caret-5.6.4~dfsg.1.orig/0000775000175000017500000000000011572427250014561 5ustar michaelmichaelcaret-5.6.4~dfsg.1.orig/windows/0000775000175000017500000000000011572067322016253 5ustar michaelmichaelcaret-5.6.4~dfsg.1.orig/windows/run_qmake_vs.bat0000664000175000017500000000147011572067322021437 0ustar michaelmichaelcd ..\caret %QTDIR%\bin\qmake -t vcapp "CONFIG+= vs" cd .. cd caret_brain_set %QTDIR%\bin\qmake -t vclib "CONFIG+= vs" cd .. cd caret_common %QTDIR%\bin\qmake -t vclib "CONFIG+= vs" cd .. cd caret_command_operations %QTDIR%\bin\qmake -t vclib "CONFIG+= vs" cd .. cd caret_statistics %QTDIR%\bin\qmake -t vclib "CONFIG+= vs" cd .. cd caret_vtk4_classes %QTDIR%\bin\qmake -t vclib "CONFIG+= vs" cd .. cd caret_uniformize %QTDIR%\bin\qmake -t vclib "CONFIG+= vs" cd .. cd caret_files %QTDIR%\bin\qmake -t vclib "CONFIG+= vs" cd .. cd caret_widgets %QTDIR%\bin\qmake -t vclib "CONFIG+= vs" cd .. cd caret_command %QTDIR%\bin\qmake -t vcapp "CONFIG+= vs" cd .. cd caret_cifti %QTDIR%\bin\qmake -t vclib "CONFIG+= vs" cd .. cd caret_edit %QTDIR%\bin\qmake -t vcapp "CONFIG+= vs" cd ..\windows caret-5.6.4~dfsg.1.orig/windows/run_qmake_nmake.bat0000755000175000017500000000150611572067322022103 0ustar michaelmichaelcd ..\caret %QTDIR%\bin\qmake -t app "CONFIG+= nmake" cd .. cd caret_brain_set %QTDIR%\bin\qmake -t lib "CONFIG+= nmake" cd .. cd caret_cifti %QTDIR%\bin\qmake -t lib "CONFIG+= nmake" cd .. cd caret_common %QTDIR%\bin\qmake -t lib "CONFIG+= nmake" cd .. cd caret_command_operations %QTDIR%\bin\qmake -t lib "CONFIG+= nmake" cd .. cd caret_statistics %QTDIR%\bin\qmake -t lib "CONFIG+= nmake" cd .. cd caret_vtk4_classes %QTDIR%\bin\qmake -t lib "CONFIG+= nmake" cd .. cd caret_uniformize %QTDIR%\bin\qmake -t lib "CONFIG+= nmake" cd .. cd caret_files %QTDIR%\bin\qmake -t lib "CONFIG+= nmake" cd .. cd caret_widgets %QTDIR%\bin\qmake -t lib "CONFIG+= nmake" cd .. cd caret_command %QTDIR%\bin\qmake -t app "CONFIG+= nmake" cd .. cd caret_edit %QTDIR%\bin\qmake -t app "CONFIG+= nmake" cd ..\windows caret-5.6.4~dfsg.1.orig/windows/run_nmake.bat0000755000175000017500000000067411572067322020732 0ustar michaelmichaelcd .. cd caret_cifti nmake %1 cd .. cd caret_brain_set nmake %1 cd .. cd caret_common nmake %1 cd .. cd caret_command_operations nmake %1 cd .. cd caret_statistics nmake %1 cd .. cd caret_vtk4_classes nmake %1 cd .. cd caret_uniformize nmake %1 cd .. cd caret_files nmake %1 cd .. cd caret_widgets nmake %1 cd .. cd caret_command nmake %1 cd .. cd caret_edit nmake %1 cd .. cd caret nmake %1 cd ..\windows caret-5.6.4~dfsg.1.orig/windows/caret5.sln0000664000175000017500000002320011572067322020151 0ustar michaelmichael Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "caret5", "..\caret\caret5.vcxproj", "{57B7F9AF-341D-3D6F-9508-FB48FFE167FB}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "caret_command", "..\caret_command\caret_command.vcxproj", "{8AD45AA0-D00D-3F8E-AC95-E19FD03266F0}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "caret_edit", "..\caret_edit\caret_edit.vcxproj", "{3741A127-2977-3ABE-A34A-FBA8660783F4}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CaretBrainSet", "..\caret_brain_set\CaretBrainSet.vcxproj", "{7C6B19BA-5B7D-3F48-B2B9-BECE409BA412}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CaretCommandOperations", "..\caret_command_operations\CaretCommandOperations.vcxproj", "{2E16351A-4F5A-3197-B483-5F5686E59EA2}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CaretCommon", "..\caret_common\CaretCommon.vcxproj", "{996F5D22-07AE-3AAF-B872-4D9AC2E45CB7}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CaretFiles", "..\caret_files\CaretFiles.vcxproj", "{5DB2FAAB-91C2-3904-916E-7FFA7FD571E1}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CaretStatistics", "..\caret_statistics\CaretStatistics.vcxproj", "{0EDBF9DC-36D5-3E67-8A65-5D636BC0B585}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CaretUniformize", "..\caret_uniformize\CaretUniformize.vcxproj", "{763665CB-B6F3-3557-8FDE-E8D690EAA978}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CaretVtk4Classes", "..\caret_vtk4_classes\CaretVtk4Classes.vcxproj", "{BF516C3F-0387-3AD2-8474-9C91EFF37794}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CaretWidgets", "..\caret_widgets\CaretWidgets.vcxproj", "{EAF3C22D-5D06-37C8-945E-0C14590D4BFD}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CaretCifti", "..\caret_cifti\CaretCifti.vcxproj", "{E819652D-852E-34C9-82A5-5AE93DD60149}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Debug|x64 = Debug|x64 Release|Win32 = Release|Win32 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {57B7F9AF-341D-3D6F-9508-FB48FFE167FB}.Debug|Win32.ActiveCfg = Debug|Win32 {57B7F9AF-341D-3D6F-9508-FB48FFE167FB}.Debug|Win32.Build.0 = Debug|Win32 {57B7F9AF-341D-3D6F-9508-FB48FFE167FB}.Debug|x64.ActiveCfg = Debug|x64 {57B7F9AF-341D-3D6F-9508-FB48FFE167FB}.Debug|x64.Build.0 = Debug|x64 {57B7F9AF-341D-3D6F-9508-FB48FFE167FB}.Release|Win32.ActiveCfg = Release|Win32 {57B7F9AF-341D-3D6F-9508-FB48FFE167FB}.Release|Win32.Build.0 = Release|Win32 {57B7F9AF-341D-3D6F-9508-FB48FFE167FB}.Release|x64.ActiveCfg = Release|x64 {57B7F9AF-341D-3D6F-9508-FB48FFE167FB}.Release|x64.Build.0 = Release|x64 {8AD45AA0-D00D-3F8E-AC95-E19FD03266F0}.Debug|Win32.ActiveCfg = Debug|Win32 {8AD45AA0-D00D-3F8E-AC95-E19FD03266F0}.Debug|Win32.Build.0 = Debug|Win32 {8AD45AA0-D00D-3F8E-AC95-E19FD03266F0}.Debug|x64.ActiveCfg = Debug|x64 {8AD45AA0-D00D-3F8E-AC95-E19FD03266F0}.Debug|x64.Build.0 = Debug|x64 {8AD45AA0-D00D-3F8E-AC95-E19FD03266F0}.Release|Win32.ActiveCfg = Release|Win32 {8AD45AA0-D00D-3F8E-AC95-E19FD03266F0}.Release|Win32.Build.0 = Release|Win32 {8AD45AA0-D00D-3F8E-AC95-E19FD03266F0}.Release|x64.ActiveCfg = Release|x64 {8AD45AA0-D00D-3F8E-AC95-E19FD03266F0}.Release|x64.Build.0 = Release|x64 {3741A127-2977-3ABE-A34A-FBA8660783F4}.Debug|Win32.ActiveCfg = Debug|Win32 {3741A127-2977-3ABE-A34A-FBA8660783F4}.Debug|Win32.Build.0 = Debug|Win32 {3741A127-2977-3ABE-A34A-FBA8660783F4}.Debug|x64.ActiveCfg = Debug|x64 {3741A127-2977-3ABE-A34A-FBA8660783F4}.Debug|x64.Build.0 = Debug|x64 {3741A127-2977-3ABE-A34A-FBA8660783F4}.Release|Win32.ActiveCfg = Release|Win32 {3741A127-2977-3ABE-A34A-FBA8660783F4}.Release|Win32.Build.0 = Release|Win32 {3741A127-2977-3ABE-A34A-FBA8660783F4}.Release|x64.ActiveCfg = Release|x64 {3741A127-2977-3ABE-A34A-FBA8660783F4}.Release|x64.Build.0 = Release|x64 {7C6B19BA-5B7D-3F48-B2B9-BECE409BA412}.Debug|Win32.ActiveCfg = Debug|Win32 {7C6B19BA-5B7D-3F48-B2B9-BECE409BA412}.Debug|Win32.Build.0 = Debug|Win32 {7C6B19BA-5B7D-3F48-B2B9-BECE409BA412}.Debug|x64.ActiveCfg = Debug|x64 {7C6B19BA-5B7D-3F48-B2B9-BECE409BA412}.Debug|x64.Build.0 = Debug|x64 {7C6B19BA-5B7D-3F48-B2B9-BECE409BA412}.Release|Win32.ActiveCfg = Release|Win32 {7C6B19BA-5B7D-3F48-B2B9-BECE409BA412}.Release|Win32.Build.0 = Release|Win32 {7C6B19BA-5B7D-3F48-B2B9-BECE409BA412}.Release|x64.ActiveCfg = Release|x64 {7C6B19BA-5B7D-3F48-B2B9-BECE409BA412}.Release|x64.Build.0 = Release|x64 {2E16351A-4F5A-3197-B483-5F5686E59EA2}.Debug|Win32.ActiveCfg = Debug|Win32 {2E16351A-4F5A-3197-B483-5F5686E59EA2}.Debug|Win32.Build.0 = Debug|Win32 {2E16351A-4F5A-3197-B483-5F5686E59EA2}.Debug|x64.ActiveCfg = Debug|x64 {2E16351A-4F5A-3197-B483-5F5686E59EA2}.Debug|x64.Build.0 = Debug|x64 {2E16351A-4F5A-3197-B483-5F5686E59EA2}.Release|Win32.ActiveCfg = Release|Win32 {2E16351A-4F5A-3197-B483-5F5686E59EA2}.Release|Win32.Build.0 = Release|Win32 {2E16351A-4F5A-3197-B483-5F5686E59EA2}.Release|x64.ActiveCfg = Release|x64 {2E16351A-4F5A-3197-B483-5F5686E59EA2}.Release|x64.Build.0 = Release|x64 {996F5D22-07AE-3AAF-B872-4D9AC2E45CB7}.Debug|Win32.ActiveCfg = Debug|Win32 {996F5D22-07AE-3AAF-B872-4D9AC2E45CB7}.Debug|Win32.Build.0 = Debug|Win32 {996F5D22-07AE-3AAF-B872-4D9AC2E45CB7}.Debug|x64.ActiveCfg = Debug|x64 {996F5D22-07AE-3AAF-B872-4D9AC2E45CB7}.Debug|x64.Build.0 = Debug|x64 {996F5D22-07AE-3AAF-B872-4D9AC2E45CB7}.Release|Win32.ActiveCfg = Release|Win32 {996F5D22-07AE-3AAF-B872-4D9AC2E45CB7}.Release|Win32.Build.0 = Release|Win32 {996F5D22-07AE-3AAF-B872-4D9AC2E45CB7}.Release|x64.ActiveCfg = Release|x64 {996F5D22-07AE-3AAF-B872-4D9AC2E45CB7}.Release|x64.Build.0 = Release|x64 {5DB2FAAB-91C2-3904-916E-7FFA7FD571E1}.Debug|Win32.ActiveCfg = Debug|Win32 {5DB2FAAB-91C2-3904-916E-7FFA7FD571E1}.Debug|Win32.Build.0 = Debug|Win32 {5DB2FAAB-91C2-3904-916E-7FFA7FD571E1}.Debug|x64.ActiveCfg = Debug|x64 {5DB2FAAB-91C2-3904-916E-7FFA7FD571E1}.Debug|x64.Build.0 = Debug|x64 {5DB2FAAB-91C2-3904-916E-7FFA7FD571E1}.Release|Win32.ActiveCfg = Release|Win32 {5DB2FAAB-91C2-3904-916E-7FFA7FD571E1}.Release|Win32.Build.0 = Release|Win32 {5DB2FAAB-91C2-3904-916E-7FFA7FD571E1}.Release|x64.ActiveCfg = Release|x64 {5DB2FAAB-91C2-3904-916E-7FFA7FD571E1}.Release|x64.Build.0 = Release|x64 {0EDBF9DC-36D5-3E67-8A65-5D636BC0B585}.Debug|Win32.ActiveCfg = Debug|Win32 {0EDBF9DC-36D5-3E67-8A65-5D636BC0B585}.Debug|Win32.Build.0 = Debug|Win32 {0EDBF9DC-36D5-3E67-8A65-5D636BC0B585}.Debug|x64.ActiveCfg = Debug|x64 {0EDBF9DC-36D5-3E67-8A65-5D636BC0B585}.Debug|x64.Build.0 = Debug|x64 {0EDBF9DC-36D5-3E67-8A65-5D636BC0B585}.Release|Win32.ActiveCfg = Release|Win32 {0EDBF9DC-36D5-3E67-8A65-5D636BC0B585}.Release|Win32.Build.0 = Release|Win32 {0EDBF9DC-36D5-3E67-8A65-5D636BC0B585}.Release|x64.ActiveCfg = Release|x64 {0EDBF9DC-36D5-3E67-8A65-5D636BC0B585}.Release|x64.Build.0 = Release|x64 {763665CB-B6F3-3557-8FDE-E8D690EAA978}.Debug|Win32.ActiveCfg = Debug|Win32 {763665CB-B6F3-3557-8FDE-E8D690EAA978}.Debug|Win32.Build.0 = Debug|Win32 {763665CB-B6F3-3557-8FDE-E8D690EAA978}.Debug|x64.ActiveCfg = Debug|x64 {763665CB-B6F3-3557-8FDE-E8D690EAA978}.Debug|x64.Build.0 = Debug|x64 {763665CB-B6F3-3557-8FDE-E8D690EAA978}.Release|Win32.ActiveCfg = Release|Win32 {763665CB-B6F3-3557-8FDE-E8D690EAA978}.Release|Win32.Build.0 = Release|Win32 {763665CB-B6F3-3557-8FDE-E8D690EAA978}.Release|x64.ActiveCfg = Release|x64 {763665CB-B6F3-3557-8FDE-E8D690EAA978}.Release|x64.Build.0 = Release|x64 {BF516C3F-0387-3AD2-8474-9C91EFF37794}.Debug|Win32.ActiveCfg = Debug|Win32 {BF516C3F-0387-3AD2-8474-9C91EFF37794}.Debug|Win32.Build.0 = Debug|Win32 {BF516C3F-0387-3AD2-8474-9C91EFF37794}.Debug|x64.ActiveCfg = Debug|x64 {BF516C3F-0387-3AD2-8474-9C91EFF37794}.Debug|x64.Build.0 = Debug|x64 {BF516C3F-0387-3AD2-8474-9C91EFF37794}.Release|Win32.ActiveCfg = Release|Win32 {BF516C3F-0387-3AD2-8474-9C91EFF37794}.Release|Win32.Build.0 = Release|Win32 {BF516C3F-0387-3AD2-8474-9C91EFF37794}.Release|x64.ActiveCfg = Release|x64 {BF516C3F-0387-3AD2-8474-9C91EFF37794}.Release|x64.Build.0 = Release|x64 {EAF3C22D-5D06-37C8-945E-0C14590D4BFD}.Debug|Win32.ActiveCfg = Debug|Win32 {EAF3C22D-5D06-37C8-945E-0C14590D4BFD}.Debug|Win32.Build.0 = Debug|Win32 {EAF3C22D-5D06-37C8-945E-0C14590D4BFD}.Debug|x64.ActiveCfg = Debug|x64 {EAF3C22D-5D06-37C8-945E-0C14590D4BFD}.Debug|x64.Build.0 = Debug|x64 {EAF3C22D-5D06-37C8-945E-0C14590D4BFD}.Release|Win32.ActiveCfg = Release|Win32 {EAF3C22D-5D06-37C8-945E-0C14590D4BFD}.Release|Win32.Build.0 = Release|Win32 {EAF3C22D-5D06-37C8-945E-0C14590D4BFD}.Release|x64.ActiveCfg = Release|x64 {EAF3C22D-5D06-37C8-945E-0C14590D4BFD}.Release|x64.Build.0 = Release|x64 {E819652D-852E-34C9-82A5-5AE93DD60149}.Debug|Win32.ActiveCfg = Debug|Win32 {E819652D-852E-34C9-82A5-5AE93DD60149}.Debug|Win32.Build.0 = Debug|Win32 {E819652D-852E-34C9-82A5-5AE93DD60149}.Debug|x64.ActiveCfg = Debug|x64 {E819652D-852E-34C9-82A5-5AE93DD60149}.Debug|x64.Build.0 = Debug|x64 {E819652D-852E-34C9-82A5-5AE93DD60149}.Release|Win32.ActiveCfg = Release|Win32 {E819652D-852E-34C9-82A5-5AE93DD60149}.Release|Win32.Build.0 = Release|Win32 {E819652D-852E-34C9-82A5-5AE93DD60149}.Release|x64.ActiveCfg = Release|x64 {E819652D-852E-34C9-82A5-5AE93DD60149}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal caret-5.6.4~dfsg.1.orig/windows/c5env64.vbs0000664000175000017500000000251211572067322020161 0ustar michaelmichaelSet objShell = WScript.CreateObject("WScript.Shell") Set colUsrEnvVars = objShell.Environment("USER") QtPath = "C:\dev64\install\Qt\bin" CCommandPath = "C:\dev64\caret5_source\caret_command\debug;C:\dev64\caret5_source\caret_command\release" Path = colUsrEnvVars("OLDPATH") If Len(Path) = 0 Then colUsrEnvVars("OLDPATH") = colUsrEnvVars("PATH") 'objShell.ExpandEnvironmentStrings("%PATH%") WScript.Echo colUsrEnvVars("OLDPATH") Path = colUsrEnvVars("OLDPATH") End If NewPath = (QtPath & ";" & CCommandPath & ";" & Path) colUsrEnvVars("PATH") = (NewPath) colUsrEnvVars("QTDIR") = "C:\dev64\install\Qt" colUsrEnvVars("VTK_LIB_DIR") = "C:\dev64\install\VTKDebug\lib\vtk-5.6" colUsrEnvVars("VTK_INC_DIR") = "C:\dev64\install\VTKDebug\include\vtk-5.6" colUsrEnvVars("QWT_LIB_DIR") = "C:\dev64\install\qwt-5.2.1\lib" colUsrEnvVars("QWT_INC_DIR") = "C:\dev64\install\qwt-5.2.1\include" colUsrEnvVars("ZLIB_LIB_DIR") = "C:\dev64\install\zlib\lib" colUsrEnvVars("ZLIB_INC_DIR") = "C:\dev64\install\zlib\include" colUsrEnvVars("VTK_RELEASE_LIB_DIR") = "C:\dev64\install\VTKRelease\lib\vtk-5.6" colUsrEnvVars("VTK_RELEASE_INC_DIR") = "C:\dev64\install\VTKRelease\include\vtk-5.6" colUsrEnvVars("NETCDF_INC_DIR") = "C:\dev64\install\minc-netcdf\include" colUsrEnvVars("NETCDF_LIB_DIR") = "C:\dev64\install\minc-netcdf\lib"caret-5.6.4~dfsg.1.orig/windows/c5env64.bat0000664000175000017500000000130611572067322020135 0ustar michaelmichaelset PATH=C:\dev64\install\Qt\bin;C:\dev64\caret5_source\caret_command\debug;C:\dev64\caret5_source\caret_command\release;%PATH% set QTDIR=C:\dev64\install\Qt set VTK_LIB_DIR=C:\dev64\install\VTKDebug\lib\vtk-5.6 set VTK_INC_DIR=C:\dev64\install\VTKDebug\include\vtk-5.6 set QWT_LIB_DIR=C:\dev64\install\qwt-5.2.1\lib set QWT_INC_DIR=C:\dev64\install\qwt-5.2.1\include set ZLIB_LIB_DIR=C:\dev64\install\zlib\lib set ZLIB_INC_DIR=C:\dev64\install\zlib\include set VTK_RELEASE_LIB_DIR=C:\dev64\install\VTKRelease\lib\vtk-5.6 set VTK_RELEASE_INC_DIR=C:\dev64\install\VTKRelease\include\vtk-5.6 set NETCDF_INC_DIR=C:\dev64\install\minc-netcdf\include set NETCDF_LIB_DIR=C:\dev64\install\minc-netcdf\libcaret-5.6.4~dfsg.1.orig/windows/c5env32.vbs0000664000175000017500000000251411572067322020156 0ustar michaelmichaelSet objShell = WScript.CreateObject("WScript.Shell") Set colUsrEnvVars = objShell.Environment("USER") QtPath = "C:\dev32\install\Qt\bin" CCommandPath = "C:\dev32\caret5_source\caret_command\debug;C:\dev32\caret5_source\caret_command\release" Path = colUsrEnvVars("OLDPATH") If Len(Path) = 0 Then colUsrEnvVars("OLDPATH") = colUsrEnvVars("PATH") 'objShell.ExpandEnvironmentStrings("%PATH%") WScript.Echo colUsrEnvVars("OLDPATH") Path = colUsrEnvVars("OLDPATH") End If NewPath = (QtPath & ";" & CCommandPath & ";" & Path) colUsrEnvVars("PATH") = (NewPath) colUsrEnvVars("QTDIR") = "C:\dev32\install\Qt" colUsrEnvVars("VTK_LIB_DIR") = "C:\dev32\install\VTKDebug\lib\vtk-5.6" colUsrEnvVars("VTK_INC_DIR") = "C:\dev32\install\VTKDebug\include\vtk-5.6" colUsrEnvVars("QWT_LIB_DIR") = "C:\dev32\install\qwt-5.2.1\lib" colUsrEnvVars("QWT_INC_DIR") = "C:\dev32\install\qwt-5.2.1\include" colUsrEnvVars("ZLIB_LIB_DIR") = "C:\dev32\install\zlib\lib" colUsrEnvVars("ZLIB_INC_DIR") = "C:\dev32\install\zlib\include" colUsrEnvVars("VTK_RELEASE_LIB_DIR") = "C:\dev32\install\VTKRelease\lib\vtk-5.6" colUsrEnvVars("VTK_RELEASE_INC_DIR") = "C:\dev32\install\VTKRelease\include\vtk-5.6" colUsrEnvVars("NETCDF_INC_DIR") = "C:\dev32\install\minc-netcdf\include" colUsrEnvVars("NETCDF_LIB_DIR") = "C:\dev32\install\minc-netcdf\lib" caret-5.6.4~dfsg.1.orig/windows/c5env32.bat0000664000175000017500000000130611572067322020130 0ustar michaelmichaelset PATH=C:\dev32\install\Qt\bin;C:\dev32\caret5_source\caret_command\debug;C:\dev32\caret5_source\caret_command\release;%PATH% set QTDIR=C:\dev32\install\Qt set VTK_LIB_DIR=C:\dev32\install\VTKDebug\lib\vtk-5.6 set VTK_INC_DIR=C:\dev32\install\VTKDebug\include\vtk-5.6 set QWT_LIB_DIR=C:\dev32\install\qwt-5.2.1\lib set QWT_INC_DIR=C:\dev32\install\qwt-5.2.1\include set ZLIB_LIB_DIR=C:\dev32\install\zlib\lib set ZLIB_INC_DIR=C:\dev32\install\zlib\include set VTK_RELEASE_LIB_DIR=C:\dev32\install\VTKRelease\lib\vtk-5.6 set VTK_RELEASE_INC_DIR=C:\dev32\install\VTKRelease\include\vtk-5.6 set NETCDF_INC_DIR=C:\dev32\install\minc-netcdf\include set NETCDF_LIB_DIR=C:\dev32\install\minc-netcdf\libcaret-5.6.4~dfsg.1.orig/windows/README.txt0000664000175000017500000000215111572067322017750 0ustar michaelmichaelc5env32.bat - sets up 32 bit caret environment variabls in a local command prompt session c5env32.vbs - sets up 64 bit caret environemnt variables system wide (this will affect ALL applications, i.e. Visual Studio, however, they have to launched AFTER running this script) c5env64.bat - sets up 32 bit caret environment variabls in a local command prompt session c5env64.vbs - sets up 64 bit caret environemtt variables system wide (this will affect ALL applications, i.e. Visual Studio, however, they have to launched AFTER running this script) Note that it is possible to compile different versions of caret in separate command prompt session. In contrast the Visual Studio IDE relies on system wide environment variables. Therefore, it is not recommended that you try to compile both 64 and 32 bit version of caret inside visual studio at the same time (even in different sessions). After setting the environment variables for a session using the scripts above, next execute: run_qmake_vs.bat Next, launch visual studio and open caret5.sln For command line building, run: run_qmake_nmake.bat run_nmake.batcaret-5.6.4~dfsg.1.orig/testing/0000775000175000017500000000000011572067322016236 5ustar michaelmichaelcaret-5.6.4~dfsg.1.orig/testing/run_test.sh0000755000175000017500000000066211572067322020442 0ustar michaelmichael#!/bin/sh # # Test rending of surface shape data # # # Use black background # caret_command -preferences-file-settings \ -background-color 0 0 0 \ # # Show the scene # caret_command -show-scene \ caret_file_check.spec \ Human.crap.R.test.scene \ 1 \ -image-file image1-test.jpg 1 # # Compare to the correct image # caret_command -image-compare \ image1-test.jpg \ image1-correct.jpg \ -tol 10 caret-5.6.4~dfsg.1.orig/testing/image1-test.jpg0000664000175000017500000005456511572067322021077 0ustar michaelmichaelJFIFHHC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222"" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((Q>@.q_JtoWZbV!?@wE{ſ-yOtoKOIu$BW[^iO >*r\YҀ0h6uͭ ,=ϥjΰ#6 dhx>YWE=zts R둑P]g< {$ʳrtQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE]Ҵ{<^)U3L㲳Wi^mmm>=+fImB`K wz)|KݺuRǂ<08Pq O=ըJ(ee B Gasks!PEd_mEʨK|y<0>9]KDV =+5-|-5Fg(s9ɠOO&#"99 :'Qd'?}5tܟHX2ќ[Z+|k&[ghrnn0FOvXedR ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (4tm&MZ X]:5 Ș /,5;"2읠{t zWat1[HI{{}+1d5e' 10<ӊ]?ú]AeǼտ+-3,!q^;sҀ2l., B t6^C\*GKBΣ)qc=ƴ/2PA/M7Qp*'<71e!aqc]7OɦzUf誹#iK1]N$6C Eei- vն팩 gLHf[UsD8W1ߜuamڂ;U-p1Pddgrk"RO&i@Kuadg}qtd#c,>zsFc 54a]is' #E9c2{m6+xq{M^a A;P[ڢHRGbq-BhH#qoRe$9 PLLm?@,/Z(u;cLY6\9gɨ8U]!H㎄~n8IXۺ?8]=[QnmNGZ؃A{bї&6#8uKX HIt$x皹y,v7iIgϬkl R=zλpǹH0 M+mwYy$`lsx2s V; nI=ȯdO-F|7^8 ϭ[}Z։eclomizeݬL:Iၹ!v78Y*v<p}ض =}cºK`y3@W0\v^7ҥ|)'+LKt /zÊ٬Hfr|ˌhn~7v.]#ߓ9'U{뵵}ƺ}7L#~P:Ie˺.aMtVZ${u@8^eXxTO2CyP{s(} ww`KH "eqҶTKR1X"+ };Y[.8e2#QW|i?f\})uZd7?6?R(Mp×5jw v4nUJEųlC`r:PO^Ƕ1e?9;^1Yel}]66ʠZkQxuY2?bҀ3=;S+dEH'#Һڔ.QJ6:Mؚǟ/ ~EΊK8;xʪq}2zi!:rk5&'FYȄ`d9}yu%%T^]k=!g>qs+jiLO9?Wyes{Z)@(((((((((((((((((<)݌J>8q@-v 'K$G8}IK;$3f'$>4 ݩf tK{bݎ)g{X7&|zB}{v瑺l@(a:mׯ(u[l_&@F(N#9V2+$sw-2`ҽ3JŦlbcO1bG6JǨ== A8alzսbI4mvurˑGF9>!;t2_8H%NF:W?ߛ0'ub76([4V;Tt=}zӵ^h5(H00Dxbq~thOnk$4LNG_^׵"V-T}Z<ohчk$ȋ9t{Hy½E1?Ziʠf[o&Y0r׏YwZu@ ޣ:ϑwʢfU,eQ=OsrHy vϿ5CZ#>.C"e,z?[:E2@~(XYiI]95Zɧ`!srwOwJKT^!MkOUHۃ۽~S zuP6,F(W'C䚟U妢Ib9&%K7Htx^\\yd\a m x\߈JQ w` m@+e=zJʕGZD&?q܏o xelgr?Zloa:xO݉d_RDK{g@koV6Q29c&+raOua?'(sP_詧LXXmOuSQӮ-.1ʟUZ4'F[PX1WEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPYñ wXZ/pdv^ǣz0[[~iWۀs 7YԭE1ӑ`$w^ &_[Ȋ\c>ƺcYsܓ֝(@oRK֩Yjo`IC} 'A⻤M&vDDC>?xn.K%%H )Ԟ1X(E).Eⲵ_[B푻=zPQuai \#?EO6rvOƹoԠ3j3|jN K 8 ր/j:oq$r vTM($5%\c^}t 6NPr}(IL:~WȯVG<\+&,ןu*:Vme8@m,֩Mi$Ď^t"0½u=,d˳ 4ihBI߷zte*IK|1+]Mw0Ez~jLZe5aksB |/fwypwwZiZD¢q@o]C_h @>{XAy9z~bY@5)'\ 䓚iڜ쫄Y {q@Νp8_T,fgvQKV{,'nۀ?k_KDpd k`RP7oZk\z+lKjZĢ%=};+ڽԀ3@6G-20-]xC}XiqCg\ <4ReJp3/OH3p=nٖ H8wQī=վ٘ls'>԰k&iE6?9goBY?te̓D0e#o.#VYodїhmS`Z5}#P:}kVCd+׈A};.2=ZjiLA=Og/Kpaeu'>yztUC0R ( ( ( ( ( ( ( ( ( ( ( ( ( ' FH3=3\} L_9|Vu#:v-fLFÐv>t3q-q**(#{jȠW{]$A@ކ@fZK-Z]oqiSRryڟ%[:YӻP<}G tL Hovl?D=s#?:O3+$Ɍ_VZqC"R0EbIsiڋ> H*Sd`/"u UCϿn]3UԬ5Dʺ~sWKm6\_kH|qYWԭu#(zU׾F<`טxoB/ ľRc^j*`o틣yN1%u³.YY?i'XZ熹.YvoQHOߕzoes #WPCgbp@+5-OQ JN-I&cPBH3vg^k6bW*6dxē%ᲷBs+εr[q* 1msenΤ\ $K,~Q}xKC{qDBrp? H,̍'pX`]{hna*($ 2kͯ_Hsї:8亾K[&'W_[^sy JwlVHؼ,~J7yc@/e[ DTg^vS^s$_y** 5-]E,Im$٢ˀSp4kD=nX/n_gϊE_$RFCȀ 6y],n c]#n@#z8l-̪#z/ՀhX2:Mh)#yfT@ xv;? .wGk|ՑsMi0 nxshsȯG$u#Zt0gp9ZX􉷏4:l,yڲ0,ѓB$/EW`Vxew3t9?Њ,{+$E9R ڨŧ7b[k&4 >sB\hA@OkDE?V~qehW`Oܹ@[ԁ:zl}@rd(c7mԌ 2>UfFnsI[@\Ŗtq׵6WP:N?dWؖPЀO.7q߂xU4KfYS{g ";1o,Hz:LD-0yIv?ךWǀe&-w)^`fue !Qv? tQEQEQEQEQEQEQEQEQEQEQEQEQEjG}gU )3¯Ҿ]/D5}+|3Ĉ:{?JRD|(Q@.#8'ykkHprSnBtJNbrܒK1<''WMm)mw u]>lHEi}i-Nd@ČbBBrq\'Uy>8b{;rݡq9&4n 8 !cE Hqgf:XҦrTǺOQ*񋵾Aݒ>FP {9ϊ5/ym3ր=;–p~fVM䞹5Q=9-*n}N۸h c1T.<) ܥLր<QYԀ1S;OqxSڰV 1$^bOz6]]o\-uבG#״-FV. *ݞ6,JpAPiTApC/$|uּ)j݃C^3iN[i[1csz[f y>Kj~}Iҽ{Nc%7+$Oˁoi\i lqzpzɥ6EIJ@2@᜚֦ڵEm9ǿ?6G$c@YJ8*1=kWՏƶ|;iw0< 5g{Bj9o<-u(4]\sA\%7Rlz֦(m&i+ʱn39w9#h/uUVTyyUQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@mxkF}WTR;HY$d|ZȆ&xLn>*7*{S}3' \x6OΌ(ʾVZAthӢqDZ#>tYk!p0y@:2[nLsY~޶&xfYA8R <ssڬ::|vP{$Dcm dMħq$jĚ쭔-G>}\e59.\1@u~JF]t]WK2ƺ4hgh"8#ߠ=5WÚKMoo,PHਓ8(γ65՝f!Sp:⸋u(' 08~.`#x,,†(P+jmel2)`A>io#y #n2YFI>ƟIk**Y#G:]N@"1>ܖ=OJXtUFqǵpaD]. 6Koax-yj͏[&%ٱ,W9<~j:$5& PP  SbC/K?vxFWnga qmXt9QĆ&}8i)*GB*wұ21]MƖD6% 5oT]5aX ~qH ]%u vXnGM5įL?"_BFbr:H; x+{Saq䡈3֏KFfzsowaL[NATmB!mu&bq4qp=V4-I@&8Q aھsl]ni[qSv1@VhӂsT_|4nJpzgG!1̧k>[OO-Vg?_Ҁ9!b^9%eG1W_(3H`0iп/@Tc(6VҧcG'Gcs^Aq9dP>L8k>oY7K+]Gev4IbdKkȘkfhY;pr:vל]eX[BQpXwrNy^K%`8Z1d Td@,1VR#J|qZ@Z(((((((((((w6 aԃWVg^mѵw=>XIx( +6v8 ۟^V7>`Gb XIkL??s{v5EG-,| `:F('W=e 1[ ^N|݃ b7uK=Nm 珯OƬ]_O}bVPk-ne4ޫ6Vg th/q{q_>ȧ"#$=jbi5]XyC1} sWIuE;}'HG]riYzh)գ]aeE`CNAuV$Pkm/Ei#.˄QՏ,Iyq4YIFf8Q .lvh-Vx+oI,E.@:1gֲ$⾅!a@ d,v_O_>y:GГq^Ӧjp@9sShVXЖ㕠e~kϲh/u4OXA)-nq#VǩZ.࿇r2MyH6Hbb]ّhhS𨣹x3tJ/ iIlT zxIŲ]ހ8-R7 #IgyVU wu~?#\_La mxݷ] 4dq3€:=.Ap+ks# 68{E-CJ]NmNngBg'Md+VU/km0%kh#Wl4mΠjWur*'5E%ΪGnI&s|`ѩ!) }3Z&GgЙG@^JRB砮l"jP2aUO=k^XpXf<1].4 l"I -6O*d|sNV4In%ϕ( ؟~5ym]"yXp>kKE =u9ZB8#:k6Mt$7,9ƥʼn,q@Qc_SCɌ6VܳF3{f/.c@>-M{U`z@|yGs2O 0^Px7Xձ\V,53!?";{מijH閬R!\_aToQso 'qV5PEPEPEPEPEPEPEPEPEPEPEP|4 @Zb9vvuz2NHUAHĎ@#cSjK8T w5;0)Xvcf9W #HXDde܏z Rfh.E6[ԥҹuO)3%g Coi7yx l{v!c?Oc$Xl8deNeYHSë€7tt4u6hQF d)suZ-ubS w1&NwO+*y9ZYZ Wӂ +N-Ǵ³dy.P ,`l9 QjI<[y‰>1g֠ h$:})UZ֚Ti[oU5 >}B\ݗ((?^>*x?TV)# ~nsPMxS"+x8/8?j4};6 Dn7?Z-<+]aT(?xgs,A%uE wl@#a}sg!$!@OpZҭ翻18n2Fʟ7ڥݿܑ֦oFb#PʼPA,ׁ#N]8 1])I<.NvNܬO^5N_O_ =>@$`9ݞs]2&OG2)p;®[h&\1)5Hy'[p0:W^Gs5>^^gIw!E,{@ $o6Z@OVNu%ɽ̧n9ɭ=nm'G;z1Ȯ}$2Mt掳ԭbVQ(.=FO^shf zcd#,nk/Tl2I;dG⺜^D#̷)(zn:r85-:! '98q$ZʼA Lۖgֳ$o5`F z—JֵY31DZkk]28q@df?Veޭ֯^}:yR=K=+F!&Gr€<~;Ԥ2M kѤ;;P}wEs^]d#$(+'Gӯ6R'K*7)5X$Ƞ$dwn[˙ og+H{ t^IK~>gg1[|}+<D z݋zEڊC&€1K툭 P,G\F{;Ԟ1Ԥ[+[K(╾p ,!ym/^=85i˙FՌF0? ʔ[YD?2hk{ɡ*9 NNO=s־3XC-8i_'=?=k>$,i*!\Z((((((((((((~g/cqR{VGA9 O )dXL#39'ZyPko'ܨX|sZ{G\ʹ*\8*5>vKCc=dQ\oҪiQ{h_}QcڴQ?AcQVm`+mnn~ X%[ռRTm^*4zcvU%R͑~: }1?QZ|+}A&tf?0??Vz%ϚBP4d MG0OW<ɌqxkICyɮ"T5;5"F#`;8<{#wa4-aȬb7J½k J ¼w#Pmo  nUnB:׻F9b0*߇BB}Wx^td@xPӭ"Yd{|{7i oZLs<£ӯ];ddg ]Wė_ nBԏ~YY^=ok4`]φ<4R-lҒJA?zkj5_- ox5o4]ė2 zj-*(b?\ ]kdZO45metUytH((,fGIFZ*23Y-(H AdNw:Zk62w2\I9I@ 5$)vE`ό"}NT4S#/Wke|d*)k5#hm8rJl-57RvG{M; Zm'L4`geK}.tt{D㡭]3S`0o=Pk[sSrvILgPI/<8bEU PAotpF@3LڲVnܭ:!%-֎\A G}=jDŽ&(亹fZCz SU'ۧ_1עu5ig,k[3z v-CkgS4\mzO75%zgoǪCq?iuoz{בEPEPEPEPEPEPEPEPEPEPEPEP> ʖRKҽ}F+m#UѵJ,vriUȸPFsO J[@KL.viLjGP<նBn師׾!zX^ ʣ60J MqZZB0j[BEnD×pu#-;C}EmS;`Vϙeu14{kwqK Pѓe.%ʰ#%S}k}+b T6.m6y5uWk[yd|T{UkٷLإ = { jN$d ߚWckyFӑ=(|EoE;&3J,5͚YWq8| ;}3l/b-4ddguxѫ`23p]m7y$PAmb:h'GLoo.!0] EsmG2HЌu -ۤi D'=-~"Lz=J5%%_=ރ<>W >i `PK$I!b88o(I15׉YVBIi.Όj7r# 2A&=(6m|8(w/kkNؐN\QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEHuQK.魮P>h|OjMww4ze q8WEzĚ*\[iUî#GК|NԶπZ'=>Q])`pA r<BT'F= ؞000w.ƒIJ ̲3c$ m7öO?4{YfkYE8JyN?M&%Ȓy#ս XA9">-2Z<1;&[vfZ6zspR?: &[YP+<3q@O#ډ%2A#9:Vݾa[%C0$ʷ~t/^Ddn%l]IkhTr:g#C?-ĉwnކ=OAl bPG᱊H `F}Q OQG*@k"((sCvO])?~nč'ţjm!y8G#5I[\G<.RX:0Ss1 מH d^Uִ}fc$T^Yvئx%<Σ#gk]!׼54wVI9KQY,޵ip@pa 8r%R|${N?Zt7rxYؕxv \J@v@Y'ԑ2}y^PcFv}}҄}׏J[3K,P"8i} QZvzZE'@\yAQ[^fpN,ih1Ȯ?]4^RxgrN3Uz]ex6'(׀xS_7ryew%%[`|^m.<|f]GHFG+OHk]ىuP>lҼċKI>Qq,#ƽsxQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@t LosP;#>ۋd3@|1ăl|K}!R6R5n+vъ{ׄ~45.K$ۜgsxzlZ4Y ew,\CῴZ1\Ɲ7tY;-Jr;$VE[5b3WM ֋HY݃<9\d\% Lg&= w8\w\{ܗ^/ LZkK4H-;v;. 'rǣYI-Ja$ų8xܾ#e:ʎG!@~qˠ]񮵯ɎPG=OS\PEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP?PM.AOU#5&iu9J#?yx7ҴI*ېA2cs9<k(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((caret-5.6.4~dfsg.1.orig/testing/image1-correct.jpg0000664000175000017500000005456511572067322021561 0ustar michaelmichaelJFIFHHC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222"" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((Q>@.q_JtoWZbV!?@wE{ſ-yOtoKOIu$BW[^iO >*r\YҀ0h6uͭ ,=ϥjΰ#6 dhx>YWE=zts R둑P]g< {$ʳrtQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE]Ҵ{<^)U3L㲳Wi^mmm>=+fImB`K wz)|KݺuRǂ<08Pq O=ըJ(ee B Gasks!PEd_mEʨK|y<0>9]KDV =+5-|-5Fg(s9ɠOO&#"99 :'Qd'?}5tܟHX2ќ[Z+|k&[ghrnn0FOvXedR ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (4tm&MZ X]:5 Ș /,5;"2읠{t zWat1[HI{{}+1d5e' 10<ӊ]?ú]AeǼտ+-3,!q^;sҀ2l., B t6^C\*GKBΣ)qc=ƴ/2PA/M7Qp*'<71e!aqc]7OɦzUf誹#iK1]N$6C Eei- vն팩 gLHf[UsD8W1ߜuamڂ;U-p1Pddgrk"RO&i@Kuadg}qtd#c,>zsFc 54a]is' #E9c2{m6+xq{M^a A;P[ڢHRGbq-BhH#qoRe$9 PLLm?@,/Z(u;cLY6\9gɨ8U]!H㎄~n8IXۺ?8]=[QnmNGZ؃A{bї&6#8uKX HIt$x皹y,v7iIgϬkl R=zλpǹH0 M+mwYy$`lsx2s V; nI=ȯdO-F|7^8 ϭ[}Z։eclomizeݬL:Iၹ!v78Y*v<p}ض =}cºK`y3@W0\v^7ҥ|)'+LKt /zÊ٬Hfr|ˌhn~7v.]#ߓ9'U{뵵}ƺ}7L#~P:Ie˺.aMtVZ${u@8^eXxTO2CyP{s(} ww`KH "eqҶTKR1X"+ };Y[.8e2#QW|i?f\})uZd7?6?R(Mp×5jw v4nUJEųlC`r:PO^Ƕ1e?9;^1Yel}]66ʠZkQxuY2?bҀ3=;S+dEH'#Һڔ.QJ6:Mؚǟ/ ~EΊK8;xʪq}2zi!:rk5&'FYȄ`d9}yu%%T^]k=!g>qs+jiLO9?Wyes{Z)@(((((((((((((((((<)݌J>8q@-v 'K$G8}IK;$3f'$>4 ݩf tK{bݎ)g{X7&|zB}{v瑺l@(a:mׯ(u[l_&@F(N#9V2+$sw-2`ҽ3JŦlbcO1bG6JǨ== A8alzսbI4mvurˑGF9>!;t2_8H%NF:W?ߛ0'ub76([4V;Tt=}zӵ^h5(H00Dxbq~thOnk$4LNG_^׵"V-T}Z<ohчk$ȋ9t{Hy½E1?Ziʠf[o&Y0r׏YwZu@ ޣ:ϑwʢfU,eQ=OsrHy vϿ5CZ#>.C"e,z?[:E2@~(XYiI]95Zɧ`!srwOwJKT^!MkOUHۃ۽~S zuP6,F(W'C䚟U妢Ib9&%K7Htx^\\yd\a m x\߈JQ w` m@+e=zJʕGZD&?q܏o xelgr?Zloa:xO݉d_RDK{g@koV6Q29c&+raOua?'(sP_詧LXXmOuSQӮ-.1ʟUZ4'F[PX1WEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPYñ wXZ/pdv^ǣz0[[~iWۀs 7YԭE1ӑ`$w^ &_[Ȋ\c>ƺcYsܓ֝(@oRK֩Yjo`IC} 'A⻤M&vDDC>?xn.K%%H )Ԟ1X(E).Eⲵ_[B푻=zPQuai \#?EO6rvOƹoԠ3j3|jN K 8 ր/j:oq$r vTM($5%\c^}t 6NPr}(IL:~WȯVG<\+&,ןu*:Vme8@m,֩Mi$Ď^t"0½u=,d˳ 4ihBI߷zte*IK|1+]Mw0Ez~jLZe5aksB |/fwypwwZiZD¢q@o]C_h @>{XAy9z~bY@5)'\ 䓚iڜ쫄Y {q@Νp8_T,fgvQKV{,'nۀ?k_KDpd k`RP7oZk\z+lKjZĢ%=};+ڽԀ3@6G-20-]xC}XiqCg\ <4ReJp3/OH3p=nٖ H8wQī=վ٘ls'>԰k&iE6?9goBY?te̓D0e#o.#VYodїhmS`Z5}#P:}kVCd+׈A};.2=ZjiLA=Og/Kpaeu'>yztUC0R ( ( ( ( ( ( ( ( ( ( ( ( ( ' FH3=3\} L_9|Vu#:v-fLFÐv>t3q-q**(#{jȠW{]$A@ކ@fZK-Z]oqiSRryڟ%[:YӻP<}G tL Hovl?D=s#?:O3+$Ɍ_VZqC"R0EbIsiڋ> H*Sd`/"u UCϿn]3UԬ5Dʺ~sWKm6\_kH|qYWԭu#(zU׾F<`טxoB/ ľRc^j*`o틣yN1%u³.YY?i'XZ熹.YvoQHOߕzoes #WPCgbp@+5-OQ JN-I&cPBH3vg^k6bW*6dxē%ᲷBs+εr[q* 1msenΤ\ $K,~Q}xKC{qDBrp? H,̍'pX`]{hna*($ 2kͯ_Hsї:8亾K[&'W_[^sy JwlVHؼ,~J7yc@/e[ DTg^vS^s$_y** 5-]E,Im$٢ˀSp4kD=nX/n_gϊE_$RFCȀ 6y],n c]#n@#z8l-̪#z/ՀhX2:Mh)#yfT@ xv;? .wGk|ՑsMi0 nxshsȯG$u#Zt0gp9ZX􉷏4:l,yڲ0,ѓB$/EW`Vxew3t9?Њ,{+$E9R ڨŧ7b[k&4 >sB\hA@OkDE?V~qehW`Oܹ@[ԁ:zl}@rd(c7mԌ 2>UfFnsI[@\Ŗtq׵6WP:N?dWؖPЀO.7q߂xU4KfYS{g ";1o,Hz:LD-0yIv?ךWǀe&-w)^`fue !Qv? tQEQEQEQEQEQEQEQEQEQEQEQEQEjG}gU )3¯Ҿ]/D5}+|3Ĉ:{?JRD|(Q@.#8'ykkHprSnBtJNbrܒK1<''WMm)mw u]>lHEi}i-Nd@ČbBBrq\'Uy>8b{;rݡq9&4n 8 !cE Hqgf:XҦrTǺOQ*񋵾Aݒ>FP {9ϊ5/ym3ր=;–p~fVM䞹5Q=9-*n}N۸h c1T.<) ܥLր<QYԀ1S;OqxSڰV 1$^bOz6]]o\-uבG#״-FV. *ݞ6,JpAPiTApC/$|uּ)j݃C^3iN[i[1csz[f y>Kj~}Iҽ{Nc%7+$Oˁoi\i lqzpzɥ6EIJ@2@᜚֦ڵEm9ǿ?6G$c@YJ8*1=kWՏƶ|;iw0< 5g{Bj9o<-u(4]\sA\%7Rlz֦(m&i+ʱn39w9#h/uUVTyyUQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@mxkF}WTR;HY$d|ZȆ&xLn>*7*{S}3' \x6OΌ(ʾVZAthӢqDZ#>tYk!p0y@:2[nLsY~޶&xfYA8R <ssڬ::|vP{$Dcm dMħq$jĚ쭔-G>}\e59.\1@u~JF]t]WK2ƺ4hgh"8#ߠ=5WÚKMoo,PHਓ8(γ65՝f!Sp:⸋u(' 08~.`#x,,†(P+jmel2)`A>io#y #n2YFI>ƟIk**Y#G:]N@"1>ܖ=OJXtUFqǵpaD]. 6Koax-yj͏[&%ٱ,W9<~j:$5& PP  SbC/K?vxFWnga qmXt9QĆ&}8i)*GB*wұ21]MƖD6% 5oT]5aX ~qH ]%u vXnGM5įL?"_BFbr:H; x+{Saq䡈3֏KFfzsowaL[NATmB!mu&bq4qp=V4-I@&8Q aھsl]ni[qSv1@VhӂsT_|4nJpzgG!1̧k>[OO-Vg?_Ҁ9!b^9%eG1W_(3H`0iп/@Tc(6VҧcG'Gcs^Aq9dP>L8k>oY7K+]Gev4IbdKkȘkfhY;pr:vל]eX[BQpXwrNy^K%`8Z1d Td@,1VR#J|qZ@Z(((((((((((w6 aԃWVg^mѵw=>XIx( +6v8 ۟^V7>`Gb XIkL??s{v5EG-,| `:F('W=e 1[ ^N|݃ b7uK=Nm 珯OƬ]_O}bVPk-ne4ޫ6Vg th/q{q_>ȧ"#$=jbi5]XyC1} sWIuE;}'HG]riYzh)գ]aeE`CNAuV$Pkm/Ei#.˄QՏ,Iyq4YIFf8Q .lvh-Vx+oI,E.@:1gֲ$⾅!a@ d,v_O_>y:GГq^Ӧjp@9sShVXЖ㕠e~kϲh/u4OXA)-nq#VǩZ.࿇r2MyH6Hbb]ّhhS𨣹x3tJ/ iIlT zxIŲ]ހ8-R7 #IgyVU wu~?#\_La mxݷ] 4dq3€:=.Ap+ks# 68{E-CJ]NmNngBg'Md+VU/km0%kh#Wl4mΠjWur*'5E%ΪGnI&s|`ѩ!) }3Z&GgЙG@^JRB砮l"jP2aUO=k^XpXf<1].4 l"I -6O*d|sNV4In%ϕ( ؟~5ym]"yXp>kKE =u9ZB8#:k6Mt$7,9ƥʼn,q@Qc_SCɌ6VܳF3{f/.c@>-M{U`z@|yGs2O 0^Px7Xձ\V,53!?";{מijH閬R!\_aToQso 'qV5PEPEPEPEPEPEPEPEPEPEPEP|4 @Zb9vvuz2NHUAHĎ@#cSjK8T w5;0)Xvcf9W #HXDde܏z Rfh.E6[ԥҹuO)3%g Coi7yx l{v!c?Oc$Xl8deNeYHSë€7tt4u6hQF d)suZ-ubS w1&NwO+*y9ZYZ Wӂ +N-Ǵ³dy.P ,`l9 QjI<[y‰>1g֠ h$:})UZ֚Ti[oU5 >}B\ݗ((?^>*x?TV)# ~nsPMxS"+x8/8?j4};6 Dn7?Z-<+]aT(?xgs,A%uE wl@#a}sg!$!@OpZҭ翻18n2Fʟ7ڥݿܑ֦oFb#PʼPA,ׁ#N]8 1])I<.NvNܬO^5N_O_ =>@$`9ݞs]2&OG2)p;®[h&\1)5Hy'[p0:W^Gs5>^^gIw!E,{@ $o6Z@OVNu%ɽ̧n9ɭ=nm'G;z1Ȯ}$2Mt掳ԭbVQ(.=FO^shf zcd#,nk/Tl2I;dG⺜^D#̷)(zn:r85-:! '98q$ZʼA Lۖgֳ$o5`F z—JֵY31DZkk]28q@df?Veޭ֯^}:yR=K=+F!&Gr€<~;Ԥ2M kѤ;;P}wEs^]d#$(+'Gӯ6R'K*7)5X$Ƞ$dwn[˙ og+H{ t^IK~>gg1[|}+<D z݋zEڊC&€1K툭 P,G\F{;Ԟ1Ԥ[+[K(╾p ,!ym/^=85i˙FՌF0? ʔ[YD?2hk{ɡ*9 NNO=s־3XC-8i_'=?=k>$,i*!\Z((((((((((((~g/cqR{VGA9 O )dXL#39'ZyPko'ܨX|sZ{G\ʹ*\8*5>vKCc=dQ\oҪiQ{h_}QcڴQ?AcQVm`+mnn~ X%[ռRTm^*4zcvU%R͑~: }1?QZ|+}A&tf?0??Vz%ϚBP4d MG0OW<ɌqxkICyɮ"T5;5"F#`;8<{#wa4-aȬb7J½k J ¼w#Pmo  nUnB:׻F9b0*߇BB}Wx^td@xPӭ"Yd{|{7i oZLs<£ӯ];ddg ]Wė_ nBԏ~YY^=ok4`]φ<4R-lҒJA?zkj5_- ox5o4]ė2 zj-*(b?\ ]kdZO45metUytH((,fGIFZ*23Y-(H AdNw:Zk62w2\I9I@ 5$)vE`ό"}NT4S#/Wke|d*)k5#hm8rJl-57RvG{M; Zm'L4`geK}.tt{D㡭]3S`0o=Pk[sSrvILgPI/<8bEU PAotpF@3LڲVnܭ:!%-֎\A G}=jDŽ&(亹fZCz SU'ۧ_1עu5ig,k[3z v-CkgS4\mzO75%zgoǪCq?iuoz{בEPEPEPEPEPEPEPEPEPEPEPEP> ʖRKҽ}F+m#UѵJ,vriUȸPFsO J[@KL.viLjGP<նBn師׾!zX^ ʣ60J MqZZB0j[BEnD×pu#-;C}EmS;`Vϙeu14{kwqK Pѓe.%ʰ#%S}k}+b T6.m6y5uWk[yd|T{UkٷLإ = { jN$d ߚWckyFӑ=(|EoE;&3J,5͚YWq8| ;}3l/b-4ddguxѫ`23p]m7y$PAmb:h'GLoo.!0] EsmG2HЌu -ۤi D'=-~"Lz=J5%%_=ރ<>W >i `PK$I!b88o(I15׉YVBIi.Όj7r# 2A&=(6m|8(w/kkNؐN\QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEHuQK.魮P>h|OjMww4ze q8WEzĚ*\[iUî#GК|NԶπZ'=>Q])`pA r<BT'F= ؞000w.ƒIJ ̲3c$ m7öO?4{YfkYE8JyN?M&%Ȓy#ս XA9">-2Z<1;&[vfZ6zspR?: &[YP+<3q@O#ډ%2A#9:Vݾa[%C0$ʷ~t/^Ddn%l]IkhTr:g#C?-ĉwnކ=OAl bPG᱊H `F}Q OQG*@k"((sCvO])?~nč'ţjm!y8G#5I[\G<.RX:0Ss1 מH d^Uִ}fc$T^Yvئx%<Σ#gk]!׼54wVI9KQY,޵ip@pa 8r%R|${N?Zt7rxYؕxv \J@v@Y'ԑ2}y^PcFv}}҄}׏J[3K,P"8i} QZvzZE'@\yAQ[^fpN,ih1Ȯ?]4^RxgrN3Uz]ex6'(׀xS_7ryew%%[`|^m.<|f]GHFG+OHk]ىuP>lҼċKI>Qq,#ƽsxQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@t LosP;#>ۋd3@|1ăl|K}!R6R5n+vъ{ׄ~45.K$ۜgsxzlZ4Y ew,\CῴZ1\Ɲ7tY;-Jr;$VE[5b3WM ֋HY݃<9\d\% Lg&= w8\w\{ܗ^/ LZkK4H-;v;. 'rǣYI-Ja$ų8xܾ#e:ʎG!@~qˠ]񮵯ɎPG=OS\PEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP?PM.AOU#5&iu9J#?yx7ҴI*ېA2cs9<k(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((caret-5.6.4~dfsg.1.orig/testing/closed.topo0000664000175000017500001144576011572067322020434 0ustar michaelmichaelBeginHeader Caret-Version 5.601 comment closed topology, cleaned version date Wed Oct 1 12:29:34 2008 encoding ASCII perimeter_id CLOSED pubmed_id resolution FULL sampling ORIGINAL EndHeader tag-version 1 143112 15 14 0 20 15 0 0 4 20 0 1 4 2 1 0 14 2 0 1 3 4 1 2 3 5 3 2 27 5 2 2 12 27 14 12 2 5 4 3 56 20 4 4 51 56 4 43 51 4 28 43 4 5 28 40 28 5 5 27 40 8 7 6 16 8 6 61 16 6 6 7 61 7 8 21 7 17 61 21 17 7 8 9 21 10 9 8 49 10 8 8 16 49 26 13 9 9 25 26 35 25 9 9 10 35 9 13 21 36 35 10 50 36 10 10 49 50 11 17 21 11 14 17 11 12 14 13 12 11 21 13 11 12 26 27 12 13 26 14 15 17 22 17 15 15 20 22 16 33 49 55 33 16 16 54 55 61 54 16 65 61 17 67 65 17 17 18 67 19 18 17 22 19 17 18 19 24 18 23 67 24 23 18 19 22 24 62 22 20 20 56 62 89 24 22 22 62 89 23 66 67 140 66 23 23 111 140 23 24 111 24 89 111 118 76 25 25 35 118 27 26 25 76 27 25 27 37 40 39 37 27 76 39 27 40 31 28 28 29 43 30 29 28 31 30 28 46 43 29 47 46 29 73 47 29 29 72 73 29 41 72 29 30 41 42 41 30 116 42 30 30 31 116 31 115 116 31 37 115 40 37 31 34 33 32 48 34 32 55 48 32 32 33 55 33 34 49 50 49 34 70 50 34 34 48 70 35 117 118 35 71 117 35 36 71 36 69 71 36 50 69 37 114 115 37 38 114 39 38 37 160 114 38 38 39 160 39 159 160 39 76 159 161 72 41 41 42 161 42 116 161 57 51 43 43 52 57 43 46 52 52 46 44 58 52 44 60 58 44 44 53 60 44 45 53 46 45 44 59 53 45 45 47 59 45 46 47 77 59 47 47 73 77 82 70 48 120 82 48 123 120 48 48 96 123 48 86 96 48 55 86 70 69 50 63 56 51 51 57 63 64 57 52 52 58 64 87 60 53 53 78 87 53 59 78 68 55 54 54 65 68 54 61 65 88 86 55 55 68 88 63 62 56 91 63 57 57 64 91 58 60 64 59 77 78 93 64 60 105 93 60 60 98 105 100 98 60 60 95 100 60 94 95 60 87 94 62 63 89 90 89 63 92 90 63 63 91 92 92 91 64 93 92 64 67 66 65 97 68 65 65 66 97 132 97 66 133 132 66 139 133 66 140 139 66 97 88 68 162 71 69 69 81 162 121 81 69 69 120 121 69 70 120 70 82 120 122 117 71 163 122 71 71 162 163 168 73 72 72 161 168 73 74 77 75 74 73 168 75 73 78 77 74 83 78 74 172 83 74 74 75 172 272 172 75 75 261 272 75 168 261 76 119 159 76 118 119 78 84 87 85 84 78 78 83 85 165 81 79 257 165 79 364 257 79 79 264 364 79 170 264 79 80 170 81 80 79 80 121 170 80 81 121 165 162 81 124 85 83 173 124 83 83 172 173 94 87 84 110 94 84 175 110 84 176 175 84 84 124 176 84 85 124 101 96 86 86 88 101 198 101 88 88 97 198 89 102 111 103 102 89 130 103 89 89 90 130 199 130 90 90 92 199 92 131 199 92 93 131 93 104 131 105 104 93 110 95 94 109 100 95 110 109 95 191 123 96 195 191 96 96 101 195 300 198 97 97 132 300 107 105 98 98 99 107 100 99 98 99 106 107 99 100 106 109 106 100 198 195 101 113 111 102 102 103 113 143 113 103 294 143 103 103 129 294 130 129 103 295 131 104 104 125 295 104 105 125 135 125 105 105 107 135 108 107 106 112 108 106 136 112 106 106 109 136 107 108 135 108 134 135 108 112 134 150 136 109 109 137 150 138 137 109 109 110 138 110 128 138 175 128 110 111 113 140 144 134 112 153 144 112 112 149 153 112 148 149 151 148 112 112 136 151 205 140 113 113 204 205 208 204 113 113 141 208 143 141 113 258 115 114 114 160 258 259 116 115 115 258 259 259 161 116 171 118 117 117 166 171 117 122 166 171 119 118 167 159 119 269 167 119 119 171 269 123 121 120 174 170 121 191 174 121 121 123 191 122 163 166 375 176 124 124 173 375 125 144 295 125 134 144 135 134 125 138 128 126 126 137 138 200 137 126 126 179 200 126 127 179 128 127 126 281 179 127 127 128 281 128 280 281 128 175 280 392 294 129 129 145 392 295 145 129 129 130 295 130 199 295 295 199 131 395 300 132 396 395 132 132 133 396 401 396 133 133 139 401 136 150 151 152 150 137 201 152 137 137 200 201 139 140 205 402 401 139 139 207 402 139 204 207 205 204 139 212 208 141 141 142 212 143 142 141 304 212 142 142 206 304 142 143 206 509 206 143 143 294 509 144 147 295 626 147 144 144 405 626 144 308 405 144 153 308 295 147 145 506 392 145 145 146 506 147 146 145 507 506 146 146 503 507 743 503 146 146 624 743 146 147 624 626 624 147 148 154 155 209 154 148 148 151 209 155 149 148 156 153 149 157 156 149 149 155 157 152 151 150 151 152 209 310 209 152 152 202 310 152 201 202 153 156 308 158 155 154 310 158 154 154 209 310 216 157 155 155 158 216 156 213 308 215 213 156 216 215 156 156 157 216 158 215 216 217 215 158 158 210 217 211 210 158 414 211 158 158 310 414 167 160 159 271 258 160 160 167 271 169 168 161 260 169 161 161 259 260 165 163 162 266 166 163 366 266 163 163 253 366 163 164 253 165 164 163 164 252 253 164 241 252 246 241 164 256 246 164 257 256 164 164 165 257 267 171 166 166 266 267 167 269 271 168 169 261 262 261 169 263 262 169 169 260 263 370 264 170 377 370 170 170 285 377 170 174 285 374 269 171 171 270 374 171 268 270 277 268 171 171 267 277 272 173 172 173 272 375 174 191 285 385 280 175 175 176 385 176 375 385 177 186 192 177 184 186 177 178 184 179 178 177 192 179 177 185 184 178 282 185 178 284 282 178 178 179 284 179 192 200 288 284 179 290 288 179 179 287 290 179 281 287 187 186 180 180 181 187 182 181 180 185 182 180 180 184 185 186 184 180 181 183 187 181 182 183 189 183 182 274 189 182 276 274 182 182 273 276 182 185 273 289 187 183 293 289 183 183 188 293 189 188 183 283 273 185 185 282 283 186 187 193 193 192 186 289 193 187 388 293 188 501 388 188 188 495 501 496 495 188 188 190 496 188 189 190 275 190 189 189 274 275 600 496 190 190 490 600 190 275 490 191 196 285 191 195 196 301 200 192 192 291 301 192 194 291 192 193 194 289 194 193 194 289 291 197 196 195 198 197 195 377 285 196 386 377 196 196 197 386 197 198 300 389 386 197 395 389 197 197 300 395 301 201 200 203 202 201 301 203 201 412 310 202 202 203 412 203 298 412 397 298 203 203 301 397 208 207 204 206 303 304 306 303 206 307 306 206 511 307 206 206 509 511 403 402 207 207 302 403 207 208 302 208 212 302 316 217 210 210 314 316 315 314 210 210 311 315 210 211 311 414 311 211 304 302 212 405 308 213 515 405 213 213 408 515 213 214 408 215 214 213 214 312 408 214 215 312 313 312 215 215 217 313 316 313 217 408 313 218 525 408 218 218 219 525 220 219 218 415 220 218 218 315 415 218 313 315 639 525 219 219 220 639 220 533 534 535 533 220 220 415 535 787 639 220 806 787 220 814 806 220 220 813 814 220 534 813 221 228 230 221 222 228 223 222 221 319 223 221 329 319 221 221 230 329 229 228 222 233 229 222 222 224 233 222 223 224 235 224 223 331 235 223 336 331 223 223 323 336 223 321 323 223 320 321 223 319 320 234 233 224 235 234 224 225 236 239 241 236 225 248 241 225 225 226 248 227 226 225 239 227 225 226 242 248 226 232 242 226 230 232 226 227 230 231 230 227 351 231 227 227 334 351 227 239 334 228 229 232 232 230 228 357 249 229 229 243 357 229 233 243 249 232 229 230 231 329 231 328 329 443 328 231 231 350 443 351 350 231 249 242 232 245 243 233 233 234 245 234 235 245 352 245 235 235 330 352 331 330 235 236 241 246 236 237 239 238 237 236 246 238 236 353 239 237 237 240 353 237 238 240 250 240 238 238 247 250 238 246 247 335 334 239 353 335 239 240 251 353 240 250 251 254 252 241 241 248 254 254 248 242 255 254 242 242 249 255 245 244 243 243 354 357 243 244 354 244 245 453 359 354 244 465 359 244 244 453 465 245 352 453 256 247 246 256 250 247 357 255 249 362 251 250 250 256 362 362 361 251 356 353 251 361 356 251 365 253 252 252 255 365 252 254 255 253 365 366 255 357 365 256 257 364 363 362 256 364 363 256 367 259 258 381 367 258 258 380 381 258 271 380 367 260 259 367 263 260 261 262 272 483 272 262 262 368 483 262 263 368 369 368 263 381 369 263 263 367 381 470 364 264 480 470 264 481 480 264 482 481 264 264 370 482 267 266 265 268 267 265 479 268 265 265 477 479 265 366 477 265 266 366 267 268 277 486 270 268 593 486 268 268 479 593 278 271 269 279 278 269 378 279 269 269 374 378 486 374 270 271 278 380 483 375 272 273 283 376 371 276 273 372 371 273 489 372 273 273 376 489 373 275 274 274 371 373 274 276 371 275 373 490 487 380 278 617 487 278 278 491 617 278 279 491 609 491 279 279 378 609 387 286 280 280 385 387 286 281 280 281 286 287 284 283 282 283 284 376 284 288 376 493 287 286 286 387 493 494 290 287 287 493 494 489 376 288 494 489 288 288 290 494 293 291 289 291 297 301 394 297 291 291 299 394 291 292 299 293 292 291 623 299 292 292 501 623 292 388 501 292 293 388 294 392 509 296 393 630 394 393 296 296 297 394 298 297 296 630 298 296 397 301 297 297 298 397 298 411 412 958 411 298 959 958 298 298 750 959 751 750 298 298 630 751 299 393 394 623 393 299 302 305 403 302 304 305 305 304 303 309 305 303 303 306 309 409 403 305 305 309 409 404 309 306 306 307 404 514 404 307 307 512 514 307 511 512 410 409 309 309 406 410 309 404 406 310 412 414 415 315 311 416 415 311 311 414 416 312 313 408 313 314 315 316 314 313 679 431 317 317 440 679 317 318 440 319 318 317 431 319 317 318 319 328 443 440 318 318 328 443 322 320 319 430 322 319 432 430 319 319 431 432 329 328 319 322 321 320 324 323 321 417 324 321 321 322 417 430 417 322 323 324 336 418 333 324 434 418 324 324 417 434 324 333 336 434 417 325 325 433 434 546 433 325 325 326 546 327 326 325 545 327 325 325 417 545 548 546 326 671 548 326 326 670 671 326 327 670 327 669 670 327 545 669 561 352 330 330 332 561 330 331 332 333 332 331 336 333 331 332 438 561 332 333 438 333 418 438 686 351 334 334 567 686 334 335 567 335 353 355 335 566 567 335 355 566 337 341 346 337 340 341 337 338 340 339 338 337 346 339 337 444 340 338 560 444 338 338 445 560 338 339 445 455 445 339 458 455 339 339 347 458 339 346 347 342 341 340 344 342 340 444 344 340 341 345 346 341 342 345 347 345 342 349 347 342 436 349 342 342 426 436 342 425 426 342 343 425 344 343 342 435 425 343 343 419 435 421 419 343 570 421 343 343 344 570 344 562 570 344 444 562 347 346 345 459 458 347 347 449 459 347 348 449 349 348 347 450 449 348 554 450 348 348 349 554 349 442 554 349 439 442 349 436 439 556 443 350 350 351 556 686 556 351 569 454 352 352 561 569 454 453 352 356 355 353 358 357 354 472 358 354 354 360 472 354 359 360 568 566 355 355 356 568 588 568 356 356 584 588 356 361 584 475 365 357 357 358 475 476 475 358 478 476 358 358 472 478 465 360 359 360 471 472 360 466 471 360 465 466 361 362 363 361 363 584 363 469 584 363 364 469 470 469 364 477 366 365 365 475 477 488 483 368 368 382 488 384 382 368 618 384 368 368 369 618 369 604 618 605 604 369 369 379 605 381 379 369 370 377 482 371 372 373 484 373 372 489 484 372 594 490 373 596 594 373 373 484 596 486 378 374 375 383 385 488 383 375 375 483 488 602 482 377 377 601 602 377 386 601 707 609 378 378 610 707 378 485 610 486 485 378 379 492 605 379 487 492 379 380 487 381 380 379 382 383 488 384 383 382 498 385 383 726 498 383 383 384 726 384 721 726 722 721 384 384 618 722 497 387 385 498 497 385 613 601 386 386 389 613 499 493 387 500 499 387 387 497 500 719 613 389 389 390 719 391 390 389 395 391 389 724 719 390 725 724 390 390 391 725 748 725 391 391 747 748 391 399 747 391 395 399 392 506 509 393 625 630 393 623 625 395 396 399 396 398 399 401 398 396 400 399 398 508 400 398 510 508 398 398 401 510 399 400 747 400 508 754 955 747 400 400 754 955 401 402 510 631 510 402 634 631 402 402 403 634 403 527 634 403 519 527 403 409 519 407 406 404 514 407 404 405 516 626 405 515 516 406 407 410 517 410 407 407 514 517 525 515 408 409 518 519 409 410 518 520 518 410 530 520 410 410 521 530 410 517 521 633 413 411 958 633 411 413 412 411 412 413 414 633 628 413 643 414 413 413 629 643 413 628 629 531 416 414 532 531 414 643 532 414 415 416 535 416 533 535 416 531 533 417 430 545 561 438 418 675 561 418 418 674 675 418 433 674 434 433 418 419 424 435 549 424 419 419 420 549 421 420 419 1032 853 420 420 421 1032 420 537 549 853 537 420 421 570 1032 424 423 422 435 424 422 422 427 435 429 427 422 540 429 422 422 423 540 423 424 550 423 539 540 550 539 423 424 549 550 427 426 425 435 427 425 437 436 426 426 428 437 426 427 428 429 428 427 541 437 428 542 541 428 428 429 542 660 542 429 429 657 660 429 540 657 430 432 545 553 432 431 679 553 431 553 545 432 858 674 433 433 852 858 433 546 852 436 437 439 441 439 437 547 441 437 437 541 547 439 441 442 680 679 440 681 680 440 440 556 681 440 443 556 552 442 441 441 551 552 441 547 551 442 452 554 555 452 442 678 555 442 442 552 678 444 560 562 445 448 560 462 448 445 445 455 462 579 448 446 693 579 446 694 693 446 446 590 694 446 447 590 448 447 446 447 585 590 447 463 585 447 462 463 447 448 462 579 560 448 460 459 449 461 460 449 449 450 461 572 461 450 450 563 572 450 451 563 452 451 450 554 452 450 564 563 451 575 564 451 684 575 451 451 682 684 683 682 451 451 555 683 451 452 555 466 465 453 473 466 453 453 454 473 454 569 687 690 473 454 454 687 690 463 462 455 455 456 463 457 456 455 458 457 455 467 463 456 468 467 456 580 468 456 581 580 456 456 457 581 457 576 581 457 458 576 458 459 576 582 576 459 459 464 582 459 460 464 460 461 464 577 464 461 461 572 577 463 467 585 464 577 582 474 471 466 466 473 474 591 585 467 467 468 591 468 586 591 587 586 468 468 580 587 698 584 469 903 698 469 469 470 903 470 480 903 592 472 471 702 592 471 471 589 702 471 474 589 592 478 472 578 474 473 690 578 473 699 589 474 474 578 699 593 477 475 475 486 593 475 485 486 475 476 485 704 485 476 476 478 704 593 479 477 707 704 478 478 705 707 478 592 705 480 715 903 480 481 715 481 697 715 481 602 697 481 482 602 711 596 484 484 607 711 484 489 607 704 610 485 617 492 487 489 606 607 489 494 606 490 595 600 490 594 595 491 609 617 616 605 492 492 615 616 933 615 492 492 932 933 492 617 932 611 494 493 493 499 611 611 606 494 502 501 495 612 502 495 495 608 612 495 496 608 496 600 608 620 500 497 727 620 497 497 498 727 498 726 727 621 611 499 499 500 621 730 621 500 500 619 730 620 619 500 735 734 501 501 502 735 737 623 501 501 733 737 734 733 501 502 729 735 502 728 729 502 622 728 502 612 622 509 507 503 503 504 509 505 504 503 743 505 503 511 509 504 504 505 511 513 511 505 739 513 505 744 739 505 505 743 744 506 507 509 508 510 631 508 631 754 513 512 511 632 514 512 758 632 512 512 513 758 513 757 758 513 739 757 632 517 514 637 516 515 515 525 637 755 626 516 516 523 755 524 523 516 637 524 516 522 521 517 635 522 517 517 632 635 529 519 518 518 520 529 519 526 527 795 526 519 519 529 795 644 529 520 645 644 520 646 645 520 520 530 646 521 522 530 638 530 522 522 635 638 957 755 523 523 773 957 523 524 773 524 771 773 524 637 771 771 637 525 525 639 771 973 780 526 526 795 973 528 527 526 780 528 526 527 528 634 1121 759 528 528 780 1121 528 631 634 759 631 528 796 795 529 529 644 796 650 646 530 530 642 650 530 638 642 534 533 531 653 534 531 531 532 653 643 629 532 792 653 532 532 629 792 822 813 534 823 822 534 534 816 823 534 653 816 849 839 536 536 846 849 859 846 536 536 853 859 536 537 853 538 537 536 839 538 536 550 549 537 537 538 550 538 539 550 665 539 538 839 665 538 665 540 539 664 657 540 665 664 540 541 543 547 541 542 543 544 543 542 662 544 542 542 661 662 542 660 661 551 547 543 668 551 543 543 544 668 544 667 668 544 663 667 544 662 663 545 553 669 546 548 852 548 671 852 673 552 551 854 673 551 856 854 551 551 667 856 668 667 551 552 672 678 673 672 552 873 864 553 553 865 873 553 679 865 862 669 553 864 862 553 555 672 683 678 672 555 556 557 681 686 557 556 557 878 898 557 567 878 686 567 557 557 558 681 559 558 557 868 559 557 898 868 557 558 559 870 1036 681 558 558 869 1036 870 869 558 559 868 870 579 562 560 676 569 561 561 675 676 571 570 562 579 571 562 573 572 563 563 564 573 575 573 564 567 566 565 878 567 565 898 878 565 565 887 898 565 566 887 566 692 887 566 568 692 568 588 692 884 687 569 569 676 884 570 571 1032 1359 1358 571 1364 1359 571 1365 1364 571 571 886 1365 571 693 886 571 579 693 1179 1032 571 1180 1179 571 1358 1180 571 691 577 572 572 574 691 572 573 574 688 574 573 573 575 688 696 691 574 574 688 696 689 688 575 575 684 689 582 581 576 695 582 577 577 691 695 884 699 578 578 690 884 580 581 583 899 587 580 580 583 899 581 582 583 695 583 582 583 891 899 583 695 891 692 588 584 698 692 584 701 590 585 585 591 701 700 591 586 710 700 586 915 710 586 918 915 586 586 587 918 1065 918 587 587 899 1065 904 702 589 589 699 904 708 694 590 590 703 708 590 701 703 591 700 701 706 705 592 592 702 706 713 595 594 714 713 594 594 712 714 594 596 712 713 600 595 596 711 712 717 599 597 728 717 597 597 723 728 597 598 723 599 598 597 1089 723 598 598 1080 1089 598 599 1080 599 717 718 1081 1080 599 1391 1081 599 599 1213 1391 599 943 1213 599 718 943 728 608 600 600 717 728 718 717 600 600 713 718 603 602 601 719 603 601 601 613 719 602 603 697 925 697 603 603 719 925 938 618 604 940 938 604 604 616 940 604 605 616 716 607 606 934 716 606 935 934 606 606 611 935 920 711 607 921 920 607 607 716 921 622 612 608 728 622 608 932 617 609 609 705 932 707 705 609 610 704 707 611 731 935 611 621 731 614 615 926 616 615 614 720 616 614 914 720 614 926 914 614 933 926 615 616 720 940 938 722 618 736 730 619 942 736 619 619 620 942 620 941 942 620 727 941 732 731 621 736 732 621 621 730 736 737 625 623 624 626 749 744 743 624 745 744 624 749 745 624 752 630 625 625 738 752 625 737 738 755 749 626 965 962 627 627 958 965 627 628 958 629 628 627 962 629 627 628 633 958 629 761 792 629 760 761 962 760 629 753 751 630 630 752 753 759 754 631 636 635 632 758 636 632 769 638 635 635 636 769 770 769 636 636 758 770 638 640 642 641 640 638 769 641 638 782 771 639 788 782 639 639 787 788 651 642 640 786 651 640 640 641 786 641 781 786 641 769 781 651 650 642 644 645 796 805 796 645 645 646 805 646 647 805 650 647 646 647 651 652 647 650 651 828 805 647 992 828 647 647 648 992 649 648 647 652 649 647 648 812 992 648 808 812 810 808 648 648 649 810 811 810 649 649 797 811 649 652 797 786 652 651 798 797 652 652 786 798 653 815 816 653 791 815 792 791 653 838 837 654 654 836 838 654 659 836 654 655 659 656 655 654 837 656 654 655 658 659 832 658 655 1004 832 655 1009 1004 655 655 656 1009 656 837 1009 657 658 660 659 658 657 664 659 657 661 660 658 832 661 658 659 664 836 666 662 661 835 666 661 661 833 835 661 832 833 666 663 662 663 666 835 1017 667 663 663 835 1017 840 836 664 664 665 840 665 839 840 1017 856 667 851 670 669 669 842 851 669 841 842 862 841 669 851 671 670 671 844 852 671 843 844 850 843 671 851 850 671 672 673 854 866 683 672 1031 866 672 672 854 1031 857 675 674 1029 857 674 674 858 1029 677 676 675 1037 677 675 675 857 1037 676 677 884 890 884 677 1037 890 677 871 865 679 679 680 871 879 871 680 680 681 879 1036 879 681 685 684 682 860 685 682 682 683 860 861 860 683 866 861 683 684 685 689 876 689 685 877 876 685 685 867 877 685 860 867 884 690 687 688 689 696 689 876 1038 1045 696 689 1046 1045 689 689 1038 1046 895 695 691 691 696 895 692 698 888 888 887 692 1047 886 693 693 694 1047 1055 1047 694 694 708 1055 892 891 695 895 892 695 1048 895 696 1049 1048 696 1050 1049 696 1051 1050 696 696 1045 1051 909 715 697 925 909 697 903 888 698 1073 904 699 699 901 1073 902 901 699 699 884 902 703 701 700 710 703 700 914 706 702 702 904 914 709 708 703 710 709 703 705 926 932 705 706 926 706 914 926 708 928 1055 708 927 928 708 709 927 1075 927 709 709 916 1075 709 710 916 710 915 916 922 712 711 711 920 922 910 714 712 912 910 712 922 912 712 923 718 713 713 714 923 1074 923 714 714 913 1074 714 910 913 909 903 715 930 921 716 934 930 716 718 923 943 931 925 719 719 724 931 1085 940 720 720 914 1085 937 936 721 721 722 937 941 726 721 1100 941 721 1232 1100 721 721 1231 1232 721 936 1231 938 937 722 729 728 723 949 729 723 1093 949 723 1094 1093 723 723 1089 1094 1090 931 724 724 725 1090 1095 1090 725 725 748 1095 941 727 726 949 945 729 729 734 735 945 734 729 1086 935 731 1088 1086 731 1229 1088 731 731 732 1229 732 736 1233 1234 1229 732 732 1233 1234 738 737 733 946 738 733 733 734 946 734 945 946 736 944 1233 736 942 944 948 752 738 738 947 948 738 946 947 739 744 745 739 740 757 741 740 739 742 741 739 745 742 739 758 757 740 740 741 758 1113 758 741 741 967 1113 741 742 967 1243 967 742 742 1107 1243 742 756 1107 742 745 756 745 749 756 746 747 955 748 747 746 950 748 746 955 950 746 1096 1095 748 748 950 1096 749 755 756 750 751 753 964 959 750 750 960 964 750 753 960 952 753 752 752 951 952 752 948 951 753 952 960 754 950 955 1241 950 754 754 1110 1241 754 1109 1110 1119 1109 754 754 759 1119 957 756 755 957 956 756 1111 1107 756 756 956 1111 1113 770 758 1121 1119 759 963 961 760 760 962 963 762 761 760 961 762 760 761 783 792 761 763 783 761 762 763 764 763 762 948 764 762 961 948 762 763 765 783 763 764 765 766 765 764 778 766 764 779 778 764 948 779 764 765 774 783 765 766 774 766 768 774 766 767 768 778 767 766 971 784 767 767 778 971 784 768 767 775 774 768 784 775 768 974 781 769 769 770 974 1113 967 770 770 966 974 967 966 770 771 772 773 782 772 771 1120 773 772 1122 1120 772 772 782 1122 1112 957 773 1114 1112 773 1115 1114 773 1120 1115 773 799 783 774 800 799 774 774 776 800 774 775 776 777 776 775 785 777 775 793 785 775 794 793 775 775 784 794 986 800 776 776 802 986 776 777 802 777 785 802 778 969 971 970 969 778 778 779 970 779 947 970 948 947 779 1123 1121 780 1124 1123 780 780 973 1124 798 786 781 1128 798 781 1129 1128 781 781 974 1129 782 789 1122 782 788 789 799 792 783 972 794 784 784 971 972 785 793 802 790 788 787 982 790 787 787 806 982 790 789 788 1260 1122 789 1261 1260 789 789 1130 1261 789 790 1130 790 982 1130 983 815 791 791 827 983 791 792 827 792 799 827 807 802 793 793 794 807 977 807 794 794 972 977 976 973 795 795 796 976 981 976 796 796 805 981 817 811 797 1126 817 797 797 798 1126 1128 1126 798 799 826 827 986 826 799 799 800 986 807 804 801 801 802 807 803 802 801 804 803 801 802 985 986 802 984 985 802 803 984 803 989 1140 803 804 989 1138 984 803 1276 1138 803 1285 1276 803 803 1284 1285 803 1282 1284 803 1277 1282 803 1140 1277 990 989 804 1132 990 804 804 1131 1132 804 807 1131 987 981 805 805 828 987 806 814 982 807 977 1131 829 812 808 830 829 808 808 809 830 810 809 808 809 819 830 809 810 819 810 818 819 810 817 818 810 811 817 993 992 812 998 993 812 999 998 812 812 829 999 822 814 813 988 982 814 814 822 988 824 816 815 996 824 815 815 983 996 824 823 816 820 818 817 1126 820 817 831 819 818 991 831 818 1134 991 818 818 821 1134 818 820 821 831 830 819 1126 821 820 1428 1134 821 1429 1428 821 821 1267 1429 821 1126 1267 822 823 988 1143 988 823 823 997 1143 823 996 997 823 824 996 825 826 986 827 826 825 983 827 825 1138 983 825 825 984 1138 985 984 825 986 985 825 828 978 987 1133 978 828 1273 1133 828 1289 1273 828 828 992 1289 829 830 999 1000 999 830 830 994 1000 830 831 994 831 991 994 834 833 832 1004 834 832 833 834 835 1005 835 834 834 1004 1005 835 1011 1017 835 1007 1011 1157 1007 835 835 1005 1157 840 839 836 839 838 836 1311 1009 837 837 1309 1311 1310 1309 837 837 1152 1310 837 838 1152 1156 1152 838 838 1012 1156 838 839 1012 839 849 1012 1020 842 841 1162 1020 841 841 1027 1162 841 862 1027 842 843 850 1023 843 842 842 1021 1023 842 1020 1021 842 850 851 845 844 843 1023 845 843 1029 852 844 844 845 1029 1030 1029 845 1176 1030 845 845 1163 1176 845 1023 1163 846 847 849 848 847 846 859 848 846 1156 849 847 847 1013 1156 1014 1013 847 847 848 1014 1016 1014 848 1325 1016 848 848 1024 1325 848 859 1024 1156 1012 849 1029 858 852 1032 1025 853 1025 859 853 1164 1031 854 1165 1164 854 854 855 1165 856 855 854 1173 1165 855 1329 1173 855 855 1018 1329 855 856 1018 856 1017 1018 1345 1037 857 857 1330 1345 857 1176 1330 857 1030 1176 857 1029 1030 1025 1024 859 860 863 867 860 861 863 885 863 861 861 866 885 862 864 1027 885 867 863 1034 1026 864 864 873 1034 864 1026 1027 865 872 873 865 871 872 1174 885 866 866 1031 1174 1182 877 867 867 885 1182 898 870 868 1186 1036 869 869 1041 1186 869 896 1041 869 870 896 898 896 870 874 872 871 880 874 871 871 879 880 872 875 1035 872 874 875 1035 873 872 1035 1034 873 880 875 874 875 880 1035 1044 1043 876 1182 1044 876 876 877 1182 1043 1038 876 1039 880 879 879 1036 1039 1188 1035 880 880 881 1188 1039 881 880 883 882 881 1039 883 881 1357 1188 881 881 1193 1357 881 882 1193 882 883 1187 882 1187 1193 883 1039 1187 1054 902 884 884 889 1054 890 889 884 1348 1182 885 1482 1348 885 885 1338 1482 885 1164 1338 1174 1164 885 1373 1365 886 886 1372 1373 886 1059 1372 886 1047 1059 887 897 898 1192 897 887 1201 1192 887 887 1052 1201 887 888 1052 888 907 1052 888 903 907 1351 1054 889 889 890 1351 890 1181 1351 890 1037 1181 900 899 891 891 893 900 891 892 893 894 893 892 895 894 892 1194 900 893 1195 1194 893 893 894 1195 894 1048 1195 894 895 1048 896 1040 1041 1183 1040 896 1196 1183 896 896 897 1196 898 897 896 897 1192 1196 1197 1065 899 1198 1197 899 899 1194 1198 899 900 1194 1215 1073 901 1521 1215 901 901 1370 1521 901 902 1370 902 1190 1496 902 1054 1190 1371 1370 902 1495 1371 902 1496 1495 902 903 905 907 906 905 903 909 906 903 1073 914 904 1053 907 905 1056 1053 905 1057 1056 905 905 908 1057 905 906 908 909 908 906 1053 1052 907 1205 1057 908 1206 1205 908 1208 1206 908 908 1082 1208 908 909 1082 909 924 1082 925 924 909 910 911 913 912 911 910 1071 913 911 911 912 1071 1074 1071 912 912 922 1074 913 1071 1074 914 1084 1085 1214 1084 914 914 1073 1214 917 916 915 919 917 915 915 918 919 1078 1075 916 916 1077 1078 916 917 1077 917 934 1077 917 930 934 917 929 930 917 919 929 929 919 918 930 929 918 1061 930 918 918 1060 1061 1065 1060 918 920 921 922 1067 922 921 921 1066 1067 921 1064 1066 921 1061 1064 921 930 1061 922 1067 1074 1074 943 923 924 931 1087 924 925 931 1083 1082 924 1087 1083 924 933 932 926 927 1075 1078 1078 928 927 1059 1055 928 928 1058 1059 1078 1058 928 1090 1087 931 1086 1077 934 934 935 1086 936 937 938 936 1228 1231 936 939 1228 936 938 939 940 939 938 1393 1228 939 939 1084 1393 939 940 1084 1085 1084 940 1100 942 941 1100 944 942 943 1210 1213 943 1209 1210 943 1074 1209 1234 1233 944 944 1076 1234 1101 1076 944 944 1100 1101 945 949 953 1108 946 945 945 954 1108 945 953 954 970 947 946 1108 970 946 961 951 948 1102 953 949 949 1093 1102 1241 1096 950 961 952 951 963 960 952 952 961 963 953 1102 1105 1105 954 953 954 969 1108 1106 969 954 954 1105 1106 956 1112 1246 956 957 1112 1246 1111 956 968 965 958 958 959 968 959 964 968 960 963 964 964 963 962 965 964 962 964 965 968 1256 974 966 966 1243 1256 966 967 1243 1244 971 969 1254 1244 969 969 1252 1254 1253 1252 969 1404 1253 969 969 1106 1404 969 970 1108 1244 972 971 1264 977 972 972 1250 1264 1251 1250 972 1254 1251 972 972 1244 1254 973 975 1124 976 975 973 1257 1129 974 974 1256 1257 1265 1124 975 1421 1265 975 975 979 1421 975 976 979 976 981 987 976 978 979 987 978 976 1264 1131 977 980 979 978 1133 980 978 1425 1421 979 979 980 1425 980 1133 1425 982 988 1130 1142 996 983 983 1138 1142 1143 1130 988 989 990 1139 989 1139 1140 990 1132 1270 1270 1139 990 1134 994 991 992 993 1289 1291 1289 993 993 1147 1291 993 1002 1147 993 998 1002 1001 1000 994 1148 1001 994 994 1134 1148 995 996 1142 997 996 995 1141 997 995 1146 1141 995 995 1142 1146 1145 1143 997 997 1141 1145 998 999 1002 999 1000 1003 1150 1002 999 999 1003 1150 1000 1001 1003 1148 1003 1001 1149 1147 1002 1150 1149 1002 1151 1150 1003 1297 1151 1003 1003 1148 1297 1010 1005 1004 1312 1010 1004 1004 1009 1312 1005 1010 1157 1006 1153 1460 1155 1153 1006 1006 1007 1155 1008 1007 1006 1462 1008 1006 1627 1462 1006 1822 1627 1006 1006 1460 1822 1157 1155 1007 1007 1008 1011 1019 1011 1008 1159 1019 1008 1463 1159 1008 1008 1462 1463 1009 1311 1312 1010 1155 1157 1010 1154 1155 1312 1154 1010 1019 1017 1011 1158 1156 1013 1013 1015 1158 1013 1014 1015 1016 1015 1014 1160 1158 1015 1015 1016 1160 1324 1160 1016 1325 1324 1016 1019 1018 1017 1470 1329 1018 1018 1159 1470 1018 1019 1159 1168 1161 1020 1020 1162 1168 1022 1021 1020 1161 1022 1020 1322 1023 1021 1021 1321 1322 1021 1022 1321 1467 1321 1022 1022 1161 1467 1336 1163 1023 1023 1322 1336 1327 1325 1024 1024 1169 1327 1024 1025 1169 1025 1032 1169 1178 1033 1026 1026 1034 1178 1028 1027 1026 1033 1028 1026 1166 1162 1027 1027 1028 1166 1167 1166 1028 1343 1167 1028 1028 1033 1343 1031 1164 1174 1177 1169 1032 1339 1177 1032 1032 1179 1339 1344 1343 1033 1033 1178 1344 1034 1035 1178 1483 1178 1035 1035 1189 1483 1035 1188 1189 1186 1039 1036 1345 1181 1037 1191 1046 1038 1038 1043 1191 1039 1186 1187 1040 1184 1492 1040 1183 1184 1042 1041 1040 1492 1042 1040 1041 1042 1186 1187 1186 1042 1492 1187 1042 1043 1044 1353 1356 1191 1043 1043 1353 1356 1044 1182 1353 1199 1051 1045 1200 1199 1045 1045 1046 1200 1046 1191 1200 1047 1055 1059 1368 1195 1048 1048 1049 1368 1378 1368 1049 1510 1378 1049 1517 1510 1049 1049 1050 1517 1050 1380 1517 1050 1051 1380 1051 1379 1380 1051 1199 1379 1052 1053 1201 1203 1201 1053 1053 1056 1203 1351 1190 1054 1205 1203 1056 1056 1057 1205 1058 1386 1682 1387 1386 1058 1058 1220 1387 1058 1078 1220 1507 1059 1058 1058 1506 1507 1529 1506 1058 1682 1529 1058 1507 1372 1059 1063 1061 1060 1374 1063 1060 1060 1202 1374 1060 1065 1202 1061 1062 1064 1063 1062 1061 1069 1064 1062 1070 1069 1062 1204 1070 1062 1062 1063 1204 1374 1204 1063 1079 1066 1064 1064 1069 1079 1065 1197 1202 1068 1067 1066 1079 1068 1066 1067 1072 1074 1067 1068 1072 1079 1072 1068 1212 1079 1069 1530 1212 1069 1531 1530 1069 1069 1525 1531 1069 1070 1525 1675 1525 1070 1070 1204 1675 1209 1074 1072 1072 1079 1209 1215 1214 1073 1076 1077 1225 1078 1077 1076 1394 1078 1076 1076 1101 1394 1076 1225 1234 1229 1225 1077 1077 1088 1229 1077 1086 1088 1221 1220 1078 1222 1221 1078 1394 1222 1078 1212 1209 1079 1397 1089 1080 1080 1081 1397 1081 1396 1397 1081 1391 1396 1082 1207 1208 1082 1083 1207 1224 1207 1083 1083 1091 1224 1083 1087 1091 1084 1214 1393 1087 1090 1091 1540 1094 1089 1089 1397 1540 1092 1091 1090 1227 1092 1090 1090 1095 1227 1091 1092 1224 1092 1216 1224 1218 1216 1092 1223 1218 1092 1541 1223 1092 1545 1541 1092 1092 1226 1545 1227 1226 1092 1103 1102 1093 1093 1094 1103 1230 1103 1094 1540 1230 1094 1238 1227 1095 1095 1096 1238 1096 1110 1238 1241 1110 1096 1099 1098 1097 1536 1099 1097 1097 1400 1536 1097 1399 1400 1542 1399 1097 1097 1231 1542 1402 1231 1097 1097 1098 1402 1098 1099 1543 1403 1402 1098 1543 1403 1098 1099 1222 1543 1536 1222 1099 1104 1101 1100 1232 1104 1100 1101 1237 1402 1101 1104 1237 1403 1394 1101 1101 1402 1403 1240 1105 1102 1102 1230 1240 1102 1103 1230 1104 1232 1237 1240 1236 1105 1235 1106 1105 1236 1235 1105 1106 1235 1404 1406 1243 1107 1107 1111 1406 1118 1110 1109 1245 1118 1109 1109 1121 1245 1109 1119 1121 1408 1238 1110 1110 1116 1408 1118 1116 1110 1407 1406 1111 1111 1246 1407 1112 1114 1246 1114 1115 1247 1247 1246 1114 1115 1120 1248 1248 1247 1115 1717 1408 1116 1732 1717 1116 1116 1117 1732 1118 1117 1116 1117 1724 1732 1725 1724 1117 1117 1242 1725 1117 1118 1242 1245 1242 1118 1120 1122 1248 1121 1123 1245 1260 1248 1122 1255 1245 1123 1123 1125 1255 1123 1124 1125 1265 1125 1124 1259 1255 1125 1420 1259 1125 1125 1265 1420 1422 1267 1126 1126 1127 1422 1128 1127 1126 1127 1129 1257 1127 1128 1129 1742 1422 1127 1127 1412 1742 1127 1257 1412 1130 1136 1261 1144 1136 1130 1130 1143 1144 1266 1132 1131 1131 1264 1266 1132 1266 1270 1133 1281 1425 1133 1273 1281 1428 1148 1134 1137 1136 1135 1275 1137 1135 1135 1274 1275 1435 1274 1135 1135 1145 1435 1135 1144 1145 1135 1136 1144 1136 1137 1261 1565 1261 1137 1137 1275 1565 1276 1142 1138 1278 1140 1139 1279 1278 1139 1139 1271 1279 1139 1270 1271 1278 1277 1140 1293 1145 1141 1141 1146 1293 1276 1146 1142 1145 1144 1143 1145 1292 1435 1293 1292 1145 1294 1293 1146 1146 1276 1294 1296 1291 1147 1147 1149 1296 1298 1297 1148 1299 1298 1148 1428 1299 1148 1149 1150 1296 1301 1296 1150 1150 1151 1301 1305 1301 1151 1307 1305 1151 1151 1297 1307 1152 1158 1310 1152 1156 1158 1155 1154 1153 1153 1154 1460 1623 1460 1154 1154 1459 1623 1154 1457 1459 1154 1312 1457 1313 1310 1158 1314 1313 1158 1315 1314 1158 1316 1315 1158 1466 1316 1158 1158 1160 1466 1159 1463 1470 1160 1324 1466 1161 1332 1467 1161 1168 1332 1332 1168 1162 1335 1332 1162 1472 1335 1162 1162 1167 1472 1162 1166 1167 1163 1175 1176 1336 1175 1163 1164 1170 1338 1172 1170 1164 1173 1172 1164 1164 1165 1173 1167 1343 1472 1169 1177 1327 1487 1338 1170 1170 1485 1487 1170 1171 1485 1172 1171 1170 1171 1347 1485 1171 1342 1347 1171 1172 1342 1346 1342 1172 1172 1340 1346 1341 1340 1172 1172 1331 1341 1172 1173 1331 1173 1329 1331 1330 1176 1175 1337 1330 1175 1175 1326 1337 1328 1326 1175 1336 1328 1175 1339 1179 1177 1478 1327 1177 1177 1179 1478 1483 1344 1178 1480 1478 1179 1179 1479 1480 1179 1180 1479 1180 1358 1479 1181 1480 1490 1181 1345 1480 1352 1351 1181 1490 1352 1181 1182 1349 1488 1182 1348 1349 1488 1353 1182 1185 1184 1183 1196 1185 1183 1184 1185 1491 1650 1492 1184 1184 1491 1650 1185 1369 1381 1185 1196 1369 1185 1381 1491 1360 1193 1187 1494 1360 1187 1187 1493 1494 1187 1492 1493 1354 1189 1188 1357 1354 1188 1652 1483 1189 1189 1361 1652 1189 1357 1361 1189 1354 1357 1190 1351 1363 1190 1363 1496 1356 1200 1191 1369 1196 1192 1381 1369 1192 1192 1201 1381 1360 1357 1193 1375 1198 1194 1194 1366 1375 1194 1195 1366 1367 1366 1195 1368 1367 1195 1374 1202 1197 1197 1198 1374 1375 1374 1198 1511 1379 1199 1199 1200 1511 1512 1511 1200 1200 1356 1512 1201 1203 1381 1384 1381 1203 1385 1384 1203 1203 1205 1385 1204 1382 1675 1204 1374 1382 1388 1385 1205 1389 1388 1205 1205 1206 1389 1206 1208 1389 1390 1208 1207 1207 1217 1390 1207 1216 1217 1224 1216 1207 1390 1389 1208 1211 1210 1209 1212 1211 1209 1395 1213 1210 1538 1395 1210 1210 1211 1538 1211 1532 1534 1211 1212 1532 1539 1538 1211 1211 1534 1539 1212 1530 1532 1395 1391 1213 1401 1393 1214 1214 1219 1401 1214 1215 1219 1521 1219 1215 1218 1217 1216 1217 1389 1390 1392 1389 1217 1217 1218 1392 1398 1392 1218 1218 1223 1398 1219 1386 1401 1682 1386 1219 1219 1529 1682 1219 1521 1529 1220 1221 1387 1400 1387 1221 1536 1400 1221 1221 1222 1536 1222 1394 1543 1535 1398 1223 1541 1535 1223 1225 1229 1234 1914 1706 1226 1226 1239 1914 1226 1238 1239 1226 1227 1238 1551 1545 1226 1705 1551 1226 1706 1705 1226 1542 1231 1228 1697 1542 1228 1228 1401 1697 1228 1393 1401 1540 1240 1230 1402 1232 1231 1402 1237 1232 1235 1236 1404 1236 1540 1550 1236 1240 1540 1405 1404 1236 1550 1405 1236 1408 1239 1238 1921 1914 1239 1239 1717 1921 1239 1408 1717 1242 1410 1725 1242 1245 1410 1258 1256 1243 1406 1258 1243 1411 1410 1245 1245 1255 1411 1246 1247 1407 1553 1407 1247 1247 1249 1553 1247 1248 1249 1260 1249 1248 1555 1553 1249 1249 1414 1555 1415 1414 1249 1416 1415 1249 1249 1260 1416 1250 1262 1264 1263 1262 1250 1269 1263 1250 1250 1251 1269 1418 1269 1251 1419 1418 1251 1558 1419 1251 1251 1417 1558 1251 1254 1417 1556 1254 1252 1730 1556 1252 1252 1253 1730 1253 1405 1730 1253 1404 1405 1556 1417 1254 1255 1259 1411 1258 1257 1256 1413 1412 1257 1257 1409 1413 1257 1258 1409 1258 1406 1409 1741 1411 1259 1259 1560 1741 1259 1420 1560 1260 1261 1416 1565 1416 1261 1266 1264 1262 1262 1263 1266 1268 1266 1263 1269 1268 1263 1560 1420 1265 1265 1421 1560 1424 1270 1266 1426 1424 1266 1266 1268 1426 1585 1429 1267 1267 1422 1585 1579 1426 1268 1268 1423 1579 1268 1269 1423 1269 1418 1423 1272 1271 1270 1572 1272 1270 1576 1572 1270 1270 1424 1576 1427 1279 1271 1271 1272 1427 1433 1427 1272 1571 1433 1272 1572 1571 1272 1273 1280 1281 1289 1280 1273 1430 1275 1274 1587 1430 1274 1770 1587 1274 1274 1440 1770 1274 1435 1440 1275 1563 1565 1275 1431 1563 1275 1430 1431 1442 1294 1276 1447 1442 1276 1276 1285 1447 1287 1282 1277 1277 1278 1287 1278 1286 1287 1278 1279 1286 1432 1286 1279 1279 1427 1432 1590 1281 1280 1280 1290 1590 1280 1289 1290 1584 1425 1281 1281 1583 1584 1590 1583 1281 1288 1284 1282 1282 1287 1288 1599 1598 1283 1283 1284 1599 1285 1284 1283 1598 1285 1283 1601 1599 1284 1605 1601 1284 1284 1288 1605 1598 1447 1285 1432 1287 1286 1437 1288 1287 1287 1432 1437 1288 1604 1605 1288 1437 1604 1291 1290 1289 1591 1590 1290 1290 1291 1591 1291 1296 1591 1292 1295 1435 1292 1293 1295 1293 1294 1295 1300 1295 1294 1442 1300 1294 1441 1435 1295 1295 1300 1441 1779 1591 1296 1296 1603 1779 1296 1439 1603 1296 1301 1439 1297 1298 1307 1308 1307 1298 1298 1299 1308 1594 1308 1299 1299 1428 1594 1609 1441 1300 1300 1442 1609 1301 1306 1439 1301 1305 1306 1778 1603 1302 1806 1778 1302 1811 1806 1302 1302 1303 1811 1304 1303 1302 1306 1304 1302 1439 1306 1302 1603 1439 1302 1815 1811 1303 1303 1614 1815 1303 1304 1614 1304 1454 1614 1304 1452 1454 1304 1306 1452 1452 1306 1305 1305 1448 1452 1449 1448 1305 1305 1307 1449 1453 1449 1307 1307 1308 1453 1456 1453 1308 1308 1450 1456 1451 1450 1308 1594 1451 1308 1313 1311 1309 1309 1310 1313 1458 1312 1311 1311 1313 1458 1458 1457 1312 1624 1458 1313 1313 1314 1624 1314 1461 2053 1314 1315 1461 1626 1624 1314 1829 1626 1314 1843 1829 1314 2053 1843 1314 1315 1319 1461 1315 1316 1319 1320 1319 1316 1465 1320 1316 1316 1464 1465 1316 1317 1464 1318 1317 1316 1466 1318 1316 1317 1336 1464 1317 1324 1336 1317 1318 1324 1466 1324 1318 1825 1461 1319 1319 1320 1825 1320 1823 1825 1824 1823 1320 1320 1465 1824 1323 1322 1321 1468 1323 1321 1321 1467 1468 1464 1336 1322 1322 1323 1464 1465 1464 1323 1631 1465 1323 1633 1631 1323 1323 1469 1633 1323 1468 1469 1324 1328 1336 1324 1325 1328 1325 1326 1328 1327 1326 1325 1326 1327 1337 1473 1337 1327 1480 1473 1327 1327 1478 1480 1471 1331 1329 1329 1470 1471 1480 1345 1330 1330 1473 1480 1330 1337 1473 1471 1341 1331 1332 1333 1467 1334 1333 1332 1335 1334 1332 1469 1467 1333 1632 1469 1333 1635 1632 1333 1333 1334 1635 1334 1477 1635 1334 1335 1477 1335 1343 1477 1472 1343 1335 1487 1482 1338 1639 1346 1340 1340 1341 1639 1341 1471 1637 1341 1638 1639 1341 1637 1638 1342 1346 1347 1343 1344 1477 1641 1477 1344 1344 1483 1641 1484 1476 1346 1642 1484 1346 1346 1639 1642 1476 1347 1346 1347 1481 1485 1347 1476 1481 1640 1350 1348 1348 1482 1640 1350 1349 1348 1349 1350 1646 1646 1488 1349 1350 1850 1855 1350 1640 1850 1855 1646 1350 1351 1352 1363 1479 1363 1352 1490 1479 1352 1353 1355 1356 1488 1355 1353 1504 1356 1355 1648 1504 1355 1355 1488 1648 1661 1512 1356 1356 1502 1661 1504 1502 1356 1357 1360 1361 1358 1359 1647 1358 1363 1479 1647 1363 1358 1359 1364 1647 1360 1494 1515 1362 1361 1360 1515 1362 1360 1665 1652 1361 1361 1505 1665 1361 1362 1505 1516 1505 1362 1362 1515 1516 1647 1496 1363 1656 1496 1364 1364 1497 1656 1364 1365 1497 1364 1496 1647 1365 1373 1497 1383 1375 1366 1501 1383 1366 1366 1367 1501 1367 1376 1501 1377 1376 1367 1378 1377 1367 1367 1368 1378 1522 1521 1370 1370 1371 1522 1371 1508 1522 1371 1495 1508 1508 1373 1372 1372 1507 1508 1508 1497 1373 1374 1375 1383 1383 1382 1374 1659 1501 1376 1376 1377 1659 1660 1659 1377 1377 1509 1660 1377 1378 1509 1510 1509 1378 1519 1380 1379 1379 1511 1519 1871 1517 1380 1380 1679 1871 1380 1676 1679 1380 1518 1676 1519 1518 1380 1513 1491 1381 1514 1513 1381 1381 1384 1514 1382 1498 1675 1382 1383 1498 1666 1498 1383 1383 1659 1666 1383 1501 1659 1384 1385 1514 1385 1388 1514 1687 1401 1386 1386 1387 1687 1387 1399 1687 1400 1399 1387 1524 1514 1388 1526 1524 1388 1388 1389 1526 1528 1526 1389 1389 1392 1528 1391 1395 1396 1690 1528 1392 1392 1398 1690 1394 1403 1543 1537 1396 1395 1538 1537 1395 1396 1537 1548 1549 1397 1396 1396 1548 1549 1550 1540 1397 1397 1549 1550 1398 1689 1690 1398 1535 1689 1700 1687 1399 1399 1542 1700 1401 1687 1697 1923 1730 1405 1405 1918 1923 1405 1549 1918 1550 1549 1405 1406 1407 1409 1412 1409 1407 1728 1412 1407 1407 1727 1728 1733 1727 1407 1407 1552 1733 1553 1552 1407 1409 1412 1413 1941 1725 1410 1948 1941 1410 1410 1411 1948 1957 1948 1411 1411 1741 1957 1412 1728 1742 1942 1555 1414 1949 1942 1414 1414 1737 1949 1414 1415 1737 1415 1566 1737 1415 1562 1566 1415 1416 1562 1563 1562 1416 1565 1563 1416 1417 1557 1558 1559 1557 1417 1731 1559 1417 1417 1556 1731 1575 1423 1418 1418 1574 1575 1418 1569 1574 1418 1419 1569 1419 1568 1569 1738 1568 1419 1419 1557 1738 1558 1557 1419 1561 1560 1421 1564 1561 1421 1421 1425 1564 1743 1585 1422 1422 1742 1743 1423 1578 1579 1423 1575 1578 1424 1426 1579 1579 1576 1424 1758 1564 1425 1425 1584 1758 1434 1432 1427 1427 1433 1434 1428 1429 1594 1429 1586 1594 1429 1585 1586 1979 1431 1430 1980 1979 1430 1430 1769 1980 1430 1587 1769 1431 1562 1563 1566 1562 1431 1567 1566 1431 1744 1567 1431 1979 1744 1431 1432 1434 1437 1577 1434 1433 1581 1577 1433 1582 1581 1433 1971 1582 1433 1433 1970 1971 1433 1573 1970 1433 1571 1573 1577 1437 1434 1441 1440 1435 1438 1437 1436 1802 1438 1436 1436 1589 1802 1436 1437 1589 1437 1438 1604 1437 1588 1589 1437 1577 1588 1801 1604 1438 1802 1801 1438 1782 1770 1440 1440 1441 1782 1441 1607 1782 1608 1607 1441 1609 1608 1441 1442 1443 1609 1444 1443 1442 1600 1444 1442 1442 1447 1600 1443 1608 1609 1443 1446 1608 1443 1445 1446 1443 1444 1445 1776 1445 1444 1444 1596 1776 1600 1596 1444 1610 1446 1445 1613 1610 1445 1784 1613 1445 1445 1776 1784 1446 1607 1608 1610 1607 1446 1447 1598 1600 1454 1452 1448 1614 1454 1448 1615 1614 1448 1448 1455 1615 1448 1449 1455 1449 1453 1455 2012 1456 1450 2013 2012 1450 1450 1997 2013 1450 1451 1997 1451 1781 1997 1451 1780 1781 1451 1594 1780 1812 1621 1453 1453 1456 1812 1616 1455 1453 1621 1616 1453 1616 1615 1455 2012 1812 1456 1622 1459 1457 1457 1458 1622 1630 1622 1458 1458 1625 1630 1458 1624 1625 1826 1623 1459 1832 1826 1459 1459 1831 1832 1459 1629 1831 1459 1622 1629 1827 1822 1460 1460 1826 1827 1460 1623 1826 2200 2053 1461 1461 1825 2200 1627 1463 1462 1628 1470 1463 1463 1627 1628 2036 1824 1465 1465 1631 2036 1469 1468 1467 1469 1632 1633 1628 1475 1470 1474 1471 1470 1475 1474 1470 1471 1474 1637 2042 1637 1474 1474 1475 2042 1475 1628 1828 1475 1834 2042 1475 1833 1834 1475 1828 1833 1489 1481 1476 1476 1484 1489 1477 1634 1635 1641 1634 1477 1490 1480 1479 1486 1485 1481 1489 1486 1481 1850 1640 1482 1854 1850 1482 1482 1487 1854 1853 1641 1483 1858 1853 1483 1483 1652 1858 1642 1489 1484 1485 1486 1487 1644 1487 1486 1645 1644 1486 1486 1643 1645 1486 1642 1643 1486 1489 1642 1857 1854 1487 1859 1857 1487 1487 1644 1859 1488 1646 1648 1491 1513 1650 1657 1493 1492 1492 1650 1657 1658 1494 1493 1493 1657 1658 1865 1667 1494 1494 1658 1865 1667 1515 1494 1656 1508 1495 1495 1496 1656 1497 1508 1656 1498 1499 1675 1500 1499 1498 1666 1500 1498 1882 1675 1499 1499 1500 1882 1666 1660 1500 1500 1868 1882 1870 1868 1500 1500 1660 1870 1873 1661 1502 1502 1862 1873 1502 1861 1862 1502 1503 1861 1504 1503 1502 1503 1860 1861 1503 1648 1860 1503 1504 1648 1668 1665 1505 1505 1516 1668 1508 1507 1506 1521 1508 1506 1529 1521 1506 1508 1521 1522 1509 1510 1660 1871 1660 1510 1510 1517 1871 1523 1519 1511 1511 1520 1523 1511 1512 1520 1661 1520 1512 1864 1650 1513 2074 1864 1513 2084 2074 1513 1513 1514 2084 1514 1524 2084 1667 1516 1515 1516 1667 1674 1674 1668 1516 1518 1523 1676 1518 1519 1523 1672 1523 1520 1673 1672 1520 1520 1661 1673 1680 1676 1523 1523 1672 1680 1686 1685 1524 1524 1526 1686 2248 2084 1524 2257 2248 1524 1524 1890 2257 1524 1685 1890 1896 1531 1525 1897 1896 1525 1899 1897 1525 1525 1675 1899 1526 1527 1686 1528 1527 1526 1527 1528 1688 1691 1686 1527 1527 1688 1691 1528 1690 1695 1695 1688 1528 1534 1532 1530 1530 1533 1534 1530 1531 1533 1898 1533 1531 1531 1896 1898 1546 1534 1533 1909 1546 1533 1533 1898 1909 1544 1539 1534 1546 1544 1534 1696 1689 1535 1699 1696 1535 1535 1541 1699 1537 1538 1547 1537 1547 1548 1538 1539 1547 1713 1547 1539 1539 1544 1713 1705 1699 1541 1541 1545 1705 1542 1697 1700 1544 1707 1713 1544 1701 1707 1544 1546 1701 1545 1551 1705 1910 1701 1546 1546 1909 1910 1916 1548 1547 1917 1916 1547 1547 1713 1917 1918 1549 1548 1923 1918 1548 1924 1923 1548 2106 1924 1548 1548 1916 2106 1552 1554 1733 1552 1553 1554 1555 1554 1553 1554 1727 1733 1942 1727 1554 1554 1555 1942 1556 1730 1731 1739 1738 1557 1740 1739 1557 1557 1559 1740 1943 1740 1559 1944 1943 1559 1559 1731 1944 1560 1561 1741 1966 1741 1561 1561 1751 1966 1561 1564 1751 1758 1751 1564 1566 1567 1737 1968 1967 1567 2121 1968 1567 1567 1744 2121 1950 1737 1567 2120 1950 1567 2286 2120 1567 1567 1967 2286 1570 1569 1568 2113 1570 1568 1568 1951 2113 1568 1943 1951 1568 1739 1943 1568 1738 1739 1569 1570 1745 1975 1574 1569 1569 1959 1975 1569 1745 1959 1570 2113 2125 2125 1745 1570 1749 1573 1571 1571 1572 1749 1572 1576 1749 1573 1962 1970 1573 1746 1962 1749 1746 1573 1578 1575 1574 1580 1578 1574 1757 1580 1574 1981 1757 1574 1574 1975 1981 1750 1749 1576 1969 1750 1576 1576 1580 1969 1576 1579 1580 1577 1581 1588 1580 1579 1578 2126 1969 1580 1580 1757 2126 1581 1582 1755 1602 1588 1581 1754 1602 1581 1755 1754 1581 1582 1971 2135 2135 1755 1582 1764 1756 1583 1772 1764 1583 1984 1772 1583 1583 1766 1984 1583 1590 1766 1756 1584 1583 1759 1758 1584 1584 1756 1759 1585 1743 1752 1760 1586 1585 1585 1752 1760 1780 1594 1586 1586 1761 1780 1586 1760 1761 1587 1768 1769 1770 1768 1587 1588 1592 1777 1593 1592 1588 1602 1593 1588 1777 1589 1588 1589 1788 1802 1789 1788 1589 1589 1777 1789 1767 1766 1590 1590 1765 1767 1590 1591 1765 1773 1765 1591 1779 1773 1591 1592 1593 2145 1986 1777 1592 1991 1986 1592 2151 1991 1592 1592 2145 2151 1593 1602 1982 1593 1982 2145 1595 1596 1598 1597 1596 1595 1786 1597 1595 1595 1599 1786 1595 1598 1599 1600 1598 1596 1783 1776 1596 1596 1597 1783 1784 1783 1597 1785 1784 1597 2000 1785 1597 1597 1786 2000 2000 1786 1599 1599 1794 2000 1795 1794 1599 1599 1787 1795 1599 1601 1787 1601 1606 1787 1601 1605 1606 1602 1754 1982 1603 1778 1779 1801 1800 1604 1606 1605 1604 1799 1606 1604 1800 1799 1604 1799 1787 1606 1607 1612 1782 1607 1611 1612 1607 1610 1611 1613 1611 1610 2015 1612 1611 1611 1613 2015 1792 1782 1612 1612 1791 1792 2015 1791 1612 1613 2014 2015 1613 1809 2014 1613 1784 1809 1614 1618 1815 1614 1617 1618 1614 1615 1617 1620 1617 1615 1615 1616 1620 1621 1620 1616 1619 1618 1617 1620 1619 1617 2025 1815 1618 1618 1820 2025 1618 1619 1820 1619 1816 1820 1619 1620 1816 1620 1813 1816 1620 1621 1813 1621 1812 1813 1630 1629 1622 1626 1625 1624 1836 1630 1625 1625 1835 1836 1625 1829 1835 1625 1626 1829 1828 1628 1627 1627 1822 1828 1629 1830 1831 1629 1630 1830 1836 1830 1630 1631 1633 2036 1632 1840 1841 2046 1840 1632 1632 1636 2046 1632 1635 1636 1841 1633 1632 2037 2036 1633 1633 1841 2037 1634 1852 2064 1634 1851 1852 1634 1641 1851 1636 1635 1634 2064 1636 1634 1636 1840 2046 2209 1840 1636 2211 2209 1636 1636 2064 2211 2048 1638 1637 1637 2042 2048 1849 1639 1638 2048 1849 1638 1849 1642 1639 1853 1851 1641 1856 1643 1642 1642 1849 1856 2066 1645 1643 1643 1856 2066 1644 1645 2067 2232 1859 1644 1644 2067 2232 1645 2066 2067 1649 1648 1646 1855 1649 1646 1648 1649 1860 2068 1860 1649 1649 2065 2068 1649 1855 2065 1864 1657 1650 1875 1866 1651 1651 1665 1875 1651 1652 1665 1653 1652 1651 1866 1653 1651 1652 1654 1858 1652 1653 1654 1655 1654 1653 2246 1655 1653 1653 2076 2246 1653 1867 2076 1653 1866 1867 2070 1858 1654 1654 1655 2070 2245 2070 1655 2246 2245 1655 1865 1658 1657 2075 1865 1657 1657 2074 2075 1657 1864 2074 1659 1660 1666 1871 1870 1660 1872 1673 1661 1873 1872 1661 2248 2247 1662 1662 2084 2248 1662 2074 2084 1662 1663 2074 1664 1663 1662 2247 1664 1662 2075 2074 1663 1663 1865 2075 2249 1865 1663 1663 1664 2249 2425 2249 1664 2428 2425 1664 2654 2428 1664 1664 2653 2654 1664 2427 2653 1664 2247 2427 1665 1668 1875 1667 1865 1879 1875 1674 1667 1880 1875 1667 1667 1879 1880 1668 1674 1875 1893 1892 1669 2092 1893 1669 2093 2092 1669 2097 2093 1669 1669 1888 2097 1669 1677 1888 1886 1677 1669 1669 1670 1886 1671 1670 1669 1892 1671 1669 1670 1679 1886 1887 1679 1670 1670 1671 1887 2081 1887 1671 2091 2081 1671 1671 1892 2091 1672 1678 1680 1889 1678 1672 1672 1681 1889 1672 1673 1681 1877 1681 1673 1673 1872 1877 2085 1899 1675 1675 1882 2085 1676 1677 1679 1678 1677 1676 1680 1678 1676 1886 1679 1677 1677 1678 1888 1889 1888 1678 1887 1871 1679 1681 1683 1889 1684 1683 1681 1877 1684 1681 1901 1889 1683 1683 1684 1901 2259 1901 1684 2261 2259 1684 1684 2090 2261 1684 1902 2090 1684 1878 1902 1684 1877 1878 1685 1686 1691 1894 1890 1685 1895 1894 1685 1904 1895 1685 1685 1691 1904 1700 1697 1687 1692 1691 1688 1694 1692 1688 1695 1694 1688 1689 1696 1907 1698 1690 1689 1907 1698 1689 1698 1695 1690 1691 1702 1904 1691 1692 1702 1692 1693 1702 1694 1693 1692 1703 1702 1693 1708 1703 1693 1709 1708 1693 1711 1709 1693 1693 1694 1711 1712 1711 1694 1694 1704 1712 1694 1695 1704 1695 1698 1704 1696 1699 1705 1696 1705 1907 1907 1704 1698 1922 1707 1701 2264 1922 1701 1701 1910 2264 1702 1903 1904 1702 1703 1903 1906 1903 1703 1703 1708 1906 1907 1712 1704 1912 1907 1705 1705 1908 1912 1705 1706 1908 2103 1908 1706 1706 1914 2103 1714 1713 1707 1922 1714 1707 2270 1906 1708 1708 1911 2270 1708 1710 1911 1708 1709 1710 1715 1710 1709 1709 1711 1715 1710 1718 1911 1710 1715 1718 1711 1712 1715 1716 1715 1712 1912 1716 1712 1712 1907 1912 1713 1714 1917 2105 1917 1714 1714 1922 2105 1721 1718 1715 1722 1721 1715 1715 1716 1722 1716 1919 1920 1716 1913 1919 1716 1912 1913 1920 1722 1716 1928 1921 1717 1717 1732 1928 2104 1911 1718 1718 1719 2104 1720 1719 1718 1721 1720 1718 2109 2104 1719 1719 1940 2109 1719 1720 1940 1945 1940 1720 1720 1723 1945 1720 1721 1723 1721 1722 1723 1726 1723 1722 1920 1726 1722 1723 1935 1945 1936 1935 1723 1937 1936 1723 1723 1931 1937 1932 1931 1723 1723 1726 1932 1938 1732 1724 1939 1938 1724 1947 1939 1724 1724 1941 1947 1724 1725 1941 1933 1932 1726 1726 1920 1933 1729 1728 1727 1949 1729 1727 1727 1942 1949 1728 2120 2285 1728 1950 2120 1728 1729 1950 1958 1742 1728 2285 1958 1728 1729 1949 1950 1929 1731 1730 1730 1923 1929 1731 1930 1944 1731 1929 1930 1938 1928 1732 2124 1958 1734 1734 1752 2124 2130 1752 1734 2287 2130 1734 1734 1735 2287 1736 1735 1734 1958 1736 1734 1735 2713 2717 1735 2293 2713 2294 2293 1735 1735 1736 2294 2493 2287 1735 2727 2493 1735 1735 2717 2727 1736 2286 2294 1736 2285 2286 1736 1958 2285 1950 1949 1737 1739 1740 1943 1966 1957 1741 1753 1743 1742 1958 1753 1742 1753 1752 1743 2131 2121 1744 1744 1979 2131 2125 1959 1745 1748 1747 1746 1960 1748 1746 1746 1750 1960 1746 1749 1750 1746 1747 1962 1747 1748 1961 1747 1961 1962 2122 1961 1748 1748 1960 2122 1969 1960 1750 1972 1966 1751 1973 1972 1751 1751 1758 1973 2130 1760 1752 1752 1753 2124 1753 1958 2124 2137 1982 1754 1754 2136 2137 1754 2135 2136 1754 1755 2135 1763 1759 1756 1771 1763 1756 1756 1764 1771 2296 2126 1757 1757 2132 2296 1757 1981 2132 1758 1762 1973 1758 1759 1762 1763 1762 1759 2130 1761 1760 1781 1780 1761 2143 1781 1761 1761 2130 2143 1977 1973 1762 2141 1977 1762 2327 2141 1762 1762 2147 2327 1762 2146 2147 1762 1763 2146 2148 2146 1763 2159 2148 1763 1763 2152 2159 1763 1993 2152 1763 1771 1993 1992 1771 1764 1764 1983 1992 1764 1772 1983 1985 1767 1765 1765 1773 1985 2149 1984 1766 2153 2149 1766 1766 2150 2153 1766 1767 2150 1767 1985 2150 1774 1769 1768 1793 1774 1768 1768 1792 1793 1768 1770 1792 1769 1775 1980 1769 1774 1775 1770 1782 1792 1771 1992 1993 2149 1983 1772 1772 1984 2149 1987 1985 1773 1988 1987 1773 1773 1779 1988 1989 1775 1774 2002 1989 1774 1774 1793 2002 2142 1980 1775 1775 1990 2142 1775 1989 1990 1776 1783 1784 1986 1789 1777 1790 1779 1778 1806 1790 1778 1779 1807 1988 1779 1790 1807 1999 1997 1781 2143 1999 1781 1784 1808 1809 1784 1785 1808 2017 1808 1785 2022 2017 1785 2183 2022 1785 1785 2170 2183 1785 2000 2170 1799 1795 1787 1804 1802 1788 1788 1803 1804 1788 1789 1803 1805 1803 1789 1996 1805 1789 1789 1986 1996 1790 1806 1807 1793 1792 1791 2001 1793 1791 2016 2001 1791 1791 2015 2016 1793 2001 2002 2171 2000 1794 1794 2004 2171 1794 1798 2004 1794 1795 1798 1799 1798 1795 2020 2003 1796 1796 2019 2020 2021 2019 1796 1796 2005 2021 1796 1797 2005 1798 1797 1796 2003 1798 1796 1797 1798 1799 1797 1801 2005 1797 1800 1801 1797 1799 1800 1798 2003 2004 1801 1802 2005 1802 1804 2005 1810 1804 1803 1803 1805 1810 2021 2005 1804 1804 2006 2021 1804 1810 2006 2008 1810 1805 2172 2008 1805 2173 2172 1805 1805 1996 2173 2166 1807 1806 2167 2166 1806 1806 2011 2167 1806 1811 2011 2150 1987 1807 2160 2150 1807 2335 2160 1807 1807 2166 2335 1807 1987 1988 2017 1809 1808 2017 2014 1809 2007 2006 1810 2008 2007 1810 1811 1815 2011 1814 1813 1812 2012 1814 1812 2026 1816 1813 1813 1814 2026 2027 2026 1814 2193 2027 1814 2363 2193 1814 2536 2363 1814 1814 2524 2536 1814 2339 2524 1814 2013 2339 1814 2012 2013 2025 2011 1815 1821 1820 1816 2026 1821 1816 1817 2027 2031 1817 2026 2027 1817 1821 2026 1817 1818 1821 1819 1818 1817 2031 1819 1817 1818 1820 1821 2025 1820 1818 2194 2025 1818 1818 1819 2194 2195 2194 1819 1819 2031 2195 1833 1828 1822 1822 1827 1833 2199 1825 1823 1823 2197 2199 1823 2036 2197 1823 1824 2036 1825 2199 2200 1832 1827 1826 2041 1833 1827 1827 2033 2041 1827 1832 2033 1843 1835 1829 1837 1831 1830 1839 1837 1830 1830 1836 1839 2033 1832 1831 2040 2033 1831 1831 2038 2040 2039 2038 1831 1831 1837 2039 2041 1834 1833 2043 2042 1834 1834 2034 2043 2035 2034 1834 2202 2035 1834 1834 2041 2202 1838 1836 1835 1843 1838 1835 1836 1838 1839 1837 1846 2039 1837 1844 1846 1837 1839 1844 1845 1839 1838 1847 1845 1838 1838 1842 1847 1843 1842 1838 2045 1844 1839 1839 2044 2045 1839 1845 2044 2388 1841 1840 1840 2208 2388 2209 2208 1840 2388 2037 1841 1848 1847 1842 2054 1848 1842 2055 2054 1842 2058 2055 1842 2219 2058 1842 1842 2052 2219 2053 2052 1842 1842 1843 2053 2039 1846 1844 2210 2039 1844 1844 2045 2210 1845 1848 2044 1845 1847 1848 2047 2044 1848 2054 2047 1848 2048 1856 1849 1850 1854 2060 2060 1855 1850 2062 1852 1851 1851 2061 2062 1851 1853 2061 2211 2064 1852 2397 2211 1852 1852 2062 2397 1853 1858 2061 1854 1857 2223 2223 2060 1854 2225 2065 1855 1855 2060 2225 2217 2066 1856 1856 2048 2217 1857 1859 2222 1857 2222 2223 2070 2061 1858 2232 2222 1859 2068 1861 1860 1863 1862 1861 2068 1863 1861 1874 1873 1862 2072 1874 1862 1862 2071 2072 2244 2071 1862 1862 1863 2244 1863 2242 2244 1863 2068 2242 2078 1879 1865 2249 2078 1865 1876 1867 1866 1866 1875 1876 2080 2076 1867 1867 1876 2080 2085 1882 1868 1868 1883 2085 1884 1883 1868 1868 1869 1884 1870 1869 1868 2082 1884 1869 1869 1885 2082 1869 1870 1885 1870 1871 1885 1887 1885 1871 1878 1877 1872 1872 1874 1878 1872 1873 1874 2083 1878 1874 1874 2072 2083 1880 1876 1875 1876 1880 2080 2083 1902 1878 1879 2078 2079 1881 1880 1879 2079 1881 1879 2250 2080 1880 2253 2250 1880 1880 1881 2253 1881 2079 2253 1883 1891 2086 1883 1884 1891 2087 2085 1883 2091 2087 1883 1883 2086 2091 2082 1891 1884 1885 2081 2082 1885 1887 2081 2100 2097 1888 1888 1900 2100 1888 1889 1900 1901 1900 1889 2436 2257 1890 1890 1894 2436 1891 2082 2086 1892 2088 2091 2089 2088 1892 1892 1893 2089 2263 2089 1893 1893 2095 2263 2096 2095 1893 1893 2092 2096 1894 2434 2436 2435 2434 1894 1894 2262 2435 2442 2262 1894 1894 1895 2442 1895 1903 2442 1904 1903 1895 1896 1897 2087 2088 1898 1896 1896 2087 2088 1897 1899 2087 2094 1909 1898 1898 2088 2094 1899 2085 2087 2101 2100 1900 1900 1901 2101 2260 2101 1901 1901 2259 2260 2254 2090 1902 1902 2083 2254 1903 2262 2442 1903 1905 2262 1906 1905 1903 2668 2262 1905 2907 2668 1905 2913 2907 1905 1905 2447 2913 1905 1906 2447 2448 2447 1906 1906 2270 2448 1908 1926 1927 2103 1926 1908 1913 1912 1908 1919 1913 1908 1927 1919 1908 1915 1910 1909 2094 1915 1909 2265 2264 1910 1910 2263 2265 1910 1915 2263 2272 2270 1911 1911 2104 2272 1914 1926 2103 1914 1921 1926 1915 2094 2263 2108 2106 1916 2275 2108 1916 1916 1917 2275 2276 2275 1917 1917 2105 2276 1934 1920 1919 1919 1927 1934 1934 1933 1920 1921 1925 1926 1928 1925 1921 2264 2105 1922 1923 1924 1929 1930 1929 1924 2106 1930 1924 1925 1928 1938 1927 1926 1925 1938 1927 1925 1927 1933 1934 1939 1933 1927 1927 1938 1939 2107 1944 1930 1930 2106 2107 1931 1932 1939 1954 1937 1931 1931 1941 1954 1947 1941 1931 1931 1939 1947 1932 1933 1939 1946 1945 1935 1935 1936 1946 1952 1946 1936 1953 1952 1936 1936 1937 1953 1954 1953 1937 2280 2109 1940 1940 2111 2280 1940 1945 2111 1941 1948 1954 2110 1951 1943 1943 2107 2110 1943 1944 2107 2112 2111 1945 1945 1946 2112 2117 2112 1946 1946 1952 2117 1957 1954 1948 2114 2113 1951 2471 2114 1951 2472 2471 1951 1951 2470 2472 1951 2464 2470 1951 2283 2464 1951 2110 2283 2118 2117 1952 2292 2118 1952 1952 2127 2292 1952 2119 2127 1952 1955 2119 1952 1953 1955 1953 1954 1955 1956 1955 1954 1965 1956 1954 1954 1957 1965 1955 1963 2119 1955 1956 1963 1964 1963 1956 1972 1964 1956 1956 1965 1972 1966 1965 1957 2125 1975 1959 2123 2122 1960 1960 1969 2123 1961 2122 2289 2290 1962 1961 2291 2290 1961 1961 2289 2291 1971 1970 1962 2135 1971 1962 1962 2134 2135 2290 2134 1962 2138 2119 1963 2139 2138 1963 1963 1976 2139 1963 1964 1976 1964 1972 1976 1965 1966 1972 1967 1968 2294 2294 2286 1967 1968 2293 2294 2713 2293 1968 1968 2295 2713 1968 2121 2295 2126 2123 1969 2139 1976 1972 2300 2139 1972 2301 2300 1972 1972 1974 2301 1972 1973 1974 1977 1974 1973 2302 2301 1974 1974 1978 2302 1974 1977 1978 2132 1981 1975 2133 2132 1975 1975 2125 2133 2141 1978 1977 2306 2302 1978 1978 2141 2306 1979 1980 2131 2142 2131 1980 2317 2145 1982 1982 2137 2317 1995 1992 1983 2149 1995 1983 1985 1987 2150 2158 1996 1986 1986 1991 2158 2169 2156 1989 1989 2002 2169 2156 1990 1989 2310 2142 1990 1990 2157 2310 1990 2156 2157 2324 2158 1991 1991 2151 2324 1994 1993 1992 2163 1994 1992 1992 1995 2163 2164 2152 1993 1993 2162 2164 1993 1994 2162 2165 2162 1994 1994 2163 2165 2334 2163 1995 1995 2149 2334 2337 2173 1996 1996 2158 2337 2339 2013 1997 2524 2339 1997 2772 2524 1997 1997 2523 2772 1997 2510 2523 1997 1998 2510 1999 1998 1997 1998 2155 2510 1998 1999 2155 1999 2143 2155 2171 2170 2000 2168 2002 2001 2534 2168 2001 2001 2016 2534 2002 2168 2169 2020 2004 2003 2004 2175 2176 2004 2020 2175 2176 2171 2004 2023 2021 2006 2024 2023 2006 2006 2007 2024 2177 2024 2007 2007 2008 2177 2008 2172 2177 2009 2166 2167 2335 2166 2009 2345 2335 2009 2354 2345 2009 2009 2010 2354 2011 2010 2009 2167 2011 2009 2010 2025 2191 2010 2011 2025 2362 2354 2010 2010 2191 2362 2016 2015 2014 2022 2016 2014 2014 2017 2022 2016 2533 2534 2016 2347 2533 2016 2180 2347 2181 2180 2016 2016 2022 2181 2188 2187 2018 2189 2188 2018 2018 2019 2189 2020 2019 2018 2187 2020 2018 2019 2021 2189 2350 2175 2020 2020 2187 2350 2021 2023 2189 2186 2181 2022 2022 2183 2186 2357 2189 2023 2023 2024 2357 2024 2190 2357 2024 2178 2190 2024 2177 2178 2194 2191 2025 2192 2032 2027 2193 2192 2027 2032 2031 2027 2028 2378 2550 2028 2377 2378 2028 2029 2377 2030 2029 2028 2550 2030 2028 2029 2031 2377 2195 2031 2029 2196 2195 2029 2375 2196 2029 2029 2030 2375 2554 2375 2030 2555 2554 2030 2556 2555 2030 2030 2550 2556 2031 2032 2377 2032 2192 2378 2378 2377 2032 2201 2041 2033 2033 2040 2201 2387 2043 2034 2034 2386 2387 2034 2035 2386 2581 2386 2035 2035 2580 2581 2035 2380 2580 2035 2202 2380 2198 2197 2036 2036 2037 2198 2388 2198 2037 2206 2040 2038 2038 2205 2206 2038 2039 2205 2210 2205 2039 2379 2201 2040 2385 2379 2040 2040 2384 2385 2040 2206 2384 2041 2201 2202 2051 2048 2042 2042 2043 2051 2387 2051 2043 2047 2045 2044 2392 2210 2045 2045 2212 2392 2045 2047 2212 2047 2057 2212 2047 2056 2057 2047 2054 2056 2048 2049 2217 2051 2049 2048 2606 2217 2049 2049 2215 2606 2216 2215 2049 2049 2050 2216 2051 2050 2049 2050 2051 2387 2587 2216 2050 2050 2586 2587 2050 2387 2586 2382 2219 2052 2591 2382 2052 2052 2390 2591 2052 2204 2390 2052 2203 2204 2052 2053 2203 2053 2200 2203 2059 2056 2054 2054 2055 2059 2055 2058 2059 2220 2214 2056 2056 2059 2220 2214 2057 2056 2398 2212 2057 2057 2221 2398 2057 2214 2221 2213 2059 2058 2218 2213 2058 2393 2218 2058 2058 2219 2393 2229 2220 2059 2059 2213 2229 2060 2224 2225 2227 2224 2060 2060 2223 2227 2063 2062 2061 2243 2063 2061 2061 2070 2243 2601 2397 2062 2602 2601 2062 2062 2063 2602 2859 2602 2063 2063 2243 2859 2069 2068 2065 2225 2069 2065 2240 2067 2066 2404 2240 2066 2066 2399 2404 2066 2217 2399 2238 2232 2067 2240 2238 2067 2068 2069 2242 2418 2242 2069 2069 2413 2418 2069 2234 2413 2069 2226 2234 2069 2225 2226 2245 2243 2070 2073 2072 2071 2419 2073 2071 2071 2244 2419 2251 2083 2072 2072 2073 2251 2252 2251 2073 2424 2252 2073 2623 2424 2073 2073 2419 2623 2421 2246 2076 2426 2421 2076 2076 2250 2426 2076 2080 2250 2077 2428 2430 2077 2425 2428 2077 2078 2425 2079 2078 2077 2430 2079 2077 2078 2249 2425 2430 2253 2079 2086 2082 2081 2091 2086 2081 2083 2251 2254 2091 2088 2087 2088 2089 2094 2263 2094 2089 2438 2261 2090 2090 2255 2438 2090 2254 2255 2092 2093 2096 2268 2096 2093 2093 2267 2268 2093 2098 2267 2093 2097 2098 2266 2263 2095 2674 2266 2095 2095 2673 2674 2095 2096 2673 2096 2268 2444 2096 2672 2673 2096 2444 2672 2099 2098 2097 2100 2099 2097 2269 2267 2098 2098 2102 2269 2098 2099 2102 2258 2102 2099 2099 2100 2258 2100 2101 2258 2439 2258 2101 2101 2260 2439 2102 2258 2269 2274 2272 2104 2104 2109 2274 2105 2273 2276 2105 2271 2273 2105 2264 2271 2108 2107 2106 2107 2108 2110 2283 2110 2108 2108 2279 2283 2108 2275 2279 2278 2274 2109 2280 2278 2109 2281 2280 2111 2282 2281 2111 2111 2112 2282 2284 2282 2112 2112 2118 2284 2112 2117 2118 2113 2114 2115 2113 2115 2125 2471 2116 2114 2116 2115 2114 2314 2125 2115 2476 2314 2115 2115 2475 2476 2115 2116 2475 2116 2471 2712 2718 2475 2116 2945 2718 2116 3159 2945 2116 2116 2712 3159 2292 2284 2118 2129 2127 2119 2138 2129 2119 2286 2285 2120 2303 2295 2121 2121 2131 2303 2122 2288 2289 2122 2123 2288 2298 2288 2123 2123 2297 2298 2123 2126 2297 2487 2133 2125 2125 2314 2487 2126 2296 2297 2127 2128 2292 2129 2128 2127 2481 2292 2128 2729 2481 2128 2128 2498 2729 2128 2304 2498 2128 2129 2304 2305 2304 2129 2129 2138 2305 2144 2143 2130 2287 2144 2130 2131 2142 2303 2132 2133 2296 2486 2296 2133 2487 2486 2133 2320 2299 2134 2480 2320 2134 2134 2290 2480 2136 2135 2134 2299 2136 2134 2299 2137 2136 2321 2317 2137 2137 2299 2321 2318 2305 2138 2319 2318 2138 2138 2140 2319 2138 2139 2140 2300 2140 2139 2140 2300 2319 2141 2300 2306 2308 2300 2141 2490 2308 2141 2141 2327 2490 2310 2303 2142 2143 2144 2155 2494 2155 2144 2144 2493 2494 2144 2287 2493 2324 2151 2145 2145 2323 2324 2145 2317 2323 2148 2147 2146 2328 2327 2147 2509 2328 2147 2147 2148 2509 2148 2508 2509 2148 2159 2508 2149 2153 2334 2154 2153 2150 2160 2154 2150 2161 2159 2152 2164 2161 2152 2515 2334 2153 2153 2154 2515 2154 2330 2515 2516 2330 2154 2154 2160 2516 2744 2510 2155 2155 2494 2744 2341 2332 2156 2156 2169 2341 2332 2157 2156 2485 2310 2157 2157 2333 2485 2157 2332 2333 2520 2337 2158 2158 2517 2520 2158 2324 2517 2159 2161 2508 2160 2335 2516 2514 2508 2161 2518 2514 2161 2519 2518 2161 2161 2338 2519 2161 2174 2338 2161 2164 2174 2174 2164 2162 2344 2174 2162 2162 2165 2344 2334 2165 2163 2528 2344 2165 2165 2336 2528 2165 2334 2336 2340 2169 2168 2783 2340 2168 2168 2534 2783 2169 2340 2341 2170 2182 2183 2170 2176 2182 2170 2171 2176 2179 2177 2172 2185 2179 2172 2172 2173 2185 2337 2185 2173 2344 2338 2174 2350 2176 2175 2176 2350 2355 2349 2182 2176 2355 2349 2176 2179 2178 2177 2351 2190 2178 2178 2179 2351 2358 2351 2179 2179 2353 2358 2179 2352 2353 2179 2342 2352 2179 2185 2342 2801 2347 2180 2180 2535 2801 2180 2346 2535 2180 2181 2346 2181 2186 2346 2184 2183 2182 2348 2184 2182 2349 2348 2182 2183 2184 2346 2346 2186 2183 2535 2346 2184 2802 2535 2184 2184 2348 2802 2185 2337 2342 2356 2350 2187 2365 2356 2187 2187 2188 2365 2367 2365 2188 2188 2357 2367 2188 2189 2357 2367 2357 2190 2538 2367 2190 2190 2360 2538 2190 2359 2360 2190 2351 2359 2191 2194 2362 2192 2369 2378 2192 2193 2369 2193 2363 2369 2368 2362 2194 2549 2368 2194 2194 2372 2549 2194 2196 2372 2194 2195 2196 2375 2372 2196 2582 2390 2197 2590 2582 2197 2197 2389 2590 2197 2198 2389 2204 2199 2197 2390 2204 2197 2198 2388 2389 2203 2200 2199 2204 2203 2199 2380 2202 2201 2201 2379 2380 2207 2206 2205 2577 2207 2205 2205 2210 2577 2206 2383 2384 2206 2207 2383 2577 2383 2207 2391 2388 2208 2593 2391 2208 2208 2209 2593 2599 2593 2209 2209 2397 2599 2209 2211 2397 2578 2577 2210 2210 2392 2578 2596 2392 2212 2607 2596 2212 2212 2403 2607 2212 2398 2403 2235 2229 2213 2409 2235 2213 2213 2230 2409 2213 2218 2230 2231 2221 2214 2214 2228 2231 2214 2220 2228 2215 2395 2606 2215 2216 2395 2396 2395 2216 2597 2396 2216 2216 2587 2597 2608 2399 2217 2611 2608 2217 2217 2606 2611 2603 2230 2218 2218 2394 2603 2218 2393 2394 2219 2382 2393 2229 2228 2220 2221 2231 2398 2411 2223 2222 2222 2232 2411 2612 2227 2223 2223 2411 2612 2406 2226 2224 2224 2405 2406 2224 2227 2405 2226 2225 2224 2226 2233 2234 2406 2233 2226 2613 2405 2227 2227 2612 2613 2236 2231 2228 2228 2229 2236 2237 2236 2229 2229 2235 2237 2602 2409 2230 2230 2601 2602 2603 2601 2230 2403 2398 2231 2604 2403 2231 2605 2604 2231 2231 2415 2605 2231 2410 2415 2231 2236 2410 2412 2411 2232 2232 2241 2412 2232 2239 2241 2232 2238 2239 2401 2234 2233 2609 2401 2233 2233 2406 2609 2234 2402 2413 2234 2401 2402 2407 2237 2235 2408 2407 2235 2409 2408 2235 2236 2237 2410 2414 2410 2237 2237 2407 2414 2240 2239 2238 2619 2241 2239 2239 2417 2619 2239 2240 2417 2240 2416 2417 2240 2404 2416 2631 2412 2241 2632 2631 2241 2241 2619 2632 2418 2244 2242 2243 2616 2859 2625 2616 2243 2243 2420 2625 2243 2245 2420 2244 2418 2419 2421 2420 2245 2245 2246 2421 2247 2257 2436 2247 2248 2257 2657 2427 2247 2247 2436 2657 2250 2253 2426 2429 2254 2251 2644 2429 2251 2251 2252 2644 2645 2644 2252 2878 2645 2252 2252 2424 2878 2432 2431 2253 2253 2430 2432 2431 2426 2253 2256 2255 2254 2429 2256 2254 2255 2433 2438 2255 2256 2433 2441 2433 2256 2646 2441 2256 2256 2429 2646 2439 2269 2258 2439 2260 2259 2440 2439 2259 2259 2438 2440 2259 2261 2438 2667 2435 2262 2668 2667 2262 2266 2265 2263 2264 2265 2271 2682 2271 2265 2265 2266 2682 2915 2682 2266 2266 2674 2915 2267 2269 2443 2669 2268 2267 2267 2443 2669 2669 2444 2268 2269 2439 2443 2681 2448 2270 2270 2272 2681 2449 2273 2271 2682 2449 2271 2689 2681 2272 2272 2274 2689 2277 2276 2273 2450 2277 2273 2273 2449 2450 2691 2689 2274 2274 2459 2691 2274 2278 2459 2462 2279 2275 2275 2277 2462 2275 2276 2277 2463 2462 2277 2277 2450 2463 2461 2459 2278 2278 2281 2461 2278 2280 2281 2464 2283 2279 2279 2462 2464 2468 2461 2281 2281 2282 2468 2473 2468 2282 2282 2284 2473 2284 2292 2473 2288 2298 2477 2477 2289 2288 2477 2291 2289 2290 2291 2480 2484 2480 2291 2954 2484 2291 2291 2477 2954 2474 2473 2292 2481 2474 2292 2295 2482 2713 2295 2478 2482 2295 2303 2478 2311 2297 2296 2486 2311 2296 2477 2298 2297 2479 2477 2297 2297 2311 2479 2299 2320 2321 2300 2308 2319 2300 2301 2306 2301 2302 2306 2303 2310 2478 2507 2498 2304 2304 2305 2507 2305 2325 2507 2326 2325 2305 2305 2318 2326 2736 2501 2307 2307 2308 2736 2309 2308 2307 2501 2309 2307 2308 2309 2319 2308 2490 2736 2309 2318 2319 2326 2318 2309 2499 2326 2309 2502 2499 2309 2309 2501 2502 2485 2478 2310 2311 2312 2479 2313 2312 2311 2486 2313 2311 2954 2479 2312 2962 2954 2312 2312 2313 2962 2486 2315 2313 2313 2961 2962 2313 2315 2961 2314 2315 2487 2316 2315 2314 2476 2316 2314 2315 2486 2487 2315 2728 2961 2315 2316 2728 2952 2728 2316 2316 2945 2952 2316 2718 2945 2316 2476 2718 2317 2321 2323 2322 2321 2320 2504 2322 2320 2320 2497 2504 2320 2496 2497 2320 2489 2496 2320 2480 2489 2321 2322 2506 2506 2323 2321 2750 2506 2322 2322 2504 2750 2512 2324 2323 2323 2506 2512 2324 2512 2517 2753 2752 2325 2325 2326 2753 2743 2507 2325 2752 2743 2325 2762 2753 2326 2326 2513 2762 2326 2499 2513 2491 2490 2327 2327 2328 2491 2736 2491 2328 2328 2501 2736 2509 2501 2328 2331 2330 2329 2754 2331 2329 2755 2754 2329 2763 2755 2329 2329 2335 2763 2516 2335 2329 2329 2330 2516 2336 2334 2330 2330 2331 2336 2330 2334 2515 2785 2336 2331 2331 2769 2785 2331 2754 2769 2525 2511 2332 2332 2341 2525 2511 2333 2332 2734 2485 2333 2745 2734 2333 2333 2511 2745 2335 2522 2763 2335 2345 2522 2785 2528 2336 2343 2342 2337 2520 2343 2337 2529 2519 2338 2338 2344 2529 2527 2525 2340 2987 2527 2340 2340 2783 2987 2525 2341 2340 2342 2766 2779 2342 2343 2766 2777 2352 2342 2787 2777 2342 2342 2779 2787 2343 2520 2766 2531 2529 2344 2532 2531 2344 2344 2528 2532 2794 2522 2345 2345 2354 2794 2786 2533 2347 2801 2786 2347 3000 2802 2348 2348 2349 3000 3007 3000 2349 3008 3007 2349 2349 2355 3008 2356 2355 2350 2351 2358 2359 2780 2353 2352 2352 2777 2780 2795 2358 2353 2353 2780 2795 2354 2361 2794 2362 2361 2354 2355 2356 2807 2355 2807 3008 2356 2366 2807 2356 2365 2366 2539 2359 2358 2795 2539 2358 2540 2360 2359 2541 2540 2359 2359 2539 2541 2540 2538 2360 3251 2782 2361 2361 2542 3251 2361 2362 2542 2361 2782 2794 2362 2368 2542 2546 2369 2363 2363 2537 2546 2363 2536 2537 2364 2365 2370 2366 2365 2364 2807 2366 2364 3017 2807 2364 2364 2812 3017 2364 2810 2812 2364 2370 2810 2365 2367 2370 2538 2371 2367 2371 2370 2367 2544 2542 2368 2549 2544 2368 2546 2545 2369 2545 2378 2369 2370 2808 2810 2370 2371 2808 2371 2538 2540 2371 2547 2808 2371 2540 2547 2372 2373 2549 2374 2373 2372 2376 2374 2372 2372 2375 2376 2816 2549 2373 2373 2553 2816 2373 2374 2553 2374 2551 2553 2552 2551 2374 2374 2376 2552 2554 2376 2375 2554 2552 2376 3004 2550 2378 2378 2545 3004 2381 2380 2379 2385 2381 2379 2380 2381 2580 2381 2579 2580 2381 2384 2579 2385 2384 2381 2394 2393 2382 2595 2394 2382 2600 2595 2382 2382 2594 2600 2382 2591 2594 2577 2384 2383 2384 2577 2579 2586 2387 2386 2386 2584 2586 2386 2583 2584 2386 2581 2583 2391 2389 2388 2389 2588 2590 2589 2588 2389 2389 2391 2589 2390 2582 2592 2594 2591 2390 2390 2592 2594 2593 2589 2391 2857 2578 2392 2392 2596 2857 2394 2595 2603 3087 2606 2395 3395 3087 2395 2395 3392 3395 3393 3392 2395 3403 3393 2395 2395 2396 3403 2396 2598 3403 2396 2597 2598 2601 2599 2397 2608 2404 2399 2402 2401 2400 3086 2402 2400 2400 2863 3086 2400 2401 2863 2401 2609 2863 2864 2413 2402 3086 2864 2402 2860 2607 2403 2403 2604 2860 2608 2416 2404 2866 2610 2405 2405 2613 2866 2610 2406 2405 2610 2609 2406 2422 2414 2407 2423 2422 2407 2407 2408 2423 2408 2409 2617 2635 2423 2408 2408 2617 2635 2409 2602 2859 2859 2617 2409 2627 2415 2410 2410 2414 2627 2622 2612 2411 2411 2412 2622 2633 2622 2412 2412 2631 2633 2614 2418 2413 2864 2614 2413 2414 2422 2627 2618 2605 2415 2627 2618 2415 2858 2417 2416 2416 2611 2858 2416 2608 2611 2621 2619 2417 2865 2621 2417 2417 2861 2865 2417 2858 2861 2614 2419 2418 2419 2614 2623 2634 2625 2420 2420 2421 2634 2641 2634 2421 2421 2426 2641 2636 2627 2422 2422 2423 2636 2642 2636 2423 2648 2642 2423 2889 2648 2423 2423 2871 2889 2423 2635 2871 2424 2873 2878 2424 2623 2873 2663 2641 2426 2426 2647 2663 2426 2431 2647 2658 2653 2427 2427 2656 2658 2657 2656 2427 2428 2654 2655 2655 2430 2428 2429 2644 2646 2437 2432 2430 2660 2437 2430 2662 2660 2430 2430 2661 2662 2430 2659 2661 2430 2655 2659 2431 2437 2647 2431 2432 2437 2441 2438 2433 2657 2436 2434 2905 2657 2434 2906 2905 2434 2434 2664 2906 2434 2435 2664 2665 2664 2435 2667 2665 2435 2660 2647 2437 2909 2440 2438 2910 2909 2438 2438 2666 2910 2438 2441 2666 2446 2443 2439 2439 2440 2446 2909 2446 2440 2441 2646 3117 3127 2666 2441 2441 3117 3127 2912 2669 2443 3133 2912 2443 2443 2445 3133 2446 2445 2443 2444 2669 2672 2445 3130 3453 2445 2446 3130 3453 3133 2445 2446 3128 3130 2446 2909 3128 2447 2448 2913 2914 2913 2448 3465 2914 2448 2448 2681 3465 2463 2450 2449 2929 2463 2449 2449 2922 2929 2923 2922 2449 2449 2682 2923 2696 2684 2451 2451 2465 2696 2451 2452 2465 2453 2452 2451 2684 2453 2451 2452 2454 2465 2452 2453 2454 2455 2454 2453 2456 2455 2453 2685 2456 2453 2453 2678 2685 2453 2458 2678 2453 2457 2458 2684 2457 2453 2454 2455 2465 2455 2456 2465 2467 2465 2456 2685 2467 2456 2690 2683 2457 2692 2690 2457 2695 2692 2457 2457 2684 2695 2683 2458 2457 2458 2677 2678 2683 2677 2458 2930 2691 2459 2932 2930 2459 2459 2460 2932 2461 2460 2459 2936 2932 2460 2460 2704 2936 2460 2461 2704 2461 2468 2704 2470 2464 2462 2462 2469 2470 2462 2463 2469 2699 2469 2463 2928 2699 2463 2929 2928 2463 2465 2466 2696 2467 2466 2465 2698 2696 2466 2703 2698 2466 2466 2467 2703 2709 2703 2467 2710 2709 2467 2467 2685 2710 2468 2473 2704 2472 2470 2469 2711 2472 2469 2934 2711 2469 2469 2699 2934 2471 2711 2712 2471 2472 2711 2951 2704 2473 2473 2474 2951 2474 2714 2951 2474 2481 2714 2718 2476 2475 2477 2479 2954 2483 2482 2478 2485 2483 2478 2480 2488 2489 2480 2484 2488 2716 2714 2481 2955 2716 2481 2481 2729 2955 2967 2713 2482 2482 2483 2967 3211 2967 2483 2483 2734 3211 2483 2485 2734 2742 2488 2484 2966 2742 2484 2484 2954 2966 2495 2489 2488 2742 2495 2488 2489 2495 2496 2490 2491 2736 2494 2493 2492 2738 2494 2492 2959 2738 2492 2492 2727 2959 2492 2493 2727 2973 2744 2494 3220 2973 2494 2494 3197 3220 2494 2738 3197 2503 2496 2495 2735 2503 2495 2741 2735 2495 2742 2741 2495 2505 2497 2496 2496 2503 2505 2749 2504 2497 2756 2749 2497 2497 2748 2756 2497 2505 2748 2498 2507 2743 2739 2729 2498 2740 2739 2498 2743 2740 2498 2499 2508 2513 2499 2502 2508 2509 2508 2500 2500 2501 2509 2502 2501 2500 2508 2502 2500 2735 2505 2503 2504 2749 2750 2505 2735 2748 2506 2750 2759 2758 2512 2506 2759 2758 2506 2514 2513 2508 2744 2523 2510 2974 2745 2511 3231 2974 2511 2511 2526 3231 2511 2525 2526 2760 2517 2512 2512 2758 2760 2768 2762 2513 2513 2518 2768 2513 2514 2518 2760 2520 2517 2781 2768 2518 2784 2781 2518 2518 2521 2784 2518 2519 2521 2529 2521 2519 2520 2765 2766 2520 2760 2765 2791 2784 2521 2521 2529 2791 2794 2782 2522 2770 2763 2522 2782 2770 2522 2978 2772 2523 2523 2973 2978 2523 2744 2973 2772 2536 2524 2527 2526 2525 3516 3231 2526 3523 3516 2526 2526 2527 3523 3549 3523 2527 2527 3238 3549 2527 2987 3238 2785 2532 2528 2529 2530 2791 2531 2530 2529 2530 2790 2791 2796 2790 2530 2800 2796 2530 2994 2800 2530 2530 2531 2994 2531 2792 2994 2793 2792 2531 2531 2532 2793 2532 2785 2793 2783 2534 2533 2786 2783 2533 2802 2801 2535 2805 2537 2536 2986 2805 2536 2536 2772 2986 2537 2805 2806 3003 2546 2537 2537 2806 3003 2539 2795 3001 3013 2541 2539 3024 3013 2539 3255 3024 2539 3257 3255 2539 2539 3001 3257 2548 2547 2540 2540 2541 2548 2811 2548 2541 2541 2803 2811 2804 2803 2541 3013 2804 2541 2542 2543 3251 2544 2543 2542 2543 3016 3252 2543 3015 3016 2543 2809 3015 2543 2544 2809 3252 3251 2543 2544 2549 2809 2545 2546 3003 2545 3003 3004 2547 2548 2811 2811 2808 2547 2816 2809 2549 3033 2556 2550 2550 3004 3033 2823 2553 2551 2824 2823 2551 2827 2824 2551 2551 2557 2827 2551 2552 2557 2552 2554 2557 2823 2816 2553 2554 2555 2557 2827 2557 2555 2555 2826 2827 3289 2826 2555 2555 3288 3289 2555 2556 3288 2556 3033 3288 2558 2564 2567 2565 2564 2558 2838 2565 2558 2558 2834 2838 3065 2834 2558 3066 3065 2558 3067 3066 2558 2558 2559 3067 2560 2559 2558 2567 2560 2558 2559 2576 3067 2559 2560 2576 2560 2575 2576 2560 2567 2575 2567 2564 2561 2568 2567 2561 2561 2566 2568 2561 2562 2566 2563 2562 2561 2564 2563 2561 2571 2566 2562 2831 2571 2562 2562 2830 2831 2562 2563 2830 2563 2565 2830 2563 2564 2565 2833 2830 2565 2838 2833 2565 2569 2568 2566 2570 2569 2566 2571 2570 2566 2567 2568 2575 2844 2575 2568 2845 2844 2568 2568 2569 2845 2569 2570 2845 2570 2841 2845 2570 2572 2841 2570 2571 2572 2573 2572 2571 2837 2573 2571 2571 2831 2837 2842 2841 2572 2843 2842 2572 3358 2843 2572 2572 2573 3358 2573 3063 3358 2573 3061 3063 2573 3059 3061 2573 2837 3059 2574 2844 2846 2574 2575 2844 2576 2575 2574 2846 2576 2574 3360 3067 2576 2576 3068 3360 2576 2846 3068 2847 2579 2577 2577 2578 2847 2853 2847 2578 2854 2853 2578 2857 2854 2578 2852 2580 2579 2579 2847 2852 2585 2581 2580 2856 2585 2580 2580 2849 2856 3075 2849 2580 2580 2852 3075 2585 2583 2581 2855 2592 2582 2582 2590 2855 2585 2584 2583 2587 2586 2584 2597 2587 2584 2584 2585 2597 2856 2597 2585 2593 2590 2588 2588 2589 2593 2590 2593 2855 2855 2600 2592 2600 2594 2592 2593 2599 2855 2595 2600 2603 3391 2857 2596 2596 3081 3391 2596 2607 3081 2856 2598 2597 3858 3403 2598 3859 3858 2598 3864 3859 2598 2598 2849 3864 2856 2849 2598 2599 2601 2855 2600 2601 2603 2855 2601 2600 3082 2860 2604 2604 2605 3082 3083 3082 2605 2605 2618 3083 2858 2611 2606 3087 2858 2606 2607 3080 3081 2607 2860 3080 2609 2862 2863 2609 2610 2862 2866 2862 2610 2622 2613 2612 2872 2866 2613 2613 2622 2872 2624 2623 2614 2864 2624 2614 2615 2626 2870 2615 2625 2626 2615 2616 2625 2617 2616 2615 2870 2617 2615 2616 2617 2859 2869 2635 2617 2870 2869 2617 3094 3083 2618 2618 2882 3094 2618 2639 2882 2618 2627 2639 2619 2620 2632 2621 2620 2619 2893 2632 2620 2894 2893 2620 2620 2630 2894 2620 2621 2630 2621 2629 2630 2865 2629 2621 2874 2872 2622 2622 2633 2874 2623 2624 2873 3091 2873 2624 2624 2867 3091 2624 2864 2867 2868 2626 2625 2880 2868 2625 2625 2634 2880 3093 2870 2626 2626 2881 3093 2626 2868 2881 2627 2637 2639 2627 2636 2637 3421 2894 2628 2628 3420 3421 2628 3415 3420 2628 2629 3415 2630 2629 2628 2894 2630 2628 2629 3411 3415 2629 2865 3411 2640 2633 2631 2893 2640 2631 2631 2632 2893 2633 2640 2874 2634 2641 2880 2635 2869 2871 2636 2642 2643 2638 2637 2636 2643 2638 2636 2882 2639 2637 2637 2651 2882 2637 2638 2651 2652 2651 2638 2638 2643 2652 2884 2874 2640 2893 2884 2640 2887 2880 2641 2641 2663 2887 2642 2650 2652 2642 2648 2650 2652 2643 2642 3111 2646 2644 2644 3106 3111 2644 2645 3106 2645 2878 3106 2646 3111 3118 3118 3117 2646 2647 2660 2662 2647 2662 2663 3107 2650 2648 2648 2897 3107 2648 2896 2897 2648 2889 2896 3437 3108 2649 2649 3113 3437 2649 2650 3113 2651 2650 2649 3108 2651 2649 2650 3107 3113 2650 2651 2652 3109 2882 2651 2651 3108 3109 2653 2658 3112 2901 2654 2653 3112 2901 2653 2901 2655 2654 3441 2659 2655 2655 2901 3441 3112 2658 2656 3125 3112 2656 2656 3119 3125 2656 2657 3119 2657 2905 3119 2659 3441 3447 3447 2661 2659 2904 2663 2661 2661 2903 2904 3447 2903 2661 2663 2662 2661 2895 2888 2663 2904 2895 2663 2888 2887 2663 2664 2665 2906 2907 2906 2665 2665 2667 2907 3129 2910 2666 2666 3126 3129 3127 3126 2666 2667 2668 2907 2669 2670 2672 2671 2670 2669 2912 2671 2669 3137 2672 2670 2670 2926 3137 2670 2671 2926 2671 2925 2926 2671 2917 2925 2671 2912 2917 3135 2673 2672 3136 3135 2672 3137 3136 2672 3141 2674 2673 2673 3135 3141 2916 2915 2674 3141 2916 2674 2679 2678 2675 2918 2679 2675 3134 2918 2675 3460 3134 2675 2675 3144 3460 2675 3138 3144 2675 2676 3138 2677 2676 2675 2678 2677 2675 3456 3138 2676 2676 2921 3456 2676 2683 2921 2676 2677 2683 2678 2680 2685 2678 2679 2680 2687 2680 2679 2688 2687 2679 2918 2688 2679 2687 2685 2680 3466 3465 2681 2681 2689 3466 2682 2916 2923 2682 2915 2916 3143 2921 2683 2683 2690 3143 2700 2695 2684 2702 2700 2684 2684 2696 2702 2685 2686 2710 2687 2686 2685 3152 2710 2686 2686 3147 3152 2686 2919 3147 2686 2688 2919 2686 2687 2688 2688 2918 2919 2689 2927 3466 2689 2691 2927 2690 3132 3143 2690 3131 3132 2690 2925 3131 2690 2692 2925 2930 2927 2691 2926 2925 2692 2692 2693 2926 2694 2693 2692 2695 2694 2692 3142 2926 2693 2693 2924 3142 2693 2694 2924 2931 2924 2694 2694 2701 2931 2694 2695 2701 2695 2700 2701 2949 2702 2696 2950 2949 2696 2696 2697 2950 2698 2697 2696 3166 2950 2697 3167 3166 2697 2697 2708 3167 2697 2698 2708 2698 2703 2708 3151 2934 2699 2699 2928 3151 2707 2701 2700 2948 2707 2700 2700 2702 2948 2947 2931 2701 2701 2707 2947 2949 2948 2702 2942 2708 2703 2703 2935 2942 2703 2709 2935 2943 2936 2704 2944 2943 2704 2951 2944 2704 2705 2946 2947 2705 2939 2946 3170 2939 2705 2705 2706 3170 2707 2706 2705 2947 2707 2705 3171 3170 2706 3172 3171 2706 2706 2707 3172 2707 3161 3172 2707 2948 3161 2942 2941 2708 2708 2940 3167 2941 2940 2708 3158 2935 2709 3474 3158 2709 2709 3153 3474 2709 2710 3153 2710 3152 3153 2711 2934 3155 3155 2712 2711 3175 3159 2712 3477 3175 2712 2712 3157 3477 2712 3155 3157 2959 2717 2713 2967 2959 2713 2714 2715 2951 2716 2715 2714 3173 2951 2715 3487 3173 2715 2715 3176 3487 2715 2716 3176 3177 3176 2716 2716 2955 3177 2959 2727 2717 3198 2961 2728 2728 2960 3198 2728 2952 2960 2968 2955 2729 2729 2739 2968 2734 2745 3211 2735 2747 2748 2970 2747 2735 2735 2969 2970 2735 2741 2969 2738 2959 2967 2738 2967 3197 3216 2968 2739 2739 2971 3216 2739 2761 2971 2739 2740 2761 2740 2751 2761 2740 2743 2751 3212 2969 2741 2741 2742 3212 2966 2963 2742 2742 3187 3212 2742 2963 3187 2752 2751 2743 2745 2974 3211 2746 2747 3234 2748 2747 2746 2764 2748 2746 2979 2764 2746 2983 2979 2746 3540 2983 2746 2746 3525 3540 2746 3524 3525 3526 3524 2746 2746 3234 3526 2747 2970 3222 2747 3222 3234 2764 2756 2748 2756 2750 2749 2750 2757 2759 2750 2756 2757 2972 2761 2751 2980 2972 2751 2751 2752 2980 2752 2753 2767 2752 2767 2980 2753 2762 2767 2981 2769 2754 2754 2771 2981 2754 2755 2771 2755 2770 2771 2755 2763 2770 2773 2757 2756 2756 2764 2773 2757 2773 2774 2774 2759 2757 2776 2760 2758 2758 2774 2776 2758 2759 2774 2779 2765 2760 2787 2779 2760 2760 2776 2787 2972 2971 2761 2762 2768 2781 2781 2767 2762 2979 2773 2764 2779 2766 2765 2985 2980 2767 2767 2781 2985 2793 2785 2769 3256 2793 2769 3541 3256 2769 2769 2981 3541 2982 2771 2770 2770 2782 2982 3236 2981 2771 2771 2982 3236 2772 2978 2986 2979 2775 2773 2775 2774 2773 2984 2776 2774 2774 2775 2984 2775 2979 2983 3244 2984 2775 3542 3244 2775 3550 3542 2775 2775 3240 3550 2775 3239 3240 2775 2983 3239 2776 2777 2787 2778 2777 2776 3244 2778 2776 2776 2984 3244 3001 2780 2777 3245 3001 2777 2777 2778 3245 2778 3241 3245 3243 3241 2778 3244 3243 2778 3001 2795 2780 2992 2985 2781 2781 2788 2992 2781 2784 2788 3251 2982 2782 2783 2786 2987 2790 2788 2784 2791 2790 2784 2991 2987 2786 2995 2991 2786 2786 2801 2995 2993 2992 2788 2788 2789 2993 2790 2789 2788 3248 2993 2789 2789 2797 3248 2789 2796 2797 2789 2790 2796 3249 2994 2792 3256 3249 2792 2792 2793 3256 2799 2798 2796 2800 2799 2796 2798 2797 2796 3261 3248 2797 3262 3261 2797 2797 2798 3262 2798 2996 3258 2798 2799 2996 3586 3262 2798 2798 3258 3586 3002 2996 2799 2799 2800 3002 3249 3002 2800 2800 2994 3249 2997 2995 2801 2999 2997 2801 2801 2802 2999 3000 2999 2802 2815 2811 2803 2803 2804 2815 3018 2815 2804 3275 3018 2804 2804 3024 3275 2804 3013 3024 2805 2986 2990 2990 2806 2805 3259 3003 2806 2806 3253 3259 2806 2990 3253 3009 3008 2807 3011 3009 2807 3017 3011 2807 2814 2810 2808 2808 2811 2814 2809 2818 3015 2809 2816 2818 2810 2814 2817 2813 2812 2810 3031 2813 2810 2810 2817 3031 2815 2814 2811 3021 3017 2812 3022 3021 2812 2812 2813 3022 3274 3022 2813 3290 3274 2813 3293 3290 2813 2813 3031 3293 2814 2815 2817 3030 2817 2815 3277 3030 2815 2815 3023 3277 2815 3018 3023 2819 2818 2816 2823 2819 2816 2817 3030 3031 2818 3014 3015 2818 2819 3014 3273 3014 2819 2819 3027 3273 2819 2823 3027 2820 2824 3037 2820 2821 2824 2822 2821 2820 3040 2822 2820 2820 3039 3040 2820 2828 3039 2829 2828 2820 3037 2829 2820 3035 2824 2821 2821 3020 3035 3034 3020 2821 2821 2822 3034 3302 3034 2822 2822 3040 3302 3029 3027 2823 2823 3019 3029 3020 3019 2823 3035 3020 2823 2823 2824 3035 2824 2827 3037 2827 2826 2825 3036 2827 2825 3289 3036 2825 2825 2826 3289 2827 3036 3037 3640 3039 2828 2828 2829 3640 2829 3037 3640 2832 2831 2830 2833 2832 2830 2831 2836 2837 2831 2832 2836 3053 2836 2832 3058 3053 2832 2832 3056 3058 2832 2833 3056 2833 2835 3056 2833 2834 2835 2838 2834 2833 2834 3065 3357 3357 2835 2834 3057 3056 2835 3695 3057 2835 2835 3357 3695 3059 2837 2836 2836 3054 3059 2836 3048 3054 2836 3046 3048 3053 3046 2836 2845 2841 2839 2839 2844 2845 2839 2840 2844 2841 2840 2839 2846 2844 2840 3070 2846 2840 3073 3070 2840 2840 3069 3073 2840 2841 3069 2841 2842 3069 3715 3069 2842 2842 2843 3715 2843 3358 3715 3070 3068 2846 2847 2851 2852 2853 2851 2847 2848 2849 3075 2850 2849 2848 3857 2850 2848 4494 3857 2848 2848 3388 4494 2848 3075 3388 2849 2850 3864 5040 3864 2850 2850 4484 5040 4485 4484 2850 2850 3857 4485 3079 2852 2851 3389 3079 2851 2851 3077 3389 2851 3076 3077 2851 2854 3076 2851 2853 2854 3388 3075 2852 2852 3079 3388 2854 2857 3076 3391 3076 2857 3087 2861 2858 3410 3080 2860 2860 3082 3410 3411 2865 2861 2861 3406 3411 2861 3087 3406 2877 2863 2862 2862 2866 2877 2863 2877 3086 3086 2867 2864 2866 2875 2877 2866 2872 2875 3417 3091 2867 2867 3089 3417 2867 3086 3089 2888 2881 2868 2868 2887 2888 2868 2880 2887 2869 2870 2871 3093 2871 2870 3093 2889 2871 2876 2875 2872 2872 2874 2876 2879 2878 2873 3092 2879 2873 2873 3091 3092 2883 2876 2874 2884 2883 2874 3096 2877 2875 3105 3096 2875 2875 2876 3105 2876 2885 3105 2886 2885 2876 2876 2883 2886 3096 3086 2877 2878 3100 3106 2878 2879 3100 3418 3100 2879 2879 3092 3418 3098 3093 2881 2881 2888 3098 3414 3094 2882 3428 3414 2882 2882 3109 3428 3110 2886 2883 2883 2898 3110 2883 2884 2898 3104 2898 2884 2884 2893 3104 3419 3105 2885 3431 3419 2885 2885 3114 3431 2885 3110 3114 2885 2886 3110 2888 3097 3098 2888 2895 3097 3101 2896 2889 2889 3093 3101 2890 2900 3104 2890 2891 2900 2892 2891 2890 3421 2892 2890 2890 2894 3421 3104 2894 2890 3120 2900 2891 3122 3120 2891 3940 3122 2891 2891 2892 3940 4562 3940 2892 2892 3422 4562 2892 3421 3422 2893 2894 3104 3103 3097 2895 2895 3102 3103 2895 2904 3102 3935 2897 2896 2896 3430 3935 2896 3102 3430 3103 3102 2896 2896 3097 3103 3101 3097 2896 3113 3107 2897 3437 3113 2897 4558 3437 2897 2897 3935 4558 3114 3110 2898 2898 2899 3114 2900 2899 2898 3104 2900 2898 3115 3114 2899 3121 3115 2899 2899 3120 3121 2899 2900 3120 3442 3441 2901 3446 3442 2901 2901 3112 3446 3434 3433 2902 3939 3434 2902 2902 3938 3939 2902 3936 3938 2902 2903 3936 2904 2903 2902 3433 2904 2902 2903 3447 3936 3433 3102 2904 3124 3119 2905 2905 2906 3124 2906 3123 3124 2906 2908 3123 2906 2907 2908 2911 2908 2907 2913 2911 2907 3450 3123 2908 3455 3450 2908 2908 2911 3455 2909 2910 3128 3129 3128 2910 2911 3451 3455 3452 3451 2911 2911 2913 3452 3132 2917 2912 3133 3132 2912 2913 2914 3452 3960 3452 2914 2914 3464 3960 3465 3464 2914 3140 2923 2916 3141 3140 2916 3131 2925 2917 3132 3131 2917 2920 2919 2918 3134 2920 2918 3972 3147 2919 2919 3462 3972 2919 3145 3462 3146 3145 2919 3461 3146 2919 2919 2920 3461 2920 3460 3461 2920 3134 3460 2921 3143 3456 3150 2929 2922 2922 2923 3150 2923 3139 3150 3140 3139 2923 3148 3142 2924 2924 2946 3148 2924 2931 2946 3142 3137 2926 3963 3466 2927 4586 3963 2927 4596 4586 2927 2927 2930 4596 2928 2929 3151 2929 3150 3151 2930 2933 4596 2930 2932 2933 2947 2946 2931 3169 2933 2932 2932 2936 3169 4601 4596 2933 2933 3169 4601 3473 3156 2934 2934 3151 3473 3156 3155 2934 3158 2942 2935 2936 2943 3169 3148 2946 2937 3149 3148 2937 3154 3149 2937 3157 3154 2937 2937 2938 3157 2939 2938 2937 2946 2939 2937 2938 3160 3483 2938 2939 3160 3477 3157 2938 3482 3477 2938 3483 3482 2938 3170 3160 2939 3480 3167 2940 3481 3480 2940 2940 3478 3481 3479 3478 2940 2940 3158 3479 2940 2941 3158 2941 2942 3158 3997 3169 2943 2943 3476 3997 2943 3168 3476 2943 2944 3168 2944 2951 3173 3173 3168 2944 2953 2952 2945 3174 2953 2945 2945 3159 3174 2948 2949 3161 3163 3161 2949 3165 3163 2949 2949 2950 3165 3166 3165 2950 2952 2953 2960 3488 2960 2953 2953 3174 3488 2954 2962 2966 2955 2968 3177 3501 3198 2960 2960 3488 3501 2965 2962 2961 3199 2965 2961 2961 3198 3199 2962 2963 2966 2964 2963 2962 2965 2964 2962 2963 2964 3187 4649 3187 2964 2964 4611 4649 4660 4611 2964 2964 3200 4660 2964 2965 3200 2965 3199 3200 3507 3197 2967 2967 3211 3507 3496 3177 2968 4031 3496 2968 2968 3216 4031 3222 2970 2969 2969 3212 3222 4059 3216 2971 2971 3521 4059 2971 3235 3521 2971 2972 3235 2972 2980 3235 2973 2977 2978 3220 2977 2973 3221 3211 2974 3509 3221 2974 2974 3231 3509 2975 3508 4044 2975 2976 3508 2977 2976 2975 3522 2977 2975 4044 3522 2975 2976 2977 3220 2976 3220 3508 2986 2978 2977 3548 2986 2977 2977 3522 3548 2980 2988 3235 2989 2988 2980 2980 2985 2989 3547 3541 2981 2981 3539 3547 2981 3236 3539 3237 3236 2982 3251 3237 2982 3540 3239 2983 3246 2989 2985 2985 2992 3246 3548 2990 2986 2987 2991 3238 3543 3235 2988 3545 3543 2988 3546 3545 2988 2988 2989 3546 2989 3246 3546 3548 3253 2990 2991 2995 3238 3247 3246 2992 2992 2993 3247 3248 3247 2993 3558 3238 2995 2995 2997 3558 2996 3002 3258 2999 2998 2997 3563 3558 2997 3568 3563 2997 2997 2998 3568 2998 2999 3000 2998 3005 3568 2998 3000 3005 3007 3005 3000 3001 3245 3257 3002 3249 3258 3260 3004 3003 3003 3259 3260 3288 3033 3004 3610 3288 3004 3004 3263 3610 3004 3260 3263 3579 3568 3005 3611 3579 3005 3005 3006 3611 3007 3006 3005 3006 3580 3611 3006 3007 3580 3007 3264 3580 3007 3008 3264 3008 3012 3264 3008 3009 3012 3009 3011 3012 3269 3012 3010 3602 3269 3010 3010 3021 3602 3010 3017 3021 3010 3011 3017 3012 3011 3010 3012 3269 3589 3589 3264 3012 3273 3268 3014 3016 3015 3014 3268 3016 3014 3016 3587 3588 3016 3268 3587 3588 3252 3016 3270 3023 3018 3272 3270 3018 3275 3272 3018 3019 3026 3029 3281 3026 3019 3019 3032 3281 3019 3020 3032 3034 3032 3020 3021 3276 3602 3021 3274 3276 3021 3022 3274 3279 3277 3023 3023 3270 3279 3024 3265 3275 3267 3265 3024 3024 3255 3267 3618 3028 3025 3025 3281 3618 3025 3026 3281 3027 3026 3025 3028 3027 3025 3026 3027 3029 3027 3028 3273 3604 3273 3028 3028 3592 3604 4116 3592 3028 3028 4114 4116 3028 3618 4114 3030 3277 3294 3294 3031 3030 3294 3293 3031 3282 3281 3032 3297 3282 3032 3298 3297 3032 3032 3034 3298 3302 3298 3034 3289 3037 3036 3037 3289 3640 3038 3039 4161 3040 3039 3038 3650 3040 3038 4156 3650 3038 4158 4156 3038 4161 4158 3038 3039 3640 4161 3641 3302 3040 3650 3641 3040 3317 3316 3041 3041 3304 3317 3041 3042 3304 3043 3042 3041 3316 3043 3041 3326 3304 3042 3042 3045 3326 3042 3044 3045 3047 3044 3042 3042 3043 3047 3049 3047 3043 3052 3049 3043 3334 3052 3043 3043 3333 3334 3043 3316 3333 3044 3047 3050 3046 3045 3044 3050 3046 3044 3674 3326 3045 3045 3341 3674 3045 3046 3341 3342 3341 3046 3685 3342 3046 3046 3053 3685 3050 3048 3046 3047 3049 3050 3055 3054 3048 3048 3050 3055 3055 3050 3049 3049 3051 3055 3052 3051 3049 3051 3054 3055 3060 3054 3051 3051 3052 3060 3343 3060 3052 3052 3334 3343 3688 3685 3053 3053 3058 3688 3060 3059 3054 3056 3057 3058 3355 3058 3057 3688 3355 3057 3696 3688 3057 3057 3695 3696 3058 3355 3688 3059 3060 3061 3690 3689 3060 3691 3690 3060 3060 3347 3691 3060 3346 3347 3060 3343 3346 3689 3061 3060 3061 3062 3063 3689 3062 3061 3064 3063 3062 4234 3064 3062 3062 4228 4234 3062 3689 4228 3063 3064 3358 3718 3358 3064 4233 3718 3064 4234 4233 3064 3065 3066 3357 3359 3357 3066 3360 3359 3066 3066 3067 3360 3362 3360 3068 3068 3361 3362 3068 3071 3361 3068 3070 3071 3074 3073 3069 4246 3074 3069 3069 3722 4246 3069 3716 3722 3069 3715 3716 3072 3071 3070 3073 3072 3070 3728 3361 3071 3071 3364 3728 3365 3364 3071 3071 3072 3365 3072 3074 3365 3072 3073 3074 4254 3365 3074 3074 4247 4254 3074 4246 4247 3078 3077 3076 3390 3078 3076 3391 3390 3076 3863 3389 3077 4504 3863 3077 3077 3078 4504 3078 3390 4504 3863 3388 3079 3079 3389 3863 3892 3081 3080 3080 3410 3892 3081 3390 3391 4507 3390 3081 3081 3891 4507 3892 3891 3081 3082 3084 3410 3082 3083 3084 3085 3084 3083 3094 3085 3083 4517 3410 3084 5776 4517 3084 3084 3085 5776 5791 5776 3085 3085 3414 5791 3085 3094 3414 3086 3088 3089 3096 3088 3086 3407 3406 3087 3087 3395 3407 3090 3089 3088 3099 3090 3088 3419 3099 3088 3088 3105 3419 3088 3096 3105 3089 3095 3417 3089 3090 3095 3927 3095 3090 3090 3099 3927 3417 3092 3091 3092 3416 3418 3417 3416 3092 3093 3098 3101 4547 3417 3095 4549 4547 3095 3095 3927 4549 3101 3098 3097 4556 3927 3099 3099 3431 4556 3099 3419 3431 3100 3418 3423 3432 3106 3100 3100 3423 3432 3433 3430 3102 3429 3111 3106 3432 3429 3106 3108 3437 3933 3933 3109 3108 3109 3427 3428 3933 3427 3109 3429 3118 3111 3112 3440 3446 3112 3125 3440 3114 3116 3431 3114 3115 3116 3121 3116 3115 3116 3948 3950 3116 3121 3948 4559 3431 3116 4565 4559 3116 3116 3950 4565 3449 3127 3117 3951 3449 3117 3117 3439 3951 3117 3118 3439 3118 3429 3439 3443 3125 3119 3119 3124 3443 3122 3121 3120 3121 3122 3438 3949 3948 3121 3121 3438 3949 3122 3941 3942 3122 3940 3941 3942 3438 3122 3443 3124 3123 3450 3443 3123 3125 3444 3445 3125 3443 3444 3445 3440 3125 3448 3129 3126 3449 3448 3126 3126 3127 3449 3454 3130 3128 3128 3129 3454 3129 3448 3454 3454 3453 3130 3132 3133 3143 3133 3138 3456 3961 3138 3133 3133 3453 3961 3456 3143 3133 3467 3141 3135 3135 3142 3467 3135 3136 3142 3136 3137 3142 3961 3144 3138 3139 3140 3150 3140 3141 3150 3467 3150 3141 3142 3148 3467 3144 3457 3460 3458 3457 3144 3144 3448 3458 3453 3448 3144 3961 3453 3144 3463 3462 3145 4566 3463 3145 3145 3962 4566 3145 3952 3962 3145 3459 3952 3145 3146 3459 3146 3458 3459 3146 3457 3458 3460 3457 3146 3461 3460 3146 3991 3152 3147 3147 3973 3991 3147 3972 3973 3148 3149 3467 3149 3150 3467 3473 3150 3149 3149 3156 3473 3149 3154 3156 3473 3151 3150 3991 3153 3152 3991 3474 3153 3157 3155 3154 3154 3155 3156 3158 3475 3479 3158 3474 3475 3175 3174 3159 3160 3170 3171 3160 3171 3483 3161 3162 3172 3163 3162 3161 4007 3172 3162 4623 4007 3162 3162 4009 4623 3162 3163 4009 3163 4008 4009 3163 3164 4008 3165 3164 3163 3164 3165 4003 3164 4003 4008 3165 3166 4003 3166 3167 4003 3167 3480 4003 3486 3476 3168 3168 3173 3486 3169 4002 4601 3169 3997 4002 3484 3483 3171 4018 3484 3171 3171 4007 4018 3171 3172 4007 3487 3486 3173 3501 3488 3174 3174 3482 3501 3174 3175 3482 3175 3477 3482 4019 3487 3176 3176 3496 4019 3176 3177 3496 3194 3181 3178 3178 3179 3194 3180 3179 3178 3181 3180 3178 3208 3194 3179 3179 3183 3208 3179 3180 3183 3180 3182 3183 3180 3181 3182 3195 3185 3181 3181 3194 3195 3185 3182 3181 3184 3183 3182 3186 3184 3182 3182 3185 3186 3489 3208 3183 4020 3489 3183 3183 3492 4020 3183 3184 3492 3184 3195 3500 3184 3186 3195 4021 3492 3184 3184 3500 4021 3195 3186 3185 3493 3212 3187 4649 3493 3187 3188 3189 3191 3190 3189 3188 3191 3190 3188 3189 3493 4022 3189 3190 3493 3495 3191 3189 4024 3495 3189 3189 4022 4024 3494 3493 3190 3190 3213 3494 3190 3202 3213 3190 3191 3202 3191 3192 3202 3193 3192 3191 3495 3193 3191 3192 3201 3202 3192 3193 3201 3206 3201 3193 3495 3206 3193 3196 3195 3194 3210 3196 3194 3194 3209 3210 3194 3208 3209 3195 3196 3219 3195 3219 3500 3196 3217 3218 3196 3210 3217 3196 3218 3219 3507 3220 3197 3501 3199 3198 4030 3200 3199 3199 3502 4030 3199 3501 3502 3200 4633 4660 4647 4633 3200 3200 4030 4647 3205 3204 3201 3215 3205 3201 3201 3206 3215 3203 3202 3201 3214 3203 3201 3201 3204 3214 3224 3213 3202 3202 3203 3224 3227 3224 3203 3203 3226 3227 3203 3214 3226 3204 3205 3207 3229 3214 3204 3204 3228 3229 3204 3207 3228 3215 3207 3205 4023 3215 3206 3206 3495 4023 3207 3215 3503 3230 3228 3207 3512 3230 3207 3207 3503 3512 3506 3209 3208 4029 3506 3208 3208 3489 4029 3217 3210 3209 3506 3217 3209 3508 3507 3211 4042 3508 3211 4043 4042 3211 3211 3221 4043 3234 3222 3212 3494 3234 3212 3212 3493 3494 3213 3223 3494 3224 3223 3213 3229 3226 3214 3504 3503 3215 4023 3504 3215 4059 4058 3216 4058 4031 3216 3506 3218 3217 3505 3219 3218 3506 3505 3218 3505 3500 3219 3220 3507 3508 3221 3509 4043 3511 3494 3223 3517 3511 3223 3223 3227 3517 3223 3224 3227 3227 3226 3225 3528 3227 3225 3225 3527 3528 3529 3527 3225 3225 3226 3529 3226 3518 3529 3226 3229 3518 3528 3517 3227 3232 3229 3228 3228 3230 3232 3229 3232 3518 3233 3232 3230 3512 3233 3230 3515 3509 3231 3516 3515 3231 3529 3518 3232 3530 3529 3232 3232 3519 3530 3232 3233 3519 3233 3513 3519 3233 3512 3513 3234 3510 3526 3511 3510 3234 3234 3494 3511 3543 3521 3235 3236 3250 3539 3236 3237 3250 3251 3250 3237 3556 3549 3238 3558 3556 3238 3540 3240 3239 3551 3550 3240 4069 3551 3240 3240 3540 4069 3241 3242 3245 3243 3242 3241 3561 3245 3242 3242 3243 3561 3243 3559 3561 3560 3559 3243 3243 3552 3560 3243 3244 3552 3244 3542 3552 3245 3255 3257 3245 3254 3255 4089 3254 3245 3245 3561 4089 3562 3546 3246 3246 3247 3562 3569 3562 3247 3247 3248 3569 3248 3261 3569 3572 3258 3249 3574 3572 3249 3249 3554 3574 3555 3554 3249 3249 3256 3555 3250 3252 3539 3250 3251 3252 3252 3538 3539 4702 3538 3252 4704 4702 3252 3252 3588 4704 4718 3259 3253 3253 3548 4718 4097 3255 3254 3254 4089 4097 4097 3267 3255 3256 3541 3555 3590 3586 3258 3258 3573 3590 3258 3572 3573 3575 3260 3259 4718 3575 3259 3575 3263 3260 3570 3569 3261 3582 3570 3261 3261 3581 3582 3584 3581 3261 3261 3262 3584 3586 3584 3262 4730 3610 3263 3263 3575 4730 3589 3580 3264 3265 3272 3275 3603 3272 3265 4100 3603 3265 3265 3266 4100 3267 3266 3265 4724 4100 3266 3266 4097 4724 3266 3267 4097 3604 3592 3268 3268 3273 3604 3591 3587 3268 3592 3591 3268 4095 3589 3269 3269 3626 4095 3628 3626 3269 3269 3606 3628 3269 3602 3606 3280 3279 3270 3270 3271 3280 3272 3271 3270 3271 3272 3603 3607 3280 3271 3271 3603 3607 3291 3276 3274 3274 3290 3291 3606 3602 3276 3276 3307 3606 3276 3291 3307 3295 3294 3277 3277 3278 3295 3279 3278 3277 3639 3295 3278 3278 3634 3639 3278 3630 3634 3278 3279 3630 3279 3280 3630 3633 3630 3280 3636 3633 3280 3280 3613 3636 3280 3607 3613 3619 3618 3281 3620 3619 3281 3281 3282 3620 3282 3614 3620 3616 3614 3282 4125 3616 3282 3282 3283 4125 3284 3283 3282 3631 3284 3282 3282 3297 3631 4740 4125 3283 4741 4740 3283 4745 4741 3283 3283 3284 4745 4749 4745 3284 3284 4138 4749 3284 3631 4138 3289 3288 3285 4132 3289 3285 4751 4132 3285 3285 4131 4751 3285 3286 4131 3287 3286 3285 3288 3287 3285 3286 3287 3299 5317 4131 3286 5318 5317 3286 3286 3299 5318 4118 3299 3287 3287 3288 4118 3288 3610 4118 4132 3640 3289 3292 3291 3290 3293 3292 3290 3317 3307 3291 3291 3292 3317 3629 3317 3292 3638 3629 3292 3292 3296 3638 3292 3293 3296 3293 3294 3296 3294 3295 3296 3632 3296 3295 3639 3632 3295 4140 3638 3296 3296 3632 4140 3297 3301 3631 3297 3300 3301 3297 3298 3300 3302 3300 3298 3299 4118 4736 3299 4736 5318 4145 3301 3300 3300 3642 4145 3300 3641 3642 3300 3302 3641 4137 3631 3301 4145 4137 3301 3303 3304 3326 3305 3304 3303 3326 3305 3303 3304 3306 3317 3304 3305 3306 3649 3306 3305 3305 3326 3649 3306 3307 3317 3308 3307 3306 3654 3308 3306 3306 3649 3654 3628 3606 3307 3307 3627 3628 3307 3308 3627 3308 3624 3627 3625 3624 3308 4129 3625 3308 3308 3654 4129 4163 3312 3309 3309 3661 4163 3309 3310 3661 3311 3310 3309 3312 3311 3309 3310 3328 3661 3310 3320 3328 3310 3319 3320 3310 3318 3319 3330 3318 3310 3310 3321 3330 3310 3311 3321 3322 3321 3311 3325 3322 3311 3311 3313 3325 3315 3313 3311 3311 3312 3315 4148 3315 3312 4163 4148 3312 3644 3325 3313 3645 3644 3313 3313 3643 3645 3313 3314 3643 3315 3314 3313 4147 3643 3314 3314 3315 4147 4148 4147 3315 3316 3629 3659 3316 3317 3629 3659 3333 3316 3318 3332 3345 3318 3323 3332 3330 3323 3318 3345 3319 3318 3327 3320 3319 3678 3327 3319 3319 3336 3678 3345 3336 3319 3320 3327 3328 3321 3323 3330 3321 3322 3323 3325 3323 3322 3323 3331 3332 3664 3331 3323 3323 3662 3664 3323 3324 3662 3325 3324 3323 3324 3645 3652 3324 3644 3645 3324 3325 3644 3324 3651 3662 3324 3646 3651 3648 3646 3324 3652 3648 3324 3674 3649 3326 3329 3328 3327 3678 3329 3327 4167 3661 3328 3328 4162 4167 3328 3329 4162 3329 3671 4162 3329 3670 3671 3678 3670 3329 3673 3340 3331 3331 3664 3673 3340 3332 3331 3354 3345 3332 3687 3354 3332 3332 3339 3687 3340 3339 3332 3335 3334 3333 3659 3335 3333 3344 3343 3334 3334 3335 3344 3669 3344 3335 3335 3665 3669 3335 3656 3665 3659 3656 3335 3336 3337 3678 3338 3337 3336 3353 3338 3336 3336 3345 3353 3337 3677 3678 4183 3677 3337 3337 3679 4183 3337 3338 3679 3693 3686 3338 3338 3350 3693 3353 3350 3338 3686 3679 3338 3339 3340 3680 4200 3687 3339 4201 4200 3339 3339 3680 4201 3340 3673 4184 4184 3680 3340 3675 3674 3341 4191 3675 3341 3341 3342 4191 4202 4191 3342 3342 3685 4202 3681 3346 3343 3343 3344 3681 3344 3676 3681 3344 3668 3676 3669 3668 3344 3345 3352 3353 3354 3352 3345 3682 3347 3346 3346 3681 3682 4810 3691 3347 3347 4205 4810 3347 3692 4205 3347 3682 3692 3348 3351 3356 3348 3349 3351 3350 3349 3348 3356 3350 3348 3349 3350 3353 3352 3351 3349 3353 3352 3349 3694 3693 3350 3350 3356 3694 3703 3356 3351 3704 3703 3351 3351 3354 3704 3351 3352 3354 4207 3704 3354 3354 4200 4207 3354 3687 4200 3699 3694 3356 3711 3699 3356 3356 3708 3711 3356 3702 3708 3703 3702 3356 4220 3695 3357 3357 3720 4220 3357 3359 3720 3718 3715 3358 4244 3720 3359 3359 3363 4244 3359 3360 3363 3360 3362 3363 3724 3362 3361 3727 3724 3361 3728 3727 3361 3713 3363 3362 3724 3713 3362 3363 3714 4244 3363 3713 3714 4256 3728 3364 3364 3365 4256 3365 4254 4256 3366 3374 3829 3366 3373 3374 3366 3367 3373 3368 3367 3366 3829 3368 3366 3378 3373 3367 3379 3378 3367 3367 3369 3379 3367 3368 3369 3803 3369 3368 3829 3803 3368 3815 3379 3369 3369 3814 3815 3369 3803 3814 4381 3838 3370 3370 3839 4381 3370 3371 3839 3372 3371 3370 3838 3372 3370 3371 3387 3839 3371 3381 3387 3371 3372 3381 3372 3380 3381 3372 3374 3380 3838 3374 3372 3380 3374 3373 3373 3377 3380 3378 3377 3373 3838 3829 3374 3382 3380 3375 3840 3382 3375 3375 3376 3840 3377 3376 3375 3380 3377 3375 4413 3840 3376 4992 4413 3376 3376 4382 4992 3376 3377 4382 4397 4382 3377 3377 3378 4397 3378 4369 4397 3378 3816 4369 3378 3379 3816 3379 3815 3816 3383 3381 3380 3380 3382 3383 3381 3383 3387 3382 3840 3841 3384 3383 3382 3386 3384 3382 3841 3386 3382 3383 3384 3387 3384 3385 3387 3386 3385 3384 3843 3387 3385 3844 3843 3385 3385 3386 3844 3845 3844 3386 3855 3845 3386 3386 3842 3855 3386 3841 3842 4407 3839 3387 3387 3843 4407 3388 3863 4494 4507 4504 3390 3392 3394 3395 3392 3393 3394 3396 3394 3393 3398 3396 3393 3403 3398 3393 3404 3395 3394 3394 3397 3404 3394 3396 3397 3395 3404 3407 3398 3397 3396 3409 3404 3397 3893 3409 3397 3397 3886 3893 3397 3879 3886 3397 3398 3879 3880 3879 3398 3398 3858 3880 3398 3403 3858 3399 3402 3405 3399 3400 3402 3401 3400 3399 3405 3401 3399 3873 3402 3400 3400 3401 3873 3888 3873 3401 3401 3405 3888 3874 3405 3402 3402 3873 3874 3408 3407 3404 3409 3408 3404 3910 3888 3405 3405 3908 3910 3405 3874 3908 3412 3411 3406 3406 3408 3412 3406 3407 3408 3413 3412 3408 3918 3413 3408 3408 3409 3918 3409 3902 3918 3903 3902 3409 3409 3893 3903 4517 3892 3410 3411 3412 3415 3925 3415 3412 3412 3413 3925 4545 3925 3413 3413 3922 4545 3413 3918 3922 3414 5784 5791 3414 3428 5784 3926 3420 3415 3415 3925 3926 4547 3418 3416 3416 3417 4547 4547 3928 3418 3928 3423 3418 3422 3421 3420 3929 3422 3420 3932 3929 3420 3420 3926 3932 5116 4562 3422 3422 4554 5116 3422 3929 4554 3423 3426 3432 4550 3426 3423 3423 3928 4550 3934 3432 3424 3424 3425 3934 3426 3425 3424 3432 3426 3424 3944 3934 3425 4560 3944 3425 3425 4551 4560 3425 3426 4551 4552 4551 3426 3426 4550 4552 3930 3428 3427 3931 3930 3427 3933 3931 3427 3428 5103 5784 3428 3930 5103 3934 3439 3429 3429 3432 3934 4557 3935 3430 3430 3435 4557 3430 3433 3435 4559 4556 3431 3433 3434 3435 3434 3939 4561 3436 3435 3434 5113 3436 3434 3434 4561 5113 3435 3436 4557 5121 4557 3436 3436 5120 5121 5148 5120 3436 3436 5113 5148 4553 3933 3437 4558 4553 3437 3953 3949 3438 3438 3947 3953 3438 3942 3947 3439 3934 3944 3439 3943 3951 3944 3943 3439 4564 3446 3440 5824 4564 3440 3440 3445 5824 3441 3945 3946 3441 3442 3945 3946 3447 3441 3442 3446 3945 3450 3444 3443 3444 3455 3957 3444 3450 3455 3957 3445 3444 3445 5127 5824 3445 4563 5127 3445 3957 4563 4564 3945 3446 3946 3936 3447 3448 3453 3454 3448 3449 3458 3951 3458 3449 3451 3960 5138 3451 3452 3960 3958 3455 3451 5138 3958 3451 3958 3957 3455 3951 3459 3458 3459 3951 3952 4579 3972 3462 3462 3463 4579 3463 4576 4579 3463 4566 4576 4581 3960 3464 5162 4581 3464 3464 4591 5162 3464 3465 4591 3465 4585 4591 4586 4585 3465 3465 3963 4586 3465 3466 3963 3472 3471 3468 3468 3469 3472 3470 3469 3468 3471 3470 3468 3993 3472 3469 3469 3992 3993 3469 3983 3992 3469 3470 3983 3985 3983 3470 3470 3471 3985 3471 3472 3993 3986 3985 3471 3993 3986 3471 3999 3475 3474 3474 3991 3999 3475 4000 4006 4001 4000 3475 3475 3999 4001 3475 3478 3479 3485 3478 3475 4004 3485 3475 4006 4004 3475 3998 3997 3476 4616 3998 3476 3476 3486 4616 4013 3481 3478 3478 3485 4013 4011 4003 3480 4012 4011 3480 3480 3481 4012 4013 4012 3481 4017 3501 3482 3482 3484 4017 3482 3483 3484 4633 4017 3484 4634 4633 3484 3484 4018 4634 4014 4013 3485 4015 4014 3485 3485 4004 4015 4617 4616 3486 3486 4019 4617 3486 3487 4019 3489 4026 4029 4644 4026 3489 3489 4020 4644 3492 3491 3490 4020 3492 3490 4644 4020 3490 4645 4644 3490 5227 4645 3490 3490 3491 5227 3491 3492 4021 3491 4646 5227 3491 4021 4646 4649 4022 3493 4025 4023 3495 3495 4024 4025 4652 4019 3496 3496 4032 4652 3496 4031 4032 4659 4646 3497 5241 4659 3497 3497 3498 5241 3499 3498 3497 4646 3499 3497 5246 5241 3498 3498 4663 5246 3498 4662 4663 3498 3499 4662 3499 4041 4662 3499 3505 4041 3499 3500 3505 4021 3500 3499 4646 4021 3499 4017 3502 3501 4647 4030 3502 3502 4017 4647 3503 3504 4661 5243 3512 3503 3503 4661 5243 3504 4023 4661 3505 3506 4041 4666 4041 3506 3506 4037 4666 3506 4029 4037 3508 4042 4045 4045 4044 3508 3509 3515 4043 3510 4046 4062 4052 4046 3510 3510 3511 4052 4062 3526 3510 3511 3517 4052 3514 3513 3512 3520 3514 3512 5243 3520 3512 3513 3514 3519 3531 3519 3514 4674 3531 3514 3514 3520 4674 3515 3516 3523 3515 4042 4043 4679 4042 3515 3515 3523 4679 4056 4052 3517 3517 3528 4056 3536 3530 3519 3519 3532 3536 3519 3531 3532 5248 4674 3520 3520 5243 5248 4675 4059 3521 3521 4068 4675 3521 3544 4068 3521 3543 3544 4687 3548 3522 4688 4687 3522 3522 4680 4688 3522 4679 4680 3522 4045 4679 3522 4044 4045 4680 4679 3523 4688 4680 3523 3523 4060 4688 4061 4060 3523 3523 3549 4061 4062 3525 3524 3524 3526 4062 4062 3540 3525 3533 3528 3527 4691 3533 3527 3527 4077 4691 3527 4064 4077 3527 3534 4064 3527 3529 3534 3528 3533 4056 3529 3530 3534 3535 3534 3530 3536 3535 3530 3537 3532 3531 4057 3537 3531 4682 4057 3531 3531 4674 4682 3537 3536 3532 3533 4055 4056 4063 4055 3533 4691 4063 3533 4071 4064 3534 3534 3535 4071 3535 3536 4071 3536 4065 4071 3536 3537 4065 3537 4057 4065 4081 3547 3538 4702 4081 3538 3547 3539 3538 4070 4069 3540 3540 4048 4070 3540 4047 4048 4062 4047 3540 3541 3547 3555 4083 3552 3542 3542 3550 4083 3545 3544 3543 4073 4068 3544 4074 4073 3544 3544 3545 4074 4710 4074 3545 3545 3553 4710 3545 3546 3553 3562 3553 3546 4081 3555 3547 3548 4686 4718 4687 4686 3548 5266 4061 3549 3549 4084 5266 3549 3557 4084 3549 3556 3557 3550 4075 4083 3550 3551 4075 3551 4069 4075 4083 3560 3552 3553 4693 4710 3553 4090 4693 3553 3571 4090 3553 3562 3571 5280 3574 3554 5281 5280 3554 3554 4703 5281 3554 3555 4703 3555 4082 4703 3555 4081 4082 3564 3557 3556 3556 3558 3564 4094 4084 3557 3557 3564 4094 3558 3563 3564 4089 3561 3559 4719 4089 3559 3559 4088 4719 3559 4085 4088 3559 3560 4085 3560 4083 4085 3562 3570 3571 3562 3569 3570 3565 3564 3563 3566 3565 3563 3568 3566 3563 3564 4093 4094 3564 3565 4093 3565 3576 4093 3577 3576 3565 3565 3566 3577 3605 3577 3566 3566 3601 3605 3566 3567 3601 3568 3567 3566 3567 3599 3601 3567 3578 3599 3567 3568 3578 3579 3578 3568 3582 3571 3570 3571 3583 4090 3571 3582 3583 3572 3574 4092 4092 3573 3572 4105 3590 3573 5294 4105 3573 3573 4092 5294 4714 4092 3574 5280 4714 3574 5958 4730 3575 3575 4721 5958 3575 4718 4721 4096 4093 3576 4108 4096 3576 3576 3577 4108 3577 3605 4108 3578 3579 3599 3600 3599 3579 3611 3600 3579 4095 3611 3580 3580 3589 4095 3583 3582 3581 4727 3583 3581 3581 4104 4727 3581 3585 4104 3581 3584 3585 4091 4090 3583 4733 4091 3583 3583 4727 4733 3586 3585 3584 3585 3590 4104 3585 3586 3590 4107 4106 3587 4728 4107 3587 4729 4728 3587 3587 3591 4729 4106 3588 3587 3588 4106 4704 4105 4104 3590 5303 4729 3591 3591 5302 5303 3591 5301 5302 3591 4116 5301 3591 3592 4116 3598 3596 3593 3605 3598 3593 4108 3605 3593 3593 3594 4108 3595 3594 3593 3596 3595 3593 3594 3622 4108 3594 3621 3622 3594 3595 3621 4121 3621 3595 3595 4120 4121 3595 3596 4120 4123 4120 3596 3596 3597 4123 3598 3597 3596 3597 3612 4123 3597 3598 3612 3598 3600 3612 3601 3600 3598 3605 3601 3598 3599 3600 3601 3626 3625 3600 4095 3626 3600 3600 3611 4095 3625 3612 3600 3608 3607 3603 3609 3608 3603 4111 3609 3603 3603 4100 4111 3607 3608 3613 3637 3613 3608 4113 3637 3608 3608 3609 4113 3609 4111 4724 3609 4112 4113 4724 4112 3609 4736 4118 3610 3610 4730 4736 3612 4122 4123 4124 4122 3612 3612 3625 4124 3637 3636 3613 3614 3619 3620 3614 3615 3619 3616 3615 3614 3615 3617 4741 3615 3616 3617 4114 3619 3615 4735 4114 3615 4743 4735 3615 3615 4741 4743 4119 3617 3616 4125 4119 3616 3617 4119 4740 3617 4740 4741 3618 3619 4114 3621 4121 4133 3623 3622 3621 4126 3623 3621 4133 4126 3621 4737 4108 3622 3622 3623 4737 5315 4737 3623 3623 4127 5315 3623 4126 4127 3624 3626 3627 3624 3625 3626 4129 4124 3625 3628 3627 3626 3629 3655 3656 3629 3638 3655 3629 3656 3659 3630 3633 3634 3631 4137 4138 3632 3658 4140 3632 3639 3658 3635 3634 3633 3636 3635 3633 3657 3639 3634 4164 3657 3634 3634 4152 4164 3634 4143 4152 3634 3635 4143 3635 4142 4143 3635 4130 4142 3635 3636 4130 3636 3637 4130 4739 4130 3637 3637 4113 4739 4140 3655 3638 3639 3657 3658 3640 4139 4161 3640 4132 4139 4146 3642 3641 3641 3650 4146 4154 4145 3642 3642 4146 4154 4147 3645 3643 4147 3652 3645 3653 3651 3646 3646 3647 3653 3648 3647 3646 4763 3653 3647 3647 3648 4763 3648 4149 4763 3648 3652 4149 4169 3654 3649 3649 4136 4169 4176 4136 3649 3649 4175 4176 3649 3674 4175 4156 4146 3650 3651 3653 3662 3652 4147 4148 3652 4148 4149 3663 3662 3653 5337 3663 3653 3653 4763 5337 4150 4129 3654 4169 4150 3654 4140 3658 3655 3658 3656 3655 3656 3660 3665 3656 3657 3660 3658 3657 3656 4164 3666 3657 3666 3660 3657 3666 3665 3660 4167 4163 3661 3662 3663 3664 4168 3664 3663 4787 4168 3663 5337 4787 3663 4179 3673 3664 3664 4173 4179 3664 4168 4173 3665 3668 3669 3665 3667 3668 3665 3666 3667 4164 3667 3666 3676 3668 3667 4779 3676 3667 3667 4778 4779 3667 4164 4778 3672 3671 3670 3677 3672 3670 3678 3677 3670 4178 4177 3671 3671 3672 4178 4177 4162 3671 3672 3677 4178 3673 4179 4185 4185 4184 3673 3674 3675 4175 4795 4175 3675 3675 4191 4795 4195 3681 3676 3676 4192 4195 4779 4192 3676 4197 4178 3677 3677 4183 4197 3679 3683 4183 3684 3683 3679 3686 3684 3679 4794 4201 3680 3680 4184 4794 3692 3682 3681 4195 3692 3681 4217 4183 3683 4218 4217 3683 3683 3684 4218 3684 3707 4218 3684 3686 3707 3685 3697 4202 3685 3688 3697 3686 3693 3707 4817 3697 3688 3688 3705 4817 3688 3696 3705 3689 3698 4229 3689 3690 3698 4229 4228 3689 4813 3698 3690 3690 4810 4813 3690 3691 4810 3692 4195 4205 3693 3706 3707 3693 3694 3706 3710 3706 3694 3694 3699 3710 4220 3696 3695 4188 3705 3696 4219 4188 3696 4220 4219 3696 4203 4202 3697 4809 4203 3697 4817 4809 3697 4827 4229 3698 3698 4813 4827 3699 3700 3710 3701 3700 3699 3711 3701 3699 4238 3710 3700 3700 4235 4238 4237 4235 3700 4239 4237 3700 3700 3701 4239 4240 4239 3701 3701 3712 4240 3701 3708 3712 3711 3708 3701 3712 3708 3702 3702 3709 3712 3702 3703 3709 3703 3704 3709 4223 3709 3704 3704 4207 4223 5359 4817 3705 3705 4808 5359 3705 4189 4808 3705 4180 4189 4187 4180 3705 4188 4187 3705 4224 3707 3706 4232 4224 3706 3706 3710 4232 4221 4218 3707 4222 4221 3707 4224 4222 3707 4223 3712 3709 4238 4232 3710 3712 4226 4240 3712 4223 4226 3713 3725 4250 3713 3724 3725 3723 3714 3713 4250 3723 3713 3714 3720 4244 3714 3719 3720 3723 3719 3714 3717 3716 3715 3718 3717 3715 3716 3717 3722 4248 3722 3717 4836 4248 3717 3717 4826 4836 3717 4233 4826 3717 3718 4233 5398 4243 3719 3719 4838 5398 3719 3723 4838 3721 3720 3719 4243 3721 3719 4241 4220 3720 3720 3721 4241 5386 4241 3721 3721 4834 5386 3721 4243 4834 4248 4246 3722 4843 4838 3723 3723 4252 4843 3723 4250 4252 3726 3725 3724 3727 3726 3724 4253 4250 3725 3725 4251 4253 3725 3726 4251 4255 4251 3726 4276 4255 3726 3726 4266 4276 3726 3727 4266 3727 3728 4266 3728 4265 4266 3728 4257 4265 3728 4256 4257 4280 4267 3729 4281 4280 3729 4286 4281 3729 3729 3740 4286 3729 3739 3740 3729 3730 3739 3731 3730 3729 3733 3731 3729 4267 3733 3729 3730 3731 3738 3730 3736 3739 3737 3736 3730 3738 3737 3730 3731 3733 3738 4268 4260 3732 3732 4267 4268 3732 3733 4267 3734 3733 3732 4260 3734 3732 3733 3735 3738 3733 3734 3735 4271 3735 3734 3734 4270 4271 3734 4269 4270 3734 4260 4269 3735 3737 3738 3742 3737 3735 4271 3742 3735 3743 3739 3736 3736 3741 3743 3736 3737 3741 3742 3741 3737 3746 3740 3739 3749 3746 3739 3739 3743 3749 3740 3745 4285 3740 3744 3745 3747 3744 3740 3740 3746 3747 3740 4285 4286 3754 3743 3741 4869 3754 3741 3741 4864 4869 3741 3742 4864 3742 4863 4864 3742 4858 4863 3742 4271 4858 3753 3749 3743 3754 3753 3743 3751 3745 3744 3744 3747 3751 3745 4284 4285 4288 4284 3745 4289 4288 3745 4298 4289 3745 3745 4290 4298 4291 4290 3745 4295 4291 3745 3745 4293 4295 3745 3751 4293 3748 3747 3746 3752 3748 3746 3753 3752 3746 3746 3749 3753 3747 3748 3751 3748 3750 3751 3752 3750 3748 3755 3751 3750 3750 3752 3755 3751 4287 4293 3751 3755 4287 4297 3755 3752 3752 4294 4297 3752 3753 4294 4305 4294 3753 3753 4292 4305 3753 3754 4292 4869 4292 3754 4296 4287 3755 4297 4296 3755 4341 3761 3756 3756 3764 4341 3756 3757 3764 3758 3757 3756 3761 3758 3756 3757 3763 3764 3757 3762 3763 3757 3758 3762 3758 3759 3762 3760 3759 3758 4330 3760 3758 3758 3761 4330 3763 3762 3759 3767 3763 3759 4332 3767 3759 3759 4319 4332 3759 3760 4319 4322 4319 3760 3760 4320 4322 3760 4312 4320 4318 4312 3760 4330 4318 3760 3761 4329 4330 4932 4329 3761 4941 4932 3761 3761 4341 4941 3768 3764 3763 3763 3767 3768 3764 3765 4341 3766 3765 3764 3768 3766 3764 4356 4341 3765 3765 3782 4356 3765 3766 3782 3783 3782 3766 3766 3768 3783 3773 3768 3767 4332 3773 3767 3795 3783 3768 3768 3785 3795 3768 3784 3785 3768 3773 3784 3769 3772 3774 3769 3770 3772 3771 3770 3769 3774 3771 3769 4343 3772 3770 4344 4343 3770 3770 3771 4344 3771 4342 4344 3771 3775 4342 3771 3774 3775 3791 3774 3772 4354 3791 3772 3772 4343 4354 4342 3784 3773 4945 4342 3773 3773 4352 4945 3773 4338 4352 3773 4333 4338 3773 4332 4333 3776 3775 3774 3790 3776 3774 3791 3790 3774 3786 3785 3775 3805 3786 3775 3775 3799 3805 3775 3776 3799 3775 3784 4342 3785 3784 3775 3776 3798 3799 3776 3790 3798 3777 3780 3792 3777 3778 3780 3779 3778 3777 3792 3779 3777 3781 3780 3778 3793 3781 3778 3794 3793 3778 4348 3794 3778 3778 3779 4348 3779 4336 4348 4366 4336 3779 3779 3792 4366 3800 3792 3780 3815 3800 3780 3780 3781 3815 3781 3804 3815 3781 3793 3804 3782 3783 4356 4363 4356 3783 3783 4360 4363 3783 3795 4360 3785 3786 3795 3819 3795 3786 3786 3788 3819 3805 3788 3786 3820 3806 3787 3787 3809 3820 3787 3788 3809 3789 3788 3787 3806 3789 3787 3788 3805 3809 3788 3789 3819 3823 3819 3789 3824 3823 3789 3789 3807 3824 3789 3806 3807 3813 3798 3790 4361 3813 3790 4948 4361 3790 3790 3791 4948 3791 4357 4948 3791 4354 4357 3792 3800 4366 4952 3804 3793 3793 3794 4952 4355 4350 3794 3794 4351 4355 3794 4348 4351 3794 4947 4952 3794 4350 4947 3795 3796 4360 3797 3796 3795 3819 3797 3795 4364 4360 3796 3796 3817 4364 3796 3797 3817 3818 3817 3797 3819 3818 3797 3808 3799 3798 3811 3808 3798 3813 3811 3798 3809 3805 3799 3799 3808 3809 3800 3814 4366 3815 3814 3800 4366 3814 3801 3801 4365 4366 3801 3802 4365 3803 3802 3801 3814 3803 3801 4368 4365 3802 3802 3829 4368 3802 3803 3829 3816 3815 3804 4957 3816 3804 3804 4952 4957 3826 3807 3806 3827 3826 3806 3806 3820 3827 3830 3824 3807 3807 3825 3830 3826 3825 3807 3820 3809 3808 3808 3811 3820 5601 4962 3810 6310 5601 3810 6319 6310 3810 3810 4949 6319 3810 4361 4949 3810 3813 4361 3810 3811 3813 3812 3811 3810 4962 3812 3810 3828 3820 3811 3811 3812 3828 3837 3828 3812 4372 3837 3812 4373 4372 3812 4962 4373 3812 4957 4369 3816 3817 3818 4364 4961 4364 3818 3818 4367 4961 3818 3821 4367 3822 3821 3818 3818 3819 3822 3823 3822 3819 3828 3827 3820 3821 3833 4367 3821 3822 3833 3822 3823 3824 3835 3833 3822 3822 3824 3835 3824 3830 3835 3832 3830 3825 3836 3832 3825 3825 3827 3836 3825 3826 3827 3837 3836 3827 3827 3828 3837 4974 4368 3829 3829 4381 4974 3829 3838 4381 3830 3831 3835 3832 3831 3830 3831 3833 3835 3834 3833 3831 3831 3832 3834 4383 3834 3832 4384 4383 3832 4409 4384 3832 3832 4408 4409 3832 4398 4408 3832 3836 4398 4965 4367 3833 4966 4965 3833 3833 4375 4966 3833 3834 4375 4383 4375 3834 3836 4378 4398 3836 3837 4378 3837 4372 4378 4407 4381 3839 4413 3842 3840 3842 3841 3840 3842 4413 4414 3842 3848 3855 5009 3848 3842 3842 4414 5009 5002 4407 3843 3843 4412 5002 3843 3844 4412 3844 4438 4456 3844 3853 4438 3844 3845 3853 4456 4412 3844 3856 3853 3845 3845 3855 3856 4439 3855 3846 4468 4439 3846 3846 3847 4468 3848 3847 3846 3855 3848 3846 4469 4468 3847 5697 4469 3847 3847 3848 5697 3848 5682 5697 3848 5009 5682 3849 3852 3854 3849 3850 3852 3851 3850 3849 3854 3851 3849 4418 3852 3850 3850 3851 4418 4433 4418 3851 3851 3854 4433 4454 3854 3852 3852 4434 4454 3852 4418 4434 3853 3856 4438 4452 4433 3854 4454 4452 3854 4439 3856 3855 4465 4438 3856 4467 4465 3856 3856 4455 4467 3856 4439 4455 4495 4485 3857 3857 4494 4495 3858 3859 3880 4496 3880 3859 3859 4488 4496 5042 4488 3859 3859 3865 5042 3859 3864 3865 3862 3861 3860 5084 3862 3860 5747 5084 3860 3860 3891 5747 4507 3891 3860 5072 4507 3860 3860 3861 5072 4495 3863 3861 3861 3862 4495 3861 3863 5072 3862 4485 4495 5054 4485 3862 5737 5054 3862 3862 5084 5737 4495 4494 3863 3863 4504 5072 5040 3865 3864 3865 5041 5042 3865 5040 5041 3881 3868 3866 3866 3869 3881 3871 3869 3866 3866 3867 3871 3868 3867 3866 4460 3871 3867 3867 4459 4460 5050 4459 3867 3867 3868 5050 3868 3890 4505 3868 3881 3890 3868 5036 5050 3868 5035 5036 3868 4505 5035 3869 3875 3881 3869 3872 3875 3869 3870 3872 3871 3870 3869 3878 3872 3870 4500 3878 3870 3870 4461 4500 3870 4431 4461 3870 3871 4431 4460 4431 3871 3878 3875 3872 3882 3874 3873 3873 3881 3882 3890 3881 3873 3873 3889 3890 3873 3888 3889 3874 3906 3908 3907 3906 3874 3911 3907 3874 3874 3901 3911 3874 3882 3901 3875 3876 3882 3877 3876 3875 3878 3877 3875 3882 3881 3875 3876 4521 4522 3876 4503 4521 3876 3877 4503 4522 3882 3876 4506 4503 3877 3877 4500 4506 3877 3878 4500 3879 3883 3886 3879 3880 3883 3880 4496 4497 3885 3883 3880 4497 3885 3880 4528 3901 3882 3882 4522 4528 3883 3884 3886 3885 3884 3883 3903 3886 3884 4509 3903 3884 3884 4508 4509 3884 3885 4508 3885 4498 4508 3885 4497 4498 3903 3893 3886 3887 3888 3910 3889 3888 3887 3898 3889 3887 3887 3897 3898 3910 3897 3887 4502 3890 3889 3889 3898 4502 3890 4502 4505 5749 5747 3891 3891 3892 5749 5769 5749 3892 3892 4517 5769 3894 3904 3905 3894 3897 3904 3894 3895 3897 3896 3895 3894 3905 3896 3894 3899 3897 3895 3900 3899 3895 3895 3896 3900 3914 3900 3896 3896 3905 3914 3899 3898 3897 3910 3904 3897 3898 3899 4502 4505 4502 3899 5075 4505 3899 5076 5075 3899 3899 3900 5076 5088 5076 3900 3900 4515 5088 3900 4514 4515 3900 3914 4514 4528 3911 3901 3922 3918 3902 5099 3922 3902 3902 3903 5099 5777 5099 3903 5794 5777 3903 6472 5794 3903 3903 5751 6472 3903 4509 5751 3915 3905 3904 3917 3915 3904 3904 3910 3917 4519 3914 3905 4533 4519 3905 3905 3919 4533 3905 3915 3919 3909 3908 3906 3920 3909 3906 3906 3907 3920 3907 3913 3920 3907 3911 3913 3908 3912 3923 3908 3909 3912 3923 3910 3908 4544 3912 3909 3909 3920 4544 3923 3917 3910 4530 3913 3911 3911 4529 4530 3911 4528 4529 4543 4542 3912 4544 4543 3912 4542 3923 3912 3921 3920 3913 4530 3921 3913 4526 4514 3914 4527 4526 3914 3914 4519 4527 3915 3916 3919 3917 3916 3915 4540 3919 3916 3916 3917 4540 3917 4539 4540 5097 4539 3917 3917 4541 5097 3917 3923 4541 4535 4533 3919 4540 4535 3919 3920 3921 3924 5768 4544 3920 3920 3924 5768 5094 3924 3921 3921 4530 5094 5104 4545 3922 5785 5104 3922 3922 5777 5785 3922 5099 5777 4542 4541 3923 3924 5094 5098 3924 5098 5768 3932 3926 3925 4545 3932 3925 4556 4549 3927 4547 4546 3928 4552 4550 3928 3928 4546 4552 3929 3932 4554 5109 5103 3930 3930 3931 5109 3931 5108 5110 3931 4553 5108 3931 3933 4553 5110 5109 3931 4555 4554 3932 5107 4555 3932 3932 4545 5107 5123 4558 3935 5817 5123 3935 3935 4557 5817 3946 3938 3936 3937 3938 3946 3939 3938 3937 4561 3939 3937 5119 4561 3937 5815 5119 3937 3937 3946 5815 4562 3941 3940 4562 3942 3941 4562 3947 3942 3952 3951 3943 3962 3952 3943 3943 3954 3962 3956 3954 3943 5117 3956 3943 3943 3944 5117 3944 4560 5117 3945 4564 5128 5128 3946 3945 3946 5129 5815 3946 5128 5129 5140 3953 3947 5141 5140 3947 3947 4562 5141 3948 3949 3950 4565 3950 3949 5125 4565 3949 5142 5125 3949 3949 3959 5142 3949 3953 3959 4575 3959 3953 5156 4575 3953 3953 5140 5156 5137 4566 3954 3954 3955 5137 3956 3955 3954 4566 3962 3954 3955 5130 5137 3955 3956 5130 3956 5117 5130 5126 4563 3957 5131 5126 3957 3957 3958 5131 5138 5131 3958 3959 4575 5142 4581 4580 3960 3960 4580 5138 3964 3968 3969 3964 3965 3968 3966 3965 3964 3971 3966 3964 3964 3969 3971 3965 3966 3967 4571 3968 3965 3965 4570 4571 5145 4570 3965 3965 4574 5145 3965 3967 4574 3971 3967 3966 4584 4574 3967 3967 3981 4584 3967 3971 3981 3978 3970 3968 4573 3978 3968 3968 4571 4573 3970 3969 3968 3977 3971 3969 3969 3970 3977 3978 3977 3970 3971 3979 3981 3971 3977 3979 4589 3973 3972 4590 4589 3972 3972 4579 4590 4599 3991 3973 3973 4589 4599 3985 3978 3974 3974 3983 3985 3974 3975 3983 3976 3975 3974 3978 3976 3974 3984 3983 3975 4577 3984 3975 3975 3976 4577 3976 4573 4577 3976 3978 4573 3977 3985 3986 3977 3978 3985 3980 3979 3977 3986 3980 3977 3982 3981 3979 3987 3982 3979 3988 3987 3979 3989 3988 3979 3979 3980 3989 3994 3989 3980 3980 3986 3994 4588 4584 3981 3981 3982 4588 4595 4588 3982 3982 3987 4595 4594 3992 3983 3983 3984 4594 5169 4594 3984 3984 5157 5169 3984 4577 5157 3995 3994 3986 3986 3993 3995 3987 3990 4595 3987 3988 3990 3988 3989 3996 3996 3990 3988 3989 3994 3996 3990 3996 4595 4600 3999 3991 3991 4599 4600 4597 3993 3992 3992 4594 4597 4597 3995 3993 3994 4588 4595 5166 4588 3994 5176 5166 3994 3994 5175 5176 3994 5174 5175 3994 3995 5174 4595 3996 3994 3995 5172 5174 3995 4597 5172 4602 4002 3997 3997 3998 4602 5190 4602 3998 5877 5190 3998 5878 5877 3998 3998 4616 5878 4600 4001 3999 4000 4600 5872 4000 4001 4600 5872 4006 4000 5178 4601 4002 5862 5178 4002 4002 5190 5862 4002 4602 5190 4011 4008 4003 4004 4005 4015 4006 4005 4004 4016 4015 4005 4005 4006 4016 4614 4016 4006 5871 4614 4006 5872 5871 4006 4623 4018 4007 4612 4010 4008 5203 4612 4008 4008 4011 5203 4010 4009 4008 4009 4010 4623 5215 4623 4010 4010 4612 5215 5205 5203 4011 5206 5205 4011 4011 4012 5206 4012 4013 5206 4013 4626 5206 4013 4014 4626 4638 4626 4014 4014 4628 4638 4014 4627 4628 4014 4613 4627 4014 4015 4613 4015 4016 4613 4614 4613 4016 4017 4633 4647 4018 4610 4634 4635 4610 4018 4018 4623 4635 4629 4617 4019 4652 4629 4019 4650 4024 4022 4651 4650 4022 4022 4649 4651 4023 4025 4661 5244 4025 4024 4024 5229 5244 4024 5204 5229 4024 4650 5204 5244 4661 4025 4034 4029 4026 4026 4027 4034 4028 4027 4026 4644 4028 4026 4027 4656 4657 5233 4656 4027 5234 5233 4027 4027 4028 5234 4040 4034 4027 4657 4040 4027 5906 5234 4028 4028 5235 5906 5236 5235 4028 4028 4644 5236 4029 4036 4037 4029 4034 4036 4033 4032 4031 4058 4033 4031 5245 4652 4032 4032 4033 5245 5247 5245 4033 4033 4058 5247 4034 4035 4036 4040 4035 4034 4038 4036 4035 4040 4038 4035 4038 4037 4036 4668 4666 4037 4037 4038 4668 4038 4665 4668 4038 4039 4665 4040 4039 4038 4676 4665 4039 5249 4676 4039 4039 4664 5249 4039 4658 4664 4039 4657 4658 4039 4040 4657 4671 4662 4041 4041 4666 4671 4679 4045 4042 4048 4047 4046 4053 4048 4046 4046 4052 4053 4046 4047 4062 4048 4053 4070 5950 5949 4049 5953 5950 4049 4049 5951 5953 4049 4050 5951 4051 4050 4049 5949 4051 4049 4050 4054 5951 4681 4054 4050 4050 4051 4681 4051 4070 4681 5948 4070 4051 5949 5948 4051 4055 4053 4052 4056 4055 4052 4681 4070 4053 4053 4054 4681 4055 4054 4053 4054 4692 5951 4054 4063 4692 4054 4055 4063 4067 4065 4057 4682 4067 4057 4058 4059 5254 5253 5247 4058 5262 5253 4058 4058 5254 5262 4059 4675 5254 5946 5264 4060 4060 5266 5946 4060 4061 5266 4060 4687 4688 5264 4687 4060 4063 4691 4692 4064 4071 4077 4078 4071 4065 4079 4078 4065 4065 4066 4079 4067 4066 4065 4080 4079 4066 4699 4080 4066 4066 4698 4699 4066 4072 4698 4066 4067 4072 5268 4072 4067 5271 5268 4067 4067 4684 5271 4067 4682 4684 5263 4675 4068 5265 5263 4068 4068 4073 5265 4076 4075 4069 4069 4070 4076 5947 4076 4070 5948 5947 4070 4078 4077 4071 5268 4698 4072 5269 5265 4073 4073 4710 5269 4073 4074 4710 5273 4706 4075 4075 4076 5273 4087 4083 4075 4705 4087 4075 4706 4705 4075 5959 5273 4076 4076 5947 5959 4077 4690 4691 4694 4690 4077 4697 4694 4077 4077 4078 4697 4078 4080 4697 4078 4079 4080 4708 4697 4080 4080 4700 4708 4080 4699 4700 4702 4082 4081 4082 4702 4703 4087 4085 4083 5267 5266 4084 5956 5267 4084 4084 4094 5956 4085 4086 4088 4087 4086 4085 4712 4088 4086 4086 4707 4712 4086 4087 4707 4087 4705 4707 4088 4099 4719 4720 4099 4088 4088 4712 4720 4719 4097 4089 4701 4693 4090 4090 4091 4701 5288 4701 4091 5989 5288 4091 4091 4102 5989 5299 4102 4091 4091 4733 5299 5295 5294 4092 4092 4714 5295 5967 4094 4093 4093 4096 5967 5967 5956 4094 4096 4109 5967 4096 4108 4109 4097 4098 4724 4099 4098 4097 4719 4099 4097 4726 4724 4098 5984 4726 4098 4098 5291 5984 4098 4099 5291 4099 4720 5291 4724 4111 4100 4101 5299 5300 4101 4102 5299 4103 4102 4101 5306 4103 4101 4101 5300 5306 4102 4103 5989 4103 5988 5989 4103 5987 5988 4103 5306 5987 5296 4727 4104 4104 4734 5296 4104 4105 4734 5971 4734 4105 4105 5294 5971 4106 4107 5290 5290 4704 4106 5983 5290 4107 4107 5297 5983 4107 4728 5297 4110 4109 4108 4737 4110 4108 4109 5304 5967 4109 4731 5304 4109 4110 4731 5298 4731 4110 5309 5298 4110 4110 4737 5309 4732 4113 4112 5311 4732 4112 4112 5305 5311 4112 4724 5305 4744 4739 4113 4113 4732 4744 4735 4116 4114 4115 4735 4742 4115 4116 4735 4117 4116 4115 4738 4117 4115 5308 4738 4115 4115 4742 5308 4116 4117 5301 5995 5301 4117 4117 4738 5995 4119 4125 4740 4133 4121 4120 4134 4133 4120 4120 4128 4134 4120 4122 4128 4123 4122 4120 4122 4124 4128 4129 4128 4124 4126 4134 5330 4126 4133 4134 5329 4127 4126 5330 5329 4126 6001 5315 4127 6005 6001 4127 4127 5329 6005 4128 4129 4150 4135 4134 4128 4136 4135 4128 4150 4136 4128 5320 4142 4130 4130 4732 5320 4744 4732 4130 4130 4739 4744 5317 4751 4131 5328 4139 4132 4132 4751 5328 4753 4752 4134 4134 4135 4753 4134 4752 5330 4772 4753 4135 4135 4136 4772 5341 4772 4136 4136 4176 5341 4136 4150 4169 4144 4138 4137 4145 4144 4137 4758 4749 4138 4759 4758 4138 4138 4757 4759 4138 4144 4757 4767 4161 4139 4768 4767 4139 5328 4768 4139 5335 4754 4141 4141 4142 5335 4143 4142 4141 4754 4143 4141 4142 5321 5335 4142 5320 5321 4143 4151 4152 4754 4151 4143 4761 4757 4144 4144 4145 4761 4145 4154 4761 4155 4154 4146 4156 4155 4146 4762 4149 4148 4777 4762 4148 4148 4163 4777 4149 4762 4763 4153 4152 4151 4165 4153 4151 4764 4165 4151 4151 4754 4764 4170 4164 4152 4152 4153 4170 4780 4170 4153 4153 4171 4780 4153 4165 4171 4766 4761 4154 4783 4766 4154 4154 4775 4783 4154 4155 4775 4155 4156 4157 4155 4166 4775 4155 4157 4166 4158 4157 4156 4157 4159 4166 4157 4158 4159 4160 4159 4158 4161 4160 4158 4767 4166 4159 4159 4160 4767 4160 4161 4767 4197 4167 4162 4162 4177 4197 4163 4769 4777 6040 4769 4163 4163 4172 6040 4163 4167 4172 4164 4170 4778 5339 4171 4165 4165 5335 5339 4165 4764 5335 4784 4775 4166 4166 4776 4784 4166 4767 4776 6052 4172 4167 4167 4197 6052 4787 4182 4168 4174 4173 4168 4182 4174 4168 4780 4778 4170 5348 4780 4171 4171 5339 5348 6041 6040 4172 6052 6041 4172 4187 4179 4173 4173 4174 4187 4174 4180 4187 4182 4180 4174 4175 4795 4808 5341 4176 4175 4175 4807 5341 4808 4807 4175 4177 4178 4197 4187 4185 4179 4190 4189 4180 6043 4190 4180 4180 4181 6043 4182 4181 4180 6044 6043 4181 4181 5351 6044 4181 4182 5351 4182 4787 5352 5352 5351 4182 4183 4196 4197 4217 4196 4183 4184 4185 4794 4185 4186 4794 4187 4186 4185 4806 4794 4186 4186 4211 4806 4186 4188 4211 4186 4187 4188 4219 4211 4188 4189 4807 4808 4189 4190 4807 6043 4807 4190 4809 4795 4191 4191 4203 4809 4191 4202 4203 4192 4193 4195 4194 4193 4192 4791 4194 4192 4792 4791 4192 4793 4792 4192 5358 4793 4192 4192 4779 5358 4204 4195 4193 4193 4194 4204 4812 4204 4194 4194 4796 4812 4194 4791 4796 4195 4204 4205 4198 4197 4196 4217 4198 4196 4197 4198 4199 4197 5366 6052 4197 4803 5366 4197 4199 4803 4212 4199 4198 4214 4212 4198 4217 4214 4198 4199 4212 4802 5364 4803 4199 4199 4802 5364 4200 4206 4207 4200 4201 4206 4806 4206 4201 4201 4794 4806 4810 4205 4204 4812 4810 4204 4804 4207 4206 4820 4804 4206 4206 4806 4820 4825 4223 4207 4207 4805 4825 4207 4804 4805 4208 4211 4823 4821 4211 4208 6082 4821 4208 6790 6082 4208 4208 4209 6790 4210 4209 4208 4823 4210 4208 6795 6790 4209 6802 6795 4209 4209 5385 6802 4209 4210 5385 4210 4823 5385 4821 4806 4211 4211 4219 4823 4212 4213 4802 4214 4213 4212 5365 5364 4213 4213 4214 5365 5364 4802 4213 4214 4819 5365 4214 4215 4819 4217 4215 4214 4822 4819 4215 4215 4225 4822 4215 4216 4225 4217 4216 4215 4216 4221 4225 4216 4218 4221 4216 4217 4218 4219 4241 4823 4219 4220 4241 4221 4222 4225 4824 4225 4222 4828 4824 4222 4222 4230 4828 4222 4224 4230 4227 4226 4223 5384 4227 4223 4223 4825 5384 4231 4230 4224 4232 4231 4224 4824 4822 4225 4831 4240 4226 4832 4831 4226 4226 4227 4832 6102 4832 4227 4227 6100 6102 4227 5384 6100 4827 4234 4228 4228 4229 4827 4833 4828 4230 4230 4231 4833 4231 4242 4833 4231 4232 4242 4232 4238 4242 4233 4234 4826 4827 4826 4234 4242 4238 4235 4837 4242 4235 5420 4837 4235 4235 4842 5420 4235 4236 4842 4237 4236 4235 5405 4842 4236 4236 5397 5405 4236 4249 5397 4236 4237 4249 4237 4239 4240 4237 4240 4249 5396 4249 4240 4240 4831 5396 5386 4823 4241 4837 4833 4242 6806 4834 4243 4243 5407 6806 4243 5398 5407 4245 4246 4248 4247 4246 4245 4835 4247 4245 4839 4835 4245 5388 4839 4245 4245 4836 5388 4245 4248 4836 4835 4254 4247 4249 5396 5397 4253 4252 4250 4855 4253 4251 4251 4255 4855 5414 4843 4252 4252 4253 5414 5429 5414 4253 4253 4855 5429 4853 4256 4254 4254 4849 4853 4254 4844 4849 4254 4835 4844 4859 4855 4255 4255 4276 4859 4853 4257 4256 4257 4264 4265 4853 4264 4257 4852 4269 4258 5408 4852 4258 4258 4845 5408 4258 4259 4845 4260 4259 4258 4269 4260 4258 4259 4260 4845 4846 4845 4260 4260 4268 4846 4276 4263 4261 4865 4276 4261 5457 4865 4261 5458 5457 4261 4261 4278 5458 4261 4277 4278 4261 4262 4277 4263 4262 4261 4279 4277 4262 4262 4263 4279 4276 4266 4263 4263 4265 4279 4266 4265 4263 4862 4283 4264 4264 4861 4862 4264 4860 4861 4264 4856 4860 4264 4853 4856 4283 4265 4264 4283 4279 4265 4267 4280 4867 4867 4268 4267 6819 4846 4268 4268 6128 6819 4268 4273 6128 4867 4273 4268 4275 4270 4269 4852 4275 4269 4858 4271 4270 5440 4858 4270 4270 4854 5440 4270 4275 4854 6139 4274 4272 4272 5439 6139 4272 4867 5439 4272 4273 4867 4274 4273 4272 4273 4274 6128 4274 6132 7569 6139 6132 4274 7565 6128 4274 7566 7565 4274 7569 7566 4274 5423 4854 4275 4275 4852 5423 4865 4859 4276 4868 4278 4277 4870 4868 4277 4277 4288 4870 4277 4282 4288 4277 4279 4282 5471 5458 4278 4278 4868 5471 4283 4282 4279 5439 4867 4280 4280 4281 5439 4281 4866 5439 4281 4862 4866 4281 4286 4862 4282 4284 4288 4862 4284 4282 4282 4283 4862 4862 4286 4284 4286 4285 4284 4879 4293 4287 4885 4879 4287 4287 4296 4885 4288 4289 4870 4871 4870 4289 4289 4298 4871 4299 4298 4290 4290 4291 4299 4300 4299 4291 4291 4295 4300 4872 4305 4292 5472 4872 4292 4292 4869 5472 4879 4300 4293 4300 4295 4293 4301 4297 4294 4305 4301 4294 4886 4885 4296 4296 4302 4886 4296 4301 4302 4296 4297 4301 4873 4871 4298 4874 4873 4298 4298 4299 4874 4876 4874 4299 4877 4876 4299 4299 4300 4877 4300 4879 4884 4878 4877 4300 4884 4878 4300 4881 4302 4301 4301 4875 4881 4301 4305 4875 4302 4303 4886 4304 4303 4302 4880 4304 4302 4881 4880 4302 4303 4304 6176 5479 4886 4303 6176 5479 4303 4304 4880 6169 4304 6169 6176 4305 4872 4875 4306 4311 4315 4306 4310 4311 4306 4307 4310 4308 4307 4306 4315 4308 4306 4307 4308 4918 4916 4310 4307 5546 4916 4307 5552 5546 4307 4307 4918 5552 4308 4313 4314 4315 4313 4308 4308 4314 4918 4917 4317 4309 4309 4915 4917 4309 4911 4915 4309 4310 4911 4311 4310 4309 4317 4311 4309 4310 4910 4911 4916 4910 4310 4317 4315 4311 4312 4313 4320 4314 4313 4312 4318 4314 4312 4313 4316 4320 4313 4315 4316 5557 4918 4314 4314 4930 5557 4314 4929 4930 4314 4318 4929 4317 4316 4315 4321 4320 4316 4917 4321 4316 4316 4317 4917 4932 4929 4318 4318 4329 4932 4330 4329 4318 4333 4332 4319 4319 4322 4333 4320 4321 4322 4331 4322 4321 4917 4331 4321 4334 4333 4322 4933 4334 4322 4322 4331 4933 4323 4324 4326 4325 4324 4323 4339 4325 4323 4323 4326 4339 4324 4922 4934 5560 4922 4324 5572 5560 4324 4324 4939 5572 4324 4325 4939 4934 4326 4324 4325 4335 4939 4337 4335 4325 4340 4337 4325 4325 4339 4340 4326 4327 4339 4328 4327 4326 4934 4328 4326 4938 4339 4327 4327 4928 4938 4327 4920 4928 4327 4328 4920 4934 4920 4328 4331 4919 4933 4331 4917 4919 4942 4338 4333 4943 4942 4333 4333 4334 4943 6255 4943 4334 4334 6251 6255 4334 4933 6251 4337 4336 4335 5596 4939 4335 4335 4336 5596 4349 4348 4336 4336 4337 4349 4336 4950 5596 4336 4358 4950 4359 4358 4336 4366 4359 4336 4351 4349 4337 4355 4351 4337 4337 4350 4355 4337 4340 4350 4338 4347 4352 4942 4347 4338 5561 4340 4339 4339 4937 5561 4938 4937 4339 5574 4350 4340 6253 5574 4340 4340 5561 6253 5563 4941 4341 5583 5563 4341 4341 4356 5583 4945 4344 4342 4343 4345 4354 4352 4345 4343 4343 4344 4352 4945 4352 4344 4345 4353 4354 4345 4346 4353 4347 4346 4345 4352 4347 4345 4946 4353 4346 5564 4946 4346 4346 4944 5564 4346 4347 4944 4347 4942 4944 4348 4349 4351 4951 4947 4350 5597 4951 4350 4350 5575 5597 4350 5574 5575 4357 4354 4353 4948 4357 4353 5585 4948 4353 7006 5585 4353 4353 6270 7006 4353 4946 6270 4356 4363 5583 6305 4950 4358 4358 4956 6305 4358 4359 4956 5616 4956 4359 4359 4365 5616 4366 4365 4359 4360 4362 4363 4364 4362 4360 4361 4948 4949 4959 4958 4362 4362 4364 4959 4958 4363 4362 4363 4955 5583 4958 4955 4363 4961 4959 4364 6367 5616 4365 4365 4368 6367 4965 4961 4367 4368 5641 6367 4368 4974 5641 4960 4396 4369 6322 4960 4369 7046 6322 4369 4369 4370 7046 4371 4370 4369 4957 4371 4369 4369 4396 4397 4370 7045 7046 4370 7031 7045 4370 5597 7031 4370 4371 5597 4957 4952 4371 4371 4951 5597 4952 4951 4371 4372 4374 4378 4372 4373 4374 4379 4374 4373 4380 4379 4373 4962 4380 4373 4400 4378 4374 4374 4379 4400 4375 4383 4966 5013 4399 4376 4376 4422 5013 4376 4377 4422 4378 4377 4376 4399 4378 4376 4377 4411 4422 4377 4388 4411 4389 4388 4377 4377 4378 4389 4399 4386 4378 4400 4389 4378 4378 4385 4398 4386 4385 4378 4989 4400 4379 4379 4975 4989 4379 4380 4975 4380 4962 4975 4381 4407 4974 5642 4992 4382 4382 5637 5642 5638 5637 4382 4382 4960 5638 4382 4396 4960 4397 4396 4382 4383 4963 4966 4383 4384 4963 4964 4963 4384 4987 4964 4384 4384 4409 4987 4478 4398 4385 4385 4416 4478 4385 4387 4416 4385 4386 4387 4386 4399 5022 5022 4387 4386 5029 4416 4387 4387 5022 5029 4995 4411 4388 4388 4994 4995 4997 4994 4388 4388 4401 4997 4388 4389 4401 4389 4400 4401 4983 4392 4390 4991 4983 4390 4390 4402 4991 4390 4393 4402 4390 4391 4393 4392 4391 4390 4394 4393 4391 4395 4394 4391 4977 4395 4391 4391 4976 4977 4391 4392 4976 4392 5634 5635 4392 4983 5634 4392 4967 4976 6345 4967 4392 4392 5635 6345 4393 4394 4402 4406 4402 4394 4394 4395 4406 4420 4406 4395 4978 4420 4395 4395 4977 4978 4415 4408 4398 4441 4415 4398 4442 4441 4398 4476 4442 4398 4477 4476 4398 4479 4477 4398 4398 4478 4479 4399 5013 5022 4997 4401 4400 4400 4989 4997 4402 4403 4991 4419 4403 4402 4402 4406 4419 4417 4405 4403 4418 4417 4403 4419 4418 4403 4403 4404 4991 4405 4404 4403 4404 4449 4991 5006 4449 4404 5680 5006 4404 4404 5007 5680 4404 4405 5007 4405 4433 4451 4405 4417 4433 4405 4451 5007 4421 4419 4406 4406 4420 4421 5003 4974 4407 4407 5002 5003 4415 4410 4408 4410 4409 4408 4988 4987 4409 4409 4410 4988 4993 4988 4410 4410 4415 4993 4995 4422 4411 5008 5002 4412 4412 4456 5008 5005 4414 4413 4413 4992 5005 4414 5005 5660 5660 5009 4414 4415 4440 4993 4441 4440 4415 5029 4478 4416 4417 4418 4433 4418 4419 4434 4437 4434 4419 4419 4421 4437 4984 4421 4420 4420 4978 4984 5017 4437 4421 5019 5017 4421 5668 5019 4421 4421 5648 5668 4421 4984 5648 4422 4995 5013 4459 4446 4423 4460 4459 4423 4423 4448 4460 4423 4426 4448 4423 4424 4426 4425 4424 4423 4446 4425 4423 4428 4426 4424 5014 4428 4424 5686 5014 4424 5687 5686 4424 4424 4457 5687 4424 4425 4457 4425 4447 4457 4425 4443 4447 4446 4443 4425 4426 4427 4448 4428 4427 4426 4450 4448 4427 4451 4450 4427 4427 4449 4451 4427 4429 4449 4427 4428 4429 4998 4429 4428 5000 4998 4428 5014 5000 4428 5001 4449 4429 4429 4998 5001 4430 4431 4448 4432 4431 4430 4450 4432 4430 4430 4448 4450 4482 4461 4431 4431 4453 4482 4431 4432 4453 4460 4448 4431 4432 4433 4452 4451 4433 4432 4432 4450 4451 4432 4452 4453 4434 4435 4454 4437 4435 4434 4435 4436 4454 4437 4436 4435 5024 4454 4436 4436 5018 5024 4436 5017 5018 4436 4437 5017 5008 4456 4438 4438 4489 5008 4438 4465 4489 4468 4455 4439 5046 4993 4440 4440 4472 5046 4440 4441 4472 4473 4472 4441 4441 4442 4473 4493 4473 4442 4442 4476 4493 4458 4447 4443 4443 4444 4458 4445 4444 4443 4446 4445 4443 4480 4458 4444 4444 4445 4480 4445 4446 4480 5036 4480 4446 4446 4481 5036 4446 4459 4481 4458 4457 4447 4449 4990 4991 5001 4990 4449 5016 4451 4449 4449 5006 5016 5016 5007 4451 4462 4453 4452 4464 4462 4452 4452 4454 4464 4483 4482 4453 5051 4483 4453 5703 5051 4453 4453 5702 5703 4453 5037 5702 4453 4462 5037 5024 4464 4454 4492 4467 4455 4455 4468 4492 5692 5687 4457 4457 4458 5692 4458 5035 5701 4458 4480 5035 5698 5692 4458 4458 5048 5698 5049 5048 4458 5701 5049 4458 5050 4481 4459 4461 4482 4500 4462 4463 5037 4464 4463 4462 5039 5037 4463 4463 5038 5039 4463 5031 5038 4463 5023 5031 4463 4464 5023 5024 5023 4464 4465 4466 4489 4467 4466 4465 4491 4489 4466 5043 4491 4466 5044 5043 4466 5057 5044 4466 4466 5026 5057 4466 4467 5026 4467 4492 5026 4468 4470 4492 4468 4469 4470 4471 4470 4469 5712 4471 4469 6398 5712 4469 4469 5697 6398 5045 4492 4470 4470 4471 5045 5720 5045 4471 6422 5720 4471 4471 5712 6422 4472 5027 5046 5028 5027 4472 4472 4474 5028 4472 4473 4474 4475 4474 4473 4493 4475 4473 5063 5028 4474 4474 4499 5063 4474 4475 4499 4475 4493 4499 5062 4493 4476 5066 5062 4476 5722 5066 4476 6405 5722 4476 4476 4477 6405 4477 4479 6405 5029 4479 4478 4479 5030 6405 4479 5012 5030 5029 5012 4479 5036 5035 4480 5050 5036 4481 4501 4500 4482 4482 4483 4501 5051 4501 4483 5707 5040 4484 4484 5052 5707 4484 4485 5052 5054 5052 4485 4486 4487 6403 4488 4487 4486 5055 4488 4486 6403 5055 4486 4487 5042 5709 4487 4488 5042 4487 5709 6403 4498 4496 4488 5055 4498 4488 5678 5008 4489 5681 5678 4489 4489 4490 5681 4491 4490 4489 4490 4491 5681 5696 5681 4491 4491 5043 5696 5045 5026 4492 5062 4499 4493 4498 4497 4496 5056 4508 4498 4498 5055 5056 4499 5061 5063 5062 5061 4499 5071 4506 4500 4500 4501 5071 4501 5051 5071 5734 4521 4503 4503 5725 5734 4503 4506 5725 4504 4507 5072 5067 5035 4505 5075 5067 4505 4506 5714 5725 4506 5071 5714 5719 4509 4508 4508 5717 5719 4508 5056 5717 4509 5728 5751 4509 5727 5728 4509 5719 5727 4510 4513 4525 4516 4513 4510 4510 4511 4516 4512 4511 4510 4525 4512 4510 5089 4516 4511 4511 4512 5089 4512 4532 5089 4512 4525 4532 4520 4515 4513 4513 4516 4520 4531 4525 4513 4513 4518 4531 4519 4518 4513 4527 4519 4513 4513 4526 4527 4513 4514 4526 4515 4514 4513 4515 4520 5088 5081 4520 4516 5089 5081 4516 5776 5769 4517 4534 4531 4518 4518 4533 4534 4518 4519 4533 4520 5076 5088 4520 5070 5076 5082 5070 4520 4520 5081 5082 6438 5742 4521 4521 5734 6438 5742 4522 4521 4529 4528 4522 5765 4529 4522 4522 5760 5765 4522 5742 5760 5771 4532 4523 5772 5771 4523 4523 5091 5772 4523 4524 5091 4525 4524 4523 4532 4525 4523 4524 4525 4531 5092 5091 4524 4524 4537 5092 4524 4536 4537 4524 4531 4536 5768 4530 4529 4529 5766 5768 4529 5765 5766 5780 5094 4530 4530 5768 5780 4538 4536 4531 4531 4534 4538 5770 5740 4532 5771 5770 4532 5090 5089 4532 5741 5090 4532 4532 5740 5741 4535 4534 4533 5096 4538 4534 5787 5096 4534 4534 4535 5787 5789 5787 4535 4535 4540 5789 4548 4537 4536 4536 4538 4548 5095 5092 4537 4537 4548 5095 5095 4548 4538 4538 5092 5095 5096 5092 4538 5100 4540 4539 5795 5100 4539 5796 5795 4539 4539 5097 5796 4540 5100 5789 5790 5097 4541 4541 5779 5790 4541 4542 5779 4542 4543 5773 4542 5773 5779 4543 5762 5773 5766 5762 4543 4543 4544 5766 5768 5766 4544 4545 5104 5107 4546 5101 5797 4546 4547 5101 5797 4552 4546 5102 5101 4547 4547 4549 5102 4549 4556 5102 5809 4560 4551 5813 5809 4551 6488 5813 4551 4551 5808 6488 4551 5807 5808 4551 4552 5807 4552 5797 5807 5115 5108 4553 5123 5115 4553 4553 4558 5123 5810 5116 4554 4554 5805 5810 4554 4555 5805 4555 5801 5805 4555 5107 5801 4556 5111 5811 5112 5111 4556 4556 4559 5112 5806 5102 4556 5811 5806 4556 4557 5121 5817 5124 5112 4559 5125 5124 4559 4559 4565 5125 5118 5117 4560 5809 5118 4560 5816 5113 4561 4561 5119 5816 5804 5141 4562 4562 5116 5804 4563 5126 5127 4564 4572 5144 5143 4572 4564 5824 5143 4564 5144 5128 4564 5137 4576 4566 4573 4571 4567 4567 4568 4573 4569 4568 4567 4571 4569 4567 4577 4573 4568 4587 4577 4568 5143 4587 4568 4568 4569 5143 4569 4572 5143 4569 4571 4572 4570 5145 5146 4572 4571 4570 4578 4572 4570 5146 4578 4570 4572 4578 5144 5150 5145 4574 5159 5150 4574 4574 4584 5159 5161 5142 4575 4575 5156 5161 4576 5137 5831 5838 4579 4576 4576 5831 5838 4577 4582 5157 4583 4582 4577 4587 4583 4577 4578 5129 5144 5132 5129 4578 5146 5132 4578 5848 4590 4579 4579 5838 5848 4580 4581 5829 4580 4583 5138 4580 4582 4583 5829 4582 4580 4581 5162 5829 5171 5157 4582 5833 5171 4582 4582 5829 5833 4583 4587 5138 4584 4588 5159 5842 4591 4585 4585 4593 5842 4585 4592 4593 4585 4586 4592 4596 4592 4586 4587 5126 5138 5127 5126 4587 5143 5127 4587 4588 5158 5159 5165 5158 4588 5166 5165 4588 4589 4590 6527 6529 4599 4589 4589 6527 6529 4590 5848 6527 5829 5162 4591 5834 5829 4591 5842 5834 4591 5854 4593 4592 4592 5177 5854 4592 4596 5177 5854 5842 4593 4598 4597 4594 5169 4598 4594 5855 5177 4596 4596 5178 5855 4596 4601 5178 5173 5172 4597 4597 4598 5173 5179 5173 4598 4598 5170 5179 4598 5169 5170 5873 4600 4599 6529 5873 4599 5873 5872 4600 4605 4604 4603 4606 4605 4603 4607 4606 4603 4603 4604 4607 5195 5193 4604 4604 4605 5195 4608 4607 4604 5193 4608 4604 4605 4606 5195 5199 5195 4606 5202 5199 4606 4606 4622 5202 4606 4607 4622 4607 4620 4622 4621 4620 4607 4607 4618 4621 4619 4618 4607 4607 4608 4619 5192 4619 4608 4608 5191 5192 5193 5191 4608 4651 4649 4609 5228 4651 4609 4609 5215 5228 4609 4635 5215 4609 4610 4635 4611 4610 4609 4649 4611 4609 4648 4634 4610 4610 4611 4648 4660 4648 4611 5228 5215 4612 5889 5228 4612 4612 5203 5889 4613 4615 4627 4613 4614 4615 5207 4615 4614 5871 5207 4614 4628 4627 4615 5219 4628 4615 5220 5219 4615 5885 5220 4615 4615 5882 5885 4615 5207 5882 5884 5878 4616 4616 5216 5884 4616 4617 5216 5221 5216 4617 5222 5221 4617 4617 4629 5222 4630 4621 4618 4640 4630 4618 5198 4640 4618 4618 5197 5198 4618 4619 5197 5200 5197 4619 4619 5196 5200 4619 5192 5196 4641 4622 4620 4620 4632 4641 4620 4631 4632 4620 4630 4631 4620 4621 4630 5212 5202 4622 4622 4641 5212 5215 4635 4623 4624 5205 5206 5229 5205 4624 4624 4625 5229 4626 4625 4624 5206 4626 4624 5891 5229 4625 4625 4626 5891 5898 5891 4626 4626 4636 5898 4638 4636 4626 5899 4638 4628 4628 5219 5899 5223 5222 4629 4629 5208 5223 4629 4652 5208 4640 4631 4630 4653 4632 4631 4631 4639 4653 4640 4639 4631 4642 4641 4632 4643 4642 4632 4653 4643 4632 4633 4648 4660 4633 4634 4648 6556 5898 4636 4636 4637 6556 4638 4637 4636 4637 5900 6556 4637 5899 5900 4637 4638 5899 4639 5198 5211 4639 4640 5198 5232 4653 4639 4639 5230 5232 4639 5211 5230 5213 5212 4641 4641 4642 5213 5214 5213 4642 4642 4654 5214 4642 4643 4654 4658 4654 4643 4664 4658 4643 4667 4664 4643 4643 4653 4667 4644 4645 5236 5237 5236 4645 5238 5237 4645 4645 5227 5238 5238 5227 4646 4646 4659 5238 5889 5204 4650 4650 5228 5889 4650 4651 5228 5245 5208 4652 5904 4667 4653 4653 5232 5904 4654 4655 5214 4658 4655 4654 5226 5214 4655 4655 4656 5226 4657 4656 4655 4658 4657 4655 5895 5226 4656 4656 5233 5895 5239 5238 4659 5240 5239 4659 5241 5240 4659 4661 5242 5243 5244 5242 4661 4669 4663 4662 4671 4669 4662 4663 4672 5246 4673 4672 4663 4663 4669 4673 5255 5249 4664 5256 5255 4664 5929 5256 4664 4664 4667 5929 4677 4668 4665 4665 4676 4677 4666 4668 4671 4667 5904 5929 4668 4677 4678 4668 4670 4671 5258 4670 4668 4668 4678 5258 5259 4673 4669 4669 4670 5259 4671 4670 4669 4670 5258 5944 7337 5259 4670 4670 6601 7337 6603 6601 4670 6613 6603 4670 4670 5944 6613 5931 5246 4672 4672 4673 5931 4673 5930 5931 4673 5259 5930 4683 4682 4674 5248 4683 4674 4675 5918 5935 5941 5918 4675 4675 5263 5941 5935 5254 4675 5249 4677 4676 4677 5257 5943 4677 5256 5257 4677 5255 5256 4677 5249 5255 5943 4678 4677 5942 5258 4678 5943 5942 4678 4685 4684 4682 5260 4685 4682 5261 5260 4682 5940 5261 4682 4682 4683 5940 6589 5940 4683 4683 5251 6589 4683 5248 5251 5952 5271 4684 4684 4685 5952 7347 5952 4685 4685 7340 7347 4685 5260 7340 4723 4718 4686 5264 4723 4686 4686 4687 5264 4692 4691 4689 5954 4692 4689 5955 5954 4689 4689 4690 5955 4691 4690 4689 4690 4695 5955 4690 4694 4695 5954 5951 4692 5279 4710 4693 4693 5278 5279 5287 5278 4693 4693 4701 5287 4696 4695 4694 4708 4696 4694 4694 4697 4708 6639 5955 4695 6653 6639 4695 4695 6652 6653 4695 4696 6652 4696 5292 6652 4696 4708 5292 4700 4699 4698 4709 4700 4698 5268 4709 4698 5285 4708 4700 4700 5275 5285 4700 4709 5275 5288 5287 4701 4704 4703 4702 4703 4704 5281 5290 5281 4704 5963 4707 4705 4705 5274 5963 4705 4706 5274 4706 5273 5274 5282 4711 4707 5963 5282 4707 4707 4711 4712 4708 5285 5292 5276 5275 4709 5277 5276 4709 4709 5268 5277 5279 5269 4710 4713 4712 4711 5282 4713 4711 4712 4713 4720 5975 4720 4713 6661 5975 4713 4713 5282 6661 5982 5295 4714 4714 5280 5982 8252 6667 4715 8255 8252 4715 4715 7402 8255 4715 4716 7402 4717 4716 4715 6667 4717 4715 4716 6668 7402 4716 5974 6668 6659 5974 4716 4716 4717 6659 6665 5971 4717 6667 6665 4717 4717 5982 6659 4717 5971 5982 4723 4721 4718 5976 5291 4720 4720 5975 5976 6649 5958 4721 4721 4722 6649 4723 4722 4721 4722 6622 6649 4722 5946 6622 4722 4723 5946 4723 5264 5946 4724 4725 5305 4726 4725 4724 5311 5305 4725 5313 5311 4725 5997 5313 4725 4725 5990 5997 4725 4726 5990 4726 5985 5990 4726 5984 5985 5300 4733 4727 5307 5300 4727 4727 5296 5307 4728 4729 5297 5303 5297 4729 5958 4736 4730 4731 5298 7412 6633 5304 4731 7412 6633 4731 4732 5311 5320 5300 5299 4733 6665 5296 4734 4734 5971 6665 4743 4742 4735 5958 5318 4736 5315 5309 4737 5999 5995 4738 6000 5999 4738 4738 5308 6000 4745 4743 4741 5314 5308 4742 5326 5314 4742 4742 5316 5326 4742 4745 5316 4742 4743 4745 4745 4750 5316 4745 4749 4750 4746 4749 4755 4750 4749 4746 4746 4747 4750 4748 4747 4746 4755 4748 4746 5322 4750 4747 4747 4748 5322 4748 4756 5322 4748 4755 4756 4758 4755 4749 4750 5322 5323 5323 5316 4750 4751 5324 5328 4751 5317 5324 4752 4753 4772 6017 5330 4752 6029 6017 4752 4752 6018 6029 4752 4772 6018 5335 4764 4754 4760 4756 4755 4755 4758 4760 5325 5322 4756 4756 4760 5325 4773 4759 4757 5340 4773 4757 4757 4774 5340 4757 4761 4774 5325 4760 4758 6010 5325 4758 4758 5331 6010 4758 4765 5331 4758 4759 4765 4773 4765 4759 4761 4766 4774 5334 4763 4762 5338 5334 4762 4762 4770 5338 4777 4770 4762 6053 5337 4763 4763 5334 6053 5336 5331 4765 4765 4773 5336 4782 4774 4766 4766 4781 4782 4783 4781 4766 6037 4776 4767 6050 6037 4767 4767 6038 6050 4767 4768 6038 6039 6038 4768 4768 6014 6039 4768 5328 6014 4769 4770 4777 4771 4770 4769 6722 4771 4769 6723 6722 4769 4769 6040 6723 4770 4771 5338 6724 5338 4771 4771 6722 6724 6042 6018 4772 4772 5342 6042 4772 5341 5342 5340 5336 4773 4774 4782 5340 4785 4783 4775 4786 4785 4775 4775 4784 4786 6037 4784 4776 4778 4780 5347 5346 4779 4778 5347 5346 4778 4779 5357 5358 4779 5346 5357 6033 6023 4780 4780 5348 6033 6023 5347 4780 4788 4782 4781 4781 4783 4788 6034 5340 4782 4782 4789 6034 4782 4788 4789 5349 4788 4783 4783 4790 5349 4783 4785 4790 5350 4786 4784 6037 5350 4784 4785 4786 4790 5349 4790 4786 5350 5349 4786 4787 5337 5352 4788 5349 6048 6057 4789 4788 6058 6057 4788 6059 6058 4788 4788 6048 6059 6057 6034 4789 4797 4796 4791 4791 4792 4797 4792 4793 5353 5353 4797 4792 6056 5356 4793 4793 5358 6056 5356 5353 4793 4795 4809 5359 5359 4808 4795 5370 4812 4796 5371 5370 4796 4796 5360 5371 4796 4797 5360 4797 5355 5360 4797 5353 5355 4816 4814 4798 4798 4801 4816 4798 4799 4801 4800 4799 4798 4814 4800 4798 5361 4801 4799 5362 5361 4799 4799 4800 5362 4800 4815 5362 4800 4814 4815 5363 4816 4801 4801 5361 5363 6060 5366 4803 4803 5364 6060 5367 4805 4804 6067 5367 4804 4804 4820 6067 5367 4825 4805 4821 4820 4806 5342 5341 4807 6042 5342 4807 6043 6042 4807 4809 4817 5359 4810 4811 4813 4812 4811 4810 5379 5378 4811 4811 5370 5379 4811 4812 5370 5378 4813 4811 5378 4827 4813 4818 4815 4814 4814 4816 4818 5372 5362 4815 5380 5372 4815 4815 4818 5380 5375 4818 4816 4816 5363 5375 5381 5380 4818 4818 5375 5381 5382 5365 4819 4819 4822 5382 4820 5369 6067 6082 5369 4820 4820 4821 6082 5383 5382 4822 4822 4829 5383 4822 4824 4829 5386 5385 4823 4824 4828 4829 4825 5367 5384 5387 4836 4826 4826 4827 5387 4827 5378 5387 4830 4829 4828 4833 4830 4828 6099 5383 4829 6106 6099 4829 4829 5391 6106 4829 4830 5391 4830 5390 5391 4830 4833 5390 6111 5396 4831 4831 6102 6111 4831 4832 6102 4833 4847 5390 4833 4837 4847 4834 5385 5386 6806 5385 4834 5399 4844 4835 5415 5399 4835 4835 4839 5415 4836 6088 6803 4836 5387 6088 5389 5388 4836 6803 5389 4836 4848 4847 4837 5420 4848 4837 4838 4843 5398 6112 5415 4839 4839 5388 6112 5421 5420 4840 4840 4841 5421 4842 4841 4840 5420 4842 4840 5428 5421 4841 4841 5422 5428 4841 4842 5422 6118 5422 4842 4842 5405 6118 5406 5398 4843 5414 5406 4843 4850 4849 4844 5399 4850 4844 4845 4851 5408 4845 4846 4851 5409 4851 4846 5411 5409 4846 6819 5411 4846 5402 5390 4847 5404 5402 4847 5427 5404 4847 4847 4848 5427 4848 5426 5427 4848 5425 5426 4848 5421 5425 4848 5420 5421 4857 4853 4849 6127 4857 4849 4849 4850 6127 7569 6127 4850 4850 7566 7569 4850 6818 7566 4850 6810 6818 4850 5399 6810 6113 5408 4851 4851 5409 6113 5424 5423 4852 4852 5412 5424 4852 5408 5412 4857 4856 4853 5441 5440 4854 4854 5423 5441 4855 4859 5429 6137 4860 4856 6138 6137 4856 4856 4857 6138 4857 6132 6138 4857 6127 6132 5440 4863 4858 5442 5429 4859 4859 4865 5442 5459 4861 4860 4860 5439 5459 6139 5439 4860 4860 6137 6139 4866 4862 4861 5459 4866 4861 5449 4864 4863 4863 5440 5449 5460 4869 4864 6150 5460 4864 4864 5449 6150 6136 5442 4865 4865 5457 6136 5459 5439 4866 4868 5470 5471 6156 5470 4868 4868 5474 6156 4868 4870 5474 5473 5472 4869 4869 5468 5473 4869 5460 5468 4870 4871 5474 4871 4873 5474 4881 4875 4872 5472 4881 4872 4873 4882 5474 4873 4874 4882 4883 4882 4874 4874 4876 4883 5477 4883 4876 5478 5477 4876 4876 4877 5478 5484 5478 4877 4877 4878 5484 4878 4884 5484 4885 4884 4879 4880 4881 6169 4881 6166 6169 6167 6166 4881 4881 6157 6167 4881 5472 6157 6165 5474 4882 4882 5475 6165 4882 4883 5475 5476 5475 4883 5477 5476 4883 4884 4885 4887 4884 4887 5484 4885 4886 4887 5479 4887 4886 6187 5484 4887 6191 6187 4887 6879 6191 4887 4887 5479 6879 5537 5536 4888 5538 5537 4888 4888 4892 5538 4893 4892 4888 4888 4891 4893 4888 4889 4891 4890 4889 4888 5536 4890 4888 5529 4891 4889 4889 5527 5529 4889 5526 5527 4889 4890 5526 4890 5522 5526 5528 5522 4890 6220 5528 4890 4890 5536 6220 4891 4896 4897 5530 4896 4891 5531 5530 4891 4891 5529 5531 4897 4893 4891 4901 4895 4892 4892 4898 4901 4892 4897 4898 4892 4893 4897 4892 4894 5538 4895 4894 4892 5539 5538 4894 4894 4903 5539 4894 4895 4903 4895 4900 4903 4901 4900 4895 4898 4897 4896 4899 4898 4896 5530 4899 4896 4902 4901 4898 4907 4902 4898 5535 4907 4898 4898 4899 5535 4899 5530 5535 4904 4903 4900 4905 4904 4900 4908 4905 4900 4900 4901 4908 4901 4902 4908 4914 4908 4902 4902 4906 4914 4907 4906 4902 4903 4904 6231 6227 5539 4903 6230 6227 4903 6231 6230 4903 4904 4912 6231 4904 4909 4912 4904 4905 4909 4905 4908 4909 5540 4914 4906 4906 4907 5540 6225 5540 4907 4907 6222 6225 4907 5533 6222 5535 5533 4907 4913 4909 4908 4914 4913 4908 4913 4911 4909 4909 4910 4912 4911 4910 4909 5542 4912 4910 4910 4916 5542 4911 4913 4915 5542 5541 4912 4912 5541 6231 5544 4915 4913 4913 4914 5544 4914 5543 5544 4914 5540 5543 4915 5544 5545 4926 4917 4915 6242 4926 4915 4915 6233 6242 4915 5545 6233 5546 5542 4916 4926 4919 4917 5557 5552 4918 5558 4933 4919 5559 5558 4919 4919 4926 5559 4920 4921 4927 4922 4921 4920 4934 4922 4920 4920 4927 4928 4921 4923 4927 5548 4923 4921 4921 5547 5548 6963 5547 4921 4921 5560 6963 4921 4922 5560 4925 4924 4923 5556 4925 4923 4923 5548 5556 4923 4924 4927 4924 4925 4936 4928 4927 4924 4938 4928 4924 4924 4937 4938 4924 4936 4937 6245 4936 4925 4925 5550 6245 4925 5549 5550 5556 5549 4925 6242 5559 4926 4931 4930 4929 5562 4931 4929 4929 4940 5562 4929 4932 4940 6244 5557 4930 6964 6244 4930 4930 4931 6964 7727 6964 4931 4931 6972 7727 6973 6972 4931 4931 5562 6973 4941 4940 4932 4933 5558 6251 4935 6248 6978 4935 6245 6248 4935 4936 6245 4937 4936 4935 6978 4937 4935 6253 5561 4937 6978 6253 4937 5573 5572 4939 6280 5573 4939 4939 5596 6280 6254 5562 4940 4940 4941 6254 4941 5563 6254 5564 4944 4942 4942 4943 5564 6255 5564 4943 4946 6256 6270 4946 5564 6256 4947 4951 4952 6289 4949 4948 4948 5585 6289 4949 5588 6319 6289 5588 4949 6304 5596 4950 6305 6304 4950 5583 4955 4953 6267 5583 4953 7800 6267 4953 4953 7791 7800 4953 4954 7791 4955 4954 4953 4954 6318 7791 4954 4955 6318 4955 5610 6318 4955 4958 5610 4956 5616 6305 5617 5610 4958 4958 4959 5617 4959 4961 5617 6322 5638 4960 5626 5617 4961 4961 4965 5626 5627 4975 4962 5628 5627 4962 4962 5601 5628 5619 4966 4963 6325 5619 4963 6349 6325 4963 4963 4964 6349 6371 6349 4964 4964 6370 6371 4964 4987 6370 4965 5618 5626 5619 5618 4965 4965 4966 5619 4967 4970 4976 4967 4968 4970 4969 4968 4967 6345 4969 4967 6335 4970 4968 4968 6333 6335 4968 4969 6333 6345 6333 4969 4977 4976 4970 4979 4977 4970 6335 4979 4970 4971 4979 6335 4971 4977 4979 4971 4972 4977 4973 4972 4971 5636 4973 4971 6335 5636 4971 4972 4973 4986 4978 4977 4972 4984 4978 4972 4986 4984 4972 6353 5639 4973 7080 6353 4973 4973 6346 7080 4973 5636 6346 5639 4986 4973 4974 5003 5641 6339 4989 4975 4975 5627 6339 4991 4990 4980 4980 4983 4991 4980 4981 4983 4982 4981 4980 4990 4982 4980 5644 4983 4981 4981 4982 5644 5656 5644 4982 4982 4990 5656 5645 5634 4983 4983 5644 5645 4984 5647 5648 4984 4985 5647 4986 4985 4984 4985 5640 5647 4985 5639 5640 4985 4986 5639 6324 6323 4987 4987 5661 6324 4987 4988 5661 4987 6323 6370 4988 4993 5661 5665 4997 4989 4989 5663 5665 6360 5663 4989 4989 6340 6360 4989 6339 6340 4990 5001 5656 5642 5005 4992 4993 5046 5661 4994 4997 5665 4996 4995 4994 5021 4996 4994 5665 5021 4994 4995 4996 5013 4996 5010 5013 5021 5010 4996 4998 4999 5001 5000 4999 4998 5667 5001 4999 4999 5000 5667 5000 5666 5667 5000 5015 5666 5000 5014 5015 5657 5656 5001 5667 5657 5001 5004 5003 5002 5658 5004 5002 5678 5658 5002 5002 5008 5678 5003 5004 5641 5658 5641 5004 5005 5642 5660 5680 5016 5006 5007 5016 5680 6389 5682 5009 5009 6388 6389 5009 5679 6388 5009 5660 5679 5022 5013 5010 5010 5011 5022 5012 5011 5010 5020 5012 5010 5021 5020 5010 5011 5012 5029 5029 5022 5011 5012 5020 5030 5686 5015 5014 6376 5666 5015 6391 6376 5015 5015 5686 6391 5019 5018 5017 5025 5024 5018 5695 5025 5018 5018 5694 5695 5018 5019 5694 5019 5668 5694 5020 5021 5030 5700 5030 5021 7925 5700 5021 5021 5685 7925 5021 5665 5685 5023 5024 5031 5024 5025 5031 5032 5031 5025 5695 5032 5025 5026 5045 5057 5047 5046 5027 6395 5047 5027 5027 5034 6395 5027 5028 5034 5713 5034 5028 5721 5713 5028 5028 5063 5721 6426 6405 5030 5030 5699 6426 5700 5699 5030 5031 5033 5038 5031 5032 5033 5705 5033 5032 6402 5705 5032 5032 5695 6402 5704 5038 5033 5705 5704 5033 5034 5713 6395 5035 5067 5068 5035 5068 5701 6400 5702 5037 5037 5039 6400 5704 5039 5038 5039 5704 6408 7143 6400 5039 5039 7142 7143 7145 7142 5039 5039 6408 7145 5706 5041 5040 5708 5706 5040 5040 5707 5708 5709 5042 5041 5041 5706 5709 5711 5696 5043 5043 5044 5711 6421 5711 5044 5044 5077 6421 5044 5057 5077 5060 5057 5045 5720 5060 5045 6382 5661 5046 5046 5047 6382 5047 6395 7124 7113 6382 5047 7124 7113 5047 7116 5698 5048 7125 7116 5048 5048 5049 7125 7126 7125 5049 5049 5732 7126 5049 5701 5732 5714 5071 5051 5715 5714 5051 5051 5703 5715 6411 5707 5052 5052 5053 6411 5054 5053 5052 6428 6411 5053 6429 6428 5053 5053 5737 6429 5053 5054 5737 5716 5056 5055 6416 5716 5055 5055 6413 6416 5055 6403 6413 5056 5716 5717 5057 5058 5077 5060 5058 5057 5085 5078 5058 5058 5059 5085 5060 5059 5058 5078 5077 5058 5729 5085 5059 5059 5060 5729 5060 5720 5729 5073 5063 5061 5074 5073 5061 5061 5064 5074 5061 5062 5064 5066 5064 5062 5063 5073 5721 5080 5074 5064 5064 5065 5080 5066 5065 5064 5065 5066 5722 5739 5080 5065 5065 5731 5739 5065 5722 5731 5070 5069 5067 5075 5070 5067 5069 5068 5067 5068 5069 5701 5069 5070 5724 5724 5701 5069 5070 5723 5724 5070 5082 5723 5070 5075 5076 5073 5086 5730 5087 5086 5073 5073 5079 5087 5073 5074 5079 5730 5721 5073 5080 5079 5074 5077 5761 6421 5077 5078 5761 5078 5743 5761 5078 5085 5743 5745 5087 5079 5079 5080 5745 5080 5740 5745 5080 5739 5740 5083 5082 5081 5090 5083 5081 5081 5089 5090 5082 5083 5723 5083 5741 6423 5083 5090 5741 6406 5723 5083 6423 6406 5083 5738 5737 5084 5747 5738 5084 5744 5743 5085 5085 5729 5744 6443 5730 5086 5086 5087 6443 5087 5746 6443 5087 5745 5746 5091 5092 5093 5778 5772 5091 5091 5093 5778 5096 5093 5092 5788 5778 5093 5093 5096 5788 5780 5098 5094 5096 5786 5788 5787 5786 5096 5097 5790 5796 5780 5768 5098 6481 5789 5100 5100 5795 6481 5101 5102 5797 5806 5797 5102 5103 5781 5784 5792 5781 5103 5103 5105 5792 5106 5105 5103 5109 5106 5103 5802 5107 5104 6485 5802 5104 5104 5785 6485 5800 5792 5105 5105 5799 5800 5105 5106 5799 6489 5799 5106 5106 5109 6489 5802 5801 5107 5803 5110 5108 5108 5114 5803 5115 5114 5108 5109 5803 6489 5109 5110 5803 5828 5821 5111 5111 5124 5828 5111 5112 5124 5821 5811 5111 5825 5148 5113 5113 5816 5825 6489 5803 5114 6497 6489 5114 6504 6497 5114 7218 6504 5114 5114 5115 7218 5115 6496 7218 5115 6495 6496 5115 5817 6495 5115 5123 5817 5810 5804 5116 5117 5118 5130 5814 5130 5118 5118 5813 5814 5118 5809 5813 5825 5816 5119 5119 5133 5825 5815 5133 5119 5122 5121 5120 5826 5122 5120 6506 5826 5120 6507 6506 5120 5120 5136 6507 5120 5135 5136 5148 5135 5120 5818 5817 5121 5121 5122 5818 5819 5818 5122 5826 5819 5122 5124 5142 5828 5124 5125 5142 5126 5131 5138 5127 5143 5824 5144 5129 5128 5129 5133 5815 5129 5132 5133 5814 5137 5130 5134 5133 5132 5146 5134 5132 5133 5139 5825 5133 5134 5139 5150 5149 5134 5134 5145 5150 5146 5145 5134 5149 5139 5134 5151 5136 5135 5153 5151 5135 5135 5147 5153 5148 5147 5135 5136 5154 6507 5155 5154 5136 5136 5151 5155 5137 5814 5832 5832 5831 5137 5139 5148 5825 5139 5147 5148 5149 5147 5139 5160 5156 5140 5140 5141 5160 5830 5160 5141 7227 5830 5141 5141 5827 7227 5141 5804 5827 5142 5821 5828 5142 5161 5821 5164 5153 5147 5147 5163 5164 5147 5149 5163 5149 5150 5163 5165 5163 5150 5150 5158 5165 5159 5158 5150 5151 5152 5155 5153 5152 5151 5839 5155 5152 5152 5153 5839 5153 5164 5839 6508 6507 5154 5154 5835 6508 5154 5155 5835 5837 5835 5155 5155 5836 5837 5839 5836 5155 5840 5161 5156 5841 5840 5156 5156 5160 5841 5170 5169 5157 5157 5167 5170 5168 5167 5157 5171 5168 5157 5847 5841 5160 5160 5830 5847 5840 5821 5161 5849 5164 5163 5163 5165 5849 5846 5839 5164 5164 5843 5846 5845 5843 5164 5849 5845 5164 5165 5166 5849 5166 5183 5849 5166 5176 5183 5167 5168 5855 5185 5170 5167 5196 5185 5167 5855 5196 5167 5168 5834 5854 5168 5833 5834 5168 5171 5833 5168 5854 5855 5185 5179 5170 5175 5174 5172 5187 5175 5172 5188 5187 5172 5858 5188 5172 5172 5180 5858 5181 5180 5172 5172 5173 5181 5173 5179 5181 5184 5176 5175 5189 5184 5175 5175 5187 5189 5176 5182 5183 5184 5182 5176 5855 5854 5177 5862 5855 5178 5186 5181 5179 5179 5185 5186 5869 5858 5180 5180 5194 5869 5180 5181 5194 5181 5186 5194 5864 5860 5182 5182 5189 5864 5182 5184 5189 5860 5183 5182 5851 5849 5183 5860 5851 5183 5191 5186 5185 5196 5191 5185 5201 5194 5186 5186 5191 5201 5863 5189 5187 5880 5863 5187 5187 5188 5880 5188 5869 5880 5188 5858 5869 5189 5863 5864 5877 5862 5190 5191 5193 5201 5196 5192 5191 5193 5194 5201 5195 5194 5193 5870 5869 5194 5194 5199 5870 5194 5195 5199 5877 5200 5196 5196 5862 5877 5196 5855 5862 5197 5200 5217 5218 5198 5197 5197 5217 5218 5218 5211 5198 5199 5202 5870 5200 5877 5878 5878 5217 5200 5202 5212 5870 5203 5204 5889 5205 5204 5203 5204 5205 5229 5883 5882 5207 5207 5871 5883 5208 5209 5223 5210 5209 5208 5231 5210 5208 5245 5231 5208 5209 5222 5223 5886 5222 5209 5209 5217 5886 5209 5210 5217 5218 5217 5210 5210 5211 5218 5230 5211 5210 5231 5230 5210 5879 5870 5212 5881 5879 5212 5212 5225 5881 5212 5213 5225 5213 5224 5225 5213 5214 5224 5888 5224 5214 5214 5226 5888 5886 5884 5216 5216 5221 5886 5217 5884 5886 5217 5878 5884 5219 5893 5899 5894 5893 5219 5219 5220 5894 5220 5892 5894 5220 5885 5892 5221 5222 5886 5887 5225 5224 6537 5887 5224 6539 6537 5224 5224 5888 6539 5887 5881 5225 5895 5888 5226 5229 5242 5244 5890 5242 5229 5891 5890 5229 5905 5232 5230 5230 5902 5905 5903 5902 5230 5230 5231 5903 5231 5245 5247 5916 5903 5231 5231 5247 5916 5905 5904 5232 6543 5895 5233 6550 6543 5233 5233 5234 6550 5234 6545 6550 6546 6545 5234 5234 5906 6546 5907 5906 5235 5908 5907 5235 5235 5237 5908 5235 5236 5237 5237 5239 5908 5237 5238 5239 5909 5908 5239 5239 5240 5909 5240 5241 5909 5241 5246 5909 5896 5243 5242 5242 5890 5896 5250 5248 5243 5912 5250 5243 5243 5911 5912 5243 5896 5911 5920 5909 5246 5931 5920 5246 5247 5253 5916 5252 5251 5248 5248 5250 5252 6569 5252 5250 5250 5912 6569 5251 5252 6569 7344 6589 5251 5251 7338 7344 5251 7327 7338 5251 6570 7327 5251 6569 6570 5919 5916 5253 5253 5262 5919 5935 5262 5254 6588 5257 5256 5256 5929 6588 6588 5943 5257 5258 5942 5945 5945 5944 5258 7337 5930 5259 5260 5261 7340 5261 5940 7340 5935 5919 5262 5263 5269 5279 5263 5265 5269 6609 5941 5263 5263 5279 6609 5266 5267 5946 6622 5946 5267 5267 5956 6622 5957 5277 5268 5268 5271 5957 6630 5272 5270 7348 6630 5270 5270 5952 7348 5270 5271 5952 5272 5271 5270 5271 5272 5957 6628 5957 5272 6630 6628 5272 5960 5274 5273 5273 5959 5960 5964 5963 5274 6638 5964 5274 6651 6638 5274 5274 5960 6651 5286 5285 5275 5275 5276 5286 5962 5286 5276 5276 5957 5962 5276 5277 5957 5278 5287 6646 6648 5279 5278 5278 6647 6648 5278 6646 6647 7359 6609 5279 7375 7359 5279 5279 6648 7375 5280 5281 5982 5281 5289 5982 5290 5289 5281 5282 5283 6661 5284 5283 5282 5964 5284 5282 5282 5963 5964 5283 6660 6661 7393 6660 5283 5283 6638 7393 5283 5284 6638 5284 5964 6638 5293 5292 5285 5285 5286 5293 5968 5293 5286 5969 5968 5286 5286 5965 5969 5286 5962 5965 6677 6646 5287 5287 5981 6677 5287 5288 5981 6677 5981 5288 5288 5989 6677 6659 5982 5289 5289 5983 6659 5289 5290 5983 5291 5976 5984 6657 6652 5292 6675 6657 5292 5292 6674 6675 5292 5293 6674 5293 5978 6674 5293 5968 5978 5294 5295 5971 5982 5971 5295 6665 5307 5296 5297 5303 5983 5298 5310 7412 5298 5309 5310 5307 5306 5300 5973 5302 5301 5996 5973 5301 5301 5995 5996 5983 5303 5302 5302 5974 5983 5302 5973 5974 6634 5967 5304 5304 6633 6634 6693 5987 5306 6694 6693 5306 5306 5993 6694 5306 5307 5993 6666 5993 5307 5307 6665 6666 5308 5998 6000 5308 5314 5998 6001 5310 5309 5309 5315 6001 5310 6697 7403 5310 6001 6697 5310 7403 7412 5311 5312 5320 5313 5312 5311 6706 5320 5312 5312 6002 6706 5312 5313 6002 6003 6002 5313 5313 5997 6003 5314 5326 5998 5316 5323 5326 6004 5324 5317 5317 5318 6004 6700 6004 5318 5318 5958 6700 6024 6023 5319 5319 5320 6024 5321 5320 5319 6023 5321 5319 5320 6002 6024 6706 6002 5320 6033 5335 5321 5321 6023 6033 5325 5323 5322 5327 5326 5323 6006 5327 5323 5323 5325 6006 5333 5328 5324 5324 5332 5333 6004 5332 5324 6010 6006 5325 6707 5998 5326 6718 6707 5326 5326 6716 6718 5326 6714 6716 5326 5327 6714 5327 6713 6714 5327 6006 6713 5328 5333 6014 6008 6005 5329 6009 6008 5329 6017 6009 5329 5329 5330 6017 6013 6010 5331 5331 5336 6013 6007 5333 5332 6701 6007 5332 5332 6004 6701 6016 6014 5333 5333 6007 6016 6735 6053 5334 5334 6028 6735 5334 5338 6028 6033 5339 5335 5336 5340 6013 5337 6053 6731 6731 5352 5337 6729 6028 5338 5338 6724 6729 6033 5348 5339 6034 6013 5340 5353 5346 5343 5354 5353 5343 5343 5344 5354 5345 5344 5343 5346 5345 5343 6019 5354 5344 6031 6019 5344 6032 6031 5344 5344 6020 6032 6021 6020 5344 5344 5345 6021 6022 6021 5345 5345 5347 6022 5345 5346 5347 5346 5356 5357 5346 5353 5356 6023 6022 5347 5349 5350 6048 5350 6037 6048 6730 6044 5351 5351 5352 6730 6731 6730 5352 5353 5354 5355 6047 5355 5354 5354 6045 6047 5354 6019 6045 6047 5360 5355 6056 5357 5356 6056 5358 5357 6047 5371 5360 6066 5363 5361 5361 5362 6066 5362 5373 6066 5362 5372 5373 6066 5375 5363 5364 5365 7507 5364 5376 6060 5377 5376 5364 7507 5377 5364 5365 6081 7507 6085 6081 5365 5365 5382 6085 6782 6052 5366 5366 5376 6782 6060 5376 5366 6087 5384 5367 5367 5368 6087 5369 5368 5367 6067 5369 5367 7520 6087 5368 7521 7520 5368 5368 7509 7521 5368 6790 7509 5368 6082 6790 5368 5369 6082 6065 5379 5370 5370 5371 6065 5371 6064 6065 5371 6047 6064 5380 5374 5372 5374 5373 5372 6078 6066 5373 5373 5374 6078 5374 5380 6078 6085 5381 5375 5375 6081 6085 5375 6066 6081 7501 6782 5376 5376 5377 7501 5377 6789 7501 8332 6789 5377 5377 8331 8332 5377 7507 8331 5378 5379 5387 6083 5387 5379 5379 6065 6083 6794 6078 5380 5380 6084 6794 5380 5381 6084 6085 6084 5381 6086 6085 5382 5382 5383 6086 6800 6086 5383 5383 6799 6800 6805 6799 5383 5383 6099 6805 5384 6087 6100 6806 6802 5385 5387 6083 6088 5388 5389 6112 6807 6112 5389 5389 6803 6807 5392 5391 5390 6117 5392 5390 6120 6117 5390 5390 5402 6120 5391 5392 6106 6808 6106 5392 6812 6808 5392 6813 6812 5392 7552 6813 5392 5392 6117 7552 5393 5408 6107 5393 5400 5408 5393 5394 5400 5395 5394 5393 6107 5395 5393 5413 5401 5394 6116 5413 5394 5394 6097 6116 5394 5395 6097 5401 5400 5394 6103 6097 5395 6107 6103 5395 6115 5397 5396 5396 6111 6115 6118 5405 5397 5397 6115 6118 5398 5406 5407 5399 5415 6810 5400 5401 5408 5412 5408 5401 5413 5412 5401 6121 6120 5402 7557 6121 5402 5402 6823 7557 5402 6122 6823 5402 5419 6122 5402 5403 5419 5404 5403 5402 6125 5419 5403 5403 5426 6125 5403 5404 5426 5427 5426 5404 6123 5407 5406 6816 6123 5406 5406 5414 6816 7545 6806 5407 7549 7545 5407 5407 6123 7549 6113 6107 5408 5409 5410 6113 5411 5410 5409 5410 5417 6113 7539 5417 5410 5410 6820 7539 5410 5411 6820 6821 6820 5411 5411 6819 6821 6815 5424 5412 5412 5413 6815 5413 6119 6815 5413 6116 6119 7572 6816 5414 5414 6835 7572 5414 6834 6835 5414 5429 6834 5415 6809 6810 5415 6112 6809 5416 6776 6797 7502 6776 5416 7535 7502 5416 5416 5417 7535 5418 5417 5416 6797 5418 5416 7539 7535 5417 5417 6107 6113 5417 6103 6107 5417 5418 6103 5418 6090 6103 6091 6090 5418 6797 6091 5418 6126 6122 5419 5419 6125 6126 5438 5433 5421 5421 5434 5438 5436 5434 5421 5421 5428 5436 5433 5425 5421 6830 5428 5422 5422 6118 6830 6124 5441 5423 5423 5424 6124 6825 6124 5424 5424 6815 6825 5430 5426 5425 5431 5430 5425 5433 5431 5425 5426 5430 6125 5437 5436 5428 6830 5437 5428 5429 6136 6834 5429 5442 6136 5430 5431 6125 6140 6135 5431 5431 5432 6140 5433 5432 5431 6135 6125 5431 5432 5450 6140 5432 5443 5450 5432 5438 5443 5432 5433 5438 5443 5438 5434 5446 5443 5434 5447 5446 5434 5434 5444 5447 5434 5435 5444 5436 5435 5434 5445 5444 5435 6130 5445 5435 5435 5436 6130 5436 5437 6130 6131 6130 5437 6830 6131 5437 5440 5448 5449 6133 5448 5440 5440 5441 6133 6134 6133 5441 5441 6124 6134 5451 5450 5443 5443 5446 5451 5444 5445 6147 5461 5447 5444 5462 5461 5444 6147 5462 5444 5445 6130 6147 5446 5447 5454 5453 5451 5446 5463 5453 5446 5446 5456 5463 5446 5455 5456 5446 5454 5455 5461 5454 5447 6840 5449 5448 7586 6840 5448 5448 7575 7586 5448 6133 7575 6844 6150 5449 5449 6840 6844 6141 6140 5450 5450 5452 6141 5450 5451 5452 5453 5452 5451 6144 6143 5452 5452 5453 6144 6143 6141 5452 6152 6144 5453 5453 5463 6152 5454 5461 5462 5462 5455 5454 5455 5466 5469 5467 5466 5455 5455 5462 5467 5469 5456 5455 5464 5463 5456 5465 5464 5456 5469 5465 5456 6837 6136 5457 6842 6837 5457 5457 5471 6842 5457 5458 5471 6150 5468 5460 6145 5467 5462 6147 6145 5462 6153 6152 5463 6154 6153 5463 5463 5464 6154 6163 6154 5464 5464 6155 6163 5464 5465 6155 5465 5466 6155 5469 5466 5465 6160 6155 5466 6161 6160 5466 6847 6161 5466 5466 5467 6847 5467 6145 6847 6157 5473 5468 6158 6157 5468 6849 6158 5468 5468 6150 6849 5470 6156 6856 6855 5471 5470 5470 6854 6855 6856 6854 5470 6855 6842 5471 5472 5473 6157 6165 6156 5474 7614 6165 5475 8414 7614 5475 5475 6881 8414 5475 6873 6881 5475 5476 6873 5476 6872 6873 5476 6181 6872 5476 5477 6181 5477 5488 6181 5477 5478 5488 5478 5484 5488 5479 6867 6879 5479 6176 6867 6186 5488 5484 6187 6186 5484 6194 6181 5488 5488 6193 6194 5488 6186 6193 5520 5523 5526 5525 5523 5520 6208 5525 5520 5520 6207 6208 6220 6207 5520 5520 5521 6220 5522 5521 5520 5526 5522 5520 5521 5528 6220 5521 5522 5528 5523 5524 5526 5525 5524 5523 5527 5526 5524 6210 5527 5524 5524 6206 6210 5524 5525 6206 6912 6206 5525 5525 6208 6912 6215 5529 5527 5527 6210 6215 6215 5531 5529 5530 5533 5535 5530 5531 5533 5531 5532 5533 6216 5532 5531 5531 6215 6216 5534 5533 5532 7695 5534 5532 5532 6216 7695 5533 6221 6222 5533 6219 6221 5533 5534 6219 7698 6219 5534 5534 7695 7698 6223 6220 5536 5536 5537 6223 5537 5538 6223 6224 6223 5538 5538 5539 6224 6227 6224 5539 6235 5543 5540 5540 6232 6235 5540 6229 6232 5540 6225 6229 5541 5542 5553 6236 6231 5541 6944 6236 5541 5541 5553 6944 5542 5546 5553 6235 6233 5543 5545 5544 5543 6233 5545 5543 5546 5552 5553 5549 5548 5547 5555 5549 5547 6963 5555 5547 5548 5549 5556 5551 5550 5549 6237 5551 5549 5549 5555 6237 6246 6245 5550 5550 6240 6246 6243 6240 5550 5550 5551 6243 5551 6237 6243 5554 5553 5552 6244 5554 5552 5552 5557 6244 5553 5554 6944 7722 6944 5554 7723 7722 5554 5554 6965 7723 5554 6244 6965 6238 6237 5555 7726 6238 5555 5555 6963 7726 6252 6251 5558 5558 5559 6252 6960 6252 5559 5559 6959 6960 5559 6958 6959 5559 6242 6958 7730 6963 5560 7733 7730 5560 7734 7733 5560 7744 7734 5560 5560 5572 7744 6983 6973 5562 6984 6983 5562 5562 6254 6984 5563 5584 6254 5563 5583 5584 5564 6255 6256 5565 5578 5579 5565 5568 5578 5565 5566 5568 5567 5566 5565 5579 5567 5565 6262 5568 5566 5566 6257 6262 6260 6257 5566 5566 5567 6260 5567 5579 6260 5568 5569 5578 5571 5569 5568 5593 5571 5568 6987 5593 5568 5568 6263 6987 5568 6262 6263 5580 5578 5569 5569 5570 5580 5571 5570 5569 5570 5571 5580 5593 5580 5571 7773 7744 5572 5572 5573 7773 5573 6278 7773 6280 6278 5573 5576 5575 5574 6988 5576 5574 5574 6253 6988 7790 7032 5575 5575 7789 7790 8595 7789 5575 8611 8595 5575 5575 7753 8611 7806 7753 5575 5575 7005 7806 5575 5576 7005 7031 5597 5575 7032 7031 5575 5576 6988 7005 5577 5578 5580 5579 5578 5577 5586 5579 5577 5598 5586 5577 5577 5581 5598 5577 5580 5581 6261 6260 5579 5579 5586 6261 5582 5581 5580 5591 5582 5580 5580 5590 5591 5600 5590 5580 5580 5592 5600 5593 5592 5580 5603 5598 5581 5611 5603 5581 5581 5582 5611 5624 5611 5582 5582 5591 5624 6267 5584 5583 6267 6254 5584 7019 6289 5585 5585 6271 7019 6990 6271 5585 7006 6990 5585 5586 5598 5603 6272 6261 5586 5586 5587 6272 5603 5587 5586 5589 5588 5587 6310 5589 5587 5587 5601 6310 5602 5601 5587 5611 5602 5587 5587 5603 5611 5587 5588 6272 5588 5589 6319 6289 6272 5588 5589 6310 6319 5599 5594 5590 5600 5599 5590 5594 5591 5590 5591 5604 5624 5605 5604 5591 5591 5594 5605 6290 5606 5592 6291 6290 5592 5592 5595 6291 5592 5593 5595 5592 5599 5600 5606 5599 5592 6266 5595 5593 6987 6266 5593 5594 5599 5605 5595 6265 6291 6266 6265 5595 6304 6280 5596 5606 5605 5599 5630 5628 5601 5601 5602 5630 5602 5611 5629 5602 5629 5630 5604 5615 5624 5604 5612 5615 5604 5605 5612 5614 5612 5605 5605 5606 5614 6312 5614 5606 6313 6312 5606 7034 6313 5606 5606 6290 7034 8634 7824 5607 5607 8625 8634 5607 7858 8625 5607 5608 7858 5609 5608 5607 7824 5609 5607 5608 5609 7045 7859 7858 5608 5608 7790 7859 5608 7032 7790 7045 7032 5608 5609 6322 7046 7857 6322 5609 7868 7857 5609 5609 7824 7868 7046 7045 5609 7057 6318 5610 7058 7057 5610 5610 5626 7058 5610 5617 5626 5611 5615 5629 5624 5615 5611 5625 5622 5612 5612 5613 5625 5614 5613 5612 5620 5615 5612 5622 5620 5612 6311 5625 5613 6321 6311 5613 5613 6320 6321 5613 6312 6320 5613 5614 6312 5615 5620 5629 6309 6305 5616 6347 6309 5616 7880 6347 5616 5616 7090 7880 5616 6367 7090 5618 5619 6325 7067 5626 5618 7069 7067 5618 5618 6325 7069 5620 5621 5629 5622 5621 5620 5632 5631 5621 5633 5632 5621 5621 5623 5633 5621 5622 5623 5631 5629 5621 5625 5623 5622 5623 5625 5633 6342 5633 5625 5625 6326 6342 5625 6311 6326 7067 7058 5626 5627 5631 6339 5627 5628 5631 5628 5629 5631 5630 5629 5628 6340 6339 5631 5631 5632 6340 6350 6340 5632 7086 6350 5632 5632 6338 7086 5632 5633 6338 6341 6338 5633 6342 6341 5633 5646 5635 5634 5634 5645 5646 5635 5646 6344 5635 6344 6345 5636 6336 6346 5636 6335 6336 5643 5642 5637 7869 5643 5637 5637 7868 7869 5637 7857 7868 5637 6322 7857 5637 5638 6322 6353 5640 5639 5650 5647 5640 6353 5650 5640 6368 6367 5641 6369 6368 5641 5641 5652 6369 5641 5651 5652 5659 5651 5641 5641 5658 5659 5642 5653 5654 5642 5643 5653 5642 5654 5660 7881 5653 5643 5643 7869 7881 6364 6352 5644 5644 5656 6364 5646 5645 5644 6344 5646 5644 6352 6344 5644 5650 5648 5647 5675 5668 5648 5648 5649 5675 5650 5649 5648 6356 5675 5649 7091 6356 5649 5649 5650 7091 5650 6355 7091 5650 6353 6355 6375 6374 5651 5651 5659 6375 6374 5652 5651 7867 6369 5652 7879 7867 5652 5652 6374 7879 6348 5655 5653 7881 6348 5653 5655 5654 5653 5679 5660 5654 5654 5655 5679 5655 6348 7106 6388 5679 5655 7106 6388 5655 5656 5657 6364 6376 6364 5657 5657 5667 6376 5678 5659 5658 6381 6375 5659 5659 5678 6381 6382 6324 5661 5662 7871 8649 5662 7088 7871 5662 6360 7088 5662 5663 6360 5664 5663 5662 8649 5664 5662 5685 5665 5663 5663 5664 5685 5664 5684 5685 9467 5684 5664 5664 8649 9467 6376 5667 5666 5668 6384 6385 5668 5675 6384 6377 5694 5668 6385 6377 5668 5669 5672 5673 5676 5672 5669 5669 5674 5676 5675 5674 5669 5669 5670 5675 5671 5670 5669 5673 5671 5669 6384 5675 5670 5670 5688 6384 5670 5671 5688 5671 5673 5688 5672 5677 5689 5672 5676 5677 5689 5673 5672 5689 5688 5673 6366 5676 5674 5674 6358 6366 5674 6356 6358 5674 5675 6356 6379 5677 5676 5676 6365 6379 6366 6365 5676 6387 5689 5677 5677 6378 6387 6379 6378 5677 7101 6381 5678 5678 5690 7101 5691 5690 5678 7121 5691 5678 5678 5681 7121 5681 7120 7121 7122 7120 5681 7919 7122 5681 5681 7151 7919 5681 5696 7151 6394 5697 5682 5682 6389 6394 11457 10425 5683 5683 11445 11457 5683 10402 11445 5683 5684 10402 5685 5684 5683 10425 5685 5683 5684 10390 10402 5684 9467 10390 8680 7925 5685 9487 8680 5685 10425 9487 5685 5686 6390 6391 5686 5693 6390 5686 5692 5693 5686 5687 5692 5688 5689 6387 6392 6384 5688 5688 6387 6392 7889 7101 5690 7908 7889 5690 5690 7907 7908 5690 5691 7907 7121 7120 5691 7918 7907 5691 5691 7120 7918 5698 5693 5692 7116 6390 5693 5693 5698 7116 6377 5695 5694 7117 6402 5695 7118 7117 5695 5695 6393 7118 5695 6386 6393 5695 6377 6386 7152 7151 5696 7945 7152 5696 7953 7945 5696 5696 7169 7953 5696 5711 7169 5697 6394 6398 5699 6425 6426 7956 6425 5699 5699 7165 7956 7166 7165 5699 5699 5700 7166 7925 7166 5700 5701 5724 5732 6400 5703 5702 6407 5715 5703 5703 6400 6407 5704 5705 6401 5704 6401 6408 6402 6401 5705 5710 5709 5706 6412 5710 5706 5706 5708 6412 6411 5708 5707 7150 6412 5708 5708 6428 7150 5708 6411 6428 5709 5710 6403 6412 6403 5710 5711 6421 7169 7133 6422 5712 5712 7128 7133 5712 6398 7128 6399 6395 5713 6404 6399 5713 5713 5721 6404 5726 5725 5714 5714 5715 5726 6407 5726 5715 5718 5717 5716 6417 5718 5716 6418 6417 5716 5716 6414 6418 6416 6414 5716 6419 5719 5717 5717 5718 6419 6420 6419 5718 5718 6417 6420 7161 5727 5719 7952 7161 5719 5719 6420 7952 5719 6419 6420 6434 5729 5720 5720 6422 6434 6435 6404 5721 5721 5730 6435 6436 5731 5722 5722 6423 6436 5722 6405 6423 6406 5724 5723 5733 5732 5724 6406 5733 5724 5735 5734 5725 5736 5735 5725 5725 5726 5736 6407 5736 5726 6433 5728 5727 7161 6433 5727 7162 5751 5728 7168 7162 5728 5728 6432 7168 6433 6432 5728 5755 5744 5729 6442 5755 5729 5729 6434 6442 5730 6443 7164 7153 6435 5730 7955 7153 5730 5730 7164 7955 6436 5739 5731 7131 7126 5732 7135 7131 5732 5732 5733 7135 5733 6406 6437 7136 7135 5733 7957 7136 5733 5733 6437 7957 5734 5735 6440 6439 6438 5734 6440 6439 5734 5735 5736 6427 5735 6427 6440 5736 6407 6427 5737 5738 6429 6441 6429 5738 6444 6441 5738 5738 5748 6444 5738 5747 5748 5741 5740 5739 6423 5741 5739 6436 6423 5739 5759 5758 5740 5770 5759 5740 5756 5745 5740 5757 5756 5740 5758 5757 5740 5742 6438 6454 6454 5760 5742 5743 5752 5761 5754 5752 5743 5743 5744 5754 5755 5754 5744 5756 5746 5745 6448 6443 5746 6450 6448 5746 5746 5756 6450 5749 5748 5747 5748 5750 6444 5748 5749 5750 5769 5750 5749 6468 6444 5750 5750 6460 6468 5750 5769 6460 7985 6472 5751 8758 7985 5751 5751 8751 8758 5751 7982 8751 5751 7174 7982 5751 7162 7174 5752 6449 7179 5752 5753 6449 5754 5753 5752 7179 5761 5752 5753 5754 5755 6455 6449 5753 5753 5755 6455 7182 6459 5755 5755 6446 7182 5755 6442 6446 6457 6455 5755 6459 6457 5755 5756 5757 6450 7170 6450 5757 7183 7170 5757 5757 5758 7183 6464 6462 5758 5758 5759 6464 8759 7183 5758 5758 6462 8759 5759 5771 6464 5759 5770 5771 5767 5765 5760 6454 5767 5760 7180 6421 5761 5761 7179 7180 5764 5763 5762 5766 5764 5762 5762 5763 5773 5763 5764 6451 5775 5773 5763 6467 5775 5763 5763 6451 6467 6453 6451 5764 5764 5767 6453 5764 5766 5767 5767 5766 5765 7175 6453 5767 7178 7175 5767 5767 6454 7178 5769 5776 6460 6465 6464 5771 5771 5772 6465 6473 6465 5772 5772 5778 6473 5773 5774 5779 5775 5774 5773 6466 5779 5774 5774 5775 6466 6467 6466 5775 5776 5793 6460 5776 5791 5793 5794 5785 5777 6479 6473 5778 5778 6474 6479 5778 5788 6474 6482 5790 5779 6483 6482 5779 5779 6466 6483 5781 5782 5793 5783 5782 5781 5792 5783 5781 5793 5784 5781 6469 5793 5782 7190 6469 5782 7203 7190 5782 8009 7203 5782 5782 6484 8009 5782 5783 6484 7206 6484 5783 5783 5800 7206 5783 5792 5800 5793 5791 5784 5785 6472 6485 5785 5794 6472 6474 5788 5786 5786 5787 6474 6480 6474 5787 5787 5789 6480 5789 6475 6480 6481 6475 5789 6482 5796 5790 6469 6460 5793 7194 6481 5795 5795 7193 7194 5795 6483 7193 5795 6482 6483 5795 5796 6482 5797 5806 5807 7211 6491 5798 5798 6490 7211 5798 6489 6490 5798 5799 6489 5800 5799 5798 6491 5800 5798 7207 7206 5800 5800 6491 7207 6487 5805 5801 5801 5802 6487 7209 6487 5802 5802 6485 7209 5804 5810 5827 6498 5810 5805 5805 6492 6498 5805 6487 6492 5808 5807 5806 6493 5808 5806 7210 6493 5806 7213 7210 5806 5806 5811 7213 6493 6488 5808 6498 5827 5810 7215 7213 5811 5811 6500 7215 5811 6499 6500 6501 6499 5811 5811 5820 6501 5821 5820 5811 8820 5823 5812 5812 6494 8820 5812 5813 6494 5814 5813 5812 5823 5814 5812 5813 6493 6494 5813 6488 6493 5814 5822 7225 5823 5822 5814 7225 5832 5814 5817 5818 6495 6502 6495 5818 5818 5819 6502 7216 6502 5819 8021 7216 5819 5819 5826 8021 7228 6501 5820 5820 5821 7228 5821 6525 7228 5821 5840 6525 8828 8027 5822 8829 8828 5822 5822 8820 8829 5822 5823 8820 8027 7225 5822 5826 6506 8021 7236 7227 5827 8036 7236 5827 5827 8020 8036 5827 6498 8020 5834 5833 5829 7227 5847 5830 6509 5838 5831 5831 5832 6509 7225 6509 5832 5834 5842 5854 6510 6508 5835 5835 5837 6510 5836 5852 5853 5836 5846 5852 5836 5839 5846 6511 5837 5836 6512 6511 5836 5836 5853 6512 6511 6510 5837 6514 5848 5838 5838 6509 6514 7237 6525 5840 5840 6517 7237 5840 5841 6517 6526 6517 5841 5841 6516 6526 5841 6513 6516 5841 5847 6513 6521 5846 5843 5843 5844 6521 5845 5844 5843 6528 6521 5844 5844 5856 6528 5844 5845 5856 5845 5849 5856 6522 5852 5846 5846 6521 6522 6515 6513 5847 7238 6515 5847 5847 7227 7238 5848 6514 6527 5849 5850 5856 5851 5850 5849 5857 5856 5850 5861 5857 5850 5850 5859 5861 5860 5859 5850 5850 5851 5860 5852 6522 6524 6524 5853 5852 7232 6512 5853 5853 6524 7232 5856 5857 6528 7247 6528 5857 7248 7247 5857 5857 5861 7248 5867 5861 5859 5859 5860 5867 5860 5864 5867 5861 5868 7248 5861 5867 5868 5866 5864 5863 6531 5866 5863 5863 6530 6531 5863 5880 6530 5864 5865 5867 5866 5865 5864 5865 5866 6531 5868 5867 5865 7257 5868 5865 5865 6531 7257 7258 7248 5868 5868 7257 7258 5869 5879 5880 5869 5870 5879 5871 5872 5883 5872 5875 5883 5872 5874 5875 5872 5873 5874 7256 5874 5873 5873 6529 7256 5876 5875 5874 7256 5876 5874 5875 5882 5883 6536 5882 5875 5875 6534 6536 5875 6533 6534 5875 5876 6533 8074 6533 5876 5876 7264 8074 5876 7256 7264 5881 5880 5879 5880 5881 6530 5881 5887 6530 6536 5885 5882 6538 5892 5885 5885 6536 6538 6537 6530 5887 7289 6539 5888 5888 6544 7289 5888 6543 6544 5888 5895 6543 5911 5896 5890 5890 5897 5911 5890 5891 5897 5898 5897 5891 6542 5894 5892 5892 6538 6542 5901 5899 5893 5893 5894 5901 5913 5901 5894 6542 5913 5894 5912 5911 5897 5897 5898 5912 6556 5912 5898 5901 5900 5899 7327 6556 5900 7339 7327 5900 7340 7339 5900 7341 7340 5900 5900 6571 7341 5900 5901 6571 5901 5913 6571 5937 5905 5902 5938 5937 5902 5902 5903 5938 5903 5936 5938 5903 5928 5936 5903 5917 5928 5918 5917 5903 5919 5918 5903 5903 5916 5919 6588 5929 5904 5904 5939 6588 5904 5937 5939 5904 5905 5937 5906 5907 6546 6552 6546 5907 6553 6552 5907 6554 6553 5907 5907 5908 6554 5908 5910 6554 5908 5909 5910 6555 5910 5909 5909 5921 6555 5909 5920 5921 6564 6554 5910 5910 6563 6564 7321 6563 5910 5910 6565 7321 5910 6555 6565 5912 6556 6569 5913 5914 8141 5915 5914 5913 6542 5915 5913 8141 6571 5913 8142 8141 5914 5914 7310 8142 9720 7310 5914 5914 8880 9720 5914 5915 8880 5915 8123 8880 5915 6542 8123 5941 5928 5917 5917 5918 5941 5918 5919 5935 5922 5921 5920 5931 5922 5920 7325 7322 5921 5921 6566 7325 5921 5922 6566 6565 6555 5921 7321 6565 5921 7322 7321 5921 6567 6566 5922 5922 5930 6567 5931 5930 5922 5923 5932 6572 5923 5927 5932 5923 5924 5927 5925 5924 5923 6572 5925 5923 5933 5927 5924 6557 5933 5924 6559 6557 5924 7293 6559 5924 5924 7292 7293 5924 6558 7292 5924 5926 6558 5924 5925 5926 6547 5926 5925 7328 6547 5925 5925 6572 7328 7302 6558 5926 5926 6548 7302 5926 6547 6548 5933 5932 5927 5941 5936 5928 6578 6567 5930 7343 6578 5930 5930 6615 7343 5930 6600 6615 6601 6600 5930 7337 6601 5930 6573 6572 5932 6582 6573 5932 5932 6574 6582 5932 5934 6574 5932 5933 5934 6557 5934 5933 6576 6574 5934 5934 6560 6576 5934 6557 6560 5936 5941 6609 6594 5938 5936 6609 6594 5936 6595 5939 5937 6596 6595 5937 5937 6593 6596 5937 5938 6593 6594 6593 5938 6595 6588 5939 5940 7339 7340 7344 7339 5940 5940 6589 7344 5942 5943 6598 6598 5945 5942 5943 6588 6597 5943 6597 6598 6614 6613 5944 7367 6614 5944 5944 5945 7367 5945 7366 7367 5945 6598 7366 5947 5948 5949 6619 5959 5947 5947 5949 6619 7385 6619 5949 5949 5950 7385 5950 7384 7385 5950 7382 7384 5950 5953 7382 6625 5953 5951 5951 5954 6625 7349 7348 5952 5952 7347 7349 5953 6626 7382 5953 6625 6626 5954 5955 6625 6627 6625 5955 6641 6627 5955 5955 6640 6641 5955 6639 6640 5956 5967 6622 6628 5962 5957 5958 6632 8240 6649 6632 5958 5958 6670 6700 5958 6669 6670 8240 6669 5958 5961 5960 5959 6619 5961 5959 6656 6651 5960 5960 6650 6656 5960 6623 6650 5960 5961 6623 6624 6623 5961 5961 6619 6624 5966 5965 5962 6654 5966 5962 6655 6654 5962 5962 6628 6655 5970 5969 5965 5965 5966 5970 6654 5970 5966 6649 6622 5967 5967 6634 6649 5968 5977 5978 5968 5969 5977 5969 5970 5977 5980 5977 5970 6654 5980 5970 5972 5973 6708 5974 5973 5972 6668 5974 5972 6695 6668 5972 7427 6695 5972 7431 7427 5972 5972 6708 7431 5973 5999 6707 5973 5996 5999 5973 6707 6708 6659 5983 5974 6672 5976 5975 5975 6662 6672 5975 6661 6662 5986 5984 5976 6672 5986 5976 5979 5978 5977 6676 5979 5977 5977 6663 6676 5977 5980 6663 6683 6674 5978 6684 6683 5978 5978 5979 6684 7415 6684 5979 5979 6688 7415 5979 6676 6688 6664 6663 5980 5980 6658 6664 5980 6654 6658 5986 5985 5984 6681 5997 5985 5985 5986 6681 5997 5990 5985 6687 6681 5986 5986 6686 6687 5986 6672 6686 6690 5988 5987 6693 6690 5987 5991 5989 5988 6689 5991 5988 6691 6689 5988 6692 6691 5988 5988 6690 6692 5989 5991 6677 6685 6677 5991 6689 6685 5991 7414 5994 5992 7419 7414 5992 5992 7410 7419 5992 6667 7410 5992 6666 6667 5992 5993 6666 5994 5993 5992 5993 5994 6694 5994 7414 7418 7417 6694 5994 7418 7417 5994 5999 5996 5995 6681 6003 5997 6707 6000 5998 5999 6000 6707 6702 6697 6001 6001 6005 6702 6682 6024 6002 6002 6003 6682 6003 6681 6682 6004 6700 6701 6709 6702 6005 6005 6008 6709 6006 6011 6713 6006 6010 6011 7451 6016 6007 6007 7428 7451 6007 6701 7428 6720 6709 6008 7440 6720 6008 6008 7439 7440 6008 7432 7439 6008 6009 7432 6009 6017 6731 6009 6736 7432 6009 6731 6736 6012 6011 6010 6025 6012 6010 6010 6013 6025 6721 6713 6011 6011 6012 6721 6012 6026 6721 6027 6026 6012 6012 6025 6027 6034 6025 6013 6728 6039 6014 6014 6015 6728 6016 6015 6014 6015 6727 6728 8307 6727 6015 6015 7451 8307 6015 6016 7451 6017 6029 6731 6730 6029 6018 6018 6042 6730 6046 6045 6019 6019 6030 6046 6031 6030 6019 6682 6032 6020 6020 6024 6682 6020 6022 6024 6020 6021 6022 6022 6023 6024 6035 6027 6025 6025 6034 6035 7446 6721 6026 6026 6732 7446 6733 6732 6026 7465 6733 6026 6026 6734 7465 6026 6027 6734 6027 6035 6734 6028 6729 7455 7439 6735 6028 7455 7439 6028 6029 6730 6731 6710 6046 6030 6030 6703 6710 6705 6703 6030 6030 6031 6705 6031 6032 6682 6031 6682 6705 6036 6035 6034 6757 6036 6034 6034 6057 6757 6746 6734 6035 6035 6036 6746 6769 6746 6036 6036 6757 6769 6049 6048 6037 6050 6049 6037 6051 6050 6038 6747 6051 6038 6038 6039 6747 6039 6728 6747 6040 6041 6723 6749 6723 6041 6041 6748 6749 6761 6748 6041 6041 6052 6761 6042 6043 6730 6043 6044 6730 6061 6047 6045 6045 6054 6061 6045 6046 6054 6055 6054 6046 6710 6055 6046 6047 6062 6064 6047 6061 6062 6048 6049 6059 6063 6059 6049 6049 6050 6063 6050 6051 6063 6759 6063 6051 6774 6759 6051 6051 6760 6774 6051 6747 6760 6762 6761 6052 6783 6762 6052 6052 6782 6783 6053 6735 7458 7458 6731 6053 6068 6061 6054 6765 6068 6054 6054 6737 6765 6054 6055 6737 6738 6737 6055 6055 6710 6738 6771 6757 6057 6057 6058 6771 6058 6770 6771 6772 6770 6058 6773 6772 6058 7489 6773 6058 6058 6059 7489 6059 6063 7489 6068 6062 6061 6069 6064 6062 6062 6068 6069 6063 6758 6787 6759 6758 6063 6063 6787 7489 6069 6065 6064 6784 6083 6065 6065 6069 6784 6066 6079 6081 6066 6078 6079 6765 6069 6068 6792 6784 6069 6796 6792 6069 8344 6796 6069 6069 6763 8344 6765 6763 6069 6095 6093 6070 6070 6092 6095 6070 6071 6092 6072 6071 6070 6094 6072 6070 6070 6093 6094 6096 6092 6071 6071 6073 6096 6071 6072 6073 6074 6073 6072 6075 6074 6072 6094 6075 6072 6073 6074 6096 6074 6076 6096 6077 6076 6074 6785 6077 6074 6074 6075 6785 6075 6780 6785 6075 6756 6780 6075 6094 6756 7511 6096 6076 6076 7505 7511 6076 7504 7505 6076 6077 7504 6077 6785 7504 6080 6079 6078 6794 6080 6078 6079 6786 7500 6079 6080 6786 6787 6081 6079 7500 6787 6079 7499 6786 6080 6080 6794 7499 6081 6787 7507 6089 6088 6083 6791 6089 6083 6083 6784 6791 7519 6794 6084 7528 7519 6084 6084 6800 7528 6084 6086 6800 6084 6085 6086 6101 6100 6087 6801 6101 6087 7520 6801 6087 6088 6089 6803 7510 6807 6089 6089 6791 7510 6807 6803 6089 6104 6103 6090 6090 6095 6104 6090 6093 6095 6090 6091 6093 6094 6093 6091 6775 6094 6091 6797 6775 6091 6098 6095 6092 6804 6098 6092 6092 6096 6804 6778 6756 6094 6094 6752 6778 6775 6752 6094 6095 6098 6104 7523 6804 6096 6096 7511 7523 6097 6108 6116 6097 6105 6108 6097 6104 6105 6097 6103 6104 6105 6104 6098 6804 6105 6098 6808 6805 6099 6099 6106 6808 6811 6102 6100 6100 6101 6811 7531 6811 6101 6101 7530 7531 6101 6801 7530 6811 6111 6102 6114 6108 6105 6804 6114 6105 7561 7551 6108 8379 7561 6108 6108 8378 8379 6108 6109 8378 6110 6109 6108 6114 6110 6108 7551 6116 6108 9097 8378 6109 6109 9082 9097 6109 7537 9082 6109 6110 7537 6110 7522 7537 6110 6114 7522 6811 6115 6111 7534 6809 6112 6112 6807 7534 6114 6804 7522 6814 6118 6115 6115 6811 6814 7551 6119 6116 6117 6120 7552 6118 6814 6830 6822 6815 6119 7551 6822 6119 7557 7552 6120 6120 6121 7557 6122 6126 6823 7555 7549 6123 8382 7555 6123 6123 6816 8382 6824 6134 6124 6825 6824 6124 6129 6126 6125 6135 6129 6125 6829 6823 6126 6126 6129 6829 7569 6132 6127 7558 6819 6128 7565 7558 6128 6836 6829 6129 6129 6135 6836 6130 6131 6147 7578 6147 6131 6131 6831 7578 6131 6830 6831 6833 6138 6132 6132 6139 6833 7577 7575 6133 6133 6134 7577 6134 6828 7577 6134 6824 6828 6839 6836 6135 6135 6140 6839 6837 6834 6136 6833 6139 6137 6137 6138 6833 6140 6141 6839 6841 6839 6141 6141 6142 6841 6143 6142 6141 6142 6845 7591 6142 6148 6845 6142 6143 6148 7591 6841 6142 6143 6144 6148 6151 6148 6144 6152 6151 6144 6848 6847 6145 6145 6146 6848 6147 6146 6145 8404 6848 6146 6146 8402 8404 8403 8402 6146 6146 7583 8403 6146 6149 7583 6146 6147 6149 7578 6149 6147 6846 6845 6148 6850 6846 6148 6148 6151 6850 6149 7582 7583 6149 7578 7582 6150 6844 6849 6851 6850 6151 6151 6159 6851 6151 6152 6159 6152 6153 6159 6162 6159 6153 6153 6154 6162 6168 6162 6154 6170 6168 6154 6172 6170 6154 6154 6163 6172 6155 6160 6163 6156 6165 6856 6860 6167 6157 6861 6860 6157 6157 6158 6861 7620 6861 6158 8411 7620 6158 6158 7621 8411 6158 7608 7621 6158 7600 7608 6158 6849 7600 6852 6851 6159 6159 6162 6852 6164 6163 6160 7602 6164 6160 6160 6161 7602 7613 7602 6161 8412 7613 6161 9135 8412 6161 6161 6847 9135 6853 6852 6162 6859 6853 6162 6162 6168 6859 6163 6164 6172 6175 6172 6164 7624 6175 6164 6164 7602 7624 7614 6856 6165 6166 6167 6860 6860 6169 6166 6866 6859 6168 6168 6171 6866 6168 6170 6171 6865 6176 6169 6169 6860 6865 6170 6180 6183 6170 6174 6180 6170 6173 6174 6170 6172 6173 6183 6171 6170 6171 6862 6866 6868 6862 6171 6171 6183 6868 6175 6173 6172 6179 6174 6173 6173 6175 6179 6174 6178 6180 6179 6178 6174 6871 6179 6175 7633 6871 6175 6175 7624 7633 6885 6867 6176 7634 6885 6176 6176 7629 7634 6176 7628 7629 6176 6865 7628 6184 6180 6178 6878 6184 6178 6178 6869 6878 6178 6179 6869 6871 6869 6179 6184 6183 6180 6181 6194 6872 6183 6184 6868 6889 6868 6184 6184 6875 6889 6877 6875 6184 6878 6877 6184 6186 6187 6193 6187 6190 6193 6187 6189 6190 6187 6188 6189 6191 6188 6187 6188 6191 6879 6879 6189 6188 7652 6190 6189 6189 6879 7652 9208 6193 6190 6190 8456 9208 6190 7652 8456 6894 6194 6193 6895 6894 6193 8453 6895 6193 9208 8453 6193 6891 6872 6194 7650 6891 6194 7651 7650 6194 6194 6894 7651 7687 6210 6206 6206 6913 7687 6206 6912 6913 6220 6213 6207 6209 6208 6207 6922 6209 6207 6207 6213 6922 6208 6209 6912 6921 6912 6209 6922 6921 6209 6218 6214 6210 7687 6218 6210 6210 6214 6215 9289 7692 6211 9290 9289 6211 6211 8492 9290 6211 6212 8492 6213 6212 6211 7692 6213 6211 6212 7700 8492 6212 6923 7700 6212 6213 6923 6213 6220 6923 7692 6922 6213 6216 6215 6214 6218 6216 6214 6216 7694 7695 6216 6217 7694 6218 6217 6216 8477 7694 6217 6217 7691 8477 6217 7688 7691 6217 6218 7688 6218 7687 7688 7698 6221 6219 6924 6923 6220 6220 6223 6924 6933 6228 6221 7698 6933 6221 6228 6222 6221 6226 6225 6222 6228 6226 6222 6925 6924 6223 6223 6224 6925 6928 6925 6224 6224 6927 6928 6224 6227 6927 6225 6226 6229 6929 6229 6226 6930 6929 6226 6226 6926 6930 6226 6228 6926 6932 6927 6227 6227 6230 6932 6933 6926 6228 6934 6232 6229 6229 6929 6934 7713 6932 6230 6230 7712 7713 6230 6236 7712 6230 6231 6236 6934 6235 6232 6235 6234 6233 6233 6234 6242 6945 6242 6234 6234 6235 6945 6235 6934 6945 7717 7712 6236 6236 6944 7717 6237 6238 6243 6238 6239 6243 6241 6239 6238 7718 6241 6238 7719 7718 6238 7729 7719 6238 6238 7726 7729 6239 6240 6243 6241 6240 6239 6943 6246 6240 6240 6939 6943 6240 6241 6939 6241 6938 6939 6241 6935 6938 7718 6935 6241 6242 6949 6958 6242 6945 6949 6244 6964 6965 6250 6248 6245 6245 6247 6250 6245 6246 6247 7731 6247 6246 6246 6943 7731 8531 6250 6247 6247 8526 8531 6247 7731 8526 6989 6978 6248 6248 6249 6989 6250 6249 6248 7739 6989 6249 6249 7738 7739 9363 7738 6249 6249 8543 9363 6249 6250 8543 6250 8531 8543 6986 6255 6251 7741 6986 6251 6251 7736 7741 6251 6252 7736 6252 6974 7736 6252 6960 6974 6253 6978 6988 7745 6984 6254 7754 7745 6254 6254 6267 7754 6985 6256 6255 6986 6985 6255 6256 6269 6270 6256 6268 6269 6985 6268 6256 6257 6260 6990 6264 6262 6257 6257 6258 6264 6259 6258 6257 6990 6259 6257 6979 6264 6258 6258 6977 6979 7748 6977 6258 6258 6259 7748 6259 7747 7748 7757 7747 6259 6259 6268 7757 6269 6268 6259 6990 6269 6259 6260 6261 6990 6272 6271 6261 6261 6271 6990 6264 6263 6262 7749 6987 6263 6263 7743 7749 6263 6981 7743 6263 6980 6981 6263 6264 6980 6264 6979 6980 7809 6291 6265 8612 7809 6265 6265 8596 8612 6265 7758 8596 6265 7008 7758 6265 6266 7008 6266 6987 7008 7799 7754 6267 7800 7799 6267 6268 6985 7757 7776 6270 6269 6269 7007 7776 6269 6990 7007 7776 7006 6270 6271 6272 7020 7020 7019 6271 7021 7020 6272 7033 7021 6272 6272 6289 7033 6273 7000 7001 6273 6283 7000 6273 6282 6283 6301 6282 6273 6273 6274 6301 6275 6274 6273 7001 6275 6273 6274 6284 6301 6286 6284 6274 6287 6286 6274 6274 6276 6287 6274 6275 6276 6277 6276 6275 7013 6277 6275 6275 7003 7013 6275 7001 7003 6288 6287 6276 6276 6277 6288 7018 6288 6277 7784 7018 6277 6277 7012 7784 7013 7012 6277 6280 6279 6278 6278 7772 7773 7774 7772 6278 6278 6279 7774 6279 6280 6304 7775 7774 6279 9399 7775 6279 6279 7805 9399 6279 6304 7805 6307 6296 6281 6308 6307 6281 6281 6302 6308 6281 6282 6302 6283 6282 6281 6296 6283 6281 6282 6301 6302 6283 6997 7000 7763 6997 6283 7783 7763 6283 6283 7023 7783 6283 6299 7023 6300 6299 6283 6283 6296 6300 6315 6301 6284 6284 6285 6315 6286 6285 6284 6285 6314 6315 6317 6314 6285 6285 6303 6317 6285 6286 6303 7018 6303 6286 6286 6288 7018 6286 6287 6288 6289 7019 7033 7816 7034 6290 6290 7808 7816 6290 6291 7808 7809 7808 6291 6292 6295 6306 6292 6293 6295 6294 6293 6292 6306 6294 6292 6297 6295 6293 6293 6294 6297 7010 6297 6294 6294 7009 7010 7015 7009 6294 7022 7015 6294 7037 7022 6294 6294 6306 7037 6307 6306 6295 6295 6296 6307 6298 6296 6295 6295 6297 6298 6296 6298 6300 7017 6298 6297 6297 7010 7017 6298 6299 6300 7780 6299 6298 6298 7017 7780 7780 7023 6299 6315 6302 6301 7059 6308 6302 6302 6315 7059 7038 6317 6303 6303 7018 7038 6304 7030 7805 6304 6305 7030 6305 6309 7030 7052 7037 6306 6306 6307 7052 6307 6308 7052 7059 7052 6308 7822 7030 6309 7823 7822 6309 6309 6347 7823 6327 6326 6311 6311 6321 6327 6312 6313 6320 7047 6320 6313 7810 7047 6313 6313 7034 7810 6316 6315 6314 6317 6316 6314 7829 7059 6315 6315 7060 7829 6315 6316 7060 7817 7060 6316 6316 6317 7817 6317 7053 7817 7054 7053 6317 7793 7054 6317 6317 7038 7793 7807 7791 6318 7825 7807 6318 6318 7057 7825 6327 6321 6320 7073 6327 6320 8627 7073 6320 6320 7810 8627 6320 7047 7810 6383 6371 6323 6323 6324 6383 6371 6370 6323 6324 6382 6383 7870 7069 6325 6325 6349 7870 7826 6342 6326 6326 7073 7826 6326 6327 7073 6332 6331 6328 6343 6332 6328 6328 6329 6343 6330 6329 6328 6352 6330 6328 6328 6344 6352 6328 6331 6344 7089 6343 6329 6329 6351 7089 6329 6330 6351 6352 6351 6330 6331 6332 6334 6345 6344 6331 6331 6333 6345 6334 6333 6331 6343 6334 6332 7843 6335 6333 6333 6334 7843 6334 6343 7077 6334 7841 7843 7842 7841 6334 6334 7077 7842 6337 6336 6335 7844 6337 6335 6335 7843 7844 6336 6337 6346 7847 6346 6337 8655 7847 6337 6337 8654 8655 6337 8638 8654 6337 7844 8638 7087 7086 6338 6338 6341 7087 6340 6350 6360 6341 6342 7087 7826 7087 6342 6343 6373 7077 6343 6372 6373 7089 6372 6343 7860 7080 6346 6346 7845 7860 7847 7845 6346 8607 7823 6347 9428 8607 6347 6347 7084 9428 7085 7084 6347 7880 7085 6347 7890 7106 6348 8675 7890 6348 6348 7881 8675 6349 6371 7870 7088 6360 6350 6350 7086 7088 6363 6361 6351 6364 6363 6351 6351 6352 6364 6351 6361 7089 7079 6355 6353 7080 7079 6353 6356 6355 6354 6358 6356 6354 6354 6357 6358 6359 6357 6354 6354 6355 6359 6355 6356 7091 7079 6359 6355 7092 6358 6357 6357 7082 7092 6357 7081 7082 6357 6359 7081 7092 6366 6358 7862 7081 6359 6359 7849 7862 7851 7849 6359 7861 7851 6359 6359 7079 7861 6361 6362 7096 6363 6362 6361 6361 6372 7089 6373 6372 6361 7096 6373 6361 7097 7096 6362 6362 6376 7097 6362 6363 6376 6363 6364 6376 7099 6379 6365 7102 7099 6365 6365 6366 7102 6366 7092 7102 6367 6368 7090 7880 7090 6368 8666 7880 6368 6368 7867 8666 6368 6369 7867 7882 7870 6371 7887 7882 6371 6371 7093 7887 6371 6383 7093 9441 7078 6373 6373 8660 9441 6373 7096 8660 7078 7077 6373 6374 6375 7101 7889 7879 6374 6374 7101 7889 6375 6381 7101 6376 6391 7097 6377 6385 6386 6378 6379 6380 7109 6387 6378 6378 6380 7109 7104 6380 6379 6379 7099 7104 7104 7103 6380 7110 7109 6380 6380 7103 7110 7112 6383 6382 7113 7112 6382 7903 7093 6383 6383 7112 7903 6386 6385 6384 6392 6386 6384 6386 6392 6393 7115 6392 6387 6387 7114 7115 6387 7109 7114 7111 6389 6388 7920 7111 6388 6388 7901 7920 6388 7106 7901 7123 6394 6389 6389 7111 7123 7097 6391 6390 7108 7097 6390 7116 7108 6390 7127 6393 6392 7149 7127 6392 6392 7115 7149 7127 7118 6393 7128 6398 6394 6394 7123 7128 6397 6396 6395 6399 6397 6395 6395 6396 7124 6396 6397 8694 6396 7113 7124 6396 7112 7113 7921 7112 6396 8694 7921 6396 6397 7937 8694 6397 7129 7937 7130 7129 6397 7153 7130 6397 6397 6399 7153 6399 6404 7153 7143 6407 6400 6409 6408 6401 6410 6409 6401 6401 6402 6410 7132 6410 6402 6402 7127 7132 6402 7117 7127 6403 6412 6413 6404 6435 7153 6426 6423 6405 7167 6437 6406 6406 6423 7167 7140 6427 6407 6407 7137 7140 7141 7137 6407 7948 7141 6407 6407 7143 7948 7154 7145 6408 6408 6409 7154 6409 6410 7146 7962 7154 6409 7963 7962 6409 7974 7963 6409 6409 7147 7974 6409 7146 7147 6410 7132 7146 7150 6413 6412 6413 6414 6416 6415 6414 6413 7150 6415 6413 7159 6418 6414 6414 6415 7159 6415 7150 7159 7965 6420 6417 6417 6418 7965 6418 7976 8737 7977 7976 6418 6418 7159 7977 8725 7965 6418 6418 8724 8725 8737 8724 6418 7966 7952 6420 6420 7965 7966 7180 7169 6421 7163 6434 6422 6422 7133 7163 6423 6424 7167 6425 6424 6423 6426 6425 6423 6424 6437 7167 7956 6437 6424 6424 6425 7956 7140 6440 6427 6428 6430 7158 6431 6430 6428 6428 6429 6431 7158 7150 6428 6441 6431 6429 7964 7158 6430 7977 7964 6430 6430 7172 7977 6430 7171 7172 6430 6431 7171 6431 6441 7171 7968 7168 6432 6432 6433 7968 6433 7161 7968 6447 6442 6434 7163 6447 6434 6437 7956 7957 7178 6454 6438 7960 7178 6438 6438 7958 7960 6438 7138 7958 6438 6439 7138 6439 7137 7138 7140 7137 6439 6439 6440 7140 6441 6445 7171 6441 6444 6445 6447 6446 6442 7170 7164 6443 6443 6448 7170 6468 6445 6444 6445 6471 7171 6445 6468 6471 6446 7181 7182 7983 7181 6446 6446 6447 7983 6447 7980 7983 6447 7973 7980 6447 7163 7973 6448 6450 7170 6449 6455 6456 6449 6456 7179 6453 6452 6451 6451 6452 6467 6452 7184 7992 6452 6453 7184 7189 6467 6452 7992 7189 6452 6453 7176 7184 6453 7175 7176 6457 6456 6455 7185 7179 6456 7187 7185 6456 6456 6457 7187 6457 6458 7187 6459 6458 6457 7991 7187 6458 6458 6459 7991 6459 7182 7991 6469 6468 6460 6463 6462 6461 7998 6463 6461 8000 7998 6461 8767 8000 6461 6461 8001 8767 6461 7188 8001 6461 6462 7188 6462 6465 6473 6462 6464 6465 9534 8759 6462 6462 6463 9534 6462 6473 7188 10521 9534 6463 6463 7998 10521 7198 6483 6466 6466 7189 7198 6466 6467 7189 6468 6470 6471 6468 6469 6470 7190 6470 6469 6470 7202 7990 6470 7190 7202 7990 6471 6470 7173 7171 6471 7990 7173 6471 6486 6485 6472 7985 6486 6472 6473 6479 7188 6480 6479 6474 6475 6476 6480 6477 6476 6475 6478 6477 6475 6481 6478 6475 7191 6480 6476 6476 6477 7191 6477 6478 7191 6478 6481 7191 7192 7188 6479 6479 6480 7192 6480 7191 7192 7201 7191 6481 6481 7194 7201 7198 7193 6483 8013 8009 6484 6484 7206 8013 7200 7199 6485 6485 6486 7200 6485 7199 7209 6486 7985 8008 8010 7200 6486 8791 8010 6486 6486 8008 8791 7208 6492 6487 7209 7208 6487 6497 6490 6489 6490 6505 7211 6490 6504 6505 6490 6497 6504 7211 7207 6491 7212 6498 6492 8015 7212 6492 6492 7208 8015 8016 6494 6493 6493 7210 8016 6494 8017 8820 6494 8016 8017 6503 6496 6495 6495 6502 6503 8822 7218 6496 8823 8822 6496 6496 8815 8823 6496 6503 8815 6498 7212 8020 8833 6500 6499 6499 8039 8833 6499 6501 8039 8827 7215 6500 8833 8827 6500 6501 7228 8039 7216 6503 6502 6503 8814 8815 8817 8814 6503 6503 8813 8817 6503 7216 8813 7217 6505 6504 7218 7217 6504 7221 7211 6505 6505 7217 7221 8821 8021 6506 10588 8821 6506 6506 8041 10588 6506 7229 8041 6506 6508 7229 6506 6507 6508 7230 7229 6508 6508 6510 7230 8029 6514 6509 6509 7226 8029 6509 7225 7226 6510 6511 7230 7233 7230 6511 6511 6512 7233 6512 7232 7233 6513 6515 6516 6514 8852 8853 6514 8837 8852 6514 8029 8837 8053 6527 6514 8055 8053 6514 8853 8055 6514 7234 6516 6515 7238 7234 6515 7244 6526 6516 7245 7244 6516 8063 7245 6516 6516 7234 8063 7240 7237 6517 6517 7239 7240 6517 6526 7239 7247 7242 6518 6518 6528 7247 6518 6521 6528 6523 6521 6518 8046 6523 6518 8854 8046 6518 6518 6519 8854 6520 6519 6518 7243 6520 6518 8056 7243 6518 6518 7241 8056 7242 7241 6518 9652 8854 6519 6519 9650 9652 6519 6520 9650 9651 9650 6520 6520 9648 9651 6520 8858 9648 6520 8068 8858 6520 7243 8068 6523 6522 6521 6522 6523 7232 7232 6524 6522 8041 7231 6523 8046 8041 6523 6523 7231 7232 8040 7228 6525 8044 8040 6525 8045 8044 6525 6525 7237 8045 6526 7244 7246 7246 7239 6526 8055 6529 6527 6527 8053 8055 8067 7256 6529 6529 8062 8067 6529 8055 8062 6532 6531 6530 6537 6532 6530 7265 7257 6531 7267 7265 6531 6531 6532 7267 6532 6537 8090 8090 7267 6532 6535 6534 6533 8074 6535 6533 8873 6541 6534 6534 6535 8873 6541 6536 6534 6535 8089 8873 6535 8074 8089 6541 6538 6536 6537 6539 8090 6538 6540 6542 6541 6540 6538 6539 7290 8090 6539 7289 7290 8123 6542 6540 8872 8123 6540 6540 6541 8872 8873 8872 6541 7305 6544 6543 6543 6550 7305 7291 7289 6544 8129 7291 6544 6544 7296 8129 7314 7296 6544 6544 7305 7314 6551 6550 6545 8137 6551 6545 6545 7306 8137 6545 6552 7306 6545 6546 6552 6549 6548 6547 7328 6549 6547 6548 6549 7302 6549 7301 7302 6549 7298 7301 7300 7298 6549 6549 6581 7300 7328 6581 6549 7316 7305 6550 7317 7316 6550 7318 7317 6550 6550 6551 7318 8137 7318 6551 7317 7306 6552 6552 7307 7317 6552 6553 7307 8167 7307 6553 8173 8167 6553 6553 7335 8173 6553 7319 7335 6553 6564 7319 6553 6554 6564 7327 6570 6556 6570 6569 6556 6557 6559 6560 8896 7292 6558 6558 8895 8896 6558 8894 8895 6558 7301 8894 7302 7301 6558 7293 6575 6559 6575 6560 6559 6560 6561 6576 6562 6561 6560 6575 6562 6560 6587 6576 6561 7312 6587 6561 6561 6562 7312 6562 7311 7312 6562 7304 7311 6562 6575 7304 7320 6564 6563 8156 7320 6563 6563 7323 8156 6563 7321 7323 7320 7319 6564 6566 6568 7325 6566 6567 6568 6578 6568 6567 7326 7325 6568 6568 6577 7326 6578 6577 6568 8141 7341 6571 7345 7328 6572 6572 6573 7345 6573 6583 7345 6573 6582 6583 6583 6582 6574 6604 6583 6574 6574 6584 6604 6574 6576 6584 6575 7303 7304 6575 7294 7303 6575 7293 7294 6587 6584 6576 8161 7326 6577 6577 6578 8161 6578 8158 8161 8168 8158 6578 6578 7343 8168 8930 8138 6579 9747 8930 6579 6579 6580 9747 6581 6580 6579 8138 6581 6579 6580 8946 9747 6580 7354 8946 8143 7354 6580 6580 6581 8143 6581 7328 8143 8138 7300 6581 7355 7345 6583 6583 7351 7355 6583 6616 7351 6583 6604 6616 6584 6585 6604 6586 6585 6584 6591 6586 6584 6584 6590 6591 6584 6587 6590 6605 6604 6585 6585 6592 6605 6585 6586 6592 6631 6592 6586 7346 6631 6586 6586 6591 7346 7312 6590 6587 6588 6595 6597 7342 6591 6590 6590 7329 7342 6590 7312 7329 6591 7342 7346 6606 6605 6592 6631 6606 6592 6618 6596 6593 7360 6618 6593 6593 7352 7360 6593 6610 7352 6593 6594 6610 6594 6609 6610 6611 6597 6595 6595 6596 6611 6618 6611 6596 6599 6598 6597 6611 6599 6597 6598 7364 7366 6598 6599 7364 6599 6611 6612 6599 7363 7364 6599 6612 7363 7353 6615 6600 7369 7353 6600 6600 6601 7369 6601 6602 7369 6603 6602 6601 7380 7369 6602 7381 7380 6602 8215 7381 6602 6602 8204 8215 6602 6603 8204 8205 8204 6603 6603 8203 8205 6603 6613 8203 6604 6605 6616 6605 6608 6616 6605 6607 6608 6605 6606 6607 6621 6607 6606 7374 6621 6606 6606 7373 7374 6606 6631 7373 6620 6608 6607 6642 6620 6607 6607 6621 6642 6617 6616 6608 6620 6617 6608 8179 6610 6609 6609 7359 8179 8179 7352 6610 6618 6612 6611 6612 6618 7363 8962 8203 6613 6613 8214 8962 6613 8191 8214 6613 6614 8191 6614 7367 8191 8168 7343 6615 8174 8168 6615 8180 8174 6615 6615 7353 8180 7358 7351 6616 6616 6617 7358 6617 7356 7358 7357 7356 6617 7386 7357 6617 6617 6642 7386 6617 6620 6642 6618 7360 7363 7372 6624 6619 7384 7372 6619 7385 7384 6619 6645 6642 6621 7374 6645 6621 7372 6650 6623 6623 6624 7372 6627 6626 6625 8197 7382 6626 6626 6641 8197 6626 6627 6641 8198 6655 6628 6628 6629 8198 6630 6629 6628 6629 8177 8181 6629 7348 8177 6629 6630 7348 6629 8182 8198 6629 8181 8182 8199 7373 6631 6631 7346 8199 8246 8240 6632 6632 6633 8246 6634 6633 6632 6649 6634 6632 6633 7412 8246 8247 8231 6635 6635 6636 8247 6637 6636 6635 8231 6637 6635 6636 6637 8206 8988 8247 6636 9794 8988 6636 9795 9794 6636 6636 8206 9795 6637 6650 7372 6656 6650 6637 8231 6656 6637 6637 7372 8206 7394 7393 6638 6638 6656 7394 6638 6651 6656 6653 6640 6639 7395 6641 6640 7397 7395 6640 6640 6653 7397 8217 8197 6641 6641 7395 8217 7389 7386 6642 6642 6643 7389 6645 6643 6642 6643 6644 7389 6645 6644 6643 8225 7389 6644 6644 8212 8225 6644 8200 8212 6644 6645 8200 6645 7374 8200 8213 6647 6646 8239 8213 6646 6646 6679 8239 6646 6677 6679 7376 6648 6647 8201 7376 6647 8213 8201 6647 7376 7375 6648 6657 6653 6652 6653 6673 7396 6653 6657 6673 6653 7396 7397 6654 6655 6658 7398 6658 6655 8218 7398 6655 6655 8198 8218 8231 7394 6656 8250 6673 6657 6657 6675 8250 7399 6664 6658 6658 7398 7399 6660 7401 7406 6660 7393 7401 7406 6661 6660 7406 6662 6661 6686 6672 6662 6704 6686 6662 7405 6704 6662 7406 7405 6662 6663 6664 6676 7399 6676 6664 6667 6666 6665 8252 7410 6667 6668 6696 8261 6668 6695 6696 8255 7402 6668 8260 8255 6668 8261 8260 6668 6671 6670 6669 7400 6671 6669 8240 7400 6669 7428 6701 6670 8273 7428 6670 6670 7411 8273 6670 6671 7411 6701 6700 6670 8995 7411 6671 6671 7400 8995 8992 7396 6673 8993 8992 6673 6673 8250 8993 7407 6675 6674 6674 6683 7407 6675 7407 8250 7409 6688 6676 6676 7408 7409 6676 7399 7408 6677 6678 6679 6685 6678 6677 6678 6685 6691 6680 6679 6678 6691 6680 6678 9829 9817 6679 6679 9003 9829 9004 9003 6679 6679 6680 9004 9817 8239 6679 6680 8257 9004 6680 6691 8257 6705 6682 6681 6681 6699 6705 6681 6698 6699 6681 6687 6698 7422 7407 6683 7423 7422 6683 7425 7423 6683 6683 6684 7425 6684 7415 7425 6685 6689 6691 6704 6687 6686 6704 6698 6687 7425 7415 6688 6688 7409 7425 9009 6692 6690 9010 9009 6690 6690 7416 9010 6690 6693 7416 6691 6692 8257 9009 8257 6692 6693 6694 7416 7417 7416 6694 7427 6696 6695 6696 7427 8261 6697 6702 7403 6703 6699 6698 6704 6703 6698 6699 6703 6705 7404 7403 6702 6702 6719 7404 6702 6709 6719 6711 6710 6703 6712 6711 6703 6703 6704 6712 7413 6712 6704 7421 7413 6704 6704 7405 7421 6718 6708 6707 8261 7431 6708 6708 7438 8261 6708 6718 7438 6720 6719 6709 6710 6725 6738 6710 6711 6725 6726 6725 6711 6711 6712 6726 7429 6726 6712 6712 7413 7429 6715 6714 6713 6721 6715 6713 6714 6715 6716 6717 6716 6715 7449 6717 6715 6715 7447 7449 6715 7446 7447 6715 6721 7446 7438 6718 6716 8300 7438 6716 6716 6717 8300 9038 8300 6717 9858 9038 6717 6717 7450 9858 6717 7449 7450 8285 7404 6719 6719 6720 8285 6720 7440 8285 7453 6724 6722 6722 7452 7453 6722 6723 7452 6723 6749 7452 7453 6729 6724 6725 7441 8289 6725 6726 7441 6725 6737 6738 8287 6737 6725 8289 8287 6725 6726 7429 7441 7472 6728 6727 8323 7472 6727 8324 8323 6727 6727 8308 8324 6727 8307 8308 7472 6747 6728 8284 7440 6729 6729 7454 8284 6729 7453 7454 6729 7440 7455 7458 6736 6731 8306 7446 6732 6732 8304 8306 8305 8304 6732 6732 7456 8305 6732 6733 7456 7465 7456 6733 7481 7465 6734 7482 7481 6734 6734 6746 7482 6735 7439 7458 7439 7432 6736 7458 7439 6736 9026 6765 6737 6737 8287 9026 7479 7468 6739 6739 6766 7479 6739 6742 6766 6745 6742 6739 6739 6740 6745 6741 6740 6739 7468 6741 6739 8311 6745 6740 6740 7461 8311 6740 7460 7461 6740 6741 7460 8302 7460 6741 6741 7468 8302 6742 6756 6766 6742 6743 6756 6744 6743 6742 6745 6744 6742 6743 6755 6756 6743 6744 6755 6768 6755 6744 7480 6768 6744 6744 6745 7480 9044 7480 6745 6745 8311 9044 7485 7482 6746 6746 6769 7485 7472 6760 6747 6750 6749 6748 6761 6750 6748 6749 6751 7452 6749 6750 6751 7473 6751 6750 8317 7473 6750 8318 8317 6750 8323 8318 6750 6750 6761 8323 7454 7452 6751 7457 7454 6751 7473 7457 6751 6752 6753 6778 6754 6753 6752 6775 6754 6752 6753 6777 6778 7475 6777 6753 7493 7475 6753 6753 6754 7493 6754 7476 7493 6754 6776 7476 6754 6775 6776 6767 6756 6755 6768 6767 6755 6756 6779 6780 6756 6767 6779 6777 6766 6756 6778 6777 6756 7486 6769 6757 6757 6770 7486 6771 6770 6757 7508 7507 6758 6758 6759 7508 7507 6787 6758 6759 6774 7508 8323 6788 6760 6760 7472 8323 8332 6774 6760 6760 6788 8332 6761 6788 8323 6761 6762 6788 6762 6783 6788 8345 8344 6763 9068 8345 6763 6763 9066 9068 6763 6764 9066 6765 6764 6763 9865 9066 6764 9877 9865 6764 6764 6765 9877 6765 9854 9877 6765 9026 9854 6766 6777 7479 7495 6779 6767 6767 7494 7495 8334 7494 6767 6767 8329 8334 6767 6768 8329 6768 7480 8329 7486 7485 6769 7487 7486 6770 6770 6772 7487 7488 7487 6772 6772 6773 7488 6773 6786 7488 7490 6786 6773 6773 7489 7490 8331 7508 6774 8332 8331 6774 6797 6776 6775 7502 7491 6776 7491 7476 6776 6777 7475 7479 6781 6780 6779 7495 6781 6779 6780 6781 6785 7495 6785 6781 6788 6783 6782 6789 6788 6782 7501 6789 6782 6792 6791 6784 6785 7495 7504 6786 7487 7488 7515 7487 6786 6786 7499 7515 6786 7490 7500 7490 7489 6787 7500 7490 6787 6788 6789 8332 6790 6795 7509 6791 6793 7510 6791 6792 6793 6796 6793 6792 8351 7510 6793 6793 8344 8351 6793 6796 8344 7518 7499 6794 7519 7518 6794 6795 6802 7509 6798 6799 6805 6800 6799 6798 7529 6800 6798 8370 7529 6798 6798 6808 8370 6798 6805 6808 7529 7528 6800 7547 7530 6801 8349 7547 6801 6801 7520 8349 7532 7509 6802 7533 7532 6802 6802 6806 7533 7523 7522 6804 7545 7533 6806 6807 7510 7534 6808 6812 8370 7550 6817 6809 6809 7546 7550 6809 7534 7546 6817 6810 6809 6810 6817 6818 7542 6814 6811 6811 7531 7542 6812 8369 8370 9092 8369 6812 9100 9092 6812 6812 6813 9100 9101 9100 6813 6813 8380 9101 6813 7552 8380 7554 6830 6814 6814 7543 7554 6814 7542 7543 6815 6822 6825 6816 8381 8382 6816 7572 8381 6817 8356 8375 6817 7550 8356 7556 6818 6817 8383 7556 6817 6817 8375 8383 8388 7566 6818 6818 8387 8388 6818 7564 8387 6818 7556 7564 7558 6821 6819 8373 7539 6820 8384 8373 6820 6820 7559 8384 6820 6821 7559 8385 7559 6821 6821 7558 8385 6827 6825 6822 7560 6827 6822 6822 7551 7560 8380 7557 6823 8393 8380 6823 6823 8392 8393 6823 6829 8392 6824 6825 6828 6825 6827 6828 6826 9107 9949 6826 8379 9107 6826 7568 8379 6826 6827 7568 6828 6827 6826 9118 6828 6826 6826 8394 9118 9953 8394 6826 6826 9112 9953 9113 9112 6826 9949 9113 6826 6827 7560 7568 9118 7577 6828 6829 7581 8392 6829 6836 7581 6832 6831 6830 7554 6832 6830 6831 7571 7578 6831 7570 7571 6831 6832 7570 8386 7570 6832 6832 7554 8386 6838 6835 6834 6834 6837 6838 8381 7572 6835 6835 7573 8381 7574 7573 6835 6835 6838 7574 6836 6839 7581 6837 6843 7585 6837 6842 6843 7585 6838 6837 7585 7574 6838 7584 7581 6839 6839 6841 7584 7588 6844 6840 6840 7586 7588 7587 7584 6841 7591 7587 6841 6855 6843 6842 7593 7585 6843 6843 6855 7593 7588 6849 6844 9129 7591 6845 9147 9129 6845 6845 7601 9147 6845 6846 7601 6846 6858 7601 6846 6850 6858 6847 6848 9135 6848 8404 9135 6849 7588 7600 6850 6851 6858 6851 6857 6858 6851 6852 6857 7623 6857 6852 6852 6853 7623 7630 7623 6853 6853 6863 7630 6866 6863 6853 6853 6859 6866 8407 6855 6854 6854 7615 8407 6854 7614 7615 6854 6856 7614 8408 7593 6855 6855 8407 8408 7611 6858 6857 7623 7611 6857 7611 7610 6858 7612 7601 6858 6858 7610 7612 7628 6865 6860 6860 7619 7628 6860 7607 7619 6860 6861 7607 7620 7607 6861 6864 6863 6862 7640 6864 6862 6862 6874 7640 6862 6868 6874 6862 6863 6866 7632 7630 6863 8426 7632 6863 6863 6864 8426 8440 8426 6864 6864 7643 8440 6864 7640 7643 6885 6879 6867 6889 6874 6868 6869 6870 6878 6871 6870 6869 6880 6878 6870 7639 6880 6870 6870 6871 7639 6871 7637 7639 6871 7633 7637 6891 6873 6872 6883 6881 6873 7641 6883 6873 6873 6891 7641 6874 6876 7640 6874 6875 6876 6889 6875 6874 6888 6876 6875 6900 6888 6875 6875 6877 6900 6876 6892 7640 6876 6888 6892 6901 6900 6877 7648 6901 6877 8447 7648 6877 8448 8447 6877 6877 6878 8448 6878 7644 8448 6878 6890 7644 6878 6880 6890 7653 7652 6879 9200 7653 6879 9202 9200 6879 6879 9193 9202 6879 6886 9193 6879 6884 6886 6885 6884 6879 8446 6890 6880 6880 7639 8446 8430 8414 6881 6881 8429 8430 9184 8429 6881 6881 6882 9184 6883 6882 6881 6882 6883 9184 6883 7641 9184 6887 6886 6884 6884 6885 6887 8436 6887 6885 6885 8431 8436 6885 7638 8431 6885 7634 7638 6886 10016 10022 6886 9185 10016 6886 6887 9185 10022 9193 6886 9186 9185 6887 6887 8436 9186 6893 6892 6888 6903 6893 6888 6888 6900 6903 7645 7644 6890 8446 7645 6890 7649 7641 6891 8451 7649 6891 6891 7650 8451 7642 7640 6892 7646 7642 6892 6892 6896 7646 6892 6893 6896 6897 6896 6893 6903 6897 6893 8453 7651 6894 6894 6895 8453 6896 6898 7654 6896 6897 6898 7658 7646 6896 6896 7654 7658 6897 6905 6907 6897 6904 6905 6897 6903 6904 6899 6898 6897 6907 6899 6897 6898 6899 7655 7655 7654 6898 7664 7663 6899 6899 6908 7664 6899 6907 6908 7663 7655 6899 6900 6902 6903 6900 6901 6902 8450 6902 6901 6901 7648 8450 6904 6903 6902 7662 6904 6902 8457 7662 6902 6902 8450 8457 6906 6905 6904 7661 6906 6904 6904 7660 7661 7662 7660 6904 6909 6907 6905 6905 6906 6909 7661 6909 6906 6909 6908 6907 6908 6910 7664 6908 6909 6910 7661 6910 6909 8461 8460 6910 6910 7661 8461 7666 7664 6910 8460 7666 6910 6914 6913 6912 6916 6914 6912 6921 6916 6912 6913 6917 7687 6913 6915 6917 6913 6914 6915 7682 6915 6914 6914 6919 7682 6914 6918 6919 6914 6916 6918 7682 7677 6915 7683 6917 6915 6915 7678 7683 6915 7677 7678 8476 6918 6916 6916 8473 8476 6916 6921 8473 7688 7687 6917 7690 7688 6917 6917 7689 7690 6917 7683 7689 6920 6919 6918 9264 6920 6918 6918 8476 9264 9261 7682 6919 6919 6920 9261 6920 9264 9265 9263 9261 6920 9265 9263 6920 6921 7693 8473 6921 6922 7693 6922 7692 7693 6923 6924 7702 7701 7700 6923 7702 7701 6923 6924 6925 7702 6925 6928 7699 6925 7699 7702 7708 6930 6926 6926 6933 7708 6932 6928 6927 6928 6932 7699 6929 6931 6934 6929 6930 6931 7703 6931 6930 7708 7703 6930 6931 7703 7704 6942 6934 6931 7704 6942 6931 7710 7699 6932 7713 7710 6932 8504 7708 6933 9307 8504 6933 6933 9302 9307 6933 7698 9302 6934 6941 6945 6942 6941 6934 6935 6936 6938 6937 6936 6935 7714 6937 6935 7718 7714 6935 6939 6938 6936 6940 6939 6936 6950 6940 6936 7707 6950 6936 6936 7706 7707 6936 6937 7706 8498 7706 6937 6937 7715 8498 6937 7714 7715 6939 6940 6943 6951 6943 6940 6940 6950 6951 6947 6945 6941 8512 6947 6941 6941 8502 8512 6941 6942 8502 6942 7704 8502 6943 7720 7731 6943 6951 7720 8532 7717 6944 6944 8526 8532 6944 7722 8526 6945 6948 6949 6945 6946 6948 6947 6946 6945 8520 6948 6946 6946 8512 8520 6946 6947 8512 6954 6949 6948 8527 6954 6948 6948 8520 8527 6949 6956 6958 6949 6953 6956 6954 6953 6949 6952 6951 6950 7707 6952 6950 6951 7716 7720 6951 6952 7716 8501 7716 6952 6952 7721 8501 6952 7710 7721 7711 7710 6952 6952 7707 7711 6957 6956 6953 6961 6957 6953 8535 6961 6953 6953 7724 8535 6953 6955 7724 6953 6954 6955 8527 6955 6954 8527 7724 6955 6966 6959 6956 6956 6962 6966 6956 6957 6962 6959 6958 6956 6970 6962 6957 6957 6969 6970 6957 6961 6969 6966 6960 6959 7732 6974 6960 6960 6966 7732 6961 6968 6969 8535 6968 6961 6971 6966 6962 6962 6970 6971 7730 7726 6963 7725 6965 6964 7727 7725 6964 7725 7723 6965 6966 6971 7732 8550 6982 6967 6967 8549 8550 6967 6968 8549 6969 6968 6967 6980 6969 6967 6982 6980 6967 6968 8535 8549 6975 6970 6969 6979 6975 6969 6980 6979 6969 6975 6971 6970 7737 7732 6971 6971 6976 7737 6971 6975 6976 9363 7727 6972 6972 7738 9363 8563 7738 6972 6972 7735 8563 6972 6973 7735 7746 7735 6973 6973 6983 7746 6974 7742 8557 6974 7732 7742 8557 7736 6974 6977 6976 6975 6979 6977 6975 8577 7737 6976 6976 7747 8577 7748 7747 6976 6976 6977 7748 6989 6988 6978 6982 6981 6980 6981 6982 7743 6982 8550 8558 8558 7743 6982 6983 6984 7746 6984 7745 7746 6985 7755 7757 6985 6986 7755 6986 7741 7755 7750 7008 6987 6987 7749 7750 7740 7005 6988 6988 6989 7740 6989 7739 7740 6990 7006 7007 7010 6993 6991 6991 6994 7010 6995 6994 6991 6991 6992 6995 6993 6992 6991 7779 6995 6992 6992 7760 7779 6992 7759 7760 6992 6993 7759 6993 7009 7016 7010 7009 6993 7792 7759 6993 6993 7016 7792 6994 6996 7010 6994 6995 6996 7779 6996 6995 7011 7010 6996 7779 7011 6996 6997 6998 7000 6999 6998 6997 7763 6999 6997 7002 7000 6998 7004 7002 6998 7751 7004 6998 6998 6999 7751 8560 7751 6999 6999 7763 8560 7002 7001 7000 7001 7002 7003 7004 7003 7002 8587 7013 7003 7003 7014 8587 7003 7004 7014 7752 7014 7004 7004 7751 7752 7005 7740 7806 7776 7007 7006 8585 7758 7008 7008 8579 8585 7008 7750 8579 7009 7015 7016 7010 7011 7017 7780 7017 7011 7782 7780 7011 7011 7761 7782 7762 7761 7011 7779 7762 7011 8603 7784 7012 7012 8587 8603 7012 7013 8587 7014 8581 8587 7014 8573 8581 7014 7752 8573 8613 7035 7015 7015 7050 8613 7015 7036 7050 7015 7022 7036 7035 7016 7015 8609 7792 7016 7016 7035 8609 7793 7038 7018 7018 7784 7793 7801 7033 7019 7019 7020 7801 7020 7021 7801 7021 7033 7801 7048 7036 7022 7022 7037 7048 7023 7781 7783 7023 7780 7781 7024 7025 7055 7026 7025 7024 7055 7026 7024 7025 7029 7042 7025 7027 7029 7028 7027 7025 7025 7026 7028 7025 7042 7055 7795 7028 7026 7802 7795 7026 7803 7802 7026 7026 7055 7803 7027 7028 7765 7043 7029 7027 7797 7043 7027 7027 7788 7797 7027 7765 7788 7767 7764 7028 7795 7767 7028 7028 7764 7765 7044 7042 7029 7029 7043 7044 7030 7822 8607 8608 7805 7030 7030 8607 8608 7031 7032 7045 7816 7810 7034 7035 8613 9403 9403 8609 7035 7036 7048 7050 7051 7048 7037 7052 7051 7037 7839 7835 7039 7039 7040 7839 7041 7040 7039 7835 7041 7039 7040 7062 7839 7040 7061 7062 7066 7061 7040 7040 7055 7066 7040 7041 7055 7803 7055 7041 8622 7803 7041 9397 8622 7041 9427 9397 7041 7041 9426 9427 7041 7835 9426 7070 7066 7042 7042 7056 7070 7042 7044 7056 7066 7055 7042 7813 7044 7043 7814 7813 7043 7043 7804 7814 7043 7797 7804 7813 7056 7044 7051 7049 7048 7048 7049 7050 7049 7051 7828 8621 7050 7049 9419 8621 7049 7049 7828 9419 8619 8613 7050 8621 8619 7050 7051 7827 7828 7051 7052 7827 7831 7827 7052 7052 7059 7831 7834 7817 7053 7053 7811 7834 7053 7054 7811 7054 7793 7811 7072 7070 7056 7818 7072 7056 7056 7813 7818 7057 7058 7825 7058 7067 7825 8629 7831 7059 8630 8629 7059 7059 7830 8630 7059 7829 7830 7830 7829 7060 7838 7830 7060 8631 7838 7060 7060 7817 8631 7065 7062 7061 7070 7065 7061 7061 7066 7070 7062 7063 7074 7065 7063 7062 7062 7074 7839 7075 7074 7063 7866 7075 7063 7063 7083 7866 7063 7064 7083 7065 7064 7063 7064 7076 7083 7064 7065 7076 7065 7071 7076 7065 7070 7071 8626 7825 7067 8634 8626 7067 7067 7068 8634 7069 7068 7067 8635 8634 7068 8648 8635 7068 7068 7069 8648 7069 7870 8648 7072 7071 7070 7071 7072 7819 7840 7076 7071 7071 7819 7840 7072 7818 7819 8632 7826 7073 7073 8627 8632 7074 7075 7865 8646 7839 7074 7074 7865 8646 7885 7865 7075 7075 7874 7885 7075 7866 7874 7854 7083 7076 7076 7853 7854 7076 7840 7853 8652 7842 7077 7077 7078 8652 9441 8652 7078 7079 7080 7861 7080 7860 7861 7862 7082 7081 7098 7092 7082 7863 7098 7082 7864 7863 7082 9454 7864 7082 7082 8658 9454 7082 7862 8658 7874 7866 7083 7883 7874 7083 7083 7876 7883 7083 7854 7876 9430 9428 7084 7084 9429 9430 9437 9429 7084 7084 7085 9437 7085 7880 9437 7872 7088 7086 7873 7872 7086 7086 7087 7873 7087 7826 7873 7872 7871 7088 7092 7099 7102 7100 7099 7092 7092 7098 7100 7093 7094 7887 7095 7094 7093 8679 7095 7093 7093 8664 8679 7093 7911 8664 7093 7903 7911 8670 8648 7094 9458 8670 7094 7094 7095 9458 7094 7882 7887 7094 7870 7882 8648 7870 7094 7095 8669 9458 9469 8669 7095 7095 8679 9469 7096 7097 7912 8661 8660 7096 7096 7912 8661 7097 7107 7912 7108 7107 7097 7885 7100 7098 7098 7863 7885 7892 7104 7099 7099 7100 7892 7100 7891 7892 7100 7885 7891 7103 7105 7110 7103 7104 7105 7893 7105 7104 7104 7892 7893 7893 7110 7105 7106 7890 7902 7902 7901 7106 8677 8676 7107 7107 7108 8677 8676 7912 7107 8690 8677 7108 7108 7926 8690 7108 7116 7926 7914 7114 7109 7109 7913 7914 7109 7904 7913 7109 7892 7904 7109 7110 7892 7893 7892 7110 7920 7123 7111 7910 7903 7112 7921 7910 7112 7914 7119 7114 7119 7115 7114 7931 7149 7115 7115 7119 7931 7927 7926 7116 7116 7125 7927 7117 7118 7127 7119 7922 7931 7119 7914 7922 7120 7122 7918 7919 7918 7122 7935 7128 7123 7936 7935 7123 7123 7920 7936 8698 7927 7125 7125 7126 8698 7126 8696 8698 8697 8696 7126 7126 7131 8697 7940 7132 7127 7127 7149 7940 7134 7133 7128 7935 7134 7128 9493 7937 7129 10455 9493 7129 7129 7130 10455 7130 8745 9511 7130 7170 8745 7130 7164 7170 7955 7164 7130 7130 7153 7955 10467 10455 7130 7130 9511 10467 8706 8697 7131 7131 7135 8706 7940 7146 7132 7954 7163 7133 7133 7134 7954 8703 7954 7134 8704 8703 7134 7134 7935 8704 7135 7136 8706 7136 8705 8706 7136 7957 8705 7139 7138 7137 7141 7139 7137 7138 7947 7958 7138 7139 7947 7139 7141 7939 7139 7946 7947 7139 7939 7946 7948 7939 7141 7144 7143 7142 8712 7144 7142 8713 8712 7142 7142 7145 8713 7143 7144 7948 8720 7948 7144 7144 8712 8720 7145 7154 8713 7148 7147 7146 7149 7148 7146 7940 7149 7146 7147 7156 7974 7147 7148 7156 7932 7156 7148 7148 7149 7932 7149 7931 7932 7160 7159 7150 7150 7158 7160 8689 7919 7151 7151 7152 8689 7152 7945 8689 7154 7961 8713 7962 7961 7154 7155 7949 7975 7155 7944 7949 7155 7932 7944 7155 7156 7932 7157 7156 7155 7975 7157 7155 9517 7974 7156 9529 9517 7156 7156 9518 9529 7156 7157 9518 9519 9518 7157 9520 9519 7157 7157 7975 9520 7964 7160 7158 7159 7964 7977 7159 7160 7964 7161 7952 7968 7979 7174 7162 7162 7978 7979 7162 7168 7978 7163 7954 7973 7165 7166 8705 7957 7956 7165 8705 7957 7165 7166 8695 8705 7166 8680 8695 7166 7925 8680 7168 7968 7978 8729 7953 7169 7169 8716 8729 7169 7180 8716 7170 7183 8745 7173 7172 7171 7984 7977 7172 7172 7173 7984 7990 7984 7173 8742 7982 7174 7174 8741 8742 7174 7979 8741 7177 7176 7175 7178 7177 7175 7186 7184 7176 7981 7186 7176 7176 7177 7981 7177 7178 7981 7178 7960 7981 7986 7180 7179 7179 7185 7986 7180 7986 8753 8747 8716 7180 8753 8747 7180 7987 7182 7181 8754 7987 7181 7181 7983 8754 7182 7987 7991 8755 8745 7183 9534 8755 7183 7183 8759 9534 7184 7186 7989 7993 7992 7184 7994 7993 7184 7184 7989 7994 7185 7187 7986 7186 7988 7989 7186 7981 7988 7991 7986 7187 8002 8001 7188 7188 7192 8002 7993 7198 7189 7189 7992 7993 7203 7202 7190 8002 7192 7191 7191 7201 8002 8005 7194 7193 7193 7198 8005 8004 7201 7194 8005 8004 7194 8006 7197 7195 7195 8004 8006 8795 8004 7195 8800 8795 7195 8803 8800 7195 7195 7196 8803 7197 7196 7195 9614 8803 7196 7196 8804 9614 7196 7197 8804 7197 8006 8007 7197 8007 8804 8007 8005 7198 8011 8007 7198 7198 7993 8011 7199 7200 8014 7199 7208 7209 8014 7208 7199 7200 8010 8014 8003 8002 7201 8004 8003 7201 7997 7990 7202 7202 7203 7997 7203 7204 7997 7205 7204 7203 8790 7205 7203 8796 8790 7203 7203 8009 8796 8773 7997 7204 10542 8773 7204 7204 7205 10542 10544 10542 7205 7205 8790 10544 8812 8013 7206 8818 8812 7206 7206 7207 8818 7207 7219 8818 7220 7219 7207 7207 7211 7220 7208 8014 8015 8017 8016 7210 7210 7214 8017 7210 7213 7214 7224 7220 7211 7211 7221 7224 8024 8020 7212 8026 8024 7212 8819 8026 7212 7212 8015 8819 7215 7214 7213 8826 8017 7214 7214 7215 8826 8827 8826 7215 8821 8813 7216 7216 8021 8821 7222 7221 7217 8022 7222 7217 8822 8022 7217 7217 7218 8822 7219 8018 8818 8019 8018 7219 7219 7220 8019 8028 8019 7220 7220 8023 8028 7220 7223 8023 7224 7223 7220 7221 7222 7224 8824 7224 7222 7222 8022 8824 8030 8023 7223 7223 7224 8030 8031 8030 7224 8824 8031 7224 8027 7226 7225 8835 8029 7226 7226 8828 8835 7226 8027 8828 7227 7236 7238 8040 8039 7228 7229 7231 8041 7229 7230 7231 7233 7231 7230 7233 7232 7231 7234 8037 8063 8038 8037 7234 7234 7235 8038 7236 7235 7234 7238 7236 7234 9633 8038 7235 7235 8024 9633 7235 8020 8024 8036 8020 7235 7235 7236 8036 8054 8045 7237 8057 8054 7237 7237 7240 8057 7251 7240 7239 7239 7246 7251 7240 7251 8057 8064 8056 7241 7241 7242 8064 7242 7247 8064 7243 8056 8068 7244 7245 7246 7250 7249 7245 8063 7250 7245 7249 7246 7245 7252 7251 7246 7253 7252 7246 7255 7253 7246 7246 7249 7255 7247 7254 8064 7247 7248 7254 7258 7254 7248 7249 7250 9661 8855 7255 7249 9661 8855 7249 7250 9653 9661 7250 8063 9653 8058 8057 7251 7251 7252 8058 7252 7263 8058 7252 7253 7263 7253 7262 7263 7253 7261 7262 7253 7255 7261 7254 7258 8064 8855 7261 7255 8067 7264 7256 8064 7258 7257 8071 8064 7257 7257 7265 8071 7263 7262 7259 8072 7263 7259 7259 7260 8072 7261 7260 7259 7262 7261 7259 8084 8072 7260 7260 8083 8084 7260 8082 8083 7260 7261 8082 8855 8082 7261 8077 8058 7263 8086 8077 7263 7263 8072 8086 9663 8074 7264 7264 8067 9663 8075 8071 7265 7265 7266 8075 7267 7266 7265 8076 8075 7266 8081 8076 7266 7266 7267 8081 8866 8859 7267 7267 8865 8866 7267 8090 8865 8859 8081 7267 7285 7283 7268 7268 7271 7285 7268 7269 7271 7270 7269 7268 7283 7270 7268 8094 7271 7269 7269 8093 8094 7269 7270 8093 7270 7284 8093 7270 7283 7284 7271 7272 7285 7273 7272 7271 8095 7273 7271 7271 8094 8095 7272 7274 7285 7272 7273 7274 8096 7274 7273 7273 8095 8096 8109 7285 7274 7274 8096 8109 7275 7278 8122 7275 7276 7278 7277 7276 7275 8122 7277 7275 7281 7278 7276 8102 7281 7276 7276 8101 8102 7276 7277 8101 8110 8101 7277 8122 8110 7277 7278 7286 8122 7278 7279 7286 7280 7279 7278 7281 7280 7278 7279 7282 7286 7279 7280 7282 8104 7282 7280 7280 8103 8104 7280 7281 8103 9677 8103 7281 9679 9677 7281 9680 9679 7281 7281 8102 9680 7287 7286 7282 8104 7287 7282 7288 7284 7283 7283 7285 7288 8121 8093 7284 7284 7288 8121 8120 7288 7285 7285 8109 8120 8128 8122 7286 7286 8112 8128 7286 8111 8112 7286 7287 8111 7287 8105 8111 7287 8104 8105 7288 8119 8121 8120 8119 7288 7291 7290 7289 7290 8113 8114 7290 7291 8113 8116 8090 7290 7290 8115 8116 7290 8114 8115 7291 8112 8113 8129 8112 7291 7294 7293 7292 8896 7294 7292 8117 7303 7294 8118 8117 7294 8896 8118 7294 8152 8140 7295 7295 7330 8152 7295 7313 7330 7295 7296 7313 7297 7296 7295 8140 7297 7295 7314 7313 7296 7296 7297 8129 7297 8128 8129 8910 8128 7297 8911 8910 7297 7297 8140 8911 8894 7301 7298 8900 8894 7298 9714 8900 7298 7298 7299 9714 7300 7299 7298 9722 9714 7299 7299 7300 9722 7300 8918 9722 7300 8138 8918 8125 7304 7303 7303 8117 8125 8125 7311 7304 7315 7314 7305 7331 7315 7305 7305 7316 7331 7306 7318 8137 7306 7317 7318 7333 7317 7307 7334 7333 7307 8167 7334 7307 7308 7349 8142 8176 7349 7308 9742 8176 7308 7308 7309 9742 7310 7309 7308 8142 7310 7308 10688 9742 7309 7309 9720 10688 7309 7310 9720 7329 7312 7311 8130 7329 7311 7311 8125 8130 7313 7315 7330 7313 7314 7315 7331 7330 7315 7332 7331 7316 7333 7332 7316 7316 7317 7333 8172 7335 7319 8938 8172 7319 7319 8156 8938 7319 7320 8156 7321 7322 7323 7336 7324 7322 7322 7325 7336 7324 7323 7322 8157 8156 7323 7323 7324 8157 8158 8157 7324 7324 7336 8158 7325 7326 7336 8161 7336 7326 8162 7338 7327 7327 7339 8162 7328 7350 8143 7328 7345 7350 8130 7342 7329 8154 8152 7330 7330 7331 8154 7331 8153 8154 7331 7332 8153 7332 7334 8153 7332 7333 7334 8167 8153 7334 7335 9751 9766 7335 8172 9751 9773 8173 7335 7335 9766 9773 8161 8158 7336 8162 7344 7338 7339 7344 8162 7340 7341 7347 8141 7347 7341 8178 7346 7342 7342 8163 8178 8164 8163 7342 8923 8164 7342 7342 8130 8923 7354 7350 7345 7355 7354 7345 8931 8199 7346 8933 8931 7346 8934 8933 7346 7346 8178 8934 8142 7349 7347 7347 8141 8142 7348 7349 8177 7349 8175 8177 8176 8175 7349 7350 7354 8143 8219 7355 7351 7351 7358 8219 7352 7359 7360 8179 7359 7352 7353 7370 8180 7371 7370 7353 7380 7371 7353 7353 7369 7380 8952 8947 7354 7354 7355 8952 8947 8946 7354 7355 8219 8952 7390 7358 7356 7391 7390 7356 7356 7357 7391 7357 7387 7391 7357 7386 7387 8959 8219 7358 7358 7390 8959 7362 7360 7359 8183 7362 7359 7359 7375 8183 7360 7361 7363 7362 7361 7360 7364 7363 7361 7377 7364 7361 8185 7377 7361 7361 7362 8185 7362 8183 8185 7364 7365 7366 7377 7365 7364 7383 7366 7365 7365 7377 7383 7383 7368 7366 7368 7367 7366 8958 8191 7367 7367 8957 8958 7367 8189 8957 7367 7368 8189 7379 7378 7368 7383 7379 7368 8190 8189 7368 7368 7378 8190 8196 8180 7370 7370 7371 8196 7371 8192 8196 7371 7380 8192 8209 8206 7372 7372 7384 8209 8211 7374 7373 8932 8211 7373 7373 8199 8932 8211 8200 7374 8184 8183 7375 8961 8184 7375 7375 8201 8961 7375 7376 8201 7377 7379 7383 8185 7379 7377 8202 8187 7378 7378 7379 8202 9782 8190 7378 9791 9782 7378 7378 9789 9791 7378 8966 9789 7378 8187 8966 7379 8187 8202 7379 8185 8187 7380 7381 8192 7381 8215 8216 8195 8192 7381 8969 8195 7381 7381 8968 8969 7381 8230 8968 7381 8216 8230 8197 7384 7382 7384 8197 8209 7388 7387 7386 7389 7388 7386 8220 7391 7387 8222 8220 7387 7387 7392 8222 7387 7388 7392 7388 7389 7392 8223 7392 7389 8225 8223 7389 8975 8959 7390 7390 8220 8975 7390 7391 8220 8235 8222 7392 7392 8223 8235 8248 7401 7393 7393 7394 8248 7394 8231 8248 8232 8217 7395 8989 8232 7395 7395 8233 8989 8234 8233 7395 7395 7397 8234 8992 8241 7396 8241 7397 7396 8241 8234 7397 8243 7399 7398 8974 8243 7398 7398 8218 8974 8242 7408 7399 8243 8242 7399 7400 8253 8996 7400 8246 8253 7400 8240 8246 8996 8995 7400 7401 7405 7406 8249 7405 7401 7401 8248 8249 7420 7412 7403 8274 7420 7403 7403 7404 8274 8284 8274 7404 8285 8284 7404 8249 7421 7405 8254 8250 7407 7407 7422 8254 7424 7409 7408 9002 7424 7408 7408 8251 9002 7408 8242 8251 7409 7424 7425 7410 8258 9850 8259 8258 7410 9845 8259 7410 7410 9023 9845 7410 9012 9023 7410 8252 9012 9850 7419 7410 7411 8262 8273 8263 8262 7411 8995 8263 7411 7412 8262 8263 9013 8262 7412 7412 7420 9013 8253 8246 7412 8996 8253 7412 7412 8263 8996 8256 7429 7413 7413 7421 8256 7419 7418 7414 9011 9010 7416 7416 7417 9011 9022 9011 7417 7417 7418 9022 7418 7419 9844 9844 9022 7418 9850 9844 7419 7420 8282 9013 7420 8274 8282 7421 8249 8256 8269 8254 7422 7422 7430 8269 7422 7423 7430 7433 7430 7423 7437 7433 7423 7423 7425 7437 9000 7426 7424 9002 9000 7424 7426 7425 7424 7443 7437 7425 9024 7443 7425 7425 7426 9024 7426 9000 9024 7427 7431 8261 8301 7451 7428 7428 8279 8301 7428 8272 8279 8273 8272 7428 8256 7441 7429 8270 8269 7430 7430 8264 8270 8290 8264 7430 7430 7434 8290 7436 7434 7430 7442 7436 7430 7430 7433 7442 7433 7437 7442 8292 8290 7434 7434 7435 8292 7436 7435 7434 8319 8313 7435 7435 8297 8319 7435 7436 8297 9034 8292 7435 7435 8312 9034 8313 8312 7435 8314 8297 7436 7436 7462 8314 7463 7462 7436 7436 7445 7463 7436 7442 7445 7445 7442 7437 7437 7444 7445 7437 7443 7444 8278 8261 7438 8300 8278 7438 7455 7440 7439 7440 8284 8285 9014 8289 7441 7441 8276 9014 7441 8256 8276 8299 7444 7443 7443 8298 8299 9024 8298 7443 8303 7445 7444 7444 8299 8303 7464 7463 7445 8315 7464 7445 7445 8303 8315 7448 7447 7446 8306 7448 7446 9873 7449 7447 7447 9872 9873 7447 7448 9872 7448 9037 9872 7448 9036 9037 7448 8306 9036 9873 7450 7449 9861 9858 7450 9874 9861 7450 7450 9873 9874 7451 8301 8307 7454 7453 7452 7454 8281 8284 7454 7457 8281 8316 8305 7456 7456 7465 8316 9032 9030 7457 9033 9032 7457 7457 7473 9033 8283 8281 7457 7457 8279 8283 9030 8279 7457 8291 7461 7459 8296 8291 7459 7459 8295 8296 7459 7460 8295 7461 7460 7459 8302 8295 7460 7461 8291 9034 9034 8311 7461 7462 7469 8314 7462 7463 7469 7463 7464 7469 7470 7469 7464 8315 7470 7464 7465 7466 8316 7467 7466 7465 7471 7467 7465 7481 7471 7465 9036 8316 7466 7466 7467 9036 9048 9036 7467 7467 8321 9048 7467 7471 8321 8326 8302 7468 7468 7474 8326 7475 7474 7468 7479 7475 7468 8320 8314 7469 7469 7470 8320 7470 8315 8320 8322 8321 7471 7471 7483 8322 7471 7481 7483 7473 8317 9033 7474 7475 7493 7474 8325 8326 7474 7477 8325 7493 7477 7474 7476 7477 7493 7478 7477 7476 7491 7478 7476 8333 8325 7477 7477 7478 8333 8341 8333 7478 7478 7492 8341 7478 7491 7492 8330 8329 7480 9044 8330 7480 7481 7482 7483 7484 7483 7482 7485 7484 7482 8336 8322 7483 8337 8336 7483 7483 7484 8337 7484 7498 8343 7484 7485 7498 8343 8337 7484 7485 7497 7498 7485 7486 7497 7513 7497 7486 7486 7487 7513 7515 7513 7487 7502 7492 7491 7492 8339 8341 7492 7503 8339 7492 7502 7503 7494 8334 8335 8335 7495 7494 7506 7504 7495 8342 7506 7495 7495 8335 8342 7496 7497 7513 7498 7497 7496 7512 7498 7496 7513 7512 7496 7498 7512 8347 8347 8343 7498 7518 7515 7499 7535 7503 7502 8354 8338 7503 7503 7535 8354 7503 8338 8339 7506 7505 7504 9070 7511 7505 9901 9070 7505 7505 7506 9901 7506 8342 9901 7507 7508 8331 7532 7521 7509 7546 7534 7510 8362 7546 7510 7510 8352 8362 7510 8351 8352 7536 7523 7511 8357 7536 7511 9070 8357 7511 7512 7516 7517 7512 7513 7516 7512 7517 8347 7513 7514 7516 7515 7514 7513 7517 7516 7514 7524 7517 7514 7514 7518 7524 7514 7515 7518 8348 8347 7517 7517 7525 8348 7517 7524 7525 7527 7524 7518 7528 7527 7518 7518 7519 7528 7520 7521 8349 7521 7532 8349 8374 7537 7522 9072 8374 7522 7522 7536 9072 7522 7523 7536 7526 7525 7524 7527 7526 7524 8363 8348 7525 7525 7540 8363 7525 7526 7540 7526 7527 7540 7541 7540 7527 7527 7529 7541 7527 7528 7529 8367 7541 7529 8368 8367 7529 8370 8368 7529 7538 7531 7530 7547 7538 7530 7531 7538 7542 8350 8349 7532 8360 8350 7532 7532 7545 8360 7532 7533 7545 8372 8354 7535 7535 7539 8372 7536 8357 9072 7537 8374 9082 7543 7542 7538 7544 7543 7538 7548 7544 7538 7538 7547 7548 8373 8372 7539 8366 8363 7540 7540 7541 8366 9088 8366 7541 9090 9088 7541 7541 8367 9090 7543 7544 7554 7544 7553 7554 7544 7548 7553 7545 7549 8360 8356 7550 7546 9071 8356 7546 9078 9071 7546 7546 8371 9078 7546 8361 8371 8362 8361 7546 8358 7548 7547 9074 8358 7547 9076 9074 7547 7547 9075 9076 7547 8349 9075 9086 7553 7548 7548 8359 9086 7548 8358 8359 7549 7555 8360 7561 7560 7551 7552 7557 8380 8386 7554 7553 9105 8386 7553 9936 9105 7553 7553 9086 9936 9077 8360 7555 9093 9077 7555 7555 8382 9093 7556 7563 7564 8383 7563 7556 7558 7567 8385 7558 7565 7567 8385 8384 7559 7560 7561 7568 8379 7568 7561 9941 8389 7562 7562 9940 9941 7562 7563 9940 7564 7563 7562 8389 7564 7562 9933 9931 7563 7563 9095 9933 7563 8383 9095 7563 9931 9940 7564 7565 8387 8389 7565 7564 8389 7567 7565 8388 8387 7565 7565 7566 8388 7567 8384 8385 9096 8384 7567 7567 9081 9096 7567 8389 9081 8390 7571 7570 7570 8386 8390 7582 7578 7571 8391 7582 7571 7571 8390 8391 9111 8381 7573 9951 9111 7573 9952 9951 7573 7573 9125 9952 7573 7579 9125 7573 7574 7579 7580 7579 7574 7585 7580 7574 7575 7576 7586 7577 7576 7575 7592 7586 7576 8395 7592 7576 9117 8395 7576 7576 7577 9117 9118 9117 7577 9954 9125 7579 7579 7580 9954 7580 7585 9130 9958 9954 7580 7580 9130 9958 9127 8392 7581 7581 7584 9127 9126 7583 7582 7582 9124 9126 7582 8391 9124 9126 8403 7583 9129 9127 7584 7584 7587 9129 7585 7593 9130 7592 7588 7586 7587 7591 9129 7609 7600 7588 7588 7589 7609 7590 7589 7588 7592 7590 7588 9140 7609 7589 7589 7590 9140 7590 7592 9140 9141 9140 7592 7592 8395 9141 7593 8408 9149 9972 9130 7593 7593 9149 9972 7594 8398 8406 7594 7599 8398 7594 7598 7599 7594 7595 7598 7596 7595 7594 8406 7596 7594 7622 7598 7595 8416 7622 7595 9146 8416 7595 9154 9146 7595 7595 9153 9154 7595 7596 9153 7596 8405 9153 8406 8405 7596 7622 7617 7597 7597 7598 7622 7599 7598 7597 7606 7599 7597 7618 7606 7597 7597 7616 7618 7617 7616 7597 8401 8398 7599 7599 7604 8401 7606 7604 7599 7609 7608 7600 7601 8409 9147 7601 8397 8409 7601 7612 8397 8424 7624 7602 8425 8424 7602 7602 8412 8425 7602 7613 8412 7603 7620 8411 7603 7607 7620 7603 7606 7607 7603 7604 7606 7605 7604 7603 8411 7605 7603 9137 8401 7604 9151 9137 7604 7604 7605 9151 9967 9151 7605 7605 9155 9967 7605 9140 9155 7605 7609 9140 7605 7608 7609 8410 7608 7605 8411 8410 7605 7618 7607 7606 7607 7618 7619 8410 7621 7608 7610 7623 7630 7610 7611 7623 8413 7612 7610 7610 7631 8413 7610 7630 7631 8413 8397 7612 7625 7615 7614 8414 7625 7614 9149 8407 7615 7615 9145 9149 9150 9145 7615 7615 7625 9150 7626 7618 7616 7616 7617 7626 7617 7622 8417 8417 7626 7617 7627 7619 7618 7618 7626 7627 7619 7627 8421 7629 7628 7619 8420 7629 7619 8421 8420 7619 7621 8410 8411 7622 8415 8417 8416 8415 7622 8424 7633 7624 7625 8430 9150 7625 8414 8430 8421 7627 7626 7626 8417 8421 7638 7634 7629 8431 7638 7629 7629 7635 8431 7636 7635 7629 8420 7636 7629 9176 7631 7630 7630 8439 9176 7630 8427 8439 7630 8426 8427 7630 7632 8426 9175 8413 7631 9176 9175 7631 8424 7637 7633 9180 8431 7635 9998 9180 7635 7635 9997 9998 7635 8433 9997 7635 8432 8433 8435 8432 7635 7635 8422 8435 7635 7636 8422 7636 8420 8422 8441 7639 7637 8442 8441 7637 7637 8424 8442 9191 8446 7639 7639 8441 9191 7640 7642 7643 7641 9183 9184 10021 9183 7641 7641 7649 10021 7642 7646 7647 8444 7643 7642 7642 7647 8444 8444 8440 7643 7644 7645 9191 9192 8448 7644 7644 8443 9192 9191 8443 7644 7645 8446 9191 7658 7647 7646 7647 8438 8444 8449 8438 7647 8454 8449 7647 7647 7658 8454 7648 8447 8450 7649 9199 10021 7649 8455 9199 7649 8451 8455 7650 7651 8451 8453 8451 7651 7652 7653 8456 10038 8456 7653 11073 10038 7653 7653 9201 11073 7653 9200 9201 7659 7658 7654 7654 7656 7659 7654 7655 7656 7657 7656 7655 7663 7657 7655 9212 7659 7656 7656 8463 9212 7656 7657 8463 7657 8462 8463 7657 7667 8462 7657 7665 7667 7657 7663 7665 7658 7659 8454 9206 8454 7659 9207 9206 7659 9212 9207 7659 8457 7661 7660 7660 7662 8457 7661 8458 8461 8459 8458 7661 7661 8457 8459 7663 7664 7666 7671 7665 7663 7672 7671 7663 7663 7666 7672 7668 7667 7665 7671 7668 7665 8460 7672 7666 7667 7668 7673 7667 7675 8462 7676 7675 7667 7667 7673 7676 7668 7671 7673 9218 8465 7669 7669 7670 9218 7671 7670 7669 7674 7671 7669 8464 7674 7669 8465 8464 7669 7670 7672 9218 7670 7671 7672 7674 7673 7671 7672 9216 9218 7672 8460 9216 7673 7674 7676 8464 7676 7674 9241 8462 7675 9249 9241 7675 7675 9243 9249 7675 9242 9243 7675 8464 9242 7675 7676 8464 7681 7680 7677 7682 7681 7677 7679 7678 7677 7680 7679 7677 7684 7683 7678 7678 7679 7684 7686 7684 7679 8467 7686 7679 7679 8466 8467 7679 7680 8466 7680 9260 10213 7680 7681 9260 9256 8466 7680 9262 9256 7680 10213 9262 7680 9261 9260 7681 7681 7682 9261 7683 7684 7689 8469 7689 7684 7684 8468 8469 7684 7685 8468 7686 7685 7684 9258 8468 7685 9259 9258 7685 7685 8467 9259 7685 7686 8467 8477 7691 7688 7688 7690 8477 8474 7690 7689 7689 8472 8474 7689 8469 8472 7690 8474 8477 9289 7693 7692 9269 8473 7693 9289 9269 7693 7696 7695 7694 8477 7696 7694 7695 7697 7698 7695 7696 7697 8478 7697 7696 8479 8478 7696 9291 8479 7696 7696 8477 9291 9302 7698 7697 7697 9299 9302 7697 8478 9299 7711 7702 7699 7699 7710 7711 7700 7709 8492 7700 7705 7709 7700 7701 7705 7701 7702 7711 7706 7705 7701 7707 7706 7701 7711 7707 7701 7703 7708 8504 8504 7704 7703 8504 8502 7704 9306 7709 7705 7705 8498 9306 7705 7706 8498 9312 8492 7709 7709 9306 9312 7710 7713 7721 7716 7713 7712 7717 7716 7712 8501 7721 7713 7713 7716 8501 8499 7715 7714 9335 8499 7714 7714 7718 9335 9314 8500 7715 7715 8499 9314 8500 8498 7715 9315 7720 7716 7716 7717 9315 7717 8532 9315 7718 9321 9335 7718 7719 9321 9341 9321 7719 7719 7729 9341 8532 7731 7720 9315 8532 7720 7722 7723 8526 7723 7725 8526 9347 8535 7724 9348 9347 7724 7724 9336 9348 7724 8527 9336 8531 8526 7725 8543 8531 7725 7725 7727 8543 7726 7728 7729 7730 7728 7726 9363 8543 7727 8575 7729 7728 7728 8548 8575 7728 7730 8548 9346 9341 7729 7729 8575 9346 7730 7733 8548 8532 8526 7731 7732 7737 7742 7733 7734 8548 7734 7744 8548 8584 8563 7735 7735 7746 8584 8557 7741 7736 7756 7742 7737 7737 7755 7756 8577 7755 7737 7740 7739 7738 8563 7740 7738 8576 7806 7740 8584 8576 7740 7740 8563 8584 7756 7755 7741 8557 7756 7741 7742 7756 8557 8578 7749 7743 7743 8558 8578 9370 8548 7744 7744 7773 9370 8576 7746 7745 7745 7753 8576 7754 7753 7745 7746 8576 8584 7747 7757 8577 8579 7750 7749 7749 8578 8579 8554 7752 7751 8560 8554 7751 7752 8547 8573 8554 8547 7752 7753 7799 8611 7753 7754 7799 7753 7806 8576 8577 7757 7755 9388 8596 7758 7758 8585 9388 7778 7777 7759 8564 7778 7759 8565 8564 7759 8598 8565 7759 8609 8598 7759 7759 7792 8609 7777 7760 7759 8567 7779 7760 7760 8566 8567 7760 7777 8566 9377 7782 7761 7761 7762 9377 7762 8586 9377 7762 7779 8586 8599 8560 7763 7763 7783 8599 7764 7767 7768 7766 7765 7764 8590 7766 7764 9380 8590 7764 7764 8591 9380 7764 7768 8591 7765 7769 7788 7765 7766 7769 8590 7769 7766 7795 7768 7767 7795 7787 7768 9392 8591 7768 7768 7785 9392 7787 7785 7768 7796 7788 7769 7769 7770 7796 7771 7770 7769 8590 7771 7769 8593 8592 7770 8594 8593 7770 7770 7771 8594 8592 7796 7770 9382 8594 7771 7771 9381 9382 7771 8590 9381 9384 7773 7772 10328 9384 7772 7772 7774 10328 9384 9370 7773 7774 10327 10328 7774 9385 10327 7774 7775 9385 10327 9385 7775 7775 9399 10327 7777 7778 8566 8569 8566 7778 7778 8564 8569 7779 8571 8586 7779 8567 8571 7782 7781 7780 8599 7783 7781 7781 7782 8599 8601 8599 7782 9378 8601 7782 7782 9377 9378 7794 7793 7784 8602 7794 7784 8603 8602 7784 7785 7786 10324 7787 7786 7785 9393 9392 7785 10324 9393 7785 10335 10324 7786 7786 9398 10335 7786 7787 9398 7787 7802 9398 7787 7795 7802 7788 7796 7797 7859 7790 7789 7789 7800 7859 7789 7799 7800 8595 7799 7789 8616 7800 7791 8618 8616 7791 7791 7807 8618 7812 7811 7793 7793 7794 7812 9404 7812 7794 7794 8589 9404 8610 8589 7794 7794 8602 8610 7798 7797 7796 8592 7798 7796 7797 7798 7804 8614 7804 7798 9395 8614 7798 7798 8593 9395 7798 8592 8593 7799 8595 8611 8616 7859 7800 7802 7803 9398 7803 9397 9398 7803 8622 9397 7820 7814 7804 8614 7820 7804 7805 8608 9399 7807 7858 8618 8626 7858 7807 7807 7825 8626 9406 7816 7808 7808 9405 9406 7808 7809 9405 7809 8612 9405 7810 7815 8627 7816 7815 7810 7811 7833 7834 8620 7833 7811 7811 7812 8620 9404 8620 7812 7813 7814 7818 7821 7818 7814 7814 7820 7821 9416 8627 7815 7815 7816 9416 9418 9416 7816 7816 9406 9418 7817 7834 8631 7836 7819 7818 7818 7821 7836 7855 7840 7819 7819 7836 7855 9415 7821 7820 7820 8623 9415 8624 8623 7820 7820 8614 8624 9417 7836 7821 7821 9415 9417 7822 7823 8607 8647 7868 7824 8670 8647 7824 7824 8634 8670 8650 7873 7826 7826 8632 8650 7827 7837 8628 7827 7831 7837 8628 7828 7827 7828 9421 9433 7828 8628 9421 9420 9419 7828 9433 9420 7828 8633 8630 7830 7830 7838 8633 8629 7837 7831 7834 7833 7832 8631 7834 7832 10355 8631 7832 7832 10347 10355 7832 9414 10347 7832 8620 9414 7832 7833 8620 7835 7839 9426 9417 7856 7836 7856 7855 7836 8629 8628 7837 9434 8633 7838 7838 8631 9434 9445 9426 7839 7839 8646 9445 7886 7853 7840 7840 7855 7886 8637 7843 7841 7841 8636 8637 8651 8636 7841 7841 7842 8651 8652 8651 7842 8639 7844 7843 7843 8637 8639 8639 8638 7844 7845 7848 7860 7845 7846 7848 7847 7846 7845 8640 7848 7846 7846 7847 8640 8655 8640 7847 8640 7860 7848 7849 7852 7862 7849 7850 7852 7851 7850 7849 8645 7852 7850 7850 7851 8645 7851 7861 8645 8657 7862 7852 7852 8645 8657 7877 7854 7853 8659 7877 7853 7853 7886 8659 7854 7875 7876 7877 7875 7854 10378 7886 7855 7855 9435 10378 7855 7856 9435 7856 9417 9435 7858 8617 8618 7858 7859 8617 8626 8625 7858 7859 8616 8617 8656 7861 7860 7860 8641 8656 8643 8641 7860 8655 8643 7860 7860 8640 8655 8657 8645 7861 7861 8656 8657 7862 8657 8658 7863 7865 7885 8646 7865 7863 9445 8646 7863 9456 9445 7863 9462 9456 7863 7863 7864 9462 9463 9462 7864 10395 9463 7864 11423 10395 7864 7864 9454 11423 9440 8666 7867 7867 9439 9440 9457 9439 7867 7867 8667 9457 7867 7878 8667 7879 7878 7867 8647 7869 7868 8663 7881 7869 7869 8647 8663 8650 8649 7871 7871 7872 8650 7872 7873 8650 7874 7884 7885 7874 7883 7884 7888 7876 7875 7898 7888 7875 7899 7898 7875 7917 7899 7875 8671 7917 7875 7875 8665 8671 7875 7877 8665 7888 7883 7876 7877 8659 8665 7878 7879 7900 8668 8667 7878 7878 7900 8668 7879 7889 7900 7880 8666 9437 7881 8663 8675 7897 7884 7883 7883 7888 7897 7891 7885 7884 7892 7891 7884 7897 7892 7884 10377 8659 7886 10378 10377 7886 7888 7895 7897 7898 7895 7888 7908 7900 7889 10414 7902 7890 7890 9468 10414 7890 8675 9468 8681 7904 7892 7892 7897 8681 7894 7898 7905 7894 7895 7898 7896 7895 7894 7905 7896 7894 7895 7896 7897 8681 7897 7896 7896 7913 8681 7916 7913 7896 7924 7916 7896 8687 7924 7896 7896 7905 8687 7898 7899 7905 7906 7905 7899 7917 7906 7899 8673 8668 7900 8674 8673 7900 7900 7908 8674 7901 7902 7920 7902 10414 10436 7936 7920 7902 10435 7936 7902 10436 10435 7902 7903 7910 7911 8681 7913 7904 9479 8687 7905 9480 9479 7905 7905 8682 9480 7905 7906 8682 7906 8672 8682 7906 7917 8672 7909 7908 7907 8686 7909 7907 9475 8686 7907 7907 9474 9475 7907 7918 9474 7908 7909 8674 9476 8674 7909 9477 9476 7909 7909 8686 9477 8664 7911 7910 10416 8664 7910 7910 9485 10416 7910 7921 9485 8676 8661 7912 7915 7914 7913 7916 7915 7913 7914 7915 7922 7934 7922 7915 7915 7923 7934 7915 7916 7923 7924 7923 7916 7917 8671 8672 7918 8688 9474 8689 8688 7918 7918 7919 8689 9493 9486 7921 7921 7937 9493 8694 7937 7921 9486 9485 7921 7933 7931 7922 7942 7933 7922 7922 7934 7942 8687 7934 7923 7923 7924 8687 9490 8690 7926 7926 7927 9490 7927 8696 9490 8698 8696 7927 8699 7938 7928 7928 7929 8699 7930 7929 7928 7938 7930 7928 8700 8699 7929 8707 8700 7929 7929 7939 8707 7929 7930 7939 7946 7939 7930 7930 7938 7946 7944 7932 7931 7931 7943 7944 7931 7933 7943 7933 7941 7943 7942 7941 7933 8701 7942 7934 8702 8701 7934 7934 8691 8702 7934 8687 8691 8718 8704 7935 7935 7936 8718 10435 8718 7936 8709 7946 7938 9492 8709 7938 7938 8699 9492 7939 7948 8707 7950 7943 7941 7951 7950 7941 7941 7942 7951 8701 7951 7942 7950 7944 7943 7950 7949 7944 7945 7970 8689 7945 7953 7970 7959 7947 7946 8710 7959 7946 7946 8709 8710 7959 7958 7947 8732 8711 7948 7948 8720 8732 8711 8707 7948 7949 7950 8722 8722 7975 7949 7950 7951 8722 7951 8714 8722 8715 8714 7951 7951 8702 8715 7951 8701 8702 7969 7968 7952 7952 7966 7969 8729 7970 7953 8730 7973 7954 7954 8703 8730 8719 7960 7958 7958 8710 8719 7958 7959 8710 8731 7981 7960 7960 8719 8731 8721 8713 7961 7961 7963 8721 7961 7962 7963 8733 8721 7963 7963 7974 8733 7967 7966 7965 8725 7967 7965 8738 7969 7966 7966 7967 8738 7967 8728 8738 7967 8727 8728 7967 8725 8727 8741 7978 7968 7968 8738 8741 7968 7969 8738 7970 8688 8689 7970 7971 8688 7972 7971 7970 8717 7972 7970 8729 8717 7970 11481 8688 7971 7971 7972 11481 7972 10464 11481 7972 8717 10464 8730 7980 7973 9516 8733 7974 9517 9516 7974 7975 8746 9520 7975 8735 8746 7975 8722 8735 7976 8736 8737 7976 7984 8736 7976 7977 7984 8741 7979 7978 9508 7983 7980 7980 9507 9508 7980 8730 9507 8731 7988 7981 8752 8751 7982 7982 8742 8752 9525 8754 7983 7983 9508 9525 8760 8736 7984 7984 7990 8760 8792 8775 7985 8793 8792 7985 9559 8793 7985 7985 8758 9559 8775 8008 7985 7986 7991 8753 8754 7991 7987 9515 9514 7988 7988 8731 9515 9514 7989 7988 9527 7994 7989 7989 9514 9527 7990 7995 8760 7997 7995 7990 8754 8753 7991 7993 7994 8011 8769 8011 7994 9527 8769 7994 7995 8757 8760 9558 8757 7995 7995 9557 9558 7995 7996 9557 7997 7996 7995 7996 8773 9557 7996 7997 8773 10531 10521 7998 7998 7999 10531 8000 7999 7998 11538 10531 7999 7999 9599 11538 9600 9599 7999 7999 8000 9600 8000 9588 9600 8000 8767 9588 8768 8767 8001 8001 8003 8768 8001 8002 8003 8789 8768 8003 8003 8004 8789 8795 8789 8004 8004 8005 8006 8007 8006 8005 8805 8804 8007 9603 8805 8007 9605 9603 8007 8007 8012 9605 8007 8011 8012 8807 8791 8008 9582 8807 8008 8008 8775 9582 8009 8013 8796 8791 8014 8010 9563 8012 8011 9574 9563 8011 8011 9537 9574 10502 9537 8011 8011 8769 10502 8012 9577 9605 8012 9575 9577 8012 9563 9575 8812 8796 8013 9626 8015 8014 8014 8808 9626 8014 8807 8808 8014 8791 8807 9626 8819 8015 8826 8820 8017 8018 8810 8818 8018 8019 8810 9629 8810 8019 8019 8028 9629 8022 8823 8824 8022 8822 8823 9631 8028 8023 8023 8035 9631 8023 8032 8035 8023 8030 8032 8024 8025 9633 8026 8025 8024 10599 9633 8025 8025 10596 10599 8025 8026 10596 8026 8830 10596 8026 8825 8830 8026 8819 8825 9631 9629 8028 8029 8835 8837 8042 8032 8030 8030 8031 8042 8043 8042 8031 8831 8043 8031 8832 8831 8031 8031 8824 8832 10597 8035 8032 8032 8842 10597 8848 8842 8032 8032 8033 8848 8034 8033 8032 8042 8034 8032 8033 8034 8043 8033 8847 8848 8033 8043 8847 8034 8042 8043 10592 9631 8035 10597 10592 8035 9656 8063 8037 10608 9656 8037 8037 8038 10608 8038 10600 10608 8038 10598 10600 8038 9633 10598 8834 8833 8039 8836 8834 8039 8039 8047 8836 8049 8047 8039 8039 8040 8049 8040 8044 8049 8041 8838 10588 8839 8838 8041 8846 8839 8041 8041 8046 8846 8043 8831 8847 8044 8045 8049 8045 8048 8049 8054 8048 8045 8854 8846 8046 8047 8048 8050 8049 8048 8047 8849 8836 8047 8047 8845 8849 8047 8051 8845 8047 8050 8051 8054 8050 8048 8052 8051 8050 8054 8052 8050 8051 8061 8845 8051 8060 8061 8066 8060 8051 8051 8052 8066 8052 8059 8066 8052 8054 8059 8065 8059 8054 8054 8057 8065 9640 8062 8055 9642 9640 8055 8055 8853 9642 8056 8064 8068 8073 8065 8057 8079 8073 8057 8080 8079 8057 8057 8058 8080 8087 8080 8058 8058 8077 8087 8059 8065 8066 8060 9657 9658 8060 8856 9657 8060 8066 8856 9658 8061 8060 9646 8845 8061 9658 9646 8061 9640 8067 8062 9656 9653 8063 8071 8068 8064 8856 8066 8065 8065 8078 8856 8065 8073 8078 8067 9662 9663 8067 9641 9662 8067 9640 9641 8068 8069 8858 8070 8069 8068 8071 8070 8068 9649 8858 8069 10631 9649 8069 10635 10631 8069 8069 8857 10635 8069 8070 8857 10646 8857 8070 8070 8876 10646 8070 8865 8876 8866 8865 8070 8070 8859 8866 8070 8071 8859 8071 8075 8859 8091 8086 8072 8072 8085 8091 8072 8084 8085 8079 8078 8073 9663 8089 8074 8075 8076 8859 8076 8081 8859 8088 8087 8077 8077 8086 8088 8868 8856 8078 8078 8079 8868 8079 8080 8087 8079 8860 8868 8861 8860 8079 8871 8861 8079 8079 8087 8871 9667 8083 8082 10626 9667 8082 8082 9664 10626 8082 8855 9664 8106 8084 8083 9667 8106 8083 8106 8085 8084 8107 8091 8085 8085 8106 8107 8092 8088 8086 8086 8091 8092 8879 8871 8087 8087 8088 8879 8889 8879 8088 8891 8889 8088 8088 8092 8891 9675 8873 8089 8089 9666 9675 8089 9663 9666 8867 8865 8090 8090 8116 8867 8108 8092 8091 8091 8107 8108 8892 8891 8092 8092 8108 8892 8882 8094 8093 10675 8882 8093 8093 8127 10675 8093 8121 8127 8098 8095 8094 8882 8098 8094 8099 8096 8095 8101 8099 8095 8874 8101 8095 9676 8874 8095 8095 8100 9676 8095 8097 8100 8098 8097 8095 8096 8099 8109 10670 8100 8097 8097 8098 10670 8098 9690 10670 8098 8882 9690 8110 8109 8099 8099 8101 8110 12573 9676 8100 13419 12573 8100 8100 10670 13419 9678 8102 8101 8101 8874 9678 8102 9678 9680 9681 8104 8103 8103 9677 9681 8885 8105 8104 9681 8885 8104 8886 8111 8105 8105 8885 8886 8869 8107 8106 8877 8869 8106 9667 8877 8106 8870 8108 8107 8107 8869 8870 8108 8870 8899 8920 8892 8108 9709 8920 8108 8108 8899 9709 8126 8120 8109 8136 8126 8109 8109 8110 8136 8898 8897 8110 8908 8898 8110 8110 8122 8908 8897 8136 8110 8113 8112 8111 8114 8113 8111 8886 8114 8111 8129 8128 8112 8886 8115 8114 8885 8116 8115 8886 8885 8115 8875 8867 8116 8885 8875 8116 8117 8124 8125 8881 8124 8117 8117 8118 8881 9697 8881 8118 9699 9697 8118 8118 9695 9699 8118 8896 9695 8131 8121 8119 8119 8126 8131 8119 8120 8126 8903 8127 8121 8121 8131 8903 8122 8128 8908 8123 8872 8880 8902 8125 8124 9701 8902 8124 8124 9689 9701 8124 8881 9689 8902 8130 8125 8135 8131 8126 8906 8135 8126 8126 8136 8906 8127 9724 10675 9725 9724 8127 8127 8903 9725 8910 8908 8128 8130 8902 8923 8131 8133 8903 8131 8132 8133 8139 8132 8131 8131 8135 8139 8132 8139 8144 8134 8133 8132 8144 8134 8132 8178 8163 8133 8133 8134 8178 8904 8903 8133 8133 8163 8904 8134 8165 8178 8134 8144 8165 8925 8924 8135 8135 8905 8925 8906 8905 8135 8146 8139 8135 8924 8146 8135 8136 8897 8906 8930 8918 8138 8146 8144 8139 8919 8911 8140 8140 8166 8919 8140 8151 8166 8152 8151 8140 8144 8146 8165 8148 8147 8145 8150 8148 8145 8935 8150 8145 8145 8924 8935 8145 8146 8924 8147 8146 8145 8146 8147 8165 8147 8148 8933 8934 8165 8147 8147 8933 8934 9748 8933 8148 8148 8149 9748 8150 8149 8148 8149 8955 9748 9755 8955 8149 8149 9744 9755 8149 8150 9744 10703 9744 8150 8150 8935 10703 8943 8166 8151 8151 8155 8943 8151 8152 8155 8152 8154 8155 8155 8154 8153 8944 8155 8153 8153 8169 8944 8170 8169 8153 8153 8167 8170 8944 8943 8155 8156 8159 8938 8156 8157 8159 8157 8158 8159 8160 8159 8158 8168 8160 8158 8939 8938 8159 8159 8160 8939 8940 8939 8160 8160 8168 8940 8163 8164 8904 8164 8903 8904 9716 8903 8164 8164 8923 9716 8934 8178 8165 8929 8919 8166 8937 8929 8166 10704 8937 8166 8166 9749 10704 8166 8943 9749 8173 8170 8167 8942 8940 8168 8168 8941 8942 8168 8174 8941 9764 8944 8169 9765 9764 8169 8169 8171 9765 8169 8170 8171 8949 8171 8170 8170 8173 8949 10711 9765 8171 10727 10711 8171 10729 10727 8171 8171 10723 10729 8171 8949 10723 8172 8945 9751 8172 8938 8945 9773 8949 8173 8174 8180 8941 8951 8950 8175 9742 8951 8175 8175 8176 9742 8181 8177 8175 8950 8181 8175 8180 8196 8941 8950 8182 8181 8973 8198 8182 9774 8973 8182 9775 9774 8182 8182 8950 9775 8183 8184 8185 8186 8185 8184 8961 8186 8184 8188 8187 8185 8185 8186 8188 9781 8188 8186 8186 8961 9781 9780 8966 8187 9781 9780 8187 8187 8188 9781 8189 8190 8957 9782 8957 8190 8958 8214 8191 8192 8193 8196 8195 8193 8192 8953 8196 8193 8954 8953 8193 8193 8194 8954 8195 8194 8193 9783 8954 8194 9784 9783 8194 9801 9784 8194 8194 8969 9801 8194 8195 8969 8953 8941 8196 8197 8207 8209 8208 8207 8197 8217 8208 8197 8973 8218 8198 8199 8931 8932 8200 8210 8212 8211 8210 8200 8965 8961 8201 8201 8213 8965 8227 8205 8203 8962 8227 8203 8216 8215 8204 8229 8216 8204 8204 8205 8229 8205 8228 8229 8205 8227 8228 8206 8972 9795 8206 8207 8972 8209 8207 8206 8982 8972 8207 8207 8208 8982 9811 8982 8208 8208 8970 9811 8971 8970 8208 8208 8232 8971 8208 8217 8232 8963 8212 8210 8964 8963 8210 8210 8960 8964 8210 8211 8960 8211 8948 8960 8211 8932 8948 8226 8225 8212 8238 8226 8212 8963 8238 8212 8213 8239 8965 8967 8962 8214 9793 8967 8214 8214 8958 9793 8981 8230 8216 8216 8229 8981 8218 8973 8974 9767 8952 8219 8219 8959 9767 8983 8975 8220 8220 8221 8983 8222 8221 8220 8221 8245 8983 8221 8235 8245 8221 8222 8235 8245 8235 8223 8223 8224 8245 8225 8224 8223 8224 8244 8245 8224 8226 8244 8224 8225 8226 8226 8238 8244 8977 8228 8227 8227 8967 8977 8227 8962 8967 8978 8229 8228 8228 8977 8978 8229 8979 8981 8980 8979 8229 8229 8978 8980 8981 8968 8230 8231 8247 8248 8989 8971 8232 9834 8989 8233 9836 9834 8233 8233 9812 9836 8233 8234 9812 8234 8241 9812 9816 8990 8236 9826 9816 8236 8236 8237 9826 8238 8237 8236 8990 8238 8236 10770 9826 8237 11768 10770 8237 8237 8987 11768 8237 8238 8987 8990 8244 8238 9797 8987 8238 8238 8964 9797 8238 8963 8964 9785 8965 8239 9786 9785 8239 9817 9786 8239 9813 9812 8241 8241 8992 9813 8994 8251 8242 8242 8243 8994 8243 8974 8994 8990 8245 8244 8985 8983 8245 8990 8985 8245 8997 8991 8247 9839 8997 8247 8247 9818 9839 8247 8988 9818 8991 8248 8247 8991 8249 8248 8275 8256 8249 8991 8275 8249 8998 8993 8250 8250 8254 8998 9823 9002 8251 8251 9822 9823 8251 8994 9822 8252 8255 8260 8252 8271 9012 8252 8260 8271 8254 8269 8998 8256 8275 8276 9020 9004 8257 8257 9009 9020 11801 9850 8258 12715 11801 8258 12716 12715 8258 8258 8259 12716 12717 12716 8259 8259 11802 12717 8259 9845 11802 8260 8261 8271 9838 8271 8261 9846 9838 8261 9851 9846 8261 8261 8278 9851 8280 8273 8262 8283 8280 8262 8262 8282 8283 9013 8282 8262 8263 8995 8996 8264 8265 8270 8266 8265 8264 8290 8266 8264 8265 8268 8270 9005 8268 8265 8265 8266 9005 9019 9005 8266 8266 9018 9019 8266 8296 9018 8266 8290 8296 8999 8998 8267 8267 8268 8999 8269 8268 8267 8998 8269 8267 9007 8999 8268 8268 9006 9007 8268 9005 9006 8268 8269 8270 9838 9012 8271 8280 8279 8272 8272 8273 8280 8274 8281 8282 8284 8281 8274 8277 8276 8275 8991 8277 8275 9830 9014 8276 8276 8286 9830 8276 8277 8286 8997 8286 8277 8277 8991 8997 9853 9851 8278 9855 9853 8278 8278 8300 9855 8279 8280 8283 9025 8301 8279 9030 9025 8279 8283 8282 8281 9831 9830 8286 9839 9831 8286 8286 8997 9839 10803 9026 8287 8287 8288 10803 8289 8288 8287 11806 10803 8288 8288 10792 11806 8288 10791 10792 8288 8289 10791 8289 9014 10782 8289 10782 10791 8290 8291 8296 8292 8291 8290 8291 8292 9034 8293 9028 9029 8293 9027 9028 8293 8294 9027 8295 8294 8293 8296 8295 8293 9018 8296 8293 9029 9018 8293 8294 9016 9027 9041 9016 8294 8294 8310 9041 8294 8309 8310 8294 8295 8309 8295 8302 8309 8297 8314 8319 8298 9024 9035 9035 8299 8298 9046 8303 8299 8299 9035 9046 8300 9039 9855 8300 9038 9039 9031 8307 8301 8301 9025 9031 8310 8309 8302 8328 8310 8302 8302 8326 8328 9045 8315 8303 9046 9045 8303 8304 8305 8306 9036 8306 8305 8305 8316 9036 8317 8308 8307 9033 8317 8307 8307 9031 9033 8308 8318 8324 8308 8317 8318 9042 9041 8310 8310 8328 9042 8311 9043 9044 9867 9043 8311 8311 9856 9867 9857 9856 8311 8311 8312 9857 9034 8312 8311 8312 8313 9857 8313 9868 9879 8313 8319 9868 9879 9857 8313 9049 8319 8314 9050 9049 8314 8314 8320 9050 9053 8320 8315 8315 9051 9053 8315 9045 9051 8318 8323 8324 8319 9049 9868 9054 9050 8320 9056 9054 8320 8320 9053 9056 8321 9047 9048 9060 9047 8321 8321 8322 9060 9064 9060 8322 8322 8336 9064 8327 8326 8325 8333 8327 8325 8326 8327 8328 8327 9864 9866 8327 9067 9864 8327 8333 9067 9042 8328 8327 9866 9042 8327 9063 8334 8329 8329 9062 9063 8329 8330 9062 9044 9043 8330 9897 9062 8330 8330 9887 9897 8330 9867 9887 8330 9043 9867 8333 8341 9067 9063 8335 8334 9063 8342 8335 9073 9064 8336 8336 8337 9073 8337 8343 9073 8353 8346 8338 8354 8353 8338 8340 8339 8338 8346 8340 8338 9069 8341 8339 8339 8340 9069 9894 9069 8340 8340 9893 9894 8340 8346 9893 9069 9067 8341 9910 9901 8342 9911 9910 8342 8342 9899 9911 8342 9063 9899 9918 9073 8343 8343 9084 9918 8343 8347 9084 8344 8345 8351 8352 8351 8345 9914 8352 8345 8345 9895 9914 8345 9068 9895 9925 9915 8346 8346 8353 9925 9915 9893 8346 8347 8364 9084 8347 8348 8364 8348 8363 8364 8349 8355 9075 8349 8350 8355 9920 8355 8350 8350 8360 9920 9913 8362 8352 9914 9913 8352 8353 9079 9925 8353 8372 9079 8353 8354 8372 9921 9075 8355 8355 9920 9921 8377 8375 8356 9095 8377 8356 8356 9087 9095 8356 9071 9087 9916 9072 8357 8357 9070 9916 9924 8359 8358 8358 9074 9924 9924 9086 8359 8360 9077 9920 9922 8371 8361 8361 8362 9922 8362 9913 9922 8365 8364 8363 9088 8365 8363 8363 8366 9088 10850 9084 8364 8364 10849 10850 8364 8365 10849 10864 10849 8365 10865 10864 8365 8365 9090 10865 8365 9088 9090 8367 8368 9089 9091 9090 8367 8367 9089 9091 8368 8369 9092 8370 8369 8368 9092 9089 8368 9922 9078 8371 9081 9079 8372 9096 9081 8372 8372 8384 9096 8372 8373 8384 10856 9082 8374 8374 9917 10856 8374 9072 9917 8377 8376 8375 8375 8376 8383 9094 8383 8376 8376 8377 9094 9095 9094 8377 9102 8379 8378 9103 9102 8378 8378 9097 9103 8379 9102 9107 9104 9101 8380 8380 8393 9104 9111 8382 8381 9937 9093 8382 9944 9937 8382 8382 9111 9944 8383 9094 9095 9105 8390 8386 8389 9080 9081 9941 9080 8389 9116 8391 8390 8390 9106 9116 8390 9105 9106 8391 9116 9123 8391 9123 9124 9119 8393 8392 9957 9119 8392 8392 9127 9957 9108 9104 8393 9115 9108 8393 9119 9115 8393 8394 8395 9117 8396 8395 8394 9955 8396 8394 10926 9955 8394 10927 10926 8394 10928 10927 8394 10929 10928 8394 8394 9953 10929 8394 9117 9118 9142 9141 8395 8395 8396 9142 10971 9142 8396 8396 10945 10971 8396 9955 10945 9174 8409 8397 8397 9164 9174 8397 8413 9164 8398 8399 8406 8400 8399 8398 8401 8400 8398 8399 8405 8406 9131 8405 8399 9963 9131 8399 8399 8400 9963 8400 9134 9963 8400 9132 9134 9133 9132 8400 8400 8401 9133 9137 9133 8401 9148 8404 8402 9965 9148 8402 8402 9962 9965 8402 8403 9962 8403 9124 9962 9126 9124 8403 9148 9135 8404 8405 9131 9153 9149 8408 8407 9991 9147 8409 8409 9163 9991 9174 9163 8409 9156 8425 8412 8412 9135 9156 9175 9164 8413 8415 9166 9169 8415 8416 9166 9169 8417 8415 8416 9146 9166 8417 8418 8421 8419 8418 8417 9169 8419 8417 8418 8420 8421 8423 8420 8418 8418 8419 8423 9987 9170 8419 8419 9166 9987 9169 9166 8419 9170 8423 8419 8423 8422 8420 9159 8435 8422 9170 9159 8422 8422 8423 9170 9181 8442 8424 8424 8428 9181 8424 8425 8428 10001 8428 8425 8425 9994 10001 8425 9985 9994 8425 9970 9985 8425 9156 9970 8440 8427 8426 8440 8439 8427 10007 9181 8428 8428 10001 10007 9179 9177 8429 9182 9179 8429 9184 9182 8429 9177 8430 8429 9165 9150 8430 8430 9157 9165 9158 9157 8430 9996 9158 8430 8430 9178 9996 8430 9177 9178 9187 8436 8431 8431 9180 9187 8434 8433 8432 9171 8434 8432 8432 9160 9171 8432 8435 9160 8433 8434 9992 8433 9992 9997 11016 9992 8434 8434 9990 11016 8434 9171 9990 8435 9159 9160 9187 9186 8436 8437 8438 8449 8439 8438 8437 8445 8439 8437 9189 8445 8437 11059 9189 8437 8437 9204 11059 8437 8449 9204 8438 8439 8444 8439 8440 8444 8439 8445 9176 8441 8443 9191 8441 8442 8443 9181 8443 8442 10009 9192 8443 8443 9190 10009 8443 9181 9190 11032 9176 8445 8445 10005 11032 8445 9189 10005 8447 8448 9192 9194 8450 8447 8447 9192 9194 8449 9203 9204 8449 8454 9203 9198 8457 8450 8450 9195 9198 8450 9194 9195 8451 8452 8455 8453 8452 8451 10014 8455 8452 10036 10014 8452 8452 9208 10036 8452 8453 9208 9206 9203 8454 10014 9199 8455 10036 9208 8456 10037 10036 8456 10038 10037 8456 9211 8459 8457 9214 9211 8457 8457 9213 9214 8457 9198 9213 9211 8461 8458 8458 8459 9211 8460 8461 9211 8460 9211 9216 9231 8463 8462 8462 9219 9231 9232 9219 8462 9241 9232 8462 8463 9207 9212 9215 9207 8463 9231 9215 8463 8464 8465 9242 8465 9233 10073 8465 9218 9233 10078 9242 8465 8465 10073 10078 9256 8467 8466 8467 9257 9259 8467 9256 9257 9266 8469 8468 8468 9258 9266 8469 8470 8472 8471 8470 8469 9266 8471 8469 8475 8472 8470 9282 8475 8470 11248 9282 8470 8470 8471 11248 8471 10212 11248 10214 10212 8471 8471 9266 10214 8475 8474 8472 9269 8476 8473 8474 8475 8477 9270 8477 8475 9282 9270 8475 9265 9264 8476 10215 9265 8476 8476 9268 10215 8476 9267 9268 9269 9267 8476 8477 9270 9291 10237 9299 8478 8478 8479 10237 8479 10224 10237 8479 9291 10224 8495 8487 8480 8480 8494 8495 8480 8488 8494 8480 8483 8488 8480 8481 8483 8482 8481 8480 8487 8482 8480 8481 9286 10226 8481 8482 9286 8485 8483 8481 9294 8485 8481 10226 9294 8481 10258 9286 8482 8482 9304 10258 8482 8487 9304 8483 8486 8488 8483 8484 8486 8485 8484 8483 8491 8486 8484 8484 8490 8491 8484 8489 8490 9274 8489 8484 8484 8485 9274 9277 9274 8485 8485 9271 9277 9284 9271 8485 9294 9284 8485 8491 8488 8486 9305 9304 8487 9308 9305 8487 8487 8495 9308 8496 8494 8488 8488 8491 8496 9278 8490 8489 8489 9275 9278 8489 9274 9275 9287 8491 8490 9288 9287 8490 10221 9288 8490 8490 9285 10221 8490 9278 9285 8511 8496 8491 9300 8511 8491 8491 9287 9300 10242 9290 8492 8492 9312 10242 8495 8494 8493 8497 8495 8493 8493 8496 8497 8493 8494 8496 8495 8497 9308 8507 8497 8496 8511 8507 8496 9313 9308 8497 8497 8507 9313 9309 9306 8498 8498 8500 9309 10269 9314 8499 10270 10269 8499 8499 9335 10270 9314 9309 8500 8502 8503 8512 8504 8503 8502 9322 8512 8503 10272 9322 8503 11292 10272 8503 8503 11291 11292 8503 10261 11291 8503 8504 10261 8504 10256 10261 10257 10256 8504 8504 10255 10257 8504 9307 10255 9313 8507 8505 9316 9313 8505 8505 8514 9316 8505 8513 8514 8505 8506 8513 8507 8506 8505 8506 8508 8513 8506 8507 8508 8519 8508 8507 8507 8511 8519 8516 8513 8508 8517 8516 8508 8519 8517 8508 9320 9317 8509 10241 9320 8509 8509 8510 10241 8511 8510 8509 9317 8511 8509 8510 10238 10241 8510 9301 10238 8510 9300 9301 8510 8511 9300 9317 8519 8511 9322 8520 8512 8515 8514 8513 8516 8515 8513 10267 9316 8514 10273 10267 8514 8514 8515 10273 10280 10273 8515 8515 9337 10280 8515 9323 9337 8515 8516 9323 8516 8521 9323 8516 8518 8521 8516 8517 8518 8525 8518 8517 8517 8524 8525 8517 8519 8524 8528 8521 8518 8529 8528 8518 8518 8525 8529 9318 8524 8519 8519 9317 9318 9336 8527 8520 8520 9322 9336 8521 8522 9323 8523 8522 8521 8528 8523 8521 9349 9323 8522 9367 9349 8522 8522 9351 9367 8522 8523 9351 8523 9342 9351 8523 8533 9342 8523 8528 8533 8534 8525 8524 9338 8534 8524 8524 9319 9338 8524 9318 9319 8530 8529 8525 8534 8530 8525 8528 8529 8533 8529 8530 8533 8534 8533 8530 8533 8534 9342 9343 9342 8534 9344 9343 8534 8534 9338 9344 9357 8549 8535 8535 9347 9357 9328 9326 8536 9354 9328 8536 8536 8544 9354 8536 8537 8544 8538 8537 8536 9326 8538 8536 8545 8544 8537 8554 8545 8537 8537 8539 8554 8537 8538 8539 8540 8539 8538 9332 8540 8538 8538 9331 9332 8538 9326 9331 8539 8547 8554 8539 8541 8547 8539 8540 8541 8542 8541 8540 9339 8542 8540 8540 9333 9339 8540 9332 9333 8541 8546 8547 8541 8542 8546 8555 8546 8542 8556 8555 8542 9345 8556 8542 8542 9339 9345 9359 9354 8544 8544 8545 9359 8545 8552 9359 8553 8552 8545 8559 8553 8545 8545 8554 8559 9360 8574 8546 8546 8561 9360 8546 8555 8561 8562 8547 8546 8574 8562 8546 9374 8573 8547 8547 8572 9374 8547 8562 8572 9370 8575 8548 8551 8550 8549 9357 8551 8549 8550 8551 8558 8551 9358 9371 8551 9357 9358 9371 8558 8551 10297 9359 8552 10298 10297 8552 8552 9373 10298 8552 8553 9373 9379 9373 8553 8553 8559 9379 8560 8559 8554 9368 8561 8555 8555 9355 9368 8555 8556 9355 9356 9355 8556 8556 9345 9356 9376 8578 8558 8558 9371 9376 8559 8600 9379 8559 8560 8600 8560 8599 8600 9369 9360 8561 8561 9368 9369 8574 8572 8562 8570 8569 8564 9372 8570 8564 11341 9372 8564 12269 11341 8564 8564 11342 12269 8564 8565 11342 11361 11342 8565 8565 8597 11361 8598 8597 8565 8568 8567 8566 8569 8568 8566 8567 8568 8571 8568 8570 8580 8568 8569 8570 8580 8571 8568 9366 9351 8570 9372 9366 8570 9351 8580 8570 10322 8586 8571 8571 10313 10322 10314 10313 8571 8571 10310 10314 8571 8580 10310 8572 9360 9374 8572 8574 9360 9374 8581 8573 9362 9346 8575 9370 9362 8575 9376 8579 8578 9388 8585 8579 8579 9376 9388 8580 9350 10310 9351 9350 8580 8588 8587 8581 10323 8588 8581 8581 8582 10323 8583 8582 8581 9374 8583 8581 12259 10323 8582 8582 11335 12259 8582 8583 11335 8583 9375 11335 8583 9374 9375 10322 9378 8586 9378 9377 8586 8587 8589 8603 8587 8588 8589 9391 8589 8588 11362 9391 8588 8588 11353 11362 8588 11352 11353 8588 10323 11352 9396 8603 8589 8589 8610 9396 9410 9404 8589 8589 9391 9410 8590 9380 9381 9394 9380 8591 8591 9393 9394 8591 9392 9393 8593 8605 9395 8606 8605 8593 10325 8606 8593 8593 8594 10325 10326 10325 8594 8594 10319 10326 8594 9382 10319 9400 8612 8596 10329 9400 8596 8596 9376 10329 9388 9376 8596 11370 11361 8597 8597 9413 11370 8597 9401 9413 8597 8598 9401 9402 9401 8598 8598 8609 9402 8601 8600 8599 8600 8601 9379 9389 9379 8601 8601 9378 9389 8602 8604 8610 8602 8603 8604 9396 8604 8603 9396 8610 8604 10332 9395 8605 8605 8606 10332 11354 10332 8606 8606 10325 11354 8615 8608 8607 9428 8615 8607 10334 9399 8608 8608 8615 10334 9403 9402 8609 8612 9400 9405 9407 9403 8613 9408 9407 8613 8613 8619 9408 9395 8624 8614 8615 9428 10334 8618 8617 8616 8619 8621 9408 8620 9404 9414 9419 9408 8621 8623 8624 9412 10339 9415 8623 8623 10336 10339 8623 9412 10336 8624 9395 9412 8625 8626 8634 9432 8632 8627 8627 9416 9432 8628 8629 9421 8629 8630 9423 9424 9421 8629 8629 9423 9424 8630 8633 9425 9425 9423 8630 10355 9434 8631 10366 8650 8632 10367 10366 8632 8632 9446 10367 8632 9432 9446 9434 9425 8633 8634 8635 8670 8635 8648 8670 8636 10368 10373 8636 9447 10368 8636 8651 9447 10373 8637 8636 9449 8639 8637 10373 9449 8637 8662 8654 8638 9450 8662 8638 8638 8653 9450 8638 8639 8653 9449 8653 8639 8641 8642 8644 8643 8642 8641 8641 8644 8656 9443 8644 8642 8642 8643 9443 9452 9443 8643 8643 8655 9452 8644 9443 9452 9452 8656 8644 8670 8663 8647 8649 8650 9467 10380 9467 8650 10382 10380 8650 10383 10382 8650 8650 10366 10383 9448 9447 8651 8651 9442 9448 8651 8652 9442 8652 8660 10372 9441 8660 8652 10372 9442 8652 9459 9450 8653 8653 9449 9459 8662 8655 8654 10374 9452 8655 8655 9460 10374 8655 9451 9460 8655 8662 9451 9453 8657 8656 8656 9452 9453 9454 8658 8657 8657 9453 9454 8685 8665 8659 10412 8685 8659 8659 10388 10412 8659 10377 10388 10384 10372 8660 10385 10384 8660 8660 8661 10385 8661 8676 10385 8662 9450 9451 8663 8669 9469 8670 8669 8663 9466 8675 8663 9469 9466 8663 10416 8679 8664 8685 8671 8665 8666 9429 9437 9438 9429 8666 9440 9438 8666 10389 9457 8667 8667 8673 10389 8667 8668 8673 8669 8670 9458 8678 8672 8671 8683 8678 8671 8685 8683 8671 8672 8678 8682 8673 9464 10389 9465 9464 8673 8673 8674 9465 10413 9465 8674 8674 9476 10413 8675 9466 9468 8676 8677 10426 10403 10385 8676 10426 10403 8676 8677 8690 10426 9482 8682 8678 9484 9482 8678 8678 8683 9484 10401 9469 8679 10416 10401 8679 8680 10437 10448 8680 9487 10437 8708 8695 8680 9494 8708 8680 10447 9494 8680 10448 10447 8680 9481 9480 8682 9482 9481 8682 8683 9483 9484 10406 9483 8683 8683 8684 10406 8685 8684 8683 11461 10406 8684 12375 11461 8684 8684 8685 12375 8685 12365 12375 8685 11462 12365 8685 10412 11462 8686 9476 9477 10413 9476 8686 11453 10413 8686 11454 11453 8686 11464 11454 8686 8686 9475 11464 9479 8691 8687 11473 9474 8688 11482 11473 8688 11483 11482 8688 8688 11481 11483 8690 9490 10426 8715 8702 8691 8691 8692 8715 8693 8692 8691 9479 8693 8691 8723 8715 8692 10440 8723 8692 10441 10440 8692 8692 8693 10441 8693 10433 10441 8693 9480 10433 8693 9479 9480 8708 8706 8695 8706 8705 8695 8696 9488 9490 9489 9488 8696 10438 9489 8696 8696 8697 10438 8697 9494 10447 8697 8708 9494 8697 8706 8708 10447 10438 8697 9497 9492 8699 8699 8700 9497 8700 8707 9497 9499 8730 8703 8703 8704 9499 10461 9499 8704 8704 10443 10461 8704 8718 10443 8707 9495 9497 9496 9495 8707 8707 8711 9496 10449 8710 8709 10450 10449 8709 8709 9492 10450 10452 8719 8710 8710 10449 10452 8711 8732 9496 8732 8720 8712 8712 8721 8732 8712 8713 8721 9498 8722 8714 10460 9498 8714 8714 8715 10460 8715 8723 10460 8716 8717 8729 10477 8717 8716 8716 8747 10477 10476 10464 8717 10477 10476 8717 8718 10435 10443 8719 10451 10462 10452 10451 8719 9515 8731 8719 10468 9515 8719 8719 10462 10468 9505 8732 8721 8721 8733 9505 8722 8734 8735 9498 8734 8722 8723 10454 10460 8723 10440 10454 9506 9500 8724 8724 8736 9506 8737 8736 8724 9500 8725 8724 9500 8727 8725 8728 8727 8726 10463 8728 8726 8726 9506 10463 8726 9500 9506 8726 8727 9500 8739 8738 8728 8740 8739 8728 10463 8740 8728 8730 9501 9507 8730 9499 9501 9504 9496 8732 9505 9504 8732 9516 9505 8733 8748 8735 8734 8749 8748 8734 8750 8749 8734 9498 8750 8734 8748 8746 8735 8736 8756 9506 8757 8756 8736 8760 8757 8736 8738 8739 8741 8742 8741 8739 8744 8742 8739 9521 8744 8739 8739 8740 9521 10483 9521 8740 8740 10473 10483 8740 10463 10473 8742 8743 8752 8744 8743 8742 10484 8752 8743 11500 10484 8743 11501 11500 8743 8743 9521 11501 8743 8744 9521 9513 9511 8745 9526 9513 8745 8745 8755 9526 8746 8748 9520 10486 10477 8747 8747 8753 10486 8748 8749 9520 10497 9520 8749 11521 10497 8749 8749 10498 11521 8749 10470 10498 8749 8750 10470 8750 10469 10470 8750 9498 10469 9530 8758 8751 8751 8752 9530 10484 9530 8752 10487 10486 8753 8753 8754 10487 8754 9531 10487 8754 9525 9531 10490 10489 8755 8755 9534 10490 10478 9526 8755 10489 10478 8755 10482 9506 8756 8756 9533 10482 8756 8757 9533 9558 9533 8757 8758 9543 9559 9544 9543 8758 8758 9530 9544 9560 8764 8761 9570 9560 8761 8761 8780 9570 8761 8779 8780 8761 8778 8779 8761 8762 8778 8763 8762 8761 8764 8763 8761 8762 8765 8778 8762 8763 8765 8766 8765 8763 9547 8766 8763 8763 8764 9547 8764 9546 9547 10517 9546 8764 10525 10517 8764 8764 9560 10525 8765 8777 8778 8784 8777 8765 9561 8784 8765 8765 8766 9561 10519 9561 8766 10520 10519 8766 8766 9545 10520 9547 9545 8766 8767 9573 9588 8767 8789 9573 8767 8768 8789 8769 9527 10502 8770 8771 9615 8772 8771 8770 10570 8772 8770 8770 8811 10570 9615 8811 8770 8771 8796 8812 8771 8772 8796 8771 8812 9615 8772 10543 10544 11547 10543 8772 8772 10570 11547 8772 8790 8796 10544 8790 8772 9569 9557 8773 10542 9569 8773 8774 10545 10551 8774 8792 10545 8774 8775 8792 8776 8775 8774 9618 8776 8774 10551 9618 8774 8775 8776 9582 9617 9582 8776 9618 9617 8776 8782 8778 8777 10557 8782 8777 8777 9606 10557 8777 8784 9606 8782 8779 8778 8782 8780 8779 10538 9570 8780 8780 8781 10538 8782 8781 8780 12450 12449 8781 8781 11553 12450 8781 8782 11553 12449 10538 8781 11554 11553 8782 8782 10557 11554 8783 8787 8794 8783 8786 8787 9561 8786 8783 8783 8784 9561 8785 8784 8783 8794 8785 8783 8784 9592 9606 9593 9592 8784 8784 8798 9593 8784 8785 8798 8785 8797 8798 8785 8794 8797 8788 8787 8786 9561 8788 8786 8797 8794 8787 8799 8797 8787 9553 8799 8787 8787 8788 9553 8788 9549 9553 8788 9548 9549 9561 9548 8788 8789 8801 9573 8789 8795 8801 8792 10536 10545 8792 8793 10536 8793 9559 10536 8795 8800 8801 8799 8798 8797 9619 9593 8798 8798 9595 9619 8798 9594 9595 8798 8799 9594 8799 9584 9594 9585 9584 8799 8799 9571 9585 9572 9571 8799 10553 9572 8799 8799 9552 10553 9553 9552 8799 8802 8801 8800 8806 8802 8800 8800 8803 8806 8801 8802 9573 9602 9573 8802 9612 9602 8802 8802 8806 9612 9613 8806 8803 9614 9613 8803 8804 8805 9614 10579 9614 8805 8805 9604 10579 8805 9591 9604 9603 9591 8805 9613 9612 8806 8807 9582 9616 9616 8808 8807 11580 9626 8808 8808 11568 11580 8808 9616 11568 8809 8810 9629 8811 8810 8809 10591 8811 8809 8809 10590 10591 8809 9629 10590 9615 8818 8810 8810 8811 9615 11574 10570 8811 8811 10591 11574 8812 8818 9615 10586 8817 8813 8813 8821 10586 8816 8815 8814 9624 8816 8814 8814 8817 9624 8832 8823 8815 9627 8832 8815 8815 9625 9627 8815 8816 9625 10587 9625 8816 8816 10567 10587 8816 10566 10567 8816 9624 10566 10564 9624 8817 10586 10564 8817 9626 8825 8819 9630 8829 8820 8820 8826 9630 8821 10582 10586 10588 10582 8821 8832 8824 8823 9626 8830 8825 8826 8827 9630 8827 8833 9630 8828 8829 8835 9632 8835 8829 8829 9630 9632 8830 10593 10595 10594 10593 8830 8830 9626 10594 8830 10595 10596 9638 8847 8831 12510 9638 8831 8831 12504 12510 8831 8840 12504 8841 8840 8831 12493 8841 8831 8831 12478 12493 8831 8832 12478 8832 9627 12478 9632 9630 8833 8833 8834 9632 8834 8851 9632 8834 8836 8851 9635 8837 8835 8835 8851 9635 9632 8851 8835 8836 8850 8851 8836 8849 8850 9635 8852 8837 11583 10588 8838 12492 11583 8838 8838 11607 12492 8838 11596 11607 8838 8839 11596 11607 11596 8839 8839 10605 11607 10607 10605 8839 8839 9652 10607 8839 8854 9652 8839 8846 8854 13357 12504 8840 8840 8841 13357 8841 12483 13357 12493 12483 8841 11594 10597 8842 11608 11594 8842 8842 8843 11608 8844 8843 8842 8848 8844 8842 8843 10620 11608 8843 10614 10620 8843 9645 10614 8843 8844 9645 8844 9638 9645 8844 8847 9638 8848 8847 8844 9637 8849 8845 9646 9637 8845 9637 8850 8849 9634 8851 8850 9637 9634 8850 8851 9634 9635 9639 8853 8852 8852 9635 9639 8853 9639 9642 8855 9661 9664 9665 9657 8856 8856 8864 9665 8868 8864 8856 10637 10635 8857 10647 10637 8857 8857 10646 10647 9649 9648 8858 8860 8864 8868 8860 8863 8864 9684 8863 8860 8860 8893 9684 8860 8861 8893 8861 8890 8893 8861 8879 8890 8861 8871 8879 8864 8863 8862 9668 8864 8862 9684 9668 8862 8862 8863 9684 9668 9665 8864 8865 8875 8876 8865 8867 8875 8878 8870 8869 8869 8877 8878 8870 8878 8899 9686 8880 8872 8872 8873 9686 8873 9675 9686 10658 9678 8874 11691 10658 8874 8874 9676 11691 10673 8876 8875 8875 10671 10673 8875 9703 10671 8875 8885 9703 10647 10646 8876 8876 10637 10647 11693 10637 8876 8876 10673 11693 8887 8878 8877 8888 8887 8877 10648 8888 8877 8877 9667 10648 10677 8899 8878 8878 8887 10677 8879 8889 8890 8880 9686 9694 9721 9720 8880 8880 9694 9721 8881 9687 9689 9688 9687 8881 10655 9688 8881 8881 9698 10655 8881 9697 9698 8882 8883 9690 8884 8883 8882 10675 8884 8882 11706 9690 8883 8883 8884 11706 8884 10682 11706 8884 10681 10682 8884 10675 10681 8885 9691 9703 8885 9683 9691 8885 9681 9683 8887 8888 11695 11715 10677 8887 8887 11707 11715 8887 11695 11707 8888 10648 11695 9710 8890 8889 8889 8915 9710 8889 8912 8915 8889 8891 8912 9710 8893 8890 8913 8912 8891 8914 8913 8891 8891 8892 8914 8921 8914 8892 8892 8920 8921 9692 9684 8893 9719 9692 8893 10692 9719 8893 8893 9711 10692 8893 9710 9711 9695 8895 8894 8894 8901 9695 8894 8900 8901 9695 8896 8895 8907 8906 8897 8897 8898 8907 8908 8907 8898 9718 9709 8899 10690 9718 8899 8899 10677 10690 9706 8901 8900 9714 9706 8900 9699 9695 8901 8901 9696 9699 9707 9696 8901 8901 9705 9707 9706 9705 8901 9708 8923 8902 8902 9701 9708 8903 9716 9725 8926 8925 8905 9717 8926 8905 8905 8907 9717 8905 8906 8907 8907 8909 9717 8907 8908 8909 8910 8909 8908 9729 9717 8909 8909 8910 9729 8910 8928 9729 8929 8928 8910 8910 8919 8929 8910 8911 8919 8917 8915 8912 8912 8913 8917 9733 8917 8913 8913 8914 9733 8914 9732 9733 8914 8921 9732 9711 9710 8915 9713 9711 8915 8915 8916 9713 8917 8916 8915 10700 9713 8916 8916 9740 10700 8916 8917 9740 8917 9739 9740 8917 9733 9739 9723 9722 8918 9734 9723 8918 8918 8930 9734 8922 8921 8920 9726 8922 8920 8920 9709 9726 9737 9732 8921 9738 9737 8921 10705 9738 8921 8921 8922 10705 8922 10699 10705 8922 9726 10699 8923 9708 9716 8924 8927 9735 8924 8925 8927 9736 8935 8924 8924 9735 9736 8925 8926 8927 8926 9729 9730 8926 9717 9729 9735 8927 8926 8926 9730 9735 8928 9760 9761 8928 8936 9760 8937 8936 8928 8928 8929 8937 9731 9729 8928 9761 9731 8928 9743 9734 8930 9747 9743 8930 8955 8932 8931 9748 8955 8931 8931 8933 9748 8956 8948 8932 8932 8955 8956 8935 9736 10703 9762 9760 8936 9763 9762 8936 9772 9763 8936 10704 9772 8936 8936 8937 10704 8938 8939 8945 9746 8945 8939 8939 8940 9746 8940 8942 9746 9746 8942 8941 9750 9746 8941 8941 8953 9750 9764 9749 8943 8943 8944 9764 8945 9750 9751 8945 9746 9750 9767 9747 8946 8946 8947 9767 8947 8952 9767 9778 8960 8948 8948 8956 9778 8949 10712 10723 8949 9773 10712 8950 8951 9775 10730 9775 8951 11739 10730 8951 8951 11737 11739 8951 10707 11737 8951 9742 10707 9753 9750 8953 8953 8954 9753 9754 9753 8954 11744 9754 8954 8954 9783 11744 9768 8956 8955 8955 9755 9768 10726 9778 8956 8956 9768 10726 9782 8958 8957 8958 9792 9793 8958 9791 9792 8958 9782 9791 9777 9767 8959 8959 9776 9777 8959 8976 9776 8959 8975 8976 9797 8964 8960 8960 9778 9797 8961 9779 9781 8961 8965 9779 9785 9779 8965 10741 9789 8966 8966 10734 10741 8966 9780 10734 9793 8977 8967 9801 8969 8968 8968 9799 9801 8968 8981 9799 8970 9810 9811 10757 9810 8970 10760 10757 8970 8970 9849 10760 8970 8971 9849 8971 8989 9849 8972 9794 9795 8972 8982 9794 9796 8974 8973 11754 9796 8973 8973 9774 11754 9796 8994 8974 8975 8983 9804 9804 8976 8975 10736 9776 8976 10743 10736 8976 8976 9804 10743 9807 8978 8977 8977 9793 9807 9807 8980 8978 8979 8980 10750 9800 8981 8979 10752 9800 8979 10753 10752 8979 8979 10750 10753 8980 9807 10750 9800 9799 8981 9811 9794 8982 8983 8986 9804 8983 8985 8986 8984 9814 9815 9816 9814 8984 8984 8990 9816 8984 8985 8990 8986 8985 8984 9805 8986 8984 9815 9805 8984 9806 9804 8986 8986 9805 9806 8987 11755 11768 8987 9797 11755 9819 9818 8988 8988 9794 9819 8989 9835 9849 8989 9834 9835 8992 8993 9813 8993 8999 9813 8993 8998 8999 10761 9822 8994 10762 10761 8994 12668 10762 8994 8994 12658 12668 8994 9796 12658 8999 9007 9813 9000 9001 9024 9002 9001 9000 9035 9024 9001 9852 9035 9001 10794 9852 9001 9001 9002 10794 9002 10777 10794 10778 10777 9002 9002 10762 10778 9002 9832 10762 9002 9823 9832 9003 9827 9829 9828 9827 9003 9833 9828 9003 9003 9004 9833 9841 9833 9004 9004 9021 9841 9004 9020 9021 9019 9006 9005 9008 9007 9006 9019 9008 9006 9821 9813 9007 9007 9820 9821 9007 9008 9820 9836 9820 9008 9008 9019 9836 9837 9020 9009 9842 9837 9009 9009 9010 9842 9843 9842 9010 9010 9011 9843 9011 9022 9843 9838 9023 9012 9014 9830 10782 9015 9016 9041 9017 9016 9015 10792 9017 9015 10805 10792 9015 9015 9886 10805 9015 9040 9886 9041 9040 9015 9847 9027 9016 9016 9017 9847 10772 9847 9017 9017 10771 10772 10792 10771 9017 9029 9019 9018 9019 9834 9836 9835 9834 9019 9019 9029 9835 9837 9021 9020 10784 9841 9021 10787 10784 9021 9021 10779 10787 9021 9837 10779 10788 9843 9022 9022 10781 10788 9022 9844 10781 9846 9845 9023 9023 9838 9846 9025 9030 9031 9026 10803 10804 9862 9854 9026 9878 9862 9026 10804 9878 9026 9847 9028 9027 9840 9029 9028 9847 9840 9028 9840 9835 9029 9032 9031 9030 9031 9032 9033 9870 9046 9035 9035 9852 9870 9871 9037 9036 9036 9048 9871 10821 9872 9037 9037 10807 10821 9037 9871 10807 9858 9039 9038 10801 9855 9039 9039 9859 10801 9039 9858 9859 9040 9878 9886 9040 9877 9878 9040 9866 9877 9040 9042 9866 9040 9041 9042 9052 9051 9045 9045 9046 9052 9870 9052 9046 9059 9048 9047 9061 9059 9047 9047 9060 9061 9048 9059 9871 9869 9868 9049 9049 9050 9869 9050 9055 9869 9050 9054 9055 9058 9053 9051 9051 9057 9058 9051 9052 9057 10811 9057 9052 11814 10811 9052 13575 11814 9052 9052 9870 13575 9058 9056 9053 9056 9055 9054 9883 9869 9055 9884 9883 9055 9055 9056 9884 9889 9884 9056 9890 9889 9056 9056 9058 9890 9890 9058 9057 10812 9890 9057 9057 10811 10812 10807 9871 9059 10813 10807 9059 9059 9891 10813 9059 9065 9891 9059 9061 9065 9065 9061 9060 9060 9064 9065 9898 9063 9062 9062 9896 9898 9897 9896 9062 9063 9898 9899 9912 9065 9064 9064 9073 9912 9892 9891 9065 9912 9892 9065 9905 9068 9066 9066 9894 9905 9066 9863 9894 9865 9863 9066 9067 9863 9864 9067 9069 9863 9905 9895 9068 9894 9863 9069 9070 9910 9916 9070 9901 9910 9071 9078 9922 9928 9087 9071 9071 9922 9928 10840 9917 9072 9072 9916 10840 9918 9912 9073 9074 9919 9924 9074 9076 9919 9919 9076 9075 9921 9919 9075 10854 9920 9077 10869 10854 9077 9077 9093 10869 9081 9080 9079 9926 9925 9079 9932 9926 9079 9934 9932 9079 9079 9080 9934 9941 9934 9080 10856 9097 9082 9085 9084 9083 10878 9085 9083 10879 10878 9083 10912 10879 9083 9083 10882 10912 9083 10852 10882 9083 9084 10852 9084 9085 9918 9084 10850 10852 9085 9912 9918 10841 9912 9085 10842 10841 9085 10878 10842 9085 9086 9924 10859 10867 9936 9086 10868 10867 9086 9086 10859 10868 9933 9095 9087 9087 9927 9933 9928 9927 9087 11861 9091 9089 9089 10889 11861 9089 9098 10889 9089 9092 9098 10866 10865 9090 9090 9091 10866 11861 10866 9091 9100 9098 9092 10871 10869 9093 10896 10871 9093 9093 9938 10896 9093 9937 9938 10863 9103 9097 9097 10857 10863 9097 10856 10857 9098 9099 10889 9100 9099 9098 10890 10889 9099 10895 10890 9099 9099 10894 10895 9099 9114 10894 9099 9104 9114 9099 9100 9104 9100 9101 9104 9945 9107 9102 9102 9942 9945 9102 9935 9942 9102 9103 9935 10874 9935 9103 9103 10863 10874 9104 9108 9114 9943 9106 9105 9105 9936 9943 9950 9116 9106 9106 9948 9950 9106 9943 9948 9110 9109 9107 9945 9110 9107 9107 9109 9949 9108 9115 10891 10894 9114 9108 10922 10894 9108 9108 10891 10922 9109 9110 10919 10920 9949 9109 9109 10919 10920 9110 9945 10919 10896 9944 9111 9111 10871 10896 11852 10871 9111 11872 11852 9111 9111 10925 11872 9111 9951 10925 10929 9953 9112 9112 9113 10929 9113 10920 10929 9113 9949 10920 9115 9119 9120 9115 9120 10891 9116 9950 10934 10934 9123 9116 10950 9121 9119 9119 9957 10950 9121 9120 9119 9120 9121 10891 10950 10893 9121 10893 10891 9121 10951 9966 9122 9122 9950 10951 10934 9950 9122 9122 9123 10934 9124 9123 9122 9966 9124 9122 9966 9962 9124 10925 9952 9125 10935 10925 9125 9125 9954 10935 9127 9956 9957 9127 9128 9956 9129 9128 9127 10965 9956 9128 10978 10965 9128 9128 9152 10978 9128 9129 9152 9129 9147 9152 9973 9958 9130 9130 9972 9973 9974 9153 9131 9131 9960 9974 9131 9959 9960 9963 9959 9131 9132 9133 9139 9961 9134 9132 9132 9139 9961 9133 9137 9139 9964 9963 9134 10942 9964 9134 10944 10942 9134 10959 10944 9134 9134 9961 10959 9970 9156 9135 9135 9968 9970 9135 9148 9968 9136 9137 9151 9138 9137 9136 10970 9138 9136 9136 9967 10970 9136 9151 9967 9137 9138 9139 10960 9139 9138 10970 10960 9138 10960 9961 9139 10972 9155 9140 9140 9141 10972 9141 9142 10972 9142 9155 10972 10971 9155 9142 9145 9144 9143 9978 9145 9143 10996 9978 9143 9143 9982 10996 9143 9144 9982 9144 9145 9165 9144 9157 9982 9165 9157 9144 9145 9150 9165 9978 9149 9145 9986 9166 9146 9146 9167 9986 9146 9154 9167 9979 9152 9147 11009 9979 9147 9147 11003 11009 9147 9991 11003 9148 9965 9968 9978 9972 9149 10985 10978 9152 9152 9979 10985 10989 9154 9153 9153 9974 10989 9168 9167 9154 10989 9168 9154 10971 9967 9155 9984 9982 9157 9157 9158 9984 9158 9983 9984 11014 9983 9158 9158 9996 11014 9171 9160 9159 9988 9171 9159 9159 9987 9988 9159 9170 9987 9161 9164 10000 9161 9162 9164 9163 9162 9161 11022 9163 9161 11031 11022 9161 9161 9999 11031 10000 9999 9161 9162 9163 9174 9174 9164 9162 9163 9172 9991 9173 9172 9163 11022 9173 9163 9164 9175 10000 9166 9986 9987 9989 9986 9167 9167 9168 9989 11909 9989 9168 9168 11005 11909 11006 11005 9168 9168 10989 11006 9171 9988 9990 11012 9991 9172 9172 9173 11012 11021 11012 9173 11022 11021 9173 9175 9176 10000 11032 10000 9176 9179 9178 9177 11026 9996 9178 9178 9179 11026 11035 11026 9179 11036 11035 9179 11037 11036 9179 9179 9182 11037 9188 9187 9180 10002 9188 9180 9180 9998 10002 10007 9190 9181 11042 11037 9182 9182 9183 11042 9184 9183 9182 11053 11042 9183 9183 11052 11053 9183 10021 11052 10017 10016 9185 9185 10010 10017 9185 9186 10010 9186 10002 10010 9186 9188 10002 9186 9187 9188 11059 10005 9189 9190 10007 10008 10011 10009 9190 10013 10011 9190 11051 10013 9190 9190 10008 11051 10011 9194 9192 9192 10009 10011 10022 9202 9193 10012 9197 9194 9194 10011 10012 9196 9195 9194 9197 9196 9194 9213 9198 9195 10042 9213 9195 9195 9196 10042 11076 10042 9196 11951 11076 9196 9196 9197 11951 9197 10012 11061 9197 11061 11951 9199 10015 10021 9199 10014 10015 10039 9201 9200 10040 10039 9200 9200 9202 10040 11078 11073 9201 9201 10039 11078 9202 10022 10040 9203 9206 9209 9205 9204 9203 9209 9205 9203 9204 10023 11059 9204 9205 10023 10041 10023 9205 9205 9209 10041 9206 9207 9210 9210 9209 9206 9207 9215 9240 9240 9210 9207 10061 10041 9209 9209 9210 10061 9210 9240 10061 9217 9216 9211 9211 9214 9217 10063 9214 9213 9213 10043 10063 9213 10042 10043 10062 9217 9214 10063 10062 9214 9215 9231 9240 9216 9217 9218 10071 9218 9217 9217 10065 10071 9217 10062 10065 10071 9233 9218 9248 9239 9219 9219 9232 9248 9219 9220 9231 9221 9220 9219 9239 9221 9219 9240 9231 9220 10070 9240 9220 10077 10070 9220 9220 9221 10077 10089 10077 9221 9221 9239 10089 11097 11092 9222 9222 11096 11097 9222 10069 11096 9222 9223 10069 9224 9223 9222 11092 9224 9222 10070 10069 9223 9223 9240 10070 10061 9240 9223 9223 9224 10061 9224 11978 11979 11994 11978 9224 9224 11092 11994 9224 10060 10061 11094 10060 9224 11979 11094 9224 9225 9228 9244 9225 9226 9228 9227 9226 9225 9244 9227 9225 9230 9228 9226 10067 9230 9226 10072 10067 9226 10076 10072 9226 10081 10076 9226 9226 9234 10081 9226 9227 9234 9235 9234 9227 9236 9235 9227 9237 9236 9227 9238 9237 9227 9244 9238 9227 9228 9229 9244 9230 9229 9228 10068 9244 9229 9229 10056 10068 9229 9230 10056 9230 10055 10056 10067 10055 9230 9232 9247 9248 9232 9241 9247 9233 10071 10073 10082 10081 9234 9234 9250 10082 9234 9235 9250 9235 9236 9250 10082 9250 9236 9236 9237 10082 11109 10082 9237 9237 11099 11109 9237 9238 11099 9238 9244 11099 9239 9245 10089 9248 9245 9239 9253 9247 9241 9241 9249 9253 10080 9243 9242 9242 10078 10080 9255 9249 9243 10080 9255 9243 11100 11099 9244 9244 10068 11100 9245 10087 10089 9245 10086 10087 9245 9246 10086 9247 9246 9245 9248 9247 9245 10088 10086 9246 11130 10088 9246 9246 10094 11130 9246 10093 10094 9246 9247 10093 9247 9253 10093 9249 9251 9253 9252 9251 9249 9255 9252 9249 10095 9253 9251 9251 9252 10095 10096 10095 9252 9252 9254 10096 9255 9254 9252 10095 10093 9253 10097 10096 9254 11112 10097 9254 9254 9255 11112 9255 10080 11112 10211 9257 9256 9256 9262 10211 10210 9259 9257 11231 10210 9257 11235 11231 9257 9257 10211 11235 10212 9266 9258 9258 10209 10212 9258 9259 10209 10210 10209 9259 9260 9261 10213 9261 9263 10213 11234 10211 9262 9262 10213 11234 11233 10213 9263 11238 11233 9263 11239 11238 9263 9263 9265 11239 9265 10215 11239 9266 10212 10214 9267 9269 9289 9289 9268 9267 11249 11247 9268 11260 11249 9268 12175 11260 9268 9268 9289 12175 11247 10215 9268 9270 9281 9291 9282 9281 9270 9271 9272 9277 9273 9272 9271 9283 9273 9271 9284 9283 9271 10217 9276 9272 10219 10217 9272 9272 10218 10219 9272 9273 10218 9272 9276 9277 9273 10216 10218 9273 9283 10216 9276 9275 9274 9277 9276 9274 9275 9276 9278 10217 9278 9276 9278 9279 9285 9280 9279 9278 10217 9280 9278 13070 11251 9279 9279 9280 13070 11251 9285 9279 9280 12162 13062 9280 10217 12162 9280 13068 13070 13069 13068 9280 9280 13062 13069 9293 9291 9281 11248 9293 9281 9281 9282 11248 13067 10216 9283 9283 10225 13067 9283 9284 10225 9284 9294 10225 10222 10221 9285 11251 10222 9285 10235 10234 9286 11274 10235 9286 9286 10258 11274 10234 10226 9286 9287 9296 9300 9287 9295 9296 9287 9288 9295 10223 9295 9288 9288 10221 10223 9289 9290 12175 12178 12175 9290 9290 11273 12178 9290 10242 11273 9291 9292 10224 9293 9292 9291 10245 10237 9292 9292 10244 10245 9292 9293 10244 10237 10224 9292 12180 10244 9293 12182 12180 9293 9293 11255 12182 11256 11255 9293 9293 11248 11256 10226 10225 9294 9301 9296 9295 9295 9297 9301 9298 9297 9295 10223 9298 9295 9301 9300 9296 10229 9301 9297 10230 10229 9297 10231 10230 9297 11257 10231 9297 11258 11257 9297 9297 11252 11258 11254 11252 9297 9297 9298 11254 9298 10223 11254 9303 9302 9299 10237 9303 9299 9301 10227 10238 10228 10227 9301 10229 10228 9301 9302 9303 9307 10252 9307 9303 11270 10252 9303 9303 10245 11270 9303 10237 10245 11276 10258 9304 9304 9305 11276 11277 11276 9305 9305 10262 11277 9305 9308 10262 9306 9310 9312 9306 9309 9310 9307 10252 10255 9308 9313 10262 9311 9310 9309 9314 9311 9309 11269 9312 9310 9310 10266 11269 9310 9311 10266 11285 10266 9311 9311 10269 11285 9311 9314 10269 11273 10242 9312 9312 11269 11273 9313 9316 10262 10267 10262 9316 9320 9318 9317 9320 9319 9318 11290 9338 9319 9319 9324 11290 9325 9324 9319 9319 9320 9325 10241 9325 9320 9340 9335 9321 9341 9340 9321 10279 9336 9322 9322 10272 10279 9349 9337 9323 9324 11282 11290 11283 11282 9324 9324 10239 11283 9324 9325 10239 10241 10239 9325 9328 9327 9326 9326 9330 9331 10264 9330 9326 9326 9327 10264 11311 11300 9327 9327 9328 11311 10274 10264 9327 11300 10274 9327 9328 10288 11311 9328 9353 10288 9354 9353 9328 10259 9334 9329 9329 10246 10259 10247 10246 9329 10263 10247 9329 9329 9330 10263 9331 9330 9329 9334 9331 9329 10264 10263 9330 9334 9332 9331 9334 9333 9332 9345 9339 9333 10276 9345 9333 10277 10276 9333 9333 10260 10277 9333 9334 10260 9334 10259 10260 9335 9340 10270 10279 9348 9336 9337 9349 10280 11309 9344 9338 9338 11290 11309 10278 10270 9340 9340 9341 10278 9341 9346 10278 9342 9350 9351 9352 9350 9342 9342 9343 9352 11310 9352 9343 9343 9344 11310 11318 11310 9344 9344 11309 11318 10283 9356 9345 9345 10282 10283 9345 10276 10282 10287 10278 9346 10293 10287 9346 9346 9361 10293 9362 9361 9346 11320 9365 9347 9347 10294 11320 9347 9348 10294 9358 9357 9347 9364 9358 9347 9365 9364 9347 11299 10294 9348 9348 10279 11299 11315 10281 9349 9349 10306 11315 9349 9367 10306 10281 10280 9349 9350 10295 10310 10296 10295 9350 9350 9352 10296 9351 9366 9367 11323 10296 9352 9352 11310 11323 9353 9359 10288 9353 9354 9359 10299 9368 9355 9355 9356 10299 10300 10299 9356 9356 10289 10300 9356 10283 10289 9358 9364 9371 10297 10288 9359 9375 9374 9360 9360 9369 9375 12230 10293 9361 9361 12215 12230 9361 12212 12215 12214 12212 9361 9361 10304 12214 9361 9362 10304 9362 9370 10304 10308 9371 9364 9364 10305 10308 9364 9365 10305 9365 11320 12239 12243 10305 9365 9365 12239 12243 10306 9367 9366 9366 9372 10306 11326 9369 9368 9368 11324 11326 9368 10301 11324 9368 10300 10301 9368 10299 10300 11336 9375 9369 9369 11326 11336 10307 10304 9370 9370 9384 10307 9386 9376 9371 11333 9386 9371 9371 10308 11333 10309 10306 9372 11341 10309 9372 10311 10298 9373 9373 9379 10311 11336 11335 9375 9376 9387 10329 9376 9386 9387 9390 9389 9378 10315 9390 9378 10322 10315 9378 10315 10311 9379 9379 9390 10315 9379 9389 9390 9394 9381 9380 9383 9382 9381 9394 9383 9381 9382 10316 10319 9382 9383 10316 10317 10316 9383 10318 10317 9383 9383 9394 10318 10312 10307 9384 10328 10312 9384 10321 9387 9386 12278 10321 9386 9386 11351 12278 9386 11333 11351 11359 10329 9387 11360 11359 9387 9387 10321 11360 11362 9410 9391 10330 9394 9393 9393 10324 10330 11330 10318 9394 11348 11330 9394 9394 11337 11348 9394 10330 11337 10336 9412 9395 10337 10336 9395 9395 10331 10337 10332 10331 9395 9411 9398 9397 10349 9411 9397 9397 9427 10349 11372 10335 9398 9398 10348 11372 9398 9411 10348 10333 10327 9399 10334 10333 9399 9406 9405 9400 9418 9406 9400 11383 9418 9400 9400 11374 11383 9400 11359 11374 9400 10329 11359 9401 9407 9413 9401 9402 9407 9402 9403 9407 9404 9409 9414 9410 9409 9404 9407 9408 9413 10345 9413 9408 10346 10345 9408 9408 9419 10346 11376 9414 9409 9409 9410 11376 9410 11372 11376 9410 11371 11372 9410 11362 11371 11385 10348 9411 9411 10349 11385 11375 11370 9413 9413 10345 11375 11376 10347 9414 10350 9417 9415 9415 10339 10350 9416 9418 9432 9436 9435 9417 10350 9436 9417 11389 9432 9418 9418 11383 11389 11391 10346 9419 9419 9420 11391 11392 11391 9420 9420 10356 11392 9420 9433 10356 9421 9424 9433 11395 10357 9422 9422 10358 11395 9422 9423 10358 9424 9423 9422 10357 9424 9422 9423 9425 10358 11394 9433 9424 11401 11394 9424 9424 10357 11401 10359 10358 9425 9425 9434 10359 9444 9427 9426 9445 9444 9426 11380 10349 9427 11407 11380 9427 9427 9444 11407 10338 10334 9428 10341 10338 9428 9428 9430 10341 9438 9431 9429 9431 9430 9429 10344 10341 9430 9430 9431 10344 9431 10362 10365 9431 9438 10362 10353 10344 9431 10365 10353 9431 11389 9446 9432 11393 10356 9433 11394 11393 9433 10364 10359 9434 9434 10354 10364 10355 10354 9434 9435 9436 12300 11425 10378 9435 12300 11425 9435 9436 11386 12300 9436 10350 11386 9438 9439 10362 9440 9439 9438 10363 10362 9439 10379 10363 9439 9439 9457 10379 10372 9448 9442 9444 10394 11407 9444 9445 10394 9445 9456 10394 11399 10367 9446 9446 11389 11399 11413 10368 9447 9447 9448 11413 9448 11411 11413 11417 11411 9448 9448 10372 11417 11418 9459 9449 9449 10373 11418 9459 9451 9450 9461 9460 9451 10392 9461 9451 9451 10386 10392 9451 9459 10386 10374 9453 9452 9455 9454 9453 10376 9455 9453 9453 10374 10376 9454 10375 11423 9454 9455 10375 10376 10375 9455 9456 9462 9463 9456 10393 10394 10395 10393 9456 9456 9463 10395 10389 10379 9457 11436 10386 9459 9459 11434 11436 9459 11418 11434 11420 10387 9460 11435 11420 9460 9460 9461 11435 10387 10374 9460 9461 10392 11435 11429 10389 9464 9464 11428 11429 12370 11428 9464 9464 11453 12370 12367 11453 9464 9464 9465 12367 9465 10413 12367 10415 9468 9466 9466 10407 10415 9466 9469 10407 9467 10381 10390 9467 10380 10381 11456 10414 9468 9468 10415 11456 9469 10401 10407 9470 9471 9478 9470 9471 9472 9470 9472 9473 9478 9473 9470 10418 9472 9471 10418 9478 9471 9472 10410 10411 9472 10411 10419 10419 9473 9472 10418 10410 9472 9473 10419 10420 10432 10420 9473 9473 10431 10432 9473 9478 10431 11451 9475 9474 11452 11451 9474 11473 11452 9474 9475 11451 11464 9478 10430 10431 9478 10418 10430 9480 9491 10433 9480 9481 9491 9481 9482 9491 10434 9491 9482 9482 9484 10434 10423 9484 9483 9483 10406 10423 9484 10422 10434 10423 10422 9484 10446 10416 9485 13245 10446 9485 13250 13245 9485 9485 9486 13250 9486 10455 11486 9486 9493 10455 9486 12391 13250 9486 11486 12391 9487 10425 10437 10426 9490 9488 11469 10426 9488 9488 11468 11469 9488 9489 11468 9489 11458 11468 9489 10437 11458 10448 10437 9489 9489 10438 10448 10442 10433 9491 9491 10434 10442 10453 10450 9492 9492 9497 10453 11488 9497 9495 9495 10456 11488 9495 9496 10456 9496 9504 10456 11488 11485 9497 11485 10453 9497 10472 10469 9498 9498 10471 10472 9498 10454 10471 10460 10454 9498 10461 9501 9499 11502 9507 9501 9501 11495 11502 9501 10461 11495 9504 9503 9502 11491 9504 9502 12397 11491 9502 13273 12397 9502 13274 13273 9502 9502 11507 13274 9502 9503 11507 9503 9504 9505 9503 10480 11507 9503 10479 10480 9503 9505 10479 11491 10456 9504 9505 9516 10479 10473 10463 9506 10482 10473 9506 10488 9508 9507 11511 10488 9507 9507 11502 11511 10488 9525 9508 11503 11496 9509 9509 9510 11503 9511 9510 9509 9512 9511 9509 11496 9512 9509 9510 9526 10478 9510 9513 9526 9510 9511 9513 9510 10478 11503 9511 9512 10467 11490 10467 9512 12393 11490 9512 9512 11496 12393 9514 9515 10468 9528 9527 9514 10468 9528 9514 10481 10479 9516 9516 9517 10481 9517 9529 10481 10497 9529 9518 9518 9519 10497 9519 9520 10497 9521 10475 11501 9521 10474 10475 10483 10474 9521 9522 10466 10485 11523 10466 9522 9522 9523 11523 9524 9523 9522 10485 9524 9522 9523 11510 11523 9523 10487 11510 9523 9524 10487 9524 10486 10487 9524 10477 10486 10485 10477 9524 9532 9531 9525 10488 9532 9525 10504 10502 9527 11504 10504 9527 9527 9528 11504 11505 11504 9528 9528 10468 11505 10497 10481 9529 10484 9544 9530 11510 10487 9531 9531 10518 11510 9531 9532 10518 11528 10518 9532 9532 11524 11528 9532 10488 11524 10514 10482 9533 9533 10513 10514 10535 10513 9533 9533 9558 10535 10521 10490 9534 9535 9563 9574 9575 9563 9535 9535 9554 9575 9535 9540 9554 9535 9536 9540 9537 9536 9535 9574 9537 9535 10505 9540 9536 9536 9538 10505 9536 9537 9538 10502 9538 9537 11514 10505 9538 9538 10503 11514 9538 10502 10503 9539 9540 10505 9541 9540 9539 9542 9541 9539 10509 9542 9539 9539 10506 10509 10507 10506 9539 11515 10507 9539 9539 10505 11515 9540 9541 9554 9541 9542 9554 9555 9554 9542 9556 9555 9542 10509 9556 9542 10536 9559 9543 10552 10536 9543 11533 10552 9543 13295 11533 9543 9543 12417 13295 9543 10484 12417 9543 9544 10484 9545 10518 10520 9545 10517 10518 9545 9546 10517 9547 9546 9545 9561 9551 9548 9550 9549 9548 9551 9550 9548 9549 9552 9553 9549 9550 9552 9562 9552 9550 10528 9562 9550 9550 9551 10528 10529 10528 9551 9551 10519 10529 9551 9561 10519 9552 9562 10553 9576 9575 9554 9554 9564 9576 9554 9555 9564 9565 9564 9555 9567 9565 9555 9555 9556 9567 10509 9567 9556 9569 9558 9557 9558 10516 10535 9558 9569 10516 9560 9570 10525 9562 10526 10553 10528 10526 9562 10546 9576 9564 9564 9579 10546 9564 9565 9579 9565 9568 9579 9565 9566 9568 9567 9566 9565 9578 9568 9566 9581 9578 9566 10522 9581 9566 9566 10510 10522 9566 10508 10510 9566 9567 10508 10509 10508 9567 9568 9578 9579 11535 10516 9569 9569 10542 11535 10537 10525 9570 10538 10537 9570 9586 9585 9571 9587 9586 9571 9571 9583 9587 9571 9572 9583 12446 9583 9572 9572 10553 12446 9601 9588 9573 9602 9601 9573 9575 9576 9577 10558 9577 9576 9576 10546 10558 9577 9591 9605 10558 9591 9577 9580 9579 9578 9581 9580 9578 9579 9580 10546 9580 10547 10566 9580 9581 10547 10554 10546 9580 10563 10554 9580 10564 10563 9580 10566 10564 9580 9581 10539 10547 9581 10534 10539 9581 10532 10534 9581 10522 10532 9617 9616 9582 12446 12444 9583 10530 9587 9583 12447 10530 9583 9583 12444 12447 9584 9586 9594 9584 9585 9586 9598 9596 9586 9599 9598 9586 9586 9587 9599 9596 9594 9586 10531 9599 9587 9587 10530 10531 9601 9600 9588 10562 9591 9589 9589 10561 10562 11566 10561 9589 12469 11566 9589 9589 10584 12469 9589 10555 10584 9589 9590 10555 9591 9590 9589 9590 10554 10555 11546 10554 9590 9590 9591 11546 10562 9604 9591 9591 10558 11546 9591 9603 9605 12466 10560 9592 9592 11561 12466 9592 9593 11561 10560 9606 9592 9593 9607 11561 9609 9607 9593 9619 9609 9593 9596 9595 9594 9620 9619 9595 9595 9596 9620 9596 9597 9621 9598 9597 9596 10574 9620 9596 9596 9621 10574 9597 9610 9621 9597 9601 9610 9597 9598 9601 9598 9599 9601 9599 9600 9601 9599 10531 11538 9611 9610 9601 9601 9602 9611 9612 9611 9602 9604 10561 11564 10562 10561 9604 11564 10579 9604 10560 10557 9606 13330 11561 9607 9607 12467 13330 9607 9608 12467 9609 9608 9607 9608 10573 12467 9608 10572 10573 9608 9609 10572 9609 10571 10572 9609 9620 10571 9609 9619 9620 10576 10575 9610 9610 9611 10576 10575 9621 9610 9611 9622 10576 9611 9612 9622 9612 9613 9622 9623 9622 9613 9613 9614 9623 10579 9623 9614 9616 11550 11568 9616 9617 11550 11551 11550 9617 9617 9618 11551 9618 11542 11551 9618 10551 11542 11570 10571 9620 9620 10574 11570 11570 10574 9621 9621 10580 11570 10581 10580 9621 9621 10575 10581 10577 10576 9622 9622 9623 10577 10578 10577 9623 10579 10578 9623 9624 10564 10566 9628 9627 9625 10587 9628 9625 11580 10594 9626 9627 11575 12478 11577 11575 9627 12470 11577 9627 9627 11567 12470 9627 9628 11567 9628 10569 11567 9628 10556 10569 10587 10556 9628 9629 9631 10590 10592 10590 9631 10599 10598 9633 9636 9635 9634 9637 9636 9634 9635 9636 9639 11610 9639 9636 9636 9637 11610 9637 9647 11610 9637 9646 9647 10614 9645 9638 10615 10614 9638 12510 10615 9638 9643 9642 9639 9644 9643 9639 11610 9644 9639 9642 9641 9640 11654 9662 9641 9641 11638 11654 9641 9642 11638 9642 9643 11638 9643 11622 11638 9643 9644 11622 9644 9647 11622 11610 9647 9644 9655 9647 9646 9646 9654 9655 9658 9654 9646 11624 11622 9647 9647 9659 11624 9647 9655 9659 9648 10629 10632 10631 10629 9648 9648 9649 10631 10613 9651 9648 10632 10613 9648 10607 9652 9650 9650 10604 10607 9650 10603 10604 9650 9651 10603 10611 10603 9651 10613 10611 9651 9653 9656 10608 10608 9661 9653 9659 9655 9654 9654 9657 9659 9658 9657 9654 9660 9659 9657 9665 9660 9657 9659 9660 11624 9660 10644 11624 9660 10639 10644 9660 9665 10639 10627 9664 9661 10638 10627 9661 9661 10616 10638 10617 10616 9661 10633 10617 9661 9661 10622 10633 9661 10621 10622 9661 10608 10621 11644 9666 9662 11645 11644 9662 11654 11645 9662 9666 9663 9662 10627 10626 9664 10640 10639 9665 9665 9670 10640 9665 9668 9670 10654 9675 9666 10665 10654 9666 11673 10665 9666 9666 11644 11673 9667 10626 10648 9668 9669 9670 9684 9669 9668 9671 9670 9669 9674 9671 9669 9685 9674 9669 9693 9685 9669 9669 9692 9693 9669 9684 9692 9670 9671 10640 10642 10640 9671 9671 9672 10642 9674 9672 9671 9672 9673 10642 9674 9673 9672 9673 10641 10642 10652 10641 9673 9673 9685 10652 9673 9674 9685 9694 9686 9675 10654 9694 9675 12573 11691 9676 9682 9681 9677 10663 9682 9677 9677 10662 10663 9677 10661 10662 9677 9679 10661 10657 9680 9678 10658 10657 9678 9679 10659 10661 10660 10659 9679 9679 10657 10660 9679 9680 10657 9681 9682 9683 10663 9683 9682 10663 9691 9683 11721 10652 9685 9685 9704 11721 9685 9693 9704 9701 9689 9687 9687 9700 9701 10656 9700 9687 9687 9688 10656 11690 10656 9688 9688 10655 11690 11706 10670 9690 11679 9703 9691 9691 10663 11679 10683 9693 9692 9692 9719 10683 10683 9704 9693 11714 9721 9694 9694 11697 11714 9694 10665 11697 9694 10654 10665 9698 9697 9696 10674 9698 9696 9696 9707 10674 9696 9697 9699 10666 10655 9698 10674 10666 9698 10668 9702 9700 11700 10668 9700 11702 11700 9700 9700 10667 11702 9700 10656 10667 9702 9701 9700 9701 9702 9708 9715 9708 9702 10669 9715 9702 9702 10668 10669 10672 10671 9703 9703 10637 10672 11679 10637 9703 12597 11721 9704 12603 12597 9704 9704 10678 12603 10683 10678 9704 10680 9707 9705 10687 10680 9705 9705 9706 10687 9706 9714 10686 9706 10684 10687 10686 10684 9706 11698 10674 9707 9707 10680 11698 9708 9715 9716 9709 9718 9726 9711 9712 10692 9713 9712 9711 10700 10692 9712 9712 9713 10700 9714 9722 10686 10675 9724 9715 9715 10669 10675 9724 9716 9715 9716 9724 9725 10689 9726 9718 10690 10689 9718 9719 10678 10683 10679 10678 9719 10691 10679 9719 10692 10691 9719 9720 9721 10688 11722 10688 9721 9721 11714 11722 9722 9728 10686 9722 9727 9728 9722 9723 9727 9734 9727 9723 9726 10698 10699 9726 10689 10698 9734 9728 9727 10697 10686 9728 9728 9734 10697 9731 9730 9729 9736 9735 9730 9757 9736 9730 9761 9757 9730 9730 9731 9761 11735 9733 9732 9732 9737 11735 11735 9739 9733 10701 10697 9734 9734 9743 10701 9736 9744 10703 9745 9744 9736 10708 9745 9736 9736 9757 10708 12629 11735 9737 12633 12629 9737 9737 9738 12633 9738 12631 12633 9738 12630 12631 9738 11734 12630 9738 10705 11734 9739 11735 12629 9741 9740 9739 12628 9741 9739 12629 12628 9739 9740 9741 11726 11726 10700 9740 12624 11726 9741 9741 11730 12624 12628 11730 9741 9742 10688 10707 9743 9747 10701 10713 9755 9744 10716 10713 9744 9744 10714 10716 9744 9745 10714 10715 10714 9745 11742 10715 9745 9745 10708 11742 11733 10701 9747 9747 10702 11733 9747 9767 10702 10710 10704 9749 9749 9764 10710 9752 9751 9750 9753 9752 9750 9751 9752 9766 11741 10724 9752 9752 11740 11741 9752 9754 11740 9752 9753 9754 10724 9766 9752 11744 11740 9754 10713 9768 9755 9756 9759 9769 9756 9757 9759 9758 9757 9756 9769 9758 9756 9761 9759 9757 9757 9758 10708 9758 9769 10708 9759 9762 9770 9759 9760 9762 9761 9760 9759 9770 9769 9759 10717 9770 9762 9762 9771 10717 9762 9763 9771 9772 9771 9763 10722 10710 9764 9764 10711 10722 9764 9765 10711 10712 9773 9766 10724 10712 9766 9767 9777 10702 10732 10726 9768 9768 10725 10732 9768 10713 10725 9769 9770 10708 10717 10708 9770 10718 10717 9771 9771 10709 10718 9771 9772 10709 9772 10704 10709 9774 10730 11754 9774 9775 10730 10739 10737 9776 9776 10736 10739 10737 9777 9776 10737 10702 9777 11755 9797 9778 9778 10731 11755 9778 10726 10731 10735 9781 9779 9779 10733 10735 9779 9785 10733 9780 9781 10734 10735 10734 9781 9783 11743 11744 9783 9784 11743 12657 11743 9784 9784 12656 12657 9784 9802 12656 9784 9801 9802 10740 10733 9785 9785 9787 10740 9785 9786 9787 9798 9787 9786 9817 9798 9786 12673 10740 9787 9787 11763 12673 9787 9798 11763 9788 10741 10742 9788 9789 10741 9790 9789 9788 10745 9790 9788 11759 10745 9788 9788 11758 11759 9788 10742 11758 9792 9791 9789 9789 9790 9792 9790 10745 11764 10746 9792 9790 11767 10746 9790 9790 11764 11767 10746 9808 9792 9807 9793 9792 9808 9807 9792 9794 9809 9819 9810 9809 9794 9811 9810 9794 13511 12658 9796 9796 11754 13511 9798 10747 11763 9798 9817 10747 11766 9801 9799 9799 9800 11766 9800 10752 11766 9803 9802 9801 11766 9803 9801 9802 9803 12656 9803 11770 12656 9803 11766 11770 10744 10743 9804 9804 9806 10744 11771 9806 9805 11784 11771 9805 9805 9815 11784 11762 10744 9806 12681 11762 9806 9806 11771 12681 10751 10750 9807 9807 10749 10751 9807 10748 10749 9807 9808 10748 9808 10746 11767 11767 10748 9808 10757 9819 9809 9809 9810 10757 9821 9820 9812 9812 9813 9821 9812 9820 9836 9825 9815 9814 9826 9825 9814 9814 9816 9826 9815 9825 10770 9815 10770 11784 9817 10766 10767 9817 9829 10766 10767 10747 9817 11783 9839 9818 9818 10758 11783 9818 10757 10758 9818 9819 10757 10761 9824 9822 9824 9823 9822 9823 9824 9832 10761 9832 9824 9825 9826 10770 10763 9829 9827 9827 9828 10763 10764 10763 9828 9828 9833 10764 9829 10765 10766 9829 10763 10765 9830 9831 10776 9830 10776 10782 11783 10758 9831 9831 9839 11783 9831 10758 10776 9832 10761 10762 9833 9841 10764 9835 9840 9849 9837 9842 10779 9840 9848 9849 9840 9847 9848 11788 10764 9841 12694 11788 9841 12705 12694 9841 9841 10774 12705 10775 10774 9841 10785 10775 9841 9841 10784 10785 10780 10779 9842 9842 9843 10780 10788 10780 9843 9844 9850 10781 9845 10802 11802 9845 9853 10802 9845 9846 9853 9846 9851 9853 10772 9848 9847 10772 10769 9848 10769 9849 9848 10769 10760 9849 11801 11800 9850 10789 10781 9850 12710 10789 9850 9850 11800 12710 10793 9870 9852 10794 10793 9852 9853 9855 10802 9878 9877 9854 9854 9862 9878 9855 10801 10802 9879 9867 9856 9856 9857 9879 9861 9859 9858 11808 10801 9859 11811 11808 9859 9859 9860 11811 9861 9860 9859 12728 10800 9860 9860 11815 12728 9860 10808 11815 9860 9861 10808 9860 10800 11811 10810 10808 9861 9861 9874 10810 9865 9864 9863 9864 9865 9866 9877 9866 9865 10806 9887 9867 9867 9880 10806 9867 9879 9880 9881 9879 9868 9882 9881 9868 9888 9882 9868 9868 9883 9888 9868 9869 9883 9870 13573 13575 9870 13572 13573 9870 13571 13572 9870 13565 13571 9870 12704 13565 9870 10793 12704 9876 9873 9872 10821 9876 9872 9875 9874 9873 9876 9875 9873 10816 10810 9874 9874 9875 10816 10822 10816 9875 9875 9885 10822 9875 9876 9885 10823 9885 9876 9876 10821 10823 10804 9886 9878 9881 9880 9879 11810 10806 9880 9880 9881 11810 11813 11810 9881 9881 9882 11813 11816 11813 9882 9882 10818 11816 9882 9888 10818 9902 9888 9883 9883 9884 9902 10824 9902 9884 9884 9904 10824 9884 9889 9904 11823 10822 9885 9885 10825 11823 9885 10823 10825 9886 10804 10805 11812 9897 9887 9887 11810 11812 9887 10806 11810 10819 10818 9888 9888 9902 10819 9889 9903 9904 10820 9903 9889 9889 9890 10820 9890 10812 10820 10833 10813 9891 9891 9892 10833 10834 10833 9892 9892 9912 10834 9895 9894 9893 9906 9895 9893 9915 9906 9893 9894 9895 9905 10835 9914 9895 10836 10835 9895 9895 9906 10836 9900 9898 9896 10817 9900 9896 9896 9897 10817 10827 10817 9897 11812 10827 9897 9900 9899 9898 9899 9908 9911 9899 9907 9908 9899 9900 9907 10829 9907 9900 9900 10817 10829 11831 10819 9902 11834 11831 9902 9902 10824 11834 10832 9904 9903 11835 10832 9903 9903 11832 11835 9903 10820 11832 9904 10832 12755 12754 10824 9904 12755 12754 9904 10837 10836 9906 9906 9925 10837 9906 9915 9925 9909 9908 9907 10829 9909 9907 9923 9911 9908 10846 9923 9908 9908 9909 10846 10847 10846 9909 10848 10847 9909 9909 10839 10848 9909 10831 10839 9909 10829 10831 10840 9916 9910 9910 9923 10840 9910 9911 9923 10841 10834 9912 9929 9922 9913 9913 9914 9929 10835 9929 9914 10857 10856 9917 9917 10840 10857 10853 9924 9919 9919 9921 10853 10854 9921 9920 10854 10853 9921 9930 9928 9922 9922 9929 9930 10857 10840 9923 9923 10855 10857 9923 10846 10855 9924 10853 11851 11851 10859 9924 10860 10837 9925 9925 9926 10860 9926 9930 10860 9926 9928 9930 10872 9928 9926 9926 9932 10872 10872 9933 9927 9927 9928 10872 10843 9930 9929 9929 10835 10843 9930 10843 10860 9931 9932 9934 9933 9932 9931 9941 9940 9931 9931 9934 9941 9932 9933 10872 10874 9942 9935 9936 10867 11867 9947 9943 9936 11867 9947 9936 9939 9938 9937 9944 9939 9937 9938 9939 10896 9939 9944 10896 10908 9945 9942 9942 10874 10908 9943 9946 9948 9947 9946 9943 9945 10908 10919 10924 9948 9946 9946 10923 10924 9946 10915 10923 9946 9947 10915 11867 10915 9947 10924 9950 9948 9950 10933 10951 9950 10924 10933 9951 9952 10925 10952 10935 9954 10953 10952 9954 9954 9958 10953 9955 10926 10945 10965 10964 9956 10950 9957 9956 10964 10950 9956 10966 10953 9958 10967 10966 9958 10980 10967 9958 9958 9973 10980 9959 10954 10969 9959 9964 10954 9959 9963 9964 10968 9960 9959 10969 10968 9959 11900 9974 9960 9960 11891 11900 9960 10968 11891 10960 10959 9961 9969 9965 9962 10951 9969 9962 9962 9966 10951 9964 10938 10954 10942 10938 9964 9969 9968 9965 10971 10970 9967 9971 9970 9968 9977 9971 9968 9968 9975 9977 9968 9969 9975 9976 9975 9969 10979 9976 9969 9969 10951 10979 9970 9980 9985 9970 9971 9980 9971 9977 9980 10980 9973 9972 10988 10980 9972 9972 9978 10988 11900 10989 9974 10987 9977 9975 11004 10987 9975 9975 10986 11004 9975 9976 10986 9976 10979 11885 11897 10986 9976 9976 11885 11897 9981 9980 9977 10987 9981 9977 10996 10988 9978 11009 10985 9979 9993 9985 9980 11013 9993 9980 9980 9981 11013 11023 11013 9981 9981 11004 11023 9981 10987 11004 10997 10996 9982 11903 10997 9982 9982 9983 11903 9984 9983 9982 11919 11903 9983 9983 11918 11919 9983 11014 11918 9985 9993 9994 9989 9987 9986 9989 9988 9987 11011 9990 9988 9988 9989 11011 11927 11011 9989 9989 11915 11927 9989 11909 11915 9990 9998 11016 11010 9998 9990 11015 11010 9990 9990 11011 11015 9991 11001 11003 11012 11001 9991 11016 9997 9992 9995 9994 9993 11024 9995 9993 9993 11013 11024 10006 10001 9994 9994 9995 10006 11060 10006 9995 11062 11060 9995 11947 11062 9995 9995 11024 11947 11026 11014 9996 11016 9998 9997 11010 10002 9998 11930 11031 9999 11931 11930 9999 9999 11033 11931 9999 10000 11033 10000 11032 11033 10008 10007 10001 10001 10006 10008 10002 10003 10010 10004 10003 10002 11010 10004 10002 11057 10010 10003 10003 11056 11057 10003 10004 11056 10004 11039 11056 10004 11027 11039 10004 11010 11027 11930 11041 10005 10005 11058 11930 11059 11058 10005 11041 11032 10005 11051 10008 10006 11060 11051 10006 11057 10017 10010 10013 10012 10011 10012 10013 11061 10013 11051 11061 11046 10015 10014 11047 11046 10014 10014 10036 11047 11052 10021 10015 10015 11043 11052 11044 11043 10015 11046 11044 10015 11064 10022 10016 10016 10017 11064 10017 11057 11064 10032 10031 10018 11071 10032 10018 10018 10028 11071 10033 10028 10018 10018 10019 10033 10020 10019 10018 10031 10020 10018 10034 10033 10019 10035 10034 10019 11077 10035 10019 10019 10020 11077 10020 10051 11077 10020 10050 10051 11085 10050 10020 11967 11085 10020 10020 11961 11967 10020 10031 11961 11064 10040 10022 11950 11059 10023 10023 10060 11950 10023 10041 10060 10024 10047 10057 10024 10027 10047 10024 10025 10027 10026 10025 10024 10057 10026 10024 10046 10027 10025 11082 10046 10025 11083 11082 10025 12851 11083 10025 10025 11987 12851 10025 11081 11987 10025 11080 11081 10025 10026 11080 10026 10055 11080 10057 10055 10026 10027 10029 10047 10046 10029 10027 10028 10029 11071 10030 10029 10028 10033 10030 10028 10049 10047 10029 10059 10049 10029 10029 10048 10059 10029 10030 10048 10029 11070 11071 10029 10046 11070 10030 10033 10048 10031 10032 11959 10031 11960 11961 10031 11959 11960 10032 11071 11072 10032 11072 11959 10050 10048 10033 10051 10050 10033 10033 10034 10051 10034 10035 10051 11077 10051 10035 11049 11047 10036 10036 10037 11049 11073 11049 10037 10037 10038 11073 10039 10040 11078 10040 11064 11078 10061 10060 10041 10045 10043 10042 11076 10045 10042 11087 10063 10043 10043 10044 11087 10045 10044 10043 11089 11087 10044 11965 11089 10044 10044 10045 11965 10045 11964 11965 11966 11964 10045 10045 11956 11966 10045 11076 11956 11957 11070 10046 11958 11957 10046 10046 11082 11958 10047 10049 10057 10048 10058 10059 11084 10058 10048 11085 11084 10048 10048 10050 11085 10058 10057 10049 10059 10058 10049 11081 11080 10052 11987 11081 10052 10052 11986 11987 10052 10053 11986 10054 10053 10052 11080 10054 10052 10053 10054 12005 12855 11986 10053 12866 12855 10053 12867 12866 10053 10053 12005 12867 10054 10066 11098 10067 10066 10054 10054 10055 10067 11080 10055 10054 10054 11098 12005 10057 10056 10055 10056 10064 10068 10056 10057 10064 10057 10058 10064 11090 10064 10058 11091 11090 10058 10058 11084 11091 10060 11093 11950 11094 11093 10060 10062 10063 11087 11088 10065 10062 10062 11087 11088 11090 10068 10064 10079 10071 10065 11088 10079 10065 10066 10074 10075 10066 10072 10074 10066 10067 10072 10066 10075 11098 10068 11095 11100 10068 11090 11095 11101 11096 10069 10069 10083 11101 10069 10077 10083 10069 10070 10077 10079 10073 10071 10076 10074 10072 10079 10078 10073 10074 10076 11103 11103 10075 10074 12011 11098 10075 10075 11102 12011 11103 11102 10075 10076 10081 11103 10084 10083 10077 11111 10084 10077 10077 10089 11111 13758 10080 10078 10078 10079 13758 10079 13741 13758 10079 11995 13741 10079 11965 11995 10079 11089 11965 10079 11088 11089 12023 11112 10080 13758 12023 10080 10081 10085 11103 10081 10082 10085 11108 10085 10082 11109 11108 10082 12008 11101 10083 12017 12008 10083 10083 11104 12017 10083 10084 11104 11111 11104 10084 11105 11103 10085 11108 11105 10085 10088 10087 10086 11111 10089 10087 10087 10102 11111 10103 10102 10087 10087 10088 10103 11127 10103 10088 11130 11127 10088 10090 11123 12930 11131 11123 10090 10090 11113 11131 10090 10091 11113 10092 10091 10090 12930 10092 10090 10091 10108 11113 10091 10098 10108 12018 10098 10091 13770 12018 10091 10091 10092 13770 13772 13770 10092 10092 12930 13772 10105 10094 10093 10106 10105 10093 10093 10095 10106 10094 11126 11130 12033 11126 10094 10094 12031 12033 10094 10105 12031 10095 10096 10106 10096 10105 10106 12034 10105 10096 10096 11112 12034 10096 10097 11112 10101 10100 10098 10116 10101 10098 12019 10116 10098 10098 12018 12019 10098 10099 10108 10100 10099 10098 10099 10107 10108 10115 10107 10099 10099 10114 10115 10099 10113 10114 10099 10104 10113 10099 10100 10104 10100 10102 10104 10116 10102 10100 10100 10101 10116 10102 10116 12019 10102 10103 10104 11114 11111 10102 11120 11114 10102 12019 11120 10102 11132 10104 10103 11133 11132 10103 10103 11125 11133 11127 11125 10103 11132 10113 10104 12035 12031 10105 10105 12034 12035 10109 10108 10107 11131 10109 10107 10107 10115 11131 10108 10109 11113 11131 11113 10109 11134 11124 10110 12044 11134 10110 10110 11135 12044 10110 10118 11135 10110 10111 10118 10112 10111 10110 10114 10112 10110 10115 10114 10110 11123 10115 10110 11124 11123 10110 10111 10112 10121 10111 10117 10118 10122 10117 10111 10111 10121 10122 10112 10120 10121 10112 10114 10120 10120 10114 10113 10124 10120 10113 10125 10124 10113 11132 10125 10113 10115 11123 11131 11156 11145 10117 10117 11148 11156 10117 10123 11148 10117 10122 10123 10119 10118 10117 11145 10119 10117 10118 10119 11135 12052 11135 10119 12063 12052 10119 10119 11145 12063 10124 10123 10120 10123 10121 10120 10123 10122 10121 10123 10124 10125 10123 11136 11148 10123 10125 11136 12045 11136 10125 10125 11132 12045 11164 11149 10126 10126 11163 11164 10126 10139 11163 10126 10137 10139 10126 10127 10137 10128 10127 10126 11149 10128 10126 10138 10137 10127 10142 10138 10127 10127 10129 10142 10127 10128 10129 10128 11149 11150 10130 10129 10128 11150 10130 10128 10129 10131 10142 10129 10130 10131 10132 10131 10130 11152 10132 10130 10130 11150 11152 10143 10142 10131 10131 10133 10143 10131 10132 10133 11160 10144 10132 11161 11160 10132 10132 11159 11161 10132 11152 11159 10144 10133 10132 10144 10143 10133 10134 10150 10156 10134 10147 10150 10153 10147 10134 10134 10135 10153 10136 10135 10134 10156 10136 10134 11171 10153 10135 11172 11171 10135 11182 11172 10135 10135 10166 11182 10135 10136 10166 10136 10162 10166 10136 10156 10162 10151 10139 10137 10152 10151 10137 10137 10138 10152 10159 10152 10138 10160 10159 10138 10161 10160 10138 10138 10145 10161 10138 10142 10145 10151 10148 10139 10139 10140 11163 10141 10140 10139 10148 10141 10139 11168 11163 10140 10140 11166 11168 10140 11165 11166 10140 10141 11165 10141 10149 11165 10141 10148 10149 10146 10145 10142 10142 10143 10146 10143 10144 10146 11175 10146 10144 11176 11175 10144 11178 11176 10144 10144 11160 11178 10145 10154 10161 10155 10154 10145 11179 10155 10145 10145 10146 11179 10146 11175 11179 10151 10150 10147 10147 10148 10151 10149 10148 10147 10153 10149 10147 10149 11157 11165 11158 11157 10149 10149 10153 11158 10150 10151 11184 10158 10156 10150 10150 10157 10158 11184 10157 10150 10151 10152 10159 10151 10159 11184 11171 11158 10153 10154 10155 11183 12112 10161 10154 12984 12112 10154 10154 12106 12984 10154 11183 12106 11179 11175 10155 10155 11175 11183 10156 10158 10162 10163 10158 10157 12111 10163 10157 10157 11184 12111 10164 10162 10158 10170 10164 10158 10171 10170 10158 10158 10163 10171 11185 11184 10159 10159 10160 11185 10160 10161 12112 12112 11185 10160 10162 10165 10166 10162 10164 10165 11187 10171 10163 12123 11187 10163 12991 12123 10163 10163 12111 12991 10169 10165 10164 10170 10169 10164 10169 10166 10165 12110 11182 10166 10166 11186 12110 10166 10167 11186 10168 10167 10166 10169 10168 10166 14632 11186 10167 10167 13005 14632 10167 10168 13005 10168 13004 13005 13009 13004 10168 10168 11195 13009 10168 10169 11195 11200 11195 10169 10169 10170 11200 10170 10171 11200 10171 11195 11200 13009 11195 10171 13880 13009 10171 10171 13006 13880 10171 11187 13006 11209 11205 10172 11210 11209 10172 11211 11210 10172 11212 11211 10172 10172 10196 11212 10172 10195 10196 10172 10173 10195 10174 10173 10172 11205 10174 10172 10198 10195 10173 10173 10179 10198 10173 10174 10179 10190 10179 10174 11205 10190 10174 10184 10177 10175 10177 10176 10175 10175 10176 10186 10186 10185 10175 10185 10181 10175 10175 10181 10182 10175 10182 11194 11194 10184 10175 10187 10186 10176 10192 10187 10176 10194 10192 10176 11202 10194 10176 10176 10184 11202 10176 10177 10184 10178 10186 10187 10191 10186 10178 10178 10190 10191 10178 10179 10190 10180 10179 10178 10193 10180 10178 10178 10187 10193 10179 10197 10198 10179 10180 10197 10201 10197 10180 11224 10201 10180 10180 10193 11224 10181 10185 10189 10183 10182 10181 10189 10183 10181 11199 11194 10182 10182 11198 11199 10182 11197 11198 10182 11192 11197 10182 10183 11192 10183 11191 11192 10183 10189 11191 10184 11194 11202 10185 10186 10189 10186 10188 10189 10191 10188 10186 10202 10193 10187 10206 10202 10187 10187 10199 10206 10187 10192 10199 11204 11196 10188 10188 10191 11204 11196 10189 10188 11196 11191 10189 11190 10191 10190 10190 11189 11190 11205 11189 10190 10191 11201 11204 10191 11190 11201 10204 10199 10192 10192 10194 10204 11229 11224 10193 10193 11216 11229 10193 10202 11216 10194 10203 10204 12131 10203 10194 10194 12125 12131 10194 11202 12125 11215 10196 10195 11220 11215 10195 10195 10200 11220 10195 10198 10200 11214 11212 10196 11223 11214 10196 10196 11215 11223 10201 10198 10197 10201 10200 10198 10199 10204 10206 11225 11220 10200 13029 11225 10200 10200 11226 13029 10200 11221 11226 10200 10201 11221 11224 11221 10201 10202 10206 11216 10205 10204 10203 12132 10205 10203 12133 12132 10203 10203 12131 12133 10204 10205 10206 11222 10206 10205 13024 11222 10205 10205 12132 13024 11222 11216 10206 12143 10212 10207 12145 12143 10207 10207 10208 12145 10209 10208 10207 10212 10209 10207 13040 12145 10208 10208 12144 13040 10208 11232 12144 10208 10209 11232 10209 10210 11232 10210 11231 11232 10211 11234 11235 13049 11248 10212 13922 13049 10212 10212 11236 13922 11237 11236 10212 12148 11237 10212 10212 12143 12148 10213 11233 11234 11243 11239 10215 11247 11243 10215 11244 10218 10216 12161 11244 10216 13067 12161 10216 10217 10219 12162 10220 10219 10218 12156 10220 10218 10218 11246 12156 10218 11245 11246 10218 11244 11245 10219 12159 12162 10219 10220 12159 10220 12156 12159 10221 10222 10223 11251 10223 10222 12168 11254 10223 12169 12168 10223 10223 11251 12169 10225 11250 13067 10225 10234 11250 10225 10226 10234 10227 10236 10238 10227 10228 10236 10228 10232 10236 10228 10230 10232 10228 10229 10230 10230 10231 10232 10233 10232 10231 11261 10233 10231 10231 11257 11261 10232 10233 10236 10240 10236 10233 10248 10240 10233 11264 10248 10233 10233 11263 11264 10233 11262 11263 10233 11261 11262 10234 10235 13085 13087 11250 10234 10234 13086 13087 10234 13085 13086 10235 11274 13085 10240 10238 10236 10238 10240 10241 11284 11283 10239 10239 10240 11284 10241 10240 10239 10240 10247 11284 10248 10247 10240 10243 12180 12182 10243 10244 12180 10245 10244 10243 12181 10245 10243 10243 11274 12181 13084 11274 10243 10243 12182 13084 12181 11270 10245 10246 10249 10259 10246 10248 10249 10246 10247 10248 10247 10275 11284 10247 10263 10275 10248 11264 11267 10250 10249 10248 11267 10250 10248 10249 10251 10259 10249 10250 10251 10265 10251 10250 11265 10265 10250 11267 11265 10250 10268 10259 10251 10251 10265 10268 10252 10253 10255 10254 10253 10252 12181 10254 10252 10252 11270 12181 10257 10255 10253 12189 10257 10253 10253 10254 12189 12190 12189 10254 10254 12181 12190 12194 10261 10256 12195 12194 10256 13093 12195 10256 10256 12189 13093 10256 10257 12189 11276 11274 10258 11301 10260 10259 10259 10268 11301 11295 10277 10260 11301 11295 10260 12194 11291 10261 11281 11277 10262 10262 10267 11281 10263 10274 10275 10263 10264 10274 11271 10268 10265 10265 11265 11271 11286 11269 10266 10266 11285 11286 11293 11281 10267 10267 10273 11293 12199 11301 10268 13098 12199 10268 10268 11278 13098 12184 11278 10268 10268 11271 12184 11288 11285 10269 10269 10271 11288 10269 10270 10271 10278 10271 10270 10271 11287 11288 11308 11287 10271 10271 11307 11308 10271 10287 11307 10271 10278 10287 11292 10279 10272 12196 11293 10273 12202 12196 10273 12203 12202 10273 10273 10280 12203 11300 10275 10274 11294 11284 10275 11300 11294 10275 10276 10277 11295 11295 10282 10276 12200 11299 10279 10279 11292 12200 10280 10281 12203 10281 11316 12203 10281 11315 11316 11305 10283 10282 12204 11305 10282 10282 11304 12204 10282 11303 11304 10282 11295 11303 10283 10285 10289 10283 10284 10285 11305 10284 10283 10286 10285 10284 10290 10286 10284 12207 10290 10284 10284 12204 12207 10284 11305 12204 10285 10286 10289 10292 10289 10286 10286 10291 10292 10286 10290 10291 10287 10293 11307 12224 11311 10288 12233 12224 10288 10288 10297 12233 10301 10300 10289 10289 10292 10301 12208 11306 10290 10290 12207 12208 11306 10291 10290 11314 10292 10291 10291 11306 11314 11312 10301 10292 11314 11312 10292 12231 11307 10293 10293 12230 12231 12239 11320 10294 10294 11299 12239 10314 10310 10295 13124 10314 10295 10295 10296 13124 10296 12233 13124 10296 11323 12233 10297 10298 12233 12240 12233 10298 10298 11334 12240 10298 10311 11334 11325 11324 10301 10301 11312 11325 10304 10303 10302 12247 10304 10302 12283 12247 10302 10302 11340 12283 10302 10303 11340 10303 10307 10312 10303 10304 10307 10303 10312 11340 12247 12214 10304 11329 10308 10305 12243 11329 10305 11322 11315 10306 10306 10309 11322 10308 11329 11333 10309 11321 11322 12257 11321 10309 10309 11341 12257 12240 11334 10311 12258 12240 10311 10311 10322 12258 10311 10315 10322 10312 10328 11340 12258 10322 10313 10313 10314 12258 13124 12258 10314 10316 10317 10319 10317 10318 11330 10320 10319 10317 11330 10320 10317 12254 10326 10319 10319 11338 12254 10319 10320 11338 11339 11338 10320 10320 11332 11339 10320 11331 11332 10320 11330 11331 13152 11360 10321 10321 12278 13152 12281 11352 10323 10323 12259 12281 10324 10335 11363 11345 10330 10324 10324 11343 11345 11344 11343 10324 12260 11344 10324 10324 11364 12260 10324 11363 11364 10325 10326 11354 12255 11354 10326 10326 12254 12255 11349 10328 10327 10327 10333 11349 11349 11340 10328 11345 11337 10330 12282 10337 10331 10331 12273 12282 10331 10332 12273 10332 11354 12273 11355 11349 10333 10333 10338 11355 10333 10334 10338 11372 11363 10335 10351 10339 10336 10336 10340 10351 10336 10337 10340 11377 10340 10337 11378 11377 10337 12282 11378 10337 10338 10342 11355 10338 10341 10342 10351 10350 10339 11381 10351 10340 12294 11381 10340 10340 11377 12294 10343 10342 10341 10344 10343 10341 11356 11355 10342 11358 11356 10342 10342 10343 11358 11366 11358 10343 11373 11366 10343 10343 10352 11373 10343 10344 10352 10353 10352 10344 12303 11375 10345 10345 11384 12303 10345 10346 11384 11390 11384 10346 11391 11390 10346 10360 10355 10347 10361 10360 10347 11376 10361 10347 12291 11372 10348 10348 11385 12291 12305 11385 10349 10349 11379 12305 11380 11379 10349 10350 11381 11386 10350 10351 11381 10352 12306 12307 10352 11387 12306 10352 11382 11387 10352 10353 11382 12295 11373 10352 12307 12295 10352 10353 10365 11382 11405 10364 10354 10354 10355 11405 10355 11396 11405 10355 10360 11396 12312 11392 10356 10356 12311 12312 13185 12311 10356 10356 12314 13185 10356 11393 12314 11402 11401 10357 10357 11395 11402 10358 10359 11395 11402 11395 10359 10359 10364 11402 11397 11396 10360 10360 10361 11397 10361 11385 11397 10361 11376 11385 11388 10365 10362 11414 11388 10362 10362 11398 11414 10362 10363 11398 10363 10369 11398 10379 10369 10363 11403 11402 10364 11406 11403 10364 10364 11404 11406 11405 11404 10364 11388 11382 10365 11415 10383 10366 11416 11415 10366 10366 10367 11416 10367 11408 11416 10367 11399 11408 12333 10373 10368 10368 11413 12333 10369 10370 11398 10371 10370 10369 10389 10371 10369 10369 10379 10389 12332 11398 10370 12368 12332 10370 10370 10371 12368 10371 11429 12368 10371 10389 11429 10372 10384 11417 12333 11418 10373 10387 10376 10374 10375 11422 11423 10375 10376 11422 10376 11421 11422 10376 10387 11421 11427 10388 10377 10377 11426 11427 10377 10378 11426 10378 11425 11426 10382 10381 10380 10391 10390 10381 10381 10382 10391 11430 10391 10382 10382 10383 11430 10383 11415 11430 11439 11417 10384 11441 11439 10384 10384 10385 11441 10385 10403 11441 11436 10392 10386 10387 11419 11421 11420 11419 10387 12364 10412 10388 10388 12343 12364 10388 11427 12343 12346 10402 10390 10390 12340 12346 10390 11430 12340 10390 10391 11430 11436 11435 10392 10397 10394 10393 10393 10396 10397 10393 10395 10396 11438 11407 10394 12369 11438 10394 10394 11444 12369 10394 10397 11444 10404 10396 10395 10405 10404 10395 11423 10405 10395 10404 10397 10396 10397 10409 11444 10397 10404 10409 11455 10400 10398 11456 11455 10398 10398 10436 11456 10445 10436 10398 11474 10445 10398 10398 10399 11474 10400 10399 10398 13243 11474 10399 13244 13243 10399 13249 13244 10399 10399 13246 13249 10399 10400 13246 10400 12382 13245 10400 11455 12382 10400 13245 13246 10415 10407 10401 12377 10415 10401 10401 10424 12377 10401 10416 10424 11467 11445 10402 10402 11446 11467 12346 11446 10402 10403 11440 11441 10403 11433 11440 11448 11433 10403 10403 10426 11448 10410 10409 10404 10404 10408 10410 10404 10405 10408 10405 11423 11424 11449 10408 10405 12371 11449 10405 10405 11437 12371 10405 11424 11437 11471 10423 10406 10406 11461 11471 10408 10410 10418 10408 10417 10418 11449 10417 10408 11450 11444 10409 10409 10411 11450 10409 10410 10411 11460 11450 10411 10411 11459 11460 10411 10419 11459 12365 11462 10412 10412 12364 12365 10413 11453 12367 11456 10436 10414 12377 11456 10415 10446 10424 10416 10427 10418 10417 11449 10427 10417 10418 10427 10430 11459 10421 10419 10421 10420 10419 10432 10421 10420 10421 10432 11459 10442 10434 10422 11476 10442 10422 10422 10423 11476 10423 11472 11476 10423 11471 11472 10424 11455 12377 12382 11455 10424 10424 10446 12382 11457 10437 10425 11469 11448 10426 10439 10430 10427 11475 10439 10427 12383 11475 10427 10427 12373 12383 10427 10428 12373 10429 10428 10427 11449 10429 10427 12378 12373 10428 10428 10429 12378 13242 12378 10429 10429 12372 13242 10429 11449 12372 10439 10431 10430 11460 10432 10431 11470 11460 10431 10431 10439 11470 11460 11459 10432 10454 10441 10433 10459 10454 10433 10433 10442 10459 10445 10443 10435 10435 10436 10445 10437 11457 11458 10438 10447 10448 11475 11470 10439 10440 10441 10454 11480 10459 10442 10442 11476 11480 11489 10461 10443 10443 10444 11489 10445 10444 10443 13254 11489 10444 13255 13254 10444 10444 13243 13255 10444 11474 13243 10444 10445 11474 13245 12382 10446 11479 10452 10449 10449 10450 11479 11484 11479 10450 10450 10453 11484 10451 11479 11487 10451 10452 11479 11487 10462 10451 11485 11484 10453 11493 10471 10454 10454 10457 11493 10459 10457 10454 11490 11486 10455 10455 10467 11490 11492 11488 10456 10456 11491 11492 11494 11493 10457 10457 10458 11494 10459 10458 10457 12387 11494 10458 10458 11480 12387 10458 10459 11480 10461 11489 11495 11505 10468 10462 11506 11505 10462 12396 11506 10462 10462 11487 12396 10464 10465 11481 10466 10465 10464 10476 10466 10464 12390 11481 10465 12418 12390 10465 10465 11523 12418 10465 10466 11523 10466 10476 10485 11497 10501 10469 10469 10472 11497 10501 10470 10469 12425 10498 10470 10470 10499 12425 10501 10499 10470 11494 10472 10471 10471 11493 11494 11498 11497 10472 10472 11494 11498 11499 10483 10473 11522 11499 10473 10473 10482 11522 13281 12398 10474 10474 13275 13281 10474 11499 13275 10474 10483 11499 12398 10475 10474 13276 11501 10475 10475 12398 13276 10476 10477 10485 10478 10489 11503 10481 10480 10479 11508 11507 10480 12407 11508 10480 10480 12406 12407 10480 10481 12406 10481 10497 12406 10482 10514 11522 10484 11500 12417 10488 11511 11524 10489 10490 11512 12395 11503 10489 10489 11512 12395 10490 10521 11512 10491 10494 10508 10495 10494 10491 10491 10492 10495 10493 10492 10491 10508 10493 10491 11519 10495 10492 10492 10493 11519 10508 10506 10493 10493 10507 11519 10493 10506 10507 10510 10508 10494 10494 10496 10510 10494 10495 10496 10512 10496 10495 11519 10512 10495 10511 10510 10496 10512 10511 10496 12424 12406 10497 10497 11521 12424 14081 11521 10498 14894 14081 10498 10498 14082 14894 14083 14082 10498 10498 12425 14083 13288 12425 10499 10499 12436 13288 10499 10500 12436 10501 10500 10499 10500 11520 12436 10500 10501 11520 10501 11509 11520 10501 11497 11509 10504 10503 10502 10503 10504 11514 10504 11504 11514 11517 11515 10505 11525 11517 10505 10505 11514 11525 10506 10508 10509 10507 11518 11519 10507 11515 11518 10523 10522 10510 11531 10523 10510 10510 10511 11531 10511 10512 12421 12431 11531 10511 10511 12421 12431 10512 11519 12421 10535 10516 10513 10516 10514 10513 12437 11522 10514 10514 10515 12437 10516 10515 10514 10515 10516 11536 13306 12437 10515 10515 11536 13306 10516 11535 11536 11510 10518 10517 12438 11510 10517 12443 12438 10517 10517 11539 12443 10517 10525 11539 11528 10520 10518 10519 10527 10529 11529 10527 10519 10519 11528 11529 10519 10520 11528 10531 10530 10521 10521 10530 11512 10522 10524 10532 10522 10523 10524 10523 11531 11532 11532 10524 10523 10533 10532 10524 11532 10533 10524 10525 10537 11539 10526 11529 11530 10526 10527 11529 10528 10527 10526 12445 10553 10526 10526 12439 12445 10526 11530 12439 10527 10528 10529 12395 11512 10530 12447 12395 10530 10532 10533 10534 10533 12440 12441 10533 11532 12440 10541 10534 10533 12441 10541 10533 10548 10539 10534 10550 10548 10534 11534 10550 10534 10534 10540 11534 10541 10540 10534 10552 10545 10536 10537 10538 11539 12449 11539 10538 10549 10547 10539 10559 10549 10539 11540 10559 10539 10539 10550 11540 10539 10548 10550 11541 11534 10540 12441 11541 10540 10540 10541 12441 11537 11535 10542 11549 11537 10542 10542 10543 11549 10544 10543 10542 10543 11548 11549 10543 11547 11548 11542 10551 10545 10545 10552 11542 11546 10558 10546 10546 10554 11546 10547 10556 10567 10547 10549 10556 10567 10566 10547 10559 10556 10549 10550 11534 11540 11551 11542 10552 14110 11551 10552 10552 12448 14110 10552 11544 12448 13293 11544 10552 10552 11533 13293 10553 12444 12446 12445 12444 10553 10565 10555 10554 10554 10563 10565 10555 10565 10584 10556 10559 10569 10587 10567 10556 11555 11554 10557 10557 10560 11555 10559 10568 10569 11540 10568 10559 12466 11555 10560 11566 11564 10561 10583 10565 10563 10563 10582 10583 10563 10564 10582 10586 10582 10564 10565 10583 10584 12459 11552 10568 10568 12454 12459 10568 12453 12454 10568 11540 12453 11552 10569 10568 10569 11552 11567 11548 11547 10570 12471 11548 10570 10570 11574 12471 10573 10572 10571 11569 10573 10571 11570 11569 10571 13334 12467 10573 10573 11569 13334 10575 10576 12474 12474 10581 10575 12475 12474 10576 10576 10577 12475 11563 11562 10577 10577 10578 11563 10577 11572 12475 10577 11562 11572 12468 11563 10578 10578 11565 12468 10578 10579 11565 10579 11564 11565 12473 11570 10580 13337 12473 10580 13338 13337 10580 10580 10581 13338 10581 12474 13338 10589 10583 10582 10582 10588 10589 10585 10584 10583 11573 10585 10583 10583 10589 11573 10584 10585 12469 10585 11573 12469 11582 10589 10588 11583 11582 10588 12477 11573 10589 10589 11582 12477 11584 10591 10590 10590 10592 11584 11578 11574 10591 11584 11578 10591 11585 11584 10592 10592 10597 11585 11589 10595 10593 10593 11588 11589 10593 10594 11588 10594 11580 11588 10595 11589 12486 11579 10596 10595 12486 11579 10595 11579 10599 10596 11591 11585 10597 11594 11591 10597 10610 10600 10598 10598 10599 10610 10619 10610 10599 10599 10618 10619 11579 10618 10599 10609 10608 10600 10610 10609 10600 10601 10602 10612 10603 10602 10601 11619 10603 10601 12508 11619 10601 10601 10612 12508 10602 10603 10624 10624 10612 10602 12503 10604 10603 10603 11619 12503 10603 10611 10624 11593 10606 10604 12490 11593 10604 10604 12487 12490 12501 12487 10604 12503 12501 10604 10604 10606 10607 12492 11607 10605 10605 11593 12492 10605 10606 11593 10607 10606 10605 10608 10609 10621 10609 10610 10619 10609 10619 10621 10611 10612 10624 10613 10612 10611 12509 12508 10612 12526 12509 10612 12537 12526 10612 10612 11630 12537 11631 11630 10612 10612 10613 11631 10613 10630 11631 10632 10630 10613 10614 10615 10620 11632 10620 10615 11633 11632 10615 12510 11633 10615 10664 10638 10616 10616 10650 10664 10616 10625 10650 10616 10617 10625 10617 10633 11657 10649 10625 10617 11657 10649 10617 11609 10619 10618 11620 11609 10618 11621 11620 10618 10618 11595 11621 10618 11579 11595 10623 10621 10619 11634 10623 10619 10619 11609 11634 12527 11608 10620 10620 11632 12527 10623 10622 10621 10634 10633 10622 11634 10634 10622 10622 10623 11634 10625 10649 10650 10626 10627 10648 11695 10648 10627 10627 11694 11695 10627 10638 11694 12574 12560 10628 12576 12574 10628 10628 12575 12576 10628 11677 12575 11678 11677 10628 10628 11665 11678 10628 10631 11665 10628 10629 10631 10630 10629 10628 12560 10630 10628 10629 10630 10632 11639 11631 10630 11656 11639 10630 12560 11656 10630 10631 10635 11665 10633 10636 11657 10633 10634 10636 11643 11635 10634 10634 11634 11643 11635 10636 10634 11678 11665 10635 11679 11678 10635 10635 10637 11679 10636 11649 11658 10636 11635 11649 11658 11657 10636 11693 10672 10637 10638 10664 11694 10639 10640 10644 10640 10642 10644 10643 10642 10641 10645 10643 10641 10653 10645 10641 10641 10652 10653 10642 10643 10644 11624 10644 10643 11651 11624 10643 11660 11651 10643 10643 10645 11660 11672 11660 10645 10645 11669 11672 10645 10653 11669 10651 10650 10649 11696 10651 10649 10649 11666 11696 10649 11658 11666 10649 11657 11658 11710 10664 10650 11712 11710 10650 10650 10651 11712 10651 11711 11712 11713 11711 10651 10651 11696 11713 11721 10653 10652 11721 11669 10653 11699 11690 10655 10655 10666 11699 11690 10667 10656 13424 10660 10657 13431 13424 10657 10657 10658 13431 10658 13425 13431 10658 11691 13425 10659 11677 11692 12575 11677 10659 12577 12575 10659 10659 10660 12577 11692 10661 10659 13424 12577 10660 11692 10662 10661 11692 10663 10662 10663 11678 11679 11692 11678 10663 11708 11694 10664 11709 11708 10664 11710 11709 10664 10665 11673 11697 12572 11699 10666 12579 12572 10666 10666 10674 12579 12580 11702 10667 10667 11690 12580 12588 10682 10668 10668 11700 12588 10682 10669 10668 10681 10675 10669 10682 10681 10669 10670 12583 13419 10670 11703 12583 11706 11703 10670 10671 10672 10676 10676 10673 10671 11693 10676 10672 10673 10676 11693 10674 11698 12579 11715 10690 10677 10678 10679 12617 12613 12603 10678 12617 12613 10678 10679 10691 12619 12619 12617 10679 10680 11689 11698 10680 11687 11689 10680 11684 11687 10680 10687 11684 12588 11706 10682 11686 10687 10684 12605 11686 10684 13452 12605 10684 13453 13452 10684 10684 10685 13453 10686 10685 10684 13473 13453 10685 10685 11731 13473 10685 10695 11731 10697 10695 10685 10685 10686 10697 11686 11684 10687 11737 10707 10688 12626 11737 10688 13485 12626 10688 10688 12604 13485 10688 11724 12604 10688 11722 11724 11718 10698 10689 10689 11717 11718 10689 10690 11717 10690 11715 11717 10691 10693 11728 10691 10692 10693 10691 11728 12619 10694 10693 10692 10700 10694 10692 10693 10694 11728 10694 11727 11728 10694 11726 11727 10694 10700 11726 11732 11731 10695 10695 10702 11732 10695 10696 10702 10697 10696 10695 11733 10702 10696 10696 10697 11733 10697 10701 11733 10698 11718 11725 10706 10699 10698 11725 10706 10698 10706 10705 10699 12647 11732 10702 14291 12647 10702 10702 10737 14291 10710 10709 10704 10705 10706 11734 11738 11734 10706 10706 11725 11738 10708 10717 11742 10719 10718 10709 10720 10719 10709 10709 10710 10720 10722 10720 10710 10728 10722 10711 10711 10727 10728 10724 10723 10712 10713 10716 10725 12638 12635 10714 10714 10715 12638 10725 10716 10714 11745 10725 10714 12635 11745 10714 10715 11742 12638 12639 11742 10717 10717 10718 12639 10718 10719 12643 12643 12639 10718 10719 10720 10721 10719 10721 12643 10722 10721 10720 13507 12643 10721 13508 13507 10721 10721 11746 13508 10721 10722 11746 10722 10728 11746 11749 10729 10723 12646 11749 10723 10723 10724 12646 10724 11741 12646 11745 10732 10725 10732 10731 10726 11747 10728 10727 11748 11747 10727 10727 10729 11748 10728 11747 12644 12648 11746 10728 10728 12644 12648 11749 11748 10729 13506 11754 10730 10730 13505 13506 10730 11739 13505 12659 11755 10731 10731 12636 12659 10731 11745 12636 10731 10732 11745 11756 10735 10733 12660 11756 10733 10733 10740 12660 10734 10735 10741 10742 10741 10735 11758 10742 10735 10735 11757 11758 10735 11756 11757 12670 10739 10736 12671 12670 10736 10736 11762 12671 10736 10744 11762 10736 10743 10744 10737 10738 14291 10739 10738 10737 15071 14291 10738 15088 15071 10738 10738 13518 15088 10738 10739 13518 10739 12670 13518 12673 12660 10740 10745 11765 12663 10745 11759 11765 12663 11764 10745 10747 10767 11763 10748 11767 11769 11769 10749 10748 12695 10751 10749 10749 11779 12695 10749 11777 11779 10749 11769 11777 11789 10753 10750 10750 10751 11789 12697 11789 10751 12698 12697 10751 10751 12695 12698 10752 10754 11766 10755 10754 10752 10752 10753 10755 10756 10755 10753 12700 10756 10753 10753 11790 12700 10753 11789 11790 11770 11766 10754 12676 11770 10754 10754 11781 12676 10754 10756 11781 10754 10755 10756 11782 11781 10756 12699 11782 10756 12700 12699 10756 10759 10758 10757 10768 10759 10757 10757 10760 10768 11791 10776 10758 10758 10759 11791 10759 10768 11791 10769 10768 10760 12668 10778 10762 10763 10764 11788 11772 10765 10763 11788 11772 10763 11773 10766 10765 10765 11772 11773 11774 10767 10766 10766 11773 11774 11774 11763 10767 10768 10769 11791 10769 10772 11791 12691 11784 10770 10770 11768 12691 10792 10783 10771 10773 10772 10771 10783 10773 10771 10772 10773 11791 10783 10776 10773 10773 10776 11791 13555 12705 10774 10774 11793 13555 10774 10775 11793 11795 11793 10775 10775 10785 11795 10783 10782 10776 10777 10793 10794 12709 10793 10777 10777 10778 12709 10778 12668 12709 10779 10786 10787 10779 10780 10786 10798 10797 10780 10780 10790 10798 10780 10788 10790 10797 10786 10780 10789 10788 10781 10782 10783 10791 10792 10791 10783 10786 10785 10784 10787 10786 10784 11797 11795 10785 10785 10786 11797 10786 10795 11797 10796 10795 10786 11803 10796 10786 10786 10797 11803 10788 10789 10790 11798 10790 10789 12710 11798 10789 11799 10798 10790 10790 11798 11799 10792 10805 11806 13540 12704 10793 10793 12709 13540 11807 11797 10795 10795 10796 11807 11809 11807 10796 10796 11803 11809 11804 11803 10797 10797 10798 11804 10798 11799 11804 11805 10802 10799 12725 11805 10799 13580 12725 10799 10799 10800 13580 10801 10800 10799 10802 10801 10799 10800 12730 13580 10800 12728 12730 10800 11808 11811 10800 10801 11808 11805 11802 10802 11806 10804 10803 11806 10805 10804 11822 10821 10807 10807 10814 11822 10807 10813 10814 10808 10809 11815 10810 10809 10808 12729 11815 10809 10809 10816 12729 10809 10810 10816 11817 10812 10811 10811 11814 11817 11821 10820 10812 12732 11821 10812 10812 11817 12732 10815 10814 10813 10833 10815 10813 12741 11822 10814 13607 12741 10814 10814 12740 13607 10814 10815 12740 10815 10833 12740 10816 10826 12729 10816 10822 10826 10838 10829 10817 11818 10838 10817 10817 10827 11818 11828 11816 10818 11831 11828 10818 10818 10819 11831 10820 11821 11832 10825 10823 10821 11822 10825 10821 11823 10826 10822 11845 11834 10824 13621 11845 10824 10824 12754 13621 13632 11823 10825 10825 12741 13632 10825 11822 12741 10826 11824 12742 10826 11823 11824 12742 12729 10826 10827 12731 12734 10827 11812 12731 12734 11818 10827 10828 10829 10838 10830 10829 10828 11833 10830 10828 11842 11833 10828 12743 11842 10828 10828 12738 12743 10828 10838 12738 10829 10830 10831 10845 10831 10830 11833 10845 10830 10845 10839 10831 10832 11835 12755 10833 11836 12740 10833 10834 11836 10834 10841 11836 11838 10843 10835 10835 10836 11838 10836 10837 11838 10837 10860 11838 10838 12734 12738 10838 11818 12734 10839 10844 10848 10845 10844 10839 11837 11836 10841 12763 11837 10841 10841 10842 12763 12769 12763 10842 10842 11860 12769 10842 10878 11860 11838 10860 10843 10861 10848 10844 11857 10861 10844 10844 10845 11857 10845 11846 11857 11848 11846 10845 10845 11841 11848 10845 11833 11841 10862 10855 10846 10846 10847 10862 10847 10861 10862 10847 10848 10861 10851 10850 10849 10858 10851 10849 10864 10858 10849 10850 10851 10852 10881 10852 10851 10884 10881 10851 10851 10858 10884 10852 10881 10882 10853 10854 10869 10853 10869 11851 10862 10857 10855 10873 10863 10857 10857 10862 10873 10858 10864 10884 10870 10868 10859 11851 10870 10859 13639 10862 10861 10861 11859 13639 10861 11858 11859 10861 11857 11858 10898 10873 10862 12770 10898 10862 13640 12770 10862 13647 13640 10862 10862 13639 13647 10863 10873 10874 10887 10884 10864 10888 10887 10864 10864 10865 10888 10905 10888 10865 10914 10905 10865 10865 10866 10914 11861 10914 10866 10867 10868 11867 10868 11850 11867 10868 10870 11850 10869 10870 11851 10871 10870 10869 10870 11849 11850 10870 10871 11849 11852 11849 10871 10908 10874 10873 10873 10897 10908 10898 10897 10873 11864 10879 10875 10875 10876 11864 10877 10876 10875 10899 10877 10875 10912 10899 10875 10875 10879 10912 12769 11864 10876 13635 12769 10876 10876 10877 13635 10877 10899 10900 14430 13635 10877 10877 13641 14430 10877 12779 13641 10877 11879 12779 10877 10900 11879 10878 10879 11860 11864 11860 10879 10882 10881 10880 10912 10882 10880 10880 10899 10912 10900 10899 10880 10880 10883 10900 10880 10881 10883 10884 10883 10881 10883 10886 10900 10883 10885 10886 10887 10885 10883 10883 10884 10887 10904 10886 10885 10885 10887 10904 10947 10900 10886 10886 10909 10947 10932 10909 10886 10949 10932 10886 10886 10931 10949 10886 10921 10931 10886 10913 10921 10886 10905 10913 10886 10904 10905 10887 10888 10904 10905 10904 10888 11866 10893 10889 10889 11865 11866 10889 10890 11865 10889 10914 11861 10889 10893 10914 10890 10895 11865 10891 10892 10922 10893 10892 10891 10892 10894 10922 11866 10894 10892 10892 10893 11866 10931 10921 10893 10950 10931 10893 10893 10913 10914 10921 10913 10893 11866 10895 10894 11866 11865 10895 10897 10906 10908 10907 10906 10897 11868 10907 10897 10897 10898 11868 12773 11868 10898 10898 12771 12773 10898 12770 12771 11883 11879 10900 10900 10910 11883 10947 10910 10900 10901 10984 10995 10901 10977 10984 10901 10902 10977 10903 10902 10901 10975 10903 10901 10994 10975 10901 10995 10994 10901 10902 10976 10977 10902 10948 10976 10902 10932 10948 10902 10903 10932 10946 10932 10903 10973 10946 10903 10975 10973 10903 10914 10913 10905 10919 10908 10906 10906 10916 10919 10906 10907 10916 10918 10916 10907 11870 10918 10907 10907 11868 11870 10909 10910 10947 10911 10910 10909 10946 10911 10909 10909 10932 10946 13658 11883 10910 10910 11884 13658 10910 10911 11884 12788 11884 10911 10911 10973 12788 10911 10946 10973 11869 10923 10915 10915 11850 11869 11867 11850 10915 10920 10919 10916 10929 10920 10916 10930 10929 10916 10916 10917 10930 10918 10917 10916 11870 10930 10917 10917 10918 11870 10923 11886 11887 12781 11886 10923 13659 12781 10923 13660 13659 10923 10923 13645 13660 10923 11869 13645 11887 10924 10923 11887 10933 10924 11873 11872 10925 10925 10935 11873 10962 10945 10926 12778 10962 10926 10926 10927 12778 10927 10928 12778 10928 10930 12778 10928 10929 10930 10930 11870 12778 10963 10949 10931 10964 10963 10931 10931 10950 10964 10949 10948 10932 11887 10951 10933 10935 10952 11873 10938 10937 10936 10954 10938 10936 10955 10954 10936 10936 10937 10955 10937 11876 11877 10937 10942 11876 10937 10938 10942 11874 10955 10937 12777 11874 10937 10937 11877 12777 13666 11878 10939 10939 12783 13666 12784 12783 10939 12785 12784 10939 10939 10940 12785 10941 10940 10939 11878 10941 10939 10940 11882 12785 10940 10960 11882 10940 10959 10960 10940 10943 10959 10940 10941 10943 11875 10943 10941 11878 11875 10941 10944 10943 10942 10942 11875 11876 10942 10943 11875 10943 10944 10959 10945 10961 10971 10962 10961 10945 10948 10963 10976 10948 10949 10963 11885 10979 10951 11899 11885 10951 10951 11886 11899 11887 11886 10951 10952 10966 11873 10952 10953 10966 10954 10955 10969 10955 10958 10969 11874 10958 10955 10956 10957 13662 10958 10957 10956 12782 10958 10956 13665 12782 10956 10956 13662 13665 10957 10958 12775 10957 12775 13662 10958 11874 12776 11891 10969 10958 12782 11891 10958 12776 12775 10958 11888 11882 10960 10960 10970 11888 10982 10971 10961 10961 10962 10982 12778 10982 10962 10963 10964 10976 10964 10965 10976 11896 10976 10965 10965 10978 11896 11880 11873 10966 11881 11880 10966 10966 10967 11881 11907 11881 10967 10967 10981 11907 10967 10980 10981 10968 10969 11891 10970 10971 11888 11890 11888 10971 10971 10982 11890 12800 12788 10973 10973 11893 12800 10973 10974 11893 10975 10974 10973 10974 10993 11893 10994 10993 10974 10974 10975 10994 11896 10985 10976 10983 10977 10976 11002 10983 10976 11895 11002 10976 10976 10985 11895 10977 10983 10984 10978 10985 11896 10988 10981 10980 10981 11906 11907 10981 10997 11906 10981 10996 10997 10981 10988 10996 13683 11890 10982 13688 13683 10982 10982 13663 13688 13664 13663 10982 10982 12778 13664 10995 10984 10983 11002 10995 10983 10985 11009 11895 11902 11004 10986 10986 11897 11902 11900 11006 10989 11007 10992 10990 11916 11007 10990 10990 11892 11916 11911 11892 10990 11913 11911 10990 10990 10991 11913 10992 10991 10990 11920 11913 10991 10991 10992 11920 11007 10999 10992 10992 11017 11920 10992 10999 11017 10993 11892 11893 11916 11892 10993 10993 11008 11916 10993 10994 11008 10994 10995 11008 10995 11007 11008 10995 10999 11007 10995 10998 10999 11001 10998 10995 11002 11001 10995 10997 11903 11906 10998 11001 11012 11000 10999 10998 11018 11000 10998 11020 11018 10998 10998 11012 11020 11029 11017 10999 10999 11000 11029 11000 11028 11029 11000 11018 11028 11001 11002 11003 11895 11003 11002 11895 11009 11003 11025 11023 11004 11921 11025 11004 11004 11917 11921 11004 11902 11917 11005 11006 12793 11910 11909 11005 13687 11910 11005 11005 12793 13687 11006 11900 12793 11916 11008 11007 11010 11015 11027 11927 11015 11011 11030 11020 11012 11012 11021 11030 11013 11023 11024 11925 11918 11014 11014 11026 11925 11926 11027 11015 11927 11926 11015 11017 11029 11920 11040 11028 11018 11018 11019 11040 11020 11019 11018 11019 11020 11945 11068 11040 11019 11953 11068 11019 11019 11949 11953 11019 11945 11949 11929 11059 11020 11020 11030 11929 11020 11059 11945 11021 11022 11030 11929 11030 11022 11022 11031 11929 11025 11024 11023 12810 11947 11024 11024 12809 12810 11024 11025 12809 13710 12809 11025 11025 11921 13710 11026 11035 11932 11932 11925 11026 11926 11039 11027 11040 11029 11028 11029 11069 11920 11029 11040 11069 12817 11929 11031 11031 11930 12817 11034 11033 11032 11041 11034 11032 11033 11034 11931 11034 11041 11931 11035 11036 11933 11933 11932 11035 11036 11038 11935 11036 11037 11038 11935 11933 11036 11042 11038 11037 11038 11042 11935 11941 11056 11039 13716 11941 11039 11039 11926 13716 11040 11068 11069 11041 11930 11931 11042 11053 11935 11935 11053 11043 11938 11935 11043 11043 11045 11938 11043 11044 11045 11053 11052 11043 11044 11046 11047 11054 11045 11044 11044 11047 11054 11940 11938 11045 11045 11939 11940 11045 11054 11939 11055 11054 11047 11047 11049 11055 12824 12822 11048 11048 11941 12824 11048 11056 11941 11063 11056 11048 11048 11049 11063 11050 11049 11048 12822 11050 11048 11049 11050 11055 11073 11063 11049 11050 11054 11055 11939 11054 11050 12823 11939 11050 11050 12822 12823 11051 11060 11061 11063 11057 11056 11057 11063 11064 12817 11930 11058 11058 11929 12817 11058 11059 11929 11949 11945 11059 11954 11949 11059 11059 11950 11954 11062 11061 11060 11061 11062 11951 11956 11951 11062 11062 11948 11956 11062 11947 11948 11078 11064 11063 11063 11073 11078 11065 11075 11079 11065 11066 11075 11067 11066 11065 11079 11067 11065 11066 11074 11075 11066 11067 11074 11944 11074 11067 11067 11943 11944 11972 11943 11067 11067 11079 11972 11075 11074 11068 11953 11075 11068 11944 11069 11068 11068 11074 11944 12821 12819 11069 12828 12821 11069 11069 11952 12828 11069 11942 11952 11944 11942 11069 12819 11920 11069 11072 11071 11070 12830 11072 11070 12832 12830 11070 12833 12832 11070 11070 11957 12833 12831 11959 11072 11072 12830 12831 11075 11953 11955 11976 11079 11075 11977 11976 11075 11075 11962 11977 11075 11955 11962 11076 11951 11956 11974 11972 11079 11975 11974 11079 11984 11975 11079 11985 11984 11079 11079 11976 11985 13723 11958 11082 11082 11083 13723 11083 12851 13723 12857 11091 11084 12858 12857 11084 11084 12000 12858 11084 11086 12000 11084 11085 11086 11967 11086 11085 11086 11999 12000 11086 11980 11999 11086 11967 11980 11089 11088 11087 11997 11095 11090 11998 11997 11090 11090 11996 11998 11090 11091 11996 12857 11996 11091 11092 11097 11994 11954 11950 11093 11963 11954 11093 11093 11094 11963 11979 11963 11094 11997 11100 11095 12009 11097 11096 11096 12008 12009 11096 11101 12008 12009 11994 11097 12010 12005 11098 12011 12010 11098 12022 11109 11099 11099 12014 12022 11099 12013 12014 11099 12012 12013 11099 11100 12012 11100 11997 12012 11102 11103 11105 12015 12011 11102 12016 12015 11102 11102 11105 12016 11104 11114 12017 11104 11111 11114 11105 11106 12016 11107 11106 11105 11108 11107 11105 12021 12016 11106 12025 12021 11106 11106 11116 12025 11106 11107 11116 11107 11110 11116 11107 11108 11110 11118 11110 11108 11119 11118 11108 11108 11109 11119 12029 11119 11109 12030 12029 11109 12909 12030 11109 11109 12022 12909 11121 11116 11110 11110 11118 11121 11112 12024 12034 11112 12023 12024 12020 12017 11114 11114 11120 12020 12032 11117 11115 12040 12032 11115 11115 11141 12040 11115 11128 11141 11129 11128 11115 11115 11121 11129 11115 11116 11121 11117 11116 11115 11116 11117 12025 12028 12025 11117 12032 12028 11117 11122 11121 11118 11118 11119 11122 12029 11122 11119 13761 12020 11120 11120 12019 13761 11121 11122 11129 11122 11128 11129 12036 11128 11122 12920 12036 11122 11122 12029 12920 12926 12925 11123 12931 12926 11123 11123 11124 12931 11123 12925 12930 11124 11134 12931 12047 11133 11125 11125 12046 12047 11125 12037 12046 11125 11126 12037 11127 11126 11125 11126 11127 11130 11126 12033 12037 11143 11141 11128 12036 11143 11128 12940 12045 11132 11132 12939 12940 11132 12047 12939 11132 11133 12047 11134 12044 12931 12052 12044 11135 11162 11148 11136 12045 11162 11136 11137 11138 11140 11139 11138 11137 12058 11139 11137 11137 11161 12058 11137 11160 11161 11137 11140 11160 12040 11141 11138 12049 12040 11138 11138 11139 12049 11141 11140 11138 12059 12049 11139 11139 12056 12059 12058 12056 11139 11140 11142 11160 11140 11141 11142 11143 11142 11141 11142 11143 11144 11142 11153 11160 11142 11144 11153 12043 11154 11143 11143 12036 12043 11154 11144 11143 11155 11153 11144 11144 11154 11155 11145 11146 12063 11147 11146 11145 11156 11147 11145 12071 12063 11146 12083 12071 11146 11146 11147 12083 11147 11156 12083 11162 11156 11148 12055 11151 11149 11149 11164 12055 11151 11150 11149 11150 11151 11152 11151 12055 12948 12057 11152 11151 12948 12057 11151 12057 11159 11152 12062 11160 11153 11153 11155 12062 12043 12041 11154 12943 11155 11154 11154 12050 12943 12051 12050 11154 11154 12041 12051 12954 12062 11155 11155 12943 12954 11156 12072 12083 11156 12064 12072 11156 11162 12064 11166 11165 11157 12068 11166 11157 11157 11173 12068 11157 11158 11173 11174 11173 11158 11158 11171 11174 12058 11161 11159 11159 12057 12058 12073 11178 11160 11160 11169 12073 11170 11169 11160 12062 11170 11160 11162 12045 12064 11167 11164 11163 11168 11167 11163 12061 12055 11164 11164 11167 12061 12068 11168 11166 12070 12061 11167 11167 11168 12070 11168 12069 12070 11168 12068 12069 11169 12953 13831 11169 11170 12953 12087 12073 11169 13831 12087 11169 12954 12953 11170 11170 12062 12954 11171 11172 11174 12084 12064 11172 12085 12084 11172 11172 11182 12085 12064 11174 11172 12086 12068 11173 12098 12086 11173 11173 12066 12098 11173 12064 12066 11173 11174 12064 11175 11177 11183 11175 11176 11177 11180 11177 11176 11181 11180 11176 11176 11178 11181 12107 11183 11177 11177 11180 12107 12073 11181 11178 12985 12107 11180 11180 12977 12985 12978 12977 11180 11180 12087 12978 11180 12073 12087 11180 11181 12073 12110 12085 11182 12107 12106 11183 11184 11185 12111 12112 12111 11185 12113 12110 11186 13853 12113 11186 14632 13853 11186 13007 13006 11187 11187 13001 13007 11187 12123 13001 11203 11201 11188 13002 11203 11188 11188 12130 13002 11188 12129 12130 11188 12128 12129 11188 11189 12128 11190 11189 11188 11201 11190 11188 11189 11209 12128 11189 11205 11209 11193 11192 11191 11196 11193 11191 12122 11197 11192 11192 11193 12122 11193 12117 12122 11193 11196 12117 11194 11199 11202 11196 12116 12117 11196 11204 12116 11197 12122 13000 13000 11198 11197 13873 11199 11198 11198 13000 13873 12125 11202 11199 13878 12125 11199 11199 13873 13878 11201 11203 11204 12114 11204 11203 13002 12114 11203 12119 12116 11204 11204 12115 12119 11204 12114 12115 11206 11209 11210 12128 11209 11206 12129 12128 11206 13015 12129 11206 11206 11207 13015 11208 11207 11206 11210 11208 11206 13885 13015 11207 11207 13884 13885 11207 13012 13884 11207 12126 13012 12127 12126 11207 11207 11208 12127 11208 11213 12127 11208 11212 11213 11208 11211 11212 11208 11210 11211 11214 11213 11212 12136 12127 11213 13022 12136 11213 13023 13022 11213 11213 12142 13023 11213 12140 12142 11213 11214 12140 11214 11223 12140 11215 11217 11223 11225 11217 11215 11215 11220 11225 11216 12138 12139 11216 11222 12138 12139 11229 11216 12140 11223 11217 12141 12140 11217 11217 11218 12141 11219 11218 11217 11225 11219 11217 13026 12141 11218 13027 13026 11218 11218 11219 13027 13028 13027 11219 13030 13028 11219 15534 13030 11219 11219 13907 15534 11219 11225 13907 11228 11226 11221 11221 11224 11228 13024 12138 11222 11229 11228 11224 11225 13906 13907 11225 13029 13906 13906 13029 11226 11226 13031 13906 11226 11227 13031 11228 11227 11226 13903 13031 11227 11227 11230 13903 11227 11228 11230 11228 11229 11230 12139 11230 11229 11230 13902 13903 11230 12139 13902 12147 11232 11231 11231 11235 12147 12147 12144 11232 11240 11234 11233 11233 11238 11240 12149 11235 11234 12150 12149 11234 11234 11240 12150 12149 12147 11235 11236 12146 14694 11236 11237 12146 16547 13922 11236 11236 14698 16547 11236 14695 14698 11236 14694 14695 11237 12145 12146 11237 12143 12145 12148 12143 11237 11241 11240 11238 11243 11241 11238 11238 11239 11243 12151 12150 11240 12152 12151 11240 12160 12152 11240 11240 11241 12160 13056 12160 11241 11241 11242 13056 11243 11242 11241 13059 13056 11242 11242 12166 13059 11242 12165 12166 11242 11243 12165 11243 11247 12165 12155 11245 11244 12161 12155 11244 12154 11246 11245 12155 12154 11245 11246 12154 13050 13054 12156 11246 11246 13051 13054 11246 13050 13051 11247 12164 13064 11247 11249 12164 13064 12165 11247 13087 11256 11248 13930 13087 11248 14715 13930 11248 11248 13937 14715 11248 13049 13937 11249 11259 12164 11260 11259 11249 13929 13067 11250 13930 13929 11250 11250 13087 13930 13071 12169 11251 11251 13070 13071 12173 11258 11252 11252 11253 12173 11254 11253 11252 11253 12170 12173 11253 11254 12170 11254 12168 12170 13084 12182 11255 13086 13084 11255 11255 11256 13086 13087 13086 11256 11257 11258 11261 13076 11261 11258 11258 12172 13076 12173 12172 11258 13080 13074 11259 11259 12171 13080 11259 11260 12171 13064 12164 11259 13074 13064 11259 12178 12171 11260 11260 12175 12178 13077 11262 11261 11261 13076 13077 13078 11263 11262 11262 13077 13078 12174 11268 11263 13078 12174 11263 11268 11264 11263 11268 11267 11264 11265 11266 11271 11267 11266 11265 11272 11271 11266 11266 11268 11272 11266 11267 11268 12174 11272 11268 12185 11273 11269 11269 11286 12185 11271 12177 12184 11271 11272 12177 11272 12176 12177 11272 12174 12176 12185 12178 11273 13090 12181 11274 11274 11275 13090 11276 11275 11274 11274 13084 13085 13095 13090 11275 11275 11276 13095 11276 12188 13095 11276 11277 12188 13106 12188 11277 11277 12191 13106 11277 11281 12191 11278 13096 13952 13097 13096 11278 11278 12183 13097 12184 12183 11278 11278 11279 13098 11280 11279 11278 13952 11280 11278 13108 13098 11279 11279 11280 13108 11280 13965 14753 13966 13965 11280 11280 13952 13966 14753 13108 11280 11281 11293 12191 11309 11290 11282 11319 11309 11282 12197 11319 11282 11282 11283 12197 11283 12192 12197 11283 11284 12192 11284 11294 12192 11289 11286 11285 11285 11288 11289 12186 12185 11286 11286 11289 12186 11289 11288 11287 12193 11289 11287 11287 11297 12193 11287 11296 11297 12221 11296 11287 11287 12220 12221 11287 11308 12220 13092 12186 11289 13104 13092 11289 11289 11298 13104 12193 11298 11289 12194 11292 11291 11292 12194 12200 12196 12191 11293 12225 12192 11294 11294 11300 12225 12198 11303 11295 12199 12198 11295 11295 11301 12199 13105 13104 11296 13962 13105 11296 14743 13962 11296 11296 13103 14743 11296 13102 13103 11296 12221 13102 11298 11297 11296 13104 11298 11296 11297 11298 12193 11299 12232 12239 11299 12223 12232 11299 12200 12223 12224 11318 11300 11300 11311 12224 11300 11318 12225 11302 12227 13113 13110 12227 11302 11302 11303 13110 11304 11303 11302 13113 11304 11302 11303 12198 13110 13113 12204 11304 12211 11314 11306 13116 12211 11306 11306 12208 13116 12220 11308 11307 12231 12220 11307 11319 11318 11309 12224 11323 11310 11310 11318 12224 11312 11313 11325 11314 11313 11312 12241 11325 11313 11313 11331 12241 11332 11331 11313 11313 11314 11332 12209 11332 11314 12211 12209 11314 11317 11316 11315 11322 11317 11315 13115 12203 11316 11316 12238 13115 11316 12237 12238 13123 12237 11316 11316 11317 13123 11322 11321 11317 11317 11321 13123 11318 11319 12225 12197 12192 11319 11319 12192 12225 11321 12249 13123 12250 12249 11321 12257 12250 11321 11323 12224 12233 11328 11326 11324 11324 11327 11328 11324 11325 11327 12241 11327 11325 13125 11336 11326 11326 11328 13125 12244 11328 11327 11327 12241 12244 11328 11347 13125 13136 11347 11328 11328 12244 13136 11350 11333 11329 12256 11350 11329 11329 12248 12256 11329 12243 12248 11348 11331 11330 11331 11348 12241 12242 11339 11332 11332 12209 12242 11333 11350 11351 11335 11336 12259 11336 12252 12259 11336 12251 12252 13125 12251 11336 12245 11348 11337 11337 11346 12245 11337 11345 11346 11338 12246 12254 11338 11339 12246 11339 12242 13118 11339 12234 12246 12236 12234 11339 13119 12236 11339 11339 13118 13119 11340 11349 12283 12269 12257 11341 12285 12280 11342 11342 11361 12285 12280 12269 11342 11347 11345 11343 11343 11344 11347 11344 12251 13125 13135 12251 11344 13146 13135 11344 11344 12260 13146 13125 11347 11344 11347 11346 11345 13136 12245 11346 11346 11347 13136 12245 12241 11348 11349 12266 12283 11349 11357 12266 11349 11356 11357 11349 11355 11356 13120 11351 11350 11350 12256 13120 13120 12278 11351 12281 11353 11352 11371 11362 11353 12281 11371 11353 11354 12255 12273 12268 11357 11356 11356 11365 12268 11356 11358 11365 11357 12265 12266 12268 12265 11357 11367 11365 11358 11358 11366 11367 13159 11374 11359 11359 12286 13159 11359 11360 12286 13153 12286 11360 11360 13152 13153 12287 12285 11361 11361 11370 12287 11372 11371 11363 11371 11364 11363 12281 12259 11364 11364 11371 12281 12271 12260 11364 11364 12259 12271 11365 11367 12268 11368 11367 11366 11369 11368 11366 11373 11369 11366 12277 12268 11367 11367 11368 12277 11368 11369 12284 11368 12276 12277 12290 12276 11368 11368 12289 12290 13156 12289 11368 11368 12296 13156 11368 12284 12296 11369 11373 12284 13161 12287 11370 11370 12299 13161 11370 11375 12299 12291 11376 11372 12295 12284 11373 11409 11383 11374 12308 11409 11374 11374 12297 12308 12298 12297 11374 13161 12298 11374 11374 13159 13161 12302 12299 11375 12303 12302 11375 12291 11385 11376 11377 12292 12294 12293 12292 11377 11377 11378 12293 11378 12282 12293 13177 12305 11379 11379 12316 13177 11379 11380 12316 12325 12316 11380 11380 11407 12325 12300 11386 11381 11381 12294 12300 11388 11387 11382 11409 11389 11383 13193 12303 11384 11384 12312 13193 11384 11400 12312 11384 11390 11400 12304 11397 11385 12305 12304 11385 13182 12306 11387 11387 12339 13182 11387 12318 12339 11387 11388 12318 11388 11414 12318 11409 11399 11389 11390 11391 11400 11391 11392 11400 12312 11400 11392 11393 11394 12314 12321 12314 11394 11394 11401 12321 11396 11404 11405 12323 11404 11396 12324 12323 11396 11396 12315 12324 11396 11397 12315 11397 12304 12315 12318 11414 11398 12339 12318 11398 11398 12332 12339 11409 11408 11399 11401 12320 12321 11401 11403 12320 11401 11402 11403 12322 12320 11403 11403 11406 12322 12323 11406 11404 12334 12322 11406 11406 12323 12334 11407 11438 12325 13199 11416 11408 13200 13199 11408 11408 12308 13200 11408 11409 12308 14021 13201 11410 11410 12341 14021 11410 11417 12341 11410 11411 11417 11412 11411 11410 13201 11412 11410 11411 11412 11413 13202 11413 11412 13209 13202 11412 11412 13201 13209 13202 12333 11413 12340 11430 11415 11415 11416 12340 13199 12340 11416 11417 11439 12341 12349 11434 11418 11418 12333 12349 11443 11421 11419 12342 11443 11419 11419 11420 12342 11420 11435 12342 11443 11422 11421 11424 11423 11422 12352 11424 11422 12354 12352 11422 11422 11442 12354 11443 11442 11422 13232 11437 11424 11424 12352 13232 12335 11426 11425 12336 12335 11425 11425 12328 12336 11425 12317 12328 11425 12300 12317 12343 11427 11426 11426 12335 12343 12368 11429 11428 11428 12362 12368 12370 12362 11428 11433 11432 11431 11440 11433 11431 12341 11440 11431 13229 12341 11431 11431 13220 13229 11431 12348 13220 11431 11432 12348 11432 12346 12347 11432 11433 12346 11432 12347 12348 11433 11446 12346 11448 11446 11433 12351 11436 11434 13230 12351 11434 11434 12349 13230 12351 12342 11435 11435 11436 12351 13232 12371 11437 12356 12325 11438 11438 12355 12356 12369 12355 11438 11439 11440 12341 11441 11440 11439 11442 12342 12354 11442 11443 12342 11444 12374 13233 11444 11450 12374 13233 12369 11444 11458 11457 11445 11467 11458 11445 11446 11447 11467 11448 11447 11446 11447 11448 11469 11447 11458 11467 11468 11458 11447 11469 11468 11447 11449 12371 12372 11450 12373 12374 11450 11460 12373 11451 11463 11464 11451 11452 11463 12376 11463 11452 13253 12376 11452 11452 11473 13253 11453 11454 12370 11454 12362 12370 11454 12360 12362 11454 12358 12360 11454 11464 12358 11455 11456 12377 12383 12373 11460 11460 11470 12383 12375 11471 11461 11466 11464 11463 12384 11466 11463 13241 12384 11463 11463 12376 13241 11464 11465 12358 11466 11465 11464 12366 12358 11465 11465 11466 12366 13240 12366 11466 11466 12384 13240 11470 11475 12383 12375 11472 11471 11480 11476 11472 12385 11480 11472 13247 12385 11472 11472 12375 13247 11473 11482 13253 11477 11478 11484 11479 11478 11477 11487 11479 11477 14057 11487 11477 11477 11484 14057 11478 11479 11484 11480 12386 12387 11480 12385 12386 12390 11483 11481 13266 13253 11482 11482 11483 13266 11483 12390 13266 11484 12389 14057 11484 11485 12389 11485 12388 12389 11485 11488 12388 11486 11490 12391 13256 12396 11487 13257 13256 11487 14057 13257 11487 11488 11492 12388 13268 11495 11489 11489 13254 13268 14056 12391 11490 11490 13269 14056 11490 12402 13269 11490 12393 12402 12397 11492 11491 12397 12388 11492 12392 11498 11494 11494 12387 12392 12401 11502 11495 13267 12401 11495 13268 13267 11495 11496 11503 12393 11497 11498 11509 12428 11509 11498 11498 12408 12428 12409 12408 11498 12410 12409 11498 11498 12392 12410 11499 12414 13275 11499 11522 12414 13282 12417 11500 11500 12399 13282 11500 11501 12399 12400 12399 11501 13276 12400 11501 12419 11511 11502 12420 12419 11502 11502 12401 12420 12403 12393 11503 11503 12394 12403 12395 12394 11503 11504 11513 11514 11504 11506 11513 11504 11505 11506 12396 11513 11506 11507 11508 13274 14065 13274 11508 14068 14065 11508 14070 14068 11508 11508 13278 14070 11508 12407 13278 12427 11520 11509 12428 12427 11509 12429 11523 11510 12438 12429 11510 12419 11524 11511 11526 11514 11513 12396 11526 11513 11526 11525 11514 11515 11517 11518 14897 13284 11516 11516 13287 14897 11516 12405 13287 11516 12404 12405 11516 11525 12404 11516 11517 11525 11518 11517 11516 13284 11518 11516 11527 11519 11518 13284 11527 11518 11519 11527 12421 13288 12436 11520 11520 12426 13288 12427 12426 11520 13280 12424 11521 14891 13280 11521 11521 14080 14891 14081 14080 11521 12415 12414 11522 12437 12415 11522 13296 12418 11523 11523 12429 13296 11529 11528 11524 12420 11529 11524 11524 12419 12420 11525 11526 12404 13277 12404 11526 11526 12396 13277 12423 12421 11527 13284 12423 11527 12420 11530 11529 11530 12420 13283 14061 12439 11530 11530 13283 14061 12434 11532 11531 11531 12431 12434 11532 12432 12440 12434 12432 11532 13295 13293 11533 11541 11540 11534 11537 11536 11535 11536 12412 13306 13313 12412 11536 11536 13311 13313 11536 11537 13311 13312 13311 11537 11537 11549 13312 11539 12442 12443 12449 12442 11539 13314 12453 11540 11540 13310 13314 11540 11541 13310 11541 13309 13310 11541 13307 13309 11541 12441 13307 11543 13293 13294 11543 11544 13293 11545 11544 11543 14912 11545 11543 15793 14912 11543 11543 14902 15793 11543 13294 14902 15812 12448 11544 11544 11545 15812 16806 15812 11545 11545 14912 16806 11556 11549 11548 12471 11556 11548 11549 11556 13312 11580 11568 11550 11550 11559 11580 11550 11551 11559 11560 11559 11551 12460 11560 11551 14110 12460 11551 12470 11567 11552 11552 12461 12470 11552 12459 12461 12456 12450 11553 12463 12456 11553 11553 11554 12463 12464 12463 11554 11554 11555 12464 12465 12464 11555 12466 12465 11555 14106 13312 11556 11556 12462 14106 11556 11557 12462 11558 11557 11556 13327 11558 11556 11556 13326 13327 11556 12471 13326 11557 11558 14144 14939 12462 11557 11557 14144 14939 11558 13327 13343 11558 13343 14144 11581 11580 11559 12472 11581 11559 11559 11560 12472 11560 12460 13333 13332 12472 11560 13333 13332 11560 13321 12466 11561 13322 13321 11561 13330 13322 11561 11562 11563 14141 11562 11571 11572 13340 11571 11562 14141 13340 11562 11563 14131 14141 11563 12468 14131 11564 11566 12476 12476 11565 11564 12499 12468 11565 13344 12499 11565 11565 12489 13344 13342 12489 11565 11565 12476 13342 13335 12476 11566 11566 12469 13335 13336 13334 11569 11569 12473 13336 11569 11570 12473 13341 12474 11571 11571 13340 13341 12474 11572 11571 11572 12474 12475 12491 12469 11573 11573 12477 12491 11574 11578 12471 12484 12483 11575 14142 12484 11575 14143 14142 11575 11575 14121 14143 11575 14119 14121 11575 11576 14119 11577 11576 11575 12483 12478 11575 11576 11577 14114 11576 14114 14119 11577 12470 14114 11578 11586 12471 11587 11586 11578 11578 11584 11587 12496 11595 11579 11579 12486 12496 11580 11581 11588 11581 12472 12479 12480 11588 11581 12481 12480 11581 11581 12479 12481 12482 12477 11582 11582 11583 12482 11583 11593 12482 12492 11593 11583 11584 11585 11587 11592 11587 11585 11585 11591 11592 13343 12471 11586 13346 13343 11586 11586 12485 13346 11586 11587 12485 12494 12485 11587 11587 11592 12494 12480 11589 11588 12495 12486 11589 12497 12495 11589 12498 12497 11589 11589 12480 12498 11590 13359 13360 11590 12511 13359 11590 11591 12511 11592 11591 11590 13360 11592 11590 11591 11594 12511 14154 12494 11592 14155 14154 11592 11592 13360 14155 12488 12482 11593 12490 12488 11593 11594 11608 12511 12528 11621 11595 11595 12505 12528 11595 12496 12505 11599 11598 11597 11611 11599 11597 11597 11600 11611 11597 11598 11600 12517 11602 11598 11598 11599 12517 11602 11600 11598 12524 12517 11599 11599 11612 12524 11599 11611 11612 11613 11611 11600 11600 11601 11613 11602 11601 11600 11614 11613 11601 11601 11603 11614 11604 11603 11601 11601 11602 11604 11602 12518 12519 11602 12517 12518 12519 11604 11602 11617 11614 11603 11603 11605 11617 11603 11604 11605 11606 11605 11604 12519 11606 11604 11618 11617 11605 11626 11618 11605 11605 11606 11626 12525 11626 11606 13353 12525 11606 11606 12520 13353 11606 12519 12520 12527 12511 11608 11643 11634 11609 11609 11620 11643 11625 11612 11611 11611 11613 11625 11612 11625 12524 12542 11625 11613 11613 11614 12542 11614 11646 12542 11647 11646 11614 11648 11647 11614 11614 11615 11648 11616 11615 11614 11617 11616 11614 12547 11648 11615 11615 12536 12547 11615 11629 12536 11615 11616 11629 11616 11618 11629 11616 11617 11618 11618 11627 11629 11618 11626 11627 11619 12502 12503 13350 12502 11619 11619 12499 13350 12500 12499 11619 12508 12500 11619 11620 11621 12528 11620 11635 11643 11636 11635 11620 12535 11636 11620 11620 12529 12535 11620 12528 12529 11624 11623 11622 11622 11623 11638 11623 11624 11637 11623 11637 11638 11650 11637 11624 11651 11650 11624 12542 12524 11625 12525 11627 11626 11627 11628 11629 13370 11628 11627 11627 12525 13370 13376 11629 11628 11628 13374 13376 11628 13370 13374 13389 13387 11629 11629 13376 13389 12559 12536 11629 13387 12559 11629 11630 11639 11640 11630 11631 11639 11630 11640 12537 11632 11642 12527 11632 11633 11642 12533 11642 11633 12538 12533 11633 13371 12538 11633 11633 13358 13371 11633 12510 13358 12567 11649 11635 11635 11636 12567 11636 12535 12541 13394 12567 11636 13405 13394 11636 11636 12541 13405 11650 11638 11637 11638 11653 11654 11638 11652 11653 11638 11651 11652 11638 11650 11651 11656 11641 11639 11641 11640 11639 12550 12537 11640 13381 12550 11640 11640 11641 13381 11641 11656 13390 13390 13381 11641 12533 12527 11642 12578 11673 11644 11644 12569 12578 11644 11672 12569 11644 11661 11672 11644 11645 11661 11645 11660 11661 11645 11654 11660 12545 12542 11646 12557 12545 11646 11646 12548 12557 11646 11647 12548 11647 12547 12548 11647 11648 12547 12568 11666 11649 11649 12567 12568 11666 11658 11649 11659 11652 11651 11660 11659 11651 11652 11659 12551 12551 11653 11652 11655 11654 11653 12551 11655 11653 11654 11659 11660 11654 11655 11659 12551 11659 11655 13403 13390 11656 11656 12560 13403 11672 11661 11660 11662 11663 11674 11664 11663 11662 12552 11664 11662 11662 11674 12552 11688 11676 11663 11689 11688 11663 12561 11689 11663 11663 12553 12561 11663 11664 12553 11676 11674 11663 12554 12553 11664 12555 12554 11664 11664 12552 12555 12568 11668 11666 11716 11696 11666 12584 11716 11666 11666 11667 12584 11668 11667 11666 14226 12595 11667 14995 14226 11667 11667 11668 14995 12595 12584 11667 11668 12568 14995 11669 11670 11672 11671 11670 11669 11721 11671 11669 12569 11672 11670 12585 12569 11670 12586 12585 11670 12587 12586 11670 12596 12587 11670 11670 11671 12596 11671 11721 12596 12578 11697 11673 11674 11685 12552 11674 11675 11685 11676 11675 11674 11675 11680 11685 11683 11680 11675 11684 11683 11675 11687 11684 11675 11675 11676 11687 11688 11687 11676 11677 11678 11692 11680 11681 11685 11682 11681 11680 11683 11682 11680 12552 11685 11681 12570 12552 11681 11681 11682 12570 13440 12570 11682 11682 12592 13440 11682 11683 12592 14233 12592 11683 11683 11684 14233 11684 12605 14233 11684 11686 12605 11687 11688 11689 12571 11698 11689 11689 12561 12571 11690 12566 12580 11690 12556 12566 12557 12556 11690 11690 11699 12557 14212 13425 11691 11691 12573 14212 11707 11695 11694 11708 11707 11694 11716 11713 11696 12590 11714 11697 13446 12590 11697 11697 12578 13446 11698 12571 12579 12572 12557 11699 13441 12588 11700 11700 11701 13441 11702 11701 11700 13442 13441 11701 11701 13416 13442 11701 12580 13416 11701 11702 12580 11703 12581 12583 12582 12581 11703 11703 11704 12582 11705 11704 11703 11706 11705 11703 14223 12582 11704 15020 14223 11704 11704 14228 15020 11704 13441 14228 11704 11705 13441 11705 12593 13441 11705 11706 12593 11706 12588 12593 11720 11715 11707 11707 11708 11720 11708 11709 11720 11709 11719 11720 12607 11719 11709 11709 12599 12607 11709 11710 12599 11710 11723 12599 11710 11712 11723 11723 11712 11711 12600 11723 11711 12601 12600 11711 11711 12594 12601 11711 11713 12594 12595 12594 11713 11713 12584 12595 11713 11716 12584 11724 11722 11714 12590 11724 11714 11720 11717 11715 11719 11718 11717 11720 11719 11717 13474 11725 11718 11718 12606 13474 11718 11719 12606 12607 12606 11719 12597 12596 11721 12608 12599 11723 11723 12600 12608 13462 12604 11724 11724 12591 13462 11724 12590 12591 13474 12623 11725 12623 11738 11725 11730 11729 11726 12624 11730 11726 11736 11727 11726 11726 11729 11736 12621 11728 11727 12625 12621 11727 13482 12625 11727 13488 13482 11727 11727 11736 13488 12621 12619 11728 11729 11730 14277 14284 11736 11729 11729 14278 14284 11729 14277 14278 11730 12628 14277 14244 13473 11731 11731 12622 14244 11731 11732 12622 13492 12622 11732 11732 12647 13492 11734 12627 12630 11734 11738 12627 14288 13488 11736 11736 14286 14288 11736 14284 14286 13486 11739 11737 11737 12626 13486 13487 12627 11738 11738 12623 13487 14293 13505 11739 14294 14293 11739 11739 14290 14294 11739 13486 14290 11743 11741 11740 11744 11743 11740 11741 11743 12646 12641 12638 11742 11742 12639 12641 12667 12655 11743 11743 11752 12667 11753 11752 11743 12657 11753 11743 12655 12646 11743 11745 12635 12636 11746 12649 13508 11746 12648 12649 11747 11748 11750 11747 11750 12644 11748 11749 11750 11751 11750 11749 12646 11751 11749 12645 12644 11750 12653 12645 11750 11750 11751 12653 11751 12646 12653 11752 11753 14314 13515 12667 11752 14313 13515 11752 14315 14313 11752 11752 14314 14315 11753 12657 14314 11754 13510 13511 11754 13506 13510 12672 11768 11755 11755 12659 12672 12669 11757 11756 13513 12669 11756 11756 12660 13513 12661 11758 11757 12669 12661 11757 11760 11759 11758 12662 11760 11758 11758 12661 12662 11759 11761 11765 11759 11760 11761 12662 11761 11760 12662 11765 11761 13531 12671 11762 13542 13531 11762 11762 12681 13542 12677 12673 11763 11763 11774 12677 11769 11767 11764 11777 11769 11764 11764 11775 11777 11776 11775 11764 12663 11776 11764 11765 12662 12663 11768 12672 12691 12676 12656 11770 12689 12681 11771 11771 11784 12689 12678 11773 11772 11772 11788 12678 12677 11774 11773 12678 12677 11773 11778 11777 11775 12685 11778 11775 12686 12685 11775 11775 12684 12686 11775 11776 12684 11776 12674 12684 11776 12663 12674 11777 11778 11779 11780 11779 11778 12685 11780 11778 12696 12695 11779 13557 12696 11779 11779 11780 13557 14349 13557 11780 11780 12685 14349 13545 12676 11781 13546 13545 11781 13552 13546 11781 11781 12701 13552 11781 11782 12701 13556 12701 11782 11782 12703 13556 11782 12699 12703 12690 12689 11784 12691 12690 11784 11785 13549 14345 11785 12692 13549 11785 12678 12692 12683 12678 11785 14346 12683 11785 11785 11786 14346 11787 11786 11785 14345 11787 11785 16022 14346 11786 11786 15142 16022 11786 11787 15142 11787 14345 15142 12694 12678 11788 12697 11790 11789 12703 12700 11790 12707 12703 11790 12708 12707 11790 11790 12697 12708 11792 11796 12718 11792 11795 11796 11792 11793 11795 11794 11793 11792 12718 11794 11792 13569 13555 11793 14357 13569 11793 11793 13574 14357 11793 13570 13574 11793 11794 13570 13576 13570 11794 11794 12718 13576 11797 11796 11795 11796 12714 12718 11796 11797 12714 11797 11807 12714 11798 12710 12711 12711 11799 11798 12727 11804 11799 13578 12727 11799 11799 12721 13578 11799 12711 12721 11800 12713 12722 11800 11801 12713 12712 12710 11800 12722 12712 11800 12715 12713 11801 11802 11805 12717 11803 11804 11809 12726 11809 11804 12727 12726 11804 12725 12717 11805 12720 12714 11807 11807 11809 12720 12726 12720 11809 11813 11812 11810 11812 11819 12731 11812 11813 11819 11813 11816 11819 13595 11817 11814 11814 13581 13595 11814 13575 13581 11815 11825 12728 12729 11825 11815 11820 11819 11816 11828 11820 11816 13601 12732 11817 11817 13595 13601 11819 11820 12731 11820 11828 11829 12734 12731 11820 12738 12734 11820 12744 12738 11820 11820 11829 12744 12739 11832 11821 11821 12735 12739 11821 12732 12735 13632 12760 11823 12748 11824 11823 12759 12748 11823 12760 12759 11823 12748 12747 11824 12747 12742 11824 12742 12736 11825 11825 12729 12742 12733 12728 11825 13602 12733 11825 11825 11826 13602 11827 11826 11825 12736 11827 11825 14390 13602 11826 15180 14390 11826 11826 13603 15180 11826 11827 13603 13604 13603 11827 11827 12737 13604 11827 12736 12737 12753 11830 11828 13621 12753 11828 11828 11845 13621 11828 11834 11845 11828 11831 11834 11830 11829 11828 12752 12744 11829 11829 11844 12752 11829 11830 11844 14404 11844 11830 14405 14404 11830 11830 12753 14405 12739 11835 11832 11833 11840 11841 11842 11840 11833 11835 12739 12755 13609 12740 11836 11836 13608 13609 11836 12757 13608 11836 11837 12757 12758 12757 11837 12763 12758 11837 11839 11842 11843 11839 11840 11842 11841 11840 11839 12749 11841 11839 13617 12749 11839 11839 11843 13617 11841 11847 11848 12762 11847 11841 11841 11854 12762 11856 11854 11841 12749 11856 11841 11842 12743 12750 12750 11843 11842 13619 13617 11843 11843 12750 13619 15206 12752 11844 11844 14404 15206 12766 11857 11846 11846 12765 12766 11846 12762 12765 11846 11847 12762 11848 11847 11846 11849 11853 12764 11849 11852 11853 12764 11850 11849 12764 11869 11850 11852 11871 13644 11872 11871 11852 13644 11853 11852 13644 11869 11853 11853 11869 12764 12765 12762 11854 13637 12765 11854 11854 11855 13637 11856 11855 11854 11855 13633 13637 11855 11856 13633 11856 12749 13620 14422 13633 11856 11856 14418 14422 11856 13629 14418 11856 13620 13629 11863 11858 11857 12766 11863 11857 11863 11862 11858 14433 11859 11858 11858 13638 14433 11858 11862 13638 13648 13639 11859 13657 13648 11859 14437 13657 11859 15234 14437 11859 11859 14433 15234 11860 11864 12769 11862 11863 12765 14425 13638 11862 11862 13637 14425 11862 12765 13637 12766 12765 11863 11868 12772 12774 12773 12772 11868 12774 11870 11868 11869 13644 13645 11870 12774 12778 11871 12780 13644 11871 11873 12780 11871 11872 11873 13686 12780 11873 11873 11880 13686 12777 12776 11874 11877 11876 11875 11878 11877 11875 13646 12777 11877 11877 11878 13646 14440 13646 11878 11878 13666 14440 13641 12779 11879 11879 11883 13641 13677 13659 11880 11880 13668 13677 13669 13668 11880 11880 11881 13669 11880 13659 13686 13679 13669 11881 11881 12798 13679 11881 11908 12798 11881 11907 11908 11882 12784 12785 12790 12784 11882 11882 12789 12790 11882 11889 12789 11882 11888 11889 13658 13641 11883 11884 12788 13658 11885 12786 13672 11885 11899 12786 11898 11897 11885 13672 11898 11885 13667 11899 11886 11886 12781 13667 11890 11889 11888 11889 11890 12789 13683 12789 11890 11901 11900 11891 12782 11901 11891 11894 11893 11892 13693 11894 11892 11892 11911 13693 11893 11894 12800 14462 12800 11894 11894 14448 14462 11894 13698 14448 11894 13693 13698 11897 11898 11902 11917 11902 11898 13671 11917 11898 13672 13671 11898 12787 12786 11899 13667 12787 11899 11900 11901 12793 12794 12793 11901 13680 12794 11901 11901 12782 13680 11903 11904 11906 11905 11904 11903 11914 11905 11903 11919 11914 11903 11908 11906 11904 12798 11908 11904 12799 12798 11904 11904 12797 12799 11904 11905 12797 14460 12797 11905 11905 11924 14460 12806 11924 11905 11905 11923 12806 11905 11914 11923 11908 11907 11906 13694 11915 11909 11909 11910 13694 11910 13692 13694 11910 13691 13692 14461 13691 11910 11910 13687 14461 13701 13693 11911 11911 11912 13701 11913 11912 11911 13708 13701 11912 11912 12818 13708 11912 11913 12818 11913 11920 12818 11914 11922 11923 12803 11922 11914 12804 12803 11914 11914 11919 12804 11928 11927 11915 12805 11928 11915 13694 12805 11915 13699 11921 11917 13700 13699 11917 14463 13700 11917 11917 13684 14463 11917 13671 13684 12812 11919 11918 11918 11925 12812 12812 12804 11919 12819 12818 11920 11921 13699 13710 11924 11923 11922 12811 11924 11922 15285 12811 11922 11922 14469 15285 11922 12803 14469 11923 11924 12806 15280 14460 11924 11924 12811 15280 11925 11932 12812 11926 13713 13716 11926 12808 13713 11926 12807 12808 11926 11928 12807 11926 11927 11928 11928 12801 12807 12802 12801 11928 12805 12802 11928 12813 12812 11932 11932 11933 12813 12814 12813 11933 11933 11934 12814 11935 11934 11933 14472 12814 11934 11934 13712 14472 11934 11936 13712 11934 11935 11936 11938 11936 11935 11936 12816 13712 11936 11937 12816 11938 11937 11936 11937 12815 12816 11937 11940 12815 11937 11938 11940 13715 11940 11939 11939 12823 13715 13715 12815 11940 13721 12824 11941 14488 13721 11941 11941 12825 14488 12827 12825 11941 13716 12827 11941 11973 11952 11942 11942 11943 11973 11944 11943 11942 11943 11970 11973 11972 11970 11943 11946 11947 12810 11948 11947 11946 12829 11948 11946 13718 12829 11946 11946 12810 13718 12839 11956 11948 12842 12839 11948 11948 12829 12842 11955 11953 11949 11949 11954 11955 12837 12828 11952 12838 12837 11952 11952 11970 12838 11973 11970 11952 11963 11955 11954 11963 11962 11955 12839 11966 11956 11957 11958 12833 13723 12833 11958 12831 11960 11959 12831 11961 11960 11968 11967 11961 12846 11968 11961 11961 12831 12846 11979 11977 11962 11962 11963 11979 13745 11995 11964 11964 13740 13745 11964 12841 13740 11964 11966 12841 11995 11965 11964 11966 12839 12841 11981 11980 11967 11982 11981 11967 11983 11982 11967 11967 11969 11983 11967 11968 11969 12846 11969 11968 11992 11983 11969 12848 11992 11969 13727 12848 11969 11969 12846 13727 13728 12838 11970 11970 12849 13728 11970 11971 12849 11972 11971 11970 11971 13739 13744 11971 12864 13739 11971 11993 12864 11971 11974 11993 11971 11972 11974 12850 12849 11971 13728 12850 11971 15314 13728 11971 11971 14506 15314 11971 13744 14506 11974 11975 11993 12865 11993 11975 11975 11984 12865 12004 11985 11976 11976 11978 12004 11976 11977 11978 11979 11978 11977 11978 11994 12004 12869 11999 11980 11980 11981 12869 11981 12006 12869 11981 11988 12006 11981 11982 11988 11990 11988 11982 11992 11990 11982 11982 11983 11992 11984 12002 12865 11984 11985 12002 12004 12002 11985 12856 11987 11986 11986 12855 12856 12856 12851 11987 11988 11990 12006 11989 11990 11992 11991 11990 11989 12863 11991 11989 11989 12848 12863 11989 11992 12848 12872 12006 11990 11990 11991 12872 11991 12860 12872 12863 12860 11991 12874 12864 11993 11993 12865 12874 12009 12004 11994 13745 13741 11995 13731 11998 11996 13732 13731 11996 11996 12857 13732 12868 12012 11997 11997 11998 12868 12880 12868 11998 13731 12880 11998 12862 12000 11999 12869 12862 11999 13735 12858 12000 12000 12862 13735 12876 12003 12001 12001 12009 12876 12001 12004 12009 12001 12002 12004 12003 12002 12001 12002 12003 12865 12875 12865 12003 12876 12875 12003 12005 12010 12867 12887 12869 12006 12006 12872 12887 12007 12008 12017 12009 12008 12007 12884 12009 12007 13752 12884 12007 13753 13752 12007 12007 12020 13753 12007 12017 12020 12884 12876 12009 12879 12867 12010 12885 12879 12010 12010 12011 12885 12011 12015 12885 12012 12868 12880 12881 12013 12012 12012 12880 12881 13757 12014 12013 12013 13755 13757 12013 12881 13755 13759 12022 12014 12014 13757 13759 12888 12885 12015 12900 12888 12015 12015 12016 12900 12016 12026 12900 12016 12021 12026 13761 12019 12018 13770 13761 12018 13761 13753 12020 12021 12025 12026 13759 12909 12022 13762 12024 12023 12023 13758 13762 12024 13762 13773 12035 12034 12024 13773 12035 12024 12028 12026 12025 12026 12027 12900 12028 12027 12026 13765 12900 12027 13777 13765 12027 12027 12898 13777 12899 12898 12027 12027 12028 12899 12028 12032 12899 13779 12920 12029 12029 13759 13779 12029 12030 13759 12030 12909 13759 12039 12033 12031 13781 12039 12031 13783 13781 12031 12031 12035 13783 12032 12898 12899 13786 12898 12032 12032 12932 13786 12032 12060 12932 12032 12059 12060 12032 12049 12059 12032 12040 12049 12038 12037 12033 12039 12038 12033 12035 13773 13783 12920 12042 12036 12036 12041 12043 12042 12041 12036 12048 12046 12037 12037 12038 12048 12942 12048 12038 14549 12942 12038 12038 13781 14549 12038 12039 13781 12041 12042 12051 12042 12920 12934 13801 12051 12042 12042 12934 13801 13796 12931 12044 14561 13796 12044 12044 12053 14561 12044 12052 12053 12066 12064 12045 12045 12065 12066 12940 12065 12045 12048 12047 12046 12047 12048 12939 12942 12941 12048 13811 12939 12048 13812 13811 12048 12048 12941 13812 13808 12943 12050 12050 13801 13808 12050 12051 13801 12054 12053 12052 12063 12054 12052 14570 14561 12053 12053 12054 14570 14577 14570 12054 12054 12947 14577 12054 12063 12947 12055 12061 12948 12058 12057 12056 12060 12059 12056 13797 12060 12056 13800 13797 12056 12056 12057 13800 12057 12948 13800 12933 12932 12060 13797 12933 12060 12950 12949 12061 12061 12070 12950 12949 12948 12061 12063 12071 12947 12084 12072 12064 12098 12066 12065 12065 12086 12098 12065 12067 12086 12951 12067 12065 12065 12940 12951 12067 12068 12086 12069 12068 12067 12951 12069 12067 12069 12951 12962 12952 12070 12069 12962 12952 12069 13813 12950 12070 12070 12952 13813 12961 12947 12071 12071 12096 12961 12071 12083 12096 12102 12083 12072 12103 12102 12072 12072 12084 12103 12078 12077 12074 12079 12078 12074 12074 12075 12079 12076 12075 12074 12077 12076 12074 12960 12079 12075 12964 12960 12075 12075 12955 12964 12971 12955 12075 12075 12076 12971 12076 12089 12971 12076 12088 12089 12099 12088 12076 12076 12077 12099 12077 12080 12099 12077 12078 12080 12094 12080 12078 12078 12079 12094 12958 12094 12079 12960 12958 12079 12966 12965 12080 12080 12094 12966 12080 12091 12099 12092 12091 12080 12095 12092 12080 12080 12081 12095 12082 12081 12080 12965 12082 12080 12100 12095 12081 12967 12100 12081 12081 12082 12967 12972 12967 12082 13827 12972 12082 12082 12965 13827 12097 12096 12083 12973 12097 12083 12083 12102 12973 12108 12103 12084 12084 12085 12108 12109 12108 12085 12110 12109 12085 14609 12978 12087 15447 14609 12087 12087 13831 15447 12090 12089 12088 12099 12090 12088 12089 12968 12971 12970 12968 12089 12089 12104 12970 12089 12090 12104 12986 12104 12090 12090 12979 12986 12090 12091 12979 12099 12091 12090 12091 12105 12979 12091 12093 12105 12091 12092 12093 12095 12093 12092 12093 12101 12105 12093 12095 12101 13828 12966 12094 12094 12958 13828 12095 12100 12101 13833 12961 12096 12096 12097 13833 12097 12973 13833 12990 12101 12100 12100 12974 12990 12975 12974 12100 12981 12975 12100 12100 12967 12981 12980 12105 12101 12995 12980 12101 12101 12989 12995 12990 12989 12101 12102 12103 12982 12976 12973 12102 12982 12976 12102 13841 12982 12103 12103 12108 13841 13840 12970 12104 13848 13840 12104 12104 12987 13848 12104 12986 12987 12986 12979 12105 12988 12986 12105 12105 12980 12988 12106 12107 12985 13844 12984 12106 12106 13839 13844 12106 12985 13839 14612 13841 12108 12108 12109 14612 12109 13843 14612 12109 13842 13843 12109 12113 13842 12109 12110 12113 12111 12983 12991 12111 12112 12983 12984 12983 12112 13853 13842 12113 12124 12115 12114 13002 12124 12114 12997 12119 12115 12998 12997 12115 13859 12998 12115 13867 13859 12115 12115 12124 13867 12118 12117 12116 12119 12118 12116 12117 12118 12122 12118 12121 12122 12999 12121 12118 12118 12997 12999 12118 12119 12997 12120 12999 13000 12120 12121 12999 12122 12121 12120 13000 12122 12120 13011 13001 12123 13864 13011 12123 12123 12996 13864 12123 12991 12996 12124 13003 13867 12124 13002 13003 13886 12131 12125 12125 13878 13886 13013 13012 12126 12126 12127 13013 12127 12134 13013 12135 12134 12127 12136 12135 12127 12129 13014 13016 13015 13014 12129 13016 12130 12129 13003 13002 12130 13883 13003 12130 12130 13016 13883 13018 12133 12131 12131 13017 13018 13886 13017 12131 13896 13024 12132 13897 13896 12132 12132 13018 13897 12132 12133 13018 13884 13013 12134 14650 13884 12134 14664 14650 12134 12134 12135 14664 12135 13894 14664 12135 12136 13894 14671 13894 12136 15521 14671 12136 12136 14675 15521 12136 13020 14675 13021 13020 12136 14674 13021 12136 12136 13898 14674 12136 13022 13898 14677 13900 12137 12137 13901 14677 12137 12138 13901 12139 12138 12137 13900 12139 12137 12138 13025 13901 12138 13024 13025 12139 13899 13902 13900 13899 12139 12140 12141 12142 13026 12142 12141 13026 13023 12142 12144 13036 13040 12144 12147 13036 13042 12146 12145 12145 13040 13042 13042 13041 12146 12146 13041 14694 12147 13035 13036 12147 12149 13035 13044 13035 12149 13047 13044 12149 13048 13047 12149 12149 12150 13048 13056 13048 12150 12150 13055 13056 12150 12151 13055 12151 12153 13055 12151 12152 12153 12160 12153 12152 12153 12160 13055 12154 12155 13050 12155 12161 13050 12156 12158 12159 13054 12158 12156 12159 12158 12157 12162 12159 12157 12163 12162 12157 13061 12163 12157 13925 13061 12157 12157 12158 13925 12158 13054 13925 13056 13055 12160 13060 13050 12161 13927 13060 12161 12161 13067 13927 12162 12163 13063 13063 13062 12162 12163 13061 13933 13933 13063 12163 12167 12166 12165 13066 12167 12165 13075 13066 12165 12165 13064 13075 13931 13059 12166 12166 12167 13931 12167 13065 13931 13066 13065 12167 13072 12170 12168 12168 13071 13072 12168 12169 13071 13072 12173 12170 13081 13080 12171 12171 12179 13081 12171 12178 12179 14718 13076 12172 12172 14717 14718 12172 13073 14717 12172 12173 13073 12173 13072 13073 13079 12176 12174 14721 13079 12174 12174 13940 14721 12174 13078 13940 13079 12177 12176 12177 12183 12184 13941 12183 12177 12177 13079 13941 13088 12179 12178 12178 12185 13088 13088 13081 12179 13090 12190 12181 14731 13097 12183 12183 13941 14731 12185 12187 13088 12185 12186 12187 13089 12187 12186 13091 13089 12186 13092 13091 12186 12187 13081 13088 13082 13081 12187 13089 13082 12187 12188 12195 13095 13106 12195 12188 13094 13093 12189 12189 13090 13094 12189 12190 13090 12191 12201 13106 12222 12201 12191 13111 12222 12191 12191 12196 13111 12201 12200 12194 12194 12195 12201 12195 13093 13095 13106 12201 12195 12196 12202 13111 12198 13107 13110 12198 12199 13107 13964 13107 12199 12199 13109 13964 12199 13098 13109 12200 12222 12223 12200 12201 12222 12202 12203 13111 12203 13115 13117 13112 13111 12203 13117 13112 12203 12226 12207 12204 12227 12226 12204 13113 12227 12204 12205 12211 13116 12205 12210 12211 13119 12210 12205 12205 13114 13119 12205 12206 13114 12207 12206 12205 13116 12207 12205 15598 13114 12206 12206 12207 15598 13116 12208 12207 12207 14754 15598 14755 14754 12207 12207 13968 14755 12207 12226 13968 12209 12210 12242 12211 12210 12209 13118 12242 12210 13119 13118 12210 12212 12213 12215 12214 12213 12212 12217 12215 12213 13967 12217 12213 14758 13967 12213 14759 14758 12213 12213 13970 14759 12213 12214 13970 12214 12247 13970 12215 12216 12230 12217 12216 12215 12231 12230 12216 12216 12220 12231 12216 12218 12220 12219 12218 12216 12216 12217 12219 12229 12219 12217 13099 12229 12217 13967 13099 12217 12218 12228 13102 12218 12219 12228 12221 12220 12218 13102 12221 12218 12229 12228 12219 12232 12223 12222 13112 12232 12222 12222 13111 13112 14753 13968 12226 14756 14753 12226 12226 12227 14756 12227 13964 14756 12227 13110 13964 12228 12229 13100 12228 13100 13102 13969 13101 12229 12229 13099 13969 13101 13100 12229 13115 12239 12232 13117 13115 12232 12232 13112 13117 12233 12258 13124 12233 12240 12258 13127 12246 12234 12234 12235 13127 12236 12235 12234 12235 12236 14765 12235 13126 13127 14769 13126 12235 14770 14769 12235 12235 14765 14770 12236 13119 14765 12239 12238 12237 12243 12239 12237 13122 12243 12237 13123 13122 12237 12238 12239 13115 12245 12244 12241 12256 12248 12243 13122 12256 12243 12244 12245 13136 13128 12254 12246 12246 13127 13128 12247 13138 13970 12247 13137 13138 12247 12283 13137 12249 13121 13123 13144 13121 12249 13986 13144 12249 12249 13158 13986 12249 12250 13158 12250 13148 13158 12250 12257 13148 12253 12252 12251 13135 12253 12251 12252 12253 13149 12271 12259 12252 12252 12260 12271 13149 12260 12252 13984 13149 12253 12253 13135 13984 13128 12255 12254 12255 12272 12273 12255 12261 12272 12262 12261 12255 13128 12262 12255 13121 13120 12256 13123 13121 12256 12256 13122 13123 12257 12270 13148 12257 12269 12270 13149 13146 12260 12261 12264 12272 12261 12262 12264 12262 12263 12264 13128 12263 12262 13128 13127 12263 13979 12264 12263 13980 13979 12263 12263 13126 13980 13127 13126 12263 13155 12272 12264 13988 13155 12264 13990 13988 12264 14775 13990 12264 12264 13979 14775 12267 12266 12265 13134 12267 12265 12265 12274 13134 12265 12268 12274 13137 12283 12266 12266 12267 13137 12267 13132 13137 13133 13132 12267 13134 13133 12267 12277 12274 12268 12279 12270 12269 12280 12279 12269 13154 13148 12270 12270 12279 13154 12293 12273 12272 13155 12293 12272 12293 12282 12273 13143 13134 12274 12274 12275 13143 12276 12275 12274 12277 12276 12274 12275 13141 13143 13147 13141 12275 12275 12290 13147 12275 12276 12290 12278 13120 13152 13160 13154 12279 12279 12280 13160 12280 12285 13160 12284 12295 12296 12285 12287 13160 12286 13154 13159 12286 13153 13154 12287 13159 13160 13161 13159 12287 14781 13151 12288 12288 12289 14781 12290 12289 12288 13151 12290 12288 12289 14004 14781 12289 13156 14004 13150 13147 12290 13151 13150 12290 12300 12294 12292 12301 12300 12292 13999 12301 12292 12292 13166 13999 12292 13162 13166 12292 12293 13162 12293 13155 13162 13156 12296 12295 13164 13156 12295 12295 12307 13164 12297 12298 13165 12319 12308 12297 12297 12302 12319 12297 12299 12302 13165 12299 12297 12298 13161 13165 13165 13161 12299 12300 12301 12317 13187 12317 12301 13999 13187 12301 14011 12319 12302 12302 12303 14011 12303 13193 14011 13177 12315 12304 12304 12305 13177 13164 12307 12306 13183 13164 12306 12306 13182 13183 14019 13200 12308 14020 14019 12308 12308 12309 14020 12310 12309 12308 12319 12310 12308 15667 14020 12309 12309 15666 15667 12309 14802 15666 12309 12310 14802 12310 14011 14802 12310 12319 14011 14014 13184 12311 14015 14014 12311 12311 13185 14015 12313 12312 12311 13184 12313 12311 12312 12313 13193 14012 13193 12313 12313 13184 14012 12314 12321 13185 12315 13177 13186 13186 12324 12315 13186 13177 12316 12316 12325 13186 12317 12326 12328 12327 12326 12317 14016 12327 12317 14796 14016 12317 12317 13178 14796 13179 13178 12317 13187 13179 12317 13194 12321 12320 14017 13194 12320 12320 13203 14017 12320 12322 13203 13194 13185 12321 14018 13203 12322 12322 13195 14018 12322 12334 13195 13211 12334 12323 14830 13211 12323 12323 13196 14830 12323 12324 13196 13198 13196 12324 12324 13186 13198 12325 12356 13186 12336 12328 12326 13205 12336 12326 12326 12327 13205 13206 13205 12327 14016 13206 12327 12329 12338 12345 12329 12330 12338 12331 12330 12329 13168 12331 12329 12329 13167 13168 13190 13167 12329 12329 12345 13190 12330 12337 12338 12330 12331 12337 12331 13171 13180 12331 13170 13171 12331 13168 13170 13180 12337 12331 12332 12361 13192 12368 12361 12332 13175 12339 12332 13192 13175 12332 12350 12349 12333 13221 12350 12333 12333 13202 13221 13204 13195 12334 14026 13204 12334 12334 13211 14026 13213 12343 12335 12335 12336 13213 13225 13213 12336 14028 13225 12336 12336 13212 14028 12336 13205 13212 12361 12338 12337 13192 12361 12337 12337 13180 13192 12361 12344 12338 12338 12344 12345 12339 13176 13182 12339 13175 13176 12347 12346 12340 13199 12347 12340 14839 14021 12341 12341 14836 14839 12341 13229 14836 12342 12351 12363 12363 12354 12342 13213 12364 12343 12344 12361 12362 12358 12345 12344 12360 12358 12344 12362 12360 12344 13216 13190 12345 12345 12357 13216 12358 12357 12345 13217 12348 12347 12347 13207 13217 12347 13199 13207 12348 13217 13220 13231 13230 12349 14032 13231 12349 12349 12350 14032 14852 14032 12350 12350 14039 14852 12350 14024 14039 12350 13221 14024 13230 12363 12351 13236 13232 12352 14041 13236 12352 14044 14041 12352 12352 12353 14044 12354 12353 12352 12353 14033 14044 12353 13224 14033 12353 12363 13224 12353 12354 12363 14832 14027 12355 12355 14046 14832 12355 14045 14046 12355 13234 14045 12355 12369 13234 14027 12356 12355 13198 13186 12356 14027 13198 12356 13226 13216 12357 14029 13226 12357 12357 12359 14029 12357 12358 12359 12366 12359 12358 12359 13228 14029 12359 12366 13228 12368 12362 12361 12363 13223 13224 13230 13223 12363 14047 12365 12364 12364 14035 14047 12364 13213 14035 13238 12375 12365 13239 13238 12365 14047 13239 12365 14851 13228 12366 12366 13240 14851 12369 13233 13234 13237 12372 12371 12371 13232 13237 12372 13237 13242 12378 12374 12373 14034 13233 12374 12374 13242 14034 12374 12378 13242 12375 13238 13247 13248 13241 12376 13251 13248 12376 13253 13251 12376 12379 12380 13239 12381 12380 12379 14048 12381 12379 14859 14048 12379 12379 13239 14859 12380 13238 13239 12380 12381 13238 13247 13238 12381 14050 13247 12381 14861 14050 12381 12381 14048 14861 14038 13240 12384 12384 13241 14038 13258 12386 12385 14052 13258 12385 12385 13247 14052 12410 12392 12386 13258 12410 12386 12392 12387 12386 13259 12389 12388 13260 13259 12388 13270 13260 12388 14054 13270 12388 12388 12397 14054 12389 13259 14869 12389 13257 14057 14053 13257 12389 14058 14053 12389 14869 14058 12389 12390 12418 13266 14056 13252 12391 13252 13250 12391 12403 12402 12393 12447 12444 12394 12394 12395 12447 13298 12403 12394 13303 13298 12394 12394 12444 13303 12396 13256 13277 12397 13273 14054 12416 12400 12398 13281 12416 12398 12398 12400 13276 14076 13282 12399 12399 12416 14076 12399 12400 12416 13283 12420 12401 14060 13283 12401 12401 13267 14060 12402 12430 13269 12402 12403 12430 13302 12430 12403 13303 13302 12403 12403 13298 13303 14067 12405 12404 12404 13277 14067 14898 13287 12405 12405 14067 14898 12424 12407 12406 12407 12424 13278 13292 12428 12408 14073 13292 12408 14892 14073 12408 12408 13261 14892 12408 12409 13261 13262 13261 12409 13263 13262 12409 12409 12410 13263 12410 13258 13263 15831 15822 12411 12411 14100 15831 14924 14100 12411 12411 12412 14924 12413 12412 12411 15822 12413 12411 14091 13306 12412 14918 14091 12412 12412 12413 14918 12412 13313 14924 12413 14917 14918 15818 14917 12413 15822 15818 12413 14086 13275 12414 12414 12415 14086 14091 14086 12415 12415 13306 14091 12415 12437 13306 12416 14074 14076 12416 13281 14074 12417 13282 13295 14059 13266 12418 12418 13297 14059 12418 13296 13297 12421 12422 12431 12423 12422 12421 13300 12431 12422 12422 13299 13300 14077 13299 12422 12422 12423 14077 14078 14077 12423 12423 13284 14078 13280 13278 12424 12425 13288 14083 13290 13288 12426 12426 13289 13290 12426 12427 13289 12427 12428 13289 13292 13289 12428 14092 13296 12429 12429 12438 14092 13283 13269 12430 14061 13283 12430 12430 13302 14061 13300 12434 12431 12434 12433 12432 12432 12435 12440 12432 12433 12435 12433 12434 13301 13301 12435 12433 12434 13300 13301 12441 12440 12435 13308 12441 12435 12435 13301 13308 12438 12451 14092 12438 12443 12451 13302 12445 12439 14061 13302 12439 13308 13307 12441 12451 12443 12442 12452 12451 12442 12442 12449 12452 12444 12445 13303 12445 13302 13303 12448 16805 16824 12448 15812 16805 15836 14110 12448 16828 15836 12448 12448 16824 16828 12449 12450 12452 14103 12452 12450 12450 12456 14103 14914 14092 12451 15795 14914 12451 12451 14919 15795 12451 12452 14919 14931 14919 12452 12452 14103 14931 12455 12454 12453 13314 12455 12453 12454 12455 12459 12461 12459 12455 13324 12461 12455 12455 13315 13324 12455 13314 13315 12456 12457 14103 12458 12457 12456 12463 12458 12456 14111 14103 12457 14112 14111 12457 14126 14112 12457 12457 12458 14126 12458 13328 14126 12458 12463 13328 12460 14110 14935 14935 13333 12460 14114 12470 12461 12461 13323 14114 13324 13323 12461 12462 14101 14106 14932 14101 12462 16834 14932 12462 12462 15853 16834 12462 14946 15853 12462 14939 14946 12463 12464 13328 13329 13328 12464 12464 12465 13329 14113 13329 12465 12465 14107 14113 12465 13319 14107 12465 12466 13319 13320 13319 12466 13321 13320 12466 13331 13330 12467 13365 13331 12467 12467 13334 13365 12468 12499 14131 13348 13335 12469 12469 12491 13348 13343 13326 12471 13332 12479 12472 13367 13336 12473 12473 13337 13367 13341 13338 12474 12476 13335 13342 12477 12482 12491 12478 12483 12493 14124 12481 12479 12479 13332 14124 13347 12498 12480 12480 12481 13347 14124 13347 12481 12482 12488 12491 12483 12484 13357 14954 13357 12484 12484 14142 14954 14145 13346 12485 14154 14145 12485 12485 12494 14154 12486 12495 12496 12487 12488 12490 12489 12488 12487 13349 12489 12487 12487 12501 13349 13345 12491 12488 12488 12489 13345 12489 13342 13345 14153 13344 12489 12489 13349 14153 12491 13345 13348 12497 12496 12495 12496 12497 12506 12512 12505 12496 12496 12507 12512 12496 12506 12507 12497 12498 12506 13347 12506 12498 12499 13344 13350 14132 14131 12499 12499 13355 14132 12499 12500 13355 12500 13354 13355 12500 12509 13354 12500 12508 12509 13351 13349 12501 12501 12502 13351 12503 12502 12501 12502 13350 13351 13358 12510 12504 12504 13357 13358 13352 12528 12505 12505 12512 13352 14156 12507 12506 14157 14156 12506 12506 13347 14157 14962 12512 12507 12507 14959 14962 12507 14156 14959 12509 12526 13354 12511 12540 13359 12511 12527 12540 14169 13352 12512 14967 14169 12512 12512 14962 14967 12523 12518 12517 12524 12523 12517 12521 12519 12518 14149 12521 12518 12518 13363 14149 12518 12523 13363 12521 12520 12519 13368 13353 12520 12520 12521 13368 14149 13368 12521 13364 13363 12523 13373 13364 12523 12523 12524 13373 12524 12542 13373 12525 13353 13370 13356 13354 12526 14159 13356 12526 12526 14140 14159 12526 12532 14140 12526 12531 12532 12537 12531 12526 12527 12534 12540 12527 12533 12534 13352 12529 12528 12541 12535 12529 13378 12541 12529 12529 13361 13378 12529 13352 13361 14189 13377 12530 12530 13381 14189 12530 12531 13381 12532 12531 12530 13377 12532 12530 12531 12550 13381 12531 12537 12550 12532 13377 14140 12539 12534 12533 12533 12538 12539 13375 12540 12534 12534 13372 13375 14191 13372 12534 12534 13393 14191 12534 13392 13393 12534 13391 13392 12534 12539 13391 12549 12547 12536 12558 12549 12536 12559 12558 12536 13391 12539 12538 12538 13371 13391 13375 13359 12540 14981 13405 12541 12541 13378 14981 14185 13373 12542 12542 12543 14185 12544 12543 12542 12545 12544 12542 14975 14185 12543 12543 12546 14975 12543 12544 12546 12544 12545 12546 12545 12557 13411 13411 12546 12545 14976 14975 12546 12546 14208 14976 14984 14208 12546 12546 12563 14984 13411 12563 12546 12549 12548 12547 12548 12556 12557 12548 12549 12556 12566 12556 12549 12549 12565 12566 12549 12558 12565 13406 12555 12552 12552 12570 13406 12553 12554 12561 13384 13382 12554 13397 13384 12554 12554 12555 13397 13382 12561 12554 13398 13397 12555 14973 13398 12555 12555 13406 14973 13415 13411 12557 12557 12572 13415 12580 12565 12558 13388 12580 12558 12558 12559 13388 12559 13386 13388 13387 13386 12559 12560 12574 13402 13404 13403 12560 12560 13402 13404 12561 12562 12571 13382 12562 12561 12562 12563 13412 12564 12563 12562 13385 12564 12562 12562 13382 13385 13409 12571 12562 13410 13409 12562 13412 13410 12562 12563 13411 13412 12563 12564 14984 12564 14208 14984 12564 14184 14208 12564 14180 14184 12564 13383 14180 13385 13383 12564 12580 12566 12565 14201 12568 12567 12567 13394 14201 12568 14201 14995 12585 12578 12569 13414 13406 12570 13430 13414 12570 13440 13430 12570 13409 12579 12571 12572 13410 13415 12572 13409 13410 12572 12579 13409 12573 13421 14212 12573 13419 13421 12574 12576 13402 12577 12576 12575 12576 12577 13402 13424 13402 12577 12578 12587 13446 12578 12586 12587 12578 12585 12586 12580 13388 13416 13417 12583 12581 12581 12582 13417 13418 13417 12582 14223 13418 12582 13421 13419 12583 12583 13420 13421 12583 13417 13420 12587 12589 13446 12598 12589 12587 12587 12596 12598 13441 12593 12588 12589 12598 13451 12589 12590 13446 12591 12590 12589 13451 12591 12589 12591 13451 13462 14231 13440 12592 14233 14231 12592 12602 12601 12594 12594 12595 12602 13454 12602 12595 14226 13454 12595 12596 12597 12598 13463 12598 12597 12597 12603 13463 13471 13451 12598 13472 13471 12598 12598 13464 13472 12598 13463 13464 12608 12607 12599 12615 12608 12600 12600 12611 12615 12612 12611 12600 12600 12601 12612 13449 13448 12601 12601 12616 13449 12601 12602 12616 13448 12612 12601 13454 12616 12602 13469 13463 12603 12603 12613 13469 14240 13485 12604 12604 13462 14240 14234 14233 12605 12605 13452 14234 13478 13474 12606 12606 12614 13478 12606 12607 12614 12607 12608 12614 12615 12614 12608 13465 12611 12609 12609 12618 13465 13475 12618 12609 14263 13475 12609 15049 14263 12609 12609 12610 15049 12611 12610 12609 12610 12611 14250 15050 15049 12610 12610 14250 15050 12611 13466 13467 12611 12612 13466 13465 12615 12611 12611 13467 14250 12612 13448 13466 12613 13468 13469 12613 12620 13468 12613 12617 12620 13479 13478 12614 12614 12618 13479 12614 12615 12618 13465 12618 12615 13454 13449 12616 12617 12619 12620 12618 13475 13479 12621 12620 12619 13483 13468 12620 12620 12621 13483 12621 12625 13483 14269 14244 12622 14270 14269 12622 14282 14270 12622 12622 13492 14282 12623 13477 13487 12623 13474 13477 12625 13482 13483 14275 13486 12626 12626 14254 14275 12626 13485 14254 13493 12630 12627 12627 13487 13493 14285 14278 12628 12628 13500 14285 12628 12629 13500 14278 14277 12628 12629 12634 13500 12629 12633 12634 12632 12631 12630 12634 12632 12630 13496 12634 12630 12630 13493 13496 12631 12632 12633 12634 12633 12632 12634 13499 13500 12634 13497 13499 12634 13496 13497 12635 13501 14299 12635 12638 13501 12637 12636 12635 14299 12637 12635 12636 12637 12659 14307 13512 12637 12637 14299 14307 13512 12659 12637 12638 12641 13501 12639 12640 12641 12643 12640 12639 15063 12642 12640 12640 13503 15063 13504 13503 12640 13507 13504 12640 12640 12643 13507 12642 12641 12640 13502 13501 12641 12641 12642 13502 12642 15063 15064 15072 13502 12642 12642 15064 15072 12650 12648 12644 12652 12650 12644 12644 12645 12652 12653 12652 12645 12654 12653 12646 12655 12654 12646 14276 13492 12647 14291 14276 12647 12650 12649 12648 13509 13508 12649 13514 13509 12649 12649 12650 13514 12650 12651 13514 12652 12651 12650 14301 13514 12651 15090 14301 12651 12651 13521 15090 12651 13520 13521 13522 13520 12651 12651 12652 13522 13524 13522 12652 12652 12664 13524 12652 12653 12664 12653 12654 12664 12665 12664 12654 12666 12665 12654 12654 12655 12666 12667 12666 12655 14314 12657 12656 12656 13527 14314 12656 12676 13527 13517 13516 12658 12658 13511 13517 13516 12668 12658 13519 12672 12659 12659 13512 13519 12660 12675 13513 12680 12675 12660 13533 12680 12660 12660 12677 13533 12660 12673 12677 12669 12663 12661 12663 12662 12661 12675 12674 12663 12663 12669 12675 12664 12665 13524 13525 13524 12665 13526 13525 12665 12665 12666 13526 12666 13515 13537 12666 12667 13515 13537 13526 12666 13529 12709 12668 12668 13516 13529 13513 12675 12669 13530 13518 12670 12670 12671 13530 13531 13530 12671 13539 12691 12672 12672 13532 13539 12672 13519 13532 12674 12679 12684 12680 12679 12674 12674 12675 12680 14333 13527 12676 14341 14333 12676 12676 14340 14341 12676 13545 14340 13543 13533 12677 12677 12682 13543 12677 12678 12682 12683 12682 12678 12694 12692 12678 12686 12684 12679 13544 12686 12679 12679 13534 13544 12679 12680 13534 13535 13534 12680 12680 13533 13535 13548 13542 12681 12681 12689 13548 14347 13543 12682 12682 12683 14347 12683 14346 14347 12685 14348 14349 12685 12686 14348 12686 13544 14348 13548 12689 12687 14342 13548 12687 15132 14342 12687 12687 14352 15132 12687 12688 14352 12689 12688 12687 12702 12691 12688 12688 12689 12702 12688 13538 14352 12688 12691 13538 12689 12690 12702 12690 12691 12702 13539 13538 12691 13550 13549 12692 12692 12693 13550 12694 12693 12692 12693 12705 13550 12693 12694 12705 12695 12696 12698 13558 12698 12696 14358 13558 12696 12696 13557 14358 13559 12708 12697 12697 12706 13559 12697 12698 12706 13558 12706 12698 12699 12700 12703 13556 13552 12701 12703 12707 13556 12704 13541 13565 12704 13540 13541 14344 13550 12705 12705 13555 14344 13561 13559 12706 12706 13558 13561 13563 13556 12707 14356 13563 12707 12707 12708 14356 12708 13562 14356 14361 13562 12708 12708 13559 14361 12709 13529 13540 12712 12711 12710 12711 12712 12721 12722 12721 12712 13585 12722 12713 13586 13585 12713 12713 12723 13586 12713 12715 12723 12719 12718 12714 12720 12719 12714 12715 12716 12723 12724 12723 12716 12716 12717 12724 13590 12724 12717 12717 12725 13590 13577 13576 12718 12718 12719 13577 13583 13577 12719 12719 12720 13583 13596 13583 12720 12720 12726 13596 13579 13578 12721 13584 13579 12721 12721 12722 13584 13585 13584 12722 13589 13586 12723 12723 12724 13589 13590 13589 12724 13593 13590 12725 12725 12730 13593 13580 12730 12725 12726 12727 13596 14384 13596 12727 14385 14384 12727 14386 14385 12727 12727 13578 14386 12733 12730 12728 13594 13593 12730 12730 12733 13594 13601 12735 12732 13600 13594 12733 12733 13599 13600 13602 13599 12733 13606 12739 12735 12735 13605 13606 12735 13601 13605 13610 12737 12736 12736 12761 13610 12736 12742 12761 14393 13604 12737 12737 13616 14393 12737 13611 13616 12737 13610 13611 12744 12743 12738 12739 12745 12755 12746 12745 12739 13606 12746 12739 13609 13607 12740 14401 13632 12741 12741 13613 14401 12741 13612 13613 12741 13607 13612 12742 12747 12761 12752 12751 12743 12743 12744 12752 12751 12750 12743 13622 12756 12745 12745 12746 13622 12756 12755 12745 12746 13606 13622 12747 12748 12759 12747 12759 12761 12749 13617 13620 14398 13619 12750 12750 12751 14398 12751 12752 15205 15205 14398 12751 15206 15205 12752 14406 14405 12753 14407 14406 12753 12753 13630 14407 12753 13621 13630 13630 13621 12754 14399 13630 12754 12754 12756 14399 12754 12755 12756 15199 14399 12756 15200 15199 12756 15202 15200 12756 12756 15201 15202 12756 13622 15201 13623 13608 12757 13624 13623 12757 13625 13624 12757 12757 12758 13625 13631 13625 12758 12758 12763 13631 13610 12761 12759 13628 13610 12759 14403 13628 12759 12759 13626 14403 13627 13626 12759 12759 12760 13627 12760 13632 14402 14402 13627 12760 12763 12767 13631 12768 12767 12763 12769 12768 12763 13634 13631 12767 14408 13634 12767 12767 12768 14408 14419 14408 12768 14426 14419 12768 12768 13635 14426 12768 12769 13635 13640 12771 12770 13640 12773 12771 12772 12773 13647 13647 12774 12772 12773 13640 13647 13648 12778 12774 12774 13647 13648 12775 13650 13662 12775 12776 13650 13652 13650 12776 13653 13652 12776 12776 12777 13653 13655 13653 12777 12777 13646 13655 12778 13656 13664 13657 13656 12778 12778 13648 13657 13686 13659 12780 13649 13644 12780 13660 13649 12780 12780 13659 13660 13675 13667 12781 13677 13675 12781 12781 13659 13677 12782 13670 13680 12782 13665 13670 14445 13666 12783 12783 12784 14445 15254 14445 12784 12784 14444 15254 12784 12790 14444 14447 13672 12786 12786 12787 14447 12787 13685 16212 12787 13667 13685 14451 14447 12787 12787 14450 14451 16212 14450 12787 12788 12795 13658 12796 12795 12788 12800 12796 12788 13682 12790 12789 13683 13682 12789 12790 13682 14444 12791 12792 14452 12793 12792 12791 13687 12793 12791 14452 13687 12791 12792 12793 12794 12792 12794 14452 14453 14452 12794 12794 13681 14453 12794 13680 13681 14442 13658 12795 12795 12800 14442 12795 12796 12800 13674 12799 12797 12797 13673 13674 14459 13673 12797 14460 14459 12797 12798 13678 13679 12798 12799 13678 12799 13676 13678 12799 13674 13676 15271 14442 12800 12800 14462 15271 13707 12807 12801 12801 13703 13707 12801 13695 13703 12801 12802 13695 12802 12805 13695 12803 12804 12813 12803 14468 14469 12803 12813 14468 12804 12812 12813 12805 13692 13695 13694 13692 12805 13707 12808 12807 14473 13713 12808 12808 13707 14473 13719 12810 12809 12809 13711 13719 12809 13710 13711 13719 13718 12810 16230 15280 12811 16236 16230 12811 12811 15285 16236 15288 14468 12813 12813 14471 15288 12813 12814 14471 14472 14471 12814 14476 12816 12815 14480 14476 12815 12815 13715 14480 14476 13712 12816 14479 13708 12818 12818 13714 14479 12818 12820 13714 12821 12820 12818 12818 12819 12821 12820 12828 13714 12820 12821 12828 13721 13720 12822 12822 12824 13721 13720 12823 12822 14480 13715 12823 14481 14480 12823 14487 14481 12823 12823 13720 14487 12827 12826 12825 12825 14484 14488 12825 14483 14484 14485 14483 12825 12825 13717 14485 12825 12826 13717 12826 12827 13713 14477 13717 12826 12826 13713 14477 13716 13713 12827 13726 13714 12828 12828 12837 13726 13722 12842 12829 14486 13722 12829 12829 13718 14486 14489 12840 12830 12830 12832 14489 12840 12831 12830 12847 12846 12831 12831 12835 12847 12840 12835 12831 12832 13724 14489 12832 13723 13724 12832 12833 13723 12834 14489 14492 12834 12840 14489 12834 12835 12840 12836 12835 12834 14492 12836 12834 12835 12836 12847 14494 12847 12836 15320 14494 12836 12836 14492 15320 15301 13726 12837 12837 12838 15301 15307 15301 12838 15312 15307 12838 12838 13728 15312 12842 12841 12839 12841 12842 13740 15316 13740 12842 16282 15316 12842 12842 16274 16282 16275 16274 12842 12842 15317 16275 12842 13722 15317 13741 13740 12843 14509 13741 12843 15332 14509 12843 12843 12844 15332 12845 12844 12843 13740 12845 12843 12844 12845 15332 16303 15332 12845 12845 15328 16303 12845 13740 15328 12846 12847 13727 14494 13727 12847 12848 13727 14494 12848 12859 12863 13737 12859 12848 12848 13729 13737 13730 13729 12848 14498 13730 12848 12848 14494 14498 12849 12850 13728 12851 12852 14497 12855 12852 12851 12856 12855 12851 14490 13723 12851 14495 14490 12851 14496 14495 12851 14497 14496 12851 12852 12853 15323 12854 12853 12852 12855 12854 12852 15323 14497 12852 12853 12854 13747 12853 13747 15323 12854 12866 13742 12854 12855 12866 12854 13742 13747 12857 12858 13732 13734 13732 12858 13735 13734 12858 12859 12860 12863 12861 12860 12859 13738 12861 12859 12859 13737 13738 14513 12872 12860 12860 14512 14513 12860 14508 14512 12860 12861 14508 15326 14508 12861 12861 13738 15326 12862 12870 13735 12862 12869 12870 12864 12873 13739 12874 12873 12864 12875 12874 12865 12866 12867 13742 12867 12879 13742 12871 12870 12869 12886 12871 12869 12887 12886 12869 13743 13735 12870 12870 12871 13743 14511 13743 12871 14524 14511 12871 14525 14524 12871 12871 12886 14525 12872 12886 12887 14525 12886 12872 14526 14525 12872 12872 14514 14526 12872 14513 14514 13748 13739 12873 12873 12882 13748 12873 12875 12882 12873 12874 12875 12875 12876 12882 12876 12877 12882 12878 12877 12876 12883 12878 12876 15349 12883 12876 12876 12884 15349 12877 12878 17381 15348 12882 12877 16318 15348 12877 16330 16318 12877 18193 16330 12877 12877 17392 18193 12877 17380 17392 17381 17380 12877 12878 12883 16341 12878 16341 17381 13749 13742 12879 12879 12885 13749 13731 12881 12880 12881 13731 13755 13751 13748 12882 15348 13751 12882 12883 15349 16340 12883 16340 16341 12884 13752 14527 12884 14528 15349 12884 14527 14528 13754 13749 12885 13775 13754 12885 12885 12888 13775 12888 13764 13775 12888 12900 13764 12916 12901 12889 12889 12912 12916 12889 12897 12912 12889 12896 12897 12905 12896 12889 12889 12890 12905 12891 12890 12889 12901 12891 12889 12890 12892 12905 13760 12892 12890 14517 13760 12890 12890 12891 14517 12891 13768 14517 12891 12910 13768 12891 12901 12910 12892 12896 12905 12892 12895 12896 13756 12895 12892 14520 13756 12892 12892 12893 14520 12894 12893 12892 13760 12894 12892 16329 14520 12893 12893 14519 16329 12893 12894 14519 12894 14518 14519 12894 13760 14518 12897 12896 12895 12914 12897 12895 12915 12914 12895 14531 12915 12895 12895 13756 14531 12914 12912 12897 13786 13777 12898 13765 13764 12900 12911 12910 12901 12916 12911 12901 12904 12903 12902 12921 12904 12902 12902 12916 12921 12902 12911 12916 12927 12911 12902 12935 12927 12902 12936 12935 12902 12902 12929 12936 12902 12903 12929 12903 12904 12938 13803 12929 12903 13805 13803 12903 12903 12946 13805 12903 12938 12946 13799 12938 12904 12904 13795 13799 12904 12928 13795 12904 12921 12928 15365 13771 12906 16350 15365 12906 17380 16350 12906 12906 12907 17380 12908 12907 12906 13771 12908 12906 17392 17380 12907 12907 16355 17392 12907 12908 16355 12908 15370 16355 12908 12918 15370 12908 12917 12918 13771 12917 12908 13789 13768 12910 12910 12911 13789 12911 12944 13789 12911 12927 12944 12922 12916 12912 12923 12922 12912 12912 12913 12923 12914 12913 12912 14536 12923 12913 12913 13769 14536 12913 12915 13769 12913 12914 12915 14533 13769 12915 12915 14531 14533 12922 12921 12916 12919 12918 12917 14548 12919 12917 12917 12925 14548 13772 12925 12917 12917 13770 13772 13771 13770 12917 12918 12919 15370 16374 15370 12919 16375 16374 12919 12919 14553 16375 12919 14548 14553 13793 12934 12920 12920 13779 13793 12921 12924 12928 12921 12922 12924 12922 12923 12924 13780 12924 12923 13792 13780 12923 14536 13792 12923 13780 12928 12924 12925 12926 14548 13772 12930 12925 14553 14548 12926 14555 14553 12926 12926 14552 14555 12926 13796 14552 12926 12931 13796 14542 12944 12927 12927 13788 14542 12927 13787 13788 12927 12935 13787 12928 13790 13795 12928 13780 13790 13804 12936 12929 12929 13803 13804 12932 12933 14551 12932 13785 13786 15379 13785 12932 15382 15379 12932 16391 15382 12932 12932 14551 16391 12933 13797 14563 14563 14551 12933 12934 13793 15383 14564 13801 12934 14565 14564 12934 15391 14565 12934 12934 15383 15391 13794 13787 12935 12935 12937 13794 12935 12936 12937 12945 12937 12936 13804 12945 12936 12937 12945 13794 12938 13799 14558 14568 12946 12938 12938 14558 14568 13806 12962 12939 13811 13806 12939 12962 12940 12939 12962 12951 12940 12941 12942 14556 15390 13812 12941 12941 14556 15390 12942 14549 14556 13823 12954 12943 12943 13808 13823 17410 13789 12944 12944 17409 17410 12944 14543 17409 12944 14542 14543 13798 13794 12945 13802 13798 12945 13804 13802 12945 14568 13805 12946 12947 12961 14577 14562 13800 12948 12948 13807 14562 12948 12949 13807 12949 12950 14571 14571 13807 12949 12950 13813 14571 14581 13813 12952 12952 13822 14581 12952 12962 13822 12953 12954 13831 12954 13823 13831 12957 12956 12955 12968 12957 12955 12971 12968 12955 12955 12956 12964 12956 13815 13817 12956 12957 13815 12956 12963 12964 13817 12963 12956 14596 14595 12957 14602 14596 12957 12957 13837 14602 12957 13832 13837 12957 12968 13832 12957 13814 13815 13824 13814 12957 14595 13824 12957 14590 13828 12958 12958 12959 14590 12960 12959 12958 12959 13821 14590 12959 13820 13821 12959 12963 13820 12959 12960 12963 12964 12963 12960 12961 13834 14577 12961 13833 13834 14580 13822 12962 12962 13806 14580 12963 13817 13820 13829 13827 12965 14593 13829 12965 12965 12966 14593 12966 13828 14593 13835 12981 12967 14597 13835 12967 12967 12972 14597 12968 12969 13832 12970 12969 12968 12969 12970 13832 13840 13832 12970 12972 13830 14597 12972 13827 13830 13836 13833 12973 12973 12976 13836 12974 12989 12990 13845 12989 12974 12974 12975 13845 14603 13845 12975 12975 13835 14603 12975 12981 13835 13841 13836 12976 12976 12982 13841 13839 12985 12977 14601 13839 12977 12977 12978 14601 15447 14601 12978 12978 14609 15447 12995 12988 12980 12992 12991 12983 12983 12984 12992 12993 12992 12984 13844 12993 12984 12994 12987 12986 12986 12988 12994 13855 13848 12987 14628 13855 12987 12987 12994 14628 13857 12994 12988 12988 12989 13857 12995 12989 12988 12989 13846 13857 12989 13845 13846 13854 12996 12991 12991 12992 13854 14613 13854 12992 12992 14605 14613 12992 12993 14605 14608 14605 12993 15430 14608 12993 15431 15430 12993 12993 13844 15431 12994 13857 14628 13866 13864 12996 12996 13860 13866 13861 13860 12996 12996 13854 13861 13849 12999 12997 13851 13849 12997 12997 12998 13851 14631 13851 12998 14639 14631 12998 12998 13858 14639 13859 13858 12998 13873 13000 12999 12999 13872 13873 14639 13872 12999 12999 13852 14639 12999 13849 13852 13010 13007 13001 13011 13010 13001 13883 13867 13003 13008 13005 13004 13879 13008 13004 13004 13009 13879 14634 14632 13005 14640 14634 13005 13005 13008 14640 13006 13007 13880 15485 13880 13007 15486 15485 13007 13007 13881 15486 13007 13010 13881 14646 14640 13008 13008 13879 14646 13880 13879 13009 13010 13863 13881 13010 13011 13863 13864 13863 13011 13012 13013 13884 14651 13016 13014 14652 14651 13014 13014 13015 14652 15495 14652 13015 13015 13885 15495 13016 13875 13883 14648 13875 13016 14653 14648 13016 13016 14651 14653 13017 13886 14660 13019 13018 13017 13889 13019 13017 13890 13889 13017 14659 13890 13017 14660 14659 13017 13018 13019 13897 13893 13888 13019 13019 13889 13893 13019 13887 13897 13888 13887 13019 14676 14675 13020 14684 14676 13020 13020 13021 14684 13021 14674 14684 13022 13030 13898 13022 13026 13030 13022 13023 13026 13895 13025 13024 13896 13895 13024 13025 13895 14672 14672 13901 13025 13026 13027 13030 13027 13028 13030 14674 13898 13030 14684 14674 13030 15529 14684 13030 15533 15529 13030 15534 15533 13030 16524 13906 13031 13031 13904 16524 13031 13903 13904 13032 13045 13914 13032 13033 13045 13034 13033 13032 13043 13034 13032 13911 13043 13032 14688 13911 13032 13032 13913 14688 13914 13913 13032 13033 13044 13045 13033 13035 13044 13033 13034 13035 13038 13035 13034 13043 13038 13034 13038 13036 13035 13036 13037 13040 13038 13037 13036 13037 13039 13040 14685 13039 13037 13037 13038 14685 13038 13912 14685 13038 13043 13912 13041 13040 13039 13908 13041 13039 13909 13908 13039 16534 13909 13039 13039 14685 16534 13040 13041 13042 14696 14694 13041 13041 13908 14696 13043 13911 13912 13924 13923 13044 13044 13047 13924 13046 13045 13044 13923 13046 13044 13045 13046 13914 13915 13914 13046 13919 13915 13046 13921 13919 13046 14701 13921 13046 13046 13923 14701 13047 13048 13924 13048 13056 13924 13938 13937 13049 15546 13938 13049 13049 13922 15546 13057 13051 13050 13058 13057 13050 13926 13058 13050 13050 13060 13926 13051 13053 13054 13057 13053 13051 13054 13053 13052 13925 13054 13052 14700 13925 13052 13052 13053 14700 15542 14700 13053 13053 13057 15542 13056 13923 13924 13056 13059 13923 13057 14697 15542 14699 14697 13057 13057 13058 14699 13058 13926 14699 14709 14702 13059 13059 13931 14709 14702 13923 13059 15550 13926 13060 13060 13927 15550 13061 13925 14705 14705 13933 13061 13934 13069 13062 13062 13063 13934 13063 13932 13934 13933 13932 13063 13064 13074 13075 14711 13931 13065 13065 13943 14711 13065 13066 13943 13066 13080 13943 13066 13075 13080 13929 13927 13067 13946 13070 13068 13955 13946 13068 13068 13947 13955 13068 13069 13947 13069 13939 13947 13069 13934 13939 13935 13071 13070 13950 13935 13070 13070 13946 13950 13936 13072 13071 13071 13935 13936 13936 13073 13072 13073 13936 14717 13080 13075 13074 14719 13077 13076 13076 14718 14719 14720 13078 13077 13077 14719 14720 14720 13940 13078 13942 13941 13079 14721 13942 13079 13080 13081 13943 13081 13083 13943 13081 13082 13083 13954 13953 13082 13956 13954 13082 13082 13089 13956 13953 13083 13082 14723 13943 13083 13083 13953 14723 13086 13085 13084 13089 13091 13956 13095 13094 13090 13960 13956 13091 13091 13105 13960 13091 13092 13105 13092 13104 13105 13093 13094 13095 14732 13952 13096 13096 13097 14732 13097 14731 14732 13098 13108 13109 14757 13969 13099 13099 13967 14757 13103 13102 13100 13100 13101 13103 13101 13969 14751 13961 13103 13101 14751 13961 13101 15580 14743 13103 13103 13961 15580 13963 13960 13105 13105 13962 13963 13964 13110 13107 14752 13109 13108 14753 14752 13108 14756 13964 13109 13109 14752 14756 15609 13119 13114 16623 15609 13114 13114 15597 16623 15598 15597 13114 16638 14765 13119 13119 15609 16638 13978 13152 13120 13120 13121 13978 13121 13145 13978 13121 13144 13145 15618 13980 13126 13126 14769 15618 13138 13137 13129 13970 13138 13129 14759 13970 13129 14760 14759 13129 14761 14760 13129 14766 14761 13129 13129 13130 14766 13131 13130 13129 13132 13131 13129 13137 13132 13129 15603 14766 13130 13130 13976 15603 13130 13131 13976 13131 13971 13976 13131 13132 13971 13132 13142 13971 13132 13133 13142 13133 13134 13142 13143 13142 13134 13135 13146 13984 13139 13140 13972 13141 13140 13139 13143 13141 13139 13139 13142 13143 13971 13142 13139 13972 13971 13139 13973 13972 13140 13974 13973 13140 13975 13974 13140 13140 13141 13975 13141 13147 13975 13983 13145 13144 13986 13983 13144 13987 13978 13145 13145 13983 13987 13146 13149 13984 13981 13975 13147 13147 13150 13981 13148 13154 13158 13982 13981 13150 13985 13982 13150 13150 13151 13985 14781 13985 13151 13157 13153 13152 13986 13157 13152 13152 13978 13986 13157 13154 13153 13154 13157 13158 13160 13159 13154 13163 13162 13155 13988 13163 13155 13156 13997 14004 13156 13183 13997 13156 13164 13183 13986 13158 13157 14001 13166 13162 13162 13163 14001 13163 13989 14001 13163 13988 13989 14000 13999 13166 14789 14000 13166 14791 14789 13166 13166 14777 14791 13166 14001 14777 13169 13168 13167 13188 13169 13167 13190 13188 13167 13168 13169 13174 13174 13170 13168 14010 13174 13169 13169 14009 14010 14792 14009 13169 13169 13188 14792 13172 13171 13170 13173 13172 13170 13174 13173 13170 13181 13180 13171 13171 13172 13181 13993 13181 13172 13172 13992 13993 13172 13173 13992 14788 14002 13173 13173 14787 14788 13173 14008 14787 13173 13174 14008 14002 13992 13173 14010 14008 13174 13192 13176 13175 13996 13182 13176 13176 13191 13996 13192 13191 13176 15673 14796 13178 13178 13179 15673 13179 14793 15673 13179 13187 14793 13180 13181 13191 13180 13191 13192 13996 13191 13181 13181 13993 13996 13998 13183 13182 13182 13996 13998 13998 13997 13183 14013 14012 13184 14804 14013 13184 13184 14014 14804 13185 13194 14015 13187 14789 14793 13187 14000 14789 13187 13999 14000 13188 13189 14792 13190 13189 13188 14811 14792 13189 13189 13190 14811 13190 13216 14811 14012 14011 13193 14817 14015 13194 13194 14017 14817 14842 14018 13195 13195 13210 14842 13195 13204 13210 13196 14829 14830 15691 14829 13196 13196 14831 15691 13196 13197 14831 13198 13197 13196 13197 14027 14831 13197 13198 14027 13199 13200 13207 14019 13207 13200 14021 13208 13201 13201 13208 13209 14022 13221 13202 13202 13209 14022 14841 14017 13203 13203 14018 14841 14026 13210 13204 13205 13206 13212 14028 13212 13206 13206 14023 14028 13206 14016 14023 14019 13217 13207 14827 13209 13208 13208 14021 14827 14827 14022 13209 13210 14026 14842 14033 14026 13211 14830 14033 13211 13213 13214 14035 13215 13214 13213 13225 13215 13213 14849 14035 13214 14850 14849 13214 15717 14850 13214 13214 13215 15717 13215 13225 14843 13215 14844 15717 13215 14843 14844 13216 13227 14811 13216 13226 13227 13217 13218 13220 13219 13218 13217 14019 13219 13217 13229 13220 13218 14030 13229 13218 13218 13219 14030 14835 14030 13219 13219 14826 14835 13219 14019 14826 13221 14022 14024 14018 13224 13222 14841 14018 13222 15709 14841 13222 13222 14848 15709 13222 13223 14848 13224 13223 13222 13223 13231 14848 13223 13230 13231 15710 14033 13224 13224 14018 15710 13225 14028 14818 13225 14818 14843 13228 13227 13226 14029 13228 13226 15685 14811 13227 15694 15685 13227 15695 15694 13227 15696 15695 13227 13227 13228 15696 13228 14851 15696 14837 14836 13229 13229 14835 14837 13229 14030 14835 14852 14848 13231 13231 14032 14852 13232 13235 13237 13236 13235 13232 14034 13235 13233 14045 13234 13233 14853 14045 13233 13233 13235 14853 14034 13237 13235 13235 13236 14853 13236 14041 14857 14856 14853 13236 14857 14856 13236 14034 13242 13237 13239 14854 14859 14855 14854 13239 13239 14047 14855 13240 14036 14851 14038 14036 13240 13241 13248 14049 14049 14038 13241 13243 13244 13255 13244 13249 13255 13250 13246 13245 13250 13249 13246 14865 14052 13247 13247 14050 14865 13248 13251 14049 13249 13252 13255 13249 13250 13252 14051 14049 13251 13251 13253 14051 14056 13255 13252 13253 13265 14051 13266 13265 13253 13269 13268 13254 14056 13269 13254 13254 13255 14056 14062 13277 13256 14875 14062 13256 13256 14867 14875 13256 13257 14867 13257 14053 14867 14871 13263 13258 13258 14052 14871 14877 14869 13259 13259 13260 14877 13260 14876 14877 13260 13270 14876 13261 13262 14892 13262 13264 14873 13262 13263 13264 14893 14892 13262 13262 14873 14893 14871 13264 13263 13264 14865 14872 14871 14865 13264 13264 14872 14873 14055 14051 13265 14866 14055 13265 14874 14866 13265 13265 14059 14874 13265 13266 14059 13267 13268 13269 13267 13283 14060 13267 13269 13283 13270 13271 14876 13272 13271 13270 14054 13272 13270 13271 14063 15766 13271 13272 14063 15765 14876 13271 16762 15765 13271 13271 15766 16762 14054 13273 13272 13272 13273 14063 14064 14063 13273 14066 14064 13273 13273 14065 14066 13273 13274 14065 14086 13281 13275 13277 14062 14067 13278 13279 14070 13280 13279 13278 13279 14069 14070 14887 14069 13279 13279 14071 14887 13279 13280 14071 14890 14071 13280 14891 14890 13280 14075 14074 13281 15806 14075 13281 13281 14086 15806 13282 13294 13295 14902 13294 13282 13282 14076 14902 14897 14078 13284 14899 14897 13285 14903 14899 13285 13285 13286 14903 13287 13286 13285 14897 13287 13285 15772 14903 13286 13286 14898 15772 13286 13287 14898 14084 14083 13288 14085 14084 13288 13288 13290 14085 13291 13290 13289 13292 13291 13289 13290 13291 14085 13291 13292 14085 14090 14085 13292 13292 14072 14090 14073 14072 13292 13295 13294 13293 14896 13297 13296 14913 14896 13296 13296 14092 14913 14087 14059 13297 14088 14087 13297 14896 14088 13297 14089 13300 13299 14907 14089 13299 13299 14077 14907 14089 13304 13300 13304 13301 13300 14093 13308 13301 13301 13305 14093 13301 13304 13305 13304 14089 14907 14916 13305 13304 13304 14908 14916 13304 14907 14908 14916 14093 13305 14095 13309 13307 13307 14094 14095 13307 13308 14094 13308 14093 14094 14096 13310 13309 13309 14095 14096 14097 13314 13310 13310 14096 14097 14102 13313 13311 13311 13312 14102 14106 14102 13312 13313 14102 14924 13325 13315 13314 13314 13318 13325 14097 13318 13314 13325 13324 13315 13318 13317 13316 13325 13318 13316 14116 13325 13316 14928 14116 13316 13316 14927 14928 13316 14105 14927 13316 13317 14105 13317 13318 14097 14923 14105 13317 13317 14922 14923 13317 14097 14922 13319 13320 14107 14108 14107 13320 13320 13321 14108 14109 14108 13321 13321 13322 14109 13322 13330 14109 13323 13324 13325 14119 14114 13323 14121 14119 13323 13323 14120 14121 13323 13325 14120 13325 14116 14120 13343 13327 13326 14129 14126 13328 13328 13329 14129 13329 14118 14129 13329 14113 14118 13330 13331 14109 13331 13366 14109 13331 13365 13366 14125 14124 13332 14937 14125 13332 13332 13333 14937 13333 14935 14937 13334 13336 13365 13348 13342 13335 13367 13365 13336 13337 13339 13367 13340 13339 13337 13341 13340 13337 13337 13338 13341 13339 13366 13367 13369 13366 13339 13374 13369 13339 13376 13374 13339 14140 13376 13339 14151 14140 13339 13339 13340 14151 13340 14150 14151 13340 14141 14150 13348 13345 13342 13343 13346 14144 13351 13350 13344 14153 13351 13344 14145 14144 13346 14948 14157 13347 13347 14124 14948 13349 13351 14153 14181 13361 13352 13352 14169 14181 13353 13369 13370 13353 13368 13369 13356 13355 13354 14159 14132 13355 13355 13356 14159 14165 14160 13357 14960 14165 13357 13357 14954 14960 14160 13358 13357 14160 13371 13358 13375 13372 13359 13372 13360 13359 14961 14155 13360 15868 14961 13360 13360 14966 15868 13360 13372 14966 14981 13378 13361 13361 14972 14981 13361 14181 14972 14158 14149 13363 14170 14158 13363 13363 13364 14170 14173 14170 13364 13364 13373 14173 13367 13366 13365 13366 14107 14108 14113 14107 13366 14118 14113 13366 14130 14118 13366 14136 14130 13366 13366 13368 14136 13369 13368 13366 13366 14108 14109 14138 14136 13368 14139 14138 13368 14149 14139 13368 13374 13370 13369 14192 13391 13371 13371 14166 14192 13371 14165 14166 13371 14160 14165 14971 14966 13372 13372 14167 14971 14168 14167 13372 14190 14168 13372 14191 14190 13372 14182 14173 13373 14185 14182 13373 13399 13389 13376 14188 13399 13376 13376 14140 14188 14164 14140 13377 14189 14164 13377 14977 14189 13379 15875 14977 13379 13379 13380 15875 13381 13380 13379 14189 13381 13379 13380 15003 15875 13380 15002 15003 13380 14985 15002 13380 13381 14985 13381 13401 14985 13381 13390 13401 13382 13383 13385 13384 13383 13382 13383 13384 14180 13384 14172 14180 14175 14172 13384 13384 13397 14175 13413 13388 13386 13386 13400 13413 13386 13387 13400 13387 13399 13400 13387 13389 13399 13388 13413 13416 13403 13401 13390 14979 13392 13391 14980 14979 13391 13391 14192 14980 14200 13393 13392 14210 14200 13392 14979 14210 13392 14193 14191 13393 15013 14193 13393 13393 15011 15013 13393 15008 15011 13393 14994 15008 13393 14200 14994 14202 14201 13394 13394 13395 14202 13396 13395 13394 13405 13396 13394 16915 14202 13395 16916 16915 13395 16917 16916 13395 13395 16901 16917 13395 15015 16901 13395 13396 15015 13396 14986 15015 13396 13405 14986 13397 13398 14175 14179 14175 13398 14983 14179 13398 13398 14973 14983 13420 13400 13399 14197 13420 13399 13399 14187 14197 14188 14187 13399 13420 13417 13400 13417 13413 13400 14991 14985 13401 13401 13403 14991 14199 13404 13402 14217 14199 13402 13402 14216 14217 13402 13424 14216 13403 14198 14991 13403 13404 14198 14199 14198 13404 13405 14981 14986 15880 14973 13406 13406 15016 15880 15017 15016 13406 15900 15017 13406 13406 13407 15900 13408 13407 13406 13414 13408 13406 15911 15900 13407 15912 15911 13407 13407 15027 15912 13407 13408 15027 13408 14227 15027 13408 13414 14227 13410 13411 13415 13412 13411 13410 13418 13416 13413 13413 13417 13418 13414 13430 14227 13416 13418 13442 13447 13442 13418 14223 13447 13418 13423 13421 13420 13420 13422 13423 14197 13422 13420 13421 13423 14212 14195 13423 13422 14196 14195 13422 14990 14196 13422 13422 14978 14990 13422 14977 14978 13422 14164 14977 14187 14164 13422 14197 14187 13422 13423 14195 14212 13424 13431 14216 14215 13431 13425 13425 14214 14215 13425 14213 14214 13425 14212 14213 13426 13435 13436 13437 13435 13426 13426 13427 13437 13428 13427 13426 13436 13428 13426 13439 13437 13427 13427 13429 13439 13427 13428 13429 14204 13429 13428 13428 13436 14204 14206 13439 13429 13429 14203 14206 14204 14203 13429 15027 14227 13430 13430 14231 15027 13430 13440 14231 13431 14215 14216 13432 14204 14211 15025 14204 13432 13432 13456 15025 13432 13433 13456 13434 13433 13432 14211 13434 13432 13458 13456 13433 13459 13458 13433 13461 13459 13433 13433 13443 13461 13433 13434 13443 13434 13435 13443 13436 13435 13434 14211 13436 13434 13445 13444 13435 13435 13438 13445 13435 13437 13438 13444 13443 13435 14211 14204 13436 13439 13438 13437 14235 13445 13438 15032 14235 13438 13438 15028 15032 13438 13439 15028 13439 14220 15028 14222 14220 13439 13439 14206 14222 13441 13447 14228 13441 13442 13447 13443 13444 13461 13444 14237 15036 13444 13445 14237 14245 13461 13444 15036 14245 13444 13445 14235 14237 15020 14228 13447 13447 14223 15020 13448 13450 13480 13448 13449 13450 13467 13466 13448 13480 13467 13448 13458 13450 13449 13449 13455 13458 13449 13454 13455 13450 13460 13480 13450 13459 13460 13450 13458 13459 14239 13462 13451 13451 13471 14239 15029 14234 13452 13452 14243 15029 13452 13453 14243 13453 13473 14243 14236 13455 13454 15031 14236 13454 13454 15030 15031 13454 14229 15030 13454 14226 14229 13455 13457 13458 14236 13457 13455 15026 15025 13456 15924 15026 13456 13456 14236 15924 13456 13457 14236 13458 13457 13456 13461 13460 13459 13460 14246 15042 13460 14238 14246 13460 13461 14238 15042 13480 13460 14245 14238 13461 13462 14239 14240 13469 13464 13463 14251 13472 13464 13464 13470 14251 13464 13469 13470 13467 13480 14250 13481 13469 13468 13491 13481 13468 13468 13490 13491 13468 13483 13490 13481 13470 13469 14267 14251 13470 13470 13481 14267 14247 14239 13471 13471 13472 14247 14253 14247 13472 13472 14252 14253 13472 14251 14252 14244 14243 13473 13474 13476 13477 13478 13476 13474 13475 13476 13479 13477 13476 13475 14264 13477 13475 13475 14263 14264 13476 13478 13479 15056 13487 13477 13477 14264 15056 14266 14250 13480 15042 14266 13480 13481 13491 14267 13484 13483 13482 13489 13484 13482 13482 13488 13489 13483 13484 13490 14289 13490 13484 13484 14279 14289 14280 14279 13484 14287 14280 13484 13484 13489 14287 13485 14242 14254 13485 14241 14242 13485 14240 14241 13486 14275 14290 13494 13493 13487 15056 13494 13487 14288 13489 13488 14288 14287 13489 14289 13491 13490 14273 14267 13491 14289 14273 13491 13492 14276 14282 15056 13496 13493 13493 13494 15056 13497 13496 13495 14283 13497 13495 15965 14283 13495 13495 15947 15965 15948 15947 13495 13495 15056 15948 13495 13496 15056 15980 13499 13497 13497 14283 15980 15067 15066 13498 15981 15067 13498 13498 15980 15981 13498 13499 15980 13500 13499 13498 15066 13500 13498 15066 14285 13500 15073 14299 13501 13501 15072 15073 13501 13502 15072 13503 15062 15063 15065 15062 13503 13503 13504 15065 13504 13507 14296 15075 15065 13504 13504 14296 15075 14293 13506 13505 14293 13510 13506 13507 13508 14296 13508 14295 14296 13508 13509 14295 14300 14295 13509 14301 14300 13509 13509 13514 14301 14306 13511 13510 15081 14306 13510 13510 14293 15081 14306 13517 13511 14307 13519 13512 14313 13537 13515 13516 14311 14316 13516 13517 14311 13516 13528 13529 14316 13528 13516 13517 14306 14311 15967 15088 13518 17000 15967 13518 13518 15119 17000 13518 13530 15119 14312 13532 13519 13519 14307 14312 15101 13521 13520 15102 15101 13520 13520 14321 15102 13520 13523 14321 13520 13522 13523 13521 15111 15112 13521 15101 15111 15112 15090 13521 13524 13523 13522 13523 13536 14320 13523 13525 13536 13523 13524 13525 13523 14320 14321 13525 13526 13536 13537 13536 13526 14332 14314 13527 15117 14332 13527 13527 14333 15117 15105 14335 13528 15106 15105 13528 13528 14316 15106 14334 13529 13528 14335 14334 13528 14334 13540 13529 15120 15119 13530 15121 15120 13530 13530 14336 15121 13530 13531 14336 13531 13542 14336 14318 13539 13532 13532 14312 14318 14331 13535 13533 14337 14331 13533 13533 13543 14337 14331 13544 13534 13534 13535 14331 13536 13537 14320 13537 14313 14323 14323 14320 13537 15141 14352 13538 13538 15122 15141 13538 14343 15122 13538 14329 14343 13538 13539 14329 13539 14318 14329 13553 13541 13540 14334 13553 13540 13566 13565 13541 14353 13566 13541 13541 13554 14353 13541 13553 13554 14342 14336 13542 13542 13548 14342 14339 14337 13543 15134 14339 13543 13543 15133 15134 13543 14347 15133 13544 14338 14348 13544 14337 14338 13544 14331 14337 13545 13547 14340 13545 13546 13547 13551 13547 13546 13552 13551 13546 13547 13551 14340 13549 13550 14345 13550 14344 14345 14341 14340 13551 13551 13552 14341 14350 14341 13552 13552 13556 14350 15137 13554 13553 13553 15129 15137 13553 14334 15129 15137 14353 13554 13555 13569 14344 14351 14350 13556 13556 13563 14351 15148 14358 13557 13557 14349 15148 13558 14358 15153 14359 13561 13558 15153 14359 13558 15155 14374 13559 13559 13560 15155 13561 13560 13559 14373 14361 13559 14374 14373 13559 13560 13561 14360 15156 15155 13560 13560 14360 15156 13561 14359 14360 13562 13563 14356 13564 13563 13562 14369 13564 13562 13562 14368 14369 13562 14367 14368 13562 14361 14367 15149 14351 13563 13563 14364 15149 13563 13564 14364 16049 14364 13564 13564 14369 16049 13565 13568 13571 13565 13566 13568 13566 13567 13568 15144 13567 13566 13566 14353 15144 15144 15137 13567 15150 13568 13567 13567 15147 15150 13567 15139 15147 13567 15138 15139 13567 15137 15138 13572 13571 13568 14365 13572 13568 15150 14365 13568 14355 14344 13569 14362 14355 13569 13569 14357 14362 13570 13576 14371 14366 13574 13570 14371 14366 13570 14365 13573 13572 13582 13575 13573 14370 13582 13573 13573 14365 14370 14362 14357 13574 14363 14362 13574 14366 14363 13574 13582 13581 13575 14372 14371 13576 13576 13577 14372 15166 14372 13577 13577 14383 15166 13577 13583 14383 13578 13579 13597 13578 13597 14386 13579 13584 13597 15169 13595 13581 13581 14382 15169 13581 13582 14382 13582 14370 14382 14388 14383 13583 13583 13596 14388 13598 13597 13584 13584 13585 13598 14389 13598 13585 13585 13587 14389 13585 13586 13587 13588 13587 13586 13589 13588 13586 16115 14389 13587 13587 15184 16115 13587 15178 15184 13587 13588 15178 15179 15178 13588 15187 15179 13588 13588 14390 15187 13588 13591 14390 13588 13589 13591 13589 13590 13591 13592 13591 13590 13593 13592 13590 13591 13599 14390 13600 13599 13591 13591 13592 13600 13592 13594 13600 13592 13593 13594 15181 13601 13595 13595 15169 15181 14391 14388 13596 15182 14391 13596 15183 15182 13596 13596 14384 15183 14387 14386 13597 13597 13598 14387 15170 14387 13598 15177 15170 13598 13598 14389 15177 13599 13602 14390 14392 13605 13601 15181 14392 13601 13603 14393 15180 13603 13604 14393 14392 13606 13605 13606 14392 15191 14394 13622 13606 16111 14394 13606 13606 15195 16111 13606 15191 15195 13623 13612 13607 13607 13608 13623 13609 13608 13607 13628 13611 13610 14397 13616 13611 13611 13628 14397 13612 13623 14395 14395 13613 13612 13613 14395 15207 13613 13614 14401 13615 13614 13613 16140 13615 13613 13613 15207 16140 13614 13615 15223 15210 14401 13614 16144 15210 13614 13614 15223 16144 16140 15223 13615 14396 14393 13616 14397 14396 13616 13617 13618 13620 13619 13618 13617 14418 13629 13618 14421 14418 13618 15208 14421 13618 13618 14417 15208 15203 14417 13618 13618 13619 15203 13629 13620 13618 15204 15203 13619 13619 14398 15204 13622 14394 15201 13623 13624 14395 15207 14395 13624 13624 14400 15207 13624 13625 14400 13625 13631 14400 13626 14397 14403 14414 14397 13626 13626 14413 14414 13626 13627 14413 13627 14411 14413 14412 14411 13627 16145 14412 13627 13627 15215 16145 13627 15211 15215 13627 14410 15211 13627 14402 14410 14403 14397 13628 13630 14399 14407 14408 14400 13631 13631 13634 14408 13632 14401 14402 13633 13636 13637 14422 13636 13633 14434 14426 13635 13635 14430 14434 14423 13637 13636 14429 14423 13636 13636 14420 14429 14422 14420 13636 13637 14424 14425 13637 14423 14424 13638 14432 14433 13638 14431 14432 13638 14425 14431 13648 13647 13639 14438 14430 13641 13641 13642 14438 13643 13642 13641 13658 13643 13641 15222 14438 13642 15242 15222 13642 13642 14442 15242 13642 13643 14442 13643 13658 14442 13649 13645 13644 13645 13649 13660 13646 13654 13655 15240 13654 13646 13646 14440 15240 13650 13651 13662 13652 13651 13650 13651 13661 13662 14436 13661 13651 13651 13652 14436 13652 13653 14436 13653 14435 14436 13653 13654 14435 13655 13654 13653 15231 14435 13654 15239 15231 13654 15240 15239 13654 13690 13664 13656 14446 13690 13656 13656 14441 14446 13656 13657 14441 13657 14437 14441 14439 13662 13661 15245 14439 13661 13661 15226 15245 13661 15225 15226 13661 14436 15225 14439 13665 13662 14456 13688 13663 14458 14456 13663 13663 13689 14458 13663 13664 13689 13690 13689 13664 14439 13670 13665 15247 14440 13666 13666 15246 15247 13666 14445 15246 13667 13675 13685 13668 13669 13677 13678 13677 13669 13679 13678 13669 15263 13680 13670 13670 15253 15263 13670 14443 15253 13670 14439 14443 14451 14450 13671 13671 14447 14451 13671 13672 14447 14449 13684 13671 14450 14449 13671 13675 13674 13673 13685 13675 13673 14459 13685 13673 13674 13675 13676 13677 13676 13675 13676 13677 13678 15263 13681 13680 16201 14453 13681 13681 16193 16201 13681 15263 16193 15256 14444 13682 15265 15256 13682 13682 14454 15265 13682 13683 14454 13683 13688 14454 13684 14449 14463 13685 14459 16212 13687 14452 14461 14456 14454 13688 13689 13690 14458 13690 14455 14458 15257 14455 13690 13690 15249 15257 13690 15248 15249 13690 14446 15248 13697 13692 13691 16221 13697 13691 13691 16214 16221 13691 15277 16214 13691 14461 15277 13697 13695 13692 14448 13698 13693 14465 14448 13693 13693 13702 14465 13693 13701 13702 13695 13696 13703 13697 13696 13695 16233 13703 13696 13696 15281 16233 13696 13697 15281 16221 15281 13697 13699 13709 13710 13699 13700 13709 13700 15272 15273 13700 14463 15272 15283 13709 13700 15284 15283 13700 16228 15284 13700 16229 16228 13700 13700 15273 16229 13708 13702 13701 14466 14465 13702 14467 14466 13702 15298 14467 13702 13702 14475 15298 13702 13708 14475 14474 13707 13703 15286 14474 13703 15296 15286 13703 16233 15296 13703 13704 13705 17303 13706 13705 13704 13722 13706 13704 15317 13722 13704 15318 15317 13704 16259 15318 13704 17303 16259 13704 13705 13706 15283 13705 15283 17303 13711 13709 13706 13719 13711 13706 13722 13719 13706 13706 13709 15283 14474 14473 13707 14479 14475 13708 13711 13710 13709 15291 14472 13712 15294 15291 13712 13712 14476 15294 13713 14473 14477 15287 14479 13714 13714 13726 15287 16253 14485 13717 13717 15297 16253 13717 14477 15297 13718 13719 14486 13719 13722 14486 13720 14482 14487 13720 13721 14482 14484 14482 13721 14488 14484 13721 13725 13724 13723 14490 13725 13723 14491 14489 13724 15305 14491 13724 13724 13725 15305 16266 15305 13725 13725 15303 16266 13725 14490 15303 15302 15287 13726 13726 15301 15302 15314 15312 13728 13729 13736 13737 15324 13736 13729 13729 13730 15324 15325 15324 13730 16286 15325 13730 13730 15321 16286 13730 14498 15321 14522 13755 13731 13731 14500 14522 13731 13733 14500 13731 13732 13733 14502 13733 13732 14503 14502 13732 13732 13734 14503 15330 14500 13733 13733 14510 15330 13733 14502 14510 14511 14503 13734 13734 13743 14511 13734 13735 13743 15326 13738 13736 15327 15326 13736 13736 15324 15327 13738 13737 13736 13748 13744 13739 13740 13741 13745 13740 15322 15328 13740 15316 15322 14521 13758 13741 13741 14509 14521 13742 13746 13747 13749 13746 13742 13744 13748 14506 14507 13747 13746 15335 14507 13746 13746 13749 15335 13747 14507 15323 13748 13750 14506 13751 13750 13748 13749 13754 15335 16311 15331 13750 16318 16311 13750 13750 13751 16318 15331 14506 13750 13751 15348 16318 13752 13753 13761 13752 13761 14527 16336 15335 13754 13754 13776 16336 13754 13775 13776 13767 13757 13755 15342 13767 13755 13755 15337 15342 13755 15336 15337 13755 14501 15336 14522 14501 13755 15352 14531 13756 13756 14520 15352 13778 13759 13757 13757 13766 13778 13767 13766 13757 13763 13762 13758 14530 13763 13758 13758 14521 14530 13759 13778 13779 13760 14517 14518 14534 14527 13761 15364 14534 13761 15365 15364 13761 13761 13771 15365 13761 13770 13771 13762 14538 15366 13762 13763 14538 15366 13773 13762 13763 14532 14538 13763 14530 14532 13764 13774 13775 14535 13774 13764 13764 13765 14535 13765 13777 14535 15373 13778 13766 15374 15373 13766 15375 15374 13766 13766 15361 15375 13766 15342 15361 13766 13767 15342 15359 14517 13768 15369 15359 13768 13768 15368 15369 13768 13789 15368 14537 14536 13769 13769 14533 14537 15366 13783 13773 13776 13775 13774 15367 13776 13774 15372 15367 13774 13774 14535 15372 16343 16336 13776 16344 16343 13776 16351 16344 13776 13776 15367 16351 15372 14535 13777 13777 13784 15372 13786 13784 13777 13793 13779 13778 15373 13793 13778 13791 13790 13780 13792 13791 13780 13781 13782 14549 13783 13782 13781 14550 14549 13782 15371 14550 13782 13782 13783 15371 13783 15366 15371 16370 15372 13784 16376 16370 13784 13784 15379 16376 13784 13785 15379 13786 13785 13784 13794 13788 13787 14544 14542 13788 13788 14540 14544 14557 14540 13788 13788 13794 14557 15378 15368 13789 16368 15378 13789 17410 16368 13789 13790 13791 13795 15380 14560 13791 13791 13792 15380 13799 13795 13791 14558 13799 13791 14560 14558 13791 15381 15380 13792 16372 15381 13792 13792 14536 16372 13793 14545 15383 14547 14545 13793 15373 14547 13793 14566 14557 13794 13794 13798 14566 14561 14552 13796 13797 13800 14563 13798 13826 14566 13798 13825 13826 13798 13810 13825 13798 13802 13810 13800 14562 14563 13809 13808 13801 14564 13809 13801 14575 13810 13802 13802 13804 14575 14576 13804 13803 13803 13805 14576 14576 14575 13804 13805 14568 14576 14587 14580 13806 13806 13811 14587 15399 14562 13807 13807 14572 15399 13807 14571 14572 14589 13823 13808 13808 13809 14589 15407 14589 13809 13809 15391 15407 13809 14565 15391 13809 14564 14565 15409 13825 13810 16413 15409 13810 13810 14575 16413 13811 14586 14587 16412 14586 13811 13811 15390 16412 13811 13812 15390 15412 15403 13813 13813 14581 15412 15403 14571 13813 13816 13815 13814 13824 13816 13814 13818 13817 13815 13819 13818 13815 13815 13816 13819 14573 13819 13816 14582 14573 13816 14584 14582 13816 13816 13824 14584 13817 13818 13826 13826 13820 13817 14566 13826 13818 14585 14566 13818 13818 14574 14585 13818 14573 14574 13818 13819 14573 13825 13821 13820 13826 13825 13820 14591 14590 13821 16424 14591 13821 13821 16416 16424 13821 15409 16416 13821 13825 15409 13822 14580 14581 14589 13831 13823 14595 14584 13824 13827 13829 13830 13828 14592 14593 13828 14590 14592 15416 13830 13829 13829 14593 15416 16426 14597 13830 13830 15416 16426 13831 15421 15447 13831 15420 15421 13831 14594 15420 13831 14589 14594 14626 13837 13832 13832 13840 14626 13836 13834 13833 14579 14577 13834 15443 14579 13834 16427 15443 13834 13834 13838 16427 13834 13836 13838 15441 14603 13835 13835 14597 15441 14604 13838 13836 13836 13841 14604 15452 14602 13837 15461 15452 13837 13837 14626 15461 13838 15454 16427 13838 15442 15454 13838 14604 15442 14600 13844 13839 15434 14600 13839 15435 15434 13839 13839 14601 15435 14627 14626 13840 13840 13856 14627 13840 13848 13856 14612 14604 13841 13853 13843 13842 15442 14612 13843 15462 15442 13843 17472 15462 13843 17485 17472 13843 13843 16461 17485 13843 14633 16461 13843 13853 14633 15433 15431 13844 16428 15433 13844 17451 16428 13844 17452 17451 13844 13844 14598 17452 14600 14598 13844 13847 13846 13845 16454 13847 13845 13845 14603 16454 14610 13857 13846 14611 14610 13846 17483 14611 13846 17484 17483 13846 13846 17476 17484 13846 13847 17476 13847 16454 17476 13848 13855 13856 13849 13850 13852 13851 13850 13849 13850 13851 14631 14631 13852 13850 13852 14631 14639 13853 14632 14633 15456 13861 13854 13854 14613 15456 13855 14629 14638 13855 14628 14629 14638 13856 13855 14638 14627 13856 13857 14610 14628 14643 14639 13858 16472 14643 13858 13858 16471 16472 13858 16469 16471 13858 15471 16469 13858 13859 15471 13859 13877 15471 13859 13867 13877 14620 13866 13860 14636 14620 13860 14637 14636 13860 16456 14637 13860 16462 16456 13860 13860 13862 16462 13860 13861 13862 15456 13862 13861 13862 15456 16462 13863 13865 13881 13863 13864 13865 13866 13865 13864 13882 13881 13865 14644 13882 13865 13865 14641 14644 13865 14621 14641 13865 13866 14621 13866 14620 14621 13867 13876 13877 13867 13874 13876 13875 13874 13867 13883 13875 13867 13868 13869 13873 13870 13869 13868 16498 13870 13868 16500 16498 13868 13868 16495 16500 13868 16470 16495 13868 13871 16470 13873 13871 13868 14649 13873 13869 15502 14649 13869 13869 13870 15502 16498 15502 13870 13871 14642 16470 13871 13872 14642 13873 13872 13871 14643 14642 13872 13872 14639 14643 14649 13878 13873 13874 14645 15489 13874 13875 14645 15474 13876 13874 15489 15474 13874 14648 14645 13875 15471 13877 13876 15474 15471 13876 14649 13886 13878 13879 13880 14646 14647 14646 13880 15485 14647 13880 13881 13882 15486 15487 15486 13882 13882 14644 15487 14650 13885 13884 15496 15495 13885 13885 14650 15496 15504 14660 13886 13886 15501 15504 13886 14649 15501 14673 13897 13887 15527 14673 13887 13887 13888 15527 13888 13893 14666 13888 15507 15527 13888 14666 15507 13889 13891 13893 13889 13890 13891 13892 13891 13890 14659 13892 13890 14666 13893 13891 13891 13892 14666 13892 14662 14666 15506 14662 13892 13892 14659 15506 15510 14664 13894 13894 14671 15510 13895 13896 14672 13896 13897 14673 14673 14672 13896 14677 13902 13899 13899 13900 14677 15524 14677 13901 15525 15524 13901 13901 14672 15525 13904 13903 13902 14677 13904 13902 13904 15530 16524 13904 14677 15530 17542 15535 13905 13905 17539 17542 13905 15536 17539 13905 15532 15536 13905 13906 15532 13907 13906 13905 15535 13907 13905 16524 15532 13906 15535 15534 13907 15540 14696 13908 13908 13916 15540 13917 13916 13908 13908 13909 13917 14687 13917 13909 16535 14687 13909 13909 16534 16535 15537 14686 13910 13910 14689 15537 13910 13911 14689 13912 13911 13910 14686 13912 13910 13911 14688 14689 14686 14685 13912 13913 13918 14688 13913 13915 13918 13913 13914 13915 14693 13918 13915 13915 13919 14693 18366 15540 13916 13916 17550 18366 13916 13917 17550 13917 14687 17550 14691 14688 13918 13918 14690 14691 14693 14690 13918 13919 13920 14693 13921 13920 13919 15549 14693 13920 13920 14707 15549 13920 13921 14707 13921 14706 14707 13921 14701 14706 16547 15546 13922 14702 14701 13923 13925 14700 14705 14704 14699 13926 15550 14704 13926 13927 13928 15550 13929 13928 13927 13928 13938 15550 13928 13937 13938 13928 13929 13937 14715 13937 13929 13929 13930 14715 15556 14709 13931 15557 15556 13931 13931 14711 15557 13939 13934 13932 13945 13939 13932 14716 13945 13932 13932 13933 14716 15564 14716 13933 13933 14714 15564 13933 14705 14714 13951 13936 13935 13935 13948 13951 13950 13948 13935 13936 13951 14717 13938 15546 15550 14724 13947 13939 13939 13944 14724 13945 13944 13939 15566 14721 13940 15567 15566 13940 13940 14720 15567 15573 14731 13941 15574 15573 13941 13941 13942 15574 13942 14721 15566 13942 15566 15574 14722 14711 13943 14723 14722 13943 14730 14724 13944 13944 13945 14730 15565 14730 13945 13945 15564 15565 13945 14716 15564 13958 13950 13946 13946 13955 13958 13957 13955 13947 14733 13957 13947 13947 14724 14733 14726 13951 13948 13948 13949 14726 13950 13949 13948 14735 14726 13949 14740 14735 13949 13949 13958 14740 13949 13950 13958 14725 14717 13951 14726 14725 13951 14742 13966 13952 13952 14732 14742 15569 14723 13953 15570 15569 13953 15576 15570 13953 15577 15576 13953 13953 13954 15577 13954 13963 15577 13954 13960 13963 13954 13956 13960 13955 13957 13958 13959 13958 13957 14733 13959 13957 13958 14739 14740 13958 13959 14739 14744 14739 13959 13959 14738 14744 13959 14733 14738 15594 15580 13961 15595 15594 13961 13961 14751 15595 15582 13963 13962 13962 15554 15582 13962 14743 15554 15582 15577 13963 13965 13968 14753 14755 13968 13965 13965 14749 14755 13965 13966 14749 13966 14748 14749 13966 14742 14748 14758 14757 13967 15600 14751 13969 13969 14757 15600 14762 13976 13971 13971 13972 14762 13972 13973 14762 14764 14762 13973 15607 14764 13973 13973 14768 15607 13973 14767 14768 13973 13974 14767 13974 13977 14767 13974 13975 13977 13981 13977 13975 13976 14762 15603 14772 14767 13977 13977 13982 14772 13977 13981 13982 13987 13986 13978 13979 13980 15618 14776 14775 13979 15619 14776 13979 13979 15618 15619 13982 14771 14772 13982 13985 14771 13983 13986 13987 14774 14771 13985 16672 14774 13985 13985 15642 16672 13985 14785 15642 13985 14781 14785 14777 13989 13988 15658 14777 13988 13988 15634 15658 15635 15634 13988 13988 13990 15635 14777 14001 13989 13990 14776 15635 13990 14775 14776 14003 13993 13991 14778 14003 13991 13991 14002 14778 13991 13992 14002 13993 13992 13991 13993 13995 13996 14003 13995 13993 14781 14004 13994 14784 14781 13994 13994 14783 14784 13994 14782 14783 13994 14003 14782 13994 13995 14003 13996 13995 13994 14004 13996 13994 13996 13997 13998 14004 13997 13996 14788 14778 14002 14003 14779 14782 14003 14778 14779 15661 15655 14005 14005 15650 15661 15658 15650 14005 14005 14006 15658 14007 14006 14005 15655 14007 14005 14006 14790 14791 15662 14790 14006 14006 14007 15662 14006 14791 15658 15672 15662 14007 14007 15655 15672 14008 14009 14792 14010 14009 14008 14794 14787 14008 14795 14794 14008 14810 14795 14008 14008 14792 14810 14812 14802 14011 14011 14803 14812 14011 14013 14803 14011 14012 14013 15680 14813 14013 14013 14805 15680 14013 14804 14805 14813 14803 14013 15668 14804 14014 14014 14814 15668 15669 14814 14014 14014 14015 15669 14015 14817 15669 14818 14023 14016 14016 14796 14818 15690 14817 14017 14017 14841 15690 14018 14842 15710 14019 14020 14826 15686 14826 14020 14020 15667 15686 14838 14827 14021 14839 14838 14021 14025 14024 14022 14840 14025 14022 14022 14827 14840 14818 14028 14023 14024 14031 14039 14024 14025 14031 15729 14031 14025 16725 15729 14025 14025 14840 16725 14026 14033 14842 14832 14831 14027 14040 14039 14031 15729 14040 14031 15710 14842 14033 14828 14044 14033 14829 14828 14033 14830 14829 14033 14855 14047 14035 14035 14849 14855 14858 14851 14036 15695 14858 14036 15733 15695 14036 14036 14037 15733 14038 14037 14036 15748 15733 14037 16745 15748 14037 14037 15757 16745 14037 15735 15757 14037 14863 15735 14037 14049 14863 14037 14038 14049 14039 14040 15709 14039 14848 14852 15709 14848 14039 14040 15690 15730 14040 14816 15690 16725 14816 14040 14040 15729 16725 15730 15709 14040 14041 14042 14857 14043 14042 14041 14044 14043 14041 15714 14856 14042 14042 14043 15714 14042 14856 14857 16730 15713 14043 16734 16730 14043 14043 15731 16734 14043 14828 15731 14043 14044 14828 14043 15713 15714 15714 14046 14045 14045 14856 15714 14045 14853 14856 15713 14832 14046 15714 15713 14046 15752 14861 14048 15753 15752 14048 14048 15746 15753 14048 15738 15746 14048 14860 15738 14048 14859 14860 14864 14863 14049 14049 14051 14864 14050 14861 15752 15752 14865 14050 14051 14055 14864 14052 14865 14871 14868 14867 14053 16771 14868 14053 14053 14870 16771 14053 14058 14870 15737 14864 14055 14055 14866 15737 15760 14870 14058 14058 14869 15760 14059 14087 14874 14883 14067 14062 14884 14883 14062 14062 14875 14884 14063 14064 15773 15773 15766 14063 14064 14066 14885 14064 14885 15773 14068 14066 14065 14066 14068 14885 15772 14898 14067 14067 14881 15772 14882 14881 14067 15764 14882 14067 14067 14883 15764 14886 14885 14068 15767 14886 14068 14068 14069 15767 14070 14069 14068 14069 14887 15767 15768 14887 14071 14071 14888 15768 14889 14888 14071 14890 14889 14071 14910 14090 14072 14911 14910 14072 14072 14073 14911 15782 14911 14073 14073 14892 15782 14902 14076 14074 15792 14902 14074 14074 14075 15792 16795 15792 14075 14075 15806 16795 14077 14899 14907 14077 14079 14899 14077 14078 14079 14897 14079 14078 14079 14897 14899 14895 14891 14080 14080 14081 14895 14081 14894 14895 14082 14083 14901 15789 14894 14082 15790 15789 14082 14082 14901 15790 14083 14084 14909 14909 14901 14083 15791 15790 14084 14084 14090 15791 14084 14085 14090 15790 14909 14084 14086 14091 15806 14087 14088 15777 15763 14874 14087 15778 15763 14087 14087 15777 15778 14088 14896 15777 14090 14910 15791 14091 14917 15806 14918 14917 14091 14914 14913 14092 14916 14094 14093 14921 14095 14094 14094 14915 14921 14916 14915 14094 14921 14096 14095 14099 14097 14096 14920 14099 14096 14921 14920 14096 14097 14104 14922 14097 14098 14104 14099 14098 14097 14098 14099 15817 15821 14104 14098 14098 15820 15821 14098 15817 15820 14099 14920 15817 14100 14933 15831 14100 14101 14933 14102 14101 14100 14924 14102 14100 14101 14102 14106 14934 14933 14101 14101 14932 14934 14926 14925 14103 14103 14111 14926 14103 14930 14931 14103 14929 14930 14103 14925 14929 15821 14922 14104 15827 14927 14105 14105 14923 15827 15836 14936 14110 14936 14935 14110 15834 14926 14111 14111 14938 15834 14111 14112 14938 15841 14938 14112 14112 14133 15841 14112 14126 14133 14123 14122 14115 16831 14123 14115 14115 16823 16831 14115 14116 16823 14117 14116 14115 14122 14117 14115 14116 16815 16823 16817 16815 14116 14116 15835 16817 14116 14928 15835 14116 14117 14120 14121 14120 14117 14945 14121 14117 14117 14122 14945 14118 14943 14944 14944 14942 14118 14942 14128 14118 14128 14127 14118 14118 14127 14129 14118 14130 14943 15852 14143 14121 14121 14945 15852 15842 14945 14122 14122 15839 15842 14122 14123 15839 16854 15839 14123 16857 16854 14123 16858 16857 14123 14123 16832 16858 16833 16832 14123 14123 16831 16833 14949 14948 14124 15854 14949 14124 14124 14125 15854 14125 15840 15854 14125 14940 15840 14125 14937 14940 14146 14135 14126 14126 14137 14146 14126 14129 14137 14135 14133 14126 14136 14129 14127 14127 14130 14136 14943 14130 14127 14944 14943 14127 14947 14944 14127 14127 14128 14947 14128 14941 14947 14942 14941 14128 14129 14136 14137 14152 14150 14131 14131 14132 14152 14150 14141 14131 14159 14152 14132 14133 14951 15855 14133 14134 14951 14135 14134 14133 15855 15841 14133 14134 14950 14951 14134 14161 14950 14134 14146 14161 14134 14135 14146 14138 14137 14136 14952 14146 14137 14137 14147 14952 14137 14138 14147 14138 14139 14147 14148 14147 14139 14149 14148 14139 14151 14150 14140 14140 14164 14188 14140 14150 14159 15860 14954 14142 14142 15858 15860 14142 14143 15858 14143 15852 15858 14946 14939 14144 15853 14946 14144 16862 15853 14144 16875 16862 14144 16880 16875 14144 14144 16878 16880 16890 16878 14144 14144 14956 16890 14144 14145 14956 14961 14956 14145 14145 14155 14961 14145 14154 14155 14952 14161 14146 14953 14952 14147 14147 14148 14953 14148 14149 14158 14955 14953 14148 14148 14186 14955 14148 14158 14186 14150 14152 14159 14156 14157 14959 14157 14948 14959 14158 14174 14186 14158 14170 14174 14955 14163 14161 14161 14952 14955 14161 14162 14950 14163 14162 14161 17811 14950 14162 17815 17811 14162 17817 17815 14162 17820 17817 14162 14162 14163 17820 14955 14186 14163 14163 16893 17820 14163 14176 16893 14186 14176 14163 14164 14187 14188 14164 14189 14977 15866 14166 14165 14165 14965 15866 14165 14964 14965 14165 14960 14964 15870 14192 14166 15871 15870 14166 14166 15866 15871 16909 14971 14167 16912 16909 14167 14167 15876 16912 14167 14168 15876 15886 15876 14168 14168 14194 15886 14168 14190 14194 14967 14181 14169 14170 14171 14174 14172 14171 14170 14173 14172 14170 14176 14174 14171 14171 14175 14176 14171 14172 14175 14172 14173 14180 14182 14180 14173 14174 14176 14186 14179 14178 14175 14177 14176 14175 14178 14177 14175 14176 14177 16893 14177 16892 16893 14177 14178 16892 14178 14983 16892 14178 14179 14983 14180 14183 14184 14180 14182 14183 14181 14967 14972 14185 14183 14182 14974 14184 14183 14183 14185 14974 14209 14208 14184 14974 14209 14184 14975 14974 14185 14190 14191 14194 14191 14193 14194 15872 14980 14192 14192 15870 15872 15013 14194 14193 15888 15886 14194 15889 15888 14194 14194 15014 15889 14194 15013 15014 15000 14212 14195 14195 14196 15000 14196 14990 15000 14198 14199 15006 14992 14991 14198 14993 14992 14198 15007 14993 14198 14198 15006 15007 14199 15005 15006 15018 15005 14199 14199 14217 15018 14200 14210 14994 14201 14202 14995 15897 14995 14202 15898 15897 14202 16915 15898 14202 14203 14204 14207 14203 14205 14206 14207 14205 14203 15892 14996 14204 14204 15025 15892 14996 14207 14204 14222 14206 14205 14997 14222 14205 14205 14988 14997 14205 14987 14988 14205 14207 14987 14989 14987 14207 15877 14989 14207 15891 15877 14207 14207 14996 15891 14208 14209 14976 14209 14974 14976 15008 14994 14210 15009 15008 14210 15010 15009 14210 14210 14979 15010 15001 14213 14212 15003 15001 14212 14212 15000 15003 15001 14214 14213 15001 14215 14214 15005 14224 14215 14215 15004 15005 14215 15001 15004 14224 14216 14215 14218 14217 14216 14224 14218 14216 14217 14219 15018 14217 14218 14219 14225 14219 14218 14218 14224 14225 14219 14225 15018 15904 15028 14220 14220 14221 15904 14222 14221 14220 15905 15904 14221 14221 15894 15905 14221 14999 15894 14221 14222 14999 14222 14997 14999 14224 15005 15018 15018 14225 14224 14230 14229 14226 14995 14230 14226 15914 15030 14229 14229 14230 15914 16952 15914 14230 14230 14995 16952 14231 14232 15027 14233 14232 14231 15912 15027 14232 15915 15912 14232 14232 15029 15915 14232 14233 15029 14233 14234 15029 15032 14237 14235 17871 15924 14236 14236 16963 17871 14236 16962 16963 14236 15923 16962 14236 15031 15923 14237 15033 15036 14237 15032 15033 14238 14245 14246 14241 14240 14239 14248 14241 14239 14239 14247 14248 14248 14242 14241 14255 14254 14242 15946 14255 14242 14242 15937 15946 14242 15043 15937 14242 14248 15043 15034 15029 14243 14243 14244 15034 15044 15034 14244 14244 14269 15044 15037 14246 14245 14245 15035 15037 15036 15035 14245 14246 15037 15931 15931 15042 14246 14249 14248 14247 14253 14249 14247 14248 14249 15043 15937 15043 14249 14249 14253 15937 14250 14266 15050 14268 14252 14251 14251 14267 14268 14268 14253 14252 14253 15054 15937 14253 14268 15054 14254 14255 14275 15955 15058 14255 14255 15946 15955 14290 14275 14255 14294 14290 14255 15058 14294 14255 14256 15912 15915 14256 14257 15912 14258 14257 14256 15915 14258 14256 14257 15911 15912 17873 15911 14257 17874 17873 14257 14257 15930 17874 14257 14258 15930 14258 15044 15930 14258 15034 15044 15915 15034 14258 15048 14265 14263 15049 15048 14263 14265 14264 14263 15948 15056 14264 14264 15047 15948 14264 15046 15047 14264 14265 15046 16987 15046 14265 16988 16987 14265 14265 15048 16988 15942 15050 14266 14266 15040 15942 15042 15040 14266 14272 14268 14267 14273 14272 14267 14268 14272 15054 15930 15044 14269 14269 15051 15930 14269 14270 15051 14270 14276 15055 14282 14276 14270 15939 15051 14270 14270 15055 15939 15057 15054 14272 14272 14274 15057 14272 14273 14274 14281 14274 14273 14289 14281 14273 15954 15057 14274 14274 15059 15954 15061 15059 14274 14274 14297 15061 14274 14281 14297 14276 14291 15055 14285 14284 14278 14303 14298 14279 14310 14303 14279 14279 14280 14310 14298 14289 14279 14280 14308 14310 14309 14308 14280 14280 14287 14309 14281 14289 14297 14283 15978 15980 14283 15976 15978 14283 15965 15976 14292 14286 14284 14284 14285 14292 15076 14292 14285 15078 15076 14285 14285 15066 15078 15077 14302 14286 14286 14292 15077 14302 14288 14286 15086 14309 14287 14287 15085 15086 14287 14302 15085 14287 14288 14302 14298 14297 14289 15071 15055 14291 14292 15076 15077 14293 15080 15081 14293 14294 15080 15956 15080 14294 14294 15058 15956 15075 14296 14295 14295 14300 15075 16998 15966 14297 14297 15079 16998 14297 14298 15079 15966 15061 14297 14298 14303 15079 14299 15073 15083 15082 14307 14299 15083 15082 14299 15084 15075 14300 15095 15084 14300 15096 15095 14300 14300 14301 15096 15100 15096 14301 14301 15090 15100 14302 15077 15085 14303 14304 15079 14305 14304 14303 14310 14305 14303 15982 15079 14304 15990 15982 14304 14304 14305 15990 16004 15990 14305 14305 15094 16004 14305 14308 15094 14310 14308 14305 14316 14311 14306 15081 14316 14306 14330 14312 14307 15089 14330 14307 14307 15082 15089 15995 15094 14308 14308 15086 15995 14308 14309 15086 14330 14318 14312 14324 14323 14313 14313 14315 14324 14332 14315 14314 14328 14324 14315 14332 14328 14315 17010 15106 14316 14316 15099 17010 14316 15087 15099 14316 15081 15087 14317 17011 17032 14317 15991 17011 14317 15983 15991 14317 14330 15983 14317 14318 14330 14319 14318 14317 15996 14319 14317 17032 15996 14317 15107 14329 14318 14318 14319 15107 16007 15107 14319 14319 15996 16007 14322 14321 14320 14323 14322 14320 15114 15102 14321 14321 14322 15114 15116 15114 14322 14322 14325 15116 14322 14323 14325 14323 14324 14325 14326 14325 14324 14328 14326 14324 14325 14326 14327 15124 15116 14325 14325 14327 15124 15103 14327 14326 15104 15103 14326 15118 15104 14326 14326 14328 15118 14327 15103 17023 17034 15124 14327 14327 17023 17034 14328 14332 15117 14328 15117 15118 15107 14343 14329 14330 15089 15983 14333 14341 15117 14334 14335 15129 15145 15129 14335 14335 15105 15145 15130 15121 14336 14336 14342 15130 14339 14338 14337 14338 14339 15134 15135 14348 14338 14338 15134 15135 15126 15117 14341 15128 15126 14341 14341 14350 15128 15132 15130 14342 16015 15122 14343 14343 15108 16015 14343 15107 15108 14354 14345 14344 14355 14354 14344 14345 14354 15142 16022 14347 14346 16027 15133 14347 14347 16026 16027 14347 16022 16026 15143 14349 14348 16028 15143 14348 14348 15135 16028 14349 15143 15148 16036 15128 14350 14350 14351 16036 16041 16036 14351 14351 15149 16041 15140 15132 14352 15141 15140 14352 14353 15137 15144 17084 15142 14354 14354 16039 17084 14354 14355 16039 14355 14362 16039 14358 15148 15153 15154 14360 14359 14359 15153 15154 16077 15156 14360 14360 15154 16077 14375 14367 14361 14361 14373 14375 17089 16039 14362 17090 17089 14362 14362 16054 17090 14362 14363 16054 14363 16053 16054 14363 16051 16053 14363 14371 16051 14363 14366 14371 16049 15149 14364 15159 14370 14365 14365 15150 15159 14375 14368 14367 15163 14369 14368 14368 14375 15163 14369 15157 16049 15158 15157 14369 16058 15158 14369 14369 15164 16058 14369 15163 15164 14370 14378 14382 15159 14378 14370 14371 14372 15161 14371 15162 16051 14371 15161 15162 15166 15161 14372 15163 14375 14373 15165 15163 14373 15167 15165 14373 14373 14374 15167 14374 15155 15156 16091 15167 14374 14374 16078 16091 14374 16057 16078 14374 15156 16057 17127 14378 14376 17137 17127 14376 14376 17125 17137 14376 14377 17125 14378 14377 14376 14377 14378 15160 14377 17116 17125 14377 17107 17116 17108 17107 14377 14377 15160 17108 17127 14382 14378 14378 15159 15160 14379 14383 14391 15166 14383 14379 14379 15161 15166 16076 15161 14379 16108 16076 14379 14379 14380 16108 14381 14380 14379 15172 14381 14379 14379 14391 15172 16122 16108 14380 14380 15196 16122 14380 14381 15196 14381 15192 15196 14381 15172 15192 17149 15169 14382 14382 17127 17149 14383 14388 14391 14384 15176 15183 14384 14385 15176 14385 14386 15176 14386 15170 15171 14386 14387 15170 16103 15176 14386 14386 15171 16103 16115 16114 14389 16114 15177 14389 14390 15180 15187 15182 15172 14391 14392 15181 15191 15194 15180 14393 14393 14396 15194 16120 15201 14394 14394 16111 16120 14396 15188 15194 14396 14397 15188 14397 14414 15188 15205 15204 14398 15199 14407 14399 15209 15207 14400 14400 14409 15209 14400 14408 14409 15210 14410 14401 14410 14402 14401 16131 15206 14404 16133 16131 14404 14404 14405 16133 14405 16132 16133 14405 15198 16132 14405 14406 15198 16116 15198 14406 14406 14407 16116 14407 15199 16116 14419 14409 14408 14409 14426 15216 14409 14419 14426 15216 15209 14409 14410 15210 16144 16147 15211 14410 14410 16144 16147 14414 14413 14411 15212 14414 14411 14411 14412 15212 16141 15212 14412 16145 16141 14412 15213 15188 14414 14414 15212 15213 16139 16138 14415 17190 16139 14415 14415 16135 17190 14415 14416 16135 14417 14416 14415 15208 14417 14415 16142 15208 14415 14415 16138 16142 16136 16135 14416 14416 14417 16136 14417 15203 16136 14418 14421 14422 14420 14421 15208 14422 14421 14420 15217 14429 14420 16142 15217 14420 14420 15208 16142 14429 14424 14423 14431 14425 14424 14424 14427 14431 14429 14427 14424 14426 14434 15216 14432 14431 14427 15233 14432 14427 14427 14428 15233 14429 14428 14427 14428 14429 15217 17201 15233 14428 17202 17201 14428 14428 15218 17202 14428 15217 15218 15216 14434 14430 15219 15216 14430 14430 14438 15219 15232 14433 14432 15233 15232 14432 14433 15232 15234 15229 14436 14435 15230 15229 14435 15231 15230 14435 15229 15225 14436 15241 14441 14437 14437 15235 15241 14437 15234 15235 15221 15219 14438 15222 15221 14438 15245 14443 14439 15247 15240 14440 15248 14446 14441 15249 15248 14441 15258 15249 14441 16172 15258 14441 14441 15241 16172 15259 15242 14442 15271 15259 14442 15267 15253 14443 15268 15267 14443 14443 15245 15268 15256 15254 14444 16186 15246 14445 16187 16186 14445 14445 15255 16187 14445 15254 15255 15278 14462 14448 14448 14465 15278 16212 15275 14449 14449 14450 16212 15272 14463 14449 15273 15272 14449 15274 15273 14449 15275 15274 14449 15277 14461 14452 14452 14453 15277 16214 15277 14453 16216 16214 14453 14453 16201 16216 14454 14456 15265 14455 14456 14458 14457 14456 14455 15257 14457 14455 15269 15265 14456 16204 15269 14456 16206 16204 14456 14456 14457 16206 17259 16206 14457 14457 17258 17259 14457 15270 17258 14457 15257 15270 14459 15276 16212 14459 14464 15276 14459 14460 14464 16220 14464 14460 14460 15280 16220 16199 15271 14462 16211 16199 14462 14462 15279 16211 14462 15278 15279 14464 16220 17281 17261 15276 14464 17281 17261 14464 15279 15278 14465 15282 15279 14465 14465 14466 15282 16211 15282 14466 14466 14467 16211 16224 16211 14467 16241 16224 14467 16242 16241 14467 14467 15298 16242 14470 14469 14468 15288 14470 14468 16237 15285 14469 14469 14470 16237 14470 15288 16237 15289 15288 14471 15290 15289 14471 14471 14472 15290 15291 15290 14472 14473 14474 15286 14478 14477 14473 15286 14478 14473 15299 15298 14475 14475 14479 15299 15295 15294 14476 14476 14480 15295 14477 14478 15297 14478 15296 15297 14478 15286 15296 14479 15287 15299 14480 14481 15295 16244 15295 14481 16247 16244 14481 14481 14487 16247 16248 14487 14482 14482 14483 16248 14484 14483 14482 17306 16248 14483 17312 17306 14483 14483 14485 17312 17313 17312 14485 14485 16253 17313 16248 16247 14487 14489 14491 14492 14490 14495 15303 14493 14492 14491 15304 14493 14491 15305 15304 14491 14492 14493 15319 16284 15320 14492 14492 15319 16284 17340 15319 14493 14493 16267 17340 14493 15304 16267 15321 14498 14494 16285 15321 14494 14494 15320 16285 16265 15303 14495 14495 15309 16265 15311 15309 14495 14495 14496 15311 17368 15311 14496 14496 15329 17368 14496 15323 15329 14496 14497 15323 14501 14500 14499 15336 14501 14499 16313 15336 14499 17369 16313 14499 14499 16314 17369 14499 15330 16314 14499 14500 15330 14500 14501 14522 14502 14504 14510 14502 14503 14504 14505 14504 14503 14511 14505 14503 15339 14510 14504 14504 14505 15339 15340 15339 14505 15343 15340 14505 14505 14511 15343 15331 15314 14506 15333 15323 14507 15335 15333 14507 16320 14512 14508 14508 16316 16320 16317 16316 14508 14508 15326 16317 15350 14521 14509 14509 15332 15350 15339 15330 14510 14511 14523 15343 14524 14523 14511 15344 14513 14512 16320 15344 14512 15344 14514 14513 16322 14526 14514 16323 16322 14514 16338 16323 14514 14514 15344 16338 16328 15345 14515 14515 14516 16328 14517 14516 14515 15345 14517 14515 16339 16328 14516 16347 16339 14516 14516 15359 16347 14516 14517 15359 15345 14518 14517 15345 14519 14518 14519 15345 16329 16329 15352 14520 15355 14530 14521 14521 15351 15355 14521 15350 15351 14523 15340 15343 16353 15340 14523 14523 15362 16353 14523 14524 15362 14524 15358 15362 14524 14525 15358 14525 14526 15358 16346 15358 14526 14526 16322 16346 14529 14528 14527 14534 14529 14527 16340 15349 14528 14528 14529 16340 14529 14534 16340 15355 14532 14530 15360 14533 14531 14531 15352 15360 14532 15355 16356 16357 14538 14532 14532 16356 16357 15360 14537 14533 14534 15364 16340 14536 16369 16372 14536 15360 16369 14536 14537 15360 16357 15366 14538 14539 14540 14557 14541 14540 14539 15385 14541 14539 14539 14567 15385 14539 14557 14567 14540 14541 14544 17405 14544 14541 17406 17405 14541 18226 17406 14541 14541 16400 18226 14541 15384 16400 15385 15384 14541 14544 14543 14542 14543 17408 17409 14543 17407 17408 14543 14544 17407 14544 17405 17407 14545 14546 16385 14547 14546 14545 16385 15383 14545 16392 16384 14546 14546 14547 16392 14546 16384 16385 14547 16359 16392 14547 15374 16359 14547 15373 15374 15397 14556 14549 15398 15397 14549 14549 14550 15398 16380 15398 14550 14550 15371 16380 14551 15400 16391 14551 14562 15400 14563 14562 14551 14561 14555 14552 16389 16375 14553 14553 15386 16389 15395 15386 14553 14553 14554 15395 14555 14554 14553 14554 15394 15395 14554 15393 15394 14554 14570 15393 14554 14555 14570 14555 14561 14570 15397 15390 14556 14557 14566 14567 14569 14568 14558 16403 14569 14558 14558 14559 16403 14560 14559 14558 14559 14560 16388 17433 16403 14559 14559 16388 17433 14560 15380 16373 14560 16373 16388 14562 15399 15400 14585 14567 14566 15401 15385 14567 14567 14574 15401 14585 14574 14567 16409 14576 14568 14568 14569 16409 16411 16409 14569 14569 16410 16411 17433 16410 14569 14569 16403 17433 14570 14578 15393 14579 14578 14570 14570 14577 14579 15404 14572 14571 14571 15403 15404 16407 15399 14572 14572 15405 16407 14572 15404 15405 15408 14574 14573 14573 14582 15408 15402 15401 14574 15408 15402 14574 17436 16413 14575 14575 16409 17436 14575 14576 16409 15411 15393 14578 16417 15411 14578 14578 15414 16417 14578 14579 15414 15443 15414 14579 14587 14586 14580 14588 14581 14580 14580 14586 14588 14581 14588 15412 16415 15408 14582 14582 15415 16415 14582 14583 15415 14584 14583 14582 15427 15415 14583 14583 14595 15427 14583 14584 14595 16412 14588 14586 16412 15412 14588 15407 14594 14589 14590 14591 14592 16425 14592 14591 14591 16424 16425 16425 14593 14592 17457 15416 14593 14593 16425 17457 15448 15420 14594 16414 15448 14594 14594 15407 16414 14595 14596 15427 15429 15427 14596 14596 14602 15429 16449 15441 14597 14597 16426 16449 18261 17452 14598 14598 14599 18261 14600 14599 14598 18262 18261 14599 14599 16431 18262 14599 16430 16431 14599 14600 16430 14600 15446 16430 14600 15434 15446 15436 15435 14601 14601 15421 15436 15447 15421 14601 14602 15428 15429 17465 15428 14602 14602 16438 17465 14602 15452 16438 14603 16439 16454 14603 15453 16439 14603 15441 15453 14604 14612 15442 14605 14606 14613 14607 14606 14605 14608 14607 14605 15455 14613 14606 14606 14607 15455 15456 15455 14607 14607 14608 15456 14608 15430 15456 14630 14628 14610 14610 14611 14630 15483 14630 14611 14611 15474 15483 15482 15474 14611 17483 15482 14611 14613 15455 15456 14623 14622 14614 14614 14617 14623 14618 14617 14614 14614 14615 14618 14616 14615 14614 14622 14616 14614 15464 14618 14615 14615 15459 15464 14615 15458 15459 14615 14616 15458 15466 15458 14616 14616 14622 15466 14617 14619 14623 14617 14618 14619 15464 14619 14618 14625 14623 14619 16458 14625 14619 14619 16450 16458 14619 15464 16450 14636 14635 14620 14635 14621 14620 14621 14635 14641 14622 14624 15466 14622 14623 14624 14625 14624 14623 15467 15466 14624 15468 15467 14624 14624 14625 15468 16458 15468 14625 16453 15461 14626 14626 14627 16453 14627 14638 16453 14630 14629 14628 14629 14630 15483 17468 14638 14629 17497 17468 14629 14629 15483 17497 14634 14633 14632 14633 14634 16461 14634 15472 16461 14634 14640 15472 15469 14641 14635 14635 14636 15469 14636 15465 15469 14636 14637 15465 16473 15465 14637 14637 16464 16473 16465 16464 14637 17474 16465 14637 14637 16456 17474 17467 16453 14638 17468 17467 14638 16478 15472 14640 14640 14646 16478 15488 14644 14641 16474 15488 14641 14641 16473 16474 14641 15465 16473 15469 15465 14641 16472 16470 14642 14642 14643 16472 16485 15487 14644 14644 15488 16485 14645 14648 15489 16479 16478 14646 14646 14647 16479 16481 16479 14647 14647 15485 16481 15490 15489 14648 14648 14653 15490 15502 15501 14649 15512 15496 14650 14650 15511 15512 14650 14664 15511 15490 14653 14651 15498 15490 14651 14651 14657 15498 14651 14654 14657 14656 14654 14651 14651 14652 14656 14669 14656 14652 14652 14667 14669 14668 14667 14652 15495 14668 14652 14658 14657 14654 14665 14658 14654 14654 14655 14665 14656 14655 14654 14670 14665 14655 14655 14656 14670 14656 14669 14670 14657 14658 15498 14658 14665 15500 16506 15498 14658 14658 15500 16506 14659 15491 15506 14659 14660 15491 15505 15491 14660 14660 15504 15505 16502 16501 14661 14661 14662 16502 14663 14662 14661 16507 14663 14661 14661 16504 16507 14661 16501 16504 14662 15506 16502 14662 14663 14666 15507 14666 14663 15508 15507 14663 16507 15508 14663 15510 15509 14664 14664 15509 15511 15517 15500 14665 15523 15517 14665 14665 14670 15523 15520 14669 14667 14667 15514 15520 15516 15514 14667 14667 14668 15516 14668 15512 15516 14668 15496 15512 14668 15495 15496 16512 14670 14669 14669 15520 16512 16512 15523 14670 15521 15510 14671 16517 15525 14672 14672 14673 16517 14673 15527 16517 16511 15521 14675 16520 16511 14675 14675 14676 16520 14676 14684 16520 14677 14681 15530 14677 14680 14681 14677 14678 14680 14679 14678 14677 15524 14679 14677 17541 14680 14678 14678 14679 17541 14679 15528 17541 16517 15528 14679 14679 15525 16517 14679 15524 15525 16526 14681 14680 17541 16526 14680 15531 15530 14681 16526 15531 14681 17536 14684 14682 19161 17536 14682 14682 16521 19161 16522 16521 14682 16529 16522 14682 14682 14683 16529 14684 14683 14682 14683 16528 16529 14683 15529 16528 14683 14684 15529 17536 16520 14684 14685 16533 16534 14685 15537 16533 14685 14686 15537 18366 17550 14687 14687 18365 18366 14687 16535 18365 15538 14689 14688 14688 14691 15538 15538 15537 14689 14692 14691 14690 15541 14692 14690 14690 14693 15541 15539 15538 14691 14691 14692 15539 17553 15539 14692 14692 16538 17553 16539 16538 14692 18372 16539 14692 14692 17554 18372 14692 16540 17554 14692 15541 16540 16540 15545 14693 15545 15541 14693 14693 15549 17564 17564 16540 14693 14696 14695 14694 16542 14698 14695 17561 16542 14695 14695 15540 17561 14695 14696 15540 14697 14698 16542 14699 14698 14697 16541 15542 14697 16546 16541 14697 17557 16546 14697 14697 16542 17557 14698 15547 16547 14698 14704 15547 14698 14699 14704 15543 14705 14700 15544 15543 14700 16541 15544 14700 14700 15542 16541 14708 14706 14701 14701 14703 14708 14701 14702 14703 14709 14703 14702 15556 14708 14703 14703 14709 15556 15550 15547 14704 14705 14713 14714 15543 14713 14705 15558 14710 14706 14706 14708 15558 14710 14707 14706 15551 15549 14707 14707 14710 15551 14708 15557 15558 14708 15556 15557 15561 15560 14710 14710 15558 15561 15552 15551 14710 15560 15552 14710 15563 15557 14711 14711 14722 15563 15565 15564 14712 16550 15565 14712 14712 14713 16550 14714 14713 14712 15564 14714 14712 16552 16550 14713 14713 15548 16552 14713 15543 15548 14725 14718 14717 15572 14719 14718 14718 14725 15572 14727 14720 14719 14728 14727 14719 15572 14728 14719 14720 14727 15567 15568 15563 14722 15569 15568 14722 14722 14723 15569 14734 14733 14724 14724 14730 14734 15578 15572 14725 14725 14726 15578 15583 15578 14726 14726 14735 15583 16572 15567 14727 14727 16570 16572 16571 16570 14727 14727 14729 16571 14727 14728 14729 16576 14729 14728 14728 15579 16576 14728 15572 15579 16577 16571 14729 14729 16576 16577 15571 14734 14730 14730 15565 15571 15573 14732 14731 16591 14742 14732 16594 16591 14732 14732 16587 16594 14732 15573 16587 14733 14737 14738 14733 14734 14737 14734 15571 16550 14734 14736 14737 16550 14736 14734 15587 15583 14735 14735 14741 15587 14735 14740 14741 14738 14737 14736 16575 14738 14736 17592 16575 14736 14736 16568 17592 14736 16550 16568 16595 14744 14738 14738 16575 16595 14746 14740 14739 14739 14744 14746 15590 14741 14740 14740 15586 15590 14740 14745 15586 14746 14745 14740 15591 15587 14741 14741 15590 15591 14750 14748 14742 15588 14750 14742 16591 15588 14742 15580 15554 14743 15585 14746 14744 16595 15585 14744 14745 14747 16596 14745 14746 14747 17610 15586 14745 14745 16610 17610 14745 16605 16610 14745 16596 16605 15585 14747 14746 14747 15585 16596 14750 14749 14748 14749 14750 14754 14749 14754 14755 15597 14754 14750 14750 15589 15597 14750 15588 15589 14751 15600 16604 16618 15595 14751 16619 16618 14751 14751 16604 16619 14752 14753 14756 14754 15597 15598 14757 14758 15600 14758 14760 15600 14758 14759 14760 14760 14761 15600 14761 14766 16630 16604 15600 14761 16630 16604 14761 14764 14763 14762 14762 14763 15603 14763 15607 16632 14763 14764 15607 14763 15601 15603 15602 15601 14763 16631 15602 14763 14763 15613 16631 14763 15612 15613 16633 15612 14763 14763 16632 16633 16617 14770 14765 16638 16617 14765 14766 15601 15602 15603 15601 14766 14766 15602 16630 14773 14768 14767 14767 14772 14773 15614 15607 14768 14768 14773 15614 15619 15618 14769 16661 15619 14769 14769 16641 16661 14769 16617 16641 14769 14770 16617 14773 14772 14771 14774 14773 14771 15616 15614 14773 14773 14774 15616 16674 15616 14774 14774 15644 16674 16672 15644 14774 14776 15634 15635 14776 15620 15634 14776 15619 15620 15658 14791 14777 14780 14779 14778 15625 14780 14778 14778 14788 15625 15627 14782 14779 15628 15627 14779 14779 14780 15628 15638 15628 14780 16647 15638 14780 14780 15626 16647 14780 15625 15626 14781 14784 14785 15637 14783 14782 14782 15627 15637 15637 14784 14783 15642 14785 14784 15643 15642 14784 14784 15637 15643 16678 15652 14786 16679 16678 14786 14786 14794 16679 14786 14787 14794 14788 14787 14786 15652 14788 14786 14788 15623 15625 15652 15623 14788 15662 14793 14789 14789 14790 15662 14791 14790 14789 14792 14809 14810 14811 14809 14792 14793 15662 15673 16695 16679 14794 14794 14795 16695 14795 16694 16695 14795 14810 16694 15673 14818 14796 14797 14801 14806 14797 14800 14801 14797 14798 14800 14799 14798 14797 14806 14799 14797 14807 14800 14798 15663 14807 14798 14798 14799 15663 14799 14806 15663 14825 14801 14800 16693 14825 14800 14800 16692 16693 14800 14807 16692 14822 14819 14801 14823 14822 14801 15665 14823 14801 14801 14825 15665 14819 14806 14801 14802 14812 15666 16706 14812 14803 16707 16706 14803 14803 14813 16707 15668 14805 14804 14805 15679 15680 14805 15678 15679 14805 14815 15678 15668 14815 14805 15676 15663 14806 15683 15676 14806 14806 14819 15683 14807 15664 16692 14807 15663 15664 14808 14809 14811 14810 14809 14808 16694 14810 14808 14808 15685 16694 14808 14811 15685 15677 15666 14812 16706 15677 14812 14813 15707 15708 14813 15680 15707 14813 15708 16707 14814 14815 15668 14816 14815 14814 15690 14816 14814 14814 14817 15690 15669 14817 14814 14815 14816 15678 16721 15678 14816 16725 16721 14816 15682 14843 14818 14818 15681 15682 14818 15673 15681 14821 14820 14819 14822 14821 14819 14819 14820 15683 14820 14846 15692 14820 14821 14846 15692 15683 14820 14821 14822 14846 15719 14846 14822 14822 14847 15719 14822 14824 14847 14822 14823 14824 14833 14824 14823 14834 14833 14823 15665 14834 14823 14824 14833 14847 16708 15665 14825 14825 16693 16708 15704 15703 14826 14826 15687 15704 14826 15686 15687 15703 14835 14826 15689 14840 14827 14827 14838 15689 16729 15731 14828 14828 15711 16729 14828 14829 15711 14829 15691 15711 15713 15691 14831 14831 14832 15713 14833 14834 15684 15720 14847 14833 14833 15693 15720 14833 15684 15693 14834 15665 15684 15705 14837 14835 14835 15703 15705 16706 14839 14836 14836 15677 16706 14836 14837 15677 14837 15687 15688 16728 15687 14837 14837 15705 16728 16720 15677 14837 14837 15688 16720 14838 14839 16706 15706 15689 14838 16707 15706 14838 14838 16706 16707 14840 15689 15706 14840 15679 16725 15707 15679 14840 14840 15706 15707 15730 15690 14841 14841 15709 15730 14845 14844 14843 15716 14845 14843 14843 15682 15716 14844 15692 15717 14844 14845 15692 16726 15692 14845 14845 15716 16726 15717 15692 14846 15718 15717 14846 15719 15718 14846 15721 15719 14847 14847 15720 15721 14849 14854 14855 14849 14850 14854 15732 14854 14850 14850 15717 15732 14851 14858 15696 15732 14859 14854 14858 15695 15696 14862 14860 14859 15739 14862 14859 14859 15721 15739 15732 15721 14859 15749 15738 14860 15750 15749 14860 14860 15747 15750 14860 14862 15747 14862 15743 15747 14862 15740 15743 14862 15739 15740 14863 14864 15735 15737 15735 14864 14865 15753 15756 14865 15752 15753 15756 14872 14865 17719 15736 14866 14866 15763 17719 14866 14874 15763 14866 15736 15737 14884 14875 14867 14867 14868 14884 14868 14883 14884 16770 14883 14868 16771 16770 14868 14869 14877 15761 15761 15760 14869 14870 16760 16771 14870 15760 16760 14880 14873 14872 15756 14880 14872 14873 14878 14893 14880 14878 14873 15762 14877 14876 15765 15762 14876 15762 15761 14877 16776 14893 14878 17725 16776 14878 14878 16769 17725 14878 14879 16769 14880 14879 14878 14879 15758 16769 14879 15753 15758 15756 15753 14879 14879 14880 15756 16786 15772 14881 14881 16779 16786 14881 14882 16779 14882 15764 16779 16778 15764 14883 14883 16777 16778 14883 16770 16777 16753 15773 14885 16757 16753 14885 14885 14886 16757 16774 16757 14886 16775 16774 14886 14886 15769 16775 14886 15767 15769 15768 15767 14887 16765 15768 14888 16768 16765 14888 14888 15770 16768 14888 14889 15770 15771 15770 14889 14889 14895 15771 14889 14890 14895 14890 14891 14895 15783 15782 14892 14892 14893 15783 16785 15783 14893 14893 16776 16785 14900 14895 14894 15789 14900 14894 16780 15771 14895 14895 14900 16780 15786 15777 14896 14896 14913 15786 14899 14906 14907 14899 14905 14906 15788 14905 14899 14899 14903 15788 14900 15789 15802 16781 16780 14900 14900 15802 16781 14901 14909 15790 14902 15792 15793 14903 15787 15788 14903 15779 15787 14903 15772 15779 16798 14906 14904 17742 16798 14904 14904 15796 17742 14904 14905 15796 14906 14905 14904 14905 15788 15796 14906 16798 17747 15797 14907 14906 17747 15797 14906 15797 14908 14907 15797 14916 14908 15804 15791 14910 14910 14911 15804 15805 15804 14911 14911 15782 15805 15793 15792 14912 14912 15806 16806 14912 15792 15806 15794 15786 14913 15807 15794 14913 14913 14914 15807 15809 15807 14914 14914 15795 15809 15811 14921 14915 14915 15798 15811 15800 15798 14915 15810 15800 14915 14915 14916 15810 14916 15797 15810 15818 15806 14917 14919 15824 16807 14919 14931 15824 15813 15795 14919 16807 15813 14919 14920 14921 15817 15819 15817 14921 14921 15814 15819 14921 15811 15814 15828 14923 14922 14922 15821 15828 14923 15826 15827 15828 15826 14923 14925 14926 15833 15833 14929 14925 15834 15833 14926 15829 14928 14927 16817 15829 14927 14927 16815 16817 14927 15827 16815 14928 15830 15835 14928 15829 15830 15833 14930 14929 15824 14931 14930 15833 15824 14930 16809 14934 14932 16834 16809 14932 15832 15831 14933 16809 15832 14933 14933 14934 16809 15837 14937 14935 14935 14936 15837 14936 15836 16828 16828 15837 14936 15838 14940 14937 14937 15837 15838 17774 15834 14938 14938 15841 17774 16838 15840 14940 14940 15838 16838 15847 14947 14941 15849 15847 14941 14941 14942 15849 15851 15849 14942 14942 15850 15851 14942 14944 15850 14944 14947 15850 14945 15842 15852 15851 15850 14947 15851 15847 14947 15862 14959 14948 14948 15859 15862 14948 14949 15859 16847 15859 14949 14949 15854 16847 17805 14951 14950 17811 17805 14950 18598 15855 14951 14951 17806 18598 14951 17805 17806 14952 14953 14955 14964 14960 14954 14965 14964 14954 15860 14965 14954 14958 14957 14956 14961 14958 14956 16897 16890 14956 14956 15868 16897 14956 14957 15868 14957 14958 15868 14958 14961 15868 14963 14962 14959 15863 14963 14959 14959 15862 15863 15869 14970 14962 14962 15867 15869 14962 14963 15867 14970 14967 14962 16889 15867 14963 14963 16874 16889 14963 15863 16874 14965 15864 15866 15865 15864 14965 14965 15860 15865 16897 15868 14966 14966 14971 16897 14967 14968 14972 14970 14968 14967 14968 16891 16905 14968 14969 16891 14970 14969 14968 15874 14972 14968 16905 15874 14968 14969 16884 16891 16889 16884 14969 14969 15869 16889 14969 14970 15869 16909 16897 14971 14982 14981 14972 15874 14982 14972 15880 14983 14973 14974 14975 14976 15875 14978 14977 15875 14990 14978 15873 15010 14979 14979 14980 15873 14980 15872 15873 14981 14982 14986 15015 14986 14982 15890 15015 14982 14982 15874 15890 16937 16892 14983 14983 15882 16937 15883 15882 14983 14983 15016 15883 15881 15016 14983 14983 15880 15881 14985 14991 15002 14987 15879 15893 14987 15878 15879 14987 14989 15878 15893 14988 14987 16935 14997 14988 14988 16925 16935 14988 15893 16925 14989 15877 15878 15875 15000 14990 15884 15002 14991 14991 14992 15884 15885 15884 14992 14992 14993 15885 14993 15007 15885 14995 15903 16952 14995 15897 15903 14996 15892 16930 16924 15891 14996 16930 16924 14996 14997 14998 14999 16935 14998 14997 14998 16935 16950 15894 14999 14998 15899 15894 14998 16950 15899 14998 15875 15003 15000 15001 15003 15004 15004 15003 15002 15884 15004 15002 15006 15005 15004 15884 15006 15004 15884 15007 15006 15007 15884 15885 15012 15011 15008 15008 15009 15012 15022 15012 15009 15895 15022 15009 15009 15010 15895 15010 15873 15895 15024 15013 15011 15011 15019 15024 15011 15012 15019 15021 15019 15012 15022 15021 15012 15024 15014 15013 16938 15889 15014 15014 15908 16938 15014 15024 15908 15015 15890 16901 15881 15880 15016 15016 15017 15883 15017 15882 15883 18641 15882 15017 15017 15900 18641 15019 15021 15024 15913 15024 15021 15916 15913 15021 15917 15916 15021 15021 15023 15917 15021 15022 15023 15907 15023 15022 16955 15907 15022 15022 15895 16955 15918 15917 15023 17862 15918 15023 15023 15907 17862 15909 15908 15024 15913 15909 15024 16946 16945 15025 16947 16946 15025 18653 16947 15025 15025 15026 18653 16930 15892 15025 16945 16930 15025 19499 18653 15026 15026 19484 19499 15026 15924 19484 15929 15032 15028 16961 15929 15028 15028 15904 16961 15029 15034 15915 15922 15031 15030 15030 15914 15922 15031 15922 15923 15928 15033 15032 15929 15928 15032 15033 15928 16965 16965 15036 15033 15932 15037 15035 16968 15932 15035 15035 15036 16968 15036 16965 16968 15934 15933 15037 15037 15038 15934 15039 15038 15037 15932 15039 15037 15933 15931 15037 15038 15039 15945 15957 15934 15038 17900 15957 15038 15038 15951 17900 15038 15945 15951 15039 15932 15945 15943 15942 15040 16976 15943 15040 16977 16976 15040 15040 15041 16977 15042 15041 15040 15041 15944 16977 15041 15933 15944 15041 15042 15933 15042 15931 15933 16987 15047 15046 16993 15948 15047 15047 16985 16993 16986 16985 15047 16987 16986 15047 17893 16988 15048 15048 15949 17893 15048 15049 15949 15049 15940 15949 15049 15050 15940 15941 15940 15050 15942 15941 15050 15051 15052 15930 15053 15052 15051 15938 15053 15051 15939 15938 15051 16972 15930 15052 15052 15053 16972 15053 15958 16972 15959 15958 15053 15960 15959 15053 16997 15960 15053 15053 15961 16997 15053 15938 15961 15946 15937 15054 15954 15946 15054 15054 15057 15954 15055 15938 15939 15961 15938 15055 15055 15071 15961 15955 15059 15058 15058 15059 15956 16992 15954 15059 15059 15955 16992 15059 15060 15956 15061 15060 15059 15060 15068 15956 15070 15068 15060 16998 15070 15060 15060 15966 16998 15060 15061 15966 15062 15065 15964 15064 15063 15062 15964 15064 15062 15064 15964 15975 15074 15072 15064 15971 15074 15064 15975 15971 15064 15065 15075 15964 15066 15067 15078 16001 15078 15067 15067 15993 16001 15067 15981 15993 15068 15080 15956 15087 15080 15068 15068 15069 15087 15070 15069 15068 17022 15099 15069 15069 17021 17022 15069 15070 17021 15099 15087 15069 17027 17021 15070 15070 17009 17027 15070 16998 17009 15962 15961 15071 15071 15088 15962 15074 15073 15072 15073 15074 15968 15985 15083 15073 15073 15969 15985 15073 15968 15969 15971 15968 15074 15075 15084 15964 15076 15078 15091 15092 15077 15076 15076 15091 15092 15092 15085 15077 15994 15091 15078 16001 15994 15078 17009 16998 15079 15079 15982 17009 15087 15081 15080 15983 15089 15082 15984 15983 15082 15082 15083 15984 15985 15984 15083 15975 15964 15084 15084 15973 15975 15084 15095 15973 15093 15086 15085 15085 15092 15093 15086 15097 15995 15098 15097 15086 15086 15093 15098 15963 15962 15088 15967 15963 15088 15112 15100 15090 15994 15989 15091 15988 15092 15091 15989 15988 15091 15098 15093 15092 15988 15098 15092 17041 16004 15094 17042 17041 15094 15094 15995 17042 15974 15973 15095 15095 15096 15974 15096 15100 15112 15986 15974 15096 15987 15986 15096 15096 15112 15987 17040 15995 15097 15097 16003 17040 15097 15098 16003 15098 15988 16003 17022 17010 15099 15115 15111 15101 15101 15102 15115 16029 15115 15102 15102 15136 16029 15102 15113 15136 15114 15113 15102 15103 15104 17023 15104 15118 17034 17034 17023 15104 17043 15145 15105 15105 15106 17043 15106 17028 17043 15106 17010 17028 15109 15108 15107 16007 15109 15107 16021 16015 15108 15108 15109 16021 17048 16021 15109 15109 17047 17048 17049 17047 15109 15109 16007 17049 17053 16009 15110 17078 17053 15110 17079 17078 15110 15110 16016 17079 15110 15115 16016 15110 15111 15115 15112 15111 15110 16009 15112 15110 15992 15987 15112 16009 15992 15112 15113 15123 15136 15113 15116 15123 15113 15114 15116 16029 16016 15115 15124 15123 15116 15126 15118 15117 15118 15125 16010 15126 15125 15118 15118 16010 17034 17060 17000 15119 15119 17045 17060 15119 16005 17045 15119 15120 16005 16006 16005 15120 15120 15121 16006 15121 15130 16006 16015 15141 15122 16033 15136 15123 15123 16017 16033 15123 15124 16017 17034 16017 15124 15125 15126 15127 15125 15127 16010 15128 15127 15126 16035 16010 15127 16036 16035 15127 15127 15128 16036 15139 15138 15129 15145 15139 15129 15138 15137 15129 16018 16006 15130 16019 16018 15130 16020 16019 15130 15130 15131 16020 15132 15131 15130 17062 16020 15131 15131 16038 17062 15131 15132 16038 15132 15140 16038 16025 15134 15133 16027 16025 15133 16028 15135 15134 15134 16025 16028 16032 16029 15136 16033 16032 15136 16042 15147 15139 15139 15146 16042 15139 15145 15146 15140 15141 16038 15141 16015 16038 17084 16022 15142 15152 15148 15143 16028 15152 15143 16037 15146 15145 17044 16037 15145 15145 17043 17044 17977 16042 15146 15146 17976 17977 15146 16037 17976 15151 15150 15147 17088 15151 15147 15147 17083 17088 15147 16042 17083 16046 15153 15148 16047 16046 15148 16048 16047 15148 15148 15152 16048 17082 16041 15149 15149 16049 17082 16044 15159 15150 15150 15151 16044 17088 16044 15151 15152 16043 16048 15152 16040 16043 15152 16028 16040 16055 15154 15153 15153 16046 16055 15154 16056 16077 15154 16055 16056 16077 16057 15156 17988 16049 15157 18001 17988 15157 15157 15158 18001 18009 18001 15158 18010 18009 15158 15158 16058 18010 16044 15160 15159 15160 17093 17108 15160 16044 17093 16076 15162 15161 16076 16051 15162 15168 15164 15163 15163 15165 15168 15164 15168 16095 17131 16058 15164 17142 17131 15164 17152 17142 15164 15164 16107 17152 15164 16095 16107 15165 15167 15168 15167 16091 16094 16095 15168 15167 15167 16094 16095 17162 15181 15169 15169 17149 17162 15177 15171 15170 15171 15177 16110 16112 16103 15171 15171 16110 16112 15172 15182 15192 15173 15182 16109 15192 15182 15173 15173 15174 15192 15175 15174 15173 16109 15175 15173 15196 15192 15174 15197 15196 15174 17184 15197 15174 17186 17184 15174 15174 16134 17186 15174 16124 16134 15174 15175 16124 15175 16123 16124 16125 16123 15175 15175 16109 16125 16103 15183 15176 16126 16110 15177 15177 16114 16126 15178 15179 15184 15187 15184 15179 15194 15187 15180 15195 15191 15181 17162 15195 15181 15182 15183 16109 15183 16103 16109 16127 16115 15184 18057 16127 15184 15184 15185 18057 15186 15185 15184 15187 15186 15184 18829 18057 15185 15185 15186 18829 15186 18065 18829 18830 18065 15186 15186 17188 18830 15186 15187 17188 15187 15189 17188 15193 15189 15187 15194 15193 15187 15188 15193 15194 15188 15189 15193 15190 15189 15188 15213 15190 15188 17189 17188 15189 15189 15190 17189 17192 17191 15190 17193 17192 15190 15190 15213 17193 17191 17189 15190 16121 16111 15195 17148 16121 15195 15195 17137 17148 17162 17137 15195 17177 16122 15196 15196 15197 17177 17184 17177 15197 15198 16116 16117 15198 16117 16132 16118 16116 15199 16119 16118 15199 15199 15200 16119 15200 15202 16119 16120 15202 15201 17148 16119 15202 15202 16121 17148 15202 16120 16121 16137 16136 15203 15203 15204 16137 15204 16129 16137 15204 15205 16129 15205 15206 16130 16130 16129 15205 16131 16130 15206 15207 15220 16140 15207 15214 15220 15207 15209 15214 15216 15214 15209 16151 15215 15211 16163 16151 15211 15211 16147 16163 17193 15213 15212 17194 17193 15212 17195 17194 15212 15212 16141 17195 15214 15216 15220 16152 16145 15215 15215 16151 16152 15216 15219 15220 16139 15218 15217 15217 16138 16139 16142 16138 15217 18072 17202 15218 15218 16139 18072 15221 15220 15219 15220 15221 16140 15221 15223 16140 15221 15222 15223 15224 15223 15222 15236 15224 15222 15238 15236 15222 15242 15238 15222 16146 16144 15223 15223 16143 16146 15223 15224 16143 16153 16143 15224 15224 15237 16153 15224 15236 15237 15225 15228 16157 15229 15228 15225 15227 15226 15225 16157 15227 15225 15268 15245 15226 15226 15227 15268 16178 15268 15227 15227 16154 16178 16157 16154 15227 16158 16157 15228 16159 16158 15228 15228 15229 16159 15229 15230 16159 16164 16159 15230 15230 15239 16164 15230 15231 15239 16166 15234 15232 15232 15233 16166 17198 16166 15233 17201 17198 15233 16166 15235 15234 16171 15241 15235 15235 16166 16171 15238 15237 15236 16160 16153 15237 16162 16160 15237 15237 16161 16162 15237 15252 16161 15237 15250 15252 15237 15238 15250 15238 15242 15250 15239 15240 16164 16165 16164 15240 15240 15247 16165 15241 16170 16172 16171 16170 15241 15251 15250 15242 15242 15243 15251 15244 15243 15242 15259 15244 15242 15266 15251 15243 15243 15244 15266 16199 15266 15244 15244 15271 16199 15244 15260 15271 15244 15259 15260 16186 15247 15246 17234 16165 15247 15247 16186 17234 15258 15257 15249 15250 15251 15252 15266 15252 15251 15252 15262 16161 15252 15261 15262 15266 15261 15252 16192 15263 15253 15253 15267 16192 15256 15255 15254 16194 16187 15255 15255 15264 16194 15255 15256 15264 15265 15264 15256 17246 15270 15257 15257 16189 17246 15257 16188 16189 15257 15258 16188 17237 16188 15258 15258 16172 17237 15271 15260 15259 15261 16199 16200 15261 15266 16199 16191 15262 15261 16200 16191 15261 18107 16161 15262 18113 18107 15262 15262 16191 18113 15263 16192 16193 17245 16194 15264 15264 16195 17245 15264 15265 16195 15265 15269 16195 17242 16192 15267 15267 15268 17242 15268 17240 17242 15268 16178 17240 15269 16204 16205 16203 16195 15269 17257 16203 15269 17258 17257 15269 15269 16205 17258 18115 17258 15270 15270 17246 18115 15273 15274 16229 15274 15275 16229 15275 16213 16229 15275 16212 16213 16213 16212 15276 17261 16213 15276 15279 15282 16211 16230 16220 15280 16240 16233 15281 15281 16223 16240 15281 16221 16223 18144 17303 15283 15283 15284 18144 18145 18144 15284 18898 18145 15284 15284 16228 18898 16237 16236 15285 15300 15299 15287 15302 15300 15287 16238 16237 15288 16239 16238 15288 15288 15289 16239 17297 16239 15289 15289 15290 17297 15290 15291 15292 17298 17297 15290 15290 15292 17298 15294 15293 15291 15293 15292 15291 18146 17298 15292 18149 18146 15292 15292 17299 18149 15292 15293 17299 15293 15294 15295 15293 15295 17299 17305 17299 15295 15295 16244 17305 17307 15297 15296 15296 17290 17307 15296 16233 17290 17315 16253 15297 15297 17307 17315 16243 16242 15298 15298 15299 16243 15299 15300 16243 16252 16243 15300 16258 16252 15300 16263 16258 15300 15300 15302 16263 15306 15302 15301 15307 15306 15301 15302 15306 16263 17319 16266 15303 15303 17318 17319 17333 17318 15303 15303 16265 17333 16268 16267 15304 15304 15305 16268 17320 16268 15305 15305 16266 17320 16264 16263 15306 16273 16264 15306 15306 15308 16273 15306 15307 15308 15315 15308 15307 15307 15312 15315 16279 16273 15308 15308 15313 16279 15315 15313 15308 17333 16265 15309 15309 17318 17333 18161 17318 15309 15309 18160 18161 15309 15310 18160 15311 15310 15309 15310 17332 18160 15310 15311 17332 17368 17332 15311 15312 15314 15315 16331 16292 15313 15313 16305 16331 15313 15314 16305 15315 15314 15313 16292 16279 15313 16311 16305 15314 15314 15331 16311 16282 15322 15316 17339 16275 15317 15317 15318 17339 18170 17339 15318 15318 18159 18170 15318 18142 18159 15318 16259 18142 18154 16284 15319 18171 18154 15319 15319 18162 18171 15319 17340 18162 15320 16284 16285 16295 16286 15321 15321 16285 16295 16303 15328 15322 15322 16282 16303 17363 15329 15323 15323 15334 17363 15323 15333 15334 16287 15327 15324 16297 16287 15324 17348 16297 15324 15324 17335 17348 15324 15325 17335 15325 17323 17335 15325 17322 17323 17334 17322 15325 15325 16286 17334 15326 16309 16317 16310 16309 15326 15326 15327 16310 15327 16287 16310 17363 17351 15329 15329 17367 17368 15329 17338 17367 15329 17337 17338 17351 17337 15329 15330 15339 16314 16333 15350 15332 15332 16319 16333 15332 16303 16319 16312 15334 15333 15333 15335 16312 15334 16319 17363 15334 16312 16319 16321 16312 15335 16336 16321 15335 15338 15337 15336 16313 15338 15336 17382 15342 15337 15337 15356 17382 15357 15356 15337 18188 15357 15337 15337 15338 18188 18189 18188 15338 15338 16313 18189 16315 16314 15339 15339 15341 16315 15339 15340 15341 17377 15341 15340 17383 17377 15340 17384 17383 15340 15340 16353 17384 15341 16306 16315 17375 16306 15341 17377 17375 15341 15377 15361 15342 15342 15376 15377 17382 15376 15342 15344 16324 16338 15344 16320 16324 17379 16329 15345 15345 15346 17379 15347 15346 15345 16328 15347 15345 18980 17379 15346 15346 18979 18980 19836 18979 15346 15346 18991 19836 15346 15347 18991 19855 18991 15347 15347 19846 19855 15347 19845 19846 15347 18988 19845 15347 16328 18988 16333 15351 15350 16334 15355 15351 15351 16333 16334 15352 15353 15360 15354 15353 15352 16329 15354 15352 16369 15360 15353 17400 16369 15353 15353 15354 17400 15354 17379 17400 15354 16329 17379 15355 16334 16356 18207 17382 15356 15356 16345 18207 15356 15357 16345 18196 16345 15357 18962 18196 15357 15357 18188 18962 15363 15362 15358 16346 15363 15358 16354 16347 15359 15359 15369 16354 15377 15375 15361 15362 16352 16353 15362 15363 16352 17395 16352 15363 15363 17389 17395 15363 16346 17389 15364 15365 16340 16342 16340 15365 16350 16342 15365 16379 15371 15366 15366 16357 16379 16370 16351 15367 15367 15372 16370 16368 16367 15368 15368 15378 16368 16367 15369 15368 16367 16354 15369 16374 16355 15370 15371 16379 16380 15374 15375 16359 17412 16359 15375 18221 17412 15375 15375 17385 18221 15375 15376 17385 15377 15376 15375 15376 17382 17385 15379 15382 16376 15380 15381 16373 15381 16372 16373 16377 16376 15382 16391 16377 15382 15392 15391 15383 16396 15392 15383 15383 16385 16396 15384 16386 16400 16387 16386 15384 17421 16387 15384 17432 17421 15384 15384 15401 17432 15384 15385 15401 15396 15389 15386 15386 15395 15396 17418 16389 15386 15386 15387 17418 15388 15387 15386 15389 15388 15386 17419 17418 15387 15387 16398 17419 15387 16397 16398 15387 15388 16397 16404 16397 15388 15388 15389 16404 15396 15394 15389 15389 15394 16404 15390 15413 16412 15390 15403 15413 15390 15397 15403 15391 15406 15407 15391 15392 15406 17428 15406 15392 17429 17428 15392 15392 16396 17429 17437 15394 15393 15393 15410 17437 15411 15410 15393 15396 15395 15394 16406 16404 15394 17438 16406 15394 15394 17437 17438 15397 15398 15405 15404 15403 15397 15405 15404 15397 16390 15405 15398 15398 16380 16390 16407 15400 15399 16399 16391 15400 16407 16399 15400 15401 15402 17432 15402 16401 17432 16402 16401 15402 15402 15408 16402 15403 15412 15413 15405 16390 16407 16414 15407 15406 17444 16414 15406 15406 17434 17444 15406 17428 17434 16420 16402 15408 15408 16415 16420 16422 16416 15409 15409 16413 16422 18250 17437 15410 15410 17461 18250 15410 17443 17461 15410 15411 17443 15411 16417 17443 16412 15413 15412 15414 15443 16417 15415 15427 16415 17457 16426 15416 20711 19062 15417 15417 19900 20711 15417 15418 19900 15419 15418 15417 19062 15419 15417 15418 19042 19900 15418 17434 19042 17453 17434 15418 15418 15419 17453 15419 17444 17453 17464 17444 15419 20698 17464 15419 15419 19062 20698 16434 15421 15420 16444 16434 15420 15420 15448 16444 16434 15436 15421 17454 15426 15422 15422 16418 17454 15422 15423 16418 15424 15423 15422 15426 15424 15422 16419 16418 15423 16432 16419 15423 15423 15437 16432 15423 15424 15437 15438 15437 15424 15424 15425 15438 15426 15425 15424 15439 15438 15425 15451 15439 15425 15460 15451 15425 16436 15460 15425 15425 16435 16436 15425 15440 16435 15425 15426 15440 16437 15440 15426 17454 16437 15426 15427 15429 16415 18277 17449 15428 15428 17465 18277 17449 15429 15428 17449 16415 15429 15430 15444 15456 15445 15444 15430 15430 15431 15445 15431 15432 15445 15433 15432 15431 15432 15444 15445 17462 15444 15432 15432 15433 17462 15433 16428 17462 15434 15436 15446 15434 15435 15436 16434 15446 15436 15437 15438 15439 15437 15439 16432 15439 15449 16432 15450 15449 15439 15457 15450 15439 15439 15451 15457 16437 16435 15440 16449 15453 15441 15462 15454 15442 16433 16417 15443 15443 16427 16433 16463 15456 15444 15444 16455 16463 17466 16455 15444 15444 17462 17466 15446 16429 16430 16434 16429 15446 17444 16444 15448 15448 16414 17444 16447 16432 15449 15449 16445 16447 16446 16445 15449 15449 15450 16446 15450 15458 16446 15450 15457 15458 15458 15457 15451 15459 15458 15451 15460 15459 15451 16451 16438 15452 15452 15461 16451 16440 16439 15453 16449 16440 15453 16433 16427 15454 16441 16433 15454 18272 16441 15454 18278 18272 15454 18291 18278 15454 15454 17472 18291 15454 15462 17472 16463 16462 15456 17493 16446 15458 17494 17493 15458 17504 17494 15458 17505 17504 15458 15458 15466 17505 15459 15463 15464 15459 15460 15463 16436 15463 15460 16453 16451 15461 16450 15464 15463 15463 16448 16450 15463 16436 16448 15466 15475 15476 15466 15473 15475 15466 15467 15473 17509 17505 15466 15466 15476 17509 15467 15470 15473 15467 15468 15470 16466 15470 15468 15468 16458 16466 15478 15473 15470 16475 15478 15470 16477 16475 15470 15470 16466 16477 15471 16468 16469 15471 15474 16468 17491 16461 15472 17499 17491 15472 15472 16478 17499 15478 15475 15473 15474 15481 16468 15482 15481 15474 15474 15479 15483 15480 15479 15474 15489 15480 15474 15477 15476 15475 16489 15477 15475 15475 15478 16489 15476 15477 18323 18323 17509 15476 15477 16488 18323 16489 16488 15477 15478 16475 16489 15484 15483 15479 16491 15484 15479 15479 15480 16491 16497 16491 15480 15480 15490 16497 15480 15489 15490 16469 16468 15481 17498 16469 15481 17507 17498 15481 15481 15482 17507 15482 17483 17507 15483 15484 17497 15484 16492 17506 15484 16491 16492 17506 17497 15484 15485 16480 16481 15485 15486 16480 15486 15487 16480 16484 16480 15487 16485 16484 15487 15488 16474 17508 16486 16485 15488 17508 16486 15488 15490 15499 16497 15490 15497 15499 15498 15497 15490 15491 15505 15506 15494 15493 15492 16502 15494 15492 15492 16501 16502 16503 16501 15492 15492 15493 16503 15493 19972 19974 15493 15494 19972 17516 16503 15493 15493 17515 17516 19130 17515 15493 19974 19130 15493 19973 19972 15494 15494 15504 19973 15505 15504 15494 15506 15505 15494 16502 15506 15494 17522 15499 15497 15497 16515 17522 15497 16506 16515 15497 15498 16506 17521 16497 15499 15499 16505 17521 17525 16505 15499 15499 17522 17525 15500 15517 16512 16515 16506 15500 15500 16512 16515 15501 15502 15503 15501 15503 15504 16498 15503 15502 17523 15504 15503 18332 17523 15503 15503 18331 18332 15503 16499 18331 15503 16498 16499 15504 17523 19973 16516 15527 15507 15507 15508 16516 16519 16516 15508 18343 16519 15508 15508 17530 18343 15508 17529 17530 15508 16507 17529 15519 15511 15509 15509 15510 15519 15510 15518 15519 15521 15518 15510 15513 15512 15511 15519 15513 15511 15512 15514 15516 15512 15513 15514 15515 15514 15513 18336 15515 15513 18337 18336 15513 15513 18335 18337 15513 16510 18335 15513 15519 16510 15514 15515 15520 16513 15520 15515 18336 16513 15515 15517 15523 16512 16510 15519 15518 15518 16508 16510 15518 15522 16508 15518 15521 15522 16513 16512 15520 16511 15522 15521 16509 16508 15522 18341 16509 15522 15522 17534 18341 15522 16511 17534 15528 15527 15526 16518 15528 15526 16519 16518 15526 15526 16516 16519 15526 15527 16516 15527 15528 16517 15528 16518 18351 19157 17541 15528 15528 18351 19157 15529 15533 16528 15530 15531 16524 16527 16524 15531 15531 16526 16527 16525 15536 15532 15532 16523 16525 16524 16523 15532 17549 16528 15533 15533 16530 17549 15533 15534 16530 16531 16530 15534 15534 15535 16531 16532 16531 15535 17542 16532 15535 15536 17538 17539 15536 16525 17538 16536 16533 15537 15537 15539 16536 15537 15538 15539 16537 16536 15539 17555 16537 15539 15539 17553 17555 18368 17561 15540 18369 18368 15540 18375 18369 15540 19170 18375 15540 15540 18366 19170 15541 15545 16540 15543 15544 15548 16548 15548 15544 18379 16548 15544 15544 17558 18379 15544 16541 17558 15546 15547 15550 16547 15547 15546 16561 16552 15548 17570 16561 15548 15548 16548 17570 15549 16543 17564 15549 15551 16543 16544 16543 15551 15551 15552 16544 16549 16544 15552 15552 15560 16549 15553 15554 15580 15555 15554 15553 15575 15555 15553 15581 15575 15553 15553 15580 15581 15554 15576 15582 15554 15570 15576 15554 15569 15570 15554 15555 15569 15555 15558 15568 15561 15558 15555 15575 15561 15555 15555 15568 15569 15559 15558 15557 15563 15559 15557 15558 15562 15568 15558 15559 15562 15563 15562 15559 16574 16549 15560 15560 15561 16574 15561 16573 16574 15561 15575 16573 15562 15563 15568 16550 15571 15565 16578 15574 15566 16579 16578 15566 16580 16579 15566 15566 16572 16580 15566 15567 16572 15572 15578 15579 15573 16586 16587 15573 16582 16586 15573 15574 16582 15574 16578 16582 18413 16573 15575 15575 15581 18413 15576 15577 15582 15584 15579 15578 15578 15583 15584 16584 16576 15579 15579 15584 16584 15594 15581 15580 20053 18413 15581 15581 17602 20053 17603 17602 15581 18425 17603 15581 15581 17598 18425 17599 17598 15581 15581 15594 17599 15587 15584 15583 16597 16584 15584 15584 15593 16597 15584 15591 15593 15584 15587 15591 15585 16595 16596 16598 15596 15586 16611 16598 15586 17610 16611 15586 15596 15590 15586 17595 15589 15588 18420 17595 15588 15588 17596 18420 15588 16591 17596 15599 15597 15589 17597 15599 15589 15589 17595 17597 15592 15591 15590 15596 15592 15590 15591 15592 15593 16599 15593 15592 15592 15596 16599 16614 16597 15593 15593 16613 16614 17613 16613 15593 15593 16612 17613 15593 16599 16612 15594 15595 17599 17605 17599 15595 15595 16618 17605 15596 16598 16599 16624 16623 15597 15597 16603 16624 15597 15599 16603 17597 16603 15599 16631 16630 15602 18433 18432 15604 18442 18433 15604 15604 15605 18442 15606 15605 15604 18432 15606 15604 15605 17617 18442 17618 17617 15605 15605 15606 17618 15606 16633 17618 15606 15612 16633 18432 15612 15606 15607 15617 16632 15607 15614 15617 18461 17631 15608 18462 18461 15608 15608 18444 18462 15608 16639 18444 15608 15609 16639 15610 15609 15608 17631 15610 15608 15609 15610 16638 16640 16639 15609 17615 16640 15609 15609 16623 17615 15610 16617 16638 17631 16617 15610 15611 17620 19243 15611 15612 17620 15613 15612 15611 17616 15613 15611 18441 17616 15611 19242 18441 15611 19244 19242 15611 15611 19243 19244 19240 17620 15612 15612 18434 19240 15612 18432 18434 15613 16625 16631 17616 16625 15613 16637 15617 15614 16642 16637 15614 15614 15615 16642 15616 15615 15614 16673 16642 15615 15615 15616 16673 16674 16673 15616 16637 16634 15617 16634 16632 15617 15621 15620 15619 16661 15621 15619 15620 15621 15634 15621 15629 15634 15631 15629 15621 16661 15631 15621 17650 15636 15622 15622 15652 17650 15622 15623 15652 15624 15623 15622 15636 15624 15622 15623 15624 15625 15626 15625 15624 16663 15626 15624 15624 16644 16663 15624 15636 16644 15626 16646 16647 16663 16646 15626 15641 15637 15627 16665 15641 15627 15627 15628 16665 15628 16664 16665 15628 15639 16664 15628 15638 15639 15658 15634 15629 15629 15650 15658 15629 15649 15650 15629 15630 15649 15631 15630 15629 15630 15633 15649 15630 15632 15633 16659 15632 15630 15630 15631 16659 16661 16659 15631 15647 15633 15632 16654 15647 15632 15632 16653 16654 16659 16653 15632 15633 15646 15649 15647 15646 15633 15636 16643 16644 16662 16643 15636 17650 16662 15636 15645 15643 15637 15637 15641 15645 15640 15639 15638 16649 15640 15638 15638 16647 16649 15639 15640 16664 16666 16664 15640 17643 16666 15640 15640 17642 17643 18463 17642 15640 15640 16649 18463 16671 15645 15641 15641 16665 16671 15642 15643 15645 15642 15644 16672 15645 15644 15642 15644 16671 16674 15644 15645 16671 15651 15649 15646 15654 15651 15646 15646 15653 15654 15646 15648 15653 15646 15647 15648 16677 15648 15647 15647 16670 16677 15647 16667 16670 16669 16667 15647 15647 16658 16669 15647 16654 16658 16677 15653 15648 15651 15650 15649 15650 15651 15661 15651 15660 15661 15651 15659 15660 15651 15654 15659 15652 16678 17650 15659 15654 15653 16683 15659 15653 15653 16680 16683 15653 16677 16680 15655 15671 15672 15655 15670 15671 16690 15670 15655 16691 16690 15655 15655 15656 16691 15657 15656 15655 15661 15657 15655 15656 15657 16691 17686 16691 15657 15657 17685 17686 15657 15661 17685 16683 15660 15659 16684 15661 15660 16685 16684 15660 16686 16685 15660 15660 16682 16686 16683 16682 15660 15661 16684 17685 15681 15673 15662 15662 15672 15681 15675 15664 15663 15663 15674 15675 15676 15674 15663 17677 16692 15664 15664 15675 17677 16708 15684 15665 15677 15667 15666 15688 15686 15667 16720 15688 15667 15667 15677 16720 18515 15671 15670 15670 18514 18515 15670 18510 18514 15670 18502 18510 15670 18501 18502 15670 16690 18501 17691 15672 15671 18514 17691 15671 18515 18514 15671 15682 15681 15672 15716 15682 15672 15672 15715 15716 17691 15715 15672 17687 15675 15674 15674 15715 17687 16722 15715 15674 15674 15683 16722 15674 15676 15683 17687 17677 15675 16721 15679 15678 15679 16721 16725 15707 15680 15679 15683 15692 16722 16709 15693 15684 15684 16708 16709 16710 16694 15685 15685 15698 16710 15685 15694 15698 15688 15687 15686 16728 15704 15687 15712 15711 15691 15713 15712 15691 16726 16722 15692 16727 15720 15693 17701 16727 15693 15693 17698 17701 15693 16709 17698 15734 15698 15694 15694 15695 15734 15695 15733 15734 15697 15698 15734 15699 15698 15697 15741 15699 15697 15697 15733 15741 15734 15733 15697 15698 16699 16710 16713 16699 15698 15698 15700 16713 15702 15700 15698 15698 15699 15702 15723 15702 15699 15724 15723 15699 15741 15724 15699 15700 15701 16713 15702 15701 15700 15701 15702 15723 16716 16713 15701 15701 15725 16716 15701 15723 15725 15728 15705 15703 15703 15704 15728 16728 15728 15704 15705 15728 16728 15708 15707 15706 16707 15708 15706 17700 16729 15711 15711 16734 17700 15711 15712 16734 15712 16730 16734 15712 15713 16730 16722 15716 15715 15715 17676 17687 17691 17676 15715 15716 16722 16726 15717 15718 15732 15718 15719 15732 15719 15721 15732 15722 15721 15720 16731 15722 15720 15720 16727 16731 15721 15722 15739 16731 15739 15722 15723 15724 15725 15742 15725 15724 15724 15741 15742 16733 16716 15725 17694 16733 15725 15725 16732 17694 15725 15726 16732 15727 15726 15725 15742 15727 15725 17705 16732 15726 18524 17705 15726 18525 18524 15726 15726 17713 18525 15726 15727 17713 15727 16736 17713 15727 15742 16736 17700 16734 15731 15731 16729 17700 15745 15741 15733 15748 15745 15733 17715 15757 15735 17719 17715 15735 15735 15736 17719 15737 15736 15735 16743 15746 15738 16744 16743 15738 15738 16741 16744 15738 15754 16741 15738 15749 15754 16737 15740 15739 15739 16735 16737 15739 16731 16735 16739 15743 15740 15740 16737 16739 15744 15742 15741 15745 15744 15741 15742 15744 16736 16738 15747 15743 16739 16738 15743 15744 15755 16736 15744 15745 15755 15745 15751 15755 15745 15748 15751 15759 15753 15746 16747 15759 15746 15746 16743 16747 16741 15750 15747 15747 16738 16741 16745 15751 15748 15749 15750 15754 16741 15754 15750 16742 15755 15751 16746 16742 15751 16748 16746 15751 15751 16745 16748 15759 15758 15753 16740 16736 15755 16742 16740 15755 16748 16745 15757 17714 16748 15757 17715 17714 15757 15758 16759 16769 15758 15759 16759 15759 16749 16759 15759 16747 16749 16761 16760 15760 15760 15761 16761 15761 15762 16763 16763 16761 15761 15762 15765 16763 19384 17719 15763 20231 19384 15763 15763 16797 20231 15763 16796 16797 15763 16793 16796 15763 15784 16793 15763 15778 15784 15764 16778 16779 15765 16762 16763 15766 16761 16762 15766 16754 16761 15766 16753 16754 15766 15773 16753 15767 15768 15769 16775 15769 15768 15768 16765 16775 15770 15771 17729 15770 15774 16768 17729 15774 15770 15771 16780 17730 17730 17729 15771 15780 15779 15772 16786 15780 15772 15774 16767 16768 15774 16764 16767 17728 16764 15774 15774 15775 17728 15776 15775 15774 17729 15776 15774 19353 17728 15775 19354 19353 15775 15775 18549 19354 15775 15776 18549 18552 18549 15776 15776 17729 18552 15785 15778 15777 15786 15785 15777 15785 15784 15778 15779 15781 15787 15779 15780 15781 16787 15781 15780 15780 16786 16787 16788 15787 15781 15781 16787 16788 16782 15805 15782 15782 15783 16782 16785 16782 15783 15784 16792 16793 15784 15794 16792 15784 15785 15794 15785 15786 15794 15796 15788 15787 16788 15796 15787 15789 15790 15802 15790 15791 16789 15803 15802 15790 17740 15803 15790 15790 17735 17740 15790 16790 17735 15790 16789 16790 15791 15804 16789 16795 15806 15792 15794 15807 16792 15813 15809 15795 15796 16788 17738 17743 17742 15796 15796 17738 17743 16800 15810 15797 17744 16800 15797 17747 17744 15797 15798 15801 15811 15798 15799 15801 15800 15799 15798 16799 15801 15799 15799 15800 16799 16801 16799 15800 15800 16800 16801 15800 15810 16800 16801 15811 15801 15801 16799 16801 16794 16781 15802 15802 15803 16794 17730 16794 15803 17740 17730 15803 15804 15805 16783 15804 16783 16789 15805 16782 16783 15806 15823 16806 15806 15818 15823 15807 15808 16792 15809 15808 15807 16796 16792 15808 16797 16796 15808 17741 16797 15808 15808 15809 17741 15809 15813 17741 15815 15814 15811 15816 15815 15811 16801 15816 15811 16806 16805 15812 15813 16810 17741 15813 16807 16810 15825 15819 15814 15814 15815 15825 15815 15820 15825 16811 15820 15815 15815 16808 16811 15815 16803 16808 15815 15816 16803 15816 16801 16802 16804 16803 15816 15816 16802 16804 15817 15819 15820 15818 15822 15823 15825 15820 15819 16811 15821 15820 16811 15828 15821 15831 15823 15822 17757 16806 15823 15823 16835 17757 15823 15831 16835 15824 15833 16807 16821 16816 15826 16822 16821 15826 17759 16822 15826 15826 16814 17759 15826 15828 16814 16816 15827 15826 16816 16815 15827 15828 16811 16814 16817 15830 15829 16817 15835 15830 15831 15832 16835 16840 16835 15832 15832 16809 16840 15833 15834 16829 16810 16807 15833 16829 16810 15833 17774 16829 15834 15837 16837 16838 15837 16836 16837 15837 16826 16836 16828 16826 15837 16838 15838 15837 15843 15842 15839 16854 15843 15839 16844 15854 15840 15840 16839 16844 15840 16838 16839 17776 17774 15841 15841 15855 17776 16850 15852 15842 16851 16850 15842 15842 15843 16851 16855 16851 15843 15843 16854 16855 15844 15847 15849 15848 15847 15844 15844 15845 15848 15846 15845 15844 15849 15846 15844 15845 15848 16848 16848 15846 15845 15846 16848 16849 16849 15849 15846 16848 15848 15847 16849 16848 15847 15847 15851 16849 16849 15851 15849 15861 15858 15852 15852 15856 15861 15857 15856 15852 16850 15857 15852 16862 16834 15853 15854 16846 16847 15854 16844 16846 15855 18598 18599 18599 17776 15855 16861 15861 15856 17787 16861 15856 15856 16852 17787 15856 15857 16852 15857 16850 16852 15861 15860 15858 16872 15862 15859 15859 16860 16872 15859 16847 16860 16869 15865 15860 15860 15861 16869 15861 16861 16869 15862 16873 16874 15862 16872 16873 16874 15863 15862 16895 15866 15864 15864 16883 16895 17818 16883 15864 15864 15865 17818 15865 16869 17818 16895 15871 15866 16889 15869 15867 16906 15872 15870 16907 16906 15870 15870 15871 16907 16908 16907 15871 15871 16896 16908 15871 16895 16896 16910 15873 15872 15872 16906 16910 16910 15895 15873 16904 15890 15874 16905 16904 15874 15876 15886 16912 16924 15878 15877 15877 15891 16924 16933 15879 15878 15878 16932 16933 15878 16931 16932 15878 16924 16931 16925 15893 15879 16933 16925 15879 15882 16936 16937 18640 16936 15882 18641 18640 15882 16914 16912 15886 15886 15887 16914 15888 15887 15886 16926 16914 15887 16940 16926 15887 15887 15896 16940 15887 15888 15896 15888 15889 15896 15889 16939 16940 15889 16938 16939 16940 15896 15889 17837 16901 15890 15890 17830 17837 15890 16904 17830 15894 15899 15905 18642 16955 15895 15895 16919 18642 15895 16910 16919 15897 15902 15903 15897 15898 15902 16915 15902 15898 16950 15905 15899 15900 17850 18641 15900 15911 17850 15903 15902 15901 16944 15903 15901 17843 16944 15901 15901 16923 17843 15901 15902 16923 15902 16915 16923 15903 16943 16952 16944 16943 15903 15904 16949 16961 15904 15906 16949 15904 15905 15906 16950 15906 15905 16935 16925 15906 16950 16935 15906 15906 16948 16949 15906 16933 16948 15906 16925 16933 17863 17862 15907 18657 17863 15907 15907 18656 18657 15907 18646 18656 15907 16955 18646 16957 16938 15908 15908 16956 16957 15908 15910 16956 15908 15909 15910 15921 15910 15909 15909 15913 15921 15910 15921 16956 17861 17850 15911 17873 17861 15911 15913 15920 15921 15913 15916 15920 16962 15922 15914 15914 16958 16962 15914 16952 16958 15927 15920 15916 15916 15917 15927 15917 15918 15927 17869 15927 15918 15918 17862 17869 15921 15920 15919 17866 15921 15919 18660 17866 15919 15919 17879 18660 15919 16966 17879 15919 15920 16966 16967 16966 15920 15920 15927 16967 17866 16956 15921 16962 15923 15922 17870 17867 15924 17871 17870 15924 15924 15925 19484 15926 15925 15924 17867 15926 15924 20325 19484 15925 15925 15926 20325 15926 20324 20325 15926 19498 20324 15926 17867 19498 16970 16967 15927 17869 16970 15927 15928 15929 16965 15929 16960 16965 15929 16959 16960 16961 16959 15929 19502 17874 15930 15930 16973 19502 15930 16972 16973 16980 15945 15932 15932 16968 16980 15933 15934 15944 15934 15935 15944 15936 15935 15934 15957 15936 15934 16979 16977 15935 17884 16979 15935 17885 17884 15935 15935 16989 17885 15935 15936 16989 16977 15944 15935 16990 16989 15936 16994 16990 15936 17904 16994 15936 15936 17900 17904 15936 15957 17900 15950 15949 15940 16981 15950 15940 16982 16981 15940 15940 15941 16982 15941 15942 16982 15942 15943 16982 15943 16974 16982 16975 16974 15943 16976 16975 15943 15952 15951 15945 16980 15952 15945 16992 15955 15946 15946 15954 16992 15947 15948 16993 15977 15965 15947 17902 15977 15947 15947 16993 17902 15949 17887 17893 15949 15950 17887 15950 16981 17887 17905 17900 15951 17906 17905 15951 15951 16991 17906 15951 15953 16991 15951 15952 15953 17890 15953 15952 15952 17886 17890 15952 16984 17886 15952 16980 16984 17899 16991 15953 15953 17890 17899 16973 16972 15958 19506 16973 15958 15958 15959 19506 15959 18670 19506 18671 18670 15959 15959 15960 18671 15960 17901 18671 15960 16997 17901 15961 15962 16997 17907 16997 15962 15962 15963 17907 17921 17907 15963 15963 16999 17921 15963 15967 16999 15977 15976 15965 17000 16999 15967 15970 15969 15968 17001 15970 15968 15968 15972 17001 15968 15971 15972 15969 15970 15985 17004 15985 15970 17930 17004 15970 15970 17001 17930 15973 15972 15971 15975 15973 15971 15972 15973 17012 17012 17001 15972 15973 15986 17005 15973 15974 15986 15973 17005 17012 17008 15978 15976 15976 17006 17008 15976 15979 17006 15976 15977 15979 17002 15979 15977 17929 17002 15977 17937 17929 15977 15977 17917 17937 17918 17917 15977 15977 17902 17918 16000 15980 15978 17008 16000 15978 15979 17002 17006 16000 15981 15980 16011 15993 15981 15981 16000 16011 17020 17009 15982 17026 17020 15982 15982 17019 17026 15982 15990 17019 17003 15991 15983 15983 15984 17003 15984 15985 17003 17004 17003 15985 15986 15987 17005 15987 15999 17005 15987 15998 15999 15987 15992 15998 15988 16002 16003 15988 15989 16002 16014 16002 15989 15989 15994 16014 15990 16004 17019 15991 17004 17011 15991 17003 17004 16008 15998 15992 16009 16008 15992 16013 16001 15993 15993 16012 16013 15993 16011 16012 15994 16013 16014 15994 16001 16013 17074 17042 15995 15995 17040 17074 17049 16007 15996 15996 17032 17049 17050 17033 15997 17051 17050 15997 17052 17051 15997 15997 15998 17052 15999 15998 15997 17033 15999 15997 15998 16008 17052 17012 17005 15999 17014 17012 15999 17033 17014 15999 17025 16011 16000 16000 17018 17025 16000 17016 17018 16000 17008 17016 17037 16003 16002 16002 16014 17037 17071 17040 16003 16003 17037 17071 17041 17019 16004 17959 17045 16005 16005 17958 17959 16005 17061 17958 16005 16006 17061 16006 16018 17061 17974 17065 16008 16008 17053 17974 16008 16009 17053 17065 17052 16008 17035 17034 16010 17954 17035 16010 17955 17954 16010 17956 17955 16010 16010 16035 17956 17025 16012 16011 17057 16013 16012 17068 17057 16012 16012 17067 17068 16012 17025 17067 17039 16014 16013 17057 17039 16013 17039 17037 16014 17062 16038 16015 17063 17062 16015 17962 17063 16015 16015 17048 17962 16015 16021 17048 17978 17079 16016 16016 17080 17978 16016 16030 17080 16016 16029 16030 17035 16033 16017 16017 17034 17035 17958 17061 16018 17960 17958 16018 16018 16019 17960 17961 17960 16019 16019 16020 17961 18749 17961 16020 16020 17062 18749 16022 16023 16026 16024 16023 16022 16039 16024 16022 17084 16039 16022 17085 16026 16023 16023 16024 17085 16024 16039 17089 19578 17085 16024 16024 17089 19578 16025 16027 16045 16040 16028 16025 16045 16040 16025 16045 16027 16026 17085 16045 16026 16032 16030 16029 17081 17080 16030 17086 17081 16030 16030 16031 17086 16032 16031 16030 17980 17086 16031 16031 17979 17980 16031 16032 17979 16032 17951 17979 16032 17950 17951 16032 16034 17950 16032 16033 16034 17035 16034 16033 17953 17950 16034 16034 17035 17953 16035 16036 16041 16035 17082 17956 16035 16041 17082 16037 17031 17976 17044 17031 16037 17094 16043 16040 16040 16045 17094 17087 17083 16042 17981 17087 16042 16042 17977 17981 16043 17094 17095 17095 16048 16043 16044 17083 17093 17088 17083 16044 17986 17094 16045 16045 17085 17986 16046 16050 16055 16046 16047 16050 17999 16050 16047 18000 17999 16047 16047 17096 18000 16047 16048 17096 16048 17095 17096 17984 17082 16049 17988 17984 16049 17109 16055 16050 17999 17109 16050 17128 16053 16051 17129 17128 16051 17138 17129 16051 17139 17138 16051 16051 16076 17139 16054 16053 16052 17091 16054 16052 17092 17091 16052 18768 17092 16052 16052 16053 18768 16053 18008 18768 16053 17128 18008 17091 17090 16054 17109 16056 16055 16089 16077 16056 17120 16089 16056 16056 17109 17120 16090 16078 16057 16057 16077 16090 16058 17131 18010 16099 16079 16059 16059 16060 16099 16061 16060 16059 16079 16061 16059 16060 17111 17112 17114 17111 16060 16060 16061 17114 17146 16099 16060 16060 17136 17146 16060 17132 17136 16060 17112 17132 16061 17097 17114 16061 16080 17097 16061 16079 16080 16062 16066 17101 16084 16066 16062 16062 16082 16084 16062 16063 16082 16064 16063 16062 17101 16064 16062 16083 16082 16063 16063 16080 16083 16063 16064 16080 17100 16080 16064 18003 17100 16064 16064 17101 18003 16085 16068 16065 16065 16066 16085 16067 16066 16065 16069 16067 16065 16065 16068 16069 16066 16084 16085 16066 16067 17101 17991 17101 16067 17992 17991 16067 16067 16069 17992 16068 16085 16087 16071 16069 16068 16068 16070 16071 16086 16070 16068 16087 16086 16068 17994 17992 16069 16069 16071 17994 16070 16073 16074 16088 16073 16070 16070 16086 16088 16072 16071 16070 16074 16072 16070 16071 16072 17994 17995 17994 16072 16072 16074 17995 16075 16074 16073 16088 16075 16073 16074 16075 17102 17997 17995 16074 16074 17102 17997 17103 17102 16075 17106 17103 16075 16075 16088 17106 17163 17139 16076 16076 16108 17163 16077 16089 16090 16078 16090 17141 16104 16091 16078 17141 16104 16078 16099 16081 16079 16081 16080 16079 17100 17097 16080 16080 16081 16083 16100 16083 16081 16081 16099 16100 16101 16084 16082 16082 16100 16101 16082 16083 16100 16102 16085 16084 16084 16101 16102 16102 16087 16085 16093 16088 16086 16086 16092 16093 16086 16087 16092 16087 16129 16130 16087 16102 16129 16130 16092 16087 16088 16093 17106 18793 16090 16089 16089 18017 18793 18019 18017 16089 16089 17130 18019 16089 17121 17130 16089 17120 17121 18793 17140 16090 16090 17140 17141 16104 16094 16091 16131 16093 16092 16092 16130 16131 17126 17106 16093 16093 16116 17126 16117 16116 16093 16132 16117 16093 16133 16132 16093 16093 16131 16133 16107 16095 16094 16094 16105 16107 16094 16104 16105 18033 18022 16096 16096 16097 18033 16098 16097 16096 18022 16098 16096 16097 16098 17142 16097 17164 18033 16097 17152 17164 16097 17142 17152 18010 17131 16098 18021 18010 16098 18022 18021 16098 16098 17131 17142 17157 16100 16099 16099 17147 17157 16099 17146 17147 17157 16101 16100 16136 16102 16101 17161 16136 16101 16101 17160 17161 16101 17157 17160 16137 16129 16102 16102 16136 16137 16113 16109 16103 17168 16113 16103 16103 16112 17168 17141 16105 16104 16105 16106 16107 17140 16106 16105 17141 17140 16105 17151 16107 16106 18030 17151 16106 16106 18027 18030 16106 17140 18027 17164 17152 16107 16107 17151 17164 17167 17163 16108 16108 16122 17167 16109 16113 16125 16110 16126 17170 17170 16112 16110 16121 16120 16111 17171 17168 16112 16112 17170 17171 17169 16125 16113 16113 17168 17169 16114 16115 16128 16128 16126 16114 16115 16127 16128 16116 16118 17126 16118 16119 17148 17137 17126 16118 17148 17137 16118 18038 17167 16122 16122 17178 18038 16122 17176 17178 17177 17176 16122 16123 16125 17169 17187 16124 16123 18042 17187 16123 16123 17169 18042 18062 16134 16124 16124 17187 18062 17172 17170 16126 18044 17172 16126 16126 17179 18044 16126 16128 17179 18057 18045 16127 18045 16128 16127 17180 17179 16128 17181 17180 16128 18047 17181 16128 16128 18045 18047 18835 17186 16134 16134 18062 18835 17196 17190 16135 18823 17196 16135 16135 17175 18823 16135 17173 17175 16135 16136 17173 16136 17161 17173 18844 18072 16139 16139 17190 18844 16141 16150 17195 16141 16145 16150 16147 16146 16143 16163 16147 16143 16143 16153 16163 16144 16146 16147 16152 16150 16145 16150 16149 16148 18851 16150 16148 18856 18851 16148 16148 17214 18856 16148 16149 17214 16149 16163 17219 16149 16151 16163 16152 16151 16149 16149 16150 16152 17226 17214 16149 16149 17219 17226 18063 17195 16150 18850 18063 16150 18851 18850 16150 16153 16160 16163 16179 16178 16154 16154 16155 16179 16156 16155 16154 16157 16156 16154 16155 16156 17220 18098 16179 16155 16155 17220 18098 16156 17215 17216 16156 16158 17215 16156 16157 16158 16156 17216 17220 18859 17215 16158 16158 16168 18859 16158 16159 16168 16159 16164 16168 16160 16162 16163 16177 16162 16161 18106 16177 16161 18107 18106 16161 17219 16163 16162 16162 16177 17219 16164 16167 16168 17236 16167 16164 16164 16165 17236 16165 17235 17236 16165 17234 17235 17204 16171 16166 16166 17198 17204 16169 16168 16167 18871 16169 16167 16167 18867 18871 18869 18867 16167 16167 17236 18869 16168 18087 18859 16168 16169 18087 18871 18087 16169 17218 17217 16170 16170 17204 17218 16170 16171 17204 17237 16172 16170 17238 17237 16170 16170 17228 17238 16170 17217 17228 16183 16180 16173 16173 16176 16183 16173 16174 16176 16175 16174 16173 16180 16175 16173 16190 16176 16174 17233 16190 16174 18089 17233 16174 16174 16175 18089 16175 17222 18089 16175 17221 17222 16175 16182 17221 16175 16180 16182 17232 16183 16176 16176 16190 17232 18093 17219 16177 18106 18093 16177 16178 16179 17241 17241 17240 16178 18098 17241 16179 16180 16183 16185 16180 16181 16182 16185 16181 16180 16197 16196 16181 16181 16185 16197 16196 16182 16181 17247 17221 16182 17250 17247 16182 16182 17248 17250 17249 17248 16182 16182 16209 17249 16182 16196 16209 16183 16184 16185 17232 16184 16183 17252 16198 16184 17253 17252 16184 17254 17253 16184 16184 17239 17254 16184 17232 17239 16198 16185 16184 16198 16197 16185 18101 17234 16186 16186 16187 18101 16187 17243 18101 17244 17243 16187 16187 16194 17244 16208 16189 16188 17238 16208 16188 16188 17237 17238 16189 16207 18889 16208 16207 16189 18888 17246 16189 19720 18888 16189 16189 18889 19720 17233 17223 16190 16190 17229 17232 17231 17229 16190 18080 17231 16190 16190 17223 18080 16191 16226 18113 16191 16200 16226 16202 16193 16192 17255 16202 16192 16192 17242 17255 16202 16201 16193 18103 17244 16194 16194 17245 18103 16195 16203 17245 16210 16209 16196 16196 16197 16210 17260 16210 16197 16197 16198 17260 16198 17252 17260 16225 16200 16199 17277 16225 16199 16199 16234 17277 16199 16211 16234 16200 16225 16226 18123 16216 16201 16201 16202 18123 16202 17256 18123 16202 17255 17256 18108 17245 16203 16203 17257 18108 16217 16205 16204 16204 16206 16217 16205 16217 17259 17259 17258 16205 17259 16217 16206 16207 18088 18875 16207 17238 18088 16207 16208 17238 16207 18875 18889 17251 17249 16209 16209 16210 17251 17273 17251 16210 16210 17265 17273 16210 17260 17265 16211 16224 16234 16213 16218 16229 16219 16218 16213 17261 16219 16213 16222 16221 16214 16214 16215 16222 16216 16215 16214 17269 16222 16215 16215 16216 17269 18123 17269 16216 18130 16228 16218 16218 16219 18130 16218 16228 16229 16219 17280 18130 16219 17261 17280 16220 16230 17281 16221 16222 16223 18124 16223 16222 16222 17269 18124 17282 16240 16223 18124 17282 16223 17277 16234 16224 16224 16225 17277 16241 16225 16224 16227 16226 16225 17278 16227 16225 17279 17278 16225 16225 16241 17279 18121 18113 16226 16226 16227 18121 16227 18110 18121 18135 18110 16227 16227 18129 18135 16227 17278 18129 16228 18130 18897 16228 18897 18898 16230 16235 17281 16236 16235 16230 18136 17290 16231 18908 18136 16231 16231 16232 18908 16233 16232 16231 17290 16233 16231 16232 16233 16240 16232 17283 18908 16232 16240 17283 18131 17281 16235 16235 17287 18131 16235 17285 17287 16235 16236 17285 16236 16237 17285 17286 17285 16237 17289 17286 16237 16237 16238 17289 16238 16239 17289 17297 17289 16239 16240 17282 17283 16241 16242 17279 17294 17279 16242 16242 16252 17294 16242 16243 16252 16244 17304 17305 16244 16245 17304 16246 16245 16244 16247 16246 16244 16245 16246 16296 18149 17304 16245 18163 18149 16245 16245 16296 18163 16246 17311 17314 16246 17306 17311 16246 16247 17306 17314 16296 16246 16247 16248 17306 16249 16250 16256 16251 16250 16249 16256 16251 16249 16250 16254 16256 16255 16254 16250 17300 16255 16250 16250 17292 17300 16250 17291 17292 16250 16251 17291 16251 17266 17291 16251 16256 17266 17309 17294 16252 16252 16258 17309 17315 17313 16253 16257 16256 16254 16262 16257 16254 16254 16255 16262 16255 17327 17328 17346 17327 16255 17347 17346 16255 16255 17300 17347 16278 16262 16255 17328 16278 16255 18151 17266 16256 16256 17308 18151 16256 16257 17308 16257 16261 17308 16257 16260 16261 16262 16260 16257 16258 16271 17309 16258 16264 16271 16258 16263 16264 16259 17303 18142 16269 16261 16260 16270 16269 16260 16260 16262 16270 18157 17308 16261 16261 17325 18157 16261 16269 17325 16278 16270 16262 16272 16271 16264 16273 16272 16264 17321 17320 16266 16266 17319 17321 18162 17340 16267 16267 16268 18162 16268 17320 18162 16269 16288 17325 16269 16276 16288 16277 16276 16269 16269 16270 16277 16278 16277 16270 17316 17309 16271 17329 17316 16271 16271 16272 17329 17331 17329 16272 16272 16280 17331 16272 16273 16280 16281 16280 16273 16291 16281 16273 16273 16279 16291 16283 16282 16274 17339 16283 16274 16274 16275 17339 16289 16288 16276 16290 16289 16276 16304 16290 16276 17359 16304 16276 16276 16278 17359 16276 16277 16278 17366 17359 16278 16278 17328 17366 16292 16291 16279 17336 17331 16280 17350 17336 16280 16280 16281 17350 18180 17350 16281 16281 18177 18180 16281 16291 18177 16282 16293 16303 16294 16293 16282 16282 16283 16294 17351 16294 16283 16283 17337 17351 17339 17337 16283 18163 17341 16284 16284 18154 18163 17341 16285 16284 17341 16295 16285 16286 16296 17334 16286 16295 16296 17364 16310 16287 16287 16297 17364 17326 17325 16288 16288 16289 17326 16289 16300 17326 16289 16299 16300 16289 16298 16299 16289 16290 16298 16304 16298 16290 18179 18177 16291 18953 18179 16291 16291 17360 18953 16291 16331 17360 16291 16292 16331 16319 16303 16293 16293 16294 16319 17363 16319 16294 16294 17351 17363 17341 16296 16295 16296 17314 17334 16296 17341 18163 16297 17352 17364 17353 17352 16297 17354 17353 16297 16297 17348 17354 16304 16299 16298 16302 16300 16299 17365 16302 16299 18183 17365 16299 16299 16304 18183 18167 17326 16300 18175 18167 16300 16300 18174 18175 16300 17356 18174 16300 16301 17356 16302 16301 16300 16301 16302 17365 17365 17356 16301 16304 17357 18183 17358 17357 16304 17359 17358 16304 16305 16311 16331 16306 16314 16315 16306 16307 16314 16308 16307 16306 17370 16308 16306 17372 17370 16306 17375 17372 16306 16307 16313 17369 16307 16308 16313 17369 16314 16307 18189 16313 16308 18198 18189 16308 16308 18194 18198 16308 17370 18194 17373 16317 16309 17374 17373 16309 16309 17371 17374 16309 16310 17371 16310 17364 17371 16311 16330 16331 16311 16318 16330 16333 16319 16312 16312 16321 16333 16324 16320 16316 17373 16324 16316 16316 16317 17373 16335 16334 16321 16337 16335 16321 16321 16336 16337 16334 16333 16321 17386 16346 16322 18210 17386 16322 16322 16323 18210 16323 16338 18210 18195 16338 16324 16324 18190 18195 16324 17373 18190 16325 16328 16339 18988 16328 16325 16325 18204 18988 16325 18203 18204 16325 17378 18203 16325 16326 17378 16327 16326 16325 16339 16327 16325 18200 17378 16326 18202 18200 16326 16326 16348 18202 16326 16327 16348 16327 16347 16348 16327 16339 16347 18193 18192 16330 16332 16331 16330 18192 16332 16330 16331 16332 17360 17362 17360 16332 19822 17362 16332 16332 18192 19822 16334 16343 16356 16334 16335 16343 16335 16337 16343 16343 16337 16336 16338 18195 18210 16342 16341 16340 16341 16350 17381 16341 16342 16350 16343 16344 16356 16358 16357 16344 16344 16351 16358 16357 16356 16344 18983 18207 16345 16345 18967 18983 16345 18196 18967 16346 17386 17389 16349 16348 16347 16354 16349 16347 18215 18202 16348 16348 16349 18215 16349 16354 17396 19010 18215 16349 16349 17398 19010 16349 17396 17398 16350 17380 17381 17401 16358 16351 16351 16370 17401 16363 16353 16352 18219 16363 16352 18222 18219 16352 16352 17395 18222 16353 16363 17384 16354 16367 17397 17397 17396 16354 17393 17392 16355 16355 17391 17393 16355 17390 17391 16355 16374 17390 16357 16358 17394 17394 16379 16357 17401 17394 16358 16359 17412 17413 16394 16392 16359 17413 16394 16359 18999 18218 16360 19006 18999 16360 16360 16361 19006 16362 16361 16360 18218 16362 16360 16361 19005 19006 16361 16362 19005 16362 18223 19005 16362 18219 18223 16362 16363 18219 17384 16363 16362 18218 17384 16362 16364 18201 18215 16364 16365 18201 16366 16365 16364 19007 16366 16364 19876 19007 16364 16364 19010 19876 16364 18215 19010 16365 18200 18201 18986 18200 16365 16365 16366 18986 19860 18986 16366 20645 19860 16366 16366 19008 20645 16366 19007 19008 16367 16368 17399 17399 17397 16367 17403 17402 16368 17410 17403 16368 17402 17399 16368 16369 16371 16372 17400 16371 16369 16370 16381 17401 16370 16376 16381 16378 16372 16371 18228 16378 16371 16371 17400 18228 16378 16373 16372 16373 16378 16388 17418 17390 16374 16374 16389 17418 16374 16375 16389 16376 16377 16381 16399 16381 16377 16377 16391 16399 19035 16388 16378 16378 18229 19035 16378 18228 18229 17411 17404 16379 16379 16382 17411 18220 16382 16379 16379 17394 18220 17404 16380 16379 17404 16390 16380 16381 16382 17401 16383 16382 16381 16408 16383 16381 16381 16399 16408 16382 16383 17411 18220 17401 16382 16383 16408 17411 16384 16392 16394 16393 16385 16384 16394 16393 16384 17424 16396 16385 17425 17424 16385 16385 16393 17425 18231 16400 16386 16386 16387 18231 16387 17422 18231 16387 17421 17422 16388 16410 17433 19035 16410 16388 17423 16407 16390 16390 17411 17423 16390 17404 17411 16393 16395 17425 16393 16394 16395 17420 16395 16394 16394 17413 17420 16395 17424 17425 17427 17424 16395 19031 17427 16395 19032 19031 16395 19033 19032 16395 16395 19030 19033 16395 17420 19030 16396 17424 17429 16405 16398 16397 16397 16404 16405 18237 17419 16398 18242 18237 16398 16398 16405 18242 16399 16407 16408 18231 18226 16400 16401 17431 17432 18243 17431 16401 18251 18243 16401 16401 16402 18251 16402 16420 18251 16406 16405 16404 16405 16406 18242 16406 17439 18242 16406 17438 17439 17423 16408 16407 17423 17411 16408 18247 17436 16409 19039 18247 16409 16409 16411 19039 18249 16411 16410 19045 18249 16410 16410 19035 19045 16411 19038 19039 16411 18249 19038 17436 16422 16413 17449 16420 16415 16416 16422 16424 16417 16433 17443 16418 17447 17454 16418 16419 17447 17448 17447 16419 16419 17445 17448 17446 17445 16419 16419 16432 17446 16420 17449 18251 16423 16422 16421 18265 16423 16421 16421 17440 18265 17450 17440 16421 16421 16422 17450 16422 16423 16424 16422 17436 17450 17458 17456 16423 19055 17458 16423 16423 18265 19055 17456 16424 16423 17456 16425 16424 17458 17457 16425 16425 17456 17458 18255 16449 16426 18256 18255 16426 16426 17458 18256 16426 17457 17458 16428 17451 17462 16444 16442 16429 16429 16434 16444 16431 16430 16429 19081 16431 16429 16429 16442 19081 19061 18262 16431 19081 19061 16431 18279 17446 16432 16432 16447 18279 16433 16441 17443 16448 16436 16435 16435 16437 16448 17482 16448 16437 18280 17482 16437 19923 18280 16437 16437 17454 19923 18281 17465 16438 16438 16452 18281 16438 16451 16452 17471 16454 16439 16439 16440 17471 16440 17469 17471 17470 17469 16440 16440 17463 17470 16440 17460 17463 16440 16449 17460 18257 17443 16441 18272 18257 16441 16442 18287 19081 18288 18287 16442 16442 16443 18288 16444 16443 16442 16443 17444 18276 16443 16444 17444 16443 18287 18288 16443 18276 18287 17481 16447 16445 18313 17481 16445 16445 18304 18313 16445 17493 18304 16445 16446 17493 16447 17481 18279 17482 16450 16448 16449 17459 17460 18269 17459 16449 16449 18255 18269 17482 16458 16450 16453 16452 16451 18289 18281 16452 16452 16453 18289 16453 17467 18289 16454 17471 17476 16455 16456 16463 16457 16456 16455 18283 16457 16455 16455 17466 18283 16456 17473 17474 17478 17473 16456 16456 16457 17478 16456 16462 16463 18284 17478 16457 16457 18283 18284 16467 16466 16458 17482 16467 16458 18290 17485 16459 18299 18290 16459 16459 16460 18299 16461 16460 16459 17485 16461 16459 19104 18299 16460 16460 17487 19104 16460 17486 17487 17491 17486 16460 16460 16461 17491 16474 16473 16464 17492 16474 16464 16464 16465 17492 16465 17488 17492 17489 17488 16465 16465 17479 17489 17480 17479 16465 16465 17475 17480 16465 17474 17475 17495 16477 16466 17496 17495 16466 16466 16467 17496 18301 17496 16467 16467 18293 18301 16467 17482 18293 17498 16471 16469 16472 16471 16470 19119 16495 16470 16470 16471 19119 19120 19119 16471 16471 19116 19120 16471 18305 19116 16471 17498 18305 16474 17502 17508 17503 17502 16474 16474 17492 17503 16477 16476 16475 16490 16489 16475 16496 16490 16475 16475 16476 16496 16476 16477 17495 17510 16496 16476 16476 17495 17510 16478 16479 17499 17500 17499 16479 17501 17500 16479 16479 16481 17501 16482 16481 16480 16484 16482 16480 18308 17501 16481 16481 16482 18308 19122 18309 16482 16482 16483 19122 16484 16483 16482 18309 18308 16482 16483 16484 18318 16483 18310 19122 18311 18310 16483 18318 18311 16483 16484 16485 18318 18326 18318 16485 16485 16487 18326 16485 16486 16487 18333 16487 16486 19131 18333 16486 16486 18312 19131 16486 17508 18312 18328 18326 16487 16487 17518 18328 17524 17518 16487 18333 17524 16487 16488 17512 18334 16488 16489 17512 18334 18323 16488 16489 16490 17512 16490 16496 17511 17519 17512 16490 16490 17511 17519 17521 16492 16491 16491 16497 17521 16492 18330 19113 16492 16493 18330 16494 16493 16492 16505 16494 16492 17521 16505 16492 16492 17497 17506 19113 17497 16492 19951 18330 16493 19957 19951 16493 16493 16494 19957 16494 17520 19957 16494 16505 17520 18316 16500 16495 18317 18316 16495 19119 18317 16495 16496 18315 18329 16496 17510 18315 18329 17511 16496 16500 16499 16498 16499 16500 18331 16500 18316 18331 16501 16503 16504 17516 16504 16503 17531 16507 16504 16504 17517 17531 16504 17516 17517 19136 17520 16505 16505 17525 19136 17531 17529 16507 17528 16510 16508 19137 17528 16508 16508 16509 19137 19145 19137 16509 16509 18341 19145 16510 17527 18335 17528 17527 16510 17535 17534 16511 16511 16520 17535 17522 16515 16512 16512 16514 17522 16512 16513 16514 18336 16514 16513 17525 17522 16514 18342 17525 16514 16514 18338 18342 16514 18336 18338 16518 18344 19158 16518 16519 18344 19158 18351 16518 16519 18343 18344 17536 17535 16520 20001 19161 16521 16521 16522 20001 20009 20001 16522 16522 18357 20009 16522 16529 18357 17537 16525 16523 18347 17537 16523 18350 18347 16523 16523 16524 18350 16524 16527 18350 16525 17537 17538 17540 16527 16526 18356 17540 16526 16526 17541 18356 16527 17540 18350 17549 16529 16528 18358 18357 16529 16529 17549 18358 16530 16532 17549 16530 16531 16532 18361 17549 16532 16532 17546 18361 18359 17546 16532 16532 18353 18359 16532 17542 18353 17552 16534 16533 16533 17551 17552 16533 16537 17551 16533 16536 16537 17552 16535 16534 16535 17552 18365 17555 17551 16537 18373 17553 16538 19173 18373 16538 16538 18386 19173 16538 16539 18386 16539 18381 18386 16539 18372 18381 17564 17554 16540 16541 16545 17558 16546 16545 16541 17561 17557 16542 18381 17564 16543 18387 18381 16543 16543 16544 18387 16544 18384 18387 16544 16549 18384 18379 17558 16545 16545 18378 18379 16545 16546 18378 16546 18377 18378 16546 18376 18377 16546 17557 18376 16548 17562 17570 17563 17562 16548 19177 17563 16548 16548 18380 19177 16548 18379 18380 18385 18384 16549 16549 16574 18385 16550 16551 16568 16552 16551 16550 16551 16558 16568 16551 16552 16558 16552 16553 16558 16554 16553 16552 16561 16554 16552 16553 16556 16558 16553 16555 16556 16553 16554 16555 16560 16555 16554 17575 16560 16554 17576 17575 16554 16554 16561 17576 16555 16560 18401 16563 16556 16555 17579 16563 16555 18401 17579 16555 16556 16557 16558 16562 16557 16556 16563 16562 16556 16559 16558 16557 16566 16559 16557 16557 16565 16566 16557 16562 16565 16569 16568 16558 16558 16559 16569 17585 16569 16559 16559 16566 17585 17575 17572 16560 16560 17572 18401 16561 17571 17576 16561 17570 17571 16562 16564 16565 16562 16563 16564 16567 16564 16563 17577 16567 16563 17578 17577 16563 17579 17578 16563 16567 16565 16564 17584 16566 16565 16565 17583 17584 16565 16567 17583 17586 17585 16566 17589 17586 16566 16566 17584 17589 16567 17581 17583 16567 17577 17581 17593 17592 16568 16568 16569 17593 17594 17593 16569 16569 17585 17594 16592 16572 16570 16570 16585 16592 16570 16571 16585 16571 16577 16585 16581 16580 16572 16592 16581 16572 19219 16574 16573 19224 19219 16573 16573 18413 19224 19205 18385 16574 19219 19205 16574 17600 16595 16575 16575 17592 17600 16584 16577 16576 16577 16584 16585 16578 16581 16582 16578 16579 16581 16579 16580 16581 16583 16582 16581 16600 16583 16581 16581 16592 16600 16593 16586 16582 16582 16590 16593 16602 16590 16582 16582 16583 16602 17608 16602 16583 16583 16601 17608 16583 16600 16601 16614 16585 16584 16584 16597 16614 16607 16592 16585 16614 16607 16585 16588 16587 16586 16593 16588 16586 16587 16588 16594 18416 16594 16588 18427 18416 16588 16588 16589 18427 16590 16589 16588 16593 16590 16588 19237 18427 16589 16589 18439 19237 16589 16602 18439 16589 16590 16602 18418 17596 16591 16591 17601 18418 16591 16594 17601 16607 16600 16592 18416 17601 16594 16595 17600 17604 17604 16596 16595 17604 16605 16596 16612 16599 16598 16622 16612 16598 16598 16620 16622 16598 16611 16620 16606 16601 16600 16607 16606 16600 16601 16608 17608 16601 16606 16608 16602 17608 18439 17611 16624 16603 18428 17611 16603 16603 17597 18428 16625 16619 16604 16630 16625 16604 18431 16610 16605 16605 17606 18431 16605 17604 17606 16609 16608 16606 16616 16609 16606 16606 16615 16616 16606 16613 16615 16606 16607 16613 16614 16613 16607 17609 17608 16608 17614 17609 16608 16608 16609 17614 18438 17614 16609 16609 16616 18438 18431 17610 16610 16611 17610 17612 16635 16620 16611 17612 16635 16611 16612 16622 17613 17613 16615 16613 17625 16616 16615 16615 17613 17625 20081 18438 16616 16616 18448 20081 16616 17625 18448 17640 16641 16617 16617 17631 17640 18426 17605 16618 18430 18426 16618 16618 16619 18430 16619 18429 18430 16619 16625 18429 16620 16621 16622 16635 16621 16620 16629 16622 16621 16636 16629 16621 16621 16635 16636 17622 17613 16622 16622 16629 17622 16623 16624 17615 18450 17615 16624 16624 17611 18450 16625 17616 18429 16625 16630 16631 17621 16635 16626 18454 17621 16626 16626 16627 18454 16628 16627 16626 16635 16628 16626 20099 18454 16627 16627 19255 20099 16627 16628 19255 19256 19255 16628 16628 18436 19256 18443 18436 16628 16628 16635 18443 16629 17621 17622 16629 16636 17621 16634 16633 16632 16633 16634 17618 16634 16637 17617 16634 17617 17618 17621 16636 16635 16635 17612 18443 17626 17617 16637 16637 16642 17626 16639 16640 18444 16640 17615 18444 16641 16660 16661 17640 16660 16641 18453 17626 16642 16642 16673 18453 16645 16644 16643 16662 16645 16643 16644 16646 16663 16644 16645 16646 16648 16646 16645 17644 16648 16645 17645 17644 16645 18478 17645 16645 16645 16662 18478 16648 16647 16646 16647 16648 16649 17644 16649 16648 16649 17649 18463 16649 17644 17649 16658 16657 16650 16669 16658 16650 16650 16651 16669 16652 16651 16650 16655 16652 16650 16656 16655 16650 17635 16656 16650 16650 17629 17635 16650 16657 17629 16651 16667 16669 16651 16652 16667 16668 16667 16652 17647 16668 16652 17648 17647 16652 16652 17632 17648 16652 16655 17632 16657 16654 16653 17636 16657 16653 16653 16660 17636 16653 16659 16660 16654 16657 16658 17633 17632 16655 18457 17633 16655 16655 16656 18457 18458 18457 16656 16656 17634 18458 17635 17634 16656 17630 17629 16657 17636 17630 16657 16661 16660 16659 17639 17636 16660 17640 17639 16660 16662 17650 18478 16666 16665 16664 16665 16666 16671 16674 16671 16666 17643 16674 16666 16667 16668 16670 16681 16670 16668 16668 16675 16681 16676 16675 16668 17647 16676 16668 16681 16677 16670 18472 18453 16673 16673 17646 18472 16673 16674 17646 18469 17646 16674 16674 17643 18469 17655 16681 16675 17656 17655 16675 18482 17656 16675 16675 17654 18482 16675 16676 17654 18481 17654 16676 16676 17651 18481 16676 17647 17651 16681 16680 16677 17669 17650 16678 16678 16679 17669 17671 17669 16679 16679 17663 17671 16679 16695 17663 16680 16682 16683 17665 16682 16680 16680 17664 17665 16680 17655 17664 16680 16681 17655 17667 16686 16682 16682 17665 17667 16684 16685 17685 16685 16686 18511 18511 17685 16685 16686 17667 18509 16686 18509 18511 17681 16689 16687 16687 17680 17681 16687 16692 17680 16693 16692 16687 16708 16693 16687 16687 16688 16708 16689 16688 16687 17692 16708 16688 16688 17689 17692 16688 16689 17689 16689 17681 17688 18516 17689 16689 16689 17688 18516 19298 18501 16690 16690 17686 19298 16690 16691 17686 16692 17677 17680 16696 16695 16694 16710 16696 16694 16695 16696 17663 16696 16711 17663 16696 16710 16711 16697 16698 16705 16699 16698 16697 16712 16699 16697 16697 16703 16712 16705 16703 16697 16717 16705 16698 16718 16717 16698 16698 16713 16718 16698 16699 16713 16711 16710 16699 16712 16711 16699 19313 18513 16700 16700 17690 19313 16700 17684 17690 16700 17683 17684 16700 16701 17683 16702 16701 16700 18513 16702 16700 16701 17682 17683 16701 16702 17682 19309 17682 16702 19316 19309 16702 19319 19316 16702 16702 18513 19319 17672 16712 16703 17674 17672 16703 17675 17674 16703 16703 16704 17675 16705 16704 16703 17683 17682 16704 17684 17683 16704 16704 16705 17684 17682 17675 16704 16705 16717 17684 17692 16709 16708 16709 17695 17698 16709 17692 17695 16711 16712 17663 17672 17663 16712 16713 16714 16718 16716 16714 16713 16714 16715 16724 16716 16715 16714 16719 16718 16714 17697 16719 16714 16714 16723 17697 16724 16723 16714 16715 16716 16733 16733 16724 16715 16717 16719 17684 16717 16718 16719 17693 17690 16719 17697 17693 16719 17690 17684 16719 16723 17693 17697 17694 17693 16723 16723 16724 17694 16724 16733 17694 17701 16731 16727 17707 16735 16731 16731 17703 17707 16731 17701 17703 16732 17693 17694 19320 17693 16732 19331 19320 16732 16732 17705 19331 17707 16737 16735 16736 17711 17713 16736 17710 17711 16736 16740 17710 17707 16739 16737 16744 16741 16738 16747 16744 16738 17708 16747 16738 16738 16739 17708 16739 17706 17708 17707 17706 16739 16740 16746 17710 16740 16742 16746 16743 16744 16747 17714 17710 16746 16746 16748 17714 16747 17708 18537 18543 16749 16747 16747 18537 18543 17724 16759 16749 18543 17724 16749 16750 16761 16772 16750 16760 16761 16750 16751 16760 16752 16751 16750 16772 16752 16750 16771 16760 16751 16777 16771 16751 16778 16777 16751 18547 16778 16751 16751 16752 18547 16752 17727 18547 16752 16772 17727 16757 16756 16753 16755 16754 16753 16756 16755 16753 16773 16761 16754 16754 16755 16773 18535 16773 16755 19356 18535 16755 16755 17717 19356 16755 17716 17717 16755 16758 17716 16755 16756 16758 16756 16757 16774 17718 16758 16756 16756 16774 17718 17722 17716 16758 16758 17718 17722 17724 16769 16759 16773 16772 16761 16763 16762 16761 16764 16765 16767 16766 16765 16764 17723 16766 16764 17728 17723 16764 16768 16767 16765 16765 16766 16775 16766 16774 16775 17718 16774 16766 17722 17718 16766 16766 17721 17722 17723 17721 16766 16769 17724 17725 16770 16771 16777 16772 17726 17727 16772 16773 17726 18535 17726 16773 17731 16785 16776 17732 17731 16776 17733 17732 16776 16776 17725 17733 17737 16779 16778 18547 17737 16778 17734 16786 16779 17737 17734 16779 16780 16781 17730 16781 16794 17730 16784 16783 16782 17739 16784 16782 16782 16785 17739 16783 16784 16789 16790 16789 16784 16791 16790 16784 17739 16791 16784 16785 17731 17739 17738 16787 16786 16786 17734 17738 17738 16788 16787 18560 17735 16790 16790 16791 18560 16791 17739 18564 19372 18560 16791 16791 18564 19372 16796 16793 16792 20234 20231 16797 16797 18571 20234 16797 17741 18571 16798 17742 17747 16802 16801 16800 17744 16802 16800 17744 16804 16802 17754 16808 16803 16803 16804 17754 16804 17745 17754 16804 17744 17745 16805 16806 17757 17757 16824 16805 16813 16811 16808 17751 16813 16808 17754 17751 16808 16841 16840 16809 16809 16834 16841 18572 17741 16810 18578 18572 16810 18579 18578 16810 16810 16829 18579 18577 16814 16811 16811 16812 18577 16813 16812 16811 16812 18576 18577 16812 17756 18576 16812 16813 17756 19390 17756 16813 16813 17751 19390 16814 17758 17759 18577 17758 16814 16815 16821 16823 16815 16816 16821 16825 16824 16818 16818 16819 16825 16820 16819 16818 17757 16820 16818 16818 16824 17757 18586 16825 16819 16819 17775 18586 16819 17770 17775 16819 16820 17770 16820 16835 17770 17757 16835 16820 16830 16823 16821 16821 16822 16830 17759 16830 16822 16823 16830 17759 16843 16831 16823 17766 16843 16823 16823 17759 17766 16824 16826 16828 16827 16826 16824 16824 16825 16827 17772 16827 16825 18586 17772 16825 16826 16827 16836 17772 16836 16827 16829 17774 18588 18588 18579 16829 16843 16833 16831 17777 16858 16832 16832 17767 17777 16832 16833 17767 16833 16843 17767 17792 17784 16834 16834 16863 17792 16834 16862 16863 17784 16841 16834 17771 17770 16835 16835 16840 17771 17773 16837 16836 16836 17772 17773 16839 16838 16837 16842 16839 16837 17780 16842 16837 16837 17773 17780 16839 16842 16844 17779 17771 16840 16840 16841 17779 17785 17779 16841 16841 17784 17785 16845 16844 16842 17780 16845 16842 17768 17767 16843 16843 17763 17768 17765 17763 16843 17766 17765 16843 16859 16846 16844 16844 16845 16859 17780 16859 16845 16860 16847 16846 16868 16860 16846 17793 16868 16846 16846 16859 17793 16850 16851 16852 16853 16852 16851 16855 16853 16851 16852 16853 17787 17795 17787 16853 16853 16855 17795 16856 16855 16854 16857 16856 16854 17796 17795 16855 17798 17796 16855 16855 16856 17798 16856 16857 17798 17799 17798 16857 16857 17789 17799 17790 17789 16857 16857 16858 17790 17791 17790 16858 16858 17777 17791 16859 17780 17793 16860 16871 16872 16860 16868 16871 17788 16869 16861 16861 17787 17788 16864 16863 16862 16865 16864 16862 16870 16865 16862 16875 16870 16862 16863 16864 17792 16864 17785 17792 16864 16866 17785 16864 16865 16866 16867 16866 16865 16870 16867 16865 17802 17785 16866 17810 17802 16866 16866 16867 17810 17819 17810 16867 16867 16877 17819 16867 16870 16877 16888 16871 16868 17813 16888 16868 16868 17793 17813 16869 18603 18607 16869 17788 18603 18607 17818 16869 16870 16875 16877 16879 16872 16871 16888 16879 16871 16879 16873 16872 16889 16874 16873 16873 16886 16889 16887 16886 16873 16888 16887 16873 16873 16879 16888 16875 16876 16877 16880 16876 16875 16878 16877 16876 16880 16878 16876 16877 17810 17819 19413 17810 16877 16877 17823 19413 18631 17823 16877 16877 17824 18631 16877 16878 17824 16878 16890 17824 16881 16908 17829 16921 16908 16881 19458 16921 16881 20290 19458 16881 16881 19449 20290 16881 16882 19449 16883 16882 16881 17829 16883 16881 16882 18619 19449 18620 18619 16882 16882 16883 18620 16896 16895 16883 17829 16896 16883 19441 18620 16883 16883 17818 19441 16884 16885 16891 16886 16885 16884 16889 16886 16884 16885 17825 17826 16885 16886 17825 16905 16891 16885 17826 16905 16885 16886 16887 17825 16887 19424 19435 16887 17814 19424 16887 16888 17814 18629 17825 16887 19435 18629 16887 16888 17813 17814 16890 16897 17824 16894 16893 16892 18622 16894 16892 16892 16937 18622 17827 17820 16893 16893 16894 17827 18623 17827 16894 16894 18622 18623 17829 16908 16896 16897 16900 17824 16897 16899 16900 16909 16899 16897 16900 16899 16898 17836 16900 16898 16898 16913 17836 16898 16912 16913 16898 16909 16912 16898 16899 16909 17836 17833 16900 17834 17824 16900 16900 17833 17834 16901 16902 16917 16903 16902 16901 18635 16903 16901 16901 17837 18635 17843 16923 16902 18636 17843 16902 19466 18636 16902 16902 19460 19466 16902 16903 19460 16902 16916 16917 16923 16916 16902 16903 18635 19460 16904 17826 17830 16904 16905 17826 16906 16907 16911 16918 16910 16906 16920 16918 16906 16906 16911 16920 16907 16908 17832 17832 16911 16907 16908 16922 18630 16908 16921 16922 18630 17832 16908 16910 16918 16919 17832 16920 16911 16914 16913 16912 16913 16929 17836 16913 16914 16929 16914 16927 16929 16928 16927 16914 16914 16926 16928 16915 16916 16923 17838 16919 16918 16918 16920 17838 18647 18642 16919 18655 18647 16919 16919 18639 18655 16919 17838 18639 17841 17838 16920 18630 17841 16920 16920 17832 18630 17831 16922 16921 19459 17831 16921 16921 19458 19459 16922 17839 17841 17840 17839 16922 16922 17831 17840 16922 17841 18630 16924 16930 16931 16940 16928 16926 17855 16929 16927 17857 17855 16927 18652 17857 16927 16927 18648 18652 16927 16951 18648 16927 16928 16951 16928 16939 16951 16940 16939 16928 16929 17833 17836 17856 17833 16929 16929 17855 17856 16945 16931 16930 16945 16932 16931 17846 16934 16932 16932 16946 17846 16932 16945 16946 16934 16933 16932 16933 16934 16948 17846 16948 16934 19469 17847 16936 20310 19469 16936 16936 18640 20310 17847 16937 16936 16937 17847 18622 16951 16939 16938 17854 16951 16938 16938 16957 17854 16958 16952 16941 16941 16942 16958 16943 16942 16941 16952 16943 16941 17865 16958 16942 16942 16943 17865 16943 17859 17865 16943 17858 17859 16943 16944 17858 16944 17842 17858 17843 17842 16944 18637 17846 16946 16946 17844 18637 17845 17844 16946 16946 16947 17845 19471 17845 16947 19481 19471 16947 16947 18653 19481 16954 16949 16948 17846 16954 16948 17860 16961 16949 16949 16953 17860 16954 16953 16949 18649 18648 16951 16951 17854 18649 20320 17860 16953 16953 17848 20320 17849 17848 16953 20311 17849 16953 16953 19475 20311 16953 18637 19475 16953 16954 18637 16954 17846 18637 16955 18642 18646 17864 16957 16956 17866 17864 16956 17864 17854 16957 16964 16962 16958 17865 16964 16958 16959 16961 17860 17860 16960 16959 17872 16965 16960 16960 17868 17872 16960 17860 17868 16964 16963 16962 16963 17870 17871 16963 16964 17870 16964 17867 17870 16964 17859 17867 17865 17859 16964 16969 16968 16965 17872 16969 16965 16966 16971 17879 16966 16967 16971 16967 16970 16971 17880 16984 16968 16968 16969 17880 16984 16980 16968 18666 17880 16969 16969 17872 18666 17881 16971 16970 16970 17877 17881 16970 17869 17877 16971 17878 17879 18665 17878 16971 18675 18665 16971 16971 17881 18675 19505 19502 16973 19506 19505 16973 16974 16981 16982 16983 16981 16974 17885 16983 16974 16974 17883 17885 16974 16975 17883 16975 16976 17883 17884 17883 16976 16976 16978 17884 16976 16977 16978 16979 16978 16977 16978 16979 17884 16981 16983 17887 17896 17887 16983 16983 17885 17896 16984 17880 17886 17891 16993 16985 16985 16986 17891 17892 17891 16986 16986 16987 17892 16987 16988 17892 17895 17894 16988 16988 17893 17895 16988 17891 17892 18684 17891 16988 16988 17894 18684 17889 17885 16989 16989 16990 17889 17897 17889 16990 16990 16994 17897 18689 17916 16991 16991 17899 18689 17916 17906 16991 18687 17902 16993 16993 17891 18687 16994 16996 17897 16994 16995 16996 17904 16995 16994 16995 17911 17923 16995 17904 17911 17903 16996 16995 18706 17903 16995 19532 18706 16995 16995 17923 19532 17898 17897 16996 17909 17898 16996 16996 17908 17909 16996 17903 17908 17907 17901 16997 18691 17921 16999 18694 18691 16999 16999 17928 18694 16999 17000 17928 18710 17928 17000 18716 18710 17000 18719 18716 17000 17000 17060 18719 17001 17012 17930 17007 17006 17002 17929 17007 17002 17934 17011 17004 17004 17930 17934 17015 17008 17006 17006 17007 17015 17929 17015 17007 17008 17015 17016 17009 17020 17027 17010 17022 17028 17938 17032 17011 17011 17934 17938 17012 17013 17930 17014 17013 17012 17013 17935 17936 17942 17935 17013 17013 17941 17942 17943 17941 17013 17013 17014 17943 17936 17930 17013 17014 17033 17943 17017 17016 17015 17929 17017 17015 17024 17018 17016 17036 17024 17016 17016 17017 17036 18717 17036 17017 17017 17931 18717 17937 17931 17017 17017 17929 17937 17054 17025 17018 17018 17024 17054 17059 17026 17019 17019 17041 17059 18718 17027 17020 17020 17058 18718 17059 17058 17020 17020 17026 17059 17028 17022 17021 17031 17028 17021 17021 17030 17031 17021 17027 17030 17055 17054 17024 17024 17036 17055 17025 17066 17067 17025 17056 17066 17025 17054 17056 18718 17030 17027 17044 17043 17028 17028 17031 17044 18722 17031 17029 19540 18722 17029 17029 19539 19540 17029 17058 19539 18718 17058 17029 17029 17030 18718 17031 17030 17029 18722 17976 17031 17032 17938 17939 17939 17049 17032 17948 17943 17033 17033 17050 17948 17035 17944 17953 17954 17944 17035 18717 17055 17036 17037 17070 17071 17037 17038 17070 17039 17038 17037 17038 17069 17070 17038 17039 17069 17039 17057 17069 17040 17073 17074 17040 17071 17073 17076 17059 17041 17041 17042 17076 17042 17075 17076 17042 17074 17075 18733 17060 17045 17045 17959 18733 18738 17048 17046 19543 18738 17046 19544 19543 17046 19545 19544 17046 19546 19545 17046 17046 18723 19546 17046 17940 18723 17046 17047 17940 17048 17047 17046 17047 17939 17940 17047 17049 17939 18738 18735 17048 18735 17962 17048 18750 17948 17050 17050 17972 18750 17050 17051 17972 17051 17052 17972 17052 17064 17972 17065 17064 17052 17053 17078 17974 17054 17055 17056 17957 17056 17055 18717 17957 17055 17964 17066 17056 17056 17957 17964 17966 17069 17057 17057 17068 17966 17058 18744 19539 18745 18744 17058 17058 18721 18745 17058 17967 18721 17058 17059 17967 17059 17077 17967 17059 17076 17077 18732 18719 17060 18733 18732 17060 17062 17970 18749 17971 17970 17062 17062 17063 17971 18735 17971 17063 17063 17962 18735 17973 17972 17064 18752 17973 17064 18753 18752 17064 18754 18753 17064 17064 17065 18754 17065 17982 18754 17065 17974 17982 17068 17067 17066 17965 17068 17066 17066 17964 17965 17068 17965 17966 18742 17070 17069 19558 18742 17069 17069 17966 19558 17072 17071 17070 18741 17072 17070 18742 18741 17070 17071 17072 17073 20396 17073 17072 17072 18741 20396 17075 17074 17073 18743 17075 17073 20396 18743 17073 17077 17076 17075 17969 17077 17075 18743 17969 17075 17968 17967 17077 17969 17968 17077 17078 17079 17978 17975 17974 17078 17978 17975 17078 17080 17081 17983 17982 17978 17080 18759 17982 17080 19574 18759 17080 17080 18762 19574 17080 17983 18762 17081 17086 17980 17081 17980 17983 17984 17956 17082 17083 17087 17093 18756 17986 17085 18757 18756 17085 19578 18757 17085 18007 17093 17087 17087 17123 18007 20422 17123 17087 17087 19564 20422 17087 17981 19564 17089 17985 19578 17089 17091 17985 17089 17090 17091 17091 17092 17985 19577 17985 17092 17092 18768 19577 17093 17107 17108 18007 17107 17093 17986 17095 17094 17986 17096 17095 17096 17987 18000 17096 17986 17987 17097 17098 17114 17099 17098 17097 17100 17099 17097 17098 17113 17114 17989 17113 17098 17098 17099 17989 17099 17100 17989 18003 17989 17100 18004 18003 17101 18005 18004 17101 17101 17990 18005 17991 17990 17101 17102 17103 17104 17102 17104 17997 17105 17104 17103 17106 17105 17103 17104 17105 17998 18006 17997 17104 18767 18006 17104 17104 17998 18767 17105 17106 17998 17126 17124 17106 17106 17124 17998 18007 17116 17107 17999 17120 17109 17135 17133 17110 18011 17135 17110 17110 17115 18011 17110 17113 17115 17110 17111 17113 17112 17111 17110 17133 17112 17110 17114 17113 17111 17133 17132 17112 18002 17115 17113 17113 17989 18002 18769 18011 17115 19583 18769 17115 17115 18002 19583 18013 17125 17116 17116 18007 18013 18774 17128 17117 17117 18014 18774 17117 17118 18014 17119 17118 17117 17128 17119 17117 18020 18015 17118 17118 17138 18020 17118 17119 17138 18015 18014 17118 17119 17129 17138 17119 17128 17129 17999 17121 17120 18016 17130 17121 17121 17999 18016 17124 17123 17122 18767 17124 17122 19586 18767 17122 20427 19586 17122 17122 18773 20427 17122 17123 18773 17123 17124 18007 20422 18773 17123 17126 17125 17124 18767 17998 17124 18013 18007 17124 17124 17125 18013 17125 17126 17137 17127 17137 17149 18774 18008 17128 17130 18016 18019 17145 17136 17132 17132 17134 17145 17132 17133 17134 17135 17134 17133 17134 17143 18785 17134 17135 17143 17153 17145 17134 18028 17153 17134 18786 18028 17134 17134 18785 18786 17144 17143 17135 18011 17144 17135 17155 17146 17136 17136 17154 17155 17136 17153 17154 17136 17145 17153 17162 17149 17137 18025 18020 17138 17138 17150 18025 17138 17139 17150 17166 17150 17139 17139 17163 17166 17140 18793 18798 18799 18027 17140 17140 18798 18799 19602 18785 17143 19609 19602 17143 17143 19608 19609 17143 17144 19608 17144 18011 18769 17144 18769 19608 17155 17147 17146 17160 17157 17147 18029 17160 17147 17147 17156 18029 17147 17155 17156 18037 18025 17150 17150 18036 18037 17150 18035 18036 17150 17166 18035 18807 17164 17151 18808 18807 17151 18809 18808 17151 17151 18030 18809 18028 17154 17153 17156 17155 17154 17159 17156 17154 18028 17159 17154 17156 17158 18029 17159 17158 17156 19617 19615 17158 17158 19614 19617 17158 17159 19614 19615 18029 17158 20475 19614 17159 21270 20475 17159 21281 21270 17159 17159 20490 21281 17159 20474 20490 17159 18023 20474 18024 18023 17159 18786 18024 17159 17159 18028 18786 17165 17161 17160 17174 17165 17160 18034 17174 17160 17160 18029 18034 17161 17165 17173 17167 17166 17163 18807 18033 17164 17174 17173 17165 17166 17167 18035 18038 18035 17167 18040 17169 17168 17168 17171 18040 17169 18040 18042 17172 17171 17170 18044 18043 17171 17171 17172 18044 18043 18040 17171 17173 17174 17175 18046 17175 17174 18805 18046 17174 17174 18034 18805 17175 18046 18823 17176 17177 17184 17182 17178 17176 17184 17182 17176 18041 18038 17178 17178 17182 18041 17179 19664 19665 17179 17180 19664 18056 18044 17179 18828 18056 17179 19662 18828 17179 19665 19662 17179 17180 17181 19664 17181 18047 19666 17181 19663 19664 19666 19663 17181 18822 18041 17182 17182 17185 18822 17182 17184 17185 18055 18054 17183 18833 18055 17183 17183 17186 18833 17183 17184 17186 17185 17184 17183 18054 17185 17183 17185 18054 18822 18835 18833 17186 18826 18062 17187 18827 18826 17187 17187 18043 18827 17187 18042 18043 17188 18058 18830 17188 17189 18058 17189 17191 18058 17190 17197 18844 17190 17196 17197 17191 17194 18063 17191 17192 17194 18059 18058 17191 18063 18059 17191 17192 17193 17194 17194 17195 18063 18836 17197 17196 18837 18836 17196 17196 18823 18837 18845 18844 17197 18846 18845 17197 17197 18836 18846 17205 17204 17198 17198 17199 17205 17200 17199 17198 17203 17200 17198 17198 17201 17203 17206 17205 17199 18050 17206 17199 17199 17200 18050 18066 18050 17200 17200 17203 18066 17201 17202 18072 18073 17203 17201 17201 18072 18073 18845 18066 17203 17203 18073 18845 17204 17205 17218 17205 17217 17218 17205 17213 17217 17205 17207 17213 17205 17206 17207 17208 17207 17206 17210 17208 17206 18050 17210 17206 17207 17212 17213 17207 17208 17212 17208 17211 17212 17208 17210 17211 18074 18071 17209 17209 18060 18074 18061 18060 17209 17209 17210 18061 17211 17210 17209 18071 17211 17209 17210 18053 18061 18067 18053 17210 17210 18050 18067 18075 17212 17211 18076 18075 17211 17211 18071 18076 17228 17213 17212 18075 17228 17212 17228 17217 17213 18863 18856 17214 17214 17227 18863 17214 17226 17227 18859 18085 17215 18085 17216 17215 18098 17220 17216 17216 18086 18098 17216 18085 18086 17227 17226 17219 18093 17227 17219 17247 17222 17221 18878 17225 17222 17222 17247 18878 17222 17225 18089 17223 17233 18089 18860 18080 17223 17223 17224 18860 17225 17224 17223 18089 17225 17223 19709 18860 17224 20537 19709 17224 17224 19713 20537 17224 17225 19713 17225 18878 19713 18880 18863 17227 17227 18092 18880 18093 18092 17227 18099 17238 17228 17228 18078 18099 17228 18075 18078 17239 17232 17229 18091 17239 17229 17229 18081 18091 17229 17230 18081 17231 17230 17229 17230 17231 18861 18082 18081 17230 18084 18082 17230 18852 18084 17230 18861 18852 17230 17231 18080 18861 18869 17235 17234 18870 18869 17234 17234 18101 18870 18869 17236 17235 18099 18088 17238 18097 17254 17239 17239 18091 18097 18891 17242 17240 19719 18891 17240 17240 19718 19719 17240 17241 19718 19725 19718 17241 19726 19725 17241 17241 19695 19726 17241 18864 19695 17241 18098 18864 18891 17255 17242 18870 18101 17243 17243 18104 18870 17243 17244 18104 17244 18103 18104 18108 18103 17245 18888 18115 17246 17247 17250 18878 18109 17250 17248 18116 18109 17248 18117 18116 17248 18118 18117 17248 17248 17249 18118 17249 17251 18118 17250 18109 18878 17251 17273 18118 18119 17260 17252 17252 17253 18119 18126 18119 17253 17253 18125 18126 17253 18105 18125 17253 17254 18105 17254 18096 18105 18097 18096 17254 18890 17256 17255 18891 18890 17255 18890 18123 17256 18886 18108 17257 18887 18886 17257 17257 18114 18887 17257 17258 18114 18115 18114 17258 17260 18119 18120 17268 17265 17260 18120 17268 17260 17281 17280 17261 18118 17273 17262 18896 18118 17262 18909 18896 17262 17262 17263 18909 17264 17263 17262 17284 17264 17262 17262 17273 17284 17263 18137 18909 18138 18137 17263 17263 17264 18138 17264 17266 18138 17272 17266 17264 17284 17272 17264 17265 17266 17272 17267 17266 17265 17268 17267 17265 17284 17273 17265 17265 17272 17284 18151 18138 17266 17266 17267 17291 17292 17291 17267 17267 17276 17292 18120 17276 17267 17267 17268 18120 17269 17270 18124 17271 17270 17269 18123 17271 17269 17270 17282 18124 19744 17282 17270 17270 17271 19744 19749 19744 17271 17271 19748 19749 17271 18123 19748 18912 18139 17274 17274 18895 18912 17274 17275 18895 17276 17275 17274 18139 17276 17274 17275 18125 18127 18126 18125 17275 17275 18120 18126 17275 17276 18120 17275 18127 18895 18139 17292 17276 17278 17293 18129 17278 17279 17293 17294 17293 17279 17280 18131 18899 17280 17281 18131 18897 18130 17280 18899 18897 17280 18907 17283 17282 19744 18907 17282 17283 18906 18908 18907 18906 17283 17285 17286 18904 17288 17287 17285 18904 17288 17285 17286 17289 17296 17286 17296 18904 18903 18131 17287 17287 17288 18903 17288 18902 18903 17288 18134 18902 18922 18134 17288 17288 18921 18922 17288 18910 18921 17288 18905 18910 17288 18904 18905 17297 17295 17289 17289 17295 17296 18136 17307 17290 18139 17300 17292 18141 18129 17293 17293 18140 18141 17293 17301 18140 17293 17294 17301 17302 17301 17294 17309 17302 17294 17295 17297 17298 18147 17296 17295 17295 17298 18147 18905 18904 17296 17296 17321 18905 17296 17320 17321 18147 17320 17296 17298 18146 18147 17305 17304 17299 17299 17304 18149 18152 17347 17300 17300 18139 18152 17301 17317 18140 17301 17302 17317 17302 17316 17317 17302 17309 17316 18143 18142 17303 18144 18143 17303 17306 17310 17311 17312 17310 17306 18150 17315 17307 17307 18136 18150 18156 18151 17308 18157 18156 17308 17322 17311 17310 17310 17312 17322 17322 17314 17311 17324 17322 17312 17312 17313 17324 17313 17315 17324 17314 17322 17334 17342 17324 17315 18155 17342 17315 17315 18150 18155 17330 17317 17316 17316 17329 17330 18926 18140 17317 17317 18165 18926 17317 17330 18165 18161 17319 17318 18920 17321 17319 18921 18920 17319 17319 18161 18921 17320 18147 18162 18920 18905 17321 17324 17323 17322 17323 17324 17342 18172 17335 17323 17323 18166 18172 17323 18164 18166 17323 17342 18164 18168 18157 17325 17325 18167 18168 17325 17326 18167 18943 17328 17327 19789 18943 17327 17327 17346 19789 18943 17366 17328 17331 17330 17329 18169 18165 17330 17330 17331 18169 17331 17336 18169 19769 18940 17332 17332 18939 19769 17332 18932 18939 17332 17368 18932 18940 18160 17332 17349 17348 17335 18172 17349 17335 18173 18169 17336 18178 18173 17336 17336 17350 18178 17339 17338 17337 18170 17367 17338 17338 17339 18170 18933 18164 17342 17342 18155 18933 18938 18174 17343 17343 18935 18938 19793 18935 17343 19800 19793 17343 17343 17344 19800 17345 17344 17343 18174 17345 17343 19815 19800 17344 17344 18181 19815 17344 17345 18181 17345 17356 18181 18174 17356 17345 17346 18923 19789 17346 18158 18923 17346 18153 18158 17346 17347 18153 17347 18152 18153 17348 17349 17354 17355 17354 17349 18172 17355 17349 18180 18178 17350 18187 17364 17352 18950 18187 17352 18951 18950 17352 17352 17353 18951 18952 18951 17353 17353 17354 18952 17354 17355 18952 17355 18942 18952 17355 18172 18942 17356 17365 18181 18961 18183 17357 17357 18184 18961 17357 17358 18184 18186 18184 17358 17358 18176 18186 17358 17359 18176 17359 17366 18176 17360 17361 18953 17362 17361 17360 17361 17362 20619 17361 18179 18953 17361 18177 18179 19812 18177 17361 20618 19812 17361 20619 20618 17361 17362 19822 19837 17362 19837 20619 18187 17371 17364 18182 18181 17365 18183 18182 17365 18948 18176 17366 17366 18943 18948 18170 17368 17367 17368 18170 18932 18197 18194 17370 18199 18197 17370 17370 17372 18199 18187 17374 17371 17372 17376 18199 17372 17375 17376 18191 18190 17373 17373 18187 18191 17373 17374 18187 17377 17376 17375 17376 17383 18199 17376 17377 17383 17378 18200 18203 18213 17400 17379 19847 18213 17379 17379 18980 19847 18221 17385 17382 17382 17387 18221 17388 17387 17382 18207 17388 17382 18208 18199 17383 18212 18208 17383 17383 17384 18212 18218 18212 17384 18214 17389 17386 18984 18214 17386 17386 18210 18984 19864 18221 17387 19869 19864 17387 20643 19869 17387 17387 17388 20643 17388 19851 20643 17388 18207 19851 18214 17395 17389 18217 17391 17390 19861 18217 17390 17390 17415 19861 17418 17415 17390 18211 17393 17391 18216 18211 17391 18217 18216 17391 17392 17393 18193 18211 18193 17393 17394 17401 18220 19004 18222 17395 17395 18997 19004 17395 18214 18997 18224 17398 17396 17396 17402 18224 17396 17397 17402 17397 17399 17402 19875 19010 17398 17398 18225 19875 17398 18224 18225 19011 18228 17400 17400 19003 19011 17400 18213 19003 17402 17403 18227 18225 18224 17402 19017 18225 17402 19021 19017 17402 17402 18227 19021 17403 17414 18227 17403 17410 17414 19020 17407 17405 17405 17406 19020 17406 18231 19020 17406 18226 18231 18233 17408 17407 19020 18233 17407 17408 18233 19885 18227 17409 17408 18234 18227 17408 19886 18234 17408 17408 19885 19886 17414 17410 17409 18227 17414 17409 17412 19016 19019 17412 18221 19016 19019 17413 17412 19030 17420 17413 17413 19019 19030 19867 19861 17415 19877 19867 17415 17415 17416 19877 17417 17416 17415 17418 17417 17415 19878 19877 17416 19882 19878 17416 17416 19023 19882 17416 17417 19023 17417 17419 19023 17417 17418 17419 18237 18236 17419 17419 18235 19023 18236 18235 17419 17432 17431 17421 17431 17422 17421 17422 18230 18231 18243 18230 17422 17422 17431 18243 17430 17429 17424 17424 17426 17430 17427 17426 17424 18238 17430 17426 19034 18238 17426 17426 17427 19034 17427 19031 19034 17428 17430 17434 17428 17429 17430 17435 17434 17430 18238 17435 17430 17453 17444 17434 17434 17435 19042 19043 19042 17435 17435 18238 19043 17436 17440 17450 18247 17440 17436 17439 17438 17437 18250 17439 17437 18244 18242 17439 18250 18244 17439 17440 17441 18265 17442 17441 17440 18248 17442 17440 17440 18247 18248 19055 18265 17441 17441 18267 19055 19909 18267 17441 19912 19909 17441 19913 19912 17441 17441 17442 19913 20685 19913 17442 17442 19893 20685 17442 18248 19893 18257 17461 17443 17444 17464 18276 18253 17448 17445 17445 17446 18253 19082 18253 17446 17446 18279 19082 17455 17454 17447 17447 17448 17455 18252 17455 17448 18253 18252 17448 18264 18251 17449 18277 18264 17449 18275 17462 17451 17451 17452 18275 17452 18261 18275 17454 18254 19923 17454 17455 18254 17455 18252 18253 17455 18253 19064 19064 19051 17455 19051 19049 17455 19049 18263 17455 18263 18254 17455 19055 18256 17458 19056 17460 17459 17459 18269 19056 19076 17463 17460 17460 19056 19076 19050 18250 17461 17461 18257 19050 19059 17466 17462 17462 18275 19059 18282 17470 17463 19083 18282 17463 17463 19076 19083 20698 18276 17464 18281 18277 17465 19079 18283 17466 17466 19059 19079 19088 18289 17467 17467 18294 19088 18295 18294 17467 17467 17468 18295 17468 17497 18295 19089 17471 17469 17469 19083 19089 17469 18282 19083 17469 17470 18282 17477 17476 17471 18298 17477 17471 19089 18298 17471 17472 18290 18291 17472 17485 18290 17475 17474 17473 19096 17475 17473 17473 17478 19096 19098 17480 17475 19932 19098 17475 17475 19095 19932 19096 19095 17475 17476 17477 17484 17507 17484 17477 18302 17507 17477 19102 18302 17477 17477 18298 19102 17478 18284 19096 18300 17489 17479 19111 18300 17479 17479 19105 19111 17479 19103 19105 17479 17480 19103 17480 19098 19103 19082 18279 17481 17481 19063 19082 19933 19063 17481 17481 18313 19933 17482 18280 18293 17483 17484 17507 17486 17491 17499 17490 17487 17486 19121 17490 17486 17486 17499 19121 19929 19104 17487 19931 19929 17487 17487 17490 19931 17503 17492 17488 18303 17503 17488 17488 17489 18303 17489 18300 18303 17490 19108 19931 19121 19108 17490 17493 17494 18304 17494 17504 18304 18315 17510 17495 19123 18315 17495 17495 17496 19123 17496 18301 19123 19113 18295 17497 17498 18296 18305 19102 18296 17498 17498 18302 19102 17498 17507 18302 17499 18307 19121 17499 18306 18307 17499 17500 18306 17500 17501 18306 18308 18306 17501 18319 18312 17502 18320 18319 17502 17502 17503 18320 18312 17508 17502 17503 18303 18320 17504 17505 18304 17505 17509 18304 18323 18304 17509 17528 17519 17511 18329 17528 17511 17512 17519 18334 17513 19952 19955 19954 19952 17513 19961 19954 17513 17513 19130 19961 17513 17514 19130 17515 17514 17513 19955 17515 17513 17514 17515 19130 17515 18326 18328 18327 18326 17515 19955 18327 17515 18328 17516 17515 17518 17517 17516 18328 17518 17516 17517 17518 17531 17532 17531 17518 17518 17526 17532 17518 17524 17526 17519 17528 18334 17520 19142 19966 17520 19136 19142 19958 19957 17520 19966 19958 17520 19971 19969 17523 17523 18332 19971 20766 19973 17523 17523 19969 20766 19982 17526 17524 17524 18333 19982 17525 18342 19136 19982 17532 17526 19138 18335 17527 17527 19134 19138 19135 19134 17527 17527 17528 19135 17528 18329 19135 19129 18334 17528 19137 19129 17528 18339 17530 17529 17529 17531 18339 17530 18340 18343 17530 18339 18340 17531 17533 18339 17531 17532 17533 17532 19982 19986 19986 17533 17532 19986 18339 17533 17534 17535 18341 17535 17536 18341 19160 18341 17536 19161 19160 17536 18345 17538 17537 18346 18345 17537 18354 18346 17537 17537 18347 18354 18352 17539 17538 17538 18345 18352 18353 17542 17539 17539 17545 18353 18352 17545 17539 17540 18347 18350 19162 18347 17540 17540 18356 19162 17541 18355 18356 19157 18355 17541 19165 17545 17543 19167 19165 17543 20010 19167 17543 17543 19997 20010 17543 17544 19997 17545 17544 17543 20005 19997 17544 17544 18352 20005 17544 17545 18352 19165 18359 17545 18359 18353 17545 19169 18361 17546 20805 19169 17546 22460 20805 17546 17546 21605 22460 17546 17547 21605 17548 17547 17546 18359 17548 17546 17547 18364 21605 20014 18364 17547 17547 20010 20014 17547 17548 20010 17548 19168 20010 17548 18360 19168 17548 18359 18360 18361 18358 17549 17559 17552 17551 17560 17559 17551 17551 17556 17560 17551 17555 17556 18371 18367 17552 17552 17559 18371 18367 18365 17552 17566 17555 17553 18373 17566 17553 17554 17564 18372 17566 17565 17555 17565 17556 17555 17568 17560 17556 17556 17565 17568 17557 17561 18376 17559 17560 18371 18382 18371 17560 18383 18382 17560 17560 17568 18383 17561 18368 18376 17571 17570 17562 17574 17571 17562 17562 17563 17574 19178 17574 17563 17563 19177 19178 18381 18372 17564 18394 17568 17565 19173 18394 17565 17565 17566 19173 17566 18373 19173 18388 17569 17567 18390 18388 17567 18394 18390 17567 17567 17568 18394 17569 17568 17567 17568 17569 18383 18388 18382 17569 17569 18382 18383 17571 17572 17576 17574 17572 17571 17572 17575 17576 18402 18401 17572 19191 18402 17572 17572 17573 19191 17574 17573 17572 19200 19191 17573 17573 18399 19200 17573 17574 18399 20026 18399 17574 17574 19178 20026 17577 17580 17581 17577 17578 17580 17578 17579 17580 18405 17580 17579 19202 18405 17579 17579 18402 19202 17579 18401 18402 17582 17581 17580 18404 17582 17580 18409 18404 17580 17580 18405 18409 17581 17582 17583 18404 17583 17582 17589 17584 17583 17591 17589 17583 17583 17590 17591 18404 17590 17583 17585 17588 17594 17585 17587 17588 17585 17586 17587 17591 17587 17586 17586 17589 17591 19233 17588 17587 17587 17591 19233 18437 17594 17588 19236 18437 17588 17588 19233 19236 18410 17591 17590 17590 18408 18410 17590 18404 18408 17591 18414 19233 18415 18414 17591 20046 18415 17591 17591 18410 20046 18421 17600 17592 17592 17593 18421 18422 18421 17593 17593 17594 18422 17594 17607 18422 18437 17607 17594 18423 17597 17595 17595 18420 18423 17596 18411 18424 18412 18411 17596 18419 18412 17596 17596 18418 18419 18424 18420 17596 19238 18428 17597 17597 18423 19238 17598 17605 18426 17598 17599 17605 18426 18425 17598 18421 17604 17600 19227 18418 17601 17601 19226 19227 17601 18417 19226 17601 18416 18417 20067 20053 17602 17602 19245 20067 20072 19245 17602 17602 17603 20072 17603 19239 20072 17603 18426 19239 17603 18425 18426 18421 17607 17604 17607 17606 17604 18437 18431 17606 17606 17607 18437 17607 18421 18422 17608 17619 18439 17608 17609 17619 17609 17614 17619 18431 17612 17610 17611 18445 18450 18446 18445 17611 19238 18446 17611 17611 18428 19238 17612 18431 18443 18449 17625 17613 17613 17623 18449 17624 17623 17613 17613 17622 17624 18438 17619 17614 18450 18444 17615 18441 18429 17616 17617 17626 18452 19254 18442 17617 17617 18452 19254 18440 18439 17619 20079 18440 17619 17619 18438 20079 17620 19241 19243 17620 19240 19241 17627 17622 17621 17628 17627 17621 18454 17628 17621 18466 17624 17622 17622 17627 18466 18455 18449 17623 18456 18455 17623 17623 17624 18456 19260 18456 17624 17624 18466 19260 18449 18448 17625 18453 18452 17626 19266 18466 17627 17627 17628 19266 20110 19266 17628 17628 20099 20110 17628 18454 20099 17629 17634 17635 17629 17630 17634 18458 17634 17630 18467 18458 17630 19263 18467 17630 19264 19263 17630 17630 18459 19264 18460 18459 17630 18462 18460 17630 17630 18461 18462 17630 17636 18461 17631 17637 17638 18461 17637 17631 17631 17638 17640 17632 17633 17648 18475 17648 17633 20109 18475 17633 17633 19262 20109 17633 19261 19262 17633 18457 19261 17636 17637 18461 17638 17637 17636 17639 17638 17636 17638 17639 17640 17643 17642 17641 18465 17643 17641 19257 18465 17641 20091 19257 17641 17641 19258 20091 17641 17642 19258 17642 18463 19258 19259 18469 17643 17643 18470 19259 18471 18470 17643 17643 18464 18471 18465 18464 17643 17644 17645 17649 18468 17649 17645 19281 18468 17645 17645 18478 19281 18474 18472 17646 19265 18474 17646 17646 19259 19265 17646 18469 19259 17653 17651 17647 17647 17648 17653 17648 17652 17653 18476 17652 17648 17648 18475 18476 18468 18463 17649 18495 18478 17650 17650 17669 18495 19294 18481 17651 17651 18480 19294 17651 18479 18480 17651 17652 18479 17653 17652 17651 17652 18477 18479 17652 18476 18477 17654 18481 19294 19297 18482 17654 17654 19295 19297 17654 19294 19295 17655 17656 17664 17666 17664 17656 18499 17666 17656 17656 18482 18499 18510 18504 17657 17657 17691 18510 17657 17676 17691 17657 17658 17676 17659 17658 17657 18504 17659 17657 17658 17662 17676 17658 17661 17662 17658 17659 17661 17668 17661 17659 18492 17668 17659 18493 18492 17659 18504 18493 17659 17660 18492 19305 17660 17668 18492 17660 17661 17668 17662 17661 17660 17678 17662 17660 19310 17678 17660 17660 19305 19310 17662 17678 17679 17677 17676 17662 17680 17677 17662 17662 17679 17680 17663 17670 17671 17672 17670 17663 17666 17665 17664 18509 17667 17665 17665 17666 18509 17666 18508 18509 17666 18499 18508 17669 18494 18495 17669 17671 18494 18494 17671 17670 17670 17673 18494 17670 17672 17673 17674 17673 17672 18497 18494 17673 18507 18497 17673 17673 18505 18507 17673 17675 18505 17673 17674 17675 17675 17682 18505 17676 17677 17687 17681 17679 17678 17688 17681 17678 19310 17688 17678 17681 17680 17679 19300 18506 17682 19309 19300 17682 18506 18505 17682 18512 17686 17685 17685 18511 18512 17686 18512 19298 19314 18516 17688 17688 19310 19314 18516 17692 17689 17690 17693 19313 18514 18510 17691 17696 17695 17692 18516 17696 17692 19332 19313 17693 17693 19320 19332 17699 17698 17695 18517 17699 17695 17695 17696 18517 19334 18517 17696 20162 19334 17696 17696 19318 20162 17696 18516 19318 17702 17701 17698 17698 17699 17702 18517 17702 17699 17701 17702 17703 17704 17703 17702 18526 17704 17702 17702 18517 18526 17703 17706 17707 17703 17704 17706 18518 17706 17704 18527 18518 17704 17704 18526 18527 17705 18524 19331 17709 17708 17706 18518 17709 17706 17708 17709 18529 17708 18529 18537 19340 18530 17709 17709 18518 19340 18530 18529 17709 17712 17711 17710 17714 17712 17710 18525 17713 17711 17711 18523 18525 18528 18523 17711 17711 17712 18528 17712 18520 18528 18531 18520 17712 17712 17720 18531 17712 17714 17720 17714 17715 17720 18538 17720 17715 17715 17719 18538 18536 17717 17716 17716 17722 18536 17717 19345 19356 19346 19345 17717 19357 19346 17717 17717 18536 19357 18539 18538 17719 19364 18539 17719 19385 19364 17719 17719 19384 19385 18538 18531 17720 18536 17722 17721 19357 18536 17721 17721 19347 19357 19348 19347 17721 19358 19348 17721 17721 17723 19358 17723 17728 19358 18554 17725 17724 17724 18543 18554 19371 17733 17725 17725 18558 19371 17725 18554 18558 18542 17727 17726 17726 18540 18542 18541 18540 17726 17726 18535 18541 18548 18547 17727 19355 18548 17727 17727 18542 19355 17728 19353 19358 17729 17730 18552 18557 18552 17730 17730 18553 18557 17730 17740 18553 18564 17739 17731 19372 18564 17731 17731 19371 19372 17731 17732 19371 17732 17733 19371 17734 17737 17738 19369 17740 17735 17735 18560 19369 17738 17737 17736 20226 17738 17736 20982 20226 17736 17736 20981 20982 21003 20981 17736 17736 18562 21003 17736 17737 18562 18563 18562 17737 17737 18561 18563 17737 18555 18561 17737 18547 18555 20226 17743 17738 18559 18553 17740 19368 18559 17740 19369 19368 17740 17741 18566 18571 18575 18566 17741 17741 18572 18575 17742 17743 17747 17743 17746 17747 17749 17746 17743 18570 17749 17743 17743 18569 18570 20226 18569 17743 17747 17745 17744 17755 17754 17745 18565 17755 17745 17745 17746 18565 17747 17746 17745 17746 17750 18565 17746 17749 17750 21015 19387 17748 17748 20235 21015 17748 17749 20235 17750 17749 17748 19387 17750 17748 17749 18569 20235 18570 18569 17749 20222 19382 17750 20232 20222 17750 17750 19386 20232 19387 19386 17750 19376 18565 17750 19382 19376 17750 17753 17752 17751 17755 17753 17751 17751 17754 17755 17751 19388 19390 17751 17752 19388 17752 17753 19377 19389 19388 17752 20236 19389 17752 17752 19378 20236 17752 19377 19378 17753 18565 19377 17753 17755 18565 17756 19390 20239 20243 18576 17756 17756 20239 20243 17760 17759 17758 18580 17760 17758 17758 18577 18580 17759 17762 17766 17759 17761 17762 17759 17760 17761 19393 17761 17760 17760 19391 19393 17760 18580 19391 19396 18582 17761 17761 19393 19396 18582 17762 17761 18583 17766 17762 17762 18581 18583 18582 18581 17762 17769 17768 17763 17763 17764 17769 17765 17764 17763 18584 17769 17764 17764 17765 18584 17765 18583 18584 17765 17766 18583 17778 17777 17767 17767 17768 17778 18590 17778 17768 17768 18585 18590 17768 17769 18585 17769 18584 18585 17786 17775 17770 17770 17771 17786 17771 17779 17786 18586 17773 17772 18595 17780 17773 19399 18595 17773 17773 18586 19399 17774 18587 18588 17774 17776 18587 19399 18586 17775 17775 17786 19399 17776 17781 18587 18599 17781 17776 19404 17791 17777 17777 17778 19404 17778 19400 19404 17778 18590 19400 17779 17785 17786 19405 17793 17780 17780 18594 19405 18595 18594 17780 17781 17782 18587 17783 17782 17781 20250 17783 17781 17781 19406 20250 17781 18599 19406 17782 18574 18587 17782 17783 18574 19397 18574 17783 19403 19397 17783 20250 19403 17783 17792 17785 17784 17804 17786 17785 17785 17803 17804 17785 17802 17803 17786 18591 19399 18593 18591 17786 17786 17804 18593 17794 17788 17787 17795 17794 17787 17788 17794 18603 17800 17799 17789 18606 17800 17789 17789 17801 18606 17789 17790 17801 17790 17791 17801 19404 17801 17791 17814 17813 17793 19408 17814 17793 17793 19405 19408 18605 18603 17794 17794 18604 18605 17794 17795 18604 17795 17796 18604 18610 18604 17796 17796 17809 18610 17796 17797 17809 17798 17797 17796 17797 17799 17809 17797 17798 17799 17812 17809 17799 17799 17800 17812 18611 17812 17800 18614 18611 17800 17800 18606 18614 18615 18606 17801 19409 18615 17801 17801 19404 19409 17810 17803 17802 18597 17804 17803 19413 18597 17803 17803 17810 19413 20257 18593 17804 17804 18597 20257 17807 17806 17805 17811 17807 17805 18600 18598 17806 17806 17808 18600 17806 17807 17808 18601 17808 17807 18602 18601 17807 17807 17811 18602 17808 18599 18600 19407 18599 17808 17808 18601 19407 17809 17812 18610 18617 18602 17811 17811 17815 18617 18611 18610 17812 19425 19424 17814 19426 19425 17814 17814 19408 19426 17815 18616 18617 17815 17816 18616 17817 17816 17815 19439 18616 17816 17816 17817 19439 17817 18624 19439 17817 17828 18624 17817 17820 17828 17818 19432 19441 17818 18607 19432 17820 17827 17828 21044 18597 17821 17821 17822 21044 17823 17822 17821 19413 17823 17821 17821 18597 19413 17822 17823 21048 21050 21044 17822 22752 21050 17822 17822 21048 22752 17823 18631 21049 21049 21048 17823 18632 18631 17824 17824 17834 18632 18629 17826 17825 18628 17830 17826 18629 18628 17826 18624 17828 17827 18625 18624 17827 19447 18625 17827 17827 18623 19447 18627 17837 17830 18628 18627 17830 19459 17840 17831 17835 17834 17833 18643 17835 17833 17833 17856 18643 18633 18632 17834 17834 17835 18633 18634 18633 17835 19470 18634 17835 17835 18643 19470 17837 18626 18635 18627 18626 17837 17838 17841 18639 19465 19463 17839 17839 17840 19465 19463 17841 17839 17840 19459 19465 20316 18639 17841 17841 19463 20316 19480 17858 17842 17842 19479 19480 17842 17843 19479 17843 18636 19479 18638 18637 17844 17844 17845 18638 19471 18638 17845 19468 18622 17847 19469 19468 17847 17848 17849 21088 20326 20320 17848 21088 20326 17848 17849 20311 20312 17849 20312 21088 18645 18641 17850 17850 17861 18645 17851 19500 19501 17851 18660 19500 17851 17866 18660 17851 17864 17866 17851 17854 17864 18658 17854 17851 17851 17852 18658 17853 17852 17851 19501 17853 17851 17852 18649 18658 18651 18649 17852 19492 18651 17852 19494 19492 17852 17852 17853 19494 20336 19494 17853 20351 20336 17853 17853 20348 20351 20349 20348 17853 17853 19501 20349 18658 18649 17854 17855 19476 19477 17855 17857 19476 19477 17856 17855 18644 18643 17856 19478 18644 17856 17856 19477 19478 17857 18650 19476 18652 18650 17857 19480 17859 17858 19498 17867 17859 20324 19498 17859 17859 19480 20324 18661 17868 17860 20320 18661 17860 19489 18645 17861 19490 19489 17861 17861 17875 19490 17861 17873 17875 17877 17869 17862 18678 17877 17862 17862 18659 18678 17862 17863 18659 17863 18657 19491 19491 18659 17863 18661 17872 17868 18669 18666 17872 17872 18661 18669 17873 17874 17875 17876 17875 17874 19502 17876 17874 20343 19490 17875 17875 17876 20343 20357 20343 17876 17876 19502 20357 17882 17881 17877 19510 17882 17877 17877 18678 19510 18662 17879 17878 18663 18662 17878 18665 18663 17878 18662 18660 17879 17890 17886 17880 18685 17890 17880 17880 18667 18685 17880 18666 18667 17881 18672 18675 17881 17882 18672 18682 18672 17882 18683 18682 17882 19510 18683 17882 17883 17884 17885 17885 17888 17896 17889 17888 17885 17887 17888 17893 17896 17888 17887 17888 17889 17897 17898 17893 17888 17888 17897 17898 18686 17899 17890 17890 18685 18686 17891 18684 18687 17909 17895 17893 17893 17898 17909 17894 17910 18693 17894 17895 17910 18693 18684 17894 17895 17909 17910 19514 18689 17899 17899 18686 19514 17913 17904 17900 17900 17905 17913 21191 18671 17901 17901 21175 21191 17901 18690 21175 17901 17907 18690 18687 17918 17902 17919 17908 17903 17924 17919 17903 18706 17924 17903 17912 17911 17904 17920 17912 17904 17904 17913 17920 17914 17913 17905 18699 17914 17905 17905 17915 18699 17905 17906 17915 17916 17915 17906 17907 17921 18690 17908 17919 18688 17910 17909 17908 18688 17910 17908 17910 18692 18693 17910 18688 18692 17911 17912 17922 17911 17922 17923 17912 17920 17925 17925 17922 17912 17925 17920 17913 18709 17925 17913 17913 17914 18709 17914 17926 18709 17927 17926 17914 18699 17927 17914 17915 19516 19525 17915 17916 19516 19523 18699 17915 19524 19523 17915 20377 19524 17915 17915 19525 20377 17916 18689 19516 17917 17932 17933 18695 17932 17917 18696 18695 17917 17917 18687 18696 17917 17918 18687 17917 17933 17937 18702 18688 17919 17919 17924 18702 18691 18690 17921 18709 17923 17922 17922 17925 18709 19533 19532 17923 17923 18707 19533 18708 18707 17923 18714 18708 17923 17923 18709 18714 18706 18702 17924 18715 18709 17926 20376 18715 17926 17926 17927 20376 17927 20375 20376 17927 19527 20375 17927 18699 19527 18703 18694 17928 18711 18703 17928 17928 18710 18711 17936 17934 17930 18731 18717 17931 19535 18731 17931 17931 18704 19535 17931 17932 18704 17933 17932 17931 17937 17933 17931 17932 18701 18704 17932 18695 18701 17940 17938 17934 17934 17935 17940 17936 17935 17934 18726 17940 17935 19534 18726 17935 17935 17942 19534 17940 17939 17938 18726 18723 17940 17949 17942 17941 17941 17943 17949 17942 17949 19534 17943 17948 17949 17954 17947 17944 17944 17950 17953 17944 17945 17950 17946 17945 17944 17947 17946 17944 17952 17950 17945 18730 17952 17945 17945 18720 18730 17945 17946 18720 17946 17947 18720 17947 17954 18720 17963 17949 17948 18750 17963 17948 17949 18726 19534 17949 17963 18726 17952 17951 17950 17951 17952 17979 18730 17979 17952 18730 18720 17954 17954 17955 18730 17955 18729 18730 17955 18728 18729 18751 18728 17955 17955 17956 18751 17956 17984 18751 18740 17964 17957 19535 18740 17957 17957 18731 19535 17957 18717 18731 18734 17959 17958 17958 17960 18734 18746 18733 17959 17959 18734 18746 18748 18734 17960 17960 17961 18748 18749 18748 17961 17963 18724 18726 18725 18724 17963 19565 18725 17963 17963 17973 19565 18750 17973 17963 18739 17965 17964 18740 18739 17964 19558 17966 17965 19559 19558 17965 17965 19557 19559 17965 18739 19557 17967 17968 18721 18745 18721 17968 19551 18745 17968 17968 17969 19551 19563 19551 17969 17969 19562 19563 17969 18743 19562 19552 18749 17970 17970 19541 19552 17970 17971 19541 17971 18735 19541 17972 17973 18750 19568 19565 17973 17973 18752 19568 17974 17975 17982 17975 17978 17982 19540 17977 17976 17976 18722 19540 19539 17981 17977 19540 19539 17977 18755 17980 17979 17979 18728 18755 18729 18728 17979 18730 18729 17979 18755 17983 17980 17981 19539 19564 19572 18754 17982 17982 18761 19572 17982 18759 18761 17983 18755 18762 19547 18751 17984 17984 17988 19547 19591 19578 17985 19598 19591 17985 19599 19598 17985 17985 19588 19599 17985 19577 19588 19579 17987 17986 17986 18756 19579 18782 18000 17987 17987 18779 18782 18780 18779 17987 19579 18780 17987 19567 19547 17988 17988 18001 19567 19584 18002 17989 17989 18003 19584 17990 17993 19595 17990 17991 17993 19593 18005 17990 19595 19593 17990 17991 17992 17993 17996 17993 17992 17992 17994 17996 17993 18012 18776 17993 17996 18012 17993 18776 19595 17994 17995 17996 20420 19585 17995 17995 18771 20420 17995 17997 18771 18012 17996 17995 18770 18012 17995 19585 18770 17995 17997 18006 18771 17999 18000 18016 18782 18016 18000 18001 18765 19567 18001 18009 18765 19584 19583 18002 20439 19584 18003 18003 18004 20439 20447 20439 18004 21249 20447 18004 18004 18005 21249 18005 20448 21249 20449 20448 18005 18005 19593 20449 18772 18771 18006 19586 18772 18006 18006 18767 19586 19597 18768 18008 19603 19597 18008 18008 19596 19603 18008 18777 19596 18008 18774 18777 18766 18765 18009 18775 18766 18009 18009 18010 18775 18010 18021 18775 18012 18770 18776 18777 18774 18014 18778 18777 18014 18014 18015 18778 18015 18020 18778 18016 18782 18783 18016 18018 18019 19605 18018 18016 18016 18783 19605 19624 18797 18017 18017 18791 19624 18017 18018 18791 18019 18018 18017 18798 18793 18017 18017 18797 18798 18792 18791 18018 19607 18792 18018 18018 19605 19607 18784 18778 18020 18020 18026 18784 18020 18025 18026 18801 18775 18021 18802 18801 18021 18807 18802 18021 18021 18022 18807 18022 18033 18807 18023 20473 20474 18023 19613 20473 18023 19612 19613 18023 18024 19612 18024 18794 19612 18024 18786 18794 18037 18026 18025 18787 18784 18026 18026 18037 18787 18799 18030 18027 18804 18034 18029 19615 18804 18029 18030 18031 18809 18032 18031 18030 18800 18032 18030 18030 18799 18800 18811 18809 18031 19641 18811 18031 19646 19641 18031 18031 19640 19646 18031 18032 19640 20486 20457 18032 18032 19627 20486 18032 19626 19627 18032 18800 19626 20457 19640 18032 18034 18804 18805 18039 18036 18035 18035 18038 18039 18806 18037 18036 18810 18806 18036 18036 18039 18810 18795 18787 18037 18806 18795 18037 18041 18039 18038 18820 18810 18039 18039 18041 18820 18043 18042 18040 18822 18820 18041 18043 18056 18827 18043 18044 18056 18057 18047 18045 19629 18823 18046 19631 19629 18046 19632 19631 18046 18046 19616 19632 18046 18805 19616 18047 18048 19668 18049 18048 18047 18829 18049 18047 18047 18057 18829 19668 19666 18047 18048 19675 20506 18048 18843 19675 18048 18049 18843 20506 19668 18048 19653 18843 18049 18049 18829 19653 18813 18067 18050 18842 18813 18050 18050 18066 18842 18061 18053 18051 18068 18061 18051 18817 18068 18051 18819 18817 18051 18051 18052 18819 18053 18052 18051 18052 18814 18819 18816 18814 18052 18824 18816 18052 18052 18053 18824 18053 18812 18824 18053 18067 18812 18831 18822 18054 18054 18055 18831 18832 18831 18055 19659 18832 18055 18055 18834 19659 18055 18833 18834 18828 18827 18056 18058 18064 18830 18058 18059 18064 18065 18064 18059 18843 18065 18059 18848 18843 18059 18849 18848 18059 18059 18063 18849 18060 18069 18074 18060 18068 18069 18060 18061 18068 18062 18826 18835 18850 18849 18063 18064 18065 18830 19653 18829 18065 18065 18843 19653 18066 18840 18842 18841 18840 18066 18845 18841 18066 18813 18812 18067 18070 18069 18068 18817 18070 18068 19656 18074 18069 18069 19652 19656 18069 18070 19652 18070 18821 19644 18070 18817 18821 18070 19644 19652 20497 18076 18071 18071 18074 20497 18844 18073 18072 18073 18844 18845 18074 19670 20497 18074 19656 19670 18075 18076 18078 18076 18077 18078 19689 18077 18076 20498 19689 18076 18076 20497 20498 18079 18078 18077 19689 18079 18077 18078 18079 18099 19698 18099 18079 18079 19689 19698 18080 18860 18861 18081 18090 18091 18081 18082 18090 18082 18083 18090 18084 18083 18082 18100 18090 18083 18854 18100 18083 18855 18854 18083 18083 18084 18855 18084 18853 18855 18084 18852 18853 18085 18859 19688 18857 18086 18085 18858 18857 18085 19687 18858 18085 19688 19687 18085 18864 18098 18086 19694 18864 18086 19702 19694 18086 18086 18857 19702 19688 18859 18087 18087 18871 19688 18088 19706 19707 18088 19698 19706 18088 18099 19698 19707 18875 18088 18095 18091 18090 18100 18095 18090 18091 18095 18097 19701 18880 18092 18092 18884 19701 18092 18879 18884 18092 18093 18879 18093 18106 18879 18096 18095 18094 19711 18096 18094 18094 19710 19711 18094 18862 19710 18094 18100 18862 18094 18095 18100 18095 18096 18097 18096 20533 20552 20538 20533 18096 18096 19711 20538 20539 18105 18096 20551 20539 18096 20553 20551 18096 18096 20552 20553 19684 18862 18100 18100 19680 19684 18100 18854 19680 18104 18103 18102 18870 18104 18102 18881 18870 18102 18882 18881 18102 18883 18882 18102 18102 18873 18883 18874 18873 18102 18102 18103 18874 18885 18874 18103 18103 18108 18885 20539 19738 18105 18128 18125 18105 19739 18128 18105 18105 19738 19739 18106 18107 18111 18893 18879 18106 18106 18111 18893 18113 18111 18107 18886 18885 18108 18109 18876 18878 18877 18876 18109 18109 18116 18877 18135 18122 18110 18110 18113 18121 18110 18111 18113 18112 18111 18110 18122 18112 18110 18111 18112 18893 19724 18893 18112 19729 19724 18112 18112 18122 19729 18888 18887 18114 18114 18115 18888 19722 18877 18116 18116 18117 19722 18117 18118 19722 18118 18896 19722 18126 18120 18119 19735 19729 18122 18122 18135 19735 18123 19736 19748 18123 19728 19736 18123 18890 19728 18128 18127 18125 18127 18128 19739 19739 18895 18127 19742 18135 18129 19747 19742 18129 18129 18141 19747 18903 18899 18131 18132 18901 18902 18132 18900 18901 18132 18133 18900 18134 18133 18132 18902 18134 18132 18941 18900 18133 18133 18134 18941 18134 18922 18941 19742 19735 18135 18155 18150 18136 18906 18155 18136 18908 18906 18136 19751 18909 18137 19757 19751 18137 18137 18138 19757 19759 19757 18138 18138 18911 19759 18138 18151 18911 18912 18152 18139 19754 18141 18140 19762 19754 18140 18140 18913 19762 18914 18913 18140 18926 18914 18140 19754 19747 18141 18916 18159 18142 18142 18143 18916 18143 18144 18916 18144 18145 18916 19767 18916 18145 18145 18900 19767 18145 18898 18900 18148 18147 18146 18149 18148 18146 18147 18148 18162 18171 18162 18148 18148 18154 18171 18148 18149 18154 18163 18154 18149 18151 18156 18911 18912 18153 18152 18918 18158 18153 18153 18912 18918 18155 18917 18933 18155 18906 18917 18930 18911 18156 18156 18929 18930 18156 18157 18929 18157 18168 18929 18158 18919 18923 18158 18918 18919 18915 18170 18159 18916 18915 18159 18921 18161 18160 18922 18921 18160 18941 18922 18160 18160 18940 18941 18933 18166 18164 19774 18926 18165 18165 18937 19774 18165 18169 18937 18942 18172 18166 18947 18942 18166 18166 18933 18947 18931 18168 18167 18167 18927 18931 18928 18927 18167 18167 18175 18928 18931 18929 18168 18169 18173 18937 18170 18915 18932 18173 18936 18937 18173 18178 18936 18938 18175 18174 18938 18928 18175 19808 18186 18176 18176 18948 19808 18177 18178 18180 18946 18178 18177 19812 18946 18177 19795 18936 18178 18178 18946 19795 18181 18959 19815 18181 18182 18959 18182 18183 18959 18960 18959 18183 18961 18960 18183 19817 18961 18184 18184 18185 19817 18186 18185 18184 18185 19810 19817 18185 19809 19810 18185 18186 19809 18186 19808 19809 18966 18191 18187 18187 18950 18966 18188 18189 18962 20623 18962 18189 18189 18968 20623 18189 18198 18968 18190 18191 18195 18965 18195 18191 18966 18965 18191 18192 18205 19822 18192 18193 18205 18206 18205 18193 18216 18206 18193 18193 18211 18216 18194 18197 18198 18954 18210 18195 18965 18954 18195 18196 18962 18967 18969 18198 18197 18197 18209 18969 18197 18208 18209 18197 18199 18208 18969 18968 18198 18987 18203 18200 18200 18985 18987 18986 18985 18200 18202 18201 18200 18201 18202 18215 18975 18204 18203 18977 18975 18203 18987 18977 18203 19842 18988 18204 18204 19841 19842 18204 18978 19841 18204 18975 18978 19837 19822 18205 19838 19837 18205 18205 18206 19838 19862 19838 18206 18206 19857 19862 18206 18216 19857 18207 18983 19851 18212 18209 18208 18995 18969 18209 18209 18212 18995 18210 18963 18984 18964 18963 18210 18970 18964 18210 18210 18958 18970 18210 18954 18958 18999 18995 18212 18212 18218 18999 19012 19003 18213 18213 19002 19012 18213 18992 19002 19847 18992 18213 18214 18963 18997 18984 18963 18214 19861 19857 18216 18216 18217 19861 19001 18223 18219 18219 18222 19001 18221 19015 19016 19864 19015 18221 18222 18996 19001 19004 18996 18222 18223 19001 19005 20666 19875 18225 18225 19879 20666 18225 19017 19879 18227 18234 19021 19011 18229 18228 18229 18240 19035 18241 18240 18229 19013 18241 18229 18229 19011 19013 18232 18231 18230 18239 18232 18230 19890 18239 18230 18230 19037 19890 18230 18243 19037 19024 19020 18231 18231 18232 19024 19025 19024 18232 18232 18239 19025 18233 19884 19885 18233 19020 19884 19886 19021 18234 18235 19036 19882 18235 18246 19036 18235 18236 18246 19882 19023 18235 18236 18237 18246 18237 18242 18246 19889 19043 18238 18238 19034 19889 20679 19025 18239 18239 19890 20679 19045 19035 18240 18240 19040 19045 19041 19040 18240 18240 18241 19041 20674 19041 18241 18241 20669 20674 18241 19881 20669 18241 19022 19881 18241 19013 19022 18242 18245 18246 18242 18244 18245 18243 18251 19037 18244 18250 19047 19047 18245 18244 19892 18246 18245 18245 19047 19892 19892 19036 18246 19039 18248 18247 18248 19039 19893 19040 19038 18249 19045 19040 18249 19894 19047 18250 18250 19050 19894 19044 19037 18251 19902 19044 18251 19903 19902 18251 18251 19054 19903 18251 18264 19054 18253 19063 19064 19082 19063 18253 20720 19923 18254 18254 20701 20720 18254 19051 20701 19904 19051 18254 18254 18263 19904 18270 18269 18255 18255 18256 18270 18271 18270 18256 19066 18271 18256 18256 19055 19066 19905 19050 18257 18257 19067 19905 18257 18273 19067 18257 18272 18273 19059 18275 18258 19060 19059 18258 19907 19060 18258 18258 18259 19907 18260 18259 18258 18275 18260 18258 20709 19907 18259 18259 19915 20709 18259 19073 19915 18259 18260 19073 18260 18261 18262 18275 18261 18260 18260 19061 19073 18260 18262 19061 18263 19049 19904 18264 19053 19054 19087 19053 18264 18264 19086 19087 19088 19086 18264 18264 18277 19088 19058 18268 18266 21499 19058 18266 18266 20712 21499 20713 20712 18266 18266 19909 20713 18266 18267 19909 18268 18267 18266 19066 19055 18267 18267 18268 19066 20704 19914 18268 18268 19058 20704 18268 18271 19066 19914 18271 18268 18269 18270 18271 20704 19056 18269 18269 19914 20704 18269 18271 19914 18274 18273 18272 18278 18274 18272 18273 18274 19067 18274 18292 19067 18274 18278 18292 19921 18287 18276 18276 19920 19921 20698 19920 18276 18277 18281 19088 19078 18292 18278 19084 19078 18278 18278 18291 19084 19074 18293 18280 19075 19074 18280 19923 19075 18280 18281 18289 19088 19079 18284 18283 18284 18285 19096 18286 18285 18284 19079 18286 18284 18285 19095 19096 18285 19094 19095 18285 18286 19094 20723 19094 18286 18286 19908 20723 18286 19060 19908 19079 19060 18286 19921 19081 18287 19092 18291 18290 18290 18299 19092 19092 19084 18291 19069 19067 18292 18292 19068 19069 19078 19068 18292 20740 18301 18293 18293 20739 20740 18293 19074 20739 19100 19088 18294 19101 19100 18294 19927 19101 18294 18294 19106 19927 18294 18295 19106 20750 19106 18295 18295 19127 20750 18295 19113 19127 19118 18305 18296 19928 19118 18296 18296 18297 19928 18298 18297 18296 19102 18298 18296 20743 19928 18297 18297 19089 20743 18297 18298 19089 19093 19092 18299 19929 19093 18299 18299 19104 19929 19111 18303 18300 19124 19123 18301 19935 19124 18301 19939 19935 18301 20740 19939 18301 18322 18320 18303 19111 18322 18303 18314 18313 18304 19112 18314 18304 18304 18324 19112 18304 18323 18324 19117 19116 18305 18305 19114 19117 19115 19114 18305 19118 19115 18305 19110 18307 18306 18306 18308 19110 18307 19108 19121 18307 19107 19108 19110 19107 18307 18308 19109 19110 19940 19109 18308 18308 18309 19940 18309 19122 19952 20752 19940 18309 18309 19953 20752 18309 19952 19953 19952 19122 18310 18310 18311 19952 19955 19952 18311 18311 18327 19955 18311 18326 18327 18311 18318 18326 18312 18319 19956 19962 19131 18312 19963 19962 18312 18312 19956 19963 19934 19933 18313 18313 18314 19934 19938 19934 18314 18314 19112 19938 18315 19124 19125 18315 19123 19124 19125 18329 18315 18332 18331 18316 19960 18332 18316 18316 19959 19960 18316 18317 19959 20757 19959 18317 18317 19948 20757 18317 19120 19948 18317 19119 19120 18319 18320 19956 18322 18321 18320 18320 18321 19956 18321 18322 19105 19963 19956 18321 21558 19963 18321 18321 19949 21558 19950 19949 18321 18321 19099 19950 19105 19099 18321 19111 19105 18322 18325 18324 18323 18334 18325 18323 20759 20753 18324 18324 18325 20759 20753 19112 18324 18325 19132 20759 18325 19128 19132 18325 18334 19128 19965 19135 18329 18329 19125 19965 19127 19113 18330 19951 19127 18330 20762 19971 18332 18332 19960 20762 18333 19962 19982 18333 19131 19962 19129 19128 18334 19138 18337 18335 19141 18338 18336 18336 18337 19141 19146 19141 18337 18337 19138 19146 19142 18342 18338 19966 19142 18338 19981 19966 18338 18338 19141 19981 19143 18340 18339 19144 19143 18339 19986 19144 18339 19153 18343 18340 18340 19143 19153 19160 19145 18341 19142 19136 18342 19153 18344 18343 18344 19153 19158 19993 18352 18345 18345 18349 19993 18345 18348 18349 18345 18346 18348 19159 18348 18346 18346 18354 19159 19162 18354 18347 19156 18349 18348 18348 19149 19156 19155 19149 18348 19159 19155 18348 18349 19987 19993 18349 19156 19987 20004 19157 18351 18351 19164 20004 18351 19163 19164 18351 19158 19163 18352 19993 20005 18354 19152 19159 19162 19152 18354 19166 18356 18355 20003 19166 18355 20007 20003 18355 20008 20007 18355 18355 19157 20008 19166 19162 18356 18357 18358 20009 18358 19169 20009 18358 18361 19169 19168 18360 18359 18359 19165 19168 21605 18364 18362 23332 21605 18362 23333 23332 18362 24082 23333 18362 18362 18363 24082 18364 18363 18362 18363 22464 24082 18363 21608 22464 18363 18364 21608 18364 20804 21608 18364 20011 20804 20014 20011 18364 18367 18366 18365 18366 18370 19170 18371 18370 18366 18366 18367 18371 19171 18376 18368 18368 18374 19171 18368 18369 18374 18375 18374 18369 19176 19170 18370 18370 18392 19176 18370 18391 18392 18370 18382 18391 18370 18371 18382 19172 19171 18374 19174 19172 18374 18374 19170 19174 18374 18375 19170 19171 18377 18376 19175 18378 18377 19190 19175 18377 18377 19183 19190 18377 19171 19183 18380 18379 18378 19175 18380 18378 19182 19177 18380 19190 19182 18380 18380 19175 19190 20810 18386 18381 18381 19187 20810 18381 18387 19187 18395 18391 18382 18382 18388 18395 18384 19186 19187 18384 18385 19186 19187 18387 18384 19205 19186 18385 20810 19173 18386 18396 18395 18388 18388 18389 18396 18390 18389 18388 19189 18396 18389 20020 19189 18389 18389 20019 20020 18389 18390 20019 18390 18394 20019 18393 18392 18391 18395 18393 18391 18392 18397 19179 18392 18393 18397 19179 19176 18392 18398 18397 18393 18393 18395 18398 18394 20015 20019 18394 19173 20015 18400 18398 18395 18395 18396 18400 19193 18400 18396 20022 19193 18396 18396 19189 20022 19181 19179 18397 19184 19181 18397 19197 19184 18397 18397 19196 19197 18397 18403 19196 18397 18398 18403 18398 18400 18403 20026 19212 18399 19212 19200 18399 19193 18403 18400 18402 19201 19202 18402 19191 19201 18403 19193 19196 18409 18408 18404 19218 18409 18405 18405 18406 19218 18407 18406 18405 19204 18407 18405 18405 19203 19204 18405 19202 19203 20023 19218 18406 18406 18407 20023 21626 20023 18407 18407 19204 21626 19225 18410 18408 18408 18409 19225 18409 19223 19225 18409 19218 19223 18410 19225 20046 20075 18424 18411 18411 20071 20075 18411 18412 20071 18412 20051 20071 18412 18419 20051 20052 19224 18413 20053 20052 18413 19234 19233 18414 20063 19234 18414 18414 18415 20063 18415 20046 20864 20064 20063 18415 20857 20064 18415 20863 20857 18415 20864 20863 18415 18427 18417 18416 19230 19226 18417 18417 18427 19230 19227 18419 18418 18419 19227 20051 18424 18423 18420 20076 19238 18423 18423 18424 20076 18424 20075 20076 18426 18430 19239 19237 19230 18427 18447 18430 18429 18429 18441 18447 19242 19239 18430 18430 18447 19242 18431 18436 18443 18437 18436 18431 18432 18433 18434 18435 18434 18433 19246 18435 18433 19247 19246 18433 18433 18442 19247 18434 18435 19240 20070 19240 18435 20077 20070 18435 18435 19246 20077 20879 19256 18436 18436 20084 20879 18436 18437 20084 18437 19235 20084 19236 19235 18437 20081 20079 18438 18439 18440 19237 20048 19237 18440 18440 20047 20048 20078 20047 18440 20079 20078 18440 19242 18447 18441 19248 19247 18442 19252 19248 18442 19254 19252 18442 18444 18451 18462 18444 18450 18451 18451 18450 18445 19264 18451 18445 20083 19264 18445 18445 18446 20083 20870 20083 18446 18446 20074 20870 18446 19238 20074 20082 20081 18448 20100 20082 18448 18448 18449 20100 18449 18455 20100 18451 18460 18462 18451 18459 18460 19264 18459 18451 18452 18453 18474 20098 19254 18452 18452 20096 20098 20105 20096 18452 18452 20104 20105 18452 18473 20104 18474 18473 18452 18453 18472 18474 18455 20089 20100 18455 20088 20089 20106 20088 18455 18455 18456 20106 18456 19260 20106 18457 18458 19261 18458 18467 19261 19270 19258 18463 18463 18468 19270 21672 18471 18464 18464 18465 21672 21673 21672 18465 18465 21671 21673 18465 20884 21671 18465 19257 20884 19266 19260 18466 20090 19261 18467 20882 20090 18467 18467 20086 20882 18467 19263 20086 19271 19270 18468 19281 19271 18468 20092 19259 18470 21674 20092 18470 21675 21674 18470 18470 18471 21675 18471 21672 21675 18473 18474 19265 18473 20095 20104 18473 19265 20095 18477 18476 18475 19272 18477 18475 19274 19272 18475 20114 19274 18475 18475 20109 20114 18480 18479 18477 19272 18480 18477 18478 18498 19281 18478 18495 18498 18480 19283 19294 18480 19282 19283 18480 19275 19282 19276 19275 18480 18480 19272 19276 19296 18499 18482 19297 19296 18482 18483 18484 19298 18485 18484 18483 18500 18485 18483 19298 18500 18483 18484 18501 19298 18503 18501 18484 18484 18485 18503 18485 18488 18503 18485 18487 18488 19299 18487 18485 18485 18500 19299 18486 18487 19277 18488 18487 18486 19280 18488 18486 19287 19280 18486 20136 19287 18486 18486 20133 20136 18486 20127 20133 18486 19277 20127 19279 19277 18487 19299 19279 18487 18488 18489 18503 18490 18489 18488 19280 18490 18488 18489 18491 18502 18489 18490 18491 18489 18502 18503 18493 18491 18490 19289 18493 18490 18490 19280 19289 18504 18502 18491 18491 18493 18504 18492 18493 19288 18492 19288 19305 19289 19288 18493 18494 18496 18498 18497 18496 18494 18498 18495 18494 19293 18498 18496 18496 18507 19293 18496 18497 18507 19293 19281 18498 19296 18508 18499 18500 18512 19299 19298 18512 18500 18503 18502 18501 18502 18504 18510 19301 18507 18505 18505 18506 19301 18506 19300 19301 20129 19293 18507 20137 20129 18507 18507 19301 20137 18512 18509 18508 19302 18512 18508 18508 19296 19302 18512 18511 18509 19302 19299 18512 20149 19319 18513 18513 19313 20149 18516 19317 19318 18516 19314 19317 19334 18526 18517 19341 19340 18518 18518 18527 19341 18519 18533 19342 18534 18533 18519 18519 18520 18534 18521 18520 18519 19342 18521 18519 18520 18531 18534 18520 18521 18528 18521 18522 18528 19339 18522 18521 20186 19339 18521 18521 19342 20186 19339 19322 18522 18522 18523 18528 18524 18523 18522 19323 18524 18522 18522 19322 19323 18523 18524 18525 18524 19327 19331 18524 19325 19327 18524 19323 19325 19338 18527 18526 18526 19334 19338 20177 19341 18527 18527 19338 20177 18529 18532 18537 18529 18530 18532 18530 19340 20187 20203 18532 18530 18530 20187 20203 19343 18534 18531 18531 18539 19343 18531 18538 18539 20215 18543 18532 18532 20213 20215 18532 20212 20213 18532 20203 20212 18543 18537 18532 20190 19342 18533 20200 20190 18533 18533 18534 20200 18534 19343 20200 19344 18541 18535 19356 19344 18535 19364 19343 18539 20207 18542 18540 20955 20207 18540 18540 18541 20955 18541 20191 20955 18541 19344 20191 20214 19355 18542 18542 20207 20214 20215 18554 18543 18544 20214 20219 18544 18548 20214 18556 18548 18544 18561 18556 18544 18544 18545 18561 18546 18545 18544 20219 18546 18544 21003 18561 18545 18545 20981 21003 18545 20980 20981 20984 20980 18545 18545 18546 20984 18546 20219 20969 18546 20983 20984 18546 20969 20983 18556 18555 18547 18547 18548 18556 18548 19355 20214 18549 19349 19354 19360 19349 18549 18549 18550 19360 18551 18550 18549 18552 18551 18549 19361 19360 18550 19363 19361 18550 19367 19363 18550 18550 18551 19367 18551 18557 19367 18551 18552 18557 19367 18557 18553 18553 19363 19367 18553 19362 19363 18553 18559 19362 20213 19375 18554 20215 20213 18554 19375 18558 18554 18555 18556 18561 19375 19371 18558 19368 19362 18559 19370 19369 18560 20998 19370 18560 18560 20230 20998 18560 19372 20230 21003 18563 18561 18562 18563 21003 18565 19376 19377 21017 18571 18566 18566 18567 21017 18568 18567 18566 20237 18568 18566 18566 18573 20237 18575 18573 18566 21755 21017 18567 21757 21755 18567 18567 21022 21757 18567 20241 21022 18567 18568 20241 20237 19397 18568 18568 19397 20241 18569 20226 20235 21017 20234 18571 18572 18573 18575 18574 18573 18572 18578 18574 18572 18573 18574 20237 18574 19397 20237 18589 18587 18574 18574 18578 18589 19391 18577 18576 19392 19391 18576 20243 19392 18576 19391 18580 18577 18578 18579 18589 18579 18588 18589 19398 18590 18581 20246 19398 18581 18581 19396 20246 18581 18582 19396 18590 18583 18581 18590 18584 18583 18590 18585 18584 18589 18588 18587 20251 19400 18590 18590 19398 20251 18591 18595 19399 18591 18592 18595 18593 18592 18591 20254 18596 18592 18592 18593 20254 18596 18595 18592 20258 20254 18593 18593 20257 20258 18594 18596 19405 18594 18595 18596 20255 19405 18596 18596 20254 20255 21044 20257 18597 18600 18599 18598 19407 19406 18599 19430 19407 18601 18601 18618 19430 18601 18602 18618 18602 18617 18618 18609 18607 18603 18603 18608 18609 18603 18605 18608 18608 18605 18604 19422 18608 18604 18604 18610 19422 18615 18614 18606 18607 18609 19421 18607 19421 19432 20267 18609 18608 18608 19422 20267 20266 19421 18609 20267 20266 18609 19423 19422 18610 18610 18611 19423 18611 18612 19423 18613 18612 18611 18614 18613 18611 20282 19423 18612 18612 19434 20282 18612 18613 19434 18613 19433 19434 18613 18615 19433 18613 18614 18615 21782 19433 18615 18615 19410 21782 18615 19409 19410 19438 18621 18616 19439 19438 18616 18618 18617 18616 18621 18618 18616 18618 19429 19430 19437 19429 18618 18618 18621 19437 20290 19449 18619 18619 20275 20290 18619 20273 20275 18619 18620 20273 20274 20273 18620 18620 19432 20274 19441 19432 18620 18621 19438 19446 19446 19437 18621 19453 18623 18622 19468 19453 18622 18623 19446 19447 19451 19446 18623 19453 19451 18623 19440 19439 18624 18624 18625 19440 20287 19440 18625 20288 20287 18625 20289 20288 18625 18625 19455 20289 18625 19447 19455 19460 18635 18626 20301 19460 18626 18626 18627 20301 18627 20291 20301 18627 19457 20291 18627 18628 19457 18628 19450 19457 18628 18629 19450 18629 19443 19450 18629 19435 19443 18631 18632 21049 21066 21049 18632 18632 19456 21066 18632 18633 19456 18633 18634 19456 21079 19456 18634 18634 20308 21079 18634 19470 20308 20317 19479 18636 18636 20309 20317 18636 20304 20309 18636 19466 20304 18637 18638 19475 18638 19471 19473 20311 19475 18638 18638 19472 20311 19473 19472 18638 20316 18655 18639 18640 20307 20310 20313 20307 18640 18640 19474 20313 18640 18641 19474 18641 18645 19474 18647 18646 18642 20308 19470 18643 18643 20299 20308 21084 20299 18643 18643 18644 21084 21091 21084 18644 18644 19478 21091 19487 19474 18645 19489 19487 18645 19491 18656 18646 18646 18654 19491 18646 18647 18654 18655 18654 18647 18648 18650 18652 18651 18650 18648 18648 18649 18651 19495 19476 18650 18650 19492 19495 18650 18651 19492 19499 19481 18653 20345 19491 18654 20346 20345 18654 20347 20346 18654 18654 20323 20347 18654 20322 20323 18654 18655 20322 18655 20314 20322 20316 20314 18655 19491 18657 18656 18659 18673 18678 18674 18673 18659 20344 18674 18659 18659 20328 20344 20331 20328 18659 21113 20331 18659 18659 19497 21113 18659 19491 19497 18660 18662 19500 18677 18669 18661 20320 18677 18661 19501 19500 18662 20349 19501 18662 18662 19504 20349 18662 18663 19504 18665 18664 18663 18663 19503 19504 18663 18664 19503 18664 18665 18681 20362 19503 18664 18664 18682 20362 18664 18681 18682 18665 18675 18681 18669 18667 18666 18667 18668 21135 18669 18668 18667 20364 18685 18667 21140 20364 18667 18667 21135 21140 18668 18676 21135 18677 18676 18668 18668 18669 18677 18670 19505 19506 21162 19505 18670 18670 18671 21162 21189 21162 18671 21191 21189 18671 18682 18675 18672 18680 18678 18673 20366 18680 18673 18673 20355 20366 20356 20355 18673 18673 18674 20356 18674 20354 20356 18674 20344 20354 18682 18681 18675 18676 21124 21861 18676 18677 21124 21861 21135 18676 18677 20353 21124 18677 20320 20353 18678 18679 19510 18680 18679 18678 18679 18683 19510 19511 18683 18679 18679 19507 19511 18679 18680 19507 18680 21143 21144 18680 20365 21143 20366 20365 18680 21144 19507 18680 18682 20359 20362 18682 19512 20359 18682 19511 19512 18682 18683 19511 18693 18687 18684 19515 18686 18685 20364 19515 18685 19515 19514 18686 18687 18693 18696 18695 18692 18688 18701 18695 18688 18688 18697 18701 18698 18697 18688 18700 18698 18688 18702 18700 18688 19517 19516 18689 18689 19514 19517 18690 18691 21175 18691 18694 21175 18692 18695 18696 18696 18693 18692 18694 20367 21175 20369 20367 18694 18694 19529 20369 18694 18703 19529 18697 18698 18705 18704 18701 18697 18705 18704 18697 18698 18700 18712 18712 18705 18698 18699 19523 19527 18700 18702 18713 18713 18712 18700 18702 18706 19530 19530 18713 18702 18703 19528 19529 18703 18711 19528 18704 18705 19535 18705 18712 19535 19532 19530 18706 20387 19533 18707 18707 18708 20387 21194 20387 18708 18708 20381 21194 18708 18714 20381 18715 18714 18709 19528 18711 18710 18710 18716 19528 18712 18740 19535 20385 18740 18712 18712 18713 20385 18713 19530 20385 18714 18715 20381 18715 20376 20381 19531 19528 18716 18716 18719 19531 18719 18732 19531 18723 18726 19546 18724 18725 20412 18727 18726 18724 20403 18727 18724 20412 20403 18724 18725 19568 20411 18725 19565 19568 18725 20411 20412 18726 18727 19546 20403 19546 18727 19548 18755 18728 18728 18751 19548 20383 19531 18732 20384 20383 18732 18732 18733 20384 20394 20384 18733 18733 18746 20394 18748 18746 18734 18735 18736 19541 18738 18736 18735 18736 19537 19541 18736 19536 19537 18736 18737 19536 18738 18737 18736 19542 19536 18737 20389 19542 18737 18737 19555 20389 18737 19543 19555 18737 18738 19543 18739 19549 19557 18739 18740 19549 20385 19549 18740 20417 20396 18741 21215 20417 18741 18741 18742 21215 20406 19561 18742 18742 19558 20406 18742 21214 21215 18742 21206 21214 18742 19560 21206 19561 19560 18742 20396 19562 18743 20398 19539 18744 18744 20397 20398 18744 18745 20397 20408 20397 18745 18745 19550 20408 19551 19550 18745 18746 18747 20394 18748 18747 18746 18747 20392 20394 18747 18748 20392 20395 20392 18748 18748 19553 20395 18748 19552 19553 18748 18749 19552 18751 19547 19548 18752 18758 19568 18752 18753 18758 19570 18758 18753 19572 19570 18753 18753 18754 19572 19566 18762 18755 18755 19548 19566 18756 18780 19579 19590 18780 18756 18756 18757 19590 18757 19578 19590 19570 19568 18758 18759 18760 18761 19574 18760 18759 18760 19574 19581 19582 18761 18760 18760 19580 19582 19581 19580 18760 19582 19572 18761 18762 18763 19574 18764 18763 18762 19571 18764 18762 18762 19566 19571 18763 18764 21979 21227 19574 18763 21979 21227 18763 18764 19571 20413 18764 20413 21979 19575 19567 18765 19576 19575 18765 18765 18766 19576 19600 19576 18766 18766 18775 19600 19587 19577 18768 19597 19587 18768 20436 19608 18769 21240 20436 18769 18769 19583 21240 19585 18776 18770 18771 20407 20420 18771 18772 20407 20419 20407 18772 20427 20419 18772 18772 19586 20427 18773 20409 20427 20410 20409 18773 20421 20410 18773 20422 20421 18773 19601 19600 18775 18775 18801 19601 18776 19594 19595 18776 19585 19594 18777 18778 19596 18778 18784 19596 18779 18780 19592 18779 18781 18782 19592 18781 18779 18780 19590 19592 18783 18782 18781 19604 18783 18781 20453 19604 18781 18781 20452 20453 20454 20452 18781 18781 19592 20454 19606 19605 18783 18783 19604 19606 18784 18789 19596 18790 18789 18784 18784 18788 18790 18784 18787 18788 19602 18794 18785 18794 18786 18785 18795 18788 18787 19610 18790 18788 18788 18796 19610 18788 18795 18796 19603 19596 18789 20450 19603 18789 18789 18790 20450 20451 20450 18790 18790 19610 20451 19625 19624 18791 20461 19625 18791 18791 18792 20461 18792 19611 20461 18792 19607 19611 18794 19602 19612 19623 18796 18795 18795 18806 19623 19639 19610 18796 18796 19623 19639 18797 19624 19626 18800 18798 18797 19626 18800 18797 18800 18799 18798 20445 19601 18801 20455 20445 18801 18801 18803 20455 18801 18802 18803 18808 18803 18802 18802 18807 18808 20470 20455 18803 18803 20457 20470 20458 20457 18803 18803 19628 20458 18803 18808 19628 19616 18805 18804 18804 19615 19616 18806 18825 19623 18806 18810 18825 18808 18811 19628 18808 18809 18811 18810 18820 18825 19641 19628 18811 18812 18840 19649 19651 18840 18812 18812 18813 19651 18812 18816 18824 19619 18816 18812 19634 19619 18812 19649 19634 18812 18813 18842 19651 19621 18819 18814 19622 19621 18814 18814 18815 19622 18816 18815 18814 18815 19620 19622 18815 19618 19620 19619 19618 18815 18815 18816 19619 19637 18821 18817 18817 18818 19637 18819 18818 18817 19638 19637 18818 18818 19621 19638 18818 18819 19621 19658 18825 18820 18820 19657 19658 18820 18822 19657 19645 19644 18821 18821 19637 19645 18822 18831 19657 19633 18837 18823 18823 19629 19633 20491 19623 18825 20493 20491 18825 18825 19658 20493 19674 18835 18826 20494 19674 18826 18826 19662 20494 18826 18827 19662 18827 18828 19662 18831 18832 19657 20503 19657 18832 18832 19673 20503 18832 19659 19673 19661 18834 18833 18833 18835 19661 20505 19672 18834 20515 20505 18834 20516 20515 18834 18834 20501 20516 18834 19660 20501 19661 19660 18834 19672 19659 18834 19674 19661 18835 18836 18838 18846 18836 18837 18838 18839 18838 18837 19633 18839 18837 18838 18839 19647 19648 18846 18838 18838 19647 19648 18839 19633 19647 18840 18841 19650 19651 18842 18840 19650 19649 18840 18841 18845 19669 19669 19650 18841 18843 18848 19675 18845 18846 18847 18845 18847 19669 19648 18847 18846 18847 19654 19669 18847 19649 19654 18847 19648 19649 19676 19675 18848 18848 18849 19676 18849 18850 19676 18850 18851 19676 20508 19676 18851 18851 18856 20508 19677 18853 18852 21313 19677 18852 18852 20516 21313 18852 19692 20516 18852 18861 19692 19678 18855 18853 18853 19677 19678 20511 19680 18854 18854 18855 20511 18855 19678 20511 18856 19686 20508 18856 19685 19686 18856 18863 19685 18857 18858 19702 20518 19702 18858 18858 19687 20518 19692 18861 18860 20516 19692 18860 20521 20516 18860 20522 20521 18860 20532 20522 18860 18860 19709 20532 18862 19700 19710 18862 19684 19700 18863 18880 19685 18864 19694 19695 22091 18868 18865 18865 22090 22091 18865 18866 22090 18867 18866 18865 18868 18867 18865 18866 21319 22090 18866 18867 21319 18867 18868 18871 18867 20519 21319 18867 18872 20519 18867 18869 18872 21317 18871 18868 22091 21317 18868 18881 18872 18869 18869 18870 18881 21317 19688 18871 18872 18882 20519 18872 18881 18882 19703 18883 18873 20526 19703 18873 18873 18892 20526 18873 18874 18892 18874 18885 18892 19707 18889 18875 18876 18877 19715 19713 18878 18876 19715 19713 18876 18877 19722 19723 19723 19715 18877 19717 18884 18879 18879 18893 19717 19693 19685 18880 19701 19693 18880 18882 19696 20519 18882 18883 19696 19697 19696 18883 19703 19697 18883 20529 19701 18884 20540 20529 18884 18884 19717 20540 18885 18886 18892 19712 18892 18886 18886 18887 19712 19721 19712 18887 18887 19720 19721 18887 18888 19720 19721 19720 18889 20536 19721 18889 18889 19707 20536 19730 19728 18890 18890 18894 19730 18890 18891 18894 19719 18894 18891 18892 20525 20526 18892 19712 20525 19724 19717 18893 19731 19730 18894 18894 19719 19731 19740 18912 18895 18895 19738 19740 19739 19738 18895 19732 19722 18896 19737 19732 18896 18896 18909 19737 18899 18898 18897 18901 18900 18898 18898 18899 18901 18903 18901 18899 20578 19767 18900 18900 18940 20578 18941 18940 18900 18903 18902 18901 18920 18910 18905 18906 18907 18917 19756 18917 18907 18907 19744 19756 19752 19737 18909 20565 19752 18909 18909 19751 20565 18910 18920 18921 18911 18930 19759 19745 18918 18912 19746 19745 18912 18912 19740 19746 19773 19762 18913 19774 19773 18913 18913 18926 19774 18913 18914 18926 18939 18932 18915 19768 18939 18915 18915 18916 19768 18916 19767 19768 18947 18933 18917 19770 18947 18917 18917 19763 19770 18917 19756 19763 19760 18919 18918 18918 19745 19760 18924 18923 18919 19766 18924 18919 18919 19760 19766 18923 19780 19789 18923 18925 19780 18923 18924 18925 19778 18925 18924 19779 19778 18924 18924 19766 19779 18925 18943 19780 18949 18943 18925 20597 18949 18925 20598 20597 18925 18925 19778 20598 19776 18931 18927 18927 19775 19776 18927 18928 19775 18928 18934 19775 18935 18934 18928 18938 18935 18928 18931 18930 18929 19764 19759 18930 18930 18931 19764 19777 19764 18931 18931 19776 19777 19791 19775 18934 19794 19791 18934 18934 19793 19794 18934 18935 19793 19784 18937 18936 19795 19784 18936 19784 19774 18937 19786 19769 18939 18939 19785 19786 18939 19768 19785 19786 19785 18940 18940 19769 19786 18940 19785 20578 19790 18952 18942 18942 19787 19790 18942 18947 19787 18949 18948 18943 19789 19780 18943 18944 19784 19795 20576 19784 18944 21391 20576 18944 18944 20611 21391 18944 18945 20611 18946 18945 18944 19795 18946 18944 21405 20611 18945 21406 21405 18945 21407 21406 18945 18945 18946 21407 18946 19812 21407 19788 19787 18947 18947 19770 19788 18948 18949 19808 20597 19808 18949 19799 18966 18950 18950 18951 19799 18951 18952 19799 18952 19790 19799 18954 18955 18958 18956 18955 18954 18965 18956 18954 18955 18957 18958 19813 18957 18955 19814 19813 18955 18955 18956 19814 18956 19801 19814 18956 19797 19801 18956 18966 19797 18956 18965 18966 19821 18972 18957 18957 19818 19821 18957 19805 19818 19813 19805 18957 18972 18958 18957 18972 18970 18958 19816 19815 18959 18959 18960 19816 20616 19816 18960 20617 20616 18960 18960 19817 20617 18960 18961 19817 19826 18967 18962 20623 19826 18962 19004 18997 18963 18963 18996 19004 18963 18964 18996 18964 18974 18996 18964 18970 18974 18966 19796 19797 19799 19796 18966 19827 18983 18967 18967 19826 19827 18968 19828 20623 19829 19828 18968 18968 18969 19829 19859 19829 18969 18969 18995 19859 18970 18973 18974 18970 18971 18973 18972 18971 18970 19819 18973 18971 19821 19819 18971 18971 18972 19821 20635 20625 18973 18973 19825 20635 18973 19824 19825 18973 19819 19824 20625 18974 18973 19853 18996 18974 19854 19853 18974 20625 19854 18974 18975 18976 18978 18977 18976 18975 19832 18978 18976 18976 18977 19832 19841 19832 18977 18977 18987 19841 18978 19832 19841 18981 18980 18979 19836 18981 18979 18980 18982 19847 18980 18981 18982 19848 18982 18981 18981 19836 19848 19848 19847 18982 19852 19851 18983 18983 19850 19852 18983 19827 19850 19831 18987 18985 18985 18986 19831 19860 19831 18986 18987 19830 19841 19831 19830 18987 18988 19842 19845 20629 19836 18989 21419 20629 18989 22233 21419 18989 18989 18990 22233 18991 18990 18989 19836 18991 18989 18990 18991 19855 18990 21441 22233 18990 20642 21441 18990 19846 20642 19855 19846 18990 20646 19002 18992 20647 20646 18992 18992 18993 20647 18994 18993 18992 19856 18994 18992 18992 19847 19856 22261 20647 18993 18993 18994 22261 18994 19849 20630 19856 19849 18994 18994 21447 22261 18994 20630 21447 18995 19858 19859 18995 19000 19858 18995 18999 19000 19866 19865 18996 18996 19853 19866 19865 19001 18996 19000 18999 18998 19870 19000 18998 19871 19870 18998 18998 19006 19871 18998 18999 19006 19870 19858 19000 19006 19005 19001 19865 19006 19001 19014 19012 19002 20652 19014 19002 19002 20646 20652 19012 19011 19003 20658 19871 19006 19006 20651 20658 19006 19865 20651 19876 19874 19007 19009 19008 19007 19874 19009 19007 21451 20645 19008 19008 19009 21451 21457 21451 19009 19009 19872 21457 19874 19872 19009 19010 19875 19876 19014 19013 19011 19011 19012 19014 20668 19022 19013 19013 19018 20668 19013 19014 19018 20652 19018 19014 19864 19029 19015 19029 19016 19015 19029 19028 19016 19028 19019 19016 19880 19879 19017 19017 19021 19880 21459 20668 19018 19018 20652 21459 19033 19030 19019 20677 19033 19019 20678 20677 19019 19019 20663 20678 19019 19028 20663 19020 19026 19884 19883 19026 19020 19020 19024 19883 19886 19880 19021 21464 19881 19022 19022 20668 21464 19024 19025 19883 19025 19026 19883 19027 19026 19025 21473 19027 19025 22314 21473 19025 22315 22314 19025 19025 20682 22315 20683 20682 19025 19025 20679 20683 19026 19027 19884 19885 19884 19027 19891 19885 19027 21481 19891 19027 19027 21473 21481 19028 19029 19869 19028 19869 20663 19029 19864 19869 20672 19034 19031 20673 20672 19031 19031 19032 20673 20677 20673 19032 19032 19033 20677 20672 19889 19034 20671 19882 19036 19036 19892 20671 19037 19044 19890 19893 19039 19038 20685 19893 19038 19038 20676 20685 19038 20675 20676 19038 19040 20675 19040 19041 20675 19041 20674 20675 19901 19900 19042 19042 19043 19901 20692 19901 19043 19043 20690 20692 19043 19889 20690 19898 19890 19044 19899 19898 19044 20693 19899 19044 19044 19902 20693 19046 19050 19905 19894 19050 19046 19046 19047 19894 19048 19047 19046 20691 19048 19046 20696 20691 19046 19046 19905 20696 20689 19892 19047 19047 20687 20689 19047 19048 20687 19048 20691 21490 19048 20686 20687 19048 19897 20686 21490 19897 19048 19049 19051 19904 20702 20701 19051 19051 19065 20702 19051 19064 19065 20703 20695 19052 21497 20703 19052 21498 21497 19052 19052 19087 21498 19052 19053 19087 19054 19053 19052 19903 19054 19052 20695 19903 19052 19056 19057 19077 19058 19057 19056 20704 19058 19056 19077 19076 19056 21519 19077 19057 19057 20716 21519 19057 19058 20716 21499 20716 19058 19059 19060 19079 19060 19907 19908 19080 19073 19061 19081 19080 19061 20718 20698 19062 19062 20711 20718 19065 19064 19063 19922 19065 19063 20726 19922 19063 20731 20726 19063 19063 19933 20731 19065 19922 20702 19906 19905 19067 19067 19069 19906 19068 19071 20705 19068 19070 19071 19078 19070 19068 20705 19069 19068 20705 19906 19069 19070 19078 19085 19072 19071 19070 19085 19072 19070 20706 20705 19071 19071 19072 20706 21508 20706 19072 19072 19916 21508 19072 19085 19916 20717 19915 19073 19073 19080 20717 21533 20739 19074 21534 21533 19074 21535 21534 19074 19074 19075 21535 22392 21535 19075 19075 21524 22392 19075 20720 21524 19075 19923 20720 19091 19083 19076 19076 19090 19091 20722 19090 19076 19076 20721 20722 19076 19077 20721 21519 20721 19077 19078 19084 19085 19080 19917 20717 19918 19917 19080 19080 19081 19918 20724 19918 19081 19081 19919 20724 19921 19919 19081 19091 19089 19083 19092 19085 19084 19085 19093 19916 19085 19092 19093 20728 19087 19086 19086 19924 20728 19086 19100 19924 19086 19088 19100 19087 20727 21498 20728 20727 19087 20744 20743 19089 19089 19090 20744 19091 19090 19089 19090 20729 20744 19090 20722 20729 20733 19916 19093 19093 19929 20733 19926 19095 19094 20734 19926 19094 21525 20734 19094 19094 20723 21525 19095 19926 19932 19097 19932 20735 19097 19098 19932 19099 19098 19097 19950 19099 19097 22420 19950 19097 19097 21531 22420 22405 21531 19097 19097 20735 22405 19098 19099 19103 19105 19103 19099 19925 19924 19100 20732 19925 19100 19100 19101 20732 19101 19927 20732 20732 19927 19106 21537 20732 19106 19106 20750 21537 19110 19109 19107 19941 19108 19107 19107 19940 19941 19107 19109 19940 20747 19931 19108 20748 20747 19108 20751 20748 19108 19108 19941 20751 20753 19938 19112 20756 19117 19114 21548 20756 19114 19114 21547 21548 19114 19115 21547 19115 21538 21547 19115 19928 21538 19115 19118 19928 19948 19120 19116 19116 19947 19948 19116 19117 19947 20756 19947 19117 20754 19126 19124 19124 19935 20754 19126 19125 19124 20763 19965 19125 19125 19126 20763 19126 20754 21556 21556 20763 19126 19127 19944 20750 19127 19943 19944 19951 19943 19127 19128 19129 19979 19133 19132 19128 20767 19133 19128 20770 20767 19128 19128 19979 20770 19129 19137 19979 19974 19961 19130 20760 20759 19132 21571 20760 19132 19132 21561 21571 19132 19133 21561 22429 21561 19133 19133 20767 22429 19140 19138 19134 19134 19135 19140 19980 19140 19135 19135 19965 19980 19137 19145 19979 19138 19139 19146 19140 19139 19138 19139 19141 19146 20771 19141 19139 19139 20768 20771 19139 19140 20768 19140 19980 20768 21574 19981 19141 19141 20769 21574 20771 20769 19141 19154 19153 19143 19992 19154 19143 19143 19144 19992 21586 19992 19144 19144 21581 21586 19144 21580 21581 19144 20775 21580 19144 19986 20775 19996 19979 19145 19145 19995 19996 19145 19160 19995 20778 20772 19147 19147 20773 20778 19147 19985 20773 19147 19984 19985 19147 19148 19984 19149 19148 19147 20772 19149 19147 19148 19151 19984 19148 19150 19151 19148 19149 19150 20772 19156 19149 19155 19150 19149 19152 19151 19150 19155 19152 19150 19151 19152 19994 19988 19984 19151 19994 19988 19151 19152 19162 20000 19152 19155 19159 20000 19994 19152 19989 19158 19153 19153 19154 19989 19991 19989 19154 20781 19991 19154 19154 19992 20781 19999 19987 19156 20783 19999 19156 19156 20772 20783 19157 20004 20008 19989 19163 19158 20001 19995 19160 19160 19161 20001 19162 19166 20000 19163 19989 19990 19990 19164 19163 21601 20004 19164 19164 19990 21601 19165 19167 19168 20002 20000 19166 20003 20002 19166 20010 19168 19167 20013 20009 19169 20805 20013 19169 19176 19174 19170 19171 19180 19183 19171 19172 19180 19172 19174 19176 19172 19179 19180 19172 19176 19179 20017 20015 19173 20018 20017 19173 20810 20018 19173 19182 19178 19177 20028 20026 19178 19178 19199 20028 19178 19190 19199 19178 19182 19190 19181 19180 19179 19180 19181 19183 19185 19183 19181 19181 19184 19185 19183 19185 19190 19184 19197 19208 19210 19185 19184 19221 19210 19184 19184 19220 19221 19184 19208 19220 19198 19190 19185 19210 19198 19185 19188 19187 19186 19192 19188 19186 19206 19192 19186 19186 19205 19206 19187 19188 22501 20811 20810 19187 22489 20811 19187 22501 22489 19187 22511 22501 19188 23348 22511 19188 24108 23348 19188 19188 22517 24108 19188 22516 22517 19188 19192 22516 20024 20022 19189 20812 20024 19189 20813 20812 19189 19189 20021 20813 19189 20020 20021 19190 19198 19199 19217 19201 19191 19191 19216 19217 19191 19213 19216 19191 19200 19213 22518 22516 19192 19192 20826 22518 19192 20825 20826 19192 19206 20825 19193 20022 20024 19193 19194 19196 19195 19194 19193 20025 19195 19193 19193 20024 20025 19197 19196 19194 19194 19195 19197 19208 19197 19195 20025 19208 19195 19209 19199 19198 19210 19209 19198 20038 20028 19199 19199 20037 20038 19199 20035 20037 19199 19211 20035 19199 19209 19211 19200 19212 19213 19203 19202 19201 19217 19203 19201 19217 19204 19203 19204 20820 21626 19204 20042 20820 19204 19217 20042 19207 19206 19205 19219 19207 19205 19206 19207 20825 19207 19219 20043 19207 20824 20825 19207 20043 20824 20030 19220 19208 20827 20030 19208 19208 20817 20827 19208 20025 20817 19209 19210 19211 19222 19211 19210 19210 19221 19222 19211 20032 20035 19211 19222 20032 20026 19213 19212 19213 19214 19216 19215 19214 19213 20029 19215 19213 19213 20026 20029 20816 19216 19214 20830 20816 19214 19214 20045 20830 19214 19215 20045 19215 20039 20045 19215 20029 20039 20042 19217 19216 20816 20042 19216 20027 19223 19218 19218 20023 20027 19219 19224 20043 19222 19221 19220 20030 19222 19220 20034 20032 19222 20828 20034 19222 19222 20031 20828 19222 20030 20031 20831 19225 19223 19223 20823 20831 19223 20822 20823 19223 20027 20822 20052 20043 19224 20864 20046 19225 19225 20831 20864 19229 19227 19226 19231 19229 19226 19232 19231 19226 20066 19232 19226 19226 19230 20066 19227 19228 20051 19229 19228 19227 20851 20051 19228 19228 19229 20851 21639 20851 19229 19229 19231 21639 19230 20065 20066 19230 19237 20065 19231 20852 21639 19231 20050 20852 19231 19232 20050 20848 20050 19232 19232 20065 20848 20066 20065 19232 19233 19235 19236 19233 19234 19235 20862 19235 19234 19234 20063 20862 20862 20084 19235 19237 20048 20065 20076 20074 19238 19239 19242 20072 20058 19241 19240 20059 20058 19240 20062 20059 19240 20070 20062 19240 20068 20067 19241 19241 20058 20068 20067 19243 19241 19242 19245 20072 19242 19244 19245 20067 19244 19243 20067 19245 19244 20861 20077 19246 19246 19247 20861 19247 20865 20871 19247 19248 20865 21653 20861 19247 19247 20871 21653 19248 19253 20874 19248 19252 19253 20873 20865 19248 20874 20873 19248 21682 21681 19249 22560 21682 19249 19249 19250 22560 19251 19250 19249 20881 19251 19249 21660 20881 19249 21681 21660 19249 22561 22560 19250 19250 20886 22561 19250 20885 20886 19250 19251 20885 21669 20885 19251 19251 20881 21669 19254 19253 19252 20098 20096 19253 19253 19254 20098 19253 20096 20874 20112 20099 19255 21684 20112 19255 19255 20892 21684 19255 20891 20892 19255 19256 20891 19256 20875 20891 20880 20875 19256 19256 20879 20880 21671 20884 19257 19257 20103 21671 19257 20091 20103 19258 19270 20091 20095 19265 19259 19259 20092 20095 19260 19268 20106 19260 19267 19268 19260 19266 19267 20090 19262 19261 19262 20101 20109 20102 20101 19262 19262 20090 20102 20870 20086 19263 19263 20083 20870 19263 19264 20083 20113 19267 19266 19266 20110 20113 19267 20113 20115 19269 19268 19267 20897 19269 19267 19267 20896 20897 19267 20115 20896 19268 19269 20106 19269 20088 20106 19269 20087 20088 21669 20087 19269 19269 20885 21669 21685 20885 19269 19269 20897 21685 20890 20091 19270 19270 19271 20890 19271 20128 20890 19271 19281 20128 19272 19273 19276 19274 19273 19272 19273 19274 20120 19273 19275 19276 20119 19275 19273 20120 20119 19273 19274 20114 20893 20893 20120 19274 20915 19282 19275 19275 20119 20915 19279 19278 19277 19277 19278 20127 19278 19286 20126 19278 19279 19286 19278 20126 20127 19279 19285 19286 19299 19285 19279 19280 19287 19289 19281 19293 20128 20140 19283 19282 20915 20140 19282 19295 19294 19283 20132 19295 19283 19283 20131 20132 20139 20131 19283 20140 20139 19283 19284 19285 19303 19286 19285 19284 20124 19286 19284 19284 20122 20124 19284 20121 20122 19284 19303 20121 19285 19302 19303 19285 19299 19302 19286 20125 20126 19286 20124 20125 20136 19289 19287 20135 19305 19288 19288 19289 20135 20141 20135 19289 20907 20141 19289 19289 20136 20907 19290 19305 20135 19306 19305 19290 20147 19306 19290 19290 20145 20147 19290 19291 20145 19292 19291 19290 20135 19292 19290 21707 20145 19291 19291 19292 21707 19292 20908 21707 19292 20906 20908 19292 20135 20906 20129 20128 19293 20132 19297 19295 19303 19302 19296 19304 19303 19296 19296 19297 19304 20121 19304 19297 20123 20121 19297 20132 20123 19297 20142 19301 19300 19300 19307 20142 19309 19307 19300 20138 20137 19301 20142 20138 19301 19303 19304 20121 19305 19306 19310 19311 19310 19306 19312 19311 19306 20146 19312 19306 20147 20146 19306 19307 20138 20142 20910 20138 19307 20912 20910 19307 19307 20143 20912 20144 20143 19307 19307 19308 20144 19309 19308 19307 19308 19315 20144 19308 19309 19315 19316 19315 19309 19310 19311 19314 19317 19314 19311 20921 19317 19311 19311 19312 20921 20922 20921 19312 19312 20146 20922 19313 19332 19333 19313 20148 20149 19313 19333 20148 20919 20144 19315 21717 20919 19315 19315 20935 21717 19315 19316 20935 19316 20150 20935 19316 19319 20150 20160 19318 19317 20921 20160 19317 20940 20162 19318 19318 20160 20940 19319 20148 20150 20149 20148 19319 20157 19332 19320 19320 19328 20157 19331 19328 19320 19321 20942 20951 19321 20169 20942 19321 19337 20169 19321 19322 19337 19323 19322 19321 19335 19323 19321 19336 19335 19321 20939 19336 19321 20951 20939 19321 19339 19337 19322 19323 19324 19325 19335 19324 19323 19335 19330 19324 19326 19325 19324 19330 19326 19324 19325 19326 19327 19328 19327 19326 20156 19328 19326 19326 19329 20156 19330 19329 19326 19327 19328 19331 19328 20156 20157 19329 20154 20156 20155 20154 19329 19329 20152 20155 19329 20151 20152 19329 19330 20151 20153 20151 19330 20939 20153 19330 19330 20161 20939 19330 19335 20161 20159 19333 19332 19332 20157 20159 20159 20158 19333 20934 20148 19333 19333 20933 20934 19333 20930 20933 19333 20158 20930 20166 19338 19334 20167 20166 19334 19334 20162 20167 19335 19336 20161 20939 20161 19336 19337 19339 20169 19338 20166 20177 20186 20169 19339 19340 19341 20187 20177 20165 19341 19341 20165 20187 20190 20186 19342 19343 19364 20204 20968 20200 19343 19343 20204 20968 19344 19356 20957 20192 20191 19344 20956 20192 19344 20957 20956 19344 19345 19346 20193 20958 19356 19345 19345 20193 20958 19346 19347 20195 19357 19347 19346 20195 20193 19346 19347 19348 20197 20197 20195 19347 19348 19358 20197 19349 19359 20201 19360 19359 19349 19349 19350 19354 19351 19350 19349 20201 19351 19349 19350 19353 19354 19350 19351 19353 19351 19352 19353 20963 19352 19351 20972 20963 19351 20973 20972 19351 19351 20201 20973 19358 19353 19352 20197 19358 19352 19352 20194 20197 20963 20194 19352 20958 20957 19356 19359 19360 19361 19359 19361 20201 20965 20201 19361 19361 19362 20965 19363 19362 19361 20977 20965 19362 19362 20225 20977 19362 19368 20225 19364 19365 20204 19366 19365 19364 20216 19366 19364 19364 19385 20216 19365 19366 20978 22688 20204 19365 19365 20979 22688 19365 20978 20979 19366 20216 20978 20997 20225 19368 19368 19370 20997 19368 19369 19370 21009 20997 19370 19370 20998 21009 20230 19372 19371 21002 20230 19371 19371 19373 21002 19375 19373 19371 19373 20999 21002 19373 20975 20999 19373 19374 20975 19375 19374 19373 19374 20217 20975 19374 19375 20217 19375 20213 20217 19380 19377 19376 20228 19380 19376 19376 19381 20228 19382 19381 19376 19380 19378 19377 21013 20236 19378 19378 19379 21013 19380 19379 19378 21016 21013 19379 19379 19383 21016 19379 19380 19383 20228 19383 19380 19381 20227 20228 19381 19382 20227 20222 20220 19382 19382 20223 20227 19382 20220 20223 19383 21012 21016 19383 20228 21012 21010 20978 19384 21752 21010 19384 19384 21021 21752 19384 21018 21021 19384 20231 21018 20978 19385 19384 20978 20216 19385 20233 20232 19386 21006 20233 19386 21015 21006 19386 19386 19387 21015 20239 19390 19388 19388 20238 20239 19388 19389 20238 19389 20236 20238 19395 19393 19391 19391 19392 19395 19392 19394 19395 21026 19394 19392 19392 20243 21026 20245 19396 19393 21028 20245 19393 19393 19394 21028 19395 19394 19393 22732 21028 19394 19394 22731 22732 19394 21026 22731 19396 20245 20246 20244 20241 19397 19397 19403 20244 19398 20247 20251 20248 20247 19398 19398 20246 20248 20251 19404 19400 21029 20244 19401 21764 21029 19401 19401 19402 21764 19403 19402 19401 20244 19403 19401 21783 21764 19402 19402 21031 21783 19402 20249 21031 19402 19403 20249 20250 20249 19403 20253 19409 19404 19404 20251 20253 20255 19408 19405 20256 20250 19406 19406 19420 20256 19406 19407 19420 19430 19420 19407 21036 19426 19408 19408 21035 21036 19408 20255 21035 19412 19410 19409 20253 19412 19409 19410 19411 21782 19412 19411 19410 22740 21782 19411 19411 21034 22740 19411 19412 21034 19412 21032 21034 19412 20253 21032 19414 19417 19427 19414 19415 19417 19416 19415 19414 19427 19416 19414 19418 19417 19415 20259 19418 19415 20261 20259 19415 19415 19416 20261 20264 20261 19416 19416 19428 20264 19416 19427 19428 19417 19419 20268 19417 19418 19419 19428 19427 19417 20272 19428 19417 20285 20272 19417 19417 20268 20285 19418 20260 20262 19418 20259 20260 19420 19419 19418 20262 19420 19418 19419 19420 19431 19419 19431 20268 20265 20256 19420 19420 20262 20265 19420 19430 19431 20266 19432 19421 20269 20267 19422 19422 19423 20269 20271 20269 19423 20281 20271 19423 20282 20281 19423 19424 19425 19436 19436 19435 19424 21051 19442 19425 19425 19426 21051 19442 19436 19425 19426 21046 21051 19426 21036 21046 20272 20264 19428 20292 20268 19429 19429 19437 20292 19431 19430 19429 20268 19431 19429 19432 20267 20270 19432 20266 20267 19432 20270 20274 20283 19434 19433 19433 20280 20283 21065 20280 19433 21782 21065 19433 20283 20282 19434 19435 19436 19443 19436 19442 19443 19437 19451 20292 19437 19446 19451 19447 19446 19438 19448 19447 19438 19438 19440 19448 19438 19439 19440 20286 19448 19440 20287 20286 19440 19444 19443 19442 19445 19444 19442 21059 19445 19442 19442 21052 21059 19442 21051 21052 20291 19450 19443 19443 19444 20291 20302 20291 19444 21071 20302 19444 21072 21071 19444 19444 19445 21072 19445 21059 21072 19447 19448 19455 20286 19455 19448 20291 19457 19450 19451 19454 20292 19451 19453 19454 21073 19454 19452 21080 21073 19452 19452 19468 21080 19452 19453 19468 19454 19453 19452 21068 20292 19454 21073 21068 19454 20293 20289 19455 19455 20286 20293 21079 21066 19456 21078 19459 19458 19458 20290 21078 21078 19465 19459 20304 19466 19460 19460 19467 20304 19460 19461 19467 19462 19461 19460 20301 19462 19460 21815 19467 19461 19461 19462 21815 19462 21813 21815 21814 21813 19462 19462 20302 21814 19462 20301 20302 19465 19464 19463 19463 19464 20316 21077 20295 19464 19464 19465 21077 21096 20316 19464 19464 20296 21096 19464 20295 20296 21078 21077 19465 20309 20304 19467 21101 20309 19467 21815 21101 19467 21082 21080 19468 19468 19469 21082 19469 20305 21082 20310 20305 19469 19471 19482 21085 19471 19481 19482 21085 19473 19471 20312 20311 19472 21087 20312 19472 19472 21086 21087 19472 19473 21086 19473 21085 21086 19474 19487 20313 19496 19478 19476 19476 19495 19496 19478 19477 19476 19478 19496 20340 19478 20340 21091 19488 19480 19479 20317 19488 19479 20341 20324 19480 19480 19488 20341 19481 21092 21093 19481 19499 21092 19483 19482 19481 21093 19483 19481 21837 21831 19482 19482 19483 21837 21831 21085 19482 19483 21093 21837 19484 19485 19499 19486 19485 19484 20325 19486 19484 21092 19499 19485 21098 21092 19485 19485 19488 21098 19485 19486 19488 20341 19488 19486 19486 20325 20341 20321 20313 19487 21102 20321 19487 21103 21102 19487 19487 20327 21103 19487 19489 20327 19488 20317 21098 21110 20327 19489 19489 19490 21110 19490 20342 21110 20343 20342 19490 20345 19497 19491 19492 19493 19495 19494 19493 19492 19496 19495 19493 20336 19496 19493 19493 19494 20336 19496 20339 20340 19496 20336 20339 21129 21113 19497 19497 20345 21129 19502 19505 20357 20358 19504 19503 20363 20358 19503 19503 20362 20363 20350 20349 19504 19504 20337 20350 21882 20337 19504 21891 21882 19504 19504 20358 21891 21893 20357 19505 19505 21162 21893 19507 19508 19511 19509 19508 19507 21144 19509 19507 19512 19511 19508 19513 19512 19508 19508 19509 19513 21168 19513 19509 19509 21163 21168 19509 21144 21163 21165 20359 19512 19512 19513 21165 21928 21165 19513 21930 21928 19513 19513 21927 21930 19513 21168 21927 20370 19517 19514 19514 19515 20370 20371 20370 19515 20372 20371 19515 21142 20372 19515 19515 20364 21142 19526 19525 19516 20370 19526 19516 19516 19517 20370 20375 19527 19523 20377 20375 19523 19523 19524 20377 21188 20377 19525 19525 20380 21188 21179 20380 19525 19525 21153 21179 21161 21153 19525 19525 20374 21161 19525 19526 20374 19526 20370 20374 20379 19529 19528 19528 19531 20379 20378 20369 19529 20379 20378 19529 20386 20385 19530 21960 20386 19530 19530 19532 21960 20382 20379 19531 20383 20382 19531 19532 21961 21970 19532 21203 21961 19532 21197 21203 19532 19533 21197 21967 21960 19532 21969 21967 19532 21970 21969 19532 19533 20387 21197 19538 19537 19536 19542 19538 19536 19537 19538 19552 19552 19541 19537 20393 19553 19538 19538 20388 20393 19538 19542 20388 19553 19552 19538 20398 19564 19539 20389 20388 19542 19543 19554 19555 19543 19544 19554 20399 19554 19544 19544 19545 20399 20403 20399 19545 19545 19546 20403 20405 19548 19547 19547 19567 20405 20404 19566 19548 20405 20404 19548 19559 19557 19549 20390 19559 19549 19549 20385 20390 21207 20408 19550 19550 20407 21207 19550 19551 20407 19551 19563 20407 19553 20393 21202 21202 20395 19553 19556 19555 19554 21212 19556 19554 21217 21212 19554 19554 20399 21217 20400 20389 19555 21209 20400 19555 19555 19556 21209 19556 21208 21209 21210 21208 19556 21212 21210 19556 19558 19559 20406 19559 19561 20406 20390 19561 19559 21973 21206 19560 19560 21966 21973 19560 21965 21966 19560 19561 21965 19561 20391 21965 19561 20390 20391 19585 19563 19562 20396 19585 19562 20420 20407 19563 19563 19585 20420 19564 20398 20422 20404 19571 19566 19567 19575 20405 20423 20411 19568 20426 20423 19568 19568 19569 20426 19570 19569 19568 20429 20428 19569 19569 19573 20429 19569 19570 19573 20430 20426 19569 19569 20428 20430 19570 19572 19573 20404 19575 19571 19571 19575 20413 21226 19573 19572 19572 19582 21226 21231 20429 19573 19573 21226 21231 21227 19581 19574 19575 20404 20405 19575 19576 20413 20434 20413 19576 19576 19600 20434 19577 19587 19588 19591 19590 19578 21232 19582 19580 19580 20432 21232 19580 19581 20432 20433 20432 19581 21234 20433 19581 19581 21233 21234 21236 21233 19581 19581 21227 21236 21232 21226 19582 22001 21240 19583 19583 19584 22001 19584 20437 22001 20438 20437 19584 20446 20438 19584 19584 20439 20446 20417 19594 19585 19585 20396 20417 19589 19588 19587 19597 19589 19587 20431 19599 19588 21241 20431 19588 19588 20443 21241 19588 19589 20443 19589 20441 20443 20442 20441 19589 19589 19597 20442 19598 19592 19590 19590 19591 19598 19592 20444 20454 19592 19598 20444 19593 20440 20449 19593 19595 20440 20418 19595 19594 19594 20417 20418 19595 20418 20440 19597 19603 20442 19598 19599 20444 19599 20431 20444 19600 19601 20434 20445 20434 19601 19613 19612 19602 20489 19613 19602 21259 20489 19602 19602 21250 21259 19602 20435 21250 19602 19609 20435 20450 20442 19603 20456 19606 19604 19604 20453 20456 19605 19606 19607 19611 19607 19606 20456 19611 19606 20436 19609 19608 21239 20435 19609 19609 20436 21239 21261 20451 19610 19610 19639 21261 20463 20461 19611 19611 20456 20463 19613 20471 20473 20472 20471 19613 20489 20472 19613 20475 19617 19614 19617 19616 19615 20464 19632 19616 19616 19617 20464 20475 20464 19617 20465 19620 19618 19618 19619 20465 19619 19655 20465 19619 19635 19655 19619 19634 19635 20467 19622 19620 19620 20466 20467 22034 20466 19620 19620 22033 22034 19620 20480 22033 19620 20465 20480 20468 19638 19621 19621 20460 20468 19621 20459 20460 19621 19622 20459 21260 20459 19622 19622 20467 21260 20483 19639 19623 20491 20483 19623 19627 19626 19624 20485 19627 19624 19624 19625 20485 21269 20485 19625 21280 21269 19625 19625 20461 21280 19627 20485 20486 19628 19641 20458 19636 19633 19629 19629 19630 19636 19631 19630 19629 20478 19636 19630 21272 20478 19630 22055 21272 19630 19630 19631 22055 19631 19632 22055 19632 20477 22055 19632 20476 20477 19632 20464 20476 20479 19647 19633 19633 19636 20479 19636 19635 19634 19642 19636 19634 19643 19642 19634 19649 19643 19634 20481 19655 19635 19635 20478 20481 19635 19636 20478 19636 19642 20479 19637 19638 20468 20482 19645 19637 19637 20468 20482 19639 20484 21261 19639 20483 20484 20457 19646 19640 19641 19646 20458 19642 19647 20479 19642 19643 19647 19648 19647 19643 19649 19648 19643 19644 19645 20482 21287 19652 19644 19644 20482 21287 19646 20457 20458 19649 19650 19654 19669 19654 19650 19671 19656 19652 21287 19671 19652 20480 20465 19655 20481 20480 19655 19671 19670 19656 20503 19658 19657 20500 20493 19658 19658 20499 20500 20503 20499 19658 19659 19672 19673 19660 19674 20501 19660 19661 19674 19662 19678 20494 19662 19665 19678 19665 19664 19663 19681 19665 19663 19663 19667 19681 19663 19666 19667 19679 19678 19665 19681 19679 19665 19668 19667 19666 19667 19668 20495 20507 19681 19667 19667 20495 20507 20506 20495 19668 19670 20496 20497 21295 20496 19670 19670 19671 21295 19671 21292 21295 19671 21287 21292 20502 19673 19672 20505 20502 19672 19673 20502 20503 19674 20494 20501 19675 19683 19699 20523 19683 19675 19675 19686 20523 20508 19686 19675 19675 19676 20508 19675 19699 20506 21313 20494 19677 20494 19678 19677 19678 19679 20511 19679 19680 20511 19681 19680 19679 19699 19684 19680 19680 19681 19699 20507 19699 19681 20527 20517 19682 19682 20523 20527 19682 19683 20523 19684 19683 19682 20517 19684 19682 19683 19684 19699 20517 19700 19684 19693 19686 19685 19686 19693 20523 19687 21314 22087 19687 19688 21314 22087 20518 19687 21315 21314 19688 21316 21315 19688 21317 21316 19688 19689 19690 19698 19691 19690 19689 20498 19691 19689 19690 21318 22097 19690 19691 21318 19706 19698 19690 19708 19706 19690 22097 19708 19690 19691 20498 21312 19691 21312 21318 19693 19701 20523 21327 19695 19694 19694 19702 21327 21340 19726 19695 19695 21327 21340 21320 20519 19696 19696 19697 21320 21321 21320 19697 19697 20524 21321 19697 19703 20524 20507 20506 19699 19711 19710 19700 20517 19711 19700 20531 20523 19701 19701 20528 20531 20529 20528 19701 19702 20518 21327 20526 20525 19703 19703 19704 20524 19705 19704 19703 21328 19705 19703 19703 20525 21328 19704 21307 21322 22098 21307 19704 19704 19705 22098 21322 20524 19704 19705 21329 22098 19705 21328 21329 19708 19707 19706 21330 20536 19707 19707 20534 21330 20535 20534 19707 19707 19708 20535 22097 20535 19708 20537 20532 19709 19711 20517 20538 20536 20525 19712 19712 19721 20536 19713 19715 20537 19716 19715 19714 20546 19716 19714 20549 20546 19714 19714 19715 20549 19715 19716 20537 21359 20549 19715 19715 20548 21359 19715 19723 20548 21325 20537 19716 21348 21325 19716 21349 21348 19716 19716 20546 21349 20541 20540 19717 19717 19724 20541 20558 19719 19718 19718 20542 20558 19718 19727 20542 19718 19725 19727 20558 19731 19719 20560 20548 19722 19722 19733 20560 19722 19732 19733 20548 19723 19722 20544 20541 19724 19724 19729 20544 19725 19726 19727 20545 19727 19726 21341 20545 19726 19726 21340 21341 20543 20542 19727 20545 20543 19727 20568 19736 19728 19728 19743 20568 19728 19730 19743 20547 20544 19729 19729 19735 20547 19730 19731 19743 20564 19743 19731 19731 20558 20564 19734 19733 19732 19737 19734 19732 19733 20559 20560 19733 19734 20559 19734 19737 20559 20557 20547 19735 19735 19742 20557 20572 19748 19736 19736 20568 20572 20560 20559 19737 19737 19752 20560 19738 20539 20550 19741 19740 19738 20550 19741 19738 19740 19741 19746 20561 19746 19741 19741 20550 20561 20567 20557 19742 19742 19747 20567 19743 20564 20568 19744 19750 19756 19744 19749 19750 19761 19760 19745 19783 19761 19745 19745 19753 19783 19745 19746 19753 20561 19753 19746 19747 19754 20567 19755 19749 19748 20572 19755 19748 19755 19750 19749 19763 19756 19750 20574 19763 19750 19750 20573 20574 19750 19755 20573 20569 20565 19751 20575 20569 19751 19751 19758 20575 19751 19757 19758 21371 20560 19752 19752 21358 21371 19752 20565 21358 20570 19783 19753 19753 20562 20570 19753 20561 20562 19754 19782 20567 19754 19762 19782 20579 20573 19755 19755 20572 20579 19759 19758 19757 19758 19772 20575 19758 19759 19772 19759 19765 19772 19759 19764 19765 19760 19761 19766 19779 19766 19761 20586 19779 19761 21378 20586 19761 19761 19783 21378 19762 19781 19782 19762 19773 19781 19788 19770 19763 20574 19788 19763 19777 19765 19764 19765 19771 19772 19777 19771 19765 20578 19768 19767 20578 19785 19768 20585 19772 19771 19771 19776 20585 19777 19776 19771 20582 20575 19772 20585 20582 19772 20577 19781 19773 19773 20576 20577 19773 19784 20576 19773 19774 19784 20585 19776 19775 19775 19792 20585 19775 19791 19792 22163 20598 19778 19778 19779 22163 19779 20586 22163 19781 20577 21378 19783 19782 19781 21378 19783 19781 20570 20567 19782 19782 19783 20570 19798 19790 19787 20580 19798 19787 19787 19788 20580 19788 20574 20580 19790 19798 19799 20591 19792 19791 21384 20591 19791 19791 20596 21384 19791 20595 20596 19791 19794 20595 19792 20581 20585 20591 20581 19792 20604 19794 19793 19793 19800 20604 20603 20595 19794 20604 20603 19794 19806 19797 19796 20589 19806 19796 19796 19807 20589 19796 19799 19807 19803 19801 19797 19806 19803 19797 19807 19799 19798 20580 19807 19798 20610 20604 19800 19800 19815 20610 19801 19802 19814 19803 19802 19801 19802 19813 19814 19802 19805 19813 19802 19804 19805 20592 19804 19802 19802 19803 20592 19803 20587 20592 20589 20587 19803 19803 19806 20589 20602 19805 19804 19804 20593 20602 19804 20592 20593 20608 19818 19805 20620 20608 19805 19805 20602 20620 19807 20580 20589 21399 19809 19808 22198 21399 19808 19808 20597 22198 19811 19810 19809 21399 19811 19809 20617 19817 19810 19810 19811 20617 21398 20617 19811 21399 21398 19811 19812 20618 21407 20615 20610 19815 21411 20615 19815 19815 19816 21411 19816 21403 21412 19816 20616 21403 21412 21411 19816 19818 19819 19821 19820 19819 19818 20608 19820 19818 19819 19820 19824 19820 19823 19824 20624 19823 19820 21409 20624 19820 19820 20609 21409 19820 20608 20609 19825 19824 19823 20624 19825 19823 22231 20635 19825 19825 21409 22231 19825 20624 21409 19850 19827 19826 20622 19850 19826 21413 20622 19826 21417 21413 19826 19826 20623 21417 19828 19829 21449 21417 20623 19828 21422 21417 19828 21423 21422 19828 22240 21423 19828 19828 21449 22240 19829 19859 21449 19830 19840 19841 19830 19831 19840 20626 19840 19831 20627 20626 19831 19831 19860 20627 19833 19839 20628 19843 19839 19833 21443 19843 19833 22239 21443 19833 19833 19834 22239 19835 19834 19833 20628 19835 19833 19834 21442 22239 22223 21442 19834 19834 21410 22223 23160 21410 19834 19834 19835 23160 19835 22204 23157 19835 20628 22204 23169 23160 19835 19835 23157 23169 20629 19848 19836 20634 20619 19837 19837 19838 20634 20649 20634 19838 19838 19862 20649 19839 19840 20626 19841 19840 19839 19843 19841 19839 19839 20626 20628 19843 19842 19841 20638 19845 19842 19842 19844 20638 19842 19843 19844 21443 19844 19843 21443 20638 19844 20638 19846 19845 19846 20641 20642 19846 20638 20641 19847 19849 19856 19847 19848 19849 20630 19849 19848 20631 20630 19848 19848 20629 20631 21416 19852 19850 19850 20622 21416 20644 20643 19851 19851 19852 20644 21416 20644 19852 21445 19866 19853 19853 19854 21445 21450 21445 19854 19854 20635 21450 19854 20625 20635 19863 19862 19857 19857 19861 19863 20656 19859 19858 19858 19870 20656 19859 20656 21449 20645 20640 19860 20639 20627 19860 20640 20639 19860 19867 19863 19861 19862 20648 20649 19862 19863 20648 19863 19868 20648 19863 19867 19868 19865 19866 20651 21454 20651 19866 21455 21454 19866 21456 21455 19866 19866 21445 21456 19877 19868 19867 19868 19877 19878 20653 20648 19868 19868 19878 20653 20665 20663 19869 19869 20643 20665 20657 20656 19870 19870 19871 20657 21454 21453 19871 19871 20658 21454 21453 20657 19871 22259 21457 19872 19872 19873 22259 19874 19873 19872 19873 19874 20667 22285 22259 19873 19873 20667 22285 19876 19875 19874 19874 20666 20667 19874 19875 20666 20662 20653 19878 19878 19882 20662 19879 19880 19886 19879 19887 20666 19879 19886 19887 21466 20669 19881 19881 21464 21466 20671 20670 19882 20670 20662 19882 19888 19886 19885 20680 19888 19885 19885 19891 20680 19888 19887 19886 21463 20666 19887 19887 20681 21463 19887 19888 20681 19888 20680 20681 21478 20690 19889 19889 21472 21478 19889 21471 21472 19889 20672 21471 19890 19898 20679 21482 20680 19891 19891 21480 21482 21481 21480 19891 20689 20671 19892 19895 23214 23236 23235 23214 19895 19895 19896 23235 19897 19896 19895 23236 19897 19895 19896 22346 23235 23255 22346 19896 19896 22358 23255 19896 19897 22358 23236 20686 19897 19897 21489 22358 21490 21489 19897 21494 20679 19898 19898 19899 21494 22323 21494 19899 22371 22323 19899 19899 21496 22371 19899 20694 21496 19899 20693 20694 19900 20699 20711 20700 20699 19900 19900 20692 20700 19900 19901 20692 20695 20693 19902 19902 19903 20695 20697 20696 19905 19905 19906 20697 21495 20697 19906 21500 21495 19906 19906 20705 21500 20708 20707 19907 21501 20708 19907 21502 21501 19907 19907 20709 21502 20707 19908 19907 19908 20707 20723 19912 19911 19909 22380 20713 19909 19909 19910 22380 19911 19910 19909 19910 21488 23254 19910 20684 21488 19910 19911 20684 23254 22380 19910 19911 19912 20684 20685 20684 19912 19912 19913 20685 21502 20709 19915 19915 20717 21502 19916 20733 21512 21510 21508 19916 21512 21510 19916 21504 20717 19917 21505 21504 19917 19917 19918 21505 21514 21505 19918 19918 20724 21514 21514 20724 19919 21515 21514 19919 19919 19920 21515 19921 19920 19919 22352 21515 19920 19920 20710 22352 19920 20698 20710 20725 20702 19922 20726 20725 19922 22394 20728 19924 19924 21526 22394 19924 19925 21526 21527 21526 19925 19925 20732 21527 20735 19932 19926 20736 20735 19926 19926 20734 20736 19928 20743 21538 19929 19930 20746 19931 19930 19929 20745 20733 19929 20746 20745 19929 19930 19931 20747 20747 20746 19930 20737 20731 19933 20738 20737 19933 19933 19934 20738 19934 19938 20738 21546 20754 19935 19935 19936 21546 19937 19936 19935 19939 19937 19935 22408 21546 19936 19936 19937 22408 19937 22407 22408 19937 19939 22407 20749 20738 19938 20753 20749 19938 19939 21536 22407 19939 20740 21536 19942 19941 19940 20758 19942 19940 19940 20752 20758 21542 20751 19941 21551 21542 19941 19941 21550 21551 19941 21549 21550 19941 19942 21549 19942 20758 21549 19945 19944 19943 20761 19945 19943 19943 19957 20761 19943 19951 19957 19944 19945 20755 20755 20750 19944 19945 19967 21565 20761 19967 19945 21565 20755 19945 19946 19947 20756 19948 19947 19946 20757 19948 19946 21557 20757 19946 22425 21557 19946 19946 22418 22425 19946 21548 22418 19946 20756 21548 19949 19950 22420 22420 21558 19949 19954 19953 19952 19953 19961 20752 19953 19954 19961 19957 19967 20761 19968 19967 19957 19957 19958 19968 21572 19968 19958 19958 19981 21572 19958 19966 19981 21566 19960 19959 19959 21557 21566 19959 20757 21557 21566 20762 19960 19961 19975 20752 19961 19974 19975 21579 19982 19962 22434 21579 19962 19962 19977 22434 19978 19977 19962 19962 19964 19978 19962 19963 19964 21558 19964 19963 22435 19978 19964 19964 22427 22435 19964 22420 22427 19964 21558 22420 20769 19980 19965 19965 20763 20769 19967 19968 21565 19968 21563 21565 22424 21563 19968 22430 22424 19968 19968 21572 22430 19969 19970 20764 19971 19970 19969 19969 20765 20766 19969 20764 20765 19970 20762 20764 19970 19971 20762 19976 19974 19972 19972 19973 19976 20766 19976 19973 19976 19975 19974 21554 20758 19975 19975 19976 21554 20758 20752 19975 21568 21554 19976 21570 21568 19976 19976 20766 21570 23305 22434 19977 19977 23298 23305 19977 19978 23298 23299 23298 19978 23300 23299 19978 19978 22435 23300 20776 20770 19979 19979 19996 20776 20769 20768 19980 21574 21572 19981 21579 20775 19982 20775 19986 19982 19983 19984 19988 19985 19984 19983 20774 19985 19983 20779 20774 19983 20780 20779 19983 19983 19988 20780 20777 20773 19985 21578 20777 19985 19985 20774 21578 20006 19993 19987 19987 19999 20006 20785 20780 19988 19988 19994 20785 19991 19990 19989 22446 21601 19990 19990 21590 22446 19990 19991 21590 21591 21590 19991 19991 20781 21591 21591 20781 19992 19992 21585 21591 21586 21585 19992 20006 20005 19993 20787 20785 19994 19994 20784 20787 19994 20002 20784 19994 20000 20002 20789 19996 19995 19995 20001 20789 20782 20776 19996 20790 20782 19996 19996 20789 20790 20014 20010 19997 19997 20011 20014 20012 20011 19997 20796 20012 19997 19997 19998 20796 19999 19998 19997 20006 19999 19997 19997 20005 20006 22442 20796 19998 19998 20783 22442 19998 19999 20783 20793 20790 20001 20001 20009 20793 20790 20789 20001 20002 20003 20784 20797 20784 20003 20003 20007 20797 20800 20008 20004 20004 20799 20800 21601 20799 20004 20007 20008 20800 20798 20797 20007 20800 20798 20007 20802 20793 20009 20009 20013 20802 20011 20012 21604 21604 20804 20011 23319 22461 20012 20012 20796 23319 22461 21604 20012 21603 20802 20013 20013 20805 21603 20020 20019 20015 20021 20020 20015 21615 20021 20015 20015 21611 21615 20015 20016 21611 20017 20016 20015 20016 20808 21611 20016 20807 20808 20016 20017 20807 20017 20806 20807 20017 20018 20806 20809 20806 20018 20811 20809 20018 20018 20810 20811 21617 20813 20021 20021 21616 21617 20021 21615 21616 20822 20027 20023 20023 20818 20822 20819 20818 20023 21624 20819 20023 21626 21624 20023 20814 20025 20024 20024 20812 20814 20025 20814 20817 20026 20028 20029 20040 20029 20028 20041 20040 20028 20028 20038 20041 20040 20039 20029 20836 20031 20030 21632 20836 20030 20030 20827 21632 20836 20828 20031 20032 20033 20035 20034 20033 20032 20036 20035 20033 20837 20036 20033 20033 20034 20837 20034 20828 20837 20035 20036 20037 20038 20037 20036 20044 20038 20036 20838 20044 20036 20036 20837 20838 20044 20041 20038 20830 20045 20039 20844 20830 20039 20039 20843 20844 20039 20040 20843 20040 20041 20843 20041 20044 20839 20041 20841 20843 20041 20839 20841 20821 20820 20042 22495 20821 20042 20042 20816 22495 20043 20052 20824 20044 20838 20839 20049 20048 20047 20078 20049 20047 20847 20065 20048 20048 20073 20847 20048 20049 20073 21650 20073 20049 20049 20080 21650 20049 20078 20080 20050 20850 20852 20050 20848 20850 20853 20071 20051 20051 20851 20853 20052 20056 20824 20052 20055 20056 20067 20055 20052 20052 20053 20067 20825 20056 20054 20054 20057 20825 20058 20057 20054 20068 20058 20054 20054 20055 20068 20056 20055 20054 20055 20067 20068 20825 20824 20056 20826 20825 20057 21631 20826 20057 20057 20832 21631 20833 20832 20057 20057 20060 20833 20057 20058 20060 20058 20059 20060 20061 20060 20059 20062 20061 20059 21633 20833 20060 20060 20069 21633 20060 20061 20069 20061 20062 20069 20070 20069 20062 22535 20867 20063 23380 22535 20063 24118 23380 20063 20063 23373 24118 20063 20064 23373 20867 20862 20063 24111 23373 20064 20064 20857 24111 20065 20847 20848 20069 20070 21633 20070 20860 21633 20070 20077 20860 20854 20075 20071 20071 20853 20854 20849 20847 20073 21645 20849 20073 21650 21645 20073 20074 20869 20870 20872 20869 20074 20074 20075 20872 20076 20075 20074 20075 20854 20872 20077 20859 20860 21648 20859 20077 20077 20861 21648 20078 20079 20080 20082 20080 20079 20079 20081 20082 20080 20082 20085 21661 21650 20080 20080 20085 21661 20100 20089 20082 20089 20085 20082 20084 20866 20879 20867 20866 20084 20084 20862 20867 20085 20881 21661 20085 20089 20881 20086 20878 20882 20086 20870 20878 21669 20881 20087 20089 20088 20087 20881 20089 20087 20882 20102 20090 20887 20103 20091 20890 20887 20091 20094 20093 20092 20888 20094 20092 21674 20888 20092 20092 20093 20095 20105 20104 20093 20093 20094 20105 20104 20095 20093 20094 20096 20105 20097 20096 20094 20888 20097 20094 20096 20097 20874 20097 20873 20874 21662 20873 20097 21679 21662 20097 20097 20888 21679 20112 20110 20099 20894 20109 20101 20101 20107 20894 20108 20107 20101 20101 20102 20108 20889 20108 20102 20102 20883 20889 20102 20882 20883 21678 21671 20103 24184 21678 20103 20103 23424 24184 20103 20887 23424 20107 20108 21670 21686 20894 20107 20107 21670 21686 20108 20889 21665 20108 21665 21670 20893 20114 20109 20894 20893 20109 20115 20113 20110 20896 20115 20110 20110 20111 20896 20112 20111 20110 20897 20896 20111 21685 20897 20111 20111 20112 21685 21688 21685 20112 20112 21683 21688 21684 21683 20112 20900 20118 20116 20901 20900 20116 20116 20899 20901 20116 20117 20899 20118 20117 20116 20117 20130 20899 20117 20129 20130 20117 20128 20129 20890 20128 20117 20895 20890 20117 20117 20118 20895 22568 22567 20118 20118 20900 22568 21689 20895 20118 22567 21689 20118 20119 20120 20915 20120 20893 20898 20120 20914 20915 20120 20913 20914 20120 20898 20913 20123 20122 20121 20902 20124 20122 20904 20902 20122 20905 20904 20122 20122 20123 20905 20123 20131 20905 20132 20131 20123 20902 20125 20124 21699 21698 20125 20125 20903 21699 20125 20902 20903 21698 20126 20125 21692 20127 20126 21698 21692 20126 20134 20133 20127 21692 20134 20127 20137 20130 20129 20901 20899 20130 20130 20138 20901 20130 20137 20138 20131 20139 20905 22585 20136 20133 20133 20134 22585 22587 22585 20134 22589 22587 20134 22602 22589 20134 20134 21692 22602 20135 20141 20906 21701 20907 20136 22585 21701 20136 20911 20901 20138 20138 20910 20911 22576 20905 20139 22577 22576 20139 20139 20914 22577 20139 20140 20914 20915 20914 20140 20907 20906 20141 20916 20912 20143 20918 20916 20143 20919 20918 20143 20143 20144 20919 20145 20146 20147 21707 20146 20145 21710 20922 20146 20146 21704 21710 21707 21704 20146 20934 20150 20148 20150 20934 20935 20153 20152 20151 20152 20923 20927 20936 20923 20152 20152 20153 20936 20927 20155 20152 20938 20936 20153 20939 20938 20153 20157 20156 20154 20931 20157 20154 20932 20931 20154 20154 20155 20932 20155 20927 20932 20931 20159 20157 20931 20930 20158 20158 20159 20931 22633 20940 20160 20160 20921 22633 20168 20167 20162 20941 20168 20162 20162 20940 20941 20165 20164 20163 20187 20165 20163 20163 20175 20187 20163 20174 20175 20163 20164 20174 20164 20166 20168 20164 20165 20166 20941 20174 20164 20164 20168 20941 20177 20166 20165 20166 20167 20168 20169 20188 20942 20169 20186 20188 20172 20171 20170 22640 20172 20170 20170 21720 22640 20170 20944 21720 20170 20178 20944 20179 20178 20170 20948 20179 20170 20170 20947 20948 20170 20171 20947 22644 22643 20171 20171 20172 22644 21723 20947 20171 22646 21723 20171 20171 22643 22646 22645 22644 20172 20172 22640 22645 20173 20174 20946 20175 20174 20173 20176 20175 20173 20950 20176 20173 20173 20178 20950 20944 20178 20173 20945 20944 20173 20946 20945 20173 20174 20941 21719 21719 20946 20174 20175 20176 20187 20199 20187 20176 20176 20185 20199 20176 20184 20185 20176 20182 20184 20183 20182 20176 20950 20183 20176 20178 20180 20950 20178 20179 20180 20181 20180 20179 20954 20181 20179 20179 20948 20954 20180 20183 20950 20180 20182 20183 20180 20181 20182 20198 20182 20181 20964 20198 20181 20181 20954 20964 20202 20184 20182 20182 20198 20202 20208 20185 20184 20184 20202 20208 20209 20199 20185 20971 20209 20185 20185 20208 20971 20189 20188 20186 20190 20189 20186 20187 20199 20203 20943 20942 20188 20188 20189 20943 22663 20943 20189 23500 22663 20189 20189 21729 23500 20189 20190 21729 20190 20200 21729 20191 20192 20206 20970 20955 20191 20191 20205 20970 20206 20205 20191 20956 20206 20192 20961 20958 20193 20193 20196 20961 20193 20195 20196 20194 20195 20197 20196 20195 20194 20961 20196 20194 20962 20961 20194 20963 20962 20194 20966 20202 20198 21730 20966 20198 21731 21730 20198 20198 20964 21731 20212 20203 20199 20199 20209 20212 20200 20967 21729 20968 20967 20200 21732 20973 20201 21733 21732 20201 21743 21733 20201 20201 20976 21743 20201 20965 20976 20966 20208 20202 22667 20968 20204 22688 22667 20204 22670 20970 20205 22671 22670 20205 20205 20206 22671 20206 22664 22671 20206 21725 22664 20206 20956 21725 20219 20214 20207 20955 20219 20207 20208 20966 20971 20218 20212 20209 20209 20210 20218 20211 20210 20209 20971 20211 20209 20991 20975 20210 20992 20991 20210 21744 20992 20210 20210 20211 21744 20210 20217 20218 20975 20217 20210 20211 21742 21744 20211 20974 21742 20211 20971 20974 20218 20213 20212 20218 20217 20213 20219 20955 20969 20220 20221 20224 20222 20221 20220 20224 20223 20220 20994 20224 20221 20221 20993 20994 21007 20993 20221 20221 20222 21007 20222 20232 21007 20989 20227 20223 20223 20987 20989 20223 20224 20987 20224 20994 20995 20224 20986 20987 20995 20986 20224 21747 20977 20225 21750 21747 20225 20225 20997 21750 21015 20235 20226 20226 20982 21015 20229 20228 20227 20990 20229 20227 20227 20989 20990 20228 20229 21012 20229 21008 21012 20229 20990 21008 21002 20998 20230 20231 20234 21018 20232 20233 21007 20233 21006 21007 20234 21017 21018 21020 20238 20236 20236 21019 21020 20236 21013 21019 20240 20239 20238 21760 20240 20238 20238 21020 21760 20239 20242 20243 20239 20240 20242 21760 20242 20240 20241 20244 21022 21025 20243 20242 21762 21025 20242 20242 21760 21762 21027 21026 20243 20243 21025 21027 21024 21022 20244 21029 21024 20244 21768 20246 20245 20245 21767 21768 20245 21028 21767 21030 20248 20246 21768 21030 20246 20252 20251 20247 21030 20252 20247 20247 20248 21030 21038 21031 20249 20249 20256 21038 20249 20250 20256 20251 20252 20253 21032 20253 20252 21033 21032 20252 20252 21030 21033 20258 20255 20254 20255 20258 21035 20256 20265 21038 21039 20258 20257 21044 21039 20257 21040 21035 20258 20258 21039 21040 20261 20260 20259 21041 20263 20260 20260 20261 21041 20263 20262 20260 21060 21041 20261 20261 20264 21060 20262 20263 20265 20263 21041 21042 21043 20265 20263 20263 21042 21043 20264 20272 20284 21061 21060 20264 20264 20284 21061 20265 21037 21038 21043 21037 20265 20267 20269 20270 21797 20285 20268 20268 20292 21797 20271 20270 20269 21057 20274 20270 20270 20271 21057 21058 21057 20271 20271 20281 21058 20285 20284 20272 21075 20275 20273 20273 21056 21075 20273 20274 21056 21057 21056 20274 21825 20290 20275 20275 21081 21825 20275 21075 21081 20276 23612 25202 20276 20277 23612 20278 20277 20276 22764 20278 20276 24375 22764 20276 25202 24375 20276 20277 22744 22745 20277 20278 22744 20277 22745 23612 20278 20279 22744 20281 20279 20278 21063 20281 20278 22764 21063 20278 20279 21064 22744 20279 20280 21064 20281 20280 20279 20280 20282 20283 20280 20281 20282 21065 21064 20280 21801 21058 20281 22760 21801 20281 22763 22760 20281 20281 21063 22763 20284 20285 21061 21795 21061 20285 21797 21795 20285 21062 20293 20286 20286 20287 21062 20287 20288 21062 20288 20294 21070 20288 20289 20294 21070 21062 20288 20303 20294 20289 20289 20293 20303 21825 21078 20290 20302 20301 20291 20292 21067 21797 21068 21067 20292 21074 20303 20293 20293 21069 21074 20293 21062 21069 20294 20303 21070 21825 20297 20295 20295 21077 21825 20297 20296 20295 22788 21096 20296 20296 22787 22788 20296 20297 22787 20297 21824 22786 21825 21824 20297 20297 22786 22787 20300 20299 20298 21829 20300 20298 21830 21829 20298 20298 21083 21830 20298 20299 21083 21079 20308 20299 20299 20300 21079 21084 21083 20299 20300 21066 21079 21790 21066 20300 20300 21789 21790 21829 21789 20300 21816 21814 20302 20302 21071 21816 21074 21070 20303 21827 21082 20305 20305 20306 21827 20307 20306 20305 20310 20307 20305 20306 21826 21827 20306 20318 21826 20306 20307 20318 20319 20318 20307 20321 20319 20307 20307 20313 20321 21098 20317 20309 21101 21098 20309 20312 21087 21088 20323 20322 20314 20335 20323 20314 20314 20315 20335 20316 20315 20314 20315 20332 20335 21095 20332 20315 20315 20316 21095 21096 21095 20316 20318 20319 21826 21843 21826 20319 20319 21090 21843 20319 20321 21090 21119 20353 20320 20320 20326 21119 21094 21090 20321 21102 21094 20321 20323 20335 20347 20341 20325 20324 20326 21118 21119 20326 21088 21118 21847 21103 20327 21850 21847 20327 20327 21110 21850 20328 20329 20344 20330 20329 20328 20331 20330 20328 21121 20344 20329 20329 21111 21121 20329 21107 21111 20329 20330 21107 20330 21106 21107 20330 20331 21106 21109 21106 20331 21111 21109 20331 21113 21111 20331 20332 20333 20335 20334 20333 20332 21848 20334 20332 20332 21095 21848 21133 20335 20333 21139 21133 20333 21872 21139 20333 21873 21872 20333 20333 20334 21873 20334 21848 21873 21133 20347 20335 20351 20339 20336 21882 20352 20337 20337 20338 20350 20339 20338 20337 20352 20339 20337 20338 20339 20351 20338 20348 20350 20351 20348 20338 21134 21114 20339 20339 20352 21134 21114 20340 20339 21097 21091 20340 21114 21097 20340 21851 21110 20342 21852 21851 20342 20342 21127 21852 20342 20343 21127 20343 21126 21127 20343 20357 21126 21121 20354 20344 21131 21129 20345 20345 20346 21131 21132 21131 20346 20346 20347 21132 21133 21132 20347 20348 20349 20350 21880 21134 20352 21882 21880 20352 21861 21124 20353 21862 21861 20353 20353 21120 21862 20353 21119 21120 21137 20356 20354 20354 21128 21137 20354 21121 21128 21877 20366 20355 20355 21869 21877 20355 20356 21869 21871 21869 20356 20356 21141 21871 20356 21137 21141 21885 21126 20357 21893 21885 20357 21898 21891 20358 20358 20363 21898 20359 20360 20362 20361 20360 20359 21165 20361 20359 20363 20362 20360 21910 20363 20360 22851 21910 20360 23671 22851 20360 20360 20361 23671 20361 22859 23671 20361 21928 22859 20361 21165 21928 21910 21898 20363 20364 21140 21142 21154 21143 20365 21901 21154 20365 20365 20366 21901 20366 21895 21901 20366 21877 21895 21948 21175 20367 22916 21948 20367 22917 22916 20367 20367 20368 22917 20369 20368 20367 20368 20369 21193 20368 21947 22917 20368 21193 21947 20369 20378 21193 21161 20374 20370 21167 21161 20370 20370 20371 21167 21912 21167 20371 20371 21908 21912 20371 20372 21908 20372 21142 21908 20380 20376 20375 21188 20380 20375 20375 20377 21188 20376 21192 21946 20376 20380 21192 21946 20381 20376 20378 20382 20383 20378 20379 20382 20378 20383 21193 20380 21179 21192 21946 21194 20381 21195 21193 20383 21956 21195 20383 21957 21956 20383 20383 21196 21957 20383 20384 21196 20384 20394 21196 20391 20390 20385 20385 20386 20391 21965 20391 20386 21966 21965 20386 21968 21966 20386 20386 21960 21968 21955 21197 20387 20387 21950 21955 20387 21194 21950 21954 20393 20388 21964 21954 20388 20388 21959 21964 20388 20389 21959 20389 20400 21959 21201 20394 20392 20392 20395 21201 21954 21202 20393 21201 21196 20394 20395 21199 21201 20395 21198 21199 21202 21198 20395 20409 20398 20397 20397 20408 20409 20398 20410 20421 20398 20409 20410 20398 20421 20422 21218 21217 20399 20399 21213 21218 20399 20403 21213 22919 21959 20400 22925 22919 20400 20400 20401 22925 20402 20401 20400 21209 20402 20400 20401 20402 21975 20401 21984 22925 20401 21975 21984 21209 21208 20402 20402 21208 21975 20403 20425 21213 20403 20412 20425 20407 20419 21207 20427 20409 20408 20408 20419 20427 21207 20419 20408 20423 20412 20411 20412 20424 20425 20412 20423 20424 21988 21979 20413 20413 21237 21988 21238 21237 20413 20413 20434 21238 20414 20448 20449 20414 20415 20448 20416 20415 20414 21215 20416 20414 21228 21215 20414 20414 20440 21228 20449 20440 20414 21249 20448 20415 22004 21249 20415 22947 22004 20415 20415 21224 22947 20415 20416 21224 21980 21224 20416 20416 21974 21980 20416 21216 21974 20416 21215 21216 21215 20418 20417 21228 20440 20418 20418 21215 21228 20423 20426 20430 21225 20424 20423 20423 20430 21225 21213 20425 20424 21225 21213 20424 20428 20429 21230 22005 20430 20428 22007 22005 20428 20428 21230 22007 20429 21229 21230 21231 21229 20429 20430 21222 21225 22005 21222 20430 21257 20444 20431 22011 21257 20431 20431 22008 22011 20431 21241 22008 20432 20433 21232 21998 21232 20433 22968 21998 20433 20433 22961 22968 20433 21235 22961 20433 21234 21235 20434 20445 21238 21992 21250 20435 20435 21239 21992 21994 21239 20436 22945 21994 20436 20436 21240 22945 20437 21996 22001 22946 21996 20437 20437 20438 22946 20438 22002 22946 20438 21249 22002 20438 20446 21249 21248 20446 20439 20439 20447 21248 20441 21254 22008 20441 21252 21254 21253 21252 20441 21263 21253 20441 20441 21262 21263 20441 20442 21262 21241 20443 20441 22008 21241 20441 20442 20450 21262 20444 20452 20454 21257 20452 20444 21258 21238 20445 22015 21258 20445 22029 22015 20445 20445 20455 22029 20446 21248 21249 21249 21248 20447 20450 21251 21278 20450 20451 21251 21264 21262 20450 21278 21264 20450 22021 21251 20451 20451 21261 22021 21255 20453 20452 21257 21255 20452 21265 20456 20453 22014 21265 20453 20453 21255 22014 20455 20486 22029 20455 20470 20486 20456 20462 20463 21265 20462 20456 20486 20470 20457 20469 20460 20459 21260 20469 20459 20469 20468 20460 20461 20462 21280 20463 20462 20461 22052 21280 20462 20462 22051 22052 20462 21266 22051 20462 21265 21266 20464 20475 20476 22018 20467 20466 22019 22018 20466 22035 22019 20466 23791 22035 20466 20466 22978 23791 20466 22034 22978 22018 21260 20467 20468 20469 22020 22046 20482 20468 20468 22020 22046 20469 21260 22020 20474 20473 20471 22042 20474 20471 22044 22042 20471 20471 20472 22044 20472 20489 22032 20472 22032 22044 22042 20490 20474 21271 20476 20475 21282 21271 20475 20475 21270 21282 21271 20477 20476 23009 22055 20477 23010 23009 20477 20477 22054 23010 20477 21286 22054 20477 21271 21286 21272 20481 20478 22990 22033 20480 20480 22045 22990 20480 20481 22045 20481 21272 22045 22059 21287 20482 20482 22047 22059 20482 22046 22047 20492 20484 20483 20483 20491 20492 21275 21261 20484 20484 20492 21275 20487 20486 20485 20488 20487 20485 21269 20488 20485 22041 22029 20486 20486 20487 22041 20487 22027 22041 22028 22027 20487 22969 22028 20487 20487 20488 22969 20488 22026 22969 20488 21269 22026 20489 22030 22032 20489 21259 22030 20490 22042 22053 22053 21281 20490 21288 20492 20491 20491 20493 21288 22067 21275 20492 20492 21288 22067 21296 21288 20493 20493 20500 21296 21313 20501 20494 20495 20506 20507 20498 20497 20496 21312 20498 20496 20496 21293 21312 21294 21293 20496 21295 21294 20496 22083 21297 20499 20499 20509 22083 20499 20503 20509 21297 20500 20499 21297 21296 20500 21313 20516 20501 20504 20503 20502 20512 20504 20502 20513 20512 20502 20514 20513 20502 20502 20505 20514 20510 20509 20503 20503 20504 20510 20520 20510 20504 21323 20520 20504 20504 20512 21323 20515 20514 20505 20509 22081 22083 20509 21336 22081 20509 20510 21336 20510 20520 21336 20512 20513 21323 21331 21323 20513 21332 21331 20513 20513 21324 21332 20513 20522 21324 20513 20521 20522 20513 20514 20521 20514 20515 20521 20515 20516 20521 20517 20527 20530 20517 20533 20538 20517 20530 20533 23054 21326 20518 20518 23044 23054 20518 23042 23044 20518 22085 23042 22087 22085 20518 20518 21326 21327 21320 21319 20519 21337 21336 20520 20520 21334 21337 20520 21333 21334 20520 21331 21333 20520 21323 21331 20522 20532 21324 20531 20527 20523 21322 21321 20524 21330 21328 20525 20525 20536 21330 20527 20529 20530 20527 20528 20529 20531 20528 20527 20540 20530 20529 20540 20533 20530 21325 21324 20532 20532 20537 21325 20556 20555 20533 20533 20541 20556 20533 20540 20541 20555 20552 20533 20534 21329 21330 22097 21329 20534 20534 20535 22097 20551 20550 20539 20541 20544 20556 21362 20558 20542 21363 21362 20542 22129 21363 20542 20542 22122 22129 20542 20543 22122 22123 22122 20543 20543 21341 22123 20543 20545 21341 20544 20547 20556 20546 20549 21349 20557 20556 20547 20548 20560 21361 21361 21359 20548 21359 21349 20549 20550 20551 20553 20550 20554 20561 20550 20552 20554 20553 20552 20550 20555 20554 20552 20554 20555 20561 20555 20556 20563 20563 20561 20555 20556 20557 20563 20567 20566 20557 20566 20563 20557 21365 20564 20558 20558 21362 21365 20560 21356 21361 21371 21356 20560 20563 20562 20561 20562 20566 20570 20562 20563 20566 20571 20568 20564 21365 20571 20564 20565 21357 21358 22138 21357 20565 20565 20569 22138 20566 20567 20570 21374 20572 20568 20568 21373 21374 20568 20571 21373 22155 22138 20569 20569 20575 22155 20571 21366 21373 20571 21365 21366 21374 20579 20572 20584 20574 20573 20573 20579 20584 20584 20580 20574 20575 20583 22155 20575 20582 20583 20590 20577 20576 21391 20590 20576 20577 20590 22165 22165 21378 20577 21375 20584 20579 20579 21374 21375 20580 20588 20589 20580 20584 20588 20581 20582 20585 20583 20582 20581 21385 20583 20581 20581 20591 21385 22158 22155 20583 22162 22158 20583 20583 21385 22162 21375 20588 20584 22164 22163 20586 22165 22164 20586 20586 21378 22165 20594 20592 20587 21382 20594 20587 20587 20588 21382 20589 20588 20587 20588 21375 21382 20590 21391 22165 21386 21385 20591 20591 21384 21386 20594 20593 20592 21380 20602 20593 21382 21380 20593 20593 20594 21382 20595 20603 21396 21390 20596 20595 21396 21390 20595 21386 21384 20596 22170 21386 20596 22171 22170 20596 20596 21390 22171 20597 21394 22198 20597 20605 21394 20597 20598 20605 22163 20605 20598 20601 20600 20599 21393 20601 20599 20599 20620 21393 20599 20608 20620 20599 20600 20608 20600 20601 21395 20609 20608 20600 21401 20609 20600 22196 21401 20600 20600 22186 22196 20600 22181 22186 20600 21395 22181 20601 21392 21395 20601 21389 21392 21393 21389 20601 21380 20620 20602 20614 20612 20603 20603 20610 20614 20603 20604 20610 20603 20612 21396 20605 20606 21394 20607 20606 20605 23128 20607 20605 20605 23120 23128 20605 22163 23120 23136 21394 20606 23928 23136 20606 20606 23921 23928 20606 20607 23921 20607 23915 23921 20607 23128 23915 20609 21400 21409 21401 21400 20609 21402 20614 20610 20610 20615 21402 22180 21391 20611 20611 21405 22180 20614 20613 20612 20612 20613 21396 22205 21397 20613 20613 20614 22205 21397 21396 20613 20614 21402 22205 21410 21402 20615 21411 21410 20615 20616 20617 21403 20617 21398 21403 21408 21407 20618 20618 20632 21408 20618 20621 20632 20618 20619 20621 20634 20621 20619 20620 21389 21393 20620 21380 21389 20634 20632 20621 20622 21413 21416 21430 20628 20626 20626 20636 21430 20626 20627 20636 20637 20636 20627 20639 20637 20627 20628 21430 22204 21419 20631 20629 20630 21420 23176 20630 20631 21420 23176 21447 20630 21421 21420 20631 20631 21419 21421 22227 21408 20632 20632 20633 22227 20634 20633 20632 23949 22227 20633 23951 23949 20633 20633 21433 23951 20633 20634 21433 20634 21432 21433 20634 20649 21432 22231 21450 20635 22237 21430 20636 20636 20637 22237 20637 21440 22237 20637 20639 21440 21443 20641 20638 20639 20640 21440 20640 20645 21451 21451 21440 20640 21441 20642 20641 21442 21441 20641 22239 21442 20641 20641 21443 22239 20643 20654 20665 20655 20654 20643 20643 20644 20655 22263 20655 20644 23966 22263 20644 20644 23181 23966 20644 23180 23181 20644 23179 23180 20644 23174 23179 20644 21416 23174 21458 20652 20646 20646 20647 21458 22261 21458 20647 20650 20649 20648 20653 20650 20648 21448 21432 20649 20649 20650 21448 21452 21448 20650 22262 21452 20650 20650 20659 22262 20650 20653 20659 21454 20658 20651 20652 21458 21459 20662 20659 20653 22280 20665 20654 20654 22264 22280 20654 22263 22264 20654 20655 22263 22252 21449 20656 20656 20657 22252 22265 22252 20657 20657 21453 22265 20659 21461 22262 20659 20660 21461 20661 20660 20659 20662 20661 20659 20660 20661 21461 20661 20670 21461 20661 20662 20670 21462 20678 20663 20663 20664 21462 20665 20664 20663 23216 21462 20664 20664 22280 23216 20664 20665 22280 21463 20667 20666 20667 22274 22285 22293 22274 20667 20667 21463 22293 20668 21460 21464 20668 21459 21460 21466 20674 20669 21465 21461 20670 20670 20671 21465 21492 21465 20671 20671 20689 21492 20672 21470 21471 20672 20673 21470 20673 21469 21470 20673 20677 21469 21475 20675 20674 20674 21466 21475 21476 20676 20675 20675 21475 21476 20676 20684 20685 21488 20684 20676 20676 21476 21488 20677 21468 21469 20677 20678 21468 23224 21468 20678 20678 22298 23224 20678 21462 22298 21494 20683 20679 21482 20681 20680 22306 21463 20681 20681 21480 22306 21482 21480 20681 22320 22315 20682 22321 22320 20682 20682 22313 22321 20682 20683 22313 22323 22313 20683 20683 21494 22323 20688 20687 20686 23236 20688 20686 21492 20689 20687 20687 21491 21492 20687 20688 21491 22318 21491 20688 23236 22318 20688 21484 20692 20690 20690 21479 21484 20690 21478 21479 20691 20696 21490 21484 20700 20692 20703 20694 20693 20693 20695 20703 21497 21496 20694 20694 20703 21497 21495 21490 20696 20696 20697 21495 20718 20710 20698 20699 20700 22337 22337 20711 20699 20700 21486 22337 20700 21484 21486 20701 20719 20720 20701 20702 20719 20725 20719 20702 20705 20706 21500 21509 21500 20706 20706 21508 21509 21522 20723 20707 22348 21522 20707 20707 20708 22348 20708 21501 22348 20710 21506 22352 20710 20718 21506 22337 20718 20711 22378 21499 20712 22380 22378 20712 20712 20713 22380 22360 21519 20714 20714 22359 22360 20714 22358 22359 23255 22358 20714 20714 20715 23255 20716 20715 20714 21519 20716 20714 23263 23255 20715 20715 23262 23263 20715 23261 23262 20715 20716 23261 20716 22386 23261 20716 21499 22386 21503 21502 20717 21504 21503 20717 22366 21506 20718 20718 22337 22366 21507 20720 20719 21517 21507 20719 20719 21516 21517 20719 20725 21516 20720 21518 21524 20720 21507 21518 20721 21520 21521 20721 21519 21520 20730 20722 20721 21521 20730 20721 20730 20729 20722 21528 21525 20723 20723 21522 21528 20725 20726 21516 21523 21516 20726 20726 20731 21523 22375 21498 20727 23275 22375 20727 20727 20728 23275 20728 23260 23275 20728 22394 23260 22416 20744 20729 20729 22404 22416 20729 22399 22404 20729 21521 22399 20729 20730 21521 20731 20737 21523 20742 20741 20732 21537 20742 20732 22397 21527 20732 23280 22397 20732 20732 20741 23280 20733 20745 21512 22405 20736 20734 20734 21525 22405 20735 20736 22405 22401 21523 20737 20737 21539 22401 20737 20738 21539 20738 20749 21539 20739 21533 21536 21536 20740 20739 20741 20742 21540 23289 23280 20741 20741 23288 23289 20741 21540 23288 20742 21537 21540 20743 20744 21538 20744 22416 22417 22402 21538 20744 22417 22402 20744 20745 21511 21512 22403 21511 20745 22409 22403 20745 22410 22409 20745 20745 21541 22410 20745 20746 21541 20746 20747 21541 21542 21541 20747 20747 20748 21542 20748 20751 21542 22406 21539 20749 22412 22406 20749 23293 22412 20749 20749 21543 23293 20749 20753 21543 21540 21537 20750 22415 21540 20750 20750 20755 22415 20753 20760 21543 20753 20759 20760 20754 21546 21556 22432 22415 20755 20755 21563 22432 21565 21563 20755 21554 21549 20758 21555 21543 20760 21571 21555 20760 21566 20764 20762 21574 20769 20763 20763 21562 21574 22423 21562 20763 20763 21556 22423 21569 20765 20764 20764 21567 21569 20764 21566 21567 22431 21570 20765 20765 21551 22431 22426 21551 20765 20765 21569 22426 21570 20766 20765 20767 21573 22429 20767 20770 21573 20768 20769 20771 20770 20776 21573 22442 20783 20772 20772 21584 22442 20772 20778 21584 20773 20777 20778 20774 20779 21578 20775 21579 21580 20776 20782 21573 22438 20778 20777 20777 21575 22438 21576 21575 20777 21578 21576 20777 22438 21584 20778 20779 21577 21578 20779 20780 21577 20780 20786 21577 20780 20785 20786 22439 21573 20782 23307 22439 20782 20782 21594 23307 20782 20790 21594 20788 20787 20784 21598 20788 20784 20784 20797 21598 20787 20786 20785 20786 20788 21577 20786 20787 20788 21587 21577 20788 21589 21587 20788 20788 21588 21589 21598 21588 20788 20790 20794 21594 20790 20793 20794 21600 20795 20791 20791 20803 21600 20791 20792 20803 20793 20792 20791 20795 20793 20791 20792 20802 20803 20792 20793 20802 21595 20794 20793 20793 20795 21595 23306 21594 20794 20794 21595 23306 21597 21595 20795 21599 21597 20795 21600 21599 20795 20796 23318 23319 20796 22442 23318 20797 20798 21598 20798 20800 20801 20798 20801 21598 20801 20800 20799 21598 20801 20799 22453 21598 20799 20799 21601 22453 21603 20803 20802 22455 21600 20803 20803 21602 22455 21603 21602 20803 22465 21608 20804 20804 21604 22465 20805 21602 21603 22460 21602 20805 20809 20807 20806 20809 20808 20807 20808 21610 21611 23335 21610 20808 23347 23335 20808 20808 21612 23347 20808 20809 21612 22473 21612 20809 20809 20811 22473 22489 22473 20811 20815 20814 20812 21620 20815 20812 20812 20813 21620 20813 21617 21620 20814 20815 20817 21623 20817 20815 20815 21620 21623 22522 22495 20816 20816 21637 22522 20816 20829 21637 20830 20829 20816 21628 20827 20817 20817 21623 21628 20831 20823 20818 21630 20831 20818 20818 20819 21630 20823 20822 20818 23359 21630 20819 20819 21627 23359 20819 21624 21627 20820 22509 22510 20820 21629 22509 20820 20821 21629 20820 21625 21626 22510 21625 20820 22500 21629 20821 22508 22500 20821 20821 22495 22508 20826 21631 22518 22492 21632 20827 20827 21628 22492 21634 20837 20828 20828 20836 21634 20829 20844 20845 20829 20830 20844 20829 21636 21637 20829 20841 21636 20845 20841 20829 20831 20863 20864 21630 20863 20831 22524 21631 20832 20832 21633 22524 20832 20833 21633 21635 21634 20834 22525 21635 20834 20834 22515 22525 20834 20835 22515 20836 20835 20834 21634 20836 20834 20835 22514 22515 20835 22512 22514 22513 22512 20835 20835 21632 22513 20835 20836 21632 21634 20838 20837 20840 20839 20838 21635 20840 20838 20838 21634 21635 20842 20841 20839 20839 20840 20842 20840 20841 20842 21635 20841 20840 22528 21636 20841 20841 21635 22528 20855 20843 20841 20841 20845 20855 20845 20844 20843 20855 20845 20843 20850 20848 20846 20846 20849 20850 20846 20847 20849 20848 20847 20846 21638 20850 20849 23374 21638 20849 23375 23374 20849 20849 21646 23375 20849 21645 21646 22529 20852 20850 20850 21638 22529 21639 20853 20851 21641 21639 20852 21642 21641 20852 22529 21642 20852 20856 20854 20853 21640 20856 20853 20853 21639 21640 21651 20872 20854 20854 20856 21651 21657 21651 20856 22536 21657 20856 20856 21640 22536 20857 23364 24111 20857 21630 23364 20857 20863 21630 21644 21633 20858 23369 21644 20858 23371 23369 20858 20858 22534 23371 20858 21649 22534 20858 20859 21649 20860 20859 20858 21633 20860 20858 20859 21648 21649 21652 21648 20861 21653 21652 20861 20873 20871 20865 21659 20877 20866 20866 21655 21659 20866 20867 21655 20866 20877 20879 22535 21655 20867 20889 20883 20868 21658 20889 20868 20868 20869 21658 20870 20869 20868 20878 20870 20868 20883 20878 20868 20869 21651 21658 20869 20872 21651 21654 21653 20871 22541 21654 20871 20871 21663 22541 20871 21662 21663 20871 20873 21662 20880 20877 20875 21677 20891 20875 20875 20876 21677 20877 20876 20875 22542 21676 20876 23381 22542 20876 20876 20877 23381 20876 21676 21677 20877 21659 23381 20880 20879 20877 20883 20882 20878 20881 21660 21661 21685 20886 20885 23409 22561 20886 23425 23409 20886 20886 22566 23425 20886 21685 22566 20887 21690 23424 20887 21689 21690 20887 20895 21689 20887 20890 20895 23397 21679 20888 20888 23394 23397 20888 21674 23394 20889 21656 22548 21658 21656 20889 22548 21665 20889 21677 21676 20891 21668 20892 20891 20891 21667 21668 21680 21667 20891 20891 21676 21680 20892 21668 21684 20893 20894 21687 21687 20898 20893 20894 21686 21687 22570 20913 20898 20898 21687 22570 20900 21693 22568 21694 21693 20900 20900 20901 21694 20901 20911 21694 20904 20903 20902 22595 21699 20903 20903 22584 22595 20903 20904 22584 22601 22584 20904 20904 22600 22601 20904 22579 22600 20904 20905 22579 20905 22576 22579 20906 20907 20908 21701 20908 20907 20908 21704 21707 21706 21704 20908 20908 21702 21706 20908 21701 21702 21694 20911 20909 22569 21694 20909 22571 22569 20909 20909 21696 22571 20909 21695 21696 20909 20916 21695 20909 20912 20916 20909 20910 20912 20911 20910 20909 23431 20914 20913 20913 23415 23431 20913 22570 23415 22578 22577 20914 23431 22578 20914 21697 21695 20916 20916 20917 21697 20918 20917 20916 21700 21697 20917 21709 21700 20917 20917 20918 21709 20918 20920 21709 20918 20919 20920 21717 20920 20919 22606 21709 20920 20920 21717 22606 20921 22628 22633 20921 20922 22628 20922 21710 23455 23456 22628 20922 20922 23455 23456 20923 20924 20927 20925 20924 20923 20936 20925 20923 20924 20931 20932 20924 20929 20931 21716 20929 20924 20924 21713 21716 20924 20926 21713 20924 20925 20926 20932 20927 20924 22613 20926 20925 20925 20936 22613 22613 21713 20926 20928 21714 22596 20928 20929 21714 20930 20929 20928 20937 20930 20928 22603 20937 20928 22605 22603 20928 20928 22596 22605 21716 21714 20929 20929 20930 20931 20937 20933 20930 20937 20934 20933 21717 20935 20934 22606 21717 20934 22614 22606 20934 22615 22614 20934 20934 20937 22615 23468 22613 20936 20936 22625 23468 20936 22624 22625 20936 20938 22624 20937 22603 22615 22638 22624 20938 20938 20939 22638 20939 20951 22638 21719 20941 20940 20940 21718 21719 22631 21718 20940 22632 22631 20940 22633 22632 20940 21721 20951 20942 20942 20943 21721 20943 22655 22656 22663 22655 20943 22650 21721 20943 22656 22650 20943 22641 21720 20944 20944 22635 22641 20944 20945 22635 22636 22635 20945 20945 22629 22636 20945 21718 22629 20945 20946 21718 21719 21718 20946 20949 20948 20947 21723 20949 20947 20948 20952 20954 20948 20949 20952 20953 20952 20949 21722 20953 20949 21723 21722 20949 20951 21721 22650 22642 22638 20951 22652 22642 20951 20951 22650 22652 20964 20954 20952 22662 20964 20952 20952 20953 22662 20953 21724 22662 20953 21722 21724 21738 20969 20955 20955 21734 21738 20955 20970 21734 22658 21725 20956 20956 21726 22658 20956 20957 21726 20957 20958 21726 21727 21726 20958 21728 21727 20958 20958 20959 21728 20961 20959 20958 22659 21728 20959 20959 20960 22659 20961 20960 20959 20960 21735 22659 20960 20962 21735 20960 20961 20962 22672 21736 20962 20962 20963 22672 21736 21735 20962 20963 21741 22672 20963 20972 21741 22662 21731 20964 20977 20976 20965 20974 20971 20966 21737 20974 20966 20966 21730 21737 22669 21729 20967 20967 22666 22669 20967 20968 22666 22667 22666 20968 21738 20983 20969 22674 21734 20970 20970 22670 22674 22675 21741 20972 20972 20973 22675 22683 22675 20973 20973 21732 22683 20974 21737 21742 20975 20991 20999 22684 21743 20976 20976 21746 22684 20976 20977 21746 21747 21746 20977 21014 20979 20978 20978 21010 21014 22695 22688 20979 20979 21751 22695 20979 21014 21751 21005 21004 20980 20980 20993 21005 20980 20984 20993 20982 20981 20980 21004 20982 20980 20982 21011 21015 20982 21004 21011 20985 20984 20983 21739 20985 20983 21745 21739 20983 20983 21738 21745 20994 20993 20984 20984 20985 20994 20985 21739 21740 20995 20994 20985 21740 20995 20985 20988 20987 20986 22689 20988 20986 20986 20995 22689 20987 20988 20989 22696 20989 20988 20988 22689 22696 22696 20996 20989 20996 20990 20989 22706 21008 20990 20990 20996 22706 20991 20992 20999 21744 21001 20992 21001 20999 20992 21007 21005 20993 20995 21740 22689 20996 22697 22706 20996 22696 22697 20997 21744 21750 20997 21009 21744 20998 21000 21009 20998 20999 21000 21002 20999 20998 21001 21000 20999 21000 21001 21009 21744 21009 21001 21004 21005 21011 21005 21006 21011 21007 21006 21005 21015 21011 21006 21753 21012 21008 22706 21753 21008 21752 21014 21010 21754 21016 21012 21012 21753 21754 21013 21016 21019 21752 21751 21014 21754 21019 21016 21755 21018 21017 22716 21021 21018 21018 21759 22716 21018 21755 21759 22717 21020 21019 21019 21754 22717 21761 21760 21020 22717 21761 21020 22703 21752 21021 22707 22703 21021 22708 22707 21021 22711 22708 21021 22713 22711 21021 22716 22713 21021 21022 21023 21757 21024 21023 21022 21023 21756 21757 23571 21756 21023 21023 21764 23571 21023 21024 21764 21024 21029 21764 21762 21027 21025 21026 21027 22731 21027 21762 22731 21028 21765 21767 21766 21765 21028 22732 21766 21028 21770 21033 21030 21030 21768 21770 21031 21037 21783 21038 21037 21031 21778 21034 21032 21032 21776 21778 21032 21770 21776 21032 21033 21770 21034 21781 22740 21034 21778 21781 21040 21036 21035 21036 21040 21046 21784 21783 21037 21037 21043 21784 21045 21040 21039 21039 21044 21045 21047 21046 21040 21040 21045 21047 21793 21042 21041 21799 21793 21041 21041 21060 21799 21793 21785 21042 21785 21043 21042 21785 21784 21043 21050 21045 21044 21050 21047 21045 21787 21051 21046 21046 21047 21787 21047 21050 22747 21792 21787 21047 22747 21792 21047 23615 22752 21048 21048 22761 23615 21048 21802 22761 21048 21049 21802 21049 21066 21802 22752 22747 21050 21053 21052 21051 21787 21053 21051 21052 21053 21791 21803 21059 21052 21052 21791 21803 21053 21787 21791 21054 21801 22760 21054 21058 21801 21054 21055 21058 21056 21055 21054 21076 21056 21054 22759 21076 21054 22760 22759 21054 21055 21056 21057 21055 21057 21058 21076 21075 21056 21803 21072 21059 21060 21798 21799 21060 21061 21798 21061 21795 21798 21805 21069 21062 21062 21070 21805 23628 22763 21063 24381 23628 21063 24387 24381 21063 21063 24386 24387 21063 23624 24386 21063 22764 23624 21064 21065 22744 21065 21782 23611 22745 22744 21065 23611 22745 21065 21066 21790 21802 21800 21797 21067 22757 21800 21067 21067 21804 22757 21067 21068 21804 21809 21804 21068 21068 21073 21809 21805 21074 21069 21070 21074 21805 21071 21806 21816 21071 21072 21806 21072 21803 21806 21818 21809 21073 21073 21080 21818 21810 21081 21075 21075 21076 21810 21812 21810 21076 22768 21812 21076 21076 22758 22768 22759 22758 21076 21077 21078 21825 21080 21082 21818 21081 21821 21825 21822 21821 21081 21081 21820 21822 21081 21810 21820 21819 21818 21082 21827 21819 21082 21083 21084 21091 21836 21830 21083 21083 21091 21836 21832 21086 21085 21085 21831 21832 21832 21087 21086 21089 21088 21087 21832 21089 21087 21841 21118 21088 21088 21089 21841 22789 21841 21089 21089 22782 22789 21089 21832 22782 21090 21105 21843 21090 21094 21105 21849 21836 21091 21091 21115 21849 21091 21097 21115 21098 21093 21092 21093 21098 21101 21093 21099 21837 21101 21099 21093 21094 21104 21105 21094 21102 21104 21095 21845 21848 21095 21844 21845 21095 21096 21844 22803 21844 21096 21096 22795 22803 21096 22788 22795 21858 21115 21097 21097 21114 21858 21099 21813 21814 21099 21100 21813 21101 21100 21099 21838 21837 21099 21099 21814 21838 21100 21101 21813 21815 21813 21101 21847 21104 21102 21102 21103 21847 21843 21105 21104 21104 21840 21843 21847 21840 21104 21108 21107 21106 21109 21108 21106 21107 21108 21112 21112 21111 21107 21108 21109 21112 21109 21111 21112 21851 21850 21110 21122 21121 21111 21111 21113 21122 21123 21122 21113 21129 21123 21113 21114 21134 21859 21859 21858 21114 23647 21849 21115 23650 23647 21115 21115 21858 23650 21857 21856 21116 21860 21857 21116 21116 21855 21860 21116 21117 21855 21118 21117 21116 21856 21118 21116 21117 21842 21855 21117 21118 21842 21118 21841 21842 21120 21119 21118 21856 21120 21118 22817 21862 21120 21120 21856 22817 21121 21122 21868 21867 21128 21121 21868 21867 21121 21122 21123 21868 21869 21868 21123 21877 21869 21123 21123 21130 21877 21123 21129 21130 21127 21126 21125 22821 21127 21125 21125 21886 22821 21125 21885 21886 21125 21126 21885 22820 21852 21127 22821 22820 21127 21128 21136 21137 21866 21136 21128 21867 21866 21128 21131 21130 21129 21887 21879 21130 21888 21887 21130 21130 21878 21888 21130 21131 21878 21879 21877 21130 21131 21132 21878 21132 21138 21878 21139 21138 21132 21132 21133 21139 22832 21859 21134 21134 21880 22832 21883 21140 21135 21884 21883 21135 21135 21861 21884 21141 21137 21136 21871 21141 21136 21876 21871 21136 21136 21866 21876 21889 21878 21138 21890 21889 21138 21138 21139 21890 21139 21874 21890 21139 21872 21874 21900 21142 21140 21140 21892 21900 21140 21883 21892 21142 21900 21908 21914 21164 21143 21143 21154 21914 21164 21144 21143 21164 21163 21144 22844 21158 21145 21145 21146 22844 21147 21146 21145 21158 21147 21145 21146 22839 22844 21146 21149 22839 21151 21149 21146 21155 21151 21146 21146 21147 21155 21156 21155 21147 21171 21156 21147 21147 21157 21171 21158 21157 21147 21148 21151 21155 21148 21149 21151 21150 21149 21148 21152 21150 21148 21153 21152 21148 21178 21153 21148 21148 21155 21178 21149 22838 22839 22840 22838 21149 21149 21905 22840 21149 21159 21905 21149 21150 21159 21150 21153 21159 21150 21152 21153 21160 21159 21153 21161 21160 21153 21153 21178 21179 21154 22848 22850 21154 22843 22848 21154 21901 22843 22858 21914 21154 21154 22850 22858 21155 21156 21178 21186 21178 21156 21156 21173 21186 21156 21171 21173 21921 21182 21157 22844 21921 21157 21157 21158 22844 21172 21171 21157 21182 21172 21157 21159 21911 22846 21159 21160 21911 22845 21905 21159 22846 22845 21159 21160 21166 21911 21160 21161 21166 21167 21166 21161 21894 21893 21162 22842 21894 21162 21162 21190 22842 21162 21189 21190 21170 21168 21163 23687 21170 21163 21163 22858 23687 21163 21164 22858 21164 21914 22858 21166 21167 21912 22852 21911 21166 21166 21912 22852 21168 21169 21927 21170 21169 21168 22871 21927 21169 22879 22871 21169 22880 22879 21169 21169 21170 22880 23690 22880 21170 21170 23687 23690 21174 21173 21171 21171 21172 21174 21177 21174 21172 21172 21176 21177 21181 21176 21172 21182 21181 21172 21173 21185 21186 21173 21184 21185 21173 21174 21184 21174 21183 21184 21174 21177 21183 21922 21191 21175 21924 21922 21175 22869 21924 21175 21175 22868 22869 21175 21948 22868 21931 21183 21176 21176 21929 21931 21176 21181 21929 21183 21177 21176 21180 21179 21178 21187 21180 21178 21178 21186 21187 21942 21192 21179 21179 21180 21942 21180 21941 21942 21180 21187 21941 22864 21929 21181 21181 22860 22864 21181 21182 22860 21182 21921 22860 21939 21184 21183 21183 21935 21939 21183 21931 21935 21939 21185 21184 21940 21186 21185 21944 21940 21185 21185 21939 21944 21941 21187 21186 21186 21940 21941 21191 21190 21189 22847 22842 21190 21190 21915 22847 21190 21191 21915 21916 21915 21191 21917 21916 21191 21918 21917 21191 21925 21918 21191 21191 21922 21925 21192 21942 21946 21193 21195 21947 21194 21942 21950 21946 21942 21194 21956 21947 21195 21196 21204 21957 21196 21201 21204 21955 21203 21197 21952 21200 21198 21198 21951 21952 21953 21951 21198 21198 21202 21953 21200 21199 21198 21958 21201 21199 22918 21958 21199 21199 21200 22918 21200 21963 23721 21200 21952 21963 23721 22918 21200 21205 21204 21201 21958 21205 21201 21954 21953 21202 21203 21955 21961 22912 21957 21204 21204 21958 22912 21204 21205 21958 21973 21214 21206 21208 21210 21975 21212 21211 21210 21981 21975 21210 21985 21981 21210 21986 21985 21210 22949 21986 21210 21210 21987 22949 21210 21211 21987 21211 21217 21219 21211 21212 21217 21211 21219 21987 21219 21218 21213 21220 21219 21213 21223 21220 21213 21225 21223 21213 21216 21215 21214 21974 21216 21214 21214 21973 21974 21217 21218 21219 22955 21987 21219 22956 22955 21219 21219 21220 22956 23770 22956 21220 23771 23770 21220 21220 21221 23771 21223 21221 21220 21221 22950 23771 21221 21222 22950 21223 21222 21221 21222 22005 22950 21222 21223 21225 22948 22947 21224 21224 22940 22948 21224 22936 22940 21224 21980 22936 21226 21229 21231 21997 21229 21226 21226 21232 21997 21989 21236 21227 21227 21979 21989 21997 21230 21229 22957 22007 21230 22958 22957 21230 21230 21997 22958 21998 21997 21232 22965 21235 21233 23768 22965 21233 21233 22000 23768 21233 21999 22000 21233 21236 21999 21235 21234 21233 23773 22961 21235 21235 22965 23773 21236 21989 21999 22951 21988 21237 22959 22951 21237 21237 21238 22959 21238 21258 22959 21239 21991 21992 21994 21991 21239 21240 21995 22945 21996 21995 21240 22001 21996 21240 21244 21243 21242 23780 21244 21242 23782 23780 21242 24587 23782 21242 21242 21243 24587 22016 21992 21243 21243 21244 22016 21243 24579 24587 21243 21993 24579 21243 21992 21993 22017 22016 21244 23781 22017 21244 21244 23780 23781 21245 21990 22941 21991 21990 21245 21992 21991 21245 21993 21992 21245 23755 21993 21245 21245 21246 23755 21247 21246 21245 22941 21247 21245 21246 23749 23755 21246 23745 23749 21246 21247 23745 21247 22941 23745 22003 22002 21249 22004 22003 21249 22017 21259 21250 21250 22016 22017 21250 21992 22016 21251 22021 22036 22036 21278 21251 22010 21254 21252 22976 22010 21252 21252 22975 22976 21252 21253 22975 21253 21263 22972 21253 22973 22975 21253 22972 22973 22010 22009 21254 22009 22008 21254 22024 22014 21255 22025 22024 21255 21255 21256 22025 21257 21256 21255 23785 22025 21256 21256 22967 23785 21256 22011 22967 21256 21257 22011 22966 22959 21258 21258 22015 22966 22031 22030 21259 21259 22017 22031 21260 22018 22020 22036 22021 21261 22038 22036 21261 21261 21275 22038 21264 21263 21262 21263 21264 22039 21263 22039 22972 21264 21277 21279 21264 21276 21277 21278 21276 21264 21264 21279 22039 21268 21266 21265 22987 21268 21265 21265 22014 22987 21266 21267 22051 21268 21267 21266 21267 21268 22051 21268 22987 22988 23007 22051 21268 24615 23007 21268 21268 22996 24615 21268 22988 22996 22040 22026 21269 21269 21280 22040 22062 21282 21270 21270 21281 22062 21271 21282 21286 22056 22045 21272 21272 22055 22056 23813 22038 21273 21273 23024 23813 23807 23024 21273 21273 21274 23807 21275 21274 21273 22038 21275 21273 21274 23017 23807 21274 23016 23017 23019 23016 21274 21274 22067 23019 21274 21275 22067 21276 21283 21284 21276 21278 21283 21284 21277 21276 21277 21284 21285 21285 21279 21277 22036 21283 21278 21279 22022 22039 22023 22022 21279 22050 22023 21279 21279 21285 22050 22977 22040 21280 21280 22052 22977 21281 22053 22062 22063 21286 21282 21282 22062 22063 21283 22036 22037 22060 21284 21283 21283 22037 22060 22060 21285 21284 22069 22050 21285 21285 22060 22069 22064 22054 21286 21286 22063 22064 21287 21290 21292 22058 21290 21287 21287 22057 22058 22059 22057 21287 22070 22067 21288 21288 21296 22070 21291 21290 21289 21301 21291 21289 22078 21301 21289 23021 22078 21289 21289 22066 23021 21289 21290 22066 21294 21292 21290 21290 21291 21294 21290 22058 22066 21302 21294 21291 21291 21301 21302 21292 21294 21295 21293 21310 21311 21293 21304 21310 21293 21302 21304 21293 21294 21302 22080 21312 21293 21293 21311 22080 22071 22070 21296 21296 21297 22071 22083 22071 21297 24634 23026 21298 24641 24634 21298 24642 24641 21298 21298 23824 24642 21298 23819 23824 21298 21299 23819 21300 21299 21298 23026 21300 21298 21299 22077 22078 21299 21308 22077 21299 21305 21308 21299 21300 21305 21299 22078 23819 23034 23033 21300 21300 23026 23034 21307 21305 21300 21322 21307 21300 23033 21322 21300 21303 21302 21301 21308 21303 21301 22077 21308 21301 22078 22077 21301 21302 21303 21304 21308 21307 21303 21309 21304 21303 21303 21307 21309 21304 21309 21310 21305 21306 21308 21307 21306 21305 21306 21307 21308 22098 21309 21307 21329 21310 21309 22098 21329 21309 21310 21329 22097 22097 21311 21310 22099 22080 21311 21311 22097 22099 22099 21318 21312 21312 22080 22099 21314 21315 22089 22089 22087 21314 21315 21316 22089 21316 21317 22089 23038 22089 21317 21317 22091 23038 22099 22097 21318 22093 22090 21319 21319 21320 22093 22094 22093 21320 21320 21321 22094 22095 22094 21321 22096 22095 21321 23032 22096 21321 23033 23032 21321 21321 21322 23033 21338 21332 21324 21339 21338 21324 21324 21325 21339 21348 21339 21325 23053 23045 21326 23054 23053 21326 23045 21327 21326 23045 21340 21327 21330 21329 21328 21331 21332 21333 21335 21333 21332 21338 21335 21332 21335 21334 21333 23052 21337 21334 23058 23052 21334 21334 22100 23058 21334 21335 22100 21335 21338 22100 23043 22081 21336 21336 21337 23043 23052 23043 21337 23058 22100 21338 23059 23058 21338 21338 22108 23059 21338 21339 22108 21339 21348 22108 23045 21341 21340 23061 22123 21341 21341 23053 23061 21341 23045 23053 22112 22109 21342 21342 21346 22112 21342 21343 21346 21344 21343 21342 22109 21344 21342 21350 21346 21343 23056 21350 21343 21343 22105 23056 21343 21344 22105 21344 22104 22105 22109 22104 21344 21345 21352 21360 21345 21351 21352 22107 21351 21345 21345 21350 22107 21345 21346 21350 21347 21346 21345 21360 21347 21345 21346 21347 22112 21347 22111 22112 21347 21360 22111 22117 22108 21348 22118 22117 21348 22121 22118 21348 21348 21349 22121 21349 21359 22121 23850 22107 21350 21350 23057 23850 21350 23056 23057 22113 21354 21351 22115 22113 21351 21351 22107 22115 21353 21352 21351 21354 21353 21351 21367 21360 21352 21369 21367 21352 21352 21368 21369 21352 21355 21368 21352 21353 21355 21353 21354 21355 23066 22116 21354 21354 22114 23066 21354 22113 22114 22116 21355 21354 21372 21368 21355 22120 21372 21355 21355 22116 22120 22127 21359 21356 21356 21357 22127 21358 21357 21356 21371 21358 21356 21356 21359 21361 21357 22143 23090 21357 22138 22143 22128 22127 21357 23090 22128 21357 21359 22127 22128 23074 22121 21359 23077 23074 21359 21359 22128 23077 21360 21367 22111 21362 21364 21365 21362 21363 21364 22129 21364 21363 21366 21365 21364 22139 21366 21364 22140 22139 21364 21364 22129 22140 21377 21373 21366 22139 21377 21366 22125 22111 21367 22141 22125 21367 21367 22133 22141 21367 21369 22133 21370 21369 21368 21372 21370 21368 22142 22133 21369 21369 22134 22142 21369 21370 22134 21370 21372 22134 22135 22134 21372 22137 22135 21372 21372 22120 22137 21376 21374 21373 21377 21376 21373 21376 21375 21374 21383 21382 21375 21375 21376 21383 22149 21383 21376 21376 21377 22149 21377 22140 22149 21377 22139 22140 21379 21383 22150 21379 21382 21383 21379 21380 21382 21381 21380 21379 22150 21381 21379 21380 21388 21389 21380 21381 21388 21381 21387 21388 22173 21387 21381 23100 22173 21381 21381 22160 23100 21381 22150 22160 21383 22149 22150 22172 22162 21385 23108 22172 21385 21385 22161 23108 21385 21386 22161 22170 22161 21386 21389 21388 21387 21392 21389 21387 22173 21392 21387 22178 22171 21390 21390 21396 22178 22180 22165 21391 22181 21395 21392 23111 22181 21392 23906 23111 21392 21392 22173 23906 23142 22198 21394 21394 23136 23142 22179 22178 21396 23134 22179 21396 21396 21397 23134 21397 23155 23157 21397 22205 23155 21397 22194 23134 22195 22194 21397 23157 22195 21397 21404 21403 21398 21421 21404 21398 21431 21421 21398 22206 21431 21398 21398 21399 22206 21399 22198 22206 21418 21409 21400 23144 21418 21400 21400 23137 23144 21400 21401 23137 21401 23130 23137 21401 22196 23130 23154 22205 21402 21402 21410 23154 22224 21412 21403 21403 21404 22224 21404 21421 22233 22226 22224 21404 23170 22226 21404 21404 22233 23170 23121 22180 21405 23128 23121 21405 23915 23128 21405 21405 23143 23915 21405 21406 23143 21406 22207 23143 21406 21408 22207 21406 21407 21408 22227 22207 21408 21409 21418 22231 23159 23154 21410 23160 23159 21410 21410 21411 22223 21411 21412 22223 21412 22224 22225 22225 22223 21412 21413 21414 21416 21415 21414 21413 22208 21415 21413 21413 21417 22208 23174 21416 21414 23179 23174 21414 23937 23179 21414 21414 21415 23937 21415 22208 22229 21415 23173 23937 21415 22228 23173 22229 22228 21415 21417 21422 22208 22234 22231 21418 23149 22234 21418 21418 23144 23149 22233 21421 21419 21420 23161 23176 21420 21444 23161 21420 21421 21444 21421 21431 21444 21422 21423 23167 22230 22208 21422 23167 22230 21422 21423 22240 23167 21424 21434 21435 21437 21434 21424 21424 21427 21437 21429 21427 21424 21424 21425 21429 21426 21425 21424 21435 21426 21424 22235 21429 21425 22244 22235 21425 21425 21446 22244 21425 21426 21446 21426 21435 21446 22217 21437 21427 21427 22215 22217 21427 21428 22215 21429 21428 21427 21428 22214 22215 22216 22214 21428 21428 21429 22216 21429 22211 22216 22235 22211 21429 21430 22195 22204 22237 22195 21430 22206 21444 21431 21432 21448 21452 22248 21433 21432 21432 21452 22248 23965 23951 21433 21433 22248 23965 21434 21436 21438 21437 21436 21434 21438 21435 21434 21435 21439 21446 21435 21438 21439 22232 21438 21436 22236 22232 21436 21436 22220 22236 21436 21437 22220 21437 22218 22220 21437 22217 22218 22256 21439 21438 21438 22232 22256 23189 21446 21439 23973 23189 21439 21439 23194 23973 21439 22256 23194 22246 22237 21440 22257 22246 21440 21440 21451 22257 22247 22233 21441 21441 21442 22247 23170 22247 21442 21442 22225 23170 21442 22223 22225 23162 23161 21444 21444 23142 23162 21444 22198 23142 22206 22198 21444 22253 21456 21445 21445 22242 22253 21445 22210 22242 21445 21450 22210 22254 22244 21446 23971 22254 21446 21446 23189 23971 21447 22249 22261 22250 22249 21447 23176 22250 21447 22252 22240 21449 22231 22210 21450 22258 22257 21451 21451 21457 22258 22251 22248 21452 22262 22251 21452 21453 21455 22267 21453 21454 21455 22267 22265 21453 23186 22267 21455 21455 21456 23186 21456 22253 23186 22260 22258 21457 21457 22259 22260 22277 21459 21458 21458 22261 22277 22287 21460 21459 23201 22287 21459 21459 22277 23201 22286 21464 21460 22287 22286 21460 22278 22262 21461 21461 21465 22278 23216 22298 21462 22294 22293 21463 22306 22294 21463 21467 21466 21464 22286 21467 21464 22295 22278 21465 21465 21492 22295 21477 21475 21466 21466 21467 21477 22307 21477 21467 23206 22307 21467 21467 22286 23206 23220 21469 21468 23224 23220 21468 22299 21470 21469 23220 22299 21469 22300 21471 21470 21470 22299 22300 22300 21472 21471 22302 21478 21472 21472 22301 22302 21472 22300 22301 23230 21481 21473 21473 22314 23230 23227 22345 21474 21474 21475 23227 21476 21475 21474 23232 21476 21474 23233 23232 21474 23234 23233 21474 21474 22346 23234 21474 22345 22346 21475 21483 23227 21475 21477 21483 23232 21488 21476 22307 21483 21477 21485 21479 21478 22302 21485 21478 21486 21484 21479 21479 21485 21486 22325 22306 21480 21480 22324 22325 21480 21481 22324 23230 22324 21481 23228 23227 21483 21483 22307 23228 21487 21486 21485 23999 21487 21485 24010 23999 21485 21485 23225 24010 21485 22302 23225 23247 22337 21486 21486 21487 23247 24802 23247 21487 21487 24793 24802 21487 23999 24793 21488 22377 23254 21488 22376 22377 23231 22376 21488 23232 23231 21488 22359 22358 21489 21489 21495 22359 21489 21490 21495 21493 21492 21491 22318 21493 21491 21492 21493 22295 23214 22295 21493 23236 23214 21493 21493 22318 23236 22361 22359 21495 21495 21520 22361 21495 21509 21520 21495 21500 21509 22372 22371 21496 22373 22372 21496 22374 22373 21496 22375 22374 21496 21496 21497 22375 21497 21498 22375 23261 22386 21499 21499 22378 23261 21501 22347 22348 21501 22328 22347 21501 22327 22328 21501 21502 22327 22330 22327 21502 21502 21503 22330 21503 22329 22330 22332 22329 21503 21503 21504 22332 22334 22332 21504 21504 21513 22334 21504 21505 21513 21514 21513 21505 22366 22352 21506 23271 21518 21507 21507 22385 23271 21507 21517 22385 21520 21509 21508 21521 21520 21508 21508 21510 21521 22399 21521 21510 22400 22399 21510 21510 21511 22400 21512 21511 21510 22403 22400 21511 21513 21514 22334 22349 22334 21514 21514 21515 22349 22352 22349 21515 22387 21517 21516 22391 22387 21516 21516 21523 22391 21517 22368 22385 22369 22368 21517 22387 22369 21517 23271 21524 21518 22360 21520 21519 21520 22360 22361 22382 21528 21522 22383 22382 21522 21522 22364 22383 22384 22364 21522 21522 22348 22384 22401 22391 21523 21524 22372 22392 21524 22370 22372 23271 22370 21524 23286 22405 21525 21525 21529 23286 21525 21528 21529 21526 22388 22394 22389 22388 21526 22396 22389 21526 21526 21527 22396 23276 22396 21527 21527 22397 23276 22382 21529 21528 23287 23286 21529 24031 23287 21529 21529 23272 24031 21529 22382 23272 21530 21531 22405 21532 21531 21530 23291 21532 21530 24034 23291 21530 21530 23283 24034 23284 23283 21530 23287 23284 21530 21530 23286 23287 21530 22405 23286 21531 21532 22420 22428 22420 21532 23291 22428 21532 23277 22395 21533 21533 22398 23277 21533 21534 22398 22395 21536 21533 21534 21535 22392 21534 22393 22398 21534 22392 22393 21536 22395 22407 22402 21547 21538 22406 22401 21539 21540 22415 23288 22411 22410 21541 21541 21552 22411 21541 21542 21552 21542 21551 21552 21543 21544 23293 21545 21544 21543 22421 21545 21543 23294 22421 21543 21543 21555 23294 24838 23293 21544 24845 24838 21544 21544 21545 24845 24856 24845 21545 21545 24042 24856 21545 22421 24042 21546 22408 22423 22423 21556 21546 22402 21548 21547 21548 22417 22418 21548 22402 22417 21554 21550 21549 21550 21568 22431 21550 21554 21568 22431 21551 21550 21553 21552 21551 22426 21553 21551 21552 21553 22411 21553 21569 22411 22426 21569 21553 23295 23294 21555 23296 23295 21555 21555 22422 23296 21555 21559 22422 21571 21559 21555 21567 21566 21557 22419 21567 21557 22425 22419 21557 21571 21561 21559 24038 22422 21559 21559 21560 24038 21561 21560 21559 24043 24038 21560 21560 23297 24043 21560 21561 23297 23301 23297 21561 21561 22429 23301 22430 21574 21562 21562 22424 22430 21562 21563 22424 21564 21563 21562 22423 21564 21562 21563 21564 22432 23292 22432 21564 21564 22423 23292 22419 21569 21567 21568 21570 22431 22419 22411 21569 21572 21574 22430 22436 22429 21573 22439 22436 21573 21575 21576 22437 23302 22438 21575 23303 23302 21575 23304 23303 21575 21575 22437 23304 21576 21578 22437 21587 21578 21577 21578 21587 22437 22433 21580 21579 22434 22433 21579 22433 21583 21580 21583 21581 21580 21581 21582 22441 21583 21582 21581 22440 21586 21581 22441 22440 21581 25628 22441 21582 21582 24877 25628 21582 21583 24877 21583 23305 24874 21583 22433 23305 21583 24874 24877 23318 22442 21584 24065 23318 21584 21584 24061 24065 21584 22438 24061 22440 21591 21585 21585 21586 22440 21587 21589 22437 21588 22453 24073 21588 21598 22453 22445 21589 21588 23320 22445 21588 24073 23320 21588 24062 22437 21589 21589 22444 24062 22445 22444 21589 23325 22446 21590 21590 21592 23325 21593 21592 21590 21590 21591 21593 22440 21593 21591 24070 23325 21592 21592 23314 24070 23315 23314 21592 23316 23315 21592 21592 21593 23316 21593 22440 23316 21594 23306 23307 23308 23306 21595 23310 23308 21595 21595 21596 23310 21597 21596 21595 23313 23310 21596 21596 22443 23313 21596 21597 22443 22447 22443 21597 21597 21599 22447 23326 22447 21599 21599 22451 23326 21599 21600 22451 22452 22451 21600 22455 22452 21600 22454 22453 21601 21601 22446 22454 22456 22455 21602 22460 22456 21602 21604 22461 22465 21605 21609 22460 21605 21606 21609 21607 21606 21605 23332 21607 21605 23331 21609 21606 24084 23331 21606 21606 21607 24084 21607 23332 24084 22465 22464 21608 21609 22456 22460 23331 22456 21609 22472 21615 21610 21610 21614 22472 21610 21613 21614 23335 21613 21610 21615 21611 21610 21612 23341 23347 21612 22473 23341 23335 22467 21613 22467 21614 21613 21614 22471 22472 21614 22466 22471 22467 22466 21614 21618 21616 21615 22472 21618 21615 21619 21617 21616 21616 21618 21619 21621 21620 21617 21617 21619 21621 22468 21619 21618 22472 22468 21618 22474 21621 21619 21619 22469 22474 21619 22468 22469 21620 21622 21623 21620 21621 21622 22477 21622 21621 21621 22474 22477 21628 21623 21622 22479 21628 21622 21622 22477 22479 21624 21625 21627 21626 21625 21624 22510 21627 21625 21627 23357 23358 24107 23357 21627 21627 22510 24107 21627 23358 23359 21628 22479 22492 21629 22499 22509 22500 22499 21629 23365 23364 21630 21630 23358 23365 23359 23358 21630 21631 22517 22518 22523 22517 21631 22524 22523 21631 21632 22492 22513 22527 22524 21633 21633 21643 22527 21644 21643 21633 21635 22525 22528 22521 21637 21636 22526 22521 21636 21636 22520 22526 21636 22519 22520 22528 22519 21636 21637 22521 22522 22530 22529 21638 23374 22530 21638 21641 21640 21639 21640 21641 22536 21641 21642 22536 21642 22529 23368 22540 22536 21642 23370 22540 21642 21642 23368 23370 22531 22527 21643 21643 21644 22531 23369 22531 21644 21647 21646 21645 21650 21647 21645 23376 23375 21646 24119 23376 21646 21646 21647 24119 24131 24119 21647 24142 24131 21647 24956 24142 21647 21647 22547 24956 21647 21660 22547 21647 21650 21660 22534 21649 21648 22539 22534 21648 21648 21652 22539 21661 21660 21650 21651 21657 21658 21652 21654 22539 21652 21653 21654 22541 22539 21654 22535 21659 21655 21656 21657 22545 21658 21657 21656 21656 22545 22548 21657 22536 22545 21659 23380 23381 21659 22535 23380 21660 21681 22547 21664 21663 21662 22555 21664 21662 21662 21679 22555 21663 21664 22541 21664 22538 22541 21664 22537 22538 22550 22537 21664 23385 22550 21664 21664 22555 23385 22559 21670 21665 21665 22552 22559 21665 22548 22552 21666 21667 21680 21668 21667 21666 22562 21668 21666 23408 22562 21666 21666 23398 23408 21666 21680 23398 22565 21684 21668 23427 22565 21668 21668 22562 23427 22558 21686 21670 22559 22558 21670 21678 21673 21671 23396 21675 21672 21672 23395 23396 21672 21673 23395 24149 23395 21673 24162 24149 21673 21673 21678 24162 21674 21675 23394 23396 23394 21675 21676 22556 22557 21676 22542 22556 22557 21680 21676 24184 24162 21678 23386 22555 21679 23397 23386 21679 21680 22557 23398 21681 21682 22554 22554 22547 21681 24151 22554 21682 21682 22560 24151 22564 21688 21683 21683 21684 22564 22565 22564 21684 21685 21688 22566 21686 23402 23410 21686 22558 23402 22563 21687 21686 23410 22563 21686 23414 22570 21687 23428 23414 21687 21687 22563 23428 21688 22564 22566 21691 21690 21689 22567 21691 21689 24182 23424 21690 21690 21691 24182 24189 24182 21691 24190 24189 21691 21691 22567 24190 22611 22602 21692 21692 21698 22611 22574 22568 21693 21693 22569 22574 21693 21694 22569 21697 21696 21695 22573 22571 21696 22581 22573 21696 21696 21697 22581 21697 21708 22581 21697 21700 21708 21698 21699 22610 21698 22610 22611 21699 22595 22610 21700 21709 21711 22593 21708 21700 21700 21711 22593 21703 21702 21701 22586 21703 21701 21701 22585 22586 22590 21706 21702 24210 22590 21702 21702 21703 24210 21703 23454 24210 21703 22586 23454 21704 21705 21710 21706 21705 21704 21705 21706 22590 21712 21710 21705 22590 21712 21705 23437 22581 21708 21708 22591 23437 22593 22591 21708 22606 21711 21709 21710 21712 23455 23450 22593 21711 23452 23450 21711 21711 22606 23452 23464 23455 21712 24214 23464 21712 24215 24214 21712 21712 22590 24215 21713 21714 21716 21715 21714 21713 22613 21715 21713 22597 22596 21714 21714 21715 22597 23465 22597 21715 21715 22613 23465 22630 22629 21718 22631 22630 21718 22641 22640 21720 22646 21724 21722 21722 21723 22646 23501 22662 21724 21724 22651 23501 21724 22647 22651 21724 22646 22647 21725 22657 22664 22658 22657 21725 21726 21727 22658 21727 21728 22659 22660 22658 21727 21727 22659 22660 21729 22669 23500 21748 21742 21730 23513 21748 21730 21730 21731 23513 21742 21737 21730 21731 22665 23513 21731 22662 22665 21732 21733 22683 21733 21743 22683 22674 21738 21734 22661 22659 21735 21735 21736 22661 24257 22661 21736 24258 24257 21736 24270 24258 21736 21736 23520 24270 21736 22672 23520 22674 21745 21738 21739 21745 22679 22679 21740 21739 22691 22689 21740 24282 22691 21740 21740 23533 24282 21740 22679 23533 23520 22672 21741 21741 22675 23520 21749 21744 21742 21742 21748 21749 23528 22683 21743 23537 23528 21743 21743 22684 23537 21744 21749 21750 21745 22674 22681 22681 22679 21745 21746 21748 22684 21746 21747 21748 21749 21748 21747 21750 21749 21747 23522 22684 21748 21748 23513 23522 22704 22695 21751 21751 21752 22704 21752 22703 22704 24298 22710 21753 21753 22709 24298 21753 22706 22709 22710 21754 21753 22723 22717 21754 21754 22710 22723 21755 21757 21759 23568 21758 21756 23571 23568 21756 21758 21757 21756 21757 21758 21759 22715 21759 21758 23559 22715 21758 23568 23559 21758 21759 22714 22716 22715 22714 21759 21763 21762 21760 22730 21763 21760 23569 22730 21760 21760 23560 23569 21760 21761 23560 23562 23560 21761 24303 23562 21761 21761 23563 24303 23564 23563 21761 21761 22728 23564 21761 22722 22728 21761 22717 22722 23577 22731 21762 21762 23575 23577 21762 22729 23575 21762 21763 22729 22730 22729 21763 24324 23571 21764 25174 24324 21764 21764 24367 25174 21764 23606 24367 21764 21783 23606 21765 21766 23580 22733 21767 21765 23580 22733 21765 21766 22732 23580 21769 21768 21767 21771 21769 21767 22733 21771 21767 21768 21769 21770 21776 21770 21769 21769 21774 21776 21769 21771 21774 21771 21772 21774 21773 21772 21771 22733 21773 21771 21777 21774 21772 21780 21777 21772 22735 21780 21772 21772 21775 22735 21772 21773 21775 22734 21775 21773 21773 22733 22734 21777 21776 21774 22736 22735 21775 21775 22734 22736 21776 21777 21778 21779 21778 21777 21780 21779 21777 21778 21779 21781 23599 21781 21779 21779 22735 23599 21779 21780 22735 22743 22740 21781 23609 22743 21781 21781 23599 23609 21782 22741 23610 22743 22741 21782 21782 22740 22743 21782 23610 23611 21783 21786 23606 21783 21784 21786 21784 21785 21786 22746 21786 21785 21785 21793 22746 21786 22746 23606 21792 21791 21787 21790 21789 21788 22761 21790 21788 21788 22749 22761 23616 22749 21788 24376 23616 21788 25203 24376 21788 25977 25203 21788 26758 25977 21788 21788 25993 26758 21788 23629 25993 21788 22774 23629 21788 21789 22774 22775 22774 21789 21789 21829 22775 22761 21802 21790 22753 21803 21791 23613 22753 21791 21791 22748 23613 21791 21792 22748 21792 22747 22748 21793 21799 22746 23617 21796 21794 21794 23614 23617 21794 22756 23614 21794 21795 22756 21796 21795 21794 21795 21796 21798 21795 21797 22756 21799 21798 21796 23617 21799 21796 21797 21800 22756 23618 22746 21799 21799 23617 23618 23614 22756 21800 21800 22754 23614 22755 22754 21800 22757 22755 21800 21807 21806 21803 21808 21807 21803 22753 21808 21803 22762 22757 21804 21804 21817 22762 21804 21809 21817 22781 21816 21806 23625 22781 21806 21806 22765 23625 21806 21807 22765 24379 22765 21807 21807 24377 24379 21807 23619 24377 23623 23619 21807 21807 21808 23623 21808 22753 23623 22766 21817 21809 21809 21818 22766 21810 21811 21820 21812 21811 21810 22767 21820 21811 21811 21812 22767 22768 22767 21812 22780 21838 21814 21814 22779 22780 21814 21816 22779 22781 22779 21816 23622 22762 21817 21817 22766 23622 22769 22766 21818 21818 21819 22769 22770 22769 21819 21819 21827 22770 22767 21822 21820 21821 21823 21828 21821 21822 21823 21821 21824 21825 22786 21824 21821 21821 21828 22786 22768 21823 21822 21822 22767 22768 21823 22772 22778 21823 22771 22772 21823 22768 22771 22778 21828 21823 21835 21827 21826 21843 21835 21826 22785 22770 21827 21827 21835 22785 23638 22786 21828 21828 22791 23638 21828 22778 22791 21829 21830 22775 22796 22775 21830 22797 22796 21830 21830 21836 22797 21831 21837 21838 21833 21832 21831 22780 21833 21831 21831 21838 22780 22783 22782 21832 21832 21834 22783 21832 21833 21834 21833 22779 22781 22780 22779 21833 23631 21834 21833 21833 23630 23631 21833 22765 23630 23625 22765 21833 21833 22781 23625 23631 22783 21834 21835 21839 22785 21840 21839 21835 21843 21840 21835 23645 22797 21836 21836 21849 23645 23635 22785 21839 21839 21847 23635 21839 21840 21847 22805 21842 21841 21841 22799 22805 21841 22789 22799 22805 21855 21842 21854 21846 21844 22804 21854 21844 21844 22803 22804 21846 21845 21844 21845 21846 21848 21854 21848 21846 21847 22800 23635 21847 21850 22800 21848 21853 21873 21854 21853 21848 24402 23645 21849 24403 24402 21849 21849 23647 24403 21850 21851 22800 22802 22800 21851 23649 22802 21851 21851 21852 23649 23654 23649 21852 21852 22820 23654 22809 21873 21853 21853 22808 22809 21853 21854 22808 21854 22804 22808 21855 22807 22812 21855 22805 22807 22810 21860 21855 22812 22810 21855 22819 22817 21856 21856 22818 22819 21856 21875 22818 21856 21857 21875 21857 21860 21875 21858 22824 23650 21858 21859 22824 22832 22824 21859 22826 21875 21860 21860 22825 22826 21860 22813 22825 21860 22810 22813 21861 21864 21884 21861 21863 21864 21861 21862 21863 22831 21863 21862 21862 22819 22831 21862 22817 22819 21865 21864 21863 24417 21865 21863 21863 22831 24417 21864 21883 21884 22841 21883 21864 21864 22833 22841 21864 21865 22833 24417 22833 21865 22822 21876 21866 21866 21867 22822 21867 21868 22822 21868 21869 22822 21871 21870 21869 21869 21870 22822 21870 21871 21876 21870 21876 22822 22814 21874 21872 21872 21873 22814 22815 22814 21873 21873 22809 22815 23663 21890 21874 21874 23660 23663 21874 23659 23660 21874 22823 23659 21874 22814 22823 22826 22818 21875 21877 21879 21895 21889 21888 21878 22848 22843 21879 21879 21887 22848 22843 21895 21879 21880 21881 22832 21882 21881 21880 21881 21899 22832 21881 21891 21899 21881 21882 21891 22841 21892 21883 21893 21886 21885 22834 22821 21886 21886 21894 22834 21886 21893 21894 21887 21902 21904 21887 21888 21902 21887 21903 22848 21904 21903 21887 21888 21896 21902 21888 21889 21896 21897 21896 21889 21889 21890 21897 23663 21897 21890 21891 21898 21899 22841 21900 21892 23667 22834 21894 21894 22842 23667 22843 21901 21895 22849 21902 21896 21896 21897 22849 23665 22849 21897 21897 23662 23665 23663 23662 21897 22835 21899 21898 21898 21910 22835 22835 22832 21899 21909 21908 21900 22857 21909 21900 21900 22841 22857 22849 21904 21902 22850 22848 21903 23679 22850 21903 23688 23679 21903 24443 23688 21903 21903 21904 24443 21904 22849 24443 21905 21906 22840 21907 21906 21905 22845 21907 21905 23666 22840 21906 24440 23666 21906 21906 21907 24440 21907 23675 24440 21907 22853 23675 21907 22846 22853 21907 22845 22846 21913 21912 21908 21908 21909 21913 22856 21913 21909 22857 22856 21909 23668 22835 21910 23672 23668 21910 21910 22851 23672 22852 22846 21911 21912 21913 22856 22853 22852 21912 22856 22853 21912 23677 22847 21915 21915 21916 23677 23685 23677 21916 23686 23685 21916 21916 21919 23686 21916 21917 21919 21920 21919 21917 21917 21918 21920 21926 21920 21918 21918 21925 21926 21919 22862 23686 21919 22861 22862 22870 22861 21919 21919 21926 22870 21919 21920 21926 23674 22860 21921 21921 23673 23674 21921 22844 23673 21922 21923 21925 21924 21923 21922 21926 21925 21923 22870 21926 21923 21923 22869 22870 21923 21924 22869 21927 22871 22872 22873 21930 21927 21927 22872 22873 22863 22859 21928 21928 21930 22863 21933 21931 21929 22864 21933 21929 22873 22863 21930 21931 21934 21935 21931 21933 21934 22884 21949 21932 21932 21933 22884 21934 21933 21932 21949 21934 21932 24507 22884 21933 21933 22865 24507 22867 22865 21933 21933 22864 22867 21936 21935 21934 21938 21936 21934 21949 21938 21934 21935 21936 21943 21943 21939 21935 22894 21943 21936 21936 22891 22894 21936 21937 22891 21938 21937 21936 21937 21949 22891 21937 21938 21949 21939 21943 21944 22896 21941 21940 21940 21945 22896 21940 21944 21945 21950 21942 21941 22896 21950 21941 21943 22894 22895 22895 21944 21943 22895 21945 21944 23715 22896 21945 23716 23715 21945 21945 22895 23716 23704 22917 21947 23705 23704 21947 23706 23705 21947 21947 21957 23706 21947 21956 21957 23694 22868 21948 21948 22916 23694 21949 22903 23713 22907 22903 21949 21949 22906 22907 21949 22882 22906 22883 22882 21949 22884 22883 21949 22893 22891 21949 23713 22893 21949 23717 21955 21950 21950 22896 23717 22901 21952 21951 22902 22901 21951 21951 21954 22902 21951 21953 21954 22898 21963 21952 21952 22897 22898 22901 22897 21952 22913 22902 21954 22914 22913 21954 22920 22914 21954 21954 22919 22920 21954 21964 22919 21962 21961 21955 23720 21962 21955 21955 23717 23720 21957 22909 23706 22911 22909 21957 22912 22911 21957 22918 22912 21958 22919 21964 21959 21960 21967 21968 22928 21970 21961 22929 22928 21961 21961 21962 22929 22932 22929 21962 23720 22932 21962 23723 23721 21963 21963 23708 23723 21963 22898 23708 21974 21973 21966 21966 21971 21974 21966 21968 21971 21972 21968 21967 21967 21969 21972 21978 21971 21968 21968 21972 21978 21969 21970 21972 22928 22927 21970 22927 21972 21970 21978 21974 21971 22936 21980 21972 21972 22930 22936 21972 22927 22930 21972 21974 21978 21980 21974 21972 21975 21976 21984 21977 21976 21975 21981 21977 21975 22925 21984 21976 22934 22925 21976 21976 22933 22934 21976 21977 22933 22935 22933 21977 21977 21982 22935 21977 21981 21982 21999 21989 21979 21979 21988 21999 21983 21982 21981 21985 21983 21981 23747 22935 21982 23754 23747 21982 21982 21983 23754 21983 21985 23754 21985 21986 23754 24566 23754 21986 21986 23769 24566 21986 22949 23769 22953 22952 21987 22955 22953 21987 22952 22949 21987 22951 21999 21988 22942 22941 21990 21990 21994 22942 21990 21991 21994 21993 23755 24579 22943 22942 21994 22944 22943 21994 22945 22944 21994 21995 22944 22945 23750 22944 21995 23752 23750 21995 21995 21996 23752 23757 23752 21996 23758 23757 21996 21996 22946 23758 22964 22958 21997 22968 22964 21997 21997 21998 22968 22951 22000 21999 22000 23766 23768 22000 23765 23766 22000 22951 23765 23759 22946 22002 23760 23759 22002 22002 22003 23760 23763 23760 22003 22003 22947 23763 22003 22004 22947 22005 22006 22950 22007 22006 22005 23772 22950 22006 22006 22007 23772 24583 23772 22007 22007 22957 24583 22008 22009 22011 22009 22010 22013 22013 22011 22009 22976 22013 22010 22011 22012 22967 22013 22012 22011 24601 22967 22012 22012 22013 24601 22013 22976 23776 22013 24600 24601 22013 23776 24600 22014 22982 22987 22014 22024 22982 22015 22028 22966 22015 22027 22028 22029 22027 22015 23781 22031 22017 22971 22020 22018 22018 22019 22971 23793 22971 22019 23794 23793 22019 22019 22035 23794 22971 22046 22020 22981 22039 22022 22022 22023 22981 22023 22061 22981 22023 22048 22061 22049 22048 22023 22050 22049 22023 22983 22982 22024 22024 22025 22983 23785 22983 22025 22989 22969 22026 23787 22989 22026 22026 22040 23787 22027 22029 22041 22970 22966 22028 22028 22969 22970 23784 22044 22030 22030 23783 23784 22030 22031 23783 22044 22032 22030 22031 23781 23783 22978 22034 22033 22990 22978 22033 25388 23794 22035 26143 25388 22035 22035 23791 26143 22038 22037 22036 22037 22038 22060 23813 22060 22038 22981 22972 22039 22040 23786 23787 22040 22977 23786 22063 22053 22042 23000 22063 22042 23789 23000 22042 22042 22043 23789 22044 22043 22042 23790 23789 22043 24607 23790 22043 22043 22997 24607 22999 22997 22043 22043 22044 22999 23784 22999 22044 23002 22990 22045 22045 23001 23002 22045 22056 23001 22993 22047 22046 22046 22980 22993 22046 22979 22980 22046 22971 22979 23005 22059 22047 22047 22993 23005 23006 22061 22048 22048 22068 23006 22048 22049 22068 22049 22050 22068 22073 22068 22050 22050 22072 22073 22050 22069 22072 23007 22052 22051 23007 22977 22052 22063 22062 22053 22054 22064 23008 23801 23010 22054 22054 23008 23801 22065 22056 22055 23009 22065 22055 23013 23001 22056 22056 23009 23013 22056 22065 23009 22057 22059 23005 22066 22058 22057 23015 22066 22057 22057 23005 23015 23813 22069 22060 23810 22981 22061 22061 23809 23810 22061 23006 23809 23008 22064 22063 22063 23000 23008 22066 23014 23021 23015 23014 22066 22067 22070 23019 22068 22073 22079 23020 23006 22068 22068 22079 23020 23813 22072 22069 22070 22071 22083 22070 23016 23019 23018 23016 22070 24627 23018 22070 25406 24627 22070 25408 25406 22070 22070 22084 25408 22070 22083 22084 23027 22073 22072 22072 23023 23027 23024 23023 22072 23813 23024 22072 23028 22076 22073 22073 23027 23028 22073 22076 22079 23020 22079 22074 23025 23020 22074 22074 22075 23025 22076 22075 22074 22079 22076 22074 23821 23025 22075 22075 23029 23821 22075 22076 23029 22076 23028 23037 23037 23029 22076 22078 23022 23819 22078 23021 23022 22081 22082 22083 23040 22082 22081 23041 23040 22081 23043 23041 22081 22084 22083 22082 23035 22084 22082 23040 23035 22082 26977 25408 22084 22084 25418 26977 22084 23839 25418 22084 23035 23839 22085 22088 23042 22085 22086 22088 22087 22086 22085 23846 22088 22086 22086 23049 23846 22086 23038 23049 22086 22089 23038 22086 22087 22089 23046 23042 22088 23846 23046 22088 22092 22091 22090 23039 22092 22090 22090 22093 23039 22091 22092 23038 23837 23038 22092 22092 23039 23837 22093 22095 23039 22093 22094 22095 23830 23039 22095 23831 23830 22095 22095 22096 23831 23832 23831 22096 22096 23032 23832 22103 22102 22101 23063 22103 22101 22101 22119 23063 22101 22104 22119 22101 22102 22104 23055 23042 22102 22102 22103 23055 22106 22104 22102 23046 22106 22102 22102 23042 23046 23063 23055 22103 22104 22109 22119 22106 22105 22104 22105 23050 23056 22105 22106 23050 22106 23047 23050 22106 23046 23047 23850 22115 22107 23860 23059 22108 22108 22117 23860 22112 22110 22109 22124 22119 22109 22109 22110 22124 22110 22111 22126 22112 22111 22110 23070 22124 22110 23071 23070 22110 22110 22126 23071 22111 22125 22126 22115 22114 22113 22114 23065 23066 22114 23064 23065 22114 22115 23064 23856 23064 22115 22115 23850 23856 23073 22120 22116 22116 23072 23073 22116 23066 23072 23867 23860 22117 22117 22118 23867 22118 23067 23867 22118 22121 23067 22119 22124 23063 23084 22137 22120 22120 23073 23084 23074 23067 22121 23079 22129 22122 23080 23079 22122 22122 22123 23080 22123 23060 23080 23061 23060 22123 22124 23062 23063 23861 23062 22124 22124 23081 23861 23082 23081 22124 22124 23070 23082 22125 22141 23083 23083 22126 22125 22126 23068 23071 23069 23068 22126 23083 23069 22126 23090 23077 22128 22145 22140 22129 23079 22145 22129 22132 22131 22130 22151 22132 22130 22169 22151 22130 22174 22169 22130 22177 22174 22130 23103 22177 22130 22130 22157 23103 22130 22131 22157 22131 22147 23087 22131 22132 22147 22131 22154 22157 23087 22154 22131 22132 22134 22147 22142 22134 22132 22151 22142 22132 22146 22141 22133 22133 22142 22146 22134 22136 22147 22134 22135 22136 23087 22136 22135 23094 23087 22135 22135 23085 23094 22135 22137 23085 23087 22147 22136 22137 23084 23085 22148 22143 22138 22155 22148 22138 22140 22144 22149 22145 22144 22140 23091 23086 22141 22141 22146 23091 23086 23083 22141 22151 22146 22142 22143 23088 23089 22143 22156 23088 22143 22148 22156 22143 23089 23090 22160 22149 22144 23896 22160 22144 22144 23888 23896 22144 22145 23888 22145 23078 23888 23079 23078 22145 22146 22151 23091 22159 22156 22148 22148 22158 22159 22148 22155 22158 22160 22150 22149 23093 23091 22151 22151 22169 23093 25487 25486 22152 22152 24716 25487 22152 23897 24716 22152 22153 23897 22154 22153 22152 24723 22154 22152 25486 24723 22152 22153 23094 23897 22153 23087 23094 22153 22154 23087 23103 22157 22154 24723 23103 22154 22156 22159 23088 23096 22159 22158 22158 22162 23096 23095 23088 22159 23102 23095 22159 22159 23096 23102 23101 23100 22160 23896 23101 22160 22161 22170 23105 22161 23107 23108 22161 23106 23107 22161 23105 23106 23117 23096 22162 22162 22172 23117 22163 22164 23121 23121 23120 22163 22164 22180 23121 22164 22165 22180 22166 22174 22175 22166 22169 22174 22166 22167 22169 22168 22167 22166 22175 22168 22166 23093 22169 22167 22167 22182 23093 22167 22168 22182 22185 22184 22168 22168 22175 22185 22183 22182 22168 22184 22183 22168 22170 22171 23105 23106 23105 22171 22171 22179 23106 22171 22178 22179 22172 23110 23117 23912 23110 22172 23919 23912 22172 22172 23108 23919 22173 23122 23906 22173 23100 23122 22177 22176 22174 22176 22175 22174 22175 22176 22185 22192 22185 22176 23104 22192 22176 22176 22177 23104 22177 23103 23104 23116 23106 22179 23909 23116 22179 22179 23135 23909 22179 23134 23135 22181 23111 23130 22188 22186 22181 23130 22188 22181 23113 23093 22182 22182 23112 23113 22182 22183 23112 23125 23112 22183 22183 23124 23125 22183 22190 23124 22183 22184 22190 22184 22185 22191 22184 22189 22190 22191 22189 22184 22193 22191 22185 23132 22193 22185 22185 22192 23132 22188 22187 22186 22186 22187 22196 22187 22188 23129 23129 22196 22187 23130 23129 22188 23150 23141 22189 22189 22197 23150 22189 22191 22197 23141 22190 22189 23126 23124 22190 23141 23126 22190 22191 22193 22197 22192 23104 23114 23914 23132 22192 22192 23114 23914 23133 22197 22193 22193 23132 23133 23926 23134 22194 22194 23923 23926 23948 23923 22194 22194 23932 23948 22194 22238 23932 22194 22195 22238 23157 22204 22195 22195 22237 22238 22196 23129 23130 22197 23133 23918 23922 23150 22197 22197 23918 23922 22221 22220 22199 22199 22203 22221 22199 22200 22203 22201 22200 22199 22218 22201 22199 22220 22218 22199 22200 22202 22203 22200 22201 22202 23126 22202 22201 23127 23126 22201 22201 22219 23127 22201 22218 22219 23126 22203 22202 22222 22221 22203 23141 22222 22203 22203 23126 23141 22205 23154 23155 23945 23143 22207 22207 22227 23945 22230 22229 22208 22209 22231 22234 22209 22210 22231 22211 22210 22209 22234 22211 22209 22210 22241 22242 22210 22211 22241 22211 22213 22216 22234 22213 22211 22211 22235 22241 23140 23138 22212 23148 23140 22212 22212 23147 23148 22212 22213 23147 22214 22213 22212 23138 22214 22212 23149 23147 22213 22213 22234 23149 22213 22214 22216 23138 22215 22214 22215 23138 23139 23127 22217 22215 23139 23127 22215 22219 22218 22217 23127 22219 22217 22220 22221 22236 23175 22236 22221 23947 23175 22221 22221 23943 23947 22221 22222 23943 22222 23150 23922 22222 23141 23150 24752 23943 22222 22222 23922 24752 22226 22225 22224 22225 22226 23170 23949 23945 22227 22228 23156 23173 22228 22230 23156 22228 22229 22230 23166 23156 22230 23946 23166 22230 22230 23167 23946 23191 22256 22232 22232 22245 23191 22232 22236 22245 22233 22247 23170 22243 22241 22235 22244 22243 22235 23175 22245 22236 23152 22238 22237 22237 23151 23152 22237 22246 23151 22238 23168 23932 22238 23152 23168 23957 23167 22240 22240 22266 23957 22240 22252 22266 22243 22242 22241 23187 22253 22242 23188 23187 22242 22242 22243 23188 22243 22255 23188 22243 22244 22255 22244 22254 22255 23958 23191 22245 22245 23947 23958 22245 23175 23947 23182 23151 22246 22246 22257 23182 23968 23965 22248 22248 23183 23968 22248 22251 23183 23178 22287 22249 22249 22250 23178 22277 22261 22249 23201 22277 22249 22249 22287 23201 22250 23177 23178 22250 23176 23177 23185 23183 22251 22251 22262 23185 22252 22265 22266 23187 23186 22253 23972 22255 22254 22254 23971 23972 22255 23972 24762 24762 23188 22255 22256 23190 23194 23191 23190 22256 22257 22258 23182 22258 22260 23182 23198 22260 22259 23979 23198 22259 22259 22285 23979 23961 23182 22260 24764 23961 22260 24765 24764 22260 22260 23198 24765 22262 22279 23185 22262 22278 22279 23193 22264 22263 23966 23193 22263 23218 23217 22264 24772 23218 22264 22264 23193 24772 23216 22280 22264 23217 23216 22264 24758 22266 22265 22265 23954 24758 22265 22267 23954 24763 23957 22266 22266 24758 24763 22267 23186 23967 23956 23954 22267 23967 23956 22267 22273 22271 22268 23197 22273 22268 23978 23197 22268 22268 23977 23978 22268 23195 23977 23196 23195 22268 22268 22269 23196 22270 22269 22268 22271 22270 22268 22269 22289 23196 22269 22288 22289 22269 22270 22288 22270 22281 22288 22270 22271 22281 22271 22272 22281 22273 22272 22271 22282 22281 22272 22283 22282 22272 22272 22273 22283 23202 22283 22273 23980 23202 22273 22273 23197 23980 22274 22275 22285 22276 22275 22274 22293 22276 22274 23205 22285 22275 23984 23205 22275 22275 22276 23984 23988 23984 22276 22276 22309 23988 22276 22294 22309 22276 22293 22294 23192 22279 22278 23215 23192 22278 22278 22295 23215 22279 23184 23185 23208 23184 22279 22279 23192 23208 22291 22288 22281 22308 22291 22281 23223 22308 22281 22281 22292 23223 22281 22282 22292 22282 22284 22292 22282 22283 22284 23202 22284 22283 23203 22292 22284 22284 23202 23203 22285 23204 23979 23205 23204 22285 23207 23206 22286 23962 23207 22286 22286 22287 23962 23963 23962 22287 22287 23178 23963 22291 22289 22288 23982 23196 22289 22289 22290 23982 22291 22290 22289 23985 23982 22290 23986 23985 22290 22290 23229 23986 22290 22310 23229 22290 22291 22310 22291 22308 22310 22292 23212 23223 22292 23203 23212 22294 22306 22309 22295 23214 23215 22296 23220 23224 22296 22297 23220 22298 22297 22296 23224 22298 22296 23992 23220 22297 24782 23992 22297 22297 23989 24782 22297 22298 23989 22298 23216 23989 23219 22300 22299 23220 23219 22299 23222 22301 22300 24784 23222 22300 22300 23219 24784 23221 22302 22301 23222 23221 22301 22302 23221 23225 22303 23223 23995 22303 22304 23223 22305 22304 22303 23995 22305 22303 22304 22308 23223 22311 22308 22304 23241 22311 22304 22304 22305 23241 24001 23241 22305 22305 23994 24001 23995 23994 22305 22316 22309 22306 22317 22316 22306 22325 22317 22306 22307 23214 23228 22307 23206 23214 22311 22310 22308 22309 22316 23988 22310 22312 23229 22310 22311 22312 23241 22319 22311 22319 22312 22311 23251 23229 22312 22312 22342 23251 22312 22341 22342 22312 22319 22341 23253 22321 22313 24013 23253 22313 22313 22356 24013 22313 22322 22356 22323 22322 22313 23997 23230 22314 22314 22320 23997 22314 22315 22320 23998 23988 22316 22316 22317 23998 22317 23243 23998 22317 22324 23243 22325 22324 22317 22343 22341 22319 23252 22343 22319 22319 23241 23252 24002 23997 22320 22320 23994 24002 22320 22321 23994 24015 23994 22321 22321 23253 24015 22322 22343 22356 22357 22343 22322 22371 22357 22322 22322 22323 22371 22324 23242 23243 22324 23230 23242 23257 22363 22326 22326 23246 23257 22326 23237 23246 22326 22327 23237 22328 22327 22326 22363 22328 22326 22327 22330 23237 22362 22347 22328 22363 22362 22328 22331 22330 22329 22333 22331 22329 22329 22332 22333 22330 22331 23237 23238 23237 22331 24004 23238 22331 24005 24004 22331 22331 22333 24005 22335 22333 22332 22332 22334 22335 22333 23239 24005 23240 23239 22333 22333 22335 23240 22336 22335 22334 22349 22336 22334 24008 23240 22335 22335 22336 24008 22336 22350 24008 22351 22350 22336 22336 22349 22351 22337 22351 22366 23248 22351 22337 23250 23248 22337 22337 23247 23250 22338 22368 22369 22338 22355 22368 22338 22342 22355 22367 22342 22338 22338 22339 22367 22340 22339 22338 23258 22340 22338 22338 22369 23258 24012 22367 22339 22339 22353 24012 22339 22340 22353 22354 22353 22340 23270 22354 22340 22340 23258 23270 22355 22342 22341 22341 22343 22355 22342 22367 23251 23252 22356 22343 22357 22355 22343 23235 22346 22344 22344 23214 23235 23228 23214 22344 22344 23227 23228 22344 22345 23227 22346 22345 22344 24016 23234 22346 24018 24016 22346 22346 23255 24018 22384 22348 22347 22347 22364 22384 22365 22364 22347 22347 22362 22365 22352 22351 22349 24009 24008 22350 22350 23249 24009 22350 23248 23249 22350 22351 23248 22351 22352 22366 24020 24012 22353 24819 24020 22353 22353 24021 24819 22353 22354 24021 24833 24021 22354 22354 24022 24833 22354 23270 24022 22355 22357 22368 22356 23252 24013 22385 22368 22357 23259 22385 22357 22357 22370 23259 22371 22370 22357 22381 22360 22359 22359 22361 22381 22381 22361 22360 23256 22365 22362 24019 23256 22362 22362 23244 24019 22362 22363 23244 23245 23244 22363 23257 23245 22363 22364 22365 22383 23256 22383 22365 24000 23251 22367 24011 24000 22367 24012 24011 22367 22369 22387 23258 23271 23259 22370 22370 22371 22372 22372 22373 22392 22393 22392 22373 22373 22374 22393 23260 22393 22374 23275 23260 22374 22374 22375 23275 23231 22379 22376 22378 22377 22376 22379 22378 22376 22377 22378 22380 22377 22380 23254 23262 23261 22378 23264 23262 22378 23268 23264 22378 22378 22379 23268 22379 23231 23268 23273 23272 22382 22382 22390 23273 22382 22383 22390 23269 22390 22383 22383 23266 23269 22383 23265 23266 22383 23256 23265 22385 23259 23271 23270 23258 22387 24023 23270 22387 22387 22391 24023 22388 22389 22413 22395 22394 22388 22407 22395 22388 22413 22407 22388 22389 22396 22413 23281 23273 22390 22390 23269 23281 22391 23285 24023 22391 22401 23285 23274 22398 22393 22393 23260 23274 23278 23260 22394 23279 23278 22394 22394 22395 23279 23277 23274 22395 22395 23274 23279 23276 22413 22396 24028 23276 22397 22397 23280 24028 22398 23274 23277 22399 22400 22404 22400 22403 22404 22401 22406 23285 22418 22404 22403 22403 22409 22418 22418 22416 22404 22406 22412 23285 22413 22408 22407 22408 22413 22414 22408 22414 22423 22409 22419 22425 22409 22410 22419 22425 22418 22409 22410 22411 22419 24027 23285 22412 24032 24027 22412 22412 23293 24032 22413 23276 23289 23289 22414 22413 23292 22423 22414 22414 23288 23292 23289 23288 22414 23292 23288 22415 22415 22432 23292 22418 22417 22416 22428 22427 22420 22421 23294 24042 25618 23296 22422 22422 24858 25618 22422 24039 24858 22422 24038 24039 22427 22428 23290 23300 22435 22427 24041 23300 22427 22427 23290 24041 23291 23290 22428 23312 23301 22429 22429 23306 23312 22429 22436 23306 22433 22434 23305 23307 23306 22436 22436 22439 23307 24055 23304 22437 24879 24055 22437 22437 24062 24879 22438 23302 24061 22440 22441 23316 22441 25628 25633 24069 23316 22441 24891 24069 22441 25633 24891 22441 22443 23311 23313 22443 22447 23311 24067 24062 22444 25638 24067 22444 25640 25638 22444 22444 24890 25640 22444 22445 24890 24895 24890 22445 22445 23320 24895 23325 22454 22446 23322 23311 22447 22447 22451 23322 23326 22451 22447 22450 22449 22448 24888 22450 22448 22448 24068 24888 22448 23318 24068 23319 23318 22448 23323 23319 22448 22448 22449 23323 22449 22450 24071 23330 23323 22449 24071 23330 22449 24072 24071 22450 25660 24072 22450 25661 25660 22450 22450 24899 25661 22450 24888 24899 22451 22452 23322 24074 23322 22452 22452 22457 24074 22452 22455 22457 22453 22454 23324 22453 23324 24073 23325 23324 22454 22455 22456 22457 22458 22457 22456 23331 22458 22456 22457 22459 24074 22457 22458 22459 22462 22459 22458 22463 22462 22458 23331 22463 22458 24077 24074 22459 22459 22462 24077 22461 23319 23323 23330 22465 22461 22461 23323 23330 24080 24077 22462 22462 22463 24080 22463 23331 24080 24908 24082 22464 22464 24081 24908 22464 22465 24081 22465 23330 24081 24088 22471 22466 24918 24088 22466 22466 24093 24918 22466 22467 24093 24921 24093 22467 24922 24921 22467 24924 24922 22467 22467 23342 24924 22467 23335 23342 22470 22469 22468 22471 22470 22468 22472 22471 22468 22475 22474 22469 22469 22470 22475 23334 22475 22470 23340 23334 22470 22470 22471 23340 24092 23340 22471 22471 24090 24092 22471 24089 24090 22471 24088 24089 22473 22489 23341 22474 22476 22477 22474 22475 22476 23334 22476 22475 22478 22477 22476 23338 22478 22476 22476 23334 23338 22477 22478 22479 22490 22479 22478 23339 22490 22478 22478 23338 23339 22479 22491 22492 22479 22490 22491 22480 22506 22514 22480 22481 22506 22482 22481 22480 22504 22482 22480 22512 22504 22480 22514 22512 22480 22481 22482 22505 22481 22483 22506 22505 22483 22481 22493 22490 22482 22502 22493 22482 22504 22502 22482 22482 22490 22505 22483 22484 22506 22485 22484 22483 22505 22485 22483 22507 22506 22484 22484 22486 22507 23346 22486 22484 22484 22485 23346 22485 23343 23346 22485 22505 23343 22488 22487 22486 24098 22488 22486 22486 23346 24098 22486 22494 22507 22486 22487 22494 22487 22496 22508 22487 22488 22496 22508 22494 22487 22498 22496 22488 24098 22498 22488 22489 22511 23341 22489 22501 22511 22493 22491 22490 23339 22505 22490 22491 22502 22503 22491 22493 22502 22503 22492 22491 22492 22503 22513 22519 22507 22494 22520 22519 22494 22494 22495 22520 22508 22495 22494 22526 22520 22495 22495 22521 22526 22522 22521 22495 22496 22500 22508 22496 22499 22500 23351 22499 22496 23352 23351 22496 22496 22497 23352 22498 22497 22496 23354 23352 22497 24099 23354 22497 22497 22498 24099 22498 24098 24099 24102 22509 22499 22499 23351 24102 22513 22503 22502 22502 22512 22513 22502 22504 22512 22505 23339 23343 22506 22507 22515 22515 22514 22506 22519 22515 22507 24107 22510 22509 22509 24103 24107 24106 24103 22509 22509 24102 24106 23348 23341 22511 22515 22519 22528 22528 22525 22515 22518 22517 22516 24109 24108 22517 22517 23360 24109 22517 22523 23360 22523 22527 23360 22523 22524 22527 23363 23360 22527 22527 22532 23363 22527 22531 22532 22529 22530 23368 23370 23368 22530 22530 23366 23370 23367 23366 22530 23374 23367 22530 22533 22532 22531 23372 22533 22531 22531 23369 23372 24113 24112 22532 22532 22533 24113 22532 23362 23363 24943 23362 22532 22532 24112 24943 23372 23371 22533 24117 24113 22533 22533 23371 24117 23382 23371 22534 22534 22537 23382 22539 22537 22534 23379 22546 22536 22536 22540 23379 22546 22545 22536 22537 22553 23382 22537 22550 22553 22539 22538 22537 22538 22539 22541 22540 23378 23379 22540 23370 23378 23390 22556 22542 22542 22543 23390 22544 22543 22542 23381 22544 22542 24144 23390 22543 22543 23388 24144 22543 22544 23388 22544 23387 23388 22544 23380 23387 23381 23380 22544 22549 22548 22545 22545 22546 22549 23384 22549 22546 22546 23379 23384 22547 24148 24956 22547 22554 24148 22548 22551 22552 22548 22549 22551 23384 22551 22549 22550 23385 23394 24121 22553 22550 22550 23394 24121 23391 22552 22551 22551 23384 23391 22552 23391 23393 23392 22559 22552 23393 23392 22552 24129 23382 22553 22553 24121 24129 24151 24145 22554 22554 24146 24148 22554 24145 24146 23386 23385 22555 24150 22557 22556 22556 24144 24150 22556 23390 24144 24150 23401 22557 23401 23398 22557 22558 22559 24167 23410 23402 22558 24167 23410 22558 22559 23392 24167 24165 24151 22560 24166 24165 22560 24980 24166 22560 22560 23430 24980 22560 22561 23430 22561 23409 23430 24175 23427 22562 22562 23408 24175 22563 23416 23428 22563 23411 23416 23413 23411 22563 24167 23413 22563 22563 23410 24167 22564 22565 22566 23425 22566 22565 23426 23425 22565 23427 23426 22565 22567 23433 24190 22567 22568 23433 22568 22574 23433 22569 22571 22574 22570 23414 23415 22575 22574 22571 24994 22575 22571 24995 24994 22571 22571 22572 24995 22573 22572 22571 24996 24995 22572 22572 24193 24996 22572 23438 24193 22572 22573 23438 22573 23437 23438 22573 22581 23437 23435 23433 22574 22574 22575 23435 24994 23435 22575 22580 22579 22576 22582 22580 22576 22583 22582 22576 22576 22577 22583 22577 22578 22583 23440 22583 22578 22578 23436 23440 22578 23431 23436 22579 22580 22600 22580 22599 22600 22580 22594 22599 22580 22582 22594 22582 23441 24209 22582 22583 23441 23453 22594 22582 24209 23453 22582 22583 23440 23441 22584 22601 22620 22619 22595 22584 22620 22619 22584 22587 22586 22585 23462 23454 22586 22586 22587 23462 22587 23460 23462 23461 23460 22587 22587 22588 23461 22589 22588 22587 24221 23461 22588 24224 24221 22588 22588 23466 24224 22588 22612 23466 22588 22589 22612 22589 22602 22612 22590 24211 24215 22590 24210 24211 23446 23437 22591 22591 23445 23446 22591 22592 23445 22593 22592 22591 24205 23445 22592 24207 24205 22592 22592 23450 24207 22592 22593 23450 22594 22598 22599 22607 22598 22594 23453 22607 22594 22619 22610 22595 22596 22597 24202 22596 22604 22605 23447 22604 22596 24202 23447 22596 22597 23465 24202 22600 22599 22598 22608 22600 22598 22609 22608 22598 22598 22607 22609 22608 22601 22600 22601 22608 22618 22601 22618 22620 22622 22612 22602 22623 22622 22602 22602 22621 22623 22602 22611 22621 24204 22615 22603 22603 24203 24204 22603 23448 24203 22603 23447 23448 22603 22604 23447 22605 22604 22603 23457 23452 22606 22606 22614 23457 22616 22609 22607 23459 22616 22607 24213 23459 22607 22607 23453 24213 22608 22609 22618 22609 22617 22618 22609 22616 22617 22621 22611 22610 22610 22619 22621 22612 22622 23466 23467 23465 22613 23468 23467 22613 22614 22615 23458 23458 23457 22614 24212 23458 22615 22615 24204 24212 23459 22617 22616 24222 22618 22617 22617 23459 24222 24228 22620 22618 24229 24228 22618 22618 24222 24229 24230 22621 22619 24231 24230 22619 22619 22620 24231 22620 24228 24231 24223 22623 22621 24230 24223 22621 24224 23466 22622 22622 24223 24224 22622 22623 24223 22638 22627 22624 22627 22625 22624 23477 23468 22625 22625 23476 23477 22625 22626 23476 22627 22626 22625 23481 23476 22626 22626 22639 23481 22626 22627 22639 22627 22638 22639 22634 22633 22628 23469 22634 22628 22628 23456 23469 22637 22636 22629 23472 22637 22629 22629 22630 23472 22630 22631 23472 23479 23472 22631 22631 22632 23479 23480 23479 22632 22632 22634 23480 22632 22633 22634 24232 23480 22634 22634 23469 24232 23478 22641 22635 22635 22636 23478 22636 22637 23478 22637 23472 23478 22642 22639 22638 22639 22642 23481 23484 22645 22640 22640 23482 23484 22640 22641 23482 22641 23478 23482 25053 23481 22642 25055 25053 22642 22642 22653 25055 22642 22652 22653 23483 22646 22643 22643 22644 23483 22644 22645 23483 23486 23483 22645 22645 23484 23486 24239 22647 22646 22646 23483 24239 22647 22648 22649 24239 22648 22647 22647 22649 22651 24238 22649 22648 24239 24238 22648 22649 24238 25066 24250 22651 22649 22649 24249 24250 25064 24249 22649 25065 25064 22649 22649 24242 25065 22649 23492 24242 23493 23492 22649 25066 23493 22649 22656 22652 22650 24250 23501 22651 22654 22653 22652 22656 22654 22652 22653 25054 25055 22653 22654 25054 25849 25054 22654 25850 25849 22654 22654 25063 25850 22654 24240 25063 24241 24240 22654 22654 22656 24241 22655 23500 24253 22655 22663 23500 24253 22656 22655 24253 24241 22656 22657 22658 24248 23506 22664 22657 23511 23506 22657 25073 23511 22657 22657 24248 25073 22658 22660 24248 22661 22660 22659 24254 24248 22660 22660 22661 24254 24257 24254 22661 23501 22665 22662 22664 22670 22671 22681 22670 22664 23506 22681 22664 22665 23512 23513 22665 23501 23512 22666 22673 22676 22666 22667 22673 22666 22668 22669 23518 22668 22666 22666 22676 23518 22688 22673 22667 22668 23516 23519 22668 23515 23516 23518 23515 22668 23519 22669 22668 24253 23500 22669 22669 24247 24253 24252 24247 22669 22669 23519 24252 22681 22674 22670 22687 22676 22673 22688 22687 22673 23521 23520 22675 23528 23521 22675 22675 22683 23528 22687 22678 22676 22676 23515 23518 22676 22685 23515 22676 22677 22685 22678 22677 22676 22686 22685 22677 22692 22686 22677 22677 22678 22692 22678 22693 22700 22678 22687 22693 22698 22692 22678 22701 22698 22678 22705 22701 22678 22678 22700 22705 22679 22682 23533 22679 22680 22682 22681 22680 22679 22680 22681 23511 24278 22682 22680 22680 23511 24278 22681 23506 23511 25093 23533 22682 22682 24278 25093 22684 23529 23537 22684 23522 23529 23517 23515 22685 23527 23517 22685 22685 22686 23527 22686 22692 23527 22695 22693 22687 22687 22688 22695 22689 22690 22696 22691 22690 22689 22697 22696 22690 23549 22697 22690 24284 23549 22690 22690 23552 24284 22690 22691 23552 24282 23552 22691 23547 23527 22692 22692 22699 23547 22692 22698 22699 22693 22694 22700 22695 22694 22693 22694 22695 22704 22704 22700 22694 22709 22706 22697 23550 22709 22697 22697 23549 23550 22698 22702 22703 22698 22701 22702 22703 22699 22698 22699 23546 23547 23555 23546 22699 22699 22708 23555 22699 22707 22708 22699 22703 22707 22700 22704 22705 22705 22702 22701 22704 22703 22702 22705 22704 22702 22708 22712 23555 22708 22711 22712 22709 23550 24298 22710 22722 22723 24298 22722 22710 22711 22714 22715 22711 22713 22714 22718 22712 22711 22711 22715 22718 23556 23555 22712 22712 22718 23556 22716 22714 22713 22724 22718 22715 23559 22724 22715 22723 22722 22717 22718 22720 23556 22718 22719 22720 22724 22719 22718 22725 22721 22719 22726 22725 22719 22719 22724 22726 22721 22720 22719 24299 23556 22720 22720 23565 24299 22720 22721 23565 22721 22727 23566 22721 22725 22727 23566 23565 22721 24298 22728 22722 23565 22726 22724 22724 23559 23565 22725 22726 22727 23566 22727 22726 22726 23565 23566 22728 23550 24291 24298 23550 22728 25901 23564 22728 22728 25101 25901 22728 24291 25101 22729 23573 23575 22729 22730 23573 22730 23569 23573 23581 22732 22731 22731 23578 23581 23579 23578 22731 22731 23577 23579 23581 23580 22732 23581 22734 22733 22733 23580 23581 23593 22736 22734 22734 23582 23593 22734 23581 23582 22735 22739 23599 23593 22739 22735 22735 22736 23593 22737 23596 23598 23597 23596 22737 23607 23597 22737 22737 22738 23607 22739 22738 22737 23598 22739 22737 24355 23607 22738 25161 24355 22738 22738 24345 25161 22738 23594 24345 23595 23594 22738 22738 23582 23595 23593 23582 22738 22738 22739 23593 24358 23599 22739 25167 24358 22739 22739 23598 25167 22741 22742 24359 22743 22742 22741 24359 23610 22741 22742 22743 23609 22742 23609 24359 22745 23611 24368 25195 23612 22745 22745 24368 25195 24366 23606 22746 22746 23618 24366 22750 22748 22747 22752 22750 22747 22748 22750 23613 23615 22761 22749 22749 22750 23615 22751 22750 22749 23616 22751 22749 22750 22751 23613 22750 22752 23615 24373 23613 22751 22751 23616 24373 24374 23623 22753 22753 23613 24374 25200 23614 22754 25206 25200 22754 25980 25206 22754 22754 22755 25980 22755 22757 22762 25981 25980 22755 25983 25981 22755 25988 25983 22755 22755 22776 25988 23622 22776 22755 22755 22762 23622 22771 22768 22758 22758 22763 22771 22758 22759 22763 22759 22760 22763 23628 23627 22763 23626 22771 22763 23627 23626 22763 25208 23624 22764 22764 24375 25208 24379 23630 22765 22766 22769 23622 22769 22776 23622 22769 22770 22776 22777 22776 22770 22785 22777 22770 22773 22772 22771 23626 22773 22771 22772 22773 22778 24390 22778 22773 22773 24384 24390 22773 23626 24384 24388 23629 22774 22774 22775 24388 22775 22796 24388 25991 25988 22776 25995 25991 22776 22776 24382 25995 24383 24382 22776 24389 24383 22776 22776 22777 24389 22777 22806 24389 23635 22806 22777 22777 22785 23635 24390 22791 22778 22782 22784 22789 22782 22783 22784 23634 22784 22783 22783 23631 23634 22790 22789 22784 23634 22790 22784 23636 22787 22786 23638 23636 22786 22795 22788 22787 23636 22795 22787 22789 22790 22799 22790 22798 22799 23634 22798 22790 24390 23638 22791 24399 23637 22792 22792 24396 24399 22792 23638 24396 22792 22793 23638 22794 22793 22792 23637 22794 22792 24392 23639 22793 22793 22794 24392 22793 23636 23638 23639 23636 22793 24397 24392 22794 22794 23637 24397 23640 22803 22795 22795 23636 23640 24400 24388 22796 24401 24400 22796 24402 24401 22796 22796 22797 24402 22797 23645 24402 24394 24393 22798 22798 23633 24394 23634 23633 22798 24393 22799 22798 23642 22805 22799 24393 23642 22799 22800 22806 23635 22800 22801 22806 22802 22801 22800 23641 22806 22801 24395 23641 22801 22801 22802 24395 22802 23649 24395 24398 22804 22803 22803 24392 24398 22803 23639 24392 23640 23639 22803 24398 22808 22804 23646 22807 22805 22805 23643 23646 22805 23642 23643 22806 23641 24389 22816 22811 22807 23656 22816 22807 24424 23656 22807 22807 23652 24424 22807 23648 23652 22807 23646 23648 22807 22811 22812 23644 22809 22808 25219 23644 22808 22808 24398 25219 24406 22815 22809 22809 23644 24406 22810 22811 22813 22812 22811 22810 22816 22813 22811 22813 22816 22825 22814 22815 22823 23659 22823 22815 24419 23659 22815 22815 24407 24419 22815 24406 24407 23655 22825 22816 23656 23655 22816 22831 22819 22818 24426 22831 22818 22818 22829 24426 22830 22829 22818 22818 22828 22830 22818 22826 22828 24405 23654 22820 25243 24405 22820 22820 23661 25243 22820 22821 23661 22821 22834 23661 23651 23650 22824 22824 22832 23651 22827 22826 22825 23657 22827 22825 22825 23655 23657 22826 22827 22828 22830 22828 22827 23658 22830 22827 22827 23657 23658 25240 24426 22829 25247 25240 22829 22829 24432 25247 22829 22830 24432 22830 23658 24432 22831 24413 24417 24426 24413 22831 24420 23651 22832 25245 24420 22832 22832 22836 25245 22832 22835 22836 24434 22841 22833 25259 24434 22833 25260 25259 22833 22833 25241 25260 22833 24418 25241 22833 24417 24418 25244 23661 22834 26033 25244 22834 22834 23667 26033 22837 22836 22835 23668 22837 22835 25251 25245 22836 22836 23664 25251 22836 22837 23664 24450 23664 22837 22837 23668 24450 23669 22839 22838 22838 23666 23669 22838 22840 23666 24451 22844 22839 22839 23669 24451 24441 22857 22841 22841 24435 24441 22841 24434 24435 23670 23667 22842 22842 22847 23670 24451 23673 22844 22846 22852 22853 23676 23670 22847 23677 23676 22847 25261 24443 22849 22849 23665 25261 23679 22858 22850 22851 23671 23672 22853 22854 23675 22855 22854 22853 22856 22855 22853 24448 23675 22854 22854 22855 24448 22855 22857 24448 22855 22856 22857 22857 24441 24448 22858 23679 23687 24455 23671 22859 24461 24455 22859 22859 23680 24461 23681 23680 22859 22859 22863 23681 22867 22864 22860 24467 22867 22860 22860 23674 24467 22861 22870 22875 23689 22862 22861 23695 23689 22861 22861 23694 23695 22861 22875 23694 24454 23686 22862 22862 23689 24454 22863 22874 23681 22863 22873 22874 25295 24507 22865 22865 22866 25295 22867 22866 22865 25296 25295 22866 22866 24469 25296 22866 24468 24469 22866 22867 24468 22867 24467 24468 22875 22869 22868 23694 22875 22868 22875 22870 22869 22871 22886 22888 22887 22886 22871 22889 22887 22871 22871 22879 22889 22888 22872 22871 22881 22873 22872 22888 22881 22872 22881 22874 22873 23692 23681 22874 23693 23692 22874 22874 22881 23693 22885 22879 22876 22876 22877 22885 22878 22877 22876 22879 22878 22876 22890 22885 22877 23696 22890 22877 22877 22878 23696 23698 23696 22878 23699 23698 22878 22878 23690 23699 22878 22880 23690 22878 22879 22880 22879 22885 22889 23703 23693 22881 22881 22888 23703 24508 22906 22882 22882 24464 24508 24466 24464 22882 22882 22883 24466 22883 22884 24466 24507 24466 22884 22890 22889 22885 24499 23702 22886 24500 24499 22886 22886 22887 24500 23702 22888 22886 22887 22889 24500 22888 23702 23703 22889 23701 24500 22889 22890 23701 24498 23701 22890 22890 23700 24498 22890 23696 23700 22891 22892 22894 22893 22892 22891 23714 22894 22892 22892 23712 23714 22892 22893 23712 23713 23712 22893 23714 22895 22894 22895 23714 24525 24525 23716 22895 22896 23715 23717 22901 22900 22897 22899 22898 22897 22900 22899 22897 22898 22899 23708 22899 22900 23708 23709 23708 22900 22900 22902 23709 22900 22901 22902 22902 22913 23709 23728 23713 22903 22903 22904 23728 22905 22904 22903 22915 22905 22903 22903 22907 22915 23730 23728 22904 24541 23730 22904 22904 23735 24541 22904 23734 23735 22904 22905 23734 22905 22924 23734 22905 22923 22924 22905 22915 22923 22908 22907 22906 24508 22908 22906 22922 22915 22907 22907 22908 22922 23710 22922 22908 24513 23710 22908 22908 24508 24513 23707 23706 22909 23722 23707 22909 22909 22910 23722 22911 22910 22909 22910 23721 23722 22910 22918 23721 22910 22911 22918 22911 22912 22918 24522 23709 22913 22913 22914 24522 24523 24522 22914 22914 22920 24523 22915 22922 22923 24493 23694 22916 22916 22917 24493 22917 23704 24493 22921 22920 22919 22925 22921 22919 22920 22921 24523 24558 24523 22921 22921 22934 24558 22921 22925 22934 22926 22923 22922 23724 22926 22922 22922 23711 23724 22922 23710 23711 22926 22924 22923 22924 22926 23734 22926 23724 23734 22937 22930 22927 22939 22937 22927 22927 22931 22939 22927 22929 22931 22927 22928 22929 22932 22931 22929 22938 22936 22930 22930 22937 22938 22931 22938 22939 24562 22938 22931 24563 24562 22931 22931 24543 24563 24544 24543 22931 24545 24544 22931 22931 23736 24545 22931 22932 23736 22932 23720 23736 22935 22934 22933 24559 24558 22934 22934 22935 24559 24565 24559 22935 22935 23747 24565 22936 22938 22940 22939 22938 22937 23753 22940 22938 24570 23753 22938 22938 24562 24570 23753 22948 22940 22941 23738 23745 23739 23738 22941 22941 22943 23739 22941 22942 22943 23746 23739 22943 23756 23746 22943 22943 23750 23756 22943 22944 23750 23759 23758 22946 23764 23763 22947 22947 22948 23764 22948 23753 23764 22949 22960 23769 22949 22952 22960 23772 23771 22950 22951 22959 23765 22952 22954 22960 22952 22953 22954 22955 22954 22953 22954 22955 22960 22955 22956 23770 23770 22960 22955 24584 24583 22957 22957 22958 24584 22958 22964 24584 22959 22970 23765 22959 22966 22970 24581 23769 22960 24582 24581 22960 24590 24582 22960 22960 23770 24590 23778 23777 22961 22961 23773 23778 23777 22968 22961 24604 24603 22962 24605 24604 22962 22962 23778 24605 22962 22963 23778 22964 22963 22962 24603 22964 22962 22963 23777 23778 22963 22964 23777 22964 22968 23777 24603 24584 22964 23774 23773 22965 22965 23768 23774 24602 23785 22967 22967 24601 24602 23779 22970 22969 23788 23779 22969 22969 22989 23788 23767 23765 22970 23775 23767 22970 23779 23775 22970 23795 22979 22971 22971 23793 23795 22974 22973 22972 22981 22974 22972 23776 22975 22973 24597 23776 22973 22973 22974 24597 24611 24597 22974 22974 22981 24611 23776 22976 22975 22977 23007 23786 23792 23791 22978 22978 22991 23792 22978 22990 22991 23795 22980 22979 22980 23795 23796 23796 22993 22980 22981 23810 24611 22982 24613 24617 22982 22983 24613 22994 22987 22982 24617 22994 22982 22983 24612 24613 22983 23785 24612 22984 22985 26133 22986 22985 22984 26134 22986 22984 22984 26133 26134 24612 24602 22985 22985 22986 24612 22985 24602 26133 24613 24612 22986 25390 24613 22986 26134 25390 22986 22994 22988 22987 22988 22995 22996 22988 22994 22995 22989 23787 23788 22992 22991 22990 23003 22992 22990 22990 23002 23003 22991 22992 24610 26956 23792 22991 22991 25376 26956 22991 24610 25376 22992 23003 23004 22992 23004 24610 23802 23005 22993 22993 23796 23802 24617 22995 22994 22995 24617 25391 24619 22996 22995 25391 24619 22995 25384 24615 22996 22996 25381 25384 22996 24619 25381 25359 24607 22997 26947 25359 22997 22997 24596 26947 22997 22998 24596 22999 22998 22997 22998 22999 24596 22999 23784 24596 23799 23008 23000 23000 23798 23799 23000 23789 23798 23011 23002 23001 23012 23011 23001 23806 23012 23001 23001 23013 23806 23004 23003 23002 23011 23004 23002 25376 24610 23004 23004 25373 25376 23004 25372 25373 23004 23011 25372 23812 23015 23005 23005 23802 23812 23815 23809 23006 23006 23020 23815 23797 23786 23007 24616 23797 23007 23007 24614 24616 24615 24614 23007 23008 23799 23801 23009 23010 23013 23805 23013 23010 23010 23799 23805 23801 23799 23010 23011 25371 25372 23011 23012 25371 23012 24609 25371 23012 23806 24609 23013 23805 23806 23817 23021 23014 23014 23812 23817 23014 23015 23812 23018 23017 23016 23017 23018 23807 24625 24622 23018 24627 24625 23018 24622 23807 23018 23816 23815 23020 23020 23025 23816 23817 23022 23021 23820 23819 23022 23022 23818 23820 23022 23817 23818 23036 23027 23023 23814 23036 23023 23023 23807 23814 23023 23024 23807 23822 23816 23025 23025 23821 23822 24634 23034 23026 23036 23028 23027 23828 23037 23028 24629 23828 23028 24630 24629 23028 23028 23036 24630 23029 23030 23821 23031 23030 23029 23037 23031 23029 24640 24633 23030 23030 24639 24640 23030 23826 24639 23827 23826 23030 23030 23031 23827 23823 23821 23030 24633 23823 23030 23834 23827 23031 23841 23834 23031 23031 23833 23841 23031 23829 23833 23031 23037 23829 23032 23034 23832 23032 23033 23034 24634 23832 23034 23035 23838 23839 23035 23041 23838 23035 23040 23041 26166 26162 23036 23036 24644 26166 23036 24638 24644 23036 24628 24638 23036 23814 24628 27752 24630 23036 23036 26172 27752 23036 26162 26172 23037 23828 23829 23849 23048 23038 23038 23837 23849 23038 23048 23049 23039 24646 24653 23039 23830 24646 23039 23836 23837 24653 23836 23039 24659 23838 23041 23041 23847 24659 23041 23043 23847 23055 23044 23042 23043 23052 23847 23861 23054 23044 23044 23062 23861 23044 23055 23062 23049 23047 23046 23846 23049 23046 23051 23050 23047 23851 23051 23047 23047 23848 23851 23849 23848 23047 23047 23048 23849 23049 23048 23047 23057 23056 23050 23852 23057 23050 23050 23051 23852 23051 23851 23852 23853 23847 23052 23854 23853 23052 23857 23854 23052 23052 23058 23857 23053 23054 23061 23054 23060 23061 23861 23060 23054 23063 23062 23055 23855 23850 23057 23057 23852 23855 23058 23059 23857 23860 23857 23059 23859 23080 23060 23861 23859 23060 24669 23065 23064 23064 24668 24669 23064 24667 24668 23064 23856 24667 23065 25458 25462 23065 24669 25458 23863 23066 23065 25461 23863 23065 25462 25461 23065 23863 23072 23066 23067 23074 23867 23068 23070 23071 23881 23070 23068 23882 23881 23068 23068 23069 23882 23069 23086 23882 23069 23083 23086 23881 23082 23070 23862 23073 23072 23863 23862 23072 23868 23084 23073 23073 23862 23868 23870 23867 23074 24683 23870 23074 23074 23886 24683 23074 23075 23886 23076 23075 23074 23077 23076 23074 23075 23076 23077 23075 23090 23886 23075 23077 23090 24685 23888 23078 23078 23871 24685 23078 23079 23871 23079 23080 23871 23080 23859 23871 24677 23861 23081 23081 23082 24677 24688 24677 23082 24695 24688 23082 23082 23881 24695 23868 23085 23084 23893 23094 23085 23085 23868 23893 23086 23091 23092 23086 23092 23882 23088 23098 23898 23099 23098 23088 23088 23097 23099 23088 23095 23097 23898 23089 23088 23887 23090 23089 23898 23887 23089 23887 23886 23090 23093 23092 23091 23092 23093 23892 23890 23882 23092 23892 23890 23092 23093 23113 23892 23094 24697 24698 23094 23893 24697 24698 23897 23094 23118 23097 23095 23095 23102 23118 23117 23110 23096 23109 23102 23096 23110 23109 23096 23118 23099 23097 23098 23099 24720 24720 23898 23098 23099 23118 23905 23099 23905 24720 23100 23101 23123 23123 23122 23100 24721 23123 23101 23101 23896 24721 23119 23118 23102 23102 23109 23119 23115 23104 23103 24723 23115 23103 23115 23114 23104 23910 23107 23106 23106 23116 23910 24736 23108 23107 23107 23910 24736 24736 23919 23108 24737 23119 23109 24738 24737 23109 24739 24738 23109 23109 23911 24739 23912 23911 23109 23109 23110 23912 23916 23130 23111 23917 23916 23111 23111 23906 23917 23892 23113 23112 23112 23890 23892 23902 23890 23112 23112 23125 23902 24728 23914 23114 23114 23115 24728 23115 24724 24728 24726 24724 23115 23115 24723 24726 25497 23910 23116 23116 24731 25497 23116 23909 24731 23118 23119 23905 24737 23905 23119 23120 23121 23128 24727 23906 23122 23122 24708 24727 23122 23123 24708 24721 24708 23123 23124 23126 23127 23131 23125 23124 23124 23127 23131 23125 23899 23902 23901 23899 23125 23125 23131 23901 23139 23131 23127 23916 23137 23130 23908 23901 23131 23131 23139 23908 23918 23133 23132 23132 23914 23918 23926 23135 23134 24735 24734 23135 23135 23926 24735 24732 23909 23135 24734 24732 23135 23920 23142 23136 23929 23920 23136 23136 23172 23929 23927 23172 23136 23928 23927 23136 23146 23145 23137 23916 23146 23137 23145 23144 23137 23140 23139 23138 23139 23140 23908 23140 23148 23908 23933 23162 23142 23142 23920 23933 23143 23945 24744 24743 23915 23143 23143 24742 24743 24744 24742 23143 23144 23145 23149 23145 23146 23149 23146 23147 23149 23148 23147 23146 23907 23148 23146 23917 23907 23146 23146 23916 23917 23148 23907 23913 23913 23908 23148 23153 23152 23151 23960 23153 23151 23961 23960 23151 23151 23182 23961 23152 23153 23168 23959 23168 23153 25532 23959 23153 23153 23960 25532 23159 23158 23154 23157 23155 23154 23158 23157 23154 23942 23173 23156 23156 23939 23942 23156 23166 23939 23157 23158 23169 23158 23159 23944 23944 23169 23158 23159 23160 23944 23160 23169 23944 23161 23165 23177 23920 23165 23161 23933 23920 23161 23161 23162 23933 23177 23176 23161 23163 23164 23964 23165 23164 23163 23177 23165 23163 23178 23177 23163 23964 23178 23163 23164 23171 23964 23172 23171 23164 23164 23165 23172 23929 23172 23165 23165 23920 23929 23941 23939 23166 23946 23941 23166 23950 23946 23167 23957 23950 23167 24757 23932 23168 23168 23959 24757 23171 23949 23951 24744 23949 23171 24747 24744 23171 24751 24747 23171 23171 23172 24751 23171 23951 23964 23172 24745 24751 23172 23927 24745 23938 23937 23173 23173 23935 23938 24748 23935 23173 23173 23942 24748 23968 23963 23178 23178 23964 23968 23937 23180 23179 24754 23181 23180 23180 23938 24754 23180 23937 23938 23970 23966 23181 23181 23952 23970 23953 23952 23181 24754 23953 23181 23183 23207 23963 23183 23184 23207 23185 23184 23183 23183 23963 23968 23184 23206 23207 23208 23206 23184 23186 23187 23967 23187 23188 23967 23188 23956 23967 23188 23955 23956 24759 23955 23188 24760 24759 23188 24762 24760 23188 23974 23971 23189 23975 23974 23189 23189 23194 23975 23973 23194 23189 23975 23194 23190 23190 23958 23975 23190 23191 23958 23215 23208 23192 25549 24772 23193 23193 23969 25549 23970 23969 23193 23193 23966 23970 23195 23976 23977 25538 23976 23195 23195 24791 25538 23195 23982 24791 23195 23196 23982 24769 23980 23197 23197 24768 24769 23197 23978 24768 24766 24765 23198 23198 23199 24766 23200 23199 23198 23979 23200 23198 25540 24766 23199 23199 23200 25540 25541 25540 23200 23200 23979 25541 23983 23203 23202 23202 23981 23983 23202 23980 23981 23213 23212 23203 23983 23213 23203 23204 23205 24770 24770 23979 23204 23205 23984 24770 23206 23208 23214 23207 23962 23963 23215 23214 23208 23211 23210 23209 23995 23211 23209 23997 23995 23209 23209 23210 23997 23210 23996 23997 23210 23211 23996 24788 23996 23211 23211 24777 24788 24779 24777 23211 23211 23987 24779 23211 23213 23987 23995 23213 23211 23212 23213 23223 23995 23223 23213 23213 23983 23987 24781 23989 23216 23216 23217 24781 23217 25551 25557 23217 23218 25551 25557 24781 23217 23218 24772 25551 25561 24784 23219 23219 25559 25561 23219 24783 25559 23219 23992 24783 23219 23220 23992 23226 23225 23221 23993 23226 23221 23221 23222 23993 23222 23990 23993 23991 23990 23222 25562 23991 23222 23222 25561 25562 23222 24784 25561 24794 24010 23225 23225 23226 24794 24804 24794 23226 26284 24804 23226 23226 23990 26284 23993 23990 23226 24792 23986 23229 23229 24000 24792 23229 23251 24000 23997 23242 23230 23231 23267 23268 24016 23267 23231 23231 23233 24016 23231 23232 23233 23233 23234 24016 23237 23238 23246 24003 23246 23238 24004 24003 23238 24806 24005 23239 23239 24007 24806 23239 24006 24007 23239 23240 24006 24008 24006 23240 24015 23253 23241 23241 24014 24015 23241 24001 24014 24013 23252 23241 23241 23253 24013 24780 23243 23242 24786 24780 23242 23242 23996 24786 23997 23996 23242 23243 23988 23998 24780 23988 23243 24810 24019 23244 23244 23245 24810 24811 24810 23245 23245 23246 24811 23257 23246 23245 23246 24795 24811 23246 24003 24795 24802 23250 23247 23250 23249 23248 24017 24009 23249 24800 24017 23249 24801 24800 23249 23249 23250 24801 24802 24801 23250 23255 23267 24018 23255 23263 23267 24019 23265 23256 23278 23274 23260 23264 23263 23262 23268 23267 23263 23263 23264 23268 24829 23266 23265 23265 24026 24829 24820 24026 23265 23265 24019 24820 24829 23269 23266 23267 24016 24018 24024 23281 23269 24829 24024 23269 24023 24022 23270 24036 24031 23272 24839 24036 23272 23272 24029 24839 23272 23282 24029 23272 23273 23282 23273 23281 23282 23274 23278 23279 24028 23289 23276 23280 23289 24028 24030 23282 23281 24837 24030 23281 23281 24024 24837 24030 24029 23282 24855 24034 23283 23283 24033 24855 23283 23284 24033 23284 24031 24033 23284 23287 24031 24027 24023 23285 23290 24037 24041 23290 23291 24037 23291 24034 24037 24838 24032 23293 23294 23295 24042 24857 24042 23295 23295 23296 24857 24868 24857 23296 25618 24868 23296 24046 24043 23297 23297 23301 24046 23298 23299 24875 24874 23305 23298 24875 24874 23298 23299 23300 24051 23299 24051 24875 23300 24041 24051 23301 23312 24046 23302 24053 24061 23302 24049 24053 23302 23303 24049 24050 24049 23303 23303 23304 24050 24054 24050 23304 24055 24054 23304 23306 23308 23312 24056 23312 23308 23308 23309 24056 23310 23309 23308 23309 23317 24056 23309 23310 23317 23310 23313 23317 24887 24886 23311 23311 23321 24887 23322 23321 23311 24064 23313 23311 25635 24064 23311 26377 25635 23311 23311 24886 26377 24056 24046 23312 24063 23317 23313 24064 24063 23313 25642 24070 23314 23314 24069 25642 23314 23315 24069 23315 23316 24069 24060 24056 23317 24063 24060 23317 23318 24065 24068 23320 24073 24895 23321 24076 24887 23321 24075 24076 23321 23322 24075 23322 24074 24075 23324 23328 24073 23324 23327 23328 24070 23327 23324 23324 23325 24070 23329 23328 23327 25662 23329 23327 23327 24070 25662 24900 24073 23328 23328 23329 24900 25650 25646 23329 26394 25650 23329 23329 25662 26394 25647 24900 23329 23329 25646 25647 23330 24071 24081 24910 24080 23331 23331 24084 24910 23332 23333 24084 24087 24084 23333 23333 24086 24087 23333 24083 24086 23333 24082 24083 23334 23336 23338 23337 23336 23334 24092 23337 23334 23334 23340 24092 23347 23342 23335 23353 23338 23336 24094 23353 23336 24923 24094 23336 25676 24923 23336 23336 25675 25676 23336 24920 25675 23336 23337 24920 23337 24916 24920 23337 24092 24916 23353 23339 23338 23344 23343 23339 24094 23344 23339 23339 23353 24094 23341 23342 23347 24929 23342 23341 23341 24100 24929 24101 24100 23341 23341 23348 24101 24929 24924 23342 23343 23344 23346 23344 23345 23346 24094 23345 23344 24097 23346 23345 23345 24095 24097 24096 24095 23345 23345 24094 24096 23346 23349 24098 23350 23349 23346 24097 23350 23346 24108 24101 23348 24925 24098 23349 23349 23350 24925 23350 24097 24925 24928 24102 23351 25687 24928 23351 25688 25687 23351 23351 23352 25688 23352 25686 25688 23352 24927 25686 23352 23354 24927 23354 24099 24927 24934 24933 23355 25703 24934 23355 23355 24105 25703 23355 23356 24105 23357 23356 23355 23358 23357 23355 24933 23358 23355 23356 24104 24105 23356 23357 24104 24107 24104 23357 24933 23365 23358 23360 23361 24109 23363 23361 23360 24110 24109 23361 24931 24110 23361 23361 23362 24931 23363 23362 23361 25714 24931 23362 23362 24943 25714 24935 24111 23364 23364 24934 24935 23364 23365 24934 23365 24933 24934 23377 23370 23366 24942 23377 23366 23366 24941 24942 23366 23367 24941 23367 24115 24941 23367 23374 24115 23369 23371 23372 23370 23377 23378 24130 24117 23371 23371 23382 24130 24944 24118 23373 23373 24936 24944 23373 24111 24936 23374 24114 24115 23374 23375 24114 24948 24114 23375 23375 23376 24948 23376 24119 24948 24942 23378 23377 23383 23379 23378 24132 23383 23378 24942 24132 23378 23379 23383 23384 24118 23387 23380 23382 24129 24130 24133 23384 23383 23383 24132 24133 24133 23391 23384 23385 23386 23389 23385 23389 23394 23397 23389 23386 24139 23388 23387 23387 24118 24139 23388 24140 24144 23388 24139 24140 23397 23394 23389 24133 23393 23391 23392 23413 24167 24160 23413 23392 24161 24160 23392 23392 23393 24161 24969 24161 23393 23393 24133 24969 23394 23399 24121 23400 23399 23394 23394 23395 23400 23396 23395 23394 24128 23400 23395 24149 24128 23395 24982 23408 23398 23398 24164 24982 23398 23401 24164 23399 24120 24121 23399 23400 24120 24123 24120 23400 24127 24123 23400 24128 24127 23400 23401 24150 24164 23403 24168 24171 23403 23412 24168 23403 23411 23412 23417 23411 23403 23418 23417 23403 23403 23404 23418 23405 23404 23403 24171 23405 23403 23419 23418 23404 23404 23405 23419 23405 23406 23419 23407 23406 23405 24156 23407 23405 23405 24153 24156 24170 24153 23405 24171 24170 23405 23421 23419 23406 23422 23421 23406 23406 23407 23422 23423 23422 23407 24157 23423 23407 23407 24156 24157 24982 24175 23408 24983 23430 23409 23409 23425 24983 23417 23416 23411 23413 23412 23411 23412 23413 24168 23413 24160 24168 23428 23416 23414 23416 23415 23414 23415 23416 23431 23416 23429 23431 23416 23417 23429 23417 23418 23429 24195 23429 23418 23418 23432 24195 23418 23420 23432 23418 23419 23420 23421 23420 23419 25004 23432 23420 23420 24999 25004 23420 24998 24999 23420 24188 24998 23420 23421 24188 23421 24185 24188 23421 23423 24185 23421 23422 23423 23423 24172 24185 24178 24172 23423 23423 24157 24178 23424 24183 24184 23424 24182 24183 24985 24983 23425 23425 23426 24985 23426 23427 24985 23427 24175 24985 24194 23436 23429 24195 24194 23429 23436 23431 23429 24986 24980 23430 23430 24983 24986 24197 24195 23432 25004 24197 23432 24191 24190 23433 23433 23434 24191 23435 23434 23433 25787 24191 23434 23434 23435 25787 23435 24994 25787 24194 23440 23436 23439 23438 23437 24198 23439 23437 23437 23446 24198 23438 24192 24193 23438 23439 24192 23439 23442 24192 24198 23442 23439 25001 23441 23440 23440 24196 25001 23440 24194 24196 25012 25011 23441 23441 25001 25012 25011 24209 23441 24198 23444 23442 25000 24192 23442 25009 25000 23442 23442 23443 25009 23444 23443 23442 23443 24200 25009 23443 24199 24200 23443 23444 24199 24198 23446 23444 24208 24199 23444 23444 23446 24208 24208 23446 23445 23445 24205 24208 23449 23448 23447 24202 23449 23447 23448 23449 24203 25013 24203 23449 23449 24202 25013 23450 23451 24207 23452 23451 23450 23451 24206 24207 25822 24206 23451 23451 24217 25822 23451 23452 24217 24218 24217 23452 23452 23457 24218 24219 24213 23453 23453 24209 24219 25023 24210 23454 23454 23462 25023 23463 23456 23455 23464 23463 23455 23470 23469 23456 23471 23470 23456 24225 23471 23456 23456 23463 24225 25017 24218 23457 25018 25017 23457 23457 24216 25018 23457 23458 24216 23458 24212 24216 25032 24222 23459 23459 25026 25032 23459 24213 25026 24220 23462 23460 24221 24220 23460 23460 23461 24221 23462 24220 25023 23463 23464 25030 25036 24225 23463 25037 25036 23463 23463 25030 25037 23464 24214 25030 25031 25025 23465 23465 23467 25031 25025 24202 23465 25038 25031 23467 23467 23477 25038 23467 23468 23477 23469 23470 24232 23470 23473 24232 23474 23473 23470 23470 23471 23474 25036 23474 23471 23471 24225 25036 23491 23478 23472 23472 23479 23491 23473 23474 25050 24235 24232 23473 25050 24235 23473 23474 25036 25052 25052 25050 23474 23475 23476 23481 23477 23476 23475 24226 23477 23475 24227 24226 23475 24233 24227 23475 23475 23481 24233 23477 24226 25038 23489 23482 23478 23491 23489 23478 23479 23480 23491 24236 23491 23480 23480 24235 24236 23480 24232 24235 25053 24233 23481 24237 23484 23482 23482 23489 24237 23483 23485 24239 23486 23485 23483 24237 23486 23484 23485 23486 24243 25057 24239 23485 23485 24243 25057 23486 24237 24243 23495 23494 23487 23487 23488 23495 23489 23488 23487 23494 23489 23487 23504 23495 23488 23488 23499 23504 23488 23490 23499 23488 23489 23490 23489 23494 24237 23491 23490 23489 23490 23498 23499 23490 23491 23498 23502 23498 23491 24236 23502 23491 25853 24242 23492 25856 25853 23492 23492 23493 25856 23493 25066 25856 24244 24237 23494 24251 24244 23494 23494 23495 24251 24260 24251 23495 23495 23496 24260 23497 23496 23495 23504 23497 23495 23496 23523 24260 23496 23507 23523 23496 23497 23507 23509 23507 23497 23510 23509 23497 23497 23504 23510 23498 23502 23503 23503 23499 23498 23499 23503 23504 24250 23512 23501 25069 23503 23502 23502 25058 25069 23502 24236 25058 23505 23504 23503 24256 23505 23503 25070 24256 23503 23503 25069 25070 23504 23505 23510 23505 24256 25077 23505 23509 23510 23514 23509 23505 25077 23514 23505 23507 23508 23523 23509 23508 23507 23508 23509 23525 23524 23523 23508 23530 23524 23508 23508 23525 23530 23509 23514 23525 25071 24278 23511 25072 25071 23511 25073 25072 23511 24259 23537 23512 23512 24250 24259 23522 23513 23512 23529 23522 23512 23537 23529 23512 23526 23525 23514 23532 23526 23514 25077 23532 23514 23517 23516 23515 23516 23517 23527 24252 23519 23516 23516 24246 24252 23516 23527 24246 24271 24270 23520 24272 24271 23520 24276 24272 23520 23520 23521 24276 23521 23528 24276 24261 24260 23523 25087 24261 23523 23523 24283 25087 23523 23524 24283 23524 23539 24283 23524 23530 23539 23531 23530 23525 23525 23526 23531 23540 23531 23526 23541 23540 23526 23526 23532 23541 24269 24246 23527 26618 24269 23527 26636 26618 23527 26639 26636 23527 23527 23547 26639 24279 24276 23528 23528 23537 24279 23530 23538 23539 23530 23531 23538 23554 23538 23531 23531 23544 23554 23531 23542 23544 23531 23540 23542 24263 23541 23532 24265 24263 23532 25077 24265 23532 25093 24282 23533 25886 25093 23534 27455 25886 23534 23534 23535 27455 23536 23535 23534 25093 23536 23534 23535 27448 27458 23535 25091 27448 25092 25091 23535 23535 23536 25092 27458 27455 23535 25869 25092 23536 23536 25071 25869 23536 24278 25071 25093 24278 23536 23537 24259 24279 23554 23539 23538 24288 24283 23539 23539 24285 24288 24292 24285 23539 23539 23554 24292 23543 23542 23540 23540 23541 23543 24277 23543 23541 23541 24263 24277 23545 23544 23542 23542 23543 23545 24289 23545 23543 23543 24280 24289 23543 24277 24280 24296 23554 23544 23544 23545 24296 23545 24295 24296 25109 24295 23545 25892 25109 23545 23545 24289 25892 23548 23547 23546 25113 23548 23546 23546 23555 25113 23547 25896 26639 23547 25895 25896 23547 23548 25895 26647 25895 23548 23548 25903 26647 23548 25113 25903 23549 24284 25100 24291 23550 23549 25100 24291 23549 23551 24282 25093 23551 23552 24282 23553 23552 23551 25886 23553 23551 23551 25093 25886 23552 23553 24284 25100 24284 23553 25102 25100 23553 26653 25102 23553 26656 26653 23553 23553 25886 26656 24294 24292 23554 24297 24294 23554 23554 24295 24297 24296 24295 23554 23555 23557 25113 23555 23556 23557 23558 23557 23556 24299 23558 23556 23557 23558 25113 23558 24302 25113 23558 24299 24302 23568 23565 23559 23560 23561 23569 23562 23561 23560 23570 23569 23561 24311 23570 23561 23561 24306 24311 23561 23562 24306 23562 24304 24306 23562 24303 24304 24307 24303 23563 25908 24307 23563 23563 23564 25908 23564 25901 25908 23565 23567 24299 23568 23567 23565 23567 23571 24308 23567 23568 23571 24308 24299 23567 23574 23573 23569 23569 23572 23574 23569 23570 23572 24311 23572 23570 24324 24308 23571 25139 23574 23572 23572 25138 25139 23572 25120 25138 23572 24311 25120 23576 23575 23573 23573 23574 23576 24334 23576 23574 25139 24334 23574 24345 23577 23575 25143 24345 23575 25144 25143 23575 23575 24335 25144 23575 24334 24335 23575 23576 24334 24345 23579 23577 23582 23581 23578 23578 23579 23582 23595 23582 23579 23579 23594 23595 24345 23594 23579 23600 23587 23583 23583 23588 23600 23589 23588 23583 23583 23584 23589 23585 23584 23583 23587 23585 23583 23592 23589 23584 23584 23590 23592 23584 23586 23590 23584 23585 23586 24349 23586 23585 25153 24349 23585 23585 24352 25153 23585 23587 24352 23591 23590 23586 24342 23591 23586 23586 24341 24342 24349 24341 23586 23587 23601 24353 23587 23600 23601 24353 24352 23587 23601 23600 23588 23604 23601 23588 23588 23589 23604 23589 23592 23604 25158 23592 23590 23590 25157 25158 23590 24351 25157 23590 23591 24351 23591 24350 24351 23591 24344 24350 23591 24342 24344 24365 23604 23592 25160 24365 23592 26697 25160 23592 23592 25158 26697 25177 23598 23596 23596 25176 25177 23596 23597 25176 23597 24362 25176 23597 23608 24362 23597 23607 23608 25177 25167 23598 24357 23609 23599 24358 24357 23599 23601 23602 24353 23603 23602 23601 24361 23603 23601 23601 23605 24361 23601 23604 23605 25171 25166 23602 25172 25171 23602 25179 25172 23602 23602 23603 25179 25166 24353 23602 25972 25179 23603 23603 24361 25972 24365 23605 23604 24364 24361 23605 24365 24364 23605 23606 24366 24367 24354 23608 23607 24355 24354 23607 23608 24356 24362 23608 24354 24356 23609 24357 24359 24359 23611 23610 23611 24359 24360 23611 24360 24368 23612 25195 25202 23613 24369 24372 24371 24369 23613 24373 24371 23613 23613 24372 24374 23618 23617 23614 25200 23618 23614 24376 24373 23616 25201 24366 23618 23618 25200 25201 23621 23620 23619 24374 23621 23619 23619 23623 24374 24378 24377 23619 23619 23620 24378 25204 24378 23620 23620 23621 25204 25205 25204 23621 23621 25198 25205 25199 25198 23621 23621 24374 25199 25989 24386 23624 23624 25208 25989 23626 23627 24384 23627 23628 24385 24385 24384 23627 23628 24381 24385 23629 24388 25993 23633 23631 23630 23630 23632 23633 24379 23632 23630 23631 23633 23634 24380 23633 23632 23632 24377 24380 24379 24377 23632 25209 24394 23633 23633 24380 25209 23636 23639 23640 25226 24397 23637 23637 24399 25226 23638 24390 24396 23641 24383 24389 25997 24383 23641 23641 24395 25997 25231 23643 23642 23642 24393 25231 25231 23646 23643 24407 24406 23644 25219 24407 23644 26007 23648 23646 23646 25230 26007 25231 25230 23646 25229 24403 23647 23647 23650 25229 23653 23652 23648 25237 23653 23648 26011 25237 23648 23648 26007 26011 24404 24395 23649 24405 24404 23649 23649 23654 24405 23650 24410 25229 23650 23651 24410 24420 24410 23651 23652 24423 24424 25236 24423 23652 23652 23653 25236 25237 25236 23653 23658 23657 23655 24422 23658 23655 24424 24422 23655 23655 23656 24424 23658 24428 24432 23658 24425 24428 23658 24422 24425 24419 23660 23659 26025 23663 23660 23660 26024 26025 23660 26012 26024 23660 24419 26012 25244 25243 23661 25265 23665 23662 26025 25265 23662 23662 23663 26025 26030 25251 23664 23664 25270 26030 23664 24450 25270 25264 25261 23665 25265 25264 23665 23683 23669 23666 24444 23683 23666 23666 24440 24444 23667 24439 26033 23667 23670 24439 23668 24449 24450 23668 23672 24449 24459 24451 23669 23669 23684 24459 23669 23683 23684 23670 23678 24439 23670 23676 23678 24455 23672 23671 25271 24449 23672 23672 25267 25271 23672 24455 25267 24451 23682 23673 23682 23674 23673 23674 24457 24467 23674 23682 24457 26825 24446 23675 23675 25272 26825 23675 24447 25272 24448 24447 23675 24445 24440 23675 24446 24445 23675 23676 23677 23678 24460 23678 23677 23677 23685 24460 25274 24439 23678 23678 24460 25274 23688 23687 23679 24462 24461 23680 24463 24462 23680 24472 24463 23680 23680 23692 24472 23680 23681 23692 24459 24457 23682 23682 24451 24459 24444 23684 23683 24476 24470 23684 25281 24476 23684 23684 24456 25281 23684 24444 24456 24470 24459 23684 23685 24454 24460 23685 23686 24454 23691 23690 23687 25275 23691 23687 23687 23688 25275 26050 25275 23688 23688 25262 26050 23688 25261 25262 23688 24443 25261 25290 24454 23689 23689 23695 25290 24477 23699 23690 23690 23691 24477 25279 24477 23691 25280 25279 23691 23691 25275 25280 24480 24472 23692 23692 23693 24480 23693 23703 24480 24494 23695 23694 23694 24493 24494 23695 24494 25290 23698 23697 23696 23696 23697 23700 23697 23698 24477 24478 23700 23697 23697 24477 24478 23698 23699 24477 23700 24478 24498 26089 24500 23701 23701 25308 26089 23701 24503 25308 23701 24498 24503 24499 23703 23702 24499 24480 23703 24495 24493 23704 23704 23705 24495 24496 24495 23705 24511 24496 23705 23705 23707 24511 23705 23706 23707 24512 24511 23707 23707 23722 24512 23708 23709 23723 24528 23723 23709 23709 24522 24528 24524 23718 23710 23710 24513 24524 23718 23711 23710 23711 23718 23724 24530 23714 23712 23712 23729 24530 23712 23713 23729 23713 23728 23729 24530 24525 23714 23720 23717 23715 23715 23719 23720 23715 23716 23719 23716 24531 24544 23716 24525 24531 23720 23719 23716 24545 23720 23716 23716 24544 24545 23725 23724 23718 24524 23725 23718 24545 23736 23720 23723 23722 23721 23722 23723 24512 24528 24512 23723 23724 23731 23734 24529 23731 23724 23724 23725 24529 23725 23726 24529 23727 23726 23725 24524 23727 23725 25322 24529 23726 26095 25322 23726 26098 26095 23726 23726 26096 26098 23726 26092 26096 23726 23727 26092 23727 24513 26092 24524 24513 23727 23730 23729 23728 23729 23730 24540 24542 24530 23729 23729 24540 24542 24541 24540 23730 23731 23732 23734 23733 23732 23731 23737 23733 23731 24538 23737 23731 23731 24529 24538 23735 23734 23732 23740 23735 23732 23732 23733 23740 23741 23740 23733 23746 23741 23733 23733 23739 23746 23733 23737 23739 23735 23740 24561 24567 24541 23735 23735 24561 24567 23737 23738 23739 24539 23738 23737 23737 24538 24539 23748 23745 23738 24560 23748 23738 23738 24550 24560 23738 24539 24550 23756 23751 23740 23740 23741 23756 23740 23751 24561 23741 23746 23756 23742 24560 25331 23742 23748 24560 23742 23743 23748 23744 23743 23742 25331 23744 23742 23755 23749 23743 24579 23755 23743 23743 24578 24579 23743 23744 24578 23743 23745 23748 23749 23745 23743 26108 24578 23744 23744 25331 26108 23747 23754 24565 23750 23751 23756 23752 23751 23750 23751 23757 24561 23751 23752 23757 24570 23764 23753 24566 24565 23754 24568 24561 23757 23757 23758 24568 23758 23759 24568 24580 24568 23759 23759 23761 24580 23759 23760 23761 23762 23761 23760 24569 23762 23760 23760 23763 24569 23761 24540 24580 25327 24540 23761 23761 23762 25327 23762 24571 25327 23762 24569 24571 24570 24569 23763 23763 23764 24570 23767 23766 23765 24586 23774 23766 23766 23767 24586 23774 23768 23766 25351 24586 23767 23767 23775 25351 26116 24566 23769 26120 26116 23769 23769 25344 26120 23769 24581 25344 27714 24590 23770 29449 27714 23770 29450 29449 23770 23770 24588 29450 24589 24588 23770 24591 24589 23770 23770 23772 24591 23770 23771 23772 25349 24591 23772 23772 24583 25349 23788 23778 23773 23773 23774 23788 24585 23788 23774 24586 24585 23774 23775 23779 25351 25362 24600 23776 23776 25361 25362 23776 24598 25361 24599 24598 23776 23776 24597 24599 23788 23787 23778 23778 23786 24605 23787 23786 23778 23779 24585 25351 23779 23788 24585 24606 23781 23780 25356 24606 23780 23780 23782 25356 24593 23783 23781 24606 24593 23781 23782 25353 25356 23782 25346 25353 23782 24587 25346 24595 23784 23783 23783 24594 24595 23783 24593 24594 23784 24595 24596 23785 24602 24612 23786 23797 24605 23789 23790 23798 24607 23798 23790 26155 26143 23791 23791 23792 26155 26956 26155 23792 23796 23795 23793 25377 23796 23793 23793 23794 25377 25388 25377 23794 24618 23802 23796 25377 24618 23796 23797 24604 24605 23797 24603 24604 24616 24603 23797 23798 24607 25368 23800 23799 23798 25368 23800 23798 24608 23805 23799 23799 23800 24608 25369 24608 23800 23800 25368 25369 23817 23812 23802 23818 23817 23802 24620 23818 23802 24621 24620 23802 23802 23803 24621 23804 23803 23802 24618 23804 23802 25395 24621 23803 23803 25378 25395 23803 23804 25378 25379 25378 23804 23804 24618 25379 24609 23806 23805 23805 24608 24609 24628 23814 23807 23807 24622 24628 23810 23809 23808 23811 23810 23808 25396 23811 23808 23808 24632 25396 23808 23815 24632 23808 23809 23815 25360 24611 23810 26128 25360 23810 26148 26128 23810 23810 25401 26148 23810 25396 25401 23810 23811 25396 23815 23816 24632 25402 24632 23816 23816 23822 25402 24623 23820 23818 23818 24620 24623 23819 23820 24631 23825 23824 23819 24631 23825 23819 23820 24635 24643 23820 24623 24635 24643 24631 23820 23823 23822 23821 25403 25402 23822 23822 24633 25403 23822 23823 24633 25409 24642 23824 23824 24647 25409 23824 23825 24647 23825 24631 24647 24645 24639 23826 24651 24645 23826 23826 23834 24651 23826 23827 23834 24650 23829 23828 23828 24629 24650 24650 23833 23829 23830 23831 24646 23831 23832 24646 24657 24646 23832 23832 24656 24657 26176 24656 23832 23832 24634 26176 23844 23841 23833 24650 23844 23833 23834 23840 24651 23841 23840 23834 23835 24665 25426 23835 24658 24665 23835 23836 24658 23837 23836 23835 23849 23837 23835 23835 23848 23849 25426 23848 23835 23836 24653 24658 25419 23839 23838 23838 24659 25419 23839 26180 26988 23839 25419 26180 26988 25418 23839 23840 23842 24651 23843 23842 23840 23840 23841 23843 23845 23843 23841 23841 23844 23845 25412 24651 23842 25421 25412 23842 23842 25420 25421 23842 24654 25420 24655 24654 23842 23842 23843 24655 23843 24660 24663 23843 23845 24660 24661 24655 23843 24663 24661 23843 26193 23845 23844 23844 24650 26193 26193 24660 23845 23847 23853 24659 25426 23851 23848 23850 23855 23856 24665 23852 23851 25426 24665 23851 24666 23855 23852 23852 24664 24666 24665 24664 23852 24670 24659 23853 24671 24670 23853 23853 23865 24671 23853 23854 23865 23854 23864 23865 23854 23858 23864 23854 23857 23858 25435 23856 23855 23855 24666 25435 25436 24667 23856 23856 25435 25436 23860 23858 23857 24676 23864 23858 24679 24676 23858 24681 24679 23858 23858 23860 24681 24672 23871 23859 23859 23861 24672 23860 23869 24681 23860 23867 23869 24677 24672 23861 23872 23868 23862 24687 23872 23862 23862 23863 24687 25468 24687 23863 23863 25467 25468 23863 25461 25467 23866 23865 23864 23875 23866 23864 23877 23875 23864 24680 23877 23864 23864 24676 24680 24675 24671 23865 23865 23866 24675 23866 23875 24675 23870 23869 23867 23868 23873 23893 23868 23872 23873 23869 23870 24681 24683 24682 23870 24682 24681 23870 23871 24684 24685 23871 24672 24684 23874 23873 23872 24687 23874 23872 23873 23874 25470 25476 23893 23873 23873 25471 25476 23873 25470 25471 23874 25468 25469 23874 24687 25468 23874 25469 25470 23875 23876 24675 23877 23876 23875 23876 24674 24675 24678 24674 23876 23876 23879 24678 23876 23878 23879 23876 23877 23878 23880 23878 23877 24690 23880 23877 23877 24680 24690 23883 23879 23878 23885 23883 23878 23878 23880 23885 23879 23884 24678 23879 23883 23884 24691 23885 23880 23880 24690 24691 23881 23889 24695 23881 23882 23889 23890 23889 23882 23895 23884 23883 24702 23895 23883 23883 23885 24702 23884 23894 24678 23895 23894 23884 24711 24702 23885 23885 24703 24711 24704 24703 23885 23885 24691 24704 23886 24682 24683 24692 24682 23886 24693 24692 23886 23886 23887 24693 23887 23898 24693 24694 23896 23888 23888 24685 24694 23889 23891 24695 23889 23890 23891 23902 23891 23890 23891 23903 24695 23891 23902 23903 25477 24697 23893 23893 25476 25477 24689 24678 23894 25478 24689 23894 23894 24700 25478 24701 24700 23894 24712 24701 23894 23894 23895 24712 24718 24712 23895 25481 24718 23895 23895 24702 25481 24722 24721 23896 23896 24694 24722 25476 24716 23897 23897 24710 25476 23897 24698 24710 24706 24693 23898 24720 24706 23898 23901 23900 23899 23903 23902 23899 23904 23903 23899 23899 23900 23904 23900 23901 23908 24708 23904 23900 23900 23913 24708 23900 23908 23913 24709 24695 23903 23903 23904 24709 24715 24709 23904 23904 24707 24715 24708 24707 23904 23905 24714 24720 24737 24714 23905 24727 23917 23906 24727 24708 23907 23907 23917 24727 24708 23913 23907 24732 24731 23909 25505 24736 23910 26238 25505 23910 23910 25497 26238 23911 23912 23919 23911 23919 24739 24729 23918 23914 23914 24728 24729 24742 23921 23915 24743 24742 23915 24729 23922 23918 23919 24736 25505 24740 24739 23919 24741 24740 23919 25505 24741 23919 24742 23928 23921 23922 23930 24752 23931 23930 23922 24729 23931 23922 24735 23926 23923 23923 23924 24735 23925 23924 23923 23948 23925 23923 25504 24735 23924 26241 25504 23924 23924 23925 26241 23925 25515 26241 23925 25512 25515 23925 23948 25512 24746 24745 23927 23927 24744 24746 23927 24742 24744 23927 23928 24742 26240 24752 23930 23930 24730 26240 23930 24729 24730 23930 23931 24729 24750 23948 23932 24757 24750 23932 23934 23935 24748 23936 23935 23934 26247 23936 23934 23934 25509 26247 23934 24748 25509 25516 23938 23935 25529 25516 23935 23935 23936 25529 23936 23953 25529 26260 23953 23936 26270 26260 23936 27881 26270 23936 23936 26248 27881 23936 26247 26248 25516 24754 23938 25510 23942 23939 25511 25510 23939 25518 25511 23939 23939 23940 25518 23941 23940 23939 25521 25518 23940 25522 25521 23940 25524 25522 23940 23940 24763 25524 23940 23941 24763 23941 23957 24763 23941 23950 23957 23941 23946 23950 25510 24748 23942 24755 23947 23943 23943 24753 24755 23943 24752 24753 23945 23949 24744 25531 23958 23947 23947 24755 25531 23948 24749 25512 24750 24749 23948 23965 23964 23951 26271 23969 23952 26274 26271 23952 23952 26269 26274 26270 26269 23952 23952 26260 26270 23952 23953 26260 23952 23969 23970 23953 25516 25529 23953 24754 25516 25524 24758 23954 25528 25524 23954 23954 23955 25528 23956 23955 23954 23955 25525 25528 25530 25525 23955 23955 24759 25530 25537 23975 23958 23958 25531 25537 26255 24757 23959 26256 26255 23959 23959 25532 26256 25533 25532 23960 23960 24764 25533 23960 23961 24764 23964 23965 23968 26271 25549 23969 23974 23972 23971 23972 24761 24762 23972 24759 24761 25536 24759 23972 23972 23974 25536 25550 25536 23974 23974 24773 25550 23974 23975 24773 25537 24773 23975 25539 24767 23976 23976 25538 25539 24767 23977 23976 24768 23978 23977 23977 24767 24768 23979 24770 25541 24769 23981 23980 24769 23983 23981 25563 24791 23982 23982 23985 25563 24769 23987 23983 24771 24770 23984 24790 24771 23984 23984 24780 24790 23984 23988 24780 25565 25563 23985 23985 24785 25565 23985 23986 24785 24792 24785 23986 25554 24779 23987 25555 25554 23987 23987 24774 25555 23987 24769 24774 24783 24782 23989 25557 24783 23989 23989 24781 25557 23990 26283 26284 23990 23991 26283 27156 26283 23991 27931 27156 23991 23991 27155 27931 23991 25562 27155 23992 24782 24783 23994 23995 24002 24014 24001 23994 24015 24014 23994 23995 23997 24002 24788 24786 23996 23999 24010 24793 24805 24792 24000 24000 24011 24805 24003 24004 24795 24797 24796 24004 24004 24005 24797 24796 24795 24004 24806 24797 24005 24798 24007 24006 24006 24009 24798 24006 24008 24009 24808 24806 24007 24809 24808 24007 24007 24798 24809 24799 24798 24009 24009 24017 24799 24794 24793 24010 24011 24020 24805 24011 24012 24020 24800 24799 24017 25574 24820 24019 24019 25573 25574 24019 24812 25573 24019 24810 24812 24819 24805 24020 24832 24819 24021 24833 24832 24021 24836 24833 24022 24022 24027 24836 24022 24023 24027 25594 24837 24024 25595 25594 24024 24024 24025 25595 24026 24025 24024 24829 24026 24024 24025 25578 25595 24025 25575 25578 25584 25575 24025 24025 25577 25584 24025 24026 25577 24026 24820 25577 24842 24836 24027 24843 24842 24027 24027 24838 24843 24027 24032 24838 24840 24839 24029 24841 24840 24029 24029 24030 24841 25594 24841 24030 24030 24837 25594 24035 24033 24031 24036 24035 24031 24866 24855 24033 24033 24035 24866 24041 24037 24034 24855 24041 24034 24035 24852 24866 24035 24844 24852 24035 24036 24844 24036 24839 24844 24040 24039 24038 25608 24040 24038 24038 25597 25608 24038 24044 25597 24038 24043 24044 25613 24858 24039 26336 25613 24039 24039 24040 26336 24040 25608 26336 24855 24051 24041 24042 24857 24867 24867 24856 24042 24045 24044 24043 24046 24045 24043 25619 25597 24044 26347 25619 24044 24044 24048 26347 24044 24047 24048 24044 24045 24047 24045 24046 24047 24056 24047 24046 24876 24048 24047 24047 24060 24876 24047 24056 24060 27211 26347 24048 24048 24876 27211 24049 24052 24053 24049 24050 24052 24864 24052 24050 24050 24057 24864 24050 24054 24057 24051 24874 24875 24051 24855 24874 24052 24869 24878 24870 24869 24052 24052 24864 24870 24878 24053 24052 24066 24061 24053 24878 24066 24053 24865 24057 24054 24054 24849 24865 24851 24849 24054 24054 24055 24851 24879 24851 24055 24057 24846 24864 24865 24846 24057 24876 24060 24058 26349 24876 24058 24058 24059 26349 24060 24059 24058 26371 26349 24059 24059 26369 26371 24059 25630 26369 24059 24060 25630 24060 24063 25630 24066 24065 24061 24062 24067 24879 25634 25630 24063 25635 25634 24063 24063 24064 25635 24888 24068 24065 24065 24066 24888 24889 24888 24066 24066 24878 24889 25624 24879 24067 25625 25624 24067 25638 25625 24067 24069 24891 25642 24070 25642 25662 24071 24072 24081 24908 24081 24072 24072 24907 24908 25665 24907 24072 24072 24902 25665 24903 24902 24072 25660 24903 24072 24900 24895 24073 24076 24075 24074 24077 24076 24074 25664 24887 24076 24076 25663 25664 24076 24901 25663 24076 24077 24901 24905 24901 24077 24077 24078 24905 24079 24078 24077 24080 24079 24077 24078 24079 25668 24078 24904 24905 25668 24904 24078 24079 24080 25668 24080 24909 25668 24910 24909 24080 24907 24083 24082 24908 24907 24082 25669 24086 24083 24083 24907 25669 24915 24910 24084 24084 24087 24915 25669 25665 24085 24085 24086 25669 24087 24086 24085 24914 24087 24085 26408 24914 24085 24085 25665 26408 24087 24914 28972 28072 24915 24087 28972 28072 24087 24917 24089 24088 24918 24917 24088 25671 24090 24089 25673 25671 24089 25674 25673 24089 24089 24917 25674 25671 25670 24090 24090 24091 24092 25670 24091 24090 25670 24916 24091 24916 24092 24091 25672 24918 24093 24093 24921 25672 24923 24096 24094 25681 24097 24095 26417 25681 24095 24095 25682 26417 24095 24096 25682 24096 24923 25682 25681 24925 24097 24926 24099 24098 24098 24925 24926 25685 24927 24099 24099 24926 25685 24100 24930 25692 24100 24101 24930 25699 24929 24100 24100 25692 25699 24101 24108 24930 24928 24106 24102 24105 24104 24103 25697 24105 24103 25698 25697 24103 24103 24106 25698 24103 24104 24107 25717 25703 24105 25718 25717 24105 26421 25718 24105 24105 25697 26421 24106 24928 25698 24108 24110 24930 24108 24109 24110 24110 24931 24932 25692 24930 24110 24110 24932 25692 24937 24936 24111 24938 24937 24111 24111 24935 24938 24112 24113 25732 25723 24943 24112 26450 25723 24112 24112 25740 26450 24112 25732 25740 24113 24950 25732 24113 24124 24950 24113 24117 24124 24116 24115 24114 25719 24116 24114 25727 25719 24114 24114 24948 25727 24115 24940 24941 24115 24939 24940 24115 24116 24939 25719 24939 24116 24130 24124 24117 24944 24139 24118 24952 24948 24119 24953 24952 24119 24119 24131 24953 24124 24121 24120 24950 24124 24120 25732 24950 24120 24120 25731 25732 26448 25731 24120 26449 26448 24120 24120 25729 26449 24120 24122 25729 24123 24122 24120 24121 24124 24129 26441 25729 24122 26447 26441 24122 24122 26440 26447 24122 24123 26440 24123 24125 24136 24127 24125 24123 24123 24949 26440 24123 24136 24949 24130 24129 24124 24127 24126 24125 24125 24126 24136 24126 24127 24128 24126 24135 24136 24137 24135 24126 24126 24128 24137 24138 24137 24128 24159 24138 24128 24128 24158 24159 24128 24149 24158 25741 24953 24131 25744 25741 24131 24131 24142 25744 24954 24133 24132 25736 24954 24132 24132 24942 25736 25747 24969 24133 25756 25747 24133 24133 24954 25756 26470 24957 24134 24134 24180 26470 24134 24159 24180 24134 24143 24159 24134 24135 24143 24136 24135 24134 24957 24136 24134 24135 24138 24143 24135 24137 24138 25739 25738 24136 26468 25739 24136 24136 24957 26468 25738 24949 24136 24159 24143 24138 24141 24140 24139 24955 24141 24139 24139 24951 24955 24139 24944 24951 24963 24144 24140 25757 24963 24140 25758 25757 24140 24140 24141 25758 26469 25758 24141 24141 25742 26469 24141 24955 25742 24142 24956 25744 24963 24150 24144 24968 24147 24145 24145 24151 24968 24147 24146 24145 25759 24148 24146 25760 25759 24146 24146 24147 25760 24147 24968 25760 25759 24956 24148 24163 24158 24149 24149 24162 24163 24967 24164 24150 24150 24963 24967 24151 24165 24968 24152 24176 24964 24152 24170 24176 24152 24153 24170 24154 24153 24152 24964 24154 24152 24153 24154 24156 24154 24155 24156 24965 24155 24154 24154 24960 24965 24154 24959 24960 24964 24959 24154 25768 25764 24155 24155 24965 25768 24157 24156 24155 25764 24157 24155 24157 24177 24178 24981 24177 24157 25764 24981 24157 24163 24159 24158 24159 24163 24977 24181 24180 24159 24977 24181 24159 24160 24161 24958 24169 24168 24160 24958 24169 24160 24161 24176 24958 24970 24176 24161 24974 24970 24161 24161 24969 24974 24977 24163 24162 24162 24184 24977 24164 24978 24982 24979 24978 24164 24164 24967 24979 24972 24968 24165 24165 24166 24972 24980 24972 24166 24168 24169 24171 24176 24171 24169 24958 24176 24169 24170 24171 24176 24172 24173 24185 24174 24173 24172 24179 24174 24172 24172 24178 24179 24188 24185 24173 24998 24188 24173 24173 24990 24998 24991 24990 24173 25005 24991 24173 24173 24174 25005 25007 25005 24174 24174 24992 25007 24174 24186 24992 24174 24179 24186 24989 24985 24175 24175 24984 24989 24175 24982 24984 24970 24964 24176 24981 24976 24177 24179 24178 24177 24976 24179 24177 24975 24186 24179 24976 24975 24179 27321 26470 24180 27335 27321 24180 24180 26477 27335 24180 24181 26477 24181 24977 26477 24993 24187 24182 24182 24189 24993 24187 24183 24182 24977 24184 24183 25774 24977 24183 24183 24187 25774 25008 24992 24186 25772 25008 24186 24186 24987 25772 24186 24975 24987 26489 25774 24187 26492 26489 24187 24187 24993 26492 24189 24190 24993 24190 24191 24993 25786 24993 24191 26495 25786 24191 24191 25787 26495 24192 25000 25791 25791 24193 24192 24997 24996 24193 25791 24997 24193 24194 24195 24196 24197 24196 24195 24196 24197 25001 25004 25001 24197 24201 24200 24199 24208 24201 24199 26517 25009 24200 26522 26517 24200 27368 26522 24200 24200 26530 27368 24200 25010 26530 24200 24201 25010 24201 24208 25022 25022 25010 24201 25014 25013 24202 25020 25014 24202 25025 25020 24202 25016 24204 24203 25805 25016 24203 25807 25805 24203 24203 25015 25807 24203 25013 25015 25815 24212 24204 25816 25815 24204 24204 25016 25816 25022 24208 24205 24205 24206 25022 24207 24206 24205 24206 25010 25022 25824 25010 24206 24206 25822 25824 25011 24219 24209 25023 24211 24210 25024 24215 24211 25830 25024 24211 24211 25023 25830 25815 24216 24212 25831 25026 24213 25832 25831 24213 24213 24219 25832 25827 25030 24214 24214 24215 25827 24215 25024 25827 24216 25815 25817 25817 25018 24216 25823 25822 24217 24217 24218 25823 24218 25017 25823 24219 25825 25832 24219 25011 25825 25028 25023 24220 24220 24221 25028 24221 25027 25028 24221 24224 25027 25043 24229 24222 24222 25032 25043 25035 24224 24223 24223 25033 25035 24223 24230 25033 25035 25027 24224 25042 25038 24226 24226 24227 25042 25843 25042 24227 24227 24233 25843 25047 24231 24228 24228 24229 25047 25049 25047 24229 25837 25049 24229 24229 25043 25837 25034 25033 24230 24230 24231 25034 25840 25034 24231 24231 25049 25840 24231 25047 25049 24233 25053 25843 25056 24236 24234 24234 25050 25056 25068 25050 24234 24234 24235 25068 24236 24235 24234 24235 25050 25068 24236 25056 25058 24244 24243 24237 25067 25066 24238 24238 24239 25067 24239 25057 25067 25852 25063 24240 24240 25851 25852 24240 25060 25851 24240 24241 25060 25062 25060 24241 24241 24253 25062 25859 25075 24242 24242 25853 25859 25075 25065 24242 24243 24244 25057 25860 25057 24244 26596 25860 24244 26597 26596 24244 26609 26597 24244 24244 25874 26609 24244 25079 25874 24244 24251 25079 26603 26602 24245 24245 24246 26603 24247 24246 24245 25867 24247 24245 26601 25867 24245 26602 26601 24245 24246 24247 24252 24246 24269 26603 25062 24253 24247 24247 25059 25062 25867 25059 24247 25074 25073 24248 24248 24255 25074 24248 24254 24255 25064 24259 24249 24259 24250 24249 24251 24262 25079 24251 24261 24262 24251 24260 24261 25870 24255 24254 25871 25870 24254 24254 25080 25871 24254 24257 25080 25862 25074 24255 25870 25862 24255 25866 25076 24256 24256 25865 25866 24256 25070 25865 24256 25076 25077 25081 25080 24257 24257 24258 25081 25086 25081 24258 24258 24270 25086 25065 24279 24259 24259 25064 25065 25087 24262 24261 25094 25079 24262 24262 25087 25094 24281 24277 24263 25088 24281 24263 25090 25088 24263 24263 24264 25090 24265 24264 24263 25875 25090 24264 25876 25875 24264 26599 25876 24264 24264 25085 26599 24264 24265 25085 25872 25085 24265 24265 25077 25872 28234 26612 24266 24266 24267 28234 24268 24267 24266 26612 24268 24266 24267 28231 28232 24267 27419 28231 24267 24268 27419 28244 28234 24267 24267 28232 28244 24268 26600 27419 24268 25876 26600 26612 25876 24268 26616 26603 24269 26618 26616 24269 24270 24271 25086 24271 25081 25086 25863 25081 24271 24271 24274 25863 24271 24272 24274 24272 24273 24274 24276 24273 24272 24275 24274 24273 25065 24275 24273 24273 24279 25065 24273 24276 24279 24274 24275 25863 24275 25075 25863 24275 25065 25075 24281 24280 24277 24290 24289 24280 25095 24290 24280 24280 24281 25095 25884 25095 24281 24281 25877 25884 24281 25088 25877 24283 24286 25087 24288 24286 24283 24285 24286 24288 24287 24286 24285 24293 24287 24285 24285 24292 24293 25099 25087 24286 24286 24287 25099 24287 25097 25099 25104 25097 24287 25105 25104 24287 25107 25105 24287 24287 24293 25107 24289 24290 25892 24290 25891 25892 24290 25884 25891 24290 25095 25884 25102 25101 24291 24291 25100 25102 24294 24293 24292 25111 25107 24293 25112 25111 24293 24293 25108 25112 24293 24294 25108 25110 25108 24294 24294 24297 25110 25109 24297 24295 24297 25109 25110 24324 24302 24299 24299 24308 24324 26654 26647 24300 28275 26654 24300 28301 28275 24300 24300 24301 28301 24302 24301 24300 25903 24302 24300 26647 25903 24300 29223 28301 24301 32736 29223 24301 33584 32736 24301 34487 33584 24301 35392 34487 24301 24301 24302 35392 25903 25113 24302 35394 35392 24302 24302 35393 35394 36131 35393 24302 36134 36131 24302 24302 27503 36134 27505 27503 24302 29231 27505 24302 24302 27524 29231 24302 26723 27524 24302 24324 26723 24305 24304 24303 24307 24305 24303 24310 24306 24304 24304 24309 24310 25115 24309 24304 24304 24305 25115 25907 25115 24305 25908 25907 24305 24305 24307 25908 24306 24310 24311 25128 25127 24309 25904 25128 24309 24309 25114 25904 25115 25114 24309 24311 24310 24309 25120 24311 24309 25127 25120 24309 24312 24321 24331 24312 24315 24321 24312 24313 24315 24314 24313 24312 24331 24314 24312 25117 24315 24313 24313 25116 25117 25122 25116 24313 25129 25122 24313 24313 24314 25129 24314 24327 25129 24329 24327 24314 24331 24329 24314 25909 24321 24315 24315 25123 25909 24315 25119 25123 24315 25117 25119 24322 24320 24316 25912 24322 24316 24316 24317 25912 24318 24317 24316 24320 24318 24316 24317 24321 25912 24317 24318 24321 24331 24321 24318 24318 24329 24331 24318 24326 24329 24318 24325 24326 24318 24319 24325 24320 24319 24318 24330 24325 24319 24319 24323 24330 24319 24320 24323 24320 24322 24323 24321 25909 25912 25125 25124 24322 25921 25125 24322 24322 25912 25921 25124 24323 24322 24332 24330 24323 24333 24332 24323 25124 24333 24323 24324 25174 26723 24336 24326 24325 24325 24332 24336 24325 24330 24332 24340 24329 24326 24348 24340 24326 25147 24348 24326 24326 24336 25147 25145 25129 24327 24327 24338 25145 24327 24328 24338 24329 24328 24327 24328 24329 24340 24328 24337 24338 24346 24337 24328 24347 24346 24328 24328 24340 24347 25939 24336 24332 25940 25939 24332 24332 25936 25940 24332 24333 25936 24333 25924 25936 24333 25126 25924 24333 25124 25126 26676 25142 24334 24334 25139 26676 25142 24335 24334 24335 25142 25144 25939 25147 24336 25156 24339 24337 24337 24346 25156 24339 24338 24337 24338 24339 25145 24339 25156 25944 25938 25145 24339 25945 25938 24339 24339 25944 25945 24348 24347 24340 24343 24342 24341 24349 24343 24341 24342 24343 24344 25132 24344 24343 25937 25132 24343 24343 24349 25937 25141 24350 24344 24344 25133 25141 24344 25132 25133 25164 25161 24345 24345 25143 25164 25950 25156 24346 24346 25949 25950 24346 24347 25949 24347 24348 25949 24348 25147 25949 24349 25931 25937 24349 25152 25931 25153 25152 24349 25154 24351 24350 25155 25154 24350 24350 25141 25155 24351 25154 25157 25163 25153 24352 25166 25163 24352 24352 24353 25166 25165 24356 24354 24354 24355 25165 24355 25161 25165 25175 24362 24356 25181 25175 24356 25957 25181 24356 24356 25165 25957 24360 24359 24357 24363 24360 24357 24357 24358 24363 24358 25167 25954 25954 24363 24358 25186 24368 24360 24360 25178 25186 24360 24363 25178 24361 25182 25972 24361 24364 25182 24362 25175 25176 25954 25178 24363 25190 25182 24364 25971 25190 24364 24364 25185 25971 24364 25159 25185 24364 24365 25159 25160 25159 24365 25173 24367 24366 25979 25173 24366 24366 25201 25979 24367 25173 25174 24368 25186 25195 24369 24370 24372 24371 24370 24369 24370 24371 25194 25194 24372 24370 24371 24373 25196 25196 25194 24371 25196 24374 24372 24372 25194 25196 25203 25197 24373 24373 24376 25203 25197 25196 24373 24374 25196 25199 25975 25208 24375 24375 25202 25975 24377 24378 24380 25209 24380 24378 24378 25204 25209 24381 24387 24391 24391 24385 24381 24382 24383 25212 26752 25995 24382 26756 26752 24382 24382 25212 26756 25997 25212 24383 24384 24385 25216 25216 24390 24384 24385 24391 25216 25992 24387 24386 24386 25989 25992 25992 24391 24387 24388 25217 25993 24388 24400 25217 25218 24396 24390 24390 25213 25218 25216 25213 24390 25996 25216 24391 24391 25992 25996 25219 24398 24392 25220 25219 24392 24392 24397 25220 26004 25231 24393 26763 26004 24393 24393 25224 26763 24393 24394 25224 25994 25224 24394 24394 25209 25994 24395 25232 25997 24395 24404 25232 25218 24399 24396 26005 25220 24397 24397 25227 26005 24397 25226 25227 24399 25225 25226 24399 25218 25225 26001 25217 24400 24400 24401 26001 24401 24409 26001 24401 24408 24409 24401 24402 24408 24402 24403 24408 24409 24408 24403 26766 24409 24403 26767 26766 24403 24403 25229 26767 26009 25232 24404 24404 25238 26009 24404 24405 25238 25243 25238 24405 25228 24419 24407 24407 25219 25228 24409 26000 26001 27586 26000 24409 24409 26766 27586 24410 24421 25229 24410 24420 24421 24418 24417 24411 25241 24418 24411 24411 24414 25241 24416 24414 24411 24411 24412 24416 24413 24412 24411 24417 24413 24411 24412 24413 25240 26014 24416 24412 24412 25240 26014 24413 24426 25240 25242 25241 24414 26016 25242 24414 24414 26015 26016 24414 24415 26015 24416 24415 24414 26786 26015 24415 24415 24416 26786 24416 26014 26786 26013 26012 24419 24419 25221 26013 25228 25221 24419 25245 24421 24420 25235 25233 24421 25245 25235 24421 25233 25229 24421 24424 24423 24422 24427 24425 24422 24422 24423 24427 25246 24427 24423 24423 25236 25246 25255 24428 24425 24425 24427 25255 24427 25246 25255 24428 24431 24432 24428 24429 24431 24430 24429 24428 25256 24430 24428 24428 25255 25256 26800 24431 24429 26811 26800 24429 24429 24430 26811 27609 26811 24430 24430 25256 27609 26796 24433 24431 26800 26796 24431 24433 24432 24431 24432 24433 25247 26795 26786 24433 26796 26795 24433 26014 25247 24433 26786 26014 24433 24436 24435 24434 25259 24436 24434 24435 24436 24442 24442 24441 24435 25259 24442 24436 24437 26022 26033 26034 26022 24437 26035 26034 24437 24437 24438 26035 24439 24438 24437 26033 24439 24437 26037 26035 24438 24438 26036 26037 24438 24439 26036 26046 26036 24439 24439 25274 26046 24445 24444 24440 24452 24448 24441 24453 24452 24441 25260 24453 24441 24441 24442 25260 24442 25259 25260 26064 24456 24444 24444 24445 26064 24445 24446 26064 26836 26064 24446 24446 26825 26836 25273 25272 24447 26818 25273 24447 24447 26043 26818 24447 24452 26043 24447 24448 24452 25271 24450 24449 25271 25270 24450 24452 24453 26043 26044 26043 24453 26045 26044 24453 24453 25260 26045 26063 24460 24454 24454 25291 26063 24454 25290 25291 24455 25266 25267 26052 25266 24455 26823 26052 24455 24455 25287 26823 24455 24461 25287 25282 25281 24456 25283 25282 24456 26064 25283 24456 24468 24467 24457 24469 24468 24457 24457 24458 24469 24459 24458 24457 24473 24469 24458 24458 24471 24473 24458 24459 24471 24459 24470 24471 26046 25274 24460 26059 26046 24460 26063 26059 24460 24461 24462 25287 27619 25287 24462 28439 27619 24462 24462 27623 28439 24462 24463 27623 27627 27623 24463 24463 26068 27627 24463 24506 26068 24463 24505 24506 24463 24472 24505 24513 24508 24464 25316 24513 24464 25317 25316 24464 24464 24465 25317 24466 24465 24464 24465 24466 24481 24465 25312 25317 24465 24481 25312 24507 24481 24466 25297 25296 24469 25298 25297 24469 24469 24473 25298 24474 24473 24470 24476 24474 24470 24473 24471 24470 24472 24499 24505 24472 24480 24499 24473 24474 25298 25303 25298 24474 25305 25303 24474 24474 24475 25305 24476 24475 24474 24475 25288 25305 24475 24485 25288 24475 24476 24485 25282 24485 24476 24476 25281 25282 24479 24478 24477 25293 24479 24477 25294 25293 24477 24477 25279 25294 24503 24498 24478 24478 24497 24503 24478 24479 24497 25292 24497 24479 25293 25292 24479 24481 25295 25312 24481 24507 25295 24489 24486 24482 24482 24485 24489 24482 24483 24485 24484 24483 24482 24486 24484 24482 25288 24485 24483 25306 25288 24483 24483 24484 25306 24484 24501 25306 24484 24490 24501 24484 24486 24490 26069 24489 24485 24485 25289 26069 24485 25282 25289 24486 24487 24490 24488 24487 24486 24489 24488 24486 24502 24490 24487 24487 24488 24502 24510 24502 24488 24488 24509 24510 24488 24489 24509 26070 24509 24489 24489 26069 26070 24490 24491 24501 24492 24491 24490 24502 24492 24490 24517 24501 24491 24518 24517 24491 24491 24492 24518 25323 24518 24492 24492 24502 25323 24495 24494 24493 25300 25290 24494 24494 24496 25300 24494 24495 24496 25301 25300 24496 24496 24511 25301 25307 24503 24497 24497 25302 25307 24497 25292 25302 24499 24504 24505 25309 24504 24499 24499 24500 25309 26089 25309 24500 24501 24516 25315 24517 24516 24501 25315 25306 24501 26077 25323 24502 26078 26077 24502 24502 24510 26078 26082 25308 24503 24503 25307 26082 24506 24505 24504 26076 24506 24504 24504 25309 26076 26076 26068 24506 25299 24510 24509 26071 25299 24509 24509 26070 26071 26846 26078 24510 24510 25299 26846 24511 24512 25301 24512 24528 25301 26093 26092 24513 24513 25316 26093 25314 25313 24514 26090 25314 24514 24514 24546 26090 24514 24515 24546 24516 24515 24514 25315 24516 24514 24514 25313 25315 24548 24546 24515 24515 24535 24548 24515 24527 24535 24515 24516 24527 24516 24517 24527 24517 24526 24527 24517 24518 24526 25319 24526 24518 25323 25319 24518 24519 26854 26855 28491 26854 24519 28504 28491 24519 24519 24520 28504 24521 24520 24519 26855 24521 24519 29399 28504 24520 29400 29399 24520 24520 26868 29400 24520 24521 26868 24521 25320 26868 24521 24522 25320 24528 24522 24521 25301 24528 24521 26855 25301 24521 24522 25318 25320 24522 24523 25318 25325 25318 24523 24523 24558 25325 24525 24530 24531 24535 24527 24526 24536 24535 24526 25319 24536 24526 25322 24538 24529 25324 24531 24530 24530 24542 25324 24571 24543 24531 25324 24571 24531 24531 24543 24544 26872 24547 24532 24532 24533 26872 24534 24533 24532 24547 24534 24532 26899 26872 24533 24533 26109 26899 24533 24534 26109 24534 25337 26109 24534 25335 25337 24534 25334 25335 24534 24552 25334 24534 24551 24552 24553 24551 24534 24534 24547 24553 24549 24548 24535 24535 24537 24549 24535 24536 24537 25328 24537 24536 26876 25328 24536 24536 25319 26876 24555 24549 24537 25328 24555 24537 24550 24539 24538 25326 24550 24538 24538 25322 25326 24540 24541 24567 25327 24542 24540 24540 24567 24580 25327 25324 24542 24571 24563 24543 26091 26090 24546 26867 26091 24546 24546 24547 26867 24548 24547 24546 24547 26872 26883 24547 24548 24553 26883 26867 24547 24548 24549 24553 24549 24555 24556 24549 24551 24553 24554 24551 24549 24556 24554 24549 25331 24560 24550 24550 25326 25331 24554 24552 24551 24552 24564 25334 24552 24554 24564 24572 24564 24554 24573 24572 24554 24554 24556 24573 24574 24557 24555 25332 24574 24555 24555 25328 25332 24557 24556 24555 24556 24557 24573 24574 24573 24557 25329 25325 24558 24558 24559 25329 25330 25329 24559 25333 25330 24559 24559 24565 25333 24568 24567 24561 24562 24569 24570 24571 24569 24562 24562 24563 24571 25339 25334 24564 24564 24575 25339 24564 24572 24575 24565 24566 25333 26112 25333 24566 26116 26112 24566 24567 24568 24580 24571 25324 25327 24572 24573 24575 24573 24574 24575 24577 24575 24574 24574 24576 24577 25332 24576 24574 24575 24577 25339 24576 26110 26910 26111 26110 24576 26901 26111 24576 24576 25332 26901 26107 24577 24576 26910 26107 24576 25342 25339 24577 25343 25342 24577 26107 25343 24577 25340 24579 24578 26121 25340 24578 24578 26113 26121 24578 26108 26113 25345 24587 24579 24579 25341 25345 24579 25340 25341 24581 24582 25344 24582 24590 25344 24583 24592 25349 24583 24584 24592 24584 25364 25366 24584 24603 25364 26125 24592 24584 24584 25367 26125 24584 25366 25367 24585 24586 25351 24587 25345 25346 30396 29450 24588 24588 29459 30396 24588 28558 29459 24588 24589 28558 24589 24591 28558 26939 25344 24590 27713 26939 24590 27714 27713 24590 28570 28558 24591 24591 27715 28570 24591 25350 27715 24591 25349 25350 26125 25349 24592 25357 24594 24593 24593 24606 25357 26129 24595 24594 24594 25357 26129 26139 24596 24595 26140 26139 24595 24595 26129 26140 24596 26139 26947 25360 24599 24597 24597 24611 25360 26940 25363 24598 24598 26127 26940 24598 24599 26127 25363 25361 24598 24599 25360 26127 24602 24601 24600 25380 24602 24600 24600 25362 25380 24602 25380 26133 25383 25364 24603 24603 24614 25383 24616 24614 24603 24606 25355 25357 25356 25355 24606 26948 25368 24607 24607 25358 26948 25359 25358 24607 25370 24609 24608 24608 25369 25370 24609 25370 25371 25390 24617 24613 24614 24615 25383 25384 25383 24615 24617 25390 25391 24618 25377 25389 26156 25379 24618 24618 25389 26156 25382 25381 24619 25385 25382 24619 25392 25385 24619 25393 25392 24619 24619 25391 25393 24620 24621 25395 24624 24623 24620 25395 24624 24620 24622 24625 24626 25399 24628 24622 24622 24626 25399 24649 24635 24623 24623 24624 24649 26175 24649 24624 24624 26159 26175 24624 25378 26159 25395 25378 24624 25405 24626 24625 24625 25404 25405 24625 24627 25404 25405 25399 24626 25406 25404 24627 25399 24638 24628 26182 24650 24629 24629 24630 26182 27779 26182 24630 28624 27779 24630 24630 28614 28624 24630 27752 28614 24631 24643 24647 25402 25396 24632 24633 24640 25403 26179 26176 24634 24634 24641 26179 24637 24636 24635 24649 24637 24635 24635 24636 24643 24636 24637 25410 24648 24643 24636 25411 24648 24636 24636 25410 25411 26174 25410 24637 24637 24649 26174 25400 24644 24638 24638 25399 25400 25403 24640 24639 24639 24645 25403 24641 24642 26179 24642 25414 26179 24642 25409 25414 24648 24647 24643 24644 25400 26166 24645 24652 25403 24645 24651 24652 24657 24653 24646 25413 25409 24647 25415 25413 24647 24647 24648 25415 24648 25411 25415 26976 26174 24649 24649 26175 26976 26996 26193 24650 24650 26182 26996 25412 24652 24651 25407 25403 24652 26981 25407 24652 24652 26177 26981 24652 25412 26177 24653 24657 24658 25425 25420 24654 25429 25425 24654 24654 24661 25429 24654 24655 24661 24656 26176 26178 24658 24657 24656 26178 24658 24656 24658 24664 24665 24666 24664 24658 26178 24666 24658 26181 25419 24659 26192 26181 24659 24659 25424 26192 24659 24670 25424 25453 24663 24660 24660 25452 25453 26193 25452 24660 24661 24662 25429 24663 24662 24661 25448 25429 24662 25454 25448 24662 24662 24663 25454 24663 25447 25454 25453 25447 24663 26178 25435 24666 25436 24668 24667 25439 24669 24668 24668 25438 25439 24668 25436 25438 24669 25439 25458 24670 25423 25424 24670 24671 25423 24671 24673 25423 24674 24673 24671 24675 24674 24671 24672 24677 24684 25428 25423 24673 27014 25428 24673 24673 25463 27014 24673 24678 25463 24673 24674 24678 24676 24679 24680 24686 24684 24677 24688 24686 24677 24678 24689 25463 24681 24680 24679 24680 24682 24690 24680 24681 24682 24692 24690 24682 24686 24685 24684 24685 24688 24694 24685 24686 24688 24696 24694 24688 24688 24695 24696 27016 25463 24689 24689 26214 27016 24689 25478 26214 24692 24691 24690 24691 24692 24704 24692 24693 24704 24705 24704 24693 24706 24705 24693 24694 24696 24722 24709 24696 24695 24696 24709 24722 25477 24699 24697 24699 24698 24697 24698 24699 24710 25477 24710 24699 26213 25478 24700 24700 24701 26213 26221 26213 24701 24701 24717 26221 24701 24712 24717 24702 24719 25481 24702 24711 24719 24719 24711 24703 24703 24713 24719 24703 24705 24713 24703 24704 24705 24705 24706 24720 24714 24713 24705 24720 24714 24705 24721 24715 24707 24707 24708 24721 24709 24715 24722 25477 25476 24710 24718 24717 24712 25490 24719 24713 24713 24714 25490 25501 25490 24714 24714 24737 25501 24715 24721 24722 24716 25476 25487 27064 26221 24717 24717 25488 27064 25489 25488 24717 24717 24718 25489 24718 25481 25489 25491 25481 24719 24719 25490 25491 25486 24726 24723 24733 24728 24724 24724 24725 24733 24726 24725 24724 25494 24733 24725 24725 25482 25494 25485 25482 24725 25486 25485 24725 24725 24726 25486 24730 24729 24728 25492 24730 24728 25494 25492 24728 24728 24733 25494 24730 25499 26240 25500 25499 24730 24730 25493 25500 24730 25492 25493 24731 24732 25497 24732 24734 25497 25496 25495 24734 24734 24735 25496 25498 25497 24734 24734 25495 25498 26235 25496 24735 26236 26235 24735 26237 26236 24735 24735 25504 26237 24737 24738 25501 25507 25501 24738 24738 24740 25507 24738 24739 24740 25508 25507 24740 24740 25506 25508 24740 24741 25506 24741 25505 25506 24747 24746 24744 25513 24751 24745 24745 24746 25513 24746 24747 25513 24747 24751 25513 25510 25509 24748 24749 24750 25512 24750 24756 25512 24757 24756 24750 25514 24753 24752 27090 25514 24752 24752 26244 27090 24752 26240 26244 26261 24755 24753 24753 25520 26261 24753 25514 25520 26261 25531 24755 26255 25512 24756 24756 24757 26255 25524 24763 24758 24759 25527 25530 27131 25527 24759 24759 25536 27131 24759 24760 24761 24762 24761 24760 24764 24765 25533 24765 24766 25533 25534 25533 24766 25535 25534 24766 25540 25535 24766 25539 24768 24767 24776 24775 24768 25547 24776 24768 24768 25539 25547 24774 24769 24768 24775 24774 24768 24770 24771 25541 24790 24787 24771 25548 25541 24771 25556 25548 24771 24771 24789 25556 24771 24787 24789 24772 25549 25551 26276 25550 24773 24773 25543 26276 24773 25542 25543 24773 25537 25542 26278 25555 24774 24774 24775 26278 24775 27140 27910 24775 24776 27140 27149 26278 24775 27910 27149 24775 24776 25547 27140 24789 24788 24777 25556 24789 24777 24777 24778 25556 24779 24778 24777 25564 25556 24778 26280 25564 24778 24778 24779 26280 27141 26280 24779 24779 25554 27141 24780 24787 24790 24780 24786 24787 24783 25558 25559 24783 25551 25558 25557 25551 24783 24785 24792 25565 24788 24787 24786 24787 24788 24789 26282 25538 24791 27150 26282 24791 24791 25563 27150 24792 24805 25565 24803 24802 24793 24804 24803 24793 24793 24794 24804 24795 24796 24811 24812 24811 24796 24796 24797 24812 24813 24812 24797 24816 24813 24797 24797 24806 24816 24798 24799 24809 24828 24809 24799 25566 24828 24799 24799 24800 25566 25567 25566 24800 24800 24801 25567 24801 24802 25567 24802 24803 25567 25571 25567 24803 24803 25570 25571 24803 24804 25570 24804 25569 25570 26284 25569 24804 26286 25565 24805 24805 26285 26286 26288 26285 24805 26289 26288 24805 24805 24819 26289 24806 24807 24816 24808 24807 24806 24807 24815 24816 24817 24815 24807 24818 24817 24807 24807 24808 24818 24828 24818 24808 24808 24809 24828 24810 24811 24812 24812 24814 25573 24812 24813 24814 24816 24815 24813 24815 24814 24813 24814 24821 25573 24825 24821 24814 24814 24815 24825 24815 24817 24825 24817 24824 24825 24817 24818 24824 24826 24824 24818 24828 24826 24818 24819 24832 26289 24820 25574 25577 24821 24822 25573 24823 24822 24821 24825 24823 24821 25584 25579 24822 24822 25575 25584 24822 24823 25575 25574 25573 24822 25579 25574 24822 25586 25575 24823 25587 25586 24823 25588 25587 24823 25593 25588 24823 24823 25589 25593 24823 24825 25589 24834 24825 24824 24824 24827 24834 24824 24826 24827 24825 24834 25589 24831 24827 24826 24826 24828 24831 24827 24830 24835 24831 24830 24827 25590 24834 24827 24827 24835 25590 25576 24831 24828 24828 25572 25576 24828 25566 25572 24830 25580 26296 24830 24831 25580 26296 24835 24830 24831 25576 25580 26297 26289 24832 24832 25583 26297 24832 24833 25583 24833 24836 25583 26300 25589 24834 24834 25590 26300 26296 25590 24835 24836 24842 25583 26318 24843 24838 24838 25596 26318 24838 24845 25596 25606 24844 24839 24839 24840 25606 26346 25606 24840 24840 26323 26346 24840 24841 26323 26324 26323 24841 26325 26324 24841 24841 25594 26325 26303 25583 24842 26307 26303 24842 24842 24843 26307 26316 26307 24843 24843 26308 26316 26319 26308 24843 24843 26317 26319 26318 26317 24843 25607 24852 24844 24844 25606 25607 24845 24856 25596 24846 24847 24864 24848 24847 24846 24865 24848 24846 24870 24864 24847 24847 24869 24870 26365 24869 24847 24847 24861 26365 24847 24848 24861 24863 24861 24848 25598 24863 24848 24848 24865 25598 25598 24865 24849 24849 24850 25598 24851 24850 24849 26330 25598 24850 26332 26330 24850 24850 26331 26332 24850 25599 26331 25600 25599 24850 24850 24851 25600 25602 25600 24851 25609 25602 24851 25614 25609 24851 24851 24879 25614 24852 24853 24866 24854 24853 24852 25610 24854 24852 24852 25607 25610 24853 24855 24866 24871 24855 24853 25622 24871 24853 24853 24854 25622 26355 25622 24854 24854 25610 26355 24855 24873 24874 24855 24872 24873 24855 24871 24872 24856 24868 25596 24856 24867 24868 24868 24867 24857 24858 24859 25618 24860 24859 24858 25613 24860 24858 26356 25618 24859 27218 26356 24859 24859 26357 27218 24859 26352 26357 24859 24860 26352 24860 26336 26363 24860 25613 26336 26361 26352 24860 26363 26361 24860 27206 26365 24861 24861 27200 27206 24861 24862 27200 24863 24862 24861 27201 27200 24862 24862 26337 27201 24862 24863 26337 26338 26337 24863 24863 25598 26338 25612 25596 24868 26340 25612 24868 24868 25617 26340 24868 25616 25617 25618 25616 24868 25620 24878 24869 26342 25620 24869 26365 26342 24869 24877 24872 24871 25628 24877 24871 24871 25623 25628 24871 25622 25623 24877 24873 24872 24877 24874 24873 24876 26348 27211 26349 26348 24876 24878 25620 26372 25636 24889 24878 25637 25636 24878 26372 25637 24878 25621 25614 24879 25624 25621 24879 24880 24881 24897 24882 24881 24880 24896 24882 24880 24880 24893 24896 24897 24893 24880 24881 24892 24894 25643 24892 24881 25644 25643 24881 24881 24882 25644 24881 24894 24897 24882 24896 25659 25658 25644 24882 25659 25658 24882 24885 24884 24883 25645 24885 24883 26387 25645 24883 24883 25643 26387 24883 24892 25643 24893 24892 24883 24883 24884 24893 24884 24885 25648 25651 24893 24884 25652 25651 24884 24884 25648 25652 24885 25645 25648 24886 25664 26392 24886 24887 25664 24886 26376 26377 26392 26376 24886 24888 24898 24899 24888 24889 24898 25655 24898 24889 24889 25654 25655 24889 25637 25654 24889 25636 25637 25647 25640 24890 24890 24895 25647 26396 25642 24891 24891 25656 26396 25657 25656 24891 27240 25657 24891 24891 25641 27240 24891 25633 25641 24892 24893 24894 24897 24894 24893 25651 24896 24893 24895 24900 25647 26399 25659 24896 24896 25651 26399 25655 24899 24898 24899 24903 25661 26393 24903 24899 24899 25655 26393 26401 25663 24901 24901 24905 26401 24902 24903 26404 25666 25665 24902 26404 25666 24902 24903 25660 25661 24903 26393 26404 24906 24905 24904 25667 24906 24904 26407 25667 24904 24904 25668 26407 24905 26400 26401 24905 26399 26400 24905 24906 26399 24906 25659 26399 26398 25659 24906 24906 25667 26398 24907 25665 25669 24915 24913 24909 24909 24910 24915 26407 25668 24909 24909 24911 26407 24913 24911 24909 24911 24912 26407 24913 24912 24911 27252 26407 24912 28075 27252 24912 24912 24913 28075 24913 24915 28072 28076 28075 24913 29893 28076 24913 24913 28070 29893 28071 28070 24913 28072 28071 24913 24914 26408 28073 24914 28073 28972 24916 24919 24920 25670 24919 24916 24917 24918 25674 24918 25672 25674 25675 24920 24919 26412 25675 24919 24919 25671 26412 24919 25670 25671 24921 24922 25672 25680 25672 24922 24922 25677 25680 25683 25677 24922 24922 24924 25683 26415 25682 24923 24923 25676 26415 24924 24929 25683 25694 24926 24925 24925 25684 25694 24925 25681 25684 25695 25685 24926 24926 25694 25695 25695 25686 24927 24927 25685 25695 24928 25691 25698 24928 25690 25691 25696 25690 24928 24928 25687 25696 25699 25683 24929 25714 24932 24931 25693 25692 24932 25704 25693 24932 25716 25704 24932 24932 25714 25716 26433 24935 24934 24934 25703 26433 26433 24938 24935 25734 24944 24936 24936 24937 25734 26437 25734 24937 24937 24938 26437 24938 26432 26437 26433 26432 24938 25720 24940 24939 24939 25719 25720 25735 24941 24940 24940 25720 25735 25735 24942 24941 24942 25735 25736 25715 25714 24943 25723 25715 24943 25733 24951 24944 25734 25733 24944 28121 25728 24945 28127 28121 24945 24945 26464 28127 24945 24946 26464 24947 24946 24945 25728 24947 24945 24946 26454 26464 24946 24947 26454 24947 25741 26454 24947 24948 25741 25727 24948 24947 25728 25727 24947 24948 24952 25741 27302 26439 24949 24949 26462 27302 24949 25738 26462 24949 26439 26440 24951 25733 26453 25743 24955 24951 26453 25743 24951 24952 24953 25741 24954 25753 25756 26455 25753 24954 24954 25736 26455 25743 25742 24955 25746 25744 24956 25759 25746 24956 27310 26468 24957 27322 27310 24957 27323 27322 24957 24957 26470 27323 24971 24962 24959 24959 24964 24971 24961 24960 24959 24962 24961 24959 24960 24961 24965 24961 24962 25761 24966 24965 24961 25761 24966 24961 24962 24971 25751 24962 25751 25761 25765 24967 24963 25766 25765 24963 24963 25757 25766 24964 24970 24971 26474 25768 24965 24965 24966 26474 24966 25754 26474 25761 25754 24966 24967 24978 24979 25765 24978 24967 25767 25760 24968 24968 25762 25767 24968 24973 25762 24968 24972 24973 25747 24974 24969 25748 24971 24970 24970 24974 25748 24971 25748 25750 24971 25750 25751 24980 24973 24972 25763 25762 24973 25769 25763 24973 24973 24980 25769 24974 25747 25748 24975 24976 24987 26485 24987 24976 24976 26483 26485 26484 26483 24976 24976 26482 26484 24976 24981 26482 24977 25773 26477 25774 25773 24977 25775 24982 24978 25781 25775 24978 26493 25781 24978 26494 26493 24978 24978 25765 26494 24980 24986 25769 24981 26479 26482 24981 25764 26479 25775 24984 24982 25784 24986 24983 25789 25784 24983 24983 24989 25789 24983 24985 24989 24984 25781 25782 24984 25775 25781 24984 24988 24989 25782 24988 24984 24986 25763 25769 25783 25763 24986 25784 25783 24986 26485 25772 24987 25788 24989 24988 27358 25788 24988 24988 26499 27358 24988 25782 26499 26501 25792 24989 24989 25788 26501 25792 25789 24989 24999 24998 24990 25799 24999 24990 25801 25799 24990 24990 24991 25801 24991 25006 25801 24991 25005 25006 25008 25007 24992 24993 25786 26492 26496 25787 24994 27353 26496 24994 24994 26510 27353 24994 24995 26510 24995 26497 26510 24995 24996 26497 24996 24997 26497 26498 26497 24997 24997 25791 26498 24999 25003 25004 25818 25003 24999 24999 25799 25818 26498 25791 25000 26512 26498 25000 25000 25009 26512 25001 25002 25012 25003 25002 25001 25004 25003 25001 25002 25003 25012 25818 25012 25003 25007 25006 25005 25810 25801 25006 25811 25810 25006 25006 25007 25811 25812 25811 25007 25007 25008 25812 26521 25812 25008 25008 25804 26521 25008 25772 25804 26517 26512 25009 25010 25824 26530 25011 25012 25818 25826 25825 25011 25011 25818 25826 25021 25015 25013 25013 25014 25021 25014 25020 25021 26524 25807 25015 26526 26524 25015 26527 26526 25015 25015 25813 26527 25015 25021 25813 25016 25805 25808 26526 25816 25016 25016 25808 26526 26534 25823 25017 25017 26529 26534 25017 25018 26529 25018 25817 26529 25021 25020 25019 25814 25021 25019 26527 25814 25019 26543 26527 25019 25019 25834 26543 25019 25020 25834 25020 25025 25834 25814 25813 25021 25023 25029 25830 25023 25028 25029 26540 25827 25024 25024 25830 26540 25025 25031 25834 25045 25032 25026 25831 25045 25026 25833 25028 25027 25027 25035 25833 26546 25029 25028 27392 26546 25028 25028 27391 27392 25028 26552 27391 25028 25833 26552 26546 25830 25029 25827 25037 25030 25031 25038 25834 25046 25043 25032 25032 25045 25046 25048 25035 25033 25033 25034 25048 26553 25048 25034 25034 25838 26553 25839 25838 25034 27399 25839 25034 25034 25841 27399 25034 25840 25841 25035 26554 27396 25035 26553 26554 25035 25048 26553 26552 25833 25035 27396 26552 25035 25036 25037 25052 25835 25052 25037 25836 25835 25037 25037 25827 25836 25040 25039 25038 25042 25040 25038 25038 25039 25834 25039 25040 27397 27397 25834 25039 27398 27397 25040 25040 25041 27398 25042 25041 25040 25041 25848 27398 25041 25042 25848 25042 25843 25848 26559 25837 25043 25043 25046 26559 25046 25045 25044 26559 25046 25044 25044 26558 26559 27388 26558 25044 25044 26545 27388 25044 25045 26545 25045 25831 26545 25049 25837 25840 25069 25056 25050 26571 25069 25050 25050 26568 26571 26569 26568 25050 25050 25844 26569 25050 25051 25844 25052 25051 25050 26569 25844 25051 26572 26569 25051 27403 26572 25051 25051 25835 27403 25051 25052 25835 25846 25843 25053 25053 25845 25846 25053 25055 25845 25845 25055 25054 25849 25845 25054 25069 25058 25056 25860 25067 25057 25059 25060 25062 25061 25060 25059 25867 25061 25059 25060 25061 25851 26560 25851 25061 25061 25867 26560 25852 25850 25063 25066 25067 26580 25857 25856 25066 26579 25857 25066 26580 26579 25066 25067 25860 26580 26574 25070 25069 25069 26571 26574 26581 25865 25070 25070 26574 26581 25071 25078 25869 25071 25072 25078 25861 25078 25072 25072 25074 25861 25072 25073 25074 25862 25861 25074 25864 25863 25075 25075 25859 25864 25076 25866 26611 25872 25077 25076 26610 25872 25076 26611 26610 25076 28235 25869 25078 25078 26584 28235 25078 25861 26584 25079 25094 25874 26608 25871 25080 25080 25873 26608 25080 25081 25873 25081 25863 25873 25082 25083 27435 25084 25083 25082 26611 25084 25082 25082 26600 26611 27419 26600 25082 27435 27419 25082 25083 26598 27435 25083 25084 26598 25084 25865 26598 25866 25865 25084 26611 25866 25084 26610 26599 25085 25085 25872 26610 25881 25094 25087 25087 25098 25881 25099 25098 25087 26626 25877 25088 25088 26622 26626 25088 25089 26622 25090 25089 25088 25089 26621 26622 25089 26614 26621 25089 25875 26614 25089 25090 25875 28254 27448 25091 25091 25868 28254 25091 25092 25868 25869 25868 25092 25883 25874 25094 25094 25879 25883 25881 25879 25094 25096 25097 25104 25098 25097 25096 25103 25098 25096 25104 25103 25096 25097 25098 25099 25098 25879 25881 25098 25103 25879 25101 25897 25901 25101 25102 25897 26653 25897 25102 25103 25878 25879 25893 25878 25103 25900 25893 25103 25103 25105 25900 25103 25104 25105 26648 25900 25105 25105 25106 26648 25107 25106 25105 25106 25902 26648 25106 25107 25902 25107 25111 25902 25108 25110 25112 26646 25110 25109 25109 25894 26646 25109 25892 25894 26652 25112 25110 27473 26652 25110 25110 26646 27473 26652 25902 25111 25111 25112 26652 25905 25904 25114 25907 25905 25114 25114 25115 25907 25122 25121 25116 25118 25117 25116 25121 25118 25116 25117 25118 25119 25911 25119 25118 26660 25911 25118 26668 26660 25118 25118 25928 26668 25118 25121 25928 26658 25123 25119 25119 26657 26658 25119 25910 26657 25911 25910 25119 25934 25138 25120 25120 25927 25934 25120 25127 25927 25935 25928 25121 25121 25146 25935 25121 25122 25146 25122 25140 25146 25122 25129 25140 26663 25909 25123 25123 26658 26663 25124 25125 25126 25917 25126 25125 25922 25917 25125 25125 25921 25922 25126 25915 25924 25917 25915 25126 25127 25128 25927 25128 25905 25927 25128 25904 25905 25145 25140 25129 25134 25133 25130 25130 25131 25134 25132 25131 25130 25133 25132 25130 25918 25134 25131 25131 25915 25918 25924 25915 25131 25929 25924 25131 25131 25132 25929 25937 25929 25132 25133 25135 25141 25136 25135 25133 25133 25134 25136 25137 25136 25134 26674 25137 25134 25134 25920 26674 25134 25918 25920 25148 25141 25135 25135 25136 25148 25926 25148 25136 25136 25137 25926 27486 25926 25137 25137 26674 27486 25934 25139 25138 25139 25934 26676 25140 25145 25146 25141 25148 25155 26682 25144 25142 27495 26682 25142 25142 26681 27495 25142 26676 26681 26693 25164 25143 27508 26693 25143 25143 27496 27508 25143 26682 27496 25143 25144 26682 25938 25935 25145 25935 25146 25145 25147 25939 25949 25148 25942 25943 25148 25932 25942 25148 25926 25932 25943 25155 25148 25945 25944 25149 26695 25945 25149 25149 25150 26695 25151 25150 25149 25944 25151 25149 27513 26695 25150 28330 27513 25150 25150 28322 28330 25150 27512 28322 25150 25151 27512 25151 25951 26696 25151 25948 25951 25151 25944 25948 25151 27506 27512 25151 26696 27506 25152 25930 25931 26684 25930 25152 26690 26684 25152 25152 25162 26690 25152 25153 25162 25163 25162 25153 25947 25157 25154 25154 25155 25947 25155 25943 25947 25948 25944 25156 25951 25948 25156 25156 25950 25951 25946 25158 25157 25947 25946 25157 27507 26697 25158 25158 25946 27507 25159 25184 25185 25159 25160 25184 25961 25184 25160 25963 25961 25160 26700 25963 25160 25160 26697 26700 25161 25164 25165 25162 25953 26690 25162 25163 25953 25163 25952 25953 25163 25166 25952 25164 26693 26694 26694 25165 25164 25958 25957 25165 26694 25958 25165 25166 25171 26698 26698 25952 25166 25167 25177 25954 25168 25169 28317 25170 25169 25168 25952 25170 25168 25953 25952 25168 26689 25953 25168 28317 26689 25168 25169 25170 28316 25169 28316 28317 25170 26704 28318 25170 26698 26704 25170 25952 26698 28318 28316 25170 26699 26698 25171 25171 25187 26699 25171 25172 25187 25172 25180 25187 25172 25179 25180 26723 25174 25173 25173 25966 26723 25979 25966 25173 25955 25176 25175 25175 25181 25955 25959 25177 25176 25176 25955 25959 26717 25954 25177 25177 25967 26717 25177 25959 25967 26718 25186 25178 25178 25960 26718 25178 25954 25960 25972 25180 25179 25972 25187 25180 25956 25955 25181 25968 25956 25181 26702 25968 25181 26703 26702 25181 25181 25957 26703 25182 25193 25972 25182 25191 25193 25182 25190 25191 25183 26719 26731 25183 26706 26719 25183 25961 26706 25183 25184 25961 25185 25184 25183 26731 25185 25183 26730 25971 25185 28359 26730 25185 28360 28359 25185 25185 28356 28360 25185 26731 28356 26733 25195 25186 25186 26718 26733 25972 25193 25187 26705 26699 25187 25187 25188 26705 25189 25188 25187 25193 25189 25187 27518 26705 25188 25188 25189 27518 27535 27518 25189 27536 27535 25189 25189 25969 27536 25189 25193 25969 25190 25971 25976 25192 25191 25190 25976 25192 25190 25191 25192 25193 25973 25193 25192 25974 25973 25192 26737 25974 25192 25192 25976 26737 25970 25969 25193 25973 25970 25193 25982 25202 25195 26729 25982 25195 26734 26729 25195 25195 26733 26734 25196 25198 25199 25196 25197 25198 25197 25203 25978 25978 25198 25197 25198 26744 26745 25198 25978 26744 26745 25205 25198 25206 25201 25200 25201 25206 25979 25982 25975 25202 25203 25977 25978 25204 25207 25209 25204 25205 25207 26745 25207 25205 25980 25979 25206 25987 25209 25207 26746 25987 25207 25207 26745 26746 25208 25975 25989 25209 25990 25994 25209 25210 25990 25211 25210 25209 25987 25211 25209 26746 25990 25210 25210 25211 26746 25211 25987 26746 25212 25998 26756 25212 25997 25998 25225 25218 25213 26002 25225 25213 25213 25214 26002 25215 25214 25213 25216 25215 25213 27573 26765 25214 25214 26760 27573 25214 25215 26760 26764 26002 25214 26765 26764 25214 25215 25999 26760 25215 25996 25999 25215 25216 25996 26758 25993 25217 25217 26001 26758 25219 25220 25228 25220 25223 25228 26005 25223 25220 25221 25222 26013 25223 25222 25221 25228 25223 25221 26778 26013 25222 25222 25223 26778 26779 26778 25223 25223 26771 26779 25223 26005 26771 25224 26759 26763 25224 26751 26759 25224 25994 26751 26006 25226 25225 25225 26002 26006 26010 25227 25226 25226 26006 26010 25227 26010 26770 26771 26005 25227 25227 26764 26771 26770 26764 25227 26781 26767 25229 25229 25233 26781 26008 26007 25230 26776 26008 25230 25230 26003 26776 25230 25231 26003 26004 26003 25231 25998 25997 25232 26769 25998 25232 25232 26009 26769 25235 25234 25233 25233 25234 26781 25234 25250 26032 25234 25235 25250 25234 26032 26781 25235 25249 25250 25235 25245 25249 25236 25239 25246 25236 25237 25239 25258 25239 25237 26783 25258 25237 25237 26782 26783 25237 26772 26782 25237 26011 26772 26789 26009 25238 25238 25243 26789 25258 25246 25239 25240 25247 26014 26045 25260 25241 26801 26045 25241 25241 25242 26801 26820 26801 25242 25242 26016 26820 25243 25244 26789 25244 26020 26789 26022 26020 25244 26033 26022 25244 25251 25249 25245 25246 25252 25255 25254 25252 25246 25257 25254 25246 25258 25257 25246 26792 26780 25248 25248 26028 26792 25248 25249 26028 25250 25249 25248 26032 25250 25248 26780 26032 25248 26031 26028 25249 25249 26030 26031 25249 25251 26030 25252 25253 25255 25254 25253 25252 25256 25255 25253 26058 25256 25253 25253 26057 26058 25253 26017 26057 25253 25254 26017 26053 26017 25254 26794 26053 25254 25254 25257 26794 25256 26809 27609 26810 26809 25256 26824 26810 25256 25256 26058 26824 25257 25258 26794 25258 26783 26794 25263 25262 25261 25264 25263 25261 25262 26038 26050 25262 25263 26038 25263 25264 26041 26040 26038 25263 26041 26040 25263 25264 25265 26041 26806 26041 25265 25265 26023 26806 26025 26023 25265 26052 26051 25266 25268 25267 25266 26051 25268 25266 25267 25269 25271 25267 25268 25269 26031 26030 25268 25268 26027 26031 26042 26027 25268 26051 26042 25268 25270 25269 25268 26030 25270 25268 25269 25270 25271 27621 26825 25272 25272 27615 27621 25272 27614 27615 25272 25273 27614 25273 26818 27614 26067 25280 25275 25275 26060 26067 25275 26050 26060 25276 28446 28450 25276 27621 28446 25276 25277 27621 25278 25277 25276 28450 25278 25276 25277 26825 27621 26836 26825 25277 25277 26065 26836 25277 25278 26065 25278 25289 26065 26072 25289 25278 27633 26072 25278 28450 27633 25278 26066 25294 25279 25279 25280 26066 26067 26066 25280 26065 25289 25282 25282 25283 26065 25283 26064 26065 26853 25286 25284 25284 26847 26853 26848 26847 25284 30319 26848 25284 31109 30319 25284 25284 30337 31109 25284 29393 30337 25284 25285 29393 25286 25285 25284 25285 28477 29393 25285 25286 28477 26853 25291 25286 25286 26079 28477 26080 26079 25286 25286 25291 26080 27619 26823 25287 25314 25305 25288 25288 25313 25314 25288 25306 25313 26072 26069 25289 26080 25291 25290 25290 25300 26080 26853 26063 25291 26075 25302 25292 25292 26074 26075 25292 25293 26074 25293 25294 26074 25294 26066 26074 25295 25296 25312 26086 26085 25296 25296 25297 26086 26085 25312 25296 26087 26086 25297 25297 25298 26087 26088 26087 25298 25298 25303 26088 25299 26071 26846 26081 26080 25300 25300 25301 26081 26855 26081 25301 26075 25307 25302 26867 26088 25303 25303 26091 26867 25303 25304 26091 25305 25304 25303 25304 26090 26091 25304 25314 26090 25304 25305 25314 25315 25313 25306 25307 26075 26082 25308 25311 26089 27655 25311 25308 25308 27651 27655 27652 27651 25308 27654 27652 25308 25308 26857 27654 25308 26082 26857 26858 26076 25309 25309 25310 26858 25311 25310 25309 26089 25311 25309 26859 26858 25310 26860 26859 25310 28478 26860 25310 25310 27650 28478 25310 25311 27650 27655 27650 25311 26083 25317 25312 26084 26083 25312 26085 26084 25312 26862 26093 25316 25316 26083 26862 25316 25317 26083 25321 25320 25318 26094 25321 25318 25318 25325 26094 26884 26876 25319 26895 26884 25319 27656 26895 25319 25319 25323 27656 26878 26868 25320 25320 25321 26878 25321 26877 26878 25321 26094 26877 26106 25326 25322 25322 26095 26106 25323 26875 27656 25323 26077 26875 26097 26094 25325 25325 25329 26097 26105 25331 25326 26106 26105 25326 26901 25332 25328 25328 26894 26901 25328 26876 26894 25329 25330 26097 26099 26097 25330 26100 26099 25330 25330 25333 26100 25331 26105 26108 26112 26100 25333 25334 25339 25342 25336 25335 25334 25342 25336 25334 25338 25337 25335 26929 25338 25335 25335 25336 26929 25336 25342 26122 25336 26118 26929 26119 26118 25336 26122 26119 25336 26890 26109 25337 25337 26889 26890 25337 26114 26889 25337 25338 26114 26929 26114 25338 26121 25341 25340 26121 25345 25341 25342 25343 26122 26931 26122 25343 25343 26930 26931 25343 26107 26930 25344 25347 26120 25348 25347 25344 26124 25348 25344 26939 26124 25344 25345 26121 26126 25352 25346 25345 26126 25352 25345 25346 25352 25353 26935 26120 25347 25347 25348 26935 26936 26935 25348 26938 26936 25348 28539 26938 25348 29447 28539 25348 25348 26123 29447 26124 26123 25348 25349 26125 26135 27717 25350 25349 25349 26135 27717 27723 27715 25350 25350 25392 27723 27717 25392 25350 25354 25353 25352 26126 25354 25352 25353 25355 25356 26138 25355 25353 26941 26138 25353 25353 25354 26941 27716 26941 25354 25354 26942 27716 25354 26126 26942 26130 25357 25355 26136 26130 25355 26137 26136 25355 26138 26137 25355 26130 26129 25357 26964 26948 25358 26971 26964 25358 25358 25359 26971 25359 26947 26971 26128 26127 25360 25363 25362 25361 26132 25380 25362 25362 25363 26132 27719 26132 25363 28564 27719 25363 25363 28562 28564 25363 26940 28562 25364 25383 25394 25394 25366 25364 25365 25385 25386 25365 25382 25385 25365 25366 25382 25367 25366 25365 25386 25367 25365 25394 25382 25366 26135 26125 25367 25367 25387 26135 25367 25386 25387 26949 25369 25368 25368 26948 26949 26141 25370 25369 26950 26141 25369 25369 26949 26950 26131 25371 25370 26141 26131 25370 26131 25372 25371 26131 25373 25372 25373 25375 25376 26131 25375 25373 27732 26968 25374 25374 26967 27732 25374 25375 26967 25376 25375 25374 26142 25376 25374 26968 26142 25374 25375 26955 26967 25375 26131 26955 26959 26956 25376 25376 26958 26959 25376 26142 26958 25377 25388 25389 25378 25379 26159 26961 26159 25379 25379 26158 26961 25379 26156 26158 26945 26133 25380 25380 26132 26945 25381 25382 25384 25394 25384 25382 25383 25384 25394 27717 26135 25385 25385 25392 27717 25387 25386 25385 26135 25387 25385 26156 25389 25388 25388 26144 26156 25388 26143 26144 25393 25391 25390 26149 25393 25390 25390 26134 26149 25392 26957 27723 25392 25393 26957 25393 26149 26957 25396 25397 25401 25398 25397 25396 25402 25398 25396 27735 25401 25397 25397 26973 27735 25397 25398 26973 25398 26167 26973 25398 25402 26167 25405 25400 25399 26171 26163 25400 25400 25406 26171 25400 25404 25406 25405 25404 25400 25400 26162 26166 26163 26162 25400 25401 26147 26148 27721 26147 25401 27725 27721 25401 27734 27725 25401 28586 27734 25401 25401 27735 28586 26168 26167 25402 25402 25403 26168 25403 25407 26168 25406 25408 26171 26981 26980 25407 26982 26168 25407 25407 26980 26982 26977 26171 25408 25409 25413 25414 25410 26174 26987 25422 25411 25410 26987 25422 25410 25422 25415 25411 25412 25421 26177 25417 25414 25413 25413 25415 25417 25414 25441 26179 25442 25441 25414 25414 25417 25442 25415 25416 25417 25431 25416 25415 25432 25431 25415 25434 25432 25415 25415 25422 25434 25431 25427 25416 25427 25417 25416 25444 25442 25417 25417 25427 25444 27750 26977 25418 27761 27750 25418 27762 27761 25418 25418 26988 27762 26181 26180 25419 26994 25421 25420 25420 25425 26994 26994 26177 25421 26191 25434 25422 26987 26191 25422 25428 25424 25423 27776 26192 25424 27790 27776 25424 25424 27777 27790 25424 26199 27777 25424 25428 26199 25425 26186 26994 25425 25430 26186 25425 25429 25430 26190 25444 25427 25427 25431 26190 27793 26199 25428 25428 27789 27793 25428 27014 27789 25448 25430 25429 26997 26186 25430 25430 26194 26997 25430 25448 26194 25431 25432 26190 26195 26190 25432 26196 26195 25432 25432 25433 26196 25434 25433 25432 26197 26196 25433 25433 26191 26197 25433 25434 26191 26189 25436 25435 25435 26188 26189 25435 26178 26188 26189 25438 25436 25439 25438 25437 25440 25439 25437 25441 25440 25437 26179 25441 25437 25437 25438 26179 26188 26179 25438 26189 26188 25438 25439 25449 25450 25439 25440 25449 26201 25458 25439 25439 25450 26201 25440 25442 25449 25440 25441 25442 25442 25443 25449 25444 25443 25442 25451 25449 25443 25443 25444 25451 26195 25451 25444 25444 26190 26195 25464 25447 25445 27004 25464 25445 25445 25446 27004 25447 25446 25445 25446 25452 27004 25446 25447 25452 25464 25454 25447 25453 25452 25447 25448 25457 26194 25448 25454 25457 25451 25450 25449 26202 26201 25450 26203 26202 25450 25450 26198 26203 25450 26195 26198 25450 25451 26195 27005 27004 25452 25452 26193 27005 27007 25457 25454 25454 25460 27007 25454 25459 25460 25454 25455 25459 25456 25455 25454 26200 25456 25454 25454 25464 26200 25455 25456 25459 26207 25459 25456 26208 26207 25456 25456 26204 26208 26205 26204 25456 25456 26200 26205 27007 27006 25457 27001 26194 25457 27006 27001 25457 26201 25462 25458 26207 25460 25459 25460 26210 27007 26212 26210 25460 25460 26207 26212 27011 25467 25461 25461 25462 27011 25462 26201 27011 27017 27014 25463 25463 27015 27017 27016 27015 25463 27787 26200 25464 25464 27003 27787 27004 27003 25464 25470 25469 25465 25465 25466 25470 25467 25466 25465 25469 25467 25465 26215 25470 25466 27012 26215 25466 25466 25467 27012 25469 25468 25467 25467 27011 27012 25472 25471 25470 26215 25472 25470 25471 25474 25476 25471 25473 25474 25471 25472 25473 26217 25473 25472 25472 26215 26217 25475 25474 25473 26217 25475 25473 26227 25476 25474 25474 26218 26227 25474 25475 26218 28695 26218 25475 25475 27812 28695 25475 26217 27812 26227 25487 25476 25478 26213 26214 27076 26232 25479 25479 25480 27076 25481 25480 25479 25489 25481 25479 26232 25489 25479 27863 27076 25480 25480 25481 27863 25481 27084 27863 27085 27084 25481 25481 25491 27085 25482 25483 25494 25484 25483 25482 25485 25484 25482 25483 25493 25494 26230 25493 25483 25483 25484 26230 26226 26222 25484 25484 26225 26226 25484 25485 26225 25484 26229 26230 25484 26222 26229 26231 26225 25485 25485 25486 26231 27075 26231 25486 25486 25487 27075 25487 26227 27075 27076 27064 25488 25488 26232 27076 25488 25489 26232 25501 25491 25490 25491 25501 27085 25494 25493 25492 26234 25500 25493 25493 26233 26234 25493 26230 26233 26235 25498 25495 25495 25496 26235 26239 26238 25497 25497 26236 26239 25497 25498 26236 25498 26235 26236 27090 26244 25499 25499 25500 27090 26244 26240 25499 25500 26234 27090 25501 25507 27085 26237 25504 25502 27103 26237 25502 25502 25503 27103 25504 25503 25502 27104 27103 25503 25503 27097 27104 25503 25504 27097 25504 26241 27097 26246 25506 25505 27110 26246 25505 25505 26242 27110 25505 26238 26242 26246 25508 25506 25507 26243 27085 25507 25508 26243 27110 26243 25508 25508 26246 27110 25509 25510 26247 25510 25518 26247 25510 25511 25518 26252 25515 25512 26255 26252 25512 26263 25520 25514 27090 26263 25514 27113 26241 25515 25515 26252 27113 25517 25521 26251 25517 25518 25521 25519 25518 25517 26251 25519 25517 26249 26247 25518 26250 26249 25518 27115 26250 25518 25518 27114 27115 25518 25519 27114 27885 27114 25519 27886 27885 25519 25519 26251 27886 26265 26261 25520 25520 26262 26265 26263 26262 25520 25521 25523 26251 25521 25522 25523 25524 25523 25522 26253 26251 25523 25523 25528 26253 25523 25524 25528 25525 25526 25528 25527 25526 25525 25530 25527 25525 26254 25528 25526 27119 26254 25526 27125 27119 25526 25526 25527 27125 27131 27125 25527 26254 26253 25528 25542 25537 25531 26272 25542 25531 25531 26265 26272 25531 26261 26265 25532 25533 26256 25533 25534 26267 26264 26256 25533 26267 26264 25533 25534 25535 26267 26268 26267 25535 25535 25540 26268 25536 26277 27131 25536 25550 26277 25545 25539 25538 25546 25545 25538 26282 25546 25538 25539 25545 25547 25540 25564 26268 25540 25548 25564 25540 25541 25548 25544 25543 25542 26272 25544 25542 25543 25544 27909 27147 26276 25543 27148 27147 25543 27909 27148 25543 25544 27896 27897 25544 26272 27896 25544 27897 27909 26273 25547 25545 25545 25546 26273 27132 26273 25546 27152 27132 25546 25546 27151 27152 27153 27151 25546 25546 26282 27153 25547 27137 27140 25547 26273 27137 25548 25556 25564 25553 25551 25549 26271 25553 25549 26279 26277 25550 25550 26276 26279 25551 25552 25558 25553 25552 25551 26281 25558 25552 27143 26281 25552 25552 25553 27143 25553 27139 27143 25553 26271 27139 27142 27141 25554 25554 25555 27142 27149 27142 25555 25555 26278 27149 25560 25559 25558 26281 25560 25558 25562 25561 25559 27155 25562 25559 27929 27155 25559 25559 25560 27929 25560 27926 27929 25560 27925 27926 25560 26281 27925 25563 25565 27150 27135 26268 25564 25564 26280 27135 25565 26282 27150 27932 26282 25565 25565 26286 27932 25582 25572 25566 25566 25571 25582 25566 25567 25571 25568 26284 27156 25568 25569 26284 25570 25569 25568 27936 25570 25568 25568 27156 27936 26292 25571 25570 27957 26292 25570 25570 27940 27957 25570 27936 27940 26293 25582 25571 25571 26291 26293 26292 26291 25571 25580 25576 25572 26290 25580 25572 25572 25581 26290 25582 25581 25572 25579 25577 25574 25585 25578 25575 25586 25585 25575 25577 25579 25584 25578 25594 25595 26325 25594 25578 25578 26312 26325 25578 25585 26312 26295 26294 25580 25580 26290 26295 25580 26294 26296 25581 25582 26293 26293 26290 25581 26304 26297 25583 25583 26303 26304 26313 26312 25585 25585 25591 26313 25585 25586 25591 25592 25591 25586 25586 25587 25592 25587 25588 25592 26335 25592 25588 25588 26299 26335 25588 25593 26299 26299 25593 25589 25589 26298 26299 26300 26298 25589 26301 26300 25590 25590 26296 26301 26326 26313 25591 26333 26326 25591 25591 26320 26333 25591 25592 26320 26335 26320 25592 25596 25612 26318 26336 25608 25597 25597 25619 26336 26339 26338 25598 25598 26330 26339 25599 26329 27195 25599 25601 26329 25599 25600 25601 27195 26331 25599 25602 25601 25600 25601 25603 26329 25601 25602 25603 25609 25603 25602 27203 26329 25603 25603 25604 27203 25605 25604 25603 25609 25605 25603 25604 25605 26345 27204 27203 25604 25604 26345 27204 25605 25609 25614 25605 25614 26345 26346 25607 25606 25611 25610 25607 26346 25611 25607 25610 26350 26355 25610 25611 26350 27210 26350 25611 25611 26346 27210 26328 26318 25612 26340 26328 25612 26353 26345 25614 25614 25626 26353 25614 25621 25626 25615 26351 27218 25615 25616 26351 25617 25616 25615 27199 25617 25615 27985 27199 25615 28899 27985 25615 25615 28001 28899 25615 27218 28001 25616 25618 26351 25617 26327 26340 27199 26327 25617 26356 26351 25618 26341 26336 25619 26347 26341 25619 25620 26343 26372 25620 26342 26343 25621 25624 25626 25627 25623 25622 25632 25627 25622 26355 25632 25622 25629 25628 25623 25623 25627 25629 26379 25626 25624 25624 25631 26379 25624 25625 25631 26378 25631 25625 25625 25638 26378 26354 26353 25626 26379 26354 25626 25632 25629 25627 25628 25629 25633 25629 25632 25641 25641 25633 25629 25630 25634 26369 27227 26379 25631 25631 26380 27227 25631 26378 26380 25632 26355 26373 26373 25641 25632 26370 26369 25634 25634 26364 26370 25634 25635 26364 26377 26364 25635 28929 25654 25637 25637 26372 28929 25638 25639 26378 25640 25639 25638 27239 26378 25639 27242 27239 25639 25639 25650 27242 25639 25640 25650 25640 25646 25650 25647 25646 25640 25641 27217 27240 25641 26373 27217 26395 25662 25642 26396 26395 25642 25643 26384 26387 25643 26382 26384 25643 26381 26382 25643 25644 26381 26383 26381 25644 26390 26383 25644 26391 26390 25644 25644 25658 26391 26366 25649 25645 26367 26366 25645 25645 26360 26367 26368 26360 25645 26387 26368 25645 25649 25648 25645 26392 25652 25648 25648 26374 26392 25648 25649 26374 25649 26366 26370 26388 26374 25649 25649 26370 26388 27244 27242 25650 25650 26403 27244 25650 26394 26403 25651 25652 26399 26400 26399 25652 25652 26392 26400 28053 26389 25653 28066 28053 25653 28932 28066 25653 25653 25654 28932 25655 25654 25653 26389 25655 25653 25654 28929 28932 25655 26389 26393 28056 26396 25656 28062 28056 25656 25656 27245 28062 25656 25657 27245 28039 27245 25657 25657 27240 28039 27243 26391 25658 25658 25659 27243 27246 27243 25659 25659 26398 27246 26395 26394 25662 26402 25664 25663 25663 26401 26402 26400 26392 25664 26402 26400 25664 27249 26408 25665 27250 27249 25665 25665 25666 27250 25666 27247 27250 25666 26404 27247 26405 26398 25667 28069 26405 25667 25667 27251 28069 27252 27251 25667 25667 26407 27252 25671 26411 26412 25671 26409 26411 26410 26409 25671 25671 25673 26410 25672 25673 25674 26413 25673 25672 25672 25680 26413 26413 26410 25673 26412 25676 25675 25676 26412 26415 25679 25678 25677 25683 25679 25677 25677 25678 25680 27265 26416 25678 25678 25679 27265 26416 25680 25678 27266 27265 25679 25679 26422 27266 25679 25683 26422 26416 26413 25680 26418 25684 25681 25681 26417 26418 27262 26417 25682 25682 27261 27262 25682 27255 27261 25682 26415 27255 25683 25699 26422 25706 25694 25684 26423 25706 25684 25684 26418 26423 25702 25688 25686 25686 25695 25702 25687 25688 25696 26419 25696 25688 25688 25702 26419 27273 27272 25689 25689 27268 27273 27269 27268 25689 25689 27267 27269 25689 26419 27267 25689 25690 26419 25691 25690 25689 27272 25691 25689 25690 25696 26419 26421 25698 25691 25691 25718 26421 27272 25718 25691 25692 25693 25699 26424 25699 25693 25693 25704 26424 25701 25695 25694 25705 25701 25694 25706 25705 25694 25695 25700 25702 25701 25700 25695 25697 25698 26421 26424 26422 25699 26431 25702 25700 25700 26430 26431 25700 25701 26430 25701 25708 26430 25701 25707 25708 25701 25705 25707 26420 26419 25702 26431 26420 25702 25703 26427 26433 25703 25717 26427 27270 26424 25704 27274 27270 25704 25704 25716 27274 25710 25707 25705 26425 25710 25705 25705 25706 26425 26426 26425 25706 28085 26426 25706 25706 26423 28085 25709 25708 25707 25710 25709 25707 25708 25712 26430 25708 25709 25712 25709 25711 25712 25709 25710 25711 26425 25711 25710 25713 25712 25711 26429 25713 25711 25711 26425 26429 26445 26430 25712 25712 26436 26445 25712 25713 26436 26444 26436 25713 25713 26435 26444 25713 26429 26435 26434 25716 25714 25714 25715 26434 25715 25723 26434 27278 27274 25716 25716 26434 27278 28094 26427 25717 28992 28094 25717 25717 27272 28992 25717 25718 27272 25721 25720 25719 25728 25721 25719 25719 25727 25728 25720 25722 25735 25720 25721 25722 26446 25722 25721 25721 25728 26446 25737 25735 25722 27306 25737 25722 27308 27306 25722 28116 27308 25722 25722 26446 28116 27263 26434 25723 25723 26450 27263 25724 25734 26437 26453 25734 25724 25724 25725 26453 25726 25725 25724 26437 25726 25724 25725 26452 26453 28120 26452 25725 25725 28114 28120 25725 27305 28114 25725 25726 27305 28107 27305 25726 25726 28106 28107 25726 26427 28106 26433 26427 25726 25726 26432 26433 26437 26432 25726 28121 27309 25728 27309 26446 25728 25729 26442 26449 25729 26441 26442 26451 25732 25730 27296 26451 25730 25730 26448 27296 25730 25731 26448 25732 25731 25730 26451 25740 25732 25733 25734 26453 25737 25736 25735 26456 26455 25736 25736 25737 26456 27306 26456 25737 25738 25739 26462 27310 26462 25739 25739 26468 27310 27288 26450 25740 25740 26451 27288 25741 25744 26454 27315 26469 25742 27316 27315 25742 25742 26452 27316 25742 25743 26452 26453 26452 25743 26464 26454 25744 25744 26463 26464 25744 25745 26463 25746 25745 25744 26466 26463 25745 26467 26466 25745 26478 26467 25745 25745 25777 26478 25745 25767 25777 25745 25746 25767 25746 25759 25767 25756 25748 25747 25756 25753 25748 25753 25750 25748 25749 25750 25752 25751 25750 25749 25755 25751 25749 26461 25755 25749 25749 25752 26461 25753 25752 25750 25751 25754 25761 25755 25754 25751 25752 25753 26455 25752 26459 26461 26460 26459 25752 25752 26456 26460 25752 26455 26456 27320 26474 25754 25754 27319 27320 29024 27319 25754 25754 29018 29024 25754 28126 29018 25754 25755 28126 25755 28118 28126 25755 26465 28118 25755 26461 26465 26469 25766 25757 25757 25758 26469 25759 25760 25767 25771 25767 25762 25762 25770 25771 25762 25763 25770 25783 25770 25763 25764 25768 26474 27331 26479 25764 25764 26474 27331 27334 26494 25765 25765 25766 27334 27336 27334 25766 25766 26469 27336 25767 25771 25777 25776 25771 25770 25783 25776 25770 25771 25776 25777 25772 25803 25804 26516 25803 25772 25772 26485 26516 27335 26477 25773 25773 27321 27335 27342 27321 25773 25773 26490 27342 25773 26489 26490 25773 25774 26489 25778 25777 25776 25785 25778 25776 25776 25783 25785 25777 25780 26478 25777 25779 25780 25777 25778 25779 25785 25779 25778 26488 25780 25779 25779 25790 26488 25779 25785 25790 26481 26478 25780 26487 26481 25780 26488 26487 25780 26500 25782 25781 25781 26493 26500 26500 26499 25782 25790 25785 25783 25798 25790 25783 25783 25797 25798 25783 25795 25797 25783 25784 25795 25784 25792 25795 25784 25789 25792 27347 26492 25786 25786 26495 27347 26496 26495 25787 27358 26501 25788 26503 26488 25790 25790 26502 26503 26515 26502 25790 25790 25798 26515 25796 25793 25792 26501 25796 25792 25792 25794 25795 25792 25793 25794 26518 26513 25793 25793 25796 26518 26513 25794 25793 26519 25800 25794 26520 26519 25794 25794 26513 26520 25797 25795 25794 25800 25797 25794 27361 26518 25796 25796 27358 27361 25796 26501 27358 26515 25798 25797 25797 25800 26515 25819 25818 25799 25820 25819 25799 25799 25809 25820 25799 25801 25809 27371 26523 25800 25800 26519 27371 26523 26515 25800 25810 25809 25801 28174 26521 25802 28175 28174 25802 25802 25803 28175 25804 25803 25802 26521 25804 25802 25803 27362 28175 25803 26516 27362 25805 25806 25808 25807 25806 25805 25806 25807 26524 26524 25808 25806 25808 26524 26526 25821 25820 25809 25809 25810 25821 26532 25821 25810 28181 26532 25810 25810 27374 28181 25810 26525 27374 25810 25811 26525 25811 25812 26525 27374 26525 25812 25812 26521 27374 25813 25814 26527 26533 25817 25815 26548 26533 25815 25815 26544 26548 25815 26528 26544 25815 25816 26528 25816 26526 26528 26533 26529 25817 25818 25819 25826 26538 25826 25819 25819 25820 26538 26539 26538 25820 27383 26539 25820 25820 26532 27383 25820 25821 26532 27382 25824 25822 25822 27381 27382 25822 27380 27381 25822 25823 27380 25823 26534 27380 26531 26530 25824 27382 26531 25824 26537 25832 25825 25825 25826 26537 25826 26536 26537 26538 26536 25826 26547 25836 25827 25827 25828 26547 25829 25828 25827 26540 25829 25827 25828 26541 26547 26542 26541 25828 25828 25829 26542 27385 26542 25829 25829 26540 27385 27385 26540 25830 25830 27384 27385 25830 26546 27384 25831 25832 26545 25832 26537 26545 27397 26543 25834 25835 26555 27403 25835 25836 26555 27393 26555 25836 25836 26547 27393 25841 25840 25837 25842 25841 25837 26559 25842 25837 26554 26553 25838 28207 26554 25838 25838 27400 28207 25838 25839 27400 28210 27400 25839 25839 27399 28210 25841 26556 27399 25841 25842 26556 26559 26556 25842 25843 25847 25848 25843 25846 25847 26567 25846 25845 25845 25849 26567 28222 25847 25846 25846 26567 28222 27405 25848 25847 27413 27405 25847 28222 27413 25847 27405 27398 25848 27411 26567 25849 25849 27409 27411 25849 26570 27409 25849 26566 26570 25849 25850 26566 25850 26564 26566 25850 25852 26564 26563 25852 25851 25851 26560 26563 25852 26563 26564 25853 25854 25859 25855 25854 25853 25858 25855 25853 25853 25856 25858 25864 25859 25854 26576 25864 25854 26578 26576 25854 25854 25855 26578 26592 26578 25855 27417 26592 25855 25855 25858 27417 25856 25857 25858 27418 25858 25857 25857 26579 27418 27418 27417 25858 26596 26580 25860 26586 26584 25861 26590 26586 25861 25861 26589 26590 25861 26585 26589 25861 25862 26585 25862 25870 26585 25863 25864 25873 26576 25873 25864 25865 26581 26598 26573 26560 25867 30079 26573 25867 30909 30079 25867 25867 29161 30909 25867 27437 29161 25867 26601 27437 25868 25869 28235 25868 28251 28254 25868 28235 28251 25870 25871 26585 26588 26585 25871 26608 26588 25871 25873 26588 26608 25873 26587 26588 25873 26576 26587 27427 26609 25874 25874 26620 27427 25874 25883 26620 26621 26614 25875 25875 26613 26621 25875 26612 26613 25875 25876 26612 25876 26599 26600 25885 25884 25877 25891 25885 25877 26626 25891 25877 25880 25879 25878 25887 25880 25878 25889 25887 25878 25893 25889 25878 25879 25880 25883 25880 25882 25883 25887 25882 25880 26633 25883 25882 26634 26633 25882 26635 26634 25882 25882 25890 26635 25882 25887 25890 26633 26620 25883 25884 25885 25891 25886 27455 28276 27461 26656 25886 28285 27461 25886 25886 28276 28285 25887 25888 25890 25889 25888 25887 25888 25889 25898 26643 25890 25888 26645 26643 25888 25888 25898 26645 25889 25893 25898 25890 26630 26635 26643 26630 25890 27456 25892 25891 27457 27456 25891 28271 27457 25891 25891 26626 28271 27456 25894 25892 25899 25898 25893 25900 25899 25893 28283 26646 25894 25894 27456 28283 26654 25896 25895 25895 26647 26654 27452 26639 25896 25896 26654 27452 26653 25901 25897 25898 25899 26645 25899 25900 27470 28289 26645 25899 25899 28278 28289 25899 27470 28278 25900 26650 27470 25900 26649 26650 25900 26648 26649 26655 25908 25901 25901 26653 26655 26649 26648 25902 27471 26649 25902 25902 26652 27471 26659 25927 25905 27478 26659 25905 25905 25906 27478 25907 25906 25905 28294 27478 25906 25906 27460 28294 25906 27459 27460 27479 27459 25906 25906 25907 27479 25907 26655 27479 25907 25908 26655 25913 25912 25909 25914 25913 25909 26663 25914 25909 27476 26657 25910 25910 27475 27476 25910 25911 27475 25911 26661 27475 25911 26660 26661 26672 25921 25912 25912 25913 26672 26673 26672 25913 25913 25914 26673 25914 26663 26673 25919 25918 25915 25915 25916 25919 25917 25916 25915 26670 25919 25916 25916 26669 26670 25916 25917 26669 25917 25922 26669 25918 25919 25920 25925 25920 25919 26670 25925 25919 27483 26674 25920 25920 25925 27483 25923 25922 25921 27489 25923 25921 25921 26672 27489 27482 26669 25922 27485 27482 25922 25922 25923 27485 28307 27485 25923 25923 28304 28307 25923 27489 28304 25924 25930 25936 25924 25929 25930 25925 26670 27483 25933 25932 25926 27486 25933 25926 26675 25934 25927 25927 26659 26675 26679 26668 25928 25928 25935 26679 25931 25930 25929 25937 25931 25929 26684 25941 25930 25941 25936 25930 25932 25933 25942 26680 25942 25933 27494 26680 25933 25933 27490 27494 25933 27487 27490 25933 27486 27487 26681 26676 25934 27492 26681 25934 25934 26675 27492 25935 25938 26679 25941 25940 25936 26683 26679 25938 25938 25945 26683 26687 25949 25939 25939 26684 26687 25939 25940 26684 25940 25941 26684 25947 25943 25942 26680 25947 25942 27499 26683 25945 27509 27499 25945 25945 26695 27509 28311 27507 25946 25946 26692 28311 25946 26691 26692 25946 26680 26691 25946 25947 26680 26696 25950 25949 27502 26696 25949 25949 26688 27502 25949 26687 26688 26696 25951 25950 25953 26689 26690 26716 25960 25954 27528 26716 25954 25954 26717 27528 25955 25956 25959 25967 25959 25956 25968 25967 25956 25957 25958 26703 28328 26703 25958 25958 27508 28328 25958 26694 27508 25960 26716 26718 26708 26706 25961 25961 25962 26708 25963 25962 25961 25962 26707 26708 27529 26707 25962 25962 25963 27529 27531 27529 25963 28337 27531 25963 25963 26701 28337 25963 26700 26701 25964 25965 26742 25966 25965 25964 26723 25966 25964 27534 26723 25964 25964 26742 27534 25965 25966 25979 25965 25979 26742 27527 26717 25967 25967 26726 27527 25967 25968 26726 25968 26702 26724 26728 26726 25968 26732 26728 25968 25968 26724 26732 27540 27536 25969 25969 26736 27540 25969 25974 26736 25969 25970 25974 25970 25973 25974 26730 25976 25971 26737 26736 25974 25975 25985 25989 25975 25984 25985 26735 25984 25975 25975 25982 26735 27547 26737 25976 27548 27547 25976 27549 27548 25976 25976 26738 27549 25976 26730 26738 27567 26750 25977 25977 27566 27567 25977 26758 27566 26750 25978 25977 26750 26744 25978 25979 26740 26742 25979 26739 26740 25979 25980 26739 26743 26739 25980 25980 25981 26743 25981 25983 26743 25982 26729 26735 27552 26743 25983 25983 26748 27552 26749 26748 25983 25983 25988 26749 25986 25985 25984 26735 25986 25984 25985 25986 27558 26754 25989 25985 27558 26754 25985 25986 27541 27545 25986 26735 27541 25986 27545 27558 25988 25991 26753 26753 26749 25988 26757 25992 25989 25989 26754 26757 26751 25994 25990 25990 26746 26751 25991 25995 26752 25991 26752 26753 26757 25996 25992 26757 25999 25996 27569 26755 25998 27581 27569 25998 25998 26769 27581 25998 26755 26756 27562 26760 25999 27564 27562 25999 25999 26757 27564 27570 26001 26000 28411 27570 26000 26000 27586 28411 27565 26758 26001 27570 27565 26001 26764 26006 26002 26003 26004 26776 26004 26768 26776 26004 26763 26768 26770 26010 26006 26006 26764 26770 26772 26011 26007 26007 26008 26772 26773 26772 26008 26777 26773 26008 26008 26776 26777 27583 26769 26009 27588 27583 26009 26009 26789 27588 26026 26024 26012 26791 26026 26012 26012 26013 26791 26013 26778 26791 26788 26016 26015 28416 26788 26015 28424 28416 26015 26015 26795 28424 26015 26786 26795 28417 26820 26016 26016 26787 28417 26788 26787 26016 26017 26018 26057 26019 26018 26017 26814 26019 26017 26017 26808 26814 26017 26053 26808 26018 26054 26057 26056 26054 26018 26062 26056 26018 26018 26019 26062 26019 26814 27608 26831 26062 26019 27608 26831 26019 27588 26789 26020 27589 27588 26020 26020 26021 27589 26022 26021 26020 27590 27589 26021 26021 26813 27590 26021 26034 26813 26021 26022 26034 26025 26024 26023 27600 26806 26023 26023 27594 27600 26023 26024 27594 27595 27594 26024 26024 26790 27595 26024 26026 26790 26791 26790 26026 26027 26028 26031 26029 26028 26027 26797 26029 26027 26027 26042 26797 26028 26029 26792 26029 26797 26827 27591 26792 26029 26029 26827 27591 26032 26780 26781 26821 26813 26034 26034 26035 26821 26035 26037 26826 27616 26821 26035 26035 26826 27616 26036 26046 26059 26047 26037 26036 26059 26047 26036 26037 26047 26826 26038 26039 26050 26040 26039 26038 26039 26048 26050 26049 26048 26039 26802 26049 26039 26805 26802 26039 26039 26040 26805 26040 26041 26805 27597 26805 26041 27600 27597 26041 26041 26806 27600 26827 26797 26042 26042 26807 26827 26042 26051 26807 26043 26044 26818 26044 26812 26818 26044 26045 26812 26045 26801 26812 26047 26059 26826 26060 26050 26048 27622 26060 26048 26048 26822 27622 26048 26049 26822 27596 26822 26049 26049 26803 27596 26049 26802 26803 26051 26052 26807 26829 26807 26052 27613 26829 26052 26052 26823 27613 27608 26808 26053 26053 26798 27608 26053 26794 26798 26058 26057 26054 26817 26058 26054 26830 26817 26054 26834 26830 26054 26835 26834 26054 26054 26055 26835 26056 26055 26054 26062 26061 26055 26055 26056 26062 26055 26833 26835 26055 26832 26833 26055 26061 26832 26058 26817 26824 26059 26063 26826 27622 26067 26060 26061 26062 26838 26837 26832 26061 26838 26837 26061 26062 26831 26838 26853 26826 26063 26836 26065 26064 26845 26074 26066 26066 26067 26845 27634 26845 26067 28436 27634 26067 26067 27622 28436 26068 26076 26858 27630 27627 26068 26068 26858 27630 26072 26070 26069 26072 26071 26070 26071 26844 26846 26071 26843 26844 26071 26072 26843 27633 26843 26072 26849 26075 26073 27643 26849 26073 28457 27643 26073 26073 28452 28457 26073 27634 28452 26073 26851 27634 26073 26074 26851 26075 26074 26073 26074 26845 26851 26075 26850 26856 26075 26849 26850 26857 26082 26075 26075 26856 26857 28487 26875 26077 28488 28487 26077 26077 28482 28488 26077 26078 28482 26078 28476 28482 26078 28475 28476 26078 28465 28475 26078 26852 28465 26078 26846 26852 26079 26080 26081 26079 26854 28477 26079 26081 26854 26855 26854 26081 26870 26862 26083 26083 26084 26870 26084 26863 26870 26084 26861 26863 26084 26086 26861 26084 26085 26086 26864 26861 26086 26086 26087 26864 26087 26088 26864 26866 26864 26088 26867 26866 26088 26092 26093 26096 26880 26096 26093 26093 26869 26880 26093 26862 26869 26886 26885 26094 26094 26103 26886 26104 26103 26094 26094 26097 26104 26885 26877 26094 26896 26106 26095 26095 26887 26896 26095 26098 26887 26880 26098 26096 26097 26099 26104 26888 26887 26098 26098 26880 26888 27672 26104 26099 27682 27672 26099 27683 27682 26099 26099 26101 27683 26102 26101 26099 26099 26100 26102 26115 26102 26100 26100 26112 26115 26101 26911 27683 26101 26102 26911 26915 26911 26102 26102 26115 26915 26103 26879 26886 26103 26104 26879 27659 26879 26104 27672 27659 26104 26912 26108 26105 26105 26903 26912 26105 26106 26903 26904 26903 26106 26905 26904 26106 26106 26896 26905 27696 26930 26107 26107 26910 27696 26117 26113 26108 26912 26117 26108 26109 26890 26899 26110 28528 28529 26110 28527 28528 26110 27681 28527 26110 26111 27681 28529 26910 26110 26111 26900 27681 26111 26894 26900 26901 26894 26111 26116 26115 26112 26113 26921 27704 26113 26117 26921 26919 26121 26113 27704 26919 26113 26917 26914 26114 26928 26917 26114 26929 26928 26114 26914 26889 26114 27682 26915 26115 26115 26918 27682 26115 26116 26918 26116 26120 26918 26117 26913 26923 26117 26912 26913 26117 26920 26921 26923 26920 26117 27712 26929 26118 28551 27712 26118 28553 28551 26118 26118 26932 28553 26118 26119 26932 26119 26931 26932 26119 26122 26931 27685 26918 26120 26120 26935 27685 26919 26126 26121 30394 29447 26123 26123 26124 30394 31208 30394 26124 26124 26939 31208 28532 26942 26126 26126 26919 28532 26944 26940 26127 26127 26943 26944 26127 26145 26943 26127 26128 26145 26146 26145 26128 26147 26146 26128 26148 26147 26128 26152 26140 26129 26129 26130 26152 26130 26150 26152 26130 26136 26150 26131 26141 26955 27719 26945 26132 26945 26134 26133 27722 26149 26134 26134 26945 27722 26136 26137 26150 26151 26150 26137 26137 26138 26151 26946 26151 26138 26138 26941 26946 26951 26947 26139 26952 26951 26139 26139 26140 26952 26140 26154 26952 26140 26152 26154 26141 26953 26955 26141 26950 26953 26968 26958 26142 26158 26144 26143 26143 26155 26158 26158 26156 26144 26145 26146 26943 27721 26943 26146 26146 26147 27721 27723 26957 26149 26149 27722 27723 26153 26152 26150 26160 26153 26150 26150 26151 26160 26946 26160 26151 26152 26153 26154 26157 26154 26153 26161 26157 26153 26170 26161 26153 27724 26170 26153 26153 26160 27724 26154 26157 26952 26960 26158 26155 26155 26956 26960 26157 26164 26952 26157 26161 26164 26962 26961 26158 29485 26962 26158 26158 26960 29485 26961 26175 26159 28582 27724 26160 26160 28579 28582 26160 27720 28579 26160 26946 27720 26165 26164 26161 26170 26165 26161 26173 26172 26162 26162 26163 26173 26163 26171 26977 27742 26173 26163 26163 26977 27742 26970 26952 26164 26164 26165 26970 26974 26970 26165 26165 26169 26974 26170 26169 26165 27753 26973 26167 27754 27753 26167 26167 26982 27754 26167 26168 26982 27728 26974 26169 28597 27728 26169 26169 28587 28597 26169 26170 28587 26170 28582 28587 26170 27724 28582 28607 27752 26172 26172 27761 28607 26172 27751 27761 26172 27742 27751 26172 26173 27742 26174 26979 26987 26174 26976 26979 26175 26961 26962 26175 26962 26976 26184 26183 26176 26176 26179 26184 26183 26178 26176 27770 26981 26177 26177 26994 27770 26178 26187 26188 26178 26183 26187 26185 26184 26179 26188 26185 26179 26180 26181 26988 26993 26988 26181 26181 26192 26993 27778 26996 26182 27779 27778 26182 26183 26184 26992 26992 26187 26183 26184 26185 26992 26188 26187 26185 26185 26187 26992 27770 26994 26186 27783 27770 26186 26186 26997 27783 27002 26197 26191 27775 27002 26191 26191 27774 27775 26191 26987 27774 27776 26993 26192 26193 26995 27005 26996 26995 26193 27000 26997 26194 27001 27000 26194 26195 26197 26198 26195 26196 26197 27788 26198 26197 26197 26998 27788 26999 26998 26197 27002 26999 26197 27788 26203 26198 28643 27777 26199 28645 28643 26199 26199 27793 28645 28638 26205 26200 26200 27787 28638 26201 26206 27011 26201 26202 26206 26202 26203 26206 27792 26206 26203 26203 27788 27792 27803 26208 26204 28655 27803 26204 26204 26205 28655 26205 28638 28655 27012 27011 26206 27013 27012 26206 27791 27013 26206 27792 27791 26206 26207 26208 26212 27020 26212 26208 27802 27020 26208 27803 27802 26208 26209 26210 27020 26211 26210 26209 27021 26211 26209 27026 27021 26209 27027 27026 26209 26209 27020 27027 26210 26212 27020 26210 26211 27007 27022 27007 26211 27024 27022 26211 26211 27021 27024 26216 26214 26213 26221 26216 26213 27025 27016 26214 27816 27025 26214 26214 27815 27816 26214 26216 27815 27812 26217 26215 26215 27799 27812 26215 27012 27799 26216 26221 27815 27843 26227 26218 28695 27843 26218 28663 27817 26219 28681 28663 26219 26219 26220 28681 26221 26220 26219 27815 26221 26219 27817 27815 26219 29579 28681 26220 29593 29579 26220 29594 29593 26220 26220 27861 29594 26220 27064 27861 26220 26221 27064 27040 27039 26222 26222 26226 27040 26222 26223 26229 26224 26223 26222 27038 26224 26222 26222 27036 27038 27037 27036 26222 27828 27037 26222 26222 27039 27828 26223 26228 26229 26223 26224 26228 27054 26228 26224 26224 27038 27054 27851 27850 26225 27858 27851 26225 26225 26231 27858 27073 26226 26225 27850 27073 26225 26226 27039 27040 27073 27039 26226 26227 27074 27075 27843 27074 26227 26230 26229 26228 26233 26230 26228 27082 26233 26228 27083 27082 26228 26228 27063 27083 26228 27054 27063 26231 27074 27858 27075 27074 26231 27082 26234 26233 26234 27081 27090 27082 27081 26234 27093 26239 26236 26236 27092 27093 26236 26237 27092 27866 27092 26237 26237 27103 27866 26238 26239 26242 26245 26242 26239 27098 26245 26239 26239 27093 27098 27113 27106 26241 27106 27097 26241 26242 26245 27110 26243 27084 27085 27875 27084 26243 26243 27110 27875 27875 27110 26245 26245 27107 27875 26245 27098 27107 26249 26248 26247 26248 26249 27881 26249 26250 27881 27882 27881 26250 26250 27115 27882 28771 27886 26251 26251 27118 28771 26251 26253 27118 27883 27113 26252 27884 27883 26252 26252 26257 27884 26258 26257 26252 26259 26258 26252 26252 26255 26259 27119 27118 26253 26253 26254 27119 26255 26256 26259 27124 26259 26256 26256 26266 27124 26256 26264 26266 28753 27884 26257 26257 26258 28753 26258 26259 27124 26258 27893 28753 26258 27887 27893 26258 27124 27887 27126 26265 26262 26262 27123 27126 26262 27091 27123 26262 27090 27091 26262 26263 27090 27130 26266 26264 26264 26267 27130 27126 26272 26265 28763 27124 26266 26266 27903 28763 26266 27130 27903 27133 27130 26267 26267 26268 27133 27135 27133 26268 27906 26274 26269 26269 27904 27906 26269 26270 27904 26270 27888 27904 26270 27881 27888 26271 27138 27139 26271 27136 27138 26271 26275 27136 26271 26274 26275 26272 27126 27896 26273 27132 27137 27906 26275 26274 27907 27136 26275 26275 27906 27907 27147 26279 26276 27922 27131 26277 26277 27921 27922 28802 27921 26277 26277 27145 28802 26277 27144 27145 26277 26279 27144 27147 27144 26279 26280 27134 27135 27141 27134 26280 27927 27925 26281 26281 27917 27927 26281 27143 27917 27154 27153 26282 27933 27154 26282 26282 27932 27933 27156 26284 26283 26287 26286 26285 27948 26287 26285 26285 26288 27948 28834 27932 26286 28835 28834 26286 26286 27941 28835 26286 26287 27941 27949 27941 26287 26287 27948 27949 27952 27948 26288 26288 27951 27952 26288 27185 27951 26288 26289 27185 26289 27168 27185 26289 26297 27168 26290 26291 26295 26293 26291 26290 26291 26292 27957 27166 26295 26291 27167 27166 26291 27957 27167 26291 26294 26295 27175 27182 26296 26294 26294 27176 27182 26294 27175 27176 26295 27166 27175 27182 26301 26296 26297 26304 27168 27181 26299 26298 26298 27173 27181 27174 27173 26298 26298 26302 27174 26298 26300 26302 26299 26314 26335 26315 26314 26299 27181 26315 26299 26300 26301 26302 27182 26302 26301 27182 27174 26302 26307 26304 26303 27187 27168 26304 26304 26306 27187 26304 26305 26306 26307 26305 26304 26309 26306 26305 26305 26308 26309 26316 26308 26305 26305 26307 26316 26306 27160 27187 27161 27160 26306 26306 26311 27161 26306 26309 26311 26311 26309 26308 26308 26310 26311 26319 26310 26308 27190 26311 26310 26310 26319 27190 27170 27161 26311 27189 27170 26311 26311 27180 27189 27188 27180 26311 27190 27188 26311 26326 26324 26312 26312 26313 26326 26312 26324 26325 27198 26335 26314 27975 27198 26314 26314 27972 27975 26314 26315 27972 28889 27972 26315 26315 28880 28889 28881 28880 26315 26315 27965 28881 26315 27181 27965 26317 26318 26322 26321 26319 26317 26322 26321 26317 26328 26322 26318 26319 26321 27190 26335 26333 26320 27191 27190 26321 27971 27191 26321 27978 27971 26321 26321 26322 27978 26322 27192 27978 26322 26327 27192 26328 26327 26322 26323 26326 26346 26323 26324 26326 26326 26334 26346 26326 26333 26334 27199 27192 26327 26327 26328 26340 27203 27195 26329 27202 26339 26330 26330 26332 27202 27195 26332 26331 26332 27195 27202 27196 26334 26333 26333 26335 27196 26334 27196 27197 27210 26346 26334 27222 27210 26334 26334 27197 27222 27198 27196 26335 26336 26341 26363 27979 27201 26337 26337 26339 27979 26337 26338 26339 27988 27979 26339 27989 27988 26339 26339 27980 27989 27981 27980 26339 26339 27207 27981 26339 27202 27207 26341 26347 27211 27211 26363 26341 26344 26343 26342 26365 26344 26342 26343 26344 28014 28014 26372 26343 26344 27212 27219 26344 26365 27212 26344 27219 28014 26345 26353 27204 26348 26362 27211 26371 26362 26348 26348 26349 26371 27214 26355 26350 26350 27210 27214 26351 26356 27218 26361 26357 26352 27213 27204 26353 26353 26354 27213 27220 27213 26354 27221 27220 26354 26354 26379 27221 26355 27214 27216 27216 26373 26355 27226 27218 26357 26357 26359 27226 26363 26359 26357 26357 26361 26363 26358 26359 26363 26360 26359 26358 26362 26360 26358 26363 26362 26358 27228 27226 26359 26359 26368 27228 26359 26360 26368 26360 26362 26367 26375 26367 26362 26362 26371 26375 26362 26363 27211 26388 26370 26364 26364 26376 26388 26377 26376 26364 26365 27205 27212 27206 27205 26365 26375 26370 26366 26366 26367 26375 26368 26384 26386 26387 26384 26368 26368 26385 27228 26386 26385 26368 26375 26371 26369 26369 26370 26375 26372 28042 28929 26372 28014 28042 26373 27216 27217 26374 26388 26392 26392 26388 26376 27239 26380 26378 28004 27221 26379 26379 27227 28004 28038 27227 26380 26380 27239 28038 26383 26382 26381 27234 26384 26382 27237 27234 26382 26382 26383 27237 26383 26390 27237 28926 26386 26384 26384 27236 28926 26384 27235 27236 26384 27234 27235 28032 28031 26385 28926 28032 26385 26385 26386 28926 28031 27228 26385 26404 26393 26389 28053 26404 26389 27238 27237 26390 28041 27238 26390 28057 28041 26390 28059 28057 26390 26390 27243 28059 26390 26391 27243 26394 26395 26403 27244 26403 26395 26395 26397 27244 26395 26396 26397 28056 26397 26396 28056 28050 26397 28055 27244 26397 26397 28050 28055 26398 26406 27246 26398 26405 26406 26402 26401 26400 27248 27247 26404 28053 27248 26404 28068 26406 26405 28069 28068 26405 28065 27246 26406 28959 28065 26406 28961 28959 26406 26406 28068 28961 26408 27249 28074 28074 28073 26408 27254 26411 26409 27260 27254 26409 26409 27258 27260 26409 26410 27258 26410 26414 27258 26410 26413 26414 27257 26412 26411 26411 27253 27257 27254 27253 26411 27257 26415 26412 26416 26414 26413 27265 27258 26414 26414 26416 27265 27257 27255 26415 27264 26418 26417 26417 27262 27264 27271 26423 26418 28987 27271 26418 26418 27264 28987 26419 26420 27267 27269 27267 26420 28991 27269 26420 26420 27275 28991 27276 27275 26420 27277 27276 26420 26420 26431 27277 28092 27266 26422 26422 27270 28092 26422 26424 27270 26423 27271 28085 26425 26428 26429 26425 26426 26428 28085 26428 26426 26427 28094 28106 27285 26429 26428 28098 27285 26428 26428 28085 28098 27285 26435 26429 27286 26431 26430 27290 27286 26430 26430 26445 27290 27286 27277 26431 26434 27263 27278 27297 26444 26435 26435 27285 27297 27290 26445 26436 27300 27290 26436 26436 27297 27300 26436 26444 27297 26438 27302 28119 26438 26439 27302 26440 26439 26438 26447 26440 26438 27301 26447 26438 28104 27301 26438 28119 28104 26438 26443 26442 26441 26447 26443 26441 27281 26449 26442 27282 27281 26442 26442 26443 27282 27294 27282 26443 26443 26447 27294 28122 28116 26446 26446 28115 28122 26446 27309 28115 27301 27294 26447 26448 27287 27296 26448 26449 27287 26449 27281 27287 27288 27263 26450 26451 27263 27288 27303 27263 26451 26451 27296 27303 26452 27311 27316 28120 27311 26452 27306 26460 26456 29018 28118 26457 26457 29015 29018 26457 26458 29015 26459 26458 26457 28118 26459 26457 26458 28117 29015 26458 26460 28117 26458 26459 26460 26465 26461 26459 28118 26465 26459 26460 27306 28117 27314 27302 26462 26462 27310 27314 27317 26464 26463 26463 26466 27317 26464 27317 28127 27318 27317 26466 27330 27318 26466 26466 27329 27330 26466 26467 27329 27337 27329 26467 26467 26480 27337 26467 26478 26480 26469 27327 27336 26469 27315 27327 27332 27323 26470 26470 26475 27332 26476 26475 26470 27321 26476 26470 28143 27331 26471 26471 26472 28143 26473 26472 26471 26474 26473 26471 27331 26474 26471 29034 28143 26472 29963 29034 26472 26472 26473 29963 26473 27320 29963 26473 26474 27320 27333 27332 26475 27357 27333 26475 28145 27357 26475 26475 26476 28145 26476 27321 27342 26476 27343 28145 26476 27342 27343 26481 26480 26478 27341 26482 26479 26479 27331 27341 26480 26481 27337 27338 27337 26481 26481 26487 27338 27341 26484 26482 26486 26485 26483 28152 26486 26483 26483 28151 28152 26483 26484 28151 26484 27341 28151 27362 26516 26485 28162 27362 26485 26485 26486 28162 26486 28152 28162 26487 27344 28161 27356 27344 26487 26487 26488 27356 27340 27338 26487 28161 27340 26487 26488 26503 27356 26491 26490 26489 26492 26491 26489 27343 27342 26490 26490 26491 27343 28145 27343 26491 26491 27347 28145 26491 26492 27347 27360 26500 26493 26493 26494 27360 28155 27360 26494 26494 28141 28155 26494 27334 28141 27357 27347 26495 26495 26496 27357 26496 27352 27357 27353 27352 26496 26511 26510 26497 27350 26511 26497 27351 27350 26497 26497 26498 27351 27355 27351 26498 26498 26512 27355 26499 26500 27358 27359 27358 26500 27360 27359 26500 26514 26503 26502 27367 26514 26502 26502 27366 27367 26502 26515 27366 28166 27356 26503 26503 26506 28166 26514 26506 26503 26504 30031 30032 26504 28176 30031 26504 26505 28176 26506 26505 26504 29054 26506 26504 29068 29054 26504 29069 29068 26504 30035 29069 26504 26504 30032 30035 26505 27366 28176 27367 27366 26505 26505 26506 27367 26506 26514 27367 29054 28166 26506 28162 28152 26507 29064 28162 26507 30018 29064 26507 26507 29999 30018 26507 29998 29999 26507 26508 29998 26509 26508 26507 28152 26509 26507 26508 29988 29998 26508 29987 29988 26508 26509 29987 26509 28153 29987 26509 28152 28153 27354 27353 26510 26510 26511 27354 26511 27350 27354 28167 27355 26512 26512 28164 28167 26512 27363 28164 27364 27363 26512 26512 26517 27364 26513 26518 26520 26515 26523 27366 26517 26522 27364 28172 26520 26518 26518 28168 28172 26518 27361 28168 27372 27371 26519 28173 27372 26519 26519 26520 28173 26520 28172 28173 28178 27374 26521 26521 28174 28178 27365 27364 26522 27368 27365 26522 27371 27366 26523 27377 26528 26526 26526 26527 27377 26527 27375 27377 27376 27375 26527 27386 27376 26527 26527 26543 27386 27378 26544 26528 26528 27377 27378 26535 26534 26529 26529 26533 26535 27373 27368 26530 26530 26531 27373 28171 27373 26531 26531 27382 28171 29085 27383 26532 26532 28181 29085 26549 26535 26533 26533 26548 26549 26534 26550 27380 26534 26535 26550 26535 26549 26550 27390 26537 26536 26536 26538 27390 27388 26545 26537 26537 27387 27388 27390 27387 26537 26538 26539 27390 28187 27390 26539 26539 27383 28187 28196 26547 26541 29095 28196 26541 26541 26542 29095 26542 27385 28190 29096 29095 26542 29097 29096 26542 26542 28189 29097 28190 28189 26542 28183 27386 26543 28197 28183 26543 26543 27397 28197 27379 26548 26544 26544 27378 27379 27392 27384 26546 28196 27393 26547 26551 26549 26548 29091 26551 26548 29092 29091 26548 26548 29090 29092 26548 28191 29090 26548 27379 28191 26551 26550 26549 27381 27380 26550 28193 27381 26550 26550 27394 28193 27395 27394 26550 26550 26551 27395 28208 27395 26551 29091 28208 26551 27396 27391 26552 28207 28206 26554 28206 27396 26554 26555 27401 27403 26555 27393 27401 28209 27399 26556 28215 28209 26556 26556 26557 28215 26558 26557 26556 26559 26558 26556 29119 28215 26557 26557 29118 29119 26557 29117 29118 26557 26558 29117 26558 29111 29117 26558 27402 29111 26558 27389 27402 26558 27388 27389 26560 26561 26563 26562 26561 26560 26573 26562 26560 26565 26563 26561 27408 26565 26561 26561 27404 27408 26561 26562 27404 26562 26573 27404 26565 26564 26563 26564 26565 26566 26570 26566 26565 27408 26570 26565 26567 27411 28222 26575 26571 26568 27415 26575 26568 26568 27412 27415 26568 26569 27412 26569 26572 27412 27410 27409 26570 29126 27410 26570 26570 27406 29126 27408 27406 26570 26575 26574 26571 26572 27403 27412 27408 27404 26573 29121 27408 26573 30079 29121 26573 26582 26581 26574 26574 26575 26582 27416 26582 26575 26575 27415 27416 26591 26587 26576 26576 26577 26591 26578 26577 26576 26577 26592 28227 26577 26578 26592 27423 26591 26577 28227 27423 26577 27425 27418 26579 26579 26593 27425 26579 26580 26593 26596 26593 26580 26581 26583 26598 26581 26582 26583 27429 26583 26582 26582 27416 27429 27429 26598 26583 28236 28235 26584 28237 28236 26584 26584 27421 28237 26584 26586 27421 26585 26588 26589 26586 27420 27421 26586 26590 27420 26591 26590 26587 26589 26588 26587 26590 26589 26587 26590 26591 27420 27422 27420 26591 27423 27422 26591 26592 27417 28229 28229 28227 26592 26593 26631 27425 27440 26631 26593 26593 26594 27440 26595 26594 26593 27428 26595 26593 26593 26596 27428 26594 27426 27440 26594 26595 27426 27427 27426 26595 27434 27427 26595 26595 27428 27434 26596 26597 27428 26597 26609 27434 27434 27428 26597 26598 27429 28241 28241 27435 26598 26611 26600 26599 26599 26610 26611 26601 27432 27437 26601 27430 27432 26601 26606 27430 26601 26602 26606 26615 26605 26602 26602 26603 26615 26602 26604 26606 26605 26604 26602 26616 26615 26603 27431 26606 26604 26604 26607 27431 26604 26605 26607 26619 26607 26605 26605 26615 26619 27431 27430 26606 27439 27433 26607 26607 26619 27439 27433 27431 26607 26609 27427 27434 28234 26613 26612 27436 26621 26613 29159 27436 26613 26613 29151 29159 26613 28245 29151 26613 28234 28245 26615 26616 26619 27441 26619 26616 26616 26617 27441 26618 26617 26616 26617 26618 26636 28266 27441 26617 26617 26623 28266 26625 26623 26617 26636 26625 26617 27441 27439 26619 26620 26633 27427 27436 26622 26621 29159 26626 26622 26622 27436 29159 29170 28266 26623 26623 26624 29170 26625 26624 26623 29171 29170 26624 26624 27474 29171 26624 26625 27474 26625 26654 27474 28267 26654 26625 26625 27451 28267 26625 26636 27451 29159 28271 26626 26627 26638 26640 26627 26628 26638 26629 26628 26627 26637 26629 26627 26640 26637 26627 26628 26630 26638 26632 26630 26628 27446 26632 26628 26628 26629 27446 27449 27446 26629 26629 27442 27449 26629 26637 27442 27440 26635 26630 26630 26631 27440 26632 26631 26630 26643 26638 26630 28253 27425 26631 26631 27447 28253 26631 26632 27447 26632 27446 27447 26633 27426 27427 26633 26634 27426 27440 27426 26634 26634 26635 27440 26636 26639 27451 27450 27442 26637 27454 27450 26637 26637 26640 27454 26644 26642 26638 26638 26643 26644 26642 26640 26638 27452 27451 26639 26640 26641 27454 26642 26641 26640 27466 27454 26641 26641 27465 27466 26641 26642 27465 26642 26644 27468 27467 27465 26642 27469 27467 26642 26642 27468 27469 27468 26644 26643 26643 26645 27468 28288 27468 26645 28289 28288 26645 28279 27473 26646 29179 28279 26646 26646 28290 29179 26646 28283 28290 26651 26650 26649 29172 26651 26649 26649 27471 29172 26650 26651 29177 29177 27470 26650 26651 29172 29173 26651 29173 29177 27472 27471 26652 27473 27472 26652 26656 26655 26653 28267 27452 26654 28275 27474 26654 26655 26656 27479 26656 27461 27479 27476 26658 26657 26664 26663 26658 27476 26664 26658 29194 26675 26659 26659 28294 29194 26659 27478 28294 26662 26661 26660 26668 26662 26660 27480 27475 26661 26661 26667 27480 26661 26662 26667 26671 26667 26662 26662 26668 26671 26663 26664 26673 27481 26673 26664 26664 27477 27481 26664 27476 27477 26665 28297 29199 26665 26666 28297 26667 26666 26665 28296 26667 26665 29195 28296 26665 29199 29195 26665 26666 26667 26671 28308 28297 26666 26666 27493 28308 26666 26677 27493 26666 26671 26677 28296 27480 26667 26677 26671 26668 26678 26677 26668 26679 26678 26668 27484 26670 26669 26669 27482 27484 27484 27483 26670 28303 27489 26672 26672 28302 28303 26672 26673 28302 29200 28302 26673 26673 28298 29200 26673 27481 28298 27488 27486 26674 26674 27483 27488 28295 27492 26675 29214 28295 26675 30154 29214 26675 26675 29198 30154 26675 29194 29198 26677 26678 27493 26678 26683 27493 26678 26679 26683 27494 26691 26680 27497 27495 26681 26681 27492 27497 27498 27496 26682 26682 27497 27498 26682 27495 27497 26683 26686 27493 26683 26685 26686 27499 26685 26683 26689 26687 26684 26690 26689 26684 29228 27500 26685 26685 28312 29228 26685 27509 28312 26685 27499 27509 27500 26686 26685 28309 27493 26686 26686 27500 28309 26689 26688 26687 28314 27502 26688 28317 28314 26688 26688 26689 28317 26691 27494 29226 29226 26692 26691 29230 28311 26692 30174 29230 26692 26692 29226 30174 27508 26694 26693 27513 27509 26695 26696 27501 27506 27502 27501 26696 26701 26700 26697 27507 26701 26697 26698 26699 26704 26705 26704 26699 26701 27519 28337 27520 27519 26701 28326 27520 26701 26701 27514 28326 26701 27507 27514 26702 26703 26715 26702 26715 26724 26703 27525 27526 28328 27525 26703 27526 26715 26703 26704 26705 27518 28325 28318 26704 26704 27518 28325 26706 26710 26719 26711 26710 26706 26706 26708 26711 26709 26708 26707 27515 26709 26707 27532 27515 26707 26707 27529 27532 26708 26709 26711 26720 26711 26709 26722 26720 26709 27516 26722 26709 26709 27515 27516 26731 26719 26710 27537 26731 26710 26710 26721 27537 26710 26720 26721 26710 26711 26720 26712 27505 29231 33672 27505 26712 26712 32819 33672 26712 31934 32819 26712 26713 31934 26714 26713 26712 29231 26714 26712 26713 26714 31934 26714 30231 31934 26714 29267 30231 29269 29267 26714 30212 29269 26714 26714 29231 30212 26725 26724 26715 27526 26725 26715 28352 27539 26716 26716 28345 28352 26716 27528 28345 27539 26718 26716 26717 27527 27528 27539 26733 26718 26722 26721 26720 28353 27537 26721 29260 28353 26721 26721 26722 29260 26722 27521 29260 26722 27517 27521 26722 27516 27517 26723 27523 27524 27534 27523 26723 26724 26725 26732 27526 26732 26725 26728 26727 26726 28350 27527 26726 26726 26727 28350 26727 26728 26732 26727 27538 28350 26727 27526 27538 26727 26732 27526 27541 26735 26729 26729 26734 27541 28359 26738 26730 26731 27537 28356 27539 26734 26733 28363 27541 26734 26734 28352 28363 26734 27539 28352 26736 26737 27540 27544 27540 26737 27547 27544 26737 29287 27549 26738 26738 28359 29287 26747 26740 26739 26739 26743 26747 26740 26741 26742 26747 26741 26740 27551 26742 26741 28371 27551 26741 26741 27552 28371 26741 26747 27552 26742 27524 27534 29231 27524 26742 29269 29231 26742 26742 29267 29269 26742 27551 29267 27552 26747 26743 26746 26745 26744 27550 26746 26744 27559 27550 26744 26744 26750 27559 27550 26751 26746 28371 27552 26748 26748 27557 28371 26748 26749 27557 26749 26753 27557 27567 27560 26750 27560 27559 26750 27568 26759 26751 26751 27550 27568 27556 26753 26752 27569 27556 26752 26752 26755 27569 26756 26755 26752 26753 27556 27557 27564 26757 26754 26754 27563 27564 26754 27558 27563 26758 27565 27566 26768 26763 26759 27568 26768 26759 27578 27574 26760 26760 26761 27578 26762 26761 26760 27562 26762 26760 27574 27573 26760 30258 27578 26761 26761 29316 30258 26761 28409 29316 26761 28377 28409 26761 26762 28377 26762 28365 28377 26762 27561 28365 27562 27561 26762 26764 26765 26771 27573 26771 26765 30264 27586 26766 26766 29328 30264 26766 26767 29328 26767 26781 29328 26777 26776 26768 27575 26777 26768 27577 27575 26768 26768 27568 27577 27582 27581 26769 27583 27582 26769 27573 26779 26771 27587 26782 26772 26772 26773 27587 28413 27587 26773 26773 26774 28413 26775 26774 26773 26777 26775 26773 29313 29310 26774 26774 29312 29313 29315 29312 26774 30253 29315 26774 26774 26775 30253 29331 28413 26774 30272 29331 26774 26774 29310 30272 26775 27575 30253 26775 26777 27575 27584 26791 26778 26778 26779 27584 27585 27584 26779 26779 27574 27585 26779 27573 27574 26780 26792 27591 26793 26781 26780 27591 26793 26780 26781 29327 29328 26781 28421 29327 26781 26793 28421 26782 27587 28413 26784 26783 26782 28413 26784 26782 26783 26785 26794 26783 26784 26785 29340 26785 26784 26784 29332 29340 26784 29331 29332 26784 28413 29331 26798 26794 26785 26799 26798 26785 29340 26799 26785 26787 26788 28417 29336 28417 26788 26788 29335 29336 26788 28416 29335 28426 27595 26790 26790 28418 28426 26790 28415 28418 26790 26791 28415 26791 27584 28415 28422 28421 26793 29339 28422 26793 26793 27591 29339 26795 28423 28424 26795 27592 28423 26795 26796 27592 27593 27592 26796 26796 26800 27593 26798 26799 27608 28437 27608 26799 29356 28437 26799 26799 29347 29356 29348 29347 26799 30278 29348 26799 26799 29340 30278 27601 27593 26800 26800 26811 27601 27603 26812 26801 26801 26819 27603 26820 26819 26801 26804 26803 26802 26805 26804 26802 26803 26804 27596 26804 26805 27596 27597 27596 26805 26829 26827 26807 27608 26814 26808 28430 27609 26809 26809 26810 28430 30306 28430 26810 26810 26815 30306 26824 26815 26810 27602 27601 26811 28430 27602 26811 26811 27609 28430 27603 26818 26812 27610 27590 26813 26813 26821 27610 26824 26817 26815 26815 28440 30306 28441 28440 26815 26815 26816 28441 26817 26816 26815 26816 27620 27626 26816 26830 27620 26816 26817 26830 26816 27626 28441 26818 27603 27614 28433 27603 26819 26819 28427 28433 26819 26820 28427 26820 28417 28427 27612 27610 26821 28438 27612 26821 26821 27616 28438 26822 27604 27607 26822 27596 27604 28436 27622 26822 26822 27606 28436 27607 27606 26822 27619 27613 26823 28438 27616 26826 26826 26853 28438 28419 27591 26827 28420 28419 26827 26827 26828 28420 26829 26828 26827 29346 28420 26828 26828 28431 29346 26828 26829 28431 29345 28431 26829 26829 27613 29345 26830 26834 27620 27625 27624 26831 26831 27608 27625 27624 26838 26831 26841 26833 26832 26832 26837 26841 26840 26835 26833 28445 26840 26833 26833 27629 28445 26833 26841 27629 26834 26840 27620 26834 26835 26840 26837 26839 26841 26837 26838 26839 27624 26839 26838 26842 26841 26839 27628 26842 26839 26839 27624 27628 28445 27620 26840 27640 27629 26841 26841 26842 27640 26842 27628 27635 26842 27638 27640 26842 27636 27638 27637 27636 26842 27645 27637 26842 28454 27645 26842 26842 27635 28454 27641 26844 26843 26843 27633 27641 26852 26846 26844 28465 26852 26844 28467 28465 26844 26844 28456 28467 26844 27641 28456 27634 26851 26845 28438 26853 26847 28444 28438 26847 26847 26848 28444 30315 28444 26848 30319 30315 26848 27642 26850 26849 27643 27642 26849 27642 26856 26850 28489 28477 26854 28490 28489 26854 28491 28490 26854 26856 27642 27648 27648 26857 26856 26857 27648 27654 26858 26859 27630 28453 27630 26859 28469 28453 26859 26859 26860 28469 29389 28469 26860 26860 28478 29389 26871 26863 26861 26861 26864 26871 26881 26869 26862 26862 26870 26881 26882 26870 26863 27660 26882 26863 26863 26871 27660 26864 26865 26871 26866 26865 26864 27660 26871 26865 26865 26892 27660 26865 26866 26892 26866 26883 26892 26866 26867 26883 26868 26878 28505 29401 29400 26868 26868 28505 29401 26888 26880 26869 27665 26888 26869 26869 26881 27665 26882 26881 26870 26892 26883 26872 26899 26892 26872 27656 26875 26873 28507 27656 26873 28510 28507 26873 29406 28510 26873 26873 26874 29406 26875 26874 26873 26874 28487 29406 26874 26875 28487 26876 26884 26894 26879 26878 26877 26885 26879 26877 26878 27659 27669 26878 26879 27659 26878 27669 28505 26879 26885 26886 26881 26882 27665 27668 27665 26882 26882 27660 27668 26884 26893 26894 26895 26893 26884 26887 26888 26898 26897 26896 26887 26898 26897 26887 26906 26898 26888 27665 26906 26888 26914 26909 26889 26891 26890 26889 26909 26891 26889 27667 26899 26890 26890 26891 27667 26891 27666 27667 26891 26909 27666 27666 27660 26892 27667 27666 26892 26892 26899 27667 26902 26894 26893 28516 26902 26893 26893 28507 28516 26893 26895 28507 26902 26900 26894 26895 27656 28507 26896 26897 26905 26906 26905 26897 26897 26898 26906 26900 27670 27681 26900 26902 27670 27671 27670 26902 28520 27671 26902 26902 28516 28520 26913 26912 26903 26903 26904 26913 26923 26913 26904 26904 26905 26923 26905 26906 26923 27689 26923 26906 26906 26907 27689 26908 26907 26906 27677 26908 26906 27691 27677 26906 26906 27676 27691 26906 27663 27676 27665 27663 26906 27706 27705 26907 28542 27706 26907 26907 26908 28542 27709 27689 26907 26907 27705 27709 26908 27678 28542 26908 27677 27678 26909 26916 27666 26909 26914 26916 27697 27696 26910 28529 27697 26910 26911 26915 27683 26917 26916 26914 26915 27682 27683 27686 27666 26916 26916 26924 27686 26916 26917 26924 26934 26924 26917 26917 26928 26934 27685 27682 26918 28541 28532 26919 26919 27704 28541 26920 26933 27704 26920 26922 26933 26923 26922 26920 27704 26921 26920 26922 26923 26933 27689 26933 26923 27702 27686 26924 27703 27702 26924 26924 26934 27703 26925 26928 27711 26937 26928 26925 28549 26937 26925 26925 28533 28549 29456 28533 26925 26925 26926 29456 26927 26926 26925 27711 26927 26925 29457 29456 26926 30426 29457 26926 31226 30426 26926 26926 30404 31226 26926 26927 30404 31226 30404 26927 26927 29463 31226 26927 27711 29463 27703 26934 26928 26928 26937 27703 27712 27711 26928 26928 26929 27712 26930 27696 28538 26932 26931 26930 28538 26932 26930 26932 28538 28553 26933 27689 27704 27698 27685 26935 28530 27698 26935 26935 26936 28530 28539 28530 26936 26936 26938 28539 27710 27703 26937 28549 27710 26937 26939 30397 31208 26939 29448 30397 26939 27713 29448 29467 28562 26940 26940 26944 29467 27718 26946 26941 26941 27716 27718 28531 27716 26942 28532 28531 26942 29465 26944 26943 29466 29465 26943 26943 28561 29466 26943 27726 28561 26943 27721 27726 30413 29467 26944 26944 30412 30413 26944 29465 30412 28569 27722 26945 26945 27719 28569 26946 27718 28554 28554 27720 26946 26947 26951 26971 26963 26949 26948 26964 26963 26948 26954 26950 26949 26963 26954 26949 26954 26953 26950 27738 26971 26951 27744 27738 26951 26951 26975 27744 26951 26952 26975 26978 26975 26952 26985 26978 26952 26986 26985 26952 26952 26970 26986 26966 26955 26953 26953 26965 26966 26953 26954 26965 26954 26963 26965 26955 26966 26967 26956 26959 26960 26968 26959 26958 29486 26960 26959 26959 26969 29486 26959 26968 26969 29486 29485 26960 28594 28593 26962 29485 28594 26962 28599 26976 26962 26962 28593 28599 27729 26965 26963 26963 26972 27729 26963 26964 26972 26964 26971 26972 27729 26966 26965 27732 26967 26966 26966 27730 27732 27731 27730 26966 27741 27731 26966 26966 27729 27741 26968 27732 28598 27733 26969 26968 28598 27733 26968 29496 29486 26969 29497 29496 26969 26969 27733 29497 26970 26983 26986 26984 26983 26970 26970 26974 26984 27737 26972 26971 27738 27737 26971 27741 27729 26972 26972 27737 27741 28595 27735 26973 26973 27753 28595 27736 26984 26974 27743 27736 26974 26974 27739 27743 26974 27728 27739 27757 27744 26975 26975 26978 27757 27749 26979 26976 28599 27749 26976 27750 27742 26977 27767 27757 26978 26978 27756 27767 26978 26985 27756 27749 26987 26979 27769 27764 26980 26980 26981 27769 27764 26982 26980 26981 27770 28615 28615 27769 26981 27764 27754 26982 26989 26986 26983 26983 26984 26989 26991 26989 26984 27736 26991 26984 26985 26990 27756 26985 26986 26990 26986 26989 26990 28622 27774 26987 26987 28612 28622 26987 27759 28612 26987 27749 27759 26988 26993 27762 26991 26990 26989 28617 27756 26990 26990 28616 28617 26990 27766 28616 26990 26991 27766 26991 27765 27766 26991 27736 27765 27776 27773 26993 27773 27762 26993 26995 26996 27778 28629 27005 26995 26995 27782 28629 26995 27778 27782 27785 27783 26997 26997 27000 27785 28632 27788 26998 26998 26999 28632 26999 27002 28632 27000 27001 27785 27786 27785 27001 27001 27006 27786 27002 28627 28632 27002 27775 28627 28634 27787 27003 28659 28634 27003 29530 28659 27003 27003 29525 29530 27003 28631 29525 27003 27005 28631 27003 27004 27005 27005 28629 28631 27006 27007 27786 27007 27022 27786 27008 27012 27013 27799 27012 27008 27008 27009 27799 27010 27009 27008 27013 27010 27008 27812 27799 27009 27813 27812 27009 27009 27010 27813 28690 27813 27010 29564 28690 27010 27010 27013 29564 27013 28660 29564 27013 28657 28660 27013 27791 28657 27014 27017 27789 27018 27017 27015 27015 27016 27018 27025 27018 27016 27017 27019 27789 27017 27018 27019 27801 27019 27018 27806 27801 27018 27018 27804 27806 27018 27025 27804 27793 27789 27019 27794 27793 27019 27795 27794 27019 27801 27795 27019 27802 27027 27020 27796 27024 27021 27021 27028 27796 27029 27028 27021 27021 27026 27029 28635 27786 27022 28648 28635 27022 27022 27023 28648 27024 27023 27022 28649 28648 27023 27023 27797 28649 27023 27024 27797 27024 27796 27797 27816 27804 27025 27831 27058 27026 27839 27831 27026 27026 27027 27839 27031 27029 27026 27044 27031 27026 27058 27044 27026 27027 27802 27839 27798 27796 27028 28656 27798 27028 27028 27030 28656 27028 27029 27030 27031 27030 27029 28670 28656 27030 27030 27031 28670 28671 28670 27031 27031 27045 28671 27031 27044 27045 27032 27035 27036 27053 27035 27032 27032 27033 27053 27034 27033 27032 27037 27034 27032 27032 27036 27037 27033 27052 27053 27033 27047 27052 27051 27047 27033 27033 27049 27051 27050 27049 27033 27033 27034 27050 27811 27050 27034 28677 27811 27034 28678 28677 27034 27034 27037 28678 27054 27038 27035 27035 27053 27054 27038 27036 27035 28679 28678 27037 27037 27828 28679 27039 27073 27828 27041 28680 28690 27041 27812 28680 28695 27812 27041 27041 27852 28695 28713 27852 27041 27041 27042 28713 27043 27042 27041 28690 27043 27041 31359 28713 27042 27042 29577 31359 29578 29577 27042 31345 29578 27042 27042 27043 31345 27043 29564 31345 27043 28690 29564 27059 27045 27044 27044 27057 27059 27058 27057 27044 29571 28671 27045 29584 29571 27045 27045 27832 29584 27045 27059 27832 27826 27061 27046 28688 27826 27046 27046 28674 28688 27046 27827 28674 27046 27047 27827 27048 27047 27046 27061 27048 27046 27047 27051 27827 27055 27052 27047 27060 27055 27047 27047 27048 27060 27061 27060 27048 28672 27051 27049 27049 27810 28672 27049 27050 27810 27811 27810 27050 28676 27827 27051 28677 28676 27051 27051 28672 28677 27054 27053 27052 27063 27054 27052 27052 27056 27063 27052 27055 27056 27055 27071 27072 27055 27070 27071 27055 27060 27070 27072 27056 27055 27089 27063 27056 27096 27089 27056 27056 27072 27096 27068 27059 27057 27057 27067 27068 27057 27058 27067 27841 27067 27058 27058 27831 27841 27059 27069 27832 27059 27068 27069 27060 27062 27070 27060 27061 27062 27833 27062 27061 27061 27826 27833 27077 27070 27062 27086 27077 27062 27833 27086 27062 27089 27083 27063 27064 27076 27861 27068 27067 27065 27069 27068 27065 27857 27069 27065 27065 27066 27857 27067 27066 27065 27865 27857 27066 27066 27864 27865 27066 27856 27864 27066 27067 27856 27067 27855 27856 27067 27841 27855 27848 27832 27069 27857 27848 27069 27078 27071 27070 27070 27077 27078 27079 27072 27071 27071 27078 27079 27072 27095 27096 27072 27079 27095 28689 27828 27073 27073 27850 28689 27074 27843 27858 27862 27861 27076 27863 27862 27076 28697 27078 27077 27077 27849 28697 27077 27086 27849 27080 27079 27078 27087 27080 27078 27088 27087 27078 28709 27088 27078 27078 28697 28709 27079 27080 27095 27080 27094 27095 27080 27087 27094 27091 27090 27081 27094 27091 27081 27096 27094 27081 27081 27089 27096 27081 27083 27089 27081 27082 27083 27084 27860 27863 27084 27859 27860 27867 27859 27084 27875 27867 27084 28694 27849 27086 27086 27842 28694 27086 27833 27842 27099 27094 27087 27087 27088 27099 27100 27099 27088 27876 27100 27088 28709 27876 27088 27091 27122 27123 27091 27116 27122 27091 27111 27116 27091 27094 27111 27866 27093 27092 27866 27109 27093 27109 27098 27093 27112 27111 27094 27094 27099 27112 27096 27095 27094 27105 27104 27097 27106 27105 27097 27109 27107 27098 27877 27112 27099 27099 27100 27877 28742 27877 27100 27100 28734 28742 27100 28727 28734 27100 27876 28727 29605 28714 27101 29606 29605 27101 30525 29606 27101 27101 27102 30525 27103 27102 27101 28714 27103 27101 31370 30525 27102 27102 29629 31370 27102 28721 29629 27102 27103 28721 27874 27866 27103 28714 27874 27103 27103 27104 28721 27104 27880 28721 27104 27105 27880 27105 27113 27880 27105 27106 27113 28722 27875 27107 27107 27108 28722 27109 27108 27107 29632 28722 27108 27108 29630 29632 27108 28728 29630 27108 27109 28728 27109 27866 27872 27109 27872 28728 27117 27116 27111 27878 27117 27111 27111 27877 27878 27111 27112 27877 27883 27880 27113 27885 27115 27114 27885 27882 27115 27116 27117 27122 27117 27121 27122 27878 27121 27117 29656 28771 27118 29670 29656 27118 27118 27918 29670 27118 27120 27918 27118 27119 27120 27125 27120 27119 27120 27125 27918 27889 27122 27121 27895 27889 27121 28752 27895 27121 27121 27878 28752 27894 27123 27122 27122 27889 27894 27897 27126 27123 27123 27894 27897 28763 27887 27124 27125 27908 27918 27125 27131 27908 27897 27896 27126 27920 27911 27127 27127 27901 27920 27902 27901 27127 27127 27900 27902 27127 27892 27900 27127 27128 27892 27129 27128 27127 27137 27129 27127 27140 27137 27127 27910 27140 27127 27911 27910 27127 27128 27129 27132 27128 27891 27892 27128 27152 27891 27128 27132 27152 27137 27132 27129 27130 27133 27903 27922 27908 27131 27135 27134 27133 27913 27903 27133 27133 27912 27913 27133 27141 27912 27133 27134 27141 27907 27138 27136 27143 27139 27138 27917 27143 27138 27138 27916 27917 27138 27907 27916 27141 27142 27912 27142 27911 27912 27142 27149 27911 27146 27145 27144 27147 27146 27144 28817 28802 27145 27145 28803 28817 27145 27146 28803 27146 28797 28803 27146 27147 28797 27147 28795 28797 27147 27148 28795 27148 27909 28795 27149 27910 27911 28792 27152 27151 29672 28792 27151 30605 29672 27151 27151 27153 30605 27899 27891 27152 27905 27899 27152 28780 27905 27152 28792 28780 27152 27153 29695 30605 30614 29695 27153 27153 29729 30614 27153 27154 29729 27154 28833 29729 27154 27933 28833 27155 27929 27931 27156 27931 27936 27157 27169 27947 27157 27158 27169 27159 27158 27157 27947 27159 27157 27158 27161 27169 27158 27160 27161 27942 27160 27158 27158 27162 27942 27158 27159 27162 27939 27162 27159 27945 27939 27159 27947 27945 27159 27942 27186 27160 27160 27186 27187 27170 27169 27161 27944 27942 27162 27162 27938 27944 27939 27938 27162 27173 27171 27163 27181 27173 27163 27163 27164 27181 27165 27164 27163 27171 27165 27163 27965 27181 27164 27164 27961 27965 27164 27960 27961 27164 27165 27960 27165 27171 27172 27165 27955 27960 27165 27172 27955 27166 27167 27175 27962 27175 27167 27963 27962 27167 28877 27963 27167 29761 28877 27167 29762 29761 27167 27167 27958 29762 27167 27957 27958 27187 27185 27168 27169 27170 27947 27953 27947 27170 27954 27953 27170 27170 27189 27954 27171 27174 27183 27171 27173 27174 27183 27172 27171 28868 27955 27172 27172 27956 28868 27172 27183 27956 27174 27182 27183 27962 27176 27175 27184 27182 27176 27962 27184 27176 27189 27180 27177 27959 27189 27177 28872 27959 27177 28878 28872 27177 27177 27178 28878 27179 27178 27177 27180 27179 27177 27178 27964 28878 27178 27179 27964 27966 27964 27179 27179 27188 27966 27179 27180 27188 27184 27183 27182 27183 27184 27956 29760 27956 27184 30670 29760 27184 27184 29772 30670 27184 27962 29772 27185 27186 27951 27187 27186 27185 27186 27942 27950 27952 27951 27186 27186 27950 27952 27968 27966 27188 27970 27968 27188 27188 27191 27970 27188 27190 27191 27959 27954 27189 27971 27970 27191 27192 27973 27978 27192 27193 27973 27194 27193 27192 27985 27194 27192 27192 27199 27985 27974 27973 27193 29812 27974 27193 27193 27194 29812 31602 29812 27194 27194 29833 31602 27194 29832 29833 27194 29831 29832 29834 29831 27194 27194 28910 29834 27194 28899 28910 27194 27985 28899 27195 27203 27209 27982 27202 27195 27195 27209 27982 27977 27976 27196 27984 27977 27196 27196 27198 27984 27976 27197 27196 27995 27994 27197 28901 27995 27197 27197 28898 28901 27197 27976 28898 27994 27222 27197 27198 27975 27984 27987 27206 27200 27200 27979 27987 27200 27201 27979 27982 27207 27202 27203 27208 27209 27203 27204 27208 27993 27208 27204 27204 27213 27993 27986 27212 27205 27205 27206 27986 27987 27986 27206 27998 27981 27207 27207 27982 27998 29815 27992 27208 29822 29815 27208 27208 27993 29822 27992 27209 27208 27983 27982 27209 28897 27983 27209 27209 27992 28897 27215 27214 27210 27222 27215 27210 27986 27219 27212 28000 27993 27213 27213 27220 28000 27214 27215 27216 27223 27216 27215 27215 27222 27223 27229 27217 27216 27216 27225 27229 27216 27224 27225 27216 27223 27224 27217 27229 27240 27218 27226 28001 28044 28014 27219 28921 28044 27219 29824 28921 27219 27219 27986 29824 28004 28000 27220 27220 27221 28004 27994 27223 27222 27994 27224 27223 28005 27225 27224 28906 28005 27224 27224 27994 28906 28029 27229 27225 27225 28005 28029 28013 28001 27226 27226 27228 28013 28917 28004 27227 27227 28038 28917 28031 28013 27228 27229 28030 28039 27229 28029 28030 28039 27240 27229 27235 27233 27230 27230 27231 27235 27232 27231 27230 27238 27232 27230 27230 27237 27238 27230 27233 27237 28010 27235 27231 27231 28009 28010 27231 28006 28009 28021 28006 27231 27231 27232 28021 28040 28021 27232 27232 27238 28040 27233 27234 27237 27235 27234 27233 28023 27236 27235 27235 28010 28023 27236 28011 28918 28023 28011 27236 28927 28926 27236 27236 28918 28927 28041 28040 27238 28051 28038 27239 27239 27241 28051 27242 27241 27239 27241 28050 28051 28055 28050 27241 27241 27242 28055 27242 27244 28055 28065 28059 27243 27243 27246 28065 28939 28062 27245 27245 28063 28939 28064 28063 27245 27245 28030 28064 28039 28030 27245 27247 27248 28067 28067 27250 27247 27248 28053 28067 27249 27250 28074 27250 28067 28074 28969 28069 27251 27251 27252 28969 28973 28969 27252 28975 28973 27252 27252 28974 28975 27252 28075 28974 27253 27256 27257 28978 27256 27253 27253 27254 28978 27254 28977 28978 27254 27260 28977 28078 27261 27255 27255 28077 28078 27255 27259 28077 27255 27256 27259 27257 27256 27255 28982 27259 27256 27256 28978 28982 28084 27260 27258 27258 27265 28084 28981 28077 27259 28982 28981 27259 27260 28976 28977 29898 28976 27260 27260 28079 29898 28084 28079 27260 28078 27262 27261 28078 27264 27262 27295 27278 27263 27303 27295 27263 27264 28983 28987 27264 28078 28983 27265 28083 28084 27265 27266 28083 27266 28082 28083 28092 28082 27266 28994 27273 27268 29915 28994 27268 27268 28991 29915 27268 27269 28991 28093 28092 27270 27270 27274 28093 28995 28085 27271 29909 28995 27271 29910 29909 27271 27271 28987 29910 28994 28992 27272 27272 27273 28994 28096 28093 27274 27274 27278 28096 29915 28991 27275 29920 29915 27275 27275 27276 29920 27276 29919 29920 27276 27279 29919 27276 27277 27279 27280 27279 27277 28103 27280 27277 27277 27286 28103 27278 27295 28096 27279 27280 29919 27280 28103 29919 27281 27283 27287 27281 27282 27283 27284 27283 27282 28089 27284 27282 28095 28089 27282 27282 27294 28095 28096 27295 27283 27283 28082 28096 27283 27284 28082 27295 27287 27283 28091 28082 27284 27284 28087 28091 28089 28087 27284 27298 27297 27285 28101 27298 27285 27285 28098 28101 27286 27289 28103 27290 27289 27286 27287 27295 27296 28996 28103 27289 29000 28996 27289 27289 28110 29000 27289 27290 28110 27290 27299 28110 27304 27299 27290 27290 27300 27304 27294 27293 27291 28095 27294 27291 27291 28090 28095 28989 28090 27291 27291 28100 28989 27291 28099 28100 27291 27292 28099 27293 27292 27291 30778 28099 27292 27292 29006 30778 27292 29005 29006 27292 27293 29005 27293 27301 28104 27293 27294 27301 27293 28104 29005 27303 27296 27295 27304 27300 27297 27297 27299 27304 27297 27298 27299 29004 28108 27298 27298 28111 29004 27298 28101 28111 28108 27299 27298 28113 28110 27299 29009 28113 27299 27299 28112 29009 27299 28109 28112 27299 28108 28109 27302 29019 29938 29020 29019 27302 27302 28133 29020 27302 27314 28133 29938 28119 27302 27305 28107 28114 27306 27307 28117 27308 27307 27306 29015 28117 27307 27307 28124 29015 27307 27308 28124 27308 28116 28124 28121 28115 27309 27326 27314 27310 27310 27322 27326 27328 27316 27311 28139 27328 27311 28140 28139 27311 27311 27312 28140 27313 27312 27311 28120 27313 27311 29023 28140 27312 27312 27313 29023 29025 29023 27313 27313 29014 29025 27313 28114 29014 28120 28114 27313 27314 28128 28133 27314 27326 28128 27328 27327 27315 27315 27316 27328 27317 27318 28127 27318 28121 28127 27318 28115 28121 28123 28115 27318 29960 28123 27318 27318 27330 29960 29961 27320 27319 27319 29024 29961 27320 29961 29963 27322 27325 27326 27322 27323 27325 27333 27325 27323 27323 27332 27333 27326 27325 27324 28129 27326 27324 28132 28129 27324 27324 27333 28132 27324 27325 27333 28129 28128 27326 27327 27328 28139 28139 27336 27327 28142 27330 27329 27329 27337 28142 29965 29960 27330 29969 29965 27330 27330 29033 29969 27330 28142 29033 28143 27341 27331 27333 27352 28132 27357 27352 27333 27334 27336 28141 28146 28141 27336 27336 28139 28146 27337 27339 28142 27337 27338 27339 27340 27339 27338 28150 28142 27339 27339 27340 28150 27340 27345 28150 28161 27345 27340 27341 28144 28151 27341 28143 28144 27344 27345 28161 27346 27345 27344 29054 27346 27344 27344 28166 29054 27344 27356 28166 29974 28150 27345 27345 27346 29974 29984 29974 27346 30859 29984 27346 27346 29054 30859 27347 27357 28145 27354 27350 27348 28154 27354 27348 29032 28154 27348 27348 29031 29032 29971 29031 27348 27348 29039 29971 27348 28160 29039 27348 27349 28160 27350 27349 27348 27349 27355 28160 27349 27351 27355 27349 27350 27351 27352 27353 28132 28138 28132 27353 27353 27354 28138 28154 28138 27354 28163 28160 27355 29047 28163 27355 27355 28167 29047 28165 27361 27358 27358 27359 28165 27359 28156 29037 27359 27360 28156 28169 28165 27359 29037 28169 27359 27360 28155 28156 27361 28165 28168 29070 28175 27362 27362 29064 29070 27362 28162 29064 29059 28164 27363 27363 28170 29059 28171 28170 27363 27363 27364 28171 27364 27365 28171 27365 27368 28171 27366 27369 28176 27371 27369 27366 27368 27373 28171 29076 28176 27369 27369 27370 29076 27371 27370 27369 29077 29076 27370 27370 29075 29077 27370 27372 29075 27370 27371 27372 27372 28173 29075 27374 28177 28181 28178 28177 27374 28185 27377 27375 30039 28185 27375 27375 27376 30039 27376 28184 30039 27376 28183 28184 27376 27386 28183 28185 27378 27377 28191 27379 27378 28202 28191 27378 27378 28185 28202 28186 27382 27381 28192 28186 27381 28193 28192 27381 28186 28171 27382 28188 28187 27383 29085 28188 27383 28190 27385 27384 28195 28190 27384 27384 27392 28195 27389 27388 27387 28194 27389 27387 29093 28194 27387 27387 27390 29093 29104 27402 27389 27389 28194 29104 27390 28187 29093 28199 27392 27391 27391 27396 28199 28200 28195 27392 27392 28199 28200 28196 27401 27393 30066 29098 27394 27394 28204 30066 27394 28198 28204 27394 27395 28198 29098 28193 27394 28208 28198 27395 28205 28199 27396 28206 28205 27396 27397 27398 27414 28201 28197 27397 27397 27414 28201 27398 27405 27414 27399 28209 28210 28211 28207 27400 27400 28210 28211 27401 28196 29095 29115 27403 27401 27401 28218 29115 30054 28218 27401 27401 29095 30054 27402 29105 29111 27402 29104 29105 28220 27412 27403 29115 28220 27403 27405 27413 27414 30081 29126 27406 27406 30079 30081 27406 27407 30079 27408 27407 27406 27407 28216 30076 27407 27408 28216 27407 30076 30079 29121 28216 27408 28223 27411 27409 29129 28223 27409 27409 27410 29129 27410 29126 30081 30084 29129 27410 27410 30081 30084 28223 28222 27411 28226 27415 27412 27412 28220 28226 28221 27414 27413 29127 28221 27413 27413 28224 29127 27413 28222 28224 28212 28201 27414 28221 28212 27414 28226 28225 27415 28225 27416 27415 28241 27429 27416 27416 28239 28241 28240 28239 27416 27416 28225 28240 27417 27418 28229 28230 28229 27418 28238 28230 27418 27418 27425 28238 28243 28231 27419 27419 27435 28243 27424 27421 27420 27420 27422 27424 29133 28237 27421 27421 27424 29133 29133 27424 27422 29134 29133 27422 27422 27423 29134 27423 28228 29134 27423 28227 28228 28253 28238 27425 27438 27432 27430 27430 27431 27438 28258 27438 27431 27431 27433 28258 27438 27437 27432 27433 28259 29163 27433 27439 28259 29163 28258 27433 27435 28241 28243 27437 29160 29161 27437 28258 29160 27437 27438 28258 27439 27441 28259 28266 28259 27441 27442 27443 27449 27444 27443 27442 27450 27444 27442 28256 27449 27443 28265 28256 27443 27443 28264 28265 27443 28260 28264 27443 27444 28260 27444 27450 28260 28257 28253 27445 27445 28255 28257 28256 28255 27445 27445 27449 28256 27445 27446 27449 27447 27446 27445 28253 27447 27445 30116 27458 27448 27448 30109 30116 27448 29153 30109 27448 28247 29153 28254 28247 27448 28268 28260 27450 28274 28268 27450 27450 27453 28274 27454 27453 27450 27451 27452 28267 27453 27454 27466 27453 27462 28274 27464 27462 27453 27466 27464 27453 27455 27458 28277 28277 28276 27455 27456 28281 28283 27456 27457 28281 27457 28271 28281 27458 30116 30925 27458 28272 28277 28273 28272 27458 30126 28273 27458 30941 30126 27458 27458 30925 30941 27461 27460 27459 27479 27461 27459 29187 28294 27460 27460 27461 29187 27461 29186 29187 27461 28287 29186 27461 28285 28287 27462 28262 28274 28270 28262 27462 27462 27463 28270 27464 27463 27462 30131 28270 27463 27463 27464 30131 27464 29180 30131 29181 29180 27464 27464 27466 29181 27467 27466 27465 27466 27467 29181 30949 29181 27467 27467 27469 30949 29176 27469 27468 27468 28288 29176 31836 30949 27469 27469 31835 31836 27469 30933 31835 27469 29176 30933 29177 28278 27470 27471 27472 29172 29175 29172 27472 27472 28280 29175 27472 28279 28280 27472 27473 28279 30125 29171 27474 27474 28275 30125 29188 27476 27475 27475 27480 29188 28293 27477 27476 29188 28293 27476 28292 27481 27477 28293 28292 27477 27480 28296 30145 29191 29188 27480 27480 29190 29191 30145 29190 27480 29192 28298 27481 27481 29189 29192 27481 28292 29189 28300 27484 27482 29207 28300 27482 27482 27485 29207 29209 27488 27483 27483 28299 29209 27483 27484 28299 28300 28299 27484 29217 29207 27485 27485 29208 29217 27485 28307 29208 27488 27487 27486 27491 27490 27487 29213 27491 27487 27487 29212 29213 27487 27488 29212 27488 29209 29212 27489 28303 28304 29226 27494 27490 27490 29218 29226 27490 27491 29218 27491 29213 29218 29225 27497 27492 27492 29224 29225 27492 29215 29224 27492 28295 29215 28309 28308 27493 28327 27508 27496 27496 27498 28327 29225 27498 27497 29240 28327 27498 27498 29234 29240 27498 29225 29234 29228 28309 27500 28324 27506 27501 27501 28313 28324 27501 27502 28313 28314 28313 27502 37704 36134 27503 37706 37704 27503 37707 37706 27503 27503 27504 37707 27505 27504 27503 38478 37707 27504 27504 27505 38478 39290 38478 27505 27505 39289 39290 27505 38530 39289 27505 35450 38530 27505 34578 35450 27505 33672 34578 28323 27512 27506 28324 28323 27506 29244 27514 27507 27507 28311 29244 27508 28327 28328 29237 28312 27509 27509 27510 29237 27511 27510 27509 27513 27511 27509 29246 29237 27510 27510 27511 29246 29247 29246 27511 27511 28330 29247 27511 27513 28330 28323 28322 27512 29241 28326 27514 29244 29241 27514 27532 27516 27515 27532 27517 27516 27522 27521 27517 29254 27522 27517 27517 27533 29254 27517 27532 27533 28335 28325 27518 28336 28335 27518 27518 27535 28336 28347 28337 27519 29242 28347 27519 27519 27520 29242 27520 28326 29242 27521 28331 29260 27521 27522 28331 28339 28331 27522 30190 28339 27522 27522 29254 30190 27534 27524 27523 28342 28332 27525 28343 28342 27525 29245 28343 27525 27525 28329 29245 27525 28328 28329 28332 27526 27525 28332 27538 27526 28344 27528 27527 28350 28344 27527 28346 28345 27528 27528 28344 28346 27529 27530 27532 27531 27530 27529 27533 27532 27530 28348 27533 27530 28349 28348 27530 27530 27531 28349 29259 28349 27531 27531 28347 29259 27531 28337 28347 27533 29252 29254 27533 28348 29252 27535 28354 29265 27535 27536 28354 29256 28336 27535 29265 29256 27535 27536 27542 28354 27536 27540 27542 27537 28353 28356 29263 28350 27538 27538 29261 29263 27538 28332 29261 27543 27542 27540 27544 27543 27540 28363 28361 27541 28361 27545 27541 28355 28354 27542 27542 27543 28355 27543 27546 28358 27543 27544 27546 28357 28355 27543 28358 28357 27543 27553 27546 27544 27544 27547 27553 29275 27558 27545 27545 28361 29275 27546 27553 28358 27554 27553 27547 27555 27554 27547 27547 27548 27555 29291 27555 27548 27548 28364 29291 27548 27549 28364 29287 28364 27549 27550 27559 27568 29268 29267 27551 27551 28371 29268 27553 27554 28384 28382 28358 27553 28384 28382 27553 27554 27555 28397 28397 28384 27554 29291 29290 27555 29290 28397 27555 29293 28400 27556 27556 27569 29293 28400 27557 27556 29296 28371 27557 27557 29295 29296 27557 28400 29295 27558 27561 27563 28365 27561 27558 28378 28365 27558 29275 28378 27558 27559 27576 27577 29305 27576 27559 27559 27560 29305 27577 27568 27559 28386 28385 27560 27560 27567 28386 27560 29304 29305 27560 28385 29304 27561 27562 27563 27564 27563 27562 28398 27566 27565 27565 27572 28398 27565 27571 27572 27565 27570 27571 28386 27567 27566 28398 28386 27566 27569 28399 29293 27569 27581 28399 28412 27571 27570 27570 28411 28412 29309 27572 27571 27571 28412 29309 29311 28398 27572 29312 29311 27572 29313 29312 27572 27572 29309 29313 29320 27585 27574 27574 27578 29320 27575 29304 30253 29305 29304 27575 27575 27576 29305 27577 27576 27575 29324 29320 27578 30258 29324 27578 30255 28399 27579 27579 27580 30255 27581 27580 27579 28399 27581 27579 27580 29322 30255 27580 27582 29322 27580 27581 27582 29323 29322 27582 27582 27583 29323 27583 27588 29323 27584 28414 28415 27584 27585 28414 29320 28414 27585 29321 28411 27586 30264 29321 27586 30274 29323 27588 30293 30274 27588 27588 28434 30293 28435 28434 27588 27588 27589 28435 27589 27611 30299 27589 27610 27611 27589 27590 27610 30308 28435 27589 27589 30299 30308 27591 28419 29339 27592 27593 29343 29342 28423 27592 29343 29342 27592 27593 27602 29343 27593 27601 27602 28425 27600 27594 27594 27595 28425 28426 28425 27595 27605 27604 27596 27596 27597 27605 28429 27599 27597 27597 27600 28429 27597 27598 27605 27599 27598 27597 29351 27605 27598 29352 29351 27598 30294 29352 27598 27598 27599 30294 28429 28425 27599 27599 30290 30294 27599 29353 30290 30279 29353 27599 27599 29338 30279 27599 28425 29338 27600 28425 28429 29350 29349 27602 27602 28430 29350 29349 29343 27602 27615 27614 27603 28442 27615 27603 27603 28432 28442 28433 28432 27603 27604 27605 29351 29351 27607 27604 28448 28436 27606 29361 28448 27606 27606 29358 29361 27606 27607 29358 29359 29358 27607 27607 29351 29359 28437 27625 27608 27612 27611 27610 27611 27612 30299 30309 30299 27612 27612 29365 30309 27612 28438 29365 27613 27618 29345 27613 27617 27618 27619 27617 27613 28442 27621 27615 27617 27619 28439 29362 27618 27617 29368 29362 27617 29369 29368 27617 30316 29369 27617 27617 29366 30316 27617 28439 29366 30304 29345 27618 27618 29362 30304 28445 27626 27620 27621 28443 28446 27621 28442 28443 28449 28439 27623 27623 27627 28449 27624 27625 29370 27635 27628 27624 29374 27635 27624 27624 29370 29374 27625 28437 29370 30324 28441 27626 27626 29378 30324 27626 28445 29378 27627 27631 28449 27627 27630 27631 29378 28445 27629 29381 29378 27629 27629 28464 29381 27629 27640 28464 27632 27631 27630 28453 27632 27630 29366 28449 27631 29373 29366 27631 27631 29372 29373 27631 27632 29372 27632 28453 29372 28447 27641 27633 27633 28443 28447 28450 28443 27633 27634 28436 28448 27634 28448 28452 28463 28454 27635 29374 28463 27635 27639 27638 27636 27644 27639 27636 27636 27637 27644 27645 27644 27637 28464 27640 27638 28474 28464 27638 27638 28473 28474 27638 27639 28473 28481 28473 27639 27639 28479 28481 27639 27647 28479 27639 27644 27647 28466 28456 27641 27641 28455 28466 27641 28447 28455 27649 27648 27642 28483 27649 27642 29388 28483 27642 27642 28468 29388 27642 27643 28468 27643 28457 28468 27644 27646 27647 27644 27645 27646 28480 27646 27645 27645 28462 28480 27645 28454 28462 28479 27647 27646 27646 28470 28479 28472 28470 27646 28480 28472 27646 27648 27649 27653 27648 27653 27654 28483 27653 27649 28498 28478 27650 27650 27655 28498 28498 27655 27651 28499 28498 27651 27651 27652 28499 27652 27654 28499 27653 28483 29397 28494 27654 27653 29397 28494 27653 27654 28494 28499 27657 27658 30363 27659 27658 27657 27669 27659 27657 29408 27669 27657 30363 29408 27657 27658 29426 30363 27658 29425 29426 29433 29425 27658 27658 27659 29433 27659 27673 29433 27675 27673 27659 27659 27672 27675 27660 27666 27680 28524 27668 27660 27660 27661 28524 27662 27661 27660 27680 27662 27660 27661 27695 28524 27661 27662 27695 27662 27686 27695 27662 27680 27686 27693 27676 27663 27663 27664 27693 27665 27664 27663 27664 27692 27693 28524 27692 27664 27664 27668 28524 27664 27665 27668 27686 27680 27666 29407 28505 27669 29408 29407 27669 28527 27681 27670 27670 27671 28527 27671 28525 28527 27671 28522 28525 27671 28521 28522 27671 28520 28521 27672 27682 27684 27688 27675 27672 27672 27684 27688 27673 27674 29433 27675 27674 27673 27674 27675 29421 29434 29433 27674 27674 29422 29434 27674 29421 29422 27675 27688 29421 27693 27691 27676 27691 27690 27677 27679 27678 27677 27690 27679 27677 28543 28542 27678 27678 27679 28543 28545 28543 27679 27679 27699 28545 27679 27690 27699 27685 27684 27682 27684 27687 27688 27698 27687 27684 27684 27685 27698 27701 27694 27686 27702 27701 27686 27686 27694 27695 28523 27688 27687 27687 27698 28523 27688 28523 29421 27709 27704 27689 27690 27692 27694 27693 27692 27690 27690 27691 27693 27690 27694 27699 28524 27695 27692 27695 27694 27692 27700 27699 27694 27701 27700 27694 27696 27697 28538 29445 28538 27697 27697 29443 29445 27697 28529 29443 29446 28523 27698 27698 28530 29446 27699 27700 28545 28546 28545 27700 27700 27701 28546 28547 28546 27701 27701 27702 28547 27702 27710 28547 27702 27703 27710 27704 27709 28541 27705 27706 29479 29479 27709 27705 27706 29453 29479 29460 29453 27706 27706 29451 29460 27706 28542 29451 28572 28541 27707 30402 28572 27707 30403 30402 27707 27707 27708 30403 27709 27708 27707 28541 27709 27707 30414 30403 27708 30424 30414 27708 27708 30423 30424 27708 30422 30423 27708 29479 30422 27708 27709 29479 28549 28547 27710 30406 29463 27711 27711 27712 30406 30407 30406 27712 27712 28556 30407 28557 28556 27712 27712 28552 28557 27712 28551 28552 27713 27714 29448 31210 29448 27714 27714 29449 31210 27715 28567 28570 27715 27723 28567 28554 27718 27716 27716 28531 28554 27719 28563 28569 28564 28563 27719 28580 28579 27720 30399 28580 27720 27720 28555 30399 27720 28554 28555 27721 27725 27726 28578 27723 27722 27722 28569 28578 28578 28567 27723 27727 27726 27725 27734 27727 27725 27726 27727 28561 28577 28561 27727 28581 28577 27727 27727 27734 28581 28597 27739 27728 28592 27732 27730 29493 28592 27730 27730 28606 29493 27730 27731 28606 27731 27741 28606 27732 28591 28598 28592 28591 27732 29503 29497 27733 27733 28598 29503 28583 28581 27734 28585 28583 27734 29484 28585 27734 27734 28596 29484 27734 28586 28596 28595 28586 27735 27736 27755 27765 27736 27743 27755 27737 27740 27741 27737 27738 27740 27746 27740 27738 27738 27745 27746 27738 27744 27745 28597 27743 27739 27748 27741 27740 28603 27748 27740 27740 27746 28603 27741 27748 28606 27742 27750 27751 28600 27755 27743 27743 28597 28600 27747 27745 27744 27757 27747 27744 27747 27746 27745 27746 27747 28603 27747 27758 28611 27747 27757 27758 27747 28602 28603 28620 28602 27747 27747 28611 28620 29500 28606 27748 27748 28603 29500 27760 27759 27749 28599 27760 27749 27761 27751 27750 27752 28607 28614 28605 28595 27753 27753 27754 28605 27754 27763 28605 27764 27763 27754 28610 27765 27755 27755 28600 28610 28617 27767 27756 27767 27758 27757 27758 27767 28611 28633 28612 27759 29498 28633 27759 27759 27760 29498 27760 28593 29498 28599 28593 27760 27761 27762 28607 28623 28607 27762 27762 28613 28623 27762 27773 28613 28609 28605 27763 27763 27764 28609 27764 27768 28609 27769 27768 27764 28610 27766 27765 27766 28610 28616 28625 28611 27767 27767 28618 28625 27767 28617 28618 27768 28608 28609 31283 28608 27768 27768 30458 31283 30459 30458 27768 27768 27769 30459 27769 29511 30459 27769 28615 29511 27770 27771 28615 27772 27771 27770 27784 27772 27770 27770 27783 27784 30465 29511 27771 27771 27772 30465 29511 28615 27771 30468 30465 27772 30469 30468 27772 27772 28636 30469 27772 27784 28636 27773 27776 28613 28622 27775 27774 27775 28622 28627 29510 28613 27776 27776 27790 29510 28643 27790 27777 27778 27781 27782 27778 27779 27781 28624 27781 27779 27780 27781 29509 27782 27781 27780 29518 27782 27780 27780 29517 29518 27780 29509 29517 27781 28624 29509 28630 28629 27782 29518 28630 27782 27785 27784 27783 27784 28635 28636 27784 27785 28635 27785 27786 28635 28654 28638 27787 27787 28634 28654 28652 27792 27788 27788 28632 28652 27790 28643 29510 27791 27800 28657 27791 27792 27800 28652 27800 27792 27793 28644 28645 27793 27794 28644 28646 28644 27794 28647 28646 27794 28653 28647 27794 27794 27795 28653 28658 28653 27795 27795 27801 28658 27798 27797 27796 28650 28649 27797 27797 27798 28650 28656 28650 27798 27800 28652 29552 29551 28657 27800 29553 29551 27800 27800 29552 29553 28666 28658 27801 27801 27805 28666 27806 27805 27801 27802 27838 27839 27802 27803 27838 28655 27809 27803 27803 27809 27838 27818 27806 27804 28666 27818 27804 28667 28666 27804 27804 27816 28667 27805 27818 28666 27805 27806 27818 27809 27808 27807 27838 27809 27807 27807 27823 27838 27807 27819 27823 27807 27808 27819 27825 27824 27808 27808 27809 27825 27820 27819 27808 27824 27820 27808 28654 27825 27809 27809 28638 28654 28655 28638 27809 27810 27811 28672 28677 28672 27811 27812 27813 28680 28690 28680 27813 27816 27815 27814 28664 27816 27814 27814 28661 28664 28663 28661 27814 27814 27817 28663 27814 27815 27817 27816 28665 28667 27816 28664 28665 27819 27821 27823 27822 27821 27819 27829 27822 27819 27830 27829 27819 27819 27820 27830 29561 27830 27820 27820 29557 29561 27820 27824 29557 27837 27823 27821 27821 27836 27837 27821 27822 27836 28682 27836 27822 28691 28682 27822 27822 27829 28691 27846 27838 27823 27823 27837 27846 27824 29544 29557 27824 27825 29544 27825 28659 29544 27825 28654 28659 27834 27833 27826 28673 27834 27826 28688 28673 27826 28675 28674 27827 28676 28675 27827 28689 28679 27828 28692 28691 27829 29569 28692 27829 27829 27830 29569 27830 29561 29569 27831 27840 27841 28669 27840 27831 27831 27839 28669 27832 28706 29584 27832 27848 28706 27833 27834 27842 28687 27842 27834 27834 28673 28687 27845 27837 27835 27835 27844 27845 27854 27844 27835 28702 27854 27835 27835 28696 28702 27835 27836 28696 27837 27836 27835 27836 28682 28683 27836 28693 28696 27836 28683 28693 27837 27845 27846 27840 27839 27838 27846 27840 27838 27839 27840 28669 27847 27841 27840 28716 27847 27840 27840 27846 28716 27841 27847 27855 27842 28684 28694 28687 28684 27842 27843 27852 27858 27853 27852 27843 28695 27853 27843 27846 27845 27844 27854 27846 27844 27846 28703 28716 27846 27854 28703 28717 27855 27847 28725 28717 27847 27847 28716 28725 28720 28706 27848 27848 28718 28720 27848 27857 28718 28708 28697 27849 27849 28707 28708 27849 28694 28707 27850 27851 28710 29597 28689 27850 29616 29597 27850 27850 28710 29616 27851 27858 28710 27852 27853 28695 28713 27858 27852 28724 28703 27854 27854 28715 28724 27854 28702 28715 27869 27856 27855 28717 27869 27855 27869 27868 27856 27870 27864 27856 27856 27868 27870 28719 28718 27857 27857 27865 28719 28712 28710 27858 28713 28712 27858 28723 27860 27859 29632 28723 27859 27859 27867 29632 27860 27862 27863 28698 27862 27860 29610 28698 27860 29611 29610 27860 27860 28723 29611 29600 29594 27861 27861 29599 29600 27861 28698 29599 27861 27862 28698 28726 27865 27864 27864 27871 28726 27864 27870 27871 28726 28719 27865 27874 27872 27866 27867 28722 29632 27867 27875 28722 27868 28717 28731 27868 27869 28717 27871 27870 27868 28733 27871 27868 27868 28731 28733 28733 28726 27871 27874 27873 27872 27872 27873 28728 27873 29605 30529 27873 27874 29605 29631 28728 27873 30530 29631 27873 27873 30529 30530 27874 28714 29605 27876 28709 28727 27879 27878 27877 28741 27879 27877 28742 28741 27877 27878 27879 28752 29652 28752 27879 27879 28741 29652 29628 28721 27880 27880 28747 29628 27880 27883 28747 28745 27888 27881 28746 28745 27881 27881 27882 28746 29644 28746 27882 29645 29644 27882 27882 27885 29645 29642 28747 27883 29647 29642 27883 27883 27884 29647 29648 29647 27884 27884 28753 29648 29646 29645 27885 27885 28770 29646 27885 27886 28770 28771 28770 27886 28754 27893 27887 28755 28754 27887 28764 28755 27887 27887 28763 28764 29664 27904 27888 27888 28745 29664 27895 27894 27889 27900 27892 27890 27890 27899 27900 27890 27891 27899 27892 27891 27890 28754 28753 27893 27898 27897 27894 28791 27898 27894 27894 28790 28791 27894 27895 28790 29665 28790 27895 27895 28778 29665 28779 28778 27895 29657 28779 27895 27895 28752 29657 28789 27909 27897 27897 27898 28789 28795 28789 27898 27898 28791 28795 28762 27900 27899 28773 28762 27899 27899 28772 28773 27899 27905 28772 28762 27902 27900 28782 27920 27901 30589 28782 27901 27901 29673 30589 27901 27902 29673 27902 28762 29673 27903 27914 28763 27903 27913 27914 29668 27906 27904 29669 29668 27904 30581 29669 27904 27904 29667 30581 27904 29664 29667 28780 28772 27905 29668 27907 27906 29687 27916 27907 27907 29677 29687 27907 29668 29677 27919 27918 27908 27923 27919 27908 27908 27922 27923 27909 28789 28795 27911 27920 28781 27913 27912 27911 28781 27913 27911 27915 27914 27913 28781 27915 27913 28764 28763 27914 28784 28764 27914 27914 28783 28784 27914 27915 28783 27915 28781 28783 29687 27917 27916 28814 27927 27917 29687 28814 27917 29688 29670 27918 27918 27919 29688 27919 28796 29688 27919 27923 28796 28782 28781 27920 28802 27924 27921 27923 27922 27921 27924 27923 27921 28815 28796 27923 28816 28815 27923 27923 27924 28816 30627 28816 27924 27924 29709 30627 27924 28802 29709 27927 27926 27925 27934 27929 27926 29728 27934 27926 27926 29725 29728 27926 29724 29725 27926 27928 29724 27926 27927 27928 28814 27928 27927 27928 29723 29724 27928 29694 29723 27928 28814 29694 27929 27930 27931 27934 27930 27929 27937 27931 27930 28848 27937 27930 27930 27935 28848 27930 27934 27935 27937 27936 27931 28834 27933 27932 28834 28833 27933 29727 27935 27934 29728 29727 27934 29752 28848 27935 27935 29733 29752 31536 29733 27935 27935 29732 31536 27935 29727 29732 28849 27940 27936 27936 27937 28849 27937 28848 28849 28851 27944 27938 29736 28851 27938 27938 27939 29736 29740 29736 27939 29741 29740 27939 27939 27945 29741 27940 28849 28871 28870 27957 27940 28871 28870 27940 28837 28835 27941 27941 27949 28837 27942 27949 27950 27942 27943 27949 27944 27943 27942 28837 27949 27943 28838 28837 27943 28840 28838 27943 28850 28840 27943 27943 27944 28850 28851 28850 27944 29745 29741 27945 27945 27946 29745 27947 27946 27945 27946 28872 29745 27946 27954 28872 27946 27953 27954 27946 27947 27953 27950 27949 27948 27952 27950 27948 27954 27959 28872 28866 27960 27955 29751 28866 27955 27955 28868 29751 29751 28868 27956 29759 29751 27956 29760 29759 27956 28869 27958 27957 28870 28869 27957 29763 29762 27958 27958 29753 29763 27958 28869 29753 28873 27961 27960 27960 28864 28873 28866 28864 27960 28876 27965 27961 27961 28873 28876 27962 27963 29772 30672 29772 27963 27963 30666 30672 27963 30664 30666 27963 28877 30664 27964 27969 28878 27964 27968 27969 27964 27966 27968 27965 28874 28881 28876 28874 27965 27969 27968 27967 28879 27969 27967 27967 27970 28879 27967 27968 27970 29771 28878 27969 27969 28879 29771 29781 28879 27970 30688 29781 27970 30689 30688 27970 27970 27973 30689 27970 27971 27973 27978 27973 27971 28889 27975 27972 30697 30689 27973 27973 27974 30697 31596 30697 27974 27974 29812 31596 28894 27984 27975 27975 28889 28894 27976 27977 28898 28901 28898 27977 29823 28901 27977 30691 29823 27977 27977 29806 30691 27977 27984 29806 27990 27987 27979 27979 27988 27990 28015 27989 27980 28019 28015 27980 27980 28002 28019 27980 27999 28002 27980 27981 27999 27981 27997 27999 27998 27997 27981 27982 27983 27998 28896 27998 27983 28897 28896 27983 27984 28894 29806 29825 29824 27986 27986 28900 29825 27986 27987 28900 27987 27990 28900 27991 27990 27988 27996 27991 27988 27988 27989 27996 28015 27996 27989 27990 27991 28900 29835 28900 27991 29836 29835 27991 27991 28916 29836 27991 28015 28916 27991 27996 28015 29815 28897 27992 27993 28000 28004 30704 29822 27993 27993 28914 30704 27993 28913 28914 28917 28913 27993 27993 28004 28917 27994 27995 28906 29823 28906 27995 27995 28901 29823 28003 27999 27997 28911 28003 27997 28912 28911 27997 27997 28895 28912 27997 27998 28895 28896 28895 27998 28003 28002 27999 28910 28899 28001 28001 28013 28910 28020 28019 28002 28002 28003 28020 28028 28020 28003 28911 28028 28003 29851 28029 28005 28005 28906 29851 28006 28007 28009 28008 28007 28006 28915 28008 28006 28925 28915 28006 28006 28021 28925 28010 28009 28007 28023 28010 28007 28007 28011 28023 28012 28011 28007 28007 28008 28012 28908 28012 28008 28008 28907 28908 28909 28907 28008 28008 28902 28909 28915 28902 28008 28919 28918 28011 28011 28022 28919 28011 28012 28022 28908 28022 28012 28013 28033 28910 28013 28031 28033 28044 28042 28014 28015 28019 28916 28934 28933 28016 28016 28054 28934 28016 28036 28054 28016 28017 28036 28018 28017 28016 28933 28018 28016 28017 28035 28036 28017 28019 28035 28916 28019 28017 29845 28916 28017 29853 29845 28017 28017 28018 29853 31619 29853 28018 31620 31619 28018 28018 28933 31620 28019 28024 28035 28019 28020 28024 28028 28024 28020 28021 28040 28925 29827 28919 28022 28022 28908 29827 28037 28035 28024 28024 28027 28037 28028 28027 28024 28049 28037 28025 28935 28049 28025 28936 28935 28025 29864 28936 28025 28025 28026 29864 28027 28026 28025 28037 28027 28025 30718 29864 28026 28026 28911 30718 28026 28027 28911 28922 28911 28027 28027 28028 28922 28028 28911 28922 28923 28030 28029 28924 28923 28029 29851 28924 28029 29866 28064 28030 28030 29859 29866 28030 28931 29859 28030 28923 28931 28031 28032 28033 28920 28033 28032 28928 28920 28032 28032 28927 28928 28032 28926 28927 28920 28910 28033 28034 28035 28037 28036 28035 28034 28054 28036 28034 28034 28048 28054 28034 28037 28048 28049 28048 28037 29854 29849 28038 28038 28930 29854 28038 28051 28930 29848 28917 28038 29849 29848 28038 29857 28925 28040 28040 28058 29857 28040 28041 28058 28041 28057 28058 29861 28929 28042 29862 29861 28042 30726 29862 28042 28042 30716 30726 28042 29852 30716 28042 28043 29852 28044 28043 28042 28043 29843 29852 29844 29843 28043 28043 28921 29844 28043 28044 28921 28061 28060 28045 28935 28061 28045 28045 28049 28935 28045 28046 28049 28047 28046 28045 28060 28047 28045 28046 28048 28049 28046 28047 28048 28054 28048 28047 28941 28054 28047 28047 28060 28941 28052 28051 28050 28056 28052 28050 28051 28052 28930 28939 28930 28052 28052 28062 28939 28052 28056 28062 28053 28066 28955 28955 28067 28053 28941 28934 28054 28944 28058 28057 28960 28944 28057 28057 28949 28960 28057 28059 28949 29867 29857 28058 28058 28944 29867 28059 28065 28949 28942 28941 28060 28956 28942 28060 28060 28061 28956 28957 28956 28061 28061 28947 28957 28061 28935 28947 29866 28939 28063 28063 28064 29866 28959 28949 28065 28066 28946 29884 28066 28940 28946 28066 28932 28940 29884 28955 28066 28966 28074 28067 28967 28966 28067 28067 28955 28967 28068 28069 28961 28969 28961 28069 28070 28963 29893 28070 28962 28963 28070 28071 28962 28970 28962 28071 28071 28072 28970 28972 28970 28072 28073 28971 28972 29889 28971 28073 29890 29889 28073 29891 29890 28073 28073 28074 29891 28074 28966 29891 28075 28076 28974 29893 28974 28076 28983 28078 28077 28077 28981 28983 29899 29898 28079 28079 28080 29899 28081 28080 28079 28084 28081 28079 30765 29899 28080 28080 29900 30765 28080 28986 29900 28080 28081 28986 28081 28984 28986 28081 28084 28984 28091 28083 28082 28097 28096 28082 28082 28092 28097 28984 28084 28083 28083 28091 28984 28102 28098 28085 28995 28102 28085 28086 28087 28090 28088 28087 28086 28990 28088 28086 29911 28990 28086 29913 29911 28086 28086 28989 29913 28086 28090 28989 28095 28090 28087 28087 28089 28095 28087 28088 28091 28988 28091 28088 28990 28988 28088 28985 28984 28091 28988 28985 28091 28092 28093 28097 28093 28096 28097 29001 28106 28094 28094 28992 29001 28102 28101 28098 30778 28100 28099 29913 28989 28100 28100 29912 29913 31658 29912 28100 28100 30777 31658 28100 30776 30777 30778 30776 28100 28101 28105 28111 28101 28102 28105 28995 28105 28102 30782 29919 28103 28103 29930 30782 28103 28996 29930 29933 29005 28104 28104 28119 29933 29917 28111 28105 28105 28995 29917 29002 28107 28106 28106 29001 29002 29012 28114 28107 28107 29010 29012 28107 29002 29010 29004 28109 28108 28109 29004 29008 29939 28112 28109 28109 29007 29939 29008 29007 28109 28110 28113 29000 29008 29004 28111 29935 29008 28111 28111 29917 29935 29945 29009 28112 28112 29939 29945 29011 29000 28113 28113 29009 29011 28114 29012 29014 28123 28122 28115 28116 28122 28124 29018 28126 28118 29938 29933 28119 28122 28123 28124 28125 28124 28123 29949 28125 28123 28123 29016 29949 29960 29016 28123 28124 28125 29015 29949 29015 28125 28128 28129 28133 28129 28130 28133 28131 28130 28129 28132 28131 28129 28134 28133 28130 29952 28134 28130 28130 28135 29952 28130 28131 28135 28137 28135 28131 28131 28132 28137 28132 28136 28137 28138 28136 28132 28133 28134 29020 28134 29019 29020 29950 29019 28134 28134 29021 29950 29022 29021 28134 29952 29022 28134 29962 29957 28135 28135 28137 29962 29957 29952 28135 28138 28137 28136 28137 28138 29962 28138 29958 29962 28138 28157 29958 28159 28157 28138 28138 28154 28159 28139 28140 28146 28149 28146 28140 29023 28149 28140 28141 28147 28155 28141 28146 28147 28142 28150 29033 29030 28144 28143 29034 29030 28143 29030 28151 28144 28149 28147 28146 29036 28155 28147 28147 28148 29036 28149 28148 28147 29038 29036 28148 28148 29027 29038 28148 28149 29027 28149 29026 29027 28149 29023 29026 29969 29033 28150 30837 29969 28150 28150 29975 30837 28150 29974 29975 28153 28152 28151 29030 28153 28151 28153 29030 29987 29032 28159 28154 29037 28156 28155 28155 29035 29037 29036 29035 28155 29964 29958 28157 28157 28158 29964 28159 28158 28157 29971 29964 28158 28158 29031 29971 29032 29031 28158 28158 28159 29032 28160 28163 29039 29047 29039 28163 29059 28167 28164 28169 28168 28165 29059 29047 28167 28168 28169 28172 29066 28172 28169 29983 29066 28169 28169 29061 29983 28169 29037 29061 29060 29059 28170 29081 29060 28170 28170 29071 29081 28170 28171 29071 28171 28179 29071 28180 28179 28171 28186 28180 28171 29062 28173 28172 29067 29062 28172 28172 29066 29067 28173 29062 29075 29073 28178 28174 28174 29072 29073 28174 28175 29072 28175 29070 29072 28176 29076 30031 29082 28181 28177 28177 28182 29082 28177 28178 28182 29073 28182 28178 30022 29081 28179 28179 29079 30022 28179 28180 29079 29081 29071 28179 29080 29079 28180 28180 29078 29080 28180 28192 29078 28180 28186 28192 28181 29083 29085 28181 29082 29083 29084 29082 28182 30036 29084 28182 28182 29073 30036 29087 28184 28183 28183 28197 29087 28184 30038 30039 28184 29089 30038 28184 29088 29089 30044 29088 28184 28184 29087 30044 28203 28202 28185 30039 28203 28185 30050 29093 28187 30051 30050 28187 28187 28188 30051 28188 29086 30051 28188 29085 29086 30052 29097 28189 30063 30052 28189 28189 28200 30063 28189 28195 28200 28189 28190 28195 28191 28202 29090 28192 28193 29078 29098 29078 28193 28194 29094 30059 28194 29093 29094 30059 29104 28194 28197 28201 29087 29109 28204 28198 28198 28208 29109 29106 28200 28199 28199 28205 29106 28200 29112 30063 28200 29106 29112 28201 28213 29087 28201 28212 28213 28202 28203 30047 30047 29090 28202 30046 30045 28203 28203 30040 30046 28203 30039 30040 28203 30045 30047 28204 29108 30066 29109 29108 28204 28205 28206 29106 28206 28207 29114 29114 29106 28206 30068 29114 28207 30073 30068 28207 28207 28211 30073 28208 29091 29109 28211 28210 28209 30072 28211 28209 28209 30071 30072 28209 28215 30071 28211 30072 30074 30078 30073 28211 28211 30074 30078 28212 28221 29116 28214 28213 28212 29116 28214 28212 30044 29087 28213 30069 30044 28213 30904 30069 28213 28213 28214 30904 31791 30904 28214 28214 30894 31791 30895 30894 28214 28214 29116 30895 28215 29119 30071 28216 29121 30076 28217 31788 32687 28217 30075 31788 28217 28218 30075 28219 28218 28217 30902 28219 28217 32687 30902 28217 28218 28219 29115 30888 30075 28218 28218 30054 30888 29125 29115 28219 28219 29124 29125 30083 29124 28219 30900 30083 28219 30902 30900 28219 29124 28226 28220 29125 29124 28220 28220 29115 29125 30895 29116 28221 28221 29128 30895 28221 29127 29128 28222 28223 28224 29129 28224 28223 29129 29127 28224 28225 28226 29132 29136 28240 28225 28225 29135 29136 28225 29132 29135 28226 29123 30085 29124 29123 28226 30085 29132 28226 28229 28228 28227 29145 29134 28228 28228 28229 29145 29150 29149 28229 28229 29146 29150 28229 28250 29146 28229 28230 28250 29149 29145 28229 28230 28238 28250 28242 28233 28231 28243 28242 28231 28233 28232 28231 29137 28244 28232 28232 28233 29137 28233 28242 29138 29148 29137 28233 30095 29148 28233 28233 29138 30095 30096 28245 28234 28234 28244 30096 28252 28251 28235 28235 28249 28252 28235 28236 28249 28236 28237 29141 29142 28249 28236 28236 29141 29142 28237 29133 29141 28257 28250 28238 28238 28253 28257 28239 28240 29136 29147 28241 28239 28239 29136 29147 28241 28242 28243 29147 28242 28241 29147 29138 28242 28244 29148 30096 28244 29137 29148 30102 29151 28245 28245 30096 30102 28254 28251 28246 28246 28247 28254 28248 28247 28246 28251 28248 28246 28247 28248 29153 30110 29153 28248 28248 30100 30110 28248 28252 30100 28248 28251 28252 30100 28252 28249 28249 29139 30100 29142 29139 28249 28250 28257 29146 28255 28256 28265 29146 28257 28255 29150 29146 28255 28255 29149 29150 28255 28265 29149 29162 29160 28258 29163 29162 28258 29164 29163 28259 28259 28266 29164 28260 28261 28264 28262 28261 28260 28268 28262 28260 29154 28264 28261 29156 29154 28261 29165 29156 28261 28261 28269 29165 28261 28262 28269 28262 28268 28274 28270 28269 28262 28263 28264 29154 28265 28264 28263 29152 28265 28263 30101 29152 28263 28263 29157 30101 29158 29157 28263 28263 29154 29158 29152 29149 28265 29170 29164 28266 28269 28270 29165 30942 29165 28270 28270 30131 30942 30124 28281 28271 28271 30123 30124 28271 30117 30123 28271 29166 30117 28271 29159 29166 28272 28273 30134 28286 28277 28272 30134 28286 28272 30946 30134 28273 28273 30941 30946 28273 30126 30941 28275 28301 30125 28276 28277 28285 28286 28285 28277 29182 28289 28278 29183 29182 28278 28278 29177 29183 29179 28280 28279 30128 29175 28280 30135 30128 28280 28280 29179 30135 28281 28282 28283 30133 28282 28281 28281 30130 30133 28281 30129 30130 28281 30124 30129 28284 28283 28282 29185 28284 28282 30133 29185 28282 28291 28290 28283 28283 28284 28291 29184 28291 28284 29185 29184 28284 28285 28286 28287 29186 28287 28286 30139 29186 28286 28286 30137 30139 28286 30134 30137 30127 29176 28288 28288 28289 30127 28289 29182 30127 30135 29179 28290 30943 30135 28290 30951 30943 28290 28290 30950 30951 28290 28291 30950 28291 29184 30950 30965 30144 28292 28292 28293 30965 30144 29189 28292 29191 29190 28293 28293 29188 29191 30966 30965 28293 28293 30961 30966 28293 29190 30961 28294 29193 29194 30142 29193 28294 28294 29187 30142 28295 29214 29215 28296 29195 30145 28297 28310 29204 28297 28308 28310 29204 29199 28297 29206 29200 28298 28298 29201 29206 28298 29189 29201 29192 29189 28298 29211 29209 28299 28299 28300 29211 30155 29211 28300 28300 29207 30155 28301 30120 30125 28301 29223 30120 29205 28303 28302 28302 29200 29205 28305 28304 28303 28306 28305 28303 29216 28306 28303 28303 29205 29216 29208 28307 28304 30160 29208 28304 30161 30160 28304 28304 28305 30161 30169 30161 28305 28305 28306 30169 28306 30167 30169 28306 29216 30167 29220 28310 28308 29221 29220 28308 29222 29221 28308 28308 28309 29222 29228 29222 28309 29220 29203 28310 28310 29203 29204 30181 29244 28311 28311 29230 30181 28312 29236 30185 29237 29236 28312 29229 29228 28312 30175 29229 28312 30178 30175 28312 30185 30178 28312 28313 28315 28324 28313 28314 28315 28316 28315 28314 28317 28316 28314 29238 28324 28315 29239 29238 28315 30183 29239 28315 28315 28333 30183 28315 28316 28333 28316 28325 28333 28316 28318 28325 28319 28323 29238 28319 28322 28323 29255 28322 28319 28319 28320 29255 28321 28320 28319 29238 28321 28319 31003 29255 28320 31004 31003 28320 28320 30186 31004 28320 28321 30186 30187 30186 28321 28321 29238 30187 29249 28330 28322 29255 29249 28322 28323 28324 29238 28334 28333 28325 28335 28334 28325 28326 29241 29242 29245 28329 28327 28327 29240 29245 28329 28328 28327 29249 29247 28330 28331 28338 29260 28339 28338 28331 28332 28342 29261 31000 30183 28333 28333 29251 31000 28333 28334 29251 31006 29251 28334 28334 29250 31006 28334 28335 29250 28335 28336 29256 29256 29250 28335 28338 28353 29260 29266 28353 28338 28338 28340 29266 28341 28340 28338 28338 28339 28341 29257 28341 28339 30190 29257 28339 30211 29266 28340 28340 28341 30211 28341 29257 30211 29262 29261 28342 30213 29262 28342 28342 30194 30213 28342 28343 30194 28343 29245 30194 29258 28346 28344 29264 29258 28344 28344 28351 29264 28344 28350 28351 29258 28352 28345 28345 28346 29258 30208 29259 28347 28347 30203 30208 28347 29242 30203 28348 28349 30210 29253 29252 28348 30210 29253 28348 28349 30215 31018 28349 29259 30215 31018 30210 28349 29263 28351 28350 31023 29264 28351 28351 30219 31023 28351 30218 30219 28351 29263 30218 28352 28362 28363 29258 28362 28352 28353 29266 29274 29273 28356 28353 29274 29273 28353 30222 30206 28354 28354 28355 30222 30206 29265 28354 28355 28357 30222 29277 28360 28356 28356 29273 29277 28357 29282 30222 28357 29281 29282 28357 29276 29281 28357 28358 29276 28358 28369 29276 28382 28369 28358 28359 29284 29287 28359 29277 29284 28359 28360 29277 28363 28362 28361 29280 29275 28361 28361 29272 29280 28361 28362 29272 28362 29258 29272 30230 29291 28364 28364 29287 30230 28365 28376 28377 28378 28376 28365 28366 28369 28379 28366 28367 28369 28368 28367 28366 28379 28368 28366 28370 28369 28367 29288 28370 28367 28367 28368 29288 29289 29288 28368 28368 28380 29289 28368 28379 28380 28369 28370 29276 28381 28379 28369 28382 28381 28369 29281 29276 28370 29283 29281 28370 29288 29283 28370 30231 29268 28371 30232 30231 28371 31950 30232 28371 28371 29296 31950 28372 28375 28376 28372 28373 28375 28374 28373 28372 28376 28374 28372 28390 28375 28373 28373 28389 28390 29298 28389 28373 30239 29298 28373 28373 29294 30239 28373 28374 29294 28374 28376 28378 30236 29294 28374 28374 28378 30236 28377 28376 28375 28391 28377 28375 28375 28390 28391 28377 28391 28409 28378 30229 30236 28378 29275 30229 28392 28380 28379 28379 28381 28392 28380 28392 29289 28404 28392 28381 29302 28404 28381 28381 28395 29302 28381 28383 28395 28381 28382 28383 28384 28383 28382 28383 28384 28395 29308 28395 28384 28384 28396 29308 28397 28396 28384 28385 28398 29314 28385 28386 28398 29314 29304 28385 28403 28390 28387 28387 28401 28403 28387 28388 28401 28389 28388 28387 28390 28389 28387 28402 28401 28388 29299 28402 28388 28388 29298 29299 28388 28389 29298 28403 28391 28390 28391 28403 28409 29306 29289 28392 28392 28410 29306 28392 28393 28410 28394 28393 28392 28404 28394 28392 29317 28410 28393 29318 29317 28393 28393 28404 29318 28393 28394 28404 29308 29302 28395 28396 29303 30243 28396 28397 29303 30249 29308 28396 31060 30249 28396 28396 30243 31060 28397 29290 29303 28398 29311 29314 28399 29292 29293 30255 29292 28399 29293 29292 28400 31047 29295 28400 28400 30246 31047 28400 29292 30246 28408 28403 28401 28401 28402 28408 28402 28405 28408 29299 28405 28402 28403 28408 28409 28404 29307 29318 28404 29302 29307 29319 28408 28405 28405 28406 29319 28407 28406 28405 29299 28407 28405 31067 29319 28406 31998 31067 28406 28406 31070 31998 28406 30265 31070 28406 28407 30265 31058 30265 28407 28407 30238 31058 28407 29299 30238 30256 28409 28408 30257 30256 28408 28408 29319 30257 30256 29316 28409 30247 29306 28410 30248 30247 28410 30261 30248 28410 28410 29317 30261 29321 28412 28411 29310 29309 28412 29321 29310 28412 29329 28415 28414 29337 29329 28414 30275 29337 28414 28414 29325 30275 28414 29324 29325 28414 29320 29324 29329 28418 28415 28416 29334 29335 28416 28424 29334 28428 28427 28417 29336 28428 28417 29338 28426 28418 28418 29337 29338 28418 29329 29337 30282 29339 28419 30285 30282 28419 28419 28420 30285 28420 29346 30285 30277 29327 28421 28421 30276 30277 28421 28422 30276 30282 30276 28422 28422 29339 30282 29342 29334 28423 29334 28424 28423 28425 28426 29338 29344 28433 28427 28427 28428 29344 30286 29344 28428 28428 29336 30286 30295 29350 28430 30306 30295 28430 28431 29345 29346 28432 28433 29364 29363 28442 28432 29364 29363 28432 30288 29364 28433 28433 29344 30288 28434 30273 30293 32015 30273 28434 28434 29357 32015 28434 28435 29357 30300 29357 28435 30308 30300 28435 28437 30305 30311 28437 29356 30305 30311 29370 28437 28438 28444 29365 28439 28449 29366 31103 30306 28440 28440 30326 31103 28440 30325 30326 28440 28441 30325 28441 30324 30325 28447 28443 28442 28455 28447 28442 29363 28455 28442 28450 28446 28443 30315 29365 28444 28448 28451 28452 29360 28451 28448 29361 29360 28448 29371 28459 28451 30320 29371 28451 31100 30320 28451 28451 30310 31100 28451 29360 30310 28459 28452 28451 28459 28457 28452 28453 28460 29372 28461 28460 28453 28469 28461 28453 28463 28462 28454 29377 28466 28455 28455 29363 29377 30330 28467 28456 28456 29377 30330 28456 28466 29377 29387 28468 28457 28457 28458 29387 28459 28458 28457 28458 29384 29387 29385 29384 28458 28458 29371 29385 28458 28459 29371 29379 28496 28460 28460 28461 29379 29380 29372 28460 31119 29380 28460 28460 28496 31119 28461 28469 29389 28461 28495 29379 29389 28495 28461 30332 28480 28462 28462 30321 30332 28462 28463 30321 30322 30321 28463 28463 29375 30322 28463 29374 29375 29391 29381 28464 28464 28474 29391 28465 28467 28475 28476 28475 28467 29382 28476 28467 29383 29382 28467 30330 29383 28467 28468 29387 29388 28503 28486 28470 28470 28485 28503 28470 28484 28485 28470 28471 28484 28472 28471 28470 28486 28479 28470 28471 28472 28506 28500 28484 28471 28501 28500 28471 28506 28501 28471 28472 28480 28506 29394 28474 28473 28473 28481 29394 29394 29391 28474 29395 28482 28476 28476 29382 29395 28477 28489 29393 28478 28497 29389 28498 28497 28478 28486 28481 28479 30332 28506 28480 29403 29394 28481 28481 28486 29403 29395 28488 28482 28483 28492 29397 28493 28492 28483 29388 28493 28483 28502 28485 28484 28484 28500 28502 28513 28503 28485 28485 28502 28513 28486 28503 29403 28487 29395 29406 28487 28488 29395 29396 29393 28489 28489 28490 29396 28490 28491 29396 29399 29396 28491 28491 28504 29399 30346 29398 28492 31143 30346 28492 28492 28493 31143 29398 29397 28492 28493 31124 31143 28493 30335 31124 28493 29388 30335 29411 28499 28494 28494 29409 29411 28494 29397 29409 28495 28496 29379 28497 28496 28495 29389 28497 28495 28496 28497 30338 31120 31119 28496 31133 31120 28496 28496 30338 31133 28497 28498 30338 28498 29412 30338 28498 28499 29412 28499 29411 29412 28511 28502 28500 28500 28501 28511 29417 28511 28501 30348 29417 28501 31154 30348 28501 32941 31154 28501 32942 32941 28501 32947 32942 28501 28501 32090 32947 28501 30336 32090 28501 28506 30336 28502 28512 28513 28502 28511 28512 29404 29403 28503 30354 29404 28503 30360 30354 28503 28503 28513 30360 29402 29401 28505 30352 29402 28505 28505 29407 30352 28506 30332 30336 28517 28516 28507 29420 28517 28507 28507 28508 29420 28509 28508 28507 28510 28509 28507 32112 29420 28508 28508 32108 32112 28508 28509 32108 28509 31167 32108 28509 30351 31167 28509 30339 30351 28509 28510 30339 28510 29406 30339 29417 28512 28511 28512 28514 28515 29418 28514 28512 29428 29418 28512 28512 29417 29428 28515 28513 28512 28513 30358 30360 30359 30358 28513 28513 28515 30359 29419 28515 28514 28514 29418 29419 28515 29419 29431 28515 30355 30359 31169 30355 28515 28515 29431 31169 28516 28518 28520 28516 28517 28518 28519 28518 28517 29420 28519 28517 28521 28520 28518 29432 28521 28518 30369 29432 28518 28518 30361 30369 28518 28519 30361 28519 29420 30361 29432 28522 28521 28526 28525 28522 29437 28526 28522 28522 29432 29437 29423 29421 28523 30391 29423 28523 28523 29446 30391 28528 28527 28525 29441 28528 28525 30390 29441 28525 28525 29438 30390 28525 28526 29438 28526 29437 29438 28528 29441 29443 29443 28529 28528 29447 29446 28530 28530 28539 29447 28531 28540 28554 28531 28532 28540 28541 28540 28532 29456 28548 28533 28533 28547 28549 28533 28534 28547 28535 28534 28533 28548 28535 28533 28534 28546 28547 29455 28546 28534 28534 28535 29455 30398 29455 28535 28535 28548 30398 32126 31202 28536 28536 28537 32126 28538 28537 28536 31202 28538 28536 28537 29458 32126 28537 28538 29458 28538 28550 28553 31211 28550 28538 31212 31211 28538 28538 31202 31212 28538 29445 29458 28540 28541 28554 28555 28554 28541 28572 28555 28541 28542 28543 29451 29452 29451 28543 28543 28544 29452 28545 28544 28543 29455 29452 28544 28544 28545 29455 28545 28546 29455 28548 29456 29457 30401 30398 28548 28548 29457 30401 28550 28551 28553 28552 28551 28550 28557 28552 28550 29461 28557 28550 31214 29461 28550 28550 31211 31214 28555 28572 30399 30408 30407 28556 30416 30408 28556 28556 29464 30416 28556 29462 29464 28556 28557 29462 28557 29461 29462 28558 28559 29459 28560 28559 28558 28571 28560 28558 28558 28570 28571 31213 29459 28559 31219 31213 28559 28559 28560 31219 28560 29472 31219 28560 28571 29472 28561 28574 29466 28577 28574 28561 28562 29467 30418 29468 28564 28562 30419 29468 28562 28562 30418 30419 28563 28565 28569 28566 28565 28563 29468 28566 28563 28563 28564 29468 29471 28569 28565 31217 29471 28565 28565 28566 31217 32137 31217 28566 28566 30419 32137 28566 29468 30419 28567 28568 28570 28569 28568 28567 28578 28569 28567 30420 29472 28568 28568 28569 30420 28571 28570 28568 29472 28571 28568 28569 29471 30420 30402 30399 28572 28573 28574 28577 28575 28574 28573 28581 28575 28573 28573 28577 28581 29469 29466 28574 30430 29469 28574 28574 30427 30430 28574 28576 30427 28574 28575 28576 29475 28576 28575 28575 29474 29475 28575 28581 29474 28576 29475 30427 28589 28582 28579 30421 28589 28579 28579 30415 30421 28579 28580 30415 28580 30399 30402 28580 30402 30415 28581 28583 29474 28589 28587 28582 28583 29473 29474 28583 28584 29473 28585 28584 28583 30448 29473 28584 28584 28585 30448 30454 30448 28585 28585 29484 30454 29491 28596 28586 28586 28595 29491 28587 28590 28597 28587 28588 28590 28589 28588 28587 30449 28590 28588 30451 30449 28588 28588 29476 30451 29477 29476 28588 30422 29477 28588 28588 28589 30422 28589 30421 30422 28601 28597 28590 30450 28601 28590 28590 30449 30450 28591 28592 29493 29493 28598 28591 28593 28594 29498 28594 29485 29498 28595 29490 29491 28595 28605 29490 29488 29484 28596 29491 29488 28596 28601 28600 28597 28598 29493 29503 29492 28610 28600 28600 28601 29492 30450 29492 28601 28604 28603 28602 28621 28604 28602 28602 28620 28621 28603 28604 29500 29515 29500 28604 30466 29515 28604 28604 29514 30466 28604 28621 29514 28605 29489 29490 28605 28608 29489 28609 28608 28605 29501 29493 28606 29502 29501 28606 28606 29500 29502 28623 28614 28607 31280 29489 28608 31282 31280 28608 31283 31282 28608 29492 28616 28610 28625 28620 28611 28633 28622 28612 28613 28614 28623 28624 28614 28613 29509 28624 28613 29510 29509 28613 29499 28617 28616 28616 29492 29499 28619 28618 28617 29508 28619 28617 28617 29507 29508 28617 29499 29507 29513 28625 28618 28618 29512 29513 28618 28619 29512 30462 29512 28619 32187 30462 28619 28619 29508 32187 28626 28621 28620 28620 28625 28626 28621 29513 29514 28621 28626 29513 28628 28627 28622 28633 28628 28622 29513 28626 28625 29527 28632 28627 29529 29527 28627 28627 28628 29529 30464 29529 28628 28628 29506 30464 28628 28633 29506 29525 28631 28629 28629 28630 29525 29526 29525 28630 28630 29524 29526 28630 29518 29524 29552 28652 28632 29554 29552 28632 28632 29527 29554 28633 29498 29506 28659 28654 28634 28637 28636 28635 32206 28637 28635 28635 31304 32206 28635 30479 31304 28635 29545 30479 28635 28648 29545 28636 28637 30469 31291 30469 28637 32223 31291 28637 28637 32222 32223 32235 32222 28637 28637 32206 32235 28651 28642 28639 28639 28650 28651 28639 28649 28650 28639 28640 28649 28641 28640 28639 28642 28641 28639 29538 28649 28640 28640 28641 29538 28641 28642 29538 28642 28651 29538 28643 28645 29510 28646 28645 28644 28645 29509 29510 28645 28646 29509 29517 29509 28646 29524 29517 28646 30478 29524 28646 30488 30478 28646 28646 28647 30488 28647 28668 30488 28647 28653 28668 28648 28649 29545 28649 29538 29545 29558 29546 28650 28650 28656 29558 29538 28651 28650 29546 29538 28650 29555 28668 28653 28653 28658 29555 29559 29558 28656 29562 29559 28656 28656 28670 29562 29551 28660 28657 28658 28667 29555 28658 28666 28667 28659 29530 29544 30516 29564 28660 28660 29551 30516 30491 28664 28661 28661 29565 30491 28661 28662 29565 28663 28662 28661 29570 29565 28662 28662 28681 29570 28662 28663 28681 29568 28665 28664 28664 29566 29568 29567 29566 28664 30491 29567 28664 29568 28667 28665 29568 29555 28667 30489 30488 28668 28668 29560 30489 28668 29555 29560 29563 29562 28670 28670 28671 29563 29571 29563 28671 29572 28687 28673 28673 28688 29572 30500 28688 28674 28674 28675 30500 28675 28676 28677 28675 29591 30500 28675 28677 29591 28677 29576 29591 28677 28678 29576 28678 28679 29576 29592 29576 28679 28679 29589 29592 28679 28689 29589 29579 29570 28681 28691 28683 28682 30526 28693 28683 28683 29601 30526 28683 29583 29601 28683 28691 29583 28687 28686 28684 28684 28685 28694 28686 28685 28684 29585 28694 28685 28685 28686 29585 28686 28687 29588 29587 29585 28686 29588 29587 28686 28687 29572 29588 30498 29572 28688 30500 30498 28688 29590 29589 28689 29597 29590 28689 28691 28692 29583 28692 29580 29583 28692 29569 29580 28702 28696 28693 29602 28702 28693 30526 29602 28693 29595 28707 28694 28694 29585 29595 29615 28709 28697 28697 29614 29615 28697 28708 29614 29610 29599 28698 28701 28700 28699 32293 28701 28699 28699 31392 32293 28699 30532 31392 28699 30517 30532 28699 29599 30517 29600 29599 28699 28699 28700 29600 30513 29593 28700 28700 28701 30513 28700 29594 29600 28700 29593 29594 32282 30513 28701 32293 32282 28701 29613 28715 28702 28702 29612 29613 28702 29602 29612 29622 28716 28703 28703 28730 29622 28703 28724 28730 32287 28706 28704 34016 32287 28704 34043 34016 28704 28704 32299 34043 28704 31384 32299 28704 28705 31384 28706 28705 28704 28705 28720 29596 28705 28706 28720 28705 31383 31384 28705 29596 31383 30503 29584 28706 32287 30503 28706 30520 28708 28707 30521 30520 28707 28707 29595 30521 30536 29614 28708 28708 30527 30536 28708 30520 30527 29615 28727 28709 28710 28711 29616 28712 28711 28710 29617 29616 28711 28711 29598 29617 28711 28712 29598 28712 28713 29598 31359 29598 28713 28715 29613 29620 28729 28724 28715 29620 28729 28715 29621 28725 28716 29622 29621 28716 28717 28725 28731 28718 28719 28720 29596 28720 28719 29623 29596 28719 28719 28740 29623 28719 28726 28740 28721 29628 29629 29619 29611 28723 29632 29619 28723 28724 28729 28730 29621 28732 28725 28732 28731 28725 28726 28733 28740 29615 28734 28727 29631 29630 28728 29635 28730 28729 28729 29620 29635 28744 28732 28730 29640 28744 28730 28730 29635 29640 28730 28732 29622 28743 28733 28731 28731 28732 28743 28732 29621 29622 28744 28743 28732 28733 28738 28740 28739 28738 28733 28743 28739 28733 29641 28742 28734 30539 29641 28734 28734 30537 30539 28734 29624 30537 28734 29615 29624 28750 28739 28735 28735 28749 28750 28735 28736 28749 28737 28736 28735 28748 28737 28735 28735 28744 28748 28735 28743 28744 28735 28739 28743 28758 28749 28736 28776 28758 28736 28787 28776 28736 28794 28787 28736 28736 28768 28794 28736 28757 28768 28736 28756 28757 28736 28737 28756 28774 28756 28737 29640 28774 28737 28737 28748 29640 29636 28740 28738 29637 29636 28738 29663 29637 28738 28738 29650 29663 28738 28750 29650 28738 28739 28750 29636 29623 28740 28741 28742 29652 28742 29641 29652 29640 28748 28744 28745 28746 29664 31428 29664 28746 28746 29651 31428 28746 29646 29651 28746 29644 29646 28747 29627 29628 29642 29627 28747 28751 28750 28749 28758 28751 28749 28750 28751 29650 29662 29650 28751 28751 29661 29662 28751 28788 29661 28751 28777 28788 28751 28758 28777 30568 29657 28752 28752 29652 30568 29653 29648 28753 28753 28754 29653 30571 29653 28754 28754 28755 30571 28755 29658 30571 28755 28764 29658 28774 28757 28756 28769 28768 28757 28757 28767 28769 28775 28767 28757 28757 28774 28775 28758 28776 28777 30578 28762 28759 31430 30578 28759 28759 28760 31430 28761 28760 28759 28762 28761 28759 28760 31429 31430 28760 30570 31429 28760 28761 30570 30586 30570 28761 30587 30586 28761 30588 30587 28761 28761 28773 30588 28761 28762 28773 30575 29673 28762 30578 30575 28762 29659 29658 28764 28764 28784 29659 28767 28766 28765 28785 28767 28765 28793 28785 28765 29660 28793 28765 28765 28766 29660 28766 28767 28775 28766 29654 29660 28766 28774 29654 28775 28774 28766 28800 28769 28767 28767 28785 28800 28801 28794 28768 29690 28801 28768 28768 28769 29690 28769 28813 29690 28769 28812 28813 28769 28811 28812 28769 28798 28811 28799 28798 28769 28800 28799 28769 29651 29646 28770 29655 29651 28770 30573 29655 28770 30574 30573 28770 28770 29656 30574 28770 28771 29656 28772 28780 29672 30588 28773 28772 28772 29696 30588 28772 29672 29696 28774 29640 29654 28787 28777 28776 28777 28787 28788 29671 29665 28778 30585 29671 28778 28778 28779 30585 28779 30583 30585 28779 29657 30583 28780 28792 29672 28781 28782 28784 28784 28783 28781 30589 28784 28782 30589 29659 28784 29674 28800 28785 28785 28793 29674 28788 28787 28786 29681 28788 28786 30608 29681 28786 28786 29692 30608 28786 28794 29692 28786 28787 28794 29666 29661 28788 29681 29666 28788 28790 29665 29678 29678 28791 28790 28797 28795 28791 28804 28797 28791 29684 28804 28791 28791 29679 29684 28791 29678 29679 29686 29674 28793 28793 29660 29686 28794 28801 29692 30593 29688 28796 31477 30593 28796 31507 31477 28796 31509 31507 28796 28796 28815 31509 28804 28803 28797 28798 28808 28811 28819 28808 28798 28798 28805 28819 28798 28799 28805 28799 28800 28805 29674 28805 28800 28801 29691 29692 28801 29690 29691 28802 28817 29709 28818 28817 28803 28803 28804 28818 30611 28818 28804 28804 29684 30611 28805 28806 28819 28807 28806 28805 29689 28807 28805 28805 29674 29689 28806 28807 29704 28826 28819 28806 28806 28825 28826 28844 28825 28806 29704 28844 28806 28807 29689 29703 28807 29703 29704 28808 28809 28811 28810 28809 28808 28826 28810 28808 28808 28819 28826 28820 28811 28809 28830 28820 28809 28809 28829 28830 28809 28828 28829 28809 28810 28828 28810 28827 28845 28810 28826 28827 28846 28828 28810 28847 28846 28810 28810 28845 28847 28822 28812 28811 28811 28821 28822 28811 28820 28821 28822 28813 28812 29691 29690 28813 29705 29691 28813 28813 28824 29705 28813 28822 28824 28814 29687 29694 31510 31509 28815 28815 28816 31510 28816 30627 31518 31518 31510 28816 29711 29709 28817 28817 28818 29711 28818 29710 29711 30628 29710 28818 28818 30611 30628 28820 28832 29718 28820 28830 28832 29718 28821 28820 28823 28822 28821 29718 28823 28821 28830 28824 28822 28832 28830 28822 28822 28823 28832 29718 28832 28823 30643 29705 28824 28824 28830 30643 28827 28826 28825 28843 28827 28825 28844 28843 28825 28827 28843 28845 29722 28829 28828 28828 28846 29722 28831 28830 28829 29722 28831 28829 28830 28846 28847 28830 28831 28846 28830 28856 30643 28830 28847 28856 29722 28846 28831 28833 29719 29729 28833 29713 29719 28833 28834 29713 28834 28836 29713 28834 28835 28836 28837 28836 28835 28836 28841 29713 28836 28838 28841 28836 28837 28838 28838 28839 28841 28840 28839 28838 29730 28841 28839 28839 28842 29730 28839 28840 28842 28851 28842 28840 28840 28850 28851 28841 29712 29713 28841 29702 29712 30639 29702 28841 28841 29730 30639 28842 28851 29736 29737 29730 28842 28842 29736 29737 28854 28845 28843 28843 28852 28854 28843 28844 28852 28844 29715 29717 28844 29704 29715 28853 28852 28844 29717 28853 28844 28845 29748 29749 28845 28858 29748 28845 28855 28858 28845 28854 28855 29742 28847 28845 30644 29742 28845 28845 29749 30644 29742 28856 28847 29743 28849 28848 29752 29743 28848 29739 28871 28849 29743 29739 28849 28857 28854 28852 28859 28857 28852 28852 28853 28859 28861 28859 28853 29731 28861 28853 28853 29717 29731 28857 28855 28854 28862 28858 28855 28855 28857 28862 31540 30643 28856 28856 29742 31540 29746 28862 28857 29747 29746 28857 30654 29747 28857 28857 28859 30654 29754 29748 28858 28858 29746 29754 28858 28862 29746 28859 28860 30654 28861 28860 28859 31550 30654 28860 33317 31550 28860 28860 32414 33317 28860 30646 32414 28860 30645 30646 28860 28861 30645 28861 29738 30642 28861 29731 29738 28861 30642 30645 28863 28864 28866 28865 28864 28863 29758 28865 28863 28863 29756 29758 29766 29756 28863 28863 28867 29766 28863 28866 28867 28864 28865 28873 28876 28873 28865 28865 28875 28876 29758 28875 28865 29750 28867 28866 29751 29750 28866 30663 29766 28867 28867 29750 30663 28869 29744 29753 28869 28870 29744 28870 28871 29744 28871 29739 29743 28871 29743 29744 29768 29745 28872 29770 29768 28872 28872 28878 29770 29776 28881 28874 28874 28875 29776 28876 28875 28874 28875 29765 29776 28875 29756 29765 29758 29756 28875 28877 29761 30664 29771 29770 28878 29781 29771 28879 28894 28889 28880 29787 28894 28880 28880 28881 29787 28881 29776 29787 31579 29775 28882 28882 28883 31579 28884 28883 28882 29775 28884 28882 28883 31573 31579 28883 29764 31573 28883 29757 29764 28883 28884 29757 28884 28886 29757 28888 28886 28884 28891 28888 28884 29775 28891 28884 28885 28892 28893 28885 28890 28892 28885 28888 28890 28885 28886 28888 28887 28886 28885 28893 28887 28885 29765 29757 28886 29782 29765 28886 28886 28887 29782 28887 28893 29782 28891 28890 28888 28890 28891 28892 29799 28892 28891 28891 29797 29799 28891 29773 29797 29775 29773 28891 29799 28893 28892 29785 29782 28893 29803 29785 28893 28893 29802 29803 28893 29799 29802 28894 29805 29806 28894 29787 29805 30700 28912 28895 28895 28896 30700 28896 30699 30700 30701 30699 28896 28896 29813 30701 29815 29813 28896 28896 28897 29815 29835 29825 28900 29842 29826 28902 28902 29841 29842 29856 29841 28902 28902 28915 29856 28902 28903 28909 28904 28903 28902 29826 28904 28902 28903 28907 28909 28903 28905 28907 28903 28904 28905 29792 28905 28904 30703 29792 28904 28904 29826 30703 29821 28907 28905 28905 29793 29821 28905 29792 29793 28906 29823 29851 29827 28908 28907 28907 29821 29827 28910 28920 29834 28911 29846 30718 28911 28912 29846 29847 29846 28912 30700 29847 28912 29838 28914 28913 29849 29838 28913 28913 29848 29849 28913 28917 29848 28914 29811 30704 29820 29811 28914 30707 29820 28914 28914 29838 30707 28915 28925 29856 29845 29836 28916 28918 28919 29830 29858 28927 28918 28918 29830 29858 28919 29827 29830 29858 29834 28920 28920 28928 29858 30709 29844 28921 28921 29824 30709 30720 28931 28923 28923 28924 30720 28924 30706 30720 30715 30706 28924 28924 29851 30715 29857 29856 28925 29858 28928 28927 29861 28932 28929 29855 29854 28930 28930 28939 29855 29860 29859 28931 30720 29860 28931 29861 28940 28932 28933 30734 31620 28933 28941 30734 28933 28934 28941 28948 28947 28935 28935 28936 28948 28936 28937 28948 28938 28937 28936 30740 28938 28936 28936 30728 30740 28936 30727 30728 28936 29863 30727 29864 29863 28936 28958 28948 28937 30750 28958 28937 28937 28938 30750 30751 30750 28938 28938 30740 30751 29865 29855 28939 29866 29865 28939 29877 28946 28940 28940 29861 29877 30748 30734 28941 28941 28942 30748 28942 30739 30748 28942 29878 30739 28942 28956 29878 30755 29879 28943 30761 30755 28943 28943 28959 30761 28960 28959 28943 28943 28944 28960 28945 28944 28943 29879 28945 28943 28944 28945 29867 30730 29867 28945 30745 30730 28945 28945 29879 30745 28946 29877 29884 28947 28948 28957 28958 28957 28948 28949 28959 28960 28952 28951 28950 28953 28952 28950 28965 28953 28950 29881 28965 28950 28950 28951 29881 28951 28952 29882 28951 29876 29881 28951 29871 29876 29873 29871 28951 29874 29873 28951 30747 29874 28951 28951 29882 30747 28952 28954 29882 28952 28953 28954 28965 28954 28953 28954 28965 29883 29883 29882 28954 29884 28967 28955 31649 29878 28956 28956 31645 31649 28956 28957 31645 28957 30754 31645 28957 28958 30754 28958 30750 30754 28959 29886 30761 28959 28961 29886 28961 28968 29886 28969 28968 28961 28964 28963 28962 29876 28964 28962 29881 29876 28962 28962 28965 29881 28970 28965 28962 28963 29888 29893 28963 28964 29888 28964 29880 30763 28964 29876 29880 29892 29888 28964 30763 29892 28964 28965 28970 29883 28966 29890 29891 28966 28967 29890 30753 29890 28967 28967 29884 30753 30761 29886 28968 28968 29892 30761 28968 28973 29892 28968 28969 28973 28970 28971 29883 28972 28971 28970 29885 29883 28971 29887 29885 28971 29889 29887 28971 28973 29888 29892 28973 28975 29888 29893 28975 28974 29893 29888 28975 28976 29898 30766 29894 28977 28976 30766 29894 28976 28980 28978 28977 29894 28980 28977 29895 28982 28978 28978 28979 29895 28980 28979 28978 29897 29895 28979 28979 29894 29897 28979 28980 29894 28987 28983 28981 28981 28982 28987 29903 28987 28982 28982 29902 29903 28982 29896 29902 28982 29895 29896 28984 28985 28986 29901 28986 28985 28985 28988 29901 29906 29900 28986 28986 29901 29906 28987 29903 29910 29904 29901 28988 28988 28990 29904 29911 29904 28990 28992 28993 29001 28994 28993 28992 29003 29001 28993 29926 29003 28993 28993 29924 29926 28993 29915 29924 28993 28994 29915 28995 29914 29917 28995 29909 29914 28996 29000 29930 31680 29940 28997 31693 31680 28997 28997 28998 31693 28999 28998 28997 29940 28999 28997 28998 30809 31693 28998 28999 30809 28999 30802 30809 28999 29946 30802 28999 29000 29946 29940 29000 28999 29940 29930 29000 29000 29011 29946 29003 29002 29001 29936 29010 29002 29002 29003 29936 29942 29936 29003 29003 29937 29942 29003 29932 29937 29003 29931 29932 29003 29926 29931 29005 29933 29934 29934 29006 29005 32568 30788 29006 29006 31672 32568 29006 30791 31672 29006 29934 30791 30788 30778 29006 29944 29939 29007 30801 29944 29007 29007 30800 30801 29007 29008 30800 29008 30794 30800 29008 29935 30794 29946 29011 29009 29009 29945 29946 29013 29012 29010 29936 29013 29010 29012 29013 29014 29947 29014 29013 29948 29947 29013 29013 29941 29948 29013 29936 29941 29947 29025 29014 29015 29017 29018 29949 29017 29015 29016 29017 29949 29018 29017 29016 30818 29018 29016 30819 30818 29016 31703 30819 29016 29016 30813 31703 29016 29960 30813 30818 29024 29018 29019 29950 30799 30799 29938 29019 29951 29950 29021 29021 29022 29951 30811 29951 29022 30812 30811 29022 29022 29953 30812 29954 29953 29022 29957 29954 29022 29022 29952 29957 29023 29025 29026 29967 29961 29024 30818 29967 29024 29947 29026 29025 29028 29027 29026 29956 29028 29026 29026 29947 29956 29027 29029 29038 29027 29028 29029 29959 29029 29028 29028 29955 29959 29956 29955 29028 30826 29038 29029 30830 30826 29029 29029 30823 30830 29029 30816 30823 29029 29959 30816 29030 29976 29987 29030 29034 29976 29034 29966 29976 29034 29963 29966 29035 29038 29040 29035 29036 29038 29040 29037 29035 29037 29040 29061 30854 29048 29038 29038 30835 30854 29038 30830 30835 29038 30826 30830 29048 29040 29038 29973 29971 29039 29039 29047 29973 29977 29061 29040 29040 29048 29977 29041 29045 29057 29041 29044 29045 29041 29042 29044 29043 29042 29041 29050 29043 29041 29057 29050 29041 29972 29966 29042 29042 29046 29972 29042 29043 29046 29966 29044 29042 29051 29046 29043 29043 29049 29051 29050 29049 29043 30833 29045 29044 29044 30831 30833 30832 30831 29044 29044 29966 30832 29980 29056 29045 29985 29980 29045 30833 29985 29045 29045 29056 29057 29046 29051 29972 29989 29973 29047 29047 29065 29989 29047 29059 29065 30854 29977 29048 29052 29051 29049 29053 29052 29049 29049 29050 29053 29055 29053 29050 29057 29055 29050 29981 29972 29051 32625 29981 29051 29051 29997 32625 29051 29052 29997 29052 31749 32637 29052 29995 31749 29996 29995 29052 29052 29063 29996 29052 29053 29063 30865 29997 29052 32631 30865 29052 32637 32631 29052 29053 29055 29063 29054 29068 30859 29055 29058 29063 29055 29056 29058 29057 29056 29055 29980 29058 29056 29986 29063 29058 29058 29980 29986 30022 30016 29059 29059 29060 30022 30016 29065 29059 29060 29081 30022 29061 29978 29983 29061 29977 29978 29062 30869 30875 29062 29067 30869 30025 29075 29062 30875 30025 29062 29063 29992 29996 29063 29986 29992 30018 29070 29064 30024 29989 29065 29065 30016 30024 30863 29067 29066 29066 29983 30863 30870 30869 29067 29067 30868 30870 29067 30863 30868 30864 30859 29068 29068 29069 30864 31744 30864 29069 29069 30035 31744 30026 29072 29070 29070 30018 30026 29074 29073 29072 30026 29074 29072 30037 30036 29073 29073 29074 30037 30880 30037 29074 29074 30026 30880 30029 29077 29075 29075 30025 30029 29076 29077 30031 30034 30031 29077 29077 30029 30034 30033 29080 29078 30049 30033 29078 30881 30049 29078 29078 30042 30881 29078 29098 30042 29079 30015 30023 30021 30015 29079 29079 29080 30021 30024 30022 29079 29079 30023 30024 30033 30021 29080 29084 29083 29082 30043 29085 29083 29083 29084 30043 29084 30036 30043 30043 29086 29085 30884 30051 29086 29086 30043 30884 31767 29089 29088 31784 31767 29088 31785 31784 29088 29088 30069 31785 29088 30044 30069 31767 30038 29089 30064 29092 29090 29090 30048 30064 29090 30047 30048 30065 29109 29091 29091 29092 30065 29092 30064 30065 30050 29094 29093 29094 30050 30059 29095 29096 30054 30888 30054 29096 29096 30053 30888 29096 29097 30053 29097 30052 30053 30066 29100 29098 29098 29099 30042 29100 29099 29098 33507 30042 29099 29099 31773 33507 31774 31773 29099 31778 31774 29099 31779 31778 29099 29099 29100 31779 29100 29110 30890 30066 29110 29100 29100 30889 31779 30890 30889 29100 33518 32682 29101 29101 30056 33518 29101 30055 30056 29101 29107 30055 29101 29102 29107 29103 29102 29101 32682 29103 29101 29108 29107 29102 29110 29108 29102 29102 29103 29110 32682 32680 29103 30890 29110 29103 32680 30890 29103 30058 29105 29104 29104 30057 30058 30059 30057 29104 30058 29111 29105 29113 29112 29106 29114 29113 29106 29107 29108 30065 30064 30055 29107 30065 30064 29107 29108 29110 30066 29108 29109 30065 29122 29117 29111 30058 29122 29111 30885 30063 29112 29112 30062 30885 29112 29113 30062 30893 30062 29113 29113 30892 30893 29113 30067 30892 29113 29114 30067 30068 30067 29114 29122 29118 29117 29120 29119 29118 30077 29120 29118 29118 30070 30077 29118 29122 30070 30907 30071 29119 29119 29120 30907 32698 30907 29120 29120 32693 32698 29120 31794 32693 29120 30077 31794 30079 30076 29121 30077 30070 29122 30905 30077 29122 29122 30891 30905 29122 30058 30891 30083 30082 29123 29123 29124 30083 29123 30082 30085 30091 29128 29127 29127 29130 30091 29131 29130 29127 30086 29131 29127 29127 29129 30086 30910 30895 29128 29128 30091 30910 30089 30086 29129 30090 30089 29129 29129 30084 30090 29130 29131 30086 31806 30091 29130 31809 31806 29130 29130 31807 31809 29130 30918 31807 29130 30086 30918 30094 29135 29132 29132 30085 30094 29133 29140 29141 29143 29140 29133 29133 29134 29143 29144 29143 29134 30101 29144 29134 29134 29145 30101 30094 29136 29135 30094 29147 29136 29138 29147 30094 30097 30095 29138 29138 30094 30097 30106 30100 29139 29139 29140 30106 29141 29140 29139 29142 29141 29139 29140 29143 30108 30108 30106 29140 29143 29157 30107 29143 29144 29157 29143 30107 30108 30101 29157 29144 29145 29149 30101 29148 30088 30096 29148 30087 30088 30095 30087 29148 29149 29152 30101 30103 29159 29151 30114 30103 29151 30921 30114 29151 29151 30102 30921 30110 30109 29153 29154 29155 29158 29156 29155 29154 30113 30111 29155 29155 29156 30113 30105 29158 29155 30106 30105 29155 30111 30106 29155 30122 30113 29156 29156 29165 30122 29157 29158 30107 29158 30105 30107 29167 29166 29159 30104 29167 29159 29159 30103 30104 29162 29161 29160 32700 30909 29161 33551 32700 29161 29161 30926 33551 29161 30923 30926 29161 29162 30923 29162 29169 30923 29162 29168 29169 29162 29163 29168 29163 29164 29168 29170 29168 29164 30942 30122 29165 30929 30117 29166 29166 30927 30929 29166 29167 30927 29167 30104 30927 29170 29169 29168 29169 30115 30119 29169 29170 30115 29169 30119 30923 29170 29171 30115 30121 30115 29171 30125 30121 29171 29174 29173 29172 29178 29174 29172 29172 29175 29178 29183 29177 29173 30936 29183 29173 30939 30936 29173 30940 30939 29173 29173 30132 30940 29173 29174 30132 29178 29175 29174 29174 30128 30132 29174 29175 30128 29176 30932 30933 29176 30127 30932 29180 29181 30949 31845 30131 29180 31846 31845 29180 29180 31842 31846 29180 31841 31842 29180 30949 31841 30932 30127 29182 30934 30932 29182 30935 30934 29182 30936 30935 29182 29182 29183 30936 30954 30950 29184 29184 29185 30954 29185 30136 30954 29185 30133 30136 30139 29187 29186 29187 30139 30142 29189 29197 29201 29189 29196 29197 30143 29196 29189 30144 30143 29189 29190 30145 30961 30149 29194 29193 29193 30141 30149 29193 30140 30141 30142 30140 29193 30149 29198 29194 29195 29202 30145 29195 29199 29202 30957 30147 29196 30967 30957 29196 31853 30967 29196 32751 31853 29196 29196 30143 32751 30147 29197 29196 30148 29201 29197 29197 30147 30148 29198 30149 30154 29203 29202 29199 29204 29203 29199 29206 29205 29200 30153 29206 29201 29201 30148 30153 30970 30145 29202 30973 30970 29202 29202 30157 30973 29202 29203 30157 29203 29220 30157 30167 29216 29205 29205 29206 30167 29206 30158 30167 29206 30152 30158 30153 30152 29206 29207 29217 30155 30160 29217 29208 29209 29210 29212 29211 29210 29209 30162 29212 29210 30164 30162 29210 30979 30164 29210 29210 29211 30979 29211 30978 30979 29211 30155 30978 30162 29213 29212 30980 29218 29213 29213 30163 30980 29213 30162 30163 29219 29215 29214 30154 29219 29214 30171 29224 29215 29215 30165 30171 29215 29219 30165 30976 30155 29217 29217 30160 30976 30989 30174 29218 29218 30980 30989 30174 29226 29218 30985 30165 29219 29219 30974 30985 29219 30154 30974 30173 30157 29220 29220 30166 30173 29220 29221 30166 29221 29222 29228 29221 29229 30166 29221 29228 29229 30926 30120 29223 31827 30926 29223 31828 31827 29223 31839 31828 29223 32736 31839 29223 29227 29225 29224 30990 29227 29224 29224 30171 30990 29225 29227 29234 29235 29234 29227 30177 29235 29227 30990 30177 29227 30993 29233 29229 29229 30175 30993 30173 30166 29229 29229 29232 30173 29233 29232 29229 30994 30181 29230 29230 30174 30994 29231 29269 30212 29232 30157 30173 30172 30157 29232 29232 29233 30172 29233 30993 31895 30987 30172 29233 31896 30987 29233 31899 31896 29233 29233 31895 31899 29234 29235 29240 30177 30176 29235 29245 29240 29235 30194 29245 29235 29235 30193 30194 29235 30176 30193 29236 29237 30195 30195 30185 29236 29237 29246 30195 29238 29239 30187 29239 29251 30187 31000 29251 29239 29239 30183 31000 29243 29242 29241 30184 29243 29241 29241 29244 30184 29242 30196 30203 29242 29243 30196 29243 30189 30196 29243 30184 30189 29244 30182 30184 29244 30181 30182 29246 29247 30195 30198 30195 29247 29247 29248 30198 29249 29248 29247 30199 30198 29248 29248 29255 30199 29248 29249 29255 29250 30202 31006 29250 30201 30202 29250 30200 30201 29250 29256 30200 30188 30187 29251 30202 30188 29251 31006 30202 29251 30197 29254 29252 31009 30197 29252 29252 29253 31009 31916 31009 29253 31917 31916 29253 29253 30210 31917 30192 30190 29254 30197 30192 29254 31013 30199 29255 29255 31002 31013 31003 31002 29255 29256 29265 30200 29257 30191 30211 30192 30191 29257 29257 30190 30192 31022 29272 29258 29258 29264 31022 29259 30208 30215 29261 29262 29271 30218 29263 29261 30220 30218 29261 29261 29270 30220 29271 29270 29261 30213 29271 29262 31023 31022 29264 30207 30200 29265 29265 30206 30207 30224 29274 29266 31955 30224 29266 29266 30216 31955 30217 30216 29266 30221 30217 29266 29266 30211 30221 29267 29268 30231 31940 30220 29270 29270 31939 31940 29270 31028 31939 29270 31020 31028 29270 29271 31020 29271 30213 31020 31022 29279 29272 29272 29279 29280 29278 29277 29273 30223 29278 29273 29273 29274 30223 30224 30223 29274 31033 30229 29275 29275 29280 31033 30226 29284 29277 29277 29278 30226 30227 30226 29278 30228 30227 29278 29278 30223 30228 29279 31022 31023 31951 29280 29279 29279 31943 31951 29279 31023 31943 31951 31033 29280 29283 29282 29281 29282 30205 30222 29282 29283 30205 30233 30205 29283 30234 30233 29283 29283 29288 30234 29284 29285 29287 29286 29285 29284 30226 29286 29284 31035 29287 29285 29285 30225 31035 29285 29286 30225 30227 30225 29286 29286 30226 30227 31035 30230 29287 31038 30234 29288 31039 31038 29288 31043 31039 29288 29288 29306 31043 29288 29289 29306 29290 29291 30230 31053 29303 29290 29290 31044 31053 29290 30235 31044 29290 30230 30235 30255 30246 29292 30240 30239 29294 29294 30236 30240 30237 29296 29295 31056 30237 29295 29295 31047 31056 29296 31046 31950 29296 31045 31046 29296 30237 31045 31983 30238 29297 29297 29300 31983 29301 29300 29297 31048 29301 29297 29297 29298 31048 29299 29298 29297 30238 29299 29297 29298 30239 31048 29300 29301 31962 32850 31983 29300 33682 32850 29300 29300 31966 33682 29300 31962 31966 29301 30239 31049 31048 30239 29301 29301 31049 31962 30250 29307 29302 29302 30249 30250 29302 29308 30249 31053 30243 29303 29304 29315 30253 29304 29314 29315 29306 30241 31043 30242 30241 29306 30247 30242 29306 30250 29318 29307 29309 29310 29313 29310 29328 30272 30264 29328 29310 29310 29321 30264 29311 29312 29315 29315 29314 29311 30267 30258 29316 29316 30259 30267 30260 30259 29316 29316 30256 30260 30262 30261 29317 29317 29318 30262 30263 30262 29318 29318 30250 30263 31067 30257 29319 29322 30254 30255 30268 30254 29322 29322 29323 30268 30274 30268 29323 30258 29325 29324 30281 30275 29325 29325 30266 30281 30267 30266 29325 29325 30258 30267 30271 29328 29326 30278 30271 29326 29326 29330 30278 29326 29327 29330 29328 29327 29326 30277 29330 29327 29328 30270 30272 30271 30270 29328 31077 30278 29330 29330 31072 31077 29330 30277 31072 29333 29332 29331 30272 29333 29331 29332 29333 29340 30278 29340 29333 29333 30272 30278 29342 29335 29334 30286 29336 29335 31079 30286 29335 31083 31079 29335 29335 31082 31083 29335 29341 31082 29342 29341 29335 30275 29338 29337 29338 30275 30279 29341 29349 31082 29341 29343 29349 29341 29342 29343 29344 30287 30288 29344 30286 30287 30285 29346 29345 30304 30285 29345 31088 29356 29347 29347 31081 31088 29347 31078 31081 29347 29348 31078 29348 30278 31078 29349 29350 30292 29349 30292 31082 30296 30292 29350 29350 30295 30296 30301 29359 29351 29351 29352 30301 30302 30301 29352 29352 30294 30302 29353 30289 30290 32019 30289 29353 29353 29354 32019 29355 29354 29353 30279 29355 29353 29354 32006 32019 32018 32006 29354 29354 30280 32018 29354 29355 30280 29355 30279 30280 31088 30305 29356 29357 32014 32015 29357 31094 32014 29357 30300 31094 30310 29361 29358 29358 29359 30310 29359 30301 30310 29360 29361 30310 29362 29367 32039 29368 29367 29362 32035 30304 29362 32039 32035 29362 30313 29377 29363 29363 30307 30313 29363 29364 30307 29364 30288 31085 31085 30307 29364 30314 30309 29365 30315 30314 29365 29366 29373 30316 29367 29368 32053 32053 32039 29367 29368 29369 32052 29368 32052 32053 29369 31101 32051 29369 30316 31101 29369 32051 32052 30323 29374 29370 31102 30323 29370 29370 30311 31102 30320 29385 29371 29380 29373 29372 31101 30316 29373 32051 31101 29373 29373 31114 32051 29373 29380 31114 29376 29375 29374 30323 29376 29374 32062 30322 29375 29375 32061 32062 29375 29376 32061 29376 31110 32061 29376 30323 31110 29377 30317 30330 30318 30317 29377 32059 30318 29377 29377 30313 32059 30328 30324 29378 29378 29381 30328 29380 31113 31114 31119 31113 29380 30333 30328 29381 29381 29390 30333 29391 29390 29381 30339 29395 29382 30340 30339 29382 29382 30334 30340 29382 29383 30334 29383 30317 30334 30330 30317 29383 29384 29386 29387 30331 29386 29384 29384 30320 30331 29384 29385 30320 29388 29387 29386 30327 29388 29386 30331 30327 29386 29388 30327 30335 31121 30333 29390 31123 31121 29390 31134 31123 29390 29390 29392 31134 29390 29391 29392 29394 29392 29391 31135 31134 29392 31146 31135 29392 29392 29414 31146 29392 29405 29414 29392 29394 29405 29393 29396 30337 29394 29403 29405 30339 29406 29395 30341 30337 29396 29396 29399 30341 29397 29398 29409 29398 30346 30353 29410 29409 29398 30353 29410 29398 31150 30341 29399 29399 30344 31150 29399 29400 30344 29400 30343 30344 29400 29401 30343 29401 29402 30343 30364 30343 29402 29402 30352 30364 29413 29405 29403 30349 29413 29403 29403 29404 30349 30354 30349 29404 29405 29413 29414 30364 30352 29407 29407 30363 30364 29407 29408 30363 30338 29411 29409 31145 30338 29409 31156 31145 29409 29409 29410 31156 29410 30353 31156 30338 29412 29411 32097 29414 29413 29413 32095 32097 32096 32095 29413 29413 30349 32096 29414 32097 32966 32948 31146 29414 32966 32948 29414 29415 29416 31154 29417 29416 29415 30347 29417 29415 30356 30347 29415 31154 30356 29415 29416 29417 30348 29416 30348 31154 30347 29428 29417 29430 29419 29418 29418 29429 29430 29418 29427 29429 29428 29427 29418 29419 29430 29431 31170 30361 29420 32112 31170 29420 29423 29422 29421 29422 29424 29434 30370 29424 29422 31173 30370 29422 29422 29423 31173 32109 31173 29423 29423 31180 32109 31182 31180 29423 29423 30391 31182 29424 29433 29434 29424 29425 29433 29426 29425 29424 30362 29426 29424 30370 30362 29424 29426 30362 30365 30365 30363 29426 29427 30347 30357 29427 29428 30347 30366 29429 29427 29427 30357 30366 29436 29430 29429 30372 29436 29429 29429 30366 30372 29430 30380 31188 29430 29435 30380 29436 29435 29430 31188 29431 29430 31175 31169 29431 31188 31175 29431 30368 29437 29432 30369 30368 29432 29435 30379 30380 29435 30378 30379 29435 29436 30378 29436 30371 30378 30372 30371 29436 29439 29438 29437 30377 29439 29437 29437 30367 30377 30368 30367 29437 31195 30390 29438 29438 29439 31195 29439 30377 30382 29439 30387 31195 29439 30381 30387 30382 30381 29439 29440 29441 30390 29442 29441 29440 30384 29442 29440 31198 30384 29440 29440 31197 31198 29440 31196 31197 29440 30390 31196 29441 29442 29444 29444 29443 29441 29458 29445 29442 31194 29458 29442 29442 30383 31194 30384 30383 29442 29445 29444 29442 29443 29444 29445 30386 30385 29446 30392 30386 29446 30393 30392 29446 29446 29447 30393 29446 30385 30391 30394 30393 29447 31209 30397 29448 31210 31209 29448 29449 30396 31210 29449 29450 30396 29451 29452 29460 29452 29453 29460 29454 29453 29452 29455 29454 29452 29453 29482 29483 30441 29482 29453 30443 30441 29453 29453 29454 30443 29483 29479 29453 31240 30443 29454 29454 30400 31240 29454 29455 30400 29455 30398 30400 30425 30401 29457 30426 30425 29457 29458 31194 32126 31213 30396 29459 29464 29462 29461 30411 29464 29461 31214 30411 29461 29463 31224 31226 29463 30405 31224 30406 30405 29463 29464 30411 30416 29465 29466 30412 29466 29470 30412 29466 29469 29470 32137 30418 29467 29467 31236 32137 29467 30413 31236 31235 29470 29469 29469 30430 31235 31228 30412 29470 32139 31228 29470 29470 31235 32139 31217 30420 29471 31223 31215 29472 29472 30420 31223 29472 31215 31219 29475 29474 29473 30431 29475 29473 30435 30431 29473 30444 30435 29473 30448 30444 29473 30428 30427 29475 30431 30428 29475 29476 30440 30451 29476 30434 30440 29476 29477 30434 29477 29478 30434 29479 29478 29477 30422 29479 29477 29478 29480 30434 29478 29479 29480 29481 29480 29479 29483 29481 29479 29480 29481 30434 29481 29482 30434 29483 29482 29481 30442 30434 29482 29482 30441 30442 29484 29487 30454 29488 29487 29484 29485 29486 29498 29486 29496 29498 31268 30454 29487 31271 31268 29487 29487 29488 31271 31272 31271 29488 29488 30455 31272 29488 29491 30455 29491 29490 29489 30456 29491 29489 31280 30456 29489 30456 30455 29491 30457 29499 29492 29492 30450 30457 30463 29503 29493 29493 29494 30463 29495 29494 29493 29501 29495 29493 30467 30463 29494 30472 30467 29494 29494 29495 30472 29495 29501 29521 29495 29522 30472 29495 29521 29522 29505 29498 29496 29496 29497 29505 29497 29504 29505 29497 29503 29504 29498 29505 29506 30457 29507 29499 29521 29502 29500 29500 29520 29521 29500 29515 29520 29501 29502 29521 29516 29504 29503 30463 29516 29503 30464 29505 29504 29504 29516 30464 30464 29506 29505 31281 29508 29507 29507 31269 31281 29507 30457 31269 33105 32187 29508 29508 32184 33105 29508 31281 32184 30465 30460 29511 30460 30459 29511 30473 30471 29512 30477 30473 29512 32202 30477 29512 29512 30461 32202 30462 30461 29512 30471 29513 29512 29519 29514 29513 30471 29519 29513 29514 29519 30466 29534 29520 29515 30466 29534 29515 30467 30464 29516 29516 30463 30467 29524 29518 29517 30470 30466 29519 30471 30470 29519 29537 29521 29520 29520 29535 29537 29520 29534 29535 29523 29522 29521 29537 29523 29521 31307 30472 29522 32234 31307 29522 29522 31311 32234 31312 31311 29522 29522 29523 31312 29523 30474 31312 30475 30474 29523 29523 29543 30475 29523 29537 29543 30476 29526 29524 30481 30476 29524 29524 30478 30481 29531 29530 29525 29556 29531 29525 30476 29556 29525 29525 29526 30476 31301 29554 29527 29527 31292 31301 29527 29528 31292 29529 29528 29527 29528 31290 31296 29528 30464 31290 29528 29529 30464 31293 31292 29528 31296 31293 29528 29530 29531 29544 29556 29544 29531 29536 29535 29532 29541 29536 29532 29532 29533 29541 29534 29533 29532 29535 29534 29532 29533 29539 29541 29540 29539 29533 29533 29534 29540 30473 29540 29534 29534 30470 30473 29534 30466 30470 29535 29536 29537 29548 29542 29536 29549 29548 29536 29536 29547 29549 29536 29541 29547 29542 29537 29536 29537 29542 29543 29546 29545 29538 29547 29541 29539 29550 29547 29539 30486 29550 29539 31300 30486 29539 29539 31295 31300 29539 29540 31295 29540 31294 31295 29540 30473 31294 29548 29543 29542 30480 30475 29543 29543 29548 30480 29544 29556 29557 30484 30479 29545 29545 29546 30484 31298 30484 29546 29546 31297 31298 29546 29558 31297 29550 29549 29547 31310 30480 29548 29548 29549 31310 29549 31306 31310 29549 29550 31306 29550 30485 31306 30486 30485 29550 31308 30516 29551 29551 29553 31308 29554 29553 29552 29553 31301 31308 29553 29554 31301 30492 29560 29555 29555 29568 30492 29556 30482 30483 29556 30476 30482 30483 29557 29556 30493 29561 29557 29557 30483 30493 31305 31297 29558 29558 30490 31305 29558 29559 30490 29559 29562 30490 30495 30489 29560 29560 29582 30495 30492 29582 29560 30493 29569 29561 31309 30490 29562 29562 29563 31309 31320 31309 29563 29563 29571 31320 29564 30516 31345 30494 30491 29565 29565 29570 30494 31321 29568 29566 31331 31321 29566 32253 31331 29566 29566 29567 32253 29567 32246 32253 29567 31329 32246 29567 31328 31329 29567 30491 31328 31321 30492 29568 30495 29580 29569 29569 30493 30495 30510 30494 29570 29570 29579 30510 29571 30502 31320 29571 29584 30502 30497 30496 29572 30498 30497 29572 30496 29588 29572 29573 29574 32274 29575 29574 29573 29591 29575 29573 30499 29591 29573 32273 30499 29573 32274 32273 29573 29574 31365 32275 29574 31358 31365 29574 29575 31358 32275 32274 29574 29575 29591 29592 31364 31358 29575 29575 30515 31364 29575 29592 30515 29592 29591 29576 32288 31359 29577 29577 32280 32288 32281 32280 29577 29577 29578 32281 33169 32281 29578 29578 32252 33169 29578 31345 32252 30513 30510 29579 29579 29593 30513 30495 29582 29580 29580 29581 29583 29582 29581 29580 30501 29583 29581 31347 30501 29581 29581 31322 31347 29581 29582 31322 29582 30492 31322 30501 29601 29583 30503 30502 29584 29585 29586 29595 29587 29586 29585 30514 29595 29586 29586 30511 30514 29586 30504 30511 30507 30504 29586 29586 29587 30507 30508 30507 29587 29587 29588 30508 29588 30496 30508 30515 29592 29589 29589 29590 30515 32276 30515 29590 29590 31367 32276 29590 30522 31367 29590 29597 30522 29591 30499 30500 29595 30514 30521 29596 29637 31383 30535 29637 29596 29596 29623 30535 30523 30522 29597 30524 30523 29597 29597 29603 30524 29604 29603 29597 29616 29604 29597 29598 31359 31381 30528 29617 29598 31381 30528 29598 29599 29610 30517 31395 30526 29601 32294 31395 29601 29601 31360 32294 29601 31347 31360 29601 30501 31347 30526 29612 29602 31380 30524 29603 31381 31380 29603 29603 30528 31381 29603 29604 30528 29604 29617 30528 29604 29616 29617 29605 29607 30529 29605 29606 29607 29609 29607 29606 31368 29609 29606 29606 30525 31368 29607 29618 31390 29607 29608 29618 29609 29608 29607 31390 30529 29607 32302 29618 29608 33204 32302 29608 29608 32292 33204 29608 32290 32292 29608 29609 32290 29609 31371 32290 29609 31368 31371 29638 29633 29610 29610 29611 29638 29610 29633 30517 29611 29619 29638 30534 29613 29612 29612 30526 30534 30540 29620 29613 29613 30534 30540 30536 29615 29614 31393 29624 29615 31407 31393 29615 29615 29625 31407 29626 29625 29615 30536 29626 29615 32301 31391 29618 32302 32301 29618 31391 31390 29618 29619 29630 29638 29632 29630 29619 30540 29639 29620 29639 29635 29620 29623 29636 30535 31393 30537 29624 33223 31407 29625 34064 33223 29625 29625 33220 34064 29625 31402 33220 29625 29626 31402 29626 31387 31402 29626 30536 31387 29629 29628 29627 31389 29629 29627 29627 30542 31389 30543 30542 29627 32320 30543 29627 29627 31423 32320 29627 30554 31423 29627 29642 30554 31388 31370 29629 31389 31388 29629 29630 29633 29638 29634 29633 29630 29630 29631 29634 30531 29634 29631 29631 30530 30531 30533 30517 29633 29633 29634 30533 29634 30531 30533 29643 29640 29635 29635 29639 29643 29636 29637 30535 34069 33236 29637 34076 34069 29637 29637 32346 34076 29637 29663 32346 33235 31383 29637 33236 33235 29637 30540 29643 29639 29640 29649 29654 29640 29643 29649 30538 29652 29641 30539 30538 29641 29642 29647 30554 30566 29649 29643 29643 30540 30566 29644 29645 29646 29647 29648 30564 30563 30554 29647 30564 30563 29647 29648 29653 30564 30566 29654 29649 29650 29662 29663 31441 31428 29651 29651 29655 31441 30584 30568 29652 29652 30567 30584 29652 30558 30567 29652 30538 30558 30565 30564 29653 30571 30565 29653 30566 29660 29654 29655 30573 31441 30582 30574 29656 29656 29670 30582 29657 30568 30583 30579 30571 29658 29658 29659 30579 29659 30576 30579 30589 30576 29659 30592 29686 29660 29660 30580 30592 29660 30572 30580 29660 30566 30572 29663 29662 29661 31446 29663 29661 32347 31446 29661 29661 30596 32347 29661 29666 30596 29663 31446 32346 31448 29667 29664 29664 31447 31448 29664 31428 31447 29665 29671 29678 29666 29681 30596 31459 30581 29667 29667 31448 31459 29668 29675 29677 29668 29669 29675 29676 29675 29669 30581 29676 29669 30593 30582 29670 29670 29688 30593 30594 29678 29671 29671 30585 30594 30605 29696 29672 29673 30576 30589 29673 30575 30576 29674 29685 29689 29686 29685 29674 29683 29677 29675 30601 29683 29675 29675 29676 30601 30602 30601 29676 30603 30602 29676 29676 30581 30603 29677 29682 29687 29683 29682 29677 29678 30594 30598 29680 29679 29678 30598 29680 29678 30610 29684 29679 29679 29680 30610 31478 30610 29680 29680 31450 31478 29680 31449 31450 29680 30598 31449 30608 30600 29681 30599 30596 29681 30600 30599 29681 29693 29687 29682 29708 29693 29682 29682 29706 29708 29682 29683 29706 29707 29706 29683 30621 29707 29683 29683 30601 30621 29684 30609 30611 30610 30609 29684 29703 29689 29685 30606 29703 29685 29685 30592 30606 29685 29686 30592 29687 29693 29694 30620 29692 29691 30631 30620 29691 29691 29705 30631 30620 30619 29692 30625 30608 29692 29692 30619 30625 29708 29694 29693 30626 29723 29694 29694 29708 30626 29695 29696 30605 29697 29696 29695 30614 29697 29695 30595 30588 29696 29696 29697 30595 32369 30595 29697 32371 32369 29697 29697 32370 32371 29697 31479 32370 29697 30613 31479 30614 30613 29697 29714 29712 29698 29698 29699 29714 29700 29699 29698 29702 29700 29698 29712 29702 29698 30614 29714 29699 29699 30613 30614 30615 30613 29699 29699 29700 30615 29700 29701 30615 29702 29701 29700 30616 30615 29701 31486 30616 29701 29701 30640 31486 29701 30639 30640 29701 29702 30639 29716 29704 29703 30607 29716 29703 29703 30606 30607 29716 29715 29704 30635 30631 29705 30643 30635 29705 31516 29708 29706 31517 31516 29706 32380 31517 29706 29706 29707 32380 29707 32379 32380 29707 30621 32379 31516 30626 29708 29711 29710 29709 30633 30627 29709 29709 29710 30633 29710 30628 30633 29714 29713 29712 29713 29714 29719 30614 29719 29714 29715 29716 29720 29720 29717 29715 30617 29721 29716 30618 30617 29716 29716 30607 30618 29721 29720 29716 29738 29731 29717 30634 29738 29717 29717 29720 30634 30614 29729 29719 29720 30630 30634 29720 29721 30630 29721 30617 30624 29721 30624 30630 30636 30632 29723 29723 30626 30636 30632 29724 29723 29726 29725 29724 30632 29726 29724 29725 29727 29728 29732 29727 29725 29725 29726 29732 30637 29732 29726 29726 30632 30637 30640 30639 29730 31520 30640 29730 29730 29737 31520 29732 30637 31536 31547 29752 29733 31548 31547 29733 29733 29734 31548 29735 29734 29733 31536 29735 29733 32401 31548 29734 32415 32401 29734 29734 29735 32415 29735 32398 32415 29735 31536 32398 30641 29737 29736 29736 29740 30641 29737 30651 31520 29737 30641 30651 29738 30634 30642 29740 29741 30641 30652 30641 29741 29741 29745 30652 31544 31540 29742 29742 30644 31544 29752 29744 29743 31547 29753 29744 29744 29752 31547 30653 30652 29745 29745 29768 30653 30656 29754 29746 29746 30655 30656 29746 29747 30655 30665 30655 29747 32417 30665 29747 29747 31550 32417 29747 30654 31550 31551 29749 29748 29748 29754 31551 31551 31544 29749 31544 30644 29749 31562 30663 29750 31577 31562 29750 29750 29759 31577 29750 29751 29759 30662 29763 29753 31559 30662 29753 29753 31547 31559 29754 30656 31551 29757 29756 29755 30658 29757 29755 31561 30658 29755 29755 31554 31561 29755 31552 31554 29755 30659 31552 29755 29756 30659 29756 29757 29765 29756 29766 30659 30657 29764 29757 30658 30657 29757 31578 31577 29759 29759 29760 31578 31580 31578 29760 29760 30670 31580 29761 29762 29763 29761 30660 30664 29761 29763 30660 30661 30660 29763 30662 30661 29763 29764 30657 31573 29786 29776 29765 29765 29783 29786 29765 29782 29783 31552 30659 29766 29766 30663 31552 29767 29768 29770 29769 29768 29767 30669 29769 29767 29767 29770 30669 31549 30653 29768 29768 29769 31549 31570 31549 29769 31571 31570 29769 32412 31571 29769 29769 32411 32412 29769 30682 32411 29769 30681 30682 29769 30669 30681 29770 29771 30669 29771 29781 30669 30672 30671 29772 31582 30670 29772 31584 31582 29772 29772 30677 31584 29772 30673 30677 29772 30671 30673 29798 29797 29773 30683 29798 29773 29773 29774 30683 29775 29774 29773 29774 29775 30683 31579 30683 29775 29788 29787 29776 29776 29786 29788 30667 29794 29777 30668 30667 29777 29777 29778 30668 29779 29778 29777 29794 29779 29777 30684 30668 29778 29778 30678 30684 29778 29790 30678 29778 29780 29790 29778 29779 29780 29779 29794 29796 29789 29780 29779 29795 29789 29779 29796 29795 29779 29780 29789 29790 30681 30669 29781 30688 30681 29781 29784 29783 29782 29785 29784 29782 29783 29784 29786 30686 29786 29784 30690 30686 29784 29784 29804 30690 29784 29803 29804 29784 29785 29803 30686 29788 29786 29787 29788 29805 30686 29805 29788 30685 29790 29789 29789 29807 30685 29789 29791 29807 29795 29791 29789 30685 30678 29790 29791 29792 29807 29793 29792 29791 29800 29793 29791 29791 29795 29800 30693 29807 29792 30702 30693 29792 30703 30702 29792 29827 29821 29793 31606 29827 29793 29793 29809 31606 29793 29808 29809 29793 29800 29808 31568 30674 29794 29794 30667 31568 30674 29796 29794 29795 29796 29800 30679 29800 29796 29796 30675 30679 29796 30674 30675 29802 29799 29797 29797 29801 29802 29814 29801 29797 29797 29810 29814 29797 29798 29810 31589 29810 29798 29798 30683 31589 30679 29808 29800 29801 29815 29818 29801 29814 29815 29811 29802 29801 29819 29811 29801 29801 29818 29819 29804 29803 29802 29811 29804 29802 29804 29820 30690 29804 29811 29820 30686 29806 29805 29806 30686 30691 30692 30685 29807 30693 30692 29807 31586 29809 29808 29808 30687 31586 29808 30679 30687 32471 31606 29809 29809 32467 32471 29809 31586 32467 29816 29814 29810 30694 29816 29810 31589 30694 29810 29811 29819 30704 31607 31596 29812 29812 31602 31607 29815 29814 29813 31597 30701 29813 29813 29817 31597 29813 29816 29817 29813 29814 29816 29822 29818 29815 30694 29817 29816 32474 31597 29817 29817 30694 32474 29822 29819 29818 29819 29822 30704 31598 30690 29820 31601 31598 29820 29820 30707 31601 29823 29839 29851 29840 29839 29823 30691 29840 29823 29824 29835 30709 29824 29825 29835 31605 30703 29826 31610 31605 29826 29826 29842 31610 29829 29828 29827 31606 29829 29827 29827 29828 29830 29828 29829 32477 32483 29830 29828 29828 31616 32483 32477 31616 29828 29829 32475 32477 29829 31606 32475 29830 29832 29858 30724 29832 29830 30725 30724 29830 32483 30725 29830 29831 29834 29858 29858 29832 29831 30708 29833 29832 30724 30708 29832 32476 31602 29833 29833 31612 32476 29833 30708 31612 30712 30709 29835 30713 30712 29835 29835 29837 30713 29835 29836 29837 29845 29837 29836 30717 30713 29837 29837 29853 30717 29837 29845 29853 29838 30705 30707 29838 29850 30705 29838 29849 29850 30715 29851 29839 31603 30715 29839 29839 30710 31603 31601 30710 29839 29839 29840 31601 29840 31598 31601 29840 30696 31598 29840 30695 30696 29840 30691 30695 30722 29842 29841 29841 29856 30722 32482 31610 29842 29842 30722 32482 30716 29852 29843 29843 29844 30716 29844 30709 30716 30719 30718 29846 29846 30714 30719 29846 29847 30714 29847 30700 30714 29854 29850 29849 29850 29854 30705 31619 30717 29853 30706 30705 29854 29854 29865 30706 29854 29855 29865 29856 30721 30722 30729 30721 29856 29856 29857 30729 29857 29867 30729 29859 29865 29866 29859 29860 29865 30706 29865 29860 30720 30706 29860 30738 29877 29861 29861 30733 30738 29861 29862 30733 29862 30726 30733 29863 29864 30718 31623 30727 29863 29863 30718 31623 30730 30729 29867 29868 29872 30736 29868 29871 29872 29868 29869 29871 29870 29869 29868 30736 29870 29868 29876 29871 29869 29869 29875 29876 31628 29875 29869 29869 29870 31628 29870 30731 31628 30732 30731 29870 30736 30732 29870 29873 29872 29871 29872 29874 30736 29872 29873 29874 30737 30736 29874 30747 30737 29874 30741 29880 29875 31628 30741 29875 29880 29876 29875 30744 29884 29877 29877 30738 30744 31643 30739 29878 31644 31643 29878 31649 31644 29878 31637 30745 29879 29879 30756 31637 29879 30755 30756 29880 30746 31642 29880 30741 30746 31642 30763 29880 30752 30747 29882 30758 30752 29882 30759 30758 29882 29882 29883 30759 29883 29885 30759 29884 30744 30753 29885 29887 30759 29887 29889 30760 30760 30759 29887 29889 29890 30760 30764 30760 29890 29890 30753 30764 30762 30761 29892 31650 30762 29892 29892 31642 31650 29892 30763 31642 30766 29897 29894 29897 29896 29895 29908 29902 29896 30769 29908 29896 31657 30769 29896 29896 29897 31657 29897 30767 31657 29897 30766 30767 30771 30767 29898 32543 30771 29898 29898 31655 32543 29898 29899 31655 30767 30766 29898 29899 30765 31655 31654 30765 29900 29900 30768 31654 29900 29906 30768 29901 29905 29906 29901 29904 29905 29910 29903 29902 29902 29908 29910 29912 29905 29904 29904 29911 29912 31656 29906 29905 31658 31656 29905 29905 29912 31658 31656 30768 29906 30772 29918 29907 29907 30770 30772 29907 29908 30770 29909 29908 29907 29914 29909 29907 29918 29914 29907 29908 29909 29910 29908 30769 30770 29913 29912 29911 29914 29916 29917 29918 29916 29914 29915 29921 29924 29923 29921 29915 29915 29920 29923 29929 29917 29916 29916 29927 29929 29928 29927 29916 30785 29928 29916 29916 30781 30785 29916 30772 30781 29916 29918 30772 29917 29929 29935 29923 29920 29919 30784 29923 29919 30789 30784 29919 29919 30782 30789 29921 29922 29924 29923 29922 29921 30783 29925 29922 29922 29923 30783 29925 29924 29922 30784 30783 29923 29924 29925 29926 29931 29926 29925 31674 29931 29925 29925 31671 31674 29925 30783 31671 30794 29929 29927 31677 30794 29927 29927 30787 31677 29927 29928 30787 29928 30786 30787 29928 30785 30786 30794 29935 29929 29930 29940 30782 31675 29932 29931 29931 31674 31675 32575 29937 29932 29932 32574 32575 29932 31675 32574 30798 30797 29933 29933 29938 30798 30797 29934 29933 30797 30791 29934 29942 29941 29936 30795 29942 29937 30796 30795 29937 32575 30796 29937 30799 30798 29938 29939 29944 29945 31680 30790 29940 30790 30782 29940 30806 29948 29941 29941 29942 30806 30808 30806 29942 30810 30808 29942 29942 30795 30810 29945 29944 29943 30803 29945 29943 29943 30800 30803 30801 30800 29943 29943 29944 30801 30804 29946 29945 31694 30804 29945 31695 31694 29945 29945 30803 31695 30805 30802 29946 29946 30804 30805 29947 29948 29956 29948 29955 29956 30806 29955 29948 31682 30793 29950 31683 31682 29950 29950 29951 31683 29950 30793 30799 29951 30811 31683 29953 29962 30812 29953 29954 29962 30814 29962 29954 29954 29957 30814 30815 29959 29955 29955 30807 30815 29955 30806 30807 29957 29962 30814 29968 29962 29958 29958 29964 29968 29959 30815 30816 29960 29965 30827 30827 30813 29960 29967 29963 29961 29962 29968 30853 29962 30853 31699 31699 30812 29962 30832 29966 29963 31712 30832 29963 29963 30825 31712 29963 29967 30825 29964 29971 30852 29970 29968 29964 30852 29970 29964 29965 29969 30827 29966 29972 29976 29967 30818 30825 29968 30820 30853 29968 29970 30820 30837 30829 29969 30829 30827 29969 30822 30820 29970 30852 30822 29970 29971 29973 30852 30838 29976 29972 29972 29982 30838 29972 29981 29982 29973 30822 30852 29973 30013 30822 30023 30013 29973 29973 29989 30023 29984 29975 29974 31723 30837 29975 29975 29984 31723 30834 29987 29976 30838 30834 29976 29979 29978 29977 30854 29979 29977 30858 29983 29978 29978 29979 30858 31735 30858 29979 29979 30835 31735 30854 30835 29979 29980 29985 29986 30839 29982 29981 32627 30839 29981 29981 32625 32627 29982 30834 30838 30839 30834 29982 29983 30858 30863 31726 31723 29984 29984 29991 31726 30860 29991 29984 29984 30859 30860 31727 31726 29985 31728 31727 29985 29985 30833 31728 31726 29986 29985 29986 29990 29992 29991 29990 29986 31726 29991 29986 30839 29988 29987 29987 30834 30839 30866 29998 29988 31739 30866 29988 33487 31739 29988 29988 33481 33487 29988 30839 33481 30024 30023 29989 29994 29992 29990 30017 29994 29990 30860 30017 29990 29990 29991 30860 29992 29995 29996 29992 29993 29995 29994 29993 29992 31749 29995 29993 29993 29994 31749 29994 31748 31749 29994 30872 31748 29994 30017 30872 33484 32625 29997 29997 30865 33484 30866 29999 29998 30026 30018 29999 30880 30026 29999 31751 30880 29999 29999 31740 31751 29999 30866 31740 30873 30005 30000 31743 30873 30000 30000 30001 31743 30002 30001 30000 30005 30002 30000 30001 30019 30027 30001 30002 30019 31750 31743 30001 30001 30874 31750 30001 30027 30874 30002 30006 30019 30002 30003 30006 30005 30003 30002 30008 30006 30003 30003 30004 30008 30005 30004 30003 30849 30008 30004 30004 30848 30849 30004 30846 30848 30004 30009 30846 30004 30005 30009 30856 30009 30005 30867 30856 30005 30871 30867 30005 30873 30871 30005 30006 30010 30019 30006 30007 30010 30008 30007 30006 30011 30010 30007 30851 30011 30007 30007 30850 30851 30007 30008 30850 30008 30849 30850 30009 30843 30846 30847 30843 30009 30856 30847 30009 30010 30011 30012 30020 30019 30010 30010 30012 30020 30851 30013 30011 30013 30012 30011 30021 30020 30012 30012 30014 30021 30012 30013 30014 30851 30822 30013 30015 30014 30013 30023 30015 30013 30014 30015 30021 30016 30022 30024 30017 30860 30872 30019 30020 30027 30878 30027 30020 30020 30028 30878 30020 30021 30028 30041 30028 30021 30021 30033 30041 30030 30029 30025 30875 30030 30025 30877 30874 30027 30878 30877 30027 31753 30878 30028 31760 31753 30028 30028 30041 31760 30029 30030 30034 30030 30032 30034 30879 30032 30030 31755 30879 30030 30030 30875 31755 30034 30032 30031 30879 30035 30032 30049 30041 30033 31761 31744 30035 31763 31761 30035 32656 31763 30035 30035 32654 32656 30035 30879 32654 30882 30043 30036 31765 30882 30036 30036 31756 31765 30036 30037 31756 30037 31751 31756 30037 30880 31751 30040 30039 30038 31767 30040 30038 31769 30046 30040 32660 31769 30040 30040 31770 32660 30040 31767 31770 30041 31759 31760 30041 30049 31759 33507 30881 30042 30043 30883 30884 30043 30882 30883 30045 30046 30048 30048 30047 30045 30055 30048 30046 30056 30055 30046 32663 30056 30046 30046 31768 32663 31769 31768 30046 30048 30055 30064 30049 30881 31759 30060 30059 30050 30061 30060 30050 30050 30051 30061 30884 30061 30051 30886 30053 30052 30052 30885 30886 30052 30063 30885 30053 30075 30888 31777 30075 30053 30053 30886 31777 30056 32662 33518 32663 32662 30056 30891 30058 30057 31792 30891 30057 30057 30887 31792 30057 30059 30887 31780 30887 30059 30059 30060 31780 32669 32668 30060 30060 31781 32669 31782 31781 30060 30060 30061 31782 32668 31780 30060 30061 31776 31782 30061 30884 31776 31783 30885 30062 30062 30893 31783 30067 30068 30892 30899 30892 30068 30068 30073 30899 31789 31785 30069 30069 30904 31789 30906 30072 30071 30907 30906 30071 30906 30074 30072 30073 30896 30899 30073 30078 30896 30896 30078 30074 30906 30896 30074 30075 31777 31788 30077 30905 31794 30079 30080 30081 30909 30080 30079 30080 30909 31796 31796 30081 30080 30911 30084 30081 31805 30911 30081 30081 31799 31805 30081 31796 31799 30082 30083 30900 30092 30085 30082 30093 30092 30082 30900 30093 30082 30911 30090 30084 30085 30092 30094 30086 30089 30918 30917 30088 30087 30087 30912 30917 30087 30095 30912 30917 30096 30088 30919 30918 30089 30089 30915 30919 30089 30090 30915 30090 30911 30915 31806 30910 30091 30097 30094 30092 30099 30097 30092 30901 30099 30092 30092 30093 30901 30093 30900 30901 31798 30912 30095 30095 30097 31798 30921 30102 30096 30096 30917 30921 30097 30098 31798 30099 30098 30097 31804 31798 30098 30098 31803 31804 30098 30099 31803 30099 30901 31803 30924 30110 30100 30100 30112 30924 30100 30106 30112 30928 30104 30103 31819 30928 30103 31821 31819 30103 30103 31818 31821 30103 30922 31818 30103 30114 30922 30928 30927 30104 30108 30107 30105 30105 30106 30108 30106 30111 30112 30925 30116 30109 30109 30110 30925 30110 30924 30925 31834 30112 30111 30111 30122 31834 30111 30113 30122 31822 30924 30112 31829 31822 30112 31834 31829 30112 30114 30921 30922 30115 30118 30119 30121 30118 30115 31830 30123 30117 30117 30929 31830 30125 30120 30118 30118 30121 30125 30120 30119 30118 30926 30923 30119 30119 30120 30926 31840 31834 30122 32729 31840 30122 30122 30947 32729 30948 30947 30122 30122 30942 30948 30129 30124 30123 30130 30129 30123 31830 30130 30123 31838 30132 30128 30128 30943 31838 30128 30135 30943 30944 30133 30130 30945 30944 30130 32721 30945 30130 30130 31830 32721 31845 30942 30131 30132 30937 30940 30938 30937 30132 31843 30938 30132 30132 31838 31843 30944 30136 30133 30946 30138 30134 30138 30137 30134 30136 30952 30954 30953 30952 30136 30136 30944 30953 30955 30139 30137 31850 30955 30137 30137 30138 31850 30138 30946 31850 30141 30140 30139 30955 30141 30139 30139 30140 30142 30151 30149 30141 31873 30151 30141 30141 30955 31873 30143 30963 32751 30143 30962 30963 30143 30144 30962 30965 30962 30144 30969 30961 30145 30970 30969 30145 31872 30148 30146 30146 31865 31872 30146 30968 31865 30146 30956 30968 30146 30147 30956 30148 30147 30146 30957 30956 30147 31872 31871 30148 31871 30153 30148 30149 30150 30154 30151 30150 30149 30156 30154 30150 30150 30151 30156 31868 30156 30151 31873 31868 30151 30159 30158 30152 31878 30159 30152 30152 31871 31878 30152 30153 31871 30975 30974 30154 30154 30156 30975 30155 30976 30978 31883 30975 30156 30156 31880 31883 30156 31867 31880 31868 31867 30156 30981 30973 30157 30157 30172 30981 30169 30167 30158 30158 30168 30169 30158 30159 30168 31884 30168 30159 32769 31884 30159 30159 31878 32769 30977 30976 30160 30160 30161 30977 30982 30977 30161 30161 30170 30982 30161 30169 30170 30164 30163 30162 30983 30980 30163 30984 30983 30163 30163 30164 30984 30979 30978 30164 31890 30984 30164 31891 31890 30164 35413 31891 30164 30164 35411 35413 30164 31879 35411 30164 30978 31879 30985 30171 30165 30168 31885 31886 30168 31884 31885 30170 30169 30168 31886 30170 30168 31887 30982 30170 33625 31887 30170 30170 31886 33625 30171 30985 30990 30987 30981 30172 30174 30989 30994 31895 30993 30175 30175 30178 31895 30176 30177 30990 30996 30193 30176 30176 30990 30996 33630 31895 30178 30178 32783 33630 30178 31910 32783 30178 30179 31910 30180 30179 30178 30185 30180 30178 30179 31011 31912 30179 31010 31011 30179 30180 31010 31911 31910 30179 32794 31911 30179 30179 31912 32794 30180 30195 31010 30180 30185 30195 31900 30182 30181 30181 30995 31900 30181 30994 30995 30997 30184 30182 31900 30997 30182 31001 30189 30184 30184 30997 31001 31905 31004 30186 30186 31005 31905 30186 30202 31005 30186 30188 30202 30186 30187 30188 31001 30196 30189 31019 30211 30191 31925 31019 30191 32790 31925 30191 30191 30192 32790 30192 31907 32790 30192 30197 31907 31908 30194 30193 30193 31898 31908 30193 30996 31898 31927 31021 30194 30194 31926 31927 30194 31909 31926 30194 31908 31909 31020 30213 30194 31021 31020 30194 31011 31010 30195 30195 30198 31011 30214 30203 30196 31008 30214 30196 30196 31001 31008 31918 31907 30197 30197 31009 31918 31012 31011 30198 30198 30199 31012 31013 31012 30199 30207 30201 30200 31015 31014 30201 30201 30207 31015 31014 30202 30201 31014 31005 30202 30209 30208 30203 30214 30209 30203 31024 30206 30204 31928 31024 30204 31941 31928 30204 30204 31030 31941 30204 30205 31030 30206 30205 30204 30205 30206 30222 31032 31030 30205 30205 30233 31032 31024 30207 30206 31024 31015 30207 31018 30215 30208 31026 31018 30208 30208 31025 31026 30208 30209 31025 30209 30214 31025 31922 31917 30210 30210 31018 31922 31019 30221 30211 30214 31008 31025 30216 31949 31955 30216 31031 31949 30216 30217 31031 32818 31031 30217 30217 31948 32818 30217 30221 31948 30220 30219 30218 31937 31023 30219 31938 31937 30219 30219 30220 31938 31940 31938 30220 30221 31923 31948 30221 31027 31923 30221 31019 31027 31947 30228 30223 30223 30224 31947 31955 31954 30224 31953 31947 30224 31954 31953 30224 30225 31034 31035 31042 31034 30225 31946 31042 30225 30225 30227 31946 30227 30228 31946 31953 31946 30228 30228 31947 31953 31036 30236 30229 30229 31033 31036 31040 30235 30230 30230 31035 31040 31942 31934 30231 30231 30232 31942 31950 31942 30232 31944 31032 30233 31952 31944 30233 30233 30234 31952 30234 31038 31952 31970 31044 30235 31971 31970 30235 30235 31040 31971 31036 30240 30236 31055 31045 30237 31056 31055 30237 31066 31058 30238 31982 31066 30238 31983 31982 30238 30239 30240 31049 30240 31036 31049 31968 31043 30241 30241 31967 31968 30241 30242 31967 31975 31967 30242 30242 31051 31975 30242 31050 31051 30242 30247 31050 30243 31053 31054 31984 31060 30243 30243 31054 31984 30244 31056 31057 31977 31056 30244 32847 31977 30244 30244 31978 32847 30244 30245 31978 30246 30245 30244 31057 30246 30244 32849 31978 30245 30245 30251 32849 30245 30246 30251 31057 31047 30246 30255 30251 30246 31059 31050 30247 31063 31059 30247 30247 30248 31063 31065 31063 30248 30248 30261 31065 30252 30250 30249 31060 30252 30249 31995 30263 30250 30250 31991 31995 30250 30252 31991 30251 31062 32849 30251 30255 31062 30252 31061 31991 30252 31060 31061 31062 30255 30254 30254 30269 31062 30254 30268 30269 30256 30257 30260 32000 30260 30257 30257 31067 32000 30259 30266 30267 32007 30266 30259 30259 30260 32007 30260 32005 32007 30260 32004 32005 30260 32000 32004 31989 31065 30261 30261 31071 31989 30261 30262 31071 31994 31071 30262 30262 31069 31994 30262 30263 31069 31994 31069 30263 31995 31994 30263 31980 31070 30265 30265 31066 31980 30265 31058 31066 32007 30281 30266 30274 30269 30268 30269 30273 31062 30274 30273 30269 30278 30272 30270 30270 30271 30278 30273 30274 30293 31073 31062 30273 32015 31073 30273 30280 30279 30275 30281 30280 30275 31072 30277 30276 30276 30284 31072 30276 30282 30284 31081 31078 30278 30278 31077 31081 30280 30281 32018 30281 32006 32018 32007 32006 30281 30282 30283 30284 30285 30283 30282 31086 31080 30283 30283 30304 31086 30283 30285 30304 31080 30284 30283 31075 31072 30284 31076 31075 30284 31080 31076 30284 31079 30287 30286 31084 30288 30287 32025 31084 30287 30287 31079 32025 30288 31084 31085 30291 30290 30289 32020 30291 30289 32021 32020 30289 30289 32019 32021 30303 30294 30290 30290 30291 30303 30291 30294 30303 30302 30294 30291 32027 30302 30291 32896 32027 30291 30291 32895 32896 30291 32020 32895 30292 30296 30297 31090 31082 30292 30292 30297 31090 30297 30296 30295 30306 30297 30295 31097 31090 30297 31104 31097 30297 30297 30306 31104 30298 30309 30314 30298 30299 30309 30300 30299 30298 31095 30300 30298 31099 31095 30298 30298 30314 31099 30299 30300 30308 31095 31094 30300 31096 30310 30301 30301 31093 31096 30301 31092 31093 30301 30302 31092 32026 31092 30302 32027 32026 30302 32028 31086 30304 32035 32028 30304 31088 30312 30305 30312 30311 30305 30306 31103 31104 32033 30313 30307 30307 32032 32033 30307 31085 32032 30310 31096 31100 32040 31102 30311 30311 32031 32040 30311 30312 32031 30312 31088 31089 30312 31089 32031 32909 32059 30313 30313 32041 32909 30313 32033 32041 31107 31099 30314 30314 30315 31107 30315 30319 31107 32072 30334 30317 30317 32068 32072 30317 30318 32068 32069 32068 30318 32917 32069 30318 30318 32059 32917 31108 31107 30319 31109 31108 30319 30320 32038 32048 30320 31100 32038 31112 30331 30320 32048 31112 30320 30336 30332 30321 30321 30322 30336 31126 30336 30322 32062 31126 30322 32040 31110 30323 30323 31102 32040 30329 30325 30324 30324 30328 30329 31115 30326 30325 30325 30329 31115 31105 31103 30326 31116 31105 30326 30326 31115 31116 31125 30335 30327 30327 30331 31125 30333 30329 30328 31121 31115 30329 30329 30333 31121 30331 31112 31125 32072 30340 30334 31125 31124 30335 30336 32081 32090 30336 32080 32081 30336 31126 32080 31132 31109 30337 30337 30342 31132 30337 30341 30342 31144 31133 30338 31145 31144 30338 30339 30340 30351 30340 30350 30351 32068 30350 30340 32072 32068 30340 31150 30342 30341 32084 31132 30342 32085 32084 30342 30342 32083 32085 30342 31151 32083 30342 31149 31151 31150 31149 30342 30345 30344 30343 32092 30345 30343 30343 31152 32092 30343 30364 31152 30344 31149 31150 32091 31149 30344 32954 32091 30344 30344 30345 32954 32963 32954 30345 30345 32962 32963 30345 32092 32962 31155 30353 30346 32094 31155 30346 30346 32089 32094 30346 31143 32089 30347 30356 30357 30349 30355 32096 30349 30354 30355 32953 30351 30350 30350 31141 32953 31142 31141 30350 32068 31142 30350 32953 31167 30351 30353 31155 31156 30360 30355 30354 30355 30358 30359 30360 30358 30355 32107 32096 30355 30355 30374 32107 31169 30374 30355 31159 30357 30356 30356 31154 31159 32106 30366 30357 30357 31159 32106 31170 30369 30361 32099 31163 30362 30362 31161 32099 30362 31160 31161 30362 30370 31160 31163 30365 30362 31164 30364 30363 30363 30365 31164 31165 31152 30364 30364 31164 31165 32102 31164 30365 30365 32101 32102 30365 31163 32101 32106 30372 30366 30367 30368 31171 31179 30377 30367 30367 31171 31179 30368 30369 31171 30369 31170 31171 31168 31160 30370 31173 31168 30370 31174 30378 30371 31184 31174 30371 30371 30372 31184 32110 31184 30372 30372 32106 32110 30373 32985 34740 30373 32984 32985 30373 30376 32984 30373 30374 30376 30375 30374 30373 34740 30375 30373 33827 32107 30374 30374 30375 33827 31169 30376 30374 33829 33827 30375 34740 33829 30375 30376 32983 32984 30376 31175 32983 30376 31169 31175 31179 30382 30377 31174 30379 30378 31186 30380 30379 30379 31185 31186 30379 31174 31185 30380 31186 31189 31189 31188 30380 30389 30387 30381 30381 30382 30389 31178 31176 30382 31179 31178 30382 30382 30388 30389 31192 30388 30382 31193 31192 30382 30382 31176 31193 32991 31194 30383 30383 30384 32991 30384 32990 32991 30384 31198 32990 30385 30386 31199 31182 30391 30385 31199 31182 30385 31200 31199 30386 30386 30392 31200 32123 31195 30387 32124 32123 30387 30387 30388 32124 30389 30388 30387 30388 32118 32124 30388 31192 32118 30390 31195 31196 30392 30393 31200 30393 30395 31200 30393 30394 30395 31207 30395 30394 31208 31207 30394 30395 31199 31200 31206 31199 30395 30395 31205 31206 31207 31205 30395 31216 31210 30396 30396 31213 31216 30397 31209 32131 32130 31208 30397 32131 32130 30397 31240 30400 30398 30398 30425 31240 30398 30401 30425 31229 30415 30402 30402 30414 31229 30402 30403 30414 31225 31224 30405 33020 31225 30405 30405 32141 33020 30405 32140 32141 30405 30406 32140 30406 31230 32140 31231 31230 30406 30406 30407 31231 30407 30408 31231 30408 30417 31231 30408 30416 30417 31251 30411 30409 30409 31250 31251 33027 31250 30409 30409 30410 33027 30411 30410 30409 30410 33021 33027 30410 30411 33021 31251 30416 30411 30411 31222 33021 30411 31214 31222 31236 30413 30412 30412 31227 31236 31228 31227 30412 30414 30424 31229 31229 30421 30415 31245 30417 30416 31251 31245 30416 31233 31232 30417 31245 31233 30417 31232 31231 30417 32137 30419 30418 30420 31218 31223 30420 31217 31218 30423 30422 30421 31229 30423 30421 31229 30424 30423 30425 30426 31240 31241 31240 30426 31242 31241 30426 32138 31242 30426 30426 31226 32138 31234 30430 30427 31246 31234 30427 30427 30429 31246 30427 30428 30429 32142 30429 30428 30428 30432 32142 30428 30431 30432 31248 31246 30429 33033 31248 30429 30429 32142 33033 30430 31234 31235 30433 30432 30431 30436 30433 30431 30431 30435 30436 30432 30433 32142 30433 31252 32142 30433 30436 31252 30452 30440 30434 30434 30442 30452 30435 30438 30439 30444 30438 30435 30439 30436 30435 31253 31252 30436 32155 31253 30436 30436 31254 32155 30436 30439 31254 30437 30444 30453 30437 30438 30444 30439 30438 30437 30453 30439 30437 31263 31254 30439 30439 30453 31263 31260 30451 30440 31262 31260 30440 30440 30452 31262 32156 30442 30441 30441 32147 32156 30441 30443 32147 31262 30452 30442 30442 31261 31262 32157 31261 30442 30442 32156 32157 32148 32147 30443 30443 32143 32148 30443 31240 32143 31266 30453 30444 30444 30447 31266 30448 30447 30444 31267 31266 30445 30445 30446 31267 30447 30446 30445 31266 30447 30445 31276 31267 30446 32169 31276 30446 30446 31268 32169 30446 30447 31268 30447 30454 31268 30447 30448 30454 31273 30450 30449 32163 31273 30449 30449 31257 32163 30449 30451 31257 31270 30457 30450 32173 31270 30450 30450 31273 32173 31260 31257 30451 31265 31263 30453 31266 31265 30453 31278 31272 30455 30455 30456 31278 31279 31278 30456 31280 31279 30456 31270 31269 30457 32185 31283 30458 32186 32185 30458 30458 31288 32186 30458 30460 31288 30458 30459 30460 30460 30468 31287 30460 30465 30468 30460 31287 31288 33117 32202 30461 30461 33112 33117 30461 30462 33112 30462 32187 33112 30464 30467 31290 31296 31290 30467 30467 30472 31296 32195 31287 30468 32196 32195 30468 30468 31291 32196 30468 30469 31291 30470 30471 30473 31307 31296 30472 30473 30477 31294 30487 30480 30474 30474 30475 30487 30474 31311 31312 32218 31311 30474 32242 32218 30474 30474 32231 32242 30474 31310 32231 30474 30480 31310 30475 30480 30487 30476 30481 30482 32217 31294 30477 30477 32207 32217 30477 32202 32207 30482 30481 30478 30483 30482 30478 31302 30483 30478 30478 30488 31302 30479 30484 31304 31302 30493 30483 30484 31298 31304 32232 31306 30485 30485 30486 32232 32233 32232 30486 30486 31300 32233 30488 30489 31302 30489 30493 31302 30495 30493 30489 31309 31305 30490 31330 31328 30491 30491 30494 31330 30492 31321 31322 30494 30510 31330 30496 30497 31344 31343 30508 30496 31344 31343 30496 30497 30509 31344 30497 30498 30509 30500 30499 30498 30498 30499 30509 31356 30509 30499 31357 31356 30499 32273 31357 30499 30502 31319 31320 33160 31319 30502 30502 32250 33160 32251 32250 30502 30502 30503 32251 32287 32251 30503 30504 30505 30511 30506 30505 30504 30507 30506 30504 30512 30511 30505 31340 30512 30505 30505 30506 31340 31342 31340 30506 30506 30507 31342 30507 30508 31342 31343 31342 30508 32269 31352 30509 32272 32269 30509 30509 31356 32272 31352 31344 30509 31346 31330 30510 30510 30513 31346 31377 30514 30511 30511 31362 31377 30511 30512 31362 31363 31362 30512 32258 31363 30512 30512 31340 32258 32270 31346 30513 32282 32270 30513 30514 30518 30521 30519 30518 30514 31377 30519 30514 32276 31364 30515 30516 31313 31345 31314 31313 30516 32243 31314 30516 30516 31308 32243 30517 30531 30532 30533 30531 30517 31386 30521 30518 30518 31378 31386 31379 31378 30518 31385 31379 30518 30518 30519 31385 30519 31377 31385 31386 30527 30520 30520 30521 31386 30522 30523 31367 32300 31367 30523 30523 30524 32300 30524 31380 32300 31370 31368 30525 30541 30534 30526 30545 30541 30526 31394 30545 30526 31395 31394 30526 31387 30536 30527 30527 31386 31387 31390 30530 30529 30532 30531 30530 31391 30532 30530 30530 31390 31391 32306 31392 30532 30532 31391 32306 30541 30540 30534 31409 30539 30537 30537 30546 31409 30547 30546 30537 31407 30547 30537 30537 31393 31407 30559 30558 30538 30538 30548 30559 30550 30548 30538 30538 30539 30550 31409 30550 30539 31416 30566 30540 31417 31416 30540 30540 30541 31417 30541 30544 31417 30545 30544 30541 30542 31388 31389 32289 31388 30542 33208 32289 30542 30542 30543 33208 33216 33208 30543 33229 33216 30543 30543 32320 33229 31425 31417 30544 32314 31425 30544 30544 30545 32314 30545 32307 32314 30545 31394 32307 33224 31409 30546 33225 33224 30546 34065 33225 30546 30546 30547 34065 34972 34065 30547 30547 33221 34972 34064 33221 30547 30547 33223 34064 33237 33223 30547 30547 31407 33237 30548 30551 30559 30548 30549 30551 30550 30549 30548 30553 30551 30549 31410 30553 30549 32319 31410 30549 30549 30550 32319 30550 31408 32319 31409 31408 30550 30551 30555 30559 30551 30552 30555 30553 30552 30551 30561 30560 30552 30562 30561 30552 30552 30553 30562 30560 30555 30552 31411 30562 30553 31412 31411 30553 30553 31410 31412 30554 30590 31423 30554 30563 30590 30555 30556 30559 30557 30556 30555 30560 30557 30555 30567 30559 30556 30583 30567 30556 30556 30557 30583 31449 30583 30557 31466 31449 30557 30557 31453 31466 32341 31453 30557 30557 30569 32341 30557 30561 30569 30557 30560 30561 30558 30559 30567 30561 30562 30569 31413 30569 30562 30562 31411 31413 30563 30564 30590 30564 30565 30590 30565 30577 30590 31431 30577 30565 30565 30571 31431 31416 30572 30566 30567 30583 30584 30584 30583 30568 30569 32335 32341 30569 31413 32335 30570 30586 31429 30571 30576 31431 30579 30576 30571 30572 31416 31424 31424 30580 30572 32348 31441 30573 32349 32348 30573 30573 31460 32349 30573 30574 31460 30574 30582 31460 30577 30576 30575 30591 30577 30575 30575 30578 30591 30576 30577 31431 30591 30590 30577 32337 30591 30578 30578 32327 32337 30578 31430 32327 31426 30592 30580 30580 31424 31426 31459 30603 30581 31465 31460 30582 30582 30597 31465 30582 30593 30597 30598 30585 30583 31449 30598 30583 30598 30594 30585 32325 31429 30586 30586 31468 32325 30586 30587 31468 30587 31467 31468 30587 30588 31467 30588 30595 31467 30590 31422 31423 30590 30591 31422 32337 31422 30591 31463 30606 30592 30592 31454 31463 30592 31426 31454 31477 30597 30593 32369 31467 30595 32362 32347 30596 30596 30599 32362 31477 31465 30597 32367 32362 30599 34119 32367 30599 30599 33283 34119 30599 32391 33283 30599 31525 32391 30599 30600 31525 30600 30608 30625 30600 30625 31525 31506 30621 30601 30601 30604 31506 30601 30602 30604 31474 30604 30602 30602 30603 31474 30603 31459 31474 32377 31506 30604 32378 32377 30604 30604 31474 32378 30618 30607 30606 31461 30618 30606 31462 31461 30606 31463 31462 30606 30612 30611 30609 32374 30612 30609 30609 31500 32374 30609 31478 31500 30609 30610 31478 30629 30628 30611 30611 30622 30629 30611 30612 30622 32389 30622 30612 30612 31529 32389 33295 31529 30612 30612 32373 33295 32374 32373 30612 30613 30623 31483 30613 30615 30623 31501 31479 30613 30613 31483 31501 30615 30616 30623 31483 30623 30616 30616 31480 31483 31486 31480 30616 31492 30624 30617 30617 30618 31492 30618 31461 31492 30619 30620 31525 31525 30625 30619 30620 30631 31525 30621 31506 32379 32389 30629 30622 31492 31488 30624 31533 30630 30624 30624 31486 31533 31488 31486 30624 31516 30636 30626 30627 30633 31518 32394 30633 30628 30628 30629 32394 30629 32389 32394 31533 30634 30630 30631 30635 31526 31526 31525 30631 30632 30636 30637 32394 31518 30633 31533 31532 30634 31532 30642 30634 30635 30648 31535 30635 30643 30648 31535 31526 30635 30638 30637 30636 31527 30638 30636 32392 31527 30636 30636 32388 32392 30636 31516 32388 30637 30638 31536 32393 31536 30638 30638 31527 32393 31533 31486 30640 31534 31533 30640 30640 31520 31534 31532 30651 30641 31537 31532 30641 31542 31537 30641 30641 30652 31542 30647 30645 30642 31543 30647 30642 30642 30652 31543 31542 30652 30642 30642 31539 31542 30642 31538 31539 30642 31532 31538 31541 30648 30643 30643 31540 31541 30647 30646 30645 30646 30647 31570 30646 32413 32414 30646 31570 32413 30647 31543 31549 30647 31549 31570 30650 30649 30648 31541 30650 30648 30648 30649 31535 30649 30650 33310 30649 31525 31535 32391 31525 30649 33310 32391 30649 33313 33310 30650 30650 31545 33313 30650 31540 31545 31541 31540 30650 31532 31520 30651 30652 30653 31543 31549 31543 30653 30665 30656 30655 30656 30665 31551 30657 31560 31573 30657 30658 31560 31561 31560 30658 31556 30664 30660 30660 31555 31556 30660 30661 31555 31559 31555 30661 30661 30662 31559 32419 31552 30663 30663 31562 32419 31563 30666 30664 30664 31556 31563 31572 31551 30665 32423 31572 30665 32425 32423 30665 33325 32425 30665 30665 32417 33325 31563 31558 30666 32432 30672 30666 30666 31558 32432 30667 30668 32406 32409 31568 30667 30667 32404 32409 30667 32403 32404 32406 32403 30667 30668 31567 32406 30668 31564 31567 30668 30684 31564 31582 31580 30670 30671 30672 32432 32447 30673 30671 30671 32439 32447 30671 32432 32439 32447 30677 30673 31568 30676 30674 30676 30675 30674 31592 30679 30675 30675 30676 31592 30676 31569 32434 30676 31568 31569 32429 31592 30676 32434 32429 30676 31590 31584 30677 30677 31576 31590 32438 31576 30677 32448 32438 30677 30677 32447 32448 32440 30684 30678 30678 31585 32440 30678 30685 31585 31592 30687 30679 30682 30681 30680 31593 30682 30680 31595 31593 30680 30680 30688 31595 30680 30681 30688 30682 31594 32411 30682 31593 31594 30683 31587 31589 30683 31579 31587 31566 31564 30684 32440 31566 30684 30685 30692 31585 30695 30691 30686 30696 30695 30686 30686 30690 30696 32455 31586 30687 30687 31591 32455 31592 31591 30687 30688 30689 31595 30689 30697 31595 31598 30696 30690 30692 30693 31585 31600 31585 30693 30693 30702 31600 33344 32474 30694 30694 32454 33344 30694 31589 32454 31596 31595 30697 30698 30699 31609 30700 30699 30698 30714 30700 30698 30719 30714 30698 31608 30719 30698 31609 31608 30698 30699 30701 31609 32472 31609 30701 30701 31597 32472 31604 31600 30702 30702 30703 31604 31605 31604 30703 30710 30707 30705 30711 30710 30705 30705 30706 30711 31603 30711 30706 30706 30715 31603 30707 30710 31601 32484 31612 30708 30708 30724 32484 30709 30712 30716 30710 30711 31603 31613 30716 30712 30712 30713 31613 31615 31613 30713 30713 30717 31615 31613 30726 30716 31619 31615 30717 30718 31622 31623 32485 31622 30718 30718 32479 32485 30718 30719 32479 30719 31611 32479 30719 31608 31611 30723 30722 30721 31624 30723 30721 31627 31624 30721 30721 30730 31627 30721 30729 30730 33378 32482 30722 30722 30723 33378 30723 32500 33378 30723 31624 32500 30724 32483 32484 30724 30725 32483 32493 30733 30726 32494 32493 30726 30726 31613 32494 30735 30728 30727 31634 30735 30727 30727 31621 31634 31623 31621 30727 30728 30735 30740 30730 30745 31627 31630 31628 30731 30731 30732 31630 30732 31629 31630 30732 30736 31629 31632 30738 30733 31633 31632 30733 32493 31633 30733 32504 31620 30734 32506 32504 30734 30734 30748 32506 31634 30740 30735 30736 30737 31629 30737 30747 31629 32513 30744 30738 30738 31632 32513 30749 30748 30739 31643 30749 30739 31641 30751 30740 32525 31641 30740 33389 32525 30740 30740 32507 33389 30740 31636 32507 30740 31634 31636 30741 30742 30746 30743 30742 30741 31628 30743 30741 32519 30746 30742 30742 32509 32519 30742 30743 32509 34243 32509 30743 30743 32496 34243 30743 31628 32496 32526 30753 30744 32527 32526 30744 30744 32513 32527 32501 31627 30745 30745 31637 32501 30746 32530 32531 30746 30755 32530 30757 30755 30746 33394 30757 30746 30746 32519 33394 32531 31642 30746 31640 31638 30747 30747 30752 31640 31638 31629 30747 30748 30749 32515 32515 32506 30748 30749 31643 32515 31641 30754 30750 30750 30751 31641 30752 30758 31640 32526 30764 30753 31646 31645 30754 32522 31646 30754 30754 31641 32522 30757 30756 30755 30755 30762 32530 30755 30761 30762 33386 31637 30756 33391 33386 30756 30756 30757 33391 33393 33391 30757 33394 33393 30757 30758 31647 31648 30758 30759 31647 30758 31639 31640 31648 31639 30758 31653 31647 30759 32535 31653 30759 30759 30764 32535 30759 30760 30764 30762 31650 32530 30764 32532 32535 30764 32526 32532 32536 31655 30765 30765 31654 32536 30767 30771 31657 32536 31654 30768 32540 32536 30768 30768 31656 32540 30771 30770 30769 31657 30771 30769 30773 30772 30770 30774 30773 30770 30770 30771 30774 32543 30774 30771 30772 30779 30781 30780 30779 30772 30772 30773 30780 32562 30780 30773 30773 32549 32562 30773 30774 32549 30774 32541 32542 32543 32541 30774 30774 32548 32549 33409 32548 30774 33418 33409 30774 34282 33418 30774 30774 34274 34282 30774 32542 34274 30777 30776 30775 32561 30777 30775 30775 30788 32561 30775 30776 30788 30776 30778 30788 32546 31658 30777 32561 32546 30777 30785 30781 30779 30786 30785 30779 30779 30780 30786 32562 30786 30780 30790 30789 30782 30783 31670 31671 30783 30789 31670 30783 30784 30789 32563 30787 30786 30786 32562 32563 30787 31665 31677 32550 31665 30787 32563 32550 30787 32568 32561 30788 30789 31669 31670 30789 30790 31669 31679 31669 30790 31680 31679 30790 30791 30792 31672 30793 30792 30791 30799 30793 30791 30791 30797 30799 33430 31672 30792 30792 30793 33430 31682 31681 30793 33431 33430 30793 30793 32577 33431 30793 31681 32577 31684 30800 30794 30794 31676 31684 31677 31676 30794 30795 30796 30810 31687 30810 30796 32582 31687 30796 30796 32575 32582 30797 30798 30799 31684 30803 30800 30802 30805 31694 31692 30809 30802 31694 31692 30802 30803 31685 31695 30803 31673 31685 31684 31673 30803 31694 30805 30804 30808 30807 30806 30817 30815 30807 31700 30817 30807 30807 31696 31700 30807 30808 31696 31697 31696 30808 30808 31688 31697 30808 31687 31688 30808 30810 31687 30809 31692 31693 32584 31683 30811 30811 32579 32584 34304 32579 30811 30811 33457 34304 30811 32597 33457 30811 31699 32597 30811 30812 31699 31704 31703 30813 30813 30827 31704 30817 30816 30815 30824 30823 30816 31702 30824 30816 30816 30817 31702 30817 31700 31702 30818 30819 30825 30828 30825 30819 31703 30828 30819 31721 30853 30820 30820 30857 31721 30820 30821 30857 30822 30821 30820 30821 30848 30857 30849 30848 30821 30850 30849 30821 30851 30850 30821 30821 30822 30851 30823 32602 32608 30823 30824 32602 32607 30830 30823 32608 32607 30823 30824 31702 32602 31722 31712 30825 32609 31722 30825 30825 31703 32609 30825 30828 31703 30827 30829 31704 30829 30837 31723 32609 31704 30829 30829 31725 32609 30829 31723 31725 30836 30835 30830 32607 30836 30830 31722 30833 30831 30831 30832 31722 30832 31712 31722 30833 31724 31728 30833 31722 31724 32618 31735 30835 30835 32606 32618 30835 30836 32606 30836 32605 32606 32607 32605 30836 30839 32627 33481 30840 30841 30861 30842 30841 30840 30855 30842 30840 30861 30855 30840 30841 30847 30856 30841 30842 30847 30841 30856 30861 30842 30843 30847 30845 30843 30842 30855 30845 30842 31715 30846 30843 30843 31710 31715 31711 31710 30843 31713 31711 30843 30843 30844 31713 30845 30844 30843 31720 31713 30844 30844 30845 31720 31729 31720 30845 31730 31729 30845 31732 31730 30845 30845 30855 31732 31715 31714 30846 31714 30848 30846 31714 30857 30848 30853 31698 31699 30853 30857 31698 31721 30857 30853 30855 30861 31732 30862 30861 30856 30867 30862 30856 31716 31698 30857 30857 31714 31716 32621 30863 30858 30858 31735 32621 31738 30860 30859 30859 30864 31738 31731 30872 30860 31738 31731 30860 31734 31732 30861 30861 31733 31734 32638 31733 30861 30861 31743 32638 30861 30871 31743 30861 30862 30871 30862 30867 30871 32621 30868 30863 30864 31737 31738 31744 31737 30864 30865 32631 33484 30866 31739 31740 30868 32621 32630 32633 30870 30868 30868 32630 32633 30869 30870 30876 30876 30875 30869 32633 30876 30870 30871 30873 31743 30872 31747 31748 30872 31746 31747 30872 31731 31746 30874 30877 31750 30875 30876 31755 32639 31755 30876 30876 32632 32639 32633 32632 30876 31753 31750 30877 30877 30878 31753 30879 31755 32654 32661 31759 30881 33507 32661 30881 31775 30883 30882 30882 31764 31775 31765 31764 30882 32666 31776 30883 30883 31775 32666 31776 30884 30883 31777 30886 30885 31783 31777 30885 32667 31792 30887 30887 31780 32667 33519 31774 30889 30889 32680 33519 30889 30890 32680 30889 31778 31779 30889 31774 31778 31792 31787 30891 31786 30905 30891 31787 31786 30891 31790 30893 30892 30892 30899 31790 32670 31783 30893 32679 32670 30893 30893 31790 32679 33541 31791 30894 30894 31793 33541 30894 30895 31793 30895 30910 31793 30896 30898 30899 30906 30898 30896 30899 30898 30897 32689 30899 30897 33533 32689 30897 30897 31795 33533 30897 30898 31795 30898 30906 31795 32689 31790 30899 30902 30901 30900 32699 31803 30901 30901 31801 32699 30901 30903 31801 30901 30902 30903 32687 30903 30902 31802 31801 30903 33536 31802 30903 30903 32687 33536 32688 31789 30904 30904 31791 32688 32686 31794 30905 30905 32685 32686 30905 31786 32685 32694 31795 30906 30906 30908 32694 30906 30907 30908 33550 30908 30907 30907 33543 33550 30907 32698 33543 33550 32694 30908 31799 31796 30909 32700 31799 30909 31800 31793 30910 32702 31800 30910 30910 31806 32702 31805 30915 30911 30912 30913 30917 30914 30913 30912 30916 30914 30912 31798 30916 30912 30920 30917 30913 30913 30914 30920 31813 30920 30914 31817 31813 30914 30914 30916 31817 31808 30919 30915 31816 31808 30915 33554 31816 30915 30915 32703 33554 32704 32703 30915 30915 31814 32704 31815 31814 30915 30915 31805 31815 32708 31817 30916 30916 31797 32708 31798 31797 30916 30917 30920 30921 30918 30919 31807 31808 31807 30919 31813 30921 30920 31813 30922 30921 32707 32705 30922 30922 31813 32707 32705 31818 30922 31822 30925 30924 31831 30941 30925 30925 31829 31831 30925 31822 31829 34470 33551 30926 30926 31827 34470 30930 30929 30927 30927 30928 30930 31819 30930 30928 30929 31824 31830 30929 30930 31824 31825 31824 30930 30930 31823 31825 30930 31819 31823 32726 32725 30931 30931 30932 32726 30933 30932 30931 31837 30933 30931 32724 31837 30931 32725 32724 30931 30932 30934 32726 31837 31835 30933 30934 32725 32726 32732 32725 30934 30934 30935 32732 30935 30936 32732 33575 32732 30936 30936 30939 33575 33577 30940 30937 30937 32733 33577 30937 30938 32733 30938 31843 32733 33576 33575 30939 30939 30940 33576 33577 33576 30940 31831 30946 30941 32737 30948 30942 32738 32737 30942 30942 31845 32738 31844 31838 30943 30943 30951 31844 30944 30945 30953 30945 30952 30953 32722 30952 30945 30945 32721 32722 30946 31831 31850 33574 32729 30947 33587 33574 30947 33588 33587 30947 30947 32737 33588 30947 30948 32737 30949 31836 31841 31848 30951 30950 30950 30954 31848 31849 31844 30951 30951 31848 31849 32745 30954 30952 30952 31857 32745 30952 31856 31857 33590 31856 30952 30952 32728 33590 30952 32722 32728 32744 31848 30954 32745 32744 30954 30955 31852 31873 30955 31851 31852 30955 31850 31851 30956 30957 30968 30957 30967 30968 30958 30971 31863 30958 30959 30971 30960 30959 30958 31863 30960 30958 30972 30971 30959 31866 30972 30959 32749 31866 30959 30959 31855 32749 30959 30960 31855 30968 30967 30960 31863 30968 30960 32747 31855 30960 32748 32747 30960 30960 30967 32748 31859 30966 30961 30961 30969 31859 30964 30963 30962 30965 30964 30962 30963 31854 32752 30963 30964 31854 32752 32751 30963 31860 31854 30964 31861 31860 30964 31862 31861 30964 30964 30965 31862 30965 30966 31862 30966 31859 31862 30967 31853 32748 30968 31863 31865 31864 31859 30969 33603 31864 30969 35402 33603 30969 30969 34514 35402 30969 32758 34514 30969 31870 32758 30969 30970 31870 30970 30973 31870 31865 31863 30971 32768 31865 30971 30971 32767 32768 34519 32767 30971 30971 32760 34519 30971 30972 32760 30972 32754 32760 30972 31866 32754 30973 31869 31870 30973 30981 31869 30986 30985 30974 31892 30986 30974 30974 31881 31892 30974 30975 31881 31883 31881 30975 31879 30978 30976 30976 30977 31879 31889 31879 30977 30977 31887 31889 30977 30982 31887 30980 30983 30989 31877 31869 30981 30981 31876 31877 30981 30988 31876 30981 30987 30988 31897 30989 30983 32771 31897 30983 30983 30984 32771 33626 32771 30984 30984 31890 33626 30992 30990 30985 30985 30986 30992 31893 30992 30986 30986 31892 31893 31896 30988 30987 32772 31876 30988 33630 32772 30988 30988 31895 33630 31899 31895 30988 30988 31896 31899 31897 30994 30989 30990 30991 30996 30992 30991 30990 30991 30992 31893 31901 30996 30991 30991 31893 31901 31897 30995 30994 32777 31900 30995 32778 32777 30995 30995 31897 32778 31902 31898 30996 30996 31901 31902 31007 31001 30997 32779 31007 30997 30997 30998 32779 30999 30998 30997 31900 30999 30997 30998 30999 33635 32780 32779 30998 33635 32780 30998 30999 32777 33633 30999 31900 32777 30999 33633 33635 31001 31007 31008 31913 31013 31002 31914 31913 31002 32785 31914 31002 31002 31903 32785 31002 31003 31903 31003 31004 31903 32786 31903 31004 31004 31904 32786 31905 31904 31004 31906 31905 31005 31915 31906 31005 31005 31014 31915 32787 31920 31007 31007 32779 32787 31920 31008 31007 31921 31025 31008 31008 31016 31921 31017 31016 31008 31920 31017 31008 31009 31916 31918 31011 31012 31912 31012 31013 31912 32794 31912 31013 31013 31913 32794 31014 31015 31915 31919 31915 31015 31015 31029 31919 31015 31024 31029 32810 31921 31016 31016 32804 32810 32806 32804 31016 31016 31017 32806 31017 31920 32806 31018 31026 31922 31925 31027 31019 31020 31021 31028 31927 31028 31021 31023 31937 31943 31928 31029 31024 31929 31026 31025 31025 31921 31929 31931 31922 31026 32813 31931 31026 31026 32812 32813 31026 31929 32812 31925 31923 31027 31028 31935 31936 31028 31927 31935 31028 31936 31939 32800 31919 31029 32817 32800 31029 31029 31928 32817 31945 31941 31030 31030 31944 31945 31030 31032 31944 31956 31949 31031 32818 31956 31031 31037 31036 31033 31951 31037 31033 31041 31035 31034 31042 31041 31034 31041 31040 31035 31036 31037 31049 31961 31049 31037 31037 31959 31961 31037 31943 31959 31951 31943 31037 31038 31039 31952 31960 31952 31039 31969 31960 31039 31039 31968 31969 31039 31043 31968 31040 31042 31971 31040 31041 31042 33684 31971 31042 31042 32827 33684 31042 31946 32827 31976 31053 31044 31044 31970 31976 31055 31046 31045 31046 31055 31977 33676 31950 31046 31046 32843 33676 31046 31977 32843 31057 31056 31047 31049 31961 31962 31052 31051 31050 31059 31052 31050 31051 31974 31975 31051 31052 31974 31052 31972 31974 31973 31972 31052 31052 31059 31973 31976 31054 31053 31054 31976 31984 31055 31056 31977 31059 31064 31973 31059 31063 31064 31984 31061 31060 31061 31984 31991 31062 31074 32849 31062 31073 31074 31068 31064 31063 31063 31065 31068 31064 31068 31986 31986 31973 31064 31986 31068 31065 31987 31986 31065 31989 31987 31065 31066 31979 31980 31982 31979 31066 31067 31999 32000 31067 31998 31999 32002 31998 31070 32003 32002 31070 31070 31992 32003 31070 31980 31992 31993 31989 31071 31994 31993 31071 31072 31075 31077 33750 31074 31073 34631 33750 31073 34648 34631 31073 35507 34648 31073 31073 35481 35507 35482 35481 31073 31073 33789 35482 31073 32014 33789 32015 32014 31073 31074 32848 32849 32855 32848 31074 32865 32855 31074 33725 32865 31074 33750 33725 31074 31075 31076 31077 31087 31077 31076 31076 31080 31087 31087 31081 31077 32032 32025 31079 31079 32024 32032 31079 31091 32024 31079 31083 31091 31080 31086 32022 32023 31087 31080 32029 32023 31080 31080 32022 32029 31089 31088 31081 31081 31087 31089 31091 31083 31082 31082 31090 31091 31084 32025 32032 32032 31085 31084 32028 32022 31086 32023 31089 31087 31089 32023 32031 31098 31091 31090 31090 31097 31098 31091 31098 32024 32034 31093 31092 31092 32026 32034 32034 31096 31093 31094 31095 32905 33787 32014 31094 33788 33787 31094 31094 33786 33788 31094 32905 33786 31095 31099 32905 32049 31100 31096 31096 32034 32049 31097 31111 32056 31097 31104 31111 32056 31098 31097 32036 32024 31098 32056 32036 31098 33786 32905 31099 31099 32042 33786 32043 32042 31099 32918 32043 31099 31099 32910 32918 31099 32045 32910 31099 31107 32045 32058 32038 31100 31100 32050 32058 31100 32049 32050 31106 31104 31103 31103 31105 31106 31104 31106 31111 31105 31116 31118 32064 31106 31105 31105 31117 32064 31118 31117 31105 32063 31111 31106 32064 32063 31106 32919 32047 31107 31107 32057 32919 31107 31108 32057 31107 32044 32045 32047 32044 31107 32929 32057 31108 32931 32929 31108 31108 31132 32931 31108 31109 31132 32924 32061 31110 31110 32040 32924 32916 32056 31111 31111 32063 32916 31153 31125 31112 33792 31153 31112 33800 33792 31112 31112 32920 33800 31112 32048 32920 32060 31114 31113 33801 32060 31113 31113 32933 33801 32934 32933 31113 31113 32070 32934 31113 31120 32070 31113 31119 31120 31114 32921 32922 31114 32060 32921 32922 32051 31114 31122 31116 31115 31123 31122 31115 31115 31121 31123 31137 31130 31116 31116 31131 31137 31116 31122 31131 31130 31118 31116 32071 32064 31117 31117 31118 32071 31118 31130 32071 31120 31133 32070 31122 31127 31131 31122 31123 31127 31135 31127 31123 31123 31134 31135 32089 31143 31124 32959 32089 31124 31124 32094 32959 31124 32076 32094 31124 32075 32076 31124 31153 32075 31124 31125 31153 31126 32062 32080 31147 31131 31127 31127 31128 31147 31129 31128 31127 31135 31129 31127 32086 31147 31128 33818 32086 31128 31128 31136 33818 31128 31129 31136 33816 31136 31129 31129 33815 33816 33821 33815 31129 31129 32948 33821 31129 31146 32948 31129 31135 31146 31130 31137 32071 31147 31137 31131 31132 32084 32931 31133 31144 32070 33822 33818 31136 34722 33822 31136 31136 33830 34722 31136 32989 33830 33816 32989 31136 31137 31139 32071 31148 31139 31137 31137 31147 31148 33823 32087 31138 34725 33823 31138 31138 34723 34725 31138 33817 34723 31138 31139 33817 31140 31139 31138 32087 31140 31138 31139 32067 32071 32082 32067 31139 32952 32082 31139 31139 31140 32952 31139 32086 33817 31139 31148 32086 31140 32087 33808 31140 32939 32952 33808 32939 31140 31141 32938 32953 32939 32938 31141 32943 32939 31141 31141 32937 32943 31141 31142 32937 31142 32068 32073 31142 32073 32937 32078 32070 31144 31144 31158 32078 31144 31145 31158 31145 31157 31158 31145 31156 31157 32086 31148 31147 32088 31151 31149 32091 32088 31149 33819 32083 31151 34716 33819 31151 31151 32973 34716 31151 32100 32973 31151 32088 32100 32956 32955 31152 31152 31165 32956 32955 32092 31152 33792 32075 31153 32940 31159 31154 32941 32940 31154 31166 31156 31155 32967 31166 31155 31155 32093 32967 32094 32093 31155 31166 31157 31156 32968 32960 31157 31157 31166 32968 32960 31158 31157 31158 32077 32078 32960 32077 31158 33826 32106 31159 33835 33826 31159 31159 32965 33835 31159 32940 32965 31162 31161 31160 31168 31162 31160 31161 32098 32099 31161 31162 32098 31162 31168 32098 32099 32091 31163 32962 32101 31163 32963 32962 31163 31163 32954 32963 31163 32091 32954 32102 31165 31164 31165 32102 32956 31166 32967 32968 32961 32108 31167 31167 32953 32961 32109 32098 31168 31168 31173 32109 31172 31171 31170 32111 31172 31170 32112 32111 31170 31171 31178 31179 31171 31172 31178 32980 31178 31172 31172 32111 32980 31187 31185 31174 32113 31187 31174 31174 31183 32113 31184 31183 31174 31175 31190 32983 31175 31189 31190 31175 31188 31189 31178 31177 31176 32986 31193 31176 32987 32986 31176 31176 31177 32987 31177 32980 33831 31177 31178 32980 33836 32987 31177 31177 33831 33836 31180 32098 32109 32973 32098 31180 33832 32973 31180 33833 33832 31180 33837 33833 31180 31180 31181 33837 31182 31181 31180 33841 33837 31181 33842 33841 31181 31181 32121 33842 32122 32121 31181 31181 31203 32122 31181 31199 31203 31181 31182 31199 32978 32113 31183 32979 32978 31183 31183 32976 32979 31183 31184 32976 31184 32110 32976 31187 31186 31185 31190 31189 31186 31191 31190 31186 32119 31191 31186 31186 32115 32119 31186 32114 32115 31186 31187 32114 31187 32113 32114 31190 31191 32995 33845 32983 31190 31190 32995 33845 33855 32995 31191 31191 32119 33855 32986 32118 31192 31192 31193 32986 32992 32126 31194 31194 32991 32992 31201 31196 31195 32125 31201 31195 31195 32123 32125 32125 31197 31196 31196 31201 32125 32990 31198 31197 32998 32990 31197 31197 32997 32998 31197 32125 32997 31206 31203 31199 31221 31212 31202 32126 31221 31202 31203 31206 32122 31204 31205 33000 31206 31205 31204 32122 31206 31204 32999 32122 31204 33000 32999 31204 31205 31208 33000 31205 31207 31208 31208 32130 33000 31209 31210 32131 32133 32131 31210 31210 31216 32133 31221 31214 31211 31211 31212 31221 31213 31215 31216 31219 31215 31213 31214 31221 31222 31218 31217 31215 31223 31218 31215 32132 31216 31215 31215 31217 32132 31216 32132 32133 32137 32132 31217 31222 31221 31220 33887 31222 31220 31220 33886 33887 31220 33008 33886 31220 32126 33008 31220 31221 32126 33032 33021 31222 33887 33032 31222 31224 31225 31226 32138 31226 31225 33024 32138 31225 33025 33024 31225 33026 33025 31225 31225 33020 33026 31237 31236 31227 31239 31237 31227 32134 31239 31227 31227 31228 32134 32139 32134 31228 31230 31231 31232 31230 31243 32140 31230 31232 31243 31244 31243 31232 31232 31233 31244 32154 31244 31233 31233 31249 32154 31250 31249 31233 31251 31250 31233 31233 31245 31251 31247 31235 31234 31234 31246 31247 31235 31247 32139 31236 31237 32137 33884 33017 31237 31237 31238 33884 31239 31238 31237 33017 32137 31237 31238 32136 33884 31238 32135 32136 33013 32135 31238 31238 31239 33013 33015 33013 31239 31239 32134 33015 32144 32143 31240 31240 31241 32144 33028 32144 31241 33030 33028 31241 31241 31242 33030 31242 33023 33030 31242 33022 33023 31242 32138 33022 32150 32141 31243 31243 31244 32150 32141 32140 31243 31244 32149 32150 31244 32145 32149 32146 32145 31244 32154 32146 31244 31248 31247 31246 33036 32139 31247 31247 33034 33036 33035 33034 31247 31247 31248 33035 31248 33033 33035 32167 32154 31249 33076 32167 31249 31249 32152 33076 32153 32152 31249 31249 31250 32153 33043 32153 31250 33905 33043 31250 31250 33027 33905 33044 32142 31252 31252 31253 33044 33062 33044 31253 31253 32155 33062 32162 32155 31254 31254 31255 32162 31256 31255 31254 31263 31256 31254 32168 32162 31255 32174 32168 31255 31255 31256 32174 32176 32174 31256 32180 32176 31256 31256 31263 32180 33056 32163 31257 33057 33056 31257 31257 31258 33057 31260 31258 31257 33913 33057 31258 31258 31259 33913 31260 31259 31258 33914 33913 31259 31259 33058 33914 31259 31261 33058 31259 31260 31261 31262 31261 31260 31261 32157 33058 31263 31274 32180 31263 31264 31274 31265 31264 31263 31275 31274 31264 31264 31267 31275 31264 31265 31267 31265 31266 31267 31276 31275 31267 31268 31271 32169 31284 31281 31269 33065 31284 31269 31269 31270 33065 31270 32173 33065 32172 32169 31271 31271 31272 32172 32178 32172 31272 31272 31278 32178 33054 32173 31273 31273 32163 33054 31274 31275 31277 33098 32180 31274 31274 32181 33098 31274 31277 32181 31275 31276 31277 32177 31277 31276 32192 32177 31276 31276 32171 32192 31276 32169 32171 32182 32181 31277 31277 32177 32182 33092 32178 31278 31278 32179 33092 31278 31279 32179 31279 31280 32179 32183 32179 31280 31280 31282 32183 33099 32184 31281 31281 31284 33099 33103 32183 31282 31282 32185 33103 31282 31283 32185 31284 31285 33099 31286 31285 31284 33921 31286 31284 31284 33065 33921 34867 33099 31285 35686 34867 31285 31285 34866 35686 31285 31286 34866 31286 34862 34866 31286 34854 34862 31286 33064 34854 33921 33064 31286 32195 31289 31287 31289 31288 31287 31288 31289 32186 33127 32186 31289 31289 32195 33127 32223 32196 31291 32211 31301 31292 31292 32210 32211 31292 31293 32210 31293 31296 32210 32217 31295 31294 32233 31300 31295 31295 32217 32233 31296 32208 32210 31296 31307 32208 31299 31298 31297 32226 31299 31297 32239 32226 31297 31297 31305 32239 31298 31303 31304 31298 31299 31303 32238 31303 31299 33142 32238 31299 31299 31318 33142 32226 31318 31299 31301 32211 32219 32243 31308 31301 33141 32243 31301 31301 32219 33141 32206 31304 31303 32225 32206 31303 32238 32225 31303 31305 31309 32239 32232 31310 31306 32209 32208 31307 33129 32209 31307 31307 32234 33129 31309 31318 32239 31319 31318 31309 31320 31319 31309 31310 32230 32231 32232 32230 31310 31311 32218 32234 31313 31314 33999 32252 31345 31313 33168 32252 31313 33999 33168 31313 31314 32243 33151 31314 33151 33999 32237 31339 31315 32245 32237 31315 31315 32236 32245 31315 32235 32236 31315 31316 32235 31317 31316 31315 31339 31317 31315 31316 32221 32235 31316 31337 32221 31316 31324 31337 31316 31323 31324 31316 31317 31323 31339 31323 31317 33153 33142 31318 31318 31319 33153 31318 32226 32239 33160 33153 31319 31331 31322 31321 31322 31331 31347 31338 31326 31323 31339 31338 31323 31326 31324 31323 31324 31334 31337 31335 31334 31324 31348 31335 31324 31324 31332 31348 31333 31332 31324 31324 31325 31333 31326 31325 31324 31325 31326 31361 31353 31333 31325 31374 31353 31325 31375 31374 31325 31376 31375 31325 31325 31361 31376 31326 31338 31354 31326 31354 31361 31329 31328 31327 33162 31329 31327 33163 33162 31327 31327 32270 33163 31327 31346 32270 31327 31330 31346 31327 31328 31330 33165 32246 31329 31329 33164 33165 31329 33162 33164 33192 33175 31331 34015 33192 31331 31331 32253 34015 32285 31347 31331 33175 32285 31331 32254 31348 31332 32264 32254 31332 31332 31336 32264 31332 31333 31336 31373 31336 31333 31333 31372 31373 31333 31353 31372 32221 31337 31334 31334 32220 32221 32244 32220 31334 31334 31335 32244 32247 32244 31335 32248 32247 31335 31335 31348 32248 31336 31373 32264 33166 31355 31338 31338 33159 33166 31338 32255 33159 31338 31339 32255 31355 31354 31338 31339 32237 32255 31340 31341 32258 31342 31341 31340 31341 31342 31343 32259 32258 31341 31341 31343 32259 32261 32259 31343 31343 31344 32261 31344 31352 32261 32285 31360 31347 32254 32248 31348 33145 32257 31349 31349 33144 33145 33154 33144 31349 31349 32260 33154 32268 32260 31349 31349 31350 32268 31351 31350 31349 32257 31351 31349 32271 32268 31350 33170 32271 31350 31350 31351 33170 33171 33170 31351 34014 33171 31351 31351 34007 34014 31351 32257 34007 31352 32269 33173 33172 32261 31352 33173 33172 31352 31382 31372 31353 31353 31374 31382 32256 31361 31354 33180 32256 31354 31354 31355 33180 31355 33166 33179 31355 33179 33180 33184 32272 31356 31356 31357 33184 34020 33184 31357 34024 34020 31357 31357 32273 34024 31358 31364 31365 32288 31381 31359 31360 32286 32294 31360 32284 32286 32285 32284 31360 32256 31376 31361 31385 31377 31362 33193 31385 31362 31362 33182 33193 33183 33182 31362 31362 32271 33183 31362 31363 32271 31363 32258 32260 31363 32268 32271 31363 32260 32268 31366 31365 31364 32276 31366 31364 31365 31366 33185 33185 32275 31365 31366 32276 33185 32278 32276 31367 32300 32278 31367 32289 31371 31368 31368 31369 32289 31370 31369 31368 31369 31388 32289 31369 31370 31388 32291 32290 31371 31371 32289 32291 32296 31373 31372 31372 31382 32296 33201 32264 31373 33202 33201 31373 31373 32295 33202 32296 32295 31373 31400 31382 31374 31374 31375 31400 32298 31400 31375 31375 32297 32298 31375 31376 32297 31376 32256 32297 32305 31386 31378 33203 32305 31378 31378 31379 33203 31379 31385 33203 31380 32280 33194 32288 32280 31380 31380 31381 32288 33194 32300 31380 32308 32296 31382 33215 32308 31382 31382 32315 33215 31382 32312 32315 31382 31397 32312 31400 31397 31382 32299 31384 31383 33235 32299 31383 31385 33193 33203 32310 31387 31386 31386 32305 32310 33220 31402 31387 31387 33207 33220 31387 32310 33207 31391 32301 32306 32303 32293 31392 32306 32303 31392 32311 32307 31394 32321 32311 31394 33209 32321 31394 33211 33209 31394 31394 31395 33211 31395 32286 33211 32294 32286 31395 31400 31399 31396 31396 31397 31400 31398 31397 31396 31399 31398 31396 31397 31398 32312 31398 31427 32312 31398 31403 31427 31418 31403 31398 31398 31406 31418 31398 31399 31406 31399 31401 31406 31399 31400 31401 32309 31401 31400 31400 32298 32309 32313 31406 31401 31401 32309 32313 31403 31404 31427 31405 31404 31403 31418 31405 31403 32332 31427 31404 31404 31438 32332 31404 31405 31438 31405 31418 31419 31440 31438 31405 31405 31420 31440 31405 31419 31420 31419 31418 31406 32317 31419 31406 31406 32316 32317 31406 32313 32316 31407 33223 33237 31408 33224 33225 31408 31409 33224 34974 32319 31408 31408 33225 34974 31415 31412 31410 31421 31415 31410 33226 31421 31410 31410 32319 33226 31414 31413 31411 31411 31412 31414 31415 31414 31412 33250 32335 31413 34070 33250 31413 31413 33243 34070 31413 31414 33243 31414 33228 33243 31414 33227 33228 31414 31415 33227 31415 31421 33227 31416 31417 31424 31425 31424 31417 31443 31420 31419 32340 31443 31419 31419 32333 32340 32334 32333 31419 33234 32334 31419 31419 32324 33234 31419 32317 32324 31420 31439 31440 31443 31439 31420 34057 33227 31421 34058 34057 31421 31421 33226 34058 32338 31423 31422 31422 32337 32338 33229 32320 31423 31423 32338 33229 31432 31426 31424 31424 31425 31432 32328 31432 31425 31425 31433 32328 31434 31433 31425 32314 31434 31425 31426 31432 31454 32322 32312 31427 32332 32322 31427 31428 31441 31447 32325 31430 31429 31430 32326 32327 31430 32325 32326 31455 31454 31432 32339 31455 31432 31432 32328 32339 32329 32328 31433 33231 32329 31433 31433 33230 33231 31433 32321 33230 31433 31434 32321 31434 32311 32321 32314 32311 31434 32332 31438 31435 31435 32330 32332 33249 32330 31435 31435 32345 33249 31435 31436 32345 31437 31436 31435 31438 31437 31435 31436 31437 31457 31436 31458 32345 31436 31456 31458 31457 31456 31436 31437 31438 31442 31437 31442 31457 31440 31439 31438 31438 31439 31442 31444 31442 31439 31439 31443 31444 32348 31447 31441 31442 31444 31498 31464 31457 31442 31498 31464 31442 31443 32340 33252 31445 31444 31443 33252 31445 31443 33263 32361 31444 31444 31445 33263 32361 31498 31444 34092 33263 31445 31445 33252 34092 31446 32347 32355 32356 32346 31446 31446 32355 32356 32348 31448 31447 31474 31459 31448 32358 31474 31448 31448 32348 32358 31466 31450 31449 31500 31478 31450 32368 31500 31450 31450 32365 32368 31450 31466 32365 32365 31466 31451 33264 32365 31451 31451 31452 33264 31453 31452 31451 31466 31453 31451 33265 33264 31452 31452 33255 33265 31452 31453 33255 31453 32341 33255 32351 31463 31454 31454 31455 32351 32360 32351 31455 31455 32342 32360 31455 32339 32342 32343 31458 31456 31456 31472 32343 31456 31457 31472 31473 31472 31457 31499 31473 31457 31457 31464 31499 31458 32344 32345 31458 32343 32344 31460 31465 31475 32357 32349 31460 32364 32357 31460 31460 31476 32364 31460 31475 31476 31461 31487 31492 31461 31462 31487 31462 31491 31502 31462 31490 31491 31462 31463 31490 31489 31487 31462 31502 31489 31462 32351 31490 31463 31464 31498 31499 31477 31475 31465 31467 32371 33276 31467 32369 32371 32336 31468 31467 34104 32336 31467 31467 33276 34104 32336 32325 31468 32352 31471 31469 33259 32352 31469 31469 31495 33259 31469 31470 31495 31471 31470 31469 31470 31493 31495 31494 31493 31470 31470 31471 31494 32344 32343 31471 32352 32344 31471 31471 31472 31494 32343 31472 31471 31497 31494 31472 31472 31473 31497 31514 31497 31473 34113 31514 31473 31473 31499 34113 31474 32359 32378 31474 32358 32359 33284 31476 31475 31475 31508 33284 31475 31477 31508 34116 32364 31476 35047 34116 31476 31476 33287 35047 31476 33284 33287 31477 31507 31508 31479 31484 32370 31501 31484 31479 31485 31483 31480 31480 31481 31485 31482 31481 31480 31486 31482 31480 33279 31485 31481 31481 31482 33279 34094 33279 31482 31482 33269 34094 33271 33269 31482 31482 31488 33271 31482 31486 31488 31483 31484 31501 31485 31484 31483 32372 32370 31484 31484 31485 32372 33278 32372 31485 33279 33278 31485 31487 31488 31492 31489 31488 31487 31488 31502 33271 31488 31489 31502 32351 31491 31490 31491 32360 33272 31491 32351 32360 33272 31502 31491 31496 31495 31493 31505 31496 31493 31493 31497 31505 31493 31494 31497 31495 32387 33259 31495 32386 32387 31495 31513 32386 31495 31496 31513 31496 31503 31513 31504 31503 31496 31521 31504 31496 31496 31505 31521 31515 31505 31497 31497 31514 31515 32361 31499 31498 34114 34113 31499 31499 33273 34114 31499 32361 33273 31500 32368 32374 33272 33271 31502 32385 31513 31503 31503 31511 32385 31503 31504 31511 31512 31511 31504 31521 31512 31504 31524 31521 31505 31505 31515 31524 31506 32377 32379 33289 31508 31507 31507 32381 33289 31507 31509 32381 33288 33284 31508 33289 33288 31508 31509 31519 32381 31509 31510 31519 33290 31519 31510 31510 31528 33290 31510 31518 31528 32390 32385 31511 32395 32390 31511 31511 31512 32395 32396 32395 31512 31512 31521 32396 31513 32385 32386 32376 31515 31514 34130 32376 31514 31514 34113 34130 32375 31524 31515 32376 32375 31515 31516 31517 32388 33294 32388 31517 31517 32380 33294 32394 31528 31518 33290 32381 31519 31520 31532 31534 31521 31522 32396 31523 31522 31521 31524 31523 31521 31522 31523 32397 33309 32396 31522 31522 32397 33309 31523 31524 32397 31524 32375 32397 31525 31526 31535 35056 32393 31527 31527 32392 35056 31528 34146 35058 34149 34146 31528 31528 33298 34149 31528 33297 33298 31528 32394 33297 35058 33290 31528 34124 33300 31529 31529 33295 34124 31529 31530 32389 31531 31530 31529 33300 31531 31529 32394 32389 31530 33299 32394 31530 34150 33299 31530 31530 34149 34150 31530 31531 34149 31531 34148 34149 31531 33300 34148 31532 31533 31534 31532 31537 31538 31536 32393 32398 31537 31542 32400 32400 31538 31537 32400 31539 31538 32400 31542 31539 31540 31544 31545 31544 31572 32407 31544 31551 31572 31546 31545 31544 32407 31546 31544 31545 33312 33313 31545 31546 33312 31546 32407 33312 31547 31548 31559 32401 31559 31548 33321 32417 31550 31550 33318 33321 31550 33317 33318 31552 31553 31554 32419 31553 31552 32426 32418 31553 32428 32426 31553 31553 32419 32428 32418 31554 31553 32418 31561 31554 31555 31559 32401 31557 31556 31555 32415 31557 31555 31555 32401 32415 31556 31558 31563 31556 31557 31558 34175 31558 31557 31557 32415 34175 32433 32432 31558 34188 32433 31558 31558 34186 34188 31558 34175 34186 31588 31573 31560 32418 31588 31560 31560 31561 32418 32428 32419 31562 31562 31577 32428 33328 31567 31564 31564 31565 33328 31566 31565 31564 31565 31566 33328 33329 33328 31566 31566 32440 33329 32416 32406 31567 31567 32405 32416 33328 32405 31567 32409 31569 31568 33330 32434 31569 31569 33324 33330 31569 33319 33324 31569 32409 33319 31570 31571 32413 31571 32412 32413 32423 32407 31572 31588 31579 31573 31574 31582 31584 31583 31582 31574 32443 31583 31574 31574 31575 32443 31576 31575 31574 31590 31576 31574 31574 31584 31590 32446 32443 31575 32466 32446 31575 31575 31576 32466 31576 32464 32466 31576 32438 32464 32431 32428 31577 31577 31581 32431 31577 31578 31581 31578 31580 31581 31588 31587 31579 31583 31581 31580 31580 31582 31583 32437 32431 31581 31581 31583 32437 32443 32437 31583 31585 31599 32440 31600 31599 31585 31586 32455 32467 32454 31589 31587 31587 32441 32454 32442 32441 31587 32453 32442 31587 31587 32430 32453 31587 31588 32430 31588 32427 32430 31588 32418 32427 31591 32435 32450 32436 32435 31591 31591 32429 32436 31591 31592 32429 32456 32455 31591 31591 32449 32456 32450 32449 31591 32451 31594 31593 32452 32451 31593 32457 32452 31593 33338 32457 31593 31593 31595 33338 32422 32411 31594 32451 32422 31594 31595 33337 33338 31595 32468 33337 31595 31596 32468 32469 32468 31596 31596 31607 32469 32474 32472 31597 33333 32440 31599 34202 33333 31599 34204 34202 31599 34209 34204 31599 34214 34209 31599 31599 31600 34214 35113 34214 31600 31600 34223 35113 34224 34223 31600 34225 34224 31600 31600 31604 34225 32476 31607 31602 31604 33364 34225 31604 31610 33364 31604 31605 31610 31606 32471 32475 32476 32469 31607 32480 31611 31608 31608 31609 32480 31609 32472 32480 31610 32482 33364 33365 32479 31611 31611 32480 33365 33362 32476 31612 31612 33358 33362 31612 31617 33358 31612 31616 31617 32484 31616 31612 31613 31614 32494 31615 31614 31613 33376 32494 31614 33377 33376 31614 33380 33377 31614 33382 33380 31614 31614 32504 33382 31614 31619 32504 31614 31615 31619 32484 32483 31616 31618 31617 31616 32477 31618 31616 34227 33358 31617 31617 31618 34227 31618 33370 34227 31618 32477 33370 31619 31620 32504 31621 31625 31634 31626 31625 31621 32499 31626 31621 31621 32489 32499 31621 31622 32489 31623 31622 31621 31622 32485 32489 34237 32500 31624 31624 32505 34237 31624 32501 32505 31624 31627 32501 31636 31634 31625 31625 31626 31636 32516 31636 31626 33383 32516 31626 31626 32499 33383 31628 31630 32496 31631 31630 31629 31635 31631 31629 31638 31635 31629 32497 32496 31630 32498 32497 31630 31630 31631 32498 33375 32498 31631 34244 33375 31631 31631 31635 34244 32514 32513 31632 33385 32514 31632 31632 31633 33385 31633 33381 33385 31633 32493 33381 31635 33387 34244 31635 32510 33387 31635 31638 32510 34264 32507 31636 35165 34264 31636 31636 34253 35165 31636 32516 34253 32505 32501 31637 32508 32505 31637 34255 32508 31637 31637 33386 34255 31640 31639 31638 32512 32510 31638 31638 31639 32512 31639 31648 32512 32525 32522 31641 32531 31650 31642 31643 31644 32529 32529 32515 31643 31644 31649 32529 31645 31646 31649 32533 32529 31646 32534 32533 31646 31646 32523 32534 31646 32522 32523 32529 31649 31646 31652 31651 31647 31653 31652 31647 31651 31648 31647 33399 32512 31648 33402 33399 31648 31648 31651 33402 32531 32530 31650 31651 31652 33402 33404 33402 31652 34272 33404 31652 31652 34270 34272 31652 34267 34270 31652 31653 34267 31653 33400 34267 31653 32535 33400 31655 32541 32543 31655 32536 32541 31656 31658 32540 32546 32540 31658 31676 31665 31659 31659 31673 31676 31659 31660 31673 31661 31660 31659 31665 31661 31659 31660 31667 31673 31660 31666 31667 31660 31661 31666 31661 31662 31666 31664 31662 31661 32558 31664 31661 31661 32557 32558 31661 32550 32557 31661 31665 32550 31668 31666 31662 31662 31663 31668 31664 31663 31662 32569 31668 31663 31663 32567 32569 31663 32560 32567 32566 32560 31663 31663 31664 32566 31664 32555 32566 31664 32554 32555 32558 32554 31664 31665 31676 31677 31668 31667 31666 31667 31668 31673 32569 31673 31668 31678 31671 31669 31679 31678 31669 31671 31670 31669 31678 31674 31671 33423 32568 31672 33429 33423 31672 33430 33429 31672 31684 31676 31673 32569 31685 31673 32572 31675 31674 32573 32572 31674 31674 31678 32573 31675 32572 32574 32581 32573 31678 31678 31679 32581 31679 31686 32581 31679 31680 31686 32586 31686 31680 32587 32586 31680 31680 31693 32587 32580 32578 31681 31681 31682 32580 32578 32577 31681 31682 31683 32580 32584 32580 31683 32571 31695 31685 31685 32569 32571 32586 32581 31686 31689 31688 31687 32583 31689 31687 34305 32583 31687 31687 33440 34305 31687 32582 33440 32598 31697 31688 31688 31689 32598 33458 32598 31689 31689 33446 33458 31689 32583 33446 33436 32585 31690 31690 33432 33436 31690 32571 33432 31690 31691 32571 31692 31691 31690 32585 31692 31690 31691 31695 32571 31691 31694 31695 31691 31692 31694 33453 31693 31692 34311 33453 31692 31692 32585 34311 33453 32587 31693 31701 31700 31696 31696 31697 31701 32598 31701 31697 32601 31699 31698 31698 31717 32601 31698 31716 31717 31699 31717 32597 32601 31717 31699 31700 31701 31702 32598 31702 31701 32603 32602 31702 31702 32598 32603 31703 31704 32609 31705 32610 33456 31705 31718 32610 31705 31706 31718 31707 31706 31705 32594 31707 31705 33456 32594 31705 31706 31713 31718 31706 31711 31713 31706 31707 31711 31707 31710 31711 31707 31708 31710 31709 31708 31707 32592 31709 31707 32594 32592 31707 31715 31710 31708 31717 31715 31708 32597 31717 31708 31708 32595 32597 31708 31709 32595 32596 32595 31709 31709 32593 32596 31709 32592 32593 32610 31718 31713 31713 31719 32610 31720 31719 31713 31714 31715 31716 31717 31716 31715 33470 32610 31719 31719 31720 33470 31720 33469 33470 33476 33469 31720 31720 31729 33476 32609 31724 31722 31727 31725 31723 31723 31726 31727 31724 31725 31728 32609 31725 31724 31725 31727 31728 31729 31730 33476 33482 33476 31730 31730 31732 33482 31738 31736 31731 31731 31745 31746 31731 31736 31745 31732 31734 33482 34371 34349 31733 31733 32638 34371 34349 31734 31733 31734 33480 33482 34349 33480 31734 31735 32618 32621 31738 31737 31736 32648 31745 31736 31736 32647 32648 31736 31737 32647 31737 31744 32647 31741 31740 31739 31742 31741 31739 33488 31742 31739 31739 33487 33488 31766 31751 31740 31740 31741 31766 32649 31766 31741 32651 32649 31741 33492 32651 31741 33493 33492 31741 31741 31742 33493 31742 33488 33493 33494 32638 31743 33497 33494 31743 31743 31752 33497 31743 31750 31752 32652 32647 31744 31744 32641 32652 31744 31761 32641 32646 31746 31745 32648 32646 31745 32646 31747 31746 32642 31748 31747 32646 32642 31747 32637 31749 31748 32642 32637 31748 31754 31752 31750 31750 31753 31754 31751 31766 32649 31757 31756 31751 32650 31757 31751 31751 32649 32650 31752 31754 33497 31758 31754 31753 31760 31758 31753 31754 31758 33499 33498 33497 31754 33499 33498 31754 32655 32654 31755 31755 32639 32655 32659 31765 31756 31756 31757 32659 33506 32659 31757 31757 32650 33506 31758 31760 32653 31758 32653 33499 32653 31760 31759 32661 32653 31759 31761 31762 32641 31763 31762 31761 34397 32641 31762 31762 31763 34397 31763 32656 34396 34401 34397 31763 31763 34396 34401 31764 31765 32659 32657 31775 31764 32658 32657 31764 32659 32658 31764 32676 31770 31767 31767 31784 32676 34405 32663 31768 31768 31772 34405 31768 31769 31772 31769 31771 31772 32660 31771 31769 31770 31771 32660 33510 31771 31770 31770 32676 33510 34404 31772 31771 31771 33510 34404 34406 34405 31772 31772 34403 34406 34404 34403 31772 31773 33519 34413 31773 32664 33519 31773 31774 32664 34400 33507 31773 34413 34400 31773 33519 32664 31774 33513 32666 31775 34407 33513 31775 31775 32657 34407 32665 31782 31776 32666 32665 31776 33530 31788 31777 31777 32674 33530 31777 32673 32674 31777 32671 32673 31777 31783 32671 32668 32667 31780 33515 32669 31781 31781 32665 33515 31781 31782 32665 31783 32670 32671 32677 32676 31784 33532 32677 31784 31784 32675 33532 31784 31785 32675 31785 31789 32675 33539 32685 31786 31786 33523 33539 33526 33523 31786 31786 31787 33526 31787 31792 32678 31787 32678 33526 33537 33536 31788 31788 33531 33537 31788 33530 33531 33536 32687 31788 32688 32675 31789 33535 32679 31790 31790 32689 33535 33541 32688 31791 31792 32667 32678 31793 32695 33541 32696 32695 31793 32701 32696 31793 31793 31800 32701 32697 32693 31794 31794 32686 32697 33534 33533 31795 31795 32694 33534 34443 34440 31797 31797 34438 34443 31797 33548 34438 31797 31801 33548 32699 31801 31797 31797 31804 32699 31797 31798 31804 34440 32708 31797 32700 31805 31799 32702 32701 31800 31801 33547 33548 31801 33540 33547 31801 31802 33540 31802 33536 33540 32699 31804 31803 32700 31815 31805 31806 32696 32702 31806 31809 32696 31810 31809 31807 31812 31810 31807 31816 31812 31807 31807 31808 31816 33552 32696 31809 34446 33552 31809 31809 31810 34446 34455 34446 31810 31810 33558 34455 31810 31811 33558 31812 31811 31810 31811 31812 32710 34460 33558 31811 31811 34459 34460 31811 32715 34459 31811 32710 32715 31812 31816 32710 31813 32706 32707 32713 32706 31813 31813 32709 32713 31813 31817 32709 31814 31815 32700 33551 32704 31814 31814 32700 33551 33554 32710 31816 31817 32708 32709 31818 31820 31821 32705 31820 31818 32720 31823 31819 31819 31821 32720 32719 31821 31820 31820 32718 32719 31820 32717 32718 31820 32705 32717 31821 32719 32720 33570 31825 31823 31823 33569 33570 31823 33568 33569 31823 32720 33568 31824 31826 31830 31824 31825 31826 33570 31826 31825 32721 31830 31826 33572 32721 31826 33573 33572 31826 31826 33570 33573 35344 34470 31827 35347 35344 31827 31827 31828 35347 36106 35347 31828 36887 36106 31828 31828 34478 36887 31828 31839 34478 31834 31831 31829 31831 31832 31850 31833 31832 31831 31840 31833 31831 31831 31834 31840 31832 31833 31850 32746 31850 31833 31833 32723 32746 31833 31840 32723 31835 31837 32724 32730 31836 31835 31835 32724 32730 32730 31841 31836 31844 31843 31838 31839 32736 34478 33586 32723 31840 31840 33574 33586 31840 32729 33574 32730 31842 31841 31847 31846 31842 32739 31847 31842 31842 32730 32739 32734 32733 31843 31843 31844 32734 31844 31849 32734 32742 32738 31845 31845 31846 32742 32743 32742 31846 31846 31847 32743 34491 32743 31847 31847 33589 34491 31847 32739 33589 32740 31849 31848 32744 32740 31848 32741 32734 31849 31849 32740 32741 32746 31851 31850 34480 31852 31851 31851 32746 34480 32757 31873 31852 34498 32757 31852 31852 34480 34498 33600 33594 31853 34492 33600 31853 31853 32751 34492 33594 32748 31853 33604 32752 31854 31854 31860 33604 32753 32749 31855 34493 32753 31855 31855 33602 34493 31855 32747 33602 31856 33590 33599 31858 31857 31856 32750 31858 31856 33608 32750 31856 31856 33599 33608 31857 32744 32745 31857 31858 32744 32756 32744 31858 34523 32756 31858 31858 33610 34523 31858 32750 33610 31864 31862 31859 34508 33604 31860 34509 34508 31860 31860 33603 34509 31860 31861 33603 31861 31864 33603 31861 31862 31864 32768 31872 31865 31866 32749 32754 32770 31880 31867 33614 32770 31867 31867 31868 33614 31868 31874 33614 31868 31873 31874 31869 32763 32764 31869 31877 32763 32764 31870 31869 32764 32758 31870 32765 31878 31871 31871 31872 32765 32766 32765 31872 32768 32766 31872 32757 31874 31873 31874 33613 33614 34530 33613 31874 31874 34524 34530 34525 34524 31874 35399 34525 31874 31874 32757 35399 33618 33617 31875 34518 33618 31875 31875 32762 34518 31875 31876 32762 31877 31876 31875 33615 31877 31875 33620 33615 31875 31875 33617 33620 32772 32762 31876 33615 32763 31877 31878 32765 32769 31879 34535 35411 31879 31888 34535 31889 31888 31879 31880 31881 31883 31882 31881 31880 32770 31882 31880 31894 31892 31881 31881 31882 31894 32776 31894 31882 33622 32776 31882 33623 33622 31882 31882 33621 33623 31882 33613 33621 31882 33612 33613 31882 32770 33612 33624 31885 31884 31884 32769 33624 33625 31886 31885 31885 33624 33625 31887 31888 31889 33627 31888 31887 31887 33625 33627 31888 33627 34535 33629 33626 31890 34536 33629 31890 34537 34536 31890 31890 31891 34537 36143 34537 31891 31891 35413 36143 31894 31893 31892 32773 31901 31893 32774 32773 31893 31893 31894 32774 32776 32774 31894 31897 32771 32778 32795 31908 31898 31898 31902 32795 32773 31902 31901 34546 32795 31902 31902 34539 34546 31902 33639 34539 33640 33639 31902 31902 32774 33640 31902 32773 32774 32786 32785 31903 31904 31906 32786 31904 31905 31906 32799 32786 31906 32800 32799 31906 31906 31915 32800 31907 32788 32790 32789 32788 31907 31907 31918 32789 33649 31909 31908 31908 32795 33649 33659 31926 31909 31909 33649 33659 33643 32783 31910 33650 33643 31910 31910 31911 33650 31911 32797 33650 31911 32794 32797 34558 32798 31913 31913 34554 34558 31913 32784 34554 31913 31914 32784 32798 32794 31913 32785 32784 31914 31915 31919 32800 32789 31918 31916 33645 32789 31916 31916 31932 33645 31916 31917 31932 31917 31931 31932 31917 31922 31931 31920 32787 32802 31920 32805 32806 31920 32803 32805 31920 32802 32803 31930 31929 31921 32810 31930 31921 32807 31948 31923 31923 31924 32807 31925 31924 31923 33648 32807 31924 31924 32790 33648 31924 31925 32790 33660 32815 31926 31926 33659 33660 32796 31927 31926 32815 32796 31926 32796 31935 31927 31928 32808 32817 31928 31941 32808 33668 32812 31929 33671 33668 31929 31929 33667 33671 31929 31930 33667 31930 32810 33667 31931 32813 33668 31933 31932 31931 32814 31933 31931 33668 32814 31931 33652 33645 31932 31932 31933 33652 34562 33652 31933 31933 32814 34562 31934 31942 32819 32816 31936 31935 31935 32815 32816 31935 32796 32815 31936 32816 32821 32820 31939 31936 32821 32820 31936 31963 31959 31937 32822 31963 31937 31937 31938 32822 31959 31943 31937 33677 32822 31938 31938 32820 33677 31938 31940 32820 32820 31940 31939 32809 32808 31941 31941 31945 32809 31942 31950 32819 32809 31945 31944 31944 31952 32809 31946 31953 32827 34573 32818 31948 34574 34573 31948 31948 32807 34574 32829 31955 31949 31949 31957 32829 31949 31956 31957 33672 32819 31950 33676 33672 31950 32823 32809 31952 32831 32823 31952 31952 31960 32831 31953 32824 32827 31953 31954 32824 31954 32828 32833 31954 31955 32828 32833 32824 31954 32829 32828 31955 31958 31957 31956 33681 31958 31956 31956 33680 33681 31956 32818 33680 32836 32829 31957 31957 31958 32836 31958 33681 34592 32838 32836 31958 33690 32838 31958 34595 33690 31958 31958 34592 34595 31962 31961 31959 31963 31962 31959 31960 31969 32831 31962 31963 31966 31963 31965 31966 32822 31965 31963 33682 31966 31964 34582 33682 31964 31964 33677 34582 31964 32822 33677 31964 31965 32822 31966 31965 31964 32832 31968 31967 31967 31975 32832 32831 31969 31968 32832 32831 31968 32837 31976 31970 31970 31971 32837 33697 32837 31971 31971 33684 33697 32839 31974 31972 32853 32839 31972 31972 31973 32853 31973 31986 32853 32832 31975 31974 32839 32832 31974 32842 31984 31976 33712 32842 31976 31976 32837 33712 32847 32843 31977 31978 32865 33704 31978 32855 32865 31978 32848 32855 32849 32848 31978 33703 32847 31978 33704 33703 31978 31985 31981 31979 32851 31985 31979 31979 31982 32851 31981 31980 31979 31997 31992 31980 31980 31996 31997 31980 31981 31996 32867 31996 31981 31981 31985 32867 31982 32850 32851 31982 31983 32850 31984 32842 33711 32854 31991 31984 33711 32854 31984 31985 32866 32867 31985 32851 32866 32859 32853 31986 32860 32859 31986 31986 31987 32860 32861 32860 31987 31987 31988 32861 31989 31988 31987 31988 31990 32861 31988 31989 31990 31993 31990 31989 31990 31993 32861 32863 31995 31991 31991 32862 32863 31991 32854 32862 31992 31997 32009 32010 32003 31992 31992 32009 32010 32863 32861 31993 31993 31994 32863 31994 31995 32863 32001 31997 31996 32883 32001 31996 31996 32871 32883 31996 32867 32871 31997 32001 32009 32002 31999 31998 32004 32000 31999 32008 32004 31999 32011 32008 31999 31999 32002 32011 32001 32883 32884 32884 32009 32001 32002 32003 32011 32012 32011 32003 32003 32010 32012 32008 32005 32004 32017 32013 32005 32885 32017 32005 32005 32008 32885 32013 32007 32005 32006 32016 32019 32006 32013 32016 32006 32007 32013 33759 32885 32008 32008 32011 33759 32884 32010 32009 33754 32012 32010 32010 32884 33754 33760 33759 32011 32011 33754 33760 32011 32012 33754 32017 32016 32013 35514 33789 32014 32014 33787 35514 32021 32019 32016 32894 32021 32016 33776 32894 32016 32016 33764 33776 32016 32017 33764 32017 32885 33764 32020 32021 32895 32021 32894 32895 32030 32029 32022 32902 32030 32022 32022 32028 32902 32903 32031 32023 32023 32030 32903 32023 32029 32030 32036 32032 32024 32897 32034 32026 32026 32027 32897 32027 32896 32897 32907 32902 32028 32028 32039 32907 32028 32035 32039 32030 32902 32903 32903 32040 32031 32037 32033 32032 32032 32036 32037 32033 32037 32041 32899 32049 32034 32034 32897 32899 32056 32037 32036 32909 32041 32037 32915 32909 32037 32037 32056 32915 32038 32911 32920 32038 32058 32911 32920 32048 32038 32913 32907 32039 32923 32913 32039 32039 32906 32923 32039 32053 32906 32040 32908 32924 32040 32904 32908 32040 32903 32904 34664 33791 32042 34681 34664 32042 32042 32043 34681 33791 33786 32042 32043 33793 34681 32043 32918 33793 32046 32045 32044 32047 32046 32044 32045 32046 32910 32046 32047 32910 32919 32918 32047 32918 32910 32047 32911 32050 32049 32049 32900 32911 32049 32899 32900 32911 32058 32050 32054 32052 32051 32922 32054 32051 32054 32053 32052 32053 32055 32906 32053 32054 32055 33803 32055 32054 32054 33794 33803 32054 32922 33794 34701 32906 32055 32055 33803 34701 32916 32915 32056 32930 32919 32057 32057 32929 32930 32059 32909 32917 33801 32921 32060 32926 32062 32061 32061 32925 32926 32061 32924 32925 32926 32080 32062 32063 32065 32916 32066 32065 32063 32063 32064 32066 32067 32066 32064 32071 32067 32064 32928 32916 32065 32065 32927 32928 32936 32927 32065 32065 32066 32936 32066 32067 32936 32067 32082 32943 32943 32936 32067 32068 32069 32073 32928 32927 32069 32069 32917 32928 32927 32073 32069 33812 32934 32070 32070 32945 33812 32070 32077 32945 32078 32077 32070 32073 32927 32937 32076 32075 32074 34717 32076 32074 35571 34717 32074 32074 35561 35571 32074 34702 35561 32074 32075 34702 32075 34695 34702 32075 33792 34695 32957 32094 32076 32958 32957 32076 34717 32958 32076 32970 32945 32077 32077 32960 32970 32079 33795 33796 33797 33795 32079 32079 32080 33797 32081 32080 32079 33809 32081 32079 34701 33809 32079 32079 32906 34701 33796 32906 32079 32080 32935 33797 32080 32926 32935 33809 32090 32081 32952 32943 32082 33814 32085 32083 33819 33814 32083 33811 32931 32084 33813 33811 32084 32084 32085 33813 33814 33813 32085 33818 33817 32086 32087 33823 33824 33824 33808 32087 32088 32091 32100 32959 32094 32089 33810 32947 32090 32090 33809 33810 32091 32099 32100 32964 32962 32092 32092 32955 32964 32975 32967 32093 32093 32974 32975 32093 32094 32974 32094 32957 32974 33827 33820 32095 32095 32107 33827 32095 32096 32107 32966 32097 32095 33820 32966 32095 32100 32099 32098 32973 32100 32098 32956 32102 32101 32964 32956 32101 32101 32962 32964 32103 34715 34721 34735 34715 32103 32103 32104 34735 32105 32104 32103 34721 32105 32103 35584 34735 32104 32104 34719 35584 34734 34719 32104 32104 32105 34734 32105 32971 34734 34721 32971 32105 32976 32110 32106 33826 32976 32106 32108 32111 32112 32972 32111 32108 32977 32972 32108 32108 32961 32977 32981 32980 32111 32111 32972 32981 32978 32114 32113 32120 32115 32114 32982 32120 32114 32114 32978 32982 32120 32119 32115 32118 32117 32116 32996 32118 32116 33002 32996 32116 33856 33002 32116 32116 32117 33856 32117 32118 32986 32117 33846 33856 32117 32986 33846 32996 32124 32118 33859 33855 32119 32119 33858 33859 32119 33001 33858 32119 32993 33001 32119 32120 32993 32120 32988 32993 32120 32982 32988 33852 33842 32121 33854 33852 32121 32121 32999 33854 32121 32122 32999 32997 32125 32123 33003 32997 32123 32123 32124 33003 32124 33006 33863 32124 32996 33006 33007 33003 32124 33866 33007 32124 32124 33863 33866 33009 33008 32126 33010 33009 32126 32126 32992 33010 34751 33000 32127 35626 34751 32127 32127 34824 35626 32127 34808 34824 32127 32128 34808 32129 32128 32127 32130 32129 32127 33000 32130 32127 32128 33016 34808 32128 32129 33016 33018 33016 32129 32129 32130 33018 32130 33011 33018 32130 32131 33011 33012 33011 32131 32131 32133 33012 33019 32133 32132 32132 32137 33019 32133 32137 33012 33019 32137 32133 32134 32139 33015 33883 32136 32135 32135 33877 33883 32135 33014 33877 32135 33013 33014 34824 33884 32136 32136 34806 34824 32136 33885 34806 32136 33883 33885 33017 33012 32137 33024 33022 32138 33882 33015 32139 32139 33036 33882 32141 32150 33020 33045 33033 32142 33046 33045 32142 32142 33044 33046 33038 32148 32143 33040 33038 32143 32143 32144 33040 32144 33029 33040 32144 33028 33029 32164 32158 32145 32165 32164 32145 32145 32146 32165 32158 32149 32145 32146 32154 32167 32166 32165 32146 32167 32166 32146 33047 32156 32147 33048 33047 32147 32147 32148 33048 32148 33039 33048 32148 33038 33039 32151 32150 32149 32158 32151 32149 33026 33020 32150 33041 33026 32150 33042 33041 32150 32150 32151 33042 33049 33042 32151 32151 32159 33049 32151 32158 32159 33923 33076 32152 33924 33923 32152 32152 33919 33924 32152 32153 33919 32153 33911 33919 32153 33043 33911 32155 33060 33062 32155 32162 33060 33047 32157 32156 33914 33058 32157 32157 33907 33914 33908 33907 32157 32157 33047 33908 32161 32160 32158 32164 32161 32158 32160 32159 32158 33072 33049 32159 32159 32160 33072 32160 32170 33073 32160 32161 32170 33073 33072 32160 32161 32164 32170 33079 33060 32162 33080 33079 32162 32162 32175 33080 32162 32168 32175 32163 33053 33054 33056 33053 32163 32164 32165 33059 33073 32170 32164 32164 33059 33073 32165 32166 33059 33077 33059 32166 32166 32167 33077 32167 33076 33077 32168 32174 32175 32172 32171 32169 33082 32192 32171 32171 32172 33082 32172 32178 33082 32173 33064 33065 32173 33055 33064 32173 33054 33055 32176 32175 32174 33090 33080 32175 32175 32176 33090 33937 33090 32176 32176 33098 33937 32176 32180 33098 32189 32182 32177 32193 32189 32177 32177 32192 32193 33092 33082 32178 33093 33092 32179 33094 33093 32179 32179 32183 33094 33110 33098 32181 32181 32188 33110 32181 32182 32188 32189 32188 32182 33943 33094 32183 32183 33103 33943 33938 33105 32184 32184 33099 33938 33104 33103 32185 32185 32186 33104 34879 33104 32186 32186 33127 34879 32187 33106 33112 32187 33105 33106 33111 33110 32188 32188 32189 33111 32189 32190 33111 32191 32190 32189 32197 32191 32189 32205 32197 32189 32189 32193 32205 33131 33111 32190 33132 33131 32190 32190 32212 33132 32190 32198 32212 32190 32191 32198 32191 32197 32198 32194 32193 32192 33929 32194 32192 32192 33091 33929 32192 33082 33091 32193 32194 32205 32194 32200 32205 32201 32200 32194 33942 32201 32194 32194 33929 33942 32195 33126 33127 32195 33116 33126 32195 32196 33116 32196 32223 33116 32213 32198 32197 32197 32199 32213 32200 32199 32197 32205 32200 32197 32198 32204 32212 32198 32203 32204 32213 32203 32198 32216 32213 32199 33119 32216 32199 33120 33119 32199 33951 33120 32199 32199 32201 33951 32199 32200 32201 32201 33942 33951 32228 32207 32202 33118 32228 32202 32202 33117 33118 32214 32204 32203 32215 32214 32203 32203 32213 32215 32204 33133 33976 32204 32214 33133 33115 32212 32204 33976 33115 32204 32236 32235 32206 32245 32236 32206 32206 32225 32245 32228 32217 32207 32219 32210 32208 33130 32219 32208 32208 32209 33130 33975 33130 32209 32209 33129 33975 32219 32211 32210 33973 33132 32212 32212 33115 33973 32216 32215 32213 32214 32215 33133 33134 33133 32215 32215 32216 33134 32216 33119 33134 32217 32227 32233 32228 32227 32217 33129 32234 32218 33975 33129 32218 34900 33975 32218 32218 33997 34900 32218 32242 33997 32219 33130 33141 32222 32221 32220 32223 32222 32220 32224 32223 32220 32244 32224 32220 32221 32222 32235 33126 33116 32223 32223 33125 33126 32223 32224 33125 32224 33121 33125 33137 33121 32224 33152 33137 32224 33157 33152 32224 32224 32247 33157 32224 32244 32247 32225 32237 32245 32238 32237 32225 33974 32233 32227 32227 33139 33974 32227 33138 33139 32227 32229 33138 32227 32228 32229 33118 32229 32228 33968 33138 32229 32229 33967 33968 32229 33118 33967 32230 32233 33974 32230 32232 32233 33990 32231 32230 32230 33974 33990 32231 32241 32242 35729 32241 32231 32231 33991 35729 32231 33990 33991 33158 32255 32237 32237 32238 33158 32238 33142 33158 32242 32241 32240 34915 32242 32240 32240 34045 34915 35735 34045 32240 32240 34903 35735 32240 32241 34903 35729 34903 32241 34917 33997 32242 32242 34915 34917 32243 33141 33151 34015 32253 32246 32246 33192 34015 34011 33192 32246 32246 33165 34011 32247 32249 33157 32247 32248 32249 32254 32249 32248 32249 32266 33157 32249 32254 32266 34005 33160 32250 32250 33142 34005 34012 33142 32250 32250 32251 34012 34016 34012 32251 32251 32287 34016 34920 33169 32252 32252 33168 34920 32254 32264 32266 32255 33158 33159 32304 32297 32256 33180 32304 32256 32257 33161 34007 32257 33145 33161 32258 32259 32260 33156 33155 32259 32259 32262 33156 32259 32261 32262 33154 32260 32259 33155 33154 32259 32263 32262 32261 33172 32263 32261 33985 33156 32262 32262 32263 33985 34004 33985 32263 32263 34003 34004 34017 34003 32263 32263 33172 34017 32264 32265 32266 33200 32265 32264 33201 33200 32264 32267 32266 32265 33177 32267 32265 32265 33176 33177 33199 33176 32265 33200 33199 32265 32266 32267 33157 32267 33152 33157 33177 33152 32267 32269 32272 33173 33164 33163 32270 33190 33164 32270 32270 32283 33190 32270 32282 32283 32271 33170 33183 33184 33173 32272 32273 34021 34024 32273 32274 34021 34022 34021 32274 32274 32275 34022 32275 33186 34022 32275 33185 33186 32276 32278 33185 32277 32278 34030 32279 32278 32277 34027 32279 32277 34028 34027 32277 34029 34028 32277 34030 34029 32277 32278 32279 33185 32278 32300 34030 33186 33185 32279 34027 33186 32279 32280 33188 33194 32280 32281 33188 32281 33169 34918 32281 33187 33188 34023 33187 32281 34918 34023 32281 33174 32283 32282 32282 32293 33174 34049 33190 32283 32283 34046 34049 32283 32292 34046 34048 32292 32283 32283 33196 34048 32283 33174 33196 33211 32286 32284 34969 33211 32284 35746 34969 32284 32284 33191 35746 33192 33191 32284 32284 33175 33192 32284 32285 33175 33195 32291 32289 33208 33195 32289 32290 32291 32292 34046 32292 32291 34047 34046 32291 32291 33195 34047 34048 33204 32292 32293 32302 33174 32293 32301 32302 32303 32301 32293 32295 32296 32308 33206 33202 32295 32295 32308 33206 32304 32298 32297 32298 32304 32309 34948 34043 32299 34956 34948 32299 32299 34955 34956 32299 33235 34955 32300 33187 34023 33188 33187 32300 33194 33188 32300 34045 34030 32300 32300 34031 34045 32300 34023 34031 32301 32303 32306 33196 33174 32302 34048 33196 32302 32302 33204 34048 33218 32309 32304 32304 33180 33218 33207 32310 32305 32305 33203 33207 32307 32311 32314 33214 33206 32308 33215 33214 32308 33219 32313 32309 32309 33218 33219 32323 32315 32312 32312 32322 32323 33233 32316 32313 33234 33233 32313 33240 33234 32313 32313 33219 33240 32315 32323 32331 33232 33215 32315 34074 33232 32315 32315 32331 34074 32318 32317 32316 33233 32318 32316 32317 32318 32324 33233 32324 32318 34059 33226 32319 34961 34059 32319 32319 34958 34961 34974 34958 32319 32321 33209 33230 32330 32323 32322 32332 32330 32322 32323 32330 32331 32324 33233 33234 33244 32326 32325 33245 33244 32325 34077 33245 32325 32325 32336 34077 33246 32327 32326 32326 33244 33246 33251 32337 32327 32327 33246 33251 32328 32329 32339 32342 32339 32329 32350 32342 32329 33231 32350 32329 33249 32331 32330 32331 33249 34074 34097 32340 32333 34996 34097 32333 32333 32334 34996 32334 34978 34996 32334 34068 34978 32334 33240 34068 32334 33234 33240 33250 32341 32335 34998 34077 32336 32336 34103 34998 34104 34103 32336 33251 32338 32337 32338 33216 33229 33244 33216 32338 34078 33244 32338 32338 33251 34078 34092 33252 32340 34098 34092 32340 32340 34097 34098 32341 33250 33255 32342 33248 34082 32342 32350 33248 34081 32360 32342 34082 34081 32342 33260 32345 32344 32344 33258 33260 32344 32353 33258 32344 32352 32353 33261 33249 32345 32345 33260 33261 32346 33254 34076 32346 33253 33254 32346 32356 33253 32362 32355 32347 32348 32349 32358 32349 32357 32358 32350 33231 33248 33259 32353 32352 32353 33257 33258 33259 33257 32353 32354 32366 33253 32354 32362 32366 32354 32355 32362 32356 32355 32354 33253 32356 32354 32363 32358 32357 32364 32363 32357 33275 32359 32358 34108 33275 32358 32358 32363 34108 33286 32378 32359 34115 33286 32359 32359 34099 34115 32359 33275 34099 32360 33270 33271 34081 33270 32360 32360 33271 33272 32361 33263 33273 32367 32366 32362 32363 32364 34116 35025 34108 32363 32363 34116 35025 33264 32368 32365 34096 33253 32366 34097 34096 32366 32366 33274 34097 32366 32367 33274 34098 33274 32367 32367 34092 34098 32367 33273 34092 34119 33273 32367 33280 32374 32368 32368 33264 33280 33281 32371 32370 32370 32372 33281 34110 33277 32371 32371 33281 34110 33277 33276 32371 32372 33278 33281 34124 33295 32373 32373 33285 34124 32373 32374 33285 34109 33285 32374 32374 33280 34109 34157 32397 32375 32375 32376 34157 32376 33313 34157 34145 33313 32376 32376 34130 34145 33286 32379 32377 32377 32378 33286 33286 32380 32379 34132 33294 32380 35046 34132 32380 32380 34133 35046 34135 34133 32380 32380 33286 34135 34123 33289 32381 34136 34123 32381 32381 33290 34136 32390 32384 32382 32382 32385 32390 32386 32385 32382 34129 32386 32382 32382 34128 34129 32382 33293 34128 32382 32383 33293 32384 32383 32382 32383 33291 33293 33292 33291 32383 33296 33292 32383 32383 32384 33296 32384 32395 32399 32384 32390 32395 32384 32399 33296 35054 32387 32386 32386 34129 35054 34118 33259 32387 35038 34118 32387 35054 35038 32387 35055 32392 32388 32388 34132 35055 32388 33294 34132 32391 33282 33283 33310 33282 32391 32392 35055 35056 33315 32398 32393 34167 33315 32393 35057 34167 32393 32393 35056 35057 33299 33297 32394 32395 32396 32399 33309 32399 32396 34156 33309 32397 34157 34156 32397 33315 32415 32398 33301 33296 32399 34161 33301 32399 34165 34161 32399 32399 33308 34165 33309 33308 32399 32404 32403 32402 34158 32404 32402 32402 34155 34158 32402 33307 34155 32402 32408 33307 32402 32403 32408 33303 32408 32403 32403 32405 33303 32406 32405 32403 33323 32409 32404 34158 33323 32404 33305 33303 32405 34169 33305 32405 34189 34169 32405 34190 34189 32405 32405 33328 34190 32405 32406 32416 32407 32423 32424 33316 33312 32407 34179 33316 32407 32407 32424 34179 32408 33304 33307 32408 33303 33304 33322 33319 32409 33323 33322 32409 32414 32413 32410 33318 32414 32410 35084 33318 32410 32410 35083 35084 32410 34191 35083 32410 32420 34191 32410 32411 32420 32412 32411 32410 32413 32412 32410 32422 32420 32411 33318 33317 32414 32415 34167 34175 32415 33315 34167 32417 33321 33325 32418 32426 32427 35869 34191 32420 35876 35869 32420 32420 32421 35876 32422 32421 32420 32421 35126 35876 32421 35119 35126 32421 32458 35119 32421 32452 32458 32421 32451 32452 32421 32422 32451 32425 32424 32423 32424 32425 34180 34180 34179 32424 32425 33325 34180 33326 32427 32426 33327 33326 32426 33331 33327 32426 32426 32428 33331 34192 32430 32427 32427 33326 34192 33332 33331 32428 33335 33332 32428 32428 33334 33335 32428 32431 33334 33330 32436 32429 32429 32434 33330 34208 32453 32430 32430 34192 34208 32431 32437 33334 32432 32433 32439 32433 34188 34194 34194 32439 32433 34199 32450 32435 32435 33330 34199 32435 32436 33330 32437 32444 33334 32437 32443 32444 32438 32448 34195 33342 32464 32438 35893 33342 32438 32438 34195 35893 32448 32447 32439 34193 32448 32439 34194 34193 32439 33333 33329 32440 32462 32454 32441 32463 32462 32441 32441 32442 32463 33336 32463 32442 32442 32453 33336 32446 32444 32443 32444 32445 33334 32446 32445 32444 35108 33334 32445 35109 35108 32445 35122 35109 32445 32445 34213 35122 32445 32465 34213 32445 32446 32465 32446 32464 32465 32466 32464 32446 34196 34195 32448 32448 34193 34196 34211 32456 32449 32449 34199 34211 32449 32450 34199 32452 32457 32458 34205 33336 32453 34208 34205 32453 32454 32461 33344 32462 32461 32454 33343 32467 32455 32455 32456 33343 34216 33343 32456 32456 34211 34216 35119 32458 32457 32457 35118 35119 32457 34199 35118 35116 34199 32457 35129 35116 32457 32457 33338 35129 32459 33353 33367 32459 32460 33353 32461 32460 32459 33344 32461 32459 33352 33344 32459 32459 33351 33352 32459 32488 33351 33367 32488 32459 33357 33353 32460 32460 33345 33357 33347 33345 32460 32460 32461 33347 32461 32470 33347 32461 32463 32470 32461 32462 32463 33336 32470 32463 33342 32465 32464 35124 34213 32465 32465 33342 35124 33348 32471 32467 32467 33343 33348 32468 32469 33337 33349 33337 32469 32469 32476 33349 32470 33340 33347 32470 33336 33340 32471 33348 33350 32478 32475 32471 33350 32478 32471 32481 32480 32472 32472 32473 32481 32474 32473 32472 32473 32474 32481 33352 32481 32474 32474 33344 33352 32478 32477 32475 33362 33349 32476 32477 33350 33370 32477 32478 33350 32486 32485 32479 33365 32486 32479 32480 32481 33365 33366 33365 32481 32481 33352 33366 33369 33364 32482 33378 33369 32482 32485 32487 32489 32485 32486 32487 32488 32487 32486 33351 32488 32486 33365 33351 32486 32495 32489 32487 33356 32495 32487 32487 32488 33356 33367 33356 32488 32489 32495 32499 35143 35142 32490 32490 34236 35143 32490 34235 34236 32490 34226 34235 32490 32491 34226 32492 32491 32490 35142 32492 32490 35130 34226 32491 35916 35130 32491 32491 32492 35916 36644 35916 32492 32492 35142 36644 32493 33376 33381 32493 32494 33376 32495 34233 35152 34234 34233 32495 32495 34232 34234 32495 33372 34232 32495 33356 33372 33383 32499 32495 35152 33383 32495 32496 34231 34243 32496 32502 34231 32503 32502 32496 32496 32497 32503 33373 32503 32497 32497 32498 33373 33374 33373 32498 33375 33374 32498 34235 33378 32500 34236 34235 32500 34237 34236 32500 36649 34231 32502 32502 35146 36649 32502 33379 35146 32502 32503 33379 32503 33373 33379 32504 32506 33382 32505 32508 34237 33388 33382 32506 33395 33388 32506 32506 32515 33395 34264 33389 32507 35157 34237 32508 35170 35157 32508 32508 34257 35170 32508 34254 34257 34255 34254 32508 32521 32519 32509 34243 32521 32509 35166 33387 32510 32510 34260 35166 32510 32511 34260 32512 32511 32510 32511 33399 34260 32511 32512 33399 33400 32527 32513 34267 33400 32513 34268 34267 32513 32513 32514 34268 35167 34268 32514 32514 34245 35167 32514 33384 34245 33385 33384 32514 33396 33395 32515 32515 32528 33396 32529 32528 32515 32516 32517 34253 32518 32517 32516 33383 32518 32516 35930 34253 32517 32517 35929 35930 32517 35152 35929 32517 32518 35152 32518 33383 35152 32519 32520 33394 32521 32520 32519 32520 33393 33394 32520 33390 33393 34259 33390 32520 32520 32521 34259 32521 34250 34259 32521 34243 34250 32522 33397 33398 32522 32524 33397 32525 32524 32522 33398 32523 32522 34262 32534 32523 32523 33398 34262 32524 32525 33389 34264 33397 32524 32524 33389 34264 32526 32527 32532 33400 32532 32527 34271 33406 32528 32528 32533 34271 32528 32529 32533 33406 33396 32528 33400 32535 32532 35177 34271 32533 32533 33401 35177 32533 32534 33401 34269 33401 32534 32534 34262 34269 32542 32541 32536 32536 32540 32542 34280 32539 32537 32537 34279 34280 34291 34279 32537 32537 33422 34291 32537 32544 33422 32537 32538 32544 32539 32538 32537 32545 32544 32538 33407 32545 32538 32538 32539 33407 35962 35182 32539 32539 34280 35962 35182 33407 32539 32545 32542 32540 32547 32545 32540 32540 32546 32547 32542 34273 34274 32542 33408 34273 32542 33407 33408 32542 32545 33407 32544 32547 33422 32544 32545 32547 32561 32547 32546 32547 32561 33422 33409 32549 32548 33420 32562 32549 32549 33409 33420 32565 32557 32550 32550 32564 32565 32550 32563 32564 34284 33415 32551 32551 33414 34284 32551 33412 33414 32551 32552 33412 32553 32552 32551 33415 32553 32551 32552 32565 33412 32552 32557 32565 32552 32553 32557 32558 32557 32553 33416 32558 32553 34285 33416 32553 32553 33415 34285 32556 32555 32554 32559 32556 32554 33417 32559 32554 32554 33416 33417 32554 32558 33416 32555 32556 32566 32556 32560 32566 32556 32559 32560 34290 34289 32559 32559 33417 34290 34289 32560 32559 33421 32567 32560 34289 33421 32560 32561 32568 33422 33419 32563 32562 33420 33419 32562 33419 32564 32563 33412 32565 32564 33419 33412 32564 32570 32569 32567 33424 32570 32567 32567 33421 33424 33423 33422 32568 33432 32571 32569 32569 33425 33432 32569 32570 33425 33426 33425 32570 32570 33424 33426 32576 32574 32572 33438 32576 32572 32572 32573 33438 33441 33438 32573 32573 32581 33441 32576 32575 32574 33433 32582 32575 32575 32576 33433 33439 33433 32576 32576 33438 33439 34302 33431 32577 32577 33434 34302 33435 33434 32577 32577 32578 33435 32578 32579 33435 32580 32579 32578 34304 33435 32579 32579 32580 32584 33450 33441 32581 32581 33449 33450 32581 32586 33449 32582 33433 33440 33448 33446 32583 35220 33448 32583 32583 34305 35220 32585 34299 34311 32585 33436 34299 32586 32588 33449 32586 32587 32588 33454 32588 32587 32587 33452 33454 33453 33452 32587 33454 33449 32588 32589 32594 34318 32589 32590 32594 32591 32590 32589 34318 32591 32589 32590 32592 32594 32590 32591 32592 32593 32592 32591 34307 32593 32591 34318 34307 32591 34307 32596 32593 32594 33463 34318 32594 33459 33463 32594 33456 33459 32595 32596 34306 33457 32597 32595 34309 33457 32595 32595 34306 34309 35225 34308 32596 32596 35217 35225 32596 34307 35217 34308 34306 32596 32598 32599 32603 32600 32599 32598 33458 32600 32598 32599 32602 32603 32608 32602 32599 32599 32607 32608 33467 32607 32599 32599 33460 33467 32599 32600 33460 33462 33460 32600 34322 33462 32600 35230 34322 32600 32600 33458 35230 32618 32606 32604 32619 32618 32604 33465 32619 32604 33466 33465 32604 32604 32605 33466 32606 32605 32604 33467 33466 32605 32605 32607 33467 33470 33456 32610 33475 32613 32611 32611 32615 33475 32611 32614 32615 32617 32614 32611 32611 32612 32617 32613 32612 32611 32620 32617 32612 33478 32620 32612 34328 33478 32612 34332 34328 32612 34333 34332 32612 32612 34327 34333 32612 33477 34327 32612 32613 33477 33475 33474 32613 32613 33471 33477 33474 33471 32613 32614 32617 32620 32616 32615 32614 32618 32616 32614 32621 32618 32614 32622 32621 32614 32614 32620 32622 32615 32616 33464 32615 33474 33475 32615 33464 33474 32616 32619 33465 32616 32618 32619 33465 33464 32616 32624 32622 32620 32626 32624 32620 33478 32626 32620 32621 32622 32630 32622 32628 32630 32629 32628 32622 32622 32623 32629 32624 32623 32622 33486 32629 32623 32623 33483 33486 32623 32624 33483 32624 32626 33483 33484 32627 32625 34328 33483 32626 32626 33478 34328 34348 33481 32627 32627 33484 34348 32634 32632 32628 33490 32634 32628 32628 33485 33490 32628 32629 33485 32632 32630 32628 33486 33485 32629 32630 32632 32633 34364 33484 32631 32631 32635 34364 32637 32635 32631 32632 32634 32639 32640 32639 32634 33490 32640 32634 34385 34364 32635 32635 34384 34385 32635 32636 34384 32637 32636 32635 32636 34362 34384 32636 32643 34362 32636 32642 32643 32636 32637 32642 32638 33494 34371 33500 32655 32639 32639 32640 33500 32640 34358 34359 32640 33490 34358 32640 33495 33500 33496 33495 32640 34359 33496 32640 33501 32652 32641 33502 33501 32641 34398 33502 32641 32641 34397 34398 32644 32643 32642 32646 32644 32642 32643 32644 34362 32644 34355 34362 32644 32645 34355 32646 32645 32644 32645 32648 33502 32645 32646 32648 32645 34347 34355 32645 34346 34347 34380 34346 32645 32645 34361 34380 32645 33502 34361 32652 32648 32647 32648 32652 33501 32648 33501 33502 32651 32650 32649 34390 33506 32650 32650 32651 34390 32651 34370 34390 32651 33492 34370 33503 33499 32653 33505 33503 32653 33511 33505 32653 32653 32661 33511 33508 32656 32654 32654 32655 33508 32655 33500 33508 32656 33508 34396 32657 33514 34407 32657 32658 33514 34408 33514 32658 32658 34402 34408 32658 33509 34402 32658 32659 33509 32659 33506 33509 32661 33507 33511 32662 33517 33518 32662 32663 33517 34409 33517 32663 32663 34405 34409 33516 33515 32665 32665 32666 33516 32666 33512 33516 33513 33512 32666 32667 32669 33527 32667 32668 32669 33527 32678 32667 32669 33515 34415 34415 33527 32669 33529 32671 32670 32670 33528 33529 32670 32679 33528 32671 32672 32673 33529 32672 32671 34416 32674 32672 34418 34416 32672 35301 34418 32672 32672 33529 35301 32674 32673 32672 34416 33530 32674 33538 33532 32675 32675 32688 33538 34403 33510 32676 32676 32677 34403 35287 34403 32677 35288 35287 32677 35289 35288 32677 32677 33532 35289 33527 33526 32678 33535 33528 32679 32682 32681 32680 32680 32683 33519 32680 32681 32683 32681 33522 34419 32681 32682 33522 32684 32683 32681 34420 32684 32681 32681 34419 34420 32682 33518 33522 34422 34414 32683 32683 32684 34422 34413 33519 32683 34414 34413 32683 35309 34422 32684 32684 34421 35309 32684 34420 34421 33539 32686 32685 33539 32697 32686 33541 33538 32688 34432 33535 32689 32689 33533 34432 32698 32693 32690 33543 32698 32690 32690 32691 33543 32692 32691 32690 32693 32692 32690 32691 32692 33549 34435 33543 32691 32691 33549 34435 32692 34429 34434 32692 33542 34429 32692 32693 33542 34434 33549 32692 32693 32697 33542 34431 33534 32694 32694 33550 34431 34428 33541 32695 35322 34428 32695 32695 32696 35322 32696 32701 32702 32696 33552 35322 34429 33542 32697 32697 33523 34429 33539 33523 32697 33555 33554 32703 34453 33555 32703 34454 34453 32703 32703 34449 34454 32703 34445 34449 32703 32704 34445 32704 33551 34445 32705 32714 32717 32705 32707 32714 32716 32714 32706 32706 32711 32716 32713 32711 32706 32714 32707 32706 34440 32709 32708 34444 32713 32709 32709 34443 34444 32709 34440 34443 33554 32715 32710 33553 32716 32711 34452 33553 32711 32711 32712 34452 32713 32712 32711 32712 34447 34452 32712 34444 34447 32712 32713 34444 33565 32717 32714 32714 33557 33565 32714 33556 33557 32714 32716 33556 32715 34458 34459 32715 33555 34458 32715 33554 33555 32716 33553 33556 33565 32718 32717 33568 32719 32718 32718 33565 33568 33568 32720 32719 32727 32722 32721 33572 32727 32721 32722 32727 32728 34480 32746 32723 32723 33586 34480 32731 32730 32724 34484 32731 32724 32724 34473 34484 32724 32725 34473 32725 33580 34473 32725 32732 33580 33579 32728 32727 34471 33579 32727 32727 33572 34471 32728 33579 33590 32730 32731 32739 34483 32739 32731 34484 34483 32731 33581 33580 32732 32732 33575 33581 33578 33577 32733 33582 33578 32733 33583 33582 32733 32733 32735 33583 32733 32734 32735 32741 32735 32734 35372 33583 32735 32735 34485 35372 32735 32741 34485 34486 34478 32736 32736 34479 34486 32736 33584 34479 33591 33588 32737 32737 32738 33591 32738 32743 33591 32738 32742 32743 34483 33589 32739 33595 32741 32740 33596 33595 32740 33606 33596 32740 32740 32744 33606 32741 33595 34485 35384 33591 32743 35386 35384 32743 32743 33593 35386 32743 33592 33593 34491 33592 32743 32744 32756 33606 32747 33601 33602 32747 33600 33601 32747 33594 33600 32747 32748 33594 32749 32753 32754 33611 33610 32750 34504 33611 32750 34511 34504 32750 32750 33608 34511 35391 34492 32751 32751 35368 35391 32751 34499 35368 32751 32752 34499 32752 33604 35395 35395 34499 32752 32755 32754 32753 32759 32755 32753 33598 32759 32753 32753 33597 33598 34501 33597 32753 32753 34493 34501 32754 32755 32760 32755 32759 32760 33607 33606 32756 32756 33605 33607 34521 33605 32756 34522 34521 32756 34523 34522 32756 32757 34498 35399 32758 34513 34514 32758 33609 34513 32758 32764 33609 32759 33598 33605 32761 32760 32759 33605 32761 32759 36135 34519 32760 36136 36135 32760 37702 36136 32760 32760 36902 37702 32760 34520 36902 32760 32761 34520 34521 34520 32761 32761 33605 34521 32762 32775 34518 32762 32772 32775 33616 32764 32763 32763 33615 33616 33616 33609 32764 33619 32769 32765 32765 32766 33619 32768 32767 32766 34528 33619 32766 32766 32767 34528 32767 34519 34528 34531 33624 32769 32769 34529 34531 32769 33619 34529 33614 33612 32770 33626 32778 32771 34542 32775 32772 32772 33631 34542 32772 33630 33631 32774 32776 33640 32775 33638 34518 34542 33638 32775 34533 33640 32776 32776 33622 34533 32777 32778 33628 32777 33628 33633 32778 33626 33628 33644 32787 32779 32779 32780 33644 32780 32782 33644 32780 32781 32782 33635 32781 32780 32781 34543 34550 32781 33634 34543 32781 33633 33634 33635 33633 32781 34550 32782 32781 34548 33644 32782 34550 34548 32782 33632 33630 32783 33641 33632 32783 33643 33641 32783 34557 33654 32784 32784 32785 34557 34556 34554 32784 32784 33654 34556 32785 32786 32799 32785 32801 34557 32785 32799 32801 33644 32802 32787 33648 32790 32788 32788 33647 33648 32788 32793 33647 32788 32792 32793 32788 32789 32792 33645 32792 32789 32791 32792 33646 32793 32792 32791 34553 32793 32791 35428 34553 32791 32791 33646 35428 32792 33645 33646 35425 33647 32793 32793 34553 35425 32798 32797 32794 34545 33649 32795 34546 34545 32795 33651 33650 32797 32797 32798 33651 34558 33651 32798 32799 32800 32801 33654 32801 32800 32800 32817 33654 32801 33654 34557 34552 32803 32802 32802 33644 34552 34551 32805 32803 34552 34551 32803 32811 32810 32804 32804 32805 32811 32806 32805 32804 33658 32811 32805 33666 33658 32805 35426 33666 32805 32805 34551 35426 32807 33648 34574 33662 32817 32808 32808 32830 33662 32808 32809 32830 32809 32823 32830 32810 33665 33667 32810 33658 33665 32810 32811 33658 33668 32813 32812 34564 34562 32814 32814 33668 34564 33669 32816 32815 32815 33660 33669 33673 32821 32816 34570 33673 32816 34571 34570 32816 34572 34571 32816 32816 33669 34572 34556 33654 32817 32817 34555 34556 32817 33670 34555 32817 33661 33670 33662 33661 32817 34573 33680 32818 32820 33674 33677 32820 32821 33674 32821 33673 33674 33679 32830 32823 32823 32832 33679 32823 32831 32832 32824 32825 32827 32826 32825 32824 32833 32826 32824 34579 32827 32825 32825 32826 34579 34581 34579 32826 34591 34581 32826 32826 33713 34591 32826 33698 33713 32826 32834 33698 32826 32833 32834 33688 33684 32827 34579 33688 32827 32835 32833 32828 33689 32835 32828 32828 32838 33689 32828 32836 32838 32828 32829 32836 33678 33662 32830 33683 33678 32830 32830 33679 33683 33683 33679 32832 32832 32841 33683 32832 32840 32841 32832 32839 32840 32835 32834 32833 33700 33699 32834 32834 32835 33700 33699 33698 32834 33701 33700 32835 32835 33689 33701 32837 33697 33712 33691 33689 32838 32838 33690 33691 33692 32840 32839 32839 32852 33692 32853 32852 32839 33692 32841 32840 34587 33683 32841 34588 34587 32841 32841 33693 34588 32841 33692 33693 32842 33694 33711 33712 33694 32842 35451 33676 32843 32843 33702 35451 32843 32846 33702 32843 32845 32846 33715 32845 32843 32843 32847 33715 32844 35474 35475 32844 33722 35474 32844 32845 33722 32846 32845 32844 35475 32846 32844 33723 33722 32845 33724 33723 32845 32845 33715 33724 35450 33702 32846 36955 35450 32846 32846 35475 36955 32847 33703 33715 32866 32851 32850 34583 32866 32850 34584 34583 32850 34585 34584 32850 34586 34585 32850 32850 33682 34586 32852 32857 33692 32852 32856 32857 32852 32853 32856 32858 32856 32853 32859 32858 32853 34601 32862 32854 32854 33711 34601 32858 32857 32856 33705 33692 32857 33719 33705 32857 32857 32858 33719 33727 33719 32858 33732 33727 32858 32858 32859 33732 32859 34617 34622 32859 34614 34617 34615 34614 32859 32859 33729 34615 32859 32860 33729 34622 33732 32859 32860 32861 33729 32861 32864 33729 32861 32863 32864 33721 33720 32862 34601 33721 32862 32864 32863 32862 33720 32864 32862 32864 33720 33729 32865 33725 34599 34599 33704 32865 32872 32867 32866 34606 32872 32866 32866 34600 34606 32866 34593 34600 32866 34583 34593 32872 32871 32867 33737 32873 32868 32868 33735 33737 32868 32869 33735 32870 32869 32868 32873 32870 32868 33736 33735 32869 33738 33736 32869 32869 33734 33738 32869 33733 33734 32869 32870 33733 33747 33733 32870 34659 33747 32870 32870 33767 34659 32870 32891 33767 32870 32886 32891 32870 32873 32886 34620 32883 32871 32871 32872 34620 32872 34612 34620 32872 34605 34612 34606 34605 32872 32873 32878 32886 33737 32878 32873 32874 33741 33742 32874 33739 33741 32874 33737 33739 32874 32877 33737 32878 32877 32874 32874 32875 32878 32876 32875 32874 33742 32876 32874 32887 32878 32875 32889 32887 32875 32890 32889 32875 32875 32879 32890 32875 32876 32879 32882 32879 32876 33742 32882 32876 32877 32878 33737 32888 32886 32878 32878 32887 32888 32879 32882 32890 32890 32882 32880 32893 32890 32880 33757 32893 32880 33770 33757 32880 32880 32881 33770 32882 32881 32880 32881 33769 33770 35471 33769 32881 35499 35471 32881 32881 32882 35499 32882 35497 35499 32882 34628 35497 32882 33742 34628 34620 33753 32883 33753 32884 32883 33758 33754 32884 32884 33753 33758 32885 33763 33764 32885 33759 33763 32886 32888 32891 32892 32888 32887 32887 32889 32892 32892 32891 32888 32893 32892 32889 32889 32890 32893 33771 33767 32891 32891 32892 33771 33778 33771 32892 33779 33778 32892 32892 33772 33779 32892 32893 33772 33773 33772 32893 32893 33768 33773 32893 33757 33768 33776 32895 32894 33784 32896 32895 32895 33776 33784 32898 32897 32896 33783 32898 32896 33784 33783 32896 33790 32899 32897 32897 32898 33790 34670 33790 32898 32898 34665 34670 32898 33783 34665 32901 32900 32899 33790 32901 32899 32900 32901 34676 32932 32911 32900 34676 32932 32900 32901 33790 34676 32904 32903 32902 32907 32904 32902 32912 32908 32904 32913 32912 32904 32904 32907 32913 33795 32923 32906 33796 33795 32906 32925 32924 32908 33798 32925 32908 32908 32914 33798 32908 32912 32914 32909 32915 32917 32932 32920 32911 32923 32914 32912 32912 32913 32923 32914 33797 33798 32914 32923 33797 32915 32916 32917 32928 32917 32916 32918 32919 33793 32919 32930 33793 32920 32932 33800 33794 32922 32921 33802 33794 32921 32921 33801 33802 32923 33795 33797 32935 32926 32925 33798 32935 32925 32927 32936 32937 33799 32930 32929 32929 32931 33799 33804 33793 32930 33805 33804 32930 32930 33799 33805 33811 33799 32931 34682 33800 32932 35538 34682 32932 32932 34676 35538 33807 33801 32933 32933 32934 33807 33812 33807 32934 33798 33797 32935 32943 32937 32936 32961 32953 32938 32938 32939 32961 33808 32961 32939 32939 32943 32952 34710 32965 32940 32940 33810 34710 32940 32941 33810 32941 32942 33810 32942 32947 33810 34721 34715 32944 32944 32969 34721 32970 32969 32944 32944 32945 32970 32946 32945 32944 34715 32946 32944 34703 33812 32945 35572 34703 32945 32945 32946 35572 37055 35572 32946 37064 37055 32946 32946 36337 37064 32946 34715 36337 32948 32951 33821 32966 32951 32948 33821 32951 32949 35586 33821 32949 35595 35586 32949 32949 34729 35595 32949 32950 34729 32951 32950 32949 34736 34729 32950 32950 33820 34736 32950 32966 33820 32950 32951 32966 32955 32956 32964 34734 32974 32957 32957 34719 34734 34720 34719 32957 34728 34720 32957 32957 32958 34728 32958 34718 34728 32958 34717 34718 32960 32968 32970 33808 32977 32961 34710 33835 32965 32969 32968 32967 32971 32969 32967 32975 32971 32967 32968 32969 32970 32969 32971 34721 32971 32974 34734 32975 32974 32971 34730 32981 32972 32972 32977 34730 34732 34716 32973 32973 33832 34732 33834 32979 32976 34712 33834 32976 32976 33826 34712 32977 33825 34730 32977 33824 33825 32977 33808 33824 33834 32982 32978 32978 32979 33834 32980 32981 33831 32981 34730 34731 34731 33831 32981 33839 32988 32982 32982 33838 33839 32982 33834 33838 33845 32984 32983 33845 32985 32984 32985 34739 34747 34773 34739 32985 34774 34773 32985 34816 34774 32985 35610 34816 32985 32985 33845 35610 34747 34740 32985 33847 33846 32986 32986 32989 33847 32986 32987 32989 33830 32989 32987 35580 33830 32987 32987 33836 35580 32994 32993 32988 33844 32994 32988 32988 33839 33844 34758 33847 32989 32989 33816 34758 33850 32991 32990 33857 33850 32990 32990 32998 33857 33850 32992 32991 33850 33010 32992 32993 32994 33001 33844 33001 32994 32995 33855 34752 34752 33845 32995 32996 33002 33006 33004 32998 32997 33005 33004 32997 32997 33003 33005 32998 33004 33857 32999 33000 33854 34751 33854 33000 33861 33858 33001 33001 33844 33861 33863 33006 33002 33002 33856 33863 33868 33005 33003 33003 33007 33868 34760 33857 33004 34779 34760 33004 33004 33005 34779 33005 33869 34779 33005 33868 33869 33869 33868 33007 33007 33865 33869 33867 33865 33007 33007 33866 33867 34835 33886 33008 33008 33009 34835 33009 34834 34835 33009 33851 34834 33009 33849 33851 33009 33010 33849 33010 33848 33849 33850 33848 33010 33011 33017 33018 33011 33012 33017 33015 33014 33013 33014 33876 33877 33014 33870 33876 33879 33870 33014 33881 33879 33014 33882 33881 33014 33014 33015 33882 34824 34808 33016 33016 33884 34824 33016 33017 33884 33018 33017 33016 33032 33027 33021 33899 33023 33022 33022 33892 33899 33022 33024 33892 33898 33030 33023 33900 33898 33023 33023 33899 33900 33893 33892 33024 33024 33041 33893 33024 33025 33041 33025 33026 33041 33027 33031 33905 33032 33031 33027 33897 33029 33028 33898 33897 33028 33028 33030 33898 33904 33040 33029 33029 33897 33904 34842 33905 33031 33031 34841 34842 33031 33888 34841 33031 33032 33888 33889 33888 33032 33032 33887 33889 33906 33035 33033 34850 33906 33033 33033 34849 34850 33033 34848 34849 33033 33045 34848 33037 33036 33034 33034 33035 33037 34840 33037 33035 34845 34840 33035 33035 33906 34845 33036 33881 33882 33890 33881 33036 35655 33890 33036 33036 34839 35655 34840 34839 33036 33036 33037 34840 33894 33039 33038 33904 33894 33038 33038 33040 33904 33909 33048 33039 33039 33894 33909 33041 33052 33893 33041 33042 33052 33042 33049 33052 34842 33911 33043 33043 33905 34842 33062 33046 33044 33045 33046 34848 33046 33062 34848 33047 33903 33908 33909 33903 33047 33047 33048 33909 33049 33050 33052 33051 33050 33049 33072 33051 33049 33900 33899 33050 33050 33896 33900 33910 33896 33050 33050 33051 33910 33892 33052 33050 33899 33892 33050 33051 33071 33910 33072 33071 33051 33052 33892 33893 33055 33054 33053 33912 33055 33053 33053 33056 33912 34854 33064 33055 33055 33912 34854 34854 33912 33056 34855 34854 33056 33056 33057 34855 35677 34855 33057 33057 33913 35677 33081 33073 33059 33089 33081 33059 33059 33077 33089 33060 33061 33062 33079 33061 33060 33920 33063 33061 34861 33920 33061 33061 33080 34861 33061 33079 33080 33063 33062 33061 34853 34848 33062 33062 34852 34853 33062 33063 34852 35673 34852 33063 33063 33920 35673 33921 33065 33064 33066 33067 33075 33068 33067 33066 33946 33068 33066 33066 33095 33946 33066 33072 33095 33066 33070 33072 33075 33070 33066 33957 33075 33067 33959 33957 33067 33067 33068 33959 34882 33959 33068 33068 33946 34882 33918 33071 33069 33922 33918 33069 33069 33084 33922 33069 33074 33084 33069 33070 33074 33071 33070 33069 33075 33074 33070 33070 33071 33072 33071 33895 33910 33918 33895 33071 33072 33073 33095 33096 33095 33073 33097 33096 33073 33073 33081 33097 33074 33083 33084 33085 33083 33074 33087 33085 33074 33088 33087 33074 33074 33075 33088 33957 33088 33075 33078 33077 33076 33923 33078 33076 33077 33078 33089 34869 33089 33078 33078 33923 34869 33080 34860 34861 33080 33090 34860 33102 33097 33081 33081 33089 33102 33093 33091 33082 33082 33092 33093 33925 33084 33083 33083 33916 33925 33083 33085 33916 33925 33922 33084 33939 33916 33085 33085 33086 33939 33087 33086 33085 33086 33108 33939 33109 33108 33086 33086 33087 33109 33113 33109 33087 33114 33113 33087 33087 33088 33114 33957 33114 33088 33940 33102 33089 34869 33940 33089 33090 33935 34860 33936 33935 33090 33937 33936 33090 33091 33093 33929 33930 33929 33093 33093 33094 33930 33952 33930 33094 35707 33952 33094 33094 33931 35707 33932 33931 33094 33943 33932 33094 33095 33100 33946 33095 33096 33100 33096 33097 33100 33101 33100 33097 33102 33101 33097 33098 33110 33937 34868 33938 33099 33099 34867 34868 34875 33946 33100 33100 33101 34875 33101 33947 34875 33101 33933 33947 33101 33102 33933 33934 33933 33102 33940 33934 33102 33944 33943 33103 33103 33104 33944 34879 33944 33104 33107 33106 33105 33938 33107 33105 33117 33112 33106 33967 33117 33106 33106 33966 33967 34892 33966 33106 33106 33107 34892 33107 34880 34892 33107 33938 34880 34889 33939 33108 33108 33955 34889 33108 33113 33955 33108 33109 33113 34877 33937 33110 33110 33949 34877 33110 33948 33949 33961 33948 33110 33110 33111 33961 33111 33131 33961 33113 33954 33955 33113 33114 33954 33960 33954 33114 33114 33957 33960 33976 33973 33115 33967 33118 33117 34000 33134 33119 33119 33135 34000 33136 33135 33119 33119 33120 33136 34894 33136 33120 33120 33962 34894 33964 33962 33120 33120 33951 33964 33121 33124 33125 33970 33124 33121 33121 33122 33970 33123 33122 33121 33137 33123 33121 33122 33136 34894 33122 33123 33136 33122 33953 33970 34886 33953 33122 34887 34886 33122 34894 34887 33122 33123 33135 33136 34895 33135 33123 33123 33137 34895 33128 33126 33124 33970 33128 33124 33126 33125 33124 33128 33127 33126 34888 34879 33127 33127 33953 34888 33127 33128 33953 33970 33953 33128 33998 33141 33130 33130 33975 33998 34891 33961 33131 33131 33132 34891 33132 33978 34891 33132 33973 33978 33992 33976 33133 33133 33134 33992 33995 33992 33134 34000 33995 33134 34902 34000 33135 33135 34895 34902 34910 34895 33137 33137 34001 34910 33137 33152 34001 33140 33139 33138 33971 33140 33138 33138 33968 33971 33990 33974 33139 33991 33990 33139 33139 33988 33991 33989 33988 33139 33139 33140 33989 35734 33989 33140 36477 35734 33140 33140 36465 36477 33140 33972 36465 33140 33971 33972 33998 33151 33141 33142 33153 34005 33167 33158 33142 33142 33166 33167 34012 33166 33142 33143 33982 33996 33143 33149 33982 33143 33146 33149 33143 33144 33146 33145 33144 33143 33161 33145 33143 34009 33161 33143 34897 34009 33143 33143 34896 34897 34911 34896 33143 33143 33996 34911 33148 33146 33144 33155 33148 33144 33144 33154 33155 33146 33147 33149 33148 33147 33146 33982 33149 33147 33983 33982 33147 33147 33150 33983 33147 33148 33150 33155 33150 33148 33985 33983 33150 33150 33156 33985 33150 33155 33156 33151 33998 33999 33152 33177 34001 33153 33160 34005 33167 33159 33158 33167 33166 33159 34009 34007 33161 33162 33163 33164 33189 33165 33164 33190 33189 33164 33165 33189 34011 34012 33179 33166 33168 34904 34920 33168 33999 34904 34920 34918 33169 34935 33183 33170 33170 33171 34935 33171 34932 34935 33171 34014 34932 34018 34017 33172 34019 34018 33172 33172 33173 34019 33173 33184 34019 33176 33199 34032 33178 33177 33176 34032 33178 33176 34910 34001 33177 34925 34910 33177 33177 33178 34925 35738 34925 33178 36501 35738 33178 33178 35750 36501 33178 34936 35750 33178 34032 34936 34012 33181 33179 33181 33180 33179 34042 33218 33180 33180 33181 34042 33181 34013 34043 33181 34012 34013 34043 34042 33181 34044 33193 33182 34941 34044 33182 33182 34939 34941 33182 33183 34939 33183 34935 34939 34020 34019 33184 35740 34026 33186 33186 34927 35740 33186 34027 34927 35733 34022 33186 33186 34025 35733 34026 34025 33186 33189 34010 34011 34947 34010 33189 33189 33190 34947 33190 34946 34947 33190 34049 34946 36500 35746 33191 33191 35749 36500 33191 34933 35749 33191 33192 34933 33192 34010 34933 34011 34010 33192 34050 33203 33193 33193 34044 34050 34055 34047 33195 33195 33208 34055 33199 33198 33197 34034 33199 33197 34036 34034 33197 33197 34035 34036 33197 33198 34035 33198 33200 33201 33198 33199 33200 33198 33201 34035 34034 34032 33199 33201 33202 34035 33202 33205 34035 33206 33205 33202 34051 33207 33203 33203 34050 34051 34037 34035 33205 34040 34037 33205 34052 34040 33205 33205 33206 34052 33206 33212 34052 33214 33212 33206 34054 33220 33207 34951 34054 33207 33207 34051 34951 34067 34055 33208 33208 33216 34067 33209 33210 33230 33211 33210 33209 34061 33230 33210 34063 34061 33210 33210 34062 34063 33210 33211 34062 34969 34062 33211 34056 34052 33212 33212 33213 34056 33214 33213 33212 33213 33217 34056 33213 33214 33217 33214 33215 33217 33232 33217 33215 33216 33245 34067 33216 33244 33245 33217 33239 34056 33217 33232 33239 34955 33219 33218 34956 34955 33218 33218 34948 34956 33218 34042 34948 34075 33240 33219 34955 34075 33219 33220 33221 34064 33222 33221 33220 34054 33222 33220 34973 34972 33221 33221 34953 34973 33221 33222 34953 34954 34953 33222 33222 34054 34954 33225 34957 34974 33225 34065 34957 34059 34058 33226 34060 33228 33227 33227 34057 34060 33228 33241 33243 33242 33241 33228 34060 33242 33228 33238 33231 33230 34061 33238 33230 33231 33247 33248 33231 33238 33247 34079 33239 33232 33232 33262 34079 33232 33261 33262 34074 33261 33232 33235 33236 34955 33236 34075 34955 33236 34069 34075 34061 33247 33238 34079 34056 33239 34075 34068 33240 34071 33243 33241 34985 34071 33241 33241 33242 34985 33242 34979 34985 33242 34962 34979 33242 34066 34962 33242 34060 34066 34071 34070 33243 34078 33246 33244 34080 34067 33245 33245 34077 34080 34078 33251 33246 34073 33248 33247 33247 34061 34073 34073 34072 33248 33248 34072 34082 33249 33261 34074 33268 33255 33250 34070 33268 33250 34096 33254 33253 33254 34069 34076 34984 34069 33254 34996 34984 33254 33254 34096 34996 34102 33265 33255 35003 34102 33255 35018 35003 33255 33255 35004 35018 33255 33266 35004 33268 33266 33255 33256 34087 34089 33256 34086 34087 33256 33257 34086 33258 33257 33256 34089 33258 33256 34093 34086 33257 33257 33259 34093 34088 33260 33258 34089 34088 33258 34106 34093 33259 34107 34106 33259 34118 34107 33259 33260 34088 34090 33262 33261 33260 34090 33262 33260 34994 34079 33262 33262 34090 34994 34092 33273 33263 34109 33280 33264 33264 33265 34109 33265 34100 34109 34102 34100 33265 35793 35004 33266 33266 35005 35793 33266 33267 35005 33268 33267 33266 35783 35005 33267 33267 34990 35783 33267 33268 34990 33268 34070 34990 33269 34081 35008 33269 33270 34081 33271 33270 33269 35008 34094 33269 34119 34114 33273 34098 34097 33274 33275 34108 35009 35009 34099 33275 35032 34104 33276 33276 33277 35032 33277 34110 35019 33277 35019 35032 34111 33281 33278 34112 34111 33278 33278 33279 34112 33279 34094 34112 34111 34110 33281 34113 33283 33282 34131 34113 33282 33282 33310 34131 33283 34114 34119 33283 34113 34114 33288 33287 33284 33285 34117 34124 33285 34109 34117 33286 34115 34135 33287 33288 34123 33287 34120 35047 34122 34120 33287 34123 34122 33287 33288 33289 34123 35058 34136 33290 34128 33293 33291 35044 34128 33291 33291 34144 35044 33291 34125 34144 34127 34125 33291 34159 34127 33291 34161 34159 33291 33291 33301 34161 33291 33292 33301 33292 33296 33301 33302 33298 33297 33297 33299 33302 33298 33302 34150 34150 34149 33298 34150 33302 33299 35050 34148 33300 33300 34124 35050 33305 33304 33303 33311 33307 33304 33304 33306 33311 33304 33305 33306 34169 34138 33305 34138 33306 33305 34139 33311 33306 33306 34137 34139 34138 34137 33306 33307 33311 34140 33307 34154 34155 33307 34140 34154 34170 34165 33308 33308 33309 34170 35069 34170 33309 35071 35069 33309 33309 34156 35071 33310 33313 34145 33310 34130 34131 34145 34130 33310 33311 34139 34140 33314 33313 33312 33316 33314 33312 33313 33314 34157 35071 34157 33314 33314 34171 35071 33314 33316 34171 35078 34171 33316 33316 34179 35078 33318 33320 33321 35084 33320 33318 34176 33324 33319 33319 33322 34176 35085 33321 33320 35086 35085 33320 33320 35084 35086 34180 33325 33321 35085 34180 33321 33322 33323 34176 33323 34158 34176 35093 33330 33324 33324 34176 35093 35095 34192 33326 35099 35095 33326 33326 33327 35099 33327 35098 35099 35101 35098 33327 33327 33331 35101 34198 34190 33328 33328 33329 34198 35105 34198 33329 35106 35105 33329 33329 34203 35106 33329 33333 34203 34201 34199 33330 35093 34201 33330 33331 35100 35101 33331 33332 35100 33332 33335 35100 33333 34202 34203 35108 33335 33334 35104 35100 33335 35108 35104 33335 33341 33340 33336 34212 33341 33336 33336 34205 34212 33339 33338 33337 33349 33339 33337 33338 35120 35129 33338 33339 35120 33339 34220 35120 33339 34219 34220 33339 33371 34219 33339 33361 33371 33339 33349 33361 33340 33345 33347 33346 33345 33340 33340 33341 33346 34217 33346 33341 33341 34212 34217 35128 35124 33342 35893 35128 33342 34216 33348 33343 34218 33357 33345 33345 33346 34218 35111 34218 33346 33346 34217 35111 33348 34219 34221 33348 34216 34219 34221 33350 33348 33362 33361 33349 34221 33370 33350 33366 33352 33351 33351 33365 33366 33368 33367 33353 33353 33363 33368 33353 33357 33363 35134 34228 33354 33354 33355 35134 33356 33355 33354 33372 33356 33354 34228 33372 33354 33355 33368 35134 33355 33356 33368 33356 33367 33368 34222 33363 33357 33357 34218 34222 33371 33361 33358 33358 33359 33371 33360 33359 33358 34221 33360 33358 34227 34221 33358 33358 33361 33362 34219 33371 33359 33359 33360 34219 34221 34219 33360 35136 33368 33363 33363 34218 35136 34222 34218 33363 33364 34224 34225 34226 34224 33364 33364 33369 34226 35135 35134 33368 35136 35135 33368 34235 34226 33369 33369 33378 34235 33370 34221 34227 33372 34228 34232 33373 33374 33379 34229 33379 33374 34230 34229 33374 33374 33375 34230 35159 34230 33375 33375 34244 35159 33376 33377 33381 33385 33381 33377 34238 33385 33377 33377 33380 34238 35919 35146 33379 35920 35919 33379 33379 34229 35920 35163 34238 33380 33380 33382 35163 33382 34246 35163 33382 33388 34246 33384 33385 35161 35943 34245 33384 33384 35162 35943 33384 35161 35162 33385 34238 35163 35163 35161 33385 33386 33391 33392 33386 33392 34255 35160 34244 33387 35166 35160 33387 33388 33395 34246 33390 33391 33393 33392 33391 33390 34259 33392 33390 34259 34255 33392 34261 34246 33395 33395 33396 34261 34265 34261 33396 33396 33405 34265 33406 33405 33396 34262 33398 33397 33397 34252 34262 34263 34252 33397 34264 34263 33397 34266 34260 33399 33399 33403 34266 33399 33402 33403 33401 35169 35177 33401 34269 35169 33404 33403 33402 35179 35178 33403 33403 33404 35179 35178 34266 33403 33404 34272 35179 35171 34265 33405 35176 35171 33405 33405 33406 35176 33406 34271 35176 35182 33408 33407 35182 34273 33408 33411 33410 33409 33418 33411 33409 33409 33410 33420 33410 33412 33419 33410 33411 33412 33410 33419 33420 33413 33412 33411 34283 33413 33411 33411 33418 34283 33412 33413 33414 34283 34277 33413 34277 33414 33413 35185 34284 33414 35972 35185 33414 33414 34278 35972 33414 34277 34278 34286 34285 33415 33415 34284 34286 34285 33417 33416 33417 34285 34290 33418 34276 34283 34282 34276 33418 33428 33424 33421 35191 33428 33421 35967 35191 33421 33421 34289 35967 35202 34291 33422 33422 33423 35202 35206 35202 33423 33423 33429 35206 33427 33426 33424 33428 33427 33424 33437 33432 33425 34299 33437 33425 34300 34299 33425 33425 34295 34300 33425 33426 34295 33426 34292 34295 33426 33427 34292 34293 34292 33427 35198 34293 33427 33427 33428 35198 33428 35197 35198 33428 35196 35197 33428 35192 35196 35193 35192 33428 33428 35191 35193 33429 33430 33431 33429 34296 35206 33429 34294 34296 33429 33431 34294 34302 34294 33431 33437 33436 33432 33444 33440 33433 33445 33444 33433 34316 33445 33433 33433 33439 34316 33434 34297 34302 34298 34297 33434 34310 34298 33434 34317 34310 33434 33434 33435 34317 33435 34304 34317 33436 33437 34299 33442 33439 33438 33438 33441 33442 33439 33443 34316 33439 33442 33443 33440 33444 34305 33450 33442 33441 33451 33443 33442 33442 33450 33451 35227 34316 33443 33443 34313 35227 33443 33451 34313 35220 34305 33444 35222 35220 33444 33444 33445 35222 35224 35222 33445 33445 34316 35224 35228 33458 33446 33446 33447 35228 33448 33447 33446 35236 35228 33447 35996 35236 33447 33447 35995 35996 33447 33448 35995 33448 35220 35995 33455 33450 33449 34313 33455 33449 34314 34313 33449 33449 33454 34314 33455 33451 33450 33451 33455 34313 34312 33454 33452 33452 33453 34312 33453 34311 34312 34315 34314 33454 33454 34312 34315 34325 33459 33456 33456 33468 34325 33470 33468 33456 34317 34304 33457 33457 34309 34317 35236 35230 33458 33458 35228 35236 35237 33463 33459 33459 34325 35237 33460 33461 33467 33462 33461 33460 33461 33462 34320 33461 33466 33467 33461 33465 33466 34321 33465 33461 35243 34321 33461 33461 34320 35243 34322 34319 33462 33462 34319 34320 35229 34318 33463 35237 35229 33463 33464 33473 33474 34324 33473 33464 33464 33465 34324 33465 34321 34324 35249 34325 33468 33468 34326 35249 33468 33469 34326 33470 33469 33468 35266 34326 33469 33469 33476 35266 34327 33477 33471 34334 34327 33471 35246 34334 33471 35247 35246 33471 33471 33472 35247 33473 33472 33471 33474 33473 33471 33472 34323 35247 33472 33473 34323 34324 34323 33473 33476 33479 35266 33480 33479 33476 33482 33480 33476 33479 34331 35266 33479 34330 34331 33479 33480 34330 35274 34330 33480 33480 34349 35274 33491 33487 33481 34348 33491 33481 34335 33486 33483 34336 34335 33483 33483 34328 34336 34357 34348 33484 34364 34357 33484 34358 33490 33485 34359 34358 33485 33485 34350 34359 33485 34335 34350 33485 33486 34335 33489 33488 33487 33491 33489 33487 34365 33493 33488 33488 33489 34365 34366 34365 33489 33489 33491 34366 34386 34366 33491 33491 34357 34386 33491 34348 34357 33492 33493 34370 33493 34369 34370 33493 34365 34369 34372 34371 33494 34373 34372 33494 33494 33497 34373 33508 33500 33495 34393 33508 33495 33495 33496 34393 34395 34393 33496 33496 34379 34395 33496 34359 34379 34374 34373 33497 34376 34374 33497 33497 33498 34376 34392 34376 33498 33498 33503 34392 33498 33499 33503 34398 34361 33502 35281 34392 33503 35282 35281 33503 33503 33504 35282 33505 33504 33503 36043 35282 33504 33504 35283 36043 33504 33505 35283 35285 35283 33505 33505 34399 35285 33505 33511 34399 34390 33509 33506 35286 34399 33507 33507 35284 35286 33507 34400 35284 34399 33511 33507 33508 34393 34396 33509 34391 34402 33509 34390 34391 33510 34403 34404 34411 33516 33512 33512 34407 34411 33512 33513 34407 35296 34407 33514 33514 34408 35296 34411 34410 33515 33515 33516 34411 33515 34410 34415 34412 33521 33517 33517 34409 34412 33520 33518 33517 33521 33520 33517 34419 33522 33518 33518 33520 34419 35298 34419 33520 35299 35298 33520 33520 33521 35299 33521 34412 36061 36061 35299 33521 33526 33525 33523 33523 33524 34429 33525 33524 33523 34434 34429 33524 33524 34423 34434 33524 33525 34423 33525 33526 35304 36074 34423 33525 33525 35314 36074 33525 35304 35314 33526 34415 35304 33526 33527 34415 34425 33529 33528 33528 33535 34425 36065 35301 33529 36075 36065 33529 33529 34425 36075 34416 33531 33530 33544 33537 33531 34417 33544 33531 33531 34416 34417 33532 33538 34424 33532 34424 35289 33533 34430 34432 33533 33534 34430 34431 34430 33534 34426 34425 33535 34432 34426 33535 33536 33537 33540 33544 33540 33537 33538 33541 34428 34428 34424 33538 33540 33544 33547 34436 33550 33543 34442 34436 33543 33543 34435 34442 34433 33547 33544 33544 33545 34433 33546 33545 33544 34427 33546 33544 33544 34417 34427 33545 33546 35307 34439 34433 33545 35330 34439 33545 33545 35307 35330 33546 34427 35307 34433 33548 33547 33548 34433 34438 35331 34435 33549 33549 35328 35331 33549 35327 35328 33549 34441 35327 33549 34434 34441 34437 34431 33550 33550 34436 34437 34449 34445 33551 34470 34449 33551 36093 35322 33552 33552 35340 36093 35341 35340 33552 33552 34446 35341 34450 33556 33553 34452 34450 33553 34467 34458 33555 35353 34467 33555 33555 34457 35353 33555 34453 34457 34465 33557 33556 33556 34456 34465 33556 34451 34456 33556 34450 34451 34465 33565 33557 35346 34455 33558 35348 35346 33558 33558 34460 35348 34465 33568 33565 34469 33569 33568 35351 34469 33568 35360 35351 33568 33568 34465 35360 33571 33570 33569 33573 33571 33569 34469 33573 33569 33570 33571 33573 33572 33573 34471 35365 34471 33573 33573 35362 35365 33573 35361 35362 33573 35352 35361 33573 34469 35352 33574 33585 33586 33587 33585 33574 33575 34474 34475 33575 33576 34474 34475 33581 33575 33576 33577 34474 33577 33578 34477 34476 34474 33577 34477 34476 33577 33578 33582 35369 35369 34477 33578 34472 33590 33579 33579 34471 34472 35366 34473 33580 33580 33581 35366 33581 34475 35366 33582 33583 35370 35370 35369 33582 33583 35371 35379 35372 35371 33583 35379 35370 33583 34487 34479 33584 33585 33587 33588 34482 33586 33585 35377 34482 33585 33585 34488 35377 33585 33588 34488 34481 34480 33586 34482 34481 33586 33588 33591 34488 33589 34490 34491 33589 34489 34490 33589 34483 34489 35373 33599 33590 33590 34472 35373 35384 34488 33591 36128 34515 33592 33592 34491 36128 34515 33593 33592 33593 34516 35386 36132 34516 33593 33593 34515 36132 35380 34485 33595 33595 34502 35380 33595 33596 34502 33596 33597 34502 33598 33597 33596 33607 33598 33596 33596 33606 33607 33597 34501 34502 33607 33605 33598 33599 35373 35397 34506 33608 33599 35396 34506 33599 33599 34503 35396 35397 34503 33599 34494 33601 33600 34495 34494 33600 34500 34495 33600 33600 34492 34500 34494 33602 33601 34496 34493 33602 34497 34496 33602 35370 34497 33602 33602 34494 35370 34517 34509 33603 35402 34517 33603 33604 35389 35395 35400 35389 33604 33604 34508 35400 33608 34507 34511 33608 34506 34507 33609 34512 34516 33609 33616 34512 34516 34513 33609 35407 34523 33610 33610 33611 35407 36138 35407 33611 33611 34505 36138 33611 34504 34505 33614 33613 33612 34530 33621 33613 34512 33616 33615 33615 33620 34512 35404 34524 33617 33617 33618 35404 35405 33620 33617 33617 34525 35405 33617 34524 34525 33618 33621 35404 34527 33621 33618 33618 34518 34527 33619 34528 34529 35401 34512 33620 36133 35401 33620 33620 35405 36133 34526 33623 33621 34527 34526 33621 33621 34530 35404 33622 34526 34533 33622 33623 34526 34534 33625 33624 33624 34531 34534 34534 33627 33625 33629 33628 33626 35412 34535 33627 35417 35412 33627 33627 35408 35417 33627 34532 35408 33627 34531 34532 34534 34531 33627 33634 33633 33628 33636 33634 33628 33628 33629 33636 35420 33636 33629 33629 34536 35420 33632 33631 33630 33631 34540 34542 34541 34540 33631 33631 33642 34541 33631 33632 33642 33632 33641 33642 34544 34543 33634 35421 34544 33634 33634 33636 35421 33636 35420 35421 33639 33638 33637 34538 33639 33637 34542 34538 33637 33637 33638 34542 33638 33639 34533 34526 34518 33638 34533 34526 33638 33639 33640 34533 33639 34538 34539 34547 33642 33641 33641 33650 34547 33641 33643 33650 34545 34541 33642 34547 34545 33642 33644 34549 34552 33644 34548 34549 33653 33646 33645 33645 33652 33653 33646 33653 35428 34566 33648 33647 35425 34566 33647 35444 34574 33648 33648 35440 35444 33648 35434 35440 33648 34566 35434 34545 33659 33649 34559 34547 33650 33650 33651 34559 35438 34559 33651 35439 35438 33651 33651 34558 35439 33652 34562 35432 35432 33653 33652 35433 35428 33653 33653 35432 35433 33655 35437 35439 35441 35437 33655 33655 34563 35441 33655 33656 34563 33657 33656 33655 33670 33657 33655 34555 33670 33655 34558 34555 33655 35439 34558 33655 36180 34563 33656 36183 36180 33656 33656 33657 36183 33657 33670 34576 33657 34576 36183 33666 33665 33658 35422 33660 33659 33659 34545 35422 34572 33669 33660 35435 34572 33660 33660 35422 35435 33678 33670 33661 33661 33662 33678 35445 34568 33663 36932 35445 33663 36936 36932 33663 33663 36173 36936 33663 33664 36173 33665 33664 33663 34568 33665 33663 33664 36172 36173 33664 34567 36172 33664 33666 34567 33664 33665 33666 33671 33667 33665 34568 33671 33665 35442 34567 33666 33666 35426 35442 33668 33671 34564 34577 34576 33670 33670 33678 34577 34569 34564 33671 33671 34568 34569 33672 33676 34578 33675 33674 33673 34575 33675 33673 33673 34570 34575 33674 33675 33677 34582 33677 33675 35453 34582 33675 36187 35453 33675 33675 34575 36187 35451 34578 33676 34587 34577 33678 33678 33683 34587 35448 33681 33680 33680 34573 35448 35448 34592 33681 33682 34582 34586 33684 33685 33697 33687 33685 33684 33688 33687 33684 33687 33686 33685 34594 33697 33685 35455 34594 33685 33685 33686 35455 33686 33687 33688 33686 35454 35455 35458 35454 33686 33686 33688 35458 33688 34579 35458 33689 33691 33701 34598 33691 33690 33690 34595 34598 34596 33701 33691 34598 34596 33691 34590 33693 33692 33692 33706 34590 33692 33705 33706 34589 34588 33693 34590 34589 33693 33694 33695 34602 33696 33695 33694 33712 33696 33694 34602 33711 33694 33695 33696 36215 36215 34602 33695 33696 34594 35461 33696 33697 34594 33712 33697 33696 33696 35461 36215 33698 33699 33713 33699 33701 34596 33699 33700 33701 33714 33713 33699 34603 33714 33699 34609 34603 33699 33699 34596 34609 35450 35449 33702 33702 35449 35451 33724 33715 33703 33725 33724 33703 34599 33725 33703 33703 33704 34599 33707 33706 33705 33728 33707 33705 33705 33719 33728 35468 35467 33706 33706 33707 35468 35467 34590 33706 33707 33716 35468 34607 33716 33707 34608 34607 33707 33707 33728 34608 33708 33721 34601 36221 33721 33708 33708 36211 36221 33708 33709 36211 33710 33709 33708 34601 33710 33708 33709 36210 36211 36215 36210 33709 33709 34602 36215 33709 33710 34602 33710 33711 34602 34601 33711 33710 33713 33714 34591 35462 34591 33714 33714 35456 35462 36204 35456 33714 33714 34603 36204 36962 36201 33716 33716 36206 36962 33716 33717 36206 33718 33717 33716 34607 33718 33716 36201 35468 33716 36208 36206 33717 33717 36207 36208 33717 35470 36207 33717 33718 35470 33718 33731 35470 33718 33726 33731 34607 33726 33718 33719 33726 33728 33727 33726 33719 33720 33721 33729 36221 33729 33721 33722 34630 35474 33722 34619 34630 33722 33723 34619 33723 33725 34619 33723 33724 33725 33725 33750 34619 34608 33728 33726 33726 34607 34608 33726 33730 33731 34621 33730 33726 33726 33727 34621 34622 34621 33727 33727 33732 34622 36233 34615 33729 33729 36221 36233 35487 35486 33730 36232 35487 33730 33730 34621 36232 35486 33731 33730 36228 35470 33731 33731 35486 36228 33747 33746 33733 33746 33734 33733 34623 33738 33734 33734 33746 34623 33740 33737 33735 34618 33740 33735 33735 33736 34618 35477 34618 33736 33736 33738 35477 33740 33739 33737 33738 34626 35477 33738 34624 34626 33738 34623 34624 34628 33741 33739 35488 34628 33739 33739 34629 35488 33739 34627 34629 33739 33740 34627 33740 34618 34627 34628 33742 33741 33743 33748 33755 33743 33746 33748 34625 33746 33743 35493 34625 33743 33743 34635 35493 33743 33744 34635 33745 33744 33743 33755 33745 33743 33744 34633 34635 34634 34633 33744 33744 33745 34634 34643 34634 33745 34644 34643 33745 33745 33755 34644 34625 34623 33746 33749 33748 33746 33746 33747 33749 33766 33749 33747 34659 33766 33747 33756 33755 33748 33748 33749 33756 33766 33756 33749 34631 34619 33750 33758 33753 33751 34636 33758 33751 36260 34636 33751 33751 36259 36260 33751 33752 36259 33753 33752 33751 33752 36254 36259 33752 35492 36254 33752 33753 35492 33753 34620 35492 35508 33760 33754 33754 34636 35508 33754 33758 34636 33755 33756 34644 34645 34644 33756 33756 33765 34645 33766 33765 33756 33774 33768 33757 33757 33770 33774 34642 33763 33759 33759 33760 34642 33760 34641 34642 35508 34641 33760 33776 33764 33761 33784 33776 33761 33761 33783 33784 34665 33783 33761 33761 33762 34665 33763 33762 33761 33764 33763 33761 35528 34665 33762 33762 34649 35528 33762 33763 34649 34650 34649 33763 33763 34642 34650 34658 34645 33765 35521 34658 33765 33765 33766 35521 35522 35521 33766 33766 34659 35522 35526 34659 33767 33767 33777 35526 33767 33771 33777 33782 33773 33768 33768 33774 33782 34639 33770 33769 35500 34639 33769 33769 35472 35500 33769 35471 35472 33775 33774 33770 34656 33775 33770 33770 34639 34656 33778 33777 33771 33781 33779 33772 33772 33780 33781 33772 33773 33780 33782 33780 33773 34655 33782 33774 33774 33775 34655 34661 34655 33775 33775 34656 34661 33777 35523 35526 35525 35523 33777 33777 34673 35525 33777 33778 34673 33778 33779 33781 33778 34672 34673 33778 33781 34672 33785 33781 33780 34666 33785 33780 33780 33782 34666 34680 34672 33781 33781 34660 34680 33781 33785 34660 35532 34666 33782 33782 34655 35532 34689 34660 33785 36287 34689 33785 33785 35534 36287 33785 34666 35534 33791 33788 33786 35527 35514 33787 33787 33788 35527 33788 34663 35527 34664 34663 33788 33788 33791 34664 35514 35482 33789 35538 34676 33790 36286 35538 33790 33790 36285 36286 33790 36276 36285 33790 35528 36276 33790 34670 35528 33792 33800 34695 33793 33804 34681 34698 33803 33794 33794 33802 34698 34706 33805 33799 33799 33811 34706 33800 34683 34695 33800 34682 34683 34705 33802 33801 33801 33806 34705 33807 33806 33801 34705 34698 33802 34708 34701 33803 33803 34698 34708 35539 34681 33804 35552 35539 33804 33804 33805 35552 36307 35552 33805 33805 35568 36307 33805 34707 35568 33805 34706 34707 33806 34714 35569 35581 34714 33806 33806 34697 35581 33806 34696 34697 33806 33807 34696 35569 34705 33806 33807 33812 34696 34701 33810 33809 33810 34709 34710 33810 34701 34709 33811 33813 34706 34703 34696 33812 33813 33814 34706 34711 34706 33814 33814 33819 34711 35586 35585 33815 33815 33821 35586 35585 33816 33815 35585 34758 33816 34724 34723 33817 33817 33822 34724 33817 33818 33822 35573 34711 33819 33819 34716 35573 33820 33827 33828 33820 33828 34736 33822 34722 34724 33823 34725 34727 34727 33824 33823 34727 33825 33824 33825 34727 34730 34714 34712 33826 33826 33835 34714 34742 33828 33827 33827 33829 34742 34742 34741 33828 34741 34736 33828 34744 34742 33829 33829 34739 34744 34740 34739 33829 34724 34722 33830 35580 34724 33830 34737 33836 33831 33831 34731 34737 34733 34732 33832 35588 34733 33832 33832 33833 35588 33833 34743 35588 33833 33837 34743 33840 33838 33834 34738 33840 33834 35591 34738 33834 35592 35591 33834 33834 34712 35592 33835 34710 34714 35582 35580 33836 33836 34737 35582 33837 33841 34743 33840 33839 33838 33839 33843 33844 33839 33840 33843 35609 33843 33840 33840 35597 35609 33840 34738 35597 34770 34743 33841 33841 33842 34770 33842 33853 34770 33842 33852 33853 35609 34745 33843 34745 33844 33843 33862 33861 33844 34746 33862 33844 33844 34745 34746 33845 34815 35610 33845 34752 34815 33846 33847 34758 34759 33856 33846 34818 34759 33846 35600 34818 33846 33846 34758 35600 33851 33849 33848 34749 33851 33848 34750 34749 33848 35601 34750 33848 33848 34748 35601 33848 33850 34748 33850 33857 34748 35616 34834 33851 33851 34749 35616 34751 33853 33852 33852 33854 34751 36372 34770 33853 36382 36372 33853 33853 35619 36382 33853 34807 35619 33853 34751 34807 34772 34752 33855 33855 34771 34772 33855 33860 34771 33855 33859 33860 33864 33863 33856 34759 33864 33856 34760 34748 33857 33860 33859 33858 34794 33860 33858 33858 34791 34794 33858 33861 34791 34794 34771 33860 33861 33862 34791 34792 34791 33862 35627 34792 33862 33862 35622 35627 33862 34746 35622 33867 33866 33863 33863 33865 33867 33863 33864 33865 34798 33865 33864 34818 34798 33864 33864 34759 34818 35614 33869 33865 35644 35614 33865 33865 34798 35644 35612 34779 33869 35614 35612 33869 33870 33871 33876 33872 33871 33870 33879 33872 33870 33871 33873 33876 33875 33873 33871 33871 33872 33875 34783 33875 33872 34823 34783 33872 33872 33880 34823 33872 33879 33880 34769 33876 33873 33873 34768 34769 33873 33874 34768 33875 33874 33873 35618 34768 33874 33874 34767 35618 33874 33875 34767 33875 34766 34767 34783 34766 33875 33878 33877 33876 34769 33878 33876 33877 33878 33883 33878 34769 34787 34805 33883 33878 35625 34805 33878 33878 34787 35625 33881 33880 33879 34838 34823 33880 33880 33891 34838 33880 33890 33891 33880 33881 33890 34805 33885 33883 33885 34788 34806 34805 34788 33885 34829 33887 33886 35637 34829 33886 33886 34835 35637 34829 33889 33887 34843 34841 33888 33888 33889 34843 35652 34843 33889 33889 35651 35652 33889 35650 35651 36406 35650 33889 33889 35647 36406 33889 35637 35647 33889 34829 35637 35655 33891 33890 33891 34837 34838 35654 34837 33891 35655 35654 33891 33897 33896 33894 33904 33897 33894 34851 33909 33894 33894 33895 34851 33896 33895 33894 33895 33918 34851 33895 33896 33910 33896 33897 33900 33897 33898 33900 34857 33903 33901 34858 34857 33901 34863 34858 33901 33901 33926 34863 33901 33902 33926 33903 33902 33901 33927 33926 33902 33902 33909 33927 33902 33903 33909 34857 33908 33903 33906 34844 34845 35663 34844 33906 33906 34850 35663 34857 33914 33907 33907 33908 34857 34851 33927 33909 33911 34842 34846 33924 33919 33911 33911 33923 33924 34869 33923 33911 35671 34869 33911 33911 35669 35671 33911 34847 35669 33911 34846 34847 35679 35677 33913 33913 34856 35679 33913 33914 34856 34857 34856 33914 33917 33916 33915 33928 33917 33915 33939 33928 33915 33915 33916 33939 33916 33917 33925 33926 33925 33917 34863 33926 33917 33917 33928 34863 33918 33927 34851 33918 33922 33927 36422 35673 33920 33920 35685 36422 33920 34861 35685 33922 33926 33927 33922 33925 33926 34864 34863 33928 33928 33945 34864 33928 33939 33945 33929 33930 33942 33952 33942 33930 33931 33963 35707 33931 33962 33963 35714 33962 33931 33931 35708 35714 33931 33932 35708 33932 34878 35708 33932 33944 34878 33932 33943 33944 34883 33947 33933 33933 33941 34883 33933 33934 33941 35706 33941 33934 33934 33940 35706 33935 34859 34860 36434 34859 33935 36438 36434 33935 33935 33936 36438 33936 35699 36438 33936 33937 35699 33937 34876 35699 34877 34876 33937 33938 34868 34880 34889 33945 33939 35713 35706 33940 33940 35671 35713 33940 34869 35671 35706 34883 33941 33952 33951 33942 34879 34878 33944 36445 34864 33945 36452 36445 33945 33945 36451 36452 33945 34889 36451 33946 34874 34882 34875 34874 33946 33947 34873 34875 34884 34873 33947 33947 34883 34884 33950 33949 33948 34885 33950 33948 34891 34885 33948 33948 33961 34891 36450 34877 33949 36456 36450 33949 33949 33950 36456 33950 34885 36456 33951 33952 33964 35707 33964 33952 33953 34886 34888 33954 33960 34893 33956 33955 33954 34893 33956 33954 36451 34889 33955 36457 36451 33955 33955 33956 36457 36463 36457 33956 33956 35715 36463 33956 34893 35715 34893 33960 33957 33957 34871 34893 33957 33958 34871 33959 33958 33957 34881 34870 33958 33958 33959 34881 33958 34870 34871 34882 34881 33959 33962 34887 34894 35714 34887 33962 33964 33963 33962 33963 33964 35707 33967 33966 33965 33969 33967 33965 36464 33969 33965 33965 35722 36464 33965 35719 35722 33965 33966 35719 33966 34892 35719 33969 33968 33967 33972 33971 33968 33968 33969 33972 36465 33972 33969 33969 36464 36465 33973 33977 33978 33973 33976 33977 34899 33998 33975 34900 34899 33975 33976 33992 33993 33993 33977 33976 33979 33978 33977 34890 33979 33977 33977 33993 34890 35717 34891 33978 35718 35717 33978 33978 33979 35718 37197 35718 33979 33979 36480 37197 33979 34890 36480 33980 33986 34898 33980 33984 33986 33980 33981 33984 33982 33981 33980 33996 33982 33980 34898 33996 33980 33981 33983 33984 33981 33982 33983 33985 33984 33983 33987 33986 33984 33984 33985 33987 34004 33987 33985 35728 35727 33986 37198 35728 33986 33986 34912 37198 33986 34004 34912 33986 33987 34004 35727 34898 33986 35732 33991 33988 33988 34026 35732 33988 34025 34026 33988 33989 34025 35733 34025 33989 35734 35733 33989 35732 35729 33991 33994 33993 33992 33995 33994 33992 33993 33994 34901 35723 34890 33993 33993 34901 35723 33994 33995 34901 33995 34000 34906 34906 34901 33995 35724 34911 33996 33996 34898 35724 34904 34900 33997 34920 34904 33997 33997 34918 34920 33997 34916 34918 34917 34916 33997 34904 33999 33998 33998 34899 34904 34000 34902 34906 34002 34017 34922 34002 34003 34017 34004 34003 34002 34922 34004 34002 34922 34912 34004 34006 34897 34921 34006 34009 34897 34006 34007 34009 34008 34007 34006 34921 34008 34006 34007 34008 34014 34926 34014 34008 34008 34921 34926 34947 34933 34010 34016 34013 34012 34013 34016 34043 35747 34932 34014 34014 34926 35747 34017 34024 34922 34017 34020 34024 34017 34018 34020 34018 34019 34020 34923 34024 34021 34924 34923 34021 34021 34022 34924 35733 34924 34022 34919 34031 34023 34023 34918 34919 34923 34922 34024 34026 35740 35741 35741 35732 34026 34027 34028 34927 35740 34927 34028 34028 35736 35740 34028 35735 35736 34028 34029 35735 34029 34045 35735 34029 34030 34045 34915 34045 34031 34919 34915 34031 34937 34936 34032 35751 34937 34032 34032 34033 35751 34034 34033 34032 36502 35751 34033 34033 36496 36502 34033 34928 36496 34033 34034 34928 35744 34928 34034 34034 34931 35744 34034 34930 34931 34034 34038 34930 34034 34036 34038 34037 34036 34035 34934 34038 34036 34036 34041 34934 34036 34037 34041 34037 34040 34041 34934 34930 34038 34056 34053 34039 34039 34052 34056 34039 34040 34052 34041 34040 34039 34053 34041 34039 34041 34929 34934 34938 34929 34041 34971 34938 34041 34041 34053 34971 34042 34043 34948 34941 34050 34044 34946 34049 34046 34046 34047 34946 34047 34944 34946 34945 34944 34047 34047 34055 34945 34951 34051 34050 34050 34941 34951 34977 34971 34053 34053 34056 34977 36510 34954 34054 34054 35756 36510 34054 35753 35756 34054 34951 35753 34055 34067 34976 34975 34945 34055 34976 34975 34055 35767 34977 34056 34056 35766 35767 34056 34079 35766 34066 34060 34057 34963 34066 34057 35760 34963 34057 34057 34058 35760 34058 35758 35760 34058 34059 35758 35759 35758 34059 34059 34961 35759 34061 34063 34073 34969 34063 34062 34063 34072 34073 34967 34072 34063 35755 34967 34063 34063 34969 35755 37259 34960 34065 34065 35757 37259 34065 34972 35757 34960 34957 34065 34963 34962 34066 34067 34080 34980 34980 34976 34067 34984 34978 34068 34068 34069 34984 34075 34069 34068 34070 34985 34990 34070 34071 34985 34968 34082 34072 34072 34967 34968 34980 34080 34077 34991 34980 34077 34997 34991 34077 34998 34997 34077 34079 35774 35775 34079 34995 35774 34079 34994 34995 35775 35766 34079 34081 34082 35008 34082 34999 35007 34082 34968 34999 34082 35007 35008 34083 34086 34093 34083 34084 34086 34085 34084 34083 35789 34085 34083 34083 35787 35789 34083 35023 35787 34083 34095 35023 34083 34093 34095 34084 34085 34086 34087 34086 34085 34987 34087 34085 34085 34986 34987 35789 34986 34085 34087 34992 35779 34993 34992 34087 34087 34988 34993 34087 34987 34988 35001 34089 34087 35773 35001 34087 35781 35773 34087 34087 35779 35781 34091 34090 34088 35001 34091 34088 34088 34089 35001 34090 34091 34994 34995 34994 34091 35774 34995 34091 34091 35001 35774 34106 34095 34093 35021 34112 34094 34094 35006 35021 35007 35006 34094 35008 35007 34094 34095 34105 35023 34106 34105 34095 34096 34097 34996 35036 34115 34099 34099 35010 35036 34099 35009 35010 34100 34101 34109 34102 34101 34100 35016 34109 34101 34101 34102 35016 34102 35002 35016 35003 35002 34102 35032 34998 34103 34103 34104 35032 35035 35023 34105 35819 35035 34105 35820 35819 34105 34105 34107 35820 34105 34106 34107 34107 34118 35820 35025 35009 34108 35037 34117 34109 34109 35016 35037 34110 34111 34112 35020 35019 34110 35795 35020 34110 35810 35795 34110 34110 35022 35810 34110 35021 35022 34110 34112 35021 34131 34130 34113 35036 34135 34115 35026 35025 34116 35027 35026 34116 35812 35027 34116 34116 35047 35812 35040 34124 34117 34117 35037 35040 34118 35039 35820 34118 35038 35039 35812 35047 34120 35813 35812 34120 34120 34121 35813 34122 34121 34120 34121 35048 35813 34121 34122 35048 34122 34123 35048 35049 35048 34123 34123 34136 35049 34124 35040 35050 35042 34144 34125 34125 34162 35042 34125 34126 34162 34127 34126 34125 34126 34160 35852 34126 34159 34160 34126 34127 34159 34164 34162 34126 35852 34164 34126 35045 34129 34128 34128 35043 35045 35044 35043 34128 35839 35054 34129 34129 35838 35839 34129 35045 35838 35067 35055 34132 34132 35046 35067 35848 35046 34133 34133 35840 35848 34133 34134 35840 34135 34134 34133 34134 34135 35036 35841 35840 34134 34134 35036 35841 35059 35049 34136 34136 35058 35059 35830 34139 34137 35844 35830 34137 35851 35844 34137 34137 34168 35851 34137 34138 34168 34169 34168 34138 34143 34141 34139 35830 34143 34139 34141 34140 34139 34140 34141 34154 34143 34142 34141 34141 34142 34154 35061 34154 34142 34142 34143 35061 35833 35061 34143 36565 35833 34143 34143 35829 36565 35830 35829 34143 35837 35044 34144 34144 35834 35837 34144 35826 35834 34144 35042 35826 36569 35849 34146 34146 34147 36569 34148 34147 34146 34149 34148 34146 35849 35058 34146 34147 35827 36569 35828 35827 34147 34147 35060 35828 34147 34148 35060 34148 35050 35060 37309 35829 34151 34151 37308 37309 34151 34152 37308 34153 34152 34151 35830 34153 34151 34151 35829 35830 38122 37308 34152 34152 37326 38122 34152 34153 37326 34153 37325 37326 34153 35850 37325 34153 35844 35850 34153 35830 35844 35063 34155 34154 34154 35061 35063 35063 34158 34155 34156 34157 35071 34178 34176 34158 35861 34178 34158 36572 35861 34158 34158 35062 36572 35063 35062 34158 34166 34160 34159 34159 34165 34166 34159 34161 34165 36577 36574 34160 34160 34166 36577 36574 35852 34160 34162 35041 35042 34162 34163 35041 34164 34163 34162 35051 35041 34163 34163 34164 35051 35052 35051 34164 35064 35052 34164 35065 35064 34164 37329 35065 34164 34164 35852 37329 34170 34166 34165 37348 36577 34166 34166 34170 37348 34183 34175 34167 34185 34183 34167 35057 34185 34167 34168 34169 35851 36576 35851 34169 34169 35081 36576 34169 34189 35081 34170 35077 37348 34170 35070 35077 34170 35069 35070 35855 35071 34171 34171 35078 35855 35079 34181 34172 34172 34182 35079 34184 34182 34172 34172 34173 34184 34174 34173 34172 34181 34174 34172 34187 34184 34173 34197 34187 34173 34173 34174 34197 35089 34197 34174 34174 35080 35089 34174 34181 35080 34175 34183 34186 35868 35093 34176 34176 35867 35868 34176 34177 35867 34178 34177 34176 35879 35867 34177 34177 35864 35879 35865 35864 34177 36580 35865 34177 34177 34178 36580 36583 36580 34178 34178 35861 36583 34179 35085 35877 34179 34180 35085 35862 35078 34179 34179 35087 35862 35088 35087 34179 35877 35088 34179 35866 35080 34181 34181 35863 35866 34181 35068 35863 35075 35068 34181 35079 35075 34181 35057 35056 34182 34182 34185 35057 34182 34183 34185 34184 34183 34182 34182 35075 35079 34182 35056 35075 34183 34184 34186 34188 34186 34184 34184 34187 34188 34193 34188 34187 34196 34193 34187 34197 34196 34187 34188 34193 34194 35082 35081 34189 36588 35082 34189 34189 35092 36588 34189 34190 35092 35873 35092 34190 34190 35872 35873 34190 34198 35872 35869 35083 34191 35095 34208 34192 35894 35893 34195 34195 35881 35894 35882 35881 34195 34195 35090 35882 34195 34197 35090 34195 34196 34197 35091 35090 34197 35871 35091 34197 34197 35089 35871 34198 35105 35872 35116 34211 34199 34199 35110 35118 34199 34200 35110 34201 34200 34199 36605 35110 34200 34200 35102 36605 34200 34201 35102 34201 35093 35102 34202 34204 35107 35106 34203 34202 35107 35106 34202 34204 34210 35107 34204 34209 34210 34217 34212 34205 34205 34206 34217 34207 34206 34205 34208 34207 34205 34206 34207 35096 35112 34217 34206 36610 35112 34206 34206 35096 36610 34207 34208 35095 34207 35095 35096 34215 34210 34209 34209 34214 34215 34210 34215 35107 34220 34216 34211 35125 34220 34211 34211 35116 35125 35124 35123 34213 35898 35122 34213 35899 35898 34213 35902 35899 34213 34213 35123 35902 35114 34215 34214 34214 35113 35114 35114 35107 34215 34220 34219 34216 35112 35111 34217 34218 35111 35136 35125 35120 34220 35115 35113 34223 35904 35115 34223 35911 35904 34223 34223 35130 35911 34223 34224 35130 34224 34226 35130 35925 34232 34228 34228 35134 35925 34229 34230 35920 35931 35920 34230 34230 35159 35931 34250 34243 34231 34251 34250 34231 36649 34251 34231 35925 34234 34232 35929 35152 34233 34233 34234 35929 36662 35929 34234 34234 35925 36662 34236 34237 35157 35936 35143 34236 34236 35157 35936 35149 34241 34239 34239 34242 35149 34239 34240 34242 34241 34240 34239 34247 34242 34240 34240 34241 34247 35149 35138 34241 34248 34247 34241 34249 34248 34241 35147 34249 34241 34241 35138 35147 35927 35149 34242 34242 35156 35927 34242 35155 35156 34242 34247 35155 35160 35159 34244 35943 35167 34245 34246 35162 35163 34246 34261 35162 34247 34263 35155 34247 34252 34263 34247 34248 34252 34262 34252 34248 34248 34249 34262 34269 34262 34249 35169 34269 34249 34249 35168 35169 37464 35168 34249 34249 35932 37464 34249 35153 35932 34249 35147 35153 34250 34256 34259 34250 34251 34256 35937 34256 34251 36649 35937 34251 34253 35164 35165 35930 35164 34253 34254 34256 34257 34259 34256 34254 34254 34255 34259 34258 34257 34256 35158 34258 34256 35940 35158 34256 34256 35937 35940 34257 34258 35170 35936 35170 34258 34258 35158 35936 35175 35166 34260 34260 34266 35175 35171 35162 34261 34261 34265 35171 34263 35154 35155 35165 35154 34263 34263 34264 35165 35945 35941 34266 35957 35945 34266 34266 35178 35957 35941 35175 34266 34267 34268 34270 35948 34270 34268 35950 35948 34268 34268 35944 35950 34268 35167 35944 35953 34272 34270 34270 35948 35953 35959 35176 34271 34271 35177 35959 35957 35179 34272 35958 35957 34272 34272 35953 35958 34275 34274 34273 35182 34275 34273 34274 34276 34282 34274 34275 34276 35963 34276 34275 34275 35180 35963 35181 35180 34275 35182 35181 34275 34276 34278 34283 35964 34278 34276 35965 35964 34276 34276 35963 35965 34283 34278 34277 34278 35964 35972 35184 34281 34279 36676 35184 34279 34279 34291 36676 34281 34280 34279 36672 35962 34280 36677 36672 34280 34280 34281 36677 37482 37481 34281 34281 35184 37482 37481 36677 34281 35190 34286 34284 34284 35185 35190 34285 34288 34290 34285 34287 34288 34285 34286 34287 35195 34287 34286 34286 35190 35195 35974 34288 34287 35978 35974 34287 34287 35194 35978 35195 35194 34287 35186 34290 34288 35966 35186 34288 35974 35966 34288 34289 35186 35967 34289 34290 35186 34291 35979 36676 36687 35979 34291 34291 35203 36687 34291 35202 35203 34301 34295 34292 35208 34301 34292 34292 34293 35208 34293 35198 35199 34293 35199 35208 35207 34296 34294 34294 34302 35207 34301 34300 34295 35207 35206 34296 35210 34302 34297 35219 35210 34297 34297 35218 35219 34297 34298 35218 34298 34308 35218 34310 34308 34298 34312 34311 34299 34299 34303 34312 34299 34300 34303 34300 34301 34303 34315 34303 34301 34301 34314 34315 35211 34314 34301 35215 35211 34301 34301 35208 35215 35210 35207 34302 34315 34312 34303 34306 34308 34309 36715 35217 34307 34307 35231 36715 34307 34318 35231 35225 35218 34308 34310 34309 34308 34309 34310 34317 34313 35226 35227 34313 35212 35226 34313 35211 35212 34313 34314 35211 35227 35224 34316 34318 35229 35231 34319 34322 35230 35235 34320 34319 36000 35235 34319 34319 35996 36000 34319 35230 35996 36005 35243 34320 34320 35999 36005 34320 35235 35999 35241 34324 34321 35242 35241 34321 35243 35242 34321 35248 35247 34323 34323 35241 35248 34323 34324 35241 35249 35238 34325 35238 35237 34325 35260 35249 34326 36775 35260 34326 34326 36020 36775 34326 35266 36020 34334 34333 34327 35267 34336 34328 35269 35267 34328 34328 34332 35269 34329 35275 35276 34329 35274 35275 34329 34330 35274 34331 34330 34329 35276 34331 34329 36020 35266 34331 36774 36020 34331 34331 35276 36774 36765 35269 34332 34332 34333 36765 36780 36765 34333 34333 36016 36780 34333 35245 36016 34333 35244 35245 34333 34334 35244 35246 35244 34334 34335 34336 34350 34351 34350 34336 35267 34351 34336 34352 34351 34337 34337 34338 34352 34339 34338 34337 34351 34339 34337 34338 34341 34352 34338 34339 34341 34339 34340 34341 35271 34340 34339 34339 34351 35271 35270 34341 34340 34340 35264 35270 36018 35264 34340 34340 35271 36018 35270 34344 34341 34353 34352 34341 34354 34353 34341 34341 34344 34354 34354 34344 34342 34342 34353 34354 34360 34353 34342 34342 34346 34360 34342 34345 34346 34342 34343 34345 34344 34343 34342 34347 34345 34343 35265 34347 34343 34343 35252 35265 34343 34344 35252 35264 35256 34344 35270 35264 34344 35256 35252 34344 34347 34346 34345 34380 34360 34346 34356 34355 34347 35265 34356 34347 35277 35274 34349 34349 34371 35277 34379 34359 34350 34350 34351 34379 35272 35271 34351 34351 35267 35272 34351 34352 34379 34352 34380 34398 34352 34360 34380 34352 34353 34360 34395 34379 34352 34396 34395 34352 34401 34396 34352 34352 34397 34401 34398 34397 34352 34355 34356 34363 34363 34362 34355 34381 34363 34356 35278 34381 34356 36025 35278 34356 36026 36025 34356 36027 36026 34356 36030 36027 34356 34356 35273 36030 34356 35265 35273 34387 34386 34357 34388 34387 34357 34389 34388 34357 34357 34364 34389 34398 34380 34361 34362 34381 34384 34362 34363 34381 34364 34385 34389 34365 34367 34369 34365 34366 34367 34386 34367 34366 35279 34369 34367 34367 34386 35279 34368 34369 36808 34370 34369 34368 34394 34370 34368 36809 34394 34368 34368 36808 36809 34369 36042 36808 34369 35279 36042 34391 34390 34370 34394 34391 34370 34371 34372 35277 36034 35277 34372 34372 34373 36034 34373 36033 36034 36039 36033 34373 36040 36039 34373 34373 34375 36040 34373 34374 34375 34377 34375 34374 34374 34376 34377 34375 34378 36040 34375 34377 34378 34378 34377 34376 34392 34378 34376 34378 35281 36040 34378 34392 35281 34381 34382 34384 34383 34382 34381 35278 34383 34381 34385 34384 34382 34382 34383 34385 36045 34385 34383 36816 36045 34383 34383 36807 36816 34383 35278 36807 36045 34389 34385 35280 35279 34386 34386 34387 35280 36041 35280 34387 34387 34388 36041 34388 34389 36041 36045 36041 34389 36823 34402 34391 34391 36821 36823 34391 36057 36821 34391 36056 36057 34391 34394 36056 34393 34395 34396 36809 36056 34394 35286 35285 34399 35293 35284 34400 34400 34413 35293 36058 34408 34402 36822 36058 34402 36823 36822 34402 35287 34406 34403 34405 34406 34409 34406 35287 35289 36828 34409 34406 34406 35289 36828 35296 34411 34407 36059 35296 34408 34408 36058 36059 35291 34412 34409 34409 35290 35291 36828 35290 34409 34410 34411 35296 35297 34415 34410 35300 35297 34410 34410 35296 35300 34412 35291 36061 34413 35292 35293 35303 35292 34413 34413 34414 35303 34414 34422 35313 36066 35303 34414 34414 35313 36066 35306 35305 34415 34415 35297 35306 35305 35304 34415 35307 34417 34416 34416 35302 35307 34416 34418 35302 35307 34427 34417 34418 35301 35302 34421 34420 34419 35298 34421 34419 34421 35308 35309 34421 35298 35308 34422 35312 35313 34422 35309 35312 34441 34434 34423 36073 34441 34423 36074 36073 34423 36835 35289 34424 36843 36835 34424 34424 35316 36843 34424 34428 35316 36081 36075 34425 34425 35318 36081 34425 34426 35318 35319 35318 34426 35321 35319 34426 34426 34432 35321 35322 35316 34428 35334 34432 34430 34430 35325 35334 35326 35325 34430 34430 34431 35326 34431 34437 35326 35334 35321 34432 34439 34438 34433 35332 34442 34435 34435 35331 35332 35333 34437 34436 35339 35333 34436 34436 34442 35339 35333 35326 34437 34444 34443 34438 35330 34444 34438 34438 34439 35330 36073 35327 34441 35342 35339 34442 36090 35342 34442 34442 35332 36090 34448 34447 34444 36086 34448 34444 34444 35330 36086 35345 35341 34446 35346 35345 34446 34446 34455 35346 36092 34452 34447 34447 34448 36092 36866 36092 34448 34448 36086 36866 34470 34454 34449 36101 34451 34450 36105 36101 34450 34450 36091 36105 36092 36091 34450 34450 34452 36092 36104 35350 34451 34451 36101 36104 35350 34456 34451 35347 34457 34453 34453 35344 35347 34453 34470 35344 34453 34454 34470 34466 34465 34456 35350 34466 34456 35355 35353 34457 34457 35347 35355 34467 34459 34458 35348 34460 34459 35353 35348 34459 34459 34467 35353 34465 35359 35360 34465 34466 35359 36119 35359 34466 34466 36109 36119 34466 35350 36109 34469 35351 35352 35364 34472 34471 35365 35364 34471 35374 35373 34472 34472 35363 35374 35364 35363 34472 35390 34484 34473 34473 35366 35390 35378 34475 34474 34474 34476 35378 35378 35368 34475 35368 35366 34475 36126 35378 34476 36127 36126 34476 34476 34477 36127 34477 35369 36127 37676 36887 34478 34478 36898 37676 36899 36898 34478 37693 36899 34478 34478 35381 37693 34478 34486 35381 35382 34486 34479 34479 34487 35382 34480 34481 34498 35376 34498 34481 34481 35375 35376 34481 34482 35375 35377 35375 34482 34483 34484 34489 35388 34489 34484 35390 35388 34484 35380 35372 34485 35382 35381 34486 35392 35382 34487 35383 35377 34488 35384 35383 34488 35387 34490 34489 35388 35387 34489 36128 34491 34490 34490 35403 36128 34490 35387 35403 35391 34500 34492 34493 34496 34501 34494 35369 35370 34494 34495 35369 36127 35369 34495 34495 36126 36127 34495 34500 36126 35371 34501 34496 34496 34497 35371 35379 35371 34497 34497 35370 35379 34498 35376 35399 34499 35367 35368 35395 35367 34499 34500 35391 36126 34501 35372 35380 34501 35371 35372 35380 34502 34501 35397 34510 34503 34503 34511 35396 34503 34504 34511 34505 34504 34503 34510 34505 34503 36139 36138 34505 34505 34510 36139 35396 34507 34506 35396 34511 34507 34508 34509 35400 34509 34517 35387 34509 35387 35400 37697 36139 34510 34510 37696 37697 34510 36896 37696 34510 35397 36896 35401 34516 34512 34515 34514 34513 36132 34515 34513 34513 34516 36132 36128 35403 34514 34514 34515 36128 35403 35402 34514 35401 35385 34516 34516 35385 35386 35402 35387 34517 34518 34526 34527 34532 34528 34519 36135 34532 34519 36903 36902 34520 37703 36903 34520 34520 36901 37703 34520 35406 36901 34520 34522 35406 34520 34521 34522 35407 35406 34522 34522 34523 35407 35404 34530 34524 34525 35399 35405 34532 34529 34528 34532 34531 34529 35410 35408 34532 36135 35410 34532 35412 35411 34535 35421 35420 34536 36147 35421 34536 34536 34537 36147 34537 36143 36147 34540 34539 34538 34542 34540 34538 34539 34540 34541 34539 34541 34546 34541 34545 34546 36153 34550 34543 34543 36149 36153 34543 34544 36149 36150 36149 34544 36151 36150 34544 34544 35421 36151 34545 34547 35422 34547 34560 35422 34547 34559 34560 34548 34550 36153 36152 34549 34548 36153 36152 34548 35427 34552 34549 34549 35423 35427 35424 35423 34549 36152 35424 34549 36158 35426 34551 34551 35427 36158 34551 34552 35427 35429 35425 34553 36154 35429 34553 36155 36154 34553 34553 35428 36155 34554 34555 34558 34556 34555 34554 34561 34560 34559 35436 34561 34559 35438 35436 34559 35435 35422 34560 34560 34561 35435 34561 34572 35435 34561 34571 34572 34561 34570 34571 36167 34570 34561 36177 36167 34561 34561 36168 36177 34561 35436 36168 34562 34564 34565 34562 34565 35432 36184 35441 34563 34563 36180 36184 34564 34569 36163 36163 34565 34564 36159 35432 34565 36162 36159 34565 36163 36162 34565 34566 35430 35434 34566 35429 35430 34566 35425 35429 34567 35442 36172 35445 34569 34568 34569 35445 36165 36165 36163 34569 36167 34575 34570 34573 35446 35448 35447 35446 34573 34573 35443 35447 35444 35443 34573 34573 34574 35444 34575 36178 36942 34575 36167 36178 36942 36187 34575 34576 34577 34588 34576 34588 36183 34577 34587 34588 34578 35449 35450 35451 35449 34578 34579 34580 35458 34581 34580 34579 34580 34581 35456 34580 35457 35458 34580 35456 35457 34581 34591 35462 35462 35456 34581 35453 34586 34582 35463 34593 34583 34583 34584 35463 34584 35459 35463 34584 34585 35459 35460 35459 34585 34585 34586 35460 34586 35453 35460 34588 34589 36183 34589 35465 36183 34589 34590 35465 34590 35464 35465 35467 35464 34590 35452 34595 34592 34592 35448 35452 35463 34600 34593 34594 35455 35461 36216 34598 34595 36954 36216 34595 34595 35452 36954 34596 34604 34609 34596 34597 34604 34598 34597 34596 34610 34604 34597 35472 34610 34597 36217 35472 34597 34597 36216 36217 34597 34598 36216 35469 34606 34600 34600 35463 35469 34603 34609 34611 34603 36202 36204 36203 36202 34603 34603 34611 36203 34610 34609 34604 34613 34612 34605 34605 34606 34613 35469 34613 34606 34609 34610 34611 35473 34611 34610 34610 35472 35473 36235 36203 34611 34611 35473 36235 35483 34620 34612 35485 35483 34612 36238 35485 34612 34612 36227 36238 34612 34613 36227 34613 35469 36227 34614 34616 34617 36967 34616 34614 34614 36966 36967 34614 34615 36966 34615 36233 36966 36976 36231 34616 37767 36976 34616 34616 37766 37767 34616 36967 37766 36231 34617 34616 34617 34621 34622 36231 34621 34617 36242 34627 34618 34618 35478 36242 36234 35478 34618 34618 35477 36234 34632 34630 34619 34619 34631 34632 34620 35491 35492 34620 35483 35491 34621 36231 36232 34625 34624 34623 35476 34626 34624 36240 35476 34624 34624 34625 36240 36248 36240 34625 34625 35493 36248 36234 35477 34626 34626 35476 36234 36245 34629 34627 34627 36242 36245 35498 35497 34628 34628 35488 35498 36245 35488 34629 35490 35474 34630 34630 34632 35490 34647 34632 34631 34648 34647 34631 35502 35490 34632 35503 35502 34632 34632 34647 35503 36247 35493 34633 34633 35506 36247 34633 34653 35506 34633 34638 34653 34633 34634 34638 35493 34635 34633 34654 34637 34634 34634 34646 34654 34634 34643 34646 34634 34637 34638 36260 35508 34636 34637 34652 34653 34654 34652 34637 34653 34638 34637 34662 34656 34639 36255 34662 34639 34639 35500 36255 34642 34641 34640 36263 34642 34640 36265 36263 34640 34640 36264 36265 34640 36260 36264 34640 34641 36260 34641 35508 36260 36263 34650 34642 34643 34645 34658 34643 34644 34645 35530 34646 34643 34643 34658 35530 35529 34654 34646 35530 35529 34646 34647 34648 35503 35507 35503 34648 36276 35528 34649 34649 36271 36276 34649 34650 36271 34650 36263 36271 34651 34652 35513 34653 34652 34651 35513 34653 34651 34652 34654 34657 34652 34657 35513 34653 35504 35506 35505 35504 34653 35513 35505 34653 35529 34657 34654 35535 35532 34655 34655 34661 35535 34662 34661 34656 35520 35513 34657 34657 35519 35520 34657 35517 35519 35518 35517 34657 35529 35518 34657 35531 35530 34658 36273 35531 34658 34658 35521 36273 35526 35523 34659 35524 35522 34659 34659 35523 35524 34690 34680 34660 34660 34689 34690 34661 35533 35535 34661 34662 35533 36275 35533 34662 34662 36267 36275 36268 36267 34662 34662 36255 36268 37002 35527 34663 34663 36258 37002 34663 35537 36258 34663 34664 35537 34664 35536 35537 34664 34681 35536 35528 34670 34665 34666 35532 35534 36286 36285 34667 34667 35540 36286 36297 35540 34667 34667 34668 36297 34669 34668 34667 36269 34669 34667 36285 36269 34667 37017 36297 34668 37815 37017 34668 39381 37815 34668 34668 37805 39381 34668 36265 37805 34668 34669 36265 36270 36265 34669 34669 36269 36270 34673 34672 34671 34677 34673 34671 34671 34675 34677 34671 34674 34675 34671 34672 34674 34680 34674 34672 34673 34677 35525 34674 34687 34688 34690 34687 34674 34674 34680 34690 34688 34675 34674 35543 34677 34675 34675 34685 35543 34675 34684 34685 34688 34684 34675 34677 34679 35525 34677 34678 34679 35543 34678 34677 37008 34679 34678 37013 37008 34678 34678 35548 37013 34678 35542 35548 35543 35542 34678 34679 35523 35525 36274 35523 34679 36295 36274 34679 37008 36295 34679 36293 35536 34681 34681 35539 36293 36304 34683 34682 34682 35541 36304 34682 35540 35541 34682 35538 35540 35553 34695 34683 35562 35553 34683 36304 35562 34683 34684 34688 34692 34686 34685 34684 34692 34686 34684 34685 35542 35543 35549 35542 34685 35550 35549 34685 35559 35550 34685 34685 34686 35559 37058 35559 34686 37059 37058 34686 34686 35560 37059 34686 34692 35560 34687 34693 35551 34694 34693 34687 34687 34690 34694 35551 34688 34687 35551 34692 34688 34691 34690 34689 35544 34691 34689 36298 35544 34689 34689 36287 36298 34690 34691 34694 36306 34694 34691 34691 35544 36306 34692 35551 35560 35567 35551 34693 34693 34694 35567 36317 35567 34694 34694 36306 36317 35553 34702 34695 34704 34697 34696 34696 34703 34704 34697 34713 35581 37065 34713 34697 34697 34704 37065 34698 34699 34708 34700 34699 34698 34705 34700 34698 34709 34708 34699 34699 34700 34709 35569 34709 34700 34700 34705 35569 34701 34708 34709 34702 35553 35561 36328 34704 34703 34703 35572 36328 34704 37055 37065 34704 36328 37055 34711 34707 34706 36312 35568 34707 34707 34711 36312 35569 34710 34709 35569 34714 34710 34711 35573 36312 37088 35592 34712 34712 37066 37088 34712 34713 37066 34714 34713 34712 34713 34714 35581 34713 37065 37066 34715 34735 36337 36343 35573 34716 34716 34732 36343 36326 35577 34717 34717 35571 36326 35577 34718 34717 34718 34720 34728 35578 34720 34718 34718 35577 35578 36350 35584 34719 34719 36348 36350 34719 34720 36348 34720 36347 36348 34720 35578 36347 34723 34724 35580 34726 34725 34723 35580 34726 34723 34725 34726 34727 35583 34727 34726 34726 35582 35583 34726 35580 35582 34731 34730 34727 35583 34731 34727 34729 34736 35595 35583 34737 34731 36351 36344 34732 34732 34733 36351 34732 36342 36343 36344 36342 34732 34733 35588 36351 37081 36337 34735 34735 35584 37081 34736 34756 35595 34736 34741 34756 35583 35582 34737 34738 35591 37083 36356 35597 34738 37083 36356 34738 34773 34744 34739 34739 34740 34747 34741 34754 34756 34741 34742 34754 34742 34744 34754 36353 35588 34743 34743 35590 36353 34743 34770 35590 34773 34754 34744 35609 34746 34745 34746 35621 35622 34746 35609 35621 34748 34761 35601 34748 34760 34761 36377 35616 34749 34749 34750 36377 34750 35615 36377 34750 35601 35615 35626 34807 34751 34752 34772 34815 34753 34773 34775 34753 34754 34773 34755 34754 34753 34775 34755 34753 34754 34755 34756 34775 34757 34755 34757 34756 34755 34756 35593 35595 35594 35593 34756 35598 35594 34756 34756 34757 35598 34757 34775 35623 35623 35598 34757 34758 35599 35600 34758 35589 35599 34758 35587 35589 34758 35585 35587 34760 34779 35612 35612 34761 34760 36376 36362 34761 37107 36376 34761 34761 35613 37107 35614 35613 34761 34761 35612 35614 35615 35601 34761 36363 35615 34761 34761 36362 36363 34762 34763 34765 34764 34763 34762 35645 34764 34762 34762 34801 35645 34762 34765 34801 34804 34765 34763 35602 34804 34763 36364 35602 34763 34763 34764 36364 34764 35645 36364 34804 34802 34765 34802 34801 34765 34766 34782 35605 34766 34781 34782 34783 34781 34766 35605 34767 34766 34767 35617 35618 36369 35617 34767 34767 35605 36369 35624 34769 34768 34768 35618 35624 34769 35624 36378 36378 34787 34769 36370 35590 34770 36371 36370 34770 36372 36371 34770 34796 34772 34771 34813 34796 34771 34814 34813 34771 34771 34794 34814 34772 34797 34815 34772 34796 34797 34773 34774 34775 35636 34775 34774 34774 35635 35636 34774 34816 35635 36390 35623 34775 36392 36390 34775 34775 35636 36392 34776 34798 34818 34800 34798 34776 35643 34800 34776 34776 35642 35643 34776 34777 35642 34778 34777 34776 34818 34778 34776 36385 35642 34777 34777 34778 36385 34778 35611 36385 34778 34818 35611 34832 34782 34780 34780 34822 34832 34780 34786 34822 34780 34785 34786 34830 34785 34780 34831 34830 34780 34836 34831 34780 34780 34781 34836 34782 34781 34780 34837 34836 34781 34781 34783 34837 34782 35604 35605 34782 34832 35604 34838 34837 34783 34783 34823 34838 35638 34802 34784 36417 35638 34784 37131 36417 34784 37132 37131 34784 34784 36418 37132 34784 34831 36418 34784 34830 34831 34784 34785 34830 34786 34785 34784 34802 34786 34784 34786 34803 34822 34786 34802 34803 36378 35625 34787 34788 34805 36380 34788 34789 34806 34790 34789 34788 36380 34790 34788 34807 34806 34789 35619 34807 34789 36386 35619 34789 34789 34790 36386 34790 35619 36386 36382 35619 34790 34790 36381 36382 34790 36380 36381 34791 34793 34794 34791 34792 34793 34795 34793 34792 35631 34795 34792 34792 35627 35631 34795 34794 34793 34825 34814 34794 34794 34795 34825 34795 35631 35632 34795 34809 34825 35632 34809 34795 34813 34797 34796 34826 34817 34797 34797 34813 34826 34817 34815 34797 34798 34799 35644 34800 34799 34798 37110 35644 34799 34799 35630 37110 34799 34800 35630 36402 35630 34800 34800 35643 36402 35646 35645 34801 34801 34819 35646 34801 34802 34819 34804 34803 34802 34821 34819 34802 35638 34821 34802 35603 34822 34803 34803 35602 35603 34803 34804 35602 34805 35625 36380 34806 34807 34824 35626 34824 34807 34828 34825 34809 36407 34828 34809 34809 34810 36407 34811 34810 34809 34812 34811 34809 35632 34812 34809 37125 36412 34810 37931 37125 34810 34810 37124 37931 34810 36387 37124 34810 34811 36387 36412 36407 34810 36399 36387 34811 34811 34812 36399 34812 35633 36399 34812 35632 35633 34813 34825 34828 34813 34814 34825 34827 34826 34813 34828 34827 34813 34815 34816 35610 34817 34816 34815 35639 35635 34816 34816 35628 35639 34816 34817 35628 34817 34826 34827 35634 35628 34817 34817 34827 35634 34818 35600 35611 34819 35638 35646 34819 34821 35638 35603 34832 34822 36414 35634 34827 34827 36408 36414 34827 36407 36408 34827 34828 36407 34831 34836 36418 34832 35603 35604 34835 34834 34833 36398 34835 34833 37112 36398 34833 37115 37112 34833 37917 37115 34833 34833 37108 37917 34833 36377 37108 34833 34834 36377 34834 35616 36377 36398 35637 34835 37132 36418 34836 37942 37132 34836 34836 37136 37942 37137 37136 34836 34836 34837 37137 37138 37137 34837 34837 35661 37138 34837 35654 35661 34839 34844 35663 34839 34840 34844 35663 35655 34839 34845 34844 34840 35659 34842 34841 34841 35652 35659 34841 34843 35652 35659 34846 34842 34846 35659 35664 35668 34847 34846 34846 35665 35668 34846 35664 35665 37140 35669 34847 34847 35668 37140 35670 34849 34848 35674 35670 34848 35675 35674 34848 34848 34853 35675 35670 34850 34849 35670 35663 34850 35673 34853 34852 36423 35675 34853 34853 35673 36423 34854 34855 34862 35676 34862 34855 35677 35676 34855 34865 34863 34856 34856 34857 34865 34856 34864 35679 34856 34863 34864 34857 34858 34865 34858 34863 34865 36434 35685 34859 34861 34860 34859 35685 34861 34859 36431 34866 34862 34862 35676 36431 36441 35679 34864 36445 36441 34864 36436 35688 34866 34866 36431 36436 35688 35686 34866 35701 34868 34867 34867 35700 35701 34867 35686 35700 35711 34880 34868 34868 35701 35711 34881 34874 34870 35695 34871 34870 34870 35693 35695 34870 35689 35693 34870 35684 35689 34870 34872 35684 34874 34872 34870 35715 34893 34871 34871 35712 35715 34871 35695 35712 34872 34884 35705 34872 34873 34884 34874 34873 34872 36433 35684 34872 34872 35698 36433 35705 35698 34872 34873 34874 34875 34874 34881 34882 36449 35699 34876 34876 34877 36449 36450 36449 34877 35714 35708 34878 34878 34888 35714 34878 34879 34888 35720 34892 34880 34880 35711 35720 35706 34884 34883 35706 35705 34884 36474 36456 34885 34885 35716 36474 34885 34891 35716 34886 34887 34888 35714 34888 34887 34890 35723 36480 35717 35716 34891 35720 35719 34892 34907 34902 34895 34910 34907 34895 35724 34897 34896 34896 34911 35724 34897 36485 36491 34897 35724 36485 35731 34921 34897 36491 35731 34897 36485 35724 34898 34898 35725 36485 35726 35725 34898 36476 35726 34898 34898 35727 36476 34899 34900 34904 35730 35723 34901 35737 35730 34901 34901 34905 35737 34906 34905 34901 34902 34905 34906 34908 34905 34902 34902 34907 34908 34903 35729 35735 35738 35737 34905 34905 34908 35738 34909 34908 34907 34910 34909 34907 34908 34925 35738 34908 34909 34925 34909 34910 34925 34923 34914 34912 34912 34922 34923 34912 34913 37198 34914 34913 34912 37199 37198 34913 34913 37188 37199 34913 35722 37188 36466 35722 34913 34913 34914 36466 34914 34923 35739 34914 36465 36466 34914 35739 36465 34919 34917 34915 34919 34918 34916 34916 34917 34919 36482 34926 34921 36484 36482 34921 34921 35731 36484 34923 34924 35739 34924 35733 35739 36492 35747 34926 34926 36482 36492 34928 35744 36490 34928 36495 36496 34928 36490 36495 34929 34930 34934 34931 34930 34929 35745 34931 34929 37227 35745 34929 37246 37227 34929 34929 34938 37246 35745 35744 34931 34940 34935 34932 34943 34940 34932 36499 34943 34932 34932 35747 36499 34933 34947 35749 34940 34939 34935 36494 35750 34936 36503 36494 34936 34936 36502 36503 34936 34937 36502 34937 35751 36502 34938 37245 37246 34938 36506 37245 34938 34970 36506 34971 34970 34938 34952 34941 34939 34939 34940 34952 34940 34942 34952 34943 34942 34940 35753 34951 34941 34941 34949 35753 34950 34949 34941 34952 34950 34941 34942 34950 34952 36507 34950 34942 37248 36507 34942 34942 34943 37248 34943 37238 37248 34943 36499 37238 35748 34946 34944 35754 35748 34944 36505 35754 34944 34944 36504 36505 34944 34964 36504 34965 34964 34944 34944 34945 34965 34966 34965 34945 35752 34966 34945 34945 34975 35752 35748 34947 34946 34947 35748 35749 35756 35753 34949 37256 35756 34949 34949 34950 37256 34950 37255 37256 34950 36508 37255 34950 36507 36508 36511 34973 34953 34953 34954 36511 38914 36511 34954 38915 38914 34954 34954 38069 38915 38070 38069 34954 34954 36510 38070 34957 34958 34974 34959 34958 34957 34960 34959 34957 34958 34959 34961 37258 34961 34959 34959 34960 37258 37259 37258 34960 37258 35759 34961 36522 34979 34962 34962 35760 36522 34962 34963 35760 37249 36504 34964 37254 37249 34964 34964 34965 37254 37263 37254 34965 34965 34966 37263 34966 35762 37263 34966 35761 35762 34966 35752 35761 35765 34968 34967 35768 35765 34967 37251 35768 34967 34967 35764 37251 34967 35746 35764 35755 35746 34967 35000 34999 34968 35765 35000 34968 34969 35746 35755 36532 36506 34970 34970 36509 36532 34970 34971 36509 34971 34977 36509 36513 35757 34972 34972 34973 36513 34973 36512 36513 34973 36511 36512 34975 34976 35752 36524 35752 34976 34976 35776 36524 34976 34980 35776 34977 35767 36509 34978 34984 34996 35782 34985 34979 36523 35782 34979 34979 36522 36523 35784 35776 34980 34980 34991 35784 34981 36506 36532 38066 36506 34981 34981 37275 38066 34981 37265 37275 34981 34982 37265 34983 34982 34981 35775 34983 34981 36532 35775 34981 34982 34983 35780 34982 36521 37265 36533 36521 34982 34982 35779 36533 35780 35779 34982 34983 35775 35780 35782 34990 34985 34988 34987 34986 34989 34988 34986 35789 34989 34986 36517 34993 34988 34988 35778 36517 34988 35772 35778 34988 34989 35772 35777 35772 34989 35789 35777 34989 34990 35782 35783 34991 34997 35784 34992 36517 36533 34992 34993 36517 36533 35779 34992 34997 34998 35784 36541 35784 34998 34998 35795 36541 34998 35032 35795 35022 35006 34999 35790 35022 34999 35811 35790 34999 36529 35811 34999 34999 36528 36529 34999 35000 36528 34999 35006 35007 35000 35765 36528 35001 35773 35774 35017 35016 35002 36558 35017 35002 35002 35791 36558 35002 35003 35791 35003 35018 35791 35791 35018 35004 35792 35791 35004 36548 35792 35004 35004 35793 36548 35794 35793 35005 36535 35794 35005 35005 35783 36535 35022 35021 35006 35796 35010 35009 35798 35796 35009 35799 35798 35009 35009 35024 35799 35025 35024 35009 35796 35036 35010 35014 35013 35011 35015 35014 35011 35028 35015 35011 35011 35012 35028 35013 35012 35011 35012 35805 35807 35808 35805 35012 35012 35013 35808 35029 35028 35012 35807 35029 35012 35013 35014 35808 35809 35808 35014 35014 35017 35809 35014 35016 35017 35014 35015 35016 35037 35016 35015 35015 35031 35037 35015 35028 35031 36557 35809 35017 36558 36557 35017 35019 35020 35032 35795 35032 35020 35022 35790 35810 35788 35787 35023 35023 35035 35788 36553 35799 35024 35024 35026 36553 35024 35025 35026 37287 36553 35026 35026 36551 37287 36552 36551 35026 35026 35027 36552 36554 36552 35027 35027 36544 36554 36545 36544 35027 35027 35814 36545 35027 35812 35814 35028 35030 35031 35028 35029 35030 35816 35030 35029 35029 35807 35816 35827 35031 35030 35843 35827 35030 35030 35818 35843 35030 35816 35818 35828 35037 35031 35031 35827 35828 37305 35788 35033 37307 37305 35033 38117 37307 35033 38126 38117 35033 35033 35034 38126 35035 35034 35033 35788 35035 35033 35034 35035 35819 35034 36561 38126 36562 36561 35034 35034 35819 36562 35036 35797 35841 35036 35796 35797 35828 35040 35037 35054 35039 35038 35039 35819 35820 36567 35819 35039 35039 35846 36567 35039 35839 35846 35039 35054 35839 35060 35050 35040 35828 35060 35040 35826 35042 35041 35836 35826 35041 35041 35053 35836 35041 35051 35053 35838 35045 35043 35043 35837 35838 35043 35044 35837 35072 35067 35046 35848 35072 35046 35821 35813 35048 35842 35821 35048 35048 35049 35842 35847 35842 35049 35049 35059 35847 35051 35052 35053 35833 35053 35052 35845 35833 35052 35052 35064 35845 36566 35836 35053 35053 35831 36566 35832 35831 35053 35833 35832 35053 35066 35056 35055 35067 35066 35055 35056 35068 35075 35056 35066 35068 35847 35059 35058 35849 35847 35058 35845 35063 35061 35061 35833 35845 35062 35065 36572 35062 35064 35065 35845 35064 35062 35062 35063 35845 36573 36572 35065 37327 36573 35065 37329 37327 35065 35073 35068 35066 35074 35073 35066 35066 35072 35074 35066 35067 35072 35068 35860 35863 35068 35073 35860 35854 35070 35069 35069 35071 35854 35070 35076 35077 36581 35076 35070 35070 35854 36581 35855 35854 35071 35853 35074 35072 35072 35848 35853 36582 35860 35073 36586 36582 35073 35073 36578 36586 35073 36575 36578 35073 35074 36575 35074 36571 36575 35074 35853 36571 35076 36581 36584 35856 35077 35076 35858 35856 35076 36584 35858 35076 38154 37348 35077 38992 38154 35077 38998 38992 35077 35077 35856 38998 35859 35855 35078 35862 35859 35078 35866 35089 35080 37344 36576 35081 35081 35082 37344 37375 37344 35082 35082 36589 37375 35082 36588 36589 35869 35084 35083 35870 35086 35084 35084 35869 35870 35085 35086 35877 35086 35088 35877 36594 35088 35086 36597 36594 35086 35086 35870 36597 35878 35862 35087 35087 35088 35878 36585 35878 35088 36593 36585 35088 36594 36593 35088 36598 35871 35089 35089 36596 36598 35089 35866 36596 36598 35882 35090 35090 35091 36598 35091 35871 36598 35092 35873 36588 35103 35102 35093 35868 35103 35093 35099 35098 35094 35094 35095 35099 35096 35095 35094 36606 35096 35094 35094 35097 36606 35098 35097 35094 36613 36610 35096 35096 36606 36613 35097 36601 36606 35097 35880 36601 35097 35100 35880 35101 35100 35097 35097 35098 35101 35100 35104 35880 37397 36605 35102 35102 36591 37397 35102 35103 36591 35103 35879 36591 35103 35867 35879 35868 35867 35103 35104 35108 35880 35884 35872 35105 35105 35106 35884 35885 35884 35106 35106 35883 35885 35106 35107 35883 35888 35883 35107 35889 35888 35107 35107 35114 35889 36602 35880 35108 35108 35887 36602 35108 35109 35887 35898 35887 35109 35109 35122 35898 35110 35117 35118 35891 35117 35110 35892 35891 35110 36605 35892 35110 36632 35136 35111 35111 35121 36632 35111 35112 35121 36621 35121 35112 36622 36621 35112 35112 36610 36622 35115 35114 35113 35895 35889 35114 35901 35895 35114 35114 35115 35901 35905 35901 35115 35115 35904 35905 35129 35125 35116 35891 35127 35117 35119 35118 35117 35127 35119 35117 35127 35126 35119 35120 35125 35129 36642 36632 35121 35121 36621 36642 35123 35124 35128 35903 35902 35123 35123 35128 35903 35886 35876 35126 37411 35886 35126 35126 37410 37411 35126 35127 37410 35127 37398 37410 35127 35891 37398 37417 35903 35128 35128 35900 37417 35128 35894 35900 35128 35893 35894 35916 35911 35130 36637 35913 35131 35131 35141 36637 35131 35140 35141 35131 35137 35140 35131 35132 35137 35133 35132 35131 35913 35133 35131 35138 35137 35132 35139 35138 35132 36636 35139 35132 35132 35917 36636 35132 35133 35917 35133 35908 35917 35918 35908 35133 35133 35913 35918 35134 35135 35925 36643 35925 35135 35135 35136 36643 35136 36632 36643 35137 35138 35140 35150 35140 35138 35138 35149 35150 35148 35147 35138 35138 35139 35148 36650 35148 35139 35139 36648 36650 35139 36636 36648 35924 35141 35140 35140 35150 35924 35141 35926 37439 35141 35924 35926 37439 36637 35141 36654 36653 35142 35142 35143 36654 36651 36644 35142 36652 36651 35142 36653 36652 35142 36656 36654 35143 35143 35936 36656 36649 35146 35144 37457 36649 35144 38252 37457 35144 35144 36640 38252 35144 35145 36640 35146 35145 35144 35145 36638 36640 35145 36634 36638 35145 35921 36634 35145 35919 35921 35145 35146 35919 35147 35148 35153 36650 35153 35148 35151 35150 35149 35927 35151 35149 35150 35151 35924 35935 35924 35151 35151 35927 35935 35933 35932 35153 37452 35933 35153 35153 36650 37452 35156 35155 35154 35164 35156 35154 35165 35164 35154 35934 35927 35156 36655 35934 35156 36660 36655 35156 35156 35164 36660 35157 35170 35936 35940 35936 35158 36658 35931 35159 35159 35942 36658 35159 35172 35942 35159 35160 35172 35160 35166 35172 35163 35162 35161 35162 35171 35943 36661 36660 35164 35164 35930 36661 35173 35172 35166 35174 35173 35166 35941 35174 35166 35166 35175 35941 35167 35943 35944 37464 36666 35168 36666 35169 35168 35956 35177 35169 36666 35956 35169 35944 35943 35171 35949 35944 35171 35955 35949 35171 35171 35176 35955 36663 35942 35172 35172 35173 36663 35173 35174 36663 36664 36663 35174 35174 35946 36664 35174 35945 35946 35174 35941 35945 36671 35955 35176 35176 35960 36671 35176 35959 35960 35961 35959 35177 35177 35956 35961 35178 35179 35957 36673 35963 35180 35180 35181 36673 35181 35183 36673 35181 35182 35183 35962 35183 35182 36675 36673 35183 37480 36675 35183 35183 35962 37480 35184 36676 37482 35971 35190 35185 35972 35971 35185 35186 35966 35967 35968 35966 35187 35970 35968 35187 37487 35970 35187 35187 35188 37487 35189 35188 35187 36682 35189 35187 35187 35966 36682 38276 37487 35188 38278 38276 35188 35188 35189 38278 35189 37489 38278 37492 37489 35189 35189 36682 37492 35190 35194 35195 35977 35194 35190 35190 35976 35977 35190 35971 35976 35975 35193 35191 35191 35969 35975 35191 35968 35969 35191 35967 35968 36684 35196 35192 35192 35193 36684 35193 35975 36684 35194 35977 35978 36685 35197 35196 35196 36684 36685 37498 35987 35197 35197 36686 37498 35197 36685 36686 35987 35198 35197 35987 35199 35198 35987 35201 35199 35209 35208 35199 35199 35200 35209 35201 35200 35199 36695 35993 35200 37500 36695 35200 35200 35201 37500 35993 35209 35200 35201 35987 37500 35206 35203 35202 35203 35981 36687 37499 35981 35203 35203 35204 37499 35205 35204 35203 35206 35205 35203 35204 35994 37499 35204 35219 35994 35204 35205 35219 35205 35206 35207 35988 35219 35205 35205 35210 35988 35205 35207 35210 35208 35209 35215 35216 35215 35209 35993 35216 35209 35210 35219 35988 35216 35212 35211 35211 35215 35216 35212 35223 35226 35212 35213 35223 35214 35213 35212 35216 35214 35212 35213 35221 35222 35992 35221 35213 35213 35214 35992 35213 35222 35223 37517 35992 35214 35214 36696 37517 35214 35216 36696 35216 35993 36696 35994 35219 35217 36715 35994 35217 35217 35218 35225 35219 35218 35217 35997 35995 35220 36705 35997 35220 35220 35221 36705 35222 35221 35220 35221 35992 36705 35224 35223 35222 35223 35224 35226 35227 35226 35224 35232 35231 35229 35233 35232 35229 35234 35233 35229 35237 35234 35229 35230 35236 35996 37533 36715 35231 35231 36002 37533 35231 35232 36002 35232 35233 36004 35232 36001 36002 36004 36001 35232 35233 35234 36004 35234 35238 36004 35234 35237 35238 36000 35999 35235 35249 35240 35238 36006 36004 35238 35238 35250 36006 35238 35239 35250 35240 35239 35238 35262 35261 35239 35239 35260 35262 35239 35240 35260 35251 35250 35239 35261 35251 35239 35240 35249 35260 36007 35248 35241 35241 35242 36007 36742 36007 35242 35242 36741 36742 35242 36005 36741 35242 35243 36005 35246 35245 35244 36756 36016 35245 35245 35246 36756 37542 36756 35246 35246 35247 37542 35247 35248 36746 35247 36747 37542 35247 36746 36747 35248 36007 36746 36743 36006 35250 36748 36743 35250 35250 36009 36748 35250 36008 36009 35250 35251 36008 35251 35261 36008 35254 35253 35252 35255 35254 35252 35256 35255 35252 35252 35259 35265 35252 35258 35259 35252 35253 35258 35253 36751 36753 35253 35254 36751 35253 35257 35258 36753 35257 35253 36752 36751 35254 35254 36750 36752 35254 35255 36750 35255 35263 36750 35264 35263 35255 35255 35256 35264 36773 36012 35257 35257 36759 36773 35257 36753 36759 35259 35258 35257 36012 35259 35257 35273 35265 35259 36012 35273 35259 36014 35262 35260 36775 36014 35260 35261 36021 36023 35261 35262 36021 36015 36008 35261 36023 36015 35261 36786 36021 35262 35262 36784 36786 35262 36013 36784 36014 36013 35262 37548 36750 35263 37557 37548 35263 35263 36771 37557 35263 35264 36771 36772 36771 35264 35264 36018 36772 36017 35272 35267 35267 35268 36017 35269 35268 35267 36768 36017 35268 35268 35269 36768 36783 36768 35269 35269 36766 36783 36767 36766 35269 35269 36765 36767 35271 35272 36018 35272 36017 36018 35273 36024 36030 35273 36019 36024 35273 36012 36019 36031 35275 35274 35274 35277 36031 37575 36032 35275 35275 36818 37575 35275 36031 36818 36032 35276 35275 38340 36774 35276 35276 36032 38340 36034 36031 35277 35278 36025 36807 35279 35280 36042 35280 36035 36042 36036 36035 35280 36041 36036 35280 36044 36040 35281 35281 35282 36044 35282 36043 36044 36052 36043 35283 35283 35285 36052 36052 35286 35284 35284 35292 36052 35293 35292 35284 35285 35286 36052 35287 35288 35289 37621 36828 35289 35289 36835 37621 36061 35291 35290 36830 36061 35290 37621 36830 35290 35290 36828 37621 36055 36052 35292 35292 35294 36055 35295 35294 35292 35303 35295 35292 36824 36055 35294 36831 36824 35294 35294 36825 36831 35294 35295 36825 36826 36825 35295 37618 36826 35295 35295 36062 37618 36063 36062 35295 35295 35303 36063 36069 35300 35296 37626 36069 35296 35296 36059 37626 36064 35306 35297 35297 35300 36064 36072 35308 35298 35298 35299 36072 36836 36072 35299 35299 36832 36836 35299 36061 36832 36069 36064 35300 36065 35302 35301 36071 35307 35302 35302 36070 36071 35302 36065 36070 36067 36063 35303 35303 36066 36067 35315 35314 35304 35304 35305 35315 35305 35306 35315 36068 35315 35306 35306 36064 36068 36834 35330 35307 36842 36834 35307 35307 36071 36842 36072 35310 35308 35311 35309 35308 35308 35310 35311 35317 35312 35309 35309 35311 35317 35310 36072 36837 36076 35311 35310 36844 36076 35310 35310 36837 36844 36066 35317 35311 36076 36066 35311 35317 35313 35312 35313 35317 36066 35314 36079 36080 35314 36068 36079 35314 35315 36068 36080 36074 35314 35316 35323 36843 35316 35322 35323 35318 35329 36081 35318 35319 35329 35319 35320 35329 35321 35320 35319 35320 35321 35329 35337 35329 35321 35321 35334 35337 35324 35323 35322 36093 35324 35322 35323 35324 36083 35323 36082 36843 36083 36082 35323 36865 36850 35324 35324 36093 36865 36850 36083 35324 36088 35334 35325 35325 35335 36088 35325 35326 35335 35336 35335 35326 35326 35333 35336 36084 35328 35327 35327 36078 36084 35327 36073 36078 36090 35331 35328 35328 36084 36090 36085 36081 35329 37656 36085 35329 35329 36089 37656 35329 36087 36089 35329 35338 36087 35329 35337 35338 36833 36086 35330 36834 36833 35330 36090 35332 35331 35339 35336 35333 36088 35337 35334 35335 35336 36088 36097 36088 35336 35336 36096 36097 35336 36094 36096 35336 35339 36094 36088 35338 35337 36869 36087 35338 38427 36869 35338 35338 38426 38427 35338 36875 38426 35338 36098 36875 35338 36097 36098 35338 36088 36097 35339 35343 36094 35339 35342 35343 35340 35345 36093 35340 35341 35345 36867 35343 35342 35342 36853 36867 35342 36090 36853 36095 36094 35343 36868 36095 35343 35343 36867 36868 35345 35346 36093 36102 36093 35346 36103 36102 35346 35346 35356 36103 35346 35348 35356 36114 35355 35347 35347 36106 36114 35348 35353 35356 35350 36108 36109 35350 36107 36108 35350 36104 36107 35351 35360 36110 36110 35352 35351 36110 35361 35352 35357 35356 35353 36116 35357 35353 35353 35358 36116 35353 35354 35358 35355 35354 35353 36890 35358 35354 35354 36889 36890 35354 36115 36889 35354 35355 36115 35355 36114 36115 35356 35357 36103 36116 36103 35357 36120 36116 35358 36895 36120 35358 35358 36892 36895 35358 36890 36892 36110 35360 35359 36112 36110 35359 36883 36112 35359 35359 36119 36883 36878 35362 35361 35361 36110 36878 36121 35365 35362 36123 36121 35362 35362 36122 36123 36877 36122 35362 36878 36877 35362 35363 35364 36121 36125 35374 35363 35363 36124 36125 35363 36121 36124 35364 35365 36121 35366 35389 35390 35395 35389 35366 35366 35367 35395 35368 35367 35366 35368 35378 35391 35373 35374 35397 35374 36125 36896 36896 35397 35374 35377 35376 35375 35376 35377 35399 35405 35399 35377 36133 35405 35377 35377 35383 36133 36126 35391 35378 35381 36129 37693 35381 35392 36129 35381 35382 35392 35383 35385 36133 35383 35384 35385 35386 35385 35384 35385 35401 36133 35387 35389 35400 35387 35388 35389 35387 35402 35403 35390 35389 35388 35392 35398 36129 35392 35393 35398 35394 35393 35392 36131 35398 35393 36131 36129 35398 35406 36137 36901 35406 35407 36137 36140 36137 35407 35407 36138 36140 35419 35417 35408 35408 35418 35419 36141 35418 35408 35408 35409 36141 35410 35409 35408 35409 36135 36144 35409 35410 36135 36144 36141 35409 36142 35413 35411 35411 35412 36142 35412 35417 36142 36911 36143 35413 35413 36909 36911 35413 36142 36909 35414 36909 36910 35414 35415 36909 35416 35415 35414 36910 35416 35414 36911 36909 35415 35415 36148 36911 39293 36148 35415 35415 38481 39293 35415 35416 38481 38482 38481 35416 39291 38482 35416 35416 37711 39291 35416 36910 37711 36146 36142 35417 36913 36146 35417 35417 35419 36913 38480 35419 35418 35418 36912 38480 35418 36141 36912 37709 36913 35419 38480 37709 35419 35421 36147 36151 37723 35427 35423 39314 37723 35423 39315 39314 35423 35423 38498 39315 35423 38497 38498 35423 37724 38497 35423 35424 37724 35424 37720 37724 35424 36914 37720 35424 36152 36914 36161 35442 35426 36164 36161 35426 35426 36158 36164 36916 36158 35427 37723 36916 35427 35428 35433 36155 36154 35431 35429 35431 35430 35429 36922 35434 35430 37729 36922 35430 35430 35431 37729 35431 37722 37729 35431 36917 37722 35431 36915 36917 35431 36154 36915 36159 35433 35432 36160 36155 35433 35433 36159 36160 36922 35440 35434 36169 36168 35436 35436 35437 36169 35438 35437 35436 35437 35438 35439 36179 36169 35437 35437 35441 36179 36166 35444 35440 36175 36166 35440 36925 36175 35440 35440 36922 36925 36940 36179 35441 35441 36184 36940 35442 36161 36172 36182 35447 35443 35443 36181 36182 35443 36176 36181 35443 36166 36176 35443 35444 36166 36931 36926 35445 36932 36931 35445 36926 36165 35445 35446 36185 36943 35446 35447 36185 36186 35448 35446 36944 36186 35446 35446 36943 36944 35447 36182 36185 36186 35452 35448 40061 38530 35450 40815 40061 35450 40829 40815 35450 35450 38539 40829 38540 38539 35450 35450 36955 38540 35452 36186 36944 35452 36953 36954 35452 36944 36953 36192 35460 35453 35453 36187 36192 35458 35457 35454 36195 35455 35454 35454 35457 36195 36195 35461 35455 36196 35457 35456 36200 36196 35456 36204 36200 35456 36196 36195 35457 36197 35463 35459 35459 36192 36197 35459 35460 36192 36963 36215 35461 36964 36963 35461 35461 36195 36964 36197 35469 35463 36951 36188 35464 35464 36201 36951 35464 35467 36201 35466 35465 35464 36188 35466 35464 35465 36180 36183 35465 35466 36180 36188 36180 35466 35467 35468 36201 35469 36218 36227 35469 36205 36218 35469 36197 36205 36228 36207 35470 35471 35499 36236 35473 35472 35471 36236 35473 35471 35501 35500 35472 36226 35501 35472 35472 36225 36226 35472 36217 36225 36236 36235 35473 36191 35475 35474 37796 36191 35474 35474 36249 37796 35474 35489 36249 35490 35489 35474 37757 36955 35475 35475 36191 37757 36241 36234 35476 36984 36241 35476 35476 35494 36984 36240 35494 35476 37764 36242 35478 35478 35479 37764 35480 35479 35478 36234 35480 35478 35479 36200 37764 37761 36200 35479 37770 37761 35479 35479 35480 37770 35480 36241 37770 35480 36234 36241 36251 35507 35481 35481 35482 36251 36252 36251 35482 36253 36252 35482 35482 35514 36253 35483 35484 35491 35485 35484 35483 36237 35491 35484 35484 35485 36237 36238 36237 35485 36239 36228 35486 36246 36239 35486 35486 35487 36246 36979 36246 35487 35487 36232 36979 36245 35498 35488 35489 35490 36249 35490 35502 36249 36237 35492 35491 35492 36238 36254 35492 36237 36238 35493 36247 36248 36985 35496 35494 35494 36248 36985 35494 36240 36248 37783 36984 35494 35494 35495 37783 35496 35495 35494 37784 37783 35495 38564 37784 35495 38565 38564 35495 35495 35496 38565 35496 36985 37790 35496 37790 38565 36970 35499 35497 35497 36235 36970 36982 36235 35497 35497 35498 36982 35498 36245 36982 36970 36236 35499 36987 36255 35500 35500 35501 36987 37785 36987 35501 35501 37778 37785 35501 36226 37778 36250 36249 35502 36251 36250 35502 35502 35503 36251 35503 35507 36251 35504 35505 35506 35510 35506 35505 35505 35509 35510 35513 35509 35505 36986 36247 35506 35506 35510 36986 35509 35519 36266 35520 35519 35509 35509 35513 35520 35511 35510 35509 36266 35511 35509 36990 36986 35510 35510 35512 36990 35510 35511 35512 35515 35512 35511 35516 35515 35511 36266 35516 35511 36991 36990 35512 35512 35515 36991 36988 36256 35514 37002 36988 35514 35514 35527 37002 36256 36253 35514 35515 35516 36991 37003 36991 35516 35516 36266 37003 36272 35519 35517 36278 36272 35517 35517 36277 36278 35517 35518 36277 36280 36277 35518 35518 35529 36280 36272 36266 35519 37000 36273 35521 37001 37000 35521 35521 35522 37001 37806 37001 35522 35522 36296 37806 35522 35524 36296 36274 35524 35523 35524 36274 36296 36283 36280 35529 35529 35530 36283 35530 35531 36283 36999 36283 35531 35531 36273 36999 36290 35534 35532 35532 35535 36290 36291 35535 35533 36292 36291 35533 35533 36284 36292 35533 36275 36284 36299 36287 35534 35534 36288 36299 36290 36288 35534 37009 36290 35535 37010 37009 35535 35535 36291 37010 36258 35537 35536 36293 36258 35536 36286 35540 35538 37015 36293 35539 35539 35552 37015 36297 35541 35540 35541 36303 36304 37825 36303 35541 37826 37825 35541 35541 36297 37826 35542 35546 35548 35549 35546 35542 35544 36298 36300 38616 36306 35544 35544 37028 38616 35544 36300 37028 35545 35546 35549 35547 35546 35545 35556 35547 35545 35558 35556 35545 35545 35549 35558 37013 35548 35546 35546 35547 37013 37036 37013 35547 35547 36305 37036 35547 35556 36305 35549 35550 35558 35566 35558 35550 36321 35566 35550 35550 35559 36321 37060 35560 35551 37061 37060 35551 35551 35567 37061 37037 37015 35552 37040 37037 35552 35552 36307 37040 35562 35561 35553 36305 35556 35554 36309 36305 35554 35554 35564 36309 35554 35563 35564 35554 35555 35563 35556 35555 35554 35565 35563 35555 35555 35557 35565 35555 35556 35557 35558 35557 35556 35557 35558 35565 35566 35565 35558 37058 36321 35559 37060 37059 35560 36327 35571 35561 37047 36327 35561 35561 35562 37047 35562 37041 37047 35562 36302 37041 36304 36302 35562 35565 35564 35563 36315 36309 35564 36316 36315 35564 35564 35570 36316 35564 35565 35570 35565 35566 35570 36321 35570 35566 35567 36324 37061 35567 36317 36324 37046 36313 35568 35568 36312 37046 36313 36307 35568 36321 36316 35570 36327 36326 35571 37055 36328 35572 36335 36312 35573 36343 36335 35573 37881 36334 35574 38700 37881 35574 35574 37909 38700 35574 37097 37909 37894 37097 35574 35574 35575 37894 35576 35575 35574 36351 35576 35574 35574 36344 36351 35574 36334 36344 37914 37894 35575 35575 35606 37914 35575 35576 35606 35608 35606 35576 37105 35608 35576 35576 37099 37105 35576 37094 37099 35576 36351 37094 35579 35578 35577 36326 35579 35577 36349 36347 35578 35578 36346 36349 35578 35579 36346 37054 36346 35579 35579 37053 37054 35579 36326 37053 37087 37081 35584 35584 36350 37087 35585 35586 35587 35589 35587 35586 35596 35589 35586 35586 35595 35596 36352 36351 35588 36353 36352 35588 35589 35596 35599 36357 36353 35590 37100 36357 35590 35590 36370 37100 35591 35592 37088 37088 37083 35591 35596 35595 35593 35600 35596 35593 35611 35600 35593 35593 35594 35611 35623 35611 35594 35594 35598 35623 35600 35599 35596 36358 35609 35597 36360 36358 35597 35597 36356 36360 36365 35603 35602 36366 36365 35602 35602 36364 36366 35603 36365 36367 36367 35604 35603 36369 35605 35604 35604 36368 36369 35604 36367 36368 35606 35617 37914 35624 35617 35606 35606 35607 35624 35608 35607 35606 36383 35625 35607 35607 35608 36383 36379 35624 35607 35607 35625 36379 37106 36383 35608 35608 37105 37106 36358 35621 35609 35611 35623 36385 37921 37107 35613 35613 35629 37921 35613 35614 35629 35644 35629 35614 35615 36363 36377 35624 35618 35617 35617 37104 37914 35617 36369 37104 35620 35621 36359 35622 35621 35620 36384 35622 35620 35620 36373 36384 35620 36359 36373 35621 36358 36359 36384 35627 35622 36390 36385 35623 36379 36378 35624 36383 36381 35625 35625 36378 36379 36381 36380 35625 35633 35631 35627 36384 35633 35627 35640 35639 35628 35628 35634 35640 38730 37921 35629 35629 37919 38730 35629 37111 37919 35629 35644 37111 35630 36404 37110 35630 36403 36404 35630 36402 36403 35633 35632 35631 35633 36387 36399 35633 36384 36387 36414 35640 35634 35641 35636 35635 35635 35639 35641 37116 36392 35636 35636 35641 37116 36398 35647 35637 37128 35646 35638 35638 36417 37128 36413 35641 35639 35639 35640 36413 36414 36413 35640 37922 37116 35641 35641 36410 37922 36413 36410 35641 36401 35643 35642 35642 36400 36401 35642 36385 36400 35643 36401 36402 35644 37110 37111 35645 35646 36364 37901 36364 35646 35646 37128 37901 37113 36406 35647 35647 37112 37113 35647 36398 37112 35653 35651 35648 35657 35653 35648 36419 35657 35648 35648 36415 36419 36416 36415 35648 35648 35649 36416 35650 35649 35648 35651 35650 35648 37127 36416 35649 35649 36405 37127 35649 35650 36405 36406 36405 35650 35653 35652 35651 35652 35656 35659 35652 35653 35656 35657 35656 35653 35654 35660 35661 35663 35660 35654 35654 35655 35663 35656 35658 35665 35656 35657 35658 35664 35659 35656 35665 35664 35656 36419 35658 35657 36419 35665 35658 35660 35674 35675 36421 35674 35660 35660 36420 36421 35660 35663 36420 35662 35661 35660 35675 35662 35660 35661 35662 37138 37945 37138 35662 35662 37143 37945 35662 35675 37143 35663 35670 36420 37140 35668 35665 35665 35666 37140 35667 35666 35665 36419 35667 35665 37943 37140 35666 35666 37934 37943 37939 37934 35666 35666 35667 37939 35667 37133 37939 35667 36419 37133 35672 35671 35669 37953 35672 35669 35669 37140 37953 36424 36420 35670 35670 35674 36424 35671 35672 35713 37162 35713 35672 37163 37162 35672 37953 37163 35672 37145 36423 35673 35673 36422 37145 35674 36421 36424 37144 37143 35675 35675 36423 37144 36440 36431 35676 35676 35677 36440 35677 36432 36440 35677 35678 36432 35679 35678 35677 35678 35704 36432 35678 35679 35704 36441 35704 35679 35684 35683 35680 35689 35684 35680 35691 35689 35680 36428 35691 35680 35680 35681 36428 35682 35681 35680 35683 35682 35680 37151 36428 35681 35681 37150 37151 35681 36429 37150 35681 35682 36429 36430 36429 35682 36433 36430 35682 35682 35683 36433 35683 35684 36433 37145 36422 35685 37146 37145 35685 35685 36434 37146 35686 35687 35700 35688 35687 35686 36436 35700 35687 35687 35688 36436 35689 35690 35693 35691 35690 35689 35690 35692 35693 36428 35692 35690 35690 35691 36428 35694 35693 35692 36437 35694 35692 35692 36425 36437 36428 36425 35692 36446 35695 35693 35693 35694 36446 36455 36446 35694 37161 36455 35694 35694 36437 37161 36446 35712 35695 36433 35698 35696 35696 36430 36433 37155 36430 35696 37156 37155 35696 35696 35697 37156 35698 35697 35696 35697 36447 37156 35697 35705 36447 35697 35698 35705 36443 36438 35699 36449 36443 35699 36444 35701 35700 37165 36444 35700 35700 36436 37165 37187 35711 35701 35701 35709 37187 35710 35709 35701 36444 35710 35701 36432 35704 35702 37955 36432 35702 37960 37955 35702 35702 35703 37960 35704 35703 35702 35703 37166 37960 35703 35704 37166 35704 36441 37166 35705 36442 36447 35705 35706 36442 35706 35713 36442 37968 37187 35709 35709 35710 37968 35710 37962 37968 35710 36444 37962 35721 35720 35711 37186 35721 35711 37187 37186 35711 36453 35715 35712 35712 36446 36453 37162 36442 35713 35715 36458 36463 36459 36458 35715 36460 36459 35715 36462 36460 35715 35715 36461 36462 35715 36453 36461 35716 36467 36474 37183 36467 35716 37979 37183 35716 35716 37185 37979 35716 35718 37185 35716 35717 35718 35718 37184 37185 37197 37184 35718 35719 35721 35722 35719 35720 35721 37188 35722 35721 35721 37186 37188 36466 36464 35722 36481 36480 35723 37210 36481 35723 35723 36488 37210 35723 35730 36488 37216 36485 35725 37217 37216 35725 35725 36486 37217 35725 35726 36486 36487 36486 35726 37200 36487 35726 35726 36476 37200 35727 35728 37203 37203 36476 35727 37990 37203 35728 35728 37981 37990 35728 37199 37981 35728 37198 37199 35736 35735 35729 35742 35736 35729 35729 35732 35742 35730 35737 36488 36491 36484 35731 35732 35741 35742 36477 35739 35733 35733 35734 36477 35742 35740 35736 35737 35738 35743 37210 36488 35737 35737 36493 37210 35737 35743 36493 36501 35743 35738 36489 36465 35739 35739 36477 36489 35742 35741 35740 35743 36501 37236 37225 36493 35743 37236 37225 35743 35744 35745 36490 36498 36490 35745 37215 36498 35745 37227 37215 35745 36500 35764 35746 35747 36492 36499 35754 35749 35748 35749 35754 36500 37237 36501 35750 35750 36494 37237 36524 35761 35752 37247 36500 35754 35754 36505 37247 37256 36510 35756 38072 37259 35757 38916 38072 35757 35757 36513 38916 37261 35760 35758 35758 37260 37261 35758 35759 37260 37268 37260 35759 35759 37258 37268 37261 36522 35760 35763 35762 35761 36524 35763 35761 37270 37263 35762 37271 37270 35762 37278 37271 35762 35762 35763 37278 37286 37278 35763 35763 36524 37286 35764 37250 37251 35764 36500 37250 35765 35768 36528 36509 35767 35766 36532 36509 35766 35766 35775 36532 35768 37249 37252 35768 36504 37249 36505 36504 35768 37251 36505 35768 37271 36528 35768 35768 37270 37271 35768 37252 37270 35769 35786 36542 35769 35770 35786 35771 35770 35769 37282 35771 35769 35769 36537 37282 36542 36537 35769 35770 35777 35786 36531 35777 35770 35770 36525 36531 35770 36514 36525 36515 36514 35770 35770 35771 36515 37273 36515 35771 37282 37273 35771 36525 35778 35772 36531 36525 35772 35772 35777 36531 35775 35774 35773 35781 35775 35773 35781 35780 35775 35776 37280 37286 35776 36540 37280 35776 35784 36540 37286 36524 35776 35777 35785 35786 35789 35785 35777 35778 36516 36517 36520 36516 35778 36525 36520 35778 35779 35780 35781 36534 35783 35782 35782 36523 36534 35783 36534 36535 36541 36540 35784 35787 35786 35785 35789 35787 35785 35786 36536 36542 35786 35788 36536 35786 35787 35788 36550 36536 35788 37305 36550 35788 35811 35810 35790 36559 36558 35791 35791 35792 36559 36560 36559 35792 35792 36548 36560 35793 35794 36548 35794 36547 36548 38102 36547 35794 35794 37276 38102 35794 36535 37276 35795 35810 36541 35798 35797 35796 36563 35841 35797 35797 35798 36563 35798 35799 36563 35799 36553 36563 35802 35801 35800 36544 35802 35800 35800 36543 36544 37288 36543 35800 35800 35817 37288 35800 35806 35817 35800 35801 35806 35801 35802 35822 35815 35806 35801 35822 35815 35801 36545 35822 35802 35802 36544 36545 35817 35806 35803 37299 35817 35803 35803 35804 37299 35805 35804 35803 35806 35805 35803 35804 36555 37299 36556 36555 35804 35804 35805 36556 35805 35806 35807 35805 35808 36556 35806 35815 35816 35816 35807 35806 37300 36556 35808 37301 37300 35808 35808 35809 37301 35809 36557 37303 37302 37301 35809 37303 37302 35809 37285 36541 35810 35810 37281 37285 35810 36529 37281 35810 35811 36529 35812 35813 35814 35821 35814 35813 35814 35822 36545 35814 35821 35822 35815 35821 35823 35822 35821 35815 35823 35816 35815 35823 35818 35816 37299 37288 35817 35849 35843 35818 35818 35823 35849 36567 36562 35819 35842 35823 35821 35823 35847 35849 35823 35842 35847 35824 35825 37314 35826 35825 35824 35835 35826 35824 38127 35835 35824 38128 38127 35824 35824 38124 38128 35824 37313 38124 37314 37313 35824 36566 35831 35825 35825 35826 36566 35825 35831 37314 35835 35834 35826 35826 35836 36566 35827 35843 36569 37309 36565 35829 35831 35832 37314 35832 37313 37314 35832 36564 37313 35832 35833 36564 36565 36564 35833 36568 35837 35834 37316 36568 35834 35834 35835 37316 38127 37316 35835 36568 35838 35837 35846 35839 35838 36568 35846 35838 37315 35848 35840 35840 35841 37315 37337 37315 35841 38129 37337 35841 35841 38118 38129 35841 36563 38118 35843 35849 36569 36576 35850 35844 35844 35851 36576 35846 36562 36567 36570 36562 35846 35846 36568 36570 36571 35853 35848 37321 36571 35848 35848 37315 37321 35850 37324 37325 37344 37324 35850 35850 36576 37344 35852 36574 37329 35854 35859 36581 35854 35855 35859 38999 38998 35856 35856 35857 38999 35858 35857 35856 35857 35858 38181 39742 38999 35857 35857 39004 39742 35857 39001 39004 35857 37378 39001 38181 37378 35857 35858 36584 37372 35858 37372 38181 36584 36581 35859 35859 35862 36584 36582 35863 35860 37357 36583 35861 35861 36572 37357 36585 36584 35862 35862 35878 36585 36582 35866 35863 36592 35879 35864 37369 36592 35864 35864 35865 37369 35865 37359 37369 35865 36580 37359 35866 36595 36596 35866 36582 36595 35875 35870 35869 35876 35875 35869 35870 35875 36597 35874 35873 35872 35884 35874 35872 35873 35874 36588 36590 36588 35874 37382 36590 35874 37391 37382 35874 35874 35884 37391 37384 37377 35875 37385 37384 35875 35875 35876 37385 37377 36597 35875 35876 36609 37385 35876 35886 36609 36592 36591 35879 36602 36601 35880 35881 35882 36603 37409 35894 35881 35881 37396 37409 35881 36607 37396 35881 36604 36607 35881 36603 36604 35882 36598 36603 36608 35885 35883 35883 35888 36608 35884 35885 37391 35885 36608 37391 37411 36609 35886 36611 36602 35887 35887 35898 36611 36612 36608 35888 35888 35890 36612 35888 35889 35890 36620 35890 35889 35889 35895 36620 35890 35896 36612 35897 35896 35890 36620 35897 35890 35891 35892 37398 35892 36605 37398 37418 35900 35894 35894 37409 37418 35895 36619 36620 35895 36618 36619 35895 35907 36618 35895 35901 35907 37420 36612 35896 35896 35897 37420 35897 36620 37420 35898 35899 36611 36623 36611 35899 36627 36623 35899 35899 35902 36627 38219 37417 35900 35900 38210 38219 35900 37418 38210 35901 35906 35907 35901 35905 35906 35902 35903 36627 37434 36627 35903 35903 37417 37434 35914 35905 35904 35904 35911 35914 35914 35906 35905 36630 35907 35906 37441 36630 35906 35906 35914 37441 38216 36618 35907 35907 36631 38216 35907 36630 36631 35908 35918 36629 37437 35917 35908 35908 35912 37437 35908 35909 35912 35910 35909 35908 36629 35910 35908 35909 37428 38225 35909 37421 37428 35909 36628 37421 35909 35910 36628 38225 35912 35909 35910 36624 36628 36626 36624 35910 36629 36626 35910 35915 35914 35911 35916 35915 35911 38229 37437 35912 35912 38228 38229 35912 38225 38228 37438 37436 35913 35913 36637 37438 36629 35918 35913 37430 36629 35913 37436 37430 35913 35914 35915 37441 35915 36644 37441 35915 35916 36644 37451 36636 35917 35917 37437 37451 35919 35920 35921 35923 35921 35920 35920 35922 35923 35931 35922 35920 35921 35923 36634 35922 35931 37450 36641 35923 35922 37450 36641 35922 35923 36633 36634 36641 36633 35923 35935 35926 35924 37445 36662 35925 35925 36643 37445 37458 37439 35926 35926 35935 37458 35927 35934 35935 38242 37461 35928 38243 38242 35928 35928 37446 38243 35928 35929 37446 35930 35929 35928 37461 35930 35928 35929 37445 37446 35929 36662 37445 37470 36661 35930 35930 37465 37470 35930 37461 37465 37463 37449 35931 35931 36658 37463 35931 37449 37450 37471 37464 35932 35932 35933 37471 37473 37471 35933 39054 37473 35933 35933 39053 39054 35933 37452 39053 37453 35935 35934 35934 36655 37453 35935 37454 37458 35935 37453 37454 36657 36656 35936 35936 35938 36657 35940 35938 35936 35937 35939 35940 37455 35939 35937 37456 37455 35937 37457 37456 35937 35937 36649 37457 35940 35939 35938 37468 36657 35938 35938 37467 37468 37469 37467 35938 35938 37455 37469 35938 35939 37455 36659 36658 35942 36663 36659 35942 35951 35950 35944 35944 35949 35951 35947 35946 35945 35957 35947 35945 38263 36664 35946 35946 36665 38263 35946 35947 36665 36668 36665 35947 35947 35958 36668 35947 35957 35958 35954 35953 35948 35948 35951 35954 35948 35950 35951 35952 35951 35949 37476 35952 35949 35949 35955 37476 35951 35952 35954 37474 35954 35952 37475 37474 35952 38267 37475 35952 35952 37476 38267 36668 35958 35953 35953 35954 36668 37474 36668 35954 35955 36670 37476 36671 36670 35955 36667 35961 35956 35956 36666 36667 35961 35960 35959 37477 36671 35960 37478 37477 35960 35960 36667 37478 35960 35961 36667 35962 36674 37480 35962 36672 36674 36673 35965 35963 35973 35972 35964 36678 35973 35964 35964 35965 36678 36680 36678 35965 37485 36680 35965 37486 37485 35965 35965 36675 37486 35965 36673 36675 35968 35967 35966 35966 35974 36682 35970 35969 35968 38282 35975 35969 35969 38281 38282 35969 35970 38281 35970 37487 38281 35982 35976 35971 36681 35982 35971 35971 36679 36681 35971 35973 36679 35971 35972 35973 35973 36678 36679 36690 36682 35974 35974 35978 36690 37494 36684 35975 37495 37494 35975 38282 37495 35975 35984 35977 35976 36692 35984 35976 35976 35983 36692 35976 35982 35983 35984 35978 35977 35978 35984 36690 38273 36676 35979 38279 38273 35979 35979 35980 38279 35981 35980 35979 36687 35981 35979 39082 38279 35980 39083 39082 35980 35980 36709 39083 35980 35981 36709 35981 36708 36709 37499 36708 35981 35985 35983 35982 36683 35985 35982 35982 36681 36683 36699 36692 35983 35983 35986 36699 35983 35985 35986 37492 36690 35984 37493 37492 35984 35984 36692 37493 35989 35986 35985 35990 35989 35985 36688 35990 35985 35985 36683 36688 37501 36699 35986 37503 37501 35986 37520 37503 35986 35986 36697 37520 35986 35991 36697 35986 35989 35991 35987 37498 37500 35989 35990 35991 37529 36698 35990 35990 37496 37529 35990 36688 37496 36697 35991 35990 36698 36697 35990 36706 36705 35992 37519 36706 35992 35992 37517 37519 37516 36696 35993 35993 36695 37516 35994 36708 37499 36709 36708 35994 37524 36709 35994 35994 37521 37524 35994 36715 37521 35995 35997 36000 36000 35996 35995 35997 35999 36000 35997 35998 35999 36705 35998 35997 35998 36705 36733 36733 35999 35998 36741 36005 35999 37543 36741 35999 35999 36733 37543 36003 36002 36001 36736 36003 36001 36001 36006 36736 36001 36004 36006 36002 37528 37533 37534 37528 36002 36002 36003 37534 37544 37534 36003 36003 36736 37544 36743 36736 36006 37547 36746 36007 36007 36742 37547 36011 36009 36008 36015 36011 36008 36011 36010 36009 37540 36748 36009 37551 37540 36009 36009 36010 37551 36010 36754 37551 36010 36011 36754 36011 36022 36754 36011 36015 36022 36029 36019 36012 36773 36029 36012 36785 36784 36013 38342 36785 36013 36013 37558 38342 36013 36776 37558 36013 36014 36776 36014 36775 36776 36023 36022 36015 36016 36756 36780 36769 36018 36017 36017 36768 36769 36018 36770 36772 36018 36769 36770 36029 36024 36019 36020 36774 36775 36786 36023 36021 36760 36754 36022 36022 36023 36760 36023 36786 36787 36777 36760 36023 36787 36777 36023 36024 36029 36030 37586 36807 36025 36025 36026 37586 37587 37586 36026 36026 36027 37587 36027 37570 37587 36027 36028 37570 36029 36028 36027 36030 36029 36027 38337 37570 36028 36028 38330 38337 36028 36773 38330 36028 36029 36773 36031 36810 36818 36031 36033 36810 36034 36033 36031 37575 37574 36032 39147 38340 36032 36032 37591 39147 36032 37590 37591 36032 37574 37590 36820 36810 36033 36033 36039 36820 36035 36036 37584 36797 36042 36035 37588 36797 36035 36035 37584 37588 36038 36037 36036 36049 36038 36036 36036 36041 36049 36036 36037 37584 36037 36038 37583 39149 37584 36037 36037 37583 39149 36038 37573 37583 36038 37572 37573 36038 36049 37572 36039 36053 36820 36054 36053 36039 36039 36040 36054 36040 36050 36054 36040 36043 36050 36044 36043 36040 36041 36046 36049 36041 36045 36046 36042 36797 36798 36042 36798 36808 36051 36050 36043 36052 36051 36043 36048 36046 36045 36816 36048 36045 37581 36049 36046 37582 37581 36046 37596 37582 36046 36046 36047 37596 36048 36047 36046 36047 37586 37596 36047 36807 37586 36047 36048 36807 36816 36807 36048 36049 37571 37572 37581 37571 36049 36050 36051 36824 38380 36054 36050 36050 36824 38380 36051 36052 36055 36051 36055 36824 38373 36820 36053 38378 38373 36053 36053 36054 38378 38379 38378 36054 38380 38379 36054 38377 36057 36056 36056 37613 38377 36056 37604 37613 36056 36809 37604 37615 36821 36057 37616 37615 36057 38377 37616 36057 36060 36059 36058 36827 36060 36058 36058 36822 36827 37628 37626 36059 38394 37628 36059 36059 38393 38394 36059 36060 38393 39192 38393 36060 36060 38382 39192 36060 36827 38382 36061 36829 36832 36830 36829 36061 36062 36063 37618 38383 37618 36063 36063 36838 38383 36063 36067 36838 36840 36068 36064 36064 36069 36840 36075 36070 36065 36077 36067 36066 36066 36076 36077 36839 36838 36067 36847 36839 36067 36067 36077 36847 36849 36079 36068 36068 36840 36849 37631 36840 36069 36069 37626 37631 36841 36071 36070 36070 36075 36841 36859 36842 36071 36071 36841 36859 36072 36836 36837 36073 36074 36078 36080 36078 36074 36075 36081 36841 36852 36845 36076 36076 36844 36852 36845 36077 36076 36077 36846 36847 36077 36845 36846 36078 36080 36084 36848 36080 36079 36855 36848 36079 36079 36849 36855 36848 36084 36080 36081 36085 36841 37638 36843 36082 36082 36083 37638 36083 36860 37638 36083 36850 36860 36853 36090 36084 36084 36848 36853 37637 36841 36085 37656 37637 36085 36086 36833 36866 36870 36089 36087 36087 36869 36870 37667 37656 36089 36089 36870 37667 37667 36105 36091 36091 37646 37667 36091 36866 37646 36091 36092 36866 37662 36865 36093 36093 36102 37662 36874 36096 36094 36094 36095 36874 36095 37665 38420 36095 37661 37665 36095 36868 37661 38425 36874 36095 36095 38420 38425 36096 36874 38431 36098 36097 36096 36875 36098 36096 36096 36099 36875 36100 36099 36096 38431 36100 36096 37670 36875 36099 36099 37668 37670 37669 37668 36099 36099 36100 37669 38436 37669 36100 39246 38436 36100 36100 39239 39246 36100 38431 39239 36870 36104 36101 37667 36870 36101 36101 36105 37667 38423 37662 36102 36102 37673 38423 36102 36871 37673 36102 36103 36871 36872 36871 36103 36103 36117 36872 36103 36116 36117 36876 36107 36104 36880 36876 36104 36104 36869 36880 36870 36869 36104 36115 36114 36106 36886 36115 36106 36887 36886 36106 36876 36108 36107 36876 36109 36108 36882 36119 36109 36109 36876 36882 36110 36113 36878 36110 36111 36113 36112 36111 36110 38429 36113 36111 36111 38428 38429 36111 37671 38428 36111 36112 37671 36112 36884 37671 36112 36883 36884 37672 36878 36113 38429 37672 36113 36893 36889 36115 36115 36888 36893 36115 36886 36888 36118 36117 36116 36120 36118 36116 36873 36872 36117 37673 36873 36117 37674 37673 36117 36117 36891 37674 36117 36118 36891 37677 36891 36118 36118 36120 37677 36119 36882 36883 36120 36895 37677 36121 36123 36124 36124 36123 36122 37678 36124 36122 36122 37675 37678 36122 36877 37675 37679 36125 36124 36124 37678 37679 37679 36897 36125 36897 36896 36125 38459 37693 36129 36129 36130 38459 36131 36130 36129 38460 38459 36130 36130 37698 38460 36130 36900 37698 36130 36131 36900 37700 36900 36131 37704 37700 36131 36131 36134 37704 36135 36136 36908 36908 36144 36135 37702 37701 36136 37701 36908 36136 36904 36901 36137 36137 36140 36904 36904 36140 36138 36138 36139 36904 36907 36904 36139 37699 36907 36139 36139 37697 37699 36141 36144 36912 36910 36909 36142 36142 36145 36910 36146 36145 36142 36148 36147 36143 36911 36148 36143 36144 36908 36912 37711 36910 36145 36145 37709 37711 36145 36146 37709 36146 36913 37709 36147 36148 36151 37712 36150 36148 37713 37712 36148 39293 37713 36148 36148 36150 36151 36914 36153 36149 37712 36914 36149 36149 36150 37712 36152 36153 36914 36917 36915 36154 37725 36917 36154 36154 36920 37725 36154 36155 36920 36155 36160 36920 36164 36158 36156 36156 36161 36164 36171 36161 36156 36918 36171 36156 36156 36157 36918 36158 36157 36156 36157 36158 36916 37730 36918 36157 36157 36916 37730 36919 36160 36159 36159 36162 36919 36921 36920 36160 36160 36919 36921 36161 36170 36172 36171 36170 36161 36924 36919 36162 36162 36923 36924 36162 36163 36923 36163 36165 36923 36926 36923 36165 36166 36175 36176 36167 36177 36178 36178 36177 36168 36933 36178 36168 36168 36928 36933 36168 36169 36928 36934 36928 36169 36939 36934 36169 36169 36179 36939 36174 36172 36170 36929 36174 36170 36170 36171 36929 36930 36929 36171 36171 36918 36930 36174 36173 36172 36173 36935 36936 36173 36174 36935 37748 36935 36174 36174 36929 37748 36927 36176 36175 37742 36927 36175 36175 37735 37742 36175 36925 37735 36927 36181 36176 37745 36942 36178 36178 36933 37745 36940 36939 36179 36194 36184 36180 36180 36188 36194 36941 36182 36181 36181 36937 36941 36181 36927 36937 36943 36185 36182 36946 36943 36182 36182 36941 36946 36184 36939 36940 36184 36934 36939 36184 36194 36934 36193 36192 36187 36942 36193 36187 36951 36194 36188 39354 38544 36189 39357 39354 36189 36189 37796 39357 36189 36190 37796 36191 36190 36189 38544 36191 36189 36190 36191 37796 38544 37757 36191 36198 36197 36192 36199 36198 36192 36192 36193 36199 36956 36199 36193 36193 36949 36956 36950 36949 36193 36193 36948 36950 36193 36942 36948 36948 36934 36194 37753 36948 36194 36194 36951 37753 37755 36964 36195 37756 37755 36195 37763 37756 36195 36195 36957 37763 36958 36957 36195 36195 36196 36958 36196 36200 36958 36197 36198 36205 36959 36205 36198 36198 36199 36959 36199 36956 36959 36200 36204 37764 36200 36957 36958 37761 36957 36200 37753 36951 36201 36201 36960 37753 36962 36960 36201 36244 36243 36202 36982 36244 36202 36202 36203 36982 36969 36204 36202 36202 36243 36969 36203 36235 36982 36204 36981 37764 36204 36969 36981 36220 36218 36205 36205 36219 36220 36205 36207 36219 36208 36207 36205 36959 36208 36205 36206 36961 36962 36206 36209 36961 36206 36208 36209 36229 36219 36207 36207 36228 36229 36959 36209 36208 36959 36956 36209 37758 36961 36209 36209 36956 37758 36965 36211 36210 36210 36214 36965 36210 36213 36214 36215 36213 36210 36223 36221 36211 36965 36223 36211 36212 37759 38553 36212 36213 37759 36214 36213 36212 37769 36214 36212 38553 37769 36212 36213 36963 37759 36213 36215 36963 38551 36965 36214 36214 37769 38551 36225 36217 36216 36216 36224 36225 37765 36224 36216 36216 37762 37765 36216 37754 37762 36216 36954 37754 36975 36227 36218 36218 36972 36975 36218 36220 36972 36219 36229 36230 36230 36220 36219 36220 36230 36972 36968 36233 36221 36221 36222 36968 36223 36222 36221 38547 36968 36222 38549 38547 36222 36222 36223 38549 38550 38549 36223 36223 36965 38550 37765 36971 36224 36226 36225 36224 36971 36226 36224 36226 36971 37778 36983 36238 36227 36227 36975 36983 36230 36229 36228 36239 36230 36228 36974 36972 36230 37780 36974 36230 37781 37780 36230 36230 36239 37781 36976 36232 36231 36232 36976 36979 36968 36966 36233 36235 36236 36970 36983 36254 36238 36239 36979 37781 36239 36246 36979 37771 37770 36241 37777 37771 36241 36241 36984 37777 36980 36245 36242 37764 36980 36242 36243 36244 36980 36981 36969 36243 36243 36980 36981 36244 36245 36980 36982 36245 36244 36985 36248 36247 37789 36985 36247 36247 36986 37789 36249 37795 37796 36249 36257 37795 36249 36250 36257 36250 36251 36252 36250 36253 36257 36250 36252 36253 36253 36256 36257 36989 36259 36254 36254 36983 36989 36992 36268 36255 36255 36987 36992 36988 36257 36256 37800 37795 36257 36257 36988 37800 37016 37002 36258 36258 37014 37016 36258 36293 37014 36262 36260 36259 36989 36262 36259 36260 36261 36264 36262 36261 36260 37804 36264 36261 36261 37803 37804 36261 36262 37803 36262 36989 37803 36263 36269 36271 36270 36269 36263 36263 36265 36270 37805 36265 36264 36264 37804 37805 36266 36993 37003 36266 36272 36993 37004 36275 36267 36267 36992 37004 36267 36268 36992 36276 36271 36269 36285 36276 36269 36995 36993 36272 36272 36278 36995 37000 36999 36273 36274 36295 36296 37004 36284 36275 36279 36278 36277 36280 36279 36277 37005 36995 36278 37007 37005 36278 36278 36279 37007 36279 36281 37007 36279 36280 36281 36283 36281 36280 37012 37007 36281 37817 37012 36281 36281 36282 37817 36283 36282 36281 38594 37817 36282 36282 37807 38594 36282 36283 37807 36283 36999 37807 37004 36292 36284 36300 36298 36287 36287 36299 36300 37812 36299 36288 37814 37812 36288 36288 36289 37814 36290 36289 36288 36289 36290 37009 38587 37814 36289 36289 37824 38587 36289 37009 37824 36291 36292 37010 36292 37004 37010 37015 37014 36293 37806 36296 36294 37822 37806 36294 36294 37027 37822 36294 37008 37027 36294 36295 37008 36296 36295 36294 36297 37017 37826 36301 36300 36299 37813 36301 36299 36299 37812 37813 36300 36301 37028 37813 37809 36301 37810 37028 36301 36301 37809 37810 36304 36303 36302 37835 37041 36302 36302 37827 37835 36302 36303 37827 36303 37825 37827 36305 36308 37036 36309 36308 36305 36306 38616 38628 36306 36310 36317 36311 36310 36306 37848 36311 36306 38628 37848 36306 37044 37040 36307 36307 36313 37044 36308 37026 37036 37841 37026 36308 36308 36314 37841 36308 36309 36314 36315 36314 36309 36324 36317 36310 36310 36322 36324 36323 36322 36310 36325 36323 36310 36310 36311 36325 37049 36325 36311 37848 37049 36311 37050 37046 36312 37051 37050 36312 36312 36335 37051 37045 37043 36313 37046 37045 36313 36313 37043 37044 38640 37841 36314 36314 37048 38640 36314 36315 37048 36315 36329 37048 36315 36319 36329 36315 36316 36319 36316 36318 36319 36331 36318 36316 36316 36321 36331 36320 36319 36318 37876 36320 36318 36318 36330 37876 36331 36330 36318 36339 36329 36319 36341 36339 36319 36319 36320 36341 37070 36341 36320 37880 37070 36320 36320 37879 37880 38684 37879 36320 36320 37876 38684 39440 36331 36321 36321 38663 39440 36321 37058 38663 37867 36324 36322 36322 37062 37867 36322 36323 37062 36323 36325 37062 37866 37061 36324 37867 37866 36324 37856 37062 36325 36325 37853 37856 36325 37851 37853 36325 37049 37851 36326 36327 37053 37852 37053 36327 36327 37047 37852 37056 37048 36329 36329 36338 37056 36339 36338 36329 36330 36331 37862 39446 37876 36330 36330 37862 39446 39440 37862 36331 36345 36334 36332 36332 36335 36345 36336 36335 36332 36332 36333 36336 36334 36333 36332 37858 37042 36333 37881 37858 36333 36333 36334 37881 37042 36336 36333 36334 36342 36344 36343 36342 36334 36345 36343 36334 36335 36336 37051 36335 36343 36345 37063 37051 36336 36336 37042 37063 37071 37064 36337 38683 37071 36337 36337 37081 38683 36338 36340 37056 36338 36339 36340 36341 36340 36339 37057 37056 36340 37861 37057 36340 36340 37860 37861 36340 37067 37860 36340 36341 37067 37070 37067 36341 37077 36349 36346 37882 37077 36346 36346 37054 37882 36349 36348 36347 37086 36350 36348 36348 36349 37086 36349 37077 37086 37885 37087 36350 36350 37086 37885 36351 36352 37094 36352 36353 36357 36352 36357 37094 37101 36360 36354 36354 36355 37101 36356 36355 36354 36360 36356 36354 37899 37101 36355 36355 37889 37899 36355 37884 37889 36355 36356 37884 36356 37084 37884 36356 37083 37084 37100 37094 36357 36360 36359 36358 36374 36373 36359 37911 36374 36359 37912 37911 36359 36359 37101 37912 36359 36360 37101 37108 36377 36361 36361 36375 37108 36361 36362 36375 36363 36362 36361 36377 36363 36361 36376 36375 36362 37900 36366 36364 37901 37900 36364 37095 36367 36365 37102 37095 36365 36365 36366 37102 37902 37102 36366 36366 37900 37902 37095 36368 36367 37905 37103 36368 36368 37095 37905 37103 36369 36368 36369 37103 37104 37106 37100 36370 36370 36383 37106 36370 36371 36383 36371 36381 36383 36371 36372 36381 36382 36381 36372 37109 36384 36373 36373 36374 37109 38720 37109 36374 36374 37911 38720 37917 37108 36375 38731 37917 36375 36375 36376 38731 36376 38729 38731 36376 37107 38729 36391 36387 36384 37109 36391 36384 36385 36397 36400 36385 36390 36397 37926 37124 36387 37927 37926 36387 36387 36388 37927 36389 36388 36387 36391 36389 36387 39525 37927 36388 36388 39517 39525 36388 38748 39517 36388 36389 38748 36389 38744 38748 36389 38732 38744 36389 37918 38732 36389 36391 37918 36390 36394 36397 36390 36393 36394 36390 36392 36393 38742 37918 36391 36391 37109 38742 37117 36393 36392 36392 37116 37117 36393 37117 38749 36396 36394 36393 38749 36396 36393 36394 36395 36397 36396 36395 36394 39518 37925 36395 40264 39518 36395 40265 40264 36395 36395 36396 40265 36400 36397 36395 37925 36400 36395 36396 40263 40265 36396 38749 40263 37118 36401 36400 37925 37118 36400 37118 36402 36401 37119 36403 36402 36402 37118 37119 37121 36404 36403 37126 37121 36403 36403 37119 37126 37111 37110 36404 37920 37111 36404 37923 37920 36404 37924 37923 36404 36404 37121 37924 36405 37113 37127 36405 36406 37113 36412 36408 36407 37928 36414 36408 37932 37928 36408 36408 36412 37932 36411 36410 36409 38756 36411 36409 38757 38756 36409 39529 38757 36409 36409 37933 39529 36409 37928 37933 36409 36410 37928 36410 36411 37922 36410 36414 37928 36410 36413 36414 36411 37117 37922 38752 37117 36411 39527 38752 36411 36411 38756 39527 36412 37125 37932 37133 36419 36415 37939 37133 36415 36415 37929 37939 36415 36416 37929 36416 37127 37929 37130 37128 36417 36417 37129 37130 37131 37129 36417 36424 36421 36420 37145 37144 36423 36425 36426 36437 36427 36426 36425 36428 36427 36425 37161 36437 36426 36426 37154 37161 36426 37147 37154 36426 36427 37147 37148 37147 36427 37151 37148 36427 36427 36428 37151 36429 36430 37155 37152 37150 36429 37155 37152 36429 36431 36435 36436 36440 36435 36431 37164 36440 36432 37955 37164 36432 36434 36439 37146 36434 36438 36439 37159 36436 36435 37160 37159 36435 37164 37160 36435 36435 36440 37164 37954 37165 36436 36436 37159 37954 36443 36439 36438 37157 37146 36439 37158 37157 36439 37173 37158 36439 36439 36443 37173 37168 37166 36441 36441 36445 37168 36442 37162 37172 36448 36447 36442 37172 36448 36442 36443 36449 37173 36444 37165 37962 36445 36452 37168 36454 36453 36446 36455 36454 36446 37959 37156 36447 36447 36448 37959 38790 37959 36448 38791 38790 36448 38792 38791 36448 36448 37172 38792 36449 36450 37173 37177 37173 36450 36450 36456 37177 36451 36457 37176 37176 36452 36451 37174 37168 36452 37175 37174 36452 37176 37175 36452 36453 36454 36461 36462 36461 36454 36454 36455 36462 37976 36462 36455 36455 37179 37976 36455 37169 37179 36455 37161 37169 37181 37177 36456 36456 36474 37181 37973 37176 36457 36457 36459 37973 36457 36458 36459 36463 36458 36457 37974 37973 36459 36459 36460 37974 38818 37974 36460 36460 38817 38818 36460 37975 38817 36460 36462 37975 37976 37975 36462 36466 36465 36464 36489 36477 36465 36469 36468 36467 37182 36469 36467 37183 37182 36467 36467 36470 36474 36467 36468 36470 36478 36475 36468 36468 36469 36478 36475 36470 36468 36479 36478 36469 38003 36479 36469 36469 37995 38003 36469 37182 37995 37194 36474 36470 36470 36471 37194 36475 36471 36470 38813 37194 36471 36471 37978 38813 36471 36472 37978 36473 36472 36471 36478 36473 36471 36471 36475 36478 37988 37978 36472 38002 37988 36472 36472 37191 38002 36472 36473 37191 37208 37191 36473 36473 37207 37208 36473 36479 37207 36473 36478 36479 37194 37181 36474 37203 37200 36476 37209 37207 36479 38003 37209 36479 36480 37195 37197 36480 36481 37195 37196 37195 36481 36481 36493 37196 37210 36493 36481 37222 36492 36482 36482 36483 37222 36484 36483 36482 37228 37222 36483 36483 37206 37228 36483 36484 37206 36484 37205 37206 36484 36491 37205 37205 36491 36485 37216 37205 36485 37223 37217 36486 37224 37223 36486 36486 36487 37224 37233 37224 36487 36487 37201 37233 36487 37200 37201 37221 36495 36490 36490 37212 37221 36490 36498 37212 37238 36499 36492 36492 37222 37238 38011 37196 36493 38012 38011 36493 36493 37225 38012 36494 36503 38039 38037 37237 36494 38039 38037 36494 36497 36496 36495 37221 36497 36495 37242 36502 36496 36496 36497 37242 38026 37242 36497 36497 38018 38026 36497 37221 38018 37214 37212 36498 37226 37214 36498 36498 37215 37226 36500 37247 37250 37237 37236 36501 37242 36503 36502 36503 37242 38026 36503 38026 38039 37251 37247 36505 38050 37245 36506 38055 38050 36506 36506 38054 38055 38066 38054 36506 37253 36508 36507 36507 37248 37253 36508 38059 38911 36508 37253 38059 38911 37255 36508 36510 38068 38070 36510 37256 38068 38914 36512 36511 38916 36513 36512 36512 38914 38916 37264 36525 36514 36514 36515 37264 37273 37264 36515 36516 36519 36527 36520 36519 36516 36518 36517 36516 36527 36518 36516 36517 36518 36521 36517 36521 36533 36527 36526 36518 36526 36521 36518 36519 36525 37264 36519 36520 36525 38061 36527 36519 38074 38061 36519 36519 37264 38074 37275 37265 36521 38066 37275 36521 36521 36526 38066 37269 36523 36522 36522 37262 37269 36522 37261 37262 37269 36534 36523 36526 36527 38062 38067 38066 36526 36526 38063 38067 38065 38063 36526 36526 38062 38065 36527 38061 38062 36530 36529 36528 37278 36530 36528 36528 37271 37278 36529 36530 37281 36530 37280 37281 36530 37278 37280 37279 36535 36534 36534 37269 37279 37279 37276 36535 36550 36549 36536 36549 36542 36536 37283 37282 36537 37284 37283 36537 36537 36538 37284 36539 36538 36537 36542 36539 36537 37290 37284 36538 36538 37289 37290 37292 37289 36538 36538 36539 37292 36539 36549 37292 36539 36542 36549 37281 37280 36540 37285 37281 36540 36540 36541 37285 38936 36554 36543 38937 38936 36543 36543 37288 38937 36554 36544 36543 36546 36547 38929 36548 36547 36546 38105 36548 36546 38929 38105 36546 36547 38102 38926 36547 38926 38929 37304 36560 36548 38107 37304 36548 36548 38105 38107 36549 36550 37292 37305 37292 36550 37295 37287 36551 36551 36552 37295 36552 36554 37295 37293 36563 36553 37295 37293 36553 36553 37287 37295 36554 37294 37295 38936 37294 36554 38104 37299 36555 38108 38104 36555 36555 37300 38108 36555 36556 37300 36557 36558 37303 36558 36560 37303 36558 36559 36560 38111 37303 36560 36560 37304 38111 36561 37317 38126 36561 36570 37317 36561 36562 36570 36563 37293 38118 36564 37311 37313 36564 36565 37311 37312 37311 36565 36565 37309 37312 37316 36570 36568 38137 37317 36570 38138 38137 36570 36570 37316 38138 36578 36575 36571 36579 36578 36571 37321 36579 36571 36572 36573 37357 37358 37357 36573 36573 37327 37358 36574 36577 37328 38145 37329 36574 36574 37357 38145 36574 37328 37357 37345 37328 36577 37346 37345 36577 37348 37346 36577 36587 36586 36578 37343 36587 36578 36578 36579 37343 36579 37323 37343 36579 37321 37323 36580 36583 37359 36582 36586 36595 36583 37357 37359 36584 36585 37372 36585 36593 37372 36586 36587 36600 36596 36595 36586 36600 36596 36586 37343 36600 36587 36590 36589 36588 36589 36590 37376 37376 37375 36589 37383 37376 36590 36590 37382 37383 38195 37397 36591 36591 38190 38195 36591 38177 38190 36591 36592 38177 36592 37368 38177 37369 37368 36592 38181 37372 36593 36593 37378 38181 36593 37377 37378 36593 36594 37377 36594 36597 37377 36603 36598 36596 36604 36603 36596 37338 36604 36596 36596 36599 37338 36600 36599 36596 37381 37338 36599 37390 37381 36599 36599 37380 37390 36599 37371 37380 36599 37352 37371 37353 37352 36599 37355 37353 36599 36599 36600 37355 36600 37342 37355 37343 37342 36600 37393 36606 36601 38201 37393 36601 36601 36602 38201 36602 38200 38201 36602 36615 38200 36602 36614 36615 36602 36611 36614 37338 36607 36604 36605 37397 37398 37393 36613 36606 36607 37389 37395 36607 37338 37389 36607 37395 37396 38203 37391 36608 36608 36612 38203 39016 38190 36609 36609 38199 39016 36609 37411 38199 38179 37385 36609 38188 38179 36609 38190 38188 36609 37426 36622 36610 36610 36613 37426 36611 36623 37416 36617 36614 36611 37416 36617 36611 39022 38203 36612 36612 38222 39022 36612 38217 38222 36612 37420 38217 38208 37426 36613 36613 37393 38208 36616 36615 36614 38215 36616 36614 36614 36617 38215 36615 38198 38200 36615 36616 38198 39019 38198 36616 36616 38215 39019 39021 38215 36617 36617 38218 39021 36617 37416 38218 38216 36619 36618 37420 36620 36619 38220 37420 36619 36619 38216 38220 37431 36642 36621 37432 37431 36621 36621 36622 37432 39026 37432 36622 36622 37426 39026 36623 36627 37416 37422 36628 36624 36624 36625 37422 36626 36625 36624 36625 37414 37422 37429 37414 36625 37430 37429 36625 36625 36629 37430 36625 36626 36629 37433 37416 36627 37434 37433 36627 36628 37413 37421 37422 37413 36628 37435 36631 36630 36630 36645 37435 37441 36645 36630 38221 38216 36631 38227 38221 36631 36631 37435 38227 36632 36642 36643 36635 36634 36633 38234 36635 36633 36633 37444 38234 36633 37443 37444 36633 37442 37443 36633 36641 37442 36639 36638 36634 36634 36635 36639 38239 36639 36635 36635 38234 38239 37452 36648 36636 36636 37451 37452 37439 37438 36637 36638 36639 38239 38238 36640 36638 38239 38238 36638 36640 38247 38252 38249 38247 36640 36640 38238 38249 37450 37442 36641 37440 36643 36642 36642 37431 37440 38233 37445 36643 36643 37440 38233 36644 36647 37441 36651 36647 36644 36645 38236 40565 38237 38236 36645 36645 36646 38237 36647 36646 36645 37441 36647 36645 40551 37435 36645 40565 40551 36645 36646 36647 38246 39047 38237 36646 36646 38251 39047 36646 38246 38251 36647 36651 37462 36647 37462 38246 37452 36650 36648 36651 36652 37462 38246 37462 36652 38247 38246 36652 36652 37457 38247 37469 37457 36652 38256 37469 36652 36652 36653 38256 36653 36654 36656 36653 37467 38256 36653 36656 37467 37465 37453 36655 37470 37465 36655 36655 36660 37470 37468 37467 36656 36656 36657 37468 36658 36664 38257 36658 36659 36664 38257 37463 36658 36659 36663 36664 36660 36661 37470 38258 38257 36664 38263 38258 36664 38269 38263 36665 36665 36669 38269 36665 36668 36669 37464 36667 36666 38264 37478 36667 36667 37464 38264 37479 36669 36668 36668 37474 37479 39062 38269 36669 39064 39062 36669 36669 37479 39064 38267 37476 36670 38268 38267 36670 36670 37477 38268 36670 36671 37477 37483 36674 36672 37484 37483 36672 36672 37481 37484 36672 36677 37481 38274 38272 36674 36674 37483 38274 38272 37480 36674 36675 37480 37486 38273 37482 36676 36680 36679 36678 36683 36681 36679 36689 36683 36679 37485 36689 36679 36679 36680 37485 36682 36690 37492 36689 36688 36683 36686 36685 36684 37494 36686 36684 36686 37497 37498 36686 37494 37497 36688 36693 37496 36694 36693 36688 36688 36691 36694 36688 36689 36691 37485 36691 36689 36691 37485 38275 38275 36694 36691 36692 36699 37493 39078 37496 36693 36693 39075 39078 39076 39075 36693 36693 36694 39076 36694 38272 39076 38275 38272 36694 38291 37516 36695 36695 37509 38291 37510 37509 36695 36695 37500 37510 36696 37516 37517 36697 36710 37520 36697 36698 36710 36711 36710 36698 37529 36711 36698 38280 37493 36699 36699 37501 38280 36700 36701 36704 36702 36701 36700 36704 36702 36700 36701 36703 36704 37505 36703 36701 36701 36702 37505 36702 36714 37515 36702 36704 36714 37514 37505 36702 37515 37514 36702 36712 36704 36703 36716 36712 36703 37513 36716 36703 36703 37507 37513 36703 37505 37507 36704 36713 36714 36704 36712 36713 36705 36707 36733 36705 36706 36707 37526 36707 36706 36706 37518 37526 37519 37518 36706 36735 36733 36707 37526 36735 36707 39086 39083 36709 36709 37524 39086 37525 37520 36710 36710 36711 37525 37530 37525 36711 38298 37530 36711 36711 37529 38298 36716 36713 36712 36721 36714 36713 36724 36721 36713 36713 36723 36724 36713 36717 36723 36713 36716 36717 36714 36721 38302 38302 37515 36714 37528 37521 36715 37533 37528 36715 37531 36717 36716 36716 37511 37531 37513 37511 36716 37532 36723 36717 36717 37531 37532 36718 36737 36739 36718 36728 36737 36718 36722 36728 36718 36719 36722 36720 36719 36718 36739 36720 36718 36719 36721 36724 36726 36721 36719 37537 36726 36719 36719 36720 37537 36724 36722 36719 36720 36739 37537 36721 36726 38305 38305 38302 36721 36722 36723 37532 36724 36723 36722 36729 36728 36722 37532 36729 36722 37537 36731 36725 36725 36726 37537 36727 36726 36725 36731 36727 36725 36726 36727 38308 38308 38305 36726 37542 37541 36727 36727 36731 37542 36727 37541 38308 37545 36737 36728 39865 37545 36728 36728 39098 39865 36728 36729 39098 36729 37532 39098 36740 36739 36730 36730 36731 36740 36732 36731 36730 36749 36732 36730 36730 36738 36749 36739 36738 36730 37537 36740 36731 36731 36732 37542 36732 36756 37542 36732 36749 36756 36733 36734 37543 36735 36734 36733 38311 37543 36734 36734 38306 38311 38307 38306 36734 36734 36735 38307 36735 37526 38307 36736 37539 37544 36736 36743 37539 36744 36739 36737 36745 36744 36737 37545 36745 36737 36738 36755 36764 36738 36744 36755 36738 36739 36744 36763 36749 36738 36764 36763 36738 36739 36740 37537 37543 36742 36741 38311 37547 36742 36742 37543 38311 36743 36748 37539 36744 36745 36755 37553 36755 36745 38317 37553 36745 36745 37545 38317 37546 36747 36746 37547 37546 36746 36747 37541 37542 37546 37541 36747 37540 37539 36748 36758 36756 36749 36763 36758 36749 37548 36752 36750 37550 36753 36751 38318 37550 36751 38319 38318 36751 39110 38319 36751 36751 38320 39110 36751 37549 38320 36751 37548 37549 36751 36752 37548 37550 36759 36753 36754 36762 37551 36754 36761 36762 36754 36760 36761 37561 36764 36755 39117 37561 36755 36755 38317 39117 36755 37553 38317 36756 36757 36780 36758 36757 36756 36782 36780 36757 36794 36782 36757 36757 36791 36794 36757 36788 36791 36757 36758 36788 37566 36788 36758 36758 37560 37566 36758 36779 37560 36758 36764 36779 36758 36763 36764 36759 38325 38330 36759 37550 38325 38330 36773 36759 36778 36761 36760 36760 36777 36778 36778 36762 36761 37552 37551 36762 38331 37552 36762 36762 37559 38331 36762 36778 37559 37561 36779 36764 37562 36767 36765 36765 36780 37562 37556 36783 36766 37563 37556 36766 36766 36781 37563 36766 36767 36781 37562 36781 36767 36783 36769 36768 37556 36770 36769 36769 36783 37556 38327 36772 36770 38335 38327 36770 36770 37556 38335 38329 37557 36771 36771 38327 38329 36771 36772 38327 36776 36775 36774 38341 36776 36774 36774 38340 38341 38341 37558 36776 36790 36778 36777 36777 36787 36790 36778 36790 37559 38343 37578 36779 36779 37561 38343 37578 37560 36779 36780 36781 37562 36782 36781 36780 37580 37563 36781 36781 36782 37580 36782 36796 37580 36782 36795 36796 36782 36794 36795 36789 36786 36784 37565 36789 36784 36784 37564 37565 36784 36785 37564 38342 37564 36785 36789 36787 36786 36787 36789 36790 37566 36791 36788 37565 36790 36789 36790 37565 37576 38333 37559 36790 38351 38333 36790 36790 37576 38351 36799 36794 36791 36791 36792 36799 36793 36792 36791 37566 36793 36791 37585 36799 36792 38367 37585 36792 39151 38367 36792 36792 39140 39151 36792 37579 39140 36792 36793 37579 36793 37578 37579 36793 37566 37578 36799 36795 36794 36800 36796 36795 36811 36800 36795 37585 36811 36795 36795 36799 37585 36796 36803 37580 36796 36802 36803 36806 36802 36796 36796 36801 36806 36796 36800 36801 37588 36798 36797 37588 36808 36798 36812 36801 36800 36800 36811 36812 37606 36806 36801 37610 37606 36801 36801 36814 37610 36801 36812 36814 36804 36803 36802 36805 36804 36802 36806 36805 36802 36803 37563 37580 37568 37563 36803 37592 37568 36803 36803 36804 37592 36804 36805 36815 37593 37592 36804 37599 37593 36804 37600 37599 36804 37602 37600 36804 37607 37602 36804 36804 36815 37607 36805 36806 36815 37607 36815 36806 36806 37606 37607 36817 36809 36808 37597 36817 36808 36808 37588 37597 36809 36817 37604 36819 36818 36810 36820 36819 36810 36813 36812 36811 37598 36813 36811 38367 37598 36811 36811 37585 38367 36812 36813 36814 37598 36814 36813 39156 37610 36814 36814 37598 39156 37605 37604 36817 38364 37605 36817 36817 37597 38364 36818 37574 37575 37589 37574 36818 36818 36819 37589 38366 37589 36819 36819 36820 38366 38373 38366 36820 37615 36823 36821 37615 36827 36822 36822 36823 37615 39178 38380 36824 39182 39178 36824 36824 36831 39182 37617 36831 36825 38384 37617 36825 36825 36826 38384 36826 37618 38384 36827 37616 38382 36827 37615 37616 37624 36832 36829 37625 37624 36829 36829 36830 37625 36830 37623 37625 36830 37622 37623 36830 37621 37622 36831 37617 39182 37630 36836 36832 36832 37624 37630 36833 36834 36866 37636 36866 36834 36834 36841 37636 36842 36841 36834 36835 37619 37622 37620 37619 36835 36835 36843 37620 37622 37621 36835 37634 36851 36836 36836 37630 37634 36851 36837 36836 36851 36844 36837 38389 38383 36838 36838 36839 38389 39210 38389 36839 36839 39205 39210 36839 38408 39205 36839 36847 38408 36857 36849 36840 37635 36857 36840 36840 37631 37635 36841 36842 36859 37637 37636 36841 38398 37620 36843 36843 37638 38398 36861 36852 36844 36844 36851 36861 36863 36846 36845 36845 36862 36863 36845 36852 36862 37643 36847 36846 36846 36863 37643 36847 37643 38408 36854 36853 36848 36864 36854 36848 36848 36855 36864 36858 36855 36849 36849 36857 36858 36850 36865 37648 37648 36860 36850 36851 37634 37642 37642 36861 36851 36852 36861 36862 36853 36854 36867 36854 36864 36867 36855 36858 36864 36856 37635 37645 36856 36857 37635 36858 36857 36856 37644 36858 36856 37655 37644 36856 36856 37645 37655 36858 37644 37654 37661 36864 36858 37665 37661 36858 37666 37665 36858 36858 37654 37666 38400 37638 36860 36860 37639 38400 37640 37639 36860 37648 37640 36860 37651 36862 36861 36861 37650 37651 36861 37642 37650 37643 36863 36862 37651 37643 36862 37661 36868 36864 36868 36867 36864 37662 37648 36865 37647 37646 36866 36866 37636 37647 38432 36880 36869 36869 38427 38432 36871 36873 37673 36871 36872 36873 36874 38425 38431 38438 38426 36875 36875 37670 38438 36876 36881 36882 36876 36879 36881 36880 36879 36876 38449 37675 36877 39243 38449 36877 36877 37672 39243 36877 36878 37672 38445 36885 36879 36879 38432 38445 36879 36880 38432 36885 36881 36879 36883 36882 36881 36885 36883 36881 36885 36884 36883 38433 37671 36884 38443 38433 36884 36884 36885 38443 38445 38443 36885 36886 36887 36888 37676 36888 36887 37676 36893 36888 36892 36890 36889 36893 36892 36889 37677 37674 36891 36892 36894 37682 36892 36893 36894 37684 36895 36892 36892 37683 37684 36892 37682 37683 37676 36894 36893 36894 37681 37687 36894 37680 37681 36894 37676 37680 37687 37682 36894 37685 37677 36895 36895 37684 37685 36896 36897 37696 36897 37679 37695 38458 37696 36897 36897 38457 38458 36897 37695 38457 37680 37676 36898 37681 37680 36898 36898 36899 37681 37687 37681 36899 37693 37687 36899 38468 37698 36900 38469 38468 36900 36900 37705 38469 36900 37700 37705 36901 36905 37703 36907 36905 36901 36901 36904 36907 40800 37702 36902 36902 40033 40800 36902 39285 40033 36902 36903 39285 39286 39285 36903 36903 38475 39286 36903 37703 38475 38474 37703 36905 36905 36906 38474 36907 36906 36905 39287 39286 36906 36906 38476 39287 36906 36907 38476 39286 38474 36906 36907 38470 38476 36907 37699 38470 37708 36912 36908 36908 37701 37708 39288 38480 36912 36912 38473 39288 36912 37708 38473 37721 37720 36914 36914 37712 37721 38509 37730 36916 38510 38509 36916 36916 37723 38510 37726 37722 36917 36917 37725 37726 37736 36930 36918 36918 37730 37736 37731 36921 36919 36919 36924 37731 36920 36921 37725 37732 37725 36921 36921 37731 37732 37722 36925 36922 37729 37722 36922 37737 36924 36923 36923 36926 37737 37738 37731 36924 36924 37737 37738 36925 37734 37735 36925 37722 37734 36926 36931 37741 37741 37737 36926 36938 36937 36927 37751 36938 36927 38527 37751 36927 36927 37742 38527 37745 36933 36928 36928 36934 37745 37749 37748 36929 36929 37746 37749 37747 37746 36929 36929 36930 37747 36930 37739 37747 36930 37736 37739 38524 37741 36931 39334 38524 36931 36931 38525 39334 36931 37744 38525 36931 36932 37744 36932 36936 37744 36934 36942 37745 36948 36942 36934 38528 36936 36935 36935 37749 38528 36935 37748 37749 38525 37744 36936 39337 38525 36936 36936 38528 39337 36945 36941 36937 36937 36938 36945 38526 36945 36938 38529 38526 36938 36938 37750 38529 37751 37750 36938 36941 36945 36946 37752 36944 36943 36943 36946 37752 38537 36953 36944 36944 37752 38537 36947 36946 36945 38535 36947 36945 36945 38534 38535 36945 38526 38534 36946 36947 37752 36947 38535 39349 38537 37752 36947 39349 38537 36947 37753 36950 36948 36949 36950 37753 37758 36956 36949 36949 36960 37758 37753 36960 36949 36954 36953 36952 37754 36954 36952 38542 37754 36952 36952 38538 38542 36952 36953 38538 36953 38537 38538 36955 37757 38540 36957 37761 37763 36960 36961 37758 36962 36961 36960 36963 37755 37759 36963 36964 37755 38551 38550 36965 37766 36967 36966 36966 36968 37766 37768 37766 36968 38547 37768 36968 38560 37778 36971 36971 38545 38560 36971 37765 38545 36972 36973 36975 36974 36973 36972 36983 36975 36973 37772 36983 36973 36973 36974 37772 37779 37772 36974 37780 37779 36974 36976 36977 36979 36978 36977 36976 37767 36978 36976 37782 36979 36977 37787 37782 36977 36977 36978 37787 36978 37776 37787 36978 37775 37776 36978 37767 37775 37782 37781 36979 37764 36981 36980 37773 36989 36983 36983 37772 37773 37783 37777 36984 36985 37789 37790 36986 37788 37789 36986 36990 37788 36998 36992 36987 38578 36998 36987 36987 37799 38578 36987 37785 37799 37801 37800 36988 36988 37002 37801 36989 37797 37803 36989 37774 37797 36989 37773 37774 37798 37788 36990 36990 36991 37798 36991 37003 37798 36992 36998 37004 36995 36994 36993 38571 37003 36993 36993 37816 38571 36993 36994 37816 36994 36995 37006 36994 37024 37816 36994 37006 37024 36995 37005 37006 37004 36998 36996 37011 37004 36996 37819 37011 36996 36996 36997 37819 36998 36997 36996 39379 37819 36997 36997 38578 39379 36997 36998 38578 36999 37806 37807 36999 37000 37806 37000 37001 37806 38589 37801 37002 37002 38588 38589 37002 37820 38588 37002 37016 37820 38573 37798 37003 39372 38573 37003 37003 38571 39372 37011 37010 37004 37005 37007 37012 37012 37006 37005 37033 37024 37006 37006 37012 37033 37008 37013 37027 37009 37011 37824 37009 37010 37011 38601 37824 37011 37011 37819 38601 37818 37033 37012 37012 37817 37818 38596 37027 37013 37013 37025 38596 37026 37025 37013 37036 37026 37013 38600 37016 37014 38605 38600 37014 38606 38605 37014 38617 38606 37014 37014 37015 38617 38621 38617 37015 37015 37037 38621 38592 37820 37016 38600 38592 37016 38610 37826 37017 37017 37815 38610 37038 37029 37018 37039 37038 37018 37018 37031 37039 37018 37021 37031 37023 37021 37018 37018 37019 37023 37020 37019 37018 37029 37020 37018 37019 37831 38611 37019 37020 37831 37821 37023 37019 38612 37821 37019 37019 38611 38612 37020 37828 37831 37020 37030 37828 37020 37029 37030 37021 37022 37031 37023 37022 37021 37034 37031 37022 37022 37024 37034 37022 37023 37024 37821 37024 37023 37024 37033 37034 37821 37816 37024 39389 38596 37025 37025 38620 39389 37025 37026 38620 37026 37843 38620 37026 37841 37843 37823 37822 37027 38596 37823 37027 38629 38616 37028 37028 37810 38629 37038 37030 37029 37030 37038 37828 37031 37035 37039 37031 37032 37035 37034 37032 37031 37833 37035 37032 37834 37833 37032 37032 37033 37834 37034 37033 37032 37033 37818 37834 37035 37833 37840 37840 37039 37035 37037 37040 37044 38622 38621 37037 37037 37042 38622 37043 37042 37037 37044 37043 37037 37830 37828 37038 37839 37830 37038 37038 37039 37839 38638 37839 37039 37039 37840 38638 37852 37047 37041 37041 37835 37852 37042 37859 38622 37042 37858 37859 37042 37043 37063 37043 37045 37063 37045 37051 37063 37045 37046 37051 37046 37050 37051 37048 37056 38640 38643 37851 37049 37049 37848 38643 37054 37053 37052 38668 37054 37052 39438 38668 37052 40178 39438 37052 37052 38647 40178 37052 37053 38647 38648 38647 37053 37053 37852 38648 38668 37882 37054 37055 37064 37065 37056 37057 38640 38659 38640 37057 37057 37861 38659 38664 38663 37058 37058 37863 38664 37058 37059 37863 37864 37863 37059 37059 37060 37864 37060 37061 37864 37865 37864 37061 37866 37865 37061 37868 37867 37062 37062 37856 37868 37072 37065 37064 37064 37071 37072 37082 37066 37065 37065 37072 37082 37066 37083 37088 37066 37082 37083 37067 37068 37860 37069 37068 37067 37074 37069 37067 37067 37073 37074 37067 37070 37073 37874 37860 37068 37068 37069 37874 37875 37874 37069 37069 37873 37875 37069 37074 37873 37076 37073 37070 37093 37076 37070 37880 37093 37070 37883 37072 37071 37889 37883 37071 37899 37889 37071 38683 37899 37071 37884 37082 37072 37072 37883 37884 37075 37074 37073 37076 37075 37073 37878 37873 37074 37074 37075 37878 38692 37878 37075 37075 37890 38692 37075 37085 37890 37075 37076 37085 37093 37085 37076 37882 37086 37077 37078 37081 37087 37899 37081 37078 38691 37899 37078 37078 38690 38691 39478 38690 37078 37078 37079 39478 37080 37079 37078 37087 37080 37078 39493 39478 37079 40227 39493 37079 40228 40227 37079 37079 40220 40228 37079 38688 40220 38689 38688 37079 37079 37080 38689 39473 38689 37080 37080 39471 39473 37080 37887 39471 37888 37887 37080 37080 37087 37888 37081 37899 38683 37084 37083 37082 37884 37084 37082 37085 37092 37890 37093 37092 37085 37086 37882 37885 37087 37885 37888 39458 38677 37089 37089 37090 39458 37091 37090 37089 38677 37091 37089 40206 39458 37090 37090 39453 40206 40932 39453 37090 40937 40932 37090 37090 40209 40937 37090 37091 40209 38677 37878 37091 40211 40209 37091 37091 37878 40211 37895 37890 37092 37092 37891 37895 37092 37093 37891 37093 37880 37891 37100 37099 37094 37095 37102 37905 37096 37894 37914 37096 37097 37894 37098 37097 37096 37103 37098 37096 37104 37103 37096 37914 37104 37096 37910 37909 37097 37097 37098 37910 39489 39457 37098 37098 37905 39489 37098 37103 37905 38715 37910 37098 39457 38715 37098 37099 37100 37106 37106 37105 37099 37101 37899 37912 37102 37902 37905 38730 38729 37107 37107 37921 38730 38743 38742 37109 37109 37915 38743 37916 37915 37109 38720 37916 37109 37920 37919 37111 38750 37113 37112 37112 37114 38750 37115 37114 37112 37929 37127 37113 37935 37929 37113 38750 37935 37113 37114 37115 37917 37114 37122 38750 37123 37122 37114 38731 37123 37114 37114 37917 38731 37922 37117 37116 38753 38749 37117 37117 38751 38753 38752 38751 37117 37120 37119 37118 37121 37120 37118 37925 37121 37118 37119 37120 37126 37120 37121 37126 37925 37924 37121 37122 39508 40256 37122 37123 39508 39532 38750 37122 40256 39532 37122 37123 38729 39508 38731 38729 37123 37124 37930 37931 37124 37926 37930 38759 37932 37125 37125 37930 38759 37931 37930 37125 37913 37901 37128 39499 37913 37128 39522 39499 37128 39523 39522 37128 37128 37937 39523 37128 37936 37937 37940 37936 37128 37128 37130 37940 37134 37130 37129 37135 37134 37129 37129 37131 37135 37130 37134 37940 37131 37132 37135 37941 37135 37132 37942 37941 37132 37941 37940 37134 37134 37135 37941 37136 37139 37944 37136 37137 37139 38764 37942 37136 38765 38764 37136 37136 37944 38765 37137 37138 37139 37944 37139 37138 37946 37944 37138 37138 37945 37946 37140 37947 37953 37140 37943 37947 37945 37143 37141 37948 37945 37141 38767 37948 37141 37141 37142 38767 37143 37142 37141 38775 38767 37142 37142 37949 38775 37142 37144 37949 37142 37143 37144 37144 37145 37949 37145 37153 37949 37145 37146 37153 38774 37153 37146 38787 38774 37146 37146 38786 38787 37146 38785 38786 37146 37157 38785 38768 37154 37147 37147 37148 38768 37148 37950 38768 37148 37151 37950 37151 37150 37149 37950 37151 37149 38771 37950 37149 38772 38771 37149 37149 37150 38772 38773 38772 37150 37150 37152 38773 38778 38773 37152 37152 37952 38778 37152 37951 37952 37152 37155 37951 38774 37949 37153 37167 37161 37154 38789 37167 37154 37154 38777 38789 37154 38768 38777 37155 37156 37951 37959 37951 37156 37157 37158 38785 38793 38785 37158 38794 38793 37158 37158 37967 38794 37158 37173 37967 37159 37160 37954 37160 37955 37958 37160 37164 37955 37963 37954 37160 38788 37963 37160 38797 38788 37160 37160 37958 38797 37961 37171 37161 37161 37167 37961 37171 37169 37161 37162 38784 38792 37162 37163 38784 38792 37172 37162 37163 38783 38784 37163 37953 38783 37963 37962 37165 37165 37954 37963 37964 37960 37166 37166 37168 37964 39564 37961 37167 37167 38789 39564 37168 37174 37964 37169 37170 37179 37171 37170 37169 37170 37178 37179 38803 37178 37170 37170 37171 38803 37171 37961 38798 37171 38798 38803 37173 37965 37967 37173 37177 37965 38802 37964 37174 38805 38802 37174 37174 37175 38805 38806 38805 37175 38807 38806 37175 37175 37969 38807 37175 37176 37969 37970 37969 37176 37973 37970 37176 37966 37965 37177 37177 37181 37966 37180 37179 37178 38808 37180 37178 38812 38808 37178 37178 38803 38812 37977 37976 37179 37179 37180 37977 37982 37977 37180 38821 37982 37180 37180 38812 38821 37180 38808 38812 38813 37966 37181 37181 37194 38813 37182 37183 37995 38814 37995 37183 37183 37979 38814 37184 37980 38827 37184 37192 37980 37193 37192 37184 37197 37193 37184 38827 37185 37184 38814 37979 37185 38815 38814 37185 38827 38815 37185 37190 37188 37186 37186 37187 37190 37981 37190 37187 37187 37971 37981 37187 37968 37971 37188 37189 37199 37190 37189 37188 37189 37190 37199 37981 37199 37190 38841 38002 37191 37191 38023 38841 37191 38022 38023 37191 37208 38022 37986 37980 37192 37192 37193 37986 37989 37986 37193 37193 37195 37989 37197 37195 37193 37195 37983 37989 37985 37983 37195 37195 37196 37985 38011 37985 37196 37202 37201 37200 37203 37202 37200 37201 37232 37233 38842 37232 37201 37201 37202 38842 37202 37991 38842 37202 37990 37991 37202 37203 37990 38006 38005 37204 38007 38006 37204 37204 37216 38007 37204 37205 37216 37206 37205 37204 38005 37206 37204 38028 37228 37206 38862 38028 37206 37206 38005 38862 37220 37208 37207 37207 37209 37220 37208 37218 38022 37220 37218 37208 38004 37220 37209 37209 38003 38004 39605 38015 37211 37211 38849 39605 37211 38019 38849 38859 38019 37211 37211 37214 38859 37211 37212 37214 37213 37212 37211 38015 37213 37211 37212 37213 37221 38018 37221 37213 39603 38018 37213 37213 38015 39603 37214 38019 38859 37214 37226 38019 37244 37226 37215 37215 37227 37244 37216 37217 38007 37217 37229 38007 37217 37223 37229 38023 38022 37218 38873 38023 37218 37218 38024 38873 37218 37219 38024 37220 37219 37218 38025 38024 37219 37219 38004 38025 37219 37220 38004 37222 37228 37238 37230 37229 37223 37231 37230 37223 37223 37224 37231 37235 37231 37224 37241 37235 37224 38029 37241 37224 37224 37233 38029 37225 37236 38012 38861 38019 37226 37226 37244 38861 37246 37245 37227 37227 37243 37244 37245 37243 37227 38027 37238 37228 38028 38027 37228 38868 38007 37229 37229 37230 38868 38875 38868 37230 37230 37239 38875 37230 37231 37239 37231 37235 37239 37232 39610 39611 37232 38842 39610 37234 37233 37232 39611 37234 37232 37233 38020 38029 38021 38020 37233 37233 37234 38021 39611 38021 37234 37240 37239 37235 37241 37240 37235 37236 37237 38037 38037 38012 37236 38041 37248 37238 37238 38027 38041 37239 38042 38875 37239 37240 38042 38051 38042 37240 37240 38043 38051 37240 37241 38043 37241 38029 38043 38906 37244 37243 37243 38050 38906 37243 37245 38050 38887 38861 37244 38888 38887 37244 40355 38888 37244 37244 38906 40355 37251 37250 37247 38041 37253 37248 37254 37252 37249 37252 37263 37270 37252 37254 37263 37253 38041 38059 37257 37256 37255 38912 37257 37255 37255 38911 38912 37256 37257 38068 38913 38068 37257 37257 38912 38913 38075 37268 37258 37258 38071 38075 38072 38071 37258 37258 37259 38072 37262 37261 37260 37266 37262 37260 38085 37266 37260 38093 38085 37260 37260 38083 38093 37260 37267 38083 37268 37267 37260 37277 37269 37262 37262 37266 37277 37264 37274 38074 37264 37273 37274 38085 37277 37266 37267 37268 38075 37267 38076 38083 38078 38076 37267 38079 38078 37267 37267 38075 38079 37269 37276 37279 37277 37276 37269 39662 37274 37272 39666 39662 37272 37272 38080 39666 37272 37273 38080 37274 37273 37272 37273 37282 38080 37274 38073 38074 39656 38073 37274 39666 39656 37274 37274 39662 39666 37276 38084 38086 37276 37277 38084 37276 38095 38102 37276 38086 38095 38085 38084 37277 37286 37280 37278 38087 38080 37282 37282 37283 38087 38917 38087 37283 39685 38917 37283 37283 39676 39685 37283 38096 39676 37283 37284 38096 37284 37290 38096 37288 38104 38937 37288 37299 38104 37289 37306 38934 37289 37292 37306 37291 37290 37289 38934 37291 37289 38103 38096 37290 39677 38103 37290 37290 38930 39677 37290 37291 38930 38934 38930 37291 37292 37305 37306 38129 38118 37293 37293 37337 38129 38943 37337 37293 37293 38935 38943 37293 37294 38935 37295 37294 37293 38936 38935 37294 38961 38944 37296 38963 38961 37296 39704 38963 37296 40453 39704 37296 37296 37297 40453 37298 37297 37296 38104 37298 37296 38937 38104 37296 38944 38937 37296 37297 39698 40453 37297 37298 39698 37298 38106 39698 37298 38104 38106 38109 38108 37300 37300 37301 38109 38945 38109 37301 38946 38945 37301 37301 37302 38946 38948 38946 37302 37302 38110 38948 37302 37303 38110 38119 38110 37303 37303 38111 38119 38120 38111 37304 38931 38120 37304 37304 38107 38931 37307 37306 37305 37306 37307 38116 38941 38934 37306 37306 38116 38941 38117 38116 37307 37310 37309 37308 38121 37310 37308 38122 38121 37308 38112 37312 37309 38114 38112 37309 37309 37310 38114 37310 38121 38955 38938 38114 37310 38956 38938 37310 38958 38956 37310 37310 38955 38958 38957 38123 37311 37311 37312 38957 38124 37313 37311 37311 38123 38124 37312 38956 38957 37312 38115 38956 37312 38112 38115 37322 37321 37315 37336 37322 37315 37337 37336 37315 38142 38138 37316 37316 38135 38142 37316 38127 38135 38137 38126 37317 38158 38146 37318 37318 37334 38158 37318 37319 37334 37320 37319 37318 38146 37320 37318 37319 37333 37334 37335 37333 37319 37319 37330 37335 37319 37320 37330 38140 37330 37320 38968 38140 37320 37320 38147 38968 37320 38146 38147 37321 37322 37323 38131 37323 37322 37322 37336 38131 38130 37341 37323 38131 38130 37323 37323 37341 37343 38164 38144 37324 37324 37344 38164 38144 37325 37324 38151 37326 37325 38152 38151 37325 39719 38152 37325 37325 38988 39719 37325 38144 38988 38955 38122 37326 39712 38955 37326 37326 38151 39712 38145 37358 37327 37327 37329 38145 37328 37345 38153 38153 37357 37328 37330 37333 37335 37330 37331 37333 37332 37331 37330 38140 37332 37330 37349 37333 37331 38965 37349 37331 38966 38965 37331 37331 37332 38966 39709 38966 37332 39710 39709 37332 37332 38139 39710 38140 38139 37332 37351 37334 37333 37333 37350 37351 37333 37349 37350 37334 38157 38158 37334 37365 38157 37334 37351 37365 37336 37337 38131 38134 38131 37337 38943 38134 37337 37338 37381 37389 38150 37356 37339 37339 38149 38150 37339 38143 38149 37339 37340 38143 37341 37340 37339 37356 37341 37339 37340 38141 38143 37340 38132 38141 37340 37341 38132 37341 38130 38132 37341 37342 37343 37354 37342 37341 37356 37354 37341 37342 37354 37355 38165 38164 37344 37344 37375 38165 37345 37368 38153 38979 37368 37345 37345 37347 38979 37345 37346 37347 38154 37347 37346 37346 37348 38154 37347 38154 38979 38976 37350 37349 37349 38965 38976 37363 37351 37350 38155 37363 37350 38980 38155 37350 37350 38976 38980 37351 37364 37365 37351 37363 37364 37352 37353 37371 37353 37355 37366 37353 37367 37371 37353 37366 37367 37356 37355 37354 37355 37356 37366 38150 37366 37356 38153 37359 37357 37357 37358 38145 38989 37369 37359 37359 38153 38989 37360 37363 38155 37364 37363 37360 37373 37364 37360 37360 37361 37373 37362 37361 37360 38155 37362 37360 38185 37373 37361 37361 37362 38185 39749 38185 37362 37362 39728 39749 37362 38980 39728 37362 38155 38980 37370 37365 37364 37379 37370 37364 37364 37373 37379 37365 38156 38157 37365 37374 38156 37365 37370 37374 38162 37367 37366 37366 38160 38162 37366 38150 38160 38162 37371 37367 37368 37369 38989 38189 38177 37368 39737 38189 37368 37368 38990 39737 37368 38979 38990 38989 38153 37368 37387 37374 37370 37370 37379 37387 38176 37380 37371 37371 38162 38176 37386 37379 37373 38185 37386 37373 38182 38156 37374 38186 38182 37374 37374 37387 38186 38166 38165 37375 37375 37376 38166 37376 37383 38167 38167 38166 37376 37377 37384 38184 38184 37378 37377 37378 38184 39001 37388 37387 37379 37392 37388 37379 37379 37386 37392 39003 37390 37380 37380 38176 39003 37390 37389 37381 38187 37383 37382 38202 38187 37382 37382 37391 38202 38174 38167 37383 38183 38174 37383 38193 38183 37383 37383 38187 38193 39001 38184 37384 39748 39001 37384 37384 37385 39748 37385 38179 39748 37400 37392 37386 38191 37400 37386 39005 38191 37386 37386 38185 39005 38192 38186 37387 37387 37388 38192 37388 37402 38192 37388 37401 37402 37388 37392 37401 37389 37394 37395 39017 37394 37389 37389 39007 39017 37389 37390 39007 37390 39003 39007 38203 38202 37391 37407 37401 37392 37392 37399 37407 37400 37399 37392 37393 38201 38208 37419 37396 37394 38210 37419 37394 37394 38209 38210 40521 38209 37394 37394 39017 40521 37396 37395 37394 37419 37409 37396 38195 37398 37397 38199 37410 37398 37398 38195 38199 37399 37406 37407 37399 37405 37406 37399 37404 37405 37399 37403 37404 37399 37400 37403 38191 37403 37400 37408 37402 37401 37401 37407 37408 38206 38192 37402 37402 37408 38206 38205 37404 37403 39762 38205 37403 37403 39018 39762 37403 38191 39018 37412 37405 37404 38204 37412 37404 38205 38204 37404 37405 37412 37413 37413 37406 37405 37415 37407 37406 38212 37415 37406 38224 38212 37406 37406 37414 38224 37406 37413 37414 37415 37408 37407 38207 38206 37408 38213 38207 37408 38214 38213 37408 37408 37424 38214 38212 37424 37408 37408 37415 38212 37419 37418 37409 38199 37411 37410 37421 37413 37412 37427 37421 37412 38223 37427 37412 39023 38223 37412 37412 38204 39023 37422 37414 37413 37414 37429 38224 37416 37433 38218 37417 37433 37434 38219 37433 37417 37418 37419 38210 38220 38217 37420 37421 37427 37428 37423 38224 38235 37423 38212 38224 37423 37424 38212 37425 37424 37423 38235 37425 37423 37424 37425 38214 39793 38214 37425 37425 38250 39793 37425 37439 38250 38235 37439 37425 37426 38208 39771 39028 39026 37426 39780 39028 37426 37426 39771 39780 38223 37428 37427 39039 38225 37428 37428 38223 39039 38235 38224 37429 37429 38226 38235 37429 37430 38226 37430 37436 38226 39029 37440 37431 37431 37432 39029 37432 39027 39029 37432 39026 39027 38219 38218 37433 39032 38227 37435 39796 39032 37435 40551 39796 37435 37436 37438 38226 39806 37451 37437 39810 39806 37437 37437 39030 39810 37437 38229 39030 38235 38226 37438 37438 37439 38235 37439 37458 37459 37439 38240 38250 38241 38240 37439 39048 38241 37439 39049 39048 37439 37439 37459 39049 39046 38233 37440 37440 39031 39046 37440 39029 39031 37450 37443 37442 37450 37444 37443 39044 38234 37444 39805 39044 37444 37444 39052 39805 37444 38255 39052 37444 37449 38255 37450 37449 37444 38231 37446 37445 38244 38231 37445 38245 38244 37445 37445 38233 38245 37446 38231 38232 39045 38243 37446 37446 38232 39045 40572 38255 37447 37447 39051 40572 37447 37448 39051 37449 37448 37447 38255 37449 37447 39812 39811 37448 37448 37463 39812 37448 37449 37463 39811 39051 37448 39053 37452 37451 39055 39053 37451 39806 39055 37451 37466 37454 37453 37453 37465 37466 37454 37466 38254 37460 37458 37454 37461 37460 37454 38254 37461 37454 37455 37456 37469 37456 37457 37469 38252 38247 37457 37460 37459 37458 37459 37460 39050 39050 39049 37459 37460 38253 39050 37460 37461 38253 37461 38242 38253 38254 37465 37461 37463 38257 39812 39060 38264 37464 37464 37471 39060 38254 37466 37465 37467 37469 38256 39829 39060 37471 37471 39058 39829 37471 37472 39058 37473 37472 37471 40585 39058 37472 37472 40579 40585 37472 39830 40579 37472 37473 39830 37473 39054 39830 39833 37479 37474 37474 38266 39833 37474 37475 38266 39831 38266 37475 37475 38267 39831 37477 37478 38268 37478 38265 38268 37478 38264 38265 39833 39064 37479 38272 37486 37480 37481 37482 37484 38273 37484 37482 39075 38274 37483 37483 38279 39075 37483 38273 38279 37483 37484 38273 37485 37486 38275 37486 38272 38275 38285 38281 37487 39074 38285 37487 37487 38276 39074 37488 37489 37492 37490 37489 37488 37493 37490 37488 37488 37492 37493 39070 38278 37489 39071 39070 37489 37489 37491 39071 37489 37490 37491 38286 37491 37490 37490 38280 38286 37490 37493 38280 37491 38286 39071 37494 37495 37497 37506 37497 37495 38282 37506 37495 39079 37529 37496 37496 39078 39079 37497 37506 37508 37500 37498 37497 37508 37500 37497 37500 37508 37510 37501 37502 38280 37503 37502 37501 38286 38280 37502 37502 38283 38286 38284 38283 37502 37502 37504 38284 37502 37503 37504 37520 37504 37503 39084 38284 37504 39097 39084 37504 37504 38301 39097 37504 38294 38301 37504 37520 38294 37505 37506 37507 38289 37506 37505 37505 37514 38289 38287 37507 37506 38288 38287 37506 37506 38282 38288 38289 37508 37506 37507 37512 37513 39080 37512 37507 37507 38287 39080 38290 37510 37508 37508 38289 38290 38297 38291 37509 37509 38296 38297 37509 38293 38296 37509 37510 38293 37510 38290 38293 39095 37531 37511 37511 37512 39095 37513 37512 37511 39099 39095 37512 39104 39099 37512 39846 39104 37512 37512 39085 39846 37512 39080 39085 38290 38289 37514 37514 37515 38290 38292 38290 37515 38295 38292 37515 38302 38295 37515 37519 37517 37516 37516 37518 37519 38297 37518 37516 37516 38291 38297 38315 38307 37518 37518 38297 38315 38307 37526 37518 38301 38294 37520 37520 37525 38301 37521 37522 37524 37523 37522 37521 37527 37523 37521 37528 37527 37521 39086 37524 37522 39096 39086 37522 37522 37523 39096 37523 37527 39096 39097 38301 37525 37525 38304 39097 37525 37530 38304 37527 37535 37536 37527 37528 37535 39105 39096 37527 37527 37536 39105 37528 37534 37535 38299 38298 37529 38300 38299 37529 39091 38300 37529 37529 39089 39091 37529 39079 39089 37530 38298 38303 39102 38304 37530 37530 38303 39102 39103 37532 37531 37531 39099 39103 37531 39095 39099 39103 39098 37532 37536 37535 37534 37538 37536 37534 38316 37538 37534 37534 37544 38316 39106 39105 37536 37536 37538 39106 39847 39106 37538 39861 39847 37538 37538 39108 39861 39109 39108 37538 37538 38316 39109 38316 37544 37539 38324 38316 37539 37539 37540 38324 38326 38324 37540 37540 37554 38326 37540 37551 37554 37541 37546 38308 39118 38317 37545 39865 39118 37545 38313 38308 37546 38314 38313 37546 37546 38309 38314 37546 37547 38309 38311 38309 37547 37557 37549 37548 39111 38320 37549 37549 38328 39111 37549 37557 38328 37550 38318 38325 37555 37554 37551 37551 37552 37555 37552 38331 38334 39883 37555 37552 37552 39138 39883 37552 38334 39138 37554 38323 38326 37554 37555 38323 39122 38323 37555 39123 39122 37555 41310 39123 37555 37555 39893 41310 37555 39883 39893 37556 37567 38335 37556 37563 37567 39119 38328 37557 37557 38329 39119 38350 38342 37558 37558 38340 38350 38341 38340 37558 38333 38331 37559 37578 37566 37560 38344 38343 37561 39117 38344 37561 37568 37567 37563 37577 37565 37564 38342 37577 37564 38348 37576 37565 38350 38348 37565 37565 37577 38350 38353 38335 37567 37567 38346 38353 37567 37568 38346 37568 37594 38346 37568 37592 37594 37571 37570 37569 37572 37571 37569 37573 37572 37569 37569 37570 37573 37603 37587 37570 37570 37571 37603 38338 37573 37570 38357 38338 37570 37570 38339 38357 37570 38337 38339 37571 37582 37603 37571 37581 37582 38338 37583 37573 37574 37589 37590 37576 38348 39150 39150 38351 37576 37577 38342 38350 38345 37579 37578 37578 38343 38345 37579 39130 39140 37579 38345 39130 37596 37586 37582 37582 37587 37603 37582 37586 37587 37583 39134 39149 39135 39134 37583 39136 39135 37583 37583 38338 39136 38365 37588 37584 39148 38365 37584 39149 39148 37584 38364 37597 37588 38365 38364 37588 38368 37590 37589 38369 38368 37589 39921 38369 37589 37589 38366 39921 39154 37591 37590 37590 38360 39154 37590 38359 38360 38368 38359 37590 39154 39147 37591 37592 37593 37594 37599 37595 37593 37595 37594 37593 38347 38346 37594 37594 37595 38347 39153 38347 37595 37595 38361 39153 38363 38361 37595 37595 37599 38363 37598 39152 39155 37598 38367 39152 39157 39156 37598 37598 39155 39157 37599 37600 38363 37600 37601 38363 37602 37601 37600 37601 37614 38363 37601 37612 37614 37601 37602 37612 37602 37609 37612 37602 37607 37609 37604 37605 37613 38364 37613 37605 37608 37607 37606 38370 37608 37606 37606 37610 38370 37607 37608 37609 37611 37609 37608 38370 37611 37608 38381 37612 37609 37609 38374 38381 37609 37611 38374 39156 38370 37610 39162 38374 37611 37611 39160 39162 37611 38370 39160 38381 37614 37612 39165 38377 37613 39166 39165 37613 37613 38364 39166 38375 38363 37614 38381 38375 37614 37616 38377 38382 39936 39182 37617 39939 39936 37617 37617 39189 39939 37617 38384 39189 37618 38383 38384 38398 37622 37619 37619 37620 38398 37622 38398 38399 38402 37623 37622 37622 38399 38402 38402 37625 37623 37633 37630 37624 37624 37625 37633 38403 37633 37625 37625 38402 38403 37626 37628 37631 37629 37628 37627 38397 37629 37627 39958 38397 37627 37627 39957 39958 37627 39950 39957 37627 37628 39950 37628 37629 37632 37628 38394 39950 37632 37631 37628 39207 37632 37629 39221 39207 37629 37629 38396 39221 38397 38396 37629 37641 37634 37630 37630 37633 37641 37631 37632 37635 39207 38416 37632 37645 37635 37632 37655 37645 37632 38416 37655 37632 38405 37641 37633 37633 38403 38405 37649 37642 37634 37634 37641 37649 37636 37637 37647 37637 37646 37647 37667 37646 37637 37637 37656 37667 38400 38398 37638 38401 38400 37639 39208 38401 37639 37639 38410 39208 37639 37640 38410 39218 38410 37640 37640 38418 39218 37640 37648 38418 38409 37649 37641 37641 38405 38409 37642 37649 37657 37657 37650 37642 38415 38408 37643 37643 37653 38415 37643 37652 37653 37643 37651 37652 37655 37654 37644 37648 37662 38418 38406 37657 37649 38409 38406 37649 37660 37651 37650 37664 37660 37650 37650 37663 37664 37650 37657 37663 37660 37652 37651 38412 37653 37652 37652 37664 38412 37652 37660 37664 39205 38415 37653 39206 39205 37653 37653 38413 39206 37653 38412 38413 38421 37666 37654 38422 38421 37654 37654 37655 38422 37655 38417 38422 37655 38416 38417 38406 37659 37657 38419 37663 37657 39223 38419 37657 37657 39222 39223 37657 37658 39222 37659 37658 37657 40746 39222 37658 37658 40737 40746 37658 37659 40737 37659 38407 39972 37659 38406 38407 37659 39972 40737 38423 38418 37662 38414 37664 37663 38424 38414 37663 37663 38419 38424 38414 38412 37664 37665 37666 38420 39225 38420 37666 37666 38421 39225 40003 37670 37668 37668 39248 40003 37668 39246 39248 37668 38437 39246 37668 37669 38437 37669 38436 38437 38439 38438 37670 40003 38439 37670 39236 38428 37671 37671 38433 39236 37672 38434 39243 37672 38430 38434 37672 38429 38430 39235 38423 37673 39245 39235 37673 37673 38444 39245 37673 37674 38444 38450 38444 37674 37674 37677 38450 38449 37678 37675 37677 37685 38450 37686 37679 37678 38449 37686 37678 37679 37692 37695 37679 37686 37692 37688 37683 37682 37691 37688 37682 37682 37690 37691 37682 37687 37690 37689 37684 37683 37683 37688 37689 38453 37685 37684 38456 38453 37684 37684 37689 38456 38452 38450 37685 39264 38452 37685 37685 38453 39264 37686 39252 39255 37686 38449 39252 39255 37692 37686 37693 37690 37687 37694 37689 37688 37688 37691 37694 37689 37694 38456 37694 37691 37690 38459 37694 37690 37690 37693 38459 39272 38457 37692 37692 39268 39272 37692 39263 39268 37692 39261 39263 37692 39255 39261 38457 37695 37692 38462 38456 37694 39278 38462 37694 39279 39278 37694 37694 38461 39279 37694 38460 38461 37694 38459 38460 38466 37697 37696 37696 38458 38466 38470 37699 37697 37697 38466 38470 38465 38460 37698 39276 38465 37698 37698 38468 39276 37700 37704 37705 37701 37702 38473 38473 37708 37701 39282 38473 37702 40801 39282 37702 37702 40800 40801 37703 38474 38475 37706 37705 37704 39277 38469 37705 37705 38471 39277 38472 38471 37705 40029 38472 37705 37705 37706 40029 37706 38479 40029 37706 37707 38479 37707 38478 38479 37709 37710 37711 38480 37710 37709 37710 39288 39292 37710 38480 39288 39292 37711 37710 39292 39291 37711 38494 37721 37712 37712 37714 38494 37712 37713 37714 39294 37714 37713 37713 39293 39294 39304 38494 37714 37714 39296 39304 37714 39294 39296 38497 37724 37720 38499 38497 37720 37720 37721 38499 37721 38494 38499 37722 37728 37734 37722 37726 37728 39313 38510 37723 39314 39313 37723 37727 37726 37725 38511 37727 37725 37725 37732 38511 37726 37727 37728 39317 37728 37727 37727 39316 39317 37727 38511 39316 39318 37734 37728 37728 39317 39318 38507 37736 37730 38508 38507 37730 38509 38508 37730 39323 37732 37731 37731 38520 39323 37731 37738 38520 39316 38511 37732 39325 39316 37732 37732 39324 39325 37732 39323 39324 37735 37734 37733 39329 37735 37733 39330 39329 37733 37733 39326 39330 37733 39318 39326 37733 37734 39318 37743 37742 37735 39329 37743 37735 37740 37739 37736 38523 37740 37736 37736 38507 38523 39328 38520 37737 37737 38524 39328 37737 37741 38524 38520 37738 37737 38531 37747 37739 39339 38531 37739 40065 39339 37739 37739 37740 40065 37740 40059 40065 37740 38523 40059 37742 37743 39344 39344 38527 37742 37743 40064 40067 37743 39330 40064 37743 39329 39330 40067 39344 37743 38528 37749 37746 38532 38528 37746 39345 38532 37746 37746 38531 39345 37746 37747 38531 39342 38529 37750 39343 39342 37750 39344 39343 37750 37750 37751 39344 37751 38527 39344 38542 37762 37754 37760 37759 37755 37755 37756 37760 37771 37760 37756 37756 37770 37771 37756 37761 37770 37763 37761 37756 38544 38540 37757 37759 37777 38552 37759 37760 37777 37759 38552 38553 37760 37771 37777 38545 37765 37762 37762 38542 38545 37768 37767 37766 39358 37775 37767 37767 38548 39358 37767 37768 38548 38554 38548 37768 37768 38547 38554 39355 38551 37769 37769 38553 39355 37774 37773 37772 38561 37774 37772 37772 37779 38561 38561 37797 37774 39358 37776 37775 38568 37787 37776 40848 38568 37776 40850 40848 37776 37776 40103 40850 37776 39358 40103 37777 37783 37784 37777 37784 38552 38560 37785 37778 37779 37780 38567 38563 38561 37779 38567 38563 37779 37780 37781 38567 37781 37786 38567 37781 37782 37786 37787 37786 37782 38564 38552 37784 38566 37799 37785 37785 38560 38566 40846 40113 37786 40847 40846 37786 40849 40847 37786 37786 40848 40849 37786 38568 40848 37786 37787 38568 40113 38567 37786 38575 37789 37788 37788 37798 38575 39368 37791 37789 37789 38575 39368 37791 37790 37789 37790 37791 38565 39368 39363 37791 38570 38565 37791 39363 38570 37791 37794 37793 37792 38569 37794 37792 40096 38569 37792 40114 40096 37792 37792 37793 40114 37793 37794 38576 37793 39375 40114 37793 38576 39375 37794 38575 38576 39368 38575 37794 37794 38569 39368 39364 37796 37795 40853 39364 37795 37795 38579 40853 37795 37801 38579 37795 37800 37801 39364 39357 37796 37797 37802 37803 39367 37802 37797 37797 39366 39367 37797 38561 39366 38576 38575 37798 37798 38574 38576 37798 38573 38574 39371 38578 37799 37799 39369 39371 39370 39369 37799 37799 38566 39370 38589 38579 37801 37804 37803 37802 38577 37804 37802 39367 38577 37802 39377 37805 37804 37804 38577 39377 37805 39377 39381 37808 37807 37806 37822 37808 37806 39388 38594 37807 37807 37808 39388 37808 37823 39388 37808 37822 37823 37813 37811 37809 38582 37810 37809 39383 38582 37809 37809 38583 39383 37809 37811 38583 39399 38629 37810 37810 38582 39399 37811 37812 38583 37813 37812 37811 38587 38583 37812 37812 37814 38587 39393 38609 37815 40138 39393 37815 37815 39381 40138 37815 38609 38610 37816 37821 38593 38572 38571 37816 38593 38572 37816 39396 37818 37817 37817 39391 39396 37817 38595 39391 37817 38594 38595 37818 37833 37834 37840 37833 37818 39409 37840 37818 39410 39409 37818 37818 39396 39410 38604 38601 37819 37819 38603 38604 39379 38603 37819 38592 38588 37820 38612 38593 37821 37823 38596 39388 38597 38587 37824 38598 38597 37824 38601 38598 37824 38625 37827 37825 37825 38608 38625 37825 38607 38608 37825 37826 38607 38610 38607 37826 38624 37835 37827 38625 38624 37827 37828 37838 37842 37828 37829 37838 37830 37829 37828 37832 37831 37828 37842 37832 37828 37829 37837 37838 37829 37836 37837 38651 37836 37829 37829 37849 38651 37829 37830 37849 37830 37839 37849 37831 37832 38611 38618 38611 37832 39407 38618 37832 37832 38627 39407 37832 37842 38627 38623 37852 37835 38624 38623 37835 38649 38637 37836 38650 38649 37836 38656 38650 37836 37836 38651 38656 37838 37837 37836 38637 37838 37836 38636 38626 37838 38637 38636 37838 38626 37842 37838 37850 37849 37839 38638 37850 37839 39409 38638 37840 38661 37846 37841 37841 38640 38661 37844 37843 37841 37846 37844 37841 37842 38626 38627 37843 38613 38620 37843 37844 38613 39405 38613 37844 39417 39405 37844 37844 37847 39417 37844 37846 37847 39397 37847 37845 39410 39397 37845 39437 39410 37845 37845 38661 39437 37845 37846 38661 37847 37846 37845 37847 39392 39417 40160 39392 37847 40166 40160 37847 37847 39397 40166 37848 38628 38643 38652 38651 37849 37849 37850 38652 38657 38652 37850 37850 38639 38657 37850 38638 38639 37854 37853 37851 38643 37854 37851 37852 38623 38648 37870 37856 37853 37853 37855 37870 37853 37854 37855 37857 37855 37854 38654 37857 37854 39426 38654 37854 37854 38643 39426 37855 37857 37870 37877 37868 37856 37856 37869 37877 37870 37869 37856 38675 37870 37857 37857 37871 38675 37872 37871 37857 38676 37872 37857 37857 38655 38676 37857 38653 38655 38654 38653 37857 37881 37859 37858 38667 38622 37859 37859 38645 38667 38646 38645 37859 37859 37881 38646 38658 37861 37860 37860 37874 38658 37861 38658 38659 37862 39440 39442 37862 39442 39446 39463 38664 37863 37863 38698 39463 40190 38698 37863 37863 39447 40190 37863 37864 39447 37864 37865 39447 39448 39447 37865 37865 37866 39448 37866 38669 39448 37866 37867 38669 37867 38665 38669 37867 37877 38665 37867 37868 37877 38665 37877 37869 38670 38665 37869 37869 37870 38670 38674 38670 37870 38675 38674 37870 38682 38681 37871 37871 37872 38682 38681 38675 37871 40208 38682 37872 37872 40196 40208 37872 38676 40196 38677 37875 37873 37873 37878 38677 39436 38658 37874 40188 39436 37874 40912 40188 37874 37874 40185 40912 37874 37875 40185 37875 39458 40185 37875 38677 39458 39446 38684 37876 37878 39468 40211 37878 38692 39468 37898 37892 37879 38684 37898 37879 37893 37880 37879 37879 37892 37893 37893 37891 37880 38701 38646 37881 37881 38700 38701 37886 37885 37882 38687 37886 37882 37882 38668 38687 37889 37884 37883 37885 37887 37888 37885 37886 37887 39471 37887 37886 39472 39471 37886 37886 38687 39472 37890 37895 38692 37897 37895 37891 37891 37893 37897 37897 37893 37892 37898 37897 37892 39474 38692 37895 39479 39474 37895 37895 37896 39479 37897 37896 37895 37896 38725 39479 39503 38725 37896 37896 38741 39503 39504 38741 37896 40230 39504 37896 40231 40230 37896 37896 39496 40231 37896 37897 39496 40232 39496 37897 37897 39497 40232 37897 38702 39497 37897 37898 38702 37898 38686 38702 37898 38685 38686 37898 38684 38685 38691 37912 37899 37908 37902 37900 37913 37908 37900 37900 37901 37913 37908 37906 37902 37902 37903 37905 37904 37903 37902 37906 37904 37902 39488 37905 37903 39492 39488 37903 40240 39492 37903 37903 37904 40240 37904 40225 40240 37904 37906 40225 37905 39488 39489 37906 37907 40225 37908 37907 37906 37907 40224 40225 37907 39498 40224 37907 37913 39498 37907 37908 37913 39456 38700 37909 39457 39456 37909 37909 38715 39457 37909 37910 38715 37911 37916 38720 39493 37916 37911 37911 39478 39493 37911 38690 39478 37911 37912 38690 38691 38690 37912 39499 39498 37913 37915 39510 40241 37915 37916 39510 40241 38743 37915 37916 39493 39510 38734 38732 37918 39506 38734 37918 37918 38742 39506 39509 38730 37919 37919 38747 39509 37919 37920 38747 39520 38747 37920 37920 37923 39520 40252 39521 37923 37923 39519 40252 37923 37924 39519 39521 39520 37923 37924 39518 39519 37924 37925 39518 38754 37930 37926 38755 38754 37926 39526 38755 37926 37926 37927 39526 37927 39525 39526 37928 37932 37933 37929 37934 37939 37935 37934 37929 37930 38758 38759 37930 38754 38758 38759 37933 37932 37933 38760 39529 37933 38759 38760 37934 37938 37943 37934 37935 37938 39531 37938 37935 37935 39530 39531 37935 38750 39530 39537 37937 37936 37936 38763 39537 37936 37940 38763 39537 39534 37937 39528 39523 37937 39535 39528 37937 37937 39534 39535 38766 37943 37938 39531 38766 37938 37940 37941 38763 39538 38763 37941 37941 38764 39538 37941 37942 38764 38766 37947 37943 37944 37946 38765 37948 37946 37945 39541 38765 37946 37946 38767 39541 37946 37948 38767 38783 37953 37947 37947 38766 38783 37949 38774 38775 38769 38768 37950 38770 38769 37950 38771 38770 37950 38782 37952 37951 37951 37959 38782 39547 38778 37952 39565 39547 37952 37952 38782 39565 37960 37957 37955 37955 37957 37958 38804 38801 37956 37956 38802 38804 37956 37957 38802 37958 37957 37956 38801 37958 37956 37957 37960 37964 37957 37964 38802 40299 38797 37958 37958 38796 40299 40300 38796 37958 37958 39571 40300 37958 38800 39571 38801 38800 37958 38790 38782 37959 39564 38798 37961 38788 37968 37962 37962 37963 38788 38799 37967 37965 38809 38799 37965 37965 37966 38809 38813 38809 37966 38799 38794 37967 37972 37971 37968 38810 37972 37968 37968 38788 38810 37969 37970 38807 38811 38807 37970 37970 37973 38811 37990 37981 37971 37991 37990 37971 38816 37991 37971 37971 37987 38816 37971 37972 37987 38810 37987 37972 37973 37974 38811 39575 38811 37974 37974 38818 39575 38820 38817 37975 37975 37982 38820 37975 37976 37982 37976 37977 37982 38865 38813 37978 37978 37988 38865 38828 38827 37980 40311 38828 37980 37980 38829 40311 37980 37986 38829 37982 37996 38820 37982 37994 37996 38822 37994 37982 37982 38821 38822 38831 37989 37983 39591 38831 37983 39600 39591 37983 37983 38857 39600 37983 37984 38857 37985 37984 37983 37984 38856 38857 37984 38011 38856 37984 37985 38011 37986 37989 38829 41042 38816 37987 37987 39579 41042 37987 38795 39579 38810 38795 37987 37988 38002 38865 38830 38829 37989 38831 38830 37989 39592 38842 37991 37991 38816 39592 37999 37996 37992 38001 37999 37992 37992 37993 38001 37994 37993 37992 37996 37994 37992 38835 38001 37993 37993 38834 38835 37993 38822 38834 37993 37994 38822 38848 38003 37995 37995 38847 38848 37995 38836 38847 37995 38814 38836 37996 37999 38009 37996 37997 38820 37998 37997 37996 38009 37998 37996 37997 38819 38820 38833 38819 37997 37997 37998 38833 38839 38832 37998 38852 38839 37998 37998 38843 38852 37998 38009 38843 37998 38832 38833 37999 38008 38009 37999 38000 38008 38001 38000 37999 38017 38008 38000 39614 38017 38000 38000 38001 39614 38001 39584 39614 38001 38835 39584 41063 38865 38002 38002 38841 41063 38848 38004 38003 38848 38025 38004 39607 38862 38005 39609 39607 38005 38005 38006 39609 39618 39609 38006 38006 38007 39618 38007 38868 39618 38010 38009 38008 38016 38010 38008 38017 38016 38008 38009 38010 38843 38010 38016 38843 38011 38040 38856 38011 38012 38040 38012 38039 38040 38012 38037 38039 38013 39600 39602 39601 39600 38013 38013 38014 39601 38015 38014 38013 39602 38015 38013 41054 39601 38014 41055 41054 38014 41656 41055 38014 38014 41056 41656 38014 38015 41056 38015 39602 39603 38015 39605 41056 38851 38843 38016 38864 38851 38016 38016 38844 38864 38016 38017 38844 38846 38844 38017 39626 38846 38017 40327 39626 38017 38017 39614 40327 38018 38038 38874 39616 38038 38018 38018 39603 39616 38874 38026 38018 38860 38849 38019 39617 38860 38019 38019 38861 39617 38869 38030 38020 39623 38869 38020 38020 39622 39623 38020 38021 39622 38030 38029 38020 40333 39622 38021 38021 39611 40333 39630 38841 38023 38023 38873 39630 38024 38866 38873 38024 38025 38866 38025 38847 39631 38848 38847 38025 38867 38866 38025 39615 38867 38025 39627 39615 38025 39631 39627 38025 38874 38039 38026 38899 38041 38027 39646 38899 38027 38027 39639 39646 38027 38889 39639 38027 38028 38889 40356 38889 38028 38028 39638 40356 38028 38862 39638 38029 38030 38043 38030 38034 38045 38869 38034 38030 38044 38043 38030 38045 38044 38030 38048 38036 38031 38049 38048 38031 38031 38032 38049 38033 38032 38031 38036 38033 38031 38877 38049 38032 38032 38876 38877 38032 38033 38876 38879 38876 38033 39629 38879 38033 38033 38046 39629 38033 38036 38046 38869 38046 38034 38034 38035 38045 38036 38035 38034 38046 38036 38034 38053 38045 38035 38035 38047 38053 38048 38047 38035 38035 38036 38048 38040 38039 38038 39604 38040 38038 39616 39604 38038 38038 38039 38874 38858 38856 38040 39604 38858 38040 38041 38057 38059 38058 38057 38041 38899 38058 38041 39641 38875 38042 38042 38900 39641 38042 38052 38900 38042 38051 38052 38052 38051 38043 38043 38044 38052 38900 38052 38044 38044 38053 38900 38044 38045 38053 38046 38869 39628 38046 39628 39629 38047 38048 38053 39647 38053 38048 38048 38901 39647 38048 38891 38901 38048 38049 38891 38049 38878 38891 38049 38877 38878 38050 38055 38906 39647 38900 38053 38054 38066 38067 38056 38055 38054 38067 38056 38054 38055 38898 38906 38055 38056 38898 40360 38898 38056 41078 40360 38056 38056 40367 41078 38056 39654 40367 38056 38067 39654 38057 38058 40371 38060 38059 38057 40371 38060 38057 38058 38899 39646 38058 39646 40371 38059 38060 38911 39657 38911 38060 40384 39657 38060 41090 40384 38060 38060 40371 41090 38061 38908 38909 38061 38074 38908 38909 38062 38061 38910 38065 38062 38062 38909 38910 39654 38067 38063 40374 39654 38063 38063 38064 40374 38065 38064 38063 41100 40374 38064 38064 40383 41100 38064 38065 40383 38065 40382 40383 38065 38910 40382 38913 38070 38068 39663 38915 38069 38069 39661 39663 38069 38070 39661 38070 38913 39661 38079 38075 38071 38071 38072 38079 38081 38079 38072 38082 38081 38072 38916 38082 38072 38908 38074 38073 38909 38908 38073 39656 38909 38073 38076 38077 38092 38078 38077 38076 38094 38083 38076 38101 38094 38076 38076 38092 38101 38077 38078 38081 38077 38081 38092 38078 38079 38081 38080 38917 39666 38080 38087 38917 38081 38090 38092 38081 38082 38090 38100 38090 38082 38082 38097 38100 38918 38097 38082 38082 38088 38918 38089 38088 38082 38916 38089 38082 38094 38093 38083 38084 38085 38086 38095 38086 38085 38085 38093 38095 38919 38918 38088 38088 38914 38919 38088 38089 38914 38916 38914 38089 38090 38091 38092 38098 38091 38090 38100 38098 38090 39691 38923 38091 38091 39690 39691 38091 38098 39690 38923 38092 38091 38923 38101 38092 38093 38094 38922 38926 38095 38093 38093 38920 38926 38921 38920 38093 38922 38921 38093 38094 38101 38922 38926 38102 38095 38096 38103 39676 38097 38098 38100 38099 38098 38097 38924 38099 38097 38097 38918 38924 38098 39689 39690 38098 38925 39689 38098 38099 38925 38099 38924 38925 39684 38922 38101 39692 39684 38101 38101 38923 39692 39677 39676 38103 38108 38106 38104 38929 38107 38105 38106 38945 39698 38106 38109 38945 38106 38108 38109 38107 38929 38931 38110 38119 38948 38120 38119 38111 38112 38113 38115 38114 38113 38112 38938 38115 38113 38113 38114 38938 38115 38938 38956 38116 38117 38940 38116 38940 38941 39702 38940 38117 39703 39702 38117 38117 38126 39703 38119 38120 38948 38952 38948 38120 38120 38931 38952 38121 38122 38955 39699 38962 38123 38123 38957 39699 38125 38124 38123 38962 38125 38123 38136 38128 38124 38124 38125 38136 38975 38136 38125 40461 38975 38125 40478 40461 38125 38125 38962 40478 38126 38964 39703 38126 38137 38964 38136 38135 38127 38127 38128 38136 38134 38132 38130 38130 38131 38134 38961 38141 38132 38132 38133 38961 38134 38133 38132 38943 38936 38133 38133 38134 38943 38133 38944 38961 38133 38936 38944 38974 38142 38135 38135 38136 38974 38975 38974 38136 38137 38138 38964 38138 38142 38964 39714 39710 38139 38139 38967 39714 38139 38140 38967 38968 38967 38140 38963 38143 38141 38141 38961 38963 38974 38964 38142 38143 38963 38973 38973 38149 38143 38144 38168 38988 38144 38164 38168 38148 38147 38146 38158 38148 38146 38969 38968 38147 38982 38969 38147 38147 38148 38982 38993 38982 38148 38148 38158 38993 38159 38150 38149 38977 38159 38149 38149 38973 38977 38150 38159 38160 38151 38954 39712 38151 38152 38954 38152 38953 38954 39719 38953 38152 38991 38979 38154 38992 38991 38154 38158 38157 38156 38175 38158 38156 39002 38175 38156 38156 38182 39002 38158 38981 38993 39743 38981 38158 38158 38175 39743 38161 38160 38159 38978 38161 38159 38159 38977 38978 38163 38162 38160 38160 38161 38163 38986 38163 38161 38161 38978 38986 38162 38163 38176 38997 38176 38163 38163 38986 38997 38164 38165 38168 38165 38166 38168 38169 38168 38166 38171 38169 38166 38166 38167 38171 38174 38171 38167 38168 38169 38988 38169 38172 38988 38169 38171 38172 39736 39735 38170 38170 38173 39736 38170 38171 38173 38172 38171 38170 39735 38172 38170 38174 38173 38171 39719 38988 38172 40487 39719 38172 41774 40487 38172 38172 40491 41774 38172 40490 40491 40500 40490 38172 38172 39735 40500 38173 39000 39736 38173 38174 39000 38174 38194 39000 38174 38183 38194 40504 39743 38175 38175 39750 40504 38175 39002 39750 39751 39003 38176 38176 39746 39751 38176 39734 39746 38176 38997 39734 38177 38188 38190 38189 38188 38177 38178 38179 38188 38180 38179 38178 39738 38180 38178 38178 38189 39738 38178 38188 38189 38179 38180 39748 38180 39741 39748 39747 39741 38180 38180 39738 39747 39006 39002 38182 38182 38186 39006 39760 38194 38183 38183 39015 39760 38183 38193 39015 39755 39005 38185 40509 39755 38185 38185 39749 40509 38186 38192 39006 39012 38193 38187 38187 39011 39012 39013 39011 38187 38187 38202 39013 38189 39737 39738 39016 38195 38190 38191 39005 39018 39008 39006 38192 38192 38206 39008 38193 39012 39015 39760 39000 38194 39016 38199 38195 38198 38197 38196 38208 38198 38196 39771 38208 38196 38196 38197 39771 38197 38198 39019 40534 39771 38197 41216 40534 38197 38197 40527 41216 38197 39019 40527 38208 38200 38198 38208 38201 38200 39014 39013 38202 38202 38203 39014 39022 39014 38203 39775 39023 38204 39776 39775 38204 38204 38205 39776 39777 39776 38205 38205 39762 39777 39009 39008 38206 38206 38207 39009 40526 39009 38207 38207 39783 40526 38207 38213 39783 38211 38210 38209 39020 38211 38209 39768 39020 38209 40521 39768 38209 38210 38211 38219 38211 38218 38219 39024 38218 38211 38211 39020 39024 40540 39783 38213 38213 39792 40540 39793 39792 38213 38213 38214 39793 39021 39019 38215 38221 38220 38216 39025 38222 38217 38217 38220 39025 39024 39021 38218 38220 38221 39025 39791 39025 38221 38221 39787 39791 38221 38227 39787 39778 39022 38222 39779 39778 38222 39781 39779 38222 38222 39025 39781 38223 39023 39782 39795 39039 38223 38223 39782 39795 39039 39038 38225 39030 38228 38225 39038 39030 38225 38227 39032 39787 39030 38229 38228 38230 38244 39040 38230 38231 38244 38232 38231 38230 39040 38232 38230 38232 38240 39045 40547 38240 38232 38232 39040 40547 39046 38245 38233 39037 38239 38234 38234 39036 39037 39804 39036 38234 38234 39044 39804 41236 40565 38236 41245 41236 38236 41248 41245 38236 38236 38237 41248 38237 40566 41248 38237 39801 40566 39808 39801 38237 38237 39047 39808 39033 38249 38238 39035 39033 38238 38238 38239 39035 39036 39035 38239 39037 39036 38239 39793 38250 38240 40549 39793 38240 38240 40547 40549 38240 38241 39045 39048 39045 38241 38242 38243 38253 39049 38253 38243 38243 39045 39049 39798 39040 38244 38244 38245 39798 39799 39798 38245 38245 39046 39799 38246 38247 38251 38247 38248 38251 38249 38248 38247 39047 38251 38248 39808 39047 38248 38248 39807 39808 38248 39043 39807 38248 38249 39043 38249 39033 39043 38253 39049 39050 39805 39052 38255 39809 39805 38255 40559 39809 38255 40572 40559 38255 38257 38258 38262 38257 38261 39812 38262 38261 38257 39057 38262 38258 38258 38263 39057 41255 40576 38259 38259 38260 41255 38261 38260 38259 40576 38261 38259 41872 41255 38260 38260 40593 41872 38260 39823 40593 38260 38262 39823 38260 38261 38262 40576 39812 38261 38262 39057 39059 38262 39059 39823 38263 39062 39063 38263 38269 39062 39059 39057 38263 39063 39059 38263 39060 38265 38264 38271 38268 38265 38265 38270 38271 39060 38270 38265 38266 39066 39833 39835 39066 38266 38266 39831 39835 39832 39831 38267 38267 38271 39832 38267 38268 38271 39061 38271 38270 39829 39061 38270 38270 39060 39829 38271 39069 39832 38271 39061 39069 38272 38274 39076 38274 39075 39076 38276 39072 39074 39073 39072 38276 39838 39073 38276 38276 38277 39838 38278 38277 38276 38277 39837 39838 38277 39070 39837 38277 38278 39070 39082 39075 38279 38285 38282 38281 38282 38285 38288 39839 38286 38283 39844 39839 38283 38283 38284 39844 38284 39084 39844 39074 38288 38285 39840 39071 38286 38286 39839 39840 38287 39074 39080 38287 38288 39074 38290 38292 38293 38296 38293 38292 38292 38295 38296 38312 38296 38295 38295 38305 38312 38295 38302 38305 38312 38297 38296 38297 38306 38315 38310 38306 38297 38314 38310 38297 38297 38312 38314 38298 38299 38303 38299 38300 38303 38300 39091 39101 39100 38303 38300 39101 39100 38300 39848 39102 38303 39852 39848 38303 38303 39107 39852 38303 39100 39107 39848 39097 38304 38304 39102 39848 38305 38308 38312 38306 38309 38311 38310 38309 38306 38306 38307 38315 38313 38312 38308 38309 38310 38314 38312 38313 38314 38316 38326 39109 38316 38324 38326 39118 39117 38317 39116 38325 38318 38318 38319 39116 38319 39112 39116 38319 39110 39112 39862 39110 38320 38320 39111 39862 39121 38323 38321 38321 39120 39121 40628 39120 38321 40633 40628 38321 38321 38322 40633 38323 38322 38321 40635 40633 38322 38322 38323 40635 39121 38326 38323 38323 39122 40635 38337 38330 38325 38339 38337 38325 39126 38339 38325 38325 39115 39126 39116 39115 38325 39121 39109 38326 38336 38329 38327 38327 38335 38336 39882 39111 38328 38328 39119 39882 39133 39119 38329 38329 39132 39133 38329 38336 39132 38331 38332 38334 38333 38332 38331 38332 38352 38358 38332 38333 38352 38358 38334 38332 38333 38351 38352 39139 39138 38334 38334 38358 39139 38353 38336 38335 38336 38353 39132 39137 39136 38338 38338 38357 39137 39114 39113 38339 39126 39114 38339 39113 38357 38339 39145 38350 38340 39146 39145 38340 39147 39146 38340 39129 38345 38343 38343 39125 39129 38343 38344 39125 38344 39117 39125 39131 39130 38345 38345 39129 39131 38354 38353 38346 38356 38354 38346 38346 38347 38356 39153 38356 38347 38348 38349 39150 38350 38349 38348 38349 39897 39898 38349 38350 39897 39899 39150 38349 40649 39899 38349 41329 40649 38349 38349 39901 41329 38349 39898 39901 38350 39145 39897 38358 38352 38351 39150 38358 38351 38353 38354 39132 39887 39132 38354 39891 39887 38354 39900 39891 38354 38354 38355 39900 38356 38355 38354 39913 39900 38355 38355 39153 39913 38355 38356 39153 38357 39113 39137 39899 39139 38358 38358 39150 39899 39908 38360 38359 38359 38368 39908 38360 39146 39154 38360 39145 39146 41328 39145 38360 38360 39908 41328 39913 39153 38361 38361 38371 39913 38361 38362 38371 38363 38362 38361 38362 38363 38375 38372 38371 38362 38376 38372 38362 38362 38375 38376 39909 39166 38364 38364 39907 39909 38364 39906 39907 38364 39148 39906 38364 38365 39148 39922 39921 38366 38366 39163 39922 38366 38373 39163 38367 39151 39152 40653 39908 38368 38368 38369 40653 40668 40653 38369 38369 40667 40668 38369 39921 40667 38370 39156 39160 40654 39913 38371 40677 40654 38371 38371 39929 40677 38371 38372 39929 38372 38376 39929 38373 38378 39163 39162 38381 38374 39170 38376 38375 38375 38381 39170 38376 39926 39929 38376 39170 39926 39165 38382 38377 39167 39163 38378 38378 38379 39167 39179 39167 38379 38379 39178 39179 38379 38380 39178 38381 39168 39170 38381 39162 39168 39933 39192 38382 38382 39165 39933 39193 38384 38383 38383 38389 39193 39193 39189 38384 38391 38388 38385 38385 38386 38391 38387 38386 38385 38388 38387 38385 38386 38390 38391 38386 38387 38390 38392 38390 38387 39186 38392 38387 38387 39183 39186 38387 39172 39183 38387 39171 39172 39174 39171 38387 39176 39174 38387 39184 39176 38387 38387 38388 39184 39187 39184 38388 39188 39187 38388 38388 38391 39188 39199 39193 38389 39210 39199 38389 38392 38391 38390 39198 39188 38391 39954 39198 38391 38391 39202 39954 38391 38392 39202 38392 39200 39202 38392 39196 39200 39197 39196 38392 38392 39185 39197 39186 39185 38392 38395 38394 38393 39951 38395 38393 38393 39192 39951 38394 39949 39950 38394 38395 39949 40697 39949 38395 38395 39951 40697 38396 39216 39221 38396 38397 39216 38397 39215 39216 39958 39215 38397 38404 38399 38398 38398 38401 38404 38398 38400 38401 38404 38402 38399 39209 38404 38401 39963 39209 38401 38401 39208 39963 38404 38403 38402 38411 38405 38403 39209 38411 38403 38403 38404 39209 38405 38406 38409 38407 38406 38405 38411 38407 38405 38407 39219 39972 38407 38411 39219 38408 38415 39205 39987 39208 38410 38410 39986 39987 38410 39217 39986 39218 39217 38410 38411 39209 39219 38414 38413 38412 40739 39206 38413 38413 39224 40739 38413 38414 39224 38414 38424 39224 39207 38417 38416 38417 38421 38422 39231 38421 38417 38417 39220 39231 38417 39207 39220 38418 38423 39232 39232 39218 38418 39223 38424 38419 38420 39226 39234 38420 39225 39226 39234 38425 38420 39229 39225 38421 39231 39229 38421 39235 39232 38423 38424 39223 39224 39238 38431 38425 38425 39234 39238 38440 38427 38426 38426 38438 38440 38442 38432 38427 38427 38440 38442 38430 38429 38428 39236 38430 38428 38435 38434 38430 40760 38435 38430 38430 39237 40760 38430 39236 39237 38431 39238 39239 38432 38441 38445 38442 38441 38432 38433 38447 39236 38433 38443 38447 39253 39243 38434 38434 38435 39253 40008 39253 38435 40770 40008 38435 38435 40760 40770 39246 38437 38436 38438 38439 38440 39251 38440 38439 40004 39251 38439 38439 40003 40004 40006 38442 38440 40007 40006 38440 40010 40007 38440 38440 39251 40010 38446 38445 38441 40005 38446 38441 38441 38442 40005 40006 40005 38442 38443 38445 38447 40002 39245 38444 40009 40002 38444 38444 39254 40009 38444 38451 39254 38444 38450 38451 38448 38447 38445 38445 38446 38448 40000 38448 38446 40005 40000 38446 39996 39236 38447 39997 39996 38447 40001 39997 38447 38447 38448 40001 38448 40000 40001 38449 39243 39252 38452 38451 38450 38451 38452 39254 40009 39254 38452 40011 40009 38452 38452 39258 40011 38452 38455 39258 38452 38454 38455 39264 38454 38452 38453 38463 39264 38453 38462 38463 38453 38456 38462 39265 38455 38454 39269 39265 38454 38454 39264 39269 38455 39265 39266 40011 39258 38455 38455 39266 40011 38457 39272 39273 39274 38458 38457 38457 39273 39274 38467 38466 38458 39274 38467 38458 38464 38461 38460 38465 38464 38460 40795 39279 38461 38461 40792 40795 38461 38464 40792 39278 38463 38462 39269 39264 38463 40018 39269 38463 38463 39278 40018 38464 40022 40791 38464 38465 40022 38464 40791 40792 38465 39276 40022 38476 38470 38466 38477 38476 38466 39281 38477 38466 38466 39280 39281 38466 38467 39280 38467 39274 39280 40024 39276 38468 38468 38472 40024 38468 38471 38472 39277 38471 38468 38468 38469 39277 41448 40024 38472 38472 40029 41448 38473 39283 39288 39284 39283 38473 40030 39284 38473 38473 39282 40030 39286 38475 38474 38476 38477 39287 40026 39287 38477 38477 39281 40026 39289 38479 38478 39290 39289 38478 40038 40029 38479 38479 39289 40038 40035 39293 38481 40805 40035 38481 42105 40805 38481 38481 42104 42105 38481 38482 42104 38482 42101 42104 38482 41453 42101 38482 40034 41453 38482 39291 40034 39302 38499 38494 39304 39302 38494 39308 38498 38497 38497 38499 39308 39322 39315 38498 38498 39309 39322 38498 39308 39309 39309 39308 38499 38499 39303 39309 38499 39302 39303 38507 38522 38523 38507 38508 38522 39313 38522 38508 38508 38509 39313 38509 38510 39313 39328 39323 38520 39321 38523 38522 38522 39313 39321 40060 40059 38523 38523 39321 40060 40066 39328 38524 38524 39334 40066 39336 39334 38525 39341 39336 38525 38525 39337 39341 38526 38533 38534 39348 38533 38526 38526 39342 39348 38526 38529 39342 40076 39337 38528 38528 38532 40076 39298 39289 38530 40041 39298 38530 40061 40041 38530 38531 39338 39345 39339 39338 38531 38532 39347 40076 38532 39345 39347 38536 38534 38533 39348 38536 38533 38536 38535 38534 38535 38536 39348 38535 39348 39349 38543 38538 38537 39349 38543 38537 38538 38541 38542 38543 38541 38538 38539 40828 40829 41484 40828 38539 38539 38540 41484 41493 41484 38540 41498 41493 38540 38540 38544 41498 39353 38542 38541 39356 39353 38541 40094 39356 38541 38541 39352 40094 38541 38543 39352 38546 38545 38542 39353 38546 38542 38543 39349 39352 38544 40099 41498 38544 39354 40099 38545 38546 38560 38546 38558 38560 39353 38558 38546 39360 38554 38547 38547 38549 39360 38548 38554 38555 40103 39358 38548 38548 39362 40103 38548 38555 39362 38549 38556 39360 38549 38550 38556 38550 38551 38556 39361 38556 38551 38551 38570 39361 38551 38565 38570 39355 38565 38551 38564 38553 38552 38553 38565 39355 38553 38564 38565 40096 39359 38554 38554 39360 40096 39359 38555 38554 40116 39362 38555 38555 39375 40116 38555 39359 39375 39361 39360 38556 38557 39353 39356 38557 38558 39353 38559 38558 38557 40095 38559 38557 38557 40091 40095 38557 39356 40091 38566 38560 38558 40108 38566 38558 38558 38559 40108 38559 40097 40108 38559 40095 40097 38561 38562 39366 38563 38562 38561 40112 39366 38562 40113 40112 38562 38562 38567 40113 38562 38563 38567 40106 39370 38566 40108 40106 38566 39361 38570 38569 40096 39361 38569 38569 39363 39368 38569 38570 39363 38571 38580 39372 38571 38572 38580 38581 38580 38572 39390 38581 38572 38572 38593 39390 39372 38574 38573 39376 38576 38574 38574 39373 39376 39374 39373 38574 38574 39372 39374 39376 39375 38576 40128 39377 38577 38577 39367 40128 38578 39378 39379 38578 39371 39378 40863 40853 38579 38579 39385 40863 39386 39385 38579 38579 38589 39386 39387 39372 38580 38580 38581 39387 40126 39387 38581 40133 40126 38581 38581 39390 40133 39400 39399 38582 40141 39400 38582 38582 40134 40141 40135 40134 38582 38582 39383 40135 38587 38585 38583 38583 39382 39383 39384 39382 38583 38583 38585 39384 38584 40149 41527 38584 38597 40149 38584 38585 38597 38586 38585 38584 41519 38586 38584 41527 41519 38584 38585 38587 38597 38585 38586 39384 38586 39382 39384 39383 39382 38586 40869 39383 38586 41519 40869 38586 38591 38589 38588 38592 38591 38588 38589 38599 39386 38589 38590 38599 38591 38590 38589 38590 38600 38605 38590 38591 38600 40156 38599 38590 40158 40156 38590 38590 40157 40158 38590 39403 40157 38590 38605 39403 38591 38592 38600 38593 38612 39390 38594 39388 39389 38615 38595 38594 38594 38614 38615 39389 38614 38594 38595 38615 39391 39389 39388 38596 40152 40149 38597 38597 38598 40152 38598 38601 38604 40153 40152 38598 38598 39401 40153 38598 38604 39401 40155 39386 38599 40156 40155 38599 40154 39401 38602 40878 40154 38602 38602 40150 40878 38602 38603 40150 38604 38603 38602 39401 38604 38602 38603 39380 40150 38603 39379 39380 38605 39402 39403 38605 38606 39402 38606 38617 39402 38609 38608 38607 38610 38609 38607 39413 38625 38608 38608 39393 39413 38608 38609 39393 39404 38612 38611 38611 38619 39404 38611 38618 38619 40133 39390 38612 40151 40133 38612 38612 39404 40151 38615 38614 38613 39405 38615 38613 38613 38614 38620 39389 38620 38614 39392 39391 38615 39405 39392 38615 38629 38628 38616 39406 39402 38617 39411 39406 38617 38617 38621 39411 38618 39407 39408 40164 38619 38618 38618 39408 40164 40151 39404 38619 40164 40151 38619 39424 39411 38621 38621 38667 39424 38621 38622 38667 38623 38630 38648 38631 38630 38623 38623 38624 38631 39413 38631 38624 38624 38625 39413 38626 38636 39416 39407 38627 38626 39415 39407 38626 39416 39415 38626 39418 38643 38628 38628 38629 39418 38629 38642 39418 39423 38642 38629 40161 39423 38629 38629 39400 40161 38629 39399 39400 38630 38647 38648 39445 38647 38630 38630 39444 39445 40167 39444 38630 38630 38631 40167 38631 39414 40167 38631 39413 39414 38632 38650 39425 38632 38649 38650 38632 38637 38649 38632 38636 38637 38632 38633 38636 38634 38633 38632 39425 38634 38632 38633 38635 40169 38633 38634 38635 39416 38636 38633 40169 39416 38633 39419 38635 38634 39425 39419 38634 38635 39419 40173 40173 40169 38635 39409 38639 38638 40176 38657 38639 40898 40176 38639 38639 39421 40898 39422 39421 38639 38639 39420 39422 38639 39409 39420 38640 38660 38661 39436 38660 38640 38640 38659 39436 40902 38644 38641 40903 40902 38641 38641 40170 40903 38641 39423 40170 38641 38642 39423 38643 38642 38641 38644 38643 38641 38642 38643 39418 38643 38644 39426 40892 39426 38644 41543 40892 38644 38644 40902 41543 38645 38666 38667 40181 38666 38645 40191 40181 38645 38645 39467 40191 38645 38646 39467 38646 38701 39467 38647 39445 40178 39428 39425 38650 39430 39428 38650 38650 38656 39430 39433 38656 38651 38651 38657 39433 38651 38652 38657 38662 38655 38653 39427 38662 38653 38653 38654 39427 38654 39426 39427 38655 38662 38676 39439 39430 38656 38656 39433 39439 40177 39433 38657 38657 40176 40177 39436 38659 38658 40174 39437 38660 38660 39436 40174 39437 38661 38660 40196 38676 38662 40894 40196 38662 38662 39427 40894 39441 39440 38663 39462 39441 38663 40194 39462 38663 38663 39463 40194 38663 38664 39463 39450 38669 38665 38665 38670 39450 40162 39424 38666 42163 40162 38666 42908 42163 38666 38666 42168 42908 38666 40906 42168 38666 40181 40906 39424 38667 38666 39438 38687 38668 39449 39448 38669 38669 38699 39449 38669 38671 38699 39450 38671 38669 38670 38671 39450 38672 38671 38670 38674 38672 38670 39455 38699 38671 38671 38679 39455 38671 38678 38679 38671 38672 38678 38672 38673 38678 38674 38673 38672 38679 38678 38673 38680 38679 38673 38673 38674 38680 38681 38680 38674 38674 38675 38681 38679 38680 39465 39476 39455 38679 40223 39476 38679 38679 39469 40223 38679 39465 39469 38680 38681 39465 39469 39465 38681 38681 39466 39469 38681 38682 39466 40208 39466 38682 39459 38685 38684 38684 39446 39459 38695 38694 38685 39459 38695 38685 38694 38686 38685 38718 38702 38686 38686 38717 38718 38686 38693 38717 38694 38693 38686 38687 40198 40205 40199 40198 38687 38687 39438 40199 40205 39472 38687 38688 40219 40220 38688 40218 40219 38688 39477 40218 38688 38689 39477 38689 39473 39477 39475 39468 38692 38692 39474 39475 38693 38704 38717 38693 38703 38704 38693 38694 38703 38694 38695 38703 38706 38703 38695 39463 38706 38695 38695 39462 39463 38695 39441 39462 39459 39441 38695 38696 38697 38699 38698 38697 38696 38707 38698 38696 38709 38707 38696 38713 38709 38696 39454 38713 38696 38696 38699 39454 39464 38699 38697 38697 39447 39464 39461 39447 38697 38697 38698 39461 38698 40190 40195 38698 38706 39463 38707 38706 38698 40195 39461 38698 39464 39449 38699 39455 39454 38699 39456 38701 38700 38701 39456 39467 38702 38718 39497 38705 38704 38703 38706 38705 38703 38704 38716 38717 39483 38716 38704 38704 38705 39483 38705 38708 39483 38705 38706 38708 38706 38707 38708 38709 38708 38707 39485 39483 38708 38708 38719 39485 38708 38709 38719 38709 38710 38719 39454 38710 38709 38709 38713 39454 38710 38714 38719 38710 38711 38714 38712 38711 38710 39455 38712 38710 38710 39454 39455 40222 38714 38711 38711 39486 40222 38711 38712 39486 38712 39476 39486 38712 39455 39476 38714 39484 39485 40238 39484 38714 40239 40238 38714 38714 40222 40239 39485 38719 38714 38718 38717 38716 40221 38718 38716 40238 40221 38716 38716 39484 40238 38716 39483 39484 40233 39497 38718 38718 40221 40233 38737 38726 38721 38738 38737 38721 38721 38727 38738 38721 38724 38727 38721 38722 38724 38723 38722 38721 38726 38723 38721 38725 38724 38722 39480 38725 38722 38722 38723 39480 39494 39480 38723 40229 39494 38723 38723 39502 40229 38723 38735 39502 38723 38726 38735 38728 38727 38724 38724 38725 38728 39480 39479 38725 38739 38728 38725 39503 38739 38725 38737 38735 38726 38727 38728 38738 38740 38738 38728 38728 38739 38740 40249 39508 38729 40966 40249 38729 38729 39509 40966 38729 38730 39509 38732 38733 38744 38734 38733 38732 38733 38735 38744 39502 38735 38733 38733 39501 39502 38733 39500 39501 38733 38734 39500 39506 39500 38734 38735 38736 38744 38737 38736 38735 38748 38744 38736 38736 38745 38748 38746 38745 38736 38736 38737 38746 38737 38738 38746 39513 38746 38738 38738 38740 39513 38741 38740 38739 39503 38741 38739 40247 39513 38740 38740 40244 40247 38740 39507 40244 38740 38741 39507 38741 39505 39507 38741 39504 39505 40242 39506 38742 38742 39511 40242 38742 38743 39511 40241 39511 38743 40251 38748 38745 38745 39512 40251 38745 38746 39512 40247 39512 38746 38746 39513 40247 39516 39509 38747 40248 39516 38747 38747 39520 40248 40251 39517 38748 38749 38753 40973 41579 40263 38749 38749 40973 41579 39532 39530 38750 38751 40261 40262 38751 40259 40261 38751 38752 40259 40973 38753 38751 38751 40262 40973 38752 39527 40259 38762 38758 38754 38754 38761 38762 38754 38755 38761 40267 38761 38755 38755 39526 40267 40260 39527 38756 38756 38757 40260 40269 40260 38757 38757 39529 40269 38760 38759 38758 39536 38760 38758 38758 38762 39536 39536 39529 38760 40272 38762 38761 38761 40266 40272 40267 40266 38761 40274 39536 38762 38762 40273 40274 38762 40272 40273 39538 39537 38763 40281 39538 38764 38764 38765 40281 40284 40281 38765 38765 39541 40284 39557 38783 38766 40279 39557 38766 40280 40279 38766 38766 39539 40280 38766 39531 39539 38767 38775 39541 38768 38769 38777 39543 38777 38769 38769 39542 39543 38769 38770 39542 39545 39542 38770 38770 38771 39545 39553 39545 38771 38771 38772 39553 38772 39546 39553 39547 39546 38772 38772 38773 39547 38773 38778 39547 38776 38775 38774 38787 38776 38774 38775 38776 39541 40287 39541 38776 38776 39555 40287 38776 39554 39555 38776 38787 39554 38777 38779 38789 39543 38779 38777 38779 38780 38789 38781 38780 38779 39548 38781 38779 38779 39543 39548 39561 38789 38780 39563 39561 38780 38780 38781 39563 41017 39563 38781 38781 41012 41017 38781 39548 41012 38782 38790 39565 39557 38784 38783 39560 38791 38784 38784 39557 39560 38784 38791 38792 39558 38786 38785 39559 39558 38785 38785 38793 39559 39558 38787 38786 39558 39554 38787 38788 38795 38810 38796 38795 38788 40299 38796 38788 38788 38797 40299 38789 39561 39564 40297 39565 38790 38790 39560 40297 38790 38791 39560 38793 38794 39559 38794 38799 39559 38795 38796 39579 40300 39579 38796 38798 39564 40301 40301 38803 38798 39570 39559 38799 38799 38809 39570 40303 39571 38800 40305 40303 38800 38800 39572 40305 38800 38801 39572 38801 38804 39572 38805 38804 38802 38824 38812 38803 39578 38824 38803 38803 39577 39578 41035 39577 38803 38803 40301 41035 39573 39572 38804 39574 39573 38804 38804 38805 39574 38805 38806 39574 39580 39574 38806 39582 39580 38806 38806 38807 39582 38807 39576 39582 38807 39575 39576 38807 38811 39575 38809 38826 39570 38809 38825 38826 38809 38813 38825 38824 38821 38812 38865 38825 38813 38837 38836 38814 38814 38815 38837 38815 38828 38837 38815 38827 38828 41049 39592 38816 38816 41042 41049 38820 38819 38817 38819 38818 38817 38818 38833 39575 38818 38819 38833 38834 38822 38821 38821 38823 38834 38824 38823 38821 39584 38834 38823 41050 39584 38823 41647 41050 38823 38823 41048 41647 38823 38824 41048 38824 41026 41048 41027 41026 38824 38824 39578 41027 39589 38826 38825 38825 39588 39589 38825 39586 39588 38825 39585 39586 38825 38865 39585 38826 39569 39570 40302 39569 38826 41033 40302 38826 41038 41033 38826 38826 39589 41038 40311 38837 38828 38829 40309 40311 40310 40309 38829 38829 40307 40310 40308 40307 38829 38829 38830 40308 38830 38831 40308 38831 39591 40308 38840 38833 38832 38832 38839 38840 38833 38840 39575 39584 38835 38834 38836 38837 38847 39631 38847 38837 40323 39631 38837 38837 40311 40323 39612 39596 38838 39613 39612 38838 38838 38884 39613 38838 38863 38884 38838 38852 38863 38838 38839 38852 38840 38839 38838 39596 38840 38838 39576 39575 38840 39596 39576 38840 38841 41062 41063 38841 39598 41062 39599 39598 38841 40347 39599 38841 38841 39630 40347 38842 39592 39610 38843 38851 38852 39632 38864 38844 38844 38845 39632 38846 38845 38844 40351 39632 38845 38845 40338 40351 38845 38846 40338 38846 39626 40338 39606 39605 38849 38849 38860 39606 38850 38853 38863 38850 38851 38853 38852 38851 38850 38863 38852 38850 38864 38853 38851 38884 38863 38853 38853 38881 38884 38895 38881 38853 38897 38895 38853 38853 38885 38897 38853 38854 38885 38855 38854 38853 38864 38855 38853 38907 38885 38854 38854 38904 38907 38854 38855 38904 38855 38886 38904 38855 38864 38886 38858 38857 38856 39602 39600 38857 39603 39602 38857 38857 38858 39603 39604 39603 38858 40324 39606 38860 38860 39617 40324 40328 39617 38861 38861 38887 40328 40325 39638 38862 38862 39607 40325 39642 38886 38864 38864 39632 39642 41063 39585 38865 39636 38873 38866 38866 38867 39636 38867 39635 39636 38867 39615 39635 38868 38890 39618 38868 38875 38890 38869 39623 39628 40326 38872 38870 38870 40322 40326 40336 40322 38870 38870 38879 40336 38870 38877 38879 38870 38871 38877 38872 38871 38870 38878 38877 38871 38882 38878 38871 38871 38881 38882 38871 38880 38881 39625 38880 38871 38871 39612 39625 38871 38872 39612 40326 40321 38872 38872 39597 39612 40321 39597 38872 38873 39635 39643 39636 39635 38873 39634 39630 38873 39643 39634 38873 39641 38890 38875 38879 38877 38876 38892 38891 38878 38893 38892 38878 38894 38893 38878 38878 38882 38894 38879 39629 40336 39613 38881 38880 38880 39612 39613 39625 39612 38880 38883 38882 38881 38896 38883 38881 38881 38895 38896 39613 38884 38881 38882 38883 38894 38902 38894 38883 39650 38902 38883 38883 38896 39650 39655 38897 38885 38885 38907 39655 38905 38904 38886 39642 38905 38886 40330 40328 38887 41070 40330 38887 38887 38888 41070 41074 41070 38888 38888 40355 41074 40362 39639 38889 38889 40357 40362 38889 40356 40357 40331 39618 38890 40349 40331 38890 38890 40348 40349 41075 40348 38890 38890 39640 41075 39641 39640 38890 38891 38892 38901 39647 38901 38892 39648 39647 38892 38892 38893 39648 39649 39648 38893 38893 38902 39649 38893 38894 38902 38903 38896 38895 38895 38897 38903 39651 39650 38896 38896 38903 39651 39652 38903 38897 39655 39652 38897 40360 38906 38898 38900 39640 39641 41075 39640 38900 41667 41075 38900 41671 41667 38900 38900 39647 41671 39650 39649 38902 39652 39651 38903 39653 38907 38904 40358 39653 38904 38904 38905 40358 38905 39642 40358 40361 40355 38906 38906 40360 40361 38907 39653 39655 39656 38910 38909 38910 39656 40382 39657 38912 38911 39657 38913 38912 40385 39661 38913 38913 39657 40385 39663 38919 38914 38914 38915 39663 39678 39666 38917 39685 39678 38917 39675 38924 38918 40401 39675 38918 38918 38919 40401 38919 40393 40401 38919 39660 40393 39664 39660 38919 39665 39664 38919 38919 39663 39665 38928 38926 38920 40413 38928 38920 38920 38921 40413 38921 40412 40413 38921 39684 40412 38921 38922 39684 39693 39692 38923 38923 39691 39693 39675 39672 38924 39683 38925 38924 38924 39682 39683 38924 39673 39682 38924 39672 39673 38925 39688 39689 38925 39683 39688 38926 38927 38929 38928 38927 38926 38927 38928 40432 39696 38929 38927 40432 39696 38927 38928 40413 40432 39696 38931 38929 38930 38933 39677 38930 38932 38933 38939 38932 38930 38930 38934 38939 40445 38952 38931 38931 40440 40445 38931 40433 40440 38931 39696 40433 38932 39697 40450 38932 38939 39697 40450 38933 38932 40414 39677 38933 40434 40414 38933 41147 40434 38933 41171 41147 38933 38933 40450 41171 38941 38939 38934 38935 38936 38943 38936 38937 38944 38939 38942 39697 38939 38941 38942 39702 39700 38940 38942 38941 38940 39700 38942 38940 40450 39697 38942 40460 40450 38942 38942 39700 40460 40455 39698 38945 38945 39705 40455 38945 38946 39705 38946 38947 39705 38948 38947 38946 38947 38948 38949 41167 39705 38947 38947 40458 41167 38947 38949 40458 38952 38949 38948 38949 38950 40458 38952 38950 38949 38950 38951 40456 38952 38951 38950 38950 40457 40458 38950 40456 40457 38951 40445 41162 38951 38952 40445 41162 40456 38951 38953 39719 39720 39720 38954 38953 40459 39712 38954 40469 40459 38954 40470 40469 38954 38954 39720 40470 38960 38958 38955 40459 38960 38955 38955 39712 40459 38959 38957 38956 38956 38958 38959 38957 38959 39699 38960 38959 38958 38959 38960 39699 40471 39699 38960 38960 39722 40471 40459 39722 38960 38962 40471 40472 38962 39699 40471 38962 40472 40478 39704 38973 38963 38964 38974 39703 39713 38976 38965 38965 39706 39713 38965 38966 39706 39709 39706 38966 38967 38969 39714 38967 38968 38969 39715 39714 38969 38969 38982 39715 38972 38971 38970 39704 38972 38970 38970 38973 39704 39716 38973 38970 39727 39716 38970 38970 39717 39727 39718 39717 38970 38970 38971 39718 38971 39711 40475 38971 38972 39711 40475 39718 38971 40452 39711 38972 40453 40452 38972 38972 39704 40453 39716 38977 38973 39724 39703 38974 39725 39724 38974 38974 38975 39725 40462 39725 38975 38975 40461 40462 40486 38980 38976 38976 40473 40486 38976 39713 40473 39716 38978 38977 38978 38985 38986 39716 38985 38978 38991 38990 38979 39729 39728 38980 40486 39729 38980 38981 38982 38993 38983 38982 38981 39730 38983 38981 39731 39730 38981 38981 38994 39731 39743 38994 38981 41187 39715 38982 38982 38983 41187 38983 40480 41187 38983 40477 40480 38983 40476 40477 40481 40476 38983 40482 40481 38983 40483 40482 38983 38983 39730 40483 40499 38987 38984 38984 39726 40499 38984 38985 39726 38986 38985 38984 38987 38986 38984 39727 39726 38985 38985 39716 39727 39734 38997 38986 38986 38987 39734 40499 39734 38987 39738 39737 38990 38990 38991 39738 38991 39732 39738 38991 38992 39732 38992 38998 39732 39745 39744 38994 40493 39745 38994 40504 40493 38994 38994 39743 40504 40489 39731 38994 38994 38995 40489 38996 38995 38994 39733 38996 38994 39744 39733 38994 40494 40489 38995 41200 40494 38995 38995 41199 41200 38995 38996 41199 43236 41199 38996 38996 43234 43236 38996 41197 43234 41198 41197 38996 41795 41198 38996 38996 39733 41795 38998 38999 39742 39740 39732 38998 39741 39740 38998 39748 39741 38998 38998 39742 39748 39000 39753 39754 39760 39753 39000 39000 39735 39736 39754 39735 39000 39748 39004 39001 39002 39006 39750 39751 39007 39003 39748 39742 39004 39755 39018 39005 39006 39008 39750 39751 39017 39007 40518 39750 39008 40519 40518 39008 40520 40519 39008 39008 39009 40520 40526 40520 39009 39758 39012 39010 39010 39013 39758 39010 39011 39013 39012 39011 39010 39759 39015 39012 40515 39759 39012 39012 39756 40515 39758 39756 39012 39769 39758 39013 39773 39769 39013 39013 39014 39773 39014 39772 39773 40539 39772 39014 39014 39778 40539 39014 39022 39778 39015 39759 39760 39017 40508 40521 39017 39751 40508 39763 39762 39018 39764 39763 39018 40509 39764 39018 39018 39755 40509 39019 39021 40527 39784 39024 39020 39020 39768 39784 39021 39785 40527 39021 39024 39785 39023 39775 40535 40535 39782 39023 39024 39784 39785 39790 39781 39025 39791 39790 39025 39028 39027 39026 39794 39029 39027 40536 39794 39027 39027 39028 40536 39028 40534 40536 39028 39780 40534 39794 39031 39029 39030 39038 39810 39031 39041 39046 39042 39041 39031 39794 39042 39031 39788 39787 39032 39789 39788 39032 39796 39789 39032 39033 39034 39043 39035 39034 39033 39034 39803 39807 40557 39803 39034 41244 40557 39034 39034 39804 41244 39034 39035 39804 39807 39043 39034 39035 39036 39804 39038 39797 39810 39038 39039 39797 39039 39795 39797 39040 39798 40561 40561 40547 39040 39800 39046 39041 40550 39800 39041 39041 39042 40550 39042 40546 40550 39042 39794 40546 40559 39804 39044 39044 39809 40559 39044 39805 39809 39045 39048 39049 39800 39799 39046 40573 40572 39051 39051 39811 40573 39056 39054 39053 39053 39055 39056 39054 39056 39830 40575 39056 39055 39055 39806 40575 40586 39830 39056 39056 40574 40586 40575 40574 39056 40585 39829 39058 39059 39065 39823 39059 39063 39065 40583 39069 39061 39061 39829 40583 39064 39063 39062 39063 39064 39065 39834 39065 39064 39064 39833 39834 40593 39823 39065 39065 39068 40593 39065 39067 39068 39834 39067 39065 39066 39835 40588 39834 39833 39066 39066 39067 39834 39068 39067 39066 40588 39068 39066 39068 40592 40593 39068 40588 40592 39069 39828 39832 39069 39815 39828 40583 39815 39069 39070 39836 39837 39070 39071 39836 39841 39836 39071 39071 39840 39841 39081 39074 39072 39072 39073 39081 39842 39081 39073 39843 39842 39073 39073 39838 39843 39081 39080 39074 39082 39078 39075 39088 39079 39077 39077 39082 39088 39077 39078 39082 39079 39078 39077 39088 39087 39079 39079 39087 39089 39080 39081 39085 39842 39085 39081 39090 39088 39082 39082 39083 39090 39083 39086 39090 39097 39092 39084 40600 39844 39084 40604 40600 39084 39084 40602 40604 40605 40602 39084 39084 39092 40605 40606 39846 39085 41270 40606 39085 39085 39842 41270 39096 39090 39086 39087 39090 39096 39087 39088 39090 39091 39089 39087 39096 39091 39087 39091 39096 39101 39092 39097 39848 39092 40601 40605 40603 40601 39092 39092 39856 40603 39092 39093 39856 39094 39093 39092 39848 39094 39092 41266 39856 39093 41273 41266 39093 41275 41273 39093 39093 39094 41275 39094 39848 39855 39094 39855 41275 39105 39101 39096 40619 39865 39098 41292 40619 39098 39098 40622 41292 41293 40622 39098 41887 41293 39098 39098 39849 41887 39850 39849 39098 39098 39103 39850 39104 39103 39099 39100 39101 39107 39851 39107 39101 39101 39847 39851 39101 39106 39847 39101 39105 39106 39103 39104 39846 39103 39846 39850 39860 39852 39107 40609 39860 39107 39107 39858 40609 39107 39851 39858 40618 39861 39108 40630 40618 39108 39108 40617 40630 39108 39864 40617 39108 39109 39864 39109 39120 39864 39121 39120 39109 39863 39112 39110 39110 39862 39863 39871 39862 39111 39872 39871 39111 39882 39872 39111 39863 39116 39112 39113 39114 39137 39144 39137 39114 40634 39144 39114 39114 39126 40634 40632 39126 39115 39115 39116 40632 39116 39873 40632 39116 39863 39873 39117 39124 39125 39117 39118 39124 39874 39124 39118 39118 39865 39874 40637 39882 39119 39119 39133 40637 40617 39864 39120 40628 40617 39120 41907 40635 39122 39122 39123 41907 41909 41907 39123 39123 41310 41909 39874 39128 39124 39127 39125 39124 39128 39127 39124 39125 39127 39129 39126 40632 40634 39876 39875 39127 39127 39128 39876 39131 39129 39127 39877 39131 39127 39127 39875 39877 39128 39865 40619 39874 39865 39128 40620 39876 39128 39128 40619 40620 39130 39131 39140 39877 39140 39131 40637 39133 39132 39132 39888 40637 39132 39887 39888 39896 39149 39134 40648 39896 39134 41319 40648 39134 39134 39135 41319 39135 40639 41319 40640 40639 39135 39135 39136 40640 39136 39137 40640 39137 39144 40640 39892 39883 39138 40641 39892 39138 39138 39139 40641 39139 39899 40641 39895 39151 39140 39140 39880 39895 39140 39877 39880 39877 39867 39141 39879 39877 39141 39886 39879 39141 39141 39881 39886 39141 39142 39881 39143 39142 39141 39867 39143 39141 39142 39869 39881 39142 39868 39869 39142 39143 39868 39143 39867 39868 41318 40640 39144 39144 41307 41318 39144 40634 41307 39898 39897 39145 40644 39898 39145 41320 40644 39145 41935 41320 39145 39145 41328 41935 39146 39147 39154 39148 39896 39906 39148 39149 39896 39155 39152 39151 39895 39155 39151 39159 39157 39155 39895 39159 39155 39162 39160 39156 39156 39161 39162 39156 39157 39161 39157 39158 39161 39159 39158 39157 39923 39910 39158 39158 39905 39923 39158 39159 39905 39164 39161 39158 39910 39164 39158 39159 39903 39905 39159 39895 39903 39164 39162 39161 39169 39168 39162 39162 39164 39169 39163 39167 39922 39910 39169 39164 39165 39927 39933 39165 39166 39927 39166 39909 39927 40670 39922 39167 39167 39179 40670 39168 39169 39170 39924 39170 39169 39169 39923 39924 39169 39910 39923 40675 39926 39170 39170 39924 40675 39173 39172 39171 39174 39173 39171 39935 39183 39172 39172 39173 39935 39173 39174 39177 39173 39915 39935 39173 39914 39915 39173 39177 39914 39174 39175 39920 39176 39175 39174 39920 39177 39174 40679 40661 39175 39175 39938 40679 39175 39176 39938 40661 39920 39175 39176 39190 39938 39191 39190 39176 39176 39184 39191 39917 39914 39177 39920 39917 39177 39181 39180 39178 39182 39181 39178 39180 39179 39178 40673 40670 39179 40683 40673 39179 40687 40683 39179 39179 39180 40687 39180 39934 39940 39180 39181 39934 39180 39940 40687 39936 39934 39181 39181 39182 39936 40689 39186 39183 39183 40678 40689 39183 39935 40678 39184 39187 39191 40688 39197 39185 39185 39186 40688 40689 40688 39186 39187 39188 39191 39198 39191 39188 39189 39194 39939 39189 39193 39194 39942 39938 39190 39190 39941 39942 39947 39941 39190 39190 39191 39947 39955 39947 39191 39191 39946 39955 39191 39198 39946 40690 39951 39192 40699 40690 39192 39192 40682 40699 39192 39933 40682 39195 39194 39193 39199 39195 39193 39940 39939 39194 39943 39940 39194 39944 39943 39194 39194 39195 39944 39195 39212 39944 39195 39210 39212 39195 39199 39210 39201 39200 39196 39945 39201 39196 39953 39945 39196 40691 39953 39196 39196 39197 40691 39197 40688 40691 39956 39946 39198 40703 39956 39198 39198 39954 40703 39200 39201 39203 39203 39202 39200 39204 39203 39201 39952 39204 39201 39201 39945 39952 39202 39204 39954 39202 39203 39204 39971 39954 39204 39204 39959 39971 39204 39952 39959 39211 39210 39205 39205 39206 39211 40732 39211 39206 40738 40732 39206 40739 40738 39206 39982 39220 39207 39207 39221 39982 40728 39963 39208 40729 40728 39208 39208 39987 40729 39963 39219 39209 39210 39211 39212 39213 39212 39211 40724 39213 39211 40732 40724 39211 39212 39213 39944 40701 39943 39213 40715 40701 39213 40716 40715 39213 41377 40716 39213 39213 40724 41377 39213 39943 39944 39984 39978 39214 40736 39984 39214 39214 40726 40736 39214 40725 40726 39214 39215 40725 39216 39215 39214 39978 39216 39214 39215 39958 40725 39977 39221 39216 39978 39977 39216 40755 39986 39217 39217 39247 40755 39217 39232 39247 39217 39218 39232 39965 39964 39219 39219 39963 39965 39219 39964 39972 39992 39231 39220 40748 39992 39220 39220 39983 40748 39220 39982 39983 39221 39977 39982 39233 39223 39222 40750 39233 39222 39222 40746 40750 39233 39224 39223 39224 39989 40739 39990 39989 39224 39224 39988 39990 39224 39233 39988 39229 39226 39225 39226 39227 39234 39228 39227 39226 39229 39228 39226 40757 39993 39227 39227 39228 40757 39993 39234 39227 39228 39230 40757 39228 39229 39230 39231 39230 39229 40758 40757 39230 39230 39991 40758 39230 39231 39991 39992 39991 39231 39232 39235 39247 40756 39988 39233 39233 40750 40756 39994 39238 39234 39995 39994 39234 39234 39993 39995 39235 39244 39247 39245 39244 39235 39240 39237 39236 39996 39240 39236 40770 40760 39237 41404 40770 39237 39237 40759 41404 39237 39241 40759 39237 39240 39241 39994 39239 39238 39994 39246 39239 39242 39241 39240 39996 39242 39240 39241 39242 40759 41396 40759 39242 39242 39996 41396 39253 39252 39243 40002 39998 39244 39244 39245 40002 39998 39247 39244 39250 39248 39246 39999 39250 39246 39246 39995 39999 39246 39994 39995 40761 40755 39247 39247 39998 40761 39248 39249 40003 39250 39249 39248 40780 40003 39249 39249 40772 40780 39249 39250 40772 39250 40765 40772 40766 40765 39250 39250 39999 40766 40773 40010 39251 40781 40773 39251 39251 40004 40781 39256 39255 39252 39257 39256 39252 39252 39253 39257 40008 39257 39253 39255 39256 39260 39255 39260 39261 40012 39260 39256 40783 40012 39256 39256 39257 40783 39257 40008 40783 39259 40782 41425 39259 40012 40782 39259 39260 40012 39261 39260 39259 39270 39261 39259 40016 39270 39259 40784 40016 39259 41425 40784 39259 39261 39262 39263 39270 39262 39261 39270 39267 39262 39267 39263 39262 39271 39268 39263 39263 39267 39271 40017 39266 39265 40023 40017 39265 39265 39269 40023 41428 41423 39266 39266 40017 41428 39266 40009 40011 40776 40009 39266 41423 40776 39266 40016 39271 39267 39267 39270 40016 39268 39271 40021 39273 39272 39268 40021 39273 39268 40790 40023 39269 39269 40025 40790 39269 40018 40025 40788 40787 39271 39271 40019 40788 40020 40019 39271 39271 40016 40020 40787 40021 39271 39275 39274 39273 40021 39275 39273 39274 39275 39280 40789 39280 39275 39275 40021 40789 40024 40022 39276 39278 39279 40018 40796 40018 39279 39279 40795 40796 40798 39281 39280 39280 40789 40798 40027 40026 39281 40028 40027 39281 40797 40028 39281 40798 40797 39281 40803 40030 39282 40804 40803 39282 39282 40801 40804 39292 39288 39283 40034 39292 39283 40803 40034 39283 39283 39284 40803 39284 40030 40803 39285 40032 40033 39285 39287 40032 39285 39286 39287 39287 40027 40032 39287 40026 40027 39289 40037 40038 39289 39297 40037 39298 39297 39289 39291 39292 40034 40036 39294 39293 39293 40035 40036 40036 39296 39294 40036 39304 39296 40040 40037 39297 40041 40040 39297 39297 39298 40041 39302 39305 40035 39302 39304 39305 40039 39303 39302 40807 40039 39302 39302 40035 40807 40050 39309 39303 41462 40050 39303 41464 41462 39303 39303 40039 41464 40036 39305 39304 40036 40035 39305 40050 39322 39309 40046 39321 39313 39313 39314 40046 40047 40046 39314 40048 40047 39314 39314 39322 40048 39314 39315 39322 39316 40051 40052 39316 39325 40051 40052 39317 39316 40053 39318 39317 39317 40052 40053 40053 39326 39318 40817 40060 39321 41471 40817 39321 39321 40046 41471 40049 40048 39322 40050 40049 39322 40051 39324 39323 39323 39327 40051 39328 39327 39323 40051 39325 39324 40820 39330 39326 39326 40053 40820 41479 40051 39327 39327 40825 41479 39327 40066 40825 39327 39328 40066 39330 40063 40064 40820 40063 39330 39334 39335 40066 39336 39335 39334 40824 40066 39335 39335 39336 40824 39341 39340 39336 40830 40824 39336 39336 39340 40830 39337 39340 39341 40070 39340 39337 40076 40070 39337 40077 39345 39338 40832 40077 39338 39338 39339 40832 39339 40069 40832 39339 40065 40069 41478 40830 39340 39340 40081 41478 39340 40070 40081 40085 39348 39342 39342 40072 40085 39342 39343 40072 39343 39344 40072 39344 40071 40072 39344 40067 40071 39345 39346 39347 40077 39346 39345 40076 39347 39346 40078 40076 39346 40080 40078 39346 40837 40080 39346 39346 40077 40837 40084 39349 39348 40085 40084 39348 39349 39351 39352 39349 39350 39351 40084 39350 39349 41491 40839 39350 39350 40838 41491 39350 40085 40838 39350 40084 40085 40839 39351 39350 40087 39352 39351 39351 40086 40087 40839 40086 39351 39352 40089 40094 39352 40088 40089 41501 40088 39352 39352 41499 41501 39352 40087 41499 39354 39357 40099 40094 40091 39356 40101 40099 39357 40109 40101 39357 39357 39365 40109 39357 39364 39365 39359 40096 40114 40114 39375 39359 39360 39361 40096 40104 40103 39362 40851 40104 39362 39362 40116 40851 40115 39365 39364 40853 40115 39364 40110 40109 39365 40115 40110 39365 40111 39367 39366 40117 40111 39366 40855 40117 39366 39366 40845 40855 39366 40112 40845 39367 40111 40128 40859 39371 39369 39369 39370 40859 39370 40106 40859 40862 39378 39371 39371 40858 40862 40859 40858 39371 40120 39374 39372 39372 39387 40120 40851 39376 39373 39373 40104 40851 40119 40104 39373 39373 39374 40119 39374 40118 40119 40120 40118 39374 39375 39376 40116 40851 40116 39376 40138 39381 39377 39377 40128 40138 40862 40127 39378 39380 39379 39378 40127 39380 39378 39380 40127 40150 40142 40135 39383 40869 40142 39383 39385 39386 40871 41515 40863 39385 39385 40871 41515 39386 40155 41521 41521 40871 39386 40126 40120 39387 39398 39396 39391 39391 39392 39398 39392 39405 39417 40160 39398 39392 39395 39394 39393 40138 39395 39393 40159 39413 39393 40872 40159 39393 39393 39394 40872 39394 39395 40864 39394 40131 40872 41510 40131 39394 39394 40864 41510 39395 40128 40864 40138 40128 39395 39396 39397 39410 39398 39397 39396 39397 39398 40166 39398 40160 40166 39400 40141 40161 40154 40153 39401 39412 39403 39402 39402 39406 39412 39403 39412 40157 39406 39411 39412 39407 39415 40163 40163 39408 39407 40165 40164 39408 40875 40165 39408 40884 40875 39408 39408 40163 40884 39409 39410 39420 39437 39420 39410 40162 39412 39411 39411 39424 40162 40162 40157 39412 40887 39414 39413 39413 40159 40887 40168 40167 39414 40887 40168 39414 40888 40884 39415 39415 39416 40888 40884 40163 39415 40889 40888 39416 39416 40169 40889 40891 40890 39419 39419 40179 40891 39419 39431 40179 39432 39431 39419 39419 39425 39432 40890 40173 39419 39437 39422 39420 40899 40898 39421 40901 40899 39421 39421 39422 40901 39422 40900 40901 39422 40174 40900 39422 39437 40174 40886 40170 39423 39423 40175 40886 39423 40161 40175 39425 39431 39432 40183 39431 39425 40193 40183 39425 39425 39428 40193 40893 39427 39426 39426 40892 40893 39427 40893 40894 40916 40193 39428 39428 39429 40916 39430 39429 39428 39429 40911 40916 39429 40910 40911 39429 39439 40910 39429 39430 39439 40180 40179 39431 40182 40180 39431 40183 40182 39431 39435 39434 39433 40177 39435 39433 40910 39439 39433 39433 40909 40910 39433 39434 40909 39434 40185 40206 39434 39435 40185 39434 39451 40909 40206 39451 39434 40187 40185 39435 40898 40187 39435 39435 40177 40898 40188 40174 39436 39438 40178 40199 40189 39442 39440 39440 39441 40189 39441 39459 40189 40189 39460 39442 39460 39446 39442 40178 39445 39443 40184 40178 39443 39443 40180 40184 39443 39444 40180 39445 39444 39443 39444 40167 40180 39460 39459 39446 39447 39448 39464 39447 39461 40190 39448 39449 39464 40911 40909 39451 39451 39452 40911 39453 39452 39451 40206 39453 39451 39452 40200 40928 40201 40200 39452 39452 39453 40201 40928 40911 39452 40930 40201 39453 40932 40930 39453 39456 39490 40214 40212 39490 39456 39456 39457 40212 40213 39467 39456 40214 40213 39456 39457 39489 40212 40206 40185 39458 39459 39460 40189 40195 40190 39461 40194 39463 39462 40208 40207 39466 39470 39469 39466 40207 39470 39466 40197 40191 39467 40917 40197 39467 39467 40213 40917 39468 39481 40934 39468 39475 39481 40934 40211 39468 39469 40217 40223 39469 39470 40217 40935 40217 39470 39470 40924 40935 39470 40207 40924 40215 39473 39471 39471 39472 40215 39472 40205 40215 40215 39477 39473 39479 39475 39474 39475 39480 39481 39475 39479 39480 39487 39486 39476 40938 39487 39476 39476 40223 40938 40929 40218 39477 39477 40215 40929 39482 39481 39480 39495 39482 39480 39480 39494 39495 39481 40209 40934 40210 40209 39481 39481 39482 40210 40933 40210 39482 39482 39495 40933 39485 39484 39483 40957 40222 39486 39486 39487 40957 41559 40957 39487 39487 40938 41559 39492 39489 39488 39489 39490 40212 39491 39490 39489 39492 39491 39489 39490 39491 40214 40951 40939 39491 39491 39492 40951 40939 40214 39491 39492 40240 40951 40227 39510 39493 40942 39495 39494 39494 40229 40942 40943 40933 39495 39495 40942 40943 40955 40231 39496 39496 40232 40955 40233 40232 39497 40949 40224 39498 39498 39499 40949 40950 40949 39499 42183 40950 39499 39499 39535 42183 40257 39535 39499 39499 39522 40257 39506 39501 39500 40229 39502 39501 40953 40229 39501 40958 40953 39501 39501 39506 40958 41569 39505 39504 41570 41569 39504 39504 40230 41570 41569 41568 39505 40963 39507 39505 41568 40963 39505 40961 40958 39506 39506 40242 40961 40963 40244 39507 40270 40256 39508 40970 40270 39508 39508 40969 40970 39508 40967 40969 39508 40250 40967 39508 40249 40250 39509 39516 40966 39510 40227 40241 40961 40242 39511 40962 40961 39511 39511 40243 40962 39511 40241 40243 39512 40246 40251 39512 40245 40246 40247 40245 39512 40969 40968 39514 40972 40969 39514 40987 40972 39514 39514 39515 40987 39516 39515 39514 40968 39516 39514 39515 40983 40987 39515 40976 40983 39515 40253 40976 40255 40253 39515 39515 39516 40255 40968 40966 39516 39516 40248 40255 39517 40266 40267 41576 40266 39517 39517 40258 41576 39517 40251 40258 40267 39525 39517 40252 39519 39518 40254 40252 39518 40264 40254 39518 39520 39521 40248 40255 40248 39521 39521 40252 40255 39522 39524 40257 39522 39523 39524 39528 39524 39523 39524 39528 40257 40267 39526 39525 40260 40259 39527 39528 39535 40257 39529 40268 40269 39529 39536 40268 40271 39531 39530 39530 40270 40271 39530 39532 40270 39540 39539 39531 40271 39540 39531 39532 40256 40270 39533 39534 41000 39535 39534 39533 40985 39535 39533 41595 40985 39533 39533 41000 41595 39534 39538 40282 39534 39537 39538 39534 40282 41000 43725 42183 39535 39535 42969 43725 39535 40985 42969 40274 40268 39536 39538 40281 40282 42987 40280 39539 39539 42207 42987 42976 42207 39539 39539 39540 42976 39540 42207 42976 39540 40971 42207 39540 40271 40971 40285 40284 39541 40286 40285 39541 40287 40286 39541 39544 39543 39542 39545 39544 39542 39543 39544 39552 39549 39548 39543 39550 39549 39543 39551 39550 39543 39552 39551 39543 39544 39545 39552 39553 39552 39545 41005 39553 39546 41014 41005 39546 39546 39565 41014 39546 39547 39565 39548 41010 41012 39548 41003 41010 39548 39549 41003 39549 39550 41003 41004 41003 39550 39550 39551 41004 41007 41004 39551 39551 39552 41007 39552 41005 41007 39552 39553 41005 39556 39555 39554 39558 39556 39554 41002 40287 39555 41614 41002 39555 41618 41614 39555 39555 39556 41618 39556 41019 41618 39556 39568 41019 39556 39558 39568 40288 39560 39557 40289 40288 39557 39557 40279 40289 39558 39567 39568 39558 39559 39567 40302 39567 39559 39559 39569 40302 39570 39569 39559 40298 40297 39560 39560 40295 40298 39560 40290 40295 40291 40290 39560 39560 40288 40291 39561 39562 39564 39563 39562 39561 39562 40292 41035 40293 40292 39562 39562 39563 40293 40301 39564 39562 41035 40301 39562 41017 40293 39563 41029 41014 39565 41630 41029 39565 39565 40296 41630 40298 40296 39565 39565 40297 40298 39566 39567 40302 39568 39567 39566 41632 39568 39566 42234 41632 39566 39566 41040 42234 39566 40302 41040 41020 41019 39568 41632 41020 39568 41043 40300 39571 41047 41043 39571 39571 40303 41047 39572 39581 40305 39572 39573 39581 39573 39580 39581 39573 39574 39580 39593 39582 39576 39597 39593 39576 39576 39596 39597 41024 39578 39577 39577 40292 41024 41035 40292 39577 39578 41024 41027 41044 41042 39579 39579 41043 41044 39579 40300 41043 39583 39581 39580 39580 39582 39583 39581 40304 40305 39581 39583 40304 39593 39583 39582 40316 40304 39583 39583 39593 40316 41050 39614 39584 39587 39586 39585 41650 39587 39585 39585 41063 41650 42249 39588 39586 39586 39587 42249 39587 41650 42249 39590 39589 39588 41648 39590 39588 42249 41648 39588 39589 39590 41038 41041 41038 39590 42244 41041 39590 42246 42244 39590 42247 42246 39590 39590 41648 42247 40314 40308 39591 40315 40314 39591 39591 39600 40315 39592 39594 39610 39595 39594 39592 41049 39595 39592 40321 40316 39593 39593 39597 40321 40332 39611 39594 39594 39595 40332 39611 39610 39594 40335 40332 39595 41049 40335 39595 39612 39597 39596 41654 41062 39598 39598 39599 41654 41657 41654 39599 39599 41071 41657 39599 40347 41071 39600 39601 40315 41052 40315 39601 41054 41052 39601 39603 39604 39616 41064 41056 39605 41653 41064 39605 39605 41057 41653 39605 39606 41057 39606 40324 41057 39607 39608 40325 39609 39608 39607 39608 39609 40325 40331 40325 39609 39609 39618 40331 39611 40332 40333 40345 40327 39614 41050 40345 39614 39637 39635 39615 40340 39637 39615 39615 39627 40340 40329 40324 39617 40330 40329 39617 39617 40328 40330 39619 40325 40331 41065 40325 39619 39619 39620 41065 39621 39620 39619 41067 39621 39619 42265 41067 39619 39619 41665 42265 39619 40331 41665 41066 41065 39620 41082 41066 39620 42264 41082 39620 39620 39621 42264 39621 41068 42264 39621 41067 41068 39624 39623 39622 40333 39624 39622 39623 39624 40337 40337 39628 39623 41046 40306 39624 41059 41046 39624 39624 40335 41059 39624 40332 40335 40333 40332 39624 39624 40306 40337 39626 40327 40338 39627 40339 40340 39627 40319 40339 39627 40318 40319 40323 40318 39627 39627 39631 40323 40334 39629 39628 40337 40334 39628 39629 40334 40336 39630 39633 40347 39634 39633 39630 40351 39642 39632 41077 40347 39633 39633 40353 41077 40354 40353 39633 39633 39634 40354 39634 39643 40354 39644 39643 39635 39645 39644 39635 39635 39637 39645 41072 39645 39637 39637 40340 41072 41066 40356 39638 39638 41065 41066 39638 40325 41065 39639 40362 40370 40370 39646 39639 39642 40351 40358 39643 39644 40366 40363 40354 39643 40364 40363 39643 40365 40364 39643 40366 40365 39643 39644 39645 40366 41072 40366 39645 39646 40370 40371 42289 41671 39647 39647 42281 42289 42290 42281 39647 43081 42290 39647 39647 41672 43081 39647 41085 41672 39647 39648 41085 41093 41085 39648 39648 40372 41093 39648 39649 40372 39649 39650 40372 40373 40372 39650 39650 39651 40373 39651 39652 40373 40381 40373 39652 39652 39655 40381 40388 39655 39653 41094 40388 39653 39653 41086 41094 39653 40358 41086 40375 40367 39654 39654 40374 40375 40387 40381 39655 39655 40380 40387 40388 40380 39655 40398 40389 39656 39656 39667 40398 39671 39667 39656 39656 39666 39671 40389 40382 39656 39657 40384 40385 40394 40393 39658 40397 40394 39658 39658 39659 40397 39660 39659 39658 40393 39660 39658 39659 40396 40397 41108 40396 39659 39659 41105 41108 39659 39660 41105 39660 39664 41105 40392 39663 39661 39661 40385 40392 40391 39665 39663 40392 40391 39663 41116 41105 39664 41691 41116 39664 43108 41691 39664 39664 39665 43108 39665 43107 43108 39665 40391 43107 39678 39671 39666 40399 40398 39667 39667 39668 40399 39669 39668 39667 39680 39669 39667 39667 39670 39680 39671 39670 39667 40400 40399 39668 41122 40400 39668 39668 40404 41122 39668 39669 40404 40405 40404 39669 39669 39680 40405 39681 39680 39670 39670 39679 39681 39670 39671 39679 39694 39679 39671 39671 39678 39694 39672 39675 40406 39674 39673 39672 40406 39674 39672 39673 39674 39682 39687 39682 39674 40421 39687 39674 39674 40407 40421 39674 40406 40407 41713 40406 39675 39675 41137 41713 39675 40402 41137 39675 40401 40402 40434 39685 39676 39676 40414 40434 39676 39677 40414 39678 39686 39694 39678 39685 39686 39695 39681 39679 39679 39694 39695 40415 40405 39680 39680 40410 40415 39680 39681 40410 40437 40410 39681 39681 39695 40437 39687 39683 39682 40426 39688 39683 39683 40422 40426 39683 39687 40422 39684 40430 40431 39684 39692 40430 40431 40412 39684 41149 39686 39685 41150 41149 39685 39685 41148 41150 39685 40434 41148 40436 39694 39686 41149 40436 39686 39687 40421 40422 40428 39689 39688 41154 40428 39688 39688 40426 41154 40427 39690 39689 40428 40427 39689 40429 39691 39690 39690 40427 40429 40429 39693 39691 41144 40430 39692 39692 39693 41144 41145 41144 39693 41156 41145 39693 39693 40429 41156 40435 39695 39694 41152 40435 39694 39694 40436 41152 39695 40435 40437 39696 40432 40433 40454 40453 39698 40455 40454 39698 39700 39701 39724 39702 39701 39700 40462 40460 39700 39700 39724 40462 39701 39703 39724 39701 39702 39703 41167 40455 39705 39706 39707 39713 39708 39707 39706 39709 39708 39706 40473 39713 39707 39707 40467 40473 39707 39708 40467 39708 40466 40467 39708 39709 40466 40468 40466 39709 39709 40464 40468 40465 40464 39709 39709 39710 40465 40474 40465 39710 39710 39714 40474 39711 40454 40475 39711 40452 40454 39714 39715 40474 41187 40474 39715 41183 39727 39717 39717 39718 41183 39718 41182 41183 39718 40475 41182 40487 39720 39719 41774 40470 39720 39720 40487 41774 39721 40469 41764 39721 40459 40469 39721 39722 40459 39723 39722 39721 41190 39723 39721 41764 41190 39721 39722 39723 40471 40472 40471 39723 41190 40472 39723 39724 39725 40462 41195 40499 39726 41785 41195 39726 39726 41194 41785 39726 39727 41194 39727 41183 41194 40512 39749 39728 39728 39729 40512 39729 40488 40512 39729 40486 40488 39730 40482 40483 41775 40482 39730 39730 41193 41775 39730 40489 41193 39730 39731 40489 39739 39738 39732 39740 39739 39732 39733 40519 41795 39733 40518 40519 39733 39744 40518 40498 39746 39734 40499 40498 39734 40501 40500 39735 40502 40501 39735 39735 39754 40502 39738 39739 39747 40503 39747 39739 39739 39740 40503 39740 39741 40503 39741 39747 40503 39744 39745 40518 39745 39750 40518 40493 39750 39745 40495 39751 39746 40497 40495 39746 40498 40497 39746 40510 40509 39749 40511 40510 39749 40512 40511 39749 39750 40493 40504 39751 40495 40508 39760 39759 39752 39752 39753 39760 39754 39753 39752 40516 39754 39752 39752 40515 40516 39752 39759 40515 40516 40502 39754 39756 39757 39761 39758 39757 39756 41202 40515 39756 39756 39761 41202 40523 39761 39757 39757 39770 40523 39757 39769 39770 39757 39758 39769 39761 40523 41202 40530 39777 39762 40533 40530 39762 41210 40533 39762 39762 41208 41210 39762 40525 41208 39762 39763 40525 41204 40525 39763 39763 39764 41204 39764 41203 41204 39764 40510 41203 39764 40509 40510 39765 39783 40540 41211 39783 39765 39765 39766 41211 39767 39766 39765 41224 39767 39765 39765 40540 41224 39766 41206 41211 41806 41206 39766 39766 39767 41806 42460 41806 39767 42473 42460 39767 43251 42473 39767 39767 41837 43251 39767 41224 41837 41209 39784 39768 39768 41207 41209 39768 40521 41207 39774 39770 39769 39769 39773 39774 39770 39774 40524 40524 40523 39770 40534 39780 39771 39774 39773 39772 40538 39774 39772 40543 40538 39772 39772 40542 40543 39772 40539 40542 40528 40524 39774 40529 40528 39774 40538 40529 39774 39775 39776 40531 39775 40531 40535 39776 39777 40530 39776 40530 40531 39778 39791 40539 39778 39790 39791 39778 39779 39790 39779 39781 39790 41214 39795 39782 39782 40535 41214 41211 40526 39783 39786 39785 39784 40541 39786 39784 41209 40541 39784 41218 40527 39785 39785 39786 41218 39786 40541 41225 41828 41218 39786 39786 41225 41828 40539 39791 39787 40542 40539 39787 40543 40542 39787 41226 40543 39787 39787 39788 41226 41232 41226 39788 39788 39789 41232 39789 40551 41232 39789 39796 40551 40548 40540 39792 40549 40548 39792 39792 39793 40549 39794 40536 40546 40552 39797 39795 41214 40552 39795 40554 40553 39797 41230 40554 39797 39797 40552 41230 39797 39806 39810 40553 39806 39797 40563 40561 39798 39798 39799 40563 39799 40555 40563 39799 39800 40555 39800 40550 40555 39801 39802 40566 39803 39802 39801 39808 39803 39801 39802 40564 40566 39802 40557 40564 39802 39803 40557 39808 39807 39803 39804 40570 41244 39804 40559 40570 39806 40553 40575 39811 40569 40573 39811 39812 40569 40576 40569 39812 39815 39814 39813 39822 39815 39813 39813 39819 39822 39820 39819 39813 39821 39820 39813 39813 39814 39821 39814 39815 40583 40578 39821 39814 41252 40578 39814 39814 40584 41252 39814 40583 40584 39815 39822 39828 39824 39819 39816 39816 39817 39824 39818 39817 39816 39819 39818 39816 39825 39824 39817 40582 39825 39817 39817 39818 40582 39818 39820 40582 39818 39819 39820 39828 39822 39819 39819 39826 39828 39819 39824 39826 41256 40582 39820 41257 41256 39820 39820 40577 41257 39820 39821 40577 40578 40577 39821 39827 39826 39824 39824 39825 39827 39835 39827 39825 40590 39835 39825 39825 40582 40590 39835 39831 39826 39826 39827 39835 39832 39828 39826 39826 39831 39832 40585 40583 39829 40586 40579 39830 40590 40588 39835 40596 39837 39836 39836 39841 40596 40596 39838 39837 40596 39843 39838 41260 39840 39839 41261 41260 39839 39839 39845 41261 39839 39844 39845 40596 39841 39840 41260 40596 39840 39842 39843 41270 39843 41265 41270 39843 41263 41265 39843 40596 41263 40600 39845 39844 41262 41261 39845 41267 41262 39845 39845 40604 41267 39845 40600 40604 40607 39850 39846 39846 40606 40607 39861 39851 39847 39857 39855 39848 39848 39852 39857 39849 41277 41887 41279 41277 39849 39849 40607 41279 39849 39850 40607 39859 39858 39851 40608 39859 39851 39851 39861 40608 39854 39853 39852 39860 39854 39852 39852 39853 39857 39853 39854 41283 41280 39857 39853 41283 41280 39853 39854 40609 41283 39854 39860 40609 39855 41274 41275 41284 41274 39855 39855 41280 41284 39855 39857 41280 41266 40603 39856 41283 40609 39858 39858 41281 41283 39858 39859 41281 39859 40608 41281 40618 40608 39861 40626 39863 39862 39862 39871 40626 40626 39873 39863 40624 40610 39866 39866 40623 40624 39866 39875 40623 39877 39875 39866 39866 39867 39877 39868 39867 39866 40610 39868 39866 39870 39869 39868 40613 39870 39868 39868 40610 40613 39885 39881 39869 39869 39870 39885 40616 39885 39870 39870 40613 40616 40627 40626 39871 39871 39882 40627 39871 39872 39882 41295 40632 39873 39873 40626 41295 39875 39876 40620 39875 40620 40623 39877 39879 39880 39904 39880 39878 40642 39904 39878 39878 40638 40642 39878 39879 40638 39880 39879 39878 39879 39889 40638 39879 39886 39889 39904 39895 39880 39881 39884 39886 39885 39884 39881 41301 40627 39882 39882 40636 41301 40637 40636 39882 39883 39892 39893 41912 39886 39884 39884 41905 41912 39884 41294 41905 39884 39885 41294 41899 41294 39885 39885 40631 41899 39885 40616 40631 41912 39889 39886 39887 39890 40647 39891 39890 39887 40647 39888 39887 41313 40637 39888 41317 41313 39888 39888 40647 41317 40643 40638 39889 41931 40643 39889 39889 41912 41931 41322 40647 39890 39890 39891 41322 41941 41322 39891 39891 41323 41941 39891 39911 41323 39891 39900 39911 39894 39893 39892 41910 39894 39892 39892 40645 41910 39892 40641 40645 39893 39894 41310 41316 41310 39894 42586 41316 39894 39894 41911 42586 39894 41910 41911 39904 39903 39895 40648 39906 39896 39902 39901 39898 41936 39902 39898 39898 40644 41936 40649 40641 39899 39912 39911 39900 39913 39912 39900 41944 41329 39901 41945 41944 39901 39901 39902 41945 39902 41936 41937 39902 41943 41945 39902 41937 41943 40646 39905 39903 39903 40642 40646 39903 39904 40642 41962 39923 39905 39905 41336 41962 39905 40650 41336 39905 40646 40650 40663 39907 39906 41335 40663 39906 39906 40662 41335 39906 40652 40662 39906 40648 40652 40663 39909 39907 41333 41328 39908 39908 40653 41333 40663 39927 39909 39911 39912 41323 41959 41323 39912 39912 41337 41959 39912 40654 41337 39912 39913 40654 39916 39915 39914 39917 39916 39914 40671 39935 39915 39915 39930 40671 39915 39916 39930 40665 39930 39916 39916 39918 40665 39916 39917 39918 39919 39918 39917 39920 39919 39917 39918 40657 40665 39918 40656 40657 40659 40656 39918 40666 40659 39918 39918 40660 40666 39918 39919 40660 40661 40660 39919 39919 39920 40661 39921 39922 40667 40672 40667 39922 39922 40669 40672 40670 40669 39922 39925 39924 39923 41962 39925 39923 41346 40675 39924 39924 39925 41346 41972 41346 39925 39925 41962 41972 39926 39928 39929 40676 39928 39926 39926 40675 40676 40682 39933 39927 41344 40682 39927 39927 40663 41344 42630 41348 39928 42635 42630 39928 39928 41973 42635 39928 40676 41973 41348 39929 39928 41348 40677 39929 39930 39931 40671 39932 39931 39930 40655 39932 39930 40657 40655 39930 40665 40657 39930 41364 40678 39931 39931 39932 41364 40678 40671 39931 39932 41339 41364 39932 40664 41339 39932 40655 40664 39934 39937 39940 39934 39936 39937 39935 40671 40678 39939 39937 39936 39937 39939 39940 40680 40679 39938 39938 39942 40680 40701 40687 39940 39940 39943 40701 40694 39942 39941 40695 40694 39941 40708 40695 39941 39941 40707 40708 39941 39948 40707 39941 39947 39948 41353 40680 39942 41361 41353 39942 39942 40694 41361 39953 39952 39945 40706 39955 39946 39946 40704 40706 39946 39956 40704 39955 39948 39947 39948 40706 40707 39948 39955 40706 39957 39950 39949 40696 39957 39949 40697 40696 39949 39951 40690 40697 39968 39959 39952 39952 39967 39968 39952 39953 39967 39953 39966 39967 41366 39966 39953 39953 40692 41366 39953 40691 40692 39954 39960 40703 39971 39960 39954 40705 40704 39956 39956 40703 40705 40711 39958 39957 39957 40710 40711 39957 40696 40710 41982 40725 39958 39958 40711 41982 39959 39970 39976 39959 39969 39970 39959 39968 39969 39959 39962 39971 39976 39962 39959 39971 39962 39960 40717 40703 39960 39960 39961 40717 39962 39961 39960 41370 40717 39961 41980 41370 39961 41985 41980 39961 39961 39962 41985 39962 41378 41985 41379 41378 39962 39962 39976 41379 40728 39965 39963 39964 39965 40730 39979 39972 39964 41382 39979 39964 39964 41381 41382 39964 40730 41381 39965 40728 40730 39968 39967 39966 40702 39968 39966 40734 40702 39966 39966 40721 40734 39966 40720 40721 41366 40720 39966 39974 39969 39968 40702 39974 39968 39973 39970 39969 39974 39973 39969 39970 39973 39980 39980 39976 39970 39972 39979 40737 39973 39974 39975 39973 39975 39980 40702 39975 39974 39981 39980 39975 40740 39981 39975 39975 40735 40740 39975 40702 40735 41387 41379 39976 41391 41387 39976 39976 39981 41391 39976 39980 39981 39983 39982 39977 39977 39978 39983 39984 39983 39978 41382 40737 39979 39981 40743 41391 40744 40743 39981 39981 40740 40744 39983 39985 40748 39983 39984 39985 41393 39985 39984 39984 41388 41393 39984 40736 41388 41393 40748 39985 40729 39987 39986 40731 40729 39986 41397 40731 39986 39986 40755 41397 40756 39990 39988 39989 40738 40739 40751 40738 39989 40752 40751 39989 39989 39990 40752 40762 40752 39990 39990 40756 40762 39991 40753 40758 40754 40753 39991 39991 39992 40754 39992 40749 40754 39992 40748 40749 39993 40757 41411 41411 39995 39993 41411 39999 39995 42005 41396 39996 39996 39997 42005 39997 40001 40767 39997 41412 42005 41413 41412 39997 39997 40767 41413 39998 40002 40771 40768 40761 39998 40771 40768 39998 41411 40766 39999 40767 40001 40000 40769 40767 40000 40000 40005 40769 40002 40009 40771 40779 40004 40003 40780 40779 40003 40004 40779 40781 40775 40769 40005 40005 40006 40775 40006 40773 40775 40006 40007 40773 40007 40010 40773 40008 40014 40783 40770 40014 40008 40776 40771 40009 40783 40782 40012 40013 42704 42705 40013 42022 42704 40013 40014 42022 40015 40014 40013 41419 40015 40013 42705 41419 40013 40014 40015 40783 40014 40770 42022 40015 40782 40783 41422 40782 40015 40015 41419 41422 40785 40020 40016 40016 40784 40785 40017 41426 41428 42033 41426 40017 40017 40023 42033 40796 40025 40018 41437 40788 40019 42050 41437 40019 42737 42050 40019 40019 42049 42737 40019 40020 42049 40020 41435 42049 40020 41430 41435 40020 40785 41430 40021 40787 40789 40022 40024 40791 40023 40790 41434 40023 41433 42033 41434 41433 40023 40793 40791 40024 41440 40793 40024 41448 41440 40024 41434 40790 40025 41441 41434 40025 40025 40796 41441 40799 40032 40027 40027 40028 40799 41444 40799 40028 40028 40797 41444 42077 41448 40029 42094 42077 40029 40029 40038 42094 40031 42085 42093 40031 40802 42085 40031 40799 40802 40031 40032 40799 40033 40032 40031 42093 40033 40031 41454 40800 40033 40033 41449 41454 42091 41449 40033 42092 42091 40033 42093 42092 40033 40034 40804 41453 40034 40803 40804 40035 40806 40807 40035 40805 40806 42799 40038 40037 40037 40808 42799 40037 40040 40808 42798 42094 40038 42799 42798 40038 40039 40806 41464 40807 40806 40039 40040 40041 40808 40041 40042 40808 40043 40042 40041 40061 40043 40041 40809 40808 40042 40810 40809 40042 40815 40810 40042 40042 40043 40815 40043 40061 40815 40046 40814 41471 40046 40047 40814 40047 40048 40814 40048 40813 40814 40048 40049 40813 42111 40813 40049 42112 42111 40049 40049 41462 42112 40049 40050 41462 40053 40052 40051 41465 40053 40051 41479 41465 40051 41470 40820 40053 40053 41465 41470 40823 40065 40059 40059 40818 40823 40059 40060 40818 40060 40817 40818 42119 41486 40062 40062 42110 42119 40062 41469 42110 40062 40063 41469 40064 40063 40062 40826 40064 40062 41486 40826 40062 40063 40820 41469 40826 40067 40064 40065 40068 40069 40822 40068 40065 40823 40822 40065 40066 40824 40825 40826 40071 40067 41488 41485 40068 40068 40831 41488 40068 40822 40831 41485 40069 40068 40834 40832 40069 41485 40834 40069 40070 40076 40081 41491 40072 40071 40071 41481 41491 40071 40826 41481 40838 40085 40072 41491 40838 40072 40073 40834 42120 40836 40834 40073 42850 40836 40073 43580 42850 40073 43581 43580 40073 40073 40074 43581 40075 40074 40073 42120 40075 40073 40074 43574 43581 40074 42840 43574 40074 40075 42840 40075 42836 42840 40075 42121 42836 40075 42120 42121 40076 40078 40081 41494 40837 40077 40077 40833 41494 40077 40832 40833 40083 40081 40078 40078 40079 40083 40080 40079 40078 42122 40083 40079 40079 40080 42122 40080 41496 42130 40080 40837 41496 42131 42122 40080 40080 42130 42131 40081 40082 41478 40083 40082 40081 41489 41478 40082 42123 41489 40082 40082 40083 42123 42124 42123 40083 40083 42122 42124 40840 40087 40086 42133 40840 40086 40086 42126 42133 40086 41497 42126 40086 40839 41497 41501 41499 40087 40087 40840 41501 43597 41500 40088 40088 43593 43597 43595 43593 40088 40088 42136 43595 40088 41501 42136 40090 40089 40088 41500 40090 40088 40842 40094 40089 40089 40090 40842 41504 40842 40090 42884 41504 40090 40090 41500 42884 40091 40092 40095 40093 40092 40091 40094 40093 40091 40098 40095 40092 40092 40093 40098 40843 40098 40093 40093 40842 40843 40093 40094 40842 40098 40097 40095 40097 40107 40108 40852 40107 40097 40097 40105 40852 40097 40098 40105 40843 40105 40098 40099 40101 41498 40100 40109 40110 40100 40101 40109 40102 40101 40100 43618 40102 40100 43620 43618 40100 40100 41508 43620 40100 40110 41508 42855 41498 40101 42876 42855 40101 40101 40102 42876 43611 42876 40102 43617 43611 40102 43618 43617 40102 40103 40841 40850 40103 40104 40841 40104 40119 40841 41505 40852 40105 40105 40844 41505 40105 40843 40844 40106 40856 40859 40106 40107 40856 40108 40107 40106 40107 40852 40856 40110 40854 41508 40110 40115 40854 40136 40128 40111 40137 40136 40111 40111 40117 40137 40112 40113 40845 40846 40845 40113 40863 40854 40115 40115 40853 40863 40861 40137 40117 40117 40855 40861 40841 40119 40118 40850 40841 40118 40118 40139 40850 40118 40122 40139 40124 40122 40118 40118 40120 40124 40125 40124 40120 40126 40125 40120 40865 40861 40121 40866 40865 40121 40121 40130 40866 40140 40130 40121 40121 40124 40140 40121 40122 40124 40123 40122 40121 40861 40123 40121 40122 40123 40139 40123 40847 40849 40861 40847 40123 40849 40139 40123 40124 40125 40140 40125 40130 40140 40874 40130 40125 40125 40126 40874 40126 40132 40874 40133 40132 40126 41511 40150 40127 40127 41507 41511 40127 40862 41507 40128 40136 40865 40865 40864 40128 40129 40130 40874 40131 40130 40129 40143 40131 40129 40874 40143 40129 40130 40131 40866 41510 40866 40131 40873 40872 40131 40876 40873 40131 40131 40143 40876 40132 40164 40874 40132 40144 40164 40132 40133 40144 40151 40144 40133 40867 40146 40134 40134 40135 40867 40145 40141 40134 40146 40145 40134 40135 40142 40867 40136 40137 40861 40136 40861 40865 40139 40849 40850 40141 40145 40161 40869 40867 40142 40882 40876 40143 40143 40875 40882 40143 40165 40875 40874 40165 40143 40144 40151 40164 40145 40148 41537 40145 40147 40148 40145 40146 40147 40885 40161 40145 41537 40885 40145 40867 40147 40146 41516 40148 40147 40147 41513 41516 40147 40868 41513 40147 40867 40868 41538 41537 40148 42162 41538 40148 40148 41524 42162 40148 41516 41524 40149 40877 41527 40149 40152 40877 41520 40878 40150 40150 41511 41520 40152 40153 40877 40883 40877 40153 40153 40154 40883 41533 40883 40154 40154 40879 41533 40154 40878 40879 40155 40156 41521 40156 40158 41521 41529 40158 40157 40157 40162 41529 41529 41521 40158 41539 40887 40159 40159 40897 41539 40159 40890 40897 40159 40881 40890 40159 40872 40881 40885 40175 40161 42163 41529 40162 40164 40165 40874 40167 40168 40180 40168 40179 40180 40891 40179 40168 40896 40891 40168 41539 40896 40168 40168 40887 41539 41540 40889 40169 40169 40173 41540 40170 40171 40903 40172 40171 40170 40886 40172 40170 42164 40903 40171 40171 41542 42164 40171 40172 41542 40172 40886 41542 40173 40890 41540 40174 40188 40900 40175 40885 40886 40898 40177 40176 40178 40192 40199 40178 40184 40192 40180 40182 40184 40908 40906 40181 40181 40191 40908 40193 40184 40182 40182 40183 40193 40193 40192 40184 40185 40186 40912 40187 40186 40185 40913 40901 40186 40186 40187 40913 40186 40188 40912 40900 40188 40186 40901 40900 40186 40187 40899 40913 40187 40898 40899 40918 40908 40191 40191 40197 40918 40192 40193 40921 40919 40199 40192 40920 40919 40192 40921 40920 40192 40193 40914 40921 40915 40914 40193 41546 40915 40193 40193 41544 41546 40193 40923 41544 40193 40916 40923 40904 40208 40196 40196 40895 40904 40196 40894 40895 41545 40918 40197 40197 40917 41545 40919 40205 40198 40198 40199 40919 41554 40928 40200 40200 40201 41554 40201 40930 41554 43690 42929 40202 40202 42922 43690 40202 40203 42922 40204 40203 40202 42929 40204 40202 40203 40904 41549 40203 40204 40904 40203 42918 42922 40203 42167 42918 40203 41549 42167 40204 40208 40904 40925 40208 40204 42174 40925 40204 42929 42174 40204 40919 40216 40205 40216 40215 40205 40207 40208 40924 40925 40924 40208 40209 40933 40937 40209 40210 40933 40209 40211 40934 41551 40917 40213 41556 41551 40213 40213 40939 41556 40213 40214 40939 40215 40926 40929 40215 40216 40926 40216 40920 40926 40216 40919 40920 40935 40223 40217 42178 40219 40218 40218 41552 42178 40218 40927 41552 40929 40927 40218 40228 40220 40219 40941 40228 40219 42178 40941 40219 42189 40233 40221 42190 42189 40221 40221 40238 42190 43703 40239 40222 40222 40957 43703 40947 40938 40223 40223 40935 40947 40226 40225 40224 40949 40226 40224 40951 40240 40225 40952 40951 40225 40225 40226 40952 41561 40952 40226 40226 41560 41561 40226 40950 41560 40226 40949 40950 40243 40241 40227 40227 40228 40243 40960 40243 40228 40228 40940 40960 40941 40940 40228 40954 40942 40229 40229 40953 40954 40230 40231 40955 40230 41565 41570 40230 40955 41565 40956 40955 40232 40232 40234 40956 40232 40233 40234 42188 40234 40233 42189 42188 40233 42188 40956 40234 44463 44459 40235 40235 40236 44463 40237 40236 40235 43703 40237 40235 45109 43703 40235 40235 44459 45109 40236 40237 42948 44467 44463 40236 45113 44467 40236 40236 44460 45113 40236 40945 44460 40236 40944 40945 41558 40944 40236 42948 41558 40236 40237 40957 41559 43703 40957 40237 40237 41559 42948 42191 42190 40238 40238 40239 42191 42944 42191 40239 42945 42944 40239 43703 42945 40239 41571 40962 40243 40243 40960 41571 40244 40245 40247 40963 40245 40244 40964 40246 40245 40965 40964 40245 40245 40963 40965 41575 40251 40246 40246 40964 41575 40966 40250 40249 40250 40966 40967 41575 40258 40251 40252 40253 40255 40254 40253 40252 40977 40976 40253 40982 40977 40253 40253 40981 40982 40253 40974 40981 40253 40254 40974 40254 40264 40975 40975 40974 40254 40258 40980 41576 42196 40980 40258 40258 41575 42196 40259 40260 40261 42204 41589 40260 40260 41586 42204 40260 40269 41586 41578 40261 40260 41589 41578 40260 41578 40262 40261 41590 40973 40262 40262 41588 41590 40262 41578 41588 41580 40265 40263 40263 41579 41580 41581 40975 40264 40264 40265 41581 40265 41580 41581 41584 40272 40266 40266 41577 41584 40266 41576 41577 41587 40269 40268 40268 41585 41587 40268 40274 41585 41587 41586 40269 40970 40271 40270 40271 40970 40971 40978 40273 40272 41584 40978 40272 41585 40274 40273 40273 40978 41585 40278 40277 40275 40283 40278 40275 40275 40276 40283 40277 40276 40275 40977 40283 40276 40276 40277 40977 40277 40278 40976 40277 40976 40977 40984 40976 40278 40997 40984 40278 40278 40283 40997 41016 40289 40279 41623 41016 40279 42217 41623 40279 40279 40280 42217 42998 42217 40280 40280 42994 42998 40280 42988 42994 40280 42987 42988 40284 40282 40281 40282 40999 41000 40282 40284 40999 40283 40994 40997 40283 40977 40994 41606 40999 40284 40284 40285 41606 40285 41002 41614 40285 40286 41002 41615 41606 40285 40285 41614 41615 40286 40287 41002 41015 40291 40288 40288 40289 41015 41016 41015 40289 40290 40291 41031 40290 40294 40295 41031 40294 40290 40291 41015 41623 41623 41031 40291 41025 41024 40292 41643 41025 40292 40292 41034 41643 40292 40293 41034 40293 41023 41034 40293 41022 41023 40293 41017 41022 40296 40295 40294 41037 40296 40294 41635 41037 40294 40294 41031 41635 40295 40296 40298 40296 41036 41630 41037 41036 40296 40302 41032 41040 41033 41032 40302 40303 40305 41047 40306 40305 40304 40317 40306 40304 40304 40316 40317 40305 40306 41047 40306 41046 41047 40306 40317 40337 40313 40310 40307 41051 40313 40307 40307 40314 41051 40307 40308 40314 40318 40311 40309 40320 40318 40309 40309 40312 40320 40309 40310 40312 41649 40312 40310 40310 40313 41649 40311 40318 40323 41053 40320 40312 41649 41053 40312 40313 41051 41649 40314 40315 41051 41052 41051 40315 40322 40317 40316 40316 40321 40322 40317 40334 40337 40336 40334 40317 40317 40322 40336 40320 40319 40318 41069 40339 40319 41651 41069 40319 40319 40320 41651 40320 41053 41651 40326 40322 40321 40324 40329 41057 40346 40338 40327 40327 40345 40346 41058 41057 40329 40329 40342 41058 40329 40330 40342 41070 40342 40330 40331 40349 41665 40335 41049 41059 40352 40351 40338 40338 40346 40352 40341 40340 40339 42270 40341 40339 42271 42270 40339 40339 41069 42271 40340 40341 41072 42277 41072 40341 40341 42270 42277 40342 40343 41058 40344 40343 40342 41070 40344 40342 42263 41058 40343 40343 40344 42263 42269 42263 40344 40344 41663 42269 40344 41662 41663 40344 41070 41662 41647 41060 40345 40345 41050 41647 41060 40346 40345 41659 40352 40346 42254 41659 40346 40346 41061 42254 40346 41060 41061 41077 41071 40347 40348 41075 41666 40350 40349 40348 41666 40350 40348 42265 41665 40349 40349 40350 42265 43046 42265 40350 43068 43046 40350 40350 42278 43068 40350 41666 42278 40359 40358 40351 40351 40352 40359 41658 40359 40352 41659 41658 40352 41668 41077 40353 40353 41088 41668 40353 41076 41088 40353 40363 41076 40353 40354 40363 40355 40361 41074 41066 40357 40356 41083 40362 40357 40357 41066 41083 40358 40359 41086 41087 41086 40359 41658 41087 40359 40368 40361 40360 40369 40368 40360 41078 40369 40360 41660 41074 40361 41670 41660 40361 40361 40368 41670 41083 40370 40362 41098 41076 40363 40363 40364 41098 41099 41098 40364 41674 41099 40364 40364 40365 41674 41675 41674 40365 40365 41073 41675 40365 40366 41073 40366 41072 41073 41089 41078 40367 40367 40375 41089 40368 40369 41670 41676 41670 40369 40369 41079 41676 40369 41078 41079 40378 40371 40370 41084 40378 40370 40370 41083 41084 40371 40378 41090 41678 41093 40372 40372 41103 41678 40372 40373 41103 40373 40381 41103 41089 40375 40374 41100 41089 40374 41104 41090 40376 42307 41104 40376 40376 41092 42307 40376 41091 41092 40376 40377 41091 40378 40377 40376 41090 40378 40376 40377 41080 41091 40377 40378 41080 41084 41080 40378 41683 41103 40379 42301 41683 40379 42310 42301 40379 42311 42310 40379 40379 40380 42311 40381 40380 40379 41103 40381 40379 40380 40381 40387 40380 41692 42311 40380 40388 41692 40389 40383 40382 41101 41100 40383 41115 41101 40383 40383 40390 41115 40383 40389 40390 40386 40385 40384 41090 40386 40384 41104 40392 40385 40385 40386 41104 40386 41090 41104 40388 41096 41692 40388 41094 41096 40399 40390 40389 40389 40398 40399 40390 40400 41115 40390 40399 40400 40391 40392 43107 40392 43106 43107 40392 43104 43106 40392 42308 43104 40392 41104 42308 41123 40401 40393 41138 41123 40393 40393 40394 41138 40394 40403 41138 40394 40397 40403 40397 40396 40395 41125 40397 40395 41698 41125 40395 40395 40396 41698 42321 41698 40396 40396 41108 42321 41124 40403 40397 41125 41124 40397 41130 41115 40400 40400 41122 41130 41123 40402 40401 40402 41123 41137 41716 41138 40403 40403 41124 41716 40404 40409 41122 40404 40405 40409 40415 40409 40405 41713 40408 40406 40408 40407 40406 40423 40421 40407 40425 40423 40407 40407 40411 40425 40407 40408 40411 41712 41136 40408 41713 41712 40408 41136 40411 40408 40409 40416 41122 40409 40415 40416 40418 40415 40410 40441 40418 40410 40410 40437 40441 40411 40424 40425 41136 40424 40411 40432 40413 40412 40412 40431 40432 40417 40416 40415 40438 40417 40415 40415 40418 40438 41133 41122 40416 40416 41132 41133 40416 40439 41132 40416 40417 40439 40417 40438 40439 41158 40443 40418 40418 40441 41158 40451 40438 40418 40418 40419 40451 40420 40419 40418 40443 40420 40418 41159 40451 40419 40419 40463 41159 40419 40420 40463 41173 40463 40420 40420 40442 41173 40443 40442 40420 40423 40422 40421 41143 40426 40422 40422 40423 41143 42356 41143 40423 40423 41735 42356 40423 40424 41735 40425 40424 40423 41142 41141 40424 40424 41135 41142 41136 41135 40424 40424 41141 41735 40426 41143 41154 41155 40429 40427 40427 40428 41155 40428 41154 41155 40429 41155 41156 41144 40431 40430 41144 40433 40431 40433 40432 40431 41144 40440 40433 40434 41146 41148 41147 41146 40434 41153 40437 40435 40435 41152 41153 40436 41151 41152 40436 41149 41151 41158 40441 40437 41739 41158 40437 40437 41153 41739 40444 40439 40438 40448 40444 40438 40449 40448 40438 40451 40449 40438 40439 41131 41132 41709 41131 40439 41719 41709 40439 41728 41719 40439 40439 40444 41728 40447 40445 40440 41144 40447 40440 41752 41173 40442 40442 41751 41752 40442 40443 41751 40443 41739 41741 40443 41158 41739 42395 41751 40443 40443 41741 42395 40444 41160 41728 40444 40448 41160 40447 40446 40445 40445 40446 41162 40446 40447 41161 41169 41162 40446 40446 41161 41169 40447 41157 41161 40447 41144 41157 40448 40449 41159 40448 41159 41160 40449 40451 41159 41172 41171 40450 40450 40460 41172 40452 40453 40454 40454 41166 41182 40454 40455 41166 41182 40475 40454 41167 41166 40455 41169 40457 40456 40456 41162 41169 41167 40458 40457 41184 41167 40457 41185 41184 40457 40457 41169 41185 41760 41172 40460 41761 41760 40460 40460 41192 41761 40460 40462 41192 40461 40478 41191 41192 40462 40461 40461 41191 41192 41173 41159 40463 41181 40468 40464 40464 40465 41181 41186 41181 40465 40465 40474 41186 41178 40467 40466 41181 41178 40466 40466 40468 41181 40485 40473 40467 41174 40485 40467 41176 41174 40467 41178 41176 40467 40469 40470 41772 41772 41764 40469 41774 41772 40470 41188 40478 40472 41189 41188 40472 41190 41189 40472 40473 40484 40486 40485 40484 40473 41187 41186 40474 41778 41777 40476 42417 41778 40476 42419 42417 40476 40476 40481 42419 41777 40477 40476 40477 40479 40480 41777 40479 40477 40478 41188 41191 41768 41763 40479 41777 41768 40479 41763 40480 40479 41763 41187 40480 42423 42422 40481 43205 42423 40481 40481 42407 43205 42408 42407 40481 40481 40482 42408 42421 42419 40481 42422 42421 40481 40482 41775 42408 40488 40486 40484 41770 40488 40484 40484 41767 41770 40484 40485 41767 40485 41177 41767 40485 41175 41177 40485 41174 41175 41776 40512 40488 40488 41770 41776 40489 40505 41193 40489 40494 40505 41787 41196 40490 40490 40500 41787 40492 40491 40490 41196 40492 40490 40491 41773 41774 43209 41773 40491 40491 43208 43209 40491 40492 43208 41196 40516 40492 40492 41788 43208 40492 40516 41788 40507 40505 40494 41200 40507 40494 40495 40496 40508 40497 40496 40495 40514 40508 40496 40496 40497 40514 40497 40498 40514 41783 40514 40498 40498 41195 41783 40498 40499 41195 40500 40501 41787 40501 40502 41787 40502 41196 41787 40502 40516 41196 41780 41193 40505 41781 41780 40505 42426 41781 40505 40505 41790 42426 40505 40506 41790 40507 40506 40505 41796 41790 40506 40506 40507 41796 40507 41200 41796 40522 40521 40508 41802 40522 40508 42449 41802 40508 40508 40517 42449 40508 40513 40517 40514 40513 40508 40510 40511 41203 41801 41203 40511 42415 41801 40511 40511 41776 42415 40511 40512 41776 41793 40517 40513 40513 41786 41793 40513 41782 41786 40513 40514 41782 41783 41782 40514 41788 40516 40515 40515 41202 41788 40517 42448 42449 43962 42448 40517 44698 43962 40517 40517 44673 44698 40517 41792 44673 41793 41792 40517 40519 41198 41795 41205 41198 40519 40519 40520 41205 41206 41205 40520 40520 40526 41206 40521 40522 41207 41802 41207 40522 41804 41202 40523 40523 41201 41804 40523 40524 41201 40524 40528 41201 41808 41208 40525 40525 41805 41808 40525 41204 41805 41211 41206 40526 40527 41213 41216 41218 41213 40527 40528 40529 41201 40529 40538 41201 40532 40531 40530 40533 40532 40530 41215 40535 40531 40531 40532 41215 42465 42464 40532 42466 42465 40532 40532 40533 42466 41820 41215 40532 42464 41820 40532 40533 41821 42466 40533 41210 41821 40537 40536 40534 41216 40537 40534 41215 41214 40535 40536 40545 40546 40536 40544 40545 40536 40537 40544 41229 40544 40537 40537 41212 41229 41213 41212 40537 41216 41213 40537 41219 41201 40538 40538 40543 41219 41228 41224 40540 40540 40548 41228 40541 41209 41225 41226 41219 40543 41229 40545 40544 41839 40562 40545 40545 41229 41839 40550 40546 40545 40562 40550 40545 41231 40549 40547 41837 41231 40547 40547 41240 41837 40547 40560 41240 40561 40560 40547 40548 40549 41228 41231 41228 40549 40562 40555 40550 41236 41232 40551 40551 40565 41236 41836 41230 40552 40552 41827 41836 40552 41214 41827 40553 41843 41846 40553 40554 41843 41239 40575 40553 41846 41239 40553 42493 41843 40554 40554 42491 42493 40554 42490 42491 40554 41230 42490 40555 40562 40563 40556 40557 41244 40558 40557 40556 41854 40558 40556 41856 41854 40556 40556 41246 41856 40556 41244 41246 40557 40558 40564 42502 42500 40558 40558 41855 42502 40558 41854 41855 40568 40564 40558 42500 40568 40558 40572 40570 40559 41242 41240 40560 41243 41242 40560 40560 40562 41243 40560 40561 40562 40563 40562 40561 41839 41243 40562 40568 40566 40564 41249 41248 40566 41860 41249 40566 40566 40567 41860 40568 40567 40566 42505 41860 40567 42506 42505 40567 40567 41866 42506 40567 40568 41866 42500 41866 40568 41247 40573 40569 41254 41247 40569 40569 40576 41254 40570 40571 41244 40572 40571 40570 41856 41246 40571 41857 41856 40571 40571 40572 41857 41246 41244 40571 40572 41247 41857 40572 40573 41247 41253 40586 40574 40574 40575 41253 40575 41239 41253 41868 41254 40576 40576 41255 41868 40577 40578 41257 40578 41250 41257 41251 41250 40578 41252 41251 40578 40579 40583 40585 40591 40583 40579 41258 40591 40579 40579 40580 41258 40581 40580 40579 40586 40581 40579 42512 41874 40580 42513 42512 40580 42515 42513 40580 40580 42514 42515 40580 40581 42514 41874 41258 40580 40581 40586 41858 40581 41865 42514 40581 41859 41865 40581 41858 41859 40582 40587 40590 40589 40587 40582 41256 40589 40582 40591 40584 40583 41871 41864 40584 42503 41871 40584 40584 41874 42503 40584 40591 41874 41864 41252 40584 40586 41253 41858 40587 40588 40590 40589 40588 40587 40588 40589 40592 40595 40592 40589 41256 40595 40589 40591 41258 41874 41259 40593 40592 40592 40594 41259 40595 40594 40592 40593 41259 41872 42521 41259 40594 43295 42521 40594 40594 41875 43295 41876 41875 40594 40594 40595 41876 42522 41876 40595 40595 41256 42522 41264 41263 40596 40596 41260 41264 40604 40602 40597 41269 40604 40597 41878 41269 40597 43296 41878 40597 40597 41881 43296 40597 40598 41881 40599 40598 40597 40602 40599 40597 41882 41881 40598 40598 41272 41882 40598 40599 41272 40599 40603 41272 40599 40602 40603 40601 40602 40605 40603 40602 40601 40603 41266 41272 41269 41267 40604 41883 40607 40606 40606 41276 41883 40606 41270 41276 41886 41279 40607 40607 41883 41886 41282 41281 40608 40608 40618 41282 40614 40613 40610 40615 40614 40610 40610 40611 40615 40612 40611 40610 40624 40612 40610 41894 40615 40611 40611 41891 41894 40611 41287 41891 40611 40612 41287 41893 41287 40612 40612 41286 41893 40612 40621 41286 40624 40621 40612 40613 40614 40616 40625 40616 40614 41290 40625 40614 40614 40615 41290 40615 41289 41290 41894 41289 40615 41895 40631 40616 40616 40625 41895 40617 40629 40630 40617 40628 40629 41291 41282 40618 40618 40630 41291 40622 40620 40619 41292 40622 40619 40620 40621 40623 40622 40621 40620 40624 40623 40621 41293 41286 40621 40621 40622 41293 40625 41290 41895 41296 41295 40626 40626 40627 41296 41906 41296 40627 40627 41301 41906 41902 41901 40628 40628 41299 41902 40628 40633 41299 40630 40629 40628 41901 40630 40628 41901 41291 40630 41900 41899 40631 40631 41898 41900 40631 41895 41898 41305 40634 40632 40632 41295 41305 41304 41299 40633 41907 41304 40633 40633 40635 41907 40634 41305 41307 41312 41301 40636 41313 41312 40636 40636 40637 41313 40643 40642 40638 40639 40652 41319 41332 40652 40639 40639 41324 41332 40639 40640 41324 40640 41318 41932 41932 41324 40640 41321 40645 40641 40641 40649 41321 40642 40643 40646 41300 40646 40643 41931 41300 40643 40644 41320 41326 41937 41936 40644 40644 41326 41937 41923 41922 40645 40645 41321 41923 41922 41910 40645 40651 40650 40646 41300 40651 40646 41322 41317 40647 41319 40652 40648 41330 41321 40649 40649 41329 41330 41930 41336 40650 40650 40651 41930 40651 41300 41930 41331 40662 40652 41332 41331 40652 41345 41333 40653 40653 40668 41345 41338 41337 40654 40654 40677 41338 40655 40656 40664 40657 40656 40655 41334 40664 40656 41950 41334 40656 40656 40658 41950 40659 40658 40656 41951 41950 40658 40658 41949 41951 40658 41933 41949 40658 41324 41933 40658 40659 41324 41332 41324 40659 40659 40666 41332 41341 40666 40660 41342 41341 40660 40660 40681 41342 40660 40661 40681 40661 40679 40681 40662 41331 41335 40663 41343 41344 40663 41335 41343 41340 41339 40664 41963 41340 40664 40664 41334 41963 40666 41341 41960 41960 41332 40666 40672 40668 40667 40668 40672 41345 41350 40672 40669 40669 40674 41350 40669 40670 40674 40670 40673 40674 41354 41345 40672 41356 41354 40672 40672 41350 41356 40683 40674 40673 40674 40684 41350 40674 40683 40684 41347 40676 40675 40675 41346 41347 40676 41347 41973 41974 41338 40677 40677 41348 41974 41364 40689 40678 40679 40680 40681 41353 41349 40680 41349 40681 40680 41349 41342 40681 41359 40699 40682 41976 41359 40682 40682 41344 41976 40685 40684 40683 40687 40685 40683 41357 41350 40684 41358 41357 40684 41360 41358 40684 40684 40686 41360 40684 40685 40686 40687 40686 40685 40686 40712 41360 40714 40712 40686 40686 40700 40714 40686 40687 40700 40701 40700 40687 40693 40691 40688 41362 40693 40688 40688 40689 41362 41364 41362 40689 40699 40697 40690 40693 40692 40691 41978 41366 40692 40692 41362 41978 40692 40693 41362 40694 40698 41361 40694 40696 40698 40694 40695 40696 40710 40696 40695 40718 40710 40695 40695 40708 40718 40696 40697 40698 40699 40698 40697 40698 41359 41361 40698 40699 41359 40700 40715 40716 40700 40701 40715 41369 40714 40700 40700 40716 41369 40702 40733 40735 40734 40733 40702 40717 40705 40703 41367 40706 40704 40704 40705 41367 40705 40717 41370 41370 41367 40705 41371 40709 40706 40706 41367 41371 40709 40707 40706 40709 40708 40707 40719 40718 40708 41372 40719 40708 40708 40709 41372 40709 41371 41372 40723 40711 40710 40710 40718 40723 40711 41373 41982 41375 41373 40711 40711 40723 41375 41365 41360 40712 40712 40713 41365 40714 40713 40712 42642 41365 40713 42645 42642 40713 40713 40714 42645 42646 42645 40714 40714 41979 42646 40714 41369 41979 40716 41368 41369 41377 41368 40716 41375 40723 40718 40718 40719 41375 40719 41373 41375 41374 41373 40719 40719 41372 41374 40722 40721 40720 41984 40722 40720 40720 41978 41984 40720 41366 41978 42651 40734 40721 42652 42651 40721 40721 40722 42652 43425 42652 40722 44178 43425 40722 40722 41984 44178 40724 40732 41377 40727 40726 40725 41376 40727 40725 41982 41376 40725 41992 40736 40726 40726 40727 41992 42653 41992 40727 40727 41991 42653 40727 41376 41991 40728 40729 40731 40731 40730 40728 41383 41381 40730 40730 40731 41383 41987 41383 40731 42665 41987 40731 40731 41996 42665 40731 41397 41996 41380 41377 40732 40732 40738 41380 41386 40735 40733 41983 41386 40733 42651 41983 40733 40733 40734 42651 40744 40740 40735 40735 40742 40744 41386 40742 40735 41992 41388 40736 40737 40745 40746 41382 40745 40737 41398 41380 40738 40738 40751 41398 40741 41395 42003 40741 41394 41395 40741 41386 41394 40741 40742 41386 40743 40742 40741 42003 40743 40741 40742 40743 40744 40743 41390 41391 42003 41390 40743 40747 40746 40745 42684 40747 40745 40745 42677 42684 40745 42673 42677 40745 41389 42673 40745 41382 41389 40746 40747 40750 42002 40750 40747 42012 42002 40747 42684 42012 40747 41392 40749 40748 41393 41392 40748 42000 40754 40749 40749 41392 42000 42002 40756 40750 41399 41398 40751 42006 41399 40751 42685 42006 40751 40751 40752 42685 40752 41409 42685 40752 41408 41409 40752 40756 41408 40762 40756 40752 40753 40757 40758 41400 40757 40753 41401 41400 40753 40753 40754 41401 42004 41401 40754 40754 42000 42004 41407 41397 40755 40755 40761 41407 42002 41408 40756 40757 40766 41411 40757 40764 40766 41400 40764 40757 41406 41404 40759 41414 41406 40759 40759 41396 41414 40761 40768 41407 40763 42674 43436 40763 41400 42674 40763 40764 41400 40765 40764 40763 42687 40765 40763 42688 42687 40763 42689 42688 40763 43436 42689 40763 40764 40765 40766 42687 40772 40765 40767 40769 41413 41415 41407 40768 41416 41415 40768 40768 40777 41416 40768 40771 40777 40769 40774 41413 40775 40774 40769 40770 41402 42022 41404 41402 40770 40778 40777 40771 40771 40776 40778 41417 40780 40772 42687 41417 40772 41418 40775 40773 40773 40781 41418 42017 41413 40774 42690 42017 40774 40774 42021 42690 40774 40775 42021 40775 41418 42021 41423 40778 40776 42030 41416 40777 40777 40778 42030 40778 41420 42030 41421 41420 40778 41423 41421 40778 41417 40781 40779 40779 40780 41417 40781 41417 41418 40782 41422 41425 40786 40785 40784 41424 40786 40784 41425 41424 40784 40785 40786 41430 41431 41430 40786 40786 41424 41431 40787 40788 40789 41439 40789 40788 40788 41438 41439 40788 41437 41438 41439 40798 40789 40793 40792 40791 41445 40795 40792 40792 40794 41445 40792 40793 40794 42077 40794 40793 40793 41440 42077 42078 41445 40794 42086 42078 40794 40794 42077 42086 41447 40796 40795 40795 41445 41447 41446 41441 40796 41447 41446 40796 40797 40798 41444 40798 41439 41444 41444 40802 40799 41452 40801 40800 41455 41452 40800 40800 41454 41455 40801 41452 41453 41453 40804 40801 40802 42068 42085 40802 41438 42068 41444 41438 40802 41461 40806 40805 42797 41461 40805 40805 41459 42797 42105 41459 40805 40806 41461 41464 42800 42799 40808 44317 42800 40808 40808 43570 44317 40808 43559 43570 40808 41482 43559 40808 40809 41482 40809 40821 41482 40809 40810 40821 40810 40815 40821 41471 40814 40811 41477 41471 40811 42114 41477 40811 42834 42114 40811 40811 42829 42834 40811 41472 42829 40811 40812 41472 40813 40812 40811 40814 40813 40811 42830 41472 40812 40812 42111 42830 40812 40813 42111 40829 40821 40815 41471 40819 40817 40819 40818 40817 40831 40823 40818 40818 40819 40831 41476 40831 40819 42113 41476 40819 42114 42113 40819 40819 41477 42114 40819 41471 41477 41470 41469 40820 40821 40827 41482 40828 40827 40821 40829 40828 40821 40822 40823 40831 41478 40825 40824 40824 40830 41478 42118 41479 40825 40825 41478 42118 41486 41481 40826 41483 41482 40827 41484 41483 40827 40827 40828 41484 40831 41475 41488 40831 41474 41475 41476 41474 40831 40834 40833 40832 40833 40835 41494 40833 40834 40835 40836 40835 40834 40834 41485 42120 42130 41494 40835 42132 42130 40835 42849 42132 40835 40835 40836 42849 42850 42849 40836 40837 41494 41496 40839 41495 41497 40839 41491 41495 42137 41501 40840 42853 42137 40840 40840 42852 42853 40840 42133 42852 40844 40843 40842 41504 40844 40842 40844 40860 41505 42139 40860 40844 40844 41502 42139 41504 41502 40844 40845 40846 40855 40861 40855 40846 40846 40847 40861 40850 40849 40848 40860 40856 40852 41505 40860 40852 42138 41508 40854 40854 40863 42138 40856 40858 40859 40856 40857 40858 40860 40857 40856 41506 40858 40857 42139 41506 40857 40857 40860 42139 41507 40862 40858 40858 41506 41507 43631 42138 40863 40863 42143 43631 40863 41515 42143 40864 40865 41510 40865 40866 41510 40870 40868 40867 40867 40869 40870 41514 41513 40868 42146 41514 40868 40868 40870 42146 41518 40870 40869 41519 41518 40869 42147 42146 40870 40870 41518 42147 42153 41515 40871 42154 42153 40871 40871 41521 42154 40872 40873 40881 40873 40888 40889 40873 40876 40888 41534 40881 40873 41535 41534 40873 40873 40889 41535 40884 40882 40875 40876 40882 40888 41532 41528 40877 40877 40883 41532 41528 41527 40877 40880 40879 40878 41520 40880 40878 42159 41533 40879 40879 40880 42159 40880 42156 42159 40880 42152 42156 40880 41520 42152 41540 40890 40881 41541 41540 40881 40881 41534 41541 40882 40884 40888 41533 41532 40883 41538 40886 40885 40885 41537 41538 40886 41538 41542 41536 41535 40889 41540 41536 40889 40890 40891 40897 40891 40896 40897 42165 40893 40892 40892 41543 42165 40895 40894 40893 40905 40895 40893 42165 40905 40893 40905 40904 40895 41539 40897 40896 40899 40901 40913 42910 41543 40902 40902 40903 42910 40903 42164 42910 40904 40905 41549 42167 41549 40905 44420 42167 40905 44425 44420 40905 40905 42912 44425 43674 42912 40905 40905 42165 43674 40906 40907 42917 40908 40907 40906 42917 42168 40906 43684 42917 40907 40907 42920 43684 40907 40908 42920 42921 42920 40908 42923 42921 40908 40908 42170 42923 40908 40918 42170 40911 40910 40909 40923 40916 40911 41544 40923 40911 40911 40928 41544 40941 40922 40914 40914 40940 40941 40914 40915 40940 40922 40921 40914 41546 40940 40915 41550 41545 40917 41551 41550 40917 42171 42170 40918 40918 42169 42171 40918 41545 42169 40927 40926 40920 40920 40921 40927 41553 40927 40921 40921 40922 41553 40922 40941 41552 40922 41552 41553 40936 40935 40924 40924 40925 40936 42174 40936 40925 40926 40927 40929 41553 41552 40927 40928 41554 41555 41547 41544 40928 41555 41547 40928 40930 40931 41554 40932 40931 40930 41557 41548 40931 41564 41557 40931 40931 41563 41564 40931 40932 41563 41555 41554 40931 40931 41548 41555 40932 40954 41563 40932 40943 40954 40932 40937 40943 40943 40937 40933 40935 40936 40947 42172 40947 40936 42174 42172 40936 40938 40948 41558 40938 40947 40948 40938 41558 41559 40939 40951 40952 40939 40952 41556 41546 40960 40940 42178 41552 40941 40954 40943 40942 40946 40945 40944 43720 40946 40944 40944 41558 43720 45114 44460 40945 45117 45114 40945 40945 45116 45117 40945 40946 45116 40946 45115 45116 40946 43720 45115 42192 40948 40947 40947 42182 42192 40947 42172 42182 40948 42192 42949 42949 41558 40948 42198 41560 40950 40950 42183 42198 42177 41556 40952 40952 41561 42177 41563 40954 40953 40953 40959 41563 40953 40958 40959 40955 40956 41565 41566 41565 40956 42936 41566 40956 40956 42188 42936 41567 40959 40958 40958 40961 41567 41564 41563 40959 40959 41557 41564 41567 41557 40959 40960 41548 41572 40960 41546 41548 41572 41571 40960 41572 41567 40961 40961 40962 41572 40962 41571 41572 41573 40965 40963 42194 41573 40963 40963 41568 42194 42195 41575 40964 42957 42195 40964 40964 41574 42957 40964 40965 41574 40965 41573 41574 40968 40967 40966 40967 40968 40969 40972 40970 40969 40972 40971 40970 40971 41601 42207 40971 41582 41601 40971 40972 41582 41583 41582 40972 40972 40987 41583 41591 41579 40973 40973 41590 41591 40974 40975 40981 41581 40991 40975 40991 40981 40975 40984 40983 40976 40977 40986 40994 40977 40982 40986 40978 40979 41585 40980 40979 40978 41584 40980 40978 42203 41585 40979 42974 42203 40979 40979 42201 42974 40979 40980 42201 41577 41576 40980 41584 41577 40980 42202 42201 40980 40980 42200 42202 40980 42196 42200 40991 40982 40981 40993 40986 40982 40982 40992 40993 40982 40991 40992 40998 40988 40983 40983 40984 40998 40988 40987 40983 40984 40989 40998 40990 40989 40984 40997 40990 40984 42971 42969 40985 40985 41596 42971 40985 41595 41596 40996 40994 40986 41001 40996 40986 40986 40993 41001 40987 40988 41583 40988 40998 41583 41604 40998 40989 40989 40990 41604 41612 41604 40990 40990 40995 41612 40997 40995 40990 41594 41593 40991 40991 41581 41594 41593 40992 40991 41001 40993 40992 41609 41001 40992 40992 41593 41609 40994 40995 40997 40996 40995 40994 40995 40996 41612 42991 41612 40996 44487 42991 40996 40996 41611 44487 40996 41610 41611 40996 41001 41610 41600 41583 40998 41604 41600 40998 41602 41000 40999 41607 41602 40999 40999 41606 41607 41602 41595 41000 41001 41609 41610 41003 41004 41620 41619 41010 41003 41620 41619 41003 41004 41008 41622 41004 41007 41008 41622 41620 41004 41005 41006 41007 41014 41006 41005 41008 41007 41006 41013 41008 41006 41028 41013 41006 41006 41014 41028 41008 41013 41621 41008 41621 41622 41011 41010 41009 41021 41011 41009 41625 41021 41009 42228 41625 41009 41009 42222 42228 41009 41619 42222 41009 41010 41619 41010 41011 41012 41017 41012 41011 41018 41017 41011 41021 41018 41011 41013 41028 41030 41013 41030 41621 41029 41028 41014 41015 41016 41623 41017 41018 41022 41634 41022 41018 41018 41633 41634 41018 41631 41633 41018 41626 41631 41018 41021 41626 41624 41618 41019 41019 41020 41624 41020 42234 42242 41020 41632 42234 42232 41624 41020 42233 42232 41020 42243 42233 41020 41020 42242 42243 41021 41625 41626 41634 41023 41022 41643 41034 41023 42238 41643 41023 41023 42236 42238 41023 41634 42236 41024 41025 41027 41646 41027 41025 42245 41646 41025 41025 41643 42245 42248 41048 41026 41026 41646 42248 41026 41027 41646 41028 41029 41030 42231 41030 41029 41029 41639 42231 41640 41639 41029 41029 41630 41640 42230 41621 41030 41030 42229 42230 42231 42229 41030 41636 41635 41031 41031 41623 41636 41032 41039 41040 41032 41033 41039 41641 41039 41033 41033 41041 41641 41033 41038 41041 41635 41630 41036 41036 41037 41635 41641 41040 41039 42242 42234 41040 43014 42242 41040 41040 41642 43014 41040 41641 41642 42244 41641 41041 41042 41044 41045 41042 41046 41049 41047 41046 41042 41042 41045 41047 41047 41044 41043 41047 41045 41044 41059 41049 41046 42248 41645 41048 41048 41644 41647 41645 41644 41048 41051 41052 41649 41052 41055 41649 41052 41054 41055 42252 41651 41053 41053 42250 42252 41053 41649 42250 42251 41649 41055 42259 42251 41055 42261 42259 41055 41055 41656 42261 41056 41064 41652 41056 41652 41656 41057 41058 42263 42262 41653 41057 42263 42262 41057 41647 41061 41060 41061 41647 42254 41654 41063 41062 41654 41650 41063 41653 41652 41064 41066 41082 41083 41067 42265 43056 43056 41068 41067 43054 42264 41068 43055 43054 41068 43817 43055 41068 41068 43043 43817 43056 43043 41068 41069 41651 42271 41070 41074 41662 41071 41077 41657 41669 41073 41072 42277 41669 41072 42294 41675 41073 41073 42284 42294 41073 41669 42284 41074 41661 41662 41074 41660 41661 41667 41666 41075 41097 41088 41076 41098 41097 41076 41673 41657 41077 41077 41668 41673 41101 41079 41078 41078 41089 41101 41079 41102 41676 41079 41101 41102 41083 41082 41080 41084 41083 41080 42287 41091 41080 41080 42286 42287 41080 41081 42286 41082 41081 41080 43084 42286 41081 41081 43054 43084 41081 42264 43054 41081 41082 42264 41085 41093 41672 41095 41094 41086 41086 41087 41095 42291 41095 41087 41087 41658 42291 41088 41097 41680 41680 41668 41088 41089 41100 41101 42295 41092 41091 41091 42287 42295 43097 42307 41092 41092 43096 43097 41092 42295 43096 41678 41672 41093 41094 41095 41096 43090 41096 41095 41095 42291 43090 42312 41692 41096 43090 42312 41096 41097 41679 41680 41097 41114 41679 41097 41098 41114 41684 41114 41098 41098 41099 41684 41693 41684 41099 41099 41674 41693 41115 41102 41101 41690 41676 41102 41694 41690 41102 41102 41115 41694 41683 41678 41103 41104 42307 42308 41116 41108 41105 43109 42321 41106 41106 41107 43109 41108 41107 41106 42321 41108 41106 41107 41691 43109 41107 41116 41691 41107 41108 41116 41111 41110 41109 41117 41111 41109 41109 41113 41117 41109 41112 41113 41109 41110 41112 41110 41695 41705 41110 41111 41695 41114 41112 41110 41679 41114 41110 41705 41679 41110 41704 41695 41111 41111 41126 41704 41111 41118 41126 41111 41117 41118 41114 41113 41112 41120 41117 41113 41684 41120 41113 41113 41114 41684 41115 41130 41694 41119 41118 41117 41120 41119 41117 41139 41126 41118 41118 41121 41139 41118 41119 41121 41119 41120 41121 41129 41121 41120 41685 41129 41120 41686 41685 41120 41687 41686 41120 41120 41684 41687 41121 41129 41139 41133 41130 41122 43141 41137 41123 41123 43140 43141 41123 41138 43140 41124 41125 41702 41717 41716 41124 42346 41717 41124 41124 42340 42346 41124 41703 42340 41124 41702 41703 41125 41698 41702 41725 41704 41126 41126 41140 41725 41126 41139 41140 41139 41129 41127 41706 41139 41127 43142 41706 41127 41127 43131 43142 41127 41707 43131 41127 41128 41707 41129 41128 41127 41708 41707 41128 41128 41696 41708 41128 41685 41696 41128 41129 41685 41130 41690 41694 41130 41133 41690 41709 41134 41131 41133 41132 41131 41134 41133 41131 41701 41690 41133 41133 41134 41701 42329 41701 41134 41134 41711 42329 41134 41710 41711 41134 41709 41710 41723 41142 41135 42336 41723 41135 42337 42336 41135 41135 41712 42337 41135 41136 41712 42345 42344 41137 43141 42345 41137 42338 41713 41137 43128 42338 41137 41137 42344 43128 41138 41716 43140 41727 41140 41139 41139 41706 41727 41140 41724 41725 42351 41724 41140 41140 41727 42351 41141 41721 41734 41141 41142 41721 41736 41735 41141 41141 41734 41736 41142 41720 41721 41723 41720 41142 42358 41154 41143 42359 42358 41143 41143 42356 42359 41144 41145 41157 41161 41157 41145 41168 41161 41145 41145 41156 41168 42365 41148 41146 41146 41163 42365 41164 41163 41146 42383 41164 41146 41146 41747 42383 41146 41147 41747 41147 41171 41747 42355 41150 41148 42365 42355 41148 41737 41151 41149 41149 41150 41737 42354 41737 41150 42355 42354 41150 41740 41152 41151 43159 41740 41151 41151 42366 43159 41151 41737 42366 41740 41153 41152 41740 41739 41153 42362 41155 41154 43158 42362 41154 41154 42361 43158 41154 42358 42361 42363 41156 41155 41155 42362 42363 42364 41168 41156 41156 42363 42364 41165 41160 41159 41745 41165 41159 41159 41173 41745 41744 41728 41160 42369 41744 41160 41160 41165 42369 41161 41168 41169 43164 42365 41163 41163 41164 43164 41164 42383 43164 43168 42369 41165 41165 42385 43168 41165 41745 42385 41166 41167 41182 41184 41182 41167 41170 41169 41168 42376 41170 41168 43163 42376 41168 41168 42364 43163 43171 41185 41169 41169 41170 43171 43892 43171 41170 41170 42376 43892 41748 41747 41171 41171 41172 41748 41760 41748 41172 41752 41745 41173 41176 41175 41174 41179 41177 41175 41175 41176 41179 41176 41178 41179 42399 41767 41177 41177 41757 42399 41177 41179 41757 41180 41179 41178 41758 41180 41178 41178 41181 41758 42386 41757 41179 41179 41180 42386 42387 42386 41180 43175 42387 41180 41180 42384 43175 41180 41758 42384 41759 41758 41181 41762 41759 41181 41181 41186 41762 41184 41183 41182 42414 41194 41183 43922 42414 41183 41183 43183 43922 41183 41746 43183 41183 41184 41746 41184 41185 41746 43172 41746 41185 41185 43171 43172 41763 41762 41186 41186 41187 41763 42391 41769 41188 41188 42390 42391 41188 42389 42390 41188 41189 42389 41769 41191 41188 41189 41190 42389 41190 41764 42389 41769 41192 41191 41769 41761 41192 41779 41775 41193 41780 41779 41193 41194 41784 41785 42412 41784 41194 42414 42412 41194 41784 41783 41195 41785 41784 41195 41197 41798 43233 41197 41198 41798 43235 43234 41197 41197 43233 43235 41198 41205 41798 41799 41200 41199 42440 41799 41199 42441 42440 41199 43236 42441 41199 41797 41796 41200 41799 41797 41200 43230 41804 41201 41201 41809 43230 41810 41809 41201 41201 41219 41810 41804 41794 41202 41794 41788 41202 41800 41204 41203 41801 41800 41203 41204 41800 41805 41806 41798 41205 41205 41206 41806 41803 41209 41207 41207 41802 41803 41822 41210 41208 41208 41808 41822 41807 41225 41209 41209 41803 41807 41822 41821 41210 41212 41217 41229 41218 41217 41212 41212 41213 41218 41214 41819 41827 41214 41215 41819 41820 41819 41215 41838 41229 41217 41217 41823 41838 41217 41218 41823 43255 41823 41218 41218 43254 43255 41218 41828 43254 41219 41226 41810 41227 41223 41220 41220 41221 41227 41222 41221 41220 41223 41222 41220 41832 41227 41221 41221 41812 41832 41814 41812 41221 41221 41222 41814 41222 41223 41814 41824 41814 41223 41223 41227 41824 41224 41231 41837 41224 41228 41231 42461 41828 41225 41225 41807 42461 43259 43256 41226 41226 41845 43259 41226 41844 41845 41226 41232 41844 43256 41810 41226 41832 41824 41227 41229 41838 41839 41230 42479 42490 41230 41836 42479 41851 41844 41232 41232 41236 41851 41235 41234 41233 44017 41235 41233 44743 44017 41233 41233 43278 44743 41233 43268 43278 41233 42494 43268 42498 42494 41233 41233 41234 42498 41234 41235 41847 41234 41238 42498 41234 41237 41238 41847 41237 41234 41865 41847 41235 42518 41865 41235 44017 42518 41235 41236 41245 41851 41858 41253 41237 41859 41858 41237 41237 41847 41859 41239 41238 41237 41253 41239 41237 41238 41239 41846 41238 41846 42498 43279 42495 41240 41240 41241 43279 41242 41241 41240 42480 41837 41240 42496 42480 41240 41240 42495 42496 43285 43279 41241 41241 41848 43285 41241 41242 41848 41242 41243 41848 41243 41839 41848 41245 41248 41851 41862 41857 41247 41247 41254 41862 41248 41249 41851 41249 41860 42505 41861 41851 41249 42505 41861 41249 41863 41257 41250 41250 41251 41863 41864 41863 41251 41251 41252 41864 41869 41862 41254 41254 41868 41869 41872 41868 41255 41256 42520 42522 41256 42508 42520 41256 41257 42508 41257 41870 42508 41257 41863 41870 42521 41872 41259 42527 41264 41260 42528 42527 41260 41260 41261 42528 41261 41262 42528 41262 42525 42528 42526 42525 41262 43299 42526 41262 41262 41879 43299 41262 41878 41879 41262 41877 41878 41262 41267 41877 41268 41265 41263 41263 41264 41268 42527 41268 41264 41271 41270 41265 41265 41268 41271 41273 41272 41266 41267 41269 41877 42533 41271 41268 41268 42527 42533 41878 41877 41269 41270 41271 41276 42529 41276 41271 42533 42529 41271 42532 41882 41272 41272 41273 42532 42537 42532 41273 41273 41884 42537 41273 41274 41884 41275 41274 41273 41274 41284 41884 42529 41883 41276 41888 41887 41277 42544 41888 41277 41277 41278 42544 41279 41278 41277 41278 41279 42534 43305 42544 41278 41278 42534 43305 41279 41886 42534 41285 41284 41280 41280 41281 41285 41283 41281 41280 41889 41285 41281 41281 41282 41889 41282 41885 41889 42545 41885 41282 42547 42545 41282 41282 41897 42547 41282 41291 41897 41284 41285 41885 41885 41884 41284 41889 41885 41285 41286 41293 41893 41287 41890 41891 41893 41890 41287 41895 41290 41288 42570 41895 41288 41288 41289 42570 41290 41289 41288 41289 41894 42570 41291 41896 41897 42571 41896 41291 41291 41901 42571 41293 41890 41893 41293 41887 41890 41294 41899 41905 41295 41297 41305 41298 41297 41295 41295 41296 41298 41906 41298 41296 41297 41298 42573 42585 41305 41297 41297 42573 42585 41298 41906 42573 41299 41304 41902 41300 41929 41930 42608 41929 41300 41300 42600 42608 41300 41931 42600 41301 41311 41906 41312 41311 41301 44065 43338 41302 44066 44065 41302 41302 41303 44066 41304 41303 41302 43338 41304 41302 41303 41908 44066 41303 41304 41908 41304 41907 41908 42572 41902 41304 43338 42572 41304 41309 41307 41305 42585 41309 41305 41306 41307 41309 41308 41307 41306 41934 41308 41306 41942 41934 41306 42576 41942 41306 42585 42576 41306 41306 41309 42585 41307 41308 41318 41933 41318 41308 41934 41933 41308 41310 41314 41909 41316 41314 41310 42575 41906 41311 43355 42575 41311 41311 41915 43355 41311 41312 41915 41312 41322 41915 41312 41317 41322 41312 41313 41317 41314 41315 41909 41316 41315 41314 42579 41909 41315 44076 42579 41315 41315 41316 44076 41316 43358 44076 41316 42586 43358 41933 41932 41318 41935 41326 41320 41321 41330 41923 41941 41915 41322 41958 41941 41323 41959 41958 41323 41324 41932 41933 41325 41328 41333 41935 41328 41325 41325 41326 41935 41327 41326 41325 41333 41327 41325 42609 41937 41326 41326 42604 42609 42606 42604 41326 41326 41327 42606 44103 42606 41327 41327 41970 44103 41327 41969 41970 41327 41333 41969 41938 41330 41329 41946 41938 41329 41329 41944 41946 41938 41923 41330 41341 41335 41331 41960 41341 41331 41331 41332 41960 41333 41345 41969 41334 41950 41963 41335 41342 41343 41335 41341 41342 41965 41962 41336 41336 41930 41965 41337 41338 41974 42623 41959 41337 41337 41967 42623 41968 41967 41337 41974 41968 41337 41339 41351 41364 41339 41340 41351 41977 41351 41340 42627 41977 41340 42628 42627 41340 41340 41963 42628 41349 41343 41342 41352 41344 41343 41343 41349 41352 41344 41352 41976 41345 41354 41969 41973 41347 41346 41346 41972 41973 42631 41974 41348 41348 42630 42631 41353 41352 41349 41357 41356 41350 41351 41362 41364 41363 41362 41351 41977 41363 41351 41361 41359 41352 41352 41353 41361 41352 41359 41976 41975 41969 41354 41354 41355 41975 41356 41355 41354 41355 41357 42636 41355 41356 41357 42634 41975 41355 42636 42634 41355 41357 41365 42637 41357 41358 41365 42637 42636 41357 41358 41360 41365 41984 41978 41362 42643 41984 41362 41362 42641 42643 41362 41363 42641 41363 42638 42641 41363 42632 42638 42633 42632 41363 41363 41977 42633 42642 42640 41365 42640 42637 41365 41981 41371 41367 41367 41370 41981 41368 41384 41979 41385 41384 41368 41398 41385 41368 41368 41380 41398 41368 41377 41380 41979 41369 41368 41370 41980 41981 42648 41372 41371 42650 42648 41371 41371 42647 42650 41371 41981 42647 41372 42648 44174 44174 41374 41372 41373 43413 43414 44175 43413 41373 41373 41374 44175 43415 41982 41373 41373 43414 43415 44853 44175 41374 44863 44853 41374 41374 44189 44863 41374 44174 44189 41376 41982 41991 41378 41995 41999 41378 41379 41995 41986 41985 41378 42663 41986 41378 41378 41999 42663 41379 41387 41995 41389 41382 41381 42666 41389 41381 41381 41987 42666 41381 41383 41987 41384 43420 43421 43423 43420 41384 41384 42656 43423 41384 41385 42656 43421 41979 41384 43426 42656 41385 41385 41399 43426 41385 41398 41399 41990 41394 41386 41386 41983 41990 41387 41391 41995 41992 41393 41388 41389 42666 42673 41998 41391 41390 42667 41998 41390 41390 42003 42667 41998 41995 41391 41392 41393 42000 42001 42000 41393 41393 41992 42001 42662 42007 41394 41394 42015 42662 41394 42008 42015 41394 41990 42008 42007 41395 41394 42680 42003 41395 41395 42010 42680 42011 42010 41395 41395 42009 42011 41395 42007 42009 42005 41414 41396 41997 41996 41397 42023 41997 41397 41397 41407 42023 44193 43426 41399 41399 43431 44193 41399 42006 43431 41400 41401 42674 42675 42674 41401 41401 42004 42675 42704 42022 41402 42705 42704 41402 41402 41403 42705 41404 41403 41402 42711 42705 41403 43439 42711 41403 41403 41405 43439 41403 41404 41405 41406 41405 41404 41405 41406 41414 41405 42683 43439 41405 41414 42683 41407 41415 42023 41410 41409 41408 42013 41410 41408 42018 42013 41408 41408 42012 42018 41408 42002 42012 43431 42685 41409 41409 41410 43431 43446 43431 41410 41410 42026 43446 41410 42014 42026 41410 42013 42014 42681 42005 41412 41412 42017 42681 41412 41413 42017 41414 42682 42683 41414 42005 42682 42031 42023 41415 41415 41416 42031 41416 42030 42031 42028 41418 41417 41417 42027 42028 42687 42027 41417 42028 42021 41418 43467 41422 41419 41419 42718 43467 42719 42718 41419 41419 42711 42719 41419 42705 42711 42731 42030 41420 41420 42729 42731 42730 42729 41420 41420 42032 42730 41420 41421 42032 41421 41426 41427 41428 41426 41421 41421 41423 41428 41421 41427 42032 41429 41424 41422 43467 41429 41422 41422 41424 41425 41424 41429 41432 41432 41431 41424 42033 41427 41426 42033 41433 41427 42735 42032 41427 41427 41433 42735 43465 41432 41429 43467 43465 41429 41430 41431 41435 41436 41435 41431 42734 41436 41431 41431 41432 42734 41432 43465 43496 42744 42734 41432 43496 42744 41432 41433 42062 42735 41433 41434 42062 41434 41443 42062 41434 41442 41443 41434 41441 41442 41435 42048 42049 41435 41436 42048 42734 42048 41436 42052 41438 41437 41437 42051 42052 41437 42050 42051 41444 41439 41438 41438 42052 42068 41440 41448 42077 41446 41442 41441 42066 41443 41442 42069 42066 41442 41442 41446 42069 41443 42066 42070 43511 42062 41443 41443 42750 43511 41443 42070 42750 42078 41447 41445 42079 42069 41446 41446 41447 42079 41447 42078 42079 41455 41454 41449 41449 41450 41455 41451 41450 41449 42084 41451 41449 42091 42084 41449 41450 41452 41455 41453 41452 41450 41456 41453 41450 41450 41451 41456 41457 41456 41451 42774 41457 41451 42793 42774 41451 43521 42793 41451 41451 42084 43521 41453 41456 42101 42789 42102 41456 41456 41457 42789 42102 42101 41456 41457 42774 42789 41458 41459 42105 41460 41459 41458 42102 41460 41458 42104 42102 41458 42105 42104 41458 42802 42797 41459 41459 42794 42802 41459 41460 42794 44302 42794 41460 41460 42793 44302 41460 42789 42793 41460 42102 42789 41461 41462 41464 41463 41462 41461 43552 41463 41461 41461 42802 43552 41461 42797 42802 41462 41463 42112 42813 42112 41463 43551 42813 41463 43552 43551 41463 42109 41470 41465 41465 41468 42109 41479 41468 41465 42110 42109 41466 42816 42110 41466 41466 42815 42816 41466 41467 42815 41468 41467 41466 42109 41468 41466 41467 42108 42815 42835 42108 41467 41467 41480 42835 41467 41468 41480 41468 41479 41480 41469 42109 42110 41469 41470 42109 43560 42829 41472 41472 42830 43560 42121 41475 41473 42826 42121 41473 42827 42826 41473 41473 41474 42827 41475 41474 41473 42828 42827 41474 41474 41476 42828 42120 41485 41475 42121 42120 41475 41475 41485 41488 43557 42828 41476 41476 43556 43557 41476 42113 43556 41478 41490 42118 41478 41489 41490 42118 41480 41479 41480 42116 42835 42118 42116 41480 42127 41491 41481 42837 42127 41481 41481 41486 42837 41482 41483 43559 45008 43559 41483 41483 41487 45008 41483 41484 41487 42128 41487 41484 41484 41492 42128 41493 41492 41484 41486 42119 42837 45691 45008 41487 41487 42848 45691 41487 42129 42848 41487 42128 42129 42115 41490 41489 42125 42115 41489 41489 42123 42125 41490 42115 42118 42126 41495 41491 42127 42126 41491 42134 42128 41492 41492 41498 42134 41492 41493 41498 42130 41496 41494 42126 41497 41495 42135 42134 41498 42856 42135 41498 41498 42854 42856 42855 42854 41498 43598 42884 41500 41500 42875 43598 43597 42875 41500 42137 42136 41501 42886 42139 41502 42887 42886 41502 41502 42885 42887 41502 41503 42885 41504 41503 41502 43623 42885 41503 41503 43610 43623 41503 42884 43610 41503 41504 42884 41509 41507 41506 42139 41509 41506 41512 41511 41507 41507 41509 41512 43627 43620 41508 43628 43627 41508 41508 42138 43628 42141 41512 41509 42142 42141 41509 41509 42140 42142 41509 42139 42140 42152 41520 41511 41511 42151 42152 41511 41512 42151 41512 42141 42151 42144 41523 41513 42149 42144 41513 41513 42148 42149 41513 41514 42148 41517 41516 41513 41523 41517 41513 42892 42148 41514 41514 42891 42892 42893 42891 41514 41514 42146 42893 42153 42143 41515 41516 41517 41524 41517 41522 41524 41523 41522 41517 41518 41519 42147 42150 42147 41519 41519 41526 42150 41527 41526 41519 41521 41530 42154 41521 41529 41530 41522 42145 42155 41522 42144 42145 41522 41523 42144 41525 41524 41522 42155 41525 41522 41524 41525 42162 42902 42162 41525 43651 42902 41525 41525 43649 43651 41525 42155 43649 42897 42150 41526 42900 42897 41526 41526 42157 42900 41526 41527 42157 42158 42157 41527 41527 41528 42158 41528 41532 41533 42159 42158 41528 41528 41533 42159 41531 41530 41529 42163 41531 41529 42899 42154 41530 43648 42899 41530 41530 41531 43648 43661 43648 41531 41531 42909 43661 41531 42163 42909 42161 41541 41534 41534 41535 42161 41535 41536 42161 41536 41541 42161 41536 41540 41541 42904 41542 41538 41538 42162 42904 43663 42164 41542 41542 42904 43663 42166 42165 41543 42910 42166 41543 41547 41546 41544 41545 41550 42169 41546 41547 41548 41555 41548 41547 41548 41567 41572 41548 41557 41567 42176 42169 41550 41550 41551 42176 41551 42175 42176 41551 41556 42175 42177 42175 41556 41558 42949 43720 42948 41559 41558 41562 41561 41560 42184 41562 41560 42199 42184 41560 41560 42198 42199 42179 42177 41561 42185 42179 41561 41561 41562 42185 42931 42185 41562 42933 42931 41562 41562 42184 42933 42187 41570 41565 41565 42180 42187 42181 42180 41565 41565 41566 42181 42937 42181 41566 41566 42936 42937 41568 42193 42947 41568 41569 42193 42951 42194 41568 41568 42947 42951 41569 41570 42193 41570 42186 42193 42187 42186 41570 42950 41574 41573 41573 42194 42950 41574 42950 42957 41575 42195 42196 41589 41588 41578 41594 41580 41579 41579 41592 41594 41579 41591 41592 41594 41581 41580 41582 41583 41601 41583 41600 41601 42203 41587 41585 41586 42203 42982 41586 41587 42203 42981 42204 41586 42982 42981 41586 42208 41590 41588 42985 42208 41588 41588 41597 42985 41598 41597 41588 41588 41589 41598 41589 42204 42981 42983 41598 41589 41589 42981 42983 41599 41591 41590 42208 41599 41590 41599 41592 41591 41608 41594 41592 41592 41599 41608 42210 41609 41593 41593 41594 42210 41594 41608 42210 41603 41596 41595 41595 41602 41603 41596 41603 42977 42973 42971 41596 42977 42973 41596 45142 42985 41597 45827 45142 41597 41597 43750 45827 41597 41598 43750 41598 42983 43750 42209 41608 41599 43751 42209 41599 41599 42989 43751 41599 42208 42989 42211 41601 41600 41600 41605 42211 41600 41604 41605 42211 42207 41601 42979 41603 41602 41602 41607 42979 42979 42978 41603 42978 42977 41603 41613 41605 41604 41604 41612 41613 41605 41613 42212 42986 42211 41605 42993 42986 41605 41605 42992 42993 41605 42212 42992 41617 41607 41606 41606 41615 41617 42980 42979 41607 41607 41617 42980 41608 42209 42210 42210 41610 41609 45144 41611 41610 41610 44490 45144 41610 44486 44490 41610 43751 44486 41610 42210 43751 45145 44487 41611 45829 45145 41611 41611 45828 45829 41611 45144 45828 42212 41613 41612 42992 42212 41612 41612 42991 42992 41616 41615 41614 41618 41616 41614 42213 41617 41615 43748 42213 41615 41615 42219 43748 41615 42216 42219 41615 41616 42216 41616 41618 42216 41617 42214 42980 41617 42213 42214 41618 41624 42999 42221 42216 41618 42999 42221 41618 42228 42222 41619 43003 42228 41619 41619 41620 43003 41620 41622 43003 41629 41622 41621 42230 41629 41621 41622 41629 43003 42227 41636 41623 41623 42226 42227 41623 42217 42226 41624 42232 42999 41631 41626 41625 41625 41628 41631 41625 41627 41628 42228 41627 41625 43768 41628 41627 41627 43767 43768 44513 43767 41627 41627 43004 44513 41627 42228 43004 41633 41631 41628 43008 41633 41628 43011 43008 41628 43768 43011 41628 43005 43003 41629 41629 42224 43005 42230 42224 41629 41630 41635 42240 42241 41640 41630 41630 42240 42241 43008 42235 41633 42235 41634 41633 41634 42235 42236 41635 41636 42240 41638 41637 41636 42227 41638 41636 41636 41637 42240 41637 41638 43774 42241 42240 41637 43012 42241 41637 43774 43012 41637 41638 42227 43774 43776 42231 41639 43786 43776 41639 41639 43785 43786 43787 43785 41639 41639 43021 43787 41639 41640 43021 41640 42241 43021 43790 41642 41641 41641 42244 43790 43789 43014 41642 43790 43789 41642 41643 42238 42245 42254 41647 41644 41644 42253 42254 41644 41645 42253 43036 42253 41645 41645 42248 43036 43032 42248 41646 41646 42245 43032 43034 42247 41648 41648 42249 43034 42251 42250 41649 43037 42249 41650 43052 43037 41650 41650 41657 43052 41650 41654 41657 41651 42256 42271 41651 42252 42256 41652 41653 42262 41652 41655 41656 42262 41655 41652 43066 43063 41655 41655 42262 43066 43063 41656 41655 43062 42261 41656 43100 43062 41656 41656 43063 43100 43053 43052 41657 43822 43053 41657 41657 43051 43822 41657 41673 43051 41658 41659 42257 41658 42257 42291 42258 42257 41659 41659 42254 42258 42285 41661 41660 41660 41677 42285 41660 41670 41677 41663 41662 41661 41664 41663 41661 42285 41664 41661 42272 42269 41663 41663 41664 42272 43067 42272 41664 43080 43067 41664 41664 42285 43080 42280 42278 41666 41666 41667 42280 41667 41671 42280 42302 41673 41668 42303 42302 41668 41668 41680 42303 43082 42284 41669 43083 43082 41669 41669 42277 43083 41682 41677 41670 41670 41681 41682 41670 41676 41681 41671 42279 42280 42289 42279 41671 43087 43081 41672 41672 42296 43087 41672 41678 42296 43841 43051 41673 41673 43838 43841 41673 43837 43838 41673 42302 43837 42292 41693 41674 42293 42292 41674 42294 42293 41674 41674 41675 42294 41690 41681 41676 42306 42285 41677 42319 42306 41677 41677 42318 42319 41677 41682 42318 42301 42296 41678 41678 41683 42301 42313 42303 41679 41679 41705 42313 42303 41680 41679 41690 41682 41681 41682 41690 42318 41693 41687 41684 41697 41696 41685 41685 41688 41697 41685 41686 41688 41686 41687 41688 41689 41688 41687 42293 41689 41687 41687 42292 42293 41687 41693 42292 41688 41689 41697 41689 42293 42294 42315 41697 41689 42317 42315 41689 41689 42294 42317 41690 41701 42318 43849 43109 41691 41691 43108 43849 42312 42311 41692 42314 41705 41695 42323 42314 41695 41695 41704 42323 42330 41708 41696 42331 42330 41696 41696 42326 42331 41696 41697 42326 41697 42325 42326 41697 42315 42325 41698 41700 41702 41698 41699 41700 42321 41699 41698 43114 41700 41699 41699 43109 43114 41699 42321 43109 43121 42341 41700 41700 43115 43121 41700 43114 43115 41703 41702 41700 42341 41703 41700 42329 42318 41701 42341 42340 41703 42324 42323 41704 41704 41725 42324 42314 42313 41705 43143 41727 41706 41706 43142 43143 41707 43130 43131 41707 41708 43130 41708 42330 43130 41718 41710 41709 41719 41718 41709 41718 41711 41710 41711 41718 42329 41712 42334 42337 42335 42334 41712 41712 41713 42335 42339 42335 41713 41713 42338 42339 41714 41715 45269 41716 41715 41714 43140 41716 41714 45268 43140 41714 45269 45268 41714 41715 44616 44617 41715 43871 44616 41715 41717 43871 41715 41716 41717 41715 44617 45269 41717 42346 43871 41718 41743 42329 41718 41719 41743 41719 41728 41743 41720 41732 41733 41720 41723 41732 41722 41721 41720 41733 41722 41720 41721 41722 41734 41722 41729 41736 41730 41729 41722 41733 41730 41722 41736 41734 41722 43136 41732 41723 43137 43136 41723 41723 42336 43137 41724 42352 43880 41724 42351 42352 41726 41725 41724 43880 41726 41724 41725 41726 42324 42343 42324 41726 41726 42342 42343 43880 42342 41726 42353 42351 41727 43143 42353 41727 41744 41743 41728 42371 42370 41729 42380 42371 41729 43151 42380 41729 41729 41730 43151 42370 41736 41729 41730 43150 43151 41730 41733 43150 41733 41732 41731 43150 41733 41731 43868 43150 41731 41731 43136 43868 41731 41732 43136 42357 42356 41735 42372 42357 41735 41735 41738 42372 41735 41736 41738 42370 41738 41736 41737 42354 42366 43161 42372 41738 41738 42381 43161 41738 42370 42381 41739 41740 41742 41742 41741 41739 42378 42377 41740 43159 42378 41740 42377 41742 41740 41741 41750 42395 41766 41750 41741 41741 41742 41766 41742 41765 41766 42377 41765 41742 41743 41744 42369 43126 42329 41743 41743 42348 43126 42369 42348 41743 42393 42385 41745 41745 42392 42393 41745 41752 42392 41746 43172 43183 43177 42383 41747 41747 41748 43177 41748 42389 43177 41748 42388 42389 41748 41760 42388 41751 41750 41749 42392 41751 41749 42393 42392 41749 42398 42393 41749 41749 41750 42398 41750 41751 42395 41750 42397 42398 42403 42397 41750 41750 41765 42403 41766 41765 41750 42392 41752 41751 41753 41754 41756 41755 41754 41753 43194 41755 41753 44664 43194 41753 41753 44650 44664 41753 41756 44650 42399 41757 41754 41754 41755 42399 41757 41756 41754 41771 41767 41755 43194 41771 41755 41755 41767 42399 41756 43901 44650 41756 43900 43901 41756 41757 43900 41757 42386 43900 43178 42384 41758 41758 42394 43178 41758 41759 42394 42401 42394 41759 41759 41762 42401 41760 41761 42388 42391 42388 41761 41761 41769 42391 41762 41763 42401 41763 42400 42401 41763 41768 42400 43177 42389 41764 43179 43177 41764 41764 41772 43179 41765 42402 42403 41765 42377 42402 41771 41770 41767 42406 42400 41768 41768 41778 42406 41768 41777 41778 42405 41776 41770 41770 42404 42405 41770 41771 42404 43194 42404 41771 43185 43179 41772 41772 43184 43185 41772 41773 43184 41774 41773 41772 43210 43184 41773 41773 43209 43210 42409 42407 41775 43199 42409 41775 41775 42410 43199 41775 41779 42410 41775 42407 42408 43211 42415 41776 41776 42405 43211 42416 42406 41778 42417 42416 41778 41779 41781 42410 41779 41780 41781 42426 42410 41781 41782 41783 41786 41783 41784 41786 43187 41786 41784 41784 42412 43187 42411 41793 41786 43187 42411 41786 43220 43208 41788 43222 43220 41788 41788 41794 43222 41789 41790 41796 41791 41790 41789 43228 41791 41789 41789 42442 43228 41789 41797 42442 41789 41796 41797 43217 42426 41790 41790 41791 43217 43960 43217 41791 41791 43228 43960 41792 44672 44673 41792 42411 44672 41792 41793 42411 41794 41804 43222 41797 41799 42442 41798 41806 43233 41799 42440 42442 42453 41805 41800 42454 42453 41800 41800 41801 42454 43219 42454 41801 41801 43212 43219 41801 42415 43212 42449 41803 41802 42455 41807 41803 41803 42447 42455 42449 42447 41803 41804 42427 43222 43230 42427 41804 42453 41808 41805 41806 42460 43233 41807 42455 42461 42472 41822 41808 41808 42453 42472 43231 43229 41809 43975 43231 41809 43976 43975 41809 41809 42476 43976 41809 41810 42476 41809 43229 43230 43256 42476 41810 41811 41814 42456 41811 41812 41814 41813 41812 41811 42477 41813 41811 41811 41829 42477 41830 41829 41811 42452 41830 41811 41811 42435 42452 42456 42435 41811 41833 41832 41812 41812 41813 41833 41840 41833 41813 41842 41840 41813 42477 41842 41813 41814 41817 42456 41814 41815 41817 41816 41815 41814 41824 41816 41814 42462 41817 41815 41815 41818 42462 41815 41816 41818 41825 41818 41816 41816 41824 41825 42459 42457 41817 42462 42459 41817 42457 42456 41817 41818 41826 42462 41818 41825 41826 42463 41827 41819 41819 41820 42463 42464 42463 41820 42467 42466 41821 42468 42467 41821 41821 41822 42468 42469 42468 41822 42472 42469 41822 42485 41838 41823 43255 42485 41823 41834 41825 41824 41824 41832 41834 41835 41826 41825 41825 41834 41835 42478 42462 41826 41826 41835 42478 42479 41836 41827 41827 42463 42479 43982 43254 41828 41828 42474 43982 41828 42461 42474 41829 41842 42477 42486 41842 41829 41829 41831 42486 41829 41830 41831 43264 41831 41830 41830 43263 43264 41830 43262 43263 43983 43262 41830 41830 42450 43983 43240 42450 41830 41830 42452 43240 43264 42486 41831 41841 41834 41832 41832 41840 41841 41832 41833 41840 42487 41835 41834 42488 42487 41834 41834 41841 42488 42481 42478 41835 42487 42481 41835 41837 42480 43251 42484 41839 41838 42485 42484 41838 41850 41848 41839 42484 41850 41839 41842 41841 41840 43270 42488 41841 43271 43270 41841 41841 41842 43271 41842 42486 43271 42494 41846 41843 41843 42493 42494 43282 42497 41844 41844 41852 43282 41844 41851 41852 42497 41845 41844 41845 42497 43281 43992 43259 41845 41845 43281 43992 41846 42494 42498 41865 41859 41847 41848 41849 43285 41850 41849 41848 41849 44002 44008 41849 41850 44002 44001 43285 41849 44008 44001 41849 41850 42484 44002 41851 41861 42499 41853 41852 41851 42499 41853 41851 44011 43282 41852 41852 41853 44011 41853 42499 44011 41854 41856 41862 41862 41855 41854 41855 41869 42502 41855 41862 41869 41856 41857 41862 44019 44018 41861 41861 42504 44019 42505 42504 41861 44018 42499 41861 41871 41870 41863 41863 41864 41871 42516 42514 41865 42517 42516 41865 42518 42517 41865 42507 42506 41866 41866 42501 42507 41866 42500 42501 41867 41868 41873 41869 41868 41867 43292 41869 41867 41867 41873 43292 41868 41872 41873 43286 42502 41869 43292 43286 41869 43293 42508 41870 41870 42510 43293 42511 42510 41870 41870 41871 42511 41871 42509 42511 41871 42503 42509 42519 41873 41872 42521 42519 41872 41873 42519 43292 42512 42503 41874 41875 41876 42524 44036 43295 41875 41875 42524 44036 41876 42522 42524 41880 41879 41878 43296 41880 41878 43301 43299 41879 41879 41880 43301 41880 44040 44044 41880 43297 44040 41880 43296 43297 43303 43301 41880 44044 43303 41880 43297 43296 41881 41881 41882 43297 43298 43297 41882 44039 43298 41882 41882 42530 44039 42532 42530 41882 42534 41886 41883 41883 42529 42534 42545 42537 41884 41884 41885 42545 41887 41888 41890 42556 41890 41888 41888 42555 42556 41888 42544 42555 41892 41891 41890 43312 41892 41890 41890 42564 43312 41890 42556 42564 41891 41892 41894 43317 41894 41892 41892 43316 43317 41892 43312 43316 43319 42570 41894 41894 43317 43319 42570 41898 41895 43311 42548 41896 41896 41903 43311 41904 41903 41896 42571 41904 41896 42548 41897 41896 42548 42547 41897 43346 41900 41898 41898 43337 43346 41898 43329 43337 41898 42570 43329 41899 41900 41905 41912 41905 41900 43347 41912 41900 41900 43345 43347 43346 43345 41900 41901 41902 42572 42572 42571 41901 44055 43311 41903 41903 41904 44055 41904 43320 44055 41904 42571 43320 42575 42573 41906 42579 41908 41907 41907 41909 42579 44075 44066 41908 41908 42580 44075 41908 42579 42580 41922 41916 41910 41916 41911 41910 43357 42586 41911 43362 43357 41911 41911 41916 43362 42600 41931 41912 41912 41913 42600 41914 41913 41912 43347 41914 41912 42608 42600 41913 43364 42608 41913 44081 43364 41913 41913 41914 44081 44788 44081 41914 41914 44074 44788 41914 43344 44074 43347 43344 41914 41915 43376 43377 41915 41957 43376 41915 41941 41957 41915 42603 43355 44090 42603 41915 41915 43377 44090 41916 42611 43362 41916 42596 42611 41916 41922 42596 43334 41919 41917 41917 42588 43334 41917 42587 42588 42594 42587 41917 41917 41918 42594 41919 41918 41917 41918 41928 42594 41918 41920 41928 41921 41920 41918 41918 41919 41921 41919 43334 43340 42591 41921 41919 42593 42591 41919 43340 42593 41919 41940 41928 41920 41920 41924 41940 41920 41921 41924 41926 41924 41921 41921 41925 41926 42591 41925 41921 42612 42596 41922 41922 41923 42612 41923 41938 42612 41924 41939 41940 41924 41927 41939 41924 41925 41927 41926 41925 41924 42598 41927 41925 41925 42592 42598 41925 42591 42592 42598 41939 41927 42599 42594 41928 41928 41940 42599 42616 41930 41929 41929 42608 42616 42615 41965 41930 42616 42615 41930 41933 41942 41949 41933 41934 41942 42609 41943 41937 41938 41946 42612 41953 41948 41939 42614 41953 41939 41939 42613 42614 41939 42598 42613 41948 41940 41939 42607 42599 41940 41940 41955 42607 41940 41947 41955 41948 41947 41940 41958 41957 41941 42595 41949 41942 41942 42576 42595 41943 41944 41945 42620 41944 41943 43382 42620 41943 43383 43382 41943 41943 42609 43383 43371 41946 41944 41944 42620 43371 43371 42612 41946 41956 41955 41947 41947 41948 41956 41948 41952 41954 41953 41952 41948 41948 41954 41956 42619 41951 41949 43379 42619 41949 41949 43369 43379 41949 43365 43369 41949 42595 43365 42618 41963 41950 41950 41951 42618 42619 42618 41951 41961 41954 41952 42624 41961 41952 41952 42621 42624 41952 42614 42621 41952 41953 42614 41954 41961 42626 42626 41956 41954 42622 42607 41955 42625 42622 41955 42626 42625 41955 41955 41956 42626 41957 42617 43376 41957 41958 42617 41958 41959 42617 42623 42617 41959 43392 42626 41961 44113 43392 41961 44114 44113 41961 41961 43385 44114 41961 42624 43385 41962 41966 41972 41962 41965 41966 43388 42628 41963 41963 42618 43388 41964 41965 42615 41966 41965 41964 44115 41966 41964 41964 44099 44115 41964 44088 44099 41964 42615 44088 42635 41972 41966 43398 42635 41966 41966 43395 43398 43397 43395 41966 44115 43397 41966 43381 42623 41967 43384 43381 41967 41967 41968 43384 41968 42629 43384 41968 41974 42629 41971 41970 41969 41975 41971 41969 44112 44103 41970 41970 41971 44112 44132 44112 41971 44138 44132 41971 41971 42634 44138 41971 41975 42634 42635 41973 41972 42631 42629 41974 41977 42627 42633 43421 42646 41979 42647 41981 41980 42650 42647 41980 41980 42649 42650 41980 41985 42649 43415 41991 41982 41993 41990 41983 42651 41993 41983 44179 44178 41984 41984 42643 44179 41985 41986 42649 42655 42649 41986 43427 42655 41986 41986 42663 43427 41987 41988 42666 41989 41988 41987 43430 41989 41987 41987 42665 43430 43441 43437 41988 41988 41989 43441 43437 42666 41988 44202 43441 41989 41989 44198 44202 41989 43430 44198 41990 41994 42008 41990 41993 41994 42654 42653 41991 44180 42654 41991 44181 44180 41991 41991 43416 44181 41991 43414 43416 43415 43414 41991 42653 42001 41992 42659 41994 41993 41993 42651 42659 42661 42008 41994 41994 42659 42661 41995 42667 42669 41995 41998 42667 42669 41999 41995 43429 42665 41996 41996 41997 43429 43440 43429 41997 41997 42023 43440 42668 42663 41999 42669 42668 41999 42664 42004 42000 42000 42001 42664 42001 42653 42664 42669 42667 42003 42680 42669 42003 43428 42675 42004 42004 42664 43428 42005 42681 42682 42006 42685 43431 42016 42009 42007 42020 42016 42007 42662 42020 42007 42661 42659 42008 43433 42015 42008 42008 42659 43433 42700 42011 42009 42009 42019 42700 42009 42016 42019 42010 42011 42700 42686 42680 42010 42700 42686 42010 42696 42018 42012 42012 42693 42696 42012 42684 42693 42018 42014 42013 42014 42024 42026 42014 42018 42024 42679 42662 42015 43433 42679 42015 42020 42019 42016 42691 42681 42017 42017 42690 42691 42696 42024 42018 42706 42700 42019 42019 42697 42706 42699 42697 42019 42019 42020 42699 42020 42662 42699 42021 42028 42690 42023 43429 43440 44201 43429 42023 42023 44200 44201 42023 42031 44200 42024 42025 42026 42696 42025 42024 42715 42026 42025 42025 42696 42715 44218 43446 42026 42026 43456 44218 42026 42715 43456 42027 42687 43448 42029 42028 42027 42710 42029 42027 43451 42710 42027 42027 43449 43451 42027 43448 43449 42028 42029 42690 44216 44215 42029 42029 42710 44216 43442 42690 42029 44215 43442 42029 44211 42031 42030 44212 44211 42030 42030 42731 44212 44217 44200 42031 44894 44217 42031 42031 44211 44894 42736 42730 42032 42032 42735 42736 42721 42043 42034 42034 42709 42721 42732 42709 42034 42034 42039 42732 42034 42038 42039 42034 42037 42038 42034 42035 42037 42036 42035 42034 42043 42036 42034 42035 42036 42037 42036 42043 43468 42040 42037 42036 42059 42040 42036 42063 42059 42036 43468 42063 42036 42040 42038 42037 42728 42725 42038 42733 42728 42038 42038 42044 42733 42038 42040 42044 42725 42039 42038 42039 42722 42732 42725 42722 42039 42045 42044 42040 42059 42045 42040 42041 42042 44252 42043 42042 42041 43468 42043 42041 44256 43468 42041 42041 44252 44256 42042 44236 44252 44237 44236 42042 42042 43459 44237 42042 43458 43459 42042 42720 43458 42721 42720 42042 42042 42043 42721 42740 42733 42044 42044 42064 42740 42044 42047 42064 42044 42045 42047 42045 42046 42047 42059 42046 42045 42046 42059 42067 42057 42047 42046 42071 42057 42046 42046 42067 42071 42047 42058 42064 42047 42057 42058 42060 42049 42048 42745 42060 42048 42048 42743 42745 42048 42734 42743 42049 42061 42737 42049 42060 42061 42050 43483 43484 42050 42737 43483 43484 42051 42050 42054 42052 42051 42055 42054 42051 42056 42055 42051 43484 42056 42051 43513 42068 42052 42052 42053 43513 42054 42053 42052 44274 43513 42053 42053 44261 44274 42053 42054 44261 42054 42055 44261 42055 44260 44261 42055 42056 44260 42056 44258 44260 42056 43485 44258 42056 43484 43485 42083 42058 42057 42057 42082 42083 42057 42071 42082 42065 42064 42058 42083 42065 42058 42059 42063 42067 43499 42061 42060 43508 43499 42060 42060 42745 43508 43499 42737 42061 42748 42735 42062 43511 42748 42062 43488 42067 42063 42063 43468 43488 42742 42740 42064 42064 42065 42742 42065 42075 42742 42076 42075 42065 42065 42072 42076 42083 42072 42065 42066 42069 42080 42080 42070 42066 42784 42071 42067 43502 42784 42067 42067 43488 43502 42093 42085 42068 42068 42092 42093 42764 42092 42068 43513 42764 42068 42069 42079 42080 42070 42081 42750 42070 42080 42081 42090 42082 42071 42752 42090 42071 42071 42751 42752 42784 42751 42071 42083 42082 42072 42773 42076 42072 42072 42767 42773 42072 42073 42767 42074 42073 42072 42082 42074 42072 42073 42090 42767 42073 42074 42090 42074 42082 42090 42756 42742 42075 42760 42756 42075 42075 42076 42760 42076 42759 42760 42773 42759 42076 42097 42086 42077 42077 42096 42097 42077 42094 42096 42088 42079 42078 42078 42087 42088 42078 42086 42087 42089 42080 42079 42079 42088 42089 42758 42081 42080 42765 42758 42080 42080 42089 42765 44282 42750 42081 42081 43515 44282 42081 42766 43515 42081 42758 42766 42084 42091 43521 42098 42087 42086 42086 42097 42098 42099 42088 42087 42087 42098 42099 42099 42089 42088 42089 42779 42780 42089 42099 42779 42780 42765 42089 42090 42752 42767 44293 43521 42091 42091 42092 44293 42764 42763 42092 42092 42775 44293 42777 42775 42092 42092 42762 42777 42763 42762 42092 42778 42096 42094 42785 42778 42094 42798 42785 42094 42103 42097 42095 42787 42103 42095 42095 42778 42787 42095 42096 42778 42097 42096 42095 42103 42100 42097 42100 42098 42097 42100 42099 42098 42099 42791 42792 42099 42788 42791 42099 42100 42788 42792 42779 42099 42100 42103 42788 42101 42102 42104 42791 42788 42103 42103 42790 42791 42103 42787 42790 42815 42108 42106 44336 42815 42106 42106 44332 44336 44333 44332 42106 42106 42107 44333 42108 42107 42106 45681 44333 42107 45685 45681 42107 42107 44338 45685 44340 44338 42107 44341 44340 42107 42107 42108 44341 42108 42835 44341 42816 42119 42110 42111 42814 42830 42111 42112 42814 42112 42813 42814 42113 42834 43556 42113 42114 42834 42115 42116 42118 42117 42116 42115 42842 42117 42115 42115 42841 42842 42115 42125 42841 43573 42835 42116 42116 42117 43573 44355 43573 42117 42117 42842 44355 42839 42837 42119 42119 42816 42839 42121 42831 42836 42121 42826 42831 42845 42124 42122 42122 42131 42845 42123 42124 42125 43576 42125 42124 43579 43576 42124 42124 42845 43579 43576 42841 42125 42847 42133 42126 42126 42127 42847 42127 42844 42847 42127 42843 42844 42127 42837 42843 42134 42129 42128 42129 42134 42848 42846 42131 42130 42130 42132 42846 43578 42845 42131 43583 43578 42131 42131 42846 43583 43582 42846 42132 42132 42849 43582 43584 42852 42133 43585 43584 42133 42133 42844 43585 42847 42844 42133 42134 42135 42848 45023 42848 42135 42135 42856 45023 42136 42137 43595 42137 42853 43595 43631 43628 42138 42886 42140 42139 42887 42142 42140 42140 42886 42887 43638 42151 42141 43639 43638 42141 42141 43624 43639 42141 42142 43624 42142 42887 43624 43643 43631 42143 43644 43643 42143 42143 42153 43644 42890 42145 42144 42144 42149 42890 42888 42155 42145 42889 42888 42145 42890 42889 42145 42898 42893 42146 42146 42147 42898 42147 42897 42898 42147 42150 42897 43633 42149 42148 43634 43633 42148 42148 42892 43634 43633 42890 42149 42156 42152 42151 43647 42156 42151 42151 43638 43647 42153 43640 43644 42153 42899 43640 42153 42154 42899 42155 42888 44391 44391 43649 42155 42160 42159 42156 43660 42160 42156 42156 43647 43660 42901 42900 42157 42903 42901 42157 42157 42158 42903 42158 42160 42903 42158 42159 42160 43660 42903 42160 42162 42902 42904 42163 42907 42909 42908 42907 42163 43667 42910 42164 43669 43667 42164 42164 43663 43669 43675 43674 42165 42165 42166 43675 42166 43671 43675 42166 42910 43671 43682 42918 42167 44420 43682 42167 42168 42906 42908 42911 42906 42168 42915 42911 42168 42917 42915 42168 42923 42171 42169 42927 42923 42169 42930 42927 42169 42932 42930 42169 42169 42176 42932 42170 42171 42923 42172 42173 42182 42174 42173 42172 42946 42182 42173 43706 42946 42173 44455 43706 42173 42173 43707 44455 42173 43694 43707 42173 42174 43694 42174 43690 43694 42174 42929 43690 42932 42176 42175 42175 42179 42932 42175 42177 42179 42179 42185 42931 42179 42931 42932 42938 42187 42180 42180 42181 42938 42181 42937 42938 42946 42192 42182 43712 42198 42183 43727 43712 42183 42183 43725 43727 43698 42933 42184 43708 43698 42184 42184 42199 43708 42947 42193 42186 42186 42187 42947 42187 42938 42947 42940 42936 42188 42188 42939 42940 42188 42189 42939 42189 42190 42939 42941 42939 42190 42944 42941 42190 42190 42191 42944 42192 42946 42949 42951 42950 42194 42197 42196 42195 42957 42197 42195 42968 42200 42196 42196 42197 42968 43736 42968 42197 42197 42957 43736 43710 42199 42198 43711 43710 42198 43712 43711 42198 43710 43708 42199 43735 42202 42200 42200 42968 43735 43742 42974 42201 42201 42972 43742 42201 42202 42972 44471 42972 42202 42202 44465 44471 42202 43735 44465 42206 42205 42203 42975 42206 42203 42203 42974 42975 42203 42205 42982 42205 42206 44478 43749 42982 42205 44478 43749 42205 42206 43743 44478 42206 43742 43743 42206 42975 43742 42207 42211 42987 42990 42989 42208 45142 42990 42208 42208 42985 45142 43751 42210 42209 42211 42986 42987 42215 42214 42213 44489 42215 42213 44491 44489 42213 42213 43748 44491 43752 43747 42214 42214 42215 43752 43747 42980 42214 45141 43752 42215 42215 44489 45141 42221 42219 42216 42998 42226 42217 43002 43001 42218 43764 43002 42218 42218 43000 43764 42218 42221 43000 42218 42219 42221 42220 42219 42218 43001 42220 42218 42219 42220 43748 43757 43748 42220 42220 43001 43757 42221 42999 43000 43006 42225 42223 43007 43006 42223 42223 42229 43007 42230 42229 42223 42223 42224 42230 42225 42224 42223 43771 43005 42224 42224 42225 43771 43772 43771 42225 42225 43006 43772 42998 42997 42226 43761 42227 42226 42226 42997 43761 42227 43761 43774 42228 43003 43004 42229 42231 43007 43776 43007 42231 42232 42233 43763 43763 42999 42232 44500 43763 42233 44501 44500 42233 42233 43782 44501 42233 42243 43782 42237 42236 42235 43019 42237 42235 42235 43009 43019 42235 43008 43009 42236 42237 42238 42239 42238 42237 43019 42239 42237 43020 42245 42238 42238 42239 43020 43027 43020 42239 43798 43027 42239 42239 43795 43798 42239 43016 43795 43019 43016 42239 42241 43012 43021 43013 42243 42242 43014 43013 42242 42243 43022 43782 43023 43022 42243 42243 43013 43023 43792 43790 42244 42244 43024 43792 42244 42246 43024 42245 43028 43032 42245 43020 43028 42246 42247 43024 43035 43024 42247 42247 43034 43035 42248 43032 43036 42249 43033 43034 43801 43033 42249 42249 43800 43801 42249 43037 43800 42255 42252 42250 42250 42251 42255 42259 42255 42251 42252 42255 42256 42267 42266 42253 43036 42267 42253 42266 42254 42253 42266 42258 42254 43060 42256 42255 42255 43041 43060 42255 42259 43041 43060 42271 42256 42257 42258 42273 43077 42291 42257 42257 43075 43077 42257 42273 43075 42258 42267 42273 42258 42266 42267 42259 42260 43041 42261 42260 42259 42260 42261 43041 43061 43041 42261 43062 43061 42261 42262 43064 43066 42262 42268 43064 42262 42263 42268 42269 42268 42263 42265 43042 43056 43046 43042 42265 43059 42273 42267 42267 43047 43059 42267 43036 43047 43065 43064 42268 43070 43065 42268 42268 42269 43070 42269 43067 43070 42269 42272 43067 42270 42271 43079 43083 42277 42270 43099 43083 42270 42270 43078 43099 43079 43078 42270 42271 43060 43061 42271 43061 43079 42273 43074 43075 42273 43059 43074 43077 43075 42274 42274 42275 43077 42276 42275 42274 43832 42276 42274 42274 43076 43832 42274 43075 43076 43090 43077 42275 43840 43090 42275 42275 42276 43840 42276 44587 44588 45237 44587 42276 42276 43833 45237 42276 43832 43833 44588 43840 42276 43069 43068 42278 42278 42280 43069 42289 42281 42279 42282 42280 42279 42279 42281 42282 43071 43069 42280 43072 43071 42280 42280 42282 43072 42283 42282 42281 42290 42283 42281 42282 42283 43072 43825 43072 42283 42283 43086 43825 42283 42290 43086 43082 42294 42284 42285 42304 43080 42306 42304 42285 42288 42287 42286 43085 42288 42286 44557 43085 42286 42286 43084 44557 42287 42288 42295 42288 43085 44543 43096 42295 42288 44576 43096 42288 45224 44576 42288 42288 44543 45224 42290 43081 43086 42291 43077 43090 43082 42317 42294 42296 42300 43087 42296 42299 42300 42301 42299 42296 43839 42300 42297 44575 43839 42297 44578 44575 42297 42297 42298 44578 42299 42298 42297 42300 42299 42297 42298 42322 44578 42298 42299 42322 42299 42309 42322 42299 42301 42309 43836 43087 42300 43839 43836 42300 42310 42309 42301 42302 43091 43837 42302 42303 43091 42303 42313 43091 42304 42305 43094 42306 42305 42304 43835 43080 42304 44570 43835 42304 42304 43094 44570 43095 43094 42305 42305 42320 43095 42305 42306 42320 42306 42319 42320 43097 42308 42307 42308 43102 43104 42308 43097 43102 43112 42322 42309 43113 43112 42309 42309 42310 43113 42310 42311 42312 42310 42312 43113 42312 43090 43113 43842 43837 42313 42313 42314 43842 43837 43091 42313 43850 43842 42314 42314 42323 43850 42315 42316 42325 42317 42316 42315 42328 42325 42316 42316 42327 42328 43088 42327 42316 42316 42317 43088 42317 43082 43088 42329 42319 42318 43095 42320 42319 43125 43095 42319 42319 42329 43125 45240 44578 42322 42322 43112 45240 43856 43850 42323 42323 42324 43856 42324 42347 43856 42324 42343 42347 42333 42326 42325 43117 42333 42325 42325 42328 43117 42333 42331 42326 42327 43088 43093 43092 42328 42327 43093 43092 42327 43120 43117 42328 43844 43120 42328 42328 43843 43844 42328 43826 43843 42328 43092 43826 43126 43125 42329 42330 43129 43130 43132 43129 42330 42330 42331 43132 42331 42332 43132 42333 42332 42331 43133 43132 42332 42332 43119 43133 42332 42333 43119 42333 43118 43119 42333 43117 43118 43127 42337 42334 42334 42335 43127 42335 42339 43127 43138 43137 42336 42336 42337 43138 42337 43127 43138 43127 42339 42338 43128 43127 42338 43152 42346 42340 42340 43121 43152 42340 42341 43121 44608 42343 42342 44618 44608 42342 42342 43880 44618 44602 42347 42343 44608 44602 42343 42344 42345 44604 44603 43128 42344 44604 44603 42344 42345 43141 44604 42346 43152 43871 44590 43856 42347 44602 44590 42347 42348 42349 43126 42350 42349 42348 43165 42350 42348 44626 43165 42348 44627 44626 42348 45291 44627 42348 45292 45291 42348 45295 45292 42348 45297 45295 42348 42348 43899 45297 42348 43166 43899 42348 42369 43166 43860 43126 42349 47258 43860 42349 48005 47258 42349 48007 48005 42349 42349 42350 48007 42350 43165 48007 42353 42352 42351 43882 43880 42352 42352 42353 43882 42353 43143 43882 42368 42366 42354 42354 42355 42368 43164 42368 42355 42355 42365 43164 43157 42359 42356 42356 42357 43157 42357 42373 43157 43162 42373 42357 42357 43160 43162 42357 42372 43160 42358 42360 42361 42358 42359 42360 43157 42360 42359 42374 42361 42360 42360 42373 42374 43157 42373 42360 44634 43158 42361 42361 43909 44634 42361 43908 43909 42361 42374 43908 42375 42363 42362 43158 42375 42362 43163 42364 42363 42363 42375 43163 42366 42367 43159 42368 42367 42366 42367 44632 44638 42367 42368 44632 42367 42378 43159 43174 42378 42367 44638 43174 42367 42368 43164 44632 43167 43166 42369 43168 43167 42369 42370 42371 42379 42370 42379 42381 42380 42379 42371 43161 43160 42372 43162 42374 42373 42374 43162 43908 43891 43163 42375 44635 43891 42375 42375 43158 44635 42376 43163 43892 42377 42378 43174 43174 42402 42377 42379 42380 42382 42382 42381 42379 43153 42382 42380 42380 43151 43153 44642 43904 42381 42381 43893 44642 42381 42382 43893 43904 43161 42381 42382 43153 43170 42382 43169 43893 43170 43169 42382 43173 43164 42383 43177 43173 42383 43902 43175 42384 43903 43902 42384 42384 43178 43903 42385 43167 43168 43898 43167 42385 42385 42393 43898 43902 43900 42386 42386 43175 43902 42386 42387 43175 42390 42389 42388 42391 42390 42388 42393 43180 43898 43181 43180 42393 42393 42398 43181 43917 43178 42394 42394 43182 43917 42394 42401 43182 44658 43192 42396 42396 43943 44658 42396 43933 43943 42396 42397 43933 42398 42397 42396 43192 42398 42396 43934 43933 42397 42397 43193 43934 42397 42403 43193 43192 43181 42398 43182 42401 42400 43186 43182 42400 42400 42406 43186 43916 42403 42402 42402 43174 43916 43202 43193 42403 43928 43202 42403 42403 43914 43928 43916 43914 42403 43194 42405 42404 43935 43211 42405 43936 43935 42405 43949 43936 42405 42405 43948 43949 42405 43194 43948 42406 42416 43186 42407 42409 43205 43944 43205 42409 42409 43199 43944 42410 43198 43199 43201 43198 42410 43206 43201 42410 42410 42426 43206 42411 43207 44672 42411 43187 43207 43188 43187 42412 42412 42413 43188 42414 42413 42412 44670 44661 42413 42413 42414 44670 43207 43188 42413 45326 43207 42413 42413 45321 45326 42413 44661 45321 42414 44662 44670 42414 43922 44662 42415 43211 43212 43204 43186 42416 42416 42425 43204 42416 42424 42425 42416 42418 42424 42416 42417 42418 42419 42418 42417 42418 42420 42424 42418 42419 42420 42421 42420 42419 43214 42424 42420 42420 42421 43214 42421 43213 43214 43216 43213 42421 42421 42422 43216 42422 44683 44684 42422 42423 44683 44684 43216 42422 42423 44668 44683 42423 43944 44668 42423 43205 43944 43213 42425 42424 43214 43213 42424 42425 43197 43204 44682 43197 42425 42425 43215 44682 42425 43213 43215 43951 43206 42426 43957 43951 42426 42426 43217 43957 42427 42428 43222 42429 42428 42427 42443 42429 42427 42451 42443 42427 43231 42451 42427 42427 43229 43231 43230 43229 42427 43224 43222 42428 42428 42429 43224 44699 43224 42429 42429 42433 44699 42429 42431 42433 42429 42430 42431 42444 42430 42429 42429 42443 42444 42432 42431 42430 42444 42432 42430 43226 42433 42431 42431 43225 43226 42431 42436 43225 42431 42432 42436 42432 42434 42436 42435 42434 42432 42445 42435 42432 42432 42444 42445 42433 43226 44699 43227 42436 42434 42434 42437 43227 42439 42437 42434 42446 42439 42434 42434 42435 42446 42456 42446 42435 42435 42445 42452 43227 43225 42436 42437 43225 43227 44700 43225 42437 42437 43967 44700 42437 42438 43967 42439 42438 42437 42438 43232 43967 42438 42439 43232 42439 42446 43232 42440 42441 42442 43236 42442 42441 43966 43228 42442 42442 43236 43966 42445 42444 42443 42451 42445 42443 43240 42452 42445 42445 42450 43240 42451 42450 42445 42446 42456 43232 43239 42455 42447 43973 43239 42447 42447 43962 43973 42447 42448 43962 42449 42448 42447 42450 43977 43983 42450 42451 43977 42451 43231 43977 43242 42472 42453 43963 43242 42453 42453 42454 43963 42454 43219 43963 43239 42461 42455 43237 43232 42456 42456 42457 43237 42459 42458 42457 43974 43237 42457 42457 42458 43974 42458 43241 43978 42458 42459 43241 43978 43974 42458 42459 42462 43241 42460 42473 43980 43980 43233 42460 42475 42474 42461 43239 42475 42461 43244 43241 42462 42462 43243 43244 42462 42478 43243 42483 42479 42463 42463 42464 42483 42464 42465 42483 43248 42483 42465 43252 43248 42465 42465 42466 43252 42466 42467 43252 43253 43252 42467 42467 42468 43253 42468 42469 43253 43249 42471 42469 42469 42472 43249 42469 42470 43253 42471 42470 42469 44729 43253 42470 42470 44728 44729 44732 44728 42470 42470 42471 44732 42471 43249 45403 45403 44732 42471 42472 43242 43249 42473 43996 44724 42473 43251 43996 44724 43980 42473 44718 43982 42474 44721 44718 42474 42474 42475 44721 42475 44719 44721 42475 43239 44719 43991 43976 42476 43992 43991 42476 42476 43256 43992 43257 43243 42478 42478 42482 43257 42478 42481 42482 43267 42490 42479 42479 43245 43267 42479 42483 43245 42480 43250 43251 43995 43250 42480 42480 42496 43995 42489 42482 42481 42481 42487 42489 43258 43257 42482 42482 42489 43258 43248 43245 42483 44734 44002 42484 42484 43269 44734 42484 42485 43269 42485 43255 43269 44003 43271 42486 42486 43264 44003 42492 42489 42487 42487 42488 42492 43273 42492 42488 42488 43272 43273 42488 43270 43272 43274 43258 42489 42489 43273 43274 42489 42492 43273 43267 42491 42490 43268 42493 42491 42491 43267 43268 43268 42494 42493 42495 43285 44001 42495 43279 43285 43995 42496 42495 44007 43995 42495 42495 44001 44007 43282 43280 42497 42497 43280 43281 44018 44011 42499 42500 42502 43286 43286 42501 42500 44021 42507 42501 44025 44021 42501 44026 44025 42501 42501 43286 44026 43287 42509 42503 42503 42512 43287 42504 42506 44019 42504 42505 42506 44021 44019 42506 42506 42507 44021 43293 42520 42508 44028 42511 42509 42509 44023 44028 42509 44022 44023 42509 43287 44022 44028 43293 42510 42510 42511 44028 42512 42513 43287 44022 43287 42513 44024 44022 42513 42513 42515 44024 42516 42515 42514 42515 44020 44024 42515 43291 44020 42515 42516 43291 42516 42517 43291 44020 43291 42517 42517 42518 44020 44763 44020 42518 42518 44753 44763 42518 44017 44753 43294 43292 42519 42519 42521 43294 42524 42522 42520 42520 42523 42524 43293 42523 42520 43295 43294 42521 44767 44038 42523 42523 44028 44767 42523 43293 44028 44038 42524 42523 42524 44033 44036 44034 44033 42524 44037 44034 42524 44038 44037 42524 42540 42528 42525 42525 42539 42540 42525 42526 42539 43299 42539 42526 42540 42533 42527 42527 42528 42540 42553 42534 42529 42529 42542 42553 42529 42533 42542 44042 44039 42530 44771 44042 42530 42530 42531 44771 42532 42531 42530 45440 44771 42531 42531 44770 45440 42531 42535 44770 42531 42532 42535 42536 42535 42532 43302 42536 42532 42532 42546 43302 42532 42537 42546 42533 42540 42542 43310 43305 42534 42534 42553 43310 42535 44053 44770 42535 44043 44053 42535 42536 44043 42536 42565 44043 43302 42565 42536 42537 42545 42546 42541 42540 42538 42549 42541 42538 42550 42549 42538 42538 42539 42550 42540 42539 42538 43300 42550 42539 43301 43300 42539 42539 43299 43301 42540 42541 42542 42543 42542 42541 42554 42543 42541 42541 42549 42554 42542 42543 42553 42559 42553 42543 42563 42559 42543 42543 42554 42563 43305 42555 42544 42565 42546 42545 42545 42547 42565 42546 42565 43302 43311 42565 42547 42547 42548 43311 42558 42554 42549 42567 42558 42549 42549 42550 42567 43309 42567 42550 42550 42551 43309 42552 42551 42550 42557 42552 42550 43300 42557 42550 42551 42552 44047 44048 43309 42551 42551 44047 44048 42552 42557 43304 42552 43304 44047 42553 42561 43310 42553 42559 42561 42568 42563 42554 42554 42566 42568 42554 42558 42566 43305 42556 42555 43307 42564 42556 42556 43305 43307 42557 43300 43304 42567 42566 42558 42559 42560 42561 42563 42560 42559 42560 42563 42569 42562 42561 42560 42569 42562 42560 42561 43306 43310 44050 43306 42561 42561 43315 44050 42561 43314 43315 42561 42562 43314 43323 43314 42562 42562 43321 43323 42562 42569 43321 42563 42568 42569 44051 43312 42564 44052 44051 42564 42564 43308 44052 42564 43307 43308 44053 44043 42565 44773 44053 42565 42565 43311 44773 42566 42567 42568 43309 42568 42567 43313 42569 42568 44054 43313 42568 42568 44048 44054 42568 43309 44048 43322 43321 42569 42569 43313 43322 42570 43319 43329 42571 42572 43320 43338 43320 42572 42573 42578 42585 42573 42574 42578 42575 42574 42573 44077 42578 42574 42574 43354 44077 42574 42575 43354 43355 43354 42575 43365 42595 42576 42576 42577 43365 42578 42577 42576 42585 42578 42576 42577 43348 43365 42577 42578 43348 44077 43348 42578 44076 42580 42579 44786 44075 42580 44793 44786 42580 42580 43358 44793 44076 43358 42580 43352 43337 42581 42581 42582 43352 42583 42582 42581 42584 42583 42581 43333 42584 42581 42581 43330 43333 42581 43329 43330 43337 43329 42581 43360 43352 42582 43361 43360 42582 42582 42583 43361 42583 42587 43361 42583 42584 42587 42588 42587 42584 43341 42588 42584 42584 43333 43341 42586 43357 43358 43368 43361 42587 42587 43367 43368 42587 42594 43367 43341 43334 42588 42597 42592 42589 43363 42597 42589 42589 42590 43363 42591 42590 42589 42592 42591 42589 42590 43332 43363 42590 42593 43332 42590 42591 42593 42592 42597 42598 42593 43327 43332 43331 43327 42593 43340 43331 42593 42594 42599 43367 42612 42611 42596 43366 42598 42597 44079 43366 42597 42597 43363 44079 43366 42613 42598 42599 42607 43367 44082 43354 42601 44795 44082 42601 42601 44790 44795 42601 44789 44790 45463 44789 42601 42601 42602 45463 42603 42602 42601 43354 42603 42601 45468 45463 42602 42602 44090 45468 42602 42603 44090 42603 43354 43355 42610 42609 42604 42604 42605 42610 42606 42605 42604 44095 42610 42605 42605 42606 44095 44096 44095 42606 44103 44096 42606 43372 43367 42607 44092 43372 42607 42607 42625 44092 42607 42622 42625 43375 42616 42608 42608 43364 43375 42609 42610 43383 44104 43383 42610 42610 44095 44104 42611 42612 43370 42611 43357 43362 44083 43357 42611 42611 43370 44083 43371 43370 42612 42621 42614 42613 44086 42621 42613 42613 44079 44086 42613 43366 44079 42615 42616 44088 42616 44087 44088 44089 44087 42616 42616 43375 44089 43380 43376 42617 43381 43380 42617 42617 42623 43381 42618 43379 43388 42618 42619 43379 44107 43371 42620 42620 44106 44107 42620 43382 44106 43386 42624 42621 44091 43386 42621 42621 44086 44091 43386 43385 42624 42625 43387 44092 42625 42626 43387 42626 43392 43394 43393 43387 42626 43394 43393 42626 43399 42633 42627 42627 42628 43399 44111 43399 42628 42628 44093 44111 42628 43388 44093 42629 42631 43389 43389 43384 42629 42630 42635 43398 43389 42631 42630 43398 43389 42630 43403 42638 42632 42632 43401 43403 42632 42633 43401 42633 43400 43401 42633 43399 43400 42634 42636 44138 42636 44131 44138 44163 44131 42636 42636 42639 44163 42636 42637 42639 42640 42639 42637 44151 42641 42638 42638 43406 44151 42638 43403 43406 42639 43409 44163 42639 42640 43409 42640 42642 43410 43410 43409 42640 42644 42643 42641 44151 42644 42641 43411 43410 42642 42642 42645 43411 44862 44179 42643 45534 44862 42643 42643 45533 45534 42643 42644 45533 42644 44847 45533 42644 44846 44847 42644 44151 44846 43412 43411 42645 42645 42646 43412 44859 43412 42646 42646 44176 44859 42646 43419 44176 43420 43419 42646 43421 43420 42646 44190 44174 42648 42648 44188 44190 42648 42655 44188 42648 42649 42655 42650 42649 42648 42651 42652 42659 43425 42659 42652 42670 42664 42653 42653 42654 42670 44180 42670 42654 42655 43427 44188 42656 43422 43423 44186 43422 42656 42656 43426 44186 44208 44187 42657 42657 44203 44208 42657 42658 44203 42659 42658 42657 44187 42659 42657 42658 43432 44203 42658 42660 43432 42658 42659 42660 44187 43433 42659 44182 42660 42659 42659 43424 44182 43425 43424 42659 42660 44182 45563 44204 43432 42660 45573 44204 42660 46173 45573 42660 42660 46172 46173 42660 45563 46172 42662 42679 42699 44199 43427 42663 42663 44194 44199 42663 42668 44194 42664 42671 43428 42672 42671 42664 42664 42670 42672 42665 43429 43430 42676 42673 42666 43437 42676 42666 44205 44194 42668 42668 42680 44205 42668 42669 42680 44181 42672 42670 42670 44180 44181 44195 43428 42671 42671 44192 44195 42671 42672 44192 42672 44181 44192 42673 42676 42677 42674 42675 43436 44196 43436 42675 42675 44195 44196 42675 43428 44195 42678 42677 42676 43437 42678 42676 42694 42684 42677 42677 42692 42694 42677 42678 42692 44214 42692 42678 42678 44207 44214 42678 43441 44207 42678 43437 43441 44208 42699 42679 42679 43433 44208 42680 42702 44205 42680 42686 42702 43438 42682 42681 42681 42691 43438 43438 42683 42682 43445 43439 42683 42683 43444 43445 42683 43438 43444 42694 42693 42684 42707 42702 42686 42686 42700 42707 42687 42688 43448 42688 43434 43448 42688 42689 43434 43436 43434 42689 43442 42691 42690 43442 43438 42691 42713 42694 42692 43455 42713 42692 44214 43455 42692 42715 42696 42693 42693 42714 42715 42693 42695 42714 42693 42694 42695 42713 42695 42694 43453 42714 42695 42695 42712 43453 42713 42712 42695 42716 42706 42697 42697 42698 42716 42699 42698 42697 43447 42716 42698 44227 43447 42698 42698 44208 44227 42698 42699 44208 42700 42706 42707 44221 44219 42701 44222 44221 42701 42701 42732 44222 42701 42708 42732 42701 42707 42708 42701 42702 42707 42703 42702 42701 44219 42703 42701 42702 42703 44205 42703 44194 44205 44220 44194 42703 42703 44219 44220 42717 42707 42706 42706 42716 42717 42709 42708 42707 42717 42709 42707 42708 42709 42732 42709 42720 42721 42709 42717 42720 42710 43452 44216 42710 43449 43452 43451 43449 42710 43439 42719 42711 43457 43453 42712 44919 43457 42712 45590 44919 42712 42712 44901 45590 42712 43454 44901 43455 43454 42712 42712 42713 43455 43456 42715 42714 43462 43456 42714 42714 43453 43462 43458 42717 42716 43459 43458 42716 42716 43450 43459 42716 43447 43450 43458 42720 42717 42718 43464 43467 44240 43464 42718 42718 42719 44240 42719 44225 44240 44226 44225 42719 42719 43439 44226 44229 42732 42722 42722 42723 44229 42724 42723 42722 42725 42724 42722 42723 44221 44229 44231 44221 42723 42723 42724 44231 42724 44230 44231 42724 43471 44230 42724 42726 43471 42724 42725 42726 42727 42726 42725 42728 42727 42725 42726 43463 43471 42726 42727 43463 43469 43463 42727 42727 42728 43469 42728 42733 43469 44212 42731 42729 42729 43460 44212 43461 43460 42729 44251 43461 42729 42729 42730 44251 42730 42738 44251 42739 42738 42730 42730 42736 42739 44229 44222 42732 42733 42740 43469 42744 42743 42734 42747 42736 42735 42748 42747 42735 43501 42739 42736 42736 43487 43501 42736 43486 43487 42736 42747 43486 43500 43483 42737 42737 43499 43500 42738 42739 44251 44918 44251 42739 42739 43501 44918 42740 42741 43469 42742 42741 42740 43472 43469 42741 42741 42754 43472 42741 42742 42754 42742 42753 42754 42757 42753 42742 42742 42756 42757 42746 42745 42743 42749 42746 42743 42743 42744 42749 43498 42749 42744 42744 43494 43498 43496 43494 42744 42745 43507 43508 42745 42746 43507 42746 42749 43498 44268 43507 42746 42746 43498 44268 42747 42748 43486 43511 43486 42748 44277 43511 42750 44282 44277 42750 43514 42752 42751 44285 43514 42751 42751 44284 44285 42751 44270 44284 42751 44269 44270 42751 42784 44269 42768 42767 42752 43514 42768 42752 42757 42755 42753 42755 42754 42753 43491 43490 42754 42754 43489 43491 42754 42755 43489 43474 43472 42754 43490 43474 42754 43520 43489 42755 42755 42757 43520 42760 42757 42756 42757 43517 43520 42757 42760 43517 42780 42766 42758 42758 42765 42780 42761 42760 42759 43516 42761 42759 42759 42771 43516 42773 42771 42759 42760 42761 43517 43518 43517 42761 44288 43518 42761 42761 43516 44288 45652 42777 42762 42762 44958 45652 42762 44951 44958 42762 43522 44951 42762 42763 43522 42763 42764 43513 42763 43513 43522 42766 42783 43515 42766 42780 42783 42767 42771 42773 42772 42771 42767 42767 42769 42772 42767 42768 42769 42770 42769 42768 43514 42770 42768 44298 42772 42769 44960 44298 42769 42769 42770 44960 42770 44296 44960 44297 44296 42770 42770 44295 44297 42770 43514 44295 43523 43516 42771 42771 42772 43523 44299 43523 42772 42772 44298 44299 42793 42789 42774 44300 44293 42775 45651 44300 42775 42775 42776 45651 42777 42776 42775 42776 42777 45652 42776 45650 45651 45652 45650 42776 42778 42785 42787 43526 42782 42779 42779 42792 43526 42782 42780 42779 42780 42782 42783 42781 43527 44304 42781 43526 43527 42781 42782 43526 42783 42782 42781 44304 42783 42781 43524 43515 42783 44304 43524 42783 42784 43502 44269 42785 42786 42787 42798 42786 42785 42795 42787 42786 43525 42795 42786 42786 42798 43525 42795 42790 42787 42796 42791 42790 42801 42796 42790 42790 42795 42801 42796 42792 42791 42792 42796 43529 43529 43526 42792 44303 44302 42793 42793 44300 44303 44301 44300 42793 42793 44292 44301 42793 43521 44292 42803 42802 42794 44306 42803 42794 42794 44303 44306 42794 44302 44303 43528 42801 42795 42795 42799 43528 43525 42799 42795 43530 43529 42796 42796 42801 43530 42798 42799 43525 43535 43528 42799 42799 42800 43535 43536 43535 42800 44317 43536 42800 42801 43528 43538 43537 43530 42801 43538 43537 42801 42802 42803 43552 42803 43551 43552 44316 43551 42803 44322 44316 42803 42803 44306 44322 42819 42818 42804 44319 42819 42804 42804 42809 44319 42804 42807 42809 42804 42805 42807 42806 42805 42804 42818 42806 42804 42808 42807 42805 42811 42808 42805 42805 42806 42811 42812 42811 42806 42817 42812 42806 42818 42817 42806 43542 42809 42807 42807 43541 43542 42807 42810 43541 42807 42808 42810 42811 42810 42808 44321 44319 42809 42809 44314 44321 42809 44313 44314 42809 43542 44313 43550 43541 42810 42810 42822 43550 42810 42821 42822 42810 42811 42821 42811 42812 42821 42823 42821 42812 42824 42823 42812 42812 42820 42824 42812 42817 42820 43558 42814 42813 42813 43551 43558 43562 42830 42814 44331 43562 42814 42814 43558 44331 43563 42816 42815 44336 43563 42815 43563 42839 42816 42817 42818 42820 42818 42819 42820 43565 42820 42819 43566 43565 42819 44337 43566 42819 42819 44334 44337 42819 44320 44334 42819 44319 44320 42832 42824 42820 43571 42832 42820 42820 43565 43571 42823 42822 42821 42822 42825 43550 42822 42823 42825 42826 42825 42823 42831 42826 42823 42823 42824 42831 42832 42831 42824 42825 42826 42827 42825 43549 43550 42825 42827 43549 42827 42828 43549 43557 43549 42828 43567 42834 42829 43568 43567 42829 43569 43568 42829 44335 43569 42829 42829 43560 44335 43561 43560 42830 43562 43561 42830 42831 42833 42836 42831 42832 42833 44353 42833 42832 42832 43571 44353 42840 42836 42833 43574 42840 42833 43575 43574 42833 44353 43575 42833 43567 43556 42834 42835 43573 44341 42839 42838 42837 42837 42838 42843 42838 43564 44336 42838 42839 43564 44369 42843 42838 45022 44369 42838 42838 44346 45022 44347 44346 42838 42838 44336 44347 42839 43563 43564 44354 42842 42841 42841 43577 44354 42841 43576 43577 42842 44354 44355 44369 42844 42843 45723 45027 42844 42844 45025 45723 42844 44369 45025 45026 43585 42844 45027 45026 42844 42845 43578 43579 42846 43582 43583 46304 45691 42848 46306 46304 42848 46315 46306 42848 42848 45023 46315 44366 43582 42849 44367 44366 42849 42849 42851 44367 42849 42850 42851 43580 42851 42850 42851 44364 44367 42851 43580 44364 43593 42853 42852 42852 43591 43593 42852 43590 43591 42852 43589 43590 42852 43584 43589 42853 43593 43595 42857 42856 42854 42876 42857 42854 42854 42855 42876 42856 42857 45023 42857 42876 45023 43589 42862 42858 43597 43589 42858 42858 42863 43597 42858 42859 42863 42860 42859 42858 42862 42860 42858 42872 42863 42859 42859 42870 42872 42859 42861 42870 42859 42860 42861 43586 42861 42860 43592 43586 42860 42860 42862 43592 43588 42870 42861 42861 43587 43588 42861 43586 43587 43589 43584 42862 42862 43584 43592 42863 42875 43597 42863 42873 42875 42874 42873 42863 42863 42872 42874 42864 42867 43588 42877 42867 42864 42881 42877 42864 43603 42881 42864 42864 43602 43603 42864 43601 43602 42864 42865 43601 42866 42865 42864 43587 42866 42864 43588 43587 42864 45030 43601 42865 45031 45030 42865 42865 45029 45031 42865 42866 45029 42866 44370 45029 42866 43586 44370 43587 43586 42866 42867 42870 43588 42867 42868 42870 42869 42868 42867 42877 42869 42867 42878 42871 42868 42868 42877 42878 42868 42869 42877 42871 42870 42868 42870 42871 42872 42871 42878 42883 42882 42872 42871 42883 42882 42871 42882 42874 42872 42880 42875 42873 42873 42874 42880 43609 42880 42874 42874 42882 43609 42875 42880 43598 45732 45023 42876 42876 45730 45732 42876 43611 45730 42879 42878 42877 42881 42879 42877 42878 42879 42883 43615 42883 42879 42879 43613 43615 43614 43613 42879 42879 43612 43614 42879 42881 43612 43616 43598 42880 42880 43608 43616 43609 43608 42880 42881 43603 43612 44384 43609 42882 42882 44382 44384 42882 42883 44382 42883 43615 44382 42884 43598 43610 43626 42887 42885 42885 43623 43626 43626 43624 42887 42888 43641 44391 43642 43641 42888 42888 42889 43642 42889 43636 43642 42889 43633 43636 42889 42890 43633 43634 42892 42891 42891 42893 43634 42893 42895 43634 42893 42894 42895 42898 42894 42893 42894 42898 43646 42896 42895 42894 43646 42896 42894 42895 43633 43634 44394 43633 42895 42895 42896 44394 42896 43646 44396 44395 44394 42896 44396 44395 42896 43646 42898 42897 42897 42900 43646 43648 43640 42899 44396 43646 42900 42900 42901 44396 44401 44396 42901 42901 43658 44401 42901 42903 43658 43653 42904 42902 42902 43651 43653 43659 43658 42903 44402 43659 42903 42903 43660 44402 44403 43663 42904 42904 43653 44403 42905 42906 42911 42907 42906 42905 43673 42907 42905 43685 43673 42905 42905 42911 43685 42906 42907 42908 43662 42909 42907 46395 43662 42907 42907 43673 46395 43662 43661 42909 42910 43667 43671 42911 42916 43685 42911 42915 42916 42912 44424 44425 45067 44424 42912 42912 45064 45067 42912 42913 45064 42914 42913 42912 43674 42914 42912 42913 42914 43675 42913 43677 45064 42913 43672 43677 43675 43672 42913 42914 43674 43675 42919 42916 42915 42915 42917 42919 42916 43676 43685 42916 42919 43676 43684 42919 42917 43688 42922 42918 44425 43688 42918 42918 44420 44425 42918 43682 44420 43683 43676 42919 43684 43683 42919 42920 43683 43684 42920 42928 43683 42920 42921 42928 42921 42927 42928 42921 42923 42927 43693 43690 42922 42922 43688 43693 42924 42927 42930 42924 42925 42927 42926 42925 42924 43695 42926 42924 42924 42930 43695 42925 42926 43689 42928 42927 42925 43683 42928 42925 42925 43676 43683 43689 43676 42925 43695 43689 42926 42930 42934 43695 42930 42931 42934 42932 42931 42930 43697 42934 42931 42931 42933 43697 43698 43697 42933 42934 43697 44448 43696 43695 42934 44448 43696 42934 42935 42936 42940 42937 42936 42935 43700 42937 42935 43714 43700 42935 42935 43701 43714 42935 42940 43701 43715 42938 42937 42937 43700 43715 43715 42953 42938 42953 42947 42938 43702 42940 42939 42939 42941 43702 43702 43701 42940 43716 43702 42941 44451 43716 42941 42941 42942 44451 42943 42942 42941 42944 42943 42941 42942 43699 44451 42942 42943 43699 42943 42944 43699 42944 42945 43699 42945 43703 44454 44452 43699 42945 42945 43704 44452 43705 43704 42945 44454 43705 42945 43717 42949 42946 42946 43706 43717 42952 42951 42947 42953 42952 42947 42949 43717 43720 43737 42957 42950 42950 42962 43737 42950 42951 42962 42963 42962 42951 42951 42952 42963 42952 42953 42956 42964 42963 42952 42952 42956 42964 42955 42954 42953 42965 42955 42953 43714 42965 42953 43715 43714 42953 42953 42954 42956 42954 42955 42964 42964 42956 42954 42965 42964 42955 43737 43736 42957 43737 42962 42958 43741 43737 42958 43743 43741 42958 44478 43743 42958 45123 44478 42958 42958 42959 45123 42960 42959 42958 42961 42960 42958 42962 42961 42958 45813 45123 42959 45814 45813 42959 42959 42960 45814 42960 44473 45814 42960 42961 44473 42961 44466 44473 42961 42963 44466 42961 42962 42963 42963 43728 44466 42963 42964 43728 42964 42965 42967 43729 43728 42964 43730 43729 42964 42964 42966 43730 42967 42966 42964 43714 42967 42965 42966 43718 43719 42966 42967 43718 43732 43730 42966 42966 43719 43732 43714 43713 42967 42967 43716 43718 42967 43713 43716 43736 43735 42968 42971 42970 42969 45139 43725 42969 42969 45133 45139 42969 42970 45133 42970 42971 42973 42970 43745 45133 42970 43744 43745 43746 43744 42970 42970 42973 43746 42972 43741 43742 44471 43741 42972 42973 42978 43746 42973 42977 42978 43742 42975 42974 42978 42979 42980 43747 43746 42978 42978 42980 43747 42984 42983 42981 42981 42982 42984 43749 42984 42982 42983 42984 43750 42984 43749 43750 42988 42987 42986 43754 42988 42986 42986 42993 43754 43754 42994 42988 44486 43751 42989 44490 44486 42989 45143 44490 42989 42989 42990 45143 42990 44484 45143 44485 44484 42990 45142 44485 42990 42996 42992 42991 44488 42996 42991 42991 44487 44488 43753 42993 42992 42992 42995 43753 42996 42995 42992 42993 43753 43754 43754 42998 42994 43762 43753 42995 44496 43762 42995 42995 43759 44496 42995 42996 43759 42996 43758 43759 44488 43758 42996 42997 42998 43754 43762 43761 42997 42997 43753 43762 43754 43753 42997 43763 43000 42999 43000 43763 43764 43766 43757 43001 43001 43765 43766 43001 43002 43765 44495 43765 43002 44499 44495 43002 43002 43764 44499 43005 43004 43003 44514 44513 43004 43004 43773 44514 43004 43772 43773 43004 43771 43772 43004 43005 43771 44516 43772 43006 44517 44516 43006 43006 43007 44517 43007 43778 44517 43779 43778 43007 43007 43776 43779 43010 43009 43008 43777 43010 43008 43008 43015 43777 43008 43011 43015 43009 43010 43018 43009 43016 43019 43018 43016 43009 44522 43018 43010 43010 44515 44522 43010 43777 44515 43768 43015 43011 43780 43021 43012 43012 43775 43780 43012 43774 43775 43013 43014 43789 43789 43023 43013 44515 43777 43015 43015 44511 44515 43015 43769 44511 43770 43769 43015 43015 43768 43770 43016 43793 43795 43016 43017 43793 43018 43017 43016 43794 43793 43017 44521 43794 43017 43017 43018 44521 44522 44521 43018 43020 43025 43028 43027 43025 43020 43788 43787 43021 43021 43780 43788 43022 43781 43782 43022 43023 43781 44525 43781 43023 43023 43789 44525 43024 43029 43792 43035 43029 43024 43039 43028 43025 43807 43039 43025 43811 43807 43025 43025 43026 43811 43027 43026 43025 43026 43799 43811 43026 43796 43799 43026 43027 43796 43798 43796 43027 43039 43032 43028 44527 43792 43029 43029 43030 44527 43031 43030 43029 43035 43031 43029 45189 44527 43030 45191 45189 43030 43030 44531 45191 43030 43031 44531 44532 44531 43031 43031 43808 44532 43031 43802 43808 43031 43038 43802 43031 43035 43038 43040 43036 43032 43032 43039 43040 43035 43034 43033 43038 43035 43033 43801 43038 43033 43048 43047 43036 43036 43040 43048 43814 43800 43037 43037 43052 43814 43038 43801 43802 43807 43040 43039 43058 43048 43040 43807 43058 43040 43061 43060 43041 43042 43043 43056 43044 43043 43042 43046 43044 43042 44534 43817 43043 43043 43803 44534 43043 43045 43803 43043 43044 43045 43810 43045 43044 43044 43057 43810 43044 43046 43057 43804 43803 43045 43810 43804 43045 43068 43057 43046 43047 43048 43073 43073 43059 43047 43048 43058 43073 43049 43053 43822 43815 43053 43049 45219 43815 43049 45223 45219 43049 43049 43050 45223 43051 43050 43049 43822 43051 43049 45231 45223 43050 45232 45231 43050 43050 43841 45232 43050 43051 43841 43052 43053 43814 43815 43814 43053 43820 43084 43054 43054 43055 43820 44551 43820 43055 43055 44533 44551 43055 43817 44533 43057 43068 43069 43818 43810 43057 43057 43069 43818 44552 43073 43058 43058 44548 44552 43058 44541 44548 43058 43807 44541 43059 43073 43074 43100 43079 43061 43061 43062 43100 43101 43100 43063 43823 43101 43063 43063 43066 43823 43823 43066 43064 44550 43823 43064 43064 44549 44550 43064 43065 44549 43065 43070 44549 43824 43070 43067 43067 43080 43824 43069 43071 43818 44567 44549 43070 43070 43824 44567 45210 43818 43071 43071 44558 45210 45228 44558 43071 43071 43825 45228 43071 43072 43825 43821 43074 43073 43073 43076 43821 44552 43076 43073 43076 43075 43074 43821 43076 43074 44565 43832 43076 44566 44565 43076 43076 44564 44566 43076 44552 44564 43078 43093 43099 43078 43079 43093 43819 43093 43079 43079 43100 43819 43827 43824 43080 43835 43827 43080 43829 43086 43081 43836 43829 43081 43081 43087 43836 43089 43088 43082 43082 43083 43089 43099 43089 43083 43084 43820 44557 43085 43820 44551 44557 43820 43085 44551 44543 43085 43828 43825 43086 43829 43828 43086 43099 43093 43088 43088 43089 43099 43840 43113 43090 43092 43819 43826 43092 43093 43819 43094 43095 43125 43094 43845 44570 43847 43845 43094 43094 43156 43847 43094 43125 43156 43098 43097 43096 44576 43098 43096 43103 43102 43097 43097 43098 43103 44584 43103 43098 43098 44577 44584 43098 44576 44577 43834 43819 43100 43100 43101 43834 44553 43834 43101 43101 43823 44553 44585 43104 43102 43102 43103 44585 44594 44585 43103 43103 44584 44594 45248 43106 43104 43104 45246 45248 43104 44585 45246 43105 43106 45248 43107 43106 43105 43111 43107 43105 45249 43111 43105 43105 45248 45249 43110 43108 43107 43111 43110 43107 44596 43849 43108 43108 43110 44596 43855 43114 43109 43109 43849 43855 45249 44596 43110 43110 43111 45249 43112 44588 45240 43112 43848 44588 43112 43113 43848 43113 43840 43848 43116 43115 43114 43855 43116 43114 43862 43121 43115 43863 43862 43115 45255 43863 43115 43115 43116 45255 43116 45253 45255 43116 43855 45253 43120 43118 43117 43122 43119 43118 43124 43122 43118 43118 43120 43124 43145 43133 43119 43119 43122 43145 43135 43124 43120 43858 43135 43120 43859 43858 43120 43120 43857 43859 43120 43844 43857 43862 43152 43121 43873 43145 43122 43122 43123 43873 43124 43123 43122 43123 43135 43146 43123 43124 43135 43883 43873 43123 43123 43146 43883 43125 43126 43156 43126 43860 45242 45254 43156 43126 43126 45242 45254 43127 43128 43138 43139 43138 43128 43870 43139 43128 44603 43870 43128 43864 43130 43129 44609 43864 43129 44610 44609 43129 43129 43865 44610 43129 43134 43865 43129 43132 43134 43864 43131 43130 44620 43142 43131 43131 44609 44620 43131 43864 44609 43132 43133 43134 43145 43134 43133 43872 43865 43134 43134 43145 43872 43135 43858 43866 43866 43146 43135 43136 43137 43868 43869 43868 43137 43137 43138 43869 43138 43139 43869 44612 43869 43139 44615 44612 43139 43139 43870 44615 44605 43141 43140 45268 44605 43140 44605 44604 43141 43144 43143 43142 45261 43144 43142 43142 44620 45261 43887 43882 43143 43143 43144 43887 45261 43887 43144 43873 43872 43145 43146 43877 43883 43146 43866 43877 43147 43148 43150 43149 43148 43147 43878 43149 43147 43147 43150 43878 43151 43150 43148 43155 43151 43148 43884 43155 43148 44624 43884 43148 43148 44611 44624 43148 43149 44611 45278 44611 43149 45279 45278 43149 43149 45264 45279 43149 43878 45264 43150 43868 43878 43155 43153 43151 44616 43871 43152 43152 44607 44616 43152 43863 44607 43152 43862 43863 43153 43154 43170 43155 43154 43153 44628 43169 43154 44633 44628 43154 43154 43889 44633 43154 43888 43889 43154 43155 43888 43154 43169 43170 43155 43884 43888 45254 43847 43156 43158 44634 44635 43176 43162 43160 43160 43161 43176 43904 43176 43161 43162 43894 43908 43895 43894 43162 43906 43895 43162 43907 43906 43162 43162 43176 43907 43911 43892 43163 43163 43890 43911 43891 43890 43163 43164 43913 44632 43164 43190 43913 43164 43173 43190 43165 47263 48007 43165 44626 47263 43166 43167 43899 43167 43898 43899 44628 43893 43169 43911 43910 43171 43171 43892 43911 43910 43172 43171 43923 43183 43172 43172 43910 43923 43173 43185 43190 43173 43179 43185 43173 43177 43179 43174 43915 43916 44637 43915 43174 44638 44637 43174 43176 43905 43907 43176 43904 43905 43917 43903 43178 44649 43898 43180 44658 44649 43180 43180 43192 44658 43924 43192 43180 43180 43181 43924 43181 43192 43924 43926 43917 43182 43182 43925 43926 43182 43186 43925 43183 43921 43922 43923 43921 43183 43189 43185 43184 43210 43189 43184 43185 43189 43190 43186 43195 43925 43204 43195 43186 43187 43188 43207 43191 43190 43189 45322 43191 43189 45332 45322 43189 43189 43932 45332 43189 43210 43932 43190 43897 43913 43190 43896 43897 43190 43191 43896 45976 43896 43191 43191 45332 45976 43191 45322 45332 43193 43203 43934 43193 43202 43203 44664 43948 43194 45329 43925 43195 43195 43196 45329 43197 43196 43195 43204 43197 43195 45336 45329 43196 43196 43950 45336 43196 43197 43950 44682 43950 43197 43200 43199 43198 43201 43200 43198 43199 43929 43944 43199 43200 43929 43931 43929 43200 43940 43931 43200 43200 43939 43940 43200 43201 43939 43945 43939 43201 43201 43937 43945 43201 43206 43937 43947 43203 43202 43952 43947 43202 44676 43952 43202 44689 44676 43202 45985 44689 43202 43202 43928 45985 43942 43934 43203 43953 43942 43203 43203 43952 43953 43203 43947 43952 43951 43938 43206 43938 43937 43206 45339 44672 43207 45341 45339 43207 43207 45326 45341 43221 43209 43208 43208 43220 43221 43221 43210 43209 43946 43932 43210 43210 43221 43946 43935 43212 43211 43212 43218 43219 43961 43218 43212 43212 43958 43961 43212 43935 43958 44693 43215 43213 43213 43216 44693 44692 44682 43215 45364 44692 43215 43215 45363 45364 43215 44693 45363 44694 44693 43216 43216 44684 44694 44687 43957 43217 45352 44687 43217 43217 44688 45352 43217 43960 44688 43963 43219 43218 43964 43963 43218 44704 43964 43218 43218 44703 44704 43218 43961 44703 44675 43221 43220 43220 43223 44675 43220 43222 43223 44675 43946 43221 43224 43223 43222 45366 44675 43223 43223 44699 45366 43223 43224 44699 44716 43226 43225 43225 44700 44716 46030 44699 43226 43226 45375 46030 43226 44716 45375 43966 43960 43228 43231 43975 43977 44708 43967 43232 43232 43237 44708 43238 43235 43233 43981 43238 43233 43233 43979 43981 43980 43979 43233 43965 43236 43234 43234 43238 43965 43234 43235 43238 43236 43965 43966 44714 44708 43237 43237 43974 44714 43969 43965 43238 43970 43969 43238 43981 43970 43238 43239 44711 44719 43239 43973 44711 43241 43244 43978 43968 43249 43242 43242 43963 43968 43978 43244 43243 43987 43978 43243 43988 43987 43243 43243 43257 43988 43245 43246 43267 43247 43246 43245 43248 43247 43245 43246 43265 43267 43266 43265 43246 44727 43266 43246 43246 43247 44727 43247 44726 44727 43247 43989 44726 43247 43252 43989 43247 43248 43252 43249 44723 45403 43249 43968 44723 43996 43251 43250 44733 43996 43250 43250 44000 44733 43250 43995 44000 43252 43253 43989 44729 43989 43253 43990 43255 43254 43254 43982 43990 43990 43269 43255 43256 43259 43992 43994 43988 43257 43257 43258 43994 43258 43993 43994 43258 43275 43993 43276 43275 43258 43258 43274 43276 43262 43261 43260 43263 43262 43260 43264 43263 43260 44003 43264 43260 44749 44003 43260 44750 44749 43260 43260 43261 44750 43261 43262 44737 43261 44018 44750 43261 44011 44018 44737 44011 43261 44738 44737 43262 43262 44730 44738 43262 43984 44730 43262 43983 43984 43998 43268 43265 44742 43998 43265 43265 43266 44742 43268 43267 43265 45402 44742 43266 43266 44726 45402 44727 44726 43266 43998 43278 43268 44735 44734 43269 43269 43990 44735 44004 43272 43270 43270 43271 44004 44755 44004 43271 43271 44003 44755 43283 43273 43272 44754 43283 43272 43272 44004 44754 43284 43274 43273 43273 43283 43284 43284 43276 43274 43275 43276 43277 44731 43993 43275 44740 44731 43275 43275 44005 44740 44006 44005 43275 43275 43277 44006 43284 43277 43276 44012 44006 43277 43277 43284 44012 43278 43999 44743 43278 43998 43999 43280 43282 44011 44009 43281 43280 44748 44009 43280 43280 44011 44748 44010 43992 43281 43281 44009 44010 44013 43284 43283 44759 44013 43283 43283 44754 44759 44016 44012 43284 43284 44013 44016 43286 43292 44026 44029 44023 43288 43288 43289 44029 43290 43289 43288 45433 43290 43288 43288 45431 45433 43288 44024 45431 43288 44023 44024 44767 44029 43289 45435 44767 43289 43289 43290 45435 46066 45435 43290 46067 46066 43290 43290 45433 46067 44027 44026 43292 44030 44027 43292 43292 43294 44030 44031 44030 43294 43294 43295 44031 44032 44031 43295 44033 44032 43295 44036 44033 43295 44041 44040 43297 43297 44039 44041 43297 43298 44039 43300 43303 43304 43300 43301 43303 44046 43304 43303 43303 44044 44046 43304 44046 44047 43305 43306 43307 43310 43306 43305 43308 43307 43306 44050 43308 43306 44775 44052 43308 43308 44050 44775 43311 44055 44773 44060 43316 43312 43312 44051 44060 44061 43322 43313 44067 44061 43313 44777 44067 43313 43313 44054 44777 43326 43315 43314 43328 43326 43314 43314 43323 43328 44058 44050 43315 43315 43326 44058 43318 43317 43316 44060 43318 43316 43317 43318 43319 43336 43319 43318 44060 43336 43318 43330 43329 43319 43336 43330 43319 43320 43339 44055 43320 43338 43339 43325 43323 43321 43321 43322 43325 44061 43325 43322 43323 43324 43328 43325 43324 43323 43332 43328 43324 43359 43332 43324 44069 43359 43324 43324 43325 44069 43325 44068 44069 43325 44061 44068 44062 44058 43326 43326 43331 44062 43326 43327 43331 43328 43327 43326 43327 43328 43332 43335 43333 43330 43336 43335 43330 44063 44062 43331 43331 43340 44063 43332 43359 43363 43333 43334 43341 43335 43334 43333 44071 43340 43334 43334 43335 44071 43335 44070 44071 43335 44064 44070 43335 43336 44064 43336 44060 44064 43352 43346 43337 44065 43339 43338 44776 44055 43339 44782 44776 43339 43339 44065 44782 44071 44063 43340 46084 44074 43342 43342 43349 46084 43342 43343 43349 43344 43343 43342 44074 43344 43342 43351 43349 43343 43343 43346 43351 43343 43344 43346 43344 43345 43346 43347 43345 43344 43352 43351 43346 44085 43365 43348 44795 44085 43348 43348 44082 44795 43348 44077 44082 43349 43350 46084 43351 43350 43349 46085 46084 43350 43350 43351 46085 46729 46085 43351 43351 45461 46729 43351 44800 45461 43351 44799 44800 43351 44078 44799 43351 43353 44078 43351 43352 43353 43360 43353 43352 43353 43360 44078 44082 44077 43354 43356 43357 44083 43358 43357 43356 44796 43358 43356 44797 44796 43356 43356 44083 44797 44796 44793 43358 44069 44068 43359 44787 43363 43359 43359 44072 44787 43359 44068 44072 43360 43361 44078 43361 43368 44078 44794 44079 43363 43363 44787 44794 44089 43375 43364 45462 44089 43364 43364 45459 45462 43364 44081 45459 44085 43369 43365 44080 43368 43367 43367 43373 44080 43367 43372 43373 44080 44078 43368 44084 43379 43369 44085 44084 43369 44803 44083 43370 44807 44803 43370 43370 44107 44807 43370 43371 44107 43374 43373 43372 44801 43374 43372 43372 44092 44801 44799 44080 43373 43373 43374 44799 45467 44799 43374 43374 44801 45467 43378 43377 43376 43380 43378 43376 43377 43378 43380 43377 43380 44090 44093 43388 43379 44094 44093 43379 43379 44084 44094 43380 43381 44101 46099 44090 43380 43380 45483 46099 43380 44818 45483 43380 44101 44818 43381 43384 44101 44824 44106 43382 43382 44823 44824 43382 43383 44823 43383 44822 44823 43383 44104 44822 44117 44101 43384 43384 44116 44117 43384 43389 44116 44816 44114 43385 43385 44815 44816 43385 43386 44815 43386 44091 44097 43386 44098 44815 43386 44097 44098 43387 44135 44811 43387 44123 44135 43387 43393 44123 44808 44092 43387 44811 44808 43387 44128 44116 43389 44129 44128 43389 43389 43396 44129 43389 43395 43396 43398 43395 43389 44123 43393 43390 43390 43391 44123 43392 43391 43390 43394 43392 43390 43390 43393 43394 44137 44123 43391 44140 44137 43391 43391 44139 44140 43391 43392 44139 43392 44134 44139 43392 44113 44134 43397 43396 43395 43396 44124 44129 45490 44124 43396 43396 44127 45490 43396 43397 44127 43397 44115 44127 44119 43400 43399 43399 44111 44119 43402 43401 43400 44119 43402 43400 43404 43403 43401 43401 43402 43404 43405 43404 43402 44119 43405 43402 43403 43404 44141 44141 43406 43403 44147 44146 43404 44840 44147 43404 44841 44840 43404 43404 44130 44841 43404 43405 44130 44146 44141 43404 43405 44119 44130 43406 43407 44151 43408 43407 43406 44141 43408 43406 44846 44151 43407 45524 44846 43407 43407 44152 45524 43407 44147 44152 43407 43408 44147 43408 44146 44147 43408 44141 44146 44164 44163 43409 43409 43410 44164 43410 43411 44168 44165 44164 43410 44168 44165 43410 44169 44168 43411 44170 44169 43411 43411 43412 44170 43412 44857 44858 44859 44857 43412 44858 44170 43412 43416 43414 43413 44854 43416 43413 44856 44854 43413 43413 44853 44856 43413 44175 44853 43416 43417 44181 43418 43417 43416 44854 43418 43416 44185 44181 43417 45544 44185 43417 43417 43418 45544 43418 45536 45544 43418 44855 45536 43418 44854 44855 43419 44177 44186 43419 43420 44177 44865 44176 43419 44872 44865 43419 43419 44186 44872 43420 43422 44177 43423 43422 43420 44186 44177 43422 45563 44182 43424 43424 45554 45563 43424 44869 45554 43424 43425 44869 43425 44178 44869 44872 44186 43426 44875 44872 43426 43426 44193 44875 45572 44188 43427 43427 44877 45572 44878 44877 43427 43427 44199 44878 44198 43430 43429 44201 44198 43429 44888 44193 43431 43431 43446 44888 44204 44203 43432 43433 44187 44208 43449 43448 43434 44209 43449 43434 43434 43435 44209 43436 43435 43434 44223 44209 43435 44885 44223 43435 43435 44196 44885 43435 43436 44196 44886 43444 43438 43438 44210 44886 43438 43442 44210 43439 44206 44226 43439 43445 44206 43441 44202 44207 44215 44210 43442 43443 43444 44886 43445 43444 43443 44887 43445 43443 43443 44886 44887 44891 44206 43445 43445 44887 44891 44899 44888 43446 43446 44218 44899 44227 43450 43447 44897 43452 43449 43449 44224 44897 43449 44223 44224 43449 44209 44223 44234 43459 43450 44235 44234 43450 44911 44235 43450 45587 44911 43450 43450 44227 45587 45585 44216 43452 43452 44897 45585 44228 43462 43453 43453 43457 44228 43454 44895 44901 43454 44214 44895 43454 43455 44214 43456 43462 44218 45596 44228 43457 45608 45596 43457 46212 45608 43457 43457 44919 46212 43459 44234 44237 44905 44212 43460 45617 44905 43460 43460 43461 45617 43461 45613 45617 43461 44251 45613 44228 44218 43462 43463 43470 43471 43463 43469 43470 43464 43465 43467 43466 43465 43464 45607 43466 43464 43464 44240 45607 44239 43496 43465 43465 43466 44239 45604 44239 43466 46209 45604 43466 43466 45605 46209 45606 45605 43466 45607 45606 43466 44259 43488 43468 43468 44256 44259 43472 43470 43469 43470 43472 43473 43473 43471 43470 44233 44230 43471 43471 43473 44233 43474 43473 43472 43473 43475 44233 43473 43474 43475 43476 43475 43474 43477 43476 43474 43478 43477 43474 43490 43478 43474 44913 44233 43475 44921 44913 43475 43475 44242 44921 43475 43476 44242 43476 44241 44242 44243 44241 43476 43476 43477 44243 43477 43479 44243 43477 43478 43479 43490 43479 43478 43479 43481 44243 43493 43481 43479 43479 43490 43493 43480 43481 43493 43482 43481 43480 44245 43482 43480 44246 44245 43480 44266 44246 43480 43480 43492 44266 43493 43492 43480 44244 44243 43481 43481 43482 44244 44922 44244 43482 43482 44247 44922 44249 44247 43482 44257 44249 43482 43482 44245 44257 43485 43484 43483 44258 43485 43483 43483 43500 44258 43510 43487 43486 43511 43510 43486 44939 43501 43487 44940 44939 43487 43487 44276 44940 43487 44275 44276 44281 44275 43487 43487 43510 44281 44259 43502 43488 44947 43491 43489 43489 44291 44947 43489 43520 44291 43490 43491 43492 43490 43492 43493 44265 43492 43491 44929 44265 43491 44947 44929 43491 43492 44265 44266 43494 43497 43498 43494 43495 43497 43496 43495 43494 44246 43497 43495 43495 44245 44246 44250 44245 43495 43495 43496 44250 44239 44238 43496 43496 44238 44250 43512 43498 43497 43497 43503 43512 44246 43503 43497 43498 43512 44268 44272 43500 43499 43499 43508 44272 44273 44258 43500 43500 44272 44273 44939 44918 43501 43502 44262 44269 43502 44259 44262 44944 43512 43503 43503 43504 44944 43505 43504 43503 44246 43505 43503 43504 44930 44944 43504 44267 44930 43504 43505 44267 43505 44266 44267 43505 44246 44266 43506 43507 43509 43508 43507 43506 44272 43508 43506 44938 44272 43506 44944 44938 43506 43506 43512 44944 43506 43509 43512 44268 43509 43507 44268 43512 43509 43510 43511 44277 44282 44281 43510 43510 44277 44282 44274 43522 43513 43514 44285 44295 43515 44279 44282 44280 44279 43515 43515 43524 44280 44289 44288 43516 44290 44289 43516 43516 43523 44290 43517 43519 43520 43517 43518 43519 44286 43519 43518 44288 44286 43518 44291 43520 43519 43519 44286 44291 44294 44292 43521 43521 44293 44294 43522 44274 44951 44299 44290 43523 44967 44280 43524 43524 44305 44967 43524 44304 44305 43529 43527 43526 43527 43533 44304 43527 43531 43533 43527 43529 43531 43528 43536 43553 43528 43535 43536 43553 43538 43528 43529 43530 43537 43537 43531 43529 44312 43533 43531 43531 43539 44312 43531 43537 43539 44329 44318 43532 43532 44312 44329 43532 43533 44312 43534 43533 43532 44318 43534 43532 43533 43534 44304 44981 44304 43534 43534 44318 44981 44317 43553 43536 43540 43539 43537 43537 43538 43540 43548 43540 43538 43553 43548 43538 44328 44312 43539 43539 43548 44328 43539 43540 43548 43550 43547 43541 43543 43542 43541 43544 43543 43541 43545 43544 43541 43547 43545 43541 43542 43543 44313 44984 44313 43543 43543 44983 44984 43543 44307 44983 43543 43544 44307 43544 43546 44307 43544 43545 43546 43547 43546 43545 44308 44307 43546 44309 44308 43546 44310 44309 43546 44315 44310 43546 43546 43547 44315 43550 43549 43547 43547 43555 44315 43547 43549 43555 44996 44328 43548 43548 44325 44996 43548 43554 44325 43548 43553 43554 43557 43555 43549 44992 43558 43551 43551 44991 44992 44995 44991 43551 43551 44316 44995 44317 43554 43553 43554 44324 44325 43554 44323 44324 43554 44317 44323 44986 44315 43555 43555 43567 44986 44330 43567 43555 43555 43556 44330 43557 43556 43555 43556 43567 44330 43558 43561 44331 44992 43561 43558 44324 43570 43559 44325 44324 43559 45000 44325 43559 45008 45000 43559 43560 43561 44335 44994 44335 43561 43561 44990 44994 44992 44990 43561 43561 43562 44331 44336 43564 43563 43565 43566 43571 43572 43571 43566 44337 43572 43566 43567 43568 44986 45663 44986 43568 43568 43569 45663 45670 45663 43569 45671 45670 43569 43569 44994 45671 43569 44335 44994 44323 44317 43570 44324 44323 43570 43571 44351 44353 43571 44350 44351 43571 43572 44350 43572 44349 44350 43572 44348 44349 45005 44348 43572 43572 44334 45005 44342 44334 43572 43572 44337 44342 44344 44341 43573 44355 44344 43573 45013 43581 43574 43574 44359 45013 43574 43575 44359 43575 44358 44359 43575 44353 44358 44360 43577 43576 43576 43579 44360 45010 44354 43577 43577 44361 45010 43577 44360 44361 44363 43579 43578 43578 44362 44363 43578 43583 44362 44363 44360 43579 44365 44364 43580 45024 44365 43580 43580 43581 45024 43581 45013 45024 44366 43583 43582 44366 44362 43583 43584 43585 43592 45032 43592 43585 45726 45032 43585 43585 45026 45726 44371 44370 43586 43586 43592 44371 43596 43590 43589 43597 43596 43589 43590 43596 44372 44372 43591 43590 43594 43593 43591 44372 43594 43591 45032 44371 43592 43593 43594 43597 43594 43596 43597 44372 43596 43594 43616 43610 43598 43605 43602 43599 43607 43605 43599 44373 43607 43599 44374 44373 43599 44375 44374 43599 45034 44375 43599 43599 43600 45034 43601 43600 43599 43602 43601 43599 43600 43601 45030 45728 45034 43600 45729 45728 43600 43600 45030 45729 43604 43603 43602 43605 43604 43602 43603 43606 43612 43603 43604 43606 43604 43605 43606 43607 43606 43605 45041 43612 43606 43606 44379 45041 43606 44378 44379 43606 43607 44378 43607 44373 44378 43621 43616 43608 44385 43621 43608 43608 43609 44385 43609 44384 44385 43610 43622 43623 43610 43616 43622 47759 45730 43611 43611 43617 47759 44381 43614 43612 45041 44381 43612 44383 44382 43613 45737 44383 43613 43613 43614 45737 44382 43615 43613 43614 45736 45737 43614 44381 45736 43616 43621 43622 47747 47746 43617 43617 43619 47747 43617 43618 43619 43617 47746 47759 43620 43619 43618 43619 43620 43627 47752 47747 43619 48434 47752 43619 48435 48434 43619 43619 47737 48435 43619 47720 47737 43619 43629 47720 43619 43627 43629 44386 43622 43621 45044 44386 43621 43621 45042 45044 43621 44385 45042 44386 43623 43622 44386 43626 43623 44388 43639 43624 45749 44388 43624 46371 45749 43624 43624 45744 46371 43624 43625 45744 43626 43625 43624 43625 45043 45744 43625 44386 45043 43625 43626 44386 43627 43628 43629 43630 43629 43628 43631 43630 43628 43629 43630 43632 43629 43643 47720 43629 43632 43643 43643 43632 43630 43630 43631 43643 43633 43635 43636 45049 43635 43633 43633 44394 45049 45747 45746 43635 43635 45049 45747 43637 43636 43635 45746 43637 43635 45045 43642 43636 45745 45045 43636 43636 45047 45745 43636 45046 45047 47057 45046 43636 43636 44387 47057 43636 43637 44387 47049 44387 43637 47051 47049 43637 43637 45746 47051 43660 43647 43638 43638 43639 43660 44389 43660 43639 43639 44388 44389 43645 43644 43640 43650 43645 43640 43640 43648 43650 45051 44393 43641 43641 45048 45051 43641 45045 45048 43641 43642 45045 44393 44391 43641 43643 46392 47720 43643 43644 46392 43644 44390 46392 43644 43645 44390 43645 43650 44390 43661 43650 43648 43652 43651 43649 44391 43652 43649 43650 43662 44390 43650 43661 43662 43651 43652 43653 43652 44398 44400 44399 44398 43652 43652 44391 44399 43654 43653 43652 44400 43654 43652 43653 43654 44403 44404 44403 43654 45061 44404 43654 43654 44400 45061 45763 45062 43655 46387 45763 43655 43655 44404 46387 43655 43656 44404 43657 43656 43655 45062 43657 43655 43656 44403 44404 43656 43657 44403 43657 43663 44403 43669 43663 43657 45062 43669 43657 43658 43659 44401 45060 44401 43659 43659 44402 45060 43660 44389 44402 45077 44390 43662 46395 45077 43662 43664 43668 43669 43670 43668 43664 43664 43665 43670 43666 43665 43664 45762 43666 43664 43664 45062 45762 43664 43669 45062 45764 43670 43665 46390 45764 43665 43665 43666 46390 43666 46389 46390 43666 45762 46389 43667 43668 43671 43669 43668 43667 43668 43670 43671 43672 43671 43670 45764 43672 43670 43671 43672 43675 45764 43677 43672 47788 46395 43673 43673 43685 47788 43687 43685 43676 43689 43687 43676 46399 45064 43677 46400 46399 43677 43677 45765 46400 43677 45764 45765 43686 43681 43678 43678 43679 43686 43680 43679 43678 43681 43680 43678 44429 43686 43679 43679 44421 44429 43679 43680 44421 43680 44416 44421 43680 43681 44416 44419 44416 43681 43681 43686 44419 47794 47788 43685 43685 47793 47794 43685 43687 47793 44429 44419 43686 43687 47792 47793 47820 47792 43687 43687 44450 47820 43687 43709 44450 43687 43689 43709 45779 43693 43688 43688 45076 45779 43688 44424 45076 44425 44424 43688 43689 43696 43709 43689 43695 43696 43693 43691 43690 43690 43691 43694 43691 43692 45103 43693 43692 43691 43707 43694 43691 45104 43707 43691 43691 45103 45104 43692 45089 45103 45779 45089 43692 43692 43693 45779 43696 43708 43709 44448 43708 43696 43697 43698 44448 43698 43708 44448 44452 44451 43699 43700 43714 43715 43701 43702 43716 43701 43713 43714 43716 43713 43701 45109 44454 43703 44453 44452 43704 44457 44453 43704 44459 44457 43704 43704 43705 44459 45109 44459 43705 43705 44454 45109 44456 43717 43706 43706 44455 44456 45105 44455 43707 43707 45104 45105 43710 43709 43708 45106 44450 43709 43709 44449 45106 43709 43711 44449 43709 43710 43711 43711 43721 44449 43711 43712 43721 43722 43721 43712 43727 43722 43712 43724 43718 43716 44451 43724 43716 45115 43720 43717 43717 45110 45115 43717 44456 45110 43724 43723 43718 43723 43719 43718 44475 43732 43719 43719 43731 44475 43719 43723 43731 45112 44449 43721 43721 43726 45112 43721 43722 43726 43722 43725 43726 43727 43725 43722 43723 43724 43733 43734 43731 43723 44458 43734 43723 43723 43733 44458 44457 43733 43724 43724 44451 44457 44477 43726 43725 43725 44476 44477 45139 44476 43725 43726 44477 45112 43728 43738 44472 43728 43729 43738 44474 44466 43728 43728 44472 44474 43729 43730 43738 43739 43738 43730 43730 43732 43739 43731 43740 44475 43731 43734 43740 45124 43739 43732 45127 45124 43732 43732 44475 45127 43733 44457 44459 44459 44458 43733 44461 43740 43734 43734 44458 44461 43735 43736 44465 43736 43737 44465 43737 43741 44465 43738 43739 44472 45124 44472 43739 45138 44475 43740 43740 44470 45138 43740 44461 44470 44471 44465 43741 43743 43742 43741 45136 45135 43744 43744 44479 45136 43744 43746 44479 45135 43745 43744 43745 44476 45134 45810 44476 43745 43745 45135 45810 45134 45133 43745 43746 43747 44479 44480 44479 43747 43747 43752 44480 43748 43755 44491 43757 43755 43748 44481 43750 43749 43749 44478 44481 46453 45827 43750 43750 45826 46453 43750 45824 45826 43750 44482 45824 43750 44481 44482 45825 44480 43752 43752 45140 45825 45141 45140 43752 45151 44491 43755 45153 45151 43755 43755 43756 45153 43757 43756 43755 43756 44494 45153 43756 43757 44494 43757 43766 44494 44493 44492 43758 43758 44488 44493 43760 43759 43758 44492 43760 43758 44509 44496 43759 43759 43760 44509 45163 44509 43760 43760 44492 45163 43775 43774 43761 44508 43775 43761 43761 44497 44508 43761 43762 44497 43762 44496 44497 44499 43764 43763 44500 44499 43763 44495 43766 43765 44495 44494 43766 43770 43768 43767 44507 43770 43767 45169 44507 43767 43767 44513 45169 43769 44505 44511 44506 44505 43769 43769 43770 44506 45168 44506 43770 43770 44507 45168 45174 43773 43772 43772 44516 45174 45171 44514 43773 45174 45171 43773 43775 44508 44510 45182 43780 43775 43775 44518 45182 43775 44510 44518 44528 43779 43776 43776 43786 44528 44520 44517 43778 45176 44520 43778 45178 45176 43778 43778 44523 45178 43778 43779 44523 44528 44523 43779 45181 43788 43780 45182 45181 43780 43783 43782 43781 44524 43783 43781 44525 44524 43781 43782 44500 44501 43782 44499 44500 45840 44499 43782 43782 45165 45840 43782 43783 45165 46474 45165 43783 43783 45873 46474 43783 44524 45873 43784 43785 43787 43786 43785 43784 44529 43786 43784 45179 44529 43784 45183 45179 43784 45185 45183 43784 43784 45180 45185 43784 43788 45180 43784 43787 43788 44529 44528 43786 45181 45180 43788 44526 44525 43789 43789 43791 44526 43789 43790 43791 44527 43791 43790 43790 43792 44527 45188 44526 43791 43791 45187 45188 43791 44527 45187 45192 43795 43793 43793 43794 45192 43794 45177 45192 43794 44521 45177 44530 43798 43795 45192 44530 43795 43796 43797 43799 43798 43797 43796 44530 43799 43797 43797 43798 44530 45206 43811 43799 43799 45205 45206 45207 45205 43799 43799 44530 45207 43802 43801 43800 44535 43802 43800 43800 43814 44535 44535 43808 43802 45202 44534 43803 43803 43805 45202 43803 43804 43805 43810 43809 43804 43806 43805 43804 43809 43806 43804 43805 45200 45202 43805 43806 45200 45201 45200 43806 45203 45201 43806 43806 44539 45203 43806 44538 44539 43806 43809 44538 43807 43812 44541 43813 43812 43807 43807 43811 43813 45878 44532 43808 43808 44536 45878 44537 44536 43808 44542 44537 43808 43808 44535 44542 43809 43810 43818 44540 44538 43809 45214 44540 43809 43809 45210 45214 43809 43818 45210 45206 43813 43811 44547 44541 43812 45209 44547 43812 43812 43813 45209 43813 45206 45209 43814 43816 44535 43814 43815 43816 45211 43816 43815 45219 45211 43815 44542 44535 43816 45211 44542 43816 44534 44533 43817 44573 43826 43819 43819 43834 44573 44555 44553 43823 43823 44550 44555 43824 43827 44567 43825 43828 45228 43851 43843 43826 44573 43851 43826 43827 43835 44567 43828 44563 45228 43828 43830 44563 43828 43829 43830 43836 43830 43829 44574 44563 43830 45236 44574 43830 43830 44575 45236 43830 43839 44575 43830 43836 43839 43831 43832 44565 43833 43832 43831 44571 43833 43831 43831 44565 44571 45914 45237 43833 45915 45914 43833 46523 45915 43833 43833 45902 46523 43833 44571 45902 43834 44553 44573 44570 44567 43835 44581 43838 43837 43837 43842 44581 45233 43841 43838 43838 44581 45233 44588 43848 43840 45233 45232 43841 44589 44581 43842 44590 44589 43842 43842 43850 44590 43851 43844 43843 43844 43853 43857 43844 43851 43853 45234 44569 43845 45245 45234 43845 43845 45242 45245 45243 45242 43845 43845 43846 45243 43847 43846 43845 43845 44569 44570 43846 43847 45254 45254 45243 43846 44597 43855 43849 43849 44596 44597 43850 43856 44590 44582 43853 43851 43851 44572 44582 44573 44572 43851 43854 43853 43852 44599 43854 43852 44601 44599 43852 43852 44582 44601 43852 43853 44582 43853 43854 43857 43859 43857 43854 43861 43859 43854 44599 43861 43854 43855 44598 45253 43855 44597 44598 43858 43861 43867 43858 43859 43861 43867 43866 43858 46539 45242 43860 46545 46539 43860 46549 46545 43860 46550 46549 43860 47258 46550 43860 43876 43874 43861 45258 43876 43861 43861 44599 45258 43874 43867 43861 43863 44606 44607 45255 44606 43863 45275 44610 43865 45276 45275 43865 43865 43872 45276 43866 43874 43877 43866 43867 43874 43879 43878 43868 43868 43869 43879 44612 43879 43869 44622 44615 43870 43870 44603 44622 43872 43873 44621 45277 45276 43872 45282 45277 43872 43872 44621 45282 43873 43883 44621 43876 43875 43874 43883 43877 43874 43874 43875 43883 43875 45263 45942 43875 43876 45263 44621 43883 43875 45952 44621 43875 43875 45942 45952 43876 45258 45263 45265 45264 43878 43878 43879 45265 43879 44612 45265 43880 43881 44618 43882 43881 43880 44619 44618 43881 43881 43885 44619 43881 43882 43885 43886 43885 43882 43887 43886 43882 43889 43888 43884 44623 43889 43884 44624 44623 43884 43885 43886 44619 44625 44619 43886 43886 43887 44625 45261 44625 43887 45303 44633 43889 43889 45289 45303 43889 44623 45289 44647 43911 43890 43890 43891 44647 44648 44647 43891 43891 44645 44648 43891 44635 44645 45308 44644 43893 43893 44628 45308 44643 44642 43893 44644 44643 43893 44660 43908 43894 43894 43895 44660 43895 43919 44660 43895 43918 43919 43895 43906 43918 45976 43897 43896 43897 45976 47298 44631 43913 43897 47298 44631 43897 44649 43899 43898 43899 45296 45297 45305 45296 43899 43899 44649 45305 43900 43902 44639 44639 43901 43900 44663 44650 43901 43901 44639 44663 45300 44639 43902 45310 45300 43902 43902 44659 45310 43902 43912 44659 43902 43903 43912 43917 43912 43903 44651 43905 43904 43904 44642 44651 44651 43907 43905 43906 43907 43918 44652 43918 43907 43907 44651 44652 44653 43909 43908 44660 44653 43908 44646 44634 43909 44661 44646 43909 43909 44653 44661 43910 43911 44647 44647 43923 43910 43912 43917 44659 43913 44629 44632 44631 44629 43913 43916 43915 43914 44656 43928 43914 43914 44636 44656 44637 44636 43914 43914 43915 44637 43917 43926 44659 43920 43919 43918 44652 43920 43918 43919 44653 44660 45321 44653 43919 45324 45321 43919 43919 45320 45324 43919 43920 45320 43920 45319 45320 43920 44652 45319 44662 43922 43921 43921 44655 44662 43921 44648 44655 43921 43923 44648 43923 44647 44648 43927 43926 43925 45329 43927 43925 45310 44659 43926 43926 43927 45310 45979 45310 43927 46589 45979 43927 46601 46589 43927 43927 45330 46601 43927 45329 45330 45998 45985 43928 43928 44630 45998 45982 44630 43928 43928 44656 45982 43929 43930 43944 43931 43930 43929 44665 43944 43930 44669 44665 43930 43930 43940 44669 43930 43931 43940 43932 45331 45332 46001 45331 43932 43932 44674 46001 43932 43946 44674 43933 43942 43943 43933 43934 43942 43935 43956 43958 43935 43936 43956 43936 43954 43956 43955 43954 43936 43936 43949 43955 44687 43945 43937 43937 43951 44687 43937 43938 43951 44685 43940 43939 43939 43945 44685 45318 44669 43940 43940 44685 45318 45342 44658 43941 45343 45342 43941 45993 45343 43941 43941 45349 45993 43941 43953 45349 43941 43942 43953 43943 43942 43941 44658 43943 43941 43944 44665 44668 45348 44686 43945 43945 44687 45348 44686 44685 43945 44675 44674 43946 45334 43949 43948 43948 44664 45334 45334 43955 43949 46003 45336 43950 43950 44691 46003 43950 44682 44691 43951 43957 44687 44677 43953 43952 44679 44677 43952 43952 44676 44679 45354 45349 43953 43953 44677 45354 44680 43956 43954 45351 44680 43954 43954 45344 45351 43954 43955 45344 43955 45334 45344 43959 43958 43956 44680 43959 43956 43958 43959 43961 44697 43961 43959 43959 44681 44697 43959 44680 44681 43960 43966 44688 43961 44697 44703 44711 43973 43962 43962 44706 44711 43962 44698 44706 43963 43964 43968 45379 43968 43964 43964 44704 45379 43972 43966 43965 44717 43972 43965 43965 43969 44717 43966 43971 44688 43972 43971 43966 44708 44700 43967 45379 44723 43968 45388 44717 43969 43969 43970 45388 45393 45388 43970 43970 44720 45393 43970 43981 44720 44705 44688 43971 45383 44705 43971 43971 43972 45383 43972 44717 45383 43974 43986 44714 43974 43978 43986 43984 43977 43975 43975 43976 43984 43985 43984 43976 43991 43985 43976 43984 43983 43977 43987 43986 43978 44720 43981 43979 44724 44720 43979 43979 43980 44724 44718 43990 43982 43984 44722 44730 43984 43985 44722 43985 44010 44722 43985 43992 44010 43985 43991 43992 45398 44714 43986 43986 43987 45398 45400 45398 43987 45408 45400 43987 43987 43988 45408 43988 44739 45408 43988 44731 44739 43988 43993 44731 43994 43993 43988 45409 44726 43989 43989 44728 45409 44729 44728 43989 43990 44718 44725 44736 44735 43990 43990 44725 44736 44007 44000 43995 45405 45392 43996 43996 45404 45405 43996 44733 45404 45392 44724 43996 43997 45415 45416 43997 45401 45415 43997 44742 45401 43997 43998 44742 43999 43998 43997 45416 43999 43997 44744 44743 43999 45416 44744 43999 45417 44733 44000 44000 44007 45417 45417 44007 44001 44001 45404 45417 44001 44008 45404 44002 44734 44745 44745 44008 44002 44003 44749 44755 44764 44754 44004 44004 44755 44764 44741 44740 44005 45418 44741 44005 46058 45418 44005 44005 44752 46058 44005 44006 44752 44006 44751 44752 44006 44012 44751 44008 44746 45404 44008 44745 44746 44747 44010 44009 44009 44738 44747 44009 44737 44738 45410 44737 44009 44009 44748 45410 44747 44722 44010 45410 44748 44011 44011 44737 45410 44012 44016 44751 44761 44016 44013 44013 44014 44761 44015 44014 44013 44759 44015 44013 45430 44761 44014 46063 45430 44014 44014 45436 46063 45437 45436 44014 44014 44015 45437 44015 44769 45437 45428 44769 44015 44015 44759 45428 44760 44751 44016 44761 44760 44016 44758 44753 44017 45420 44758 44017 44017 44743 45420 44018 44019 45423 44018 44749 44750 45423 44749 44018 44019 44021 45423 44762 44024 44020 44763 44762 44020 44021 44025 45424 45424 45423 44021 44024 44023 44022 44029 44028 44023 44024 45425 45431 44024 44762 45425 44025 44026 44764 44025 44764 45424 44026 44765 44766 44026 44027 44765 44766 44764 44026 44027 44030 44765 44028 44029 44767 44768 44765 44030 44030 44031 44768 44031 44032 44768 44032 44035 44768 44032 44034 44035 44032 44033 44034 44769 44035 44034 45437 44769 44034 44034 44037 45437 45432 44768 44035 44035 44769 45432 44037 45436 45437 44037 44038 45436 44038 45434 45436 45435 45434 44038 44038 44767 45435 44042 44041 44039 44040 44045 44772 44040 44041 44045 44772 44044 44040 45441 44045 44041 44041 44042 45441 44042 44771 45441 44772 44046 44044 45441 44772 44045 45444 44047 44046 44046 45442 45444 44046 44772 45442 44049 44048 44047 45444 44049 44047 44774 44054 44048 44048 44049 44774 45447 44774 44049 44049 45446 45447 44049 45444 45446 44050 44059 44775 44050 44058 44059 44051 44052 44060 44052 44059 44060 44775 44059 44052 46073 44770 44053 46689 46073 44053 44053 45449 46689 44053 44773 45449 44054 44774 44777 44055 44056 44773 44057 44056 44055 44776 44057 44055 45450 44773 44056 44056 44057 45450 46710 45450 44057 44057 44776 46710 44062 44059 44058 44064 44060 44059 44059 44062 44064 44061 44067 44068 44070 44064 44062 44062 44063 44070 44071 44070 44063 44783 44782 44065 44065 44780 44783 44065 44066 44780 44781 44780 44066 44066 44075 44781 44778 44068 44067 44067 44777 44778 44073 44072 44068 44779 44073 44068 44068 44778 44779 45455 44787 44072 45456 45455 44072 44072 44779 45456 44072 44073 44779 46084 44788 44074 44786 44781 44075 44078 44080 44799 44804 44086 44079 44079 44794 44804 44081 44788 45459 44798 44797 44083 44803 44798 44083 44802 44094 44084 45471 44802 44084 44084 45464 45471 44084 44791 45464 44084 44085 44791 44795 44791 44085 44097 44091 44086 44098 44097 44086 44804 44098 44086 45475 44108 44087 45476 45475 44087 44087 44089 45476 44108 44088 44087 44100 44099 44088 44108 44100 44088 44089 45462 45476 45477 45468 44090 46099 45477 44090 44808 44801 44092 44093 44109 44111 44110 44109 44093 44093 44102 44110 44093 44094 44102 45480 44102 44094 44094 44802 45480 44820 44104 44095 44095 44112 44820 44095 44096 44112 44096 44103 44112 45479 44815 44098 44098 44804 45479 44127 44115 44099 44834 44127 44099 44099 44100 44834 46102 44834 44100 44100 44108 46102 44819 44818 44101 44827 44819 44101 44101 44117 44827 45480 44110 44102 44104 44820 44822 45495 44825 44105 44105 44824 45495 44105 44106 44824 44107 44106 44105 44825 44107 44105 44813 44807 44107 44825 44813 44107 44108 46095 46102 44108 45475 46095 44120 44118 44109 45488 44120 44109 44109 44110 45488 44118 44111 44109 44110 45480 45488 44111 44118 44119 44112 44132 44820 44113 44122 44134 44113 44114 44122 44816 44122 44114 44128 44117 44116 44117 44128 44129 44828 44827 44117 44117 44129 44828 44120 44119 44118 44119 44121 44130 44119 44120 44121 45499 44121 44120 44120 45488 45499 46113 44130 44121 44121 45499 46113 44150 44134 44122 44826 44150 44122 44122 44816 44826 44137 44135 44123 45497 44129 44124 46119 45497 44124 44124 44125 46119 44126 44125 44124 45489 44126 44124 45490 45489 44124 46764 46119 44125 44125 46758 46764 44125 44126 46758 44126 44834 46102 45489 44834 44126 44126 46757 46758 44126 46756 46757 44126 46102 46756 44127 45489 45490 44127 44834 45489 44836 44828 44129 45498 44836 44129 44129 45497 45498 45514 44841 44130 46768 45514 44130 44130 46113 46768 44131 44132 44138 44133 44132 44131 44838 44133 44131 44842 44838 44131 44848 44842 44131 44131 44163 44848 44821 44820 44132 44132 44133 44821 45507 44821 44133 46773 45507 44133 46775 46773 44133 44133 44843 46775 44133 44838 44843 44142 44139 44134 44150 44142 44134 45512 44811 44135 44135 45500 45512 44135 44136 45500 44137 44136 44135 45513 45500 44136 44136 44839 45513 44136 44137 44839 44137 44144 44839 44145 44144 44137 44137 44143 44145 44137 44140 44143 44143 44140 44139 44139 44142 44143 44145 44143 44142 44154 44145 44142 44845 44154 44142 45517 44845 44142 44142 44150 45517 44144 44155 44839 44144 44145 44155 44145 44153 44155 44154 44153 44145 45515 44152 44147 44147 44840 45515 46130 45517 44148 44148 44149 46130 44150 44149 44148 45517 44150 44148 44149 46129 46130 44149 46125 46129 44149 45510 46125 44149 44150 45510 45511 45510 44150 44150 44826 45511 44152 45521 45524 44152 45515 45521 44161 44155 44153 44851 44161 44153 44153 44154 44851 44154 44845 44851 45513 44839 44155 45519 45513 44155 44155 44158 45519 44155 44156 44158 44157 44156 44155 44161 44157 44155 44156 44157 44167 44160 44158 44156 44852 44160 44156 44156 44167 44852 44157 44161 44162 44157 44162 44167 44160 44159 44158 44158 45518 45519 46131 45518 44158 44158 45523 46131 44158 44159 45523 44159 44160 44852 44159 45522 45523 44159 44852 45522 44171 44166 44161 44860 44171 44161 44861 44860 44161 44161 44851 44861 44166 44162 44161 44172 44167 44162 44162 44166 44172 44849 44848 44163 44163 44164 44849 44850 44849 44164 44164 44165 44850 44165 44168 44850 44166 44171 44172 44167 44172 44852 44168 44169 44850 45528 44850 44169 45530 45528 44169 44169 45529 45530 44169 44170 45529 44170 44858 45529 44173 44172 44171 44860 44173 44171 44172 44173 45553 45522 44852 44172 46150 45522 44172 44172 45553 46150 44173 45549 45553 44173 44868 45549 44173 44860 44868 44174 44190 44874 44874 44189 44174 44176 44857 44859 45559 44857 44176 44176 44865 45559 44870 44869 44178 44178 44183 44870 44184 44183 44178 44862 44184 44178 44178 44179 44862 44181 44185 44191 44871 44192 44181 44181 44191 44871 46153 44870 44183 46166 46153 44183 44183 45540 46166 44183 44184 45540 44184 44862 45540 45544 44191 44185 45564 44190 44188 45572 45564 44188 44874 44863 44189 44190 44873 44874 45564 44873 44190 44191 45544 46158 45569 44871 44191 46158 45569 44191 44197 44195 44192 45574 44197 44192 44192 45566 45574 45567 45566 44192 45569 45567 44192 44192 44871 45569 44876 44875 44193 44888 44876 44193 44220 44199 44194 44197 44196 44195 44196 44197 44885 45574 44885 44197 44198 44201 44202 44199 44220 45575 45575 44878 44199 44202 44201 44200 44213 44202 44200 44217 44213 44200 44213 44207 44202 44227 44208 44203 44884 44227 44203 46185 44884 44203 44203 44204 46185 44204 45573 46174 46186 46185 44204 44204 46174 46186 44893 44226 44206 44206 44892 44893 44206 44891 44892 44207 44213 44214 44890 44886 44210 44210 44216 44890 44210 44215 44216 44211 44906 45581 44211 44212 44906 44211 44217 44894 45581 44217 44211 44212 44905 44906 44895 44214 44213 44896 44895 44213 45581 44896 44213 44213 44217 45581 45585 44890 44216 44218 44228 44903 44902 44899 44218 44903 44902 44218 44219 44231 45583 44219 44221 44231 44900 44220 44219 45583 44900 44219 44220 44900 45575 44221 44222 44229 45579 44224 44223 44223 44885 45579 46829 44897 44224 44224 45579 46829 44915 44240 44225 44917 44915 44225 44225 44893 44917 44225 44226 44893 44227 44882 45587 44884 44882 44227 45596 44908 44228 44908 44903 44228 44230 44232 44904 44233 44232 44230 45588 44231 44230 44230 44904 45588 45588 45583 44231 44232 46198 46201 46205 46198 44232 44232 44912 46205 44232 44233 44912 46201 44904 44232 44913 44912 44233 44920 44237 44234 44234 44910 44920 44234 44235 44910 44923 44910 44235 45597 44923 44235 44235 45587 45597 44235 44911 45587 44255 44253 44236 44920 44255 44236 44236 44237 44920 44253 44252 44236 45604 45603 44238 44238 44239 45604 44257 44250 44238 44238 44249 44257 45603 44249 44238 44240 44915 45607 44241 44244 44922 44241 44243 44244 44921 44242 44241 45599 44921 44241 44241 44922 45599 44245 44250 44257 45600 44922 44247 44247 44248 45600 44249 44248 44247 45602 45600 44248 45612 45602 44248 44248 44249 45612 44249 45603 45612 46863 45613 44251 44251 45625 46863 44251 44918 45625 44252 44253 44256 44255 44254 44253 44263 44256 44253 44253 44254 44263 44254 44923 45609 44254 44255 44923 45611 44263 44254 44254 45610 45611 44254 45609 45610 44255 44920 44923 44263 44259 44256 44925 44260 44258 44258 44273 44925 44264 44262 44259 44259 44263 44264 44925 44261 44260 44925 44274 44261 44271 44269 44262 44262 44264 44271 44278 44264 44263 44924 44278 44263 45611 44924 44263 44264 44278 44926 44941 44271 44264 44264 44926 44941 44267 44266 44265 44929 44267 44265 44932 44930 44267 44267 44929 44932 44271 44270 44269 44945 44284 44270 46238 44945 44270 44270 44271 46238 46240 46238 44271 44271 44942 46240 44271 44941 44942 44938 44273 44272 45621 44925 44273 44273 44938 45621 45626 44951 44274 44274 45624 45626 44274 44925 45624 44281 44279 44275 44948 44276 44275 44953 44948 44275 44275 44279 44953 45628 44940 44276 45641 45628 44276 44276 44948 45641 44278 44924 44943 44943 44926 44278 44279 44281 44282 44954 44953 44279 44968 44954 44279 44279 44967 44968 44279 44280 44967 44955 44287 44283 45644 44955 44283 44283 44945 45644 44283 44284 44945 44285 44284 44283 44287 44285 44283 44285 44287 44295 45648 44291 44286 44286 44956 45648 44286 44288 44956 44955 44295 44287 44288 44289 44956 44289 44299 44956 44289 44290 44299 44957 44947 44291 45649 44957 44291 44291 44949 45649 44950 44949 44291 45648 44950 44291 44292 44294 44301 44301 44294 44293 44293 44300 44301 44970 44297 44295 44295 44955 44970 46262 44960 44296 44296 44297 46262 44297 45655 46262 44297 44971 45655 44297 44970 44971 45653 44299 44298 44298 44960 45653 45654 44956 44299 44299 45653 45654 44972 44303 44300 45651 44972 44300 44972 44306 44303 45662 44305 44304 44304 44981 45662 44974 44967 44305 45662 44974 44305 44972 44322 44306 44307 44982 44983 44307 44308 44982 44308 44309 44982 44309 44975 44982 44309 44311 44975 44309 44310 44311 44315 44311 44310 44980 44975 44311 44311 44315 44980 44312 44326 44329 44328 44326 44312 44984 44314 44313 44989 44321 44314 44314 44985 44989 44314 44984 44985 44986 44980 44315 44316 44993 44995 45664 44993 44316 44316 44322 45664 44318 44329 44988 44987 44981 44318 44988 44987 44318 44321 44320 44319 45683 44334 44320 44320 45674 45683 45676 45674 44320 44320 44321 45676 44321 44989 45676 46271 45664 44322 44322 44972 46271 45001 44996 44325 44325 45000 45001 45687 44998 44326 44326 44327 45687 44328 44327 44326 44998 44329 44326 44327 45694 45696 44327 45688 45694 44327 44328 45688 45695 45687 44327 45696 45695 44327 44328 45002 45688 44328 44996 45002 44998 44988 44329 45004 44336 44332 44332 44333 45004 45681 45004 44333 44342 44337 44334 45006 45005 44334 45684 45006 44334 44334 45683 45684 45004 44347 44336 46288 45685 44338 44338 44339 46288 44340 44339 44338 44339 45689 46288 44339 45007 45689 44339 44345 45007 44339 44340 44345 44340 44341 44345 44341 44343 44345 44344 44343 44341 44343 44344 45699 45007 44345 44343 46290 45007 44343 44343 45700 46290 44343 45699 45700 44344 44355 44356 44344 44356 45699 46295 45022 44346 44346 44347 46295 44347 46291 46295 44347 45004 46291 44357 44349 44348 45009 44357 44348 44348 45005 45009 44357 44350 44349 44352 44351 44350 44357 44352 44350 44358 44353 44351 44351 44352 44358 45709 44358 44352 45710 45709 44352 44352 45012 45710 44352 44357 45012 44356 44355 44354 45010 44356 44354 44356 45011 45699 44356 45010 45011 44357 45009 45012 45709 44359 44358 45713 45013 44359 44359 45709 45713 45015 44361 44360 44360 45014 45015 44360 44363 45014 45016 45010 44361 45017 45016 44361 44361 45015 45017 44368 44363 44362 44362 44366 44368 44363 44368 45014 44364 44365 44367 45021 44367 44365 44365 45020 45021 44365 45019 45020 45024 45019 44365 44366 44367 44368 45021 44368 44367 45716 45014 44368 45718 45716 44368 44368 45020 45718 45021 45020 44368 45719 45025 44369 44369 45022 45719 44370 45028 45029 44370 44371 45028 45727 45028 44371 44371 45032 45727 45036 44378 44373 44373 44376 45036 44373 44374 44376 44374 44375 44376 44377 44376 44375 45035 44377 44375 44375 45033 45035 45034 45033 44375 44376 44377 45036 45037 45036 44377 45038 45037 44377 44377 45035 45038 44380 44379 44378 45039 44380 44378 44378 45036 45039 46349 45041 44379 44379 46348 46349 46357 46348 44379 44379 44380 46357 44380 45039 46357 46353 45736 44381 44381 46349 46353 44381 45041 46349 44382 44383 44384 45042 44384 44383 45740 45042 44383 46354 45740 44383 44383 45737 46354 45042 44385 44384 45044 45043 44386 44387 47056 47057 44387 47048 47056 47049 47048 44387 45750 44389 44388 44388 45749 45750 45060 44402 44389 44389 45057 45060 45059 45057 44389 45751 45059 44389 44389 45750 45751 48451 46392 44390 44390 47770 48451 47776 47770 44390 47783 47776 44390 44390 45077 47783 44391 44397 44399 44391 44392 44397 44393 44392 44391 45051 44397 44392 44392 44393 45051 46374 45049 44394 44394 45748 46374 44394 45053 45748 44394 44395 45053 45056 45053 44395 45058 45056 44395 44395 45057 45058 44395 44396 45057 44396 44401 45057 45055 44399 44397 44397 45051 45055 45756 44400 44398 44398 44399 45756 45757 45756 44399 45758 45757 44399 44399 45055 45758 45756 45061 44400 45060 45057 44401 44404 45061 46387 44422 44417 44405 44426 44422 44405 45769 44426 44405 44405 44415 45769 44405 44406 44415 44407 44406 44405 44417 44407 44405 44406 44408 44414 44418 44408 44406 44406 44407 44418 44406 44414 44415 44407 44416 44418 44417 44416 44407 44408 45072 45767 44408 44409 45072 44410 44409 44408 44413 44410 44408 44418 44413 44408 45063 44414 44408 44408 44411 45063 44412 44411 44408 45065 44412 44408 45767 45065 44408 44409 44438 45073 45066 44438 44409 44409 44410 45066 45075 45072 44409 44409 45073 45075 44410 44437 45066 44410 44435 44437 44410 44419 44435 44410 44413 44419 45761 45063 44411 44411 45753 45761 45758 45753 44411 44411 45757 45758 44411 44412 45757 44412 45756 45757 44412 45061 45756 45065 45061 44412 44413 44418 44419 45063 44415 44414 44415 45759 45771 44415 45063 45759 46397 45769 44415 47063 46397 44415 44415 46396 47063 44415 46393 46396 44415 45770 46393 45771 45770 44415 44419 44418 44416 44416 44417 44421 44422 44421 44417 44419 44431 44435 44419 44430 44431 44419 44429 44430 44421 44428 44429 44421 44423 44428 44421 44422 44423 44426 44423 44422 44432 44428 44423 44423 44427 44432 44423 44426 44427 45778 45076 44424 44424 45067 45778 45071 44427 44426 45769 45071 44426 45070 44432 44427 45071 45070 44427 44434 44429 44428 44442 44434 44428 44428 44432 44442 44433 44430 44429 44434 44433 44429 44444 44431 44430 44430 44433 44444 44439 44435 44431 44444 44439 44431 45772 44442 44432 44432 45070 45772 45093 44444 44433 45094 45093 44433 44433 45091 45094 44433 44443 45091 44433 44434 44443 44434 44442 44443 44441 44437 44435 44435 44439 44441 45082 45080 44436 45087 45082 44436 44436 45078 45087 44436 44437 45078 44438 44437 44436 45074 44438 44436 45080 45074 44436 44437 44438 45066 45079 45078 44437 44437 44440 45079 44441 44440 44437 45074 45073 44438 44447 44441 44439 44439 44445 44447 44439 44444 44445 44440 44447 45079 44440 44441 44447 45090 44443 44442 45092 45090 44442 45780 45092 44442 44442 45772 45780 44443 45090 45091 44446 44445 44444 45093 44446 44444 45786 44447 44445 44445 45095 45786 44445 44446 45095 44446 45093 46413 46414 45095 44446 44446 46413 46414 44447 45078 45079 45087 45078 44447 45097 45087 44447 45789 45097 44447 44447 45786 45789 45108 45106 44449 45111 45108 44449 45112 45111 44449 44450 45107 46420 44450 45106 45107 47840 47820 44450 48495 47840 44450 44450 46420 48495 44451 44453 44457 44451 44452 44453 45802 44456 44455 45803 45802 44455 44455 45801 45803 44455 45105 45801 45802 45110 44456 44462 44461 44458 44463 44462 44458 44458 44459 44463 45114 45113 44460 44461 44464 44470 44461 44462 44464 44462 44463 44464 44467 44464 44463 45129 44470 44464 44464 44467 45129 44474 44473 44466 44467 44468 45129 44469 44468 44467 45120 44469 44467 44467 45113 45120 45820 45819 44468 44468 45119 45820 44468 44469 45119 45130 45129 44468 45817 45130 44468 45819 45817 44468 44469 45122 45131 44469 45120 45122 45821 45119 44469 44469 45131 45821 44470 45129 45138 45815 44474 44472 44472 45125 45815 44472 45124 45125 46438 45814 44473 44473 46427 46438 44473 46426 46427 44473 44474 46426 46429 46426 44474 44474 45815 46429 45128 45127 44475 45818 45128 44475 44475 45817 45818 44475 45138 45817 45139 45134 44476 45132 44477 44476 45809 45132 44476 45810 45809 44476 45805 45112 44477 46421 45805 44477 46423 46421 44477 44477 45132 46423 45123 44481 44478 45812 45136 44479 44479 44480 45812 45825 45812 44480 44481 45137 45823 44481 45123 45137 44483 44482 44481 45823 44483 44481 45826 45824 44482 44482 45813 45826 44482 44483 45813 45823 45813 44483 45832 45143 44484 47110 45832 44484 44484 47108 47110 44484 46455 47108 44484 46454 46455 44484 44485 46454 44485 45827 46454 44485 45142 45827 45147 44488 44487 44487 45146 45147 44487 45145 45146 45147 44493 44488 45150 45141 44489 45151 45150 44489 44489 44491 45151 44490 45143 45144 45833 45163 44492 44492 44493 45833 44493 45147 45833 45154 45153 44494 45160 45154 44494 45161 45160 44494 44494 44504 45161 44494 44495 44504 44495 44499 44504 44498 44497 44496 44509 44498 44496 44497 44498 44508 44510 44508 44498 44498 44509 44510 44499 44502 44504 44503 44502 44499 45166 44503 44499 45840 45166 44499 45841 44504 44502 46467 45841 44502 44502 44503 46467 46473 46467 44503 44503 45166 46473 45841 45161 44504 44512 44511 44505 45168 44512 44505 44505 44506 45168 45844 45168 44507 46470 45844 44507 44507 45847 46470 45848 45847 44507 44507 45169 45848 45164 44510 44509 44509 45163 45164 45170 44518 44510 44510 45164 45170 45173 44515 44511 44511 44512 45173 45843 45173 44512 44512 45842 45843 44512 45167 45842 45168 45167 44512 44513 44514 45169 45172 45169 44514 44514 45171 45172 44515 45173 45862 45862 44522 44515 45175 45174 44516 44516 44517 45175 44517 44519 45175 44520 44519 44517 44518 45170 45854 45867 45182 44518 44518 45866 45867 44518 45854 45866 45853 45175 44519 44519 44520 45853 44520 45178 45853 44520 45176 45178 44521 44522 45177 45868 45177 44522 44522 45862 45868 45863 45178 44523 45865 45863 44523 44523 45179 45865 44523 44528 45179 47143 45873 44524 44524 45193 47143 44524 45186 45193 44524 44525 45186 45194 45186 44525 44525 44526 45194 45195 45194 44526 44526 45188 45195 45189 45187 44527 44528 44529 45179 45874 45207 44530 44530 45192 45874 44531 44532 45191 45197 45196 44532 45878 45197 44532 45196 45191 44532 44533 44543 44551 44544 44543 44533 44545 44544 44533 44533 44534 44545 45198 44545 44534 45199 45198 44534 45200 45199 44534 45202 45200 44534 47199 45878 44536 44536 45891 47199 45892 45891 44536 45893 45892 44536 44536 44537 45893 44537 45211 45893 44537 44542 45211 44540 44539 44538 46504 45203 44539 46505 46504 44539 44539 44540 46505 44540 45214 46505 44541 44546 44548 44547 44546 44541 44543 45220 45224 44543 44544 45220 44544 45212 45220 44544 44545 45212 45213 45212 44545 45887 45213 44545 44545 45198 45887 44564 44548 44546 45208 44564 44546 45209 45208 44546 44546 44547 45209 44564 44552 44548 44556 44550 44549 44567 44556 44549 44572 44555 44550 45238 44572 44550 44550 44556 45238 44553 44554 44573 44555 44554 44553 44554 44572 44573 44554 44555 44572 44556 44568 45238 44556 44567 44568 44558 44559 45210 44560 44559 44558 45227 44560 44558 45228 45227 44558 45214 45210 44559 46511 45214 44559 47183 46511 44559 44559 46512 47183 44559 44560 46512 47193 46512 44560 44560 46514 47193 44560 45227 46514 44561 45227 45228 46514 45227 44561 46515 46514 44561 44561 44562 46515 44563 44562 44561 45228 44563 44561 44562 45909 46515 44562 44563 45909 44563 44574 45909 45218 44566 44564 44564 45215 45218 45216 45215 44564 44564 45208 45216 45902 44571 44565 44565 45217 45902 44565 44566 45217 45218 45217 44566 45234 44568 44567 44567 44569 45234 44570 44569 44567 44568 45234 45238 44583 44582 44572 44591 44583 44572 45238 44591 44572 45910 45909 44574 44574 45236 45910 45913 45236 44575 44575 44579 45913 44575 44578 44579 45226 44577 44576 44576 45224 45226 44595 44584 44577 45235 44595 44577 44577 45230 45235 44577 45226 45230 44580 44579 44578 45240 44580 44578 46522 45913 44579 46529 46522 44579 44579 45919 46529 44579 44580 45919 44580 44586 45919 44587 44586 44580 45240 44587 44580 45241 45233 44581 44581 44589 45241 44582 44583 44601 44583 44592 44601 44583 44591 44592 44595 44594 44584 44585 44594 45246 46530 45919 44586 44586 45924 46530 44586 45914 45924 44586 44587 45914 45240 44588 44587 44587 45237 45914 45925 45241 44589 44589 44590 45925 45927 45925 44590 45939 45927 44590 44590 44602 45939 44593 44592 44591 45244 44593 44591 44591 45238 45244 45247 44601 44592 46537 45247 44592 46538 46537 44592 44592 44593 46538 44593 45920 46538 44593 45245 45920 44593 45244 45245 44594 45239 45246 44594 44595 45239 44595 45235 45239 45923 44597 44596 44596 45249 45923 44597 45923 45935 45935 44598 44597 45256 45253 44598 45935 45256 44598 45940 45258 44599 46543 45940 44599 44599 44600 46543 44601 44600 44599 46544 46543 44600 44600 45932 46544 44600 44601 45932 44601 45247 45932 44602 45259 45283 45260 45259 44602 44602 44608 45260 45967 45939 44602 46546 45967 44602 44602 45283 46546 44603 45955 45966 45956 45955 44603 44603 45266 45956 44603 44604 45266 45966 44622 44603 45267 45266 44604 44604 44605 45267 45268 45267 44605 45271 44607 44606 44606 45270 45271 44606 45257 45270 44606 45255 45257 45271 44616 44607 44608 44618 45260 45262 44620 44609 44609 44610 45262 45275 45262 44610 45954 44624 44611 44611 45278 45954 44612 44613 45265 44614 44613 44612 45280 44614 44612 44612 44615 45280 44613 45264 45265 44613 44614 45264 45281 45264 44614 44614 45280 45281 44615 44622 45280 45960 45958 44616 44616 45271 45960 45958 44617 44616 45958 45269 44617 45284 45260 44618 44618 44619 45284 45290 45284 44619 44619 45286 45290 44619 44625 45286 45946 45261 44620 44620 45262 45946 45952 45282 44621 45963 45280 44622 45966 45963 44622 45302 45289 44623 44623 45287 45302 45288 45287 44623 44623 44624 45288 45954 45288 44624 45948 45286 44625 44625 45261 45948 44626 44627 47263 44627 45291 47263 44628 44640 45308 44641 44640 44628 45303 44641 44628 44628 44633 45303 44638 44632 44629 44629 44637 44638 44629 44636 44637 44629 44630 44636 44631 44630 44629 45982 44636 44630 44630 45981 45998 44630 44631 45981 47298 45981 44631 44646 44635 44634 44646 44645 44635 45982 44656 44636 45298 44663 44639 45300 45298 44639 44640 44641 45311 45315 45308 44640 45316 45315 44640 45980 45316 44640 44640 45311 45980 44641 45303 45304 44641 45304 45311 45312 44651 44642 44642 44643 45312 44643 45306 45312 44643 44644 45306 44644 45317 45990 44644 45308 45317 45307 45306 44644 45989 45307 44644 45990 45989 44644 44654 44648 44645 44645 44646 44654 45314 44654 44646 44646 44670 45314 44646 44661 44670 44648 44654 44655 45309 45305 44649 44649 44657 45309 44658 44657 44649 46588 44664 44650 44650 46584 46588 46585 46584 44650 44650 45977 46585 44650 44663 45977 45313 44652 44651 44651 45312 45313 44652 45313 45319 45321 44661 44653 45314 44655 44654 44670 44662 44655 45314 44670 44655 46582 45309 44657 46586 46582 44657 44657 44658 46586 44658 45342 46596 46596 46586 44658 44663 45971 45977 44663 45298 45971 45335 45334 44664 46588 45335 44664 44665 44666 44668 44667 44666 44665 44669 44667 44665 45328 44668 44666 44666 44667 45328 44667 45323 45328 44667 44669 45323 45337 44683 44668 45338 45337 44668 44668 45328 45338 44669 45308 45323 45317 45308 44669 45318 45317 44669 45360 44673 44671 46017 45360 44671 44671 45999 46017 44671 45340 45999 44671 44672 45340 44673 44672 44671 44672 45339 45340 45360 44698 44673 44674 44675 45366 44674 45367 46001 44674 45366 45367 44689 44679 44676 45361 45354 44677 44677 44678 45361 44679 44678 44677 46018 45361 44678 44678 46013 46018 44678 45353 46013 44678 44679 45353 44679 44689 45353 44690 44681 44680 45350 44690 44680 45351 45350 44680 44681 44696 44697 44681 44695 44696 44681 44690 44695 44692 44691 44682 45346 44684 44683 44683 45337 45346 44684 45346 45347 45372 44694 44684 44684 45347 45372 45990 45318 44685 46604 45990 44685 44685 44686 46604 47313 46604 44686 44686 45348 47313 45352 45348 44687 46012 45352 44688 44688 44705 46012 46007 45353 44689 44689 45985 46007 45357 44695 44690 45358 45357 44690 44690 45350 45358 44691 46002 46003 44691 44692 46002 46016 46002 44692 44692 45364 46016 44693 45362 45363 45372 45362 44693 44693 44694 45372 44701 44696 44695 44709 44701 44695 44710 44709 44695 45357 44710 44695 44701 44697 44696 44697 44702 44703 44697 44701 44702 44707 44706 44698 45360 44707 44698 46022 45366 44699 46030 46022 44699 44700 44715 44716 44700 44714 44715 44700 44708 44714 45377 44702 44701 44701 45368 45377 44701 44709 45368 44704 44703 44702 45377 44704 44702 46028 45379 44704 44704 45378 46028 44704 45377 45378 44705 45384 46012 44705 45383 45384 44713 44711 44706 44706 44707 44713 46020 44713 44707 46021 46020 44707 44707 45359 46021 45360 45359 44707 44709 44710 45355 45376 45368 44709 46033 45376 44709 44709 46019 46033 44709 45355 46019 45357 45355 44710 45390 44719 44711 44711 44712 45390 44713 44712 44711 46628 45390 44712 44712 44713 46628 44713 46020 46628 45391 44715 44714 45398 45391 44714 45374 44716 44715 45391 45374 44715 44716 45374 45375 46037 45383 44717 44717 45388 46037 44718 44721 45395 45395 44725 44718 45390 45389 44719 45394 44721 44719 44719 45389 45394 44720 45392 45393 44720 44724 45392 44721 45394 45395 44738 44730 44722 44747 44738 44722 46036 45403 44723 44723 45380 46036 45382 45380 44723 44723 45379 45382 46049 44736 44725 44725 45396 46049 44725 45395 45396 45409 45402 44726 44728 44732 45409 44740 44739 44731 46051 45409 44732 44732 45419 46051 46047 45419 44732 44732 45403 46047 45417 45404 44733 44734 44735 44745 45405 44745 44735 46053 45405 44735 46054 46053 44735 44735 45407 46054 44735 44736 45407 46054 45407 44736 44736 46048 46054 46049 46048 44736 45413 45408 44739 44739 44740 45413 44740 44741 45413 45414 45413 44741 46060 45414 44741 44741 45418 46060 45402 45401 44742 44743 44744 45420 46668 45420 44744 46669 46668 44744 47373 46669 44744 44744 46055 47373 44744 45419 46055 44744 45416 45419 46057 44746 44745 44745 45406 46057 44745 45405 45406 46057 45404 44746 45424 44755 44749 44749 45423 45424 44756 44752 44751 44760 44756 44751 44752 45422 46058 44752 45421 45422 44752 44760 45421 44752 44756 44760 45426 44763 44753 44753 44757 45426 44758 44757 44753 44764 44759 44754 45424 44764 44755 46668 45426 44757 44757 44758 46668 44758 45420 46668 45429 45428 44759 44759 44766 45429 44759 44764 44766 46064 45421 44760 44760 45430 46064 44760 44761 45430 45426 45425 44762 44762 44763 45426 44768 44766 44765 45432 45429 44766 44766 44768 45432 44769 45428 45432 46068 45440 44770 46073 46068 44770 44771 45438 45441 45439 45438 44771 45440 45439 44771 44772 45441 45442 45450 45449 44773 45448 44777 44774 44774 45447 45448 44776 46079 46710 46080 46079 44776 46081 46080 44776 44776 44782 46081 44777 45448 45452 46078 44778 44777 44777 45451 46078 45452 45451 44777 45456 44779 44778 45458 45456 44778 46078 45458 44778 45453 44783 44780 44780 44784 45453 44785 44784 44780 44792 44785 44780 44780 44786 44792 44780 44781 44786 44782 44783 46081 44783 45454 46081 44783 45453 45454 45454 45453 44784 46097 45454 44784 44784 44785 46097 44785 45460 46097 44785 44792 45460 44793 44792 44786 45455 44794 44787 46091 45459 44788 44788 46086 46091 44788 46084 46086 44791 44790 44789 45464 44791 44789 45469 45464 44789 44789 45468 45469 44789 45463 45468 44790 44791 44795 44792 44793 45460 45465 45460 44793 44793 44796 45465 44806 44804 44794 46087 44806 44794 44794 46082 46087 44794 45455 46082 45466 45465 44796 44796 44797 45466 44797 44798 45466 45472 45466 44798 44798 44803 45472 46093 44800 44799 44799 45467 46093 46730 45461 44800 47418 46730 44800 44800 46736 47418 44800 46093 46736 46094 45467 44801 44801 44809 46094 44801 44808 44809 45481 45480 44802 44802 45471 45481 44803 44813 45472 44803 44807 44813 44804 44805 45479 44806 44805 44804 45482 45479 44805 46740 45482 44805 44805 46092 46740 44805 44806 46092 44806 46087 46092 44811 44809 44808 46753 46751 44809 44809 44810 46753 44811 44810 44809 46751 46094 44809 46755 46753 44810 46771 46755 44810 44810 46112 46771 44810 44811 46112 44811 45512 46112 44812 44825 46109 44812 44813 44825 44814 44813 44812 46105 44814 44812 46110 46105 44812 44812 46109 46110 44813 44814 45472 46750 45472 44814 46752 46750 44814 44814 46105 46752 44817 44816 44815 45482 44817 44815 44815 45479 45482 45496 44826 44816 44816 44817 45496 46761 45496 44817 44817 46100 46761 44817 45482 46100 45484 45483 44818 44818 44819 45484 44819 44830 45484 44819 44827 44830 44832 44822 44820 44833 44832 44820 44820 44821 44833 45507 44833 44821 44831 44823 44822 44832 44831 44822 44831 44824 44823 44824 44831 45495 44825 45495 46109 46111 45511 44826 44826 45496 46111 45491 44830 44827 44827 44835 45491 44827 44829 44835 44827 44828 44829 44836 44829 44828 44837 44835 44829 44829 44836 44837 46106 45487 44830 46107 46106 44830 44830 45492 46107 45493 45492 44830 44830 45491 45493 45487 45484 44830 44831 45494 45495 44831 44832 45494 46108 45494 44832 44832 44833 46108 44833 45507 46108 44835 44837 45501 45503 45491 44835 44835 45501 45503 45501 44837 44836 44836 45498 45501 44844 44843 44838 44838 44842 44844 44840 44841 45514 44840 45514 45515 45527 44844 44842 45528 45527 44842 44842 44848 45528 44843 44844 46775 46791 46775 44844 44844 45527 46791 45532 44851 44845 46138 45532 44845 44845 45517 46138 45525 44847 44846 44846 45524 45525 45535 45533 44847 46145 45535 44847 46146 46145 44847 44847 45525 46146 44848 44849 45528 44849 44850 45528 45532 44861 44851 44864 44856 44853 44853 44863 44864 44856 44855 44854 44855 44856 45536 45543 45536 44856 44856 44864 45543 44857 45547 46141 44857 45546 45547 45559 45546 44857 46141 44858 44857 46140 45529 44858 46141 46140 44858 44860 44861 44868 45548 44868 44861 46149 45548 44861 44861 45532 46149 44862 45534 45540 44874 44864 44863 45557 45543 44864 44864 44874 45557 44865 44866 45559 44867 44866 44865 44872 44867 44865 45571 45559 44866 44866 45570 45571 44866 44879 45570 44866 44867 44879 44867 44875 44879 44867 44872 44875 44868 45548 45549 45555 45554 44869 44869 44870 45555 46154 45555 44870 44870 46153 46154 46177 45556 44873 44873 46175 46177 44873 45564 46175 45556 44874 44873 44874 45556 45557 44881 44879 44875 44875 44876 44881 44888 44881 44876 45576 45572 44877 45577 45576 44877 45578 45577 44877 44877 44878 45578 44878 45575 45578 44879 44880 45570 44881 44880 44879 46184 45570 44880 44880 46182 46184 46191 46182 44880 44880 44881 46191 46193 46191 44881 44881 44888 46193 45597 45587 44882 44882 44883 45597 44884 44883 44882 46196 45597 44883 44883 44884 46196 46204 46196 44884 46836 46204 44884 44884 46835 46836 44884 46185 46835 46179 45579 44885 44885 45574 46179 44890 44887 44886 44892 44891 44887 44887 44889 44892 44890 44889 44887 44888 44899 45592 46195 46193 44888 44888 45593 46195 44888 45592 45593 44893 44892 44889 44917 44893 44889 46203 44917 44889 47548 46203 44889 44889 45580 47548 44889 44890 45580 46831 45580 44890 44890 45585 46831 45590 44901 44895 45591 45590 44895 44895 44898 45591 44895 44896 44898 46200 44898 44896 44896 45581 46200 46829 45585 44897 46845 45591 44898 44898 46200 46845 44899 44902 45592 45578 45575 44900 45584 45578 44900 44900 45582 45584 45583 45582 44900 44902 44903 45592 44903 44908 45592 45589 45588 44904 46201 45589 44904 45586 44906 44905 46200 45586 44905 46846 46200 44905 44905 45617 46846 45586 45581 44906 44907 45608 45620 44907 45596 45608 44907 44908 45596 44909 44908 44907 45614 44909 44907 46219 45614 44907 44907 45620 46219 45593 45592 44908 45595 45593 44908 44908 44909 45595 44909 46210 46861 44909 45614 46210 46861 45595 44909 44923 44920 44910 44912 44914 46205 44912 44913 44914 44921 44914 44913 44914 44921 45598 44914 45598 46205 44915 44916 45607 44917 44916 44915 44916 45605 45606 46202 45605 44916 44916 44917 46202 44916 45606 45607 46203 46202 44917 45629 45625 44918 44918 44939 45629 44919 46860 46866 44919 45590 46860 46217 46212 44919 46866 46217 44919 45599 45598 44921 45600 45599 44922 44923 45597 45609 44924 45615 45616 44924 45611 45615 45616 44943 44924 44925 45621 45624 44926 44927 44941 44928 44927 44926 44943 44928 44926 46240 44942 44927 44927 44928 46240 44942 44941 44927 46241 46240 44928 44928 46231 46241 44928 45630 46231 44928 44943 45630 44946 44932 44929 44947 44946 44929 44930 44934 44944 44930 44933 44934 44930 44931 44933 44932 44931 44930 46879 44933 44931 44931 45633 46879 44931 44932 45633 44932 44946 45633 45635 44934 44933 46228 45635 44933 44933 46227 46228 46879 46227 44933 44934 44935 44936 45635 44935 44934 44934 44936 44944 46235 44937 44935 44935 45636 46235 45637 45636 44935 44935 45635 45637 44937 44936 44935 44936 44938 44944 45621 44938 44936 44936 44937 45621 46235 45638 44937 45638 45621 44937 44939 45628 45629 44939 44940 45628 45631 45630 44943 46216 45631 44943 44943 45616 46216 44945 45643 45644 46238 45643 44945 45634 45633 44946 46234 45634 44946 44946 45639 46234 44946 44957 45639 44946 44947 44957 44948 44952 45641 44953 44952 44948 44949 45640 45649 46901 45640 44949 44949 44950 46901 44950 46248 46901 44950 46247 46248 46907 46247 44950 44950 44962 46907 44950 44961 44962 45648 44961 44950 46246 44958 44951 44951 46243 46246 44951 45626 46243 45642 45641 44952 45646 45642 44952 44952 44959 45646 44952 44954 44959 44952 44953 44954 44968 44959 44954 44955 44969 44970 45645 44969 44955 44955 45644 45645 44956 44961 45648 44963 44961 44956 45654 44963 44956 45640 45639 44957 45649 45640 44957 46246 45652 44958 44968 44966 44959 46909 45646 44959 44959 46256 46909 44959 45656 46256 44959 44964 45656 44966 44964 44959 46262 45653 44960 44963 44962 44961 44962 46906 46907 44962 44963 46906 46914 46906 44963 44963 46251 46914 44963 46250 46251 44963 45654 46250 45660 45656 44964 44964 44965 45660 44966 44965 44964 44965 44973 45660 44965 44966 44973 44966 44967 44973 44968 44967 44966 44974 44973 44967 44971 44970 44969 45647 44971 44969 46257 45647 44969 44969 45645 46257 46912 45655 44971 44971 45647 46912 44972 46252 46271 44972 45651 46252 44973 44974 45662 45661 45660 44973 45662 45661 44973 44975 44978 44982 44975 44976 44978 44977 44976 44975 44980 44977 44975 45659 44978 44976 44976 44979 45659 44976 44977 44979 44980 44979 44977 45658 44982 44978 45659 45658 44978 44979 45663 45670 44979 44980 45663 46268 45659 44979 44979 45667 46268 45668 45667 44979 45670 45668 44979 44980 44986 45663 44981 45661 45662 44981 44987 45661 45657 44983 44982 45658 45657 44982 44985 44984 44983 46933 44985 44983 46934 46933 44983 44983 46276 46934 44983 45657 46276 46282 44989 44985 46933 46282 44985 45669 45661 44987 45673 45669 44987 44987 44988 45673 44988 44998 45682 45682 45673 44988 46282 45676 44989 44992 44991 44990 45671 44994 44990 44990 44993 45671 44990 44991 44993 44995 44993 44991 46270 45671 44993 46274 46270 44993 44993 45672 46274 44993 45664 45672 44996 45001 45002 45707 45698 44997 44997 45697 45707 44997 45695 45697 44997 44998 45695 44999 44998 44997 45698 44999 44997 44998 44999 45682 44998 45687 45695 46958 46285 44999 44999 46289 46958 44999 45698 46289 46285 45682 44999 45686 45001 45000 45000 45008 45686 45003 45002 45001 45686 45003 45001 45693 45688 45002 45002 45003 45693 45003 45692 45693 45003 45686 45692 45004 45680 46291 45681 45680 45004 46297 45009 45005 45005 46296 46297 45005 46292 46296 45005 45006 46292 45006 46286 46292 45006 45684 46286 46966 45689 45007 45007 46290 46966 45692 45686 45008 45008 45691 45692 45704 45012 45009 45724 45704 45009 46311 45724 45009 45009 46297 46311 45705 45011 45010 45010 45016 45705 46293 45699 45011 45011 45705 46293 45725 45710 45012 45012 45704 45725 45013 45019 45024 45013 45018 45019 45713 45018 45013 45716 45015 45014 45716 45017 45015 46303 45705 45016 45016 46302 46303 45016 45017 46302 45017 45716 46302 46299 45019 45018 46971 46299 45018 46973 46971 45018 45018 45714 46973 45018 45713 45714 45718 45020 45019 46299 45718 45019 46313 45719 45022 45022 46295 46313 45023 46314 46315 47002 46314 45023 47687 47002 45023 45023 45732 47687 45025 45719 45723 46330 45726 45026 45026 46322 46330 45026 45027 46322 45027 45723 46322 45031 45029 45028 46332 45031 45028 45028 45727 46332 46331 45729 45030 45030 45031 46331 47019 46331 45031 45031 46332 47019 46333 45727 45032 45032 46330 46333 45032 45726 46330 45033 45034 45728 46337 45035 45033 46338 46337 45033 45033 45728 46338 45731 45038 45035 46336 45731 45035 46337 46336 45035 45040 45039 45036 45036 45037 45040 46364 45040 45037 45037 46363 46364 45037 45741 46363 45743 45741 45037 46356 45743 45037 45037 46347 46356 45037 45733 46347 45037 45038 45733 45735 45733 45038 46335 45735 45038 45038 45731 46335 46364 46357 45039 45039 45040 46364 46345 45738 45042 46355 46345 45042 45042 46340 46355 45042 45740 46340 45738 45044 45042 46359 45744 45043 46360 46359 45043 45043 46345 46360 45043 45739 46345 45043 45044 45739 45044 45738 45739 45050 45048 45045 45052 45050 45045 45745 45052 45045 47057 47056 45046 46368 45047 45046 47055 46368 45046 47743 47055 45046 47744 47743 45046 45046 47056 47744 45047 45052 45745 46372 45052 45047 45047 46369 46372 45047 46368 46369 45048 45050 45051 46373 45747 45049 46374 46373 45049 45052 45051 45050 45051 45054 45055 45051 45052 45054 45752 45054 45052 46372 45752 45052 46379 45748 45053 45053 45056 46379 45755 45055 45054 45054 45752 45755 45055 45753 45758 45754 45753 45055 45755 45754 45055 46380 46379 45056 45056 45058 46380 45059 45058 45057 45058 45059 46380 45059 46375 46380 45059 45751 46375 45061 46386 46387 45061 45065 46386 45763 45762 45062 45761 45759 45063 46404 45067 45064 45064 46399 46404 45065 45767 46386 46404 45778 45067 46410 45772 45068 45068 45785 46410 47066 45785 45068 47068 47066 45068 45068 45069 47068 45070 45069 45068 45772 45070 45068 47069 47068 45069 45069 46406 47069 45069 45070 46406 46407 46406 45070 45070 45071 46407 45071 45769 46407 45072 45075 45768 45768 45767 45072 45080 45075 45073 45073 45074 45080 45075 45080 46401 46401 45768 45075 45076 45777 45779 45076 45776 45777 45076 45775 45776 45778 45775 45076 45077 47782 47783 45077 47775 47782 47785 47775 45077 47788 47785 45077 45077 46395 47788 46403 46402 45080 45080 45081 46403 45082 45081 45080 46402 46401 45080 45081 45083 45773 45081 45082 45083 45081 45773 46403 45084 45083 45082 45085 45084 45082 45087 45085 45082 45774 45773 45083 45083 45084 45774 45777 45774 45084 45084 45089 45777 45084 45085 45089 45085 45088 45089 45085 45087 45088 45086 45096 45102 45086 45087 45096 45088 45087 45086 45101 45088 45086 45102 45101 45086 45097 45096 45087 45782 45089 45088 45088 45101 45782 45779 45777 45089 45782 45103 45089 45787 45091 45090 46412 45787 45090 45090 45092 46412 45787 45094 45091 45092 46411 46412 45092 45780 46411 45093 45094 45788 45093 45788 46413 45094 45787 45788 46414 45786 45095 45096 45097 45790 45790 45102 45096 45097 45789 46417 46417 45790 45097 45795 45102 45098 45796 45795 45098 46418 45796 45098 45098 45099 46418 45100 45099 45098 45102 45100 45098 47083 46418 45099 45099 45100 47083 45100 47081 47083 45100 45790 47081 45100 45102 45790 45101 45102 45782 45795 45782 45102 45791 45104 45103 45103 45781 45791 45782 45781 45103 45801 45105 45104 45104 45791 45801 45108 45107 45106 45107 45111 46420 45107 45108 45111 45804 45115 45110 45110 45802 45804 45111 45112 45805 45111 45805 46420 45122 45120 45113 45113 45114 45122 45131 45122 45114 45114 45121 45131 45114 45117 45121 45118 45116 45115 45804 45118 45115 45807 45117 45116 45116 45118 45807 45806 45121 45117 46431 45806 45117 45117 45807 46431 46430 45807 45118 45118 45804 46430 46441 45820 45119 45119 45821 46441 45822 45131 45121 46445 45822 45121 45121 46444 46445 45121 45806 46444 45813 45137 45123 45127 45126 45124 45126 45125 45124 45125 45808 45815 45125 45126 45808 45126 45127 45808 45127 45128 45808 46439 45808 45128 45128 45818 46439 45129 45130 45138 45817 45138 45130 45822 45821 45131 46425 46423 45132 45132 45809 46425 45133 45134 45139 45811 45810 45135 45135 45136 45811 45812 45811 45136 45137 45813 45823 47103 45825 45140 45140 47101 47103 45140 46449 47101 46450 46449 45140 45140 45150 46450 45140 45141 45150 45831 45144 45143 45832 45831 45143 45830 45828 45144 45831 45830 45144 46457 45146 45145 45145 45148 46457 45149 45148 45145 46456 45149 45145 45145 45829 46456 45833 45147 45146 45834 45833 45146 46460 45834 45146 45146 46459 46460 45146 46457 46459 46459 46457 45148 47113 46459 45148 45148 47111 47113 45148 45149 47111 45149 46456 47111 45150 45152 46450 45150 45151 45152 45153 45152 45151 45152 45155 46450 45152 45153 45155 46452 45155 45153 46461 46452 45153 46462 46461 45153 47115 46462 45153 45153 45837 47115 45153 45836 45837 45153 45160 45836 45153 45154 45160 47107 46450 45155 45155 46451 47107 46452 46451 45155 45160 45161 45836 45841 45836 45161 45163 45833 45834 45839 45164 45163 45163 45835 45839 45163 45834 45835 45849 45170 45164 45164 45839 45849 45850 45840 45165 46474 45850 45165 45166 45840 45850 45166 45850 46473 45167 45168 45844 46466 45842 45167 46476 46466 45167 46477 46476 45167 45167 46469 46477 45167 45844 46469 45169 45172 45848 45170 45849 47131 47131 45854 45170 45852 45172 45171 45171 45174 45852 46472 45848 45172 46478 46472 45172 45172 45852 46478 45858 45856 45173 45173 45851 45858 45173 45843 45851 45173 45856 45862 45853 45852 45174 45174 45175 45853 45868 45192 45177 45863 45853 45178 45179 45183 45865 45180 45182 45185 45180 45181 45182 45867 45185 45182 46489 45865 45183 45183 45184 46489 45185 45184 45183 47155 46489 45184 45184 45185 47155 45185 45867 47155 45875 45193 45186 45186 45194 45875 45877 45188 45187 45187 45190 45877 45187 45189 45190 46496 45195 45188 45188 45877 46496 45191 45190 45189 45190 45196 45877 45190 45191 45196 45192 45872 45874 45192 45868 45872 47160 47143 45193 45193 46495 47160 45193 45876 46495 45193 45875 45876 45194 45195 45875 46498 45875 45195 45195 46496 46498 45196 45197 45877 46500 45877 45197 47163 46500 45197 47169 47163 45197 45197 45878 47169 45889 45887 45198 46502 45889 45198 45198 45199 46502 45199 45879 46502 45199 45200 45879 45880 45879 45200 45200 45201 45880 45886 45880 45201 46504 45886 45201 45201 45203 46504 45206 45205 45204 45209 45206 45204 45204 45208 45209 45883 45208 45204 45204 45882 45883 45204 45871 45882 45204 45207 45871 45204 45205 45207 45874 45871 45207 45890 45216 45208 45208 45883 45890 45211 45229 45893 45211 45219 45229 45221 45220 45212 45212 45213 45221 45222 45221 45213 45889 45222 45213 45213 45887 45889 46511 46505 45214 45215 45217 45218 45888 45217 45215 45215 45216 45888 46508 45888 45216 45216 45890 46508 46518 45902 45217 45217 45888 46518 45219 45223 45229 45226 45224 45220 45220 45225 45226 45220 45221 45225 45894 45225 45221 47200 45894 45221 45221 47190 47200 45221 45222 47190 45222 47189 47190 45222 47180 47189 45222 45889 47180 45231 45229 45223 45230 45226 45225 45894 45230 45225 45897 45893 45229 45903 45897 45229 45229 45231 45903 45900 45235 45230 45230 45898 45900 45899 45898 45230 45230 45895 45899 45230 45894 45895 45911 45903 45231 45916 45911 45231 45231 45232 45916 45232 45241 45916 45232 45233 45241 45245 45238 45234 45906 45239 45235 45235 45900 45906 45913 45910 45236 45245 45244 45238 45908 45246 45239 45239 45906 45908 45925 45916 45241 46539 45928 45242 45242 45243 45254 45928 45245 45242 46532 45920 45245 45245 45928 46532 45252 45248 45246 45908 45252 45246 46537 45932 45247 45921 45249 45248 45248 45252 45921 45249 45921 45923 45922 45921 45250 47235 45922 45250 47980 47235 45250 47981 47980 45250 45250 47226 47981 45250 45251 47226 45252 45251 45250 45921 45252 45250 45251 46520 47226 45251 45252 46520 45252 45908 46520 45256 45255 45253 45255 45256 45257 46541 45257 45256 45256 45935 46541 45945 45270 45257 45257 45944 45945 45257 45936 45944 46541 45936 45257 45258 45940 45941 45942 45263 45258 45258 45941 45942 45259 45260 45284 45284 45283 45259 45950 45948 45261 46555 45950 45261 45261 45947 46555 45261 45946 45947 46551 45946 45262 45262 45275 46551 46552 45279 45264 46553 46552 45264 45264 45281 46553 45266 45267 45956 45267 45943 45956 45267 45268 45943 45957 45943 45268 45268 45269 45957 46565 45957 45269 45269 45958 46565 45960 45271 45270 47259 45960 45270 45270 45944 47259 45945 45944 45270 45951 45274 45272 46556 45951 45272 46557 46556 45272 46559 46557 45272 46560 46559 45272 45272 45273 46560 45274 45273 45272 47262 46560 45273 45273 45961 47262 45273 45274 45961 46558 46551 45274 45274 45951 46558 45274 45276 45961 45274 45275 45276 46551 45275 45274 45276 45277 45961 45962 45961 45277 45277 45952 45962 45277 45282 45952 46552 45954 45278 45278 45279 46552 46553 45281 45280 46568 46553 45280 45280 45963 46568 48004 46546 45283 45283 45285 48004 45283 45284 45285 46574 45285 45284 45284 45286 46574 45290 45286 45284 45285 47272 48004 45285 46574 47272 45286 45948 46574 45968 45302 45287 45969 45968 45287 46561 45969 45287 45287 45288 46561 45288 45954 46561 45289 45302 45303 47276 47263 45291 45291 45292 47276 45292 45293 47276 45295 45293 45292 45293 45294 47276 45295 45294 45293 47277 47276 45294 45294 45972 47277 45294 45295 45972 45295 45305 45972 45295 45296 45305 45297 45296 45295 45298 45299 45971 45300 45299 45298 45299 45970 45971 45299 45301 45970 45299 45300 45301 45310 45301 45300 45978 45970 45301 45301 45310 45978 45304 45303 45302 45968 45304 45302 45968 45311 45304 45305 45309 46582 46582 45972 45305 46593 45312 45306 46594 46593 45306 45306 45307 46594 47306 46594 45307 45307 47304 47306 45307 45989 47304 45308 45315 45323 45979 45978 45310 45311 45968 45980 45984 45313 45312 46593 45984 45312 45984 45319 45313 45315 45316 45323 45328 45323 45316 45987 45328 45316 45316 45986 45987 45316 45983 45986 45316 45980 45983 45317 45318 45990 45984 45320 45319 46598 45324 45320 45320 45984 46598 45321 45325 45326 45321 45324 45325 45991 45325 45324 46598 45991 45324 45327 45326 45325 45991 45327 45325 45992 45341 45326 45326 45327 45992 45995 45992 45327 45327 45991 45995 45988 45338 45328 45328 45987 45988 45336 45330 45329 47311 46601 45330 45330 46615 47311 45330 45336 46615 46001 45996 45331 45333 45332 45331 45996 45333 45331 46595 45976 45332 45332 45333 46595 47315 46595 45333 45333 46605 47315 45333 45996 46605 45345 45344 45334 45334 45335 45345 48056 45345 45335 45335 48049 48056 45335 46587 48049 46588 46587 45335 45336 46003 46615 45337 45338 46004 45347 45346 45337 46004 45347 45337 45338 45988 45994 45338 45994 46004 45999 45340 45339 46000 45999 45339 45339 45992 46000 45339 45341 45992 47302 46596 45342 45342 46606 47302 45342 45343 46606 45343 45993 47331 47309 46606 45343 47331 47309 45343 45344 45350 45351 45358 45350 45344 46009 45358 45344 45344 46008 46009 45344 45345 46008 47327 46008 45345 48056 47327 45345 46010 45372 45347 45347 46004 46010 45348 46619 47313 45348 46617 46619 45348 46011 46617 45348 45352 46011 46609 45993 45349 45349 45354 46609 46012 46011 45352 45353 46007 46013 45354 45361 46018 46625 46609 45354 45354 46018 46625 45355 45356 46019 45357 45356 45355 46626 46019 45356 45356 46610 46626 45356 45357 46610 45357 45358 46610 46611 46610 45358 46612 46611 45358 45358 46015 46612 45358 46009 46015 45359 46017 46021 45359 45360 46017 45372 45371 45362 45371 45363 45362 45365 45364 45363 46026 45365 45363 46029 46026 45363 45363 45371 46029 45364 45365 46016 46024 46016 45365 46025 46024 45365 46026 46025 45365 46022 45367 45366 46632 46001 45367 45367 46022 46632 46027 45377 45368 46035 46027 45368 46638 46035 45368 45368 46637 46638 45368 46034 46637 45368 45376 46034 47350 46636 45369 48100 47350 45369 45369 47343 48100 45369 45370 47343 45371 45370 45369 46636 45371 45369 45370 47334 47343 45370 45371 47334 45371 45372 47334 45371 46025 46029 46636 46025 45371 45372 46010 47334 46043 46023 45373 45373 45399 46043 45373 45391 45399 45373 45374 45391 45375 45374 45373 46023 45375 45373 46650 46030 45375 45375 46045 46650 45375 46023 46045 45376 46033 46034 46027 45378 45377 46641 46028 45378 45378 46639 46641 45378 46027 46639 46028 45382 45379 45380 45381 46642 45382 45381 45380 46642 46036 45380 45381 45382 46028 45381 46028 46642 45387 45384 45383 46037 45387 45383 45384 46011 46012 45384 45385 46011 45387 45385 45384 46618 46011 45385 45385 45386 46618 45387 45386 45385 47354 46618 45386 48096 47354 45386 45386 45387 48096 45387 47367 48096 45387 46645 47367 45387 46037 46645 46040 46037 45388 45388 45393 46040 45389 45390 46646 46646 45394 45389 45390 46628 46646 45391 45398 45399 45392 45405 46041 46040 45393 45392 46041 46040 45392 45397 45395 45394 46646 45397 45394 45397 45396 45395 47372 46049 45396 45396 45397 47372 45397 47371 47372 45397 46646 47371 45400 45399 45398 45399 46031 46043 46032 46031 45399 45399 45400 46032 46050 46032 45400 45400 45408 46050 46052 45415 45401 45401 46051 46052 45401 45402 46051 45402 45409 46051 45403 46036 46047 45406 45405 45404 46057 45406 45404 46053 46041 45405 45408 45411 46050 45412 45411 45408 45413 45412 45408 46655 46050 45411 46656 46655 45411 45411 45412 46656 45412 46059 46656 45412 45413 46059 45413 45414 46059 46061 46059 45414 45414 46060 46061 46651 45419 45415 45415 46052 46651 45419 45416 45415 46062 46060 45418 46665 46062 45418 45418 46058 46665 46651 46051 45419 46056 46055 45419 46653 46056 45419 45419 46647 46653 45419 46047 46647 45421 46064 46066 46672 45422 45421 46674 46672 45421 45421 46065 46674 46066 46065 45421 46665 46058 45422 46672 46665 45422 45425 45427 45431 45425 45426 45427 46677 45427 45426 45426 46669 46677 45426 46668 46669 46681 45431 45427 47387 46681 45427 45427 46677 47387 45428 45429 45432 45430 46063 46064 46680 45433 45431 46681 46680 45431 46679 46067 45433 46680 46679 45433 46063 45436 45434 46064 46063 45434 45434 45435 46064 46066 46064 45435 45438 45439 46068 45443 45441 45438 46069 45443 45438 45438 46068 46069 45439 45440 46068 45443 45442 45441 45445 45444 45442 46070 45445 45442 45442 45443 46070 46071 46070 45443 46683 46071 45443 45443 46069 46683 45444 45445 45446 46077 45446 45445 45445 46074 46077 45445 46072 46074 45445 46070 46072 46077 45447 45446 46075 45448 45447 46076 46075 45447 46685 46076 45447 46687 46685 45447 45447 46077 46687 46075 45452 45448 46691 46689 45449 46695 46691 45449 45449 45450 46695 46710 46695 45450 46706 46078 45451 45451 46701 46706 45451 45452 46701 46702 46701 45452 45452 46693 46702 45452 46075 46693 46725 46081 45454 46737 46725 45454 46738 46737 45454 45454 46097 46738 46083 46082 45455 46719 46083 45455 45455 45456 46719 45456 45457 46719 45458 45457 45456 46720 46719 45457 45457 45458 46720 45458 46078 46720 46091 45462 45459 46098 46097 45460 45460 45465 46098 46730 46729 45461 45462 46091 46096 46096 45476 45462 45464 45470 45471 45464 45469 45470 45465 45473 46098 45465 45466 45473 45466 45472 45473 46094 46093 45467 45477 45469 45468 45485 45470 45469 46099 45485 45469 45469 45477 46099 45481 45471 45470 45485 45481 45470 45474 45473 45472 45478 45474 45472 46750 45478 45472 46734 46098 45473 46749 46734 45473 45473 45474 46749 45474 45478 47419 47415 46749 45474 47419 47415 45474 45475 45476 46095 46096 46095 45476 45478 46750 47419 46760 45488 45480 45480 46104 46760 45480 45485 46104 45480 45481 45485 46101 46100 45482 46740 46101 45482 45483 45485 46099 45486 45485 45483 45483 45484 45486 45487 45486 45484 45485 46103 46104 45485 45486 46103 46106 46103 45486 45486 45487 46106 46124 45499 45488 45488 46107 46124 46760 46107 45488 45503 45493 45491 46124 46107 45492 45492 46123 46124 45492 46121 46123 45492 46120 46121 45492 45505 46120 45492 45493 45505 45493 45503 45505 46109 45495 45494 46110 46109 45494 46115 46110 45494 45494 46114 46115 45494 46108 46114 46767 46111 45496 45496 46761 46767 46119 45498 45497 45502 45501 45498 46119 45502 45498 46124 46113 45499 45513 45512 45500 45506 45503 45501 45501 45504 45506 45501 45502 45504 46781 45504 45502 47440 46781 45502 45502 46119 47440 45506 45505 45503 46786 45506 45504 45504 46781 46786 46128 46120 45505 45505 46127 46128 45505 46126 46127 45505 45506 46126 46786 46126 45506 46774 46108 45507 45507 45508 46774 45509 45508 45507 46773 45509 45507 48164 46774 45508 48167 48164 45508 45508 45509 48167 45509 47443 48167 45509 46773 47443 45510 45511 46125 45511 46111 46125 46778 46112 45512 45512 45518 46778 45512 45513 45518 45519 45518 45513 45516 45515 45514 46768 45516 45514 45515 45520 45521 45515 45516 45520 45516 46768 46783 47454 45520 45516 45516 46787 47454 45516 46783 46787 45517 46135 46138 46136 46135 45517 45517 46130 46136 46792 46778 45518 45518 46131 46792 47454 45521 45520 45521 47454 47459 45526 45524 45521 46799 45526 45521 46800 46799 45521 47460 46800 45521 45521 47459 47460 45531 45523 45522 46151 45531 45522 45522 46150 46151 46793 46131 45523 45523 46139 46793 45523 45531 46139 45526 45525 45524 45525 45526 46146 45526 46145 46146 46799 46145 45526 45527 46132 46791 45527 45530 46132 45527 45528 45530 46134 45530 45529 46140 46134 45529 46133 46132 45530 46134 46133 45530 46148 46139 45531 47463 46148 45531 48200 47463 45531 45531 47462 48200 45531 46151 47462 45532 45560 46149 46137 45560 45532 46138 46137 45532 45535 45534 45533 45542 45540 45534 46155 45542 45534 45534 45535 46155 46156 46155 45535 45535 46145 46156 46157 45544 45536 45536 45543 46157 45539 45538 45537 46138 45539 45537 45537 46137 46138 47465 46137 45537 45537 47464 47465 48202 47464 45537 45537 45538 48202 45538 45539 46135 45538 48184 48202 45538 46135 48184 46138 46135 45539 45540 45541 46166 45542 45541 45540 47468 46166 45541 47469 47468 45541 45541 45542 47469 45542 46155 47469 46169 46157 45543 45543 45557 46169 45544 46157 46158 45545 45546 45571 45547 45546 45545 46161 45547 45545 45545 46160 46161 46170 46160 45545 45545 45571 46170 45546 45559 45571 46163 46147 45547 45547 46162 46163 45547 46161 46162 46147 46141 45547 45552 45549 45548 46149 45552 45548 45549 45550 46803 45552 45550 45549 46803 45553 45549 47492 47482 45550 47493 47492 45550 45550 46816 47493 45550 45551 46816 45552 45551 45550 47482 46803 45550 45551 46815 46816 45551 46812 46815 45551 46811 46812 45551 46165 46811 45551 45552 46165 45552 45561 46165 46149 45561 45552 46152 46150 45553 46803 46152 45553 46154 45563 45554 45554 45555 46154 45558 45557 45556 45565 45558 45556 46176 45565 45556 46177 46176 45556 46806 46169 45557 48221 46806 45557 45557 45558 48221 45558 47511 48221 45558 46825 47511 45558 45565 46825 45560 45561 46149 45562 45561 45560 46137 45562 45560 45561 46164 46165 45561 45562 46164 48215 46164 45562 45562 47465 48215 45562 46137 47465 45563 46154 46172 45564 45572 46175 45565 46176 46825 46180 45574 45566 46813 46180 45566 45566 45567 46813 45567 46807 46813 45567 45568 46807 45569 45568 45567 45568 46167 46807 45568 46158 46167 45568 45569 46158 46178 45571 45570 46184 46178 45570 46178 46170 45571 45572 45576 46175 46188 46187 45573 45573 46173 46188 46187 46174 45573 46821 46179 45574 45574 46189 46821 45574 46180 46189 46177 46175 45576 46825 46177 45576 47510 46825 45576 45576 45577 47510 45577 46194 47510 45577 45578 46194 45578 45584 46194 45579 46179 46821 45579 46826 46829 45579 46821 46826 48255 47548 45580 45580 47561 48255 48262 47561 45580 45580 46833 48262 45580 46831 46833 45581 45586 46200 46194 45584 45582 45582 45589 46194 45582 45588 45589 45582 45583 45588 45585 46830 46831 45585 46829 46830 46199 46194 45589 46201 46199 45589 45590 46856 46860 45590 46850 46856 45590 45591 46850 45591 46849 46850 45591 46845 46849 46838 46195 45593 45593 45594 46838 45595 45594 45593 46839 46838 45594 45594 45595 46839 46861 46839 45595 45597 46204 46840 45597 46196 46204 46840 45609 45597 46844 46205 45598 45598 45601 46844 45598 45599 45601 45599 45600 45601 46852 45601 45600 46853 46852 45600 47560 46853 45600 45600 45602 47560 46851 46844 45601 46852 46851 45601 45602 46206 47560 45602 45612 46206 46207 46206 45603 45603 45604 46207 46206 45612 45603 46208 46207 45604 46209 46208 45604 46854 46209 45605 47552 46854 45605 45605 46855 47552 45605 46202 46855 46212 45620 45608 46211 45610 45609 46840 46211 45609 46214 45611 45610 46862 46214 45610 45610 46858 46862 45610 46857 46858 45610 46211 46857 46214 45615 45611 47559 45617 45613 45613 46865 47559 45613 46864 46865 47564 46864 45613 47566 47564 45613 45613 46863 47566 46878 46210 45614 45614 46219 46878 45615 46214 46215 46215 45616 45615 46223 46216 45616 46225 46223 45616 45616 46215 46225 47553 46846 45617 47559 47553 45617 46226 46219 45618 46230 46226 45618 45618 45619 46230 45620 45619 45618 46219 45620 45618 45619 45620 46230 45620 46212 46217 45620 46218 46230 45620 46217 46218 45621 45622 45624 45623 45622 45621 45638 45623 45621 46229 45624 45622 45622 45623 46229 46872 46229 45623 45623 45638 46872 45627 45626 45624 46229 45627 45624 45625 46880 47575 45625 45629 46880 48287 46863 45625 45625 47574 48287 47575 47574 45625 45626 46236 46243 45626 45627 46236 46891 46236 45627 45627 46229 46891 45628 45641 45642 46237 45629 45628 45628 45642 46237 46881 46880 45629 45629 46237 46881 46232 46231 45630 46233 46232 45630 45630 45632 46233 45630 45631 45632 46216 45632 45631 45632 46216 46233 45633 45634 46879 46888 46879 45634 45634 46234 46888 46228 45637 45635 47581 46235 45636 45636 45637 47581 45637 47579 47581 45637 46228 47579 45638 46235 46872 46242 46234 45639 45639 45640 46242 46897 46242 45640 46901 46897 45640 46899 46237 45642 46910 46899 45642 45642 46903 46910 45642 45646 46903 45645 45644 45643 46244 45645 45643 46245 46244 45643 45643 46239 46245 45643 46238 46239 46261 46257 45645 47604 46261 45645 45645 46896 47604 45645 46244 46896 46909 46903 45646 45647 46265 46912 45647 46257 46265 46255 45651 45650 45650 46249 46255 45650 46246 46249 45650 45652 46246 46254 46252 45651 46264 46254 45651 45651 46255 46264 46250 45654 45653 46263 46250 45653 45653 46262 46263 46921 46262 45655 46926 46921 45655 45655 46266 46926 46267 46266 45655 46912 46267 45655 46917 46256 45656 45656 46275 46917 45656 45666 46275 45656 45660 45666 45657 46272 46276 45657 45658 46272 46922 46272 45658 45658 45659 46922 45659 46915 46922 46916 46915 45659 45659 46268 46916 45660 45665 45666 45660 45661 45665 46278 45665 45661 45661 45669 46278 46923 45672 45664 45664 46271 46923 46278 45666 45665 46278 46275 45666 46269 46268 45667 46270 46269 45667 45667 45668 46270 45668 45671 46270 45668 45670 45671 46283 46278 45669 45669 46281 46283 45669 45673 46281 48325 46274 45672 48326 48325 45672 45672 48321 48326 45672 46923 48321 46285 46281 45673 45673 45682 46285 46287 45683 45674 46947 46287 45674 45674 45675 46947 45676 45675 45674 45675 46282 46947 45675 45676 46282 45679 45678 45677 46949 45679 45677 48349 46949 45677 49709 48349 45677 45677 49046 49709 45677 45678 49046 45678 45679 48348 45678 49043 49046 49044 49043 45678 45678 48348 49044 45679 47642 48348 45679 46288 47642 46950 46288 45679 45679 46949 46950 46981 46291 45680 45680 46949 46981 46951 46949 45680 45680 45681 46951 45681 45685 46951 46287 46286 45683 46286 45684 45683 45685 46949 46951 46950 46949 45685 45685 46288 46950 45688 45693 45694 47642 46288 45689 45689 47641 47642 45689 46966 47641 46304 45701 45690 45690 45691 46304 45692 45691 45690 45701 45692 45690 45701 45693 45692 45702 45694 45693 45693 45701 45702 45694 45702 45706 45706 45696 45694 45703 45697 45695 45695 45696 45703 45706 45703 45696 45708 45707 45697 45697 45703 45708 45698 45707 46289 46293 45700 45699 46965 46290 45700 45700 46294 46965 45700 46293 46294 45701 46304 46306 46305 45702 45701 46306 46305 45701 46305 45706 45702 46317 45708 45703 45703 46316 46317 45703 46307 46316 45703 46305 46307 45703 45706 46305 45704 45724 45725 46978 46293 45705 47647 46978 45705 45705 46303 47647 46310 46289 45707 46992 46310 45707 45707 46317 46992 45707 45708 46317 46312 45713 45709 45709 45711 46312 45709 45710 45711 45712 45711 45710 45725 45712 45710 45711 45715 46312 46997 45715 45711 45711 46996 46997 45711 45712 46996 45712 45725 46996 45715 45714 45713 46312 45715 45713 45714 45715 46997 46984 46973 45714 46985 46984 45714 46997 46985 45714 45716 45717 46302 45718 45717 45716 45717 46301 46302 45717 46300 46301 45717 46299 46300 45717 45718 46299 45719 46313 46323 46322 45723 45719 46323 46322 45719 45725 45724 45720 47011 45725 45720 45720 47010 47011 45720 45721 47010 45722 45721 45720 45724 45722 45720 45721 46995 47010 45721 46989 46995 45721 46321 46989 45721 45722 46321 45722 46311 46321 45722 45724 46311 47014 46996 45725 45725 47011 47014 46333 46332 45727 45728 46334 46338 45728 45729 46334 47017 46334 45729 45729 46331 47017 47693 45732 45730 48397 47693 45730 45730 47759 48397 47023 46335 45731 47026 47023 45731 45731 46336 47026 47692 47687 45732 47693 47692 45732 46356 46347 45733 45733 46339 46356 45733 45734 46339 45735 45734 45733 46346 46339 45734 47030 46346 45734 45734 47028 47030 45734 45735 47028 45735 46335 47028 46352 45737 45736 46353 46352 45736 45737 46352 46354 46345 45739 45738 46341 46340 45740 46354 46341 45740 45743 45742 45741 47042 46363 45741 45741 46367 47042 45741 46362 46367 45741 45742 46362 45742 45743 46366 46366 46362 45742 47037 46366 45743 45743 47031 47037 45743 46346 47031 46356 46346 45743 45744 46365 46371 45744 46361 46365 45744 46359 46361 45746 47050 47051 47053 47050 45746 45746 45747 47053 45747 47052 47053 45747 46373 47052 47059 46374 45748 45748 46379 47059 45751 45750 45749 46375 45751 45749 46376 46375 45749 46377 46376 45749 45749 46371 46377 45770 45755 45752 46383 45770 45752 45752 46382 46383 45752 46378 46382 45752 46372 46378 45753 45759 45761 45753 45754 45759 45760 45759 45754 45754 45755 45760 45770 45760 45755 45759 45760 45771 45760 45770 45771 45762 45763 46389 46387 46386 45763 45763 46388 46389 46394 46388 45763 45763 46386 46394 45766 45765 45764 46390 45766 45764 45765 45766 46400 46405 46400 45766 45766 45773 46405 46391 45773 45766 45766 46390 46391 45767 45768 46386 46398 46386 45768 46401 46398 45768 47070 46407 45769 47071 47070 45769 47797 47071 45769 45769 46397 47797 45770 46385 46393 45770 46383 46385 46410 45780 45772 45773 45774 46405 45773 46389 46403 46391 46389 45773 45774 45775 46405 45776 45775 45774 45777 45776 45774 46404 46399 45775 45775 45778 46404 45775 46399 46405 45780 46410 46411 45792 45791 45781 45794 45792 45781 45795 45794 45781 45781 45782 45795 46412 46411 45783 47831 46412 45783 45783 45784 47831 45785 45784 45783 46410 45785 45783 46411 46410 45783 45784 47830 47831 45784 47829 47830 45784 46408 47829 45784 45785 46408 46409 46408 45785 47067 46409 45785 45785 47066 47067 46417 45789 45786 45786 46414 46417 46412 45788 45787 46415 46413 45788 45788 46412 46415 45790 47074 47081 45790 47073 47074 45790 46417 47073 46419 45801 45791 45791 45792 46419 45792 45803 46419 45792 45793 45803 45794 45793 45792 45793 45802 45803 46422 45802 45793 45793 45797 46422 45793 45794 45797 45800 45797 45794 45794 45795 45800 45795 45796 45800 47084 45800 45796 45796 46418 47084 47086 46422 45797 45797 45798 47086 45799 45798 45797 45800 45799 45797 45798 45799 47086 47842 47086 45799 45799 47085 47842 45799 47084 47085 45799 45800 47084 46419 45803 45801 46422 45804 45802 46432 46430 45804 47087 46432 45804 45804 46422 47087 46421 46420 45805 47861 46444 45806 45806 47096 47861 45806 46431 47096 45807 46430 46431 45816 45815 45808 46439 45816 45808 46435 46425 45809 46436 46435 45809 45809 45810 46436 45810 45811 46436 46437 46436 45811 47097 46437 45811 45811 45812 47097 45812 45825 47097 45813 45814 46438 46448 45826 45813 45813 46438 46448 45815 46428 46429 45815 45816 46428 46439 46428 45816 46440 45818 45817 45817 45819 46440 46440 46439 45818 45819 45820 47859 47858 46440 45819 47859 47858 45819 45820 46441 47859 46442 46441 45821 45821 45822 46442 46443 46442 45822 46445 46443 45822 47103 47097 45825 45826 46446 46453 46447 46446 45826 46448 46447 45826 45827 46453 46454 46456 45829 45828 45828 45830 46456 46458 46456 45830 45830 45831 46458 45831 45832 46458 47110 46458 45832 47114 45835 45834 45834 46460 47114 47124 45839 45835 47132 47124 45835 45835 47114 47132 45836 46463 46464 45836 45841 46463 46464 45837 45836 47888 47115 45837 45837 47127 47888 45837 46464 47127 47124 45849 45839 46467 46463 45841 46465 45843 45842 46466 46465 45842 46465 45851 45843 46471 46469 45844 45844 46470 46471 47129 46470 45845 47136 47129 45845 45845 45846 47136 45847 45846 45845 46470 45847 45845 45846 47135 47136 45846 46472 47135 45846 45847 46472 45847 45848 46472 45849 47124 47131 46475 46473 45850 45850 46474 46475 45851 46465 47140 45851 45855 45858 47140 45855 45851 45852 45853 46481 46480 46478 45852 46481 46480 45852 45853 45863 46481 46490 45866 45854 47902 46490 45854 45854 47130 47902 47131 47130 45854 45855 45856 45858 45857 45856 45855 47151 45857 45855 45855 47147 47151 45855 47146 47147 45855 47141 47146 45855 47140 47141 46488 45862 45856 47152 46488 45856 45856 45857 47152 47913 47152 45857 45857 47151 47913 48619 45870 45859 45859 45860 48619 45861 45860 45859 45870 45861 45859 45860 47914 48619 45860 47153 47914 45860 45861 47153 45861 45871 46492 45861 45870 45871 45861 46491 47153 46492 46491 45861 46488 45868 45862 46483 46481 45863 46484 46483 45863 46485 46484 45863 45863 45864 46485 45865 45864 45863 46489 46486 45864 45864 45865 46489 46486 46485 45864 46490 45867 45866 45867 46486 47155 46487 46486 45867 47149 46487 45867 47150 47149 45867 45867 46490 47150 46491 45872 45868 45868 46488 46491 47156 46494 45869 45869 45870 47156 45871 45870 45869 45881 45871 45869 46494 45881 45869 48622 47156 45870 45870 48619 48622 45871 45881 45882 45871 45874 46492 46492 45874 45872 45872 46491 46492 47145 46474 45873 45873 47143 47145 46503 45876 45875 45875 46499 46503 45875 46498 46499 46503 46495 45876 46500 46496 45877 47933 47169 45878 45878 47199 47933 47922 46502 45879 45879 46501 47922 45879 45880 46501 47922 46501 45880 47923 47922 45880 45880 45886 47923 46494 45882 45881 46493 45883 45882 46494 46493 45882 46507 45890 45883 47159 46507 45883 45883 46493 47159 45886 45885 45884 47923 45886 45884 48631 47923 45884 48632 48631 45884 45884 47170 48632 45884 45885 47170 45885 45886 46504 47171 47170 45885 45885 46504 47171 45888 46513 46518 45888 46509 46513 45888 46508 46509 47182 47180 45889 45889 46502 47182 45890 46506 46508 46507 46506 45890 47946 47199 45891 45891 47202 47946 45891 45892 47202 45892 46519 47202 45892 45896 46519 45892 45893 45896 45897 45896 45893 47200 45895 45894 45901 45899 45895 45905 45901 45895 47213 45905 45895 45895 47211 47213 45895 47200 47211 46525 46519 45896 45896 45897 46525 45897 45912 46525 45897 45903 45912 45901 45900 45898 45898 45899 45901 45900 45901 45906 45901 45904 45906 45905 45904 45901 45902 46518 46523 45917 45912 45903 45903 45911 45917 45907 45906 45904 47214 45907 45904 45904 45905 47214 45905 47212 47214 47213 47212 45905 45906 45907 45908 45918 45908 45907 47214 45918 45907 45908 45918 46520 46516 46515 45909 46517 46516 45909 45909 45910 46517 45910 45913 46517 46531 45917 45911 46533 46531 45911 45911 45916 46533 47219 46525 45912 45912 46531 47219 45912 45917 46531 46522 46517 45913 46526 45924 45914 46528 46526 45914 45914 45915 46528 45915 46523 46528 45916 45926 46533 45916 45925 45926 47226 46520 45918 45918 47214 47226 46530 46529 45919 47977 47229 45920 45920 47230 47977 45920 46532 47230 47229 46538 45920 45921 45922 45923 45933 45923 45922 45934 45933 45922 47235 45934 45922 45923 45929 45935 45933 45929 45923 47215 46530 45924 45924 46526 47215 45927 45926 45925 47242 46533 45926 45926 45927 47242 45927 47241 47242 45927 46542 47241 45927 45939 46542 47249 46532 45928 45928 46539 47249 46541 45935 45929 45929 45930 46541 45931 45930 45929 47239 45931 45929 45929 45933 47239 45930 45938 46541 47992 45938 45930 45930 45931 47992 45931 47991 47992 45931 47990 47991 45931 47239 47990 45932 46536 46544 46537 46536 45932 45933 45934 47239 47979 47240 45934 45934 47235 47979 47240 47239 45934 47251 45944 45936 48003 47251 45936 45936 45937 48003 45938 45937 45936 46541 45938 45936 45937 47994 48003 45937 47993 47994 45937 47992 47993 45937 45938 47992 45939 45967 46542 45940 46548 47248 45940 46543 46548 47248 45941 45940 45953 45942 45941 47250 45953 45941 45941 47248 47250 45953 45952 45942 46562 45956 45943 46563 46562 45943 46564 46563 45943 45943 45957 46564 45944 47251 47259 46551 45947 45946 46558 46555 45947 45947 46551 46558 47273 46574 45948 47274 47273 45948 45948 45949 47274 45950 45949 45948 45949 46556 47274 45949 45950 46556 45950 46555 46556 45951 46555 46558 46556 46555 45951 47255 45962 45952 45952 47253 47255 45952 45953 47253 45953 47252 47253 47983 47252 45953 45953 47247 47983 47250 47247 45953 47268 46561 45954 45954 46552 47268 45955 45963 45966 45965 45963 45955 46562 45965 45955 45955 45956 46562 46565 46564 45957 45960 45959 45958 46567 46565 45958 45958 46566 46567 45958 46554 46566 45958 45959 46554 45959 47259 47267 45959 45960 47259 47261 46554 45959 47267 47261 45959 45961 45962 47262 45962 47255 47262 45963 45964 46568 45965 45964 45963 47280 46568 45964 48031 47280 45964 45964 46578 48031 46580 46578 45964 45964 45965 46580 45965 46562 46580 47995 46542 45967 45967 46547 47995 45967 46546 46547 45983 45980 45968 45968 45975 45983 46577 45975 45968 45968 45969 46577 47270 46577 45969 45969 46561 47270 46575 45971 45970 46576 46575 45970 45970 45978 46576 46575 45977 45971 45972 46582 47277 45973 45974 46602 45975 45974 45973 45983 45975 45973 45986 45983 45973 46592 45986 45973 46602 46592 45973 45974 47270 48729 45974 46577 47270 45974 45975 46577 48729 46602 45974 45976 46595 47298 47286 46585 45977 48030 47286 45977 45977 47278 48030 45977 46575 47278 46583 46576 45978 45978 45979 46583 46589 46583 45979 45981 45997 45998 48054 45997 45981 48055 48054 45981 45981 48053 48055 45981 47298 48053 45984 46597 46598 45984 46593 46597 45985 46005 46007 46006 46005 45985 45985 45997 46006 45998 45997 45985 46591 45987 45986 46592 46591 45986 47312 45988 45987 45987 46591 47312 47312 45994 45988 45989 46604 47304 45989 45990 46604 46598 45995 45991 46603 46000 45992 45992 45995 46603 45993 46609 47326 45993 47326 47331 47317 46004 45994 47319 47317 45994 45994 47312 47319 45995 46598 46603 45996 46001 47316 47316 46605 45996 48060 46006 45997 45997 48054 48060 46607 46017 45999 45999 46603 46607 45999 46000 46603 46001 46621 47316 46622 46621 46001 46633 46622 46001 46001 46632 46633 46627 46003 46002 46002 46024 46627 46002 46016 46024 46616 46615 46003 46627 46616 46003 47323 46010 46004 46004 47318 47323 46004 47317 47318 47330 46007 46005 46005 47324 47330 47325 47324 46005 46005 46006 47325 47329 47325 46006 48060 47329 46006 46014 46013 46007 47330 46014 46007 46015 46009 46008 46613 46015 46008 46614 46613 46008 47328 46614 46008 46008 47327 47328 46010 47323 47334 46618 46617 46011 46623 46018 46013 47344 46623 46013 46013 46014 47344 48094 47344 46014 46014 48093 48094 46014 47330 48093 46613 46612 46015 46608 46021 46017 46620 46608 46017 46017 46607 46620 46018 46624 46625 46018 46623 46624 46626 46033 46019 46629 46628 46020 46020 46021 46629 46021 46608 46629 46022 46631 46632 46022 46030 46631 46023 46038 46045 46039 46038 46023 46649 46039 46023 46023 46043 46649 47342 46627 46024 46024 46025 47342 48088 47342 46025 48099 48088 46025 46025 47366 48099 46025 46636 47366 46025 46026 46029 46640 46639 46027 46027 46035 46640 46028 46641 46642 47352 46631 46030 46030 46650 47352 46044 46043 46031 46654 46044 46031 46655 46654 46031 46031 46032 46655 46032 46050 46655 46635 46034 46033 47349 46635 46033 46033 47335 47349 46033 46626 47335 46034 46634 46637 46635 46634 46034 47360 46640 46035 46035 46638 47360 46643 46047 46036 47363 46643 46036 46036 46642 47363 46037 46042 46645 46037 46040 46042 46046 46045 46038 46038 46044 46046 46038 46039 46044 46649 46044 46039 46644 46042 46040 46040 46041 46644 46041 46053 46644 46648 46645 46042 46042 46053 46648 46644 46053 46042 46043 46044 46649 48826 46046 46044 46044 48111 48826 46044 46657 48111 46044 46654 46657 48108 46650 46045 48109 48108 46045 48110 48109 46045 46045 46046 48110 48826 48110 46046 46047 46643 46647 46648 46054 46048 47369 46648 46048 47372 47369 46048 46048 46049 47372 46651 46052 46051 46053 46054 46648 46055 46056 47375 47375 47373 46055 46056 46653 47375 46664 46656 46059 46059 46061 46664 46062 46061 46060 46671 46664 46061 46673 46671 46061 46061 46062 46673 48112 46673 46062 46062 46666 48112 46667 46666 46062 46062 46665 46667 46065 46066 46682 46676 46674 46065 46678 46676 46065 46682 46678 46065 46066 46679 46682 46066 46067 46679 46694 46069 46068 46068 46690 46694 46068 46073 46690 46694 46683 46069 46070 46071 46072 46684 46072 46071 46071 46683 46684 47391 46074 46072 46072 46684 47391 46691 46690 46073 46073 46689 46691 47393 46077 46074 46074 47391 47393 46075 46688 46693 46075 46685 46688 46075 46076 46685 48128 46687 46077 46077 47393 48128 46078 46707 46720 46078 46706 46707 46079 46704 46710 46079 46080 46704 46712 46704 46080 46721 46712 46080 46080 46081 46721 46081 46716 46721 46737 46716 46081 46081 46725 46737 46089 46087 46082 46082 46083 46089 46724 46089 46083 46726 46724 46083 46727 46726 46083 46083 46720 46727 46083 46719 46720 46084 46085 46086 46088 46086 46085 46730 46088 46085 46085 46729 46730 46735 46091 46086 46086 46088 46735 46087 46090 46092 46087 46089 46090 46088 46731 46735 46088 46730 46731 47410 46090 46089 46089 46724 47410 47412 46092 46090 46090 47410 47412 46735 46096 46091 46092 46739 46740 47414 46739 46092 46092 47412 47414 46751 46736 46093 46093 46094 46751 46756 46102 46095 46095 46096 46756 46096 46735 46746 46759 46756 46096 46096 46746 46759 47411 46738 46097 46097 46734 47411 46097 46098 46734 47441 46761 46100 46100 47428 47441 46100 46754 47428 46100 46101 46754 46101 46740 46754 46106 46104 46103 46104 46106 46760 46766 46752 46105 46105 46765 46766 46105 46110 46765 46106 46107 46760 46774 46114 46108 46110 46115 46765 46770 46125 46111 46111 46767 46770 46112 46778 48165 47431 46771 46112 48161 47431 46112 48165 48161 46112 46124 46123 46113 46113 46122 46768 46123 46122 46113 46774 46769 46114 46769 46115 46114 47435 46765 46115 46115 47432 47435 46115 46769 47432 46777 46125 46116 46116 46117 46777 46118 46117 46116 46125 46118 46116 48184 46777 46117 48907 48184 46117 46117 48174 48907 48175 48174 46117 46117 48173 48175 46117 48168 48173 46117 46118 48168 46118 46125 46770 46118 47442 48168 46118 46776 47442 46118 46770 46776 46119 47437 47440 46119 46772 47437 46119 46764 46772 46128 46121 46120 46782 46122 46121 46121 46128 46782 46121 46122 46123 46783 46768 46122 46787 46783 46122 46788 46787 46122 46794 46788 46122 46122 46782 46794 46777 46129 46125 47446 46127 46126 46126 46786 47446 46790 46128 46127 47446 46790 46127 46794 46782 46128 46128 46790 46794 46136 46130 46129 46777 46136 46129 46793 46792 46131 46132 46785 46791 46795 46785 46132 46796 46795 46132 46132 46133 46796 46133 46144 46796 46133 46134 46144 46134 46140 46144 46135 46136 48184 46136 46777 48184 46139 46148 46793 46140 46143 46144 46147 46143 46140 46140 46141 46147 47461 47448 46142 46142 46163 47461 46142 46147 46163 46142 46143 46147 46144 46143 46142 46798 46144 46142 47448 46798 46142 46798 46796 46144 47470 46156 46145 47471 47470 46145 46145 46799 47471 47449 46793 46148 47457 47449 46148 47463 47457 46148 46152 46151 46150 47473 47462 46151 48216 47473 46151 46151 47483 48216 46151 47482 47483 46151 46152 47482 46152 46803 47482 46153 46804 47484 46805 46804 46153 46153 46166 46805 47484 46154 46153 47484 46172 46154 47474 47469 46155 46155 47470 47474 46155 46156 47470 46169 46168 46157 46168 46158 46157 46168 46167 46158 46159 46808 46809 46159 46160 46808 46161 46160 46159 46809 46161 46159 46160 46171 46808 46160 46170 46171 47486 46162 46161 47488 47486 46161 46161 46809 47488 47486 47476 46162 47476 46163 46162 48214 47461 46163 46163 47476 48214 47477 46802 46164 47478 47477 46164 47489 47478 46164 48215 47489 46164 46802 46165 46164 46165 46802 46811 47468 46805 46166 46167 46801 46807 46167 46168 46801 46168 46169 46801 47485 46801 46169 46169 46806 47485 46178 46171 46170 46171 46183 46808 46171 46178 46183 47495 46173 46172 46172 47484 47495 47495 46188 46173 46819 46186 46174 46174 46187 46819 46176 46177 46825 46184 46183 46178 47513 46189 46180 46180 46813 47513 46181 46182 46191 46183 46182 46181 46190 46183 46181 46191 46190 46181 46182 46183 46184 47521 46808 46183 46183 46822 47521 46183 46190 46822 46185 46828 46835 46185 46186 46828 46186 46824 46828 46186 46819 46824 46187 46188 46820 46820 46819 46187 47508 46820 46188 48226 47508 46188 48227 48226 46188 46188 47495 48227 46827 46821 46189 47513 46827 46189 47527 46822 46190 46190 46192 47527 46190 46191 46192 46193 46192 46191 46192 46193 46195 47528 47527 46192 46192 46195 47528 46194 46197 47510 46199 46197 46194 47534 47528 46195 46195 46837 47534 46838 46837 46195 47546 47510 46197 46197 46842 47546 46197 46198 46842 46199 46198 46197 46198 46205 46842 46198 46199 46201 46846 46845 46200 46202 46203 46855 47548 46855 46203 46204 46836 46841 46841 46840 46204 46843 46842 46205 46844 46843 46205 46206 47556 47560 46206 46207 47556 47557 47556 46207 46207 46208 47557 47558 47557 46208 46208 46209 47558 46209 46854 47558 48274 46861 46210 48284 48274 46210 46210 47571 48284 46210 46878 47571 47544 46857 46211 46211 46840 47544 46213 46862 47555 46213 46214 46862 46215 46214 46213 46225 46215 46213 47565 46225 46213 46213 47555 47565 46886 46233 46216 46887 46886 46216 46216 46870 46887 46216 46223 46870 46875 46218 46217 46217 46866 46875 46892 46230 46218 46895 46892 46218 46218 46868 46895 46869 46868 46218 46875 46869 46218 46219 46877 46878 46219 46226 46877 48989 48290 46220 46220 46221 48989 46222 46221 46220 48290 46222 46220 48991 48989 46221 46221 47594 48991 46221 47591 47594 46221 46222 47591 46222 46882 47591 46222 46877 46882 47572 46877 46222 48290 47572 46222 46871 46870 46223 46223 46867 46871 46223 46224 46867 46225 46224 46223 48280 46867 46224 46224 47565 48280 46224 46225 47565 46882 46877 46226 46226 46230 46882 46227 46879 46888 47580 46228 46227 48296 47580 46227 46227 46888 48296 47580 47579 46228 46229 46872 46891 46892 46882 46230 46885 46241 46231 46231 46232 46885 46232 46233 46885 46886 46885 46233 46234 46242 46888 46873 46872 46235 47582 46873 46235 46235 47581 47582 46891 46243 46236 47584 46881 46237 46237 46899 47584 46893 46239 46238 46238 46240 46893 46900 46245 46239 47595 46900 46239 46239 46893 47595 47596 46893 46240 47597 47596 46240 48305 47597 46240 46240 46241 48305 46241 46884 48305 46241 46883 46884 46885 46883 46241 47599 46888 46242 47600 47599 46242 46242 46897 47600 46898 46246 46243 46243 46894 46898 46243 46891 46894 46244 46245 46896 46900 46896 46245 46898 46249 46246 48317 46248 46247 46247 46907 48317 46248 46897 46901 47600 46897 46248 49013 47600 46248 46248 48316 49013 48317 48316 46248 47601 46255 46249 46249 46898 47601 46263 46251 46250 47612 46914 46251 46251 46913 47612 46251 46263 46913 46923 46271 46252 46252 46253 46923 46254 46253 46252 47617 46923 46253 46253 46254 47617 46254 46264 47617 47621 46264 46255 46255 47601 47621 46918 46909 46256 46256 46917 46918 46257 46258 46265 46259 46258 46257 46905 46259 46257 46257 46260 46905 46261 46260 46257 46920 46265 46258 46258 46259 46920 46259 46911 46920 46259 46905 46911 47605 46905 46260 46260 46261 47605 46261 47604 47605 46921 46263 46262 47611 46913 46263 46263 46921 47611 47621 47617 46264 46924 46912 46265 46925 46924 46265 46265 46920 46925 46932 46926 46266 46266 46267 46932 46267 46924 46932 46267 46912 46924 47615 46916 46268 47616 47615 46268 46268 46269 47616 46269 46277 47616 46269 46270 46277 46270 46273 46277 46274 46273 46270 48333 46276 46272 46272 47626 48333 46272 46922 47626 48324 46277 46273 48325 48324 46273 46273 46274 48325 46927 46917 46275 46275 46279 46927 46275 46278 46279 46935 46934 46276 46936 46935 46276 48333 46936 46276 49025 47616 46277 46277 48324 49025 46280 46279 46278 46940 46280 46278 46278 46283 46940 47625 46927 46279 46279 46280 47625 46280 47622 47625 46280 46940 47622 46284 46283 46281 46285 46284 46281 46948 46947 46282 46282 46939 46948 46282 46933 46939 47634 46940 46283 46283 46952 47634 46283 46284 46952 46958 46952 46284 46284 46285 46958 47644 46292 46286 47656 47644 46286 46286 46287 47656 48340 47656 46287 46287 46947 48340 46289 46956 46958 46957 46956 46289 46289 46309 46957 46310 46309 46289 46290 46965 46966 46980 46295 46291 46981 46980 46291 46298 46296 46292 47644 46298 46292 46978 46294 46293 47648 46965 46294 47649 47648 46294 46294 46979 47649 46294 46978 46979 46986 46313 46295 46295 46980 46986 46298 46297 46296 46321 46311 46297 46989 46321 46297 46990 46989 46297 47639 46990 46297 46297 46298 47639 47644 47639 46298 46971 46300 46299 46974 46301 46300 46300 46971 46974 46974 46972 46301 47646 46302 46301 48353 47646 46301 48354 48353 46301 46301 46972 48354 46975 46303 46302 46976 46975 46302 46977 46976 46302 47646 46977 46302 48358 47647 46303 46303 48357 48358 46303 46975 48357 46308 46307 46305 46324 46308 46305 46305 46306 46324 46315 46314 46306 47002 46324 46306 46306 46314 47002 47007 46316 46307 46307 46325 47007 46307 46308 46325 46326 46325 46308 46308 46324 46326 46309 46987 47659 46309 46310 46987 47659 46957 46309 46992 46987 46310 46313 46986 46991 46991 46323 46313 46319 46317 46316 47007 46319 46316 46317 46319 46992 46318 47008 47009 46318 47007 47008 46318 46319 47007 46320 46319 46318 47009 46320 46318 46319 46320 46992 47662 46992 46320 46320 47009 47662 46322 46329 46330 46322 46328 46329 46322 46323 46328 47001 46328 46323 46323 46991 47001 47006 46326 46324 46324 47002 47006 47016 47007 46325 47022 47016 46325 46325 46326 47022 46326 47020 47022 46326 47006 47020 46333 46329 46327 47005 46333 46327 47673 47005 46327 47676 47673 46327 46327 46328 47676 46329 46328 46327 46328 47001 47676 46333 46330 46329 47018 47017 46331 47019 47018 46331 47674 47019 46332 46332 47005 47674 46332 46333 47005 47689 46338 46334 47690 47689 46334 47691 47690 46334 46334 47017 47691 46335 47023 47028 46336 46337 47026 47027 47026 46337 46337 46338 47027 47697 47027 46338 46338 47689 47697 46339 46346 46356 47032 46355 46340 47707 47032 46340 46340 46341 47707 46341 46342 47707 47034 46342 46341 46341 46354 47034 46342 47032 47707 46342 46343 47032 46344 46343 46342 47704 46344 46342 46342 47034 47704 49107 47708 46343 46343 49104 49107 46343 49100 49104 46343 46344 49100 47708 47032 46343 46344 47705 49100 46344 47704 47705 47041 46360 46345 46345 47033 47041 46345 46355 47033 46346 47030 47031 46358 46350 46348 46348 46357 46358 46350 46349 46348 46349 46351 46353 46349 46350 46351 47714 47036 46350 46350 46358 47714 47036 46351 46350 47035 46353 46351 47036 47035 46351 47034 46354 46352 47035 47034 46352 46352 46353 47035 46355 47032 47033 47040 46358 46357 46357 46364 47040 47715 47714 46358 46358 47040 47715 46359 46360 46361 47041 46361 46360 47045 46365 46361 47731 47045 46361 46361 47041 47731 46362 46366 46367 47039 46364 46363 47042 47039 46363 46364 47038 47040 47039 47038 46364 47742 46371 46365 46365 47045 47742 46366 47037 47716 47046 46367 46366 47047 47046 46366 46366 47043 47047 47044 47043 46366 47721 47044 46366 46366 47716 47721 48430 47042 46367 48439 48430 46367 46367 47046 48439 46370 46369 46368 47055 46370 46368 47061 46372 46369 47763 47061 46369 47768 47763 46369 46369 46370 47768 47772 47064 46370 46370 47749 47772 46370 47748 47749 46370 47055 47748 46370 47064 47768 47741 46377 46371 47742 47741 46371 47061 46378 46372 46373 46374 47052 47054 47052 46374 47058 47054 46374 47059 47058 46374 46381 46380 46375 47060 46381 46375 46375 46376 47060 47062 47060 46376 46376 46377 47062 47740 47062 46377 47741 47740 46377 47061 46382 46378 47060 47059 46379 46379 46381 47060 46379 46380 46381 46384 46383 46382 47061 46384 46382 47064 46385 46383 46383 46384 47064 46384 47061 47064 46396 46393 46385 47063 46396 46385 47064 47063 46385 46398 46394 46386 46402 46389 46388 46388 46398 46402 46388 46394 46398 46389 46402 46403 46391 46390 46389 47753 47720 46392 47769 47753 46392 48451 47769 46392 46397 47790 47797 46397 47786 47790 46397 47063 47786 46398 46401 46402 46399 46400 46405 47806 47069 46406 47807 47806 46406 46406 47070 47807 46406 46407 47070 48499 47829 46408 46408 46409 48499 49196 48499 46409 46409 48483 49196 46409 47803 48483 46409 47067 47803 47077 46415 46412 47831 47077 46412 46416 46414 46413 46413 46415 46416 47072 46417 46414 46414 46416 47072 47079 46416 46415 46415 47077 47079 47079 47072 46416 46417 47072 47073 47835 47084 46418 46418 47082 47835 47083 47082 46418 48518 48495 46420 48532 48518 46420 48536 48532 46420 46420 48535 48536 46420 46421 48535 48544 48535 46421 46421 48543 48544 46421 46423 48543 47088 47087 46422 47844 47088 46422 47845 47844 46422 46422 47086 47845 46423 46424 48543 46425 46424 46423 46424 47092 48543 46424 46425 47092 46425 46435 47092 47090 46427 46426 47093 47090 46426 46426 46429 47093 47089 46438 46427 47090 47089 46427 46428 47091 47851 46428 46439 47091 47093 46429 46428 47850 47093 46428 47851 47850 46428 46432 46431 46430 46431 46432 47096 46432 46433 47096 46434 46433 46432 47087 46434 46432 47862 47096 46433 48564 47862 46433 46433 46434 48564 46434 47846 48564 46434 47087 47846 46435 46437 47092 46435 46436 46437 48554 47092 46437 46437 47098 48554 46437 47097 47098 46438 46447 46448 47866 46447 46438 46438 47099 47866 46438 47089 47099 46439 46440 47091 47857 47095 46440 47858 47857 46440 47094 47091 46440 47095 47094 46440 46441 46442 47867 47867 47859 46441 46442 46443 48562 48562 47867 46442 46443 46444 47868 46445 46444 46443 46443 47868 48562 46444 47861 48563 48563 47868 46444 47109 46453 46446 48570 47109 46446 46446 48567 48570 46446 47871 48567 46446 47866 47871 46446 46447 47866 47102 47101 46449 47107 47102 46449 46449 46450 47107 46451 47106 47107 47865 47106 46451 46451 46452 47865 47870 47865 46452 46452 46461 47870 46455 46454 46453 47109 46455 46453 47874 47108 46455 46455 47109 47874 46456 46458 47111 48578 47111 46458 46458 47873 48578 46458 47110 47873 47116 46460 46459 46459 47113 47116 47116 47114 46460 46461 47880 48583 46461 46462 47880 46461 47869 47870 48584 47869 46461 46461 48583 48584 46462 47115 47880 47126 46464 46463 46463 46468 47126 46463 46467 46468 46464 47122 47127 47126 47122 46464 46465 46466 47140 46466 47133 47140 47134 47133 46466 46466 46476 47134 46473 46468 46467 46468 47121 47126 46468 46473 47121 47892 46477 46469 46469 46471 47892 47128 46471 46470 47129 47128 46470 46471 47128 47892 47137 47135 46472 46472 46478 47137 46473 47120 47121 46473 46475 47120 47145 46475 46474 46475 47117 47120 47125 47117 46475 47891 47125 46475 46475 47144 47891 47145 47144 46475 47893 47134 46476 46476 46477 47893 46477 47892 47893 47138 47137 46478 46478 46479 47138 46480 46479 46478 47139 47138 46479 47904 47139 46479 47906 47904 46479 47907 47906 46479 46479 47142 47907 46479 46481 47142 46479 46480 46481 46481 46482 47142 46483 46482 46481 47907 47142 46482 48609 47907 46482 46482 47908 48609 46482 46483 47908 46483 46484 47908 48615 47908 46484 46484 47154 48615 46484 46485 47154 46485 46486 47154 46486 46489 47155 48613 47154 46486 46486 46487 48613 48614 48613 46487 49297 48614 46487 46487 47149 49297 47153 46491 46488 46488 47152 47153 47902 47150 46490 47917 47158 46493 46493 47156 47917 46493 46494 47156 46493 47158 47159 47161 47160 46495 46495 46503 47161 47162 46498 46496 46496 46500 47162 47168 47167 46497 46497 47162 47168 46497 46498 47162 46499 46498 46497 47167 46499 46497 47164 46503 46499 47167 47164 46499 47932 47162 46500 47933 47932 46500 46500 47163 47933 47922 47182 46502 47178 47161 46503 46503 47164 47178 46504 46505 47171 46505 46511 47171 46510 46508 46506 47175 46510 46506 46506 47174 47175 46506 46507 47174 47919 47174 46507 46507 47159 47919 46510 46509 46508 47175 46513 46509 46509 46510 47175 47172 47171 46511 47926 47172 46511 47938 47926 46511 46511 47183 47938 47938 47183 46512 47939 47938 46512 46512 47193 47939 46513 47175 47184 47206 46518 46513 48644 47206 46513 46513 48638 48644 46513 48637 48638 46513 47184 48637 46514 47192 47193 46514 46516 47192 46514 46515 46516 47195 47192 46516 46516 47194 47195 46516 46521 47194 46516 46517 46521 46522 46521 46517 47961 46523 46518 46518 47207 47961 46518 47206 47207 47208 47202 46519 46519 46524 47208 46525 46524 46519 47201 47194 46521 47204 47201 46521 47215 47204 46521 46521 46522 47215 46522 46530 47215 46522 46529 46530 46523 46527 46528 47961 46527 46523 47958 47208 46524 46524 47220 47958 46524 47219 47220 46524 46525 47219 46526 46527 47961 46528 46527 46526 47216 47215 46526 47217 47216 46526 47961 47217 46526 47221 47219 46531 47236 47221 46531 46531 46533 47236 47249 47230 46532 47237 47236 46533 47243 47237 46533 46533 47242 47243 46536 46535 46534 46543 46536 46534 46548 46543 46534 47238 46548 46534 46534 46535 47238 46535 46536 46537 46535 47228 47238 46535 47227 47228 46535 46540 47227 46535 46537 46540 46536 46543 46544 46537 46538 46540 47229 46540 46538 46539 47231 47249 46539 46545 47231 47970 47227 46540 47972 47970 46540 46540 47229 47972 47998 47241 46542 46542 47995 47998 46545 46549 47231 48011 46547 46546 46546 48004 48011 47997 47995 46547 48011 47997 46547 46548 47238 47248 47232 47231 46549 46549 46550 47232 47258 47232 46550 47269 47268 46552 47271 47269 46552 48016 47271 46552 46552 46569 48016 46552 46553 46569 46570 46569 46553 46553 46568 46570 47261 46566 46554 48037 47274 46556 46556 47275 48037 46556 46557 47275 46557 46559 48039 48038 47275 46557 48039 48038 46557 46559 46560 48021 46559 48021 48039 46560 47262 48020 46560 48020 48021 46561 47269 47270 46561 47268 47269 46562 46572 46580 46562 46563 46572 46563 46571 46572 46563 46564 46571 46564 46565 46571 46573 46571 46565 46565 46567 46573 47266 46567 46566 47292 47266 46566 48017 47292 46566 46566 47260 48017 47261 47260 46566 46581 46573 46567 47266 46581 46567 47280 46570 46568 48018 48016 46569 46569 46570 48018 46570 47280 48018 46581 46572 46571 46571 46573 46581 46572 46579 46580 47288 46579 46572 46572 47281 47288 46572 46581 47281 47282 47272 46574 46574 47273 47282 46575 46576 47278 48029 47278 46576 46576 47279 48029 46576 46583 47279 48043 48031 46578 48753 48043 46578 46578 47287 48753 46578 46579 47287 46580 46579 46578 47288 47287 46579 47292 47281 46581 46581 47266 47292 47285 47277 46582 47293 47285 46582 46582 46586 47293 47297 47279 46583 46583 46590 47297 46583 46589 46590 46584 46585 47286 46584 46587 46588 47286 46587 46584 47302 47293 46586 46586 46596 47302 46587 48041 48049 46587 47286 48041 46601 46590 46589 46590 47294 47297 47296 47294 46590 47303 47296 46590 47311 47303 46590 46590 46601 47311 48063 47312 46591 48761 48063 46591 46591 46592 48761 48762 48761 46592 46592 46602 48762 47306 46597 46593 46593 46594 47306 48052 47298 46595 46595 47315 48052 46600 46598 46597 47306 46600 46597 47314 46603 46598 46598 46599 47314 46600 46599 46598 47321 47314 46599 48061 47321 46599 46599 47305 48061 46599 46600 47305 47306 47305 46600 46602 48729 48762 46620 46607 46603 47314 46620 46603 47308 47304 46604 47313 47308 46604 47316 47315 46605 47307 47302 46606 46606 47301 47307 47310 47301 46606 46606 47309 47310 48073 46629 46608 46608 47320 48073 46608 46620 47320 46609 46625 47326 47333 46626 46610 46610 46611 47333 47339 47333 46611 46611 46612 47339 47340 47339 46612 47341 47340 46612 46612 46613 47341 46613 46614 47341 48797 47341 46614 46614 48086 48797 46614 48075 48086 48077 48075 46614 46614 48071 48077 46614 47328 48071 46615 47303 47311 48766 47303 46615 48787 48766 46615 46615 48786 48787 46615 46616 48786 49439 48786 46616 46616 48079 49439 46616 48078 48079 46616 48058 48078 46616 46627 48058 48064 46619 46617 48080 48064 46617 46617 46618 48080 48097 48080 46618 46618 47355 48097 46618 47354 47355 48059 47313 46619 48064 48059 46619 47321 47320 46620 46620 47314 47321 46621 48051 48052 48776 48051 46621 48780 48776 46621 46621 48779 48780 48781 48779 46621 46621 46622 48781 48052 47316 46621 46622 48065 48781 48066 48065 46622 46622 46633 48066 47326 46624 46623 47345 47326 46623 46623 47344 47345 47326 46625 46624 48082 47335 46626 46626 47332 48082 47333 47332 46626 46627 47342 48058 47355 47354 46628 46628 46630 47355 46628 46629 46630 47354 46646 46628 48073 46630 46629 48073 48072 46630 48097 47355 46630 46630 48080 48097 46630 48072 48080 47351 46633 46631 47352 47351 46631 46633 46632 46631 46633 47351 48066 47358 46637 46634 46634 47353 47358 46634 46635 47353 46635 47349 47353 46636 47365 47366 46636 47350 47365 46637 47358 48102 47359 46638 46637 48102 47359 46637 48106 47360 46638 46638 47359 48106 47362 46641 46639 46639 47361 47362 46639 46640 47361 48105 47361 46640 46640 47360 48105 47363 46642 46641 46641 47362 47363 46652 46647 46643 47370 46652 46643 46643 47363 47370 47369 47367 46645 46645 46648 47369 46646 47367 47371 48096 47367 46646 46646 47354 48096 46647 46652 46653 46650 47351 47352 48805 47351 46650 46650 48108 48805 47370 46653 46652 46653 47364 47375 47370 47364 46653 46660 46657 46654 46654 46655 46660 46661 46660 46655 46662 46661 46655 46655 46656 46662 46663 46662 46656 46670 46663 46656 46656 46664 46670 46657 46658 48111 46659 46658 46657 46660 46659 46657 48828 48111 46658 49494 48828 46658 46658 46659 49494 46659 48832 49494 46659 48115 48832 46659 47374 48115 46659 46660 47374 46660 46661 47374 46661 47376 47377 46661 46662 47376 47377 47374 46661 46662 46663 47376 47383 47376 46663 46663 47379 47383 46663 46670 47379 47380 46670 46664 46664 46671 47380 46672 46667 46665 46666 46667 46675 48124 48112 46666 46666 46675 48124 46667 46672 46675 47378 46677 46669 46669 47373 47378 47380 47379 46670 47388 47380 46671 48121 47388 46671 46671 47385 48121 46671 46673 47385 46676 46675 46672 46672 46674 46676 48112 47385 46673 46675 48117 48124 46675 47381 48117 46675 46676 47381 47386 47381 46676 46676 46678 47386 46677 47382 48113 46677 47378 47382 48113 47387 46677 47389 47386 46678 46678 46682 47389 46679 46680 46682 47389 46682 46680 47390 47389 46680 46680 46681 47390 48126 47390 46681 46681 47387 48126 46690 46684 46683 46694 46690 46683 46684 46690 47391 46685 46686 46688 46687 46686 46685 46686 46687 46688 47394 46688 46687 48843 47394 46687 46687 48128 48843 47394 46693 46688 46690 46691 46692 47392 47391 46690 46690 46692 47392 46691 46695 47395 47395 46692 46691 46692 46697 47392 47395 46697 46692 47394 46702 46693 46695 46696 46697 46704 46696 46695 46710 46704 46695 46695 46697 47395 46703 46698 46696 46711 46703 46696 46696 46704 46711 46698 46697 46696 46697 46698 47392 46698 46703 46705 46698 46699 47392 46700 46699 46698 46705 46700 46698 47396 47392 46699 47397 47396 46699 46699 46700 47397 48136 47397 46700 48138 48136 46700 46700 47401 48138 46700 46705 47401 46714 46706 46701 47398 46714 46701 46701 46702 47398 48133 47398 46702 46702 47394 48133 46718 46705 46703 46703 46711 46718 46712 46711 46704 46705 46718 47403 47403 47401 46705 46713 46707 46706 46714 46713 46706 46727 46720 46707 46707 46708 46727 46709 46708 46707 46713 46709 46707 47404 46727 46708 46708 46709 47404 47405 47404 46709 46709 47402 47405 46709 46713 47402 47407 46718 46711 46711 47406 47407 46711 46712 47406 47409 47406 46712 46712 46721 47409 46713 47400 47402 46713 47399 47400 46713 46714 47399 46714 47398 47399 48854 48853 46715 46715 48142 48854 46715 46716 48142 46717 46716 46715 48853 46717 46715 46716 46737 48142 46716 46717 46721 47409 46721 46717 48858 47409 46717 46717 48853 48858 47407 47403 46718 48140 47408 46722 46722 46723 48140 46724 46723 46722 47408 46724 46722 46723 46728 47404 46723 46726 46728 46723 46724 46726 46723 47405 48140 46723 47404 47405 46724 47408 47410 46726 46727 46728 47404 46728 46727 46733 46731 46730 46743 46733 46730 47417 46743 46730 47418 47417 46730 46731 46732 46735 46733 46732 46731 46745 46735 46732 46732 46733 46745 48870 46745 46733 46733 48868 48870 46733 46741 48868 46743 46741 46733 46734 46749 47411 46735 46744 46746 46745 46744 46735 46736 46751 47418 46737 46738 48142 46738 47413 48142 46738 47411 47413 47421 46740 46739 48152 47421 46739 46739 47414 48152 47421 46754 46740 48869 48868 46741 46741 46742 48869 46743 46742 46741 49537 48869 46742 46742 48879 49537 46742 46743 48879 46743 47416 48879 47417 47416 46743 48154 46748 46744 46744 48153 48154 48870 48153 46744 46744 46745 48870 46748 46746 46744 46762 46759 46746 46746 46747 46762 46748 46747 46746 47439 46762 46747 48154 47439 46747 46747 46748 48154 48146 47411 46749 48147 48146 46749 48148 48147 46749 48150 48148 46749 46749 47415 48150 47420 47419 46750 46750 46752 47420 46751 46753 47418 47422 47420 46752 47423 47422 46752 48157 47423 46752 46752 47424 48157 46752 46766 47424 46753 47417 47418 47425 47417 46753 46753 46755 47425 48155 47428 46754 46754 47421 48155 48160 47425 46755 48161 48160 46755 46755 47431 48161 46755 46771 47431 46759 46757 46756 46764 46758 46757 46772 46764 46757 46757 46763 46772 46757 46759 46763 46759 46762 46763 47436 46767 46761 47441 47436 46761 47439 46763 46762 47437 46772 46763 47439 47437 46763 47435 46766 46765 47426 47424 46766 47435 47426 46766 46776 46770 46767 47436 46776 46767 47433 47432 46769 46769 46774 47433 46773 46784 47443 46773 46775 46784 48163 47433 46774 48164 48163 46774 46785 46784 46775 46791 46785 46775 46776 47436 47442 48179 48165 46778 46778 48176 48179 48185 48176 46778 46778 46779 48185 46780 46779 46778 46792 46780 46778 46779 48178 48185 46779 47449 48178 46779 46780 47449 46780 46793 47449 46780 46792 46793 48162 46786 46781 46781 47440 48162 48169 47443 46784 46784 46795 48169 46784 46785 46795 48162 47446 46786 47459 47454 46787 46787 47452 47459 46787 46788 47452 47453 47452 46788 46788 46789 47453 46790 46789 46788 46794 46790 46788 48913 47453 46789 48915 48913 46789 46789 48910 48915 46789 46790 48910 46790 47444 48910 47446 47444 46790 48170 48169 46795 46795 47455 48170 46795 46796 47455 47456 47455 46796 46796 46797 47456 46798 46797 46796 46797 47447 47456 47448 47447 46797 46797 46798 47448 47472 47471 46799 48205 47472 46799 46799 46800 48205 46800 48196 48205 46800 47460 48196 46801 47485 47502 46813 46807 46801 47502 46813 46801 46814 46811 46802 47477 46814 46802 46804 46805 47467 47495 47484 46804 48219 47495 46804 46804 47467 48219 46805 47468 48208 48208 47467 46805 46806 48221 48222 47502 47485 46806 48222 47502 46806 46810 46809 46808 47503 46810 46808 47521 47503 46808 46809 47475 47488 46809 46810 47475 48942 47475 46810 46810 47503 48942 46814 46812 46811 46818 46815 46812 46812 46817 46818 46812 46814 46817 46813 47499 47513 47500 47499 46813 47502 47500 46813 46823 46817 46814 47504 46823 46814 47505 47504 46814 47514 47505 46814 46814 47477 47514 47506 46816 46815 47515 47506 46815 46815 46818 47515 47507 47493 46816 46816 47506 47507 46823 46818 46817 46818 46823 47515 47525 46824 46819 46819 46820 47525 46820 47508 47509 46820 47509 47525 46827 46826 46821 47522 47521 46822 47527 47522 46822 47516 47515 46823 47519 47516 46823 47523 47519 46823 47535 47523 46823 47536 47535 46823 46823 47504 47536 47529 46828 46824 48260 47529 46824 46824 48243 48260 46824 47525 48243 46825 47510 47511 46830 46829 46826 46832 46830 46826 47526 46832 46826 46826 46827 47526 48238 47526 46827 46827 47513 48238 47545 46835 46828 46828 47538 47545 46828 47529 47538 46832 46831 46830 46831 46832 46833 46834 46833 46832 47533 46834 46832 48248 47533 46832 46832 47526 48248 46833 46834 48262 48965 48262 46834 46834 47533 48965 46841 46836 46835 47544 46841 46835 47545 47544 46835 47549 47534 46837 47550 47549 46837 46837 46838 47550 46838 46839 47550 48271 47550 46839 46839 46861 48271 46840 46841 47544 47547 47546 46842 46842 46843 47547 46843 46851 47547 46843 46844 46851 46845 46848 46849 46845 46846 46848 47553 46848 46846 46847 46848 47553 46849 46848 46847 46859 46849 46847 46865 46859 46847 47553 46865 46847 46856 46850 46849 46859 46856 46849 47551 47547 46851 46851 46852 47551 46852 47532 47551 46852 46853 47532 48247 47532 46853 48251 48247 46853 46853 47560 48251 48269 47558 46854 46854 47552 48269 46855 47548 47552 47563 46860 46856 46856 46859 47563 46857 47544 48267 47554 46858 46857 48267 47554 46857 47555 46862 46858 46858 47554 47555 46859 46864 47563 46865 46864 46859 46860 47563 47567 47567 46866 46860 48274 48271 46861 48287 47566 46863 47564 47563 46864 46865 47553 47559 46866 46874 46875 47576 46874 46866 47577 47576 46866 46866 47570 47577 46866 47567 47570 47569 46871 46867 48280 47569 46867 47593 46895 46868 47602 47593 46868 46868 46869 47602 48307 47602 46869 46869 47590 48307 46869 46875 47590 47578 46887 46870 46870 47573 47578 46870 46871 47573 48286 47573 46871 46871 48281 48286 46871 47568 48281 47569 47568 46871 46894 46891 46872 48304 46894 46872 46872 48299 48304 46872 46873 48299 46873 47582 48299 46876 46875 46874 47576 46876 46874 46875 46876 47590 49005 47590 46876 46876 48998 49005 46876 48300 48998 46876 47576 48300 47572 46878 46877 47572 47571 46878 46880 46881 47575 47584 47575 46881 46882 46892 47591 47585 46884 46883 48292 47585 46883 46883 47587 48292 46883 46885 47587 46884 47586 48305 46884 47585 47586 46885 46886 47587 46886 46887 47587 46887 47578 47587 49003 48296 46888 46888 46889 49003 46890 46889 46888 47599 46890 46888 46889 46890 49652 49642 49003 46889 49652 49642 46889 46890 47598 49658 47599 47598 46890 49658 49652 46890 46892 46895 47591 47596 47595 46893 47621 47601 46894 48303 47621 46894 48304 48303 46894 47601 46898 46894 47593 47591 46895 48314 47604 46896 46896 46900 48314 46910 46904 46899 47589 47584 46899 46899 46904 47589 46900 47595 48314 46902 46909 46918 46902 46903 46909 46904 46903 46902 47610 46904 46902 48318 47610 46902 48331 48318 46902 46902 46918 48331 46903 46904 46910 49009 47589 46904 46904 47610 49009 46919 46911 46905 47605 46919 46905 47606 46908 46906 46906 46914 47606 46908 46907 46906 48320 48317 46907 46907 48315 48320 46907 46908 48315 46908 49019 49023 46908 47606 49019 49023 48315 46908 47618 46920 46911 46911 46919 47618 48323 47612 46913 46913 47611 48323 48319 47606 46914 46914 47612 48319 47613 46922 46915 47615 47613 46915 46915 46916 47615 46917 46927 47625 47625 46918 46917 48332 48331 46918 46918 47624 48332 47625 47624 46918 46919 46930 47618 47619 46930 46919 46919 47605 47619 46931 46925 46920 47618 46931 46920 47628 47611 46921 46921 46926 47628 46922 47613 47626 48322 48321 46923 46923 47617 48322 46924 46925 46932 46937 46932 46925 46925 46931 46937 46926 47627 47628 46926 46932 47627 46928 49029 49041 46928 46929 49029 46930 46929 46928 47618 46930 46928 46928 46931 47618 47629 46931 46928 47637 47629 46928 49049 47637 46928 49680 49049 46928 46928 49041 49680 46929 47619 49029 46929 46930 47619 47629 46937 46931 46932 46962 47627 46932 46943 46962 46932 46938 46943 46932 46937 46938 47633 46939 46933 46933 46935 47633 46933 46934 46935 48341 47633 46935 48342 48341 46935 46935 46936 48342 49688 48342 46936 46936 49037 49688 46936 48333 49037 46942 46938 46937 47629 46942 46937 46938 46941 46943 46942 46941 46938 48345 46948 46939 46939 48341 48345 46939 47633 48341 47623 47622 46940 47634 47623 46940 46945 46943 46941 46941 46944 46945 46959 46944 46941 46968 46959 46941 46941 46942 46968 47636 46968 46942 46942 47629 47636 47632 46962 46943 46943 46955 47632 46943 46945 46955 46946 46945 46944 46953 46946 46944 46960 46953 46944 46944 46959 46960 46945 46946 46955 46963 46955 46946 46946 46954 46963 46946 46953 46954 48344 48340 46947 46947 47640 48344 46947 46948 47640 48346 47640 46948 46948 48345 48346 48351 46981 46949 46949 48349 48351 46952 46967 47634 46952 46956 46967 46958 46956 46952 46969 46954 46953 46953 46961 46969 46953 46960 46961 46964 46963 46954 46969 46964 46954 47639 47632 46955 46955 46963 47639 47653 46967 46956 47658 47653 46956 46956 46957 47658 47659 47658 46957 46959 46968 48343 47643 46960 46959 47660 47643 46959 48343 47660 46959 47643 46961 46960 46988 46969 46961 46994 46988 46961 46961 46993 46994 47643 46993 46961 47630 47627 46962 47632 47630 46962 46963 46964 47639 46964 46990 47639 46964 46970 46990 46964 46969 46970 47648 46966 46965 47648 47641 46966 47651 47634 46967 47653 47651 46967 46968 47636 48343 46969 46982 46983 46988 46982 46969 46983 46970 46969 46970 46983 46990 46971 46972 46974 46973 46972 46971 46972 46984 48354 46972 46973 46984 46975 48356 48357 46975 46976 48356 46976 46977 48356 49053 48356 46977 46977 48355 49053 46977 47646 48355 47647 46979 46978 46979 47647 48358 48359 47649 46979 49054 48359 46979 46979 48358 49054 48351 46986 46980 46980 46981 48351 46995 46983 46982 46982 46994 46995 46982 46988 46994 46995 46989 46983 46983 46989 46990 48365 48354 46984 46984 46985 48365 46985 46997 48365 48351 46991 46986 46987 46992 47659 47665 47001 46991 48351 47665 46991 47661 47659 46992 47662 47661 46992 47669 46994 46993 48369 47669 46993 46993 47654 48369 46993 47643 47654 47004 46995 46994 47670 47004 46994 46994 47669 47670 47013 47010 46995 46995 47003 47013 47004 47003 46995 47663 46997 46996 46996 47014 47663 46997 47671 48365 46997 47663 47671 47663 47014 46998 47672 47663 46998 46998 46999 47672 47000 46999 46998 47684 47000 46998 46998 47014 47684 49728 47672 46999 49737 49728 46999 49738 49737 46999 50475 49738 46999 50476 50475 46999 46999 47000 50476 50477 50476 47000 47000 49746 50477 47000 48386 49746 47000 48385 48386 47000 47684 48385 48377 47676 47001 47001 47664 48377 47665 47664 47001 47015 47006 47002 47687 47015 47002 47680 47013 47003 48387 47680 47003 47003 47677 48387 47679 47677 47003 47003 47004 47679 47004 47670 47679 47675 47674 47005 47005 47673 47675 47021 47020 47006 47694 47021 47006 47006 47015 47694 47016 47008 47007 47695 47009 47008 47008 47688 47695 47008 47016 47688 47696 47662 47009 48381 47696 47009 47009 47695 48381 47013 47011 47010 47683 47014 47011 47011 47012 47683 47013 47012 47011 47012 47681 47683 47682 47681 47012 47012 47680 47682 47012 47013 47680 47014 47681 47684 47683 47681 47014 47015 47687 47694 47016 47022 47698 47699 47688 47016 47700 47699 47016 47016 47698 47700 47017 47018 47691 48383 47691 47018 47018 47685 48383 47018 47019 47685 47019 47674 47685 47698 47022 47020 47710 47698 47020 47020 47021 47710 47021 47694 47709 47021 47709 47710 47023 47024 47028 47025 47024 47023 47026 47025 47023 47029 47028 47024 48398 47029 47024 49105 48398 47024 47024 47025 49105 47025 47697 48389 47025 47026 47697 47025 49085 49105 47025 48389 49085 47026 47027 47697 47028 47029 47030 47031 47030 47029 47717 47031 47029 49113 47717 47029 47029 48398 49113 47717 47037 47031 47708 47033 47032 48404 47041 47033 47033 47728 48404 48400 47728 47033 47033 47708 48400 48396 47704 47034 47034 48394 48396 47034 47035 48394 48395 48394 47035 47035 47036 48395 47036 47714 48395 47717 47716 47037 47719 47040 47038 48415 47719 47038 47038 47039 48415 47039 48409 48415 48410 48409 47039 47039 47042 48410 47719 47715 47040 48404 47731 47041 48430 48410 47042 48438 47047 47043 47043 47738 48438 47043 47044 47738 48429 47738 47044 47044 48422 48429 47044 48421 48422 47044 47721 48421 48412 47742 47045 47045 47731 48412 49140 48439 47046 49142 49140 47046 47046 47047 49142 47047 48438 49142 47744 47056 47048 48441 47744 47048 47048 48431 48441 48432 48431 47048 48433 48432 47048 47048 47739 48433 47048 47049 47739 47049 47734 47739 47049 47051 47734 47733 47051 47050 47050 47054 47733 47050 47053 47054 47051 47733 47734 47054 47053 47052 47736 47733 47054 47745 47736 47054 47054 47058 47745 48443 47748 47055 47055 47743 48443 47058 47740 47745 47751 47740 47058 47058 47059 47751 47059 47060 47751 47060 47062 47751 47763 47064 47061 47062 47740 47751 47063 47064 47786 47064 47772 47786 47064 47763 47768 47065 47066 47068 47067 47066 47065 47814 47067 47065 47065 47068 47814 47804 47803 47067 47814 47804 47067 47068 47806 47814 47068 47069 47806 47808 47807 47070 47070 47071 47808 47071 47797 47808 47833 47073 47072 48503 47833 47072 47072 47079 48503 48491 47075 47073 47073 47833 48491 47075 47074 47073 47074 47080 47081 47074 47075 47080 48490 47824 47075 48491 48490 47075 47824 47080 47075 47078 47077 47076 49217 47078 47076 49218 49217 47076 49891 49218 47076 47076 48510 49891 47076 47077 48510 47077 47078 47079 47077 47832 48510 47077 47831 47832 48503 47079 47078 49212 48503 47078 49217 49212 47078 47082 47081 47080 47823 47082 47080 47824 47823 47080 47081 47082 47083 47082 47834 47835 47082 47823 47834 47835 47085 47084 47085 47841 47842 47085 47835 47841 47086 47843 47845 47086 47842 47843 48552 47846 47087 47087 47088 48552 49245 48552 47088 47088 47844 49245 47089 47090 47093 48558 47099 47089 47089 47093 48558 47091 47094 47851 48553 48543 47092 48554 48553 47092 48559 48558 47093 49259 48559 47093 47093 47850 49259 48560 47851 47094 47094 47095 48560 47095 47857 49251 49251 48560 47095 47862 47861 47096 47100 47098 47097 47103 47100 47097 47098 48545 48554 48546 48545 47098 47098 48541 48546 47098 47100 48541 47871 47866 47099 48567 47871 47099 47099 48558 48567 47100 47853 48541 47100 47103 47853 47852 47103 47101 47101 47102 47852 47856 47852 47102 47102 47106 47856 47107 47106 47102 47103 47852 47853 47104 47854 47856 47855 47854 47104 48556 47855 47104 47104 47105 48556 47106 47105 47104 47856 47106 47104 47105 47872 48556 47105 47106 47872 47106 47865 47872 47112 47110 47108 47874 47112 47108 49266 47874 47109 47109 49263 49266 47109 48570 49263 47110 47112 47873 48585 47113 47111 47111 48579 48585 47111 48578 48579 49944 47873 47112 47112 49943 49944 47112 49267 49943 47112 47874 49267 47883 47116 47113 47884 47883 47113 47889 47884 47113 48585 47889 47113 47114 47890 47898 47114 47883 47890 47114 47116 47883 47898 47132 47114 47888 47880 47115 47117 47118 47120 47119 47118 47117 47875 47119 47117 47887 47875 47117 47117 47125 47887 47126 47121 47118 47118 47122 47126 47123 47122 47118 47118 47119 47123 47121 47120 47118 47877 47123 47119 47119 47876 47877 47119 47875 47876 47882 47127 47122 47122 47123 47882 47123 47878 47882 47123 47877 47878 47124 47130 47131 47132 47130 47124 48588 47887 47125 48589 48588 47125 47125 47891 48589 47127 47881 48582 47882 47881 47127 48572 47888 47127 48582 48572 47127 47128 47129 47136 48590 47892 47128 47128 47136 48590 47130 47132 47898 47130 47898 47902 47141 47140 47133 47899 47141 47133 47133 47134 47899 47134 47893 47899 48591 47136 47135 49283 48591 47135 47135 49282 49283 47135 47137 49282 48591 48590 47136 47137 47138 47139 47137 47904 49282 47137 47139 47904 47903 47146 47141 47141 47899 47903 47143 47144 47145 48604 47144 47143 49288 48604 47143 49291 49288 47143 47143 47921 49291 47143 47160 47921 48603 47891 47144 48604 48603 47144 47148 47147 47146 47910 47148 47146 47912 47910 47146 47146 47903 47912 48617 47151 47147 47147 48607 48617 47147 47148 48607 49298 48607 47148 49980 49298 47148 47148 47910 49980 47149 48616 49297 47149 47150 48616 47150 47895 48616 47909 47895 47150 47150 47902 47909 48617 47913 47151 47914 47153 47152 47915 47914 47152 47152 47913 47915 47154 48614 48615 47154 48613 48614 47918 47917 47156 48622 47918 47156 47919 47159 47157 48624 47919 47157 47157 47158 48624 47159 47158 47157 47158 47917 48624 47160 47920 47921 47160 47165 47920 47160 47161 47165 47166 47165 47161 47178 47166 47161 47932 47168 47162 47163 47169 47933 47197 47178 47164 47164 47179 47197 47164 47167 47179 50694 47920 47165 47165 47166 50694 47166 48626 50694 47166 47176 48626 47177 47176 47166 47178 47177 47166 47198 47179 47167 47167 47168 47198 47931 47198 47168 47168 47930 47931 47932 47930 47168 48633 48632 47170 47170 47173 48633 47170 47171 47173 47171 47172 47173 47927 47173 47172 47172 47926 47927 49314 48633 47173 47173 47927 49314 47928 47175 47174 48628 47928 47174 47174 47919 48628 47175 47928 47929 47929 47184 47175 48627 48626 47176 47176 47187 48627 47176 47177 47187 47177 47186 47187 47197 47186 47177 47177 47178 47197 47198 47197 47179 47180 47181 47189 47182 47181 47180 47934 47189 47181 47181 47182 47934 47182 47924 47934 47925 47924 47182 47182 47922 47925 49319 48637 47184 49320 49319 47184 47184 49310 49320 47184 47929 49310 47187 47186 47185 47964 47187 47185 48646 47964 47185 47185 47963 48646 47185 47962 47963 47185 47954 47962 47185 47186 47954 47955 47954 47186 47186 47950 47955 47186 47198 47950 47186 47197 47198 50706 48627 47187 47187 47964 50706 47190 47189 47188 47210 47190 47188 47952 47210 47188 47188 47189 47952 47189 47951 47952 47189 47934 47951 47203 47200 47190 47209 47203 47190 47210 47209 47190 47939 47193 47191 48636 47939 47191 47191 47942 48636 47191 47192 47942 47193 47192 47191 47192 47195 47942 47196 47195 47194 47201 47196 47194 47944 47942 47195 47195 47196 47944 47196 47201 47948 48641 47944 47196 47196 47959 48641 47196 47953 47959 47196 47948 47953 47198 47931 47950 47199 47930 47933 47945 47930 47199 47946 47945 47199 47200 47203 47211 47201 47204 47216 47201 47216 47948 47957 47946 47202 47958 47957 47202 47202 47208 47958 47223 47211 47203 47203 47209 47223 47204 47215 47216 47205 47206 48644 47207 47206 47205 47218 47207 47205 49327 47218 47205 47205 48644 49327 47207 47217 47961 47218 47217 47207 47224 47223 47209 47225 47224 47209 47233 47225 47209 48654 47233 47209 47209 47222 48654 47209 47210 47222 48650 47222 47210 47210 48648 48650 47210 47952 48648 47223 47213 47211 47212 47213 47214 47223 47214 47213 47214 47223 47224 47985 47226 47214 47214 47978 47985 47214 47224 47978 47960 47948 47216 47216 47217 47960 49326 47960 47217 47217 47218 49326 50023 49336 47218 47218 49332 50023 47218 49327 49332 49336 49326 47218 47221 47220 47219 47220 47973 48665 47220 47221 47973 47969 47958 47220 47220 47968 47969 48656 47968 47220 48658 48656 47220 48665 48658 47220 47221 47236 47973 47222 48650 49330 49339 48654 47222 47222 49330 49339 47224 47234 47978 47224 47225 47234 47225 47233 47234 47986 47981 47226 48002 47986 47226 47226 47985 48002 47970 47228 47227 47976 47238 47228 47228 47971 47976 47228 47970 47971 48661 47974 47229 47229 47977 48661 47974 47972 47229 48661 47977 47230 48670 48661 47230 47230 47249 48670 47257 47249 47231 47231 47232 47257 48005 47257 47232 47232 47258 48005 48654 48653 47233 47984 47234 47233 48662 47984 47233 47233 48653 48662 47984 47978 47234 47980 47979 47235 47236 47237 47973 47989 47973 47237 47237 47243 47989 47238 47246 47248 47976 47246 47238 47239 47240 47990 47240 47979 47980 47240 47987 47990 47240 47980 47987 47988 47242 47241 47998 47988 47241 47988 47243 47242 48665 47989 47243 48669 48665 47243 49343 48669 47243 47243 48677 49343 47243 47988 48677 47247 47246 47244 47982 47247 47244 48672 47982 47244 47244 47245 48672 47246 47245 47244 47245 47975 48672 47245 47246 47975 47246 47247 47248 47976 47975 47246 47250 47248 47247 47247 47982 47983 47249 47257 48670 47251 47994 49359 48003 47994 47251 48010 47259 47251 48698 48010 47251 49359 48698 47251 47252 47983 47999 47254 47253 47252 47999 47254 47252 48012 47255 47253 47253 47256 48012 47253 47254 47256 48679 47256 47254 47254 47999 48679 48020 47262 47255 47255 48012 48020 48679 48012 47256 48671 48670 47257 47257 48005 48671 48010 47267 47259 48722 48017 47260 47260 47261 48722 47261 48708 48722 47261 47267 48708 47263 47264 48007 47265 47264 47263 47276 47265 47263 47264 48006 48007 48703 48006 47264 48704 48703 47264 47264 48701 48704 47264 47265 48701 48702 48701 47265 49372 48702 47265 47265 48024 49372 47265 48022 48024 47265 47276 48022 47267 48010 48698 47267 48698 48708 47271 47270 47269 48731 48730 47270 48745 48731 47270 47270 48016 48745 47270 47271 48016 48730 48729 47270 48035 48004 47272 47272 47282 48035 47273 47274 48036 48036 47282 47273 48737 48036 47274 47274 48037 48737 48740 48037 47275 48741 48740 47275 47275 48038 48741 48023 48022 47276 47276 47283 48023 47276 47277 47283 47284 47283 47277 47285 47284 47277 47278 48025 48030 48727 48025 47278 47278 48028 48727 48029 48028 47278 47297 47294 47279 48724 48029 47279 47279 48042 48724 47279 47294 48042 48031 48018 47280 47291 47288 47281 48034 47291 47281 47281 48032 48034 47281 47292 48032 48036 48035 47282 48725 48023 47283 47283 47284 48725 47284 48046 48725 47284 48040 48046 47284 47285 48040 47285 47293 48040 47286 48025 48041 48030 48025 47286 47287 48048 48753 47287 47289 48048 48047 47289 47287 47287 47288 48047 47288 47291 48047 48757 48048 47289 48760 48757 47289 47289 47290 48760 47291 47290 47289 48047 47291 47289 50122 48760 47290 47290 47291 50122 47291 48034 50122 47292 48017 48722 48722 48032 47292 48046 48040 47293 48751 48046 47293 47293 47299 48751 47307 47299 47293 47293 47302 47307 48752 48042 47294 47294 47295 48752 47296 47295 47294 49411 48752 47295 49412 49411 47295 47295 48756 49412 47295 48057 48756 47295 47296 48057 47296 47303 48057 47298 48052 48053 47301 47300 47299 47307 47301 47299 49407 48751 47299 47299 47300 49407 47300 48768 48769 47300 47301 48768 49410 49407 47300 49424 49410 47300 47300 48769 49424 47301 47310 48768 48766 48057 47303 47308 47306 47304 47305 48059 48061 47305 47306 48059 47306 47308 48059 47308 47313 48059 47322 47310 47309 47331 47322 47309 48784 48768 47310 48785 48784 47310 47310 47322 48785 48063 47319 47312 47315 47316 48052 47317 47319 48062 48062 47318 47317 48062 47323 47318 48063 48062 47319 47320 48061 48073 47320 47321 48061 47322 48777 48785 48778 48777 47322 47322 47331 48778 47343 47334 47323 48062 47343 47323 48795 47330 47324 47324 48091 48795 47324 48090 48091 47324 47329 48090 47324 47325 47329 47348 47331 47326 47326 47347 47348 47326 47345 47347 48071 47328 47327 48077 48071 47327 47327 48069 48077 48070 48069 47327 48770 48070 47327 47327 48056 48770 48782 48090 47329 47329 48771 48782 47329 48060 48771 48795 48093 47330 47331 48074 48778 47331 47348 48074 47332 47333 47339 47332 47338 48082 47339 47338 47332 47357 47349 47335 48082 47357 47335 47336 47337 49446 47338 47337 47336 48082 47338 47336 47336 47357 48082 48083 47357 47336 48802 48083 47336 49446 48802 47336 47337 48793 49445 47337 47338 48793 47337 49445 49446 47338 48085 48793 47338 47339 48085 47339 48084 48085 47339 47340 48084 47340 47341 48084 48797 48084 47341 48088 48058 47342 49453 48100 47343 50166 49453 47343 47343 50157 50166 47343 48062 50157 47346 47345 47344 48094 47346 47344 47345 48098 48800 47345 48081 48098 47345 47346 48081 48796 47347 47345 48800 48796 47345 48094 48081 47346 48068 47348 47347 48796 48068 47347 47348 48067 48074 48068 48067 47348 47356 47353 47349 47357 47356 47349 47350 48804 48810 47350 48100 48804 47366 47365 47350 48810 47366 47350 48798 48066 47351 48806 48798 47351 47351 48805 48806 48095 47358 47353 47353 47356 48095 47356 48083 48801 47356 47357 48083 48103 48095 47356 48801 48103 47356 47358 48095 48102 49470 48106 47359 47359 49469 49470 47359 49468 49469 47359 48104 49468 47359 48102 48104 48106 48105 47360 47368 47362 47361 48107 47368 47361 47361 48105 48107 47364 47363 47362 47368 47364 47362 47363 47364 47370 48824 47375 47364 47364 48817 48824 47364 47368 48817 48810 48099 47366 47367 47369 47371 47368 48107 48817 47372 47371 47369 47382 47378 47373 48114 47382 47373 47373 47375 48114 48116 48115 47374 47374 47377 48116 48829 48114 47375 47375 48827 48829 47375 48824 48827 48120 47377 47376 47376 47383 48120 47377 48120 48836 48118 48116 47377 48836 48118 47377 47384 47383 47379 47379 47380 47384 47388 47384 47380 47381 47386 48117 49501 48833 47382 47382 48830 49501 47382 48114 48830 48833 48113 47382 48127 48120 47383 47383 47384 48127 47384 47388 48127 47385 48112 48121 47386 47389 48117 47387 48113 48126 47388 48121 48122 49508 48127 47388 47388 48839 49508 47388 48122 48839 47389 47390 48117 48842 48117 47390 47390 48834 48842 47390 48126 48834 47391 47392 47393 47396 47393 47392 47393 47396 48128 47394 48130 48133 47394 48129 48130 48843 48129 47394 48132 48131 47396 48846 48132 47396 47396 47397 48846 48131 48128 47396 47397 48135 48846 48136 48135 47397 48134 47399 47398 47398 48133 48134 48137 47400 47399 47399 48134 48137 48847 48139 47400 47400 48137 48847 48139 47402 47400 47401 47403 48138 49516 47405 47402 47402 48139 49516 47407 47406 47403 48848 48138 47403 47403 47406 48848 48141 48140 47405 48852 48141 47405 49516 48852 47405 48849 48848 47406 48850 48849 47406 48851 48850 47406 47406 47409 48851 48143 47410 47408 47408 48140 48143 48858 48851 47409 48143 47412 47410 48146 47413 47411 48144 47414 47412 47412 48143 48144 48145 48142 47413 48860 48145 47413 47413 48146 48860 47414 48144 48152 47415 48149 48150 48151 48149 47415 47415 47423 48151 47415 47422 47423 47415 47419 47422 48873 48160 47416 47416 47417 48873 48883 48879 47416 47416 48160 48883 47417 47425 48873 47419 47420 47422 47421 48152 48155 48158 48151 47423 47423 48157 48158 47424 47427 48157 47424 47426 47427 47425 48160 48873 48874 47427 47426 48880 48874 47426 47426 47434 48880 47426 47432 47434 47435 47432 47426 48158 48157 47427 48159 48158 47427 48874 48159 47427 48881 47441 47428 47428 47429 48881 47430 47429 47428 48155 47430 47428 48882 48881 47429 49541 48882 47429 47429 47430 49541 47430 49540 49541 47430 48877 49540 47430 48152 48877 48155 48152 47430 47432 47433 47434 48887 47434 47433 48888 48887 47433 47433 48163 48888 48887 48880 47434 48168 47442 47436 47436 47441 48168 47437 47438 47440 47439 47438 47437 47438 47439 48885 48162 47440 47438 48166 48162 47438 48891 48166 47438 47438 48885 48891 47439 48154 48156 47439 48156 48885 48881 48168 47441 48169 48167 47443 47444 48186 48910 47444 47445 48186 47446 47445 47444 47445 47450 48186 47451 47450 47445 48162 47451 47445 47445 47446 48162 48181 47456 47447 48188 48181 47447 48192 48188 47447 48197 48192 47447 48198 48197 47447 47447 47461 48198 47447 47448 47461 47449 47458 48178 47449 47457 47458 49561 48186 47450 47450 48901 49561 48902 48901 47450 47450 48166 48902 47450 47451 48166 47451 48162 48166 47460 47459 47452 48196 47460 47452 47452 48194 48196 48195 48194 47452 47452 47453 48195 48913 48195 47453 47455 48164 48170 48895 48164 47455 47455 48180 48895 47455 47456 48180 48181 48180 47456 48193 47458 47457 48199 48193 47457 47457 47463 48199 48191 48178 47458 48193 48191 47458 48201 48198 47461 48935 48201 47461 47461 48214 48935 48204 48200 47462 47462 47473 48204 48928 48199 47463 47463 48203 48928 47463 48200 48203 47466 47465 47464 48926 47466 47464 47464 48202 48926 48220 48215 47465 47465 47466 48220 48925 48220 47466 48927 48925 47466 47466 48926 48927 48937 48219 47467 47467 48208 48937 47468 47469 48932 48932 48208 47468 47469 48210 48933 47469 48209 48210 47469 47474 48209 48933 48932 47469 48209 47474 47470 48212 48209 47470 48213 48212 47470 47470 47472 48213 47470 47471 47472 47472 48206 48213 47472 48205 48206 47473 47479 48204 48216 47479 47473 48942 47488 47475 48935 48214 47476 47476 48934 48935 47476 48217 48934 47476 47486 48217 47477 47490 47514 47491 47490 47477 47494 47491 47477 47477 47478 47494 48943 47494 47478 47478 48224 48943 48225 48224 47478 47478 48223 48225 47478 47489 48223 47481 47480 47479 48940 47481 47479 47479 47483 48940 48216 47483 47479 47479 47480 48204 50311 48936 47480 47480 47481 50311 48936 48204 47480 50320 50311 47481 47481 49587 50320 47481 48940 49587 47482 47492 48218 48218 47483 47482 48941 48940 47483 47483 48218 48941 47486 47487 48217 47488 47487 47486 47487 47488 49584 49581 48217 47487 50318 49581 47487 50319 50318 47487 47487 49584 50319 47488 48942 49584 48939 48223 47489 47489 48215 48939 48962 47514 47490 47490 48943 48962 47490 47491 48943 47491 47494 48943 48941 48218 47492 47492 48940 48941 49587 48940 47492 47492 48231 49587 47492 47493 48231 47493 48230 48231 47493 47507 48230 48228 48227 47495 47495 48219 48228 48237 47509 47496 47496 47497 48237 47498 47497 47496 47509 47498 47496 48946 48237 47497 47497 48229 48946 47497 47498 48229 47498 48227 48228 47498 48226 48227 47498 47509 48226 48948 48229 47498 50325 48948 47498 47498 48945 50325 47498 48228 48945 48239 47513 47499 47499 47501 48239 47499 47500 47501 48222 47501 47500 47500 47502 48222 48950 48239 47501 47501 48222 48950 48953 48942 47503 48959 48953 47503 47503 47520 48959 47521 47520 47503 47504 47505 48962 48962 47536 47504 47505 47514 48962 47516 47507 47506 47506 47515 47516 47507 47516 48230 48226 47509 47508 48243 47525 47509 47509 48237 48243 47512 47511 47510 47546 47512 47510 48949 48221 47511 48954 48949 47511 47511 47512 48954 47512 48261 48954 47512 47531 48261 47546 47531 47512 48239 48238 47513 47516 47517 48230 47519 47517 47516 48232 48230 47517 48233 48232 47517 48955 48233 47517 47517 47518 48955 47519 47518 47517 47518 48250 48955 47518 47524 48250 47518 47519 47524 47519 47523 47524 49593 48959 47520 47520 48961 49593 47520 48240 48961 47520 47521 48240 48960 48240 47521 47521 48241 48960 47521 47522 48241 48242 48241 47522 48249 48242 47522 47522 47527 48249 47537 47524 47523 47540 47537 47523 47523 47535 47540 47524 47541 48250 48254 47541 47524 47524 47537 48254 47526 48238 48248 47527 47528 48249 47528 47549 48249 47528 47534 47549 47539 47538 47529 48260 47539 47529 47530 47546 47547 47530 47531 47546 47532 47531 47530 47551 47532 47530 47530 47547 47551 47531 47532 48261 47532 48247 48261 47533 47560 48965 48251 47560 47533 47533 48248 48251 48252 47540 47535 48967 48252 47535 47535 48962 48967 47535 47536 48962 47537 47540 48254 48267 47545 47538 47538 47539 48267 47539 47554 48267 48268 47554 47539 47539 48259 48268 48260 48259 47539 47540 47543 48254 48253 47543 47540 47540 48252 48253 48968 48250 47541 47541 47542 48968 47543 47542 47541 48254 47543 47541 49610 48968 47542 47542 48979 49610 47542 48258 48979 47542 47543 48258 47543 48253 48258 47544 47545 48267 48269 47552 47548 47548 48255 48269 48970 48249 47549 47549 47550 48970 47550 48275 48970 47550 48270 48275 48271 48270 47550 48268 47555 47554 48279 47565 47555 47555 48278 48279 47555 48272 48278 48273 48272 47555 47555 48268 48273 48965 47560 47556 47556 47557 48965 47557 47562 48965 47557 47558 47562 48269 47561 47558 47558 47561 47562 48269 48255 47561 48262 47562 47561 47562 48262 48965 48282 47570 47563 47563 47564 48282 47570 47567 47563 47564 47566 48282 47565 48279 48280 48287 48282 47566 48285 48281 47568 47568 47569 48285 48983 48285 47569 47569 48280 48983 48282 47577 47570 47571 48283 48284 48989 48283 47571 47571 48290 48989 47571 47572 48290 48286 47578 47573 48289 48287 47574 48999 48289 47574 49000 48999 47574 47574 48997 49000 47574 47575 48997 47575 47588 48997 47575 47584 47588 47576 47577 48300 47577 48288 48289 47577 48282 48288 47577 48289 48300 48292 47587 47578 47578 48291 48292 48294 48291 47578 47578 48286 48294 47579 48995 49641 47579 47580 48995 48298 47581 47579 49641 48298 47579 47580 48296 48995 47583 47582 47581 48996 47583 47581 47581 48297 48996 48298 48297 47581 49645 49644 47582 47582 47583 49645 49644 48299 47582 50388 49645 47583 50389 50388 47583 47583 48996 50389 47589 47588 47584 48301 47586 47585 47585 48293 48301 47585 48292 48293 49006 48305 47586 47586 48302 49006 47586 48301 48302 49000 48997 47588 49646 49000 47588 47588 49008 49646 47588 47589 49008 49009 49008 47589 49011 48307 47590 47590 49005 49011 47591 47593 47594 49016 48312 47592 47592 48310 49016 47592 47603 48310 47592 47593 47603 47594 47593 47592 48312 47594 47592 47593 47602 47603 47594 48312 48991 47595 48308 48314 47595 47596 48308 47596 47597 48308 49012 48308 47597 47597 48306 49012 47597 48305 48306 50399 50391 47598 47598 49657 50399 47598 48309 49657 47598 47599 48309 50391 49658 47598 47599 47600 48309 49013 48309 47600 48311 47603 47602 49015 48311 47602 47602 48307 49015 48311 48310 47603 48313 47605 47604 48314 48313 47604 48313 47619 47605 49022 49019 47606 47606 48319 49022 48322 47609 47607 47607 48321 48322 49665 48321 47607 47607 49664 49665 47607 49653 49664 47607 47608 49653 47609 47608 47607 47608 49644 49653 47608 49004 49644 47608 47609 49004 48322 47620 47609 47609 47620 49004 47610 48318 49666 49666 49009 47610 48329 48323 47611 48330 48329 47611 47611 47628 48330 48329 48319 47612 47612 48323 48329 49038 47626 47613 47613 47614 49038 47615 47614 47613 47614 47616 49025 47614 47615 47616 49672 49038 47614 47614 49024 49672 49025 49024 47614 47617 47620 48322 47621 47620 47617 47619 48327 49029 47619 48313 48327 47620 48303 49004 47620 47621 48303 48334 47624 47622 47622 47623 48334 47622 47624 47625 49040 48334 47623 47623 47635 49040 47623 47634 47635 49039 48332 47624 47624 48334 49039 49038 48333 47626 47631 47628 47627 47627 47630 47631 47628 47631 48330 47637 47636 47629 48335 47631 47630 47630 47638 48335 47630 47632 47638 48335 48330 47631 47639 47638 47632 47651 47635 47634 49700 49040 47635 47635 47651 49700 49049 49048 47636 47636 47637 49049 49047 48343 47636 49048 49047 47636 48336 48335 47638 48338 48336 47638 47638 47645 48338 47638 47639 47645 47639 47644 47645 49035 48344 47640 47640 48346 49035 47650 47642 47641 47641 47648 47650 47642 47650 48348 47655 47654 47643 47660 47655 47643 47656 47645 47644 47645 47656 48338 47646 48353 48355 47648 47649 47650 48350 47650 47649 48359 48350 47649 48350 48348 47650 49701 49700 47651 47651 49062 49701 47651 47652 49062 47653 47652 47651 49067 49062 47652 47652 48367 49067 47652 48366 48367 47652 47657 48366 47652 47653 47657 47658 47657 47653 49068 48369 47654 47654 47655 49068 47655 47660 49068 48340 48338 47656 48371 48366 47657 47657 47658 48371 47658 47661 48371 47658 47659 47661 47660 48343 48352 47660 48362 49068 47660 48352 48362 48374 48371 47661 47661 47666 48374 47661 47662 47666 47696 47666 47662 47672 47671 47663 49730 48377 47664 47664 49725 49730 47664 49710 49725 47664 48363 49710 47664 47665 48363 47665 48351 48363 47666 47696 48374 47679 47670 47667 47667 47678 47679 48382 47678 47667 47667 47668 48382 47669 47668 47667 47670 47669 47667 49076 48382 47668 47668 49070 49076 47668 47669 49070 47669 48369 49070 49069 48365 47671 47671 47672 49069 49728 49069 47672 48378 47675 47673 47673 47676 48378 47686 47685 47674 47674 47675 47686 48376 47686 47675 48378 48376 47675 47676 48377 48378 49753 48387 47677 47677 49743 49753 47677 47678 49743 47679 47678 47677 47678 48382 49092 49744 49743 47678 47678 49092 49744 48387 47682 47680 48385 47684 47681 47681 47682 48385 48388 48385 47682 47682 48387 48388 48384 48383 47685 47685 47686 48384 47686 48376 48384 47687 47692 47694 47699 47695 47688 48389 47697 47689 48390 48389 47689 49078 48390 47689 47689 47690 49078 47690 49077 49078 47690 48383 49077 47690 47691 48383 47692 47693 47694 47709 47694 47693 48397 47709 47693 49096 48381 47695 47695 48393 49096 47695 47703 48393 47695 47699 47703 48380 48374 47696 49091 48380 47696 47696 48381 49091 47713 47700 47698 47698 47710 47713 47699 47702 47703 47699 47700 47702 47712 47702 47700 47713 47712 47700 47703 47702 47701 48403 47703 47701 48408 48403 47701 47701 48402 48408 47701 48401 48402 47701 47702 48401 47702 47712 48401 49766 48393 47703 47703 49108 49766 47703 48403 49108 47706 47705 47704 48396 47706 47704 49102 49100 47705 49755 49102 47705 47705 47706 49755 47706 49106 49755 47706 48394 49106 48396 48394 47706 48405 48400 47708 49107 48405 47708 47711 47710 47709 47759 47711 47709 48397 47759 47709 48401 47713 47710 47710 47711 48401 48413 48401 47711 48425 48413 47711 47711 48407 48425 47711 48406 48407 47711 47759 48406 47712 47713 48401 48399 48395 47714 47714 47715 48399 48411 48399 47715 47715 47719 48411 47716 47717 47718 47716 47718 47721 49114 47718 47717 47717 49113 49114 47718 49114 49116 48421 47721 47718 49116 48421 47718 48415 48411 47719 48444 47737 47720 47720 47753 48444 49777 49121 47722 49778 49777 47722 47722 49772 49778 47722 49110 49772 47722 47725 49110 47722 47723 47725 47724 47723 47722 49121 47724 47722 47732 47725 47723 47734 47732 47723 47739 47734 47723 47723 47724 47739 49123 47739 47724 47724 49121 49123 47725 47726 49110 47727 47726 47725 47730 47727 47725 47732 47730 47725 49111 49110 47726 47726 49107 49111 47726 48405 49107 47726 47728 48405 47726 47727 47728 47731 47728 47727 48412 47731 47727 47727 47742 48412 47727 47729 47742 47730 47729 47727 47728 47731 48404 47728 48400 48405 47729 47733 47736 47729 47730 47733 47729 47735 47742 47736 47735 47729 47730 47732 47733 47734 47733 47732 47735 47741 47742 47745 47741 47735 47735 47736 47745 48442 48435 47737 48444 48442 47737 47738 48429 48438 49124 48433 47739 47739 49123 49124 47740 47741 47745 47743 48440 48443 47743 47744 48440 48441 48440 47744 48407 48406 47746 47746 47747 48407 48406 47759 47746 48425 48407 47747 47747 47752 48425 47750 47749 47748 48448 47750 47748 47748 48443 48448 49163 47772 47749 47749 47750 49163 47750 48463 49163 49153 48463 47750 47750 49152 49153 47750 48448 49152 48434 48424 47752 47752 48424 48425 47753 48436 48444 47753 47754 48436 47755 47754 47753 47764 47755 47753 47769 47764 47753 48437 48436 47754 47754 48413 48437 47754 47761 48413 47754 47760 47761 47754 47755 47760 47755 47764 47771 47762 47760 47755 47771 47762 47755 47756 47760 47762 47761 47760 47756 47756 47757 47761 47758 47757 47756 47762 47758 47756 48445 47761 47757 48447 48445 47757 48450 48447 47757 47757 47758 48450 48452 48450 47758 47758 47771 48452 47758 47762 47771 48418 48413 47761 48445 48418 47761 47764 47765 47771 47767 47765 47764 47770 47767 47764 47764 47769 47770 47767 47766 47765 48452 47771 47765 48454 48452 47765 47765 47778 48454 47765 47766 47778 47766 47774 47777 47766 47767 47774 47781 47778 47766 47766 47780 47781 47785 47780 47766 47766 47777 47785 47767 47773 47774 47775 47773 47767 47767 47770 47775 48451 47770 47769 47776 47775 47770 47787 47786 47772 49163 47787 47772 48458 47774 47773 47773 47784 48458 47773 47775 47784 48458 47777 47774 47785 47784 47775 47775 47776 47782 47783 47782 47776 48458 47784 47777 47777 47784 47785 48456 48454 47778 48460 48456 47778 47778 47781 48460 47781 47780 47779 47789 47781 47779 47801 47789 47779 47779 47788 47801 47779 47785 47788 47779 47780 47785 47781 47789 48460 47786 47787 47790 47799 47790 47787 48462 47799 47787 48463 48462 47787 49163 48463 47787 47788 47794 47801 47789 47795 48460 47801 47795 47789 47798 47797 47790 47799 47798 47790 47796 47794 47791 47802 47796 47791 47791 47800 47802 47791 47792 47800 47793 47792 47791 47794 47793 47791 47812 47800 47792 47821 47812 47792 47792 47820 47821 47794 47795 47801 47796 47795 47794 48461 48460 47795 47795 47796 48461 48465 48461 47796 47796 47802 48465 47809 47808 47797 47797 47798 47809 47811 47809 47798 47798 47810 47811 47798 47799 47810 48462 47810 47799 47813 47802 47800 47819 47813 47800 47800 47818 47819 47800 47812 47818 48467 48465 47802 47802 47813 48467 47803 48476 48483 47803 47805 48476 47803 47804 47805 49193 47805 47804 47804 48477 49193 47804 48474 48477 47804 48473 48474 47804 47814 48473 49192 48476 47805 49193 49192 47805 48473 47814 47806 47806 47815 48473 47806 47807 47815 47807 47808 47815 47816 47815 47808 48478 47816 47808 47808 47817 48478 47808 47809 47817 47809 47811 47817 48478 47811 47810 48481 48478 47810 49177 48481 47810 47810 49169 49177 47810 48470 49169 47810 48462 48470 48478 47817 47811 47822 47818 47812 47828 47822 47812 47812 47827 47828 47812 47821 47827 48471 48467 47813 47813 47819 48471 49185 48473 47815 47815 47816 49185 49187 49185 47816 47816 48479 49187 47816 48478 48479 47822 47819 47818 48482 48471 47819 48494 48482 47819 47819 47822 48494 48489 47821 47820 47820 47828 48489 47840 47828 47820 48489 47827 47821 47822 47828 48494 47823 47826 47836 47823 47825 47826 47823 47824 47825 47836 47834 47823 48490 47825 47824 49197 47826 47825 47825 48492 49197 47825 48490 48492 47837 47836 47826 48493 47837 47826 49197 48493 47826 48489 47828 47827 48495 48494 47828 47828 47840 48495 47832 47830 47829 49207 47832 47829 47829 48499 49207 47832 47831 47830 48511 48510 47832 49882 48511 47832 47832 49207 49882 48492 48491 47833 49208 48492 47833 47833 48503 49208 47839 47835 47834 47834 47838 47839 47834 47836 47838 47835 47839 47841 47836 47837 47838 48487 47838 47837 47837 48484 48487 48485 48484 47837 48493 48485 47837 48507 47839 47838 47838 48504 48507 47838 48488 48504 47838 48487 48488 48507 47841 47839 47843 47842 47841 48507 47843 47841 48507 47845 47843 47844 48531 49245 47844 48523 48531 47844 48515 48523 48516 48515 47844 47844 47845 48516 47845 48514 48516 47845 48507 48514 47846 48551 48564 47846 48550 48551 47846 48549 48550 48552 48549 47846 47847 49913 49917 47847 47850 49913 50629 47850 47847 47847 49918 50629 47847 47848 49918 47849 47848 47847 49917 47849 47847 50631 49918 47848 50632 50631 47848 50634 50632 47848 51311 50634 47848 47848 47849 51311 47849 49917 51311 50629 49259 47850 49914 49913 47850 47850 47851 49914 47851 48560 49914 47854 47853 47852 47856 47854 47852 47853 47854 48541 47854 48538 48541 48540 48538 47854 47854 47855 48540 48555 48540 47855 48557 48555 47855 47855 48556 48557 49255 49251 47857 47857 47858 49255 47858 48561 49255 47858 47860 48561 47858 47859 47860 47867 47860 47859 47860 47867 48561 47861 47862 48564 48564 48563 47861 47872 47865 47863 48568 47872 47863 48569 48568 47863 47863 48566 48569 47863 47864 48566 47865 47864 47863 47870 47869 47864 47864 47865 47870 49262 48566 47864 47864 48584 49262 47864 47869 48584 49254 48561 47867 47867 48562 49254 49253 48562 47868 47868 48563 49253 49258 48556 47872 47872 48568 49258 49945 48578 47873 47873 49944 49945 47874 49266 49267 47887 47876 47875 47879 47877 47876 48575 47879 47876 47876 48574 48575 49273 48574 47876 47876 49268 49273 47876 47887 49268 47879 47878 47877 47878 47881 47882 47878 47879 47881 48577 47881 47879 49264 48577 47879 49265 49264 47879 47879 48580 49265 47879 48575 48580 47880 48573 48583 47880 48572 48573 47880 47888 48572 47881 48577 48582 47883 47885 47890 47886 47885 47883 47883 47884 47886 47889 47886 47884 47909 47890 47885 47885 47901 47909 47885 47900 47901 47885 47886 47900 48586 47900 47886 47886 47889 48586 49271 49268 47887 47887 48588 49271 48587 48586 47889 47889 48585 48587 47909 47898 47890 48603 48589 47891 47894 47893 47892 48590 47894 47892 48595 47899 47893 48598 48595 47893 47893 47894 48598 49275 48598 47894 49276 49275 47894 49277 49276 47894 47894 48590 49277 47895 47896 48616 47897 47896 47895 47909 47897 47895 47896 47897 49971 49290 48616 47896 49971 49290 47896 47897 48601 49969 47897 47909 48601 47897 49969 49971 47909 47902 47898 47912 47903 47899 48595 47912 47899 47900 48586 48587 48592 47901 47900 47900 48587 48592 48602 47909 47901 47901 48600 48602 47901 48592 48600 49967 49282 47904 47904 49287 49967 47904 47905 49287 47906 47905 47904 49972 49287 47905 47905 48608 49972 47905 47906 48608 48609 48608 47906 47906 47907 48609 49289 48609 47908 47908 48615 49289 48602 48601 47909 47910 48597 49962 47910 47911 48597 47912 47911 47910 47910 49979 49980 47910 49962 49979 47911 47912 48597 47912 48596 48597 47912 48595 48596 47916 47915 47913 48618 47916 47913 47913 48617 48618 48621 48619 47914 47914 48620 48621 47914 47915 48620 47915 47916 48620 49299 48620 47916 47916 48618 49299 49307 48624 47917 50001 49307 47917 47917 49306 50001 47917 48625 49306 47917 47918 48625 47918 48623 48625 47918 48622 48623 47919 48624 48628 49303 47921 47920 49993 49303 47920 49994 49993 47920 50694 49994 47920 49292 49291 47921 47921 48612 49292 49303 48612 47921 47922 47923 47925 48630 47925 47923 48631 48630 47923 47951 47934 47924 47924 47937 47951 47924 47925 47937 48630 47937 47925 47938 47927 47926 49315 49314 47927 47927 48635 49315 47927 47938 48635 47928 49308 49310 47928 48628 49308 49310 47929 47928 47930 47932 47933 47945 47931 47930 47931 47945 47946 47956 47950 47931 47931 47946 47956 50012 49311 47935 47935 49312 50012 47935 47936 49312 47937 47936 47935 49311 47937 47935 47936 48634 49312 47936 48630 48634 47936 47937 48630 47952 47951 47937 48640 47952 47937 49311 48640 47937 47938 47939 48635 49316 48635 47939 47939 47940 49316 47941 47940 47939 48636 47941 47939 50010 49316 47940 50017 50010 47940 47940 50014 50017 47940 47941 50014 47941 49317 50014 47941 48636 49317 47942 47943 48636 47944 47943 47942 49318 48636 47943 47943 47944 49318 47944 48641 49318 47957 47956 47946 47947 47948 47960 47949 47948 47947 47960 47949 47947 47948 47949 47953 48643 47953 47949 49325 48643 47949 47949 48647 49325 47949 47960 48647 47965 47955 47950 47950 47956 47965 47952 48640 48648 48643 47959 47953 47967 47962 47954 48651 47967 47954 47954 47955 48651 47955 47968 48651 47955 47965 47968 47956 47957 47965 47969 47968 47957 47957 47958 47969 47968 47965 47957 48642 48641 47959 48643 48642 47959 49326 48647 47960 47967 47963 47962 48649 48646 47963 47963 47966 48649 47967 47966 47963 47964 49328 50706 47964 48646 49328 47966 47967 48663 50029 48649 47966 50709 50029 47966 47966 50036 50709 47966 48663 50036 47967 48655 48664 47967 48651 48655 48664 48663 47967 48655 48651 47968 48656 48655 47968 48652 47971 47970 47970 47972 48652 48660 47976 47971 49337 48660 47971 49338 49337 47971 47971 48652 49338 47972 47974 48652 47973 47989 48665 48667 48652 47974 47974 48661 48667 47975 48666 48672 47975 47976 48666 47976 48659 48666 48660 48659 47976 48009 47985 47978 48688 48009 47978 47978 47984 48688 47980 47986 47987 47980 47981 47986 48673 47983 47982 48678 48673 47982 47982 48672 48678 48673 47999 47983 49354 48688 47984 47984 49348 49354 47984 48662 49348 47985 48000 48002 48001 48000 47985 48008 48001 47985 48009 48008 47985 48682 47987 47986 47986 48002 48682 48685 47990 47987 47987 48684 48685 47987 48683 48684 47987 48682 48683 47988 47998 48677 48674 47991 47990 48685 48674 47990 47993 47992 47991 48674 47993 47991 48674 47994 47993 47994 48674 49359 47995 47996 47998 47997 47996 47995 48676 47998 47996 50056 48676 47996 47996 49361 50056 47996 49360 49361 47996 47997 49360 47997 48699 49360 48700 48699 47997 48712 48700 47997 47997 48011 48712 47998 48676 48677 47999 48673 48679 48695 48690 48000 48000 48694 48695 48000 48001 48694 48690 48002 48000 48707 48694 48001 48001 48008 48707 48690 48682 48002 48712 48011 48004 48004 48709 48712 48710 48709 48004 48004 48035 48710 48681 48671 48005 48005 48006 48681 48007 48006 48005 48703 48681 48006 48008 48689 48707 48008 48687 48689 48008 48009 48687 48688 48687 48009 48012 48686 49371 48012 48679 48686 48012 48019 48020 49371 48019 48012 49388 48021 48013 48013 48014 49388 48015 48014 48013 48019 48015 48013 48021 48019 48013 50803 49388 48014 48014 50798 50803 48014 48015 50798 48015 50774 50798 48015 49371 50774 48015 48019 49371 48746 48745 48016 48016 48018 48746 48747 48746 48018 48018 48031 48747 48021 48020 48019 49394 48039 48021 48021 49388 49394 49384 48024 48022 48022 48023 49384 48023 48744 49384 48023 48725 48744 50075 49372 48024 48024 49384 50075 48025 48026 48041 48027 48026 48025 48728 48027 48025 48025 48727 48728 48049 48041 48026 48765 48049 48026 48026 48726 48765 48026 48027 48726 50092 48726 48027 48027 48728 50092 48724 48719 48028 48028 48029 48724 49385 48727 48028 48028 49378 49385 48028 48717 49378 48719 48717 48028 48031 48044 48747 48031 48043 48044 48032 48033 48034 48722 48033 48032 48748 48034 48033 49393 48748 48033 48033 48722 49393 50825 50122 48034 48034 50109 50825 48034 48748 50109 48733 48710 48035 48035 48732 48733 48035 48036 48732 48036 48737 48750 48750 48732 48036 48740 48737 48037 48038 48039 48741 49395 48741 48039 48039 49394 49395 48042 48719 48724 49390 48719 48042 48042 48752 49390 48045 48044 48043 48753 48045 48043 49409 48747 48044 49416 49409 48044 48044 48045 49416 49419 49416 48045 49420 49419 48045 48045 48753 49420 48742 48725 48046 48751 48742 48046 49420 48753 48048 48048 48758 49420 48759 48758 48048 48048 48757 48759 48763 48056 48049 49426 48763 48049 49427 49426 48049 48049 48765 49427 48767 48055 48050 48050 48051 48767 48052 48051 48050 48055 48052 48050 48776 48767 48051 48055 48053 48052 48771 48060 48054 48772 48771 48054 49433 48772 48054 48054 48767 49433 48054 48055 48767 48056 48764 48770 48056 48763 48764 48766 48756 48057 48089 48078 48058 48058 48088 48089 48064 48061 48059 48061 48072 48073 48061 48064 48072 48062 48774 50157 48775 48774 48062 49428 48775 48062 48062 48063 49428 48063 48773 49428 48063 48761 48773 48080 48072 48064 49441 48781 48065 49444 49441 48065 48065 48066 49444 48066 48798 49444 50156 48074 48067 50168 50156 48067 48067 49456 50168 48067 48068 49456 48068 48800 49456 48068 48796 48800 48069 48070 48792 48791 48077 48069 48792 48791 48069 48070 48770 48792 48074 48777 48778 49438 48777 48074 50156 49438 48074 48077 48076 48075 48075 48076 48086 48076 48077 48791 48087 48086 48076 49448 48087 48076 48076 49447 49448 48076 48791 49447 48089 48079 48078 48079 48803 49439 48079 48089 48803 48101 48098 48081 48081 48093 48101 48094 48093 48081 48802 48801 48083 49452 48085 48084 48084 49451 49452 48084 48797 49451 49452 48793 48085 49458 48797 48086 49459 49458 48086 48086 48087 49459 49460 49459 48087 48087 49448 49460 48099 48089 48088 48089 48794 48803 48089 48099 48794 48090 48783 49442 48090 48782 48783 48092 48091 48090 49442 48092 48090 49450 48795 48091 48091 49449 49450 48091 48092 49449 49454 49449 48092 48092 48807 49454 48092 48806 48807 50167 48806 48092 48092 48790 50167 49442 48790 48092 48799 48101 48093 48093 48795 48799 48103 48102 48095 48098 48101 48809 48809 48800 48098 48810 48794 48099 48812 48804 48100 49464 48812 48100 48100 49463 49464 48100 49453 49463 48101 48799 48808 48101 48808 48809 48102 48103 48104 48816 48104 48103 49465 48816 48103 48103 48801 49465 48104 48816 49468 48822 48107 48105 49470 48822 48105 48105 48106 49470 48818 48817 48107 48822 48818 48107 48108 48109 48805 48820 48805 48109 48823 48820 48109 48109 48110 48823 48825 48823 48110 48826 48825 48110 48828 48826 48111 48123 48121 48112 48124 48123 48112 48833 48126 48113 48831 48830 48114 48114 48829 48831 50231 48832 48115 48115 48119 50231 48115 48116 48119 48116 48118 48119 48125 48124 48117 48838 48125 48117 48841 48838 48117 48842 48841 48117 49507 48119 48118 48118 48836 49507 50232 50231 48119 50233 50232 48119 48119 49507 50233 49507 48836 48120 48120 48127 49507 48123 48122 48121 48840 48839 48122 48122 48837 48840 48122 48123 48837 49502 48837 48123 49503 49502 48123 48123 48125 49503 48123 48124 48125 48125 48838 49503 48126 48833 48834 50233 49507 48127 48127 50228 50233 50236 50228 48127 48127 49508 50236 48128 48131 48843 48844 48130 48129 48845 48844 48129 49510 48845 48129 48129 48843 49510 48134 48133 48130 48847 48134 48130 49513 48847 48130 48130 48844 49513 48131 48132 48843 49510 48843 48132 48132 49509 49510 48132 48846 49509 48847 48137 48134 49512 48846 48135 49514 49512 48135 48135 48136 49514 49519 49514 48136 48136 48849 49519 48136 48848 48849 48136 48138 48848 48139 49513 49515 48139 48847 49513 48139 49515 49516 48140 48141 48143 48144 48143 48141 49530 48144 48141 48141 48852 49530 48142 48145 48854 48872 48152 48144 49530 48872 48144 48145 48853 48854 48858 48853 48145 48145 48857 48858 49526 48857 48145 48145 48861 49526 48145 48859 48861 48860 48859 48145 48146 48147 48860 49531 48860 48147 48147 48863 49531 48864 48863 48147 48867 48864 48147 48147 48148 48867 48148 48149 48867 48150 48149 48148 48149 48151 48867 49532 48867 48151 49536 49532 48151 48151 49535 49536 48151 48874 49535 48151 48159 48874 48151 48158 48159 48878 48877 48152 50266 48878 48152 48152 48865 50266 48866 48865 48152 48872 48866 48152 48153 48870 50967 48871 48154 48153 50967 48871 48153 48871 48156 48154 48886 48885 48156 50275 48886 48156 48156 50272 50275 48156 50270 50272 48156 48871 50270 48890 48883 48160 48160 48889 48890 48160 48161 48889 48161 48165 48889 48905 48888 48163 48163 48895 48905 48163 48164 48895 48164 48167 48170 48165 48179 48892 48890 48889 48165 48892 48890 48165 49550 48902 48166 48166 48891 49550 48167 48169 48170 48881 48173 48168 48171 48882 49540 48171 48172 48882 48173 48172 48171 49555 48173 48171 50974 49555 48171 48171 50285 50974 50287 50285 48171 48171 49540 50287 48172 48881 48882 48172 48173 48881 49555 48175 48173 48174 48183 48907 49547 48183 48174 48174 48175 49547 49555 49547 48175 48185 48178 48176 48176 48177 48179 48178 48177 48176 48894 48179 48177 49545 48894 48177 49549 49545 48177 48177 48178 49549 48178 48897 49549 48178 48190 48897 48191 48190 48178 48894 48892 48179 48903 48895 48180 48904 48903 48180 48906 48904 48180 48180 48181 48906 48181 48187 48906 48188 48187 48181 48920 48202 48182 48921 48920 48182 48182 48183 48921 48184 48183 48182 48202 48184 48182 48183 48184 48907 49566 48921 48183 48183 49553 49566 48183 49547 49553 49561 48910 48186 48187 48189 48914 48187 48188 48189 48914 48906 48187 48192 48189 48188 48189 48192 48914 48190 48191 48193 48190 48896 48897 49570 48896 48190 48190 48193 49570 48192 48197 48914 48193 48929 49570 48193 48199 48929 48931 48196 48194 48194 48195 48931 48195 48913 48931 48931 48205 48196 48916 48914 48197 48197 48198 48916 48917 48916 48198 48919 48917 48198 48198 48201 48919 48930 48929 48199 48199 48928 48930 48204 48203 48200 48935 48919 48201 48202 48920 48926 48930 48928 48203 50306 48930 48203 48203 48936 50306 48203 48204 48936 48207 48206 48205 48931 48207 48205 48206 48211 48213 49579 48211 48206 48206 48207 49579 50304 49579 48207 48207 50303 50304 48207 48931 50303 48938 48937 48208 48208 48932 48938 48211 48210 48209 48212 48211 48209 49577 49575 48210 49578 49577 48210 48210 48211 49578 49575 48933 48210 48211 49579 50312 48211 48212 48213 50313 49578 48211 48211 50312 50313 48215 48220 48939 48217 48924 48934 49581 48924 48217 48944 48228 48219 49572 48944 48219 48219 48937 49572 49583 48939 48220 48220 48925 49583 48221 48949 48950 48950 48222 48221 49585 48225 48223 48223 48939 49585 48958 48943 48224 48224 48225 48958 49585 48958 48225 49592 48945 48228 48228 49588 49592 48228 48944 49588 49589 48946 48229 48229 48947 49589 48948 48947 48229 48232 48231 48230 49591 49587 48231 48231 48232 49591 48232 48233 49591 49598 49591 48233 48233 48955 49598 48245 48244 48234 48234 48235 48245 48236 48235 48234 49608 48236 48234 50338 49608 48234 48234 49602 50338 48234 48244 49602 48973 48245 48235 49611 48973 48235 48235 48236 49611 50344 49611 48236 48236 49608 50344 48245 48243 48237 48237 48244 48245 48946 48244 48237 48238 48247 48248 48238 48246 48247 48238 48239 48246 48954 48246 48239 48239 48949 48954 48950 48949 48239 48240 48960 48961 48241 48242 48975 48966 48960 48241 49605 48966 48241 48241 48975 49605 48242 48249 48256 48242 48256 48975 48243 48245 48260 48244 49589 49602 48244 48946 49589 48972 48260 48245 48973 48972 48245 48954 48247 48246 48251 48248 48247 48954 48261 48247 48970 48256 48249 48964 48955 48250 48969 48964 48250 48250 48968 48969 48257 48253 48252 48971 48257 48252 48252 48967 48971 48264 48258 48253 48253 48257 48264 48256 48974 48975 48256 48970 48974 48266 48264 48257 48971 48266 48257 48258 48264 48979 48972 48272 48259 48259 48260 48972 48273 48268 48259 48259 48272 48273 48263 48264 48976 48265 48264 48263 48978 48265 48263 49620 48978 48263 49634 49620 48263 48263 49631 49634 49632 49631 48263 48263 49617 49632 48263 48976 49617 49624 48979 48264 48264 48265 49624 48264 48266 48976 48265 49621 49624 49622 49621 48265 48265 48978 49622 48266 48971 48976 48270 48274 48275 48270 48271 48274 48272 48972 48973 48272 48277 48278 48980 48277 48272 48272 48973 48980 48276 48275 48274 49628 48276 48274 48274 48981 49628 48982 48981 48274 48274 48283 48982 48284 48283 48274 48977 48970 48275 48275 48276 48977 49614 48977 48276 49628 49614 48276 48279 48278 48277 49635 48279 48277 48277 48980 49635 48984 48280 48279 49635 48984 48279 48984 48983 48280 48281 48285 49637 48295 48286 48281 48988 48295 48281 48281 48987 48988 49637 48987 48281 48282 48287 48288 48990 48982 48283 48283 48989 48990 48986 48985 48285 48285 48983 48986 48285 48985 49637 48295 48294 48286 48289 48288 48287 48999 48300 48289 48293 48292 48291 48994 48293 48291 48291 48993 48994 48291 48294 48993 49001 48301 48293 50380 49001 48293 48293 48994 50380 48294 48988 48993 48294 48295 48988 49003 48995 48296 50383 48996 48297 48297 48298 50383 50387 50383 48298 48298 50381 50387 48298 49641 50381 49004 48304 48299 49644 49004 48299 48999 48998 48300 49002 48302 48301 48301 49001 49002 49649 49006 48302 48302 49002 49649 48303 48304 49004 49006 48306 48305 49656 49012 48306 48306 49007 49656 48306 49006 49007 49660 49015 48307 48307 49011 49660 49012 48314 48308 48309 49013 49657 49020 49016 48310 48310 48311 49020 49678 49020 48311 48311 49026 49678 49027 49026 48311 48311 49015 49027 49647 48991 48312 48312 49017 49647 48312 49016 49017 48328 48327 48313 49018 48328 48313 48313 48314 49018 49681 49018 48314 48314 49012 49681 49667 48320 48315 48315 49023 49667 49661 49013 48316 48316 48320 49661 48316 48317 48320 48318 48331 49666 48319 48329 49022 49662 49661 48320 49668 49662 48320 48320 49667 49668 49665 48326 48321 48324 49670 50415 48324 48325 49670 49028 49025 48324 49033 49028 48324 50415 49033 48324 48325 48326 49670 49671 49670 48326 48326 49665 49671 48327 48328 49029 49041 49029 48328 49673 49041 48328 48328 49018 49673 49030 49022 48329 48329 48330 49030 48330 48335 49030 49676 49666 48331 49677 49676 48331 48331 48332 49677 48332 49039 49677 49687 49037 48333 48333 49038 49687 50435 49039 48334 48334 49692 50435 48334 49040 49692 48335 48336 49030 48336 49022 49030 49032 49022 48336 48336 48337 49032 48338 48337 48336 48337 48339 49032 48337 48338 48339 48340 48339 48338 48339 48344 49032 48339 48340 48344 49042 48345 48341 48341 48342 49042 49688 49042 48342 49047 48352 48343 49034 49032 48344 49035 49034 48344 48347 48346 48345 49042 48347 48345 49036 49035 48346 49675 49036 48346 48346 48347 49675 49683 49675 48347 49684 49683 48347 49691 49684 48347 48347 49042 49691 48348 48350 49044 48364 48351 48349 49709 48364 48349 49694 49044 48350 48350 48360 49694 48350 48359 48360 48364 48363 48351 49711 48362 48352 48352 49705 49711 48352 49047 49705 49057 48355 48353 48353 49055 49057 48353 48354 49055 49063 49055 48354 48354 48365 49063 49056 49053 48355 49057 49056 48355 49059 48357 48356 48356 49053 49059 49060 48358 48357 48357 49058 49060 49059 49058 48357 49060 49054 48358 48361 48360 48359 50444 48361 48359 48359 49054 50444 49695 49694 48360 48360 48361 49695 51134 49695 48361 48361 51133 51134 48361 50445 51133 48361 50444 50445 49723 49068 48362 48362 49711 49723 48363 48364 49710 48364 49709 49710 49065 49063 48365 49069 49065 48365 48368 48367 48366 48370 48368 48366 48371 48370 48366 48367 48368 49067 48368 49066 49067 48368 48370 49066 49726 49070 48369 48369 49068 49726 48370 48373 49066 48370 48372 48373 48370 48371 48372 48375 48372 48371 48371 48374 48375 48379 48373 48372 48372 48375 48379 49073 49066 48373 48373 48379 49073 48380 48375 48374 48380 48379 48375 48378 48377 48376 49080 48384 48376 49081 49080 48376 48376 48377 49081 48377 49071 49081 49072 49071 48377 49730 49072 48377 49082 49073 48379 49090 49082 48379 48379 48380 49090 48380 49087 49090 49095 49087 48380 48380 49091 49095 49096 49091 48381 48382 49076 49084 48382 49084 49092 49086 49077 48383 48383 48384 49086 48384 49080 49086 48388 48386 48385 48386 49745 49746 49754 49745 48386 48386 48388 49754 49754 48388 48387 48387 49753 49754 49098 49085 48389 48389 48391 49098 48389 48390 48391 48392 48391 48390 49078 48392 48390 50478 49098 48391 50479 50478 48391 48391 49740 50479 48391 49079 49740 48391 48392 49079 48392 49078 49079 49759 49096 48393 49766 49759 48393 48394 48395 49106 48395 48399 49117 49763 49106 48395 48395 49117 49763 48398 49105 49767 49115 49113 48398 49767 49115 48398 48399 48411 48416 48399 48416 49117 48414 48402 48401 48401 48413 48414 48414 48408 48402 49112 49108 48403 48403 48408 49112 49118 49112 48408 49119 49118 48408 48408 48414 49119 48416 48415 48409 49131 48416 48409 48409 49130 49131 48409 48410 49130 48410 48430 49130 48411 48415 48416 48417 48414 48413 48418 48417 48413 48413 48423 48437 48424 48423 48413 48425 48424 48413 48414 48419 49119 48414 48417 48419 49764 49117 48416 49784 49764 48416 49785 49784 48416 50507 49785 48416 48416 49131 50507 48417 48418 48419 48420 48419 48418 49135 48420 48418 48418 48445 49135 49122 49119 48419 49125 49122 48419 48419 48420 49125 49135 49125 48420 48427 48422 48421 49783 48427 48421 48421 49774 49783 48421 49116 49774 48422 48426 48429 48427 48426 48422 48423 48435 48437 48423 48434 48435 48423 48424 48434 48438 48429 48426 49137 48438 48426 48426 48428 49137 48426 48427 48428 49127 48428 48427 49782 49127 48427 49783 49782 48427 48428 49127 49137 49140 49130 48430 48430 48439 49140 48431 48432 49133 49133 48441 48431 48432 48433 49133 48433 49124 49133 48435 48436 48437 48442 48436 48435 48436 48442 48444 49143 49142 48438 49146 49143 48438 48438 49137 49146 49144 48443 48440 48440 48441 49144 49792 49144 48441 48441 49133 49792 49144 48448 48443 48445 48446 49135 48447 48446 48445 49136 49135 48446 49790 49136 48446 49795 49790 48446 48446 48447 49795 48447 49147 49795 48447 48453 49147 48447 48449 48453 48450 48449 48447 49792 49152 48448 48448 49144 49792 49156 48453 48449 48449 48457 49156 48449 48454 48457 48449 48450 48454 48450 48452 48454 49148 49147 48453 49156 49148 48453 48454 48456 48457 48466 48459 48455 48455 48460 48466 48455 48456 48460 48457 48456 48455 48459 48457 48455 49162 49156 48457 48457 48459 49162 49815 49162 48459 48459 49175 49815 48459 49174 49175 48459 48466 49174 48460 48461 48466 48468 48466 48461 48461 48465 48468 48462 48464 48470 48462 48463 48464 49153 48464 48463 48464 49153 49154 49161 48470 48464 48464 49154 49161 48469 48468 48465 48465 48467 48469 48466 49168 49174 48466 48468 49168 48472 48469 48467 48467 48471 48472 48468 48469 49168 49183 49168 48469 48469 49180 49183 48469 48472 49180 49176 49169 48470 48470 49170 49176 48470 49164 49170 48470 49161 49164 48475 48472 48471 48482 48475 48471 48472 48475 49180 48473 49184 49851 49185 49184 48473 49851 48474 48473 49850 48477 48474 49851 49850 48474 48475 48497 49180 48475 48482 48497 49190 48483 48476 49192 49190 48476 49850 49193 48477 48480 48479 48478 49194 48480 48478 48478 48481 49194 50560 49187 48479 48479 48480 50560 48480 49194 50560 49195 49194 48481 48481 49177 49195 48482 48496 48497 48519 48496 48482 48482 48494 48519 49200 49196 48483 49201 49200 48483 48483 49191 49201 48483 49190 49191 48484 48486 48487 49863 48486 48484 48484 48485 49863 48485 49858 49863 48485 48493 49858 48506 48505 48486 49872 48506 48486 48486 49863 49872 48488 48487 48486 48505 48488 48486 48505 48504 48488 48490 48491 48492 49202 49197 48492 49209 49202 48492 49210 49209 48492 48492 49208 49210 49859 49858 48493 48493 49202 49859 48493 49197 49202 48494 48495 48508 48527 48519 48494 48494 48526 48527 48494 48508 48526 48518 48517 48495 48517 48508 48495 48498 48497 48496 48509 48498 48496 48528 48509 48496 48496 48519 48528 49189 49180 48497 48497 48498 49189 49204 49189 48498 48498 48509 49204 49882 49207 48499 48499 49881 49882 48499 49206 49881 48499 49196 49206 49206 49200 48500 50587 49206 48500 50588 50587 48500 48500 49888 50588 48500 49875 49888 48500 48501 49875 48502 48501 48500 49200 48502 48500 48501 49201 49875 48501 48502 49201 48502 49200 49201 49212 49208 48503 48504 48506 48507 48504 48505 48506 48513 48507 48506 49884 48513 48506 48506 49872 49884 48507 48513 48514 48508 48525 48526 48508 48524 48525 48508 48517 48524 49211 49204 48509 48509 48520 49211 48522 48520 48509 48528 48522 48509 50582 49891 48510 48510 50580 50582 48510 50579 50580 48510 48511 50579 48511 49880 51276 48511 49879 49880 49882 49879 48511 51277 50579 48511 48511 51276 51277 48514 48513 48512 49214 48514 48512 49224 49214 48512 49884 49224 48512 48512 48513 49884 48514 48515 48516 49214 48515 48514 49223 48523 48515 48515 49214 49223 48517 48518 48524 48532 48524 48518 48530 48528 48519 48537 48530 48519 48519 48527 48537 49219 49211 48520 48520 48521 49219 48522 48521 48520 48521 48522 49225 49221 49219 48521 49226 49221 48521 49227 49226 48521 48521 49225 49227 48522 48528 49229 49229 49225 48522 50611 48531 48523 48523 49223 50611 48532 48525 48524 48525 48536 48547 48525 48532 48536 48547 48526 48525 48546 48527 48526 48548 48546 48526 48526 48547 48548 48546 48537 48527 48528 48533 48534 48528 48529 48533 48530 48529 48528 48528 48534 49229 48529 48530 48538 48540 48533 48529 48529 48538 48540 48542 48539 48530 48530 48537 48542 48539 48538 48530 49907 49245 48531 50611 49907 48531 48540 48534 48533 49230 49229 48534 48534 48540 49230 49250 48536 48535 48535 48544 49250 49250 48547 48536 48546 48542 48537 48538 48539 48541 48542 48541 48539 48540 48555 49230 48541 48542 48546 48553 48544 48543 48544 48547 49250 48544 48545 48547 48554 48545 48544 48544 48553 48554 48548 48547 48545 48545 48546 48548 48549 48552 49245 48565 48550 48549 49907 48565 48549 48549 49245 49907 48563 48551 48550 49253 48563 48550 49257 49253 48550 48550 48565 49257 48551 48563 48564 48555 48557 49230 49239 48557 48556 49258 49239 48556 49239 49230 48557 49261 48567 48558 48558 49260 49261 48558 48559 49260 49925 49260 48559 48559 49259 49925 48560 49910 49914 48560 49252 49910 48560 49251 49252 48561 49254 49255 48562 49244 49254 49253 49244 48562 50618 49257 48565 48565 49907 50618 49916 48569 48566 49931 49916 48566 48566 49922 49931 49923 49922 48566 48566 49262 49923 49261 48570 48567 49916 49258 48568 48568 48569 49916 49932 49263 48570 48570 49261 49932 48571 48581 49929 48571 48577 48581 48582 48577 48571 48571 48572 48582 48573 48572 48571 48584 48573 48571 49930 48584 48571 48571 49929 49930 48584 48583 48573 48574 49273 49939 48576 48575 48574 49939 48576 48574 48575 48576 48580 49934 48580 48576 49939 49934 48576 49264 48581 48577 49269 48579 48578 49946 49269 48578 48578 49945 49946 49270 48585 48579 49949 49270 48579 48579 49269 49949 49926 49265 48580 49928 49926 48580 49934 49928 48580 48581 49920 49929 49936 49920 48581 48581 49264 49936 49923 49262 48584 49930 49923 48584 48593 48587 48585 49270 48593 48585 48593 48592 48587 49274 49271 48588 49956 49274 48588 48588 49278 49956 48588 48589 49278 48589 48603 49278 48590 48591 49277 49280 49277 48591 49281 49280 48591 49283 49281 48591 48592 48594 48600 48592 48593 48594 48599 48594 48593 49270 48599 48593 48594 48599 48600 49279 48596 48595 48595 48598 49279 48596 49279 49957 49962 48597 48596 48596 49957 49962 48598 49275 49279 49284 48600 48599 48599 49270 49284 49285 48602 48600 49968 49285 48600 48600 49952 49968 48600 49284 49952 48601 48602 49285 48601 49285 49969 49286 49278 48603 48603 48605 49286 48603 48604 48605 48606 48605 48604 49288 48606 48604 48605 49288 49291 48605 48606 49288 49292 49286 48605 48605 49291 49292 49298 48617 48607 48608 48609 49289 48608 49289 49972 50659 49286 48610 51359 50659 48610 48610 48611 51359 48612 48611 48610 49292 48612 48610 48610 49286 49292 52044 51359 48611 48611 51372 52044 48611 51371 51372 51382 51371 48611 48611 48612 51382 48612 49303 49993 51384 51382 48612 48612 50687 51384 48612 50686 50687 48612 49993 50686 49294 48615 48614 48614 49290 49294 48614 48616 49290 49297 48616 48614 49293 49289 48615 49295 49293 48615 48615 49294 49295 49985 48618 48617 48617 49983 49985 49984 49983 48617 48617 49298 49984 49985 49299 48618 48619 48621 48622 49300 48621 48620 49302 49300 48620 48620 49299 49302 48623 48622 48621 49300 48623 48621 49305 48625 48623 48623 49300 49305 48629 48628 48624 49307 48629 48624 48625 49304 49306 49305 49304 48625 51385 50694 48626 51398 51385 48626 48626 48627 51398 51399 51398 48627 48627 50706 51399 48628 48629 49308 49309 49308 48629 48629 49307 49309 48630 48631 48634 48631 48632 48634 49313 48634 48632 48632 48633 49313 49324 49313 48633 48633 49314 49324 49313 49312 48634 49316 49315 48635 49318 49317 48636 48639 48638 48637 49319 48639 48637 48645 48644 48638 48638 48639 48645 49319 48645 48639 49329 48648 48640 50012 49329 48640 48640 49311 50012 48641 48642 49318 50021 49318 48642 48642 50019 50021 50020 50019 48642 48642 48643 50020 50022 50020 48643 48643 49325 50022 48644 49320 49327 48644 48645 49320 48645 49319 49320 49335 49328 48646 48646 48649 49335 50026 49325 48647 50027 50026 48647 48647 49331 50027 48647 49326 49331 49330 48650 48648 48648 49329 49330 50029 49335 48649 48652 49349 50717 48652 48667 49349 50039 49338 48652 50716 50039 48652 50717 50716 48652 48653 48654 49348 49348 48662 48653 48654 49339 49348 48655 48656 48657 48655 48657 48664 48658 48657 48656 49345 48664 48657 48657 48668 49345 48657 48658 48668 48669 48668 48658 48658 48665 48669 50037 48666 48659 50038 50037 48659 48659 48660 50038 48660 49337 50039 50039 50038 48660 48671 48667 48661 48661 48670 48671 50045 50036 48663 48663 49344 50045 49345 49344 48663 48663 48664 49345 49341 48672 48666 50037 49341 48666 49351 49349 48667 48667 49346 49351 49347 49346 48667 48667 48671 49347 48668 49344 49345 48668 49343 49344 48668 48669 49343 48671 48681 49347 49342 48678 48672 48672 49341 49342 48673 48678 48679 48674 48693 49359 48674 48685 48693 48675 48676 50056 48677 48676 48675 49343 48677 48675 49344 49343 48675 50045 49344 48675 50737 50045 48675 48675 50726 50737 48675 50057 50726 48675 50056 50057 48680 48679 48678 49355 48680 48678 48678 49342 49355 49356 48686 48679 48679 48680 49356 50061 49356 48680 48680 50058 50061 48680 49355 50058 48681 49346 49347 50055 49346 48681 48681 48703 50055 48690 48683 48682 48683 48696 49357 48683 48691 48696 48683 48690 48691 48692 48684 48683 49357 48692 48683 48692 48685 48684 48685 48692 48693 48686 49356 50061 50061 49371 48686 49368 48689 48687 50063 49368 48687 48687 50060 50063 48687 49353 50060 48687 48688 49353 48688 49352 49353 49354 49352 48688 48689 48694 48707 50077 48694 48689 48689 49369 50077 48689 49368 49369 48695 48691 48690 48697 48696 48691 48705 48697 48691 48691 48695 48705 49357 48693 48692 50771 50072 48693 48693 49377 50771 48693 49357 49377 48693 49358 49359 50069 49358 48693 50072 50069 48693 48706 48695 48694 50080 48706 48694 48694 50077 50080 48706 48705 48695 49377 49357 48696 48696 48697 49377 50081 49377 48697 50795 50081 48697 48697 48705 50795 49358 48708 48698 49359 49358 48698 49370 49360 48699 48699 48700 49370 48700 48711 49370 48712 48711 48700 50755 48704 48701 48701 50066 50755 48701 48702 50066 48702 49372 50066 50755 50055 48703 48703 48704 50755 48705 48706 50795 50796 50795 48706 48706 50078 50796 50080 50078 48706 48723 48722 48708 49358 48723 48708 48709 48711 48712 48735 48711 48709 48709 48710 48735 48710 48734 48735 49405 48734 48710 48710 48733 49405 50073 49370 48711 48711 48735 50073 48713 49365 49366 49383 49365 48713 48713 49382 49383 48713 48716 49382 48713 48714 48716 48715 48714 48713 49366 48715 48713 48721 48716 48714 48714 48720 48721 48714 48715 48720 48715 48718 48720 49380 48718 48715 48715 49375 49380 48715 49366 49375 49387 49382 48716 48716 49386 49387 48716 48721 49386 49379 49378 48717 49380 49379 48717 48717 48718 49380 48719 48718 48717 48721 48720 48718 48718 48719 48721 49391 48721 48719 48719 49390 49391 49391 49386 48721 48722 48723 49393 48723 49358 49393 48725 48743 48744 48725 48742 48743 49401 48765 48726 50092 49401 48726 49389 48728 48727 48727 49385 49389 48728 50085 50092 48728 49389 50085 49404 48762 48729 48729 48730 49404 48730 48731 50117 49414 49404 48730 48730 49413 49414 50117 49413 48730 48731 48745 50117 48749 48733 48732 48750 48749 48732 48733 48749 49405 48736 48735 48734 49398 48736 48734 50813 49398 48734 50814 50813 48734 48734 50100 50814 48734 49405 50100 50783 50073 48735 48735 48736 50783 50785 50783 48736 51512 50785 48736 52124 51512 48736 48736 51521 52124 48736 51520 51521 48736 49398 51520 49406 48750 48737 50110 49406 48737 48737 48738 50110 48740 48738 48737 48738 48739 50111 48740 48739 48738 50830 50110 48738 48738 50111 50830 48739 50101 50111 48739 48740 50101 48740 49399 50101 48740 48741 49399 48741 49395 49399 50805 50804 48742 48742 50112 50805 48742 48751 50112 50804 48743 48742 49397 48744 48743 51513 49397 48743 48743 50804 51513 49397 49384 48744 50120 50119 48745 48745 49408 50120 48745 48746 49408 50119 50117 48745 49409 49408 48746 48746 48747 49409 50812 50109 48748 48748 50782 50812 48748 50086 50782 48748 49393 50086 49406 49405 48749 48749 48750 49406 48751 48754 50112 48755 48754 48751 49410 48755 48751 48751 49407 49410 50099 49390 48752 50115 50099 48752 48752 49411 50115 50821 50112 48754 50831 50821 48754 48754 50822 50831 48754 48755 50822 48755 49410 49424 48755 50131 50822 50132 50131 48755 48755 50129 50132 48755 49424 50129 48756 48766 49412 49423 48759 48757 48757 48760 49423 49430 49417 48758 48758 49421 49430 48758 48759 49421 48758 49418 49420 48758 49417 49418 49422 49421 48759 49423 49422 48759 50122 49423 48760 49415 48773 48761 48761 49414 49415 48761 48762 49414 48762 49404 49414 49431 48764 48763 48763 49426 49431 49431 48770 48764 48765 49401 49427 50139 49412 48766 48766 48787 50139 48767 48788 49433 50859 48788 48767 48767 50155 50859 48767 48780 50155 48767 48776 48780 48784 48769 48768 48769 48784 49436 50129 49424 48769 50130 50129 48769 48769 49435 50130 48769 49434 49435 49436 49434 48769 50151 48792 48770 48770 49432 50151 48770 49431 49432 48771 48772 48782 48783 48782 48772 49433 48783 48772 50851 49428 48773 48773 50845 50851 48773 49425 50845 48773 49415 49425 50875 50157 48774 48774 50855 50875 48774 48775 50855 48775 50852 50855 48775 49428 50852 49438 48785 48777 48779 49441 50159 48779 48781 49441 50158 48780 48779 50159 50158 48779 50158 50155 48780 48783 48789 49442 49433 48789 48783 48784 48785 49436 48785 49438 49443 49443 49436 48785 49440 49437 48786 48786 49439 49440 49437 48787 48786 50152 50139 48787 48787 49437 50152 48788 48789 49433 48790 48789 48788 50163 48790 48788 50176 50163 48788 48788 50158 50176 50859 50158 48788 48789 48790 49442 50877 50167 48790 48790 50163 50877 50164 49447 48791 48791 50161 50164 48791 48792 50161 48792 50151 50161 48793 49452 50172 50172 49445 48793 48811 48803 48794 48794 48810 48811 49454 48799 48795 48795 49450 49454 49458 49451 48797 50175 49444 48798 48798 48806 50175 49454 48813 48799 48813 48808 48799 49457 49456 48800 48800 48809 49457 50180 49465 48801 48801 48802 50180 48802 50170 50180 48802 49446 50170 49462 49439 48803 48803 49461 49462 48803 48811 49461 48811 48810 48804 48812 48811 48804 48807 48806 48805 48821 48807 48805 48805 48819 48821 48820 48819 48805 48806 50167 50175 48807 48821 49454 48814 48809 48808 48808 48813 48814 49473 49457 48809 48809 48814 49473 50189 49461 48811 48811 48812 50189 50193 50189 48812 50901 50193 48812 48812 50898 50901 48812 49464 50898 48813 49454 49455 48815 48814 48813 49455 48815 48813 50194 49473 48814 50200 50194 48814 48814 48815 50200 50201 50200 48815 48815 49472 50201 48815 49455 49472 50196 49468 48816 48816 49466 50196 49467 49466 48816 48816 49465 49467 48817 48818 48824 48827 48824 48818 50219 48827 48818 48818 48822 50219 48819 50197 50198 48819 49474 50197 48819 48820 49474 49471 48821 48819 50198 49471 48819 48820 48823 49474 49455 49454 48821 49471 49455 48821 48822 50205 50219 48822 49470 50205 48823 48825 49474 48825 48828 49474 48825 48826 48828 49493 48829 48827 50215 49493 48827 50216 50215 48827 50219 50216 48827 50206 49474 48828 48828 49494 50206 49493 48831 48829 50229 49501 48830 48830 48831 50229 48831 50215 50229 48831 49493 50215 48832 50231 50929 50230 49494 48832 50929 50230 48832 49501 49500 48833 48835 48834 48833 49500 48835 48833 49505 48842 48834 49506 49505 48834 48834 48835 49506 48835 49499 49506 49500 49499 48835 50237 48840 48837 48837 49502 50237 49505 49503 48838 48838 48841 49505 50930 49508 48839 48839 48840 50930 48840 50237 50930 48841 48842 49505 48844 49511 49513 48844 48845 49511 49522 49511 48845 50239 49522 48845 48845 49510 50239 49512 49509 48846 48849 48850 49519 48850 48855 49519 48850 48851 48855 48857 48855 48851 48858 48857 48851 50254 49530 48852 50255 50254 48852 48852 50252 50255 48852 49525 50252 48852 49516 49525 48855 48856 50244 48857 48856 48855 49520 49519 48855 48855 49518 49520 48855 49517 49518 50244 49517 48855 48856 49526 50248 48856 48857 49526 50248 50244 48856 48859 48860 49531 48862 48861 48859 49531 48862 48859 50950 49526 48861 48861 48862 50950 50955 50950 48862 48862 50954 50955 48862 50263 50954 48862 49531 50263 48863 48864 49536 50263 49531 48863 50268 50263 48863 48863 49536 50268 48864 49532 49536 48864 48867 49532 50964 50266 48865 48865 48866 50964 48866 50264 50964 50265 50264 48866 50267 50265 48866 48866 48872 50267 48868 48869 49537 49533 48870 48868 49537 49533 48868 48870 49533 50967 50967 50270 48871 48872 50256 50267 48872 49530 50256 48874 49534 49535 48874 48875 49534 48876 48875 48874 48880 48876 48874 50271 49534 48875 48875 49539 50271 48875 48876 49539 48876 48880 49539 50287 49540 48877 48877 50286 50287 50966 50286 48877 48877 48878 50966 48878 50266 50966 49538 49537 48879 48879 48884 49538 48879 48883 48884 48880 48887 49539 49541 49540 48882 48890 48884 48883 49542 49538 48884 48884 48893 49542 48884 48890 48893 50277 48891 48885 48885 48886 50277 50976 50277 48886 48886 50971 50976 48886 50275 50971 48887 48888 49539 50276 49539 48888 50972 50276 48888 48888 50281 50972 48888 48905 50281 48890 48892 48893 50280 49550 48891 48891 50277 50280 48894 48893 48892 49543 49542 48893 48893 48894 49543 49545 49543 48894 48895 48903 48905 48909 48897 48896 49562 48909 48896 49569 49562 48896 49570 49569 48896 48909 48908 48897 49557 49549 48897 49558 49557 48897 48897 48908 49558 48898 48904 48906 48898 48903 48904 48898 48899 48903 48900 48899 48898 49552 48900 48898 48898 48914 49552 48898 48906 48914 49546 48903 48899 50977 49546 48899 48899 48900 50977 49552 49551 48900 50985 50977 48900 48900 50297 50985 48900 49551 50297 48901 49560 49561 51655 49560 48901 48901 48902 51655 48902 50975 51655 48902 49550 50975 49546 48905 48903 48905 49546 50281 48908 48909 50292 50291 49558 48908 50995 50291 48908 48908 50308 50995 48908 50292 50308 48909 49562 50292 49561 48915 48910 48911 50984 50988 48911 48912 50984 48913 48912 48911 50293 48913 48911 51675 50293 48911 48911 50989 51675 48911 50988 50989 48912 48915 49561 48912 48913 48915 48912 49559 50984 49561 49559 48912 50304 50303 48913 50996 50304 48913 48913 50293 50996 50303 48931 48913 48914 48916 49552 48916 49551 49552 49563 49551 48916 48916 48917 49563 48917 48922 49563 48934 48922 48917 48917 48918 48934 48919 48918 48917 48935 48934 48918 48918 48919 48935 48920 48921 49566 49571 48926 48920 48920 49566 49571 48934 48924 48922 49565 49563 48922 48922 48923 49565 48924 48923 48922 50296 49565 48923 48923 50295 50296 50305 50295 48923 48923 48924 50305 48924 49582 50305 48924 49581 49582 50316 49583 48925 48925 50310 50316 48925 48927 50310 49568 48927 48926 49571 49568 48926 48927 49567 50310 49568 49567 48927 50307 49570 48929 48929 48930 50307 48930 50306 50307 49572 48938 48932 49576 49572 48932 48932 48933 49576 48933 49574 49576 49575 49574 48933 50311 50306 48936 48937 48938 49572 49586 49585 48939 50317 49586 48939 48939 49583 50317 48942 48951 49584 48952 48951 48942 48953 48952 48942 48943 48956 48962 48958 48956 48943 50323 49588 48944 48944 49573 50323 48944 49572 49573 48945 50324 50325 50326 50324 48945 48945 49592 50326 49590 49589 48947 50327 49590 48947 48947 48948 50327 48948 50325 50327 48951 48952 49594 50322 49584 48951 48951 49594 50322 48952 48953 49594 48953 48959 49594 48955 48963 49598 48964 48963 48955 50337 48962 48956 48956 50336 50337 51021 50336 48956 48956 48957 51021 48958 48957 48956 48957 49585 49586 48957 48958 49585 51022 51021 48957 48957 51012 51022 48957 49586 51012 48959 49593 49594 48966 48961 48960 48961 48966 49603 49600 49593 48961 49603 49600 48961 50343 48967 48962 48962 50337 50343 49601 49598 48963 48963 48964 49601 50340 49601 48964 51715 50340 48964 48964 51057 51715 48964 50341 51057 48964 48969 50341 49605 49603 48966 49609 48971 48967 50343 49609 48967 49606 48969 48968 49607 49606 48968 49610 49607 48968 50342 50341 48969 48969 49606 50342 48977 48974 48970 49615 48976 48971 49616 49615 48971 48971 49609 49616 49611 48980 48973 49613 48975 48974 48974 48977 49613 49612 49605 48975 49613 49612 48975 48976 49615 49617 49614 49613 48977 49640 49622 48978 48978 49633 49640 48978 49620 49633 49624 49610 48979 49636 49635 48980 48980 49626 49636 48980 49618 49626 48980 49611 49618 48981 48982 48990 50350 49628 48981 50355 50350 48981 48981 49648 50355 48981 48990 49648 49636 48986 48983 48983 48984 49636 48984 49635 49636 48985 48986 49618 50359 49637 48985 48985 50351 50359 48985 49611 50351 49618 49611 48985 49626 49618 48986 49636 49626 48986 51092 48988 48987 48987 50371 51092 48987 49638 50371 48987 49637 49638 48988 48992 48993 51092 48992 48988 48991 48990 48989 48990 49647 49648 48990 48991 49647 48994 48993 48992 50380 48994 48992 50384 50380 48992 51096 50384 48992 48992 51094 51096 48992 51092 51094 48995 49003 49643 49643 49641 48995 48996 50382 50389 50383 50382 48996 49010 49005 48998 48998 48999 49010 49646 49010 48999 48999 49000 49646 51099 50390 49001 49001 50380 51099 50390 49002 49001 49651 49649 49002 50390 49651 49002 49003 49642 49643 49014 49011 49005 49005 49010 49014 49649 49007 49006 50398 49656 49007 49007 49649 50398 49655 49646 49008 50396 49655 49008 49008 49659 50396 49008 49009 49659 49666 49659 49009 49646 49014 49010 50405 49660 49011 49011 49014 50405 50411 49681 49012 50425 50411 49012 49012 50412 50425 49012 49656 50412 49663 49657 49013 49013 49661 49663 49014 50402 50405 49014 49654 50402 49655 49654 49014 49014 49646 49655 49660 49027 49015 49021 49017 49016 49016 49020 49021 50397 49647 49017 51103 50397 49017 49017 49021 51103 49681 49673 49018 49031 49023 49019 49019 49022 49031 49678 49021 49020 49021 50421 51103 50422 50421 49021 49021 49678 50422 49032 49031 49022 49023 49031 49668 49668 49667 49023 51108 49672 49024 49024 50429 51108 50430 50429 49024 49024 49033 50430 49024 49028 49033 49024 49025 49028 49679 49678 49026 50433 49679 49026 49026 49027 50433 49027 50420 50433 49027 50408 50420 49027 49660 50408 49031 49034 49668 49031 49032 49034 49033 50416 50430 49033 50415 50416 49034 49036 49675 49034 49035 49036 49675 49668 49034 49037 49687 49688 49038 49672 49687 50419 49677 49039 50435 50419 49039 49718 49692 49040 49040 49700 49718 49041 49673 49680 49042 49688 49691 49043 49045 49046 49043 49044 49045 49051 49045 49044 49694 49051 49044 49051 49046 49045 49046 49708 49709 49046 49050 49708 49051 49050 49046 49047 49704 49705 49047 49052 49704 49047 49048 49052 49048 49049 49680 49693 49052 49048 49048 49680 49693 50451 49708 49050 49050 49697 50451 49050 49051 49697 50437 49699 49051 49051 49696 50437 49051 49695 49696 49051 49694 49695 49699 49697 49051 49052 49693 49704 49053 49056 49059 50445 50444 49054 49054 49061 50445 49054 49060 49061 50457 49057 49055 49055 50456 50457 49055 49064 50456 49055 49063 49064 49056 49057 50457 49056 49058 49059 49703 49058 49056 50457 49703 49056 49061 49060 49058 49702 49061 49058 49703 49702 49058 51815 50445 49061 49061 50441 51815 50443 50441 49061 49061 49702 50443 49715 49701 49062 49720 49715 49062 49062 49067 49720 49065 49064 49063 50468 50456 49064 49064 49729 50468 49064 49065 49729 49065 49069 49729 49735 49722 49066 49066 49074 49735 49066 49073 49074 49722 49067 49066 49067 49719 49720 49722 49719 49067 49068 49723 49726 49069 49728 49729 49084 49076 49070 49726 49084 49070 49734 49081 49071 50473 49734 49071 49071 50469 50473 49071 49072 50469 50470 50469 49072 49072 49730 50470 49075 49074 49073 49082 49075 49073 49074 49075 49735 49075 49083 49735 49075 49082 49083 49077 49086 49739 49079 49078 49077 49739 49079 49077 49750 49740 49079 49079 49739 49750 49741 49086 49080 49080 49081 49741 49081 49734 49741 49742 49083 49082 49082 49090 49742 49742 49735 49083 49736 49092 49084 49084 49727 49736 49084 49726 49727 49767 49105 49085 49085 49098 49767 49741 49739 49086 49093 49090 49087 49087 49088 49093 49089 49088 49087 49095 49089 49087 49757 49093 49088 49768 49757 49088 49769 49768 49088 49088 49760 49769 49088 49089 49760 49089 49095 49096 49766 49760 49089 49089 49759 49766 49089 49096 49759 49090 49094 49742 49090 49093 49094 49096 49095 49091 50481 49744 49092 49092 49733 50481 49736 49733 49092 49758 49094 49093 49093 49757 49758 49752 49742 49094 49758 49752 49094 50492 49761 49097 51200 50492 49097 49097 51183 51200 49097 51182 51183 49097 50478 51182 49097 49098 50478 49099 49098 49097 49761 49099 49097 50491 49767 49098 49098 49099 50491 50505 50491 49099 51205 50505 49099 49099 49761 51205 49100 49103 49104 49100 49102 49103 49103 49102 49101 49756 49103 49101 50485 49756 49101 49101 49102 50485 49102 49755 50485 49107 49104 49103 49109 49107 49103 49765 49109 49103 49103 49756 49765 49762 49755 49106 49763 49762 49106 49107 49109 49111 49769 49766 49108 49771 49769 49108 49108 49112 49771 49772 49111 49109 50493 49772 49109 49109 49765 50493 49110 49111 49772 49112 49118 49771 49116 49114 49113 49113 49115 49116 50497 49116 49115 50502 50497 49115 50505 50502 49115 49115 49767 50505 50501 49774 49116 49116 50497 50501 50489 49763 49117 49117 49764 50489 49779 49771 49118 49118 49120 49779 49118 49119 49120 49122 49120 49119 49120 49122 49779 49786 49123 49121 49789 49786 49121 49121 49777 49789 49122 49126 49781 49122 49125 49126 49780 49779 49122 49781 49780 49122 49786 49124 49123 49134 49133 49124 49794 49134 49124 49124 49786 49794 49136 49126 49125 49125 49135 49136 49126 49136 49781 49138 49137 49127 49782 49138 49127 49128 51231 51885 49128 49129 51231 49130 49129 49128 49132 49130 49128 51878 49132 49128 51885 51878 49128 49129 49130 49140 49129 50520 51231 49129 49791 50520 49129 49140 49791 49132 49131 49130 49131 49132 50507 51878 50507 49132 49133 49155 49792 49133 49134 49155 49793 49155 49134 49794 49793 49134 49790 49781 49136 49137 49145 49146 49137 49141 49145 49137 49139 49141 49137 49138 49139 49138 49782 49788 49796 49139 49138 49138 49787 49796 49788 49787 49138 49796 49141 49139 49800 49791 49140 49140 49143 49800 49140 49142 49143 49157 49145 49141 49159 49157 49141 49805 49159 49141 50518 49805 49141 49141 49797 50518 49141 49796 49797 49143 49798 49800 49143 49146 49798 49149 49146 49145 49151 49149 49145 49157 49151 49145 49146 49149 49798 49147 49148 49804 49804 49795 49147 49148 49156 49804 49799 49798 49149 49806 49799 49149 49819 49806 49149 49149 49812 49819 49149 49150 49812 49151 49150 49149 49150 49158 49812 49150 49151 49158 49151 49157 49158 49155 49153 49152 49792 49155 49152 49155 49154 49153 49801 49161 49154 49154 49155 49801 49155 49793 49801 49809 49804 49156 49156 49162 49809 49159 49158 49157 49821 49812 49158 49158 49816 49821 49158 49160 49816 49158 49159 49160 49805 49160 49159 49817 49816 49160 49160 49805 49817 49165 49164 49161 49801 49165 49161 49811 49809 49162 49815 49811 49162 49173 49170 49164 49164 49166 49173 49164 49165 49166 49167 49166 49165 49171 49167 49165 49807 49171 49165 49165 49803 49807 49165 49801 49803 49822 49173 49166 50549 49822 49166 49166 49831 50549 49166 49824 49831 49166 49823 49824 49166 49167 49823 49167 49814 49823 49167 49171 49814 49834 49174 49168 49168 49183 49834 49178 49177 49169 49179 49178 49169 49169 49176 49179 49170 49172 49176 49173 49172 49170 49171 49813 49814 49171 49807 49813 49179 49176 49172 49835 49179 49172 49172 49830 49835 49172 49173 49830 49173 49822 49830 49834 49833 49174 49833 49175 49174 49175 49811 49815 49833 49811 49175 50562 49195 49177 49177 49178 50562 49178 49181 50562 49178 49179 49181 49835 49182 49179 49182 49181 49179 49849 49183 49180 49180 49188 49849 49189 49188 49180 51255 51254 49181 49181 49836 51255 49181 49182 49836 51916 50562 49181 49181 51254 51916 49182 49835 49836 49848 49834 49183 49849 49848 49183 50566 49851 49184 49184 50559 50566 49184 49185 50559 49185 49186 50559 49187 49186 49185 51262 50559 49186 49186 51257 51262 49186 51256 51257 49186 49187 51256 49187 50560 51256 49866 49849 49188 49867 49866 49188 49188 49189 49867 49189 49203 49867 49204 49203 49189 49198 49191 49190 49199 49198 49190 49856 49199 49190 49190 49855 49856 49190 49192 49855 49191 49198 49201 49192 49193 49855 49857 49855 49193 49193 49850 49857 50561 50560 49194 49194 49195 50561 50562 50561 49195 49196 49200 49206 49875 49201 49198 49198 49868 49875 49198 49199 49868 49877 49868 49199 49199 49856 49877 50568 49859 49202 49202 49870 50568 49202 49869 49870 49202 49209 49869 50573 49867 49203 49203 49876 50573 49203 49215 49876 49203 49205 49215 49203 49204 49205 49216 49205 49204 49204 49211 49216 49216 49215 49205 50587 49881 49206 49213 49210 49208 49208 49212 49213 49209 49210 49869 49883 49869 49210 49210 49213 49883 49219 49216 49211 49212 49218 50582 49212 49217 49218 50583 49213 49212 49212 50582 50583 50583 49883 49213 49224 49223 49214 49893 49876 49215 49215 49216 49893 49216 49886 49893 49216 49220 49886 49216 49219 49220 49218 49891 50582 49221 49220 49219 49220 49222 49886 49220 49221 49222 49226 49222 49221 49222 49226 49886 49223 50592 50611 49223 49224 50592 49224 49885 50592 49224 49884 49885 49231 49227 49225 49225 49229 49231 49892 49886 49226 49894 49892 49226 49226 49228 49894 49226 49227 49228 49240 49228 49227 49227 49231 49240 49228 49240 49894 49229 49230 49231 49232 49231 49230 49238 49232 49230 49239 49238 49230 49895 49240 49231 49231 49232 49895 50622 49895 49232 49232 49908 50622 49232 49238 49908 49233 49234 50614 49235 49234 49233 49244 49235 49233 49233 49241 49244 49243 49241 49233 50613 49243 49233 50614 50613 49233 49234 49235 49236 49234 49236 50614 49244 49237 49235 49237 49236 49235 49236 49901 50614 49903 49901 49236 49904 49903 49236 49236 49237 49904 49237 49244 49904 49909 49908 49238 49238 49239 49909 49239 49258 49909 49895 49894 49240 49241 49242 49249 49243 49242 49241 49254 49244 49241 49255 49254 49241 49241 49247 49255 49249 49247 49241 49242 49897 49900 50612 49897 49242 49242 49243 50612 49900 49249 49242 50613 50612 49243 49244 49253 49904 49246 49898 49899 49900 49898 49246 49246 49249 49900 49246 49247 49249 49248 49247 49246 49899 49248 49246 49247 49251 49255 49252 49251 49247 49247 49248 49252 49899 49252 49248 49912 49910 49252 49252 49899 49912 49253 49256 49904 49257 49256 49253 49256 49257 50618 49905 49904 49256 50617 49905 49256 50618 50617 49256 49924 49909 49258 49258 49916 49924 50629 49925 49259 49932 49261 49260 49933 49932 49260 49260 49925 49933 49263 49932 49933 49940 49266 49263 49941 49940 49263 49263 49937 49941 49263 49933 49937 49264 49265 49936 49265 49935 49936 49265 49926 49935 49940 49267 49266 49267 49942 49943 49267 49940 49942 49947 49273 49268 49268 49272 49947 49268 49271 49272 50637 49949 49269 49269 49946 50637 49270 49949 49951 49953 49284 49270 49960 49953 49270 49961 49960 49270 49270 49951 49961 49274 49272 49271 49272 49274 49947 49947 49939 49273 49956 49947 49274 49957 49279 49275 49958 49957 49275 49959 49958 49275 49275 49276 49959 49276 49277 49959 49277 49280 49959 49278 49955 49956 50659 49955 49278 49278 49286 50659 51357 49959 49280 52022 51357 49280 49280 51362 52022 49280 51361 51362 49280 49964 51361 49280 49281 49964 49966 49964 49281 49281 49283 49966 49966 49283 49282 49967 49966 49282 49953 49952 49284 49285 49968 49969 50667 49967 49287 49287 49973 50667 49287 49972 49973 49289 49293 49972 49975 49294 49290 49290 49971 49975 50676 49972 49293 51380 50676 49293 49293 49296 51380 49293 49295 49296 49974 49295 49294 49975 49974 49294 50677 49296 49295 49295 49970 50677 49971 49970 49295 49974 49971 49295 52037 51380 49296 49296 50677 52037 50675 49984 49298 51369 50675 49298 49298 49980 51369 50693 49302 49299 49299 49992 50693 49299 49985 49992 50000 49305 49300 49300 49998 50000 49300 49301 49998 49302 49301 49300 49999 49998 49301 50693 49999 49301 49301 49302 50693 50006 49306 49304 50701 50006 49304 49304 50700 50701 49304 49305 50700 49305 50000 50700 50006 50001 49306 50001 49309 49307 49308 49309 50007 50007 49310 49308 49309 50702 50704 49309 50001 50702 50704 50007 49309 49321 49320 49310 50007 49321 49310 49312 49322 50012 49323 49322 49312 49312 49313 49323 49324 49323 49313 49314 49323 49324 50011 49323 49314 50013 50011 49314 50015 50013 49314 50016 50015 49314 49314 50010 50016 49314 49315 50010 49315 49316 50010 50018 50014 49317 49317 49318 50018 50021 50018 49318 49332 49327 49320 50705 49332 49320 49320 49321 50705 49321 50008 50705 49321 50007 50008 49322 49329 50012 50011 49329 49322 49322 49323 50011 50028 50022 49325 49325 50026 50028 49336 49331 49326 50708 50706 49328 49328 49333 50708 49335 49333 49328 50025 49330 49329 50030 50025 49329 49329 50011 50030 49340 49339 49330 50025 49340 49330 49331 50023 50027 49331 49336 50023 50024 50023 49332 50707 50024 49332 49332 50705 50707 51407 50708 49333 51419 51407 49333 49333 49334 51419 49335 49334 49333 49334 50709 51434 49334 49335 50709 51426 51419 49334 51434 51426 49334 49335 50029 50709 49337 49338 50039 49339 49340 50046 50046 49348 49339 50719 50059 49340 49340 50031 50719 50711 50031 49340 49340 50025 50711 50059 50046 49340 50062 50053 49341 49341 50037 50062 50053 49342 49341 50058 49355 49342 49342 50053 50058 50054 49351 49346 50055 50054 49346 50046 49354 49348 49349 49350 50717 49351 49350 49349 51452 51447 49350 49350 50743 51452 49350 50054 50743 49350 49351 50054 51447 50717 49350 49352 49354 50738 50738 49353 49352 50750 50060 49353 49353 50749 50750 49353 50738 50749 49354 50727 50738 49354 50059 50727 49354 50046 50059 50069 49393 49358 50064 49361 49360 49360 49370 50064 50057 50056 49361 50759 50057 49361 49361 50065 50759 49361 50064 50065 50760 50064 49362 49362 49363 50760 49364 49363 49362 50064 49364 49362 50784 50760 49363 49363 50074 50784 49363 49364 50074 49364 50073 50074 49364 49370 50073 50064 49370 49364 49365 49373 49381 49374 49373 49365 50780 49374 49365 49365 50779 50780 49365 50071 50779 49365 49383 50071 49367 49366 49365 49381 49367 49365 49376 49375 49366 49366 49367 49376 50068 49376 49367 49367 49381 50068 50766 49369 49368 49368 50762 50766 49368 50063 50762 50792 50077 49369 49369 50763 50792 50766 50763 49369 49371 50061 50774 50775 50066 49372 49372 50075 50775 50748 49381 49373 51482 50748 49373 49373 49374 51482 49374 50780 51482 50070 49380 49375 49375 49376 50070 50758 50070 49376 49376 50067 50758 50068 50067 49376 50781 50771 49377 49377 50081 50781 50085 49385 49378 49378 50083 50085 49378 49379 50083 50777 50083 49379 49379 50082 50777 49379 49380 50082 49380 50070 50082 49381 50067 50068 50745 50067 49381 50746 50745 49381 50747 50746 49381 50748 50747 49381 50778 50071 49382 49382 50076 50778 49382 49387 50076 50071 49383 49382 49397 49396 49384 49384 49396 50075 50085 49389 49385 49391 49387 49386 50084 50076 49387 49387 49391 50084 49400 49394 49388 50803 49400 49388 50099 50093 49390 49392 49391 49390 50093 49392 49390 49391 49392 50084 50789 50084 49392 50791 50789 49392 51534 50791 49392 49392 50093 51534 49393 50072 50086 49393 50069 50072 49400 49395 49394 50101 49399 49395 49395 49400 50101 51513 50075 49396 49396 49397 51513 49398 50813 51520 50102 50101 49400 50803 50102 49400 49401 49426 49427 50138 49426 49401 50840 50138 49401 49401 49402 50840 49403 49402 49401 50092 49403 49401 51541 50840 49402 49402 50824 51541 49402 49403 50824 51537 50824 49403 49403 50811 51537 49403 50092 50811 49405 49406 50100 50826 50100 49406 49406 50110 50826 49408 49409 50120 49409 49416 50120 50832 50115 49411 49411 50128 50832 49411 49412 50128 50139 50128 49412 49415 49414 49413 49425 49415 49413 50116 49425 49413 50117 50116 49413 50121 50120 49416 49416 49419 50121 49417 49430 50142 49419 49418 49417 49429 49419 49417 50142 49429 49417 49418 49419 49420 50148 50121 49419 49419 50141 50148 49419 49429 50141 49421 49422 50833 50142 49430 49421 50833 50142 49421 49422 49423 50833 50835 50833 49423 51540 50835 49423 49423 50122 51540 49425 50116 50845 50138 49431 49426 49428 50851 50852 50154 50141 49429 50836 50154 49429 49429 50142 50836 50162 49432 49431 50848 50162 49431 49431 50138 50848 50162 50151 49432 49434 49436 49443 49443 49435 49434 50846 50130 49435 50871 50846 49435 49435 50868 50871 49435 50860 50868 49435 50160 50860 49435 49443 50160 50153 50152 49437 50850 50153 49437 49437 50849 50850 49437 49440 50849 50156 49443 49438 49462 49440 49439 50854 50849 49440 49440 50187 50854 49440 49462 50187 49441 49444 50159 49443 50156 50160 50175 50159 49444 50170 49446 49445 50171 50170 49445 50172 50171 49445 50179 49448 49447 49447 50174 50179 49447 50173 50174 49447 50164 50173 50179 49460 49448 49454 49450 49449 50172 49452 49451 50181 50172 49451 49451 49458 50181 50884 49463 49453 49453 50166 50884 49455 49471 49472 50879 50168 49456 49456 50190 50879 49456 49457 50190 50195 50190 49457 49457 50194 50195 49457 49473 50194 50182 50181 49458 49458 49459 50182 50183 50182 49459 49459 49460 50183 50192 50183 49460 49460 50179 50192 50188 50187 49461 50881 50188 49461 49461 50880 50881 49461 50189 50880 50187 49462 49461 50887 49464 49463 49463 50884 50887 49464 50887 50898 50177 49467 49465 50191 50177 49465 49465 50180 50191 50202 50196 49466 49466 49485 50202 50212 49485 49466 49466 49467 50212 49467 50211 50212 50892 50211 49467 49467 50177 50892 50196 49469 49468 50202 49470 49469 49469 50196 50202 50213 50205 49470 49470 50203 50213 50204 50203 49470 49470 50202 50204 50198 49472 49471 51596 50201 49472 49472 51595 51596 49472 50198 51595 50206 50197 49474 49475 49476 50907 49477 49476 49475 49478 49477 49475 49490 49478 49475 49496 49490 49475 50207 49496 49475 50907 50207 49475 49476 49477 50906 49476 50906 50907 49477 49478 49479 49477 49479 50906 49489 49480 49478 49490 49489 49478 49480 49479 49478 50909 50906 49479 49479 50208 50909 49479 49485 50208 49479 49481 49485 49479 49480 49481 49480 49489 50221 49482 49481 49480 49498 49482 49480 50221 49498 49480 49481 49483 49485 49484 49483 49481 49481 49482 49484 49491 49484 49482 49498 49491 49482 49486 49485 49483 49483 49484 49486 49487 49486 49484 49491 49487 49484 50210 50208 49485 50212 50210 49485 49485 49486 50202 49486 49488 50202 49486 49487 49488 49492 49488 49487 49487 49491 49492 50204 50202 49488 49488 49492 50204 49489 49495 50221 49489 49490 49495 49496 49495 49490 50223 49492 49491 49491 50218 50223 49491 49498 50218 50214 50204 49492 50223 50214 49492 50912 50206 49494 49494 50230 50912 50931 50930 49495 49495 50227 50931 49495 50226 50227 49495 49497 50226 49495 49496 49497 50917 50221 49495 50930 50917 49495 50217 49497 49496 49496 50207 50217 49497 50220 50226 49497 50217 50220 50222 50218 49498 49498 50221 50222 50932 49506 49499 50933 50932 49499 49499 49500 50933 49500 50229 50927 49500 49501 50229 49500 50927 50933 49502 49503 50237 49503 49504 50237 49505 49504 49503 49504 50932 51621 49504 49506 50932 49504 49505 49506 50238 50237 49504 51622 50238 49504 49504 51621 51622 49508 50227 50236 50931 50227 49508 49508 50930 50931 50239 49510 49509 50250 50239 49509 49509 49512 50250 49522 49513 49511 49512 50243 50250 49512 50240 50243 49512 49514 50240 49521 49515 49513 49522 49521 49513 49514 49520 50240 49514 49519 49520 49515 49521 49524 49523 49516 49515 49524 49523 49515 49516 49523 49525 50245 49518 49517 49517 50244 50245 50241 49520 49518 50242 50241 49518 50245 50242 49518 50936 50240 49520 49520 50241 50936 49528 49524 49521 50246 49528 49521 49521 49522 50246 50935 50246 49522 49522 50239 50935 50252 49525 49523 50258 50252 49523 49523 49529 50258 49523 49524 49529 49524 49528 49529 50950 50248 49526 50261 50251 49527 50938 50261 49527 49527 50246 50938 49527 49528 50246 49529 49528 49527 50251 49529 49527 50259 50258 49529 49529 50253 50259 49529 50251 50253 49530 50254 50256 50968 50967 49533 49533 49538 50968 49533 49537 49538 50269 49535 49534 50959 50269 49534 49534 50271 50959 50268 49536 49535 50269 50268 49535 49538 50278 50968 49538 49544 50278 49538 49542 49544 50276 50271 49539 49542 49543 49544 49545 49544 49543 49544 49548 50278 49544 49545 49548 49549 49548 49545 50283 50281 49546 50284 50283 49546 50977 50284 49546 49556 49553 49547 49547 49555 49556 49548 49557 49558 49548 49549 49557 50279 50278 49548 49548 49558 50279 49550 50280 50975 49551 49564 50297 49551 49563 49564 50298 49566 49553 50299 50298 49553 50300 50299 49553 49553 49556 50300 49554 50974 51643 49554 49555 50974 49556 49555 49554 50290 49556 49554 51643 50290 49554 49556 50288 50300 50290 50288 49556 50291 50279 49558 49559 49560 50984 49561 49560 49559 51655 50984 49560 49562 49569 50292 49565 49564 49563 49564 49565 50296 49564 50294 50297 50296 50294 49564 50298 49571 49566 52285 50310 49567 49567 51663 52285 49567 49568 51663 49568 49571 51663 49569 49570 50292 50307 50292 49570 49571 50301 51663 49571 50298 50301 49574 49573 49572 49576 49574 49572 51016 50323 49573 49573 51000 51016 49573 49574 51000 49574 49575 51000 49575 49577 51674 51673 51000 49575 51674 51673 49575 49577 49578 51674 49578 50313 51674 50996 50293 49579 49579 50304 50996 49579 50293 50312 49580 49581 50318 49582 49581 49580 50318 49582 49580 50997 50305 49582 49582 50318 50997 49583 50314 50317 50316 50314 49583 50322 50319 49584 49586 50317 51012 49587 49595 50320 49596 49595 49587 49587 49591 49596 50326 49592 49588 49588 50323 50326 49589 49597 49602 49589 49590 49597 50333 49597 49590 49590 50332 50333 49590 50327 50332 49598 49596 49591 49599 49594 49593 49600 49599 49593 51028 50322 49594 51711 51028 49594 49594 49599 51711 51033 50320 49595 49595 50331 51033 49595 49596 50331 49596 49598 50331 50335 49602 49597 49597 50333 50335 49598 49601 50331 52317 51711 49599 49599 51051 52317 49599 49600 51051 51059 51051 49600 49600 49603 51059 51037 50331 49601 49601 50340 51037 49602 50335 50338 51065 51059 49603 49603 50352 51065 50353 50352 49603 50358 50353 49603 49603 49604 50358 49605 49604 49603 49604 49619 50358 49604 49612 49619 49604 49605 49612 49606 49607 51062 52331 50342 49606 52344 52331 49606 49606 51062 52344 49607 49610 49625 49607 49625 51062 50348 50344 49608 49608 50347 50348 49608 50338 50347 51054 49616 49609 49609 50343 51054 49610 49624 49625 49611 50344 50351 49612 49613 49619 49627 49619 49613 49613 49614 49627 50349 49627 49614 50350 50349 49614 49614 49628 50350 49615 49616 50354 50354 49617 49615 51052 50354 49616 51053 51052 49616 51054 51053 49616 51072 49632 49617 49617 51052 51072 49617 50354 51052 50364 50358 49619 49619 49627 50364 49620 49629 49633 49634 49629 49620 49625 49624 49621 51062 49625 49621 49621 49623 51062 49621 49622 49623 51734 49623 49622 49622 49640 51734 52351 51062 49623 49623 51734 52351 49627 50349 50364 50366 49633 49629 49629 49630 50366 49631 49630 49629 49634 49631 49629 50369 50366 49630 49630 49631 50369 51080 50369 49631 49631 51079 51080 49631 51072 51079 49631 49632 51072 49633 50366 50370 50370 49640 49633 49639 49638 49637 50360 49639 49637 50361 50360 49637 49637 50359 50361 50372 50371 49638 49638 50367 50372 49638 49639 50367 49639 50362 50367 50363 50362 49639 49639 50360 50363 51739 51734 49640 49640 50370 51739 49641 49643 50381 50385 49643 49642 50392 50385 49642 49642 49652 50392 50385 50381 49643 49644 49645 49653 49664 49653 49645 50388 49664 49645 50397 49648 49647 50357 50355 49648 50397 50357 49648 49649 49650 50398 49651 49650 49649 51104 50398 49650 51105 51104 49650 51772 51105 49650 49650 51106 51772 49650 49651 51106 49651 51100 51106 49651 50390 51100 50393 50392 49652 49652 50391 50393 49652 49658 50391 49654 50396 50402 49654 49655 50396 50413 50412 49656 51113 50413 49656 49656 50398 51113 50407 50399 49657 49657 49663 50407 50402 50396 49659 49659 50400 50402 50401 50400 49659 49659 49666 50401 50410 50408 49660 49660 50405 50410 50406 49663 49661 49661 49669 50406 49661 49662 49669 49674 49669 49662 49662 49668 49674 50414 50407 49663 50423 50414 49663 49663 50406 50423 50394 49665 49664 49664 50389 50394 49664 50388 50389 50395 49671 49665 49665 50394 50395 50404 50401 49666 49666 49676 50404 49675 49674 49668 49669 49674 50406 49670 49671 50417 50417 50415 49670 49671 51114 51776 49671 51112 51114 49671 50395 51112 51776 50417 49671 50428 49687 49672 49672 50424 50428 49672 49689 50424 49690 49689 49672 51108 49690 49672 49682 49680 49673 49673 49681 49682 49674 49683 50406 49674 49675 49683 50419 50404 49676 49676 49677 50419 49678 49679 50422 51120 50422 49679 51126 51120 49679 49679 50433 51126 50434 49693 49680 49680 49682 50434 50426 49682 49681 49681 50411 50426 49682 50426 50434 50428 50406 49683 49683 49684 50428 49684 49685 50428 49686 49685 49684 49688 49686 49684 49691 49688 49684 49685 49687 50428 49685 49686 49687 49688 49687 49686 49689 49690 51109 49689 50423 50424 49689 50414 50423 49689 50399 50414 51107 50399 49689 51109 51107 49689 49690 51108 51109 51131 50435 49692 49692 49718 51131 49706 49704 49693 50434 49706 49693 51129 49696 49695 51130 51129 49695 51134 51130 49695 51816 50437 49696 49696 51807 51816 49696 51129 51807 51147 50451 49697 49697 49698 51147 49699 49698 49697 51830 51147 49698 49698 51816 51830 49698 49699 51816 49699 50437 51816 50458 50453 49700 49700 49701 50458 50452 49718 49700 50453 50452 49700 49701 49716 50458 49701 49715 49716 49702 49703 50443 50450 50443 49703 50459 50450 49703 49703 50457 50459 49707 49705 49704 50447 49707 49704 49704 50438 50447 49704 49706 50438 49712 49711 49705 49705 49707 49712 50439 50438 49706 49706 50436 50439 49706 50434 50436 50447 49712 49707 49710 49709 49708 50451 49710 49708 49710 49713 49725 49714 49713 49710 50451 49714 49710 49724 49723 49711 49711 49712 49724 50454 49724 49712 49712 50448 50454 49712 50447 50448 49730 49725 49713 50470 49730 49713 49713 49714 50470 51153 50470 49714 49714 51151 51153 51152 51151 49714 51830 51152 49714 49714 51147 51830 49714 50451 51147 49715 49721 51163 49715 49719 49721 49720 49719 49715 49717 49716 49715 51163 49717 49715 50461 50458 49716 50466 50461 49716 49716 49717 50466 51165 50466 49717 51171 51165 49717 51172 51171 49717 49717 51163 51172 51145 51131 49718 49718 50452 51145 49722 49721 49719 49721 49722 51164 51164 51163 49721 49722 49735 51164 49727 49726 49723 49723 49724 49727 49732 49727 49724 50454 49732 49724 49727 49733 49736 49727 49731 49733 49732 49731 49727 49748 49729 49728 49728 49737 49748 49729 49748 50468 51174 49733 49731 51853 51174 49731 49731 51175 51853 49731 51169 51175 49731 50467 51169 49731 49732 50467 49732 50454 50467 51174 50481 49733 50473 49741 49734 49735 49742 50472 49735 50471 51164 50472 50471 49735 49749 49748 49737 49737 49738 49749 51854 49749 49738 49738 50475 51854 51843 51160 49739 49739 51170 51843 49739 49741 51170 51159 49750 49739 51160 51159 49739 50480 50479 49740 51176 50480 49740 51181 51176 49740 49740 49751 51181 49740 49750 49751 49741 50473 51170 49742 49752 51177 51177 50472 49742 50481 49753 49743 49743 49744 50481 49747 49746 49745 50484 49747 49745 49745 50483 50484 49745 49754 50483 49746 49747 50477 49747 51870 52505 49747 50484 51870 49747 50476 50477 51871 50476 49747 52507 51871 49747 49747 52506 52507 49747 52505 52506 51157 50468 49748 51851 51157 49748 49748 49749 51851 52490 51851 49749 49749 51854 52490 51159 49751 49750 52491 51181 49751 49751 51867 52491 49751 51852 51867 49751 51844 51852 49751 51843 51844 49751 51159 51843 49752 49758 50486 49752 50486 51177 50482 49754 49753 50488 50482 49753 49753 50481 50488 49754 50482 50483 51185 50485 49755 49755 50489 51185 49755 49762 50489 50493 49765 49756 51185 50493 49756 49756 50485 51185 50490 49758 49757 50495 50490 49757 49757 49768 50495 50490 50487 49758 50487 50486 49758 49760 49766 49769 49761 50492 51205 49762 49763 50489 49764 49784 50489 49767 50491 50505 49768 49770 50500 49773 49770 49768 49768 49769 49773 50499 50495 49768 50500 50499 49768 49769 49770 49773 49771 49770 49769 49770 49771 49779 49770 49779 50500 50498 49778 49772 49772 50494 50498 49772 50493 50494 49774 49782 49783 49788 49782 49774 51217 49788 49774 49774 50501 51217 49775 49786 49789 49802 49786 49775 49808 49802 49775 49775 49776 49808 49777 49776 49775 49789 49777 49775 50509 49808 49776 51223 50509 49776 49776 49777 51223 49777 50523 51223 49777 50522 50523 49777 50498 50522 49777 49778 50498 50504 50500 49779 49779 49780 50504 50506 50504 49780 49780 49790 50506 49780 49781 49790 51196 50489 49784 52514 51196 49784 49784 49785 52514 49785 51873 52518 51874 51873 49785 49785 50508 51874 49785 50507 50508 52516 52514 49785 52519 52516 49785 49785 52517 52519 52518 52517 49785 49802 49794 49786 50515 49796 49787 51216 50515 49787 49787 49788 51216 51217 51216 49788 50513 50506 49790 50514 50513 49790 50516 50514 49790 49790 49795 50516 49791 50519 50520 49791 49800 50519 49802 49801 49793 49793 49794 49802 49795 49804 50516 50515 49797 49796 51228 50518 49797 49797 51226 51228 49797 50515 51226 49798 49799 49800 50519 49800 49799 50536 50519 49799 49799 50534 50536 49799 49806 50534 49801 49802 49803 49807 49803 49802 49808 49807 49802 49804 50514 50516 50527 50514 49804 49804 49809 50527 50531 49817 49805 50533 50531 49805 49805 50517 50533 50518 50517 49805 49806 49820 50534 49806 49819 49820 50528 49813 49807 49807 50509 50528 49807 49808 50509 49809 49810 50527 49811 49810 49809 50530 50527 49810 49810 49826 50530 49828 49826 49810 49829 49828 49810 49810 49811 49829 49833 49829 49811 49821 49819 49812 49823 49814 49813 50529 49823 49813 49813 50510 50529 50528 50510 49813 49816 49818 49821 49816 49817 49818 50546 49818 49817 49817 50531 50546 50546 49821 49818 50553 49820 49819 49819 50552 50553 50556 50552 49819 49819 49821 50556 50547 50534 49820 50553 50547 49820 51245 50556 49821 49821 50546 51245 50558 49830 49822 51240 50558 49822 49822 50549 51240 50529 49824 49823 49824 50529 51232 51889 49831 49824 49824 51888 51889 49824 51232 51888 49842 49839 49825 49825 49829 49842 49832 49829 49825 49825 49826 49832 49827 49826 49825 49839 49827 49825 49826 49828 49832 50542 50530 49826 49826 49840 50542 49826 49827 49840 49827 49839 49840 49828 49829 49832 49829 49833 49842 49837 49835 49830 50558 49837 49830 49831 50548 50549 51889 50548 49831 49833 49834 49842 49848 49842 49834 49837 49836 49835 49836 49838 51255 49836 49837 49838 50558 49838 49837 51909 51255 49838 49838 51247 51909 49838 50558 51247 49844 49843 49839 49847 49844 49839 49839 49842 49847 49841 49840 49839 49843 49841 49839 50557 50542 49840 49840 49841 50557 49841 50555 50557 51251 50555 49841 49841 49843 51251 49853 49847 49842 49842 49848 49853 51253 51251 49843 49843 49846 51253 49843 49844 49846 49844 49845 49846 49852 49845 49844 49844 49847 49852 49845 49852 49865 49865 49846 49845 51259 51253 49846 49846 50563 51259 49846 49865 50563 49853 49852 49847 49866 49853 49848 49848 49849 49866 51260 49857 49850 49850 50567 51260 49850 49851 50567 49851 50566 50567 49866 49865 49852 49852 49853 49866 49856 49855 49854 50564 49856 49854 50565 50564 49854 49854 49857 50565 49854 49855 49857 50564 49877 49856 51260 50565 49857 49858 49860 49863 50568 49860 49858 49858 49859 50568 50594 49872 49860 51266 50594 49860 49860 49861 51266 49862 49861 49860 49873 49862 49860 49874 49873 49860 50568 49874 49860 49872 49863 49860 51936 50593 49861 49861 49864 51936 49861 49862 49864 49861 50593 51266 52577 49864 49862 49862 52576 52577 49862 49873 52576 52577 51936 49864 50575 50563 49865 50576 50575 49865 50585 50576 49865 49865 50573 50585 49865 49866 50573 49866 49867 50573 49890 49875 49868 49868 49878 49890 49868 49877 49878 49871 49870 49869 50578 49871 49869 49869 50577 50578 49869 49883 50577 50570 50568 49870 49870 49871 50570 51924 50570 49871 49871 50578 51924 50594 49884 49872 49873 50569 52576 49873 49874 50569 49874 50568 50569 49890 49888 49875 49876 49893 50573 50574 49878 49877 49877 50564 50574 49878 49887 49890 50608 49887 49878 49878 50574 50608 49882 49881 49879 50600 49880 49879 49879 49881 50600 49880 50600 51276 49881 50587 50600 50584 50577 49883 49883 50583 50584 50602 49885 49884 51278 50602 49884 49884 50593 51278 50594 50593 49884 51282 50592 49885 51289 51282 49885 49885 51287 51289 49885 50602 51287 50572 49893 49886 50604 50572 49886 49886 49892 50604 49887 49888 49890 49889 49888 49887 50608 49889 49887 50598 50588 49888 49888 49889 50598 49889 50597 50598 51281 50597 49889 49889 50608 51281 49892 49894 50604 49893 50572 50573 50620 50604 49894 49894 50605 50620 49894 49895 50605 50622 50605 49895 51966 51303 49896 51967 51966 49896 49896 51297 51967 49896 49906 51297 49896 49897 49906 49898 49897 49896 51303 49898 49896 50612 49906 49897 49897 49898 49900 49912 49899 49898 49898 49911 49912 51304 49911 49898 49898 51303 51304 51957 50614 49901 49901 49902 51957 49903 49902 49901 50616 50615 49902 50617 50616 49902 49902 49905 50617 49902 49903 49905 49902 51288 51957 49902 51287 51288 49902 50615 51287 49903 49904 49905 49906 51284 51297 49906 50612 51284 50619 50618 49907 49907 50611 50619 50623 50622 49908 49908 49921 50623 49924 49921 49908 49908 49909 49924 49915 49914 49910 49910 49911 49915 49912 49911 49910 50624 49915 49911 51976 50624 49911 49911 51304 51976 50624 49917 49913 49913 49915 50624 49913 49914 49915 49916 49920 49924 49929 49920 49916 49931 49929 49916 51994 51311 49917 49917 50624 51994 49918 49925 50629 49937 49925 49918 50631 49937 49918 49936 49935 49919 49919 49920 49936 49921 49920 49919 49935 49921 49919 49920 49921 49924 49921 50621 50623 49921 49935 50621 49922 49929 49931 49930 49929 49922 49922 49923 49930 49937 49933 49925 49926 49927 49935 49928 49927 49926 50621 49935 49927 49927 49938 50621 49927 49928 49938 49928 49934 49938 49934 50638 50639 49934 49939 50638 51321 49938 49934 51325 51321 49934 49934 50639 51325 50631 49941 49937 50628 50621 49938 51320 50628 49938 51321 51320 49938 49939 49948 50638 49939 49947 49948 49940 49941 49942 50631 49942 49941 50632 49943 49942 49942 50631 50632 50635 49944 49943 49943 50632 50635 50636 49945 49944 51326 50636 49944 49944 50635 51326 50636 49946 49945 49946 50636 50637 49950 49948 49947 49956 49950 49947 50639 50638 49948 51337 50639 49948 51344 51337 49948 49948 49950 51344 49949 50637 50640 50640 49951 49949 51346 51344 49950 49950 49954 51346 49956 49954 49950 51350 49961 49951 49951 51330 51350 49951 50640 51330 50657 49968 49952 49952 50652 50657 49952 49963 50652 49952 49953 49963 49953 49960 49963 49954 51345 51346 49954 50654 51345 49954 49955 50654 49956 49955 49954 51359 50654 49955 49955 50659 51359 50655 49962 49957 49957 49958 50655 51357 51356 49958 49958 49959 51357 51355 50655 49958 51356 51355 49958 50641 49963 49960 50650 50641 49960 49960 49961 50650 51350 50650 49961 51360 49979 49962 49962 50656 51360 49962 50655 50656 49963 50651 50652 49963 50641 50651 49964 49965 51361 49966 49965 49964 52031 51361 49965 52036 52031 49965 49965 51368 52036 49965 49966 51368 51370 51368 49966 49966 50667 51370 49966 49967 50667 50657 49969 49968 49969 49970 49971 50658 49970 49969 49969 50657 50658 52037 50677 49970 49970 51363 52037 49970 50658 51363 49971 49974 49975 50676 49973 49972 50668 50667 49973 51379 50668 49973 49973 50676 51379 49982 49981 49976 50666 49982 49976 49976 49977 50666 49978 49977 49976 49981 49978 49976 49977 50665 50666 50673 50665 49977 51375 50673 49977 49977 49991 51375 49977 49978 49991 49996 49991 49978 49978 49988 49996 49978 49981 49988 51369 49980 49979 52035 51369 49979 49979 51360 52035 49981 49987 49988 49981 49986 49987 49981 49982 49986 50666 50665 49982 50672 49986 49982 49982 50663 50672 50665 50663 49982 50675 49985 49983 49983 49984 50675 50675 49992 49985 50681 49987 49986 49986 50669 50681 50672 50669 49986 50682 50003 49987 50683 50682 49987 49987 50681 50683 49995 49988 49987 50003 49995 49987 49997 49996 49988 49988 49995 49997 49989 51374 51375 52048 51374 49989 52684 52048 49989 49989 49990 52684 49991 49990 49989 51375 49991 49989 49990 49991 52684 49991 52053 52684 49991 50691 52053 49991 49996 50691 51387 50693 49992 49992 51376 51387 51383 51376 49992 49992 50675 51383 49993 49994 50686 50687 50686 49994 51385 50687 49994 49994 50694 51385 50005 49997 49995 49995 50004 50005 49995 50003 50004 49996 50005 50691 49996 49997 50005 51392 50000 49998 49998 49999 51392 49999 51387 51392 49999 50693 51387 51392 50700 50000 50703 50702 50001 50001 50701 50703 50001 50006 50701 50002 50695 51402 50002 50682 50695 50002 50003 50682 50004 50003 50002 51403 50004 50002 50002 51402 51403 51411 50005 50004 50004 51410 51411 50004 51404 51410 50004 51403 51404 50692 50691 50005 50696 50692 50005 50697 50696 50005 51411 50697 50005 50009 50008 50007 51396 50009 50007 51397 51396 50007 50007 50704 51397 51412 50705 50008 50008 51406 51412 50008 50009 51406 52060 51406 50009 50009 51396 52060 50040 50016 50010 50041 50040 50010 50718 50041 50010 50010 50017 50718 50031 50030 50011 50032 50031 50011 50011 50013 50032 50047 50032 50013 50013 50015 50047 50043 50017 50014 50014 50018 50043 50048 50047 50015 50015 50016 50048 50016 50040 50048 50017 50042 50718 50043 50042 50017 50732 50043 50018 50018 50021 50732 50724 50021 50019 50019 50050 50724 50019 50020 50050 50020 50022 50050 50021 50724 50732 50051 50050 50022 50022 50028 50051 50033 50027 50023 50035 50033 50023 50710 50035 50023 50023 50024 50710 50024 50707 50710 50025 50030 50711 50044 50028 50026 50026 50034 50044 50026 50033 50034 50026 50027 50033 50052 50051 50028 50028 50044 50052 50030 50031 50711 50031 50032 50719 50720 50719 50032 50032 50047 50720 51449 50034 50033 52065 51449 50033 50033 51448 52065 50033 50035 51448 51449 50044 50034 50035 50710 51448 51434 50709 50036 51435 51434 50036 51440 51435 50036 51441 51440 50036 50036 50045 51441 50712 50062 50037 50713 50712 50037 50037 50038 50713 50715 50713 50038 50038 50714 50715 50038 50039 50714 50716 50714 50039 50049 50048 50040 50722 50049 50040 50040 50041 50722 50041 50718 50722 50723 50718 50042 51458 50723 50042 50042 50043 51458 51466 51458 50043 50043 50732 51466 51468 50052 50044 50044 51461 51468 50044 51449 51461 50045 50737 51441 50729 50720 50047 50047 50728 50729 50047 50048 50728 50730 50728 50048 50048 50049 50730 50740 50730 50049 50049 50731 50740 50049 50722 50731 50733 50724 50050 50735 50733 50050 50050 50051 50735 50736 50735 50051 50051 50725 50736 50051 50052 50725 51468 50725 50052 50062 50058 50053 50054 50742 50743 50054 50055 50742 50755 50742 50055 51481 50726 50057 50057 50751 51481 50752 50751 50057 50759 50752 50057 50753 50061 50058 51495 50753 50058 50058 50062 51495 50059 50719 51462 51462 50727 50059 50762 50063 50060 50060 50750 50762 50061 50753 50774 50062 51469 51495 51471 51469 50062 50062 50712 51471 50760 50065 50064 50065 50752 50759 51492 50752 50065 50065 51491 51492 50065 50760 51491 50066 50754 50755 50066 50090 50754 50775 50090 50066 50067 50745 50758 50756 50082 50070 50758 50756 50070 50071 50778 50779 50782 50086 50072 50072 50771 50782 51508 50074 50073 50073 50785 51508 50073 50783 50785 51507 50784 50074 51508 51507 50074 51513 50775 50075 51526 50778 50076 50076 50789 51526 50076 50084 50789 50077 50078 50080 50079 50078 50077 50792 50079 50077 52126 50796 50078 50078 50079 52126 52791 52126 50079 50079 52790 52791 50079 52779 52790 50079 50793 52779 50079 50792 50793 50081 50773 50781 50797 50773 50081 50081 50795 50797 51511 50777 50082 50082 50757 51511 50082 50756 50757 50788 50085 50083 50083 50777 50788 50811 50092 50085 50085 50788 50811 50087 50094 50096 50087 50088 50094 50089 50088 50087 50096 50089 50087 50088 50091 50094 50088 50090 50091 50800 50090 50088 50802 50800 50088 50809 50802 50088 50088 50089 50809 50816 50809 50089 50089 50096 50816 50775 50091 50090 50776 50754 50090 51509 50776 50090 50090 50800 51509 50098 50094 50091 50103 50098 50091 50104 50103 50091 50799 50104 50091 50091 50786 50799 50091 50775 50786 51539 51534 50093 50093 50820 51539 50093 50099 50820 50098 50096 50094 50095 50103 50105 50095 50098 50103 50095 50096 50098 50097 50096 50095 50107 50097 50095 50113 50107 50095 50095 50105 50113 50096 50108 50816 50096 50097 50108 50097 50106 50108 50107 50106 50097 50099 50115 50820 50837 50814 50100 50100 50826 50837 50101 50102 50111 51535 50111 50102 50102 51528 51535 50102 50803 51528 50103 50104 50105 50807 50806 50104 50104 50799 50807 50806 50105 50104 50124 50113 50105 50808 50124 50105 50105 50806 50808 50816 50108 50106 50106 50135 50816 50106 50114 50135 50106 50107 50114 50125 50114 50107 50107 50113 50125 51518 50825 50109 50109 50812 51518 51544 50826 50110 51545 51544 50110 50110 50838 51545 50110 50830 50838 50838 50830 50111 51538 50838 50111 50111 51535 51538 51530 50805 50112 50112 50821 51530 50124 50123 50113 50113 50123 50125 50137 50135 50114 50114 50127 50137 50114 50126 50127 50114 50125 50126 50832 50820 50115 50853 50845 50116 50116 50118 50853 50116 50117 50118 50119 50118 50117 50118 50119 50853 50119 50120 50140 50119 50140 50853 50120 50121 50140 50121 50148 50149 50149 50140 50121 50122 50825 51540 50843 50134 50123 50123 50124 50843 50133 50125 50123 50134 50133 50123 51549 50843 50124 50124 51548 51549 50124 50808 51548 50133 50126 50125 50147 50127 50126 50126 50143 50147 50126 50133 50143 50147 50137 50127 50128 50139 50832 50129 50130 50132 51552 50132 50130 50130 50846 51552 50823 50822 50131 50131 50132 50823 51547 50823 50132 51552 51547 50132 50133 50134 50143 50843 50143 50134 50839 50816 50135 50135 50136 50839 50137 50136 50135 50844 50839 50136 50136 50146 50844 50147 50146 50136 50136 50137 50147 50138 50840 50848 50139 50152 50832 50863 50853 50140 50140 50149 50863 50141 50154 50858 50150 50148 50141 50858 50150 50141 50142 50833 50836 50143 50146 50147 50143 50145 50146 50843 50145 50143 52177 50847 50144 50144 52176 52177 50144 51561 52176 50144 50145 51561 50146 50145 50144 50847 50146 50144 50145 50843 51561 51563 50844 50146 50146 50847 51563 50150 50149 50148 50866 50863 50149 50149 50857 50866 50149 50150 50857 50865 50857 50150 51568 50865 50150 51569 51568 50150 51570 51569 50150 50150 51562 51570 50150 50858 51562 50162 50161 50151 50152 50819 50832 50152 50153 50819 50153 50818 50819 50850 50818 50153 50154 50836 51562 51562 50858 50154 50155 50158 50859 50874 50160 50156 50156 50169 50874 50156 50168 50169 50882 50166 50157 50157 50875 50882 50158 50159 50176 50159 50175 50176 50874 50860 50160 50165 50164 50161 51566 50165 50161 50161 50861 51566 50161 50162 50861 50862 50861 50162 51557 50862 50162 50162 50848 51557 50163 50175 50877 50176 50175 50163 50164 50165 50173 51571 50173 50165 50165 51566 51571 50166 50882 50884 50877 50175 50167 50879 50169 50168 50888 50874 50169 50889 50888 50169 50169 50878 50889 50879 50878 50169 50191 50180 50170 50170 50177 50191 50178 50177 50170 50170 50171 50178 50883 50178 50171 51587 50883 50171 50171 51586 51587 50171 50885 51586 50171 50172 50885 50886 50885 50172 50172 50181 50886 51571 50174 50173 50185 50179 50174 51574 50185 50174 50174 51571 51574 50893 50892 50177 50177 50178 50893 51579 50893 50178 50178 50883 51579 50179 50184 50192 50185 50184 50179 50181 50182 50886 50894 50886 50182 50182 50183 50894 50895 50894 50183 50183 50192 50895 50896 50192 50184 50184 50186 50896 50184 50185 50186 50902 50186 50185 51589 50902 50185 50185 51581 51589 50185 51574 51581 50902 50896 50186 51567 50854 50187 50187 50188 51567 52192 51567 50188 52193 52192 50188 50188 51593 52193 50188 50881 51593 50189 50193 50880 50190 50195 50879 50897 50895 50192 50192 50896 50897 50881 50880 50193 50901 50881 50193 50200 50195 50194 50891 50879 50195 50195 50200 50891 50206 50199 50197 50199 50198 50197 50198 50903 51595 50904 50903 50198 50198 50199 50904 50199 50206 50912 51606 50904 50199 50199 50913 51606 50199 50912 50913 50200 50201 50891 50201 50890 50891 51596 50890 50201 50214 50213 50203 50203 50204 50214 50910 50219 50205 50911 50910 50205 50205 50905 50911 50205 50213 50905 50914 50217 50207 50915 50914 50207 50207 50907 50915 51608 50909 50208 52219 51608 50208 50208 50209 52219 50210 50209 50208 50209 50210 51597 50209 52218 52219 50209 51597 52218 50210 50212 51597 51597 50212 50211 51598 51597 50211 52215 51598 50211 50211 51591 52215 50211 50892 51591 51609 50905 50213 50213 50214 51609 50223 50218 50214 50214 50918 51609 50919 50918 50214 50214 50218 50919 50215 50224 50229 50225 50224 50215 50215 50216 50225 50910 50225 50216 50216 50219 50910 50914 50220 50217 51614 50919 50218 50218 50222 51614 50916 50226 50220 50220 50914 50916 50917 50222 50221 51615 51614 50222 50222 50917 51615 50928 50229 50224 51618 50928 50224 50224 50225 51618 50225 51616 51618 51617 51616 50225 50225 50910 51617 50228 50227 50226 50925 50228 50226 50226 50916 50925 50227 50228 50236 50228 50232 50233 50234 50232 50228 50925 50234 50228 50928 50927 50229 50920 50912 50230 51612 50920 50230 50230 50929 51612 50231 50234 50235 50231 50232 50234 50231 50235 50929 50925 50235 50234 50235 50924 50929 50235 50923 50924 50925 50923 50235 50934 50930 50237 50237 50238 50934 52228 50934 50238 50238 51622 52228 50239 50243 50935 50250 50243 50239 50940 50243 50240 51623 50940 50240 50240 50936 51623 52229 50936 50241 50241 50242 52229 52871 52229 50242 50242 51625 52871 50242 50937 51625 50242 50245 50937 50940 50935 50243 50248 50245 50244 50245 50249 50937 50245 50248 50249 50939 50938 50246 50246 50935 50939 50942 50249 50247 52231 50942 50247 50247 51630 52231 50247 50950 51630 50247 50248 50950 50249 50248 50247 50942 50941 50249 51624 50937 50249 50249 50941 51624 50261 50257 50251 50257 50253 50251 50945 50255 50252 50946 50945 50252 50252 50258 50946 50262 50259 50253 50953 50262 50253 50253 50257 50953 50944 50256 50254 50254 50255 50944 50945 50944 50255 50256 50265 50267 51634 50265 50256 50256 50947 51634 50949 50947 50256 50256 50944 50949 50257 50261 50953 50258 50260 50946 50258 50259 50260 50262 50260 50259 51629 50946 50260 51632 51629 50260 50260 50262 51632 50261 50943 50953 50261 50938 50943 52241 51632 50262 52242 52241 50262 50262 51638 52242 50262 50953 51638 50960 50954 50263 50263 50268 50960 51640 50964 50264 51642 51640 50264 51644 51642 50264 50264 51641 51644 50264 50957 51641 50264 50265 50957 51634 50957 50265 50266 50964 50966 50268 50269 50960 50269 50959 50960 50270 50967 50968 50274 50272 50270 50968 50274 50270 50965 50959 50271 50969 50965 50271 50271 50276 50969 51648 50971 50272 50272 51647 51648 50272 50273 51647 50274 50273 50272 50971 50275 50272 50273 50970 51647 50273 50968 50970 50273 50274 50968 51649 50969 50276 50276 50973 51649 50276 50972 50973 50975 50280 50277 51652 50975 50277 50277 50976 51652 50970 50968 50278 50278 50279 50970 50981 50970 50279 50279 50291 50981 50973 50972 50281 51650 50973 50281 50281 50282 51650 50283 50282 50281 52272 51650 50282 50282 51657 52272 50282 50283 51657 50283 50284 51657 50284 50977 51657 51643 50974 50285 51646 51643 50285 50285 51640 51646 50285 50966 51640 50285 50286 50966 50287 50286 50285 51656 50300 50288 50288 50980 51656 51653 50980 50288 50288 50289 51653 50290 50289 50288 50289 51643 51645 50289 50290 51643 50289 51645 51653 50982 50981 50291 50995 50982 50291 50292 50307 50308 51675 50312 50293 50986 50297 50294 51660 50986 50294 50294 50992 51660 50294 50295 50992 50296 50295 50294 50295 50305 50992 50986 50985 50297 50298 50299 50301 50302 50301 50299 50299 50300 50302 51663 50302 50300 50300 50991 51663 50300 50990 50991 51656 50990 50300 50301 50302 51663 50997 50992 50305 50309 50307 50306 51666 50309 50306 50306 50998 51666 50999 50998 50306 51668 50999 50306 50306 51665 51668 50306 51008 51665 50306 51007 51008 50306 50311 51007 50309 50308 50307 50308 50993 50995 50308 50309 50993 51666 50993 50309 50310 50315 50316 51681 50315 50310 52285 51681 50310 50311 50321 51007 50311 50320 50321 51675 50313 50312 51676 51674 50313 50313 50989 51676 51675 50989 50313 50316 50315 50314 51004 50317 50314 51679 51004 50314 50314 51678 51679 50314 50315 51678 51681 51678 50315 50317 51004 51012 51003 50997 50318 51009 51003 50318 50318 50322 51009 50318 50319 50322 51024 50321 50320 51698 51024 50320 50320 51033 51698 51008 51007 50321 51665 51008 50321 50321 51023 51665 51024 51023 50321 51029 51009 50322 50322 51028 51029 51014 50326 50323 51016 51014 50323 50324 50326 51014 50327 50325 50324 51699 50327 50324 50324 51025 51699 50324 51014 51025 51699 51695 50327 51694 50332 50327 51695 51694 50327 52941 52308 50328 53620 52941 50328 50328 50329 53620 50330 50329 50328 52308 50330 50328 53626 53620 50329 53628 53626 50329 50329 52948 53628 50329 52310 52948 50329 50330 52310 50330 51034 52310 50330 51024 51034 52308 51024 50330 51037 51033 50331 51026 50334 50332 51696 51026 50332 51697 51696 50332 50332 51694 51697 50334 50333 50332 50333 50334 50335 50334 51027 51703 50334 51026 51027 50345 50335 50334 50346 50345 50334 51703 50346 50334 50339 50338 50335 50345 50339 50335 51044 50337 50336 51702 51044 50336 50336 51021 51702 51043 51042 50337 51702 51043 50337 50337 51044 51702 51054 50343 50337 50337 51048 51054 50337 51042 51048 50338 50339 50347 51050 50347 50339 50339 51045 51050 50339 50345 51045 51041 51037 50340 51709 51041 50340 51715 51709 50340 52962 51057 50341 50341 51729 52962 51730 51729 50341 52331 51730 50341 50341 50342 52331 50344 50348 50351 50345 50346 51045 51046 51045 50346 51047 51046 50346 51710 51047 50346 50346 51703 51710 51058 50348 50347 50347 51050 51058 51058 50351 50348 50368 50364 50349 50374 50368 50349 50349 50350 50374 51086 50374 50350 50350 50355 51086 51058 50359 50351 51066 51065 50352 51071 51066 50352 50352 50353 51071 50353 50365 51071 50353 50358 50365 50355 50356 51086 50357 50356 50355 51089 51086 50356 50356 50357 51089 51759 51089 50357 50357 51102 51759 50357 50397 51102 50358 50364 50365 51058 50361 50359 50360 50361 51058 51064 50363 50360 51067 51064 50360 50360 51058 51067 50373 50367 50362 51069 50373 50362 50362 50363 51069 51082 51069 50363 50363 51068 51082 50363 51063 51068 51064 51063 50363 50368 50365 50364 51078 51071 50365 50365 50368 51078 51088 50370 50366 50366 51087 51088 50366 50377 51087 51080 50377 50366 50366 50369 51080 50373 50372 50367 50368 50374 51078 50370 51088 51739 50371 50378 51092 50371 50372 50378 50379 50378 50372 50372 50373 50379 51076 50379 50373 50373 51069 51076 51086 51085 50374 51085 51078 50374 51093 51090 50375 52377 51093 50375 52385 52377 50375 53003 52385 50375 50375 50376 53003 50377 50376 50375 51090 50377 50375 50376 52371 53003 50376 51742 52371 50376 50377 51742 50377 51733 51742 50377 51080 51733 51090 51087 50377 51095 51092 50378 51752 51095 50378 50378 50379 51752 50379 51738 51752 50379 51075 51738 51076 51075 50379 50380 51098 51099 50380 50384 51098 51101 50387 50381 50381 51097 51101 50381 50385 51097 50394 50389 50382 50395 50394 50382 51112 50395 50382 51114 51112 50382 50382 50386 51114 50382 50383 50386 50387 50386 50383 50384 51764 51769 50384 51096 51764 51768 51098 50384 51769 51768 50384 50385 50392 51097 51776 51114 50386 50386 50387 51776 50387 51115 51776 50387 51101 51115 50390 51099 51100 50391 50399 51107 51107 50393 50391 51111 51110 50392 50392 50393 51111 51110 51097 50392 50393 51108 51111 51109 51108 50393 50393 51107 51109 51103 51102 50397 50398 51104 51113 50399 50407 50414 50403 50402 50400 50404 50403 50400 50400 50401 50404 50410 50405 50402 50402 50403 50410 50403 50408 50410 50409 50408 50403 50403 50404 50409 51779 50409 50404 51784 51779 50404 50404 50418 51784 50419 50418 50404 50424 50423 50406 50428 50424 50406 51800 50420 50408 50408 51785 51800 50408 50409 51785 50409 51779 51785 50411 50425 50426 50426 50425 50412 50427 50426 50412 51121 50427 50412 50412 51117 51121 50412 50413 51117 51118 51117 50413 50413 51113 51118 51116 50416 50415 50415 51115 51116 50415 50417 51115 51777 50430 50416 50416 51116 51777 51776 51115 50417 51790 51784 50418 50418 50431 51790 50432 50431 50418 51819 50432 50418 50418 50435 51819 50418 50419 50435 51808 50433 50420 51809 51808 50420 52426 51809 50420 50420 51800 52426 51782 51103 50421 50421 51119 51782 50421 50422 51119 51120 51119 50422 50426 50427 50434 50436 50434 50427 51123 50436 50427 50427 51121 51123 50429 50430 51777 51111 51108 50429 51777 51111 50429 52422 51790 50431 50431 50432 52422 50432 51819 52422 51808 51126 50433 51831 51819 50435 50435 51131 51831 51123 50439 50436 50449 50447 50438 50438 50439 50449 51127 50449 50439 50439 51123 51127 50440 50441 50450 50442 50441 50440 51823 50442 50440 53741 51823 50440 50440 53066 53741 50440 52453 53066 50440 50450 52453 50441 50442 51815 50441 50443 50450 50442 51135 51815 51823 51135 50442 51135 51133 50445 51815 51135 50445 50448 50447 50446 50464 50448 50446 50465 50464 50446 50446 50455 50465 50446 50447 50455 51139 50455 50447 50447 51128 51139 50447 50449 51128 50463 50454 50448 50464 50463 50448 50449 51127 51128 50450 50459 52453 50452 50453 51145 50453 50462 51832 50453 50458 50462 51832 51145 50453 50454 50463 50467 51137 50465 50455 51139 51137 50455 51842 50457 50456 50456 51157 51842 50456 50468 51157 51842 50460 50457 50460 50459 50457 50458 50461 50462 52459 52453 50459 50459 50460 52459 52460 52459 50460 50460 51842 52460 51154 50462 50461 50461 50466 51154 51836 51832 50462 51838 51836 50462 50462 51837 51838 50462 51154 51837 51169 50467 50463 50463 51158 51169 50463 50464 51158 51168 51158 50464 51840 51168 50464 51841 51840 50464 50464 50465 51841 50465 51155 51841 51156 51155 50465 50465 51146 51156 50465 51143 51146 50465 51140 51143 50465 51137 51140 51166 51154 50466 50466 51165 51166 51162 50473 50469 50469 50470 51162 50470 51153 51162 51859 51164 50471 50471 50474 51859 50471 50472 50474 51177 50474 50472 50473 51161 51170 51162 51161 50473 51860 51859 50474 50474 50486 51860 51177 50486 50474 50475 50476 51854 52489 51854 50476 50476 51871 52489 50478 51176 51182 50478 50480 51176 50478 50479 50480 51186 50488 50481 51868 51186 50481 50481 51862 51868 50481 51174 51862 51190 50483 50482 50482 51186 51190 50482 50488 51186 51190 50484 50483 50484 51190 51870 51861 51860 50486 50486 50487 51861 50487 50490 51198 52499 51861 50487 50487 51197 52499 51198 51197 50487 51196 51185 50489 50490 50496 51198 50490 50495 50496 51877 51205 50492 50492 51199 51877 51200 51199 50492 50493 51185 51196 51872 50494 50493 50493 51196 51872 51207 50498 50494 50494 51206 51207 51213 51206 50494 51872 51213 50494 51201 50496 50495 50495 50499 51201 51201 51198 50496 51210 50501 50497 50497 50503 51210 50497 50502 50503 51207 50522 50498 50499 50500 51201 51202 51201 50500 50500 50504 51202 51221 51217 50501 50501 51210 51221 51204 50503 50502 50502 50505 51204 51879 51210 50503 50503 51204 51879 51203 51202 50504 50504 50506 51203 51205 51204 50505 50506 50513 51203 51222 50508 50507 51878 51222 50507 50508 51222 51884 52523 51874 50508 50508 51884 52523 50509 50523 50528 51223 50523 50509 51232 50529 50510 51233 51232 50510 50510 50511 51233 50512 50511 50510 50523 50512 50510 50528 50523 50510 52526 51233 50511 50511 50512 52526 50512 52525 52526 50512 50521 52525 50523 50521 50512 51225 51203 50513 50513 50514 51225 50514 50525 51225 50514 50524 50525 50527 50524 50514 51229 51226 50515 50515 51216 51229 51228 50533 50517 50517 50518 51228 50538 50520 50519 50519 50537 50538 50519 50536 50537 50520 50538 51231 50521 51208 52525 50521 50522 51208 50523 50522 50521 50522 51207 51208 51883 50525 50524 50524 51227 51883 50524 50526 51227 50527 50526 50524 51883 51882 50525 51880 51225 50525 51882 51880 50525 50526 50540 51227 50526 50527 50540 50527 50530 50540 50541 50540 50530 50543 50541 50530 50530 50542 50543 50531 50532 50546 50533 50532 50531 50532 50544 50546 50545 50544 50532 50532 50533 50545 51235 50545 50533 50533 51228 51235 50534 50535 50536 50547 50535 50534 50537 50536 50535 51239 50537 50535 50535 50547 51239 50539 50538 50537 51893 50539 50537 50537 51237 51893 51238 51237 50537 51239 51238 50537 51891 51231 50538 50538 50539 51891 51893 51891 50539 51236 51227 50540 50540 51234 51236 50540 50541 51234 50541 50543 51234 50554 50543 50542 50555 50554 50542 50557 50555 50542 50543 50554 51234 51242 50546 50544 51244 51242 50544 51897 51244 50544 51898 51897 50544 50544 51243 51898 50544 50545 51243 51890 51243 50545 50545 51235 51890 50546 51242 51245 50547 50553 51239 51241 50549 50548 51248 51241 50548 51889 51248 50548 50549 51241 51247 51247 51240 50549 51239 50553 50550 50550 50551 51239 50552 50551 50550 50553 50552 50550 51900 51239 50551 51908 51900 50551 52559 51908 50551 50551 50552 52559 50552 51246 52559 50552 50556 51246 50554 50555 51907 52551 51234 50554 50554 51907 52551 50555 51251 51907 50556 51245 51246 50558 51240 51247 51262 50566 50559 51258 51256 50560 51917 51258 50560 50560 50561 51917 50561 50562 51917 51918 51917 50562 50562 51916 51918 51269 51259 50563 50563 50575 51269 51928 50574 50564 50564 51264 51928 50564 50565 51264 51929 51264 50565 50565 51265 51929 50565 51260 51265 51261 50567 50566 51923 51261 50566 50566 51262 51923 51265 51260 50567 51932 51265 50567 50567 51261 51932 50570 50569 50568 52579 52576 50569 50569 51925 52579 50569 50570 51925 50570 51924 51925 50586 50585 50571 50595 50586 50571 50571 50572 50595 50573 50572 50571 50585 50573 50571 50603 50595 50572 50604 50603 50572 51928 50608 50574 51270 51269 50575 50575 50576 51270 50576 50585 51270 51933 50578 50577 50577 51273 51933 50577 50584 51273 51933 51924 50578 50581 50580 50579 52592 50581 50579 53222 52592 50579 50579 52591 53222 50579 51277 52591 51272 50582 50580 50580 50581 51272 51939 51272 50581 52583 51939 50581 52592 52583 50581 51271 50583 50582 51272 51271 50582 51271 50584 50583 50584 51271 51273 51275 51270 50585 50585 50586 51275 51279 51275 50586 51280 51279 50586 50586 50595 51280 50587 50590 50600 50609 50590 50587 50587 50588 50609 50610 50609 50588 50588 50598 50610 50591 50590 50589 51965 50591 50589 50589 51962 51965 50589 51296 51962 50589 50609 51296 50589 50590 50609 50590 50591 50600 50591 50599 50600 51964 50599 50591 52614 51964 50591 50591 51965 52614 51282 50611 50592 51936 51278 50593 50593 50594 51266 50595 50603 51280 51293 50598 50596 51958 51293 50596 50596 51301 51958 50596 51294 51301 50596 50597 51294 50598 50597 50596 50597 51292 51294 50597 51283 51292 50597 51281 51283 51295 50610 50598 50598 51293 51295 50599 51963 53232 51964 51963 50599 50601 50600 50599 53232 50601 50599 51952 51276 50600 50600 50601 51952 52595 51952 50601 53232 52595 50601 51953 51287 50602 50602 51278 51953 51949 51280 50603 50603 51307 51949 50603 50606 51307 50620 50606 50603 50603 50604 50620 50605 50606 50620 50607 50606 50605 50623 50607 50605 50605 50622 50623 51968 51307 50606 50606 50625 51968 50606 50607 50625 50607 50623 50625 51943 51281 50608 50608 51937 51943 50608 51928 51937 50609 51295 51296 50609 50610 51295 51291 50619 50611 50611 50615 51291 51290 50615 50611 50611 51282 51290 51285 51284 50612 50612 50613 51285 51286 51285 50613 50613 50614 51286 51957 51286 50614 50615 50616 51291 51289 51287 50615 51290 51289 50615 50616 50619 51291 50616 50618 50619 50616 50617 50618 50627 50623 50621 50630 50627 50621 50621 50628 50630 50627 50625 50623 50624 51982 51994 50624 51976 51982 50625 51305 51968 50625 50626 51305 50627 50626 50625 51306 51305 50626 51310 51306 50626 50626 50627 51310 50627 50630 51310 52003 50630 50628 50628 51996 52003 50628 51320 51996 53924 51310 50630 50630 53920 53924 50630 52003 53920 50632 50633 50635 50634 50633 50632 51997 51982 50633 50633 50634 51997 52004 50635 50633 50633 52000 52004 50633 51981 52000 51982 51981 50633 50634 51311 51997 51347 51326 50635 52004 51347 50635 51341 50637 50636 50636 51326 51341 51341 50640 50637 51338 51325 50639 50639 51337 51338 51341 51330 50640 50641 50642 50651 51332 50642 50641 50641 51328 51332 50641 50650 51328 51332 51314 50642 50642 50643 50651 50644 50643 50642 51314 50644 50642 50643 50645 50651 50646 50645 50643 50647 50646 50643 50643 50644 50647 50649 50647 50644 51342 50649 50644 50644 51334 51342 51335 51334 50644 50644 51322 51335 50644 51314 51322 50652 50651 50645 50653 50652 50645 50645 50646 50653 50646 50648 50653 50646 50647 50648 50649 50648 50647 52024 50653 50648 50648 51343 52024 50648 50649 51343 50649 51342 51343 51351 51328 50650 50650 51330 51351 51350 51330 50650 50658 50657 50652 51363 50658 50652 50652 50653 51363 52024 51363 50653 50654 52013 52014 50654 51364 52013 50654 51359 51364 52652 51345 50654 50654 52014 52652 51355 50656 50655 52028 51360 50656 50656 51355 52028 50660 50663 50664 50660 50661 50663 50662 50661 50660 50664 50662 50660 50672 50663 50661 50661 50669 50672 50670 50669 50661 50661 50662 50670 51366 50670 50662 50662 51365 51366 50662 50674 51365 50662 50664 50674 50665 50664 50663 50664 50673 50674 50664 50665 50673 50667 50668 51370 52036 51370 50668 52674 52036 50668 52676 52674 50668 50668 51381 52676 50668 51379 51381 50690 50681 50669 50669 50671 50690 50669 50670 50671 50680 50671 50670 52039 50680 50670 52040 52039 50670 52041 52040 50670 50670 51366 52041 50671 50678 50688 50680 50678 50671 50671 50681 50690 50688 50681 50671 52047 51365 50673 52048 52047 50673 50673 51374 52048 51375 51374 50673 51365 50674 50673 50675 50684 51383 50685 50684 50675 51369 50685 50675 51381 51379 50676 50676 51380 51381 51372 50688 50678 52046 51372 50678 50678 50679 52046 50680 50679 50678 50679 52039 52046 50679 50680 52039 50689 50683 50681 50681 50688 50689 50682 50683 50695 50683 50689 50695 50684 51376 51383 51378 51376 50684 52683 51378 50684 50684 50685 52683 50685 52672 52683 50685 52035 52672 50685 51369 52035 51385 51384 50687 50688 51372 51373 51373 50689 50688 51386 50695 50689 50689 51373 51386 50691 50692 52053 52692 52053 50692 50692 51394 52692 51395 51394 50692 50692 50696 51395 50695 51386 51402 52699 51395 50696 52709 52699 50696 50696 51413 52709 50696 50697 51413 50697 51411 51413 50698 51390 52062 50698 50699 51390 50700 50699 50698 50701 50700 50698 50703 50701 50698 52057 50703 50698 52062 52057 50698 50699 51389 51390 52056 51389 50699 50699 50700 52056 50700 51392 52056 50702 50703 52057 52057 50704 50702 52057 51397 50704 51415 50707 50705 50705 51412 51415 51416 51399 50706 50706 51407 51416 50706 50708 51407 52064 50710 50707 50707 52063 52064 50707 51415 52063 52064 51448 50710 50712 50713 51471 50713 51451 51471 50713 50715 51451 52077 52076 50714 50714 51452 52077 50714 51447 51452 50714 50716 51447 51451 50715 50714 52075 51451 50714 52076 52075 50714 50716 50717 51447 50723 50722 50718 50719 50721 51462 50719 50720 50721 51479 50721 50720 50720 50729 51479 51483 51478 50721 50721 51479 51483 51478 51462 50721 50722 50723 50731 51456 50731 50723 51458 51456 50723 51467 50732 50724 51480 51467 50724 52087 51480 50724 50724 51459 52087 50724 50734 51459 50724 50733 50734 51459 50736 50725 51460 51459 50725 51468 51460 50725 51489 50737 50726 51490 51489 50726 50726 51481 51490 51477 50738 50727 50727 51462 51477 50739 50729 50728 50728 50730 50739 51484 51479 50729 51486 51484 50729 50729 51485 51486 50729 50739 51485 50740 50739 50730 51464 50740 50731 50731 51456 51464 51467 51466 50732 50735 50734 50733 50734 50741 51459 50734 50735 50741 50735 50736 50741 51459 50741 50736 51450 51441 50737 52066 51450 50737 52733 52066 50737 50737 52099 52733 50737 51489 52099 51477 50749 50738 51488 51485 50739 50739 50740 51488 50740 51465 51488 50740 51464 51465 50744 50743 50742 50755 50744 50742 51472 51452 50743 51473 51472 50743 51474 51473 50743 50743 50744 51474 50744 50770 51474 50744 50755 50770 52103 50758 50745 52104 52103 50745 50745 50761 52104 50745 50746 50761 52093 50761 50746 50746 51475 52093 50746 50747 51475 51476 51475 50747 51482 51476 50747 50747 50748 51482 51501 50750 50749 51502 51501 50749 50749 51477 51502 51501 50762 50750 51490 51481 50751 50751 51489 51490 50751 50752 51489 51492 51489 50752 51497 50774 50753 50753 51495 51497 50776 50770 50754 50770 50755 50754 50758 50757 50756 50757 51510 51511 50757 51504 51510 50757 50758 51504 51505 51504 50758 52103 51505 50758 50760 50767 51491 50769 50767 50760 51507 50769 50760 50760 50784 51507 52093 52092 50761 52741 52104 50761 52742 52741 50761 50761 52092 52742 51501 50766 50762 50794 50792 50763 52121 50794 50763 50763 50764 52121 50765 50764 50763 50766 50765 50763 50764 52115 52121 50764 51506 52115 50764 50765 51506 50765 51501 51506 50765 50766 51501 51493 51491 50767 50767 50768 51493 50769 50768 50767 52747 51493 50768 52754 52747 50768 50768 52117 52754 50768 50769 52117 50769 52116 52117 50769 51508 52116 50769 51507 51508 52101 51474 50770 50770 51514 52101 50770 51503 51514 50770 50776 51503 50771 50772 50782 50773 50772 50771 50781 50773 50771 50812 50782 50772 51517 50812 50772 51527 51517 50772 50772 50773 51527 50773 50797 51527 51496 50798 50774 51497 51496 50774 51513 50786 50775 51509 51503 50776 50777 50787 50788 51511 50787 50777 51500 50779 50778 51526 51500 50778 51500 50780 50779 52094 51482 50780 52113 52094 50780 50780 51500 52113 52116 51508 50785 50785 51512 52116 51513 50799 50786 51531 50788 50787 52132 51531 50787 50787 52125 52132 50787 51511 52125 51531 50811 50788 50789 50790 51526 50791 50790 50789 52114 51526 50790 52787 52114 50790 50790 52133 52787 50790 50791 52133 52134 52133 50791 50791 51534 52134 50794 50793 50792 50793 50794 52121 50793 52777 52779 50793 52121 52777 51516 50797 50795 50795 50796 51516 52128 51516 50796 50796 52126 52128 52127 51527 50797 53467 52127 50797 50797 51516 53467 51522 50803 50798 51523 51522 50798 50798 51496 51523 51513 50804 50799 51529 50807 50799 50799 50804 51529 50802 50801 50800 51524 51509 50800 50800 50801 51524 50801 50810 51525 50801 50802 50810 51525 51524 50801 50802 50809 50810 50803 51522 51528 51530 51529 50804 50804 50805 51530 50806 50807 51529 52136 50808 50806 50806 51530 52136 50806 51529 51530 52136 51548 50808 50815 50810 50809 50816 50815 50809 50810 50815 51525 50811 51531 51537 50812 51517 51518 50813 50827 51520 50813 50814 50827 50837 50827 50814 50815 50816 51525 51536 51525 50816 50816 50839 51536 50832 50819 50817 50817 50820 50832 51539 50820 50817 50817 51533 51539 52154 51533 50817 52811 52154 50817 50817 50818 52811 50819 50818 50817 52814 52811 50818 50818 52182 52814 50818 50850 52182 52139 51530 50821 52140 52139 50821 50821 50831 52140 52149 50831 50822 50822 50823 52149 52151 52149 50823 50823 51547 52151 51542 51541 50824 52141 51542 50824 50824 51537 52141 52144 51540 50825 50825 52138 52144 50825 51518 52138 51543 50837 50826 51544 51543 50826 51521 51520 50827 52124 51521 50827 50827 50828 52124 50829 50828 50827 51543 50829 50827 50827 50837 51543 50828 51512 52124 53459 51512 50828 54773 53459 50828 50828 54772 54773 50828 52781 54772 52782 52781 50828 54784 52782 50828 50828 52164 54784 50828 50829 52164 50829 51544 52155 50829 51543 51544 50829 52163 52164 52165 52163 50829 50829 52155 52165 52149 52140 50831 50833 50834 50836 50835 50834 50833 50834 50835 50842 50841 50836 50834 50842 50841 50834 51540 50842 50835 50836 50841 51558 50836 51558 51562 50838 51538 52145 51546 51545 50838 52145 51546 50838 52813 51536 50839 50839 51554 52813 51556 51554 50839 50839 50844 51556 51541 50848 50840 52142 51559 50841 50841 50842 52142 51559 51558 50841 52143 51551 50842 50842 51540 52143 50842 51550 52142 51551 51550 50842 50843 51560 51561 50843 51553 51560 50843 51549 51553 51564 51556 50844 50844 51563 51564 50853 50851 50845 50846 50869 51552 50871 50869 50846 52181 51563 50847 50847 52177 52181 50848 51541 51557 50854 50850 50849 50850 52172 52182 50850 50872 52172 50850 50854 50872 50853 50852 50851 50856 50855 50852 50852 50853 50856 50863 50856 50853 51567 50872 50854 50855 50864 50875 50855 50863 50864 50855 50856 50863 50857 50865 50866 50874 50868 50860 52171 51566 50861 50861 50862 52171 50862 51557 52171 50866 50864 50863 50882 50875 50864 51572 50882 50864 50864 50876 51572 50864 50873 50876 50864 50866 50873 50867 50866 50865 52183 50867 50865 50865 51568 52183 50866 50867 50873 50876 50873 50867 51575 50876 50867 52191 51575 50867 50867 52183 52191 51565 50871 50868 51585 51565 50868 50868 50874 51585 52148 51552 50869 52167 52148 50869 52168 52167 50869 52173 52168 50869 50869 50870 52173 50871 50870 50869 50870 50871 52173 52179 52173 50871 50871 51565 52179 52188 52172 50872 50872 51567 52188 50874 50888 51585 51573 51572 50876 52190 51573 50876 50876 51575 52190 50890 50889 50878 50878 50879 50890 50891 50890 50879 50881 50901 51593 51572 50884 50882 50883 51578 51579 52202 51578 50883 50883 52201 52202 50883 51587 52201 51590 50887 50884 50884 51572 51590 51588 51586 50885 50885 50886 51588 51592 51588 50886 50886 50894 51592 50900 50898 50887 51590 50900 50887 52194 51585 50888 52213 52194 50888 50888 51602 52213 52200 51602 50888 50888 50889 52200 50889 50890 52200 50890 51602 52200 50890 51596 51602 50892 50893 51591 50893 51576 51591 51579 51576 50893 50894 50895 51592 51600 51592 50895 50895 50897 51600 51600 50897 50896 50896 51599 51600 50896 50902 51599 50898 50900 50901 50899 50900 51590 50901 50900 50899 51594 50901 50899 52848 51594 50899 50899 52203 52848 50899 51590 52203 51594 51593 50901 51601 51599 50902 52214 51601 50902 50902 52210 52214 50902 51589 52210 50903 50904 51603 52212 51595 50903 50903 52211 52212 50903 51603 52211 51606 51603 50904 51619 50911 50905 50905 51609 51619 50908 50907 50906 50909 50908 50906 50907 50908 50915 51613 50915 50908 50908 51607 51613 50908 50909 51607 51608 51607 50909 50910 50911 51617 51619 51617 50911 50920 50913 50912 51610 51606 50913 50913 50920 51610 50926 50916 50914 51613 50926 50914 50914 50915 51613 50916 50923 50925 50926 50923 50916 50917 50930 51620 51620 51615 50917 51622 51609 50918 52228 51622 50918 50918 51614 52228 50918 50919 51614 50920 50921 51610 50922 50921 50920 51611 50922 50920 51612 51611 50920 52222 51610 50921 52865 52222 50921 53565 52865 50921 50921 50922 53565 50922 52226 53565 50922 52225 52226 50922 51611 52225 52227 50924 50923 50923 52223 52227 50923 50926 52223 51612 50929 50924 52227 51612 50924 50926 51613 52223 50927 50928 51618 51618 50933 50927 50930 50934 51620 50932 50933 51621 50933 51619 51621 50933 51618 51619 52228 51620 50934 51626 50939 50935 50935 50940 51626 51627 51623 50936 52876 51627 50936 50936 52229 52876 50937 51624 51625 50951 50943 50938 51636 50951 50938 50938 50939 51636 50939 51628 51636 50939 51626 51628 50940 51623 51626 52872 51624 50941 50941 50942 52872 52874 52872 50942 50942 52231 52874 50943 50951 50953 50944 50945 50949 50945 50948 50949 51633 50948 50945 50945 51629 51633 50945 50946 51629 52238 51634 50947 50947 52237 52238 50947 50948 52237 50949 50948 50947 50948 51633 52237 51631 51630 50950 50950 50955 51631 50951 50952 50953 51636 50952 50951 51635 50953 50952 52250 51635 50952 50952 52249 52250 50952 51636 52249 50953 51637 51638 50953 51635 51637 50960 50956 50954 50956 50955 50954 52240 51631 50955 50955 50956 52240 50956 50960 50961 52248 52240 50956 50956 50961 52248 52247 51641 50957 50957 52238 52247 50957 51634 52238 50958 50965 51639 50958 50959 50965 50960 50959 50958 50961 50960 50958 51639 50961 50958 50961 50962 52248 50963 50962 50961 51639 50963 50961 52884 52248 50962 52890 52884 50962 50962 50963 52890 52891 52890 50963 50963 52255 52891 50963 51639 52255 51640 50966 50964 50965 50969 51639 52255 51639 50969 50969 52254 52255 50969 51649 52254 52267 51647 50970 50970 50981 52267 51651 50976 50971 50971 51648 51651 51650 51649 50973 50975 51652 51655 51654 51652 50976 50976 51651 51654 50977 50985 51657 51656 50980 50978 52264 51656 50978 52906 52264 50978 54228 52906 50978 50978 50979 54228 50980 50979 50978 50979 53588 54228 50979 52270 53588 50979 52262 52270 50979 50980 52262 50980 51653 52262 52268 52267 50981 52271 52268 50981 52897 52271 50981 50981 50983 52897 50981 50982 50983 52903 50983 50982 50982 50994 52903 50995 50994 50982 52901 52900 50983 52903 52901 50983 52898 52897 50983 52900 52898 50983 51655 50988 50984 51658 51657 50985 50985 50986 51658 52280 51658 50986 50986 51661 52280 50986 51660 51661 52288 51676 50987 50987 52282 52288 50987 51659 52282 50987 50988 51659 50989 50988 50987 51676 50989 50987 50988 51655 51659 52902 50991 50990 50990 52264 52902 50990 51656 52264 52913 51663 50991 50991 52904 52913 52905 52904 50991 50991 52902 52905 51664 51660 50992 51667 51664 50992 50992 50997 51667 50993 50994 50995 52283 50994 50993 50993 51666 52283 52907 52903 50994 52908 52907 50994 53601 52908 50994 50994 52284 53601 50994 52283 52284 50997 51001 51667 51003 51001 50997 50998 52286 53609 50998 50999 52286 52283 51666 50998 52914 52283 50998 53609 52914 50998 50999 51683 52286 50999 51668 51683 51672 51016 51000 51000 51669 51672 51673 51669 51000 51677 51667 51001 52289 51677 51001 51001 51002 52289 51003 51002 51001 51002 51005 52289 51006 51005 51002 51002 51003 51006 51018 51006 51003 51003 51017 51018 51003 51009 51017 51686 51012 51004 51004 51682 51686 51004 51679 51682 52290 52289 51005 51005 51006 52290 52292 52290 51006 52293 52292 51006 51006 51685 52293 51006 51018 51685 51009 51010 51017 51011 51010 51009 51030 51011 51009 51009 51029 51030 51684 51017 51010 51010 51020 51684 51010 51019 51020 51010 51011 51019 51031 51019 51011 51706 51031 51011 51011 51705 51706 51011 51030 51705 51688 51022 51012 51012 51686 51688 51013 51690 51693 51691 51690 51013 51013 51016 51691 51013 51014 51016 51015 51014 51013 51693 51015 51013 51014 51015 51025 51693 51025 51015 51016 51672 51691 51684 51018 51017 51018 51684 51685 51031 51020 51019 52297 51684 51020 52307 52297 51020 51020 51708 52307 51020 51032 51708 51020 51031 51032 52298 51702 51021 51021 51022 52298 51022 51688 52298 51668 51665 51023 52308 51668 51023 51023 51024 52308 51698 51034 51024 51025 51695 51699 52300 51695 51025 51025 51693 52300 51038 51027 51026 52303 51038 51026 51026 51696 52303 51027 51038 51703 51704 51029 51028 51712 51704 51028 51028 51711 51712 51704 51030 51029 51707 51705 51030 51030 51704 51707 51706 51032 51031 52311 51708 51032 51032 51700 52311 51701 51700 51032 51714 51701 51032 51032 51713 51714 51032 51706 51713 51033 51036 51698 51037 51036 51033 51034 51035 52310 51036 51035 51034 51698 51036 51034 52948 52310 51035 51035 52309 52948 51035 51036 52309 52313 52309 51036 51036 51041 52313 51036 51037 51041 52327 51710 51038 51038 51039 52327 51040 51039 51038 52303 51040 51038 51710 51703 51038 52961 52327 51039 51039 51040 52961 51040 52944 52961 51040 52303 52944 51041 51709 52313 51042 51043 52956 51049 51048 51042 52326 51049 51042 53630 52326 51042 51042 52956 53630 51043 52316 52956 51043 52312 52316 51043 51702 52312 51719 51050 51045 51720 51719 51045 51721 51720 51045 51045 51046 51721 51046 51720 51721 52327 51720 51046 51046 51047 52327 51047 51710 52327 51056 51054 51048 51728 51056 51048 51048 51049 51728 53644 51728 51049 51049 52326 53644 51067 51058 51050 51722 51067 51050 51050 51719 51722 51051 51060 52317 51061 51060 51051 51051 51059 51061 52350 51072 51052 51052 51053 52350 51053 51054 51056 52975 52350 51053 51053 51055 52975 51056 51055 51053 52982 52975 51055 51055 51727 52982 51728 51727 51055 51055 51056 51728 51718 51715 51057 52332 51718 51057 52962 52332 51057 51065 51061 51059 52330 52317 51060 52964 52330 51060 51060 51061 52964 53677 52964 51061 51061 52361 53677 51061 51066 52361 51061 51065 51066 52351 52344 51062 52356 51068 51063 51063 52355 52356 51063 51725 52355 51063 51064 51725 51726 51725 51064 51064 51067 51726 52370 52361 51066 51066 51070 52370 51071 51070 51066 51067 51723 51726 51067 51722 51723 52356 51082 51068 51069 51075 51076 51069 51074 51075 51731 51074 51069 51069 51081 51731 51082 51081 51069 51070 52366 52370 51070 51740 52366 51070 51077 51740 51070 51071 51077 51071 51078 51741 51741 51077 51071 52357 51079 51072 51072 52350 52357 52374 51738 51073 51073 52369 52374 51073 51074 52369 51075 51074 51073 51738 51075 51073 51074 52360 52369 51074 51731 52360 51754 51740 51077 51077 51083 51754 51741 51083 51077 51078 51083 51741 51084 51083 51078 51085 51084 51078 51732 51080 51079 52357 51732 51079 51080 51732 51733 52360 51731 51081 51081 52358 52360 51081 51082 52358 52359 52358 51082 51082 52356 52359 51083 51753 51754 51083 51084 51753 52382 51753 51084 52383 52382 51084 51084 51755 52383 51084 51085 51755 51085 51086 51089 51085 51089 51755 51090 51088 51087 51088 51091 51739 51088 51090 51091 51759 51755 51089 51093 51091 51090 52386 51757 51091 52387 52386 51091 51091 52381 52387 51091 51756 52381 51091 51093 51756 51757 51739 51091 51095 51094 51092 52377 51756 51093 51758 51096 51094 51094 51095 51758 51766 51758 51095 51095 51752 51766 51096 51758 51764 51110 51101 51097 51100 51099 51098 51773 51100 51098 51098 51767 51773 51768 51767 51098 51774 51106 51100 51100 51773 51774 51101 51110 51115 51778 51759 51102 52402 51778 51102 51102 51783 52402 51102 51103 51783 51103 51782 51783 51122 51113 51104 52413 51122 51104 52416 52413 51104 51104 51105 52416 51105 51772 52416 51774 51772 51106 51110 51111 51115 51777 51115 51111 51122 51118 51113 51777 51116 51115 51786 51121 51117 52421 51786 51117 51117 52419 52421 51117 52413 52419 51117 51122 52413 51117 51118 51122 52420 51782 51119 51119 51792 52420 51119 51125 51792 51119 51120 51125 51126 51125 51120 51124 51123 51121 51787 51124 51121 51121 51786 51787 51123 51124 51127 51132 51127 51124 51793 51132 51124 51124 51788 51793 51124 51787 51788 51125 51126 51802 51801 51792 51125 52437 51801 51125 51125 51802 52437 51126 51808 51811 51811 51802 51126 51132 51128 51127 51128 51136 51139 51128 51132 51136 51129 51130 51807 51130 51806 51807 51130 51134 51806 52444 51831 51131 51131 52443 52444 51131 51145 52443 51793 51136 51132 51806 51134 51133 52441 51806 51133 51133 51135 52441 53055 52441 51135 51135 51823 53055 51136 51137 51139 51138 51137 51136 51793 51138 51136 51137 51138 51140 51142 51140 51138 51796 51142 51138 51138 51795 51796 51138 51793 51795 51140 51141 51143 51142 51141 51140 51141 51142 51796 51144 51143 51141 51799 51144 51141 51141 51798 51799 51141 51796 51798 51143 51144 51146 51826 51146 51144 51144 51150 51826 51813 51150 51144 51144 51812 51813 51144 51799 51812 51145 51834 52443 51145 51832 51834 51826 51156 51146 52463 51156 51148 53077 52463 51148 53752 53077 51148 51148 53069 53752 51148 51149 53069 51150 51149 51148 51156 51150 51148 51149 52464 53069 51149 51150 52464 51150 51813 52464 51150 51156 51826 51161 51153 51151 51847 51161 51151 51151 51152 51847 52461 51847 51152 51152 51830 52461 51153 51161 51162 51839 51837 51154 51154 51167 51839 51154 51166 51167 52463 51841 51155 51155 51156 52463 52482 51842 51157 52483 52482 51157 51157 51851 52483 51158 51168 51169 51159 51160 51843 51845 51170 51161 52472 51845 51161 51161 51848 52472 51161 51847 51848 51855 51172 51163 51856 51855 51163 51163 51164 51856 51859 51856 51164 51173 51167 51165 51850 51173 51165 51165 51171 51850 51167 51166 51165 51846 51839 51167 51167 51173 51846 51175 51169 51168 52479 51175 51168 51168 52477 52479 51168 51840 52477 51845 51843 51170 51857 51850 51171 51171 51855 51857 51171 51172 51855 52474 51846 51173 52478 52474 51173 52485 52478 51173 51173 51849 52485 51850 51849 51173 52486 51862 51174 51174 51853 52486 52487 51853 51175 52488 52487 51175 51175 52480 52488 51175 52479 52480 51176 51181 51182 51178 51179 51855 51180 51179 51178 53116 51180 51178 51178 53102 53116 51178 53100 53102 51178 51856 53100 51178 51855 51856 51857 51855 51179 51858 51857 51179 51179 51180 51858 52494 51858 51180 52503 52494 51180 53116 52503 51180 52493 51182 51181 51181 51866 52493 51867 51866 51181 52491 51867 51181 51184 51183 51182 51865 51184 51182 52493 51865 51182 51183 51193 51200 51183 51184 51193 51195 51193 51184 51865 51195 51184 51868 51190 51186 51189 51188 51187 53108 51189 51187 51187 52498 53108 51187 52486 52498 51187 51188 52486 51188 51189 51868 51188 51862 52486 51868 51862 51188 51189 51190 51868 51192 51190 51189 53121 51192 51189 51189 53108 53121 52505 51870 51190 51190 51191 52505 51192 51191 51190 53121 52505 51191 51191 51192 53121 51193 51199 51200 51193 51194 51199 51195 51194 51193 53136 51199 51194 54427 53136 51194 51194 54426 54427 51194 52510 54426 51194 51195 52510 51195 51863 52510 51864 51863 51195 51869 51864 51195 51195 51865 51869 52511 51872 51196 52514 52511 51196 53126 52499 51197 51197 51198 53126 51198 52512 53126 51198 51214 52512 51198 51201 51214 51199 51876 51877 53135 51876 51199 53136 53135 51199 51215 51214 51201 51201 51202 51215 52513 51215 51202 52520 52513 51202 51202 51881 52520 51202 51224 51881 51202 51203 51224 51880 51224 51203 51203 51225 51880 51204 51877 51879 51204 51205 51877 51208 51207 51206 51212 51208 51206 51213 51212 51206 53132 52525 51208 51208 53131 53132 51208 51212 53131 51209 51210 51875 51211 51210 51209 52522 51211 51209 51209 51876 52522 51209 51875 51876 51210 51216 51221 51218 51216 51210 51210 51211 51218 51879 51875 51210 51220 51218 51211 53139 51220 51211 51211 52522 53139 51212 53130 53131 51212 51213 53130 51213 52519 53130 51213 52516 52519 51213 52515 52516 51213 51872 52515 52513 52512 51214 51214 51215 52513 51216 51218 51229 51216 51217 51221 51230 51229 51218 52531 51230 51218 52532 52531 51218 51218 51219 52532 51220 51219 51218 53139 52540 51219 51219 51220 53139 52539 52532 51219 52540 52539 51219 51222 51878 51884 52520 51881 51224 52521 52520 51224 51224 51880 52521 51230 51228 51226 51226 51229 51230 51227 51236 52543 52527 51883 51227 52543 52527 51227 52542 51235 51228 51228 51230 52542 51230 52530 52542 52531 52530 51230 51887 51886 51231 51891 51887 51231 51886 51885 51231 53153 51888 51232 53154 53153 51232 51232 52526 53154 51232 51233 52526 52544 51236 51234 52551 52544 51234 53819 51890 51235 51235 53163 53819 51235 52542 53163 52544 52543 51236 51901 51893 51237 52554 51901 51237 52555 52554 51237 51237 51238 52555 52557 52555 51238 51238 51899 52557 51238 51239 51899 51900 51899 51239 51248 51247 51241 51249 51245 51242 51242 51244 51249 52545 51898 51243 51243 51890 52545 51250 51249 51244 51897 51250 51244 51249 51246 51245 53184 52559 51246 51246 52570 53184 51246 51249 52570 51247 51248 51909 52562 51909 51248 51248 51905 52562 51906 51905 51248 51248 51889 51906 53195 52570 51249 51249 53194 53195 51249 53183 53194 51249 51913 53183 51249 51250 51913 51250 51903 51913 51904 51903 51250 51250 51897 51904 52563 51907 51251 51251 51912 52563 51251 51252 51912 51253 51252 51251 52571 51912 51252 51252 51253 52571 51253 51267 52571 51253 51259 51267 51254 51911 52561 51254 51255 51911 51919 51916 51254 52564 51919 51254 53840 52564 51254 51254 52561 53840 51255 51910 51911 51255 51909 51910 51263 51257 51256 51256 51258 51263 51263 51262 51257 52572 51263 51258 51258 51922 52572 51258 51917 51922 51268 51267 51259 51269 51268 51259 53208 51932 51261 51261 53201 53208 51261 51923 53201 51262 51920 51923 51921 51920 51262 51262 51263 51921 52578 51921 51263 51263 52572 52578 51938 51928 51264 51264 51930 51938 51264 51929 51930 51932 51929 51265 51267 51268 52571 51268 51926 52571 51268 51269 51926 51269 51270 51926 51927 51926 51270 51942 51927 51270 51270 51941 51942 51270 51275 51941 51274 51273 51271 51939 51274 51271 51271 51272 51939 51934 51933 51273 53211 51934 51273 53215 53211 51273 51273 53210 53215 51273 51940 53210 51273 51274 51940 53214 51940 51274 51274 52583 53214 51274 51939 52583 51944 51941 51275 51275 51279 51944 51952 51277 51276 52601 52591 51277 51277 51952 52601 51278 51936 51953 51279 51280 51944 51949 51944 51280 51951 51283 51281 51281 51946 51951 51947 51946 51281 51281 51943 51947 51282 51289 51290 51954 51292 51283 51283 51951 51954 51955 51297 51284 51284 51285 51955 51285 51286 51956 51956 51955 51285 51957 51956 51286 51953 51288 51287 52597 51957 51288 53226 52597 51288 51288 53217 53226 51288 51953 53217 51301 51294 51292 51292 51299 51301 51959 51299 51292 51292 51954 51959 51958 51295 51293 51961 51296 51295 51295 51958 51961 51296 51960 51962 51961 51960 51296 51297 51955 52611 52615 51967 51297 53238 52615 51297 51297 52611 53238 51300 51299 51298 51302 51300 51298 52613 51302 51298 51298 52607 52613 51298 51959 52607 51298 51299 51959 51299 51300 51301 51300 51969 51974 51971 51969 51300 51973 51971 51300 51300 51302 51973 51974 51301 51300 51974 51958 51301 52617 51973 51302 51302 52613 52617 51303 51966 51983 51980 51304 51303 51983 51980 51303 51980 51976 51304 51977 51968 51305 51305 51310 51977 51305 51306 51310 51307 51308 51949 51309 51308 51307 51968 51309 51307 51950 51949 51308 52603 51950 51308 53234 52603 51308 51308 51309 53234 53890 53234 51309 51309 53239 53890 51309 51968 53239 51993 51977 51310 53924 51993 51310 51311 51994 51997 51312 51315 51319 51312 51313 51315 51314 51313 51312 51319 51314 51312 51313 51314 52005 51318 51315 51313 51986 51318 51313 51999 51986 51313 52001 51999 51313 52005 52001 51313 51332 51331 51314 51314 51319 51322 51314 51331 52005 51315 51316 51319 51317 51316 51315 51995 51317 51315 51315 51989 51995 51315 51988 51989 51315 51318 51988 51322 51319 51316 51316 51317 51322 51995 51324 51317 51323 51322 51317 51324 51323 51317 51990 51988 51318 51318 51984 51990 51986 51984 51318 51320 51321 51996 51321 51327 51996 51321 51325 51327 51322 51323 51335 51323 51354 52006 51323 51353 51354 51323 51333 51353 51323 51324 51333 52006 51335 51323 52634 51333 51324 51324 52630 52634 51324 51992 52630 51995 51992 51324 51338 51327 51325 51348 51341 51326 51326 51347 51348 52632 51996 51327 51327 51338 52632 51328 51331 51332 51328 51329 51331 51330 51329 51328 51351 51330 51328 52005 51331 51329 51329 52001 52005 51329 52000 52001 52002 52000 51329 51329 51349 52002 51329 51348 51349 51329 51341 51348 51329 51330 51341 52641 51353 51333 51333 52634 52641 51334 51336 51342 51334 51335 51336 52006 51336 51335 52006 51342 51336 51337 51344 51346 51340 51338 51337 51346 51340 51337 53263 52632 51338 51338 52639 53263 51338 52637 52639 51338 51339 52637 51340 51339 51338 52640 52637 51339 51339 52018 52640 51339 51346 52018 51339 51340 51346 51354 51343 51342 52006 51354 51342 51343 52007 52024 51343 51354 52007 52018 51346 51345 52652 52018 51345 52004 52002 51347 51349 51348 51347 52002 51349 51347 53277 52007 51352 51352 53265 53277 51352 52642 53265 51352 52641 52642 51352 51353 52641 51354 51353 51352 52007 51354 51352 51355 52019 52028 52020 52019 51355 51355 51356 52020 51356 51357 51358 51356 51358 52020 52022 51358 51357 52022 52011 51358 51358 52009 52020 52011 52009 51358 52044 51364 51359 51360 52029 52035 51360 52028 52029 52031 51362 51361 52023 52022 51362 52647 52023 51362 52656 52647 51362 51362 52030 52656 52031 52030 51362 51363 52032 52037 52033 52032 51363 52666 52033 51363 51363 52657 52666 51363 52024 52657 52043 52013 51364 52044 52043 51364 51367 51366 51365 52047 51367 51365 51366 51367 52041 51367 52027 52041 52042 52027 51367 52047 52042 51367 51368 51370 52036 51371 51382 51384 51373 51372 51371 51384 51373 51371 51372 52043 52044 52045 52043 51372 52046 52045 51372 51373 51384 51386 51388 51387 51376 52688 51388 51376 51376 51377 52688 51378 51377 51376 52689 52688 51377 51377 52685 52689 52686 52685 51377 51377 51378 52686 53306 52686 51378 51378 53305 53306 51378 52683 53305 52677 51381 51380 52679 52677 51380 51380 52678 52679 51380 52037 52678 52677 52676 51381 51384 51385 51386 51400 51386 51385 51385 51398 51400 51386 51400 51401 51386 51401 51402 52054 51392 51387 51387 51393 52054 51387 51388 51393 52688 51393 51388 51391 51390 51389 52056 51391 51389 52691 52062 51390 53988 52691 51390 51390 51391 53988 52056 52055 51391 51391 53987 53988 51391 52690 53987 51391 52055 52690 51392 52054 52056 52055 52054 51393 52688 52055 51393 52697 52692 51394 51394 51395 52697 53334 52697 51395 51395 52699 53334 51396 52058 52060 51396 51397 52058 52059 52058 51397 51397 52057 52059 51398 51399 51400 51418 51400 51399 51399 51416 51418 51418 51409 51400 51409 51401 51400 51408 51402 51401 51409 51408 51401 51405 51403 51402 51408 51405 51402 51405 51404 51403 51424 51410 51404 51404 51421 51424 51404 51405 51421 51422 51421 51405 51405 51408 51422 52061 51412 51406 51406 52060 52061 51418 51416 51407 51419 51418 51407 51408 51420 51422 51408 51409 51420 51418 51417 51409 51409 51417 51420 51413 51411 51410 51414 51413 51410 51424 51414 51410 52061 51415 51412 51413 51414 51423 52710 52709 51413 51413 51425 52710 51413 51423 51425 51424 51423 51414 51415 52061 52063 51417 51419 51426 51417 51418 51419 51436 51420 51417 51417 51426 51436 51420 51436 51437 51437 51422 51420 51421 51423 51424 51439 51423 51421 51421 51422 51439 51422 51438 51439 51422 51437 51438 51427 51425 51423 51428 51427 51423 51430 51428 51423 51439 51430 51423 51425 52700 52710 51425 51427 52700 51442 51436 51426 51426 51435 51442 51426 51434 51435 51427 51428 52700 51428 51432 52700 51428 51431 51432 51428 51429 51431 51430 51429 51428 51446 51431 51429 51429 51430 51446 51430 51445 51446 51430 51438 51445 51439 51438 51430 51433 51432 51431 52727 51433 51431 51431 51446 52727 53384 52700 51432 53394 53384 51432 51432 51433 53394 51433 52727 53394 52066 51442 51435 51435 51450 52066 51435 51440 51450 51444 51437 51436 51436 51443 51444 51436 51442 51443 51444 51438 51437 51438 51444 51445 51440 51441 51450 52066 51443 51442 52088 51444 51443 51443 52072 52088 52073 52072 51443 52079 52073 51443 51443 52066 52079 52080 51445 51444 52088 52080 51444 52074 51446 51445 52080 52074 51445 53397 52727 51446 51446 52074 53397 52713 52065 51448 51448 52064 52713 52065 51461 51449 52075 51471 51451 51452 51472 52077 52085 51464 51453 52729 52085 51453 51453 51463 52729 51453 51454 51463 51455 51454 51453 51464 51455 51453 52070 51463 51454 51454 52067 52070 52068 52067 51454 51454 51457 52068 51454 51455 51457 51455 51456 51457 51464 51456 51455 51458 51457 51456 51457 51466 52068 51457 51458 51466 52098 52087 51459 51459 51460 52098 52732 52098 51460 51460 52731 52732 51460 52728 52731 51460 51468 52728 52728 51468 51461 51461 52726 52728 51461 52065 52726 52095 51477 51462 52096 52095 51462 51462 51478 52096 51463 52070 52729 52085 51465 51464 52107 51488 51465 52743 52107 51465 51465 52085 52743 52071 52068 51466 52078 52071 51466 52086 52078 51466 51466 51467 52086 52087 52086 51467 51467 51480 52087 52750 51495 51469 51469 52735 52750 51469 51470 52735 51471 51470 51469 51470 52734 52735 51470 52083 52734 51470 52075 52083 51470 51471 52075 52084 52077 51472 51472 51473 52084 53406 52084 51473 51473 52738 53406 52739 52738 51473 51473 52101 52739 51473 51474 52101 51475 51476 52093 52094 52093 51476 51476 51482 52094 52095 51502 51477 51478 51483 51484 52102 52096 51478 52772 52102 51478 51478 51486 52772 51478 51484 51486 51484 51483 51479 52106 51486 51485 51485 51487 52106 51488 51487 51485 51486 52760 52772 51486 52106 52760 52109 52106 51487 52110 52109 51487 52111 52110 51487 51487 52107 52111 51487 51488 52107 52100 52099 51489 51489 51492 52100 51493 51492 51491 51492 52091 52100 51492 52089 52091 51492 51494 52089 51492 51493 51494 52747 51494 51493 52090 52089 51494 52746 52090 51494 52747 52746 51494 52765 51497 51495 51495 52755 52765 51495 52750 52755 52119 51523 51496 51496 51498 52119 51499 51498 51496 51496 51497 51499 52765 51499 51497 53455 52119 51498 51498 52766 53455 51498 51499 52766 51499 52765 52766 52770 52113 51500 51500 52114 52770 51500 51526 52114 52752 51506 51501 51501 51502 52752 51502 52102 52752 51502 52095 52102 51515 51514 51503 52108 51515 51503 51503 51509 52108 52784 51510 51504 53447 52784 51504 51504 51505 53447 51505 53446 53447 51505 52768 53446 51505 52103 52768 52773 52115 51506 51506 52752 52773 52120 52108 51509 51509 51524 52120 52784 52125 51510 52125 51511 51510 52118 52116 51512 52774 52118 51512 53459 52774 51512 52739 52101 51514 52756 52739 51514 52757 52756 51514 51514 51515 52757 51515 52108 52757 51516 52128 53467 51517 52127 52792 51517 51527 52127 51519 51518 51517 52792 51519 51517 51518 51519 52138 52798 52138 51519 53480 52798 51519 51519 52793 53480 51519 52792 52793 52129 51528 51522 52130 52129 51522 51522 51523 52130 53469 52130 51523 51523 52119 53469 52122 52120 51524 52123 52122 51524 51524 51525 52123 52131 52123 51525 52158 52131 51525 51525 51536 52158 52129 51535 51528 52139 52136 51530 52137 51537 51531 51531 52132 52137 51534 51533 51532 52134 51534 51532 52801 52134 51532 51532 52154 52801 51532 51533 52154 51533 51534 51539 52135 51538 51535 51535 52129 52135 52813 52158 51536 51537 52137 52141 51538 52135 52145 52144 52143 51540 52161 51557 51541 51541 52159 52161 51541 51542 52159 52160 52159 51542 51542 52141 52160 51544 51545 52156 52156 52155 51544 51545 51546 52156 53495 52156 51546 53501 53495 51546 53502 53501 51546 51546 52146 53502 51546 52145 52146 51547 52147 52151 51547 51552 52147 52150 51549 51548 51548 52136 52150 52157 51553 51549 51549 52153 52157 51549 52150 52153 51550 51559 52142 52808 51559 51550 51550 51551 52808 51551 52143 52803 51551 52803 52808 52148 52147 51552 52157 51560 51553 52817 52813 51554 51554 51555 52817 51556 51555 51554 53507 52817 51555 51555 52829 53507 51555 52180 52829 51555 51556 52180 51556 51564 52180 51557 52161 52171 52162 51562 51558 51558 51559 52162 52821 52162 51559 53494 52821 51559 51559 52808 53494 52174 51561 51560 51560 52169 52174 51560 52157 52169 51561 52174 52176 52162 51570 51562 52180 51564 51563 52181 52180 51563 51565 51585 52179 52184 51571 51566 52186 52184 51566 51566 52178 52186 51566 52171 52178 52192 52188 51567 52830 52183 51568 51568 52827 52830 51568 51569 52827 51569 52819 52827 51569 51570 52819 53500 52819 51570 51570 52162 53500 51580 51574 51571 52184 51580 51571 51572 51584 51590 51572 51583 51584 51572 51573 51583 52189 51583 51573 52190 52189 51573 51574 51580 51581 53525 52190 51575 51575 52191 53525 52849 51591 51576 51576 51577 52849 51578 51577 51576 51579 51578 51576 53545 52849 51577 51577 52844 53545 51577 51578 52844 51578 52202 52844 51582 51581 51580 52185 51582 51580 51580 52184 52185 52843 51589 51581 51581 51582 52843 51582 52841 52843 51582 52840 52841 53536 52840 51582 51582 52185 53536 52198 51584 51583 51583 52189 52198 52203 51590 51584 51584 52198 52203 52194 52179 51585 51588 51587 51586 52204 52201 51587 52206 52204 51587 51587 51588 52206 52207 52206 51588 51588 51592 52207 52843 52210 51589 52858 52215 51591 51591 52849 52858 51592 51600 52207 51593 51594 52193 52848 52193 51594 52212 51596 51595 52213 51602 51596 51596 52212 52213 51597 51598 52218 52856 52218 51598 51598 52215 52856 51601 51600 51599 52209 52207 51600 51600 51601 52209 52859 52209 51601 52860 52859 51601 51601 52214 52860 51603 51604 52211 51605 51604 51603 51606 51605 51603 51604 51605 52864 52864 52211 51604 51605 52220 52864 51605 51606 52220 52221 52220 51606 51606 51610 52221 52223 51613 51607 52224 52223 51607 52870 52224 51607 51607 52868 52870 51607 51608 52868 51608 52219 52868 51622 51619 51609 52222 52221 51610 52227 52225 51611 51611 51612 52227 51614 51615 51620 51614 51620 52228 51619 51618 51616 51616 51617 51619 51622 51621 51619 51627 51626 51623 52872 51625 51624 52875 52871 51625 51625 52872 52875 52230 51628 51626 51626 51627 52230 52876 52230 51627 51628 52230 52877 52879 51636 51628 51628 52877 52879 52236 51633 51629 51629 51632 52236 51630 51631 52235 52235 52231 51630 52240 52235 51631 52241 52236 51632 52239 52237 51633 52883 52239 51633 51633 52880 52883 51633 52236 52880 52250 51637 51635 52879 52249 51636 52253 51638 51637 51637 52250 52253 52253 52242 51638 51640 51642 51646 51645 51644 51641 52263 51645 51641 52269 52263 51641 52892 52269 51641 51641 52889 52892 51641 52247 52889 51642 51644 51646 51646 51645 51643 51644 51645 51646 52262 51653 51645 52263 52262 51645 52267 51648 51647 52268 51651 51648 51648 52267 52268 52256 52254 51649 52260 52256 51649 51649 51650 52260 52272 52260 51650 52899 51654 51651 51651 52897 52899 51651 52271 52897 51651 52268 52271 51652 51654 51655 53596 51655 51654 51654 52899 53596 53596 51659 51655 52273 52272 51657 51657 51658 52273 53589 52273 51658 51658 52275 53589 52280 52275 51658 52915 52282 51659 53599 52915 51659 51659 53596 53599 51662 51661 51660 51664 51662 51660 51661 52274 52280 52281 52274 51661 51661 51662 52281 51662 51664 52281 52921 52285 51663 51663 52913 52921 52909 52281 51664 53600 52909 51664 51664 52910 53600 52911 52910 51664 52912 52911 51664 51664 51677 52912 51664 51667 51677 52299 51683 51668 52308 52299 51668 51669 51670 51672 51671 51670 51669 51673 51671 51669 51689 51672 51670 51670 51671 51689 52922 51689 51671 51671 52287 52922 51671 51673 52287 51672 51689 51690 51672 51690 51691 51673 51674 52287 52288 52287 51674 51674 51676 52288 51677 52289 52912 51680 51679 51678 51681 51680 51678 52291 51682 51679 52931 52291 51679 51679 52917 52931 51679 51680 52917 52918 52917 51680 52919 52918 51680 52920 52919 51680 51680 52285 52920 51680 51681 52285 51687 51686 51682 52291 51687 51682 52939 52286 51683 51683 52299 52939 52293 51685 51684 52297 52293 51684 51692 51688 51686 51686 51687 51692 52936 51692 51687 51687 52291 52936 51688 52294 52298 51688 51692 52294 52923 51690 51689 51689 52922 52923 51690 52923 52932 53621 51693 51690 51690 52932 53621 52295 52294 51692 52296 52295 51692 52936 52296 51692 52305 52300 51693 53622 52305 51693 51693 53621 53622 52302 51697 51694 51694 51695 52302 52306 52302 51695 51695 52300 52306 51696 51697 52303 51697 52301 52303 52302 52301 51697 52950 52311 51700 52954 52950 51700 51700 52315 52954 51700 51701 52315 52324 52315 51701 51701 52323 52324 51701 51714 52323 51702 52298 52312 52314 51707 51704 51704 51712 52314 51716 51713 51705 51705 51707 51716 51713 51706 51705 51717 51716 51707 52314 51717 51707 52949 52307 51708 52950 52949 51708 51708 52311 52950 52955 52313 51709 52958 52955 51709 51709 51718 52958 51709 51715 51718 52317 51712 51711 52317 52314 51712 51716 51714 51713 51714 51716 52323 51716 52319 52323 51716 52318 52319 51716 51717 52318 52328 52318 51717 52329 52328 51717 52330 52329 51717 51717 52317 52330 51717 52314 52317 51718 52957 52958 51718 52332 52957 51723 51722 51719 51724 51723 51719 51719 51720 51724 52990 51724 51720 51720 52988 52990 53648 52988 51720 51720 53642 53648 51720 53635 53642 51720 52327 53635 52349 51726 51723 51723 51724 52349 52990 52349 51724 51725 52349 52355 51725 51726 52349 51727 52973 52982 52974 52973 51727 51727 51728 52974 53644 52974 51728 53650 52962 51729 51729 51730 53650 54289 53650 51730 51730 52965 54289 51730 52331 52965 52362 51733 51732 51732 52357 52362 51733 52362 52371 52371 51742 51733 51734 51737 52351 51744 51737 51734 51734 51739 51744 53690 53683 51735 51735 51736 53690 51737 51736 51735 52351 51737 51735 52352 52351 51735 53671 52352 51735 53683 53671 51735 54298 53690 51736 54299 54298 51736 54304 54299 51736 51736 53696 54304 51736 51745 53696 51736 51737 51745 51737 51744 51745 52379 51752 51738 51738 52373 52379 52374 52373 51738 51739 51743 51744 51757 51743 51739 51740 51754 52366 51747 51744 51743 51748 51747 51743 51757 51748 51743 51746 51745 51744 52372 51746 51744 51744 51747 52372 51745 53695 53696 51745 53694 53695 51745 53009 53694 51745 51746 53009 51746 53006 53009 51746 52372 53006 53006 52372 51747 51747 52378 53006 51747 51748 52378 51748 51760 52378 51748 51757 51760 51749 53024 54333 51749 52379 53024 52392 52379 51749 51749 51750 52392 51751 51750 51749 54333 51751 51749 51750 52391 52392 53711 52391 51750 51750 53710 53711 51750 51751 53710 55013 53710 51751 51751 55004 55013 55005 55004 51751 51751 54333 55005 52390 51766 51752 52392 52390 51752 51752 52379 52392 52380 51754 51753 52382 52380 51753 52375 52366 51754 52376 52375 51754 53016 52376 51754 51754 53011 53016 51754 52393 53011 51754 52380 52393 52396 52383 51755 52397 52396 51755 51755 51759 52397 51756 52377 52381 52386 51763 51757 51763 51760 51757 51765 51764 51758 52390 51765 51758 51758 51766 52390 51759 51778 52397 51760 51761 52378 51762 51761 51760 51763 51762 51760 52388 52378 51761 53020 52388 51761 51761 52411 53020 51761 52410 52411 52417 52410 51761 51761 52403 52417 51761 51771 52403 51761 51770 51771 51761 51762 51770 51762 51763 51770 52386 51770 51763 51764 51765 52398 52398 51769 51764 51765 52391 52399 51765 52390 52391 52399 52398 51765 51775 51773 51767 52407 51775 51767 53026 52407 51767 51767 51769 53026 51767 51768 51769 51769 52408 53026 52409 52408 51769 51769 52399 52409 51769 52398 52399 52386 51771 51770 51771 52386 52404 52404 52403 51771 53037 52416 51772 51772 51774 53037 51775 51774 51773 51774 51775 53037 53720 53037 51775 51775 52407 53720 52401 52397 51778 52402 52401 51778 51779 51780 51785 51781 51780 51779 51784 51781 51779 51791 51785 51780 52425 51791 51780 51780 52423 52425 51780 51781 52423 51781 52422 52423 51781 51790 52422 51781 51784 51790 52418 51783 51782 52420 52418 51782 52418 52402 51783 51785 51791 51800 51788 51787 51786 51789 51788 51786 52421 51789 51786 51794 51793 51788 51788 51789 51794 53046 51794 51789 51789 52421 53046 52427 51800 51791 51791 52425 52427 53053 52420 51792 53054 53053 51792 51792 51801 53054 51793 51794 51795 51797 51795 51794 52428 51797 51794 53048 52428 51794 51794 53046 53048 51797 51796 51795 51796 51797 51798 51803 51798 51797 52428 51803 51797 51814 51799 51798 51798 51804 51814 51798 51803 51804 51814 51812 51799 52427 52426 51800 51801 52438 53054 51801 52437 52438 51802 51820 52437 51802 51811 51820 51805 51804 51803 52429 51805 51803 51803 52428 52429 52430 51814 51804 52431 52430 51804 51804 51805 52431 53730 52431 51805 51805 53729 53730 51805 53049 53729 51805 52429 53049 51818 51807 51806 52441 51818 51806 51817 51816 51807 51818 51817 51807 51808 51810 51820 51808 51809 51810 51820 51811 51808 53059 51810 51809 51809 52426 53059 53062 52437 51810 51810 52449 53062 52450 52449 51810 53059 52450 51810 52437 51820 51810 51821 51813 51812 51812 51814 51821 51813 51822 52464 51813 51821 51822 52430 51821 51814 51816 51824 51830 51816 51817 51824 51825 51824 51817 53058 51825 51817 51817 52442 53058 51817 51818 52442 51818 52441 52442 52454 52422 51819 51819 51831 52454 51828 51822 51821 51821 51827 51828 52439 51827 51821 51821 52430 52439 51822 51828 52464 53061 53055 51823 53742 53061 51823 51823 53741 53742 52461 51830 51824 53071 52461 51824 53750 53071 51824 51824 51825 53750 54392 53750 51825 51825 54385 54392 51825 53058 54385 51827 52447 52452 51827 52439 52447 51829 51828 51827 52452 51829 51827 51828 52457 52464 52458 52457 51828 51828 51829 52458 53748 52458 51829 51829 53747 53748 51829 52452 53747 51831 52444 52454 51836 51833 51832 51832 51833 51834 51833 51838 52469 51833 51836 51838 51835 51834 51833 52469 51835 51833 52462 52443 51834 53073 52462 51834 53080 53073 51834 51834 51835 53080 53081 53080 51835 51835 52469 53081 51839 51838 51837 52470 52469 51838 52473 52470 51838 51838 51846 52473 51838 51839 51846 51840 52476 52477 51840 52475 52476 51840 52471 52475 51840 51841 52471 51841 52463 52471 52467 52460 51842 52481 52467 51842 52482 52481 51842 52472 51844 51843 51843 51845 52472 52484 51852 51844 53078 52484 51844 53079 53078 51844 53757 53079 51844 51844 53074 53757 51844 52472 53074 52474 52473 51846 52468 51848 51847 51847 52461 52468 53074 52472 51848 53075 53074 51848 51848 52468 53075 52492 52485 51849 51849 51858 52492 51849 51857 51858 51849 51850 51857 53089 52483 51851 53094 53089 51851 51851 52490 53094 53095 51867 51852 51852 52484 53095 52487 52486 51853 53098 52490 51854 53099 53098 51854 51854 52508 53099 51854 52489 52508 51856 51860 53100 51856 51859 51860 52494 52492 51858 51860 51861 53100 53102 53100 51861 53103 53102 51861 51861 52499 53103 53124 52510 51863 53125 53124 51863 51863 51864 53125 51864 52502 53096 51864 51869 52502 51864 53114 53125 53115 53114 51864 51864 53096 53115 52493 51869 51865 53095 52484 51866 51866 51867 53095 52502 52493 51866 54406 52502 51866 51866 53765 54406 51866 53078 53765 51866 52484 53078 51869 52493 52502 52507 52489 51871 51872 52511 52515 53137 53133 51873 53138 53137 51873 51873 52523 53138 51873 51874 52523 51873 52517 52518 53133 52517 51873 51879 51876 51875 51879 51877 51876 53140 52522 51876 53798 53140 51876 51876 53135 53798 51885 51884 51878 51880 51882 52521 51882 52527 52528 51882 51883 52527 52528 52521 51882 52524 52523 51884 52529 52524 51884 51884 51885 52529 51885 51886 52529 51886 51887 52541 52533 52529 51886 52534 52533 51886 52541 52534 51886 51887 51892 52541 51887 51891 51892 52556 51889 51888 53153 52556 51888 51889 51905 51906 52556 51905 51889 53160 52545 51890 53162 53160 51890 53819 53162 51890 52548 51892 51891 51891 51893 52548 52548 52541 51892 51893 51901 52548 51896 51895 51894 51902 51896 51894 55141 51902 51894 51894 53159 55141 51894 51895 53159 51895 52563 53180 51895 51896 52563 53182 53159 51895 51895 53181 53182 51895 53180 53181 51896 51907 52563 51896 51902 51907 52552 51904 51897 51897 51898 52552 51898 52545 52552 52558 52557 51899 51899 51908 52558 51899 51900 51908 52554 52548 51901 52551 51907 51902 53818 52551 51902 54469 53818 51902 55141 54469 51902 51915 51913 51903 52568 51915 51903 53177 52568 51903 51903 53173 53177 51903 51904 53173 51904 52552 52553 51904 52553 53173 53176 52562 51905 51905 52556 53176 52560 52558 51908 51908 52559 52560 52561 51910 51909 52562 52561 51909 52561 51911 51910 53188 52563 51912 51912 52585 53188 51912 52571 52585 51913 52569 53183 51913 51914 52569 51915 51914 51913 51914 51915 52568 53178 52569 51914 51914 52568 53178 51919 51918 51916 51917 51918 51922 52565 51922 51918 51918 52564 52565 51918 51919 52564 53201 51923 51920 53209 53201 51920 51920 53203 53209 51920 53202 53203 51920 52578 53202 51920 51921 52578 53846 52572 51922 51922 52565 53846 51935 51925 51924 51924 51934 51935 51924 51933 51934 51925 51935 52579 52585 52571 51926 51926 51927 52585 53212 52585 51927 51927 51945 53212 51927 51941 51945 51942 51941 51927 51938 51937 51928 51931 51930 51929 51932 51931 51929 53213 51938 51930 53858 53213 51930 51930 51931 53858 51931 53208 53858 51931 51932 53208 52581 51935 51934 53211 52581 51934 53207 52579 51935 51935 53206 53207 51935 52581 53206 52584 51953 51936 51936 52582 52584 51936 52577 52582 52588 51943 51937 52590 52588 51937 51937 51938 52590 53213 52590 51938 53859 53210 51940 51940 53214 53859 51941 51944 51945 52593 51947 51943 51943 52588 52593 51948 51945 51944 51950 51948 51944 51944 51949 51950 51945 51948 53212 52593 51951 51946 51946 51947 52593 51948 51950 53212 51950 52605 53212 51950 52603 52605 52594 51954 51951 51951 52593 52594 51952 52595 52601 51953 53216 53217 51953 52584 53216 52608 51959 51954 51954 52594 52608 51955 52602 52611 51955 51956 52602 51956 51957 52602 51957 52596 52602 52597 52596 51957 51974 51961 51958 52608 52607 51959 51975 51962 51960 51979 51975 51960 51960 51961 51979 51961 51978 51979 51961 51974 51978 51975 51965 51962 53244 53232 51963 51963 51964 53244 51964 52618 53244 51964 52614 52618 51965 51975 52614 51985 51983 51966 51966 51984 51985 52620 51984 51966 51966 52619 52620 51966 51967 52619 51967 52615 52619 51968 52612 53239 51968 51977 52612 51978 51974 51969 53254 51978 51969 51969 51970 53254 51971 51970 51969 53910 53254 51970 51970 51971 53910 53911 53910 51971 51971 51972 53911 51973 51972 51971 54556 53911 51972 54557 54556 51972 51972 53909 54557 51972 51973 53909 51973 53908 53909 51973 52624 53908 51973 52617 52624 52618 52614 51975 53256 52618 51975 51975 51978 53256 51979 51978 51975 51976 51980 51982 51977 51993 52612 51978 53255 53256 51978 53254 53255 51980 51981 51982 51983 51981 51980 51981 51998 52000 51981 51985 51998 51981 51983 51985 51997 51994 51982 52621 51990 51984 51984 52620 52621 51986 51985 51984 51985 51986 51998 51999 51998 51986 51987 51988 51990 51989 51988 51987 51991 51989 51987 51987 51990 51991 51989 51992 51995 51989 51991 51992 52626 51991 51990 51990 52625 52626 51990 52621 52625 52628 51992 51991 53257 52628 51991 51991 52626 53257 51992 52629 52630 51992 52628 52629 53898 52612 51993 53924 53898 51993 52633 52003 51996 52635 52633 51996 51996 52632 52635 51998 51999 52000 52001 52000 51999 52000 52002 52004 54548 53920 52003 54565 54548 52003 52003 52633 54565 52664 52657 52007 53277 52664 52007 52657 52024 52007 52008 52011 52644 52008 52009 52011 52010 52009 52008 52644 52010 52008 52009 52010 52020 52021 52020 52010 52655 52021 52010 53267 52655 52010 52010 52644 53267 52011 52023 52646 52011 52022 52023 52645 52644 52011 52646 52645 52011 53289 52017 52012 52012 52668 53289 52012 52043 52668 52012 52013 52043 52014 52013 52012 52017 52014 52012 52653 52652 52014 52014 52017 52653 52045 52017 52015 52015 52016 52045 52017 52016 52015 53289 52668 52016 52016 52017 53289 52668 52045 52016 52017 52045 52653 52643 52640 52018 52653 52643 52018 52018 52652 52653 52029 52028 52019 52019 52021 52029 52019 52020 52021 52671 52029 52021 52021 52655 52671 52648 52646 52023 52023 52647 52648 52654 52034 52025 52025 52643 52654 53264 52643 52025 53278 53264 52025 52025 52665 53278 52025 52026 52665 52027 52026 52025 52034 52027 52025 53290 52665 52026 52026 52027 53290 52027 52042 53290 52659 52041 52027 52027 52034 52659 52671 52035 52029 52030 52036 52656 52030 52031 52036 52038 52037 52032 53301 52038 52032 53302 53301 52032 52032 52033 53302 52033 53294 53302 52033 52666 53294 52667 52659 52034 52034 52654 52667 52673 52672 52035 52035 52671 52673 52660 52656 52036 52675 52660 52036 52036 52674 52675 52037 52038 52678 53303 52678 52038 52038 53301 53303 52669 52046 52039 52039 52040 52669 52040 52667 52669 52040 52659 52667 52040 52041 52659 53291 53290 52042 52042 53285 53291 54612 53285 52042 52042 53965 54612 52042 53962 53965 52042 53299 53962 52042 52049 53299 52042 52047 52049 52043 52045 52668 52658 52653 52045 53295 52658 52045 52045 52680 53295 52045 52046 52680 52046 52669 52680 52047 52048 52049 52670 52049 52048 52681 52670 52048 52682 52681 52048 52684 52682 52048 52049 52670 53299 53309 52687 52050 53970 53309 52050 53975 53970 52050 52050 53312 53975 52050 53311 53312 52050 52051 53311 52052 52051 52050 52687 52052 52050 52051 52052 53311 53314 53311 52052 53315 53314 52052 52052 52693 53315 52052 52687 52693 52693 52684 52053 52053 52692 52693 52054 52055 52056 52055 52689 52690 52055 52688 52689 52694 52059 52057 52057 52062 52694 52708 52060 52058 52058 52059 52708 54000 53333 52059 52059 52695 54000 52059 52694 52695 53333 52708 52059 52696 52061 52060 52698 52696 52060 52708 52698 52060 52696 52063 52061 52062 52691 53323 53323 52694 52062 52718 52064 52063 52063 52696 52718 52715 52713 52064 52718 52715 52064 52065 52713 52726 52733 52079 52066 52067 52068 52071 52067 52069 52070 52712 52069 52067 52067 52071 52712 52720 52070 52069 52069 52719 52720 52725 52719 52069 52069 52711 52725 52712 52711 52069 52070 52720 52729 52724 52712 52071 52071 52078 52724 52089 52088 52072 52091 52089 52072 52072 52073 52091 52073 52079 52091 52074 52081 53397 52082 52081 52074 52748 52082 52074 52074 52080 52748 52075 52076 52083 52076 52077 52083 52734 52083 52077 52737 52734 52077 52077 52084 52737 52730 52724 52078 52078 52087 52730 52078 52086 52087 52100 52091 52079 52733 52100 52079 52080 52090 52748 52080 52089 52090 52080 52088 52089 54022 53397 52081 52081 52082 54022 54064 54022 52082 52082 52748 54064 53406 52737 52084 52085 52729 52743 52732 52730 52087 52087 52097 52732 52098 52097 52087 52090 52746 52748 52092 52093 52094 53415 52742 52092 52092 52094 53415 52094 52771 53415 52094 52759 52771 52094 52113 52759 52095 52096 52102 52097 52098 52732 52099 52100 52733 53416 52752 52102 52102 52772 53416 52103 52105 52768 52103 52104 52105 52758 52105 52104 52104 52740 52758 52741 52740 52104 52769 52768 52105 52105 52758 52769 52106 52109 52760 52112 52111 52107 52743 52112 52107 52776 52757 52108 52108 52120 52776 53439 52760 52109 52109 52110 53439 52110 52764 53439 52110 52763 52764 52110 52112 52763 52110 52111 52112 52112 52761 52763 52112 52743 52761 52770 52759 52113 52789 52770 52114 52114 52788 52789 52114 52787 52788 52777 52121 52115 52780 52777 52115 52115 52773 52780 52118 52117 52116 52775 52754 52117 52117 52118 52775 54083 52775 52118 52118 53453 54083 53454 53453 52118 54096 53454 52118 52118 52774 54096 54105 53469 52119 52119 54100 54105 52119 53455 54100 52778 52776 52120 52120 52122 52778 54097 52778 52122 54116 54097 52122 52122 52783 54116 52122 52123 52783 52123 52131 52783 52785 52132 52125 52125 52784 52785 52791 52128 52126 53467 52792 52127 54111 53467 52128 52128 54108 54111 52128 52791 54108 52145 52135 52129 52799 52145 52129 52129 52130 52799 54112 52799 52130 52130 53470 54112 52130 53468 53470 53469 53468 52130 52131 52158 52783 52794 52137 52132 52132 52785 52794 52133 52802 53476 52133 52801 52802 52133 52134 52801 52797 52787 52133 53475 52797 52133 53476 53475 52133 52805 52150 52136 52136 52140 52805 52136 52139 52140 52800 52141 52137 52137 52794 52800 52798 52144 52138 52140 52149 52805 52807 52160 52141 52141 52800 52807 52804 52803 52143 52143 52144 52804 52144 52798 52804 53478 52146 52145 52145 53477 53478 52145 52799 53477 52146 53478 53502 53503 52151 52147 52147 52167 53503 52147 52148 52167 52806 52805 52149 52149 52152 52806 52149 52151 52152 52805 52153 52150 52809 52152 52151 53496 52809 52151 53503 53496 52151 52809 52806 52152 52170 52157 52153 52806 52170 52153 52153 52805 52806 52154 52810 53490 52811 52810 52154 52802 52801 52154 53489 52802 52154 53490 53489 52154 52155 52156 52165 52166 52165 52156 53495 52166 52156 52170 52169 52157 54135 52783 52158 52158 53508 54135 52158 52813 53508 52818 52161 52159 52159 52807 52818 52159 52160 52807 52825 52171 52161 52161 52818 52825 52162 52820 53500 52821 52820 52162 52815 52164 52163 52163 52165 52815 54819 54784 52164 52164 54136 54819 52164 52815 54136 52165 52166 52815 53495 52815 52166 54137 53503 52167 52167 52168 54137 52168 53504 54137 52168 52822 53504 52168 52173 52822 52175 52174 52169 52169 52170 52175 52812 52175 52170 52170 52806 52812 52825 52178 52171 52826 52182 52172 53498 52826 52172 52172 52187 53498 52188 52187 52172 52173 52179 52822 52823 52176 52174 52174 52816 52823 52174 52175 52816 52175 52812 52816 52823 52177 52176 53520 53519 52177 52177 52823 53520 52833 52181 52177 53519 52833 52177 53515 52186 52178 52178 52825 53515 52831 52822 52179 52179 52194 52831 52180 52828 52829 52180 52181 52828 52833 52828 52181 53497 52814 52182 52182 52826 53497 52830 52191 52183 52186 52185 52184 52185 52837 53536 52185 52186 52837 52838 52837 52186 53515 52838 52186 53522 53498 52187 52187 52192 53522 52187 52188 52192 52199 52198 52189 53525 52199 52189 52189 52190 53525 52191 53524 53525 52191 52830 53524 52192 52845 53522 52192 52193 52845 52848 52845 52193 52196 52195 52194 52213 52196 52194 53540 52831 52194 52194 53539 53540 52194 52197 53539 52194 52195 52197 52195 52196 52852 52839 52197 52195 53547 52839 52195 52195 52852 53547 52196 52212 52852 52213 52212 52196 54160 53539 52197 52197 53542 54160 52197 52839 53542 53544 52203 52198 52198 52199 53544 54169 53544 52199 52199 53541 54169 52199 53525 53541 52204 52202 52201 53545 52844 52202 52202 52853 53545 52854 52853 52202 53551 52854 52202 52202 53548 53551 52202 52205 53548 52202 52204 52205 52203 52847 52848 53544 52847 52203 52206 52205 52204 53549 53548 52205 52205 52855 53549 52205 52206 52855 52206 52208 52855 52206 52207 52208 52209 52208 52207 52208 52217 52855 52208 52216 52217 52208 52209 52216 52859 52216 52209 52850 52214 52210 52210 52843 52850 52852 52212 52211 52864 52852 52211 52861 52860 52214 52863 52861 52214 52214 52850 52863 52857 52856 52215 52858 52857 52215 53563 53558 52216 52216 52859 53563 53558 52217 52216 53557 52855 52217 53562 53557 52217 52217 53558 53562 52869 52219 52218 52218 52857 52869 52218 52856 52857 52869 52868 52219 52220 52221 52865 52865 52864 52220 52221 52222 52865 52223 52225 52227 52223 52224 52225 52870 52866 52224 52867 52225 52224 52224 52866 52867 53569 52226 52225 52225 52867 53569 54186 53565 52226 52226 53569 54186 53570 52876 52229 52229 52871 53570 52230 52876 52877 52878 52874 52231 52231 52235 52878 52885 52881 52232 55585 52885 52232 52232 53583 55585 52232 52233 53583 52234 52233 52232 52881 52234 52232 52233 53582 53583 54203 53582 52233 52233 52234 54203 52234 53584 54203 52234 52891 53584 52234 52235 52891 52881 52235 52234 52235 52240 52884 52881 52878 52235 52235 52890 52891 52235 52884 52890 52236 52241 52880 52239 52238 52237 52238 52243 52247 52238 52239 52243 53575 52243 52239 52239 52883 53575 52240 52248 52884 52882 52880 52241 52241 52242 52882 53578 52882 52242 52242 52253 53578 52243 52244 52247 52245 52244 52243 53576 52245 52243 52243 53575 53576 52244 52246 52247 52244 52245 52246 54201 52246 52245 54878 54201 52245 52245 54199 54878 52245 54198 54199 52245 53576 54198 52889 52247 52246 52894 52889 52246 53581 52894 52246 54201 53581 52246 52887 52250 52249 52249 52886 52887 53572 52886 52249 52249 52879 53572 53573 52253 52250 52250 52887 53573 53578 52253 52251 54197 53578 52251 54876 54197 52251 52251 54202 54876 52251 52252 54202 52253 52252 52251 52252 52253 53573 52252 53580 54202 52252 53573 53580 52257 52255 52254 52254 52256 52257 53584 52891 52255 52255 52258 53584 52255 52257 52258 52261 52257 52256 52256 52260 52261 52259 52258 52257 52895 52259 52257 52257 52261 52895 54203 53584 52258 54204 54203 52258 52258 52259 54204 52259 52895 54204 52896 52261 52260 52260 52272 52896 54207 52895 52261 52261 52896 54207 52262 52263 52270 52263 52265 52270 52266 52265 52263 52269 52266 52263 52906 52902 52264 53585 52270 52265 52265 52266 53585 52266 52893 53585 52266 52892 52893 52266 52269 52892 52270 53585 53588 53589 52896 52272 52272 52273 53589 52274 52909 53600 52274 52281 52909 52274 52275 52280 52276 52275 52274 53592 52276 52274 53600 53592 52274 52275 52278 53589 52275 52277 52278 52275 52276 52277 53591 52277 52276 53592 53591 52276 54224 53593 52277 54225 54224 52277 54905 54225 52277 52277 53591 54905 52279 52278 52277 53593 52279 52277 52278 52896 53589 54207 52896 52278 52278 52279 54207 52279 54205 54207 52279 53593 54205 52915 52288 52282 52914 52284 52283 53602 53601 52284 52284 52914 53602 52921 52920 52285 52286 52939 53609 53606 52922 52287 52287 52288 53606 53607 53606 52288 52288 53598 53607 52288 52915 53598 52925 52912 52289 52927 52925 52289 52289 52290 52927 52934 52927 52290 52290 52292 52934 53613 52936 52291 52291 52931 53613 52292 52924 52934 52292 52297 52924 52292 52293 52297 52312 52298 52294 52937 52312 52294 52938 52937 52294 52294 52295 52938 53619 52938 52295 52295 53618 53619 52295 52296 53618 52296 52929 53618 53613 52929 52296 52296 52936 53613 52297 52307 52924 52940 52939 52299 52941 52940 52299 52299 52308 52941 52300 52305 52306 52944 52303 52301 52951 52944 52301 53627 52951 52301 54260 53627 52301 52301 52302 54260 52302 54254 54260 52302 53623 54254 52302 52306 53623 54254 53623 52304 52304 52305 54254 52306 52305 52304 53623 52306 52304 54927 54254 52305 52305 54255 54927 52305 53622 54255 52945 52924 52307 52949 52945 52307 52309 52313 52948 52937 52316 52312 52955 52948 52313 52315 52324 52954 52316 52947 53641 52316 52937 52947 53641 52956 52316 52320 52319 52318 52322 52320 52318 52328 52322 52318 52324 52323 52319 52325 52324 52319 52963 52325 52319 52319 52320 52963 53660 52963 52320 53670 53660 52320 54291 53670 52320 54292 54291 52320 52320 53669 54292 52320 53668 53669 52320 52321 53668 52322 52321 52320 52321 52328 53668 52321 52322 52328 53639 52954 52324 53643 53639 52324 52324 52325 53643 52325 52963 53643 53645 53644 52326 52326 53630 53645 52327 52953 53635 52961 52953 52327 52328 52329 53667 52328 53667 53668 52329 52330 52964 52329 52964 53667 52966 52965 52331 52331 52344 52966 53650 52957 52332 52332 52962 53650 52335 52334 52333 52345 52335 52333 52346 52345 52333 52333 52334 52346 52334 52335 52336 52967 52346 52334 53647 52967 52334 52334 52336 53647 52338 52336 52335 52335 52337 52338 52347 52337 52335 52353 52347 52335 52335 52345 52353 52336 52338 54270 54271 53647 52336 52336 54270 54271 52337 52339 52340 52348 52339 52337 52337 52347 52348 52340 52338 52337 52338 52968 54270 52338 52340 52968 52343 52342 52339 52348 52343 52339 52341 52340 52339 52342 52341 52339 53655 52968 52340 52340 53654 53655 52340 52341 53654 52341 52969 53654 52341 52342 52969 52970 52969 52342 52342 52354 52970 52342 52343 52354 52343 52348 52354 52344 52352 52966 52344 52351 52352 52345 52976 52979 52345 52346 52976 52978 52353 52345 52979 52978 52345 52977 52976 52346 53663 52977 52346 52346 52967 53663 52984 52348 52347 52347 52353 52984 52984 52354 52348 53676 52355 52349 52349 53675 53676 53692 53675 52349 52349 52990 53692 52363 52357 52350 52981 52363 52350 52350 52975 52981 53646 52966 52352 53671 53646 52352 52991 52984 52353 52353 52983 52991 52353 52978 52983 52354 52984 52991 52986 52970 52354 52995 52986 52354 53691 52995 52354 52354 52991 53691 53676 52356 52355 53676 52359 52356 52363 52362 52357 52365 52360 52358 53693 52365 52358 52358 52359 53693 52359 53676 53693 52360 52364 52369 52365 52364 52360 53689 53677 52361 52361 52370 53689 53003 52371 52362 53004 53003 52362 52362 52363 53004 54967 53004 52363 52363 54303 54967 52363 52981 54303 53000 52369 52364 53702 53000 52364 53703 53702 52364 52364 53699 53703 52364 52365 53699 52365 53693 53699 52366 52367 52370 52368 52367 52366 53705 52368 52366 52366 52375 53705 53689 52370 52367 54965 53689 52367 52367 52368 54965 54982 54965 52368 52368 53705 54982 53007 52374 52369 52369 53001 53007 52369 53000 53001 53024 52379 52373 52373 53010 53024 52373 53007 53010 52373 52374 53007 52375 52376 53705 52376 53017 53705 52376 53016 53017 52385 52381 52377 52378 52389 53006 52378 52388 52389 52394 52393 52380 52380 52382 52394 52381 52384 52387 52385 52384 52381 52395 52394 52382 52382 52383 52395 52396 52395 52383 53025 52387 52384 53709 53025 52384 52384 53708 53709 52384 52385 53708 52385 53005 53708 52385 53003 53005 53023 52404 52386 52386 52387 53023 53025 53023 52387 53015 52389 52388 53020 53015 52388 53015 53006 52389 52392 52391 52390 54342 53027 52391 52391 53711 54342 53027 52399 52391 53021 53011 52393 52393 52394 53021 52394 52395 53021 53022 53021 52395 52395 52396 53022 53031 53022 52396 52396 52400 53031 52396 52397 52400 52401 52400 52397 53027 52409 52399 53717 53031 52400 52400 53030 53717 53722 53030 52400 53723 53722 52400 52400 52401 53723 52401 52402 53723 52402 53043 53723 52402 52418 53043 52403 52406 52417 52403 52405 52406 52403 52404 52405 52404 53023 53025 53025 52405 52404 52405 54340 54344 52405 53025 54340 54344 52406 52405 53032 52417 52406 53034 53032 52406 54344 53034 52406 52407 53715 53720 52407 53713 53715 52407 53026 53713 53713 53026 52408 54341 53713 52408 52408 52409 54341 54342 54341 52409 52409 53027 54342 52412 52411 52410 52417 52412 52410 53036 53020 52411 53040 53036 52411 52411 52412 53040 52412 53032 53040 52412 52417 53032 52413 52414 52419 52415 52414 52413 52416 52415 52413 53045 52419 52414 52414 52415 53045 53724 53045 52415 52415 53038 53724 52415 52416 53038 52416 53037 53038 53725 53043 52418 52418 53044 53725 52418 52420 53044 53045 52421 52419 53053 53044 52420 52421 53045 53046 52424 52423 52422 52454 52424 52422 52423 52424 52425 52436 52425 52424 52424 52435 52436 53737 52435 52424 52424 52454 53737 53740 52427 52425 54378 53740 52425 52425 54377 54378 52425 54376 54377 52425 52436 54376 52426 52427 53059 53740 53059 52427 53049 52429 52428 52428 53048 53049 52440 52439 52430 52430 52432 52440 52434 52432 52430 52430 52431 52434 53730 52434 52431 52432 52433 53732 52434 52433 52432 52451 52440 52432 53732 52451 52432 52433 52434 53052 52433 53052 53732 53730 53052 52434 53737 52455 52435 53738 52436 52435 52435 52456 53738 52435 52455 52456 52436 53739 54376 52436 53738 53739 53062 52438 52437 53063 53054 52438 52438 53062 53063 52451 52447 52439 52439 52440 52451 53056 52442 52441 53057 53056 52441 52441 53055 53057 53736 53058 52442 52442 53056 53736 52445 52444 52443 52462 52445 52443 52456 52454 52444 52444 52445 52456 53738 52456 52445 54395 53738 52445 52445 52462 54395 52446 53050 53065 53052 53050 52446 53732 53052 52446 52446 52447 53732 52448 52447 52446 53065 52448 52446 53747 52452 52447 52447 52448 53747 52447 52451 53732 54381 53747 52448 54382 54381 52448 52448 53734 54382 52448 53065 53734 53744 53062 52449 53746 53744 52449 52449 52450 53746 52450 53743 53746 52450 53059 53743 52453 52459 53066 52454 52455 53737 52456 52455 52454 53069 52464 52457 52457 53067 53069 53068 53067 52457 53751 53068 52457 52457 53748 53751 52457 52458 53748 53070 53066 52459 52459 52460 53070 52460 52465 53070 52467 52465 52460 53071 52468 52461 52462 53759 54395 52462 53072 53759 53073 53072 52462 52475 52471 52463 53077 52475 52463 54391 53070 52465 54400 54391 52465 52465 54399 54400 52465 52466 54399 52467 52466 52465 55061 54399 52466 52466 53763 55061 53764 53763 52466 52466 52481 53764 52466 52467 52481 52468 53071 53076 53076 53075 52468 52469 52470 53081 53762 53081 52470 52470 53085 53762 53086 53085 52470 52470 53084 53086 52470 52473 53084 53090 53084 52473 52473 52474 53090 52474 52478 53090 53754 52476 52475 52475 53753 53754 52475 53077 53753 53083 52477 52476 54403 53083 52476 52476 53754 54403 53088 53087 52477 52477 53083 53088 53087 52479 52477 52478 52485 53090 53087 52480 52479 53087 52488 52480 52481 53760 53764 52481 53089 53760 52481 52482 53089 52482 52483 53089 53093 53090 52485 52485 52501 53093 52485 52492 52501 52486 52487 52498 53107 52498 52487 52487 52488 53107 52488 53091 53107 52488 53087 53091 52489 52507 52508 53098 53094 52490 52492 52495 52501 52500 52495 52492 52492 52494 52500 52494 52497 52500 52504 52497 52494 52494 52503 52504 53097 52501 52495 53766 53097 52495 53767 53766 52495 52495 53105 53767 52495 52496 53105 52497 52496 52495 52500 52497 52495 53119 53105 52496 52496 53101 53119 52496 52497 53101 52497 52504 53101 52498 53107 53108 53126 53103 52499 53097 53093 52501 52502 54406 54410 54410 53096 52502 53117 52504 52503 53118 53117 52503 52503 53116 53118 53117 53101 52504 53122 52506 52505 52505 53121 53122 52509 52507 52506 53109 52509 52506 53775 53109 52506 52506 53122 53775 52509 52508 52507 53776 53110 52508 52508 53123 53776 52508 53109 53123 52508 52509 53109 53110 53099 52508 52510 53124 54426 52511 52514 52515 53788 53126 52512 54432 53788 52512 52512 53134 54432 52512 52513 53134 52513 52520 53134 52516 52515 52514 53133 53130 52517 53130 52519 52517 52520 52521 53134 54438 53134 52521 52521 52528 54438 52522 52540 53139 53140 52540 52522 53806 53138 52523 52523 52535 53806 52523 52524 52535 52524 52533 52535 52524 52529 52533 53808 52526 52525 52525 53800 53808 52525 53132 53800 53808 53154 52526 52536 52528 52527 53141 52536 52527 52527 52543 53141 52528 52536 53802 54450 54438 52528 55124 54450 52528 55126 55124 52528 55857 55126 52528 52528 55127 55857 52528 54453 55127 52528 54452 54453 52528 54451 54452 52528 53809 54451 52528 53802 53809 52546 52542 52530 52547 52546 52530 52530 52537 52547 52530 52531 52537 52531 52532 52538 52538 52537 52531 52539 52538 52532 52533 52534 52535 53147 52535 52534 53820 53147 52534 52534 53168 53820 52534 52541 53168 52535 53147 53806 52536 53155 53802 52536 52543 53155 53141 52543 52536 53148 52547 52537 52537 52538 53148 53149 53148 52538 52538 52539 53149 52539 53144 53149 52539 53143 53144 52539 52540 53143 52540 53142 53143 52540 53140 53142 53816 53168 52541 52541 52549 53816 52550 52549 52541 52541 52548 52550 52542 52546 53163 53815 53155 52543 52543 53158 53815 52543 52544 53158 52544 52551 53158 53160 52552 52545 53164 53163 52546 53165 53164 52546 52546 52547 53165 52547 53148 53165 52554 52550 52548 52549 52550 53166 53817 53816 52549 52549 53166 53817 52550 52554 53166 53818 53158 52551 53160 52553 52552 52553 53169 53173 52553 53161 53169 52553 53160 53161 52554 52555 53166 53167 53166 52555 52555 52557 53167 52556 53157 53176 52556 53153 53157 53175 53167 52557 52557 53174 53175 52557 52558 53174 52558 52560 53174 53179 52560 52559 53185 53179 52559 52559 53184 53185 53179 53174 52560 52561 52567 53840 52561 52562 52567 53186 52567 52562 52562 53176 53186 53188 53180 52563 52566 52565 52564 53840 52566 52564 52565 53196 53846 52565 52566 53196 54491 53196 52566 54492 54491 52566 52566 53840 54492 52567 53187 53840 52567 53186 53187 52568 53177 53178 53190 53183 52569 53191 53190 52569 53845 53191 52569 52569 53189 53845 52569 53178 53189 53836 53184 52570 52570 53195 53836 53198 52578 52572 53846 53198 52572 52573 52574 53199 52575 52574 52573 53200 52575 52573 53851 53200 52573 53852 53851 52573 52573 53850 53852 52573 53199 53850 52574 52580 53199 52574 52577 52580 52574 52575 52577 52582 52577 52575 53200 52582 52575 52580 52577 52576 53199 52580 52576 52576 52579 53199 53204 53202 52578 52578 53198 53204 53207 53199 52579 52581 53211 53215 52581 53205 53206 53856 53205 52581 52581 53215 53856 53200 52584 52582 53218 53214 52583 52583 52592 53218 53863 53216 52584 52584 53200 53863 52585 52586 53197 52587 52586 52585 53212 52587 52585 53834 53188 52585 52585 53197 53834 52586 54509 55194 52586 52587 54509 55194 53197 52586 52587 53220 54509 52587 53212 53220 53221 52593 52588 52588 52589 53221 52590 52589 52588 53228 53221 52589 53864 53228 52589 52589 52590 53864 52590 53860 53864 52590 53213 53860 53225 53222 52591 52591 53223 53225 53224 53223 52591 52591 52601 53224 52592 53222 53225 53219 53218 52592 53225 53219 52592 53230 52594 52593 52593 53228 53230 52593 53221 53228 52610 52608 52594 52594 52609 52610 53230 52609 52594 53224 52601 52595 53232 53224 52595 52606 52602 52596 52596 52597 52606 53871 52606 52597 52597 53226 53871 54523 54513 52598 52598 53876 54523 53877 53876 52598 52598 52599 53877 52600 52599 52598 54513 52600 52598 52599 52604 53877 52605 52604 52599 53212 52605 52599 52599 52600 53212 53220 53212 52600 54511 53220 52600 54512 54511 52600 54513 54512 52600 53881 53880 52602 53889 53881 52602 52602 53888 53889 52602 52606 53888 53880 52611 52602 52603 52604 52605 53234 52604 52603 54531 53877 52604 54532 54531 52604 54537 54532 52604 52604 54536 54537 52604 53890 54536 52604 53234 53890 52606 53871 53888 52607 52608 52610 53235 52613 52607 52607 52610 53235 53884 52610 52609 52609 53230 53884 53237 53235 52610 53884 53237 52610 52611 52622 53238 53880 52622 52611 53890 53239 52612 54541 53890 52612 52612 53898 54541 52613 52616 52617 53235 52616 52613 53238 52619 52615 52623 52617 52616 53243 52623 52616 52616 53241 53243 52616 53240 53241 52616 53235 53240 52617 52623 52624 53903 53244 52618 52618 53249 53903 53250 53249 52618 53256 53250 52618 52622 52620 52619 53238 52622 52619 52622 52621 52620 53245 52625 52621 52621 52622 53245 53886 53245 52622 52622 53880 53886 53908 52624 52623 52623 53243 53908 52627 52626 52625 53245 52627 52625 53258 53257 52626 52626 52627 53258 53896 53258 52627 53897 53896 52627 52627 53895 53897 52627 53245 53895 53259 52629 52628 52628 53257 53259 52631 52630 52629 53259 52631 52629 53931 52634 52630 52630 52631 53931 52631 53262 53931 52631 53261 53262 54564 53261 52631 52631 53923 54564 52631 53259 53923 53936 52635 52632 52632 53263 53936 53935 53934 52633 52633 52635 53935 54571 54565 52633 54572 54571 52633 52633 53934 54572 53931 52641 52634 53936 53935 52635 52636 52637 52640 52638 52637 52636 53940 52638 52636 53942 53940 52636 52636 53938 53942 52636 53266 53938 52636 52643 53266 52636 52640 52643 52637 52638 52639 53937 52639 52638 54584 53937 52638 54587 54584 52638 52638 53940 54587 53937 53263 52639 53260 52642 52641 53931 53260 52641 53946 53265 52642 52642 53260 53946 52643 53264 53266 52643 52653 52654 52644 52645 53267 53953 53267 52645 52645 53947 53953 53949 53947 52645 52645 52646 53949 52646 52648 53949 52649 52648 52647 52650 52649 52647 52651 52650 52647 52656 52651 52647 52648 52649 53949 54597 53948 52649 54598 54597 52649 52649 53268 54598 52649 52650 53268 52649 53948 53949 52650 52661 53268 52650 52651 52661 52663 52661 52651 52651 52656 52663 52658 52654 52653 52680 52667 52654 52654 52658 52680 53958 52671 52655 52655 53957 53958 52655 53267 53957 52656 52660 52663 53288 53287 52657 52657 52664 53288 53294 52666 52657 52657 53287 53294 53295 52680 52658 52660 52675 53296 52660 52661 52663 52662 52661 52660 53296 52662 52660 53269 53268 52661 53270 53269 52661 52661 52662 53270 53297 53270 52662 52662 53296 53297 53956 53288 52664 52664 53955 53956 52664 53277 53955 53290 53278 52665 52680 52669 52667 53962 53299 52670 53969 53962 52670 52670 52681 53969 53300 52673 52671 53963 53300 52671 52671 53958 53963 53305 52683 52672 52672 52673 53305 53966 53305 52673 52673 53300 53966 53296 52675 52674 52674 52676 53296 53297 53296 52676 53298 53297 52676 52676 52677 53298 53307 53298 52677 53973 53307 52677 52677 53308 53973 52677 52679 53308 53967 52679 52678 52678 53304 53967 52678 53303 53304 53967 53308 52679 52681 52682 53969 53970 53969 52682 52682 53309 53970 52682 52687 53309 52682 52684 52687 52693 52687 52684 53310 52689 52685 54654 53310 52685 52685 54653 54654 52685 52686 54653 52686 53984 54653 52686 53306 53984 53310 52690 52689 54660 53987 52690 52690 54654 54660 52690 53310 54654 53994 53323 52691 52691 53988 53994 53325 52693 52692 53334 53325 52692 52692 52697 53334 53326 53315 52693 52693 53325 53326 53994 52695 52694 52694 53323 53994 54673 54000 52695 52695 53998 54673 52695 53997 53998 52695 53994 53997 53365 52718 52696 52696 52708 53365 52696 52698 52708 54002 53334 52699 52699 52709 54002 53384 53348 52700 53348 52710 52700 52701 52702 52711 52703 52702 52701 52711 52703 52701 53380 52725 52702 52702 52704 53380 52702 52703 52704 52725 52711 52702 52705 52704 52703 52706 52705 52703 52712 52706 52703 52703 52711 52712 52704 53363 53380 54006 53363 52704 54686 54006 52704 54687 54686 52704 54688 54687 52704 52704 54008 54688 52704 53381 54008 52704 53364 53381 52704 52705 53364 54013 53364 52705 52705 53393 54013 52705 52707 53393 52705 52706 52707 52706 52712 52723 52723 52707 52706 52707 52722 53393 52707 52721 52722 52723 52721 52707 53383 53365 52708 52708 53333 53383 52709 53347 54002 53348 53347 52709 52709 52710 53348 52724 52723 52712 53395 52726 52713 52713 52714 53395 52715 52714 52713 54034 53395 52714 52714 52716 54034 52718 52716 52714 52714 52715 52718 52716 52717 54034 52718 52717 52716 54049 54034 52717 54709 54049 52717 52717 54707 54709 52717 54689 54707 52717 52718 54689 52718 53365 54689 52719 54713 54714 52719 54047 54713 52719 52725 54047 54048 52720 52719 54714 54048 52719 54063 52729 52720 52720 54048 54063 52721 52724 52730 52721 52723 52724 53401 52722 52721 52721 52744 53401 52721 52730 52744 54700 53393 52722 54706 54700 52722 52722 53401 54706 52725 53392 54047 52725 53380 53392 53396 52728 52726 52726 53395 53396 53397 53394 52727 52745 52731 52728 54059 52745 52728 52728 53396 54059 54063 52743 52729 52730 52731 52744 52732 52731 52730 52745 52744 52731 52736 52735 52734 52737 52736 52734 52735 52736 53407 53407 52750 52735 52736 52737 53407 52737 53406 53407 53407 53406 52738 53411 53407 52738 53412 53411 52738 53413 53412 52738 53420 53413 52738 52738 53419 53420 52738 52739 53419 52739 52756 53419 52740 52751 52758 52740 52741 52751 53408 52751 52741 53414 53408 52741 52741 53409 53414 52741 52742 53409 54067 53409 52742 52742 53415 54067 52762 52761 52743 54063 52762 52743 53402 53401 52744 52744 52745 53402 54060 53402 52745 52745 54059 54060 52749 52748 52746 52753 52749 52746 52746 52747 52753 52754 52753 52747 54065 54064 52748 54066 54065 52748 52748 52749 54066 52749 53403 54066 52749 52753 53403 53410 52755 52750 52750 53407 53410 53434 52758 52751 52751 53408 53434 53416 52773 52752 53425 53403 52753 52753 52754 53425 54084 53425 52754 52754 54083 54084 52754 52775 54083 52767 52765 52755 53427 52767 52755 52755 53410 53427 53420 53419 52756 53445 53420 52756 52756 53429 53445 52756 52757 53429 52757 52776 53429 53430 52769 52758 53431 53430 52758 53434 53431 52758 53422 52771 52759 52759 53421 53422 52759 52770 53421 53436 52772 52760 53439 53436 52760 53423 52763 52761 53424 53423 52761 52761 52762 53424 54750 54076 52762 52762 53400 54750 52762 53399 53400 54063 53399 52762 54076 53424 52762 53442 52764 52763 52763 53423 53442 52764 53451 54094 52764 53442 53451 53441 53439 52764 54090 53441 52764 54094 54090 52764 52767 52766 52765 52766 53426 53455 52766 52767 53426 53427 53426 52767 52768 52769 53446 52769 53430 53446 53435 53421 52770 52770 52789 53435 54071 53415 52771 52771 53422 54071 54079 53416 52772 52772 53437 54079 52772 53436 53437 53458 52780 52773 52773 53416 53458 52774 54095 54096 52774 53459 54095 53444 53429 52776 54097 53444 52776 52776 52778 54097 52780 52779 52777 53462 52790 52779 52779 52780 53462 53463 53462 52780 52780 53458 53463 55496 54772 52781 52781 55495 55496 52781 52782 55495 52782 54783 55495 54784 54783 52782 55491 54116 52783 52783 54135 55491 52786 52785 52784 53447 52786 52784 53484 52794 52785 53485 53484 52785 52785 53473 53485 53474 53473 52785 54107 53474 52785 52785 53471 54107 53472 53471 52785 52785 52786 53472 52786 53447 53472 52797 52788 52787 53466 52789 52788 54099 53466 52788 52788 52795 54099 52797 52795 52788 53466 53435 52789 54110 52791 52790 52790 53462 54110 54109 54108 52791 54110 54109 52791 54118 52793 52792 52792 54111 54118 52792 53467 54111 54118 53480 52793 53484 52800 52794 52797 52796 52795 54771 54099 52795 52795 54126 54771 52795 52796 54126 52796 52797 53475 52796 54125 54126 52796 53475 54125 53481 52804 52798 52798 53480 53481 54112 53477 52799 53483 52807 52800 53484 53483 52800 53489 53476 52802 52803 52804 54127 53494 52808 52803 54127 53494 52803 52804 53487 54127 53488 53487 52804 52804 53481 53488 52806 52809 52812 52807 53483 54124 54123 52818 52807 54124 54123 52807 52816 52812 52809 53496 52816 52809 52810 52811 52814 52810 52814 53490 52813 52817 53508 53497 53490 52814 52815 54134 54136 52815 53495 54134 52824 52823 52816 53496 52824 52816 52817 53507 53508 53509 52825 52818 53510 53509 52818 54794 53510 52818 52818 54123 54794 53517 52827 52819 52819 53500 53517 54131 53500 52820 54132 54131 52820 52820 52821 54132 54133 54132 52821 52821 53494 54133 53511 53504 52822 52822 52831 53511 53521 53520 52823 52823 52824 53521 52824 53505 53521 52824 53496 53505 52825 53509 53515 53498 53497 52826 53516 52830 52827 53517 53516 52827 53530 52836 52828 52828 52832 53530 52833 52832 52828 52834 52829 52828 52836 52834 52828 52829 52835 53507 52829 52834 52835 52830 53516 53524 53540 53511 52831 54158 53530 52832 52832 54147 54158 52832 52833 54147 52833 53519 54147 52836 52835 52834 53514 53507 52835 54150 53514 52835 52835 53533 54150 52835 53531 53533 52835 53529 53531 52835 52836 53529 53530 53529 52836 54159 53536 52837 52837 53534 54159 53535 53534 52837 52837 52838 53535 52838 53515 53535 54835 53542 52839 52839 53547 54835 52842 52841 52840 54159 52842 52840 52840 53536 54159 53543 52843 52841 54167 53543 52841 52841 52842 54167 54834 54167 52842 52842 54833 54834 52842 54159 54833 52851 52850 52843 53543 52851 52843 52848 52847 52845 53523 53522 52845 53546 53523 52845 54168 53546 52845 52845 52846 54168 52847 52846 52845 52846 53544 54168 52846 52847 53544 53556 52858 52849 54170 53556 52849 54171 54170 52849 52849 53545 54171 53561 52863 52850 52850 53552 53561 52850 52851 53552 54172 53552 52851 54176 54172 52851 52851 53543 54176 52852 52864 53547 54173 53545 52853 54846 54173 52853 52853 52854 54846 54848 54846 52854 54851 54848 52854 52854 53551 54851 53557 53549 52855 53554 52869 52857 52857 52858 53554 53556 53554 52858 52859 52860 53563 54182 53563 52860 52860 53564 54182 52860 52861 53564 52861 52862 53564 52863 52862 52861 54177 53564 52862 52862 52863 54177 52863 53561 54177 52864 52865 53550 53550 53547 52864 52865 53565 54184 54184 53550 52865 52866 52870 53568 53566 52867 52866 54189 53566 52866 52866 53568 54189 52867 53567 53569 52867 53566 53567 53568 52870 52868 52868 52869 53568 54183 53568 52869 52869 54179 54183 52869 53554 54179 54193 53570 52871 52871 54192 54193 52871 52875 54192 52872 52873 52875 52874 52873 52872 54192 52875 52873 52873 54191 54192 52873 53571 54191 52873 52874 53571 52874 52878 53571 54193 53572 52876 52876 53570 54193 53572 52877 52876 53572 52879 52877 54871 53571 52878 52878 52885 54871 52878 52881 52885 53574 52883 52880 52880 52882 53574 53579 53574 52882 52882 53578 53579 53576 53575 52883 52883 53574 53576 55585 54871 52885 54194 53577 52886 52886 53572 54194 52888 52887 52886 53577 52888 52886 52887 52888 53573 53580 53573 52888 52888 53577 53580 52894 52892 52889 52894 52893 52892 52893 52894 53581 53590 53585 52893 54206 53590 52893 52893 53581 54206 54205 54204 52895 54207 54205 52895 52897 52898 52899 53596 52899 52898 52898 53595 53596 52898 53594 53595 52898 52900 53594 52900 52901 53594 52901 52907 53594 52901 52903 52907 53597 52905 52902 52902 52906 53597 54236 52913 52904 54238 54236 52904 52904 52905 54238 52905 54232 54238 52905 53597 54232 54228 53597 52906 54233 54229 52907 52907 52908 54233 54229 53594 52907 52908 53601 54233 52910 53591 53600 53603 53591 52910 55643 53603 52910 52910 54246 55643 52910 53610 54246 52910 52916 53610 52910 52911 52916 52925 52916 52911 52911 52912 52925 54236 52921 52913 54241 53602 52914 52914 53609 54241 53599 53598 52915 53612 53610 52916 52916 52928 53612 52916 52925 52928 52917 52926 52931 52917 52918 52926 53604 52926 52918 52918 52919 53604 52919 52920 53604 52920 52921 53604 54234 53604 52921 54235 54234 52921 54236 54235 52921 52933 52923 52922 53606 52933 52922 52933 52932 52923 52935 52934 52924 53617 52935 52924 52924 52945 53617 52925 52927 52928 52926 52930 52931 53604 52930 52926 52935 52928 52927 52927 52934 52935 52928 53611 53612 52928 52935 53611 54921 53618 52929 52929 54250 54921 52929 52930 54250 52931 52930 52929 53613 52931 52929 54919 54250 52930 52930 53605 54919 52930 53604 53605 52932 52933 54248 54248 53621 52932 52933 54244 54248 52933 54243 54244 52933 53606 54243 53617 53611 52935 52937 52942 52947 52937 52938 52942 52943 52942 52938 53619 52943 52938 52939 53608 53609 52939 52940 53608 54920 53608 52940 54922 54920 52940 52940 53620 54922 52940 52941 53620 52942 52946 52947 52942 52943 52946 53619 52946 52943 52944 52952 52961 52944 52951 52952 53625 53617 52945 53639 53625 52945 52945 52949 53639 53619 53615 52946 54265 52947 52946 52946 53615 54265 54265 53641 52947 53629 53628 52948 52948 52959 53629 52948 52955 52959 52949 52950 53639 52950 52954 53639 52953 52952 52951 53634 52953 52951 52951 53627 53634 52952 52953 52961 54275 53635 52953 52953 53634 54275 52955 52958 52959 53641 53630 52956 52960 52958 52957 53650 52960 52957 52960 52959 52958 53632 53629 52959 52959 52960 53632 54936 53632 52960 55670 54936 52960 52960 54282 55670 52960 53650 54282 52963 53638 53643 53649 53638 52963 53660 53649 52963 53678 53667 52964 52964 53677 53678 52965 53646 54289 52965 52966 53646 52967 53662 53663 54945 53662 52967 52967 54285 54945 52967 53647 54285 54946 54269 52968 52968 54272 54946 52968 53655 54272 52968 54269 54270 53657 53654 52969 52969 52972 53657 52969 52971 52972 52969 52970 52971 52985 52971 52970 52986 52985 52970 52980 52972 52971 52987 52980 52971 52971 52985 52987 53666 53657 52972 52972 52980 53666 54280 52982 52973 54281 54280 52973 52973 54278 54281 52973 52974 54278 54944 54278 52974 52974 54268 54944 52974 53645 54268 52974 53644 53645 52982 52981 52975 52976 54294 54295 52976 52977 54294 54295 52979 52976 52977 53661 54294 53663 53661 52977 52978 52979 52983 53686 52983 52979 53687 53686 52979 54295 53687 52979 52980 52988 53666 52989 52988 52980 52980 52987 52989 52981 53682 54303 52981 52982 53682 54280 53682 52982 53688 52991 52983 52983 53686 53688 52994 52987 52985 52996 52994 52985 52997 52996 52985 52985 52995 52997 52985 52986 52995 52992 52989 52987 52993 52992 52987 52994 52993 52987 52988 53648 53666 52988 52989 52990 52992 52990 52989 52990 52999 53692 52990 52992 52999 54300 53691 52991 54310 54300 52991 52991 54305 54310 52991 53688 54305 52992 52993 52999 53697 52999 52993 54314 53697 52993 52993 52994 54314 52994 54313 54314 52994 52996 54313 52998 52997 52995 53691 52998 52995 52996 54312 54313 52996 52997 54312 52997 54309 54312 52997 52998 54309 52998 54300 54309 52998 53691 54300 52999 53697 53701 52999 53674 53692 53698 53674 52999 53701 53698 52999 53002 53001 53000 53702 53002 53000 53008 53007 53001 53001 53002 53008 53702 53008 53002 53003 53004 53005 53704 53005 53004 54967 53704 53004 54317 53708 53005 54328 54317 53005 53005 53704 54328 53012 53009 53006 53015 53012 53006 53703 53010 53007 53007 53008 53703 53008 53702 53703 53009 53013 53694 53009 53012 53013 54334 53024 53010 53010 54316 54334 53010 53703 54316 53017 53016 53011 53018 53017 53011 53021 53018 53011 53012 53015 53706 53014 53013 53012 53706 53014 53012 53700 53694 53013 54968 53700 53013 54983 54968 53013 53013 54319 54983 53013 54318 54319 53013 53014 54318 54323 54318 53014 54329 54323 53014 53014 53706 54329 53712 53706 53015 53015 53019 53712 53020 53019 53015 54331 53705 53017 53017 53018 54331 54997 54331 53018 54999 54997 53018 55006 54999 53018 53018 55002 55006 53018 55001 55002 53018 53028 55001 53707 53028 53018 53018 53021 53707 54345 53712 53019 54347 54345 53019 53019 53035 54347 53036 53035 53019 53019 53020 53036 53021 53031 53707 53021 53022 53031 54334 54333 53024 53025 54332 54340 53025 53709 54332 53028 53029 55001 53030 53029 53028 53717 53030 53028 53028 53707 53717 55002 55001 53029 53029 54351 55002 53029 54350 54351 54357 54350 53029 53029 53030 54357 53030 53722 54357 53717 53707 53031 53032 53033 53040 53034 53033 53032 54361 53040 53033 53033 54360 54361 53033 53034 54360 53034 54353 54360 53034 54344 54353 54355 54347 53035 53035 53040 54355 53035 53036 53040 53039 53038 53037 53720 53039 53037 53038 53039 53724 54356 53724 53039 53039 53721 54356 53039 53720 53721 53040 53041 54355 53042 53041 53040 54361 53042 53040 53041 53718 54355 53719 53718 53041 53041 53042 53719 54361 53719 53042 54359 53723 53043 54363 54359 53043 53043 53725 54363 53044 53053 53725 53047 53046 53045 53724 53047 53045 53726 53048 53046 53046 53047 53726 53727 53726 53047 53047 53724 53727 53731 53049 53048 53048 53726 53731 54370 53729 53049 53049 54369 54370 53049 53731 54369 53735 53065 53050 54362 53735 53050 55022 54362 53050 53050 53051 55022 53052 53051 53050 53051 55020 55022 53051 55018 55020 53051 53730 55018 53051 53052 53730 53733 53725 53053 53053 53054 53733 55031 53733 53054 53054 53063 55031 53060 53057 53055 53061 53060 53055 54374 53736 53056 53056 53057 54374 53057 53060 54374 53058 53736 54385 53059 53740 53743 53060 53061 54374 54375 54374 53061 53061 53742 54375 53064 53063 53062 54380 53064 53062 53062 53744 54380 55032 55031 53063 55041 55032 53063 53063 55036 55041 53063 53064 55036 53064 54380 55036 53735 53734 53065 55051 53745 53066 53066 53070 55051 53745 53741 53066 53752 53069 53067 53067 53068 53752 54397 53752 53068 55045 54397 53068 53068 53751 55045 53070 54390 55051 54391 54390 53070 54392 53076 53071 53071 53750 54392 55066 53759 53072 53072 54401 55066 53072 53073 54401 53073 53761 54401 53073 53080 53761 53074 53075 53757 54392 53757 53075 53075 53076 54392 53077 53752 53753 53078 53758 53765 53078 53079 53758 53079 53757 53758 53080 53082 53761 53080 53081 53082 53762 53082 53081 54402 54401 53082 53082 53762 54402 54401 53761 53082 53092 53088 53083 54403 53092 53083 53090 53086 53084 53085 53086 54415 55093 53762 53085 55094 55093 53085 53085 54415 55094 53086 53097 53766 53086 53093 53097 53086 53090 53093 53086 53766 54415 53087 53088 53091 53092 53091 53088 53769 53760 53089 53089 53098 53769 53089 53094 53098 53091 53106 53107 55096 53106 53091 55103 55096 53091 53091 55081 55103 53091 53092 55081 53092 54403 55081 54410 53115 53096 53098 53768 53769 53098 53111 53768 53098 53099 53111 53099 53110 53111 53101 53117 53119 53783 53116 53102 53102 53104 53783 53102 53103 53104 53126 53104 53103 53786 53783 53104 54421 53786 53104 53104 53126 54421 53105 53120 53767 53105 53119 53120 53122 53121 53106 55096 53122 53106 53108 53107 53106 53121 53108 53106 53784 53123 53109 53109 53775 53784 53776 53111 53110 53111 53112 53768 53113 53112 53111 53776 53113 53111 54409 53768 53112 53112 53770 54409 53772 53770 53112 53778 53772 53112 53112 53113 53778 53113 53777 53778 53113 53776 53777 53779 53125 53114 53114 53773 53779 53114 53115 53773 53779 53773 53115 54410 53779 53115 53127 53118 53116 53128 53127 53116 53783 53128 53116 53127 53119 53117 53117 53118 53127 53774 53120 53119 53119 53129 53774 53119 53127 53129 54418 53767 53120 53120 53794 54418 53120 53774 53794 54422 53775 53122 55098 54422 53122 53122 55096 55098 53777 53776 53123 53785 53777 53123 54423 53785 53123 53123 54419 54423 53123 53784 54419 54430 54426 53124 53124 53779 54430 53124 53125 53779 53126 53788 54421 53791 53129 53127 53792 53791 53127 53127 53790 53792 53127 53128 53790 53128 53789 53790 53128 53783 53789 53791 53774 53129 53132 53131 53130 53133 53132 53130 53801 53800 53132 53132 53133 53801 54444 53801 53133 53133 53799 54444 53133 53137 53799 54438 54432 53134 53135 53797 53798 53135 53136 53797 54442 53797 53136 53136 54427 54442 53806 53147 53137 53137 53138 53806 53137 53146 53799 53147 53146 53137 53798 53142 53140 53805 53143 53142 53142 53803 53805 53142 53798 53803 53145 53144 53143 53805 53145 53143 53152 53149 53144 53144 53145 53152 53145 53151 53152 54457 53151 53145 53145 53805 54457 54445 53799 53146 54447 54445 53146 54448 54447 53146 53146 53147 54448 53147 53820 54448 53148 53156 53165 53148 53149 53156 53149 53152 53156 54470 54459 53150 53150 54462 54470 53150 53151 54462 53152 53151 53150 54459 53152 53150 53151 54457 54462 54459 53156 53152 53153 53154 53157 53814 53157 53154 54454 53814 53154 53154 53808 54454 54460 53813 53155 53155 53811 54460 53812 53811 53155 53815 53812 53155 53813 53802 53155 53827 53165 53156 54461 53827 53156 53156 54459 54461 54463 53176 53157 54464 54463 53157 55131 54464 53157 53157 53814 55131 53818 53815 53158 53159 53830 55141 53159 53182 53830 53162 53161 53160 53172 53169 53161 53825 53172 53161 55149 53825 53161 53161 53823 55149 53161 53162 53823 54472 53823 53162 53162 53819 54472 53826 53819 53163 53163 53164 53826 53827 53826 53164 53164 53165 53827 54475 53817 53166 53166 53167 54475 55159 54475 53167 53167 53832 55159 53833 53832 53167 53167 53175 53833 55136 53820 53168 55137 55136 53168 55144 55137 53168 53168 53816 55144 53177 53173 53169 53169 53170 53177 53171 53170 53169 53172 53171 53169 53178 53177 53170 53835 53178 53170 54473 53835 53170 53170 53171 54473 54474 54473 53171 53171 54471 54474 53171 53172 54471 53172 53824 54471 53825 53824 53172 53831 53175 53174 53174 53179 53831 53175 53831 53833 53821 53186 53176 53822 53821 53176 54463 53822 53176 53842 53189 53178 53178 53835 53842 53179 53185 53831 53180 53188 53834 53834 53181 53180 53834 53830 53181 53830 53182 53181 53183 53190 53194 53836 53185 53184 53837 53831 53185 54488 53837 53185 53185 53843 54488 53185 53836 53843 53841 53187 53186 53186 53821 53841 53187 53838 53840 53839 53838 53187 55158 53839 53187 53187 53841 55158 54494 53845 53189 53189 53844 54494 53189 53842 53844 53190 53191 53194 53193 53192 53191 53845 53193 53191 53191 53192 53194 53192 53193 55177 53195 53194 53192 54495 53195 53192 54497 54495 53192 55177 54497 53192 53193 55175 55177 53193 53845 55175 53843 53836 53195 54495 53843 53195 53847 53846 53196 54491 53847 53196 54484 53834 53197 55195 54484 53197 53197 55194 55195 54498 53204 53198 53198 53847 54498 53198 53846 53847 53199 53848 53850 53199 53207 53848 54508 53863 53200 55208 54508 53200 53200 54499 55208 53200 53851 54499 53209 53208 53201 53855 53203 53202 53202 53204 53855 53853 53209 53203 53854 53853 53203 55199 53854 53203 53203 53855 55199 54498 53855 53204 53207 53206 53205 53848 53207 53205 53849 53848 53205 53856 53849 53205 53208 53853 53858 53208 53209 53853 54502 53215 53210 53210 53859 54502 53866 53860 53213 54500 53866 53213 53213 53858 54500 53861 53859 53214 53214 53218 53861 53857 53856 53215 54507 53857 53215 53215 54502 54507 53862 53217 53216 53863 53862 53216 53862 53226 53217 53867 53861 53218 53218 53219 53867 53868 53867 53219 53219 53225 53868 54510 54509 53220 54511 54510 53220 53868 53225 53223 53874 53868 53223 53223 53233 53874 53223 53224 53233 53224 53232 53233 53872 53871 53226 53226 53862 53872 53227 53228 53864 53229 53228 53227 53231 53229 53227 53879 53231 53227 53227 53865 53879 53227 53864 53865 53228 53229 53230 53885 53878 53229 53229 53231 53885 53878 53230 53229 53230 53878 53884 54534 53885 53231 53231 53879 54534 53902 53233 53232 53232 53244 53902 53902 53874 53233 53883 53240 53235 53235 53236 53883 53237 53236 53235 53236 53882 53883 54526 53882 53236 54527 54526 53236 53236 53237 54527 54529 54527 53237 53237 54528 54529 53237 53884 54528 53883 53246 53240 53242 53241 53240 53246 53242 53240 53252 53243 53241 53241 53248 53252 53241 53242 53248 53251 53248 53242 53242 53247 53251 53242 53246 53247 54551 53908 53243 53243 53253 54551 53243 53252 53253 53903 53902 53244 53245 53887 53895 53245 53886 53887 53883 53882 53246 53894 53247 53246 53246 53891 53894 53893 53891 53246 53246 53882 53893 53894 53251 53247 53248 53251 53252 54544 53903 53249 54559 54544 53249 53249 53250 54559 53256 53255 53250 53250 54558 54559 53250 53255 54558 53906 53252 53251 53251 53900 53906 53251 53894 53900 53906 53253 53252 54552 54551 53253 53253 53918 54552 53253 53916 53918 53253 53906 53916 54558 53255 53254 53254 53912 54558 53254 53910 53912 53257 53258 53259 53914 53259 53258 53258 53896 53914 55252 53923 53259 53259 55246 55252 53259 53914 55246 54577 53946 53260 55289 54577 53260 53260 53261 55289 53262 53261 53260 53931 53262 53260 53261 54564 55289 53939 53936 53263 53263 53937 53939 53280 53266 53264 53281 53280 53264 53264 53279 53281 53264 53278 53279 53955 53277 53265 54583 53955 53265 53265 53946 54583 53266 53280 53938 53267 53953 53957 54599 54598 53268 53268 53945 54599 53268 53269 53945 53269 53271 53945 53275 53271 53269 53269 53274 53275 53286 53274 53269 53292 53286 53269 53269 53270 53292 53298 53292 53270 53270 53297 53298 54590 53945 53271 53271 54581 54590 53271 53272 54581 53273 53272 53271 53275 53273 53271 54582 54581 53272 54591 54582 53272 53272 53273 54591 53273 53950 54591 53273 53275 53950 53276 53275 53274 53286 53276 53274 53275 53276 53950 53951 53950 53276 53954 53951 53276 53276 53286 53954 53282 53279 53278 53290 53282 53278 53283 53281 53279 53279 53282 53283 53944 53938 53280 55312 53944 53280 53280 54603 55312 53280 54595 54603 53280 53281 54595 54596 54595 53281 53281 53283 54596 53291 53283 53282 53282 53290 53291 53283 53284 54596 53285 53284 53283 53291 53285 53283 54604 54596 53284 54612 54604 53284 53284 53285 54612 53286 53293 53954 53286 53292 53293 54619 53961 53287 53287 53288 54619 53961 53294 53287 53288 54611 54619 53288 53956 54611 53307 53293 53292 53292 53298 53307 54627 53954 53293 53293 53307 54627 53961 53302 53294 53300 53959 53966 53960 53959 53300 53963 53960 53300 53961 53303 53301 53301 53302 53961 53303 53968 53974 53303 53964 53968 53303 53961 53964 53974 53304 53303 53304 53308 53967 54633 53308 53304 53304 53974 54633 53986 53306 53305 53305 53966 53986 53306 53983 53984 53306 53982 53983 53986 53982 53306 54634 54627 53307 53307 53973 54634 54633 53973 53308 53314 53312 53311 54645 53975 53312 53312 54644 54645 53312 53313 54644 53314 53313 53312 55365 54644 53313 53313 53990 55365 53313 53989 53990 53991 53989 53313 53313 53314 53991 53314 53324 53991 53314 53315 53324 53326 53324 53315 53330 53329 53316 54646 53330 53316 53316 53985 54646 53316 53328 53985 53316 53317 53328 53318 53317 53316 53329 53318 53316 53317 53322 53328 53331 53322 53317 53317 53319 53331 53332 53319 53317 53335 53332 53317 53350 53335 53317 54001 53350 53317 53317 53318 54001 54003 54001 53318 54005 54003 53318 54693 54005 53318 55397 54693 53318 53318 55391 55397 53318 54664 55391 53318 53329 54664 53319 53322 53331 53319 53320 53322 53321 53320 53319 53332 53321 53319 53980 53322 53320 53981 53980 53320 54637 53981 53320 54649 54637 53320 53320 54647 54649 54648 54647 53320 53320 53336 54648 53320 53321 53336 53338 53336 53321 53341 53338 53321 53321 53332 53341 53980 53328 53322 53992 53991 53324 53993 53992 53324 53995 53993 53324 53996 53995 53324 53324 53326 53996 53327 53326 53325 53334 53327 53325 54671 53996 53326 54672 54671 53326 53326 53327 54672 53327 54002 54672 53327 53334 54002 53328 53980 53985 55391 54664 53329 55392 55391 53329 53329 53330 55392 53330 55378 55392 53330 54646 55378 53351 53341 53332 53332 53349 53351 53332 53335 53349 53333 54673 54701 53333 54000 54673 54679 53383 53333 54701 54679 53333 53350 53349 53335 53336 53339 54648 53336 53337 53339 53338 53337 53336 53340 53339 53337 53342 53340 53337 53337 53338 53342 53343 53342 53338 53352 53343 53338 53338 53341 53352 55383 54648 53339 53339 54674 55383 54676 54674 53339 55399 54676 53339 53339 54677 55399 53339 53340 54677 53340 53344 54677 53340 53342 53344 53341 53351 53352 53346 53344 53342 53353 53346 53342 53357 53353 53342 53342 53343 53357 53370 53357 53343 53343 53367 53370 53343 53352 53367 54678 54677 53344 53344 53345 54678 53346 53345 53344 54682 54678 53345 53345 53354 54682 53345 53346 53354 53346 53353 53354 54681 54002 53347 53347 54033 54681 53347 53348 54033 53348 53384 54033 54004 53351 53349 53349 53350 54004 53350 54001 54004 53366 53352 53351 54695 53366 53351 53351 54023 54695 54025 54023 53351 53351 54004 54025 53352 53366 53367 53372 53354 53353 53353 53357 53372 53354 53355 54682 53356 53355 53354 53375 53356 53354 53354 53372 53375 55402 54682 53355 53355 53356 55402 53375 53358 53356 53356 54697 55402 53356 53376 54697 53356 53358 53376 53357 53370 53371 53373 53372 53357 53386 53373 53357 53357 53371 53386 53375 53360 53358 54683 53376 53358 53358 53379 54683 53358 53377 53379 53378 53377 53358 53358 53359 53378 53360 53359 53358 53391 53378 53359 53359 53390 53391 53359 53360 53390 53360 53374 53389 53375 53374 53360 53360 53389 53390 53361 53362 53380 53363 53362 53361 53380 53363 53361 53392 53380 53362 54026 53392 53362 53362 54011 54026 53362 54007 54011 53362 53363 54007 53363 54006 54007 53382 53381 53364 54013 53382 53364 53365 54679 54689 53365 53383 54679 53369 53367 53366 54695 53369 53366 53371 53370 53367 53367 53368 53371 53369 53368 53367 53385 53371 53368 54042 53385 53368 55419 54042 53368 53368 53369 55419 53369 54041 55419 56178 54041 53369 53369 54705 56178 53369 54695 54705 53388 53386 53371 53371 53385 53388 53372 53374 53375 53372 53373 53374 53389 53374 53373 53373 53386 53389 55413 54697 53376 53376 55403 55413 53376 54683 55403 54027 53379 53377 54708 54027 53377 53377 53391 54708 53377 53378 53391 53379 54009 54010 54027 54009 53379 54684 54683 53379 53379 54010 54684 54688 54008 53381 53381 53382 54688 54699 54688 53382 53382 54013 54699 54039 54033 53384 53384 53394 54039 55425 53388 53385 53385 54042 55425 54043 53389 53386 53386 53387 54043 53388 53387 53386 54717 54043 53387 53387 54716 54717 53387 53388 54716 54718 54716 53388 55425 54718 53388 54043 53390 53389 54057 53391 53390 53390 54043 54057 54710 54708 53391 53391 54045 54710 54720 54045 53391 53391 54719 54720 53391 54057 54719 53392 54026 54047 54699 54013 53393 54700 54699 53393 54056 54039 53394 53394 54055 54056 53394 54022 54055 53394 53397 54022 54034 53396 53395 54060 54059 53396 53396 54049 54060 53396 54034 54049 53400 53399 53398 54726 53400 53398 53398 53399 54726 53399 54048 54726 54063 54048 53399 55441 54750 53400 53400 54726 55441 53401 53402 54706 53402 54060 54735 55426 54706 53402 56185 55426 53402 53402 55436 56185 53402 54735 55436 54745 54066 53403 53403 54741 54745 53403 53404 54741 53405 53404 53403 53425 53405 53403 55450 54741 53404 53404 53405 55450 55465 55450 53405 55484 55465 53405 53405 55472 55484 53405 54084 55472 53405 53425 54084 53411 53410 53407 54068 53434 53408 54748 54068 53408 53408 54742 54748 53408 53414 54742 54743 53414 53409 53409 54069 54743 53409 54067 54069 53428 53427 53410 53410 53411 53428 53411 53412 53428 54078 53428 53412 54087 54078 53412 53412 53413 54087 54756 54087 53413 54759 54756 53413 53413 53445 54759 53413 53420 53445 54744 54742 53414 53414 54743 54744 54071 54067 53415 54073 53418 53416 54079 54073 53416 53416 53417 53458 53418 53417 53416 54754 53458 53417 53417 53418 54754 54073 54072 53418 55461 54754 53418 53418 54072 55461 54074 53422 53421 54075 54074 53421 53421 53435 54075 54074 54071 53422 53452 53442 53423 54094 53452 53423 53423 54082 54094 53423 54080 54082 54081 54080 53423 53423 53424 54081 53424 54077 54081 53424 54076 54077 53456 53455 53426 53457 53456 53426 53461 53457 53426 53426 53443 53461 53426 53427 53443 53427 53428 53443 54078 53443 53428 53429 53444 53445 53430 53431 53446 54088 53446 53431 54089 54088 53431 53431 53432 54089 53433 53432 53431 53434 53433 53431 54752 54089 53432 54760 54752 53432 55452 54760 53432 53432 53433 55452 53433 54746 55452 53433 54068 54746 53433 53434 54068 53435 53466 54075 53436 53439 53440 53438 53437 53436 53440 53438 53436 53437 53438 55462 53437 54073 54079 53437 54072 54073 55462 54072 53437 53438 53440 54755 53438 54755 55462 53441 53440 53439 53440 53441 54093 53440 54093 54755 53441 54090 54093 53452 53451 53442 54085 53461 53443 53443 54078 54085 54759 53445 53444 55473 54759 53444 53444 54097 55473 53448 53447 53446 53450 53448 53446 54762 53450 53446 53446 54088 54762 53447 53448 53472 53448 53449 53472 53450 53449 53448 54098 53472 53449 53449 53450 54098 55493 54098 53450 56243 55493 53450 56245 56243 53450 53450 55486 56245 53450 54762 55486 53451 53452 54094 54084 54083 53453 55472 54084 53453 55483 55472 53453 53453 53454 55483 53454 55481 55483 53454 55480 55481 53454 54096 55480 53455 53460 54100 53455 53456 53460 53464 53460 53456 53465 53464 53456 53456 53457 53465 53457 53461 53465 54102 53463 53458 54754 54102 53458 54773 54095 53459 54765 54105 53460 53460 54120 54765 53460 54113 54120 53460 53464 54113 54105 54100 53460 54101 53465 53461 54766 54101 53461 53461 54086 54766 53461 54085 54086 53462 53463 54102 53462 54103 54110 53462 54102 54103 53464 54106 54113 53464 53465 54106 53465 54101 54106 53466 54099 54764 54763 54075 53466 54764 54763 53466 54774 53470 53468 53468 54765 54774 53468 54105 54765 53468 53469 54105 54770 54112 53470 54774 54770 53470 53471 53472 55493 54778 54107 53471 55492 54778 53471 55493 55492 53471 53472 54098 55493 53473 53483 53485 53473 53474 53483 54121 53483 53474 53474 54107 54121 53475 53486 54125 53475 53476 53486 54125 53486 53476 53476 53489 54125 53479 53478 53477 54112 53479 53477 53478 54119 54787 53478 53479 54119 54787 53502 53478 55510 54119 53479 55527 55510 53479 53479 55497 55527 53479 54768 55497 53479 54112 54768 53482 53481 53480 54118 53482 53480 53481 53482 53488 54117 53488 53482 53482 54111 54117 54118 54111 53482 53483 53484 53485 53483 54121 54124 53487 54779 55509 53487 53488 54779 55509 54127 53487 53488 54117 54779 53489 53490 54125 53490 53497 54125 53493 53492 53491 54125 53493 53491 55507 54125 53491 55530 55507 53491 56275 55530 53491 53491 55519 56275 55520 55519 53491 55531 55520 53491 53491 53492 55531 55533 55531 53492 53492 53493 55533 53493 54824 55533 53493 53523 54824 53493 53498 53523 53499 53498 53493 54125 53499 53493 54796 54133 53494 53494 54127 54796 53495 53501 54134 53506 53505 53496 53496 53503 53506 53497 53499 54125 53497 53498 53499 53498 53522 53523 54130 53517 53500 54131 54130 53500 53501 54803 54812 53501 54128 54803 53501 53502 54128 54812 54134 53501 54129 54128 53502 54793 54129 53502 53502 54787 54793 54137 53506 53503 54142 54137 53504 53504 53518 54142 53504 53511 53518 55548 53521 53505 53505 54146 55548 54829 54146 53505 53505 54143 54829 53505 53506 54143 53506 54142 54143 53506 54137 54142 53514 53508 53507 53508 53512 54135 53513 53512 53508 54138 53513 53508 53508 53514 54138 53509 53510 54814 53535 53515 53509 54140 53535 53509 54152 54140 53509 54814 54152 53509 53510 54794 54814 54828 53518 53511 53511 53540 54828 54801 54135 53512 54802 54801 53512 53512 54139 54802 53512 53513 54139 56294 54139 53513 53513 55536 56294 53513 54138 55536 54150 54138 53514 54817 53524 53516 53516 54130 54817 53516 53517 54130 53518 53528 54142 54828 53528 53518 54149 54148 53519 53519 53520 54149 54148 54147 53519 53520 53521 54149 55548 54149 53521 53523 53537 54824 53538 53537 53523 54830 53538 53523 54831 54830 53523 53523 54154 54831 53523 53546 54154 54817 53525 53524 54155 53541 53525 54157 54155 53525 54817 54157 53525 55555 55554 53526 55560 55555 53526 53526 54836 55560 53526 53527 54836 53528 53527 53526 55554 53528 53526 53527 54828 54836 53527 53528 54828 54829 54142 53528 53528 54145 54829 55545 54145 53528 55554 55545 53528 54153 53532 53529 53529 53530 54153 53532 53531 53529 54161 54153 53530 53530 54158 54161 53531 53532 53533 54164 54163 53532 53532 54153 54164 54163 53533 53532 54151 54150 53533 54826 54151 53533 53533 54165 54826 53533 54163 54165 54833 54159 53534 55557 54833 53534 53534 55542 55557 53534 54140 55542 53534 53535 54140 55543 54824 53537 53537 53538 55543 53538 54832 55543 53538 54830 54832 54141 53540 53539 54160 54141 53539 54836 54828 53540 53540 54141 54836 53541 54154 54169 54831 54154 53541 54832 54831 53541 55544 54832 53541 53541 54155 55544 53542 54141 54160 54835 54141 53542 53543 54167 54176 54169 54168 53544 54173 54171 53545 54169 54154 53546 53546 54168 54169 55560 54835 53547 53547 54840 55560 54841 54840 53547 53547 54185 54841 53547 53550 54185 54174 53551 53548 53548 53549 54174 53549 53557 54174 53550 54184 54185 53551 54174 54851 54172 53561 53552 53553 54170 54173 53553 53556 54170 53553 53554 53556 53555 53554 53553 54860 53555 53553 53553 54859 54860 53553 54847 54859 53553 54173 54847 53554 53555 54179 54860 54179 53555 54180 54174 53557 54181 54180 53557 53557 53562 54181 53560 53559 53558 53563 53560 53558 54865 53562 53558 53558 53559 54865 53559 54182 54866 53559 53560 54182 54866 54865 53559 53560 53563 54182 54178 54177 53561 53561 54172 54178 54865 54181 53562 54856 54182 53564 53564 54855 54856 53564 54177 54855 54186 54184 53565 54869 54188 53566 54870 54869 53566 53566 54190 54870 53566 54189 54190 54188 53567 53566 54187 53569 53567 54188 54187 53567 53568 54183 54189 54867 54186 53569 53569 54187 54867 54871 54191 53571 53572 54193 54195 54195 54194 53572 54198 53576 53574 53574 53579 54198 54196 53580 53577 55591 54196 53577 53577 54875 55591 53577 54194 54875 54197 53579 53578 54877 54198 53579 53579 54876 54877 53579 54197 54876 53580 54196 54202 54880 54206 53581 53581 54878 54880 53581 54201 54878 55599 53583 53582 56342 55599 53582 53582 55600 56342 53582 54879 55600 53582 54203 54879 55599 55585 53583 53590 53588 53585 54228 53588 53586 53586 53597 54228 54908 53597 53586 54909 54908 53586 53586 53587 54909 53588 53587 53586 56363 54909 53587 53587 56357 56363 53587 55615 56357 53587 53588 55615 53588 55606 55615 55607 55606 53588 53588 53590 55607 53590 54206 55607 55622 54905 53591 55623 55622 53591 56365 55623 53591 53591 53603 56365 53591 53592 53600 54224 54205 53593 54229 53595 53594 54230 53596 53595 54231 54230 53595 53595 54229 54231 54239 53599 53596 53596 54230 54239 54908 54232 53597 54240 53607 53598 53598 53599 54240 53599 54239 54240 54912 54233 53601 53601 53602 54912 54917 54912 53602 53602 54241 54917 56366 56365 53603 56372 56366 53603 56373 56372 53603 53603 55643 56373 54234 53605 53604 55632 54919 53605 55633 55632 53605 53605 54916 55633 53605 54913 54916 53605 54234 54913 54245 54243 53606 53606 53607 54245 53607 54240 54245 54241 53609 53608 54242 54241 53608 54920 54242 53608 54247 54246 53610 53610 53612 54247 53624 53612 53611 54257 53624 53611 54262 54257 53611 53611 54261 54262 53611 53617 54261 54249 54247 53612 53612 53624 54249 53614 53618 54251 53619 53618 53614 53614 53615 53619 53616 53615 53614 55650 53616 53614 53614 54251 55650 55661 54265 53615 53615 55658 55661 53615 55654 55658 53615 55653 55654 53615 53616 55653 56395 55653 53616 53616 55650 56395 54264 54261 53617 53617 53625 54264 54921 54251 53618 53620 54259 54922 53620 53626 54259 54248 53622 53621 53622 54253 54255 53622 54252 54253 53622 54248 54252 54257 54249 53624 54939 54264 53625 53625 54277 54939 53625 53639 54277 53626 54258 54259 53626 53628 54258 54266 53634 53627 54932 54266 53627 53627 54260 54932 53628 53633 54258 53628 53629 53633 53629 53632 53633 53630 53640 54267 53641 53640 53630 54267 53645 53630 53633 53632 53631 54937 53633 53631 55659 54937 53631 55664 55659 53631 53631 54935 55664 53631 53632 54935 54936 54935 53632 54937 54258 53633 53634 54274 54275 53634 54273 54274 53634 54266 54273 54275 53642 53635 54277 53643 53636 55679 54277 53636 53636 53637 55679 53638 53637 53636 53643 53638 53636 55680 55679 53637 55684 55680 53637 53637 54948 55684 53637 54286 54948 53637 53638 54286 53638 53649 54286 53639 53643 54277 54268 54267 53640 56417 54268 53640 53640 55663 56417 53640 54934 55663 53640 53641 54934 53641 54265 54934 53658 53648 53642 53642 53656 53658 54275 53656 53642 53645 54267 54268 53646 53671 54289 53647 54279 54285 53647 54271 54279 53648 53658 53659 53648 53659 53666 53649 53670 54286 53649 53660 53670 53650 53653 54282 53650 53652 53653 54288 53652 53650 54289 54288 53650 53651 54287 56425 53651 53652 54287 53653 53652 53651 56423 53653 53651 56425 56423 53651 54288 54287 53652 54947 54282 53653 56424 54947 53653 53653 56423 56424 53656 53655 53654 53657 53656 53654 54274 54272 53655 54276 54274 53655 53655 53656 54276 53656 54275 54276 53656 53657 53658 53659 53658 53657 53666 53659 53657 53663 53662 53661 54952 54294 53661 53661 54949 54952 53661 53664 54949 53665 53664 53661 54290 53665 53661 53661 53662 54290 54945 54290 53662 53664 53672 55686 53664 53665 53672 55687 54949 53664 56427 55687 53664 53664 55686 56427 53673 53672 53665 54945 53673 53665 53665 54290 54945 53679 53669 53667 53667 53678 53679 53669 53668 53667 53669 53680 54297 53669 53679 53680 54297 54292 53669 54291 54286 53670 54299 54289 53671 53671 53684 54299 53671 53683 53684 53672 54947 56424 53672 53673 54947 56424 55686 53672 55674 54947 53673 53673 54283 55674 54284 54283 53673 54945 54284 53673 53674 53675 53692 53676 53675 53674 54306 53676 53674 53674 53698 54306 54311 53693 53676 53676 54306 54311 53689 53678 53677 54296 53679 53678 53678 53689 54296 53681 53680 53679 54296 53681 53679 54950 54297 53680 53680 54301 54950 53680 53681 54301 54302 54301 53681 54308 54302 53681 53681 54296 54308 55698 54303 53682 53682 55693 55698 53682 54280 55693 53690 53685 53683 53685 53684 53683 53684 54298 54299 53684 53685 54298 53685 53690 54298 54956 53688 53686 53686 54955 54956 55688 54955 53686 53686 54954 55688 53686 53687 54954 53687 54295 54954 54956 54305 53688 54308 54296 53689 53689 54302 54308 54966 54302 53689 53689 54964 54966 54965 54964 53689 54307 53699 53693 54311 54307 53693 53700 53695 53694 54293 53696 53695 54961 54293 53695 53695 53700 54961 53696 54293 54304 53697 54314 54973 54973 53701 53697 54974 54306 53698 53698 54973 54974 53698 53701 54973 54316 53703 53699 53699 54307 54316 54968 54961 53700 55709 54328 53704 53704 54978 55709 54979 54978 53704 53704 54967 54979 54997 54982 53705 53705 54331 54997 54339 54329 53706 53706 53712 54339 54317 53709 53708 55007 54332 53709 53709 54994 55007 53709 54993 54994 53709 54317 54993 55013 53711 53710 55012 54342 53711 55013 55012 53711 53712 54338 54339 54345 54338 53712 53713 53714 53715 55003 53714 53713 53713 54341 55003 53714 55003 55010 53716 53715 53714 55010 53716 53714 54349 53720 53715 53715 54348 54349 53715 53716 54348 55015 54348 53716 53716 55010 55015 53718 54347 54355 53718 54346 54347 55733 54346 53718 55759 55733 53718 53718 53719 55759 55765 55759 53719 53719 55764 55765 53719 54361 55764 54349 53721 53720 55017 54356 53721 53721 54349 55017 55756 54357 53722 53722 55023 55756 53722 54358 55023 53722 53723 54358 54359 54358 53723 54356 53727 53724 53725 53733 54363 54369 53731 53726 54371 54369 53726 53726 53728 54371 53726 53727 53728 54368 53728 53727 53727 54356 54368 53728 54366 54371 54368 54366 53728 53729 55027 55028 53729 55026 55027 53729 54370 55026 55019 53730 53729 55028 55019 53729 55019 55018 53730 55025 54363 53733 55031 55025 53733 53734 54373 54382 53734 53735 54373 53735 54372 54373 53735 54362 54372 53736 54374 54385 54394 53739 53738 54395 54394 53738 55052 54376 53739 53739 54393 55052 54394 54393 53739 54378 53743 53740 53745 53742 53741 54388 54375 53742 53742 53745 54388 54389 53746 53743 53743 54379 54389 53743 54378 54379 55036 54380 53744 55042 55036 53744 55055 55042 53744 53744 55040 55055 53744 53746 55040 55051 54388 53745 53746 54389 55040 55033 53749 53747 53747 54381 55033 53749 53748 53747 53748 53749 53751 55047 53751 53749 53749 55033 55047 55047 55045 53751 54397 53753 53752 53755 53754 53753 54398 53755 53753 53753 54397 54398 53754 53755 54403 53755 55070 55787 53755 54398 55070 55080 54403 53755 55787 55080 53755 53756 55781 55786 53756 55038 55781 53756 54392 55038 53756 53757 54392 53758 53757 53756 55786 53758 53756 55076 55075 53758 55077 55076 53758 55786 55077 53758 55087 53765 53758 53758 55074 55087 55075 55074 53758 53759 54394 54395 53759 54393 54394 55066 54393 53759 53769 53764 53760 54405 54402 53762 55091 54405 53762 55092 55091 53762 55093 55092 53762 53763 53764 54404 55089 55061 53763 53763 54404 55089 53764 53769 54404 55087 54406 53765 53766 54407 55095 54408 54407 53766 53766 53767 54408 55095 54415 53766 55104 54408 53767 53767 54418 55104 54409 53769 53768 54409 54404 53769 55099 54409 53770 55110 55099 53770 53770 53771 55110 53772 53771 53770 53771 54424 55110 53771 53772 54424 53772 53778 54424 53774 53791 53794 54419 53784 53775 54420 54419 53775 54422 54420 53775 53785 53778 53777 53778 53785 54424 53779 53782 54430 53779 53781 53782 55112 53781 53779 53779 54416 55112 54417 54416 53779 53779 54413 54417 53779 54410 54413 53782 53781 53780 55117 53782 53780 56544 55117 53780 56545 56544 53780 53780 55836 56545 53780 53781 55836 53781 55112 55836 55116 54430 53782 55117 55116 53782 53783 53786 53789 55826 55824 53785 53785 54423 55826 55110 54424 53785 55849 55110 53785 53785 55848 55849 53785 55837 55848 53785 55824 55837 54421 53788 53786 53786 53787 53789 53788 53787 53786 55856 53789 53787 56548 55856 53787 53787 55120 56548 53787 54425 55120 53787 53788 54425 54431 54425 53788 54432 54431 53788 53796 53790 53789 54433 53796 53789 54435 54433 53789 55856 54435 53789 53796 53792 53790 53791 53793 53794 53791 53792 53793 53796 53793 53792 53795 53794 53793 54439 53795 53793 54440 54439 53793 53793 53796 54440 55847 54418 53794 53794 53795 55847 55855 55847 53795 53795 54437 55855 53795 54436 54437 54439 54436 53795 53796 54434 54440 53796 54433 54434 53810 53798 53797 54443 53810 53797 53797 54442 54443 53810 53803 53798 54445 54444 53799 53800 53801 53807 53800 53807 53808 54444 53807 53801 53813 53809 53802 53803 53804 53805 53810 53804 53803 54446 53805 53804 53804 54443 54446 53804 53810 54443 53805 54446 54457 53807 54444 54445 54455 53808 53807 53807 54445 54455 54455 54454 53808 53809 53813 54451 53811 53812 54465 54466 54460 53811 53811 54465 54466 54469 54468 53812 53812 53818 54469 53812 53815 53818 54468 54465 53812 53813 54460 54466 54456 54451 53813 55135 54456 53813 53813 54466 55135 53814 55130 55131 53814 54448 55130 54454 54448 53814 55145 55144 53816 53816 53828 55145 53816 53817 53828 53829 53828 53817 54475 53829 53817 53819 53826 54472 54458 54448 53820 55136 54458 53820 55158 53841 53821 53821 54463 55158 53821 53822 54463 55905 55149 53823 55906 55905 53823 55907 55906 53823 53823 55150 55907 53823 54472 55150 53824 53825 55901 55888 54471 53824 55901 55888 53824 53825 55149 55905 55905 55901 53825 55150 54472 53826 55151 55150 53826 53826 53827 55151 55152 55151 53827 53827 54461 55152 53828 54476 55145 53828 53829 54476 55159 54476 53829 53829 54475 55159 55875 55141 53830 53830 54483 55875 53830 53834 54483 53837 53833 53831 55163 55159 53832 55164 55163 53832 55165 55164 53832 53832 54479 55165 53832 53833 54479 53833 53837 54479 54484 54483 53834 53835 54478 54485 53835 54473 54478 53844 53842 53835 54485 53844 53835 54480 54479 53837 54489 54480 53837 53837 54488 54489 54482 53840 53838 55171 54482 53838 53838 53839 55171 53839 55160 55171 53839 55158 55160 53840 54481 54492 54482 54481 53840 54489 54488 53843 55178 54489 53843 53843 54496 55178 53843 54495 54496 53844 54485 54494 55176 55175 53845 53845 55174 55176 53845 54494 55174 55191 54498 53847 53847 54491 55191 55192 53850 53848 53848 53849 55192 55193 55192 53849 53849 53856 55193 55192 53852 53850 55192 54499 53851 53851 53852 55192 54500 53858 53853 55211 54500 53853 53853 54504 55211 53853 54501 54504 53853 53854 54501 55199 54501 53854 53855 54498 55199 55207 55193 53856 53856 53857 55207 55949 55207 53857 53857 55948 55949 53857 54507 55948 53859 53870 54502 53859 53861 53870 53865 53864 53860 53866 53865 53860 53861 53869 53870 53861 53867 53869 54522 53872 53862 53862 54508 54522 53862 53863 54508 54535 53879 53865 53865 54514 54535 53865 54503 54514 53865 53866 54503 53866 54500 54503 54516 53869 53867 53867 53868 54516 54517 54516 53868 53868 53875 54517 53868 53874 53875 54506 53870 53869 54518 54506 53869 53869 54516 54518 55212 54502 53870 53870 54505 55212 54506 54505 53870 54521 53888 53871 53871 54520 54521 53871 53872 54520 54522 54520 53872 53873 53874 53902 53875 53874 53873 55239 53875 53873 55985 55239 53873 53873 55243 55985 53873 53902 55243 55954 54519 53875 53875 55239 55954 54519 54517 53875 53876 53877 55230 55968 54523 53876 55974 55968 53876 53876 55230 55974 55236 55230 53877 53877 55235 55236 53877 54531 55235 53878 54534 55983 53878 53885 54534 55238 53884 53878 55983 55238 53878 54535 54534 53879 53880 53881 53886 53889 53886 53881 54524 53893 53882 54525 54524 53882 54526 54525 53882 55238 54528 53884 53889 53887 53886 53887 53888 53895 53889 53888 53887 54521 53895 53888 54540 54536 53890 53890 54538 54540 54539 54538 53890 54543 54539 53890 53890 54541 54543 53899 53894 53891 53904 53899 53891 55240 53904 53891 53891 53892 55240 53893 53892 53891 53892 54524 55240 53892 53893 54524 53894 53899 53900 53895 54521 54530 54530 53897 53895 54530 53914 53896 53896 53897 54530 54542 54541 53898 53898 53924 54542 53901 53900 53899 53904 53901 53899 53907 53906 53900 53900 53905 53907 53900 53901 53905 54549 53905 53901 53901 53904 54549 55993 55243 53902 53902 54545 55993 53902 53903 54545 54546 54545 53903 53903 54544 54546 55241 54549 53904 55242 55241 53904 53904 55240 55242 53921 53907 53905 54562 53921 53905 53905 54550 54562 53905 54549 54550 53906 53907 53916 53907 53915 53916 53921 53915 53907 54555 53909 53908 53908 54554 54555 53908 54553 54554 53908 54551 54553 53909 54555 54557 53913 53912 53910 53910 53911 53913 55259 53913 53911 53911 55257 55259 53911 55256 55257 53911 54556 55256 55260 54558 53912 53912 55258 55260 53912 53913 55258 55259 55258 53913 53914 55244 55246 53914 54530 55244 53922 53917 53915 53928 53922 53915 53915 53925 53928 53915 53921 53925 53917 53916 53915 53919 53918 53916 53916 53917 53919 53932 53919 53917 53917 53922 53932 55255 54552 53918 53918 54563 55255 53918 53919 54563 53919 53932 54563 54547 53924 53920 54561 54547 53920 53920 54560 54561 53920 54548 54560 54570 53925 53921 56009 54570 53921 53921 54562 56009 53922 53926 53932 53928 53926 53922 55271 54564 53923 53923 55252 55271 54547 54542 53924 53925 53926 53928 53927 53926 53925 54573 53927 53925 54575 54573 53925 53925 54570 54575 53933 53932 53926 55301 53933 53926 53926 53927 55301 56059 55301 53927 53927 53929 56059 53930 53929 53927 54574 53930 53927 54575 54574 53927 53927 54573 54575 56720 56059 53929 56729 56720 53929 53929 56069 56729 53929 53930 56069 56729 56069 53930 53930 56728 56729 53930 55306 56728 56058 55306 53930 53930 55300 56058 53930 54574 55300 54576 54563 53932 53932 53933 54576 55292 54576 53933 55301 55292 53933 53934 53935 53936 55304 54572 53934 53934 54594 55304 53934 53936 54594 53936 53939 54594 55322 53939 53937 53937 54584 55322 53938 53941 53942 53943 53941 53938 53944 53943 53938 53939 54593 54594 55311 54593 53939 55323 55311 53939 53939 55322 55323 53940 53943 54587 53940 53941 53943 53942 53941 53940 54588 54587 53943 53943 53944 54588 53944 55312 56066 56065 54588 53944 56066 56065 53944 53945 54590 54599 56052 54583 53946 53946 56047 56052 53946 54577 56047 54608 53953 53947 53947 54606 54608 53947 53948 54606 53949 53948 53947 53948 54597 54606 54592 54591 53950 53950 53952 54592 53950 53951 53952 54601 53952 53951 53951 53954 54601 54609 54592 53952 53952 54601 54609 54605 53957 53953 54608 54605 53953 54618 54601 53954 53954 54617 54618 54627 54617 53954 54602 53956 53955 53955 54583 54602 55329 54611 53956 53956 54602 55329 53963 53958 53957 54605 53963 53957 54642 53966 53959 54643 54642 53959 53959 53960 54643 55359 54643 53960 53960 55345 55359 53960 54605 55345 53960 53963 54605 54619 53964 53961 54635 53965 53962 53962 53971 54635 53972 53971 53962 53962 53969 53972 56108 53968 53964 53964 56091 56108 53964 54623 56091 53964 54619 54623 55333 54612 53965 55341 55333 53965 53965 54635 55341 54642 53986 53966 55364 53974 53968 56107 55364 53968 56108 56107 53968 53976 53972 53969 53969 53975 53976 53969 53970 53975 55341 54635 53971 55355 55341 53971 55356 55355 53971 53971 53972 55356 53972 53976 55356 53973 54633 54634 55364 54633 53974 54645 53976 53975 55366 55356 53976 53976 54645 55366 56122 55379 53977 56123 56122 53977 53977 55367 56123 53977 53978 55367 53979 53978 53977 55379 53979 53977 53978 53981 54637 53978 53979 53981 53978 54636 55367 54637 54636 53978 53985 53981 53979 54646 53985 53979 55378 54646 53979 55379 55378 53979 53980 53981 53985 53982 54642 54651 53982 53986 54642 54651 53983 53982 55388 53984 53983 53983 55387 55388 53983 54652 55387 53983 54651 54652 54659 54653 53984 55389 54659 53984 56134 55389 53984 56139 56134 53984 56140 56139 53984 53984 55388 56140 54660 53988 53987 53997 53994 53988 55393 53997 53988 53988 54661 55393 53988 54660 54661 53989 53991 54670 54670 53990 53989 53990 54665 54666 54670 54665 53990 53990 54657 55365 54666 54657 53990 53991 54017 54670 53991 53992 54017 54680 54017 53992 53992 53993 54680 53993 53995 54680 54691 54680 53995 53995 53996 54691 54692 54691 53996 53996 54671 54692 53999 53998 53997 55393 53999 53997 55407 54673 53998 56145 55407 53998 53998 53999 56145 53999 55393 56141 53999 56143 56145 53999 56141 56143 54001 54003 54004 54681 54672 54002 54005 54004 54003 54004 54005 54025 54694 54025 54005 54005 54693 54694 55406 54007 54006 54006 54686 55406 54698 54011 54007 55406 54698 54007 54012 54010 54009 54009 54011 54012 54026 54011 54009 54027 54026 54009 54010 54012 55404 55403 54684 54010 55404 55403 54010 54698 54685 54011 54685 54012 54011 54012 54685 55404 54014 54017 54020 54018 54017 54014 54019 54018 54014 54014 54015 54019 54016 54015 54014 54029 54016 54014 54014 54020 54029 54703 54019 54015 54704 54703 54015 54015 54035 54704 54015 54016 54035 54036 54035 54016 54050 54036 54016 54016 54029 54050 54021 54020 54017 54031 54021 54017 54680 54031 54017 54017 54018 54670 54018 54019 54670 54019 54669 54670 54703 54669 54019 54020 54021 54028 54020 54028 54029 54032 54028 54021 54021 54031 54032 54715 54055 54022 54022 54064 54715 54696 54695 54023 55411 54696 54023 54023 54024 55411 54025 54024 54023 54024 54025 54694 54024 55409 55411 54024 54694 55409 54712 54047 54026 54026 54708 54712 54026 54027 54708 54028 54032 54037 54030 54029 54028 54054 54030 54028 54028 54053 54054 54028 54037 54053 54052 54050 54029 54058 54052 54029 54029 54030 54058 54030 54061 54062 54030 54054 54061 54730 54058 54030 54030 54062 54730 54038 54032 54031 54690 54038 54031 54031 54680 54690 54038 54037 54032 54690 54681 54033 54033 54038 54690 54039 54038 54033 55418 54704 54035 54035 54721 55418 54035 54036 54721 54036 54050 54051 54036 54051 54721 54037 54038 54056 54056 54053 54037 54038 54039 54056 54040 55430 56184 56807 55430 54040 54040 56804 56807 54040 54041 56804 54042 54041 54040 56184 54042 54040 54041 56178 56804 54041 54042 55419 56184 55425 54042 54717 54057 54043 54044 54045 54725 54046 54045 54044 56198 54046 54044 54044 56195 56198 54044 54725 56195 54711 54710 54045 54045 54046 54711 54045 54720 54725 54713 54711 54046 54714 54713 54046 55435 54714 54046 56817 55435 54046 54046 56816 56817 54046 56196 56816 56198 56196 54046 54047 54712 54713 54048 54714 54726 54735 54060 54049 55436 54735 54049 54049 55427 55436 54049 54709 55427 54052 54051 54050 54051 54052 54058 54727 54721 54051 54728 54727 54051 54051 54058 54728 54053 54055 54715 54056 54055 54053 54715 54054 54053 54733 54061 54054 54054 54715 54733 54057 54717 54719 54729 54728 54058 54730 54729 54058 54733 54731 54061 54731 54062 54061 54737 54730 54062 54739 54737 54062 54062 54731 54739 54734 54715 54064 54064 54065 54734 54065 54733 54734 56201 54733 54065 54065 54741 56201 54065 54066 54741 54745 54741 54066 54070 54069 54067 54071 54070 54067 54747 54746 54068 54748 54747 54068 55455 54743 54069 55456 55455 54069 54069 54070 55456 55457 55456 54070 54070 54071 55457 55458 55457 54071 54071 54074 55458 55462 55461 54072 55459 55458 54074 54074 54751 55459 54074 54075 54751 54753 54751 54075 54763 54753 54075 54749 54077 54076 54750 54749 54076 54077 55454 55464 54077 54749 55454 55464 54081 54077 54087 54085 54078 55470 54082 54080 54080 55464 55470 54080 54081 55464 54082 54090 54094 55470 54090 54082 54087 54086 54085 55512 54766 54086 54086 54757 55512 54086 54087 54757 54758 54757 54087 54087 54756 54758 54088 54089 54762 54089 54752 54762 54090 54091 54093 54092 54091 54090 55479 54092 54090 54090 55470 55479 55478 54093 54091 56234 55478 54091 54091 54092 56234 56235 56234 54092 54092 55479 56235 55477 54755 54093 55478 55477 54093 54761 54096 54095 54773 54761 54095 54096 54761 55480 55474 55473 54097 55475 55474 54097 54097 54116 55475 54771 54767 54099 54767 54764 54099 54115 54106 54101 54782 54115 54101 54101 54766 54782 54104 54103 54102 54754 54104 54102 55503 54110 54103 54103 55502 55503 56233 55502 54103 54103 54104 56233 54104 56228 56233 54104 54754 56228 54115 54113 54106 54122 54121 54107 54792 54122 54107 55505 54792 54107 54107 54778 55505 54117 54111 54108 54108 54109 54117 54109 54110 55503 54779 54117 54109 55508 54779 54109 54109 55503 55508 54770 54768 54112 54113 54114 54120 54115 54114 54113 54780 54120 54114 54781 54780 54114 54114 54115 54781 54782 54781 54115 55491 55475 54116 55510 54787 54119 54775 54765 54120 54780 54775 54120 54794 54124 54121 54795 54794 54121 54121 54122 54795 55513 54795 54122 54122 54792 55513 54123 54124 54794 55507 54126 54125 54126 54767 54771 55501 54767 54126 55506 55501 54126 55507 55506 54126 55509 54796 54127 54804 54803 54128 55526 54804 54128 54128 55510 55526 54128 54129 55510 54129 54793 55510 54130 54807 54817 54130 54131 54807 54808 54807 54131 54131 54132 54808 54810 54808 54132 54811 54810 54132 54132 54133 54811 54133 54797 54811 54133 54796 54797 54818 54136 54134 54134 54812 54818 54135 54801 55491 54136 54818 54819 55541 55536 54138 54138 54826 55541 54138 54151 54826 54138 54150 54151 55538 54802 54139 56294 55538 54139 54140 54827 55542 54140 54152 54827 54141 54835 54836 54829 54143 54142 56306 55548 54144 56312 56306 54144 54144 55546 56312 54144 54145 55546 54146 54145 54144 55548 54146 54144 54145 55545 55546 54145 54146 54829 54825 54158 54147 54147 54148 54825 54148 55549 56910 54148 54149 55549 55550 54825 54148 56910 55550 54148 54149 55548 55549 56277 54827 54152 54152 54814 56277 54153 54161 56317 55561 54164 54153 56317 55561 54153 54155 55535 55544 54155 54156 55535 54157 54156 54155 54156 54815 55535 54156 54157 54815 54157 54807 54815 54817 54807 54157 54162 54161 54158 54825 54162 54158 54161 54162 56313 54161 56313 56317 54162 54825 55550 54162 55550 56313 54166 54165 54163 54163 54164 54166 54850 54166 54164 55561 54850 54164 54165 55556 56307 54165 54166 55556 55552 54826 54165 56307 55552 54165 55564 55556 54166 54166 54838 55564 54843 54838 54166 54849 54843 54166 54850 54849 54166 54167 54175 54176 54834 54175 54167 54170 54171 54173 54172 54176 54178 54173 54845 54847 54846 54845 54173 55575 54851 54174 54174 54180 55575 54844 54176 54175 54175 54834 54844 54855 54178 54176 54858 54855 54176 54176 54852 54858 54176 54844 54852 54177 54178 54855 54860 54183 54179 54180 54861 55575 54180 54181 54861 55578 54861 54181 55579 55578 54181 54181 55576 55579 54181 55572 55576 54181 54866 55572 54181 54865 54866 54182 54856 54866 54860 54189 54183 55580 54185 54184 54184 54868 55580 54184 54867 54868 54184 54186 54867 56331 54841 54185 54185 55580 56331 55581 54867 54187 54187 54188 55581 55582 55581 54188 55583 55582 54188 54188 54869 55583 54860 54190 54189 54190 54864 54870 54190 54860 54864 54871 54192 54191 54192 54872 54874 54192 54871 54872 54195 54193 54192 54874 54195 54192 54194 54874 54875 54194 54195 54874 55596 54202 54196 54196 55591 55596 54200 54199 54198 54877 54200 54198 54887 54878 54199 54199 54200 54887 54200 54886 54887 54200 54877 54886 56340 54876 54202 54202 55605 56340 56341 55605 54202 54202 55596 56341 54203 54204 54879 54204 54224 54879 54204 54205 54224 54206 54881 55607 54206 54880 54881 54208 54209 54214 54210 54209 54208 54214 54210 54208 54209 54211 54214 54213 54211 54209 54893 54213 54209 54209 54210 54893 54210 54218 54884 54210 54217 54218 54210 54214 54217 54210 54892 54893 55603 54892 54210 54210 54884 55603 54216 54214 54211 54906 54216 54211 55619 54906 54211 54211 54212 55619 54213 54212 54211 56360 55619 54212 54212 54900 56360 55613 54900 54212 54212 54213 55613 54213 55608 55613 54213 54894 55608 54213 54893 54894 54214 54215 54217 54216 54215 54214 54222 54217 54215 56361 54222 54215 54215 54216 56361 56362 56361 54216 56945 56362 54216 54216 54906 56945 54219 54218 54217 54222 54219 54217 54218 54219 54884 54219 54221 54896 54219 54220 54221 54222 54220 54219 54219 54883 54884 54896 54883 54219 54223 54221 54220 54220 54222 54223 54221 54895 54896 54221 54223 54895 54226 54223 54222 54227 54226 54222 56361 54227 54222 54904 54895 54223 54223 54226 54904 54891 54879 54224 54898 54891 54224 54224 54225 54898 54905 54898 54225 55617 54904 54226 54226 54227 55617 54227 56361 56362 56362 55617 54227 54229 54233 55625 55624 54231 54229 55625 55624 54229 54918 54239 54230 55631 54918 54230 54230 55624 55631 54230 54231 55624 54907 54238 54232 54908 54907 54232 54233 54912 55625 54234 54235 54913 54914 54913 54235 54235 54236 54914 54916 54914 54236 54236 54915 54916 54236 54237 54915 54238 54237 54236 54237 54238 54907 55626 54915 54237 55628 55626 54237 54237 54907 55628 54918 54240 54239 54918 54245 54240 54241 54242 54917 55639 54917 54242 55640 55639 54242 54242 54922 55640 54242 54920 54922 54918 54244 54243 54243 54245 54918 55641 54923 54244 54244 55630 55641 54244 54918 55630 54923 54248 54244 55644 55643 54246 54246 54247 55644 55645 55644 54247 54247 54925 55645 54247 54924 54925 54247 54249 54924 54923 54252 54248 54928 54924 54249 54929 54928 54249 54249 54257 54929 54250 54919 55632 55633 54921 54250 54250 55632 55633 54251 54921 55633 56967 55650 54251 54251 55634 56967 54251 55633 55634 55642 54253 54252 54252 54923 55642 54256 54255 54253 54931 54256 54253 55642 54931 54253 54932 54260 54254 54254 54927 54932 55656 54927 54255 54255 54256 55656 54256 54930 55656 54931 54930 54256 54257 54262 54929 55660 54259 54258 54258 55659 55660 54258 54937 55659 55651 54922 54259 55660 55651 54259 54263 54262 54261 55667 54263 54261 54261 54938 55667 54261 54264 54938 55657 54929 54262 54262 54263 55657 56398 55657 54263 56408 56398 54263 54263 55667 56408 54939 54938 54264 55663 54934 54265 54265 55662 55663 54265 55661 55662 54942 54273 54266 54266 54932 54942 55673 54944 54268 56417 55673 54268 54269 54946 55677 54271 54270 54269 54279 54271 54269 55677 54279 54269 55678 54946 54272 54272 55672 55678 54272 54273 55672 54274 54273 54272 54273 55666 55672 54273 54942 55666 54276 54275 54274 54943 54939 54277 55679 54943 54277 54944 54281 54278 55675 54285 54279 55676 55675 54279 56414 55676 54279 54279 55677 56414 56438 55693 54280 56442 56438 54280 57000 56442 54280 54280 54951 57000 54280 54281 54951 56416 54951 54281 54281 55673 56416 54281 54944 55673 54282 54947 55670 56418 55674 54283 56419 56418 54283 54283 54284 56419 54284 54285 56419 54945 54285 54284 54285 55675 56419 54286 54291 54948 56426 56425 54287 54287 54293 56426 54287 54288 54293 54288 54289 54293 54299 54293 54289 54291 54292 54948 54950 54948 54292 54292 54297 54950 54293 54299 54304 54293 54960 56426 54961 54960 54293 54294 54952 54954 54954 54295 54294 54310 54309 54300 55684 54950 54301 55696 55684 54301 54301 55694 55696 54301 54302 55694 54302 54966 55694 55705 54967 54303 54303 55697 55705 55698 55697 54303 54305 54309 54310 54958 54309 54305 54959 54958 54305 55690 54959 54305 54305 54956 55690 54974 54311 54306 54307 54315 54316 54307 54311 54315 54969 54312 54309 54309 54958 54969 54977 54315 54311 54311 54974 54977 54969 54313 54312 54970 54314 54313 54313 54969 54970 54314 54970 54973 54981 54316 54315 54315 54980 54981 54315 54977 54980 54981 54334 54316 54317 54327 54993 54328 54327 54317 54324 54321 54318 54318 54323 54324 55710 54319 54318 54318 54321 55710 55706 54983 54319 56447 55706 54319 54319 55710 56447 54320 55711 55712 54320 54996 55711 54320 54985 54996 54320 54984 54985 54320 54321 54984 54322 54321 54320 55712 54322 54320 54321 54324 54326 54321 54322 55710 54321 54326 54984 56447 55710 54322 57012 56447 54322 54322 56448 57012 56449 56448 54322 54322 55712 56449 54325 54324 54323 54330 54325 54323 54323 54329 54330 54324 54325 54326 54330 54326 54325 54995 54984 54326 54326 54330 54995 55717 54993 54327 55721 55717 54327 56445 55721 54327 54327 55709 56445 54327 54328 55709 54339 54330 54329 54330 54337 54995 54338 54337 54330 54339 54338 54330 55007 54340 54332 55727 55005 54333 54333 54335 55727 54336 54335 54333 54333 54334 54336 54981 54336 54334 54335 54336 54981 56458 55727 54335 54335 54980 56458 54981 54980 54335 56463 54995 54337 56471 56463 54337 54337 55736 56471 54337 54338 55736 54338 54345 55736 55008 54344 54340 54340 55007 55008 55726 55003 54341 55741 55726 54341 55742 55741 54341 54341 55738 55742 54341 55011 55738 54341 54343 55011 54341 54342 54343 55012 54343 54342 54343 55012 55739 56465 55011 54343 56473 56465 54343 54343 56466 56473 54343 55739 56466 54354 54353 54344 55016 54354 54344 55744 55016 54344 54344 55008 55744 54345 55734 55736 54345 55733 55734 54345 54346 55733 54347 54346 54345 55017 54349 54348 54348 55014 55017 55015 55014 54348 55756 55755 54350 54350 54357 55756 54352 54351 54350 55755 54352 54350 55006 55002 54351 56475 55006 54351 56483 56475 54351 54351 54352 56483 54352 55755 56483 54353 54354 54360 55751 54360 54354 55753 55751 54354 54354 54364 55753 54365 54364 54354 55016 54365 54354 55017 54368 54356 54358 54359 55023 55024 55023 54359 54359 54363 55024 56500 55764 54360 54360 56498 56500 54360 55751 56498 55764 54361 54360 55762 54372 54362 54362 55021 55762 55022 55021 54362 55025 55024 54363 54364 54365 55745 55758 55753 54364 54364 55757 55758 54364 55745 55757 54365 55016 55744 54365 55744 55745 55760 54371 54366 54366 55746 55760 54366 54367 55746 54368 54367 54366 54367 54368 55017 54367 55014 55746 55017 55014 54367 54371 54370 54369 55030 55026 54370 54370 54371 55030 55760 55030 54371 54382 54373 54372 55775 54382 54372 54372 55769 55775 54372 55762 55769 54374 54383 54385 54384 54383 54374 55034 54384 54374 54374 54375 55034 54375 54386 55034 54388 54386 54375 55052 55039 54376 55039 54377 54376 55039 54396 54377 54379 54378 54377 54396 54379 54377 54396 54389 54379 55047 55033 54381 55777 55047 54381 54381 55776 55777 54381 54382 55776 56503 55776 54382 54382 56501 56503 54382 55775 56501 54392 54385 54383 55035 54392 54383 54383 54384 55035 54384 55034 55035 55037 55034 54386 54386 54387 55037 54388 54387 54386 55779 55037 54387 54387 54388 55779 54388 55050 55779 54388 55049 55050 55051 55049 54388 55053 55040 54389 54389 54396 55053 54390 55049 55051 55062 55049 54390 54390 54391 55062 54391 54400 55062 54392 55035 55038 54393 55066 55069 55067 55052 54393 55069 55067 54393 54396 55039 55053 55043 54398 54397 55046 55043 54397 54397 55045 55046 54398 55044 55070 54398 55043 55044 55061 54400 54399 55071 55062 54400 54400 55061 55071 54401 54402 55066 55078 55066 54402 55079 55078 54402 54402 54405 55079 55082 55081 54403 54403 55080 55082 54404 54412 55089 54404 54409 54412 54405 55091 55804 55804 55079 54405 55090 54411 54406 54406 55087 55090 54411 54410 54406 55102 55095 54407 54407 54408 55102 54408 55101 55102 55104 55101 54408 55099 54412 54409 54414 54413 54410 54410 54411 54414 54411 55090 55803 55810 54414 54411 54411 55807 55810 54411 55803 55807 54412 55072 55089 55073 55072 54412 55088 55073 54412 55099 55088 54412 55818 54417 54413 54413 55810 55818 54413 54414 55810 55095 55094 54415 55836 55112 54416 54416 55818 55836 54416 54417 55818 55847 55104 54418 55826 54423 54419 54419 54420 55826 54420 55824 55826 54420 55108 55824 54420 55105 55108 54420 55098 55105 54420 54422 55098 54425 54431 54438 54425 55119 55120 54425 54438 55119 54428 54427 54426 54429 54428 54426 54430 54429 54426 54427 54428 54442 55125 54442 54428 55128 55125 54428 55868 55128 54428 55869 55868 54428 54428 55118 55869 54428 55116 55118 54428 54429 55116 54429 54430 55116 54431 54432 54438 54435 54434 54433 54441 54440 54434 55122 54441 54434 54434 54435 55122 55861 55122 54435 54435 55856 55861 54436 55122 55123 54436 54441 55122 54436 54439 54441 55123 54437 54436 54437 55123 55865 56555 55855 54437 56558 56555 54437 54437 55864 56558 55865 55864 54437 54438 54449 55119 54450 54449 54438 54439 54440 54441 55125 54443 54442 55129 54446 54443 54443 55128 55129 54443 55125 55128 54445 54447 54455 54462 54457 54446 56577 54462 54446 54446 56567 56577 54446 55132 56567 54446 55129 55132 54447 54454 54455 54447 54448 54454 54448 54458 55130 55860 55119 54449 54449 54450 55860 56559 55860 54450 54450 55124 56559 54456 54452 54451 54456 54453 54452 54453 54456 55127 55858 55127 54456 54456 55135 55858 55140 55130 54458 54458 55138 55140 54458 55137 55138 54458 55136 55137 54470 54461 54459 55890 55152 54461 54461 54470 55890 56577 55134 54462 55133 54470 54462 55134 55133 54462 54463 54464 55158 54464 55146 55158 55147 55146 54464 55874 55147 54464 54464 55131 55874 54467 54466 54465 55142 54467 54465 54465 55141 55142 54465 54468 55141 55872 55135 54466 54466 54467 55872 56566 55872 54467 54467 55873 56566 54467 55142 55873 54468 54469 55141 54470 55879 55890 55882 55879 54470 54470 55133 55882 55148 54474 54471 55888 55148 54471 54473 54477 54478 54473 54474 54477 55161 54477 54474 54474 55148 55161 55157 55145 54476 55166 55157 54476 54476 55163 55166 54476 55159 55163 54487 54478 54477 55162 54487 54477 54477 55161 55162 54487 54486 54478 54486 54485 54478 54479 54480 55165 55929 55165 54480 54480 55914 55929 54480 55167 55914 54480 54489 55167 54481 54491 54492 54481 54490 54491 55925 54490 54481 54481 55169 55925 54481 54482 55169 55170 55169 54482 55171 55170 54482 56604 55875 54483 56609 56604 54483 56610 56609 54483 54483 55172 56610 54483 54484 55172 55173 55172 54484 55195 55173 54484 54485 54493 54494 54485 54486 54493 54486 54487 55162 55919 54493 54486 55920 55919 54486 54486 55162 55920 55180 55167 54489 54489 55178 55180 55168 54491 54490 57290 55168 54490 54490 56615 57290 54490 55925 56615 54491 55168 55191 55927 54494 54493 55928 55927 54493 56611 55928 54493 57270 56611 54493 54493 55919 57270 55927 55174 54494 54497 54496 54495 55189 55178 54496 55190 55189 54496 54496 54497 55190 54497 55177 55190 55934 55199 54498 54498 55191 55934 54499 55203 55208 54499 55192 55203 55211 54503 54500 55221 54504 54501 54501 55199 55221 55212 54507 54502 54515 54514 54503 55220 54515 54503 54503 55211 55220 55220 55211 54504 55221 55220 54504 55955 55212 54505 54505 54518 55955 54505 54506 54518 54507 55212 55948 55213 54522 54508 54508 55208 55213 55951 55935 54509 54509 54510 55951 55935 55194 54509 56627 55951 54510 54510 54511 56627 56639 56627 54511 54511 54512 56639 54512 54513 55966 54512 55966 56639 54513 54523 55968 55968 55966 54513 55984 54535 54514 56657 55984 54514 54514 56645 56657 54514 54515 56645 54515 55220 56643 57318 56645 54515 54515 56641 57318 56643 56641 54515 54516 54517 54518 54519 54518 54517 54518 55954 55955 54518 54519 55954 54520 55973 55987 54520 54522 55973 54530 54521 54520 55987 54530 54520 54522 55228 55973 55229 55228 54522 54522 55222 55229 54522 55213 55222 55969 55240 54524 54524 55237 55969 54524 54525 55237 54525 54526 55237 54526 55231 55237 54526 54527 55231 55232 55231 54527 54527 54529 55232 55234 54529 54528 55238 55234 54528 55233 55232 54529 55234 55233 54529 55994 55244 54530 54530 55987 55994 54531 54533 55235 54531 54532 54533 54537 54533 54532 54533 54537 55235 54534 55981 55983 55982 55981 54534 55990 55982 54534 54534 55984 55990 54534 54535 55984 55236 54537 54536 54536 54540 55236 55236 55235 54537 55245 54540 54538 55248 55245 54538 54538 54547 55248 54538 54539 54547 54539 54543 54547 55988 55236 54540 55996 55988 54540 54540 55245 55996 54541 54542 54543 54547 54543 54542 55995 54546 54544 54544 54559 55995 54545 54546 55993 55995 55993 54546 54547 55247 55248 54547 54561 55247 54567 54560 54548 54571 54567 54548 54548 54565 54571 54549 55241 55992 55992 54550 54549 56008 54562 54550 54550 55992 56008 54551 54552 54553 55255 54553 54552 55255 54554 54553 54554 55254 55293 55255 55254 54554 56011 54555 54554 54554 55293 56011 55256 54557 54555 56010 55256 54555 56012 56010 54555 54555 56011 56012 54556 54557 55256 55249 54559 54558 55260 55249 54558 56015 55995 54559 54559 56013 56015 56014 56013 54559 54559 55250 56014 55251 55250 54559 54559 55249 55251 55247 54561 54560 55272 55247 54560 54560 54566 55272 54567 54566 54560 54562 56008 56009 55286 55255 54563 54563 54576 55286 55296 55289 54564 54564 55271 55296 55283 55272 54566 55291 55283 54566 54566 55290 55291 54566 54567 55290 54567 54571 55290 55285 55284 54568 56704 55285 54568 54568 54569 56704 54570 54569 54568 55284 54570 54568 54569 56006 56704 56008 56006 54569 54569 54570 56008 56009 56008 54570 55284 54575 54570 55297 55290 54571 54571 54572 55297 55304 55297 54572 54574 55299 55300 54574 54575 55299 54575 55284 55299 55292 55286 54576 54577 55289 56047 54580 54579 54578 55309 54580 54578 56715 55309 54578 54578 56706 56715 54578 55302 56706 54578 54579 55302 54579 54580 55295 54579 55277 55302 55281 55277 54579 55295 55281 54579 54600 54599 54580 56074 54600 54580 54580 55309 56074 54580 54589 55295 54590 54589 54580 54599 54590 54580 54581 54589 54590 54581 54582 54589 55295 54589 54582 55310 55295 54582 54582 54591 55310 56052 54602 54583 54584 54585 55322 54586 54585 54584 54587 54586 54584 54585 54586 56077 56732 55322 54585 54585 56077 56732 54586 56065 56066 54586 54587 56065 54586 56066 56077 54587 54588 56065 54591 55303 55310 54591 54592 55303 56075 55303 54592 54592 56042 56075 56082 56042 54592 54592 54609 56082 55311 54594 54593 55305 55304 54594 55311 55305 54594 55334 54603 54595 54595 55324 55334 54595 55313 55324 54595 54596 55313 55333 55313 54596 54596 54604 55333 54607 54606 54597 55342 54607 54597 54597 55340 55342 54597 54598 55340 54598 54600 55340 54598 54599 54600 55343 55340 54600 56074 55343 54600 54610 54609 54601 54618 54610 54601 56052 55329 54602 55334 55312 54603 54604 54612 55333 55348 55345 54605 54605 55347 55348 54605 54607 55347 54608 54607 54605 54606 54607 54608 54607 55342 55347 54609 55354 56082 54609 54610 55354 54610 55353 55354 54610 54616 55353 54618 54616 54610 54623 54619 54611 55329 54623 54611 55327 54620 54613 54613 54614 55327 54615 54614 54613 54620 54615 54613 55328 55327 54614 55339 55328 54614 55357 55339 54614 54614 54622 55357 54614 54615 54622 54615 54621 54622 54615 54620 54621 54616 54617 54634 54618 54617 54616 56107 55353 54616 54616 55364 56107 54616 54633 55364 54634 54633 54616 54617 54627 54634 54620 55335 55336 54620 55327 55335 54628 54621 54620 55344 54628 54620 54620 55336 55344 54624 54622 54621 54629 54624 54621 54621 54628 54629 54622 54625 55357 54622 54624 54625 54623 56089 56091 56092 56089 54623 54623 55330 56092 54623 55329 55330 54626 54625 54624 54631 54626 54624 54624 54629 54631 55358 55357 54625 56098 55358 54625 54625 54626 56098 54626 55368 56098 54626 54631 55368 55363 54640 54628 56116 55363 54628 54628 56097 56116 54628 55344 56097 54630 54629 54628 54640 54630 54628 54632 54631 54629 54629 54630 54632 54639 54632 54630 54640 54639 54630 55370 55368 54631 54631 54632 55370 55380 55370 54632 54632 54639 55380 54636 55361 55367 54636 54638 55361 54636 54637 54638 54649 54638 54637 54638 55360 55361 54638 54649 55360 54639 54650 55380 54639 54641 54650 54639 54640 54641 55363 55360 54640 55360 54641 54640 54641 54649 54650 55360 54649 54641 54652 54651 54642 54642 54643 54652 55371 54652 54643 54643 55359 55371 55366 54645 54644 55375 55366 54644 55377 55375 54644 54644 55365 55377 55383 54674 54647 54647 54648 55383 55386 54649 54647 54647 55384 55386 55385 55384 54647 54647 54675 55385 54647 54674 54675 55386 54650 54649 55386 55380 54650 54652 55371 55387 54659 54654 54653 54663 54660 54654 56135 54663 54654 54654 54659 56135 55374 55372 54655 54655 54658 55374 54655 54656 54658 54657 54656 54655 55372 54657 54655 54666 54658 54656 54656 54657 54666 55373 55365 54657 54657 55372 55373 56129 55374 54658 54658 55390 56129 54658 54667 55390 54658 54666 54667 56769 56135 54659 54659 55389 56769 54663 54661 54660 56142 56141 54661 54661 54662 56142 54663 54662 54661 56141 55393 54661 56771 56142 54662 56772 56771 54662 54662 56137 56772 54662 56136 56137 54662 54663 56136 54663 56135 56136 54668 54667 54665 54669 54668 54665 54670 54669 54665 54667 54666 54665 56129 55390 54667 54667 54668 56129 56138 56129 54668 56146 56138 54668 56155 56146 54668 54668 56149 56155 54668 55417 56149 54668 54703 55417 54668 54669 54703 54671 54672 54692 54672 54681 54692 55407 54701 54673 54676 54675 54674 56763 55385 54675 54675 54676 56763 56773 56763 54676 57439 56773 54676 54676 57438 57439 54676 55399 57438 54677 54678 55399 55402 55399 54678 54678 54682 55402 54701 54689 54679 54691 54690 54680 54681 54691 54692 54681 54690 54691 54683 54684 55403 54685 54698 55405 55405 55404 54685 55415 55406 54686 54686 54687 55415 54687 54688 56154 56152 55415 54687 56153 56152 54687 56154 56153 54687 54688 54699 56154 54689 54702 54707 54689 54701 54702 55408 54694 54693 54693 55400 55408 55401 55400 54693 54693 55397 55401 54694 55408 55409 56163 54705 54695 54695 54696 56163 54696 55412 56163 54696 55411 55412 56151 55402 54697 56159 56151 54697 54697 55414 56159 54697 55413 55414 55406 55405 54698 56161 56154 54699 54699 54700 56161 54700 54706 55426 56179 56161 54700 54700 55426 56179 55407 54702 54701 54702 56148 56167 54702 55407 56148 55420 54707 54702 56167 55420 54702 54703 55416 55417 54703 54704 55416 55418 55416 54704 56804 56178 54705 54705 56163 56804 55420 54709 54707 54708 54710 54712 54709 55421 55427 54709 55420 55421 54710 54711 54712 54713 54712 54711 55435 54726 54714 54734 54733 54715 55432 54717 54716 56191 55432 54716 54716 56190 56191 54716 54718 56190 54724 54719 54717 55432 54724 54717 54718 55431 56190 54718 55425 55431 54724 54720 54719 54720 54724 54725 54723 54722 54721 54727 54723 54721 55423 55418 54721 55428 55423 54721 54721 54722 55428 54722 54723 54738 55437 55428 54722 56813 55437 54722 54722 56206 56813 54722 54738 56206 54723 54728 54738 54723 54727 54728 55432 54725 54724 54725 55438 56195 54725 55433 55438 54725 55432 55433 55443 55441 54726 56200 55443 54726 54726 55440 56200 54726 55439 55440 54726 55435 55439 54728 54729 54738 54729 54736 54738 54729 54730 54736 54737 54736 54730 54733 54732 54731 54731 54732 54739 56201 54740 54732 54732 54733 56201 54740 54739 54732 55445 54738 54736 54736 54737 55445 54737 55444 55445 54737 54739 55444 54738 55445 56206 54739 54740 56202 55448 55444 54739 56826 55448 54739 56827 56826 54739 54739 56202 56827 54740 54741 55450 56201 54741 54740 54740 55450 56202 55442 54748 54742 54742 54744 55442 56207 54744 54743 54743 55455 56207 56203 55442 54744 56207 56203 54744 54746 55451 55452 54746 54747 55451 54747 54748 55451 54748 55442 55451 56209 55454 54749 54749 55443 56209 54749 54750 55443 54750 55441 55443 55460 55459 54751 54751 54753 55460 55486 54762 54752 54752 54760 55486 55468 55460 54753 55469 55468 54753 54753 54763 55469 54754 56218 56228 54754 55461 56218 55463 55462 54755 56217 55463 54755 54755 55477 56217 55473 54758 54756 54756 54759 55473 54757 54758 55485 54757 55488 55512 54757 55485 55488 54758 55473 55474 54758 55474 55485 56231 55486 54760 54760 55466 56231 54760 55452 55466 56237 55480 54761 56865 56237 54761 54761 55496 56865 54761 54773 55496 55476 55469 54763 54763 54764 55476 55487 55476 54764 54764 54767 55487 54775 54774 54765 54791 54782 54766 55512 54791 54766 55494 55487 54767 56246 55494 54767 54767 55499 56246 55501 55499 54767 55498 55497 54768 54768 54776 55498 54768 54769 54776 54770 54769 54768 54769 54775 54776 54769 54770 54775 54770 54774 54775 55496 54773 54772 54777 54776 54775 54780 54777 54775 55504 55498 54776 56270 55504 54776 54776 54777 56270 56271 56270 54777 54777 55514 56271 55515 55514 54777 54777 54790 55515 54777 54780 54790 56263 55505 54778 54778 56256 56263 54778 56255 56256 54778 56253 56255 54778 55492 56253 54779 55508 55509 54780 54789 54790 54780 54781 54789 54781 54788 54789 54781 54782 54788 54800 54788 54782 54782 54791 54800 55525 55524 54783 56269 55525 54783 54783 54784 56269 54783 54785 55495 54786 54785 54783 56285 54786 54783 54783 55524 56285 54784 54819 56269 55496 55495 54785 54785 54786 55496 56865 55496 54786 58211 56865 54786 54786 57565 58211 54786 56285 57565 55510 54793 54787 54790 54789 54788 55515 54790 54788 54788 54798 55515 54800 54798 54788 55512 55511 54791 56272 54800 54791 56882 56272 54791 54791 56868 56882 56869 56868 54791 54791 55511 56869 56263 55513 54792 54792 55505 56263 56277 54814 54794 56289 56277 54794 54794 54795 56289 54795 55516 55517 54795 55513 55516 54795 55517 56289 55509 54797 54796 55523 54811 54797 54797 55508 55523 55509 55508 54797 55529 55515 54798 54798 54799 55529 54800 54799 54798 54799 55528 55529 54799 54800 55528 56273 55528 54800 54800 56272 56273 56249 55491 54801 54801 54802 56249 56871 56249 54802 54802 55538 56871 55532 54812 54803 54803 54813 55532 54803 54804 54813 56297 54813 54804 54804 56286 56297 54804 55526 56286 54815 54807 54805 54816 54815 54805 54805 54806 54816 54807 54806 54805 55520 54816 54806 54806 55519 55520 56280 55519 54806 56284 56280 54806 54806 54809 56284 54806 54807 54809 54807 54808 54809 54810 54809 54808 54809 55522 56284 54809 54811 55522 54809 54810 54811 55523 55522 54811 55532 54818 54812 55540 55532 54813 56298 55540 54813 54813 56297 56298 54815 55521 55535 54815 54816 55521 54816 55520 55521 56269 54819 54818 54818 54820 56269 54821 54820 54818 54822 54821 54818 54823 54822 54818 55532 54823 54818 54820 55525 56269 54820 55524 55525 57566 55524 54820 54820 56894 57566 54820 54821 56894 54821 54822 56894 54822 56310 56894 54822 54823 56310 54823 56302 56310 54823 55532 56302 55553 55533 54824 54824 55534 55553 55543 55534 54824 55551 55541 54826 55552 55551 54826 56296 55542 54827 54827 56289 56296 54827 56277 56289 54830 54831 54832 55544 55543 54832 55558 54834 54833 54833 55557 55558 55559 54844 54834 54834 55558 55559 55560 54836 54835 54837 54843 54849 54837 54838 54843 54839 54838 54837 55562 54839 54837 54837 54849 55562 54838 54842 55564 54838 54839 54842 55567 54842 54839 55574 55567 54839 54839 54857 55574 55573 54857 54839 54839 55565 55573 54839 55562 55565 56322 55560 54840 56921 56322 54840 54840 54841 56921 54841 56331 56921 55567 55564 54842 55563 54852 54844 54844 55559 55563 56329 54847 54845 54845 54848 56329 54845 54846 54848 56329 54859 54847 54848 55568 56329 55569 55568 54848 55575 55569 54848 54848 54851 55575 55565 55562 54849 55566 55565 54849 55570 55566 54849 54849 54850 55570 54850 55561 55570 55574 54858 54852 56330 55574 54852 56923 56330 54852 54852 54853 56923 54854 54853 54852 55563 54854 54852 57608 56923 54853 54853 57603 57608 57604 57603 54853 54853 54854 57604 54854 56920 57604 54854 55563 56920 54857 54856 54855 54858 54857 54855 54856 54857 55573 55573 54866 54856 54857 54858 55574 56329 55568 54859 54864 54860 54859 54859 54863 54864 56925 54863 54859 54859 56924 56925 54859 55568 56924 56333 55575 54861 54861 55578 56333 56335 54864 54862 56336 56335 54862 56933 56336 54862 54862 56925 56933 54862 54863 56925 54864 54863 54862 56335 54870 54864 54866 55571 55572 55573 55571 54866 55581 54868 54867 54868 55581 55582 56929 55580 54868 56930 56929 54868 54868 55582 56930 56335 55583 54869 54869 54870 56335 55585 55584 54871 54873 54872 54871 55584 54873 54871 54872 54873 54874 54875 54874 54873 55584 54875 54873 55592 55591 54875 54875 55589 55592 54875 55588 55589 54875 55584 55588 55597 54877 54876 55598 55597 54876 56340 55598 54876 55597 54886 54877 54889 54880 54878 54878 54887 54889 54879 54890 55600 54891 54890 54879 54882 54881 54880 54889 54882 54880 56351 55615 54881 54881 55612 56351 54881 55611 55612 54881 54882 55611 54881 55606 55607 55615 55606 54881 54882 54897 55611 54882 54887 54897 54889 54887 54882 54896 54888 54883 54899 54884 54883 54883 54888 54899 54884 55602 55603 54884 55598 55602 54884 54899 55598 54897 54887 54885 54885 54895 54897 54896 54895 54885 54885 54888 54896 54885 54886 54888 54887 54886 54885 55597 54888 54886 55597 54899 54888 54890 54891 56355 55601 55600 54890 56355 55601 54890 54891 54898 56347 54891 56347 56355 55610 55609 54892 54892 55603 55610 54894 54893 54892 55609 54894 54892 55609 55608 54894 54903 54897 54895 54904 54903 54895 54897 54903 55611 54898 56346 56347 56359 56346 54898 54898 56358 56359 54898 55622 56358 54898 54905 55622 54899 55597 55598 54900 56349 56356 54900 56345 56349 54900 55608 56345 55613 55608 54900 56364 56360 54900 54900 54901 56364 54902 54901 54900 56356 54902 54900 56952 56364 54901 56954 56952 54901 56955 56954 54901 57639 56955 54901 54901 57637 57639 54901 54902 57637 54902 57636 57637 54902 56348 57636 56356 56348 54902 54903 54904 55617 56352 55611 54903 54903 55617 56352 57624 56945 54906 57625 57624 54906 54906 55619 57625 55629 55628 54907 54907 54908 55629 54908 54909 55629 54909 54910 55629 54911 54910 54909 56363 54911 54909 56368 55629 54910 56953 56368 54910 54910 56951 56953 54910 54911 56951 54911 56353 56951 56357 56353 54911 56363 56357 54911 55637 55625 54912 54912 55636 55637 54912 54917 55636 54913 54914 54916 54915 55626 55635 55635 54916 54915 55634 55633 54916 56381 55634 54916 54916 55635 56381 56383 55636 54917 54917 55639 56383 55638 55630 54918 54918 55631 55638 55655 55640 54922 54922 55651 55655 54923 55641 55642 54926 54925 54924 54928 54926 54924 55652 55645 54925 54925 54926 55652 54926 54928 55652 54933 54932 54927 56402 54933 54927 54927 55656 56402 54928 54929 55652 54929 55645 55652 55657 55645 54929 56982 55656 54930 57657 56982 54930 57667 57657 54930 54930 57663 57667 54930 56971 57663 54930 54931 56971 54931 55642 56971 54932 54933 54942 55666 54942 54933 56401 55666 54933 56402 56401 54933 54935 54936 55664 55665 55664 54936 55669 55665 54936 55670 55669 54936 55668 55667 54938 54938 54940 55668 54938 54939 54940 54941 54940 54939 54943 54941 54939 56986 55668 54940 54940 56421 56986 54940 54941 56421 54941 55680 56421 54941 55679 55680 54941 54943 55679 55678 55677 54946 55674 55670 54947 54948 54950 55684 55687 54952 54949 54951 56989 57000 54951 56416 56989 55687 54953 54952 54952 54953 54954 54953 55687 56427 55685 54954 54953 56428 55685 54953 54953 56427 56428 56429 55688 54954 54954 55685 56429 55688 54957 54955 54957 54956 54955 54956 54957 55690 54957 54962 55690 54963 54962 54957 56430 54963 54957 54957 55688 56430 54972 54969 54958 54958 54959 54972 56431 54972 54959 54959 55689 56431 55690 55689 54959 54960 54961 55707 56439 56426 54960 54960 55707 56439 54961 54968 55707 56995 55690 54962 54962 56994 56995 57686 56994 54962 54962 57684 57686 54962 54963 57684 58966 57684 54963 54963 56430 58966 54986 54966 54964 54987 54986 54964 54964 54982 54987 54964 54965 54982 55704 55694 54966 54966 54986 55704 55705 54979 54967 54968 54983 55707 54972 54970 54969 54970 55691 55702 54970 54971 55691 54972 54971 54970 54975 54973 54970 55702 54975 54970 55692 55691 54971 56433 55692 54971 57002 56433 54971 54971 56431 57002 54971 54972 56431 54975 54974 54973 54974 54976 54977 54974 54975 54976 55702 54976 54975 56451 54977 54976 56452 56451 54976 54976 55703 56452 54976 55702 55703 56451 54980 54977 56445 55709 54978 54978 56444 56445 54978 56441 56444 54978 54979 56441 56443 56441 54979 54979 55705 56443 56459 56458 54980 56460 56459 54980 54980 56451 56460 54988 54987 54982 54991 54988 54982 54997 54991 54982 54983 55706 55707 54995 54985 54984 54985 54995 54996 55708 55704 54986 54986 54988 55708 54986 54987 54988 55715 55708 54988 54988 54989 55715 54990 54989 54988 54992 54990 54988 54988 54991 54992 54989 55714 55715 55730 55714 54989 54989 54990 55730 54990 55728 55730 54990 55000 55728 54990 54992 55000 54998 54992 54991 54991 54997 54998 54992 54998 55000 55717 54994 54993 55009 55007 54994 55732 55009 54994 54994 55731 55732 54994 55717 55731 55737 54996 54995 56463 55737 54995 55713 55711 54996 56450 55713 54996 57715 56450 54996 54996 56456 57715 54996 55737 56456 54999 54998 54997 55740 55000 54998 54998 54999 55740 54999 55724 55740 54999 55006 55724 55729 55728 55000 55743 55729 55000 55000 55740 55743 55725 55010 55003 55726 55725 55003 55739 55013 55004 57027 55739 55004 55004 56459 57027 55004 55005 56459 55005 55727 56459 56475 55724 55006 55009 55008 55007 56477 55744 55008 57042 56477 55008 55008 56469 57042 55008 55732 56469 55008 55009 55732 55725 55015 55010 56465 55738 55011 55012 55013 55739 55747 55746 55014 55754 55747 55014 56482 55754 55014 55014 56478 56482 55014 55015 56478 55015 55725 56478 55018 55028 55761 55018 55019 55028 55761 55020 55018 56486 55022 55020 55020 56485 56486 55020 55761 56485 55763 55762 55021 56488 55763 55021 55021 56487 56488 55021 55022 56487 55022 56486 56487 56489 55756 55023 55023 55024 56489 55024 55770 56489 55024 55025 55770 56502 55770 55025 55025 55032 56502 55025 55031 55032 55746 55027 55026 55760 55746 55026 55026 55030 55760 55029 55028 55027 55746 55029 55027 55028 55029 55747 55028 55747 55761 55029 55746 55747 57064 56502 55032 57084 57064 55032 55032 56504 57084 55032 55771 56504 55772 55771 55032 55032 55041 55772 55037 55035 55034 55035 55037 55038 55042 55041 55036 55778 55038 55037 55779 55778 55037 55038 55778 55781 55058 55053 55039 55039 55052 55058 55040 55054 55055 55040 55053 55054 55041 55042 55772 55042 55055 55772 55043 55780 56507 55043 55046 55780 56507 55044 55043 55785 55070 55044 57117 55785 55044 55044 56507 57117 55774 55046 55045 55045 55048 55774 55045 55047 55048 55046 55774 55780 55777 55048 55047 55048 55773 55774 55777 55773 55048 56510 55050 55049 55049 55062 56510 57107 55779 55050 57110 57107 55050 57122 57110 55050 57123 57122 55050 55050 55063 57123 56510 55063 55050 55067 55058 55052 55059 55054 55053 55060 55059 55053 55782 55060 55053 55053 55058 55782 55056 55055 55054 55057 55056 55054 55059 55057 55054 55055 55771 55772 55055 55056 55771 56504 55771 55056 57076 56504 55056 55056 56511 57076 55056 55057 56511 55057 55060 56511 55057 55059 55060 56511 55782 55058 56512 56511 55058 56517 56512 55058 55058 56514 56517 55058 55067 56514 55060 55782 56511 55072 55071 55061 55089 55072 55061 55062 55065 56510 55071 55065 55062 56510 55065 55063 57812 57123 55063 55063 57138 57812 55063 55064 57138 55065 55064 55063 55064 57134 57138 55064 56521 57134 55064 55801 56521 55064 55073 55801 55064 55072 55073 55064 55071 55072 55064 55065 55071 55066 55068 55069 55078 55068 55066 56515 56514 55067 55067 55069 56515 56518 56516 55068 55068 55078 56518 56516 55069 55068 56516 56515 55069 55788 55787 55070 55070 55785 55788 55073 55106 55801 55073 55088 55106 55803 55087 55074 55811 55803 55074 56529 55811 55074 55074 56523 56529 55074 55075 56523 55075 55076 57126 56530 56523 55075 57132 56530 55075 57133 57132 55075 55075 57126 57133 55076 55077 57126 55077 55786 57127 57127 57126 55077 56525 56518 55078 55078 56524 56525 55078 55794 56524 55795 55794 55078 55078 55079 55795 55804 55795 55079 55084 55082 55080 55085 55084 55080 55787 55085 55080 55081 55097 55103 55081 55083 55097 55081 55082 55083 55084 55083 55082 55105 55097 55083 55796 55105 55083 55083 55084 55796 55084 55791 55796 55084 55086 55791 55084 55085 55086 55787 55086 55085 55793 55792 55086 55086 55788 55793 55086 55787 55788 55792 55791 55086 55803 55090 55087 55107 55106 55088 55838 55107 55088 55088 55111 55838 55088 55099 55111 55091 55092 55805 55805 55804 55091 55092 55093 55805 55819 55805 55093 55822 55819 55093 55093 55100 55822 55093 55094 55100 55094 55095 55100 55102 55100 55095 55103 55098 55096 55097 55098 55103 55105 55098 55097 55099 55110 55111 55100 55101 56537 55102 55101 55100 55100 55821 55822 56536 55821 55100 55100 55845 56536 56537 55845 55100 55101 55113 56537 55847 55113 55101 55101 55104 55847 55109 55108 55105 55796 55109 55105 55802 55801 55106 55828 55802 55106 55106 55806 55828 55106 55107 55806 55828 55806 55107 55107 55827 55828 55839 55827 55107 55107 55838 55839 55108 55109 55812 55825 55824 55108 55108 55812 55825 55109 55796 55812 55849 55111 55110 55850 55838 55111 55852 55850 55111 57141 55852 55111 55111 56542 57141 55111 55849 56542 55846 55845 55113 55113 55114 55846 55115 55114 55113 55854 55115 55113 55855 55854 55113 55113 55847 55855 55113 55845 56537 57845 55846 55114 57846 57845 55114 55114 55115 57846 55115 57166 57846 55115 56546 57166 55115 55854 56546 55116 55117 55118 56562 55118 55117 55117 56544 56562 57162 55869 55118 55118 56562 57162 55121 55120 55119 55860 55121 55119 55120 56547 56548 55120 55121 56547 56557 56547 55121 55121 55860 56557 55863 55123 55122 55122 55861 55863 55123 55863 55865 55124 55859 56559 55124 55126 55859 55126 55857 55859 55858 55857 55127 55866 55129 55128 55868 55866 55128 55867 55132 55129 55129 55866 55867 55140 55131 55130 55131 55140 55874 55132 55867 55871 58548 56567 55132 55132 55871 58548 55133 55134 55882 55134 56577 57226 55883 55882 55134 57226 55883 55134 55872 55858 55135 55139 55138 55137 55144 55139 55137 56583 55140 55138 55138 55139 56583 56589 56583 55139 55139 55892 56589 55139 55144 55892 56584 55874 55140 55140 56583 56584 55143 55142 55141 55875 55143 55141 55142 55143 55873 56580 55873 55143 55143 55896 56580 55143 55875 55896 55144 55156 55892 55144 55145 55156 55157 55156 55145 55160 55158 55146 56585 55160 55146 55146 55147 56585 55147 55874 56585 55902 55161 55148 55148 55889 55902 55148 55888 55889 55908 55907 55150 55150 55151 55908 55909 55908 55151 55151 55152 55909 56597 55909 55152 55152 55910 56597 55911 55910 55152 55152 55890 55911 55911 55879 55153 55153 55910 55911 57253 55910 55153 55153 55154 57253 55155 55154 55153 55880 55155 55153 55153 55879 55880 57254 57253 55154 55154 55155 57254 55155 57244 57254 55155 56598 57244 55155 55880 56598 56589 55892 55156 56591 56589 55156 55156 56590 56591 55156 55884 56590 55156 55157 55884 56599 55884 55157 56602 56599 55157 55157 55166 56602 56603 55171 55160 55160 55893 56603 55894 55893 55160 56585 55894 55160 55899 55162 55161 55900 55899 55161 55902 55900 55161 56601 55920 55162 55162 55899 56601 56608 55166 55163 55163 55164 56608 55164 56607 56608 55164 55921 56607 55164 55165 55921 55929 55921 55165 56608 56602 55166 55167 55179 55914 55180 55179 55167 56622 56621 55168 57288 56622 55168 57290 57288 55168 55934 55191 55168 55168 55933 55934 56621 55933 55168 55926 55925 55169 55169 55170 55926 57279 55926 55170 55170 57263 57279 55170 57262 57263 55170 55171 57262 55171 57257 57262 55171 56603 57257 56616 56610 55172 55172 55930 56616 55172 55173 55930 55173 55195 55930 55927 55176 55174 55175 55176 55932 55932 55177 55175 55176 55927 55932 57272 55190 55177 55177 56613 57272 55177 55932 56613 55189 55180 55178 55179 55180 55189 57286 55914 55179 55179 57285 57286 55179 55189 57285 55181 55182 56618 55183 55182 55181 55198 55183 55181 56626 55198 55181 55181 56619 56626 55181 56618 56619 55182 55912 55915 55913 55912 55182 55182 55183 55913 55182 55915 56618 55183 55187 55913 55183 55185 55187 55183 55184 55185 55198 55184 55183 55197 55196 55184 55198 55197 55184 55186 55185 55184 55196 55186 55184 55916 55187 55185 55185 55188 55916 55185 55186 55188 55196 55188 55186 55917 55913 55187 55918 55917 55187 55187 55916 55918 57267 55916 55188 57282 57267 55188 55188 56620 57282 55188 55931 56620 55188 55196 55931 55189 57284 57285 55189 55190 57284 57296 57284 55190 55190 57272 57296 55192 55201 55203 55192 55200 55201 55192 55193 55200 55939 55200 55193 55193 55207 55939 55930 55195 55194 55935 55930 55194 55196 55206 55931 55196 55197 55206 55209 55206 55197 55197 55204 55209 55205 55204 55197 55197 55198 55205 56626 55205 55198 55938 55221 55199 55199 55934 55938 55202 55201 55200 55950 55202 55200 55200 55940 55950 55200 55939 55940 55941 55203 55201 55201 55202 55941 55950 55941 55202 55941 55208 55203 55204 55205 55943 55210 55209 55204 55223 55210 55204 55942 55223 55204 55943 55942 55204 55205 56626 56630 56630 55943 55205 56631 55931 55206 56636 56631 55206 55206 55216 56636 55206 55209 55216 55949 55939 55207 55222 55213 55208 55941 55222 55208 55209 55215 55216 55209 55214 55215 55209 55210 55214 55224 55214 55210 55210 55223 55224 55972 55948 55212 55212 55971 55972 55212 55955 55971 55224 55215 55214 55946 55216 55215 55215 55224 55946 55216 55944 56636 55946 55944 55216 55217 55218 57309 55219 55218 55217 55938 55219 55217 55217 55221 55938 55952 55221 55217 57309 55952 55217 55218 55219 57302 55218 57302 57309 55938 55933 55219 55219 55933 57302 55220 55221 55947 55220 55947 56643 55952 55947 55221 55941 55229 55222 55959 55224 55223 55223 55942 55959 55964 55946 55224 55224 55227 55964 55224 55226 55227 55959 55226 55224 55227 55226 55225 56644 55227 55225 56647 56644 55225 57333 56647 55225 55225 57332 57333 55225 57325 57332 55225 55226 57325 55226 55963 57325 55226 55959 55963 55965 55964 55227 56648 55965 55227 55227 56644 56648 56663 55973 55228 55228 55229 56663 55229 55957 56663 55229 55941 55957 55230 55236 55974 55969 55237 55231 55976 55969 55231 56650 55976 55231 55231 55977 56650 55231 55232 55977 55978 55977 55232 55232 55233 55978 55980 55978 55233 55233 55234 55980 55234 55238 55980 55988 55974 55236 56655 55980 55238 55238 55983 56655 55239 55953 55954 55986 55953 55239 55239 55985 55986 55976 55242 55240 55240 55969 55976 56685 55992 55241 55241 56665 56685 55241 55242 56665 55242 56651 56665 55242 55976 56651 56668 55985 55243 55243 55993 56668 55253 55246 55244 55994 55253 55244 55997 55996 55245 55245 55248 55997 55270 55252 55246 55246 55253 55270 55997 55248 55247 55998 55997 55247 55247 55272 55998 55260 55251 55249 57350 56014 55250 55250 56025 57350 55250 55258 56025 55250 55251 55258 55260 55258 55251 55252 55269 55271 55270 55269 55252 56693 55270 55253 57342 56693 55253 55253 56671 57342 55253 56670 56671 55253 55994 56670 55254 55286 55293 55254 55255 55286 56010 55257 55256 56026 55259 55257 56689 56026 55257 55257 56688 56689 55257 56012 56688 55257 56010 56012 56026 56025 55258 55258 55259 56026 55265 55263 55261 55266 55265 55261 55282 55266 55261 55261 55279 55282 55261 55262 55279 55263 55262 55261 55262 55278 55279 55262 55264 55278 55262 55263 55264 56696 55264 55263 55263 56030 56696 56031 56030 55263 56691 56031 55263 56692 56691 55263 55263 55268 56692 55263 55265 55268 55264 55273 55278 56036 55273 55264 56696 56036 55264 55265 55267 55268 55265 55266 55267 56042 55271 55266 56044 56042 55266 55266 55288 56044 55266 55282 55288 55271 55267 55266 55271 55269 55267 55269 55268 55267 55268 55270 56692 55268 55269 55270 56693 56692 55270 56042 55296 55271 55272 55291 56049 55272 55283 55291 56697 55998 55272 55272 56049 56697 55275 55274 55273 56036 55275 55273 55273 55276 55278 55273 55274 55276 55274 55275 56035 55277 55276 55274 55287 55277 55274 56035 55287 55274 55275 56029 56035 55275 56028 56029 56036 56028 55275 55276 55280 56037 55281 55280 55276 55276 55277 55281 55279 55278 55276 56037 55279 55276 55277 55287 55302 56037 55282 55279 56044 55288 55280 55280 55303 56044 55310 55303 55280 55280 55281 55310 55280 55288 56037 55281 55295 55310 56037 55288 55282 56041 55299 55284 55284 55285 56041 56050 56041 55285 56704 56050 55285 55286 55292 55293 56706 55302 55287 55287 56029 56706 56035 56029 55287 55289 55296 56047 55298 55291 55290 55290 55297 55298 55291 55298 56049 55294 55293 55292 55301 55294 55292 56024 56011 55293 57368 56024 55293 57373 57368 55293 55293 56709 57373 55293 56061 56709 55293 55294 56061 55294 55301 56059 56720 56061 55294 55294 56059 56720 55296 56043 56047 55296 56042 56043 56048 55298 55297 55297 55305 56048 55297 55304 55305 55298 56048 56049 56046 55300 55299 55299 56041 56046 55300 56051 56058 55300 56046 56051 56710 56044 55303 55303 56075 56710 56054 56048 55305 56064 56054 55305 55305 55311 56064 55306 56727 56728 55306 55307 56727 55308 55307 55306 56058 55308 55306 57393 56727 55307 55307 56736 57393 55307 56726 56736 55307 56719 56726 55307 55308 56719 55308 56714 56719 55308 56051 56714 56058 56051 55308 56730 56074 55309 55309 56724 56730 55309 56715 56724 55311 55323 56064 55312 55334 56066 55333 55324 55313 55314 55317 55320 55325 55317 55314 55326 55325 55314 55314 55315 55326 55316 55315 55314 55320 55316 55314 57380 55326 55315 55315 55316 57380 55316 56723 57380 55316 55320 56723 55321 55319 55317 55325 55321 55317 55317 55318 55320 55319 55318 55317 56063 55320 55318 56723 56063 55318 55318 56070 56723 55318 55319 56070 55319 55321 55328 56071 56070 55319 55319 55338 56071 55319 55328 55338 55320 56063 56723 55321 55327 55328 55321 55325 55327 56733 55323 55322 55322 56732 56733 56725 56064 55323 56740 56725 55323 55323 56733 56740 56079 55334 55324 55324 55332 56079 55333 55332 55324 56080 55337 55325 55325 55326 56080 55335 55327 55325 55336 55335 55325 55337 55336 55325 56737 56080 55326 57388 56737 55326 55326 57380 57388 55339 55338 55328 55329 56076 56083 55329 56052 56076 55331 55330 55329 56083 55331 55329 56739 56092 55330 55330 55331 56739 55331 56082 56739 56083 56082 55331 55332 56068 56079 55332 56067 56068 55332 55355 56067 55332 55333 55355 55333 55341 55355 56079 56068 55334 56068 56066 55334 55336 55337 55344 55337 56080 56742 56742 55344 55337 56073 56071 55338 56085 56073 55338 55338 56084 56085 56744 56084 55338 55338 56096 56744 55338 55339 56096 55339 55357 56096 55351 55350 55340 55340 55343 55351 55350 55342 55340 55349 55347 55342 55350 55349 55342 55352 55351 55343 56074 55352 55343 56741 56097 55344 56742 56741 55344 56103 55359 55345 55345 55348 56103 56119 56104 55346 55346 56106 56119 55346 56105 56106 55346 55349 56105 55346 55347 55349 55348 55347 55346 56104 55348 55346 56104 56103 55348 55349 55350 56105 55350 55351 56752 57419 56105 55350 55350 56752 57419 55351 56751 56752 55351 55352 56751 57405 56751 55352 55352 57398 57405 55352 56730 57398 55352 56074 56730 56090 55354 55353 56108 56090 55353 55353 56107 56108 56739 56082 55354 55354 56092 56739 55354 56089 56092 56090 56089 55354 56094 56067 55355 56095 56094 55355 55355 56093 56095 55355 55356 56093 55356 55375 56093 55356 55366 55375 55357 55358 56096 56099 56096 55358 55358 56098 56099 56103 55371 55359 55362 55361 55360 55363 55362 55360 55361 55362 55367 56112 55367 55362 56754 56112 55362 55362 56115 56754 55362 56113 56115 55362 55363 56113 56114 56113 55363 56750 56114 55363 55363 56116 56750 55365 55373 55377 55367 56112 56123 56124 56098 55368 55368 55369 56124 55370 55369 55368 56133 56124 55369 55369 55381 56133 55369 55370 55381 55370 55380 55381 56125 55387 55371 56126 56125 55371 56760 56126 55371 55371 56103 56760 55374 55373 55372 56109 55377 55373 56120 56109 55373 55373 55374 56120 56758 56120 55374 57430 56758 55374 55374 56129 57430 55375 55376 56093 55377 55376 55375 55376 55377 56109 56095 56093 55376 56746 56095 55376 55376 56121 56746 55376 56109 56121 55378 55382 55392 55378 55379 55382 56122 55382 55379 56132 55381 55380 55380 56130 56132 55380 55386 56130 55381 56132 56133 55395 55392 55382 55398 55395 55382 56122 55398 55382 56131 55386 55384 55384 55385 56131 56763 56131 55385 56131 56130 55386 56125 55388 55387 55388 56125 56140 56770 56769 55389 57451 56770 55389 55389 57442 57451 55389 56134 57442 55391 55395 55397 55391 55392 55395 58125 57434 55394 55394 56762 58125 55394 55398 56762 55394 55395 55398 55396 55395 55394 57434 55396 55394 56147 55397 55395 56775 56147 55395 57454 56775 55395 55395 57447 57454 55395 55396 57447 55396 57434 57447 56147 55401 55397 55398 56122 56762 57471 57438 55399 55399 56151 57471 55399 55402 56151 56158 55408 55400 55400 56150 56158 55400 55401 56150 55401 56147 56150 56166 55413 55403 56798 56166 55403 55403 55404 56798 55404 55405 56798 55405 55415 56798 55405 55406 55415 55407 56145 56148 55410 55409 55408 56790 55410 55408 55408 56781 56790 55408 56158 56781 55412 55411 55409 55409 55410 55412 56792 55412 55410 56793 56792 55410 55410 56790 56793 57470 56163 55412 55412 56792 57470 57482 55414 55413 55413 57481 57482 55413 56805 57481 55413 56166 56805 56164 56159 55414 56165 56164 55414 57479 56165 55414 57482 57479 55414 57472 56798 55415 55415 56799 57472 55415 56152 56799 56149 55417 55416 56157 56149 55416 55416 55424 56157 55416 55418 55424 55418 55423 55424 55422 55421 55420 56167 55422 55420 55436 55427 55421 56186 55436 55421 56187 56186 55421 55421 55422 56187 57475 56187 55422 55422 56168 57475 55422 56167 56168 56169 55424 55423 55423 55428 56169 56170 56157 55424 56171 56170 55424 55424 56169 56171 56184 55431 55425 56185 56179 55426 55428 55437 56169 57504 56809 55429 55429 57498 57504 55429 57489 57498 55429 55430 57489 55431 55430 55429 56809 55431 55429 55430 56807 57489 55430 55431 56184 56809 56190 55431 55434 55433 55432 56191 55434 55432 56819 55438 55433 56820 56819 55433 55433 56818 56820 55433 55434 56818 55434 56815 56818 55434 56191 56815 56199 55439 55435 56817 56199 55435 56811 56185 55436 55436 56186 56811 56188 56169 55437 56813 56188 55437 56819 56195 55438 56199 55440 55439 55440 57506 58174 55440 56199 57506 57512 56200 55440 58176 57512 55440 55440 58174 58176 56204 55451 55442 56205 56204 55442 55442 56203 56205 55443 56200 56209 55446 55445 55444 55448 55446 55444 55445 55446 56206 55446 55449 56206 55446 55448 55449 55449 55448 55447 56829 55449 55447 55447 56212 56829 56826 56212 55447 55447 55448 56826 56211 56206 55449 56829 56211 55449 56839 56202 55450 55450 55465 56839 55453 55452 55451 56204 55453 55451 56216 55466 55452 55452 55453 56216 55453 56215 56216 56828 56215 55453 55453 56204 56828 56209 55464 55454 56831 56207 55455 55455 55456 56831 55456 55457 56831 55457 56226 56831 55457 56221 56226 55457 55458 56221 55458 55459 55467 55458 56220 56221 55458 55467 56220 55459 55460 55467 56220 55467 55460 55460 55468 56220 55461 56217 56218 55461 55463 56217 55461 55462 55463 56209 55471 55464 55471 55470 55464 55465 55484 56838 55465 56838 56839 55466 56219 56231 55466 56216 56219 56222 56220 55468 55468 55469 56222 56223 56222 55469 55469 55476 56223 56235 55479 55470 55470 55471 56235 55471 56229 56848 55471 56209 56229 56236 56235 55471 56848 56236 55471 55472 55482 55484 55483 55482 55472 55490 55485 55474 55474 55475 55490 55491 55490 55475 55476 55487 56223 56858 56217 55477 55477 55478 56858 56864 56858 55478 55478 56234 56864 56230 55481 55480 56237 56230 55480 56230 55483 55481 56849 55484 55482 55482 55483 56849 55483 56241 56849 56242 56241 55483 55483 56240 56242 55483 56230 56240 56849 56838 55484 55489 55488 55485 55490 55489 55485 55486 56231 56245 56232 56223 55487 56856 56232 55487 55487 55494 56856 55488 55511 55512 56247 55511 55488 56866 56247 55488 55488 55489 56866 55489 55490 56248 55489 56248 56866 55490 55491 56248 56249 56248 55491 55492 56250 56253 55492 55493 56250 55493 56243 56250 57532 56856 55494 55494 56259 57532 55494 56246 56259 55497 55526 55527 55497 55504 55526 55497 55498 55504 55501 55500 55499 56257 56246 55499 55499 55500 56257 55500 55501 55506 55500 55506 56257 56252 55503 55502 56867 56252 55502 55502 56233 56867 56260 55508 55503 55503 56252 56260 56287 55526 55504 55504 56270 56287 55506 56246 56257 55506 55507 56246 56267 56246 55507 56268 56267 55507 55507 55530 56268 56260 55523 55508 55527 55526 55510 56875 56869 55511 56876 56875 55511 57540 56876 55511 55511 56247 57540 56263 55516 55513 56888 56271 55514 55514 56292 56888 55514 55515 56292 55515 55529 56292 55518 55517 55516 56264 55518 55516 55516 56263 56264 55517 55518 56883 56296 56289 55517 56907 56296 55517 55517 56883 56907 58246 56883 55518 55518 56264 58246 56280 56275 55519 55531 55521 55520 55521 55534 55535 55521 55531 55534 56893 56284 55522 57563 56893 55522 55522 55523 57563 55523 57558 57572 55523 57557 57558 55523 56260 57557 57572 57563 55523 57566 56285 55524 56287 56286 55526 56288 55529 55528 56885 56288 55528 55528 56884 56885 55528 56868 56884 56882 56868 55528 55528 56276 56882 55528 56273 56276 56896 56292 55529 55529 56895 56896 55529 56288 56895 56880 56268 55530 55530 56258 56880 56278 56258 55530 55530 56275 56278 55531 55533 55534 55532 55540 56302 55553 55534 55533 55543 55535 55534 55535 55543 55544 55536 55541 56294 55537 55538 56294 55539 55538 55537 56890 55539 55537 57575 56890 55537 55537 56301 57575 55537 56294 56301 56891 56871 55538 55538 55539 56891 55539 56890 56891 56305 56302 55540 56311 56305 55540 55540 56299 56311 55540 56298 56299 56295 56294 55541 56308 56295 55541 55541 55551 56308 56319 55557 55542 56320 56319 55542 55542 56296 56320 55547 55546 55545 56917 55547 55545 55545 55554 56917 55546 55547 56312 55547 57599 57600 55547 56917 57599 57592 56312 55547 57600 57592 55547 56306 55549 55548 55549 56306 56910 56912 56313 55550 55550 56911 56912 55550 56910 56911 55551 55552 56308 55552 56307 56308 55554 56321 56918 55554 55555 56321 56918 56917 55554 56322 56321 55555 55555 55560 56322 56324 56307 55556 56325 56324 55556 55556 55564 56325 56319 55558 55557 56326 55559 55558 55558 56319 56326 56326 55563 55559 56316 55570 55561 55561 56315 56316 56913 56315 55561 55561 56317 56913 55563 56914 56920 55563 56326 56914 56328 56325 55564 55564 55567 56328 55565 55571 55573 55572 55571 55565 55577 55572 55565 55565 55566 55577 56922 55577 55566 56926 56922 55566 57614 56926 55566 55566 57610 57614 55566 55570 57610 56330 56328 55567 55567 55574 56330 56927 56924 55568 57612 56927 55568 55568 55569 57612 57613 57612 55569 55569 56332 57613 55569 55575 56332 55570 56316 56327 55570 56327 57610 55577 55576 55572 56333 56332 55575 55576 55577 56922 56926 55579 55576 55576 56922 56926 57617 56333 55578 57618 57617 55578 55578 55579 57618 55579 57614 57618 55579 56926 57614 56334 56331 55580 56929 56334 55580 56931 56930 55582 55582 55583 56931 56933 56931 55583 55583 56336 56933 55583 56335 56336 55584 55585 55588 55590 55588 55585 55585 55586 55590 55587 55586 55585 56337 55587 55585 55585 55599 56337 55586 55587 55593 55593 55590 55586 55587 56337 56938 56938 55593 55587 55590 55589 55588 55589 55593 55595 55589 55590 55593 55595 55592 55589 56339 55596 55591 55591 55592 56339 55592 55594 56339 55595 55594 55592 55593 55594 55595 56939 55594 55593 55593 56938 56939 56936 56339 55594 56940 56936 55594 55594 56939 56940 56944 56341 55596 55596 56344 56944 55596 56339 56344 56340 55602 55598 56342 56337 55599 55600 56338 56342 55600 55601 56338 58289 56338 55601 55601 56355 58289 56340 55605 55602 55605 55603 55602 55603 55604 55610 55605 55604 55603 56345 55610 55604 55604 56343 56345 55604 55605 56343 55605 56341 56343 55608 55609 56345 55609 55610 56345 55614 55612 55611 56352 55614 55611 56354 56351 55612 57623 56354 55612 55612 57622 57623 55612 55614 57622 55614 55618 57622 56352 55618 55614 55615 56353 56357 55615 56351 56353 55618 55617 55616 56947 55618 55616 56948 56947 55616 55616 56946 56948 55616 56362 56946 55616 55617 56362 55617 55618 56352 57630 57622 55618 55618 56947 57630 57626 57625 55619 55619 55620 57626 55621 55620 55619 56360 55621 55619 55620 56950 57626 55620 55621 56950 55621 56949 56950 55621 56364 56949 55621 56360 56364 55622 55623 56358 56359 56358 55623 55623 56346 56359 56375 56346 55623 55623 56365 56375 55624 55625 55631 55638 55631 55625 55625 55637 55638 55626 55627 56370 55628 55627 55626 56370 55635 55626 55627 56367 56960 55627 55628 56367 56960 56370 55627 56368 56367 55628 55628 55629 56368 56392 55641 55630 55630 56371 56392 55630 55637 56371 55638 55637 55630 55634 56381 56967 56964 56381 55635 55635 56370 56964 56369 55637 55636 56961 56369 55636 56962 56961 55636 55636 56383 56962 55637 56369 56371 55639 55640 55655 55639 56382 56383 55639 55655 56382 56392 55642 55641 55642 56392 56971 56385 56373 55643 55643 55644 56385 56398 56385 55644 55644 55645 56398 55645 55657 56398 57645 55649 55646 55646 56370 57645 55646 55647 56370 55648 55647 55646 55649 55648 55646 58310 56964 55647 55647 56397 58310 55647 55648 56397 56964 56370 55647 55648 56395 56397 56977 56395 55648 57661 56977 55648 58320 57661 55648 55648 55649 58320 58946 58320 55649 55649 58314 58946 55649 57645 58314 56397 56395 55650 57652 56397 55650 55650 57651 57652 55650 56967 57651 56970 55655 55651 56976 56970 55651 55651 56400 56976 55651 55660 56400 56396 55654 55653 55653 56395 56396 56396 55658 55654 56968 56382 55655 56970 56968 55655 56412 56402 55656 56982 56412 55656 55658 56396 56403 56403 55661 55658 56400 55660 55659 56411 56400 55659 55659 56410 56411 55659 55664 56410 56406 55662 55661 55661 56403 56406 56406 55663 55662 55663 56407 56417 55663 56404 56407 56406 56404 55663 55664 55671 56410 55664 55665 55671 56418 55671 55665 55665 55674 56418 55665 55669 55674 56401 55672 55666 55667 55668 56408 56986 56408 55668 55669 55670 55674 55671 56418 56419 56419 56410 55671 56401 55678 55672 56988 56416 55673 55673 56417 56988 55675 56410 56419 57675 56410 55675 55675 55676 57675 55676 56414 57675 55677 55678 56420 55677 56413 56414 56420 56413 55677 55678 56401 56420 56422 56421 55680 55680 55684 56422 55681 55682 56997 55683 55682 55681 56422 55683 55681 56436 56422 55681 56997 56436 55681 55682 56435 57003 55682 56434 56435 55682 55683 56434 57003 56997 55682 56422 55684 55683 55683 55696 56434 55683 55684 55696 56992 56429 55685 56993 56992 55685 55685 56428 56993 56428 56427 55686 56991 56428 55686 57001 56991 55686 55686 56990 57001 55686 56424 56990 56432 56430 55688 55688 56429 56432 57002 56431 55689 55689 56995 57002 55689 55690 56995 57009 55702 55691 55691 55692 57009 57691 57009 55692 55692 56433 57691 56438 55698 55693 55694 55695 55696 56440 55695 55694 55694 55704 56440 56434 55696 55695 56435 56434 55695 57003 56435 55695 57692 57003 55695 55695 57005 57692 55695 56440 57005 56443 55705 55697 55697 56442 56443 55697 55698 56442 55698 56438 56442 55699 56425 56439 57688 56425 55699 55699 55700 57688 55701 55700 55699 56439 55701 55699 55700 56455 57694 55700 55701 56455 57696 57688 55700 57697 57696 55700 55700 57694 57697 55701 55706 56455 55707 55706 55701 56439 55707 55701 57009 57008 55702 57008 55703 55702 57718 56452 55703 55703 57008 57718 56453 56440 55704 55704 55715 56453 55704 55708 55715 55706 56446 56455 56447 56446 55706 55713 55712 55711 56450 56449 55712 55712 55713 56450 55716 55715 55714 55719 55716 55714 55720 55719 55714 55730 55720 55714 57010 56453 55715 55715 56457 57010 55715 55718 56457 55715 55716 55718 56454 55718 55716 55716 55719 56454 55717 55722 55731 55723 55722 55717 55717 55721 55723 57015 56457 55718 55718 56454 57015 57015 56454 55719 57022 57015 55719 55719 56461 57022 55719 55720 56461 56462 56461 55720 56467 56462 55720 55720 55730 56467 57017 55723 55721 57018 57017 55721 57020 57018 55721 55721 56445 57020 57713 56468 55722 55722 57017 57713 55722 55723 57017 56470 55731 55722 55722 56469 56470 55722 56468 56469 56474 55740 55724 56475 56474 55724 56479 56478 55725 57032 56479 55725 55725 56472 57032 55725 55726 56472 55726 55741 56472 55727 56458 56459 56467 55730 55728 55728 55729 56467 57029 56467 55729 55729 55743 57029 56469 55732 55731 56470 56469 55731 55735 55734 55733 55759 55735 55733 56471 55736 55734 57039 56471 55734 55734 55735 57039 57742 57039 55735 55735 57061 57742 55735 55759 57061 57025 56456 55737 55737 56463 57025 56464 55742 55738 56465 56464 55738 57027 56466 55739 56474 55743 55740 55741 55742 56464 57031 56472 55741 55741 56464 57031 55743 56476 57029 55743 56474 56476 55750 55745 55744 56477 55750 55744 55745 55748 55757 55750 55748 55745 55747 55754 55761 56480 55757 55748 57044 56480 55748 57738 57044 55748 55748 57045 57738 55748 55749 57045 55750 55749 55748 57734 57045 55749 55749 57040 57734 55749 55750 57040 55750 56477 57040 55751 56496 56498 55751 55752 56496 55753 55752 55751 57062 56496 55752 55752 55758 57062 55752 55753 55758 56484 55761 55754 57047 56484 55754 55754 56482 57047 57054 56483 55755 55755 55756 57054 55756 56493 57054 55756 56489 56493 56480 55758 55757 55758 57057 57062 57058 57057 55758 55758 56480 57058 55759 56499 57061 55759 55765 56499 57049 56485 55761 57050 57049 55761 55761 56484 57050 55762 55766 55769 55762 55763 55766 55768 55766 55763 56495 55768 55763 55763 56488 56495 56499 55765 55764 56500 56499 55764 55766 55768 55769 55767 55768 57071 55769 55768 55767 55775 55769 55767 56501 55775 55767 57071 56501 55767 55768 56494 57066 56495 56494 55768 55768 57066 57071 56493 56489 55770 55770 56492 56493 56502 56492 55770 56508 55774 55773 57097 56508 55773 55773 57080 57097 55773 55777 57080 56505 55780 55774 56508 56505 55774 56506 55777 55776 57082 56506 55776 55776 56503 57082 55777 56506 57080 56513 55781 55778 57110 56513 55778 55778 57107 57110 55778 55779 57107 55780 56505 56507 56513 55786 55781 57816 57120 55783 55783 57121 57816 55783 55784 57121 55785 55784 55783 57120 55785 55783 55784 55785 57121 55789 55788 55785 57120 55789 55785 55785 57117 57121 55786 56513 57128 57128 57127 55786 55788 55790 55793 55788 55789 55790 56520 55790 55789 57118 56520 55789 57120 57118 55789 55799 55793 55790 55790 55798 55799 56520 55798 55790 55797 55796 55791 56531 55797 55791 55791 55792 56531 55792 55800 56531 55792 55793 55800 55793 55799 55800 57829 56524 55794 55794 55820 57829 55794 55795 55820 55795 55804 55820 55796 55797 55812 55825 55812 55797 56531 55825 55797 55798 56520 56522 55800 55799 55798 56522 55800 55798 55800 55848 56531 56539 55848 55800 55800 56538 56539 57832 56538 55800 57833 57832 55800 55800 56526 57833 56527 56526 55800 55800 56522 56527 55801 55802 56521 56533 56521 55802 55802 56532 56533 55802 55829 56532 55830 55829 55802 55802 55828 55830 55811 55807 55803 55804 55819 55820 55804 55805 55819 55811 55809 55807 55817 55810 55807 55807 55815 55817 55807 55808 55815 55809 55808 55807 55808 55813 55815 55814 55813 55808 55816 55814 55808 55808 55809 55816 56529 56528 55809 55809 55811 56529 56528 55816 55809 55810 55817 55818 55832 55815 55813 55833 55832 55813 55813 55831 55833 55813 55814 55831 55814 55829 55831 55814 55816 55829 55832 55817 55815 56532 55829 55816 56533 56532 55816 57135 56533 55816 55816 56528 57135 55834 55818 55817 55817 55832 55834 55818 55835 55836 55818 55834 55835 55822 55820 55819 57830 57829 55820 57831 57830 55820 55820 57139 57831 55820 55823 57139 55820 55822 55823 55823 55822 55821 57840 55823 55821 57841 57840 55821 55821 57140 57841 55821 56536 57140 57835 57139 55823 57840 57835 55823 55824 55825 55837 56531 55837 55825 55830 55828 55827 55840 55830 55827 55827 55839 55840 55829 55830 55831 55841 55831 55830 55830 55840 55841 55841 55833 55831 56534 55834 55832 55832 55833 56534 55833 55844 56534 55833 55842 55844 55843 55842 55833 55833 55841 55843 56535 55835 55834 55834 56534 56535 56541 55836 55835 55835 56535 56541 57839 56545 55836 55836 56541 57839 56531 55848 55837 55850 55839 55838 55853 55840 55839 55839 55851 55853 55839 55850 55851 55843 55841 55840 56543 55843 55840 55840 55853 56543 57149 55844 55842 55842 55843 57149 55843 57148 57149 55843 56543 57148 56540 56535 55844 57850 56540 55844 55844 57149 57850 56535 56534 55844 55845 55846 56536 57845 56536 55846 56539 55849 55848 55849 56538 56542 56539 56538 55849 55852 55851 55850 57147 55853 55851 55851 57145 57147 55851 57144 57145 55851 55852 57144 55852 57142 57144 55852 57141 57142 57146 56543 55853 57147 57146 55853 56555 56546 55854 55854 55855 56555 55862 55861 55856 56548 55862 55856 56564 55859 55857 55857 55858 56564 56566 56564 55858 55858 55872 56566 57181 56559 55859 57188 57181 55859 57189 57188 55859 55859 56563 57189 56564 56563 55859 56559 56557 55860 55861 55862 55863 55862 56548 56551 56560 55863 55862 56561 56560 55862 55862 56550 56561 56551 56550 55862 56560 55865 55863 55864 56554 56558 56560 56554 55864 55864 55865 56560 55870 55867 55866 55866 55868 55870 55867 55870 55871 55871 55870 55868 56565 55871 55868 55868 55869 56565 57161 56565 55869 57162 57161 55869 59173 58548 55871 55871 57210 59173 55871 56565 57210 56570 56566 55873 57217 56570 55873 55873 56580 57217 55874 56584 56585 55875 55895 55896 56604 55895 55875 55897 55887 55876 55876 55877 55897 55878 55877 55876 55887 55878 55876 55917 55898 55877 55877 55912 55917 55915 55912 55877 55877 55878 55915 55898 55897 55877 56592 55915 55878 55878 56578 56592 55878 56574 56578 55878 55885 56574 55887 55885 55878 55911 55890 55879 55881 55880 55879 55891 55881 55879 55879 55882 55891 55880 55881 56598 57235 56598 55881 55881 57227 57235 55881 56588 57227 55881 55891 56588 55882 55883 55891 57227 56588 55883 55883 57226 57227 56588 55891 55883 56599 56590 55884 56575 56574 55885 56576 56575 55885 55885 55886 56576 55887 55886 55885 57224 56576 55886 55886 56587 57224 55886 55887 56587 55887 55897 56587 55901 55889 55888 55889 55901 55902 57257 56603 55893 57930 57257 55893 55893 57922 57930 55893 57236 57922 55893 55894 57236 55894 56585 57236 56600 55896 55895 56604 56600 55895 55896 56568 56580 56569 56568 55896 57246 56569 55896 55896 56600 57246 55897 56582 56587 55897 55898 56582 57238 56582 55898 57249 57238 55898 55898 55936 57249 55898 55918 55936 55898 55917 55918 57269 56601 55899 55899 55900 57269 55900 57240 57269 55900 56593 57240 55900 55902 56593 55905 55902 55901 55902 55903 56593 55904 55903 55902 57923 55904 55902 55902 57241 57923 55902 55905 57241 57239 56593 55903 58557 57239 55903 55903 55904 58557 58558 58557 55904 55904 57924 58558 55904 57923 57924 55905 55906 57241 57242 57241 55906 55906 56594 57242 55906 55907 56594 55907 55908 56594 56595 56594 55908 55908 55909 56595 56596 56595 55909 56597 56596 55909 57253 56597 55910 55912 55913 55917 56614 55929 55914 57287 56614 55914 55914 57286 57287 57248 56618 55915 55915 57237 57248 55915 56592 57237 57267 55937 55916 55936 55918 55916 55937 55936 55916 55919 56606 57270 55919 56605 56606 55919 56601 56605 55919 55920 56601 56614 56607 55921 55921 55929 56614 57942 57929 55922 55922 57256 57942 55922 55923 57256 55924 55923 55922 57929 55924 55922 55923 56602 57256 55923 56599 56602 57245 56599 55923 55923 55924 57245 57921 57245 55924 57943 57921 55924 55924 57929 57943 55925 55926 57279 57279 56615 55925 55927 55928 55932 56612 55932 55928 57271 56612 55928 55928 56611 57271 56623 56616 55930 55930 55935 56623 56631 56620 55931 55932 56612 56613 55938 55934 55933 55933 56621 57302 55935 55951 56629 56629 56623 55935 57267 57249 55936 55936 55937 57267 56637 55940 55939 55939 56632 56637 55939 55949 56632 56638 55950 55940 55940 56637 56638 55958 55957 55941 56638 55958 55941 55941 55950 56638 55942 55956 55959 55942 55943 55956 56635 55956 55943 55943 56630 56635 57305 56636 55944 57312 57305 55944 55944 55945 57312 55946 55945 55944 55945 55964 57312 55945 55946 55964 55947 56642 56643 55947 56640 56642 55947 55952 56640 56632 55949 55948 55948 55972 56632 56633 56629 55951 55951 56628 56633 55951 56627 56628 57309 56640 55952 55955 55954 55953 56661 55955 55953 55953 56659 56661 55953 55986 56659 56661 55971 55955 55962 55959 55956 56635 55962 55956 57996 56663 55957 55957 55958 57996 55958 57988 57996 55958 56638 57988 57331 55963 55959 55959 55962 57331 58016 57331 55960 55960 55961 58016 55962 55961 55960 57331 55962 55960 55961 57997 58016 55961 57992 57997 55961 57308 57992 55961 55962 57308 55962 56635 57308 57331 57325 55963 57317 57312 55964 55964 55965 57317 57999 57317 55965 58000 57999 55965 55965 56648 58000 55968 55967 55966 57313 56639 55966 55966 56646 57313 55966 55967 56646 55967 55968 55974 57324 56646 55967 55967 55989 57324 55967 55975 55989 55967 55974 55975 55972 55971 55970 57306 55972 55970 58597 57306 55970 55970 57321 58597 55970 55971 57321 55971 56660 57321 56661 56660 55971 57306 56632 55972 56663 56662 55973 56662 55987 55973 55988 55975 55974 55975 55988 55989 55976 56650 56651 55977 55978 56650 55978 55979 56650 55980 55979 55978 57326 56650 55979 57327 57326 55979 57328 57327 55979 55979 55980 57328 55980 56655 57328 55981 55982 56656 56656 55983 55981 55982 55990 55991 55982 55991 56656 56656 56655 55983 55991 55990 55984 56657 55991 55984 56668 55986 55985 56669 56659 55986 55986 56668 56669 56662 55994 55987 55999 55989 55988 55988 55996 55999 55989 56679 57324 55989 55999 56679 58008 56656 55991 55991 56658 58008 55991 56657 56658 57344 56008 55992 55992 56685 57344 55993 56666 56668 56667 56666 55993 56690 56667 55993 55993 56015 56690 55993 55995 56015 55994 56662 56670 56679 55999 55996 56687 56679 55996 55996 56686 56687 55996 55997 56686 55997 55998 56686 56694 56686 55998 56697 56694 55998 56038 56016 56000 56000 56001 56038 56002 56001 56000 56016 56002 56000 56001 56695 56701 56001 56682 56695 56001 56002 56682 56039 56038 56001 56701 56039 56001 56002 56003 56682 56017 56003 56002 56002 56016 56017 56003 56681 56682 56003 56004 56681 56005 56004 56003 56017 56005 56003 56683 56681 56004 56004 56672 56683 56004 56005 56672 57325 56672 56005 57332 57325 56005 57335 57332 56005 56005 56674 57335 56005 56017 56674 56006 56050 56704 57358 56050 56006 56006 56007 57358 56008 56007 56006 58036 57358 56007 56007 57344 58036 56007 56008 57344 56705 56012 56011 56011 56024 56705 56705 56688 56012 57351 56015 56013 58041 57351 56013 56013 56014 58041 58631 58041 56014 56014 57350 58631 57351 56690 56015 56019 56018 56016 56038 56019 56016 56018 56017 56016 56017 56673 56674 56017 56020 56673 56017 56018 56020 56022 56020 56018 56023 56022 56018 56034 56023 56018 56018 56021 56034 56018 56019 56021 56019 56038 56040 56032 56021 56019 56033 56032 56019 56040 56033 56019 56020 56022 56673 56021 56032 56034 56684 56673 56022 57343 56684 56022 58029 57343 56022 56022 56023 58029 56023 56034 58029 58647 56705 56024 58655 58647 56024 56024 57368 58655 58040 57350 56025 56025 57349 58040 56025 56026 57349 56026 56689 57349 58057 56707 56027 56027 58051 58057 56027 58043 58051 56027 56028 58043 56029 56028 56027 56707 56029 56027 56028 58042 58043 56028 57353 58042 56028 56036 57353 56707 56706 56029 57356 56696 56030 58047 57356 56030 56030 57354 58047 56030 56031 57354 56031 56691 57354 56698 56034 56032 56032 56033 56698 56702 56698 56033 56033 56040 56702 58629 58029 56034 56034 56703 58629 56034 56698 56703 56036 57352 57353 56036 56696 57352 56038 56039 56040 56701 56040 56039 56713 56702 56040 56040 56701 56713 56708 56046 56041 56041 56050 56708 56045 56043 56042 56731 56045 56042 56042 56082 56731 56710 56075 56042 56042 56044 56710 56052 56047 56043 56053 56052 56043 56711 56053 56043 56043 56045 56711 56731 56711 56045 56708 56051 56046 56697 56049 56048 56048 56057 56697 56048 56055 56057 56048 56054 56055 56716 56708 56050 58056 56716 56050 56050 57358 58056 56051 56708 56714 56052 56053 56076 56711 56076 56053 56056 56055 56054 56064 56056 56054 56712 56057 56055 57374 56712 56055 57375 57374 56055 56055 56056 57375 58071 57375 56056 58682 58071 56056 56056 57392 58682 56056 56725 57392 56056 56064 56725 57365 56697 56057 56057 56712 57365 56060 56061 56720 56062 56061 56060 56721 56062 56060 58072 56721 56060 56060 56728 58072 56729 56728 56060 56060 56720 56729 56061 56062 56709 56722 56709 56062 56062 56721 56722 56078 56077 56066 56734 56078 56066 56735 56734 56066 56066 56067 56735 56068 56067 56066 56067 56094 56735 56738 56723 56070 56070 56081 56738 56070 56072 56081 56073 56072 56070 56070 56071 56073 56072 56073 56085 56085 56081 56072 56076 56711 56731 56076 56082 56083 56731 56082 56076 58682 56732 56077 56077 58083 58682 56077 56078 58083 58697 58083 56078 56078 56747 58697 58091 56747 56078 56078 56734 58091 56743 56742 56080 57406 56743 56080 56080 57401 57406 56080 56737 57401 57397 56738 56081 56081 56085 57397 58097 56085 56084 58100 58097 56084 56084 57407 58100 56084 56744 57407 57403 57397 56085 58088 57403 56085 58097 58088 56085 59374 58713 56086 60067 59374 56086 56086 56087 60067 56088 56087 56086 56101 56088 56086 58713 56101 56086 60699 60067 56087 56087 60688 60699 60689 60688 56087 56087 60079 60689 56087 56088 60079 56088 56102 60079 56088 56101 56102 56089 56090 56091 56108 56091 56090 56094 56734 56735 58091 56734 56094 56094 56095 58091 56095 56746 58091 56096 56099 56744 56750 56116 56097 56097 56745 56750 56097 56741 56745 56117 56099 56098 56124 56117 56098 57407 56744 56099 57415 57407 56099 56099 56117 57415 58124 57423 56100 56100 56101 58124 56102 56101 56100 58126 56102 56100 56100 57423 58126 56101 58120 58124 58713 58120 56101 56102 58126 58723 60080 60079 56102 56102 58730 60080 56102 58723 58730 56103 56118 56760 56103 56104 56118 56119 56118 56104 57419 57416 56105 57416 56106 56105 56756 56119 56106 58116 56756 56106 56106 57416 58116 56109 56110 56121 56111 56110 56109 56120 56111 56109 57408 56121 56110 56110 56757 57408 56110 56111 56757 57409 56757 56111 56111 56759 57409 56111 56120 56759 56753 56123 56112 56754 56753 56112 57410 56115 56113 58109 57410 56113 56113 56114 58109 58110 58109 56114 56114 56755 58110 56114 56750 56755 57411 56754 56115 56115 57410 57411 57420 57415 56117 56117 56124 57420 57421 56760 56118 56118 56756 57421 56118 56119 56756 56120 56758 56759 56749 56746 56121 57408 56749 56121 56122 56123 56762 56123 56753 56762 57423 57420 56124 56124 56133 57423 56768 56140 56125 56125 56126 56768 57424 56768 56126 56126 56760 57424 57432 57430 56127 58135 57432 56127 56127 56785 58135 56127 56774 56785 56127 56128 56774 56129 56128 56127 57430 56129 56127 56128 56162 56774 56128 56138 56162 56128 56129 56138 56766 56132 56130 56130 56765 56766 56130 56131 56765 57436 57435 56131 56131 56764 57436 56131 56763 56764 57435 56765 56131 56767 56133 56132 56132 56766 56767 57428 57423 56133 56133 56767 57428 56134 56139 57442 56137 56136 56135 56769 56137 56135 57443 56772 56137 56137 56769 57443 56138 56146 56162 56139 57429 57442 56139 56140 57429 56140 57424 57429 56140 56768 57424 56144 56143 56141 56141 56142 56144 57445 56144 56142 56142 56771 57445 57452 56782 56143 56143 56144 57452 56782 56145 56143 56144 57445 57452 57456 56148 56145 56145 56782 57456 56146 56149 56162 56155 56149 56146 56777 56150 56147 56780 56777 56147 56147 56776 56780 56147 56775 56776 57456 56167 56148 56149 56156 56162 56157 56156 56149 56781 56158 56150 56150 56777 56781 56151 56797 57471 56151 56164 56797 56151 56159 56164 57473 56799 56152 56152 56800 57473 56152 56153 56800 56153 56160 56800 56161 56160 56153 56153 56154 56161 56156 56157 56784 56774 56162 56156 56784 56774 56156 56157 56170 56175 56157 56175 56784 57473 56800 56160 57487 57473 56160 56160 56161 57487 56161 56801 57487 56161 56179 56801 56163 56794 56804 57470 56794 56163 56164 57479 57480 56164 56165 57479 58152 56797 56164 56164 57480 58152 57483 56805 56166 56166 56798 57483 57456 56782 56167 56783 56168 56167 56167 56782 56783 56168 56783 57475 56180 56171 56169 56808 56180 56169 56169 56189 56808 56169 56188 56189 56170 56171 56175 56176 56175 56171 56177 56176 56171 56180 56177 56171 56172 56176 56177 57460 56176 56172 56172 57459 57460 56172 56787 57459 56172 56173 56787 56174 56173 56172 56177 56174 56172 56789 56787 56173 56173 56788 56789 56802 56788 56173 56173 56174 56802 56806 56802 56174 56808 56806 56174 56174 56177 56808 57466 56784 56175 57467 57466 56175 56175 56176 57467 56176 57460 57467 56177 56180 56808 56179 56812 57493 56179 56185 56812 56810 56801 56179 57493 56810 56179 56181 56788 56806 56803 56788 56181 57476 56803 56181 57497 57476 56181 56181 56182 57497 56183 56182 56181 56806 56183 56181 58777 57497 56182 59438 58777 56182 56182 58786 59438 56182 58167 58786 56182 56183 58167 56183 58166 58167 56183 57496 58166 56183 56814 57496 56183 56806 56814 56185 56811 56812 57494 56811 56186 56186 57488 57494 56186 56187 57488 56187 57475 57488 57502 56189 56188 56188 57501 57502 56188 56813 57501 56814 56808 56189 57496 56814 56189 57502 57496 56189 56192 56191 56190 56809 56192 56190 56191 56192 56815 56192 56194 56815 56192 56193 56194 56809 56193 56192 58171 56194 56193 56193 58170 58171 56193 57504 58170 56193 56809 57504 56818 56815 56194 57508 56818 56194 58171 57508 56194 56195 56196 56198 56197 56196 56195 56819 56197 56195 57505 56816 56196 57511 57505 56196 56196 56197 57511 58173 57511 56197 56197 56821 58173 56197 56819 56821 56199 56817 57505 58175 57506 56199 58180 58175 56199 56199 57505 58180 56229 56209 56200 57514 56229 56200 56200 57512 57514 56838 56827 56202 56839 56838 56202 57516 56205 56203 56203 56208 57516 56203 56207 56208 56204 56205 56828 57516 56828 56205 57507 56813 56206 56206 56824 57507 56206 56210 56824 56211 56210 56206 57521 56208 56207 56207 56851 57521 56860 56851 56207 56207 56831 56860 57521 57516 56208 56210 56823 56824 56210 56211 56823 56829 56823 56211 56212 56213 56829 56214 56213 56212 56837 56214 56212 56850 56837 56212 56212 56826 56850 57526 56829 56213 56213 56238 57526 56213 56214 56238 56242 56238 56214 56837 56242 56214 56840 56216 56215 56215 56830 56840 56215 56828 56830 56840 56219 56216 56224 56218 56217 56857 56224 56217 56858 56857 56217 56845 56228 56218 56847 56845 56218 56218 56224 56847 57524 56231 56219 57525 57524 56219 56219 57520 57525 56219 56840 57520 56841 56221 56220 56220 56222 56841 57522 56226 56221 56221 56841 57522 56843 56841 56222 56844 56843 56222 56222 56232 56844 56222 56223 56232 57545 56847 56224 58206 57545 56224 56224 57535 58206 58201 57535 56224 56224 56857 58201 56225 57522 58195 56225 56226 57522 56227 56226 56225 56861 56227 56225 57529 56861 56225 58195 57529 56225 56860 56831 56226 56226 56227 56860 56861 56860 56227 56862 56233 56228 56228 56845 56862 56229 56832 56848 56833 56832 56229 57514 56833 56229 56230 56237 56240 56231 56244 56245 57524 56244 56231 56855 56844 56232 56856 56855 56232 56233 56863 56867 56233 56862 56863 56234 56859 56864 56234 56236 56859 56234 56235 56236 57519 56859 56236 56236 56848 57519 56237 56239 56240 56865 56239 56237 56238 56865 58211 56238 56239 56865 56240 56239 56238 56242 56240 56238 58237 57526 56238 56238 58211 58237 56241 56837 56850 56241 56242 56837 56850 56849 56241 56251 56250 56243 56243 56244 56251 56245 56244 56243 56873 56251 56244 57548 56873 56244 56244 57524 57548 56246 56258 56259 56265 56258 56246 56267 56265 56246 56247 56866 57540 57541 56866 56248 58212 57541 56248 58228 58212 56248 56248 58219 58228 58221 58219 56248 56248 56870 58221 56248 56249 56870 56871 56870 56249 56254 56253 56250 56878 56254 56250 56250 56872 56878 56250 56251 56872 56873 56872 56251 56262 56260 56252 57549 56262 56252 56252 56867 57549 56253 56254 56255 56874 56255 56254 56879 56874 56254 57551 56879 56254 58246 57551 56254 56254 57555 58246 56254 56881 57555 56254 56878 56881 56874 56256 56255 56874 56263 56256 56258 56265 56880 58230 56259 56258 56258 57556 58230 56258 56278 57556 58224 57532 56259 58230 58224 56259 56260 56261 57557 56262 56261 56260 57558 57557 56261 57560 57558 56261 56261 56262 57560 58232 57560 56262 56262 57549 58232 56879 56264 56263 56263 56874 56879 56264 57551 58246 56264 56879 57551 56265 56266 56880 56267 56266 56265 56266 56268 56880 56266 56267 56268 56290 56287 56270 56270 56271 56290 56888 56290 56271 56274 56273 56272 56882 56274 56272 56273 56274 56276 56882 56276 56274 56279 56278 56275 56281 56279 56275 56275 56280 56281 56278 56279 57556 57569 57556 56279 56279 56281 57569 56284 56283 56280 56282 56281 56280 56283 56282 56280 56281 56282 57569 58255 57569 56282 56282 57571 58255 56282 56283 57571 58250 57571 56283 56283 56887 58250 56283 56284 56887 56893 56887 56284 56285 57564 57565 57566 57564 56285 56286 56290 56297 56286 56287 56290 56288 57561 57562 56288 56889 57561 56288 56885 56889 57567 56895 56288 56288 57562 57567 56300 56297 56290 56897 56300 56290 56290 56888 56897 56291 56292 56901 56293 56292 56291 58265 56293 56291 56291 56901 58265 56292 56896 56901 56292 56293 56888 56900 56888 56293 56293 56899 56900 57580 56899 56293 58261 57580 56293 58262 58261 56293 58263 58262 56293 58264 58263 56293 58265 58264 56293 56294 56295 56301 57581 56301 56295 57582 57581 56295 56295 56309 57582 56295 56308 56309 56907 56320 56296 56300 56298 56297 56300 56299 56298 56906 56311 56299 56299 56898 56906 56299 56300 56898 56300 56897 56898 57581 57575 56301 56302 56303 56310 56305 56303 56302 56905 56310 56303 56303 56904 56905 56303 56304 56904 56305 56304 56303 56304 56311 56904 56304 56305 56311 56306 56312 56323 56306 56323 56910 56307 56324 56916 56309 56308 56307 56318 56309 56307 56916 56318 56307 57584 57582 56309 56309 56318 57584 57573 56894 56310 56310 56905 57573 56909 56904 56311 56311 56906 56909 57592 56323 56312 56912 56317 56313 56314 57593 58279 56314 56315 57593 56316 56315 56314 58279 56316 56314 56315 56911 57593 56913 56911 56315 58279 56327 56316 56317 56912 56913 56318 56916 57584 56914 56326 56319 57590 56914 56319 56319 56903 57590 56319 56320 56903 57577 56903 56320 56320 56907 57577 57609 56918 56321 56321 56921 57609 56321 56322 56921 57589 56910 56323 57592 57589 56323 56324 56325 56916 56325 56328 56916 56327 58279 58280 58280 57610 56327 57595 56916 56328 56328 56919 57595 56328 56330 56919 56923 56919 56330 57611 56921 56331 56331 56334 57611 57617 57613 56332 56332 56333 57617 56334 57605 57611 56334 56929 57605 56337 56342 56938 56940 56342 56338 56338 56935 56940 57620 56935 56338 58289 57620 56338 56943 56344 56339 56339 56942 56943 56339 56941 56942 56339 56936 56941 56944 56343 56341 56939 56938 56342 56940 56939 56342 56343 56344 56345 56944 56344 56343 56943 56345 56344 56350 56349 56345 56942 56350 56345 56943 56942 56345 56348 56347 56346 57634 56348 56346 56346 56375 57634 58292 56355 56347 58295 58292 56347 56347 56348 58295 56348 56356 58295 56348 57634 57636 57621 56356 56349 58293 57621 56349 56349 56350 58293 56350 56941 58293 56942 56941 56350 56354 56353 56351 57623 56951 56353 56353 56354 57623 58296 58289 56355 56355 58291 58296 58292 58291 56355 58297 58295 56356 56356 57621 58297 56362 56945 56946 56952 56949 56364 56365 56374 56375 56377 56374 56365 56365 56366 56377 56366 56372 56377 56367 56368 56953 56367 56953 56960 56369 56961 56968 57650 56371 56369 56369 56968 57650 56370 56960 57645 57650 56392 56371 56372 56373 56377 56373 56374 56377 56384 56374 56373 56385 56384 56373 56376 56375 56374 56384 56376 56374 57636 57634 56375 56375 56376 57636 56376 57635 57636 57638 57635 56376 56376 56388 57638 56376 56384 56388 56378 56379 56955 56380 56379 56378 56386 56380 56378 56388 56386 56378 57638 56388 56378 57640 57638 56378 56378 56955 57640 56379 56954 56955 56379 56952 56954 56379 56380 56952 56956 56952 56380 56380 56391 56956 56380 56390 56391 56380 56386 56390 57651 56967 56381 56381 56964 57651 56968 56383 56382 56968 56962 56383 56389 56388 56384 56394 56389 56384 56384 56385 56394 56973 56394 56385 56385 56399 56973 56385 56398 56399 56386 56387 56390 56388 56387 56386 56969 56390 56387 56387 56389 56969 56387 56388 56389 56389 56393 56969 56394 56393 56389 56956 56391 56390 56965 56956 56390 56969 56965 56390 56972 56971 56392 57650 56972 56392 57653 56969 56393 57658 57653 56393 57659 57658 56393 57660 57659 56393 56393 56974 57660 56393 56394 56974 56394 56973 56974 56977 56396 56395 56977 56403 56396 56397 57652 58310 56409 56399 56398 56398 56408 56409 56981 56973 56399 56983 56981 56399 56399 56409 56983 56400 56411 56976 56401 56402 56420 56402 56412 56420 56980 56406 56403 56403 56979 56980 56403 56977 56979 56404 56405 56407 56406 56405 56404 56405 57669 57670 56405 56406 57669 57677 56407 56405 58333 57677 56405 56405 57670 58333 56406 56980 57669 57677 56987 56407 56987 56417 56407 57673 56409 56408 56408 56986 57673 57673 56983 56409 57674 56411 56410 57675 57674 56410 57662 56976 56411 58322 57662 56411 56411 57674 58322 56982 56413 56412 56412 56413 56420 56415 56414 56413 56982 56415 56413 56414 56415 57675 58327 57675 56415 56415 57668 58327 56415 57657 57668 56415 56982 57657 57678 56989 56416 56416 56988 57678 56417 56987 56988 56421 56437 56986 56421 56422 56437 56422 56436 56437 57689 56990 56423 56423 57688 57689 56423 56425 57688 56990 56424 56423 56425 56426 56439 57681 56993 56428 57682 57681 56428 56428 57680 57682 56428 56991 57680 56992 56432 56429 56430 57687 58966 56430 57685 57687 56430 56432 57685 56432 56992 57685 56433 57002 57691 57676 56437 56436 57693 57676 56436 56436 56997 57693 57673 56986 56437 58331 57673 56437 56437 57676 58331 56440 56453 57005 57706 56444 56441 56441 56443 57706 56998 56443 56442 57000 56998 56442 58356 57706 56443 56443 57690 58356 56443 57004 57690 56443 56998 57004 57016 56445 56444 57706 57016 56444 56445 57016 57020 57694 56455 56446 57697 57694 56446 56446 57011 57697 57012 57011 56446 56446 56447 57012 58359 57698 56448 56448 57007 58359 56448 57006 57007 57013 57006 56448 56448 56449 57013 57698 57012 56448 57021 57013 56449 56449 56450 57021 57715 57021 56450 58369 56460 56451 56451 56452 58369 58370 58369 56452 56452 57718 58370 57010 57005 56453 57719 57715 56456 56456 57026 57719 56456 57025 57026 57702 57010 56457 57705 57702 56457 56457 57015 57705 56459 56460 57027 58369 57027 56460 57023 57022 56461 57721 57023 56461 56461 56462 57721 56462 57028 57721 56462 56467 57028 57030 57025 56463 56463 56471 57030 57034 57031 56464 58377 57034 56464 56464 56473 58377 56464 56465 56473 57730 56473 56466 56466 57729 57730 56466 57027 57729 57029 57028 56467 57726 56469 56468 57727 57726 56468 56468 57713 57727 56469 57726 57731 57731 57042 56469 57039 57030 56471 56472 57031 57032 59007 58377 56473 56473 58380 59007 56473 57730 58380 56474 56475 56476 56483 56476 56475 57720 57029 56476 56476 57035 57720 58372 57035 56476 59015 58372 56476 56476 57737 59015 56476 57736 57737 56476 56483 57736 57041 57040 56477 57042 57041 56477 56478 56479 56481 56478 56481 56482 56479 57032 57046 57046 56481 56479 57739 57058 56480 56480 57044 57739 57047 56482 56481 56481 57046 57047 57751 57736 56483 56483 57054 57751 56484 57048 57050 56484 57047 57048 57051 56486 56485 56485 57049 57051 57051 56487 56486 57052 56488 56487 56487 57051 57052 57052 56495 56488 57054 56493 56490 57761 57054 56490 57765 57761 56490 57767 57765 56490 56490 56491 57767 56492 56491 56490 56493 56492 56490 57769 57767 56491 56491 56492 57769 56492 56502 57769 56494 56495 57052 56494 57052 57066 56496 56497 56498 57063 56497 56496 56496 57062 57063 57773 57762 56497 56497 57063 57773 57762 56498 56497 57762 56500 56498 57754 57061 56499 56499 57060 57754 56499 56500 57060 56500 57059 57060 57762 57059 56500 57082 56503 56501 57788 57082 56501 56501 57072 57788 56501 57071 57072 56502 57064 57769 56504 57076 57084 57784 56507 56505 56505 57096 57784 56505 57095 57096 56505 56509 57095 56505 56508 56509 57081 57080 56506 57796 57081 56506 56506 57082 57796 56507 57116 57117 57784 57116 56507 57079 56509 56508 56508 57078 57079 57097 57078 56508 58416 57095 56509 56509 57785 58416 56509 57079 57785 56511 56512 57076 56512 57074 57076 56512 57073 57074 57098 57073 56512 57099 57098 56512 56512 56517 57099 56513 57110 57122 56513 57122 57128 56514 56515 56517 57099 56517 56515 57100 57099 56515 57112 57100 56515 56515 56516 57112 56516 56518 56519 57819 57112 56516 57820 57819 56516 56516 56519 57820 56525 56519 56518 56519 56525 57818 58435 57820 56519 56519 57818 58435 57129 56527 56520 56520 57125 57129 56520 57119 57125 56520 57118 57119 56527 56522 56520 56521 56533 57134 56530 56529 56523 56524 57829 58468 57818 56525 56524 58468 57818 56524 56526 57825 58473 56526 57131 57825 56526 57130 57131 56526 56527 57130 57834 57833 56526 58472 57834 56526 58473 58472 56526 56527 57129 57130 56528 56530 57137 56528 56529 56530 57137 57135 56528 56530 57132 57137 57135 57134 56533 56535 56540 56541 57845 57842 56536 58484 57140 56536 56536 57842 58484 57832 56542 56538 57143 56541 56540 57851 57143 56540 56540 57850 57851 56541 57838 57839 56541 57143 57838 56542 57832 57834 57849 57141 56542 57854 57849 56542 56542 57834 57854 56543 57146 57148 57862 56562 56544 56544 56545 57862 56545 57856 57862 56545 57839 57856 56546 56555 57166 56549 56548 56547 57150 56549 56547 56547 56556 57150 56557 56556 56547 56548 56549 56551 56549 57150 57151 57151 56551 56549 57870 56561 56550 56550 57868 57870 56550 56551 57868 56551 57151 57868 57871 56554 56552 58511 57871 56552 56552 58509 58511 58510 58509 56552 58521 58510 56552 56552 56553 58521 56554 56553 56552 56553 57877 58521 56553 56554 57877 57871 56558 56554 56554 56560 57877 56555 56558 57166 57151 57150 56556 57164 57151 56556 56556 57163 57164 56556 56557 57163 57181 57163 56557 56557 56559 57181 57871 57166 56558 56560 56561 57877 58508 57877 56561 56561 57870 58508 57876 57162 56562 56562 57862 57876 57213 57189 56563 57216 57213 56563 56563 56566 57216 56563 56564 56566 57212 57210 56565 59828 57212 56565 60484 59828 56565 56565 59155 60484 56565 58520 59155 56565 57875 58520 56565 57161 57875 56566 56570 57216 57226 56577 56567 58548 57226 56567 57231 56580 56568 57264 57231 56568 56568 56569 57264 56569 57246 57264 56570 56572 57216 56581 56572 56570 57217 56581 56570 56581 56579 56571 56571 56572 56581 56573 56572 56571 56579 56573 56571 57901 57216 56572 57902 57901 56572 56572 57218 57902 56572 56573 57218 56573 56574 57218 56578 56574 56573 56579 56578 56573 57219 57218 56574 56574 56575 57219 57903 57219 56575 57910 57903 56575 56575 56576 57910 56576 57223 57910 57224 57223 56576 56578 56579 56592 57233 56592 56579 56579 57232 57233 56579 56580 57232 56581 56580 56579 56580 56581 57217 56580 57231 57232 57234 57228 56582 57238 57234 56582 57228 56587 56582 57229 56584 56583 56583 56589 57229 57230 56586 56584 56584 57229 57230 56586 56585 56584 56585 56586 57236 58551 57931 56586 56586 57230 58551 57922 57236 56586 57931 57922 56586 57911 57224 56587 57914 57911 56587 56587 57228 57914 57916 57229 56589 56589 56591 57916 57245 56591 56590 56590 56599 57245 57921 57916 56591 56591 57245 57921 56592 57233 57237 56593 57239 57240 56594 56595 57242 57250 57242 56595 56595 56596 57250 58560 57250 56596 56596 57253 58560 56596 56597 57253 56598 57243 57244 56598 57235 57243 57264 57246 56600 56600 57258 57264 56600 56604 57258 57261 56605 56601 57269 57261 56601 56602 56608 57256 56604 56609 57258 56605 57268 57283 56605 57261 57268 57283 56606 56605 57965 57270 56606 56606 57283 57965 57276 56608 56607 56607 57275 57276 56607 56614 57275 57276 57256 56608 56609 56610 57258 57265 57258 56610 56610 56617 57265 56610 56616 56617 57965 57271 56611 56611 57270 57965 57956 56613 56612 56612 57271 57956 57958 57272 56613 56613 57956 57958 57278 57275 56614 57297 57278 56614 56614 57287 57297 56615 57289 57290 56615 57280 57289 56615 57279 57280 56624 56617 56616 56625 56624 56616 56616 56623 56625 57945 57265 56617 56617 56624 57945 57939 56619 56618 56618 57933 57939 56618 57248 57933 56619 57939 57948 57304 56626 56619 57948 57304 56619 57295 57282 56620 57301 57295 56620 56620 56631 57301 57977 57303 56621 56621 56622 57977 57303 57302 56621 56622 57288 57977 57281 56625 56623 56623 56629 57281 56624 57939 57945 57948 57939 56624 56624 56625 57948 57960 57948 56625 57961 57960 56625 56625 57281 57961 57304 56630 56626 56639 56628 56627 57984 57983 56628 56628 57307 57984 56628 56639 57307 56634 56633 56628 57983 56634 56628 56629 56633 56634 57979 57281 56629 56629 56634 57979 57304 56635 56630 56631 56636 57301 57990 56637 56632 56632 57306 57990 57985 57979 56634 56634 57983 57985 56635 57304 57308 57305 57301 56636 57989 56638 56637 57990 57989 56637 57989 57988 56638 57313 57307 56639 57994 56642 56640 56640 57309 57994 57319 57318 56641 58001 57319 56641 58002 58001 56641 56641 56642 58002 56643 56642 56641 56642 57994 58002 56644 56647 56648 56658 56657 56645 57318 56658 56645 56646 56680 57313 57324 56680 56646 56649 56648 56647 57333 56649 56647 58004 58000 56648 58005 58004 56648 56648 57337 58005 56648 57334 57337 56648 56649 57334 57336 57334 56649 56649 56675 57336 57333 56675 56649 56664 56651 56650 57326 56664 56650 56651 56664 56665 56652 59254 59255 59256 59254 56652 56652 58608 59256 56652 58020 58608 56652 56653 58020 56654 56653 56652 59255 56654 56652 58607 58020 56653 56653 57330 58607 58606 57330 56653 56653 58025 58606 56653 56654 58025 59265 58025 56654 56654 59255 59265 58007 57328 56655 56655 56656 58007 58008 58007 56656 58608 58008 56658 58609 58608 56658 56658 58009 58609 56658 57318 58009 58010 56661 56659 56659 56669 58010 56660 57320 57321 58010 57320 56660 56660 56661 58010 56662 56663 57322 58011 56670 56662 56662 57322 58011 57323 57322 56663 57996 57323 56663 57339 56665 56664 56664 57326 57339 57339 56685 56665 58021 56668 56666 58613 58021 56666 56666 58030 58613 58031 58030 56666 56666 56667 58031 56667 56690 58031 58021 56669 56668 58601 58010 56669 56669 58021 58601 58026 56671 56670 56670 58011 58026 58026 57342 56671 56672 57325 57331 58016 56683 56672 56672 57331 58016 56675 56674 56673 56684 56675 56673 56674 56675 57335 56675 57332 57335 57333 57332 56675 56675 56684 57336 56676 56687 57345 56676 56679 56687 56676 56677 56679 56678 56677 56676 58028 56678 56676 56676 57345 58028 56680 56679 56677 57316 56680 56677 58014 57316 56677 56677 58003 58014 56677 56678 58003 58615 58003 56678 58618 58615 56678 56678 58028 58618 56679 56680 57324 57316 57313 56680 56681 56683 58015 56695 56682 56681 57357 56695 56681 58015 57357 56681 58016 58015 56683 57343 57336 56684 58035 57344 56685 56685 57339 58035 57345 56687 56686 56686 56694 57345 58038 56689 56688 58039 58038 56688 56688 56705 58039 58038 57349 56689 56690 57351 58031 56691 56692 56693 57355 57354 56691 56691 56693 57355 56693 57342 57355 58049 57345 56694 56694 56697 58049 57357 56701 56695 57356 57352 56696 56697 57364 58049 57365 57364 56697 57366 56703 56698 56698 56702 57366 58657 58062 56699 56699 57359 58657 56699 56700 57359 56701 56700 56699 58062 56701 56699 57361 57359 56700 58032 57361 56700 56700 57357 58032 56700 56701 57357 58062 56713 56701 56702 56713 57366 56703 57363 58629 56703 57362 57363 57366 57362 56703 58630 58039 56705 58647 58630 56705 56724 56715 56706 56706 56707 56724 57391 56724 56707 58052 57391 56707 58057 58052 56707 56716 56714 56708 58059 57373 56709 56709 56722 58059 58643 57365 56712 59298 58643 56712 56712 57374 59298 57369 57366 56713 58062 57369 56713 56714 56716 56719 57387 56719 56716 56716 56717 57387 56718 56717 56716 58056 56718 56716 58064 57387 56717 58661 58064 56717 56717 58054 58661 56717 56718 58054 56718 58056 58646 58055 58054 56718 59292 58055 56718 56718 58646 59292 57387 56726 56719 57378 56722 56721 58662 57378 56721 56721 58072 58662 58658 58059 56722 56722 57379 58658 56722 57378 57379 57389 57380 56723 56723 56738 57389 57391 56730 56724 56725 56740 57392 57387 56736 56726 57395 56728 56727 56727 57393 57395 56728 57396 58072 56728 57395 57396 56730 57390 57398 57391 57390 56730 58682 56733 56732 57392 56740 56733 58682 57392 56733 57399 57393 56736 56736 57387 57399 56737 58073 58086 56737 57388 58073 57402 57401 56737 58087 57402 56737 56737 58086 58087 56738 57382 57389 56738 57381 57382 58076 57381 56738 56738 57397 58076 56741 57406 57414 56741 56743 57406 56741 56742 56743 57413 56745 56741 58103 57413 56741 56741 57414 58103 57413 56750 56745 56746 56747 58091 56749 56747 56746 56747 56748 58697 56749 56748 56747 56748 58107 58697 56748 56749 58107 56749 57408 58107 57413 56755 56750 57405 57404 56751 57404 56752 56751 58115 57419 56752 56752 57417 58115 57418 57417 56752 58106 57418 56752 56752 57404 58106 57411 56762 56753 56753 56754 57411 58716 58110 56755 56755 58111 58716 56755 57413 58111 58121 57421 56756 56756 58116 58121 58101 57408 56757 58102 58101 56757 56757 57409 58102 56761 56759 56758 57425 56761 56758 57430 57425 56758 58102 57409 56759 58118 58102 56759 58123 58118 56759 56759 57422 58123 56759 56761 57422 56760 57421 57424 57425 57422 56761 56762 57412 58125 56762 57411 57412 56773 56764 56763 57439 57436 56764 56764 56773 57439 57440 56766 56765 56765 57435 57440 57440 56767 56766 57440 57428 56767 56769 56770 57443 57444 57443 56770 58137 57444 56770 56770 57451 58137 58134 57445 56771 56771 56772 58134 56772 57443 58134 56786 56785 56774 56774 56784 56786 57453 56776 56775 57454 57453 56775 56781 56780 56776 57464 56781 56776 56776 56779 57464 56776 56778 56779 57453 56778 56776 56777 56780 56781 57465 56779 56778 58755 57465 56778 56778 58754 58755 56778 57453 58754 57478 57464 56779 58147 57478 56779 56779 57465 58147 56791 56790 56781 57464 56791 56781 57457 56783 56782 56782 57452 57457 56783 58138 58149 56783 57457 58138 58154 57475 56783 56783 58148 58154 58149 58148 56783 57466 56786 56784 58139 58135 56785 56785 56786 58139 56786 57466 58139 57463 57459 56787 56787 56789 57463 56788 56802 56806 56803 56789 56788 56789 57462 57463 57476 57462 56789 56789 56803 57476 57469 56793 56790 56790 56791 57469 56791 57464 57478 58159 57469 56791 56791 58158 58159 56791 57478 58158 58150 57470 56792 56792 56793 58150 58151 58150 56793 58159 58151 56793 56793 57469 58159 56794 56795 56804 56796 56795 56794 57470 56796 56794 57489 56804 56795 58165 57489 56795 56795 58162 58165 56795 56796 58162 56796 57470 58150 56796 58161 58162 56796 58150 58161 58740 57471 56797 58761 58740 56797 56797 58152 58761 57484 57483 56798 57485 57484 56798 57486 57485 56798 56798 57472 57486 58153 57472 56799 56799 57474 58153 56799 57473 57474 57500 57487 56801 56801 57495 57500 56801 56810 57495 57489 56807 56804 57483 57481 56805 56806 56808 56814 56810 57488 57495 57494 57488 56810 56810 57493 57494 57493 56812 56811 57494 57493 56811 57503 57501 56813 57507 57503 56813 57505 56817 56816 57509 56820 56818 56818 57508 57509 56822 56821 56819 56819 56820 56822 58177 56822 56820 56820 57509 58177 58178 58173 56821 56821 56822 58178 56822 58177 58179 58179 58178 56822 56825 56824 56823 56834 56825 56823 56836 56834 56823 56823 56829 56836 57515 57507 56824 58796 57515 56824 56824 58795 58796 56824 56825 58795 59479 58795 56825 56825 56835 59479 56825 56834 56835 56826 56827 56850 56827 56838 56850 57513 56830 56828 58181 57513 56828 58186 58181 56828 56828 57516 58186 57526 56836 56829 58182 56840 56830 56830 57513 58182 58191 57519 56832 56832 58190 58191 56832 56833 58190 57519 56848 56832 56833 58187 58190 56833 57514 58187 56836 56835 56834 56835 56836 59463 56835 59478 59479 56835 59463 59478 56836 57526 58194 56836 58194 59463 56838 56849 56850 58182 57520 56840 58195 57522 56841 56841 56842 58195 56843 56842 56841 58198 58195 56842 56842 58196 58198 56842 56843 58196 56843 57523 58196 56843 56844 57523 56844 56855 57523 56845 56846 57534 56847 56846 56845 57533 56862 56845 57534 57533 56845 56846 56847 57545 57545 57534 56846 56860 56854 56851 58192 57521 56851 58193 58192 56851 56851 56852 58193 56853 56852 56851 56854 56853 56851 56852 57528 58193 56852 56853 57528 56853 57527 57528 56853 56854 57527 57542 57527 56854 56854 56860 57542 58200 58197 56855 58205 58200 56855 56855 57531 58205 57532 57531 56855 56855 56856 57532 58196 57523 56855 58197 58196 56855 56857 56858 58201 56858 57537 58201 56858 56864 57537 57539 56864 56859 56859 57519 57539 57543 57542 56860 56860 56861 57543 56861 57530 57543 56861 57529 57530 57533 56863 56862 57533 56867 56863 57538 57537 56864 58210 57538 56864 56864 57539 58210 57541 57540 56866 56867 57544 57549 56867 57534 57544 56867 57533 57534 57561 56884 56868 57562 57561 56868 56868 56869 57562 58238 57562 56869 56869 57552 58238 56869 56875 57552 58229 58221 56870 56870 57546 58229 56870 56871 57546 56871 56891 57546 56872 56877 56878 56872 56873 56877 57547 56877 56873 58241 57547 56873 56873 58235 58241 56873 57548 58235 56875 56876 58233 58233 57552 56875 56876 57540 58233 56881 56878 56877 57555 56881 56877 56877 57550 57555 56877 57547 57550 58246 58243 56883 57578 56907 56883 58269 57578 56883 58911 58269 56883 56883 58242 58911 58243 58242 56883 56886 56885 56884 57561 56886 56884 56885 56886 56889 57561 56889 56886 56887 57563 58250 56887 56893 57563 56900 56897 56888 56892 56891 56890 57576 56892 56890 56890 57575 57576 56891 56892 58244 58240 57546 56891 58244 58240 56891 59544 58874 56892 56892 58883 59544 56892 57576 58883 58874 58244 56892 57573 57566 56894 56895 57567 57574 56902 56896 56895 57574 56902 56895 56902 56901 56896 56899 56898 56897 56900 56899 56897 57579 56906 56898 56898 56899 57579 57583 57579 56899 56899 57580 57583 56901 56902 58265 58906 58265 56902 56902 57574 58906 58260 57590 56903 56903 58259 58260 56903 57577 58259 56908 56905 56904 56909 56908 56904 57585 57573 56905 57586 57585 56905 58270 57586 56905 56905 57598 58270 56905 56908 57598 56915 56909 56906 57588 56915 56906 56906 57579 57588 57578 57577 56907 56908 56915 57598 56908 56909 56915 57589 56911 56910 56911 57589 57593 56913 56912 56911 57591 56920 56914 56914 57590 57591 56915 57587 57598 57588 57587 56915 57594 57584 56916 57595 57594 56916 56917 56918 57599 57605 57599 56918 58276 57605 56918 56918 57609 58276 57603 57595 56919 57608 57603 56919 56919 56923 57608 56920 57597 57604 56920 57596 57597 56920 57591 57596 57611 57609 56921 57616 56925 56924 58283 57616 56924 58286 58283 56924 56924 56928 58286 56924 56927 56928 56925 56932 56933 57616 56932 56925 57612 56928 56927 58926 58286 56928 58929 58926 56928 56928 58273 58929 58930 58273 56928 56928 58928 58930 56928 57615 58928 56928 57612 57615 57619 57605 56929 56929 56930 57619 56930 56931 57619 56931 56934 57619 56931 56932 56934 56933 56932 56931 58283 56934 56932 56932 57616 58283 58284 57619 56934 58285 58284 56934 56934 58283 58285 56935 56936 56940 56937 56936 56935 57620 56937 56935 58290 56941 56936 56936 58287 58290 56936 56937 58287 58288 58287 56937 58294 58288 56937 58297 58294 56937 56937 58289 58297 56937 57620 58289 56941 58290 58293 57624 56946 56945 58931 56948 56946 56946 57629 58931 56946 57628 57629 56946 57624 57628 58301 57630 56947 58935 58301 56947 56947 58934 58935 56947 56948 58934 56948 58931 58934 56958 56950 56949 56949 56952 56958 57641 57626 56950 58307 57641 56950 56950 56959 58307 56950 56958 56959 57633 56953 56951 56951 57632 57633 56951 57623 57632 56952 56957 56958 56952 56956 56957 57633 56960 56953 56955 57639 57640 56965 56957 56956 56963 56958 56957 56966 56963 56957 56957 56965 56966 56963 56959 56958 56959 58305 58307 56959 57646 58305 57647 57646 56959 56959 56963 57647 56960 57644 57645 56960 57633 57644 56961 56962 56968 57648 57647 56963 56963 56966 57648 57652 57651 56964 58310 57652 56964 58317 56966 56965 56965 57653 58317 56965 56969 57653 57649 57648 56966 58317 57649 56966 56968 56975 57650 56968 56970 56975 56976 56975 56970 56971 56972 57663 56972 57655 57663 56972 57650 57655 57660 56974 56973 56973 56981 57660 56975 56976 57662 57654 57650 56975 57662 57654 56975 57661 56979 56977 57666 56980 56978 57669 57666 56978 58321 57669 56978 56978 56979 58321 56980 56979 56978 56979 57661 58321 56980 57666 57669 57665 57660 56981 56981 57664 57665 56981 56983 57664 56983 56984 57664 56985 56984 56983 57673 56985 56983 58330 57664 56984 56984 56985 58330 58952 58330 56985 56985 58332 58952 56985 58331 58332 56985 57673 58331 56987 57677 58333 58336 56988 56987 56987 58333 58336 58335 57678 56988 58336 58335 56988 58340 57000 56989 56989 57678 58340 57689 57679 56990 57679 57001 56990 56991 57679 57680 56991 57001 57679 56992 57683 57685 56992 57681 57683 56992 56993 57681 56996 56995 56994 57686 56996 56994 56995 56996 57002 57691 57002 56996 58352 57691 56996 59619 58352 56996 56996 58343 59619 58344 58343 56996 56996 57686 58344 58345 57693 56997 56997 57695 58345 56997 57003 57695 56998 56999 57004 57000 56999 56998 57690 57004 56999 58348 57690 56999 56999 58340 58348 56999 57000 58340 57003 57692 57695 57005 57010 57692 57006 57013 57014 57014 57007 57006 57007 57700 58359 57707 57700 57007 57007 57014 57707 57008 57009 57718 58364 57718 57009 57009 58360 58364 58361 58360 57009 57009 57691 58361 58353 57692 57010 57010 57702 58353 57011 58338 58339 57011 57698 58338 57011 57012 57698 58342 57697 57011 57011 58339 58342 57021 57014 57013 57708 57707 57014 57014 57021 57708 57710 57705 57015 57015 57024 57710 57015 57022 57024 57016 57706 58363 57711 57020 57016 58986 57711 57016 57016 58363 58986 57017 57712 57713 57017 57019 57712 57017 57018 57019 57711 57019 57018 57018 57020 57711 57019 57711 58987 57714 57712 57019 58365 57714 57019 58979 58365 57019 58987 58979 57019 57717 57708 57021 57021 57716 57717 57021 57715 57716 57022 57023 57024 57710 57024 57023 57721 57710 57023 58375 57026 57025 57025 58373 58375 58374 58373 57025 57025 57728 58374 57025 57030 57728 59004 57719 57026 59005 59004 57026 57026 58375 59005 58369 57729 57027 57723 57721 57028 57028 57720 57723 57028 57029 57720 57735 57728 57030 57030 57038 57735 57039 57038 57030 57033 57032 57031 57034 57033 57031 57032 57732 57733 57032 57043 57732 57032 57033 57043 57733 57046 57032 57033 57034 58378 58378 57043 57033 57034 58377 58378 57035 57036 57720 57037 57036 57035 58372 57037 57035 57723 57720 57036 59001 57723 57036 57036 57037 59001 59642 59001 57037 57037 59009 59642 59010 59009 57037 59645 59010 57037 57037 59015 59645 57037 58372 59015 58385 57735 57038 57038 57741 58385 57038 57039 57741 57742 57741 57039 57040 57041 57734 58381 57734 57041 57041 58376 58381 57041 57042 58376 57042 57731 58376 58386 57732 57043 57043 58378 58386 57044 57738 57739 58387 57738 57045 57045 57734 58387 57048 57047 57046 57746 57048 57046 57046 57745 57746 57046 57744 57745 57046 57733 57744 57756 57050 57048 59028 57756 57048 57048 57746 59028 57747 57051 57049 57749 57747 57049 57049 57050 57749 58396 57749 57050 57050 57757 58396 57050 57756 57757 57053 57052 57051 57760 57053 57051 59669 57760 57051 57051 57757 59669 57051 57750 57757 57051 57747 57750 57052 57053 57066 57758 57066 57053 57759 57758 57053 57760 57759 57053 57752 57751 57054 57761 57752 57054 57065 57062 57055 57070 57065 57055 57055 57056 57070 57057 57056 57055 57062 57057 57055 57779 57070 57056 57056 57772 57779 57056 57057 57772 57057 57058 57772 57058 57771 57772 57058 57766 57771 57058 57739 57766 58405 57763 57059 57059 57762 58405 57763 57060 57059 58398 57754 57060 57060 57763 58398 57754 57742 57061 57065 57063 57062 57774 57773 57063 57063 57065 57774 57064 57084 57769 57065 57102 57774 57065 57070 57102 57072 57071 57066 57758 57072 57066 57069 57068 57067 57792 57069 57067 58406 57792 57067 57067 57068 58406 57068 57069 57771 57068 57766 58406 57771 57766 57068 57772 57771 57069 57792 57772 57069 57070 57101 57102 57782 57101 57070 57070 57779 57782 57789 57788 57072 57072 57758 57789 57098 57083 57073 57075 57074 57073 57083 57075 57073 57077 57076 57074 57781 57077 57074 57074 57075 57781 57075 57797 57798 57075 57790 57797 57075 57083 57790 57798 57781 57075 57770 57084 57076 57076 57077 57770 57778 57770 57077 57781 57778 57077 57785 57079 57078 57078 57081 57785 57078 57080 57081 57097 57080 57078 59052 57785 57081 59054 59052 57081 57081 57796 59054 57082 57786 57796 57787 57786 57082 57788 57787 57082 57083 57098 57100 57791 57790 57083 57083 57111 57791 57083 57100 57111 57770 57769 57084 57783 57102 57085 57085 57093 57783 57104 57093 57085 57085 57086 57104 57087 57086 57085 57102 57087 57085 57086 57103 57104 57086 57087 57103 57108 57103 57087 57109 57108 57087 57087 57101 57109 57102 57101 57087 58415 57093 57088 59045 58415 57088 57088 59044 59045 59048 59044 57088 59049 59048 57088 57088 57089 59049 57090 57089 57088 57093 57090 57088 59051 59049 57089 57089 58428 59051 57089 57795 58428 57089 57090 57795 57090 57794 57795 57090 57091 57794 57093 57091 57090 57800 57794 57091 57091 57106 57800 57091 57094 57106 57091 57092 57094 57093 57092 57091 57105 57094 57092 57092 57104 57105 57092 57093 57104 57793 57783 57093 58415 57793 57093 57805 57106 57094 57094 57105 57805 58417 57096 57095 57095 58416 58417 57802 57784 57096 58417 57802 57096 57098 57099 57100 57112 57111 57100 58426 57109 57101 57101 58424 58426 57101 57799 58424 57101 57782 57799 57780 57774 57102 57783 57780 57102 57105 57104 57103 57804 57105 57103 57103 57108 57804 57105 57804 57805 57805 57800 57106 57108 57803 57804 57814 57803 57108 57108 57113 57814 57114 57113 57108 57108 57109 57114 58427 57114 57109 57109 58426 58427 58423 57791 57111 58425 58423 57111 57111 57112 58425 57112 57819 58425 57822 57814 57113 58436 57822 57113 57113 57114 58436 59064 58436 57114 57114 59057 59064 57114 58427 59057 57121 57117 57115 57806 57121 57115 58431 57806 57115 58432 58431 57115 57115 57116 58432 57117 57116 57115 57116 57801 58432 57116 57784 57801 57120 57119 57118 57119 57124 57125 57817 57124 57119 57119 57816 57817 57119 57120 57816 58438 57816 57121 57121 57806 58438 57122 57127 57128 57122 57123 57127 57812 57127 57123 58434 57810 57124 57124 58433 58434 57124 57817 58433 57810 57125 57124 57811 57129 57125 57125 57810 57811 57136 57133 57126 57812 57136 57126 57126 57127 57812 57131 57130 57129 57824 57131 57129 57129 57811 57824 58467 57825 57131 57131 57823 58467 57824 57823 57131 57136 57135 57132 57132 57133 57136 57132 57135 57137 57134 57136 57138 57134 57135 57136 57812 57138 57136 57835 57831 57139 58482 57841 57140 58483 58482 57140 58484 58483 57140 57847 57142 57141 57849 57847 57141 57847 57144 57142 57853 57838 57143 57143 57852 57853 57143 57851 57852 57847 57145 57144 58480 57147 57145 58487 58480 57145 57145 57848 58487 57145 57847 57848 58478 57148 57146 58480 58478 57146 57146 57147 58480 57855 57149 57148 58481 57855 57148 57148 58478 58481 57855 57850 57149 57869 57868 57151 57151 57866 57869 57151 57865 57866 57151 57164 57865 57156 57154 57152 57175 57156 57152 57152 57155 57175 57152 57153 57155 57154 57153 57152 57173 57155 57153 57153 57172 57173 58497 57172 57153 57153 57154 58497 57154 57156 57157 58498 58497 57154 58500 58498 57154 57154 57157 58500 57155 57174 57175 57155 57170 57174 57171 57170 57155 57173 57171 57155 57158 57157 57156 57160 57158 57156 57175 57160 57156 57157 57158 57178 57157 57178 58500 57158 57177 57178 57158 57176 57177 57158 57159 57176 57160 57159 57158 57180 57176 57159 57185 57180 57159 57159 57160 57185 57186 57185 57160 57160 57175 57186 57161 57162 57875 57876 57875 57162 57165 57164 57163 57181 57165 57163 57164 57165 57865 57165 57181 57865 57858 57846 57166 57871 57858 57166 57167 57171 57172 57182 57171 57167 57167 57168 57182 57169 57168 57167 57874 57169 57167 57167 57172 57874 57183 57182 57168 57190 57183 57168 57887 57190 57168 57168 57879 57887 57168 57169 57879 57169 57872 57879 57873 57872 57169 57874 57873 57169 57170 57171 57184 57191 57174 57170 57170 57184 57191 57171 57183 57184 57171 57182 57183 57173 57172 57171 58502 57874 57172 58503 58502 57172 57172 58497 58503 57192 57175 57174 57174 57191 57192 57200 57186 57175 57892 57200 57175 57175 57192 57892 57187 57177 57176 57176 57180 57187 58504 57179 57177 57177 57880 58504 57177 57187 57880 57179 57178 57177 57178 57179 58500 57179 58504 58505 59139 58500 57179 59783 59139 57179 57179 58505 59783 57197 57187 57180 57180 57185 57197 57181 57188 57865 57190 57184 57183 57193 57191 57184 57886 57193 57184 57184 57190 57886 57202 57197 57185 57185 57200 57202 57185 57186 57200 57187 57196 57880 57197 57196 57187 57867 57865 57188 58507 57867 57188 57188 57189 58507 59169 58507 57189 59172 59169 57189 57189 57214 59172 57189 57213 57214 57887 57886 57190 57193 57192 57191 58526 57892 57192 57192 57888 58526 57192 57193 57888 57193 57886 57888 57196 57195 57194 57881 57196 57194 58518 57881 57194 57194 57199 58518 57194 57198 57199 57194 57195 57198 57204 57198 57195 57195 57196 57204 57206 57204 57196 57196 57197 57206 57881 57880 57196 57221 57206 57197 57905 57221 57197 57197 57202 57905 57198 57207 57209 57198 57204 57207 57205 57199 57198 57209 57205 57198 57199 58517 58518 59800 58517 57199 57199 57889 59800 57199 57205 57889 57200 57201 57202 57203 57201 57200 57892 57203 57200 57201 57203 58534 57894 57202 57201 57904 57894 57201 58534 57904 57201 57202 57897 57905 57202 57896 57897 57904 57896 57202 57202 57894 57904 57203 58529 58534 57203 57893 58529 57203 57892 57893 57204 57206 57207 57898 57891 57205 57205 57209 57898 57891 57889 57205 57220 57207 57206 57221 57220 57206 57207 57208 57209 57220 57208 57207 57912 57909 57208 57208 57222 57912 57208 57220 57222 57909 57209 57208 57909 57898 57209 59175 59173 57210 57210 57211 59175 57212 57211 57210 59177 59175 57211 60494 59177 57211 57211 57212 60494 57212 59828 60494 57215 57214 57213 57899 57215 57213 57900 57899 57213 57213 57216 57900 57214 57215 59172 57215 58538 59172 57215 57899 58538 57901 57900 57216 57903 57902 57218 57218 57219 57903 57220 57221 57222 57907 57222 57221 57221 57905 57907 57222 57907 57912 58547 58546 57223 57223 57225 58547 57223 57224 57225 58546 57910 57223 57911 57225 57224 57225 57911 58547 57920 57227 57226 57226 57915 57920 57226 57909 57915 58541 57909 57226 58548 58541 57226 57243 57235 57227 57920 57243 57227 57228 57234 57914 57918 57230 57229 57229 57916 57918 57230 57918 58551 57919 57232 57231 57937 57919 57231 57231 57264 57937 57247 57233 57232 57919 57247 57232 57247 57237 57233 57234 57238 57914 57237 57247 57248 57934 57914 57238 57238 57249 57934 57941 57240 57239 58556 57941 57239 58557 58556 57239 58564 57269 57240 57240 57940 58564 57941 57940 57240 57241 57242 57923 58559 57923 57242 57242 57250 58559 58549 57244 57243 57243 57915 58549 57920 57915 57243 57928 57254 57244 57244 57927 57928 58549 57927 57244 57932 57248 57247 57247 57919 57932 57248 57932 57933 57249 57259 57934 57260 57259 57249 57266 57260 57249 57267 57266 57249 59197 58559 57250 59198 59197 57250 57250 58560 59198 59198 58560 57251 57251 57252 59198 57253 57252 57251 58560 57253 57251 57252 58561 59198 57252 57253 58561 57253 57255 58561 57253 57254 57255 57928 57255 57254 59198 58561 57255 59201 59198 57255 57255 57928 59201 57256 57276 57942 57935 57262 57257 57936 57935 57257 57257 57930 57936 57265 57264 57258 58555 57934 57259 59186 58555 57259 59191 59186 57259 57259 57949 59191 57259 57260 57949 57950 57949 57260 58568 57950 57260 57260 57294 58568 57260 57293 57294 57260 57266 57293 57951 57268 57261 58564 57951 57261 57261 57269 58564 57944 57263 57262 57262 57935 57944 57280 57279 57263 57959 57280 57263 58566 57959 57263 57263 57944 58566 57264 57265 57937 57946 57937 57265 57265 57945 57946 57266 57267 57293 57267 57282 57293 57962 57283 57268 57268 57951 57962 57271 57955 57956 57271 57952 57955 57965 57952 57271 57968 57296 57272 58576 57968 57272 57272 57971 58576 57972 57971 57272 57272 57958 57972 58571 57275 57273 58572 58571 57273 59884 58572 57273 57273 59883 59884 57273 57973 59883 57273 57274 57973 57275 57274 57273 57274 57277 57973 57278 57277 57274 57274 57275 57278 57942 57276 57275 58571 57942 57275 57277 57297 57974 57277 57278 57297 57974 57973 57277 58575 57289 57280 57280 57959 58575 57980 57961 57281 57281 57979 57980 57295 57292 57282 57282 57292 57293 57283 57964 57965 57283 57962 57964 57975 57285 57284 57284 57968 57975 57284 57296 57968 57976 57286 57285 57285 57975 57976 57297 57287 57286 57976 57297 57286 57288 57291 57977 57288 57290 57291 57291 57290 57289 57969 57291 57289 58575 57969 57289 57978 57977 57291 57291 57969 57978 57292 57301 57970 57292 57295 57301 57294 57293 57292 58568 57294 57292 57292 57982 58568 57292 57981 57982 57292 57970 57981 57976 57974 57297 57298 57948 57960 57298 57299 57948 57300 57299 57298 58586 57300 57298 57298 57960 58586 57992 57304 57299 57997 57992 57299 57299 57348 57997 57299 57347 57348 59900 57347 57299 57299 57300 59900 57299 57304 57948 57300 58583 59900 58585 58583 57300 58586 58585 57300 57301 57305 57970 57987 57309 57302 57302 57303 57987 59229 57987 57303 57303 57977 59229 57992 57308 57304 57986 57970 57305 57305 57310 57986 57311 57310 57305 57312 57311 57305 58590 57990 57306 58597 58590 57306 57991 57984 57307 57307 57314 57991 57307 57313 57314 57995 57994 57309 58588 57995 57309 57309 57987 58588 57993 57986 57310 57310 57311 57993 58595 57993 57311 57311 57998 58595 57311 57312 57998 57312 57317 57998 57315 57314 57313 57316 57315 57313 58587 57991 57314 57314 57315 58587 57315 58022 58587 57315 57316 58022 57316 58014 58022 57999 57998 57317 57318 57319 58009 58596 58009 57319 57319 58001 58596 59246 57321 57320 59248 59246 57320 57320 58601 59248 57320 58010 58601 59240 58597 57321 59246 59240 57321 57322 57323 58013 58012 58011 57322 58013 58012 57322 57323 57996 58013 57340 57339 57326 57326 57330 57340 57326 57327 57330 57327 57329 57330 58007 57329 57327 57327 57328 58007 58019 58018 57329 57329 58007 58019 58607 57330 57329 57329 58020 58607 57329 58018 58020 58606 57340 57330 57334 57336 57337 57338 57337 57336 57343 57338 57336 58017 58005 57337 58600 58017 57337 58604 58600 57337 58605 58604 57337 57337 57338 58605 57338 57343 58605 58625 58035 57339 57339 58024 58625 57339 57341 58024 57339 57340 57341 58606 57341 57340 58025 58024 57341 58606 58025 57341 58026 57355 57342 59253 58605 57343 57343 58034 59253 57343 58029 58034 58037 58036 57344 57344 58035 58037 58049 58028 57345 58016 57348 57346 58033 58016 57346 58627 58033 57346 59261 58627 57346 59937 59261 57346 57346 59935 59937 57346 59922 59935 57346 57347 59922 57348 57347 57346 57347 59900 59922 58016 57997 57348 57349 58038 58633 58632 58040 57349 58634 58632 57349 57349 58633 58634 57350 58040 58631 58623 58031 57351 57351 58041 58623 58042 57353 57352 58626 58042 57352 57352 58044 58626 57352 57356 58044 59268 58047 57354 57354 58048 59268 57354 57355 58048 58616 58048 57355 57355 58026 58616 58047 58044 57356 57357 58015 58032 58646 58056 57358 57358 58642 58646 57358 58036 58642 59299 58657 57359 57359 59296 59299 57359 58651 59296 57359 58053 58651 57359 57360 58053 57361 57360 57359 57360 58033 58627 57360 57361 58033 58638 58053 57360 57360 58627 58638 57361 58032 58033 57367 57363 57362 57371 57367 57362 57372 57371 57362 57362 57370 57372 57362 57366 57370 57363 58628 58629 58645 58628 57363 59289 58645 57363 59312 59289 57363 57363 58652 59312 57363 57367 58652 58050 58049 57364 59277 58050 57364 57364 57365 59277 57365 58643 59277 57366 57369 57370 57367 57371 58652 57368 58059 58655 57368 57373 58059 58063 57370 57369 57369 58062 58063 57376 57372 57370 57377 57376 57370 58063 57377 57370 59312 58652 57371 57371 58675 59312 57371 57372 58675 57372 57376 58675 57374 58656 59298 57374 57375 58656 57375 58071 58656 57376 58674 58675 57376 57377 58674 57377 58673 58674 58683 58673 57377 57377 58063 58683 59315 57379 57378 57378 59313 59315 57378 58662 59313 59297 58658 57379 57379 58663 59297 58664 58663 57379 59314 58664 57379 59315 59314 57379 58066 57388 57380 57380 57384 58066 57386 57384 57380 57389 57386 57380 57381 58078 58666 57381 58077 58078 57381 58076 58077 57383 57382 57381 58666 57383 57381 60002 57389 57382 57382 57383 60002 60004 60002 57383 60008 60004 57383 57383 58668 60008 57383 58667 58668 57383 58666 58667 57384 57385 58066 57386 57385 57384 58665 58066 57385 57385 58067 58665 57385 57386 58067 60003 58067 57386 57386 58068 60003 58069 58068 57386 57386 57389 58069 58074 57399 57387 57387 58065 58074 57387 58064 58065 57388 58066 58073 60002 58069 57389 58079 57398 57390 57390 58070 58079 57390 58060 58070 58061 58060 57390 57390 58052 58061 57390 57391 58052 57400 57395 57393 57393 57399 57400 59325 58678 57394 57394 58684 59325 58685 58684 57394 57394 58075 58685 57394 57395 58075 57396 57395 57394 58678 57396 57394 57395 57400 58075 58662 58072 57396 58678 58662 57396 57397 57403 58076 58079 57405 57398 58085 57400 57399 57399 58084 58085 57399 58074 58084 58085 58075 57400 57401 57402 57406 57414 57406 57402 58087 57414 57402 58089 58076 57403 57403 58088 58089 57404 57405 58090 58702 58106 57404 57404 58090 58702 58671 58090 57405 57405 58079 58671 58113 58100 57407 57407 57415 58113 58705 58107 57408 57408 58101 58705 57412 57411 57410 58131 57412 57410 57410 58119 58131 57410 58109 58119 58131 58125 57412 58112 58111 57413 57413 58103 58112 58706 58103 57414 57414 58700 58706 57414 58087 58700 58120 58113 57415 57415 57420 58120 57416 58115 58116 57416 57419 58115 58720 58115 57417 57417 58117 58720 57417 58104 58117 57417 57418 58104 58106 58104 57418 58124 58120 57420 57420 57423 58124 57429 57424 57421 58724 57429 57421 58726 58724 57421 57421 58121 58726 57422 57426 58123 57427 57426 57422 58127 57427 57422 57422 57433 58127 57422 57425 57433 57423 57428 58126 57425 57431 57433 57425 57430 57431 57426 58118 58123 58721 58118 57426 57426 57427 58721 57427 58136 58721 57427 58127 58136 58723 58126 57428 57428 57441 58723 57428 57440 57441 57448 57442 57429 58725 57448 57429 57429 58724 58725 57432 57431 57430 57446 57433 57431 58130 57446 57431 58139 58130 57431 57431 58135 58139 57431 57432 58135 57433 57446 58127 57455 57447 57434 58132 57455 57434 57434 58125 58132 57435 57437 57440 57435 57436 57437 57439 57437 57436 58729 57440 57437 57437 57438 58729 57439 57438 57437 57438 57471 58729 58729 58133 57440 58133 57441 57440 57441 58741 59408 57441 58728 58741 57441 58133 58728 58730 58723 57441 59408 58730 57441 57442 57449 57451 57450 57449 57442 57442 57448 57450 58734 58134 57443 58735 58734 57443 57443 57444 58735 57444 58137 58735 58138 57452 57445 57445 58134 58138 58129 58127 57446 58130 58129 57446 57455 57454 57447 58745 57450 57448 57448 58725 58745 58137 57451 57449 59423 58137 57449 57449 58743 59423 57449 57450 58743 58745 58743 57450 58138 57457 57452 58758 58754 57453 57453 58756 58758 57453 57454 58756 57454 58142 58756 57454 57455 58142 58732 58142 57455 57455 58132 58732 58759 58141 57458 57458 58750 58759 58752 58750 57458 57458 58145 58752 57458 57468 58145 57458 57459 57468 57460 57459 57458 58141 57460 57458 57459 57463 57468 58141 57467 57460 57463 57462 57461 57468 57463 57461 58145 57468 57461 57461 58144 58145 58146 58144 57461 58155 58146 57461 58157 58155 57461 57461 57477 58157 57461 57462 57477 57462 57476 57477 58781 58147 57465 57465 58763 58781 57465 58760 58763 57465 58755 58760 58141 58139 57466 57466 57467 58141 58740 58729 57471 58153 57486 57472 57487 57474 57473 58774 58153 57474 58775 58774 57474 58776 58775 57474 57474 57487 58776 58154 57488 57475 57497 57477 57476 57477 57497 58157 57478 58147 58158 57482 57480 57479 58761 58152 57480 58764 58761 57480 57480 57482 58764 57490 57482 57481 57481 57484 57490 57481 57483 57484 57482 57491 58764 57482 57490 57491 58772 57490 57484 57484 57485 58772 57485 58771 58772 57485 57486 58771 57486 58153 58771 57487 58163 58776 57487 57500 58163 58154 57495 57488 58170 57498 57489 58787 58170 57489 57489 58165 58787 57492 57491 57490 58772 57492 57490 60118 59433 57491 57491 60115 60118 57491 57492 60115 59429 58764 57491 59433 59429 57491 60116 60115 57492 57492 58772 60116 57495 57499 57500 58765 57499 57495 57495 58154 58765 58169 58166 57496 57496 57502 58169 58164 58157 57497 58777 58164 57497 58170 57504 57498 58782 57500 57499 59436 58782 57499 57499 58765 59436 59435 58163 57500 57500 58782 59435 58784 57502 57501 57501 58783 58784 58790 58783 57501 57501 58168 58790 57501 57503 58168 58785 58169 57502 57502 58784 58785 57503 57515 58168 57503 57507 57515 57505 57511 58180 57506 58175 58792 58792 58174 57506 57510 57509 57508 58172 57510 57508 57508 58171 58172 57509 57510 58177 58797 58177 57510 58798 58797 57510 59458 58798 57510 57510 59453 59458 57510 58791 59453 57510 58172 58791 58793 58180 57511 57511 58173 58793 58187 57514 57512 58188 58187 57512 57512 58176 58188 57513 58181 58182 58788 58168 57515 58789 58788 57515 58796 58789 57515 57516 57517 58186 57518 57517 57516 58192 57518 57516 57516 57521 58192 57517 58185 58186 58814 58185 57517 57517 57518 58814 59484 58814 57518 57518 58815 59484 57518 58192 58815 58191 57539 57519 58825 57525 57520 59482 58825 57520 57520 58189 59482 57520 58182 58189 57524 57525 57548 58234 57548 57525 58825 58234 57525 58237 58194 57526 58843 58213 57527 57527 57543 58843 57527 57542 57543 58213 57528 57527 58826 58193 57528 59496 58826 57528 57528 58834 59496 57528 58213 58834 58214 57530 57529 58215 58214 57529 59525 58215 57529 57529 58844 59525 57529 58199 58844 57529 58195 58199 58214 57543 57530 58835 58205 57531 58852 58835 57531 57531 58224 58852 57531 57532 58224 57545 57544 57534 58207 58206 57535 57535 57536 58207 57537 57536 57535 58201 57537 57535 59521 58207 57536 57536 58836 59521 57536 57537 58836 57537 57538 58836 58837 58836 57538 57538 58210 58837 58209 58208 57539 57539 58191 58209 57539 58208 58210 57540 58228 58233 57540 58212 58228 57540 57541 58212 58851 58843 57543 57543 58223 58851 57543 58222 58223 57543 58215 58222 57543 58214 58215 58226 57549 57544 58854 58226 57544 58855 58854 57544 57544 58207 58855 57544 58206 58207 57544 57545 58206 58861 58229 57546 57546 58240 58861 57553 57550 57547 58241 57553 57547 57548 58234 58235 57549 58231 58232 57549 58225 58231 58226 58225 57549 57550 57554 57555 57550 57553 57554 58239 58238 57552 58873 58239 57552 57552 58227 58873 58233 58227 57552 58867 57554 57553 57553 58235 58867 58241 58235 57553 58245 57555 57554 58867 58245 57554 58887 58246 57555 57555 58885 58887 57555 58245 58885 57556 57570 58230 57556 57569 57570 57558 57559 57572 57560 57559 57558 57559 58888 58889 57559 58869 58888 58870 58869 57559 57559 57560 58870 58889 57572 57559 57560 58232 58870 57568 57567 57562 58238 57568 57562 57563 57571 58250 57572 57571 57563 58892 58891 57564 57564 58256 58892 57564 58251 58256 57564 57566 58251 58891 57565 57564 59540 58211 57565 57565 58890 59540 58891 58890 57565 58257 58251 57566 57566 57573 58257 57567 57568 57574 58238 57574 57568 58255 57570 57569 58248 58230 57570 58254 58248 57570 58255 58254 57570 57571 58254 58255 59554 58254 57571 57571 58889 59554 57571 57572 58889 58258 58257 57573 57573 57585 58258 57574 58253 58906 57574 58238 58253 58267 58266 57575 58268 58267 57575 57575 57581 58268 58266 57576 57575 57576 58266 58883 57577 57578 58259 58269 58259 57578 58916 57588 57579 58921 58916 57579 59565 58921 57579 57579 58262 59565 57579 58261 58262 57579 57583 58261 58261 57583 57580 57581 57582 58268 57582 57584 58268 57584 57607 58268 57584 57594 57607 57585 57586 58258 58905 58258 57586 58912 58905 57586 57586 58270 58912 57587 57588 57598 58920 57598 57588 57588 58916 58920 57602 57593 57589 57589 57592 57602 57596 57591 57590 58260 57596 57590 58272 57602 57592 58274 58272 57592 57592 57600 58274 57593 58271 58279 57593 57602 58271 57594 57606 57607 57594 57595 57606 57595 57603 57606 58260 57597 57596 58275 57604 57597 57597 58260 58275 59563 58270 57598 57598 58920 59563 58277 57601 57599 58278 58277 57599 57599 57605 58278 57601 57600 57599 57600 57601 58274 57601 58277 58927 58927 58274 57601 58930 58928 57602 57602 58273 58930 57602 58272 58273 58928 58271 57602 58923 57606 57603 57603 58275 58923 57603 57604 58275 57605 57609 57611 58276 57609 57605 57605 57619 58278 58918 57607 57606 59574 58918 57606 57606 58922 59574 58923 58922 57606 58914 58268 57607 58915 58914 57607 58917 58915 57607 58918 58917 57607 57618 57614 57610 58280 57618 57610 57612 57613 57615 58282 57615 57613 57613 57617 58282 57615 58271 58928 58282 58271 57615 57617 58281 58282 57617 57618 58281 57618 58280 58281 58284 58278 57619 57621 58294 58297 57621 58293 58294 57632 57623 57622 57622 57631 57632 57622 57630 57631 57624 57625 57628 57641 57628 57625 57625 57626 57641 59578 58299 57627 57627 58303 59578 57627 57628 58303 57629 57628 57627 58299 57629 57627 57628 57641 58303 57629 58300 58931 57629 58299 58300 58301 57631 57630 58302 57632 57631 58304 58302 57631 58936 58304 57631 57631 58935 58936 57631 58301 58935 58302 57633 57632 58302 57644 57633 57635 57638 57639 57637 57636 57635 57639 57637 57635 57640 57639 57638 57641 57642 58303 57643 57642 57641 58307 57643 57641 59578 58303 57642 59579 59578 57642 57642 57643 59579 57643 58937 59579 57643 58307 58937 58309 57645 57644 57644 58302 58309 57645 58309 58314 57646 57647 58305 58311 58305 57647 57647 57649 58311 57647 57648 57649 58312 58311 57649 58313 58312 57649 58317 58313 57649 57656 57655 57650 57650 57654 57656 57653 57658 58317 57662 57656 57654 57655 57656 57663 57656 57662 57663 58327 57668 57657 57657 57674 58327 57657 57667 57674 57658 58316 58317 57658 58315 58316 57658 57659 58315 57659 57665 58315 57659 57660 57665 57661 58320 58321 58322 57663 57662 57674 57667 57663 58322 57674 57663 58323 57665 57664 58324 58323 57664 58330 58324 57664 58316 58315 57665 58318 58316 57665 58319 58318 57665 58323 58319 57665 58325 57672 57669 58326 58325 57669 57669 58321 58326 57672 57670 57669 58957 58333 57670 57670 57671 58957 57672 57671 57670 59602 58957 57671 57671 57672 59602 57672 58325 58329 57672 58328 59602 58329 58328 57672 57674 57675 58327 57676 57693 58334 58334 58331 57676 58964 58340 57678 57678 58962 58964 57678 58959 58962 57678 58955 58959 57678 58335 58955 57679 58341 58342 57679 57689 58341 58339 57680 57679 58342 58339 57679 58338 57682 57680 58339 58338 57680 58359 57683 57681 57681 57698 58359 57681 57682 57698 58338 57698 57682 57701 57685 57683 57683 57700 57701 58359 57700 57683 58344 57686 57684 58967 58344 57684 57684 58966 58967 58965 57687 57685 57685 57701 58965 59614 58966 57687 57687 58965 59614 58341 57689 57688 57688 57696 58341 57690 58348 58356 57691 58352 58361 58353 57695 57692 58346 58334 57693 57693 58345 58346 58353 58345 57695 58342 58341 57696 57696 57697 58342 58980 57701 57699 58982 58980 57699 57699 58981 58982 57699 57707 58981 57699 57700 57707 57701 57700 57699 58980 58965 57701 58355 58353 57702 58357 58355 57702 57702 57703 58357 57704 57703 57702 57705 57704 57702 58983 58357 57703 58985 58983 57703 57703 57704 58985 57704 58362 58985 57704 57710 58362 57704 57705 57710 57706 58356 58358 57706 58358 58363 58994 58981 57707 57707 57709 58994 57707 57708 57709 57717 57709 57708 57709 57717 58994 58371 58362 57710 57710 57721 58371 57711 58986 58987 57714 57713 57712 57713 57726 57727 57713 57725 57726 58992 57725 57713 57713 57714 58992 57714 58989 58992 57714 58365 58989 57719 57716 57715 58994 57717 57716 57716 58993 58994 57716 57719 58993 57718 58367 58370 57718 58364 58367 59004 58993 57719 57721 57722 58371 57723 57722 57721 58995 58371 57722 59002 58995 57722 57722 57723 59002 57723 59001 59002 59646 58384 57724 59650 59646 57724 57724 57725 59650 57726 57725 57724 58384 57726 57724 57725 58997 59650 57725 58992 58997 58384 57731 57726 57728 57735 58374 59006 57730 57729 57729 58367 59006 58370 58367 57729 57729 58369 58370 59006 58380 57730 58384 58376 57731 57732 58386 58389 58389 57733 57732 57733 57743 57744 58400 57743 57733 57733 58389 58400 57734 58382 58387 57734 58381 58382 58388 58374 57735 57735 58385 58388 58390 57737 57736 57736 57751 58390 57737 59014 59015 57737 58390 59014 57740 57739 57738 57753 57740 57738 58387 57753 57738 58392 57766 57739 57739 57740 58392 57740 58391 58392 59655 58391 57740 57740 57753 59655 59020 58385 57741 57741 58393 59020 57741 57755 58393 57741 57742 57755 57742 57754 57755 58400 57745 57743 57745 57744 57743 58401 57746 57745 57745 58400 58401 57746 59027 59028 57746 58401 59027 57747 57748 57750 57749 57748 57747 58396 57750 57748 57748 57749 58396 58396 57757 57750 57751 57752 58390 57752 57764 58390 57752 57761 57764 57753 59016 59655 57753 58387 59016 58398 57755 57754 59019 58393 57755 57755 59018 59019 57755 58398 59018 59030 57757 57756 57756 59029 59030 57756 59028 59029 60371 59669 57757 57757 60370 60371 57757 59030 60370 59038 57789 57758 57758 57759 59038 57759 57760 59670 57759 58403 59038 57759 58402 58403 59670 58402 57759 57760 59669 59670 57765 57764 57761 57762 58404 58405 57762 57776 58404 57762 57773 57776 58399 58398 57763 59025 58399 57763 57763 58405 59025 58397 58390 57764 59022 58397 57764 57764 57765 59022 57765 57768 59022 57765 57767 57768 58407 58406 57766 59032 58407 57766 57766 58392 59032 58408 57768 57767 57767 57769 58408 59671 59022 57768 57768 59040 59671 57768 59039 59040 57768 58408 59039 57769 57770 58408 58411 58408 57770 57770 57778 58411 57792 57779 57772 57773 57775 57776 57780 57775 57773 57773 57774 57780 58415 58413 57775 57775 57793 58415 57775 57783 57793 57775 57780 57783 57777 57776 57775 58413 57777 57775 57776 57777 58404 59034 58404 57777 57777 58413 59034 58412 58411 57778 57778 57781 58412 57792 57782 57779 57781 58410 58412 57781 57798 58410 57782 57792 57799 57802 57801 57784 58418 58416 57785 59052 58418 57785 59691 57796 57786 59692 59691 57786 59693 59692 57786 57786 58421 59693 57786 57787 58421 57787 57789 58421 57787 57788 57789 57789 58420 58421 59038 58420 57789 57790 57791 58423 59702 57797 57790 57790 58423 59702 59055 57799 57792 59683 59055 57792 57792 59046 59683 57792 58406 59046 57800 57795 57794 57795 57800 58428 59691 59054 57796 58422 57798 57797 59041 58422 57797 59681 59041 57797 59702 59681 57797 57798 58409 58410 58422 58409 57798 59056 58424 57799 57799 59055 59056 57800 57805 58428 57801 57802 58432 59053 58432 57802 57802 58417 59053 57821 57813 57803 57803 57814 57821 57813 57804 57803 57815 57805 57804 57804 57813 57815 58429 58428 57805 58430 58429 57805 57805 57815 58430 58440 58438 57806 59060 58440 57806 59061 59060 57806 57806 58431 59061 57807 57808 58458 57809 57808 57807 58447 57809 57807 57807 57821 58447 57807 57815 57821 58455 57815 57807 58462 58455 57807 58469 58462 57807 57807 58458 58469 57808 57809 59731 59731 58458 57808 57809 58447 59082 57809 59082 59731 58434 57811 57810 57811 57823 57824 58442 57823 57811 59067 58442 57811 57811 59066 59067 57811 58434 59066 57821 57815 57813 57822 57821 57814 58437 58430 57815 58455 58437 57815 58433 57817 57816 58441 58433 57816 57816 58439 58441 57816 58438 58439 58451 58435 57818 58464 58451 57818 58468 58464 57818 58443 58425 57819 57819 57820 58443 57820 58435 58443 58453 58447 57821 57821 57822 58453 59071 58453 57822 57822 58436 59071 59086 58467 57823 57823 58448 59086 57823 58442 58448 59106 58473 57825 57825 59095 59106 57825 58467 59095 61016 59750 57826 61022 61016 57826 57826 59108 61022 57826 57827 59108 57828 57827 57826 59750 57828 57826 57827 59102 59108 57827 59097 59102 57827 57828 59097 57828 59098 59099 59100 59098 57828 59745 59100 57828 59746 59745 57828 59750 59746 57828 57828 58468 59097 59099 58468 57828 57829 57830 59097 59097 58468 57829 57830 57831 57836 57830 57836 59097 57831 57835 57837 57837 57836 57831 57832 57833 57834 58477 57854 57834 57834 58476 58477 57834 58472 58476 57840 57837 57835 59102 59097 57836 57836 57837 59102 59118 59102 57837 59119 59118 57837 59120 59119 57837 57837 57840 59120 57856 57839 57838 57857 57856 57838 58488 57857 57838 57838 57853 58488 57840 57841 59120 59766 59120 57841 57841 58482 59766 57844 57843 57842 57845 57844 57842 57842 57843 58484 58486 58485 57843 57843 57844 58486 59768 58484 57843 59769 59768 57843 57843 59123 59769 57843 58485 59123 57844 57846 58486 57844 57845 57846 58489 58486 57846 57846 57858 58489 57849 57848 57847 59111 58487 57848 57848 59109 59111 59110 59109 57848 57848 58476 59110 58477 58476 57848 57848 57854 58477 57848 57849 57854 58481 57851 57850 57850 57855 58481 58481 57852 57851 59116 57853 57852 57852 58481 59116 59116 58488 57853 57863 57862 57856 57864 57863 57856 57856 57857 57864 58488 57864 57857 58511 58489 57858 57858 57871 58511 60453 58499 57859 57859 58500 60453 57859 57860 58500 57861 57860 57859 58499 57861 57859 57860 58498 58500 59136 58498 57860 59137 59136 57860 57860 57861 59137 59780 59137 57861 60457 59780 57861 57861 58499 60457 58501 57876 57862 57862 57863 58501 59794 58501 57863 57863 59121 59794 57863 57864 59121 57864 59116 59121 57864 58488 59116 57867 57866 57865 58507 57869 57866 57866 57867 58507 59147 57870 57868 57868 57869 59147 57869 59144 59147 59145 59144 57869 59146 59145 57869 57869 58507 59146 58519 58508 57870 59147 58519 57870 57872 57878 57879 57885 57878 57872 58513 57885 57872 57872 58495 58513 58512 58495 57872 57872 57873 58512 59134 58512 57873 59148 59134 57873 57873 58502 59148 57873 57874 58502 57875 57876 58520 59155 58520 57876 57876 59149 59155 57876 58501 59149 57877 58508 58521 57885 57879 57878 59167 57887 57879 57879 57882 59167 57884 57882 57879 57885 57884 57879 57880 57881 58518 58506 58504 57880 58514 58506 57880 58518 58514 57880 57882 57883 59158 57884 57883 57882 59168 59167 57882 57882 59166 59168 57882 59158 59166 57883 57884 58525 57883 58525 59158 57884 57885 58513 57884 58513 58525 58524 57888 57886 57886 57887 58524 57887 59168 59832 57887 59167 59168 59159 58524 57887 59810 59159 57887 59832 59810 57887 58527 58526 57888 59159 58527 57888 57888 58524 59159 57889 59154 59800 57889 58536 59154 57889 57890 58536 57891 57890 57889 57890 58530 58536 57890 57891 58530 57891 57898 58530 58526 57893 57892 59160 58529 57893 59812 59160 57893 57893 59161 59812 57893 58526 59161 59827 59825 57895 57895 59164 59827 57895 57896 59164 57897 57896 57895 59170 57897 57895 59825 59170 57895 57896 58534 59164 57896 57904 58534 57907 57905 57897 57897 57906 57907 59170 57906 57897 58540 58530 57898 57898 57909 58540 57899 57900 58538 57900 57901 59180 57900 58533 58538 59180 58533 57900 57901 59179 59180 57901 57902 59179 57902 58544 59179 57902 58543 58544 57902 58542 58543 57902 58539 58542 57902 57903 58539 57903 57910 58539 57908 57907 57906 59170 57908 57906 58550 58549 57907 57907 57908 58550 58549 57912 57907 59833 58550 57908 57908 59170 59833 57909 57912 57915 58541 58540 57909 58545 58539 57910 58546 58545 57910 57911 57913 58547 57914 57913 57911 58549 57915 57912 59184 58547 57913 57913 58553 59184 57913 57914 58553 57914 57934 58553 57916 57917 57918 57921 57917 57916 59188 57918 57917 57917 59187 59188 57917 57921 59187 58552 58551 57918 59188 58552 57918 57937 57932 57919 57921 57943 59187 57931 57930 57922 57926 57924 57923 58559 57926 57923 59192 58558 57924 57924 57925 59192 57926 57925 57924 57925 57926 59193 59194 59192 57925 57925 59193 59194 57926 58559 59197 59197 59193 57926 57927 59189 59195 57927 58554 59189 57927 58549 58554 59195 57928 57927 57928 59195 59201 58563 57943 57929 57929 58562 58563 57929 57942 58562 59196 57936 57930 57930 58551 59196 57930 57931 58551 57938 57933 57932 57947 57938 57932 57932 57937 57947 57933 57938 57939 58555 58553 57934 58565 57944 57935 57935 57936 58565 59202 58565 57936 57936 59196 59202 57937 57946 57947 57947 57939 57938 57946 57945 57939 57947 57946 57939 59204 58564 57940 59217 59204 57940 59867 59217 57940 57940 58556 59867 57940 57941 58556 58571 58562 57942 59850 59187 57943 57943 58563 59850 57944 58565 58566 59865 59191 57949 59866 59865 57949 59869 59866 57949 57949 59213 59869 57949 57950 59213 57950 58577 59213 57950 57982 58577 58568 57982 57950 57963 57962 57951 58564 57963 57951 59208 57955 57952 59214 59208 57952 57952 57953 59214 57954 57953 57952 57965 57954 57952 59904 59214 57953 57953 59227 59904 57953 57954 59227 57954 59226 59228 57954 57966 59226 57954 57965 57966 59228 59227 57954 57957 57956 57955 59208 57957 57955 57956 57957 57958 59208 57958 57957 59209 57972 57958 59211 59209 57958 57958 59208 59211 59216 58575 57959 57959 59205 59216 57959 58566 59205 57960 57961 58586 57961 58585 58586 57961 57980 58585 57962 57963 58567 57967 57964 57962 58567 57967 57962 57963 58564 58567 57967 57965 57964 57967 57966 57965 57966 59219 59226 59220 59219 57966 57966 59218 59220 57966 58569 59218 57966 57967 58569 59217 58569 57967 57967 59207 59217 57967 58567 59207 58576 57975 57968 58573 57978 57969 58574 58573 57969 58575 58574 57969 57986 57981 57970 57971 57975 58576 60525 57975 57971 57971 58570 60525 57971 57972 58570 59881 58570 57972 57972 59212 59881 57972 59209 59212 57973 57974 59883 60540 59883 57974 57974 59882 60540 57974 57976 59882 59882 57976 57975 60525 59882 57975 57977 59224 59229 57977 57978 59224 57978 58573 59224 58584 57980 57979 57979 58582 58584 57979 57985 58582 57980 58583 58585 58584 58583 57980 58580 57982 57981 59233 58580 57981 57981 57993 59233 57981 57986 57993 58578 58577 57982 58579 58578 57982 58580 58579 57982 57983 57984 57985 57991 57985 57984 57985 57991 58587 57985 58581 58582 59232 58581 57985 57985 58587 59232 57987 59230 59906 57987 59229 59230 58589 58588 57987 59906 58589 57987 58013 57996 57988 58591 58013 57988 57988 57989 58591 57989 57990 58591 57990 58590 58591 59237 59233 57993 59242 59237 57993 57993 58595 59242 58593 58002 57994 57994 57995 58593 59239 58593 57995 59910 59239 57995 57995 58589 59910 57995 58588 58589 57998 57999 58595 57999 58000 58595 58600 58595 58000 58000 58599 58600 58000 58004 58599 58001 58594 58596 58001 58002 58594 58002 58593 58594 58003 58615 58624 58022 58014 58003 58023 58022 58003 58624 58023 58003 58004 58006 58599 58004 58005 58006 58017 58006 58005 58006 58017 58599 58007 58008 58019 58008 58018 58019 58020 58018 58008 58608 58020 58008 58612 58609 58009 58009 58596 58612 58027 58026 58011 59249 58027 58011 58011 58012 59249 59250 59249 58012 59251 59250 58012 58012 58598 59251 58012 58013 58598 59241 58598 58013 58013 58592 59241 58013 58591 58592 58033 58032 58015 58015 58016 58033 58600 58599 58017 58603 58601 58021 58613 58603 58021 58022 58023 58587 60580 59898 58023 58023 59259 60580 58023 58624 59259 59234 58587 58023 59898 59234 58023 58024 58620 58625 58024 58025 58620 59265 58620 58025 58617 58616 58026 58026 58027 58617 59257 58617 58027 58027 59249 59257 58619 58618 58028 58028 58050 58619 58028 58049 58050 58628 58034 58029 58629 58628 58029 58614 58613 58030 58030 58031 58614 59928 58614 58031 58031 58636 59928 58031 58621 58636 58623 58621 58031 58034 58640 59253 58034 58628 58640 58625 58037 58035 59280 58642 58036 58036 58037 59280 58037 59269 59280 58037 58625 59269 58038 58039 58630 58038 58630 58633 58632 58631 58040 58631 58623 58041 58626 58043 58042 58626 58051 58043 58044 58045 58626 58046 58045 58044 58047 58046 58044 59275 58626 58045 59966 59275 58045 60600 59966 58045 58045 59967 60600 58045 58046 59967 58046 59276 59967 58046 59268 59276 58046 58047 59268 58048 58616 59257 59952 59268 58048 58048 59934 59952 58048 59257 59934 58637 58619 58050 59277 58637 58050 59282 58057 58051 58051 59274 59282 58051 58626 59274 58659 58061 58052 58052 58058 58659 58052 58057 58058 59279 58651 58053 58053 58638 59279 58054 59979 60618 59980 59979 58054 58054 58055 59980 58054 58653 58661 58654 58653 58054 60618 58654 58054 58055 59292 59980 59974 58058 58057 58057 59282 59974 59986 58659 58058 58058 59974 59986 58658 58655 58059 58670 58070 58060 58060 58660 58670 58060 58659 58660 58060 58061 58659 58683 58063 58062 59310 58683 58062 58062 58657 59310 58661 58065 58064 58690 58074 58065 58065 58677 58690 58065 58661 58677 58665 58073 58066 59316 58665 58067 59317 59316 58067 60003 59317 58067 60632 60003 58068 58068 58069 60632 58069 60002 60632 58671 58079 58070 58070 58670 58671 58071 58081 58656 58682 58081 58071 58665 58086 58073 58690 58084 58074 58075 58085 58685 58089 58077 58076 58679 58078 58077 58680 58679 58077 58695 58680 58077 58077 58694 58695 58077 58089 58694 58669 58666 58078 58679 58669 58078 58082 58081 58080 59337 58082 58080 59346 59337 58080 58080 58697 59346 58080 58083 58697 58682 58083 58080 58080 58081 58682 58081 58082 58656 59329 58656 58082 59337 59329 58082 58095 58085 58084 58690 58095 58084 58691 58685 58085 58085 58096 58691 58085 58095 58096 58692 58087 58086 59340 58692 58086 58086 59330 59340 58086 58665 59330 58701 58700 58087 58087 58693 58701 58087 58692 58693 58694 58089 58088 58703 58694 58088 58088 58097 58703 58090 58671 58672 59328 58702 58090 58090 58681 59328 58090 58672 58681 58094 58093 58092 59339 58094 58092 59365 59339 58092 58092 59361 59365 58092 58698 59361 58092 58098 58698 58092 58093 58098 58093 58094 58099 58093 58095 58098 58099 58095 58093 59350 58099 58094 59368 59350 58094 58094 59339 59368 58099 58096 58095 58690 58098 58095 59351 58691 58096 58096 58099 59351 58097 58100 58703 58699 58698 58098 58098 58677 58699 58690 58677 58098 58099 59350 59351 58710 58703 58100 58100 58113 58710 59363 58705 58101 59364 59363 58101 60052 59364 58101 58101 59378 60052 58101 59372 59378 58101 58712 59372 58101 58108 58712 58101 58102 58108 58118 58108 58102 58706 58112 58103 58711 58117 58104 58104 58105 58711 58106 58105 58104 60062 58711 58105 58105 58106 60062 58106 59345 60062 58106 58702 59345 58704 58697 58107 58705 58704 58107 58108 58118 58712 58714 58119 58109 58109 58110 58714 58715 58714 58110 58716 58715 58110 59383 58716 58111 59393 59383 58111 58111 59384 59393 58111 58706 59384 58111 58112 58706 58713 58710 58113 58113 58120 58713 58122 58116 58114 59385 58122 58114 59387 59385 58114 59388 59387 58114 58114 58720 59388 58114 58115 58720 58116 58115 58114 58122 58121 58116 58117 58711 59376 59390 58720 58117 58117 59375 59390 59376 59375 58117 59395 58712 58118 59397 59395 58118 59398 59397 58118 58118 58721 59398 58119 58125 58131 58722 58125 58119 59391 58722 58119 58119 58714 59391 58121 58717 58726 58121 58122 58717 59385 58717 58122 58722 58132 58125 58127 58128 58136 58129 58128 58127 58731 58136 58128 58128 58140 58731 58128 58129 58140 58129 58130 58140 58130 58139 58140 58733 58732 58132 59403 58733 58132 58132 58722 59403 58740 58728 58133 58133 58729 58740 58736 58138 58134 58134 58734 58736 58727 58721 58136 58731 58727 58136 59410 58735 58137 59423 59410 58137 59412 58149 58138 58138 59411 59412 58138 58736 59411 58141 58140 58139 59401 58731 58140 59407 59401 58140 59413 59407 58140 58140 58748 59413 58140 58141 58748 58759 58748 58141 58757 58756 58142 58142 58732 58757 58753 58752 58143 58143 58146 58753 58143 58144 58146 58145 58144 58143 58752 58145 58143 58146 58155 58753 58769 58158 58147 58781 58769 58147 59431 59430 58148 58148 59412 59431 58148 58149 59412 58766 58154 58148 59430 58766 58148 58150 58151 58161 59432 58161 58151 58151 58770 59432 58151 58159 58770 58774 58771 58153 58766 58765 58154 59425 58753 58155 58155 58767 59425 58155 58156 58767 58157 58156 58155 58156 58164 58767 58156 58157 58164 58768 58159 58158 58769 58768 58158 58159 58768 58770 58162 58161 58160 60128 58162 58160 60755 60128 58160 60756 60755 58160 58160 60122 60756 58160 58161 60122 58161 59432 60122 59445 58165 58162 60128 59445 58162 59434 58776 58163 59435 59434 58163 58777 58767 58164 59445 58787 58165 58785 58167 58166 58166 58169 58785 59452 58786 58167 58167 58785 59452 59450 58790 58168 59454 59450 58168 58168 58788 59454 58172 58171 58170 58787 58172 58170 59447 58791 58172 58172 59446 59447 58172 58787 59446 59460 58793 58173 58173 59459 59460 58173 58178 59459 58792 58176 58174 58175 58180 58792 58792 58188 58176 58797 58179 58177 58178 58179 59459 58179 58800 59459 58179 58799 58800 58179 58797 58799 58793 58792 58180 58183 58182 58181 58805 58183 58181 58181 58185 58805 58186 58185 58181 58182 58184 58189 58182 58183 58184 58813 58184 58183 59468 58813 58183 58183 58805 59468 58812 58189 58184 58813 58812 58184 58814 58805 58185 58816 58190 58187 58187 58188 58816 58188 58806 58816 58807 58806 58188 58188 58804 58807 58188 58792 58804 58189 58812 59482 58202 58191 58190 58816 58202 58190 58191 58203 58209 58191 58202 58203 58192 58193 58815 59495 58815 58193 58193 58826 59495 59497 59463 58194 59508 59497 58194 58194 58237 59508 58195 58198 58199 58827 58199 58196 58828 58827 58196 58196 58197 58828 58199 58198 58196 58197 58200 58828 58199 59505 59506 58199 58827 59505 59506 58844 58199 58829 58828 58200 58200 58205 58829 58204 58203 58202 58821 58204 58202 58822 58821 58202 58202 58816 58822 60165 59507 58203 58203 60164 60165 58203 58204 60164 58203 58208 58209 59507 58208 58203 60795 60164 58204 58204 58821 60795 58835 58829 58205 59521 58855 58207 58837 58210 58208 59507 58837 58208 58211 58236 58237 59537 58236 58211 59540 59537 58211 59519 58834 58213 58213 58843 59519 59525 58222 58215 58216 58835 58852 58216 58829 58835 58216 58217 58829 58218 58217 58216 58249 58218 58216 58852 58249 58216 59520 58829 58217 60188 59520 58217 60197 60188 58217 58217 58218 60197 58218 60194 60197 60196 60194 58218 58218 59539 60196 58218 58249 59539 58233 58228 58219 58219 58227 58233 58219 58220 58227 58221 58220 58219 58873 58227 58220 60199 58873 58220 58220 59543 60199 58220 58229 59543 58220 58221 58229 58862 58223 58222 59525 58862 58222 59532 58851 58223 59533 59532 58223 58223 58862 59533 58224 58249 58852 58224 58230 58249 58853 58231 58225 58225 58226 58853 58854 58853 58226 58229 58861 59543 58230 58248 58249 58853 58232 58231 58232 58869 58870 58232 58854 58869 58232 58853 58854 58841 58235 58234 58842 58841 58234 59503 58842 58234 58234 58825 59503 58868 58867 58235 59518 58868 58235 58235 58841 59518 58236 59535 60172 59537 59535 58236 58863 58237 58236 60172 58863 58236 58237 58863 59508 58238 58252 58253 58238 58239 58252 59549 58252 58239 58239 58882 59549 58239 58881 58882 58239 58873 58881 58875 58861 58240 58240 58874 58875 58240 58244 58874 60225 58911 58242 58242 58243 60225 58243 58886 58897 58243 58246 58886 58243 58897 60225 59550 58885 58245 58245 59546 59550 58245 58884 59546 58245 58867 58884 58887 58886 58246 59547 59539 58247 58247 59542 59547 58247 58248 59542 58249 58248 58247 59539 58249 58247 58248 58254 59542 58257 58256 58251 58904 58253 58252 59549 58904 58252 58908 58906 58253 58253 58904 58908 60217 59542 58254 58254 59555 60217 58254 59554 59555 58256 58257 58892 58899 58892 58257 58257 58258 58899 58905 58899 58258 60236 58260 58259 58259 58910 60236 58259 58269 58910 59575 58275 58260 58260 58924 59575 58925 58924 58260 60236 58925 58260 58262 58263 59565 59566 59565 58263 59569 59566 58263 58263 58264 59569 60862 59569 58264 58264 60239 60862 58264 59567 60239 58264 58913 59567 58264 58265 58913 58265 58907 58913 58265 58906 58907 58266 58267 58909 59552 58883 58266 58266 58909 59552 58267 58268 58909 59562 58909 58268 58268 58914 59562 58911 58910 58269 59563 58912 58270 58281 58279 58271 58282 58281 58271 58929 58273 58272 58272 58926 58929 58272 58274 58926 58927 58926 58274 58275 58922 58923 59575 58922 58275 58277 58284 58927 58277 58278 58284 58281 58280 58279 58286 58285 58283 58284 58285 58927 58285 58286 58927 58286 58926 58927 58294 58290 58287 58287 58288 58294 58289 58296 58297 58294 58293 58290 58297 58296 58291 58291 58295 58297 58291 58292 58295 58298 59578 60254 58298 58299 59578 58300 58299 58298 60254 58300 58298 58933 58931 58300 60260 58933 58300 58300 60254 60260 58302 58304 58309 58304 58936 59580 59589 58309 58304 58304 59588 59589 58304 59580 59588 58305 58306 58307 58311 58306 58305 58938 58308 58306 58306 58312 58938 58306 58311 58312 58308 58307 58306 58307 58308 58937 58308 58938 58941 59584 58937 58308 59587 59584 58308 58308 58941 59587 59589 58314 58309 58941 58938 58312 58312 58313 58941 58313 58317 58942 58313 58939 58941 58940 58939 58313 58942 58940 58313 58314 58944 58946 58945 58944 58314 59589 58945 58314 58318 58317 58316 58317 58318 58942 58318 58319 58942 58943 58942 58319 60272 58943 58319 60882 60272 58319 58319 58949 60882 58319 58323 58949 58947 58321 58320 58320 58944 58947 58946 58944 58320 58947 58326 58321 60882 58949 58323 58323 58324 60882 60892 60882 58324 58324 59593 60892 58324 58953 59593 58324 58330 58953 58950 58329 58325 58325 58326 58950 58326 58947 58951 58951 58950 58326 58328 58957 59602 59594 58957 58328 59596 59594 58328 59603 59596 58328 58328 58329 59603 58329 58950 59604 59604 59603 58329 58330 58952 58953 59606 58332 58331 58331 58334 59606 60897 58952 58332 58332 59606 60897 58957 58336 58333 58334 58346 58974 60301 59606 58334 58334 58960 60301 58961 58960 58334 60312 58961 58334 58334 58972 60312 58974 58972 58334 58335 58337 58955 58335 58336 58337 58957 58337 58336 58337 58954 58955 58957 58954 58337 58349 58348 58340 58964 58349 58340 58343 59616 59619 58343 58344 59616 58344 58967 59616 58347 58346 58345 58354 58347 58345 58345 58353 58354 58346 58347 58974 58347 58354 58973 58347 58973 58974 58358 58356 58348 58348 58349 58358 58968 58358 58349 58969 58968 58349 58349 58964 58969 58984 58361 58350 59631 58984 58350 58350 58351 59631 58352 58351 58350 58361 58352 58350 58351 59619 60308 58351 58352 59619 59638 59631 58351 60308 59638 58351 58355 58354 58353 58354 58355 58976 58976 58973 58354 58355 58975 58977 58355 58357 58975 58977 58976 58355 58983 58975 58357 58971 58363 58358 58358 58968 58971 58366 58364 58360 58984 58366 58360 58360 58361 58984 59003 58985 58362 58362 58371 59003 58363 58971 58986 58990 58368 58364 58364 58366 58990 58368 58367 58364 58365 58988 58989 58991 58988 58365 58365 58979 58991 59636 58990 58366 58366 59631 59636 58366 58984 59631 58367 58999 59006 59000 58999 58367 58367 58368 59000 58368 58990 59000 58371 58995 59003 59005 58375 58373 58373 58374 59005 59651 59005 58374 58374 58388 59651 58383 58381 58376 58384 58383 58376 58379 58378 58377 59007 58379 58377 59013 58386 58378 58378 58379 59013 59654 59013 58379 58379 59007 59654 59008 59007 58380 58380 59006 59008 59012 58382 58381 58381 58383 59012 58382 59011 59016 59012 59011 58382 59016 58387 58382 59648 59012 58383 58383 59646 59648 58383 58384 59646 59659 58388 58385 58385 59020 59659 59013 58395 58386 58395 58389 58386 59659 59651 58388 59661 58400 58389 58389 58394 59661 58395 58394 58389 59017 59014 58390 58390 58397 59017 60365 59033 58391 58391 59656 60365 58391 59655 59656 59033 58392 58391 59033 59032 58392 59659 59020 58393 58393 59021 59659 58393 59019 59021 58394 59036 59661 59665 59036 58394 58394 59653 59665 58394 58395 59653 58395 59013 60344 60932 59653 58395 58395 60343 60932 60344 60343 58395 59662 59017 58397 58397 59023 59662 58397 59022 59023 58398 58399 59018 59663 59018 58399 58399 59026 59663 58399 59025 59026 59036 58401 58400 59661 59036 58400 59037 59027 58401 58401 59036 59037 60374 58403 58402 58402 60372 60374 58402 59670 60372 59679 59038 58403 60375 59679 58403 58403 60374 60375 59034 58405 58404 59034 59025 58405 58406 58407 59046 59047 59046 58407 58407 59032 59047 58408 58411 59039 58409 58422 59042 59042 58410 58409 59675 58412 58410 58410 59042 59675 58411 58412 59039 59040 59039 58412 59675 59040 58412 58415 58414 58413 59035 59034 58413 58413 58414 59035 58414 59043 60381 58414 58415 59043 59667 59035 58414 60381 59667 58414 59045 59043 58415 59053 58417 58416 58416 58418 59053 59701 59053 58418 58418 59697 59701 58418 59696 59697 58418 59052 59696 58421 58420 58419 59682 58421 58419 58419 59679 59682 58419 59038 59679 58419 58420 59038 58421 59682 59693 58422 59041 59681 59681 59042 58422 58423 58425 58443 59709 59702 58423 59710 59709 58423 58423 58443 59710 59056 58426 58424 59056 58427 58426 58427 59056 59057 58428 58429 59051 59059 59051 58429 59073 59059 58429 58429 59065 59073 58429 58430 59065 58430 58437 59065 59705 59061 58431 58431 58432 59705 58432 59701 59705 58432 59053 59701 59066 58434 58433 59075 59066 58433 58433 58441 59075 58446 58443 58435 58451 58446 58435 58436 59064 59071 59074 59065 58437 58437 58459 59074 58437 58454 58459 58455 58454 58437 58440 58439 58438 59085 58441 58439 58439 58440 59085 59727 59085 58440 58440 59716 59727 59725 59716 58440 58440 59723 59725 58440 59060 59723 59085 59075 58441 58450 58448 58442 59068 58450 58442 58442 59067 59068 58443 59062 59710 59063 59062 58443 58443 58444 59063 58445 58444 58443 58446 58445 58443 59070 59063 58444 58444 59069 59070 58444 58445 59069 59076 59069 58445 58445 58452 59076 58445 58446 58452 58446 58451 58452 58447 58453 59082 59719 59086 58448 58448 58449 59719 58450 58449 58448 60405 59719 58449 58449 58450 60405 58450 59068 60405 58464 58452 58451 59089 59076 58452 59100 59089 58452 58452 59098 59100 58452 58464 59098 59091 59082 58453 58453 59064 59091 59071 59064 58453 58462 58459 58454 58454 58455 58462 59107 58469 58456 60434 59107 58456 58456 58457 60434 58458 58457 58456 58469 58458 58456 60435 60434 58457 61005 60435 58457 58457 61003 61005 58457 59740 61003 58457 58458 59740 58458 59731 59740 58459 58460 59083 58461 58460 58459 58463 58461 58459 58459 58462 58463 59083 59074 58459 59092 59083 58460 59093 59092 58460 58460 58461 59093 59101 59093 58461 58461 58471 59101 58461 58465 58471 58461 58463 58465 58465 58463 58462 58466 58465 58462 58469 58466 58462 59099 59098 58464 58464 58468 59099 58465 58470 58471 58465 58466 58470 59103 58470 58466 58466 58475 59103 58466 58474 58475 58466 58469 58474 59096 59095 58467 58467 59086 59096 59107 58474 58469 59103 58471 58470 59103 59101 58471 59104 58476 58472 59105 59104 58472 58472 58473 59105 59106 59105 58473 59749 58475 58474 59757 59749 58474 58474 59756 59757 58474 59747 59756 58474 59107 59747 59749 59103 58475 58476 59104 59110 59114 58481 58478 59115 59114 58478 59758 59115 58478 58478 59112 59758 58478 58479 59112 58480 58479 58478 58479 59111 59112 58479 58480 59111 58480 58487 59111 58481 59114 59116 59767 59766 58482 58482 58483 59767 59768 59767 58483 58483 58484 59768 58485 58489 59131 58485 58486 58489 59770 59123 58485 58485 59131 59770 58489 59130 59131 58489 58511 59130 58523 58496 58490 59127 58523 58490 58490 58491 59127 58492 58491 58490 58496 58492 58490 58491 58492 58494 59128 59127 58491 58491 59124 59128 59773 59124 58491 58491 59133 59773 58491 58493 59133 58494 58493 58491 58492 58495 59764 58496 58495 58492 59764 58494 58492 59777 59133 58493 58493 59135 59777 58493 58512 59135 58493 58494 58512 59764 58512 58494 58495 58496 58513 58495 58512 59764 58522 58513 58496 58523 58522 58496 59136 58503 58497 58497 58498 59136 61055 60457 58499 61572 61055 58499 58499 60454 61572 58499 60453 60454 58500 59138 60453 59139 59138 58500 59794 59149 58501 58502 59136 59148 58502 58503 59136 58506 58505 58504 58505 58506 59786 59786 59783 58505 59787 59786 58506 58506 58515 59787 58506 58514 58515 59795 59146 58507 58507 59169 59795 59151 58521 58508 58508 58519 59151 59130 58511 58509 59131 59130 58509 59770 59131 58509 58509 59153 59770 58509 58510 59153 59804 59153 58510 58510 58521 59804 58512 59134 59135 58513 58522 58525 58516 58515 58514 58518 58516 58514 58515 58516 59787 59792 59787 58516 58516 58517 59792 58518 58517 58516 59793 59792 58517 59800 59793 58517 59796 59151 58519 58519 59150 59796 58519 59147 59150 58521 59156 59804 58521 59151 59156 59805 58525 58522 58522 59799 59805 58522 59142 59799 58522 58523 59142 58523 59127 59142 59165 59158 58525 59805 59165 58525 58526 58528 59161 58526 58527 58528 59809 58528 58527 58527 59159 59809 60469 59161 58528 58528 59811 60469 58528 59809 59811 59164 58534 58529 58529 59160 59164 58530 58535 58536 58537 58535 58530 58540 58537 58530 59178 58533 58531 60495 59178 58531 58531 59839 60495 58531 58532 59839 58533 58532 58531 60496 59839 58532 58532 59174 60496 58532 58533 59174 59178 58538 58533 59180 59174 58533 58535 59176 59817 58535 59171 59176 58535 58537 59171 59817 58536 58535 59817 59154 58536 58537 58540 58541 59173 59171 58537 58537 58541 59173 59178 59172 58538 58545 58542 58539 58541 58548 59173 59181 58543 58542 58542 58545 59181 60501 58544 58543 58543 59840 60501 58543 59181 59840 60500 59179 58544 60501 60500 58544 59182 59181 58545 58545 58546 59182 59183 59182 58546 58546 58547 59183 59184 59183 58547 58549 58550 58554 59842 58554 58550 58550 59833 59842 58551 59190 59196 58551 58552 59190 59851 59190 58552 58552 59188 59851 59186 59184 58553 58553 58555 59186 59842 59189 58554 60524 59867 58556 58556 60514 60524 58556 58558 60514 58556 58557 58558 58558 59192 60514 58562 58571 59863 59863 58563 58562 58563 59849 59850 59863 59849 58563 59204 58567 58564 59205 58566 58565 59206 59205 58565 58565 59202 59206 58567 59204 59207 59220 59218 58569 59891 59220 58569 58569 59217 59891 60526 60525 58570 60537 60526 58570 58570 59221 60537 59881 59221 58570 58571 59215 59863 58571 58572 59215 60541 59215 58572 58572 60527 60541 58572 59884 60527 59231 59224 58573 59888 59231 58573 58573 58574 59888 58574 59216 59888 58574 58575 59216 58577 58578 59213 59887 59213 58578 58578 59235 59887 59236 59235 58578 58578 58579 59236 60566 59236 58579 58579 59915 60566 58579 59893 59915 58579 59233 59893 58579 58580 59233 59225 58582 58581 59897 59225 58581 59898 59897 58581 58581 59234 59898 58581 59232 59234 59225 58584 58582 60559 59900 58583 58583 59899 60559 58583 59225 59899 58583 58584 59225 59234 59232 58587 59911 59910 58589 58589 59906 59911 58592 58591 58590 58597 58592 58590 58592 58597 59241 59238 58594 58593 59239 59238 58593 59238 58596 58594 59243 59242 58595 58595 58600 59243 59245 58612 58596 58596 59238 59245 59251 59241 58597 58597 59250 59251 59919 59250 58597 58597 59912 59919 58597 59240 59912 58598 59241 59251 59247 59243 58600 58600 58604 59247 58601 58602 59248 58603 58602 58601 59918 59248 58602 59929 59918 58602 58602 58603 59929 58603 58614 59929 58603 58613 58614 59923 59247 58604 58604 59253 59923 58604 58605 59253 59925 59256 58608 58608 58609 59925 59927 59925 58609 59932 59927 58609 58609 58610 59932 58612 58610 58609 60587 59932 58610 58610 59933 60587 58610 58611 59933 58612 58611 58610 58611 59244 59933 58611 58612 59244 59245 59244 58612 58614 59928 59929 58615 58618 58624 58616 58617 59257 58618 58619 59260 59260 58624 58618 58619 58637 59260 59269 58625 58620 59958 59269 58620 58620 59947 59958 58620 59946 59947 58620 59265 59946 60599 58636 58621 58621 59964 60599 58621 58622 59964 58623 58622 58621 58622 58623 58631 58622 59271 59964 58622 58631 59271 59260 59259 58624 59275 59274 58626 58639 58638 58627 59261 58639 58627 58641 58640 58628 59957 58641 58628 58628 58645 59957 59270 58633 58630 58630 58650 59270 58630 58647 58650 59963 59271 58631 58631 58635 59963 58631 58632 58635 59962 58635 58632 60597 59962 58632 58632 58634 60597 59960 58634 58633 58633 59270 59960 60612 60597 58634 58634 59973 60612 58634 59960 59973 58635 59961 59963 59962 59961 58635 58636 59272 59928 59273 59272 58636 60599 59273 58636 59277 59260 58637 58638 58644 59279 58638 58639 58644 59266 58644 58639 58639 59261 59266 58640 58641 59253 59267 59253 58641 59957 59267 58641 60614 58646 58642 58642 59981 60614 58642 59281 59981 58642 59280 59281 59968 59277 58643 59988 59968 58643 58643 59307 59988 58643 59298 59307 59288 59279 58644 58644 59266 59288 59978 59957 58645 59991 59978 58645 58645 59289 59991 59980 59292 58646 60614 59980 58646 59295 58650 58647 58647 58648 59295 58649 58648 58647 58655 58649 58647 58648 58649 60619 60620 59295 58648 58648 60619 60620 58649 59293 60619 59294 59293 58649 58649 58655 59294 59960 59270 58650 58650 59295 59960 59993 59296 58651 58651 59975 59993 58651 59279 59975 58676 58661 58653 59994 58676 58653 58653 58654 59994 60625 59994 58654 58654 60618 60625 58655 58658 59294 60013 59298 58656 58656 59329 60013 58657 59299 59310 59297 59294 58658 59992 58660 58659 58659 59986 59992 59306 58670 58660 58660 59303 59306 59992 59303 58660 58661 58676 58677 58662 58678 59313 60631 59302 58663 60640 60631 58663 58663 60639 60640 58663 58664 60639 59302 59297 58663 58664 60628 60639 58664 59314 60628 59331 59330 58665 58665 59316 59331 58669 58667 58666 59334 59318 58667 58667 58669 59334 59318 58668 58667 60009 60008 58668 58668 59335 60009 58668 59318 59335 58669 58696 59334 58669 58679 58696 59306 58681 58670 58672 58671 58670 58681 58672 58670 58673 58686 58688 58687 58686 58673 58673 58683 58687 58688 58674 58673 58688 58675 58674 58675 59291 59312 59322 59291 58675 58675 58688 59322 59323 58677 58676 60000 59323 58676 58676 59994 60000 58677 59323 59324 59324 58699 58677 59325 59313 58678 58679 58680 58696 59342 58696 58680 58680 59341 59342 58680 58695 59341 58681 59306 59319 58681 59319 59328 59310 58687 58683 59326 59325 58684 60016 59326 58684 60017 60016 58684 58684 58685 60017 58685 58691 60017 58689 58688 58686 59348 58689 58686 58686 58687 59348 60014 59348 58687 58687 59310 60014 59338 59322 58688 60015 59338 58688 58688 58689 60015 60036 60015 58689 58689 59348 60036 60037 60017 58691 58691 59352 60037 58691 59351 59352 59356 58693 58692 58692 59340 59356 59357 58701 58693 58693 59356 59357 59360 58695 58694 60046 59360 58694 58694 58703 60046 59360 59341 58695 59342 59334 58696 58697 58704 59346 60051 59361 58698 58698 58699 60051 58699 60000 60051 58699 59324 60000 58709 58706 58700 58700 58708 58709 58700 58701 58708 58701 58707 58708 59358 58707 58701 58701 59357 59358 58702 59328 59345 58703 59370 60046 58703 58710 59370 59347 59346 58704 60034 59347 58704 58704 58705 60034 60676 60034 58705 58705 59363 60676 58706 58709 59384 58707 59359 59362 58707 59358 59359 58709 58708 58707 59369 58709 58707 58707 59362 59369 60064 59384 58709 58709 60059 60064 58709 59369 60059 59374 59370 58710 58710 58713 59374 60062 59376 58711 58712 59371 59372 59395 59371 58712 58714 58715 59391 59392 59391 58715 58715 59382 59392 58715 58716 59382 59383 59382 58716 58717 59385 59386 58717 58718 58726 58719 58718 58717 59386 58719 58717 59400 58726 58718 60081 59400 58718 58718 58719 60081 60702 60081 58719 58719 59386 60702 59389 59388 58720 59390 59389 58720 58721 58727 59398 58722 59399 59403 58722 59391 59399 59405 58725 58724 58724 59400 59405 58724 58726 59400 59405 58745 58725 59401 59398 58727 58727 58731 59401 58762 58742 58728 58728 58740 58762 58742 58741 58728 60088 60080 58730 58730 59408 60088 59421 58757 58732 58732 58733 59421 59422 59421 58733 58733 59403 59422 58747 58736 58734 58734 58735 58747 60093 58747 58735 60094 60093 58735 58735 60092 60094 58735 59410 60092 58747 58739 58736 58736 58739 59411 59431 59411 58737 60722 59431 58737 58737 58738 60722 58739 58738 58737 59411 58739 58737 58738 60093 60714 58738 58747 60093 58738 58739 58747 60738 60722 58738 58738 60714 60738 58740 58761 58762 60087 59408 58741 58741 59428 60087 58741 58742 59428 58742 58761 59428 58762 58761 58742 60104 59423 58743 58743 58746 60104 58743 58744 58746 58745 58744 58743 60709 58746 58744 58744 59409 60709 58744 58745 59409 58745 59405 59409 60709 60104 58746 59415 59413 58748 58748 58759 59415 58749 58750 58752 58751 58750 58749 59418 58751 58749 58749 58752 59418 59415 58759 58750 59417 59415 58750 58750 59416 59417 58750 58751 59416 59418 59416 58751 58752 58753 59418 60096 59418 58753 60109 60096 58753 58753 58767 60109 59425 58767 58753 59419 58755 58754 58754 58758 59419 59426 58760 58755 59427 59426 58755 58755 59419 59427 59420 58758 58756 60099 59420 58756 58756 58757 60099 60100 60099 58757 60114 60100 58757 58757 59421 60114 59420 59419 58758 59426 58763 58760 58761 58764 59428 58763 58778 58781 59426 58778 58763 59429 59428 58764 58765 59430 59436 58765 58766 59430 60121 60109 58767 58767 59438 60121 58767 58777 59438 59444 58770 58768 58768 59442 59444 58768 58769 59442 59443 59442 58769 58769 58781 59443 59444 59432 58770 58773 58772 58771 60129 58773 58771 58771 58774 60129 60763 60116 58772 58772 58773 60763 58773 60762 60763 61312 60762 58773 61313 61312 58773 58773 60766 61313 58773 60129 60766 58774 59448 60129 59449 59448 58774 58774 58775 59449 58775 59434 59449 58775 58776 59434 59441 58781 58778 60126 59441 58778 58778 58779 60126 58780 58779 58778 59426 58780 58778 60750 60126 58779 60751 60750 58779 58779 60742 60751 58779 58780 60742 58780 60111 60742 58780 59439 60111 59440 59439 58780 58780 59426 59440 58781 59441 59443 60134 59435 58782 58782 60120 60134 58782 59437 60120 58782 59436 59437 59451 58784 58783 58783 59450 59451 58783 58790 59450 59452 58785 58784 58784 59451 59452 60121 59438 58786 60137 60121 58786 60769 60137 58786 58786 60140 60769 58786 59452 60140 58787 59445 59446 58788 58789 59454 58789 58796 59454 60758 59453 58791 60759 60758 58791 58791 60757 60759 58791 59447 60757 58792 58803 58804 58792 58793 58803 58793 58802 58803 59460 58802 58793 60147 58796 58794 58794 60142 60147 58794 60141 60142 58794 59470 60141 58794 58795 59470 58796 58795 58794 59479 59470 58795 60768 59454 58796 58796 60147 60768 58797 58798 58799 59458 58799 58798 59458 58800 58799 58800 59455 59459 59458 59455 58800 58801 59455 60144 58801 58802 59455 58803 58802 58801 59462 58803 58801 58801 59461 59462 61329 59461 58801 58801 61328 61329 58801 60144 61328 59459 59455 58802 59460 59459 58802 59477 58804 58803 60146 59477 58803 58803 59462 60146 59477 58807 58804 60149 59468 58805 58805 58814 60149 58806 58807 59477 59476 58816 58806 59477 59476 58806 58808 58809 58817 58810 58809 58808 58811 58810 58808 58817 58811 58808 59464 58817 58809 59466 59464 58809 58809 58810 59466 59467 59466 58810 58810 58820 59467 58810 58811 58820 58811 58819 58820 58811 58818 58819 58811 58817 58818 59483 59482 58812 58812 59475 59483 58812 58813 59475 60151 59475 58813 58813 60149 60151 58813 59468 60149 60794 60149 58814 58814 59484 60794 60152 59484 58815 58815 59495 60152 59476 58822 58816 58817 59464 59489 58830 58818 58817 59492 58830 58817 58817 59489 59492 58823 58819 58818 58824 58823 58818 58830 58824 58818 59481 58820 58819 58819 58823 59481 59474 59467 58820 59481 59474 58820 58821 60792 60795 58821 58822 60792 58822 59476 60792 59517 59481 58823 58823 58832 59517 58823 58824 58832 58833 58832 58824 58824 58831 58833 58824 58830 58831 58825 59494 59503 58825 59482 59494 58826 59487 59495 59496 59487 58826 58827 58829 59505 58827 58828 58829 59514 59505 58829 59520 59514 58829 59480 58831 58830 59492 59480 58830 58838 58833 58831 59491 58838 58831 58831 59480 59491 58832 58839 59517 58832 58833 58839 58840 58839 58833 58833 58838 58840 59504 59496 58834 59519 59504 58834 58836 58845 59521 58846 58845 58836 58836 58837 58846 59507 58846 58837 58857 58840 58838 59491 58857 58838 59531 59517 58839 58839 58850 59531 58858 58850 58839 58839 58840 58858 58840 58856 58858 58857 58856 58840 60181 59518 58841 58841 60180 60181 58841 60176 60180 58841 58842 60176 58842 59511 60176 58842 59503 59511 59524 59519 58843 58843 58851 59524 58844 59515 59525 58844 59506 59515 59528 59521 58845 60171 59528 58845 58845 60170 60171 58845 58846 60170 58846 59507 60170 58847 58848 58850 58849 58848 58847 58871 58849 58847 58847 58865 58871 58847 58864 58865 58847 58858 58864 58847 58850 58858 58848 58849 58859 58859 58850 58848 58866 58860 58849 58871 58866 58849 58860 58859 58849 58850 58859 59531 59532 59524 58851 59534 58869 58854 58854 59526 59534 58854 58855 59526 59527 59526 58855 58855 59521 59527 58864 58858 58856 59530 58864 58856 58856 59529 59530 58856 59523 59529 58856 58857 59523 58857 59522 59523 58857 59491 59522 60186 59531 58859 60190 60186 58859 60813 60190 58859 58859 58860 60813 60204 60203 58860 58860 59538 60204 58860 58872 59538 58860 58866 58872 58860 60203 60813 58861 58875 59543 58862 59525 59533 59509 59508 58863 59523 59509 58863 60172 59523 58863 58876 58865 58864 59530 58876 58864 58876 58871 58865 59538 58872 58866 58866 58879 59538 58866 58878 58879 58866 58871 58878 59541 58884 58867 58867 58868 59541 58868 59518 59541 60198 58888 58869 60208 60198 58869 60825 60208 58869 58869 60818 60825 60819 60818 58869 58869 59534 60819 58893 58878 58871 58871 58877 58893 58871 58876 58877 60205 58881 58873 58873 60199 60205 59544 58875 58874 59544 59543 58875 58898 58877 58876 59537 58898 58876 58876 59536 59537 58876 59530 59536 58877 58892 58893 58898 58892 58877 58880 58879 58878 58894 58880 58878 58878 58893 58894 60204 59538 58879 58879 59548 60204 58879 58880 59548 58880 58900 59548 58880 58894 58900 60205 58882 58881 58882 60205 60210 60210 59549 58882 59552 59544 58883 60206 59546 58884 58884 59545 60206 58884 59541 59545 58896 58887 58885 59550 58896 58885 58886 58896 58897 58886 58887 58896 58888 60198 60207 60207 58889 58888 60218 59554 58889 60219 60218 58889 58889 60207 60219 58890 59537 59540 58890 58898 59537 58890 58891 58898 58891 58892 58898 58895 58893 58892 58899 58895 58892 58895 58894 58893 58894 58895 58900 58901 58900 58895 58895 58899 58901 58896 60215 60216 58896 59550 60215 60216 58897 58896 60235 60225 58897 60839 60235 58897 58897 60216 60839 59559 58901 58899 58899 59557 59559 58899 59556 59557 58899 58905 59556 60220 59548 58900 60226 60220 58900 58900 58902 60226 58900 58901 58902 58903 58902 58901 59559 58903 58901 58902 58903 60226 60229 60226 58903 58903 59559 60229 59551 58908 58904 58904 59549 59551 58905 58912 59556 58908 58907 58906 59567 58913 58907 60244 59567 58907 58907 58908 60244 60854 60244 58908 58908 60241 60854 60242 60241 58908 58908 59551 60242 60222 59552 58909 58909 59562 60222 58910 60227 60236 58910 58911 60227 60235 60227 58911 58911 60225 60235 59560 59556 58912 59563 59560 58912 60855 59562 58914 58914 58915 60855 61395 60855 58915 61402 61395 58915 58915 60857 61402 58915 58917 60857 58916 58919 58920 59577 58919 58916 60249 59577 58916 58916 59573 60249 58916 58921 59573 58917 58925 60857 58917 58918 58925 59574 58925 58918 59568 58920 58919 59576 59568 58919 59577 59576 58919 59568 59563 58920 58921 59566 59573 58921 59565 59566 59575 59574 58922 58924 58925 59574 58924 59574 59575 58925 60856 60857 58925 60233 60856 60236 60233 58925 58931 58932 58934 58933 58932 58931 59586 58934 58932 60263 59586 58932 58932 58933 60263 60869 60263 58933 58933 60260 60869 59586 58935 58934 59580 58936 58935 59586 59580 58935 59584 59579 58937 59590 58941 58939 58939 58943 59590 58939 58940 58943 58940 58942 58943 59590 59587 58941 60874 59590 58943 60878 60874 58943 58943 60272 60878 58948 58947 58944 58944 58945 58948 60271 58948 58945 58945 59589 60271 58947 58948 58951 59592 58951 58948 60273 59592 58948 58948 60271 60273 58950 59592 59604 58950 58951 59592 59593 58953 58952 60897 59593 58952 58956 58955 58954 59601 58956 58954 59605 59601 58954 58954 58957 59605 58955 58958 59607 58955 58956 58958 58963 58959 58955 59607 58963 58955 59600 58958 58956 59601 59600 58956 58957 59594 59605 59608 59607 58958 60299 59608 58958 58958 60287 60299 58958 59600 60287 58963 58962 58959 58960 60901 62024 60902 60901 58960 61453 60902 58960 58960 58961 61453 62024 60301 58960 58961 60312 61453 58962 58963 59607 59609 58964 58962 58962 59607 59609 59609 58969 58964 58965 58980 59614 59615 58967 58966 58966 59614 59615 58967 59615 59616 58968 58970 58971 58968 58969 58970 59623 58970 58969 60302 59623 58969 58969 59609 60302 58978 58971 58970 58979 58978 58970 59624 58979 58970 58970 59621 59624 59623 59621 58970 58987 58986 58971 58971 58978 58987 60907 60312 58972 58972 60313 60907 58972 58973 60313 58974 58973 58972 58973 58976 60313 58975 59625 59627 58975 58983 59625 59627 58977 58975 58976 59628 60313 58976 59627 59628 58976 58977 59627 58978 58979 58987 59624 58991 58979 59615 59614 58980 58980 58982 59615 59630 58982 58981 60319 59630 58981 60327 60319 58981 58981 59635 60327 58981 58994 59635 59616 59615 58982 59619 59616 58982 60308 59619 58982 60311 60308 58982 58982 59630 60311 58983 58985 59625 59626 59625 58985 58985 59003 59626 59632 58989 58988 60310 59632 58988 58988 59629 60310 58988 58991 59629 59632 58992 58989 59639 59000 58990 58990 59636 59639 58991 59621 59629 59624 59621 58991 58992 58996 58997 59632 58996 58992 58993 59004 59635 59635 58994 58993 59640 59003 58995 58995 59002 59640 59634 59633 58996 58996 59632 59634 58998 58997 58996 59633 58998 58996 60930 59650 58997 58997 60331 60930 58997 58998 60331 60336 60331 58998 60921 60336 58998 60931 60921 58998 58998 60323 60931 60325 60323 58998 58998 59633 60325 59641 59006 58999 58999 59000 59641 59000 59639 59641 60328 59002 59001 59001 59642 60328 60328 59640 59002 60320 59626 59003 59003 59640 60320 60326 59635 59004 60330 60326 59004 59004 59647 60330 59004 59005 59647 59652 59647 59005 59005 59651 59652 59006 59641 59643 60345 59008 59006 59006 59643 60345 59007 59008 59654 60345 59654 59008 60920 59642 59009 59009 60332 60920 59009 59010 60332 59645 59644 59010 59010 59644 60332 60348 59016 59011 60349 60348 59011 59011 59012 60349 59012 60341 60349 59012 59648 60341 59013 59654 60344 59645 59015 59014 59662 59645 59014 59014 59017 59662 60348 59655 59016 59664 59019 59018 59018 59663 59664 59664 59021 59019 59021 59657 59658 60353 59657 59021 59021 59664 60353 59660 59659 59021 59021 59658 59660 59671 59031 59022 59024 59023 59022 59031 59024 59022 60352 59662 59023 59023 59024 60352 60950 60352 59024 59024 60362 60950 60363 60362 59024 59024 59031 60363 59035 59026 59025 59025 59034 59035 60361 59663 59026 60366 60361 59026 59026 59666 60366 59026 59035 59666 59673 59028 59027 59674 59673 59027 59027 59672 59674 59027 59037 59672 59673 59029 59028 59668 59030 59029 59673 59668 59029 60961 60370 59030 59030 60368 60961 59030 59668 60368 59031 59671 60364 60364 60363 59031 60365 59047 59032 59032 59033 60365 59667 59666 59035 59672 59037 59036 60369 59672 59036 59036 59665 60369 60373 59671 59040 60376 60373 59040 59040 59675 60376 59678 59675 59042 59680 59678 59042 59681 59680 59042 59043 60380 60381 59043 59045 60380 59044 59686 60383 59044 59048 59686 60380 59045 59044 60382 60380 59044 60383 60382 59044 59684 59683 59046 60387 59684 59046 59046 59047 60387 60969 60387 59047 60970 60969 59047 61502 60970 59047 59047 60365 61502 59048 59050 59686 59048 59049 59050 59051 59050 59049 59688 59686 59050 59699 59688 59050 59050 59051 59699 59051 59694 59699 59051 59059 59694 59052 59689 59696 59052 59054 59689 59691 59689 59054 59683 59056 59055 59056 59683 59684 59058 59057 59056 59685 59058 59056 59056 59684 59685 59711 59064 59057 59712 59711 59057 59057 59058 59712 59058 59703 59712 59704 59703 59058 60388 59704 59058 59058 59685 60388 59695 59694 59059 60402 59695 59059 59059 59073 60402 59724 59723 59060 59060 59705 59724 59060 59061 59705 60398 59710 59062 59062 59063 60398 59063 59713 60398 59063 59070 59713 59711 59091 59064 59065 59072 59073 59074 59072 59065 59718 59067 59066 59066 59075 59718 59718 59068 59067 59068 60404 60405 59068 59718 60404 59077 59070 59069 59079 59077 59069 59087 59079 59069 59069 59076 59087 59070 59077 59713 60402 59073 59072 60403 60402 59072 59072 59714 60403 59072 59074 59714 59074 59084 59714 59074 59083 59084 59075 59717 59718 59727 59717 59075 59075 59085 59727 59089 59087 59076 59077 59078 59713 59079 59078 59077 60992 59713 59078 60993 60992 59078 59078 59081 60993 59078 59079 59081 59079 59080 59081 59090 59080 59079 59079 59088 59090 59079 59087 59088 59729 59081 59080 59738 59729 59080 59080 59090 59738 60996 60993 59081 59081 60430 60996 61001 60430 59081 59081 59739 61001 59081 59729 59739 59082 59091 59731 59092 59084 59083 60403 59714 59084 59084 59092 60403 59728 59096 59086 59086 59719 59728 59089 59088 59087 59738 59090 59088 59088 59089 59738 59744 59738 59089 59089 59742 59744 59089 59100 59742 59091 59730 59731 60399 59730 59091 59091 59711 60399 59092 59720 60403 59092 59094 59720 59092 59093 59094 59093 59101 59748 59733 59094 59093 59734 59733 59093 59748 59734 59093 59094 59733 60419 60419 59720 59094 59095 59109 59110 59737 59109 59095 59095 59096 59737 59095 59105 59106 59110 59105 59095 59096 59735 59737 59096 59728 59735 59743 59742 59100 59745 59743 59100 59101 59103 59748 59118 59108 59102 59749 59748 59103 59104 59105 59110 59751 59747 59107 60436 59751 59107 59107 60434 60436 59108 60445 61022 59108 59117 60445 59118 59117 59108 59113 59111 59109 59737 59113 59109 59113 59112 59111 59112 59737 59758 59112 59113 59737 59129 59116 59114 59761 59129 59114 59114 59115 59761 59115 59760 59761 59115 59759 59760 60437 59759 59115 59115 59758 60437 59122 59121 59116 59129 59122 59116 61041 60445 59117 59117 61035 61041 59117 60448 61035 59117 59765 60448 59117 59119 59765 59117 59118 59119 59119 59120 59765 59766 59765 59120 59121 59788 59794 59121 59122 59788 60461 59788 59122 59122 59129 60461 60455 59769 59123 59123 59770 60455 59124 59125 59128 59126 59125 59124 59773 59126 59124 59125 59127 59128 59142 59127 59125 59125 59141 59142 59778 59141 59125 59125 59132 59778 59125 59126 59132 59772 59132 59126 60441 59772 59126 60446 60441 59126 59126 59763 60446 59773 59763 59126 61033 60461 59129 59129 59761 61033 59132 59771 59778 59772 59771 59132 59133 59763 59773 59133 59762 59763 59777 59762 59133 59148 59143 59134 59143 59135 59134 59135 59762 59777 59763 59762 59135 60452 59763 59135 61037 60452 59135 59135 60462 61037 59135 59143 60462 59136 59137 59148 59780 59148 59137 60454 60453 59138 59138 59139 60454 59139 59781 59782 59783 59781 59139 59139 59782 60454 60463 59789 59140 59140 59141 60463 59142 59141 59140 59789 59142 59140 59141 59791 60463 59141 59778 59791 59142 59789 59799 59143 59148 60462 59150 59147 59144 59152 59150 59144 59144 59145 59152 61064 59152 59145 59145 59146 61064 59146 59795 61064 61566 60462 59148 61580 61566 59148 59148 60458 61580 59148 59780 60458 59801 59155 59149 59149 59794 59801 59797 59796 59150 60466 59797 59150 59150 59152 60466 59157 59156 59151 59796 59157 59151 61068 60466 59152 59152 60477 61068 60478 60477 59152 61064 60478 59152 59153 59820 60489 59153 59804 59820 59798 59770 59153 60467 59798 59153 60479 60467 59153 60489 60479 59153 59154 59793 59800 60475 59793 59154 59154 59818 60475 59154 59817 59818 59155 60476 60484 59155 59801 60476 59820 59804 59156 60488 59820 59156 59156 59803 60488 59156 59157 59803 59157 59802 59803 60465 59802 59157 59157 59797 60465 59157 59796 59797 59158 59165 59166 59810 59809 59159 59160 59163 59164 59812 59163 59160 60469 59812 59161 62200 60471 59162 59162 61603 62200 59162 60469 61603 59162 59812 60469 59162 59163 59812 59164 59163 59162 59813 59164 59162 60471 59813 59162 60470 59827 59164 59164 59813 60470 59824 59166 59165 59165 59821 59824 59165 59808 59821 59165 59805 59808 59832 59168 59166 59166 59821 59832 59824 59821 59166 60487 59831 59169 59169 59829 60487 59169 59172 59829 59831 59795 59169 59834 59833 59170 59170 59816 59834 59825 59816 59170 59171 59175 59176 59171 59173 59175 59830 59829 59172 59835 59830 59172 59172 59178 59835 59174 59180 60496 59177 59176 59175 60482 59817 59176 59176 59177 60482 60494 60482 59177 60493 59835 59178 59178 60487 60493 60495 60487 59178 60499 59180 59179 61609 60499 59179 59179 60500 61609 60499 60496 59180 59181 59182 59840 59182 59185 59841 59182 59183 59185 59841 59840 59182 59183 59184 59185 59186 59185 59184 60503 59841 59185 59185 59844 60503 59185 59186 59844 59852 59844 59186 59186 59191 59852 59843 59188 59187 59855 59843 59187 59187 59850 59855 59188 59843 59851 59848 59195 59189 59189 59842 59848 59203 59196 59190 59851 59203 59190 59856 59852 59191 59865 59856 59191 61098 60514 59192 61099 61098 59192 59192 59194 61099 60509 59194 59193 59193 59857 60509 59193 59199 59857 59193 59197 59199 61630 61099 59194 59194 61100 61630 59194 60509 61100 59848 59201 59195 59203 59202 59196 59197 59198 59199 59200 59199 59198 59858 59200 59198 59859 59858 59198 59861 59859 59198 59198 59847 59861 59860 59847 59198 59198 59201 59860 59199 59200 59857 61090 59857 59200 59200 59858 61090 59201 59848 59860 59886 59206 59202 60516 59886 59202 59202 59203 60516 59203 60511 60516 59203 59851 60511 59217 59207 59204 59871 59216 59205 59205 59206 59871 59886 59871 59206 59870 59211 59208 59881 59870 59208 59208 59879 59881 59880 59879 59208 59208 59214 59880 59209 59210 59212 59211 59210 59209 59870 59212 59210 59210 59211 59870 59212 59870 59881 59874 59869 59213 59875 59874 59213 59887 59875 59213 60534 59880 59214 59214 59904 60534 59215 59862 59863 60518 59862 59215 60541 60518 59215 59889 59888 59216 59216 59871 59889 59217 59878 59891 59217 59867 59878 59219 59876 59877 59219 59220 59876 59877 59226 59219 59891 59876 59220 59221 59879 59880 59881 59879 59221 59221 60535 60537 59221 59222 60535 59223 59222 59221 60555 59223 59221 59221 59880 60555 60536 60535 59222 61119 60536 59222 59222 61115 61119 59222 59223 61115 61128 61115 59223 59223 60554 61128 60555 60554 59223 59895 59229 59224 59224 59231 59895 59225 59897 59899 59226 60531 60548 59226 59877 60531 60548 59228 59226 59905 59904 59227 59227 59901 59905 59227 59894 59901 59227 59228 59894 60547 59894 59228 60548 60547 59228 59895 59230 59229 59907 59906 59230 59230 59896 59907 59230 59895 59896 59896 59895 59231 59231 59892 59896 59231 59888 59892 59233 59237 59893 59235 59236 61139 59890 59887 59235 61126 59890 59235 61139 61126 59235 59236 61665 62270 59236 61145 61665 59236 60566 61145 59236 61137 61139 61138 61137 59236 62848 61138 59236 59236 62270 62848 59237 59252 59893 59237 59247 59252 59237 59243 59247 59237 59242 59243 59916 59245 59238 59238 59910 59916 59238 59239 59910 59913 59912 59240 59914 59913 59240 59240 59246 59914 59244 59916 59933 59244 59245 59916 59917 59914 59246 59246 59248 59917 59924 59252 59247 59247 59923 59924 59918 59917 59248 59258 59257 59249 59249 59250 59258 59919 59258 59250 59909 59893 59252 59938 59909 59252 59252 59924 59938 59940 59923 59253 60582 59940 59253 59253 59943 60582 59253 59267 59943 59254 59256 60583 59264 59255 59254 59931 59264 59254 60583 59931 59254 59946 59265 59255 59255 59945 59946 59255 59262 59945 59264 59262 59255 59256 59926 60584 59256 59925 59926 60584 60583 59256 59257 59258 59934 60578 59934 59258 59258 60571 60578 59258 59919 60571 59259 59260 59953 61156 60580 59259 59259 59941 61156 59942 59941 59259 59953 59942 59259 59260 59278 59953 59260 59277 59278 59288 59266 59261 59935 59288 59261 59937 59935 59261 61170 59945 59262 61701 61170 59262 59262 61166 61701 59262 59263 61166 59264 59263 59262 59263 59264 59931 61693 61166 59263 59263 59931 61693 59944 59943 59267 60595 59944 59267 59267 59957 60595 59952 59276 59268 59971 59280 59269 59269 59958 59971 60598 59964 59271 59271 59961 60598 59963 59961 59271 59930 59928 59272 60588 59930 59272 61165 60588 59272 59272 59273 61165 61695 61165 59273 59273 61172 61695 59273 59948 61172 59949 59948 59273 60599 59949 59273 59965 59282 59274 59274 59275 59965 59966 59965 59275 59276 59950 59967 59951 59950 59276 59952 59951 59276 59968 59278 59277 59968 59942 59278 59278 59942 59953 59279 59970 59975 59279 59969 59970 59279 59288 59969 59971 59281 59280 59982 59981 59281 59281 59972 59982 59281 59971 59972 59987 59974 59282 59282 59304 59987 61182 59304 59282 61183 61182 59282 59282 59965 61183 59283 59284 60622 59285 59284 59283 59975 59285 59283 59999 59975 59283 61195 59999 59283 59283 60622 61195 59284 59308 60623 59284 59285 59308 60623 60622 59284 59990 59308 59285 59285 59970 59990 59975 59970 59285 59286 59287 60564 59288 59287 59286 60594 59288 59286 59286 60564 60594 59287 59936 61143 59287 59935 59936 59287 59288 59935 61143 60564 59287 59989 59969 59288 60604 59989 59288 60606 60604 59288 59288 60593 60606 60594 60593 59288 60617 59991 59289 59289 59290 60617 59291 59290 59289 59312 59291 59289 59290 59322 59338 59290 59291 59322 59290 59301 60617 59290 59300 59301 59338 59300 59290 61188 60619 59293 59293 60631 61188 59293 59302 60631 59293 59294 59302 59294 59297 59302 59983 59960 59295 59985 59983 59295 60620 59985 59295 59311 59299 59296 59993 59311 59296 59309 59307 59298 60013 59309 59298 59311 59310 59299 61199 59301 59300 59300 60024 61199 59300 59338 60024 61728 60617 59301 61730 61728 59301 59301 61199 61730 59305 59304 59303 59992 59305 59303 59996 59306 59303 59303 59995 59996 60621 59995 59303 59303 59304 60621 59304 59305 59987 61182 60621 59304 59305 59986 59987 59992 59986 59305 59996 59319 59306 59990 59988 59307 59307 59308 59990 59309 59308 59307 59308 59309 60623 61192 60623 59309 59309 60634 61192 59309 60013 60634 59310 59320 60014 59321 59320 59310 59310 59311 59321 59993 59321 59311 59327 59315 59313 59313 59325 59327 59314 60001 60628 59314 59315 60001 59315 59327 60001 60018 59331 59316 60641 60018 59316 59316 59317 60641 60642 60641 59317 61202 60642 59317 59317 60003 61202 59318 59334 59335 59319 59996 60005 60005 59328 59319 59320 59348 60014 59349 59348 59320 60635 59349 59320 59320 59321 60635 59321 59993 59999 59321 59998 60635 59999 59998 59321 60000 59324 59323 60629 59327 59325 59325 59326 60629 60637 60629 59326 59326 60016 60637 60628 60001 59327 60629 60628 59327 60654 59345 59328 60655 60654 59328 59328 60633 60655 59328 60011 60633 59328 60005 60011 59329 60012 60013 60656 60012 59329 59329 59337 60656 59355 59340 59330 59330 59353 59355 59330 59332 59353 59330 59331 59332 59333 59332 59331 60018 59333 59331 59354 59353 59332 59332 59333 59354 60029 59354 59333 60032 60029 59333 60650 60032 59333 59333 60641 60650 59333 60018 60641 59336 59335 59334 60020 59336 59334 59334 60019 60020 60022 60019 59334 59334 59342 60022 60644 60009 59335 59335 59336 60644 61743 60644 59336 59336 61205 61743 59336 60645 61205 59336 60020 60645 59337 59346 60656 59338 60015 60024 59373 59368 59339 59339 59366 59373 59367 59366 59339 60055 59367 59339 59339 59365 60055 60662 59356 59340 59340 60043 60662 59340 60040 60043 59340 59355 60040 60022 59342 59341 60033 60022 59341 60047 60033 59341 59341 60045 60047 59341 59360 60045 61264 59345 59343 61763 61264 59343 62356 61763 59343 59343 59344 62356 59345 59344 59343 59344 61215 62356 61216 61215 59344 59344 61206 61216 59344 60655 61206 59344 60654 60655 59344 59345 60654 61264 61254 59345 61254 60062 59345 60666 60656 59346 59346 59347 60666 61236 60666 59347 59347 60034 61236 59348 60035 60036 59348 60023 60035 59348 59349 60023 60667 60023 59349 61218 60667 59349 59349 61213 61218 59349 60635 61213 59352 59351 59350 59366 59352 59350 59373 59366 59350 59350 59368 59373 60038 60037 59352 60678 60038 59352 59352 59366 60678 59353 59354 60029 60040 59355 59353 59353 60039 60040 59353 60029 60039 60044 59357 59356 60662 60044 59356 59359 59358 59357 60044 59359 59357 60044 59362 59359 60046 60045 59360 60054 59365 59361 59361 60051 60054 60056 59369 59362 60066 60056 59362 61225 60066 59362 59362 60671 61225 59362 60044 60671 61236 60676 59363 59363 61217 61236 61256 61217 59363 59363 61235 61256 59363 59364 61235 59364 61234 61235 59364 60052 61234 59365 60054 60055 60686 60678 59366 59366 59367 60686 61259 60686 59367 59367 60058 61259 59367 60055 60058 59369 60056 60059 60673 60046 59370 60690 60673 59370 60692 60690 59370 59370 59374 60692 60063 59377 59371 59371 59395 60063 59377 59372 59371 59372 59377 59378 59374 60067 60692 60072 59390 59375 60073 60072 59375 59375 59376 60073 59376 60062 60073 60679 60674 59377 60680 60679 59377 59377 60063 60680 60674 59378 59377 60675 60052 59378 59378 60674 60675 59399 59391 59379 59379 59380 59399 59381 59380 59379 60706 59381 59379 59379 60693 60706 59379 59382 60693 59392 59382 59379 59379 59391 59392 59404 59399 59380 59380 59381 59404 60706 59404 59381 59382 59383 60693 59383 59393 60693 59394 59393 59384 60064 59394 59384 60077 59386 59385 59385 59387 60077 60703 60702 59386 61272 60703 59386 59386 60077 61272 60078 60077 59387 59387 60068 60078 59387 59388 60068 60071 60068 59388 59388 59389 60071 59389 59390 60071 59390 60070 60071 61270 60070 59390 59390 60691 61270 59390 60072 60691 59393 59394 60693 61267 60693 59394 59394 60696 61267 60698 60696 59394 59394 60065 60698 59394 60064 60065 59395 60074 60076 60075 60074 59395 59395 59396 60075 59397 59396 59395 60076 60063 59395 60089 60075 59396 59396 60085 60089 60086 60085 59396 59396 59406 60086 59396 59398 59406 59396 59397 59398 59398 59402 59406 59398 59401 59402 59404 59403 59399 60082 59405 59400 59400 60081 60082 59407 59402 59401 59407 59406 59402 60090 59422 59403 59403 59404 60090 60103 60090 59404 60705 60103 59404 60706 60705 59404 60084 59409 59405 59405 60082 60084 60105 60086 59406 60106 60105 59406 60726 60106 59406 59406 60095 60726 59406 59414 60095 59406 59407 59414 59407 59413 59414 59408 60087 60088 59409 60084 60709 59410 60091 60092 59410 59423 60091 59431 59412 59411 59424 59414 59413 59413 59415 59424 59414 59424 60095 60095 59424 59415 59415 59417 60095 60098 59417 59416 59416 60097 60098 59416 60096 60097 59416 59418 60096 60107 60095 59417 59417 60098 60107 60113 59427 59419 60729 60113 59419 59419 59420 60729 60730 60729 59420 60732 60730 59420 59420 60099 60732 60733 60114 59421 59421 60101 60733 60102 60101 59421 59421 60090 60102 59421 59422 60090 60104 60091 59423 59426 59427 60113 60113 59440 59426 59428 59429 60087 59429 59433 60087 59437 59436 59430 59430 59431 59437 60120 59437 59431 60736 60120 59431 59431 60722 60736 59432 59444 60122 59433 60118 60119 61276 60087 59433 59433 60119 61276 60134 59449 59434 59434 59435 60134 59439 59440 60111 59440 60110 60111 60113 60110 59440 59441 60126 60750 60752 59443 59441 59441 60749 60752 60750 60749 59441 60754 59444 59442 59442 60753 60754 59442 59443 60753 59443 60752 60753 60127 60122 59444 60754 60127 59444 60128 59446 59445 59446 60128 60755 60743 59447 59446 60755 60743 59446 59447 60748 60757 59447 60747 60748 59447 60743 60747 60764 60129 59448 59448 59449 60764 59449 60130 60764 60132 60130 59449 60134 60132 59449 60136 59451 59450 59450 59454 60136 60135 59452 59451 60136 60135 59451 59452 60135 60140 59453 59457 59458 60758 59457 59453 60768 60136 59454 59457 59456 59455 59458 59457 59455 59455 59456 60144 59456 59457 60758 60145 60144 59456 60758 60145 59456 60783 60146 59461 61338 60783 59461 61885 61338 59461 61886 61885 59461 59461 61329 61886 60146 59462 59461 59498 59478 59463 59463 59497 59498 59464 59469 59489 59464 59465 59469 59466 59465 59464 59470 59469 59465 60141 59470 59465 59465 59472 60141 59465 59466 59472 59466 59467 59472 59467 59471 59472 60777 59471 59467 59467 59493 60777 59467 59474 59493 59479 59478 59469 59469 59470 59479 59490 59489 59469 59469 59478 59490 59473 59472 59471 60148 59473 59471 62512 60148 59471 59471 61348 62512 59471 61341 61348 59471 60775 61341 60777 60775 59471 59472 59473 60141 59473 60140 60141 60769 60140 59473 60772 60769 59473 59473 60148 60772 59474 59481 59493 60159 59483 59475 59475 60150 60159 60151 60150 59475 59476 60783 60792 59476 59477 60783 59477 60146 60783 59498 59490 59478 59522 59491 59480 59480 59510 59522 59480 59500 59510 59480 59492 59500 60796 59493 59481 59481 60173 60796 59481 59517 60173 59482 59483 59494 59502 59494 59483 60159 59502 59483 59484 60161 60794 59484 60152 60161 60152 59495 59485 60789 60152 59485 61340 60789 59485 59485 59486 61340 59487 59486 59485 59495 59487 59485 59486 59488 61340 59486 59487 59488 60153 59488 59487 59487 59496 60153 59488 60790 61340 60791 60790 59488 59488 60155 60791 59488 60154 60155 59488 60153 60154 59489 59490 59492 59500 59492 59490 59490 59498 59500 60796 60777 59493 59494 59501 59503 59502 59501 59494 59496 59513 60153 59496 59512 59513 59496 59504 59512 59499 59498 59497 59508 59499 59497 59510 59500 59498 59498 59499 59510 59499 59509 59510 59499 59508 59509 59511 59503 59501 60175 59511 59501 59501 59502 60175 59502 60166 60175 59502 60159 60166 59519 59512 59504 59515 59506 59505 59505 59514 59515 59507 60165 60170 59523 59522 59509 59522 59510 59509 59511 60175 60176 60167 59513 59512 60184 60167 59512 59512 59519 60184 60158 60157 59513 60169 60158 59513 60811 60169 59513 59513 60167 60811 60154 60153 59513 60157 60154 59513 59516 59515 59514 59520 59516 59514 59515 59516 59525 60179 59525 59516 60194 60179 59516 60807 60194 59516 59516 59520 60807 60806 60173 59517 59517 60185 60806 59517 59531 60185 60181 59541 59518 59519 59524 60184 59520 60188 60807 59528 59527 59521 60172 59529 59523 60187 60184 59524 59524 59532 60187 60192 59533 59525 60193 60192 59525 61373 60193 59525 59525 60177 61373 60179 60177 59525 59526 59527 59534 59527 59528 59534 60819 59534 59528 59528 60189 60819 59528 60171 60189 59535 59530 59529 60172 59535 59529 59530 59535 59536 60186 60185 59531 60809 60187 59532 59532 60192 60809 59532 59533 60192 59537 59536 59535 60823 60196 59539 59539 60200 60823 59539 59547 60200 60181 59545 59541 60211 59547 59542 60217 60211 59542 60205 60199 59543 60824 60205 59543 60828 60824 59543 60829 60828 59543 59543 60212 60829 59543 59544 60212 59544 59553 60212 59544 59552 59553 59545 60191 60815 59545 60181 60191 60822 60206 59545 59545 60815 60822 60213 59550 59546 59546 60206 60213 60211 60200 59547 60220 60204 59548 60209 59551 59549 60210 60209 59549 59550 60213 60215 59551 60209 60242 60221 59553 59552 60222 60221 59552 60830 60212 59553 60838 60830 59553 59553 60837 60838 59553 60221 60837 60218 59555 59554 60843 60217 59555 59555 60218 60843 59558 59557 59556 59561 59558 59556 59556 59560 59561 60230 59559 59557 59557 59558 60230 60237 60230 59558 59558 59561 60237 60230 60229 59559 59564 59561 59560 59560 59563 59564 59561 59564 60237 60232 60222 59562 60855 60232 59562 59568 59564 59563 60243 60237 59564 59564 59568 60243 59566 59569 59573 60240 60239 59567 60244 60240 59567 60245 60243 59568 59568 59576 60245 60247 59573 59569 60862 60247 59569 59572 59571 59570 60858 59572 59570 60859 60858 59570 59570 60853 60859 59570 60234 60853 59570 59571 60234 59571 59572 60863 59571 60233 60234 60856 60233 59571 60857 60856 59571 60863 60857 59571 61402 60863 59572 59572 61401 61402 61403 61401 59572 59572 60858 61403 60250 60249 59573 59573 60247 60250 60251 60245 59576 60252 60251 59576 59576 59577 60252 59577 60249 60252 60258 60254 59578 59578 60257 60258 59578 59579 60257 60262 60257 59579 59579 59585 60262 59579 59584 59585 59580 59586 59588 59591 59583 59581 60261 59591 59581 60866 60261 59581 61417 60866 59581 59581 61416 61417 59581 61415 61416 59581 59582 61415 59583 59582 59581 59582 60872 61415 59582 59583 60872 59583 59590 60872 59591 59590 59583 60261 59585 59584 59584 59587 60261 59585 60261 60262 60268 60267 59586 59586 60265 60268 60869 60265 59586 59586 60263 60869 60267 59588 59586 59587 59591 60261 59587 59590 59591 60267 59589 59588 59589 60268 60271 59589 60267 60268 60874 60872 59590 60293 59596 59592 59592 60273 60293 59592 59596 59604 61439 60892 59593 59593 60897 61439 60295 59605 59594 61431 60295 59594 59594 59595 61431 59596 59595 59594 59595 60293 61431 59595 59596 60293 59596 59603 59604 59597 59600 60294 59597 59598 59600 59599 59598 59597 60294 59599 59597 60287 59600 59598 60296 60287 59598 59598 60288 60296 59598 60278 60288 60289 60278 59598 59598 59599 60289 60294 60289 59599 59600 59601 60294 59601 60282 60294 60292 60282 59601 59601 59605 60292 59605 60281 60292 60891 60281 59605 59605 60889 60891 59605 60295 60889 61442 60897 59606 59606 60301 61442 59607 59608 60300 59610 59609 59607 60300 59610 59607 60305 60300 59608 59608 60299 60305 59609 59611 60302 59609 59610 59611 60300 59611 59610 59611 60303 61448 60305 60303 59611 59611 60300 60305 59611 59612 60302 59613 59612 59611 62619 59613 59611 59611 61448 62619 60306 60302 59612 60899 60306 59612 59612 59617 60899 59618 59617 59612 62621 59618 59612 62622 62621 59612 59612 59613 62622 59613 62619 62622 62023 60899 59617 62621 62023 59617 59617 59618 62621 59620 59621 59623 59622 59621 59620 60302 59622 59620 59620 59623 60302 59621 59622 59629 60306 59629 59622 59622 60302 60306 59625 59626 60316 60316 59627 59625 60320 60316 59626 60315 59628 59627 60316 60315 59627 60907 60313 59628 59628 60906 60907 61455 60906 59628 59628 60908 61455 60909 60908 59628 59628 60315 60909 59629 60309 60310 59629 60307 60309 59629 60306 60307 60915 60311 59630 59630 60319 60915 59637 59636 59631 59638 59637 59631 60317 59634 59632 59632 60310 60317 59633 60318 60325 59633 59634 60318 59634 60317 60318 59635 60326 60327 59641 59639 59636 59643 59641 59636 59636 59637 59643 60918 59643 59637 61471 60918 59637 59637 60321 61471 59637 59638 60321 60917 60321 59638 59638 60308 60917 60916 60320 59640 59640 60329 60916 59640 60328 60329 60920 60328 59642 60346 60345 59643 60923 60346 59643 59643 60918 60923 59644 60347 60934 59644 59645 60347 60934 60332 59644 59645 59662 60347 59649 59648 59646 59650 59649 59646 60340 60330 59647 59647 59652 60340 60342 60341 59648 59648 59649 60342 60929 60342 59649 60930 60929 59649 59649 59650 60930 59660 59652 59651 59651 59659 59660 60351 60340 59652 59652 59660 60351 60356 59665 59653 60357 60356 59653 60932 60357 59653 60345 60344 59654 60348 59656 59655 61498 60365 59656 59656 60359 61498 60360 60359 59656 59656 60348 60360 60355 59658 59657 60949 60355 59657 59657 60353 60949 60355 60350 59658 60351 59660 59658 59658 60350 60351 60358 60347 59662 59662 60352 60358 60354 59664 59663 60361 60354 59663 60354 60353 59664 60960 60369 59665 59665 60356 60960 60955 60366 59666 59666 59667 60955 59667 60381 60955 59668 60367 60368 59668 59674 60367 59668 59673 59674 60372 59670 59669 59669 60371 60372 60373 60364 59671 60369 59674 59672 60369 60367 59674 60965 60376 59675 59675 59676 60965 59677 59676 59675 59678 59677 59675 61505 60965 59676 61509 61505 59676 59676 59677 61509 59677 59678 60379 61510 61509 59677 59677 60379 61510 59678 59680 60377 59678 60377 60379 60375 59682 59679 60393 60378 59680 59680 59702 60393 59680 59681 59702 60378 60377 59680 60392 59693 59682 59682 60375 60392 60386 59685 59684 60387 60386 59684 60971 60388 59685 59685 60386 60971 59686 60384 60391 59686 59687 60384 59688 59687 59686 60391 60383 59686 59687 59688 59700 60385 60384 59687 59687 59700 60385 59688 59699 59700 59697 59696 59689 59708 59697 59689 60988 59708 59689 59689 60395 60988 59689 60394 60395 59689 59690 60394 59691 59690 59689 59690 60392 60982 59690 59692 60392 59690 59691 59692 61528 60394 59690 61529 61528 59690 59690 60982 61529 59692 59693 60392 59694 59698 59699 62105 59698 59694 59694 60983 62105 60984 60983 59694 61527 60984 59694 59694 59695 61527 59695 60412 61527 59695 60402 60412 59708 59701 59697 60977 60975 59698 60980 60977 59698 61526 60980 59698 62101 61526 59698 62105 62101 59698 59700 59699 59698 60975 59700 59698 60975 60385 59700 59708 59705 59701 59702 59709 60396 60978 60393 59702 60979 60978 59702 60985 60979 59702 60986 60985 59702 59702 60396 60986 60397 59712 59703 60401 60397 59703 59703 59704 60401 60987 60401 59704 61525 60987 59704 59704 60388 61525 60420 60415 59705 59705 59706 60420 59708 59706 59705 60415 59724 59705 61543 60420 59706 62120 61543 59706 59706 62110 62120 59706 61534 62110 59706 59707 61534 59708 59707 59706 59707 61531 61534 59707 60988 61531 59707 59708 60988 59709 59710 60396 60398 60396 59710 60401 60399 59711 59711 59712 60401 59712 60397 60401 60408 60398 59713 60992 60408 59713 59715 59716 59725 59717 59716 59715 61009 59717 59715 61010 61009 59715 59715 59725 61010 59716 59717 59727 60416 59718 59717 61000 60416 59717 61009 61000 59717 60416 60404 59718 59741 59728 59719 60405 59741 59719 59720 59721 60403 59722 59721 59720 61007 59722 59720 59720 60419 61007 59721 60402 60403 60999 60402 59721 59721 59722 60999 62122 60999 59722 62123 62122 59722 59722 61542 62123 59722 61007 61542 59726 59725 59723 59723 59724 59726 60415 59726 59724 59725 60422 61010 59725 60421 60422 59725 59726 60421 59726 60420 60421 59726 60415 60420 59754 59735 59728 59728 59741 59754 59729 59738 59739 60418 60417 59730 59730 60400 60418 59730 60399 60400 59732 59731 59730 60417 59732 59730 59731 59732 59740 60417 59740 59732 59733 59734 60419 59734 59753 60419 59734 59748 59753 59735 59736 59737 59754 59736 59735 59736 60425 60440 59736 59754 60425 59759 59737 59736 60440 59759 59736 60437 59758 59737 59737 59759 60437 61001 59739 59738 59738 60427 61001 59738 59744 60427 59740 61002 61003 59740 60417 61002 60413 59754 59741 59741 60407 60413 59741 60406 60407 59741 60405 60406 60426 59744 59742 60429 60426 59742 59742 59743 60429 59743 59745 60429 59744 60426 60427 61013 60429 59745 59745 60438 61013 59745 59746 60438 59746 59750 60438 59747 59755 59756 59747 59751 59755 59748 59752 59753 59748 59749 59752 60444 59752 59749 59749 59757 60444 61020 60438 59750 59750 61015 61020 61016 61015 59750 60436 59755 59751 61019 61018 59752 61025 61019 59752 59752 60442 61025 60444 60442 59752 61018 59753 59752 61007 60419 59753 61548 61007 59753 61551 61548 59753 59753 61018 61551 59754 60413 60425 60441 59756 59755 59755 59776 60441 60436 59776 59755 59756 60441 60444 60444 59757 59756 60439 59760 59759 60440 60439 59759 61027 59761 59760 59760 61026 61027 59760 61021 61026 59760 60439 61021 59761 61027 61033 60452 60446 59763 59765 60447 60448 59765 59766 60447 60449 60447 59766 59766 59767 60449 59767 59768 60449 60450 60449 59768 59768 59769 60450 60451 60450 59769 61042 60451 59769 59769 60455 61042 60456 60455 59770 59770 59798 60456 59779 59778 59771 59771 59772 59779 59772 59774 59779 59776 59774 59772 60441 59776 59772 59785 59779 59774 61036 59785 59774 59774 61024 61036 59774 59775 61024 59776 59775 59774 59775 61017 61024 59775 60436 61017 59775 59776 60436 59778 59790 59791 61053 59790 59778 59778 59784 61053 59785 59784 59778 59778 59779 59785 59780 60457 60458 61057 60459 59781 59781 59787 61057 59781 59786 59787 59781 59783 59786 60459 59782 59781 59782 60459 61573 61573 60454 59782 61054 61053 59784 59784 61036 61054 59784 59785 61036 59787 60464 61057 59787 59792 60464 61045 59794 59788 59788 60460 61045 60461 60460 59788 60463 59799 59789 61592 61059 59790 59790 61053 61592 61059 59791 59790 61058 60463 59791 61059 61058 59791 61060 60464 59792 59792 59793 61060 61061 61060 59793 59793 60475 61061 59819 59801 59794 61045 59819 59794 59795 59831 61064 60466 60465 59797 60468 60456 59798 61072 60468 59798 59798 60467 61072 59808 59805 59799 60463 59808 59799 60486 60476 59801 59801 59819 60486 59802 60465 60466 61075 59803 59802 59802 60466 61075 59803 61080 61611 59803 61075 61080 61076 60488 59803 61611 61076 59803 59821 59808 59806 62199 59821 59806 59806 62180 62199 59806 59807 62180 59808 59807 59806 59807 61595 62180 59807 61593 61595 59807 59808 61593 59808 61589 61593 59808 61058 61589 59808 60463 61058 60480 59811 59809 59809 59810 60480 59810 59822 60480 59832 59822 59810 61065 60469 59811 59811 60491 61065 59811 60480 60491 60481 60470 59813 59813 60471 60481 59814 61604 61607 59814 59815 61604 59816 59815 59814 61607 59816 59814 59815 60473 61604 59815 60472 60473 61074 60472 59815 59815 59827 61074 59815 59826 59827 59815 59816 59826 59816 59825 59826 61077 59834 59816 61607 61077 59816 60482 59818 59817 61067 60475 59818 61078 61067 59818 59818 61066 61078 59818 60482 61066 61608 60492 59819 62190 61608 59819 59819 61586 62190 59819 61574 61586 59819 61045 61574 60492 60486 59819 59820 60488 60489 59821 59822 59832 59823 59822 59821 62199 59823 59821 60490 60480 59822 59822 59823 60490 61605 60490 59823 61606 61605 59823 62207 61606 59823 62208 62207 59823 59823 62203 62208 59823 62202 62203 59823 62199 62202 59827 59826 59825 59827 60470 61074 59828 60483 60485 60484 60483 59828 59828 60485 60494 60493 60487 59829 59829 59830 60493 59830 59835 60493 59831 60487 61063 59831 60478 61064 61062 60478 59831 61063 61062 59831 59833 59836 59842 59837 59836 59833 59838 59837 59833 59833 59834 59838 61081 59838 59834 59834 61077 61081 59836 59837 60497 59848 59842 59836 59853 59848 59836 60497 59853 59836 59837 59838 61081 61081 60497 59837 59839 60477 61062 61068 60477 59839 61079 61068 59839 61609 61079 59839 59839 60496 61609 61612 60495 59839 59839 61062 61612 60502 60501 59840 59840 59841 60502 60503 60502 59841 61101 60511 59843 59843 60508 61101 59843 60498 60508 59843 59855 60498 60511 59851 59843 59844 59852 60504 60504 60503 59844 61092 59861 59845 62222 61092 59845 59845 61621 62222 61623 61621 59845 59845 59846 61623 59847 59846 59845 59861 59847 59845 59846 59854 61623 59846 59847 59854 59860 59854 59847 59848 59854 59860 59848 59853 59854 59855 59850 59849 60510 59855 59849 59849 59864 60510 59849 59863 59864 59852 59856 60513 60513 60504 59852 61093 59854 59853 61615 61093 59853 59853 60497 61615 59854 61622 61623 59854 61093 61622 60510 60498 59855 59856 59865 60513 60515 60509 59857 61090 60515 59857 61091 61090 59858 59858 59859 61091 61092 61091 59859 59859 59861 61092 59864 59863 59862 61094 59864 59862 59862 60517 61094 60518 60517 59862 61094 60510 59864 59865 60512 60513 59865 59866 60512 59866 59868 60512 59869 59868 59866 60524 59878 59867 59868 59869 60522 61108 60512 59868 61640 61108 59868 59868 61106 61640 59868 60522 61106 59874 59872 59869 59869 59872 60522 59871 59885 59889 59886 59885 59871 59874 59873 59872 60523 60522 59872 59872 60520 60523 59872 60519 60520 59872 59873 60519 59873 59875 61120 59873 59874 59875 61120 60519 59873 59875 60542 61120 59875 59887 60542 59891 59878 59876 59878 59877 59876 59877 59878 60531 60532 60531 59878 59878 60524 60532 59880 60533 60555 60534 60533 59880 60546 60540 59882 59882 60538 60546 59882 60525 60538 60527 59884 59883 61117 60527 59883 59883 60540 61117 60528 59889 59885 60529 60528 59885 61102 60529 59885 59885 59886 61102 59886 60516 61102 59887 59890 60542 60549 59892 59888 59888 59889 60549 61122 60549 59889 61650 61122 59889 59889 60528 61650 61121 60542 59890 61126 61121 59890 60553 59896 59892 59892 60549 60553 59893 59909 59915 59903 59901 59894 60560 59903 59894 59894 60547 60560 59908 59907 59896 60553 59908 59896 60558 59899 59897 59897 59920 60558 59897 59898 59920 60580 59921 59898 59921 59920 59898 59899 60558 60559 59936 59922 59900 61143 59936 59900 59900 60564 61143 59900 60559 60564 59901 59902 59905 59903 59902 59901 61130 59905 59902 59902 60569 61130 59902 59903 60569 59903 60560 60569 59904 59905 60534 59905 60533 60534 60554 60533 59905 61130 60554 59905 59906 59907 60556 60556 59911 59906 60557 60556 59907 59907 59908 60557 59908 61123 61129 59908 60553 61123 61129 60557 59908 61144 59915 59909 59909 59938 61144 60570 59916 59910 59910 59911 60570 59911 60562 60570 59911 60556 60562 60571 59919 59912 59912 59913 60571 61142 60571 59913 59913 59914 61142 59914 60577 61142 59914 59917 60577 61144 60566 59915 60586 59933 59916 59916 60581 60586 59916 60572 60581 60573 60572 59916 61131 60573 59916 59916 60570 61131 59917 60575 60577 59917 59918 60575 59918 60574 60575 59918 59929 60574 61134 60558 59920 61135 61134 59920 61663 61135 59920 59920 59921 61663 59921 61149 61663 59921 60580 61149 59936 59935 59922 59940 59924 59923 59940 59938 59924 59927 59926 59925 59926 59927 60584 61162 60584 59927 59927 59932 61162 59930 59929 59928 59929 59930 60574 60576 60574 59930 60588 60576 59930 59931 61159 61693 59931 61158 61159 59931 60583 61158 59932 60587 61162 59933 60586 60587 60590 59952 59934 59934 60589 60590 59934 60578 60589 59938 59939 61144 59940 59939 59938 61145 61144 59939 61153 61145 59939 59939 59940 61153 59940 60582 61153 59941 60602 61156 60603 60602 59941 59941 60601 60603 59941 59942 60601 59942 59968 60601 61153 60582 59943 61164 61153 59943 59943 59944 61164 61688 61164 59944 59944 59956 61688 60595 59956 59944 59959 59946 59945 61170 59959 59945 59959 59947 59946 60610 59958 59947 61177 60610 59947 59947 60596 61177 59947 59959 60596 59948 61709 62311 59948 59949 61709 62891 61172 59948 59948 62311 62891 59949 59964 60598 60599 59964 59949 61710 61709 59949 59949 60598 61710 61173 59967 59950 61696 61173 59950 59950 59951 61696 59951 60591 60592 59951 59952 60591 59951 60592 61696 59952 60590 60591 59954 60608 61169 59954 60607 60608 59954 59955 60607 59956 59955 59954 61169 59956 59954 59955 59977 60607 60595 59977 59955 59955 59956 60595 59956 61167 61688 61169 61167 59956 59957 59977 60595 59957 59976 59977 59978 59976 59957 60610 59971 59958 61170 60596 59959 59983 59973 59960 59961 59962 60598 61181 60598 59962 59962 61180 61181 59962 60597 61180 59965 59966 61183 61711 61183 59966 59966 60600 61711 60613 60600 59967 61173 60613 59967 60606 60601 59968 59968 60604 60606 60605 60604 59968 59968 59988 60605 59969 59988 59990 59989 59988 59969 59990 59970 59969 60610 59972 59971 60611 59982 59972 59972 60610 60611 61179 60612 59973 59973 59983 61179 59987 59986 59974 59999 59993 59975 60609 59977 59976 59976 59991 60609 59976 59978 59991 60609 60607 59977 59979 61184 61187 59979 60614 61184 59979 59980 60614 61187 60618 59979 59981 59982 61718 61185 60614 59981 61717 61185 59981 59981 61716 61717 61718 61716 59981 59982 60615 61719 60616 60615 59982 59982 60611 60616 61719 61718 59982 59985 59984 59983 59983 59984 61179 61720 61708 59984 59984 59985 61720 61708 61179 59984 61724 61720 59985 59985 60620 61724 59988 59989 60605 59989 60604 60605 60617 60609 59991 60007 60000 59994 60625 60007 59994 59997 59996 59995 60626 59997 59995 61189 60626 59995 59995 60621 61189 59996 59997 60005 60627 60006 59997 61191 60627 59997 59997 60626 61191 60006 60005 59997 60636 60635 59998 61196 60636 59998 59998 59999 61196 59999 61195 61196 61207 60051 60000 60000 60007 61207 60002 60004 60632 60003 60643 61202 60003 60632 60643 60004 60008 60010 60004 60010 60632 60005 60006 60011 60006 60627 61737 61206 60011 60006 61216 61206 60006 61737 61216 60006 60007 61200 61207 60007 60625 61200 60008 60009 60010 61204 60010 60009 61736 61204 60009 60009 60644 61736 61203 60632 60010 62340 61203 60010 62350 62340 60010 60010 61204 62350 61206 60633 60011 61192 60634 60012 60012 60646 61192 60647 60646 60012 61212 60647 60012 60012 60656 61212 60634 60013 60012 60026 60024 60015 60050 60026 60015 60015 60036 60050 60660 60637 60016 60016 60657 60660 60016 60037 60657 60016 60017 60037 60019 60022 60033 60021 60020 60019 60033 60021 60019 60652 60645 60020 60653 60652 60020 60020 60021 60653 60659 60653 60021 60021 60033 60659 60677 60035 60023 60023 60667 60677 61731 61199 60024 60024 60027 61731 60028 60027 60024 60024 60025 60028 60026 60025 60024 62377 60028 60025 60025 61768 62377 60025 60026 61768 60026 60668 61768 60026 60050 60668 62362 61731 60027 62363 62362 60027 62929 62363 60027 60027 61238 62929 60027 60028 61238 62377 61238 60028 60029 60030 60039 60032 60030 60029 60030 60031 60039 60032 60031 60030 60669 60039 60031 61214 60669 60031 60031 60661 61214 60031 60649 60661 60031 60032 60649 60032 60640 60649 60650 60640 60032 60033 60658 60659 60033 60047 60658 60034 60676 61236 60048 60036 60035 60049 60048 60035 60677 60049 60035 60036 60048 60050 61243 60657 60037 60037 60038 61243 61257 61243 60038 60038 60678 61257 60042 60040 60039 60670 60042 60039 60039 60669 60670 60040 60041 60043 60042 60041 60040 61759 60043 60041 60041 61244 61759 60041 60042 61244 61245 61244 60042 60042 60670 61245 61220 60662 60043 61759 61220 60043 60044 60663 60671 60044 60662 60663 60665 60047 60045 60045 60046 60665 60673 60672 60046 60672 60665 60046 61769 60658 60047 60047 61229 61769 60047 61228 61229 60047 60665 61228 60053 60050 60048 60048 60049 60053 60683 60053 60049 60049 60677 60683 60050 60053 60668 61752 60054 60051 60051 61207 61752 60052 61232 61234 60052 60675 61232 61774 60668 60053 60053 60683 61774 60057 60055 60054 60684 60057 60054 62372 60684 60054 60054 61752 62372 60055 60057 60058 60056 60066 60664 60061 60059 60056 60664 60061 60056 61793 60058 60057 60057 61783 61793 60057 61775 61783 61776 61775 60057 60057 60684 61776 61793 61259 60058 60065 60064 60059 60059 60060 60065 60061 60060 60059 60698 60065 60060 61785 60698 60060 60060 60061 61785 60061 61777 61785 60061 60664 61777 60691 60073 60062 61773 60691 60062 60062 61254 61773 61258 60680 60063 60063 60076 61258 60066 61225 61226 61226 60664 60066 60699 60692 60067 60704 60078 60068 60068 60069 60704 60070 60069 60068 60071 60070 60068 62400 61809 60069 60069 61798 62400 60069 60070 61798 61809 60704 60069 60070 61797 61798 60070 61270 61797 60072 60073 60691 61258 60076 60074 61266 61258 60074 60074 60710 61266 60074 60075 60710 60075 60089 60710 60077 60078 61272 60078 60704 61272 61269 60689 60079 60079 60700 61269 60701 60700 60079 60079 60080 60701 60707 60701 60080 60080 60087 60707 60088 60087 60080 60083 60082 60081 60702 60083 60081 60708 60084 60082 60082 60083 60708 61278 60708 60083 60083 60702 61278 60712 60709 60084 60084 60708 60712 60710 60089 60085 60723 60710 60085 60085 60717 60723 60085 60086 60717 60718 60717 60086 60086 60105 60718 61276 60707 60087 60103 60102 60090 60094 60092 60091 60716 60094 60091 60091 60104 60716 60093 60094 60714 61833 60714 60094 60094 61287 61833 60094 60715 61287 60716 60715 60094 60737 60726 60095 60095 60727 60737 60095 60107 60727 60108 60097 60096 60139 60108 60096 60096 60109 60139 61292 60098 60097 60097 61286 61292 60097 60108 61286 60719 60107 60098 61292 60719 60098 60099 60100 60732 60734 60732 60100 60100 60733 60734 60100 60114 60733 61294 60733 60101 60101 60735 61294 60101 60102 60735 60102 60720 60735 60102 60103 60720 60721 60720 60103 61274 60721 60103 60103 60705 61274 60104 60713 60716 60104 60712 60713 60104 60709 60712 60725 60718 60105 61296 60725 60105 61306 61296 60105 61307 61306 60105 60105 60106 61307 60106 61299 61307 60106 61290 61299 60106 61289 61290 60106 60726 61289 61291 60727 60107 60107 60719 61291 60108 60124 61286 60139 60124 60108 60109 60138 60139 60109 60121 60138 60112 60111 60110 60728 60112 60110 60729 60728 60110 60110 60113 60729 60111 60112 60742 61303 60742 60112 61847 61303 60112 61849 61847 60112 60112 60728 61849 60115 60117 60118 60115 60116 60117 60761 60117 60116 60763 60761 60116 61305 61281 60117 60117 60761 61305 60119 60118 60117 61281 60119 60117 61281 61276 60119 60120 60736 60739 60120 60132 60134 60739 60132 60120 60121 60137 60138 61308 60756 60122 60122 60127 61308 60125 60124 60123 61856 60125 60123 60123 61314 61856 60123 60765 61314 60123 60741 60765 60123 60124 60741 60124 60125 61286 60124 60139 60741 61301 61286 60125 60125 61300 61301 61846 61300 60125 61856 61846 60125 61320 61308 60127 60127 60754 61320 60767 60766 60129 61321 60767 60129 60129 60764 61321 61323 60764 60130 60130 60131 61323 60132 60131 60130 61871 61323 60131 60131 61862 61871 60131 60133 61862 60131 60132 60133 60740 60133 60132 60132 60739 60740 60133 61861 61862 60133 61853 61861 60133 60740 61853 60143 60140 60135 60135 60142 60143 60135 60136 60142 60768 60142 60136 61315 60138 60137 60137 60770 61315 60772 60770 60137 60137 60769 60772 60765 60741 60138 61315 60765 60138 60741 60139 60138 60143 60141 60140 60143 60142 60141 60768 60147 60142 61880 61328 60144 60144 61324 61880 60144 60145 61324 60145 60760 61324 60145 60758 60760 60148 60771 60772 61879 60771 60148 62512 61879 60148 60149 60150 60151 60786 60150 60149 60149 60784 60786 60785 60784 60149 60794 60785 60149 60160 60159 60150 60786 60160 60150 60802 60161 60152 60152 60789 60802 60156 60155 60154 60157 60156 60154 61330 60791 60155 60155 60781 61330 60155 60778 60781 60155 60158 60778 60155 60156 60158 60156 60157 60158 60158 60168 60778 60169 60168 60158 60159 60160 60166 60160 60163 60166 60160 60162 60163 60786 60162 60160 60800 60794 60161 60802 60800 60161 61349 60797 60162 61350 61349 60162 61906 61350 60162 60162 61342 61906 60162 60786 61342 60797 60163 60162 60174 60166 60163 60797 60174 60163 60164 60795 61344 60170 60165 60164 61344 60170 60164 60166 60174 60175 60167 60184 60810 60167 60810 60811 60780 60778 60168 60782 60780 60168 61334 60782 60168 61909 61334 60168 60168 60169 61909 61921 61909 60169 60169 60811 61921 61361 60171 60170 61911 61361 60170 60170 61345 61911 60170 61344 61345 61361 60189 60171 60806 60801 60173 60801 60796 60173 60808 60175 60174 61367 60808 60174 60174 61366 61367 60174 60797 61366 60180 60176 60175 60808 60180 60175 60177 61372 61373 61949 61372 60177 62557 61949 60177 60177 61950 62557 60177 60178 61950 60179 60178 60177 60178 61371 61950 60178 60195 61371 60178 60179 60195 60179 60194 60195 60183 60181 60180 60808 60183 60180 60181 60182 60191 60183 60182 60181 61370 60191 60182 60182 60183 61370 60183 60808 61367 61948 61370 60183 60183 61367 61948 60184 60187 60809 60184 60809 60810 60185 60186 60190 60185 60805 60806 60185 60190 60805 60188 60194 60807 60197 60194 60188 61929 60819 60189 60189 61353 61929 61354 61353 60189 61361 61354 60189 60813 60805 60190 60191 61370 61952 61952 60815 60191 61368 60809 60192 60192 60816 61368 60817 60816 60192 60192 60193 60817 61373 61372 60193 61372 60817 60193 60196 60195 60194 60195 60196 61371 61961 61371 60196 60196 61960 61961 60196 60823 61960 60833 60832 60198 61380 60833 60198 60198 60208 61380 60844 60207 60198 60198 60832 60844 60200 60211 60823 60821 60813 60201 61377 60821 60201 60201 60202 61377 60203 60202 60201 60813 60203 60201 60846 60835 60202 60202 60814 60846 60202 60203 60814 60202 60834 61377 60835 60834 60202 60203 60204 60814 60836 60814 60204 60204 60220 60836 60824 60210 60205 60214 60213 60206 60822 60214 60206 60844 60219 60207 61968 61380 60208 62558 61968 60208 60208 60825 62558 61386 60242 60209 61392 61386 60209 60209 60210 61392 60210 60827 61392 60210 60826 60827 60210 60824 60826 60831 60823 60211 60211 60217 60831 60830 60829 60212 60839 60215 60213 60213 60214 60839 60840 60839 60214 60214 60822 60840 60839 60216 60215 60842 60831 60217 60843 60842 60217 60218 60842 60843 60844 60842 60218 60218 60219 60844 60220 60226 60836 60221 60223 60837 60221 60222 60223 60224 60223 60222 60232 60224 60222 61390 60837 60223 61973 61390 60223 60223 60224 61973 60224 61394 61973 60224 60232 61394 60846 60836 60226 60847 60846 60226 60226 60228 60847 60229 60228 60226 60227 60233 60236 60234 60233 60227 60850 60234 60227 60227 60235 60850 60851 60847 60228 60228 60231 60851 60228 60230 60231 60228 60229 60230 60237 60231 60230 60231 60238 60851 60231 60237 60238 60232 60855 61394 60234 60850 60853 60235 60839 60850 60243 60238 60237 60852 60851 60238 61398 60852 60238 61405 61398 60238 60238 60245 61405 60238 60243 60245 60239 60240 60862 61407 60862 60240 60240 61396 61407 60240 60854 61396 60240 60244 60854 61399 60854 60241 61978 61399 60241 60241 61386 61978 60241 60242 61386 60245 60251 61405 60861 60860 60246 61407 60861 60246 60246 60862 61407 60246 60247 60862 60248 60247 60246 60860 60248 60246 60247 60248 60250 60253 60250 60248 60864 60253 60248 61406 60864 60248 61409 61406 60248 60248 60860 61409 60253 60252 60249 60249 60250 60253 60251 61404 61405 61988 61404 60251 60251 60252 61988 60252 60253 60864 61991 61988 60252 61994 61991 60252 60252 60864 61994 60865 60260 60254 60254 60258 60865 60255 60256 61414 60257 60256 60255 60258 60257 60255 61418 60258 60255 62000 61418 60255 60255 61999 62000 60255 61998 61999 60255 61414 61998 60256 60259 61413 60256 60257 60259 60256 61413 61414 60262 60259 60257 61418 60865 60258 60259 60262 60867 60259 60867 61413 60260 60868 60869 60260 60865 60868 60866 60262 60261 60262 60866 60867 60869 60868 60264 60264 60265 60869 60266 60265 60264 60873 60266 60264 60264 60868 60873 60269 60268 60265 60270 60269 60265 60265 60266 60270 60871 60270 60266 60266 60870 60871 61419 60870 60266 60266 60873 61419 60268 60269 60271 60877 60271 60269 60269 60270 60877 61429 60877 60270 60270 60871 61429 60274 60273 60271 60877 60274 60271 61422 60878 60272 60272 60884 61422 60272 60883 60884 60272 60882 60883 61423 60293 60273 60273 60274 61423 60274 60875 61423 60877 60875 60274 60286 60285 60275 60288 60286 60275 60275 60276 60288 60277 60276 60275 60285 60277 60275 60893 60288 60276 61437 60893 60276 60276 61434 61437 60276 60890 61434 60276 60277 60890 60277 60284 60890 60277 60283 60284 60285 60283 60277 60289 60280 60278 60278 60286 60288 60278 60279 60286 60280 60279 60278 60279 60283 60286 60870 60283 60279 60888 60870 60279 60279 60290 60888 60279 60280 60290 60282 60281 60280 60289 60282 60280 60291 60290 60280 60889 60291 60280 60891 60889 60280 60280 60281 60891 60281 60282 60292 60282 60289 60294 60283 60870 60886 60283 60285 60286 60885 60284 60283 60887 60885 60283 61424 60887 60283 62006 61424 60283 60283 60886 62006 61432 60890 60284 60284 61425 61432 60284 60885 61425 60304 60299 60287 60896 60304 60287 60287 60298 60896 60287 60296 60298 60297 60296 60288 60895 60297 60288 60288 60893 60895 60290 60871 60888 60290 60291 60871 61429 60871 60291 60291 60295 61429 60889 60295 60291 60293 61423 61431 61430 61429 60295 61431 61430 60295 60296 60297 60298 60297 60895 62017 61443 60298 60297 62020 61443 60297 60297 62017 62020 60298 60303 60896 61447 60303 60298 60298 61443 61447 60299 60304 60305 62024 61442 60301 60303 61447 61448 60303 60304 60896 60305 60304 60303 60899 60307 60306 60900 60309 60307 60307 60899 60900 60308 60311 60917 60314 60310 60309 60900 60314 60309 60310 60314 60317 61458 60917 60311 61459 61458 60311 60311 61456 61459 60311 60915 61456 60312 60902 61453 60906 60902 60312 60907 60906 60312 60904 60317 60314 60905 60904 60314 61452 60905 60314 60314 60910 61452 60911 60910 60314 60314 60900 60911 60315 60316 60909 60316 60320 60909 60322 60318 60317 60904 60322 60317 60318 60323 60325 60318 60322 60323 60319 60914 60915 60319 60327 60914 60916 60909 60320 60321 61466 61471 60321 60917 61466 60324 60323 60322 60913 60324 60322 60322 60904 60913 61464 60931 60323 60323 60324 61464 60324 60913 61460 62051 61464 60324 60324 62039 62051 60324 61460 62039 60326 60338 60339 60326 60330 60338 60339 60327 60326 61457 60914 60327 62042 61457 60327 60327 60339 62042 60919 60329 60328 60920 60919 60328 61462 60916 60329 60329 60919 61462 60340 60338 60330 60331 60335 60930 60336 60335 60331 60332 60333 60920 60334 60333 60332 60934 60334 60332 60928 60920 60333 60333 60924 60928 60333 60334 60924 60926 60924 60334 61475 60926 60334 60334 60934 61475 60335 60929 60930 61474 60929 60335 60335 61472 61474 60335 60336 61472 62058 61472 60336 60336 60921 62058 60337 60338 60351 60339 60338 60337 62636 60339 60337 60337 61478 62636 60337 60943 61478 60337 60351 60943 60338 60340 60351 62043 62042 60339 62048 62043 60339 62640 62048 60339 60339 62636 62640 60341 60935 60938 60341 60342 60935 60937 60349 60341 60938 60937 60341 60342 60929 60935 60923 60922 60343 60343 60346 60923 60343 60344 60346 60933 60932 60343 60343 60922 60933 60344 60345 60346 61480 60934 60347 60347 60358 61480 60936 60360 60348 60348 60349 60936 60937 60936 60349 60944 60943 60350 60350 60355 60944 60943 60351 60350 60945 60358 60352 60950 60945 60352 60353 60948 60949 60353 60354 60948 60354 60361 60948 61484 60944 60355 60355 60949 61484 61492 60960 60356 60356 61491 61492 60356 61486 61491 60356 60357 61486 60357 61479 61486 60357 60932 61479 60358 60946 61480 60358 60945 60946 60359 60947 61498 60359 60939 60947 60359 60360 60939 60360 60936 60939 60953 60948 60361 60361 60366 60953 61495 60950 60362 60362 60951 61495 60362 60363 60951 60956 60951 60363 60966 60956 60363 60363 60364 60966 60364 60373 60965 60364 60965 60966 60365 61498 61502 60955 60953 60366 60369 60368 60367 61492 60959 60368 60368 60960 61492 60368 60369 60960 60962 60961 60368 60368 60959 60962 60964 60371 60370 61493 60964 60370 60370 60961 61493 60963 60374 60371 60964 60963 60371 60374 60372 60371 60373 60376 60965 60981 60375 60374 62089 60981 60374 62667 62089 60374 60374 60963 62667 60981 60392 60375 61510 60379 60377 61514 61510 60377 60377 60378 61514 60378 60393 61514 60382 60381 60380 60967 60955 60381 60381 60382 60967 60968 60967 60382 60382 60383 60968 60383 60389 60968 60391 60389 60383 60384 60385 60391 60975 60391 60385 60386 60387 60969 60386 60969 60971 62094 61525 60388 60388 61523 62094 60388 60973 61523 60388 60971 60973 60974 60968 60389 62670 60974 60389 60389 62085 62670 62086 62085 60389 60389 61513 62086 60389 61511 61513 60389 60390 61511 60391 60390 60389 61512 61511 60390 61521 61512 60390 60390 61520 61521 60390 60976 61520 60390 60391 60976 60391 60975 60976 60392 60981 60982 61522 61514 60393 60393 60978 61522 61532 60395 60394 60394 61528 61532 61531 60988 60395 62111 61531 60395 60395 61532 62111 60989 60986 60396 60396 60398 60989 60398 60408 60989 60401 60400 60399 60400 60401 60998 60997 60418 60400 60998 60997 60400 60401 60990 62125 60401 60987 60990 62125 60998 60401 60999 60412 60402 60406 60405 60404 60991 60406 60404 61539 60991 60404 60404 60416 61539 61537 60407 60406 60406 60991 61537 60414 60413 60407 60433 60414 60407 62124 60433 60407 60407 61537 62124 60408 60409 60411 60410 60409 60408 60994 60410 60408 60995 60994 60408 60408 60992 60995 60408 60411 60989 63782 63781 60409 64789 63782 60409 60409 63783 64789 60409 60410 63783 62709 60411 60409 63780 62709 60409 60409 63779 63780 63781 63779 60409 60410 63262 63783 60410 60994 63262 61536 60989 60411 62117 61536 60411 62709 62117 60411 60412 60984 61527 62115 60984 60412 60412 60999 62115 60413 60414 60425 60414 60432 62148 60433 60432 60414 61558 60425 60414 62148 61558 60414 60416 61000 61539 60417 60418 61002 61544 61002 60418 60418 60997 61544 60422 60421 60420 60423 60422 60420 60424 60423 60420 61543 60424 60420 61012 61010 60422 60422 60423 61012 62134 61012 60423 60423 62128 62134 60423 60424 62128 60424 62120 62128 60424 61543 62120 61558 60440 60425 60426 61013 61014 60426 60429 61013 60428 60427 60426 61014 60428 60426 60427 60430 61001 60427 60428 60430 60431 60430 60428 62720 60431 60428 60428 62719 62720 62730 62719 60428 60428 61555 62730 60428 61014 61555 60430 60431 60996 61541 60996 60431 60431 60992 61541 60995 60992 60431 62720 60995 60431 60432 60433 62138 60432 62138 62148 60433 62130 62718 60433 62124 62130 62718 62138 60433 61017 60436 60434 61561 61017 60434 60434 61556 61561 60434 60435 61556 60435 61005 61556 61020 61013 60438 62145 61021 60439 62146 62145 60439 62148 62146 60439 60439 61558 62148 60439 60440 61558 60441 60443 60444 60446 60443 60441 60442 60446 60452 60442 60443 60446 60444 60443 60442 60442 60452 61025 61041 61032 60445 61032 61022 60445 61047 60448 60447 60447 60449 61047 60448 61034 61035 61047 61034 60448 61048 61047 60449 61049 61048 60449 60449 60450 61049 60450 60451 61049 60451 61569 61575 61570 61569 60451 60451 61042 61570 61575 61049 60451 61037 61025 60452 62173 61572 60454 60454 61573 62173 61052 61042 60455 60455 60456 61052 60456 61051 61052 60456 60468 61051 61581 60458 60457 60457 61055 61581 61581 61580 60458 60459 61585 62177 60459 61057 61585 62174 61573 60459 62177 62174 60459 61574 61045 60460 60460 61040 61574 60460 60461 61040 60461 61033 61040 61038 61037 60462 61566 61038 60462 60464 61060 61591 61590 61057 60464 61591 61590 60464 61079 61075 60466 60466 61068 61079 60467 60479 61072 61056 61051 60468 61596 61056 60468 60468 61072 61596 60469 61065 61603 60470 60481 61074 60471 63331 63841 60471 62200 63331 61598 60481 60471 61599 61598 60471 63841 61599 60471 60474 60473 60472 61598 60474 60472 60472 60481 61598 61074 60481 60472 62789 61604 60473 60473 62783 62789 60473 60474 62783 60474 61598 62783 61067 61061 60475 60476 60483 60484 60485 60483 60476 60486 60485 60476 60477 60478 61062 61073 61072 60479 60479 60489 61073 60480 60490 60491 60482 60485 61066 60494 60485 60482 61608 61066 60485 60485 60492 61608 60485 60486 60492 60487 60495 61063 61076 60489 60488 61076 61073 60489 61605 60491 60490 61603 61065 60491 61605 61603 60491 61612 61063 60495 60496 60499 61609 61616 61615 60497 60497 61085 61616 60497 61081 61085 60498 60505 60508 60510 60505 60498 60500 61079 61609 61610 61079 60500 60500 60501 61610 60501 60502 61610 61089 61088 60502 60502 60503 61089 61614 61610 60502 60502 61086 61614 61088 61086 60502 60503 60504 61089 60504 60513 61089 61095 60507 60505 60505 60510 61095 61617 60508 60505 60505 60506 61617 60507 60506 60505 62216 61617 60506 60506 60507 62216 60507 61095 62214 60507 61626 62216 62214 61626 60507 61617 61101 60508 60509 60515 61100 60510 61094 61095 61101 60516 60511 61107 60513 60512 61108 61107 60512 61107 61089 60513 61098 60524 60514 61632 61100 60515 60515 61090 61632 60516 61101 61102 61625 61094 60517 62234 61625 60517 60517 61633 62234 60517 60518 61633 60518 60541 61633 61120 60530 60519 60521 60520 60519 60530 60521 60519 61109 60523 60520 60520 60521 61109 60521 61105 61109 60521 61104 61105 60521 60530 61104 60522 60523 61106 61638 61106 60523 60523 61637 61638 60523 61109 61637 61097 60532 60524 61098 61097 60524 60539 60538 60525 60525 60526 60539 61110 60539 60526 60526 60535 61110 60537 60535 60526 61117 60541 60527 60528 61649 61650 63385 61649 60528 60528 63384 63385 60528 60529 63384 60529 62801 63384 60529 61626 62801 62244 61626 60529 60529 62215 62244 60529 61617 62215 60529 61102 61617 61114 61104 60530 62241 61114 60530 60530 61121 62241 60530 61120 61121 60531 60532 60543 60531 60543 60548 60532 60545 60550 60532 60544 60545 61096 60544 60532 61097 61096 60532 60550 60543 60532 60533 60554 60555 61116 61110 60535 60535 60536 61116 62240 61116 60536 60536 61119 62240 60538 60539 61110 61644 60546 60538 60538 61110 61644 61118 61117 60540 60540 61113 61118 60540 60546 61113 61634 61633 60541 60541 61117 61634 61121 61120 60542 60550 60548 60543 60544 61096 62225 61124 60545 60544 62225 61124 60544 61124 60550 60545 61644 61113 60546 60561 60560 60547 61141 60561 60547 61655 61141 60547 60547 60552 61655 60547 60548 60552 60548 60551 60552 60548 60550 60551 61123 60553 60549 60549 61122 61123 61127 60551 60550 60550 61125 61127 60550 61124 61125 61127 60552 60551 62260 61655 60552 60552 62249 62260 62250 62249 60552 60552 61127 62250 61661 61128 60554 60554 61130 61661 60556 60557 60563 60563 60562 60556 61133 60563 60557 60557 61129 61133 60565 60559 60558 61136 60565 60558 60558 61134 61136 60565 60564 60559 60560 60561 60569 60561 60567 60569 60568 60567 60561 61141 60568 60561 61131 60570 60562 61132 61131 60562 60562 60563 61132 60563 61133 61662 61662 61132 60563 61152 60594 60564 60564 61150 61152 61151 61150 60564 60564 61136 61151 60564 60565 61136 60566 61144 61145 61130 60569 60567 61667 61130 60567 61668 61667 60567 61677 61668 60567 60567 60568 61677 60568 61676 61677 60568 61154 61676 60568 61148 61154 60568 61140 61148 61141 61140 60568 60579 60578 60571 61142 60579 60571 62281 60581 60572 60572 62269 62281 60572 60573 62269 60573 61664 62269 60573 61131 61664 60576 60575 60574 61669 60577 60575 60575 60576 61669 62283 61669 60576 60576 61155 62283 60576 60588 61155 61681 61142 60577 60577 61680 61681 60577 61669 61680 60578 60579 60589 61681 60589 60579 60579 61142 61681 61157 61149 60580 60580 61156 61157 60581 60585 60586 61690 60585 60581 62281 61690 60581 61161 61158 60583 60583 60584 61161 61162 61161 60584 60587 60586 60585 61689 60587 60585 61690 61689 60585 61684 61162 60587 61689 61684 60587 61685 61155 60588 61692 61685 60588 60588 61691 61692 60588 61165 61691 60591 60590 60589 60592 60591 60589 61681 60592 60589 62284 61696 60592 60592 61680 62284 61681 61680 60592 60593 60601 60606 60603 60601 60593 62274 60603 60593 60593 61152 62274 60593 60594 61152 61705 61177 60596 60596 61171 61705 60596 61170 61171 61707 61180 60597 60597 60612 61707 60598 61181 61710 60600 60613 61711 61670 61156 60602 60602 61150 61670 62274 61150 60602 60602 60603 62274 60609 60608 60607 61174 61169 60608 61175 61174 60608 60608 60609 61175 61176 61175 60609 60609 60617 61176 61177 60611 60610 61178 60616 60611 60611 61177 61178 61721 61707 60612 60612 61708 61721 60612 61179 61708 61712 61711 60613 60613 61703 61712 60613 61173 61703 61185 61184 60614 62320 62319 60615 60615 60616 62320 62319 61719 60615 60616 62313 62320 60616 61178 62313 61728 61176 60617 60618 60624 60625 61197 60624 60618 60618 61187 61197 61190 60620 60619 60619 61188 61190 61725 61724 60620 60620 61190 61725 61711 61189 60621 60621 61183 61711 60621 61182 61183 60622 61194 61195 60622 61193 61194 60622 60623 61193 60623 61192 61193 61200 60625 60624 61732 61200 60624 60624 61197 61732 62332 61191 60626 60626 62326 62332 60626 61189 62326 60627 61191 61737 60648 60639 60628 60628 60638 60648 60628 60630 60638 60628 60629 60630 60637 60630 60629 61208 60638 60630 60630 61201 61208 60630 60637 61201 61734 61188 60631 60631 61733 61734 60631 60640 61733 61203 60643 60632 61206 60655 60633 60635 60636 61213 61756 61213 60636 62346 61756 60636 62358 62346 60636 60636 61729 62358 60636 61196 61729 60637 60660 61201 60661 60648 60638 61757 60661 60638 60638 61208 61757 60649 60640 60639 60639 60648 60649 60640 60650 61733 60651 60650 60641 61742 60651 60641 60641 60642 61742 62349 61742 60642 60642 61209 62349 60642 61202 61209 61210 61202 60643 60643 61203 61210 62352 61736 60644 62353 62352 60644 62354 62353 60644 60644 61743 62354 61745 61205 60645 60645 60652 61745 61198 61192 60646 61738 61198 60646 60646 60647 61738 61750 61738 60647 60647 61212 61750 60661 60649 60648 60650 60651 61733 61734 61733 60651 62330 61734 60651 60651 62329 62330 60651 61742 62329 60652 61211 61745 60652 60653 61211 60653 60659 61211 61217 61212 60656 60656 60666 61217 62348 60660 60657 62365 62348 60657 60657 61241 62365 61243 61241 60657 61251 60659 60658 61252 61251 60658 61769 61252 60658 61748 61211 60659 60659 61251 61748 62348 61201 60660 61757 61214 60661 61220 60663 60662 61224 60671 60663 61760 61224 60663 60663 61759 61760 60663 61220 61759 60664 61246 61777 60664 61226 61246 60665 60672 61228 61236 61217 60666 60667 61218 61237 60681 60677 60667 60682 60681 60667 61782 60682 60667 60667 61237 61782 61774 61768 60668 61219 60670 60669 61758 61219 60669 60669 61214 61758 60670 61219 61245 60671 61224 61225 60672 60673 61228 61230 61228 60673 60673 60690 61230 60674 61231 61232 60674 60679 61231 61232 60675 60674 60677 60681 60683 60678 60686 61257 60679 60680 61231 61258 61231 60680 61774 60683 60681 61780 61774 60681 60681 60682 61780 61781 61780 60682 61791 61781 60682 60682 61782 61791 62371 61776 60684 62372 62371 60684 60685 61260 62425 60685 60686 61260 60687 60686 60685 61801 60687 60685 62424 61801 60685 62425 62424 60685 60686 61259 61260 60686 60687 61257 61784 61257 60687 62398 61784 60687 60687 61801 62398 61268 60699 60688 60688 60689 61268 61269 61268 60689 61250 61230 60690 60690 60692 61250 61773 61270 60691 60692 60699 61250 60693 60694 60706 60695 60694 60693 61267 60695 60693 60694 60705 60706 61274 60705 60694 61275 61274 60694 60694 60695 61275 61267 60696 60695 60695 60696 61275 61813 61275 60696 61818 61813 60696 60696 60697 61818 60698 60697 60696 60697 60698 61785 60697 61796 61818 60697 61795 61796 60697 61785 61795 61268 61250 60699 60700 61268 61269 61807 61268 60700 60700 60701 61807 60701 60707 61807 60702 60703 61278 61814 61278 60703 61816 61814 60703 60703 61273 61816 60703 61272 61273 61808 61272 60704 61809 61808 60704 60707 61281 61807 60707 61276 61281 61278 60712 60708 61279 61266 60710 60710 60723 61279 60711 61277 61822 60711 60712 61277 60713 60712 60711 61822 60713 60711 61815 61277 60712 60712 61278 61815 61822 60716 60713 61833 60738 60714 61832 61287 60715 60715 61831 61832 60715 61830 61831 60715 61828 61830 60715 60716 61828 60716 61822 61828 61282 60723 60717 61283 61282 60717 60717 60724 61283 60717 60718 60724 60725 60724 60718 60719 61285 61291 60719 61284 61285 61292 61284 60719 61824 60735 60720 61826 61824 60720 60720 60721 61826 61827 61826 60721 60721 61280 61827 60721 61274 61280 60738 60736 60722 61817 61279 60723 60723 61282 61817 61295 61283 60724 60724 60725 61295 61296 61295 60725 60726 60737 61289 61289 60737 60727 61291 61289 60727 60728 61293 61848 60728 60729 61293 60728 61848 61849 60729 60730 61293 60730 60731 61851 60732 60731 60730 61848 61293 60730 61851 61848 60730 60731 60732 60734 60731 60734 61851 61304 60734 60733 60733 61294 61304 62462 61851 60734 60734 61304 62462 61825 61294 60735 60735 61824 61825 60736 60738 60739 60740 60739 60738 61853 60740 60738 60738 61834 61853 60738 61833 61834 61857 60751 60742 60742 61303 61857 61309 60747 60743 60743 60755 61309 61878 60746 60744 63023 61878 60744 60744 63002 63023 60744 60745 63002 60746 60745 60744 60745 61858 62469 60745 60746 61858 60745 63001 63002 60745 62466 63001 62469 62466 60745 60746 60759 61311 60746 60758 60759 60760 60758 60746 61878 60760 60746 60746 61311 61858 61859 60748 60747 62465 61859 60747 60747 61309 62465 61311 60757 60748 61858 61311 60748 61859 61858 60748 61317 60752 60749 60749 61316 61317 60749 60750 61316 61872 61316 60750 60750 60751 61872 60751 61864 61872 60751 61857 61864 61319 60753 60752 60752 61317 61319 61318 60754 60753 61319 61318 60753 60754 61318 61320 60755 60756 61309 61310 61309 60756 60756 61308 61310 61311 60759 60757 61878 61324 60760 61860 61305 60761 60761 60762 61860 60763 60762 60761 60762 61852 61860 60762 61312 61852 61322 61321 60764 61323 61322 60764 61315 61314 60765 60766 60767 61313 61321 61313 60767 62479 61315 60770 60770 61877 62479 60770 61876 61877 60770 60771 61876 60772 60771 60770 61879 61876 60771 60773 60774 61339 60775 60774 60773 61341 60775 60773 61897 61341 60773 60773 61339 61897 60774 60775 60803 60774 60803 61339 60775 60776 60801 60777 60776 60775 60775 60801 60803 60776 60777 60796 60776 60796 60801 60778 60779 60781 60780 60779 60778 61332 60781 60779 60779 60782 61332 60779 60780 60782 61332 61331 60781 61331 61330 60781 61333 61332 60782 61334 61333 60782 61338 60792 60783 60784 60785 60793 61342 60786 60784 61351 61342 60784 60784 60793 61351 60794 60793 60785 60787 60788 61898 60789 60788 60787 61908 60789 60787 62535 61908 60787 60787 61898 62535 61340 60790 60788 60788 60789 61340 60788 60790 61898 61358 60802 60789 61359 61358 60789 61927 61359 60789 62534 61927 60789 60789 61908 62534 60790 60791 61898 60791 61887 61898 60791 61330 61887 61338 60795 60792 61355 61351 60793 61356 61355 60793 60793 60798 61356 60799 60798 60793 60793 60794 60799 60800 60799 60794 60795 61338 61902 61902 61344 60795 61363 61362 60797 60797 61349 61363 60797 61362 61366 60798 60800 60802 60798 60799 60800 61357 61356 60798 61358 61357 60798 60798 60802 61358 60805 60803 60801 60806 60805 60801 60803 60804 61339 60805 60804 60803 61900 61339 60804 60804 61360 61900 60804 60805 61360 60805 60813 61360 61368 60810 60809 60812 60811 60810 61368 60812 60810 60811 61343 61921 60811 60812 61343 61368 61343 60812 60813 60820 61360 60821 60820 60813 60814 60836 60846 61957 60822 60815 60815 61952 61957 60816 61343 61368 61938 61343 60816 60816 61372 61938 60816 60817 61372 62558 60825 60818 60818 61940 62558 60818 60819 61940 60819 61929 61940 61900 61360 60820 61930 61900 60820 61943 61930 60820 60820 60821 61943 60821 61377 61943 61965 60840 60822 60822 61957 61965 60823 60832 61960 61379 60832 60823 60823 60831 61379 60828 60826 60824 60828 60827 60826 60827 61381 61392 60827 60828 61381 60828 60829 61381 61389 61381 60829 60829 60830 61389 60830 60838 61389 60831 60842 61379 60832 60833 61960 61379 60844 60832 61961 61960 60833 61968 61961 60833 60833 61380 61968 61378 61377 60834 60834 61375 61378 60834 60835 61375 60835 60845 61374 60846 60845 60835 60835 61374 61375 61390 60838 60837 61390 61389 60838 61391 60850 60839 62565 61391 60839 60839 60849 62565 60839 60841 60849 60839 60840 60841 61965 60841 60840 61972 60849 60841 60841 61967 61972 60841 61965 61967 60842 60844 61379 61383 61374 60845 60845 60848 61383 60845 60847 60848 60845 60846 60847 60851 60848 60847 60848 60851 60852 61393 61383 60848 60848 60852 61393 63106 62570 60849 60849 61972 63106 62570 62565 60849 60859 60853 60850 61391 60859 60850 60852 61397 62592 61398 61397 60852 60852 61385 61393 61975 61385 60852 62592 61975 60852 61399 61396 60854 61395 61394 60855 60857 60863 61402 63111 61403 60858 60858 61986 63111 60858 61979 61986 60858 60859 61979 60859 61391 61979 61995 61409 60860 60860 61412 61995 60860 60861 61412 61992 61412 60861 60861 61407 61992 60864 61410 61994 61411 61410 60864 60864 61406 61411 61418 60868 60865 61413 60867 60866 61417 61413 60866 62002 60873 60868 60868 61418 62002 60888 60871 60870 61419 60886 60870 60872 60874 61415 62002 61419 60873 61422 61415 60874 60874 60878 61422 60875 60876 61423 60877 60876 60875 61430 61423 60876 60876 60877 61430 60877 61429 61430 60879 60884 62008 61422 60884 60879 60879 61415 61422 62001 61415 60879 62596 62001 60879 60879 61420 62596 61421 61420 60879 60879 60880 61421 60881 60880 60879 62008 60881 60879 62004 61421 60880 62603 62004 60880 60880 60881 62603 63143 62603 60881 60881 62609 63143 60881 60894 62609 62008 60894 60881 60892 60883 60882 61433 60884 60883 60883 60894 61433 60883 60892 60894 60884 61433 62008 60885 60887 61425 62007 62006 60886 60886 62005 62007 60886 61419 62005 60887 61424 61425 60890 61432 61434 62009 60894 60892 60892 61439 62009 61437 60895 60893 62008 61433 60894 60894 62014 62609 60894 62009 62014 60895 61437 62017 61440 61439 60897 61442 61440 60897 60898 62026 62029 60898 61451 62026 60898 60899 61451 60900 60899 60898 60903 60900 60898 62028 60903 60898 62029 62028 60898 60899 61450 61451 62023 61450 60899 60900 60903 60911 63155 62024 60901 60901 62625 63155 62626 62625 60901 60901 60902 62626 60902 62035 62626 60902 61454 62035 60902 60906 61454 62032 60911 60903 60903 62028 62032 60904 60905 60913 61460 60913 60905 62039 61460 60905 62632 62039 60905 60905 62036 62632 60905 62033 62036 60905 61452 62033 62038 61454 60906 60906 61455 62038 62038 61455 60908 60908 60912 62038 60908 60909 60912 60916 60912 60909 62033 61452 60910 60910 62032 62033 60910 60911 62032 60912 61463 62038 60912 60916 61463 61456 60915 60914 62041 61456 60914 60914 62040 62041 60914 61457 62040 60916 61462 61463 60917 61461 61466 60917 61458 61461 60918 61466 61467 61471 61466 60918 60918 60922 60923 61467 60922 60918 60919 60927 61462 60919 60920 60927 60928 60927 60920 62633 62058 60921 60921 60931 62633 62045 60933 60922 60922 61467 62045 62049 60928 60924 62054 62049 60924 60924 60925 62054 60926 60925 60924 64209 62054 60925 60925 62655 64209 60925 61481 62655 62060 61481 60925 60925 60926 62060 60926 61475 62060 61468 61462 60927 62049 61468 60927 60927 60928 62049 61474 60935 60929 60931 62050 62633 60931 61464 62050 60932 60933 61479 62046 61479 60933 60933 62045 62046 61480 61475 60934 60935 61474 61477 61477 60938 60935 60936 60937 60939 61473 60939 60937 60937 60938 61473 61476 61473 60938 60938 60940 61476 62644 60940 60938 60938 61477 62644 61482 60947 60939 60939 61473 61482 63201 61476 60940 60940 60941 63201 60942 60941 60940 62644 60942 60940 60941 60942 64195 63738 63201 60941 64196 63738 60941 60941 64195 64196 60942 63202 63740 60942 62059 63202 62644 62059 60942 60942 63740 64195 62062 61478 60943 60943 60944 62062 60944 61485 62062 60944 61484 61485 60945 60950 61495 62075 60946 60945 62077 62075 60945 60945 61495 62077 61487 61480 60946 62649 61487 60946 60946 62074 62649 62075 62074 60946 61501 61498 60947 62078 61501 60947 63213 62078 60947 60947 62661 63213 62662 62661 60947 60947 61483 62662 60947 61482 61483 60954 60949 60948 60948 60953 60954 61488 61484 60949 60949 60954 61488 61496 61495 60951 60951 60956 61496 60952 62080 62081 60952 61499 62080 60952 60953 61499 60954 60953 60952 62069 60954 60952 62081 62069 60952 60953 60955 61499 62067 61488 60954 62070 62067 60954 60954 62068 62070 62069 62068 60954 60955 60967 61499 61497 61496 60956 60956 60966 61497 62658 62071 60957 63212 62658 60957 60957 62651 63212 60957 62065 62651 60957 61490 62065 60957 61489 61490 60957 60958 61489 60959 60958 60957 62071 60959 60957 61491 61489 60958 61492 61491 60958 60958 60959 61492 62072 60962 60959 60959 62071 62072 61494 61493 60961 60961 60962 61494 61503 61494 60962 62072 61503 60962 60963 61504 62667 60963 60964 61504 60964 61494 61504 60964 61493 61494 61500 60966 60965 61505 61500 60965 61500 61497 60966 62080 61499 60967 62081 62080 60967 60967 60974 62081 60967 60968 60974 60969 60970 60971 60972 60971 60970 61502 60972 60970 60971 60972 60973 61502 60973 60972 60973 61507 61523 60973 61502 61507 60974 62068 62081 62666 62068 60974 62670 62666 60974 60977 60976 60975 60976 60980 61520 60976 60977 60980 61524 61522 60978 60978 60979 61524 60979 60985 61524 61521 61520 60980 62087 61521 60980 62088 62087 60980 62682 62088 60980 60980 61526 62682 62091 60982 60981 62683 62091 60981 60981 62089 62683 62102 61529 60982 60982 62091 62102 60983 60984 62115 62698 62105 60983 62710 62698 60983 60983 62115 62710 61530 61524 60985 60985 60986 61530 61535 61530 60986 60986 60989 61535 61533 60990 60987 60987 61525 61533 61536 61535 60989 63257 62125 60990 63272 63257 60990 60990 63250 63272 60990 62114 63250 60990 61533 62114 61538 61537 60991 61539 61538 60991 60992 60996 61541 60992 60993 60996 60994 62721 63262 60994 62720 62721 60994 60995 62720 62125 61544 60997 60997 60998 62125 62122 62115 60999 61009 61008 61000 61540 61539 61000 62129 61540 61000 62132 62129 61000 61000 61008 62132 61004 61003 61002 61545 61004 61002 61002 61544 61545 61006 61005 61003 61003 61004 61006 61011 61006 61004 61545 61011 61004 61005 61006 61556 61006 61549 61556 61550 61549 61006 61006 61011 61550 61548 61542 61007 61008 61009 61010 61008 61557 62132 61008 61554 61557 61008 61010 61554 61010 61553 61554 61010 61012 61553 61011 61545 61550 62136 61553 61012 61012 62134 62136 61020 61014 61013 61014 61020 61555 61028 61020 61015 61030 61028 61015 61559 61030 61015 61015 61016 61559 61016 61022 61559 61017 61023 61024 61560 61023 61017 61561 61560 61017 61018 61019 62740 62732 61551 61018 62740 62732 61018 62742 62740 61019 61019 62149 62742 61019 61025 62149 62739 61555 61020 61020 62139 62739 62140 62139 61020 61020 61028 62140 62751 61026 61021 61021 62145 62751 61022 61031 61559 61032 61031 61022 62161 61562 61023 62745 62161 61023 61023 61560 62745 61562 61024 61023 61044 61036 61024 61563 61044 61024 61024 61562 61563 61025 61037 62149 61033 61027 61026 61040 61033 61026 62751 61040 61026 61030 61029 61028 61028 61029 62140 61029 61030 61565 62155 62140 61029 61029 61565 62155 61030 61031 61565 61559 61031 61030 61031 61564 61565 61031 61041 61564 61031 61032 61041 61047 61046 61034 61046 61035 61034 61564 61041 61035 61035 61046 61564 61036 61043 61054 61044 61043 61036 62742 62149 61037 61037 61039 62742 61037 61038 61039 61038 62163 62759 61038 62162 62163 61038 61566 62162 62759 61039 61038 62758 62742 61039 62759 62758 61039 61587 61574 61040 62751 61587 61040 61571 61570 61042 61042 61052 61571 61578 61054 61043 62166 61578 61043 61043 61044 62166 61044 62161 62166 61044 61563 62161 61567 61564 61046 61568 61567 61046 62761 61568 61046 61046 62168 62761 61046 61047 62168 61047 61048 62168 61048 61575 62168 61048 61049 61575 61571 61052 61050 61576 61571 61050 61050 61056 61576 61050 61051 61056 61052 61051 61050 61053 61588 61592 61053 61577 61588 61053 61054 61577 61578 61577 61054 61583 61581 61055 62173 61583 61055 61055 61572 62173 62184 61576 61056 61056 61596 62184 61590 61585 61057 61058 61059 61589 61594 61589 61059 62179 61594 61059 61059 62178 62179 61059 61592 62178 61060 61061 61591 62189 61591 61061 61061 61601 62189 61061 61600 61601 61061 61067 61600 61062 61063 61612 62193 61078 61066 61066 61608 62193 61067 61078 61600 61069 61576 62184 61069 61571 61576 61069 61070 61571 61071 61070 61069 62184 61071 61069 62170 61571 61070 61070 62169 62170 61070 61071 62169 63310 62169 61071 63317 63310 61071 61071 62779 63317 61071 62184 62779 61597 61596 61072 61072 61073 61597 61602 61597 61073 61073 61076 61602 61613 61080 61075 61075 61610 61613 61075 61079 61610 61611 61602 61076 61082 61081 61077 61607 61082 61077 62191 61600 61078 62193 62191 61078 61080 61613 62209 62209 61611 61080 61081 61082 61085 61082 61083 61616 61084 61083 61082 61607 61084 61082 61616 61085 61082 62800 61616 61083 61083 62796 62800 61083 61084 62796 63849 62796 61084 61084 62210 63849 62211 62210 61084 62789 62211 61084 61084 61604 62789 61607 61604 61084 61086 61613 61614 62209 61613 61086 61086 61087 62209 61088 61087 61086 62212 62209 61087 62792 62212 61087 62793 62792 61087 61087 61088 62793 61088 61627 62797 61088 61089 61627 62797 62793 61088 61628 61627 61089 61089 61107 61628 61090 61618 61632 62222 61618 61090 61090 61091 62222 61091 61092 62222 62213 61622 61093 62800 62213 61093 61093 61615 62800 61625 61095 61094 61095 61625 62214 61096 61097 62220 61096 62220 62225 61097 61098 61629 61097 61629 62220 61098 61099 61629 62220 61629 61099 61099 62219 62220 61099 61631 62219 61099 61630 61631 62221 61630 61100 62803 62221 61100 61100 61618 62803 61632 61618 61100 61617 61102 61101 61103 61104 61114 61105 61104 61103 62226 61105 61103 61103 61652 62226 61103 61114 61652 62226 61645 61105 61637 61109 61105 62805 61637 61105 61105 61635 62805 61636 61635 61105 62235 61636 61105 61105 61645 62235 61106 61638 61640 61107 61108 61628 61640 61628 61108 62238 61644 61110 61110 62237 62238 61110 61116 62237 61118 61113 61111 61111 61117 61118 61634 61117 61111 61111 61112 61634 61113 61112 61111 62812 61634 61112 61112 61643 62812 61112 61113 61643 61644 61643 61113 62241 61652 61114 61128 61119 61115 62240 62237 61116 62245 62240 61119 62252 62245 61119 61119 61128 62252 61121 61653 62241 61654 61653 61121 61121 61126 61654 61650 61123 61122 62253 61129 61123 62256 62253 61123 61123 61656 62256 61123 61650 61656 61648 61125 61124 62839 61648 61124 61124 62225 62839 62250 61127 61125 61125 61648 62250 61126 61139 61654 62264 62252 61128 61128 61661 62264 62257 61133 61129 61129 62253 62257 61667 61661 61130 61131 61132 61664 62269 61664 61132 61132 61662 62269 62265 61662 61133 62850 62265 61133 61133 62255 62850 61133 62254 62255 62257 62254 61133 61151 61136 61134 61134 61150 61151 61670 61150 61134 61134 61135 61670 61135 61663 61670 61137 61138 62848 61654 61139 61137 62258 61654 61137 62259 62258 61137 62848 62259 61137 61140 61147 61148 61140 61146 61147 61140 61141 61146 61660 61146 61141 61141 61655 61660 62275 61665 61145 61145 61153 62275 61666 61147 61146 62266 61666 61146 61146 62261 62266 61146 61660 62261 61154 61148 61147 61676 61154 61147 61147 61674 61676 61147 61671 61674 61147 61666 61671 61670 61663 61149 61149 61157 61670 62274 61152 61150 61153 61163 62275 61164 61163 61153 61155 61685 62283 61670 61157 61156 61158 61684 62290 61158 61162 61684 61158 61161 61162 61160 61159 61158 62290 61160 61158 62296 61693 61159 61159 61160 62296 61160 62291 62296 61160 62290 62291 62862 62275 61163 62873 62862 61163 61163 62289 62873 61163 61164 62289 61164 61688 62289 61695 61691 61165 62301 61701 61166 61166 61694 62301 61166 61693 61694 62289 61688 61167 62295 62289 61167 61167 61168 62295 61169 61168 61167 61168 61698 62295 61700 61698 61168 61168 61169 61700 61169 61174 61700 61701 61171 61170 62306 61705 61171 61171 61702 62306 61171 61701 61702 63446 61695 61172 61172 62891 63446 61173 61696 61703 61174 61697 61700 61704 61697 61174 61174 61175 61704 61713 61704 61175 61722 61713 61175 61175 61186 61722 61175 61176 61186 62328 61186 61176 61176 61728 62328 61705 61178 61177 61178 61706 62313 61178 61705 61706 62310 61181 61180 61180 62308 62310 61180 61707 62308 62310 61710 61181 61184 61185 61714 61714 61187 61184 61717 61715 61185 61715 61714 61185 62316 61722 61186 62327 62316 61186 62328 62327 61186 62317 61197 61187 61187 61714 62317 61726 61190 61188 61734 61726 61188 62896 62326 61189 62897 62896 61189 61189 62885 62897 61189 61711 62885 61726 61725 61190 61191 62896 62903 61191 62332 62896 62903 61737 61191 61198 61193 61192 61727 61194 61193 61193 61198 61727 62361 61195 61194 62909 62361 61194 61194 62345 62909 61194 61738 62345 61194 61727 61738 61729 61196 61195 62358 61729 61195 62361 62358 61195 62317 61732 61197 61738 61727 61198 61731 61730 61199 61739 61207 61200 61200 61732 61739 62373 61208 61201 61201 62348 62373 61210 61209 61202 61735 61210 61203 62340 61735 61203 62352 62350 61204 61204 61736 62352 61744 61743 61205 61745 61744 61205 61207 61739 61752 62367 61757 61208 62912 62367 61208 61208 62373 62912 61209 61210 61735 61209 61741 62349 62324 61741 61209 61209 62323 62324 62916 62323 61209 61209 61735 62916 61746 61745 61211 61749 61746 61211 61211 61748 61749 61212 61217 61256 61751 61750 61212 61212 61256 61751 61756 61218 61213 61214 61757 61758 62368 62356 61215 61215 61737 62368 61215 61216 61737 61756 61237 61218 61758 61245 61219 61221 61759 62379 61221 61222 61759 61223 61222 61221 62932 61223 61221 61221 62926 62932 61221 62379 62926 61760 61759 61222 61222 61227 61760 61248 61227 61222 61222 61247 61248 62934 61247 61222 61222 61223 62934 64501 62934 61223 65013 64501 61223 65519 65013 61223 61223 65518 65519 61223 65010 65518 61223 64008 65010 61223 62932 64008 61226 61225 61224 61227 61226 61224 61760 61227 61224 61226 61227 61246 61778 61246 61227 61227 61249 61778 61227 61248 61249 61230 61229 61228 61229 61230 61250 62380 61769 61229 61229 61250 62380 61233 61232 61231 61255 61233 61231 62374 61255 61231 62396 62374 61231 62401 62396 61231 62410 62401 61231 61231 61258 62410 61232 61233 61234 61766 61234 61233 61233 61255 61766 61766 61235 61234 61764 61755 61235 61766 61764 61235 61751 61256 61235 61755 61751 61235 62385 61782 61237 62402 62385 61237 61237 62369 62402 61237 62346 62369 61237 61756 62346 62377 61774 61238 61238 61239 62929 61240 61239 61238 61774 61240 61238 62935 62929 61239 61239 62406 62935 62941 62406 61239 61239 61240 62941 61240 61781 61792 61240 61774 61781 61240 62406 62941 62407 62406 61240 61240 62386 62407 61240 61792 62386 61241 61242 62365 61243 61242 61241 61242 61243 61784 62940 62365 61242 61242 62378 62940 61242 61784 62378 61243 61257 61784 62379 61759 61244 62933 62379 61244 61244 62931 62933 61244 62366 62931 61244 61758 62366 61244 61245 61758 61778 61777 61246 62934 61761 61247 61249 61248 61247 61761 61249 61247 61779 61778 61249 61787 61779 61249 61249 61761 61787 62381 62380 61250 63517 62381 61250 61250 61261 63517 61262 61261 61250 61268 61262 61250 61771 61748 61251 61251 61253 61771 61251 61252 61253 61770 61253 61252 61252 61769 61770 61772 61771 61253 61253 61770 61772 61254 61263 61773 61264 61263 61254 61255 61764 61766 61765 61764 61255 62374 61765 61255 62411 62410 61258 61258 61802 62411 61258 61271 61802 61258 61265 61271 61266 61265 61258 61793 61260 61259 61260 61793 62425 61261 62963 63517 63522 62963 61261 63530 63522 61261 61261 62968 63530 61261 61262 62968 63529 62968 61262 61262 62972 63529 61262 61268 62972 61790 61773 61263 61263 61788 61790 61789 61788 61263 61263 61763 61789 61263 61264 61763 61810 61271 61265 61265 61279 61810 61265 61266 61279 61268 62437 62972 61268 61807 62437 61270 61790 61797 61270 61773 61790 61803 61802 61271 61810 61803 61271 61808 61273 61272 61273 61808 61816 61274 61275 61280 61813 61280 61275 61829 61822 61277 62445 61829 61277 61277 61815 62445 61278 61814 61815 61821 61810 61279 61279 61817 61821 62434 61827 61280 61280 61819 62434 61280 61813 61819 61281 61305 61839 61839 61807 61281 61821 61817 61282 62441 61821 61282 61282 62440 62441 61282 61835 62440 61282 61283 61835 61841 61835 61283 61283 61295 61841 61302 61285 61284 61284 61301 61302 61284 61292 61301 61285 61288 61291 61823 61288 61285 61285 61302 61823 61301 61292 61286 61287 61832 61834 61834 61833 61287 61290 61289 61288 61298 61290 61288 61836 61298 61288 61288 61823 61836 61288 61289 61291 61290 61298 61299 61837 61304 61294 61838 61837 61294 61294 61825 61838 61295 61296 61841 61842 61841 61296 61854 61842 61296 61296 61306 61854 62993 61844 61297 63552 62993 61297 61297 61836 63552 61297 61298 61836 61299 61298 61297 61844 61299 61297 61843 61307 61299 61844 61843 61299 61300 62457 62985 61300 61845 62457 61846 61845 61300 61302 61301 61300 62985 61302 61300 62442 61823 61302 62984 62442 61302 62985 62984 61302 61303 61847 61857 61304 61837 62462 61840 61839 61305 61860 61840 61305 61855 61854 61306 61306 61843 61855 61306 61307 61843 61873 61310 61308 61308 61320 61873 61309 61874 62465 61309 61310 61874 63000 61874 61310 61310 62485 63000 61310 62484 62485 61310 61873 62484 61868 61867 61312 61312 61313 61868 61867 61852 61312 61869 61868 61313 61313 61321 61869 61314 62471 62995 61314 61315 62471 62995 61856 61314 62479 62471 61315 63010 61317 61316 61316 63009 63010 61316 61865 63009 61872 61865 61316 62481 61319 61317 63019 62481 61317 61317 63010 63019 62483 61320 61318 61318 62482 62483 61318 61319 62482 61319 62481 62482 62484 61873 61320 61320 62483 62484 61321 61322 61869 61322 61323 61871 62477 61869 61322 61322 61871 62477 61324 61878 61880 61329 61328 61325 61886 61329 61325 61325 61326 61886 61327 61326 61325 63024 61327 61325 61325 62503 63024 61325 61328 62503 61326 61327 62531 61326 61885 61886 61901 61885 61326 62531 61901 61326 64094 63620 61327 61327 64093 64094 61327 63610 64093 61327 63609 63610 61327 63024 63609 63620 62531 61327 61328 61880 62503 61888 61887 61330 61330 61331 61888 61331 61332 61881 61331 61887 61888 62530 61887 61331 63042 62530 61331 61331 62515 63042 61331 62514 62515 61331 61881 62514 61332 61336 61881 61332 61333 61336 61333 61335 61336 61333 61334 61335 62525 61335 61334 62536 62525 61334 61334 61909 62536 61337 61336 61335 61883 61337 61335 61884 61883 61335 62525 61884 61335 62514 61881 61336 62516 62514 61336 62517 62516 61336 61336 61337 62517 61337 61882 62517 61883 61882 61337 61338 61885 62522 62522 61902 61338 61339 61896 61897 61339 61894 61896 61339 61346 61894 61347 61346 61339 61899 61347 61339 61900 61899 61339 61897 61348 61341 61342 61352 61906 61342 61351 61352 61343 61918 61921 61937 61918 61343 61938 61937 61343 61902 61345 61344 61345 61903 61911 61345 61902 61903 61346 61890 61894 61904 61890 61346 62529 61904 61346 61346 61347 62529 61347 61899 61913 61347 61912 62529 61913 61912 61347 61348 61895 62512 61897 61895 61348 61922 61363 61349 61349 61907 61922 61349 61350 61907 61350 61905 61907 61906 61905 61350 61917 61352 61351 61351 61355 61917 62543 61906 61352 61352 61916 62543 61917 61916 61352 61942 61929 61353 61962 61942 61353 61353 61369 61962 61353 61354 61369 62539 61369 61354 61354 61910 62539 61911 61910 61354 61354 61361 61911 61924 61917 61355 61925 61924 61355 61926 61925 61355 61355 61357 61926 61355 61356 61357 61357 61359 61926 61357 61358 61359 61936 61926 61359 61359 61928 61936 61359 61927 61928 61365 61364 61362 61362 61363 61365 61362 61364 61366 61922 61365 61363 61364 61934 61939 61364 61365 61934 61939 61366 61364 61365 61933 61934 61365 61923 61933 61365 61922 61923 61935 61367 61366 61939 61935 61366 61367 61944 61948 61367 61935 61944 63634 61962 61369 61369 63047 63634 61369 63046 63047 61369 63045 63046 61369 62539 63045 61370 61948 61952 61961 61950 61371 61949 61938 61372 61374 61383 61384 61376 61375 61374 61382 61376 61374 61384 61382 61374 61964 61378 61375 61375 61376 61964 61376 61951 61964 62561 61951 61376 62563 62561 61376 61376 61382 62563 61951 61943 61377 61377 61378 61951 61964 61951 61378 61389 61388 61381 61381 61388 61392 63097 62563 61382 61382 61976 63097 61382 61384 61976 61385 61384 61383 61393 61385 61383 61384 61385 61975 61384 61975 61976 61386 61387 61978 61388 61387 61386 61392 61388 61386 62576 61978 61387 61387 62569 62576 61387 61388 62569 61388 61969 62569 61388 61389 61969 61970 61969 61389 61389 61390 61970 61971 61970 61390 61973 61971 61390 62565 61979 61391 61983 61973 61394 61394 61982 61983 61987 61982 61394 61394 61401 61987 61394 61395 61401 61402 61401 61395 61992 61407 61396 61396 61989 61992 61990 61989 61396 61396 61400 61990 61396 61399 61400 61405 61404 61397 61397 61398 61405 61397 61404 62592 61980 61400 61399 61399 61978 61980 63124 61990 61400 61400 61980 63124 61401 61403 61987 63111 61987 61403 62593 62592 61404 61404 61988 62593 61406 61408 61411 61409 61408 61406 61408 61409 61995 63135 61411 61408 61408 61996 63135 61408 61995 61996 62595 61994 61410 63134 62595 61410 63677 63134 61410 61410 61411 63677 61411 63121 63677 63135 63121 61411 61412 61992 61995 61998 61414 61413 61413 61417 61998 61997 61416 61415 62003 61997 61415 61415 62001 62003 62599 61417 61416 61416 62003 62599 61416 61997 62003 61999 61998 61417 62600 61999 61417 61417 62598 62600 62599 62598 61417 61418 62000 62002 61419 62002 62005 62597 62596 61420 63139 62597 61420 63140 63139 61420 61420 61421 63140 61421 62004 63140 61423 61430 61431 61426 61425 61424 62006 61426 61424 62013 61432 61425 61425 61428 62013 61425 61426 61428 61426 61427 61428 62602 61427 61426 61426 62006 62602 62607 62010 61427 62608 62607 61427 61427 62011 62608 62012 62011 61427 62602 62012 61427 62010 61428 61427 61428 61434 62013 61435 61434 61428 62010 61435 61428 62013 61434 61432 61438 61437 61434 62016 61438 61434 61434 61436 62016 61434 61435 61436 63146 61436 61435 61435 62607 63146 61435 62010 62607 63148 62016 61436 61436 63146 63148 61437 61438 62017 61438 62016 62017 62015 62009 61439 62614 62015 61439 61439 61440 62614 62620 62614 61440 61440 61441 62620 61442 61441 61440 61441 62018 62620 62019 62018 61441 62024 62019 61441 61441 61442 62024 61449 61447 61443 62020 61449 61443 62022 61449 61444 63687 62022 61444 61444 61445 63687 61446 61445 61444 61449 61446 61444 61445 62616 63687 61445 61446 62616 61446 62615 62616 61446 62017 62615 62020 62017 61446 61446 61449 62020 61449 61448 61447 61448 62021 62619 61448 61449 62021 62022 62021 61449 62025 61451 61450 61450 62023 62025 61451 62025 62026 61454 62030 62035 62031 62030 61454 62037 62031 61454 62634 62037 61454 61454 61470 62634 61454 61469 61470 62038 61469 61454 62041 61459 61456 62042 62040 61457 61458 61459 61461 62044 61461 61459 61459 62041 62044 61461 61465 61466 62044 61465 61461 61462 61469 62038 61462 61468 61469 62038 61463 61462 62051 62050 61464 61467 61466 61465 62053 61467 61465 61465 62044 62053 62053 62045 61467 61470 61469 61468 62634 61470 61468 61468 62049 62634 62058 61474 61472 62642 62057 61473 61473 61476 62642 62055 61482 61473 62057 62055 61473 62058 61477 61474 61475 61481 62060 61475 61480 61481 63201 62642 61476 61477 62059 62644 61477 62058 62059 61478 62063 62636 61478 62062 62063 61479 62046 62065 61490 61486 61479 62065 61490 61479 61487 61481 61480 61481 62649 62655 61481 61487 62649 62061 61483 61482 61482 62056 62061 61482 62055 62056 61483 62660 62662 61483 62650 62660 61483 62061 62650 62066 61485 61484 62067 62066 61484 61484 61488 62067 62654 62062 61485 61485 62066 62654 61486 61489 61491 61490 61489 61486 61494 61503 61504 61495 61496 62077 61496 61497 62077 61497 61500 62084 62665 62077 61497 62677 62665 61497 61497 62674 62677 61497 62084 62674 61498 61501 61502 61500 61505 62084 61506 61502 61501 62078 61506 61501 61502 61506 61507 62076 61504 61503 63222 62076 61503 61503 62073 63222 61503 62072 62073 61504 62076 62667 62090 62084 61505 61505 61517 62090 61505 61509 61517 61508 61507 61506 62079 61508 61506 61506 62078 62079 61507 61508 61523 62681 61523 61508 61508 62083 62681 61508 62079 62083 61509 61515 61517 61509 61514 61515 61509 61510 61514 61511 61512 61513 61512 61521 62087 62671 61513 61512 63230 62671 61512 61512 62087 63230 62671 62086 61513 61514 61522 62092 61516 61515 61514 62688 61516 61514 61514 62092 62688 62686 61517 61515 63245 62686 61515 61515 61516 63245 61516 63243 63245 61516 62688 63243 62686 61519 61517 61519 61518 61517 61517 61518 62090 62676 62090 61518 61518 62675 62676 63232 62675 61518 61518 62686 63232 61518 61519 62686 61522 61524 62092 62681 62094 61523 61524 61530 62092 62096 61533 61525 61525 62095 62096 61525 62094 62095 61526 62101 62682 62102 61532 61528 61528 61529 62102 62093 62092 61530 62103 62093 61530 61530 61535 62103 62109 61534 61531 61531 62106 62109 62111 62106 61531 62112 62111 61532 62703 62112 61532 61532 62692 62703 61532 62685 62692 61532 62102 62685 61533 62104 62114 61533 62096 62104 61534 62109 62110 62113 62103 61535 62117 62113 61535 61535 61536 62117 61537 62121 62124 61537 61538 62121 61538 61539 62121 61539 61540 62121 62129 62121 61540 62127 62123 61542 61542 61548 62127 61547 61545 61544 62131 61547 61544 61544 62125 62131 63275 61550 61545 61545 63264 63275 61545 61546 63264 61547 61546 61545 61546 63263 63264 63796 63263 61546 61546 63273 63796 61546 63272 63273 61546 61547 63272 61547 62131 63272 61548 61552 62127 61548 61551 61552 62142 61556 61549 62731 62142 61549 61549 61550 62731 63266 62731 61550 63275 63266 61550 62733 62133 61551 61551 62732 62733 62133 61552 61551 62133 62127 61552 62136 61554 61553 62136 61557 61554 62739 62730 61555 62142 61561 61556 62724 62132 61557 62736 62724 61557 61557 62141 62736 61557 62136 62141 61560 62143 62745 61560 61561 62143 62144 62143 61561 61561 62142 62144 62161 61563 61562 62760 61565 61564 61564 61567 62760 63296 62155 61565 61565 62760 63296 62165 62162 61566 61566 61579 62165 61580 61579 61566 61567 61568 62760 63300 62760 61568 63817 63300 61568 61568 63301 63817 61568 62761 63301 62168 61575 61569 62753 62168 61569 61569 62752 62753 61569 61570 62752 62756 62752 61570 61570 62170 62756 61570 61571 62170 61573 62174 62764 62764 62173 61573 61587 61586 61574 62157 61588 61577 62772 62157 61577 61577 61578 62772 61578 62167 62772 61578 62166 62167 61579 62164 62165 62175 62164 61579 62176 62175 61579 61579 61582 62176 61579 61581 61582 61579 61580 61581 61583 61582 61581 61582 61584 62176 61582 61583 61584 62172 61584 61583 61583 62171 62172 62173 62171 61583 63823 62176 61584 61584 62762 63823 62763 62762 61584 61584 62172 62763 61585 61590 62177 62193 62190 61586 61586 62192 62193 62770 62192 61586 61586 62768 62770 61586 61587 62768 61587 62751 62768 62178 61592 61588 62186 62178 61588 61588 62157 62186 61594 61593 61589 61590 61591 62182 62182 62177 61590 62189 62183 61591 62183 62182 61591 62774 61595 61593 61593 62179 62774 61593 61594 62179 62774 62187 61595 62181 62180 61595 62187 62181 61595 62185 62184 61596 61596 61597 62185 62197 62185 61597 62201 62197 61597 61597 61602 62201 62784 62783 61598 63318 62784 61598 61598 61599 63318 63840 63318 61599 61599 62780 63840 62782 62780 61599 63841 62782 61599 62191 61601 61600 61601 62192 62775 61601 62191 62192 62767 62189 61601 62775 62767 61601 61602 62198 62201 61602 61611 62198 61603 61605 61606 62205 62200 61603 61603 61606 62205 62207 62205 61606 61608 62190 62193 61614 61613 61610 62209 62198 61611 61615 61616 62800 62216 62215 61617 61618 61619 62803 61620 61619 61618 62222 61620 61618 63865 62803 61619 63866 63865 61619 61619 61620 63866 61620 63364 63866 61620 63361 63364 61620 62798 63361 61620 62222 62798 62798 62222 61621 62799 62798 61621 61621 62213 62799 61621 61622 62213 61623 61622 61621 62814 62223 61624 61624 62813 62814 61624 62234 62813 61624 61625 62234 61626 61625 61624 62223 61626 61624 61625 61626 62214 62244 62216 61626 61626 62224 62801 61626 62223 62224 61627 62217 62797 61627 61628 62217 62233 62217 61628 61628 61640 62233 62221 61631 61630 62802 62219 61631 61631 62221 62802 62813 62234 61633 61633 61634 62813 61634 62812 62813 63356 62805 61635 61635 61636 63356 61636 62804 63356 61636 62227 62804 62235 62227 61636 63880 63370 61637 61637 63367 63880 61637 62805 63367 61639 61638 61637 63370 61639 61637 62230 61640 61638 62231 62230 61638 62809 62231 61638 61638 61639 62809 63376 62809 61639 61639 63369 63376 63370 63369 61639 61640 62232 62233 61640 62230 62232 63379 62812 61641 63380 63379 61641 61641 61642 63380 61643 61642 61641 62812 61643 61641 61642 62822 63380 61642 61643 62822 61643 61644 62822 61644 62238 62821 61644 62820 62822 62821 62820 61644 62226 61652 61645 61645 61646 62235 61647 61646 61645 61651 61647 61645 61652 61651 61645 62816 62235 61646 61646 61647 62816 62823 62816 61647 62828 62823 61647 61647 62239 62828 61647 61651 62239 62251 62250 61648 61648 62243 62251 61648 62242 62243 62839 62242 61648 63385 62831 61649 62831 61650 61649 62831 61656 61650 62835 62239 61651 61651 62241 62835 61651 61652 62241 61653 61659 62241 62842 61659 61653 62843 62842 61653 61653 62258 62843 61653 61654 62258 62260 61660 61655 62831 62256 61656 63912 63389 61657 63913 63912 61657 63914 63913 61657 61657 61658 63914 61659 61658 61657 63389 61659 61657 61658 62842 63914 61658 61659 62842 62835 62241 61659 63389 62835 61659 61660 62260 62261 61661 62263 62264 61661 61667 62263 61662 62265 62269 62858 62851 61665 61665 62275 62858 62851 62270 61665 61672 61671 61666 62268 61672 61666 61666 62267 62268 61666 62266 62267 62271 62263 61667 61667 61668 62271 62272 62271 61668 61668 61677 62272 61669 61679 61680 62283 61679 61669 61675 61674 61671 61671 61673 61675 61671 61672 61673 62276 61673 61672 62286 62276 61672 62852 62286 61672 62854 62852 61672 61672 62268 62854 61682 61675 61673 62287 61682 61673 61673 62276 62287 61683 61676 61674 61674 61682 61683 61674 61675 61682 61678 61677 61676 62277 61678 61676 61676 61683 62277 62860 62272 61677 61677 61678 62860 61678 62859 62860 61678 62277 62859 62283 62282 61679 62282 61680 61679 62299 62284 61680 61680 62282 62299 62287 61683 61682 62287 62277 61683 62292 62290 61684 62293 62292 61684 61684 61689 62293 61692 61687 61685 61685 61686 62283 61687 61686 61685 62868 62283 61686 62870 62868 61686 63428 62870 61686 61686 61687 63428 61687 61692 62298 63953 63428 61687 61687 63447 63953 61687 62298 63447 61689 61690 62293 62294 62293 61690 62874 62294 61690 61690 62281 62874 61695 61692 61691 61692 61695 62298 62296 61694 61693 62883 62301 61694 61694 62297 62883 61694 62296 62297 63446 62298 61695 62284 61703 61696 61697 61698 61700 61699 61698 61697 61704 61699 61697 62875 62295 61698 62876 62875 61698 61698 61699 62876 62882 62876 61699 61699 62300 62882 61699 61704 62300 62301 61702 61701 62887 62306 61702 61702 62302 62887 61702 62301 62302 62878 61712 61703 61703 62284 62878 61704 61713 62305 62304 62300 61704 61704 62303 62304 62305 62303 61704 62306 61706 61705 62889 62313 61706 61706 62307 62889 61706 62306 62307 61707 61721 62308 62314 61721 61708 61708 61720 62314 61709 61710 62311 61710 62309 62311 62310 62309 61710 61711 61712 62885 61712 62878 62885 61713 61722 62316 62316 62305 61713 62333 62317 61714 61714 61723 62333 61714 61715 61723 61717 61716 61715 61715 61716 61723 61716 61718 61723 62318 61723 61718 62319 62318 61718 61718 61719 62319 62325 62314 61720 61720 61724 62325 61721 62331 63470 61721 62314 62331 63471 62308 61721 61721 63470 63471 63467 62333 61723 63481 63467 61723 61723 62318 63481 61724 62321 62325 61724 61725 62321 61725 61726 62321 62329 62321 61726 62330 62329 61726 61726 61734 62330 61728 61730 62328 62339 62328 61730 62905 62339 61730 61730 61731 62905 61731 62362 62905 62347 61739 61732 61732 62334 62347 61732 62317 62334 61735 62914 62916 61735 62341 62914 61735 62340 62341 62903 62368 61737 61738 61750 62345 62364 61752 61739 61739 62347 62364 62329 61742 61740 62902 62329 61740 61740 62325 62902 62331 62325 61740 61740 62324 62331 61740 61741 62324 61742 61741 61740 61741 61742 62349 61743 61747 62354 61743 61744 61747 61744 61745 61747 62355 61747 61745 61745 61746 62355 61746 61749 62355 62917 62354 61747 62918 62917 61747 61747 62355 62918 61771 61749 61748 61749 61771 61788 61749 61754 62355 61749 61753 61754 61789 61753 61749 61749 61788 61789 62357 62345 61750 61750 61764 62357 61750 61755 61764 61750 61751 61755 61752 62364 62372 61762 61754 61753 62927 61762 61753 61753 61789 62927 62918 62355 61754 63498 62918 61754 61754 61762 63498 62366 61758 61757 62367 62366 61757 62937 61787 61761 61761 62934 62937 64005 63498 61762 61762 62342 64005 62927 62342 61762 62927 61789 61763 61763 62383 62927 61763 62368 62383 61763 62356 62368 61764 61767 62357 61764 61765 61767 62928 61767 61765 61765 62375 62928 61765 62374 62375 62928 62357 61767 61768 61774 62377 62946 61770 61769 61769 62382 62946 61769 62380 62382 62946 61772 61770 61771 61772 61788 61790 61788 61772 62395 61790 61772 61772 61797 62395 62947 61797 61772 61772 62946 62947 61774 61780 61781 62391 61783 61775 61775 62390 62391 61775 61776 62390 61776 62371 62390 62394 61785 61777 61777 61779 62394 61777 61778 61779 61779 61786 62394 61787 61786 61779 61781 61791 61792 61799 61791 61782 62385 61799 61782 61794 61793 61783 62408 61794 61783 61783 62391 62408 62939 62378 61784 61784 62398 62939 62394 61795 61785 62945 62394 61786 63503 62945 61786 61786 61787 63503 61787 62936 63503 62937 62936 61787 62395 61797 61790 61800 61792 61791 61791 61799 61800 61792 61800 62386 61793 62422 62425 62423 62422 61793 62952 62423 61793 61793 61794 62952 61794 62408 62952 62409 61796 61795 62943 62409 61795 61795 62394 62943 62960 61818 61796 61796 62409 62960 62947 61798 61797 62947 62400 61798 61799 62397 62420 61799 62384 62397 62385 62384 61799 62420 61800 61799 62421 62386 61800 61800 62420 62421 62957 62398 61801 61801 62424 62957 61802 61803 62411 62415 62411 61803 61803 61805 62415 61812 61805 61803 61803 61810 61812 61804 61805 61811 61806 61805 61804 62426 61806 61804 62427 62426 61804 62433 62427 61804 61804 61812 62433 61804 61811 61812 62950 62415 61805 61805 61806 62950 61812 61811 61805 62417 62403 61806 61806 62416 62417 62426 62416 61806 61806 62403 62950 61807 62399 62437 61807 61839 62399 62965 61816 61808 61808 62400 62965 61808 61809 62400 62970 61812 61810 62974 62970 61810 61810 62438 62974 61810 62432 62438 61810 62431 62432 61810 61821 62431 62969 62433 61812 62970 62969 61812 61813 61818 61819 62439 61815 61814 61814 61816 62439 62976 62445 61815 62977 62976 61815 61815 62439 62977 62964 62963 61816 62965 62964 61816 62963 62439 61816 61820 61819 61818 62961 61820 61818 61818 62960 62961 61819 61820 62434 62975 62434 61820 61820 62967 62975 61820 62961 62967 62441 62431 61821 61829 61828 61822 62442 61836 61823 62443 61825 61824 61824 61826 62443 62443 61838 61825 62444 62443 61826 62986 62444 61826 61826 61827 62986 61827 62980 62986 61827 62434 62980 61828 61829 61830 61831 61830 61829 62446 61831 61829 61829 62445 62446 62450 61832 61831 62452 62450 61831 61831 62446 62452 61832 62450 62463 62463 61834 61832 61861 61853 61834 62463 61861 61834 61835 61841 62440 63553 63552 61836 61836 62983 63553 61836 62442 62983 61837 62448 62462 61837 61838 62448 62449 62448 61838 63563 62449 61838 61838 62443 63563 61839 61840 62436 62436 62399 61839 61840 62435 62436 61840 61860 62435 61841 61842 62440 62447 62440 61842 62456 62447 61842 61842 61854 62456 61843 61844 61855 62456 61855 61844 61844 62455 62456 62993 62455 61844 62994 62457 61845 63557 62994 61845 63576 63557 61845 61845 61863 63576 61845 61846 61863 61846 61856 61863 62458 61857 61847 62461 62458 61847 61847 61849 62461 61850 61849 61848 63571 61850 61848 61848 61851 63571 62990 62461 61849 62991 62990 61849 61849 61850 62991 63560 62991 61850 63571 63560 61850 63573 63571 61851 61851 62462 63573 62992 61860 61852 61852 61867 62992 61854 61855 62456 62996 61863 61856 61856 62995 62996 62472 61864 61857 61857 62459 62472 61857 62458 62459 61858 61859 62469 62997 62469 61859 61859 62465 62997 63566 62435 61860 61860 62992 63566 62463 61862 61861 62478 61871 61862 61862 62463 62478 61863 62996 63576 61864 61865 61872 61866 61865 61864 62472 61866 61864 61865 63018 63034 61865 62497 63018 61865 62480 62497 61865 61866 62480 63034 63009 61865 62486 62480 61866 62493 62486 61866 62494 62493 61866 61866 62475 62494 61866 62472 62475 61867 61868 62992 63005 62992 61868 61868 61870 63005 61868 61869 61870 62476 61870 61869 62477 62476 61869 61870 62453 63005 61870 62452 62453 62998 62452 61870 61870 62476 62998 61871 62476 62477 62478 62476 61871 63000 62465 61874 62490 62489 61875 61875 61876 62490 61877 61876 61875 62511 61877 61875 61875 62489 62511 61876 61879 62490 63007 62479 61877 61877 62511 63007 63023 61880 61878 62512 62490 61879 63023 62503 61880 61882 62500 62517 61882 62499 62500 61882 61884 62499 61882 61883 61884 62502 62499 61884 62526 62502 61884 61884 62525 62526 61885 61901 62522 62530 61898 61887 61889 61890 61904 61891 61890 61889 61904 61891 61889 61890 61892 61894 61893 61892 61890 61890 61891 61893 62507 61893 61891 62518 62507 61891 62527 62518 61891 61891 62523 62527 62524 62523 61891 61891 61904 62524 61895 61894 61892 62489 61895 61892 62492 62489 61892 62510 62492 61892 61892 61893 62510 61893 62507 62510 61894 61895 61896 61897 61896 61895 61895 62489 62512 61898 62530 62535 61899 61900 61913 61900 61930 62555 62555 61913 61900 61901 61902 62522 61903 61902 61901 62531 61903 61901 62540 61911 61903 61903 62531 62540 62541 62524 61904 62546 62541 61904 61904 62529 62546 61915 61907 61905 62533 61915 61905 63051 62533 61905 63052 63051 61905 61905 62543 63052 61905 61906 62543 61907 61914 62532 61915 61914 61907 61923 61922 61907 62532 61923 61907 62544 62534 61908 62552 62544 61908 63042 62552 61908 61908 62535 63042 62545 62536 61909 61909 61921 62545 63045 62539 61910 61910 62540 63045 61910 61911 62540 62547 62529 61912 62555 62547 61912 61912 61913 62555 62549 62542 61914 63041 62549 61914 61914 63040 63041 61914 61915 63040 62542 62532 61914 61915 62533 63040 63052 62543 61916 63055 63052 61916 61916 63054 63055 61916 61917 63054 61917 61924 63054 62545 61921 61918 61918 61919 62545 61920 61919 61918 61937 61920 61918 63043 62545 61919 63056 63043 61919 63065 63056 61919 61919 61920 63065 61920 61958 63065 61920 61938 61958 61920 61937 61938 62532 61933 61923 63062 63054 61924 61924 61925 63062 63063 63062 61925 61925 62551 63063 61925 61926 62551 61926 61936 62551 61927 62534 62550 62550 61928 61927 61928 62550 62553 63071 61936 61928 61928 62553 63071 61941 61940 61929 61942 61941 61929 61932 61931 61930 61943 61932 61930 61930 61931 62555 61931 61932 62561 62560 62555 61931 62561 62560 61931 61932 61951 62561 61932 61943 61951 61947 61934 61933 63079 61947 61933 61933 63067 63079 61933 62556 63067 61933 62542 62556 61933 62532 62542 61946 61939 61934 61947 61946 61934 61945 61944 61935 61935 61939 61945 63069 62551 61936 63070 63069 61936 63071 63070 61936 61959 61958 61938 61938 61949 61959 61946 61945 61939 61940 61941 62558 62559 62558 61941 61941 61963 62559 61941 61942 61963 61942 61962 61963 63090 61954 61944 61944 63081 63090 61944 61945 63081 61954 61948 61944 61945 61946 63081 61946 61955 63081 61946 61947 61955 61956 61955 61947 64635 61956 61947 61947 64633 64635 61947 63079 64633 61953 61952 61948 61954 61953 61948 62557 61959 61949 61950 61961 62559 63084 62557 61950 61950 62559 63084 61965 61957 61952 61966 61965 61952 61952 61953 61966 63094 61966 61953 61953 63091 63094 61953 61954 63091 61954 63090 63091 63090 63081 61955 63653 63090 61955 61955 61956 63653 63656 63653 61956 64150 63656 61956 64639 64150 61956 61956 64635 64639 61958 62557 63065 61958 61959 62557 61961 61968 62558 61961 62558 62559 61962 63634 63637 63637 61963 61962 63084 62559 61963 61963 63083 63084 64130 63083 61963 61963 64124 64130 61963 63637 64124 63095 61967 61965 61965 61966 63095 61966 63094 63095 64154 61972 61967 61967 63660 64154 61967 63095 63660 62576 62569 61969 62585 62576 61969 61969 62577 62585 61969 61970 62577 61970 61971 62577 62578 62577 61971 61971 61977 62578 61971 61973 61977 61972 62586 63106 62591 62586 61972 64154 62591 61972 61983 61977 61973 61976 61975 61974 62582 61976 61974 63663 62582 61974 61974 62592 63663 61974 61975 62592 63101 63097 61976 61976 62582 63101 62579 62578 61977 61977 61983 62579 63125 61980 61978 64652 63125 61978 61978 63104 64652 61978 62585 63104 61978 62576 62585 62586 61986 61979 63106 62586 61979 61979 62570 63106 61979 62565 62570 63125 63124 61980 61981 61984 63110 61987 61984 61981 61981 61982 61987 61983 61982 61981 63110 61983 61981 63110 62579 61983 63668 63118 61984 61984 61985 63668 61986 61985 61984 63111 61986 61984 61984 61987 63111 63117 63110 61984 63118 63117 61984 64656 63668 61985 61985 64158 64656 61985 62591 64158 61985 61986 62591 61986 62586 62591 62594 62593 61988 61988 61991 62594 61993 61992 61989 63129 61993 61989 61989 61990 63129 61990 63124 63129 62595 62594 61991 61991 61994 62595 61992 61993 61995 63132 61995 61993 63133 63132 61993 61993 63129 63133 63131 61996 61995 63132 63131 61995 61996 63131 63135 62600 62000 61999 62007 62002 62000 62000 62006 62007 62600 62006 62000 62596 62003 62001 62007 62005 62002 62606 62599 62003 62003 62605 62606 62003 62596 62605 62004 62603 63140 62006 62601 62602 62006 62600 62601 62015 62014 62009 63681 62608 62011 62011 63142 63681 62011 62012 63142 62012 62604 62606 62012 62602 62604 62012 62605 63142 62606 62605 62012 62613 62609 62014 62014 62015 62613 63686 62613 62015 62015 62614 63686 62612 62017 62016 63148 62612 62016 62017 62612 62615 63154 62620 62018 62018 62019 63154 63155 63154 62019 62019 62024 63155 63149 62618 62021 62021 62022 63149 62021 62618 62619 63690 63149 62022 62022 63687 63690 62621 62025 62023 62027 62026 62025 62623 62027 62025 62025 62621 62623 63164 62029 62026 62026 62027 63164 63704 63164 62027 62027 63156 63704 62027 62623 63156 63164 62032 62028 62028 62029 63164 63730 62035 62030 65677 63730 62030 62030 65675 65677 62030 62031 65675 62031 63193 65675 62031 62037 63193 62034 62033 62032 63177 62034 62032 63192 63177 62032 62032 63164 63192 62033 62034 62036 63177 62036 62034 63727 62626 62035 63730 63727 62035 63190 62632 62036 63192 63190 62036 62036 63177 63192 62037 62054 63193 62037 62049 62054 62634 62049 62037 62635 62051 62039 62039 62632 62635 62044 62041 62040 62047 62044 62040 62048 62047 62040 62040 62043 62048 62040 62042 62043 62044 62045 62053 62046 62045 62044 62047 62046 62044 62046 62047 62651 62651 62065 62046 62047 63197 63206 62047 62052 63197 62047 62048 62052 63206 62651 62047 62640 62052 62048 63194 62633 62050 63196 63194 62050 62050 62051 63196 62051 63195 63196 62051 62635 63195 62640 62639 62052 62052 62639 63197 63735 63193 62054 65678 63735 62054 62054 64708 65678 62054 64209 64708 62057 62056 62055 62056 62057 62061 62641 62061 62057 62642 62641 62057 62645 62059 62058 62058 62633 62645 62059 62645 63202 63205 62650 62061 62061 62641 63205 62064 62063 62062 62654 62064 62062 63747 62636 62063 62063 63208 63747 62063 62064 63208 63752 63208 62064 62064 62652 63752 62654 62652 62064 62657 62654 62066 62066 62067 62657 62067 62070 62657 62666 62070 62068 62068 62069 62081 62070 62656 62657 62666 62656 62070 62659 62072 62071 62071 62658 62659 62659 62073 62072 64212 63222 62073 62073 63755 64212 62073 62659 63755 62663 62649 62074 62669 62663 62074 62074 62668 62669 62074 62664 62668 62074 62075 62664 62665 62664 62075 62075 62077 62665 63242 62667 62076 63761 63242 62076 62076 63222 63761 63213 62079 62078 62079 62082 62083 63759 62082 62079 62079 63218 63759 62079 63213 63218 63764 63225 62082 62082 63228 63764 63237 63228 62082 64219 63237 62082 64220 64219 62082 62082 63758 64220 62082 63757 63758 63759 63757 62082 63225 62083 62082 62695 62681 62083 63225 62695 62083 62676 62674 62084 62084 62090 62676 62085 63219 63221 63760 63219 62085 62085 63226 63760 63227 63226 62085 62085 62086 63227 63221 62670 62085 62086 62671 63229 63229 63227 62086 63234 63230 62087 62087 62672 63234 63766 62672 62087 62087 62088 63766 62088 62687 63766 62088 62682 62687 63242 63235 62089 62089 62667 63242 62684 62683 62089 63235 62684 62089 62683 62102 62091 62092 62093 62688 62693 62688 62093 63255 62693 62093 62093 62705 63255 62093 62103 62705 62681 62095 62094 62095 62681 62695 62097 62096 62095 63233 62097 62095 62095 63228 63233 62095 62695 63228 62114 62104 62096 62096 62097 62114 62706 62114 62097 63249 62706 62097 62097 63233 63249 62098 62099 62105 62100 62099 62098 63252 62100 62098 63774 63252 62098 62098 62696 63774 62098 62105 62696 62682 62101 62099 62099 62100 62682 62099 62101 62105 63766 62687 62100 63773 63766 62100 62100 63252 63773 62687 62682 62100 62102 62683 62685 62103 62704 62705 62103 62113 62704 62698 62696 62105 62106 62111 62116 62106 62107 62109 62108 62107 62106 62116 62108 62106 62120 62110 62107 62107 62119 62120 62107 62118 62119 62700 62118 62107 62107 62108 62700 62110 62109 62107 62702 62700 62108 63239 62702 62108 63241 63239 62108 62108 62689 63241 62108 62116 62689 62111 62112 62116 63248 62116 62112 62112 62703 63248 62113 62117 62704 63251 63250 62114 62114 62706 63251 62115 62122 62710 62691 62689 62116 63248 62691 62116 62709 62704 62117 62711 62119 62118 63776 62711 62118 62118 62700 63776 62717 62120 62119 62119 62713 62717 62119 62711 62713 62135 62128 62120 62717 62135 62120 62130 62124 62121 62718 62130 62121 63270 62718 62121 62121 62129 63270 62122 62123 62710 62123 62126 62710 62127 62126 62123 63257 62131 62125 63258 62710 62126 62126 62714 63258 62126 62127 62714 62127 62133 62714 62135 62134 62128 62129 62725 63270 62129 62132 62725 62131 63257 63272 62726 62725 62132 62132 62724 62726 62716 62714 62133 62733 62716 62133 62137 62136 62134 62717 62137 62134 62134 62135 62717 62136 62137 62141 63280 62141 62137 62137 62722 63280 62137 62717 62722 62727 62148 62138 62138 62153 62727 62737 62153 62138 62138 62718 62737 63276 62739 62139 63277 63276 62139 63285 63277 62139 62139 62140 63285 62140 62155 63285 62141 62735 62736 63280 62735 62141 62731 62144 62142 63292 62745 62143 63809 63292 62143 62143 62144 63809 62144 63806 63809 62144 63278 63806 62144 62731 63278 62145 62160 62751 62145 62150 62160 62145 62146 62150 62146 62147 62150 62148 62147 62146 62744 62150 62147 62147 62727 62744 62147 62148 62727 62744 62160 62150 62151 62152 62738 62153 62152 62151 63290 62153 62151 63800 63290 62151 63801 63800 62151 62151 62738 63801 62152 62153 62737 62152 62737 62738 62743 62727 62153 63291 62743 62153 63295 63291 62153 62153 63289 63295 63290 63289 62153 63816 63810 62154 62154 63300 63816 62154 63296 63300 62154 62155 63296 62156 62155 62154 63810 62156 62154 62155 62156 63285 62156 63283 63285 63810 63283 62156 62773 62186 62157 62157 62158 62773 62159 62158 62157 62772 62159 62157 62158 62159 64834 64296 62773 62158 64844 64296 62158 62158 64834 64844 62159 63311 64821 62159 62772 63311 62159 64821 64834 62160 62748 62751 62750 62748 62160 62160 62746 62750 62160 62744 62746 62167 62166 62161 62757 62167 62161 62161 62745 62757 62747 62163 62162 62162 62164 62747 62165 62164 62162 63297 62759 62163 62163 62747 63297 62164 62175 62747 63306 62772 62167 62167 62757 63306 62168 62755 62761 62168 62753 62755 63830 63303 62169 62169 63310 63830 63303 62170 62169 63303 62756 62170 62171 62764 63308 62171 62173 62764 63308 62172 62171 63308 62763 62172 62765 62764 62174 62174 62177 62765 63299 62747 62175 62175 62176 63299 63819 63299 62176 63823 63819 62176 62766 62765 62177 62177 62182 62766 62186 62179 62178 62179 62773 62774 62179 62186 62773 62202 62199 62180 62180 62181 62202 62204 62202 62181 63338 62204 62181 62181 62188 63338 62181 62187 62188 62182 62749 62766 62767 62749 62182 62182 62183 62767 62183 62189 62767 62184 62185 62776 62184 62776 62779 62185 62197 62776 62187 62774 63829 63313 62188 62187 63829 63313 62187 63843 63338 62188 62188 63839 63843 62188 63827 63839 62188 63313 63827 62193 62192 62191 62192 62770 62771 62192 62771 62775 62198 62196 62194 62194 62197 62198 62776 62197 62194 62778 62776 62194 62194 62777 62778 62194 62195 62777 62196 62195 62194 63314 62777 62195 62195 62787 63314 62195 62785 62787 62195 62196 62785 62791 62790 62196 62196 62198 62791 62786 62785 62196 62790 62786 62196 62201 62198 62197 62198 62209 62791 62200 62206 63331 62200 62205 62206 62204 62203 62202 62203 62204 62208 63330 62208 62204 63337 63330 62204 63338 63337 62204 62207 62206 62205 63848 63331 62206 63851 63848 62206 62206 63847 63851 62206 62207 63847 62207 63344 63847 62207 62208 63344 62208 63330 63344 62209 62212 62791 62210 63320 63849 62210 62211 63320 62211 63319 63320 62211 62789 63319 63345 62791 62212 62212 62792 63345 62800 62799 62213 62215 62216 62244 62217 62233 62810 62810 62797 62217 62218 62824 62825 62218 62819 62824 62218 62818 62819 62218 62802 62818 62218 62219 62802 62220 62219 62218 62825 62220 62218 62825 62225 62220 62221 62803 63360 63359 62802 62221 63360 63359 62221 62223 62814 63373 63365 62224 62223 63882 63365 62223 62223 63373 63882 63887 62801 62224 62224 63365 63887 62225 62824 62839 62825 62824 62225 62227 62228 62804 62229 62228 62227 62816 62229 62227 62227 62235 62816 63355 62804 62228 63374 63355 62228 64387 63374 62228 62228 62229 64387 62229 62806 64387 62807 62806 62229 62815 62807 62229 62816 62815 62229 62236 62232 62230 62230 62231 62236 62808 62236 62231 62809 62808 62231 62232 62236 62808 62809 62233 62232 62232 62808 62809 62233 62809 62810 62246 62238 62237 62237 62240 62246 62238 62827 63382 62238 62826 62827 62238 62246 62826 63382 62821 62238 62835 62828 62239 62248 62246 62240 62240 62245 62248 62819 62817 62242 62824 62819 62242 62839 62824 62242 62817 62243 62242 63396 62251 62243 62243 62840 63396 62243 62817 62840 62245 63390 63930 62245 62838 63390 62245 62252 62838 62245 62247 62248 62830 62247 62245 62837 62830 62245 63930 62837 62245 62246 62247 62826 62248 62247 62246 62830 62826 62247 62262 62260 62249 62844 62262 62249 62845 62844 62249 62249 62250 62845 62250 62251 62845 63928 62845 62251 62251 63396 63928 62252 62264 62838 62253 62256 62831 62253 62254 62257 62255 62254 62253 62831 62255 62253 63387 62850 62255 62255 62831 63387 63393 62843 62258 62258 62259 63393 62259 62848 63393 62262 62261 62260 62267 62266 62261 62855 62267 62261 62261 62849 62855 62261 62262 62849 63405 62849 62262 62262 62844 63405 62273 62264 62263 63414 62273 62263 62263 62857 63414 62263 62856 62857 62263 62271 62856 62846 62838 62264 62264 62273 62846 62847 62269 62265 63947 62847 62265 64430 63947 62265 62265 63398 64430 62265 62850 63398 63413 62268 62267 62267 62855 63413 63400 62854 62268 63402 63400 62268 63933 63402 62268 63939 63933 62268 62268 63413 63939 62847 62281 62269 63394 62848 62270 63408 63394 62270 62270 62851 63408 62271 62272 62856 62861 62856 62272 62272 62860 62861 63397 62846 62273 63414 63397 62273 62862 62858 62275 62276 62286 62287 62277 62287 62859 63961 63960 62278 64964 63961 62278 62278 64958 64964 62278 64952 64958 62278 64950 64952 62278 62279 64950 62280 62279 62278 63960 62280 62278 62279 63943 64950 63952 63943 62279 62279 62847 63952 62279 62280 62847 63427 62874 62280 63960 63427 62280 62280 62281 62847 62874 62281 62280 62282 62283 62299 62868 62299 62283 62284 62299 62871 62284 62869 62878 62871 62869 62284 62287 62286 62285 62864 62287 62285 63410 62864 62285 62285 62288 63410 62285 62286 62288 62852 62288 62286 62865 62859 62287 62866 62865 62287 62287 62864 62866 63412 63410 62288 63421 63412 62288 62288 62853 63421 62288 62852 62853 62289 62872 62873 62289 62295 62872 62292 62291 62290 62297 62296 62291 62877 62297 62291 62291 62292 62877 63437 62877 62292 62292 62293 63437 62293 63427 63437 62293 62294 63427 62294 62874 63427 63417 62872 62295 63424 63417 62295 62295 62875 63424 63443 62883 62297 62297 62877 63443 62298 63446 63447 62299 62868 62871 63432 62882 62300 63441 63432 62300 62300 62880 63441 62300 62879 62880 62300 62304 62879 62883 62302 62301 63451 62887 62302 62302 62884 63451 62302 62883 62884 62312 62304 62303 62315 62312 62303 62303 62305 62315 62888 62879 62304 62304 62312 62888 62893 62315 62305 62305 62316 62893 62887 62307 62306 63453 62889 62307 62307 62887 63453 63455 62310 62308 63471 63455 62308 62891 62311 62309 63461 62891 62309 62309 63458 63461 62309 63457 63458 62309 62890 63457 62309 62310 62890 63455 62890 62310 63477 62888 62312 62312 62892 63477 62312 62315 62892 62889 62320 62313 62314 62325 62331 62893 62892 62315 62898 62893 62316 62316 62327 62898 62317 62333 62334 63482 63481 62318 63483 63482 62318 62318 62894 63483 62318 62319 62894 62319 62320 62895 62895 62894 62319 62901 62895 62320 62320 62889 62901 62902 62325 62321 62321 62329 62902 62322 62323 63983 62324 62323 62322 62331 62324 62322 63470 62331 62322 63983 63470 62322 62323 62916 63983 62896 62332 62326 62899 62898 62327 63479 62899 62327 62327 62339 63479 62327 62328 62339 62335 62334 62333 62900 62335 62333 63466 62900 62333 63467 63466 62333 62922 62347 62334 62334 62335 62922 63988 62922 62335 63990 63988 62335 62335 63480 63990 62335 62900 63480 62336 64007 64017 62336 62337 64007 62338 62337 62336 64017 62338 62336 62337 62360 63491 62370 62360 62337 62337 62338 62370 62337 62919 64007 63491 62919 62337 63504 62370 62338 62338 62404 63504 62338 62403 62404 63515 62403 62338 64017 63515 62338 62339 62911 63479 62339 62905 62911 62350 62341 62340 62341 62350 62914 64482 64005 62342 62342 62343 64482 62344 62343 62342 62906 62344 62342 62927 62906 62342 62343 64481 64482 62343 62907 64481 62908 62907 62343 62343 62344 62908 63976 62908 62344 62344 62904 63976 62344 62903 62904 62906 62903 62344 62345 62357 62909 62920 62369 62346 62346 62358 62920 62921 62364 62347 63488 62921 62347 62347 62922 63488 63489 62373 62348 63493 63489 62348 62348 62365 63493 62350 62351 62914 62352 62351 62350 64002 63994 62351 62351 63495 64002 62351 62352 63495 63490 62914 62351 63994 63490 62351 62352 62353 63495 64004 63495 62353 62353 62917 64004 62353 62354 62917 62919 62909 62357 63499 62919 62357 62357 62928 63499 62358 62361 62920 62920 62361 62359 62359 62369 62920 62359 62360 62369 62361 62360 62359 62360 62361 63491 62370 62369 62360 62361 62909 62919 62361 62919 63491 62910 62905 62362 62362 62363 62910 63487 62910 62363 63501 63487 62363 62363 62935 63501 62363 62929 62935 62930 62372 62364 62364 62921 62930 62365 62940 63493 62366 62923 62931 62366 62367 62923 62925 62923 62367 62367 62913 62925 62367 62912 62913 62903 62383 62368 62369 62370 62402 62418 62402 62370 62951 62418 62370 63504 62951 62370 62371 62387 62390 62393 62387 62371 62371 62392 62393 62371 62372 62392 62930 62392 62372 63489 62912 62373 62396 62376 62374 62376 62375 62374 62375 62396 63500 62375 62376 62396 63500 62928 62375 64014 62940 62378 62378 63507 64014 62378 62939 63507 62933 62926 62379 62380 62381 62382 62964 62382 62381 63517 62964 62381 62955 62946 62382 62964 62955 62382 62383 62906 62927 62383 62903 62906 62419 62397 62384 62384 62416 62419 62417 62416 62384 62384 62385 62417 62385 62405 62417 62418 62405 62385 62385 62402 62418 63516 62407 62386 62386 62428 63516 62386 62421 62428 62391 62390 62387 62942 62391 62387 62387 62388 62942 62389 62388 62387 62938 62389 62387 62387 62393 62938 62952 62942 62388 62954 62952 62388 62388 62389 62954 64509 64030 62389 62389 64018 64509 62389 64012 64018 62389 62938 64012 64030 62954 62389 62942 62408 62391 63502 62393 62392 62392 62930 63502 63506 62938 62393 64020 63506 62393 62393 63502 64020 62944 62943 62394 62945 62944 62394 62396 62401 62949 62396 62949 63500 62397 62419 62428 62428 62420 62397 63510 62939 62398 63528 63510 62398 62398 62958 63528 62398 62957 62958 63545 63544 62399 62399 62436 63545 63533 62437 62399 63544 63533 62399 62400 62947 62965 62401 62410 62948 62401 62948 62949 62405 62404 62403 62417 62405 62403 63508 62950 62403 63515 63508 62403 62404 62405 63504 62405 62951 63504 62405 62418 62951 63505 62935 62406 62406 62407 63505 64027 63505 62407 62407 63524 64027 62407 63516 63524 62408 62942 62952 62962 62960 62409 62409 62943 62962 62410 62411 62948 62411 62412 62948 62415 62412 62411 62949 62948 62412 63512 62949 62412 63514 63512 62412 62412 62413 63514 62414 62413 62412 62415 62414 62412 62413 62950 63514 62413 62414 62950 62414 62415 62950 62426 62419 62416 62419 62426 62428 62428 62421 62420 62956 62425 62422 63525 62956 62422 63526 63525 62422 62422 62423 63526 62423 63518 63526 62423 62953 63518 62423 62952 62953 62959 62957 62424 63525 62959 62424 62424 62956 63525 62424 62425 62956 62426 62427 62428 62966 62428 62427 62971 62966 62427 62427 62433 62971 63523 63516 62428 62428 62430 63523 62428 62429 62430 62966 62429 62428 64039 62430 62429 62429 64038 64039 62429 62971 64038 62429 62966 62971 64514 63523 62430 62430 64039 64514 62431 62441 62978 62978 62432 62431 62979 62438 62432 62432 62978 62979 62973 62971 62433 62433 62969 62973 62434 62975 62980 63566 63545 62435 63545 62436 62435 63533 62972 62437 63536 62974 62438 62438 62979 63536 63522 62977 62439 62439 62963 63522 62447 62441 62440 62441 62447 62978 63549 62983 62442 62442 62984 63549 62443 62444 63563 62444 62987 63563 62444 62986 62987 62988 62446 62445 62445 62976 62988 62446 62451 62452 62988 62451 62446 62981 62978 62447 62447 62454 62981 62455 62454 62447 62456 62455 62447 63582 62462 62448 63583 63582 62448 62448 62449 63583 64059 63583 62449 62449 63564 64059 62449 63563 63564 62450 62452 62470 62470 62463 62450 62453 62452 62451 63575 62453 62451 62451 63005 63575 63566 63005 62451 62451 63545 63566 62451 63544 63545 64046 63544 62451 62451 62988 64046 62998 62470 62452 63575 63005 62453 64058 62981 62454 62454 62455 64058 62455 63567 64058 62455 62993 63567 63557 62985 62457 62457 62994 63557 62460 62459 62458 62464 62460 62458 62458 62461 62464 62473 62472 62459 62459 62460 62473 62474 62473 62460 63568 62474 62460 62460 62464 63568 62989 62464 62461 63561 62989 62461 63562 63561 62461 62461 62990 63562 63574 63573 62462 63582 63574 62462 62463 62470 62478 63569 63568 62464 62464 62989 63569 63584 62997 62465 62465 63011 63584 62465 63000 63011 62466 62467 63001 62468 62467 62466 62997 62468 62466 62466 62469 62997 64066 63001 62467 62467 62468 64066 62468 64065 64066 62468 63584 64065 62468 62997 63584 62470 62476 62478 62998 62476 62470 62471 62479 62999 62999 62995 62471 62472 62473 62475 62473 62474 62475 63589 62475 62474 62474 63568 63589 63017 62494 62475 63589 63017 62475 63007 62999 62479 62480 62496 62497 62480 62495 62496 62480 62486 62495 63021 62482 62481 62481 63019 63021 63021 62483 62482 63022 62484 62483 62483 63020 63022 63021 63020 62483 63022 62485 62484 63601 63000 62485 62485 63600 63601 62485 63022 63600 62486 62487 62495 62488 62487 62486 62493 62488 62486 62496 62495 62487 62487 62488 62496 62513 62496 62488 63025 62513 62488 62488 62493 63025 62489 62490 62512 62489 62491 62511 62492 62491 62489 63591 62511 62491 62491 63014 63591 62491 63012 63014 62491 62492 63012 62492 62508 63012 62510 62508 62492 63613 63025 62493 62493 63016 63613 62493 62494 63016 63017 63016 62494 63616 62497 62496 62496 63033 63616 62496 62513 63033 63618 63018 62497 62497 63616 63618 63029 63028 62498 63031 63029 62498 62498 62499 63031 62500 62499 62498 63028 62500 62498 62499 63030 63031 62499 62501 63030 62502 62501 62499 63027 62517 62500 63028 63027 62500 63612 63030 62501 62501 63037 63612 62501 63036 63037 62501 62502 63036 62502 62526 63036 62503 63023 63024 62504 62508 62509 63012 62508 62504 63013 63012 62504 62504 62505 63013 62506 62505 62504 62509 62506 62504 63595 63013 62505 64551 63595 62505 62505 64086 64551 62505 62506 64086 62506 64085 64086 62506 62528 64085 62506 62509 62528 62507 62508 62510 62509 62508 62507 62518 62509 62507 62509 62527 62528 62509 62518 62527 63015 63007 62511 63591 63015 62511 62513 63025 63613 63616 63033 62513 62513 63613 63616 62516 62515 62514 62515 62552 63042 63064 62552 62515 64123 63064 62515 62515 62521 64123 62515 62516 62521 62516 62519 62521 62520 62519 62516 63611 62520 62516 63614 63611 62516 62516 63026 63614 62516 62517 63026 63027 63026 62517 64113 62521 62519 64120 64113 62519 64582 64120 62519 65614 64582 62519 62519 65127 65614 62519 62520 65127 65614 65127 62520 62520 65600 65614 62520 65108 65600 62520 63611 65108 62521 63064 64123 64113 63064 62521 64085 63032 62523 62523 63625 64085 62523 62524 63625 63032 62527 62523 62524 63039 63625 62524 62541 63039 62538 62537 62525 63044 62538 62525 62525 62536 63044 63036 62526 62525 62525 62537 63036 63032 62528 62527 62528 63032 64085 63057 62546 62529 63058 63057 62529 62529 62547 63058 63042 62535 62530 64110 62540 62531 62531 63620 64110 63041 63040 62533 63051 63041 62533 62534 62544 62550 62536 62545 63044 62537 62538 63043 63038 63036 62537 63043 63038 62537 63044 63043 62538 63635 63045 62540 64110 63635 62540 63625 63039 62541 62541 63057 63625 62541 62546 63057 62549 62548 62542 63053 62556 62542 62542 62548 63053 62553 62550 62544 62544 62552 62553 62545 63043 63044 62547 62555 63058 64122 63053 62548 62548 62549 64122 62549 63629 64122 62549 63051 63629 62549 63041 63051 63069 63063 62551 62554 62553 62552 63645 62554 62552 63646 63645 62552 64146 63646 62552 62552 63640 64146 62552 63064 63640 62553 62554 63071 63072 63071 62554 63645 63072 62554 64604 63058 62555 62555 63050 64604 63074 63050 62555 62555 62560 63074 62556 63059 63067 63061 63059 62556 62556 63053 63061 63082 63065 62557 63084 63082 62557 62560 62562 63074 62560 62561 62562 62564 62562 62561 62561 62563 62564 64140 63074 62562 64141 64140 62562 62562 62564 64141 63096 62564 62563 63097 63096 62563 64624 64141 62564 62564 64147 64624 62564 63096 64147 62566 62573 62574 62566 62572 62573 62566 62567 62572 62568 62567 62566 62575 62568 62566 62581 62575 62566 62566 62574 62581 62567 62571 62572 63099 62571 62567 63100 63099 62567 63659 63100 62567 62567 63102 63659 63103 63102 62567 62567 62568 63103 62568 62584 63103 62568 62575 62584 62573 62572 62571 63098 62573 62571 62571 63087 63098 63099 63087 62571 63662 62574 62573 62573 63658 63662 62573 63098 63658 63662 63107 62574 62574 62580 62581 63107 62580 62574 62575 62583 62584 62575 62581 62583 63105 62585 62577 62577 62578 63105 62578 62579 63105 63661 63105 62579 63667 63661 62579 62579 63110 63667 63107 62589 62580 62589 62581 62580 62590 62583 62581 62581 62587 62590 62589 62587 62581 64147 63101 62582 64153 64147 62582 62582 63664 64153 62582 63663 63664 62590 62584 62583 63114 63103 62584 62584 62590 63114 63105 63104 62585 63113 62590 62587 63122 63113 62587 63128 63122 62587 62587 62588 63128 62589 62588 62587 62588 63112 63128 62588 62589 63112 62589 63107 63112 62590 63113 63114 62591 64154 64158 62592 63126 63663 62592 62593 63126 63127 63126 62593 62593 62594 63127 63130 63127 62594 63134 63130 62594 62594 62595 63134 62596 62597 62605 63142 62605 62597 63678 63142 62597 62597 63139 63678 62601 62600 62598 62598 62599 62601 62604 62601 62599 62606 62604 62599 62604 62602 62601 63141 63140 62603 63143 63141 62603 63147 63146 62607 62607 62608 63147 63681 63147 62608 62609 63141 63143 62609 62613 63141 62612 62611 62610 62616 62612 62610 63685 62616 62610 64174 63685 62610 62610 62611 64174 63148 63146 62611 62611 62612 63148 62611 63683 64174 62611 63147 63683 62611 63146 63147 62616 62615 62612 63144 63141 62613 63145 63144 62613 63686 63145 62613 62614 63154 63692 62614 62620 63154 63692 63686 62614 63691 63687 62616 62616 63688 63691 62616 63685 63688 62622 62619 62617 63150 62622 62617 62617 63149 63150 62617 62618 63149 62619 62618 62617 62624 62623 62621 62621 62622 62624 63694 62624 62622 62622 63150 63694 62623 62624 63156 63698 63156 62624 62624 63694 63698 63705 63155 62625 63716 63705 62625 62625 62626 63716 63727 63716 62626 62631 62630 62627 62627 62628 62631 62629 62628 62627 62630 62629 62627 63166 62631 62628 62628 62629 63166 62629 63163 63166 62629 62630 63163 63169 63163 62630 62630 62631 63169 63185 63169 62631 62631 63166 63185 63190 62635 62632 63194 62645 62633 62635 63190 63195 63747 62638 62636 62636 62639 62640 62636 62638 62639 62637 63746 64198 62637 63745 63746 62637 62638 63745 62639 62638 62637 63748 62639 62637 64200 63748 62637 62637 64198 64200 63747 63745 62638 63203 63197 62639 63748 63203 62639 62641 63198 63205 62641 62643 63198 62641 62642 62643 63199 62643 62642 63200 63199 62642 63201 63200 62642 63199 63198 62643 62645 63194 63202 62646 63203 63207 62646 63197 63203 63206 63197 62646 63212 63206 62646 62646 62647 63212 62648 62647 62646 63207 62648 62646 64208 63210 62647 62647 63753 64208 62647 62648 63753 62647 63211 63212 62647 63210 63211 64701 63753 62648 64702 64701 62648 62648 63207 64702 62663 62655 62649 63204 62660 62650 63205 63204 62650 62651 63206 63212 62654 62653 62652 62652 63214 63752 62652 62653 63214 62653 62654 62657 62653 62657 63214 64713 64209 62655 64714 64713 62655 62655 63220 64714 62655 62663 63220 63219 62657 62656 63221 63219 62656 62656 62666 63221 63219 63214 62657 63212 63211 62658 63211 62659 62658 62659 63211 63755 63217 63215 62660 62660 63204 63217 62660 62661 62662 63215 62661 62660 63218 63213 62661 63759 63218 62661 62661 63756 63759 64205 63756 62661 62661 63215 64205 62663 62669 63220 62677 62668 62664 62664 62665 62677 62666 62670 63221 63223 62669 62668 62668 62677 63223 62669 63223 63224 63763 63220 62669 62669 63762 63763 62669 63224 63762 62671 62672 63229 62673 62672 62671 62679 62673 62671 62680 62679 62671 63230 62680 62671 62672 62673 63231 64211 63229 62672 62672 63767 64211 62672 63766 63767 62672 63231 63234 62673 62679 63231 62678 62677 62674 62674 62675 62678 62676 62675 62674 63232 62678 62675 62677 62678 63223 63224 63223 62678 63236 63224 62678 62678 63232 63236 62679 62680 63231 63234 63231 62680 62680 63230 63234 62683 62684 62685 63235 62685 62684 63235 62692 62685 63236 63232 62686 63238 63236 62686 63244 63238 62686 63245 63244 62686 62688 62694 63243 62688 62693 62694 62689 62690 63241 62691 62690 62689 64237 63241 62690 62690 64228 64237 62690 63768 64228 62690 62691 63768 62691 63242 63768 63248 63242 62691 63248 62703 62692 62692 63242 63248 62692 63235 63242 63771 62694 62693 64239 63771 62693 62693 63777 64239 62693 63255 63777 63772 63243 62694 62694 63771 63772 63764 63228 62695 62695 63225 63764 63775 63774 62696 62696 62697 63775 62698 62697 62696 63778 63775 62697 62697 62698 63778 62698 63260 63778 62698 62710 63260 62699 62702 63239 62699 62700 62702 62701 62700 62699 63239 62701 62699 62700 63253 63776 63254 63253 62700 62700 62701 63254 63770 63254 62701 62701 63246 63770 62701 63239 63246 63255 62705 62704 63780 63255 62704 62704 62709 63780 62706 64771 64772 62706 64230 64771 62706 63249 64230 62706 62707 63251 62708 62707 62706 64772 62708 62706 65298 64251 62707 65299 65298 62707 65734 65299 62707 62707 62708 65734 64251 63251 62707 62708 64772 65734 62710 63259 63260 62710 63258 63259 62711 62712 62713 63776 62712 62711 63256 62713 62712 64247 63256 62712 62712 63786 64247 62712 63776 63786 62723 62717 62713 63790 62723 62713 62713 63256 63790 62714 62715 63258 62716 62715 62714 63793 63258 62715 62715 63279 63793 62715 62733 63279 62715 62716 62733 62723 62722 62717 63270 62737 62718 63261 62721 62719 62719 62728 63261 62730 62728 62719 62721 62720 62719 62721 63261 63262 62722 62723 63280 63798 63280 62723 64798 63798 62723 62723 63790 64798 63804 62726 62724 62724 62734 63804 62736 62734 62724 63271 63270 62725 62725 62726 63271 63799 63271 62726 63805 63799 62726 62726 63804 63805 62727 62743 62744 62730 62729 62728 64269 63261 62728 62728 62729 64269 62729 62730 63276 64796 64269 62729 62729 63276 64796 62730 62739 63276 62731 63266 63278 63279 62733 62732 63288 63279 62732 63808 63288 62732 62732 62741 63808 62732 62740 62741 62736 62735 62734 64273 63804 62734 62734 63807 64273 62734 62735 63807 62735 63281 63807 62735 63280 63281 63270 62738 62737 62738 63270 63271 62738 63799 63801 62738 63271 63799 62742 62741 62740 62741 63293 63813 62741 62742 63293 63813 63808 62741 62742 62758 63293 62746 62744 62743 63294 62746 62743 62743 63291 63294 63292 62757 62745 63294 62750 62746 63298 63297 62747 64284 63298 62747 62747 63299 64284 62768 62751 62748 62775 62768 62748 62748 62749 62775 62750 62749 62748 62749 62767 62775 62749 62750 62766 63304 62766 62750 62750 63294 63304 62754 62753 62752 63302 62754 62752 62752 62756 63302 63301 62755 62753 63305 63301 62753 62753 62754 63305 64817 63305 62754 62754 64816 64817 62754 63302 64816 63301 62761 62755 63303 63302 62756 63312 63306 62757 63814 63312 62757 62757 63292 63814 62758 62759 63297 63297 63293 62758 63300 63296 62760 62762 62763 62769 64286 63823 62762 62762 62769 64286 63308 63307 62763 63307 62769 62763 62764 62765 63309 63826 63308 62764 62764 63820 63826 62764 63309 63820 62765 63304 63309 62765 62766 63304 62771 62770 62768 62775 62771 62768 64289 64286 62769 64292 64289 62769 62769 63825 64292 62769 63307 63825 62772 63306 63312 63312 63311 62772 63831 62774 62773 64296 63831 62773 63832 63829 62774 62774 63831 63832 62776 62778 62779 63317 62778 62777 62777 63316 63317 62777 63314 63316 63317 62779 62778 63842 63840 62780 62780 62781 63842 62782 62781 62780 64309 63842 62781 64311 64309 62781 62781 64310 64311 64316 64310 62781 62781 63845 64316 62781 62782 63845 62782 63844 63845 62782 63841 63844 63319 62789 62783 62783 62784 63319 63842 63319 62784 62784 63840 63842 62784 63318 63840 62788 62787 62785 63336 62788 62785 62785 63334 63336 62785 62786 63334 63343 63334 62786 62786 63341 63343 62786 62790 63341 62787 63315 63835 62787 62788 63315 63836 63314 62787 62787 63835 63836 63327 63315 62788 63336 63327 62788 62790 62791 63341 63345 63341 62791 63853 63345 62792 62792 63352 63853 63353 63352 62792 62792 62793 63353 62793 62797 63353 63867 62800 62794 63879 63867 62794 62794 63868 63879 62794 62795 63868 62796 62795 62794 62800 62796 62794 64317 63868 62795 62795 63849 64317 62795 62796 63849 62797 62810 63353 62798 62799 63361 63878 63361 62799 62799 63867 63878 62799 62800 63867 63887 63384 62801 63881 62818 62802 62802 63377 63881 64372 63377 62802 62802 63876 64372 62802 63359 63876 63865 63864 62803 63864 63360 62803 62804 63354 63356 63355 63354 62804 62805 63362 63367 62805 63356 63362 65877 64387 62806 62806 65876 65877 65883 65876 62806 62806 64906 65883 62806 64885 64906 62806 62807 64885 62807 62828 62833 62807 62815 62828 62807 63897 64885 62807 62834 63897 62807 62833 62834 62811 62810 62809 63376 62811 62809 63363 63353 62810 62810 62811 63363 63375 63363 62811 63376 63375 62811 63381 62813 62812 62812 63379 63381 63381 62814 62813 63884 63373 62814 62814 63381 63884 62815 62823 62828 62815 62816 62823 62841 62840 62817 63881 62841 62817 62817 62818 63881 62819 62818 62817 63382 62822 62820 62820 62821 63382 63382 63380 62822 62829 62827 62826 62830 62829 62826 63895 63383 62827 63903 63895 62827 62827 62829 63903 63383 63382 62827 62835 62833 62828 62829 62836 63903 62837 62836 62829 62829 62830 62837 62831 63385 63387 62832 63389 63898 62832 62835 63389 62832 62833 62835 62834 62833 62832 63898 62834 62832 63898 63897 62834 64386 63903 62836 62836 64385 64386 62836 62837 64385 62837 63930 64385 63407 63390 62838 62838 63397 63407 62838 62846 63397 63904 63396 62840 62840 63902 63904 62840 63901 63902 62840 63378 63901 62840 62841 63378 62841 63377 63378 63881 63377 62841 62842 62843 63914 64403 63914 62843 62843 63922 64403 62843 63391 63922 63392 63391 62843 63393 63392 62843 63934 63405 62844 62844 63395 63934 62844 62845 63395 63928 63395 62845 62847 63947 63952 63394 63393 62848 63405 62855 62849 63907 63398 62850 62850 63387 63907 62851 62858 63409 63409 63408 62851 62854 62853 62852 62853 63401 63421 62853 62854 63401 62854 63400 63401 63939 63413 62855 62855 63403 63939 63404 63403 62855 63935 63404 62855 62855 63405 63935 63418 62857 62856 62856 62861 63418 63946 63414 62857 62857 63945 63946 62857 63418 63945 63420 63409 62858 62858 62863 63420 62858 62862 62863 62867 62860 62859 63425 62867 62859 62859 62865 63425 63419 62861 62860 63423 63419 62860 62860 62867 63423 63419 63418 62861 62873 62863 62862 62873 62872 62863 62863 62872 63420 63422 62866 62864 62864 63410 63422 63426 63425 62865 62865 63422 63426 62865 62866 63422 63949 63423 62867 62867 63425 63949 62868 62870 62871 62886 62878 62869 63429 62886 62869 63968 63429 62869 62869 63962 63968 62869 63430 63962 62869 62870 63430 62871 62870 62869 62870 63428 63430 62872 63417 63420 63434 63424 62875 63435 63434 62875 62875 62876 63435 62876 63433 63435 62876 62882 63433 63445 63443 62877 63965 63445 62877 63966 63965 62877 62877 63959 63966 62877 63437 63959 62886 62885 62878 62881 62880 62879 62888 62881 62879 63442 63441 62880 62880 62881 63442 62881 62888 63477 63475 63442 62881 63477 63475 62881 62882 63431 63433 63432 63431 62882 63443 62884 62883 63970 63451 62884 62884 63444 63970 62884 63443 63444 63462 62897 62885 62885 62886 63462 62886 63452 63462 62886 63429 63452 63973 63453 62887 62887 63451 63973 63486 62901 62889 62889 63454 63486 62889 63453 63454 62890 63456 63457 62890 63455 63456 63461 63446 62891 62892 63465 63477 62892 62893 63465 62893 63464 63465 63478 63464 62893 62893 62898 63478 62894 62895 63483 62895 62901 63485 63485 63483 62895 62896 62897 62904 62904 62903 62896 63462 62904 62897 62898 62899 63478 63987 63478 62899 62899 63479 63987 62900 63466 63480 63486 63485 62901 62904 63462 63976 62905 62910 62911 62907 63975 64481 64971 63975 62907 62907 62908 64971 62908 63977 64971 62908 63976 63977 63487 62911 62910 63992 63479 62911 62911 63487 63992 63489 62913 62912 62913 62924 62925 64000 62924 62913 64001 64000 62913 62913 63494 64001 62913 63489 63494 62914 62915 62916 63490 62915 62914 63993 62916 62915 64463 63993 62915 64477 64463 62915 62915 63490 64477 63993 63983 62916 62917 63496 64004 62917 62918 63496 63497 63496 62918 64010 63497 62918 62918 63498 64010 64025 64007 62919 62919 63499 64025 63502 62930 62921 62921 63488 63502 63988 63488 62922 62923 62925 62931 62924 63998 63999 64000 63998 62924 62926 62925 62924 63999 62926 62924 62925 62926 62931 64009 62932 62926 62926 63999 64009 62933 62931 62926 63500 63499 62928 64009 64008 62932 65014 64016 62934 65015 65014 62934 62934 64501 65015 64016 62937 62934 63509 63501 62935 62935 63505 63509 64021 63503 62936 62936 62937 64021 62937 64016 64021 64013 64012 62938 64019 64013 62938 62938 63506 64019 63510 63507 62939 64015 63493 62940 62940 64014 64015 63532 62962 62943 63543 63532 62943 64032 63543 62943 62943 62944 64032 62944 62945 64032 62945 63503 63511 64033 64032 62945 62945 63511 64033 62955 62947 62946 62947 62955 62965 63513 63500 62949 62949 63512 63513 62950 63508 63514 62954 62953 62952 64030 63518 62953 62953 62954 64030 62955 62964 62965 62959 62958 62957 62958 63527 63528 62958 62959 63527 62959 63525 63527 62962 62961 62960 63540 62967 62961 62961 63532 63540 62961 62962 63532 62963 62964 63517 63538 62975 62967 63540 63538 62967 64043 63531 62968 62968 63534 64043 62968 63529 63534 63531 63530 62968 62969 62970 62973 62974 62973 62970 64513 64038 62971 62971 64037 64513 62971 63537 64037 62971 63536 63537 62971 62973 63536 63533 63529 62972 62973 62974 63536 63538 62980 62975 64046 62988 62976 62976 63535 64046 62976 62977 63535 62977 63522 63535 62982 62979 62978 62978 62981 62982 63546 63536 62979 64040 63546 62979 62979 62982 64040 63550 62986 62980 62980 63538 63550 64047 62982 62981 64058 64047 62981 64042 64040 62982 64047 64042 62982 64052 63553 62983 62983 63549 64052 62984 62985 63557 63554 63549 62984 63555 63554 62984 63557 63555 62984 63550 62987 62986 63564 63563 62987 63565 63564 62987 64055 63565 62987 62987 63551 64055 62987 63550 63551 63570 63569 62989 62989 63561 63570 62990 62991 63562 62991 63560 63562 62992 63005 63566 64050 63567 62993 62993 63552 64050 63586 62996 62995 62995 62999 63586 63586 63577 62996 63577 63576 62996 62999 63008 63586 62999 63006 63008 63007 63006 62999 63602 63011 63000 63000 63601 63602 63004 63002 63001 63585 63004 63001 64066 63585 63001 63002 63003 63023 63004 63003 63002 63003 64072 64073 63003 63004 64072 63594 63023 63003 64074 63594 63003 63003 64073 64074 63004 63585 64072 63587 63008 63006 63592 63587 63006 63006 63007 63592 63007 63015 63592 63587 63586 63008 63034 63010 63009 63596 63019 63010 63010 63034 63596 63590 63584 63011 63602 63590 63011 63012 63013 63014 63595 63014 63013 64075 63591 63014 63014 63595 64075 63015 63591 63592 63617 63613 63016 64087 63617 63016 64556 64087 63016 63016 64068 64556 63016 63017 64068 64069 64068 63017 63017 63589 64069 63035 63034 63018 63621 63035 63018 63018 63618 63621 63597 63021 63019 63019 63596 63597 63600 63022 63020 64089 63600 63020 63020 64079 64089 63020 63021 64079 63021 63597 64079 63609 63024 63023 63023 63594 63609 63615 63614 63026 63026 63027 63615 64090 63615 63027 63027 63028 64090 63028 63604 64090 63606 63604 63028 63608 63606 63028 63028 63029 63608 63029 63031 63608 63612 63031 63030 63031 63607 63608 63612 63607 63031 63034 63035 63596 63599 63596 63035 64088 63599 63035 64109 64088 63035 63035 63622 64109 63035 63621 63622 63038 63037 63036 63619 63612 63037 63037 63038 63619 64583 63619 63038 63038 63623 64583 63038 63043 63623 64121 63623 63043 63043 63627 64121 63043 63626 63627 63633 63626 63043 63043 63056 63633 63635 63046 63045 64603 63047 63046 63046 64584 64603 63046 63635 64584 64125 63634 63047 64603 64125 63047 63050 63049 63048 64604 63050 63048 64608 64604 63048 63048 64137 64608 63048 64114 64137 63048 63049 64114 63049 63050 63074 64140 64114 63049 63049 63074 64140 63631 63629 63051 63632 63631 63051 63051 63055 63632 63051 63052 63055 64122 63061 63053 63632 63055 63054 63639 63632 63054 63054 63062 63639 63056 63065 63633 63057 63624 63625 63057 63058 63624 64593 63624 63058 64604 64593 63058 63059 63066 63067 63636 63066 63059 63059 63060 63636 63061 63060 63059 64133 63636 63060 63060 64122 64133 63060 63061 64122 63062 63063 63639 63642 63639 63063 63063 63069 63642 63641 63640 63064 64618 63641 63064 65153 64618 63064 63064 65143 65153 63064 64112 65143 64113 64112 63064 63065 63626 63633 64129 63626 63065 63065 63082 64129 63075 63068 63066 63076 63075 63066 63086 63076 63066 63638 63086 63066 63066 63636 63638 63068 63067 63066 63067 63077 63079 63067 63068 63077 63068 63075 63078 63078 63077 63068 63643 63642 63069 63069 63070 63643 64138 63643 63070 64139 64138 63070 63070 63644 64139 63070 63073 63644 63070 63071 63073 63071 63072 63073 63072 63645 63649 63649 63073 63072 63651 63644 63073 63073 63650 63651 63073 63649 63650 63075 63076 63078 63076 63087 63089 63088 63087 63076 63092 63088 63076 63076 63085 63092 63086 63085 63076 63089 63078 63076 63080 63079 63077 63648 63080 63077 63077 63078 63648 63078 63089 63648 64634 64633 63079 64636 64634 63079 65172 64636 63079 65175 65172 63079 63079 64632 65175 63079 64144 64632 63079 63080 64144 64145 64144 63080 63080 63648 64145 63082 63083 64129 63084 63083 63082 64130 64129 63083 63654 63092 63085 63655 63654 63085 63085 63086 63655 63086 63638 64126 64126 63655 63086 63087 63093 63098 63087 63088 63093 63099 63089 63087 63088 63092 63093 63089 63100 63648 63089 63099 63100 63653 63091 63090 63656 63094 63091 63091 63653 63656 63647 63093 63092 63652 63647 63092 63654 63652 63092 63647 63098 63093 63657 63095 63094 63094 63656 63657 63095 63657 63660 63096 63101 64147 63096 63097 63101 63098 63647 63658 64145 63648 63100 63100 63659 64145 63665 63659 63102 63102 63108 63665 63102 63103 63108 63109 63108 63103 63114 63109 63103 64653 64652 63104 63104 64156 64653 63104 63661 64156 63104 63105 63661 64651 64160 63107 63107 63662 64651 64160 63112 63107 63669 63665 63108 63108 63109 63669 63109 63666 63669 63109 63116 63666 63109 63114 63116 63110 63117 63667 64160 63128 63112 63115 63114 63113 63122 63115 63113 63114 63115 63116 63123 63116 63115 63115 63122 63123 63116 63138 63666 63116 63123 63138 64161 63667 63117 63117 63118 64161 64656 64655 63118 63118 63668 64656 64655 64161 63118 63119 63120 63123 63121 63120 63119 63128 63121 63119 63119 63122 63128 63123 63122 63119 63132 63123 63120 63120 63131 63132 63135 63131 63120 63120 63121 63135 63121 63674 63677 63121 63128 63674 63123 63132 63138 63133 63129 63124 63137 63133 63124 63124 63136 63137 63124 63125 63136 63671 63136 63125 64163 63671 63125 64164 64163 63125 64652 64164 63125 63126 63672 64165 63126 63127 63672 64159 63663 63126 64658 64159 63126 63126 64165 64658 63673 63672 63127 63676 63673 63127 63127 63130 63676 63675 63674 63128 64160 63675 63128 63677 63676 63130 63130 63134 63677 63132 63137 63138 63132 63133 63137 63138 63137 63136 63671 63138 63136 63671 63666 63138 64169 63678 63139 63139 63680 64169 63139 63141 63680 63139 63140 63141 63141 63144 63680 63142 63679 63681 63142 63678 63679 63682 63680 63144 64666 63682 63144 64667 64666 63144 63144 63145 64667 63145 63153 64667 63686 63153 63145 63684 63683 63147 64172 63684 63147 64173 64172 63147 63147 64171 64173 63147 63681 64171 64176 63150 63149 63149 63690 64176 63695 63694 63150 64176 63695 63150 64667 63153 63151 65653 64667 63151 63151 65195 65653 63151 63152 65195 63153 63152 63151 65196 65195 63152 63152 64178 65196 63152 63696 64178 63152 63693 63696 63152 63692 63693 63152 63153 63692 63153 63686 63692 63693 63692 63154 63154 63155 63693 63697 63693 63155 63705 63697 63155 63156 63698 63704 63157 64677 64678 63157 64673 64677 64676 64673 63157 63157 63701 64676 63157 63158 63701 63159 63158 63157 64678 63159 63157 63158 63178 63701 64179 63178 63158 64683 64179 63158 63158 63159 64683 65205 64683 63159 63159 64678 65205 63710 63702 63160 63160 63170 63710 63160 63161 63170 63162 63161 63160 63702 63162 63160 63161 63162 63163 63161 63169 63170 63161 63163 63169 63162 63706 63707 63162 63702 63706 63707 63163 63162 63163 63165 63166 63707 63165 63163 63164 63191 63192 63704 63191 63164 63165 63707 63708 63167 63166 63165 63708 63167 63165 63166 63184 63185 63166 63180 63184 63166 63179 63180 63166 63168 63179 63166 63167 63168 63178 63168 63167 63708 63178 63167 63168 63178 63179 63186 63170 63169 63169 63171 63186 63172 63171 63169 63185 63172 63169 63170 63174 63710 63186 63174 63170 63188 63186 63171 63734 63188 63171 63171 63732 63734 63171 63172 63732 63185 63184 63172 63733 63732 63172 63172 63184 63733 63176 63175 63173 63189 63176 63173 63173 63174 63189 63175 63174 63173 63174 63175 63710 63174 63187 63189 63174 63186 63187 63175 63176 63718 63711 63710 63175 64177 63711 63175 63175 63712 64177 63713 63712 63175 63717 63713 63175 63718 63717 63175 63176 63189 63718 63178 63700 63701 63708 63700 63178 63181 63179 63178 63183 63181 63178 64179 63183 63178 63181 63180 63179 63180 64187 64193 63180 63181 64187 63731 63184 63180 64193 63731 63180 63181 63182 64187 63183 63182 63181 64192 64187 63182 63182 63183 64192 64684 64192 63183 63183 64683 64684 63183 64179 64683 63184 63731 63733 63188 63187 63186 63718 63189 63187 64189 63718 63187 64190 64189 63187 63187 63728 64190 63187 63188 63728 63734 63728 63188 63196 63195 63190 63739 63196 63190 63742 63739 63190 63190 63726 63742 63190 63725 63726 63190 63191 63725 63192 63191 63190 63191 63704 63725 63193 63735 65675 63194 63196 63739 63742 63202 63194 63194 63739 63742 63749 63205 63198 63198 63744 63749 63198 63199 63744 63199 63200 63744 63738 63737 63200 63200 63201 63738 63200 63736 63744 63737 63736 63200 63742 63740 63202 64199 63207 63203 64200 64199 63203 63203 63748 64200 63749 63217 63204 63204 63205 63749 63207 64199 64702 63208 63745 63747 63746 63745 63208 63750 63746 63208 63752 63750 63208 63755 63211 63209 64216 63755 63209 63209 64208 64216 63209 63210 64208 63211 63210 63209 64204 63752 63214 63214 63760 64204 63214 63219 63760 63215 63216 63751 63217 63216 63215 64706 64205 63215 65214 64706 63215 63215 64197 65214 63215 63754 64197 63215 63751 63754 63216 63744 63751 63216 63743 63744 63216 63217 63743 63749 63743 63217 63220 64213 64714 63220 63763 64213 63222 64214 64215 63222 64212 64214 64215 63761 63222 63765 63762 63224 63224 63238 63765 63224 63236 63238 64204 63760 63226 63226 64203 64204 63226 64201 64203 64202 64201 63226 63226 63227 64202 63227 63229 64202 63237 63233 63228 64211 64202 63229 63769 63249 63233 63233 63237 63769 64224 63769 63237 63237 64221 64224 63237 64219 64221 63238 63244 63765 63239 63240 63246 63241 63240 63239 63240 63241 64237 63247 63246 63240 64237 63247 63240 64229 63768 63242 63242 64223 64229 63242 63761 64223 63772 63245 63243 63772 63765 63244 63244 63245 63772 63246 63254 63770 63789 63254 63246 64234 63789 63246 63246 63247 64234 64237 64234 63247 63249 63769 64230 63273 63272 63250 64250 63273 63250 63250 63251 64250 64251 64250 63251 63774 63773 63252 63785 63776 63253 63789 63785 63253 63253 63254 63789 63779 63777 63255 63780 63779 63255 64247 63790 63256 64791 63259 63258 63258 63268 64791 63269 63268 63258 63792 63269 63258 63793 63792 63258 64242 63260 63259 64791 64242 63259 64242 63778 63260 63794 63262 63261 64268 63794 63261 64269 64268 63261 63784 63783 63262 63794 63784 63262 63274 63264 63263 63795 63274 63263 64261 63795 63263 63263 63796 64261 63264 63274 63275 63265 63266 63275 63267 63266 63265 64257 63267 63265 63265 63795 64257 63265 63274 63795 63275 63274 63265 63287 63278 63266 64263 63287 63266 63266 63267 64263 63267 64259 64263 63267 64258 64259 63267 64257 64258 65301 64791 63268 65302 65301 63268 65303 65302 63268 63268 63269 65303 65307 65303 63269 63269 63797 65307 63269 63792 63797 63273 64256 64261 63273 64255 64256 63273 64250 64255 64261 63796 63273 63276 64267 64796 63276 63802 64267 63276 63277 63802 63277 63285 63802 63278 63286 63806 63287 63286 63278 63803 63793 63279 64802 63803 63279 63279 64277 64802 63279 63288 64277 63798 63281 63280 64272 63807 63281 63281 63798 64272 65306 64799 63282 65311 65306 63282 65318 65311 63282 63282 63283 65318 63284 63283 63282 64799 63284 63282 63283 63811 65318 63283 63810 63811 63283 63284 63285 64266 63285 63284 64799 64266 63284 64266 63802 63285 64276 63806 63286 63286 64270 64276 63286 63287 64270 63287 64264 64270 63287 64263 64264 63288 63808 64277 63289 63294 63295 63304 63294 63289 64287 63304 63289 64805 64287 63289 63289 63290 64805 63290 64804 64805 63290 64275 64804 63290 63800 64275 63295 63294 63291 64279 63814 63292 63292 63809 64279 63815 63813 63293 63293 63297 63815 63297 63298 63815 64283 63815 63298 64812 64283 63298 64814 64812 63298 63298 64284 64814 64285 64284 63299 63299 63819 64285 63817 63816 63300 63818 63817 63301 64829 63818 63301 63301 63305 64829 63302 64288 64816 63302 63303 64288 64819 64288 63303 64820 64819 63303 63303 63830 64820 64287 63821 63304 63821 63309 63304 65321 64829 63305 63305 64817 65321 63307 63308 63824 63307 63824 63825 63826 63824 63308 63821 63820 63309 63838 63830 63310 63310 63837 63838 63310 63317 63837 63311 63312 63822 63311 63822 64821 63312 63814 63822 63313 63829 64298 63828 63827 63313 64298 63828 63313 63836 63316 63314 63315 63834 63835 63315 63327 63834 63837 63317 63316 64304 63837 63316 63316 63836 64304 63321 63320 63319 63842 63321 63319 64317 63849 63320 64318 64317 63320 64850 64318 63320 63320 63321 64850 65351 64850 63321 63321 64312 65351 63321 64311 64312 63321 64309 64311 63321 63842 64309 63322 63325 63332 63322 63323 63325 63324 63323 63322 63332 63324 63322 63326 63325 63323 64306 63326 63323 63323 63846 64306 63323 63324 63846 63324 63339 63846 63324 63332 63339 63325 63329 63332 63325 63328 63329 63325 63326 63328 64306 63328 63326 63327 63328 63834 63329 63328 63327 63336 63329 63327 63328 63833 63834 64306 63833 63328 63336 63334 63329 63334 63332 63329 63850 63344 63330 63330 63337 63850 64315 63841 63331 63331 63848 64315 63332 63335 63339 63332 63334 63335 63852 63349 63333 63333 63342 63852 63333 63334 63342 63335 63334 63333 63348 63335 63333 63349 63348 63333 63343 63342 63334 63340 63339 63335 63347 63340 63335 63348 63347 63335 64307 63850 63337 63337 63843 64307 63337 63338 63843 64313 63846 63339 65373 64313 63339 63339 63374 65373 63339 63340 63374 63340 63350 63374 63340 63346 63350 63347 63346 63340 63345 63343 63341 63342 63343 63852 63854 63852 63343 63343 63853 63854 63343 63345 63853 63344 63850 64861 64323 63847 63344 63344 64322 64323 64861 64322 63344 63354 63350 63346 63356 63354 63346 63346 63351 63356 63346 63347 63351 63347 63348 63351 63357 63351 63348 63348 63349 63357 63852 63357 63349 63350 63355 63374 63350 63354 63355 63358 63356 63351 63351 63357 63358 63856 63366 63352 63352 63353 63856 63854 63853 63352 63855 63854 63352 63352 63366 63855 63353 63363 63856 63356 63358 63362 63854 63358 63357 63357 63852 63854 63367 63362 63358 63855 63367 63358 63358 63854 63855 63359 63360 63876 63877 63876 63360 63360 63864 63877 63878 63364 63361 63871 63856 63363 63363 63372 63871 63363 63371 63372 63375 63371 63363 64355 63866 63364 64356 64355 63364 63364 63878 64356 63892 63887 63365 63365 63882 63892 63368 63367 63366 63856 63368 63366 63366 63367 63855 63883 63880 63367 63367 63368 63883 63368 63372 63883 63871 63372 63368 63368 63856 63871 63369 63371 63376 63880 63371 63369 63369 63370 63880 63371 63375 63376 63883 63372 63371 63371 63880 63883 63373 63884 63886 64369 63882 63373 63373 63885 64369 63886 63885 63373 66286 65373 63374 66309 66286 63374 66310 66309 63374 63374 66307 66310 66308 66307 63374 63374 64387 66308 63888 63378 63377 63889 63888 63377 64890 63889 63377 63377 64372 64890 63378 63899 63901 63900 63899 63378 63378 63888 63900 63890 63381 63379 63891 63890 63379 64891 63891 63379 63379 63380 64891 63380 64380 64891 63380 63383 64380 63380 63382 63383 63890 63884 63381 63895 63894 63383 64382 64380 63383 63383 63894 64382 63386 63385 63384 63893 63386 63384 63384 63887 63893 63388 63387 63385 63385 63386 63388 63896 63388 63386 63386 63893 63896 63908 63907 63387 63909 63908 63387 63387 63388 63909 63388 63896 64370 64383 63909 63388 64900 64383 63388 63388 64895 64900 63388 64370 64895 64401 63898 63389 63389 63912 64401 64419 63930 63390 63390 63937 64419 63390 63407 63937 63391 63399 63922 63391 63392 63399 63392 63393 63399 63393 63394 63399 64412 63399 63394 63394 63408 64412 64420 63934 63395 63395 63929 64420 63395 63928 63929 63396 63921 63928 63396 63904 63921 63397 63406 63407 63415 63406 63397 63397 63414 63415 64926 64430 63398 63398 64409 64926 63398 64399 64409 63398 63907 64399 64405 63922 63399 64411 64405 63399 64412 64411 63399 63402 63401 63400 63923 63421 63401 63401 63402 63923 63402 63918 63923 63933 63918 63402 63940 63939 63403 63403 63404 63940 64425 63940 63404 63404 63935 64425 63405 63934 63935 63937 63407 63406 64429 63937 63406 63406 64427 64429 63406 63415 64427 63408 63948 64412 63408 63416 63948 63417 63416 63408 63408 63409 63417 63420 63417 63409 63410 63411 63422 63412 63411 63410 64441 63422 63411 63411 63944 64441 63411 63412 63944 63412 63421 63944 64427 63415 63414 63414 63946 64427 64435 63948 63416 63416 63434 64435 64436 63434 63416 63416 63436 64436 63416 63417 63436 63417 63424 63436 63418 63419 63945 63950 63945 63419 63419 63423 63950 63421 63923 63924 64423 63944 63421 63421 63938 64423 63421 63924 63938 64442 63426 63422 63422 64441 64442 63423 63949 63950 63958 63436 63424 63424 63434 63958 64444 63949 63425 63425 63426 64444 63426 64443 64444 63426 64442 64443 63959 63437 63427 63960 63959 63427 63428 63953 63962 63962 63430 63428 63968 63452 63429 64438 63433 63431 63431 63957 64438 63431 63432 63957 63432 63441 63957 64439 63435 63433 64440 64439 63433 63433 64438 64440 64436 63958 63434 64439 64435 63434 63434 63435 64439 63436 63958 64436 63438 63459 63460 63438 63446 63459 63447 63446 63438 63438 63439 63447 63440 63439 63438 63971 63440 63438 63438 63460 63971 63439 63440 64449 63953 63447 63439 63962 63953 63439 64449 63962 63439 63440 63971 64449 63963 63957 63441 63441 63442 63963 63442 63450 63963 63442 63449 63450 63475 63449 63442 63445 63444 63443 63444 63964 63970 63444 63445 63964 63965 63964 63445 63461 63459 63446 63450 63449 63448 63969 63450 63448 63972 63969 63448 64456 63972 63448 63448 63985 64456 63448 63981 63985 63448 63449 63981 63449 63475 63981 63450 63954 63963 63969 63954 63450 63451 63970 63973 63976 63462 63452 63977 63976 63452 64451 63977 63452 63452 64449 64451 63452 63968 64449 63469 63454 63453 63974 63469 63453 63453 63973 63974 64470 63486 63454 64475 64470 63454 63454 64460 64475 63454 63468 64460 63469 63468 63454 63471 63456 63455 63473 63457 63456 63978 63473 63456 63456 63471 63978 63979 63458 63457 63457 63473 63979 63458 63459 63461 63979 63459 63458 64464 63975 63459 63459 64454 64464 63459 63980 64454 63459 63979 63980 63975 63460 63459 64968 63971 63460 64977 64968 63460 63460 63975 64977 63465 63464 63463 64466 63465 63463 65498 64466 63463 63463 64982 65498 63463 64457 64982 63463 63464 64457 63464 63987 64457 63464 63478 63987 63982 63477 63465 64466 63982 63465 63466 63467 63480 64458 63480 63467 63467 63481 64458 64471 64460 63468 63468 64461 64471 63468 63469 64461 63469 63974 64461 63978 63471 63470 63983 63978 63470 63472 63983 64463 63472 63978 63983 63472 63473 63978 63474 63473 63472 64462 63474 63472 64463 64462 63472 63980 63979 63473 63473 63474 63980 64455 63980 63474 64462 64455 63474 63475 63476 63981 63477 63476 63475 64465 63981 63476 63476 63982 64465 63476 63477 63982 63992 63987 63479 64458 63990 63480 63481 63482 64458 64467 64458 63482 63482 63991 64467 63482 63483 63991 63483 63484 63991 63485 63484 63483 64469 63991 63484 63484 63486 64469 63484 63485 63486 64470 64469 63486 64474 63992 63487 64483 64474 63487 64485 64483 63487 63487 63501 64485 63988 63502 63488 63489 63492 63494 63493 63492 63489 64478 64477 63490 64479 64478 63490 63490 63994 64479 64001 63494 63492 64015 64001 63492 63492 63493 64015 64003 64002 63495 64004 64003 63495 64487 64004 63496 63496 63497 64487 63497 64010 64487 63498 64005 64010 63499 64006 64025 63499 63500 64006 63500 63513 64006 63501 63509 64485 63502 63995 64020 63502 63988 63995 64021 63511 63503 64027 63509 63505 64497 64019 63506 64503 64497 63506 63506 64498 64503 63506 64020 64498 64028 64014 63507 63507 63510 64028 63515 63514 63508 64494 64485 63509 63509 64027 64494 64031 64028 63510 64036 64031 63510 63510 63528 64036 63511 64023 64033 63511 64021 64023 63514 63513 63512 64026 64006 63513 63513 63514 64026 63514 63515 64026 63515 64017 64026 63516 63523 63524 63518 63521 63526 64035 63521 63518 63518 64030 64035 66017 65031 63519 63519 66011 66017 63519 65529 66011 63519 65022 65529 63519 63520 65022 63521 63520 63519 65031 63521 63519 63520 64035 65022 63520 63521 64035 65030 63526 63521 65031 65030 63521 63522 63531 63535 63522 63530 63531 64034 63524 63523 64514 64034 63523 64034 64027 63524 64521 63527 63525 64527 64521 63525 65040 64527 63525 63525 65039 65040 63525 63526 65039 63526 65030 65535 65535 65039 63526 64521 63528 63527 64521 64036 63528 63529 63533 63534 64043 63535 63531 63548 63540 63532 63532 63543 63548 63544 63534 63533 63534 63544 64043 63535 64043 64046 63546 63537 63536 64520 64037 63537 63537 63546 64520 63538 63547 63550 63538 63539 63547 63540 63539 63538 63548 63547 63539 63539 63540 63548 63543 63542 63541 63548 63543 63541 64049 63548 63541 65548 64049 63541 63541 65036 65548 63541 64044 65036 63541 63542 64044 63542 63543 64045 64045 64044 63542 63543 64032 64045 64046 64043 63544 63546 64519 64520 63546 64041 64519 63546 64040 64041 63551 63550 63547 64057 63551 63547 64529 64057 63547 63547 63548 64529 63548 64048 64529 64049 64048 63548 63549 63554 64052 64056 64055 63551 64542 64056 63551 63551 64057 64542 64051 64050 63552 63552 63553 64051 64531 64051 63553 63553 64052 64531 64533 64052 63554 64534 64533 63554 64535 64534 63554 63554 63555 64535 63555 63556 64535 63557 63556 63555 65057 64535 63556 63556 64540 65057 63556 63576 64540 63556 63557 63576 63562 63560 63558 63558 63561 63562 63570 63561 63558 64543 63570 63558 65065 64543 63558 63558 65064 65065 63558 63559 65064 63560 63559 63558 63559 63560 63572 63559 64545 65064 63559 63572 64545 63560 63571 63572 63564 64053 64059 63564 63565 64053 64054 64053 63565 65058 64054 63565 63565 64055 65058 64537 64058 63567 63567 64050 64537 63568 63578 63589 63579 63578 63568 63568 63569 63579 63569 63570 63579 64543 63579 63570 63581 63572 63571 63571 63580 63581 63571 63573 63580 63572 63581 64545 63581 63580 63573 64062 63581 63573 64063 64062 63573 63573 63574 64063 63574 63582 64063 63576 63577 64540 63577 64060 64540 63577 63586 64060 64070 63589 63578 63578 64061 64070 63578 63579 64061 64544 64061 63579 63579 64543 64544 63581 64062 64545 63582 63583 64063 63583 64059 64063 64071 64065 63584 63584 63590 64071 63585 63605 64072 64081 63605 63585 63585 64066 64081 63586 63588 64060 63586 63587 63588 64547 63588 63587 63587 63592 64547 64067 64060 63588 65067 64067 63588 63588 64548 65067 63588 64547 64548 64070 64069 63589 64549 64071 63590 63590 63602 64549 63593 63592 63591 64075 63593 63591 63592 63593 64547 64553 64547 63593 65073 64553 63593 63593 64075 65073 64080 63609 63594 63594 64074 64080 64552 64075 63595 63595 64551 64552 63599 63597 63596 63597 63598 64079 63599 63598 63597 65091 64089 63598 63598 64563 65091 63598 64558 64563 63598 64557 64558 63598 63599 64557 64089 64079 63598 63599 64088 64557 64089 63601 63600 64554 63602 63601 64555 64554 63601 63601 64089 64555 64554 64549 63602 63605 63604 63603 64072 63605 63603 64073 64072 63603 63603 63607 64073 63603 63606 63607 63603 63604 63606 64091 64090 63604 63604 63605 64091 65080 64091 63605 63605 65079 65080 63605 64081 65079 63608 63607 63606 64080 64073 63607 63607 63612 64080 64080 63610 63609 63610 64080 64093 63611 64569 65108 63611 63614 64569 64092 64080 63612 64566 64092 63612 63612 63619 64566 63617 63616 63613 63614 63615 64569 63615 64564 64569 63615 64090 64564 64098 63618 63616 63616 63617 64098 64574 64098 63617 64575 64574 63617 63617 64087 64575 64100 63621 63618 63618 64099 64100 63618 64098 64099 64583 64566 63619 63620 64094 64110 64100 63622 63621 63622 64108 64109 63622 64100 64108 64597 64583 63623 63623 64121 64597 64567 63625 63624 64585 64567 63624 64586 64585 63624 64593 64586 63624 63625 64078 64085 64101 64078 63625 64567 64101 63625 64599 63627 63626 65144 64599 63626 63626 64130 65144 63626 64129 64130 64599 64121 63627 63628 65628 65629 66584 65628 63628 63628 66117 66584 63628 64609 66117 63628 63629 64609 63630 63629 63628 65629 63630 63628 63629 63630 64122 63629 63631 64609 64133 64122 63630 63630 64132 64133 64614 64132 63630 65629 64614 63630 63631 64127 64609 63631 63632 64127 64128 64127 63632 63632 63639 64128 64125 63637 63634 63635 64576 64584 63635 64110 64576 64133 64132 63636 64126 63638 63636 64132 64126 63636 64125 64124 63637 63639 63642 64128 64622 64146 63640 63640 63641 64622 64623 64622 63641 63641 64618 64623 64135 64128 63642 64136 64135 63642 63642 63643 64136 64138 64136 63643 63644 63651 64630 64629 64139 63644 64630 64629 63644 63645 63646 63649 63650 63649 63646 64146 63650 63646 64148 63658 63647 63647 64142 64148 64143 64142 63647 63647 63652 64143 64146 63651 63650 63651 64622 64631 63651 64146 64622 64631 64630 63651 63652 64131 64143 63652 63654 64131 65158 64131 63654 63654 63655 65158 63655 65149 65158 63655 64126 65149 64150 63657 63656 64150 63660 63657 64148 63662 63658 64152 64145 63659 63659 63665 64152 64644 64154 63660 64645 64644 63660 64647 64645 63660 63660 64150 64647 64157 64156 63661 64161 64157 63661 63661 63667 64161 65169 64651 63662 63662 64151 65169 63662 64148 64151 64159 63664 63663 64159 64153 63664 64646 64152 63665 63665 64155 64646 63665 63669 64155 63670 63669 63666 64163 63670 63666 63666 63671 64163 63669 63670 64155 65171 64155 63670 63670 64659 65171 63670 64163 64659 64657 64167 63672 63672 63673 64657 64167 64165 63672 63676 63674 63673 63673 64166 64657 63673 63674 64166 63674 63676 63677 63674 63675 64166 63675 64160 64166 64664 63679 63678 65187 64664 63678 63678 64660 65187 63678 64169 64660 64170 63681 63679 64664 64170 63679 63680 63682 64169 63681 64170 64171 64660 64169 63682 65187 64660 63682 65651 65187 63682 63682 64662 65651 64666 64662 63682 65193 64174 63683 63683 65192 65193 63683 63684 65192 63684 65190 65192 63684 65189 65190 63684 64172 65189 63689 63688 63685 64174 63689 63685 63691 63690 63687 64185 64175 63688 63688 64180 64185 63688 63709 64180 63688 63689 63709 64175 63691 63688 64174 63709 63689 64669 64176 63690 63690 63710 64669 64185 63710 63690 63690 64175 64185 63690 63691 64175 63697 63696 63693 63703 63698 63694 63694 63695 63703 63712 63703 63695 64177 63712 63695 63695 64176 64177 63696 63705 64178 63696 63697 63705 63715 63704 63698 63698 63714 63715 63698 63703 63714 63699 63700 63708 63701 63700 63699 64181 63701 63699 63699 63707 64181 63708 63707 63699 63701 64181 64676 64180 63706 63702 64185 64180 63702 63702 63710 64185 63703 63712 63714 63704 63723 63725 63704 63722 63723 63704 63715 63722 65204 64178 63705 63705 63716 65204 64180 63709 63706 63709 63707 63706 64182 64181 63707 64184 64182 63707 63707 63709 64184 63709 64174 64184 63710 64186 64669 63710 63711 64186 63711 64176 64186 64177 64176 63711 63712 63713 63714 63717 63714 63713 63722 63715 63714 63714 63719 63722 63714 63717 63719 63716 65203 65204 63716 63727 65203 63729 63719 63717 63717 63718 63729 63718 63721 63729 64188 63721 63718 64189 64188 63718 63719 63720 63722 63721 63720 63719 63729 63721 63719 63724 63722 63720 64680 63724 63720 63720 63721 64680 63721 64679 64680 63721 64188 64679 63724 63723 63722 64680 64191 63723 63723 63724 64680 63726 63725 63723 64191 63726 63723 63726 63741 63742 64691 63741 63726 64693 64691 63726 63726 64690 64693 63726 64191 64690 65663 65203 63727 65676 65663 63727 63727 63730 65676 63728 63734 64190 65677 65676 63730 64685 63733 63731 63731 64193 64685 64686 63734 63732 63732 64194 64686 63732 63733 64194 64685 64194 63733 64687 64190 63734 65206 64687 63734 63734 64686 65206 66148 65675 63735 66149 66148 63735 66154 66149 63735 63735 65678 66154 63751 63744 63736 63736 63737 63751 63737 63738 64196 64196 63751 63737 64692 64195 63740 63740 64691 64692 63740 63741 64691 63742 63741 63740 63749 63744 63743 64207 64198 63746 63746 63750 64207 64204 64203 63750 63750 63752 64204 64700 64207 63750 63750 64203 64700 64196 63754 63751 64701 64208 63753 63754 64196 64197 64216 64212 63755 63756 64205 64206 63756 63757 63759 63758 63757 63756 64206 63758 63756 63758 64210 64220 63758 64206 64210 64738 64223 63761 63761 64215 64738 64739 63763 63762 63762 64226 64739 63762 63772 64226 63762 63765 63772 64739 64213 63763 64222 63767 63766 63766 63773 64222 65258 64211 63767 65264 65258 63767 63767 64225 65264 63767 64222 64225 64229 64228 63768 64761 64230 63769 64769 64761 63769 63769 64756 64769 63769 64224 64756 64238 63772 63771 64240 64238 63771 63771 64239 64240 64764 64226 63772 63772 64238 64764 63773 63774 64233 64773 64222 63773 63773 64233 64773 64241 64232 63774 63774 63775 64241 63774 64232 64233 63775 63778 64241 63776 63785 63786 64245 64239 63777 63777 63779 64245 64242 64241 63778 63779 63791 64245 63779 63781 63791 63781 63782 63791 64787 63791 63782 64788 64787 63782 64789 64788 63782 63783 63784 64789 63784 64248 64789 64249 64248 63784 63784 63794 64249 64244 64243 63785 63785 63788 64244 63789 63788 63785 63787 63786 63785 64243 63787 63785 64786 64247 63786 63786 63787 64786 63787 64785 64786 65295 64785 63787 63787 64243 65295 63788 63789 64235 65276 64244 63788 63788 64235 65276 63789 64234 64235 63790 64247 64798 64787 64245 63791 64265 63797 63792 63792 63803 64265 63792 63793 63803 64268 64249 63794 64258 64257 63795 64794 64258 63795 63795 64256 64794 64261 64256 63795 63797 64265 65307 64798 64272 63798 63805 63801 63799 63800 63801 63805 63800 64274 64275 63800 63805 64274 63802 64266 64267 64802 64265 63803 64274 63805 63804 63804 64273 64274 64278 63809 63806 63806 64276 64278 63807 64272 64273 64283 64277 63808 63808 63815 64283 63808 63813 63815 63809 64278 64279 63816 63812 63810 63812 63811 63810 63811 64811 65318 63811 63812 64811 63812 63816 64811 64282 63822 63814 63814 64279 64282 63816 64810 64811 63816 63817 64810 64815 64810 63817 63817 63818 64815 63818 64829 65321 65321 64815 63818 64286 64285 63819 63819 63823 64286 64295 64291 63820 63820 64287 64295 63820 63821 64287 64293 63826 63820 63820 64290 64293 64291 64290 63820 63822 64282 64821 63824 63826 64293 64292 63825 63824 64294 64292 63824 63824 64293 64294 64839 63839 63827 63827 63828 64839 64840 64839 63828 65799 64840 63828 63828 65798 65799 63828 64298 65798 63829 64296 64301 63829 63832 64296 64301 64298 63829 64830 64820 63830 63830 63838 64830 64296 63832 63831 64843 63834 63833 65328 64843 63833 63833 64314 65328 63833 64306 64314 64843 64302 63834 64302 63835 63834 64303 63836 63835 63835 64302 64303 63836 64303 64304 64305 63838 63837 63837 64304 64305 63838 64820 64830 64838 64820 63838 63838 64305 64838 64307 63843 63839 64308 64307 63839 64839 64308 63839 64315 63844 63841 64849 63845 63844 63844 64315 64849 64848 64316 63845 64849 64848 63845 64313 64306 63846 64323 63851 63847 64323 64320 63848 63848 63851 64323 64857 64315 63848 64863 64857 63848 64867 64863 63848 63848 64320 64867 63850 64307 64862 64862 64861 63850 63872 63860 63857 63857 63858 63872 63859 63858 63857 63860 63859 63857 64358 63872 63858 63858 64337 64358 63858 64333 64337 64338 64333 63858 63858 63859 64338 64339 64338 63859 63859 63861 64339 63859 63860 63861 63872 63861 63860 63861 63873 64339 63861 63872 63873 64372 63877 63862 63862 64353 64372 64354 64353 63862 63862 63863 64354 63864 63863 63862 63877 63864 63862 64355 64354 63863 63863 63865 64355 63863 63864 63865 63865 63866 64355 64357 63878 63867 65381 64357 63867 63867 64875 65381 64876 64875 63867 63867 63879 64876 63868 63869 63879 63870 63869 63868 64864 63870 63868 64865 64864 63868 63868 64317 64865 64876 63879 63869 63869 64874 64876 63869 63870 64874 65367 64874 63870 63870 64864 65367 63874 63873 63872 64358 63874 63872 64347 64339 63873 64359 64347 63873 63873 63875 64359 63873 63874 63875 64878 63875 63874 63874 64358 64878 64360 64359 63875 64361 64360 63875 64878 64361 63875 63876 63877 64372 64357 64356 63878 64369 63892 63882 64373 63886 63884 63884 63890 64373 64897 64369 63885 63885 64374 64897 63885 63886 64374 63886 64373 64374 63887 63892 63893 64381 63900 63888 63888 63889 64381 64890 64381 63889 63890 63891 64373 64893 64373 63891 63891 64892 64893 63891 64891 64892 63896 63893 63892 64370 63896 63892 64895 64370 63892 63892 64369 64895 63894 63903 64382 63894 63895 63903 64905 64885 63897 63897 63910 64905 63911 63910 63897 63897 63898 63911 64401 63911 63898 64384 63901 63899 63899 64379 64384 63899 63900 64379 63900 64378 64379 64381 64378 63900 63906 63902 63901 64384 63906 63901 63906 63904 63902 64386 64382 63903 64408 63921 63904 63904 63905 64408 63906 63905 63904 64924 64408 63905 65431 64924 63905 63905 65411 65431 63905 64902 65411 63905 63906 64902 63906 64384 64902 63907 64388 64399 63907 63908 64388 64389 64388 63908 63908 63909 64389 63909 64383 64389 63910 63911 64401 64906 64905 63910 64907 64906 63910 63910 64401 64907 64907 64401 63912 64908 64907 63912 63912 63913 64908 63913 64404 64908 63913 64402 64404 63913 63914 64402 64403 64402 63914 63919 63917 63915 63915 63918 63919 63923 63918 63915 63915 63916 63923 63917 63916 63915 63924 63923 63916 63925 63924 63916 64395 63925 63916 64407 64395 63916 63916 63917 64407 63917 63919 64407 63920 63919 63918 63927 63920 63918 63933 63927 63918 64911 64407 63919 63919 63920 64911 63920 63932 64911 63920 63927 63932 63929 63928 63921 64408 63929 63921 64913 64403 63922 63922 64391 64913 64393 64391 63922 64405 64393 63922 63924 63926 63938 63924 63925 63926 64416 63926 63925 63925 64396 64416 63925 64395 64396 63926 64414 64920 64416 64414 63926 64920 63938 63926 63927 63931 63932 63933 63931 63927 64927 64420 63929 63929 64417 64927 63929 64408 64417 64419 64418 63930 64925 64385 63930 63930 64422 64925 63930 64418 64422 63931 63939 63940 63931 63933 63939 64424 63932 63931 63931 63940 64424 63932 64424 64936 63932 64910 64911 64922 64910 63932 65433 64922 63932 66365 65433 63932 63932 65456 66365 63932 64937 65456 63932 64936 64937 63936 63935 63934 64420 63936 63934 63935 63936 64425 64939 64425 63936 63936 64421 64939 63936 64420 64421 64941 64929 63937 64942 64941 63937 63937 64429 64942 63937 64418 64419 64929 64418 63937 64920 64423 63938 64426 64424 63940 63940 64425 64426 63941 63942 64926 63943 63942 63941 64951 63943 63941 65450 64951 63941 63941 64926 65450 63942 64430 64926 63942 63943 64430 63943 63947 64430 63952 63947 63943 65470 64950 63943 63943 64951 65470 64945 64441 63944 63944 64935 64945 63944 64423 64935 63951 63946 63945 63945 63950 63951 64428 64427 63946 64949 64428 63946 63946 63951 64949 64434 64412 63948 64934 64434 63948 63948 64439 64934 63948 64435 64439 64955 63950 63949 63949 64444 64955 64956 63951 63950 63950 64955 64956 65467 64949 63951 66390 65467 63951 63951 64956 66390 63954 63969 64448 63954 63955 63963 63956 63955 63954 64448 63956 63954 64433 63963 63955 63955 64432 64433 64943 64432 63955 63955 63956 64943 65926 64943 63956 63956 64961 65926 64962 64961 63956 63956 64448 64962 63957 64437 64438 63957 64431 64437 63957 63963 64431 63967 63966 63959 63959 63961 63967 63959 63960 63961 64964 63967 63961 64449 63968 63962 64433 64431 63963 63974 63970 63964 64965 63974 63964 63964 64452 64965 64453 64452 63964 64969 64453 63964 64970 64969 63964 63964 64450 64970 63964 63965 64450 63965 63966 64450 64963 64450 63966 63966 63967 64963 64964 64963 63967 64973 64448 63969 63969 63972 64973 63974 63973 63970 64968 64449 63971 63972 64456 64973 64965 64461 63974 63975 64464 64481 63975 64971 64977 64977 64971 63977 63977 64968 64977 63977 64451 64968 64455 64454 63980 64465 63985 63981 64473 64465 63982 63982 64466 64473 63983 63993 64463 63986 63985 63984 64980 63986 63984 63984 64473 64980 63984 63985 64473 63985 63986 64456 63985 64465 64473 64973 64456 63986 64992 64973 63986 63986 64980 64992 64983 64457 63987 63987 64474 64983 63987 63992 64474 64486 63996 63988 63988 63989 64486 63990 63989 63988 63996 63995 63988 64997 64486 63989 65483 64997 63989 63989 64975 65483 63989 63990 64975 63990 64459 64975 63990 64458 64459 64469 64467 63991 63994 64002 64479 64491 64020 63995 63995 63996 64491 64996 64492 63996 63996 64486 64996 64492 64491 63996 65012 64493 63997 65517 65012 63997 63997 65515 65517 63997 65009 65515 63997 63998 65009 63999 63998 63997 64493 63999 63997 63998 64000 65009 64493 64009 63999 64000 64500 65009 64000 64001 64500 64001 64015 64500 64002 64003 64479 64998 64990 64003 64003 64488 64998 64003 64487 64488 64003 64004 64487 64990 64479 64003 64011 64010 64005 64482 64011 64005 64006 64007 64025 64017 64007 64006 64026 64017 64006 64008 64493 65010 64008 64009 64493 65011 64487 64010 64010 64011 65011 64011 64480 65011 64482 64480 64011 64495 64018 64012 64012 64013 64495 64496 64495 64013 64013 64019 64496 64505 64015 64014 64014 64028 64505 64505 64500 64015 65014 64029 64016 64029 64021 64016 64511 64509 64018 64018 64502 64511 64018 64495 64502 65007 64496 64019 64019 64497 65007 64020 64491 64498 64029 64023 64021 64024 64023 64022 65530 64024 64022 64022 65017 65530 64022 65014 65017 64022 64029 65014 64022 64023 64029 64023 64024 64033 65036 64033 64024 65530 65036 64024 64506 64494 64027 64508 64506 64027 64027 64034 64508 64028 64031 64505 64509 64035 64030 64512 64505 64031 64516 64512 64031 64031 64036 64516 64032 64033 64045 64033 64044 64045 65036 64044 64033 64515 64508 64034 64034 64514 64515 64035 64509 65022 64522 64516 64036 64036 64521 64522 65025 64513 64037 65531 65025 64037 64037 64526 65531 64037 64520 64526 65029 64039 64038 64038 65026 65029 64038 65025 65026 64038 64513 65025 64515 64514 64039 65029 64515 64039 64042 64041 64040 64525 64519 64041 65049 64525 64041 65051 65049 64041 64041 64530 65051 64041 64042 64530 64042 64047 64530 64536 64530 64047 64047 64058 64536 65059 64529 64048 64048 65050 65059 64048 64049 65050 65548 65050 64049 64539 64537 64050 64050 64051 64539 65054 64539 64051 64051 64531 65054 64532 64531 64052 64533 64532 64052 64546 64059 64053 65566 64546 64053 64053 64054 65566 64054 65565 65566 65568 65565 64054 64054 65058 65568 64055 64056 65058 65568 65058 64056 64056 65066 65568 64056 64542 65066 64057 64541 64542 64057 64529 64541 64538 64536 64058 64058 64537 64538 64064 64063 64059 64546 64064 64059 64060 64067 64540 64061 64544 65087 65083 64070 64061 65084 65083 64061 65085 65084 64061 66068 65085 64061 64061 65087 66068 64062 65069 65572 64062 65068 65069 64062 64063 65068 65071 64545 64062 64062 65070 65071 65572 65070 64062 64063 64064 65068 65069 65068 64064 65076 65069 64064 65566 65076 64064 64064 64546 65566 64081 64066 64065 65079 64081 64065 65080 65079 64065 65586 65080 64065 64065 65078 65586 64065 64071 65078 65060 65057 64067 65067 65060 64067 65057 64540 64067 64560 64556 64068 65090 64560 64068 64068 65082 65090 64068 64069 65082 64069 64070 65082 65083 65082 64070 64071 65077 65078 64071 64549 65077 64080 64074 64073 64075 64552 65073 64550 64086 64076 64076 64082 64550 65587 64082 64076 64076 65118 65587 64076 64077 65118 64078 64077 64076 64086 64078 64076 65119 65118 64077 64077 64101 65119 64077 64078 64101 64086 64085 64078 64080 64092 64093 65081 64550 64082 65578 65081 64082 64082 64083 65578 64084 64083 64082 65587 64084 64082 66053 65578 64083 66061 66053 64083 64083 64084 66061 64084 65587 65598 66539 66061 64084 64084 66093 66539 64084 65598 66093 64086 64550 64551 64087 64556 64560 64087 64561 64575 64087 64560 64561 64088 64109 64557 65091 64555 64089 64090 64559 64564 64090 64091 64559 65098 64559 64091 64091 65093 65098 64091 65080 65093 64566 64565 64092 64570 64093 64092 64092 64565 64570 64570 64094 64093 64577 64110 64094 64094 64570 64577 64105 64104 64095 64578 64105 64095 64095 64096 64578 64097 64096 64095 64104 64097 64095 64579 64578 64096 64580 64579 64096 64096 64107 64580 64096 64097 64107 64097 64106 64107 64097 64104 64106 64581 64099 64098 64098 64574 64581 64590 64100 64099 65126 64590 64099 64099 64581 65126 64590 64108 64100 64101 64568 65119 64101 64567 64568 64588 64587 64102 64102 64103 64588 64104 64103 64102 64111 64104 64102 64115 64111 64102 64117 64115 64102 64587 64117 64102 65120 64588 64103 65123 65120 64103 64103 65122 65123 64103 64105 65122 64103 64104 64105 64111 64106 64104 65124 65122 64105 64105 64578 65124 64119 64107 64106 64106 64111 64119 65131 64580 64107 64107 64602 65131 64107 64119 64602 64596 64109 64108 64108 64590 64596 64562 64557 64109 65136 64562 64109 64109 65132 65136 64109 64596 65132 64577 64576 64110 64111 64118 64119 64111 64115 64118 65627 65143 64112 66110 65627 64112 64112 66109 66110 64112 65624 66109 64112 64120 65624 64112 64113 64120 64619 64137 64114 64114 64140 64619 64606 64118 64115 64607 64606 64115 64115 64116 64607 64117 64116 64115 64116 64591 64607 64116 64586 64591 64589 64586 64116 64116 64117 64589 64117 64587 64589 64602 64119 64118 65133 64602 64118 65142 65133 64118 64118 64606 65142 64120 65619 65624 64120 64582 65619 64598 64597 64121 64599 64598 64121 65144 64130 64124 64124 64598 65144 64124 64125 64598 64125 64597 64598 64603 64597 64125 65152 65149 64126 64126 64132 65152 64615 64609 64127 64127 64134 64615 64127 64128 64134 64135 64134 64128 64131 64142 64143 64626 64142 64131 64627 64626 64131 65158 64627 64131 64132 64614 65152 64616 64615 64134 64617 64616 64134 64134 64135 64617 64135 64136 64617 64620 64617 64136 64621 64620 64136 64136 64138 64621 65148 64608 64137 64137 64619 65148 64138 64139 64621 64628 64621 64139 64629 64628 64139 64140 64141 64619 64625 64619 64141 64141 64624 64625 64151 64148 64142 64626 64151 64142 64144 64149 64632 64144 64145 64149 64646 64149 64145 64145 64152 64646 65157 64624 64147 64147 64641 65157 64147 64153 64641 64646 64632 64149 64150 64643 64647 64150 64639 64643 64151 65167 65169 65168 65167 64151 64151 64627 65168 64151 64626 64627 64153 64159 64162 64648 64641 64153 64153 64162 64648 64644 64158 64154 65170 64646 64155 65171 65170 64155 65186 64653 64156 64156 65181 65186 64156 64157 65181 65182 65181 64157 64157 64654 65182 64157 64161 64654 64158 64645 64656 64158 64644 64645 64658 64162 64159 64651 64166 64160 64655 64654 64161 65183 64648 64162 64162 64658 65183 64163 64164 64659 64164 64653 65178 64164 64652 64653 65184 64659 64164 64164 65179 65184 64164 65178 65179 65649 64658 64165 65650 65649 64165 64165 65648 65650 64165 64168 65648 64165 64167 64168 64166 64167 64657 64168 64167 64166 64651 64168 64166 64168 64651 65648 64664 64171 64170 64664 64173 64171 65191 65189 64172 64172 64173 65191 64173 64663 65191 64664 64663 64173 65193 64184 64174 64669 64186 64176 65204 65196 64178 64181 64182 64676 64182 64675 64676 64182 64183 64675 64184 64183 64182 64183 64668 64670 64183 64184 64668 65198 64675 64183 64183 65197 65198 64183 64671 65197 64183 64670 64671 65193 64668 64184 64187 64192 64193 65208 64679 64188 64188 65207 65208 64188 64189 65207 64189 64190 64687 64189 64687 65207 64191 64680 64688 64191 64688 64690 65211 64193 64192 65666 65211 64192 64192 64684 65666 65210 64685 64193 65211 65210 64193 65668 64686 64194 64194 65667 65668 64194 65210 65667 64194 64685 65210 64197 64196 64195 64694 64197 64195 64195 64692 64694 65215 65214 64197 65687 65215 64197 64197 64694 65687 64198 64207 64700 65227 64200 64198 64198 64700 65227 64199 64701 64702 65229 64701 64199 64199 64200 65229 64200 65227 65229 65227 64700 64201 65228 65227 64201 64201 64202 65228 64700 64203 64201 64202 64211 65235 65235 65228 64202 64706 64206 64205 64707 64210 64206 64206 64706 64707 64724 64216 64208 65247 64724 64208 64208 65236 65247 64208 64701 65236 64712 64708 64209 64713 64712 64209 64737 64221 64210 65233 64737 64210 64210 64707 65233 64210 64219 64220 64221 64219 64210 65258 65256 64211 65256 65235 64211 64216 64214 64212 65237 64714 64213 65254 65237 64213 64213 64739 65254 64217 64215 64214 64214 64216 64217 64215 64217 64738 64218 64217 64216 64724 64218 64216 65259 64738 64217 64217 64218 65259 64218 64724 65252 65260 65259 64218 64218 65252 65260 65250 64736 64221 64221 64737 65250 64736 64224 64221 64227 64225 64222 64773 64227 64222 64738 64229 64223 64224 64740 64756 64224 64736 64740 65721 65264 64225 64225 65270 65721 65725 65270 64225 64225 64227 65725 65265 64739 64226 64226 64764 65265 64227 64773 65725 64228 64229 64744 64745 64237 64228 64228 64744 64745 64229 64738 64744 64230 64761 64771 64231 64232 64246 64233 64232 64231 65275 64233 64231 64231 64246 65275 64232 64241 64242 64232 64242 64246 65275 64773 64233 64237 64236 64234 64774 64235 64234 64234 64236 64774 64235 65274 65276 64235 64774 65274 64236 64237 64745 64236 64762 64774 64236 64745 64762 64777 64764 64238 64238 64776 64777 64238 64240 64776 64776 64240 64239 64780 64776 64239 64239 64245 64780 64791 64246 64242 64243 64244 65750 65296 65295 64243 65750 65296 64243 64244 65284 65750 64244 65276 65284 65277 64780 64245 65297 65277 64245 64245 64787 65297 64246 64795 65275 64246 64791 64795 64247 64790 64798 64247 64786 64790 65741 64789 64248 64248 65288 65741 65289 65288 64248 65756 65289 64248 64248 64793 65756 64248 64792 64793 64248 64249 64792 64249 64268 64792 65300 64255 64250 64250 65298 65300 64250 64251 65298 64790 64786 64252 64798 64790 64252 64252 64253 64798 64254 64253 64252 64785 64254 64252 64786 64785 64252 64801 64798 64253 65310 64801 64253 64253 65309 65310 65316 65309 64253 64253 64254 65316 65776 65316 64254 66210 65776 64254 64254 65753 66210 64254 64785 65753 64794 64256 64255 65300 64794 64255 64260 64259 64258 65757 64260 64258 64258 64794 65757 64264 64263 64259 64271 64264 64259 64797 64271 64259 64259 64262 64797 64259 64260 64262 66209 64262 64260 64260 65761 66209 64260 65757 65761 65766 64797 64262 66209 65766 64262 64271 64270 64264 65752 65307 64265 65775 65752 64265 64265 65308 65775 64265 64803 65308 64265 64802 64803 64799 64267 64266 65304 64796 64267 64267 64800 65304 64267 64799 64800 64793 64792 64268 65305 64793 64268 64268 64269 65305 64269 64796 65305 64280 64276 64270 64809 64280 64270 64270 64807 64809 64808 64807 64270 65314 64808 64270 64270 64271 65314 64271 64797 65314 64801 64273 64272 64272 64798 64801 64801 64274 64273 65317 64275 64274 64274 64801 65317 65317 64804 64275 64280 64278 64276 64812 64802 64277 64277 64283 64812 64280 64279 64278 64279 64281 64282 64279 64280 64281 64809 64281 64280 64833 64282 64281 66251 64833 64281 64281 65789 66251 64281 65784 65789 64281 64809 65784 64833 64821 64282 64822 64814 64284 64826 64822 64284 64284 64285 64826 64285 64824 64826 64285 64286 64824 65790 64824 64286 64286 65323 65790 64286 64289 65323 64805 64295 64287 65322 64818 64288 66245 65322 64288 66256 66245 64288 64288 65810 66256 64288 64841 65810 64288 64819 64841 64818 64816 64288 64289 64836 65323 64289 64292 64836 64290 64291 64828 64294 64293 64290 65324 64294 64290 64290 64827 65324 64828 64827 64290 64291 64805 64806 64291 64295 64805 64831 64828 64291 64832 64831 64291 64291 64806 64832 64837 64836 64292 64292 64294 64837 65324 64837 64294 64844 64301 64296 66705 66262 64297 64297 66271 66705 64297 66270 66271 64297 65325 66270 64297 64298 65325 64299 64298 64297 66262 64299 64297 64298 64299 65798 64298 64300 65325 64301 64300 64298 66262 65798 64299 65326 65325 64300 65339 65326 64300 64300 64844 65339 64300 64301 64844 64843 64841 64302 64841 64303 64302 64841 64304 64303 64841 64305 64304 64841 64838 64305 64306 64313 64314 65353 64862 64307 64307 65346 65353 64307 65345 65346 64307 65340 65345 64307 64308 65340 64308 65327 65340 64308 64839 65327 64312 64311 64310 65352 64312 64310 65820 65352 64310 64310 65350 65820 64310 64316 65350 65371 65351 64312 64312 65352 65371 64845 64314 64313 65373 64845 64313 64314 64846 65328 64314 64845 64846 64857 64849 64315 65819 65350 64316 64316 64848 65819 64317 64319 64865 64317 64318 64319 65351 64319 64318 64318 64850 65351 65368 64865 64319 64319 65351 65368 64323 64322 64320 64320 64321 64867 64322 64321 64320 65362 64867 64321 64321 64322 65362 64322 65359 65362 64322 64861 65359 64324 64859 64866 64324 64852 64859 64858 64852 64324 64324 64854 64858 64860 64854 64324 64324 64325 64860 64326 64325 64324 64866 64326 64324 64325 64327 64860 64328 64327 64325 64325 64326 64328 64329 64328 64326 64335 64329 64326 64340 64335 64326 64344 64340 64326 64326 64343 64344 65363 64343 64326 64326 64866 65363 64870 64860 64327 64327 64336 64870 64327 64330 64336 64331 64330 64327 64327 64329 64331 64327 64328 64329 64335 64331 64329 64330 64333 64336 64337 64333 64330 64330 64331 64337 64331 64335 64340 64358 64337 64331 64331 64341 64358 64331 64340 64341 64334 64333 64332 65369 64334 64332 65374 65369 64332 64332 64872 65374 64332 64346 64872 64332 64333 64346 64333 64334 64336 64333 64338 64346 64870 64336 64334 64334 64868 64870 64869 64868 64334 65369 64869 64334 64338 64339 64346 64872 64346 64339 64339 64871 64872 64339 64347 64871 64342 64341 64340 64345 64342 64340 64340 64344 64345 64877 64358 64341 65380 64877 64341 64341 64342 65380 64342 64345 65380 65380 64345 64343 64343 65378 65380 65379 65378 64343 64343 65363 65379 64345 64344 64343 64347 64348 64871 64349 64348 64347 64363 64349 64347 64347 64359 64363 64348 64350 64871 64352 64350 64348 64348 64349 64352 64364 64352 64349 64349 64363 64364 65377 64871 64350 64350 65375 65377 64350 64351 65375 64352 64351 64350 65376 65375 64351 65849 65376 64351 64351 65386 65849 64351 64352 65386 64352 64364 64366 64352 64883 65386 64352 64367 64883 64352 64366 64367 64890 64372 64353 64353 64376 64890 64377 64376 64353 64353 64354 64377 64354 64884 65389 64354 64355 64884 64354 64376 64377 64898 64376 64354 65389 64898 64354 64355 64356 64884 65389 64884 64356 64356 64357 65389 64357 65381 65389 64358 64877 64878 64359 64882 64886 64359 64360 64882 64359 64362 64363 64886 64362 64359 64887 64882 64360 64360 64361 64887 65384 64887 64361 64361 64878 65384 64365 64363 64362 64371 64365 64362 64888 64371 64362 64362 64886 64888 64365 64364 64363 64364 64365 64366 64371 64366 64365 64368 64367 64366 64879 64368 64366 64888 64879 64366 64366 64371 64888 65388 64883 64367 64367 65387 65388 64367 64879 65387 64367 64368 64879 64897 64895 64369 64375 64374 64373 64893 64375 64373 64374 64375 65869 65404 64897 64374 65869 65404 64374 64375 64893 65869 64376 64381 64890 64376 64378 64381 64898 64378 64376 65410 64379 64378 65873 65410 64378 64378 65872 65873 64378 65407 65872 64378 64898 65407 64903 64384 64379 65410 64903 64379 64380 64382 64891 64382 64386 64899 64899 64891 64382 64904 64389 64383 64383 64900 64904 64903 64902 64384 64397 64386 64385 64925 64397 64385 64912 64899 64386 64386 64398 64912 64386 64397 64398 64387 66307 66308 66760 66307 64387 64387 65877 66760 64400 64399 64388 64388 64389 64400 64904 64400 64389 64390 64391 64393 64392 64391 64390 64909 64392 64390 64390 64405 64909 64390 64393 64405 65416 64913 64391 65417 65416 64391 64391 64392 65417 64392 64916 65417 64917 64916 64392 64918 64917 64392 64392 64909 64918 64396 64395 64394 64413 64396 64394 64914 64413 64394 65428 64914 64394 65430 65428 64394 64394 64910 65430 64911 64910 64394 64394 64406 64911 64394 64395 64406 64407 64406 64395 64396 64413 64416 64915 64398 64397 64925 64915 64397 65882 64912 64398 65889 65882 64398 65890 65889 64398 65900 65890 64398 65905 65900 64398 64398 64915 65905 64410 64409 64399 64399 64400 64410 65419 64410 64400 64400 64904 65419 64402 64403 64404 64901 64404 64403 64913 64901 64403 64404 65413 65423 64404 64901 65413 65423 64908 64404 64405 64411 64909 64406 64407 64911 65434 64417 64408 64408 64924 65434 65450 64926 64409 65898 65450 64409 64409 64410 65898 64410 65874 65898 64410 65419 65874 64918 64909 64411 65437 64918 64411 65454 65437 64411 64411 64434 65454 64411 64412 64434 64413 64414 64416 64415 64414 64413 64914 64415 64413 64921 64920 64414 65443 64921 64414 64414 64415 65443 64415 65442 65443 64415 64919 65442 64415 64914 64919 64928 64927 64417 65434 64928 64417 64929 64422 64418 64927 64421 64420 65458 64939 64421 64421 64928 65458 64421 64927 64928 65436 64925 64422 64422 64929 65436 64423 64920 64935 64424 64426 64936 64939 64426 64425 65461 64936 64426 64426 64940 65461 64426 64939 64940 64427 64428 64429 65462 64429 64428 65467 65462 64428 64428 64949 65467 65462 64942 64429 64930 64437 64431 64431 64432 64930 64433 64432 64431 64933 64930 64432 64432 64932 64933 64943 64932 64432 64434 64934 65454 64930 64438 64437 64944 64440 64438 64946 64944 64438 64438 64930 64946 64439 64440 64934 64944 64934 64440 64948 64442 64441 64441 64947 64948 64441 64945 64947 64948 64443 64442 64954 64444 64443 65471 64954 64443 64443 64948 65471 64957 64955 64444 64444 64953 64957 64954 64953 64444 64445 66840 67274 67256 66840 64445 64445 66391 67256 64445 64446 66391 64447 64446 64445 67274 64447 64445 66822 66391 64446 64446 64447 66822 67626 66822 64447 64447 67274 67626 64973 64962 64448 64968 64451 64449 65475 64970 64450 65478 65475 64450 64450 64963 65478 64966 64965 64452 65491 64966 64452 64452 64453 65491 64453 64969 65491 64976 64464 64454 64454 64455 64976 64979 64976 64455 64455 64462 64979 64983 64982 64457 64974 64459 64458 64458 64468 64974 64458 64467 64468 65483 64975 64459 64459 64974 65483 64476 64475 64460 64460 64471 64476 64472 64471 64461 64965 64472 64461 64462 64478 64979 64989 64478 64462 64462 64463 64989 64463 64477 64989 65011 64481 64464 64464 64999 65011 64464 64998 64999 64464 64976 64998 64991 64981 64466 65500 64991 64466 64466 65498 65500 64981 64473 64466 64978 64468 64467 64467 64469 64978 65485 64974 64468 64468 64978 65485 64984 64978 64469 64469 64470 64984 64988 64984 64470 64470 64475 64988 65494 64476 64471 64471 64472 65494 64472 65490 65494 64472 64966 65490 64472 64965 64966 64981 64980 64473 64474 64484 64983 64474 64483 64484 64475 64476 64988 65493 64988 64476 65494 65493 64476 64477 64478 64989 64478 64479 64979 64990 64979 64479 64480 64481 65011 64482 64481 64480 64995 64484 64483 64483 64489 64995 64483 64485 64489 65501 64983 64484 64484 64995 65501 64490 64489 64485 64494 64490 64485 65008 64996 64486 64486 64997 65008 64999 64488 64487 65011 64999 64487 64999 64998 64488 64489 64994 64995 65000 64994 64489 64489 64490 65000 64490 64494 65000 64499 64498 64491 64491 64492 64499 64492 65008 65511 64492 64996 65008 65020 64499 64492 65514 65020 64492 64492 65511 65514 65012 65010 64493 64494 64506 65000 65002 64502 64495 64495 64496 65002 64496 65001 65002 65005 65001 64496 64496 65004 65005 65007 65004 64496 64497 65006 65007 64497 64504 65006 64497 64503 64504 65019 64503 64498 64498 64499 65019 65526 65019 64499 64499 65020 65526 65024 65009 64500 64500 64517 65024 64500 64505 64517 65993 65015 64501 64501 65992 65993 64501 65013 65992 64502 65003 65021 64502 65002 65003 65021 64511 64502 65018 64504 64503 65019 65018 64503 65513 65006 64504 65982 65513 64504 65987 65982 64504 64504 65018 65987 64505 64512 64517 65522 65000 64506 64506 64507 65522 64508 64507 64506 65528 65522 64507 64507 64515 65528 64507 64508 64515 64509 64510 65022 64511 64510 64509 65529 65022 64510 64510 64511 65529 64511 65021 65529 65035 64517 64512 64512 64516 65035 65532 65528 64515 66014 65532 64515 64515 65029 66014 64516 64523 65035 64516 64522 64523 64517 65023 65024 65032 65023 64517 65035 65032 64517 64518 64524 65037 64518 64519 64524 64520 64519 64518 65037 64520 64518 64525 64524 64519 65038 64526 64520 64520 65037 65038 64527 64522 64521 64528 64523 64522 64522 64527 64528 64523 65032 65035 65034 65032 64523 65041 65034 64523 65048 65041 64523 64523 65045 65048 64523 64528 65045 65534 65037 64524 64524 64525 65534 64525 65049 65534 66005 65531 64526 64526 66003 66005 64526 66002 66003 64526 65038 66002 65045 64528 64527 64527 65040 65045 65059 64541 64529 64530 64536 65051 65055 65054 64531 64531 64532 65055 65553 65055 64532 64532 65052 65553 64532 64533 65052 65053 65052 64533 64533 64534 65053 65555 65053 64534 65556 65555 64534 65562 65556 64534 64534 65062 65562 64534 64535 65062 64535 65057 65062 64536 64538 65051 64537 64539 65056 65056 64538 64537 65558 65051 64538 64538 65056 65558 64539 65054 65056 65066 64542 64541 65563 65066 64541 64541 65059 65563 65087 64544 64543 65584 65087 64543 64543 65065 65584 65071 65064 64545 65074 64548 64547 64547 64553 65074 65570 65067 64548 64548 65074 65570 64549 64554 65077 64552 64551 64550 65081 64552 64550 65574 65073 64552 64552 65081 65574 64553 65073 65074 65585 65077 64554 65589 65585 64554 64554 65091 65589 64554 64555 65091 64562 64558 64557 65597 64563 64558 64558 64562 65597 65098 64564 64559 65088 64561 64560 65089 65088 64560 65090 65089 64560 64561 65103 65105 64561 65088 65103 65116 64575 64561 64561 65114 65116 64561 65105 65114 64562 65107 65597 65607 65107 64562 64562 65140 65607 64562 65136 65140 65097 65091 64563 65106 65097 64563 65107 65106 64563 65597 65107 64563 65098 65094 64564 65109 64569 64564 64564 65094 65109 64565 64583 64584 64565 64566 64583 64577 64570 64565 64565 64576 64577 64584 64576 64565 65129 64568 64567 64567 64585 65129 65598 65119 64568 66093 65598 64568 64568 65130 66093 64568 65129 65130 65109 65108 64569 64573 64572 64571 64579 64573 64571 65110 64579 64571 64571 65099 65110 65101 65099 64571 65591 65101 64571 65592 65591 64571 65601 65592 64571 64571 64595 65601 64571 64572 64595 64572 64573 64595 64573 64580 64594 64573 64579 64580 64573 64594 64595 64574 64575 65116 65117 64581 64574 64574 65116 65117 64578 65111 65124 64578 65110 65111 64578 64579 65110 65131 64594 64580 65606 65126 64581 64581 65117 65606 65626 65619 64582 66104 65626 64582 64582 65614 66104 64583 64597 64603 64603 64584 64583 64585 65128 65129 64585 65121 65128 64585 64601 65121 64585 64592 64601 64585 64586 64592 64600 64591 64586 64605 64600 64586 64586 64593 64605 64586 64589 64592 64587 64588 64589 64592 64589 64588 64601 64592 64588 65121 64601 64588 64588 65120 65121 64590 65126 65135 65613 64596 64590 64590 65134 65613 65135 65134 64590 64591 65145 65625 64591 64600 65145 65625 64607 64591 64593 64604 64605 64594 65131 65601 65601 64595 64594 65613 65132 64596 64598 64599 65144 64600 64605 64608 65148 65145 64600 64600 64608 65148 65133 65131 64602 64608 64605 64604 65622 65142 64606 65625 65622 64606 64606 64607 65625 64609 64612 66117 64615 64612 64609 64612 64611 64610 66117 64612 64610 64610 65630 66117 65631 65630 64610 66119 65631 64610 64610 64611 66119 64611 64613 65634 64611 64612 64613 64611 65634 66119 64616 64613 64612 64612 64615 64616 64613 64616 65634 65629 65152 64614 64616 64617 64620 64616 64620 65634 65153 64623 64618 64619 65147 65148 65632 65147 64619 65633 65632 64619 64619 64625 65633 65635 65634 64620 64620 64628 65635 64620 64621 64628 64622 64623 64640 64640 64631 64622 64623 65153 65163 65163 64640 64623 65157 64625 64624 64625 65157 65633 65174 65168 64627 64627 65158 65174 64628 65160 65635 64628 64629 65160 64629 64630 65160 65161 65160 64630 65162 65161 64630 64630 64631 65162 65163 65162 64631 64631 64640 65163 64632 64646 65175 64633 64634 64635 64636 64635 64634 64635 64638 64639 65173 64638 64635 64635 64642 65173 64635 64636 64642 65176 64642 64636 64636 65172 65176 64637 64638 65182 64639 64638 64637 65177 64639 64637 65182 65177 64637 64638 65181 65182 64638 65173 65181 65177 64643 64639 65166 65157 64641 65639 65166 64641 64641 64648 65639 65186 65173 64642 65641 65186 64642 64642 65176 65641 64649 64647 64643 65177 64649 64643 64645 64647 64650 64645 64655 64656 64645 64650 64655 65640 65175 64646 64646 65170 65640 64647 64649 64650 64648 65183 65639 65177 64650 64649 64650 64654 64655 65182 64654 64650 64650 65177 65182 65650 65648 64651 64651 65169 65650 65186 65178 64653 65647 65183 64658 65649 65647 64658 65184 65171 64659 64661 65654 65655 64661 65652 65654 64661 64662 65652 64663 64662 64661 64665 64663 64661 65655 64665 64661 64662 64663 65651 64662 64666 65652 64663 64664 65187 64663 65188 65191 64663 64665 65188 64663 65187 65651 64665 64672 65188 65655 64672 64665 66129 65652 64666 64666 64667 66129 66130 66129 64667 64667 65653 66130 65193 64670 64668 64672 64671 64670 65194 64672 64670 64670 65193 65194 65654 65197 64671 65655 65654 64671 64671 64672 65655 65189 65188 64672 65190 65189 64672 65194 65190 64672 64676 64675 64673 65199 64677 64673 65660 65199 64673 64673 64674 65660 64675 64674 64673 64674 65659 65660 64674 65197 65659 65198 65197 64674 64674 64675 65198 65199 64678 64677 64678 65199 65205 65208 64680 64679 64689 64688 64680 64680 64681 64689 64682 64681 64680 65208 64682 64680 66144 64689 64681 64681 65671 66144 64681 64682 65671 64682 65207 65671 65208 65207 64682 65209 64684 64683 64683 65205 65209 64684 65665 65666 64684 65664 65665 64684 65209 65664 65669 65206 64686 64686 65668 65669 64687 65206 65207 64688 64689 64690 65682 64690 64689 66145 65682 64689 66146 66145 64689 64689 66144 66146 65682 65213 64690 65213 64693 64690 64693 64692 64691 64692 64693 64694 65213 64694 64693 64694 65682 65687 64694 65213 65682 64704 64703 64695 64695 64698 64704 64695 64696 64698 64697 64696 64695 64703 64697 64695 64699 64698 64696 65216 64699 64696 65219 65216 64696 64696 65218 65219 64696 64705 65218 64696 64697 64705 64697 64703 64705 64698 65216 65220 64698 64699 65216 65222 64704 64698 65224 65222 64698 64698 65220 65224 64701 65229 65236 64718 64705 64703 64703 64715 64718 64716 64715 64703 64703 64704 64716 65222 64716 64704 65232 65218 64705 65243 65232 64705 65694 65243 64705 64705 64719 65694 64705 64718 64719 65225 64707 64706 65226 65225 64706 64706 65214 65226 65234 65233 64707 65695 65234 64707 64707 65225 65695 65693 65678 64708 65700 65693 64708 64708 65699 65700 64708 64712 65699 64717 64711 64709 64718 64717 64709 64719 64718 64709 65241 64719 64709 64709 64723 65241 64709 64710 64723 64711 64710 64709 64728 64723 64710 64710 64725 64728 64710 64711 64725 64711 64717 64721 64711 64721 64725 64712 65237 65707 64712 64713 65237 65707 65699 64712 64713 64714 65237 64715 64717 64718 64720 64717 64715 64715 64716 64720 65248 64720 64716 64716 65238 65248 65239 65238 64716 64716 65222 65239 64717 64720 64721 64719 65241 65694 65248 64722 64720 64722 64721 64720 64726 64725 64721 64721 64722 64726 64722 65248 65253 64727 64726 64722 65253 64727 64722 65249 65241 64723 64723 64734 65249 64723 64728 64734 64724 65247 65252 64732 64728 64725 64725 64726 64732 64746 64735 64726 65255 64746 64726 64726 64727 65255 64735 64732 64726 65710 65255 64727 64727 65253 65710 64728 64733 64734 64735 64733 64728 64728 64732 64735 65250 64737 64729 64729 64741 65250 64743 64741 64729 66166 64743 64729 66640 66166 64729 64729 64730 66640 64731 64730 64729 64737 64731 64729 67063 66640 64730 64730 64731 67063 64731 65245 67063 64731 64737 65245 65249 64734 64733 65261 65249 64733 64733 64752 65261 64733 64751 64752 64733 64735 64751 64735 64750 64751 64735 64746 64750 64753 64740 64736 65250 64753 64736 65246 65245 64737 65695 65246 64737 64737 65234 65695 64737 65233 65234 65259 64763 64738 64745 64744 64738 64763 64745 64738 65265 65254 64739 64740 64753 64756 64741 64742 65250 64743 64742 64741 64742 64753 65250 64755 64753 64742 66179 64755 64742 64742 64743 66179 66180 66179 64743 64743 66166 66180 64763 64762 64745 64757 64750 64746 64758 64757 64746 65255 64758 64746 65263 64752 64747 65266 65263 64747 65267 65266 64747 64747 64768 65267 64747 64748 64768 64749 64748 64747 64750 64749 64747 64751 64750 64747 64752 64751 64747 64748 64759 64768 64760 64759 64748 64748 64749 64760 64778 64760 64749 64749 64757 64778 64749 64750 64757 65263 65261 64752 64769 64756 64753 64753 64754 64769 64755 64754 64753 65720 64769 64754 66182 65720 64754 64754 66179 66182 64754 64755 66179 65268 64778 64757 66173 65268 64757 64757 64758 66173 64758 66168 66173 64758 65710 66168 64758 65255 65710 65273 64768 64759 65281 65273 64759 64759 65280 65281 64759 64765 65280 64766 64765 64759 64779 64766 64759 64759 64767 64779 64759 64760 64767 64781 64767 64760 64783 64781 64760 64760 64778 64783 64761 64770 64771 65282 64770 64761 64761 64769 65282 64762 65722 65726 64762 65716 65722 64762 64763 65716 65274 64774 64762 65726 65274 64762 64763 65259 65716 64764 64777 65265 65733 65280 64765 64765 64766 65733 64766 65293 65733 64766 65279 65293 64766 64779 65279 64782 64779 64767 64767 64781 64782 65273 65267 64768 65720 65282 64769 64772 64771 64770 65734 64772 64770 64770 65283 65734 64770 65282 65283 64773 65272 65725 65275 65272 64773 64775 64776 64780 64777 64776 64775 65285 64777 64775 64775 64780 65285 65724 65265 64777 64777 65285 65724 65278 64783 64778 66185 65278 64778 64778 65268 66185 64779 64782 65279 64780 65277 65285 64783 64782 64781 65293 65279 64782 65294 65293 64782 64782 65292 65294 64782 64784 65292 64782 64783 64784 65291 64784 64783 64783 65278 65291 64784 65291 65292 66205 65753 64785 64785 65295 66205 64787 64788 65297 64788 65286 65297 65287 65286 64788 64788 64789 65287 65741 65287 64789 65301 64795 64791 65764 65756 64793 64793 65305 65764 64794 65751 65757 64794 65300 65751 65301 65275 64795 64796 65304 65305 64797 64808 65314 66230 64808 64797 64797 66224 66230 64797 65766 66224 65306 64800 64799 65762 65304 64800 64800 65306 65762 64801 65310 65317 64813 64803 64802 64802 64812 64813 64803 65315 65783 64803 64813 65315 65779 65308 64803 65783 65779 64803 64806 64805 64804 65317 64806 64804 65317 64832 64806 65784 64809 64807 64807 64808 65784 65785 65784 64808 64808 65781 65785 65782 65781 64808 66230 65782 64808 65319 64811 64810 64810 64815 65319 65319 65318 64811 64814 64813 64812 64813 64814 65315 64814 64822 65786 65783 65315 64814 65786 65783 64814 65320 65319 64815 65321 65320 64815 64818 64817 64816 65787 65321 64817 64817 65322 65787 64817 64818 65322 64819 64838 64841 64819 64820 64838 64835 64834 64821 65791 64835 64821 64821 64833 65791 64826 64825 64822 64822 64825 65786 66253 66252 64823 64823 65792 66253 64823 65790 65792 64823 64824 65790 64825 64824 64823 66252 64825 64823 64824 64825 64826 66231 65786 64825 66240 66231 64825 66252 66240 64825 64827 64837 65324 65793 64837 64827 64827 64828 65793 64828 64831 65780 64828 65780 65793 64831 65317 65780 64831 64832 65317 66251 65791 64833 65339 64844 64834 64834 64835 65339 64835 65791 65797 65797 65339 64835 65793 65323 64836 64836 64837 65793 64839 64840 65327 65807 65327 64840 64840 65799 65807 64841 64842 65810 64843 64842 64841 66274 65810 64842 64842 66273 66274 64842 65331 66273 64842 64843 65331 65809 65331 64843 64843 65328 65809 64847 64846 64845 65831 64847 64845 64845 65373 65831 65809 65328 64846 64846 65330 65809 66280 65330 64846 64846 65821 66280 64846 64847 65821 65823 65821 64847 65831 65823 64847 64848 64849 65361 65827 65819 64848 65839 65827 64848 64848 65361 65839 64849 64857 65361 64851 64856 65343 64851 64855 64856 64851 64854 64855 64858 64854 64851 64851 64852 64858 64853 64852 64851 65343 64853 64851 65341 64859 64852 64852 64853 65341 64853 65334 65341 65343 65334 64853 64860 64855 64854 65358 64856 64855 64855 64860 65358 65824 65343 64856 65826 65824 64856 64856 65358 65826 64857 64863 65361 65364 64866 64859 64859 65341 65364 64860 64868 65358 64870 64868 64860 64861 64862 65359 64862 65353 65359 65362 65361 64863 64863 64867 65362 64864 64865 65367 65368 65367 64865 65364 65363 64866 65826 65358 64868 65844 65826 64868 64868 64869 65844 64869 65843 65844 65848 65843 64869 64869 65369 65848 65374 64872 64871 65377 65374 64871 66328 65382 64873 64873 65370 66328 64873 64874 65370 64875 64874 64873 65382 64875 64873 64874 64875 64876 64874 65367 65370 65382 65381 64875 65384 64878 64877 64877 65383 65384 64877 65378 65383 65380 65378 64877 65400 65387 64879 64879 64880 65400 64881 64880 64879 64888 64881 64879 65864 65400 64880 64880 64881 65864 65865 65864 64881 64881 65863 65865 64881 65399 65863 64881 64888 65399 64887 64886 64882 65388 65386 64883 64885 64905 64906 65399 64888 64886 65863 65399 64886 66343 65863 64886 64886 65861 66343 64886 64889 65861 64886 64887 64889 65856 64889 64887 64887 65384 65856 66336 65861 64889 64889 65856 66336 64899 64892 64891 64894 64893 64892 64899 64894 64892 64893 64894 65869 64894 65401 65869 66777 65401 64894 64894 66361 66777 64894 65882 66361 64894 64912 65882 64894 64899 64912 64895 64896 64900 64897 64896 64895 65405 64900 64896 64896 65404 65405 64896 64897 65404 64898 65395 65407 64898 65389 65395 65405 64904 64900 65414 65413 64901 64901 64913 65414 64902 64903 65411 64903 65410 65411 64904 65418 65419 64904 65406 65418 64904 65405 65406 65893 65883 64906 64906 65420 65893 64906 64907 65420 65421 65420 64907 64907 64908 65421 65422 65421 64908 65423 65422 64908 64910 64923 65430 64910 64922 64923 65415 65414 64913 65416 65415 64913 65428 64919 64914 64915 65435 65905 64915 64925 65435 64916 65416 65417 64916 65415 65416 65881 65415 64916 66351 65881 64916 66373 66351 64916 64916 64917 66373 64917 66362 66373 64917 65899 66362 64917 64918 65899 64918 65437 65899 64919 65427 65442 64919 65425 65427 65428 65425 64919 64920 64921 64935 64947 64935 64921 65912 64947 64921 66379 65912 64921 64921 65444 66379 64921 65443 65444 66364 64923 64922 64922 65433 66364 65897 65430 64923 66793 65897 64923 64923 66363 66793 66364 66363 64923 65449 65434 64924 64924 65432 65449 64924 65431 65432 65436 65435 64925 65459 65458 64928 66381 65459 64928 64928 65449 66381 64928 65434 65449 64929 64941 65457 65457 65436 64929 64930 64931 64946 64933 64931 64930 65453 65452 64931 65909 65453 64931 64931 64932 65909 64933 64932 64931 65452 64946 64931 64932 65907 65909 65908 65907 64932 64932 65460 65908 64932 64943 65460 64934 65451 65454 64934 64944 65451 64947 64945 64935 64938 64937 64936 65461 64938 64936 66800 65456 64937 64937 66386 66800 64937 64938 66386 64938 65461 66387 66387 66386 64938 65458 64940 64939 66387 65461 64940 64940 65459 66387 64940 65458 65459 64941 64942 65457 64942 65462 65463 65463 65457 64942 65943 65460 64943 64943 65926 65943 65452 65451 64944 64944 64946 65452 65469 64948 64947 65941 65469 64947 64947 65930 65941 64947 65912 65930 64948 65469 65471 65470 64952 64950 65942 65470 64951 66382 65942 64951 66797 66382 64951 64951 65917 66797 64951 65450 65917 65470 64958 64952 65472 64957 64953 65954 65472 64953 64953 65946 65954 64953 64954 65946 64954 65471 65946 64957 64956 64955 64956 65472 65955 64956 64957 65472 64956 65473 66390 65474 65473 64956 65955 65474 64956 65479 64967 64958 64958 64959 65479 64960 64959 64958 65470 64960 64958 64967 64964 64958 66400 65479 64959 64959 64960 66400 66401 66400 64960 64960 66382 66401 64960 65942 66382 64960 65470 65942 66396 65926 64961 64961 64972 66396 64961 64962 64972 64973 64972 64962 64963 64967 65478 64963 64964 64967 64966 65489 65490 65964 65489 64966 64966 65960 65964 64966 65491 65960 65480 65478 64967 64967 65479 65480 65960 65491 64969 64969 65476 65960 64969 65475 65476 64969 64970 65475 66402 66396 64972 66412 66402 64972 64972 64973 66412 64973 65957 66412 65958 65957 64973 64973 64992 65958 65485 65483 64974 64976 64990 64998 64976 64979 64990 64978 65482 65485 64978 65481 65482 65486 65481 64978 65488 65486 64978 64978 64984 65488 64980 64991 64992 64980 64981 64991 65968 65498 64982 64982 65502 65968 64982 65501 65502 64982 64983 65501 64984 65487 65488 65967 65487 64984 64984 64988 65967 64987 64986 64985 66445 64987 64985 66874 66445 64985 64985 65972 66874 64985 65967 65972 64985 65487 65967 64985 64986 65487 66866 65487 64986 64986 64987 66866 67293 66866 64987 67294 67293 64987 64987 66445 67294 65493 65492 64988 65972 65967 64988 64988 65492 65972 65505 64992 64991 64991 65500 65505 64992 65506 65958 64992 65505 65506 66452 65502 64993 64993 66451 66452 64993 65522 66451 64993 64994 65522 64995 64994 64993 65502 64995 64993 64994 65000 65522 65502 65501 64995 64997 65484 65963 64997 65483 65484 65511 65008 64997 65963 65511 64997 65524 65507 65001 65001 65509 65524 65001 65508 65509 65001 65005 65508 65003 65002 65001 65507 65003 65001 65523 65021 65003 65003 65507 65523 65513 65512 65004 65004 65006 65513 65007 65006 65004 65512 65005 65004 65510 65508 65005 65512 65510 65005 65009 65024 65515 66474 65518 65010 65010 66469 66474 66470 66469 65010 65010 65516 66470 65010 65012 65516 65517 65516 65012 65013 65990 65992 65013 65519 65990 65520 65017 65014 65014 65016 65520 65014 65015 65016 65520 65016 65015 65993 65520 65015 65017 65521 65530 65017 65520 65521 65018 65526 65987 65018 65019 65526 65020 65525 65526 65985 65525 65020 65020 65514 65985 65021 65523 65986 65999 65529 65021 65021 65986 65999 65989 65515 65023 65023 65538 65989 65023 65537 65538 65023 65033 65537 65023 65032 65033 65515 65024 65023 65027 65026 65025 65028 65027 65025 65531 65028 65025 66014 65029 65026 65026 66006 66014 65026 65027 66006 65027 65028 66006 65028 66004 66006 65028 65531 66004 66019 65535 65030 66486 66019 65030 65030 65031 66486 66487 66486 65031 65031 66017 66487 65034 65033 65032 65540 65537 65033 65033 65041 65540 65033 65034 65041 65036 65533 65548 65036 65530 65533 65534 65042 65037 66002 65038 65037 65037 65042 66002 65046 65040 65039 65536 65046 65039 66018 65536 65039 65039 65535 66018 65046 65045 65040 65550 65540 65041 65041 65541 65550 65041 65048 65541 65534 65049 65042 66479 66002 65042 66481 66479 65042 65042 65043 66481 65044 65043 65042 65557 65044 65042 65042 65049 65557 65043 66016 66481 65043 65044 66016 66495 66016 65044 66496 66495 65044 66497 66496 65044 65044 65557 66497 65541 65048 65045 65045 65047 65541 65045 65046 65047 65536 65047 65046 65047 65536 66027 66027 65541 65047 65049 65552 65557 65049 65051 65552 65569 65059 65050 66042 65569 65050 65050 66033 66042 66034 66033 65050 66035 66034 65050 65050 65548 66035 65558 65552 65051 65555 65553 65052 65052 65053 65555 65560 65056 65054 65054 65055 65560 66037 65560 65055 65055 65553 66037 66036 65559 65056 66040 66036 65056 66041 66040 65056 65056 65560 66041 65559 65558 65056 65057 65060 65061 65562 65062 65057 65057 65061 65562 65564 65563 65059 65569 65564 65059 65063 65061 65060 66512 65063 65060 65060 65571 66512 65060 65570 65571 65060 65067 65570 65061 65063 65562 65063 65561 65562 66512 65561 65063 65575 65065 65064 65064 65071 65575 65065 65575 65584 66043 65568 65066 66044 66043 65066 66045 66044 65066 65066 65563 66045 65069 65076 65572 65070 65572 66528 65072 65071 65070 66528 65072 65070 65576 65575 65071 65577 65576 65071 65071 65072 65577 66526 65577 65072 66527 66526 65072 66528 66527 65072 65075 65074 65073 65574 65075 65073 66047 65570 65074 65074 65075 66047 66521 66047 65075 66530 66521 65075 65075 66055 66530 65075 65574 66055 65076 65573 66049 65076 65566 65573 66049 65572 65076 65585 65078 65077 65078 65093 65586 65590 65093 65078 65078 65585 65590 65586 65093 65080 66052 65574 65081 66054 66052 65081 65081 65578 66054 65082 65086 65090 65082 65084 65086 65082 65083 65084 65084 65085 65086 65582 65086 65085 66068 65582 65085 65581 65090 65086 66058 65581 65086 65086 65582 66058 65087 65583 66068 65584 65583 65087 65088 65089 65096 65088 65095 65103 65096 65095 65088 65089 65090 65579 65579 65096 65089 65581 65580 65090 65580 65579 65090 65091 65588 65589 65595 65588 65091 65091 65097 65595 65590 65109 65092 65092 65093 65590 65094 65093 65092 65109 65094 65092 65093 65094 65098 65104 65103 65095 65095 65096 65104 66079 65104 65096 65096 65579 66079 66086 65595 65097 65097 66085 66086 65097 65106 66085 65099 65102 65110 65099 65100 65102 65101 65100 65099 65594 65102 65100 65100 65593 65594 66071 65593 65100 65100 65101 66071 65101 65591 66071 65102 65594 65596 65596 65110 65102 65113 65105 65103 65103 65112 65113 65103 65104 65112 65125 65112 65104 65599 65125 65104 66084 65599 65104 65104 66076 66084 66079 66076 65104 65105 65113 65125 65115 65114 65105 65125 65115 65105 65106 65107 65607 66099 66085 65106 65106 66098 66099 65106 65607 66098 65108 65109 65600 65109 66080 66089 65109 65590 66080 66089 65600 65109 65596 65111 65110 66081 65124 65111 66082 66081 65111 65111 65596 66082 65125 65113 65112 65604 65116 65114 65114 65603 65604 65114 65115 65603 65115 65602 65603 65115 65125 65602 65604 65117 65116 65117 65605 65606 65117 65604 65605 65118 65119 65587 65598 65587 65119 65608 65121 65120 65120 65123 65608 65608 65128 65121 65608 65123 65122 65122 65124 65608 66094 65608 65124 65124 66081 66094 65125 65599 65602 65606 65135 65126 65130 65129 65128 66548 65130 65128 66551 66548 65128 65128 65610 66551 65128 65608 65610 66548 66093 65130 65131 65133 65141 65131 65141 65601 65140 65136 65132 65132 65139 65140 65613 65139 65132 65621 65620 65133 65622 65621 65133 65133 65142 65622 65620 65141 65133 66103 65613 65134 65134 65618 66103 65134 65135 65618 65135 65605 65618 65606 65605 65135 65137 65138 66106 65139 65138 65137 65140 65139 65137 65623 65140 65137 66105 65623 65137 66106 66105 65137 65138 65139 66573 66573 66106 65138 65139 65613 66573 65623 65607 65140 65141 65592 65601 65616 65592 65141 66563 65616 65141 65141 65620 66563 65627 65153 65143 66111 65625 65145 65145 65146 66111 65147 65146 65145 65148 65147 65145 65146 65632 66111 65146 65147 65632 65149 65150 65158 65151 65150 65149 65628 65151 65149 65629 65628 65149 65149 65152 65629 65174 65158 65150 66122 65174 65150 65150 66116 66122 65150 65151 66116 66583 66116 65151 65151 66582 66583 65151 66578 66582 65151 65628 66578 65159 65154 65153 65627 65159 65153 65153 65154 65163 65159 65156 65154 65154 65162 65163 65154 65155 65162 65156 65155 65154 66581 65165 65155 65155 66580 66581 65155 65156 66580 65165 65162 65155 65156 65159 66580 65157 65166 65633 65159 66115 66580 65159 65627 66115 66125 65635 65160 66126 66125 65160 65160 65161 66126 65161 65162 66126 66597 66126 65162 65162 65164 66597 65165 65164 65162 66598 66597 65164 67010 66598 65164 65164 67009 67010 65164 65165 67009 65165 67008 67009 65165 66581 67008 65637 65633 65166 65638 65637 65166 65639 65638 65166 65646 65169 65167 65167 65645 65646 66128 65645 65167 66599 66128 65167 65167 65168 66599 65168 66590 66599 65168 66122 66590 65168 65174 66122 65169 65646 65650 65170 65172 65640 65185 65172 65170 65170 65171 65185 65171 65184 65185 65180 65176 65172 65185 65180 65172 65172 65175 65640 65186 65181 65173 65176 65180 65641 65178 65186 65641 65180 65179 65178 65641 65180 65178 65185 65184 65179 65179 65180 65185 66127 65639 65183 65183 65647 66127 65188 65189 65191 65193 65192 65190 65194 65193 65190 65195 65196 65653 65196 65204 65653 65197 65654 65659 65660 65201 65199 65662 65205 65199 65199 65200 65662 65201 65200 65199 66134 65662 65200 65200 66133 66134 65200 65201 66133 65201 65660 65661 65201 66132 66133 65201 65661 66132 65204 65203 65202 65658 65204 65202 66135 65658 65202 66603 66135 65202 65202 65203 66603 65203 65663 66603 65658 65653 65204 65664 65209 65205 65205 65662 65664 65212 65207 65206 65670 65212 65206 65206 65669 65670 65207 65212 65671 65210 65211 65667 66140 65667 65211 65211 65666 66140 66143 65671 65212 65212 66142 66143 65212 65670 66142 65214 65215 65226 65689 65226 65215 65692 65689 65215 65215 65687 65692 65216 65219 65220 66156 65690 65217 65217 65232 66156 65217 65218 65232 65219 65218 65217 65690 65219 65217 65680 65221 65219 65219 65679 65680 65690 65679 65219 65221 65220 65219 65683 65224 65220 65220 65221 65683 65221 65680 65681 65688 65683 65221 65221 65684 65688 65221 65681 65684 65691 65239 65222 65222 65223 65691 65224 65223 65222 66157 65691 65223 65223 65688 66157 65223 65224 65688 65224 65683 65688 66161 65695 65225 65225 65226 66161 65226 65689 66161 65231 65229 65227 65227 65228 65231 65228 65230 65231 65251 65230 65228 65228 65235 65251 65229 65230 65236 65231 65230 65229 65251 65236 65230 66159 66156 65232 65232 65243 66159 65705 65251 65235 65235 65256 65705 65251 65247 65236 65237 65254 65707 65704 65248 65238 66164 65704 65238 65238 65239 66164 65239 65691 66164 65242 65241 65240 65711 65242 65240 65240 65262 65711 65240 65249 65262 65240 65241 65249 65244 65243 65241 65241 65242 65244 65241 65243 65694 66165 65244 65242 66167 66165 65242 65242 65711 66167 66163 66159 65243 65243 65244 66163 66165 66163 65244 65245 67061 67063 65245 65246 67061 65246 65701 67061 65246 65695 65701 65247 65251 65252 65710 65253 65248 65248 65703 65710 65704 65703 65248 65249 65261 65262 65706 65252 65251 65251 65705 65706 65706 65260 65252 65718 65707 65254 65719 65718 65254 65724 65719 65254 65254 65265 65724 65258 65257 65256 65256 65257 65705 65257 65264 65717 65257 65258 65264 65713 65705 65257 65717 65713 65257 65259 65714 65716 65259 65260 65714 65260 65706 65714 65712 65262 65261 65261 65263 65712 65712 65711 65262 65263 65266 65712 66171 65717 65264 65264 65721 66171 66170 65712 65266 66175 66170 65266 66176 66175 65266 65266 65269 66176 65266 65267 65269 65273 65269 65267 66645 66185 65268 65268 66173 66645 65269 65273 66176 65270 65271 65721 65272 65271 65270 65725 65272 65270 66183 65721 65271 66184 66183 65271 65271 65738 66184 65271 65737 65738 66192 65737 65271 65271 65272 66192 65272 65746 66192 65272 65275 65746 66188 66176 65273 65273 66187 66188 65273 66186 66187 65273 65281 66186 65738 65736 65274 66172 65738 65274 65274 65726 66172 65749 65276 65274 65274 65736 65749 65275 65301 65746 65749 65284 65276 66169 65285 65277 66651 66169 65277 65277 65729 66651 65277 65297 65729 65278 65290 65291 65743 65290 65278 66185 65743 65278 66186 65281 65280 66191 66186 65280 65280 65733 66191 66189 65283 65282 65282 65720 66189 65735 65734 65283 66199 65735 65283 66650 66199 65283 65283 66189 66650 65284 65749 65750 66169 65724 65285 65729 65297 65286 65286 65728 65729 66193 65728 65286 65286 65287 66193 65287 65741 66193 66193 65741 65288 65288 65739 66193 65740 65739 65288 65288 65289 65740 65756 65740 65289 65292 65291 65290 65742 65292 65290 66194 65742 65290 65290 65743 66194 66655 65294 65292 65292 66195 66655 66196 66195 65292 65292 65742 66196 66191 65733 65293 66655 66191 65293 65293 65294 66655 65295 65296 66205 65296 66204 66205 65296 65750 66204 65751 65300 65298 65298 65299 65751 65299 65734 65751 65301 65302 65746 65748 65746 65302 65302 65303 65748 66203 65748 65303 65303 65752 66203 65303 65307 65752 65765 65305 65304 65304 65763 65765 65304 65762 65763 65765 65764 65305 65306 65311 65762 65308 65767 65775 65768 65767 65308 65772 65768 65308 65779 65772 65308 65309 65316 65776 65780 65310 65309 66227 65780 65309 65309 65776 66227 65780 65317 65310 65770 65762 65311 65771 65770 65311 65311 65312 65771 65313 65312 65311 65318 65313 65311 66681 65771 65312 65312 65313 66681 66685 66681 65313 65313 65777 66685 65313 65318 65777 65778 65777 65318 65318 65319 65778 65319 65320 65778 66241 65778 65320 65320 65788 66241 65320 65321 65788 65321 65787 65788 66245 65787 65322 65323 65793 66253 65792 65790 65323 66253 65792 65323 66272 66270 65325 65325 65326 66272 65326 65805 66272 65326 65339 65805 65807 65340 65327 65331 65330 65329 67145 65331 65329 65329 66280 67145 65329 65330 66280 65330 65331 65809 67144 66273 65331 67145 67144 65331 66281 65341 65332 65332 65333 66281 65334 65333 65332 65341 65334 65332 65333 65795 66281 65333 65794 65795 65333 65335 65794 65337 65335 65333 65333 65334 65337 65342 65337 65334 65343 65342 65334 65801 65794 65335 65335 65336 65801 65337 65336 65335 65803 65801 65336 65336 65338 65803 65336 65337 65338 65342 65338 65337 65338 65802 65803 65812 65802 65338 65338 65344 65812 65338 65342 65344 65339 65797 65805 65816 65345 65340 65817 65816 65340 65818 65817 65340 65340 65814 65818 65340 65813 65814 65340 65807 65813 65842 65364 65341 65341 65840 65842 65841 65840 65341 66281 65841 65341 65342 65343 65344 65812 65344 65343 65824 65812 65343 65347 65346 65345 65816 65347 65345 65346 65347 65354 65354 65353 65346 65816 65354 65347 65828 65820 65348 66724 65828 65348 65348 65349 66724 65350 65349 65348 65820 65350 65348 65349 66716 67162 65349 66279 66716 65349 65350 66279 67167 66724 65349 65349 67162 67167 65350 65819 66279 65372 65368 65351 65351 65371 65372 66746 65371 65352 65352 65830 66746 65352 65829 65830 65352 65828 65829 65352 65820 65828 65360 65359 65353 65817 65360 65353 65353 65354 65817 65354 65816 65817 67156 65357 65355 65355 67147 67156 67512 67147 65355 68244 67512 65355 68591 68244 65355 65355 65356 68591 65357 65356 65355 68593 68591 65356 65356 67882 68593 65356 65357 67882 65357 67163 67174 65357 67156 67163 65357 67876 67882 65357 67175 67876 65357 67174 67175 65366 65362 65359 65359 65360 65366 66282 65836 65360 65360 66278 66282 65360 65817 66278 65837 65366 65360 65360 65836 65837 65361 65365 65839 65361 65362 65365 65366 65365 65362 65845 65379 65363 65846 65845 65363 66293 65846 65363 65363 65364 66293 65364 65842 66293 65365 65837 65839 65365 65366 65837 65367 65368 65370 65372 65370 65368 65369 65374 65848 66332 66328 65370 65370 66317 66332 66318 66317 65370 66746 66318 65370 65370 65371 66746 65372 65371 65370 65373 65823 65831 66287 65823 65373 65373 66285 66287 66286 66285 65373 65374 65377 65848 66302 65377 65375 66316 66302 65375 65375 66305 66316 65375 65376 66305 65376 65849 66305 66302 65848 65377 65850 65383 65378 65378 65379 65850 65852 65850 65379 66323 65852 65379 65379 65845 66323 65859 65395 65381 65860 65859 65381 65381 65390 65860 65381 65382 65390 65395 65389 65381 66335 65390 65382 65382 66328 66335 65385 65384 65383 66329 65385 65383 65383 65850 66329 65384 65385 65856 65857 65856 65385 66329 65857 65385 66325 65849 65386 66327 66325 65386 65386 65388 66327 65392 65391 65387 65393 65392 65387 65400 65393 65387 65391 65388 65387 65388 66326 66327 65388 65391 66326 66339 65860 65390 65390 66335 66339 66759 66326 65391 65391 66338 66759 65391 65392 66338 65392 65394 66338 65392 65393 65394 65862 65858 65393 65393 65400 65862 65858 65394 65393 65394 65397 66338 65858 65397 65394 65859 65407 65395 66346 66345 65396 65396 65871 66346 65396 65870 65871 65396 65862 65870 65396 65397 65862 65398 65397 65396 66345 65398 65396 65397 65398 66338 65397 65858 65862 65398 66330 66338 66331 66330 65398 66766 66331 65398 65398 66345 66766 65867 65862 65400 65400 65864 65867 65401 65402 65869 65403 65402 65401 66777 65403 65401 65402 65406 65868 65402 65403 65406 65402 65868 65869 65892 65406 65403 66777 65892 65403 65406 65405 65404 65868 65406 65404 65869 65868 65404 65891 65418 65406 65892 65891 65406 66348 65872 65407 65407 65408 66348 65409 65408 65407 65860 65409 65407 65407 65859 65860 66774 66348 65408 65408 66770 66774 65408 65409 66770 65409 66768 66770 65409 66339 66768 65409 65860 66339 65412 65411 65410 65873 65412 65410 65411 65412 65431 66356 65431 65412 65412 66352 66356 65412 65873 66352 65884 65423 65413 65885 65884 65413 65413 65878 65885 65413 65414 65878 65879 65878 65414 65414 65415 65879 65880 65879 65415 65881 65880 65415 65891 65874 65418 65874 65419 65418 65420 65421 65893 66353 65893 65421 65421 65422 66353 65422 65884 66353 65422 65423 65884 65441 65439 65424 65895 65441 65424 65424 65429 65895 65424 65428 65429 65424 65425 65428 65426 65425 65424 65439 65426 65424 65425 65426 65427 65438 65427 65426 65439 65438 65426 65427 65438 65442 65897 65429 65428 65428 65430 65897 65429 65894 65895 65897 65894 65429 66356 65432 65431 65432 65448 65449 66356 65448 65432 65433 66363 66364 66375 66363 65433 65433 66365 66375 65435 65436 65905 65906 65905 65436 65436 65457 65906 65437 65451 65899 65454 65451 65437 65455 65442 65438 65438 65439 65455 65439 65440 65455 65441 65440 65439 65911 65455 65440 65916 65911 65440 65440 65910 65916 65440 65901 65910 65440 65441 65901 66359 65901 65441 65441 65895 66359 65904 65443 65442 65442 65455 65904 65904 65444 65443 65444 66378 66379 65444 65445 66378 65446 65445 65444 65904 65446 65444 66385 66378 65445 65445 65929 66385 65445 65913 65929 65916 65913 65445 65445 65446 65916 65446 65911 65916 65446 65904 65911 66381 65449 65447 65447 66367 66381 65447 65448 66367 65449 65448 65447 65448 66366 66367 65448 66357 66366 65448 66356 66357 65918 65917 65450 65450 65898 65918 66362 65899 65451 66372 66362 65451 65451 66371 66372 65451 65453 66371 65451 65452 65453 65453 65909 66371 65911 65904 65455 66799 66365 65456 66800 66799 65456 66376 65906 65457 65457 65936 66376 65457 65463 65936 65459 66380 66387 66381 66380 65459 65919 65908 65460 66383 65919 65460 65460 65943 66383 65936 65463 65462 65462 65935 65936 65462 65468 65935 65462 65467 65468 65464 65465 65934 65466 65465 65464 67612 65466 65464 68680 67612 65464 65464 67980 68680 65464 67255 67980 65464 65934 67255 68345 67953 65465 65465 65466 68345 67953 65934 65465 65466 67612 68345 66390 65468 65467 66391 65935 65468 67256 66391 65468 65468 66818 67256 65468 66390 66818 65946 65471 65469 65469 65940 65946 65941 65940 65469 65956 65955 65472 66398 65956 65472 65472 65953 66398 65954 65953 65472 66399 66390 65473 65473 65474 66399 66409 66399 65474 65474 66408 66409 65474 65956 66408 65474 65955 65956 65477 65476 65475 65478 65477 65475 65476 65959 65960 65476 65477 65959 65962 65959 65477 65477 65961 65962 66424 65961 65477 65477 65480 66424 65477 65478 65480 66419 65480 65479 66420 66419 65479 65479 66400 66420 66425 66424 65480 65480 66419 66425 65483 65482 65481 65484 65483 65481 66431 65484 65481 66432 66431 65481 65481 65486 66432 65482 65483 65485 65484 66431 66437 66437 65963 65484 66438 66432 65486 66444 66438 65486 66866 66444 65486 65486 65487 66866 65488 65487 65486 65504 65490 65489 66433 65504 65489 66435 66433 65489 65489 65964 66435 65504 65494 65490 65492 65493 65494 65974 65972 65492 65492 65503 65974 65492 65494 65503 65504 65503 65494 65505 65500 65495 65506 65505 65495 65980 65506 65495 65981 65980 65495 65495 65496 65981 65497 65496 65495 65500 65497 65495 66455 65981 65496 66457 66455 65496 66458 66457 65496 65496 65977 66458 65496 65497 65977 65500 65498 65497 65497 65499 65977 65497 65498 65499 65968 65499 65498 65499 65968 65977 66882 65968 65502 65502 66452 66882 65503 65973 65974 65976 65973 65503 65503 65504 65976 66433 65976 65504 65966 65965 65506 66436 65966 65506 65506 65980 66436 65965 65958 65506 65969 65523 65507 65970 65969 65507 65507 65524 65970 65971 65509 65508 65508 65510 65971 65978 65524 65509 65979 65978 65509 65509 65971 65979 65510 65512 65971 65984 65514 65511 65511 65963 65984 65512 65513 65982 65983 65971 65512 65512 65982 65983 66468 65985 65514 65514 66454 66468 65514 65984 66454 65989 65517 65515 66478 66470 65516 65516 66477 66478 65516 65988 66477 65516 65517 65988 65989 65988 65517 65991 65519 65518 66474 65991 65518 65991 65990 65519 65993 65521 65520 66026 65530 65521 66904 66026 65521 65521 65995 66904 65521 65994 65995 65521 65993 65994 65522 65528 66451 65523 65969 65986 65978 65970 65524 65527 65526 65525 66468 65527 65525 65525 65985 66468 65526 65527 65987 66461 65987 65527 66892 66461 65527 67690 66892 65527 65527 67688 67690 65527 66894 67688 65527 66468 66894 65528 65998 66451 65528 65532 65998 65529 65999 66011 66026 65533 65530 66005 66004 65531 66015 65998 65532 65532 66014 66015 65533 65547 65548 66012 65547 65533 66026 66012 65533 66019 66018 65535 67338 66027 65536 65536 66488 67338 66489 66488 65536 65536 66019 66489 65536 66018 66019 65539 65538 65537 65543 65539 65537 65537 65540 65543 66477 65989 65538 65538 65539 66477 66484 66477 65539 65539 65544 66484 65539 65543 65544 65545 65543 65540 65551 65545 65540 65540 65550 65551 66032 65550 65541 65541 66029 66032 65541 66027 66029 65542 65545 65551 65542 65543 65545 65544 65543 65542 65546 65544 65542 66020 65546 65542 66021 66020 65542 65542 65551 66021 65544 66024 66484 65544 65546 66024 65546 66023 66024 65546 66020 66023 65549 65548 65547 66494 65549 65547 65547 66492 66494 65547 66012 66492 65548 65549 66035 66498 66035 65549 66499 66498 65549 65549 66494 66499 66021 65551 65550 66039 66021 65550 65550 66031 66039 66032 66031 65550 66036 65557 65552 65552 65559 66036 65552 65558 65559 66504 66037 65553 65553 66038 66504 65553 65554 66038 65555 65554 65553 66508 66038 65554 65554 65556 66508 65554 65555 65556 65556 65561 66508 65562 65561 65556 65557 66036 66497 66501 66041 65560 66502 66501 65560 65560 66037 66502 66512 66508 65561 66046 66045 65563 65563 65564 66046 65564 65569 66046 65567 65566 65565 66057 65567 65565 65565 66051 66057 65565 66050 66051 65565 66043 66050 65565 65568 66043 65566 65567 65573 66057 65573 65567 65569 66042 66046 66047 65571 65570 66517 66512 65571 65571 66047 66517 65572 66056 66528 65572 66048 66056 66049 66048 65572 66961 66943 65573 65573 66057 66961 66943 66049 65573 65574 66052 66055 65575 65583 65584 66069 65583 65575 65575 66059 66069 65575 65576 66059 66060 66059 65576 65576 65577 66060 66526 66060 65577 65578 66053 66054 65579 66065 66079 65579 66058 66065 65579 65580 66058 65580 65581 66058 66537 66058 65582 66540 66537 65582 65582 66068 66540 66542 66068 65583 65583 66075 66542 65583 66069 66075 65585 65588 65590 65589 65588 65585 65595 65590 65588 65590 65595 66080 65591 66979 66980 65591 66083 66979 65591 65592 66083 66981 66071 65591 65591 66980 66981 65592 65616 66083 66062 65594 65593 66534 66062 65593 65593 66071 66534 65594 66063 66070 65594 66062 66063 66070 65596 65594 66086 66080 65595 65596 66070 66082 66097 65602 65599 65599 66096 66097 66546 66096 65599 65599 66084 66546 66091 65614 65600 65600 66089 66091 65612 65603 65602 66558 65612 65602 65602 66097 66558 65603 66102 66553 65603 65612 66102 66553 65604 65603 66554 65605 65604 65604 66553 66554 66561 65618 65605 65605 66554 66561 65607 65623 66098 66095 65610 65608 65608 66094 66095 66095 66094 65609 65609 65610 66095 65611 65610 65609 66552 65611 65609 65609 66549 66552 65609 66094 66549 66988 66551 65610 67402 66988 65610 65610 65611 67402 67403 67402 65611 65611 66552 67403 66564 66102 65612 65612 66558 66564 65613 66103 66573 65614 66091 66104 65615 66567 66568 65615 66566 66567 65615 66563 66566 65615 65616 66563 65617 65616 65615 66568 65617 65615 65616 65617 66083 66995 66083 65617 65617 66568 66995 65618 66561 66571 66571 66103 65618 65626 65624 65619 65620 65621 66563 66566 66563 65621 65621 65622 66566 66567 66566 65622 66999 66567 65622 65622 66112 66999 65622 65625 66112 66101 66098 65623 66105 66101 65623 66556 66109 65624 65624 65626 66556 65625 66111 66113 66570 66112 65625 65625 66113 66570 65626 66104 66556 65627 66110 66115 66582 66578 65628 66584 66582 65628 66588 66117 65630 67015 66588 65630 67020 67015 65630 65630 66592 67020 65630 65631 66592 65631 66120 66592 65631 66119 66120 65632 65637 66111 65632 65633 65637 66121 66119 65634 66123 66121 65634 65634 65636 66123 65634 65635 65636 66125 66124 65635 66124 65636 65635 66596 66123 65636 65636 66124 66596 66118 66111 65637 67004 66118 65637 65637 66594 67004 65637 66589 66594 65637 65638 66589 66595 66589 65638 65638 66127 66595 65638 65639 66127 67031 65644 65642 67414 67031 65642 67422 67414 65642 67786 67422 65642 65642 65643 67786 65644 65643 65642 65643 67032 67786 65643 65644 67032 67031 66128 65644 65644 66600 67032 65644 66599 66600 65644 66128 66599 65647 65646 65645 66128 65647 65645 65646 65649 65650 65646 65647 65649 67031 66127 65647 65647 66128 67031 66129 65654 65652 65653 65656 66130 65658 65656 65653 65654 66129 66130 66131 65659 65654 65654 66130 66131 66131 66130 65656 65656 65657 66131 65658 65657 65656 66601 66131 65657 65657 65658 66601 65658 66135 66601 65661 65660 65659 66131 65661 65659 65661 66131 66132 66134 65664 65662 66605 66603 65663 65663 65676 66605 66136 65665 65664 66137 66136 65664 66138 66137 65664 65664 66134 66138 66139 65666 65665 65665 66136 66139 65666 66139 66140 66140 65668 65667 66141 65669 65668 66608 66141 65668 65668 66140 66608 66141 65670 65669 66609 66142 65670 65670 66141 66609 65671 66143 66144 65674 65673 65672 67042 65674 65672 67045 67042 65672 65672 65673 67045 65673 65674 66612 67440 67045 65673 65673 67433 67440 65673 67041 67433 65673 66612 67041 65674 66146 66612 65674 66145 66146 66151 66145 65674 67042 66151 65674 66147 65677 65675 66148 66147 65675 66621 66605 65676 65676 65677 66621 65677 66604 66621 65677 66147 66604 66162 66154 65678 65678 66155 66162 65678 65693 66155 66152 65686 65679 66622 66152 65679 66628 66622 65679 65679 65690 66628 65681 65680 65679 65686 65681 65679 65686 65684 65681 66145 65687 65682 66158 65688 65684 67043 66158 65684 65684 65685 67043 65686 65685 65684 65685 66614 67043 65685 66613 66614 66617 66613 65685 65685 65686 66617 65686 66152 66617 66153 65692 65687 65687 66150 66153 65687 66145 66150 66158 66157 65688 65689 66160 66161 66632 66160 65689 67048 66632 65689 65689 65692 67048 65690 66627 66628 65690 66156 66627 66630 66164 65691 65691 66157 66630 65692 66153 67048 66634 66155 65693 65693 65700 66634 65702 65701 65695 66160 65702 65695 66161 66160 65695 66629 66162 65696 65696 65697 66629 65698 65697 65696 66155 65698 65696 66162 66155 65696 67053 66629 65697 65697 67052 67053 67441 67052 65697 65697 65698 67441 67798 67441 65698 65698 66635 67798 67055 66635 65698 65698 66155 67055 65707 65700 65699 65700 65707 66634 65701 67057 67061 65701 65702 67057 65702 66160 67057 66168 65710 65703 66638 66168 65703 65703 66633 66638 65703 65704 66633 65704 66164 66633 65714 65706 65705 65705 65713 65714 66635 66634 65707 65707 65708 66635 65709 65708 65707 65718 65709 65707 68174 68170 65708 65708 66641 68174 65708 65709 66641 67799 66635 65708 68170 67799 65708 65709 65719 66641 65709 65718 65719 66642 66167 65711 66643 66642 65711 65711 66170 66643 65711 65712 66170 65723 65715 65713 66171 65723 65713 65713 65717 66171 65715 65714 65713 65714 65715 65716 65723 65716 65715 65723 65722 65716 65719 65724 66641 65720 66182 66189 66183 66171 65721 66172 65726 65722 65722 66171 66172 65722 65723 66171 66647 66641 65724 65724 66169 66647 65727 65728 66193 65729 65728 65727 66651 65729 65727 66652 66651 65727 67086 66652 65727 65727 66653 67086 65727 66193 66653 65730 65743 66190 66654 65743 65730 65730 66206 66654 65730 65731 66206 65732 65731 65730 66190 65732 65730 67099 66206 65731 67474 67099 65731 65731 67473 67474 65731 65732 67473 65732 67469 67473 65732 67081 67469 65732 66190 67081 66201 65751 65734 66202 66201 65734 65734 65745 66202 65734 65735 65745 66657 65744 65735 65735 66199 66657 65735 65744 65745 65736 65737 66192 65738 65737 65736 65736 65747 65749 65748 65747 65736 66192 65748 65736 65738 66172 66184 66653 66193 65739 67089 66653 65739 65739 65754 67089 65739 65740 65754 65755 65754 65740 65756 65755 65740 66656 66196 65742 65742 66206 66656 65742 66194 66206 66654 66194 65743 65743 66185 66190 65744 66657 67092 67092 65745 65744 66207 66202 65745 66661 66207 65745 67092 66661 65745 65746 65748 66192 65750 65749 65747 66204 65750 65747 66662 66204 65747 65747 65769 66662 66200 65769 65747 65747 65748 66200 66203 66200 65748 66201 65757 65751 65752 65769 66203 65752 65768 65769 65752 65767 65768 65775 65767 65752 66663 66210 65753 65753 66205 66663 67097 67089 65754 65754 65755 67097 65755 66208 67097 65755 65756 66208 65756 65764 66208 66207 65761 65757 65757 66201 66207 67101 66225 65758 65758 67093 67101 65758 66657 67093 65758 65759 66657 65760 65759 65758 66225 65760 65758 65759 65761 66661 66209 65761 65759 65759 65760 66209 67092 66657 65759 65759 66661 67092 65760 65766 66209 66224 65766 65760 66225 66224 65760 65761 66207 66661 66211 65763 65762 65762 65770 66211 66666 65765 65763 65763 66211 66666 65764 65765 66208 66667 66208 65765 65765 66666 66667 66662 65769 65768 66680 66662 65768 65768 65772 66680 65769 66200 66203 66666 66211 65770 66677 66666 65770 65770 66664 66677 66665 66664 65770 65770 65771 66665 66681 66665 65771 66684 66680 65772 65772 65773 66684 65774 65773 65772 66231 65774 65772 65772 65779 66231 67123 66684 65773 67128 67123 65773 67129 67128 65773 65773 66701 67129 65773 65774 66701 65774 66240 66701 65774 66231 66240 65776 66226 66227 65776 66219 66226 65776 66210 66219 66687 66685 65777 65777 66241 66687 65777 65778 66241 65779 65783 66231 66255 65793 65780 65780 66227 66255 66679 66250 65781 65781 65782 66679 66250 65785 65781 65782 66230 66679 65783 65786 66231 65784 65785 65789 66250 65789 65785 67134 66696 65787 67138 67134 65787 65787 67137 67138 65787 66245 67137 66696 65788 65787 66687 66241 65788 66696 66687 65788 65789 66249 66251 66250 66249 65789 66251 65797 65791 66690 66253 65793 65793 66254 66690 66255 66254 65793 65796 65795 65794 65801 65796 65794 65795 66268 66281 65795 66261 66268 65795 65796 66261 65796 66248 66261 65796 65801 66248 65806 65805 65797 66251 65806 65797 65800 65799 65798 65808 65800 65798 66262 65808 65798 65799 65800 65807 65808 65807 65800 65801 65804 66248 65801 65803 65804 65802 65812 65825 65804 65803 65802 65811 65804 65802 66269 65811 65802 65802 65825 66269 65804 66247 66248 65804 66242 66247 66244 66242 65804 65804 65811 66244 65805 65806 66272 65806 66270 66272 66271 66270 65806 66709 66271 65806 65806 66259 66709 65806 66251 66259 66275 65813 65807 66276 66275 65807 66277 66276 65807 65807 65808 66277 65808 66264 66277 66707 66264 65808 65808 66262 66707 66274 66267 65810 66257 66256 65810 66267 66257 65810 66704 66703 65811 66708 66704 65811 65811 66269 66708 66700 66244 65811 66703 66700 65811 65812 65824 65825 66275 65815 65813 65815 65814 65813 65814 65815 65818 66275 65818 65815 65817 66276 66278 65817 65818 66276 65818 66275 66276 65819 65827 66279 66717 66280 65821 65821 65822 66717 65823 65822 65821 65822 66292 66717 65822 66288 66292 65822 66287 66288 65822 65823 66287 66713 65825 65824 65824 65832 66713 65824 65826 65832 66712 66269 65825 66713 66712 65825 66725 65832 65826 65826 65844 66725 66284 66279 65827 65827 65838 66284 65839 65838 65827 66731 65829 65828 67535 66731 65828 65828 67530 67535 65828 66724 67530 66318 65830 65829 66731 66318 65829 65830 66318 66746 66719 66713 65832 66725 66719 65832 65833 66728 66730 65833 66283 66728 65833 65836 66283 65837 65836 65833 65833 65834 65837 65835 65834 65833 66730 65835 65833 65838 65837 65834 66284 65838 65834 67166 66284 65834 65834 65835 67166 67526 67166 65835 67874 67526 65835 65835 67183 67874 65835 66730 67183 65836 66282 66283 65837 65838 65839 66732 65842 65840 65840 65841 66732 65841 66281 66732 66733 66293 65842 65842 66732 66733 66303 65847 65843 65843 65848 66303 65847 65844 65843 65844 65847 66725 66324 66323 65845 67186 66324 65845 65845 65846 67186 67543 67186 65846 65846 67179 67543 65846 66733 67179 65846 66293 66733 66734 66725 65847 66744 66734 65847 67180 66744 65847 65847 66303 67180 65848 66302 66303 66306 66305 65849 66325 66306 65849 65850 65851 66329 65852 65851 65850 67193 66329 65851 65851 65852 67193 65852 66324 67193 65852 66323 66324 67919 67209 65853 65853 67918 67919 65853 67557 67918 65853 65854 67557 65855 65854 65853 67209 65855 65853 65854 67201 67557 65854 66763 67201 66767 66763 65854 65854 65855 66767 65855 66342 66767 65855 66341 66342 67212 66341 65855 65855 67209 67212 66337 66336 65856 65856 65857 66337 66762 66337 65857 65857 66329 66762 66767 66343 65861 65861 66763 66767 65861 66336 66763 65862 65867 65870 66343 65865 65863 66344 65867 65864 65864 65866 66344 65864 65865 65866 66341 65866 65865 66342 66341 65865 66343 66342 65865 66771 66344 65866 65866 66769 66771 65866 66341 66769 66347 65870 65867 65867 66344 66347 66772 65871 65870 65870 66347 66772 66775 66346 65871 65871 66772 66775 66349 65873 65872 65872 66348 66349 65873 66349 66352 65874 65891 65898 67225 66778 65875 65875 66353 67225 65875 65883 66353 65875 65876 65883 65877 65876 65875 66778 65877 65875 67205 66760 65877 65877 66778 67205 66355 65885 65878 65878 65879 66355 65879 66351 66355 65879 65880 66351 65880 65881 66351 65882 65889 66361 65883 65893 66353 66354 66353 65884 65884 66350 66354 65884 65885 66350 66355 66350 65885 67250 66367 65886 65886 65887 67250 65888 65887 65886 68343 65888 65886 65886 68334 68343 65886 67236 68334 65886 66367 67236 67963 67250 65887 65887 67252 67963 65887 67251 67252 65887 65888 67251 68341 67251 65888 68342 68341 65888 68673 68342 65888 65888 68672 68673 65888 68343 68672 66784 66360 65889 65889 65890 66784 65889 66360 66361 67229 66784 65890 65890 65900 67229 66777 66361 65891 65891 65892 66777 65918 65898 65891 66360 65918 65891 66361 66360 65891 65896 65895 65894 66789 65896 65894 67232 66789 65894 67235 67232 65894 65894 67234 67235 65894 65897 67234 65895 65896 66359 66788 66359 65896 67231 66788 65896 65896 66789 67231 65897 66793 67234 65900 66368 67229 65900 65924 66368 65900 65923 65924 66376 65923 65900 65900 65905 66376 66384 65910 65901 65901 65902 66384 65903 65902 65901 66359 65903 65901 67247 66384 65902 67596 67247 65902 65902 67595 67596 65902 65903 67595 65903 67586 67595 65903 66788 67586 65903 66359 66788 65905 65906 66376 66369 65909 65907 66370 66369 65907 66377 66370 65907 65907 65908 66377 65908 65919 66377 65909 66369 66371 65910 65915 65916 66384 65915 65910 65931 65930 65912 65932 65931 65912 66379 65932 65912 65913 65928 65929 65913 65920 65928 65921 65920 65913 65913 65914 65921 65915 65914 65913 65916 65915 65913 66808 65921 65914 65914 65915 66808 66809 66808 65915 65915 66384 66809 65917 67590 67604 65917 65918 67590 67608 66797 65917 65917 67604 67608 65918 67233 67590 65918 66784 67233 66785 66784 65918 65918 66360 66785 66795 66377 65919 65919 66794 66795 65919 66383 66794 65937 65928 65920 65920 65921 65937 66812 65937 65921 65921 66808 66812 67598 67592 65922 65922 65925 67598 65922 65923 65925 65924 65923 65922 67592 65924 65922 66376 65925 65923 67591 66368 65924 67592 67591 65924 66391 65934 65925 65925 65935 66391 65936 65935 65925 66376 65936 65925 65925 65933 67598 65934 65933 65925 66819 65943 65926 66825 66819 65926 65926 66403 66825 65926 66396 66403 65927 65944 65945 65927 65928 65944 65929 65928 65927 65938 65929 65927 66394 65938 65927 65927 65945 66394 65928 65937 65944 66388 66385 65929 66389 66388 65929 65929 65938 66389 65930 65940 65941 65930 65939 65940 65930 65931 65939 67254 65939 65931 65931 65932 67254 65932 66379 66385 65932 66804 67254 65932 66803 66804 65932 66802 66803 65932 66385 66802 67953 67598 65933 65933 65934 67953 65934 66822 67255 65934 66391 66822 65945 65944 65937 65950 65945 65937 66405 65950 65937 66812 66405 65937 66394 66389 65938 66821 65940 65939 65939 66816 66821 65939 66815 66816 67614 66815 65939 65939 67254 67614 66821 65946 65940 66807 66383 65943 66819 66807 65943 65945 65951 66394 65952 65951 65945 65945 65950 65952 66820 65954 65946 66821 66820 65946 65950 65949 65947 65952 65950 65947 65947 65951 65952 66395 65951 65947 65947 65948 66395 65949 65948 65947 66417 66395 65948 65948 65949 66417 65949 65950 66397 65949 66416 66417 65949 66397 66416 66413 66397 65950 66837 66413 65950 65950 66406 66837 65950 66405 66406 65951 66393 66394 66407 66393 65951 65951 66395 66407 66850 66398 65953 65953 66839 66850 65953 66820 66839 65953 65954 66820 65956 66398 66408 66854 66412 65957 65957 66426 66854 65957 65958 66426 66864 66426 65958 65958 65965 66864 65964 65960 65959 65959 65962 65964 66423 65962 65961 65961 66422 66423 66425 66422 65961 65961 66424 66425 65962 66423 66429 66435 65964 65962 65962 66429 66435 66437 65984 65963 65965 65966 66864 66865 66864 65966 67291 66865 65966 65966 66870 67291 65966 66436 66870 66458 65977 65968 66882 66458 65968 65969 65970 66460 66460 65986 65969 65970 66453 66459 65970 65978 66453 65970 66459 66460 66442 65979 65971 66443 66442 65971 66462 66443 65971 65971 65983 66462 66876 66874 65972 65972 65974 66876 65975 65974 65973 66446 65975 65973 66880 66446 65973 65973 66434 66880 65973 66433 66434 65973 65976 66433 66877 66875 65974 65974 65975 66877 65974 66875 66876 67677 66877 65975 65975 66446 67677 65978 66442 66453 65978 65979 66442 65980 66447 66887 65980 65981 66447 66870 66436 65980 67291 66870 65980 65980 66887 67291 66455 66447 65981 66462 65983 65982 65982 66461 66462 65982 65987 66461 65984 66437 66454 66001 65999 65986 66466 66001 65986 65986 66460 66466 65988 65989 66477 66476 65992 65990 65990 66475 66476 65990 65991 66475 65991 66473 66475 66474 66473 65991 65994 65993 65992 66476 65994 65992 66476 65995 65994 65995 66895 66904 65995 66471 66895 66476 66471 65995 66884 66451 65996 67302 66884 65996 67303 67302 65996 65996 65997 67303 65998 65997 65996 66451 65998 65996 65997 66907 67303 65997 66906 66907 65997 66905 66906 65997 66015 66905 65997 65998 66015 65999 66010 66011 65999 66000 66010 66001 66000 65999 67322 66010 66000 66000 67319 67322 66000 66001 67319 66001 67316 67319 66001 66467 67316 66001 66466 66467 66479 66003 66002 66899 66005 66003 66900 66899 66003 66003 66898 66900 66003 66479 66898 66007 66006 66004 66009 66007 66004 66004 66005 66009 66899 66009 66005 66006 66007 66014 66007 66013 66014 66007 66008 66013 66009 66008 66007 66015 66013 66008 66905 66015 66008 66906 66905 66008 67331 66906 66008 66008 66901 67331 66008 66009 66901 67330 66901 66009 66009 66899 67330 66483 66011 66010 66909 66483 66010 67321 66909 66010 67322 67321 66010 66482 66017 66011 66483 66482 66011 66494 66492 66012 66499 66494 66012 66896 66499 66012 66904 66896 66012 66012 66026 66904 66015 66014 66013 67325 66481 66016 67695 67325 66016 66016 66495 67695 66917 66487 66017 66017 66913 66917 66017 66482 66913 66919 66489 66019 66019 66486 66919 66025 66023 66020 66925 66025 66020 66929 66925 66020 66020 66022 66929 66020 66021 66022 66039 66022 66021 66022 66031 66929 66039 66031 66022 66025 66024 66023 66024 66480 66484 66024 66470 66480 66490 66470 66024 66024 66025 66490 66493 66491 66025 66925 66493 66025 66491 66490 66025 67338 66028 66027 66027 66028 66029 67339 66030 66028 66028 67338 67339 66030 66029 66028 66029 66030 66032 66922 66921 66030 67339 66922 66030 67349 66032 66030 66030 66921 67349 66031 66505 66929 66031 66032 66505 67347 66505 66032 67349 67347 66032 66511 66042 66033 66033 66506 66511 66033 66034 66506 66034 66035 66506 66035 66498 66506 66500 66497 66036 66507 66500 66036 66036 66040 66507 66503 66502 66037 66504 66503 66037 66509 66504 66038 66038 66508 66509 66926 66507 66040 67353 66926 66040 66040 66041 67353 66041 66501 67353 66513 66046 66042 66042 66511 66513 66043 66044 66050 66518 66050 66044 66044 66045 66518 66519 66518 66045 66045 66046 66519 66046 66513 66519 66522 66517 66047 66047 66521 66522 66533 66056 66048 66048 66532 66533 66943 66532 66048 66048 66049 66943 66050 66518 66939 66939 66051 66050 66944 66057 66051 66051 66939 66944 66529 66055 66052 66052 66053 66529 66054 66053 66052 66950 66529 66053 66053 66949 66950 66053 66061 66949 66935 66530 66055 66940 66935 66055 66055 66529 66940 66937 66527 66056 66056 66533 66937 66056 66527 66528 66962 66961 66057 67378 66962 66057 66057 66944 67378 66058 66064 66065 66537 66064 66058 66075 66069 66059 66059 66074 66075 66538 66074 66059 66059 66531 66538 66059 66060 66531 66060 66526 66531 66061 66539 66949 66535 66063 66062 66062 66534 66535 66535 66070 66063 66536 66065 66064 66064 66066 66536 66067 66066 66064 66965 66067 66064 66064 66537 66965 66096 66079 66065 66957 66096 66065 66959 66957 66065 66065 66536 66959 67377 66536 66066 66066 66969 67377 66066 66067 66969 66067 66965 66969 66541 66540 66068 66542 66541 66068 66968 66082 66070 66070 66535 66968 66981 66534 66071 66072 66970 67395 66972 66970 66072 66974 66972 66072 66072 66973 66974 66072 66073 66973 66074 66073 66072 67395 66074 66072 66073 66538 66973 66073 66074 66538 66984 66075 66074 67395 66984 66074 66984 66542 66075 66076 66077 66084 66078 66077 66076 66079 66078 66076 66546 66084 66077 66077 66078 66546 66078 66096 66546 66078 66079 66096 66090 66089 66080 66547 66090 66080 66080 66086 66547 66549 66094 66081 66081 66082 66549 66989 66549 66082 66082 66976 66989 66082 66968 66976 66991 66979 66083 67751 66991 66083 66083 66995 67751 66099 66086 66085 66099 66088 66086 66086 66087 66547 66088 66087 66086 66087 66092 66547 66550 66092 66087 66562 66550 66087 66087 66107 66562 66087 66088 66107 66099 66098 66088 66088 66100 66107 66088 66098 66100 66089 66090 66092 66092 66091 66089 66547 66092 66090 66091 66092 66104 66550 66104 66092 66543 66539 66093 66545 66543 66093 66986 66545 66093 66093 66548 66986 67393 66097 66096 66096 67383 67393 66096 66957 67383 66997 66558 66097 68131 66997 66097 66097 67752 68131 66097 67405 67752 66097 67393 67405 66101 66100 66098 66108 66107 66100 66100 66101 66108 66101 66105 66108 66559 66553 66102 66564 66559 66102 66998 66573 66103 66103 66571 66998 66104 66550 66556 66574 66108 66105 66105 66572 66574 66105 66106 66572 66573 66572 66106 66994 66562 66107 66107 66557 66994 66569 66557 66107 66107 66108 66569 67003 66569 66108 66108 66574 67003 66109 66556 66557 66557 66110 66109 66575 66115 66110 66110 66557 66575 66114 66113 66111 66118 66114 66111 67006 66999 66112 67007 67006 66112 66112 67000 67007 66112 66570 67000 66113 66114 67004 67000 66570 66113 67004 67000 66113 66114 66118 67004 66115 66579 66580 66115 66575 66579 66583 66122 66116 66587 66584 66117 66588 66587 66117 66121 66120 66119 67022 66592 66120 67024 67022 66120 66120 66121 67024 67025 67024 66121 67026 67025 66121 66121 66123 67026 66122 66583 66590 66123 66596 67026 67011 66596 66124 66124 66598 67011 66124 66125 66598 66125 66597 66598 66125 66126 66597 67017 66595 66127 67031 67017 66127 66601 66132 66131 66601 66133 66132 66135 66134 66133 66601 66135 66133 67033 66138 66134 66134 66605 67033 66134 66602 66605 66134 66135 66602 66603 66602 66135 67034 66139 66136 66136 66137 67034 67035 67034 66137 66137 66138 67035 67428 67035 66138 66138 67033 67428 66607 66140 66139 67034 66607 66139 66140 66606 66608 66607 66606 66140 66615 66609 66141 66141 66608 66615 66612 66143 66142 66142 66610 66612 66611 66610 66142 66142 66609 66611 66146 66144 66143 66612 66146 66143 66151 66150 66145 66147 66148 66604 66624 66623 66148 66148 66149 66624 66623 66604 66148 66149 66154 66624 66150 67042 67045 66150 66151 67042 67045 66153 66150 66152 66613 66617 66615 66613 66152 66622 66615 66152 66153 67045 67048 66629 66624 66154 66154 66162 66629 66155 66634 67055 66156 66159 66627 67046 66630 66157 66157 66158 67046 67047 67046 66158 67434 67047 66158 66158 67043 67434 66159 67049 67056 66159 66163 67049 67056 66627 66159 67058 67057 66160 66160 66632 67058 67050 67049 66163 66163 66637 67050 66163 66165 66637 66164 66631 66633 66164 66630 66631 66642 66637 66165 66165 66167 66642 66166 66640 67063 66166 66179 66180 67063 66179 66166 66174 66173 66168 66639 66174 66168 66168 66638 66639 66169 66651 66652 66652 66647 66169 66170 66177 66643 66170 66175 66177 66183 66172 66171 66172 66183 66184 66646 66645 66173 66173 66174 66646 67064 66646 66174 66174 66639 67064 66178 66177 66175 66175 66176 66178 66181 66178 66176 66188 66181 66176 66177 66178 66644 67068 66643 66177 66177 66644 67068 66178 66181 66648 66648 66644 66178 66650 66182 66179 67082 66650 66179 66179 67073 67082 66179 67063 67073 66181 66188 66648 66650 66189 66182 66645 66190 66185 66649 66187 66186 66186 66198 66649 66186 66191 66198 66649 66188 66187 66649 66648 66188 66190 66645 67081 66191 66197 66198 66655 66197 66191 66654 66206 66194 66195 66197 66655 67096 66197 66195 66195 66196 67096 67100 67096 66196 66196 66660 67100 66196 66659 66660 66196 66656 66659 66658 66198 66197 67479 66658 66197 66197 67096 67479 67465 67085 66198 66198 67083 67465 67084 67083 66198 67475 67084 66198 66198 66658 67475 67085 66649 66198 67090 66657 66199 67091 67090 66199 66199 66650 67091 66201 66202 66207 66674 66205 66204 66204 66662 66674 66673 66663 66205 66674 66673 66205 66659 66656 66206 67099 66659 66206 66208 66669 67097 66208 66667 66669 66210 66663 66673 66673 66219 66210 66212 66213 67105 66214 66213 66212 66221 66214 66212 66212 66220 66221 67113 66220 66212 66212 67105 67113 66213 67104 67105 66213 66671 67104 66213 66214 66671 66214 66217 66671 66221 66217 66214 66215 66676 67112 66215 66216 66676 66217 66216 66215 66675 66217 66215 67107 66675 66215 67110 67107 66215 67112 67110 66215 66216 66218 66222 66216 66217 66218 66682 66676 66216 66216 66222 66682 67107 66671 66217 66217 66675 67107 66223 66218 66217 66217 66221 66223 66223 66222 66218 66683 66226 66219 66684 66683 66219 66219 66673 66684 67121 66232 66220 66220 67114 67121 66220 67113 67114 66232 66221 66220 66221 66222 66223 66228 66222 66221 66229 66228 66221 66232 66229 66221 66222 66228 66682 66679 66230 66224 66224 66678 66679 66224 66672 66678 66224 66225 66672 67102 66672 66225 66225 67101 67102 66691 66227 66226 66226 66683 66691 66227 66254 66255 66691 66254 66227 66689 66682 66228 66228 66233 66689 66228 66229 66233 66234 66233 66229 66235 66234 66229 66229 66232 66235 67121 66235 66232 66233 66686 66689 66233 66238 66686 66233 66236 66238 66233 66234 66236 66237 66236 66234 66234 66235 66237 66688 66237 66235 67121 66688 66235 66239 66238 66236 66243 66239 66236 66236 66242 66243 66236 66237 66242 66246 66242 66237 66697 66246 66237 66237 66688 66697 67130 66686 66238 66238 66698 67130 66238 66239 66698 66700 66698 66239 66239 66244 66700 66239 66243 66244 66240 66699 66701 66240 66252 66699 66244 66243 66242 66242 66246 66247 66245 66266 67137 66245 66257 66266 66245 66256 66257 66258 66247 66246 66697 66258 66246 66258 66248 66247 66248 66258 66261 67142 66260 66249 67505 67142 66249 66249 67135 67505 66249 66250 67135 66260 66251 66249 67136 67135 66250 66250 66679 67136 66260 66259 66251 66252 66253 66699 67129 66699 66253 66253 66691 67129 66692 66691 66253 66253 66690 66692 66691 66690 66254 66267 66266 66257 67143 66261 66258 67507 67143 66258 66258 67503 67507 67504 67503 66258 66258 66702 67504 66258 66697 66702 66710 66709 66259 67142 66710 66259 66259 66260 67142 67143 66268 66261 66262 66705 66707 66265 66264 66263 66706 66265 66263 67155 66706 66263 66263 66711 67155 66263 66707 66711 66263 66264 66707 66264 66265 66277 67510 66277 66265 66265 66706 67510 67139 67137 66266 67148 67139 66266 66266 66267 67148 66267 66274 67148 67151 66281 66268 66268 67143 67151 67160 66708 66269 66269 66712 67160 66710 66705 66271 66271 66709 66710 67144 66274 66273 67150 67148 66274 66274 67146 67150 66274 67144 67146 66714 66278 66276 66276 66277 66714 66715 66714 66277 67510 66715 66277 66283 66282 66278 66714 66283 66278 66279 66284 66716 67156 67145 66280 67163 67156 66280 66280 66717 67163 67164 66732 66281 66281 67159 67164 66281 67151 67159 66283 66723 66728 66283 66714 66723 67162 66716 66284 67527 67162 66284 67528 67527 66284 66284 67526 67528 66284 67166 67526 66285 66286 66309 66295 66287 66285 66309 66295 66285 66289 66288 66287 66294 66289 66287 66295 66294 66287 66288 66289 66296 66288 66291 66292 66296 66291 66288 66289 66294 66296 66292 66291 66290 67174 66292 66290 67175 67174 66290 67178 67175 66290 66290 66301 67178 66290 66291 66301 66291 66296 66301 67168 66717 66292 67174 67168 66292 66298 66296 66294 66319 66298 66294 66294 66311 66319 66294 66295 66311 66295 66309 66311 66296 66297 66301 66298 66297 66296 66297 66299 66301 66300 66299 66297 66312 66300 66297 66297 66298 66312 66755 66312 66298 66298 66320 66755 66298 66319 66320 66740 66301 66299 66299 66313 66740 66299 66300 66313 66315 66313 66300 66300 66312 66315 66301 66741 67178 66301 66740 66741 66304 66303 66302 66749 66304 66302 66302 66316 66749 66303 66304 67180 67538 67180 66304 66304 66749 67538 66750 66748 66305 66305 66306 66750 66748 66316 66305 66306 66736 66750 66738 66736 66306 66306 66325 66738 66751 66310 66307 66760 66751 66307 66309 66310 66311 66751 66311 66310 66321 66319 66311 66752 66321 66311 66311 66751 66752 66322 66315 66312 66754 66322 66312 66755 66754 66312 66313 66739 66740 67184 66739 66313 66313 66757 67184 66313 66314 66757 66315 66314 66313 66314 66322 66757 66314 66315 66322 66316 66747 66749 66748 66747 66316 66334 66332 66317 67187 66334 66317 66317 66318 67187 67544 67187 66318 66318 66731 67544 66321 66320 66319 67194 66755 66320 66320 66753 67194 66320 66321 66753 66321 66752 66753 66322 66756 66757 67198 66756 66322 66322 66754 67198 67545 67193 66324 66324 67186 67545 66325 66327 66738 66738 66327 66326 66759 66738 66326 66328 66332 66335 67199 66762 66329 66329 67193 67199 66759 66338 66330 67173 66759 66330 67547 67173 66330 66330 66331 67547 67556 67547 66331 66331 66765 67556 66766 66765 66331 66332 66333 66335 66334 66333 66332 66339 66335 66333 66340 66339 66333 67208 66340 66333 66333 66334 67208 67211 67208 66334 67548 67211 66334 66334 67187 67548 66764 66763 66336 66336 66337 66764 67200 66764 66337 66337 66762 67200 66339 66340 66768 67208 66768 66340 67212 66769 66341 66342 66343 66767 66771 66347 66344 67207 66766 66345 66345 66346 67207 67564 67207 66346 66346 67215 67564 66346 66775 67215 66773 66772 66347 67214 66773 66347 66347 66771 67214 66776 66349 66348 66348 66774 66776 66780 66352 66349 66349 66776 66780 66782 66354 66350 66350 66779 66782 66350 66355 66779 66779 66355 66351 66351 66373 66779 66358 66356 66352 66780 66358 66352 67577 67225 66353 66353 66781 67577 66353 66354 66781 67571 66781 66354 66354 66782 67571 66358 66357 66356 66783 66366 66357 66357 66358 66783 66358 66780 66783 66360 66784 66785 66362 66372 66373 67240 66793 66363 66363 66374 67240 66375 66374 66363 66799 66375 66365 67236 66367 66366 67237 67236 66366 67584 67237 66366 66366 66783 67584 67250 66811 66367 66806 66381 66367 66811 66806 66367 67589 67229 66368 67591 67589 66368 67238 66371 66369 66369 66796 67238 66369 66370 66796 66370 66377 66796 66790 66372 66371 67238 66790 66371 66790 66373 66372 66787 66779 66373 66791 66787 66373 66373 66790 66791 67588 67240 66374 67602 67588 66374 66374 66798 67602 66374 66375 66798 66799 66798 66375 66377 66795 66796 66385 66379 66378 67246 66387 66380 66380 66805 67246 66806 66805 66380 66380 66381 66806 66824 66401 66382 66382 66797 66824 67242 66794 66383 66383 66807 67242 67247 66809 66384 67243 66802 66385 66385 66814 67243 66385 66388 66814 66801 66800 66386 67245 66801 66386 66386 66810 67245 67246 66810 66386 66386 66387 67246 66388 66389 66814 67243 66814 66389 67642 67243 66389 66389 66826 67642 66389 66392 66826 66394 66392 66389 66390 66410 66818 66390 66399 66410 67639 66826 66392 66392 66393 67639 66394 66393 66392 67640 67639 66393 66393 66856 67640 66393 66407 66856 66418 66407 66395 66395 66417 66418 66396 66402 66403 66397 66413 66416 66850 66408 66398 66399 66409 66410 66422 66420 66400 66841 66422 66400 66400 66401 66841 67275 66841 66401 66401 66824 67275 66404 66403 66402 66412 66404 66402 66827 66825 66403 66828 66827 66403 66403 66411 66828 66403 66404 66411 66412 66411 66404 66838 66406 66405 66405 66812 66838 66406 66835 66837 67262 66835 66406 66406 66838 67262 66407 66418 66856 66408 66850 66851 66857 66409 66408 66408 66851 66857 66858 66410 66409 66409 66857 66858 66840 66818 66410 66858 66840 66410 66829 66828 66411 67267 66829 66411 67277 67267 66411 66411 67276 67277 66411 66852 67276 66411 66412 66852 66854 66852 66412 66413 66414 66416 66415 66414 66413 66836 66415 66413 66837 66836 66413 67283 66860 66414 66414 66415 67283 66860 66416 66414 66855 66844 66415 66415 66836 66855 67286 67283 66415 66415 66844 67286 66421 66417 66416 66416 66418 66421 66861 66418 66416 66416 66859 66861 66860 66859 66416 66421 66418 66417 66861 66856 66418 66419 66422 66425 66419 66420 66422 66430 66423 66422 66862 66430 66422 66863 66862 66422 66422 66841 66863 66423 66427 66429 66428 66427 66423 66430 66428 66423 67290 67287 66426 66426 66865 67290 66426 66864 66865 67287 66854 66426 66427 66428 67292 67292 66429 66427 66428 66862 68008 66428 66430 66862 68008 67292 66428 66441 66435 66429 68017 66441 66429 66429 67292 68017 66431 66432 66438 66438 66437 66431 66435 66434 66433 66434 66879 66880 66434 66439 66879 66434 66435 66439 66440 66439 66435 66441 66440 66435 66464 66454 66437 66867 66464 66437 66868 66867 66437 66437 66444 66868 66437 66438 66444 67299 66879 66439 66439 66869 67299 66439 66440 66869 66440 66441 66869 68017 66869 66441 66871 66453 66442 66872 66871 66442 66442 66443 66872 66873 66872 66443 66885 66873 66443 66443 66462 66885 66444 66866 66868 67667 67294 66445 66445 66878 67667 66445 66874 66878 66446 67309 67677 66446 66886 67309 66446 66880 66886 66447 66455 66887 66448 66449 66883 66450 66449 66448 66883 66450 66448 66449 66458 66882 66465 66458 66449 67314 66465 66449 66449 66450 67314 66449 66882 66883 67682 67314 66450 68029 67682 66450 66450 68027 68029 66450 67668 68027 66450 66883 67668 66884 66452 66451 66884 66882 66452 67297 66888 66453 67661 67297 66453 67665 67661 66453 66453 67298 67665 66453 66871 67298 66888 66459 66453 66454 66463 66468 66464 66463 66454 66891 66887 66455 66455 66456 66891 66457 66456 66455 67313 66891 66456 66456 66465 67313 66456 66458 66465 66456 66457 66458 66467 66460 66459 66888 66467 66459 66467 66466 66460 66892 66462 66461 66892 66885 66462 66894 66468 66463 67318 66894 66463 66463 66893 67318 66463 66464 66893 67315 66893 66464 66464 66890 67315 66464 66889 66890 66464 66867 66889 67680 67313 66465 67681 67680 66465 66465 67314 67681 67317 67316 66467 66467 66888 67317 66902 66474 66469 66469 66490 66902 66469 66470 66490 66470 66478 66480 66476 66475 66471 66897 66895 66471 67323 66897 66471 66471 66916 67323 66471 66472 66916 66473 66472 66471 66475 66473 66471 66472 66903 66916 66472 66474 66903 66472 66473 66474 66474 66902 66903 66480 66478 66477 66484 66480 66477 66479 66481 66898 67324 66898 66481 67325 67324 66481 66482 66485 66913 66482 66483 66485 66909 66485 66483 66485 66912 66913 66485 66909 66912 66920 66919 66486 66486 66918 66920 66486 66487 66918 66487 66917 66918 67706 67338 66488 66488 67705 67706 66488 66489 67705 66489 67346 67705 66489 66919 67346 66910 66902 66490 66914 66910 66490 66490 66491 66914 66491 66493 66914 67341 66914 66493 66493 66925 67341 66495 67342 67695 66495 66496 67342 67343 67342 66496 67352 67343 66496 66496 66926 67352 66496 66497 66926 66497 66500 66926 66930 66506 66498 66498 66499 66930 67351 66930 66499 66499 66896 67351 66500 66507 66926 66501 66927 67353 66501 66502 66927 66502 66503 66927 66503 66504 66927 66928 66927 66504 66504 66509 66928 67347 66929 66505 66514 66511 66506 66934 66514 66506 66506 66930 66934 66510 66509 66508 66512 66510 66508 67355 66928 66509 66509 66933 67355 66509 66510 66933 66510 66524 66933 66510 66512 66524 66514 66513 66511 66512 66517 66524 66520 66519 66513 66513 66514 66520 66514 66515 66520 66516 66515 66514 66934 66516 66514 66515 66516 67726 67367 66520 66515 66515 66947 67367 68084 66947 66515 66515 67726 68084 66516 66934 67726 66517 66523 66524 66517 66522 66523 66963 66939 66518 66518 66945 66963 66948 66945 66518 66518 66938 66948 66518 66519 66938 66519 66520 66938 67367 66938 66520 66935 66522 66521 66521 66530 66935 67357 66523 66522 66522 66935 67357 66525 66524 66523 66936 66525 66523 67357 66936 66523 66524 66525 66933 67354 66933 66525 67360 67354 66525 66525 66936 67360 66937 66531 66526 66526 66527 66937 67368 66940 66529 67369 67368 66529 66529 66950 67369 66941 66538 66531 66942 66941 66531 66531 66532 66942 66533 66532 66531 66937 66533 66531 66943 66942 66532 66952 66535 66534 66955 66952 66534 66981 66955 66534 66535 66953 66968 66535 66952 66953 66536 66958 66959 67377 66958 66536 66537 66540 66966 66966 66965 66537 66538 66941 66973 66539 66543 66949 66540 66541 66966 66541 66542 66985 66985 66966 66541 66542 66984 66985 66543 66544 66949 66545 66544 66543 66950 66949 66544 66967 66950 66544 66544 66545 66967 66986 66967 66545 66548 66551 66986 66989 66552 66549 66550 66555 66556 66562 66555 66550 66987 66986 66551 66988 66987 66551 66552 66990 67403 66552 66989 66990 66992 66554 66553 66553 66560 66992 66553 66559 66560 66565 66561 66554 66992 66565 66554 66557 66556 66555 66994 66557 66555 66555 66562 66994 66557 66569 66575 66997 66564 66558 67408 66560 66559 66559 67407 67408 66559 66996 67407 66997 66996 66559 66559 66564 66997 66993 66992 66560 67763 66993 66560 66560 67408 67763 66561 66565 67409 67409 66571 66561 68140 67767 66565 66565 67765 68140 66565 66993 67765 66565 66992 66993 67767 67409 66565 67412 66568 66567 66567 67006 67412 66567 66999 67006 67412 67001 66568 67406 66995 66568 66568 67002 67406 66568 67001 67002 67003 66575 66569 67410 66998 66571 66571 67409 67410 66572 66576 66577 66572 66573 66576 67008 66574 66572 67009 67008 66572 66572 66577 67009 66998 66576 66573 67008 67003 66574 66581 66579 66575 67003 66581 66575 66998 66577 66576 67010 67009 66577 67012 67010 66577 66577 66998 67012 66581 66580 66579 66581 67003 67008 66585 66583 66582 66582 66584 66585 66591 66590 66583 66583 66585 66591 66586 66585 66584 67416 66586 66584 67779 67416 66584 66584 66588 67779 66584 66587 66588 67014 66591 66585 66585 66586 67014 67415 67014 66586 67416 67415 66586 66588 67423 67779 66588 67417 67423 66588 67015 67417 66589 66593 66594 66595 66593 66589 66600 66599 66590 66590 66591 66600 67027 66600 66591 66591 67018 67027 67019 67018 66591 67415 67019 66591 66591 67014 67415 67022 67020 66592 67016 66594 66593 67414 67016 66593 66593 67017 67414 66593 66595 67017 67005 67004 66594 67016 67005 66594 67418 67026 66596 66596 67011 67418 67012 67011 66598 66598 67010 67012 66600 67027 67032 66602 66603 66605 66604 66620 66621 66604 66619 66620 66623 66619 66604 67038 67033 66605 66605 66621 67038 66613 66608 66606 66618 66613 66606 66606 66607 66618 67036 66618 66607 66607 67034 67036 66608 66613 66615 66615 66611 66609 67041 66612 66610 67044 67041 66610 66610 66616 67044 66610 66611 66616 66611 66615 66616 66618 66614 66613 66614 67039 67043 67040 67039 66614 66614 67036 67040 66614 66618 67036 66622 66616 66615 66616 66625 67044 66628 66625 66616 66616 66622 66628 66624 66620 66619 66619 66623 66624 67431 66621 66620 67438 67431 66620 66620 66629 67438 66620 66624 66629 66621 67431 67432 67432 67038 66621 67433 67044 66625 66625 66626 67433 66627 66626 66625 66628 66627 66625 67437 67433 66626 66626 67056 67437 66626 66627 67056 67439 67438 66629 66629 67053 67439 66636 66631 66630 67796 66636 66630 66630 67046 67796 67062 66633 66631 67448 67062 66631 66631 66636 67448 66632 67051 67058 66632 67048 67051 67062 66638 66633 66634 66635 67055 67799 67798 66635 67449 67448 66636 67796 67449 66636 66637 66642 67060 67059 67050 66637 67060 67059 66637 67062 66639 66638 66639 67062 67064 66641 67468 68174 66641 67466 67468 67467 67466 66641 67470 67467 66641 66641 66647 67470 66642 66643 67060 67454 67060 66643 66643 67068 67454 67077 67068 66644 67079 67077 66644 66644 66648 67079 66645 66646 67081 67461 67081 66646 66646 67456 67461 66646 67066 67456 66646 67064 67066 67471 67470 66647 66647 66652 67471 67463 67079 66648 67464 67463 66648 67465 67464 66648 66648 67085 67465 66648 66649 67085 67462 67091 66650 66650 67082 67462 67472 67471 66652 66652 67086 67472 67089 67086 66653 66657 67090 67093 67477 67475 66658 67479 67477 66658 67099 66660 66659 67482 67100 66660 66660 67098 67482 67099 67098 66660 66680 66674 66662 67103 66677 66664 67493 67103 66664 66664 66665 67493 66665 67120 67493 66665 66681 67120 66668 66667 66666 66677 66668 66666 66670 66669 66667 66667 66668 66670 67823 66670 66668 66668 67490 67823 66668 67103 67490 66668 66677 67103 67481 67097 66669 67824 67481 66669 66669 66670 67824 66670 67823 67824 67106 67104 66671 67107 67106 66671 67119 66678 66672 66672 67102 67119 66673 66674 66684 66674 66680 66684 66676 66682 67112 67118 66679 66678 67119 67118 66678 66679 67127 67136 66679 67118 67127 66681 66685 67120 67494 67112 66682 66682 67117 67494 66682 66689 67117 67129 66691 66683 66683 67125 67129 66683 67124 67125 66683 66684 67124 66684 67123 67124 66685 66693 67120 66685 66687 66693 67122 66689 66686 67497 67122 66686 66686 67130 67497 66696 66693 66687 67845 66697 66688 67846 67845 66688 66688 67844 67846 66688 67121 67844 67122 67117 66689 66690 66691 66692 66693 66694 67120 66695 66694 66693 67132 66695 66693 67134 67132 66693 66693 66696 67134 67493 67120 66694 67830 67493 66694 67847 67830 66694 66694 67126 67847 66694 66695 67126 67848 67126 66695 66695 67133 67848 66695 67132 67133 67859 66702 66697 66697 67845 67859 67501 67130 66698 66698 66703 67501 66698 66700 66703 67129 66701 66699 67859 67504 66702 66703 67509 67853 66703 66704 67509 67852 67501 66703 67853 67852 66703 66704 67508 67509 66704 66708 67508 66711 66707 66705 66705 66710 66711 67511 67510 66706 67514 67511 66706 66706 67155 67514 66708 67160 67508 67513 66711 66710 66710 67140 67513 67142 67140 66710 66711 67154 67155 67513 67154 66711 67165 67160 66712 66712 66718 67165 66712 66713 66718 66719 66718 66713 66714 66722 66723 67161 66722 66714 66714 66715 67161 67523 67161 66715 66715 67516 67523 66715 67510 67516 67168 67163 66717 67177 67165 66718 66718 66735 67177 66718 66719 66735 66719 66725 66735 66728 66723 66720 66720 66726 66728 66720 66721 66726 66722 66721 66720 66723 66722 66720 66727 66726 66721 66721 66722 66727 67161 66727 66722 66724 67167 67530 66725 66734 66735 66729 66728 66726 66745 66729 66726 66726 66727 66745 67172 66745 66727 67520 67172 66727 66727 67161 67520 66728 66729 66730 66729 66736 66737 66745 66736 66729 66737 66730 66729 66730 66737 67183 66731 67540 67544 66731 67535 67540 67169 66733 66732 66732 67164 67169 66733 67169 67179 67176 66735 66734 66734 66742 67176 66744 66742 66734 66735 67176 67177 66736 67173 67185 66736 66738 67173 66736 66745 66750 67185 66737 66736 66737 67181 67183 67182 67181 66737 67185 67182 66737 66738 66759 67173 66741 66740 66739 67536 66741 66739 67541 67536 66739 66739 67184 67541 67884 67178 66741 66741 67536 67884 67529 67176 66742 67533 67529 66742 66742 66743 67533 66744 66743 66742 68252 67533 66743 68253 68252 66743 66743 67537 68253 66743 67180 67537 66743 66744 67180 67170 66750 66745 67171 67170 66745 67172 67171 66745 66747 67534 67538 66747 67170 67534 66747 66748 67170 67538 66749 66747 66748 66750 67170 66761 66752 66751 66751 66760 66761 67188 66753 66752 66752 66761 67188 67551 67194 66753 66753 67188 67551 66754 66755 67198 66755 67194 67198 66758 66757 66756 67189 66758 66756 67191 67189 66756 66756 67190 67191 67198 67190 66756 66757 66758 67184 67189 67184 66758 67205 66761 66760 67204 67188 66761 66761 67203 67204 67205 67203 66761 67202 67200 66762 67910 67202 66762 66762 67199 67910 66763 66764 67201 67206 67201 66764 67555 67206 66764 66764 67202 67555 66764 67200 67202 67561 67556 66765 66765 66766 67561 66766 67207 67561 67213 66770 66768 66768 67208 67213 67212 66771 66769 67213 66774 66770 66771 67212 67214 67221 66775 66772 66772 66773 67221 67568 67221 66773 66773 67567 67568 66773 67214 67567 67224 66776 66774 67569 67224 66774 67570 67569 66774 66774 67566 67570 66774 67565 67566 66774 67213 67565 67217 67215 66775 67221 67217 66775 67224 66780 66776 67228 67205 66778 66778 67225 67228 66786 66782 66779 66787 66786 66779 67584 66783 66780 66780 67576 67584 66780 67569 67576 66780 67224 67569 67931 67577 66781 66781 67571 67931 67572 67571 66782 66782 66786 67572 66784 67229 67233 66786 66787 67572 66787 67230 67572 66787 66791 67230 66788 67231 67586 67585 67231 66789 67587 67585 66789 66789 67581 67587 66789 67232 67581 66792 66791 66790 67239 66792 66790 66790 67238 67239 66791 66792 67230 67574 67230 66792 67949 67574 66792 66792 67239 67949 67240 67234 66793 67599 66795 66794 67955 67599 66794 66794 67242 67955 67947 66796 66795 66795 67600 67947 66795 67599 67600 67593 67238 66796 67952 67593 66796 66796 67947 67952 66797 66823 66824 67608 66823 66797 66798 67244 67602 66798 67241 67244 66798 66799 67241 66799 66801 67241 66799 66800 66801 67245 67241 66801 66804 66803 66802 67610 66804 66802 66802 67248 67610 66802 67243 67248 67614 67254 66804 67966 67614 66804 66804 67611 67966 66804 67610 67611 66805 66810 67246 66811 66810 66805 66805 66806 66811 66807 66819 67242 66813 66812 66808 66808 66809 66813 67247 66813 66809 67607 67245 66810 67963 67607 66810 66810 67250 67963 66810 66811 67250 67623 66838 66812 67624 67623 66812 66812 67613 67624 66812 66813 67613 66813 67609 67613 66813 67606 67609 66813 67247 67606 68348 67971 66815 66815 67966 68348 66815 67614 67966 66817 66816 66815 67971 66817 66815 67625 66821 66816 66816 66817 67625 67989 67625 66817 68362 67989 66817 66817 68356 68362 66817 67971 68356 66818 66840 67256 66819 66825 67242 66851 66839 66820 66820 66821 66851 67625 66851 66821 67626 67255 66822 67282 66824 66823 67615 67282 66823 67616 67615 66823 66823 67608 67616 67282 67275 66824 66825 66827 67264 67265 67242 66825 66825 67264 67265 66826 67641 67642 68377 67641 66826 68388 68377 66826 66826 67639 68388 66827 66828 66829 66827 66829 67264 67267 67264 66829 66843 66842 66830 66830 66831 66843 66832 66831 66830 66842 66832 66830 67258 66843 66831 67260 67258 66831 67261 67260 66831 67263 67261 66831 66831 66833 67263 66831 66832 66833 66849 66834 66832 66855 66849 66832 66832 66844 66855 66832 66842 66844 66834 66833 66832 66833 67262 67263 66833 66835 67262 66833 66834 66835 66836 66835 66834 66849 66836 66834 66835 66836 66837 66836 66849 66855 67271 67262 66838 67623 67271 66838 66851 66850 66839 67632 67274 66840 66840 67284 67632 66840 66858 67284 66841 66862 66863 67275 66862 66841 66845 66844 66842 67268 66845 66842 66842 66843 67268 66843 67258 67268 67638 67286 66844 66844 66845 67638 66845 67637 67638 66845 67268 67637 67638 67637 66846 66846 66847 67638 66848 66847 66846 67637 66848 66846 68007 67638 66847 68387 68007 66847 66847 66848 68387 66848 67636 68708 66848 67635 67636 66848 67278 67635 67637 67278 66848 68709 68387 66848 68711 68709 66848 66848 68708 68711 67273 66857 66851 67990 67273 66851 66851 67989 67990 66851 67625 67989 66852 66853 67276 66854 66853 66852 67285 67276 66853 67288 67285 66853 66853 67287 67288 66853 66854 67287 66856 66861 67640 67284 66858 66857 66857 67280 67284 66857 67272 67280 67273 67272 66857 66859 67650 67653 66859 66860 67650 67653 66861 66859 66860 67283 67286 67651 67650 66860 66860 67646 67651 66860 67286 67646 67653 67640 66861 66862 67275 68008 67296 67290 66865 66865 67295 67296 66865 67291 67295 67293 66868 66866 66867 66868 66889 67293 66889 66868 67300 67299 66869 68038 67300 66869 66869 68018 68038 66869 68017 68018 67666 67298 66871 66871 66872 67666 66872 66873 67666 68034 67666 66873 66873 67687 68034 66873 66885 67687 66874 66875 66878 66876 66875 66874 66875 66877 66878 67305 66878 66877 67678 67305 66877 66877 67677 67678 67670 67667 66878 66878 67304 67670 67305 67304 66878 66881 66880 66879 67299 66881 66879 66880 66881 66886 67671 66886 66881 66881 67300 67671 66881 67299 67300 67301 66883 66882 67302 67301 66882 66882 66884 67302 66883 67301 67668 66885 67307 67687 66885 67306 67307 66885 66892 67306 67671 67309 66886 67310 67291 66887 67311 67310 66887 66887 66891 67311 66888 67297 67664 67664 67317 66888 67293 66890 66889 67675 67315 66890 66890 67669 67675 66890 67294 67669 66890 67293 67294 67312 67311 66891 67313 67312 66891 67690 67306 66892 66893 67315 67318 66894 67320 67688 66894 67318 67320 66895 66896 66904 66897 66896 66895 66896 67332 67351 66896 66897 67332 67333 67332 66897 66897 67323 67333 67327 66900 66898 66898 67324 67327 66899 67329 67330 66899 66900 67329 66900 67327 67329 67696 67331 66901 66901 67330 67696 66910 66903 66902 66903 66910 66916 66908 66907 66906 67331 66908 66906 67673 67303 66907 66907 67672 67673 66907 66908 67672 68069 67672 66908 68077 68069 66908 66908 67699 68077 66908 67698 67699 66908 67331 67698 67321 66912 66909 66910 66915 66916 66910 66914 66915 66913 66912 66911 67334 66913 66911 67700 67334 66911 66911 66912 67700 66912 67321 67700 67335 66917 66913 67344 67335 66913 66913 67334 67344 67341 66915 66914 66915 66923 67701 66924 66923 66915 67341 66924 66915 67701 66916 66915 67701 67323 66916 67336 66918 66917 66917 67335 67336 67336 66920 66918 66919 66920 67346 66920 67337 67346 66920 67336 67337 66921 67348 68781 66921 66922 67348 68438 67349 66921 68782 68438 66921 69102 68782 66921 66921 68781 69102 68776 67348 66922 66922 68082 68776 66922 67340 68082 66922 67339 67340 67708 67701 66923 67722 67708 66923 68441 67722 66923 66923 67707 68441 66923 66924 67707 67717 67707 66924 66924 67341 67717 67350 67341 66925 66925 66929 67350 67721 67352 66926 66926 67353 67721 66927 66931 67353 66932 66931 66927 66927 66928 66932 67354 66932 66928 67355 67354 66928 66929 67347 67350 67722 66934 66930 66930 67709 67722 66930 67351 67709 67724 67353 66931 67725 67724 66931 66931 66932 67725 66932 67354 67725 66933 67354 67355 66934 67722 67726 67358 67357 66935 66935 67356 67358 66935 66940 67356 66936 67359 67360 66936 67358 67359 66936 67357 67358 67367 66948 66938 66963 66944 66939 67730 67356 66940 66940 67368 67730 66941 66942 66960 66941 66960 66973 66942 66943 66960 66943 66961 67387 67385 66960 66943 67386 67385 66943 67387 67386 66943 66944 66963 67378 66948 66947 66945 67380 66963 66945 66945 67379 67380 66945 66946 67379 66947 66946 66945 68112 67379 66946 68113 68112 66946 68461 68113 66946 66946 66947 68461 66947 66948 67367 66947 68094 68461 66947 68084 68094 66950 66967 67369 66951 66952 66954 66953 66952 66951 67374 66953 66951 66951 66954 67374 66955 66954 66952 66977 66968 66953 67373 66977 66953 66953 67372 67373 67737 67372 66953 66953 67732 67737 66953 67374 67732 66954 66956 67374 66954 66955 66956 66981 66956 66955 66956 66964 67374 66956 66957 66964 67375 66957 66956 66956 66981 67375 66957 66958 67361 66959 66958 66957 67384 67383 66957 66957 67376 67384 66957 67375 67376 67362 66964 66957 66957 67361 67362 67366 67361 66958 66958 67365 67366 67735 67365 66958 66958 67377 67735 66974 66973 66960 66975 66974 66960 67385 66975 66960 66961 66962 67387 67746 67744 66962 66962 67745 67746 66962 67378 67745 67744 67387 66962 67739 67378 66963 66963 67379 67739 67380 67379 66963 66964 67371 67374 66964 67362 67371 67394 66969 66965 66965 66966 67394 67748 67394 66966 66966 66982 67748 66985 66982 66966 67736 67369 66967 68475 67736 66967 66967 67381 68475 67382 67381 66967 66967 66986 67382 66977 66976 66968 67735 67377 66969 67740 67735 66969 66969 67394 67740 68134 67395 66970 66970 67756 68134 66970 67401 67756 66970 66971 67401 66972 66971 66970 66971 66975 67401 66971 66972 66975 66972 66974 66975 68129 67401 66975 66975 67388 68129 67389 67388 66975 67390 67389 66975 66975 67385 67390 66990 66989 66976 67750 66990 66976 66976 67747 67750 66976 67373 67747 66976 66977 67373 67392 67376 66978 68124 67392 66978 66978 66991 68124 66978 66979 66991 66980 66979 66978 67376 66980 66978 67375 66981 66980 67376 67375 66980 66982 67397 67748 66982 67396 67397 66982 66983 67396 66984 66983 66982 66985 66984 66982 67400 67396 66983 66983 67395 67400 66983 66984 67395 67749 67382 66986 66986 66987 67749 66987 67399 67749 66987 67398 67399 67402 67398 66987 66987 66988 67402 67754 67403 66990 66990 67753 67754 66990 67750 67753 66991 68119 68124 66991 67751 68119 66993 67763 67765 66995 67406 67751 67757 67407 66996 66996 66997 67757 68131 67757 66997 66998 67011 67012 67013 67011 66998 67410 67013 66998 67413 67007 67000 67000 67005 67413 67000 67004 67005 67001 67411 68143 67412 67411 67001 67766 67002 67001 67770 67766 67001 68143 67770 67001 67759 67758 67002 67766 67759 67002 67758 67406 67002 67005 67016 67413 67006 67411 67412 67006 67007 67411 67769 67411 67007 67774 67769 67007 67007 67413 67774 67421 67418 67011 67011 67013 67421 67772 67421 67013 67013 67771 67772 67013 67410 67771 67015 67021 67417 67015 67020 67021 67774 67413 67016 67775 67774 67016 67016 67414 67775 67017 67031 67414 67018 67778 67783 67018 67019 67778 68151 67027 67018 67018 67783 68151 67019 67416 67778 67019 67415 67416 67022 67021 67020 67423 67417 67021 67021 67023 67423 67021 67022 67023 67424 67023 67022 67776 67424 67022 67022 67024 67776 67781 67423 67023 68146 67781 67023 67023 68144 68146 68149 68144 67023 67023 67782 68149 67023 67424 67782 67024 67419 67776 67024 67025 67419 67025 67418 67419 67025 67026 67418 67425 67032 67027 68151 67425 67027 67028 67786 68150 67028 67422 67786 67028 67414 67422 67775 67414 67028 68145 67775 67028 67028 67029 68145 67030 67029 67028 68150 67030 67028 67029 68142 68145 68519 68142 67029 67029 67030 68519 67030 68150 68519 67787 67786 67032 67032 67425 67787 67033 67426 67428 67427 67426 67033 67432 67427 67033 67033 67038 67432 67037 67036 67034 67034 67035 67037 67429 67037 67035 67035 67428 67429 67430 67040 67036 67788 67430 67036 67036 67037 67788 67037 67429 67788 67793 67434 67039 67039 67040 67793 67434 67043 67039 67040 67430 67793 67041 67044 67433 67440 67048 67045 68162 67796 67046 67046 68156 68162 67046 67047 68156 67047 68155 68156 67047 67435 68155 67047 67434 67435 67440 67051 67048 67437 67056 67049 67795 67437 67049 67049 67443 67795 67049 67050 67443 67050 67442 67443 67050 67059 67442 67444 67058 67051 67051 67442 67444 67443 67442 67051 67795 67443 67051 67051 67440 67795 67054 67053 67052 68168 67054 67052 67052 68164 68168 67052 67441 68164 67053 67054 68867 68530 67439 67053 68867 68530 67053 68871 68867 67054 67054 68168 68871 67057 67447 67451 67057 67058 67447 67451 67061 67057 67058 67444 67447 67450 67442 67059 67059 67060 67450 67453 67450 67060 67454 67453 67060 67072 67063 67061 67451 67072 67061 67065 67064 67062 67448 67065 67062 67063 67072 67073 67064 67065 67066 67067 67066 67065 67448 67067 67065 67457 67456 67066 67458 67457 67066 67802 67458 67066 67066 67067 67802 68172 67802 67067 67067 67800 68172 67067 67448 67800 67068 67074 67454 67075 67074 67068 67068 67069 67075 67077 67069 67068 67077 67076 67069 67069 67070 67075 67071 67070 67069 67076 67071 67069 67445 67075 67070 67452 67445 67070 67070 67451 67452 67070 67072 67451 67070 67071 67072 67455 67072 67071 67071 67078 67455 67071 67076 67078 67455 67073 67072 67803 67082 67073 67073 67455 67803 67074 67450 67453 67074 67446 67450 67074 67075 67446 67074 67453 67454 67075 67445 67446 67806 67078 67076 67076 67080 67806 67076 67077 67080 67077 67079 67080 68178 67459 67078 67078 68177 68178 67078 67806 68177 67459 67455 67078 67463 67080 67079 67808 67806 67080 67080 67463 67808 67081 67461 67469 67803 67462 67082 68878 68544 67083 67083 68556 68878 67083 67084 68556 68183 67465 67083 68544 68183 67083 67084 68193 68556 67084 67475 68193 67089 67088 67086 67813 67472 67086 67814 67813 67086 67086 67087 67814 67088 67087 67086 67815 67814 67087 68189 67815 67087 67087 67818 68189 67087 67088 67818 67088 67089 67097 67088 67097 67818 67478 67093 67090 67090 67091 67478 67819 67478 67091 67091 67462 67819 67093 67094 67101 67095 67094 67093 67478 67095 67093 67102 67101 67094 67111 67102 67094 67094 67095 67111 67822 67111 67095 67095 67480 67822 67095 67478 67480 67487 67479 67096 67096 67100 67487 67097 67481 67818 67826 67482 67098 67098 67484 67826 67098 67099 67484 67099 67474 67484 67486 67105 67100 67100 67482 67486 67488 67487 67100 67100 67105 67488 67492 67119 67102 67829 67492 67102 67102 67822 67829 67102 67111 67822 67830 67490 67103 67103 67493 67830 67104 67106 67488 67488 67105 67104 67486 67113 67105 67827 67489 67106 67106 67115 67827 67106 67108 67115 67106 67107 67108 67489 67488 67106 67110 67108 67107 67116 67115 67108 67108 67109 67116 67110 67109 67108 68204 67116 67109 68205 68204 67109 67109 67110 68205 67110 67495 68205 67496 67495 67110 67110 67494 67496 67110 67112 67494 67837 67114 67113 67113 67491 67837 67113 67486 67491 67844 67121 67114 67114 67838 67844 67114 67837 67838 67828 67827 67115 67115 67116 67828 68204 67828 67116 67496 67494 67117 67840 67496 67117 67117 67497 67840 67117 67122 67497 67118 67119 67127 67842 67127 67119 68213 67842 67119 67119 67492 68213 67498 67124 67123 67123 67128 67498 67498 67125 67124 67125 67128 67129 67498 67128 67125 68231 67847 67126 68236 68231 67126 67126 67848 68236 67127 67135 67136 67499 67135 67127 67500 67499 67127 67843 67500 67127 67127 67841 67843 67842 67841 67127 67861 67497 67130 67130 67852 67861 67130 67501 67852 68238 67849 67131 67131 67138 68238 67131 67132 67138 67133 67132 67131 67849 67133 67131 67132 67134 67138 68236 67848 67133 67133 67849 68236 68240 67505 67135 67135 68228 68240 67135 67499 68228 67139 67138 67137 67138 67864 68238 67138 67502 67864 67138 67139 67502 67139 67149 67502 67139 67148 67149 67855 67513 67140 67140 67141 67855 67142 67141 67140 67141 67506 67855 67141 67142 67506 67142 67505 67506 67153 67151 67143 67865 67153 67143 67143 67507 67865 67147 67146 67144 67144 67145 67147 67156 67147 67145 67146 67147 67512 67860 67150 67146 67864 67860 67146 68239 67864 67146 67146 67863 68239 67146 67512 67863 67150 67149 67148 67860 67502 67149 67149 67150 67860 67153 67152 67151 67151 67157 67159 67158 67157 67151 67151 67152 67158 67152 67153 67858 67515 67158 67152 68936 67515 67152 67152 68927 68936 67152 68248 68927 67152 68247 68248 67152 68241 68247 67152 67858 68241 67865 67858 67153 67154 67513 67855 67867 67155 67154 67154 67856 67867 67154 67855 67856 67870 67514 67155 68243 67870 67155 67155 67866 68243 67867 67866 67155 67164 67159 67157 67525 67164 67157 67873 67525 67157 67157 67158 67873 67158 67515 67873 67509 67508 67160 67517 67509 67160 67160 67165 67517 67524 67520 67161 67161 67523 67524 67527 67167 67162 67163 67168 67174 67525 67169 67164 67165 67177 67517 67880 67530 67167 67167 67879 67880 67167 67527 67879 67531 67179 67169 67169 67525 67531 67170 67171 67534 67171 67172 67534 67172 67520 67534 67547 67182 67173 67173 67182 67185 67884 67876 67175 67175 67178 67884 67529 67177 67176 67529 67517 67177 67179 67532 67543 67179 67531 67532 67538 67537 67180 67887 67183 67181 67181 67550 67887 67181 67182 67550 67182 67547 67550 68259 67874 67183 67183 67887 68259 67542 67541 67184 67184 67189 67542 67546 67545 67186 67186 67543 67546 67187 67544 67548 67188 67204 67551 67189 67191 67542 67192 67191 67190 67553 67192 67190 67554 67553 67190 67190 67198 67554 67191 67192 67542 67890 67542 67192 67192 67553 67890 67908 67199 67193 67193 67545 67908 67904 67903 67194 67194 67899 67904 67194 67551 67899 67194 67196 67198 67903 67196 67194 67195 68960 68968 67195 67900 68960 67195 67196 67900 67197 67196 67195 68968 67197 67195 67196 67197 67198 67903 67900 67196 67916 67198 67197 67197 67905 67916 67907 67905 67197 68968 67907 67197 67916 67554 67198 67911 67910 67199 67199 67909 67911 67199 67908 67909 67201 67206 67557 67912 67555 67202 68622 67912 67202 67202 68293 68622 67202 68292 68293 67202 67910 68292 67220 67204 67203 67203 67219 67220 67228 67219 67203 67203 67205 67228 67899 67551 67204 67204 67552 67899 67204 67220 67552 67913 67557 67206 67206 67555 67913 67562 67561 67207 67564 67562 67207 67208 67210 67213 67211 67210 67208 67563 67212 67209 67921 67563 67209 67209 67919 67921 67565 67213 67210 67566 67565 67210 68305 67566 67210 67210 67211 68305 67211 67897 68305 67211 67548 67897 67563 67214 67212 67214 67563 67567 67926 67564 67215 67927 67926 67215 67215 67216 67927 67217 67216 67215 67938 67927 67216 67216 67575 67938 67216 67223 67575 67216 67222 67223 67216 67217 67222 67217 67221 67222 67218 67929 68308 67218 67219 67929 67220 67219 67218 67902 67220 67218 68976 67902 67218 67218 68308 68976 67219 67228 67929 67902 67552 67220 67223 67222 67221 67568 67223 67221 67934 67575 67223 67223 67568 67934 67225 67227 67228 67577 67227 67225 67226 67227 67577 67228 67227 67226 67929 67228 67226 67930 67929 67226 67226 67577 67930 67589 67233 67229 67574 67572 67230 67231 67585 67586 67232 67235 67581 67233 67589 67590 67581 67235 67234 67588 67581 67234 67234 67240 67588 67236 67237 68334 67237 68330 68334 67237 68324 68330 67237 67944 68324 67237 67584 67944 67948 67239 67238 67238 67594 67948 67238 67593 67594 67239 67948 67949 67245 67244 67241 67242 67617 67955 67242 67265 67617 67249 67248 67243 67642 67249 67243 67958 67602 67244 67961 67958 67244 67244 67607 67961 67244 67245 67607 67247 67601 67606 67247 67596 67601 67965 67610 67248 67248 67249 67965 67249 67642 67965 67253 67252 67251 68341 67253 67251 68350 68340 67252 67252 67253 68350 68340 67963 67252 68678 68350 67253 67253 68341 68678 67255 67626 67981 67981 67980 67255 67269 67259 67257 67621 67269 67257 67257 67618 67621 67976 67618 67257 67257 67622 67976 67257 67258 67622 67259 67258 67257 67258 67259 67268 67258 67260 67622 67269 67268 67259 67976 67622 67260 67979 67976 67260 67260 67261 67979 67261 67263 67979 67986 67263 67262 67262 67270 67986 67271 67270 67262 67986 67979 67263 67266 67265 67264 67633 67266 67264 67264 67631 67633 67264 67267 67631 67972 67617 67265 67265 67630 67972 67265 67266 67630 68365 67630 67266 67266 67993 68365 67994 67993 67266 68386 67994 67266 67266 67999 68386 67266 67633 67999 67634 67631 67267 67267 67277 67634 67268 67278 67637 67268 67269 67278 67629 67278 67269 67269 67627 67629 67269 67621 67627 68368 67986 67270 67270 67987 68368 67270 67271 67987 67271 67623 67987 67654 67280 67272 68378 67654 67272 68379 68378 67272 67272 67273 68379 67273 67991 68379 67273 67990 67991 67632 67626 67274 68009 68008 67275 67275 67655 68009 67656 67655 67275 67982 67656 67275 67275 67282 67982 67649 67634 67276 67276 67285 67649 67634 67277 67276 67278 67629 67635 67279 67626 67632 68374 67626 67279 67279 68005 68374 67279 67654 68005 67279 67280 67654 67281 67280 67279 67284 67281 67279 67632 67284 67279 67280 67281 67284 67282 67615 67982 67285 67288 67649 68004 67646 67286 67286 67638 68004 67290 67288 67287 67288 67643 67649 67645 67643 67288 67288 67289 67645 67290 67289 67288 67289 67296 67645 67289 67290 67296 67310 67295 67291 68019 68017 67292 69066 68019 67292 69372 69066 67292 67292 68714 69372 67292 68008 68714 67670 67669 67294 67294 67667 67670 67295 67310 67660 68022 67296 67295 67295 67659 68022 67660 67659 67295 68016 67645 67296 68022 68016 67296 67297 67661 67664 68020 67665 67298 68024 68020 67298 67298 67666 68024 68406 67671 67300 67300 68038 68406 67301 67302 67668 67302 67303 67668 67673 67668 67303 67676 67670 67304 68041 67676 67304 68042 68041 67304 67304 67305 68042 67305 67678 68042 67690 67683 67306 67308 67307 67306 67683 67308 67306 68409 67687 67307 68411 68409 67307 67307 67308 68411 67308 67684 68411 67308 67683 67684 67679 67677 67309 68036 67679 67309 67309 67671 68036 67310 67311 67660 67311 67312 67660 68039 67660 67312 67312 67680 68039 67312 67313 67680 67682 67681 67314 67691 67318 67315 68050 67691 67315 67315 67692 68050 67315 67675 67692 67685 67319 67316 67686 67685 67316 67316 67317 67686 68033 67686 67317 67317 67664 68033 67691 67320 67318 67685 67322 67319 67689 67688 67320 67693 67689 67320 67320 67691 67693 67321 67697 67700 67321 67322 67697 68070 67697 67322 67322 67685 68070 67701 67333 67323 67324 67326 67327 67324 67325 67326 67695 67326 67325 67328 67327 67326 68067 67328 67326 67326 67695 68067 68068 67329 67327 67327 68066 68068 67327 67328 68066 68067 68066 67328 68068 67330 67329 68068 67696 67330 67331 67696 67698 67332 67333 67351 67701 67351 67333 67710 67344 67334 67334 67700 67710 67345 67336 67335 67335 67344 67345 67704 67337 67336 67713 67704 67336 67336 67345 67713 67714 67346 67337 68080 67714 67337 67337 67704 68080 67340 67339 67338 67706 67340 67338 67340 67706 68082 67341 67350 67717 67703 67695 67342 68435 67703 67342 68436 68435 67342 68447 68436 67342 67342 67719 68447 67342 67343 67719 67343 67718 67719 67721 67718 67343 67343 67352 67721 67713 67345 67344 67344 67710 67713 68437 67705 67346 67346 67714 68437 67347 67349 67350 67348 68777 68781 68778 68777 67348 67348 68776 68778 67716 67350 67349 68438 67716 67349 67350 67716 67717 67351 67701 67709 67353 67718 67721 67723 67718 67353 67724 67723 67353 67354 67360 67725 68106 67358 67356 67356 68104 68106 67356 67730 68104 67727 67359 67358 68476 67727 67358 68477 68476 67358 67358 68105 68477 68106 68105 67358 67727 67360 67359 68455 67725 67360 67360 67727 68455 67366 67364 67361 67363 67362 67361 67370 67363 67361 67361 67364 67370 67362 67363 67371 67734 67371 67363 68102 67734 67363 68103 68102 67363 67363 67370 68103 67364 67365 67728 67366 67365 67364 67728 67370 67364 67729 67728 67365 67738 67729 67365 67365 67735 67738 67736 67730 67368 67368 67369 67736 67370 68097 68103 67370 68096 68097 67370 67728 68096 67731 67374 67371 67734 67731 67371 67372 67737 68478 67747 67373 67372 68831 67747 67372 67372 68490 68831 67372 68478 68490 67374 67731 67732 67376 67383 67384 67392 67383 67376 67378 67739 67745 68112 67739 67379 68497 68475 67381 67381 67382 68497 67382 68123 68497 67382 67749 68123 67383 67392 67393 67385 67386 67390 67391 67390 67386 67744 67391 67386 67386 67387 67744 68505 68129 67388 67388 67389 68505 67389 68116 68498 67389 67391 68116 67389 67390 67391 67389 68498 68505 67391 67744 68116 67405 67393 67392 67752 67405 67392 68124 67752 67392 67742 67740 67394 67748 67742 67394 68133 67400 67395 68134 68133 67395 68127 67397 67396 68132 68127 67396 67396 67400 68132 67397 68126 68508 68127 68126 67397 68508 67748 67397 67404 67399 67398 67398 67403 67404 67398 67402 67403 67399 67404 68135 68130 67749 67399 68135 68130 67399 68133 68132 67400 68128 67756 67401 68129 68128 67401 67755 67404 67403 67403 67754 67755 68136 68135 67404 68137 68136 67404 68138 68137 67404 67404 67755 68138 68119 67751 67406 67406 67758 68119 67764 67408 67407 67407 67757 67764 67764 67763 67408 67768 67410 67409 67409 67767 67768 67410 67768 67771 67411 68142 68143 67411 67769 68142 67785 67778 67416 67416 67779 67785 67420 67419 67418 67421 67420 67418 67419 67420 67776 67420 67421 67772 67777 67776 67420 67420 67772 67777 67780 67779 67423 67781 67780 67423 67776 67773 67424 67424 67773 67782 68525 67787 67425 68527 68525 67425 67425 68151 68527 67429 67428 67426 67789 67429 67426 67426 67427 67789 67792 67789 67427 67427 67431 67792 67432 67431 67427 67791 67788 67429 67429 67790 67791 67429 67789 67790 67430 67791 67793 67430 67788 67791 67794 67792 67431 67431 67438 67794 67433 67436 67440 67437 67436 67433 67793 67791 67434 67791 67435 67434 67435 67791 68155 67795 67440 67436 67436 67437 67795 67438 67439 67794 68158 67794 67439 68159 68158 67439 68161 68159 67439 68529 68161 67439 68530 68529 67439 67441 67797 68164 67798 67797 67441 67446 67444 67442 67450 67446 67442 67444 67446 67447 67447 67446 67445 67452 67447 67445 67452 67451 67447 67801 67800 67448 68166 67801 67448 67448 67449 68166 67449 68163 68166 67449 67796 68163 67812 67803 67455 67455 67459 67812 67456 67460 67461 67456 67457 67460 67804 67460 67457 67457 67458 67804 68175 67804 67458 67458 68172 68175 67458 67802 68172 67459 67811 67812 68178 67811 67459 67807 67461 67460 68537 67807 67460 67460 68176 68537 67460 68175 68176 67460 67804 68175 67807 67469 67461 68184 67819 67462 67462 67805 68184 67462 67803 67805 67463 67464 67808 67810 67808 67464 68545 67810 67464 67464 68544 68545 67464 68183 68544 67464 67465 68183 68536 67468 67466 67466 68186 68536 67466 68181 68186 67466 67467 68181 67467 67813 68181 67467 67472 67813 67467 67471 67472 67467 67470 67471 68536 68174 67468 67817 67473 67469 67469 67816 67817 67469 67807 67816 67817 67474 67473 67474 67483 67484 67817 67483 67474 67475 67476 68193 67477 67476 67475 68203 68193 67476 67476 68202 68203 67476 67827 68202 67476 67477 67827 67477 67489 67827 67477 67479 67489 68185 67480 67478 67478 67819 68185 67479 67487 67489 68557 68196 67480 67480 68195 68557 67480 68185 68195 68196 67822 67480 67820 67818 67481 67824 67820 67481 67482 67831 67832 67482 67826 67831 67482 67485 67486 67832 67485 67482 67821 67484 67483 68191 67821 67483 67483 67817 68191 67831 67826 67484 68194 67831 67484 67484 67825 68194 67484 67821 67825 68211 67491 67485 67485 67833 68211 67485 67832 67833 67491 67486 67485 67487 67488 67489 68197 67823 67490 68201 68197 67490 68207 68201 67490 68222 68207 67490 67490 67830 68222 68214 67837 67491 67491 68211 68214 67492 68206 68213 67492 67829 68206 68569 68205 67495 67495 68220 68569 67495 67496 68220 67496 67840 68220 67861 67840 67497 67499 67500 68221 67499 68221 68228 67500 67843 68221 67502 67860 67864 67862 67507 67503 67503 67857 67862 67859 67857 67503 67503 67504 67859 67855 67506 67505 67856 67855 67505 68240 67856 67505 67507 67862 67865 67854 67853 67509 67509 67517 67854 67510 67511 67516 67511 67514 67870 67524 67516 67511 67868 67524 67511 67869 67868 67511 68243 67869 67511 67511 67870 68243 68245 67863 67512 67512 68244 68245 68257 67873 67515 68258 68257 67515 68937 68258 67515 67515 68936 68937 67524 67523 67516 67517 67518 67854 67519 67518 67517 67529 67519 67517 67518 67519 68250 68249 67854 67518 68250 68249 67518 67519 68252 68253 67519 67529 68252 68253 68250 67519 68254 67534 67520 67520 67521 68254 67522 67521 67520 67524 67522 67520 67521 67522 68596 68255 68254 67521 68597 68255 67521 67521 68596 68597 67522 67524 67872 67522 67872 68596 67524 67868 67871 67524 67871 67872 67877 67531 67525 67525 67873 67877 67878 67528 67526 67526 67874 67878 67527 67528 67875 68264 67879 67527 67527 68263 68264 67527 68262 68263 67527 67875 68262 67878 67875 67528 67529 67533 68252 67880 67535 67530 67877 67532 67531 67532 67891 67896 67532 67877 67891 67896 67543 67532 67886 67538 67534 68254 67886 67534 67888 67540 67535 67535 67880 67888 67885 67884 67536 67536 67541 67885 67537 67539 68253 67537 67538 67539 67538 67886 68608 68266 67539 67538 68608 68266 67538 68266 68253 67539 67549 67544 67540 67888 67549 67540 67889 67885 67541 67541 67542 67889 67890 67889 67542 67896 67546 67543 67549 67548 67544 67545 67901 67908 67545 67546 67901 67546 67896 67901 68269 67550 67547 67547 67915 68269 67547 67559 67915 67547 67556 67559 67898 67897 67548 67548 67549 67898 68277 67898 67549 67549 67888 68277 68269 67887 67550 67904 67899 67552 67552 67903 67904 68960 67903 67552 69279 68960 67552 67552 68640 69279 67552 68639 68640 67552 67902 68639 67893 67890 67553 67895 67893 67553 68279 67895 67553 67553 67916 68279 67553 67554 67916 68285 67913 67555 68286 68285 67555 68287 68286 67555 67555 67912 68287 67561 67559 67556 67557 67913 67918 67558 67561 67562 67558 67559 67561 67560 67559 67558 68304 67560 67558 68975 68304 67558 67558 67920 68975 67558 67562 67920 67559 67560 67915 67560 67914 67915 68630 67914 67560 67560 68304 68630 67925 67920 67562 67562 67564 67925 67924 67567 67563 67563 67921 67924 67926 67925 67564 68305 67570 67566 67935 67568 67567 68306 67935 67567 67567 67924 68306 67935 67934 67568 67928 67576 67569 67569 67570 67928 67940 67928 67570 68316 67940 67570 67570 68305 68316 68310 67931 67571 67571 67572 68310 67572 67573 68310 67574 67573 67572 68312 68310 67573 68317 68312 67573 67573 67574 68317 67574 67949 68317 67575 67936 67938 67937 67936 67575 68313 67937 67575 67575 68309 68313 67575 67934 68309 67944 67584 67576 67945 67944 67576 67576 67940 67945 67576 67928 67940 67931 67930 67577 67578 67587 67943 67578 67585 67587 67586 67585 67578 67578 67579 67586 67580 67579 67578 67943 67580 67578 67595 67586 67579 67597 67595 67579 68662 67597 67579 67579 67580 68662 67580 67943 68323 67580 67941 68662 67942 67941 67580 68660 67942 67580 67580 68323 68660 67943 67587 67581 68323 67943 67581 67581 68322 68323 67581 67582 68322 67583 67582 67581 67946 67583 67581 67581 67588 67946 68661 68322 67582 67582 67583 68661 67583 68332 68661 67583 67946 68332 67588 67603 67946 67588 67602 67603 67591 67590 67589 67590 67591 67604 67605 67604 67591 67959 67605 67591 67591 67592 67959 67592 67598 67959 68327 67594 67593 67593 67951 68327 67952 67951 67593 68327 67948 67594 67597 67596 67595 67957 67601 67596 67596 67597 67957 68331 67957 67597 67597 68329 68331 67597 67950 68329 67597 67941 67950 68662 67941 67597 67598 67953 67959 67954 67600 67599 67956 67954 67599 67964 67956 67599 67599 67955 67964 68325 67947 67600 67600 67954 68325 67957 67606 67601 67958 67603 67602 68332 67946 67603 68333 68332 67603 67603 67958 68333 67616 67608 67604 67604 67605 67616 67959 67616 67605 67606 67957 68347 67960 67609 67606 68347 67960 67606 68340 67961 67607 67607 67963 68340 67960 67613 67609 68349 67611 67610 67610 67970 68349 67610 67969 67970 67610 67965 67969 68348 67966 67611 68355 68348 67611 67611 68349 68355 68688 67655 67612 67612 68680 68688 68357 68345 67612 67612 67655 68357 67967 67624 67613 67613 67960 67967 67615 67656 67982 68353 67656 67615 67615 68344 68353 67615 67616 68344 67616 67959 68344 68346 67955 67617 68358 68346 67617 67617 67972 68358 67974 67621 67618 67975 67974 67618 67618 67619 67975 67620 67619 67618 67977 67620 67618 67618 67976 67977 67619 68689 68690 67619 67620 68689 67984 67975 67619 67619 67983 67984 68690 67983 67619 69016 68689 67620 69345 69016 67620 69356 69345 67620 69358 69356 67620 70321 69358 67620 67620 69346 70321 69622 69346 67620 67620 67977 69622 67628 67627 67621 67974 67628 67621 67623 67624 67967 67988 67987 67623 67623 67967 67988 68374 67981 67626 67627 67628 67629 67635 67629 67628 67636 67635 67628 67998 67636 67628 67628 67973 67998 67974 67973 67628 68365 67972 67630 67644 67633 67631 67631 67634 67644 67633 67644 67999 67634 67643 67644 67649 67643 67634 67636 68002 68708 67636 67998 68002 68007 68004 67638 68389 68388 67639 67639 67648 68389 67639 67647 67648 67639 67640 67647 67653 67647 67640 68377 68372 67641 68361 67642 67641 68372 68361 67641 67969 67965 67642 68361 67969 67642 67645 67644 67643 67644 67645 68003 68000 67999 67644 68010 68000 67644 67644 68003 68010 68016 68003 67645 68391 67651 67646 67646 68004 68391 67652 67648 67647 68015 67652 67647 67647 68014 68015 67647 67650 68014 67653 67650 67647 68722 68389 67648 67648 67652 68722 67650 67651 68014 67651 68012 68014 68391 68012 67651 68726 68722 67652 67652 68015 68726 68378 68005 67654 68688 68009 67655 67655 67656 68357 67656 68353 68357 67657 67658 68395 67659 67658 67657 68407 67659 67657 67657 68395 68407 68748 68736 67658 67658 68046 68748 67658 67660 68046 67658 67659 67660 68736 68395 67658 68396 68022 67659 68407 68396 67659 67660 68039 68046 67663 67662 67661 67665 67663 67661 67661 67662 67664 67662 67663 68032 68033 67664 67662 67662 68032 68033 67663 68021 68032 67663 68020 68021 67663 67665 68020 68035 68024 67666 67666 68034 68035 67668 67673 68027 67676 67675 67669 67669 67670 67676 68037 68036 67671 68405 68037 67671 68406 68405 67671 67674 67673 67672 68069 67674 67672 68403 68027 67673 67673 68031 68403 67673 67674 68031 68413 68031 67674 67674 68079 68413 67674 68069 68079 68040 67692 67675 67675 67676 68040 68041 68040 67676 67679 67678 67677 68043 68042 67678 67678 67679 68043 68045 68043 67679 67679 68036 68045 68048 68039 67680 67680 67681 68048 67681 67682 68048 68049 68048 67682 67682 68029 68049 67683 67690 68057 68057 67684 67683 68412 68411 67684 67684 68057 68412 67685 68062 68070 67685 67686 68062 68762 68062 67686 69084 68762 67686 67686 68397 69084 67686 68033 68397 68408 68034 67687 68409 68408 67687 68058 67690 67688 68060 68058 67688 67688 67689 68060 68063 68060 67689 67689 67693 68063 68058 68057 67690 67694 67693 67691 68064 67694 67691 67691 68050 68064 68065 68050 67692 67692 68040 68065 67693 67694 68063 67694 68061 68063 68064 68061 67694 68072 68067 67695 67695 67702 68072 67703 67702 67695 68076 67698 67696 67696 68068 68076 68071 67700 67697 67697 68070 68071 68076 67699 67698 68078 68077 67699 67699 68076 68078 67711 67710 67700 67712 67711 67700 68071 67712 67700 67701 67708 67709 68770 68072 67702 69094 68770 67702 67702 68433 69094 67702 67703 68433 68435 68433 67703 68091 68080 67704 67704 67713 68091 68081 67706 67705 68437 68081 67705 67706 68081 68082 67707 68085 68441 68446 68085 67707 67707 68083 68446 67707 67717 68083 67722 67709 67708 67720 67713 67710 67710 67711 67720 68086 67720 67711 68442 68086 67711 67711 67712 68442 67712 68432 68442 67712 68071 68432 67713 67720 68086 67713 68087 68091 68088 68087 67713 68450 68088 67713 67713 68086 68450 68445 68437 67714 67714 68444 68445 67714 68080 68444 67717 67716 67715 68083 67717 67715 68439 68083 67715 67715 67716 68439 68440 68439 67716 67716 68438 68440 68458 67719 67718 67718 67723 68458 68453 68447 67719 67719 68452 68453 68458 68452 67719 68084 67726 67722 68085 68084 67722 68441 68085 67722 68786 68458 67723 67723 68454 68786 67723 68092 68454 67723 67724 68092 67724 67725 68092 68093 68092 67725 68455 68093 67725 68456 68455 67727 68476 68456 67727 67728 67729 68481 68099 68096 67728 68464 68099 67728 68481 68464 67728 67729 67738 68481 67730 67736 68104 67733 67732 67731 67734 67733 67731 68478 67737 67732 67732 68107 68478 67732 67733 68107 68470 68107 67733 67733 68101 68470 67733 67734 68101 68102 68101 67734 67743 67738 67735 68114 67743 67735 67735 67740 68114 68475 68104 67736 67738 67743 68482 68482 68481 67738 68110 67745 67739 68112 68110 67739 67742 67741 67740 68494 68114 67740 67740 67741 68494 67741 67742 67748 67741 68120 68494 68122 68120 67741 68125 68122 67741 67741 67748 68125 69136 68804 67743 69139 69136 67743 67743 68820 69139 67743 68114 68820 68804 68482 67743 67744 68115 68116 67744 68111 68115 67744 67746 68111 68111 67746 67745 67745 68110 68111 68118 67750 67747 68499 68118 67747 68831 68499 67747 68508 68125 67748 68130 68123 67749 68118 67753 67750 68507 68131 67752 67752 68124 68507 68117 67754 67753 68118 68117 67753 68510 67755 67754 67754 68117 68510 68515 68138 67755 67755 68510 68515 68500 68134 67756 67756 68128 68500 67757 67760 67764 67762 67760 67757 68131 67762 67757 68851 67761 67758 67758 67759 68851 68512 68119 67758 67758 68511 68512 67758 67761 68511 68853 68851 67759 68859 68853 67759 67759 68858 68859 67759 68852 68858 67759 68517 68852 67759 67766 68517 68518 67764 67760 68851 68518 67760 67760 67761 68851 67762 67761 67760 68513 68511 67761 67761 67762 68513 67762 68131 68513 68139 67765 67763 67763 67764 68139 68520 68139 67764 67764 68518 68520 67765 68139 68140 67766 67770 68517 67767 68140 68141 67773 67768 67767 68141 67773 67767 67773 67771 67768 68145 68142 67769 67769 67775 68145 67769 67774 67775 67770 68143 68517 67777 67772 67771 67771 67773 67777 67773 67776 67777 68141 67782 67773 68147 67784 67778 67778 67785 68147 67784 67783 67778 68147 67785 67779 67779 67780 68147 67780 67781 68146 68148 68147 67780 67780 68146 68148 67782 68141 68149 68527 68151 67783 68865 68527 67783 68866 68865 67783 67783 68524 68866 67783 67784 68524 67784 68147 68148 67784 68148 68524 67786 67787 68150 68525 68150 67787 68152 67790 67789 67789 67792 68152 67790 68154 68155 67790 68152 68154 68155 67791 67790 68153 68152 67792 67792 67794 68153 68157 68153 67794 68158 68157 67794 67796 68162 68163 68167 68164 67797 68171 68167 67797 67797 67799 68171 67797 67798 67799 67799 68170 68171 68173 68172 67800 67800 67801 68173 67801 68169 68173 67801 68166 68169 67811 67805 67803 67812 67811 67803 68550 68184 67805 67805 68179 68550 67805 67811 68179 67806 67809 68177 67806 67808 67809 68551 67816 67807 67807 68537 68551 67810 67809 67808 68543 68177 67809 68546 68543 67809 67809 68180 68546 67809 67810 68180 68545 68180 67810 67811 68178 68179 67813 67814 67815 68182 68181 67813 68188 68182 67813 67813 67815 68188 68553 68188 67815 67815 68189 68553 68192 67817 67816 68551 68192 67816 68192 68191 67817 68190 68189 67818 67818 67820 68190 67819 68184 68185 68199 68190 67820 67820 67824 68199 68555 67825 67821 67821 68191 68555 68206 67829 67822 67822 68196 68206 68197 67824 67823 67824 68198 68199 67824 68197 68198 68210 68194 67825 68555 68210 67825 67827 67828 68202 68560 68202 67828 67828 68204 68560 67830 67847 68222 68194 67832 67831 67832 68194 68210 68210 67833 67832 68212 68211 67833 68567 68212 67833 68899 68567 67833 67833 68210 68899 67834 67835 68209 67836 67835 67834 68575 67836 67834 67834 68223 68575 67834 68209 68223 67835 68208 68209 68898 68208 67835 67835 67836 68898 69511 68898 67836 69512 69511 67836 67836 69217 69512 67836 68575 69217 67839 67838 67837 68214 67839 67837 68225 67844 67838 68571 68225 67838 67838 67839 68571 67839 68214 68571 67840 68219 68220 67840 67861 68219 68215 67843 67841 67841 67842 68215 67842 68213 68215 67843 68215 68221 68227 67846 67844 67844 68217 68227 68218 68217 67844 68225 68218 67844 68237 67859 67845 67845 68226 68237 67845 67846 68226 68227 68226 67846 68224 68222 67847 68231 68224 67847 67851 67850 67849 68238 67851 67849 67849 68231 68236 68232 68231 67849 68579 68232 67849 67849 67850 68579 67850 67851 68246 68583 68579 67850 68587 68583 67850 67850 68246 68587 67851 68239 68246 67851 68238 68239 69227 69224 67852 67852 68916 69227 67852 67853 68916 68911 67861 67852 69224 68911 67852 67853 68595 68916 67853 68249 68595 67853 67854 68249 68584 67867 67856 67856 68242 68584 67856 68240 68242 67865 67862 67857 67857 67858 67865 67859 67858 67857 67858 68237 68241 67858 67859 68237 68911 68219 67861 68246 68239 67863 67863 68245 68246 68239 68238 67864 67866 67867 68584 68588 68243 67866 68592 68588 67866 67866 68585 68592 67866 68242 68585 68584 68242 67866 67868 67869 68588 68588 67871 67868 67869 68243 68588 68596 67872 67871 67871 68589 68596 67871 68588 68589 68257 67877 67873 68260 67878 67874 67874 68259 68260 67875 67878 68262 68256 67882 67876 67876 67883 68256 67884 67883 67876 67892 67891 67877 68257 67892 67877 67878 68260 68262 68271 67881 67879 67879 68264 68271 67881 67880 67879 67880 67881 67888 68277 67888 67881 67881 68271 68277 68598 68593 67882 67882 68256 68598 68265 68256 67883 67883 67885 68265 67883 67884 67885 68952 68265 67885 67885 68603 68952 67885 68273 68603 67885 67889 68273 67886 68267 68608 67886 68254 68267 68269 68259 67887 67889 68272 68273 67889 67894 68272 67889 67893 67894 67889 67890 67893 68276 67896 67891 68606 68276 67891 67891 67892 68606 68947 68606 67892 67892 68946 68947 67892 68258 68946 67892 68257 68258 67895 67894 67893 68278 68272 67894 68617 68278 67894 68618 68617 67894 67894 67895 68618 67895 68279 68618 68276 68274 67896 68274 67901 67896 68638 68305 67897 67897 68281 68638 67897 67898 68281 67898 68277 68281 67900 67903 68960 67917 67908 67901 68275 67917 67901 67901 68274 68275 68648 68639 67902 67902 68647 68648 68979 68647 67902 67902 68976 68979 68279 67916 67905 68632 68279 67905 67905 67906 68632 67907 67906 67905 68642 68632 67906 69285 68642 67906 67906 69283 69285 67906 67907 69283 67907 69282 69283 67907 68968 69282 67917 67909 67908 68291 67911 67909 67909 68290 68291 67909 67917 68290 67910 68291 68292 67910 67911 68291 68624 68287 67912 67912 68622 68624 68285 67918 67913 68619 68289 67914 68620 68619 67914 68631 68620 67914 67914 68630 68631 68289 67915 67914 68289 68269 67915 68643 68290 67917 67917 68275 68643 68295 67919 67918 67918 68285 68295 67922 67921 67919 68295 67922 67919 67920 68652 68975 67920 67925 68652 67921 67923 67924 67921 67922 67923 68300 67923 67922 67922 68299 68300 67922 68295 68299 68306 67924 67923 67923 68302 68306 67923 68300 68302 67925 68636 68652 68637 68636 67925 68653 68637 67925 67925 68307 68653 67925 67926 68307 67926 67927 68307 68315 68307 67927 67927 67939 68315 67927 67938 67939 67929 67930 68308 68658 68308 67930 67930 67931 68658 67931 67932 68658 67933 67932 67931 68310 67933 67931 67932 67933 68981 67932 68657 68658 68980 68657 67932 68981 68980 67932 69305 69303 67933 67933 68659 69305 67933 68310 68659 69303 68981 67933 67934 67935 68309 67935 68306 68309 67939 67938 67936 67936 67937 67939 68319 67939 67937 67937 68313 68319 68320 68315 67939 67939 68319 68320 68655 67945 67940 68974 68655 67940 67940 68973 68974 67940 68316 68973 67941 67942 67950 68318 67950 67942 68660 68318 67942 67944 68321 68324 67944 67945 68321 68992 68321 67945 67945 68654 68992 68655 68654 67945 68325 67952 67947 68328 67949 67948 67948 68327 68328 67949 68312 68317 68328 68312 67949 68668 68329 67950 67950 68318 68668 68997 68327 67951 69324 68997 67951 67951 68996 69324 67951 68325 68996 67951 67952 68325 68345 68344 67953 68344 67959 67953 68664 68325 67954 67954 68326 68664 67954 67956 68326 68338 67964 67955 68346 68338 67955 67956 67964 68326 68671 68347 67957 67957 68331 68671 67958 67962 68333 67958 67961 67962 67968 67967 67960 68354 67968 67960 67960 68347 68354 68339 67962 67961 68350 68339 67961 67961 68340 68350 68335 68333 67962 68339 68335 67962 68336 68326 67964 68338 68336 67964 68371 67988 67967 67967 67968 68371 67968 68360 68371 67968 68359 68360 67968 68354 68359 68361 67970 67969 68355 68349 67970 68361 68355 67970 68684 68356 67971 67971 68681 68684 67971 68348 68681 68364 68358 67972 68365 68364 67972 67973 67985 67998 67973 67974 67985 67974 67983 67985 67974 67975 67983 67984 67983 67975 67978 67977 67976 67979 67978 67976 67977 68691 69622 68693 68691 67977 67977 68369 68693 67977 67978 68369 67978 67986 68369 67978 67979 67986 68687 68680 67980 67980 68375 68687 67980 67981 68375 67981 68374 68385 69019 68375 67981 67981 68385 69019 68690 68366 67983 67996 67985 67983 68366 67996 67983 67985 67995 67998 67996 67995 67985 67986 68367 68369 68368 68367 67986 67987 68367 68368 68371 68367 67987 67987 67988 68371 68373 67990 67989 67989 68362 68373 67992 67991 67990 68373 67992 67990 67991 67992 69022 68702 68379 67991 68703 68702 67991 69022 68703 67991 67992 68373 68696 67992 68696 69022 67993 68364 68365 68701 68364 67993 69627 68701 67993 67993 68698 69627 68700 68698 67993 67993 67994 68700 67994 68386 68700 68001 67998 67995 67995 67997 68001 67995 67996 67997 68366 67997 67996 68380 68001 67997 67997 68376 68380 67997 68366 68376 67998 68001 68002 67999 68000 68386 68715 68386 68000 68716 68715 68000 68000 68393 68716 68000 68392 68393 68000 68010 68392 68382 68002 68001 68001 68380 68382 68002 68382 68383 68002 68383 68708 68003 68016 68392 68392 68010 68003 68004 68006 68011 68007 68006 68004 68004 68011 68391 68713 68374 68005 68724 68713 68005 68005 68723 68724 68005 68378 68723 68720 68011 68006 69361 68720 68006 68006 68007 69361 68007 68718 69361 68007 68387 68718 69018 68714 68008 69019 69018 68008 68008 68009 69019 68009 68687 69019 68688 68687 68009 68720 68719 68011 68011 68012 68391 68013 68012 68011 68719 68013 68011 68725 68014 68012 69045 68725 68012 68012 68013 69045 69384 69045 68013 68013 68719 69384 68725 68015 68014 68015 68725 68726 68016 68022 68392 68019 68018 68017 68018 68019 68038 68739 68038 68019 68740 68739 68019 69401 68740 68019 68019 69066 69401 68024 68021 68020 68024 68023 68021 68021 68023 68032 68396 68392 68022 68023 68024 68401 68399 68032 68023 68023 68398 68399 69059 68398 68023 68023 68401 69059 68024 68035 68401 68025 68028 68029 68402 68028 68025 68403 68402 68025 68025 68026 68403 68027 68026 68025 68029 68027 68025 68026 68027 68403 68030 68029 68028 69076 68030 68028 68028 68402 69076 68750 68049 68029 68751 68750 68029 68029 68742 68751 68029 68030 68742 69415 68742 68030 68030 69411 69415 68030 69076 69411 68743 68403 68031 68031 68414 68743 68031 68413 68414 68397 68033 68032 68399 68397 68032 68404 68035 68034 68408 68404 68034 68404 68400 68035 68035 68400 68401 68746 68045 68036 68036 68741 68746 68036 68037 68741 68037 68737 68741 68037 68405 68737 68738 68406 68038 68739 68738 68038 68047 68046 68039 68048 68047 68039 68427 68065 68040 68040 68051 68427 68040 68041 68051 68041 68042 68051 68052 68051 68042 68042 68043 68052 68045 68044 68043 68760 68052 68043 68043 68053 68760 68043 68044 68053 68044 68045 69081 69081 68053 68044 68045 69079 69081 68045 68746 69079 68749 68748 68046 68046 68047 68749 69085 68749 68047 68047 68753 69085 68047 68048 68753 68048 68752 68753 68048 68049 68752 68049 68750 68752 68065 68064 68050 68428 68427 68051 68764 68428 68051 68051 68052 68764 68052 68760 68764 69090 68760 68053 68053 69081 69090 68054 68397 68399 69084 68397 68054 68054 69072 69084 68054 68055 69072 68056 68055 68054 68399 68056 68054 68055 69067 69395 68055 68056 69067 69412 69072 68055 69916 69412 68055 68055 69653 69916 68055 69395 69653 68056 68398 69067 68399 68398 68056 68057 68059 68412 68057 68058 68059 68061 68059 68058 68058 68060 68061 68418 68412 68059 68059 68061 68418 68063 68061 68060 69087 68418 68061 68061 68426 69087 68061 68425 68426 68061 68065 68425 68061 68064 68065 68420 68070 68062 68762 68420 68062 68766 68425 68065 68065 68427 68766 68430 68068 68066 68066 68072 68430 68066 68067 68072 68429 68076 68068 68430 68429 68068 68069 68077 68079 68421 68071 68070 68070 68420 68421 68434 68432 68071 68071 68421 68434 68072 68073 68430 68770 68073 68072 68073 68074 68430 68075 68074 68073 68770 68075 68073 68771 68430 68074 68772 68771 68074 69937 68772 68074 68074 69936 69937 68074 69446 69936 69447 69446 68074 68074 68075 69447 69704 69447 68075 68075 69445 69704 68075 68770 69445 68431 68078 68076 68076 68429 68431 68765 68079 68077 68077 68419 68765 68077 68078 68419 68431 68419 68078 68414 68413 68079 68765 68414 68079 68779 68444 68080 68080 68091 68779 68775 68082 68081 69099 68775 68081 68081 68445 69099 68081 68437 68445 68775 68774 68082 68778 68776 68082 69114 68778 68082 69462 69114 68082 68082 68774 69462 68457 68446 68083 68783 68457 68083 68784 68783 68083 68083 68439 68784 68095 68094 68084 68100 68095 68084 68084 68085 68100 68446 68100 68085 68086 68443 68450 68086 68442 68443 68087 68089 68091 68090 68089 68087 68087 68088 68090 68451 68090 68088 68088 68443 68451 68450 68443 68088 68779 68091 68089 68780 68779 68089 68787 68780 68089 68089 68090 68787 68090 68451 68787 68459 68454 68092 68092 68456 68459 68092 68093 68456 68093 68455 68456 68474 68461 68094 68094 68457 68474 68094 68095 68457 68095 68100 68446 68095 68446 68457 68098 68097 68096 68099 68098 68096 68460 68103 68097 68097 68098 68460 68098 68099 68460 68464 68460 68099 68101 68462 68470 68101 68102 68462 68463 68462 68102 68102 68103 68463 68464 68463 68103 68103 68460 68464 68109 68106 68104 68104 68108 68109 68475 68108 68104 68789 68477 68105 68105 68489 68789 68105 68109 68489 68105 68106 68109 68479 68478 68107 68107 68470 68479 68825 68109 68108 69142 68825 68108 69147 69142 68108 68108 68827 69147 68108 68475 68827 68817 68489 68109 68818 68817 68109 68825 68818 68109 68496 68111 68110 68110 68488 68496 68110 68112 68488 68116 68115 68111 68495 68116 68111 68496 68495 68111 68112 68113 68488 68113 68487 68488 68799 68487 68113 68113 68461 68799 68114 68120 68820 68494 68120 68114 68116 68495 68498 68841 68510 68117 68117 68839 68841 68117 68499 68839 68117 68118 68499 68507 68124 68119 68512 68507 68119 68821 68820 68120 68120 68121 68821 68122 68121 68120 69483 68821 68121 68121 69482 69483 68121 69155 69482 68121 68122 69155 69156 69155 68122 68122 68503 69156 68122 68125 68503 68827 68497 68123 68123 68506 68827 68123 68130 68506 68508 68503 68125 68126 68842 68847 68126 68132 68842 68126 68127 68132 68847 68508 68126 68504 68500 68128 68505 68504 68128 68128 68129 68505 68130 68135 68506 68131 68507 68513 68843 68842 68132 68844 68843 68132 68132 68133 68844 69162 68844 68133 68133 68845 69162 68133 68840 68845 68133 68500 68840 68133 68134 68500 68135 68136 68514 68514 68506 68135 68136 68137 68514 68137 68138 68515 68515 68514 68137 68144 68140 68139 68521 68144 68139 68139 68520 68521 68144 68141 68140 68141 68144 68149 68519 68143 68142 68519 68517 68143 68521 68146 68144 68523 68148 68146 68146 68521 68523 68528 68524 68148 68148 68522 68528 68523 68522 68148 68526 68519 68150 68150 68525 68526 68152 68153 68154 68157 68154 68153 68156 68155 68154 68159 68156 68154 68154 68158 68159 68154 68157 68158 68156 68160 68162 68156 68159 68160 68161 68160 68159 68160 68161 68162 68163 68162 68161 68165 68163 68161 68529 68165 68161 68531 68166 68163 68163 68165 68531 68164 68167 68168 68873 68531 68165 68165 68870 68873 68165 68529 68870 68531 68169 68166 68532 68168 68167 68535 68532 68167 68167 68171 68535 68872 68871 68168 68168 68533 68872 68168 68532 68533 69176 68173 68169 68169 68876 69176 68169 68531 68876 68174 68171 68170 68536 68535 68171 68171 68174 68536 68176 68175 68172 68537 68176 68172 68172 68173 68537 68538 68537 68173 69176 68538 68173 68179 68178 68177 68543 68179 68177 68179 68543 68550 68552 68546 68180 68879 68552 68180 68180 68545 68879 68187 68186 68181 68181 68182 68187 69182 68187 68182 68182 69181 69182 68182 68188 69181 68880 68185 68184 68184 68547 68880 68550 68547 68184 68880 68195 68185 68186 68534 68536 68186 68187 68534 69182 68534 68187 68188 68882 69181 68188 68881 68882 68188 68190 68881 68553 68190 68188 68189 68190 68553 68887 68881 68190 68890 68887 68190 68190 68199 68890 68191 68192 68555 68192 68554 68555 68877 68554 68192 68192 68551 68877 68193 68203 68556 68558 68557 68195 68559 68558 68195 68880 68559 68195 68563 68206 68196 68196 68557 68563 68201 68198 68197 68890 68199 68198 68198 68200 68890 68201 68200 68198 68898 68897 68200 68200 68208 68898 68200 68201 68208 69507 68890 68200 68200 68897 69507 68201 68207 68208 68560 68203 68202 68562 68556 68203 68203 68561 68562 68203 68560 68561 69195 69194 68204 69198 69195 68204 68204 68907 69198 68204 68568 68907 68204 68205 68568 68895 68560 68204 69194 68895 68204 68569 68568 68205 68563 68213 68206 68209 68208 68207 68223 68209 68207 68207 68222 68223 68210 68893 68899 68210 68555 68893 68211 68212 68214 68571 68214 68212 68572 68571 68212 68212 68567 68572 68216 68215 68213 68566 68216 68213 68213 68563 68566 68574 68221 68215 68215 68216 68574 68216 68573 68574 68216 68564 68573 68566 68564 68216 68909 68227 68217 68217 68570 68909 68217 68218 68570 68905 68570 68218 68906 68905 68218 68218 68904 68906 68218 68225 68904 68219 68911 68912 68912 68220 68219 68908 68569 68220 68912 68908 68220 68235 68228 68221 68574 68235 68221 68224 68223 68222 68223 68224 68575 68576 68575 68224 68224 68232 68576 68224 68231 68232 68225 68571 68904 68580 68237 68226 68226 68577 68580 68226 68227 68577 68915 68577 68227 68227 68909 68915 68581 68240 68228 68228 68229 68581 68230 68229 68228 68235 68230 68228 68922 68581 68229 68229 68230 68922 68230 68235 68922 68917 68576 68232 68232 68233 68917 68234 68233 68232 68579 68234 68232 69534 68917 68233 68233 68582 69534 68233 68234 68582 68926 68582 68234 68234 68925 68926 68234 68587 68925 68234 68578 68587 68579 68578 68234 68235 68573 68922 68574 68573 68235 68580 68241 68237 68581 68242 68240 68580 68247 68241 68586 68585 68242 68242 68581 68586 68587 68245 68244 68925 68587 68244 68244 68590 68925 68591 68590 68244 68587 68246 68245 68580 68248 68247 69530 68927 68248 68248 68918 69530 68248 68580 68918 68249 68251 68595 68249 68250 68251 68613 68251 68250 68250 68599 68613 68250 68253 68599 68935 68595 68251 68251 68613 68935 68253 68266 68599 68268 68267 68254 68254 68255 68268 68609 68268 68255 69258 68609 68255 68255 69248 69258 68255 68938 69248 68255 68597 68938 68256 68265 68598 68258 68937 68946 68261 68260 68259 68270 68261 68259 68259 68269 68270 68260 68261 68263 68263 68262 68260 68261 68270 68610 68610 68263 68261 68610 68264 68263 68615 68271 68264 68616 68615 68264 68264 68610 68616 68934 68598 68265 68942 68934 68265 68265 68600 68942 68601 68600 68265 68952 68601 68265 68607 68599 68266 68951 68607 68266 68266 68614 68951 68266 68608 68614 68951 68614 68267 68267 68609 68951 68267 68268 68609 68614 68608 68267 68289 68270 68269 68270 68289 68610 68615 68277 68271 68611 68273 68272 68272 68278 68611 68273 68602 68603 68611 68602 68273 68274 68606 68955 68274 68276 68606 68280 68275 68274 68957 68280 68274 68274 68955 68957 68961 68643 68275 68275 68280 68961 68621 68281 68277 68277 68616 68621 68277 68615 68616 68278 68604 68611 68612 68604 68278 68617 68612 68278 68632 68618 68279 69273 68961 68280 68280 68958 69273 68280 68957 68958 68281 68621 68638 69814 69813 68282 68282 69268 69814 68282 68283 69268 68284 68283 68282 68617 68284 68282 69270 68617 68282 69812 69270 68282 69813 69812 68282 68283 69267 69268 68283 68284 69267 68284 68633 69267 68284 68618 68633 68284 68617 68618 68627 68295 68285 68285 68626 68627 68285 68288 68626 68285 68286 68288 68625 68288 68286 68286 68287 68625 68287 68624 68625 68288 68628 68629 69561 68628 68288 68288 69275 69561 68288 68625 69275 68629 68626 68288 68619 68610 68289 68296 68291 68290 68643 68296 68290 68294 68292 68291 68296 68294 68291 68294 68293 68292 68623 68622 68293 68962 68623 68293 68293 68634 68962 68293 68294 68634 68294 68296 68634 68635 68299 68295 68295 68627 68635 68296 68297 68634 68298 68297 68296 68644 68298 68296 68296 68643 68644 69297 68634 68297 68297 69295 69297 68297 68298 69295 68298 68972 69295 68298 68644 68972 68301 68300 68299 68303 68301 68299 68635 68303 68299 68300 68301 68302 68303 68302 68301 68646 68306 68302 68302 68645 68646 68302 68303 68645 68649 68645 68303 69281 68649 68303 68303 68628 69281 68629 68628 68303 68635 68629 68303 68631 68630 68304 68638 68631 68304 68304 68316 68638 68975 68316 68304 68638 68316 68305 68314 68309 68306 68977 68314 68306 68306 68646 68977 68307 68315 68653 68308 68656 68976 68657 68656 68308 68658 68657 68308 68314 68313 68309 68310 68311 68659 68312 68311 68310 68986 68659 68311 68311 68666 68986 68311 68328 68666 68311 68312 68328 68313 68314 68319 68985 68319 68314 68314 68982 68985 68314 68977 68982 68315 68320 68653 68975 68973 68316 68998 68668 68318 69317 68998 68318 68318 68660 69317 68984 68320 68319 68985 68984 68319 68320 68637 68653 68984 68637 68320 68663 68324 68321 68992 68663 68321 68987 68323 68322 68322 68661 68987 68987 68660 68323 68667 68330 68324 68324 68663 68667 68325 68665 68996 68325 68664 68665 68995 68664 68326 68326 68337 68995 68326 68336 68337 68997 68328 68327 68997 68666 68328 68671 68331 68329 68329 68669 68671 68329 68668 68669 68667 68334 68330 68332 68333 68661 69006 68661 68333 68333 68335 69006 68670 68343 68334 68334 68667 68670 69331 69006 68335 68335 69005 69331 68335 68351 69005 69007 68351 68335 68335 68339 69007 68675 68337 68336 68336 68346 68675 68336 68338 68346 69001 68995 68337 68337 68675 69001 68339 68350 69007 68679 68678 68341 69010 68679 68341 68341 68342 69010 69336 69010 68342 69338 69336 68342 68342 68673 69338 68343 68670 68672 68357 68353 68344 68344 68345 68357 68701 68675 68346 68346 68358 68701 68671 68354 68347 68348 68355 68681 68350 68351 69007 68352 68351 68350 68677 68352 68350 68678 68677 68350 68351 68352 69005 69612 69005 68352 68352 69008 69612 68352 68677 69008 68671 68359 68354 69011 68681 68355 68355 68695 69011 68355 68361 68695 68363 68362 68356 68684 68363 68356 68358 68364 68701 68694 68360 68359 69017 68694 68359 68359 68671 69017 68360 68367 68371 68370 68367 68360 68694 68370 68360 68361 68372 68695 68696 68373 68362 68362 68363 68696 68363 68682 68696 68683 68682 68363 68684 68683 68363 68381 68376 68366 68690 68381 68366 68370 68369 68367 68369 68370 68693 68370 68694 69021 69349 68693 68370 69354 69349 68370 68370 69021 69354 68372 68377 68695 68713 68385 68374 69019 68687 68375 68381 68380 68376 69023 68695 68377 68377 68721 69023 68377 68388 68721 68378 68712 68723 68378 68390 68712 68378 68379 68390 68702 68390 68379 68384 68382 68380 68707 68384 68380 68380 68704 68707 68380 68381 68704 68381 68690 68704 68382 68384 69034 69034 68383 68382 69029 68708 68383 69034 69029 68383 68384 68706 69043 68707 68706 68384 69043 69034 68384 68385 68713 69025 68385 69018 69019 69026 69018 68385 68385 69025 69026 68715 68700 68386 68387 68709 68718 68388 68389 68721 68722 68721 68389 69024 68712 68390 68390 68702 69024 68394 68393 68392 68396 68394 68392 69057 68716 68393 68393 68394 69057 69058 69057 68394 69071 69058 68394 68394 69070 69071 68394 68395 69070 68396 68395 68394 68395 68396 68407 68395 68736 69070 68398 69059 69067 68400 68404 68408 68745 68401 68400 68400 68744 68745 68400 68409 68744 68400 68408 68409 69397 69059 68401 68401 68745 69397 68402 68754 69076 68402 68743 68754 68402 68403 68743 68747 68737 68405 68405 68406 68747 68406 68738 68747 68409 68410 68744 68411 68410 68409 69077 68744 68410 69080 69077 68410 69425 69080 68410 68410 68758 69425 68759 68758 68410 68410 68411 68759 68411 68412 68759 68412 68418 68759 68761 68743 68414 68765 68761 68414 68415 68762 69433 68763 68762 68415 68415 68416 68763 68417 68416 68415 69433 68417 68415 69444 69093 68416 69693 69444 68416 68416 68417 69693 69093 68763 68416 68417 69690 69693 69691 69690 68417 68417 69433 69691 68418 68758 68759 69088 68758 68418 68418 69087 69088 68773 68765 68419 68419 68772 68773 68419 68771 68772 68419 68431 68771 68763 68421 68420 68420 68762 68763 68769 68434 68421 68421 68763 68769 68422 68425 68766 69688 68425 68422 68422 68423 69688 68424 68423 68422 68766 68424 68422 69928 69688 68423 68423 68424 69928 70167 69928 68424 68424 69698 70167 68424 68766 69698 69434 68426 68425 69688 69434 68425 69434 69087 68426 68768 68766 68427 68427 68428 68768 68428 68764 68768 68771 68431 68429 68429 68430 68771 69095 68442 68432 68432 68434 69095 69445 69094 68433 68433 69100 69445 68433 69097 69100 68433 68436 69097 68433 68435 68436 68434 68763 69095 68769 68763 68434 68436 68448 69097 68436 68447 68448 68782 68440 68438 68439 68440 68784 69104 68784 68440 68440 68782 69104 69098 68443 68442 68442 69096 69098 68442 69095 69096 68785 68451 68443 69098 68785 68443 68788 68445 68444 68444 68779 68788 68445 68788 69099 68449 68448 68447 68453 68449 68447 69101 69097 68448 69103 69101 68448 68448 68449 69103 68453 68452 68449 69106 69103 68449 68449 68452 69106 68451 68780 68787 68785 68780 68451 68452 68458 69106 69129 68786 68454 68454 68789 69129 68790 68789 68454 68454 68459 68790 68476 68459 68456 68800 68474 68457 68457 68783 68800 68458 68786 69106 68459 68476 68790 68461 68798 68799 68461 68474 68798 68480 68470 68462 68462 68463 68480 68801 68480 68463 68463 68464 68801 68464 68481 68801 68467 68466 68465 68471 68467 68465 68472 68471 68465 68805 68472 68465 68465 68468 68805 68465 68466 68468 68466 68467 68469 68807 68468 68466 68466 68469 68807 68471 68469 68467 69133 68805 68468 68468 68806 69133 68807 68806 68468 68469 68471 68796 68469 68791 68807 68796 68791 68469 68826 68479 68470 68470 68480 68826 68471 68795 68796 68471 68486 68795 68471 68473 68486 68471 68472 68473 68483 68473 68472 68484 68483 68472 68805 68484 68472 68491 68486 68473 68473 68483 68491 68800 68798 68474 68475 68497 68827 68476 68789 68790 68476 68477 68789 68478 68479 68490 68826 68490 68479 68480 68814 68826 68815 68814 68480 68480 68809 68815 68480 68802 68809 68480 68801 68802 68803 68801 68481 68804 68803 68481 68481 68482 68804 68483 68485 68491 68483 68484 68485 68810 68485 68484 68484 68805 68810 68492 68491 68485 68810 68492 68485 68812 68795 68486 68486 68509 68812 68486 68491 68509 68816 68488 68487 69141 68816 68487 68487 68797 69141 68799 68797 68487 68816 68496 68488 68808 68789 68489 68817 68808 68489 69153 68831 68490 68490 69148 69153 68490 68826 69148 68491 68493 68509 68491 68492 68493 69145 68493 68492 68492 69140 69145 68492 68810 69140 68832 68509 68493 68837 68832 68493 69145 68837 68493 68502 68501 68495 68495 68496 68502 68501 68498 68495 68496 68816 68822 68822 68502 68496 68509 68505 68498 68498 68501 68509 69154 68839 68499 68499 68830 69154 68831 68830 68499 68500 68838 68840 68500 68504 68838 68501 68502 68823 68812 68509 68501 68823 68812 68501 68502 68822 68823 69157 69156 68503 68503 68847 69157 68503 68508 68847 68504 68832 68838 68504 68509 68832 68504 68505 68509 68833 68827 68506 68506 68516 68833 68506 68514 68516 68507 68512 68513 68846 68515 68510 68510 68841 68846 68513 68512 68511 68514 68515 68516 68846 68516 68515 68516 68829 68833 69165 68829 68516 68516 68848 69165 68516 68846 68848 68857 68852 68517 68517 68519 68857 68856 68520 68518 68518 68855 68856 68518 68851 68855 68860 68857 68519 68519 68526 68860 68523 68521 68520 68520 68522 68523 68856 68522 68520 68856 68528 68522 68524 68854 68866 68855 68854 68524 68524 68528 68855 68864 68863 68525 68525 68527 68864 68863 68526 68525 68863 68860 68526 68865 68864 68527 68856 68855 68528 68529 68530 68870 68530 68868 68870 68530 68867 68868 68531 68875 68876 68531 68873 68875 68535 68533 68532 69168 68872 68533 69170 69168 68533 69172 69170 68533 68533 68534 69172 68535 68534 68533 68534 68535 68536 69182 69172 68534 68537 68540 68551 68537 68539 68540 68537 68538 68539 69178 68539 68538 68538 69176 69178 68541 68540 68539 68542 68541 68539 69178 68542 68539 68877 68551 68540 68884 68877 68540 68540 68541 68884 69184 68884 68541 68541 68542 69184 69498 69184 68542 69499 69498 68542 68542 69183 69499 68542 69178 69183 68543 68546 68550 68878 68545 68544 68545 68878 68879 68552 68550 68546 68886 68880 68547 68547 68548 68886 68549 68548 68547 68552 68549 68547 68547 68550 68552 68548 68559 68886 69189 68559 68548 68548 69186 69189 68548 68549 69186 68549 68879 69186 68549 68552 68879 68894 68555 68554 68554 68891 68894 68554 68877 68891 68894 68893 68555 68885 68878 68556 68556 68562 68885 68900 68563 68557 68557 68558 68900 68903 68900 68558 69508 68903 68558 68558 69193 69508 68558 68559 69193 68559 68880 68886 68559 69189 69193 68895 68561 68560 68892 68562 68561 68895 68892 68561 68892 68885 68562 68900 68566 68563 68923 68573 68564 68564 68913 68923 68564 68565 68913 68566 68565 68564 68914 68913 68565 69205 68914 68565 68565 68566 69205 68566 68900 69205 69201 68572 68567 68567 68899 69201 68908 68907 68568 68568 68569 68908 69222 68909 68570 69521 69222 68570 68570 68905 69521 69206 68904 68571 68571 68572 69206 69207 69206 68572 68572 69201 69207 68923 68922 68573 68575 68576 69217 68576 69216 69217 68576 68917 69216 68918 68580 68577 68919 68918 68577 68577 68915 68919 68578 68583 68587 68578 68579 68583 68924 68586 68581 68581 68922 68924 70028 69534 68582 68582 69232 70028 68582 68926 69232 69542 68592 68585 68585 69538 69542 69539 69538 68585 68585 69536 69539 68585 68586 69536 68586 69231 69536 68586 68924 69231 68592 68589 68588 68938 68596 68589 68589 68592 68938 68590 68591 68593 68926 68925 68590 69233 68926 68590 68590 68594 69233 68590 68593 68594 69248 68938 68592 69542 69248 68592 68934 68594 68593 68593 68598 68934 69544 69232 68594 68594 69242 69544 68594 68933 69242 68934 68933 68594 68594 69232 69233 69229 68916 68595 69230 69229 68595 68595 68935 69230 68938 68597 68596 68599 68607 68613 69261 68942 68600 68600 69260 69261 68600 68952 69260 68600 68601 68952 68602 68605 68943 68602 68604 68605 68611 68604 68602 68943 68603 68602 68954 68952 68603 68603 68943 68954 68939 68605 68604 68604 68612 68939 68605 68940 68943 68605 68939 68940 68956 68955 68606 68606 68950 68956 68606 68947 68950 68948 68613 68607 69256 68948 68607 68607 68951 69256 69258 68951 68609 68620 68616 68610 68610 68619 68620 68945 68939 68612 69266 68945 68612 68612 69265 69266 68612 68617 69265 68948 68935 68613 68631 68621 68616 68616 68620 68631 69270 69265 68617 68618 68632 68633 68621 68631 68638 68622 68623 68624 68962 68624 68623 69275 68625 68624 68624 68963 69275 68624 68962 68963 68629 68627 68626 68627 68629 68635 68628 68964 69281 68965 68964 68628 69561 68965 68628 68642 68633 68632 69286 69267 68633 68633 68642 69286 69287 68962 68634 69289 69287 68634 69569 69289 68634 68634 69297 69569 69302 68651 68636 68636 68637 69302 68636 68651 68652 68637 69301 69302 68637 68988 69301 68637 68984 68988 68641 68640 68639 68648 68641 68639 68640 68967 69279 68640 68966 68967 68640 68641 68966 68641 68647 68966 68648 68647 68641 68642 69285 69286 68971 68644 68643 68643 68961 68971 68644 68971 68972 68649 68646 68645 69298 68977 68646 69299 69298 68646 68646 68649 69299 69578 68966 68647 68647 69577 69578 68647 69576 69577 68647 69300 69576 68647 68979 69300 68649 69281 69299 68978 68974 68650 68650 68655 68978 68650 68651 68655 68652 68651 68650 68974 68652 68650 69302 68655 68651 68652 68973 68975 68974 68973 68652 69301 68992 68654 69302 69301 68654 68654 68655 69302 68655 68974 68978 68656 68657 68980 68979 68976 68656 69300 68979 68656 68656 68980 69300 69306 69305 68659 68659 68986 69306 68660 68987 69317 68989 68987 68661 69310 68989 68661 68661 69006 69310 68674 68667 68663 68999 68674 68663 68663 68992 68999 68995 68665 68664 69598 68996 68665 69852 69598 68665 69853 69852 68665 68665 68993 69853 68995 68993 68665 68997 68986 68666 68674 68670 68667 69000 68669 68668 69315 69000 68668 68668 68998 69315 68676 68671 68669 69000 68676 68669 68673 68672 68670 68674 68673 68670 69341 69017 68671 68671 68676 69341 69339 69338 68673 68673 69332 69339 69333 69332 68673 68673 68674 69333 68674 68999 69333 68675 68701 69001 69342 69341 68676 68676 69334 69342 68676 69003 69334 68676 69000 69003 69613 69008 68677 68677 69335 69613 68677 69009 69335 68677 68678 69009 68678 68679 69009 69336 69009 68679 68679 69010 69336 68680 68687 68688 69014 68684 68681 69343 69014 68681 68681 69011 69343 68697 68696 68682 69015 68697 68682 69344 69015 68682 68682 68683 69344 68683 68685 69344 68683 68684 68685 69014 68686 68684 68686 68685 68684 69620 69344 68685 68685 68686 69620 68686 69014 69620 68689 69016 69020 69020 68690 68689 68705 68704 68690 69020 68705 68690 68691 68692 70111 68693 68692 68691 70106 69622 68691 70111 70106 68691 68692 69349 69350 68692 68693 69349 68692 69350 70111 69352 69351 68694 68694 69017 69352 69351 69021 68694 69023 69013 68695 69013 69011 68695 68696 68697 69022 69355 69022 68697 68697 69015 69355 70539 69627 68698 70768 70539 68698 68698 68699 70768 68700 68699 68698 68699 70338 70768 68699 68700 70338 70339 70338 68700 68700 68715 70339 69611 69001 68701 69867 69611 68701 70312 69867 68701 70319 70312 68701 70323 70319 68701 68701 69627 70323 69371 69024 68702 68702 69360 69371 68702 68703 69360 68703 69022 69360 68717 68707 68704 68704 68705 68717 69028 68717 68705 68705 69020 69028 68706 69041 69042 68706 68717 69041 68706 68707 68717 68706 69042 69043 69029 68711 68708 68709 68710 68718 68711 68710 68709 69363 68718 68710 68710 69037 69363 68710 68711 69037 68711 69035 69037 68711 69029 69035 69033 68723 68712 68712 69024 69033 68713 68724 69025 68714 69026 69372 68714 69018 69026 68715 69656 70339 68715 68716 69656 68716 69058 69656 68716 69057 69058 68717 69028 69041 69362 69361 68718 69363 69362 68718 68719 68720 69384 68720 69364 69384 69375 69364 68720 68720 69361 69375 69030 69023 68721 68721 68722 69030 69048 69030 68722 69053 69048 68722 68722 68732 69053 68722 68726 68732 69025 68724 68723 69033 69025 68723 68732 68726 68725 69055 68732 68725 68725 69045 69055 69069 69068 68727 69073 69069 68727 68727 69062 69073 68727 68728 69062 68729 68728 68727 69068 68729 68727 68728 69056 69062 68728 68733 69056 68728 68731 68733 68728 68730 68731 68728 68729 68730 68735 68730 68729 69038 68735 68729 69040 69038 68729 69054 69040 68729 69064 69054 68729 68729 69063 69064 69068 69063 68729 68733 68731 68730 68735 68733 68730 69055 69053 68732 69394 69056 68733 68733 69393 69394 68733 69050 69393 68733 68734 69050 68735 68734 68733 68734 69049 69050 69051 69049 68734 68734 68735 69051 68735 69038 69051 68736 68748 68749 69407 69070 68736 69673 69407 68736 68736 69428 69673 69429 69428 68736 68736 69085 69429 68736 68749 69085 69075 68741 68737 68737 69074 69075 68737 68747 69074 69074 68747 68738 69406 69074 68738 68738 68739 69406 68739 69404 69406 68739 68740 69404 69644 69404 68740 68740 69401 69644 69075 68746 68741 69421 68751 68742 68742 69415 69421 68755 68754 68743 68761 68755 68743 69402 68745 68744 68744 69077 69402 68745 69402 69661 69413 69397 68745 69661 69413 68745 68746 69078 69079 68746 69075 69078 69086 68752 68750 69667 69086 68750 68750 69431 69667 68750 69421 69431 68750 68751 69421 69086 68753 68752 69086 69085 68753 68754 68757 69076 68754 68756 68757 68754 68755 68756 68761 68756 68755 69082 68757 68756 69683 69082 68756 68756 68761 69683 69411 69076 68757 68757 69083 69411 68757 69082 69083 68758 69088 69425 69090 68764 68760 68761 68765 68773 68761 69091 69683 69092 69091 68761 68761 68773 69092 68762 69422 69433 69423 69422 68762 68762 69084 69423 68763 69093 69095 69089 68768 68764 69435 69089 68764 68764 69090 69435 68766 69089 69435 68766 68767 69089 68768 68767 68766 68766 69696 69698 69697 69696 68766 68766 69669 69697 69672 69669 68766 68766 69435 69672 68767 68768 69089 68770 69094 69445 69092 68773 68772 69700 69092 68772 69937 69700 68772 68774 68775 69463 68774 69113 69462 69463 69113 68774 68775 69461 69463 68775 69099 69461 69117 69116 68777 69124 69117 68777 68777 68778 69124 69116 68781 68777 68778 69114 69124 68779 68780 68788 69111 68788 68780 69470 69111 68780 68780 69108 69470 68780 68785 69108 69116 69102 68781 69128 69104 68782 68782 69125 69128 68782 69119 69125 68782 69102 69119 69105 68800 68783 68783 69104 69105 68783 68784 69104 69109 69108 68785 68785 69098 69109 69121 69106 68786 69476 69121 68786 68786 69129 69476 69469 69099 68788 68788 69111 69469 69135 69129 68789 69143 69135 68789 68789 68808 69143 68791 68794 68807 68791 68792 68794 68793 68792 68791 68796 68793 68791 68792 69117 69124 68792 68813 69117 68792 68793 68813 69123 68794 68792 69124 69123 68792 68793 68795 68813 68796 68795 68793 69122 68807 68794 69123 69122 68794 68795 68812 68813 68797 68798 69126 68799 68798 68797 68797 69134 69141 68797 69126 69134 68798 68800 69105 68798 69105 69126 68803 68802 68801 68802 68803 68809 69137 68809 68803 68803 68804 69137 68804 69136 69137 68811 68810 68805 69133 68811 68805 69473 69472 68806 68806 69122 69473 68806 68807 69122 68806 69130 69133 69472 69130 68806 68808 68817 69143 69477 68815 68809 68809 69137 69477 68810 68811 69140 68811 69131 69140 68811 69130 69131 69133 69130 68811 68823 68813 68812 69134 69120 68813 69141 69134 68813 68813 68822 69141 68823 68822 68813 69118 69117 68813 69120 69118 68813 69148 68826 68814 68814 68819 69148 68814 68815 68819 69149 68819 68815 69477 69149 68815 68824 68822 68816 69141 68824 68816 68817 68818 69143 68818 69142 69143 68818 68825 69142 69149 69148 68819 69150 69139 68820 69151 69150 68820 68820 68821 69151 69483 69151 68821 68822 68824 69141 69152 69147 68827 68827 68828 69152 68829 68828 68827 68833 68829 68827 68828 68829 69490 69484 69152 68828 69751 69484 68828 68828 69490 69751 69493 69490 68829 68829 69165 69493 68830 68831 69153 68830 68836 69154 69486 68836 68830 68830 69153 69486 68840 68838 68832 68832 68837 68840 68836 68835 68834 69154 68836 68834 68834 68839 69154 68841 68839 68834 68848 68841 68834 69158 68848 68834 69159 69158 68834 68834 68835 69159 68835 68836 69486 69999 69159 68835 70000 69999 68835 68835 69486 70000 68845 68840 68837 69488 68845 68837 69747 69488 68837 68837 69489 69747 68837 69145 69489 68848 68846 68841 68842 68843 69163 69163 68847 68842 68843 68844 69162 68843 69162 69163 69488 69162 68845 69160 69157 68847 69164 69160 68847 68847 69163 69164 68848 68849 69165 68850 68849 68848 69158 68850 68848 69494 69165 68849 69753 69494 68849 69757 69753 68849 68849 69756 69757 68849 68850 69756 69758 69756 68850 68850 69158 69758 68851 68854 68855 68851 68853 68854 68852 68857 68860 68861 68858 68852 68852 68860 68861 68866 68854 68853 68853 68865 68866 68853 68858 68865 68859 68858 68853 68858 68864 68865 68858 68862 68864 68858 68861 68862 68863 68861 68860 68863 68862 68861 68862 68863 68864 68871 68869 68867 68869 68868 68867 68868 68869 68870 68874 68870 68869 68869 68871 68874 68874 68873 68870 69166 68874 68871 69167 69166 68871 68871 68872 69167 69168 69167 68872 68873 68874 68875 69169 68875 68874 68874 69166 69169 69169 68876 68875 68876 69174 69176 69175 69174 68876 68876 69169 69175 68877 68888 68891 68889 68888 68877 68877 68884 68889 69187 68879 68878 69188 69187 68878 68878 68885 69188 69191 69186 68879 68879 69187 69191 68883 68882 68881 68887 68883 68881 68882 68883 69181 69502 69497 68883 68883 69501 69502 68883 69185 69501 68883 68887 69185 69497 69181 68883 69498 68889 68884 68884 69184 69498 68885 68896 69188 68885 68892 68896 68887 68890 69185 69503 68891 68888 69504 69503 68888 68888 68889 69504 70008 69504 68889 68889 69499 70008 68889 69498 69499 69507 69185 68890 69197 68901 68891 69503 69197 68891 68891 68893 68894 68901 68893 68891 68892 68895 68896 68901 68899 68893 69194 68896 68895 69194 69188 68896 68897 69511 69765 68897 68898 69511 69765 69507 68897 69202 69201 68899 68899 68901 69202 68900 68902 69205 68903 68902 68900 68901 69197 69202 69210 69205 68902 68902 69209 69210 69508 69209 68902 68902 68903 69508 69206 68906 68904 68905 68906 69521 68906 69214 69521 68906 69206 69214 69203 69198 68907 68907 68908 69203 69208 69203 68908 68908 68912 69208 69222 68915 68909 69208 68912 68910 69215 69208 68910 69218 69215 68910 68910 68911 69218 68912 68911 68910 69223 69218 68911 69224 69223 68911 69219 68921 68913 68913 68914 69219 68913 68920 68923 68921 68920 68913 69220 69219 68914 68914 69211 69220 68914 69205 69211 69226 68919 68915 68915 69221 69226 69222 69221 68915 69229 69227 68916 69777 69216 68917 68917 69534 69777 68918 69226 69530 68918 68919 69226 69533 69231 68920 68920 69528 69533 68920 68921 69528 68920 68922 68923 68924 68922 68920 69231 68924 68920 68921 69219 69528 69233 69232 68926 69240 68936 68927 68927 68928 69240 68929 68928 68927 69537 68929 68927 68927 69530 69537 69254 69240 68928 69797 69254 68928 68928 69540 69797 68928 68929 69540 69788 69540 68929 68929 69785 69788 68929 69537 69785 68930 69225 69228 68930 68931 69225 68932 68931 68930 69229 68932 68930 68930 69227 69229 68930 69224 69227 69228 69224 68930 69528 69225 68931 69529 69528 68931 68931 68932 69529 69787 69529 68932 68932 69234 69787 68932 69230 69234 68932 69229 69230 69548 69242 68933 68933 68949 69548 68933 68942 68949 68933 68934 68942 69236 69230 68935 69247 69236 68935 68935 69241 69247 68935 68948 69241 69240 68937 68936 69246 68946 68937 68937 69240 69246 68941 68940 68939 68945 68941 68939 68944 68943 68940 68940 68941 68944 69244 68944 68941 69245 69244 68941 69251 69245 68941 68941 68945 69251 69261 68949 68942 68943 68953 68954 69545 68953 68943 68943 69243 69545 68943 68944 69243 69244 69243 68944 69266 69251 68945 69246 68947 68946 69255 68950 68947 68947 69246 69255 69256 69241 68948 69805 69548 68949 69806 69805 68949 68949 69261 69806 68959 68956 68950 69255 68959 68950 69257 69256 68951 69258 69257 68951 69263 69260 68952 68952 68954 69263 70034 69249 68953 68953 69803 70034 68953 69546 69803 68953 69545 69546 69249 68954 68953 69558 69263 68954 68954 69250 69558 68954 69249 69250 68955 68956 68959 68958 68957 68955 68959 68958 68955 68958 68959 69560 69560 69273 68958 69804 69560 68959 68959 69551 69804 68959 69255 69551 68969 68968 68960 69284 68969 68960 68960 69279 69284 69271 68971 68961 69273 69271 68961 69280 68963 68962 69287 69280 68962 69278 69275 68963 69280 69278 68963 69292 69281 68964 69832 69292 68964 68964 68965 69832 68965 69819 69832 68965 69276 69819 69561 69276 68965 69565 68967 68966 69578 69565 68966 69563 69279 68967 69565 69563 68967 68968 68969 69282 69570 69282 68969 68969 69566 69570 68969 69284 69566 69568 69288 68970 68970 68971 69568 68972 68971 68970 69288 68972 68970 68971 69274 69568 68971 69271 69274 68972 69288 69295 68983 68982 68977 69298 68983 68977 69580 69300 68980 69584 69580 68980 68980 69583 69584 68980 68981 69583 69585 69583 68981 68981 69303 69585 68982 69318 69319 69321 69318 68982 69596 69321 68982 68982 68983 69596 69319 68985 68982 70089 69596 68983 70090 70089 68983 68983 69298 70090 69319 68988 68984 68984 68985 69319 69325 69306 68986 68986 68997 69325 68987 69308 69317 69309 69308 68987 68987 68989 69309 69323 69301 68988 68988 69322 69323 68988 69319 69322 68989 68990 69309 68991 68990 68989 69314 68991 68989 68989 69310 69314 69588 69309 68990 69847 69588 68990 68990 69846 69847 68990 68991 69846 68991 69314 69593 68991 69311 69846 69593 69311 68991 69304 68999 68992 68992 69301 69304 68993 68994 69853 68995 68994 68993 68994 69606 69853 68994 69002 69606 68994 68995 69002 68995 69001 69002 69599 69324 68996 68996 69598 69599 69326 69325 68997 68997 69324 69326 69317 69315 68998 68999 69332 69333 68999 69323 69332 69597 69323 68999 68999 69304 69597 69004 69003 69000 69316 69004 69000 69000 69315 69316 69611 69002 69001 69867 69606 69002 69002 69611 69867 69618 69334 69003 69856 69618 69003 69003 69591 69856 69607 69591 69003 69608 69607 69003 69003 69004 69608 69004 69590 69608 69004 69589 69590 69004 69316 69589 69609 69331 69005 69612 69609 69005 69327 69310 69006 69602 69327 69006 69006 69331 69602 69008 69330 69612 69864 69330 69008 69008 69613 69864 69336 69335 69009 69353 69343 69011 69011 69012 69353 69013 69012 69011 69012 69628 69870 69012 69031 69628 69012 69013 69031 69870 69353 69012 69013 69023 69031 69014 69343 69620 69629 69355 69015 69015 69626 69629 69015 69344 69626 69345 69020 69016 69017 69340 69352 69341 69340 69017 69020 69027 69028 69345 69027 69020 69614 69354 69021 69021 69351 69614 69022 69355 69360 69023 69030 69031 69370 69033 69024 69371 69370 69024 69373 69026 69025 69025 69370 69373 69025 69033 69370 69373 69372 69026 69027 69356 69868 69027 69345 69356 69632 69028 69027 69868 69632 69027 69382 69041 69028 69632 69382 69028 69029 69034 69035 69032 69031 69030 69046 69032 69030 69048 69046 69030 69031 69359 69628 69031 69032 69359 69379 69359 69032 69032 69046 69379 69374 69035 69034 69034 69043 69374 69035 69036 69037 69374 69036 69035 69880 69037 69036 69036 69641 69880 69036 69391 69641 69036 69374 69391 70120 69363 69037 69037 69880 70120 69052 69049 69038 69038 69039 69052 69040 69039 69038 69038 69049 69051 69368 69052 69039 69369 69368 69039 69389 69369 69039 69039 69040 69389 69040 69387 69389 69388 69387 69040 69040 69054 69388 69382 69042 69041 69044 69043 69042 69390 69044 69042 69042 69383 69390 69042 69382 69383 69043 69044 69374 69391 69374 69044 69044 69390 69391 69399 69055 69045 69045 69378 69399 69384 69378 69045 69637 69379 69046 69046 69047 69637 69048 69047 69046 69047 69385 69637 69047 69048 69385 69386 69385 69048 69048 69053 69386 69052 69050 69049 69638 69393 69050 69050 69367 69638 69050 69052 69367 69368 69367 69052 69400 69386 69053 69053 69399 69400 69053 69055 69399 69427 69388 69054 69054 69064 69427 69056 69060 69062 69061 69060 69056 69394 69061 69056 70162 69656 69058 69058 69659 70162 69058 69071 69659 69395 69067 69059 69396 69395 69059 69398 69396 69059 69059 69397 69398 69073 69062 69060 69663 69073 69060 69664 69663 69060 69665 69664 69060 69060 69061 69665 69888 69665 69061 69061 69394 69888 69065 69064 69063 69419 69065 69063 69063 69418 69419 69063 69069 69418 69063 69068 69069 69064 69065 69427 69065 69426 69427 69672 69426 69065 69065 69419 69672 69066 69373 69644 69066 69372 69373 69644 69401 69066 69069 69073 69418 69407 69071 69070 69666 69659 69071 69071 69660 69666 69071 69407 69660 69423 69084 69072 69424 69423 69072 69674 69424 69072 69072 69412 69674 69663 69418 69073 69406 69075 69074 69405 69078 69075 69406 69405 69075 69661 69402 69077 69662 69661 69077 69077 69080 69662 69405 69403 69078 69420 69079 69078 69427 69420 69078 69078 69403 69427 69079 69420 69426 69426 69081 69079 69080 69425 69668 69668 69662 69080 69426 69090 69081 69417 69083 69082 69927 69417 69082 69082 69689 69927 69082 69683 69689 69083 69408 69411 69410 69408 69083 69083 69409 69410 69417 69409 69083 69085 69086 69667 69667 69429 69085 69434 69088 69087 69668 69425 69088 69088 69434 69668 69090 69426 69435 69689 69683 69091 69929 69689 69091 69091 69699 69929 69091 69092 69699 69700 69699 69092 69096 69095 69093 69444 69096 69093 69468 69098 69096 69711 69468 69096 69712 69711 69096 69096 69444 69712 69454 69100 69097 69456 69454 69097 69097 69101 69456 69468 69109 69098 69469 69461 69099 69454 69445 69100 69101 69103 69456 69102 69116 69119 69722 69456 69103 69103 69107 69722 69103 69106 69107 69128 69105 69104 69128 69126 69105 69734 69107 69106 69106 69731 69734 69106 69471 69731 69106 69121 69471 69107 69721 69722 69734 69721 69107 69108 69110 69470 69715 69110 69108 69108 69109 69715 69109 69711 69715 69109 69468 69711 69110 69111 69470 69112 69111 69110 69724 69112 69110 69110 69715 69724 69111 69112 69469 69716 69469 69112 69724 69716 69112 69113 69114 69462 69115 69114 69113 69717 69115 69113 69113 69463 69717 69114 69115 69124 69115 69123 69124 69474 69123 69115 69730 69474 69115 69115 69725 69730 69115 69717 69725 69116 69117 69118 69116 69118 69119 69120 69119 69118 69119 69120 69125 69134 69127 69120 69127 69125 69120 69738 69471 69121 69121 69476 69738 69474 69473 69122 69122 69123 69474 69125 69126 69128 69127 69126 69125 69126 69127 69134 69143 69142 69129 69129 69135 69143 69129 69146 69476 69129 69142 69146 69132 69131 69130 69475 69132 69130 69732 69475 69130 69130 69472 69732 69144 69140 69131 69737 69144 69131 69131 69132 69737 69980 69737 69132 69132 69475 69980 69138 69137 69136 69139 69138 69136 69137 69138 69477 69735 69477 69138 69736 69735 69138 69138 69150 69736 69138 69139 69150 69140 69144 69145 69147 69146 69142 69742 69489 69144 69144 69737 69742 69489 69145 69144 69481 69476 69146 69146 69147 69481 69147 69152 69481 69486 69153 69148 69148 69149 69486 69149 69478 69486 69149 69477 69478 69739 69736 69150 69150 69151 69739 69151 69483 69739 69743 69481 69152 69152 69485 69743 69152 69484 69485 69155 69156 69482 69156 69157 69482 69998 69482 69157 69157 69161 69998 69157 69160 69161 70002 69758 69158 69158 69999 70002 69158 69159 69999 69491 69161 69160 69492 69491 69160 69160 69162 69492 69164 69162 69160 69161 69748 69998 69161 69491 69748 69164 69163 69162 69162 69488 69492 69494 69493 69165 69166 69167 69171 69173 69169 69166 69166 69171 69173 69167 69170 69171 69167 69168 69170 69169 69173 69175 69170 69172 69180 69180 69171 69170 69495 69173 69171 69171 69179 69495 69180 69179 69171 69182 69179 69172 69172 69179 69180 69177 69175 69173 69178 69177 69173 69760 69178 69173 69173 69759 69760 69173 69495 69759 69178 69176 69174 69174 69177 69178 69174 69175 69177 69760 69183 69178 69182 69181 69179 69496 69495 69179 69179 69181 69496 69497 69496 69181 70007 69499 69183 69183 69760 70007 69506 69501 69185 69507 69506 69185 69190 69189 69186 69192 69190 69186 69186 69191 69192 69505 69191 69187 69187 69188 69505 69188 69195 69505 69188 69194 69195 69196 69193 69189 69189 69190 69196 69199 69196 69190 69190 69192 69199 69199 69192 69191 69505 69199 69191 69193 69196 69508 69195 69199 69505 69195 69198 69199 69196 69200 69508 69196 69199 69200 69510 69202 69197 69197 69503 69510 69200 69199 69198 69203 69200 69198 69200 69204 69508 69200 69203 69204 69201 69202 69207 69513 69207 69202 69202 69510 69513 69208 69204 69203 69204 69209 69508 69204 69208 69209 69205 69210 69211 69206 69207 69214 69207 69212 69214 69213 69212 69207 69513 69213 69207 69215 69209 69208 69514 69210 69209 69209 69215 69514 69514 69211 69210 69514 69220 69211 69520 69214 69212 69770 69520 69212 69212 69213 69770 69213 69513 69770 69214 69520 69521 69215 69218 69514 69524 69217 69216 69774 69524 69216 69777 69774 69216 69522 69512 69217 69524 69522 69217 69218 69220 69514 69225 69220 69218 69218 69223 69225 69219 69225 69528 69219 69220 69225 69535 69226 69221 69783 69535 69221 69221 69517 69783 69221 69222 69517 69521 69517 69222 69228 69225 69223 69223 69224 69228 69535 69530 69226 69236 69234 69230 69231 69533 69536 69232 69792 70025 69232 69544 69792 69232 69526 70028 70025 69526 69232 69234 69235 69539 69236 69235 69234 69234 69536 69787 69539 69536 69234 69235 69538 69539 69791 69538 69235 69235 69547 69791 69235 69247 69547 69235 69236 69247 69549 69253 69237 69237 69243 69549 69237 69238 69243 69239 69238 69237 69800 69239 69237 69237 69550 69800 69237 69253 69550 69545 69243 69238 69546 69545 69238 69799 69546 69238 69800 69799 69238 69238 69239 69800 69254 69246 69240 69257 69247 69241 69241 69256 69257 69798 69544 69242 69802 69798 69242 69242 69548 69802 69243 69244 69549 69244 69253 69549 69244 69245 69253 69245 69252 69253 69245 69251 69252 69551 69255 69246 69246 69254 69551 69247 69257 69547 69259 69258 69248 69543 69259 69248 69248 69542 69543 70034 69807 69249 69807 69250 69249 70044 69558 69250 69250 69807 70044 69266 69252 69251 69252 69266 69559 69553 69253 69252 69554 69553 69252 69559 69554 69252 69553 69550 69253 69552 69551 69254 69797 69552 69254 69257 69543 69547 69257 69259 69543 69257 69258 69259 69260 69263 69558 69262 69261 69260 69558 69262 69260 69261 69262 69806 69262 69558 69806 69264 69265 69269 69266 69265 69264 69559 69266 69264 69808 69559 69264 69811 69808 69264 69264 69269 69811 69270 69269 69265 69286 69268 69267 69286 69285 69268 69827 69814 69268 69268 69572 69827 69268 69285 69572 69269 69270 69812 70051 69811 69269 69269 70050 70051 69269 69812 70050 69271 69272 69274 69273 69272 69271 69815 69274 69272 69817 69815 69272 69272 69560 69817 69272 69273 69560 69574 69568 69274 69816 69574 69274 69274 69815 69816 69275 69276 69561 69278 69276 69275 70059 69819 69276 69276 69820 70059 69276 69277 69820 69278 69277 69276 70058 69820 69277 69277 70057 70058 69277 69818 70057 69277 69278 69818 69278 69280 69818 69566 69284 69279 69567 69566 69279 70060 69567 69279 70061 70060 69279 69279 69823 70061 69279 69564 69823 69279 69563 69564 69280 69287 69818 69575 69299 69281 69281 69292 69575 69571 69283 69282 69572 69571 69282 69282 69570 69572 69571 69285 69283 69285 69571 69572 69831 69818 69287 69287 69289 69831 69834 69295 69288 69288 69833 69834 69288 69568 69833 69289 69290 69831 69291 69290 69289 70282 69291 69289 69289 69838 70282 69289 69569 69838 70057 69831 69290 70277 70057 69290 69290 69291 70277 70708 70277 69291 69291 70493 70708 69291 70282 70493 70078 69575 69292 69292 69293 70078 69294 69293 69292 69832 69294 69292 70283 70078 69293 69293 69294 70283 69294 70066 70283 69294 70063 70066 69294 69832 70063 69295 69296 69297 69837 69296 69295 69295 69835 69837 69295 69834 69835 69569 69297 69296 70075 69569 69296 69296 70074 70075 69296 70073 70074 69296 69837 70073 69298 70085 70090 69298 69299 70085 69299 70078 70085 69299 69575 70078 69581 69576 69300 69300 69580 69581 69323 69304 69301 69303 69305 69307 69303 69307 69585 69304 69323 69597 69305 69306 69307 69325 69307 69306 69586 69585 69307 69587 69586 69307 69594 69587 69307 69307 69325 69594 69595 69317 69308 69308 69309 69595 69309 69588 69595 69327 69314 69310 70092 69846 69311 69311 69312 70092 69313 69312 69311 69593 69313 69311 70086 70082 69312 69312 69313 70086 69312 70081 70092 70082 70081 69312 69313 69601 70086 69313 69593 69601 69314 69327 69593 69317 69316 69315 69595 69589 69316 69316 69317 69595 69320 69319 69318 69604 69320 69318 69318 69321 69604 69319 69320 69322 69860 69322 69320 69320 69604 69860 69321 69596 69604 69860 69605 69322 69332 69323 69322 69605 69332 69322 69599 69326 69324 69325 69326 69594 69599 69594 69326 69603 69593 69327 69327 69602 69603 69609 69330 69328 69328 69602 69609 69603 69602 69328 69857 69603 69328 70102 69857 69328 69328 69329 70102 69330 69329 69328 69329 69864 70102 69329 69330 69864 69330 69609 69612 69609 69602 69331 69605 69339 69332 69619 69342 69334 69334 69618 69619 69861 69613 69335 69862 69861 69335 69335 69337 69862 69335 69336 69337 69338 69337 69336 69863 69862 69337 69337 69338 69863 69338 69610 69863 69338 69339 69610 69339 69605 69610 69340 69341 69342 69615 69352 69340 69340 69342 69615 69619 69615 69342 69621 69620 69343 69343 69353 69621 69344 69620 69626 69346 69622 69623 69346 69347 70321 69348 69347 69346 70313 69348 69346 69346 69623 70313 70538 70321 69347 70753 70538 69347 69347 70752 70753 69347 69348 70752 70755 70752 69348 70756 70755 69348 69348 70313 70756 69354 69350 69349 69350 70107 70111 69350 69624 70107 69350 69614 69624 69350 69354 69614 69351 69352 69615 69615 69614 69351 69870 69621 69353 69630 69360 69355 69355 69629 69630 70540 70118 69356 69356 69357 70540 69358 69357 69356 70118 69868 69356 69357 70538 70540 69357 70320 70538 69357 69358 70320 70321 70320 69358 69359 69379 69876 69870 69628 69359 69876 69870 69359 69389 69371 69360 69360 69369 69389 69630 69369 69360 69877 69375 69361 69361 69362 69877 70330 69877 69362 70331 70330 69362 69362 69363 70331 69363 70328 70331 70329 70328 69363 69363 70122 70329 69363 70120 70122 69636 69384 69364 69364 69365 69636 69366 69365 69364 69375 69366 69364 69642 69636 69365 70124 69642 69365 69365 69366 70124 70327 70124 69366 69366 70123 70327 69366 69375 70123 69367 69633 69638 69367 69368 69633 69634 69633 69368 69368 69369 69634 69635 69634 69369 69369 69630 69635 69380 69373 69370 69370 69371 69380 69381 69380 69371 69639 69381 69371 69371 69387 69639 69389 69387 69371 69373 69380 69644 69375 69877 70123 69376 69642 70334 69376 69377 69642 69378 69377 69376 69884 69378 69376 70340 69884 69376 69376 70334 70340 69377 69636 69642 69377 69384 69636 69377 69378 69384 69400 69399 69378 69893 69400 69378 69900 69893 69378 69378 69884 69900 69379 69637 69881 69881 69876 69379 69380 69643 69644 69380 69381 69643 69655 69643 69381 69657 69655 69381 69895 69657 69381 69381 69639 69895 69640 69383 69382 69382 69632 69640 69882 69390 69383 69883 69882 69383 69383 69640 69883 69649 69637 69385 69385 69386 69649 69386 69648 69649 69386 69400 69648 69895 69639 69387 69387 69388 69895 69388 69657 69895 69388 69427 69657 69882 69651 69390 69392 69391 69390 69651 69392 69390 69645 69641 69391 69391 69392 69645 69651 69645 69392 69638 69394 69393 69394 69650 69888 69394 69638 69650 69395 69396 69653 69396 69398 69652 69396 69652 69653 69414 69398 69397 69397 69413 69414 69398 69414 69652 69894 69648 69400 69400 69893 69894 69405 69404 69403 69658 69427 69403 69403 69404 69658 69404 69405 69406 69404 69644 69658 69673 69660 69407 69410 69409 69408 69408 69409 69415 69415 69411 69408 69416 69415 69409 69417 69416 69409 69681 69674 69412 69921 69681 69412 69922 69921 69412 69412 69916 69922 69910 69414 69413 69413 69904 69910 69413 69903 69904 69911 69903 69413 69413 69661 69911 69910 69652 69414 69914 69421 69415 69915 69914 69415 70154 69915 69415 69415 69416 70154 70155 70154 69416 70158 70155 69416 69416 69417 70158 69417 69927 70158 69672 69419 69418 69418 69669 69672 69671 69669 69418 69418 69663 69671 69427 69426 69420 69914 69430 69421 69421 69430 69431 69422 69423 69424 69682 69433 69422 69422 69680 69682 69422 69674 69680 69422 69424 69674 69672 69435 69426 69658 69657 69427 69920 69673 69428 69428 69432 69920 69428 69431 69432 69428 69429 69431 69667 69431 69429 69430 69914 69926 69432 69431 69430 69926 69432 69430 69432 69909 69920 69925 69909 69432 69926 69925 69432 69433 69685 69691 69433 69440 69685 69682 69440 69433 69676 69668 69434 69688 69676 69434 69436 69439 69440 69441 69439 69436 69436 69437 69441 69438 69437 69436 69440 69438 69436 69448 69441 69437 69684 69448 69437 69437 69438 69684 69438 69682 69684 69438 69440 69682 69439 69442 69685 69443 69442 69439 69439 69441 69443 69685 69440 69439 69450 69443 69441 69457 69450 69441 69441 69449 69457 69441 69448 69449 69692 69691 69442 69933 69692 69442 69442 69708 69933 69442 69703 69708 69442 69459 69703 69442 69443 69459 69691 69685 69442 69443 69458 69459 69443 69450 69458 69444 69694 69712 69444 69693 69694 69445 69454 69704 70176 69936 69446 70181 70176 69446 69446 69447 70181 69447 70180 70181 69447 69705 70180 69447 69704 69705 69448 69684 69923 69702 69449 69448 69930 69702 69448 69448 69923 69930 69710 69457 69449 69931 69710 69449 69449 69701 69931 69702 69701 69449 69457 69453 69450 69450 69451 69458 69452 69451 69450 69453 69452 69450 69707 69458 69451 69451 69464 69707 69451 69452 69464 69452 69460 69464 69452 69453 69460 69706 69460 69453 69710 69706 69453 69453 69457 69710 69454 69455 69704 69456 69455 69454 69705 69704 69455 69718 69705 69455 69722 69718 69455 69455 69456 69722 69707 69459 69458 69707 69703 69459 69706 69464 69460 69461 69469 69716 69716 69463 69461 69463 69716 69717 69464 69465 69707 69467 69465 69464 69714 69467 69464 69464 69706 69714 69942 69707 69465 70187 69942 69465 69465 69723 70187 69465 69466 69723 69467 69466 69465 69466 69467 69941 69954 69723 69466 69466 69951 69954 69466 69727 69951 69941 69727 69466 69467 69714 69941 69970 69731 69471 69471 69738 69970 69472 69473 69474 69472 69474 69732 69474 69730 69732 69475 69733 69980 69475 69732 69733 69476 69481 69738 69735 69478 69477 69487 69486 69478 69746 69487 69478 69478 69479 69746 69480 69479 69478 69740 69480 69478 69478 69735 69740 70220 69746 69479 69479 70216 70220 69479 69979 70216 69479 69480 69979 69480 69739 69979 69740 69739 69480 69743 69738 69481 69741 69483 69482 69998 69741 69482 69741 69739 69483 69745 69485 69484 69752 69745 69484 69484 69751 69752 69745 69743 69485 69486 69996 70000 69486 69487 69996 69997 69996 69487 70231 69997 69487 69487 69754 70231 69487 69746 69754 69747 69492 69488 69750 69747 69489 69993 69750 69489 69489 69990 69993 69489 69742 69990 69490 69493 69753 69753 69751 69490 69750 69748 69491 69491 69747 69750 69491 69492 69747 69493 69494 69753 70003 69759 69495 69495 69496 70003 70005 70003 69496 69496 69500 70005 69496 69497 69500 69762 69761 69497 69497 69502 69762 69761 69500 69497 69499 70006 70008 70007 70006 69499 70233 70005 69500 70234 70233 69500 69500 69761 70234 69763 69502 69501 69501 69506 69763 69763 69762 69502 69503 69509 69510 69503 69504 69509 70008 69509 69504 69764 69763 69506 70011 69764 69506 69506 69766 70011 69506 69507 69766 69507 69765 69766 69509 70008 70009 69768 69510 69509 70013 69768 69509 69509 70009 70013 70241 69513 69510 69510 70240 70241 69510 69768 70240 69766 69765 69511 69511 69516 69766 69511 69515 69516 69523 69515 69511 69511 69512 69523 69512 69522 69523 70241 69770 69513 69515 69773 69775 69515 69522 69773 69523 69522 69515 69775 69516 69515 70012 69766 69516 69516 69771 70012 69772 69771 69516 69775 69772 69516 69784 69783 69517 70020 69784 69517 70245 70020 69517 69517 69518 70245 69519 69518 69517 69521 69519 69517 70246 70245 69518 69518 69519 70246 70447 70246 69519 70448 70447 69519 69519 70444 70448 69519 69520 70444 69521 69520 69519 69520 70443 70444 69520 69769 70443 69770 69769 69520 69774 69773 69522 69522 69524 69774 70455 70454 69525 70456 70455 69525 69525 70025 70456 69525 69526 70025 69527 69526 69525 70454 69527 69525 69526 69527 70028 69527 69781 70021 70024 69781 69527 70454 70024 69527 69527 70021 70028 69528 69531 69533 69528 69529 69531 69532 69531 69529 69787 69532 69529 69530 69535 69537 69531 69532 69533 69536 69533 69532 69787 69536 69532 70022 69777 69534 70028 70022 69534 69785 69537 69535 69535 69784 69785 69535 69783 69784 69538 69541 69542 69791 69541 69538 69540 69789 69797 69540 69788 69789 69547 69543 69541 69791 69547 69541 69543 69542 69541 69793 69792 69544 69798 69793 69544 70255 69803 69546 69546 69799 70255 69805 69802 69548 70041 69800 69550 69550 70032 70041 69550 69553 70032 69551 69557 69804 69551 69555 69557 69556 69555 69551 69551 69552 69556 69801 69556 69552 69552 69794 69801 69797 69794 69552 70048 70032 69553 69553 69554 70048 69554 70047 70048 69554 69808 70047 69554 69559 69808 70042 69557 69555 70267 70042 69555 70476 70267 69555 69555 70264 70476 69555 69556 70264 69556 70259 70264 69556 69801 70259 69810 69804 69557 70042 69810 69557 70044 69806 69558 69560 69804 69817 69824 69823 69562 70067 69824 69562 69562 69579 70067 69562 69565 69579 69562 69563 69565 69564 69563 69562 69823 69564 69562 69565 69578 69579 69566 69567 69570 70060 69570 69567 69568 69573 69833 69574 69573 69568 70075 69838 69569 69825 69572 69570 69826 69825 69570 70061 69826 69570 69570 70060 70061 69572 69825 69827 70072 69833 69573 69573 70071 70072 69573 69574 70071 69574 70062 70071 69574 69816 70062 69579 69577 69576 69581 69579 69576 69579 69578 69577 70069 70067 69579 70070 70069 69579 69579 69840 70070 69579 69581 69840 69584 69581 69580 69841 69840 69581 69581 69584 69841 69843 69841 69582 70079 69843 69582 69582 69848 70079 69582 69583 69848 69584 69583 69582 69841 69584 69582 69583 69844 69848 69583 69586 69844 69583 69585 69586 69845 69844 69586 69586 69587 69845 69587 69594 69845 69588 69589 69595 69590 69589 69588 69847 69590 69588 69590 69607 69608 69590 69591 69607 69592 69591 69590 69847 69592 69590 70101 69856 69591 69591 70094 70101 70095 70094 69591 70096 70095 69591 69591 69592 70096 69592 70092 70096 69592 69846 70092 69847 69846 69592 69603 69601 69593 69594 69599 69845 69851 69604 69596 70089 69851 69596 69600 69599 69598 69854 69600 69598 69598 69852 69854 69849 69845 69599 69599 69600 69849 69600 69854 70080 70091 69849 69600 69600 70080 70091 69601 69603 69857 70087 70086 69601 70093 70087 69601 69601 69857 70093 69604 69858 69860 69859 69858 69604 70097 69859 69604 69604 69850 70097 69851 69850 69604 69860 69610 69605 69855 69853 69606 69865 69855 69606 69866 69865 69606 69867 69866 69606 69610 69862 69863 69610 69860 69862 69613 69861 69864 69869 69624 69614 69614 69615 69869 69615 69616 69869 69617 69616 69615 69619 69617 69615 70108 69869 69616 70318 70108 69616 69616 70317 70318 69616 69617 70317 69619 69618 69617 69617 70109 70317 69617 70105 70109 69617 69618 70105 70308 70105 69618 69618 69856 70308 69874 69626 69620 69620 69872 69874 69873 69872 69620 69620 69625 69873 69620 69621 69625 69871 69625 69621 70112 69871 69621 69621 69870 70112 70106 69623 69622 70536 70313 69623 69623 70106 70536 69624 69869 70108 70108 70107 69624 69625 69871 70114 70113 69873 69625 70114 70113 69625 69631 69629 69626 69875 69631 69626 69626 69874 69875 70535 70323 69627 70539 70535 69627 69631 69630 69629 69630 69631 69635 69875 69635 69631 69868 69640 69632 69633 69634 69878 69878 69638 69633 69634 69635 69878 69635 69875 69878 69637 69649 69885 69885 69881 69637 69889 69650 69638 69638 69878 69889 70127 69883 69640 69640 69868 70127 70121 69880 69641 69641 69891 70121 69641 69645 69891 69642 70124 70334 69655 69644 69643 69644 69654 69658 69655 69654 69644 69645 69646 69891 69647 69646 69645 69879 69647 69645 70352 69879 69645 69645 69896 70352 69645 69651 69896 69892 69891 69646 70342 69892 69646 70972 70342 69646 70973 70972 69646 69646 69647 70973 69647 70971 70973 69647 69879 70971 69901 69897 69648 69648 69894 69901 69887 69649 69648 69897 69887 69648 69887 69885 69649 70141 69888 69650 69650 70140 70141 69650 69889 70140 69651 69882 69896 70135 69653 69652 69652 70134 70135 69652 69910 70134 70135 69916 69653 69654 69657 69658 69654 69655 69657 70577 70339 69656 69656 70532 70577 70533 70532 69656 69656 70162 70533 69659 69912 70162 69659 69666 69912 69919 69666 69660 69660 69673 69919 69661 69662 69911 69917 69911 69662 69662 69675 69917 69662 69668 69675 69663 69664 69671 69918 69671 69664 69664 69665 69918 70147 69918 69665 69665 70141 70147 69665 69888 70141 69919 69912 69666 69676 69675 69668 69669 69670 69697 69671 69670 69669 69670 70152 70169 69670 69918 70152 69670 69671 69918 70169 69697 69670 69920 69919 69673 69681 69680 69674 70160 69917 69675 69675 69686 70160 69675 69676 69686 69928 69686 69676 69676 69688 69928 70160 69686 69677 69677 69678 70160 69679 69678 69677 70595 69679 69677 70599 70595 69677 69677 69687 70599 69677 69686 69687 70161 70160 69678 70593 70161 69678 70799 70593 69678 69678 69679 70799 70800 70799 69679 70801 70800 69679 69679 70595 70801 69684 69682 69680 69923 69684 69680 69680 69921 69923 69680 69681 69921 70166 69687 69686 69686 69928 70166 69687 70166 70599 70178 69927 69689 69689 69929 70178 70171 69693 69690 69690 69692 70171 69690 69691 69692 69692 69933 70171 69695 69694 69693 70171 69695 69693 69944 69712 69694 69694 69940 69944 69694 69939 69940 69694 69695 69939 70369 69939 69695 69695 69933 70369 70171 69933 69695 70167 69698 69696 70169 70167 69696 69696 69697 70169 69699 69700 69929 69932 69929 69700 69938 69932 69700 69700 69937 69938 69701 69702 70165 70372 69931 69701 69701 70170 70372 69701 70165 70170 69702 69930 70165 69703 69707 69708 69705 69934 70180 69935 69934 69705 69705 69718 69935 69941 69714 69706 69706 69713 69941 69706 69710 69713 69709 69708 69707 69942 69709 69707 69708 69709 69933 70373 69933 69709 69709 70187 70373 69709 69942 70187 70182 69713 69710 70183 70182 69710 69710 69931 70183 69724 69715 69711 69943 69724 69711 69711 69712 69943 69944 69943 69712 69713 69729 69941 70182 69729 69713 69945 69717 69716 69947 69945 69716 69949 69947 69716 69716 69943 69949 69716 69724 69943 69726 69725 69717 70188 69726 69717 69717 69945 70188 69718 69948 70184 69718 69721 69948 69722 69721 69718 69718 69719 69935 69720 69719 69718 70184 69720 69718 70179 69935 69719 70615 70179 69719 70619 70615 69719 70623 70619 69719 69719 69720 70623 69720 70393 70623 69720 70184 70393 69721 69734 69948 70388 70187 69723 69723 70201 70388 69723 69955 70201 69723 69954 69955 69725 69726 69730 69959 69730 69726 69726 69958 69959 70382 69958 69726 69726 70188 70382 69941 69729 69727 69727 69950 69951 69727 69728 69950 69729 69728 69727 69967 69950 69728 70185 69967 69728 69728 69729 70185 69729 70182 70185 69733 69732 69730 69957 69733 69730 69969 69957 69730 70398 69969 69730 69730 69958 70398 69959 69958 69730 69952 69734 69731 69953 69952 69731 69981 69953 69731 69731 69970 69981 69733 69742 69980 69991 69742 69733 69733 69956 69991 69957 69956 69733 69952 69948 69734 69735 69736 69740 69736 69739 69740 69980 69742 69737 69975 69970 69738 69982 69975 69738 69738 69744 69982 69738 69743 69744 69989 69979 69739 69992 69989 69739 69739 69741 69992 70221 69992 69741 70225 70221 69741 69741 69998 70225 69991 69990 69742 69745 69744 69743 70210 69982 69744 70406 70210 69744 69744 70217 70406 69744 69745 70217 69745 69994 70217 69745 69752 69994 70224 69754 69746 69746 70220 70224 70225 69998 69748 69748 69749 70225 69750 69749 69748 70226 70225 69749 69749 69755 70226 69749 69750 69755 69993 69755 69750 69995 69752 69751 69751 69757 69995 69751 69753 69757 69995 69994 69752 70642 70231 69754 70643 70642 69754 69754 70224 70643 70647 70226 69755 69755 70419 70647 69755 69991 70419 69755 69990 69991 69993 69990 69755 69995 69757 69756 70218 69995 69756 69756 70212 70218 69756 69758 70212 69758 70002 70212 69759 70003 70005 70004 69760 69759 70005 70004 69759 69760 70004 70007 69761 69767 70238 69761 69762 69767 70236 70234 69761 70238 70236 69761 69762 69763 69767 69763 69764 69767 69764 70011 70428 70238 69767 69764 70428 70238 69764 70012 70011 69766 70436 70240 69768 69768 70239 70436 69768 70013 70239 69769 70438 70445 70439 70438 69769 69769 69770 70439 70446 70443 69769 69769 70445 70446 69770 70241 70439 69771 70440 70656 70441 70440 69771 69771 70016 70441 69771 70015 70016 69771 69772 70015 70427 70012 69771 70656 70427 69771 69772 70014 70015 70242 70014 69772 69772 70017 70242 69772 69779 70017 69772 69778 69779 69772 69775 69778 69776 69775 69773 69781 69776 69773 69773 69774 69781 69774 69777 69781 69775 69776 69778 69779 69778 69776 69781 69779 69776 70022 69781 69777 70018 70017 69779 70023 70018 69779 69779 69782 70023 69779 69781 69782 69780 70450 70451 69780 70024 70450 69780 69781 70024 69782 69781 69780 70244 69782 69780 70451 70244 69780 70022 70021 69781 69782 70014 70023 70244 70014 69782 69786 69785 69784 70027 69786 69784 69784 70020 70027 69785 69786 69788 69790 69788 69786 70027 69790 69786 69790 69789 69788 69789 69794 69797 69796 69794 69789 69789 69790 69796 70027 70026 69790 70250 69796 69790 70453 70250 69790 69790 70026 70453 70456 70025 69792 70457 70456 69792 69792 69793 70457 70464 70457 69793 69793 70038 70464 69793 69798 70038 70036 69801 69794 69794 69795 70036 69796 69795 69794 69795 70029 70036 69795 69796 70029 70250 70029 69796 69798 69802 70038 70467 70255 69799 69799 70458 70467 69799 70040 70458 69799 69800 70040 70041 70040 69800 69801 70036 70259 69802 70033 70038 69802 69805 70033 70253 70034 69803 70254 70253 69803 70255 70254 69803 69804 69809 69817 69810 69809 69804 70043 70033 69805 69805 69806 70043 70045 70043 69806 69806 70044 70045 70046 70044 69807 69807 70034 70046 69808 69811 70047 70271 70055 69809 69809 69810 70271 70055 69817 69809 69810 70042 70271 70051 70047 69811 70053 70050 69812 69812 70052 70053 69812 69813 70052 69813 69814 69825 69813 69825 70052 69827 69825 69814 70054 69816 69815 69815 69817 70054 70281 70062 69816 69816 69829 70281 70054 69829 69816 70056 70054 69817 69817 70055 70056 69818 69831 70057 70059 69832 69819 69820 69821 70059 69822 69821 69820 70058 69822 69820 70065 70059 69821 70279 70065 69821 69821 69822 70279 69822 70278 70279 69822 70058 70278 69823 69824 70061 70280 70061 69824 70486 70280 69824 69824 70068 70486 69824 70067 70068 70275 70052 69825 69825 69826 70275 70276 70275 69826 69826 70061 70276 69828 69829 70056 69830 69829 69828 70702 69830 69828 69828 70273 70702 69828 70055 70273 70056 70055 69828 69829 70054 70056 70482 70281 69829 69829 69830 70482 70483 70482 69830 70703 70483 69830 69830 70702 70703 69832 70059 70063 70072 69834 69833 69836 69835 69834 70074 69836 69834 69834 70072 70074 69839 69837 69835 69835 69836 69839 70073 69839 69836 70074 70073 69836 69837 69839 70073 69838 70077 70282 69838 70075 70077 70284 70070 69840 69840 69842 70284 69843 69842 69840 69840 69841 69843 70289 70284 69842 69842 70100 70289 69842 70098 70100 69842 70079 70098 69842 69843 70079 69844 69849 70091 69844 69845 69849 70091 69848 69844 70080 70079 69848 70091 70080 69848 70103 70097 69850 69850 69857 70103 69850 69851 69857 70093 69857 69851 69851 70089 70093 70080 69854 69852 69852 70079 70080 70098 70079 69852 69852 69855 70098 69852 69853 69855 70100 70098 69855 69855 69865 70100 70309 70308 69856 69856 70101 70309 69857 70102 70103 69858 69859 69862 69862 69860 69858 70097 69861 69859 69859 69861 69862 70097 69864 69861 70104 70102 69864 69864 70097 70104 70296 70100 69865 70305 70296 69865 70306 70305 69865 70307 70306 69865 69865 69866 70307 70310 70307 69866 69866 69867 70310 70311 70310 69867 70312 70311 69867 69868 70125 70127 69868 70119 70125 69868 70118 70119 69870 69876 70112 70112 69876 69871 69871 69876 70114 70115 69874 69872 70117 70115 69872 69872 69873 70117 70322 70117 69873 69873 70113 70322 70115 69875 69874 70128 69878 69875 69875 70116 70128 69875 70115 70116 69876 70113 70114 70333 70113 69876 69876 69886 70333 69876 69881 69886 70330 70123 69877 70129 69889 69878 69878 70128 70129 69879 70780 70971 69879 70585 70780 69879 70352 70585 70121 70120 69880 69881 69885 69886 69882 69890 69896 69882 69883 69890 70126 69890 69883 70127 70126 69883 70340 69900 69884 69897 69886 69885 69885 69887 69897 70347 70333 69886 69886 69897 70347 69889 70132 70140 69889 70129 70132 69890 70130 70131 69890 70126 70130 70131 69896 69890 70122 70121 69891 69891 69892 70122 70544 70122 69892 69892 70343 70544 69892 70342 70343 70353 69898 69893 69893 69900 70353 70139 69894 69893 69893 69898 70139 69894 69899 69901 70139 69899 69894 70778 70352 69896 69896 70142 70778 69896 70131 70142 69901 69899 69897 70349 70347 69897 69897 69898 70349 69899 69898 69897 70353 70349 69898 69898 69899 70139 69900 70340 70353 69906 69905 69902 70356 69906 69902 69902 69911 70356 69902 69903 69911 69904 69903 69902 69905 69904 69902 70137 69910 69904 70138 70137 69904 70143 70138 69904 70146 70143 69904 69904 69905 70146 70579 70146 69905 69905 69906 70579 70586 70579 69906 69906 70356 70586 69919 69909 69907 69907 69912 69919 69913 69912 69907 70364 69913 69907 69907 69908 70364 69909 69908 69907 70594 70364 69908 70597 70594 69908 69908 69925 70597 69908 69909 69925 69909 69919 69920 70346 70134 69910 69910 70137 70346 69911 70150 70356 70151 70150 69911 69911 69917 70151 70533 70162 69912 70581 70533 69912 70583 70581 69912 69912 69913 70583 69913 70582 70583 70788 70582 69913 69913 70787 70788 69913 70364 70787 70591 69926 69914 69914 70156 70591 69914 69915 70156 69915 70154 70156 70159 69922 69916 69916 70135 70159 70160 70151 69917 70153 70152 69918 70367 70153 69918 69918 70148 70367 70149 70148 69918 69918 70147 70149 69924 69923 69921 70163 69924 69921 69921 69922 70163 70362 70163 69922 69922 70159 70362 70165 69930 69923 69923 70164 70165 69923 69924 70164 70365 70164 69924 69924 70163 70365 71000 70597 69925 69925 70591 71000 69925 69926 70591 70361 70158 69927 69927 70178 70361 70167 70166 69928 69929 70177 70178 69929 69932 70177 70377 70183 69931 69931 70372 70377 69932 69938 70177 70607 70369 69933 69933 70374 70607 69933 70373 70374 70615 70180 69934 69934 70179 70615 69934 69935 70179 70175 69937 69936 70176 70175 69936 70177 69938 69937 69937 70175 70177 70607 70174 69939 69939 70369 70607 70174 69940 69939 70173 69944 69940 70376 70173 69940 69940 70174 70376 69943 69944 69949 70172 69949 69944 70173 70172 69944 69947 69946 69945 70189 70188 69945 69945 69946 70189 69946 70186 70380 69946 69947 70186 70381 70189 69946 69946 70380 70381 69947 70172 70186 69947 69949 70172 69948 69952 70184 69968 69951 69950 69950 69966 69968 69967 69966 69950 69968 69954 69951 70198 70184 69952 69952 69953 70198 70392 70198 69953 69953 69981 70392 70204 69955 69954 69954 69968 70204 70204 70201 69955 70410 69991 69956 70636 70410 69956 69956 69957 70636 69957 70633 70636 70634 70633 69957 69957 69969 70634 69958 70389 70398 69958 70382 70389 70203 69962 69960 69960 69963 70203 69965 69963 69960 70202 69965 69960 69960 70199 70202 69960 69961 70199 69962 69961 69960 69961 70194 70199 69961 70193 70194 69961 69962 70193 70200 70197 69962 70203 70200 69962 70196 70193 69962 70197 70196 69962 69963 69964 70203 69965 69964 69963 69964 70200 70203 69964 69971 70200 69973 69971 69964 69964 69965 69973 69976 69973 69965 70202 69976 69965 69972 69968 69966 69974 69972 69966 69966 69967 69974 70396 69974 69967 69967 70185 70396 69968 70205 70215 69968 69972 70205 70214 70204 69968 70215 70214 69968 70823 70634 69969 69969 70398 70823 69970 69975 69981 70402 70200 69971 69971 70396 70402 69971 69974 70396 69971 69972 69974 69973 69972 69971 70208 70205 69972 69972 69977 70208 69972 69973 69977 69973 69976 69977 70209 69981 69975 69975 69982 70209 70211 69985 69976 69976 70202 70211 69978 69977 69976 69985 69978 69976 69977 69987 70208 69977 69978 69987 69978 69983 69987 69985 69983 69978 69979 69989 70216 70404 70392 69981 69981 70209 70404 70210 70209 69982 69983 69984 69987 69985 69984 69983 69984 69986 69987 70219 69986 69984 69984 69985 70219 69985 70211 70219 69988 69987 69986 70652 69988 69986 69986 70421 70652 69986 70228 70421 69986 70219 70228 69987 69988 70208 69988 70207 70208 70835 70207 69988 70836 70835 69988 69988 70652 70836 70220 70216 69989 70418 70220 69989 69989 69992 70418 70639 70419 69991 69991 70637 70639 69991 70410 70637 70420 70418 69992 69992 70221 70420 70227 70222 69994 69994 69995 70227 70222 70217 69994 69995 70218 70227 69996 69997 70000 70229 70001 69997 70231 70229 69997 70001 70000 69997 70223 70002 69999 70228 70223 69999 69999 70000 70228 70000 70001 70228 70001 70229 70424 70421 70228 70001 70423 70421 70001 70424 70423 70001 70223 70212 70002 70233 70007 70004 70004 70005 70233 70010 70008 70006 70006 70007 70010 70235 70010 70007 70007 70233 70235 70010 70009 70008 70431 70013 70009 70009 70430 70431 70009 70426 70430 70009 70010 70426 70010 70237 70426 70010 70235 70237 70011 70012 70434 70434 70428 70011 70012 70427 70434 70431 70239 70013 70016 70015 70014 70452 70016 70014 70014 70449 70452 70014 70243 70449 70244 70243 70014 70242 70023 70014 70442 70441 70016 70452 70442 70016 70017 70019 70242 70017 70018 70019 70023 70019 70018 70019 70023 70242 70020 70026 70027 70246 70026 70020 70020 70245 70246 70021 70022 70028 70671 70450 70024 70673 70671 70024 70024 70672 70673 70024 70456 70672 70024 70455 70456 70024 70454 70455 70675 70453 70026 70026 70247 70675 70026 70246 70247 70029 70035 70036 70250 70035 70029 70030 70031 70257 70032 70031 70030 70041 70032 70030 70252 70041 70030 70256 70252 70030 70257 70256 70030 70031 70032 70049 70031 70049 70257 70032 70048 70049 70039 70038 70033 70043 70039 70033 70253 70046 70034 70035 70250 70670 70037 70036 70035 70251 70037 70035 70670 70251 70035 70036 70037 70259 70679 70259 70037 70037 70251 70679 70038 70261 70464 70038 70039 70261 70039 70043 70045 70039 70260 70261 70039 70045 70260 70040 70252 70458 70040 70041 70252 70272 70271 70042 70042 70267 70272 70046 70045 70044 70263 70260 70045 70045 70046 70263 70465 70263 70046 70046 70253 70465 70266 70048 70047 70047 70265 70266 70047 70051 70265 70266 70049 70048 70472 70257 70049 70474 70472 70049 70475 70474 70049 70049 70266 70475 70053 70051 70050 70051 70053 70265 70269 70053 70052 70275 70269 70052 70270 70265 70053 70053 70269 70270 70055 70271 70273 70278 70058 70057 70057 70277 70278 70065 70063 70059 70280 70276 70061 70491 70071 70062 70062 70281 70491 70063 70064 70066 70065 70064 70063 70085 70066 70064 70716 70085 70064 70064 70065 70716 70720 70716 70065 70912 70720 70065 70065 70911 70912 70065 70899 70911 70065 70492 70899 70065 70279 70492 70066 70078 70283 70085 70078 70066 70069 70068 70067 70068 70070 70284 70068 70069 70070 70497 70486 70068 70068 70284 70497 70285 70072 70071 70286 70285 70071 70494 70286 70071 70071 70491 70494 70285 70074 70072 70076 70075 70074 70285 70076 70074 70495 70077 70075 70075 70076 70495 70717 70495 70076 70076 70496 70717 70076 70286 70496 70076 70285 70286 70493 70282 70077 70718 70493 70077 70077 70495 70718 70096 70092 70081 70099 70096 70081 70287 70099 70081 70081 70082 70287 70082 70086 70088 70082 70088 70287 70288 70085 70083 70083 70093 70288 70083 70088 70093 70083 70084 70088 70085 70084 70083 70287 70088 70084 70723 70287 70084 70084 70085 70723 70288 70090 70085 70085 70716 70723 70086 70087 70088 70093 70088 70087 70288 70093 70089 70089 70090 70288 70507 70101 70094 70737 70507 70094 70738 70737 70094 70094 70095 70738 70925 70738 70095 70095 70924 70925 70095 70732 70924 70095 70728 70732 70095 70099 70728 70095 70096 70099 70097 70103 70104 70099 70287 70728 70296 70289 70100 70507 70309 70101 70104 70103 70102 70110 70109 70105 70751 70110 70105 70936 70751 70105 70105 70522 70936 70105 70308 70522 70106 70529 70536 70106 70315 70529 70106 70314 70315 70106 70111 70314 70314 70111 70107 70107 70108 70314 70537 70314 70108 70108 70318 70537 70318 70317 70109 70109 70110 70318 70751 70318 70110 70326 70322 70113 70337 70326 70113 70113 70333 70337 70117 70116 70115 70116 70117 70326 70551 70128 70116 70116 70337 70551 70116 70326 70337 70117 70322 70326 70540 70325 70118 70325 70119 70118 70959 70563 70119 70119 70324 70959 70325 70324 70119 70562 70125 70119 70563 70562 70119 70120 70121 70122 70544 70329 70122 70332 70327 70123 70123 70330 70332 70124 70327 70763 70550 70334 70124 70763 70550 70124 70561 70127 70125 70562 70561 70125 70559 70351 70126 70560 70559 70126 70561 70560 70126 70126 70127 70561 70133 70130 70126 70351 70133 70126 70552 70129 70128 70128 70551 70552 70557 70132 70129 70129 70555 70557 70129 70552 70555 70133 70131 70130 70131 70133 70142 70557 70140 70132 70350 70142 70133 70351 70350 70133 70136 70135 70134 70345 70136 70134 70346 70345 70134 70354 70159 70135 70355 70354 70135 70135 70136 70355 70566 70355 70136 70136 70345 70566 70569 70346 70137 70137 70138 70569 70775 70569 70138 70783 70775 70138 70138 70143 70783 70341 70141 70140 70580 70341 70140 70140 70572 70580 70140 70557 70572 70141 70144 70147 70145 70144 70141 70341 70145 70141 70142 70350 70778 70143 70579 70783 70143 70146 70579 70149 70147 70144 70580 70149 70144 70144 70145 70580 70145 70341 70580 70792 70367 70148 70148 70587 70792 70148 70149 70587 70149 70573 70587 70149 70572 70573 70580 70572 70149 70588 70356 70150 70589 70588 70150 70150 70161 70589 70150 70151 70161 70151 70160 70161 70596 70168 70152 70602 70596 70152 70152 70153 70602 70152 70168 70169 70367 70366 70153 70153 70601 70602 70153 70366 70601 70154 70155 70156 70155 70158 70361 70157 70156 70155 70361 70157 70155 70156 70357 70591 70358 70357 70156 70795 70358 70156 70156 70157 70795 70157 70359 70795 70361 70359 70157 70159 70354 70362 70593 70589 70161 70163 70362 70365 70368 70165 70164 70605 70368 70164 70164 70598 70605 70164 70365 70598 70368 70170 70165 70602 70601 70166 70166 70596 70602 70166 70168 70596 70166 70167 70168 70600 70599 70166 70601 70600 70166 70169 70168 70167 70609 70372 70170 70610 70609 70170 70170 70605 70610 70170 70368 70605 70172 70173 70186 70376 70186 70173 70612 70376 70174 70174 70611 70612 70174 70607 70611 70178 70177 70175 70604 70178 70175 70175 70176 70604 70176 70371 70604 70176 70370 70371 70176 70181 70370 70604 70361 70178 70370 70181 70180 70371 70370 70180 70810 70371 70180 70180 70616 70810 70180 70615 70616 70182 70183 70377 70378 70185 70182 70182 70377 70378 70184 70391 70393 70184 70383 70391 70184 70198 70383 70397 70396 70185 70185 70378 70397 70186 70376 70380 70187 70190 70373 70388 70190 70187 70390 70382 70188 70188 70381 70390 70188 70189 70381 70190 70388 70627 70190 70191 70373 70192 70191 70190 70627 70192 70190 70375 70373 70191 71022 70375 70191 70191 70192 71022 70192 71021 71022 70192 70820 71021 70821 70820 70192 70192 70627 70821 70195 70194 70193 70196 70195 70193 70385 70199 70194 70194 70384 70385 70194 70195 70384 70195 70197 70384 70195 70196 70197 70402 70394 70197 70197 70200 70402 70394 70384 70197 70392 70383 70198 70395 70202 70199 70199 70385 70395 70627 70388 70201 70628 70627 70201 70201 70403 70628 70201 70204 70403 70409 70211 70202 70202 70408 70409 70202 70401 70408 70202 70395 70401 70204 70214 70403 70205 70206 70215 70207 70206 70205 70208 70207 70205 70635 70628 70206 70833 70635 70206 70837 70833 70206 70206 70207 70837 70628 70215 70206 70841 70837 70207 70207 70835 70841 70405 70404 70209 70406 70405 70209 70209 70210 70406 70211 70212 70219 70213 70212 70211 70409 70213 70211 70212 70213 70218 70223 70219 70212 70413 70218 70213 70213 70409 70413 70214 70215 70403 70628 70403 70215 70407 70406 70217 70417 70407 70217 70217 70222 70417 70413 70227 70218 70219 70223 70228 70418 70224 70220 70422 70420 70221 70221 70225 70422 70222 70227 70417 70224 70418 70643 70225 70226 70422 70647 70422 70226 70227 70413 70417 70229 70230 70424 70231 70230 70229 70641 70423 70230 70649 70641 70230 70651 70649 70230 70230 70232 70651 70230 70231 70232 70230 70423 70424 70642 70232 70231 70844 70651 70232 70232 70642 70844 70236 70235 70233 70233 70234 70236 70235 70236 70237 70654 70237 70236 70236 70653 70654 70236 70425 70653 70236 70238 70425 70429 70426 70237 70654 70429 70237 70428 70425 70238 70239 70433 70436 70239 70431 70433 70436 70241 70240 70241 70436 70439 70857 70449 70243 71047 70857 70243 70243 70451 71047 70243 70244 70451 70248 70247 70246 70249 70248 70246 70668 70249 70246 70246 70447 70668 71057 70871 70247 70247 70248 71057 70872 70675 70247 70247 70871 70872 70248 71052 71057 70248 70249 71052 70249 71051 71052 70249 71050 71051 70249 70668 71050 70250 70453 70670 70251 70670 70679 70459 70458 70252 70463 70459 70252 70252 70462 70463 70252 70256 70462 70466 70465 70253 70253 70254 70466 70681 70466 70254 70254 70467 70681 70254 70255 70467 70468 70462 70256 70256 70258 70468 70256 70257 70258 70472 70258 70257 70469 70468 70258 70472 70469 70258 70877 70264 70259 70259 70679 70877 70262 70261 70260 70471 70262 70260 70867 70471 70260 70260 70263 70867 70261 70262 70464 70680 70464 70262 70262 70471 70680 70263 70465 70684 70263 70684 70867 70689 70476 70264 70877 70689 70264 70478 70266 70265 70265 70477 70478 70265 70270 70477 70266 70478 70687 70688 70475 70266 70266 70687 70688 70479 70272 70267 70267 70476 70479 70268 70269 70275 70270 70269 70268 70480 70270 70268 70268 70275 70480 70693 70477 70270 70270 70480 70693 70274 70273 70271 70479 70274 70271 70271 70272 70479 70273 70274 70481 70273 70481 70702 70694 70481 70274 70274 70479 70694 70696 70480 70275 70700 70696 70275 70275 70699 70700 70275 70276 70699 70276 70698 70699 70276 70280 70698 70485 70278 70277 70277 70484 70485 70708 70484 70277 70485 70279 70278 70279 70485 70492 70280 70487 70698 70488 70487 70280 70280 70486 70488 70281 70482 70491 70721 70497 70284 70725 70721 70284 70284 70501 70725 70502 70501 70284 70284 70289 70502 70722 70496 70286 70286 70489 70722 70494 70489 70286 70287 70724 70728 70287 70723 70724 70289 70501 70502 70289 70296 70501 70290 70295 70505 70290 70291 70295 70292 70291 70290 70505 70292 70290 70291 70293 70295 70294 70293 70291 70291 70292 70294 70297 70294 70292 70508 70297 70292 70509 70508 70292 70292 70505 70509 70300 70295 70293 70302 70300 70293 70303 70302 70293 70293 70297 70303 70293 70294 70297 70295 70300 70503 70295 70503 70505 70916 70501 70296 71233 70916 70296 70296 70739 71233 70296 70305 70739 70297 70298 70303 70299 70298 70297 70504 70299 70297 70508 70504 70297 70298 70302 70303 70304 70302 70298 70512 70304 70298 70298 70299 70512 70513 70512 70299 70299 70504 70513 70510 70503 70300 70511 70510 70300 70516 70511 70300 70300 70301 70516 70302 70301 70300 70301 70304 70516 70301 70302 70304 70304 70515 70516 70304 70512 70515 70740 70739 70305 70931 70740 70305 70305 70526 70931 70305 70306 70526 70306 70310 70526 70306 70307 70310 70744 70522 70308 70308 70507 70744 70308 70309 70507 70310 70311 70526 70311 70525 70526 70311 70312 70525 70312 70319 70525 70757 70756 70313 70313 70536 70757 70316 70315 70314 70537 70316 70314 70315 70528 70529 70315 70316 70528 70531 70528 70316 70749 70531 70316 70316 70537 70749 70749 70537 70318 70751 70749 70318 70534 70525 70319 70535 70534 70319 70319 70323 70535 70320 70321 70538 71131 70959 70324 70324 70556 71131 70324 70540 70556 70324 70325 70540 70327 70332 70763 70545 70331 70328 70546 70545 70328 70328 70329 70546 70329 70544 70546 70547 70332 70330 70330 70331 70547 70331 70545 70547 70332 70548 70763 70549 70548 70332 70332 70547 70549 70551 70337 70333 70555 70551 70333 70333 70348 70555 70333 70347 70348 70334 70336 70340 70334 70335 70336 70550 70335 70334 70554 70336 70335 70335 70553 70554 70335 70550 70553 70565 70340 70336 70336 70554 70565 70770 70768 70338 70338 70339 70770 70339 70577 70770 70776 70353 70340 70340 70564 70776 70565 70564 70340 70342 70972 71136 70344 70343 70342 71136 70344 70342 70765 70544 70343 70766 70765 70343 71125 70766 70343 70343 70344 71125 71264 71125 70344 71265 71264 70344 70344 71135 71265 70344 71134 71135 71136 71134 70344 70568 70567 70345 70345 70346 70568 70567 70566 70345 70569 70568 70346 70349 70348 70347 70558 70555 70348 70574 70558 70348 70576 70574 70348 70348 70570 70576 70348 70349 70570 70776 70570 70349 70349 70353 70776 70781 70778 70350 70350 70779 70781 70350 70584 70779 70350 70578 70584 70350 70351 70578 70351 70559 70578 70778 70585 70352 70363 70362 70354 70798 70363 70354 70354 70789 70798 70354 70355 70789 70355 70774 70789 70355 70566 70774 70588 70586 70356 70357 70590 70591 70804 70590 70357 70357 70794 70804 70357 70358 70794 70358 70793 70794 70993 70793 70358 70358 70795 70993 70797 70795 70359 70359 70592 70797 70359 70360 70592 70361 70360 70359 70807 70592 70360 70360 70606 70807 70360 70604 70606 70360 70361 70604 70603 70365 70362 70806 70603 70362 70362 70363 70806 70994 70806 70363 70363 70798 70994 70803 70787 70364 70364 70594 70803 70603 70598 70365 70366 70367 70600 70366 70600 70601 70792 70600 70367 70811 70604 70371 70371 70810 70811 70617 70377 70372 70372 70609 70617 70375 70374 70373 70611 70607 70374 70374 70375 70611 70814 70611 70375 70816 70814 70375 71022 70816 70375 70376 70612 70613 70613 70380 70376 70621 70378 70377 70377 70617 70621 70815 70397 70378 70378 70621 70815 70379 70817 70818 71175 70817 70379 70379 70614 71175 70379 70613 70614 70379 70380 70613 70381 70380 70379 70818 70381 70379 70823 70390 70381 70381 70818 70823 70390 70389 70382 70383 70385 70391 70395 70385 70383 70399 70395 70383 70383 70392 70399 70624 70385 70384 70384 70387 70624 70384 70386 70387 70394 70386 70384 70393 70391 70385 70622 70393 70385 70624 70622 70385 71032 71028 70386 70386 70824 71032 70386 70394 70824 71028 70387 70386 70387 70622 70624 70387 70618 70622 70819 70618 70387 71028 70819 70387 70823 70398 70389 70389 70390 70823 70400 70399 70392 70404 70400 70392 70393 70622 70623 70394 70629 70824 70394 70402 70629 70395 70400 70401 70395 70399 70400 70626 70402 70396 70396 70397 70626 70397 70625 70626 70815 70625 70397 70404 70401 70400 70416 70408 70401 70401 70405 70416 70401 70404 70405 70402 70626 70629 70405 70415 70416 70405 70407 70415 70405 70406 70407 70407 70414 70415 70417 70414 70407 70413 70409 70408 70416 70413 70408 70638 70637 70410 70830 70638 70410 70410 70411 70830 70412 70411 70410 71035 70412 70410 70410 70633 71035 70636 70633 70410 70834 70830 70411 70839 70834 70411 70411 70827 70839 70411 70412 70827 71035 71034 70412 71033 70827 70412 71177 71033 70412 71179 71177 70412 70412 71025 71179 71034 71025 70412 70415 70414 70413 70416 70415 70413 70413 70414 70417 70648 70643 70418 70418 70645 70648 70418 70420 70645 70419 70640 70647 70419 70639 70640 70420 70422 70645 70421 70650 70652 70421 70641 70650 70421 70423 70641 70647 70645 70422 70654 70653 70425 70425 70429 70654 70425 70428 70429 70432 70430 70426 70426 70429 70432 70656 70434 70427 70655 70429 70428 70428 70434 70655 70655 70432 70429 70433 70431 70430 70435 70433 70430 70430 70432 70435 70655 70435 70432 70437 70436 70433 70433 70435 70437 70656 70655 70434 70657 70437 70435 70435 70655 70657 70659 70439 70436 70436 70437 70659 70437 70657 70659 70663 70445 70438 70438 70661 70663 70438 70439 70661 70439 70659 70661 70440 70658 70847 70660 70658 70440 70440 70441 70660 70847 70656 70440 70441 70442 70662 70849 70660 70441 70441 70662 70849 70442 70452 70662 70446 70444 70443 70444 70446 70448 70445 70663 70664 70448 70446 70445 70664 70448 70445 70862 70668 70447 70447 70664 70862 70447 70448 70664 70857 70452 70449 70669 70451 70450 70671 70669 70450 70451 70669 70866 70451 70865 71047 70866 70865 70451 70852 70662 70452 70857 70852 70452 70674 70670 70453 70675 70674 70453 70456 70457 70672 70457 70464 70680 70676 70672 70457 70680 70676 70457 70873 70467 70458 70458 70682 70873 70683 70682 70458 70458 70459 70683 70685 70683 70459 70459 70463 70685 70463 70462 70460 70685 70463 70460 71060 70685 70460 70460 71057 71060 70460 70876 71057 70460 70875 70876 70460 70461 70875 70462 70461 70460 70461 70462 70686 70461 70686 70875 70462 70468 70686 70465 70466 70684 70879 70684 70466 70880 70879 70466 70466 70681 70880 70881 70681 70467 70467 70873 70881 70468 70470 70686 70468 70469 70470 70473 70470 70469 70469 70472 70473 70883 70686 70470 70470 70473 70883 70471 70677 70680 70867 70677 70471 70688 70473 70472 70472 70474 70688 70885 70883 70473 71065 70885 70473 70473 70688 71065 70474 70475 70688 70694 70479 70476 70695 70694 70476 70476 70689 70695 70884 70478 70477 70477 70693 70884 70884 70687 70478 70697 70693 70480 70480 70696 70697 70481 70694 70695 70890 70702 70481 70481 70695 70890 70482 70483 70491 70483 70490 70491 70703 70490 70483 70484 70708 70710 70710 70485 70484 70899 70492 70485 70485 70709 70899 70710 70709 70485 70705 70488 70486 70486 70704 70705 70486 70497 70704 70706 70698 70487 70707 70706 70487 70487 70488 70707 70488 70705 70707 70901 70722 70489 70489 70898 70901 70489 70490 70898 70491 70490 70489 70494 70491 70489 70490 70703 70898 70718 70708 70493 70495 70717 70718 70905 70717 70496 70496 70722 70905 70711 70704 70497 70902 70711 70497 70497 70721 70902 70915 70500 70498 70498 70728 70915 70732 70728 70498 71087 70732 70498 70498 70499 71087 70500 70499 70498 71088 71087 70499 71222 71088 70499 70499 71083 71222 70499 70500 71083 70915 70912 70500 70500 71078 71083 70500 70911 71078 70912 70911 70500 70916 70725 70501 70503 70510 70923 70506 70505 70503 70922 70506 70503 70923 70922 70503 70928 70513 70504 70504 70926 70928 70504 70508 70926 70727 70509 70505 70505 70726 70727 70505 70506 70726 70727 70726 70506 70921 70727 70506 71086 70921 70506 70506 70922 71086 70745 70744 70507 70507 70737 70745 70508 70729 70926 70508 70509 70729 70509 70727 70729 70510 70511 70923 70511 70519 70735 70511 70518 70519 70511 70516 70518 70511 70735 70923 70520 70515 70512 70512 70514 70520 70512 70513 70514 70928 70514 70513 70741 70520 70514 70932 70741 70514 71104 70932 70514 70514 70928 71104 70517 70516 70515 70520 70517 70515 70516 70517 70518 70521 70518 70517 70517 70520 70521 70731 70519 70518 70518 70730 70731 70742 70730 70518 70518 70521 70742 70519 70733 70734 70519 70731 70733 70519 70734 70735 70742 70521 70520 70520 70741 70742 70937 70936 70522 70522 70523 70937 70524 70523 70522 70744 70524 70522 71105 70937 70523 70523 70524 71105 70524 70943 71105 70524 70930 70943 70524 70744 70930 70527 70526 70525 70534 70527 70525 70526 70527 70931 70938 70931 70527 70939 70938 70527 70527 70534 70939 70530 70529 70528 70748 70530 70528 70528 70747 70748 70528 70531 70747 70757 70536 70529 70529 70530 70757 70530 70746 70757 70530 70730 70746 70748 70730 70530 70531 70749 70750 70934 70747 70531 70531 70750 70934 70532 70533 70581 70532 70560 70577 70532 70559 70560 70578 70559 70532 70581 70578 70532 70949 70939 70534 70534 70759 70949 70534 70535 70759 70535 70539 70759 70753 70540 70538 70761 70759 70539 70768 70761 70539 70540 70543 70556 70540 70542 70543 70753 70542 70540 70541 70542 70760 70543 70542 70541 71111 70543 70541 71255 71111 70541 70541 70760 71255 70542 70753 70946 70946 70760 70542 70543 71111 71124 71124 70556 70543 70765 70546 70544 70762 70547 70545 70953 70762 70545 70545 70950 70953 70545 70546 70950 70951 70950 70546 70546 70765 70951 70762 70549 70547 70954 70763 70548 70548 70549 70954 70549 70952 70954 70549 70762 70952 70763 70553 70550 70555 70552 70551 70553 70763 70764 70955 70554 70553 70956 70955 70553 70553 70764 70956 70767 70565 70554 70955 70767 70554 70558 70557 70555 70556 71130 71131 70556 71124 71130 70557 70558 70574 70573 70572 70557 70777 70573 70557 70557 70575 70777 70557 70574 70575 70770 70577 70560 70771 70770 70560 70772 70771 70560 70560 70563 70772 70560 70562 70563 70560 70561 70562 70960 70772 70563 70563 70959 70960 70963 70571 70564 70564 70773 70963 70564 70565 70773 70564 70570 70776 70571 70570 70564 70565 70769 70773 70565 70767 70769 70566 70567 70774 70567 70568 70774 70775 70774 70568 70568 70569 70775 70570 70571 70576 70571 70963 70970 70981 70576 70571 71139 70981 70571 70571 70970 71139 70777 70587 70573 70576 70575 70574 70978 70777 70575 70981 70978 70575 70575 70576 70981 70578 70581 70584 70784 70783 70579 70579 70586 70784 70581 70583 70584 70782 70583 70582 71149 70782 70582 71150 71149 70582 70582 70788 71150 70980 70584 70583 70583 70782 70980 70979 70779 70584 70980 70979 70584 70585 70778 70780 70785 70784 70586 70586 70588 70785 70587 70777 70978 70982 70792 70587 70587 70978 70982 70790 70785 70588 70588 70589 70790 70791 70790 70589 70589 70593 70791 71001 71000 70590 71007 71001 70590 71292 71007 70590 70590 70804 71292 71000 70591 70590 70592 70796 70797 70805 70796 70592 70807 70805 70592 70799 70791 70593 70594 70597 70803 70595 70599 70801 71000 70803 70597 71165 70610 70598 70598 71010 71165 70598 71009 71010 70598 70603 71009 70610 70605 70598 70998 70801 70599 70599 70802 70998 70599 70600 70802 70600 70792 70982 70982 70802 70600 70603 70806 71009 70608 70606 70604 70812 70608 70604 70604 70811 70812 71008 70807 70606 70606 70608 71008 70608 70812 71008 70609 70610 70617 70809 70617 70610 71165 70809 70610 70814 70612 70611 71014 70614 70612 71015 71014 70612 70612 70814 71015 70614 70613 70612 70614 71014 71017 70614 71017 71175 70619 70616 70615 70813 70810 70616 70616 70619 70813 70808 70621 70617 70809 70808 70617 70623 70622 70618 70618 70619 70623 70620 70619 70618 70819 70620 70618 70619 70620 70813 71173 70813 70620 70620 71023 71173 70620 70819 71023 70621 70808 70815 70825 70626 70625 71036 70825 70625 70625 71024 71036 70625 71018 71024 70625 70815 71018 70825 70629 70626 70627 70628 70821 70628 70635 70821 70826 70824 70629 70629 70825 70826 71181 71024 70630 70630 70631 71181 70632 70631 70630 71019 70632 70630 71024 71019 70630 70631 70632 71442 71308 71181 70631 71442 71308 70631 70632 71300 71438 70632 71019 71300 70632 71438 71442 70633 70634 71035 70823 70818 70634 70634 70822 71035 70634 70818 70822 70831 70821 70635 70832 70831 70635 70833 70832 70635 70838 70639 70637 70637 70834 70838 70637 70638 70834 70638 70830 70834 70645 70640 70639 70639 70644 70645 70838 70644 70639 70640 70645 70647 70641 70649 70650 70846 70844 70642 70642 70643 70846 70643 70648 70846 70646 70645 70644 70838 70646 70644 70645 70646 70648 70843 70648 70646 70646 70828 70843 70838 70828 70646 70648 70845 70846 70648 70842 70845 70843 70842 70648 70649 70651 71045 71045 70650 70649 70841 70652 70650 70650 70840 70841 71187 70840 70650 70650 71045 71187 70651 71042 71045 70651 70844 71042 70652 70835 70836 70841 70835 70652 70658 70657 70655 70847 70658 70655 70655 70656 70847 70660 70659 70657 70657 70658 70660 70851 70661 70659 70659 70850 70851 70659 70660 70850 70660 70848 70850 70849 70848 70660 70851 70663 70661 70852 70849 70662 70858 70664 70663 70663 70853 70858 70663 70851 70853 70664 70858 70862 70665 70857 71047 70665 70666 70857 70667 70666 70665 71054 70667 70665 70665 71047 71054 70666 70852 70857 70854 70852 70666 70855 70854 70666 70666 70667 70855 71048 70855 70667 71054 71048 70667 70668 70859 71050 70862 70859 70668 70669 70671 70866 70670 70678 70679 70670 70674 70678 70671 70673 70867 70867 70866 70671 70677 70673 70672 70672 70676 70677 70673 70677 70867 70674 70675 70872 70870 70678 70674 70872 70870 70674 70680 70677 70676 70877 70679 70678 70878 70877 70678 70678 70870 70878 70881 70880 70681 71058 70874 70682 70682 70683 71058 70874 70873 70682 71059 71058 70683 70683 70685 71059 70869 70867 70684 70879 70869 70684 70685 71056 71059 70685 71055 71056 71060 71055 70685 70883 70875 70686 70886 70688 70687 71198 70886 70687 70687 71196 71198 70687 70889 71196 70687 70884 70889 70688 70886 71065 70882 70695 70689 70689 70877 70882 70690 70693 70697 70889 70693 70690 71067 70889 70690 70690 70691 71067 70692 70691 70690 70697 70692 70690 70691 71066 71067 71320 71066 70691 70691 71202 71320 70691 70692 71202 70692 71069 71202 70692 70696 71069 70697 70696 70692 70889 70884 70693 70891 70890 70695 70695 70882 70891 71070 71069 70696 70696 70700 71070 70894 70699 70698 70895 70894 70698 70698 70706 70895 70701 70700 70699 70894 70701 70699 71072 71070 70700 70700 70701 71072 70701 70894 71072 70892 70703 70702 70893 70892 70702 71073 70893 70702 70702 71071 71073 70702 70890 71071 70703 70892 70898 70900 70705 70704 70704 70712 70900 70704 70711 70712 70900 70707 70705 70706 70707 71074 71326 70895 70706 70706 71211 71326 70706 71210 71211 70706 71074 71210 70707 70900 71074 71076 70710 70708 70708 70714 71076 70715 70714 70708 70718 70715 70708 71216 71082 70709 70709 71077 71216 70709 70710 71077 70913 70899 70709 71078 70913 70709 71218 71078 70709 70709 71082 71218 70710 71076 71077 70902 70713 70711 70713 70712 70711 71079 70900 70712 70712 70713 71079 71080 71079 70713 70713 70902 71080 71217 71076 70714 70714 71208 71217 70714 70910 71208 70714 70715 70910 70715 70719 70910 70715 70718 70719 70716 70720 70723 70719 70718 70717 70905 70719 70717 70719 70906 70910 70909 70906 70719 70719 70905 70909 70912 70723 70720 71080 70902 70721 70721 70725 71080 70909 70905 70722 70722 70904 70909 70722 70903 70904 70722 70901 70903 70915 70724 70723 70723 70912 70915 70915 70728 70724 70725 70917 71080 70725 70916 70917 70919 70729 70727 70920 70919 70727 70921 70920 70727 70729 70919 71097 71099 70926 70729 70729 71097 71099 70748 70743 70730 70730 70742 70746 70743 70731 70730 70743 70733 70731 71087 70924 70732 70733 70747 70927 70748 70747 70733 70733 70743 70748 70927 70734 70733 70736 70735 70734 71240 70736 70734 71243 71240 70734 71244 71243 70734 70734 71103 71244 70734 70927 71103 70735 70736 70923 71234 70923 70736 71238 71234 70736 71239 71238 70736 71357 71239 70736 71358 71357 70736 70736 71243 71358 70736 71240 71243 70929 70745 70737 70737 70738 70929 71102 70929 70738 70738 70925 71102 71491 71233 70739 70739 71488 71491 70739 70740 71488 71571 71488 70740 70740 71249 71571 71341 71249 70740 70740 70931 71341 70746 70742 70741 70933 70746 70741 70741 70932 70933 70744 70929 70930 70744 70745 70929 70933 70757 70746 70934 70927 70747 70749 70751 70941 70941 70750 70749 70935 70934 70750 70941 70935 70750 70751 70936 70937 70751 70937 70941 70752 70755 70940 70754 70753 70752 70940 70754 70752 70753 70754 70946 70947 70946 70754 70754 70945 70947 70754 70940 70945 70755 70756 70940 70756 70758 70940 70756 70757 70758 70933 70758 70757 70933 70932 70758 70948 70940 70758 70758 70932 70948 70961 70949 70759 70759 70761 70961 70760 71252 71255 71253 71252 70760 71254 71253 70760 70760 70946 71254 70761 70944 70961 70761 70768 70944 70953 70952 70762 70954 70764 70763 71117 70956 70764 70764 70954 71117 71120 70951 70765 70765 70766 71120 71126 71120 70766 70766 71125 71126 71128 70769 70767 70767 71127 71128 70767 70957 71127 70767 70955 70957 70768 70771 70944 70768 70770 70771 71128 70773 70769 70771 70772 70944 70962 70944 70772 70772 70960 70962 70970 70963 70773 71128 70970 70773 70983 70789 70774 70774 70967 70983 70774 70775 70967 70968 70967 70775 70969 70968 70775 70775 70783 70969 70781 70780 70778 71141 70781 70779 71142 71141 70779 70779 70979 71142 70780 70781 70971 70977 70971 70781 70781 70976 70977 71141 70976 70781 71147 70980 70782 71149 71147 70782 70975 70969 70783 71137 70975 70783 70783 70784 71137 70784 70984 71137 70784 70785 70984 70985 70984 70785 70785 70790 70985 70786 70803 71154 70786 70787 70803 70788 70787 70786 71154 70788 70786 71154 71150 70788 70986 70798 70789 70789 70983 70986 70987 70985 70790 70790 70791 70987 70988 70987 70791 70791 70799 70988 71156 70794 70793 70793 71155 71156 70793 70993 71155 71160 70804 70794 70794 71156 71160 70795 70796 70993 70797 70796 70795 71155 70993 70796 70796 71006 71155 70796 70805 71006 70995 70994 70798 70798 70986 70995 70996 70988 70799 70799 70800 70996 70800 70801 70996 70997 70996 70801 70998 70997 70801 71148 70998 70802 70802 70989 71148 70802 70982 70989 71159 71154 70803 70803 71001 71159 70803 71000 71001 70804 71160 71292 70805 71003 71006 71005 71003 70805 70805 70807 71005 70806 70994 71009 71008 71005 70807 71018 70815 70808 71020 71018 70808 70808 70809 71020 71169 71020 70809 70809 71165 71169 71016 70811 70810 70810 70813 71016 71012 70812 70811 70811 71011 71012 71016 71011 70811 71166 71008 70812 70812 71012 71166 71173 71016 70813 71301 71015 70814 70814 70816 71301 70816 71176 71303 70816 71022 71176 70816 71180 71301 71302 71180 70816 71303 71302 70816 71025 70822 70817 71175 71025 70817 70822 70818 70817 71299 71023 70819 70819 71026 71299 71027 71026 70819 71031 71027 70819 70819 71028 71031 71309 71021 70820 71310 71309 70820 70820 70821 71310 70821 70831 71038 71312 71310 70821 70821 71038 71312 70822 71034 71035 70822 71025 71034 70824 70826 71032 71036 70826 70825 71037 71032 70826 70826 71036 71037 70827 70828 70839 70829 70828 70827 71180 70829 70827 70827 71033 71180 70828 70838 70839 71039 70843 70828 70828 70829 71039 71186 71039 70829 70829 71185 71186 71302 71185 70829 70829 71180 71302 70831 70840 71038 70831 70832 70840 70832 70837 70840 70832 70833 70837 70839 70838 70834 70841 70840 70837 70840 71187 71188 71188 71038 70840 71041 71040 70842 70842 70843 71041 71189 70845 70842 70842 71040 71189 70843 71039 71041 70844 70845 71042 70846 70845 70844 71044 71042 70845 71189 71044 70845 70856 70850 70848 70848 70855 70856 70848 70854 70855 70848 70849 70854 70849 70852 70854 70853 70851 70850 70856 70853 70850 70861 70858 70853 70853 70856 70861 70861 70856 70855 71046 70861 70855 71048 71046 70855 70858 70859 70862 70860 70859 70858 70863 70860 70858 70864 70863 70858 70858 70861 70864 70859 70860 71050 71051 71050 70860 71059 71051 70860 70860 70863 71059 71046 70864 70861 71193 71059 70863 70863 71049 71193 70863 70864 71049 70864 71046 71049 71053 71047 70865 70865 70868 71053 70865 70866 70868 70866 70867 70868 70869 70868 70867 70868 70879 71053 70868 70869 70879 70870 70876 70878 70870 70871 70876 70872 70871 70870 71057 70876 70871 71063 70881 70873 70873 71062 71063 70873 70874 71062 70874 71058 71194 71194 71062 70874 70878 70876 70875 70882 70878 70875 70883 70882 70875 70877 70878 70882 71061 71053 70879 70879 70880 71061 71064 71061 70880 70880 70881 71064 70881 71063 71064 70882 70887 70891 70882 70885 70887 70882 70883 70885 70888 70887 70885 71065 70888 70885 71201 71065 70886 71203 71201 70886 70886 71199 71203 70886 71198 71199 71073 70891 70887 70887 70893 71073 71204 70893 70887 70887 71068 71204 70887 70888 71068 70888 71065 71068 71197 71196 70889 70889 71067 71197 70890 70891 71071 71073 71071 70891 70903 70898 70892 70892 70896 70903 70897 70896 70892 71075 70897 70892 70892 70893 71075 71204 71075 70893 71207 71072 70894 70894 70895 71207 71326 71207 70895 70914 70903 70896 71214 70914 70896 70896 70897 71214 71329 71214 70897 71330 71329 70897 70897 71327 71330 70897 71323 71327 70897 71075 71323 70903 70901 70898 70913 70911 70899 71213 71074 70900 70900 71079 71213 70914 70904 70903 70914 70909 70904 70906 70907 70910 70908 70907 70906 70909 70908 70906 71209 70910 70907 71466 71209 70907 70907 70908 71466 70908 71331 71466 70908 71215 71331 70908 70909 71215 70909 70914 71215 71209 71208 70910 70911 70913 71078 71331 71215 70914 71334 71331 70914 70914 71333 71334 70914 71214 71333 70918 70917 70916 71231 70918 70916 71233 71231 70916 71219 71080 70917 71336 71219 70917 71337 71336 70917 70917 70918 71337 71478 71337 70918 70918 71231 71478 70919 71092 71093 70919 70920 71092 70919 71093 71097 70920 70921 71092 70921 71090 71092 71226 71090 70921 70921 71084 71226 71086 71084 70921 70922 70923 71234 70922 71085 71086 71349 71085 70922 70922 71234 71349 71098 70925 70924 71100 71098 70924 70924 71094 71100 70924 71087 71094 70925 71098 71102 71246 70928 70926 70926 71237 71246 70926 71101 71237 70926 71099 71101 70927 70935 71103 70927 70934 70935 70928 70945 71104 70947 70945 70928 71362 70947 70928 70928 71246 71362 71102 70930 70929 71102 70943 70930 70931 71107 71341 70931 70938 71107 71104 70948 70932 70935 70941 71103 71245 70941 70937 70937 70942 71245 70943 70942 70937 71105 70943 70937 71110 71107 70938 70938 70939 71110 70939 70949 71110 71104 70945 70940 70940 70948 71104 71361 71103 70941 70941 71245 71361 71352 71245 70942 70942 71242 71352 71248 71242 70942 70942 70943 71248 70943 71106 71248 70943 71102 71106 70962 70961 70944 70946 71108 71254 70946 70947 71108 71362 71108 70947 70949 71109 71110 70949 70961 71109 71112 70953 70950 71122 71112 70950 70950 70951 71122 70951 71121 71122 70951 71120 71121 71114 70954 70952 71115 71114 70952 70952 70953 71115 70953 71113 71115 70953 71112 71113 70954 71116 71117 70954 71114 71116 70958 70957 70955 70955 70956 70958 71123 70958 70956 70956 71117 71123 70957 71123 71127 70957 70958 71123 71131 70960 70959 70966 70962 70960 71131 70966 70960 70961 70962 71109 71263 71109 70962 70962 70966 71263 70964 71371 71497 70964 70965 71371 70966 70965 70964 71368 70966 70964 70964 71367 71368 71497 71367 70964 70965 71369 71371 70965 71124 71369 71130 71124 70965 70965 70966 71130 71368 71263 70966 71131 71130 70966 71140 70983 70967 70967 71138 71140 70967 70968 71138 70968 70969 71138 70969 71137 71138 70969 70975 71137 70970 71132 71139 71133 71132 70970 70970 71128 71133 70974 70973 70971 70977 70974 70971 70972 70973 71136 71269 71136 70973 70973 70974 71269 71389 71269 70974 70974 71388 71389 70974 71270 71388 70974 70977 71270 71274 71144 70976 70976 71272 71274 70976 71141 71272 71144 70977 70976 70977 71144 71270 71146 70982 70978 70978 70981 71146 71143 71142 70979 70979 70980 71143 71147 71143 70980 70981 71139 71146 71146 70989 70982 71140 70986 70983 70984 71281 71394 70984 71152 71281 70984 71151 71152 70984 70985 71151 71394 71137 70984 70985 70987 71151 71286 70995 70986 71287 71286 70986 70986 71145 71287 70986 71140 71145 71282 71151 70987 70987 71153 71282 70987 70988 71153 70988 70996 71153 70989 71146 71271 70989 70998 71148 71271 70998 70989 70990 71002 71157 70990 70991 71002 70992 70991 70990 71409 70992 70990 71417 71409 70990 70990 71410 71417 70990 71157 71410 71160 71002 70991 71292 71160 70991 70991 71161 71292 70991 70992 71161 71412 71161 70992 70992 71408 71412 71409 71408 70992 70994 70999 71009 70994 70995 70999 71158 70999 70995 71289 71158 70995 70995 71286 71289 70996 70997 71153 71288 71153 70997 70997 71284 71288 70997 71271 71284 70997 70998 71271 71295 71009 70999 71415 71295 70999 70999 71414 71415 70999 71158 71414 71001 71007 71159 71002 71155 71157 71156 71155 71002 71160 71156 71002 71005 71004 71003 71155 71006 71003 71291 71155 71003 71003 71004 71291 71004 71005 71168 71411 71291 71004 71413 71411 71004 71418 71413 71004 71004 71168 71418 71005 71164 71168 71005 71008 71164 71293 71162 71007 71007 71292 71293 71162 71159 71007 71166 71164 71008 71294 71010 71009 71295 71294 71009 71172 71165 71010 71294 71172 71010 71013 71012 71011 71298 71013 71011 71011 71174 71298 71011 71173 71174 71011 71016 71173 71012 71013 71166 71167 71166 71013 71422 71167 71013 71423 71422 71013 71432 71423 71013 71013 71298 71432 71178 71017 71014 71182 71178 71014 71014 71015 71182 71015 71180 71182 71301 71180 71015 71178 71175 71017 71018 71019 71024 71020 71019 71018 71019 71020 71300 71020 71169 71300 71309 71176 71021 71176 71022 71021 71174 71173 71023 71299 71174 71023 71181 71036 71024 71025 71175 71179 71430 71299 71026 71026 71027 71430 71027 71429 71430 71027 71031 71429 71028 71029 71031 71030 71029 71028 71032 71030 71028 71429 71031 71029 71439 71429 71029 71029 71030 71439 71030 71304 71439 71305 71304 71030 71030 71184 71305 71030 71032 71184 71032 71037 71183 71032 71183 71184 71182 71180 71033 71033 71177 71182 71036 71181 71306 71183 71037 71036 71306 71183 71036 71038 71188 71312 71186 71041 71039 71040 71041 71186 71315 71189 71040 71040 71314 71315 71040 71186 71314 71316 71045 71042 71042 71043 71316 71044 71043 71042 71043 71191 71316 71043 71044 71191 71192 71191 71044 71044 71189 71192 71190 71187 71045 71316 71190 71045 71062 71049 71046 71063 71062 71046 71046 71048 71063 71047 71053 71054 71048 71054 71063 71194 71193 71049 71049 71062 71194 71055 71052 71051 71056 71055 71051 71059 71056 71051 71052 71055 71060 71060 71057 71052 71195 71054 71053 71053 71061 71195 71064 71063 71054 71195 71064 71054 71058 71193 71194 71058 71059 71193 71061 71064 71195 71201 71068 71065 71319 71067 71066 71320 71319 71066 71318 71197 71067 71319 71318 71067 71068 71201 71204 71069 71070 71202 71206 71202 71070 71070 71072 71206 71321 71206 71072 71072 71207 71321 71213 71210 71074 71445 71323 71075 71075 71204 71445 71217 71077 71076 71217 71216 71077 71218 71083 71078 71220 71213 71079 71079 71219 71220 71079 71080 71219 71340 71230 71081 71081 71221 71340 71081 71082 71221 71083 71082 71081 71222 71083 71081 71230 71222 71081 71082 71216 71221 71082 71083 71218 71344 71226 71084 71345 71344 71084 71084 71085 71345 71086 71085 71084 71353 71345 71085 71085 71349 71353 71087 71088 71094 71222 71094 71088 71226 71224 71089 71089 71090 71226 71091 71090 71089 71225 71091 71089 71089 71224 71225 71090 71091 71092 71093 71092 71091 71096 71093 71091 71091 71095 71096 71227 71095 71091 71228 71227 71091 71091 71225 71228 71093 71096 71097 71229 71100 71094 71094 71222 71229 71101 71099 71095 71227 71101 71095 71097 71096 71095 71099 71097 71095 71241 71102 71098 71098 71100 71241 71242 71241 71100 71346 71242 71100 71100 71229 71346 71101 71235 71237 71236 71235 71101 71101 71227 71236 71241 71106 71102 71247 71244 71103 71361 71247 71103 71106 71242 71248 71106 71241 71242 71107 71249 71341 71250 71249 71107 71251 71250 71107 71107 71110 71251 71362 71254 71108 71263 71110 71109 71263 71251 71110 71255 71124 71111 71259 71113 71112 71112 71256 71259 71112 71122 71256 71260 71115 71113 71508 71260 71113 71113 71259 71508 71261 71116 71114 71114 71260 71261 71114 71115 71260 71119 71117 71116 71261 71119 71116 71117 71118 71123 71119 71118 71117 71118 71119 71261 71376 71123 71118 71118 71261 71376 71258 71121 71120 71262 71258 71120 71120 71126 71262 71258 71122 71121 71258 71256 71122 71376 71127 71123 71124 71252 71369 71255 71252 71124 71264 71126 71125 71373 71262 71126 71126 71372 71373 71126 71264 71372 71129 71128 71127 71377 71129 71127 71127 71375 71377 71376 71375 71127 71268 71133 71128 71128 71129 71268 71399 71268 71129 71129 71377 71399 71271 71139 71132 71283 71271 71132 71397 71283 71132 71132 71268 71397 71132 71133 71268 71134 71378 71379 71134 71269 71378 71134 71136 71269 71379 71135 71134 71374 71265 71135 71511 71374 71135 71593 71511 71135 71135 71519 71593 71135 71512 71519 71135 71379 71512 71266 71138 71137 71267 71266 71137 71387 71267 71137 71394 71387 71137 71275 71140 71138 71380 71275 71138 71138 71266 71380 71271 71146 71139 71275 71145 71140 71273 71272 71141 71141 71142 71273 71142 71143 71273 71277 71273 71143 71143 71147 71277 71388 71270 71144 71391 71388 71144 71144 71274 71391 71404 71287 71145 71145 71279 71404 71280 71279 71145 71145 71275 71280 71285 71277 71147 71147 71149 71285 71149 71276 71285 71149 71162 71276 71149 71154 71162 71149 71150 71154 71282 71152 71151 71402 71281 71152 71152 71401 71402 71152 71282 71401 71403 71282 71153 71153 71288 71403 71154 71159 71162 71291 71157 71155 71419 71410 71157 71157 71411 71419 71157 71291 71411 71532 71414 71158 71533 71532 71158 71605 71533 71158 71158 71406 71605 71158 71290 71406 71158 71289 71290 71293 71292 71161 71161 71162 71293 71163 71162 71161 71412 71163 71161 71162 71163 71276 71526 71276 71163 71163 71412 71526 71164 71166 71167 71164 71167 71168 71172 71169 71165 71296 71168 71167 71297 71296 71167 71422 71297 71167 71168 71296 71418 71169 71170 71300 71171 71170 71169 71172 71171 71169 71539 71300 71170 71170 71171 71539 71540 71539 71171 71171 71172 71540 71172 71426 71427 71172 71294 71426 71541 71540 71172 71172 71424 71541 71425 71424 71172 71427 71425 71172 71299 71298 71174 71175 71178 71179 71440 71303 71176 71176 71309 71440 71177 71178 71182 71179 71178 71177 71308 71306 71181 71306 71184 71183 71306 71305 71184 71313 71186 71185 71185 71311 71313 71185 71303 71311 71185 71302 71303 71186 71313 71314 71316 71191 71187 71187 71190 71316 71191 71188 71187 71314 71312 71188 71188 71192 71314 71317 71192 71188 71188 71191 71317 71315 71192 71189 71191 71192 71317 71315 71314 71192 71200 71198 71196 71196 71197 71200 71318 71200 71197 71200 71199 71198 71205 71203 71199 71451 71205 71199 71549 71451 71199 71199 71546 71549 71199 71444 71546 71199 71443 71444 71199 71200 71443 71200 71318 71443 71201 71203 71204 71322 71320 71202 71202 71206 71322 71445 71204 71203 71203 71205 71445 71205 71327 71445 71451 71327 71205 71206 71321 71322 71448 71321 71207 71207 71324 71448 71326 71324 71207 71335 71217 71208 71473 71335 71208 71208 71471 71473 71208 71209 71471 71472 71471 71209 71209 71466 71472 71212 71211 71210 71328 71212 71210 71210 71213 71328 71455 71326 71211 71211 71342 71455 71211 71212 71342 71470 71342 71212 71212 71467 71470 71212 71458 71467 71212 71328 71458 71332 71328 71213 71213 71220 71332 71457 71333 71214 71214 71329 71457 71216 71217 71221 71335 71221 71217 71336 71220 71219 71336 71332 71220 71221 71335 71340 71230 71229 71222 71456 71338 71223 71475 71456 71223 71223 71339 71475 71223 71224 71339 71225 71224 71223 71338 71225 71223 71343 71339 71224 71224 71226 71343 71342 71228 71225 71225 71338 71342 71344 71343 71226 71227 71232 71236 71227 71228 71232 71228 71342 71470 71481 71232 71228 71560 71481 71228 71228 71470 71560 71347 71346 71229 71229 71340 71347 71229 71230 71340 71483 71478 71231 71231 71233 71483 71481 71236 71232 71491 71483 71233 71234 71238 71349 71246 71237 71235 71363 71246 71235 71365 71363 71235 71235 71236 71365 71484 71365 71236 71236 71481 71484 71356 71349 71238 71238 71239 71356 71489 71356 71239 71490 71489 71239 71239 71357 71490 71242 71346 71352 71243 71244 71358 71244 71247 71482 71360 71358 71244 71485 71360 71244 71487 71485 71244 71244 71482 71487 71245 71352 71361 71363 71362 71246 71247 71350 71482 71361 71350 71247 71249 71495 71571 71249 71250 71495 71250 71493 71495 71494 71493 71250 71496 71494 71250 71250 71366 71496 71250 71251 71366 71251 71263 71366 71252 71253 71507 71501 71369 71252 71507 71501 71252 71253 71362 71492 71253 71254 71362 71253 71492 71507 71370 71259 71256 71256 71257 71370 71258 71257 71256 71257 71262 71370 71257 71258 71262 71259 71502 71508 71504 71502 71259 71259 71370 71504 71586 71261 71260 71260 71585 71586 71260 71584 71585 71260 71508 71584 71509 71376 71261 71510 71509 71261 71586 71510 71261 71373 71370 71262 71368 71367 71263 71367 71366 71263 71264 71265 71372 71374 71372 71265 71382 71380 71266 71266 71267 71382 71387 71382 71267 71398 71397 71268 71399 71398 71268 71389 71378 71269 71271 71283 71284 71392 71274 71272 71272 71273 71392 71273 71278 71392 71273 71277 71278 71392 71391 71274 71380 71280 71275 71276 71277 71285 71278 71277 71276 71405 71278 71276 71526 71405 71276 71278 71391 71392 71525 71391 71278 71278 71405 71525 71279 71280 71400 71407 71404 71279 71528 71407 71279 71279 71400 71528 71280 71380 71400 71281 71393 71394 71281 71375 71393 71395 71375 71281 71396 71395 71281 71401 71396 71281 71402 71401 71281 71403 71401 71282 71288 71284 71283 71397 71288 71283 71286 71287 71404 71290 71289 71286 71404 71290 71286 71288 71397 71403 71407 71406 71290 71290 71404 71407 71294 71295 71426 71427 71426 71295 71534 71427 71295 71295 71533 71534 71295 71420 71533 71295 71415 71420 71419 71418 71296 71421 71419 71296 71296 71297 71421 71537 71421 71297 71297 71422 71537 71298 71431 71432 71298 71299 71431 71299 71430 71431 71300 71539 71542 71542 71438 71300 71440 71311 71303 71441 71439 71304 71304 71307 71441 71304 71305 71307 71305 71306 71307 71308 71307 71306 71442 71441 71307 71307 71308 71442 71309 71311 71440 71309 71310 71311 71314 71311 71310 71310 71312 71314 71314 71313 71311 71444 71443 71318 71446 71444 71318 71318 71319 71446 71447 71446 71319 71547 71447 71319 71548 71547 71319 71319 71450 71548 71319 71320 71450 71320 71449 71450 71320 71322 71449 71449 71322 71321 71321 71448 71449 71445 71327 71323 71326 71325 71324 71454 71448 71324 71324 71325 71454 71455 71454 71325 71325 71326 71455 71453 71330 71327 71327 71451 71453 71328 71332 71458 71555 71457 71329 71329 71452 71555 71329 71330 71452 71453 71452 71330 71331 71465 71466 71331 71461 71465 71331 71334 71461 71332 71336 71458 71457 71334 71333 71334 71457 71461 71473 71340 71335 71469 71458 71336 71336 71337 71469 71478 71469 71337 71338 71456 71459 71459 71342 71338 71339 71474 71475 71339 71343 71474 71348 71347 71340 71473 71348 71340 71459 71455 71342 71343 71344 71474 71344 71345 71474 71479 71474 71345 71345 71354 71479 71345 71353 71354 71346 71351 71352 71346 71347 71351 71471 71351 71347 71347 71348 71471 71473 71471 71348 71356 71353 71349 71352 71351 71350 71361 71352 71350 71350 71351 71482 71351 71471 71482 71355 71354 71353 71356 71355 71353 71558 71479 71354 71563 71558 71354 71354 71355 71563 71355 71489 71563 71355 71356 71489 71568 71490 71357 71357 71566 71568 71357 71359 71566 71357 71358 71359 71360 71359 71358 71359 71559 71566 71359 71486 71559 71359 71360 71486 71360 71485 71486 71362 71363 71492 71363 71364 71492 71365 71364 71363 71364 71484 71567 71364 71365 71484 71576 71492 71364 71364 71572 71576 71364 71567 71572 71366 71367 71496 71497 71496 71367 71500 71499 71369 71501 71500 71369 71506 71371 71369 71369 71499 71506 71580 71504 71370 71582 71580 71370 71632 71582 71370 71370 71583 71632 71370 71581 71583 71370 71373 71581 71506 71497 71371 71374 71373 71372 71588 71581 71373 71373 71374 71588 71374 71511 71588 71399 71377 71375 71375 71395 71399 71375 71384 71393 71375 71376 71384 71509 71384 71376 71518 71379 71378 71378 71517 71518 71378 71389 71517 71518 71512 71379 71380 71381 71400 71382 71381 71380 71521 71400 71381 71599 71521 71381 71381 71520 71599 71381 71383 71520 71381 71382 71383 71515 71383 71382 71382 71387 71515 71383 71513 71596 71515 71513 71383 71596 71520 71383 71394 71393 71384 71384 71387 71394 71516 71387 71384 71384 71385 71516 71386 71385 71384 71509 71386 71384 71587 71516 71385 71385 71586 71587 71385 71510 71586 71385 71386 71510 71386 71509 71510 71516 71515 71387 71598 71524 71388 71388 71390 71598 71391 71390 71388 71524 71389 71388 71524 71517 71389 71390 71391 71522 71669 71598 71390 71696 71669 71390 71390 71523 71696 71390 71522 71523 71525 71522 71391 71395 71398 71399 71395 71397 71398 71395 71396 71397 71401 71397 71396 71397 71401 71403 71400 71521 71528 71600 71525 71405 71405 71526 71600 71406 71601 71673 71406 71407 71601 71671 71605 71406 71673 71671 71406 71407 71527 71601 71528 71527 71407 71603 71412 71408 71408 71602 71603 71408 71409 71602 71409 71529 71602 71409 71417 71529 71531 71417 71410 71410 71419 71531 71411 71413 71419 71649 71526 71412 71412 71603 71649 71413 71418 71419 71532 71416 71414 71416 71415 71414 71415 71416 71420 71532 71420 71416 71530 71529 71417 71531 71530 71417 71419 71530 71531 71604 71530 71419 71419 71421 71604 71420 71532 71533 71421 71535 71604 71536 71535 71421 71607 71536 71421 71421 71606 71607 71421 71537 71606 71538 71537 71422 71422 71432 71538 71422 71423 71432 71655 71541 71424 71424 71425 71655 71425 71654 71655 71425 71428 71654 71425 71427 71428 71534 71428 71427 71428 71534 71654 71431 71430 71429 71435 71431 71429 71545 71435 71429 71429 71441 71545 71429 71439 71441 71433 71432 71431 71435 71433 71431 71610 71538 71432 71432 71543 71610 71432 71433 71543 71544 71543 71433 71433 71434 71544 71435 71434 71433 71612 71544 71434 71613 71612 71434 71434 71437 71613 71434 71435 71437 71435 71436 71437 71545 71436 71435 71438 71437 71436 71442 71438 71436 71545 71442 71436 71437 71438 71613 71438 71611 71613 71438 71542 71611 71441 71442 71545 71444 71446 71546 71614 71546 71446 71446 71447 71614 71447 71547 71614 71550 71449 71448 71553 71550 71448 71448 71454 71553 71550 71450 71449 71551 71548 71450 71450 71550 71551 71549 71453 71451 71616 71555 71452 71452 71453 71616 71453 71614 71616 71453 71552 71614 71453 71549 71552 71454 71455 71553 71455 71459 71553 71556 71459 71456 71617 71556 71456 71622 71617 71456 71456 71475 71622 71457 71460 71461 71555 71460 71457 71468 71467 71458 71469 71468 71458 71556 71553 71459 71464 71461 71460 71460 71463 71464 71569 71463 71460 71628 71569 71460 71460 71555 71628 71461 71464 71465 71561 71559 71462 71462 71463 71561 71464 71463 71462 71465 71464 71462 71466 71465 71462 71476 71466 71462 71480 71476 71462 71487 71480 71462 71462 71485 71487 71559 71485 71462 71569 71561 71463 71557 71472 71466 71466 71476 71557 71467 71468 71477 71477 71470 71467 71468 71469 71478 71478 71477 71468 71470 71477 71560 71471 71480 71482 71471 71476 71480 71471 71472 71476 71557 71476 71472 71558 71475 71474 71474 71479 71558 71475 71558 71625 71623 71622 71475 71625 71623 71475 71562 71560 71477 71567 71562 71477 71570 71567 71477 71477 71491 71570 71477 71483 71491 71477 71478 71483 71487 71482 71480 71562 71484 71481 71481 71560 71562 71484 71562 71567 71559 71486 71485 71570 71491 71488 71571 71570 71488 71569 71563 71489 71489 71564 71569 71568 71564 71489 71489 71490 71568 71575 71507 71492 71576 71575 71492 71574 71495 71493 71578 71574 71493 71493 71577 71578 71493 71498 71577 71493 71494 71498 71494 71496 71498 71495 71570 71571 71574 71570 71495 71496 71497 71498 71499 71498 71497 71506 71499 71497 71498 71499 71577 71499 71500 71577 71579 71577 71500 71500 71575 71579 71500 71501 71575 71501 71507 71575 71502 71505 71508 71502 71503 71505 71504 71503 71502 71580 71505 71503 71503 71504 71580 71582 71508 71505 71505 71580 71582 71508 71582 71584 71590 71588 71511 71636 71590 71511 71511 71593 71636 71512 71518 71519 71513 71589 71596 71513 71514 71589 71515 71514 71513 71514 71587 71589 71514 71516 71587 71514 71515 71516 71594 71518 71517 71517 71524 71594 71595 71519 71518 71640 71595 71518 71518 71594 71640 71636 71593 71519 71637 71636 71519 71519 71595 71637 71520 71597 71599 71520 71596 71597 71643 71528 71521 71521 71642 71643 71521 71599 71642 71525 71523 71522 71523 71670 71696 71523 71644 71670 71645 71644 71523 71523 71525 71645 71640 71594 71524 71524 71598 71640 71525 71600 71645 71645 71600 71526 71647 71645 71526 71648 71647 71526 71649 71648 71526 71673 71601 71527 71674 71673 71527 71527 71646 71674 71527 71643 71646 71527 71528 71643 71529 71535 71536 71529 71530 71535 71651 71602 71529 71529 71650 71651 71678 71650 71529 71529 71536 71678 71604 71535 71530 71653 71534 71533 71533 71652 71653 71533 71605 71652 71534 71653 71680 71680 71654 71534 71536 71607 71678 71610 71606 71537 71537 71538 71610 71539 71540 71611 71611 71542 71539 71540 71541 71657 71657 71611 71540 71541 71655 71657 71687 71610 71543 71543 71612 71687 71543 71544 71612 71552 71549 71546 71614 71552 71546 71618 71614 71547 71547 71615 71618 71547 71548 71615 71548 71551 71615 71553 71551 71550 71551 71554 71615 71551 71553 71554 71556 71554 71553 71617 71615 71554 71554 71556 71617 71555 71626 71628 71627 71626 71555 71658 71627 71555 71555 71616 71658 71558 71569 71625 71558 71563 71569 71559 71561 71566 71561 71565 71566 71569 71565 71561 71564 71565 71569 71566 71565 71564 71568 71566 71564 71573 71572 71567 71567 71570 71573 71628 71625 71569 71574 71573 71570 71578 71576 71572 71572 71574 71578 71572 71573 71574 71575 71576 71579 71576 71578 71579 71579 71578 71577 71633 71583 71581 71581 71588 71633 71634 71584 71582 71582 71632 71634 71583 71630 71632 71633 71630 71583 71634 71585 71584 71587 71586 71585 71589 71587 71585 71634 71589 71585 71588 71590 71635 71635 71633 71588 71634 71632 71589 71632 71596 71589 71592 71591 71590 71661 71592 71590 71590 71636 71661 71590 71591 71635 71591 71592 71659 71591 71629 71635 71659 71629 71591 71663 71659 71592 71693 71663 71592 71694 71693 71592 71592 71692 71694 71592 71665 71692 71592 71661 71665 71665 71637 71595 71666 71665 71595 71595 71640 71666 71638 71597 71596 71639 71638 71596 71660 71639 71596 71596 71632 71660 71641 71599 71597 71597 71638 71641 71697 71640 71598 71598 71669 71697 71599 71641 71642 71651 71603 71602 71603 71651 71676 71603 71648 71649 71676 71648 71603 71677 71652 71605 71605 71671 71677 71608 71607 71606 71609 71608 71606 71610 71609 71606 71607 71608 71678 71717 71678 71608 71721 71717 71608 71608 71719 71721 71608 71609 71719 71609 71688 71719 71689 71688 71609 71609 71610 71689 71610 71687 71689 71691 71613 71611 71611 71687 71691 71611 71686 71687 71611 71657 71686 71691 71687 71612 71612 71613 71691 71619 71616 71614 71614 71618 71619 71620 71618 71615 71615 71617 71620 71616 71619 71658 71621 71620 71617 71622 71621 71617 71620 71619 71618 71619 71620 71658 71620 71627 71658 71620 71621 71627 71621 71624 71627 71621 71623 71624 71621 71622 71623 71625 71624 71623 71624 71626 71627 71628 71626 71624 71624 71625 71628 71629 71630 71633 71631 71630 71629 71662 71631 71629 71629 71659 71662 71629 71633 71635 71660 71632 71630 71630 71631 71660 71631 71639 71660 71631 71638 71639 71664 71638 71631 71631 71663 71664 71631 71662 71663 71636 71637 71661 71665 71661 71637 71664 71641 71638 71695 71666 71640 71697 71695 71640 71664 71642 71641 71646 71643 71642 71668 71646 71642 71642 71667 71668 71642 71664 71667 71675 71670 71644 71644 71647 71675 71644 71645 71647 71646 71668 71674 71647 71648 71675 71676 71675 71648 71707 71651 71650 71650 71678 71707 71706 71705 71651 71707 71706 71651 71705 71676 71651 71679 71653 71652 71652 71677 71679 71653 71679 71680 71656 71655 71654 71680 71656 71654 71684 71657 71655 71655 71683 71684 71655 71656 71683 71656 71680 71683 71657 71684 71686 71663 71662 71659 71667 71664 71663 71693 71667 71663 71665 71666 71692 71695 71692 71666 71701 71668 71667 71667 71693 71701 71702 71674 71668 71668 71701 71702 71700 71697 71669 71669 71696 71700 71670 71675 71696 71710 71677 71671 71671 71672 71710 71673 71672 71671 71711 71710 71672 71672 71704 71711 71672 71673 71704 71673 71702 71704 71673 71674 71702 71705 71696 71675 71675 71676 71705 71713 71679 71677 71677 71710 71713 71716 71707 71678 71717 71716 71678 71682 71680 71679 71713 71682 71679 71680 71682 71683 71685 71684 71681 71719 71685 71681 71681 71718 71719 71681 71682 71718 71683 71682 71681 71684 71683 71681 71682 71713 71718 71684 71685 71686 71690 71686 71685 71719 71690 71685 71690 71687 71686 71687 71688 71689 71690 71688 71687 71688 71690 71719 71699 71694 71692 71692 71695 71699 71703 71701 71693 71693 71694 71703 71694 71699 71703 71695 71698 71699 71695 71697 71698 71722 71700 71696 71696 71709 71722 71696 71706 71709 71696 71705 71706 71700 71698 71697 71708 71699 71698 71722 71708 71698 71698 71700 71722 71708 71703 71699 71703 71702 71701 71702 71703 71704 71708 71704 71703 71704 71708 71711 71706 71708 71709 71706 71707 71708 71716 71708 71707 71716 71711 71708 71722 71709 71708 71710 71712 71713 71710 71711 71712 71716 71712 71711 71714 71713 71712 71716 71714 71712 71713 71714 71715 71713 71715 71718 71716 71715 71714 71720 71718 71715 71715 71717 71720 71715 71716 71717 71721 71720 71717 71720 71719 71718 71719 71720 71721 caret-5.6.4~dfsg.1.orig/testing/caret_file_check.spec0000664000175000017500000000061411572067322022345 0ustar michaelmichaelBeginHeader Caret-Version 5.614 Date 2010-04-14T14:10:24 category Individual encoding ASCII space 711-2B species Human structure right subject crap surface_vector_file binary.svec EndHeader CLOSEDtopo_file closed.topo FIDUCIALcoord_file Human.colin.Cerebral.R.FIDUCIAL.TLRC.711-2B.71723.coord scene_file Human.crap.R.test.scene surface_shape_file Human.colin.Cerebral.R.71723.surface_shape caret-5.6.4~dfsg.1.orig/testing/Human.crap.R.test.scene0000664000175000017500000023114011572067322022430 0ustar michaelmichael caret-5.6.4~dfsg.1.orig/testing/Human.colin.Cerebral.R.FIDUCIAL.TLRC.711-2B.71723.coord0000664000175000017500001172421011572067322026543 0ustar michaelmichaelBeginHeader Caret-Version 5.613 Date 2010-04-09T13:46:22 comment Human.colin right hemisphere in Talairach space via 711-2B_AS (Avi Snyder) transformation configuration_id FIDUCIAL coordframe_id TAL encoding ASCII orientation LPI resolution FULL sampling ORIGINAL scale 1.000000 EndHeader 71723 0 30.670700 -0.309235 -41.573906 1 31.019333 0.381027 -41.451397 2 30.277931 0.610977 -41.290352 3 31.075775 0.742783 -41.282341 4 31.830439 0.266876 -41.099644 5 31.062462 1.423950 -40.877026 6 26.282257 -1.255203 -41.511646 7 26.865524 -1.274658 -41.678085 8 26.444489 -0.236832 -41.286728 9 27.332077 1.090347 -40.830475 10 26.074409 1.205795 -40.596626 11 28.410690 -0.415237 -41.676632 12 29.059647 0.567993 -41.256641 13 28.157974 0.460251 -41.306957 14 29.393333 -0.510971 -41.684559 15 29.903404 -1.343262 -41.655849 16 25.654999 -1.133011 -41.141506 17 28.116440 -2.045242 -41.649944 18 28.522797 -3.422409 -41.447201 19 29.068405 -2.974976 -41.585476 20 31.049469 -1.215637 -41.271671 21 27.513870 -0.418839 -41.570644 22 30.092079 -2.421371 -41.201263 23 28.521576 -4.418457 -40.573753 24 29.566803 -3.648865 -40.970276 25 28.054626 2.116943 -39.849220 26 28.436508 1.308289 -40.796444 27 29.674423 1.940430 -40.253353 28 32.450424 2.139481 -40.290447 29 34.403732 2.359222 -39.542896 30 33.217926 3.236450 -39.172241 31 32.051620 3.208771 -39.341682 32 24.355789 -0.523117 -40.536270 33 24.878632 -0.515335 -40.806149 34 24.492218 0.206512 -40.483662 35 26.533203 2.185928 -39.634178 36 25.332382 1.934113 -39.869247 37 30.836708 3.128616 -39.150936 38 30.381531 3.188713 -38.424118 39 29.811455 2.851181 -38.695362 40 31.180923 2.473938 -40.178921 41 34.039276 3.195396 -38.641235 42 33.571274 3.444885 -38.467537 43 33.700714 0.578873 -40.607944 44 35.906616 -0.333984 -40.529350 45 35.988937 0.697403 -40.278896 46 35.097870 0.850220 -40.401772 47 35.758179 1.629166 -39.732529 48 23.619568 -0.448120 -40.000317 49 25.437103 0.189240 -40.866493 50 24.886665 1.131546 -40.276966 51 32.935051 -0.757629 -40.733765 52 34.961418 -0.577286 -40.653496 53 36.773087 0.019180 -39.969391 54 25.681618 -2.196655 -40.920731 55 24.700516 -1.502075 -40.418941 56 32.060089 -1.189941 -40.863338 57 33.990105 -1.142639 -40.479950 58 35.788147 -1.156998 -40.548515 59 36.554352 1.076813 -39.739826 60 37.009018 -1.835999 -39.995010 61 26.466454 -1.954910 -41.395481 62 31.484627 -2.076889 -40.698795 63 32.898972 -1.958206 -40.100323 64 35.168518 -1.744202 -40.233459 65 26.512573 -3.082520 -40.730350 66 27.160019 -4.623428 -39.380676 67 27.673676 -3.609039 -40.924149 68 25.365555 -2.716812 -40.215702 69 23.771774 1.598907 -39.334023 70 23.769409 0.691177 -40.050461 71 25.122688 2.529953 -38.794579 72 34.755569 2.900070 -38.410194 73 35.805908 2.376678 -38.630432 74 37.017380 1.846436 -38.354797 75 36.391022 2.214447 -37.562893 76 28.794975 2.479874 -38.805779 77 36.585258 1.683456 -39.168312 78 37.478882 0.885864 -38.978851 79 22.039825 2.417694 -36.897835 80 21.962494 1.406464 -37.715420 81 22.617958 1.945770 -38.100098 82 23.303436 0.297775 -40.007805 83 37.731071 1.397949 -37.932724 84 38.577782 0.115662 -38.240860 85 38.131989 0.933929 -38.160564 86 23.909103 -1.698868 -39.701263 87 37.685913 -0.352631 -39.474010 88 24.622513 -2.547684 -39.487804 89 31.364426 -3.382980 -39.739273 90 32.961746 -2.758255 -39.105446 91 34.069275 -1.844772 -40.052685 92 34.169815 -2.466873 -39.456558 93 35.586143 -2.886185 -39.576195 94 38.403145 -1.102554 -39.335052 95 38.787712 -2.177307 -39.490547 96 23.193314 -1.473877 -39.048382 97 25.620255 -3.538834 -39.184044 98 37.717682 -3.637848 -39.833324 99 38.360992 -4.082092 -39.763603 100 38.564133 -3.276443 -39.728256 101 23.873413 -2.298553 -38.972496 102 30.838394 -4.827591 -39.337753 103 31.556488 -4.460922 -38.344543 104 35.518723 -3.734924 -38.815502 105 36.718277 -3.866943 -39.424980 106 39.005707 -4.617889 -39.398083 107 37.830505 -4.576202 -39.533783 108 38.080093 -5.420990 -39.252369 109 40.131317 -3.412415 -38.953659 110 39.627457 -1.440552 -38.427002 111 29.910416 -4.797760 -39.964260 112 39.201233 -6.323273 -38.865646 113 30.217598 -5.994720 -38.813370 114 30.926018 3.082077 -38.103176 115 31.841722 3.199158 -38.211182 116 32.912506 3.390671 -38.363888 117 26.228378 2.394608 -38.301659 118 27.489510 2.301453 -38.548447 119 28.370201 2.020950 -37.589645 120 23.063110 0.388763 -39.605892 121 22.362595 0.544662 -38.456951 122 25.422668 2.661438 -37.950554 123 22.753860 -0.507797 -39.098404 124 38.151955 0.935898 -37.230770 125 36.356987 -4.717087 -38.557915 126 41.739288 -2.139145 -37.412453 127 41.609665 -1.387634 -36.945702 128 40.687225 -1.311768 -37.214161 129 32.629227 -3.481033 -37.131996 130 32.686920 -3.316132 -38.290802 131 34.706520 -3.176651 -38.766460 132 26.092148 -4.477127 -37.640392 133 26.926041 -5.335037 -37.494297 134 37.547867 -5.663773 -38.726055 135 37.212708 -4.965393 -39.178673 136 40.261902 -5.086227 -39.019806 137 41.860306 -3.744431 -37.974655 138 40.803650 -2.374207 -38.072071 139 28.143997 -6.195114 -37.873047 140 28.734558 -5.551331 -39.354046 141 30.898033 -6.784134 -38.245834 142 31.330933 -6.977585 -37.817970 143 31.425148 -5.736511 -37.639454 144 37.220375 -6.014511 -37.289528 145 33.519394 -3.408249 -36.052864 146 33.675529 -3.774338 -34.887634 147 35.004807 -4.300934 -35.647766 148 41.085236 -7.199646 -38.754070 149 39.955193 -7.809708 -38.822418 150 41.283157 -4.846573 -38.546394 151 41.183578 -6.045898 -38.661957 152 42.366440 -5.660141 -37.725594 153 38.770157 -7.456314 -38.176956 154 42.031342 -7.769257 -38.063446 155 41.122070 -8.249298 -38.673645 156 39.572876 -8.523117 -38.209023 157 40.339050 -8.487259 -38.795971 158 41.915527 -9.200912 -37.647179 159 29.245560 2.540024 -37.930672 160 30.131836 2.558670 -37.637516 161 33.994095 3.073387 -37.705460 162 23.756866 2.595352 -38.221226 163 24.700150 3.200302 -37.096016 164 23.811165 4.533630 -36.630112 165 23.110428 3.139915 -37.277023 166 25.740036 2.357986 -37.260952 167 29.245445 1.969193 -37.179535 168 35.311691 2.694717 -37.596291 169 34.754158 2.502930 -36.668022 170 21.784439 0.798096 -36.976707 171 27.004288 1.625473 -36.873753 172 37.188599 1.815552 -37.486008 173 37.535477 1.389404 -36.957825 174 21.972633 -0.054688 -37.754444 175 39.457199 -0.440308 -36.921371 176 38.611931 0.318512 -36.642563 177 44.709549 -0.846909 -37.352898 178 44.304626 -0.057144 -37.023750 179 42.974609 -0.960815 -36.703205 180 46.021591 0.308197 -37.391361 181 46.716400 0.510849 -37.265160 182 46.415070 1.187744 -36.630718 183 47.502563 0.219269 -36.704166 184 45.199280 -0.145447 -37.408607 185 45.106049 0.662109 -36.847137 186 45.801331 -0.730362 -37.488075 187 46.734238 -0.276108 -37.350639 188 48.966858 0.007004 -35.198353 189 47.900192 1.307526 -35.936176 190 48.986847 1.513458 -34.782219 191 22.465012 -0.857834 -38.117134 192 45.126526 -1.889267 -37.097015 193 46.449371 -1.169662 -37.234837 194 46.532043 -1.708679 -36.970757 195 23.428955 -2.124268 -38.076767 196 22.711334 -1.357483 -36.955017 197 23.981667 -2.732727 -36.769516 198 24.478195 -2.912216 -38.349495 199 33.775909 -2.984573 -38.504627 200 43.106125 -2.886719 -37.251740 201 43.169250 -4.516907 -37.127937 202 43.220413 -5.927750 -36.521488 203 43.993073 -5.158157 -35.934769 204 29.332878 -6.663513 -38.227497 205 28.998894 -6.241043 -38.680069 206 31.855547 -6.806763 -36.845367 207 29.304169 -7.271515 -37.339928 208 30.197113 -7.097549 -38.091362 209 42.086380 -6.830582 -38.049774 210 41.962646 -10.676010 -37.520454 211 42.518677 -10.108826 -36.969681 212 30.878098 -7.353409 -37.939304 213 39.308838 -8.900024 -37.067177 214 39.828720 -9.712814 -37.270294 215 40.420105 -9.648941 -37.840588 216 40.682831 -8.917496 -38.446205 217 41.353271 -10.353577 -37.838253 218 40.874802 -11.013763 -36.105534 219 40.687119 -10.966141 -35.112881 220 41.841843 -12.199478 -34.730038 221 27.366173 10.503296 -35.920101 222 28.348534 9.697754 -36.250439 223 29.082230 11.512726 -35.571159 224 29.399689 9.953552 -36.047287 225 24.492554 7.749054 -36.546501 226 25.623276 7.995117 -36.556519 227 24.713608 9.156723 -35.722168 228 27.339661 9.129547 -36.359276 229 28.059639 7.822815 -36.286179 230 26.216301 9.422363 -36.164661 231 25.286362 10.348831 -35.203484 232 26.824684 7.890137 -36.509460 233 29.264374 8.757568 -36.152599 234 29.979324 9.359589 -35.882309 235 30.572693 10.131592 -35.347450 236 23.505295 7.231476 -36.637245 237 22.815582 7.529312 -36.312603 238 22.751480 6.636536 -36.662941 239 23.425446 8.348343 -35.796356 240 22.362442 6.910950 -36.237770 241 24.454773 6.135620 -36.700733 242 26.212914 6.771973 -36.568497 243 29.419960 7.343964 -35.806656 244 30.740234 7.160034 -35.323540 245 30.598335 8.535217 -35.432987 246 23.268387 5.810837 -36.730793 247 22.648056 5.737091 -36.673645 248 25.272133 6.870590 -36.715500 249 27.186203 6.693466 -36.242271 250 22.273788 5.937408 -36.383614 251 21.959473 6.377060 -35.745693 252 25.325485 5.205048 -36.281139 253 25.136909 4.230225 -36.221581 254 25.571457 6.071609 -36.538021 255 26.535385 5.755432 -36.128029 256 22.426292 4.879044 -36.315388 257 22.554283 3.745033 -36.596916 258 31.503174 2.132965 -36.887623 259 32.815689 2.839493 -37.261810 260 33.719849 2.549805 -36.667870 261 35.769676 2.269516 -36.808567 262 35.569290 1.783524 -35.907921 263 34.092636 1.693893 -35.696667 264 21.586281 2.087357 -35.470364 265 25.870232 2.572311 -35.780602 266 25.454369 2.675644 -36.410542 267 26.093765 1.969467 -36.496971 268 26.502502 1.824554 -35.854374 269 28.630943 0.993073 -36.116196 270 27.039032 1.342758 -35.876690 271 30.071915 1.396561 -36.556137 272 36.677574 1.717407 -36.550278 273 45.305939 1.358688 -35.769684 274 47.026871 1.927429 -35.753330 275 48.084778 2.032852 -35.119602 276 46.190430 1.763733 -35.992340 277 26.491661 1.625671 -36.485657 278 29.928963 0.232300 -35.263161 279 29.112953 0.355942 -34.896202 280 40.280594 -0.773697 -35.937405 281 41.426331 -0.963821 -36.328026 282 44.358643 0.555801 -36.735573 283 44.481995 0.877243 -36.337452 284 43.876251 0.348129 -36.407494 285 22.102432 -0.369553 -37.161446 286 41.283539 -0.772614 -35.429367 287 42.191315 -0.545883 -35.565117 288 43.481567 0.235123 -35.611164 289 47.173065 -1.067398 -36.895645 290 42.811066 -0.219742 -35.645634 291 46.673462 -2.384949 -36.280075 292 48.143814 -1.955933 -35.236103 293 47.987335 -1.053848 -36.064362 294 31.935564 -4.146713 -36.898331 295 34.505417 -3.729477 -37.567871 296 46.038879 -3.852478 -34.735050 297 45.540894 -3.852539 -35.592934 298 44.796997 -5.087326 -34.165283 299 47.398621 -2.659561 -35.242237 300 25.152802 -3.645218 -37.580124 301 44.563812 -3.698425 -36.583580 302 30.388107 -7.731033 -37.374584 303 31.780474 -7.990250 -37.119572 304 31.241776 -7.656189 -37.470291 305 31.093582 -8.413437 -36.872288 306 32.262985 -7.856461 -36.748623 307 32.564606 -7.290665 -35.931938 308 38.535614 -7.788803 -37.378597 309 32.143425 -8.727600 -36.597137 310 42.702347 -7.379807 -36.888515 311 42.494553 -10.913788 -36.663197 312 40.128265 -10.078201 -37.316025 313 40.809021 -10.667511 -37.354229 314 41.474335 -11.098663 -37.560295 315 41.624329 -11.231583 -37.021179 316 41.430222 -10.865616 -37.739464 317 26.609924 11.813354 -33.707176 318 26.103409 11.431320 -34.274818 319 27.246948 12.141068 -34.815544 320 28.286972 12.664001 -35.234360 321 28.959900 13.097061 -35.058411 322 28.141479 13.295761 -34.796608 323 29.640800 12.718811 -35.209309 324 30.063538 13.307556 -34.468273 325 29.630898 14.863586 -33.009151 326 29.751251 15.470505 -32.302395 327 28.875580 15.226471 -32.576633 328 25.978012 11.169571 -34.961464 329 26.365730 10.797165 -35.553684 330 31.593292 10.610199 -34.364437 331 30.824326 11.385132 -35.013107 332 31.663439 11.427475 -34.169769 333 31.128860 12.292648 -34.422691 334 23.490097 9.402451 -34.407421 335 22.685707 8.546753 -34.360920 336 30.249962 12.308884 -35.105423 337 39.964775 9.745560 -34.923340 338 38.906860 9.511169 -34.432487 339 40.164337 8.927505 -34.666473 340 39.416138 10.474091 -34.544983 341 40.410309 10.403900 -34.950012 342 40.636230 11.787949 -34.359642 343 38.457825 12.706268 -33.596214 344 38.426903 11.194580 -33.735741 345 41.031525 10.411835 -34.899612 346 40.788940 9.786148 -34.976311 347 41.960648 9.863998 -34.534714 348 43.646011 10.501434 -34.089920 349 42.921844 11.903259 -33.980328 350 24.626930 10.556488 -34.272739 351 24.197968 10.109436 -34.340199 352 31.830851 9.369843 -34.095207 353 22.394058 7.561981 -35.442467 354 29.906570 5.999428 -35.244560 355 22.104950 7.726334 -34.307751 356 21.721718 6.660782 -34.697441 357 28.003761 5.716263 -35.583923 358 28.936981 4.401321 -34.735199 359 30.817047 6.439163 -35.142792 360 30.969917 5.829895 -34.727486 361 21.588943 5.728561 -35.288841 362 21.876114 5.486328 -35.928062 363 21.643036 4.879234 -35.349091 364 21.771255 3.661896 -35.652409 365 26.319725 4.459862 -35.639912 366 25.555099 3.437981 -35.927166 367 32.934402 2.070267 -36.369701 368 35.511581 0.711075 -34.590927 369 33.625961 0.535568 -34.366386 370 21.630630 0.873642 -35.929413 371 46.285919 1.972107 -35.377579 372 45.855606 1.867676 -34.724327 373 47.157990 2.372742 -34.432098 374 27.597061 1.099915 -35.737808 375 37.582123 0.737976 -35.821739 376 44.251495 0.855331 -35.715984 377 22.095688 -0.094589 -35.829857 378 28.382057 1.116867 -34.687279 379 32.020844 0.327499 -34.653252 380 31.157112 0.783936 -35.727791 381 32.582741 1.236664 -35.650574 382 36.464256 0.138931 -34.145325 383 37.411644 -0.223221 -34.218102 384 36.214584 -0.418137 -33.209064 385 38.933777 -0.423325 -35.176357 386 22.881172 -1.406677 -35.471451 387 40.677505 -0.978195 -34.590622 388 48.700256 -1.182373 -35.163689 389 23.791092 -2.325012 -34.656799 390 24.172859 -2.123642 -33.243793 391 24.871399 -3.540848 -33.760448 392 32.507431 -3.528625 -36.157406 393 46.974045 -3.316803 -34.499420 394 46.604126 -3.148605 -35.389313 395 25.165550 -3.975754 -35.946758 396 26.276886 -5.181076 -36.259647 397 44.708679 -4.533005 -35.657467 398 26.600037 -5.928391 -35.240639 399 25.799149 -4.956924 -34.754501 400 26.231674 -5.804413 -33.950985 401 27.197128 -6.112640 -36.402489 402 28.216354 -7.216354 -36.100662 403 29.716232 -8.345184 -36.074421 404 32.718369 -8.262848 -36.293175 405 38.180481 -7.466888 -36.135330 406 32.789185 -8.915756 -36.330940 407 33.118652 -8.810654 -35.967628 408 39.960899 -9.891434 -36.565456 409 31.274261 -9.333511 -35.986061 410 32.828941 -9.670456 -35.784649 411 43.668137 -6.733292 -33.962021 412 43.488281 -6.883820 -35.280624 413 43.659729 -8.098312 -34.184700 414 43.197418 -9.612671 -35.694107 415 42.094345 -11.689545 -36.104794 416 42.872787 -11.528290 -35.806328 417 28.855179 14.034409 -34.095993 418 31.415009 12.945099 -32.980827 419 37.724075 13.736359 -33.217659 420 36.514954 13.856201 -31.994961 421 36.908737 12.910904 -32.271408 422 39.055077 15.829254 -33.133541 423 38.182617 15.969681 -32.934380 424 38.133301 14.892975 -33.265976 425 39.896904 13.730988 -33.945610 426 41.022415 14.145126 -33.813103 427 40.048584 15.226685 -33.432251 428 41.113815 15.820160 -33.090923 429 39.983566 16.911713 -32.584442 430 27.882523 13.594620 -34.133476 431 27.114639 12.458160 -33.429523 432 27.524887 13.226196 -33.563358 433 30.914932 14.444977 -32.225166 434 30.157761 14.111526 -33.477486 435 38.953690 14.354172 -33.633793 436 42.004974 13.214172 -33.918335 437 42.253723 14.647537 -33.331184 438 31.748560 11.951385 -33.712311 439 43.087952 13.401764 -33.495041 440 25.778839 11.069702 -33.172215 441 43.650436 14.408005 -32.819817 442 44.500153 12.817001 -33.011547 443 25.274498 10.878433 -34.229988 444 38.262466 10.189926 -33.922474 445 38.605911 8.485626 -34.216194 446 36.976425 6.878754 -32.655518 447 37.819023 6.636963 -33.505623 448 37.561783 7.973053 -33.464439 449 43.691727 9.368103 -34.191723 450 45.038895 10.006546 -33.517872 451 46.635681 10.852570 -32.463234 452 45.353607 11.500519 -33.033985 453 31.753954 7.665771 -34.442513 454 32.465233 8.352081 -33.244656 455 39.662659 7.627136 -34.268997 456 40.119171 6.644836 -33.541893 457 40.904312 7.369171 -33.976639 458 41.261658 8.203354 -34.370346 459 42.839951 8.484344 -34.171410 460 43.751495 8.685699 -34.159561 461 44.410126 8.785233 -33.794197 462 38.399078 7.491333 -34.038895 463 38.853951 6.640137 -33.842613 464 43.729630 8.268799 -33.831707 465 31.354996 6.684708 -34.862328 466 31.833048 6.370209 -34.159515 467 39.356842 5.905685 -33.475445 468 40.169006 5.672241 -32.779800 469 21.674408 4.418335 -34.213879 470 21.681915 3.348816 -34.391548 471 31.463898 4.929939 -33.716846 472 30.248726 4.648987 -34.335640 473 32.427017 7.183136 -33.347820 474 32.404655 5.876701 -32.996513 475 27.429611 3.438828 -34.858070 476 28.437332 3.135910 -34.251724 477 26.274055 3.217094 -35.328388 478 29.504944 3.171959 -33.906555 479 26.210632 2.526764 -35.383114 480 21.828262 2.674622 -33.988575 481 21.885620 1.706680 -34.178436 482 21.718536 0.988785 -35.159084 483 36.446564 1.106140 -35.492107 484 45.903366 2.226379 -33.686954 485 28.000412 2.179108 -34.329117 486 27.306740 1.806030 -35.085892 487 30.905426 0.050705 -34.673950 488 36.697281 0.489212 -34.819763 489 44.531387 1.094986 -34.456123 490 48.540237 2.383881 -34.041500 491 29.607574 0.072937 -34.542831 492 31.244919 0.127899 -33.319675 493 42.069931 -0.733536 -34.475815 494 43.114319 0.008682 -34.534615 495 50.040863 -0.162323 -34.045811 496 49.755554 0.810272 -34.251293 497 39.520340 -1.222061 -33.851295 498 38.419006 -0.831406 -33.856773 499 41.879211 -1.195801 -33.646423 500 40.888626 -1.638306 -33.342384 501 49.460022 -1.713440 -33.832451 502 50.563446 -0.697693 -33.259914 503 32.850235 -4.178497 -34.558128 504 32.330887 -4.860046 -34.702927 505 32.914841 -4.934204 -33.866890 506 32.916321 -3.533081 -35.459824 507 32.876389 -3.792206 -35.036724 508 26.810394 -6.498032 -34.359451 509 32.195076 -4.584351 -35.728882 510 27.264648 -6.657578 -35.341381 511 32.377014 -5.920441 -35.045338 512 33.044861 -7.002060 -34.524395 513 32.978790 -5.977386 -33.539223 514 33.172676 -8.042297 -35.447388 515 39.155319 -8.712814 -35.660053 516 38.228798 -7.205933 -34.541897 517 33.582687 -9.009308 -35.295525 518 31.659685 -10.184219 -35.300957 519 30.372940 -9.844879 -34.854172 520 32.670151 -10.899994 -34.960365 521 33.699501 -9.810638 -35.450020 522 34.078537 -9.712845 -35.027885 523 38.057678 -6.593994 -33.246880 524 38.685623 -7.572800 -33.615883 525 39.972015 -9.831299 -35.135712 526 29.388519 -9.880844 -33.730553 527 29.194687 -8.990341 -34.641666 528 28.330017 -8.690247 -33.598640 529 31.401260 -10.789520 -34.536171 530 33.917175 -10.624573 -35.058861 531 43.639542 -11.571426 -35.010410 532 44.600220 -10.371155 -34.394260 533 42.810547 -12.300461 -35.198528 534 43.257568 -12.907288 -34.287666 535 42.443298 -12.134415 -35.569855 536 35.740997 16.218369 -31.227036 537 36.437721 15.037445 -32.083603 538 36.730957 16.381195 -32.063637 539 37.616806 16.442261 -32.502544 540 38.588760 17.054565 -32.438812 541 42.081757 16.013947 -32.811455 542 41.441284 17.319550 -32.188744 543 42.785553 16.516815 -32.175236 544 42.665680 17.450317 -31.642342 545 28.217728 14.318085 -33.116364 546 30.463737 15.161713 -32.185539 547 42.963165 15.509079 -32.673153 548 30.339851 15.471390 -31.831886 549 37.223000 14.490982 -32.852394 550 37.356606 15.473434 -32.765179 551 43.928833 15.927429 -31.529255 552 44.749039 14.280365 -32.022453 553 27.376450 13.098831 -32.258743 554 44.296753 11.354279 -33.588585 555 45.827728 12.611481 -32.165993 556 24.348106 10.564133 -33.156166 557 23.407326 10.126862 -31.725098 558 24.089386 10.309509 -30.837692 559 23.437134 10.309875 -30.888069 560 37.735329 9.231995 -33.544495 561 32.108337 10.932159 -32.968937 562 37.257690 10.167465 -32.683228 563 46.313522 9.592224 -33.044296 564 46.914749 9.722549 -32.741505 565 22.456238 8.751434 -31.880424 566 22.233047 7.970795 -33.007912 567 22.844864 9.306702 -32.846954 568 21.862823 7.133484 -33.767036 569 32.623405 9.359222 -32.478638 570 36.967949 11.630295 -32.151527 571 36.035469 9.818024 -30.011894 572 45.646729 8.689270 -33.102283 573 46.820267 9.009567 -32.699135 574 46.626358 8.229156 -32.305782 575 47.496017 9.686996 -32.282349 576 41.944824 7.691620 -33.870743 577 44.364670 8.053101 -33.147354 578 32.824280 6.929398 -32.257675 579 36.897919 8.595398 -32.381596 580 41.124298 6.447815 -32.403145 581 41.559830 7.115204 -33.272102 582 43.002502 7.664169 -33.296623 583 42.411774 7.148529 -32.251572 584 21.577530 5.652939 -34.193161 585 38.501305 5.672546 -33.422363 586 40.040314 4.403114 -32.320751 587 40.847275 5.512115 -31.676903 588 21.637665 6.476456 -33.886681 589 32.341827 4.731422 -32.558502 590 37.615845 5.251022 -32.695240 591 39.296516 5.089859 -33.092403 592 30.768379 3.472595 -33.331322 593 26.654427 2.544724 -35.138313 594 47.819885 2.973145 -33.126545 595 48.770996 2.684097 -33.238464 596 46.776337 2.864288 -33.273254 597 50.968231 0.752335 -31.138351 598 51.107559 0.378586 -30.149483 599 49.976700 1.190262 -30.034096 600 49.706604 1.778854 -33.165726 601 22.608894 -0.442734 -34.397118 602 22.193535 0.655289 -34.302269 603 22.796555 0.323822 -33.448948 604 33.481659 -0.164032 -32.658298 605 32.548904 0.017181 -33.525024 606 43.693588 0.703308 -32.820072 607 44.872253 2.070770 -32.682110 608 50.329330 0.561096 -33.557365 609 29.524460 0.748901 -33.876842 610 28.428642 1.800766 -34.039177 611 42.827133 -0.588440 -33.033226 612 50.489838 -0.045563 -33.643589 613 23.071724 -1.284409 -34.412987 614 31.832476 1.027802 -31.645409 615 31.340622 0.646454 -32.247208 616 32.211029 0.193588 -32.176277 617 30.218994 0.090652 -34.087845 618 34.780563 -0.205231 -33.069935 619 40.518036 -2.033691 -32.672462 620 39.608223 -1.705933 -32.908813 621 41.982330 -1.461868 -32.535454 622 50.668091 0.077255 -33.310780 623 48.025146 -2.666382 -34.212200 624 34.765129 -4.490891 -34.012634 625 47.506638 -3.537170 -33.422062 626 36.570366 -5.615601 -34.819374 627 44.453064 -7.195953 -32.772072 628 43.965164 -7.523254 -33.252941 629 45.069611 -8.494171 -33.497856 630 46.243515 -4.182434 -33.618790 631 27.553360 -7.405884 -34.303749 632 33.614456 -7.980484 -34.328896 633 43.591187 -7.169510 -33.481712 634 28.539452 -8.164734 -34.938789 635 34.157242 -8.953232 -34.288269 636 34.083725 -8.091797 -33.340351 637 39.148888 -8.491089 -34.501999 638 34.574142 -9.993332 -34.333847 639 40.558350 -10.666489 -34.063896 640 35.091331 -10.711975 -34.175079 641 35.120316 -10.083038 -33.456436 642 34.723976 -10.944748 -34.657059 643 44.113312 -9.284439 -34.381752 644 32.080704 -11.297119 -34.452717 645 32.601532 -11.723969 -34.358994 646 33.578339 -11.842422 -34.599525 647 34.512390 -13.086777 -33.836159 648 35.773895 -14.446075 -33.641159 649 36.274529 -13.055847 -33.640392 650 34.471924 -11.687393 -34.655113 651 35.097458 -11.600067 -34.230175 652 35.816399 -11.991821 -33.566177 653 44.817566 -12.001831 -34.013916 654 37.696274 19.921051 -30.364319 655 39.017700 20.218292 -30.438908 656 38.083786 20.575989 -29.835011 657 39.247025 18.178589 -31.933151 658 39.772690 19.209793 -31.289051 659 38.597313 19.153015 -31.216087 660 40.268616 18.195709 -31.894318 661 41.050735 19.076630 -31.202568 662 41.968262 18.260880 -31.503731 663 42.641541 18.423538 -30.795654 664 38.111893 18.188065 -31.781456 665 37.429489 17.377045 -31.983688 666 41.924683 18.955505 -30.964256 667 43.382690 17.378891 -30.864990 668 43.302582 16.837448 -31.613739 669 27.977585 15.083313 -31.694912 670 29.010498 15.591400 -31.938187 671 29.813690 15.748505 -31.285130 672 45.680939 14.236725 -31.046082 673 44.868408 15.112778 -31.138657 674 31.641069 13.724396 -31.177773 675 32.213585 11.887482 -31.045227 676 32.653351 10.268311 -31.497330 677 32.704460 10.527695 -30.453529 678 45.308167 13.478210 -32.120316 679 26.850601 11.597565 -32.695885 680 26.232208 10.750107 -32.160923 681 25.029266 10.508499 -31.810059 682 47.485046 11.658264 -31.499985 683 46.783859 12.812042 -31.182175 684 47.791992 10.608871 -31.796570 685 48.381348 11.424896 -30.792862 686 23.493813 10.021133 -33.194225 687 32.824211 8.539505 -32.290604 688 47.487900 8.735382 -31.999428 689 48.703156 9.399231 -31.033566 690 32.797333 7.877808 -32.445862 691 45.516144 7.813751 -32.204769 692 21.924622 6.440033 -33.001312 693 36.430130 7.337128 -31.392250 694 36.786865 5.663116 -31.682003 695 43.865433 7.567871 -32.159233 696 47.120193 7.701691 -30.693596 697 22.664116 1.392014 -33.236923 698 21.934464 5.182617 -33.196812 699 32.986771 5.630768 -31.152748 700 39.135361 4.218506 -32.765533 701 38.543060 4.771286 -33.003258 702 31.888277 3.650993 -32.584011 703 38.393646 3.953041 -32.453293 704 28.610580 2.426437 -33.934029 705 30.202026 1.974258 -33.105701 706 31.283844 2.589294 -32.453606 707 29.082748 1.818787 -33.812759 708 37.519547 3.977219 -31.512283 709 38.540070 2.861053 -31.579613 710 39.348198 3.316971 -32.151196 711 45.947754 2.852890 -32.616074 712 46.823639 3.301605 -32.294830 713 48.723755 2.829468 -32.342598 714 47.578644 3.337158 -31.828777 715 22.424355 2.402008 -33.212818 716 43.710175 1.882629 -31.868156 717 50.418198 1.429382 -31.660187 718 49.487457 2.239639 -31.418514 719 23.493805 -0.896088 -33.361813 720 32.437675 0.871704 -31.198700 721 36.717377 -1.277344 -31.496258 722 35.452980 -0.793762 -32.100124 723 51.653915 -0.389893 -31.078495 724 24.478203 -1.399689 -32.425598 725 25.021988 -2.522461 -32.363556 726 37.620270 -0.944870 -33.014587 727 38.691315 -1.307190 -33.157444 728 50.816467 0.367599 -32.482689 729 51.194901 -1.433701 -32.247520 730 41.223480 -1.948029 -32.709881 731 42.402328 -0.707840 -31.516655 732 41.714249 -1.386826 -31.306271 733 49.562469 -2.977158 -32.840660 734 50.514435 -2.468155 -32.626877 735 50.522385 -1.657288 -33.010490 736 41.030045 -1.927734 -31.939827 737 48.632782 -2.955215 -33.327148 738 48.632065 -3.932327 -32.673798 739 33.649658 -5.373993 -32.582352 740 33.401840 -6.037766 -32.375168 741 33.790840 -6.201950 -31.928593 742 34.717857 -5.770248 -31.472153 743 33.619995 -4.220886 -33.974808 744 33.914841 -4.618317 -33.287514 745 34.817673 -4.970016 -32.673626 746 25.820007 -4.961334 -32.645142 747 25.694962 -4.878067 -33.396400 748 25.617691 -4.061890 -32.386307 749 35.860794 -5.107101 -33.330914 750 45.280304 -5.083801 -32.710007 751 45.531799 -4.665817 -33.204216 752 47.169403 -4.428741 -32.683334 753 46.094162 -4.680267 -32.625896 754 26.818497 -6.472214 -32.595963 755 37.126465 -5.862839 -33.367016 756 36.155945 -5.542862 -31.962833 757 33.231842 -6.010529 -32.735165 758 33.525742 -6.872910 -32.899040 759 27.447418 -7.838318 -32.883774 760 46.305786 -7.159485 -32.816910 761 46.962463 -8.456055 -33.341988 762 47.613770 -6.921982 -32.868259 763 48.076447 -8.055191 -33.264210 764 48.933929 -6.986664 -32.785324 765 48.840775 -8.524002 -33.307518 766 49.818237 -8.166336 -32.945580 767 50.684967 -8.088501 -32.331642 768 50.483932 -9.066284 -32.942204 769 34.686676 -9.047089 -32.987007 770 34.284508 -7.729446 -32.129601 771 39.570061 -8.875076 -33.536201 772 39.571472 -8.639847 -32.368610 773 38.611038 -7.193024 -32.294693 774 49.377670 -10.055466 -33.320808 775 50.874710 -10.278610 -33.052872 776 49.959900 -11.283218 -33.252113 777 50.734238 -11.209915 -33.274067 778 50.334564 -6.785355 -31.978706 779 49.577271 -5.766586 -32.266010 780 28.614899 -9.844284 -32.640175 781 35.582321 -10.022888 -32.176807 782 40.209106 -9.863983 -32.746353 783 47.996796 -9.642242 -33.449631 784 51.065155 -9.088547 -32.167755 785 51.095276 -11.056351 -33.184681 786 35.531769 -10.918625 -33.428226 787 41.295227 -11.809189 -33.551655 788 40.815521 -10.956161 -33.038044 789 40.782532 -10.804459 -31.850391 790 41.253479 -11.768524 -32.642807 791 46.064468 -12.200821 -33.222603 792 46.448166 -10.632568 -33.570625 793 51.385895 -10.942917 -32.830296 794 51.466110 -10.217056 -32.167290 795 30.371925 -10.895386 -33.725098 796 31.530479 -11.735931 -33.820724 797 36.802460 -12.253510 -32.835106 798 36.309875 -11.272141 -32.416908 799 48.155792 -11.294617 -33.169926 800 49.090530 -11.322418 -33.194622 801 51.364471 -12.616043 -32.170334 802 50.529785 -12.100616 -32.711147 803 50.856308 -14.170074 -31.184383 804 52.001434 -12.603363 -31.680321 805 32.621834 -12.655487 -33.677910 806 41.765289 -12.528320 -33.712601 807 51.660767 -11.518997 -32.181732 808 36.853088 -15.138687 -33.720600 809 37.522560 -14.810211 -33.706329 810 37.192459 -13.965256 -33.485519 811 37.016342 -12.959106 -33.276814 812 35.940620 -15.755539 -33.239067 813 42.454971 -13.140320 -34.112629 814 42.104965 -13.087296 -33.664902 815 45.185608 -13.121017 -33.205662 816 44.249512 -13.262711 -33.679440 817 37.452362 -12.964569 -32.586052 818 38.242950 -14.091339 -32.566349 819 37.940903 -14.637833 -33.396320 820 37.895912 -13.111313 -31.817520 821 38.350410 -13.806030 -30.965965 822 42.671021 -13.521210 -33.634075 823 43.480682 -13.982437 -33.093277 824 44.462112 -13.761597 -33.211861 825 48.140350 -12.817764 -32.358204 826 48.099976 -12.166672 -32.790245 827 47.219543 -12.153458 -32.913673 828 32.783844 -14.099319 -32.149429 829 36.893387 -15.812393 -33.524178 830 37.784119 -15.502960 -33.396790 831 38.435165 -14.894989 -33.049374 832 40.253357 20.104752 -30.655334 833 41.006958 20.024429 -30.587193 834 40.841949 20.504013 -30.109108 835 41.943375 19.867981 -29.878662 836 37.382874 18.898621 -31.066406 837 37.012955 20.773956 -28.992950 838 36.363647 19.473175 -30.063267 839 36.441406 17.923660 -31.152115 840 37.312836 18.152405 -31.522167 841 27.146042 15.234772 -30.139847 842 28.481804 16.179077 -30.148411 843 29.782196 16.053101 -30.178459 844 30.608673 15.410706 -30.450249 845 30.794250 15.360992 -29.430908 846 35.041779 16.623108 -30.546654 847 34.711105 17.570068 -30.035706 848 34.435120 16.547272 -29.728134 849 35.401825 17.641373 -30.545715 850 29.153244 16.151733 -30.790260 851 28.829529 15.884323 -31.265076 852 30.804642 15.113083 -31.333248 853 35.751579 14.657837 -31.007473 854 44.734314 15.617676 -30.046898 855 44.035172 16.388901 -28.980766 856 43.963715 16.996338 -29.882004 857 31.930269 13.402527 -29.488762 858 31.284576 14.538010 -31.236603 859 35.094223 15.590240 -30.418251 860 47.667725 12.605499 -30.659195 861 47.223450 13.451904 -30.050766 862 27.053375 14.193314 -31.080635 863 47.616653 13.242874 -29.818619 864 27.023254 13.104767 -30.904366 865 27.383560 11.571976 -31.959187 866 46.577805 14.090546 -29.967079 867 48.225800 12.609711 -29.799690 868 23.162415 10.053314 -30.905525 869 24.191093 9.845032 -29.994362 870 23.407990 9.944031 -30.445179 871 27.186485 10.692886 -31.726337 872 27.744865 10.918427 -31.270370 873 27.505157 11.879684 -31.175674 874 27.781876 10.451324 -31.297829 875 27.970261 10.471710 -30.880199 876 49.524353 10.714874 -29.921944 877 48.935547 11.823151 -29.868546 878 22.761490 9.482178 -31.778145 879 26.295425 10.204346 -31.257965 880 27.643280 9.977997 -30.595219 881 27.658417 8.939728 -29.693886 882 27.153282 8.547165 -29.416985 883 26.871201 8.850433 -29.612534 884 32.883118 8.604858 -30.884869 885 47.029129 13.703125 -28.662102 886 36.253036 7.093155 -29.750092 887 22.343857 7.063629 -31.290051 888 22.314301 5.442154 -32.160942 889 32.722885 9.375534 -29.610657 890 32.794296 10.249939 -29.567554 891 42.783447 7.473618 -31.307110 892 43.704346 7.716629 -31.179085 893 42.931320 7.759979 -30.460716 894 44.029984 7.765930 -30.505222 895 44.925278 7.607239 -31.207279 896 23.210297 9.043793 -29.570587 897 22.484795 8.022644 -30.090603 898 22.813095 9.165878 -30.900906 899 41.636597 6.751434 -30.833717 900 42.224213 7.465225 -30.556610 901 33.576340 5.133759 -29.154373 902 33.356430 7.292999 -28.930202 903 22.484451 3.762543 -32.856415 904 32.728317 3.946228 -31.587666 905 23.520523 3.875687 -31.603634 906 23.514992 3.254822 -32.061821 907 22.832550 4.654381 -31.785938 908 24.420982 2.889709 -31.122818 909 23.572845 2.192108 -32.314293 910 46.988541 3.637665 -31.752426 911 46.880814 3.785248 -31.504662 912 46.688568 3.601334 -31.560081 913 47.071762 3.652985 -31.442421 914 32.544907 2.202377 -31.122219 915 40.426178 2.974823 -31.763863 916 39.711037 1.991867 -31.177742 917 41.305206 1.927948 -31.400555 918 41.230286 3.974098 -31.293003 919 41.130493 2.847412 -31.595062 920 45.274643 2.845703 -32.095837 921 44.351532 3.121155 -31.370758 922 45.948486 3.291702 -31.676857 923 48.325623 2.974472 -31.230473 924 24.575104 0.824280 -31.890293 925 23.543236 0.618454 -32.689102 926 31.145660 1.452332 -32.246185 927 38.075104 2.648727 -30.790604 928 37.394028 3.456970 -30.123817 929 41.533981 2.801575 -31.465111 930 42.451752 2.657364 -31.353504 931 24.467628 -0.356033 -32.189674 932 30.440857 0.780792 -33.065460 933 30.922531 0.717499 -32.587601 934 42.657501 1.027527 -31.550812 935 42.988770 0.030304 -31.952305 936 35.181572 -0.895889 -30.365101 937 35.322014 -1.056030 -31.332245 938 34.428116 -0.596146 -31.463440 939 34.109573 -0.074020 -30.043030 940 33.191086 0.191971 -31.071346 941 38.470490 -1.590347 -32.270691 942 39.721985 -1.991043 -32.007202 943 48.255310 2.378448 -30.176758 944 40.197540 -1.748016 -30.970078 945 51.427399 -3.009705 -31.636757 946 50.315643 -3.832321 -32.153934 947 49.546906 -4.776581 -32.229591 948 48.197693 -5.366669 -32.518494 949 51.965698 -1.769760 -31.307510 950 26.152710 -5.125443 -32.135918 951 47.270416 -5.092880 -32.376755 952 46.614960 -5.118271 -32.257668 953 52.113953 -2.789536 -30.911221 954 51.895233 -4.040344 -30.752609 955 26.081207 -5.541626 -32.903717 956 37.213150 -5.863892 -31.351101 957 37.535843 -6.041550 -32.301937 958 44.106110 -6.398758 -32.935368 959 44.644943 -5.601761 -32.690384 960 45.843445 -5.247009 -32.217827 961 47.014709 -5.896301 -32.467560 962 45.208679 -6.887909 -32.578922 963 46.021652 -5.991760 -32.276527 964 45.102585 -5.868378 -32.261154 965 44.560089 -6.491028 -32.381470 966 34.668198 -7.563263 -31.049324 967 34.281097 -6.779739 -31.372902 968 44.490265 -6.034103 -32.351254 969 51.324097 -5.839813 -30.254395 970 50.506210 -5.201233 -31.692532 971 50.938873 -7.788071 -31.326721 972 50.817322 -9.371780 -30.853645 973 29.389130 -10.966705 -32.798119 974 35.121544 -8.694595 -31.328415 975 29.233521 -12.012070 -31.516739 976 30.492401 -12.190857 -32.705360 977 51.607071 -10.684540 -31.507973 978 31.146034 -13.412247 -31.769798 979 30.031479 -13.031982 -31.103615 980 30.713928 -13.714447 -30.869160 981 31.491348 -12.465210 -33.320396 982 41.747147 -12.611435 -32.991444 983 46.508698 -13.337143 -32.450218 984 49.284424 -13.155853 -32.002533 985 49.201920 -12.630814 -32.506187 986 49.010681 -12.068466 -32.889473 987 31.627504 -13.028625 -32.800468 988 42.315063 -13.468689 -32.844860 989 52.387390 -13.431747 -31.322330 990 52.705933 -12.736526 -31.065914 991 38.750519 -14.837418 -32.619492 992 34.521362 -15.059906 -32.689381 993 35.076736 -16.246307 -32.172222 994 38.784302 -15.637772 -32.661110 995 44.851105 -15.163040 -32.018559 996 44.939804 -14.242310 -32.557686 997 43.729813 -14.936584 -32.124054 998 35.953011 -16.426956 -32.915607 999 37.011917 -16.490448 -33.040611 1000 38.294243 -16.298553 -32.969765 1001 38.856453 -16.443390 -32.515858 1002 35.982559 -16.887970 -32.436188 1003 38.320297 -17.150009 -32.348518 1004 39.956879 20.943588 -29.434402 1005 41.033173 20.798798 -29.342224 1006 42.639877 20.765045 -26.722130 1007 42.518799 20.475906 -28.281559 1008 43.436432 19.931992 -27.683739 1009 38.514244 21.025146 -29.096180 1010 40.734741 21.233032 -28.190094 1011 43.126099 19.589157 -28.857857 1012 35.738129 18.624176 -30.367592 1013 34.391785 18.440506 -29.355816 1014 34.181808 17.595490 -29.560425 1015 33.904152 18.309891 -29.012352 1016 33.655930 17.385529 -28.973999 1017 43.312744 18.459290 -29.609329 1018 43.859558 17.769089 -28.398949 1019 43.674591 19.008377 -28.475910 1020 27.466568 16.225952 -28.954704 1021 28.680046 16.886597 -28.703102 1022 27.946068 16.941711 -28.226589 1023 29.884163 16.434280 -28.979118 1024 34.510956 15.279755 -29.243946 1025 35.182281 14.570435 -29.978050 1026 26.846176 12.966141 -29.895638 1027 26.590347 14.116913 -29.920959 1028 26.417160 13.635193 -29.224342 1029 31.258186 14.577606 -30.317039 1030 31.353104 14.474289 -29.405006 1031 45.778992 14.814194 -29.831718 1032 35.771645 13.119751 -30.101269 1033 26.708778 12.882965 -28.974041 1034 27.336708 12.158295 -30.272701 1035 27.963669 10.789703 -29.802677 1036 25.195709 10.047043 -30.626492 1037 32.507690 11.642487 -29.531506 1038 49.905640 9.470764 -30.086548 1039 26.444107 9.500244 -30.133568 1040 24.034180 8.961487 -28.514641 1041 24.295532 9.449585 -29.226395 1042 24.989815 9.105225 -28.758141 1043 50.393463 9.890030 -29.157055 1044 50.031281 10.799652 -29.044968 1045 49.124268 7.807907 -29.919323 1046 49.791580 8.554001 -29.997612 1047 36.502113 6.000000 -30.684254 1048 45.121490 7.563324 -30.053368 1049 46.115646 7.220596 -28.880604 1050 47.516479 6.854904 -28.815666 1051 48.590530 6.995392 -29.116028 1052 22.680168 5.501953 -31.251320 1053 23.144318 4.712280 -30.977104 1054 32.821823 8.757309 -29.336246 1055 36.911301 4.830406 -30.739632 1056 23.779053 4.021263 -30.781120 1057 24.140137 3.544296 -30.951355 1058 36.680374 3.305222 -28.397839 1059 36.676743 5.249420 -29.558342 1060 41.476929 5.094635 -30.094528 1061 42.496857 4.014336 -30.536831 1062 42.795044 4.289124 -29.243088 1063 42.062668 4.939156 -29.474216 1064 43.794189 3.819977 -30.114056 1065 41.129730 5.615616 -30.566536 1066 44.886337 3.776657 -30.563332 1067 45.659744 3.604950 -30.913948 1068 45.480530 3.832062 -30.426132 1069 43.808685 3.229065 -28.527763 1070 42.813034 4.078636 -27.960163 1071 46.873596 3.689484 -31.305824 1072 45.986938 3.576660 -30.325844 1073 33.311157 3.766624 -30.161446 1074 46.909454 3.362320 -30.936058 1075 38.716614 2.153519 -30.838924 1076 40.194397 -0.691772 -30.115444 1077 41.155975 0.381332 -30.724686 1078 38.748337 1.345612 -29.673882 1079 45.061646 3.565056 -29.746105 1080 50.666260 0.129898 -29.258377 1081 49.862381 0.072617 -28.882732 1082 25.052002 1.758011 -31.252850 1083 25.670830 0.722427 -31.200996 1084 33.406418 1.002167 -30.044724 1085 32.866165 1.025223 -30.740871 1086 42.370255 0.053726 -31.219444 1087 25.303764 -0.072144 -31.601952 1088 41.992706 -0.269241 -30.892654 1089 51.469574 -0.390060 -29.611660 1090 25.724190 -1.320602 -31.475788 1091 26.180511 -0.205322 -31.021152 1092 27.422813 -0.832962 -29.906525 1093 52.301056 -1.115173 -30.779655 1094 52.174469 -0.834351 -30.073910 1095 26.238953 -3.059891 -31.354771 1096 26.571930 -4.434952 -31.342064 1097 37.206688 -0.689804 -28.160900 1098 38.281250 -1.088135 -28.569492 1099 38.180801 -0.648834 -28.193535 1100 38.646057 -1.851242 -31.064171 1101 39.116928 -1.497696 -29.997383 1102 52.472870 -1.856796 -30.470825 1103 52.514771 -1.178146 -30.356606 1104 38.526779 -1.867447 -30.291458 1105 52.368774 -3.090836 -30.073414 1106 52.141113 -4.312302 -29.989742 1107 35.635651 -5.958115 -30.729721 1108 51.230484 -4.446075 -31.322250 1109 27.639038 -7.497742 -31.175446 1110 27.648872 -5.640121 -30.619576 1111 36.586449 -6.061203 -30.465004 1112 37.899582 -6.271149 -31.512062 1113 33.865341 -6.891006 -31.971626 1114 38.339645 -6.661041 -31.106377 1115 38.885361 -7.248520 -31.145699 1116 28.881714 -5.931015 -28.852081 1117 28.980576 -6.971161 -28.373871 1118 28.432068 -7.206940 -29.675102 1119 27.316345 -7.697739 -32.105286 1120 39.305573 -8.027725 -31.612793 1121 27.903069 -8.658188 -31.965027 1122 39.965736 -9.222656 -31.628105 1123 28.209518 -9.853241 -31.372223 1124 28.607407 -10.907242 -31.815582 1125 28.258301 -10.810638 -30.864079 1126 37.284332 -12.061905 -31.109631 1127 36.658615 -10.438339 -29.708191 1128 36.379196 -10.694855 -31.174015 1129 35.919495 -9.738251 -30.794144 1130 41.721039 -12.699066 -31.814651 1131 51.884064 -11.615433 -31.348007 1132 52.313629 -12.198593 -30.986946 1133 31.680010 -14.173111 -30.701622 1134 38.884308 -15.004181 -31.819923 1135 42.245117 -14.134384 -30.091080 1136 41.789139 -12.986588 -30.710411 1137 41.634888 -12.599106 -29.995369 1138 48.059052 -13.922485 -31.601353 1139 53.347534 -13.357407 -30.693726 1140 52.628998 -14.117554 -31.034702 1141 44.043243 -15.587952 -31.674873 1142 46.210754 -14.636383 -31.813503 1143 42.619736 -14.205719 -31.994461 1144 42.209412 -13.981888 -31.104404 1145 43.043488 -15.271957 -31.128387 1146 45.283722 -15.629150 -31.467415 1147 35.404732 -16.914978 -31.625980 1148 39.239349 -16.594238 -31.564579 1149 35.947586 -17.242813 -31.766281 1150 36.832962 -17.539276 -31.977867 1151 37.978882 -18.409653 -31.667656 1152 35.662766 20.147461 -28.936493 1153 41.708435 21.241562 -26.444237 1154 40.659653 21.215027 -26.488739 1155 41.704163 21.142471 -27.464661 1156 35.146896 18.911194 -29.657623 1157 41.637375 20.813995 -28.669094 1158 34.331375 19.613495 -28.024193 1159 43.857605 18.981659 -27.627842 1160 33.366135 18.304672 -28.530113 1161 27.269775 16.567673 -28.110569 1162 26.517303 15.069153 -28.658722 1163 30.975693 15.741882 -28.480209 1164 44.940491 14.799133 -28.812767 1165 44.276062 15.634933 -29.172695 1166 26.249924 14.286102 -29.149513 1167 26.197174 14.213409 -28.647968 1168 26.884819 16.044144 -28.317047 1169 34.863937 14.254059 -29.060295 1170 44.262268 13.733398 -27.597252 1171 43.304565 13.592560 -27.796154 1172 43.087738 14.463577 -27.880222 1173 43.716415 15.583572 -28.510654 1174 46.182022 14.524933 -29.271820 1175 31.928591 15.385712 -27.849991 1176 31.501274 14.662430 -28.654022 1177 34.970367 13.547882 -28.490402 1178 27.239296 12.054413 -29.094688 1179 35.114029 12.332092 -28.429787 1180 35.395218 11.037094 -28.380531 1181 33.028915 11.336990 -28.440201 1182 49.248840 12.012283 -28.621964 1183 23.196342 8.421234 -28.542656 1184 23.666397 8.184647 -27.775185 1185 22.916077 7.453827 -28.368279 1186 25.226875 9.538239 -29.603237 1187 26.400635 8.540543 -28.750935 1188 28.447350 9.493042 -29.298714 1189 28.718903 9.460846 -28.272850 1190 33.206741 8.816559 -28.488461 1191 50.403763 8.890915 -29.304028 1192 22.441635 6.833557 -29.775406 1193 27.653549 8.312607 -29.092590 1194 42.175659 7.479568 -29.724697 1195 43.619263 7.776108 -29.542736 1196 22.605713 7.769958 -29.174469 1197 41.229980 6.287033 -29.907200 1198 41.537308 6.840240 -29.620251 1199 49.559265 7.087173 -28.893211 1200 50.233643 7.833313 -28.916946 1201 22.771591 5.722961 -30.304932 1202 41.183868 5.780121 -29.846191 1203 23.338745 4.581238 -29.916344 1204 42.260864 4.985229 -28.323372 1205 24.257660 3.311989 -30.016403 1206 24.944359 2.689514 -30.123962 1207 26.161896 1.397568 -30.310482 1208 25.409012 2.209854 -30.242012 1209 46.406921 2.737717 -29.579227 1210 47.284607 1.461700 -29.078995 1211 45.875305 1.197311 -28.517281 1212 45.084808 2.500778 -28.724079 1213 48.540161 1.389618 -29.355522 1214 33.842079 2.215668 -29.265350 1215 33.992340 3.778473 -28.870541 1216 26.970436 0.613373 -29.937469 1217 26.401726 1.310654 -29.381851 1218 27.274879 0.345444 -29.230721 1219 34.746109 3.096634 -28.052902 1220 37.577820 1.768661 -28.338684 1221 37.833893 0.808777 -28.126251 1222 38.540947 -0.034744 -28.508072 1223 27.887978 -0.362061 -28.929577 1224 26.610985 0.409439 -30.558098 1225 41.098114 -0.676987 -30.337193 1226 28.511826 -2.585693 -28.665115 1227 27.152573 -2.323059 -30.436890 1228 35.020050 -0.079025 -28.803650 1229 41.657074 -0.729996 -30.716133 1230 52.443085 -1.348633 -29.826210 1231 36.427231 -1.056030 -29.407913 1232 37.815613 -1.673996 -30.238541 1233 41.106049 -1.663818 -31.147675 1234 41.079391 -1.248764 -30.620209 1235 52.385315 -3.710510 -29.570946 1236 52.103348 -2.906204 -28.909199 1237 38.432373 -1.726501 -29.922947 1238 27.700638 -3.846359 -30.109779 1239 28.922791 -3.965973 -28.373039 1240 52.407898 -2.054657 -29.542870 1241 26.686913 -5.344788 -31.599407 1242 28.776764 -7.920914 -28.858170 1243 35.010178 -6.739548 -30.514366 1244 50.853348 -7.670914 -30.436577 1245 28.314697 -8.763443 -30.006142 1246 37.622215 -6.359589 -30.486870 1247 38.526886 -7.032364 -29.931847 1248 39.496712 -8.115143 -30.677135 1249 39.577560 -8.125519 -29.216515 1250 50.270508 -10.690308 -30.285221 1251 49.171875 -9.580139 -29.322563 1252 50.905365 -6.319382 -28.663094 1253 51.345322 -5.253281 -28.485554 1254 50.395401 -7.647263 -29.434052 1255 28.305267 -10.013885 -30.152748 1256 35.088623 -7.856506 -30.414169 1257 35.692825 -8.772415 -29.776363 1258 35.404099 -7.578400 -29.826389 1259 28.466324 -10.800156 -29.722366 1260 40.267090 -9.618759 -30.595207 1261 41.135925 -11.485367 -30.604652 1262 50.899689 -11.304688 -30.522877 1263 50.495972 -11.561630 -30.188828 1264 51.265991 -10.902954 -30.850983 1265 28.595894 -11.666641 -30.721886 1266 51.544098 -11.912048 -30.336796 1267 38.010254 -12.996613 -29.746574 1268 50.471512 -12.161713 -29.658260 1269 49.512238 -11.336273 -29.618351 1270 52.861084 -12.305557 -29.868477 1271 54.122940 -12.871017 -29.945541 1272 54.320480 -12.256210 -29.158348 1273 32.796616 -14.788010 -30.604095 1274 42.593521 -14.821609 -28.868889 1275 41.705353 -12.734283 -29.015938 1276 47.543304 -15.349167 -30.712837 1277 52.803116 -14.780350 -30.775097 1278 53.672897 -14.301147 -30.619152 1279 54.388992 -13.696869 -30.184093 1280 33.536362 -15.238190 -29.950180 1281 32.217407 -14.884872 -29.463642 1282 52.734131 -15.405319 -30.295334 1283 50.676727 -16.318924 -29.178265 1284 51.969452 -16.169312 -29.526505 1285 49.826401 -15.621140 -29.821392 1286 54.412506 -14.371796 -30.224800 1287 54.111420 -15.061813 -30.093132 1288 53.765701 -16.135880 -29.463043 1289 33.904732 -15.443497 -31.152199 1290 34.344353 -15.759644 -29.937950 1291 34.854324 -16.418182 -30.731163 1292 43.343460 -16.139023 -30.804184 1293 43.992584 -16.078125 -31.189415 1294 45.245102 -16.353149 -30.835506 1295 43.917633 -16.610947 -30.552834 1296 35.787125 -17.508835 -30.538445 1297 38.988907 -17.983170 -31.597137 1298 39.516983 -17.994827 -30.915192 1299 39.567146 -16.999619 -30.330444 1300 44.766266 -17.050903 -30.268837 1301 36.822098 -18.543472 -31.158268 1302 36.001656 -19.427368 -29.376755 1303 36.298439 -20.545334 -29.289391 1304 36.604721 -20.331406 -30.045525 1305 37.722534 -19.675156 -31.037262 1306 36.685516 -19.478073 -30.536880 1307 38.971367 -19.231430 -30.962761 1308 39.824760 -18.608063 -29.564728 1309 36.577484 21.072601 -27.948048 1310 35.903641 20.687653 -28.132397 1311 37.511353 21.110855 -27.848087 1312 39.197243 21.206146 -27.620758 1313 36.230530 20.619995 -27.139587 1314 35.232887 19.778992 -25.789093 1315 33.566513 20.034271 -26.417648 1316 32.119652 19.281097 -27.004517 1317 31.661371 18.052979 -27.651703 1318 32.197166 18.352127 -27.783810 1319 32.659813 20.168732 -25.738567 1320 31.622538 20.065125 -25.322483 1321 28.718033 17.481033 -27.743900 1322 29.741089 17.368713 -27.901588 1323 29.430206 18.235413 -26.618408 1324 32.538071 17.479965 -28.136089 1325 33.445206 16.170578 -28.477463 1326 32.786163 15.497528 -27.740631 1327 33.764542 14.425812 -27.923248 1328 32.354675 16.289398 -27.936485 1329 43.576019 16.588165 -27.822754 1330 32.377731 13.856445 -27.983299 1331 43.060196 15.593643 -27.599091 1332 26.810059 15.895233 -27.551704 1333 27.132782 16.265915 -26.459770 1334 26.665848 15.001587 -26.754608 1335 26.421188 14.582993 -27.572937 1336 31.141960 16.834305 -27.972507 1337 32.696793 14.699783 -27.553207 1338 45.560349 13.786743 -27.455982 1339 35.394287 13.113968 -28.823532 1340 42.170746 14.379303 -27.116867 1341 42.486069 15.089294 -26.674332 1342 42.788483 13.674713 -27.847248 1343 26.433838 13.652512 -28.183983 1344 26.961975 12.615051 -27.789093 1345 32.602455 12.563934 -28.535545 1346 42.172363 13.570099 -27.259453 1347 42.784500 13.168747 -27.591572 1348 48.075653 13.268845 -27.154778 1349 49.392044 12.551361 -27.078827 1350 48.808853 13.029785 -26.129372 1351 32.969498 9.840454 -28.691582 1352 33.553421 10.754822 -27.923950 1353 50.494186 10.629868 -28.246273 1354 28.814293 9.237076 -28.747086 1355 51.056885 10.428894 -27.337502 1356 51.143066 9.010559 -27.901070 1357 28.532013 8.645523 -28.776951 1358 35.235329 10.243347 -28.158951 1359 35.556763 9.577652 -28.381554 1360 27.974205 7.586182 -28.275146 1361 28.910316 7.833557 -27.817062 1362 28.662956 6.855408 -27.844097 1363 34.014496 9.836365 -27.894188 1364 35.437622 8.684464 -28.252590 1365 35.931839 8.024078 -28.910572 1366 42.649933 7.644379 -28.649727 1367 43.839966 7.782623 -28.393429 1368 44.764633 7.548157 -29.078056 1369 22.551346 6.928497 -29.015308 1370 33.754517 5.948257 -28.260414 1371 33.966721 6.648529 -28.029621 1372 36.250816 6.345673 -28.785957 1373 35.979782 7.132675 -28.639374 1374 41.609177 5.994217 -29.050201 1375 41.878113 7.112442 -28.897110 1376 43.625702 7.804535 -27.754379 1377 44.210175 7.569077 -27.665840 1378 44.939087 7.431824 -28.228367 1379 49.355164 6.544098 -28.306988 1380 48.457703 6.081970 -27.677208 1381 22.930595 5.974449 -28.749802 1382 42.044861 5.760475 -27.752922 1383 42.306305 6.897751 -27.862785 1384 23.212494 4.658699 -28.997623 1385 23.621727 3.918755 -29.142529 1386 35.639229 2.314560 -27.614761 1387 36.706528 1.439011 -27.586105 1388 23.982491 3.032501 -28.551975 1389 25.228607 2.009262 -29.143509 1390 25.902618 1.850098 -29.670303 1391 49.054001 0.561066 -29.005398 1392 26.343048 0.865051 -28.634094 1393 34.130409 0.817184 -29.125389 1394 39.197342 -0.580246 -29.277050 1395 48.034790 0.297455 -28.596809 1396 49.134979 -0.921112 -28.113461 1397 50.652985 -0.948669 -28.512863 1398 27.350639 0.024139 -28.402905 1399 36.380508 0.239426 -27.416870 1400 37.209824 0.285873 -27.608566 1401 34.790398 1.308868 -28.157005 1402 38.074570 -1.383255 -29.305782 1403 38.825485 -1.178970 -29.113529 1404 51.957962 -4.365219 -29.093529 1405 51.006897 -3.731720 -27.665794 1406 35.861008 -6.747116 -29.790855 1407 37.190491 -7.160202 -28.675415 1408 28.658707 -4.863022 -29.146973 1409 35.903046 -7.958862 -29.143826 1410 28.772232 -8.758209 -28.370911 1411 28.720596 -9.938721 -28.795246 1412 36.471573 -9.027817 -28.549664 1413 35.854408 -8.633072 -29.040890 1414 39.412262 -7.961609 -27.811317 1415 40.136871 -8.900620 -28.412258 1416 40.606628 -10.048752 -29.471134 1417 49.244751 -7.817261 -28.346680 1418 48.272507 -11.270538 -28.552845 1419 47.568924 -9.630569 -28.008278 1420 28.354172 -11.320206 -30.268509 1421 29.265472 -12.515656 -29.925694 1422 37.436172 -11.833817 -29.060863 1423 49.336914 -12.125015 -29.007511 1424 51.710892 -12.248871 -29.418030 1425 30.410927 -13.853409 -29.756126 1426 51.200729 -12.360596 -29.594696 1427 55.034332 -13.135254 -29.450729 1428 39.100471 -15.505524 -30.467720 1429 38.699020 -14.424179 -29.408340 1430 42.053772 -13.500275 -27.817921 1431 41.114471 -11.346863 -27.808887 1432 55.041504 -14.258179 -29.748772 1433 55.563461 -12.252258 -28.009663 1434 55.737457 -13.706192 -28.979248 1435 43.102798 -15.925323 -30.015068 1436 56.269241 -16.727310 -28.636017 1437 55.688263 -15.528122 -28.947159 1438 55.630920 -17.126709 -28.585960 1439 36.090401 -18.637344 -30.268372 1440 43.231339 -16.376877 -28.991562 1441 44.002563 -17.268784 -29.557037 1442 46.377289 -16.821899 -29.996094 1443 45.794434 -17.874481 -29.578636 1444 46.984818 -17.362839 -29.143303 1445 46.392242 -18.446701 -28.824318 1446 45.304367 -18.546509 -29.260162 1447 48.223602 -16.022705 -29.661495 1448 37.767624 -20.966080 -30.350193 1449 38.637589 -20.532562 -30.626732 1450 40.319000 -19.088013 -27.630089 1451 39.819115 -17.452408 -27.903744 1452 37.114960 -20.286346 -30.557579 1453 39.680733 -20.644119 -29.823349 1454 37.046463 -20.784225 -30.212242 1455 38.765656 -21.328308 -30.198349 1456 40.378235 -20.049652 -28.600094 1457 39.283264 20.873825 -26.416656 1458 37.843269 20.516846 -26.577545 1459 39.978760 20.436066 -25.600956 1460 41.622955 20.957153 -25.748680 1461 33.704605 19.971939 -25.031418 1462 43.427368 20.366440 -26.800270 1463 43.759338 19.720596 -26.799492 1464 30.730545 18.226028 -27.205925 1465 30.590599 19.340744 -25.677757 1466 32.819122 18.613922 -28.005211 1467 27.791092 17.107300 -27.366215 1468 28.593903 17.742889 -27.076126 1469 28.211693 17.607925 -26.299435 1470 43.788422 18.098282 -26.709084 1471 43.228851 16.335693 -26.552536 1472 26.225647 14.377350 -28.157394 1473 33.007965 13.890778 -27.542965 1474 43.560883 17.165527 -25.494034 1475 43.567551 18.918091 -25.126835 1476 42.264114 12.865433 -27.331673 1477 26.771286 13.783051 -26.778694 1478 34.386826 13.317825 -27.864395 1479 34.493843 11.272247 -27.783756 1480 33.585953 12.716705 -27.782074 1481 42.728180 12.662079 -27.142693 1482 46.747925 13.450043 -26.423367 1483 27.918945 11.086914 -27.362968 1484 41.971130 12.914734 -27.023727 1485 43.510941 12.994003 -27.134838 1486 42.862747 12.350754 -26.151295 1487 44.824188 12.723892 -25.960556 1488 50.414795 11.513519 -27.289299 1489 42.242676 12.627426 -26.886078 1490 33.656425 11.534912 -27.768867 1491 23.293259 7.237778 -27.543182 1492 24.922195 8.391602 -27.689308 1493 25.949196 7.804550 -27.222336 1494 27.036438 7.086060 -27.162525 1495 34.231110 7.407776 -27.915070 1496 34.212860 8.499359 -27.949631 1497 35.632629 7.632172 -28.149990 1498 42.412292 6.088745 -26.959618 1499 42.575043 5.728676 -26.465393 1500 43.251740 6.246262 -26.325790 1501 43.074921 7.686844 -27.916393 1502 52.351059 8.989624 -26.145924 1503 51.994308 10.044830 -26.041542 1504 51.635254 9.862274 -26.830357 1505 29.064346 6.716675 -27.491306 1506 35.797821 4.830276 -27.915352 1507 36.292618 5.332817 -28.392723 1508 35.244492 6.455032 -27.964851 1509 44.860352 7.312241 -27.582584 1510 45.671158 7.004501 -27.642288 1511 50.274734 6.653412 -27.993347 1512 51.112137 7.403290 -27.777897 1513 23.499947 6.419952 -26.780487 1514 23.295258 4.513412 -27.871742 1515 28.135132 6.566910 -27.502708 1516 28.744095 6.169556 -27.261574 1517 46.876099 6.630386 -27.867500 1518 49.521942 5.681534 -27.434410 1519 49.614426 6.099365 -27.757870 1520 51.319397 6.366272 -27.203423 1521 34.570541 4.881630 -28.057449 1522 34.241508 5.966125 -27.905819 1523 50.330551 5.681488 -27.277451 1524 23.120865 3.184731 -26.516106 1525 43.032928 3.129471 -26.972443 1526 24.152557 1.890686 -27.972286 1527 24.012863 0.915176 -27.577751 1528 25.123154 0.716660 -28.097031 1529 35.492599 3.941727 -27.810390 1530 44.399719 1.759033 -27.961056 1531 43.708252 1.989258 -27.138695 1532 45.034882 1.558136 -28.301926 1533 44.028244 0.721680 -26.951553 1534 44.822571 0.339005 -27.815147 1535 27.985336 -0.665497 -28.144245 1536 37.826523 -0.094406 -27.937214 1537 47.813156 -1.296402 -27.714241 1538 46.838715 -0.312332 -28.146343 1539 45.666214 -0.870911 -27.690956 1540 51.845016 -1.440094 -29.028267 1541 28.219658 -1.098541 -28.534981 1542 35.914215 -0.286606 -27.951366 1543 38.713814 -0.795837 -28.620617 1544 44.678833 -1.259216 -27.209385 1545 28.443428 -1.722656 -28.628033 1546 44.163345 -0.486420 -26.657536 1547 46.613708 -2.378357 -26.768162 1548 48.771362 -3.120239 -26.649311 1549 50.217773 -2.325058 -27.497765 1550 51.245728 -2.196045 -28.130306 1551 28.670563 -2.112686 -28.323868 1552 37.841560 -6.903076 -28.041222 1553 38.422867 -7.093140 -28.547203 1554 38.267029 -7.155640 -27.696148 1555 38.965591 -7.449814 -28.030357 1556 50.243317 -6.848450 -28.207981 1557 47.952698 -8.333389 -27.887012 1558 48.366058 -8.791199 -28.507584 1559 48.575958 -7.455200 -27.347668 1560 28.730911 -11.602539 -29.603500 1561 29.169006 -12.039810 -28.666245 1562 40.671341 -10.040085 -28.522175 1563 41.042557 -11.165359 -28.908958 1564 29.525993 -12.978714 -28.848503 1565 41.205963 -11.606552 -29.626869 1566 40.474762 -9.584000 -27.730183 1567 40.165649 -10.033005 -26.342148 1568 46.786713 -9.289429 -26.700981 1569 46.974106 -11.139572 -27.202576 1570 46.203873 -10.642090 -26.419598 1571 54.280136 -11.720551 -28.411507 1572 53.373230 -11.865311 -28.759815 1573 54.380707 -11.339005 -27.532177 1574 48.262466 -12.072128 -27.544502 1575 48.649780 -12.118790 -28.471581 1576 51.840042 -11.835785 -28.324497 1577 56.468369 -13.803284 -28.337357 1578 49.256119 -12.365204 -28.377758 1579 50.563293 -12.358826 -28.861145 1580 49.886230 -12.089584 -27.547150 1581 56.941269 -13.102875 -27.425659 1582 56.281265 -12.176727 -26.941391 1583 32.334564 -15.547470 -28.109711 1584 30.817375 -15.026794 -28.654427 1585 38.119667 -13.171570 -28.317841 1586 38.845505 -14.738907 -28.200809 1587 42.702927 -15.023483 -27.843689 1588 57.556168 -14.834595 -27.757809 1589 57.206604 -16.574722 -28.232388 1590 34.028732 -15.483414 -28.664841 1591 35.130753 -16.390213 -29.228775 1592 58.577515 -15.271347 -26.604988 1593 58.127441 -14.425156 -26.656021 1594 39.342918 -16.294800 -29.140423 1595 49.585999 -17.099762 -28.250500 1596 48.307892 -17.069214 -28.544624 1597 48.904877 -17.917404 -27.775070 1598 49.439392 -16.453491 -28.939465 1599 51.116516 -17.351013 -28.369263 1600 47.872986 -16.602539 -29.216164 1601 52.580948 -17.177841 -28.783825 1602 57.634323 -13.741348 -26.972225 1603 35.832794 -18.320999 -29.478565 1604 54.460434 -17.257812 -28.698082 1605 53.336029 -16.937805 -29.066071 1606 53.410141 -17.517181 -28.659271 1607 44.463074 -18.443924 -28.854073 1608 44.789368 -18.049042 -29.509438 1609 45.009842 -17.525742 -29.868813 1610 45.363525 -19.027267 -28.769691 1611 44.897156 -19.267441 -28.206516 1612 44.230225 -18.704910 -27.762436 1613 46.052567 -19.469818 -28.026093 1614 37.043121 -21.359985 -29.598114 1615 38.276962 -21.861206 -29.845848 1616 39.266586 -21.775864 -29.790234 1617 37.906662 -22.309937 -29.369492 1618 37.201988 -22.334076 -28.786781 1619 38.262833 -22.843842 -28.956112 1620 39.109398 -22.435669 -29.250679 1621 39.876389 -21.787155 -29.214127 1622 38.871979 20.238525 -26.033051 1623 40.817673 20.919098 -25.681885 1624 36.465660 20.204117 -26.117897 1625 36.995789 19.404877 -25.697395 1626 36.201691 19.802994 -25.688591 1627 43.375854 20.347107 -26.141197 1628 43.723145 19.601059 -25.992638 1629 39.058670 19.640488 -25.540916 1630 38.166565 19.404831 -25.769703 1631 29.700287 19.027283 -25.288879 1632 27.454506 16.614838 -25.060101 1633 28.805145 18.318436 -24.984974 1634 27.372437 13.827057 -25.182022 1635 26.975739 15.030121 -25.761780 1636 27.485184 15.325989 -24.342823 1637 42.915710 15.827133 -25.332832 1638 42.222351 14.883759 -25.466972 1639 41.942902 14.241089 -26.332146 1640 47.775345 13.436111 -26.210533 1641 27.387100 12.553543 -26.308033 1642 41.950089 13.106125 -26.139069 1643 42.059143 12.383057 -25.161140 1644 43.608612 11.714706 -24.913204 1645 42.532867 11.797699 -24.890175 1646 50.254669 12.142975 -26.164978 1647 34.973312 9.418854 -27.886986 1648 51.325165 10.917679 -26.333481 1649 51.276077 11.649307 -25.236725 1650 24.093079 7.605270 -26.842258 1651 29.466888 7.219116 -26.191700 1652 29.005386 8.829239 -26.657867 1653 29.389893 7.746979 -25.264595 1654 28.994293 9.149963 -25.483551 1655 29.016945 8.682571 -24.727322 1656 35.005852 7.763977 -27.836990 1657 25.164207 7.289764 -26.256077 1658 26.152298 7.167297 -26.498672 1659 43.380432 7.440063 -27.412148 1660 44.474060 6.954681 -26.943577 1661 52.174164 7.493378 -26.675652 1662 23.996384 5.610001 -24.542740 1663 25.155090 6.174423 -24.687153 1664 24.866714 5.275635 -23.190071 1665 29.247864 7.059387 -26.933426 1666 43.065216 6.851013 -26.997322 1667 28.200592 5.888779 -26.354469 1668 29.134003 6.218842 -26.986046 1669 48.206451 2.155258 -25.353371 1670 47.590271 3.680664 -25.696293 1671 46.365082 3.302414 -25.327908 1672 51.285492 4.981232 -26.696419 1673 52.296249 5.906952 -26.445026 1674 28.885384 5.894829 -26.758026 1675 42.536453 4.781784 -26.858322 1676 49.563873 4.938385 -26.911331 1677 49.279480 3.531082 -26.133720 1678 50.444931 4.000824 -26.388611 1679 48.146088 4.670883 -26.364220 1680 50.434906 4.912544 -26.870621 1681 52.357620 4.532486 -26.013557 1682 35.611336 3.262390 -27.725880 1683 52.450928 3.556046 -25.637383 1684 53.412766 3.947571 -24.861809 1685 22.451141 1.654144 -25.749214 1686 23.345200 1.644409 -27.039314 1687 35.698586 0.955078 -27.404095 1688 24.294121 -0.218552 -27.604794 1689 27.183868 -0.762924 -27.688751 1690 26.295059 -0.025391 -27.962936 1691 23.214386 0.443802 -26.811615 1692 23.530762 -0.911896 -27.198196 1693 23.132111 -2.045486 -27.128391 1694 24.512383 -1.693985 -27.588585 1695 25.346207 -0.710098 -27.738159 1696 27.842865 -1.246735 -27.613922 1697 35.342140 0.330612 -27.746208 1698 26.276756 -1.021896 -27.535706 1699 28.231277 -1.201477 -27.904652 1700 35.763626 0.229446 -27.402340 1701 44.120697 -1.609665 -26.165825 1702 22.546364 -0.747940 -26.355461 1703 21.850174 -1.640610 -25.907059 1704 25.673164 -1.691147 -27.478874 1705 28.228676 -2.038193 -27.710419 1706 28.692314 -2.816940 -27.240223 1707 44.406281 -2.234543 -26.416832 1708 21.960533 -2.808807 -26.209675 1709 23.362228 -3.135803 -27.433216 1710 22.947098 -3.814865 -27.195827 1711 24.221916 -2.800110 -27.636593 1712 25.568291 -2.732651 -27.417393 1713 45.190155 -2.356186 -26.572678 1714 44.631302 -2.876083 -25.693848 1715 24.428391 -4.022202 -27.603565 1716 26.289940 -3.872925 -27.129589 1717 29.150391 -4.978348 -27.966648 1718 23.026321 -4.927170 -27.235916 1719 22.402580 -5.796021 -26.865219 1720 23.406326 -6.315750 -27.333015 1721 24.293060 -5.533768 -27.619129 1722 25.530746 -5.198318 -27.396042 1723 25.014465 -7.215134 -27.411545 1724 28.653549 -6.993118 -27.321815 1725 28.860321 -7.812286 -28.010468 1726 26.365166 -5.927017 -27.150467 1727 37.928482 -7.594376 -27.201126 1728 37.686005 -8.993759 -26.791462 1729 38.133400 -8.184692 -26.645073 1730 50.515457 -5.522095 -27.494797 1731 49.574341 -6.576736 -27.251236 1732 29.077881 -5.931839 -27.614681 1733 37.730392 -7.062042 -27.754669 1734 38.020531 -11.869904 -25.691948 1735 38.635254 -11.774826 -24.325493 1736 38.502258 -10.555801 -25.125023 1737 39.733208 -8.681702 -27.292824 1738 47.222305 -8.858795 -27.522423 1739 47.404327 -8.341705 -27.253220 1740 47.896576 -7.897293 -27.307320 1741 28.898865 -11.078552 -28.624454 1742 37.200829 -10.631912 -27.835346 1743 37.546623 -11.892838 -27.838848 1744 41.111771 -11.556381 -26.694984 1745 46.226151 -11.305862 -26.546608 1746 53.196075 -10.864151 -26.924915 1747 53.342026 -10.599609 -26.234360 1748 52.629486 -10.499222 -26.215332 1749 53.257187 -11.413361 -27.956593 1750 52.160828 -11.177124 -27.364937 1751 29.151627 -12.731155 -27.894386 1752 37.897018 -12.471909 -26.958260 1753 37.474594 -11.453552 -27.019852 1754 56.995865 -12.919556 -26.338451 1755 56.722977 -12.434265 -26.696884 1756 30.902046 -16.091370 -28.004074 1757 48.731445 -12.141815 -26.517437 1758 29.744583 -13.989853 -28.154228 1759 30.077438 -15.381271 -27.872021 1760 38.416397 -13.739532 -27.335861 1761 38.973808 -14.906281 -27.149536 1762 29.371452 -14.746826 -26.626595 1763 29.868851 -16.739029 -27.173569 1764 31.859011 -16.465424 -27.647583 1765 35.028671 -15.830185 -28.203766 1766 33.709030 -15.693665 -27.288929 1767 34.675812 -15.619431 -27.617859 1768 43.102554 -16.204803 -27.168640 1769 42.613022 -14.794052 -27.019333 1770 43.129410 -16.235229 -28.111786 1771 31.045837 -17.080887 -27.542931 1772 32.475105 -16.022675 -27.417542 1773 35.507294 -16.410797 -28.084797 1774 43.074127 -16.153305 -26.228447 1775 42.588516 -14.751663 -26.070950 1776 47.443924 -17.759842 -28.509640 1777 58.262665 -16.062256 -27.547321 1778 35.877319 -18.541092 -28.661999 1779 35.814880 -17.462967 -28.540226 1780 39.331161 -16.004395 -27.933029 1781 39.589149 -16.351974 -26.877850 1782 43.734802 -17.451401 -28.406097 1783 48.073425 -17.733978 -28.167618 1784 47.588776 -18.770477 -27.804195 1785 48.458252 -19.617981 -26.901363 1786 49.930328 -17.620163 -27.885738 1787 52.676300 -17.709702 -28.361084 1788 57.426819 -17.854080 -27.974365 1789 58.428467 -17.248642 -27.520638 1790 35.921066 -18.228683 -27.990784 1791 44.286713 -18.961700 -26.699398 1792 43.662872 -17.526550 -27.380089 1793 43.639816 -17.555679 -26.385269 1794 51.662231 -18.949448 -27.285011 1795 52.466843 -18.277847 -27.908272 1796 54.611237 -20.000061 -27.315781 1797 54.489761 -18.866791 -27.891762 1798 53.173843 -19.249969 -27.478264 1799 53.623962 -18.181061 -28.216961 1800 54.502808 -18.153671 -28.301369 1801 55.238831 -18.112381 -28.275093 1802 56.366699 -17.843719 -28.228470 1803 58.079697 -18.316696 -27.549080 1804 57.037750 -18.995071 -27.632729 1805 59.101135 -18.363266 -26.949909 1806 35.834457 -19.275909 -27.755905 1807 35.784584 -17.617630 -26.936295 1808 47.666977 -19.597458 -27.271954 1809 46.967911 -19.777054 -27.529778 1810 58.244446 -19.167130 -27.206078 1811 35.946960 -20.315216 -28.515022 1812 40.449799 -21.174820 -28.325867 1813 40.094681 -22.288147 -28.268478 1814 40.834549 -21.545166 -26.302078 1815 36.392792 -21.346786 -28.570518 1816 39.260284 -23.100433 -28.508163 1817 39.371269 -24.086914 -27.505421 1818 37.928246 -23.836121 -27.698303 1819 38.186905 -24.508591 -27.253723 1820 38.029587 -23.200333 -28.372398 1821 39.098656 -23.633270 -28.037415 1822 42.627914 20.517410 -25.558136 1823 31.401817 19.824615 -23.979057 1824 30.836700 19.908905 -24.651562 1825 32.508171 20.099075 -24.488968 1826 40.948898 20.620972 -25.328907 1827 41.631531 20.490585 -24.876671 1828 43.329376 20.020111 -25.465641 1829 36.174149 19.173218 -25.397057 1830 38.674774 18.547394 -25.247902 1831 39.559349 19.416489 -24.570305 1832 40.611649 20.205093 -24.901447 1833 42.735809 20.050156 -24.758690 1834 42.963928 19.503326 -23.575367 1835 36.671417 18.304962 -25.239185 1836 37.600792 18.110107 -25.396645 1837 39.003326 18.069290 -24.589642 1838 37.059097 16.810455 -25.132725 1839 38.241966 16.913940 -24.855766 1840 27.770233 16.480103 -23.728531 1841 28.104904 17.525696 -23.984585 1842 35.944092 15.660370 -24.360428 1843 35.917801 18.079895 -24.897629 1844 38.701630 17.348785 -24.013203 1845 37.677338 15.869171 -25.114807 1846 39.026459 17.870392 -24.209141 1847 37.069801 15.696777 -25.052460 1848 37.343452 15.076721 -24.773361 1849 41.950256 14.166016 -25.260864 1850 47.899155 13.156342 -25.296402 1851 27.871002 12.611160 -24.762955 1852 28.053566 13.718658 -23.830490 1853 27.919266 11.589279 -25.728043 1854 46.584305 12.794647 -24.742805 1855 49.812531 12.650620 -24.885292 1856 41.966415 13.366379 -24.505131 1857 45.601044 12.210510 -24.358932 1858 28.507072 10.319168 -25.738918 1859 44.687668 11.875732 -24.443481 1860 51.926910 10.711792 -25.429916 1861 52.523788 9.922958 -25.155930 1862 53.308350 8.852783 -24.508400 1863 52.894455 10.069412 -24.208759 1864 24.221130 7.132019 -26.169067 1865 26.446732 6.234009 -25.531879 1866 29.700439 6.709961 -25.626244 1867 29.745392 6.644714 -24.983849 1868 43.571762 5.398491 -25.534805 1869 44.523102 5.474838 -25.421368 1870 44.644379 6.043671 -26.011803 1871 46.378754 6.016342 -26.681061 1872 53.133392 6.574081 -25.686264 1873 52.985138 7.833847 -25.530788 1874 53.696274 7.133667 -24.725933 1875 29.271011 6.152740 -26.171562 1876 29.683777 6.081741 -25.282566 1877 53.073318 5.279572 -25.705704 1878 53.766815 5.602814 -24.971390 1879 27.909554 5.220284 -25.196960 1880 29.051285 5.410446 -25.098324 1881 28.517548 4.843094 -24.792324 1882 42.835373 5.405327 -26.065536 1883 43.765076 4.259201 -25.058182 1884 44.076630 5.035110 -25.103752 1885 45.452728 5.286263 -25.656464 1886 48.393341 3.459633 -25.935902 1887 46.598419 4.600990 -25.732883 1888 50.374725 2.469833 -25.606537 1889 51.569122 3.415543 -25.911060 1890 22.176559 2.766724 -24.931725 1891 44.207306 4.643219 -24.907867 1892 45.950684 2.078568 -25.112740 1893 46.741562 0.711884 -24.589417 1894 21.259888 1.899689 -24.207565 1895 21.754456 0.894974 -25.013725 1896 43.413132 2.214478 -26.130413 1897 43.010330 2.789795 -26.147423 1898 43.853455 1.252319 -26.005081 1899 42.848816 3.498154 -26.158104 1900 51.630997 2.236176 -25.219643 1901 52.557770 2.672211 -24.934700 1902 54.240234 4.930679 -24.297108 1903 21.393089 -0.256729 -24.976669 1904 22.266647 0.429535 -25.780613 1905 20.017693 -0.061676 -23.214287 1906 20.724701 -1.603439 -24.407269 1907 26.894806 -1.790985 -27.385353 1908 28.087029 -3.312653 -26.755390 1909 44.022232 0.223969 -25.728729 1910 44.279922 -0.761856 -25.177708 1911 21.747604 -3.935059 -26.063522 1912 27.084023 -2.805237 -27.070721 1913 27.209114 -3.433640 -26.769279 1914 28.995850 -3.380203 -27.316589 1915 44.403015 0.066101 -25.008987 1916 47.134735 -4.011795 -25.604988 1917 45.600311 -3.427704 -25.397602 1918 50.089844 -3.263672 -26.941902 1919 27.342117 -4.169861 -26.732502 1920 26.788895 -4.948395 -27.003479 1921 29.103889 -4.284592 -27.256233 1922 44.175415 -2.479019 -25.553513 1923 50.004852 -4.181915 -26.740509 1924 49.357391 -4.537201 -26.267143 1925 28.808952 -4.778488 -26.825939 1926 28.752899 -3.929688 -26.742836 1927 28.097656 -4.886063 -26.663231 1928 29.069527 -5.104279 -27.213257 1929 49.839111 -5.334076 -26.671368 1930 49.159683 -5.714081 -26.300129 1931 26.986641 -8.004852 -27.270164 1932 26.796310 -6.695770 -27.124451 1933 27.291428 -5.688126 -26.845005 1934 27.441071 -4.917450 -26.758812 1935 23.964386 -8.602692 -27.257275 1936 24.487564 -9.463760 -27.227184 1937 25.690750 -9.188339 -27.374378 1938 28.704895 -5.726395 -26.926170 1939 27.881348 -6.553955 -26.907082 1940 22.386459 -6.809906 -26.743565 1941 28.191147 -8.438644 -27.505280 1942 38.655785 -7.515167 -27.363106 1943 47.715759 -7.548248 -26.407562 1944 48.718842 -6.755463 -26.592285 1945 23.235016 -7.970535 -26.998260 1946 23.459137 -9.571182 -26.905632 1947 28.003235 -7.534683 -27.107761 1948 28.427017 -9.647629 -27.889557 1949 38.734268 -7.972946 -26.955948 1950 38.818695 -8.713226 -26.493141 1951 46.464035 -7.914642 -24.822289 1952 23.808899 -11.056534 -26.655521 1953 25.272858 -10.436417 -27.147850 1954 27.004578 -10.236984 -27.448662 1955 25.555206 -11.553665 -27.045250 1956 26.829971 -11.842331 -27.246574 1957 28.487579 -10.690781 -27.916767 1958 37.697571 -10.642166 -26.236443 1959 46.456345 -11.590439 -26.504044 1960 51.866135 -10.797394 -26.482536 1961 52.836655 -10.698013 -25.403893 1962 54.345856 -11.257416 -26.153770 1963 26.085793 -12.679367 -26.941422 1964 26.847260 -12.499054 -27.127277 1965 27.915146 -11.440094 -27.459419 1966 28.767464 -11.722809 -27.826443 1967 39.885834 -10.233994 -25.226593 1968 40.143768 -10.880707 -24.911228 1969 50.985214 -11.317368 -26.881466 1970 55.077545 -11.455811 -27.044342 1971 55.560638 -11.701050 -26.765041 1972 28.022629 -12.572769 -26.820442 1973 29.042870 -13.405640 -26.994209 1974 28.908791 -12.953598 -26.088524 1975 47.170410 -11.971390 -26.353489 1976 26.840973 -12.811447 -26.958218 1977 29.039062 -13.576004 -26.173531 1978 29.022919 -13.168259 -25.668968 1979 41.616364 -12.488983 -27.078350 1980 42.078186 -13.562363 -26.727383 1981 47.986954 -12.293030 -26.633514 1982 57.637268 -13.856613 -25.982788 1983 32.353867 -16.679001 -27.142254 1984 32.863899 -15.729782 -27.375591 1985 35.211746 -15.930878 -27.552670 1986 59.005692 -16.317169 -26.594704 1987 35.551346 -16.451294 -27.352390 1988 35.802505 -16.881607 -27.664696 1989 43.048691 -16.115158 -25.274345 1990 42.567017 -14.731064 -25.111568 1991 58.966629 -15.699478 -25.750748 1992 31.840265 -17.475967 -27.080894 1993 30.717102 -18.114731 -27.072792 1994 31.680788 -18.426407 -26.699715 1995 32.484947 -17.230850 -26.623417 1996 59.435471 -17.404800 -26.344894 1997 40.127289 -17.990463 -25.710648 1998 39.766373 -16.622116 -25.333946 1999 39.654305 -16.367615 -25.889568 2000 50.112091 -18.704498 -27.263245 2001 44.218597 -18.994370 -25.616554 2002 43.595642 -17.520340 -25.398254 2003 53.457855 -20.147064 -27.006104 2004 52.315674 -20.242325 -26.655014 2005 55.667801 -19.069397 -27.772686 2006 57.597931 -20.101639 -27.078098 2007 58.501892 -19.931488 -26.781330 2008 59.046997 -19.304169 -26.738956 2009 35.769333 -20.290558 -25.940598 2010 35.784317 -21.899887 -26.349384 2011 35.900406 -20.867935 -27.409683 2012 40.669006 -20.333099 -27.459785 2013 40.634857 -19.692856 -26.521809 2014 46.200165 -20.257141 -27.184174 2015 45.086792 -19.719025 -27.341389 2016 45.473938 -20.541809 -25.918850 2017 47.275726 -20.127380 -27.128368 2018 55.296616 -21.701324 -26.508102 2019 55.334869 -20.977188 -26.891754 2020 53.840103 -21.055328 -26.572758 2021 56.295105 -20.286865 -27.211815 2022 47.098175 -20.709686 -26.525082 2023 57.254013 -21.047165 -26.681587 2024 58.373047 -20.891830 -26.380398 2025 36.589684 -22.600143 -27.587242 2026 40.105698 -23.131241 -27.595020 2027 40.591492 -23.707108 -26.683327 2028 40.049988 -26.326904 -25.661476 2029 38.849564 -26.003998 -26.355286 2030 39.176521 -27.346146 -25.249882 2031 39.459091 -24.911087 -26.889946 2032 40.572723 -24.860916 -26.314499 2033 40.726624 20.179871 -24.061474 2034 43.268555 19.351761 -22.430603 2035 42.240509 19.843704 -21.981537 2036 30.054878 19.205841 -24.039459 2037 28.939384 18.378281 -23.634579 2038 39.044418 19.257507 -23.410500 2039 38.902214 18.319534 -23.797951 2040 39.722923 19.967163 -23.040649 2041 41.807419 20.326263 -23.883774 2042 43.436707 17.331848 -24.183563 2043 43.576508 18.512985 -23.055359 2044 38.037369 15.573471 -24.634636 2045 38.189117 15.917694 -23.539627 2046 27.300247 16.165253 -24.431904 2047 37.868698 14.500641 -24.031487 2048 42.629440 15.069183 -24.006416 2049 43.105225 15.325424 -22.089729 2050 43.642670 17.156555 -21.827827 2051 43.509674 16.946136 -22.924614 2052 33.838867 17.122330 -22.955582 2053 34.521996 18.511383 -24.145355 2054 36.920135 14.135666 -24.455990 2055 36.154099 14.057770 -24.296089 2056 37.389275 13.348053 -24.083412 2057 38.017761 13.419556 -23.421570 2058 35.284096 14.009415 -23.552132 2059 36.328873 13.149628 -24.030811 2060 48.209030 12.683624 -23.698883 2061 28.433136 11.321045 -24.309589 2062 28.881203 12.833984 -23.111389 2063 29.170319 11.649521 -22.837051 2064 27.658096 14.364594 -24.144146 2065 51.307983 12.059052 -24.186790 2066 42.051086 12.174362 -23.683964 2067 42.850037 11.334991 -23.869610 2068 52.244003 11.002594 -24.384415 2069 52.183868 11.820786 -22.935017 2070 28.704834 9.766556 -24.582188 2071 53.841446 9.070282 -23.288109 2072 54.155731 7.863449 -23.606457 2073 54.435272 8.763977 -22.335487 2074 24.327332 6.547607 -25.542496 2075 25.254951 6.682098 -25.415001 2076 29.389984 6.745514 -24.188519 2077 27.069962 4.793442 -23.485970 2078 26.970383 5.260559 -24.401840 2079 27.901642 4.735672 -24.238564 2080 29.628586 6.046188 -24.658878 2081 45.411743 4.227676 -25.207039 2082 44.721985 4.860710 -25.150616 2083 54.326599 6.255356 -24.028130 2084 23.435349 5.238464 -25.921116 2085 42.995224 4.359604 -25.707855 2086 44.565338 4.214371 -24.925598 2087 43.438980 3.099716 -25.542931 2088 44.360809 1.956390 -25.270473 2089 45.391617 1.120026 -24.865929 2090 54.385971 3.913399 -23.638741 2091 44.782959 3.251839 -25.073944 2092 47.899353 0.762070 -24.647453 2093 48.993469 0.532013 -24.342552 2094 44.454193 0.791519 -25.108971 2095 46.366638 -0.767471 -23.161087 2096 47.772781 -0.483963 -23.320969 2097 50.040649 1.238266 -24.962437 2098 50.469788 0.459656 -24.133999 2099 51.070099 0.838989 -24.512058 2100 51.281296 1.458313 -24.867199 2101 52.288040 1.673981 -24.289597 2102 51.266876 0.582397 -24.011395 2103 28.757523 -3.259216 -26.799351 2104 21.606529 -4.958359 -25.981140 2105 44.541138 -3.154648 -24.646255 2106 48.429291 -4.803802 -25.860069 2107 48.227371 -6.181992 -25.840244 2108 47.384277 -5.429520 -25.087784 2109 21.519028 -5.970673 -25.937439 2110 47.451859 -6.701202 -25.313416 2111 22.103912 -7.920135 -26.222557 2112 22.492043 -9.367905 -26.350380 2113 45.982910 -9.829224 -25.466721 2114 45.779282 -9.256821 -24.358322 2115 45.425949 -10.492538 -24.339996 2116 45.470718 -9.713135 -23.121552 2117 22.991180 -10.265060 -26.595352 2118 22.567184 -10.467743 -26.169102 2119 24.763077 -12.618744 -26.591579 2120 38.816071 -9.333359 -25.937473 2121 40.946167 -11.513031 -25.725071 2122 51.768646 -10.492157 -25.567535 2123 50.765518 -10.850616 -25.597397 2124 37.638458 -11.591949 -26.407539 2125 46.108704 -11.393448 -25.527534 2126 49.774384 -11.482254 -26.024250 2127 23.570343 -12.501694 -26.113144 2128 22.809128 -13.561096 -25.115147 2129 24.209671 -13.810089 -25.944603 2130 38.442245 -13.626556 -26.208733 2131 41.597443 -12.517181 -26.221581 2132 47.904114 -12.224854 -25.947479 2133 47.167175 -12.114365 -25.184830 2134 54.656708 -12.425507 -25.168983 2135 55.927994 -12.110214 -26.141003 2136 56.032074 -12.741440 -25.564686 2137 56.639496 -13.518051 -25.389008 2138 25.656052 -13.937363 -26.180244 2139 26.801895 -13.268723 -26.502983 2140 26.719589 -13.828842 -26.056801 2141 28.847923 -13.839661 -25.526733 2142 42.059113 -13.564941 -25.761452 2143 39.133247 -15.211548 -26.097252 2144 38.765808 -14.265015 -25.034142 2145 58.151291 -14.754318 -25.593826 2146 29.234726 -15.868393 -26.454620 2147 29.023804 -15.503922 -25.709621 2148 28.879539 -16.545547 -26.043831 2149 32.918465 -16.388397 -26.758049 2150 34.898865 -16.257538 -26.719467 2151 58.674484 -15.234177 -25.669453 2152 29.644516 -18.127701 -26.809647 2153 33.829750 -16.431107 -26.124336 2154 34.523514 -16.817932 -25.538673 2155 39.325127 -15.661026 -24.943985 2156 43.017502 -16.060059 -24.331207 2157 42.542618 -14.740402 -24.118523 2158 59.223495 -16.643372 -25.177734 2159 28.970169 -17.547089 -26.320049 2160 35.295731 -17.197540 -25.735584 2161 28.856522 -18.875015 -25.874146 2162 30.993935 -19.175156 -26.517288 2163 32.274300 -17.993332 -26.431580 2164 30.080856 -18.893478 -26.684242 2165 32.011658 -18.944168 -25.836403 2166 35.862930 -19.134598 -26.461617 2167 35.818947 -19.910767 -26.857525 2168 44.047852 -18.866196 -24.569042 2169 43.535706 -17.435715 -24.419773 2170 49.816132 -20.289703 -26.183662 2171 50.976898 -19.896606 -26.515488 2172 59.774261 -19.146362 -26.223366 2173 59.907196 -18.320877 -26.079006 2174 30.111626 -19.577805 -26.211689 2175 52.524445 -21.119263 -26.151176 2176 51.237442 -21.319229 -25.629784 2177 59.259857 -20.043808 -26.264931 2178 59.426743 -20.857193 -25.758274 2179 60.237427 -20.048508 -25.087013 2180 46.362930 -21.630554 -24.976685 2181 46.633682 -21.309616 -25.882729 2182 49.549408 -21.661682 -25.130684 2183 48.340561 -20.988327 -25.860432 2184 48.223206 -22.052368 -24.755371 2185 60.173782 -18.904816 -25.430317 2186 47.318909 -21.269363 -26.008633 2187 54.482727 -22.189774 -25.952278 2188 56.131165 -22.320648 -26.074665 2189 56.353683 -21.488113 -26.623470 2190 59.043549 -21.982986 -25.447868 2191 35.950974 -22.965042 -26.480255 2192 41.160980 -24.275192 -25.961571 2193 41.309052 -23.273621 -25.809502 2194 36.465332 -24.285202 -26.427299 2195 37.995071 -25.075638 -26.826141 2196 37.357941 -25.625214 -26.431984 2197 31.138885 18.448090 -22.559067 2198 29.633003 18.439423 -22.880280 2199 32.392754 19.341766 -23.343330 2200 33.321075 19.569199 -23.921421 2201 40.846436 20.423553 -23.022400 2202 41.772736 20.290085 -22.909496 2203 33.346024 18.743866 -23.269653 2204 32.623337 18.326752 -22.772686 2205 38.391502 18.775543 -22.691887 2206 38.755524 19.521912 -22.639229 2207 38.265244 19.230118 -22.257504 2208 28.631149 16.657623 -22.607422 2209 28.517670 15.553116 -22.865677 2210 38.141243 17.424072 -22.654030 2211 28.045998 14.634552 -23.481548 2212 37.857544 14.302811 -22.314880 2213 34.864853 12.588623 -23.030579 2214 37.678268 12.601044 -23.619183 2215 43.219391 15.150497 -20.830112 2216 43.406555 16.466309 -20.709545 2217 42.291748 13.474777 -22.793610 2218 34.222809 13.742065 -22.544014 2219 34.695778 15.264297 -23.234226 2220 37.035324 12.550949 -23.935371 2221 38.018532 12.668854 -23.185799 2222 45.327316 11.607941 -23.584328 2223 46.523010 11.896484 -23.338905 2224 49.240204 12.584488 -22.473343 2225 50.402847 12.612885 -23.379375 2226 50.940857 12.631165 -22.206829 2227 47.744461 11.866379 -22.499443 2228 37.175407 11.934509 -23.587051 2229 36.289215 11.820831 -23.590252 2230 32.773376 13.018906 -22.058395 2231 37.567894 11.724152 -22.587791 2232 44.056274 10.960052 -23.372375 2233 51.063522 12.572067 -21.387035 2234 52.057663 12.244019 -21.539314 2235 34.964172 11.049347 -22.839386 2236 36.936844 11.208923 -23.304974 2237 36.209351 10.539780 -23.156757 2238 42.993652 10.926422 -23.169712 2239 43.096008 10.579163 -22.400528 2240 42.428284 11.360413 -22.658615 2241 43.915039 9.823669 -22.270546 2242 52.840317 10.755280 -23.486794 2243 28.995575 10.166077 -22.949501 2244 53.375610 9.925598 -23.409355 2245 28.796844 8.800537 -23.755966 2246 29.104004 7.895126 -24.215393 2247 23.079819 4.562210 -23.631817 2248 23.186951 4.558037 -24.963760 2249 25.984344 5.699890 -24.251060 2250 29.338470 5.686501 -24.157841 2251 54.820053 7.050095 -22.598953 2252 55.123978 8.149414 -21.397846 2253 28.779068 4.781250 -23.923168 2254 54.784576 5.273468 -23.268490 2255 54.894531 4.164764 -22.881851 2256 55.250488 4.899284 -22.279194 2257 22.649612 3.718384 -24.704079 2258 51.807526 0.969574 -23.980461 2259 53.493134 2.490402 -23.575043 2260 52.887207 1.978409 -23.924393 2261 54.010880 3.176910 -23.649643 2262 20.489258 0.905441 -23.783043 2263 45.272095 -0.128876 -24.361645 2264 44.156250 -2.018097 -24.769215 2265 44.610031 -1.443436 -23.792542 2266 45.330780 -1.287048 -22.870106 2267 50.077591 0.014725 -23.195572 2268 48.966705 -0.376724 -23.198906 2269 51.361816 0.476151 -23.311813 2270 20.716263 -2.927002 -24.477554 2271 44.259033 -2.764297 -23.522690 2272 20.660027 -4.037430 -24.494724 2273 44.601166 -3.845459 -23.588371 2274 20.537598 -5.184448 -24.393150 2275 46.130432 -4.713577 -24.517921 2276 45.174789 -4.011337 -24.340424 2277 45.204010 -4.700943 -23.641766 2278 20.850037 -6.406845 -24.887138 2279 46.642838 -5.751404 -24.402496 2280 21.572525 -6.918121 -25.908852 2281 21.223381 -7.585815 -25.205261 2282 21.566162 -8.815048 -25.397617 2283 46.987106 -6.477036 -24.726616 2284 21.882912 -9.945923 -25.565651 2285 38.356583 -9.755600 -25.666725 2286 39.238533 -9.968658 -25.349396 2287 38.364487 -13.003525 -25.091324 2288 51.013245 -10.560577 -24.844513 2289 51.667664 -10.630707 -24.708534 2290 53.393860 -11.562775 -24.903324 2291 52.003952 -11.393097 -24.087997 2292 22.258453 -11.362427 -25.366920 2293 39.424408 -11.099045 -24.261948 2294 39.343277 -10.588806 -24.703033 2295 40.740631 -11.884460 -24.569283 2296 48.518936 -11.770752 -25.131012 2297 49.805023 -11.125549 -24.635902 2298 50.509399 -10.762085 -24.703850 2299 55.559814 -13.368454 -25.035782 2300 27.908859 -13.489700 -25.718361 2301 28.693192 -12.827560 -25.784901 2302 29.027588 -12.874557 -25.621700 2303 41.522247 -12.574615 -25.221565 2304 23.634949 -14.879166 -25.362614 2305 24.690468 -15.519058 -25.533836 2306 28.819443 -13.106064 -25.500690 2307 28.024017 -14.990524 -24.671997 2308 28.064774 -14.410538 -25.035736 2309 26.997429 -15.673599 -25.062965 2310 42.016815 -13.601746 -24.751896 2311 48.744644 -11.574829 -23.854622 2312 49.174805 -11.679932 -23.015205 2313 47.998169 -12.047531 -22.994808 2314 45.597565 -11.585770 -23.955360 2315 46.458588 -12.179062 -23.119148 2316 45.396820 -11.441971 -22.720459 2317 57.247711 -14.309418 -25.100052 2318 25.849121 -15.381073 -25.602432 2319 26.788940 -14.457169 -25.648670 2320 54.308487 -14.149200 -24.408806 2321 56.158325 -14.514084 -24.605911 2322 55.375183 -15.380539 -24.201324 2323 57.349808 -15.275528 -24.555225 2324 58.398117 -15.736664 -24.814861 2325 24.353790 -17.127869 -24.679321 2326 25.664078 -17.120178 -24.963379 2327 29.162498 -14.645340 -25.360802 2328 28.893616 -15.169388 -24.910500 2329 34.654800 -18.047379 -23.973831 2330 33.871643 -17.525238 -24.815937 2331 33.407669 -18.627319 -23.813324 2332 42.985901 -16.049606 -23.356628 2333 42.505066 -14.804596 -23.067848 2334 32.961349 -17.468536 -25.788113 2335 35.643814 -18.582214 -25.046722 2336 32.744194 -18.677612 -24.826767 2337 59.929230 -17.965958 -25.059635 2338 29.575562 -20.103577 -25.633461 2339 40.666458 -19.673553 -25.781891 2340 43.915833 -18.733002 -23.382980 2341 43.430984 -17.180847 -23.605991 2342 59.991776 -18.978302 -24.086903 2343 59.928329 -18.132950 -24.207050 2344 30.888855 -20.283722 -25.477722 2345 35.886200 -20.139343 -24.730911 2346 47.309204 -21.672821 -25.336739 2347 45.587799 -21.331940 -24.562004 2348 49.025238 -22.599365 -24.016834 2349 50.430878 -22.826279 -23.843231 2350 52.869171 -21.897476 -25.715477 2351 60.101746 -21.223038 -25.065346 2352 60.458282 -19.955093 -23.760807 2353 60.906387 -20.456268 -23.785027 2354 35.714371 -21.343735 -25.002495 2355 52.107407 -22.837616 -24.515388 2356 53.576385 -22.953430 -25.080696 2357 57.468079 -21.857758 -26.116798 2358 60.893372 -21.173340 -24.008377 2359 60.405640 -22.304199 -24.305912 2360 59.655670 -22.679153 -24.819366 2361 35.619843 -21.791092 -23.901978 2362 35.620537 -22.836945 -25.272102 2363 41.346634 -22.703278 -24.811783 2364 55.749054 -24.924667 -24.019135 2365 55.470398 -23.332611 -25.244350 2366 54.382477 -23.776199 -24.631687 2367 57.549347 -22.983551 -25.390305 2368 35.295151 -23.962936 -24.969677 2369 41.462250 -24.058914 -25.124023 2370 57.409805 -24.395874 -24.506645 2371 58.673279 -23.803986 -24.636879 2372 36.301743 -26.197098 -25.933979 2373 35.248138 -26.650055 -25.302635 2374 36.054909 -27.503159 -25.502773 2375 37.742020 -26.833603 -26.012703 2376 36.964966 -27.423477 -25.735821 2377 40.102066 -25.619888 -26.223354 2378 40.901306 -25.384186 -25.211395 2379 40.173111 20.356827 -22.293190 2380 40.995667 20.305115 -21.981815 2381 39.986572 20.067871 -21.502422 2382 33.648743 15.622162 -22.336769 2383 38.442474 19.453247 -22.133156 2384 39.063995 19.737701 -21.976822 2385 39.673996 20.140594 -22.173367 2386 43.167923 19.152802 -21.561577 2387 43.643341 18.440094 -22.195457 2388 28.683617 17.552246 -22.904793 2389 29.672546 17.793549 -22.127628 2390 32.459663 17.405426 -22.162560 2391 29.086792 17.229187 -22.207237 2392 37.631073 15.885101 -21.827633 2393 34.458221 14.582840 -22.765808 2394 33.866379 14.547485 -22.242043 2395 43.824387 15.171432 -19.396393 2396 43.557053 16.920532 -19.278107 2397 28.871689 14.294922 -22.741684 2398 38.004395 12.968002 -22.690758 2399 41.922714 12.566742 -22.815094 2400 51.670990 11.658905 -20.333790 2401 51.449570 12.104584 -20.817810 2402 52.388947 11.810333 -20.671230 2403 37.620186 12.895050 -21.596325 2404 41.981750 12.075226 -22.616989 2405 48.751495 11.809250 -21.794991 2406 50.005371 12.479370 -21.632507 2407 35.285995 9.686142 -22.684635 2408 33.668945 10.174545 -21.976990 2409 32.768700 11.593567 -22.058273 2410 37.006393 10.252899 -22.801659 2411 45.664154 10.898300 -22.847412 2412 45.030579 9.925797 -22.404034 2413 52.981979 11.602097 -21.566780 2414 36.352539 9.509140 -22.792587 2415 37.354996 10.258789 -21.977337 2416 42.329681 12.025848 -21.781105 2417 42.955811 11.018738 -21.082722 2418 53.239349 10.850464 -22.532074 2419 53.818542 9.918915 -22.422813 2420 28.814865 8.687164 -22.719498 2421 28.941299 7.532318 -23.202419 2422 35.891380 8.769241 -22.447311 2423 34.236320 8.364304 -21.816521 2424 54.777908 9.144684 -21.226181 2425 26.272781 5.171181 -23.552956 2426 29.168289 5.690559 -23.144447 2427 23.271683 4.630341 -22.289635 2428 26.242218 4.874435 -22.590260 2429 55.257233 6.002411 -22.111427 2430 27.859207 4.347092 -22.544029 2431 28.992180 4.460434 -23.252800 2432 28.678413 4.254387 -23.291862 2433 55.089386 4.025360 -22.310219 2434 20.808640 2.797363 -22.811024 2435 20.333961 1.904480 -23.224945 2436 21.856758 3.290085 -23.738319 2437 28.731415 4.108894 -22.918949 2438 54.453140 3.038849 -22.262386 2439 52.676971 1.404846 -22.920586 2440 53.662369 2.059601 -22.192375 2441 55.257675 4.094978 -21.295734 2442 21.241928 0.831863 -24.492790 2443 51.612991 0.313751 -21.797203 2444 48.551727 -0.854218 -22.630501 2445 52.951660 0.947693 -20.464851 2446 53.213989 1.521683 -21.245640 2447 19.807495 -0.953293 -22.897186 2448 19.672707 -1.804428 -22.294983 2449 44.276962 -3.920502 -22.402725 2450 44.682755 -4.478485 -23.072220 2451 54.564835 -5.023453 -22.974266 2452 54.967560 -4.671417 -23.182423 2453 54.982681 -4.048004 -22.836079 2454 55.261154 -4.609726 -23.215675 2455 55.569824 -4.591385 -23.149815 2456 56.098404 -4.539505 -22.857147 2457 52.743179 -3.642105 -22.192432 2458 54.183289 -2.876785 -22.207779 2459 19.866791 -6.170624 -23.180950 2460 19.931717 -7.261368 -22.981792 2461 20.469406 -7.293289 -24.055954 2462 45.820618 -5.766632 -23.760708 2463 44.812088 -5.303665 -22.644981 2464 46.458176 -6.560806 -24.297283 2465 55.500519 -5.191772 -22.947025 2466 56.147522 -6.073135 -22.462452 2467 56.975616 -5.155396 -22.238201 2468 20.933739 -8.350952 -24.476494 2469 45.400604 -6.537384 -22.794495 2470 45.977722 -6.851471 -23.876507 2471 45.783173 -8.413498 -23.369144 2472 45.783875 -7.477707 -23.469704 2473 21.187996 -9.828552 -24.501549 2474 21.217873 -11.261978 -24.173550 2475 45.101746 -10.470917 -23.634415 2476 45.125076 -10.999191 -23.603165 2477 50.726654 -10.951523 -24.009987 2478 41.388947 -12.802582 -24.086739 2479 49.766876 -11.280930 -23.545792 2480 52.987152 -12.597580 -24.208912 2481 21.450912 -12.634491 -23.974091 2482 40.523514 -12.498734 -23.441509 2483 41.185699 -13.376297 -22.804024 2484 51.742630 -12.331253 -23.175758 2485 41.956177 -13.776215 -23.638046 2486 47.438049 -12.115280 -24.075684 2487 46.404083 -12.092636 -24.342587 2488 52.277588 -13.195160 -23.524162 2489 52.881195 -13.730286 -24.046432 2490 28.902267 -14.356201 -24.935883 2491 29.085930 -14.655823 -24.831432 2492 38.585434 -13.349487 -23.358185 2493 38.507935 -13.282104 -24.130119 2494 39.002533 -14.667725 -23.375591 2495 52.254410 -14.209549 -23.405746 2496 52.963928 -14.820953 -23.999737 2497 53.678101 -15.844772 -23.866077 2498 22.736336 -15.484161 -24.328201 2499 26.828506 -17.053146 -24.954514 2500 28.025986 -16.402710 -24.773155 2501 28.137711 -15.615448 -24.704185 2502 27.510284 -16.435150 -24.886490 2503 52.421661 -15.023300 -23.663189 2504 54.618790 -15.710999 -24.107731 2505 52.709137 -15.576492 -23.655182 2506 56.423279 -16.215134 -23.933502 2507 23.744080 -16.069946 -24.950607 2508 27.898354 -17.338470 -25.166443 2509 28.511276 -16.130371 -25.095123 2510 39.714226 -16.687378 -24.673714 2511 42.864777 -15.999100 -22.212387 2512 57.658707 -16.549973 -23.934872 2513 26.731873 -18.313873 -24.705517 2514 27.662491 -18.521652 -24.999641 2515 33.820343 -16.917648 -25.450836 2516 34.869858 -17.457901 -24.929466 2517 58.578125 -16.754196 -24.143021 2518 27.519981 -19.683182 -24.706703 2519 28.695602 -20.187424 -25.238197 2520 59.338882 -17.574982 -24.110081 2521 28.350639 -20.885071 -24.723137 2522 35.872719 -19.645294 -23.865112 2523 39.807053 -17.278305 -23.836864 2524 40.619751 -19.694443 -25.013828 2525 43.442245 -17.449829 -22.617153 2526 43.225662 -17.337524 -21.383595 2527 43.800537 -19.199112 -21.732620 2528 31.928102 -19.826645 -24.943405 2529 29.516068 -21.119141 -24.927044 2530 29.599518 -22.313980 -23.897949 2531 30.873886 -21.509872 -24.173916 2532 31.612169 -20.650620 -24.477489 2533 45.015289 -20.713776 -24.572845 2534 44.647308 -19.938538 -24.877686 2535 47.218842 -22.120987 -24.491791 2536 40.789368 -20.726517 -24.014465 2537 41.063599 -22.397064 -23.448563 2538 58.918793 -22.976227 -24.978607 2539 61.294022 -22.360916 -22.555775 2540 59.838440 -23.364227 -24.379410 2541 60.948730 -23.684937 -23.494484 2542 35.293716 -23.054703 -23.885452 2543 35.023643 -23.748901 -22.687649 2544 34.955704 -24.227493 -24.102741 2545 41.320618 -24.584869 -24.041637 2546 41.409637 -23.619293 -24.066605 2547 59.568466 -24.118652 -24.161777 2548 60.181778 -23.967270 -23.972836 2549 35.137131 -25.255234 -25.034477 2550 40.440063 -26.732635 -24.349449 2551 36.105881 -28.796387 -24.864723 2552 36.935692 -28.318176 -25.387787 2553 35.073715 -27.652786 -25.006653 2554 37.923027 -28.145691 -25.319069 2555 38.897324 -28.945145 -23.853806 2556 40.012985 -27.837723 -23.724224 2557 37.587250 -28.968948 -24.827782 2558 50.943054 -43.912338 -24.723602 2559 50.949829 -45.121185 -24.752384 2560 51.420807 -45.077728 -25.151459 2561 53.012695 -43.564545 -25.789612 2562 53.666412 -42.530716 -25.359650 2563 52.725311 -42.654922 -25.439590 2564 52.091583 -43.387634 -25.525261 2565 51.824631 -42.549911 -25.049889 2566 54.029892 -43.790344 -25.686737 2567 52.124176 -44.427719 -25.608337 2568 53.239105 -44.989502 -25.788033 2569 54.117615 -44.822815 -25.746819 2570 54.831589 -44.495010 -25.271221 2571 54.912659 -42.724228 -24.916924 2572 55.714844 -44.138092 -24.302910 2573 56.315414 -42.205231 -23.785400 2574 52.180176 -46.489609 -25.181515 2575 52.198212 -45.624268 -25.403790 2576 51.215240 -46.051041 -24.626804 2577 38.225174 18.753174 -21.681049 2578 37.522209 17.164642 -21.100422 2579 39.143318 19.439697 -20.773178 2580 41.166565 19.689072 -20.294823 2581 42.413498 19.434784 -21.053459 2582 31.392059 17.192474 -21.730103 2583 42.893524 19.084198 -20.987747 2584 43.290054 18.561310 -20.905266 2585 42.623093 18.996124 -20.429886 2586 43.626602 18.281616 -21.485058 2587 43.559708 17.675537 -21.047363 2588 29.716141 17.308914 -21.756050 2589 29.429268 17.293152 -21.903694 2590 30.384201 17.267014 -21.767399 2591 33.227585 16.789520 -22.247437 2592 32.011971 16.505463 -21.639725 2593 29.506355 16.539536 -22.012436 2594 32.784210 16.411224 -21.899868 2595 33.291870 14.858292 -21.970650 2596 37.241776 15.016754 -20.346809 2597 43.240097 17.978851 -20.054474 2598 43.663757 18.367203 -18.361446 2599 29.614845 15.161743 -22.129196 2600 32.329575 15.349991 -21.726383 2601 30.691734 14.052338 -21.967674 2602 30.579597 12.421204 -22.136726 2603 32.959106 14.160828 -21.917126 2604 37.393448 11.996979 -21.004471 2605 37.349701 11.020111 -20.973198 2606 42.974564 13.908096 -20.945042 2607 37.298706 13.868103 -20.199551 2608 42.076157 12.603668 -22.296970 2609 50.477875 12.082733 -21.028145 2610 49.576248 11.752289 -21.252945 2611 42.414337 12.883652 -21.670017 2612 46.754684 11.077072 -22.447685 2613 47.667007 10.866699 -21.873756 2614 53.674652 10.810028 -21.472450 2615 30.596436 9.566818 -21.248436 2616 30.062729 10.172028 -21.782005 2617 31.727396 10.282715 -21.442368 2618 37.215759 9.794891 -20.742924 2619 43.265686 9.746658 -21.530258 2620 43.749664 8.617996 -20.861164 2621 43.449234 9.737915 -20.468464 2622 46.466873 9.994446 -22.039364 2623 54.290894 9.928986 -21.403969 2624 54.061737 10.705902 -20.439468 2625 29.458572 8.857590 -21.845257 2626 30.539673 8.603745 -21.099674 2627 36.888412 9.077209 -21.957771 2628 44.778854 8.581421 -19.009220 2629 44.433884 9.741898 -19.434669 2630 43.964371 8.757324 -19.947151 2631 44.789154 8.908691 -21.913559 2632 43.983398 8.914307 -21.671406 2633 45.713684 9.085999 -21.903545 2634 28.956871 7.914795 -22.322315 2635 32.896759 9.515045 -21.370403 2636 35.990067 7.868439 -22.008736 2637 36.696945 8.053635 -21.172611 2638 36.316589 7.238266 -21.581650 2639 37.073349 8.881210 -20.958580 2640 45.639679 8.251160 -21.526791 2641 29.160309 6.837234 -22.266659 2642 35.162582 7.015747 -21.778782 2643 35.945534 7.121429 -21.949200 2644 55.529022 7.015305 -21.016338 2645 55.535431 7.972092 -20.610199 2646 55.671326 5.539917 -20.880287 2647 29.006683 4.492088 -22.554932 2648 33.884399 6.503876 -20.877201 2649 35.656921 5.716415 -19.968727 2650 35.247025 6.065002 -20.878410 2651 36.269119 6.911957 -20.442577 2652 35.889572 6.757217 -21.510696 2653 24.172928 4.753525 -21.530769 2654 25.263184 4.842484 -21.721497 2655 26.193298 4.412628 -21.248600 2656 22.499634 4.057343 -21.284382 2657 21.867561 3.731102 -22.387405 2658 23.315948 4.468643 -21.411308 2659 27.025940 4.144470 -20.730682 2660 28.646782 4.116661 -22.507523 2661 28.143097 4.357361 -20.799194 2662 28.639580 4.372513 -21.972130 2663 29.240265 5.482628 -21.505413 2664 20.244781 2.375366 -22.621651 2665 19.997772 1.881073 -22.542408 2666 54.783295 3.108841 -20.788200 2667 19.927261 1.337555 -22.914295 2668 19.838760 0.825714 -22.963829 2669 49.541397 -0.779510 -22.008499 2670 48.938416 -1.888336 -21.287571 2671 49.850143 -1.668243 -21.106171 2672 48.021408 -1.634247 -21.630856 2673 46.788727 -1.619873 -21.804264 2674 45.744675 -1.680344 -21.818340 2675 55.468262 -1.218018 -20.839855 2676 53.918884 -1.581024 -20.828232 2677 54.444107 -2.109268 -21.633080 2678 55.719986 -2.619232 -22.112434 2679 56.689865 -2.057938 -21.587742 2680 56.759781 -2.709549 -22.114784 2681 19.659683 -3.201584 -22.429707 2682 44.551605 -2.370270 -22.250156 2683 53.102722 -2.263763 -21.318073 2684 53.423767 -5.254929 -22.665352 2685 56.840912 -3.631973 -22.173622 2686 57.937454 -2.965973 -20.835342 2687 57.252441 -2.698380 -21.727989 2688 57.424911 -2.109619 -21.068058 2689 19.624062 -4.254395 -22.560806 2690 51.600739 -2.353989 -21.024994 2691 19.496002 -5.143814 -22.427746 2692 50.772812 -3.759232 -21.679657 2693 49.499985 -4.318527 -21.529701 2694 50.315231 -5.298569 -21.977489 2695 51.734131 -5.185425 -22.389305 2696 54.664963 -6.429016 -22.286613 2697 55.532410 -7.385773 -21.253994 2698 56.110336 -6.740936 -21.980709 2699 44.863297 -6.010208 -21.976566 2700 52.249756 -6.457962 -22.323090 2701 50.973969 -6.396530 -22.187935 2702 53.280334 -6.641891 -22.212349 2703 57.305862 -6.301956 -21.761982 2704 20.243774 -8.680038 -23.177109 2705 49.777786 -7.758774 -21.315239 2706 50.290649 -8.326035 -20.740974 2707 51.222382 -7.607880 -21.403915 2708 56.892700 -7.172333 -21.179230 2709 58.197906 -5.547913 -21.004269 2710 57.971161 -4.283340 -21.095394 2711 45.637115 -7.466034 -22.297462 2712 45.994781 -8.488785 -21.734425 2713 39.564903 -11.910706 -23.748539 2714 20.813583 -11.744675 -23.271454 2715 20.236908 -11.632431 -22.071823 2716 20.635849 -12.599930 -22.538879 2717 38.758011 -12.159271 -23.583099 2718 45.138855 -10.632095 -23.045044 2719 32.775818 -11.191132 -21.091803 2720 32.565971 -11.153885 -21.005869 2721 32.730141 -11.055603 -20.990892 2722 33.316040 -11.150055 -20.984137 2723 33.225601 -11.521240 -21.106199 2724 33.900749 -11.054474 -20.963152 2725 33.794685 -11.272964 -21.054960 2726 34.039261 -11.156662 -20.953539 2727 38.509094 -12.604874 -23.612862 2728 46.063461 -12.105057 -21.964691 2729 21.704422 -14.307114 -23.552818 2730 32.752861 -11.378143 -21.034666 2731 33.035759 -11.605515 -20.989527 2732 33.589935 -11.608063 -21.021692 2733 33.859528 -11.370834 -20.948587 2734 41.938599 -14.144592 -22.552933 2735 52.050507 -15.207397 -22.908905 2736 28.656097 -14.771988 -24.667576 2737 33.314339 -11.742462 -21.014727 2738 38.964958 -13.622299 -22.802383 2739 21.684135 -15.901520 -22.779518 2740 22.501717 -16.632065 -23.630684 2741 51.875595 -14.227692 -22.384796 2742 51.659851 -13.206421 -22.291489 2743 23.358002 -16.950134 -24.246780 2744 39.399811 -16.124863 -23.844086 2745 42.307922 -14.856628 -22.121307 2746 51.793289 -17.412460 -21.574650 2747 51.762299 -15.973724 -22.090271 2748 52.686752 -16.513535 -23.045677 2749 54.456116 -16.368637 -23.868408 2750 55.235397 -16.568863 -23.790955 2751 22.900475 -17.806641 -23.454395 2752 23.889908 -18.206848 -23.886868 2753 24.815079 -18.222534 -24.326965 2754 34.013855 -18.758362 -22.806953 2755 34.934235 -18.578094 -23.040974 2756 54.133850 -17.044128 -23.430038 2757 55.155029 -17.679916 -23.336884 2758 57.027298 -17.794037 -23.362259 2759 55.993912 -17.490448 -23.483055 2760 58.463242 -17.957199 -23.493122 2761 22.134796 -17.108246 -22.924149 2762 25.720131 -18.863144 -24.324997 2763 35.421341 -18.691788 -23.718983 2764 53.098801 -17.590942 -22.707829 2765 59.230408 -18.029434 -23.674149 2766 59.679993 -18.199432 -23.846855 2767 24.752968 -19.294510 -23.736027 2768 26.506920 -19.318146 -24.365860 2769 32.811142 -19.866287 -22.665524 2770 35.561249 -19.392014 -22.936157 2771 34.797791 -19.249588 -22.212723 2772 40.243347 -18.803558 -23.872463 2773 54.248444 -18.127930 -22.768833 2774 55.721939 -18.568741 -22.795128 2775 54.130203 -19.287735 -21.660339 2776 57.528915 -19.374405 -22.500340 2777 59.518646 -20.232147 -22.600708 2778 57.964401 -20.821304 -21.551102 2779 59.321762 -18.449905 -23.566582 2780 60.692001 -20.556442 -22.922325 2781 26.167877 -20.301392 -23.842575 2782 35.796005 -20.609482 -23.127220 2783 44.538742 -20.005417 -23.918808 2784 27.577713 -21.184158 -24.195187 2785 32.393867 -19.829285 -23.999557 2786 45.125076 -21.067139 -23.559696 2787 59.031479 -19.021210 -23.168179 2788 26.846077 -21.815399 -23.443413 2789 27.329834 -22.910110 -23.043602 2790 28.129684 -22.305176 -23.778130 2791 28.624458 -21.702026 -24.385445 2792 31.333298 -21.911041 -22.869102 2793 31.846529 -20.921829 -23.362713 2794 35.881180 -20.782913 -24.066753 2795 61.086746 -21.114960 -22.953056 2796 28.614594 -23.233322 -23.139481 2797 27.468231 -23.848816 -22.505962 2798 28.514877 -24.151535 -22.255943 2799 29.267845 -23.669022 -22.651253 2800 29.896805 -23.038986 -22.832886 2801 46.469940 -22.049622 -23.613747 2802 47.955505 -22.513138 -23.725845 2803 61.052185 -24.745834 -23.214203 2804 61.822205 -24.561707 -22.588150 2805 40.667465 -20.964539 -22.697186 2806 40.668457 -22.048004 -22.012589 2807 53.496765 -24.209335 -23.712070 2808 58.948807 -24.810745 -24.028801 2809 34.645531 -25.124527 -23.735703 2810 58.016556 -26.003479 -23.492649 2811 60.196716 -24.720047 -23.663837 2812 56.431915 -26.400360 -23.017708 2813 57.413803 -27.523895 -22.607948 2814 59.512451 -25.628555 -23.433495 2815 60.856110 -25.955917 -22.807930 2816 34.370758 -26.526077 -24.324051 2817 59.424957 -26.483658 -22.997902 2818 34.171082 -25.930740 -23.270901 2819 33.625000 -26.832672 -23.272133 2820 35.709534 -31.596710 -22.897705 2821 34.287140 -30.731750 -23.610500 2822 34.133591 -31.558075 -22.979210 2823 33.930573 -28.503815 -24.117371 2824 35.565720 -30.089462 -24.007668 2825 38.363716 -30.230270 -23.288002 2826 38.545486 -29.909607 -23.380974 2827 37.655441 -29.871582 -23.986698 2828 36.593384 -31.968399 -22.333744 2829 36.881729 -31.656235 -22.546738 2830 52.856644 -41.737427 -24.927101 2831 54.023712 -41.347168 -24.682777 2832 52.959381 -40.494202 -23.937057 2833 51.731384 -41.556717 -24.322411 2834 50.670334 -42.597168 -24.025990 2835 50.768204 -41.465622 -23.390602 2836 54.591324 -39.709106 -23.788795 2837 55.245392 -41.238235 -24.264320 2838 51.180283 -42.583115 -24.611397 2839 54.010193 -46.484787 -25.188301 2840 53.617004 -46.969315 -24.600418 2841 54.796219 -45.744293 -24.653549 2842 55.418793 -45.226242 -23.757694 2843 55.852600 -44.596756 -23.553341 2844 53.103455 -46.407944 -25.340553 2845 54.082428 -45.657486 -25.450302 2846 52.220428 -47.024094 -24.764019 2847 37.946564 18.323776 -20.402725 2848 40.384918 19.507446 -17.423569 2849 41.964951 19.511658 -18.222713 2850 41.805542 19.513626 -16.489628 2851 37.657379 17.868393 -19.214619 2852 39.000504 19.140518 -19.360138 2853 37.363281 17.522308 -20.268024 2854 37.180054 16.958405 -20.032982 2855 30.808289 15.955338 -21.675125 2856 42.571716 18.982849 -19.455524 2857 37.138329 16.104980 -20.262157 2858 42.967896 12.467316 -20.719372 2859 30.372101 11.178696 -22.050755 2860 37.224998 12.805786 -19.929039 2861 44.045059 11.717453 -19.772785 2862 50.032639 11.245712 -20.862366 2863 50.952118 11.384857 -20.498936 2864 53.230560 11.291931 -20.517616 2865 43.905197 10.656113 -19.873917 2866 48.975784 10.732788 -21.159103 2867 53.506073 10.827744 -19.425858 2868 29.843193 7.779663 -21.422371 2869 32.207207 9.567215 -21.050205 2870 31.519028 9.253281 -20.966095 2871 32.504044 8.751404 -21.032276 2872 47.879395 9.627167 -21.324123 2873 54.691971 9.941559 -20.241264 2874 46.805237 8.534042 -21.392082 2875 49.380188 9.361938 -20.603012 2876 48.471405 8.133453 -20.717945 2877 50.318832 10.431412 -20.419987 2878 55.331894 8.834106 -20.256660 2879 55.190903 9.617233 -19.309124 2880 29.280869 7.667328 -21.871429 2881 30.508698 7.727936 -20.965561 2882 36.959427 8.673309 -19.754974 2883 47.490326 7.245300 -20.863468 2884 46.156555 7.356323 -21.083557 2885 49.229340 7.024246 -19.820976 2886 48.381134 7.170547 -20.502453 2887 29.530975 6.892685 -21.632286 2888 30.090042 6.819839 -20.962017 2889 32.576355 7.499435 -20.747887 2890 44.848480 6.296860 -19.556858 2891 45.149536 5.118073 -19.211399 2892 44.981750 5.671677 -18.307396 2893 44.784561 7.882141 -21.168373 2894 44.433533 7.662781 -19.985340 2895 30.028961 5.967430 -20.275620 2896 31.998735 6.102066 -19.694248 2897 34.030884 5.327454 -19.455532 2898 46.832825 6.239090 -20.452248 2899 46.957291 5.155914 -19.884014 2900 45.738373 5.606781 -20.043018 2901 24.919098 4.269707 -20.335110 2902 28.639557 4.648102 -18.525124 2903 28.056450 4.408272 -19.509354 2904 29.265244 5.067177 -19.854752 2905 20.903610 3.147507 -21.774773 2906 20.259415 2.449951 -21.763866 2907 19.753372 1.144745 -21.993053 2908 20.014351 2.002609 -20.694931 2909 53.929672 2.200241 -21.340504 2910 54.324356 2.538574 -20.957520 2911 19.699219 1.023163 -20.437218 2912 50.824738 -0.724319 -21.011784 2913 19.561577 -0.189301 -21.509979 2914 19.269257 -0.949097 -20.051064 2915 45.101028 -1.809540 -21.885639 2916 44.993225 -2.464127 -21.215599 2917 50.550049 -1.495422 -20.684151 2918 56.838806 -1.363647 -20.784874 2919 57.874237 -1.141953 -19.692913 2920 56.884094 -0.832886 -20.268082 2921 53.165558 -1.720215 -20.650887 2922 44.294250 -4.240646 -21.463959 2923 44.428131 -3.466599 -21.178974 2924 49.002029 -5.354126 -21.467621 2925 50.450165 -2.326889 -20.925789 2926 49.396454 -2.975433 -21.174137 2927 18.777519 -4.601257 -20.459789 2928 44.610596 -5.517090 -21.849133 2929 44.471390 -4.886490 -21.697342 2930 18.998932 -5.800293 -21.104698 2931 49.819305 -6.243851 -21.869152 2932 19.329254 -6.852478 -21.777790 2933 18.645447 -6.557510 -20.268665 2934 45.323364 -6.494507 -21.563065 2935 58.083282 -6.345291 -21.219303 2936 19.610313 -7.826309 -22.048721 2937 47.583038 -6.875702 -20.961708 2938 47.658051 -8.375778 -20.668625 2939 48.688995 -7.894836 -21.024303 2940 57.797409 -7.878204 -20.111656 2941 57.797012 -7.155090 -20.853729 2942 57.792542 -6.759659 -21.206478 2943 19.310730 -8.848679 -21.264923 2944 19.900139 -9.721390 -22.161755 2945 45.455872 -10.621628 -22.015892 2946 48.912903 -6.687607 -21.386116 2947 50.098541 -7.041580 -21.774590 2948 52.529175 -7.386703 -21.576199 2949 53.533203 -7.607071 -21.016796 2950 54.583588 -7.562332 -20.990192 2951 20.479019 -10.531784 -23.090897 2952 45.523605 -11.482224 -21.768250 2953 45.616028 -11.169159 -21.233482 2954 50.490891 -11.631897 -23.020348 2955 21.032715 -13.531586 -22.772728 2956 32.840073 -11.271332 -20.923735 2957 33.402275 -11.498764 -20.906366 2958 33.819466 -11.190155 -20.887747 2959 38.894150 -12.751419 -23.141953 2960 45.834900 -11.749283 -21.135189 2961 47.380920 -12.338089 -21.845200 2962 49.252457 -12.133942 -22.018253 2963 50.574570 -12.550720 -21.563961 2964 49.730652 -12.456451 -20.274410 2965 48.323669 -12.383408 -20.923527 2966 50.750214 -12.279266 -22.337769 2967 39.852295 -13.375671 -22.446152 2968 20.915466 -14.604584 -21.821739 2969 51.691437 -14.737213 -22.074982 2970 51.623260 -15.266068 -22.183449 2971 21.458015 -17.424179 -21.740509 2972 22.362000 -18.128952 -22.691818 2973 39.495079 -16.383087 -22.731106 2974 42.388306 -15.334061 -21.375835 2975 40.071121 -16.525696 -20.294453 2976 39.778343 -16.152115 -20.879951 2977 39.945862 -17.287613 -21.220715 2978 39.920937 -17.747635 -22.757000 2979 53.083984 -18.277603 -22.171555 2980 23.403275 -19.332550 -22.938965 2981 33.723701 -19.840973 -21.550301 2982 35.467201 -20.123703 -22.189003 2983 52.605728 -18.639496 -21.510403 2984 55.814728 -19.433624 -22.136448 2985 24.713608 -20.568375 -23.070801 2986 40.280075 -19.338089 -22.296120 2987 44.491348 -20.227066 -22.839085 2988 22.720284 -20.431808 -21.766720 2989 23.771072 -20.928909 -22.285725 2990 40.394012 -20.685593 -21.523155 2991 44.878952 -21.030502 -22.721382 2992 25.688431 -21.621277 -23.001213 2993 26.376831 -22.488235 -22.826851 2994 30.638039 -22.422180 -23.109859 2995 45.476898 -21.693130 -22.609612 2996 29.263206 -24.045761 -22.161613 2997 46.768356 -22.638199 -22.126488 2998 48.197174 -23.049271 -21.971256 2999 47.724350 -22.663544 -22.806877 3000 49.072266 -23.052444 -22.774780 3001 60.597229 -21.364456 -22.093582 3002 29.794281 -23.630447 -22.139252 3003 40.996155 -23.682327 -22.697075 3004 40.853149 -25.631546 -22.723785 3005 49.477936 -23.637680 -21.400917 3006 50.577667 -23.850784 -21.213242 3007 50.695099 -23.654221 -22.061531 3008 51.979904 -23.925232 -22.915970 3009 52.927856 -24.488922 -22.793610 3010 54.297882 -25.756134 -21.959690 3011 53.663025 -24.974854 -22.657394 3012 52.925461 -24.831421 -21.983475 3013 61.762238 -23.449966 -22.571209 3014 34.078789 -25.977448 -22.303570 3015 34.652351 -25.120972 -22.630913 3016 34.755630 -24.659286 -21.278492 3017 54.873901 -25.517624 -22.911911 3018 62.259460 -25.775558 -22.130295 3019 32.268730 -29.029892 -23.417908 3020 33.203003 -29.960754 -23.659924 3021 55.664062 -26.751831 -22.213394 3022 56.545212 -27.163116 -22.556278 3023 61.845612 -26.848923 -22.117729 3024 62.104431 -23.686203 -21.627121 3025 31.562164 -27.855713 -22.344475 3026 31.886477 -28.228821 -23.045597 3027 32.660614 -27.571304 -22.974220 3028 32.186432 -27.289169 -21.464973 3029 32.610413 -28.278336 -23.548767 3030 59.915390 -27.218872 -22.449883 3031 58.718964 -27.465591 -22.585831 3032 31.635149 -30.351547 -22.796967 3033 40.571075 -27.180893 -23.212330 3034 33.090485 -31.047348 -23.143417 3035 34.210022 -29.858887 -23.983971 3036 38.075134 -30.456680 -23.233669 3037 37.240784 -30.927399 -23.051308 3038 34.965683 -33.062332 -21.461876 3039 35.907272 -32.424805 -21.943623 3040 34.422195 -32.340118 -22.149612 3041 55.750458 -34.437073 -22.529720 3042 54.924789 -35.412827 -22.841820 3043 56.745712 -35.996933 -22.856464 3044 54.662186 -36.590164 -23.182755 3045 53.672913 -35.977509 -22.394352 3046 53.879181 -37.741913 -22.744141 3047 55.646759 -36.580795 -23.354530 3048 55.225800 -38.449936 -23.620773 3049 56.587326 -37.384003 -23.412174 3050 55.315308 -37.486130 -23.500980 3051 57.265350 -38.341309 -23.271160 3052 57.933304 -37.499847 -22.842186 3053 53.142151 -39.249176 -22.783009 3054 56.442123 -39.114944 -23.558792 3055 56.234619 -38.197281 -23.625420 3056 51.831680 -40.589661 -23.483994 3057 51.163971 -40.271423 -22.570541 3058 52.245880 -39.906967 -22.782230 3059 56.499680 -40.452789 -23.580154 3060 58.413757 -39.319336 -22.343925 3061 57.517197 -41.321701 -22.721046 3062 57.604767 -42.151703 -21.849190 3063 57.037689 -42.581345 -22.726715 3064 56.829956 -43.083832 -21.976490 3065 50.193329 -43.466614 -23.891979 3066 49.924500 -44.396988 -23.660057 3067 50.512482 -45.138916 -24.221565 3068 50.832275 -47.281555 -23.792461 3069 54.403732 -46.090302 -23.042557 3070 52.439270 -47.734039 -24.146809 3071 51.672775 -48.422546 -23.274559 3072 52.697037 -48.077744 -23.368530 3073 53.365662 -47.451859 -23.658859 3074 53.045609 -47.257538 -22.226662 3075 40.263046 19.575623 -18.618763 3076 37.197769 16.647385 -18.834179 3077 37.632538 17.436920 -17.961876 3078 37.430573 16.711166 -17.850151 3079 38.307526 18.622391 -18.372425 3080 37.373505 13.603424 -18.441124 3081 37.501343 14.797424 -18.049625 3082 37.197601 11.852371 -19.623299 3083 37.184143 10.868652 -19.509243 3084 37.595734 11.812225 -17.920006 3085 37.634964 10.848145 -17.898129 3086 51.953583 10.791153 -19.800518 3087 44.212463 13.159882 -19.582405 3088 51.439331 8.984955 -18.864090 3089 52.782379 10.060394 -18.448307 3090 52.246918 9.008881 -17.890968 3091 54.267456 10.542694 -19.469505 3092 54.718796 10.164429 -18.915359 3093 31.441101 8.039139 -20.743462 3094 37.161606 9.993515 -19.300667 3095 53.089355 9.495041 -17.451408 3096 50.668076 9.498047 -19.849113 3097 30.812569 6.606735 -20.184841 3098 30.841507 7.273865 -20.564625 3099 51.369904 7.700165 -17.920368 3100 55.732819 8.786896 -18.821007 3101 31.517548 7.094467 -20.299644 3102 30.597565 5.683640 -19.384987 3103 30.788712 6.139694 -19.808567 3104 45.329407 6.733612 -20.505257 3105 50.021454 8.336655 -19.771145 3106 55.973846 7.633224 -19.675220 3107 34.524582 5.587029 -20.443245 3108 36.019562 6.169754 -19.317253 3109 36.610054 7.252228 -18.988056 3110 48.123047 6.576340 -20.329788 3111 56.067719 6.408051 -19.982475 3112 23.447968 4.098740 -20.277737 3113 35.013298 5.339935 -20.002357 3114 48.341095 5.725983 -19.585289 3115 47.874161 4.844864 -19.319355 3116 48.877701 4.439453 -18.386688 3117 55.969070 4.300812 -19.719975 3118 56.278214 5.515190 -19.572586 3119 21.425827 3.450836 -21.043491 3120 46.066315 4.750702 -19.607506 3121 47.318604 4.053375 -19.010635 3122 45.738739 4.068527 -18.843288 3123 20.388695 2.655518 -20.700344 3124 20.730103 2.991226 -21.033051 3125 21.995026 3.520180 -19.744209 3126 55.006821 2.891663 -19.866837 3127 55.305542 3.540253 -20.158619 3128 53.973450 1.997757 -20.478802 3129 54.537720 2.402588 -20.114403 3130 53.609192 1.537216 -20.171394 3131 50.892715 -1.790985 -20.599781 3132 51.416977 -1.230423 -20.498917 3133 52.659973 -0.185593 -20.230694 3134 56.324890 -0.949249 -20.486038 3135 47.121307 -2.745316 -20.921234 3136 47.809601 -2.655212 -20.942257 3137 48.371292 -2.582642 -21.067432 3138 54.069305 -0.529556 -20.022980 3139 44.602051 -3.671646 -20.671761 3140 44.886383 -3.269608 -20.711845 3141 45.856598 -2.845749 -20.896774 3142 48.126099 -3.790070 -21.030453 3143 52.471725 -1.497971 -20.516808 3144 55.099655 0.421661 -19.517902 3145 58.072952 0.959824 -18.235775 3146 56.932953 0.369949 -19.336620 3147 58.690613 -2.645584 -19.145176 3148 47.777237 -5.442245 -21.011051 3149 46.451355 -5.656067 -20.707638 3150 45.076904 -4.378281 -20.832275 3151 44.822006 -5.553223 -21.333023 3152 58.528732 -3.653381 -19.884716 3153 58.639694 -4.552689 -19.975719 3154 46.579224 -6.699753 -20.843636 3155 46.001968 -7.180817 -21.279182 3156 45.916489 -6.365417 -20.892803 3157 46.771423 -7.662857 -21.035053 3158 58.487396 -6.737427 -20.434395 3159 45.739594 -9.673813 -21.629246 3160 48.698944 -8.655777 -20.548725 3161 52.266388 -8.139084 -20.345600 3162 51.795151 -8.942444 -19.131176 3163 53.254547 -8.524109 -19.238537 3164 54.238449 -8.539307 -18.861107 3165 54.329987 -8.109344 -19.751595 3166 55.171616 -7.929352 -20.174347 3167 56.235397 -7.943329 -20.147354 3168 19.393433 -9.917358 -21.045856 3169 18.761810 -7.633926 -20.432465 3170 49.442413 -8.437149 -20.767803 3171 49.538849 -9.142029 -19.878616 3172 51.033234 -8.639511 -20.070202 3173 19.831253 -10.699997 -21.576920 3174 45.948837 -10.447449 -20.893642 3175 46.206696 -9.371628 -20.950676 3176 20.078369 -12.567642 -21.179886 3177 20.523888 -13.418900 -21.737801 3178 33.213272 -12.715256 -21.553329 3179 33.009186 -12.773514 -21.216286 3180 33.399689 -12.455276 -21.295361 3181 33.783302 -12.693115 -21.531563 3182 34.110382 -12.430878 -21.182121 3183 33.386047 -12.495560 -20.495090 3184 34.416779 -12.639023 -20.563606 3185 34.326881 -12.626968 -21.441418 3186 34.486725 -12.618027 -21.207489 3187 51.397324 -12.935730 -20.802677 3188 54.543640 -12.525024 -20.665257 3189 54.318481 -12.334885 -19.894375 3190 54.302689 -13.230392 -20.777054 3191 55.269669 -12.561111 -20.628021 3192 56.047394 -12.856979 -20.973045 3193 56.258575 -12.455368 -20.511768 3194 33.246277 -13.382950 -21.500011 3195 34.198265 -13.146072 -21.275517 3196 33.630943 -14.026169 -21.509239 3197 39.311012 -14.293488 -22.191738 3198 46.440445 -12.169083 -21.108650 3199 47.134842 -12.282990 -20.373867 3200 48.013611 -12.301926 -19.664761 3201 56.940857 -13.361221 -20.898651 3202 55.530029 -13.766281 -21.065945 3203 56.362015 -14.869019 -21.049522 3204 57.985855 -14.027054 -21.046913 3205 57.845200 -13.290573 -20.705856 3206 56.835815 -12.475128 -20.015270 3207 58.460663 -13.754440 -20.364887 3208 32.754517 -13.392136 -20.707668 3209 32.945648 -14.066956 -21.258705 3210 33.171066 -14.092148 -21.580185 3211 41.340973 -14.647858 -21.325771 3212 51.988297 -14.188354 -21.323814 3213 54.566360 -14.418152 -20.952030 3214 57.356369 -14.708237 -21.135380 3215 57.613739 -12.888397 -19.941269 3216 20.865402 -16.164322 -21.016174 3217 33.224899 -14.378403 -21.332611 3218 33.678589 -14.379517 -21.098896 3219 34.122070 -13.948898 -21.069656 3220 39.533989 -15.485428 -21.694279 3221 42.101883 -15.141006 -20.852627 3222 51.631226 -15.205597 -21.642868 3223 54.463196 -15.544800 -20.577518 3224 55.325409 -14.993225 -20.904991 3225 57.114746 -16.967606 -20.279907 3226 57.323669 -15.898880 -20.821335 3227 55.837875 -16.072800 -20.543999 3228 58.685074 -14.755234 -20.911892 3229 58.147491 -15.227249 -21.034878 3230 59.153198 -14.814529 -20.446999 3231 42.752655 -16.233658 -21.124607 3232 59.130692 -15.930649 -20.621445 3233 59.726822 -15.338837 -20.169460 3234 51.946259 -15.906342 -20.900291 3235 22.068810 -18.884781 -21.840744 3236 34.852104 -19.977615 -21.505295 3237 35.328354 -20.459015 -21.703999 3238 44.597992 -21.019699 -21.858871 3239 52.721252 -19.156448 -21.137280 3240 52.727905 -19.697388 -20.532593 3241 58.144119 -21.457092 -20.996941 3242 58.190598 -21.675201 -20.684002 3243 57.139969 -21.376251 -20.604454 3244 56.052917 -20.279007 -21.377087 3245 59.385925 -21.893372 -21.001331 3246 24.602310 -21.899124 -22.253216 3247 25.527161 -22.771164 -22.282326 3248 26.449165 -23.379211 -22.403488 3249 30.828484 -22.932129 -21.466873 3250 35.054626 -20.798203 -21.269047 3251 35.376755 -21.548752 -22.338341 3252 34.756081 -22.296509 -20.690323 3253 40.370819 -21.364365 -20.616295 3254 60.126190 -22.929337 -20.294209 3255 61.001846 -22.940048 -20.954887 3256 32.004791 -21.324615 -21.998966 3257 60.699097 -22.111557 -21.520710 3258 29.320786 -24.216034 -21.267353 3259 40.516251 -22.780075 -20.840015 3260 40.720810 -24.156357 -21.268581 3261 26.352768 -24.372650 -21.670429 3262 27.548843 -24.474670 -21.966110 3263 40.652161 -25.009567 -20.631226 3264 51.870102 -24.255096 -21.800446 3265 62.898453 -24.763245 -20.752876 3266 62.427322 -24.602478 -19.817547 3267 61.953247 -23.918716 -20.477470 3268 33.913567 -26.132523 -21.070919 3269 53.446991 -26.199936 -21.136894 3270 62.714569 -26.858383 -21.737938 3271 63.328568 -26.743073 -21.300919 3272 63.049164 -25.778198 -21.428120 3273 33.226288 -26.715347 -22.141815 3274 56.504944 -27.847763 -22.201672 3275 62.628433 -24.857620 -21.712349 3276 55.499985 -27.875549 -21.697327 3277 60.845062 -27.903641 -21.990540 3278 61.248856 -29.441864 -21.327583 3279 62.046936 -28.044434 -21.607552 3280 63.147156 -28.151749 -21.189064 3281 30.822891 -28.819565 -22.269268 3282 29.706444 -29.922684 -21.493752 3283 28.989014 -29.716888 -20.610367 3284 29.182175 -30.765442 -20.717110 3285 39.431160 -29.757492 -20.532997 3286 39.829346 -28.943497 -19.472164 3287 40.219269 -28.321716 -20.364063 3288 40.169830 -27.979156 -21.977684 3289 38.562943 -30.268143 -22.321693 3290 57.222855 -28.719894 -22.137722 3291 56.237320 -29.319153 -21.837238 3292 57.429214 -30.415451 -21.768612 3293 58.177536 -28.805191 -22.109848 3294 59.410049 -28.546677 -21.955200 3295 60.024643 -29.621323 -21.443665 3296 58.721527 -30.190735 -21.508698 3297 30.931946 -31.425659 -22.106941 3298 32.150703 -31.521362 -22.672131 3299 40.206802 -27.862839 -19.476765 3300 31.979189 -32.331665 -22.003922 3301 30.808296 -32.215439 -21.599541 3302 33.164658 -31.959549 -22.538971 3303 53.887024 -33.846344 -22.350082 3304 54.480743 -33.741241 -22.339481 3305 53.510727 -33.511963 -21.953415 3306 53.600311 -32.124710 -21.586121 3307 54.491577 -29.414642 -21.466385 3308 52.686188 -30.074997 -21.193485 3309 41.118851 -34.590240 -21.487347 3310 41.346527 -35.781342 -22.528709 3311 42.210693 -34.330215 -22.195999 3312 41.641891 -33.793060 -21.052750 3313 42.755295 -33.132538 -21.809971 3314 42.492157 -32.781479 -21.459995 3315 42.253113 -33.182861 -21.345428 3316 56.878693 -34.262009 -22.216896 3317 55.810486 -32.200043 -21.935123 3318 42.738220 -36.961884 -22.822899 3319 40.668762 -37.244202 -22.871635 3320 40.213379 -36.389160 -22.623917 3321 42.878922 -35.367401 -22.684711 3322 43.219711 -34.805023 -22.521622 3323 44.096161 -35.554947 -22.310246 3324 44.336975 -33.571335 -21.571678 3325 43.372452 -34.018219 -22.146629 3326 53.537094 -34.480530 -22.108635 3327 39.605385 -36.652344 -22.464592 3328 39.747360 -35.935135 -21.790108 3329 38.850433 -36.507538 -21.946594 3330 42.908752 -36.031952 -22.768921 3331 45.065887 -36.604370 -21.997719 3332 44.091156 -37.739639 -22.285248 3333 57.756821 -35.289108 -22.369286 3334 58.478149 -36.330536 -22.415337 3335 59.019821 -35.118652 -21.918541 3336 40.152405 -38.523651 -22.862633 3337 38.559250 -38.568283 -22.314117 3338 39.468788 -39.779816 -22.627007 3339 44.674194 -38.050339 -21.546349 3340 45.109894 -37.309769 -21.682159 3341 52.898743 -36.727112 -21.551609 3342 53.107056 -37.661133 -21.563538 3343 59.280289 -37.509201 -22.124496 3344 59.843658 -36.208054 -21.695072 3345 42.300735 -38.475403 -22.857353 3346 59.835175 -38.252777 -21.707752 3347 59.802109 -38.723770 -21.090656 3348 41.781708 -40.851181 -22.805874 3349 41.768585 -40.272919 -22.950424 3350 40.773056 -40.789322 -22.747005 3351 42.670029 -40.551010 -22.521015 3352 42.394028 -39.624466 -22.836231 3353 41.144501 -39.565735 -22.973312 3354 43.569748 -39.260223 -21.971966 3355 51.813202 -39.802261 -22.269119 3356 41.918991 -41.915222 -22.524498 3357 49.658905 -42.946945 -22.967426 3358 56.280579 -43.656738 -23.043606 3359 48.967865 -44.731735 -22.597198 3360 49.746658 -45.888290 -23.396744 3361 50.049133 -48.247314 -22.950508 3362 49.064133 -47.107834 -22.864117 3363 48.461899 -45.913544 -22.423992 3364 51.735413 -48.941132 -22.465931 3365 52.230606 -48.357590 -22.342861 3366 5.246780 27.646011 -18.309761 3367 5.920784 28.226166 -18.093250 3368 5.103623 28.300552 -18.006531 3369 5.546829 29.107544 -17.793804 3370 4.463432 25.627045 -17.980694 3371 4.795494 25.144073 -18.300636 3372 4.973847 25.803604 -18.473503 3373 6.117912 27.208588 -18.176720 3374 5.120659 26.747009 -18.352001 3375 7.393540 25.173553 -17.810497 3376 8.183105 25.285797 -16.877563 3377 7.380478 26.634964 -17.160744 3378 7.020249 28.276276 -17.073578 3379 6.340347 29.105728 -17.500549 3380 6.121872 25.696716 -18.397316 3381 5.312164 25.062439 -18.558895 3382 6.841919 24.114792 -18.211758 3383 5.870178 24.496475 -18.513214 3384 5.971115 23.666718 -18.313515 3385 5.456032 23.147858 -17.998493 3386 6.548409 22.633209 -17.938038 3387 5.090119 24.247650 -18.018253 3388 39.180412 19.106934 -17.975069 3389 37.893616 18.128876 -18.164513 3390 37.395287 16.023102 -17.857685 3391 37.116562 15.668701 -19.017944 3392 44.677673 14.735779 -18.797035 3393 44.814789 15.365952 -18.488491 3394 45.497208 14.687073 -18.578613 3395 44.993439 14.062653 -18.971581 3396 45.623260 15.280472 -18.281212 3397 46.786530 15.073090 -17.963100 3398 45.680908 16.237900 -17.914909 3399 25.956650 13.585815 -18.930386 3400 26.012367 13.895081 -18.804443 3401 25.761253 13.700073 -18.759762 3402 26.351608 13.634521 -18.729156 3403 44.299713 16.624741 -18.422283 3404 46.390106 13.841537 -18.514221 3405 25.888359 12.970886 -18.690941 3406 45.582581 12.036438 -19.004585 3407 45.752060 13.081116 -18.907337 3408 46.998322 12.463226 -18.292870 3409 48.022476 13.686707 -17.646633 3410 37.524658 12.759201 -18.072327 3411 45.090607 10.841141 -19.126701 3412 46.431702 11.009018 -18.374878 3413 47.738113 11.101288 -17.627609 3414 37.618103 9.805328 -17.941334 3415 45.728577 9.649521 -18.480022 3416 54.581268 10.061279 -17.934151 3417 53.929016 10.248123 -18.255863 3418 55.190491 9.608093 -17.985641 3419 50.513031 7.546967 -18.922211 3420 45.854065 8.068390 -17.969013 3421 44.968079 7.207321 -18.657890 3422 45.784698 6.316772 -17.335781 3423 55.992310 8.764755 -17.532017 3424 56.891052 7.195190 -17.415066 3425 57.109879 6.821732 -16.679615 3426 56.500366 7.918121 -16.758034 3427 36.907822 7.260513 -17.924267 3428 37.531090 8.504150 -17.772308 3429 56.520584 6.397705 -18.900040 3430 31.423431 5.311935 -18.424568 3431 50.124176 6.158630 -18.303032 3432 56.470886 7.570465 -18.153625 3433 30.122185 5.154564 -18.551250 3434 29.574692 4.636551 -17.484592 3435 30.739975 4.898743 -17.643223 3436 30.655609 3.987335 -16.683189 3437 35.390793 5.406532 -18.857471 3438 46.519318 3.000443 -18.270050 3439 56.928558 5.057770 -18.325577 3440 23.104485 3.390137 -18.368896 3441 25.966507 3.916977 -19.644615 3442 25.074127 3.844009 -19.360321 3443 20.860542 3.112907 -20.189346 3444 20.801926 2.976852 -19.060871 3445 21.704788 3.060181 -17.866920 3446 24.291489 3.663498 -19.057926 3447 27.106201 4.019348 -19.546337 3448 54.953400 1.953659 -19.372787 3449 55.704483 2.974052 -19.303223 3450 20.325111 2.629227 -19.937740 3451 19.542305 0.978378 -19.001282 3452 19.488678 0.154907 -19.945415 3453 53.929642 1.053101 -19.612129 3454 54.196548 1.820709 -19.766430 3455 19.987411 2.051697 -19.262524 3456 53.249695 -1.161255 -20.315636 3457 56.075668 0.468964 -19.434982 3458 56.095810 1.561493 -19.053589 3459 57.112808 1.670364 -18.616684 3460 56.231491 -0.338120 -19.963955 3461 57.006226 -0.462494 -19.908512 3462 58.764603 -0.341965 -17.990841 3463 58.907013 0.543045 -17.247086 3464 18.865829 -1.336685 -18.458492 3465 18.789017 -2.644760 -19.632545 3466 19.051666 -3.704407 -20.716873 3467 46.707199 -4.180176 -20.728035 3468 24.450193 -3.496467 -18.241636 3469 24.243092 -3.674366 -18.249155 3470 24.285671 -3.293331 -18.408386 3471 24.727982 -3.393793 -18.166035 3472 24.561964 -3.671433 -18.112343 3473 45.413071 -5.703506 -20.895817 3474 59.071884 -5.530304 -19.595947 3475 59.834183 -7.146332 -18.964073 3476 18.718628 -9.673691 -19.761414 3477 46.713165 -8.675339 -20.847309 3478 58.908066 -8.502930 -19.254253 3479 58.810730 -7.666519 -19.812374 3480 56.815430 -8.694321 -19.140797 3481 57.967377 -8.911835 -19.007431 3482 46.974274 -9.789673 -20.244198 3483 48.148117 -9.183395 -20.096508 3484 48.249725 -10.266098 -19.249836 3485 59.993835 -8.908295 -18.664238 3486 19.082764 -10.888885 -20.011967 3487 19.678162 -11.627548 -20.895939 3488 45.823624 -11.246155 -20.748047 3489 32.590286 -12.887787 -19.762001 3490 33.839119 -12.400314 -18.844688 3491 34.518005 -12.437592 -18.941299 3492 34.125191 -12.360123 -19.613693 3493 52.791168 -13.022552 -20.200851 3494 53.318192 -14.577621 -20.706421 3495 55.917419 -12.223679 -19.493332 3496 20.115692 -13.715622 -20.414536 3497 35.496552 -13.610336 -18.475735 3498 35.630753 -14.502335 -18.480701 3499 34.936836 -13.975754 -19.376991 3500 34.510040 -13.449417 -20.424515 3501 46.384705 -11.402084 -20.300140 3502 46.876068 -11.945969 -19.628418 3503 58.068115 -13.286270 -19.055248 3504 57.564987 -12.796051 -19.074688 3505 34.141037 -14.261292 -20.382622 3506 33.016594 -14.492310 -20.453060 3507 39.941803 -14.575562 -21.484024 3508 40.310333 -15.615646 -20.543839 3509 42.393097 -15.613007 -20.729492 3510 51.989548 -16.802383 -19.903748 3511 53.260986 -16.082840 -20.164471 3512 59.197739 -14.419464 -19.322617 3513 60.073257 -15.353821 -19.753506 3514 60.268631 -15.461624 -19.035503 3515 42.302551 -16.396164 -20.210953 3516 42.894302 -16.973297 -20.619293 3517 54.608917 -16.614304 -19.959866 3518 58.239960 -16.049011 -20.777168 3519 60.426086 -16.411087 -19.959938 3520 59.422943 -14.813019 -18.088032 3521 21.040726 -18.625092 -20.384022 3522 40.795135 -17.541809 -19.424946 3523 42.774155 -18.139542 -19.802265 3524 51.021011 -17.447174 -20.642754 3525 51.113663 -17.843140 -20.604309 3526 51.332428 -16.996902 -20.543686 3527 57.892548 -18.281189 -19.459332 3528 56.078629 -17.243439 -19.781361 3529 58.384964 -17.010895 -20.387024 3530 59.752060 -17.363144 -20.254951 3531 61.191925 -16.476425 -18.851997 3532 61.131653 -16.998810 -19.679283 3533 56.035568 -18.055359 -18.987442 3534 59.250137 -18.137161 -19.910202 3535 60.042770 -18.122589 -19.996204 3536 60.800049 -17.746902 -19.837299 3537 61.526566 -17.387100 -19.392082 3538 33.891090 -21.353119 -20.177876 3539 34.327286 -20.690613 -20.812916 3540 51.697708 -18.617859 -20.182194 3541 32.730827 -20.636688 -21.336246 3542 54.774261 -20.461517 -20.611416 3543 21.722244 -19.735901 -21.027592 3544 21.269623 -19.941895 -20.163731 3545 22.087646 -21.110886 -20.665627 3546 23.440178 -21.848938 -21.523613 3547 33.278664 -20.872940 -20.559586 3548 40.437561 -19.497437 -19.903038 3549 43.735748 -20.458313 -20.162891 3550 53.626511 -20.387390 -20.173256 3551 52.731354 -20.338654 -19.832817 3552 55.697327 -20.930725 -20.418976 3553 22.896927 -22.847397 -20.327183 3554 31.851839 -22.999893 -19.810642 3555 32.368118 -21.806107 -20.446346 3556 44.448151 -21.778870 -21.039215 3557 44.035599 -21.864548 -20.128265 3558 45.334381 -22.254730 -21.669399 3559 57.581726 -22.321075 -19.637943 3560 56.229309 -21.541946 -19.869389 3561 58.265335 -22.027390 -20.307304 3562 24.439819 -23.112732 -21.513454 3563 46.121704 -23.322998 -21.331562 3564 44.726532 -22.850494 -20.706444 3565 45.275742 -24.071945 -20.809269 3566 46.705872 -24.648804 -21.112637 3567 47.759430 -24.676743 -21.001888 3568 47.810944 -23.750320 -21.239506 3569 25.549110 -23.647614 -21.844612 3570 25.025589 -24.068939 -21.328346 3571 24.076431 -24.119171 -20.695042 3572 30.124176 -23.931366 -20.332169 3573 29.371643 -24.603012 -19.770477 3574 30.881439 -23.673706 -19.796482 3575 40.442047 -23.758499 -19.368591 3576 44.659912 -24.787079 -20.254078 3577 45.501617 -25.099243 -20.695518 3578 48.193604 -24.366547 -20.858250 3579 48.994141 -24.464203 -20.858994 3580 51.360031 -24.270706 -21.195820 3581 26.384514 -25.233673 -20.652554 3582 25.189896 -24.712158 -20.936554 3583 24.626373 -25.317444 -20.004177 3584 27.232941 -24.873062 -21.439117 3585 27.552490 -25.183578 -20.808956 3586 28.131065 -24.716171 -21.414185 3587 34.763611 -25.275879 -19.791008 3588 34.863861 -23.765030 -19.893986 3589 52.371216 -24.853012 -21.252567 3590 28.441620 -25.016052 -20.320160 3591 34.001793 -26.537445 -19.526287 3592 33.145340 -26.765564 -20.627052 3593 46.327667 -27.137695 -20.909313 3594 45.588837 -27.730133 -20.447773 3595 46.425995 -28.417831 -20.725677 3596 47.336884 -28.043869 -21.059551 3597 48.092163 -27.907028 -21.114517 3598 47.828735 -26.981476 -21.114647 3599 48.417725 -25.051743 -20.853157 3600 49.736237 -26.277618 -20.844620 3601 47.814423 -25.626877 -21.074402 3602 54.787857 -26.784500 -21.490971 3603 63.550720 -25.977051 -20.537952 3604 33.110435 -26.692871 -21.359459 3605 46.448578 -25.929443 -20.956955 3606 54.470123 -27.579559 -21.212299 3607 63.710342 -27.158081 -20.950424 3608 64.140152 -27.205795 -20.297798 3609 63.813171 -26.412430 -19.535782 3610 40.589050 -26.273300 -20.644558 3611 50.416458 -24.498077 -20.895851 3612 49.102539 -28.174362 -20.863987 3613 63.958145 -28.051163 -20.746590 3614 29.429283 -28.944244 -21.317722 3615 29.520065 -28.562134 -20.592262 3616 28.961128 -29.069672 -20.964657 3617 28.804703 -28.887939 -20.596176 3618 30.923248 -27.923782 -21.646801 3619 30.075104 -28.410461 -21.419930 3620 29.847084 -28.998260 -21.700546 3621 45.863281 -29.012665 -20.151577 3622 45.106232 -27.901474 -19.893269 3623 45.172272 -28.850433 -19.289204 3624 52.520294 -28.767334 -21.107231 3625 51.159378 -28.710541 -20.835682 3626 52.357529 -27.428009 -20.917492 3627 53.269714 -28.706284 -21.193893 3628 53.680023 -27.825073 -21.068253 3629 57.669037 -32.645996 -21.687588 3630 62.258438 -29.276596 -21.157623 3631 29.978874 -31.544312 -21.331085 3632 59.425812 -30.812073 -21.101189 3633 63.018402 -29.571442 -20.751686 3634 62.044022 -31.019577 -20.689278 3635 63.716156 -30.274673 -20.088345 3636 63.897919 -29.016586 -20.445274 3637 64.468857 -28.373947 -20.004032 3638 58.170792 -31.420319 -21.385689 3639 60.391953 -30.867950 -21.013130 3640 37.233986 -31.840942 -21.699223 3641 33.186012 -32.667740 -21.794884 3642 32.351730 -33.149399 -21.321381 3643 42.764557 -32.661926 -21.464638 3644 43.463196 -33.221344 -21.837124 3645 43.327637 -32.806824 -21.442131 3646 45.123825 -33.375168 -21.012783 3647 45.202393 -33.313919 -20.347893 3648 44.666809 -33.078293 -20.465385 3649 51.939316 -33.573502 -20.761147 3650 33.996193 -32.969101 -21.514202 3651 45.190979 -33.710815 -21.343143 3652 43.720551 -32.766220 -20.700443 3653 45.558609 -33.739349 -20.457619 3654 51.956848 -31.746658 -20.865879 3655 58.594513 -32.249130 -21.244881 3656 59.181122 -33.390335 -21.480873 3657 60.436295 -32.518082 -20.992207 3658 59.431519 -31.955566 -21.059357 3659 58.009796 -34.225845 -21.947750 3660 60.139313 -33.496307 -21.320553 3661 40.424316 -35.164261 -21.204384 3662 45.275482 -34.419220 -21.450668 3663 46.112778 -34.533127 -20.393612 3664 45.843292 -35.650360 -21.456287 3665 60.090775 -34.424026 -21.402870 3666 60.611633 -33.619934 -21.011543 3667 60.755157 -34.500626 -20.546516 3668 60.366714 -35.338974 -21.244453 3669 59.941895 -35.323013 -21.639645 3670 38.242798 -36.881714 -21.990067 3671 38.148094 -36.550461 -21.571995 3672 37.884155 -36.869659 -21.714825 3673 45.774048 -36.732498 -21.544109 3674 52.457397 -35.432861 -21.166840 3675 52.255249 -36.458481 -20.634617 3676 60.426559 -36.038635 -20.696526 3677 37.951309 -37.522736 -21.714890 3678 39.048660 -37.419525 -22.403404 3679 38.101898 -39.572449 -22.149242 3680 45.151016 -37.635330 -21.178345 3681 60.231445 -37.387543 -21.345108 3682 60.278336 -38.151077 -21.291985 3683 37.390091 -39.698196 -21.631996 3684 37.741707 -40.361969 -21.968807 3685 52.993729 -38.435608 -21.743279 3686 38.421005 -40.494019 -22.294250 3687 44.234161 -38.525574 -21.796276 3688 51.758331 -39.241547 -21.648735 3689 58.224228 -41.103760 -21.520435 3690 58.791672 -40.166061 -20.917130 3691 59.219391 -39.475784 -21.080830 3692 60.284760 -38.025238 -20.942131 3693 39.250587 -41.252319 -22.395653 3694 40.266785 -42.263000 -22.410645 3695 49.977066 -41.278732 -22.563911 3696 49.677704 -40.010071 -21.592941 3697 52.517456 -38.517609 -20.876656 3698 58.352921 -40.937531 -20.629246 3699 41.111115 -43.336838 -22.264126 3700 40.950836 -44.816818 -21.692032 3701 42.045486 -43.956375 -21.785233 3702 43.071472 -42.297409 -22.120068 3703 43.123535 -41.454575 -22.203857 3704 43.575546 -40.671112 -21.525749 3705 50.005203 -38.030579 -20.341377 3706 39.045418 -42.662292 -22.000423 3707 37.938179 -41.542847 -21.833439 3708 42.518143 -42.953125 -22.158463 3709 43.544464 -41.859985 -21.556755 3710 39.996277 -43.695160 -21.989922 3711 41.881149 -43.103897 -22.324387 3712 43.202850 -43.006393 -21.247738 3713 47.566467 -46.906769 -21.939587 3714 47.560944 -45.380844 -21.527157 3715 55.399261 -44.792923 -22.706665 3716 54.764801 -45.155640 -22.181458 3717 55.115524 -44.216766 -21.290855 3718 56.004852 -43.824539 -22.033039 3719 46.806549 -44.684433 -20.270027 3720 48.124664 -43.689255 -21.449402 3721 47.247070 -43.249634 -19.946495 3722 54.302795 -45.253464 -21.734726 3723 46.479965 -46.121902 -20.728550 3724 48.452545 -48.130875 -22.447704 3725 47.012115 -48.135498 -21.715969 3726 47.782227 -49.288940 -21.961308 3727 49.290466 -49.057236 -22.468563 3728 50.747803 -49.381805 -22.328903 3729 54.933380 -51.692917 -21.692608 3730 56.420807 -51.955170 -22.470474 3731 56.169861 -51.195953 -22.269791 3732 56.802658 -49.089661 -21.020569 3733 56.635193 -50.387512 -21.773090 3734 58.236862 -49.429443 -21.212536 3735 57.939316 -50.864487 -21.902115 3736 57.271576 -52.824036 -22.388962 3737 57.718231 -51.936096 -22.192268 3738 56.955826 -51.199677 -22.344048 3739 55.962097 -53.298325 -22.503113 3740 54.132950 -53.977905 -22.279305 3741 58.402588 -53.191696 -21.486980 3742 58.911621 -51.744888 -21.082756 3743 57.324295 -53.924713 -22.228333 3744 53.747528 -55.095642 -22.495590 3745 52.079987 -55.692276 -22.159523 3746 55.621674 -54.802750 -22.661751 3747 54.515259 -55.066452 -22.665817 3748 55.055115 -55.621750 -22.700813 3749 56.538742 -54.377869 -22.576202 3750 55.051498 -56.126038 -22.565800 3751 54.129700 -56.128952 -22.461506 3752 55.807281 -55.994690 -22.446739 3753 56.962845 -55.319992 -22.174377 3754 58.026443 -54.577087 -21.566769 3755 55.074463 -56.789902 -22.317696 3756 11.690849 35.971542 -16.610939 3757 12.147522 36.006744 -17.004108 3758 12.139206 36.888214 -16.570621 3759 13.244011 36.817139 -16.529480 3760 12.601990 38.231277 -16.015301 3761 11.495186 36.856262 -15.873554 3762 12.586693 36.423798 -16.923004 3763 12.966339 35.775421 -16.986099 3764 12.111923 35.048508 -16.931450 3765 11.745773 34.303726 -16.681644 3766 12.177490 34.068985 -17.015736 3767 13.955154 35.901443 -16.607002 3768 13.622978 34.375107 -16.971046 3769 17.083023 34.618530 -16.807194 3770 16.956856 34.971085 -16.567625 3771 16.680183 34.450073 -16.670616 3772 17.352310 34.760925 -16.431591 3773 15.220139 35.669144 -16.118279 3774 17.280434 33.892853 -16.688679 3775 16.235237 33.174347 -16.911533 3776 17.398308 32.828506 -16.896488 3777 5.111549 32.360718 -17.281300 3778 5.527832 32.716919 -16.930958 3779 4.860542 32.703583 -16.803787 3780 5.480805 31.694550 -17.380714 3781 6.073029 31.677979 -17.036667 3782 11.906052 33.779312 -16.755066 3783 12.443954 33.259247 -16.648827 3784 15.214417 34.149704 -16.715328 3785 14.784164 33.128677 -17.117977 3786 15.246796 31.983582 -17.220585 3787 16.912216 30.192291 -17.354507 3788 16.085815 30.952866 -17.228817 3789 15.960175 29.842896 -17.262432 3790 18.249046 33.091080 -16.043320 3791 17.923309 34.256622 -15.792053 3792 4.943443 31.821548 -17.208439 3793 6.339295 32.341812 -16.448833 3794 6.179207 33.672897 -16.024136 3795 13.471237 32.171875 -17.140831 3796 12.759651 31.316833 -16.923866 3797 13.212814 30.977814 -17.225803 3798 18.144897 31.966599 -16.791008 3799 17.189919 31.989304 -17.152969 3800 5.155159 30.989868 -17.352560 3801 4.322647 29.726944 -16.767944 3802 4.163490 28.677673 -16.632751 3803 4.672691 28.908630 -17.435368 3804 6.727570 31.235596 -16.468910 3805 16.360153 31.835907 -17.138500 3806 17.060768 29.222137 -17.387566 3807 16.245041 28.723846 -17.239567 3808 17.914070 31.128769 -17.145638 3809 17.097450 31.012268 -17.297287 3810 19.770264 31.300659 -14.990356 3811 18.872269 30.688354 -16.507950 3812 19.759109 29.052032 -16.243156 3813 18.926613 31.975204 -15.947060 3814 5.006882 30.019974 -17.363617 3815 5.954018 30.387161 -17.339649 3816 6.975685 29.861649 -16.572083 3817 12.870430 30.787323 -16.957523 3818 13.335144 30.133636 -16.852715 3819 14.588257 30.672928 -17.303646 3820 17.876755 29.954422 -17.238384 3821 13.423241 29.185455 -16.888248 3822 14.118225 29.302002 -17.206688 3823 15.011650 29.753998 -17.324455 3824 15.191147 29.005219 -17.220123 3825 16.578850 27.621643 -17.216347 3826 17.020889 28.428619 -17.380981 3827 17.805679 28.276321 -17.255630 3828 18.764496 29.096924 -16.868752 3829 4.414154 27.393097 -17.392227 3830 15.282463 27.911667 -17.144989 3831 14.351120 27.545349 -17.015633 3832 14.911545 26.014847 -16.810505 3833 13.695007 28.306152 -16.570023 3834 13.925674 27.211929 -16.697800 3835 14.463898 28.369629 -17.161469 3836 17.472794 26.114670 -17.009880 3837 18.950012 27.457352 -16.825512 3838 4.451462 26.295242 -17.937111 3839 4.564468 25.057709 -17.722034 3840 7.861831 24.090775 -17.495277 3841 7.457062 23.314240 -17.783222 3842 7.980636 22.722473 -16.840546 3843 4.865982 23.294235 -17.297493 3844 5.112190 22.171417 -17.672089 3845 5.870499 21.489563 -17.839554 3846 7.323288 20.442993 -16.707256 3847 7.636581 20.143372 -16.011368 3848 8.018600 21.200439 -16.048088 3849 32.293427 22.475708 -17.259834 3850 32.278282 22.711899 -17.170528 3851 32.067062 22.572739 -17.110615 3852 32.602333 22.550446 -17.016472 3853 5.169960 21.291351 -17.721806 3854 32.292450 22.157867 -16.997444 3855 6.902756 21.265076 -17.269352 3856 5.524574 20.493942 -17.428207 3857 40.355850 19.131989 -16.487457 3858 45.093735 17.620392 -17.673435 3859 45.218246 18.972931 -16.604137 3860 39.047173 16.155441 -15.751148 3861 38.961853 17.327179 -16.108841 3862 39.980690 17.402771 -15.403046 3863 38.452576 18.065643 -17.144556 3864 43.448288 19.485306 -16.912569 3865 44.423126 19.716034 -15.974468 3866 26.757980 17.774826 -17.481487 3867 26.387482 18.705963 -17.013435 3868 25.278084 17.786072 -16.948189 3869 27.814011 17.578400 -17.693161 3870 28.737885 18.344650 -17.321320 3871 27.669334 18.666489 -17.300575 3872 28.507080 17.569351 -17.654755 3873 26.212975 14.430008 -18.265747 3874 27.514900 13.030823 -18.221874 3875 28.433525 16.758865 -17.452637 3876 28.922714 16.118042 -16.306362 3877 29.256592 17.253586 -16.641006 3878 28.935257 17.614090 -17.300865 3879 47.014145 16.384567 -17.485016 3880 46.575470 17.695221 -16.978104 3881 26.863785 16.429825 -17.692284 3882 28.132874 14.836365 -17.348465 3883 47.781509 16.925720 -16.939610 3884 49.006378 16.767151 -16.080254 3885 47.987427 17.868073 -16.215416 3886 48.130646 15.789642 -17.083160 3887 24.196991 13.579468 -18.207619 3888 25.139908 13.522858 -18.448997 3889 24.793427 14.569275 -17.910110 3890 25.209496 15.871231 -17.502495 3891 38.735641 14.926575 -16.102398 3892 38.423225 13.715012 -16.619781 3893 48.208588 14.809296 -17.341248 3894 22.291512 12.971756 -18.164604 3895 22.333466 13.880310 -17.743820 3896 21.876999 13.226227 -17.780445 3897 23.163155 13.436737 -18.076385 3898 23.820595 14.476303 -17.731735 3899 22.815193 15.088135 -17.130039 3900 21.682732 14.142120 -17.061485 3901 28.470444 13.595322 -17.542648 3902 49.152008 12.761810 -16.848427 3903 49.925293 14.305679 -15.884651 3904 22.738426 11.894653 -18.257812 3905 21.777687 11.951218 -17.961243 3906 27.444412 11.456558 -18.192402 3907 28.207520 11.890167 -17.989567 3908 26.123947 11.481323 -18.254169 3909 26.870041 10.912766 -17.813393 3910 24.349350 12.051498 -18.324539 3911 28.550385 12.637939 -17.376343 3912 25.938385 10.830429 -17.385689 3913 28.584396 11.617065 -17.491493 3914 21.399704 12.870972 -17.435770 3915 22.310646 11.045013 -18.093353 3916 22.325211 10.561050 -17.739437 3917 23.281303 10.574097 -17.533939 3918 48.294312 12.221710 -17.503899 3919 21.766235 10.844177 -17.648247 3920 27.934280 11.067017 -17.493023 3921 28.625809 11.118317 -17.083023 3922 49.278717 11.412537 -16.440155 3923 24.844551 10.781693 -17.619835 3924 28.442108 10.888107 -16.853989 3925 47.041809 9.835266 -17.679138 3926 46.479431 8.976135 -17.831715 3927 52.300797 8.393738 -17.215633 3928 55.416382 9.213043 -16.749733 3929 46.436829 7.269821 -17.220911 3930 37.674622 7.652527 -17.025711 3931 37.033661 6.590439 -17.053833 3932 47.214645 8.262024 -16.953831 3933 36.251839 6.289902 -18.265575 3934 56.989334 6.410522 -17.762367 3935 33.178268 5.067215 -17.983513 3936 27.436539 4.224945 -18.671913 3937 27.574966 4.083801 -17.183620 3938 27.574860 4.283073 -17.921413 3939 28.417664 4.465317 -17.571442 3940 45.092560 4.550667 -18.319252 3941 45.301102 3.991699 -18.112251 3942 45.630585 3.474548 -18.001465 3943 57.881226 3.883362 -17.182278 3944 57.456299 5.576408 -16.966526 3945 25.168610 3.495453 -18.463566 3946 26.490021 3.680008 -17.980564 3947 45.865723 2.596985 -17.234409 3948 48.323181 3.628952 -18.415939 3949 48.173157 2.924561 -17.829605 3950 48.731384 3.547699 -18.074200 3951 56.801819 3.158203 -18.539150 3952 57.673492 2.423889 -17.941914 3953 46.908569 1.827927 -17.423164 3954 58.651215 2.944183 -16.499786 3955 58.844574 3.454163 -15.875908 3956 58.479675 3.977142 -16.168848 3957 20.358841 2.551605 -17.938015 3958 19.707687 1.753891 -18.187801 3959 47.994995 1.931213 -17.303471 3960 19.288185 -0.169220 -18.619358 3961 53.959137 0.259399 -19.588860 3962 58.273315 2.372284 -17.342815 3963 18.635101 -3.739120 -19.701054 3964 25.603271 -1.161499 -19.027664 3965 25.852509 -0.518387 -18.438560 3966 26.007767 -1.100983 -18.973557 3967 26.196476 -1.256386 -18.302500 3968 24.851669 -1.134750 -18.792606 3969 25.279629 -1.676621 -18.739895 3970 24.994553 -1.904617 -19.009819 3971 25.748423 -1.739469 -18.473291 3972 59.128448 -1.557892 -17.654949 3973 59.420654 -2.785873 -17.654236 3974 23.745201 -2.879623 -19.150860 3975 23.240417 -2.776184 -18.788132 3976 23.425911 -2.115311 -18.761765 3977 25.118454 -2.445208 -18.449911 3978 24.309113 -2.148132 -18.985886 3979 25.775133 -2.334806 -18.088348 3980 25.577570 -2.943713 -17.902313 3981 26.266153 -1.899275 -17.958311 3982 26.355858 -2.307788 -17.685863 3983 23.745045 -3.353749 -18.561605 3984 23.007690 -3.313477 -18.354313 3985 24.479925 -2.866315 -18.576044 3986 25.241909 -3.374974 -17.895929 3987 26.145334 -2.511722 -17.736921 3988 25.997976 -2.683411 -17.757139 3989 25.895708 -2.931189 -17.702913 3990 26.190559 -2.743932 -17.590725 3991 59.311279 -4.057281 -18.566471 3992 24.139620 -4.043887 -18.169943 3993 24.739473 -3.989032 -17.889872 3994 26.168087 -3.521233 -17.228889 3995 25.243340 -4.266865 -17.514940 3996 26.148527 -3.006128 -17.492001 3997 18.344604 -8.652390 -19.538841 3998 18.092361 -9.268036 -18.433662 3999 59.708145 -5.515991 -18.567257 4000 60.845779 -6.429459 -17.742764 4001 60.179214 -6.042603 -18.231899 4002 17.947258 -7.785522 -18.764507 4003 55.267731 -8.534409 -19.070526 4004 60.716537 -8.195999 -18.531097 4005 61.209259 -8.276733 -18.246170 4006 61.443604 -7.577530 -17.717304 4007 50.652710 -9.421906 -19.112961 4008 54.015259 -9.184082 -18.092430 4009 52.541519 -9.142014 -18.375452 4010 52.615189 -9.657745 -17.799568 4011 55.966034 -9.419327 -17.958363 4012 57.364182 -9.427399 -18.286690 4013 58.761230 -9.761002 -18.214600 4014 60.613617 -10.218552 -17.781555 4015 60.984436 -8.939743 -18.270107 4016 61.575012 -8.470367 -17.946362 4017 47.174347 -11.177322 -19.422333 4018 49.822449 -10.275223 -18.571903 4019 19.401581 -12.384476 -19.844154 4020 33.288971 -12.430527 -19.481911 4021 34.717789 -12.840515 -19.581856 4022 53.224274 -12.100769 -18.818214 4023 56.967804 -12.532852 -19.154369 4024 55.184235 -11.941696 -18.175781 4025 56.317566 -12.380264 -18.443935 4026 31.763186 -13.235413 -19.138298 4027 30.498459 -13.742881 -18.180546 4028 31.852125 -13.648665 -17.887386 4029 31.979937 -13.847778 -19.917595 4030 47.205429 -12.282181 -19.606224 4031 20.344116 -15.132034 -20.240692 4032 19.960266 -14.418655 -19.419003 4033 19.998611 -15.189285 -19.141701 4034 30.946671 -13.917160 -19.479843 4035 30.612183 -14.471008 -19.627796 4036 31.178360 -14.478928 -19.718544 4037 31.849428 -15.038589 -19.613293 4038 30.610443 -15.198883 -19.321934 4039 29.114868 -15.173813 -18.843792 4040 30.068802 -14.335632 -19.218277 4041 33.963005 -14.941544 -19.632832 4042 41.357422 -15.871750 -20.048225 4043 41.960846 -15.452881 -20.483280 4044 40.362762 -16.447372 -19.855106 4045 40.785278 -16.419113 -19.672287 4046 51.888580 -17.493484 -19.267906 4047 51.364517 -17.991058 -19.501759 4048 51.721054 -18.134888 -19.017353 4049 53.509338 -19.126144 -16.349701 4050 53.554749 -18.590759 -17.198402 4051 52.627350 -18.686523 -16.988731 4052 53.366730 -17.050842 -19.372356 4053 52.810364 -17.866577 -18.532928 4054 54.226410 -18.346130 -17.860325 4055 54.444397 -17.776703 -18.717461 4056 54.862183 -17.353088 -19.361992 4057 62.027252 -17.432205 -18.565678 4058 20.138641 -16.276382 -19.259212 4059 20.602188 -17.359253 -19.971943 4060 42.287537 -19.130524 -18.308605 4061 43.125275 -19.419785 -19.072830 4062 51.210388 -17.638458 -19.998810 4063 55.525070 -18.453629 -18.320419 4064 59.203186 -18.853485 -19.471638 4065 61.844421 -18.664795 -19.203247 4066 63.120895 -19.775864 -18.725803 4067 63.241547 -18.494354 -17.813858 4068 20.817665 -19.405930 -19.231270 4069 52.074738 -19.897919 -19.295929 4070 51.925323 -18.889633 -18.080639 4071 60.241043 -18.807388 -19.552235 4072 63.816025 -19.679779 -18.173798 4073 21.106422 -20.406570 -19.361496 4074 21.448883 -20.832199 -19.966740 4075 52.998978 -21.071838 -18.760624 4076 51.819565 -20.328354 -17.872009 4077 59.517990 -19.824127 -18.722473 4078 61.186447 -19.791107 -19.096645 4079 62.141083 -19.743958 -19.149933 4080 62.435501 -20.624969 -18.767723 4081 33.204773 -21.492798 -19.990582 4082 33.044136 -21.860062 -19.756325 4083 54.804260 -21.197144 -19.653099 4084 43.546814 -21.344193 -18.748493 4085 56.124847 -22.049118 -19.165359 4086 56.010162 -22.546158 -18.455208 4087 54.737930 -21.869339 -18.627789 4088 57.490631 -23.109909 -18.631607 4089 59.188110 -22.809402 -19.920853 4090 23.011711 -24.343582 -19.531769 4091 23.316093 -25.920105 -18.817707 4092 30.153046 -24.338715 -19.276844 4093 44.243210 -23.778275 -19.798748 4094 43.864059 -22.591461 -19.223564 4095 51.770569 -25.453751 -20.883003 4096 44.101227 -24.741241 -19.345844 4097 60.719223 -23.918625 -19.537506 4098 60.323303 -24.959808 -18.213997 4099 59.114960 -24.014847 -18.440025 4100 63.121048 -25.196838 -19.867199 4101 24.428696 -27.188370 -18.425671 4102 23.686928 -26.923920 -18.443863 4103 23.720459 -27.535049 -17.901947 4104 27.575714 -25.618820 -19.508327 4105 28.793411 -25.231400 -18.969311 4106 34.820557 -24.197479 -19.094242 4107 34.891571 -25.118881 -18.804417 4108 44.889832 -26.258484 -19.914577 4109 43.816498 -25.363953 -18.267750 4110 43.990845 -26.702545 -18.299873 4111 63.412521 -25.663025 -19.669662 4112 63.666245 -27.164154 -18.589149 4113 64.440918 -27.822861 -19.301903 4114 30.833282 -27.834213 -20.740662 4115 31.516609 -28.080627 -18.928215 4116 32.389824 -27.422684 -19.756470 4117 32.644302 -27.809311 -18.765251 4118 40.452118 -27.341949 -20.317879 4119 28.627426 -29.059891 -20.725197 4120 47.543564 -29.515579 -20.556362 4121 46.521484 -29.316971 -20.506870 4122 48.807571 -29.380325 -20.636139 4123 48.148956 -28.613541 -20.892548 4124 49.906021 -29.539795 -20.593521 4125 28.844345 -29.369827 -20.847855 4126 46.213120 -30.189560 -19.247387 4127 45.132263 -29.636841 -18.356503 4128 49.336838 -30.822449 -20.155155 4129 51.006500 -30.464233 -20.580204 4130 64.408386 -29.336121 -19.227974 4131 39.403259 -29.815720 -19.575741 4132 38.328354 -31.331726 -20.502682 4133 46.694687 -29.933823 -20.120697 4134 47.765564 -31.113327 -19.557224 4135 48.952393 -32.054596 -19.478966 4136 50.235245 -32.778244 -19.789253 4137 30.299294 -32.425125 -21.044807 4138 29.315903 -32.267624 -20.542305 4139 37.086411 -32.866791 -20.005333 4140 58.789230 -31.388306 -21.141506 4141 64.470642 -31.690674 -19.234264 4142 64.210312 -30.986435 -18.958992 4143 63.806091 -31.607437 -19.883789 4144 30.216537 -33.094391 -20.665100 4145 31.218163 -33.095779 -21.104668 4146 33.214973 -33.420502 -21.185875 4147 42.792542 -32.675430 -21.035236 4148 42.587509 -32.956161 -20.060410 4149 43.973083 -32.818497 -19.765110 4150 50.759399 -31.651581 -20.287159 4151 63.949219 -32.587524 -19.709526 4152 62.838715 -32.674484 -20.194031 4153 63.282288 -33.291702 -19.592308 4154 32.199776 -34.145065 -20.639454 4155 33.500473 -34.007690 -20.662487 4156 34.163513 -33.476181 -21.071861 4157 34.348740 -33.872040 -20.635124 4158 35.048935 -33.635223 -20.913441 4159 34.982338 -34.015823 -20.377254 4160 35.521828 -33.862946 -20.474564 4161 36.014114 -33.222549 -20.866470 4162 38.647415 -36.371780 -21.114754 4163 40.982071 -34.277435 -19.632641 4164 61.437927 -33.168854 -20.458237 4165 64.072861 -33.001068 -19.181755 4166 34.220703 -34.294525 -20.008560 4167 39.544044 -35.833511 -20.095268 4168 46.834244 -35.270416 -20.308121 4169 51.179672 -32.446960 -20.368931 4170 62.286407 -33.451141 -19.804085 4171 63.647385 -33.432602 -18.987888 4172 40.223358 -35.366791 -18.615467 4173 46.986755 -36.013275 -20.934673 4174 47.622040 -35.912567 -20.154617 4175 51.354950 -35.468231 -19.879520 4176 50.863144 -34.091187 -19.797989 4177 38.011139 -36.692535 -21.050415 4178 37.820839 -36.928024 -21.269073 4179 46.552536 -36.547562 -21.267883 4180 48.748230 -36.245193 -19.278389 4181 48.198730 -35.523911 -18.394367 4182 47.474442 -35.332611 -19.038105 4183 37.494888 -38.682663 -21.474545 4184 45.593872 -37.273895 -21.236694 4185 46.385315 -37.271622 -21.138435 4186 46.846466 -38.108078 -20.777637 4187 47.748688 -37.143967 -20.727638 4188 48.237228 -38.825623 -20.894627 4189 49.941711 -36.626022 -19.217533 4190 49.515594 -36.004242 -18.768223 4191 52.615417 -37.492050 -20.767189 4192 59.980591 -36.269547 -19.809265 4193 59.700943 -37.213913 -20.338924 4194 59.202057 -37.238586 -19.893391 4195 60.122025 -37.323517 -20.634415 4196 36.933838 -38.571075 -20.876038 4197 37.733429 -37.525940 -20.320396 4198 36.317505 -38.641983 -20.515778 4199 36.319778 -38.350769 -19.950127 4200 44.309662 -38.622437 -21.075787 4201 44.938995 -38.067032 -20.796608 4202 52.901459 -38.102737 -21.048237 4203 52.671478 -38.128281 -20.642349 4204 59.470795 -37.903030 -20.262230 4205 59.899719 -38.250061 -20.558258 4206 44.649200 -38.465790 -20.030670 4207 43.923004 -39.550522 -20.251335 4208 46.203049 -39.745270 -18.743156 4209 46.162582 -40.481888 -17.923199 4210 46.538361 -40.601929 -18.650528 4211 46.903259 -39.284805 -20.146160 4212 35.617630 -38.699860 -20.225876 4213 35.358780 -38.901978 -19.799866 4214 35.475021 -39.417496 -20.271317 4215 35.750832 -40.452057 -20.702045 4216 36.478882 -40.640610 -21.246456 4217 36.608047 -39.553741 -21.045044 4218 37.161240 -40.509491 -21.575958 4219 48.116150 -40.461426 -20.913181 4220 48.908463 -41.711380 -21.786461 4221 36.951958 -41.340881 -21.419453 4222 37.030334 -42.549377 -21.123672 4223 43.632904 -41.499329 -20.109406 4224 38.084732 -43.259933 -21.534443 4225 36.201569 -41.454163 -20.904533 4226 43.376434 -43.186066 -20.014927 4227 43.395813 -42.428131 -19.096302 4228 57.856094 -41.791733 -21.020599 4229 58.115707 -41.386520 -20.798637 4230 37.468842 -43.988586 -21.014244 4231 38.206650 -44.490677 -21.212475 4232 39.009460 -44.126755 -21.648216 4233 56.351700 -43.239944 -21.256088 4234 57.181808 -42.446930 -21.023235 4235 40.329895 -46.284592 -20.903580 4236 41.544144 -46.159286 -20.275314 4237 41.648285 -45.504852 -20.996468 4238 39.845413 -44.969940 -21.575817 4239 41.850204 -44.874191 -21.401703 4240 42.599640 -44.541183 -20.630257 4241 47.770493 -42.056015 -20.544415 4242 38.976883 -45.438660 -21.149487 4243 46.433792 -43.867279 -18.945915 4244 48.255936 -44.978500 -21.981701 4245 52.994522 -44.909470 -20.007641 4246 53.498779 -45.822311 -21.393253 4247 52.578384 -46.236832 -20.751930 4248 53.981354 -44.759415 -20.830093 4249 42.160660 -45.502899 -20.274326 4250 46.433273 -47.281860 -21.163460 4251 46.529556 -48.968979 -21.410828 4252 45.756546 -47.043762 -20.101677 4253 45.867020 -48.252594 -20.459167 4254 51.887695 -47.526245 -20.651894 4255 46.566315 -49.772247 -21.354645 4256 51.622299 -48.931854 -21.614452 4257 51.212555 -49.882568 -21.398819 4258 58.768356 -46.936981 -20.186272 4259 58.131653 -47.045151 -20.324577 4260 57.772186 -47.696869 -20.377251 4261 47.041046 -52.641235 -20.743004 4262 48.162262 -52.677048 -21.588169 4263 48.406418 -51.657471 -21.698009 4264 51.408340 -50.840805 -20.643227 4265 50.251129 -50.908142 -21.711189 4266 49.001038 -50.192413 -22.015526 4267 55.366837 -49.964157 -20.779011 4268 55.747467 -48.119171 -19.573009 4269 59.152649 -48.141907 -20.431934 4270 59.625366 -49.589722 -20.287960 4271 58.937454 -50.549179 -21.108459 4272 53.188522 -49.498016 -18.759171 4273 53.993134 -48.598785 -18.690338 4274 52.663940 -48.123047 -17.797417 4275 59.982758 -48.319489 -19.934284 4276 47.168915 -50.798019 -21.311058 4277 48.326111 -53.790527 -21.264126 4278 47.095749 -53.900864 -20.190735 4279 49.517197 -52.319778 -21.710503 4280 54.167694 -50.834824 -20.470215 4281 53.259323 -51.801437 -20.670689 4282 50.494507 -53.084061 -21.609238 4283 50.860703 -51.895706 -21.362305 4284 51.819183 -53.698517 -21.719364 4285 52.894547 -53.990280 -21.964600 4286 53.185059 -52.883469 -21.514954 4287 54.191772 -57.694992 -22.085766 4288 49.850052 -54.630707 -21.779068 4289 49.457336 -55.892502 -21.777618 4290 50.980408 -57.067886 -21.997601 4291 51.636719 -57.404068 -22.040161 4292 57.961914 -55.675400 -21.164783 4293 53.095978 -57.377823 -22.146080 4294 56.562912 -56.475800 -22.039597 4295 52.300629 -57.317215 -22.124107 4296 55.314697 -57.986908 -21.699978 4297 55.879929 -56.919098 -22.083626 4298 49.845154 -57.035492 -21.719250 4299 50.729660 -58.222260 -21.600346 4300 52.207855 -58.552841 -21.726269 4301 56.568054 -57.357513 -21.389370 4302 56.348328 -58.498550 -20.667549 4303 56.177704 -59.392990 -19.885834 4304 56.733093 -58.897400 -19.723755 4305 57.280914 -56.490891 -21.517487 4306 11.445320 42.443390 -15.353374 4307 10.717331 42.742310 -14.662624 4308 11.235550 41.687805 -15.285870 4309 12.526199 43.318726 -14.738655 4310 11.353928 43.386246 -14.946381 4311 12.084068 42.658325 -15.214951 4312 11.837646 39.623337 -15.687134 4313 11.921478 40.767746 -15.567162 4314 11.113403 40.564697 -14.765549 4315 12.094330 41.814590 -15.480431 4316 12.898323 41.210724 -15.312977 4317 12.729897 42.293335 -15.097404 4318 11.429871 38.673340 -15.438648 4319 13.956834 37.674866 -15.870617 4320 12.886230 39.869629 -15.623421 4321 13.651123 40.612976 -15.082645 4322 14.120934 39.103760 -15.073547 4323 4.878471 37.721466 -15.364799 4324 4.104096 38.004913 -14.502495 4325 4.907555 36.835205 -15.190254 4326 4.858879 38.282120 -15.313927 4327 5.287171 38.817978 -15.186413 4328 4.782669 38.781647 -15.322849 4329 11.324722 37.751892 -15.691158 4330 11.681923 37.683258 -16.040478 4331 14.180916 40.694580 -14.487392 4332 14.347206 36.737000 -16.105728 4333 15.193481 37.443130 -15.122700 4334 15.287674 38.618652 -13.951498 4335 4.297875 35.555832 -15.091835 4336 4.496910 33.760300 -15.549110 4337 5.410790 35.285248 -15.639652 4338 15.965813 36.536972 -15.293037 4339 5.752251 37.998672 -14.904133 4340 6.501633 36.770325 -14.433399 4341 11.748444 35.328125 -15.763792 4342 16.009827 34.596710 -16.379139 4343 16.988174 35.385681 -16.066925 4344 16.518723 35.084183 -16.206470 4345 17.084061 35.966492 -15.299316 4346 17.119743 36.607269 -14.539898 4347 16.650711 36.576843 -15.074413 4348 5.221710 33.743439 -16.432373 4349 5.119606 34.463013 -16.152794 4350 7.072273 34.736389 -14.564568 4351 5.592529 34.474258 -16.208565 4352 16.345329 35.813339 -15.704979 4353 17.738892 35.629288 -14.114239 4354 17.551491 35.143845 -15.559662 4355 6.049500 34.630341 -15.794579 4356 12.025681 33.971344 -15.971256 4357 18.000046 34.786407 -15.003754 4358 4.116554 32.758850 -14.578552 4359 4.173836 31.571793 -15.155571 4360 12.619797 32.049271 -16.334461 4361 19.019592 32.702301 -15.112774 4362 12.776871 31.821686 -15.501785 4363 12.560806 32.929688 -15.244572 4364 12.878326 31.031143 -16.235924 4365 4.038673 29.564819 -15.564022 4366 4.562195 31.253006 -16.537216 4367 13.382591 29.309891 -16.268671 4368 4.202133 27.420273 -15.697350 4369 8.141838 29.434891 -15.083878 4370 8.830322 31.537628 -13.627411 4371 7.888198 31.818665 -14.628754 4372 19.845665 27.296692 -16.483055 4373 20.561615 28.084732 -16.073853 4374 20.345062 26.841949 -16.231216 4375 13.647644 27.507858 -16.343996 4376 20.252457 23.265747 -16.615948 4377 20.673904 23.926712 -16.636292 4378 19.516228 24.639771 -16.693180 4379 20.965508 27.442841 -15.690033 4380 21.051804 28.270966 -15.615150 4381 4.293686 25.825043 -17.312557 4382 8.738976 26.740738 -15.340771 4383 13.939255 26.934601 -16.126583 4384 14.115356 26.020523 -15.703201 4385 18.405495 21.624863 -16.843765 4386 19.230011 22.177994 -16.699875 4387 18.781082 21.235260 -16.667328 4388 20.937325 24.312271 -16.227200 4389 20.726593 24.904907 -16.470871 4390 31.031494 26.328903 -15.789742 4391 31.908342 27.065125 -15.646839 4392 30.810028 27.362167 -14.913929 4393 31.644678 26.283997 -16.146084 4394 32.255600 26.213089 -16.133877 4395 33.033348 26.697998 -15.679615 4396 8.359497 27.999954 -15.196674 4397 7.941711 27.819641 -15.962013 4398 16.256485 21.955780 -16.793243 4399 19.726456 22.718079 -16.583649 4400 20.800598 25.976700 -15.956547 4401 21.014473 25.168976 -16.140060 4402 31.744860 25.433228 -16.246040 4403 31.444977 24.134628 -16.313480 4404 30.439285 23.849609 -15.782818 4405 30.987305 23.315460 -16.168228 4406 33.113510 25.548035 -16.008221 4407 4.631004 24.540222 -16.949684 4408 14.358551 23.906006 -16.767555 4409 13.998581 24.817963 -16.191723 4410 13.730286 23.819443 -16.398602 4411 20.897003 23.623322 -16.464344 4412 4.613884 22.564194 -16.907131 4413 8.477029 24.140518 -16.537445 4414 8.743752 23.461121 -15.838036 4415 14.067094 22.698227 -16.712376 4416 18.407379 20.878082 -16.711624 4417 31.556122 23.308319 -16.518246 4418 32.199615 23.144165 -16.797863 4419 32.939133 24.201843 -16.300640 4420 33.961311 26.160477 -15.456463 4421 34.636505 24.715836 -15.271362 4422 20.619942 23.237381 -16.495678 4423 26.551926 21.058258 -16.681831 4424 26.207047 22.200989 -15.779079 4425 25.355133 21.397171 -16.372112 4426 27.465721 22.088165 -16.473530 4427 28.665199 22.572266 -16.356094 4428 27.485786 23.087570 -15.950470 4429 28.324265 23.639709 -15.892132 4430 29.385925 21.051498 -16.740067 4431 29.210518 19.848434 -16.932133 4432 30.431046 21.267807 -16.621323 4433 31.472588 22.442398 -16.692238 4434 33.170898 22.943024 -16.605778 4435 33.781311 22.690948 -16.395683 4436 34.332611 22.590790 -15.992348 4437 34.006355 23.405914 -16.056225 4438 4.518204 21.202881 -17.043579 4439 6.637657 20.226089 -17.149105 4440 13.519485 21.893402 -16.383652 4441 14.209412 21.026352 -16.913704 4442 14.947853 19.902588 -16.970284 4443 24.487663 20.903503 -16.508690 4444 24.001678 20.538116 -16.447952 4445 24.305466 20.487335 -16.712902 4446 25.095169 20.348083 -16.701530 4447 24.623627 21.296936 -16.135017 4448 28.309387 21.211807 -16.758648 4449 29.479317 23.829269 -15.792221 4450 29.418938 21.725433 -16.520969 4451 30.178787 22.677063 -16.180111 4452 32.063278 21.230423 -16.555103 4453 31.075150 19.849945 -16.095959 4454 33.268211 22.059418 -16.493355 4455 6.099968 19.599350 -17.156769 4456 4.481590 21.992661 -17.021969 4457 24.945450 21.639099 -15.628407 4458 23.719574 20.673721 -15.414967 4459 26.060303 19.695312 -16.788200 4460 27.298363 19.839798 -16.976204 4461 29.458611 18.794693 -17.012142 4462 32.391258 20.407303 -15.936821 4463 33.367996 20.243134 -15.283451 4464 33.255554 21.059631 -16.033394 4465 4.488319 20.038910 -16.853672 4466 4.226769 18.732239 -16.263073 4467 5.222527 19.293930 -17.062103 4468 6.951264 19.521454 -16.522869 4469 7.537987 19.186218 -15.444595 4470 6.789673 18.538040 -16.171059 4471 7.209351 17.894821 -15.410507 4472 13.368042 20.269699 -16.342487 4473 13.954041 19.471130 -17.034630 4474 13.465195 18.707153 -16.707790 4475 13.858025 18.624619 -17.070976 4476 15.699982 18.980591 -16.265667 4477 16.473892 19.940872 -16.044609 4478 17.804337 20.843658 -16.629234 4479 17.302948 20.396851 -15.939529 4480 24.115273 20.050522 -16.449875 4481 25.419037 19.545502 -16.633076 4482 30.131737 18.944336 -16.718105 4483 30.628891 18.942474 -16.350605 4484 42.202164 19.200195 -15.404911 4485 40.917221 18.704346 -15.632320 4486 46.469269 19.545364 -14.588165 4487 45.986282 19.737610 -14.754524 4488 46.384048 19.339706 -15.309322 4489 3.939476 20.570770 -15.666195 4490 3.374092 20.214462 -15.006176 4491 3.399498 19.468674 -15.056835 4492 6.082825 18.780396 -16.802872 4493 14.496133 18.694397 -16.949917 4494 39.431946 18.948441 -16.957062 4495 39.545013 18.352798 -16.214199 4496 46.624100 18.771393 -16.162628 4497 47.257904 18.395432 -16.292973 4498 47.665176 18.803436 -15.362820 4499 13.914185 17.974960 -16.798584 4500 29.625595 18.153229 -16.713905 4501 30.306381 18.526718 -16.380447 4502 24.074524 15.393768 -17.389378 4503 29.554520 16.994415 -15.656677 4504 37.769714 16.809387 -17.204533 4505 23.625191 16.729492 -16.791115 4506 29.879601 17.763519 -15.897961 4507 37.999077 15.867447 -16.801842 4508 49.073120 18.198853 -14.734177 4509 50.709442 16.867950 -14.239616 4510 18.874619 13.376968 -17.266205 4511 18.628883 13.818512 -17.047264 4512 18.346771 13.385376 -16.984936 4513 20.159157 13.004761 -17.273918 4514 21.083237 13.449768 -17.087223 4515 20.909874 14.132935 -16.785233 4516 19.222000 14.152847 -16.914005 4517 38.430145 12.658173 -16.618450 4518 20.337509 11.431046 -17.523415 4519 20.996979 12.085602 -17.591892 4520 20.294609 15.053482 -16.463036 4521 28.898254 16.161026 -15.047527 4522 28.335800 14.598694 -15.652534 4523 17.963966 11.767136 -16.403839 4524 18.439178 10.894592 -17.164780 4525 18.611252 12.300659 -17.153393 4526 20.966270 12.949799 -17.245960 4527 20.948410 12.650085 -17.393532 4528 28.540039 13.710373 -16.755455 4529 28.192795 12.831604 -16.161438 4530 28.616051 11.631012 -16.712421 4531 19.296082 11.095901 -17.448547 4532 17.673386 13.403000 -16.213638 4533 21.041290 11.160675 -17.510303 4534 20.061249 10.536911 -17.085705 4535 21.096855 10.440979 -16.803638 4536 18.646271 10.273163 -17.478897 4537 18.437317 10.175949 -17.336765 4538 18.965469 10.217804 -17.250931 4539 23.062805 9.914856 -16.192059 4540 22.142403 10.251358 -16.773293 4541 24.305954 10.304092 -16.593742 4542 25.084557 10.792053 -16.533279 4543 25.926743 11.392273 -16.262695 4544 26.900269 11.118378 -16.833008 4545 48.273590 9.823364 -16.750401 4546 54.837494 9.163391 -16.040775 4547 54.196411 9.478561 -16.918991 4548 18.572739 9.980545 -17.410000 4549 52.983536 8.612350 -16.713608 4550 56.004288 8.738464 -16.660839 4551 56.856781 7.226532 -15.168312 4552 55.748383 8.506165 -15.776974 4553 35.949074 5.589874 -17.217857 4554 47.005127 6.535965 -16.374859 4555 47.953568 7.356033 -15.896904 4556 51.926575 6.461319 -16.410881 4557 31.905893 4.728943 -17.124962 4558 34.745842 5.098770 -18.010769 4559 50.163651 4.576385 -17.143532 4560 57.541779 6.193939 -15.819962 4561 28.644470 4.202621 -16.931297 4562 45.550934 4.205780 -17.103001 4563 20.914185 2.682846 -17.319401 4564 24.170204 2.684250 -17.569942 4565 49.211456 3.661240 -17.604771 4566 58.812027 1.680649 -16.879570 4567 23.560371 -0.109619 -18.151031 4568 22.966660 -0.054932 -17.812691 4569 23.625969 0.455780 -17.765926 4570 25.751068 0.427536 -17.675400 4571 24.471855 -0.066910 -18.161747 4572 24.540482 1.083939 -17.404591 4573 23.648033 -1.008057 -18.438946 4574 26.755798 -0.980576 -18.001297 4575 47.839142 1.314651 -16.870121 4576 59.346893 1.044052 -16.049622 4577 22.428841 -1.663467 -17.979713 4578 25.907043 1.262909 -17.106064 4579 59.391769 -0.278275 -16.431484 4580 19.702682 -0.561264 -17.525864 4581 19.007080 -0.855652 -17.770073 4582 20.712044 -1.879456 -17.386864 4583 20.918900 -0.564178 -17.383839 4584 26.652348 -1.609191 -17.801311 4585 18.023438 -3.020828 -18.068180 4586 18.182556 -3.899887 -19.010910 4587 21.653549 0.562180 -17.288723 4588 26.921959 -2.298815 -17.275440 4589 60.057846 -2.421112 -15.939812 4590 59.738708 -1.300110 -15.836792 4591 18.554825 -2.137863 -17.788567 4592 17.804840 -3.997437 -18.087887 4593 17.841385 -3.331299 -17.627426 4594 23.635384 -4.171936 -18.459572 4595 26.424452 -2.728223 -17.429474 4596 18.108444 -5.465652 -18.953838 4597 24.418432 -4.690268 -17.756800 4598 23.497742 -4.814133 -17.966122 4599 60.409149 -3.761902 -16.442093 4600 60.558243 -5.201355 -17.298824 4601 18.089897 -6.837265 -19.205620 4602 17.855400 -8.578445 -18.656406 4603 24.274139 -8.824905 -18.517262 4604 23.934898 -8.577942 -18.290844 4605 24.286980 -8.548355 -18.327412 4606 24.575531 -8.915558 -18.226219 4607 24.098267 -9.571289 -18.512085 4608 23.043076 -8.586411 -18.053947 4609 51.398621 -11.376114 -17.912315 4610 49.915619 -11.249786 -18.118000 4611 50.014557 -12.049088 -18.640945 4612 53.369354 -10.213165 -17.332081 4613 61.699677 -9.343170 -17.729652 4614 62.243271 -8.499496 -17.272377 4615 62.713104 -9.899124 -16.800423 4616 18.284798 -10.506454 -18.526237 4617 18.556839 -11.679688 -18.761509 4618 23.537666 -10.640457 -18.462349 4619 22.119186 -9.360931 -18.045971 4620 25.109451 -10.862854 -18.728714 4621 24.421860 -10.570663 -18.705936 4622 25.153641 -9.844208 -18.257011 4623 51.348267 -9.764343 -18.265900 4624 57.288162 -10.908417 -16.953079 4625 57.681870 -11.481018 -16.817806 4626 58.814850 -11.338882 -17.013367 4627 61.735550 -10.152161 -17.441330 4628 61.757294 -11.110779 -17.011951 4629 19.079254 -12.640762 -18.708069 4630 24.461639 -11.196228 -18.769100 4631 24.883705 -12.056778 -18.707554 4632 26.007149 -12.100540 -18.685783 4633 48.101166 -11.568939 -18.900192 4634 48.919312 -11.076141 -18.449162 4635 50.848129 -10.585892 -17.958992 4636 59.819290 -12.751740 -16.260864 4637 60.787079 -13.278778 -16.007301 4638 60.667160 -11.947891 -16.746479 4639 23.858505 -12.742432 -18.251461 4640 23.993820 -11.629532 -18.573627 4641 26.098366 -10.763824 -18.275887 4642 27.098755 -11.818314 -18.434425 4643 26.969986 -13.448563 -18.552361 4644 32.853516 -12.820053 -18.769924 4645 33.749908 -12.856735 -18.286514 4646 34.955139 -12.987030 -18.663788 4647 47.330429 -11.955185 -19.285156 4648 49.060028 -11.751251 -18.418633 4649 51.538574 -12.310898 -19.118641 4650 53.825073 -11.518311 -17.637939 4651 52.485931 -11.745499 -18.076431 4652 19.583099 -13.489029 -19.128971 4653 25.410873 -13.574020 -18.262714 4654 27.866699 -12.717590 -18.561535 4655 28.354229 -13.070108 -18.003111 4656 29.190004 -13.397457 -17.628126 4657 29.229050 -13.828659 -18.692238 4658 28.213249 -13.943832 -18.676510 4659 35.263832 -13.339890 -17.953663 4660 48.906036 -12.171265 -19.028908 4661 57.159897 -12.823105 -18.219044 4662 34.919815 -15.270966 -18.884972 4663 35.615311 -15.580658 -18.191296 4664 27.557053 -15.313889 -18.113930 4665 29.843613 -16.064880 -18.761478 4666 32.790337 -15.444534 -19.469486 4667 26.347122 -14.810974 -17.955299 4668 31.199181 -16.616913 -18.507130 4669 34.704910 -16.486298 -18.098389 4670 32.964806 -18.282547 -17.090969 4671 33.543282 -16.158859 -18.773582 4672 35.931076 -15.812500 -17.703474 4673 35.646698 -16.407440 -17.557842 4674 60.336029 -15.687256 -17.680325 4675 20.639679 -18.151443 -18.640755 4676 29.063950 -16.124069 -18.495811 4677 28.727234 -16.858627 -17.853020 4678 29.191223 -17.901443 -17.317009 4679 41.578552 -16.944336 -19.485222 4680 41.676315 -17.637054 -19.143387 4681 52.920654 -18.294754 -17.717178 4682 61.821121 -16.754929 -16.713455 4683 60.257523 -16.005844 -16.283257 4684 63.522552 -17.622223 -16.318790 4685 62.965622 -16.786636 -15.419621 4686 40.916840 -19.924713 -18.266510 4687 41.251602 -18.890991 -18.519142 4688 41.725540 -18.211624 -18.844585 4689 57.197922 -20.022964 -17.295448 4690 58.773102 -20.651718 -17.494953 4691 57.254745 -19.219574 -18.294407 4692 55.816849 -19.128433 -17.570824 4693 21.984512 -23.215530 -18.512886 4694 60.589249 -21.397995 -17.690147 4695 59.852051 -22.255920 -16.460503 4696 61.336670 -22.619690 -16.894865 4697 61.209106 -20.793793 -18.538670 4698 63.950882 -20.466187 -18.253166 4699 63.406738 -20.630157 -18.600571 4700 63.642792 -21.414078 -18.166740 4701 22.283882 -24.757004 -18.521114 4702 33.751862 -22.008133 -19.777637 4703 33.024689 -22.447556 -19.500149 4704 34.227982 -23.074402 -19.333599 4705 53.667023 -22.054871 -17.829296 4706 52.762650 -21.690933 -17.774239 4707 55.203217 -22.722260 -17.721664 4708 62.325455 -22.022049 -17.848759 4709 64.492737 -20.992081 -17.783936 4710 21.671089 -21.563034 -19.292278 4711 56.019974 -23.453690 -17.341820 4712 56.668549 -23.339813 -17.825340 4713 56.523438 -24.065231 -17.066940 4714 30.819801 -24.224609 -18.742035 4715 32.190735 -27.045578 -15.689430 4716 33.143692 -26.595978 -16.249699 4717 31.278809 -26.070679 -16.708618 4718 40.510742 -21.416367 -18.939121 4719 58.876709 -23.258118 -19.170120 4720 57.844589 -24.232132 -17.614830 4721 40.792191 -22.520004 -17.461388 4722 41.585297 -21.687103 -16.756546 4723 41.200043 -20.755844 -17.454269 4724 62.479218 -25.696991 -18.802250 4725 61.985184 -27.000687 -17.720539 4726 60.912247 -26.041672 -17.690968 4727 26.145294 -26.153183 -19.253258 4728 34.985352 -25.621399 -19.173485 4729 34.762062 -25.979507 -19.229160 4730 40.418121 -25.403244 -19.327904 4731 43.250763 -26.065384 -16.779354 4732 64.113815 -28.542160 -18.464676 4733 24.729141 -26.250061 -19.226929 4734 28.404396 -25.880722 -18.228252 4735 30.581337 -28.165909 -19.734108 4736 40.316910 -26.695648 -19.137920 4737 44.599335 -27.684753 -19.075462 4738 32.268608 -28.424698 -18.407589 4739 64.751251 -28.550644 -19.442001 4740 28.724670 -29.167053 -20.544197 4741 29.022461 -29.133423 -20.249771 4742 30.221375 -29.218002 -18.956795 4743 29.585220 -28.930023 -19.791843 4744 64.669067 -28.574707 -19.063107 4745 29.079468 -29.973312 -19.903130 4746 27.883331 -31.032196 -20.031937 4747 27.801300 -30.888153 -19.838791 4748 27.618225 -31.184647 -19.898964 4749 28.493576 -31.209976 -20.174160 4750 28.385483 -30.758362 -19.685738 4751 38.978577 -30.664871 -19.492558 4752 47.886078 -32.383835 -18.473843 4753 48.397156 -32.200058 -19.107231 4754 64.366623 -32.111755 -19.358856 4755 27.811913 -31.608521 -20.018333 4756 27.645844 -31.583313 -19.752293 4757 29.571167 -33.668610 -20.201473 4758 28.234024 -32.480362 -19.798065 4759 28.803192 -33.235107 -20.129395 4760 27.801895 -31.958023 -19.767776 4761 30.707260 -34.036530 -20.480164 4762 43.445648 -32.823196 -18.661354 4763 44.910767 -33.369263 -19.166622 4764 64.312622 -32.514908 -19.243473 4765 28.500595 -33.409058 -19.745560 4766 31.189240 -34.968613 -20.075958 4767 35.528137 -34.261276 -19.455704 4768 36.976906 -33.823776 -18.690853 4769 41.608582 -33.524643 -17.939171 4770 42.568268 -32.849121 -18.001549 4771 42.357224 -32.966217 -17.406116 4772 49.106781 -33.287292 -18.755108 4773 28.902824 -33.774597 -19.817932 4774 30.177917 -34.497040 -19.914391 4775 33.188599 -34.805801 -20.157207 4776 34.385658 -34.532593 -19.374355 4777 42.219757 -33.077164 -18.805542 4778 61.333359 -33.926727 -19.451698 4779 60.574387 -35.004562 -19.543388 4780 62.698486 -33.422989 -18.811958 4781 31.424240 -35.552444 -19.603455 4782 30.447678 -35.168503 -19.210808 4783 32.336288 -35.427963 -19.906307 4784 33.753868 -34.842178 -19.514454 4785 32.993515 -35.412628 -20.057686 4786 33.244629 -35.329834 -19.759331 4787 46.610474 -34.792572 -19.297951 4788 31.785753 -35.945877 -18.769703 4789 30.460281 -35.579208 -18.489326 4790 32.915482 -35.591553 -19.857861 4791 59.175430 -36.552948 -19.435192 4792 59.496216 -35.966507 -19.196747 4793 59.988541 -35.592377 -18.946697 4794 45.707458 -37.719437 -20.832035 4795 51.954803 -37.138245 -20.072899 4796 58.382248 -37.156754 -19.099979 4797 58.828537 -36.148880 -18.865490 4798 33.271553 -38.849152 -20.213661 4799 33.177200 -38.625504 -19.964737 4800 33.040726 -38.904480 -20.094463 4801 33.386795 -38.724030 -19.933132 4802 35.697968 -38.574356 -19.841812 4803 37.124733 -38.294678 -19.288925 4804 44.226990 -38.806732 -19.154804 4805 43.734039 -39.453140 -19.199844 4806 45.673294 -38.310013 -20.097019 4807 50.025909 -35.487015 -18.821541 4808 50.954926 -36.893723 -19.597931 4809 52.258499 -38.053070 -20.319668 4810 59.085907 -39.087311 -20.243958 4811 57.936691 -39.248459 -19.383408 4812 58.604553 -38.178619 -19.606674 4813 58.238739 -40.216049 -19.969887 4814 33.175751 -39.216080 -20.184311 4815 32.867081 -39.311295 -19.856045 4816 33.411133 -39.136932 -19.945454 4817 51.691086 -38.471634 -20.483917 4818 33.165489 -39.536774 -19.729176 4819 35.062553 -40.263000 -19.915333 4820 44.991440 -38.508331 -18.946690 4821 45.834900 -38.847580 -19.166538 4822 35.265350 -41.360153 -19.960327 4823 47.029602 -40.873840 -19.633633 4824 36.071045 -42.396210 -20.472225 4825 43.587784 -40.218491 -19.236248 4826 56.127975 -42.669922 -20.281136 4827 57.448730 -41.375870 -20.126335 4828 36.643967 -43.693207 -20.438358 4829 35.495155 -42.868774 -19.417961 4830 36.330513 -44.323334 -19.671661 4831 42.923782 -44.002609 -19.489510 4832 43.242767 -43.255814 -19.327785 4833 37.549454 -45.339920 -20.480186 4834 46.748245 -42.805557 -18.864574 4835 51.894897 -45.737030 -19.452679 4836 54.245651 -43.204071 -19.427776 4837 38.800354 -46.905624 -20.610558 4838 46.139862 -45.451096 -19.917503 4839 52.261459 -44.505005 -18.867630 4840 40.559174 -48.197937 -19.877048 4841 40.946503 -48.254562 -19.495811 4842 41.018982 -47.201263 -19.780361 4843 45.666779 -46.098709 -19.359360 4844 51.398865 -46.812958 -19.167404 4845 58.153458 -46.424332 -19.802399 4846 57.074554 -46.237915 -18.857742 4847 37.286453 -47.167938 -19.843292 4848 38.384598 -48.487457 -20.141144 4849 51.215057 -47.909409 -19.270058 4850 51.183014 -46.868896 -17.880920 4851 58.158371 -45.431519 -18.935699 4852 60.066345 -47.048676 -19.674202 4853 51.397095 -49.139099 -20.372467 4854 60.325424 -49.072433 -19.443722 4855 45.884552 -49.360168 -20.684566 4856 51.285782 -49.932465 -19.594624 4857 51.136841 -48.927063 -19.123447 4858 59.575485 -50.861023 -20.294289 4859 45.955002 -50.277496 -20.483559 4860 51.866196 -50.714661 -19.556011 4861 51.959747 -51.523361 -20.096378 4862 51.984253 -52.244171 -20.933315 4863 59.781036 -51.687531 -19.761723 4864 59.391785 -52.990555 -19.919289 4865 46.177155 -51.381485 -20.058681 4866 52.446381 -51.716614 -20.095581 4867 54.267151 -49.707794 -19.648632 4868 47.432907 -55.150299 -19.960136 4869 58.816269 -54.647720 -20.336185 4870 48.265656 -55.532364 -21.115768 4871 48.562531 -56.600128 -21.235413 4872 57.817215 -56.627884 -20.796806 4873 48.623535 -57.512238 -20.971039 4874 49.402069 -58.443207 -21.035339 4875 57.374039 -57.062454 -20.968029 4876 50.129898 -59.607361 -20.850361 4877 51.278717 -59.685089 -21.159561 4878 52.107346 -59.793427 -21.217453 4879 53.343201 -58.559540 -21.765526 4880 57.012207 -58.405457 -19.965721 4881 57.472656 -57.500854 -20.030441 4882 48.327896 -58.326599 -20.049061 4883 48.965790 -59.644913 -20.052765 4884 52.974670 -59.719757 -21.189819 4885 54.176788 -59.130249 -21.362083 4886 55.264572 -59.434296 -20.625195 4887 53.928833 -60.948471 -19.948006 4888 9.048424 50.634888 -13.633865 4889 9.149376 52.089828 -13.279392 4890 8.187103 51.731079 -13.229633 4891 10.162933 51.287537 -13.476887 4892 9.801041 49.445862 -14.110676 4893 9.731277 50.410919 -14.006516 4894 9.401825 48.680847 -13.790596 4895 9.913391 48.299057 -14.193260 4896 10.823608 50.542755 -13.775078 4897 10.297066 50.273865 -14.008999 4898 11.202484 49.619965 -13.856010 4899 11.298050 50.414215 -13.638199 4900 10.369499 47.379883 -14.332787 4901 10.765182 48.327240 -14.308205 4902 11.941574 48.295258 -13.916977 4903 9.776505 47.723755 -13.355995 4904 10.214279 46.545837 -14.044910 4905 10.592865 46.593170 -14.495293 4906 12.858505 48.215820 -13.479225 4907 12.839996 49.414581 -13.069878 4908 11.310593 46.959091 -14.358009 4909 10.897813 45.727005 -14.457413 4910 10.740303 44.552109 -14.492094 4911 11.832855 44.529236 -14.552704 4912 10.323227 45.535538 -13.825966 4913 12.140106 45.740753 -14.128071 4914 12.671844 47.088135 -13.695389 4915 13.298691 44.486084 -13.762539 4916 10.524216 43.729355 -14.410896 4917 13.532852 42.193848 -14.492172 4918 10.740303 41.856720 -14.494030 4919 14.433731 41.474960 -13.643826 4920 4.626907 39.421906 -14.975361 4921 4.068642 40.492493 -13.950737 4922 4.014183 39.156219 -14.378483 4923 4.808952 41.111267 -14.259537 4924 5.620911 40.273605 -14.294331 4925 5.525223 41.739868 -13.589649 4926 14.241707 42.934296 -13.410259 4927 4.851898 40.251846 -14.654537 4928 5.278511 39.587006 -14.883678 4929 11.339677 39.048248 -13.957703 4930 11.136261 40.771790 -13.208353 4931 11.489197 39.838013 -12.187706 4932 11.380867 37.787476 -14.993778 4933 14.731461 40.001297 -13.808285 4934 4.368248 38.698013 -15.094099 4935 7.106827 40.396515 -12.704792 4936 6.356690 40.700470 -13.390472 4937 6.547623 39.146973 -13.749500 4938 5.789147 39.099716 -14.712166 4939 3.775124 36.490891 -13.890743 4940 11.719833 37.693954 -13.935829 4941 11.749931 36.704941 -14.704773 4942 16.218895 37.092575 -14.664249 4943 15.894432 37.682892 -14.106606 4944 16.752747 36.961838 -14.611382 4945 16.039276 35.251404 -16.018970 4946 17.291992 36.631012 -13.659416 4947 6.825775 33.579895 -15.236259 4948 18.476891 34.038452 -14.510452 4949 19.289200 32.898605 -14.093594 4950 3.905861 33.681458 -14.127033 4951 7.402214 33.170975 -14.662506 4952 6.998734 32.453125 -15.565212 4953 12.892891 33.937836 -12.492039 4954 13.283577 33.187103 -12.424023 4955 13.196930 32.928085 -13.471474 4956 3.973892 31.857651 -14.330402 4957 7.364334 30.955200 -15.648430 4958 13.128113 31.889923 -14.516445 4959 13.089432 31.165131 -15.238590 4960 8.813957 28.075989 -14.655682 4961 13.378532 30.225098 -15.442831 4962 20.963432 29.336655 -15.188927 4963 14.135254 27.190094 -14.791492 4964 14.311417 26.119614 -14.343563 4965 13.816833 29.022156 -15.134777 4966 13.816711 27.870270 -15.615341 4967 31.079742 28.550095 -14.423355 4968 31.370079 29.197250 -13.695580 4969 30.752533 28.947815 -13.843098 4970 32.087509 28.927155 -14.172192 4971 33.594887 28.814529 -13.827953 4972 34.199768 27.950668 -14.518597 4973 34.882736 28.462341 -13.482948 4974 4.426079 25.871552 -16.282070 4975 21.386093 28.190506 -14.988602 4976 31.696886 28.086868 -14.979248 4977 32.926048 28.084702 -14.893127 4978 33.848679 27.155121 -15.172913 4979 32.857376 29.005844 -13.930679 4980 29.574043 25.986069 -15.361919 4981 29.513565 26.290604 -15.052498 4982 29.179420 25.982361 -15.035160 4983 30.138626 26.388000 -15.092472 4984 34.939484 26.654922 -14.733521 4985 35.582596 27.269394 -14.293999 4986 35.051346 27.744659 -14.290615 4987 14.096558 24.819687 -14.856537 4988 13.761673 24.046143 -15.713337 4989 21.460373 26.721741 -14.545567 4990 29.144501 25.313904 -15.355507 4991 30.330719 25.213455 -15.772312 4992 8.862152 25.142609 -15.847416 4993 13.552231 23.043167 -15.938473 4994 20.348541 23.834930 -15.376595 4995 20.558899 23.392670 -16.146265 4996 19.748672 22.832001 -15.640236 4997 20.984261 25.188919 -15.457417 4998 27.770111 24.053543 -15.627834 4999 27.728020 24.414276 -15.281651 5000 27.339355 23.903503 -15.222687 5001 28.325768 24.640396 -15.273697 5002 4.876869 23.428925 -16.072781 5003 4.863968 24.618958 -15.980568 5004 5.170448 24.311203 -15.558479 5005 9.029694 24.370544 -15.593609 5006 30.076134 23.565033 -15.625858 5007 30.479919 23.320114 -15.769768 5008 4.474518 22.021439 -16.188522 5009 8.964142 22.433044 -15.002701 5010 18.888130 21.895432 -15.716167 5011 18.536270 21.350159 -16.112961 5012 18.064514 21.039307 -15.697834 5013 19.927643 22.631348 -16.269802 5014 26.706238 23.081299 -15.250729 5015 26.830597 23.624054 -14.534988 5016 30.142334 23.305984 -15.704620 5017 34.775879 23.383209 -15.535873 5018 35.137032 22.590515 -15.060074 5019 35.291672 23.620148 -14.876934 5020 18.210945 21.351898 -15.069935 5021 18.860641 22.194061 -14.134083 5022 19.098892 21.716522 -16.379215 5023 33.908264 20.805893 -15.686440 5024 34.333054 21.574280 -15.737099 5025 35.084961 21.514450 -14.936790 5026 5.264404 18.291443 -16.718937 5027 13.001053 20.131775 -15.118553 5028 13.017242 18.791443 -15.738010 5029 18.294807 20.905365 -16.352905 5030 17.648346 20.309174 -14.600204 5031 34.438232 20.594910 -15.199539 5032 35.275276 20.753571 -14.456844 5033 34.854805 20.046509 -14.700356 5034 12.768463 19.251663 -14.977627 5035 23.451462 18.829788 -16.212257 5036 24.792236 19.274796 -16.572556 5037 32.215149 19.863235 -15.031364 5038 34.163879 19.910278 -14.694801 5039 33.364838 19.342529 -13.746986 5040 43.457718 19.569931 -15.467003 5041 44.610641 19.839340 -15.248791 5042 45.344391 19.723053 -15.404827 5043 3.502426 18.275177 -15.142551 5044 3.964996 17.255676 -15.595345 5045 6.186379 17.622498 -16.320717 5046 13.374084 21.837479 -15.242783 5047 13.299110 21.078659 -14.108414 5048 23.215347 21.105225 -13.579605 5049 22.510498 20.354065 -13.676960 5050 25.594429 18.933472 -16.707726 5051 30.630478 18.832886 -15.708626 5052 41.932617 18.576996 -14.840897 5053 42.024155 17.751495 -14.378670 5054 41.076248 17.892471 -14.944954 5055 47.087906 19.171570 -14.306461 5056 48.269669 18.900757 -14.249268 5057 4.943985 17.126099 -16.348366 5058 5.385063 15.794373 -16.257034 5059 6.142960 15.625229 -16.232254 5060 6.114899 16.365601 -16.214993 5061 14.124763 16.955978 -16.447311 5062 14.787308 17.720825 -16.562126 5063 13.424606 17.646729 -16.195045 5064 15.081680 16.686432 -16.292664 5065 15.822830 16.662888 -15.797661 5066 15.568008 17.483917 -16.098251 5067 22.319733 17.602570 -16.196301 5068 22.362770 18.522476 -15.891365 5069 21.742371 18.135910 -15.624527 5070 21.007439 16.767883 -15.830589 5071 30.185181 18.281158 -15.979622 5072 38.334702 16.816055 -16.487610 5073 13.678848 16.393250 -15.719677 5074 14.519966 16.121368 -16.210384 5075 22.210297 16.379913 -16.433609 5076 21.479164 15.427612 -16.431778 5077 4.542122 15.942535 -15.627213 5078 5.179604 15.133835 -15.736938 5079 14.439621 15.587997 -15.889610 5080 15.340103 15.749329 -15.866970 5081 19.058228 15.152542 -16.236465 5082 19.648041 16.111740 -15.800114 5083 18.592346 16.155640 -15.340973 5084 40.103882 16.214844 -15.055809 5085 6.023659 15.110947 -15.996170 5086 13.606987 15.924667 -15.012318 5087 14.026672 15.449432 -15.342613 5088 21.102058 14.728134 -16.534046 5089 18.485718 14.122665 -16.586945 5090 18.234383 14.816864 -15.987164 5091 18.366653 10.964050 -16.341808 5092 18.623871 10.420074 -16.925732 5093 18.807968 10.505508 -16.244379 5094 28.684418 11.012070 -16.622179 5095 18.572151 10.073578 -17.260368 5096 19.299545 10.191177 -16.460152 5097 23.759430 9.949387 -16.395401 5098 28.490463 10.907547 -16.486416 5099 49.738525 12.623199 -16.285172 5100 22.282608 9.953323 -15.600891 5101 54.258591 9.101929 -15.975811 5102 53.706696 8.376816 -15.878811 5103 39.076225 8.398254 -16.039581 5104 49.641068 9.875198 -15.463074 5105 39.988319 7.755875 -15.309576 5106 39.231308 7.269104 -15.546545 5107 48.563858 8.474075 -15.807343 5108 37.098984 5.873581 -16.113815 5109 38.208328 6.953598 -16.087780 5110 37.580750 6.329865 -16.258415 5111 51.323685 4.210953 -15.623470 5112 50.972931 4.790848 -16.384209 5113 29.424286 3.750961 -16.749645 5114 38.020767 5.568924 -14.978672 5115 36.029694 5.354271 -15.241486 5116 46.404816 5.215637 -16.284985 5117 58.084244 5.008682 -16.061195 5118 58.089844 5.550766 -15.004829 5119 28.044281 3.600159 -16.685059 5120 31.164177 2.742416 -15.576553 5121 31.988451 4.253571 -15.787037 5122 31.847391 4.058167 -14.792236 5123 34.803658 5.077255 -16.845791 5124 50.384247 3.663895 -16.265556 5125 49.537567 3.359390 -16.942459 5126 20.492615 1.909332 -17.257111 5127 21.714317 2.215103 -17.118797 5128 25.372452 2.956314 -17.428635 5129 26.309616 2.501083 -16.980553 5130 58.680405 4.229103 -15.369858 5131 19.853119 1.868225 -17.593670 5132 26.888588 1.483154 -16.935547 5133 27.672180 2.347687 -16.791470 5134 27.667068 0.735825 -17.179958 5135 30.755630 0.997086 -16.722050 5136 31.469406 1.162064 -16.121170 5137 59.132629 2.709457 -15.455673 5138 19.941101 0.792435 -17.700882 5139 28.761688 1.401627 -17.000153 5140 46.044952 1.454178 -16.510944 5141 45.884491 2.208755 -15.637280 5142 49.296173 2.318787 -16.429558 5143 23.072792 1.383545 -17.268158 5144 25.206894 2.009033 -17.110447 5145 26.795746 -0.030609 -17.639595 5146 26.677376 0.756027 -17.252605 5147 29.753120 -0.032410 -17.019539 5148 29.889099 2.271866 -16.715755 5149 28.623611 -0.170837 -17.175182 5150 27.698257 -0.995911 -17.372215 5151 31.373444 0.261520 -16.814323 5152 31.493759 -0.370255 -16.901352 5153 30.875702 -0.427170 -16.958492 5154 31.865679 0.876602 -15.708015 5155 31.973726 0.056229 -16.339077 5156 46.993652 0.515747 -16.266949 5157 21.660934 -3.475204 -17.683960 5158 27.418467 -1.656828 -17.242750 5159 27.093410 -1.478395 -17.549938 5160 45.920746 0.589859 -15.597992 5161 48.493469 0.981750 -16.032219 5162 18.747284 -1.348114 -17.673336 5163 28.805489 -0.996587 -16.789822 5164 29.926479 -1.011471 -16.329300 5165 27.893789 -1.769718 -16.858431 5166 27.294064 -2.718278 -16.764503 5167 20.959709 -5.240112 -17.422533 5168 19.917679 -3.780334 -17.333981 5169 22.911972 -4.070633 -18.009563 5170 22.451065 -4.865799 -17.683662 5171 20.593903 -2.926697 -17.417551 5172 25.123005 -5.456193 -17.205866 5173 24.163198 -5.394150 -17.558886 5174 25.646139 -4.503031 -17.197773 5175 26.025372 -4.777759 -16.850420 5176 26.727976 -3.737311 -16.698828 5177 17.955460 -4.749756 -17.891335 5178 17.974045 -6.687241 -18.282543 5179 23.348053 -5.684204 -17.601360 5180 24.772167 -6.656357 -17.201981 5181 24.301071 -6.223633 -17.334984 5182 26.966160 -4.233181 -16.195890 5183 27.479052 -3.177060 -16.301283 5184 26.529152 -4.525596 -16.516533 5185 22.221085 -6.243240 -17.429321 5186 23.349335 -6.734787 -17.373917 5187 25.915077 -5.951984 -16.631090 5188 25.535923 -6.543459 -16.866179 5189 26.441401 -5.299246 -16.295815 5190 17.925423 -8.439560 -18.137016 5191 22.551834 -7.582840 -17.571884 5192 21.984543 -8.401367 -17.819439 5193 23.557739 -7.932526 -17.783012 5194 24.309120 -7.507492 -17.273724 5195 24.233932 -8.277924 -17.912849 5196 20.567734 -7.709946 -17.560417 5197 21.775032 -10.604752 -18.053406 5198 22.974060 -11.581299 -18.281376 5199 24.640320 -8.489075 -17.625885 5200 20.255287 -9.564774 -17.702774 5201 23.417770 -7.392700 -17.474529 5202 25.020378 -9.144470 -17.731209 5203 54.731369 -10.190750 -17.255829 5204 55.088715 -11.141663 -17.192982 5205 56.141907 -10.511414 -17.125278 5206 57.362228 -10.148911 -17.479580 5207 62.921478 -8.499802 -16.524437 5208 19.654182 -13.277695 -18.228462 5209 19.358208 -12.269836 -17.883827 5210 20.993668 -12.705460 -17.857281 5211 22.518204 -12.501419 -18.065971 5212 25.860556 -9.643245 -17.515280 5213 26.690857 -10.892409 -17.520210 5214 27.470169 -11.933604 -17.360100 5215 52.072327 -10.409485 -17.646347 5216 18.159790 -11.299316 -18.123055 5217 19.967445 -11.048080 -17.760574 5218 21.677704 -11.630829 -18.028500 5219 62.724182 -11.558136 -16.358780 5220 63.449692 -10.914780 -16.056488 5221 18.278687 -11.746674 -18.154911 5222 18.667145 -12.168701 -18.190285 5223 19.074295 -12.664078 -18.190525 5224 26.959715 -10.813892 -16.448311 5225 26.449038 -9.949418 -16.928843 5226 28.168871 -12.663038 -17.095461 5227 34.393288 -12.639069 -18.483273 5228 52.831558 -11.061279 -17.420486 5229 56.589523 -11.796936 -17.009617 5230 22.811996 -14.256378 -17.729782 5231 20.613701 -14.559387 -17.934376 5232 24.356506 -14.297897 -17.809952 5233 29.609995 -13.672688 -16.809175 5234 30.797844 -14.036267 -16.926374 5235 32.884617 -14.128035 -17.023872 5236 32.956833 -13.437893 -17.890896 5237 33.789890 -13.657959 -17.492067 5238 34.543861 -13.119781 -18.088848 5239 34.773743 -13.612244 -17.491383 5240 35.395073 -13.639450 -17.476143 5241 35.675415 -13.917297 -17.799774 5242 56.979828 -12.798721 -17.168377 5243 57.998352 -13.780823 -17.383148 5244 56.390213 -12.384125 -17.687756 5245 19.815025 -14.406494 -18.597961 5246 35.925858 -15.013260 -17.630165 5247 19.947968 -15.408096 -18.444748 5248 59.154114 -15.164261 -16.846474 5249 28.446602 -16.025360 -18.278988 5250 58.431381 -14.637436 -16.427441 5251 59.563858 -15.587265 -15.539478 5252 58.829468 -15.155426 -16.152214 5253 19.927895 -16.214142 -18.333588 5254 20.158020 -17.298294 -18.794678 5255 27.975967 -16.248795 -17.909824 5256 27.395485 -16.555008 -17.505993 5257 27.486481 -17.239792 -17.191654 5258 30.071701 -18.653366 -16.757637 5259 34.900177 -17.220703 -17.337906 5260 62.059906 -16.628738 -15.523209 5261 61.655197 -16.484665 -15.515823 5262 19.963379 -16.835663 -18.426834 5263 21.146011 -19.511871 -18.028343 5264 41.537125 -19.659119 -17.753258 5265 20.870804 -20.000900 -18.769787 5266 43.078369 -20.241333 -18.357445 5267 42.935242 -21.122940 -17.553391 5268 64.400864 -19.945862 -17.505764 5269 21.177429 -20.574783 -18.544098 5270 65.400513 -18.686157 -15.278305 5271 64.687927 -18.878967 -16.345184 5272 65.654495 -19.626785 -15.555141 5273 52.069336 -21.347809 -17.454361 5274 52.696808 -22.349289 -16.894543 5275 64.441025 -21.908066 -17.695477 5276 65.009476 -21.510925 -17.216679 5277 64.877792 -20.746414 -17.315340 5278 21.818230 -22.985794 -16.792587 5279 21.964462 -21.188858 -17.183792 5280 31.529251 -23.776108 -18.897240 5281 32.894310 -23.585571 -18.737217 5282 54.930054 -23.576508 -16.771236 5283 54.063873 -24.200699 -16.062366 5284 53.813339 -23.622940 -16.320473 5285 63.725952 -22.757828 -17.536133 5286 64.888763 -22.903152 -17.109169 5287 21.711853 -24.764496 -17.492649 5288 22.098190 -25.829636 -17.943222 5289 33.422142 -24.673935 -17.915369 5290 34.293701 -24.286209 -18.508408 5291 59.032425 -24.824356 -17.668003 5292 62.618576 -23.815170 -16.539165 5293 64.071991 -24.293869 -16.829945 5294 29.578400 -24.839081 -18.758476 5295 30.290359 -24.735626 -18.379597 5296 27.489998 -26.282593 -18.309975 5297 34.895409 -25.776321 -18.756119 5298 43.419968 -27.132660 -16.913780 5299 24.317635 -26.684448 -18.810112 5300 25.260162 -26.822906 -18.617550 5301 33.539406 -27.653046 -18.632301 5302 34.231415 -26.902390 -18.276909 5303 34.587067 -26.216873 -18.744461 5304 43.196259 -24.829224 -16.808468 5305 62.936340 -26.935532 -18.185165 5306 25.025696 -27.612289 -17.605282 5307 26.748779 -26.953613 -17.811440 5308 31.313919 -28.861572 -18.437668 5309 44.022797 -27.811615 -17.897816 5310 43.443909 -28.067093 -16.592705 5311 63.117996 -28.202530 -17.787243 5312 62.701782 -29.198196 -17.272709 5313 61.961105 -28.411987 -17.324924 5314 30.764450 -29.526520 -18.319450 5315 44.601257 -28.583328 -18.470787 5316 29.331764 -30.417816 -19.083260 5317 39.395576 -29.697372 -18.794445 5318 39.910889 -28.110504 -18.254631 5319 62.906189 -31.483994 -17.496151 5320 63.239044 -30.081131 -17.669624 5321 63.626511 -31.808151 -18.041916 5322 27.883736 -31.174271 -19.549122 5323 28.664185 -31.206589 -18.813980 5324 38.923569 -30.802658 -18.429565 5325 27.961700 -31.886429 -19.229729 5326 30.600296 -30.733414 -17.778111 5327 29.000015 -31.511612 -17.845551 5328 38.103378 -32.190369 -18.961727 5329 45.996964 -31.100739 -17.904251 5330 47.000305 -31.404587 -18.601940 5331 28.344368 -33.309265 -19.269447 5332 39.010262 -30.666809 -17.541836 5333 38.479141 -31.826096 -17.782337 5334 44.370636 -33.116577 -17.665012 5335 64.259399 -32.312897 -18.772003 5336 28.714203 -33.769470 -19.372944 5337 45.975372 -34.112946 -18.868320 5338 43.283066 -32.784775 -17.345602 5339 64.008163 -33.140823 -18.679615 5340 29.341064 -34.315567 -19.349457 5341 50.238983 -34.297119 -19.142143 5342 49.668152 -34.410477 -18.613037 5343 59.497208 -34.094666 -18.373039 5344 59.255051 -32.954834 -17.726528 5345 60.307007 -33.362061 -18.084328 5346 60.350754 -34.392090 -18.760040 5347 61.387054 -33.376755 -18.373695 5348 63.610016 -33.390594 -18.611370 5349 32.828804 -35.623657 -19.379356 5350 33.419373 -35.305176 -19.235405 5351 47.703964 -35.115570 -18.148003 5352 46.922150 -34.648468 -18.288887 5353 59.364120 -35.196304 -18.703430 5354 58.231628 -34.431931 -18.090294 5355 58.301437 -35.544632 -18.391243 5356 60.055481 -35.135391 -18.713188 5357 60.343018 -35.018494 -18.836716 5358 60.327606 -35.417221 -19.043888 5359 51.488892 -37.860306 -20.006142 5360 57.984055 -36.343140 -18.499187 5361 33.230988 -38.633514 -19.571194 5362 32.894058 -38.883865 -19.606010 5363 33.420395 -38.869095 -19.529915 5364 36.209656 -38.681244 -18.817219 5365 34.897652 -39.423157 -19.091923 5366 38.049728 -38.010223 -18.482292 5367 43.826950 -39.576752 -18.328705 5368 44.535492 -39.754761 -17.211727 5369 44.578354 -38.920242 -18.066946 5370 57.432022 -38.239258 -18.892685 5371 57.098938 -37.134384 -18.393671 5372 32.559250 -39.325455 -19.487862 5373 32.574776 -39.147552 -19.184940 5374 32.394547 -39.421539 -19.143326 5375 33.531403 -39.343231 -19.224751 5376 37.541512 -38.462067 -17.736401 5377 36.823914 -38.373657 -17.043381 5378 57.181992 -40.274948 -19.344723 5379 56.513138 -39.427811 -18.684658 5380 32.646011 -39.709885 -19.037636 5381 33.249512 -39.838043 -19.021248 5382 34.583755 -40.528763 -19.039207 5383 34.519897 -41.660690 -18.574055 5384 43.410187 -41.107178 -18.601383 5385 46.558502 -41.555939 -18.465328 5386 47.082886 -42.151459 -19.465328 5387 55.842300 -41.141357 -19.018829 5388 52.961273 -43.811829 -18.823685 5389 53.199249 -42.657196 -18.041763 5390 36.065422 -45.432510 -18.853836 5391 35.731674 -44.040848 -18.858761 5392 35.329285 -44.312225 -17.584007 5393 60.478668 -43.986496 -18.901840 5394 61.581818 -44.098892 -18.692989 5395 61.014908 -43.297562 -18.488991 5396 42.400085 -44.973938 -19.566143 5397 41.952148 -45.842133 -19.563763 5398 45.913208 -44.990341 -18.981979 5399 51.267517 -45.883179 -18.415276 5400 60.666626 -44.470749 -19.143620 5401 61.065369 -44.925613 -19.131088 5402 35.624710 -47.308090 -18.485500 5403 36.095703 -48.502167 -19.246723 5404 36.679558 -48.064819 -19.528423 5405 41.574875 -46.444443 -19.629635 5406 45.189758 -45.589478 -17.908539 5407 45.406540 -44.175186 -17.593369 5408 59.660904 -45.230118 -19.275726 5409 57.641525 -45.059006 -18.128979 5410 57.539307 -44.007248 -17.178253 5411 56.664230 -45.182236 -17.402702 5412 61.150574 -45.877731 -19.082645 5413 62.083389 -45.046341 -18.596130 5414 45.268402 -47.553680 -18.303104 5415 51.567276 -44.663788 -18.111591 5416 58.526077 -40.757431 -16.782013 5417 58.661316 -42.452881 -17.233017 5418 59.959778 -41.125778 -17.486500 5419 35.451195 -48.565781 -18.869011 5420 39.912331 -47.850464 -20.265198 5421 40.125290 -49.517059 -19.932720 5422 41.316437 -47.724213 -18.976078 5423 60.684113 -48.033951 -19.209297 5424 61.386703 -47.000015 -18.704536 5425 38.043335 -49.854797 -19.944382 5426 37.055283 -49.028000 -19.699043 5427 37.349838 -48.229568 -19.910538 5428 41.368774 -48.750839 -19.046478 5429 45.592361 -49.606445 -19.427338 5430 37.007439 -49.940491 -19.643639 5431 37.078659 -50.821701 -19.600193 5432 38.096039 -51.873093 -19.885406 5433 38.519653 -50.785233 -20.017113 5434 41.164856 -51.707489 -19.998417 5435 42.238953 -51.059204 -19.426346 5436 41.664932 -50.092392 -19.367237 5437 41.948517 -49.326675 -18.646454 5438 39.431732 -51.415512 -20.128578 5439 52.950150 -50.773560 -19.594650 5440 60.406097 -50.512680 -18.984852 5441 60.945389 -49.013199 -18.521950 5442 45.726715 -50.635223 -19.721016 5443 39.330933 -52.740540 -20.151260 5444 42.579315 -52.094574 -19.441589 5445 42.694824 -51.207779 -18.979221 5446 40.763977 -54.162994 -20.191368 5447 42.104553 -52.976257 -20.048882 5448 60.878128 -51.369904 -17.668953 5449 60.192398 -52.277237 -18.631050 5450 37.796875 -52.952332 -19.763412 5451 38.862793 -53.803543 -20.057968 5452 37.538422 -53.978394 -19.621376 5453 38.834061 -54.841629 -19.856590 5454 42.401825 -53.768143 -20.004707 5455 42.635529 -54.809265 -19.842892 5456 41.757751 -55.674530 -20.121403 5457 46.408142 -52.545837 -19.139912 5458 46.695160 -53.395508 -19.804405 5459 52.267014 -51.340591 -19.724602 5460 59.380341 -54.022644 -19.449524 5461 42.721283 -53.081009 -19.783859 5462 43.061401 -53.409607 -19.209034 5463 40.199570 -56.019623 -19.886456 5464 42.022461 -56.708405 -19.810696 5465 42.747955 -56.174988 -19.838242 5466 43.527283 -55.781876 -19.027161 5467 43.517410 -54.552002 -18.831779 5468 59.130280 -54.962341 -18.862148 5469 42.724487 -55.676880 -19.923607 5470 47.317749 -55.480530 -18.474949 5471 46.922058 -54.022873 -18.985085 5472 58.308411 -56.136719 -20.135857 5473 58.753448 -55.600769 -19.593159 5474 47.870850 -56.782257 -20.250313 5475 47.773560 -59.415314 -18.404022 5476 48.589874 -61.028366 -19.113876 5477 49.665970 -60.888977 -20.068886 5478 50.646912 -60.731125 -20.515976 5479 55.604919 -60.450455 -19.214943 5480 37.793800 -59.761520 -18.360460 5481 37.751167 -59.523300 -18.255228 5482 37.671349 -59.779800 -18.313150 5483 37.839546 -59.777969 -18.232096 5484 51.876312 -61.118698 -20.341263 5485 37.780235 -60.372711 -18.423868 5486 37.657417 -60.371506 -18.324129 5487 37.872887 -60.372284 -18.294733 5488 50.498413 -62.196564 -19.572205 5489 37.786240 -61.234055 -18.477446 5490 37.671722 -61.231720 -18.369898 5491 37.886345 -61.231567 -18.357355 5492 37.800667 -62.177597 -18.535772 5493 37.688087 -62.175720 -18.428476 5494 37.900642 -62.174118 -18.417719 5495 37.816460 -63.141312 -18.596319 5496 37.704071 -63.139633 -18.489267 5497 37.916222 -63.137497 -18.478441 5498 37.832390 -64.109070 -18.657316 5499 37.719986 -64.107407 -18.550306 5500 37.932098 -64.105164 -18.539434 5501 37.848305 -65.077515 -18.718279 5502 37.735909 -65.075867 -18.611288 5503 37.948013 -65.073624 -18.600389 5504 37.864235 -66.046097 -18.778269 5505 37.751862 -66.044510 -18.671530 5506 37.963844 -66.042267 -18.660292 5507 37.880608 -67.014282 -18.832132 5508 37.767570 -67.013687 -18.727472 5509 37.979515 -67.010406 -18.712015 5510 37.898499 -67.979797 -18.866240 5511 37.778847 -67.983078 -18.763491 5512 37.997978 -67.970459 -18.725367 5513 37.905563 -68.877274 -18.887560 5514 37.770325 -68.971451 -18.697847 5515 38.032867 -68.936066 -18.652811 5516 37.881783 -69.513931 -18.851381 5517 37.782806 -69.676788 -18.614931 5518 38.032677 -69.494461 -18.743135 5519 37.937309 -69.813248 -18.627291 5520 7.191696 53.302902 -12.725555 5521 7.358505 52.321747 -12.908642 5522 7.629867 52.430817 -13.146572 5523 7.700737 53.859192 -12.906647 5524 8.325317 54.121323 -12.636318 5525 7.446465 54.636398 -12.449226 5526 8.182587 53.007004 -13.087158 5527 9.195557 53.224335 -12.741909 5528 7.606598 51.988815 -13.002460 5529 9.981270 52.431458 -12.857044 5530 11.323822 51.074646 -13.254303 5531 11.068924 52.175735 -12.440269 5532 11.990051 52.321671 -11.447224 5533 12.671265 51.223297 -12.208946 5534 12.820236 51.934570 -11.093456 5535 11.905212 50.372269 -13.299381 5536 8.304047 50.826126 -13.047287 5537 8.644676 50.249344 -13.178669 5538 9.015503 49.581848 -13.295929 5539 9.263261 48.721710 -13.073059 5540 13.845474 47.892410 -12.845818 5541 10.394829 45.342682 -12.604755 5542 10.361366 44.511871 -13.685667 5543 13.588120 46.459854 -13.074863 5544 12.946807 45.849182 -13.585907 5545 13.414323 45.594543 -13.287968 5546 10.425415 43.591370 -13.812302 5547 3.915115 41.670380 -13.440849 5548 4.305161 41.614716 -13.980042 5549 4.560509 42.568970 -13.467625 5550 5.566704 43.318161 -12.870140 5551 4.728607 43.446976 -13.134567 5552 10.694213 42.773895 -13.479195 5553 10.558968 44.140213 -12.738655 5554 10.896606 43.424011 -11.897842 5555 3.839928 42.489471 -12.650291 5556 4.770508 41.883423 -13.961815 5557 10.857605 41.612442 -13.759846 5558 14.950981 40.757767 -12.932655 5559 15.227264 42.145172 -12.484730 5560 3.774826 39.461914 -12.479774 5561 6.555069 37.909790 -14.083275 5562 11.859276 38.226898 -12.748444 5563 12.102966 35.805511 -14.239120 5564 16.691910 37.193787 -13.933723 5565 21.140091 36.681335 -13.750725 5566 20.713089 37.068634 -13.376785 5567 20.599457 36.636246 -13.620487 5568 22.066147 37.118713 -13.257069 5569 22.902573 36.565933 -13.909286 5570 23.391602 36.470764 -13.970352 5571 23.217468 36.680847 -13.675159 5572 3.532486 37.875046 -12.334347 5573 3.246491 36.768616 -12.022396 5574 8.039581 36.593399 -12.989296 5575 9.774490 35.083481 -11.773447 5576 8.937225 36.698822 -11.986446 5577 21.985519 35.129639 -14.014729 5578 22.061722 36.189575 -13.905193 5579 20.887611 35.898010 -13.672684 5580 23.738411 35.493668 -13.890419 5581 22.611542 34.247269 -14.088619 5582 23.498520 33.980713 -14.055714 5583 12.461243 34.517624 -14.141792 5584 12.375923 35.597290 -13.454998 5585 18.525665 34.945389 -13.145283 5586 20.985466 34.527100 -13.631628 5587 20.981339 32.822861 -13.594608 5588 19.789314 33.068008 -13.338310 5589 20.147812 32.456985 -13.438614 5590 24.994629 34.601822 -13.985512 5591 24.487656 33.938492 -14.012688 5592 25.064972 34.999374 -12.823952 5593 23.611496 36.576035 -12.793694 5594 25.189468 33.998611 -13.958691 5595 24.389130 35.983307 -11.942513 5596 3.769280 34.863770 -14.075623 5597 8.388275 33.228485 -13.553955 5598 21.825378 34.369690 -14.024487 5599 25.442825 34.176575 -13.607281 5600 25.062386 34.892441 -13.682961 5601 21.051132 31.053680 -14.211060 5602 21.855667 31.606522 -13.964180 5603 21.815208 33.750977 -13.893456 5604 24.435699 32.797699 -13.907326 5605 25.259018 33.137222 -13.719025 5606 25.858154 33.309250 -12.808598 5607 12.085403 30.685226 -10.979588 5608 10.921997 31.952972 -11.590816 5609 10.641403 29.735840 -12.264986 5610 13.748672 31.477737 -13.352806 5611 22.636169 32.840454 -13.941475 5612 24.879791 31.530518 -13.960133 5613 26.017525 31.152267 -13.300831 5614 25.819138 32.234055 -13.410156 5615 23.700577 32.040802 -14.027573 5616 3.754723 30.340302 -13.682919 5617 13.530014 30.981567 -14.438679 5618 14.331871 29.034073 -13.444210 5619 14.112305 28.227859 -14.507900 5620 23.887070 30.877182 -14.295670 5621 23.781860 29.643280 -14.297958 5622 24.497314 30.291809 -14.255783 5623 24.562988 29.642410 -14.190079 5624 23.750252 33.148117 -13.945770 5625 25.245468 30.048492 -13.691128 5626 14.025314 30.227936 -13.720333 5627 21.776886 28.963501 -14.685635 5628 21.840866 29.958893 -14.461857 5629 22.760887 30.856155 -14.244453 5630 21.856079 30.771423 -14.155079 5631 22.628464 29.078613 -14.337334 5632 23.542664 28.376587 -13.726906 5633 24.525864 29.007706 -13.773518 5634 30.313408 26.766724 -14.535908 5635 30.182175 27.320923 -14.217438 5636 33.970474 28.973251 -12.892712 5637 10.252701 27.262283 -13.323578 5638 9.397041 27.688934 -14.225388 5639 35.571999 27.791183 -13.912708 5640 35.979507 27.276398 -13.872639 5641 5.117371 25.506012 -14.587772 5642 9.666595 25.367325 -14.414978 5643 10.696991 26.179398 -12.874645 5644 29.337189 26.372192 -14.436512 5645 30.016022 26.454468 -14.521645 5646 29.929596 26.787231 -14.228344 5647 35.875908 26.664185 -14.172749 5648 36.059662 25.627136 -14.239883 5649 36.944153 25.990417 -13.622036 5650 36.406906 26.737167 -13.560982 5651 5.910553 24.777771 -13.832249 5652 5.832420 25.506409 -12.930862 5653 10.551361 25.146973 -13.012665 5654 9.915764 24.373337 -13.894436 5655 10.279488 23.971375 -13.038570 5656 28.734802 25.522858 -14.735550 5657 28.139244 24.999847 -14.522774 5658 5.379471 23.991089 -15.087894 5659 5.791756 24.097626 -14.384682 5660 9.315308 23.914597 -14.842197 5661 13.774063 23.348358 -14.934765 5662 21.955612 26.481689 -11.938126 5663 21.237411 25.613861 -12.784897 5664 21.033989 25.613708 -10.989353 5665 20.508163 24.585159 -14.025448 5666 27.352859 24.128830 -14.621418 5667 27.731682 24.476120 -14.792656 5668 36.130478 24.098221 -14.114483 5669 39.054092 24.390747 -14.217373 5670 38.392281 23.880783 -14.104317 5671 38.909630 23.761795 -14.309235 5672 39.925217 24.209076 -14.203850 5673 39.365280 23.792160 -14.306522 5674 38.972687 25.446838 -13.680447 5675 37.615021 24.863113 -13.906845 5676 40.167618 24.889771 -13.736298 5677 40.517487 24.193069 -13.725498 5678 5.019638 22.644135 -14.280508 5679 9.648376 23.420670 -14.013586 5680 30.303909 23.486816 -15.584408 5681 3.395607 20.625839 -13.917610 5682 8.580093 21.146393 -14.930172 5683 20.168289 24.201752 -9.191463 5684 20.520645 25.271637 -9.567547 5685 19.717041 23.507477 -11.242039 5686 25.742142 22.676849 -14.419605 5687 25.379456 22.068848 -15.087669 5688 38.895828 23.316345 -13.870457 5689 39.786377 23.650955 -13.998096 5690 5.409226 23.104294 -12.380386 5691 4.259590 22.249878 -12.585686 5692 24.624725 21.787033 -14.699215 5693 24.628113 22.250351 -13.656250 5694 35.659386 23.227081 -14.142632 5695 35.853409 22.079834 -13.639698 5696 2.926140 18.599899 -13.621056 5697 8.126160 20.273819 -15.194168 5698 23.864319 21.540085 -13.945328 5699 17.683273 19.372253 -13.163887 5700 18.006111 20.676102 -13.186005 5701 22.289001 19.224396 -15.054903 5702 31.475128 19.693726 -15.019886 5703 31.025826 19.269775 -14.913845 5704 34.763161 19.546753 -14.187851 5705 35.331032 20.005234 -14.240120 5706 44.613251 19.548706 -14.672806 5707 42.801682 19.021088 -14.799446 5708 43.894562 18.867477 -14.320141 5709 45.338120 19.793839 -14.697678 5710 45.330627 19.565887 -14.334522 5711 3.415054 17.372665 -14.504299 5712 7.848434 18.471100 -14.433258 5713 12.713554 18.527512 -14.728504 5714 30.300323 18.321671 -15.298521 5715 30.615738 18.751343 -14.834076 5716 47.798889 18.805115 -13.235386 5717 48.857498 18.806488 -13.486038 5718 48.566681 18.866638 -12.751114 5719 49.926880 18.236450 -13.222900 5720 7.039902 16.758957 -15.453709 5721 13.031082 17.527344 -15.111073 5722 16.221024 17.511749 -15.418583 5723 19.774826 16.945587 -15.183571 5724 20.844582 18.100769 -14.710358 5725 30.156540 17.692108 -15.086319 5726 30.486618 18.315521 -14.662960 5727 51.085754 17.734787 -13.228607 5728 52.075745 17.045853 -12.932808 5729 6.894104 15.440033 -15.476524 5730 13.323700 16.639938 -14.251060 5731 16.187798 16.732986 -15.385887 5732 21.372086 19.376434 -13.368969 5733 20.020660 18.436768 -13.214474 5734 29.602150 17.123932 -14.631882 5735 30.269470 17.528290 -14.567413 5736 30.528625 17.947052 -14.491768 5737 41.005890 16.946762 -14.644100 5738 41.084381 15.748169 -14.461784 5739 16.392624 16.145599 -15.368494 5740 16.153214 14.482727 -15.352486 5741 17.392075 15.384644 -15.506008 5742 28.193306 15.281631 -14.529381 5743 5.755493 14.470856 -15.557861 5744 6.510552 14.505585 -15.582954 5745 14.811409 15.010437 -15.540260 5746 14.361870 14.938309 -14.922771 5747 39.865662 15.234756 -15.190693 5748 40.616791 14.712891 -14.713959 5749 39.702309 14.171707 -15.381973 5750 40.723907 13.720978 -14.725212 5751 53.141571 15.094452 -12.328285 5752 5.589645 13.788025 -14.984787 5753 6.127022 13.425079 -15.073395 5754 6.216164 13.905762 -15.352531 5755 6.979256 13.856079 -14.672405 5756 14.986938 14.583527 -14.990170 5757 15.473175 14.423187 -14.034233 5758 16.516991 13.490417 -13.781513 5759 16.571350 13.069748 -15.060402 5760 27.693939 14.413467 -14.696163 5761 4.978836 14.742554 -14.808300 5762 25.828590 12.264557 -15.563122 5763 25.389702 12.378082 -15.048706 5764 25.958023 13.023911 -14.855659 5765 27.592667 13.622391 -15.252209 5766 26.877975 12.456467 -15.689537 5767 26.741814 14.072678 -14.344437 5768 28.009155 11.352753 -16.471172 5769 39.553513 13.047134 -15.587364 5770 16.814529 13.181915 -15.642410 5771 17.244888 12.288666 -15.447273 5772 17.955437 11.403412 -15.445824 5773 25.160309 11.593109 -15.644131 5774 24.783630 11.438324 -15.210827 5775 25.000481 11.845825 -15.019676 5776 38.976913 11.787537 -16.219959 5777 50.192215 12.370728 -15.776646 5778 18.765648 10.701767 -15.404850 5779 24.515213 10.716110 -15.489594 5780 28.530632 11.116150 -16.421425 5781 40.609085 9.545776 -15.125854 5782 42.276337 10.184128 -13.570557 5783 41.633575 8.709824 -14.120644 5784 38.966614 9.746490 -16.348961 5785 50.642334 11.316498 -15.022987 5786 19.475967 9.966537 -15.818996 5787 20.164085 10.081268 -15.935642 5788 19.117538 10.205261 -15.818672 5789 21.293762 10.124084 -15.607380 5790 24.118484 10.066437 -15.820667 5791 38.694679 10.685791 -16.571976 5792 40.555862 8.466644 -15.102940 5793 40.398834 10.921265 -15.232235 5794 50.789108 12.518250 -15.160507 5795 23.144287 9.958755 -14.870716 5796 23.673218 9.861450 -15.668587 5797 54.729095 8.512085 -15.351639 5798 40.345245 6.037964 -14.613667 5799 39.961853 6.922989 -15.016380 5800 40.976837 7.189301 -14.388626 5801 48.810120 7.509918 -15.115189 5802 49.680176 8.489227 -14.672913 5803 38.007408 6.104797 -15.682125 5804 46.452423 3.922897 -15.636833 5805 48.406006 6.363647 -14.939129 5806 54.737381 6.939392 -14.276184 5807 55.710388 7.834717 -14.816307 5808 56.272141 7.288544 -14.255257 5809 57.550705 6.404694 -14.980980 5810 47.358643 4.975143 -15.255859 5811 53.002686 4.296051 -14.010704 5812 58.005936 5.199707 -12.793037 5813 57.539642 6.144089 -13.965752 5814 58.718887 4.335739 -13.858231 5815 27.130981 3.379730 -16.943325 5816 28.736748 3.750076 -16.622005 5817 33.679779 4.869621 -15.959415 5818 32.911919 4.650467 -14.693722 5819 32.128181 4.368744 -13.847183 5820 51.880798 2.610703 -13.913918 5821 50.620255 2.071411 -14.848362 5822 58.717377 3.963303 -12.324020 5823 58.375763 4.613068 -12.558346 5824 22.806175 2.676437 -17.341305 5825 28.768066 2.933929 -16.677120 5826 31.493828 3.529480 -14.166267 5827 47.184143 2.817917 -14.096519 5828 50.512634 3.017197 -15.709415 5829 19.258377 -1.590652 -17.355507 5830 45.674164 0.956238 -15.028507 5831 59.667862 1.760162 -14.884605 5832 59.476089 2.790985 -14.181740 5833 19.932678 -2.582428 -17.278709 5834 19.007713 -2.772659 -17.282684 5835 32.257339 0.482269 -15.648186 5836 31.791418 -0.583759 -15.721016 5837 32.581253 -0.050186 -15.722496 5838 59.834259 0.610626 -14.870575 5839 31.537781 -1.013580 -16.592613 5840 48.594757 -0.311142 -15.043003 5841 46.597168 -0.980042 -15.105026 5842 18.179428 -2.943405 -17.461494 5843 29.870712 -1.292887 -15.275173 5844 29.342228 -1.659634 -14.782928 5845 29.255402 -1.607382 -15.648174 5846 30.669270 -1.023993 -15.493750 5847 45.755371 -0.188538 -14.758877 5848 59.978973 -0.543121 -14.926941 5849 28.483479 -1.987375 -16.191969 5850 28.176601 -2.797465 -15.410021 5851 27.922058 -2.911304 -15.918625 5852 31.166338 -0.837680 -15.139681 5853 31.667318 -0.703922 -15.024651 5854 18.305832 -3.857498 -17.467442 5855 18.783997 -5.658600 -17.663795 5856 28.748114 -2.121169 -15.137369 5857 28.399897 -2.653540 -14.580061 5858 25.164883 -6.502322 -17.081808 5859 27.728424 -3.590820 -15.347412 5860 27.455925 -3.803305 -15.777613 5861 27.885021 -3.462199 -14.909863 5862 18.398048 -7.554260 -17.840408 5863 26.409307 -6.451352 -16.002682 5864 26.908604 -5.039702 -15.760641 5865 27.056873 -5.238204 -15.062029 5866 26.762638 -5.862113 -15.500610 5867 27.368055 -4.341198 -15.272068 5868 27.480993 -4.282115 -14.684603 5869 25.227997 -7.451746 -17.046555 5870 25.158497 -8.418093 -17.348377 5871 62.499268 -7.692520 -16.655888 5872 62.294449 -6.580917 -16.182785 5873 62.020294 -5.059525 -15.277500 5874 63.060501 -6.082794 -14.693306 5875 63.688843 -7.416977 -14.796654 5876 63.716949 -6.228622 -13.692890 5877 18.734726 -8.760742 -17.746391 5878 18.729820 -9.938812 -17.831650 5879 25.698286 -8.351884 -17.027025 5880 25.965347 -7.357902 -16.542793 5881 26.162441 -8.738291 -16.693211 5882 63.521103 -8.810043 -15.796310 5883 63.081482 -7.808838 -15.952692 5884 18.508293 -10.822372 -17.863926 5885 63.799896 -9.966232 -15.661957 5886 18.613899 -11.566879 -17.874361 5887 26.544453 -9.366206 -16.298998 5888 27.536137 -12.129354 -16.011555 5889 54.000565 -10.871490 -17.163689 5890 57.289612 -12.681061 -16.539864 5891 57.881287 -12.182983 -16.566216 5892 64.080795 -10.888077 -15.287659 5893 62.782547 -12.598236 -15.937561 5894 63.627838 -12.044174 -15.403919 5895 28.578798 -13.042724 -16.601984 5896 57.285522 -13.114471 -16.732792 5897 57.960266 -12.979279 -16.215996 5898 58.795761 -12.889938 -16.203888 5899 61.893356 -12.761642 -16.136276 5900 61.605423 -14.593704 -15.006207 5901 62.896103 -13.448242 -15.243927 5902 23.401604 -16.260071 -17.289684 5903 21.801506 -16.471222 -17.451561 5904 25.383301 -15.826569 -17.484943 5905 24.155304 -15.639175 -17.457439 5906 31.969076 -14.256443 -16.839920 5907 32.668507 -14.988118 -15.903851 5908 33.975784 -14.427190 -16.580442 5909 35.483543 -14.261627 -16.856899 5910 34.609470 -14.951477 -15.846657 5911 57.630737 -13.253632 -16.433849 5912 58.386810 -13.816940 -16.177097 5913 64.342072 -13.086014 -14.251923 5914 65.516449 -13.216461 -12.903362 5915 65.371384 -11.971069 -13.155647 5916 20.351395 -15.789780 -17.945881 5917 21.478378 -17.339539 -17.368958 5918 20.917267 -17.335358 -17.768044 5919 20.365982 -16.631851 -17.952229 5920 36.219322 -15.092056 -16.860935 5921 36.307602 -14.822693 -15.909924 5922 36.648773 -15.563675 -16.414909 5923 11.541894 -14.954535 -9.805540 5924 11.619924 -14.020657 -9.827702 5925 11.137820 -14.779957 -9.581419 5926 11.029950 -14.085424 -9.526251 5927 11.797711 -14.809232 -9.952621 5928 21.814110 -17.461411 -17.164043 5929 26.556259 -16.009903 -17.564404 5930 36.163651 -17.099335 -16.306213 5931 36.155167 -15.885391 -17.113615 5932 12.057836 -15.485872 -9.974182 5933 12.090003 -14.797052 -10.073722 5934 12.628274 -15.125338 -10.231141 5935 20.243851 -17.291504 -18.212879 5936 22.421936 -17.922516 -16.832413 5937 24.488388 -17.303116 -16.922512 5938 23.294220 -17.572296 -16.771332 5939 25.409126 -17.170639 -16.992332 5940 60.946274 -16.226059 -15.398014 5941 21.530785 -18.146255 -17.362038 5942 28.512695 -18.789062 -16.445374 5943 27.643631 -18.079224 -16.854664 5944 30.315506 -19.899460 -15.595989 5945 28.756577 -19.671600 -15.664722 5946 42.166199 -20.501328 -17.301834 5947 51.705826 -19.656021 -16.804790 5948 52.030212 -19.007065 -16.857628 5949 52.440704 -19.426620 -16.000622 5950 53.340454 -19.925888 -15.409058 5951 54.784149 -19.298004 -16.793201 5952 64.601410 -17.434845 -15.128738 5953 54.501480 -19.940247 -15.772232 5954 56.295639 -20.027817 -16.786545 5955 57.646271 -21.315582 -16.210587 5956 43.292648 -22.044006 -17.817375 5957 65.285110 -20.484497 -16.482376 5958 40.425293 -25.430099 -17.060085 5959 51.494141 -20.720612 -16.735985 5960 51.461655 -21.781906 -16.230797 5961 51.186783 -20.924881 -16.049805 5962 65.744415 -21.936218 -16.258404 5963 53.975418 -22.695145 -17.121979 5964 53.600464 -23.117538 -16.569981 5965 65.643402 -22.900330 -16.740681 5966 65.951935 -22.747162 -16.420567 5967 43.307800 -23.537552 -17.754185 5968 64.993500 -24.366425 -16.793190 5969 65.505692 -23.672241 -16.801704 5970 65.995758 -23.457306 -16.446007 5971 29.711227 -25.423752 -17.880390 5972 34.485901 -28.760910 -16.426559 5973 33.869133 -28.549774 -17.561157 5974 34.077042 -26.971725 -17.031387 5975 57.010391 -24.986084 -16.673908 5976 58.203995 -25.366348 -16.986729 5977 65.841492 -24.756271 -16.267929 5978 64.766953 -25.856400 -16.208416 5979 65.760239 -26.433167 -15.868153 5980 66.451874 -23.889099 -15.973480 5981 21.680786 -25.772720 -17.525246 5982 31.588776 -24.732162 -17.880669 5983 34.378021 -25.664841 -18.084492 5984 59.443436 -25.708878 -17.340500 5985 59.901505 -26.746368 -17.083317 5986 58.295715 -26.560516 -16.620598 5987 23.879822 -28.033295 -17.100559 5988 22.769318 -27.943436 -16.869919 5989 22.706810 -26.944580 -17.836716 5990 60.967239 -26.766983 -17.406693 5991 22.076965 -27.520676 -17.127750 5992 28.202698 -28.045959 -15.713013 5993 26.672791 -27.712662 -16.848431 5994 26.598198 -28.260330 -15.931969 5995 33.062622 -28.224274 -18.381985 5996 33.507652 -28.436752 -18.176846 5997 60.780548 -27.609940 -17.208908 5998 31.447006 -29.720490 -18.064060 5999 32.990158 -28.972107 -18.050922 6000 32.142120 -29.280945 -18.111652 6001 44.198639 -28.904007 -17.421974 6002 61.900894 -29.728348 -17.104454 6003 60.685455 -28.879440 -17.001015 6004 39.379333 -29.587173 -17.757599 6005 44.868073 -30.158356 -17.262222 6006 28.194756 -31.969269 -18.279869 6007 38.872467 -31.259140 -16.805836 6008 45.189255 -31.431076 -16.601555 6009 46.146301 -32.390289 -17.043701 6010 27.922684 -32.924072 -18.689335 6011 27.809402 -32.524475 -17.874176 6012 27.350815 -33.378555 -17.835892 6013 28.533485 -33.968994 -18.837440 6014 37.785599 -33.342590 -17.722458 6015 38.276604 -33.472809 -16.473679 6016 38.374954 -32.488983 -16.991825 6017 46.916275 -32.389648 -17.752724 6018 48.367523 -33.568314 -18.085403 6019 57.616714 -33.164398 -17.535015 6020 60.261734 -32.103607 -17.364906 6021 60.248566 -32.760788 -17.675430 6022 61.126144 -32.572922 -17.726116 6023 62.551071 -32.463516 -17.901875 6024 61.747375 -31.342102 -17.317127 6025 27.875488 -34.285339 -18.259281 6026 26.547653 -33.964478 -16.883842 6027 27.104324 -34.531799 -17.648212 6028 44.215942 -32.749130 -16.607929 6029 47.588501 -33.307541 -17.755779 6030 57.025528 -31.733047 -16.972584 6031 58.459137 -31.868103 -17.210323 6032 59.402756 -31.953110 -17.307693 6033 63.589554 -32.887543 -18.336906 6034 29.204910 -35.329803 -18.292702 6035 27.760307 -35.467270 -17.759151 6036 28.507614 -36.337540 -17.635246 6037 34.178284 -35.141205 -18.955883 6038 36.259674 -35.121353 -18.066849 6039 37.143372 -34.516357 -17.748756 6040 40.837753 -34.556458 -18.048115 6041 40.353851 -35.310318 -17.198639 6042 49.038742 -34.451889 -18.302505 6043 48.868683 -35.378708 -18.365631 6044 48.184265 -35.192947 -18.006889 6045 56.535980 -34.352646 -17.552937 6046 56.081482 -33.106949 -17.055378 6047 56.866135 -35.745651 -17.961391 6048 33.209068 -35.795517 -18.801125 6049 33.970200 -36.091217 -18.432594 6050 35.032944 -35.680313 -18.333717 6051 35.895294 -36.375748 -17.255932 6052 39.358665 -36.730576 -18.052471 6053 45.343414 -33.567398 -17.641586 6054 54.710938 -34.247589 -16.560478 6055 54.761841 -32.929398 -16.470711 6056 60.226944 -35.302551 -18.727604 6057 30.471176 -36.086853 -17.962574 6058 31.513275 -36.824402 -17.501312 6059 32.997391 -36.564407 -18.125328 6060 37.328232 -38.494888 -18.556686 6061 55.597076 -35.241928 -17.276619 6062 55.360001 -36.190201 -17.295315 6063 34.319290 -36.911636 -17.641129 6064 55.797333 -36.956421 -17.738903 6065 55.696030 -38.178162 -17.972034 6066 33.140602 -38.931030 -18.941982 6067 44.387207 -38.716507 -18.520760 6068 54.413132 -35.625702 -16.558498 6069 53.893829 -37.304230 -16.452362 6070 62.846481 -39.597412 -17.832245 6071 63.864380 -39.207077 -17.691534 6072 63.264862 -38.602219 -17.642651 6073 64.084641 -38.692810 -17.517683 6074 64.135010 -38.205139 -17.090294 6075 62.965881 -37.756485 -17.204651 6076 64.859253 -38.383560 -16.138557 6077 64.463867 -37.933777 -16.472542 6078 32.476524 -39.342453 -18.478912 6079 32.988190 -38.822174 -17.756100 6080 32.241875 -39.258240 -17.542057 6081 33.970985 -39.022202 -18.347076 6082 45.312378 -39.111725 -18.111061 6083 54.837646 -39.684082 -17.860504 6084 32.969284 -40.427765 -18.093929 6085 33.914268 -39.905594 -18.694363 6086 33.918228 -40.745621 -18.358246 6087 43.335739 -40.762985 -17.383736 6088 54.492401 -41.241226 -18.210548 6089 53.601074 -40.541428 -17.297508 6090 61.479721 -41.056366 -17.951687 6091 60.611572 -40.072571 -17.543106 6092 63.964828 -40.150482 -17.643066 6093 61.815338 -40.084427 -17.859230 6094 61.451477 -38.636108 -17.400688 6095 62.869720 -40.715195 -17.950005 6096 64.762497 -39.290039 -16.873829 6097 62.761475 -43.070663 -17.958961 6098 63.916183 -41.154205 -17.639893 6099 34.869019 -42.601074 -18.391827 6100 42.995148 -42.228394 -18.008568 6101 42.544769 -42.028519 -17.133961 6102 42.932159 -43.329285 -18.692665 6103 60.884140 -42.281525 -18.034161 6104 62.813919 -41.780212 -17.946175 6105 64.295029 -42.113586 -17.317108 6106 35.254570 -43.346771 -18.407524 6107 59.824585 -43.478043 -18.408745 6108 64.781387 -43.702530 -16.371071 6109 65.869629 -42.840607 -14.877079 6110 65.667328 -42.277710 -15.727089 6111 42.493927 -44.266983 -18.791088 6112 52.211746 -43.165802 -17.643753 6113 58.622086 -44.235367 -18.207428 6114 65.265289 -42.011978 -16.495573 6115 42.037521 -45.121735 -18.685425 6116 63.113373 -44.316757 -17.850983 6117 35.519440 -45.221390 -17.823906 6118 41.555603 -46.472351 -18.865795 6119 63.045105 -45.233093 -17.796303 6120 35.396255 -45.989868 -17.863422 6121 35.237671 -46.523926 -17.849056 6122 35.124001 -48.352325 -18.282982 6123 44.612259 -44.892319 -16.494148 6124 61.539398 -47.954971 -18.166019 6125 35.938477 -49.710663 -19.188919 6126 35.066254 -49.209778 -18.316921 6127 51.145416 -48.070724 -18.313667 6128 54.204605 -47.179611 -17.691780 6129 35.129013 -50.173996 -18.457901 6130 42.405487 -50.454391 -18.787659 6131 42.245712 -49.666901 -17.915802 6132 51.487839 -48.832840 -18.281265 6133 61.204697 -49.933273 -17.537544 6134 61.653305 -48.686371 -17.348774 6135 35.702454 -50.957977 -18.845314 6136 45.904648 -50.991913 -18.930996 6137 51.470947 -50.030533 -18.962250 6138 51.215012 -49.553864 -18.847813 6139 52.117264 -49.729263 -18.664711 6140 36.621780 -51.974396 -19.311977 6141 36.261604 -53.117584 -19.048210 6142 35.419510 -53.937073 -18.363640 6143 36.412567 -54.175720 -19.075195 6144 37.295441 -54.969116 -19.392250 6145 43.514542 -53.505600 -17.939438 6146 43.118988 -52.449127 -16.588669 6147 42.890701 -51.488998 -18.096008 6148 35.862869 -55.055115 -18.643227 6149 42.857422 -51.042114 -16.780304 6150 59.754395 -53.676056 -18.741207 6151 36.976517 -55.936798 -19.049526 6152 38.384155 -55.916656 -19.545540 6153 39.238243 -56.904022 -19.523254 6154 40.959671 -57.834976 -19.572094 6155 43.274155 -56.699615 -19.415737 6156 47.517426 -56.402344 -19.205215 6157 58.209183 -56.536804 -18.849422 6158 58.672180 -55.695831 -17.268543 6159 37.931511 -56.878555 -19.120956 6160 43.927383 -57.021957 -18.480873 6161 43.798569 -56.192307 -17.335373 6162 38.929443 -57.979630 -19.072998 6163 43.121964 -57.561020 -19.304405 6164 44.139938 -58.182693 -18.427452 6165 47.783081 -57.579941 -18.989960 6166 57.537750 -57.826950 -19.105247 6167 57.745789 -57.441910 -19.051579 6168 39.943726 -59.046310 -19.185196 6169 57.179794 -58.383087 -19.129635 6170 41.649139 -59.783401 -19.502857 6171 40.129532 -60.388031 -19.064457 6172 43.115417 -58.777573 -19.280354 6173 43.311081 -59.846863 -19.336224 6174 42.829346 -60.556931 -19.460625 6175 44.286774 -59.545227 -18.509811 6176 56.614136 -59.401398 -18.416664 6177 37.720665 -59.790222 -18.191385 6178 43.090485 -61.458893 -19.088310 6179 43.846329 -60.624359 -18.972370 6180 42.067291 -60.986191 -19.429554 6181 49.371658 -62.055756 -19.244415 6182 37.753304 -60.377563 -18.204424 6183 41.134476 -60.986115 -19.265305 6184 41.667130 -62.213043 -18.985264 6185 37.775024 -61.231735 -18.258963 6186 51.472382 -62.562164 -19.415405 6187 52.608429 -62.684784 -19.070507 6188 53.603897 -62.810425 -18.526283 6189 53.377640 -63.391144 -18.100250 6190 52.392456 -63.958221 -17.502319 6191 53.725739 -62.301331 -18.874908 6192 37.791298 -62.173096 -18.319513 6193 51.023132 -63.764404 -18.104172 6194 49.565765 -63.271011 -18.371872 6195 37.807091 -63.136154 -18.380461 6196 37.822960 -64.103745 -18.441492 6197 37.838882 -65.072189 -18.502443 6198 37.854713 -66.040909 -18.562502 6199 37.869652 -67.009933 -18.615881 6200 37.881386 -67.973236 -18.629839 6201 37.897728 -68.838303 -18.510679 6202 37.937538 -69.397263 -18.288660 6203 37.795937 -69.516632 -18.341333 6204 38.020012 -69.646149 -18.380022 6205 37.880043 -69.828827 -18.339212 6206 8.248337 55.318207 -11.892040 6207 6.297409 53.577576 -11.855045 6208 6.680771 54.616760 -12.137260 6209 6.021225 54.826416 -11.507719 6210 9.323517 54.269806 -12.015705 6211 4.718887 52.526993 -9.127342 6212 5.332245 51.607742 -10.185223 6213 5.719711 52.650192 -10.790833 6214 10.123993 53.765793 -11.724262 6215 10.129181 53.200058 -12.240337 6216 10.995972 53.224258 -11.189087 6217 10.878441 54.204208 -10.164448 6218 10.123863 54.386215 -11.057743 6219 13.371277 51.578003 -11.188042 6220 7.382568 51.780151 -12.296383 6221 13.892876 51.073029 -11.111748 6222 13.889160 50.263000 -12.049818 6223 8.431137 50.336624 -12.431572 6224 9.016861 49.400421 -12.226013 6225 14.085739 49.200531 -12.412357 6226 14.897362 49.681183 -11.590611 6227 9.492188 48.509506 -12.190292 6228 14.564835 50.467926 -11.075470 6229 14.984299 48.565781 -12.020653 6230 9.863457 47.501968 -11.675652 6231 10.107773 46.500504 -12.835510 6232 15.042274 47.718292 -12.146881 6233 14.259933 45.586761 -12.833649 6234 15.404343 45.762634 -12.210957 6235 15.066696 46.763733 -12.270664 6236 10.301994 46.218719 -11.483322 6237 4.236870 43.407089 -12.886833 6238 3.964508 43.911728 -11.729134 6239 4.684395 44.666199 -12.290359 6240 5.591583 44.782852 -12.203259 6241 4.668495 45.435944 -11.824677 6242 15.391800 44.405716 -12.428047 6243 4.740967 44.045624 -12.681915 6244 11.027206 42.088348 -12.666901 6245 7.060600 41.990860 -12.190346 6246 7.073685 44.002518 -11.649982 6247 8.780304 43.214615 -10.621716 6248 8.100151 40.643951 -11.518044 6249 9.512543 40.542404 -10.376896 6250 9.015198 41.803558 -10.633762 6251 15.481628 39.432831 -12.587738 6252 15.464638 40.691284 -12.055733 6253 7.376968 37.934509 -13.177780 6254 12.206398 36.664520 -12.959782 6255 16.138657 37.946594 -13.049843 6256 17.131836 37.106262 -12.817841 6257 19.862503 37.289703 -12.682102 6258 19.413452 38.121719 -12.050312 6259 18.585854 37.400192 -11.986717 6260 20.074524 36.460571 -13.258930 6261 19.896347 35.310226 -13.171494 6262 20.963303 37.566467 -12.783768 6263 21.770218 38.166382 -11.920055 6264 20.536179 38.197601 -12.258293 6265 23.956169 36.060501 -10.674950 6266 23.632690 36.820648 -11.665405 6267 12.437714 35.120407 -12.387684 6268 17.637825 37.295258 -12.072342 6269 18.004135 36.591965 -12.321899 6270 17.665009 36.279892 -12.837372 6271 19.092377 34.852753 -12.751572 6272 19.673080 34.102158 -12.923119 6273 34.605263 35.781067 -12.443336 6274 35.740662 35.155914 -12.676300 6275 35.627609 36.250061 -11.985744 6276 36.283188 35.598679 -12.376030 6277 36.478394 35.862610 -11.560280 6278 2.722176 36.383774 -10.992416 6279 2.689781 35.187531 -11.006695 6280 3.232735 35.522064 -12.497646 6281 32.946373 34.192398 -12.693302 6282 33.885887 34.688156 -12.671928 6283 33.013657 35.853394 -11.844692 6284 35.706383 33.834030 -12.633141 6285 36.222374 33.417511 -12.236443 6286 36.376160 34.580734 -12.421993 6287 36.368484 35.192322 -12.610649 6288 36.597458 35.253571 -12.249817 6289 19.000458 33.911072 -13.223110 6290 25.450760 33.979553 -11.662445 6291 24.855301 35.001129 -11.391003 6292 30.368744 34.051834 -12.742344 6293 30.251953 34.351074 -12.612789 6294 29.541092 34.216934 -12.332855 6295 30.965256 34.253204 -12.600506 6296 32.014908 34.665314 -12.392056 6297 30.212265 34.875885 -12.158257 6298 31.194473 35.132919 -11.864639 6299 31.900248 35.604721 -11.565968 6300 32.033798 35.228668 -11.915131 6301 34.850006 34.107635 -12.718231 6302 33.908554 33.358185 -12.555969 6303 36.629120 34.090561 -11.898241 6304 3.265968 34.088608 -12.624004 6305 3.594864 32.553207 -13.427605 6306 30.752831 33.470032 -12.571644 6307 31.875307 33.592743 -12.688824 6308 32.819916 33.065277 -12.502754 6309 3.215698 31.716064 -12.383541 6310 20.276367 31.921539 -13.851883 6311 26.017006 30.301529 -13.241684 6312 26.261063 32.137756 -12.815117 6313 26.310944 32.498154 -12.047836 6314 36.280907 32.736450 -11.971924 6315 35.280434 32.622620 -12.028877 6316 36.378723 32.386505 -11.565315 6317 36.939377 33.247025 -11.451183 6318 13.557724 32.224899 -12.338734 6319 19.780312 32.283142 -13.795940 6320 26.192375 31.391144 -12.115993 6321 26.279343 30.683197 -12.954475 6322 9.605927 28.604858 -13.672516 6323 14.467392 24.698364 -13.717064 6324 14.136108 23.766464 -14.038651 6325 14.498521 27.970688 -13.403652 6326 25.512550 29.756699 -12.769035 6327 26.029358 30.354202 -12.665924 6328 28.375717 28.292587 -13.284187 6329 27.776352 27.902802 -13.021690 6330 28.073593 27.762878 -13.354717 6331 29.256180 28.780396 -13.210503 6332 28.435989 28.886215 -12.783401 6333 30.536972 29.209641 -12.917694 6334 28.854202 29.195190 -11.772964 6335 32.640198 29.251617 -12.651726 6336 33.847122 29.062286 -12.213711 6337 33.868881 28.987411 -11.265614 6338 24.253494 28.378540 -13.238590 6339 21.963943 28.152405 -14.448364 6340 22.535645 27.707336 -13.958927 6341 24.678551 28.650635 -13.221264 6342 24.963608 29.108246 -13.022728 6343 27.688995 28.263870 -12.318741 6344 29.417892 27.579559 -13.843010 6345 30.262665 28.299194 -13.933304 6346 34.726028 28.976303 -12.012249 6347 3.482857 30.780685 -11.544392 6348 10.966194 24.694016 -11.993210 6349 14.555534 27.010742 -13.508106 6350 23.010208 27.534943 -13.245575 6351 27.910110 26.982437 -13.203747 6352 28.591103 27.187653 -13.660946 6353 36.040115 27.873138 -13.188812 6354 38.069229 27.344345 -12.918404 6355 37.048485 27.432800 -12.923889 6356 37.804367 26.323151 -13.400780 6357 38.873718 27.642822 -12.320961 6358 39.087166 26.517456 -13.086395 6359 37.726028 28.480560 -11.969990 6360 22.233307 26.817154 -13.220104 6361 27.250427 26.597794 -12.475481 6362 27.032547 25.403275 -12.844124 6363 27.583252 25.802582 -13.383984 6364 28.280945 25.851181 -13.976246 6365 40.703705 25.266068 -13.070522 6366 40.032074 25.704468 -13.144691 6367 4.153824 27.849640 -14.225929 6368 4.714233 27.153824 -12.727440 6369 5.366676 26.131592 -12.873329 6370 14.463379 25.405609 -13.937267 6371 14.741745 25.939636 -12.801613 6372 27.327805 27.452469 -12.178818 6373 26.874344 27.578156 -11.346500 6374 6.148499 24.576553 -13.017384 6375 6.114937 24.124313 -13.772442 6376 27.338577 24.633987 -13.895370 6377 36.170891 23.253067 -13.529655 6378 41.165070 24.124451 -13.146919 6379 41.209290 24.792740 -13.098148 6380 41.847351 24.436615 -12.711407 6381 5.930756 23.566956 -13.978062 6382 13.823196 22.481491 -13.812756 6383 14.438423 23.886795 -12.835823 6384 37.568176 23.507019 -13.612358 6385 36.678398 23.486115 -13.458775 6386 36.876419 22.819489 -13.120289 6387 40.070587 23.125671 -13.138695 6388 9.837082 22.468872 -13.229404 6389 9.142616 21.380341 -13.968403 6390 25.322563 23.013916 -12.949436 6391 26.323280 23.615997 -13.636536 6392 38.174751 22.129761 -12.848881 6393 36.794044 22.006989 -12.792198 6394 8.601410 20.350189 -14.192768 6395 12.958023 19.653198 -13.903378 6396 13.373413 20.466980 -12.459274 6397 13.119095 18.878052 -12.325401 6398 8.139946 19.500366 -14.507809 6399 12.743745 18.445694 -13.713661 6400 31.766680 19.349487 -14.158115 6401 35.554680 19.524445 -13.671566 6402 35.905899 20.535477 -13.495159 6403 46.032227 19.501083 -14.263882 6404 12.738464 17.801758 -14.272850 6405 16.767288 18.932114 -15.199379 6406 19.126152 17.420151 -14.240208 6407 30.802917 18.600998 -13.748146 6408 34.797379 18.989746 -13.272099 6409 35.794083 18.548920 -12.716656 6410 36.187378 19.580414 -13.209419 6411 42.782822 18.452805 -14.356750 6412 45.249359 19.138763 -14.078045 6413 46.291733 18.950714 -13.702393 6414 46.852417 18.570633 -13.101070 6415 46.164276 18.565720 -13.211491 6416 47.066406 18.893311 -13.645985 6417 48.212860 18.601959 -12.271275 6418 47.279999 17.938965 -11.852474 6419 49.113312 18.776459 -12.858829 6420 49.130188 18.508728 -12.271091 6421 4.074165 16.101791 -14.532463 6422 7.692008 17.307632 -14.457558 6423 17.408577 17.280960 -14.538910 6424 18.049652 17.821075 -13.392281 6425 17.552719 18.313171 -13.507298 6426 17.262390 18.785614 -14.162945 6427 30.482986 17.834076 -14.130310 6428 43.582199 17.712433 -13.765141 6429 42.263092 16.758286 -14.056629 6430 44.446609 16.856644 -12.953217 6431 43.309143 16.529648 -13.499172 6432 52.020004 17.509842 -12.469021 6433 51.609161 17.722198 -12.631565 6434 7.647064 16.203751 -14.451962 6435 12.933655 17.310089 -14.278912 6436 16.505981 16.852112 -15.102570 6437 18.846725 17.962692 -13.226391 6438 28.285889 16.624695 -13.604416 6439 29.523560 17.575226 -13.766365 6440 30.097488 17.511597 -14.165123 6441 42.442230 15.671783 -13.765335 6442 7.612640 15.156525 -14.337929 6443 13.951370 15.641846 -14.293545 6444 41.594360 14.678680 -14.202751 6445 42.642746 14.661545 -13.638287 6446 7.925552 14.475189 -13.468361 6447 8.254059 15.613983 -13.198444 6448 14.338211 15.103607 -14.198639 6449 5.766739 13.238052 -14.728798 6450 14.685349 14.771240 -14.310272 6451 25.435486 12.829117 -14.336761 6452 25.109222 12.803497 -13.514927 6453 25.641708 13.699478 -13.734154 6454 27.549980 15.107758 -14.012344 6455 6.232300 13.080048 -14.778316 6456 5.965202 12.925491 -14.353680 6457 6.537529 12.862930 -14.319588 6458 6.774506 12.797089 -13.792107 6459 7.053177 13.127899 -13.889721 6460 40.650879 12.400650 -14.900631 6461 19.434311 11.611008 -11.473625 6462 17.900330 12.414627 -12.710617 6463 18.324135 12.505188 -10.883091 6464 17.005569 12.513596 -14.349018 6465 17.611122 11.862946 -14.466736 6466 24.685410 11.270905 -14.462387 6467 25.085358 12.150681 -14.335968 6468 42.053375 13.414490 -13.994144 6469 42.022568 11.895813 -13.982681 6470 43.386658 12.820190 -13.049213 6471 43.542572 14.113373 -13.127634 6472 51.955475 12.208069 -13.781639 6473 18.467865 11.312424 -14.258263 6474 19.510788 10.193268 -15.286369 6475 21.168945 10.495743 -14.790356 6476 20.923370 10.612930 -14.561989 6477 21.146362 10.699066 -14.524021 6478 21.361061 10.576157 -14.531059 6479 19.440201 10.640503 -14.357006 6480 20.439117 10.367462 -14.774803 6481 21.852127 10.188980 -14.602413 6482 23.931938 10.121399 -15.219952 6483 24.073280 10.362305 -14.488674 6484 42.356903 8.833893 -13.119396 6485 51.156067 9.820328 -13.854210 6486 52.823517 10.319107 -12.515701 6487 49.666458 7.329346 -14.125870 6488 56.907349 6.975052 -14.148678 6489 39.077591 6.169647 -15.151722 6490 39.707077 5.242722 -14.580635 6491 40.947327 5.970375 -14.149555 6492 49.841782 6.174667 -13.335876 6493 56.545883 6.697266 -13.435089 6494 57.267624 5.867355 -12.610939 6495 34.426300 5.150421 -14.136787 6496 36.602295 5.222023 -12.846283 6497 38.983124 5.430511 -14.798355 6498 48.638306 4.736351 -13.820503 6499 53.690094 2.831787 -12.851437 6500 54.465286 3.601135 -12.544376 6501 52.668579 2.499557 -13.313240 6502 33.189240 4.872635 -13.588707 6503 34.156311 5.345917 -12.255127 6504 38.977493 4.992249 -14.350384 6505 39.747772 4.533737 -14.102394 6506 31.404747 2.110092 -13.595776 6507 31.507614 1.523239 -15.184013 6508 31.966135 0.817230 -14.891159 6509 59.779739 1.940430 -13.510004 6510 32.516541 0.281799 -15.212433 6511 32.900810 -0.364792 -15.216347 6512 32.210449 -0.608792 -15.013348 6513 45.876709 -1.174728 -14.734982 6514 60.332626 -0.098114 -12.975826 6515 45.773865 -1.008545 -14.190323 6516 46.031281 -2.000839 -14.038391 6517 47.976562 -2.080093 -14.468540 6518 28.924778 -1.588140 -12.761000 6519 28.283379 -1.191324 -11.525181 6520 27.320654 -1.988722 -11.564724 6521 29.849400 -1.320942 -14.088551 6522 30.714880 -0.972548 -14.394125 6523 30.666729 -0.820057 -13.393270 6524 31.275541 -0.821865 -14.694757 6525 50.955322 -0.100311 -13.606201 6526 46.751007 -2.637680 -14.398499 6527 60.569870 -1.620300 -14.218479 6528 28.971104 -1.941025 -14.031292 6529 61.808594 -3.562393 -13.974636 6530 26.430244 -7.915263 -15.919888 6531 26.702307 -6.616620 -15.148115 6532 26.567001 -8.086705 -15.207293 6533 64.185928 -7.028122 -13.575264 6534 64.510803 -7.988358 -13.669411 6535 64.582642 -7.238937 -12.793568 6536 64.178452 -8.925171 -14.739246 6537 26.646139 -9.399642 -15.651850 6538 64.470398 -10.055450 -14.536537 6539 26.819941 -10.648193 -15.419174 6540 65.076416 -10.151642 -13.442280 6541 64.832535 -9.135468 -13.548130 6542 64.775787 -11.286575 -14.107861 6543 28.465948 -13.354665 -15.747501 6544 27.296888 -13.015990 -14.838333 6545 30.895632 -14.560456 -16.028458 6546 31.654581 -14.667002 -16.170128 6547 10.705608 -14.658862 -9.316990 6548 10.613817 -14.260558 -9.276608 6549 10.214460 -14.382064 -8.904090 6550 29.656994 -14.200074 -15.778175 6551 30.341038 -14.517442 -15.759064 6552 31.718878 -15.369773 -15.260178 6553 32.545563 -16.285641 -14.446058 6554 33.458767 -15.296862 -15.547913 6555 35.605911 -14.454315 -16.011578 6556 59.733627 -14.088684 -15.639763 6557 12.299150 -14.435195 -10.157000 6558 11.011809 -13.247964 -9.396138 6559 12.321212 -13.892769 -10.134911 6560 12.893711 -14.350852 -10.337046 6561 13.497293 -14.573208 -10.506208 6562 13.419259 -13.851119 -10.454107 6563 34.776134 -15.615734 -15.082132 6564 33.781845 -15.834476 -14.945982 6565 35.638397 -14.623566 -15.683487 6566 37.088013 -15.207672 -15.824406 6567 37.064758 -15.823700 -15.913765 6568 37.426018 -15.535812 -15.413284 6569 58.932404 -14.785889 -15.785095 6570 59.484299 -14.986404 -15.341003 6571 63.183502 -14.235977 -14.525490 6572 11.320226 -15.516791 -9.592417 6573 11.704693 -16.036182 -9.688728 6574 12.871188 -15.945971 -10.159286 6575 12.751421 -13.344109 -10.207032 6576 13.290807 -15.249043 -10.403976 6577 37.503998 -15.828064 -15.063381 6578 37.125969 -16.341736 -15.145744 6579 9.646183 -15.779394 -8.111624 6580 9.939902 -16.142885 -8.286992 6581 10.035060 -15.231360 -8.659732 6582 12.195214 -16.068949 -9.909398 6583 12.060381 -16.698963 -9.616397 6584 14.023173 -15.852880 -10.479534 6585 14.033916 -16.616547 -10.376101 6586 14.994979 -16.345062 -10.606939 6587 13.948252 -15.053405 -10.575510 6588 26.415039 -17.253403 -17.039127 6589 60.167038 -16.071976 -15.484348 6590 14.697969 -14.953115 -10.693340 6591 15.206610 -15.559459 -10.719652 6592 14.561361 -17.053516 -10.422340 6593 24.032913 -18.760284 -16.248917 6594 23.203255 -18.474197 -16.318855 6595 25.448936 -18.059097 -16.742825 6596 24.787094 -18.589600 -16.547253 6597 26.362770 -18.620804 -16.529114 6598 27.273933 -19.360153 -15.991600 6599 26.051125 -19.405609 -16.101830 6600 35.943069 -18.699844 -15.629555 6601 34.738541 -19.052078 -16.165375 6602 34.666527 -21.046692 -15.047981 6603 33.125732 -20.940598 -15.345825 6604 13.113725 -16.662945 -10.070147 6605 13.638940 -17.303869 -10.120029 6606 14.701826 -17.740274 -10.300709 6607 13.804962 -17.959740 -10.054462 6608 13.072830 -17.778822 -9.819300 6609 22.541138 -19.206818 -16.482864 6610 23.415802 -18.995224 -15.940174 6611 25.452560 -18.921585 -16.386494 6612 25.413666 -19.349854 -16.107140 6613 31.224342 -20.924377 -14.968975 6614 30.092331 -20.688904 -14.759510 6615 36.747009 -18.061188 -14.958458 6616 12.456980 -17.434071 -9.572407 6617 12.508883 -18.217829 -9.397602 6618 24.855759 -19.281235 -16.177582 6619 51.725906 -20.374817 -15.690666 6620 13.205522 -18.180536 -9.791999 6621 14.298812 -18.341612 -10.090427 6622 42.476974 -21.945923 -16.948074 6623 51.066498 -21.305115 -15.587616 6624 51.211014 -20.888000 -15.544853 6625 55.881058 -20.386276 -16.045650 6626 55.300720 -20.934982 -15.273987 6627 56.342102 -21.094254 -15.617630 6628 66.263474 -20.497025 -14.932085 6629 66.524506 -19.234802 -13.768333 6630 66.001083 -19.301819 -14.770802 6631 15.451653 -17.088169 -10.549488 6632 41.508514 -24.791611 -15.771889 6633 42.379211 -25.400955 -15.768837 6634 42.525574 -24.228699 -16.302601 6635 50.727600 -24.225388 -13.898525 6636 51.050186 -23.847870 -13.303928 6637 50.989136 -23.035477 -14.293911 6638 52.700867 -23.543137 -15.933350 6639 58.970901 -22.596786 -15.664928 6640 58.136108 -22.922256 -14.954700 6641 56.360779 -22.055771 -14.921925 6642 13.524673 -18.610270 -9.781533 6643 13.921832 -19.069016 -9.779440 6644 14.338850 -19.433418 -9.710573 6645 14.402586 -18.865221 -9.952782 6646 21.615417 -24.164719 -15.699745 6647 22.187714 -22.690598 -15.602943 6648 22.333832 -22.052994 -16.047951 6649 41.730911 -23.295837 -16.589632 6650 51.043198 -22.056580 -15.183327 6651 51.916534 -22.693909 -16.128689 6652 61.111237 -23.398331 -16.007393 6653 59.923004 -23.676117 -15.029369 6654 66.306702 -22.847656 -15.869816 6655 66.729340 -21.934586 -14.654205 6656 51.337677 -23.089111 -15.306572 6657 61.609360 -24.473969 -15.167355 6658 66.863892 -23.403503 -15.185577 6659 33.145782 -25.622665 -17.204041 6660 54.181915 -24.965561 -15.694908 6661 55.427704 -24.740219 -16.269188 6662 56.037231 -25.972076 -15.947910 6663 66.502777 -24.666061 -15.893127 6664 66.819931 -24.423615 -15.502419 6665 28.812790 -26.439926 -17.243168 6666 28.176804 -27.220016 -16.688591 6667 30.275589 -27.352173 -15.851059 6668 33.970383 -28.002899 -15.771530 6669 40.314056 -26.164795 -15.517456 6670 39.911102 -27.978394 -15.769272 6671 40.278015 -26.967133 -14.995102 6672 57.354706 -25.863724 -16.420647 6673 60.808014 -24.754944 -14.134583 6674 63.545166 -25.540771 -15.876999 6675 62.639709 -25.162140 -15.269276 6676 66.652542 -25.656250 -15.356674 6677 21.679070 -26.397812 -16.806511 6678 21.448540 -27.417465 -15.810770 6679 21.130646 -26.406784 -14.456020 6680 21.308670 -27.797546 -14.950985 6681 58.756958 -28.297699 -16.686028 6682 59.816391 -30.628555 -17.029663 6683 64.112076 -27.382828 -15.431244 6684 65.208405 -27.254349 -15.680550 6685 21.713394 -27.622498 -16.611778 6686 57.013062 -26.695816 -16.093102 6687 57.387268 -27.522400 -16.180649 6688 66.258438 -27.154770 -15.418156 6689 22.032104 -27.931778 -16.761223 6690 23.566559 -28.487183 -15.678410 6691 21.893372 -28.062927 -15.941719 6692 22.565292 -28.443771 -15.486164 6693 24.503418 -28.212524 -16.536655 6694 25.478775 -28.184174 -16.375526 6695 34.701164 -28.735886 -16.036129 6696 34.585648 -28.879333 -15.598839 6697 43.667145 -28.790741 -16.545712 6698 57.155518 -28.452087 -16.241268 6699 57.496353 -29.094986 -16.503944 6700 39.796341 -28.213089 -17.011284 6701 39.352280 -29.693100 -16.740150 6702 43.959839 -29.562775 -16.431587 6703 56.364166 -29.803528 -16.391796 6704 55.770416 -27.809357 -15.798534 6705 57.905029 -30.177002 -16.794945 6706 62.699951 -29.649323 -17.172867 6707 32.639114 -29.982758 -17.448288 6708 33.897110 -30.006714 -16.156723 6709 44.523590 -30.380981 -16.444366 6710 55.349091 -31.673889 -16.457947 6711 54.909027 -30.470093 -15.979851 6712 54.926971 -29.365738 -15.780594 6713 28.518265 -32.147537 -17.296638 6714 29.788124 -31.764877 -16.902428 6715 29.356148 -32.877838 -15.775948 6716 31.872835 -31.983826 -15.702782 6717 31.970476 -33.440948 -14.361126 6718 32.699402 -31.029114 -16.372620 6719 44.095078 -30.198456 -15.940872 6720 44.450195 -30.790985 -15.994202 6721 27.710602 -32.857407 -16.985918 6722 41.835251 -33.240662 -16.940689 6723 41.113739 -34.141327 -17.048996 6724 42.590759 -32.792694 -16.833221 6725 53.368652 -31.259064 -15.189381 6726 53.891251 -30.081146 -15.459232 6727 38.418747 -34.586838 -15.714451 6728 37.670822 -34.505127 -16.877911 6729 43.255402 -32.222046 -16.167686 6730 47.919556 -34.452225 -17.875675 6731 46.458221 -33.572922 -17.458923 6732 25.978683 -33.656067 -16.011349 6733 25.779022 -34.114288 -16.443443 6734 26.657318 -35.691544 -17.012104 6735 44.895111 -33.150848 -16.922089 6736 45.861450 -32.961212 -16.711895 6737 53.172333 -33.037186 -15.217419 6738 54.244598 -32.255463 -15.991390 6739 59.310669 -34.359222 -16.157024 6740 59.459442 -33.256195 -15.197063 6741 58.396957 -33.590927 -15.595551 6742 60.627655 -34.808029 -16.463551 6743 61.402390 -35.119644 -16.555222 6744 61.315491 -34.695251 -15.956657 6745 60.445892 -34.038696 -15.325279 6746 27.618134 -36.748108 -17.195892 6747 37.025345 -35.452759 -17.103813 6748 40.250916 -35.283356 -16.254951 6749 40.737305 -34.455673 -16.189468 6750 40.012787 -34.785187 -15.483681 6751 40.945221 -33.382370 -15.395138 6752 59.629364 -38.143677 -17.003727 6753 58.774567 -37.242233 -16.634544 6754 58.549744 -38.221786 -16.613373 6755 61.866028 -35.478683 -16.212486 6756 61.533081 -36.426331 -16.783066 6757 29.531799 -36.678589 -17.527092 6758 34.743927 -37.673798 -17.051529 6759 35.229202 -37.156876 -16.891491 6760 37.315002 -36.445038 -16.429207 6761 39.668167 -36.100250 -16.496746 6762 39.416412 -36.954895 -17.003441 6763 52.143417 -37.363953 -14.307243 6764 51.996872 -36.270233 -13.526009 6765 52.550919 -35.230957 -14.612129 6766 59.852478 -35.395126 -16.674244 6767 62.271835 -36.432922 -15.632816 6768 61.827057 -35.390137 -15.446598 6769 28.531929 -37.286865 -17.219128 6770 30.413086 -37.219177 -17.068195 6771 30.451569 -36.593140 -17.478226 6772 31.183151 -37.461349 -16.795662 6773 31.989771 -37.587357 -16.924961 6774 36.115204 -37.199265 -16.556377 6775 59.651138 -39.119629 -17.104038 6776 58.367477 -39.349686 -16.610977 6777 59.426971 -36.309387 -16.730042 6778 60.086472 -37.350174 -16.987553 6779 62.772079 -36.919357 -16.344837 6780 62.975082 -37.186737 -16.797642 6781 63.280701 -37.285492 -16.409172 6782 38.453224 -37.827759 -17.253494 6783 39.147102 -37.297363 -17.152386 6784 54.218597 -38.532440 -17.245132 6785 63.747131 -37.642059 -16.549629 6786 32.031570 -38.542068 -16.956516 6787 33.815704 -38.107559 -17.397823 6788 38.549530 -37.097412 -16.467110 6789 37.780380 -37.979385 -16.609409 6790 45.621262 -39.847305 -17.558937 6791 53.455612 -39.361008 -16.885006 6792 53.413391 -38.457016 -16.605251 6793 52.605255 -39.001205 -15.953537 6794 32.223282 -39.918671 -17.762177 6795 45.813889 -40.432007 -17.302296 6796 53.076950 -38.266541 -16.090088 6797 59.430725 -40.108124 -17.147141 6798 33.937088 -42.384155 -17.303886 6799 34.119446 -41.929733 -17.850204 6800 33.470642 -41.527161 -17.753311 6801 42.813126 -41.102875 -16.418564 6802 45.839905 -41.303940 -17.253178 6803 53.702789 -41.761520 -17.931858 6804 64.936554 -40.858032 -16.916782 6805 34.463081 -42.313095 -17.888252 6806 46.036911 -42.768341 -17.786976 6807 52.778778 -41.586792 -17.111282 6808 34.683517 -43.109390 -17.439907 6809 51.184723 -43.341614 -16.750702 6810 51.061768 -45.152725 -17.327477 6811 42.242950 -43.663406 -17.836533 6812 34.699509 -43.887939 -16.053905 6813 35.131157 -44.929123 -16.086582 6814 41.561920 -45.256927 -17.723301 6815 62.317856 -46.026917 -18.191311 6816 44.632339 -46.222137 -16.687943 6817 50.726959 -44.219635 -16.121090 6818 51.332764 -45.851746 -16.426788 6819 55.640701 -46.241211 -17.733635 6820 56.217773 -44.203873 -16.242214 6821 55.585510 -45.244553 -16.575138 6822 63.247116 -45.999115 -17.234924 6823 34.834999 -48.345200 -17.015038 6824 61.964066 -47.930206 -17.347992 6825 62.325638 -47.109985 -17.479366 6826 63.518066 -47.656219 -14.665405 6827 63.251694 -46.802292 -16.371208 6828 62.357605 -47.999084 -16.318922 6829 34.674286 -49.975739 -17.418064 6830 41.590912 -47.726181 -17.941372 6831 41.906509 -48.704849 -16.949802 6832 41.438187 -47.406738 -16.728226 6833 51.464920 -49.618683 -18.572174 6834 45.651978 -49.821457 -17.912640 6835 45.145859 -48.612091 -16.627968 6836 34.966232 -50.852798 -18.044083 6837 46.179169 -51.670441 -17.633984 6838 45.735596 -50.332169 -16.832138 6839 35.276878 -51.892532 -18.251396 6840 60.593872 -52.541473 -17.535233 6841 35.053711 -52.958771 -17.978813 6842 46.694427 -53.113647 -17.995384 6843 46.664978 -52.911972 -17.016056 6844 60.166779 -53.349777 -17.872971 6845 34.530243 -54.672821 -17.287022 6846 35.165520 -55.758331 -18.015564 6847 43.656342 -54.830185 -17.660866 6848 43.424835 -53.899323 -16.856319 6849 59.708344 -54.396713 -17.721642 6850 35.905853 -56.070526 -18.580162 6851 36.600937 -56.854385 -18.684669 6852 37.346771 -57.761749 -18.659084 6853 37.871857 -58.858627 -18.371082 6854 47.472046 -55.908279 -17.325779 6855 47.112442 -54.365128 -17.304817 6856 47.592651 -56.627853 -18.282887 6857 36.295685 -57.561646 -18.297474 6858 35.496681 -56.884827 -17.939606 6859 38.989365 -58.858215 -18.874210 6860 57.289658 -57.645752 -18.254936 6861 57.741531 -56.678925 -17.655312 6862 38.831352 -61.153427 -18.445648 6863 37.636292 -60.096344 -17.866409 6864 37.355133 -61.419693 -17.740797 6865 57.041824 -58.509827 -18.373737 6866 38.958389 -59.704559 -18.687420 6867 56.065659 -60.804352 -18.074314 6868 40.241928 -61.641327 -18.959419 6869 44.157379 -61.471100 -18.639961 6870 44.608353 -61.758682 -18.072315 6871 44.594818 -60.768784 -18.047691 6872 48.657288 -62.325821 -18.489079 6873 47.670532 -61.589020 -17.566410 6874 39.420158 -62.514542 -18.696510 6875 40.433487 -63.399780 -18.862450 6876 39.089806 -63.525589 -18.689716 6877 42.043488 -63.572189 -18.149334 6878 43.619476 -62.474838 -18.146523 6879 55.054138 -62.631241 -17.312840 6880 44.655304 -62.271011 -17.630230 6881 46.610062 -60.281052 -16.594971 6882 46.544891 -61.119324 -16.335979 6883 46.885498 -61.435684 -16.486992 6884 56.413757 -61.781860 -16.577606 6885 56.681793 -60.590729 -17.061493 6886 56.411743 -62.436127 -15.748898 6887 57.026016 -61.375839 -15.915115 6888 39.703583 -64.485992 -18.941498 6889 40.396500 -62.495392 -18.962032 6890 44.437256 -62.618240 -17.409977 6891 48.520844 -62.931595 -17.329895 6892 38.198776 -64.318604 -18.579380 6893 39.209076 -65.332153 -18.965836 6894 50.184509 -64.090454 -17.776848 6895 50.519394 -64.275940 -17.646301 6896 38.000397 -65.656219 -18.551941 6897 39.529968 -66.493546 -19.013817 6898 38.274170 -66.749023 -18.667023 6899 38.918213 -67.574753 -18.800922 6900 41.014038 -64.543549 -18.655598 6901 41.772278 -64.571732 -17.947083 6902 41.291779 -65.503189 -18.082153 6903 40.408051 -65.499054 -18.889091 6904 40.867554 -66.513260 -18.604973 6905 40.473877 -67.120773 -19.034683 6906 40.859451 -67.211578 -18.738453 6907 39.788666 -67.364105 -19.060413 6908 39.675323 -67.772827 -18.755268 6909 40.416016 -67.554276 -18.749557 6910 40.043304 -67.999298 -18.126171 6911 37.906174 -69.696457 -18.177797 6912 6.820664 55.872055 -11.329002 6913 8.260544 56.704788 -10.934402 6914 6.912750 57.428436 -10.084393 6915 8.453957 58.078140 -10.098614 6916 5.621513 56.287384 -9.825600 6917 9.775833 56.858276 -10.235188 6918 5.803543 57.255981 -8.916580 6919 6.536530 58.163712 -8.924789 6920 6.282913 57.891891 -8.034027 6921 5.370110 55.222351 -10.493694 6922 5.320496 54.085968 -10.719408 6923 6.484985 50.972717 -10.958332 6924 7.760948 50.613007 -11.525249 6925 8.443352 49.895248 -11.433109 6926 15.100769 50.136292 -10.629475 6927 9.324768 49.062836 -11.652725 6928 9.002678 49.358871 -11.350086 6929 15.685913 49.036530 -11.414101 6930 15.632248 49.608795 -10.709190 6931 16.273941 48.903931 -10.628922 6932 9.325546 48.582306 -11.077450 6933 14.495140 50.438187 -9.634968 6934 16.242889 47.846939 -11.421379 6935 4.409599 46.432907 -11.214020 6936 5.463921 47.190079 -11.190079 6937 4.317131 47.474731 -10.571953 6938 4.977600 46.360077 -11.660400 6939 5.659935 46.062225 -11.721138 6940 6.471359 46.566040 -11.246201 6941 17.533340 47.308197 -10.445263 6942 16.973351 48.142914 -10.317577 6943 7.091614 45.498764 -11.255302 6944 10.508598 44.726776 -11.149670 6945 17.118629 46.214600 -11.370110 6946 18.351990 46.269638 -10.336300 6947 17.996719 46.730286 -10.452087 6948 18.583679 45.455658 -10.561142 6949 17.771248 44.431122 -11.446236 6950 6.738228 47.288757 -10.901272 6951 7.679702 46.572052 -10.672756 6952 7.992614 47.665558 -10.328690 6953 19.202164 43.500854 -10.865467 6954 19.038185 44.649628 -10.621841 6955 19.417526 44.310944 -10.252205 6956 17.591728 42.783417 -11.649220 6957 19.020073 42.137604 -11.609493 6958 16.351379 43.256470 -11.936153 6959 16.317322 42.324005 -11.774883 6960 16.068062 41.370728 -11.650574 6961 19.911697 42.262009 -11.085735 6962 17.993156 41.678345 -11.705566 6963 3.731155 41.080872 -12.502052 6964 11.316322 41.484909 -11.862900 6965 11.210976 42.603195 -11.634766 6966 17.033127 41.615631 -11.552738 6967 21.025475 40.585602 -10.823627 6968 20.517349 41.621368 -10.727665 6969 20.014648 40.774750 -11.586929 6970 18.729538 41.016083 -11.728340 6971 17.814156 40.477875 -11.496521 6972 11.222244 39.663177 -10.661629 6973 11.708153 38.767807 -11.595951 6974 16.068787 40.364136 -11.277210 6975 18.907974 39.861145 -11.757423 6976 18.178032 38.970413 -11.419373 6977 18.976280 38.829727 -11.753128 6978 7.804367 39.314178 -12.280682 6979 19.850601 39.126953 -11.957821 6980 21.079109 39.299789 -11.661575 6981 21.740326 38.955353 -11.369736 6982 21.598633 39.576920 -10.725620 6983 11.971725 38.159958 -11.933170 6984 12.124100 37.611877 -12.045479 6985 16.794922 37.715591 -12.054214 6986 16.111649 38.395416 -12.007015 6987 22.796066 37.471649 -11.800819 6988 8.598030 37.901459 -11.877728 6989 8.899368 39.436646 -11.069443 6990 18.908356 36.068802 -12.661541 6991 28.564743 36.790863 -11.650230 6992 28.173431 37.271118 -10.947353 6993 27.876823 36.267197 -11.213627 6994 29.010643 36.818008 -11.745483 6995 28.861145 37.226654 -11.363239 6996 29.279663 36.950958 -11.333633 6997 33.496902 37.140747 -11.333858 6998 33.985870 37.734283 -11.148365 6999 33.495987 37.826309 -10.757774 7000 34.059296 36.878418 -11.782814 7001 34.821350 36.805756 -11.835289 7002 34.556076 37.411011 -11.387798 7003 35.261581 37.228699 -10.989784 7004 34.612320 38.055573 -10.780529 7005 9.488403 36.955841 -11.267590 7006 18.129654 35.807144 -12.743458 7007 18.248428 36.101990 -12.371483 7008 23.295135 37.211792 -10.798752 7009 28.385544 35.205017 -11.735157 7010 29.211288 35.948151 -11.760979 7011 29.993805 36.681335 -10.773670 7012 36.558624 36.412033 -10.564564 7013 35.981247 36.612732 -10.968235 7014 35.230652 38.162857 -10.033913 7015 28.124046 34.214355 -11.432209 7016 27.598953 35.431732 -10.964741 7017 30.307129 35.662476 -11.539444 7018 36.799339 34.918533 -11.618500 7019 18.854477 34.326508 -12.610474 7020 19.104965 34.319672 -12.475536 7021 19.197433 34.118454 -12.433220 7022 28.828644 33.400497 -12.055582 7023 32.086678 36.122726 -11.226757 7024 41.507278 34.154510 -11.574989 7025 42.269699 34.362640 -11.534924 7026 41.010132 34.735306 -10.983791 7027 43.517807 35.288361 -11.070557 7028 42.015106 35.866394 -10.875099 7029 43.531097 34.117035 -11.493813 7030 2.981361 32.908569 -11.779713 7031 9.301559 32.946030 -12.661556 7032 9.983299 33.032013 -11.991238 7033 19.080566 34.047043 -12.570755 7034 25.916321 33.126846 -11.660030 7035 27.480469 34.927185 -10.444206 7036 28.334389 33.348190 -11.684120 7037 29.956566 32.916672 -12.191776 7038 36.879715 34.167542 -11.449856 7039 40.301407 31.286880 -10.439590 7040 40.986816 31.561691 -11.132973 7041 40.029556 32.303680 -9.914043 7042 43.042145 33.100006 -11.710701 7043 44.781403 34.263580 -10.940548 7044 44.169739 33.442520 -11.374249 7045 9.779266 31.564804 -12.637856 7046 9.389008 30.046417 -13.451794 7047 26.360352 32.101944 -11.691349 7048 28.958893 32.797684 -11.672314 7049 29.095490 32.345551 -10.685333 7050 28.173340 33.236267 -10.925682 7051 30.265625 32.156158 -11.430458 7052 31.628824 32.416718 -12.017250 7053 37.525192 32.907166 -10.666954 7054 37.469147 33.427002 -10.769600 7055 41.277390 33.322754 -11.290596 7056 44.421295 32.508347 -11.419659 7057 13.936371 31.475082 -12.499268 7058 14.110809 30.915192 -12.605240 7059 33.675041 31.999634 -11.420540 7060 35.885315 31.865540 -10.972622 7061 42.138245 31.212097 -11.776093 7062 41.670105 30.342270 -11.395123 7063 42.397705 29.247955 -11.669476 7064 43.341309 29.297943 -11.794086 7065 43.151382 30.243790 -11.789001 7066 42.080673 32.178848 -11.743309 7067 14.150261 30.050446 -11.940025 7068 14.227188 29.176956 -11.115967 7069 14.529449 28.639664 -12.065453 7070 43.513992 31.591568 -11.775032 7071 44.658340 30.522964 -11.414772 7072 44.889557 31.525803 -11.360748 7073 25.325554 30.283035 -11.617661 7074 41.320709 29.362549 -11.016678 7075 41.783676 28.460541 -11.310669 7076 44.516998 29.223114 -11.413319 7077 27.374878 28.646912 -11.111183 7078 26.754738 28.295486 -10.715763 7079 36.683609 28.387207 -12.293758 7080 35.800140 28.678406 -12.228592 7081 38.592392 28.356400 -11.702057 7082 39.353737 27.986511 -10.922913 7083 43.443512 28.179565 -11.531200 7084 4.196472 30.405579 -10.485600 7085 3.843308 29.675873 -11.177650 7086 23.547249 27.942200 -12.624680 7087 24.356850 28.536545 -12.558350 7088 22.737442 27.257629 -12.368988 7089 27.580109 27.456650 -12.624634 7090 4.006821 28.293396 -13.170948 7091 37.002228 26.597687 -13.288383 7092 40.240631 26.604080 -12.181347 7093 14.677917 25.092102 -11.233467 7094 14.555428 27.014160 -10.844582 7095 14.137733 26.154465 -10.018341 7096 26.447189 25.987625 -11.402843 7097 26.198334 24.367996 -12.282227 7098 40.569305 27.400513 -11.143879 7099 41.225708 25.457214 -12.348797 7100 41.198822 26.397186 -11.506893 7101 5.960205 23.606155 -13.267265 7102 40.603363 25.704773 -12.709469 7103 42.226227 24.578171 -12.460979 7104 42.002808 24.813370 -12.365677 7105 42.317505 24.613022 -12.284985 7106 10.535156 23.307663 -12.113754 7107 25.324005 24.253494 -10.797699 7108 24.850441 23.274231 -11.413342 7109 41.637436 23.676270 -12.296139 7110 42.155975 24.441223 -12.254887 7111 9.516251 21.451859 -13.164707 7112 13.961235 22.145966 -12.210228 7113 13.590668 21.396606 -13.176376 7114 40.731827 22.502869 -12.389301 7115 39.704147 21.656464 -12.424026 7116 23.847015 22.021408 -12.421902 7117 36.088509 21.351105 -13.013607 7118 36.300285 21.638901 -12.828487 7119 40.764465 21.735931 -12.105499 7120 3.505943 21.466003 -12.961567 7121 4.051499 21.799179 -13.439842 7122 3.126465 20.996918 -12.871414 7123 9.202019 20.546585 -13.002243 7124 13.309258 20.685944 -13.384506 7125 22.768982 21.157928 -12.289211 7126 21.860123 20.543030 -11.911385 7127 36.850357 20.933350 -12.704880 7128 8.530502 19.227798 -13.425926 7129 13.476624 18.666260 -10.848454 7130 13.955734 17.237640 -11.584862 7131 21.025009 19.816925 -11.925678 7132 36.560577 20.008896 -12.910828 7133 8.263412 17.860153 -13.442772 7134 8.785408 18.341675 -12.312279 7135 20.565186 19.185944 -12.393589 7136 19.828323 18.959183 -12.184679 7137 29.841614 18.404236 -13.273087 7138 28.937546 18.116333 -12.883274 7139 29.475479 18.954529 -12.475182 7140 30.196289 17.935684 -13.782257 7141 30.328728 18.901367 -12.680401 7142 33.162193 18.617279 -12.132141 7143 32.126038 18.852844 -12.718727 7144 32.373741 18.332550 -11.721428 7145 34.052185 18.782867 -12.567070 7146 36.948563 19.308838 -12.732502 7147 37.024803 18.291885 -12.357857 7148 37.901001 18.795044 -12.401802 7149 38.217026 20.187103 -12.435619 7150 45.208374 18.416489 -13.437565 7151 2.740845 19.692490 -12.880600 7152 2.533150 19.130936 -12.661102 7153 13.064255 17.563187 -13.338215 7154 34.783920 18.409027 -12.466648 7155 39.896896 17.809494 -11.629108 7156 38.257202 17.420227 -11.447777 7157 39.730515 16.755341 -10.861416 7158 44.803589 17.773758 -13.051846 7159 46.040558 18.085449 -12.699570 7160 45.366821 18.044830 -12.868378 7161 50.911194 17.972565 -12.602505 7162 52.880615 16.658646 -12.117893 7163 8.204880 16.759506 -13.453735 7164 13.759590 16.357574 -13.110714 7165 18.385696 19.067596 -12.297478 7166 18.399406 20.194092 -11.954391 7167 18.350586 17.524399 -13.731232 7168 52.332321 17.230026 -12.284090 7169 3.456993 16.658081 -13.226948 7170 14.707794 15.505951 -13.046909 7171 43.647629 15.457703 -13.155243 7172 44.751831 15.882751 -12.519276 7173 44.507294 14.879089 -12.564926 7174 53.418640 16.391006 -11.326359 7175 26.024788 14.655243 -13.488071 7176 25.468842 14.643433 -12.911091 7177 25.894531 15.151520 -13.011391 7178 26.671631 15.472687 -13.222977 7179 5.543655 13.597198 -14.113243 7180 4.913712 14.757431 -13.160500 7181 7.968750 14.008545 -12.714996 7182 7.512978 13.653015 -13.474184 7183 16.348114 14.426407 -12.174278 7184 24.944183 13.610397 -12.414440 7185 5.902283 13.030121 -13.865700 7186 25.128571 14.869904 -12.065727 7187 6.325295 12.849976 -13.792900 7188 19.541046 11.161972 -13.147150 7189 24.781052 11.890335 -13.401005 7190 43.214264 11.556549 -12.910759 7191 21.077377 10.542160 -14.185482 7192 20.254425 10.634735 -13.880524 7193 23.639771 9.878830 -13.824110 7194 22.656342 9.752945 -13.753437 7195 22.483856 8.495590 -12.187435 7196 23.103348 7.909668 -11.751694 7197 23.673492 8.370575 -12.008999 7198 24.533783 10.591583 -13.030754 7199 51.377686 8.504562 -12.972511 7200 52.101761 9.202209 -12.709194 7201 21.683868 10.150467 -13.536385 7202 44.173218 12.116074 -12.280148 7203 43.845230 10.508530 -11.709122 7204 45.003372 10.970871 -10.463135 7205 44.710999 10.238129 -10.199837 7206 42.074524 7.492645 -13.015320 7207 41.428314 5.847412 -13.303936 7208 50.857849 7.392838 -12.946629 7209 50.510284 8.281555 -13.693680 7210 55.899963 6.236404 -12.791023 7211 40.528336 4.740677 -13.923222 7212 50.131256 4.701370 -12.159847 7213 54.877136 5.632187 -13.020462 7214 55.788940 5.400429 -12.214558 7215 55.009766 4.560059 -12.427856 7216 32.465401 4.682541 -12.763065 7217 39.146240 4.414841 -13.576195 7218 37.884026 5.129440 -13.900417 7219 41.770309 5.160553 -12.347580 7220 41.225876 3.965797 -12.837059 7221 39.885468 3.951851 -13.719357 7222 39.565804 3.776917 -13.169617 7223 40.778519 2.702393 -12.915646 7224 40.179153 3.193161 -13.111008 7225 59.272461 3.280792 -13.099434 7226 59.354370 2.770859 -12.374405 7227 46.035477 1.127380 -14.376320 7228 51.904495 1.437683 -13.442337 7229 31.925104 0.400879 -14.025681 7230 32.507965 0.016190 -14.700630 7231 32.340538 -0.600143 -14.197151 7232 31.631052 -0.746525 -14.342554 7233 32.940048 -0.660416 -14.781582 7234 46.551941 -0.758667 -12.732273 7235 48.138275 1.267944 -12.063850 7236 46.807083 1.029922 -13.300419 7237 50.254013 -2.123398 -13.757423 7238 45.949493 -0.072479 -13.878769 7239 47.683868 -3.372452 -14.120583 7240 49.033005 -3.395615 -13.841530 7241 28.143372 -2.685797 -13.042244 7242 28.278896 -2.627169 -13.280703 7243 27.779402 -2.422750 -12.339075 7244 46.183304 -3.119629 -14.070236 7245 45.974915 -3.338638 -13.260468 7246 46.733276 -4.250916 -13.788700 7247 28.398363 -2.588465 -13.732273 7248 27.971567 -3.350722 -14.337713 7249 46.185760 -4.493866 -12.548521 7250 46.334473 -3.638962 -12.011612 7251 48.594147 -4.731766 -13.722366 7252 47.840195 -5.592499 -13.741894 7253 46.748230 -5.708618 -13.738167 7254 27.884590 -3.392767 -13.875214 7255 46.085205 -5.271286 -13.146477 7256 62.993774 -5.154861 -13.664093 7257 27.147688 -4.994178 -14.315788 7258 27.564157 -4.030130 -14.123920 7259 46.621643 -6.900223 -13.661438 7260 46.041702 -7.400024 -13.211929 7261 46.074554 -6.323166 -13.189495 7262 46.730988 -6.385864 -13.762592 7263 47.752258 -6.869751 -13.680695 7264 63.675690 -5.532318 -12.642208 7265 26.856430 -5.940778 -14.383911 7266 26.752766 -6.315549 -14.247126 7267 26.581490 -7.327260 -14.534195 7268 19.327766 -11.272002 -11.310701 7269 18.930225 -10.867723 -11.181973 7270 18.793699 -11.385486 -11.232336 7271 19.580427 -10.625073 -11.254745 7272 19.938742 -11.131351 -11.392309 7273 20.099731 -10.625134 -11.344625 7274 20.298260 -11.431289 -11.490562 7275 23.028639 -11.230378 -12.204351 7276 22.650236 -10.377192 -11.981131 7277 22.439299 -11.264629 -11.999733 7278 23.508579 -10.915526 -12.369677 7279 24.028343 -10.939962 -12.626205 7280 23.892569 -10.113088 -12.476313 7281 23.225594 -9.482929 -12.057402 7282 24.349924 -10.677260 -12.780516 7283 19.195747 -11.773793 -11.348209 7284 18.657963 -11.903247 -11.256897 7285 19.842499 -11.790507 -11.451448 7286 24.409697 -11.861099 -12.883438 7287 24.733747 -10.820936 -13.036028 7288 19.201122 -12.341887 -11.388371 7289 26.896946 -11.752235 -15.044098 7290 26.335743 -10.617568 -14.518074 7291 26.347687 -12.131675 -14.298544 7292 11.643803 -13.097473 -9.727823 7293 12.103236 -13.330989 -9.978638 7294 12.235483 -12.440475 -9.853612 7295 26.785492 -14.852780 -13.346676 7296 26.692442 -13.871634 -13.881781 7297 25.662861 -14.213778 -13.109894 7298 9.878343 -13.430655 -8.548508 7299 9.487645 -13.740293 -8.220139 7300 9.695394 -14.380961 -8.433320 7301 10.369701 -13.454281 -8.982624 7302 10.628010 -13.834867 -9.243067 7303 12.967417 -12.531683 -10.135994 7304 13.402512 -13.110530 -10.363200 7305 28.558022 -14.160269 -14.927143 7306 30.953671 -14.996873 -15.438194 7307 31.266689 -15.966475 -14.465868 7308 66.300934 -15.082916 -12.312534 7309 66.522476 -14.289093 -11.224815 7310 66.079285 -14.031876 -12.256905 7311 14.060821 -13.461089 -10.542370 7312 14.082623 -14.318154 -10.614063 7313 27.380184 -14.527324 -13.876570 7314 27.604610 -13.954852 -14.412159 7315 28.136236 -14.683081 -14.210110 7316 29.502205 -14.947213 -14.786045 7317 30.510437 -15.176856 -15.016996 7318 30.378736 -14.747107 -15.477587 7319 33.821514 -16.707191 -14.119764 7320 34.321987 -16.131483 -14.625267 7321 35.529797 -15.160635 -15.406607 7322 36.448715 -15.171066 -15.110146 7323 35.591221 -15.656853 -14.874229 7324 36.396042 -15.585632 -14.678875 7325 37.105865 -15.151611 -15.291317 7326 37.441116 -15.497650 -15.025795 7327 60.120224 -15.295288 -14.918850 7328 10.667315 -15.323494 -9.178053 7329 14.743276 -14.111987 -10.701536 7330 27.865526 -15.264556 -13.626804 7331 28.874760 -15.417414 -14.023266 7332 29.668348 -15.843984 -14.025068 7333 30.283842 -15.632460 -14.455526 7334 30.405714 -16.285688 -13.897352 7335 33.264172 -17.537392 -13.399178 7336 37.005341 -15.498047 -14.823692 7337 34.749092 -17.892746 -16.930096 7338 59.902878 -15.752792 -14.835358 7339 60.814423 -15.730194 -14.719139 7340 62.061478 -15.969955 -14.841412 7341 62.976273 -15.040695 -14.399452 7342 15.716690 -14.497811 -10.829611 7343 36.858337 -17.161377 -15.140953 7344 60.187531 -15.971588 -14.947697 7345 11.177047 -16.238991 -9.290932 7346 16.222702 -16.141888 -10.779943 7347 63.965897 -15.828110 -14.321743 7348 65.798279 -18.102112 -14.368160 7349 65.722534 -16.392471 -13.505905 7350 10.670877 -16.014236 -9.035501 7351 11.599689 -17.403536 -9.076159 7352 23.767075 -19.402496 -15.741291 7353 36.467972 -19.380875 -14.861221 7354 10.507067 -16.546249 -8.669388 7355 11.144543 -16.959717 -8.965445 7356 11.893365 -18.546610 -8.881327 7357 12.348742 -18.768169 -9.161729 7358 11.538720 -18.078423 -8.718241 7359 23.394730 -20.192566 -15.656189 7360 24.431969 -19.800751 -15.757111 7361 25.195877 -20.381836 -15.401855 7362 24.317688 -20.497940 -15.290081 7363 25.372673 -19.738632 -15.835148 7364 26.253418 -20.152756 -15.653698 7365 26.515930 -20.716721 -15.438835 7366 27.397194 -20.403275 -15.236282 7367 28.885681 -20.779770 -14.494698 7368 27.489357 -21.186386 -14.414803 7369 35.531967 -19.768539 -15.394215 7370 37.021111 -19.597229 -14.396885 7371 36.715775 -20.086868 -14.393066 7372 51.608276 -21.519272 -14.715160 7373 15.687138 -18.051327 -10.346816 7374 15.071918 -18.532440 -10.152657 7375 22.971786 -21.409607 -15.199638 7376 22.602600 -22.083267 -15.415241 7377 25.918152 -20.930817 -15.252312 7378 26.993706 -22.063446 -13.613152 7379 26.244141 -21.620499 -14.550156 7380 35.915749 -20.538315 -14.706242 7381 35.674583 -22.008698 -14.004875 7382 54.116211 -20.671875 -15.007481 7383 26.671585 -21.062073 -15.095055 7384 52.897324 -20.843582 -14.793781 7385 52.554688 -20.058640 -15.280193 7386 12.915145 -18.849405 -9.454062 7387 12.441864 -19.239206 -9.017167 7388 12.951125 -19.254444 -9.339331 7389 13.532471 -19.330198 -9.528641 7390 11.392982 -18.815737 -8.269971 7391 11.945303 -19.014595 -8.735903 7392 12.975876 -19.574842 -9.178434 7393 52.986877 -24.735764 -15.425343 7394 51.882263 -24.320648 -15.108898 7395 57.048157 -23.833466 -13.657883 7396 59.782990 -24.358536 -13.924934 7397 58.668915 -23.970993 -13.982422 7398 67.266434 -22.902588 -13.895599 7399 67.265793 -24.429779 -14.487411 7400 40.762100 -26.304184 -14.886894 7401 53.517029 -25.748795 -15.167679 7402 33.117500 -27.213089 -15.678028 7403 43.092773 -28.835159 -15.706291 7404 43.440582 -29.902847 -15.608650 7405 54.509094 -26.629883 -15.307064 7406 54.734207 -25.593109 -15.640968 7407 63.013260 -26.439163 -14.844955 7408 67.492538 -26.035400 -13.904011 7409 66.793579 -27.099854 -14.811211 7410 30.312088 -29.503174 -13.779522 7411 40.313782 -27.865097 -14.823765 7412 42.129303 -27.371689 -15.262936 7413 54.327988 -28.523254 -15.388092 7414 27.261765 -28.436447 -15.394104 7415 65.783600 -27.445404 -15.569187 7416 24.605209 -28.592407 -15.359135 7417 25.560097 -28.670807 -15.086594 7418 26.525452 -28.848557 -14.740646 7419 27.727684 -29.148453 -14.354042 7420 42.437714 -28.783432 -14.949348 7421 54.107010 -27.679367 -15.150536 7422 62.891327 -28.057312 -14.800301 7423 63.809631 -29.232468 -15.267937 7424 67.191803 -27.580963 -13.884026 7425 65.892365 -28.496796 -14.982029 7426 67.039474 -28.462234 -13.902985 7427 34.684067 -29.198227 -15.756168 7428 39.347160 -30.319092 -15.606255 7429 53.703491 -29.259583 -15.205055 7430 62.103729 -29.964722 -14.865891 7431 34.458176 -29.530899 -15.771935 7432 45.690018 -32.394592 -16.575687 7433 63.527176 -30.283401 -15.351955 7434 61.346405 -31.369247 -14.629623 7435 61.387466 -32.520981 -14.236416 7436 62.914322 -32.284805 -14.963810 7437 64.927200 -30.493134 -15.259254 7438 33.570892 -31.139282 -15.057041 7439 45.032883 -32.529724 -16.400894 7440 44.189941 -31.534805 -15.887260 7441 52.453949 -29.629440 -14.412781 7442 63.593079 -31.133591 -15.297565 7443 66.297409 -30.264450 -14.521675 7444 65.842194 -31.396851 -14.817486 7445 64.761993 -32.280655 -15.157829 7446 27.286491 -33.476135 -15.762505 7447 28.447937 -34.355469 -14.561905 7448 26.916977 -34.598846 -14.452431 7449 30.055344 -34.250473 -14.380898 7450 31.413437 -34.903748 -13.666851 7451 38.768127 -32.210114 -16.017242 7452 41.461060 -33.373703 -16.204323 7453 42.256119 -32.728867 -16.334511 7454 42.013138 -32.142090 -15.573158 7455 44.216614 -32.298798 -16.085213 7456 25.463043 -34.161438 -16.031464 7457 40.716888 -31.927231 -14.659256 7458 45.506393 -33.265732 -16.866528 7459 58.584015 -31.619446 -14.605972 7460 58.404449 -32.573257 -15.005310 7461 59.413269 -32.380600 -14.537640 7462 63.562729 -33.183517 -15.116253 7463 64.030060 -32.999969 -15.312004 7464 64.707642 -33.301514 -15.196995 7465 25.482315 -35.175903 -16.201130 7466 24.940598 -35.048019 -15.373699 7467 24.687790 -35.775009 -15.209637 7468 57.691483 -34.822342 -15.833511 7469 64.151352 -33.585510 -15.042900 7470 64.793152 -33.758682 -14.890240 7471 24.993607 -36.698547 -15.739422 7472 37.774132 -35.383209 -16.306099 7473 40.289307 -33.412796 -14.869110 7474 56.853455 -36.170334 -15.672504 7475 58.052032 -36.186691 -16.266457 7476 57.496704 -38.213318 -16.165092 7477 56.588562 -37.229767 -15.624413 7478 56.481354 -38.179962 -15.618576 7479 58.765381 -35.375549 -16.401176 7480 61.166412 -34.800415 -14.795818 7481 25.836823 -36.627136 -16.341118 7482 26.666550 -37.402145 -16.643799 7483 25.618088 -38.035751 -15.903595 7484 26.622383 -38.840485 -16.158806 7485 27.818817 -38.234253 -16.791168 7486 29.291199 -38.108536 -16.918266 7487 30.670494 -38.296173 -16.646820 7488 31.442375 -37.889221 -16.655937 7489 32.958298 -37.295578 -17.405785 7490 32.836205 -37.923630 -17.085793 7491 57.305664 -39.006775 -16.116737 7492 56.435364 -39.133514 -15.633366 7493 57.649078 -37.220047 -16.174095 7494 62.461029 -37.109436 -15.189171 7495 63.198624 -37.449341 -15.494530 7496 28.599182 -39.714874 -16.479733 7497 28.570740 -39.121185 -16.663742 7498 27.729256 -39.695465 -16.285168 7499 31.790987 -39.534958 -17.091766 7500 32.991302 -38.360321 -17.206280 7501 37.723396 -38.328720 -16.984013 7502 57.409088 -39.984238 -16.196339 7503 56.272751 -40.142349 -15.542686 7504 64.347198 -37.888016 -15.700245 7505 64.758041 -38.425278 -14.881886 7506 63.975830 -38.022629 -14.661507 7507 35.206848 -38.462921 -17.533813 7508 35.393974 -37.688507 -16.712368 7509 45.325958 -40.447311 -16.805649 7510 52.057281 -40.335846 -15.861897 7511 65.315247 -39.223175 -15.298569 7512 28.704880 -40.326080 -16.316528 7513 29.555923 -39.501572 -16.543388 7514 30.242142 -40.438446 -16.699165 7515 30.995674 -39.467316 -16.714878 7516 29.462212 -40.391556 -16.457050 7517 29.337440 -41.203583 -16.403969 7518 31.444412 -40.573273 -17.079510 7519 32.230606 -40.534897 -17.475834 7520 43.735748 -40.408401 -16.516819 7521 44.526886 -40.466034 -16.317902 7522 65.808411 -41.078949 -15.484737 7523 65.511734 -40.078735 -16.036709 7524 30.459915 -41.457001 -16.830776 7525 29.869713 -42.120956 -16.454445 7526 30.526817 -42.144028 -16.781036 7527 31.313202 -42.036636 -16.794960 7528 32.329201 -41.280533 -17.302162 7529 32.711136 -42.544724 -16.567844 7530 42.090378 -41.910568 -16.487949 7531 41.927094 -42.774857 -17.003841 7532 44.886230 -41.505447 -16.117348 7533 45.558548 -42.153763 -16.856815 7534 51.781204 -41.877701 -16.513870 7535 57.038132 -41.378357 -16.045307 7536 65.784454 -40.042252 -15.107506 7537 65.993744 -41.908295 -14.828857 7538 41.402252 -42.959335 -16.431286 7539 56.785263 -42.965179 -16.152508 7540 30.494995 -42.612701 -16.323788 7541 31.267944 -43.076370 -15.703152 7542 41.620850 -43.802246 -17.183235 7543 41.211365 -44.316742 -16.924011 7544 40.894043 -44.162918 -16.259087 7545 45.200775 -42.936783 -16.641403 7546 50.751785 -41.762436 -15.256310 7547 41.919006 -41.634064 -15.448044 7548 40.853424 -43.137207 -15.313519 7549 44.785126 -43.843430 -16.317875 7550 50.727600 -43.088486 -15.944817 7551 63.876953 -45.083344 -17.000023 7552 35.270844 -45.464111 -17.058807 7553 40.650421 -44.965485 -15.318062 7554 41.162231 -45.710129 -16.710361 7555 44.208679 -44.048264 -15.217201 7556 51.029373 -44.901459 -15.559914 7557 35.123962 -46.592056 -17.303673 7558 54.453476 -45.855072 -16.529099 7559 55.481506 -44.674332 -15.981209 7560 63.867706 -45.930283 -16.578579 7561 64.379547 -45.403168 -16.231377 7562 52.099487 -44.662003 -14.431007 7563 51.324890 -44.407806 -14.496178 7564 51.904373 -45.371475 -15.345837 7565 52.877548 -46.212662 -16.220009 7566 51.897598 -46.984970 -16.964554 7567 53.976135 -44.827652 -15.388523 7568 64.015518 -46.319366 -15.871719 7569 51.563934 -47.810547 -17.707684 7570 41.550110 -47.937439 -16.112671 7571 41.996384 -48.985001 -16.012907 7572 44.839340 -47.295120 -16.812164 7573 44.801743 -48.276978 -14.855583 7574 45.436493 -49.922302 -15.767445 7575 61.390396 -50.732697 -16.707096 7576 61.512787 -50.954407 -15.723679 7577 61.796417 -49.421265 -16.128170 7578 42.420685 -50.010529 -16.964104 7579 45.239349 -49.614151 -14.768345 7580 45.805878 -50.891663 -14.958439 7581 34.493988 -51.045990 -17.067833 7582 42.489410 -50.227859 -15.881226 7583 42.895493 -51.229172 -16.031918 7584 34.414612 -52.196503 -17.048447 7585 46.179611 -51.711365 -16.179810 7586 61.000931 -51.953720 -16.659634 7587 34.444893 -52.968750 -17.148338 7588 60.351791 -53.486832 -16.655685 7589 60.338745 -53.678360 -15.783215 7590 60.564743 -53.309357 -15.711552 7591 34.615723 -53.578842 -17.394970 7592 60.916626 -52.421265 -15.522562 7593 46.859283 -53.508698 -16.017891 7594 53.668549 -54.052429 -16.325832 7595 53.173981 -54.912567 -15.756119 7596 52.987244 -53.725906 -15.730335 7597 54.441086 -56.285263 -17.081482 7598 53.898819 -55.190781 -16.654461 7599 54.738693 -54.472351 -16.496666 7600 59.640030 -54.658386 -16.770733 7601 34.358536 -56.139877 -16.891739 7602 43.941956 -57.628174 -17.089073 7603 57.154556 -55.472748 -16.559238 7604 56.347900 -54.062393 -15.926273 7605 58.524170 -54.201477 -15.455082 7606 55.761826 -55.734009 -16.939873 7607 56.720627 -56.726166 -17.321789 7608 59.094971 -55.044937 -16.240425 7609 59.795746 -54.164734 -15.938263 7610 35.466629 -58.001144 -17.427055 7611 35.827972 -57.723114 -17.982941 7612 34.865540 -57.150101 -17.032833 7613 43.877777 -56.794205 -16.852383 7614 47.438477 -57.472931 -17.472492 7615 47.102112 -56.225922 -16.227463 7616 54.442200 -57.200592 -17.248127 7617 54.119568 -57.064575 -16.945267 7618 55.242920 -57.142075 -17.267113 7619 56.118622 -57.794357 -17.263401 7620 57.682236 -56.151031 -16.989746 7621 58.654907 -55.543945 -16.404520 7622 53.686752 -56.305267 -16.479321 7623 36.478432 -58.293381 -18.054428 7624 44.386765 -58.888672 -17.541924 7625 46.702667 -57.481186 -16.338577 7626 54.605560 -57.500885 -16.997410 7627 55.200043 -57.680695 -17.093014 7628 56.790985 -58.441376 -17.847393 7629 56.801010 -58.662949 -16.995857 7630 36.333450 -59.539703 -17.301926 7631 35.240036 -58.747604 -16.674858 7632 36.977798 -59.987106 -17.447220 7633 44.502747 -59.829041 -17.447723 7634 56.795914 -59.554855 -17.462776 7635 57.693542 -58.074097 -15.393963 7636 56.852356 -57.879501 -16.275089 7637 44.438599 -60.634415 -16.865311 7638 56.973679 -59.582932 -17.005051 7639 44.747650 -61.645996 -17.209770 7640 37.945129 -62.707291 -18.273849 7641 47.630844 -61.977356 -15.994568 7642 36.792320 -63.526321 -18.012100 7643 36.763817 -62.400391 -17.713541 7644 43.858383 -62.620972 -16.950737 7645 44.515289 -62.584259 -16.992847 7646 36.956207 -64.663406 -18.160362 7647 35.813156 -64.166107 -17.464794 7648 42.100998 -64.178452 -17.567890 7649 48.710022 -62.685562 -15.883644 7650 49.099579 -63.579590 -17.591713 7651 49.619141 -63.882401 -17.564022 7652 53.476105 -63.930435 -17.059406 7653 54.093414 -64.060791 -15.904655 7654 37.159882 -66.615662 -18.128860 7655 37.719604 -67.684097 -18.366795 7656 36.521309 -67.675491 -17.665062 7657 37.026169 -69.052582 -18.017239 7658 36.447639 -65.541306 -17.782860 7659 35.573898 -66.738876 -17.293331 7660 40.997910 -66.605179 -17.971180 7661 40.783600 -67.309540 -17.971333 7662 41.128799 -66.229828 -17.981953 7663 38.465408 -68.818512 -18.327370 7664 39.290428 -68.139786 -18.418919 7665 37.783081 -69.750504 -18.402412 7666 39.404396 -68.549698 -17.948021 7667 37.394928 -70.542908 -18.130116 7668 37.887573 -70.353729 -18.465076 7669 38.699417 -70.538239 -17.381470 7670 38.972893 -69.961105 -17.455080 7671 38.488098 -70.143646 -18.164394 7672 39.174072 -69.217133 -17.530540 7673 38.105522 -70.784500 -18.354538 7674 38.425636 -70.946259 -18.004833 7675 37.237968 -71.801285 -17.203445 7676 37.976822 -71.210403 -17.968861 7677 8.275238 59.155670 -9.354610 7678 9.195908 58.907074 -9.727165 7679 9.279526 59.723251 -9.022892 7680 8.404793 59.724625 -8.188423 7681 7.603897 59.272766 -8.632668 7682 7.344299 58.632736 -9.248302 7683 9.782509 58.109467 -9.898655 7684 10.450333 58.999359 -9.212761 7685 10.842819 59.967987 -8.451782 7686 10.086510 59.854065 -8.899796 7687 9.338333 55.588196 -11.038074 7688 10.466049 55.233978 -10.103233 7689 10.984055 57.407227 -9.444099 7690 10.885796 56.135742 -9.627190 7691 10.878685 54.652618 -9.703117 7692 4.766876 53.498657 -9.535587 7693 4.644615 54.494720 -9.348103 7694 11.459793 53.473892 -9.967285 7695 12.176331 52.525726 -10.295868 7696 11.940567 52.927612 -8.941116 7697 12.623779 51.858307 -9.175674 7698 13.387497 51.567749 -10.195423 7699 8.461899 49.194550 -10.742302 7700 5.293427 50.518997 -10.170776 7701 6.170761 49.458954 -10.611389 7702 7.495499 49.812729 -10.824459 7703 15.931717 49.251953 -9.665386 7704 16.485886 48.646667 -9.557640 7705 4.800385 49.467133 -9.970459 7706 5.109917 48.430054 -10.591118 7707 6.465126 48.181824 -10.743980 7708 15.402679 49.742859 -9.677063 7709 4.540466 50.260345 -9.251656 7710 8.734390 48.347931 -10.393475 7711 7.541847 48.763779 -10.507721 7712 9.992607 46.908249 -10.689087 7713 9.468857 47.711182 -10.462452 7714 3.816383 46.495056 -10.245140 7715 3.780403 47.491272 -9.731937 7716 9.197021 46.712601 -10.096878 7717 10.107666 45.874451 -10.356346 7718 3.870957 45.270233 -10.700668 7719 3.700417 44.054352 -10.225281 7720 8.826096 45.675217 -10.178471 7721 8.904320 47.864532 -10.135021 7722 10.797867 43.883392 -10.958942 7723 11.007027 43.310516 -11.014111 7724 19.438843 43.800522 -9.453362 7725 10.973351 42.404785 -10.769062 7726 3.730438 42.030441 -11.400703 7727 11.184845 40.945786 -10.830872 7728 3.830368 41.429489 -10.446728 7729 3.746719 42.796570 -10.078796 7730 3.854248 40.639648 -11.359669 7731 8.746339 44.562958 -10.442978 7732 16.794266 40.546906 -11.270111 7733 3.923531 39.844345 -11.341892 7734 3.863052 39.450592 -11.299576 7735 11.454567 38.697479 -10.651230 7736 15.726990 39.862076 -11.530640 7737 17.194939 39.313431 -11.098522 7738 10.249466 39.625488 -10.161640 7739 9.575600 39.525787 -10.363049 7740 10.064613 38.246597 -10.517899 7741 15.994354 39.094803 -11.411011 7742 16.535736 39.816483 -10.964039 7743 21.967758 38.742157 -10.769024 7744 3.540375 38.975327 -11.046860 7745 11.976883 36.911621 -11.400692 7746 11.743027 37.930756 -11.156841 7747 18.193268 38.071030 -11.416309 7748 18.683746 38.221085 -11.664467 7749 22.414871 38.064697 -10.929504 7750 22.839630 37.683304 -10.922352 7751 33.939560 38.556854 -10.480659 7752 34.732216 39.087769 -10.098721 7753 11.289238 36.033295 -10.865738 7754 12.128906 35.955811 -11.618172 7755 16.805923 38.411728 -11.275898 7756 16.451233 39.191040 -10.979958 7757 17.644516 37.782562 -11.522663 7758 23.463837 36.845428 -10.093346 7759 26.912811 37.085526 -9.836151 7760 27.901154 37.984985 -10.182240 7761 30.216400 37.005280 -10.012917 7762 29.832123 37.376999 -9.900879 7763 33.028870 37.145432 -10.805229 7764 42.114517 37.328400 -9.947285 7765 43.149536 36.638428 -10.558075 7766 43.104828 37.337143 -10.078373 7767 41.308105 36.721252 -10.372646 7768 40.625229 37.182068 -9.511475 7769 43.973175 37.168610 -9.895435 7770 45.114349 37.403168 -9.220871 7771 44.105804 37.921844 -8.864952 7772 2.416168 37.240387 -9.806259 7773 2.986084 37.858490 -10.615818 7774 2.306252 36.304749 -9.742504 7775 2.405655 35.635101 -9.722061 7776 17.981918 36.140167 -12.367550 7777 27.324677 38.015030 -9.873974 7778 26.826538 38.208847 -9.456230 7779 29.047150 37.797958 -10.260021 7780 31.157806 36.067291 -11.105038 7781 31.808794 36.552414 -10.664894 7782 30.996193 36.970154 -9.997532 7783 32.494598 36.567810 -10.904144 7784 36.995026 35.698349 -10.620941 7785 39.712524 37.379684 -8.477661 7786 39.003174 36.675476 -8.100235 7787 39.615417 36.334808 -9.209438 7788 44.121506 36.241119 -10.550121 7789 11.245193 34.227844 -11.148006 7790 10.657043 33.454712 -11.418644 7791 12.940903 33.114990 -11.600605 7792 27.244392 36.122971 -10.586716 7793 37.176910 34.329895 -10.721203 7794 37.152924 35.350616 -9.796940 7795 40.632080 36.067810 -10.323338 7796 45.017242 36.563599 -9.975883 7797 44.941895 35.510498 -10.506302 7798 46.140518 36.146210 -9.522614 7799 11.782394 35.039001 -11.149174 7800 12.237442 33.996643 -11.402382 7801 19.001480 34.162231 -12.354847 7802 39.811913 35.287018 -9.806454 7803 39.815613 33.986160 -9.868717 7804 45.997192 34.793030 -10.096001 7805 2.830856 34.088364 -11.143259 7806 10.375694 36.743057 -10.736092 7807 13.244415 32.100449 -11.344315 7808 24.803955 34.163971 -10.399433 7809 24.353241 34.904007 -10.276596 7810 25.971954 32.281433 -11.188364 7811 37.570557 33.495560 -10.032646 7812 37.268631 34.373077 -9.710785 7813 45.069031 33.219467 -11.033806 7814 46.010651 33.576385 -10.383389 7815 25.503738 32.224915 -10.422546 7816 25.265350 33.077026 -10.377983 7817 37.017120 32.376877 -10.798912 7818 45.850189 32.304794 -10.728142 7819 46.058411 30.982010 -10.664783 7820 47.115845 34.276886 -9.478191 7821 47.048080 32.903000 -9.648281 7822 2.914803 32.067734 -11.697308 7823 3.015831 31.600525 -11.664089 7824 12.170959 29.115356 -11.031521 7825 13.829034 31.298615 -11.869984 7826 24.421272 29.097183 -11.646782 7827 31.534317 31.573578 -11.000736 7828 30.628288 31.696808 -9.878773 7829 34.909027 31.813477 -11.345570 7830 34.873276 31.498932 -10.714672 7831 32.449417 31.525665 -11.107422 7832 37.312843 33.003632 -8.853851 7833 37.597153 33.258331 -9.403294 7834 37.494339 32.747345 -9.927811 7835 40.201782 31.065826 -10.009346 7836 47.070023 31.725433 -9.654343 7837 32.210434 31.249420 -10.698368 7838 35.697449 31.447189 -10.119221 7839 40.698166 30.293396 -10.343060 7840 46.122879 29.805435 -10.610844 7841 29.457001 29.462234 -9.911377 7842 27.939400 29.260025 -10.336113 7843 31.057137 29.352112 -10.999786 7844 32.666534 29.169800 -11.036442 7845 34.997147 29.234726 -11.365162 7846 34.930878 29.340591 -11.163036 7847 34.690781 29.150208 -11.165604 7848 35.141731 29.276840 -11.143368 7849 37.798218 29.120956 -11.342216 7850 37.665306 29.321350 -11.133556 7851 37.476685 29.128082 -11.310188 7852 37.835266 29.171021 -10.995140 7853 46.219635 28.513733 -10.584244 7854 45.041260 27.714935 -11.154602 7855 47.410797 30.625229 -9.214745 7856 47.622498 31.530975 -8.740173 7857 10.493896 28.394714 -12.772934 7858 12.415733 31.998459 -10.836891 7859 11.683029 33.115677 -11.044537 7860 35.556686 29.072327 -11.036320 7861 36.850113 28.914917 -11.285603 7862 38.264343 28.751450 -11.129532 7863 40.543274 28.104355 -10.167133 7864 39.757462 27.674301 -9.412743 7865 41.133392 28.529205 -10.796219 7866 42.468399 28.410263 -11.544800 7867 6.010361 26.725616 -11.214722 7868 11.185898 28.232315 -11.945450 7869 11.353104 27.040482 -11.837017 7870 14.756058 27.458069 -12.109955 7871 22.293976 27.200348 -11.367634 7872 22.872536 27.692535 -11.602814 7873 23.536575 28.190231 -11.661995 7874 42.439285 27.611618 -11.348026 7875 45.605164 26.049927 -10.822571 7876 44.313965 26.853165 -11.271595 7877 46.317017 27.343597 -10.480656 7878 6.582893 25.504486 -11.108955 7879 6.254776 25.144882 -11.943085 7880 4.018128 28.929993 -12.012951 7881 11.307404 25.878326 -11.834293 7882 14.959053 26.798798 -11.789059 7883 43.329422 26.669586 -11.302628 7884 42.352661 26.408722 -11.178341 7885 41.439423 27.445831 -11.023556 7886 47.537003 29.227356 -9.315083 7887 14.937088 26.296021 -11.652710 7888 44.239716 25.705170 -11.172779 7889 6.120171 24.007416 -12.157120 7890 11.079544 23.838928 -11.075401 7891 41.718277 26.337784 -11.209431 7892 42.058395 24.986404 -11.667240 7893 42.231033 24.684937 -12.087368 7894 44.302460 24.089249 -11.253284 7895 44.061874 24.670990 -11.274750 7896 43.509720 23.678070 -11.182026 7897 43.188705 25.204468 -11.214336 7898 44.793579 24.763367 -11.174667 7899 45.482086 24.663544 -10.937191 7900 6.499725 24.572113 -11.042709 7901 10.183044 22.373260 -12.208046 7902 10.353271 22.142792 -11.166843 7903 14.458893 23.468521 -11.669113 7904 42.173981 23.931580 -11.643570 7905 44.773697 23.607758 -10.722710 7906 45.906067 24.159134 -10.664333 7907 4.517258 22.761536 -10.864407 7908 5.839256 23.643723 -11.129498 7909 5.668213 23.504135 -10.074196 7910 14.130257 22.637268 -10.580399 7911 14.537888 23.711304 -11.003086 7912 25.702545 25.066437 -10.767982 7913 42.446289 23.285431 -11.615417 7914 41.590500 22.537964 -11.971531 7915 42.428696 22.415161 -11.579262 7916 43.066940 22.899445 -11.442944 7917 46.204956 24.923233 -10.641472 7918 3.259552 21.147995 -11.680393 7919 2.934349 20.423584 -12.624783 7920 9.827660 21.564392 -12.375259 7921 13.674561 20.659027 -10.715309 7922 41.562653 21.484039 -11.714077 7923 43.111160 22.469742 -11.241776 7924 43.419357 22.887146 -11.183064 7925 18.575653 21.538025 -12.146091 7926 23.844337 22.519241 -11.008739 7927 22.993584 21.863800 -11.146297 7928 30.044044 20.648499 -11.287346 7929 30.340240 20.294510 -11.289024 7930 29.874588 20.276367 -11.547817 7931 40.329956 20.427368 -12.036922 7932 39.150002 18.900574 -12.073711 7933 41.346649 20.507202 -11.679562 7934 42.655441 21.638550 -10.996635 7935 9.162224 19.455780 -12.018616 7936 9.645950 20.609894 -11.574268 7937 13.356789 19.488068 -11.035599 7938 29.464111 20.561371 -10.899933 7939 30.180756 19.533188 -11.830997 7940 37.092888 20.021759 -12.607414 7941 41.753937 19.935318 -11.445312 7942 41.992935 20.701935 -11.284336 7943 41.173004 19.763412 -11.756584 7944 40.531265 18.959610 -11.820007 7945 2.564697 18.622833 -12.408474 7946 28.954559 19.619873 -11.469181 7947 28.686325 18.717194 -12.064934 7948 31.365105 18.689545 -11.724327 7949 41.004776 18.085602 -11.410969 7950 41.574249 19.028336 -11.386414 7951 42.511871 19.769440 -10.803364 7952 50.229248 18.026550 -12.141468 7953 2.811485 17.771713 -12.527542 7954 8.658348 17.294510 -12.450832 7955 13.403358 16.901367 -12.980579 7956 18.211761 18.431641 -12.861954 7957 19.079605 18.580383 -12.488583 7958 27.723618 18.014816 -11.845551 7959 28.240280 18.856979 -11.547077 7960 26.602089 16.750961 -12.082275 7961 34.618080 17.949097 -11.889538 7962 35.095795 18.063644 -12.277660 7963 35.117386 17.682922 -11.741516 7964 45.301056 17.603409 -12.645348 7965 48.556732 18.276764 -11.528301 7966 49.645447 18.042297 -11.486900 7967 49.322449 18.002136 -10.689487 7968 51.538666 17.580322 -11.856678 7969 50.447342 17.768066 -11.553329 7970 2.846382 18.142670 -11.218075 7971 2.988510 18.402542 -10.014015 7972 3.155968 17.593521 -10.095238 7973 8.641823 16.402557 -12.461140 7974 36.217133 17.363495 -11.390396 7975 40.905060 17.037643 -11.048317 7976 46.547089 16.664703 -11.488113 7977 45.721405 16.938599 -12.209583 7978 52.506119 17.088516 -11.732338 7979 52.913284 16.810272 -11.540024 7980 8.901581 15.631500 -11.663902 7981 25.692215 15.640320 -12.278591 7982 54.157654 15.869186 -10.824295 7983 8.413422 14.688049 -12.037163 7984 45.670639 15.406418 -11.847378 7985 54.340225 11.964630 -11.338028 7986 5.983276 13.461472 -13.271252 7987 7.634445 13.640671 -12.757191 7988 25.104736 15.721863 -11.255882 7989 24.779861 14.654175 -11.157772 7990 44.921082 13.618927 -12.087925 7991 6.946739 13.333221 -13.071251 7992 24.843285 12.627762 -12.847759 7993 24.824326 12.202789 -12.159035 7994 24.874435 13.266296 -11.009190 7995 46.007019 13.010529 -10.878677 7996 45.767776 12.183578 -10.784241 7997 45.104538 12.007080 -11.283394 7998 18.897911 11.845566 -10.008835 7999 19.120422 10.976410 -9.428555 8000 19.830780 10.867462 -10.307053 8001 20.612869 10.935516 -12.322105 8002 20.820129 10.677155 -13.264084 8003 21.379150 10.348694 -12.629486 8004 22.266006 9.443787 -12.729626 8005 23.657562 9.467926 -12.964767 8006 23.493797 8.883865 -12.400520 8007 24.989914 9.157120 -11.677628 8008 54.011734 9.848206 -11.357056 8009 42.921173 9.328415 -12.398344 8010 52.682159 9.214233 -12.295837 8011 25.698990 11.647919 -10.918694 8012 26.760406 10.091324 -10.977457 8013 42.675354 8.373856 -12.296677 8014 52.469894 7.885773 -11.758381 8015 51.308975 6.221359 -11.863392 8016 56.652939 6.282608 -12.583420 8017 56.657120 5.633537 -12.093544 8018 42.129669 5.254219 -11.677826 8019 41.956467 4.442917 -11.731239 8020 48.596802 2.975006 -12.740051 8021 31.660097 3.834061 -13.204771 8022 39.045761 4.233383 -12.708908 8023 41.262268 2.313873 -12.143465 8024 49.564758 2.840424 -11.467068 8025 50.649231 2.548050 -10.411375 8026 51.244446 4.018600 -10.598026 8027 59.132156 3.406548 -12.351933 8028 41.721817 3.390671 -11.747158 8029 59.700424 1.744827 -12.352512 8030 40.452576 1.793686 -12.643032 8031 39.757950 1.979889 -11.953152 8032 40.876572 0.598495 -11.758572 8033 40.193909 -0.026047 -12.014523 8034 40.228973 0.342651 -12.308617 8035 41.682098 1.549042 -10.981358 8036 47.679413 1.932373 -13.002151 8037 47.260391 -1.580399 -11.312447 8038 48.310532 -0.323914 -10.974419 8039 53.782104 1.178192 -12.479038 8040 52.264160 0.276428 -12.840595 8041 31.293053 0.006866 -12.455048 8042 40.187042 0.896057 -12.411316 8043 39.905769 0.557983 -11.874176 8044 52.046417 -0.489731 -12.888023 8045 52.052917 -1.335648 -13.106468 8046 30.069075 -0.744321 -12.525370 8047 54.557770 -0.863785 -12.342354 8048 53.278961 -1.582489 -12.825127 8049 52.977707 -0.576752 -12.654243 8050 53.967926 -2.051102 -12.811974 8051 54.953491 -2.514130 -12.351204 8052 54.076675 -2.969803 -12.885612 8053 60.763718 -1.291245 -13.251537 8054 52.856110 -2.956131 -13.126980 8055 61.486206 -2.094452 -12.473923 8056 27.836882 -2.842192 -12.792168 8057 51.282227 -5.213272 -13.301506 8058 49.624390 -6.633286 -13.432365 8059 53.826996 -3.776459 -12.972786 8060 55.527390 -3.851074 -11.824799 8061 55.973068 -2.693008 -11.711357 8062 62.381897 -3.349228 -12.371513 8063 46.312805 -2.413559 -12.193970 8064 27.550915 -3.698805 -13.422581 8065 53.499878 -4.931747 -12.840462 8066 54.509338 -3.978836 -12.539764 8067 62.993027 -4.492310 -11.869453 8068 27.053053 -3.614455 -12.563051 8069 26.230331 -4.335237 -12.236946 8070 26.539890 -5.293610 -13.057001 8071 27.014095 -4.718638 -13.477335 8072 46.913162 -7.943390 -13.551640 8073 52.828339 -6.122803 -12.943668 8074 64.176819 -6.382141 -12.649483 8075 26.847862 -5.624858 -13.910370 8076 26.752436 -6.025498 -13.972595 8077 49.262741 -8.022278 -13.361610 8078 53.609650 -6.302597 -12.525646 8079 52.485199 -7.568207 -12.595097 8080 51.118683 -7.046204 -13.034431 8081 26.686972 -6.460808 -14.139809 8082 45.778061 -7.124008 -12.122337 8083 45.719818 -8.054550 -12.671021 8084 46.105713 -8.272278 -13.227837 8085 46.521515 -8.944595 -13.301350 8086 48.247803 -8.628174 -13.421085 8087 50.733856 -8.302582 -12.925011 8088 49.655670 -9.843170 -12.983566 8089 64.626175 -6.999466 -11.684975 8090 26.467993 -9.072245 -14.735575 8091 47.263519 -9.508636 -13.315811 8092 48.215240 -10.621948 -13.021671 8093 18.154152 -11.158481 -11.069479 8094 18.961931 -10.177290 -11.069868 8095 20.137907 -9.645597 -11.187485 8096 20.555981 -10.944464 -11.468885 8097 19.183317 -8.787365 -10.838366 8098 18.833675 -9.315168 -10.884539 8099 21.125397 -11.022568 -11.601341 8100 19.361193 -8.121346 -10.723431 8101 21.546169 -10.215020 -11.602766 8102 22.316101 -9.590532 -11.744919 8103 23.985769 -9.334185 -12.408541 8104 24.586859 -9.770655 -12.836367 8105 25.044289 -10.131476 -13.187769 8106 45.871948 -9.035599 -12.562170 8107 46.406601 -10.004715 -12.956818 8108 46.791672 -11.558533 -12.646645 8109 20.796528 -12.126235 -11.647514 8110 22.066467 -12.083150 -11.941401 8111 25.190950 -11.236642 -13.399324 8112 25.350971 -12.295170 -13.476593 8113 25.830811 -11.476229 -13.941271 8114 25.736446 -10.718992 -13.867977 8115 25.785595 -9.904718 -13.844257 8116 26.004103 -9.268089 -14.014763 8117 12.812212 -11.630143 -9.883298 8118 11.887830 -11.460315 -9.464170 8119 19.259655 -13.015582 -11.419193 8120 19.932037 -12.567756 -11.518532 8121 18.348637 -12.567470 -11.239399 8122 23.445591 -12.221553 -12.417727 8123 65.450424 -10.864548 -12.915298 8124 13.613133 -11.330674 -10.076811 8125 13.789119 -12.405960 -10.321255 8126 20.144991 -13.441197 -11.555992 8127 17.599861 -11.919180 -11.060568 8128 24.644459 -13.235721 -12.880262 8129 25.992022 -13.138852 -13.748117 8130 14.775218 -13.216599 -10.626717 8131 18.842367 -13.734250 -11.344639 8132 18.396805 -14.461320 -11.280462 8133 17.636190 -14.138902 -11.175631 8134 17.794571 -14.898095 -11.173521 8135 20.099722 -14.697786 -11.458185 8136 21.129333 -12.915978 -11.751015 8137 30.674578 -14.713485 -15.684380 8138 9.612259 -15.129751 -8.285198 8139 19.143728 -14.721627 -11.344212 8140 26.359657 -15.549783 -12.774597 8141 64.281021 -14.398514 -13.988857 8142 65.371628 -14.796814 -13.303383 8143 10.305952 -15.846367 -8.776846 8144 18.558046 -15.120235 -11.250000 8145 19.358950 -16.643457 -11.043337 8146 19.276943 -15.666773 -11.235004 8147 18.372585 -16.312944 -11.036152 8148 18.559853 -17.158560 -10.849571 8149 18.805401 -18.073545 -10.577021 8150 19.469723 -17.619814 -10.768591 8151 27.132519 -16.445339 -12.577557 8152 27.445866 -15.798798 -13.077694 8153 29.589163 -16.809799 -13.185339 8154 28.493814 -16.045908 -13.350796 8155 28.216440 -16.689175 -12.806202 8156 34.957886 -16.312050 -14.399946 8157 35.844147 -16.079205 -14.481455 8158 36.662247 -16.144287 -14.432953 8159 35.767143 -16.592312 -14.075289 8160 36.537071 -16.644135 -13.820194 8161 37.261368 -15.876236 -14.828625 8162 60.181610 -15.764359 -14.646206 8163 16.651447 -14.280379 -11.017527 8164 16.340622 -13.430308 -10.942589 8165 18.017088 -15.581103 -11.124023 8166 26.254929 -16.758873 -12.128534 8167 31.144943 -16.813435 -13.641888 8168 37.021004 -17.167358 -14.171005 8169 29.540838 -17.973068 -12.312746 8170 30.695162 -17.734039 -12.768373 8171 30.469847 -18.917236 -11.812237 8172 34.312099 -17.509058 -13.474134 8173 31.997438 -17.431322 -13.304216 8174 37.102737 -18.057678 -14.175846 8175 66.757874 -16.979385 -12.221699 8176 66.513046 -15.943237 -12.280302 8177 66.317413 -17.799118 -13.426254 8178 16.871239 -15.133266 -11.001368 8179 23.321564 -19.393311 -15.755596 8180 37.075874 -18.858093 -14.269489 8181 66.819397 -18.337891 -12.835934 8182 67.215714 -19.387299 -12.266094 8183 23.789459 -20.876068 -14.972805 8184 23.752060 -21.345932 -14.459976 8185 24.784546 -21.251907 -14.654572 8186 24.157745 -21.664551 -13.932232 8187 25.562439 -21.966217 -13.729725 8188 24.686081 -21.802475 -13.830544 8189 28.160553 -21.052582 -13.975380 8190 27.832481 -21.426590 -13.743763 8191 29.942444 -21.268784 -14.255684 8192 36.669861 -20.809250 -13.942329 8193 37.297119 -20.551880 -12.977524 8194 37.256271 -21.585709 -12.100525 8195 36.771057 -21.531158 -13.336506 8196 37.237503 -19.676331 -13.767883 8197 54.367111 -21.923920 -14.322575 8198 66.982056 -20.608932 -13.322220 8199 16.217039 -17.398540 -10.555782 8200 15.039803 -19.246635 -9.890725 8201 22.569641 -22.242661 -14.748428 8202 26.286667 -22.027039 -14.084007 8203 31.994669 -21.977249 -14.652615 8204 33.822281 -22.462265 -14.652256 8205 32.701500 -22.716629 -14.494019 8206 51.906509 -22.645325 -13.584064 8207 53.231842 -22.755005 -13.496002 8208 54.317139 -23.772430 -13.192966 8209 52.861267 -21.869553 -14.062283 8210 15.520323 -19.713337 -9.708532 8211 15.881836 -18.999084 -10.041477 8212 14.809046 -19.935804 -9.508373 8213 21.977402 -22.993912 -14.729065 8214 30.389053 -22.123825 -13.916836 8215 34.677399 -22.281219 -14.558910 8216 34.612198 -23.062271 -14.083904 8217 55.536743 -23.038483 -13.870941 8218 67.273300 -21.718216 -13.122810 8219 10.811127 -17.704933 -8.283136 8220 11.936142 -19.489981 -8.394864 8221 12.506147 -19.961580 -8.539883 8222 12.497493 -19.638117 -8.825153 8223 13.426976 -19.882318 -9.179813 8224 13.800067 -20.209105 -9.086588 8225 14.053802 -19.838892 -9.425280 8226 14.444350 -20.303196 -9.204639 8227 31.746508 -22.906540 -14.074062 8228 32.178040 -23.583694 -13.899673 8229 33.306305 -23.859879 -13.695625 8230 35.273911 -23.063507 -13.653923 8231 51.101379 -24.341736 -14.461338 8232 55.653290 -24.198639 -13.177425 8233 57.585419 -25.356812 -12.557945 8234 58.202744 -24.547684 -13.095009 8235 12.929811 -19.931995 -8.899436 8236 14.653563 -21.166328 -8.534754 8237 15.288650 -21.517685 -8.342501 8238 15.099172 -20.783234 -8.932188 8239 21.645889 -24.003647 -13.790825 8240 40.789490 -25.495605 -15.501404 8241 59.221664 -24.655655 -13.175127 8242 67.779083 -24.762848 -13.341488 8243 67.676743 -23.743134 -13.271492 8244 14.104901 -20.551350 -8.889399 8245 13.197600 -20.341633 -8.645775 8246 41.447922 -25.891617 -15.177979 8247 50.881104 -25.434219 -13.368889 8248 51.997437 -25.520477 -14.615688 8249 52.862213 -26.975098 -14.715290 8250 61.974579 -25.574356 -14.265541 8251 68.028259 -25.454803 -12.641636 8252 32.034805 -28.119080 -14.852766 8253 41.351715 -26.545776 -14.844822 8254 62.417923 -26.844833 -14.224380 8255 32.940506 -27.702347 -15.346878 8256 52.896790 -28.351105 -14.689758 8257 21.820755 -28.505188 -14.755905 8258 29.337402 -32.120773 -11.681641 8259 30.700867 -31.981384 -11.803608 8260 33.196014 -28.353790 -14.942055 8261 33.906967 -29.519455 -14.711723 8262 40.953735 -28.748154 -14.639740 8263 40.929108 -27.571091 -14.630955 8264 60.456146 -29.350128 -14.418545 8265 60.075455 -28.450348 -13.997509 8266 59.164886 -29.039215 -13.927113 8267 61.352554 -26.869110 -13.488361 8268 60.465149 -27.355484 -13.554939 8269 61.789917 -27.816910 -14.168642 8270 60.983215 -28.614838 -14.303543 8271 32.873367 -28.653381 -14.388199 8272 39.646393 -29.934967 -14.911671 8273 39.925522 -29.085770 -14.994801 8274 42.674881 -29.723145 -15.106392 8275 51.849152 -27.597260 -14.109406 8276 51.372543 -28.371735 -13.586540 8277 51.101166 -27.408096 -13.624052 8278 33.869598 -31.075333 -13.708046 8279 39.845474 -30.900757 -14.657162 8280 40.149582 -29.757690 -14.658249 8281 41.940002 -30.708450 -14.932514 8282 41.916229 -29.483917 -14.684353 8283 40.975891 -30.267685 -14.603237 8284 43.018478 -30.913193 -15.469585 8285 43.891190 -30.624786 -15.655251 8286 50.722931 -27.516037 -12.912384 8287 51.576721 -32.068802 -13.477654 8288 51.098862 -31.445007 -12.299561 8289 51.407623 -30.525299 -13.128159 8290 60.163910 -30.455460 -14.450680 8291 59.491776 -31.431412 -14.345390 8292 60.462112 -31.584290 -14.328621 8293 56.689270 -30.019775 -13.835758 8294 55.884933 -31.542694 -14.053783 8295 57.365250 -31.645401 -14.581600 8296 58.406860 -30.420425 -14.212086 8297 62.368851 -33.034546 -14.543427 8298 66.828995 -30.313873 -13.745651 8299 66.533295 -31.197998 -13.923256 8300 33.434502 -32.449524 -14.084450 8301 39.245148 -31.888153 -15.000160 8302 56.985840 -33.411987 -15.012798 8303 66.050201 -32.456802 -14.242065 8304 25.805359 -33.619324 -15.570950 8305 25.515427 -33.988358 -15.465855 8306 26.131104 -33.862946 -15.275127 8307 39.042923 -33.287979 -15.190941 8308 39.006363 -34.414276 -15.072189 8309 56.504395 -32.397552 -14.602798 8310 55.634888 -33.040863 -14.314342 8311 60.106339 -33.365067 -13.887806 8312 60.712051 -32.899429 -13.731941 8313 61.190903 -33.346771 -13.453556 8314 63.240540 -33.598282 -14.504730 8315 65.463196 -33.677979 -14.413933 8316 25.175003 -34.575668 -15.514095 8317 39.597404 -33.961014 -14.911488 8318 39.286537 -34.899719 -15.121689 8319 62.136444 -33.525009 -13.996964 8320 64.544586 -34.374298 -14.257072 8321 24.237808 -36.810349 -14.974838 8322 24.641632 -37.866013 -15.266205 8323 38.749649 -35.648865 -15.751049 8324 38.845200 -35.000687 -15.245861 8325 55.795914 -36.330750 -15.123970 8326 56.103180 -35.156525 -15.070099 8327 54.536423 -35.773392 -14.194565 8328 55.494980 -34.285156 -14.472866 8329 61.557037 -36.071182 -14.418221 8330 60.414490 -35.149399 -13.412415 8331 36.084000 -37.947998 -16.638035 8332 37.096085 -37.557083 -16.429279 8333 55.454956 -37.175339 -14.980518 8334 62.088821 -36.933243 -14.777111 8335 62.489716 -37.466690 -14.686073 8336 24.996620 -38.961212 -15.264233 8337 25.686768 -39.309998 -15.533657 8338 55.005356 -40.155991 -14.783474 8339 55.255646 -39.174728 -14.960480 8340 53.945435 -39.225403 -14.121853 8341 55.330200 -38.188477 -14.967819 8342 63.076981 -38.287354 -14.010101 8343 26.258904 -40.355469 -15.434772 8344 52.460388 -38.343964 -15.309959 8345 51.720261 -38.890442 -14.130680 8346 53.698151 -40.172791 -13.910477 8347 27.774773 -41.226486 -15.732647 8348 28.841782 -42.045578 -15.906559 8349 43.505798 -40.955551 -15.634212 8350 44.060196 -41.609024 -15.119308 8351 51.901611 -39.270386 -15.109104 8352 51.357147 -39.857681 -14.388695 8353 54.343781 -41.255844 -14.290157 8354 55.663345 -41.076736 -15.134388 8355 43.316284 -41.325607 -14.632217 8356 50.509674 -43.211090 -15.223312 8357 65.498276 -39.648285 -14.309303 8358 41.097763 -42.151260 -14.719311 8359 40.737442 -42.748398 -14.470230 8360 44.440765 -42.760330 -15.360962 8361 50.467468 -41.105988 -14.421494 8362 50.907623 -40.664368 -14.487064 8363 29.593552 -42.745499 -15.553917 8364 27.950531 -42.526245 -14.726200 8365 29.394539 -43.374680 -14.088963 8366 30.435081 -42.983734 -15.721405 8367 32.336472 -43.493301 -14.954189 8368 33.418579 -43.435669 -15.423557 8369 34.102951 -43.522461 -15.618599 8370 33.964996 -43.091553 -16.346092 8371 50.327271 -41.362259 -14.421055 8372 55.166061 -42.645844 -15.030575 8373 55.825623 -43.394836 -15.660759 8374 65.960571 -41.368896 -13.942989 8375 50.338104 -43.926544 -15.584301 8376 50.209045 -44.023422 -15.407833 8377 50.304504 -43.788345 -15.272137 8378 65.670792 -44.044418 -14.649368 8379 64.772995 -45.566437 -15.173141 8380 34.963196 -46.421310 -16.054405 8381 44.516449 -46.997467 -15.643894 8382 44.089890 -45.356003 -14.962341 8383 50.524780 -44.247513 -15.338829 8384 55.095490 -44.071060 -15.492378 8385 54.889236 -44.978607 -15.937397 8386 41.122208 -46.629578 -15.812115 8387 51.996887 -46.086456 -15.996841 8388 51.997681 -46.411133 -16.331802 8389 52.876389 -44.731384 -14.727493 8390 41.399292 -47.843704 -15.140106 8391 41.989899 -49.209015 -15.040684 8392 34.187775 -49.923798 -15.890480 8393 34.598038 -48.155594 -15.169128 8394 62.165787 -49.072021 -13.687130 8395 61.374634 -51.034393 -14.528820 8396 60.930618 -50.398117 -13.563831 8397 34.199768 -57.225983 -16.321259 8398 53.978867 -53.021667 -15.929501 8399 53.158432 -52.320297 -15.279167 8400 54.128708 -51.698700 -14.926834 8401 55.038971 -52.886642 -15.537357 8402 42.517517 -52.735611 -15.254501 8403 42.672226 -51.650864 -15.356377 8404 42.970184 -53.598389 -15.909225 8405 52.755417 -53.002243 -15.308624 8406 53.259338 -53.139832 -15.903011 8407 47.344666 -55.108627 -16.502243 8408 47.197372 -54.428299 -16.334473 8409 33.193863 -56.749252 -15.690304 8410 58.636581 -55.212875 -16.041691 8411 58.173187 -55.499146 -16.427456 8412 43.445435 -56.652298 -16.352543 8413 34.789803 -57.953186 -16.555695 8414 46.816742 -58.594650 -16.899761 8415 53.762314 -56.699875 -15.949127 8416 53.419876 -56.093582 -15.791580 8417 54.349823 -57.143860 -16.295540 8418 55.223312 -57.390686 -16.140614 8419 55.019287 -56.959595 -15.575249 8420 56.074142 -57.696045 -16.491322 8421 55.182831 -57.647934 -16.680119 8422 56.734375 -57.272446 -15.784573 8423 55.816498 -57.232651 -15.915163 8424 43.845322 -59.478424 -16.316559 8425 42.799133 -57.969162 -15.466782 8426 36.830070 -60.527267 -17.346317 8427 36.267471 -60.655029 -17.039124 8428 43.114716 -59.612457 -15.342388 8429 45.970703 -59.792831 -15.320980 8430 45.698181 -58.135635 -15.494827 8431 57.386124 -59.584015 -16.118839 8432 57.954895 -57.016312 -14.923920 8433 58.324585 -57.496902 -14.700306 8434 58.187302 -57.144333 -14.388645 8435 57.467468 -56.982025 -15.310089 8436 57.403687 -60.524628 -15.890049 8437 34.497253 -62.291214 -15.712536 8438 35.257156 -62.855972 -16.830124 8439 35.556740 -61.175323 -16.610176 8440 36.403473 -61.487579 -17.273933 8441 44.394409 -61.413071 -16.510277 8442 44.034195 -60.752060 -16.162598 8443 43.666473 -61.765076 -16.091774 8444 35.972023 -62.616959 -17.355728 8445 34.868271 -60.804306 -15.367241 8446 44.742645 -62.352295 -17.125755 8447 42.310074 -63.649246 -16.969704 8448 42.966568 -63.074326 -17.261730 8449 34.724655 -64.015778 -16.585670 8450 41.712677 -64.734009 -16.917561 8451 49.318787 -63.572678 -16.707214 8452 50.387817 -63.551453 -15.825684 8453 50.336685 -64.132126 -17.097408 8454 35.080132 -65.392563 -17.007698 8455 49.554718 -62.979218 -15.577663 8456 52.700516 -64.093750 -15.878498 8457 40.957428 -66.434631 -17.072342 8458 40.699982 -67.680222 -17.330429 8459 40.826416 -67.345688 -17.263477 8460 39.862740 -68.439789 -17.411369 8461 40.407654 -67.940643 -17.481716 8462 35.695877 -70.880585 -17.335030 8463 35.249588 -68.857040 -17.205862 8464 38.179779 -71.239349 -17.284470 8465 38.302231 -70.616913 -16.240910 8466 9.144455 60.174438 -8.411293 8467 9.902504 60.349411 -8.258606 8468 11.703636 59.346252 -8.422913 8469 12.168488 58.222092 -8.394928 8470 13.207397 57.003540 -7.331833 8471 13.486420 58.250488 -6.648071 8472 12.121689 57.064545 -8.726379 8473 4.828163 55.438904 -9.257618 8474 11.622688 56.306244 -9.159569 8475 12.490616 56.114258 -8.343918 8476 5.249298 56.161591 -8.059868 8477 11.509735 54.765503 -9.130814 8478 12.173248 51.995758 -8.347855 8479 12.088234 52.605728 -7.864601 8480 20.181190 51.442734 -8.804817 8481 18.930298 52.671387 -8.119987 8482 18.731483 51.419830 -7.807075 8483 20.605316 52.607300 -8.851059 8484 21.759712 53.654327 -8.493118 8485 19.992004 54.064255 -8.256149 8486 21.656601 52.471680 -8.933868 8487 19.650772 50.516266 -8.218163 8488 21.506104 51.632126 -9.036720 8489 22.324440 54.953537 -7.929657 8490 23.654114 54.389908 -7.774536 8491 23.270844 52.168182 -8.572891 8492 4.609444 51.304840 -8.863541 8493 21.477036 50.337646 -8.967262 8494 21.260513 50.838104 -9.051266 8495 20.728745 50.421692 -8.788139 8496 22.496239 50.505463 -8.872864 8497 21.637688 49.707825 -8.787384 8498 4.099053 48.499283 -9.737000 8499 3.880043 46.565659 -9.087498 8500 3.712784 48.086105 -9.325012 8501 8.979034 47.519135 -10.049599 8502 17.187073 47.730942 -9.321846 8503 17.288666 46.816132 -8.017143 8504 15.509079 48.707703 -8.072754 8505 22.612762 47.743332 -8.893204 8506 23.349220 47.679199 -9.253845 8507 23.333603 48.731506 -8.925552 8508 24.162849 47.326172 -9.292244 8509 27.188202 49.639175 -7.904060 8510 27.180283 50.734863 -7.801330 8511 25.261864 50.102280 -8.470894 8512 18.057770 46.656143 -9.545204 8513 23.256630 46.847733 -9.118931 8514 22.272415 46.831482 -8.301559 8515 22.946930 45.650558 -8.422348 8516 24.173271 45.862946 -9.261013 8517 25.340256 46.518921 -9.236530 8518 25.276566 45.349152 -9.436771 8519 25.523598 47.995605 -8.795273 8520 18.696747 45.674347 -9.598022 8521 24.718216 44.509766 -9.226681 8522 24.649803 43.257401 -8.772552 8523 25.709366 43.525543 -9.091007 8524 26.833900 46.627502 -8.472610 8525 26.180008 45.566071 -9.110966 8526 10.205360 43.750946 -10.386848 8527 19.138611 44.830704 -9.858974 8528 25.523178 44.413422 -9.413750 8529 25.954933 44.861450 -9.388351 8530 26.429810 44.865417 -9.126381 8531 10.001633 42.612045 -10.271687 8532 9.834915 45.015778 -10.125458 8533 26.304749 44.222885 -9.090099 8534 27.190536 44.919144 -8.389793 8535 20.034058 42.499893 -9.962776 8536 32.773911 43.339905 -8.826294 8537 33.468094 42.310669 -9.401043 8538 33.979973 44.056778 -8.864426 8539 34.698090 42.357925 -9.433125 8540 35.451080 44.032700 -8.787910 8541 35.844643 42.429352 -9.272724 8542 36.849617 43.337509 -8.697098 8543 10.361359 41.548538 -10.315296 8544 32.541809 42.316650 -9.093838 8545 32.587479 41.080002 -9.189102 8546 36.849319 41.508362 -9.052990 8547 35.564934 40.513428 -9.529045 8548 3.777031 40.158783 -10.513752 8549 20.771721 41.349609 -9.974888 8550 21.279259 40.326935 -10.025368 8551 20.870590 40.560883 -9.260262 8552 31.652269 40.987015 -8.177620 8553 32.054306 40.042465 -8.788239 8554 33.852539 40.217148 -9.784470 8555 38.045990 42.455292 -8.461990 8556 38.119270 43.544159 -8.324997 8557 16.095779 39.675446 -11.051559 8558 21.641174 39.216690 -9.610371 8559 32.692352 39.461685 -9.322803 8560 33.126144 38.339020 -10.051857 8561 37.879463 41.512878 -8.185516 8562 36.444672 40.579697 -9.417648 8563 10.904755 38.879181 -10.258312 8564 25.629135 38.341125 -8.270882 8565 25.617714 36.758881 -8.235466 8566 27.470627 38.625458 -9.776127 8567 28.259171 38.691589 -9.726860 8568 27.694252 39.401947 -9.220882 8569 26.785118 38.946472 -9.242870 8570 26.379181 40.031677 -8.758560 8571 28.980255 39.264465 -8.433578 8572 36.395386 40.258453 -9.177593 8573 35.347229 39.142990 -9.449532 8574 36.754501 40.628021 -9.159477 8575 3.621155 41.492798 -9.407921 8576 11.174194 37.282440 -10.600014 8577 17.642044 38.392395 -11.182716 8578 22.200195 38.263840 -10.037655 8579 22.757797 37.646942 -10.165031 8580 27.777954 40.531799 -8.378479 8581 35.609093 38.430634 -8.503548 8582 35.737144 38.913330 -7.197845 8583 35.894867 39.366943 -7.718429 8584 11.140732 38.161194 -10.423672 8585 23.227036 37.275955 -10.145760 8586 29.846039 38.147797 -9.027916 8587 36.076263 37.087906 -9.729492 8588 36.045341 37.093475 -7.964935 8589 36.828751 36.108002 -8.976196 8590 43.123169 37.787384 -9.393562 8591 41.291046 37.938324 -8.776520 8592 45.742737 36.940521 -9.427677 8593 46.532822 37.323944 -8.458885 8594 45.335159 38.182236 -8.111305 8595 11.069016 34.863174 -11.028587 8596 23.282196 36.253632 -9.283836 8597 25.794800 35.551758 -8.050278 8598 26.248749 35.972946 -9.081783 8599 32.228157 37.235565 -10.108261 8600 32.398880 38.203064 -9.430862 8601 31.668352 37.689667 -9.262913 8602 37.296471 35.968277 -9.965519 8603 37.041176 36.323273 -9.855991 8604 37.391663 36.149490 -9.737206 8605 47.556046 37.273712 -7.770325 8606 47.378296 37.702515 -7.494736 8607 3.069985 32.252319 -10.900547 8608 2.961311 33.528534 -10.359066 8609 27.006577 35.698639 -10.025677 8610 37.288452 35.953888 -9.613029 8611 11.074532 35.240280 -10.934814 8612 23.891380 35.260422 -9.537994 8613 27.509583 34.090424 -10.162605 8614 46.941681 35.356537 -9.250755 8615 3.302864 32.970428 -9.946297 8616 12.362503 33.241257 -10.968094 8617 12.282043 32.848984 -10.739838 8618 12.679626 32.737839 -10.941261 8619 27.743622 33.328812 -10.110767 8620 37.363953 33.837662 -9.120670 8621 28.144669 32.812378 -10.074196 8622 39.555458 33.275711 -9.589634 8623 48.030823 34.641052 -8.587234 8624 47.635590 35.216309 -8.828194 8625 12.903740 30.985229 -10.679050 8626 13.416214 31.086304 -11.068531 8627 25.296341 31.359390 -10.582790 8628 31.896929 31.285934 -10.244991 8629 32.928780 31.336670 -10.078293 8630 34.149170 31.520691 -10.083118 8631 36.734238 32.012405 -9.742592 8632 23.945801 29.897202 -9.885735 8633 35.019142 31.351242 -9.876030 8634 13.352478 29.844208 -10.788918 8635 13.946175 28.909729 -10.679268 8636 29.732819 29.361938 -8.499557 8637 30.946671 29.090607 -9.274704 8638 33.299179 28.680008 -10.253487 8639 32.150360 28.916138 -9.951553 8640 35.013206 29.188492 -10.922333 8641 35.881989 29.260056 -10.414072 8642 35.809952 29.374023 -10.191193 8643 35.596985 29.191193 -10.249424 8644 35.997147 29.255997 -10.122692 8645 37.512527 29.184113 -10.968983 8646 40.857620 29.141785 -10.298126 8647 12.163223 27.857239 -10.982773 8648 14.363449 28.247040 -11.064594 8649 21.694061 26.697998 -10.790535 8650 22.305405 27.908401 -10.128098 8651 27.948898 29.408981 -8.983536 8652 26.766037 28.699524 -9.804985 8653 32.816254 28.506638 -9.321152 8654 33.992081 28.645752 -10.478458 8655 34.859711 28.746841 -10.134583 8656 36.425034 29.034805 -10.313210 8657 37.608246 28.877808 -10.426897 8658 38.450195 28.544708 -10.427601 8659 47.841782 27.649338 -9.077480 8660 25.969429 27.477570 -9.795399 8661 25.503189 26.054306 -9.992737 8662 33.929451 28.376205 -9.922688 8663 12.460815 26.499146 -10.520542 8664 14.413177 23.845734 -10.307583 8665 47.196594 26.500366 -9.837509 8666 5.067803 28.361450 -11.002663 8667 6.855850 25.983887 -10.289032 8668 6.842514 25.223557 -10.664101 8669 13.498795 26.801147 -9.920212 8670 13.425964 28.018585 -10.491003 8671 47.248077 25.292603 -9.861950 8672 46.650909 24.448181 -10.314117 8673 6.917770 25.036911 -9.797756 8674 6.417587 24.064362 -9.926117 8675 11.706009 25.137268 -10.881428 8676 24.752068 25.026550 -9.547737 8677 24.640472 23.811905 -10.144066 8678 47.240204 24.132217 -9.583797 8679 14.156418 24.731750 -9.721046 8680 19.366966 21.439514 -10.420216 8681 42.645966 24.137131 -11.354153 8682 46.116028 23.556305 -10.076153 8683 48.456635 24.475418 -8.624039 8684 49.398132 24.579773 -7.665207 8685 48.865845 25.827362 -8.014786 8686 5.109902 23.724701 -9.159164 8687 43.613525 22.663635 -10.702866 8688 2.933304 19.594299 -9.897724 8689 2.727959 19.539398 -11.864899 8690 24.158936 23.136688 -10.272755 8691 43.464874 21.602051 -9.890015 8692 43.737366 20.994934 -8.963799 8693 44.334290 21.931885 -9.091244 8694 13.343346 19.869949 -11.596119 8695 19.276901 20.087952 -11.096203 8696 22.012108 21.643616 -10.246502 8697 20.759781 20.674194 -10.563816 8698 22.393204 21.291779 -11.326542 8699 30.033951 20.593094 -10.649715 8700 30.402763 20.250671 -10.606209 8701 42.492081 20.735474 -10.938049 8702 42.903473 20.783905 -10.484634 8703 9.102539 17.645950 -11.507549 8704 9.421608 18.486298 -10.829487 8705 19.133926 19.325943 -11.777100 8706 20.083221 19.666351 -11.413925 8707 30.726288 19.496185 -10.680115 8708 19.867477 20.452179 -10.587860 8709 28.509895 20.352173 -10.215881 8710 27.589905 19.230286 -10.629456 8711 31.342621 18.672104 -10.727375 8712 33.046494 18.041534 -11.349804 8713 33.980652 18.276123 -11.821796 8714 43.408264 19.003372 -9.883450 8715 43.424774 20.194534 -9.677174 8716 4.042679 15.710876 -11.930073 8717 3.478912 16.556671 -10.790241 8718 9.612854 19.609497 -10.772671 8719 25.968689 17.899521 -10.109779 8720 32.273628 18.072754 -11.250584 8721 34.033875 17.676071 -11.082428 8722 42.317673 17.979996 -10.718021 8723 43.867508 20.231171 -8.808380 8724 47.781708 17.262772 -10.631477 8725 48.358276 17.976318 -10.742573 8726 49.169220 17.413666 -9.642223 8727 49.067429 17.858170 -10.076611 8728 50.167480 17.541153 -9.784721 8729 3.180420 16.890076 -11.943752 8730 9.175812 16.670959 -11.253193 8731 25.595901 16.590530 -11.219128 8732 32.420090 17.961029 -10.526073 8733 34.982544 17.266479 -10.804615 8734 42.682129 16.797546 -10.125652 8735 41.758286 16.689804 -10.814884 8736 47.066483 15.808151 -10.679138 8737 47.161499 16.983658 -11.136421 8738 50.764908 17.619263 -10.794758 8739 52.255737 17.223053 -9.551449 8740 51.067596 17.163849 -8.790588 8741 52.554794 17.097748 -10.912453 8742 53.810638 16.578827 -9.909748 8743 54.436234 16.501099 -8.306290 8744 53.524475 16.874847 -8.900597 8745 15.618561 15.804611 -11.214806 8746 41.229309 16.391953 -10.746628 8747 5.085442 14.886734 -11.762634 8748 41.673340 16.239258 -10.369938 8749 41.885468 16.024673 -8.873581 8750 43.635483 16.577988 -9.185204 8751 54.681320 15.239136 -10.459785 8752 54.795212 15.864700 -9.544415 8753 6.177734 14.117783 -12.039543 8754 7.648147 14.023666 -11.726341 8755 16.685577 14.782730 -10.461823 8756 47.678940 15.068207 -9.748920 8757 46.880859 14.114471 -10.245819 8758 55.065659 14.204865 -10.011868 8759 17.146065 13.502869 -12.276772 8760 46.198059 14.351456 -11.141537 8761 8.016190 10.457870 -11.482590 8762 8.921661 10.332672 -11.777515 8763 8.876854 10.987274 -11.418877 8764 7.957687 11.445557 -10.819637 8765 9.952866 10.020111 -11.495888 8766 9.750961 11.578659 -10.827999 8767 20.587173 10.474335 -11.346825 8768 21.109184 10.504379 -12.013321 8769 25.156944 13.199982 -10.288471 8770 43.676636 7.253571 -9.774902 8771 43.394165 7.842545 -10.537029 8772 44.175446 8.580551 -9.625919 8773 45.671692 11.590225 -10.241554 8774 55.878342 10.347549 -9.836315 8775 55.029404 10.255585 -10.667431 8776 55.520630 9.480194 -9.974689 8777 9.945098 8.494476 -11.153812 8778 8.857620 9.536011 -11.572437 8779 8.065353 9.512573 -11.372219 8780 7.394196 9.648804 -10.749557 8781 6.996178 9.066071 -9.457279 8782 8.492816 8.647670 -10.136705 8783 12.658875 9.648209 -11.791523 8784 11.950516 8.629669 -11.281742 8785 13.224960 8.934021 -11.811291 8786 12.539536 10.305725 -11.605885 8787 13.393852 9.961807 -11.551151 8788 12.637032 10.816208 -11.346397 8789 21.279037 9.718903 -11.964096 8790 44.177368 9.606659 -10.443806 8791 53.203583 9.173721 -11.818703 8792 55.629089 11.348404 -10.060753 8793 55.538040 12.147858 -10.078983 8794 13.342331 9.337936 -11.895023 8795 21.616714 8.948441 -12.179634 8796 43.389145 8.862518 -11.238434 8797 13.880943 9.192841 -11.613861 8798 14.363052 8.222122 -11.215500 8799 14.852417 9.984695 -10.651833 8800 21.517159 8.257278 -11.958614 8801 21.099625 8.821472 -11.823910 8802 20.949814 8.143585 -11.621582 8803 22.239853 7.788147 -11.669151 8804 23.998642 8.016144 -11.508308 8805 24.983368 7.815506 -10.680019 8806 21.478683 7.711838 -11.615261 8807 53.914856 8.349609 -10.774448 8808 54.159790 6.957458 -9.828411 8809 42.805939 4.485970 -10.015152 8810 42.518738 5.228745 -10.864166 8811 43.351395 5.815521 -9.652691 8812 42.831299 7.521484 -11.585835 8813 32.670494 5.162979 -11.772049 8814 34.740334 5.842720 -10.857292 8815 36.633148 5.332855 -10.719788 8816 35.568039 6.346893 -10.026772 8817 33.414474 5.814232 -11.029160 8818 42.258224 6.162460 -11.886639 8819 51.542603 5.194748 -10.989483 8820 57.612762 4.633911 -11.874859 8821 31.676104 4.190948 -11.836666 8822 38.263603 4.751381 -12.891239 8823 38.278694 4.529144 -11.863739 8824 39.342361 3.590431 -12.182755 8825 52.168945 4.881210 -10.225845 8826 56.327484 4.585541 -11.759182 8827 55.631256 3.743652 -11.921562 8828 58.907059 3.255646 -11.859879 8829 58.079681 3.409012 -11.533180 8830 53.515747 4.142365 -9.463917 8831 39.720085 1.080017 -9.597534 8832 38.790222 3.576492 -10.389847 8833 55.353699 2.684372 -11.998119 8834 55.917526 1.639786 -11.754318 8835 58.765121 2.183105 -11.525364 8836 55.870880 0.550323 -11.738388 8837 59.754303 1.009888 -11.754005 8838 30.644867 1.004929 -10.014423 8839 29.973330 0.111457 -10.806780 8840 40.039642 0.851532 -8.056412 8841 40.042847 1.472382 -7.950333 8842 41.134216 -0.597626 -10.473217 8843 40.675171 -1.572388 -10.361134 8844 40.310638 -1.071991 -10.984474 8845 56.040161 -1.565842 -11.686390 8846 30.204802 -0.298645 -11.843273 8847 39.955948 -0.286880 -11.291649 8848 40.431061 -0.426620 -11.476597 8849 56.245972 -0.434494 -11.530773 8850 57.215652 0.263046 -10.995697 8851 57.541595 1.225052 -11.193592 8852 60.208160 -0.022858 -11.421741 8853 60.875458 -1.029297 -11.454674 8854 29.314655 -0.743667 -11.742384 8855 46.119888 -5.725159 -12.177189 8856 54.925079 -5.568192 -11.852570 8857 26.003445 -5.360307 -12.541662 8858 26.622684 -3.107265 -11.828186 8859 26.699488 -5.821246 -13.681370 8860 54.181534 -8.586761 -11.812325 8861 52.640030 -9.553833 -12.193573 8862 55.409500 -8.185516 -11.294529 8863 55.030426 -8.283630 -11.467354 8864 55.145645 -7.402237 -11.452148 8865 26.338411 -7.413581 -13.890791 8866 26.530359 -6.533425 -13.803745 8867 26.188290 -8.466398 -14.064466 8868 54.082123 -7.092804 -12.015102 8869 45.860367 -10.067795 -12.346931 8870 46.034378 -10.916870 -12.446186 8871 51.769119 -8.898849 -12.547218 8872 65.399323 -9.714325 -12.445023 8873 64.986420 -8.259262 -12.300034 8874 20.879585 -8.860878 -11.192640 8875 25.862549 -8.144120 -13.535170 8876 26.137861 -6.725358 -13.282331 8877 45.728882 -9.460236 -11.362495 8878 45.715454 -10.711319 -11.656200 8879 51.251923 -9.919525 -12.597469 8880 65.792877 -11.220367 -11.709595 8881 12.600763 -10.334881 -9.512766 8882 18.055105 -10.087461 -10.888605 8883 17.681976 -9.353035 -10.689625 8884 17.267776 -9.749738 -10.686865 8885 25.308348 -8.978338 -13.225206 8886 25.409521 -10.174123 -13.495281 8887 45.991974 -10.298798 -10.610634 8888 45.990601 -9.378876 -10.639133 8889 50.827194 -11.735703 -12.548882 8890 52.140778 -10.979004 -12.212067 8891 49.248260 -12.394638 -12.694427 8892 47.888824 -12.879227 -12.527786 8893 54.210632 -11.294220 -11.606720 8894 10.338123 -12.595813 -8.794744 8895 10.910126 -12.556676 -9.209229 8896 11.484068 -12.374083 -9.492929 8897 21.767706 -13.217433 -11.888321 8898 22.432360 -13.151953 -12.053566 8899 45.826477 -11.825562 -11.645809 8900 9.721746 -12.537868 -8.249552 8901 10.071871 -11.542083 -8.334623 8902 14.565103 -12.012376 -10.441441 8903 17.508284 -13.086361 -11.129486 8904 17.037165 -13.721357 -11.088907 8905 21.411917 -14.733275 -11.695108 8906 21.063381 -13.912356 -11.712700 8907 22.265741 -14.009438 -11.966042 8908 23.386772 -13.397549 -12.319725 8909 23.222752 -14.482533 -12.124752 8910 24.370409 -14.721462 -12.392885 8911 25.448538 -14.979529 -12.693167 8912 50.378387 -13.246216 -12.417404 8913 49.699417 -13.980331 -12.221397 8914 48.787445 -14.166122 -12.137794 8915 51.651657 -13.331070 -12.061985 8916 51.898285 -14.540131 -11.542789 8917 50.748489 -14.726654 -11.676197 8918 9.329493 -14.772487 -8.027119 8919 25.519693 -15.664534 -12.410566 8920 46.821350 -13.467972 -12.028828 8921 47.724503 -15.055237 -11.526573 8922 46.633392 -14.701050 -11.439285 8923 15.494121 -12.924938 -10.737947 8924 20.341692 -16.207813 -11.217583 8925 20.908564 -15.380953 -11.493826 8926 21.942652 -15.677700 -11.607988 8927 21.138573 -15.973283 -11.409435 8928 24.147024 -16.248642 -11.838469 8929 25.035040 -16.017414 -12.120701 8930 9.340314 -15.509255 -7.851920 8931 16.996050 -17.450008 -10.609222 8932 16.680212 -18.435289 -10.290955 8933 17.475603 -16.767010 -10.838137 8934 17.303537 -15.990853 -10.970098 8935 20.157318 -17.130520 -10.967886 8936 24.705219 -17.468983 -11.456308 8937 25.247974 -16.905157 -11.809225 8938 34.942215 -17.023317 -13.824453 8939 35.899136 -17.194759 -13.591105 8940 36.882645 -16.975433 -13.437939 8941 37.203667 -18.190445 -13.381439 8942 37.185776 -17.335846 -13.394814 8943 27.559380 -17.340744 -12.185434 8944 28.640162 -17.498894 -12.410545 8945 35.298271 -17.834896 -13.244326 8946 9.907682 -16.716019 -7.966459 8947 10.180758 -16.998981 -8.128929 8948 16.650888 -19.417665 -9.886126 8949 31.626101 -18.503094 -12.353731 8950 67.184067 -18.059052 -11.779427 8951 67.449097 -17.172775 -10.215004 8952 10.530600 -17.191456 -8.346215 8953 37.183075 -19.228439 -12.556664 8954 37.096222 -20.077042 -11.630310 8955 17.758156 -18.455805 -10.360706 8956 17.371529 -19.328453 -9.961948 8957 28.404869 -21.353851 -13.681938 8958 29.103081 -22.096298 -13.474697 8959 10.599685 -18.462965 -7.591504 8960 16.222757 -19.946495 -9.601521 8961 23.357460 -21.841629 -13.906029 8962 31.227966 -22.208496 -14.179169 8963 15.252510 -20.220711 -9.396706 8964 15.703537 -20.344378 -9.345314 8965 22.390503 -22.648041 -13.694351 8966 25.931137 -22.280655 -12.888676 8967 30.961609 -22.900574 -13.697239 8968 35.939423 -23.110168 -13.081287 8969 36.614044 -22.296982 -12.967808 8970 53.803055 -25.373169 -12.297760 8971 55.086151 -25.218033 -12.573605 8972 52.382309 -23.129578 -13.055092 8973 67.626740 -20.868973 -11.605862 8974 67.701569 -22.541595 -12.317093 8975 11.352223 -19.437187 -7.782090 8976 10.770823 -19.428442 -7.096459 8977 31.282639 -23.694412 -13.456718 8978 31.969652 -24.195465 -13.297878 8979 34.086464 -25.150192 -12.500761 8980 32.550873 -24.757324 -12.725342 8981 34.937653 -23.990509 -13.242676 8982 53.085358 -23.579559 -12.976185 8983 12.214465 -20.156202 -8.047489 8984 13.401447 -21.164139 -7.964203 8985 13.010243 -20.674597 -8.198851 8986 12.525709 -20.821241 -7.653304 8987 15.929054 -21.310677 -8.617413 8988 51.008636 -24.782425 -12.625946 8989 56.308563 -25.608810 -12.612778 8990 13.905389 -20.840977 -8.535559 8991 51.507751 -26.641968 -13.960062 8992 60.165314 -24.875565 -13.379105 8993 60.978882 -25.419312 -13.405567 8994 68.029495 -24.263443 -11.582680 8995 40.610962 -27.043808 -14.638428 8996 41.140533 -26.912201 -14.677181 8997 50.805145 -26.725998 -13.259850 8998 61.717514 -26.400620 -13.642330 8999 60.821869 -26.131424 -13.098213 9000 67.496887 -28.265167 -13.163017 9001 67.562973 -28.899445 -12.320816 9002 67.867477 -26.904465 -12.157818 9003 20.260895 -27.161728 -13.450527 9004 20.816200 -28.212814 -13.817329 9005 59.404663 -27.859039 -13.543427 9006 59.377853 -27.096802 -13.047134 9007 59.866562 -26.236542 -12.648621 9008 58.996475 -26.691940 -12.547516 9009 22.778656 -29.016327 -14.387566 9010 23.876129 -29.100113 -14.335407 9011 24.758842 -29.094498 -14.284252 9012 32.081497 -28.762344 -14.079258 9013 41.926331 -28.605026 -14.721653 9014 51.149506 -29.317978 -13.075050 9015 53.047607 -31.975479 -12.695599 9016 54.524872 -31.056900 -13.245106 9017 53.385788 -30.322662 -12.408440 9018 57.726913 -29.036423 -13.650837 9019 58.137863 -27.585236 -12.992641 9020 21.854111 -29.043198 -13.939575 9021 21.424347 -29.699158 -13.096760 9022 25.552605 -29.527832 -13.610477 9023 32.110458 -29.364349 -13.614494 9024 66.990082 -29.335114 -13.589989 9025 39.483032 -31.727264 -14.436253 9026 51.387421 -33.532379 -13.277828 9027 55.484406 -30.297836 -13.532394 9028 55.719543 -29.350052 -13.241203 9029 56.636505 -28.580643 -13.180279 9030 39.817154 -31.800659 -14.286018 9031 39.465775 -32.358368 -14.464180 9032 39.908012 -32.267090 -14.286705 9033 39.822342 -32.891479 -14.578796 9034 60.243896 -32.334137 -14.141502 9035 67.081909 -30.321640 -12.543163 9036 25.287041 -35.038498 -14.567692 9037 26.291420 -35.861572 -13.524323 9038 33.295883 -33.435623 -13.713074 9039 33.761459 -33.475800 -13.048275 9040 52.853195 -33.764679 -13.016422 9041 54.431656 -32.542725 -13.613159 9042 54.329834 -34.051102 -13.819283 9043 60.223587 -34.217773 -13.486298 9044 60.575348 -34.257248 -14.179882 9045 66.341217 -33.344315 -13.448322 9046 66.746796 -32.018219 -12.799911 9047 23.830673 -37.045319 -14.366852 9048 24.295395 -36.270248 -14.242165 9049 62.788651 -34.108963 -13.729481 9050 63.597015 -34.532074 -13.840305 9051 66.152527 -34.489365 -13.344460 9052 66.895615 -33.591064 -11.749458 9053 65.470047 -34.851501 -13.833122 9054 64.208466 -35.090424 -13.785561 9055 63.791473 -35.574417 -13.353104 9056 64.906769 -35.793793 -13.356007 9057 66.470551 -35.148712 -12.432819 9058 65.818115 -35.379684 -13.264751 9059 23.980499 -37.342346 -13.464993 9060 23.968552 -37.750092 -14.705597 9061 23.718948 -37.603104 -14.221565 9062 60.739258 -36.527298 -13.342564 9063 61.837158 -37.338028 -13.951805 9064 24.299019 -38.965408 -14.708107 9065 23.664421 -38.465958 -13.936138 9066 52.157715 -37.391586 -13.371403 9067 54.139328 -37.177292 -14.134026 9068 51.861359 -38.205399 -13.522205 9069 54.023956 -38.220383 -14.148911 9070 64.877502 -39.147598 -14.093311 9071 50.476624 -42.202530 -14.287506 9072 65.669159 -40.429565 -14.030611 9073 24.960358 -39.937485 -14.861629 9074 41.485504 -41.631485 -14.530302 9075 42.507172 -41.217758 -14.678894 9076 41.875259 -41.320282 -14.660259 9077 43.635147 -43.021393 -14.057861 9078 50.344147 -41.652496 -14.407719 9079 53.164886 -42.715530 -13.619026 9080 53.016510 -43.891449 -13.909302 9081 53.712921 -43.808670 -14.537048 9082 66.027924 -42.170883 -13.936657 9083 24.789688 -43.600739 -13.220036 9084 26.008682 -42.129608 -14.234150 9085 24.081116 -42.189392 -13.386330 9086 40.452423 -43.764267 -13.948250 9087 50.660034 -42.988937 -13.971325 9088 30.375938 -43.254898 -15.002842 9089 33.300247 -44.070923 -14.042557 9090 31.104805 -43.725861 -14.079079 9091 32.221985 -43.977478 -13.695492 9092 34.148895 -43.987427 -14.952763 9093 43.627563 -44.318680 -13.897888 9094 50.310120 -43.998199 -15.183678 9095 50.619751 -43.779694 -14.687447 9096 54.401245 -43.850037 -15.034691 9097 65.785156 -43.034180 -13.602875 9098 34.257500 -44.597061 -14.111404 9099 34.727150 -45.415359 -13.847321 9100 34.790909 -44.893219 -14.937084 9101 35.030060 -45.525833 -15.380264 9102 65.561218 -45.105362 -14.002129 9103 65.856476 -44.176697 -13.562576 9104 34.832413 -46.236008 -14.786919 9105 40.702942 -46.336441 -14.702797 9106 40.929245 -47.456528 -14.150612 9107 64.915176 -46.414886 -14.055035 9108 34.801712 -47.183090 -14.047611 9109 64.768982 -46.942352 -13.538715 9110 65.074066 -46.488525 -13.542400 9111 44.056641 -46.432602 -13.721756 9112 63.471405 -48.252777 -13.793842 9113 63.806183 -47.924927 -13.703316 9114 34.857864 -46.227982 -14.025845 9115 34.525406 -48.405807 -14.119152 9116 41.496872 -48.574722 -14.313377 9117 61.882309 -49.724579 -14.938782 9118 62.337799 -48.696503 -15.049572 9119 34.033913 -49.348862 -14.315548 9120 34.336578 -48.701843 -13.727264 9121 33.852051 -48.742905 -13.496170 9122 41.441223 -49.866852 -13.925571 9123 41.845367 -49.393509 -14.325756 9124 42.173279 -50.512344 -14.745583 9125 44.958069 -48.858826 -13.990318 9126 42.695419 -50.907303 -15.461266 9127 33.651337 -51.421677 -15.603809 9128 32.954575 -52.277298 -14.628349 9129 33.636589 -53.148117 -16.043251 9130 46.467499 -52.392731 -14.994629 9131 52.285736 -52.398178 -14.312973 9132 54.871216 -50.884094 -14.159218 9133 55.141739 -51.770493 -14.680130 9134 54.023392 -50.075974 -13.694763 9135 42.877258 -55.033997 -16.059647 9136 57.304245 -52.226532 -14.208084 9137 56.196838 -52.425003 -14.780796 9138 56.645538 -51.431641 -13.820721 9139 55.748779 -51.080139 -13.925587 9140 60.202332 -53.199280 -14.954899 9141 60.771927 -52.258759 -14.468822 9142 60.471558 -51.647141 -13.903946 9143 45.973938 -55.140640 -14.315186 9144 45.680084 -55.877716 -14.647617 9145 46.406387 -55.685669 -15.123436 9146 53.510880 -55.568604 -15.016644 9147 32.762123 -54.956818 -15.234650 9148 42.308838 -53.718063 -15.249512 9149 47.008118 -54.724762 -15.593800 9150 46.376038 -56.821014 -15.685883 9151 57.393524 -53.175842 -14.867249 9152 32.647522 -53.424210 -14.625740 9153 52.604401 -53.689194 -14.588665 9154 53.150620 -54.659790 -14.314030 9155 59.559265 -52.521515 -14.112053 9156 42.775406 -56.435974 -15.735710 9157 45.165894 -56.671539 -14.691589 9158 44.661041 -57.349747 -14.396072 9159 56.850128 -56.606522 -15.027687 9160 57.551697 -56.623718 -14.990452 9161 33.535736 -58.619904 -14.663929 9162 33.432083 -58.083221 -15.355778 9163 32.586594 -57.854507 -14.859070 9164 34.153732 -58.181290 -15.705868 9165 45.823334 -56.621262 -15.148357 9166 54.174713 -56.421082 -15.280540 9167 54.037201 -55.279053 -14.082878 9168 53.877762 -54.502335 -12.978664 9169 54.228180 -56.882492 -15.704937 9170 56.012665 -56.895767 -15.410915 9171 57.543427 -56.654053 -14.534912 9172 31.717211 -57.826523 -14.429787 9173 31.812243 -58.331879 -14.197369 9174 33.512901 -57.626740 -15.705990 9175 34.780350 -58.719833 -15.971390 9176 35.164276 -59.677277 -15.941971 9177 45.535568 -59.095169 -15.042908 9178 45.202026 -58.700272 -14.625626 9179 45.766602 -59.303314 -14.189095 9180 57.780899 -59.445175 -14.915661 9181 43.469055 -60.582062 -15.596130 9182 46.389984 -60.241089 -14.442020 9183 47.304520 -60.919327 -14.473816 9184 46.620239 -60.996246 -15.670319 9185 56.918335 -61.879547 -14.947746 9186 57.435867 -60.827530 -14.966034 9187 57.736298 -60.170486 -15.302952 9188 57.746246 -60.180801 -14.757492 9189 34.217636 -61.410934 -14.750187 9190 42.804779 -61.463791 -15.166401 9191 44.447479 -62.152222 -16.722992 9192 42.836700 -62.804718 -16.242615 9193 55.967041 -63.056625 -15.892044 9194 41.772400 -63.520874 -15.663540 9195 41.043396 -64.742004 -15.605556 9196 40.901810 -63.977386 -14.655766 9197 41.361435 -63.167130 -14.572788 9198 41.101166 -65.478149 -16.258949 9199 49.289062 -62.161423 -15.015030 9200 55.151093 -63.808884 -15.648479 9201 54.783691 -64.082764 -15.111996 9202 55.702820 -63.413651 -15.731842 9203 33.808960 -65.102280 -16.214603 9204 33.569504 -63.674774 -15.430595 9205 32.952423 -64.788574 -15.334267 9206 33.902122 -66.452057 -16.559708 9207 33.964806 -67.956100 -16.777744 9208 51.393738 -64.038757 -16.436863 9209 32.792717 -65.993301 -15.714779 9210 32.811134 -67.343002 -16.113781 9211 40.195114 -67.797943 -16.843803 9212 35.485001 -67.744965 -17.174263 9213 40.281052 -66.013306 -15.576591 9214 39.844238 -67.201141 -15.967026 9215 33.582474 -69.055649 -16.792004 9216 39.436539 -68.666489 -16.857193 9217 39.070305 -68.354141 -16.052837 9218 38.840309 -69.581192 -16.592255 9219 33.421913 -71.719284 -16.760384 9220 32.183731 -70.795639 -16.270485 9221 32.216797 -72.056442 -16.189178 9222 30.030922 -68.764053 -14.691795 9223 30.864319 -68.681107 -15.285435 9224 30.198997 -67.014069 -14.099312 9225 44.948822 -69.494904 -15.922630 9226 44.161255 -69.615570 -15.783596 9227 45.053650 -70.306183 -15.926414 9228 44.954285 -68.988968 -15.769341 9229 45.319305 -68.447144 -15.498291 9230 44.484665 -68.383438 -15.605961 9231 33.601913 -70.078110 -16.816917 9232 34.658707 -72.606461 -16.942062 9233 38.438927 -69.945297 -15.860878 9234 44.592773 -70.811600 -15.982338 9235 44.926331 -70.944382 -16.206467 9236 45.063858 -71.041412 -15.947235 9237 45.295700 -70.946701 -15.204193 9238 45.468735 -70.229996 -15.196320 9239 32.794273 -72.768280 -16.362724 9240 32.320251 -68.977310 -16.182526 9241 35.825867 -72.876068 -16.898899 9242 37.760239 -71.555145 -16.174683 9243 37.424141 -72.446701 -16.158691 9244 45.431427 -69.350204 -15.263336 9245 33.024597 -74.049881 -16.195507 9246 33.881256 -75.357529 -15.917149 9247 34.635574 -73.968582 -16.478550 9248 33.678917 -73.065063 -16.663635 9249 36.802795 -73.324936 -16.453979 9250 44.862778 -71.195786 -16.049011 9251 36.585190 -74.126114 -16.261108 9252 37.080063 -74.056137 -15.903076 9253 35.936333 -74.099991 -16.384922 9254 37.426453 -73.961014 -15.337051 9255 37.363922 -73.292191 -15.603043 9256 9.191681 60.335815 -7.681335 9257 9.952530 60.837280 -6.980057 9258 11.990448 60.172424 -7.330772 9259 10.884979 60.770554 -7.377777 9260 7.674713 59.352631 -7.989624 9261 7.137512 58.785400 -8.106674 9262 8.779228 59.905548 -7.151611 9263 7.355492 58.108566 -6.991615 9264 5.687317 57.183304 -8.076492 9265 6.272904 57.223938 -7.292198 9266 12.880249 59.201294 -7.282547 9267 4.652687 55.069031 -7.595505 9268 5.310288 55.017487 -6.673767 9269 4.545807 55.026505 -8.347839 9270 12.741081 55.228958 -7.872948 9271 19.412537 55.386581 -7.598755 9272 20.260857 56.399902 -6.831345 9273 18.807625 56.291901 -6.744057 9274 21.370544 55.015976 -8.028557 9275 22.033173 55.498795 -7.622749 9276 21.477295 55.846252 -7.245651 9277 20.538086 55.396744 -7.765129 9278 22.629189 55.534134 -6.816490 9279 23.306000 55.444565 -5.501495 9280 22.029251 55.443939 -4.894722 9281 13.490616 55.064377 -6.641022 9282 13.430649 55.957733 -6.991287 9283 18.116699 55.470657 -6.666519 9284 18.666367 54.575470 -7.623596 9285 23.964005 55.436249 -6.554359 9286 17.397079 52.311081 -6.756378 9287 25.007156 53.236267 -8.001350 9288 25.079781 54.427643 -7.354767 9289 4.546608 53.879517 -7.847755 9290 4.623657 52.317932 -7.361313 9291 12.476318 53.803925 -7.563454 9292 12.779510 52.703476 -6.723915 9293 13.755989 53.801971 -5.817978 9294 18.502457 53.760132 -7.743507 9295 26.258987 53.807266 -7.260841 9296 26.090927 52.729614 -7.888489 9297 28.043045 54.195053 -6.386093 9298 26.743011 54.698090 -6.515465 9299 12.610916 51.376038 -8.272507 9300 25.728447 51.827759 -8.147736 9301 27.496529 52.336624 -7.457077 9302 13.391113 50.942032 -8.792007 9303 13.003326 50.825684 -7.444870 9304 18.683228 50.495590 -7.341461 9305 19.374863 49.650223 -7.332809 9306 4.253075 49.422775 -8.887604 9307 13.946747 49.961060 -7.943931 9308 20.535492 49.596985 -8.310806 9309 3.972412 48.480591 -8.729401 9310 4.542008 49.148682 -7.841858 9311 4.659584 47.992844 -7.858704 9312 4.510094 50.387283 -7.923157 9313 21.675438 48.677017 -8.533600 9314 3.932983 47.560669 -8.781784 9315 9.660889 45.779694 -9.931385 9316 21.709793 47.767075 -8.216843 9317 26.676453 48.853180 -8.284622 9318 27.068314 47.878952 -8.211960 9319 28.137131 47.445816 -7.374199 9320 27.859314 48.680618 -7.654694 9321 3.708275 44.664429 -9.593719 9322 18.241348 45.794464 -8.545448 9323 23.714706 44.558075 -8.732956 9324 29.095169 47.867844 -6.407417 9325 28.750793 48.549011 -6.994354 9326 32.624275 44.843811 -8.216522 9327 31.595123 44.961990 -7.354019 9328 31.812777 43.746460 -7.889549 9329 33.035706 47.426086 -7.475159 9330 32.601234 46.138916 -7.799133 9331 33.574333 45.813049 -8.212105 9332 34.657921 45.365402 -8.386276 9333 35.793564 45.676437 -7.856056 9334 34.495895 46.704971 -7.764152 9335 3.775795 45.550583 -9.446674 9336 18.868149 44.827667 -8.786514 9337 23.069748 44.583038 -8.203293 9338 28.042877 46.106247 -7.341202 9339 36.367844 44.535309 -8.360504 9340 3.966339 44.724533 -8.945709 9341 3.901726 43.843735 -9.219269 9342 27.174530 43.273392 -8.357971 9343 28.029739 43.999481 -7.487060 9344 28.366997 45.002426 -6.951469 9345 37.419342 44.780731 -7.763626 9346 3.875488 43.004440 -8.431519 9347 19.486397 42.377075 -8.302727 9348 18.922668 43.861176 -7.873199 9349 23.368591 43.291885 -7.861664 9350 28.049911 41.764252 -7.551498 9351 26.307465 41.925110 -8.618820 9352 28.354118 42.987823 -7.048126 9353 31.605822 42.942276 -8.041840 9354 32.045769 42.889862 -8.568314 9355 38.874802 43.006393 -8.157265 9356 39.041031 43.860764 -7.840729 9357 20.321640 41.651337 -9.245731 9358 20.260513 40.994995 -8.610641 9359 31.752748 42.132919 -8.278610 9360 36.999664 40.641876 -8.456123 9361 2.902077 42.945435 -7.211319 9362 3.036614 41.684631 -8.277283 9363 10.622978 40.540207 -10.245304 9364 19.854530 40.867004 -7.781357 9365 19.320602 41.693939 -7.043808 9366 25.290634 41.042145 -8.454727 9367 24.674164 42.113556 -8.347008 9368 39.167511 42.198242 -7.476013 9369 37.941360 41.051056 -7.209366 9370 2.926697 39.854904 -9.312469 9371 20.821686 39.449875 -8.178558 9372 25.018394 39.972961 -7.966415 9373 31.533333 39.987762 -8.005913 9374 35.994354 39.721375 -8.658081 9375 36.689819 40.076752 -7.481933 9376 22.223816 37.658539 -8.851486 9377 30.275803 37.422485 -9.500988 9378 30.788841 37.921021 -8.758530 9379 31.767389 38.714417 -8.564316 9380 42.320709 38.183578 -8.831078 9381 43.146851 38.460815 -8.444969 9382 44.103516 38.656586 -8.037750 9383 43.326630 39.070267 -7.799209 9384 2.388580 38.326385 -9.238380 9385 2.282860 35.987213 -9.401897 9386 21.328293 37.961472 -7.214950 9387 22.220451 36.744080 -7.268066 9388 23.057587 37.152771 -9.674263 9389 31.434311 37.983093 -8.733833 9390 31.237122 38.147476 -8.407028 9391 36.446457 36.272446 -8.018860 9392 40.443375 37.697449 -8.713531 9393 40.426987 38.091705 -7.977142 9394 42.038055 38.940155 -7.624931 9395 47.738403 36.306519 -8.040970 9396 37.255722 36.172089 -9.511265 9397 39.454292 33.334976 -8.770599 9398 38.974197 35.117294 -8.299072 9399 2.883675 34.793854 -9.800186 9400 23.687805 34.571045 -8.311691 9401 26.253113 35.149353 -8.830872 9402 26.591057 35.279068 -9.416866 9403 27.072449 34.952530 -9.818523 9404 37.019951 34.861603 -8.792381 9405 24.264969 34.552643 -9.502396 9406 24.547073 33.842773 -9.406471 9407 26.771164 34.528168 -9.247032 9408 27.356857 33.273926 -9.117676 9409 36.946465 34.613449 -7.974289 9410 36.841393 35.517319 -7.790863 9411 39.049744 33.863831 -7.733688 9412 48.035522 35.360474 -8.355835 9413 26.350174 34.212128 -8.119614 9414 37.157684 33.961456 -8.236496 9415 47.926697 33.615295 -8.685738 9416 25.109360 32.133209 -9.847618 9417 47.811707 32.414612 -8.472580 9418 24.465729 32.671478 -8.869072 9419 28.645020 32.160202 -9.201405 9420 29.739639 31.663788 -8.241379 9421 32.037262 31.321854 -9.364590 9422 33.985565 31.448151 -8.342422 9423 33.891235 31.492523 -9.087498 9424 33.076065 31.272995 -8.413040 9425 34.740250 31.468018 -9.151928 9426 40.299469 30.719589 -9.311863 9427 40.038452 31.570206 -8.280441 9428 4.050980 32.249374 -9.832581 9429 5.092415 29.776978 -10.222240 9430 5.227356 31.227203 -9.596512 9431 6.436829 30.356506 -9.354073 9432 24.489899 31.331161 -9.276875 9433 31.520538 31.520645 -8.179008 9434 35.769852 31.352203 -8.974854 9435 47.965454 31.452728 -7.611923 9436 48.296143 32.512848 -7.226898 9437 4.315117 29.328064 -10.896114 9438 6.070259 28.995865 -10.023441 9439 6.775200 27.992920 -9.829823 9440 5.936386 28.055450 -10.476681 9441 26.478073 28.061401 -10.428455 9442 26.786102 29.112366 -8.727036 9443 35.810349 29.278198 -10.024952 9444 40.574371 29.964478 -8.325623 9445 40.699646 29.158356 -9.284157 9446 23.626015 30.555115 -8.596771 9447 28.726074 29.472839 -7.807533 9448 27.130051 29.359344 -7.708298 9449 32.007195 28.503571 -8.604797 9450 33.438126 28.283798 -9.380112 9451 34.073105 27.950562 -8.926773 9452 35.902328 28.994110 -9.800533 9453 36.899124 28.704361 -9.351372 9454 38.310707 28.241180 -9.382912 9455 37.449265 28.470535 -8.710716 9456 40.714478 27.702042 -9.047771 9457 6.876068 26.946426 -9.890820 9458 13.972885 27.097351 -10.097832 9459 33.092468 28.006332 -8.279022 9460 35.079544 28.122406 -8.496140 9461 34.532867 27.729950 -8.345596 9462 40.368774 27.690277 -9.505798 9463 40.361786 27.418472 -9.206017 9464 6.772049 25.367340 -8.320724 9465 6.758415 24.549286 -8.932770 9466 12.442200 25.198181 -9.829266 9467 21.149002 26.625275 -9.670490 9468 11.733887 24.168182 -10.039665 9469 13.369789 25.608490 -9.559925 9470 42.449615 23.704422 -9.278194 9471 42.234589 23.730988 -9.189430 9472 42.444550 24.018600 -8.977692 9473 42.790833 23.647034 -8.955544 9474 3.125725 21.672821 -9.786190 9475 3.786713 23.025116 -9.407055 9476 5.954681 23.657272 -9.489979 9477 5.660515 23.486557 -9.568272 9478 42.383865 23.467560 -9.039951 9479 44.260254 22.626007 -9.918331 9480 45.263763 22.758148 -9.568981 9481 46.052734 22.947922 -9.596123 9482 46.657166 23.159821 -9.324989 9483 48.576538 23.728897 -8.227661 9484 47.637131 23.421844 -8.636276 9485 13.687088 21.688904 -8.688553 9486 13.751663 19.812988 -8.895454 9487 19.478806 22.661331 -10.009666 9488 22.505203 22.814774 -9.116226 9489 21.269180 22.409729 -9.045483 9490 23.265762 22.617294 -10.080326 9491 46.103333 22.511322 -9.033249 9492 29.296158 20.597107 -9.865486 9493 13.626709 19.398239 -10.165321 9494 19.990112 20.878906 -10.171013 9495 30.726036 19.227631 -9.417797 9496 31.346603 18.600403 -9.892220 9497 30.081345 20.021423 -9.499481 9498 44.220337 18.074692 -9.103756 9499 9.498489 17.471130 -10.553436 9500 48.542313 17.527008 -10.047424 9501 9.814514 16.719727 -9.668724 9502 32.974312 17.280396 -7.471084 9503 34.115829 17.009384 -8.404236 9504 32.449036 17.695831 -9.000690 9505 34.077011 17.249222 -9.760941 9506 48.504333 16.457031 -9.622604 9507 9.419868 15.595398 -10.126118 9508 9.000587 14.940933 -10.867714 9509 15.651009 16.342926 -9.322033 9510 16.017349 15.971100 -9.769447 9511 15.314636 16.543945 -10.211113 9512 15.145219 16.893402 -9.025177 9513 15.912056 16.042465 -10.435047 9514 24.740219 15.741074 -10.267483 9515 25.155327 16.609100 -10.425655 9516 35.631653 16.806396 -10.090252 9517 36.981483 16.708542 -10.433609 9518 38.994339 16.348480 -10.306992 9519 39.672684 16.258377 -10.085194 9520 40.639038 16.298203 -10.193176 9521 52.909912 17.087219 -7.905495 9522 5.257271 15.100754 -9.197655 9523 6.072090 14.645081 -9.257553 9524 5.549774 14.937500 -10.000599 9525 8.616211 14.366394 -10.748329 9526 16.259842 15.652374 -10.342590 9527 24.877289 14.593109 -9.924500 9528 24.691071 15.894104 -9.434929 9529 38.062057 16.355270 -10.098545 9530 55.265228 15.165237 -9.385395 9531 7.991500 13.978943 -10.189201 9532 9.017150 14.030685 -9.854664 9533 47.533356 13.886841 -9.298977 9534 17.446075 13.525391 -11.027351 9535 27.734123 11.798645 -10.583221 9536 27.611206 13.064865 -10.068680 9537 26.695053 12.461472 -10.242439 9538 26.753647 13.780884 -9.555794 9539 29.620483 13.742950 -9.482864 9540 28.652168 12.918030 -10.170895 9541 29.402046 12.747635 -10.278076 9542 29.968216 12.592255 -10.178146 9543 55.966965 14.142181 -8.026291 9544 55.575989 14.831192 -8.860428 9545 8.781921 12.339951 -10.289055 9546 8.230453 12.031677 -10.481812 9547 8.725891 11.722656 -10.906231 9548 12.200455 11.488708 -11.050247 9549 12.910110 11.385925 -10.973263 9550 12.692520 11.922333 -10.523209 9551 11.819107 12.027008 -10.552139 9552 13.647079 11.400726 -10.355900 9553 13.509979 10.742096 -11.071045 9554 29.297272 11.582001 -10.566296 9555 30.457520 11.745132 -10.386204 9556 30.513260 12.402618 -10.100769 9557 46.144623 12.210388 -10.327370 9558 46.781281 12.812668 -9.758026 9559 55.527588 12.976959 -9.737965 9560 7.501587 10.945618 -10.923115 9561 11.495308 10.795959 -11.209061 9562 13.195953 12.143204 -9.767834 9563 26.999039 11.002563 -10.752651 9564 30.370529 10.748169 -10.431900 9565 31.329254 11.297287 -10.382050 9566 32.410263 12.009033 -9.981415 9567 31.138664 12.333527 -10.062138 9568 31.962534 11.057159 -10.336090 9569 46.389450 11.778778 -9.408157 9570 7.208580 10.493134 -10.681992 9571 16.216133 10.329742 -9.614265 9572 15.410507 11.039490 -9.200050 9573 20.591766 9.045197 -11.297939 9574 26.760231 11.594543 -10.561234 9575 28.088104 10.593201 -10.752102 9576 29.187317 10.210358 -10.426407 9577 27.851669 9.563019 -10.580299 9578 32.461624 10.666641 -10.150642 9579 31.451462 10.316528 -10.225178 9580 32.441650 8.853409 -9.876408 9581 34.176819 10.845520 -9.757706 9582 54.859665 8.925629 -10.342106 9583 16.157951 11.584793 -8.522217 9584 16.135597 9.341522 -10.669994 9585 16.147186 9.660690 -10.321575 9586 17.059631 9.278198 -10.250591 9587 17.251930 10.923004 -9.092384 9588 20.155350 9.797516 -10.602470 9589 27.839302 7.145630 -8.798660 9590 28.663605 8.097733 -9.258244 9591 27.123131 8.270905 -10.030468 9592 12.079142 7.403867 -10.333117 9593 13.468348 7.387857 -10.604404 9594 16.056061 8.553970 -10.948505 9595 15.971115 7.316055 -10.966476 9596 17.292450 7.319931 -10.702827 9597 18.523529 7.332672 -10.756004 9598 18.195335 8.417023 -10.580593 9599 18.490013 10.160522 -9.581760 9600 19.559128 10.055099 -9.979321 9601 19.501907 8.457413 -10.731895 9602 20.437027 7.995941 -11.263977 9603 25.908638 8.541260 -10.875317 9604 25.766136 7.158401 -9.578964 9605 26.574356 9.084076 -10.903652 9606 10.967690 7.987100 -10.592422 9607 13.924105 6.189297 -9.901295 9608 14.705681 5.696376 -9.705425 9609 14.865513 6.422724 -10.166358 9610 19.395523 6.857208 -10.491909 9611 20.329758 7.228531 -10.867085 9612 21.068680 7.440643 -11.262890 9613 22.006256 7.289795 -11.055054 9614 23.282684 7.406631 -10.941032 9615 43.021042 6.621201 -10.669960 9616 54.953995 7.750610 -9.575466 9617 55.760895 8.687744 -9.249058 9618 56.149597 9.688751 -9.219460 9619 15.101067 6.898193 -10.625961 9620 16.343353 6.302933 -10.189644 9621 18.344818 6.168457 -9.873436 9622 21.380753 6.765457 -10.464287 9623 22.708084 6.603470 -9.987732 9624 34.223145 6.379181 -10.382351 9625 36.584618 5.985870 -9.484322 9626 53.191574 5.721527 -10.061302 9627 37.823601 5.314789 -8.471657 9628 37.000656 6.599136 -8.835945 9629 42.263092 3.833099 -10.843716 9630 56.736938 3.572876 -11.545074 9631 41.990631 2.643127 -10.938797 9632 57.075500 2.481567 -11.451862 9633 49.444092 1.308212 -10.766132 9634 58.226151 0.245056 -10.635624 9635 59.205551 0.529709 -10.924820 9636 58.916428 -0.453018 -10.283802 9637 57.696259 -0.908188 -10.619690 9638 39.897659 -1.081665 -10.407999 9639 60.213547 -1.033249 -10.290333 9640 62.349045 -3.276443 -11.327724 9641 62.383224 -4.120178 -10.240685 9642 61.514771 -2.498291 -10.510277 9643 60.837601 -2.401077 -9.661541 9644 59.956421 -1.910629 -9.628067 9645 40.216843 -1.555176 -10.691534 9646 57.043762 -2.464767 -10.895512 9647 58.675110 -2.543137 -9.887180 9648 25.978716 -2.605755 -11.121000 9649 26.061581 -3.538013 -11.675676 9650 27.497921 -0.739139 -10.460915 9651 26.348297 -1.484875 -10.576031 9652 28.751560 -0.491082 -10.898544 9653 47.044189 -3.098831 -11.213699 9654 57.041122 -3.503845 -10.648643 9655 57.660095 -3.105682 -10.326374 9656 47.130676 -2.299545 -11.133537 9657 56.495239 -4.634445 -10.940079 9658 56.389297 -3.415802 -11.206909 9659 57.858765 -3.927322 -10.106468 9660 57.785065 -5.258194 -10.117565 9661 48.160797 -5.139023 -10.953491 9662 63.249664 -5.584351 -10.087311 9663 63.983002 -5.907120 -11.420731 9664 46.407944 -6.601944 -11.336716 9665 56.544708 -6.449966 -10.814686 9666 64.378677 -7.190369 -10.146301 9667 45.704941 -8.304764 -11.715794 9668 56.108475 -8.022446 -11.133949 9669 57.129089 -9.120407 -11.143444 9670 57.071411 -7.744995 -10.877327 9671 57.970581 -7.918839 -10.875175 9672 58.597351 -7.913864 -10.916313 9673 58.965881 -8.288177 -10.792202 9674 58.300522 -8.539352 -11.055161 9675 65.041382 -8.130920 -10.936157 9676 20.085205 -8.288170 -10.897427 9677 23.860746 -8.461240 -12.141838 9678 21.741920 -8.887915 -11.424221 9679 23.132097 -8.151284 -11.730230 9680 22.553417 -8.775440 -11.662945 9681 24.535643 -8.922860 -12.653336 9682 24.428965 -8.208469 -12.389400 9683 24.831776 -8.275381 -12.668711 9684 55.535675 -9.195190 -11.433075 9685 58.524384 -9.707306 -10.657349 9686 65.453125 -9.279449 -11.415207 9687 13.679209 -9.795629 -9.797639 9688 13.030778 -9.092773 -9.419748 9689 13.551419 -10.550534 -9.912369 9690 18.111713 -8.980567 -10.688152 9691 25.075937 -7.730347 -12.668514 9692 56.273575 -10.883163 -11.108749 9693 57.491409 -10.711502 -10.713017 9694 65.453812 -9.541733 -10.178745 9695 10.906740 -11.902236 -9.029088 9696 10.725377 -10.496040 -8.580170 9697 11.604812 -10.629376 -9.126945 9698 11.575515 -9.747238 -8.901749 9699 10.994446 -11.216757 -8.917281 9700 14.610583 -9.330100 -9.984410 9701 14.444949 -10.726401 -10.205199 9702 15.304755 -10.453422 -10.382240 9703 25.433004 -7.628794 -12.917999 9704 58.734238 -11.537048 -9.735542 9705 9.374366 -11.154245 -7.676896 9706 9.117510 -12.248093 -7.561605 9707 9.905678 -10.354582 -7.974826 9708 15.348909 -11.648208 -10.573683 9709 46.130981 -12.772720 -11.850746 9710 52.321564 -12.106781 -12.076077 9711 53.218445 -13.049866 -11.679131 9712 53.374527 -13.842850 -11.291904 9713 52.632141 -13.900681 -11.605652 9714 9.277025 -13.143751 -7.891031 9715 16.136137 -11.223125 -10.696287 9716 16.286909 -12.395078 -10.860619 9717 22.398779 -14.905174 -11.862722 9718 45.753723 -12.807236 -11.122181 9719 56.144730 -12.690994 -10.411758 9720 66.289810 -13.074966 -11.223213 9721 66.214874 -11.809875 -10.087929 9722 9.156100 -13.961913 -7.837422 9723 9.108454 -14.580652 -7.810979 9724 16.816048 -11.670827 -10.897717 9725 17.051107 -12.322246 -11.009769 9726 46.036133 -13.793777 -11.134567 9727 8.981404 -14.457222 -7.644145 9728 8.822229 -14.279974 -7.363263 9729 23.182175 -15.525169 -11.886734 9730 22.238352 -16.623409 -11.389099 9731 23.180420 -16.316273 -11.653618 9732 48.829819 -15.518677 -11.371334 9733 49.661285 -15.257599 -11.500416 9734 8.982872 -15.010583 -7.507318 9735 21.350500 -16.586464 -11.261467 9736 21.167683 -17.698133 -10.850590 9737 48.615173 -16.637939 -10.315372 9738 47.544250 -16.854248 -10.033535 9739 50.642181 -16.484131 -10.222221 9740 51.836517 -15.643326 -10.649326 9741 51.935455 -16.660477 -9.571693 9742 66.871445 -15.582397 -10.963089 9743 9.160208 -15.691781 -7.541984 9744 20.062805 -18.658751 -10.395594 9745 21.148714 -19.058681 -10.268139 9746 36.323711 -17.812521 -13.259598 9747 9.401648 -16.468288 -7.413075 9748 17.909958 -17.618132 -10.662819 9749 26.945393 -17.851109 -11.722485 9750 35.895458 -18.682386 -12.742920 9751 34.524250 -18.379328 -12.831062 9752 34.771084 -19.457464 -12.033463 9753 36.153763 -19.459225 -12.156324 9754 35.846748 -20.028767 -11.667942 9755 18.804001 -18.735130 -10.326756 9756 22.655394 -17.909283 -10.986227 9757 22.235302 -17.572086 -11.048784 9758 22.387470 -18.156908 -10.835667 9759 23.199669 -17.761889 -11.111229 9760 23.875622 -17.297731 -11.397015 9761 23.130516 -16.981625 -11.412560 9762 23.868786 -18.262899 -10.969767 9763 24.539927 -18.228201 -11.087612 9764 28.121458 -18.487589 -11.617495 9765 29.276745 -18.701757 -11.727903 9766 33.627674 -18.748260 -12.459604 9767 9.894887 -17.424229 -7.439781 9768 18.317907 -19.400246 -9.991774 9769 22.728203 -18.287737 -10.823948 9770 23.105219 -18.564899 -10.730577 9771 24.475685 -18.919542 -10.727953 9772 25.152636 -18.306171 -11.140306 9773 32.635609 -18.211351 -12.757471 9774 67.727997 -19.699203 -10.798244 9775 67.561554 -18.674194 -10.982662 9776 10.031501 -18.923334 -6.515058 9777 9.691751 -17.984705 -6.768551 9778 17.045736 -20.386847 -9.357314 9779 23.295906 -22.328079 -12.635519 9780 25.291443 -22.013290 -12.984341 9781 24.480263 -21.964539 -13.087620 9782 28.103424 -21.885345 -13.418179 9783 36.966095 -21.033844 -10.908684 9784 37.080521 -22.371658 -10.615604 9785 22.257874 -23.252716 -12.355927 9786 21.724976 -24.294357 -12.620766 9787 22.003738 -24.185516 -11.713448 9788 26.009903 -23.180191 -11.698345 9789 26.977104 -22.936478 -12.524017 9790 27.291702 -23.998642 -11.870640 9791 28.042809 -22.538483 -13.036247 9792 28.736526 -23.637512 -12.537903 9793 30.166504 -23.299210 -13.209137 9794 51.932236 -24.067581 -12.647720 9795 51.728668 -23.275085 -13.055439 9796 68.034180 -22.033127 -10.186481 9797 16.220932 -20.756599 -9.076639 9798 21.762741 -24.965485 -12.137840 9799 36.012650 -24.073563 -12.501846 9800 35.422195 -24.824432 -12.434391 9801 36.944321 -23.167740 -11.806206 9802 37.273605 -23.382385 -10.724998 9803 37.065384 -24.015182 -10.856293 9804 11.664035 -20.251791 -7.390616 9805 13.152814 -21.470602 -7.417309 9806 12.207688 -21.132629 -6.993135 9807 30.632126 -24.824905 -12.272133 9808 28.998352 -24.580826 -12.057877 9809 51.894745 -24.817123 -12.147049 9810 52.588776 -24.828369 -12.244759 9811 53.208557 -24.337814 -12.659790 9812 58.775742 -25.419250 -12.436409 9813 59.950623 -25.383255 -12.751129 9814 14.041588 -21.485910 -8.024353 9815 13.957930 -21.723358 -7.658955 9816 14.097471 -21.237055 -8.293123 9817 21.382950 -25.557297 -12.820946 9818 51.053284 -25.859192 -12.076050 9819 51.416595 -24.976898 -12.182560 9820 59.122253 -26.102783 -12.273411 9821 59.513168 -25.721054 -12.330544 9822 68.299713 -25.194397 -12.066166 9823 68.278290 -25.711639 -12.213009 9824 68.416626 -25.474838 -11.997932 9825 14.436100 -21.749895 -7.902496 9826 14.668902 -21.567303 -8.173838 9827 20.069069 -26.956284 -12.992355 9828 19.818771 -27.327667 -12.941055 9829 20.623024 -26.621780 -12.944191 9830 50.833740 -28.427170 -12.502525 9831 50.816086 -27.401901 -11.980137 9832 68.271240 -25.795380 -11.886337 9833 19.890526 -27.930588 -13.066704 9834 57.328766 -26.458252 -12.470367 9835 56.462601 -27.297012 -12.681999 9836 58.294159 -26.308441 -12.372765 9837 22.426094 -29.561630 -13.492649 9838 32.863831 -29.096771 -13.953148 9839 50.685699 -26.603302 -12.400455 9840 55.467865 -28.360641 -12.765541 9841 19.568420 -29.181900 -12.161003 9842 23.289291 -29.743576 -13.383930 9843 24.343903 -29.760010 -13.309654 9844 26.671303 -29.819931 -13.471916 9845 32.047630 -30.750458 -12.736427 9846 33.069077 -29.880051 -13.520554 9847 54.630020 -29.493973 -12.827984 9848 54.445099 -28.241074 -12.329304 9849 54.924210 -26.861755 -12.304714 9850 27.574722 -31.195755 -12.273689 9851 33.700516 -30.294846 -13.562656 9852 67.364548 -29.502853 -11.261253 9853 33.378250 -31.025101 -12.908249 9854 51.442474 -34.464859 -13.244385 9855 33.743462 -32.355576 -12.811123 9856 60.069214 -33.528992 -12.976028 9857 60.447983 -33.261307 -13.218719 9858 32.960297 -34.251740 -13.292892 9859 33.727951 -34.545807 -12.320927 9860 33.376221 -35.464508 -11.764221 9861 32.604568 -35.393829 -12.774784 9862 51.143555 -34.066040 -13.016510 9863 52.995697 -37.275757 -13.563267 9864 53.246674 -36.350418 -13.549213 9865 52.397568 -36.270065 -13.211891 9866 53.098618 -35.238266 -13.307281 9867 59.831741 -34.166351 -12.716156 9868 61.802246 -34.568085 -12.873798 9869 62.989014 -34.844269 -13.321560 9870 66.980240 -30.754913 -10.078289 9871 24.953949 -36.196609 -13.578785 9872 27.829025 -35.653214 -13.697273 9873 29.607689 -35.517273 -13.719082 9874 31.179031 -36.012985 -13.167339 9875 30.091225 -36.775757 -13.025089 9876 28.700958 -36.682068 -13.132130 9877 52.077927 -35.087036 -13.195126 9878 51.514740 -33.930878 -12.811779 9879 60.416840 -33.798035 -12.633579 9880 59.769226 -34.196686 -12.070698 9881 60.410980 -34.591766 -11.938492 9882 61.102982 -35.679199 -11.747566 9883 62.906738 -36.005447 -12.724709 9884 64.061478 -37.150345 -12.443401 9885 29.315445 -37.811646 -12.509518 9886 52.006958 -33.029099 -12.497463 9887 59.534210 -35.062988 -12.158920 9888 62.057541 -36.308319 -12.080391 9889 65.319489 -37.191193 -12.352905 9890 65.940521 -36.128067 -12.600315 9891 23.400452 -38.365540 -12.956078 9892 23.188934 -39.180832 -13.121510 9893 52.932114 -39.460999 -13.561699 9894 52.813507 -38.382507 -13.541260 9895 51.981689 -39.175262 -13.211945 9896 60.057907 -37.184097 -12.775349 9897 59.617142 -36.274536 -12.302925 9898 60.889633 -37.477219 -13.257130 9899 61.772644 -38.523865 -13.310966 9900 60.321213 -38.159119 -12.765854 9901 64.174728 -38.598389 -14.050312 9902 62.848785 -37.511536 -11.820122 9903 65.902832 -38.086319 -11.454418 9904 64.992889 -38.556717 -11.192863 9905 52.100037 -38.257904 -13.264709 9906 52.435745 -39.979599 -13.098598 9907 60.872955 -39.223373 -12.832977 9908 62.028824 -40.060303 -12.879402 9909 60.619507 -40.602829 -12.502666 9910 64.049744 -39.577621 -13.484268 9911 62.901779 -39.528900 -13.299835 9912 23.802826 -40.217712 -13.794823 9913 50.947845 -40.382401 -13.667870 9914 51.326080 -39.793488 -13.409630 9915 52.951035 -40.134308 -13.462227 9916 65.036819 -39.801163 -13.643700 9917 65.460907 -41.287491 -13.229786 9918 24.972015 -41.039017 -14.397514 9919 41.870010 -41.554611 -14.083855 9920 43.574341 -42.043976 -14.261303 9921 42.661011 -41.632050 -13.926224 9922 50.596451 -41.197632 -13.712711 9923 63.384354 -40.915512 -12.843369 9924 41.173126 -42.369354 -13.805565 9925 52.809647 -40.946945 -13.181107 9926 51.822678 -41.983994 -12.764366 9927 50.864197 -42.887543 -13.155231 9928 50.863449 -42.172989 -13.160629 9929 50.989410 -40.417999 -12.913113 9930 51.147888 -41.148193 -12.678940 9931 51.919601 -43.927933 -13.568043 9932 51.960571 -43.117767 -13.120056 9933 51.162537 -43.451050 -13.506424 9934 52.569168 -43.656403 -13.470108 9935 65.837616 -44.778336 -13.458485 9936 40.180542 -45.226547 -13.797245 9937 43.672638 -44.967773 -14.112968 9938 43.587814 -44.811691 -13.845440 9939 43.564972 -45.052704 -13.872353 9940 51.963440 -44.360336 -13.989912 9941 52.476746 -44.255402 -13.901424 9942 65.585892 -45.197449 -13.369087 9943 40.351654 -46.430435 -13.702126 9944 43.746521 -45.374802 -14.026211 9945 65.257507 -45.873413 -13.497345 9946 40.208191 -46.895279 -12.770988 9947 39.963478 -45.915512 -12.988091 9948 40.555969 -47.430328 -13.457909 9949 64.324036 -47.381592 -13.802292 9950 40.876175 -48.770813 -13.623146 9951 44.509491 -47.750259 -13.950584 9952 44.709473 -48.244125 -14.002075 9953 63.118988 -48.467926 -13.803185 9954 45.385681 -49.968414 -13.866375 9955 61.284241 -49.587860 -13.248772 9956 33.001068 -51.186569 -14.235931 9957 33.594498 -50.442001 -14.663155 9958 45.970673 -51.512833 -13.755318 9959 51.846329 -51.011566 -13.667603 9960 51.606064 -52.071960 -13.196709 9961 55.274200 -50.220734 -13.503578 9962 41.639084 -51.742157 -14.380413 9963 52.989288 -51.219131 -14.368034 9964 52.615311 -49.924942 -13.556240 9965 41.624588 -53.004471 -14.696732 9966 41.447083 -50.733826 -14.015282 9967 58.322876 -52.422272 -14.104614 9968 41.075317 -54.322006 -14.737362 9969 40.199524 -52.654419 -13.965946 9970 41.847580 -56.144623 -15.103783 9971 40.902451 -55.529556 -14.646210 9972 46.729843 -53.529984 -14.600330 9973 46.533157 -52.627548 -14.227417 9974 52.093491 -53.078506 -13.506153 9975 39.067139 -54.133759 -13.742420 9976 38.503372 -52.868958 -13.276993 9977 39.988800 -55.205536 -14.194481 9978 46.489594 -54.521942 -14.452068 9979 32.291496 -54.068985 -14.417610 9980 40.720703 -56.616791 -14.347214 9981 39.507233 -56.126083 -13.749165 9982 45.100342 -55.570572 -13.801514 9983 44.182617 -56.645691 -13.407532 9984 44.676651 -56.564941 -14.157921 9985 41.667328 -57.594910 -14.703148 9986 54.481400 -55.876999 -14.519768 9987 55.572617 -56.418594 -14.748077 9988 56.663223 -56.432159 -14.153469 9989 55.530777 -55.718979 -13.311279 9990 57.454178 -57.235275 -13.923134 9991 31.821489 -56.769302 -14.619350 9992 58.481766 -57.499054 -14.382893 9993 40.939438 -58.300644 -13.990173 9994 41.835999 -58.985596 -14.377842 9995 41.015915 -60.124680 -13.563110 9996 44.809875 -58.122406 -14.423840 9997 58.277328 -57.831848 -14.518581 9998 57.772675 -58.394379 -14.312290 9999 34.277527 -59.269119 -14.063663 10000 34.563858 -59.092407 -15.003845 10001 42.545242 -59.658417 -14.739677 10002 57.243530 -59.952087 -14.211727 10003 56.221802 -60.656891 -13.791756 10004 56.405914 -59.690765 -13.378845 10005 34.282967 -60.576996 -14.112865 10006 41.966141 -60.388641 -14.090645 10007 42.964005 -60.411240 -15.017105 10008 42.553192 -60.664230 -14.580879 10009 42.903259 -62.182144 -15.688107 10010 56.727417 -61.240860 -14.323147 10011 42.310989 -62.467468 -15.410000 10012 41.777725 -62.676163 -14.911915 10013 42.107880 -62.049591 -14.787663 10014 50.275772 -62.247421 -14.728844 10015 49.442535 -61.063858 -14.205101 10016 56.485428 -62.600143 -14.851704 10017 56.427216 -62.134537 -14.434933 10018 47.530792 -63.859222 -14.473007 10019 48.142395 -64.251373 -14.723614 10020 48.145355 -64.388367 -14.088200 10021 48.431000 -61.603470 -14.838684 10022 56.126678 -63.115463 -15.167309 10023 32.436783 -64.061569 -14.453205 10024 44.179001 -65.538559 -14.962173 10025 43.204132 -65.132782 -13.890240 10026 43.572418 -66.205460 -14.842392 10027 44.548004 -64.756332 -14.715218 10028 46.833405 -64.013107 -14.864418 10029 45.812683 -64.419510 -14.690838 10030 46.720840 -64.468460 -14.918133 10031 47.848877 -63.654877 -13.643616 10032 47.313751 -63.349274 -13.781143 10033 47.543503 -64.416916 -14.837971 10034 48.198395 -64.393860 -14.905624 10035 48.374619 -64.385544 -14.804604 10036 51.655899 -63.172028 -14.947884 10037 52.948410 -63.680679 -14.804859 10038 53.414581 -64.133621 -15.236084 10039 55.245499 -63.965805 -15.011547 10040 55.617294 -63.609558 -15.015686 10041 32.246269 -65.425812 -14.908260 10042 40.189789 -64.994781 -14.709740 10043 39.479889 -66.106888 -14.601303 10044 38.756409 -66.431732 -14.106285 10045 38.955490 -65.167862 -13.763145 10046 44.638931 -63.752716 -13.709650 10047 44.997711 -65.303223 -15.097603 10048 46.754990 -65.135605 -14.468143 10049 45.537170 -65.505783 -14.967674 10050 47.671234 -64.769150 -14.378269 10051 48.147324 -64.499634 -14.678871 10052 41.943176 -66.720490 -13.887405 10053 41.268005 -67.351151 -13.264420 10054 42.173340 -67.959427 -14.414257 10055 43.655731 -67.363541 -15.176151 10056 45.120728 -67.605789 -15.340973 10057 44.938538 -66.356781 -15.133663 10058 45.948120 -66.172043 -14.465511 10059 45.982147 -65.318924 -14.729496 10060 31.490341 -65.311234 -14.115444 10061 31.746706 -67.015533 -15.255936 10062 38.952530 -67.582626 -15.269951 10063 39.473022 -66.809464 -15.179863 10064 45.602371 -67.140579 -14.875999 10065 38.337219 -68.371307 -15.157303 10066 42.551651 -69.258804 -14.918159 10067 43.316605 -68.625885 -15.325264 10068 45.575745 -68.156708 -14.854290 10069 30.540909 -70.169983 -15.167465 10070 31.302567 -70.139420 -15.798355 10071 38.320068 -69.223297 -15.508099 10072 43.202774 -69.510239 -15.403915 10073 38.071327 -69.988251 -15.281933 10074 42.718521 -70.048721 -15.182922 10075 42.099731 -70.172928 -14.630341 10076 43.267059 -70.184097 -15.474937 10077 31.284645 -71.724426 -15.584572 10078 37.513779 -70.841766 -14.819481 10079 37.452194 -68.689713 -14.053238 10080 37.193542 -72.295929 -14.731319 10081 43.843124 -70.780853 -15.520699 10082 44.678574 -71.494720 -15.429680 10083 30.563972 -71.356171 -14.742855 10084 30.888649 -72.202484 -15.042992 10085 43.622040 -71.632187 -15.153404 10086 32.813423 -75.077759 -15.954090 10087 31.670702 -74.775131 -15.660809 10088 32.627258 -76.063034 -15.669197 10089 31.938601 -73.123184 -15.838505 10090 24.897766 -74.750443 -14.224075 10091 25.949951 -74.045242 -14.336891 10092 25.055771 -73.973373 -13.293991 10093 35.495026 -75.112228 -15.835495 10094 34.740578 -76.317337 -14.946449 10095 36.464920 -74.641434 -15.951134 10096 36.981178 -74.553299 -15.159096 10097 37.402763 -74.074509 -15.032999 10098 27.322128 -74.906952 -15.473202 10099 26.765686 -76.687668 -16.093868 10100 28.063019 -75.739227 -15.910542 10101 27.927223 -75.263107 -15.913921 10102 29.474060 -74.832794 -15.208233 10103 30.924118 -77.056854 -15.389317 10104 28.603683 -77.057556 -15.707802 10105 35.996651 -75.511047 -14.660862 10106 36.324493 -75.103043 -15.511478 10107 25.598328 -76.013565 -15.987003 10108 26.078110 -75.224533 -15.709721 10109 25.408836 -75.321960 -15.744186 10110 24.231636 -78.749985 -15.195427 10111 24.925659 -79.957336 -16.053555 10112 25.296165 -79.227325 -16.220837 10113 27.329529 -78.491745 -15.962723 10114 25.763611 -78.255707 -16.130661 10115 25.186401 -77.057968 -15.688560 10116 28.244949 -74.951370 -15.548624 10117 25.138565 -81.055542 -15.779678 10118 24.187492 -80.184555 -15.555241 10119 23.907822 -81.009583 -15.130749 10120 26.199608 -79.233032 -16.301086 10121 25.615540 -79.852951 -16.332905 10122 25.487564 -80.337738 -16.173439 10123 26.349983 -80.289658 -16.026012 10124 26.909767 -79.430496 -16.082571 10125 27.740623 -79.932541 -15.631870 10126 36.025070 -82.605972 -15.895096 10127 37.143219 -83.581741 -16.394161 10128 37.313560 -82.158524 -15.938629 10129 37.957504 -82.974487 -16.346313 10130 38.344376 -81.999649 -15.900066 10131 38.859894 -83.022766 -16.317966 10132 39.790085 -82.049973 -15.678772 10133 39.608566 -83.132294 -16.179745 10134 32.296944 -86.983734 -16.659210 10135 30.581078 -86.841934 -16.098686 10136 31.522713 -87.837845 -16.533646 10137 36.162872 -84.517197 -16.484787 10138 37.400635 -85.543625 -16.334499 10139 34.816818 -83.915176 -16.283485 10140 33.730545 -83.130081 -15.697666 10141 33.697021 -84.089035 -16.153778 10142 38.422302 -84.253021 -16.391159 10143 39.386147 -83.802032 -16.286110 10144 40.550262 -83.760101 -15.659233 10145 38.710510 -85.545975 -15.825951 10146 39.479347 -84.700287 -15.983097 10147 33.389893 -86.032303 -16.631554 10148 34.011505 -84.984497 -16.513165 10149 32.747459 -84.781631 -16.127525 10150 34.180969 -87.418228 -16.589439 10151 35.285019 -85.990341 -16.586491 10152 36.440079 -85.855194 -16.585947 10153 31.772135 -85.855972 -16.260078 10154 38.666275 -86.015793 -14.685890 10155 39.450157 -85.699448 -15.332558 10156 32.697479 -87.978897 -16.767891 10157 35.160538 -88.065994 -15.811993 10158 33.645676 -88.935959 -16.269833 10159 36.595352 -86.619568 -16.257925 10160 37.301025 -86.650711 -15.761475 10161 37.948074 -86.262619 -15.547104 10162 32.124557 -88.757828 -16.689327 10163 35.173492 -88.762009 -14.833073 10164 32.573723 -89.558273 -16.613075 10165 31.809114 -89.348389 -16.581089 10166 30.475327 -88.643906 -15.759712 10167 29.922340 -89.326401 -14.193707 10168 30.942322 -90.047028 -14.563774 10169 31.870699 -89.985168 -16.010235 10170 32.883842 -90.103867 -16.031805 10171 33.538223 -90.272888 -14.796803 10172 20.724808 -95.564209 -16.981781 10173 22.057968 -95.855774 -17.398254 10174 21.948486 -94.872925 -17.191795 10175 27.483994 -92.271255 -16.886509 10176 28.116257 -93.400040 -16.956936 10177 28.118912 -92.757233 -17.073246 10178 24.504730 -94.603012 -17.353500 10179 23.086327 -95.416580 -17.490425 10180 24.260071 -96.449310 -17.452515 10181 26.727966 -91.552414 -16.719181 10182 27.521500 -91.270828 -15.853725 10183 26.475899 -91.077713 -16.377892 10184 28.388809 -92.618866 -16.738678 10185 26.386993 -92.013885 -17.038704 10186 25.821411 -92.914490 -17.119858 10187 27.050476 -95.157120 -17.220894 10188 24.733215 -91.810257 -16.536858 10189 25.775124 -91.557999 -16.675049 10190 22.631157 -93.894897 -16.931793 10191 23.771896 -92.689316 -16.604622 10192 28.538773 -94.684799 -16.872597 10193 25.727112 -96.685791 -17.114929 10194 29.607231 -93.913162 -15.855495 10195 21.687561 -97.257568 -17.020084 10196 20.305542 -97.331604 -16.784172 10197 23.528885 -96.515182 -17.549137 10198 22.836060 -96.803574 -17.367264 10199 28.298882 -95.480209 -16.864571 10200 22.782806 -98.674606 -16.391590 10201 23.714020 -97.545227 -17.141243 10202 26.953743 -96.522858 -16.992455 10203 30.299133 -95.002014 -15.371578 10204 29.154663 -95.361450 -16.303970 10205 29.375198 -96.287979 -15.512161 10206 28.104591 -96.347641 -16.472404 10207 12.695282 61.444778 -4.965408 10208 11.681480 62.088028 -4.779503 10209 11.807831 61.201447 -6.107902 10210 10.744377 61.308197 -6.505279 10211 9.291039 60.365356 -6.797111 10212 13.561607 59.693619 -5.014557 10213 8.119171 59.173035 -7.182022 10214 13.514648 59.122131 -6.486641 10215 6.355599 56.428864 -6.604538 10216 17.772163 56.550064 -5.709808 10217 21.379700 56.297058 -6.061600 10218 18.856354 57.492096 -5.747925 10219 20.325043 57.185318 -5.690422 10220 19.772430 57.808212 -5.406563 10221 24.701294 55.143631 -6.977646 10222 24.738007 55.508301 -6.344925 10223 25.618942 55.205902 -6.132477 10224 12.310715 52.704590 -7.325874 10225 17.506912 54.421982 -6.399017 10226 17.681480 53.343918 -7.023727 10227 28.694687 51.878479 -7.254791 10228 28.844711 52.611176 -7.091263 10229 28.389954 53.188858 -7.048553 10230 28.982254 53.450897 -6.757553 10231 29.613663 53.936737 -6.168289 10232 29.690292 53.002579 -6.612778 10233 31.035461 53.016434 -5.991302 10234 16.524033 53.490875 -5.496597 10235 16.407928 52.514740 -5.707504 10236 29.625290 51.909332 -6.833725 10237 12.455856 51.873306 -7.462265 10238 28.706497 51.035446 -7.281830 10239 29.616837 48.833755 -6.463287 10240 30.381859 50.205307 -6.653694 10241 28.602020 49.679047 -7.282989 10242 4.487770 51.344666 -7.557907 10243 14.118187 52.005005 -5.610886 10244 13.392410 52.555008 -6.031433 10245 13.101929 51.572906 -6.456436 10246 33.026749 48.966003 -7.085937 10247 31.742723 48.507874 -6.724777 10248 32.557205 50.741455 -6.573273 10249 33.773972 49.759949 -6.960243 10250 34.180122 50.848770 -6.529037 10251 34.760612 49.891663 -6.622421 10252 13.555351 49.990952 -6.678497 10253 14.024948 49.210541 -6.346100 10254 14.004105 49.697144 -5.831695 10255 14.174423 49.235489 -7.141182 10256 15.717880 48.095306 -5.969414 10257 14.663162 48.733582 -6.560913 10258 17.794540 51.095856 -6.827652 10259 34.533829 48.469772 -6.999267 10260 35.479996 47.030441 -7.143539 10261 16.333893 47.351776 -6.890671 10262 20.565414 48.481445 -7.522888 10263 31.937227 46.816650 -7.158401 10264 31.987795 45.756622 -7.584396 10265 35.176575 50.824265 -6.106903 10266 5.343132 48.660553 -7.197891 10267 21.360397 47.192688 -7.391777 10268 35.992111 49.805542 -5.470383 10269 4.789810 46.747513 -7.956909 10270 4.320427 45.527374 -8.544022 10271 5.173691 45.376190 -7.608612 10272 17.866882 45.870270 -7.748840 10273 21.775505 45.958435 -7.012710 10274 31.475418 45.958908 -7.014961 10275 31.235329 46.951538 -6.457535 10276 36.627975 45.941376 -7.097977 10277 36.066925 46.403595 -7.131340 10278 4.382904 44.303802 -8.432617 10279 18.261185 45.079819 -7.439911 10280 22.496613 44.670364 -7.398582 10281 22.267120 43.633362 -6.708176 10282 37.519501 45.900909 -6.290749 10283 38.969040 45.089478 -7.080795 10284 39.771904 45.763229 -6.033577 10285 39.946259 45.026306 -6.994049 10286 40.684174 44.953171 -6.685730 10287 4.663582 44.047424 -7.826164 10288 31.077774 42.943497 -7.082138 10289 40.094971 44.161423 -7.287384 10290 41.118927 45.636536 -5.669800 10291 41.676575 44.845367 -6.239097 10292 41.273376 44.049164 -6.690262 10293 4.196411 43.654678 -7.351829 10294 18.923248 43.076172 -7.070022 10295 28.734245 41.049622 -6.672638 10296 28.873734 41.961151 -6.410812 10297 31.136978 41.783920 -7.208328 10298 31.067535 40.722321 -6.946243 10299 39.344109 43.047028 -7.889351 10300 39.755798 43.217010 -7.595245 10301 40.567642 42.978546 -6.955589 10302 1.989639 39.914551 -6.990539 10303 1.864845 39.571671 -7.868225 10304 2.156120 40.993607 -7.501915 10305 19.555382 40.739594 -6.965408 10306 24.056717 41.378067 -7.648773 10307 2.130615 39.486633 -8.519722 10308 19.972321 39.955887 -7.274925 10309 24.070816 40.093826 -6.932388 10310 28.570190 40.488708 -7.473793 10311 30.972107 39.609924 -7.140411 10312 2.006470 38.601105 -8.415939 10313 29.556137 39.512512 -7.198685 10314 29.155121 40.148926 -6.923508 10315 30.987244 38.542145 -7.962402 10316 44.013351 39.188995 -7.636551 10317 43.747818 39.622742 -7.271637 10318 43.041153 39.416473 -7.410095 10319 44.855988 39.476837 -7.097610 10320 44.041138 40.768890 -6.406006 10321 21.830917 37.268250 -6.440246 10322 30.148483 38.946564 -7.674911 10323 35.738480 38.049698 -7.185715 10324 38.876114 37.888519 -6.857422 10325 46.642044 38.036957 -7.568405 10326 46.268555 38.910416 -6.878464 10327 2.727394 36.048492 -8.919716 10328 2.381981 37.439667 -8.693924 10329 22.859749 36.144196 -8.086151 10330 40.507935 38.685669 -7.152527 10331 48.478806 37.026321 -6.628616 10332 47.984772 37.463806 -7.008530 10333 3.697441 35.194061 -8.599442 10334 3.571907 33.817810 -9.415161 10335 38.364044 36.329071 -7.325981 10336 48.434662 35.157898 -7.708633 10337 48.673279 36.079346 -6.634735 10338 4.568771 34.000000 -8.733032 10339 48.448273 34.247009 -8.034904 10340 48.756073 34.811066 -6.718223 10341 5.528916 32.864166 -8.926544 10342 5.665558 34.433746 -8.187767 10343 6.972313 33.468597 -8.189987 10344 6.658600 31.877838 -8.827759 10345 26.817360 32.874313 -7.610687 10346 27.725716 32.211426 -8.083359 10347 37.345825 33.145142 -7.791870 10348 38.544327 34.437302 -7.281578 10349 39.476120 32.767914 -7.426872 10350 48.485245 33.378647 -7.604256 10351 48.713913 34.280273 -7.401543 10352 8.325737 32.217133 -7.745224 10353 7.500183 31.152191 -8.608635 10354 36.218643 31.223358 -8.185112 10355 36.867455 31.876312 -8.169998 10356 30.545990 31.579803 -6.806381 10357 33.983879 31.194275 -7.910187 10358 34.485626 31.497925 -8.532974 10359 35.029045 31.246384 -8.354012 10360 37.551987 32.349594 -7.255768 10361 37.823959 33.153198 -7.089157 10362 7.497444 29.302734 -8.972427 10363 7.589111 28.216339 -9.028755 10364 35.687920 30.809891 -7.703171 10365 7.660903 30.373886 -8.732903 10366 22.295876 28.738586 -8.669617 10367 22.774040 29.677246 -8.186165 10368 29.859352 29.112473 -7.401138 10369 7.740119 27.572495 -8.586945 10370 7.669052 27.967133 -7.678024 10371 7.501984 26.990082 -8.113365 10372 26.093803 28.679260 -8.524132 10373 30.929901 28.770203 -7.812652 10374 35.881378 28.560013 -8.969116 10375 37.748413 28.156540 -8.211807 10376 36.799858 28.425659 -8.235039 10377 48.451874 28.752823 -8.005142 10378 48.078369 29.934311 -7.921532 10379 7.335663 27.399841 -9.325916 10380 21.225388 27.347916 -9.315338 10381 20.873642 27.153458 -8.817947 10382 21.179375 27.626801 -8.826614 10383 21.620705 28.046448 -8.674286 10384 25.208298 27.963409 -8.193253 10385 24.918610 26.586441 -8.859848 10386 33.718964 27.746643 -8.308159 10387 35.915131 28.446564 -7.979278 10388 48.779236 27.996552 -7.254753 10389 7.238861 26.393692 -9.060028 10390 20.898102 26.676407 -8.257774 10391 20.839088 27.325775 -8.371780 10392 34.138229 27.671875 -8.211304 10393 41.084351 27.067917 -8.466011 10394 41.053757 27.943665 -7.776924 10395 40.494019 26.853455 -8.683617 10396 41.193787 26.519394 -8.544952 10397 41.513016 26.415756 -8.165260 10398 11.355324 21.839844 -8.272995 10399 11.678131 21.246902 -7.234215 10400 12.352448 22.282364 -7.560226 10401 13.424362 24.352081 -8.954216 10402 20.845657 25.177750 -8.174400 10403 23.863037 25.679108 -8.143799 10404 41.328262 25.727386 -8.461739 10405 40.278290 25.766006 -7.747131 10406 49.203979 23.914368 -7.853416 10407 12.999847 24.968903 -9.214283 10408 41.277374 24.714417 -8.320213 10409 42.038116 25.288193 -8.133148 10410 41.995728 24.664825 -8.617409 10411 42.607178 24.357269 -8.334381 10412 49.089661 26.928391 -7.244614 10413 6.262947 24.128159 -8.872925 10414 11.047256 22.987610 -10.202412 10415 12.478592 24.328644 -9.180344 10416 13.892273 23.331802 -9.142128 10417 41.415405 24.013382 -8.167580 10418 41.918915 23.834656 -8.708138 10419 42.988831 23.941742 -8.665512 10420 43.128708 23.725616 -8.727371 10421 43.208008 23.765259 -8.551102 10422 47.435028 22.681107 -8.198608 10423 48.507126 23.132370 -7.841873 10424 13.278488 23.378159 -8.316483 10425 19.776993 23.306793 -9.559227 10426 23.606567 23.741760 -9.111660 10427 41.861038 23.431686 -7.748619 10428 41.662735 23.692032 -6.977905 10429 41.280304 23.987289 -6.843902 10430 42.264496 23.208466 -8.565720 10431 42.658997 23.229370 -8.495544 10432 43.029938 23.590149 -8.507042 10433 45.320602 21.652420 -8.559837 10434 46.825180 22.730576 -8.669037 10435 10.095810 20.595978 -10.206017 10436 10.704536 21.827148 -9.593292 10437 20.086197 22.642227 -9.220711 10438 20.889214 21.469086 -9.625778 10439 42.376343 22.954926 -8.173439 10440 44.025879 20.651169 -8.509689 10441 44.359375 21.156647 -8.533615 10442 46.644913 21.962509 -8.194763 10443 10.105774 19.209305 -9.359520 10444 10.874893 19.645340 -7.668426 10445 10.570877 20.586746 -8.756302 10446 13.514221 22.685760 -8.066544 10447 20.180893 21.201813 -9.831161 10448 20.278122 21.784363 -9.420113 10449 27.608353 20.198242 -9.432400 10450 28.336227 20.532166 -9.035919 10451 26.021591 18.913986 -8.580032 10452 26.716019 19.422974 -9.333073 10453 29.116318 20.328979 -8.823631 10454 44.791794 19.981827 -8.273438 10455 13.999931 18.409546 -9.598446 10456 31.162170 18.446136 -8.833588 10457 45.701401 19.883423 -7.684379 10458 46.402817 20.211731 -7.473328 10459 46.033844 20.829758 -7.908768 10460 43.961273 19.404907 -9.081184 10461 9.989029 17.862350 -9.398350 10462 25.323441 17.628754 -8.484177 10463 49.763412 17.036987 -9.249352 10464 3.699967 16.718124 -9.570862 10465 4.055985 16.670212 -8.416008 10466 4.507065 15.711761 -9.139809 10467 14.594276 17.408463 -9.654636 10468 24.914589 16.770340 -9.518467 10469 44.969086 16.834839 -8.433075 10470 43.985947 15.865906 -7.891449 10471 45.314514 18.805267 -8.054222 10472 45.770081 17.909210 -8.019012 10473 49.868988 16.401276 -8.471069 10474 52.058044 16.876465 -6.628715 10475 53.261230 17.088394 -6.652206 10476 4.064957 15.863235 -10.000858 10477 4.578598 15.374146 -10.752079 10478 16.410583 15.364014 -9.644272 10479 35.243195 16.694916 -9.084602 10480 35.766815 16.412018 -7.996185 10481 36.876053 16.324341 -9.237831 10482 48.515671 15.157089 -8.847397 10483 51.291473 16.946655 -7.789108 10484 55.410950 15.550537 -8.196266 10485 4.702873 15.345276 -9.805756 10486 5.681778 14.742065 -10.950098 10487 6.685448 14.305710 -10.373501 10488 9.259827 14.679779 -9.935093 10489 16.691528 14.534210 -9.195175 10490 17.234657 13.879929 -9.808159 10491 31.578766 14.651627 -9.378162 10492 31.452530 14.939178 -9.064816 10493 31.074821 14.563416 -9.108208 10494 32.119949 14.397934 -9.380772 10495 31.927904 14.873047 -9.030785 10496 32.470306 14.478210 -8.985535 10497 39.169136 16.008911 -8.926758 10498 42.464340 15.767746 -5.983871 10499 44.957993 15.336380 -7.136001 10500 45.402069 15.308380 -7.292511 10501 45.449921 15.895340 -7.672851 10502 25.728027 13.475220 -9.840637 10503 26.000656 14.198517 -9.296787 10504 25.472572 14.621521 -9.265076 10505 28.207344 14.343079 -8.943581 10506 30.562119 13.992126 -9.282158 10507 30.367966 14.489105 -8.679291 10508 31.508385 13.657837 -9.588787 10509 30.521790 13.173462 -9.755386 10510 32.879288 13.550354 -9.239239 10511 32.771042 14.224701 -8.370247 10512 32.223755 14.778030 -8.470253 10513 47.589676 13.291351 -8.797424 10514 48.232742 13.925507 -8.186371 10515 48.306610 13.176559 -7.285118 10516 47.364044 12.583618 -8.421242 10517 7.617111 12.237289 -9.487816 10518 8.607712 13.246689 -9.756512 10519 10.818306 12.491669 -10.045727 10520 9.589592 12.666580 -10.019127 10521 17.795898 12.823410 -9.696789 10522 33.832687 12.497818 -9.537247 10523 33.912872 13.193176 -9.020145 10524 34.511696 12.763947 -9.079338 10525 7.324860 11.098694 -10.208126 10526 12.609193 12.935760 -8.820786 10527 11.673378 12.855530 -9.605789 10528 12.320389 12.444519 -9.934124 10529 11.661644 12.529770 -10.081146 10530 17.080078 12.465958 -8.653046 10531 18.245087 11.547104 -9.141445 10532 34.799820 12.073349 -9.348446 10533 35.291428 12.540604 -8.581520 10534 36.062233 11.535721 -9.055695 10535 47.285431 13.038086 -9.108059 10536 56.036087 12.356567 -9.010555 10537 7.012207 10.597427 -10.025684 10538 6.887474 10.078934 -9.809456 10539 36.538162 10.135544 -9.268494 10540 36.537720 12.069183 -8.223808 10541 35.997086 12.263474 -8.404251 10542 45.684387 10.509232 -8.969673 10543 45.109665 9.117706 -8.608734 10544 44.748322 9.650208 -9.514263 10545 56.260101 11.207977 -9.032314 10546 30.206604 9.485886 -9.894615 10547 35.406235 8.638107 -9.677391 10548 36.659920 10.917404 -9.294262 10549 36.683960 8.849640 -9.309158 10550 36.967560 10.935562 -8.928413 10551 56.303406 10.405121 -9.288292 10552 56.622711 12.050369 -6.842209 10553 14.300758 11.784393 -9.090179 10554 30.225006 8.282516 -9.262638 10555 29.316864 7.630219 -8.783234 10556 36.664352 7.699905 -9.174034 10557 9.808065 7.838005 -9.980915 10558 28.669212 9.292053 -10.059177 10559 37.304260 8.936996 -8.737244 10560 10.959249 7.264598 -9.870605 10561 26.571075 6.786148 -8.881111 10562 26.761597 7.339249 -9.372650 10563 31.386902 7.086807 -9.435162 10564 32.805908 6.645401 -10.188854 10565 30.244835 7.244263 -8.807884 10566 34.481598 7.324982 -9.981876 10567 35.784744 7.260300 -9.623142 10568 38.098099 8.827667 -8.072746 10569 37.454994 7.699905 -8.484573 10570 44.335785 6.983521 -8.762428 10571 16.004492 5.675886 -9.762922 10572 15.262914 5.760086 -9.784293 10573 15.392705 5.172935 -9.450468 10574 17.342697 6.201614 -10.092461 10575 19.474426 5.970856 -9.599262 10576 20.475288 6.237244 -9.802425 10577 21.847420 5.690689 -8.929008 10578 23.383942 5.391983 -8.574745 10579 24.339813 6.457367 -9.504738 10580 18.014866 4.831276 -9.107187 10581 19.140213 5.289917 -8.808762 10582 31.385391 5.209579 -10.067490 10583 30.375275 5.876335 -8.788582 10584 29.318138 6.609512 -8.379936 10585 29.431503 5.806183 -8.103691 10586 32.293251 5.411102 -10.949997 10587 36.304977 6.669724 -9.406940 10588 30.860970 2.820374 -10.575279 10589 30.366440 4.356720 -9.061333 10590 42.584534 3.302216 -9.946945 10591 43.260620 4.305359 -9.204437 10592 42.321777 1.977478 -9.941456 10593 55.937225 3.719589 -8.693909 10594 55.162048 4.747498 -8.913734 10595 55.456238 2.690201 -8.853378 10596 52.650558 2.696350 -9.591351 10597 41.932785 0.642685 -9.953163 10598 49.526260 0.197464 -10.219170 10599 51.477997 0.699173 -9.739048 10600 49.146515 -0.773010 -10.175152 10601 24.943584 -0.217468 -9.173077 10602 25.008036 -0.559467 -9.474068 10603 26.268972 -0.397466 -9.654697 10604 27.604515 0.380222 -9.322503 10605 29.617279 0.536514 -9.425411 10606 28.778946 0.565491 -9.313789 10607 28.666840 0.020687 -10.085839 10608 48.418610 -2.126816 -10.585224 10609 49.823334 -1.554062 -9.987278 10610 50.136780 -0.569214 -9.851444 10611 25.329319 -1.180978 -10.003668 10612 23.767141 -0.902556 -9.480928 10613 24.981115 -1.939067 -10.340043 10614 40.184479 -1.885590 -10.357430 10615 39.958221 -2.069534 -9.745476 10616 49.332672 -7.867310 -10.507023 10617 50.614090 -6.847580 -10.389057 10618 54.431290 -0.981964 -9.045216 10619 51.778305 -1.764435 -9.710316 10620 40.536469 -2.242615 -9.799973 10621 50.227112 -2.858185 -10.259758 10622 51.423950 -3.970459 -10.209709 10623 51.678970 -2.990250 -10.039803 10624 25.106699 -0.800268 -9.681580 10625 50.394745 -8.068359 -10.317635 10626 46.063095 -7.640259 -11.243988 10627 46.993439 -7.811844 -10.771162 10628 24.403389 -4.552109 -11.195318 10629 25.012653 -3.509303 -11.069920 10630 24.195112 -3.141721 -10.581406 10631 25.459713 -4.087594 -11.565384 10632 25.059731 -2.766119 -10.765009 10633 51.602081 -5.332275 -10.188965 10634 53.173035 -4.278641 -9.643089 10635 25.485878 -5.296084 -12.095373 10636 53.298050 -5.560822 -9.518063 10637 25.630749 -6.316113 -12.613134 10638 48.147308 -7.969025 -10.573215 10639 57.695114 -6.168488 -10.218277 10640 57.790390 -6.947601 -10.512840 10641 59.661865 -7.719315 -10.279324 10642 58.811691 -7.246826 -10.480865 10643 59.910889 -6.232925 -9.791977 10644 58.622162 -6.032562 -10.005051 10645 60.575546 -7.462372 -9.697315 10646 26.200895 -5.838941 -12.946285 10647 25.974190 -6.098465 -12.837069 10648 46.079147 -8.634048 -10.892548 10649 51.607956 -8.082932 -9.811264 10650 50.116241 -9.372223 -10.059170 10651 51.361816 -9.772919 -9.618774 10652 59.488937 -8.962830 -10.350636 10653 60.113495 -8.698898 -9.921276 10654 64.973419 -8.195618 -10.139572 10655 12.307746 -8.912672 -9.072086 10656 13.712702 -8.757114 -9.589130 10657 22.228931 -7.846986 -11.340376 10658 21.302105 -7.874944 -11.085579 10659 23.573568 -6.863588 -11.556273 10660 22.921684 -7.249413 -11.412191 10661 23.719604 -7.600803 -11.834362 10662 24.114355 -7.544925 -12.013462 10663 24.603964 -7.286311 -12.215607 10664 48.675903 -9.739639 -10.167854 10665 64.801285 -8.358185 -9.558861 10666 11.375097 -8.720710 -8.565638 10667 14.102420 -8.006670 -9.546049 10668 15.620386 -9.492250 -10.286367 10669 16.188042 -10.310775 -10.567856 10670 18.339691 -7.941165 -10.501968 10671 25.713905 -7.580782 -13.162807 10672 25.649990 -7.075089 -12.907421 10673 25.906847 -7.327949 -13.260767 10674 10.617259 -9.524735 -8.296801 10675 17.188513 -10.836955 -10.850788 10676 25.782375 -7.207462 -13.082764 10677 45.733398 -11.290222 -10.839466 10678 57.890533 -12.968124 -9.507828 10679 56.943466 -13.679138 -9.576668 10680 9.051665 -10.161206 -7.211987 10681 16.790386 -10.114099 -10.664927 10682 16.552788 -9.416059 -10.482771 10683 57.262421 -11.826950 -10.372990 10684 8.339140 -12.589885 -6.666286 10685 8.197716 -13.978139 -6.361052 10686 8.712504 -13.449545 -7.170250 10687 8.736019 -11.374524 -7.072503 10688 66.664154 -13.922638 -9.154858 10689 45.877014 -13.214752 -10.174126 10690 45.781204 -12.167587 -10.473875 10691 55.877014 -13.992966 -9.929764 10692 54.444977 -13.654419 -10.787209 10693 55.082199 -14.370636 -10.035309 10694 54.420914 -14.942932 -9.972054 10695 8.334187 -15.281610 -6.216445 10696 8.664683 -15.769133 -6.598102 10697 8.608078 -14.768457 -6.877831 10698 45.885101 -14.407089 -10.024376 10699 46.087204 -14.942764 -10.743252 10700 53.111206 -14.659515 -10.819778 10701 8.959556 -15.586873 -7.236218 10702 8.937835 -16.924297 -6.341436 10703 20.238968 -17.827856 -10.749069 10704 25.914726 -17.875164 -11.486330 10705 46.715347 -15.814163 -10.694809 10706 45.998199 -15.668655 -9.937843 10707 67.251755 -15.666183 -9.692699 10708 22.119192 -18.736288 -10.512569 10709 25.646288 -19.005980 -10.842018 10710 26.864038 -18.777431 -11.172001 10711 28.937038 -19.421846 -11.150793 10712 32.663548 -19.020443 -12.114351 10713 19.208742 -19.221500 -10.130255 10714 20.339151 -20.060955 -9.696907 10715 21.282011 -19.942633 -9.827948 10716 19.764141 -19.474791 -10.014519 10717 23.358665 -19.306126 -10.373362 10718 24.542652 -19.688450 -10.303261 10719 25.599129 -19.906811 -10.299426 10720 26.510166 -19.621519 -10.599819 10721 26.430084 -20.585485 -9.957020 10722 27.666206 -19.761946 -10.686790 10723 32.041489 -19.659895 -11.520927 10724 33.427700 -19.792597 -11.625628 10725 19.234472 -19.919189 -9.764179 10726 17.802509 -20.082232 -9.597431 10727 29.836901 -19.883196 -10.982935 10728 28.741951 -20.506783 -10.337311 10729 30.935099 -19.787928 -11.241014 10730 67.886734 -19.011078 -9.268600 10731 17.983162 -20.945902 -9.050503 10732 18.524191 -20.249672 -9.542571 10733 23.063545 -22.933945 -11.277271 10734 25.157211 -22.219833 -12.517601 10735 24.458267 -22.521011 -11.684387 10736 10.510569 -19.994240 -6.200390 10737 9.202692 -18.188108 -5.851399 10738 8.857275 -18.667578 -4.817514 10739 9.612009 -19.313187 -5.515600 10740 22.403656 -23.590851 -11.133274 10741 25.583138 -22.675934 -12.184502 10742 25.274002 -22.796005 -11.683758 10743 11.035716 -20.060778 -6.882152 10744 11.385431 -20.583969 -6.739977 10745 26.206055 -23.772903 -11.151402 10746 28.299744 -24.362152 -12.100172 10747 21.687042 -25.503693 -12.089756 10748 29.119263 -25.160172 -11.688446 10749 29.636215 -26.178467 -11.055275 10750 32.739044 -25.887497 -11.709923 10751 31.650087 -26.952454 -10.829876 10752 35.433624 -25.640808 -11.753174 10753 34.443077 -26.676132 -11.264046 10754 36.404160 -25.843140 -10.733711 10755 35.554359 -26.345261 -11.203293 10756 35.793457 -26.969772 -10.678940 10757 52.235641 -25.789337 -11.880257 10758 51.531555 -26.844696 -11.586609 10759 52.298126 -26.680084 -11.525955 10760 53.517273 -26.469131 -11.965725 10761 68.287552 -25.279343 -11.740318 10762 68.053070 -25.642746 -11.221752 10763 19.962494 -27.157059 -12.388895 10764 19.643036 -27.855942 -12.487698 10765 20.526543 -26.757767 -12.061485 10766 21.074249 -26.303452 -12.091854 10767 21.507378 -25.832993 -11.964722 10768 52.854126 -26.753677 -11.688023 10769 53.629211 -27.456268 -11.936310 10770 15.000358 -22.055546 -7.695489 10771 52.549728 -29.636902 -11.877590 10772 53.390030 -28.739883 -12.040550 10773 52.302078 -28.716278 -11.625187 10774 18.069733 -29.877426 -10.751549 10775 18.692368 -30.601288 -11.373119 10776 51.370087 -28.293564 -11.702003 10777 67.629639 -27.595383 -10.660973 10778 67.790771 -26.497208 -10.558163 10779 22.375259 -30.443481 -12.838470 10780 23.463745 -31.101440 -12.289875 10781 26.169243 -30.450928 -12.594746 10782 51.029358 -29.439529 -12.190678 10783 51.653992 -29.574615 -11.716110 10784 20.824661 -30.536560 -12.512100 10785 19.856308 -31.084122 -11.952316 10786 21.438065 -31.898544 -12.119976 10787 21.590599 -30.666260 -12.691975 10788 24.997101 -30.612488 -12.422430 10789 25.932358 -31.367752 -11.805649 10790 24.653519 -31.859726 -11.636452 10791 51.225372 -30.414825 -12.044582 10792 51.924194 -31.006790 -11.974892 10793 67.108978 -28.513779 -10.069321 10794 67.622955 -28.457001 -11.293198 10795 20.537827 -33.097809 -11.807941 10796 21.073792 -33.429123 -11.681602 10797 22.641266 -32.586548 -11.688055 10798 23.594910 -32.608856 -11.402897 10799 32.970955 -33.861801 -11.001781 10800 33.490356 -34.737579 -11.154617 10801 33.723068 -33.679459 -11.958511 10802 32.880127 -32.464340 -11.824776 10803 51.030884 -32.420898 -12.486286 10804 51.297974 -32.902740 -12.362099 10805 51.826538 -32.235992 -12.134708 10806 59.475357 -34.453186 -12.051498 10807 25.458588 -37.242554 -12.738968 10808 32.703064 -36.016891 -12.224224 10809 32.221695 -36.626068 -12.159477 10810 32.004097 -36.261307 -12.632740 10811 67.040527 -34.916443 -11.226883 10812 66.822357 -35.995987 -11.368221 10813 24.068802 -38.160156 -12.338608 10814 25.109940 -38.695755 -11.550266 10815 23.979477 -38.730423 -11.734451 10816 31.329681 -37.111115 -12.518448 10817 59.241180 -37.607117 -12.055088 10818 61.558746 -37.029251 -11.432034 10819 62.142746 -37.191559 -11.675755 10820 66.261673 -37.063202 -11.695713 10821 27.320374 -37.131180 -12.775852 10822 30.448029 -37.930313 -12.337101 10823 28.336899 -37.543259 -12.667770 10824 63.622787 -38.698486 -11.082375 10825 28.139008 -38.744141 -11.760361 10826 31.265884 -38.500412 -11.708424 10827 59.009460 -36.779800 -11.402725 10828 58.185715 -39.219116 -11.268501 10829 59.299667 -39.119965 -12.173176 10830 58.328522 -39.995850 -11.895859 10831 59.073822 -40.351562 -12.249809 10832 65.763672 -38.740433 -10.923916 10833 23.264206 -39.135010 -12.152454 10834 23.011787 -40.073349 -12.625103 10835 51.429779 -39.914993 -12.684486 10836 51.915771 -39.866165 -12.681805 10837 52.157684 -40.338562 -12.640503 10838 58.632614 -38.137405 -11.398098 10839 59.459900 -41.170990 -12.260826 10840 64.754684 -40.651443 -13.175533 10841 22.856308 -41.434860 -12.339565 10842 22.879776 -43.174057 -12.376266 10843 51.322495 -40.441635 -12.425697 10844 59.307526 -42.137192 -11.833031 10845 58.079727 -41.350708 -11.742676 10846 62.287796 -41.660812 -12.386089 10847 61.320267 -42.230576 -12.061317 10848 60.222076 -41.880432 -12.138390 10849 27.836830 -43.245529 -13.524887 10850 26.864517 -42.908401 -13.741585 10851 26.988525 -43.556519 -13.136379 10852 26.037598 -43.422974 -13.293072 10853 42.041428 -42.081467 -13.327614 10854 42.873596 -42.218246 -13.485508 10855 63.301422 -42.261322 -12.297501 10856 65.677719 -42.020813 -13.293221 10857 64.604797 -42.469223 -12.716957 10858 27.697876 -43.698318 -13.054401 10859 40.867767 -43.259705 -13.055870 10860 51.818634 -40.851318 -12.488014 10861 60.498581 -43.605362 -11.069996 10862 63.141418 -43.780838 -11.382236 10863 65.428024 -43.724747 -12.983238 10864 28.643654 -44.140839 -13.177155 10865 30.314362 -44.595032 -13.271690 10866 31.600412 -44.442871 -13.245064 10867 40.016327 -44.469131 -13.212784 10868 40.362320 -44.129486 -12.771072 10869 42.635651 -43.081787 -13.054863 10870 41.526749 -43.841232 -12.428093 10871 43.065414 -44.753510 -12.834908 10872 51.254089 -42.766190 -12.902252 10873 64.619492 -44.298691 -12.349991 10874 65.532654 -44.630859 -13.054310 10875 23.346161 -45.860153 -12.724174 10876 22.390152 -45.826401 -11.757719 10877 22.663895 -47.071350 -11.675507 10878 23.703346 -43.578491 -12.884686 10879 23.738388 -44.689255 -12.893429 10880 25.365265 -45.620285 -13.287224 10881 26.429642 -44.425217 -13.125439 10882 25.478378 -44.385422 -13.168266 10883 27.044022 -45.829483 -13.324249 10884 27.532913 -44.360901 -13.065708 10885 28.428833 -46.138550 -13.422050 10886 28.480415 -48.146103 -13.501827 10887 28.418610 -45.145142 -13.212460 10888 29.397041 -45.157761 -13.163929 10889 33.823685 -45.270966 -13.298439 10890 34.695992 -45.226807 -13.258759 10891 34.434097 -47.823959 -13.487000 10892 34.538055 -46.974426 -13.174995 10893 32.948158 -47.563522 -13.218590 10894 34.933365 -46.294449 -13.453068 10895 34.905548 -45.555847 -13.238262 10896 43.611633 -45.093750 -13.644306 10897 64.255142 -45.413696 -12.218723 10898 64.092453 -44.862167 -11.360065 10899 24.017212 -46.429260 -13.022293 10900 24.474518 -47.772919 -12.930969 10901 27.729980 -53.563934 -13.970196 10902 28.433197 -52.195160 -13.783352 10903 26.039291 -52.270508 -13.725754 10904 29.126495 -46.065460 -13.333366 10905 30.137054 -46.146591 -13.313732 10906 64.239090 -46.060867 -12.720705 10907 63.752731 -46.184494 -12.266579 10908 64.951004 -45.466522 -12.909157 10909 25.078758 -50.086960 -13.419357 10910 23.546295 -49.837311 -12.674946 10911 23.652695 -51.103210 -12.903645 10912 24.516525 -45.134933 -13.188377 10913 31.006599 -47.178833 -13.362091 10914 31.774279 -45.694534 -13.143929 10915 40.162018 -46.113876 -12.040764 10916 63.620407 -46.893127 -12.767658 10917 63.226196 -46.873795 -12.364391 10918 63.424942 -46.604599 -12.344120 10919 64.667572 -46.510941 -13.161209 10920 64.112946 -47.408096 -13.319149 10921 31.063873 -48.098495 -13.399326 10922 34.873535 -47.054535 -13.445091 10923 40.749802 -47.951553 -11.335026 10924 40.453979 -48.141068 -12.821743 10925 44.602417 -48.029846 -13.201813 10926 61.488312 -49.032593 -12.679634 10927 62.064178 -48.541855 -12.533848 10928 62.488358 -48.216507 -12.590744 10929 63.208725 -48.086868 -13.232506 10930 62.973480 -47.465912 -12.344505 10931 31.220490 -49.341034 -13.363968 10932 27.067848 -50.783646 -13.636440 10933 40.415237 -49.115906 -13.056675 10934 41.493805 -49.110352 -13.973213 10935 44.960663 -49.020477 -13.102905 10936 51.546036 -48.876587 -12.885956 10937 51.909576 -48.177917 -12.151016 10938 52.097717 -49.019318 -13.044662 10939 54.748383 -49.112839 -10.489525 10940 55.278473 -49.263794 -11.888069 10941 54.276871 -48.571884 -11.475533 10942 53.114746 -48.804672 -12.814613 10943 54.186417 -48.761246 -12.426659 10944 54.078873 -49.162064 -13.049198 10945 60.587433 -49.844193 -12.984930 10946 24.860466 -51.347504 -13.404892 10947 25.161804 -49.039230 -13.334480 10948 29.359993 -51.227112 -13.571590 10949 29.494629 -50.071701 -13.534897 10950 33.019669 -49.736420 -13.662865 10951 40.228058 -50.605423 -13.147171 10952 45.202759 -49.679688 -12.829540 10953 45.547867 -50.375885 -13.193699 10954 51.596771 -49.688705 -13.216805 10955 51.133392 -48.981216 -12.528080 10956 49.914536 -49.446411 -10.827282 10957 49.853607 -48.895554 -10.956429 10958 50.443268 -49.213120 -11.613121 10959 54.960495 -49.497314 -12.934086 10960 56.250809 -50.279739 -12.944412 10961 60.091629 -50.048508 -12.550957 10962 60.867249 -49.425049 -12.255337 10963 30.630341 -50.806015 -13.406197 10964 31.941469 -50.933655 -13.521278 10965 32.322952 -52.040695 -13.805248 10966 45.132843 -50.607727 -12.241772 10967 45.618469 -52.130249 -12.607788 10968 51.237167 -51.283005 -13.046726 10969 51.089386 -50.307312 -12.820583 10970 57.585663 -51.213928 -13.446213 10971 59.289795 -50.907272 -13.077934 10972 60.334091 -52.467148 -14.160873 10973 24.178467 -52.585754 -12.978180 10974 24.921738 -53.872894 -13.461998 10975 25.694595 -53.343216 -13.758389 10976 30.738434 -52.577271 -13.573441 10977 29.246933 -53.177048 -13.814590 10978 32.492599 -52.778168 -13.992863 10979 39.222900 -51.964584 -13.298611 10980 46.360580 -52.852219 -13.585300 10981 45.774796 -53.490097 -12.991928 10982 60.105240 -50.387115 -11.343353 10983 29.669907 -53.919846 -13.736435 10984 28.940407 -53.989853 -13.899101 10985 32.004860 -53.462616 -13.899788 10986 37.872391 -53.858551 -12.972015 10987 39.090645 -55.149033 -13.683674 10988 46.412537 -53.780960 -13.759872 10989 52.676712 -53.788788 -13.315281 10990 24.522736 -56.954193 -13.313591 10991 24.631363 -58.063110 -13.407959 10992 25.604889 -58.018433 -13.739971 10993 24.980888 -54.868225 -13.470795 10994 26.310287 -54.496170 -13.906433 10995 28.423752 -55.528442 -14.024435 10996 45.912567 -54.500977 -13.671703 10997 45.122910 -54.497543 -13.078945 10998 29.309860 -58.361206 -14.043507 10999 27.199753 -58.175690 -14.071503 11000 27.970871 -59.362717 -14.061573 11001 30.466522 -56.429214 -14.123215 11002 30.428497 -54.650391 -13.776823 11003 31.466286 -55.271011 -14.155533 11004 38.373138 -55.456375 -12.656702 11005 53.857819 -53.666168 -11.448521 11006 53.037552 -53.510986 -12.238306 11007 26.149063 -56.702103 -13.913830 11008 26.174011 -55.535812 -13.909210 11009 31.968180 -54.455933 -14.161221 11010 57.065903 -58.559952 -13.679306 11011 56.675323 -56.639694 -13.376862 11012 31.079895 -58.294357 -14.051643 11013 40.134094 -57.427231 -13.739273 11014 44.338135 -57.670959 -13.608681 11015 56.979538 -57.557053 -13.064552 11016 58.200806 -57.580475 -14.207159 11017 26.144859 -58.862427 -13.847565 11018 28.814713 -60.071960 -13.817108 11019 29.345551 -61.577759 -13.613125 11020 30.757706 -60.170609 -13.516808 11021 31.690218 -58.710770 -13.863785 11022 32.434334 -58.871033 -13.941505 11023 39.434410 -57.104050 -13.129549 11024 40.095016 -58.683594 -12.840160 11025 39.086555 -57.351700 -12.012863 11026 44.950195 -58.406403 -13.598709 11027 56.775696 -58.628494 -12.935017 11028 27.777725 -60.059296 -13.939396 11029 26.651588 -59.789093 -13.844482 11030 31.660067 -59.214417 -13.594688 11031 33.385445 -59.328629 -13.621010 11032 34.955414 -59.851532 -14.637173 11033 34.893242 -59.450699 -14.248791 11034 35.089058 -59.688492 -14.110359 11035 45.729187 -58.743256 -13.069393 11036 46.476242 -59.164795 -13.313728 11037 46.468964 -59.699814 -13.860382 11038 46.872910 -59.577881 -13.479591 11039 56.310638 -59.385803 -12.344967 11040 27.494926 -60.952911 -13.798500 11041 34.818222 -59.914902 -13.986977 11042 46.974976 -60.074341 -13.711243 11043 49.031128 -60.004944 -13.316380 11044 50.278656 -60.514435 -13.553799 11045 50.234161 -59.810013 -12.639519 11046 50.325623 -61.185135 -14.116268 11047 51.251923 -61.518082 -13.959053 11048 53.949753 -60.883896 -12.419258 11049 52.873657 -62.210297 -13.842285 11050 52.367462 -60.600754 -12.405907 11051 42.144958 -61.382614 -14.335220 11052 48.376968 -60.715515 -14.045456 11053 47.789444 -60.229904 -13.609833 11054 51.236298 -60.476440 -12.966667 11055 51.971329 -61.166687 -13.363060 11056 55.388123 -60.681335 -13.003212 11057 55.760422 -61.667145 -13.977932 11058 33.404968 -60.389114 -13.344440 11059 32.557259 -61.935455 -13.825859 11060 41.486313 -61.298904 -13.818253 11061 41.494400 -62.264404 -14.185909 11062 40.441605 -61.984558 -13.373871 11063 54.617630 -62.325394 -13.863762 11064 55.782242 -62.854858 -14.483665 11065 26.871140 -64.902054 -14.196114 11066 26.945740 -64.494507 -14.279617 11067 25.942116 -64.631042 -14.056213 11068 27.305290 -62.745178 -13.923645 11069 24.894180 -61.562775 -13.377163 11070 45.758163 -62.991669 -13.103222 11071 46.678116 -63.482285 -14.165428 11072 46.968903 -63.008179 -13.050900 11073 53.995850 -63.666809 -14.706535 11074 26.794991 -63.945328 -14.190285 11075 27.981995 -64.515579 -13.979271 11076 40.055771 -64.207535 -14.020134 11077 48.307434 -64.376617 -14.599220 11078 55.046036 -63.613373 -14.619179 11079 26.310318 -65.977859 -13.941963 11080 42.630051 -66.558960 -14.471516 11081 42.362885 -66.081421 -13.994663 11082 43.960007 -63.707092 -12.981976 11083 43.364136 -64.013336 -12.646496 11084 46.791016 -66.069809 -13.298325 11085 47.712250 -65.271820 -13.795395 11086 47.926666 -66.198792 -13.238056 11087 38.919495 -67.006409 -14.601402 11088 38.364922 -67.816513 -14.632133 11089 38.268875 -67.318832 -14.174973 11090 45.542862 -67.312393 -13.842827 11091 45.956635 -66.446747 -13.300880 11092 29.680397 -68.220001 -14.261726 11093 31.180695 -64.487442 -13.501350 11094 30.641403 -65.376602 -13.562679 11095 45.463776 -68.188110 -14.136482 11096 29.903702 -69.738663 -14.437836 11097 29.539688 -68.908539 -14.206139 11098 41.698425 -69.222488 -14.133131 11099 45.302032 -70.460114 -13.853798 11100 45.395294 -68.942932 -14.127060 11101 30.280075 -70.454681 -14.645546 11102 41.773804 -71.185760 -14.281361 11103 42.737518 -70.923096 -15.046230 11104 30.563126 -72.355423 -14.645134 11105 42.549164 -72.198395 -14.720322 11106 41.916077 -73.190384 -14.385563 11107 42.766541 -73.297363 -14.780483 11108 44.080963 -72.890335 -14.862194 11109 45.283936 -72.364624 -14.041954 11110 43.379303 -73.947815 -14.848282 11111 30.843979 -73.190353 -15.220230 11112 37.130707 -73.709824 -14.568909 11113 25.382629 -74.768600 -15.132256 11114 29.999100 -73.017166 -14.346462 11115 42.700592 -76.109543 -14.386368 11116 42.390839 -74.334686 -14.510456 11117 41.596893 -75.050217 -14.045296 11118 44.281326 -74.182281 -14.720737 11119 44.973953 -73.788071 -14.281120 11120 29.173477 -73.239136 -13.771912 11121 43.535706 -74.956070 -14.685825 11122 44.767670 -75.318314 -14.146454 11123 24.297195 -76.677643 -14.044720 11124 23.846451 -77.945328 -14.301720 11125 32.109154 -77.887421 -14.760380 11126 33.514938 -77.270340 -14.838764 11127 32.608673 -77.071548 -15.307465 11128 44.032394 -76.869308 -14.471619 11129 43.808716 -75.817230 -14.581398 11130 33.562668 -76.538498 -15.417963 11131 24.949280 -75.673218 -15.242912 11132 29.536087 -79.074356 -14.940361 11133 30.928055 -78.268951 -14.934261 11134 23.690163 -78.431259 -14.234089 11135 23.659142 -79.991150 -14.885899 11136 27.310326 -81.025391 -15.528297 11137 41.475128 -80.084198 -14.915054 11138 41.926865 -78.784607 -14.556805 11139 40.921051 -78.860382 -14.161564 11140 42.490921 -79.934204 -15.011429 11141 43.023590 -78.327789 -14.662148 11142 43.460846 -80.040085 -15.000378 11143 44.407883 -78.630371 -14.488426 11144 44.421066 -80.001053 -14.695694 11145 24.406593 -82.097839 -15.285316 11146 23.973152 -82.787888 -14.889736 11147 24.560463 -82.918884 -15.145844 11148 26.348328 -81.502197 -15.658745 11149 36.777908 -81.147369 -15.205368 11150 37.690659 -81.190292 -15.416256 11151 37.556641 -80.281235 -14.431465 11152 38.568634 -80.930710 -15.151497 11153 43.978302 -80.970963 -14.869923 11154 45.385223 -79.441589 -13.890648 11155 44.874069 -80.806778 -14.157204 11156 25.702286 -82.749390 -15.282944 11157 31.982485 -83.822540 -15.428505 11158 31.183273 -84.774475 -15.746696 11159 39.537598 -80.674271 -14.988419 11160 42.562759 -82.097290 -14.939781 11161 40.677887 -80.910522 -15.121597 11162 27.252419 -82.029953 -15.251083 11163 34.690308 -82.241913 -15.410484 11164 35.688629 -81.180099 -14.797533 11165 33.000687 -83.779449 -15.779079 11166 32.771996 -83.082703 -15.268272 11167 34.598434 -81.188446 -14.369457 11168 33.305107 -82.064804 -14.682976 11169 43.840622 -83.297241 -13.489052 11170 44.192535 -82.434479 -13.993713 11171 30.439911 -85.632828 -15.860989 11172 28.967285 -85.762924 -15.427608 11173 30.380539 -83.549133 -14.967766 11174 29.839859 -84.693893 -15.423386 11175 40.192505 -85.101151 -15.347721 11176 41.227783 -84.762344 -14.778011 11177 40.736298 -85.372757 -14.432102 11178 41.921097 -84.056381 -14.853222 11179 39.484612 -85.365509 -15.730434 11180 41.598938 -85.046646 -13.445755 11181 41.960052 -84.699707 -14.309853 11182 29.202675 -87.146072 -15.492870 11183 39.910614 -85.686386 -14.514584 11184 35.812546 -87.275558 -15.998566 11185 36.706451 -87.104507 -15.589676 11186 29.033020 -88.616959 -14.248482 11187 35.295471 -89.836090 -14.048450 11188 21.775444 -92.332260 -15.351101 11189 21.487518 -93.376953 -16.277168 11190 22.511086 -92.829575 -16.269234 11191 25.845261 -90.832932 -16.242149 11192 26.530273 -90.615234 -15.830124 11193 25.783943 -90.422073 -15.799509 11194 28.357803 -92.047668 -16.077988 11195 31.996614 -90.510773 -15.098148 11196 25.059647 -90.786911 -15.992439 11197 27.115540 -90.574677 -15.118725 11198 27.686172 -91.003983 -14.541019 11199 28.557060 -91.839798 -14.713791 11200 32.512848 -90.462677 -15.635696 11201 22.862564 -92.051498 -15.773758 11202 29.001312 -92.734543 -15.888420 11203 22.593506 -91.445633 -15.202045 11204 23.718292 -90.971970 -15.530167 11205 21.368301 -94.258530 -16.810810 11206 19.594360 -93.799774 -15.356670 11207 18.121864 -93.842896 -14.531487 11208 18.650574 -95.127975 -15.851366 11209 20.481033 -94.125534 -16.328358 11210 19.651924 -94.773575 -16.407536 11211 19.495193 -95.480469 -16.640896 11212 19.356590 -96.430359 -16.546803 11213 18.029922 -97.284409 -15.530178 11214 19.310051 -97.609451 -16.335213 11215 20.919083 -98.558960 -16.442192 11216 27.078384 -97.466034 -16.102417 11217 19.961754 -99.503860 -15.690403 11218 19.198563 -100.135651 -15.124866 11219 19.668304 -100.872559 -14.223785 11220 21.793335 -98.647217 -16.442963 11221 23.941422 -98.757324 -16.404884 11222 28.435410 -97.056305 -15.486809 11223 19.937271 -98.348831 -16.344124 11224 24.706078 -97.957565 -16.804569 11225 21.486053 -99.974731 -15.119316 11226 23.718094 -99.885437 -15.069042 11227 24.817322 -99.910324 -14.719845 11228 24.766708 -99.230423 -15.736492 11229 25.764954 -98.346268 -16.041729 11230 25.672714 -99.401016 -14.916523 11231 10.179413 61.369598 -6.024094 11232 10.845566 61.751846 -5.574463 11233 8.518509 58.529816 -6.395538 11234 9.102478 59.554977 -6.136703 11235 9.600815 60.770447 -5.978638 11236 14.216904 60.213608 -2.079498 11237 13.641632 61.027786 -3.856598 11238 8.247604 57.685593 -6.043838 11239 7.207077 57.237976 -6.497803 11240 9.291359 58.392792 -5.637268 11241 8.984039 57.589020 -5.217361 11242 8.756081 56.816391 -4.470199 11243 7.813194 56.698792 -5.641502 11244 17.668198 57.460327 -5.245193 11245 17.853874 58.130630 -5.111206 11246 18.328491 58.640701 -4.552750 11247 6.626686 55.698029 -5.760559 11248 14.352249 55.976944 -4.740501 11249 5.947624 54.925125 -5.844635 11250 16.428528 54.722275 -4.488525 11251 24.468346 55.431503 -5.302582 11252 27.861099 55.190353 -5.145477 11253 27.444199 55.533783 -4.816612 11254 26.972595 55.326981 -5.498032 11255 14.468292 53.447723 -4.996735 11256 14.598526 54.256500 -4.718262 11257 29.241074 54.520538 -5.672836 11258 28.754593 54.833344 -4.774368 11259 6.489716 54.394852 -5.323112 11260 5.654350 53.883453 -5.924423 11261 30.127625 54.433365 -4.925033 11262 31.280334 54.416763 -4.533386 11263 32.318878 54.145248 -4.824753 11264 32.626022 52.923401 -5.865906 11265 34.734726 51.781052 -6.035034 11266 34.432442 52.797195 -5.548187 11267 33.678024 52.210861 -6.078140 11268 33.491272 53.563141 -5.187988 11269 5.280373 49.785202 -6.923492 11270 13.216156 50.714828 -6.531853 11271 35.436188 52.069778 -5.191017 11272 34.493393 53.688751 -4.555115 11273 4.979286 51.176163 -6.817940 11274 16.048126 51.455795 -5.666733 11275 16.563095 50.319611 -5.319473 11276 17.853889 50.017853 -6.076157 11277 19.189331 48.568481 -6.087906 11278 37.288651 51.033691 -3.770081 11279 37.511238 49.470596 -3.841568 11280 38.137421 49.486404 -3.275986 11281 20.412659 47.620392 -6.516174 11282 29.245758 47.192612 -5.802429 11283 29.794434 47.887222 -5.786865 11284 30.596207 48.152679 -6.083755 11285 5.791870 47.717529 -7.109299 11286 6.231323 48.902496 -6.477196 11287 6.106369 46.288116 -6.364792 11288 5.910591 46.713104 -7.076637 11289 6.878517 47.615005 -6.049614 11290 28.650726 46.923492 -6.548202 11291 16.892815 46.690460 -6.895477 11292 17.481491 46.047470 -6.947586 11293 20.895950 46.782684 -6.402252 11294 30.749016 46.762421 -5.842407 11295 36.312988 46.862244 -6.214264 11296 5.984932 47.569183 -4.790497 11297 6.680412 46.775925 -5.753075 11298 6.890495 47.136841 -5.554733 11299 18.681511 44.141449 -6.286613 11300 30.788872 45.417847 -6.313690 11301 35.743279 47.984055 -6.223678 11302 37.069778 46.295380 -4.741707 11303 36.839722 46.514801 -5.357460 11304 37.396675 46.109192 -5.225265 11305 38.610733 45.853180 -6.177849 11306 42.204773 45.331451 -5.446419 11307 4.996925 44.519821 -7.149567 11308 5.490189 45.244080 -6.924148 11309 28.797943 46.099030 -6.187767 11310 28.823853 43.981049 -6.418320 11311 31.082596 44.155243 -6.848801 11312 41.747665 43.188766 -6.424827 11313 42.472946 42.498383 -6.054443 11314 42.606659 44.054260 -5.867569 11315 22.814606 42.382385 -6.775337 11316 21.466125 42.790466 -5.757217 11317 22.465904 41.565186 -6.021309 11318 29.430054 45.202988 -5.935974 11319 29.542770 46.458298 -5.530723 11320 19.075974 42.427307 -7.093155 11321 23.205170 40.159683 -5.875893 11322 23.379204 41.118256 -6.684509 11323 29.164719 42.943085 -6.166931 11324 40.243835 41.860809 -6.344086 11325 41.335876 42.225677 -6.231338 11326 39.034630 41.235901 -6.228104 11327 40.984756 41.501740 -5.844635 11328 40.183197 40.992035 -5.657196 11329 19.783798 40.023834 -6.424240 11330 43.006454 39.936813 -6.864456 11331 42.912109 41.120605 -6.218262 11332 43.626099 42.743958 -5.722946 11333 20.400757 38.989044 -6.812042 11334 31.002579 40.216858 -6.567123 11335 36.247955 39.539185 -6.872528 11336 37.439331 40.153778 -6.160782 11337 41.193848 39.516159 -6.551315 11338 45.140686 40.792709 -5.995773 11339 44.812515 42.572968 -4.869820 11340 2.253159 38.640076 -7.621185 11341 24.658508 39.075027 -7.154358 11342 24.962067 37.103729 -7.176834 11343 39.351654 39.065430 -6.080749 11344 38.433960 39.319611 -5.548263 11345 40.141159 39.112518 -6.382141 11346 40.782959 39.856262 -5.917587 11347 39.874863 39.945892 -5.684769 11348 42.097748 40.160980 -6.444824 11349 3.661835 37.121353 -7.560303 11350 20.313080 39.210892 -5.942230 11351 20.796951 38.429047 -6.239487 11352 35.803299 37.369781 -7.148567 11353 36.104622 36.932846 -7.169189 11354 47.403366 38.209442 -6.687973 11355 4.656235 35.410461 -8.047646 11356 5.523178 36.067795 -7.471985 11357 5.016457 37.464447 -6.882339 11358 6.621994 35.077698 -7.728134 11359 23.006577 35.573669 -6.818695 11360 22.346840 36.610962 -6.221115 11361 25.149643 36.008972 -7.165764 11362 36.402649 36.424805 -7.527206 11363 37.682327 36.687561 -6.780586 11364 37.034714 37.751587 -6.287857 11365 6.492302 36.001160 -7.312111 11366 7.719452 34.672607 -7.574478 11367 7.264130 35.862808 -7.185501 11368 8.577737 35.413620 -6.601135 11369 8.462875 34.422913 -7.297600 11370 25.432144 34.634796 -6.884804 11371 36.793060 36.534866 -6.969765 11372 37.794563 35.384720 -7.170059 11373 8.361404 33.621216 -7.586258 11374 23.670013 33.634140 -6.409279 11375 25.977837 33.338959 -6.872520 11376 37.524063 34.218246 -7.332825 11377 48.621613 35.462601 -5.805786 11378 48.726471 36.307083 -5.783096 11379 39.619476 32.189575 -6.566498 11380 40.009995 31.464874 -7.016838 11381 48.649841 33.704788 -6.747261 11382 8.223984 31.022217 -8.115463 11383 23.734146 32.649490 -7.613342 11384 27.595093 31.828583 -6.914337 11385 38.523407 33.408157 -6.904907 11386 48.526581 32.996231 -6.852112 11387 8.599037 31.156464 -7.187637 11388 8.336121 30.227234 -8.079948 11389 23.765930 31.424652 -8.046494 11390 27.958054 31.670532 -7.537361 11391 28.505615 31.652863 -7.952026 11392 29.157913 31.424469 -7.333404 11393 31.681124 31.552292 -7.206970 11394 32.516800 31.300430 -7.302902 11395 34.483849 31.301208 -8.100784 11396 37.442986 31.212479 -6.722687 11397 38.088028 32.372131 -6.604301 11398 8.037949 28.973526 -7.927765 11399 23.051956 30.478149 -7.661590 11400 28.364365 31.445251 -7.237831 11401 33.681503 30.953552 -7.148773 11402 34.644302 30.929901 -7.692612 11403 34.751205 30.489975 -6.670662 11404 36.550941 30.542557 -6.853958 11405 36.559586 31.014435 -7.610550 11406 35.813522 30.206818 -6.229156 11407 40.542694 30.038483 -7.308243 11408 22.374329 29.934479 -6.754974 11409 23.111877 31.374405 -6.909836 11410 26.447098 29.359528 -5.652496 11411 27.070396 29.453568 -6.514206 11412 27.843384 29.411499 -5.630844 11413 28.710007 29.287460 -6.660904 11414 8.316010 29.583832 -8.087921 11415 21.566391 28.292999 -7.904632 11416 21.917801 28.923492 -7.388245 11417 25.778275 28.926682 -6.981972 11418 32.000778 28.080475 -7.166992 11419 35.962700 28.506927 -7.280228 11420 35.441162 28.258514 -7.570496 11421 36.504578 28.503784 -7.458816 11422 37.387177 27.943954 -7.021049 11423 38.954727 27.309784 -8.098457 11424 38.974152 26.564041 -6.757263 11425 47.723312 30.570816 -6.317795 11426 48.386383 29.273865 -6.959526 11427 48.714447 28.642761 -7.127853 11428 6.545502 26.198212 -7.518547 11429 7.126343 26.349274 -8.022163 11430 21.125725 27.696930 -8.097580 11431 23.178162 27.535583 -6.152717 11432 22.417168 26.965973 -6.538528 11433 22.766937 26.027802 -7.196922 11434 33.118393 27.642654 -6.803635 11435 34.706299 27.866730 -7.624298 11436 33.813545 27.731323 -7.632080 11437 39.657829 25.744110 -6.738434 11438 40.797989 28.686310 -6.342155 11439 24.702415 28.173172 -7.073975 11440 23.874634 27.260330 -7.020050 11441 24.432632 27.206467 -7.839493 11442 36.533661 28.234802 -6.497291 11443 36.430222 28.427856 -6.899597 11444 41.709152 25.945114 -7.126663 11445 20.571037 24.219986 -8.398926 11446 21.784386 24.961060 -7.566566 11447 21.812042 23.876740 -7.975204 11448 22.736053 24.436798 -7.945846 11449 40.979111 24.456070 -7.478294 11450 42.275711 24.646454 -7.480102 11451 2.811279 22.785812 -8.766418 11452 2.127968 21.613495 -8.336678 11453 5.935707 24.742538 -8.177834 11454 4.640984 25.304291 -7.844726 11455 12.383530 22.985794 -8.164429 11456 11.657295 23.167007 -9.125324 11457 20.220787 23.581436 -8.847580 11458 20.949905 23.470215 -8.461075 11459 43.023926 23.862335 -8.344116 11460 42.667725 23.686615 -7.914200 11461 49.571136 24.098099 -7.373611 11462 49.380417 26.306076 -7.143890 11463 1.628548 22.986893 -7.702927 11464 2.981285 24.196930 -8.158951 11465 1.621468 25.065842 -7.435272 11466 1.214920 24.292526 -7.239975 11467 21.116806 24.361069 -7.977257 11468 21.840744 23.163986 -8.469467 11469 22.541885 23.483124 -8.404282 11470 42.552216 23.056763 -7.944244 11471 49.276733 23.608185 -7.325424 11472 48.639145 22.668762 -6.853943 11473 2.559067 20.526794 -8.736511 11474 11.050240 20.731018 -7.724541 11475 42.323242 22.959991 -7.825882 11476 47.789215 22.273300 -7.711418 11477 27.263077 20.154266 -7.362503 11478 27.548843 20.428665 -7.656723 11479 27.191628 20.105225 -8.231094 11480 47.305511 21.168365 -7.225784 11481 3.363617 18.070602 -9.133255 11482 2.743172 19.619339 -8.331490 11483 3.158417 18.893280 -8.500641 11484 28.141479 20.242706 -7.678970 11485 29.427666 19.780289 -7.836319 11486 13.983658 18.798065 -8.416374 11487 26.189278 19.041046 -7.254143 11488 30.425644 19.076996 -8.365784 11489 10.664886 18.366669 -7.957809 11490 14.208023 17.761780 -7.980789 11491 31.701357 17.789291 -8.117645 11492 30.926437 18.279449 -7.905121 11493 45.456253 19.362701 -7.748123 11494 46.213715 19.099976 -7.414123 11495 10.504242 17.028687 -8.067886 11496 15.493111 16.377319 -8.726250 11497 46.091003 16.924377 -7.783844 11498 47.173859 17.762863 -6.766228 11499 50.663406 16.354523 -7.121109 11500 55.158600 16.267883 -6.775017 11501 54.146729 16.839447 -6.698883 11502 10.063866 15.673431 -8.704109 11503 15.843460 15.373383 -8.578018 11504 25.145767 15.671021 -8.891434 11505 24.843254 16.572403 -8.828384 11506 25.164795 16.657883 -8.275154 11507 34.437210 16.757172 -7.368713 11508 35.463516 16.606262 -6.347397 11509 46.624008 16.253113 -7.139183 11510 7.033196 13.736053 -9.027782 11511 9.646614 14.977600 -9.222984 11512 17.074730 13.558746 -9.023598 11513 25.699646 16.119934 -8.119675 11514 26.424408 15.042175 -8.661530 11515 29.501732 14.541245 -8.455475 11516 29.156013 15.292007 -6.547310 11517 29.030777 14.974213 -7.766373 11518 30.205704 14.878815 -7.630478 11519 31.341095 14.928314 -8.364525 11520 45.918716 15.419434 -6.960586 11521 40.139709 16.091476 -6.314682 11522 49.394333 15.228226 -7.521294 11523 5.409233 15.000336 -8.203156 11524 9.843819 14.299469 -9.125114 11525 27.791275 15.376251 -7.608841 11526 26.511765 16.167389 -7.438057 11527 31.240158 15.006119 -7.312469 11528 9.798546 13.423187 -9.570831 11529 10.967422 13.498856 -8.987267 11530 11.844833 13.944595 -7.861481 11531 33.567390 13.649567 -8.363945 11532 34.537758 13.242706 -8.357475 11533 56.435226 13.937378 -6.631668 11534 37.020370 11.457611 -8.365463 11535 46.812271 11.432312 -8.158905 11536 47.927109 11.907166 -6.716598 11537 46.741974 10.538467 -7.303429 11538 18.718002 10.962433 -9.125412 11539 6.917465 10.963333 -9.103916 11540 37.739662 10.307312 -7.964676 11541 37.065048 11.789490 -7.398025 11542 56.542694 10.506454 -8.551064 11543 55.732544 14.398560 -3.924118 11544 56.404694 12.817810 -4.230011 11545 55.685257 13.086533 -3.321816 11546 28.932953 8.745728 -9.622097 11547 44.774536 8.226639 -8.639801 11548 45.334824 7.768250 -7.846680 11549 45.990967 9.207260 -7.539780 11550 55.935669 7.628967 -8.573769 11551 56.747330 9.096786 -7.543793 11552 38.053101 7.648804 -7.869766 11553 7.730596 8.149016 -8.614487 11554 9.006318 7.497412 -9.009614 11555 10.297227 6.795784 -9.125792 11556 46.434921 6.700256 -6.339218 11557 47.433868 4.860352 -5.083252 11558 46.727661 4.625320 -5.750038 11559 56.962189 7.053833 -7.526489 11560 57.499542 7.542282 -6.365555 11561 12.865604 6.457652 -9.847795 11562 21.664993 4.170090 -7.600059 11563 22.702652 4.116226 -7.642242 11564 25.765167 6.058792 -8.505630 11565 25.208237 4.272255 -7.802917 11566 26.930725 6.123016 -8.074066 11567 37.594864 6.782913 -8.140610 11568 55.146698 6.949524 -9.079601 11569 16.260618 4.828526 -9.289434 11570 17.140759 5.397050 -9.565919 11571 20.379002 4.138349 -8.158566 11572 21.147049 5.065262 -8.266235 11573 29.488556 4.969528 -8.148697 11574 43.985123 5.298233 -8.678833 11575 39.094025 4.328278 -6.621658 11576 38.528885 5.410286 -6.677353 11577 38.203522 5.533737 -7.119827 11578 43.915741 3.950317 -8.342453 11579 55.094543 1.023254 -8.855888 11580 55.666748 6.021729 -8.664154 11581 57.609070 5.404877 -7.325546 11582 29.981621 3.234863 -9.013660 11583 29.985077 2.112778 -9.265278 11584 43.061554 2.857925 -9.025864 11585 42.746536 1.521240 -8.786209 11586 44.671585 3.388123 -7.430176 11587 43.685776 2.419601 -7.931152 11588 56.821732 4.397751 -8.136589 11589 57.567734 2.799881 -8.028900 11590 42.917801 -0.390015 -7.405472 11591 42.492615 0.224716 -8.443970 11592 43.428833 1.014557 -7.268341 11593 28.939041 1.409042 -8.882660 11594 41.891220 -0.495636 -9.281399 11595 56.401276 -0.379440 -8.345154 11596 30.622513 0.410706 -9.827930 11597 11.796828 -2.330979 -7.484164 11598 11.747425 -1.932005 -7.382584 11599 11.487607 -2.349102 -7.327502 11600 12.117980 -2.273316 -7.610521 11601 12.574951 -2.286304 -7.793967 11602 12.030990 -1.389751 -7.410139 11603 13.101624 -2.203770 -7.974741 11604 12.804583 -1.305332 -7.721607 11605 13.564313 -1.453992 -8.006704 11606 13.300185 -0.403774 -7.777151 11607 30.377853 0.552979 -9.592796 11608 41.313004 -1.500107 -9.477024 11609 54.019577 -2.362320 -9.274696 11610 59.092087 -1.298080 -9.944550 11611 11.857386 -2.735258 -7.575685 11612 11.518418 -2.779176 -7.416697 11613 12.248332 -3.095458 -7.793103 11614 12.963227 -3.405258 -8.118677 11615 14.269584 -3.280262 -8.526356 11616 14.227531 -2.607496 -8.378050 11617 13.655335 -2.335319 -8.170455 11618 14.458773 -1.750836 -8.307877 11619 25.180254 0.482432 -8.578307 11620 55.765350 -2.573013 -8.476608 11621 55.981262 -1.311661 -8.502419 11622 60.248535 -3.058823 -9.368404 11623 60.475479 -3.791992 -9.164272 11624 59.578308 -4.398438 -9.516903 11625 11.688917 -3.202437 -7.563224 11626 14.093482 -0.945764 -8.092150 11627 14.960502 -0.919242 -8.318574 11628 15.830200 -0.552964 -8.446494 11629 15.547771 -2.118739 -8.640749 11630 23.217699 -1.633464 -9.706516 11631 24.011274 -2.018694 -10.062576 11632 40.291016 -2.752411 -9.358265 11633 39.916031 -2.519287 -8.603348 11634 52.856567 -3.150146 -9.701168 11635 54.674088 -4.504349 -8.775719 11636 56.026337 -4.135834 -7.623779 11637 60.521790 -4.136765 -9.167824 11638 61.224762 -4.022125 -9.401089 11639 23.343386 -2.464316 -10.071856 11640 22.461458 -1.963626 -9.684819 11641 22.503084 -2.575266 -9.916023 11642 40.347672 -3.123398 -8.964981 11643 54.280518 -3.343582 -9.225372 11644 63.131027 -7.158218 -9.062981 11645 62.525787 -5.987045 -9.295052 11646 12.367376 -4.820644 -8.185176 11647 13.066080 -4.429619 -8.384198 11648 13.531466 -3.837107 -8.417690 11649 54.044418 -6.281830 -8.715683 11650 60.564438 -4.425552 -9.270451 11651 60.797623 -5.066055 -9.357147 11652 61.343491 -4.891602 -9.150726 11653 61.640030 -4.822937 -9.143570 11654 62.083023 -5.106430 -9.420277 11655 61.771378 -5.082794 -9.117886 11656 23.204443 -3.231248 -10.310196 11657 52.114822 -6.504623 -9.915409 11658 52.950989 -6.901016 -9.421715 11659 61.532593 -5.265640 -9.183563 11660 61.461090 -6.104507 -9.342892 11661 62.278534 -6.569138 -9.064346 11662 7.744169 -7.830600 -5.457935 11663 8.324639 -8.003358 -6.144260 11664 7.742176 -7.141131 -5.287116 11665 25.009260 -4.942217 -11.653885 11666 53.171524 -8.024765 -8.646652 11667 53.281097 -8.680893 -7.442428 11668 53.627014 -7.923706 -7.376633 11669 60.834122 -8.888779 -9.353188 11670 61.888229 -9.233536 -8.680344 11671 60.977783 -9.842041 -9.040833 11672 61.792480 -7.574783 -9.055214 11673 64.156250 -8.103806 -9.060574 11674 7.799592 -8.461634 -5.669521 11675 7.930459 -9.556449 -6.011530 11676 8.168074 -8.905003 -6.188343 11677 24.200047 -5.899661 -11.545635 11678 24.749294 -5.894942 -11.845583 11679 25.151918 -6.599048 -12.346132 11680 7.503905 -9.387365 -5.483469 11681 7.221488 -8.709476 -4.972910 11682 7.208829 -9.451948 -5.067864 11683 7.608288 -10.184606 -5.665101 11684 8.175776 -10.641577 -6.367791 11685 7.524561 -8.727423 -5.389929 11686 8.270034 -11.585797 -6.584401 11687 8.502495 -9.645467 -6.628510 11688 8.513471 -8.819991 -6.523450 11689 9.012323 -8.743853 -6.938996 11690 13.150969 -7.622061 -9.119567 11691 20.408434 -7.431154 -10.772423 11692 24.199924 -6.759985 -11.823374 11693 25.843691 -6.831256 -13.009552 11694 47.509689 -9.355759 -10.302170 11695 46.553040 -9.328949 -10.442318 11696 52.249573 -8.995331 -9.342812 11697 64.716370 -9.395218 -8.889877 11698 9.736752 -9.263254 -7.626276 11699 12.110146 -7.825906 -8.732368 11700 15.380399 -8.507310 -10.026913 11701 15.286988 -7.342431 -9.743746 11702 14.752773 -8.011323 -9.749031 11703 17.585037 -7.347019 -10.236753 11704 16.868240 -7.259044 -10.089018 11705 16.926058 -7.852926 -10.232253 11706 17.323822 -8.581306 -10.460901 11707 46.832596 -10.565735 -10.135693 11708 47.737976 -10.724548 -10.016907 11709 48.433258 -11.850922 -9.735298 11710 49.585297 -11.198639 -9.822258 11711 51.552658 -11.172745 -9.137089 11712 50.559708 -10.787338 -9.692062 11713 52.324280 -9.866089 -8.915329 11714 65.722916 -10.893661 -9.159626 11715 46.200638 -11.445496 -10.116669 11716 52.740692 -9.022324 -8.954376 11717 46.395676 -12.514084 -9.694527 11718 46.521912 -13.867401 -9.220520 11719 47.496033 -12.931427 -9.341164 11720 47.204681 -11.736984 -9.751534 11721 60.034058 -10.153824 -9.540688 11722 66.268036 -12.133987 -9.176567 11723 50.423050 -12.076675 -9.367626 11724 65.842468 -12.002426 -8.328903 11725 45.983734 -15.179535 -9.135544 11726 53.187103 -16.246094 -9.438301 11727 55.257782 -16.192062 -8.860550 11728 55.649887 -14.896027 -9.470192 11729 53.040085 -17.599609 -8.222763 11730 52.412735 -17.106812 -8.891510 11731 7.801871 -14.642591 -5.538929 11732 8.134514 -15.748169 -5.672401 11733 8.923766 -16.038021 -6.917173 11734 46.514938 -16.746704 -9.665356 11735 49.482437 -16.447266 -10.495743 11736 54.239441 -17.850937 -8.035423 11737 67.387970 -15.948364 -8.653061 11738 45.904007 -16.370239 -9.032269 11739 67.677185 -17.744781 -7.894668 11740 35.172112 -20.529566 -11.281776 11741 34.267059 -20.544472 -11.181932 11742 22.285881 -19.890041 -9.930540 11743 35.223442 -21.705732 -10.501987 11744 36.075249 -20.745310 -11.148983 11745 19.295425 -20.684858 -9.297895 11746 27.582819 -20.951925 -9.843584 11747 29.794590 -20.732986 -10.343134 11748 30.610510 -20.405140 -10.724337 11749 31.670168 -20.463043 -10.853148 11750 30.712976 -21.125067 -10.196329 11751 31.790735 -21.069057 -10.412468 11752 34.854076 -23.167654 -9.383790 11753 35.539696 -22.874430 -9.790182 11754 68.070618 -20.489929 -9.293152 11755 16.913153 -21.424231 -8.597640 11756 23.750809 -22.982132 -10.436928 11757 24.557358 -22.787720 -10.572506 11758 25.393829 -22.830917 -11.053123 11759 26.020050 -23.115433 -11.121563 11760 25.957504 -22.900558 -10.917690 11761 26.107841 -23.046494 -10.890133 11762 11.482482 -21.105272 -6.233742 11763 21.801025 -25.252106 -11.381870 11764 26.892227 -24.992142 -10.930298 11765 25.988190 -23.370270 -10.857811 11766 36.378952 -24.667450 -11.573204 11767 28.141113 -24.840881 -11.704937 11768 15.963102 -21.988993 -7.979081 11769 28.340927 -25.503525 -11.263271 11770 36.873764 -24.815201 -10.453449 11771 13.112672 -21.834496 -6.942750 11772 20.095932 -26.924728 -11.523880 11773 20.838898 -26.438828 -11.226727 11774 21.430893 -25.955627 -11.324284 11775 26.695877 -26.152939 -10.036701 11776 25.791290 -25.323242 -10.295807 11777 28.126472 -26.179901 -10.587616 11778 27.902786 -26.855270 -9.803493 11779 29.124481 -27.388840 -9.881695 11780 28.033936 -27.658691 -9.147774 11781 36.863342 -26.752731 -9.756748 11782 36.340492 -27.611694 -10.048775 11783 50.901672 -26.659134 -11.794426 11784 14.136796 -22.132410 -7.222734 11785 19.373055 -27.505295 -8.867645 11786 19.620438 -27.874207 -7.602753 11787 19.030144 -27.823654 -7.978653 11788 19.549164 -27.674606 -11.695156 11789 33.186829 -27.267838 -10.805115 11790 34.452316 -28.353577 -10.264175 11791 52.493195 -27.600052 -11.588541 11792 18.003952 -32.423737 -10.666405 11793 17.321091 -31.142273 -9.907177 11794 17.305016 -32.672836 -9.986729 11795 18.735458 -31.780273 -11.267477 11796 18.781677 -32.915695 -11.065224 11797 19.790207 -32.702377 -11.586082 11798 25.434402 -32.357025 -11.233810 11799 24.402939 -33.667725 -10.681465 11800 27.293076 -33.152573 -11.019318 11801 28.317780 -32.853470 -11.181995 11802 31.704485 -32.422501 -11.519012 11803 21.862015 -33.327759 -11.553503 11804 22.653900 -33.940033 -10.801033 11805 32.157974 -33.366821 -11.016010 11806 51.255005 -32.059067 -12.043339 11807 20.337738 -33.923279 -11.308418 11808 33.932610 -34.473175 -11.728943 11809 21.373322 -34.310913 -10.960377 11810 59.660080 -34.792252 -11.711380 11811 33.854614 -34.878128 -11.691124 11812 59.503784 -35.821838 -11.420792 11813 60.188080 -35.542130 -11.397705 11814 67.403137 -34.316025 -9.913239 11815 32.783150 -36.424133 -11.546261 11816 60.693146 -36.744965 -11.092983 11817 67.361679 -35.402542 -10.006088 11818 58.708115 -37.414825 -11.386543 11819 59.932327 -36.360062 -10.989227 11820 59.832565 -37.627960 -10.680496 11821 66.899933 -37.048019 -10.657581 11822 26.540665 -38.330322 -11.949768 11823 30.359863 -39.619202 -11.191360 11824 31.366455 -39.473572 -11.245995 11825 32.707916 -37.444931 -10.588421 11826 32.938034 -37.735947 -9.601852 11827 33.397873 -38.379395 -10.036751 11828 61.580124 -38.460800 -10.528206 11829 60.156921 -39.087128 -9.912914 11830 60.930069 -39.573608 -8.981873 11831 62.158813 -37.809540 -11.377567 11832 66.456009 -37.820602 -10.953293 11833 57.475800 -40.226974 -11.445564 11834 62.674774 -38.441986 -11.206669 11835 66.195587 -38.485550 -10.722744 11836 22.985710 -40.246918 -11.347553 11837 22.224350 -41.388535 -11.144333 11838 51.713348 -40.229370 -12.415266 11839 56.229431 -40.149429 -10.439068 11840 56.780869 -40.246094 -11.101284 11841 56.374252 -41.308945 -11.041821 11842 57.266022 -39.748337 -10.633007 11843 56.561295 -39.883606 -9.711300 11844 59.980438 -39.729507 -8.786674 11845 62.792206 -38.893173 -10.808235 11846 57.168579 -42.613022 -11.213013 11847 56.644409 -42.148239 -11.278236 11848 57.016678 -41.871231 -11.447388 11849 41.855820 -44.908264 -11.738422 11850 40.640335 -44.997726 -11.843475 11851 41.596222 -42.751389 -12.939503 11852 43.146500 -46.043793 -11.878792 11853 41.877045 -45.638687 -11.128563 11854 55.601105 -42.631531 -10.356766 11855 55.022308 -42.787369 -9.829594 11856 54.829819 -41.843201 -9.741203 11857 58.384293 -43.117981 -11.166893 11858 58.767319 -44.735855 -9.888405 11859 61.203949 -46.132858 -9.187042 11860 23.024918 -44.291138 -12.497128 11861 32.619904 -44.583862 -13.264278 11862 57.135498 -44.322083 -9.764580 11863 57.593018 -43.897705 -10.505970 11864 22.879028 -45.149765 -12.393120 11865 34.658180 -45.409454 -13.075115 11866 34.474487 -46.125320 -13.099831 11867 39.988937 -45.095139 -12.666615 11868 63.851562 -45.862381 -11.404327 11869 41.091949 -46.157516 -11.073906 11870 63.341675 -46.776581 -11.790035 11871 43.541122 -47.256821 -11.287533 11872 44.086426 -47.282959 -12.278816 11873 44.304443 -48.742126 -11.712074 11874 50.959686 -48.148605 -11.679073 11875 53.413788 -48.191666 -11.738533 11876 52.778732 -48.030518 -11.965530 11877 52.559555 -47.768372 -11.133938 11878 53.449356 -48.233093 -10.355286 11879 22.686646 -48.131927 -11.759129 11880 43.590408 -50.153946 -10.727917 11881 44.346283 -51.736313 -11.420059 11882 56.589066 -50.108215 -11.468628 11883 22.965187 -48.984604 -11.879295 11884 23.015488 -50.850266 -12.278999 11885 38.350739 -51.920059 -12.188065 11886 40.119858 -49.847351 -11.476608 11887 40.326263 -49.079056 -12.372787 11888 57.623352 -50.489090 -12.496883 11889 57.583221 -50.415573 -11.736343 11890 58.458008 -50.591537 -11.726624 11891 51.082703 -51.226608 -12.169586 11892 23.812393 -55.433746 -12.646278 11893 23.842117 -53.964264 -12.606514 11894 22.883896 -54.465515 -11.168983 11895 31.364105 -54.164047 -13.763483 11896 32.007538 -52.706543 -13.667900 11897 37.596619 -53.047958 -12.512108 11898 37.429214 -53.050781 -11.505127 11899 39.187744 -51.065186 -11.345840 11900 52.064087 -52.725449 -12.354366 11901 51.551590 -51.853149 -11.016190 11902 37.438263 -53.980911 -12.156914 11903 43.748016 -55.215988 -12.414837 11904 43.059662 -53.649048 -11.529919 11905 42.063904 -55.018463 -10.734661 11906 44.558685 -53.736832 -12.412113 11907 45.042374 -52.776642 -12.187965 11908 44.175049 -52.863449 -11.768120 11909 54.991608 -54.499878 -11.765343 11910 54.619324 -53.900558 -10.275902 11911 23.360733 -56.903763 -12.256538 11912 23.259354 -58.080963 -11.984692 11913 23.909538 -58.113480 -12.820095 11914 42.933884 -56.334518 -11.124100 11915 56.237518 -55.284943 -11.617912 11916 25.078827 -55.884262 -13.541710 11917 37.461685 -54.711563 -10.617012 11918 43.923141 -57.401672 -12.799740 11919 43.604691 -56.795166 -12.185898 11920 24.899063 -59.351288 -13.344490 11921 38.262634 -56.352875 -11.190529 11922 42.696823 -56.380402 -9.799263 11923 42.083649 -55.837189 -10.455032 11924 41.776154 -55.546265 -9.766487 11925 44.362732 -57.936737 -12.844093 11926 57.331543 -57.863510 -11.700203 11927 56.782257 -56.525787 -12.400162 11928 57.317917 -56.112427 -11.174450 11929 32.513580 -59.921783 -13.348408 11930 34.097336 -59.808350 -13.578011 11931 34.789467 -59.609924 -13.888596 11932 45.147736 -58.207809 -12.344872 11933 46.351410 -58.405258 -12.025135 11934 47.503113 -58.162033 -11.215488 11935 47.621429 -59.263367 -12.797234 11936 48.585938 -58.509903 -11.501831 11937 49.499664 -58.766998 -11.462357 11938 49.219696 -59.201385 -12.312275 11939 51.215103 -59.780136 -11.870888 11940 50.245468 -59.203232 -11.681412 11941 55.283539 -59.848450 -11.333805 11942 24.149521 -63.253647 -13.492435 11943 24.372711 -64.239685 -13.579861 11944 25.576065 -63.441818 -13.884571 11945 30.821503 -61.558273 -13.392929 11946 39.658585 -60.816437 -11.752647 11947 40.111420 -60.606339 -12.632263 11948 39.061470 -62.150284 -12.045834 11949 30.555588 -62.520813 -13.444588 11950 31.835024 -63.795425 -13.710844 11951 40.659073 -63.235916 -13.944408 11952 23.442558 -62.944275 -12.516243 11953 29.111946 -62.974243 -13.728924 11954 31.167824 -63.479095 -13.420338 11955 29.844948 -63.748337 -13.595428 11956 39.372498 -63.507919 -13.227188 11957 44.915512 -63.008682 -13.006882 11958 44.517426 -63.071396 -12.751198 11959 47.570526 -63.284103 -13.119705 11960 47.970230 -63.478455 -12.982086 11961 48.562042 -63.886902 -12.996754 11962 29.444862 -64.738251 -13.653355 11963 30.418076 -64.544571 -13.422577 11964 37.304443 -65.359802 -12.618500 11965 37.840240 -66.586151 -13.627075 11966 38.288971 -64.255569 -12.820824 11967 49.090973 -65.228775 -13.226265 11968 49.333832 -64.172058 -12.672848 11969 50.147003 -64.390152 -12.194878 11970 23.266647 -64.582260 -12.444225 11971 23.156525 -66.452408 -12.108051 11972 24.496033 -65.419022 -13.436646 11973 23.582100 -63.756439 -13.153046 11974 24.599411 -66.541229 -13.519562 11975 25.304428 -67.213562 -13.774708 11976 27.881592 -66.278839 -13.808876 11977 28.834015 -65.531784 -13.726372 11978 28.975761 -66.665710 -13.638756 11979 29.768875 -65.599869 -13.553665 11980 48.614166 -66.797089 -13.101688 11981 49.435272 -67.018173 -13.056240 11982 50.191376 -66.183807 -13.009686 11983 50.174042 -65.234192 -12.849056 11984 26.114075 -67.412872 -13.786316 11985 26.998474 -67.165573 -13.780632 11986 41.689270 -66.512634 -13.195538 11987 42.179260 -65.900940 -13.322845 11988 50.133789 -67.182434 -12.951630 11989 51.457123 -65.790924 -11.824062 11990 50.771957 -66.994415 -12.357315 11991 51.503799 -66.937622 -11.621490 11992 50.835114 -65.415131 -12.295738 11993 24.318436 -67.608185 -13.330856 11994 29.230576 -68.035934 -13.807312 11995 36.702118 -66.844055 -12.778206 11996 45.419083 -66.792313 -12.407280 11997 45.249008 -68.228561 -13.402176 11998 45.042847 -67.627274 -12.623363 11999 48.088303 -67.106461 -12.797726 12000 47.474854 -66.794250 -12.573750 12001 27.532730 -68.904694 -13.071213 12002 26.668793 -68.173691 -13.463276 12003 26.419708 -68.988892 -12.968441 12004 28.033875 -67.791733 -13.527416 12005 41.288422 -68.401062 -13.577606 12006 49.823669 -68.058929 -12.454292 12007 29.802414 -71.017990 -12.816036 12008 30.034470 -70.601990 -13.984905 12009 29.005173 -69.434830 -13.280888 12010 40.771515 -69.229645 -13.206593 12011 41.223312 -70.215347 -13.700142 12012 45.004639 -69.048157 -12.862904 12013 44.672577 -70.129745 -12.029839 12014 45.113586 -71.439865 -12.339058 12015 40.764343 -71.257141 -13.303635 12016 41.393890 -72.341187 -13.873413 12017 30.184570 -71.829361 -13.936714 12018 27.154175 -73.525436 -13.720734 12019 28.286514 -73.848175 -14.288879 12020 29.652702 -72.295776 -13.120201 12021 41.435730 -73.175827 -13.960526 12022 45.375580 -72.024368 -13.012344 12023 36.374680 -72.934845 -13.275639 12024 36.237411 -74.066711 -13.130434 12025 41.464417 -73.956528 -14.062202 12026 40.933075 -73.327026 -13.556778 12027 40.114380 -73.813766 -12.901695 12028 40.871567 -74.579163 -13.590431 12029 45.567413 -74.065216 -13.146015 12030 45.616440 -73.082184 -13.015282 12031 35.156113 -76.291260 -13.411324 12032 40.829147 -76.216690 -13.230793 12033 34.261017 -77.162933 -13.954926 12034 36.576744 -74.723022 -14.125175 12035 35.879082 -75.200745 -13.171314 12036 45.252747 -77.203796 -13.859547 12037 33.122635 -77.838928 -13.997356 12038 33.715881 -77.480362 -12.887375 12039 34.509140 -76.996979 -13.164986 12040 42.015778 -77.424866 -14.196457 12041 45.747879 -78.202240 -13.676685 12042 45.977982 -77.696609 -12.909363 12043 45.320786 -78.316452 -14.075592 12044 23.654266 -79.138962 -13.751278 12045 28.731354 -81.359238 -14.775421 12046 32.293144 -78.271622 -14.044563 12047 31.300461 -78.642563 -14.170971 12048 32.346848 -78.448410 -12.851242 12049 41.303375 -77.843002 -13.901787 12050 45.975677 -79.704956 -12.967705 12051 45.989349 -78.787338 -13.160789 12052 23.466652 -80.593384 -14.104294 12053 23.679344 -80.006256 -12.918152 12054 23.575233 -81.118195 -13.029358 12055 36.545471 -80.314743 -14.151424 12056 39.726387 -78.680298 -13.272511 12057 38.708679 -79.728088 -13.878590 12058 40.175735 -79.814468 -14.466827 12059 40.602890 -77.869644 -13.397415 12060 39.945549 -77.667099 -12.485035 12061 35.479736 -80.352859 -13.444344 12062 44.207260 -81.694397 -14.394722 12063 23.592659 -81.853363 -14.370537 12064 28.107162 -83.615494 -15.067516 12065 30.147011 -82.058990 -14.113567 12066 29.460907 -82.696198 -14.582115 12067 31.120956 -82.212875 -13.977081 12068 31.781633 -82.759125 -14.648281 12069 32.082390 -81.635452 -13.587006 12070 33.769592 -80.883804 -13.270611 12071 23.611664 -82.924606 -14.130951 12072 25.820206 -84.555054 -14.869259 12073 42.647537 -84.182816 -13.941238 12074 16.184692 -84.158691 -14.922977 12075 15.160034 -84.041489 -14.545967 12076 15.979294 -84.996231 -15.014240 12077 16.866379 -84.515686 -15.016991 12078 16.862114 -83.932953 -14.673374 12079 16.053116 -83.607864 -14.335545 12080 18.172371 -84.356277 -14.413910 12081 19.804169 -84.488586 -13.996376 12082 19.665833 -83.751389 -13.358936 12083 24.404663 -83.821655 -14.609829 12084 26.976913 -85.560883 -14.863983 12085 27.770081 -86.747025 -14.852547 12086 30.737259 -82.731216 -14.374567 12087 43.083344 -84.384415 -12.607044 12088 16.316437 -85.833084 -15.051071 12089 15.415047 -85.987274 -14.679237 12090 16.949783 -86.573135 -14.805771 12091 18.092155 -85.957993 -14.963890 12092 18.699562 -85.336929 -14.931938 12093 19.031387 -86.030762 -14.872578 12094 16.974411 -83.451050 -13.832275 12095 19.432831 -85.308533 -14.563805 12096 23.738449 -83.651382 -13.821438 12097 23.965042 -84.126343 -13.900040 12098 30.156326 -82.803009 -14.436905 12099 17.057327 -85.445435 -15.050190 12100 20.718788 -85.464569 -13.680405 12101 19.916077 -86.677750 -14.246296 12102 24.813049 -85.189865 -14.291668 12103 25.607323 -85.717560 -14.270821 12104 16.029007 -87.449478 -14.145752 12105 18.806213 -86.992188 -14.577374 12106 39.381584 -85.269104 -13.088165 12107 40.460495 -85.523605 -13.718353 12108 26.419739 -86.455963 -13.966911 12109 27.314056 -87.346985 -13.651756 12110 28.534561 -87.813171 -14.828831 12111 36.101685 -87.542755 -14.960785 12112 37.312271 -86.716644 -14.835510 12113 28.019760 -88.053482 -13.868690 12114 22.642380 -90.738190 -14.779030 12115 23.030548 -89.953659 -14.077244 12116 24.753738 -90.143005 -15.401459 12117 25.445984 -90.123962 -15.463585 12118 25.328613 -89.697220 -14.732685 12119 24.281723 -89.862885 -14.829353 12120 26.373955 -89.858459 -14.268562 12121 26.019501 -89.698502 -14.375343 12122 26.268799 -90.111923 -15.021061 12123 36.133430 -88.861526 -13.709213 12124 22.073586 -90.561737 -14.238216 12125 29.764954 -92.870895 -14.507713 12126 17.380470 -93.943741 -14.655457 12127 17.197037 -94.942352 -14.639519 12128 20.777443 -93.267227 -15.580338 12129 20.725739 -92.925797 -14.489109 12130 21.351425 -91.874023 -14.350365 12131 30.842041 -93.829025 -14.446751 12132 30.501472 -95.967834 -14.573071 12133 30.984177 -94.838470 -14.785240 12134 16.776672 -94.266922 -13.691669 12135 16.178177 -95.083145 -13.529678 12136 15.752892 -97.032196 -13.412312 12137 27.582382 -98.306641 -13.776550 12138 28.140854 -97.741379 -14.539925 12139 26.825996 -98.631683 -14.768671 12140 19.102066 -98.487961 -15.942581 12141 18.999451 -99.323730 -15.533573 12142 18.396553 -98.651596 -15.530586 12143 13.378555 61.188248 -4.559593 12144 10.710358 62.304550 -4.507034 12145 12.698242 61.945114 -3.886780 12146 13.350304 61.579071 -2.719498 12147 9.903214 61.661392 -5.002258 12148 13.683105 60.799561 -4.586708 12149 9.209991 60.320663 -4.938919 12150 9.429504 59.016678 -5.090607 12151 9.733124 58.540924 -5.238876 12152 9.761627 58.343506 -5.344993 12153 9.863846 58.358978 -5.162567 12154 17.617378 58.455658 -4.637390 12155 17.383636 57.994766 -4.711121 12156 19.401886 58.361023 -4.797577 12157 20.374878 58.012192 -3.820213 12158 19.915726 58.526703 -4.057793 12159 20.170746 57.854248 -4.804520 12160 9.603439 58.175247 -5.123779 12161 17.072037 57.119095 -4.359253 12162 20.811058 56.799561 -4.583687 12163 20.433990 57.321762 -3.378471 12164 6.454048 55.131027 -5.550163 12165 7.985489 55.609085 -4.723389 12166 8.668503 56.029205 -3.749496 12167 8.468155 55.254623 -3.722153 12168 26.102051 55.552994 -4.669609 12169 25.295914 55.525742 -4.874580 12170 26.987457 55.573166 -4.504928 12171 6.402710 53.243408 -5.318573 12172 28.363403 54.736832 -3.486244 12173 27.711761 55.250809 -4.219002 12174 33.401489 54.482498 -3.638489 12175 4.966354 53.482468 -6.608642 12176 34.475845 54.334976 -3.691849 12177 35.464767 53.495667 -3.658630 12178 5.617470 52.365891 -6.050575 12179 6.408653 52.447327 -5.350357 12180 13.836746 52.774933 -5.713486 12181 14.114288 50.645142 -5.761307 12182 14.199432 52.894577 -5.405464 12183 36.552490 52.787140 -3.139694 12184 36.304718 51.906677 -4.345001 12185 6.175057 50.587082 -6.065658 12186 7.248947 49.408051 -5.592873 12187 7.229431 50.919739 -5.191055 12188 17.787918 48.792633 -5.175148 12189 14.888840 49.133682 -5.489578 12190 14.480133 49.839355 -5.409515 12191 19.662491 46.910004 -5.384979 12192 30.205330 47.131027 -5.515869 12193 6.894539 46.851318 -5.967117 12194 16.937622 46.817810 -5.961029 12195 16.963638 48.022476 -5.025177 12196 20.923813 46.238312 -5.867317 12197 29.711815 47.276718 -5.464783 12198 36.417526 47.072052 -5.167068 12199 36.357498 47.871368 -5.017845 12200 18.030777 45.550797 -5.889519 12201 18.058044 46.768677 -5.114143 12202 21.267601 45.682724 -5.886986 12203 21.305489 44.623154 -5.843307 12204 38.331589 46.233902 -5.018845 12205 42.737885 45.883331 -3.504852 12206 41.715088 46.616364 -2.760658 12207 40.498352 46.674606 -3.774200 12208 41.605865 46.007690 -4.904022 12209 43.636612 44.161636 -5.211990 12210 43.907394 44.685852 -4.311157 12211 43.080246 45.146545 -4.764961 12212 2.212738 43.558472 -6.320541 12213 1.915009 44.120087 -5.141624 12214 1.991089 42.612320 -6.164184 12215 2.775688 44.181488 -6.288147 12216 3.772316 44.878571 -6.189041 12217 2.579537 45.273560 -5.277954 12218 4.352455 45.871017 -5.661835 12219 3.434387 45.800781 -5.404137 12220 5.047325 45.240295 -6.389557 12221 5.271431 46.246521 -5.678635 12222 19.119919 45.581619 -5.035980 12223 18.687210 44.847931 -5.398529 12224 30.026581 43.798492 -6.157288 12225 30.226807 46.135193 -5.635452 12226 38.420586 46.944214 -3.693687 12227 37.374924 46.565186 -4.245117 12228 3.712250 46.536804 -5.012955 12229 2.817116 46.487534 -4.375748 12230 3.635246 43.920609 -6.793564 12231 4.417320 44.309326 -6.770325 12232 19.527237 44.248215 -5.225052 12233 30.101654 41.800385 -6.248176 12234 45.704849 42.373901 -4.207436 12235 45.881912 42.641937 -2.957443 12236 45.363113 43.203140 -3.440178 12237 20.458977 42.061554 -5.511032 12238 20.439270 42.850098 -5.556656 12239 19.485214 42.796707 -6.050384 12240 30.672485 40.454681 -6.377991 12241 41.827057 41.255341 -5.978760 12242 44.173065 43.710526 -4.972931 12243 19.699844 41.138092 -6.083183 12244 41.093170 40.946182 -5.630890 12245 41.375153 40.348312 -5.910004 12246 45.820770 41.405212 -4.999557 12247 2.184891 41.049103 -5.925774 12248 19.711258 40.391083 -6.039902 12249 22.639656 39.402313 -4.935516 12250 23.452545 39.006424 -5.419395 12251 37.714401 39.769501 -5.363769 12252 37.085129 39.202927 -5.495071 12253 37.351349 39.356979 -5.061195 12254 46.091415 40.183044 -5.853454 12255 47.248413 39.278534 -5.447403 12256 20.330399 40.207230 -5.562683 12257 23.986732 38.955536 -6.149086 12258 29.968231 40.163864 -6.524429 12259 36.368347 38.779694 -6.306732 12260 37.554306 38.630402 -5.621849 12261 47.552139 39.128952 -4.540268 12262 47.239746 39.817307 -4.398407 12263 46.860550 40.729813 -3.620430 12264 47.246704 38.902710 -3.596314 12265 5.605217 38.259430 -6.271965 12266 4.186417 38.683060 -6.343162 12267 5.016365 39.555359 -5.684082 12268 6.370072 36.923462 -6.878220 12269 24.562599 37.987885 -6.660034 12270 24.007172 37.944519 -5.941879 12271 36.871689 38.554214 -5.787430 12272 47.836975 38.194427 -4.677093 12273 48.154297 37.743240 -5.840683 12274 7.041367 37.891418 -6.167557 12275 8.294189 38.056824 -5.660797 12276 8.186134 37.009003 -6.172691 12277 7.505089 36.692795 -6.676155 12278 21.358170 37.936752 -6.119568 12279 24.127533 37.286942 -6.133331 12280 24.497192 37.033478 -6.493545 12281 36.138199 37.530838 -6.725861 12282 48.641205 36.857849 -5.906914 12283 2.855515 39.243469 -6.542435 12284 8.928635 34.176010 -7.058571 12285 24.700867 36.378479 -6.585403 12286 22.930183 36.276321 -6.003609 12287 24.640533 35.515533 -6.384460 12288 9.636124 36.065582 -4.803871 12289 9.236481 35.402634 -5.213028 12290 9.276413 36.804886 -5.419388 12291 38.131729 34.370758 -7.001572 12292 47.898804 34.654236 -4.922501 12293 48.278381 36.533051 -5.019653 12294 48.447861 34.280411 -5.997696 12295 9.176605 33.361511 -6.862533 12296 9.178696 34.247009 -6.620323 12297 24.380417 33.071945 -5.607345 12298 24.223557 33.876907 -5.765602 12299 25.151146 33.644089 -6.116600 12300 48.017395 32.771729 -6.062424 12301 47.386032 33.386490 -4.829254 12302 25.495750 32.675247 -5.736694 12303 26.529282 32.253555 -6.205917 12304 38.704796 32.461731 -6.256897 12305 39.171555 32.668427 -6.528107 12306 8.998512 32.264343 -6.616852 12307 9.193756 32.623749 -6.867119 12308 23.120087 31.243225 -5.333664 12309 23.652359 31.395752 -3.777565 12310 24.360443 31.780365 -4.317558 12311 30.177490 31.558243 -5.259567 12312 28.874146 31.416534 -6.358116 12313 28.715179 31.383453 -5.266708 12314 31.875055 31.502045 -6.600876 12315 38.549774 31.621582 -6.019020 12316 39.789810 31.456757 -6.254074 12317 46.949615 31.671539 -4.816780 12318 8.490295 30.057159 -7.502426 12319 24.627518 32.189743 -4.975929 12320 33.730087 30.583817 -5.490478 12321 32.749687 31.155487 -6.222671 12322 34.881569 29.903061 -5.133263 12323 37.118240 30.184250 -5.364235 12324 38.407227 30.716705 -5.369537 12325 40.264023 30.379318 -6.298111 12326 46.602509 30.476334 -5.379593 12327 46.225922 30.528580 -5.021561 12328 47.040131 30.592804 -5.614029 12329 3.048363 29.541504 -6.801666 12330 4.083992 29.461823 -6.992371 12331 4.121101 30.583649 -6.550125 12332 7.315971 29.058594 -6.969826 12333 30.613434 28.435257 -6.237167 12334 35.921326 29.704651 -5.124710 12335 47.985535 29.341187 -5.900452 12336 47.027740 29.725281 -5.191666 12337 5.030808 29.603226 -6.764709 12338 4.166489 28.630768 -7.121902 12339 8.114288 30.377060 -6.758453 12340 21.440994 27.913010 -7.209030 12341 24.772667 28.707230 -5.450989 12342 35.627945 28.133850 -6.665604 12343 48.564087 28.596390 -6.240066 12344 4.155418 27.321045 -7.292572 12345 2.407898 28.078644 -6.887772 12346 21.679749 26.406754 -7.178345 12347 21.925423 27.948486 -6.296265 12348 22.505356 27.654724 -6.007805 12349 32.185844 27.661942 -5.714363 12350 31.265434 27.928589 -4.708176 12351 34.271561 27.702881 -6.615463 12352 38.151161 26.991760 -5.258865 12353 36.577888 27.930878 -4.622169 12354 36.574707 27.901749 -5.863678 12355 40.685822 28.035049 -4.938118 12356 40.207962 29.587357 -5.379166 12357 1.052887 27.261017 -6.378250 12358 2.307304 26.172180 -7.271881 12359 0.642868 26.472092 -6.265213 12360 4.252228 26.322128 -7.476791 12361 5.721527 28.339050 -6.974075 12362 5.531693 26.578125 -7.311035 12363 35.094963 27.920944 -5.421577 12364 49.033051 27.510254 -5.732925 12365 49.418945 25.971527 -6.199989 12366 0.700081 25.479095 -6.429840 12367 6.549889 24.625916 -8.401947 12368 6.846733 27.320038 -7.361984 12369 41.272003 27.102829 -6.210419 12370 5.930542 25.591507 -7.640900 12371 40.227310 25.083862 -6.696823 12372 40.781494 24.472488 -6.576652 12373 42.077026 23.853912 -7.152397 12374 41.683807 24.781799 -6.373077 12375 49.363846 24.335724 -6.736557 12376 1.108070 21.654205 -7.271805 12377 12.647308 23.717758 -8.632820 12378 41.571442 24.058472 -6.569168 12379 50.343994 24.844376 -4.199188 12380 49.938232 24.773834 -4.800476 12381 49.845657 23.888397 -4.520805 12382 13.024734 22.792450 -7.759216 12383 42.342499 23.254776 -7.622635 12384 0.651611 23.526474 -6.737808 12385 48.035034 21.270096 -5.981613 12386 47.446808 20.084229 -6.364685 12387 46.865982 19.939743 -7.007416 12388 30.195053 18.777649 -6.649032 12389 28.512550 19.738373 -5.793426 12390 3.516571 17.896667 -8.002327 12391 13.619919 19.300491 -7.499702 12392 47.097382 19.162094 -6.695877 12393 15.019547 16.389664 -8.022026 12394 15.531021 13.837555 -7.530670 12395 16.471100 13.763229 -8.333939 12396 25.678345 17.261505 -7.408661 12397 31.569939 17.803818 -7.094681 12398 53.084534 16.858017 -5.842239 12399 54.644302 16.564758 -5.552978 12400 53.865646 16.870911 -5.762527 12401 10.769424 15.844574 -7.489700 12402 14.242073 16.421631 -7.194321 12403 14.761108 14.934021 -7.246452 12404 27.502190 16.096893 -6.421738 12405 28.290726 15.790192 -5.626785 12406 37.360619 15.994385 -8.046005 12407 36.802078 16.079071 -7.080749 12408 48.246033 16.905319 -5.209282 12409 48.401779 18.236389 -5.379486 12410 47.778839 19.074692 -6.007233 12411 49.480621 11.160217 -4.098160 12412 49.078262 12.255981 -5.105926 12413 49.977814 12.372330 -4.032143 12414 50.358093 15.672729 -6.373337 12415 49.808945 14.673386 -6.217834 12416 53.676422 16.584579 -5.052299 12417 55.738159 15.516571 -6.846023 12418 4.089691 16.654953 -7.119354 12419 9.969940 14.880371 -8.708572 12420 10.645172 14.738876 -8.174492 12421 32.184326 14.771423 -7.551475 12422 32.620041 14.496231 -6.523819 12423 31.724672 14.922089 -6.520698 12424 38.229599 16.019409 -6.843803 12425 44.199722 15.445709 -6.438904 12426 46.312515 15.309143 -6.366150 12427 46.789093 15.663345 -6.653389 12428 47.421051 16.194885 -6.214966 12429 6.171852 13.797104 -7.530609 12430 13.475586 15.414291 -6.859619 12431 33.154640 14.088074 -7.463043 12432 34.886887 13.594360 -7.725189 12433 34.872932 13.772247 -7.318657 12434 34.236908 13.745651 -7.485252 12435 35.297012 13.398132 -7.317810 12436 45.394836 15.143936 -6.938949 12437 48.905106 14.102158 -7.088333 12438 6.682617 12.765564 -7.825363 12439 12.857849 13.605865 -7.582260 12440 35.202820 13.112869 -7.934715 12441 35.992249 12.608292 -7.616333 12442 6.455330 11.024292 -7.714950 12443 6.809044 11.792892 -8.110275 12444 15.184875 12.503571 -7.925514 12445 13.833969 13.099380 -7.851028 12446 15.312927 11.647705 -8.540176 12447 16.157471 12.712677 -8.006157 12448 56.603958 10.777191 -3.856613 12449 6.512879 10.024796 -8.322311 12450 6.337326 8.829315 -7.804428 12451 5.858498 11.846130 -6.384781 12452 5.887726 10.176620 -6.628769 12453 38.598869 9.424347 -7.632622 12454 38.660675 8.944031 -7.814773 12455 39.042046 8.801880 -7.411178 12456 7.286555 7.652290 -7.246860 12457 7.210167 6.747460 -6.067740 12458 8.058663 6.324887 -6.826430 12459 38.582001 8.382263 -7.788933 12460 57.385468 8.509277 -5.706444 12461 38.758606 7.532211 -7.331131 12462 48.323242 5.897079 -4.427223 12463 8.456437 6.943321 -7.871846 12464 9.655776 6.268341 -8.221009 12465 10.959113 5.654561 -8.519484 12466 11.651918 6.402361 -9.412877 12467 14.558254 4.932093 -9.257001 12468 23.799294 3.673935 -7.552025 12469 28.299133 5.566002 -7.819847 12470 38.023270 6.501404 -7.508850 12471 45.058685 5.321060 -7.574943 12472 57.864594 6.389496 -6.594429 12473 16.986725 4.156915 -8.943029 12474 20.185135 5.114365 -8.505661 12475 20.946205 5.597771 -8.922745 12476 26.241501 5.343903 -7.642410 12477 29.550301 3.924561 -8.336914 12478 39.251938 3.189278 -8.441360 12479 58.392227 5.561554 -6.201782 12480 58.200119 3.864510 -7.190018 12481 58.571640 4.627609 -6.374069 12482 29.210648 2.815002 -8.461823 12483 39.842026 2.436966 -7.305458 12484 39.864220 2.548569 -6.193245 12485 44.459900 2.226654 -6.891556 12486 56.915970 1.769806 -8.318359 12487 27.442810 1.471832 -8.234612 12488 28.164810 2.432907 -8.052017 12489 26.867783 2.613098 -7.558662 12490 28.041351 1.386948 -8.599869 12491 28.589493 3.998749 -7.804169 12492 30.020111 1.159088 -9.274410 12493 39.831749 2.110031 -8.278458 12494 43.870560 1.839996 -7.150101 12495 57.912506 1.772873 -7.965286 12496 57.888611 0.861679 -7.602447 12497 58.418854 1.950424 -7.544342 12498 58.630417 2.757034 -7.139450 12499 24.503944 1.578247 -7.533905 12500 23.949310 0.669374 -8.348959 12501 26.831627 0.840622 -8.359039 12502 26.074587 0.720569 -8.356430 12503 26.421164 0.322032 -8.962591 12504 39.900200 0.217117 -8.110359 12505 57.887878 -0.495316 -7.524200 12506 59.059830 1.978592 -6.557960 12507 59.431717 0.949585 -5.957878 12508 24.177038 -0.023184 -8.896297 12509 23.184311 -0.096227 -8.895766 12510 39.773087 -0.856934 -8.955826 12511 42.111359 -1.278061 -8.334305 12512 59.073868 -0.350342 -6.229462 12513 7.615424 -0.264099 -6.666620 12514 7.613623 -0.210876 -6.608263 12515 7.564299 -0.267365 -6.612710 12516 7.664778 -0.266357 -6.610445 12517 11.314219 -1.751543 -7.120457 12518 11.263777 -0.786149 -6.936223 12519 12.307950 -0.514571 -7.406347 12520 12.746591 0.423027 -7.503524 12521 11.861429 0.269726 -7.132681 12522 7.615332 -0.315002 -6.614400 12523 10.706179 -1.930461 -6.793747 12524 11.128798 -2.791521 -7.189231 12525 14.199387 -0.185436 -8.026843 12526 21.589373 -0.140562 -8.884179 12527 41.086594 -2.698273 -8.774811 12528 57.132141 -1.391098 -7.932960 12529 57.484161 -2.460434 -7.319794 12530 20.643667 -1.396462 -9.224318 12531 21.366318 -1.098624 -9.208694 12532 20.440498 -0.491922 -8.936581 12533 40.354630 -3.572281 -8.424744 12534 41.243500 -4.034729 -7.300522 12535 56.718079 -3.156387 -7.764725 12536 14.709305 -3.879298 -8.793666 12537 22.432358 -1.075452 -9.351688 12538 39.917381 -3.418121 -7.871857 12539 40.228302 -3.984863 -7.823135 12540 41.941040 -2.481857 -7.843346 12541 57.174362 -3.419342 -6.935051 12542 11.678535 -3.937868 -7.671794 12543 11.069571 -4.498489 -7.499947 12544 11.353618 -4.843049 -7.727472 12545 11.709452 -5.385105 -8.012032 12546 10.875753 -5.430427 -7.590035 12547 13.794035 -4.412724 -8.631705 12548 13.010321 -5.393119 -8.570777 12549 13.911377 -5.269887 -8.863379 12550 21.871014 -1.632666 -9.457439 12551 61.581116 -5.044907 -9.043095 12552 7.208138 -7.745391 -4.698911 12553 8.248981 -7.159035 -5.879648 12554 8.091388 -6.201854 -5.481317 12555 7.260030 -6.509131 -4.504236 12556 13.133252 -6.322690 -8.827085 12557 12.216227 -6.500597 -8.482396 12558 14.767602 -5.070503 -9.079945 12559 15.487878 -3.792999 -8.981513 12560 23.522596 -4.111485 -10.694756 12561 8.871828 -7.337959 -6.513367 12562 9.633024 -6.845408 -7.041000 12563 10.261073 -6.092119 -7.336936 12564 9.580739 -5.573423 -6.755314 12565 14.252092 -5.895233 -9.120277 12566 13.738358 -6.490406 -9.084044 12567 54.989456 -5.672562 -7.672790 12568 54.081940 -7.058670 -7.488953 12569 62.553909 -8.265503 -8.644356 12570 6.893336 -8.576679 -4.406625 12571 9.606283 -8.069538 -7.283968 12572 11.255675 -7.675102 -8.263539 12573 19.569277 -7.020086 -10.509796 12574 23.640127 -4.817094 -10.962341 12575 23.822962 -5.791216 -11.334557 12576 23.609779 -5.387552 -11.125681 12577 23.196856 -6.274616 -11.233877 12578 63.362045 -8.837311 -8.427551 12579 10.467266 -8.525812 -7.982943 12580 14.534311 -6.723988 -9.382477 12581 17.527048 -6.319470 -9.988859 12582 17.077482 -6.422515 -9.931733 12583 18.097670 -6.218429 -10.062262 12584 52.997955 -9.108566 -8.395859 12585 62.588745 -8.836578 -8.412941 12586 62.627823 -9.217102 -8.299637 12587 62.794067 -10.108902 -8.222534 12588 16.202370 -8.743576 -10.272326 12589 64.014145 -11.009018 -7.922867 12590 65.065796 -10.762878 -8.327942 12591 65.000809 -11.522171 -7.783173 12592 7.207262 -10.210761 -5.107290 12593 16.604399 -8.272601 -10.261588 12594 52.442108 -10.765549 -8.522018 12595 52.856750 -9.927795 -7.757965 12596 61.401886 -10.606766 -8.713867 12597 60.471649 -11.742157 -8.857468 12598 62.300430 -12.043015 -7.990761 12599 49.445007 -12.526855 -9.469330 12600 51.376755 -12.939423 -8.745468 12601 52.691498 -11.843582 -8.352631 12602 52.898865 -10.881348 -7.814392 12603 59.481262 -12.884232 -8.916443 12604 66.028854 -12.910110 -7.682281 12605 7.874403 -11.653007 -6.068030 12606 47.672791 -14.023636 -8.780128 12607 48.661072 -13.315109 -9.205036 12608 49.934952 -13.372910 -9.054619 12609 50.512421 -15.328629 -7.046844 12610 51.989655 -15.160583 -6.706551 12611 51.944855 -14.328766 -7.735588 12612 52.550598 -13.164337 -8.227463 12613 58.707550 -14.052917 -8.805542 12614 48.892609 -14.306168 -8.577164 12615 50.401398 -14.237061 -8.413406 12616 53.209412 -11.245300 -7.640854 12617 57.711792 -14.024689 -9.129349 12618 49.520523 -14.981400 -7.889168 12619 56.833923 -14.531937 -9.243103 12620 57.817688 -14.987610 -8.699974 12621 56.648987 -15.486099 -8.838470 12622 7.451830 -14.972841 -4.731226 12623 46.033051 -15.897644 -8.407867 12624 52.475723 -16.643250 -9.361046 12625 56.435394 -16.200623 -8.548828 12626 66.958435 -15.082291 -7.601868 12627 46.174164 -17.176483 -8.757065 12628 51.551498 -17.905197 -8.468559 12629 49.657196 -17.615097 -9.120621 12630 47.066238 -17.677414 -8.817261 12631 47.688217 -17.562057 -9.341072 12632 47.822586 -17.898376 -8.924850 12633 48.311829 -17.551331 -9.289009 12634 48.398773 -18.652069 -8.000916 12635 20.193348 -21.291321 -8.922344 12636 18.906925 -21.367979 -8.815584 12637 19.243364 -21.999229 -8.362054 12638 21.330442 -20.770603 -9.333596 12639 23.557985 -20.301205 -9.819366 12640 23.999565 -21.227484 -9.262167 12641 22.553083 -20.991047 -9.286325 12642 23.003958 -21.879381 -8.712407 12643 24.905993 -20.537916 -9.816734 12644 29.496531 -21.584675 -9.649588 12645 30.407482 -21.818113 -9.615456 12646 33.088390 -20.939249 -10.718054 12647 8.305689 -16.639759 -5.495188 12648 28.488071 -21.510628 -9.556433 12649 27.730860 -22.079283 -9.024745 12650 28.834282 -22.512087 -8.836460 12651 28.845098 -23.773478 -7.830146 12652 29.994396 -22.665001 -8.888515 12653 31.484999 -21.735392 -9.851939 12654 32.519989 -21.980236 -9.834418 12655 33.678890 -21.856180 -10.127278 12656 36.995331 -23.935242 -9.718052 12657 36.243370 -22.891655 -10.033705 12658 68.188553 -23.066467 -9.142914 12659 17.886185 -21.836714 -8.370235 12660 23.007538 -24.076889 -10.082981 12661 25.080772 -23.086975 -10.435394 12662 25.761299 -23.119217 -10.705673 12663 25.407555 -23.981323 -10.440567 12664 31.305668 -22.453918 -9.266348 12665 31.989389 -22.767677 -9.135344 12666 33.111328 -22.694517 -9.388632 12667 34.231781 -22.463800 -9.771220 12668 67.827408 -25.050186 -9.664871 12669 24.363625 -23.250473 -10.112804 12670 10.045956 -20.220011 -5.279887 12671 10.710073 -20.769604 -5.654246 12672 16.763554 -22.412058 -7.706252 12673 22.201096 -24.457092 -10.750664 12674 24.865593 -25.079498 -9.886688 12675 24.070816 -24.046997 -9.874332 12676 36.998169 -25.677597 -9.215965 12677 21.901749 -25.815536 -10.120998 12678 20.063873 -27.012634 -10.305927 12679 24.819344 -25.769974 -9.327713 12680 23.875595 -24.994568 -9.401363 12681 12.475135 -21.793964 -6.454379 12682 21.409378 -26.943390 -9.089462 12683 20.598755 -27.305466 -8.811951 12684 25.572647 -25.854263 -9.823421 12685 26.984879 -27.158936 -9.127266 12686 25.809952 -26.482330 -9.215157 12687 13.585135 -22.995491 -5.837721 12688 14.573004 -23.077322 -6.319454 12689 13.589459 -22.446573 -6.529528 12690 14.417226 -22.501429 -6.945095 12691 15.493769 -22.719736 -7.093275 12692 18.590057 -27.613785 -9.996197 12693 18.115250 -28.057877 -10.306561 12694 18.831970 -28.008850 -10.926453 12695 30.514771 -27.535934 -10.258064 12696 30.018776 -28.557907 -9.375233 12697 33.027710 -28.880859 -9.883492 12698 31.464920 -28.559097 -9.773598 12699 35.732018 -27.652481 -10.447792 12700 35.138756 -27.621552 -10.613068 12701 36.827011 -27.522232 -9.540043 12702 14.525858 -22.737156 -6.718332 12703 35.671722 -28.216736 -10.073296 12704 66.408264 -28.760361 -9.055321 12705 18.047455 -28.840347 -10.373917 12706 32.165100 -29.801727 -9.176865 12707 35.646049 -29.222900 -9.325294 12708 34.745026 -30.177551 -9.128361 12709 67.318436 -26.692947 -9.559155 12710 26.391144 -32.371063 -11.287197 12711 25.641624 -33.266724 -10.895504 12712 26.357407 -33.545883 -10.798119 12713 28.237648 -34.334991 -10.384937 12714 19.331970 -34.009171 -10.900150 12715 29.100761 -33.460236 -10.875721 12716 30.026108 -33.384933 -10.936861 12717 31.167686 -33.594040 -10.827377 12718 18.136810 -33.659271 -10.337452 12719 18.944550 -34.855453 -10.237019 12720 20.272415 -35.098969 -10.311337 12721 25.638885 -34.503784 -10.285595 12722 26.838181 -34.521835 -10.305916 12723 29.495926 -34.490952 -10.318630 12724 30.408844 -34.428345 -10.361931 12725 32.182770 -34.407669 -10.423439 12726 21.609161 -35.115173 -10.046902 12727 22.809784 -35.533966 -9.322723 12728 32.985016 -35.922760 -10.863098 12729 32.117981 -37.498444 -11.631525 12730 32.689682 -35.240234 -10.328415 12731 59.357071 -36.654510 -10.965744 12732 67.265991 -36.278534 -10.094788 12733 32.440964 -36.299057 -10.091282 12734 58.883606 -37.391861 -11.004585 12735 67.315094 -37.039383 -9.449760 12736 32.834320 -39.069855 -10.488846 12737 33.652924 -39.383179 -9.949074 12738 58.755005 -38.368774 -10.791656 12739 66.745056 -38.121643 -9.793839 12740 23.930664 -39.300888 -11.264221 12741 26.642456 -40.092194 -10.537323 12742 32.048950 -38.915802 -11.070549 12743 58.308609 -39.363358 -10.160751 12744 59.249924 -38.858917 -10.248947 12745 66.348465 -38.886505 -9.028717 12746 66.841705 -38.518295 -8.825897 12747 31.887606 -39.941162 -10.993763 12748 31.408295 -40.058319 -11.032585 12749 55.473938 -40.694122 -10.108322 12750 57.383698 -39.781815 -9.459629 12751 58.136765 -39.740723 -9.053753 12752 59.086960 -39.610641 -9.162628 12753 62.220276 -39.577255 -8.887833 12754 64.350372 -39.375595 -9.671364 12755 65.723389 -38.939514 -9.969788 12756 65.332703 -39.117981 -8.115417 12757 22.744995 -40.993958 -10.366829 12758 21.942513 -41.819336 -10.512009 12759 32.061829 -40.896393 -10.302731 12760 30.487602 -41.435852 -9.864613 12761 32.394394 -39.880005 -10.715683 12762 56.313141 -42.498917 -10.956009 12763 21.900841 -42.826645 -11.115952 12764 41.206619 -45.295517 -11.250938 12765 56.543991 -43.351837 -10.508293 12766 57.398438 -43.355881 -10.917942 12767 21.434441 -43.416534 -10.265564 12768 21.743546 -44.282516 -10.246868 12769 22.219345 -44.590820 -11.545383 12770 63.896240 -44.551880 -10.898048 12771 64.106522 -44.896042 -10.788128 12772 63.800629 -45.908005 -10.727993 12773 63.996902 -45.374908 -10.772663 12774 63.405136 -46.516769 -10.787308 12775 49.825409 -48.417297 -10.870014 12776 50.197449 -47.867599 -10.840096 12777 51.294983 -47.555954 -10.855591 12778 62.381256 -48.267929 -11.192005 12779 22.313972 -47.929337 -11.418240 12780 42.892914 -47.904175 -10.559128 12781 40.963165 -49.998245 -10.561760 12782 50.441727 -50.512054 -10.739334 12783 54.799011 -49.501373 -9.343880 12784 55.755035 -49.987732 -9.827091 12785 55.616180 -49.553299 -10.980259 12786 38.325844 -51.744858 -10.894859 12787 38.785828 -52.094162 -10.058048 12788 22.929436 -51.691910 -11.886993 12789 57.630722 -50.662155 -10.858547 12790 56.847015 -50.497452 -10.163040 12791 53.129868 -52.865341 -10.296379 12792 52.802124 -52.684738 -10.212803 12793 52.807281 -52.861801 -11.016052 12794 52.117493 -52.408493 -9.795990 12795 22.660759 -51.610764 -11.027550 12796 22.556252 -52.033783 -11.284935 12797 41.494263 -53.577499 -10.441666 12798 43.426437 -52.452911 -11.215015 12799 42.341339 -52.675613 -10.934181 12800 23.057320 -52.720566 -11.057232 12801 57.856995 -55.921249 -10.130836 12802 57.377029 -55.465942 -10.334980 12803 43.788177 -57.063431 -10.291161 12804 43.845947 -57.269730 -11.235733 12805 56.665161 -55.076172 -10.458950 12806 41.793427 -55.501648 -10.396973 12807 57.929932 -56.745575 -10.783661 12808 58.073166 -57.417862 -10.459641 12809 39.404442 -58.549561 -11.372528 12810 39.826828 -59.739380 -11.734604 12811 42.135727 -55.835587 -8.798492 12812 44.218689 -57.654297 -11.988075 12813 45.190720 -57.598114 -10.720165 12814 46.590576 -57.772614 -10.662014 12815 50.177734 -58.706955 -10.754574 12816 49.330978 -58.328308 -10.726883 12817 33.368912 -59.813828 -13.242661 12818 23.453003 -59.602905 -12.083412 12819 24.118340 -60.387085 -12.907738 12820 23.160461 -60.655518 -12.029186 12821 23.612450 -60.771347 -12.576435 12822 53.288986 -60.024185 -11.339981 12823 52.117355 -59.366486 -10.617081 12824 54.130615 -60.138123 -11.410835 12825 55.752228 -59.318008 -9.631992 12826 56.916519 -59.059128 -9.643021 12827 56.522339 -59.326157 -10.518787 12828 23.307693 -61.536819 -12.018465 12829 38.879517 -61.265671 -10.839958 12830 46.791168 -62.429977 -11.873520 12831 48.089386 -63.030899 -12.087006 12832 45.694839 -62.175003 -11.544563 12833 44.990738 -62.610413 -12.353954 12834 48.091522 -62.179031 -10.097309 12835 48.461609 -62.611526 -10.779270 12836 49.024750 -62.544739 -9.731670 12837 23.182144 -62.460403 -11.270035 12838 23.267899 -63.645859 -11.126301 12839 38.230362 -63.420197 -12.050678 12840 47.647430 -62.325089 -11.023407 12841 37.359634 -64.205978 -11.761101 12842 37.005188 -62.966965 -10.028603 12843 34.734680 -66.855789 -10.351524 12844 34.539207 -66.642731 -9.839188 12845 34.829353 -66.103439 -9.825741 12846 49.310791 -63.663712 -12.018829 12847 49.273392 -63.060410 -10.915901 12848 51.577011 -64.342972 -10.777023 12849 22.757812 -65.338654 -11.852978 12850 22.679573 -65.560486 -11.710857 12851 42.088837 -64.377991 -11.620445 12852 40.322632 -65.449326 -10.926086 12853 39.594826 -65.931198 -10.543745 12854 39.913139 -66.526474 -11.380394 12855 41.051239 -66.235123 -12.305080 12856 41.792175 -65.886841 -12.720818 12857 46.069763 -66.355042 -12.427618 12858 46.710907 -66.692001 -12.050648 12859 52.554504 -65.574234 -10.660698 12860 52.162506 -67.133163 -10.605556 12861 52.966827 -66.330963 -10.043564 12862 47.895126 -67.489609 -12.278347 12863 51.944565 -65.837662 -11.244217 12864 23.679230 -68.095383 -12.808250 12865 25.438034 -68.288300 -13.386707 12866 40.336945 -67.264389 -12.271984 12867 40.436615 -68.222214 -12.770641 12868 44.979202 -68.268570 -12.784554 12869 48.688171 -68.095123 -12.301182 12870 47.897888 -68.125549 -11.770538 12871 48.322876 -69.133316 -11.120678 12872 50.571442 -68.694946 -11.089581 12873 24.063087 -68.879166 -12.326523 12874 24.481453 -68.627640 -13.058876 12875 25.364006 -69.173615 -12.561539 12876 27.291328 -69.682526 -11.548813 12877 25.718681 -69.847519 -9.253502 12878 27.194046 -70.083603 -9.676090 12879 39.812943 -68.988007 -12.349571 12880 44.739441 -68.238251 -12.257339 12881 44.493530 -68.873886 -11.782303 12882 24.803360 -69.322113 -11.070412 12883 28.006607 -70.245010 -9.986839 12884 29.171204 -70.408524 -11.605087 12885 39.761078 -70.210831 -12.371643 12886 49.315430 -69.153564 -11.456779 12887 49.562958 -68.762283 -11.947876 12888 39.721985 -71.433823 -12.374649 12889 18.722946 -73.396057 -13.122238 12890 17.990997 -72.194641 -12.373985 12891 17.237846 -73.209763 -12.253529 12892 19.095520 -71.430069 -12.021774 12893 18.760986 -70.503387 -11.084869 12894 18.019653 -70.701126 -11.479561 12895 20.407242 -72.452164 -12.289543 12896 19.499550 -72.515366 -12.919609 12897 20.062622 -73.202759 -13.066338 12898 40.001099 -74.875336 -12.660099 12899 40.431396 -74.878311 -13.193722 12900 40.193375 -72.429688 -12.857609 12901 17.495041 -74.310791 -12.889759 12902 17.480698 -77.381180 -13.450764 12903 18.540787 -79.117355 -13.107483 12904 19.530396 -78.037369 -13.127441 12905 18.826004 -72.349319 -12.846252 12906 26.594933 -72.131165 -9.704071 12907 25.896332 -72.154770 -9.147446 12908 25.334427 -73.155579 -10.038780 12909 45.520325 -72.669708 -12.991638 12910 16.781738 -74.284546 -12.141453 12911 16.696640 -75.530746 -12.554085 12912 20.236649 -74.267242 -13.095673 12913 21.255486 -73.991913 -12.141319 12914 20.749878 -73.399399 -12.680477 12915 21.116493 -73.117477 -11.903091 12916 18.579147 -75.219162 -13.351341 12917 24.781242 -74.275009 -11.246799 12918 24.702805 -74.139206 -10.361076 12919 24.827858 -75.124176 -10.259216 12920 45.752380 -76.019485 -12.661686 12921 19.643188 -76.504761 -13.413399 12922 20.204460 -75.440155 -13.255127 12923 21.126747 -75.258255 -12.357948 12924 20.656326 -76.175735 -13.010693 12925 24.324417 -75.575989 -12.288628 12926 24.403618 -77.189697 -12.244648 12927 15.197723 -76.960602 -12.554558 12928 20.455673 -77.177811 -12.938110 12929 17.534058 -79.106735 -13.321835 12930 24.459396 -74.909637 -13.228001 12931 23.891724 -77.955307 -13.550034 12932 39.307083 -76.830994 -11.209351 12933 39.288803 -77.862854 -11.591637 12934 46.265656 -77.705765 -11.432755 12935 15.636528 -78.199295 -13.324860 12936 16.562668 -78.921677 -13.444458 12937 15.660736 -78.978653 -13.362350 12938 19.419624 -79.171738 -12.319420 12939 30.940979 -79.675247 -13.057625 12940 30.152603 -80.832214 -13.777489 12941 32.618988 -78.274063 -11.669071 12942 33.076614 -77.815079 -12.035812 12943 45.550293 -80.677567 -13.194744 12944 15.550629 -76.001282 -10.909626 12945 15.747589 -79.611465 -12.940340 12946 18.905426 -79.678574 -12.391739 12947 23.487938 -82.164551 -13.303503 12948 37.101013 -79.535416 -12.844833 12949 35.693451 -79.711365 -12.296291 12950 34.686356 -80.155136 -12.427620 12951 30.922409 -81.603226 -13.529099 12952 32.575974 -80.939682 -12.441490 12953 44.566833 -82.677612 -13.255569 12954 44.949493 -81.843124 -13.371910 12955 13.853027 -84.098038 -14.149902 12956 13.316818 -83.073120 -13.586945 12957 12.441261 -84.024582 -12.978027 12958 16.020363 -83.085968 -13.314373 12959 15.075607 -82.717422 -12.860703 12960 15.114731 -83.258484 -13.868164 12961 23.675331 -83.040848 -13.057121 12962 31.352509 -80.882858 -12.651199 12963 14.186592 -82.738235 -13.473507 12964 14.280548 -83.394669 -14.057945 12965 18.800415 -83.211227 -12.875614 12966 17.787186 -83.210022 -13.104794 12967 20.783890 -84.299240 -12.900776 12968 13.850090 -85.328461 -14.153049 12969 13.688583 -85.953995 -14.037426 12970 14.418533 -86.437927 -14.137661 12971 14.832901 -84.895889 -14.595341 12972 20.345520 -83.558014 -12.409119 12973 24.272797 -84.685104 -13.807915 12974 21.070023 -86.363632 -12.992622 12975 21.547668 -85.633575 -12.492897 12976 24.634491 -85.457672 -13.688602 12977 41.301224 -84.870728 -12.188400 12978 42.282227 -84.774796 -12.089771 12979 17.927963 -86.858917 -14.728127 12980 19.476212 -87.441666 -14.300003 12981 21.366104 -85.001053 -12.875126 12982 24.968475 -85.760574 -13.927956 12983 36.425034 -86.752686 -13.942005 12984 37.453354 -85.624207 -13.150005 12985 40.601700 -85.170609 -12.857533 12986 17.741592 -87.682159 -14.225639 12987 17.058075 -88.494202 -13.286575 12988 19.034981 -87.865509 -13.807999 12989 20.201584 -87.354324 -13.007797 12990 20.632217 -86.541718 -13.637646 12991 35.843002 -87.519913 -13.626793 12992 35.824951 -86.082840 -12.700802 12993 36.079132 -84.722015 -11.666180 12994 18.158203 -88.436188 -13.246922 12995 19.725975 -87.544144 -13.964323 12996 36.507172 -87.763626 -12.601299 12997 24.441193 -89.374298 -13.916447 12998 23.754410 -89.296570 -12.989765 12999 25.705101 -89.656326 -13.553123 13000 26.931610 -90.376709 -14.237000 13001 36.121735 -89.793472 -13.593460 13002 21.958252 -91.230408 -14.705727 13003 21.558182 -91.045532 -14.122532 13004 31.237755 -90.424255 -13.195396 13005 30.405594 -89.729538 -12.756241 13006 34.545120 -90.492126 -13.686378 13007 35.531250 -90.460983 -12.896538 13008 31.394691 -90.195435 -12.213509 13009 32.033661 -90.606857 -13.868736 13010 36.543961 -90.095566 -13.255524 13011 36.696426 -89.501450 -13.446320 13012 17.398560 -93.683655 -14.418381 13013 17.116501 -93.974930 -14.351292 13014 20.744011 -93.288437 -13.443314 13015 19.602165 -93.549133 -13.764389 13016 21.030159 -92.489243 -13.409920 13017 32.102798 -93.550400 -13.228863 13018 31.490540 -94.801086 -14.166054 13019 32.373550 -94.825974 -13.397316 13020 15.026649 -98.225204 -12.616714 13021 15.442055 -98.388596 -12.979668 13022 17.262070 -98.646545 -14.547504 13023 17.872757 -98.549881 -15.264694 13024 29.366135 -97.002151 -14.467403 13025 29.050575 -97.449493 -13.683151 13026 18.314301 -99.568939 -14.974976 13027 18.856392 -100.621567 -14.514473 13028 18.880310 -100.944626 -14.156673 13029 22.662811 -100.010956 -14.997269 13030 17.802063 -100.484268 -13.437046 13031 24.422821 -100.307617 -13.632616 13032 6.698540 61.972717 -3.408340 13033 7.773582 61.654800 -4.028946 13034 7.929718 62.370667 -3.630081 13035 8.825089 61.836670 -4.149063 13036 9.851204 62.615173 -3.737305 13037 9.739944 63.133026 -2.640060 13038 8.611839 62.908264 -3.026550 13039 10.564362 63.139618 -1.554489 13040 11.245506 62.634125 -3.231705 13041 12.441010 62.388947 -1.887978 13042 12.495392 62.271744 -2.939377 13043 7.535599 62.689972 -3.060028 13044 8.172211 60.312683 -4.170273 13045 7.085129 61.014648 -3.950691 13046 6.523766 59.647339 -3.583237 13047 8.900070 59.818771 -4.369232 13048 9.187340 59.347137 -4.493065 13049 14.517532 57.403137 -2.905991 13050 17.292313 58.523132 -3.713608 13051 18.272751 59.250305 -3.558090 13052 19.472687 59.330505 -2.832932 13053 18.809929 59.633469 -2.705009 13054 19.219009 59.013519 -3.712875 13055 9.680573 58.460876 -4.953400 13056 9.132118 58.263260 -4.392792 13057 17.606613 59.650497 -2.487457 13058 16.959732 59.085815 -2.701553 13059 8.531792 57.159576 -3.323097 13060 16.555031 57.620621 -3.141281 13061 20.250092 57.990936 -2.874390 13062 20.963364 55.718491 -4.075958 13063 20.414864 56.332581 -3.427155 13064 7.047173 55.069977 -5.159958 13065 8.343857 54.690826 -3.289558 13066 8.038544 54.561066 -4.114525 13067 16.995766 55.726776 -4.787498 13068 22.167992 53.789078 -3.898315 13069 21.143730 54.590668 -3.833588 13070 23.609314 54.336014 -4.211350 13071 25.325134 55.082947 -4.129501 13072 26.705917 55.292755 -3.935417 13073 27.455154 54.915527 -3.495117 13074 7.109604 54.481659 -4.974655 13075 7.541016 54.681900 -4.732086 13076 29.473434 54.512253 -3.474564 13077 30.697327 54.479980 -3.339523 13078 31.917742 54.562012 -3.360321 13079 34.464218 54.326050 -2.866623 13080 7.289200 53.856522 -4.702972 13081 7.275345 52.431030 -4.701591 13082 7.948112 51.272003 -4.135132 13083 8.017334 52.361404 -3.572609 13084 14.909042 52.648102 -5.142227 13085 15.784271 52.714691 -5.220474 13086 15.218369 53.497498 -4.762009 13087 15.477386 54.429184 -4.369835 13088 6.511803 51.721207 -5.448944 13089 7.862686 50.265472 -4.875793 13090 15.483994 50.056351 -5.154999 13091 7.901428 49.354843 -4.692665 13092 7.480270 48.440414 -5.109009 13093 15.908997 48.787277 -4.998001 13094 15.704849 49.384659 -4.895546 13095 16.616982 49.397095 -4.991249 13096 37.788177 51.865036 -2.711639 13097 37.342590 52.325821 -2.679802 13098 36.972519 49.082642 -4.306854 13099 2.075462 45.890274 -4.179924 13100 3.617699 47.354492 -4.186035 13101 3.004166 47.592499 -3.180771 13102 4.527702 46.969116 -4.892471 13103 4.188233 48.438324 -3.391861 13104 7.034554 47.726318 -5.120254 13105 7.272308 48.757797 -4.197037 13106 18.329803 47.823273 -5.088814 13107 36.399071 47.180115 -4.676056 13108 37.494019 48.601440 -3.575012 13109 36.995987 47.970154 -3.866035 13110 36.696960 46.746643 -4.642914 13111 20.455971 45.701080 -5.253891 13112 20.203049 44.888580 -5.044128 13113 37.483086 46.160736 -4.738975 13114 42.715637 46.542801 -1.906403 13115 20.447861 43.583191 -5.423492 13116 42.178970 45.949524 -4.454071 13117 20.411797 44.287659 -5.157905 13118 44.413727 43.922073 -4.326492 13119 44.361053 44.494186 -2.928421 13120 21.008820 38.876007 -5.363022 13121 21.556488 39.710312 -4.723267 13122 20.441620 41.215149 -5.413238 13123 21.556442 40.954407 -5.303604 13124 29.289566 41.021667 -6.266708 13125 38.839325 40.403824 -5.610229 13126 46.368134 41.717529 -2.985428 13127 46.261749 41.726593 -4.009110 13128 46.654266 40.630966 -4.713173 13129 3.318703 42.577774 -3.797722 13130 4.848099 42.876770 -3.273682 13131 5.121826 42.092377 -3.911888 13132 5.109902 40.882507 -4.780792 13133 5.697449 39.912933 -5.304031 13134 6.211197 39.117111 -5.714401 13135 37.666519 39.429825 -5.069260 13136 40.763214 40.422211 -5.602814 13137 3.525375 40.442291 -5.420593 13138 2.530823 41.668762 -4.838249 13139 7.453964 40.475235 -4.772278 13140 8.523117 40.667740 -4.450210 13141 8.382332 39.355194 -5.064514 13142 6.403839 40.163208 -5.057648 13143 7.321610 39.142090 -5.490860 13144 22.192093 39.253296 -4.416199 13145 21.809380 39.343460 -4.249878 13146 37.692116 39.141022 -5.116646 13147 9.301895 38.353607 -5.043182 13148 23.669571 38.248947 -5.554169 13149 37.382217 39.071152 -5.116211 13150 10.093025 37.740677 -4.549179 13151 9.909393 36.680389 -4.506714 13152 21.935600 37.713516 -5.448090 13153 22.608856 36.952850 -5.621467 13154 23.442818 37.127640 -5.685501 13155 47.720230 37.137848 -3.823730 13156 9.146240 34.069885 -5.869301 13157 22.670013 37.606598 -5.204422 13158 23.111359 38.272720 -5.133133 13159 23.724854 35.523132 -6.104401 13160 24.201233 36.425934 -6.145706 13161 24.484665 34.437286 -6.038284 13162 47.766541 35.759537 -3.935165 13163 47.549072 36.207611 -3.232300 13164 9.320770 33.044891 -6.304550 13165 24.550560 33.850418 -5.708557 13166 46.977417 34.895264 -3.692535 13167 2.179375 30.303589 -6.127411 13168 2.942101 30.991180 -6.203934 13169 2.044075 31.263672 -5.473495 13170 3.702087 32.116791 -5.935348 13171 4.736717 31.875641 -6.076965 13172 4.536934 33.167130 -5.511032 13173 3.167526 33.808365 -4.912170 13174 2.652176 32.161926 -5.425285 13175 7.446144 30.206924 -6.475387 13176 7.473602 31.237854 -6.017197 13177 39.252129 31.986526 -6.082855 13178 46.915070 31.784103 -3.672775 13179 46.921997 32.343597 -3.631409 13180 5.488197 31.011337 -6.261452 13181 5.737198 32.445618 -5.665092 13182 8.378036 32.044434 -6.026306 13183 8.949554 33.015259 -5.806946 13184 29.091904 31.497528 -4.303391 13185 31.660234 31.487274 -5.690399 13186 39.445145 30.903244 -5.656631 13187 46.908600 33.328506 -3.988380 13188 1.586983 30.440720 -5.455871 13189 1.302261 30.103912 -5.123047 13190 1.714142 29.430237 -5.926208 13191 6.563133 31.552704 -5.870178 13192 6.495026 30.136612 -6.446693 13193 27.539917 31.534409 -5.587082 13194 32.631966 31.026794 -4.961990 13195 35.414398 29.393768 -4.561119 13196 38.398483 29.889420 -3.962006 13197 39.283714 29.801163 -3.994255 13198 39.325958 30.142746 -4.747024 13199 21.786247 28.987747 -6.384872 13200 22.122879 29.748413 -5.774994 13201 27.214325 29.412598 -4.933121 13202 29.163361 28.897034 -5.366699 13203 34.004402 29.871704 -4.319023 13204 35.752930 29.389359 -4.777306 13205 46.293350 29.965302 -5.229248 13206 46.055145 29.986786 -4.798218 13207 21.953842 29.004959 -5.701492 13208 27.282249 29.295776 -4.428268 13209 28.046555 29.191376 -4.678757 13210 35.713470 29.281189 -4.463653 13211 36.621864 29.613495 -4.504707 13212 46.306519 29.690063 -4.992462 13213 48.319870 28.705856 -4.632736 13214 49.301910 28.228714 -3.572090 13215 48.556152 28.936600 -3.129036 13216 1.157501 28.286316 -5.728912 13217 22.290283 28.438385 -5.469063 13218 22.667297 28.407135 -4.967056 13219 22.434616 28.811783 -4.618881 13220 22.767822 28.026154 -5.478516 13221 30.100159 28.405441 -4.812523 13222 33.865425 28.450714 -3.740860 13223 33.921600 27.931549 -4.564926 13224 35.259491 28.360016 -4.109879 13225 47.345886 29.493561 -3.769043 13226 0.587952 27.459824 -5.510315 13227 1.095848 27.883774 -4.484253 13228 0.364784 26.591553 -5.314232 13229 23.328201 28.621048 -4.620842 13230 33.576874 27.601227 -5.640427 13231 32.792686 27.586563 -4.775818 13232 39.559097 25.778946 -5.809204 13233 41.204575 25.937683 -5.516220 13234 41.136017 26.896515 -5.249130 13235 40.410751 25.545090 -5.192123 13236 39.518967 26.248138 -4.476570 13237 40.525757 24.909363 -5.917648 13238 49.623657 24.610291 -5.433006 13239 49.926193 25.753632 -4.512726 13240 0.503166 24.484055 -6.065704 13241 0.629318 22.553253 -6.659546 13242 41.181885 24.446152 -6.180115 13243 11.315063 20.411728 -7.059593 13244 11.711494 20.542740 -6.739548 13245 13.122161 22.083847 -7.552872 13246 12.528656 21.574524 -7.153068 13247 49.051178 22.773102 -5.328133 13248 0.580521 21.804230 -6.598663 13249 12.320938 20.639328 -6.783493 13250 13.202866 20.719711 -7.428665 13251 0.938751 21.214706 -6.552658 13252 12.897385 19.817535 -6.800217 13253 1.948219 20.281158 -7.225311 13254 11.740822 18.584961 -6.948295 13255 11.912750 19.760071 -6.756134 13256 25.828751 18.442612 -5.946274 13257 26.709137 19.491089 -5.693329 13258 47.945831 20.115875 -5.437431 13259 29.570236 19.289352 -5.301956 13260 30.085617 18.897110 -5.249344 13261 48.845810 17.776901 -4.708168 13262 48.992020 18.585144 -4.151505 13263 48.403656 19.289429 -5.018951 13264 48.825928 19.798416 -3.977135 13265 2.545471 19.245667 -5.709930 13266 3.008949 18.612640 -7.217956 13267 11.340881 16.517502 -7.068100 13268 11.409393 17.604141 -7.145813 13269 12.777847 17.136642 -6.903458 13270 30.691925 18.416260 -5.354538 13271 31.151558 18.555603 -4.214706 13272 31.565529 17.952271 -5.234772 13273 32.775269 17.504913 -5.794708 13274 33.987503 16.910767 -6.524956 13275 51.172043 16.204666 -6.036590 13276 53.630600 17.035431 -6.180176 13277 26.304230 17.089279 -6.260055 13278 37.013374 16.328354 -5.867485 13279 37.011383 16.931839 -4.608337 13280 38.498093 16.660049 -5.134048 13281 52.338409 16.101761 -4.977081 13282 55.403625 15.905334 -5.409233 13283 11.788834 15.384567 -7.098114 13284 30.635025 14.965698 -6.543732 13285 29.836319 15.003876 -4.843323 13286 29.087387 15.381409 -4.659866 13287 29.191246 15.312775 -5.366562 13288 45.427795 15.141113 -6.074470 13289 46.953354 15.390533 -6.089432 13290 46.371719 15.119461 -5.909210 13291 46.829407 15.114288 -5.683700 13292 47.378128 15.461487 -5.155929 13293 56.372604 14.020050 -5.381393 13294 55.802765 15.103607 -4.902977 13295 56.057755 14.899765 -6.142807 13296 5.225632 14.749741 -6.511261 13297 4.308304 16.204559 -5.848984 13298 15.044731 14.131775 -7.087006 13299 32.969887 14.218216 -5.744873 13300 33.571274 13.926773 -6.430389 13301 34.763046 13.569641 -6.557480 13302 13.691666 14.132141 -7.094398 13303 14.664696 13.748596 -7.236236 13304 34.142693 13.747040 -5.493057 13305 34.744781 13.433075 -5.651459 13306 48.998932 13.355225 -6.217941 13307 36.506577 12.422028 -6.527786 13308 35.684982 12.965622 -6.555862 13309 37.140335 11.924973 -6.369156 13310 37.864647 11.125839 -6.582031 13311 47.504852 10.490906 -6.217544 13312 46.917114 9.203430 -6.376564 13313 48.236069 11.077545 -5.586639 13314 39.050621 9.835358 -6.760795 13315 39.549683 8.932129 -6.919289 13316 41.540924 10.030502 -4.825027 13317 40.497437 10.588684 -4.947998 13318 40.170242 10.101730 -5.723297 13319 11.731705 5.504004 -8.809235 13320 12.283220 5.297235 -8.920664 13321 12.657024 5.555484 -9.221608 13322 13.185270 5.455661 -9.317908 13323 39.551620 6.952423 -6.506195 13324 39.516266 8.139328 -6.970444 13325 40.321259 8.810425 -6.089714 13326 45.832733 5.147110 -6.735184 13327 46.161896 5.038788 -6.367599 13328 9.100380 5.571021 -7.180828 13329 10.401567 5.067686 -7.724201 13330 13.739263 5.330514 -9.363637 13331 14.139038 4.162877 -8.783986 13332 58.227264 6.562790 -5.460174 13333 57.821655 7.707550 -5.289780 13334 15.388007 4.496929 -9.087999 13335 27.154816 5.258209 -7.415718 13336 15.966219 3.986740 -8.868891 13337 17.807722 3.311186 -8.555799 13338 18.820395 4.425982 -8.678385 13339 16.957121 1.744189 -8.371714 13340 19.427809 2.863639 -8.208745 13341 19.285172 3.895646 -8.413563 13342 26.675659 4.388168 -7.321899 13343 45.863785 4.007736 -6.449356 13344 25.921188 1.944244 -7.501236 13345 27.603455 3.578568 -7.434997 13346 45.519958 2.723450 -6.268425 13347 59.039276 3.443817 -6.039558 13348 27.653305 4.555161 -7.356445 13349 26.920685 1.493988 -7.778732 13350 25.682404 0.964920 -7.869179 13351 26.417389 1.176743 -7.780731 13352 58.443542 -1.424988 -6.748199 13353 13.705891 0.722857 -7.797791 13354 22.783733 0.377003 -8.571244 13355 22.968731 1.036761 -8.156914 13356 22.033773 0.557014 -8.502460 13357 40.167511 0.838089 -6.722679 13358 39.889252 -0.762054 -7.539886 13359 42.747284 -1.691635 -7.152649 13360 44.027283 -0.527130 -6.005783 13361 58.216278 -2.435043 -6.125969 13362 7.613654 -0.261948 -6.563760 13363 10.248878 -1.140438 -6.378017 13364 10.016067 -2.284938 -6.395096 13365 14.942034 3.743261 -8.667910 13366 13.846988 2.906042 -8.075958 13367 16.079538 3.055246 -8.496885 13368 12.474169 1.620333 -7.366033 13369 14.642802 1.554940 -8.019730 13370 14.927523 0.308778 -8.159688 13371 39.993408 -1.926544 -6.667496 13372 43.765900 -3.047409 -5.821968 13373 10.534487 -3.105869 -6.873114 13374 16.004898 0.659681 -8.330805 13375 42.364105 -2.782944 -7.128059 13376 17.139454 -0.361626 -8.619292 13377 19.754459 -0.899166 -8.992172 13378 57.755890 -2.956543 -6.565552 13379 20.428251 -2.737639 -9.562066 13380 20.783567 -3.457178 -9.807156 13381 21.331057 -2.332473 -9.599360 13382 8.758347 -6.144716 -6.158692 13383 8.958930 -5.251780 -6.167616 13384 8.347980 -4.787767 -5.475448 13385 9.228161 -6.000078 -6.563686 13386 16.121758 -4.231858 -9.221664 13387 16.369087 -3.039559 -9.008883 13388 15.411974 -5.243443 -9.285788 13389 16.628063 -1.893796 -8.820621 13390 22.315947 -3.023422 -10.018485 13391 39.869026 -3.881302 -6.814865 13392 40.105408 -5.240494 -6.637161 13393 41.150131 -6.136505 -6.323601 13394 55.539459 -5.159561 -6.173233 13395 55.143234 -4.697037 -4.312592 13396 56.128143 -4.314056 -5.227432 13397 7.691411 -5.231816 -4.839572 13398 7.121888 -5.138467 -4.095979 13399 17.419617 -2.444592 -9.074919 13400 17.014912 -4.002966 -9.349644 13401 21.885710 -3.242488 -9.977840 13402 22.961348 -5.449941 -10.907719 13403 22.643736 -3.774029 -10.324092 13404 22.852827 -4.552725 -10.608074 13405 56.614624 -4.103119 -6.160751 13406 6.521916 -7.633947 -3.529020 13407 6.155783 -9.304974 -2.943296 13408 6.407817 -8.958860 -3.521766 13409 10.281332 -7.655674 -7.676541 13410 10.641670 -7.038648 -7.774293 13411 11.179504 -6.197982 -7.907225 13412 10.414397 -6.563046 -7.534591 13413 16.332293 -5.134419 -9.471390 13414 6.610766 -8.673161 -3.931191 13415 11.346807 -6.864501 -8.144098 13416 15.554945 -6.186347 -9.538733 13417 17.251850 -5.306903 -9.696051 13418 16.431366 -6.021139 -9.704411 13419 18.814470 -7.056423 -10.383680 13420 17.998833 -4.442629 -9.624629 13421 18.851120 -5.864638 -10.108313 13422 18.833979 -3.332505 -9.482302 13423 18.894686 -4.813595 -9.859058 13424 22.521502 -6.708107 -11.127453 13425 20.865757 -6.837433 -10.731054 13426 58.952759 -8.479782 -7.229217 13427 59.569427 -8.137436 -7.028908 13428 58.816681 -7.760925 -6.807449 13429 59.611282 -7.375153 -6.491699 13430 6.723402 -9.511441 -4.240155 13431 21.715216 -7.014365 -10.981188 13432 56.768402 -8.455734 -5.979187 13433 56.367188 -10.302551 -7.009781 13434 57.377350 -9.189133 -7.031464 13435 58.767685 -9.723083 -7.095100 13436 58.116211 -8.287109 -6.829712 13437 59.637085 -8.932632 -7.051201 13438 60.030823 -9.869614 -6.414871 13439 60.547729 -8.327850 -6.321136 13440 6.959466 -9.602573 -4.683212 13441 16.036625 -7.802167 -10.033757 13442 15.853455 -6.851664 -9.775276 13443 57.680847 -10.568344 -7.153992 13444 58.770813 -11.454483 -6.462387 13445 59.535461 -10.698624 -6.581634 13446 64.077942 -9.978134 -8.238968 13447 16.245676 -6.895438 -9.880572 13448 53.663666 -12.982025 -7.864532 13449 53.863312 -11.589142 -7.510750 13450 54.916321 -12.459061 -7.470306 13451 64.170319 -12.000366 -7.470596 13452 7.654370 -12.437114 -5.726292 13453 7.845662 -13.176703 -5.957039 13454 53.031616 -10.703186 -6.582916 13455 53.969604 -10.870651 -6.538193 13456 55.323578 -9.491714 -5.095520 13457 54.421509 -10.475677 -6.080887 13458 54.990616 -10.983154 -7.021164 13459 55.908554 -11.775330 -7.300621 13460 56.059570 -13.034378 -6.789246 13461 57.164490 -11.882507 -6.884453 13462 65.258438 -12.237854 -7.404045 13463 60.737961 -12.889603 -8.363609 13464 61.410706 -13.713928 -7.888550 13465 50.598236 -14.845947 -7.824127 13466 52.954956 -13.684280 -7.942985 13467 53.320999 -13.986664 -7.547623 13468 59.037689 -15.578171 -8.203751 13469 60.028305 -14.154037 -8.293777 13470 60.887741 -14.785370 -7.848251 13471 63.514999 -12.816437 -7.307838 13472 62.700317 -13.737717 -7.245163 13473 7.637808 -13.796798 -5.507810 13474 46.803406 -14.948334 -8.417900 13475 48.483002 -15.584290 -7.196129 13476 47.573151 -15.196655 -7.836258 13477 46.778870 -16.069626 -7.562767 13478 47.828232 -14.670105 -8.272461 13479 48.431000 -14.992538 -7.962616 13480 54.516083 -13.844696 -6.955780 13481 60.186096 -15.460831 -7.926117 13482 56.364227 -17.140839 -8.198578 13483 57.596954 -16.429413 -8.271790 13484 57.748077 -18.685379 -7.648773 13485 66.125900 -13.880798 -7.098495 13486 67.383606 -16.176971 -7.533478 13487 45.976196 -16.943207 -8.023788 13488 55.398376 -17.701996 -8.016411 13489 56.153503 -18.500000 -7.725906 13490 58.957825 -17.217377 -7.762970 13491 60.167099 -16.781586 -7.604431 13492 7.864649 -15.931929 -5.129887 13493 46.235275 -17.690186 -7.858353 13494 45.982803 -17.496582 -7.558998 13495 46.885406 -19.261246 -6.071030 13496 47.008789 -18.571365 -7.363525 13497 48.008148 -20.105850 -6.574524 13498 50.244827 -21.241516 -6.388870 13499 49.277893 -20.336243 -6.718506 13500 50.537201 -19.477798 -7.378807 13501 21.311396 -21.824884 -8.612893 13502 22.238649 -21.783184 -8.723876 13503 24.246719 -22.007244 -8.735770 13504 24.947840 -21.927271 -8.851863 13505 68.018875 -19.019577 -7.987503 13506 68.166351 -19.708511 -8.106590 13507 25.475782 -21.266016 -9.380442 13508 26.671614 -21.698257 -9.186213 13509 27.032492 -22.855196 -8.341625 13510 68.276443 -20.630554 -7.575447 13511 68.355637 -21.653717 -8.406738 13512 18.475536 -22.330921 -8.045717 13513 23.694901 -23.434937 -9.967159 13514 27.992243 -23.064405 -8.291666 13515 33.824516 -23.192356 -9.142569 13516 67.984482 -23.623505 -7.936767 13517 68.393250 -22.456116 -7.953117 13518 9.355035 -19.967106 -4.370261 13519 17.811300 -22.637592 -7.693967 13520 29.779455 -24.745232 -7.158238 13521 28.589392 -25.055384 -6.727136 13522 29.979136 -23.716465 -8.043119 13523 30.865904 -24.116255 -7.860731 13524 30.840141 -23.189045 -8.607907 13525 31.529549 -23.434172 -8.528290 13526 32.379787 -23.256269 -8.819205 13527 36.718803 -24.868256 -8.438057 13528 67.509750 -24.630615 -6.865265 13529 67.279282 -25.448822 -8.303017 13530 10.451834 -21.123358 -4.805901 13531 11.230017 -21.450768 -5.518842 13532 17.227192 -23.145094 -7.120475 13533 23.169998 -25.610550 -9.154778 13534 24.145142 -25.669357 -8.996933 13535 23.679382 -25.429214 -9.022129 13536 31.932360 -23.819822 -8.289902 13537 32.961910 -23.702616 -8.571957 13538 15.477401 -23.620352 -6.083296 13539 16.407612 -23.287695 -6.768599 13540 66.548492 -27.110580 -8.552490 13541 65.907135 -28.120972 -8.103088 13542 12.026811 -21.957518 -5.813347 13543 22.694016 -26.841339 -8.425240 13544 24.606186 -26.427429 -8.732803 13545 37.310562 -26.415253 -9.166039 13546 37.317703 -26.768311 -9.186756 13547 37.461143 -26.616150 -8.994453 13548 12.854956 -22.418074 -6.025425 13549 18.403229 -27.732574 -9.297970 13550 17.975525 -28.154129 -9.574314 13551 37.307190 -26.783249 -8.838028 13552 37.028091 -27.237244 -8.927925 13553 66.089600 -27.071625 -7.572769 13554 65.721954 -27.629196 -7.582039 13555 17.481918 -29.756012 -9.695801 13556 36.557022 -28.267700 -8.952591 13557 28.526321 -28.550446 -8.804253 13558 30.762558 -29.753891 -8.767090 13559 33.479675 -31.311768 -8.457451 13560 32.461601 -31.680634 -7.985626 13561 31.884737 -30.781387 -8.438110 13562 35.772499 -31.169724 -8.300232 13563 36.337753 -29.704926 -8.034607 13564 36.259384 -30.708908 -7.280487 13565 66.393646 -29.538986 -8.549095 13566 66.083450 -28.740448 -7.674103 13567 66.511429 -28.457825 -6.877197 13568 66.768143 -29.916656 -7.773910 13569 17.113853 -30.086319 -8.633736 13570 16.506470 -32.575531 -9.152321 13571 66.779388 -30.356918 -8.704102 13572 67.043350 -30.856918 -8.544250 13573 67.367767 -31.848206 -8.565048 13574 16.315094 -31.672226 -8.465332 13575 67.421204 -32.956619 -9.480354 13576 17.042961 -33.682007 -9.410297 13577 17.857803 -34.923706 -9.582249 13578 24.599037 -35.419907 -9.545979 13579 25.477470 -35.493881 -9.733379 13580 32.898880 -34.544373 -10.588097 13581 67.733185 -34.003067 -8.300171 13582 67.686737 -32.970535 -8.146980 13583 19.160583 -35.798828 -9.701839 13584 26.202469 -35.644440 -9.666599 13585 27.497330 -36.099930 -9.354816 13586 29.084732 -35.867691 -9.536533 13587 28.715408 -37.795120 -8.194016 13588 30.300308 -37.317657 -8.657196 13589 30.287811 -35.551224 -9.773151 13590 31.297379 -35.035339 -10.037781 13591 31.345627 -36.257721 -9.439816 13592 31.804644 -35.615723 -9.700344 13593 32.069046 -35.155258 -9.972382 13594 32.232033 -35.652939 -9.885391 13595 67.715546 -35.107391 -8.498566 13596 20.627014 -36.396927 -9.142864 13597 25.315399 -36.304092 -9.022865 13598 26.126808 -37.010147 -8.561447 13599 32.048508 -36.649521 -9.580231 13600 31.943369 -36.119827 -9.709625 13601 67.658905 -36.186096 -8.833740 13602 32.503677 -37.059341 -9.752831 13603 33.495331 -38.364975 -9.460655 13604 33.786758 -38.729630 -9.677654 13605 67.616180 -36.943649 -8.641632 13606 67.195068 -37.703384 -8.076927 13607 24.743507 -39.814911 -10.543201 13608 23.627365 -40.188629 -10.499039 13609 23.799072 -39.785385 -10.815443 13610 33.018898 -40.109406 -10.334694 13611 33.674500 -40.305542 -9.909698 13612 25.274490 -40.681015 -9.901264 13613 26.047195 -42.117142 -9.131546 13614 27.396744 -43.403641 -8.418823 13615 26.503708 -43.577377 -8.430496 13616 33.963303 -40.048599 -9.394936 13617 55.661209 -40.252014 -9.484558 13618 54.830124 -40.887115 -8.542328 13619 56.419891 -40.108276 -8.644760 13620 54.934692 -40.856491 -9.456829 13621 63.036316 -39.288269 -10.061134 13622 66.565063 -38.773239 -8.141815 13623 24.057266 -40.675537 -9.987385 13624 23.480225 -41.673920 -9.585674 13625 22.369644 -41.856140 -9.927624 13626 32.937195 -41.952896 -9.194431 13627 31.562973 -43.199387 -8.536774 13628 33.187653 -40.811249 -10.027527 13629 54.555176 -41.264297 -9.240108 13630 63.425385 -39.718475 -9.047691 13631 21.732208 -42.740097 -10.121372 13632 28.931503 -40.827286 -10.137676 13633 54.712219 -42.898529 -9.388882 13634 21.421333 -43.239883 -10.036819 13635 22.134186 -45.717422 -10.448997 13636 54.670090 -43.451019 -8.731400 13637 55.637054 -43.645859 -9.505787 13638 57.703354 -45.164108 -8.991699 13639 62.363403 -45.216858 -10.162018 13640 63.822678 -44.833740 -10.661236 13641 22.656754 -48.410294 -10.753098 13642 23.822289 -49.136017 -9.665531 13643 22.928391 -49.799255 -10.278683 13644 42.396988 -46.669830 -10.754780 13645 41.637695 -47.099503 -10.526840 13646 52.134796 -47.533661 -9.843262 13647 63.442993 -45.526978 -10.417229 13648 62.762405 -46.601257 -9.941975 13649 42.242035 -47.286743 -10.319450 13650 49.526855 -48.038651 -10.411957 13651 49.187302 -48.018127 -9.830185 13652 49.567978 -47.613022 -10.067230 13653 50.304474 -47.242783 -9.914371 13654 51.045135 -46.994583 -9.116970 13655 51.180298 -47.201050 -10.045464 13656 62.685196 -49.151917 -9.382683 13657 62.517960 -47.727448 -9.200775 13658 22.811127 -50.383331 -11.277657 13659 42.180908 -49.022476 -10.426655 13660 41.887238 -47.817001 -10.418072 13661 48.789993 -48.556320 -9.036865 13662 49.452698 -48.829086 -10.190521 13663 60.697784 -51.358215 -9.819546 13664 61.652771 -50.342117 -10.121101 13665 49.715851 -49.842712 -10.092476 13666 53.922913 -49.040710 -8.909973 13667 39.922661 -51.113510 -10.501991 13668 43.204895 -50.688828 -10.394245 13669 43.376511 -51.158646 -10.658001 13670 49.867279 -50.717514 -9.209171 13671 37.616272 -53.056412 -10.211185 13672 37.818161 -52.241776 -10.980053 13673 40.704056 -52.791138 -10.204586 13674 41.369003 -52.553009 -10.601700 13675 40.956711 -51.659988 -10.348717 13676 41.931198 -51.888763 -10.646111 13677 42.393127 -50.779190 -10.424431 13678 42.833710 -51.795212 -10.795834 13679 43.536179 -51.792587 -10.966454 13680 50.958496 -51.505737 -9.593319 13681 51.412933 -52.312759 -8.409531 13682 57.724319 -51.064819 -9.414562 13683 58.683960 -51.010742 -10.402222 13684 37.289383 -53.973206 -9.737179 13685 39.899582 -52.441223 -9.890373 13686 43.299454 -48.916046 -10.611282 13687 53.595566 -53.225311 -10.336632 13688 59.660370 -51.397354 -9.877323 13689 61.520111 -51.173920 -9.552704 13690 62.359528 -50.471802 -8.715057 13691 54.413818 -53.959076 -8.745445 13692 55.767441 -54.455994 -9.626488 13693 22.821732 -55.826340 -11.071381 13694 55.692963 -54.518448 -10.696209 13695 57.109711 -55.190704 -9.437195 13696 57.086151 -55.281235 -8.293076 13697 55.917938 -54.681320 -8.503929 13698 22.532608 -54.982971 -10.857521 13699 37.973877 -56.378860 -10.047691 13700 37.691574 -55.643570 -8.432938 13701 22.977158 -57.389832 -11.346249 13702 23.280174 -57.400253 -10.167252 13703 58.058060 -56.105362 -8.764954 13704 37.616341 -59.702469 -8.050125 13705 37.824249 -58.651657 -7.923569 13706 38.349968 -58.795746 -8.906036 13707 58.314545 -56.632050 -9.835312 13708 23.083473 -58.527542 -11.123055 13709 38.257301 -57.414062 -9.295586 13710 38.667465 -57.463287 -10.694363 13711 38.896431 -58.376587 -10.102028 13712 48.584534 -57.871735 -10.069542 13713 57.545074 -58.454193 -10.331074 13714 23.144424 -60.622467 -11.213535 13715 50.986847 -59.140778 -10.942831 13716 56.679581 -59.129364 -11.321053 13717 56.770645 -58.914261 -8.645905 13718 39.470787 -60.373505 -11.043995 13719 39.187988 -59.542130 -10.403435 13720 53.270538 -59.295151 -10.234730 13721 54.196442 -59.557281 -10.544983 13722 38.278992 -60.575378 -9.562355 13723 44.290558 -62.584518 -11.471603 13724 45.624512 -61.475952 -9.902130 13725 44.550308 -61.130371 -9.203575 13726 23.324127 -61.575836 -10.767830 13727 50.162674 -63.659836 -11.134605 13728 23.000061 -65.091507 -11.303841 13729 53.046631 -64.038925 -9.722000 13730 52.584915 -63.264511 -8.962250 13731 44.506119 -67.439911 -11.195286 13732 45.778931 -66.616241 -11.184071 13733 44.950943 -66.381607 -10.120560 13734 46.813095 -67.417847 -11.036884 13735 47.387695 -67.414841 -11.811928 13736 53.626953 -64.744873 -9.540798 13737 52.875275 -64.735703 -10.271835 13738 53.220627 -65.522736 -10.031364 13739 23.226807 -68.008057 -12.150284 13740 35.771103 -65.363785 -10.750320 13741 35.533195 -67.802307 -11.660767 13742 39.440826 -67.884476 -11.596352 13743 47.458344 -68.208954 -11.205772 13744 22.938019 -67.583038 -11.559326 13745 36.201508 -66.272385 -11.938282 13746 38.606941 -67.991180 -10.571220 13747 39.159470 -66.785645 -10.543404 13748 23.485275 -68.390137 -11.155762 13749 38.757576 -69.058258 -11.205421 13750 23.629868 -68.048172 -10.006226 13751 24.010307 -68.855682 -10.284565 13752 29.525154 -71.358810 -11.737358 13753 29.582977 -71.825562 -12.273659 13754 38.164047 -70.181137 -10.667240 13755 43.501007 -69.225708 -10.377804 13756 20.259018 -71.559921 -11.373726 13757 44.526489 -71.626755 -11.200508 13758 35.857918 -71.100815 -12.466377 13759 45.398849 -73.038788 -12.237469 13760 17.740250 -71.275024 -11.759270 13761 28.459961 -72.466751 -11.886131 13762 35.568550 -73.129807 -11.806717 13763 35.041565 -72.116379 -11.056879 13764 39.099434 -72.299988 -11.628151 13765 39.384247 -73.119080 -12.041309 13766 43.639999 -72.677475 -10.091408 13767 43.635941 -71.179031 -10.345547 13768 16.478668 -73.459167 -11.211678 13769 21.504074 -73.523727 -11.364624 13770 25.877785 -73.445740 -12.494759 13771 26.313164 -72.885345 -10.925175 13772 24.667755 -74.326447 -12.448380 13773 35.628708 -74.373642 -12.043247 13774 38.381653 -72.572937 -10.649014 13775 38.669403 -71.340851 -11.231598 13776 37.543289 -71.609024 -9.897251 13777 39.242065 -74.136444 -11.680874 13778 45.016159 -73.712234 -11.108723 13779 45.647995 -74.591812 -11.978825 13780 21.004593 -76.649872 -12.337044 13781 34.561630 -76.596069 -12.281708 13782 34.606613 -76.125229 -11.178562 13783 35.155609 -75.409958 -11.791985 13784 38.745270 -75.033890 -10.542946 13785 39.104286 -75.837952 -10.963627 13786 39.564873 -75.437485 -11.759663 13787 14.592278 -77.924179 -12.802368 13788 13.791702 -77.465378 -11.930840 13789 16.536156 -74.946030 -11.004623 13790 20.789490 -77.515274 -12.438286 13791 20.857529 -77.711411 -11.601643 13792 21.417007 -76.133575 -11.182732 13793 45.411530 -75.626312 -10.947830 13794 14.479370 -78.919571 -12.670071 13795 20.429970 -77.955963 -12.573288 13796 24.038963 -78.261230 -12.772705 13797 39.305000 -78.275757 -12.232506 13798 14.692238 -80.247360 -12.208305 13799 20.122292 -78.519257 -12.230282 13800 38.538589 -78.791565 -12.452988 13801 46.265060 -78.951691 -12.211256 13802 15.862381 -80.242844 -12.052567 13803 17.885010 -79.838135 -12.677917 13804 16.886864 -79.894958 -12.503387 13805 18.459549 -79.909409 -12.290962 13806 31.246193 -80.087891 -11.915863 13807 36.273514 -79.152237 -11.448967 13808 46.060822 -80.365311 -12.246944 13809 46.440094 -79.598999 -11.288490 13810 15.290314 -80.686935 -11.192993 13811 31.731020 -79.379669 -11.588287 13812 32.270584 -78.687622 -11.660652 13813 33.574165 -80.247452 -11.766525 13814 11.687454 -82.920502 -13.001854 13815 12.212463 -82.347244 -12.974670 13816 11.212532 -82.274368 -12.505085 13817 13.275009 -82.038834 -12.979431 13818 12.213745 -81.000046 -12.252678 13819 11.598320 -81.617142 -12.462566 13820 14.244789 -82.056503 -12.530113 13821 15.139214 -82.263367 -11.392738 13822 32.024155 -80.844223 -11.950443 13823 45.535294 -81.470963 -12.439339 13824 11.278374 -83.086197 -12.735199 13825 14.559746 -81.252625 -11.671532 13826 13.665604 -81.082458 -12.305740 13827 19.698318 -83.238388 -12.499567 13828 16.938766 -83.008652 -12.661083 13829 19.263031 -82.887543 -11.897629 13830 20.022530 -83.065430 -11.474018 13831 44.594772 -82.857925 -11.977566 13832 13.596321 -85.972031 -13.386944 13833 23.993912 -84.013626 -13.193085 13834 24.432678 -83.438980 -11.875481 13835 21.566254 -84.760284 -11.973978 13836 24.642113 -84.911743 -12.801250 13837 13.234161 -85.633682 -12.081455 13838 25.431290 -84.708557 -11.412140 13839 40.410049 -84.207397 -11.465240 13840 14.836563 -87.330322 -13.279247 13841 25.354004 -85.932663 -13.318512 13842 27.657570 -87.778687 -13.079090 13843 27.516830 -87.046982 -11.543388 13844 37.912453 -83.255325 -10.421021 13845 21.363525 -86.570007 -11.557762 13846 20.489487 -87.649796 -10.797073 13847 21.448883 -86.958115 -10.479588 13848 15.973152 -88.266266 -13.187199 13849 24.739914 -89.039307 -13.454117 13850 24.561890 -88.845566 -13.212589 13851 24.334915 -88.995026 -13.315971 13852 24.828148 -89.040558 -13.128700 13853 28.280533 -88.161911 -12.914513 13854 35.695709 -86.623108 -12.206509 13855 16.605850 -88.637421 -12.153481 13856 15.612747 -88.070282 -12.372021 13857 19.127907 -88.199249 -12.399868 13858 23.626053 -89.449615 -11.344913 13859 22.411392 -89.730743 -12.577553 13860 37.621750 -87.022293 -11.142746 13861 36.253998 -86.675705 -11.552879 13862 36.528999 -86.313095 -10.949364 13863 37.138206 -89.741989 -13.097118 13864 37.118149 -88.954987 -13.064819 13865 37.874275 -89.611038 -12.307291 13866 37.746918 -88.368576 -12.347778 13867 21.553764 -90.528931 -13.242928 13868 27.498672 -91.623138 -10.807777 13869 28.340477 -92.292694 -11.515095 13870 28.277977 -92.346680 -10.789288 13871 26.643059 -90.774109 -11.532066 13872 25.912743 -90.034836 -12.223831 13873 27.657593 -91.331421 -12.922508 13874 20.713799 -90.925644 -12.342793 13875 20.843918 -91.579437 -13.059517 13876 21.150642 -90.263824 -12.103989 13877 21.624710 -90.025909 -12.363880 13878 29.195679 -92.290817 -13.412769 13879 32.067657 -90.552536 -12.605831 13880 33.536011 -90.569687 -12.656372 13881 36.793961 -90.344009 -12.588928 13882 37.259354 -90.462265 -11.652031 13883 21.199471 -91.503082 -13.714024 13884 17.398376 -93.745331 -13.819862 13885 18.255051 -93.682968 -13.247581 13886 30.575249 -92.849106 -12.662949 13887 31.942377 -95.935303 -12.735432 13888 32.940155 -95.335938 -12.455208 13889 32.949203 -93.878510 -13.232353 13890 33.108376 -93.395325 -12.861641 13891 33.523903 -93.789963 -12.793549 13892 33.726616 -93.379074 -12.206741 13893 33.253830 -94.422806 -12.959381 13894 15.641434 -95.396133 -12.855377 13895 29.578598 -97.162292 -13.636192 13896 30.208344 -96.757599 -13.613075 13897 31.275543 -95.977646 -13.571480 13898 16.602478 -98.749115 -13.822281 13899 26.966644 -98.974182 -13.802608 13900 27.182205 -98.671082 -13.777504 13901 28.367668 -97.818970 -13.006771 13902 26.365814 -99.435562 -13.869984 13903 25.430298 -99.931076 -14.025459 13904 25.629654 -100.013992 -12.933681 13905 21.580460 -100.944763 -11.515427 13906 22.590210 -100.546249 -13.273758 13907 20.920242 -101.170502 -12.992336 13908 11.969803 62.871246 -0.429199 13909 10.715988 63.281387 -0.248871 13910 6.872803 62.959076 -2.032989 13911 6.656601 62.659515 -2.607529 13912 7.590401 63.050415 -2.379410 13913 5.561310 61.363220 -3.095436 13914 6.193276 60.951981 -3.571259 13915 5.237946 60.381149 -3.061623 13916 11.875549 62.951111 0.657272 13917 11.397278 63.272461 0.252091 13918 4.703377 61.140747 -2.282387 13919 5.023361 59.328171 -2.938026 13920 4.312508 58.627136 -2.384254 13921 5.348267 58.259842 -2.897690 13922 14.353424 58.738403 -2.388504 13923 7.988899 58.568771 -3.498169 13924 8.753815 59.269989 -4.097946 13925 19.927139 58.760727 -2.986694 13926 16.451645 58.489899 -2.466675 13927 16.284042 56.637177 -3.228714 13928 15.621117 56.519714 -2.455124 13929 15.957489 55.667862 -3.240143 13930 15.562866 55.123383 -3.708649 13931 8.270821 55.783966 -2.838196 13932 19.840256 55.549713 -2.815826 13933 19.928452 56.863525 -2.399231 13934 20.462143 55.300140 -3.497635 13935 25.151489 53.765991 -3.531242 13936 26.472168 54.536285 -3.453972 13937 15.180328 56.174408 -2.813393 13938 15.095001 56.993164 -2.202530 13939 20.136459 54.232635 -3.045197 13940 32.647339 54.275848 -2.167725 13941 35.553329 53.398834 -2.223358 13942 34.387474 53.819016 -1.867523 13943 7.995185 53.580566 -3.449234 13944 19.550125 53.914505 -2.386841 13945 19.466187 54.758545 -2.190941 13946 23.013672 52.679352 -3.660034 13947 21.074402 53.051163 -3.247475 13948 25.347061 52.617767 -3.085358 13949 24.826126 51.463623 -2.891884 13950 24.131241 52.553497 -3.448395 13951 26.402618 53.401627 -2.998413 13952 38.285202 51.136963 -2.594139 13953 7.849555 51.676453 -2.781006 13954 8.048431 50.609634 -3.369400 13955 22.161667 52.372406 -3.457092 13956 8.150787 50.270844 -4.250153 13957 21.589279 51.826370 -2.962173 13958 22.969200 51.326553 -3.034332 13959 21.581390 50.983459 -2.398376 13960 7.955642 49.725632 -3.877975 13961 3.081833 48.824112 -2.053864 13962 6.502464 49.641510 -3.171158 13963 7.472626 49.960297 -3.143753 13964 36.754044 47.206360 -4.213043 13965 39.016815 48.565155 -2.848251 13966 39.064789 49.979553 -2.488495 13967 1.831627 45.237885 -4.358887 13968 39.133400 47.525116 -3.143585 13969 2.230293 46.430023 -3.281616 13970 2.056786 42.650604 -4.855270 13971 6.420319 41.561951 -4.218155 13972 7.703605 41.537918 -4.106033 13973 8.981567 41.809738 -3.564301 13974 9.430725 40.661713 -4.086212 13975 9.319618 39.678329 -4.617355 13976 5.849289 42.589401 -3.574661 13977 10.129364 39.869415 -4.085609 13978 21.633636 38.919952 -4.632454 13979 46.746033 40.171173 -2.749321 13980 46.716324 41.068542 -2.880234 13981 10.001190 38.896820 -4.531952 13982 10.554276 38.887573 -3.944412 13983 22.087090 39.078003 -4.238709 13984 37.477066 39.254410 -4.936249 13985 10.157806 37.697144 -3.481957 13986 22.302124 38.585052 -4.693512 13987 21.886414 39.024963 -4.286873 13988 46.780487 37.230789 -2.880112 13989 47.223267 36.041748 -2.916092 13990 46.784744 38.586395 -2.897858 13991 4.762253 35.326263 -4.486175 13992 4.299240 34.454285 -4.988769 13993 5.589256 34.129562 -5.006042 13994 7.531975 35.311234 -4.148720 13995 6.585083 34.548462 -4.623962 13996 7.378449 33.203110 -5.260513 13997 8.548553 33.561691 -5.328743 13998 8.382294 32.987030 -5.505447 13999 47.144470 34.180740 -4.290413 14000 46.768280 34.207687 -3.861168 14001 47.352539 35.591248 -3.242645 14002 3.850304 35.318665 -4.455170 14003 5.855629 35.771149 -4.095963 14004 8.562302 34.503876 -4.877457 14005 44.742218 34.544495 -1.782928 14006 45.558899 34.285141 -2.386658 14007 45.606323 33.342163 -1.801102 14008 1.981804 32.524475 -4.255898 14009 1.813957 31.786011 -4.910202 14010 2.080109 31.999100 -5.118591 14011 26.054420 31.735123 -4.299439 14012 27.807030 31.394043 -4.563194 14013 27.939751 31.232086 -3.286263 14014 30.546844 31.506195 -3.796722 14015 31.592941 31.402023 -4.492439 14016 46.270782 30.658081 -4.322464 14017 33.158257 30.311432 -4.024361 14018 34.777443 29.082184 -3.949715 14019 22.303619 29.559753 -4.925140 14020 22.751869 30.482788 -3.913788 14021 26.411072 29.262192 -4.409218 14022 29.040688 28.876434 -3.991943 14023 46.150620 30.118073 -4.232010 14024 30.346558 28.338303 -3.801666 14025 29.731102 28.850555 -3.024376 14026 36.052948 29.337982 -4.442100 14027 39.893127 29.325500 -4.340164 14028 46.438370 29.775909 -4.392601 14029 0.418900 26.981995 -5.817917 14030 22.748680 28.633972 -4.523788 14031 30.639709 28.495331 -3.034775 14032 32.059601 27.558563 -4.818230 14033 36.598907 28.821457 -3.743591 14034 41.081665 25.024948 -5.687385 14035 49.220154 27.590302 -4.340973 14036 1.147247 24.919266 -4.733986 14037 2.373261 23.089111 -4.201538 14038 0.708641 23.433441 -5.694984 14039 31.657175 28.134766 -3.547775 14040 31.445816 29.001801 -2.683228 14041 38.738754 26.899445 -3.682793 14042 39.274757 26.993637 -3.075829 14043 38.516541 27.924850 -2.587463 14044 37.662079 27.737564 -3.706062 14045 40.586761 26.916168 -4.244576 14046 40.201401 27.891418 -3.631424 14047 49.421631 26.628342 -4.863510 14048 51.010010 23.841278 -3.436707 14049 0.976158 22.056335 -5.614075 14050 49.508575 22.837524 -4.171707 14051 1.544517 20.693008 -5.786552 14052 48.326187 21.093552 -4.994965 14053 27.184204 19.693634 -4.317253 14054 31.300980 17.957092 -6.112106 14055 2.282990 20.275604 -4.847633 14056 12.965813 18.741272 -6.898514 14057 27.338249 19.861740 -6.658554 14058 28.512230 19.922791 -4.267571 14059 3.488464 17.576187 -5.940529 14060 11.167053 15.874573 -7.014267 14061 12.705490 14.372742 -7.106201 14062 25.996147 17.982437 -5.036941 14063 32.217056 18.209473 -4.365128 14064 33.120972 18.073242 -4.343002 14065 34.219879 17.085205 -5.583748 14066 33.827248 17.665771 -4.729744 14067 27.250778 16.821732 -4.730850 14068 35.036728 17.616669 -4.463394 14069 36.094536 17.307190 -4.235504 14070 36.088493 16.827621 -5.034592 14071 37.922928 17.696503 -3.885696 14072 47.557724 15.179398 -4.128670 14073 48.243103 15.849030 -4.200623 14074 53.628540 16.086639 -4.155602 14075 52.881592 15.493423 -3.727158 14076 54.499115 16.304398 -4.655151 14077 32.080193 14.646759 -5.570938 14078 31.217842 14.924789 -5.840118 14079 31.231094 14.818909 -5.327377 14080 40.376099 16.468201 -5.004158 14081 41.036743 16.230988 -5.082626 14082 43.368622 15.756271 -4.203514 14083 44.212921 15.389801 -5.045029 14084 45.453644 15.223618 -4.363007 14085 46.331940 15.050934 -5.257187 14086 50.924988 15.196838 -5.291885 14087 3.912644 16.552124 -4.852821 14088 4.491554 15.996033 -5.198555 14089 33.458664 13.962448 -5.597832 14090 46.658707 15.105621 -4.286331 14091 50.168365 13.818680 -4.979446 14092 5.736740 13.253632 -6.397667 14093 35.213692 13.174774 -5.793198 14094 35.968719 12.831787 -5.480926 14095 36.746017 12.266968 -5.701836 14096 37.519592 11.808685 -5.491745 14097 38.962639 10.980545 -5.378319 14098 38.469360 11.369858 -4.449264 14099 38.071709 11.720764 -4.869621 14100 48.990204 9.693634 -4.244743 14101 48.566406 8.035461 -4.324997 14102 47.942078 9.634583 -5.307991 14103 6.303095 8.443118 -6.244984 14104 39.106514 11.138367 -4.537064 14105 41.398560 10.503036 -4.357010 14106 47.478088 7.999146 -5.392464 14107 12.346956 4.521248 -8.425936 14108 12.997424 4.398418 -8.633324 14109 13.484168 4.465724 -8.822292 14110 57.175003 9.726135 -5.055725 14111 6.420619 7.286513 -5.183163 14112 6.919479 5.976354 -4.974445 14113 11.840902 4.401142 -8.070775 14114 38.541840 6.248260 -6.858597 14115 42.563461 7.425522 -3.822372 14116 42.107712 8.950897 -4.342941 14117 41.315872 6.539917 -4.833252 14118 11.528392 4.024046 -7.638327 14119 39.048279 5.644302 -6.431831 14120 40.664673 7.223236 -5.615646 14121 39.917206 5.555748 -5.542198 14122 41.971512 5.827026 -4.129982 14123 43.396759 6.021454 -3.207291 14124 58.941422 4.934189 -5.041946 14125 58.627319 6.375961 -4.313416 14126 8.227108 4.945362 -5.928387 14127 11.140819 3.618245 -7.250617 14128 11.351283 3.800912 -7.454132 14129 9.908816 4.278289 -6.883416 14130 12.214475 3.266905 -7.584128 14131 22.667866 2.620281 -7.793803 14132 22.727129 1.626645 -7.958708 14133 6.841954 4.872784 -4.337924 14134 7.225788 3.374705 -4.368321 14135 7.634676 4.173315 -5.014977 14136 11.479620 2.877718 -7.140681 14137 9.539529 3.278697 -6.239599 14138 10.842386 2.226614 -6.711654 14139 10.785937 1.268777 -6.569369 14140 19.087906 0.377997 -8.611493 14141 21.302940 3.043956 -7.916809 14142 39.562843 3.234222 -5.297813 14143 39.463768 4.307343 -5.213730 14144 48.172897 2.724289 -4.387604 14145 45.310699 1.602310 -5.627602 14146 8.244654 3.302505 -5.326948 14147 9.801333 1.907991 -6.117945 14148 9.595057 0.563165 -5.851688 14149 10.819206 0.232822 -6.583919 14150 20.440571 1.869240 -8.220369 14151 18.875313 1.670590 -8.363731 14152 21.695095 1.766206 -8.097677 14153 26.606750 1.705933 -7.503265 14154 44.187698 1.522995 -6.553329 14155 44.300247 0.832443 -6.101074 14156 59.643295 1.763153 -5.737717 14157 59.583939 2.478989 -5.574051 14158 9.549923 -0.636408 -5.851038 14159 21.098782 0.913773 -8.407038 14160 40.145752 -0.489700 -6.526993 14161 7.652317 1.866148 -4.512321 14162 6.804906 1.162255 -3.559113 14163 7.518899 -0.028731 -4.200480 14164 19.073879 -1.547916 -9.079129 14165 40.551178 -0.176178 -5.467682 14166 40.709641 -1.602539 -4.956756 14167 45.976181 -3.542709 -4.489532 14168 44.764435 -4.337875 -4.942703 14169 59.077576 -1.204941 -5.946884 14170 9.258545 -2.062822 -5.798017 14171 8.338006 -2.512873 -5.076708 14172 8.656778 -3.450882 -5.509766 14173 9.508578 -3.135037 -6.167605 14174 8.664362 -1.425340 -5.241836 14175 7.697420 -3.646351 -4.575930 14176 7.727074 -1.698606 -4.409372 14177 7.081772 -2.719725 -3.740835 14178 6.822854 -3.719445 -3.492653 14179 6.990146 -4.372110 -3.798803 14180 9.172669 -4.306124 -6.140527 14181 58.817032 -1.785385 -5.737045 14182 9.922334 -3.694956 -6.585380 14183 9.895379 -4.235861 -6.695499 14184 9.716281 -4.807788 -6.706307 14185 10.653940 -3.951061 -7.123838 14186 8.515679 -0.363084 -5.061212 14187 18.337881 -2.232212 -9.151155 14188 18.164713 -1.048349 -8.858250 14189 20.125540 -1.908583 -9.303914 14190 43.659790 -4.488846 -5.469452 14191 42.577454 -4.965103 -6.026733 14192 39.980431 -2.893814 -5.514450 14193 42.527802 -6.021072 -5.819214 14194 43.901123 -5.831528 -5.171051 14195 19.360725 -4.669394 -9.896286 14196 19.388735 -4.096464 -9.753773 14197 18.119678 -3.171974 -9.343447 14198 22.311605 -4.397909 -10.404734 14199 22.382309 -5.044336 -10.609411 14200 40.170105 -6.045303 -6.522858 14201 54.554276 -6.431412 -6.498444 14202 54.333725 -6.153030 -5.197143 14203 59.713486 -6.436386 -5.996262 14204 58.143097 -7.021637 -5.632751 14205 60.790009 -5.945938 -5.475113 14206 60.615082 -6.995880 -6.181251 14207 59.329468 -5.545700 -5.135582 14208 10.108687 -5.271846 -7.091241 14209 10.104517 -4.893193 -7.023980 14210 39.646629 -6.129791 -6.151565 14211 57.410172 -8.121338 -6.455765 14212 19.854921 -5.879118 -10.284576 14213 20.503725 -6.102865 -10.463717 14214 20.882036 -6.167410 -10.556154 14215 21.362646 -6.111008 -10.649490 14216 22.152470 -6.251907 -10.891647 14217 22.442726 -5.583085 -10.778149 14218 22.137276 -5.892823 -10.774227 14219 22.199570 -5.662405 -10.721416 14220 61.334229 -8.136810 -5.438263 14221 61.920532 -7.436066 -5.106735 14222 61.494873 -7.093109 -5.649147 14223 16.653290 -6.642229 -9.906500 14224 21.810551 -5.863155 -10.683401 14225 22.041340 -5.732120 -10.697649 14226 52.841614 -9.358078 -6.502876 14227 6.535166 -9.346633 -3.870822 14228 16.385456 -7.314550 -10.010265 14229 52.393616 -9.977875 -5.805176 14230 52.417496 -9.178085 -5.478210 14231 6.885225 -10.371733 -4.539177 14232 6.752389 -11.070362 -4.214837 14233 7.378168 -11.035778 -5.314876 14234 7.461766 -11.789178 -5.475647 14235 59.994537 -10.740189 -6.227997 14236 53.363327 -10.675507 -4.725075 14237 59.832962 -11.372284 -5.914528 14238 57.142731 -12.895081 -6.478027 14239 64.594849 -12.840515 -6.862579 14240 65.492844 -12.896423 -6.978897 14241 65.264526 -13.400238 -6.455597 14242 65.376816 -14.514389 -5.931457 14243 7.316595 -13.022171 -5.080649 14244 7.187070 -13.914206 -4.580605 14245 58.316818 -12.896118 -5.933609 14246 57.043808 -13.570099 -5.995727 14247 63.846909 -13.586090 -6.630073 14248 64.617447 -13.635345 -6.124641 14249 64.168915 -14.050964 -6.007751 14250 53.151718 -14.623383 -6.836609 14251 61.876404 -14.715042 -7.403282 14252 62.650940 -14.645844 -7.027672 14253 63.465393 -14.576340 -6.461243 14254 66.437302 -14.980209 -6.578033 14255 66.279297 -16.112778 -5.816109 14256 6.262567 -11.706945 -3.047427 14257 5.966144 -11.701899 -2.211679 14258 6.377949 -12.596719 -3.096231 14259 21.861639 -14.601334 -5.365411 14260 21.810507 -14.599213 -5.311327 14261 21.864965 -14.548035 -5.306772 14262 21.911108 -14.604782 -5.309259 14263 49.672424 -16.061996 -5.974853 14264 47.844574 -16.623306 -6.066231 14265 49.074295 -16.537109 -4.966095 14266 54.137207 -14.822403 -5.975693 14267 61.319595 -15.903473 -7.398971 14268 62.609100 -15.410934 -6.897186 14269 6.863103 -14.392088 -3.626302 14270 7.269159 -15.543682 -4.021785 14271 21.860464 -14.652100 -5.313257 14272 62.607391 -16.608459 -6.695297 14273 61.521484 -17.552338 -7.039970 14274 62.881302 -18.036087 -6.118912 14275 66.943375 -15.742950 -6.810654 14276 7.859421 -16.503963 -4.723359 14277 52.380463 -17.651047 -8.271820 14278 52.520538 -18.260880 -7.831833 14279 59.184235 -20.638443 -7.203346 14280 57.766617 -21.070374 -7.215889 14281 61.722519 -18.713974 -6.658523 14282 7.570520 -15.736399 -4.651195 14283 47.468384 -21.084610 -5.792038 14284 53.322052 -18.806839 -7.512108 14285 52.336304 -19.791992 -7.142914 14286 54.274216 -19.577972 -7.236687 14287 56.276733 -20.473724 -7.242035 14288 55.224838 -19.133698 -7.538010 14289 60.305359 -18.894028 -7.182869 14290 67.237762 -16.690414 -6.771423 14291 8.457854 -17.496048 -5.104742 14292 53.502502 -20.075943 -7.005608 14293 67.889267 -19.404404 -7.002945 14294 67.117233 -17.913528 -6.091438 14295 26.226738 -22.665710 -8.407658 14296 25.756685 -22.074184 -8.817039 14297 62.024689 -20.013519 -6.090378 14298 60.618607 -20.723801 -6.677750 14299 20.240623 -22.394072 -8.114825 14300 26.165291 -23.648659 -7.619105 14301 27.332602 -23.888035 -7.549371 14302 55.075104 -20.421082 -7.078781 14303 59.881775 -21.805344 -6.508606 14304 60.208405 -22.755005 -5.842239 14305 59.085327 -22.997086 -6.159012 14306 68.352615 -21.761185 -7.246933 14307 18.946562 -22.843880 -7.642963 14308 57.667587 -22.717529 -6.470512 14309 56.974762 -21.709015 -6.916061 14310 58.731628 -21.873718 -6.863426 14311 68.306183 -22.564240 -7.332321 14312 18.012375 -23.289108 -7.123463 14313 34.004967 -23.917963 -8.612617 14314 35.946468 -23.856638 -9.185588 14315 34.979462 -24.204554 -8.607775 14316 67.825150 -22.731491 -6.342239 14317 18.617508 -24.601765 -5.914798 14318 17.463583 -23.960041 -6.336933 14319 17.728418 -24.669436 -5.648218 14320 31.963942 -24.381449 -7.836579 14321 30.928181 -24.951431 -7.172578 14322 32.148174 -25.016779 -7.338498 14323 33.081055 -24.484726 -7.962894 14324 34.123615 -24.721535 -7.984751 14325 33.200565 -25.247721 -7.345086 14326 34.294250 -25.429037 -7.426528 14327 33.625668 -25.818888 -6.933464 14328 35.136875 -25.165033 -7.839024 14329 16.468407 -24.005163 -6.014640 14330 18.478849 -23.782986 -6.721510 14331 23.791321 -25.882248 -8.842850 14332 35.809586 -24.710344 -8.382921 14333 36.809601 -25.653931 -8.294334 14334 66.800446 -26.013687 -7.406525 14335 67.095032 -25.690659 -6.450928 14336 11.680585 -22.161282 -5.122160 14337 23.651199 -26.434967 -8.529556 14338 24.314453 -27.030762 -8.143280 14339 23.560745 -26.909470 -8.134499 14340 37.292953 -26.431030 -8.821960 14341 36.845627 -26.518112 -8.201813 14342 12.635098 -22.758778 -5.359157 14343 16.032494 -24.477253 -5.294222 14344 17.619301 -29.053589 -8.838654 14345 18.363441 -28.156784 -8.478737 14346 20.346924 -27.727066 -7.822204 14347 21.548904 -27.820251 -7.575806 14348 25.671219 -27.480621 -8.235168 14349 27.206039 -28.260040 -8.391769 14350 36.751923 -27.568436 -7.836655 14351 36.565918 -28.531754 -7.395080 14352 14.401181 -23.535950 -5.670115 14353 65.742203 -28.049011 -7.547577 14354 18.189445 -28.893082 -7.552315 14355 17.590439 -29.628967 -7.706642 14356 35.687729 -30.099289 -8.811813 14357 16.783768 -30.810593 -8.559418 14358 29.233986 -29.460800 -8.456375 14359 30.761742 -30.864975 -8.032433 14360 31.420654 -31.763412 -7.716095 14361 35.018829 -31.775131 -8.514404 14362 16.976273 -30.755081 -7.123100 14363 15.634491 -32.510696 -7.233383 14364 36.397446 -30.096146 -6.993606 14365 67.276825 -31.014267 -7.580215 14366 15.957504 -32.623596 -8.374672 14367 35.613525 -32.073486 -8.433701 14368 35.855865 -32.350815 -8.025009 14369 36.022621 -32.087402 -6.790451 14370 67.611206 -32.171432 -7.299072 14371 15.965630 -33.845154 -8.210022 14372 16.805916 -34.661728 -8.834457 14373 34.853561 -33.062515 -7.919395 14374 33.520905 -33.274841 -7.372513 14375 35.507996 -32.646484 -8.205627 14376 66.490906 -33.103882 -5.411781 14377 66.518677 -31.932709 -5.066551 14378 67.311081 -32.374283 -5.999405 14379 17.289459 -37.122116 -8.211441 14380 17.308990 -38.682297 -7.688812 14381 18.067139 -38.742905 -8.155357 14382 67.629822 -33.601578 -6.784111 14383 18.216660 -36.293274 -9.172523 14384 21.993622 -36.422424 -8.450523 14385 22.779297 -36.332153 -8.383171 14386 23.904678 -36.806000 -8.329758 14387 25.193619 -36.920990 -8.384705 14388 19.210556 -36.596832 -9.309452 14389 27.227631 -37.982407 -7.992691 14390 31.939302 -37.458160 -8.975731 14391 18.993195 -37.248749 -8.872070 14392 67.696991 -36.771484 -7.965286 14393 33.709488 -39.224380 -9.068684 14394 66.821732 -38.476151 -7.384025 14395 24.657227 -41.514191 -9.462109 14396 33.854958 -40.211838 -8.574341 14397 33.711716 -41.028061 -9.142105 14398 57.460144 -39.923492 -8.478470 14399 64.060150 -39.544693 -8.372177 14400 22.805038 -42.858475 -9.309067 14401 28.096542 -42.188385 -9.094528 14402 29.660873 -42.268402 -9.112049 14403 33.056259 -41.266235 -9.774872 14404 60.193817 -39.409500 -7.635742 14405 61.245712 -39.336487 -7.496193 14406 62.209488 -39.216599 -7.501335 14407 63.117004 -39.383759 -7.951034 14408 21.863342 -43.525940 -9.689331 14409 22.625221 -44.090958 -9.182709 14410 29.365707 -43.590820 -8.310898 14411 32.984528 -42.998749 -8.198967 14412 32.798309 -43.632858 -7.825508 14413 32.883331 -42.629410 -8.628502 14414 33.585770 -42.161575 -8.234390 14415 54.352081 -41.667496 -6.411117 14416 54.579742 -40.319046 -6.419655 14417 54.723145 -40.590622 -7.222305 14418 54.304367 -41.726379 -8.999100 14419 22.037148 -44.233307 -9.518661 14420 54.163284 -42.927048 -7.903129 14421 54.076416 -41.992340 -8.423622 14422 54.291580 -42.542191 -8.864433 14423 55.225952 -44.015305 -8.726028 14424 55.976303 -44.482590 -8.648613 14425 56.640793 -44.614517 -9.127968 14426 22.281158 -44.933243 -9.528088 14427 56.633163 -44.861115 -7.810890 14428 56.311050 -44.281662 -6.654022 14429 55.237762 -44.044617 -7.900253 14430 22.868866 -46.583786 -9.891693 14431 56.885498 -45.021378 -8.562714 14432 57.829819 -45.473099 -8.082130 14433 59.105164 -45.898941 -8.612946 14434 22.512375 -45.697205 -9.582619 14435 50.067444 -46.824127 -8.732117 14436 49.257050 -47.424240 -9.145660 14437 61.720978 -47.500259 -8.090477 14438 23.944550 -47.351715 -9.441166 14439 49.155701 -49.692123 -9.194672 14440 52.891541 -48.230591 -8.926010 14441 62.624664 -48.767853 -8.036407 14442 23.460182 -51.057678 -9.980503 14443 49.019974 -50.463104 -8.137962 14444 56.681564 -50.658447 -9.214981 14445 54.873169 -49.913528 -8.078644 14446 62.883057 -49.500458 -8.647835 14447 38.060776 -52.198151 -10.341682 14448 22.782684 -54.964706 -10.262955 14449 37.679779 -53.792755 -8.895248 14450 38.158287 -52.873062 -9.524593 14451 38.101959 -52.476974 -9.958385 14452 53.002243 -52.965103 -9.559246 14453 52.403702 -53.068329 -8.247246 14454 58.894363 -51.528946 -9.209583 14455 61.646347 -51.464615 -8.073502 14456 60.245392 -51.844086 -8.322540 14457 61.189056 -51.842010 -7.189850 14458 61.334305 -51.457199 -8.972679 14459 40.337494 -53.567047 -9.299198 14460 41.225830 -54.596497 -9.257233 14461 53.775665 -53.416489 -9.474411 14462 23.613396 -54.294724 -9.626175 14463 37.302124 -54.550659 -9.224377 14464 40.535736 -54.318710 -8.096054 14465 23.029114 -55.781082 -9.712090 14466 23.699303 -56.463058 -9.343994 14467 24.779053 -57.287186 -9.061707 14468 44.560120 -57.068542 -9.588696 14469 43.791199 -56.725693 -9.162128 14470 44.539886 -56.781097 -8.848969 14471 46.434860 -57.228668 -9.400723 14472 47.450134 -57.497925 -9.707901 14473 58.369934 -57.409042 -9.383823 14474 58.531891 -56.662613 -9.172489 14475 23.383484 -58.776352 -10.257328 14476 49.812561 -58.139145 -9.817230 14477 57.683548 -58.394211 -8.966202 14478 58.272934 -57.619797 -8.342743 14479 23.264824 -59.645691 -10.734734 14480 50.919632 -58.644089 -9.918400 14481 51.761139 -58.466476 -8.942871 14482 53.950623 -58.829895 -9.321842 14483 54.721161 -58.935806 -8.573051 14484 54.744141 -59.168076 -9.670498 14485 55.826996 -59.095596 -8.208290 14486 39.099426 -60.450470 -10.428452 14487 52.954880 -58.648285 -9.151756 14488 54.980042 -59.485428 -10.309811 14489 46.910278 -61.880600 -10.287769 14490 43.415955 -61.962845 -9.990612 14491 46.701553 -61.298584 -8.788422 14492 48.176346 -61.820450 -8.747269 14493 47.376038 -61.315643 -7.840439 14494 50.321121 -63.073212 -9.654354 14495 42.237335 -61.905243 -9.034184 14496 40.272644 -63.610413 -8.997658 14497 40.470459 -64.704834 -10.300980 14498 51.414154 -63.422958 -9.479263 14499 43.341354 -66.543686 -8.615349 14500 43.958038 -66.694885 -9.770969 14501 43.238754 -67.392044 -9.612850 14502 45.700027 -66.429825 -10.111855 14503 46.302536 -67.210587 -10.213760 14504 45.917297 -66.821793 -9.560188 14505 46.252289 -67.945068 -9.471245 14506 23.197289 -67.344849 -10.686592 14507 38.360481 -67.266464 -9.838249 14508 52.860626 -67.091599 -9.285831 14509 34.590485 -67.959122 -10.343109 14510 45.410309 -66.404526 -9.472099 14511 47.134476 -68.750122 -10.280937 14512 52.307816 -67.840195 -9.546299 14513 51.644424 -68.367355 -9.980835 14514 51.089584 -69.158920 -9.071507 14515 15.882111 -70.807632 -10.036556 14516 15.207062 -71.411362 -9.996628 14517 16.641907 -71.682190 -11.131866 14518 17.295532 -70.728790 -11.111549 14519 17.914429 -70.356339 -10.737041 14520 19.657181 -70.833878 -10.957878 14521 34.688339 -69.497833 -10.564152 14522 43.700500 -67.586472 -10.293365 14523 47.334885 -70.142380 -9.568901 14524 48.364120 -70.122269 -10.144203 14525 49.392670 -69.844330 -10.516602 14526 50.184555 -69.953705 -9.467033 14527 29.288528 -71.286957 -10.934498 14528 29.154297 -70.750122 -10.494122 14529 29.195557 -71.219269 -10.291172 14530 34.784119 -71.135269 -10.778591 14531 20.889435 -72.385834 -11.240883 14532 34.876404 -71.932281 -10.018841 14533 21.337234 -73.042572 -11.138824 14534 29.020721 -71.712936 -10.516090 14535 38.863213 -73.169998 -11.217274 14536 21.504898 -74.323318 -10.872318 14537 21.518776 -73.431625 -10.842167 14538 35.029716 -72.907974 -10.434292 14539 12.188705 -77.982742 -11.115520 14540 12.793121 -77.365448 -11.131622 14541 11.865593 -76.818176 -9.688728 14542 14.361710 -76.475616 -11.135376 14543 14.623230 -76.336380 -9.417358 14544 13.343735 -76.548203 -10.097511 14545 44.762192 -76.113693 -9.930489 14546 43.819214 -75.955566 -9.433090 14547 43.901947 -75.194382 -9.826096 14548 24.606735 -75.834885 -11.262535 14549 33.916687 -77.185379 -11.269882 14550 34.465591 -76.295456 -10.348705 14551 38.488152 -77.942657 -10.901144 14552 24.358810 -78.143295 -12.229931 14553 25.348976 -76.826355 -10.580154 14554 25.472916 -78.565109 -10.779545 14555 24.762253 -78.259033 -11.666142 14556 33.139008 -77.977371 -11.211311 14557 13.034096 -78.543808 -11.876068 14558 20.115067 -78.915878 -10.851192 14559 20.719894 -78.706451 -9.780319 14560 21.024605 -77.946625 -10.202400 14561 24.140900 -78.982574 -12.420708 14562 37.614510 -78.614258 -11.375546 14563 38.743134 -78.317841 -11.614620 14564 46.521820 -78.769958 -11.507797 14565 46.620804 -78.721436 -11.119965 14566 13.153732 -79.898621 -12.133316 14567 11.917374 -79.155258 -11.430183 14568 18.845238 -79.745483 -11.200031 14569 19.463028 -79.328415 -9.513096 14570 24.425385 -80.161362 -11.577187 14571 34.842926 -79.507736 -11.363762 14572 35.566422 -78.761932 -10.461792 14573 11.051834 -81.341293 -11.861931 14574 11.068512 -80.242111 -11.343475 14575 16.521240 -80.336990 -10.769566 14576 17.761513 -80.076767 -11.455517 14577 23.907272 -81.967560 -12.239254 14578 24.823334 -81.093887 -10.505478 14579 24.452835 -81.886688 -11.165707 14580 31.716539 -80.448456 -11.512505 14581 32.500877 -80.518127 -11.531631 14582 10.559799 -82.212143 -11.556992 14583 10.500961 -82.907761 -11.789936 14584 10.751747 -82.802200 -12.256592 14585 12.073357 -80.068588 -11.787346 14586 31.720087 -79.962509 -11.084068 14587 31.453438 -79.968933 -11.399883 14588 32.126053 -80.206421 -11.015045 14589 45.932373 -81.133194 -11.433716 14590 15.999619 -82.918243 -12.181999 14591 16.159294 -82.916550 -11.161823 14592 16.835312 -83.008057 -11.652035 14593 18.034729 -82.858780 -11.678421 14594 45.662445 -81.724823 -10.414787 14595 11.043816 -83.332870 -12.172993 14596 11.596329 -83.731857 -11.569103 14597 20.974197 -83.682236 -11.254982 14598 39.165688 -82.121475 -8.973534 14599 40.177353 -82.181992 -8.439224 14600 40.189697 -82.859634 -9.721668 14601 41.814133 -84.343979 -11.342896 14602 12.612961 -84.626587 -10.946133 14603 21.992310 -85.490326 -11.086594 14604 25.503891 -85.663940 -12.207207 14605 35.233017 -85.491257 -11.952621 14606 34.934929 -85.654373 -11.785599 14607 35.091675 -85.466873 -11.610191 14608 35.395790 -85.066147 -11.479721 14609 42.866104 -84.675369 -11.996048 14610 19.172775 -88.499496 -11.288345 14611 19.798996 -88.828125 -10.428799 14612 26.341187 -86.526321 -12.592014 14613 35.219406 -85.901489 -11.877472 14614 11.096368 -88.089844 -12.400520 14615 10.632965 -87.644089 -11.989296 14616 10.679749 -88.407211 -12.045248 14617 11.496674 -87.914810 -12.294472 14618 11.277649 -87.638824 -12.108589 14619 11.907669 -87.666992 -11.610588 14620 38.432808 -88.002731 -11.916470 14621 38.558273 -88.757767 -12.073555 14622 11.443253 -88.764969 -12.189323 14623 11.802170 -88.323257 -12.185600 14624 12.364685 -88.931778 -11.834774 14625 12.515213 -88.271912 -11.536892 14626 14.192368 -86.669052 -12.185650 14627 15.056839 -87.433228 -11.940590 14628 17.991760 -88.771103 -12.055943 14629 17.463371 -88.994278 -10.735172 14630 18.641357 -89.011520 -10.902840 14631 24.420670 -88.989471 -12.994186 14632 29.259254 -88.872925 -12.808868 14633 28.630264 -88.151520 -11.688728 14634 29.724731 -88.833206 -11.420105 14635 39.041321 -88.459091 -11.793842 14636 38.963547 -87.768692 -11.387123 14637 39.476593 -87.121445 -10.094749 14638 16.114601 -87.971359 -10.854691 14639 24.710114 -89.336487 -12.504372 14640 31.074585 -89.667221 -11.358727 14641 39.311996 -89.234634 -11.191322 14642 25.858597 -90.112259 -11.250069 14643 25.070557 -89.609619 -11.556374 14644 38.199280 -90.274857 -10.882561 14645 20.546387 -91.620163 -12.515305 14646 32.430565 -90.137833 -11.417892 14647 33.696472 -90.187103 -10.983112 14648 20.716339 -92.230667 -12.551666 14649 29.159943 -92.466217 -12.094723 14650 17.360077 -94.091125 -12.749882 14651 21.530396 -93.400696 -12.610008 14652 20.396141 -94.202942 -12.691467 14653 21.044945 -92.792175 -12.573135 14654 22.373100 -94.018143 -12.530052 14655 22.306122 -94.625793 -12.475903 14656 21.668541 -94.496704 -12.507927 14657 22.373398 -93.540115 -12.319496 14658 22.685455 -93.903259 -11.964256 14659 32.988022 -93.048691 -12.233562 14660 32.151825 -92.786041 -11.822445 14661 35.335823 -93.390930 -10.816196 14662 34.479301 -93.457550 -11.457687 14663 34.746140 -94.418655 -11.210144 14664 16.302841 -94.587357 -12.653812 14665 22.605385 -94.691330 -12.059288 14666 33.904663 -94.334213 -12.169952 14667 19.758888 -94.942368 -11.761646 14668 19.098816 -94.397537 -12.189331 14669 20.944275 -95.109985 -11.836315 14670 21.980003 -95.100128 -11.970612 14671 15.191086 -95.887939 -12.556301 14672 29.500015 -97.185287 -12.803329 14673 30.825203 -96.642822 -12.597057 14674 16.091393 -98.825150 -13.280235 14675 14.515671 -97.657730 -12.068832 14676 14.719025 -98.466095 -12.046715 14677 27.275024 -98.931503 -12.477852 14678 27.834915 -98.971252 -10.981045 14679 28.515442 -98.139954 -11.118185 14680 27.311783 -99.405426 -10.876133 14681 26.542175 -99.770584 -11.258308 14682 15.212563 -100.218414 -9.924522 14683 16.165848 -100.861069 -10.961861 14684 15.472672 -99.475494 -11.948933 14685 8.437958 63.171265 -1.592316 14686 7.383392 63.129532 -1.814850 14687 10.756607 63.201660 0.690056 14688 5.641457 62.123474 -2.322777 14689 6.267563 62.651688 -1.939621 14690 4.083252 60.988770 -1.431320 14691 4.934990 61.761871 -1.336884 14692 4.163529 61.144135 -0.078827 14693 3.833580 59.895096 -1.672546 14694 13.658890 61.476974 -1.497688 14695 14.448532 61.241776 -0.272850 14696 13.247421 62.080963 -0.562225 14697 17.021805 60.583755 -0.612564 14698 15.515915 59.813080 -0.940750 14699 16.609940 59.421143 -1.815689 14700 19.449463 59.615494 -1.597748 14701 6.642655 57.742554 -2.851166 14702 7.724594 57.569733 -2.774048 14703 7.230408 57.082962 -2.405319 14704 15.925125 58.736298 -1.594467 14705 20.080933 58.151398 -1.837196 14706 5.464066 56.800171 -2.496185 14707 4.314362 57.581879 -2.240189 14708 6.608147 56.422974 -2.267570 14709 7.908462 56.893616 -2.561523 14710 4.207497 56.238739 -1.794037 14711 8.012199 54.601929 -2.409821 14712 19.965523 55.788269 -1.166206 14713 20.620636 57.183411 -0.923172 14714 19.922897 56.883881 -1.507401 14715 15.326515 55.576385 -3.290817 14716 19.490685 55.739395 -2.246613 14717 27.558739 54.178085 -3.022858 14718 28.658669 53.861221 -2.719734 14719 29.975143 53.674576 -2.205978 14720 31.446205 53.990860 -2.098068 14721 33.625427 54.319016 -2.257591 14722 7.691635 53.636887 -2.179901 14723 7.925918 52.753387 -2.739456 14724 19.997566 53.253906 -2.406715 14725 27.638474 53.001114 -2.564499 14726 26.442032 51.984070 -2.625069 14727 31.160866 52.825912 -1.107636 14728 29.818710 52.623688 -1.489235 14729 30.440796 52.294861 -0.963020 14730 19.575745 53.834656 -1.791992 14731 36.781448 52.741821 -2.095444 14732 37.769142 52.000031 -1.336151 14733 20.668335 52.066269 -2.222389 14734 20.235352 53.019333 -1.492416 14735 25.779564 50.709595 -2.433487 14736 21.174263 52.332642 -0.686165 14737 20.594864 52.046631 -1.390442 14738 21.108261 51.154984 -1.288101 14739 22.437851 50.219086 -2.462029 14740 24.061447 49.806625 -2.270454 14741 25.635284 49.822266 -2.045792 14742 39.213226 51.222595 -1.332878 14743 5.291817 49.538376 -3.003677 14744 21.654388 50.138214 -1.756531 14745 22.932053 48.618576 -1.094879 14746 22.431519 49.502823 -1.917664 14747 22.239685 49.164673 -1.411263 14748 39.708183 50.098480 -2.012657 14749 39.789352 49.093582 -2.326363 14750 40.443481 49.902649 -1.335564 14751 2.503830 47.278214 -1.843842 14752 37.451096 47.941040 -3.375473 14753 38.135773 47.993042 -3.235519 14754 40.541656 48.189102 -2.143677 14755 39.753044 47.970032 -2.760986 14756 37.449463 47.350159 -3.588242 14757 1.824188 45.618439 -3.565689 14758 1.785339 44.749191 -3.709732 14759 2.016594 43.663666 -3.999290 14760 2.268799 44.109406 -3.184074 14761 3.036255 44.317261 -2.391373 14762 7.260040 42.649246 -3.405655 14763 7.416153 44.272614 -1.921783 14764 8.393303 42.921936 -2.926537 14765 45.274185 43.464020 -2.059990 14766 4.532089 43.708954 -2.491074 14767 10.159340 40.856934 -3.518189 14768 10.265198 41.754318 -2.828857 14769 45.617126 41.865845 -1.749725 14770 45.555664 42.829147 -1.787979 14771 10.838768 39.351624 -3.158295 14772 10.703308 39.963745 -3.525894 14773 10.858102 40.744843 -2.554634 14774 10.379829 39.612396 -2.099396 14775 46.886353 39.248566 -2.886414 14776 46.374893 39.231842 -2.461380 14777 46.647797 35.714355 -2.924866 14778 4.410820 36.694382 -3.641083 14779 5.622269 37.531189 -3.139786 14780 4.422371 38.617584 -2.568298 14781 9.198097 35.954056 -4.160355 14782 6.753914 36.586319 -3.448853 14783 7.547669 36.259857 -3.483963 14784 8.411407 36.402039 -3.414337 14785 9.309830 36.692352 -3.457954 14786 1.940514 35.012695 -2.751282 14787 2.180924 34.153381 -3.763374 14788 2.828865 35.820251 -3.664352 14789 46.394409 33.978561 -3.319412 14790 45.920868 34.086807 -2.832047 14791 46.061646 34.864716 -2.937195 14792 1.490204 30.969940 -4.575073 14793 46.656158 32.868591 -3.215698 14794 1.905693 33.463943 -2.835480 14795 1.851303 32.203171 -2.972061 14796 46.704254 31.283905 -3.743279 14797 50.875107 32.251572 -2.808289 14798 50.776047 32.628296 -2.494408 14799 50.503952 32.368423 -2.702179 14800 51.359375 32.462128 -2.173996 14801 51.484467 31.426605 -2.863312 14802 24.662323 31.657898 -3.590942 14803 26.407013 30.991302 -2.779182 14804 29.358414 31.468536 -3.380356 14805 29.229614 31.083694 -2.552788 14806 50.471649 31.713577 -2.760246 14807 50.902344 32.855286 -1.966003 14808 1.503731 30.332642 -3.450134 14809 1.258751 30.492371 -3.871475 14810 1.599350 31.277618 -3.545334 14811 1.268867 29.571304 -4.514770 14812 25.190697 31.237350 -2.951050 14813 27.363510 30.760712 -2.249458 14814 31.244637 30.962433 -2.957191 14815 30.219536 31.025208 -2.418106 14816 30.722008 30.277405 -2.284821 14817 32.250885 30.854874 -3.746704 14818 46.718552 30.552567 -3.363266 14819 50.738937 30.646790 -3.069611 14820 50.332504 30.065353 -2.897400 14821 50.786789 29.950394 -3.211044 14822 51.511765 29.957367 -3.197411 14823 52.239563 30.563461 -2.998985 14824 52.236115 29.891724 -3.134522 14825 51.922073 31.952087 -2.037903 14826 22.461716 29.373383 -3.717773 14827 27.527084 29.261780 -3.757858 14828 37.556091 28.549896 -2.650360 14829 37.666817 29.261017 -3.095169 14830 37.319565 29.644592 -4.017097 14831 39.293404 29.321701 -3.439209 14832 40.029541 28.640198 -3.734177 14833 52.528336 29.923538 -2.637680 14834 52.558517 30.666199 -2.624557 14835 22.766823 28.883850 -3.859230 14836 24.423889 29.428253 -3.436234 14837 23.298279 29.401535 -3.030869 14838 26.523766 29.632935 -3.043366 14839 25.473434 29.395813 -3.610184 14840 28.441238 29.537643 -2.785149 14841 33.435410 29.307755 -3.419815 14842 35.689682 29.097870 -4.026611 14843 47.821426 29.863159 -2.543900 14844 48.872040 29.306000 -2.414459 14845 48.627686 29.849182 -1.971390 14846 50.602631 29.391937 -2.979904 14847 52.152496 29.205109 -2.917831 14848 32.861076 27.980515 -3.925400 14849 49.638016 27.521729 -3.692993 14850 49.942032 27.849548 -3.292419 14851 0.416504 25.566788 -5.148743 14852 32.109772 27.695084 -4.263306 14853 40.395020 26.138474 -4.521027 14854 50.119080 26.946381 -3.522720 14855 49.604370 26.854752 -4.061951 14856 39.890709 26.622910 -3.689087 14857 39.385445 26.571045 -3.563133 14858 0.778007 25.867401 -4.494110 14859 51.337128 26.035339 -3.232208 14860 52.711990 24.703842 -2.845169 14861 50.001175 23.355072 -3.898483 14862 52.900620 25.770676 -2.576485 14863 1.881271 22.032227 -4.441986 14864 1.959694 21.228241 -4.697693 14865 49.146652 21.338715 -3.913940 14866 2.988617 19.366211 -3.970215 14867 26.069214 19.092865 -4.739357 14868 26.358444 19.056854 -3.723930 14869 29.285934 19.655762 -4.430466 14870 28.031448 19.971985 -3.505981 14871 48.403687 20.255737 -4.627350 14872 49.160370 20.247635 -3.220184 14873 49.313385 19.372772 -3.102325 14874 3.302788 17.923843 -4.742859 14875 25.712936 18.612000 -4.953445 14876 30.404343 18.804794 -4.419182 14877 29.885071 19.216721 -4.421280 14878 50.261154 19.360764 -1.966736 14879 50.571014 20.515823 -2.270142 14880 49.674683 20.046677 -2.635437 14881 27.830917 16.828735 -3.486084 14882 27.397041 17.213730 -3.482269 14883 26.502426 18.320282 -3.548515 14884 25.943420 18.655334 -4.333550 14885 33.857193 18.853531 -3.503334 14886 35.053040 19.188354 -3.055183 14887 36.714180 17.651428 -3.871155 14888 38.043518 18.969391 -2.872665 14889 39.336372 18.106812 -3.268616 14890 39.265579 17.205078 -4.126450 14891 39.763947 16.659821 -4.797974 14892 48.955429 17.134796 -3.943275 14893 49.519623 18.129272 -2.828491 14894 41.925385 16.183350 -4.252640 14895 40.626373 17.076187 -3.830017 14896 4.855354 15.293030 -5.358612 14897 30.348343 14.940201 -5.559273 14898 28.437111 15.785645 -4.889831 14899 31.244873 14.731537 -4.529495 14900 41.972626 16.827301 -3.131821 14901 44.225952 15.541260 -4.006058 14902 54.818726 15.598770 -4.073349 14903 29.743103 15.297150 -4.154755 14904 31.855181 14.405579 -2.782547 14905 31.397751 14.694046 -3.426636 14906 32.654449 14.285248 -3.349167 14907 33.233101 14.190308 -4.774071 14908 34.204041 13.841782 -4.624435 14909 44.649139 15.411346 -4.031227 14910 47.162704 15.160614 -3.580170 14911 47.904572 15.377747 -3.479614 14912 54.600677 14.049301 -3.219345 14913 5.015038 14.115417 -5.210701 14914 5.068062 12.912277 -5.071976 14915 35.815765 13.317154 -4.279297 14916 34.935623 13.477341 -4.803749 14917 50.528229 13.318771 -4.054802 14918 49.841858 13.029419 -4.509384 14919 5.300064 10.780838 -4.946625 14920 37.546951 12.050049 -4.800552 14921 36.811829 12.309097 -4.624618 14922 39.702576 10.869904 -4.378655 14923 40.646667 10.563568 -4.017685 14924 48.673813 10.834946 -4.824829 14925 5.694964 8.577660 -5.120331 14926 5.910770 8.150548 -4.916587 14927 42.329498 10.334869 -3.932899 14928 42.754303 10.062225 -4.065872 14929 5.256897 8.699646 -5.269035 14930 5.347763 9.137054 -5.192337 14931 5.494667 9.705841 -5.496567 14932 49.483704 6.759521 -3.670525 14933 49.770355 8.469711 -3.534561 14934 49.499115 7.559097 -3.603378 14935 57.687500 8.516571 -4.552185 14936 57.483704 9.224091 -3.886841 14937 58.146255 7.522964 -4.350266 14938 6.074621 6.827369 -4.155749 14939 47.942642 4.457443 -4.504059 14940 58.441010 7.192261 -3.778969 14941 11.369608 3.779750 -7.463227 14942 11.447458 3.845341 -7.525556 14943 11.672966 3.602599 -7.502344 14944 11.472824 3.726455 -7.473104 14945 40.770340 5.402084 -4.614242 14946 48.256454 4.386200 -4.186905 14947 11.316759 3.709451 -7.395607 14948 59.589523 3.323235 -4.686012 14949 59.342590 4.360641 -4.030396 14950 6.723991 2.524823 -3.662923 14951 6.319005 3.946275 -3.462188 14952 8.726872 2.216283 -5.452740 14953 9.118247 1.372410 -5.612404 14954 40.228546 1.724075 -5.312958 14955 8.397003 0.874339 -5.025211 14956 46.580246 0.566666 -4.290604 14957 45.867981 0.368423 -4.212158 14958 45.688019 0.404922 -4.400574 14959 59.948318 1.677063 -4.819809 14960 40.505585 0.769592 -5.655426 14961 45.161865 0.499069 -5.105987 14962 59.902069 0.029816 -4.798660 14963 60.256409 0.832184 -4.093948 14964 40.635117 0.774857 -5.173859 14965 40.631668 0.849960 -4.263367 14966 45.535278 -1.573059 -4.748154 14967 59.246597 -1.201080 -5.051826 14968 58.653351 -1.524506 -3.951195 14969 59.359360 -0.749069 -3.725830 14970 59.576874 -0.866058 -4.259872 14971 46.242355 -2.556686 -4.438492 14972 58.211899 -2.297668 -4.816543 14973 6.769016 -6.077716 -3.750956 14974 10.250819 -4.511480 -7.022444 14975 10.677178 -4.666032 -7.326085 14976 10.444804 -5.003262 -7.266004 14977 19.611927 -2.600282 -9.409319 14978 19.519424 -3.286427 -9.567015 14979 39.347519 -4.984283 -5.926453 14980 39.475784 -4.059525 -5.572815 14981 57.486877 -3.236511 -5.654991 14982 57.012802 -3.045761 -4.370750 14983 6.330905 -4.886002 -2.911012 14984 10.210093 -5.626230 -7.225240 14985 21.360874 -3.369022 -9.892879 14986 56.721832 -3.727219 -5.117241 14987 60.414124 -5.163406 -4.705368 14988 61.390579 -5.472763 -4.555443 14989 59.613922 -5.074646 -4.693626 14990 19.581978 -3.798743 -9.706053 14991 21.833374 -3.878550 -10.141512 14992 21.883171 -4.264347 -10.251294 14993 21.997528 -4.434322 -10.321707 14994 40.214172 -6.407181 -6.385094 14995 53.285904 -7.816010 -5.884903 14996 58.312119 -5.824249 -4.582947 14997 61.884628 -6.159103 -4.890869 14998 62.379257 -6.500229 -4.586853 14999 62.174667 -6.816406 -5.124260 15000 19.886757 -4.605719 -9.960110 15001 20.661816 -5.539131 -10.345064 15002 21.118544 -4.167188 -10.061848 15003 20.475073 -4.644561 -10.069891 15004 21.146112 -5.092414 -10.320797 15005 21.677568 -5.412663 -10.526720 15006 21.812126 -4.919908 -10.422096 15007 21.877398 -4.611405 -10.344790 15008 40.279037 -6.999588 -6.108719 15009 39.525803 -7.046875 -5.443260 15010 39.188164 -5.978760 -5.352936 15011 41.285156 -7.749695 -5.938164 15012 40.277527 -8.106506 -5.703735 15013 42.468689 -7.095215 -5.600876 15014 43.527405 -7.732880 -4.932983 15015 56.113174 -3.732193 -4.205795 15016 6.224853 -6.530944 -2.949519 15017 5.928498 -7.142051 -2.414008 15018 22.084217 -5.465489 -10.640150 15019 41.060867 -8.676025 -5.761467 15020 16.548450 -7.029460 -9.981060 15021 40.530731 -9.559616 -5.219955 15022 39.325836 -8.335480 -4.501266 15023 39.268967 -10.051285 -4.042191 15024 42.101944 -8.861862 -5.362862 15025 57.338379 -6.956528 -3.462799 15026 55.653458 -8.242844 -2.210907 15027 6.475530 -10.079532 -3.707999 15028 60.809143 -9.371780 -5.254486 15029 7.082267 -12.011312 -4.776100 15030 52.334503 -10.531235 -5.556885 15031 52.638504 -10.825607 -5.387955 15032 60.362778 -10.788040 -5.469818 15033 60.300659 -11.687042 -5.004204 15034 6.850203 -12.828914 -4.171065 15035 59.443665 -13.601425 -4.976959 15036 59.755585 -12.425446 -5.125427 15037 58.225418 -14.488678 -5.291626 15038 58.841446 -16.392197 -4.748810 15039 59.295334 -15.322769 -4.937546 15040 54.964264 -14.894730 -5.048584 15041 56.014618 -14.865723 -5.112755 15042 55.749664 -14.269775 -5.858093 15043 64.619934 -14.131500 -5.767090 15044 6.659127 -13.472154 -3.519879 15045 21.860083 -14.598984 -5.262529 15046 48.302155 -16.728180 -5.130203 15047 47.727814 -16.992340 -4.849533 15048 50.444107 -16.325516 -4.600098 15049 51.309036 -15.787506 -5.708053 15050 52.761078 -15.362762 -5.842651 15051 6.748789 -15.035436 -2.986365 15052 6.461056 -14.785940 -2.349032 15053 6.676852 -15.972938 -2.110536 15054 63.724136 -15.790741 -6.042175 15055 7.662665 -16.805386 -4.028478 15056 46.492889 -17.584122 -6.976074 15057 63.410370 -16.791595 -6.054878 15058 66.005600 -17.414597 -5.233978 15059 64.569351 -17.887238 -5.158638 15060 64.292435 -19.933060 -5.052933 15061 63.245392 -19.270569 -5.555885 15062 23.977571 -22.584332 -8.280054 15063 23.631145 -22.094528 -8.613804 15064 23.250402 -22.914843 -7.948660 15065 24.637571 -22.536110 -8.372713 15066 51.377014 -20.859055 -6.665092 15067 51.070999 -22.361328 -6.211410 15068 66.132263 -20.555527 -4.973350 15069 66.143967 -22.279694 -4.745712 15070 64.481232 -22.074646 -4.650268 15071 8.074224 -17.830339 -4.042022 15072 22.225241 -22.491776 -8.193263 15073 21.364876 -23.010504 -7.703501 15074 22.413645 -23.274189 -7.586734 15075 25.353132 -22.905148 -8.140839 15076 53.366791 -21.371414 -6.611023 15077 54.306274 -20.985397 -6.804031 15078 52.269440 -22.060196 -6.341614 15079 61.367661 -21.960190 -5.674652 15080 67.266876 -19.762497 -5.682381 15081 67.918335 -20.971054 -6.429726 15082 19.722082 -23.215008 -7.405560 15083 20.508017 -23.238844 -7.452943 15084 24.917356 -23.730289 -7.435008 15085 55.248154 -21.588943 -6.711059 15086 56.206619 -22.636414 -6.393906 15087 67.225372 -21.437805 -5.440407 15088 8.446860 -18.851830 -3.838301 15089 19.100864 -23.479696 -7.109037 15090 27.915621 -24.624346 -7.005456 15091 53.372208 -22.906372 -6.126724 15092 54.421112 -22.369003 -6.301544 15093 55.265320 -22.500977 -6.314163 15094 58.325165 -24.357788 -5.539078 15095 25.387989 -24.254814 -7.042961 15096 26.287121 -24.814375 -6.656095 15097 55.984650 -24.254639 -5.567490 15098 55.215851 -23.381821 -5.953918 15099 67.064636 -22.584808 -5.198807 15100 27.159620 -24.798836 -6.768680 15101 29.308462 -25.686359 -6.283230 15102 30.278084 -25.947241 -6.197972 15103 34.092613 -25.810795 -7.046051 15104 34.421028 -26.031208 -6.929675 15105 67.333038 -25.156830 -5.853760 15106 67.392258 -24.211823 -5.647980 15107 16.939034 -24.715532 -5.347035 15108 16.376106 -25.085112 -4.674496 15109 17.161678 -25.691362 -4.212011 15110 28.120958 -26.950974 -5.012485 15111 28.415419 -26.032713 -5.861838 15112 27.240919 -25.760775 -5.950918 15113 31.339966 -26.066277 -6.275603 15114 31.333429 -25.508512 -6.766146 15115 29.252502 -26.692469 -5.388825 15116 32.242729 -25.678923 -6.783161 15117 36.264435 -25.549927 -7.760330 15118 35.084618 -26.125250 -7.021769 15119 9.867155 -21.172415 -3.865694 15120 10.644066 -21.826502 -4.258827 15121 11.317513 -22.196325 -4.643902 15122 15.455743 -24.348284 -5.204964 15123 32.084454 -26.346401 -6.158212 15124 33.004124 -26.039133 -6.609984 15125 35.376789 -26.716644 -6.651629 15126 35.997841 -26.411514 -7.285705 15127 35.855896 -27.024704 -6.614357 15128 36.412674 -27.053192 -7.319466 15129 66.545975 -26.669128 -6.712784 15130 12.401233 -23.178339 -4.534417 15131 13.424431 -23.986771 -4.340878 15132 13.442922 -23.491886 -5.061906 15133 22.772812 -27.764801 -7.417953 15134 23.712563 -27.476318 -7.674225 15135 24.613068 -27.491211 -7.764130 15136 31.069624 -26.725761 -5.630122 15137 66.027008 -27.565857 -7.172958 15138 66.442780 -27.455383 -6.731644 15139 66.612183 -27.453873 -5.836090 15140 14.223122 -23.894346 -5.113511 15141 14.911737 -24.171478 -5.145404 15142 18.994255 -28.330795 -7.329269 15143 26.248779 -28.650284 -7.742737 15144 65.970993 -28.192032 -7.285141 15145 66.770660 -26.063934 -5.457886 15146 66.246506 -26.876801 -4.389603 15147 66.950409 -28.807495 -5.666199 15148 27.531357 -29.833130 -7.649185 15149 36.308067 -29.397003 -6.651092 15150 67.162247 -29.860535 -6.566376 15151 67.321564 -29.464844 -5.803406 15152 25.821014 -29.554703 -7.069221 15153 29.384583 -30.672913 -7.783676 15154 30.232254 -31.910599 -7.296966 15155 32.963387 -32.229828 -7.802338 15156 32.273682 -32.606064 -7.409714 15157 35.763550 -31.285522 -5.345390 15158 35.740738 -32.316238 -5.198028 15159 67.447662 -31.105347 -6.463394 15160 67.065552 -31.137955 -5.457611 15161 16.292259 -35.427490 -8.071075 15162 15.485855 -35.056015 -7.529739 15163 35.744156 -33.416901 -7.574608 15164 36.030594 -34.331924 -6.495064 15165 35.368286 -33.923355 -7.627670 15166 17.215988 -35.648895 -8.774620 15167 34.825737 -34.237610 -7.312210 15168 35.581818 -34.306808 -7.289825 15169 67.672333 -34.853058 -6.949081 15170 25.089317 -37.444626 -8.008797 15171 24.254051 -38.087311 -7.580765 15172 18.699097 -38.186707 -8.468781 15173 20.159767 -39.417389 -7.784042 15174 19.404922 -40.666031 -7.012878 15175 20.854111 -40.010391 -7.155319 15176 22.553490 -36.941437 -8.034088 15177 25.722946 -38.334106 -7.565056 15178 29.618332 -38.267303 -7.930595 15179 30.212494 -38.504013 -7.899048 15180 32.772644 -38.504654 -8.723450 15181 67.638443 -36.019073 -7.245834 15182 20.041870 -38.183701 -8.382767 15183 21.485504 -37.480682 -8.124237 15184 29.588516 -39.585999 -6.939094 15185 29.972679 -41.000839 -5.607132 15186 30.929932 -41.025467 -5.650726 15187 31.587296 -39.284897 -7.545792 15188 33.578545 -41.073669 -7.721611 15189 32.696884 -40.940826 -6.785919 15190 33.380524 -42.112350 -6.626373 15191 67.515732 -36.856934 -7.333420 15192 19.066689 -39.236023 -8.056290 15193 32.804718 -40.196167 -7.381119 15194 33.110809 -39.696747 -8.022514 15195 66.879807 -36.797256 -6.567436 15196 18.048927 -39.799057 -7.441170 15197 18.226044 -40.662796 -6.924713 15198 61.795959 -38.740723 -6.741501 15199 64.151672 -38.750092 -7.102539 15200 64.999344 -38.822159 -6.923424 15201 66.295914 -38.819748 -7.375717 15202 65.765137 -38.479401 -6.729202 15203 55.806076 -39.904846 -7.492409 15204 56.982590 -39.596268 -7.550354 15205 58.119263 -39.462784 -7.800140 15206 59.209320 -39.349442 -7.694374 15207 24.356659 -43.059235 -8.821434 15208 54.117294 -41.806763 -7.623810 15209 23.427414 -43.869720 -8.841522 15210 28.328476 -43.330811 -8.428917 15211 30.414139 -44.958557 -7.657623 15212 33.521019 -43.149139 -7.284454 15213 33.778015 -42.245728 -7.286674 15214 23.938965 -44.193573 -8.638603 15215 31.483978 -44.880127 -7.644722 15216 23.324387 -45.051727 -9.053112 15217 54.803467 -43.489227 -6.801201 15218 55.723709 -43.767609 -5.940628 15219 24.051292 -45.933105 -9.036469 15220 24.502686 -44.701782 -8.637505 15221 25.247337 -45.850769 -8.750908 15222 25.990631 -47.741776 -8.910431 15223 27.018036 -45.307404 -8.182404 15224 27.651588 -47.203201 -8.247528 15225 48.269302 -47.640198 -8.125229 15226 48.187866 -48.901764 -8.002090 15227 47.571960 -48.742157 -7.282158 15228 48.236923 -46.901062 -7.329842 15229 49.142639 -46.870056 -7.971008 15230 50.127930 -46.815231 -7.611038 15231 50.618423 -46.745544 -8.343819 15232 59.105179 -46.142349 -7.686355 15233 58.131744 -45.191635 -6.945473 15234 60.406738 -46.719727 -7.908043 15235 61.049332 -47.266922 -7.277939 15236 27.349373 -48.148651 -8.670013 15237 28.347122 -48.876236 -8.244522 15238 27.001266 -49.023087 -8.879906 15239 50.962769 -47.050232 -7.922516 15240 51.862610 -47.713455 -8.019760 15241 61.849960 -47.855530 -7.178909 15242 25.539017 -50.412033 -9.181763 15243 26.239624 -51.497986 -9.026985 15244 25.391678 -52.105576 -8.899391 15245 48.620438 -49.588608 -8.271652 15246 53.884125 -49.382751 -7.687607 15247 53.035736 -48.820831 -7.419319 15248 62.869446 -49.629715 -8.269310 15249 62.732849 -49.819489 -7.777100 15250 27.240295 -50.058441 -8.868736 15251 26.863556 -51.043747 -8.972778 15252 27.898743 -51.069199 -8.425568 15253 49.609512 -51.163757 -8.019356 15254 56.045547 -50.455292 -8.517044 15255 56.079117 -50.678665 -7.417824 15256 57.085205 -50.995041 -8.270065 15257 62.344421 -50.772705 -6.916511 15258 62.687561 -49.377670 -7.035873 15259 24.466530 -51.638077 -9.137676 15260 24.550545 -52.094254 -8.945602 15261 27.511856 -52.960968 -8.235725 15262 28.665176 -52.214508 -7.605225 15263 50.419891 -51.595428 -8.319412 15264 57.280350 -51.215546 -7.142700 15265 58.408936 -51.574585 -8.026978 15266 26.721878 -52.190033 -8.754379 15267 49.139587 -51.102234 -7.132622 15268 48.227036 -50.221298 -6.915993 15269 59.478348 -51.920700 -6.930633 15270 61.712677 -51.595840 -6.260712 15271 24.235474 -52.620728 -9.303226 15272 37.431839 -54.627533 -8.637398 15273 37.605377 -54.514038 -8.224594 15274 37.745102 -54.053329 -8.077133 15275 38.149551 -53.774551 -8.092407 15276 39.700638 -53.858429 -8.130371 15277 53.293793 -53.386978 -8.669571 15278 23.042252 -54.983704 -9.567009 15279 23.421021 -55.231155 -9.241787 15280 41.523651 -55.268311 -8.753342 15281 56.194550 -54.996780 -7.450523 15282 23.545006 -55.788345 -9.181328 15283 37.793625 -57.668549 -7.799591 15284 37.914230 -56.690582 -6.508980 15285 43.056931 -56.249649 -8.695282 15286 58.492599 -56.894653 -8.603813 15287 23.679382 -60.600662 -10.234932 15288 45.409332 -56.833969 -8.783295 15289 46.415527 -56.835098 -8.207672 15290 47.297119 -57.197250 -8.138298 15291 48.354095 -57.441910 -8.686783 15292 48.460510 -57.780334 -7.346023 15293 49.169312 -57.613663 -8.139816 15294 49.240143 -57.658493 -9.007545 15295 50.255341 -58.066788 -8.572899 15296 58.090897 -57.137466 -7.647476 15297 57.570816 -58.359940 -7.799393 15298 24.364891 -58.544571 -9.468651 15299 24.055229 -59.603424 -9.841515 15300 25.075706 -60.469955 -9.371181 15301 23.714203 -62.575668 -10.369339 15302 24.290848 -61.573761 -9.888805 15303 43.392807 -60.745117 -8.168930 15304 46.626312 -60.939560 -7.755585 15305 45.729309 -60.656662 -7.937233 15306 25.162537 -62.662216 -9.468037 15307 24.096313 -63.620239 -10.087219 15308 25.148537 -63.942337 -9.318634 15309 42.042267 -60.703049 -7.533943 15310 40.968109 -60.844238 -6.878860 15311 40.711227 -61.847931 -7.696075 15312 23.529236 -64.577972 -10.439022 15313 24.843979 -65.262115 -8.989761 15314 23.649384 -66.065170 -10.078350 15315 24.211304 -64.646057 -9.822884 15316 35.801285 -64.303207 -9.720459 15317 37.080971 -61.424728 -8.463242 15318 37.028839 -60.671555 -7.181999 15319 48.186996 -61.060379 -7.117134 15320 49.451630 -62.358780 -8.600983 15321 51.380737 -62.826279 -8.559189 15322 35.372437 -64.888138 -9.565735 15323 38.873123 -65.653397 -9.424011 15324 54.341110 -63.692932 -8.402451 15325 54.035858 -62.060852 -7.721062 15326 53.589020 -65.994400 -9.112160 15327 54.167480 -65.002930 -8.773445 15328 35.145454 -65.417023 -9.753899 15329 37.712296 -64.156464 -7.597755 15330 44.605484 -66.400192 -9.046066 15331 23.511002 -67.252808 -9.865082 15332 34.736588 -67.046371 -9.468666 15333 37.715668 -67.203964 -9.169868 15334 37.180649 -66.492310 -8.660248 15335 37.657776 -68.701813 -9.782303 15336 42.416214 -67.540283 -8.633698 15337 41.391113 -68.828888 -8.028374 15338 41.711121 -67.394516 -7.444252 15339 45.494904 -67.234543 -8.772102 15340 45.995331 -69.341217 -8.624115 15341 45.261566 -68.046585 -8.156708 15342 42.472534 -71.138123 -9.338215 15343 46.624954 -69.073792 -9.519714 15344 51.911682 -68.366730 -8.867790 15345 17.301270 -70.359985 -9.403881 15346 18.740860 -69.678589 -6.806930 15347 16.686409 -70.078659 -6.670288 15348 24.583847 -69.271759 -9.986408 15349 28.605667 -70.315628 -10.580929 15350 34.538780 -68.420013 -9.594193 15351 34.685425 -69.375900 -9.426029 15352 20.475594 -71.565079 -10.308533 15353 20.887955 -72.594162 -9.413609 15354 20.421806 -71.422775 -9.093422 15355 34.771759 -70.633713 -9.784359 15356 40.293991 -69.436646 -7.012421 15357 40.309113 -68.279648 -6.860001 15358 49.296417 -70.586533 -9.439926 15359 15.624893 -72.570587 -10.349590 15360 21.197968 -73.033386 -10.387455 15361 42.651611 -72.215988 -9.364681 15362 48.359161 -71.053635 -9.219337 15363 49.126923 -71.187744 -8.328316 15364 28.649246 -71.976120 -10.447853 15365 27.854172 -71.976349 -10.111969 15366 35.187057 -74.134445 -10.532799 15367 37.910995 -73.055389 -9.943672 15368 16.673462 -74.293961 -10.425140 15369 16.159332 -73.512177 -10.261414 15370 24.899689 -74.028259 -9.705894 15371 34.885406 -75.402679 -10.289371 15372 38.506546 -73.743958 -10.499931 15373 44.415787 -74.234070 -10.390854 15374 43.350174 -74.002975 -9.613182 15375 42.045837 -73.044937 -8.569176 15376 41.678040 -71.905289 -8.561531 15377 42.211151 -72.068558 -9.080582 15378 16.805977 -74.816269 -10.426918 15379 38.798523 -76.047913 -10.363976 15380 21.307434 -77.066147 -10.627758 15381 21.526009 -76.419052 -10.362717 15382 38.566734 -76.632935 -9.971069 15383 45.819855 -77.107361 -9.992992 15384 10.411346 -77.802399 -9.608517 15385 11.354942 -78.144547 -10.636147 15386 26.783096 -77.046921 -9.604813 15387 27.679382 -76.901093 -8.705055 15388 27.600082 -77.619553 -9.486038 15389 27.151886 -77.964706 -9.855659 15390 32.723541 -78.879974 -10.898926 15391 46.542465 -78.682281 -10.319096 15392 46.394516 -77.974854 -9.164082 15393 25.334991 -79.901596 -9.981281 15394 26.406693 -78.711609 -9.729935 15395 26.197693 -77.836792 -10.337738 15396 26.735306 -77.929047 -10.089966 15397 33.838913 -78.167786 -10.460476 15398 34.466202 -77.061035 -9.886517 15399 36.621719 -78.527939 -10.560146 15400 37.434532 -78.020004 -10.253159 15401 10.661232 -79.086517 -10.572731 15402 10.211777 -80.045624 -10.257477 15403 33.594131 -79.370941 -10.806572 15404 34.542130 -78.848038 -10.490467 15405 34.921295 -77.955353 -9.780296 15406 46.612549 -79.444031 -8.993042 15407 46.343018 -80.207413 -10.307953 15408 10.515472 -81.190002 -10.678703 15409 15.051651 -81.398773 -10.615654 15410 25.338959 -80.387466 -8.792961 15411 25.161804 -80.976379 -9.687164 15412 32.790825 -80.024582 -10.946136 15413 32.801521 -79.569504 -10.659248 15414 24.762482 -81.894348 -10.547356 15415 10.496559 -82.712067 -11.268734 15416 19.226593 -82.732483 -11.027740 15417 46.769608 -80.340805 -5.228851 15418 47.041611 -79.935776 -6.171989 15419 46.299866 -80.982178 -5.973434 15420 44.305237 -83.046585 -10.089684 15421 43.060562 -83.782516 -10.824638 15422 8.299744 -83.149261 -9.898682 15423 7.674209 -83.477509 -10.387482 15424 8.514320 -83.963623 -10.768387 15425 9.431870 -84.914963 -10.833370 15426 9.106903 -83.794174 -9.810616 15427 10.861511 -83.143219 -11.279701 15428 12.511642 -83.943100 -9.605034 15429 11.667664 -83.446396 -10.417435 15430 35.623116 -84.415924 -10.755482 15431 36.114227 -83.647003 -10.443043 15432 35.959366 -83.452728 -9.753540 15433 36.522583 -83.023865 -9.764465 15434 41.039093 -83.532913 -10.501835 15435 41.252487 -83.951721 -10.994308 15436 41.846390 -83.755234 -10.503220 15437 7.978820 -84.528992 -11.070034 15438 8.563477 -84.700684 -11.211601 15439 8.373215 -85.744354 -11.168938 15440 9.722687 -84.327286 -9.915092 15441 21.765663 -84.359024 -10.810612 15442 26.356117 -85.745956 -11.243816 15443 24.965599 -82.662537 -10.651144 15444 35.971718 -84.257202 -9.614113 15445 35.718750 -83.873413 -10.125351 15446 41.476685 -83.215759 -9.600582 15447 43.006363 -84.282471 -11.694195 15448 45.403656 -82.018936 -9.295094 15449 7.590942 -86.568954 -10.270084 15450 8.357162 -87.053268 -10.916439 15451 9.458771 -86.339066 -11.393085 15452 13.352470 -85.647156 -11.011700 15453 22.327187 -84.676544 -10.130779 15454 26.664955 -84.365860 -9.731560 15455 35.065979 -85.673416 -11.559479 15456 35.693100 -85.613708 -11.022987 15457 8.850876 -86.825577 -11.364723 15458 9.497940 -88.083298 -11.055038 15459 10.365204 -86.866318 -11.493473 15460 10.197282 -85.900970 -11.141083 15461 13.929260 -86.192062 -11.295280 15462 26.969009 -85.766556 -10.499969 15463 10.951852 -86.246124 -10.978436 15464 11.205276 -87.143784 -11.531456 15465 39.630440 -88.232208 -11.063271 15466 11.310181 -89.658417 -11.327496 15467 12.839844 -89.606323 -11.565189 15468 13.158791 -88.899033 -11.168442 15469 39.378975 -88.456284 -11.497219 15470 13.609940 -90.001785 -11.009308 15471 21.836075 -89.855591 -11.425087 15472 30.607086 -88.971268 -10.250271 15473 12.744522 -90.338699 -11.445255 15474 20.473534 -90.135910 -10.901428 15475 12.077301 -90.940567 -10.954468 15476 11.055656 -90.786255 -10.159809 15477 11.526733 -91.392349 -10.007271 15478 13.115105 -90.942764 -11.107182 15479 19.195618 -90.721649 -10.606133 15480 19.908325 -91.584732 -11.082535 15481 21.460449 -89.220779 -9.691772 15482 20.622101 -88.891541 -9.854641 15483 18.775612 -89.718521 -10.375450 15484 18.370338 -90.548874 -9.913177 15485 34.861099 -90.434097 -11.260040 15486 36.164948 -90.561829 -11.484528 15487 36.989868 -90.499207 -10.421341 15488 39.358078 -90.173981 -9.864769 15489 20.435204 -91.581024 -11.880592 15490 20.998596 -92.733154 -11.572701 15491 32.952911 -92.723587 -11.646866 15492 35.014008 -92.342255 -9.944630 15493 35.355194 -91.845947 -8.667725 15494 33.764351 -92.201813 -9.655708 15495 19.116852 -93.884323 -12.783287 15496 18.322685 -94.011154 -12.475014 15497 22.012756 -93.533081 -10.819962 15498 22.202728 -93.399704 -11.745483 15499 20.937881 -93.109009 -10.060062 15500 22.611343 -94.524353 -11.336231 15501 29.954071 -92.543732 -10.958363 15502 28.957146 -92.488846 -10.766972 15503 29.481339 -92.101074 -9.264507 15504 31.549576 -92.262039 -10.039371 15505 32.847092 -92.481476 -10.979031 15506 33.703445 -92.837067 -11.308907 15507 33.637375 -95.443619 -11.430843 15508 34.573013 -95.452042 -10.110741 15509 16.192841 -94.663742 -11.845303 15510 15.475853 -95.195816 -11.942852 15511 16.914917 -94.582809 -11.709118 15512 18.116753 -94.550079 -11.722363 15513 17.471176 -95.170670 -10.178848 15514 18.902725 -95.104080 -11.058754 15515 19.075089 -95.328476 -10.198742 15516 18.971741 -94.790573 -11.701782 15517 22.506104 -95.057449 -11.539948 15518 14.734619 -95.482742 -10.724655 15519 16.058327 -94.978165 -11.021809 15520 20.057800 -95.318481 -10.946907 15521 14.551636 -96.432037 -11.764275 15522 13.689354 -96.594925 -10.258278 15523 22.328217 -95.212952 -11.675011 15524 28.177666 -97.970123 -12.077187 15525 28.780533 -97.529755 -11.999649 15526 32.045334 -96.656235 -10.179932 15527 31.876070 -96.410843 -11.448055 15528 30.238625 -97.586945 -9.814777 15529 16.936615 -101.092941 -11.814255 15530 25.857040 -100.032730 -11.870258 15531 25.683144 -100.208588 -11.026134 15532 22.467133 -100.288742 -11.393639 15533 18.024918 -101.830231 -11.548315 15534 19.439362 -101.696396 -12.288860 15535 20.626434 -101.707809 -11.444736 15536 21.845413 -100.209976 -10.768501 15537 6.903099 62.740372 -1.200356 15538 5.802048 62.356705 -1.405518 15539 5.887802 61.964035 -0.377334 15540 13.280624 62.283539 1.052254 15541 3.599922 60.562195 -1.060982 15542 18.295212 60.224686 -1.486313 15543 20.246643 58.886215 -0.841705 15544 19.681610 60.383759 0.279892 15545 3.389298 60.246521 -1.151611 15546 14.891785 57.955200 -1.823402 15547 15.355942 58.557083 -1.357239 15548 21.090668 58.846710 0.027351 15549 3.564049 58.529816 -1.292641 15550 15.722473 57.630096 -2.137283 15551 3.502678 57.444077 -1.132797 15552 3.383957 56.634033 -0.853462 15553 4.268501 51.879883 -1.343010 15554 6.020622 51.393921 -2.195244 15555 5.469215 53.272949 -1.632095 15556 7.445320 56.381851 -2.295944 15557 7.302155 55.456390 -2.014969 15558 6.011810 55.078033 -1.841919 15559 7.017181 54.973740 -1.641495 15560 3.473785 55.809784 -0.729057 15561 4.036278 54.634277 -0.871124 15562 6.952957 54.596344 -1.591080 15563 7.452858 54.533081 -1.738892 15564 19.546722 55.786835 -1.714989 15565 19.726807 54.685913 -1.397316 15566 33.495667 53.110077 -1.091736 15567 32.271317 53.402145 -1.238998 15568 6.884308 53.909103 -1.722122 15569 7.094772 52.643372 -2.056030 15570 7.131096 51.772507 -2.164963 15571 19.948059 53.894104 -1.305931 15572 28.779785 52.811066 -2.050339 15573 36.247208 51.988312 -1.174469 15574 34.892929 52.569473 -1.190140 15575 3.743309 52.906204 -0.383407 15576 7.228722 51.269943 -2.341942 15577 7.668426 50.800262 -2.704681 15578 27.775764 51.849274 -2.057404 15579 28.901810 51.796692 -1.537964 15580 3.957901 50.194946 -1.823196 15581 3.153061 50.653839 0.326050 15582 7.033875 50.633026 -2.589920 15583 26.927185 51.031357 -2.126846 15584 27.905952 50.524231 -1.458206 15585 21.863602 49.541901 -1.395721 15586 24.457520 48.074615 -1.218582 15587 26.611130 50.264252 -1.957748 15588 40.228729 51.546478 0.202133 15589 41.338303 50.262939 -0.171059 15590 25.422768 48.971436 -1.649315 15591 26.670982 49.477661 -1.500511 15592 26.459679 48.653091 -1.123039 15593 28.126373 48.591232 -0.663940 15594 2.929840 49.636597 -0.968460 15595 2.522247 48.718903 -0.968506 15596 25.761436 48.116074 -1.149796 15597 41.864975 48.436768 -0.792847 15598 41.374741 47.263672 -2.208466 15599 41.961914 49.636475 0.082153 15600 2.213951 45.492828 -2.689758 15601 5.769211 43.970215 -2.282394 15602 5.403526 44.319504 -1.812866 15603 5.885086 43.406189 -2.854355 15604 10.911285 46.632538 0.899368 15605 11.213998 45.766586 0.377159 15606 10.042831 46.155228 0.063927 15607 9.621811 42.931152 -2.448090 15608 43.582047 44.963959 0.562080 15609 43.733459 45.729919 -0.491852 15610 44.214310 44.258759 -0.192528 15611 5.617386 47.556915 0.848816 15612 8.102074 47.140411 0.448570 15613 5.783127 45.936050 -0.431168 15614 11.068497 42.232178 -1.652252 15615 11.351631 41.867676 -0.729027 15616 10.797173 41.184296 -1.140823 15617 10.637642 43.482788 -1.620667 15618 46.365677 41.133652 -2.381165 15619 45.817291 40.320816 -1.962631 15620 45.743240 39.343445 -2.149811 15621 44.980804 39.405212 -1.895538 15622 1.927765 37.354248 -2.340591 15623 2.394966 37.089417 -2.961823 15624 2.506149 38.200775 -2.480774 15625 3.356407 37.648727 -3.019318 15626 3.277207 38.867249 -2.374863 15627 6.682572 37.929016 -2.759766 15628 5.744812 39.051910 -2.213142 15629 44.218628 38.047882 -2.064209 15630 43.040268 39.080917 -1.668213 15631 43.955017 39.542236 -1.562256 15632 42.004257 39.823593 -1.307312 15633 42.103210 38.573120 -1.808754 15634 45.699677 38.264801 -2.351936 15635 46.418823 38.351227 -2.637970 15636 1.854706 38.167877 -1.808250 15637 7.634765 37.090790 -3.008362 15638 4.683327 39.936188 -1.730469 15639 5.566017 40.018768 -1.615082 15640 5.358521 41.054367 -0.607513 15641 7.552605 38.174622 -2.397781 15642 9.179932 37.409027 -2.914360 15643 8.399864 37.033875 -2.935486 15644 9.221550 38.859039 -2.029236 15645 8.360817 37.825897 -2.490166 15646 41.783646 37.357452 -1.921295 15647 40.515060 38.924316 -1.397888 15648 40.811127 37.551422 -1.607605 15649 42.961121 37.588409 -2.039490 15650 43.859177 36.026688 -2.030685 15651 42.547394 35.994553 -1.898445 15652 1.951767 36.350037 -2.530830 15653 40.924011 36.623718 -1.589401 15654 41.839020 36.398834 -1.929047 15655 44.929474 33.729843 -0.594475 15656 44.209808 33.717773 -0.333664 15657 43.707855 34.047607 -0.352478 15658 45.378693 36.052521 -2.426186 15659 41.649429 35.835693 -1.687866 15660 41.706360 35.020874 -1.211273 15661 43.244873 34.622101 -1.192139 15662 46.233734 32.934387 -2.553032 15663 50.295959 32.461044 -2.169365 15664 50.552536 33.103897 -1.556686 15665 52.298065 31.274765 -2.340446 15666 24.232010 31.329346 -3.003777 15667 23.401848 30.834015 -2.898087 15668 30.123825 31.361435 -2.936073 15669 31.552933 31.228088 -3.679825 15670 45.858063 34.575989 0.587387 15671 46.431641 33.575485 0.125954 15672 46.801651 32.267242 -1.350647 15673 46.724564 31.850586 -3.116684 15674 49.549408 31.930267 -1.743698 15675 50.036682 32.846756 -1.458061 15676 49.991150 31.737518 -2.339722 15677 24.235344 30.475708 -2.606667 15678 29.838638 30.721008 -2.080917 15679 29.076477 30.394730 -2.089233 15680 28.284119 30.818726 -2.287369 15681 46.730621 31.568588 -2.474716 15682 47.199860 30.892593 -2.254410 15683 49.951843 30.918213 -2.398911 15684 52.530212 30.706268 -1.970886 15685 2.214913 29.410767 -3.385498 15686 22.725662 30.160416 -3.100052 15687 22.715347 29.470871 -2.944756 15688 23.078316 30.135986 -2.666779 15689 27.382759 29.543350 -3.022697 15690 32.267128 29.929413 -2.939713 15691 38.488953 29.193741 -2.760391 15692 49.565384 29.842194 -2.295853 15693 52.587570 29.669662 -1.580765 15694 2.402145 28.052124 -3.554565 15695 1.710892 26.688431 -4.058563 15696 0.676537 26.503998 -4.558090 15697 4.179924 26.976074 -3.432884 15698 4.288262 28.596390 -3.131790 15699 5.121681 27.274475 -3.449669 15700 5.512657 28.617401 -3.133904 15701 6.026932 28.262421 -2.995461 15702 5.427742 28.086594 -3.306534 15703 22.587296 28.814056 -3.376221 15704 22.524567 28.926682 -3.142532 15705 22.809303 28.816467 -3.185852 15706 27.310135 29.971115 -2.456696 15707 27.946777 30.356659 -2.106949 15708 27.265167 30.411346 -2.045509 15709 32.711342 28.547424 -3.214317 15710 35.604324 28.788223 -3.765183 15711 37.873642 28.898590 -2.147240 15712 38.500244 28.835709 -2.114754 15713 39.232918 28.523071 -2.738388 15714 39.649536 27.473175 -3.105545 15715 48.487030 32.224731 -1.074371 15716 48.059662 30.773041 -1.708962 15717 49.792587 28.733154 -2.902222 15718 50.641754 28.693207 -2.948196 15719 51.348633 28.818085 -2.979843 15720 52.489441 28.759460 -2.201714 15721 51.992523 27.905823 -2.717529 15722 52.506775 27.861237 -2.214661 15723 5.793999 27.521393 -3.191650 15724 5.715271 26.680664 -3.259583 15725 6.299370 27.444000 -2.255257 15726 5.609978 27.049637 -1.004646 15727 5.851372 26.006210 -1.953537 15728 22.626678 28.696396 -3.096718 15729 30.387993 28.883621 -2.663559 15730 32.577011 29.090759 -2.872833 15731 37.825928 28.458069 -2.017372 15732 50.738129 27.842438 -3.039154 15733 3.333534 25.442978 -3.816742 15734 3.132507 27.253189 -3.478340 15735 2.943764 21.416992 -3.368629 15736 3.087273 20.438828 -3.320511 15737 2.721985 20.572723 -4.089767 15738 52.615204 23.905334 -2.519646 15739 52.541061 26.910156 -2.248581 15740 53.063080 26.215591 -2.089279 15741 5.138138 25.795746 -3.520874 15742 5.841683 25.774475 -2.892990 15743 53.299469 25.599350 -2.102142 15744 5.675026 24.701691 -3.207932 15745 5.087090 24.179306 -3.539513 15746 51.949310 23.110001 -2.334259 15747 53.309525 24.912994 -2.373764 15748 4.181961 23.479065 -3.707352 15749 53.138641 24.148041 -2.692764 15750 53.321381 24.325073 -2.567825 15751 5.191658 22.964310 -3.125122 15752 49.993881 22.699463 -3.613686 15753 50.721985 21.939224 -2.843483 15754 53.203247 24.034515 -2.535461 15755 5.668434 23.717896 -3.012222 15756 49.779510 20.816193 -2.903442 15757 3.797066 22.196518 -2.971985 15758 51.471313 21.153168 -1.924713 15759 51.992935 22.102188 -1.749428 15760 29.058533 19.939911 -3.494782 15761 29.784126 19.514755 -3.606796 15762 30.117989 19.064072 -3.791977 15763 3.512917 16.537308 -2.835526 15764 27.106598 17.666840 -3.242607 15765 30.533104 18.853821 -3.717163 15766 31.814791 19.357162 -3.175171 15767 35.890533 18.188995 -3.612824 15768 36.754555 18.771362 -3.122467 15769 35.878098 18.996246 -3.031250 15770 39.328156 19.313950 -2.235138 15771 40.692825 18.452240 -2.365364 15772 28.599243 16.052368 -4.019394 15773 32.834305 18.921112 -3.491173 15774 39.024406 20.617493 -1.249817 15775 39.455963 22.100220 -0.034698 15776 40.288452 21.030548 -0.550247 15777 4.453819 15.611618 -4.801979 15778 3.967087 15.746490 -4.206230 15779 29.362045 15.802338 -3.744003 15780 29.037476 16.136185 -3.365356 15781 29.464081 15.886780 -3.278030 15782 48.625198 16.080719 -3.327759 15783 49.158188 16.914215 -2.960144 15784 3.972954 15.194077 -3.849045 15785 4.272316 15.114822 -4.439690 15786 4.682678 14.893890 -4.808578 15787 29.943893 15.487015 -3.413490 15788 30.603683 15.049744 -3.647423 15789 42.927536 16.185776 -3.334984 15790 44.907227 16.239883 -2.546814 15791 46.375015 15.462784 -3.313400 15792 53.681702 15.171249 -3.404160 15793 54.767273 14.939331 -3.431519 15794 4.387123 14.544617 -4.324448 15795 4.961861 11.950668 -4.677627 15796 30.805099 15.071167 -2.547890 15797 34.247322 13.839050 -3.529991 15798 35.931900 13.682251 -3.766151 15799 35.873932 13.933441 -3.573524 15800 35.628128 13.741501 -3.581406 15801 36.003311 13.683060 -3.526238 15802 43.105469 16.737366 -2.526360 15803 43.792374 17.366287 -1.651268 15804 47.373291 15.507492 -2.985443 15805 48.120850 15.738586 -2.940468 15806 52.269806 14.094696 -3.654999 15807 4.424751 13.772141 -4.121941 15808 3.969414 13.810135 -3.059097 15809 4.367485 12.712280 -3.731277 15810 35.127579 13.628342 -3.816734 15811 36.255859 12.878494 -3.627495 15812 55.911682 11.852325 -3.294540 15813 4.650856 11.388016 -3.619324 15814 36.737007 11.830231 -3.786156 15815 36.837593 11.721893 -2.951477 15816 36.122971 12.841141 -2.801147 15817 37.660675 11.776703 -4.380295 15818 51.037918 12.599762 -3.472794 15819 37.147385 11.596085 -4.042419 15820 37.714340 11.229492 -3.638245 15821 38.813354 10.947464 -3.729324 15822 50.545639 11.487000 -3.450493 15823 52.247238 11.305298 -2.967888 15824 5.294846 9.784210 -4.686371 15825 37.045761 11.407501 -3.631714 15826 40.928162 10.065384 -2.946175 15827 41.547302 10.353088 -3.676865 15828 39.654037 10.548325 -3.173714 15829 42.995514 10.306107 -3.801147 15830 43.150146 10.172668 -3.797768 15831 50.577301 9.998184 -3.293945 15832 51.166870 8.456238 -2.917664 15833 5.269278 9.052846 -4.040684 15834 5.658022 7.826638 -4.005976 15835 42.936493 9.877136 -3.913208 15836 57.198334 9.822754 -3.856995 15837 57.599121 8.324982 -3.398117 15838 58.178116 7.698242 -3.659836 15839 42.189270 5.210800 -3.657700 15840 58.412170 6.495621 -3.510819 15841 5.981494 6.007372 -3.576719 15842 40.997116 5.001900 -3.872559 15843 41.647018 4.746872 -3.387215 15844 11.371686 3.759662 -7.470988 15845 11.368403 3.752918 -7.473258 15846 11.376330 3.761892 -7.477034 15847 11.359386 3.750318 -7.451290 15848 11.364081 3.750482 -7.466042 15849 11.392708 3.785058 -7.484031 15850 11.414094 3.754108 -7.469117 15851 11.389852 3.764303 -7.468048 15852 39.738823 4.603188 -4.167992 15853 49.229767 4.427414 -3.819565 15854 58.808624 5.296310 -3.689613 15855 5.714486 5.181710 -2.941833 15856 39.290123 4.161163 -3.216888 15857 39.574028 4.578690 -3.411896 15858 39.374420 3.635956 -4.513817 15859 59.388245 3.533829 -3.685822 15860 39.679367 2.426559 -4.088821 15861 39.167915 3.495789 -3.599281 15862 59.792007 2.322495 -3.826019 15863 60.217621 1.601517 -4.034058 15864 40.956024 0.332062 -2.951218 15865 40.139313 1.372772 -3.051254 15866 41.178223 -0.478180 -4.057899 15867 60.215607 0.103882 -4.085144 15868 45.776794 -0.237808 -4.494461 15869 59.952896 -0.348602 -4.052185 15870 40.814346 -2.840195 -4.367561 15871 41.667267 -1.819244 -3.698257 15872 39.939041 -3.943878 -4.637474 15873 39.308914 -5.108109 -4.866959 15874 57.421005 -2.192444 -3.725746 15875 20.120289 -3.603022 -9.738302 15876 45.947617 -4.304001 -4.389389 15877 59.118454 -5.134659 -4.502029 15878 59.669037 -5.281235 -4.087936 15879 60.621216 -5.244690 -4.126770 15880 6.471274 -6.309112 -3.347425 15881 6.327512 -5.915070 -3.084237 15882 5.656469 -5.806002 -1.807039 15883 6.010526 -6.024138 -2.507805 15884 21.497841 -4.509448 -10.232294 15885 21.793915 -4.462063 -10.278500 15886 45.765335 -5.258682 -4.447044 15887 45.973007 -6.217606 -4.311737 15888 45.230988 -6.167404 -4.666550 15889 44.800339 -6.989883 -4.472710 15890 56.386612 -2.719635 -3.186462 15891 58.744080 -5.328995 -4.557159 15892 57.818359 -6.369247 -4.354050 15893 61.038879 -5.154678 -4.322365 15894 62.381943 -6.964294 -4.828186 15895 39.314407 -6.683990 -4.077683 15896 45.462860 -6.557724 -4.451324 15897 53.505508 -6.821838 -4.727287 15898 53.843811 -6.269257 -4.513222 15899 62.439728 -6.839386 -4.494919 15900 5.902444 -8.407180 -2.368128 15901 52.875351 -6.363800 -3.176697 15902 53.380737 -6.292862 -3.987244 15903 52.663147 -7.397781 -4.005920 15904 61.355499 -7.950577 -4.464584 15905 62.074173 -7.148209 -4.495453 15906 61.439377 -6.631912 -3.910683 15907 38.656113 -9.280640 -2.914475 15908 43.343201 -9.118683 -4.589004 15909 42.690857 -9.886871 -4.920204 15910 43.128326 -9.958023 -4.551163 15911 5.780860 -10.032350 -2.012835 15912 6.219868 -10.726248 -3.052706 15913 41.775238 -10.378555 -5.055313 15914 52.019775 -9.964706 -4.831558 15915 6.591926 -11.837827 -3.796974 15916 40.703140 -10.903076 -4.938705 15917 39.905937 -10.758209 -4.613098 15918 39.387520 -11.221115 -3.842682 15919 42.722870 -11.767624 -3.706467 15920 41.637421 -11.629501 -4.506935 15921 42.772430 -10.693207 -4.329041 15922 52.291901 -10.618698 -4.931213 15923 52.595856 -10.804916 -4.796234 15924 54.049347 -9.784851 -2.284790 15925 54.222382 -9.304291 -1.005554 15926 53.610504 -9.471512 -0.979416 15927 40.215698 -11.879822 -4.222206 15928 60.564041 -11.333847 -4.699631 15929 60.677307 -10.540543 -4.347694 15930 6.191190 -13.429322 -2.230967 15931 56.940567 -14.184280 -5.599487 15932 59.722839 -14.585678 -4.658981 15933 56.835999 -14.792679 -5.298065 15934 57.398911 -15.932632 -4.865341 15935 56.127014 -15.760544 -4.254135 15936 56.844604 -17.669144 -4.260910 15937 64.412567 -14.761551 -5.783432 15938 7.069039 -16.171432 -3.085931 15939 7.169277 -15.904469 -3.567072 15940 52.309311 -15.705490 -4.922806 15941 53.010162 -15.599319 -5.171051 15942 53.707962 -15.286407 -5.201691 15943 54.156860 -14.988998 -4.539139 15944 56.542969 -15.241913 -4.835983 15945 59.937180 -15.689407 -4.394951 15946 64.926941 -15.840897 -5.445038 15947 46.667007 -18.937851 -4.802994 15948 47.002289 -17.752518 -5.489464 15949 51.553940 -16.000641 -4.392349 15950 52.081360 -15.701492 -4.274567 15951 60.226776 -17.294495 -3.667412 15952 60.841995 -15.592300 -3.514145 15953 61.311951 -16.493454 -3.077469 15954 64.061432 -16.798309 -5.503723 15955 65.342667 -16.720901 -5.116119 15956 66.071716 -18.798950 -5.217377 15957 57.958939 -17.203613 -4.665146 15958 6.201997 -15.129047 -1.347904 15959 6.229660 -15.778392 -0.868289 15960 6.558404 -16.623384 -1.142118 15961 7.340579 -17.035870 -3.038954 15962 7.680925 -17.982151 -2.998802 15963 7.963198 -18.837801 -2.814830 15964 24.353107 -23.125175 -7.884063 15965 46.722153 -20.353958 -5.270477 15966 63.024277 -20.193390 -5.459610 15967 8.607721 -19.621557 -3.372051 15968 22.187716 -24.025671 -6.920711 15969 21.459877 -23.904417 -6.955640 15970 21.443336 -24.650723 -6.267362 15971 23.171160 -23.877520 -7.148139 15972 23.034872 -24.630493 -6.472063 15973 24.124470 -24.621258 -6.593662 15974 25.227091 -24.715940 -6.636679 15975 23.951601 -23.698042 -7.373907 15976 46.748428 -21.666443 -5.130066 15977 46.436203 -20.684555 -4.217987 15978 47.672989 -22.360046 -5.457466 15979 46.183441 -21.604172 -4.805282 15980 48.728607 -21.834229 -6.003326 15981 49.800400 -23.025391 -5.897453 15982 60.994446 -23.658859 -5.140533 15983 19.319324 -24.047184 -6.598002 15984 20.074831 -23.781141 -6.942717 15985 20.809881 -24.031225 -6.771513 15986 25.161139 -25.175390 -6.226748 15987 25.670946 -25.868950 -5.667692 15988 54.265686 -23.695297 -5.839126 15989 53.412506 -24.139709 -5.788391 15990 59.888321 -23.676880 -5.583153 15991 19.589485 -24.708241 -5.980990 15992 26.300655 -26.556707 -5.136029 15993 50.694824 -24.170425 -5.757980 15994 52.527618 -23.953430 -5.883934 15995 57.083054 -24.552795 -5.469192 15996 18.165024 -25.157009 -5.212173 15997 24.469933 -27.234478 -4.267600 15998 25.358585 -26.914982 -4.690539 15999 24.301994 -26.319113 -5.085953 16000 48.361145 -23.682526 -5.325180 16001 51.640930 -23.646866 -5.970077 16002 53.979858 -24.742554 -5.445930 16003 55.031006 -24.861313 -5.302788 16004 59.247894 -24.316391 -5.448059 16005 10.647949 -22.280645 -3.679478 16006 11.385774 -22.624643 -4.197874 16007 17.544437 -25.227089 -4.950772 16008 26.236799 -27.604696 -4.187708 16009 27.063797 -26.817856 -5.000035 16010 34.770363 -27.300142 -5.798496 16011 49.625443 -24.487137 -5.429878 16012 50.361832 -25.700500 -5.063248 16013 51.710800 -25.163330 -5.408249 16014 52.977173 -25.118347 -5.413132 16015 15.432089 -25.033985 -4.243090 16016 29.183998 -27.902435 -4.285829 16017 32.943871 -26.602821 -6.086882 16018 11.818247 -23.274008 -3.823710 16019 12.359049 -23.742279 -3.710877 16020 13.054682 -24.160452 -3.735332 16021 16.401457 -25.571466 -4.039927 16022 20.108391 -28.803406 -6.593887 16023 20.766479 -29.741821 -5.699989 16024 19.926102 -30.222977 -5.486542 16025 23.567978 -28.568039 -6.929062 16026 21.615585 -29.303833 -6.183807 16027 22.539566 -28.641220 -6.714630 16028 24.845886 -28.300110 -7.373085 16029 30.147247 -27.166376 -5.083962 16030 30.106203 -28.215612 -4.110282 16031 31.132566 -28.309332 -4.131710 16032 31.185244 -27.604862 -4.823566 16033 32.068779 -26.941408 -5.607627 16034 32.237267 -27.306234 -5.291029 16035 35.833847 -27.826447 -5.827202 16036 36.351181 -27.723557 -6.836639 16037 66.220703 -25.980301 -4.334229 16038 14.318904 -24.348686 -4.516809 16039 18.573151 -29.658768 -6.570007 16040 24.521240 -29.562744 -6.616363 16041 36.235825 -28.504288 -6.384842 16042 66.261383 -28.103516 -4.177330 16043 25.245781 -30.378494 -6.350357 16044 67.214355 -30.058273 -5.601959 16045 23.149933 -29.901245 -5.968223 16046 28.242340 -31.264160 -7.080238 16047 27.096909 -31.855270 -6.342163 16048 26.099266 -30.793091 -6.516601 16049 35.991310 -30.313660 -5.891678 16050 28.145020 -32.379974 -6.419647 16051 14.579346 -34.504532 -6.668304 16052 15.974319 -32.191055 -5.062309 16053 14.942070 -32.955292 -5.653892 16054 16.185913 -31.702759 -5.986885 16055 29.057922 -32.110413 -6.912025 16056 29.691635 -33.186417 -6.459854 16057 32.356232 -33.668854 -6.826782 16058 36.037415 -33.271378 -5.782272 16059 51.398163 -33.343262 -6.008041 16060 50.498749 -33.495712 -5.694015 16061 51.483368 -32.649597 -5.867660 16062 54.361313 -32.681427 -5.918518 16063 53.567993 -32.786240 -6.130134 16064 53.326111 -32.027176 -5.234375 16065 56.201492 -32.269043 -5.867920 16066 55.343597 -32.571075 -5.845657 16067 55.694931 -31.752396 -5.157654 16068 57.205597 -32.669907 -5.935104 16069 56.639465 -31.635941 -5.270683 16070 58.387177 -32.132553 -5.733200 16071 57.474350 -31.618866 -5.310333 16072 58.131302 -31.476334 -4.871529 16073 59.227417 -32.054123 -5.733841 16074 59.169388 -31.535278 -4.934753 16075 60.100098 -31.868469 -5.412300 16076 15.531890 -36.240204 -7.193275 16077 31.136795 -33.247604 -6.803100 16078 33.100861 -34.451889 -6.564285 16079 51.931351 -33.270523 -6.154312 16080 52.538315 -32.563721 -5.955612 16081 52.580688 -33.730438 -6.231178 16082 54.053497 -33.911026 -6.260406 16083 53.268219 -33.580444 -6.286354 16084 55.068848 -34.058853 -6.209854 16085 56.193024 -33.730164 -6.159340 16086 58.485703 -33.789383 -6.058151 16087 57.369751 -35.229172 -6.162155 16088 59.629349 -32.896194 -5.851227 16089 30.113571 -34.736115 -5.565727 16090 32.017487 -34.850937 -5.945633 16091 33.985924 -34.458344 -6.940178 16092 58.672913 -35.839020 -6.147133 16093 60.538071 -35.738068 -6.013916 16094 34.607872 -35.132401 -6.771683 16095 35.382660 -34.875214 -6.915192 16096 36.615044 -36.358002 -4.930534 16097 36.536469 -36.095306 -5.325470 16098 36.393814 -35.309525 -4.912865 16099 51.832062 -34.296127 -5.911674 16100 53.181061 -34.558029 -6.109543 16101 54.126770 -35.825424 -6.011368 16102 55.870483 -36.199905 -6.243988 16103 22.769531 -38.163300 -7.540329 16104 33.762711 -35.085861 -6.507324 16105 33.934525 -35.779846 -6.114853 16106 33.991608 -36.552917 -5.418732 16107 35.242935 -35.860306 -6.121193 16108 16.225739 -37.795944 -7.132370 16109 21.358170 -38.910233 -7.636650 16110 24.741333 -38.811401 -7.042679 16111 66.879807 -37.913040 -6.886673 16112 23.753334 -38.792770 -6.917160 16113 22.188011 -39.092911 -7.096672 16114 26.850525 -39.188248 -7.059921 16115 28.038696 -39.253525 -7.094330 16116 62.663879 -37.770630 -6.553894 16117 61.542572 -37.804474 -6.304871 16118 64.376144 -37.018631 -6.092850 16119 64.950729 -38.255127 -6.426483 16120 66.530258 -38.423523 -6.842880 16121 66.424561 -37.851318 -6.436829 16122 16.741699 -39.374069 -6.769195 16123 21.551720 -40.358734 -6.472473 16124 20.783531 -41.148834 -6.357101 16125 21.660980 -39.611145 -7.030563 16126 25.427361 -39.777985 -6.317581 16127 28.420303 -40.342560 -6.140167 16128 27.028809 -40.771667 -5.454124 16129 57.191177 -38.007797 -6.670517 16130 58.312408 -37.832611 -6.659103 16131 59.460724 -37.924408 -6.621170 16132 61.069946 -38.181473 -6.482239 16133 60.411911 -38.303207 -6.679336 16134 20.055313 -41.906662 -5.866417 16135 54.466461 -40.057358 -5.274963 16136 54.904831 -38.718796 -6.323975 16137 56.232330 -38.609467 -6.729378 16138 54.320831 -42.752472 -6.485191 16139 55.082657 -42.906326 -5.727005 16140 25.624832 -43.980133 -8.523087 16141 33.143326 -44.085968 -7.140953 16142 54.090500 -42.612228 -7.033707 16143 28.437683 -46.152283 -7.672638 16144 28.284439 -44.339203 -7.966171 16145 32.366188 -44.494873 -7.507141 16146 28.248062 -45.225739 -7.668877 16147 29.137299 -45.163895 -7.612686 16148 32.911438 -46.457993 -5.602981 16149 31.981058 -46.765060 -6.577362 16150 32.965210 -45.106750 -6.246773 16151 31.179390 -45.835358 -7.252289 16152 32.046944 -45.461777 -7.126007 16153 28.702057 -47.355087 -7.866562 16154 46.859604 -48.589600 -6.637047 16155 46.346191 -48.443100 -6.079880 16156 46.611664 -47.584503 -6.186066 16157 47.395172 -47.543564 -7.075729 16158 47.757294 -46.865524 -6.090477 16159 49.155502 -46.855774 -6.721657 16160 29.253967 -47.976425 -7.747887 16161 29.415878 -50.579529 -7.426636 16162 29.874390 -48.857101 -7.340973 16163 29.974030 -46.868332 -7.332832 16164 50.752808 -47.498276 -6.426971 16165 52.057037 -48.352295 -6.366699 16166 60.165817 -46.358337 -6.914001 16167 50.895767 -47.378952 -4.474197 16168 49.227417 -46.978210 -5.209747 16169 49.680725 -46.900650 -4.208504 16170 62.286926 -47.422272 -6.242523 16171 61.288422 -47.179962 -6.732513 16172 62.456726 -48.453552 -6.955627 16173 19.499435 -50.218689 -7.824448 16174 19.499496 -49.468719 -7.231316 16175 18.688950 -50.261063 -7.188347 16176 20.233978 -49.840485 -7.624390 16177 30.559113 -50.064011 -6.619446 16178 47.086426 -49.821518 -6.063270 16179 46.421188 -49.240204 -5.785683 16180 19.276611 -51.170456 -7.870605 16181 19.243698 -52.224609 -7.895111 16182 18.049774 -51.782242 -7.156509 16183 20.338593 -50.740829 -7.793457 16184 21.530029 -51.444412 -6.994896 16185 20.193024 -51.866562 -7.823982 16186 53.935471 -49.621368 -6.728653 16187 55.081573 -50.257568 -6.402954 16188 62.847473 -49.532669 -6.122085 16189 62.484451 -50.277863 -5.096527 16190 20.555214 -48.936279 -6.722061 16191 28.236511 -53.591843 -7.653755 16192 49.991592 -51.878662 -7.029900 16193 50.903564 -52.306900 -7.433067 16194 56.410156 -50.802429 -6.269638 16195 58.156418 -51.626480 -6.775482 16196 18.834862 -52.837234 -7.735153 16197 19.812782 -52.901764 -7.725632 16198 20.748306 -52.600571 -7.425011 16199 25.927666 -54.248413 -8.612556 16200 27.473923 -54.396912 -8.010551 16201 51.652588 -53.058121 -7.006225 16202 50.832581 -52.821976 -6.333176 16203 58.572571 -51.595627 -5.966888 16204 60.208160 -52.248764 -7.451683 16205 60.215881 -52.248611 -7.030266 16206 60.573502 -52.229523 -7.435081 16207 63.112717 -49.238205 -4.516212 16208 63.045273 -49.415619 -5.415298 16209 18.005463 -53.029205 -7.500580 16210 18.840744 -53.788605 -7.598472 16211 24.535751 -55.696747 -8.936241 16212 38.917572 -53.250046 -8.884430 16213 38.833931 -53.959152 -7.518036 16214 53.379654 -53.798782 -7.568260 16215 53.141388 -53.986588 -6.630066 16216 52.506561 -53.705215 -6.699699 16217 60.394653 -52.382187 -7.251587 16218 38.517349 -54.558792 -6.679275 16219 39.105293 -54.416733 -6.563240 16220 41.154282 -54.851562 -8.143036 16221 54.786621 -54.355072 -7.560028 16222 53.890182 -54.277451 -6.632370 16223 55.095505 -54.802643 -6.577919 16224 25.770081 -56.372589 -8.540375 16225 27.372597 -55.966431 -7.954285 16226 28.576065 -54.662964 -7.427139 16227 29.617073 -55.497620 -6.821899 16228 38.364258 -55.350647 -6.436989 16229 38.010040 -54.515839 -7.524567 16230 41.671844 -55.342102 -7.882996 16231 57.633408 -56.506546 -6.203857 16232 57.179428 -55.983871 -6.126694 16233 57.387405 -55.944641 -7.208801 16234 25.578812 -55.575562 -8.524956 16235 41.850677 -55.526108 -6.834770 16236 42.692795 -55.896957 -7.752273 16237 44.277451 -56.382812 -7.853165 16238 45.351273 -56.448929 -7.834846 16239 45.932327 -56.577042 -7.783783 16240 56.360809 -55.401031 -6.422684 16241 26.409851 -57.247681 -8.485062 16242 26.199730 -58.410690 -8.696251 16243 25.206787 -59.383438 -9.182053 16244 51.234375 -58.539536 -7.703369 16245 50.925995 -59.463608 -6.914856 16246 52.434113 -59.372589 -7.148392 16247 52.706482 -58.532806 -8.028374 16248 53.690033 -58.552658 -8.382477 16249 19.599838 -59.089600 -8.390198 16250 20.217491 -59.232635 -8.027710 16251 19.489265 -58.639618 -8.184814 16252 26.518814 -59.634262 -8.709610 16253 56.679245 -58.936646 -7.759773 16254 20.091209 -60.473221 -8.456886 16255 21.355286 -60.984940 -7.565834 16256 19.218765 -59.521057 -8.208450 16257 19.294067 -60.914627 -8.538925 16258 26.634056 -60.817947 -8.796532 16259 37.275589 -59.596970 -7.232651 16260 19.360046 -61.859497 -8.787170 16261 18.508881 -61.645691 -8.227524 16262 20.169022 -61.662354 -8.590691 16263 25.548531 -61.534775 -9.260483 16264 26.794373 -62.082932 -8.846054 16265 42.663788 -60.933609 -8.196587 16266 44.585541 -60.047821 -7.279007 16267 47.043304 -60.893661 -7.190002 16268 46.481201 -60.425888 -7.012749 16269 18.843231 -62.784897 -8.723557 16270 19.865990 -62.573822 -8.792923 16271 27.788620 -61.283783 -8.283989 16272 27.961487 -62.400696 -8.267982 16273 26.773560 -63.502762 -8.552483 16274 36.266006 -63.066544 -8.493912 16275 36.592712 -62.394058 -8.580681 16276 18.984962 -64.242538 -8.655357 16277 19.725113 -63.272018 -8.766594 16278 20.561607 -63.204010 -8.056602 16279 25.852264 -64.538300 -8.647568 16280 28.280312 -63.326767 -7.832184 16281 27.819984 -64.177292 -7.406723 16282 35.804161 -64.328278 -8.803314 16283 36.192879 -63.804062 -7.873871 16284 49.413574 -61.522888 -7.428024 16285 50.368195 -62.360931 -8.024231 16286 52.441986 -62.121902 -7.826935 16287 54.506271 -64.787323 -8.072975 16288 17.905197 -63.539307 -8.552986 16289 17.499153 -64.573349 -8.701477 16290 18.200516 -65.054871 -8.865219 16291 26.577576 -65.052917 -7.339279 16292 25.649811 -65.267014 -8.274536 16293 35.580032 -65.319153 -8.479401 16294 36.058838 -65.032776 -8.092606 16295 51.302216 -62.072250 -7.639931 16296 51.792496 -60.887878 -7.087944 16297 54.932098 -64.139267 -7.261841 16298 17.732178 -65.269836 -8.797096 16299 16.852158 -65.430618 -8.279961 16300 15.873558 -64.548965 -7.839226 16301 15.562248 -65.316544 -7.880798 16302 15.946869 -65.336151 -8.079727 16303 35.186844 -65.581665 -9.091446 16304 18.276077 -65.588547 -8.110588 16305 24.291809 -66.308487 -8.930809 16306 44.385345 -67.452087 -7.638306 16307 43.447708 -66.679565 -7.529709 16308 43.180939 -67.309296 -6.852547 16309 53.740540 -66.329285 -8.011551 16310 54.176514 -65.634018 -8.162636 16311 24.060265 -67.330475 -9.076424 16312 36.558121 -67.791550 -8.835503 16313 42.615128 -66.787613 -7.548286 16314 44.288666 -66.657745 -8.169289 16315 45.024475 -67.260956 -8.159210 16316 52.819275 -67.327759 -8.295235 16317 53.285126 -66.779266 -8.427826 16318 24.326950 -68.624573 -9.367577 16319 35.812698 -66.383377 -8.560608 16320 52.467712 -67.772202 -8.719742 16321 36.310272 -69.325775 -9.002380 16322 50.394867 -69.730576 -8.000824 16323 50.812378 -69.179794 -7.794456 16324 52.138382 -67.765839 -7.717880 16325 13.843048 -70.370209 -8.191154 16326 13.052155 -71.005066 -8.448906 16327 13.689316 -71.360657 -9.025028 16328 15.336700 -70.467926 -8.790894 16329 19.314636 -70.548264 -9.902302 16330 24.814545 -68.352005 -7.890137 16331 25.121948 -66.443771 -7.804176 16332 25.246696 -67.510788 -6.409012 16333 35.247597 -68.331680 -8.943375 16334 35.466766 -70.024536 -9.024460 16335 36.095322 -70.099075 -8.953247 16336 37.087540 -70.140396 -9.523098 16337 36.443314 -70.118057 -9.090736 16338 51.293732 -68.581009 -7.727226 16339 14.355499 -71.144608 -9.289120 16340 28.669472 -71.118591 -9.905304 16341 27.837479 -70.649551 -9.304108 16342 28.136238 -71.249268 -9.414215 16343 36.354012 -70.817490 -9.108612 16344 36.462982 -72.151917 -9.151085 16345 39.675903 -68.824341 -6.376221 16346 49.809082 -70.528900 -8.312988 16347 14.421303 -72.234924 -9.456390 16348 13.414520 -72.182663 -8.695709 16349 14.320702 -73.341751 -8.293076 16350 27.436096 -71.270386 -9.248024 16351 37.253830 -73.045105 -9.353035 16352 48.175934 -71.812683 -7.998749 16353 47.199524 -71.202530 -8.665329 16354 15.492554 -73.424408 -9.317371 16355 25.273468 -72.840836 -8.647331 16356 35.501335 -71.421341 -9.218758 16357 35.616684 -73.040466 -9.311935 16358 36.566803 -73.195770 -8.980675 16359 42.469574 -74.863037 -8.487267 16360 45.466461 -72.473434 -6.152374 16361 45.973969 -72.734497 -6.065712 16362 46.355087 -72.582031 -6.816467 16363 47.095230 -72.096649 -7.818596 16364 12.466255 -72.954041 -6.834961 16365 11.755264 -71.820328 -7.079208 16366 11.335107 -72.106705 -6.087112 16367 16.474106 -74.073364 -9.560719 16368 16.784172 -74.962479 -9.600822 16369 21.217857 -73.911163 -9.474384 16370 37.841843 -74.338821 -9.554077 16371 21.254318 -74.718567 -8.666016 16372 21.533401 -75.487854 -9.796974 16373 21.482697 -76.878815 -9.727638 16374 25.319153 -74.797806 -8.932098 16375 25.246086 -75.773438 -9.687565 16376 38.185982 -75.789139 -9.645157 16377 37.978249 -76.649857 -9.431725 16378 21.480385 -76.149216 -8.504166 16379 35.640594 -74.858124 -8.934479 16380 34.957504 -76.038040 -9.415474 16381 37.235893 -75.765457 -8.894852 16382 36.423996 -75.145294 -8.434143 16383 36.471016 -75.912704 -8.391052 16384 43.463409 -76.168610 -8.843384 16385 44.596115 -76.593445 -8.997482 16386 10.416442 -77.083862 -8.786064 16387 9.996506 -77.526718 -8.742241 16388 21.154770 -77.931458 -8.988853 16389 25.887497 -76.060089 -9.246758 16390 35.291672 -76.837845 -9.003536 16391 38.238403 -77.346756 -10.090168 16392 43.122437 -75.658768 -9.004585 16393 43.699036 -76.429962 -8.253479 16394 42.870850 -75.906662 -8.041916 16395 43.764893 -76.284393 -6.970039 16396 45.715485 -77.216339 -8.935753 16397 27.926300 -77.686371 -9.047466 16398 28.072586 -77.372330 -8.305283 16399 37.300613 -77.151382 -9.379250 16400 10.892899 -76.785446 -8.869148 16401 9.937233 -79.830078 -9.027134 16402 10.356903 -80.723022 -9.406040 16403 20.240410 -79.116516 -9.834301 16404 27.475342 -78.191467 -9.367691 16405 27.769005 -78.056808 -8.691437 16406 27.044037 -78.534348 -8.736664 16407 36.196838 -77.733078 -9.490486 16408 36.467712 -76.649567 -8.672028 16409 17.809357 -79.804047 -9.433487 16410 20.343086 -78.693771 -8.133171 16411 19.009796 -79.136398 -7.820900 16412 32.225090 -79.711899 -10.829559 16413 15.620575 -80.860565 -10.177101 16414 46.134247 -80.887512 -9.392082 16415 10.887062 -82.397202 -10.452148 16416 15.262497 -82.028702 -10.359001 16417 25.109589 -81.878983 -10.033466 16418 7.655868 -82.653595 -9.466045 16419 6.769844 -82.744507 -9.390671 16420 10.848892 -81.560837 -9.373306 16421 16.014740 -81.594940 -8.420883 16422 15.674774 -81.629745 -9.509399 16423 16.609756 -82.301865 -8.844383 16424 16.038498 -82.598190 -10.158192 16425 17.127693 -82.896790 -10.482056 16426 19.911835 -82.720840 -9.907524 16427 25.411621 -83.676559 -10.689043 16428 36.952103 -82.638351 -9.466614 16429 42.260803 -83.088745 -8.321228 16430 41.065643 -82.656097 -8.751266 16431 41.113983 -82.440674 -7.653702 16432 7.072983 -84.714417 -10.167713 16433 25.655273 -82.880646 -9.862373 16434 42.753204 -83.495605 -9.665314 16435 10.192383 -84.814758 -10.095589 16436 10.435181 -85.415161 -10.696327 16437 10.041519 -84.444962 -8.736794 16438 13.493195 -85.340317 -10.000580 16439 22.586411 -85.543060 -9.899586 16440 23.063797 -84.675842 -8.949387 16441 26.189758 -82.807083 -8.992859 16442 43.369415 -83.368698 -7.399437 16443 44.272827 -83.073837 -7.315170 16444 44.051483 -82.997589 -8.600128 16445 7.666221 -87.581451 -9.075283 16446 8.223694 -87.641861 -10.200146 16447 6.852913 -86.060776 -9.351223 16448 11.036751 -85.663162 -10.079334 16449 21.720901 -83.287827 -9.209614 16450 11.738288 -86.822723 -10.641560 16451 13.984558 -85.960648 -10.469872 16452 14.273521 -85.743500 -9.674313 16453 14.876961 -86.626816 -10.512505 16454 22.045631 -86.370361 -10.207451 16455 36.910263 -84.646225 -8.660439 16456 38.057480 -85.632965 -9.096718 16457 37.636497 -84.814804 -8.051010 16458 12.734193 -87.815216 -10.450983 16459 28.562897 -86.897919 -8.770523 16460 29.207489 -87.657944 -8.350441 16461 28.960968 -87.835114 -10.103340 16462 36.850616 -85.981674 -10.295235 16463 36.630096 -85.268066 -9.675308 16464 40.574265 -88.080261 -9.856815 16465 40.793991 -87.032684 -8.664818 16466 13.805389 -88.982544 -9.938663 16467 13.370499 -87.795395 -8.752228 16468 21.572250 -89.742249 -10.519363 16469 22.543488 -89.418671 -10.055702 16470 26.262329 -90.402069 -10.201958 16471 24.615112 -89.333466 -8.914818 16472 25.148163 -89.696228 -10.643093 16473 40.083374 -88.449326 -10.519791 16474 40.513321 -89.306656 -9.751122 16475 13.999054 -91.131912 -10.535320 16476 14.745163 -90.676285 -9.900345 16477 14.292450 -90.088303 -10.212299 16478 31.823725 -89.602234 -10.400650 16479 32.978134 -89.666550 -9.973480 16480 35.805763 -90.169052 -10.033150 16481 34.451492 -89.754990 -9.582897 16482 35.698334 -89.546112 -8.349365 16483 36.752960 -89.840851 -8.043739 16484 36.749870 -90.129883 -9.107162 16485 38.029175 -90.630020 -9.286438 16486 39.544212 -90.997269 -8.437057 16487 38.517860 -91.588547 -8.404465 16488 11.865472 -91.917267 -9.585968 16489 12.683929 -91.685944 -10.439249 16490 13.760284 -92.165878 -10.026924 16491 19.110367 -91.508316 -10.246078 16492 18.501259 -91.047668 -8.927177 16493 18.744026 -91.154175 -7.735924 16494 19.280457 -91.839386 -7.976105 16495 27.121506 -90.928162 -9.088959 16496 14.810249 -91.553391 -9.578323 16497 20.084702 -92.396835 -10.596191 16498 28.365067 -92.159668 -10.084160 16499 28.467728 -91.992233 -9.358387 16500 27.887009 -91.685913 -9.322269 16501 35.491013 -92.685745 -10.382076 16502 34.687424 -92.803192 -10.634781 16503 35.832108 -92.305359 -9.793194 16504 36.295959 -92.972733 -9.981056 16505 20.013367 -92.611282 -8.796036 16506 22.580467 -93.858078 -11.224464 16507 35.780823 -94.220688 -10.205055 16508 13.959259 -95.283722 -9.453209 16509 13.341400 -96.329086 -9.132835 16510 15.482132 -94.967453 -9.676754 16511 13.919099 -97.487320 -11.030575 16512 21.615257 -95.067398 -10.908325 16513 20.082985 -95.165421 -10.022591 16514 20.661957 -94.544373 -9.260319 16515 22.285522 -94.278488 -10.753681 16516 33.087967 -96.088303 -10.620472 16517 29.867599 -97.186142 -11.514435 16518 31.713762 -97.047775 -8.996811 16519 33.058319 -96.350891 -9.611988 16520 14.308594 -98.427429 -11.288544 16521 14.996536 -99.993256 -8.657852 16522 15.556496 -100.489685 -8.620148 16523 23.347054 -99.803543 -10.481239 16524 24.328384 -100.316040 -11.620972 16525 22.325249 -99.724426 -10.510033 16526 26.481270 -99.808746 -10.155052 16527 25.333160 -100.202011 -10.423256 16528 17.040070 -101.611084 -10.801819 16529 16.302078 -101.281296 -9.725769 16530 19.065872 -102.223648 -11.049831 16531 19.878883 -102.141968 -11.232224 16532 20.046822 -102.116119 -9.951515 16533 7.916839 62.581207 -0.283455 16534 9.372986 63.126099 -0.359497 16535 9.958061 63.139923 0.457817 16536 6.932602 62.416794 -0.406494 16537 6.979370 62.020554 0.003700 16538 4.518936 61.358810 1.436813 16539 3.927300 60.850983 1.263672 16540 3.420052 60.307663 -0.615143 16541 18.445618 60.859833 -0.031052 16542 15.696335 60.952957 0.074310 16543 3.331703 58.488327 0.193588 16544 3.317116 57.453491 0.270798 16545 18.387802 61.444305 1.169373 16546 17.336060 61.340149 1.177933 16547 14.817978 58.948380 -1.464584 16548 20.394646 60.265503 1.473343 16549 3.338364 56.483093 0.401123 16550 20.939072 54.467117 -0.880157 16551 22.289337 54.575089 -0.540558 16552 22.391899 56.710938 -0.362198 16553 23.921982 56.687576 -0.123016 16554 23.731766 57.851532 0.378250 16555 24.885468 57.262665 0.631203 16556 24.835342 56.011047 -0.116531 16557 25.031204 54.753586 -0.166305 16558 23.568207 54.683304 -0.297104 16559 24.536903 53.681381 0.066246 16560 24.362114 57.947723 1.002258 16561 22.480255 58.492340 0.409660 16562 25.637894 55.596588 -0.070343 16563 25.953796 56.414185 0.459107 16564 26.130539 55.675171 0.145493 16565 26.161148 54.895233 0.227997 16566 25.744980 53.777542 0.362579 16567 26.678268 55.693512 0.474945 16568 22.352615 53.083282 -0.204605 16569 23.736305 52.771866 0.277847 16570 31.526199 51.665100 -0.437256 16571 30.897705 51.906067 -0.632889 16572 32.500191 52.080154 -0.582382 16573 3.472405 53.891891 0.945023 16574 3.477501 55.322327 0.822617 16575 21.495949 51.141449 -0.430527 16576 29.794388 51.897324 -1.097130 16577 30.329147 51.630585 -0.751480 16578 34.186440 51.845703 -0.758850 16579 33.655090 51.993439 -0.630783 16580 33.302765 52.034622 -0.554878 16581 33.491447 50.903625 -0.548752 16582 35.149483 50.615479 -0.474167 16583 34.047104 49.384064 -0.291969 16584 29.493240 50.922806 -0.875488 16585 30.802299 50.811478 -0.423256 16586 36.248436 50.798767 -0.407059 16587 36.974548 51.376862 -0.421890 16588 36.472137 50.770554 0.567108 16589 35.327827 50.259247 1.369904 16590 35.657074 50.009216 0.392052 16591 38.778702 52.153625 0.469009 16592 32.120468 50.571136 -0.380478 16593 35.977966 50.299744 -0.053955 16594 37.563370 51.718826 0.408020 16595 21.667984 50.149857 -0.730331 16596 22.117889 49.206314 -0.740997 16597 28.817009 49.959351 -0.738388 16598 25.834167 47.096466 -0.862305 16599 26.692749 47.911652 -0.781601 16600 32.750412 49.287781 -0.490204 16601 33.336746 48.449173 -0.289841 16602 34.871445 49.539551 0.530937 16603 42.319153 49.155945 0.694763 16604 2.897904 45.728455 -1.514420 16605 22.598480 48.599167 0.095993 16606 32.138123 47.854401 -0.189110 16607 31.383591 49.289703 -0.349335 16608 33.352982 47.868561 0.191467 16609 32.763565 47.422989 0.591950 16610 22.903984 47.991486 -0.045952 16611 24.479774 46.818436 -0.599495 16612 27.324234 47.020935 -0.516022 16613 30.418030 47.932068 -0.312149 16614 29.835876 49.628876 -0.458405 16615 31.058502 46.673553 0.073403 16616 31.801813 46.795929 0.868095 16617 44.747696 42.964569 -0.771515 16618 2.570160 48.010284 -0.365578 16619 2.935433 46.827637 -0.530655 16620 25.479095 46.104568 -0.675385 16621 25.868530 45.415344 -0.576813 16622 26.843819 45.803513 -0.482788 16623 42.959534 47.149292 -0.414497 16624 42.764709 47.963425 0.606133 16625 4.029221 45.791779 -0.611870 16626 25.044449 44.586121 0.816025 16627 24.817093 44.281586 1.686951 16628 24.466446 45.484009 1.620087 16629 26.439011 44.953186 -0.362663 16630 4.068482 44.767792 -1.536255 16631 5.319672 44.963440 -1.216064 16632 9.581337 44.019394 -1.716698 16633 9.399063 45.144531 -0.934677 16634 10.661362 44.369125 -0.975235 16635 24.859245 45.594101 0.082153 16636 25.792503 44.996399 -0.315430 16637 11.477722 43.554596 -0.767616 16638 44.625092 44.201782 -1.163483 16639 43.701996 45.886368 0.413452 16640 43.598282 46.271255 0.407181 16641 44.453339 41.825317 -0.731880 16642 11.632721 42.592163 -0.411133 16643 1.837845 38.807190 -1.504898 16644 2.196320 38.893570 -1.909027 16645 2.257469 39.395401 -1.028076 16646 2.759468 39.454758 -1.873108 16647 3.551590 39.742767 -1.860374 16648 2.819817 40.092377 -1.318024 16649 3.478127 40.687866 -0.841812 16650 38.999420 41.593292 -0.295837 16651 38.509193 40.401199 -0.839188 16652 37.327332 40.486267 -0.299698 16653 42.067795 41.162872 -0.602890 16654 41.130127 40.490326 -0.950821 16655 37.383423 42.164810 0.425324 16656 38.401672 42.980438 0.582642 16657 40.791626 42.022003 -0.084106 16658 40.176208 40.591125 -0.880417 16659 43.112183 40.341309 -1.120438 16660 43.270187 41.551300 -0.444153 16661 44.507843 40.717041 -1.248047 16662 1.907272 38.467773 -1.082382 16663 2.684517 38.923248 -2.220337 16664 6.247910 39.986298 -1.437485 16665 6.983452 39.145676 -1.924377 16666 7.164307 40.572998 -0.804169 16667 38.602303 39.509308 -1.021057 16668 37.528961 38.806732 -0.568260 16669 39.345047 40.177643 -1.019920 16670 38.871811 38.434967 -1.114685 16671 8.087677 39.214325 -1.723328 16672 9.889847 38.329239 -2.566605 16673 10.835519 41.923462 0.001572 16674 9.044647 40.958679 -0.526657 16675 37.648209 37.597412 -0.095611 16676 36.462746 38.444016 0.135544 16677 39.787682 37.530487 -1.286270 16678 1.884010 35.820404 -1.735535 16679 2.270439 34.464264 -1.770691 16680 39.606155 36.399948 -0.862396 16681 38.540085 37.556702 -0.772278 16682 40.479980 35.403061 -0.812355 16683 40.804596 35.754013 -1.320084 16684 42.205902 34.508102 -0.869522 16685 41.661179 34.618378 -0.541138 16686 41.003143 35.001938 -0.436295 16687 51.748077 33.052948 -0.690308 16688 52.313538 32.507507 -0.441391 16689 52.175262 33.225372 0.096550 16690 44.562836 34.691284 0.475945 16691 44.168091 34.034622 -0.051910 16692 51.122498 33.120667 -1.303543 16693 51.681427 32.457291 -1.452843 16694 2.180901 31.125275 -2.813141 16695 2.327713 32.673431 -2.226593 16696 3.026154 31.768066 -2.180176 16697 5.805176 31.703522 -1.956482 16698 6.462921 30.901108 -2.292580 16699 4.945358 30.598694 -2.424431 16700 9.114997 32.408920 -0.110763 16701 8.891762 33.586700 -0.175613 16702 9.642906 33.609177 0.600212 16703 5.935837 33.100555 -1.377853 16704 7.354904 33.274429 -1.043182 16705 6.960999 32.067886 -1.711044 16706 25.506454 30.254044 -2.652687 16707 26.644501 30.366318 -2.303101 16708 52.220734 31.806976 -1.266953 16709 52.642395 30.701889 -1.013153 16710 3.444351 30.446350 -2.643585 16711 3.914940 31.601776 -2.083710 16712 4.786453 32.263000 -1.786903 16713 6.080917 29.371613 -2.711479 16714 7.489128 29.305878 -2.130737 16715 7.355728 28.585251 -2.387947 16716 6.762161 28.488358 -2.566406 16717 7.488968 31.187866 -1.915482 16718 7.221558 30.269775 -2.219238 16719 8.033920 30.518890 -1.332245 16720 23.496658 30.301834 -2.516457 16721 29.909912 30.313004 -1.993042 16722 49.030182 30.895493 -1.669296 16723 7.810157 29.179932 -1.378380 16724 7.572121 28.666168 -2.002930 16725 29.956100 29.585785 -2.384140 16726 48.810181 30.220825 -1.727539 16727 52.517944 28.802551 -1.555878 16728 22.748581 28.937317 -2.959114 16729 37.606567 28.662079 -2.006607 16730 38.659653 28.518829 -2.125473 16731 52.611420 27.885437 -1.581512 16732 6.407105 28.593033 -0.494049 16733 7.160164 28.242432 -2.207497 16734 38.189598 28.586823 -1.913666 16735 52.604935 27.065521 -1.646774 16736 5.547546 24.669388 -2.313576 16737 52.815247 26.611816 -1.706558 16738 53.195480 24.767288 -1.638474 16739 53.178467 25.994858 -1.407845 16740 5.543976 23.520370 -2.511322 16741 53.185425 24.276840 -2.234688 16742 5.624397 23.107910 -2.786270 16743 52.510895 23.633423 -1.901901 16744 52.846558 24.027451 -1.827782 16745 4.189484 22.654434 -3.413658 16746 5.205620 22.924042 -2.522675 16747 52.757965 23.370255 -1.070831 16748 4.674042 22.506897 -2.814651 16749 52.532684 21.984238 -0.724640 16750 28.775650 20.658325 -1.970154 16751 27.558540 19.859436 -1.917229 16752 28.369751 20.844131 -1.205032 16753 32.996948 20.291885 -2.575539 16754 31.806955 20.755310 -2.124756 16755 32.760895 22.125778 -1.103691 16756 33.899063 21.173477 -1.920532 16757 34.113274 20.164413 -2.611740 16758 34.028809 21.838913 -1.331650 16759 52.140930 21.246887 -1.148148 16760 28.412735 20.144455 -2.733231 16761 30.255447 20.177032 -2.607559 16762 30.868988 19.143402 -3.316643 16763 30.302750 19.259399 -3.312683 16764 37.666916 21.023163 -1.175461 16765 37.168442 20.028244 -2.218239 16766 36.176895 21.308533 -1.239700 16767 37.950043 20.354004 -1.832825 16768 38.214569 19.856415 -2.198944 16769 51.412842 20.317657 -1.265213 16770 26.498787 18.959900 -3.055634 16771 27.090454 19.548019 -2.994705 16772 29.565758 21.405792 -1.230186 16773 30.966042 21.756363 -1.210976 16774 34.973145 20.614426 -2.076019 16775 35.963242 19.855240 -2.465088 16776 50.189255 18.296387 -1.262520 16777 26.806915 19.008362 -2.566025 16778 27.207764 18.540253 -2.003448 16779 27.706070 17.436737 -2.354408 16780 41.648209 17.687225 -2.574013 16781 42.469666 17.370941 -2.311653 16782 48.662735 16.439163 -2.440636 16783 47.850739 16.004776 -2.516098 16784 47.943848 16.526276 -1.688957 16785 49.432373 17.388824 -1.936005 16786 28.545532 16.578278 -2.718903 16787 29.186890 16.125244 -2.722275 16788 29.708626 15.758026 -2.708481 16789 46.931122 16.019867 -2.307297 16790 46.959198 16.846008 -0.939285 16791 48.169769 17.100983 -0.440949 16792 4.108894 14.578690 -3.578110 16793 3.891586 15.258896 -3.316910 16794 43.061737 17.405594 -1.914223 16795 52.881348 15.038666 -3.365982 16796 3.842468 14.919312 -2.920578 16797 3.568367 14.523285 -1.641937 16798 32.539101 14.127029 -2.479813 16799 35.849060 13.812103 -3.433769 16800 35.188843 13.631409 -3.103058 16801 35.808205 13.430511 -3.223694 16802 35.580849 13.392883 -2.677017 16803 36.504456 12.461060 -2.265884 16804 35.912018 13.343231 -2.163139 16805 55.461411 10.872070 -2.916245 16806 54.429199 12.123657 -2.981964 16807 4.996422 10.182281 -3.942749 16808 36.953598 11.830933 -1.780083 16809 50.668457 7.143433 -3.114960 16810 4.715935 10.076721 -2.726990 16811 38.095917 10.766159 -2.182594 16812 37.825333 10.642746 -0.800568 16813 37.199730 11.345551 -0.912170 16814 39.798851 10.189362 -2.005173 16815 42.183762 9.873764 -3.507401 16816 41.589188 10.035767 -3.283005 16817 42.815186 10.033920 -3.767387 16818 54.934814 9.583328 -1.746407 16819 54.717010 8.867569 -1.211510 16820 53.938843 9.273758 -1.647133 16821 41.703430 9.621643 -3.030724 16822 41.403931 9.631226 -2.640747 16823 42.545258 9.002563 -2.933212 16824 55.867432 9.770386 -2.552361 16825 55.676422 9.136932 -1.666008 16826 56.721008 8.918823 -2.798706 16827 56.263367 8.939423 -2.250290 16828 57.024841 9.481720 -3.293335 16829 5.108283 8.560146 -3.146040 16830 41.749390 9.413788 -2.638428 16831 43.414032 7.757767 -3.058319 16832 44.591003 6.531723 -2.456314 16833 44.170090 7.296143 -2.655876 16834 50.766724 5.443802 -3.215927 16835 52.549591 9.121140 -2.283340 16836 56.818436 8.356583 -2.381439 16837 57.429169 7.422287 -2.520233 16838 58.072098 7.375580 -3.280319 16839 57.840912 6.724930 -2.997696 16840 51.968964 7.548920 -2.431091 16841 51.869965 6.276062 -2.540710 16842 57.591751 6.482758 -2.531616 16843 44.157928 8.552078 -2.293472 16844 58.010437 5.838394 -2.936493 16845 57.673996 5.996826 -2.391602 16846 58.447662 4.715729 -2.668991 16847 59.045929 4.375473 -3.392899 16848 11.367379 3.751906 -7.467945 16849 11.376978 3.760077 -7.470989 16850 40.100739 4.699051 -3.507408 16851 40.785217 4.538963 -3.283508 16852 39.919449 4.382599 -3.074036 16853 40.565247 4.093918 -2.849030 16854 42.553680 4.743866 -3.191208 16855 41.672363 4.080177 -2.846085 16856 42.625351 4.181427 -2.889603 16857 43.635284 4.370743 -2.676292 16858 44.694336 5.490997 -2.383591 16859 57.964142 5.475983 -2.216278 16860 58.778259 3.700401 -2.988998 16861 39.099930 3.482483 -2.740288 16862 51.241470 3.644417 -3.321838 16863 51.728256 4.495316 -2.993866 16864 52.453217 4.207443 -2.757744 16865 52.632965 3.391022 -2.890610 16866 53.186279 3.681808 -2.305023 16867 52.998917 2.652573 -2.397202 16868 58.532043 3.727402 -2.101440 16869 39.248314 2.423569 -2.536385 16870 52.330078 2.595123 -2.895020 16871 58.665237 3.043991 -2.627441 16872 59.051193 2.795975 -3.164253 16873 59.287369 1.731293 -2.864723 16874 60.034210 1.393936 -3.620926 16875 51.308670 2.016525 -3.228592 16876 51.565567 1.110123 -2.983833 16877 52.335968 1.353455 -1.884750 16878 50.574692 0.584183 -3.087769 16879 58.862076 2.528793 -2.689796 16880 50.678757 1.400558 -3.451622 16881 42.306503 -1.720505 -1.277847 16882 41.284149 -0.975281 -0.894234 16883 41.322754 -0.429245 -1.877335 16884 58.999054 -0.335907 -3.307228 16885 58.422836 -0.565918 -2.872757 16886 58.988358 0.402924 -2.715034 16887 58.985779 1.306396 -1.405548 16888 58.826004 2.701141 -1.908760 16889 59.781631 0.302582 -3.543076 16890 48.966553 -0.026276 -3.512016 16891 58.640076 -0.980164 -3.428894 16892 6.249251 -3.193523 -2.636997 16893 6.801418 -1.608327 -3.343971 16894 5.944137 -2.140760 -2.167629 16895 41.633301 -0.660080 -3.101975 16896 42.129181 -1.322754 -2.748718 16897 47.992126 -1.634872 -3.685730 16898 48.708801 -3.694366 -3.316566 16899 48.837357 -2.883911 -3.372269 16900 49.295303 -2.900467 -2.549660 16901 55.187531 -3.549255 -2.723343 16902 54.088913 -4.362579 -1.797867 16903 54.622726 -3.451065 -1.443131 16904 57.146317 -1.864487 -2.926537 16905 57.930145 -1.426743 -3.192963 16906 40.990662 -4.268524 -3.765350 16907 41.756439 -3.244934 -3.569412 16908 42.621307 -2.648361 -2.548203 16909 47.828552 -3.112946 -3.865875 16910 40.040268 -5.361649 -3.809448 16911 41.777176 -4.108810 -3.389023 16912 47.292419 -4.339508 -3.942406 16913 48.192215 -4.753235 -3.278305 16914 46.952057 -5.898392 -3.670181 16915 54.089706 -5.633118 -4.095200 16916 54.282410 -4.815628 -3.326988 16917 54.659119 -4.291260 -3.106010 16918 40.965271 -5.564301 -3.176872 16919 40.475128 -6.776779 -2.711342 16920 41.936768 -4.881714 -2.958229 16921 43.196472 -2.898254 -1.427010 16922 43.353546 -3.959961 -1.823441 16923 53.568329 -5.478424 -3.091209 16924 58.727249 -5.432602 -4.166718 16925 61.254822 -5.587982 -4.067955 16926 46.291489 -6.569046 -3.974014 16927 46.665314 -7.111618 -2.615402 16928 46.159973 -6.989273 -3.542923 16929 48.010345 -5.533615 -2.386627 16930 58.172516 -6.016434 -3.902679 16931 58.909866 -5.683197 -3.746643 16932 59.633179 -5.667099 -3.270973 16933 60.524246 -5.779083 -3.706131 16934 60.268341 -5.870575 -3.220337 16935 61.918243 -6.085526 -4.261436 16936 5.234412 -4.949383 -0.962454 16937 5.722077 -4.256238 -1.853870 16938 44.418488 -8.135422 -3.917145 16939 45.349731 -7.319275 -3.745537 16940 45.698547 -6.787201 -4.077805 16941 51.330139 -9.050018 -3.526138 16942 51.248291 -9.169189 -3.176147 16943 51.696671 -8.495132 -2.888344 16944 52.298981 -7.145233 -2.490967 16945 58.630569 -5.998260 -3.300468 16946 59.113388 -5.631180 -2.204575 16947 57.773163 -5.896347 -1.368790 16948 60.704056 -6.295364 -3.173393 16949 60.971115 -7.486237 -3.051346 16950 62.182648 -6.662872 -4.259918 16951 45.477371 -7.777359 -2.975983 16952 51.951996 -8.826874 -4.328758 16953 60.617676 -7.088272 -1.004440 16954 60.661682 -6.385559 -2.275414 16955 39.010208 -8.004105 -3.315842 16956 43.455200 -9.945435 -3.974693 16957 43.972839 -9.173126 -3.745148 16958 51.527161 -9.675400 -3.643478 16959 60.697479 -9.989105 -3.518753 16960 60.729156 -10.711090 -3.261337 16961 60.872833 -9.168884 -3.845520 16962 52.256104 -10.553619 -4.086037 16963 52.650330 -10.707138 -3.217514 16964 52.090408 -10.095016 -2.667557 16965 60.552582 -11.858475 -3.941483 16966 42.062256 -12.657196 -3.895660 16967 41.172302 -12.767258 -4.047188 16968 60.434509 -13.566757 -3.896088 16969 61.042130 -12.689453 -2.862923 16970 40.368225 -13.324234 -3.471703 16971 41.852905 -13.861511 -3.165085 16972 6.251022 -14.620408 -1.831434 16973 5.912443 -14.078410 -1.076389 16974 53.745880 -15.166199 -4.076508 16975 54.321518 -14.806107 -4.140152 16976 55.029221 -14.774033 -4.253098 16977 55.852814 -14.971848 -4.516479 16978 55.692871 -14.787186 -4.148651 16979 55.932358 -15.024414 -4.157356 16980 60.371506 -14.792664 -4.001999 16981 52.735046 -15.511566 -4.189499 16982 53.252136 -15.429276 -4.675827 16983 53.258606 -15.542099 -3.703362 16984 60.910141 -14.529907 -3.373367 16985 47.704208 -17.070450 -4.117813 16986 48.084869 -16.791290 -4.069931 16987 48.544983 -16.668381 -4.361359 16988 49.601669 -16.932541 -3.508438 16989 55.584534 -16.716614 -3.929695 16990 55.507889 -17.566910 -3.887825 16991 61.478867 -17.454880 -2.720398 16992 64.720581 -16.740250 -5.096313 16993 47.282257 -17.805145 -4.152023 16994 55.622559 -18.885040 -3.823044 16995 55.493134 -21.465164 -3.026169 16996 53.744736 -19.191315 -3.508743 16997 7.015169 -17.191776 -1.990049 16998 62.927292 -21.260178 -5.208549 16999 8.136476 -19.614771 -2.330822 17000 9.038452 -20.516968 -3.204834 17001 22.275217 -24.917522 -6.119980 17002 45.948547 -21.759186 -4.587318 17003 20.104994 -24.364521 -6.395052 17004 20.555943 -25.038511 -5.768530 17005 24.383938 -25.527523 -5.819641 17006 46.200302 -22.261597 -4.886398 17007 45.920013 -22.267822 -4.596290 17008 47.004181 -22.916199 -5.064773 17009 62.606766 -22.948853 -4.801483 17010 67.160660 -23.392334 -5.258919 17011 19.555073 -25.309420 -5.331119 17012 23.115477 -25.545137 -5.633896 17013 22.019970 -26.268349 -4.762582 17014 23.121101 -26.377676 -4.852388 17015 46.341644 -22.844818 -4.576775 17016 47.195206 -23.933746 -4.668678 17017 46.788513 -23.247574 -3.814377 17018 47.921371 -24.847092 -4.917007 17019 60.094543 -24.772629 -5.043487 17020 62.090759 -24.578735 -4.223732 17021 65.409729 -23.590164 -4.216476 17022 66.487854 -23.238083 -4.776695 17023 34.023361 -26.093616 -6.776229 17024 47.516190 -24.913147 -4.512710 17025 48.892944 -25.452515 -4.840210 17026 60.916412 -24.822968 -4.723701 17027 63.773773 -23.739044 -4.034988 17028 66.571609 -24.290207 -4.768265 17029 64.543289 -25.622726 -2.948395 17030 64.606934 -24.513016 -3.538971 17031 65.692535 -25.159576 -3.777374 17032 18.763824 -25.482744 -4.975878 17033 23.509336 -27.048502 -4.278636 17034 34.009350 -26.558361 -6.347451 17035 33.433254 -27.085928 -5.722728 17036 47.257202 -24.390640 -4.032578 17037 53.942261 -25.964294 -4.882286 17038 53.276321 -26.690613 -4.391373 17039 52.606995 -26.176208 -4.842354 17040 56.183487 -25.657227 -4.912041 17041 59.191452 -25.432907 -4.957519 17042 58.132156 -25.756409 -4.863052 17043 67.027618 -25.051651 -5.235153 17044 66.495300 -25.328613 -4.723480 17045 10.178696 -22.097172 -3.203948 17046 17.916042 -27.346144 -2.326446 17047 17.940275 -26.488495 -3.466100 17048 16.752617 -26.303486 -3.171369 17049 18.015785 -25.776075 -4.420650 17050 23.669954 -27.765818 -3.627246 17051 24.412392 -27.869471 -3.667765 17052 25.244776 -28.018724 -3.663763 17053 27.214767 -27.544569 -4.372132 17054 47.995941 -25.411255 -4.535324 17055 47.728912 -25.131134 -3.906387 17056 48.421417 -25.805725 -3.920456 17057 51.435455 -26.447937 -4.553078 17058 62.450775 -26.257248 -2.877228 17059 60.533798 -25.826981 -4.186180 17060 9.653207 -21.618710 -2.957915 17061 11.243563 -22.838676 -3.771643 17062 14.108004 -24.781540 -3.686666 17063 15.057960 -25.402193 -3.483698 17064 24.952787 -29.041168 -2.668895 17065 26.133163 -28.741575 -3.142362 17066 49.255005 -26.436432 -3.948784 17067 49.689133 -26.240616 -4.593094 17068 50.315979 -26.653763 -4.146202 17069 52.325638 -27.221710 -3.637253 17070 54.003510 -27.331375 -3.552933 17071 55.210693 -26.435104 -4.398132 17072 55.410431 -27.605743 -3.317001 17073 56.567001 -27.028702 -3.807068 17074 57.194565 -26.100769 -4.620460 17075 58.129669 -26.828369 -3.884644 17076 59.070908 -26.281647 -4.379303 17077 59.547501 -26.820953 -3.613098 17078 27.784796 -27.994076 -4.039580 17079 28.407585 -27.881218 -4.214809 17080 29.332050 -29.438211 -2.890404 17081 30.293402 -28.998089 -3.387883 17082 35.881546 -28.986252 -5.570022 17083 66.693680 -29.271988 -4.745888 17084 18.934616 -28.868515 -6.836365 17085 21.597610 -30.872131 -5.015198 17086 30.685328 -28.616409 -3.788796 17087 65.738251 -29.235596 -2.909256 17088 67.181885 -29.345779 -5.438934 17089 18.373863 -31.019897 -5.391403 17090 17.104858 -31.143631 -5.871170 17091 17.172653 -31.721771 -4.996269 17092 16.885460 -32.423218 -4.276489 17093 66.471909 -30.374298 -4.541679 17094 24.375221 -30.597534 -5.857933 17095 25.043518 -31.155807 -5.744522 17096 25.462830 -32.056808 -5.457931 17097 51.667084 -31.838196 -5.423691 17098 51.200348 -31.699585 -4.919983 17099 51.648636 -31.522110 -4.850387 17100 52.242035 -31.747314 -4.875564 17101 54.436752 -32.130707 -4.395050 17102 60.250641 -31.303864 -4.739990 17103 61.025116 -31.438629 -4.923942 17104 61.247498 -31.106628 -4.057190 17105 61.688232 -31.334961 -4.613769 17106 61.714111 -32.396042 -5.056656 17107 66.248230 -31.213730 -4.495117 17108 66.603500 -31.141876 -4.962791 17109 28.635284 -33.075424 -6.225128 17110 49.105820 -32.540359 -4.505577 17111 49.980774 -32.564835 -5.247650 17112 49.335388 -33.173325 -5.311485 17113 50.389343 -32.016907 -4.497795 17114 50.854401 -32.268707 -5.392242 17115 49.472565 -32.187637 -3.366592 17116 65.903168 -31.767548 -4.241394 17117 12.907501 -34.060135 -5.361000 17118 12.606552 -34.654877 -5.485466 17119 13.089142 -34.441483 -5.762070 17120 28.900520 -33.815094 -5.827454 17121 28.679230 -34.386383 -5.313980 17122 63.235779 -30.529831 -2.014091 17123 64.657364 -30.155228 -2.185822 17124 63.882202 -31.604965 -3.606598 17125 65.400635 -32.756805 -4.679047 17126 63.497955 -34.394440 -5.352035 17127 67.008224 -33.732483 -5.856728 17128 13.634552 -33.877502 -5.538933 17129 13.544945 -34.522034 -6.066772 17130 28.923042 -34.928207 -5.089966 17131 36.261963 -34.221603 -5.529617 17132 49.097717 -34.120499 -5.376503 17133 48.579865 -33.502441 -4.900894 17134 48.048325 -34.717102 -4.488312 17135 48.016632 -33.301590 -4.068604 17136 49.795715 -34.871857 -5.415024 17137 65.876755 -34.938263 -5.707367 17138 13.252304 -35.435150 -5.918671 17139 14.354148 -36.372025 -6.438217 17140 32.826157 -36.151627 -5.257919 17141 33.099548 -35.306015 -6.081215 17142 36.480476 -35.057983 -5.665436 17143 47.017914 -33.956894 -3.149857 17144 47.743179 -33.011612 -3.151398 17145 48.920746 -34.833679 -5.268967 17146 50.855026 -34.784195 -5.599556 17147 51.616623 -35.600708 -5.252289 17148 65.697952 -37.327042 -6.166748 17149 67.178375 -34.585526 -6.098930 17150 13.492493 -37.132812 -5.783783 17151 34.929840 -37.133667 -4.930130 17152 36.203308 -35.713104 -5.877968 17153 48.995056 -35.257156 -4.963928 17154 49.699005 -35.748901 -4.558784 17155 50.558197 -35.431686 -5.135689 17156 50.669891 -36.108002 -4.247192 17157 52.725922 -35.455872 -5.755295 17158 50.935440 -36.737228 -3.164963 17159 49.285400 -37.178268 -2.672775 17160 52.875977 -36.642914 -5.236465 17161 53.802994 -37.544556 -5.743133 17162 67.150314 -35.488708 -6.280983 17163 15.159332 -37.253540 -6.650726 17164 35.909660 -36.637009 -5.298218 17165 53.384354 -37.659775 -5.327835 17166 14.491302 -37.484451 -6.182403 17167 15.373657 -38.267120 -6.372620 17168 22.848099 -39.101349 -6.655113 17169 22.181061 -39.645218 -6.532303 17170 24.449821 -39.239502 -6.480087 17171 23.601456 -39.661301 -6.120895 17172 24.447922 -39.748642 -6.064079 17173 53.901016 -38.458649 -5.378464 17174 53.288849 -37.672226 -4.590866 17175 53.941788 -38.745132 -4.497513 17176 16.989502 -40.461853 -6.247238 17177 17.596085 -40.374390 -6.735245 17178 16.175461 -40.124893 -5.983673 17179 24.846497 -41.860352 -4.411438 17180 25.991074 -41.924149 -4.119682 17181 26.736923 -42.281647 -3.704567 17182 16.398582 -41.014725 -5.619530 17183 17.734955 -42.455673 -5.222534 17184 17.799103 -41.303650 -6.171303 17185 16.740013 -41.863602 -5.349464 17186 19.023788 -42.127197 -5.645691 17187 21.818039 -41.461868 -5.535995 17188 32.030800 -41.154587 -5.937752 17189 32.709953 -41.883423 -6.025429 17190 55.110168 -41.820831 -4.912552 17191 33.063751 -42.870056 -5.784813 17192 33.586227 -42.828949 -6.273720 17193 33.750183 -42.774246 -6.690750 17194 33.562195 -43.308929 -6.321411 17195 33.396439 -43.944305 -6.506210 17196 55.256607 -40.980682 -3.926498 17197 56.340698 -42.074875 -3.793205 17198 59.920990 -44.760437 -5.973190 17199 61.135239 -43.918488 -5.603485 17200 60.214920 -43.416046 -5.083443 17201 57.596802 -44.062515 -5.647491 17202 56.483826 -43.982544 -5.702194 17203 58.817261 -43.449173 -4.900299 17204 61.246979 -46.343689 -6.332298 17205 61.886017 -45.283966 -5.945160 17206 62.258636 -43.709610 -5.579971 17207 62.869339 -44.633575 -5.748833 17208 63.288757 -43.754715 -5.474365 17209 64.700333 -41.933563 -4.442703 17210 63.104858 -42.214630 -4.846847 17211 64.383667 -43.567627 -4.851837 17212 63.689636 -44.808685 -5.389526 17213 62.956406 -45.540680 -5.641556 17214 32.599823 -47.477524 -5.588676 17215 46.804169 -46.846588 -5.210579 17216 46.029083 -47.417999 -5.121094 17217 62.504822 -46.310547 -5.816513 17218 61.943710 -46.429550 -6.083053 17219 31.206680 -48.585464 -6.552917 17220 46.092926 -47.961685 -5.777328 17221 18.095184 -50.577698 -6.769081 17222 18.374275 -50.137756 -6.188827 17223 19.819946 -48.902985 -5.679352 17224 19.805290 -49.745056 -4.545219 17225 19.030609 -49.909317 -5.359283 17226 32.093750 -47.931152 -6.131744 17227 32.107666 -48.767990 -5.490753 17228 63.551529 -46.397888 -5.306724 17229 22.007767 -48.809830 -6.396362 17230 22.110725 -47.747879 -5.469948 17231 21.227188 -48.147842 -5.905273 17232 21.299866 -49.940765 -7.171570 17233 19.626785 -49.006027 -6.610969 17234 53.108215 -49.024841 -5.763733 17235 52.300522 -48.581528 -5.479172 17236 51.691971 -48.155258 -5.429428 17237 62.712585 -48.652924 -6.336563 17238 63.194550 -48.333435 -5.316711 17239 22.547928 -50.046326 -6.508598 17240 47.515701 -51.343063 -4.984634 17241 45.844269 -50.236984 -4.294777 17242 48.966614 -51.596710 -5.998032 17243 54.925568 -50.083267 -5.434029 17244 55.739685 -50.454254 -5.582428 17245 57.532547 -51.221512 -6.057075 17246 62.078018 -51.197083 -5.600433 17247 17.870575 -50.843765 -6.302734 17248 16.983902 -52.555603 -6.176231 17249 17.293884 -52.992142 -7.008713 17250 17.504585 -51.503799 -6.085220 17251 17.584351 -53.705414 -7.302772 17252 21.276566 -52.863739 -6.867699 17253 22.083694 -52.855988 -5.915749 17254 23.149063 -51.375977 -5.696731 17255 49.912094 -52.439636 -5.699608 17256 50.595337 -53.105881 -5.481384 17257 59.656738 -51.452866 -5.340645 17258 60.651566 -51.893784 -6.262047 17259 60.585861 -52.221313 -7.017326 17260 20.387642 -53.880463 -7.206032 17261 39.792564 -54.330292 -7.165726 17262 16.739708 -55.661545 -6.535087 17263 16.792809 -56.970856 -6.262253 17264 17.399323 -56.830597 -7.125076 17265 19.085426 -55.414261 -7.515304 17266 18.686707 -57.680252 -7.587936 17267 20.131500 -56.485291 -7.192772 17268 20.236061 -55.110779 -7.145691 17269 53.108765 -54.389893 -5.776153 17270 53.887741 -55.078934 -5.174469 17271 52.907898 -55.292236 -4.698013 17272 18.104858 -56.449051 -7.579468 17273 17.683174 -54.717834 -7.280975 17274 22.336967 -56.523575 -5.580124 17275 22.094727 -55.218002 -5.406891 17276 21.233505 -56.489288 -6.376236 17277 26.125092 -55.639923 -8.325645 17278 29.127594 -56.680359 -7.194374 17279 27.795441 -57.524185 -7.908981 17280 39.773125 -54.899460 -6.157844 17281 40.805481 -54.919601 -7.121185 17282 55.191422 -55.404099 -5.537231 17283 56.534531 -56.091568 -5.577446 17284 17.705299 -55.807526 -7.379837 17285 43.186691 -56.221466 -6.445022 17286 44.508331 -56.569031 -6.471153 17287 41.930115 -55.987701 -5.920471 17288 42.489914 -57.076782 -5.247116 17289 45.494644 -56.645462 -7.010193 17290 57.846466 -57.011322 -6.700432 17291 19.877090 -57.945374 -7.752350 17292 20.739517 -57.831924 -7.215111 17293 29.565689 -57.766907 -6.839233 17294 27.986404 -58.802704 -7.884476 17295 46.355377 -57.276260 -6.495331 17296 45.256592 -57.624786 -6.033630 17297 46.500168 -56.902374 -7.309189 17298 47.320511 -57.503220 -6.866470 17299 49.600983 -58.113968 -7.495529 17300 21.380585 -59.059769 -7.109756 17301 29.315567 -58.955765 -6.971863 17302 28.688309 -59.667938 -7.533104 17303 37.431427 -58.777100 -7.172745 17304 50.282837 -58.655350 -7.174454 17305 50.308197 -58.280884 -7.674637 17306 53.800827 -58.954300 -7.586563 17307 57.780411 -57.929749 -6.789001 17308 18.393982 -60.590530 -7.668449 17309 27.735779 -60.063095 -8.156731 17310 54.191376 -59.480713 -7.254822 17311 53.586380 -59.597412 -7.088715 17312 54.953979 -59.390213 -7.577354 17313 56.054977 -59.279205 -7.460960 17314 53.041229 -60.269516 -7.048187 17315 57.022064 -58.965836 -6.835022 17316 28.630371 -60.673126 -7.634247 17317 29.544495 -60.120758 -6.655777 17318 42.853668 -60.227615 -7.265289 17319 43.482605 -59.547089 -6.453888 17320 45.813950 -59.438721 -6.472061 17321 44.471863 -58.839539 -6.019653 17322 54.294159 -60.369308 -7.244301 17323 55.742126 -61.149567 -6.799713 17324 55.827179 -59.914429 -7.064964 17325 17.571510 -62.504410 -7.912048 17326 16.920334 -63.612152 -8.152275 17327 22.554352 -62.021408 -6.426666 17328 21.808304 -62.853882 -6.877792 17329 28.543030 -61.633469 -7.810944 17330 29.140152 -61.417984 -7.053802 17331 28.802612 -62.423096 -7.540543 17332 39.497124 -60.896942 -5.725662 17333 42.757202 -60.606995 -7.817993 17334 53.130188 -61.172607 -7.356048 17335 55.379852 -62.500565 -7.290291 17336 28.975327 -63.262405 -7.129753 17337 36.680252 -63.654526 -7.401215 17338 37.003662 -63.144257 -7.008133 17339 36.655357 -62.473557 -7.613182 17340 47.488190 -61.036545 -7.118225 17341 50.575211 -61.594894 -7.231026 17342 56.676743 -59.946396 -6.254021 17343 13.745056 -64.669418 -6.220146 17344 14.084129 -65.517502 -5.984634 17345 14.414383 -65.278458 -6.759262 17346 22.926071 -60.588516 -6.320816 17347 22.186737 -59.632233 -6.753021 17348 55.382553 -63.305023 -7.319733 17349 55.784454 -62.871033 -6.722160 17350 28.586716 -63.928177 -7.183731 17351 36.618462 -64.555023 -7.661392 17352 54.300354 -64.620605 -6.291038 17353 54.890930 -63.889420 -6.132378 17354 55.440323 -63.397491 -6.452164 17355 55.703812 -62.753372 -5.967148 17356 15.104623 -65.297714 -7.396805 17357 18.070068 -66.208023 -6.983887 17358 19.085617 -65.763260 -6.836555 17359 19.892242 -64.927277 -7.462433 17360 26.042755 -66.285904 -6.287048 17361 27.094398 -65.992462 -5.248703 17362 26.039658 -67.323410 -5.244575 17363 37.024414 -65.457977 -8.178360 17364 54.315750 -65.178421 -7.284393 17365 15.794601 -65.796661 -7.609688 17366 21.308853 -64.135559 -6.616775 17367 37.485420 -63.082123 -6.750152 17368 38.624176 -62.553101 -6.794281 17369 43.305756 -66.421738 -7.885391 17370 43.904480 -68.134262 -7.003075 17371 53.976715 -65.911942 -7.422287 17372 44.419586 -68.317368 -7.421699 17373 52.968246 -66.797485 -7.380913 17374 53.617935 -66.273438 -7.297897 17375 44.811554 -68.295334 -7.761337 17376 44.595596 -68.916565 -7.597847 17377 45.068695 -68.922546 -7.965355 17378 12.960373 -70.333282 -7.986381 17379 19.867950 -70.652176 -7.837463 17380 26.449265 -71.191818 -8.978561 17381 26.973320 -70.533707 -9.118557 17382 40.558975 -71.032379 -7.243423 17383 44.779785 -69.869843 -7.548271 17384 45.744781 -71.362442 -7.617775 17385 41.149078 -72.218094 -7.813484 17386 49.785828 -70.107742 -7.118500 17387 39.401047 -72.036530 -5.383209 17388 39.194443 -70.839676 -5.286461 17389 49.478973 -70.849274 -7.385727 17390 25.436768 -73.650421 -7.468094 17391 25.053055 -72.227737 -7.350586 17392 25.657433 -71.268890 -8.378868 17393 25.221725 -71.505661 -7.670372 17394 36.268082 -73.853287 -8.717804 17395 48.850922 -71.307617 -7.011368 17396 15.651794 -74.070724 -8.082428 17397 16.310104 -74.144104 -8.730751 17398 15.073433 -74.175659 -7.179672 17399 16.717575 -74.501694 -8.913315 17400 20.781631 -72.987396 -7.998550 17401 36.927063 -74.186874 -8.806786 17402 16.561684 -75.075470 -7.927704 17403 16.694183 -75.784698 -8.766815 17404 35.357155 -75.937973 -8.767059 17405 12.634354 -76.354507 -8.533508 17406 11.792496 -76.367981 -8.197754 17407 13.632149 -76.534668 -8.164536 17408 15.035339 -76.784912 -7.466270 17409 15.781746 -76.326782 -8.996773 17410 16.394768 -75.799255 -9.666359 17411 35.856964 -76.029419 -8.471764 17412 41.353210 -74.394623 -7.024734 17413 42.093140 -75.491028 -7.111847 17414 16.433540 -76.186859 -8.815414 17415 26.426659 -74.186508 -6.535683 17416 27.513542 -74.804550 -6.100334 17417 27.357483 -75.340988 -6.879311 17418 26.652130 -75.556213 -8.023575 17419 28.063919 -76.414093 -7.521515 17420 42.646042 -76.006226 -7.184311 17421 9.611267 -78.261414 -9.070339 17422 9.601486 -78.120071 -8.266960 17423 35.880722 -76.864532 -8.692810 17424 45.222382 -76.895065 -7.869308 17425 44.259964 -76.671555 -8.096100 17426 45.878799 -76.654678 -6.792862 17427 45.073044 -76.404297 -6.651047 17428 46.705170 -78.192993 -8.248856 17429 46.221924 -77.497955 -8.327202 17430 46.514038 -77.465866 -7.333328 17431 9.489708 -78.911545 -8.865829 17432 9.866302 -79.021805 -9.628517 17433 20.445648 -78.917725 -9.206146 17434 46.929199 -79.090454 -7.317284 17435 47.227249 -77.783844 -6.468796 17436 16.335274 -80.548798 -9.140762 17437 25.779160 -79.439606 -8.766541 17438 26.346024 -78.963150 -8.805092 17439 26.430359 -78.875534 -8.025909 17440 16.407692 -80.686859 -7.682632 17441 17.034958 -80.913162 -6.280456 17442 16.987076 -79.882858 -6.331055 17443 25.564560 -81.701508 -9.025394 17444 45.822281 -81.303101 -7.709518 17445 6.032158 -82.456329 -8.613380 17446 6.042931 -83.538788 -8.799133 17447 7.186607 -82.120926 -8.702271 17448 6.403442 -81.911652 -8.397110 17449 11.962006 -82.748657 -8.929764 17450 15.937920 -81.118973 -8.615707 17451 37.405762 -82.239212 -8.971489 17452 38.262360 -81.973541 -8.749741 17453 46.674789 -80.386612 -6.910217 17454 8.249612 -82.891708 -8.332253 17455 6.595284 -81.803787 -7.388580 17456 16.900299 -82.767975 -9.603725 17457 18.404572 -82.697174 -10.392822 17458 17.975174 -82.557648 -9.240021 17459 22.143982 -82.797119 -7.760849 17460 22.940712 -83.528488 -7.865036 17461 25.542091 -80.882996 -7.967384 17462 36.543365 -82.885513 -8.818634 17463 23.694580 -84.346039 -7.992088 17464 45.634354 -81.694778 -6.122276 17465 13.112427 -84.678467 -9.543526 17466 36.490738 -83.711960 -8.137909 17467 16.175003 -87.130295 -8.919495 17468 16.940384 -88.526245 -9.583233 17469 23.597900 -85.227753 -8.138855 17470 23.667542 -84.760223 -8.464928 17471 22.718864 -86.115967 -8.643890 17472 27.564789 -85.792740 -9.682716 17473 39.036552 -85.494354 -7.945343 17474 39.506294 -86.128403 -8.631874 17475 39.980301 -85.912933 -7.168930 17476 21.609085 -87.023468 -9.609764 17477 21.776077 -87.305649 -8.475662 17478 38.290649 -85.110077 -7.828766 17479 41.709549 -87.076721 -7.585998 17480 41.037079 -86.477875 -7.294678 17481 6.624352 -86.153259 -8.003990 17482 11.941551 -86.369431 -8.995804 17483 20.548630 -88.170609 -9.799606 17484 21.050255 -87.625076 -9.471573 17485 28.096664 -86.691269 -9.652328 17486 30.300865 -88.441269 -8.181198 17487 29.648193 -87.761734 -7.323135 17488 41.596130 -88.086868 -8.719856 17489 41.801147 -87.553207 -8.240532 17490 30.502960 -88.198166 -7.253708 17491 30.123802 -88.496445 -9.211842 17492 41.138718 -88.354080 -9.323776 17493 8.605225 -88.468063 -9.742317 17494 9.053413 -88.948898 -9.823460 17495 14.661865 -89.878098 -9.189686 17496 14.206390 -88.804214 -8.569603 17497 17.797249 -89.717209 -9.425205 17498 22.416710 -88.552307 -8.215302 17499 31.696558 -89.028748 -9.020874 17500 32.827332 -89.221786 -9.127701 17501 33.528763 -89.269058 -8.982048 17502 41.127258 -89.845505 -8.373985 17503 41.487137 -88.964752 -8.713211 17504 9.326431 -89.188461 -9.893425 17505 9.863403 -89.514771 -10.130482 17506 18.021744 -90.455566 -9.472519 17507 21.252106 -88.274185 -9.014996 17508 40.309814 -90.234177 -8.861252 17509 10.340042 -90.241821 -9.768471 17510 15.033386 -90.704071 -9.368221 17511 14.332947 -92.642975 -9.395061 17512 12.748672 -92.319412 -9.742390 17513 36.495140 -90.931259 -7.101341 17514 36.492065 -91.347275 -7.527412 17515 36.877838 -91.276871 -8.031822 17516 36.867935 -92.137863 -9.146248 17517 37.167252 -92.831848 -9.354980 17518 37.938095 -92.653519 -8.563049 17519 13.456528 -92.803238 -9.441254 17520 20.027863 -92.685013 -7.568619 17521 19.702484 -92.275574 -9.745010 17522 21.615570 -94.110535 -10.076221 17523 31.060089 -91.643707 -7.199798 17524 38.773445 -92.577621 -7.618713 17525 20.938461 -93.583588 -9.093342 17526 38.488029 -93.099945 -7.537109 17527 15.471634 -94.611954 -8.471817 17528 14.167007 -93.780838 -8.776375 17529 35.945763 -94.891830 -9.259125 17530 35.329147 -95.442047 -8.779320 17531 36.968491 -93.875000 -8.944130 17532 37.944138 -93.655991 -7.650925 17533 37.294815 -94.290665 -7.769943 17534 13.534592 -97.563919 -10.286091 17535 13.793999 -98.165787 -10.427910 17536 14.272132 -99.044556 -10.096169 17537 22.923843 -99.153534 -9.671665 17538 21.974586 -99.601852 -9.842663 17539 21.770187 -100.578125 -10.126953 17540 25.508331 -99.802582 -9.551704 17541 28.094643 -99.038513 -9.621815 17542 21.264069 -101.391464 -10.633064 17543 22.885986 -100.647675 -8.161346 17544 22.495262 -100.004059 -8.072845 17545 22.304443 -100.869217 -9.076534 17546 19.391220 -102.199982 -7.283050 17547 21.765419 -102.038986 -6.589592 17548 22.012474 -102.091263 -7.821426 17549 17.800728 -102.048492 -10.003639 17550 11.328316 63.129089 0.813377 17551 7.851135 61.529510 0.419975 17552 9.151192 62.337341 0.670471 17553 5.165642 61.482254 0.730629 17554 3.442741 60.371277 0.085945 17555 6.334480 61.343735 0.553490 17556 7.246445 60.678513 0.728806 17557 16.292801 61.378189 0.769287 17558 18.929810 61.227600 0.808121 17559 8.840675 61.407501 0.785851 17560 8.552307 60.507172 0.767616 17561 15.140038 61.681747 0.980652 17562 21.612152 59.606644 1.539490 17563 20.941574 59.738678 2.170288 17564 3.362885 59.618256 -0.045654 17565 6.331986 60.657059 1.454086 17566 5.511589 61.227158 1.400986 17567 7.840942 59.164566 1.645813 17568 7.627395 59.852814 1.169144 17569 8.555634 59.232086 1.150139 17570 21.672958 59.370010 0.834190 17571 22.548653 58.929169 1.235184 17572 23.767128 58.044098 1.691803 17573 23.182373 57.558411 2.453766 17574 22.144020 58.463272 2.318695 17575 23.948624 58.229416 0.952545 17576 23.392639 58.474609 0.893341 17577 26.836777 56.352127 0.752640 17578 26.583405 56.732452 1.024574 17579 25.969521 57.079437 1.558151 17580 27.425194 56.417130 1.487953 17581 27.327629 55.832458 0.856339 17582 27.734482 55.687149 1.135880 17583 27.360291 54.779694 1.018036 17584 26.557053 54.197906 0.536285 17585 25.025436 52.506592 0.721390 17586 26.189056 52.987305 1.046867 17587 26.018044 52.146912 1.423973 17588 25.212662 51.079269 1.517960 17589 26.726059 53.690903 0.949066 17590 28.243515 54.526321 1.783157 17591 27.404968 53.188232 2.180527 17592 22.035599 51.644150 0.030365 17593 22.954926 51.722260 0.532074 17594 23.979477 51.155823 1.080246 17595 41.217896 51.245193 0.913941 17596 39.749275 52.488022 1.853928 17597 41.891693 50.284943 1.041779 17598 2.573761 49.517944 0.381867 17599 2.555664 49.501968 -0.243393 17600 21.904770 50.703369 0.020592 17601 37.606537 52.417694 1.595749 17602 3.764298 50.244110 1.697640 17603 3.146683 49.541565 1.225693 17604 22.302063 49.770584 0.256561 17605 2.462814 48.894196 -0.107895 17606 23.148666 49.063828 0.974777 17607 23.223236 50.126740 1.070664 17608 34.022812 48.667206 0.575020 17609 33.695374 48.113617 0.804459 17610 23.473541 47.553925 -0.284454 17611 42.357513 48.592575 1.858040 17612 23.857574 46.761993 0.197311 17613 29.195129 45.826660 0.138229 17614 33.285561 47.827988 0.962448 17615 43.287231 46.833420 0.507156 17616 4.618981 46.436615 0.169357 17617 11.674408 44.722244 0.337296 17618 10.596901 45.188232 -0.374756 17619 33.312950 48.708511 1.774338 17620 7.001808 48.855133 1.507202 17621 25.990021 44.325516 0.388855 17622 27.494476 44.416992 0.217682 17623 29.452835 44.421310 1.279572 17624 28.651810 44.024918 0.975319 17625 30.847656 45.902435 0.715378 17626 11.862679 43.587006 0.195480 17627 26.900101 43.453644 0.968353 17628 26.072678 43.276031 1.595619 17629 39.844368 42.953705 0.436279 17630 40.806091 44.506912 1.719208 17631 43.633850 43.429901 0.314453 17632 36.499176 41.541214 0.475388 17633 36.083504 42.880280 1.739037 17634 39.305504 43.570572 0.855042 17635 39.135460 42.833038 0.261017 17636 42.287323 42.604004 0.303772 17637 42.920685 43.133377 0.558518 17638 43.090210 42.667358 0.304787 17639 43.047729 42.206833 0.049179 17640 43.727661 42.374969 -0.141983 17641 4.481331 43.618332 2.283066 17642 4.605721 42.431915 0.846497 17643 6.875839 42.974487 1.376404 17644 2.629219 40.339279 -0.625130 17645 2.668129 39.914246 0.080567 17646 9.836380 42.316833 0.787171 17647 36.092789 39.444885 0.009369 17648 35.570854 40.753571 0.656693 17649 2.879692 40.789185 0.008255 17650 1.971298 37.198013 -1.267044 17651 35.268890 39.006363 0.725800 17652 34.815002 39.864990 0.714386 17653 35.310326 39.645172 0.386040 17654 36.916130 38.060425 0.964943 17655 38.503891 36.815613 -0.434296 17656 38.458054 36.746338 0.154236 17657 48.015320 35.180573 0.085968 17658 49.041443 35.523163 -0.121338 17659 48.629395 36.418076 0.354828 17660 50.332062 36.300415 0.794952 17661 49.575699 36.160736 0.136383 17662 50.259705 35.162704 -0.133858 17663 3.494339 33.388870 -1.595535 17664 39.011124 36.289627 -0.220879 17665 39.871391 35.776459 -0.267677 17666 39.478638 36.228210 0.339104 17667 40.450897 35.332794 -0.325806 17668 49.508789 36.646332 0.449387 17669 2.447128 35.994995 -0.923584 17670 4.009277 34.844498 -0.848732 17671 3.088020 35.027740 -0.997505 17672 4.811043 33.888000 -1.188232 17673 5.198593 35.320694 -0.324524 17674 5.590790 34.176758 -0.882294 17675 6.437309 34.367462 -0.595741 17676 48.987183 34.115692 -0.486237 17677 50.273163 33.731018 -0.937103 17678 51.154556 35.159668 0.588539 17679 51.125458 34.823624 -0.015739 17680 51.101898 34.135620 -0.517891 17681 51.602493 34.184052 0.044556 17682 8.045441 34.663452 0.119324 17683 8.376007 33.215073 -0.663017 17684 8.135788 31.997421 -1.144074 17685 42.476532 34.613220 -0.252884 17686 43.497833 34.759903 0.305893 17687 49.477539 32.939117 -1.083801 17688 51.876297 34.148621 0.885132 17689 52.515564 32.588623 0.071961 17690 8.589737 31.257629 -0.331192 17691 47.497925 33.640350 -0.125473 17692 52.652069 31.708588 -0.139206 17693 7.717207 30.122238 -0.181763 17694 7.267349 28.583405 -1.403282 17695 53.084717 30.455261 -0.116501 17696 52.826172 31.050720 1.116623 17697 7.981559 29.720749 -1.245331 17698 53.050110 29.750580 -0.707352 17699 53.374573 29.761398 -0.154159 17700 37.779785 28.671997 -1.826424 17701 52.840439 28.838409 -1.038681 17702 53.366806 28.978699 -0.171799 17703 53.150360 27.891174 -0.739532 17704 53.406601 27.910156 0.189087 17705 5.564690 28.031494 -0.321533 17706 53.348984 26.684357 -0.388954 17707 52.895950 27.008362 -1.218376 17708 53.296661 24.979874 -0.482666 17709 53.153473 25.792084 0.498551 17710 4.880043 23.665955 -2.046188 17711 4.562828 24.999237 -1.410469 17712 3.736748 23.684494 -1.410934 17713 5.370476 25.731796 -1.467323 17714 4.281715 22.670532 -2.147057 17715 3.548691 21.751648 -2.107727 17716 34.036697 22.361725 -0.828339 17717 33.985107 23.310486 0.090881 17718 34.803452 21.436142 -1.459320 17719 3.132897 20.212738 -1.583420 17720 3.583016 22.504242 -1.574867 17721 36.085876 22.761200 0.001221 17722 34.977524 22.044235 -0.861633 17723 37.230980 22.122696 -0.304024 17724 52.150909 20.973816 -0.271835 17725 51.041351 19.442566 -0.301285 17726 29.892570 22.570877 -0.123802 17727 28.659622 21.609589 -0.250030 17728 38.305634 22.123230 -0.182396 17729 40.602417 19.788208 -1.274330 17730 42.607132 18.664413 -1.180771 17731 49.571289 17.678543 -0.541245 17732 50.210632 18.114578 -0.333679 17733 50.507706 18.473724 -0.288788 17734 28.402130 17.122726 -1.699677 17735 46.069519 17.612122 -0.265938 17736 29.364632 17.206039 0.868103 17737 28.157700 18.037018 -0.398254 17738 29.574631 16.248352 -1.362961 17739 48.831406 16.988785 -1.245834 17740 44.675583 18.454224 -0.181152 17741 3.958717 12.294983 -2.037994 17742 32.142395 14.300522 -2.025696 17743 32.014641 14.699829 -0.755699 17744 35.011543 13.743393 -2.336784 17745 35.470673 14.134857 -1.393990 17746 34.059982 14.781723 -0.506630 17747 33.580154 14.126144 -1.897293 17748 32.893135 15.397903 0.969215 17749 32.839157 14.894226 0.252800 17750 34.169403 16.256744 0.755875 17751 37.092209 12.875671 -0.664154 17752 37.722122 14.185120 0.398682 17753 37.017792 14.577393 -0.348480 17754 36.530571 13.052948 -1.585526 17755 36.506676 14.137558 -0.936485 17756 37.326752 11.023483 0.077286 17757 54.177429 10.298157 -2.343582 17758 40.027817 10.152954 -1.158020 17759 41.489288 9.736298 -1.741547 17760 40.534668 10.072632 -0.366318 17761 41.765121 9.684235 -0.122131 17762 42.868469 9.532013 -0.719620 17763 44.943130 9.150391 -1.823959 17764 45.024841 9.458176 -1.573196 17765 44.460266 9.385376 -1.621567 17766 43.309357 9.389130 -1.732819 17767 44.909241 7.478729 -2.026794 17768 45.111694 8.533539 -1.505150 17769 45.227432 9.223846 -1.473694 17770 53.642334 8.234833 -1.412781 17771 52.874725 7.638382 -1.845459 17772 56.267456 8.643234 -1.700638 17773 56.665359 7.820419 -1.408096 17774 5.313027 7.190269 -2.955197 17775 54.671082 8.045685 -0.919342 17776 5.003031 6.242750 -2.134633 17777 45.221207 6.420563 -1.706940 17778 45.239899 7.485336 -1.012314 17779 52.735168 6.669205 -2.027588 17780 57.607834 6.379791 -1.450569 17781 4.110020 6.469844 -0.670349 17782 4.032747 7.734371 -0.561840 17783 3.607734 7.825072 0.435075 17784 51.940033 5.475983 -2.576279 17785 53.057556 5.094543 -1.959770 17786 54.139740 6.721313 -1.049210 17787 39.741524 3.788223 -2.558830 17788 39.287971 3.175171 -2.199158 17789 44.483871 3.537491 -2.051277 17790 44.862518 4.522400 -2.090958 17791 45.301483 5.281754 -1.617668 17792 52.021545 4.919090 -2.681473 17793 58.366364 4.625504 -1.196251 17794 39.881607 3.126724 -1.925354 17795 40.733032 3.453461 -2.337662 17796 41.896606 2.944763 -2.167969 17797 42.662140 2.904999 -2.395378 17798 42.645416 3.556244 -2.598953 17799 43.413879 3.017906 -2.340546 17800 44.135208 2.525604 -1.804993 17801 45.282074 4.226761 -1.039566 17802 53.540237 3.830872 -1.741776 17803 53.895203 3.737228 -0.954330 17804 54.543045 4.796616 -0.375290 17805 5.998042 3.045843 -2.918696 17806 5.515233 3.729585 -2.446625 17807 5.271421 2.979770 -2.021989 17808 4.708505 3.842079 -1.466473 17809 42.720688 2.538162 -2.119568 17810 53.349609 2.806808 -1.631119 17811 5.963145 2.118648 -2.713047 17812 43.289825 2.294037 -1.905739 17813 58.655182 3.530457 -1.361877 17814 58.919601 2.900696 -0.424301 17815 5.940842 1.276975 -2.557241 17816 5.732897 0.802249 -2.241814 17817 6.247598 0.474533 -2.847308 17818 39.945992 0.906952 -1.933342 17819 53.036255 2.193619 -2.011070 17820 6.725548 -0.289843 -3.331061 17821 54.323608 2.281601 0.923393 17822 54.603149 1.576828 1.909828 17823 53.056061 0.988388 0.632599 17824 50.299103 -1.076218 -2.049988 17825 58.581818 -0.034119 -2.064346 17826 57.807648 -1.082245 -2.204422 17827 6.048261 -1.178305 -2.380859 17828 6.253279 -0.327409 -2.770754 17829 42.329193 -1.426239 -2.172844 17830 56.834900 -1.837112 -2.001694 17831 43.608459 -3.494492 -1.377594 17832 42.287064 -3.862183 -3.061661 17833 48.999146 -4.201355 -1.452606 17834 49.823212 -2.597046 -1.161911 17835 49.576080 -3.583618 -0.386673 17836 48.775848 -4.191452 -2.628799 17837 55.885651 -2.477798 -1.707489 17838 41.649109 -5.999329 -2.514099 17839 43.536652 -4.740738 -1.159012 17840 43.659958 -3.979599 -1.145508 17841 42.859680 -5.502975 -1.758087 17842 52.457611 -7.036819 -1.339951 17843 52.984894 -5.939880 -1.799019 17844 59.527893 -5.193039 -1.339043 17845 58.880249 -5.166290 -1.136353 17846 60.196167 -5.839737 -2.590034 17847 5.158159 -3.846816 -0.801353 17848 60.273773 -7.652969 0.265450 17849 60.180023 -6.717590 0.225998 17850 5.507183 -8.884893 -1.451486 17851 44.414719 -10.177872 -2.114944 17852 45.311249 -9.074417 -1.474686 17853 45.507538 -10.147858 -0.879463 17854 44.583267 -8.912827 -2.875267 17855 47.380463 -6.882675 -1.670540 17856 48.248550 -5.981918 -0.872864 17857 46.804306 -7.639496 -1.879044 17858 52.079727 -7.916443 -1.620346 17859 52.207077 -9.056686 -1.526566 17860 60.877579 -9.380829 -2.346802 17861 5.254400 -9.860583 -0.629099 17862 38.663681 -11.392609 -2.620285 17863 38.145508 -10.164520 -1.975456 17864 43.985580 -9.811234 -3.181824 17865 51.513474 -9.385803 -2.762482 17866 43.462036 -10.729309 -3.287720 17867 52.966797 -9.846085 -1.597099 17868 60.969437 -10.607986 -2.394516 17869 39.428680 -12.288361 -3.363457 17870 52.958847 -10.397598 -2.326828 17871 53.216324 -10.609955 -2.944252 17872 61.098495 -11.555740 -2.395073 17873 5.566626 -10.957243 -1.291958 17874 5.673348 -12.183384 -1.221762 17875 5.229491 -11.100271 -0.219236 17876 5.302533 -12.137414 -0.048700 17877 39.481430 -13.790375 -2.585197 17878 43.009827 -13.624619 -2.314789 17879 42.921204 -12.745667 -2.944244 17880 61.540421 -13.857788 -2.330200 17881 40.811279 -14.664307 -2.840302 17882 40.359070 -15.428802 -2.278038 17883 54.539307 -14.981720 -3.938751 17884 55.397171 -15.059372 -3.979630 17885 54.399765 -15.774185 -3.736328 17886 61.325378 -14.827209 -3.011833 17887 52.452057 -15.932465 -3.734650 17888 53.331268 -16.627487 -3.416504 17889 54.596375 -16.842514 -3.684670 17890 61.712265 -15.394150 -2.495140 17891 48.295639 -17.285583 -3.403412 17892 48.602295 -16.752350 -3.727860 17893 51.606537 -16.875443 -3.479363 17894 49.975098 -17.900879 -2.725952 17895 50.802551 -17.716263 -3.004044 17896 53.305237 -15.891953 -3.474777 17897 54.311127 -17.749039 -3.616745 17898 53.016388 -17.707977 -3.340668 17899 61.947571 -16.539276 -2.252556 17900 58.578949 -18.399948 -4.023399 17901 6.726970 -17.543993 -0.636319 17902 46.836487 -19.030655 -3.767395 17903 53.535263 -21.013138 -3.358704 17904 57.172058 -20.024307 -3.713501 17905 60.065674 -19.376724 -3.090401 17906 61.003357 -18.419800 -2.837822 17907 7.306594 -18.069405 -1.924404 17908 52.248047 -19.844254 -3.361633 17909 52.043213 -18.343399 -3.208893 17910 50.692535 -18.942459 -2.920319 17911 57.002609 -21.582138 -3.205444 17912 57.506393 -21.203964 -3.445000 17913 58.672134 -20.432877 -3.351364 17914 59.838394 -20.920898 -2.507874 17915 61.428940 -19.449905 -1.742203 17916 61.799133 -18.263199 -2.110313 17917 47.360504 -20.533981 -2.912369 17918 46.925125 -19.684021 -3.282036 17919 52.423584 -21.130951 -3.292572 17920 57.856949 -20.786789 -3.492035 17921 7.620669 -18.851294 -1.950880 17922 57.817581 -21.956802 -2.943680 17923 57.623444 -23.085068 -1.808685 17924 53.041275 -21.797546 -3.089417 17925 58.122284 -21.342194 -3.198433 17926 59.862183 -21.852264 -1.671890 17927 60.533173 -21.280319 -1.508881 17928 8.312164 -20.164497 -2.138618 17929 46.115707 -22.051819 -4.159660 17930 21.579220 -25.504341 -5.451604 17931 47.677185 -23.019348 -2.856895 17932 48.028610 -21.659012 -2.705963 17933 47.244919 -21.729660 -2.803146 17934 20.272825 -25.951054 -4.748616 17935 20.574440 -26.764692 -3.941059 17936 21.107840 -26.135920 -4.727292 17937 46.709793 -21.837967 -3.382202 17938 19.368561 -26.003574 -4.509518 17939 18.673903 -26.181965 -4.119023 17940 19.317429 -26.840879 -3.497262 17941 21.945236 -26.967215 -4.064350 17942 21.413774 -26.941420 -3.970325 17943 22.562561 -27.010052 -4.142283 17944 33.096855 -27.507732 -5.234052 17945 32.783604 -27.843832 -4.832263 17946 33.111694 -27.715370 -5.020874 17947 33.384869 -27.666147 -5.117899 17948 22.698763 -27.732658 -3.456816 17949 21.715502 -27.634327 -3.329028 17950 32.220497 -27.667337 -4.925383 17951 31.920885 -27.976519 -4.560307 17952 32.439888 -28.091518 -4.521837 17953 32.752522 -27.381567 -5.305617 17954 33.869656 -27.634838 -5.232196 17955 34.159664 -28.182941 -4.650399 17956 35.247803 -28.113403 -4.695412 17957 48.402740 -25.135803 -3.025620 17958 11.271457 -23.145981 -3.317400 17959 10.731478 -22.861158 -2.940538 17960 11.919554 -23.811453 -3.065939 17961 12.517698 -24.242666 -3.035433 17962 15.762121 -25.758247 -3.416972 17963 21.946455 -28.468901 -2.539415 17964 49.033844 -26.235657 -2.999718 17965 49.981094 -27.149399 -2.863220 17966 51.066803 -27.138168 -3.590668 17967 60.788269 -26.663467 -3.300377 17968 60.292297 -27.354553 -2.785507 17969 58.949875 -27.771759 -2.790665 17970 13.876317 -25.214697 -2.780677 17971 14.629383 -25.492290 -3.013390 17972 24.175991 -28.452656 -3.070709 17973 23.448225 -29.073435 -2.326069 17974 26.955549 -28.408836 -3.561662 17975 27.638237 -28.721413 -3.367551 17976 65.816803 -26.213837 -3.391617 17977 65.693207 -27.114838 -3.081505 17978 28.428083 -28.754162 -3.425397 17979 32.091785 -28.554573 -3.992883 17980 31.274139 -28.946981 -3.519987 17981 65.558228 -27.976654 -2.611397 17982 27.390078 -29.575809 -2.566239 17983 30.741095 -29.500448 -2.938277 17984 35.335953 -29.287704 -4.457474 17985 18.782860 -32.818192 -3.641159 17986 23.735306 -31.593384 -4.939377 17987 24.452103 -33.112213 -4.327698 17988 35.323883 -30.348099 -4.313583 17989 51.399109 -31.838394 -3.927765 17990 55.344147 -32.491791 -3.423218 17991 55.595688 -31.984940 -4.397217 17992 56.415451 -31.695312 -4.610947 17993 56.393280 -32.202545 -3.735893 17994 57.339005 -31.512466 -4.629105 17995 58.396988 -31.513702 -3.562172 17996 57.177338 -31.865997 -4.118347 17997 60.001633 -31.310059 -3.834076 17998 62.309357 -31.294281 -4.063690 17999 27.811478 -33.463058 -5.578659 18000 26.262878 -33.361435 -4.985260 18001 35.229919 -31.364944 -4.143417 18002 50.437363 -32.072357 -3.172859 18003 52.581543 -32.193878 -3.482941 18004 53.317108 -32.658783 -2.307434 18005 54.460938 -32.797760 -2.212410 18006 61.078537 -31.078827 -2.944580 18007 65.578156 -30.889053 -3.535187 18008 13.941704 -33.916901 -4.433784 18009 35.148056 -32.449020 -3.886551 18010 35.767647 -33.719040 -4.699173 18011 48.543793 -32.543518 -3.501907 18012 57.364532 -32.074356 -3.530457 18013 65.292801 -31.790253 -3.881546 18014 12.546440 -34.269470 -5.039665 18015 12.274078 -34.708847 -5.144272 18016 27.484116 -34.811478 -4.473831 18017 30.561279 -36.575195 -4.188263 18018 28.532562 -36.173813 -3.894905 18019 29.180389 -35.514755 -4.711334 18020 12.289612 -35.427872 -5.215637 18021 35.737404 -35.447388 -4.094070 18022 36.311455 -36.342789 -4.630524 18023 47.355865 -37.399612 -1.986816 18024 47.396118 -36.741699 -2.891891 18025 12.622238 -36.352814 -5.510071 18026 12.089706 -36.323807 -5.066650 18027 33.316940 -36.711731 -4.933227 18028 48.709396 -35.779541 -4.208122 18029 51.822418 -36.463333 -4.195343 18030 33.721298 -37.373642 -4.437668 18031 34.069504 -38.493896 -3.659195 18032 33.119804 -38.082199 -3.215744 18033 36.354683 -36.715759 -4.939667 18034 52.645630 -36.894608 -4.324417 18035 14.366707 -38.329224 -5.804405 18036 13.376663 -38.345032 -5.247970 18037 12.430763 -37.287964 -5.127731 18038 15.374176 -39.305725 -5.934875 18039 14.335213 -39.392456 -5.274391 18040 22.715157 -39.830048 -6.125732 18041 15.339050 -40.363998 -5.351547 18042 22.173157 -40.400787 -6.033401 18043 22.938049 -40.894241 -5.569626 18044 24.117615 -40.667801 -5.507370 18045 28.225014 -41.074326 -5.290268 18046 53.708496 -37.983368 -3.225235 18047 28.373878 -42.278397 -4.077782 18048 29.456238 -43.752548 -3.445847 18049 29.918831 -42.899109 -3.848068 18050 61.322891 -42.586212 -4.703216 18051 63.968582 -39.319092 -3.773026 18052 62.893814 -38.830002 -3.481476 18053 62.739243 -40.401276 -4.043625 18054 16.607697 -42.504379 -4.818359 18055 17.338791 -43.436813 -4.322769 18056 23.658813 -41.686493 -4.894722 18057 29.115463 -41.092743 -5.430168 18058 32.346756 -42.216187 -5.184753 18059 32.223404 -43.349182 -4.776916 18060 65.052155 -40.908875 -4.054840 18061 64.089935 -40.752747 -4.350243 18062 20.897644 -42.108826 -5.369751 18063 33.142975 -44.000259 -5.583046 18064 31.949480 -42.371201 -4.646576 18065 31.241806 -42.371719 -4.505752 18066 59.851974 -42.591782 -4.210243 18067 61.899780 -41.466827 -4.198006 18068 64.978836 -39.876266 -3.726173 18069 65.625443 -40.449997 -3.130638 18070 65.642899 -39.343033 -2.787933 18071 65.276733 -42.874252 -3.945847 18072 56.405762 -43.546585 -5.226425 18073 57.438461 -43.332138 -4.766556 18074 65.507095 -41.643661 -3.318848 18075 64.390503 -45.042770 -4.919907 18076 65.001007 -44.529144 -3.922813 18077 64.863098 -45.688828 -3.876106 18078 64.497665 -45.976273 -4.459656 18079 64.561142 -46.393600 -3.801735 18080 20.573395 -48.263550 -5.566818 18081 22.870125 -48.197083 -5.939529 18082 23.077789 -47.641464 -5.483208 18083 23.911484 -47.278748 -4.997955 18084 22.911560 -47.142593 -4.764053 18085 46.482864 -46.730942 -3.698105 18086 45.296295 -47.700058 -3.907822 18087 48.998810 -46.584076 -3.938713 18088 63.510559 -48.172256 -3.669037 18089 19.062889 -49.444901 -6.372597 18090 23.848862 -48.129440 -5.536865 18091 23.328918 -49.027527 -6.052612 18092 31.665819 -49.858475 -4.688759 18093 31.328918 -50.148590 -5.741333 18094 25.821426 -49.323776 -4.634476 18095 24.578705 -49.230515 -5.260406 18096 25.399231 -51.320267 -4.037788 18097 23.809357 -50.132599 -5.667358 18098 45.778046 -48.558640 -5.071205 18099 64.024261 -47.165329 -4.297775 18100 25.333771 -47.841324 -4.756126 18101 54.157684 -49.739868 -5.724518 18102 55.874237 -49.032303 -4.177361 18103 56.877304 -50.395874 -5.076858 18104 55.533401 -49.984451 -4.988510 18105 23.643860 -53.093475 -4.520340 18106 30.605827 -51.404572 -6.164452 18107 29.688278 -52.069031 -6.846771 18108 58.362900 -51.022690 -5.138252 18109 17.355499 -51.922852 -5.368820 18110 30.445480 -54.305099 -6.141640 18111 30.471672 -52.871292 -6.117523 18112 31.144478 -53.422302 -5.143265 18113 29.375504 -53.503998 -6.934547 18114 60.845886 -51.499771 -5.040146 18115 61.503098 -51.582962 -5.471558 18116 16.767563 -52.700500 -5.308403 18117 16.504478 -53.169266 -5.635582 18118 16.709152 -53.917725 -6.329964 18119 21.297585 -53.700516 -6.434799 18120 20.970825 -54.963516 -6.478401 18121 29.520844 -54.559067 -6.865539 18122 31.206192 -54.318298 -5.050690 18123 51.498703 -54.144028 -5.226654 18124 54.187469 -54.748093 -5.884804 18125 22.501801 -53.926575 -4.992256 18126 21.719208 -54.084030 -5.769211 18127 22.945099 -54.623627 -4.633423 18128 23.137833 -53.964813 -4.446022 18129 30.639420 -56.451050 -5.804169 18130 38.918747 -54.829071 -6.114693 18131 40.899475 -55.396591 -6.046585 18132 40.346970 -56.985947 -4.329407 18133 40.361572 -57.511459 -4.313377 18134 41.148956 -57.408203 -4.574684 18135 30.939407 -55.219482 -5.416199 18136 57.632080 -57.407974 -5.951088 18137 16.658585 -57.614304 -5.541664 18138 17.304077 -58.332855 -6.346817 18139 21.833145 -57.673141 -6.346771 18140 30.301071 -58.797424 -5.639374 18141 30.786331 -57.442062 -5.469414 18142 37.114868 -59.519211 -6.540550 18143 37.224281 -58.810287 -6.372856 18144 37.505447 -58.069778 -6.407349 18145 38.020355 -57.626617 -5.364906 18146 48.138596 -58.275574 -6.433411 18147 46.985107 -58.421417 -6.193710 18148 48.236969 -59.271744 -6.165779 18149 49.405548 -59.023605 -6.658676 18150 57.573273 -58.233444 -6.205032 18151 18.114922 -59.431381 -7.069870 18152 22.333778 -58.563217 -6.320213 18153 23.138847 -59.022369 -6.015839 18154 49.002274 -60.274490 -6.518898 18155 57.128052 -58.563110 -5.677902 18156 17.766891 -60.507370 -6.590439 18157 17.803223 -61.420761 -7.242691 18158 23.791641 -59.707153 -5.773018 18159 37.105225 -60.362335 -6.099029 18160 41.259201 -59.514603 -5.684967 18161 42.508911 -59.709702 -6.410850 18162 47.326675 -60.138092 -6.494202 18163 50.204224 -60.478851 -6.817078 18164 56.559021 -60.668274 -6.045273 18165 29.700455 -61.188629 -6.122940 18166 56.257568 -61.111130 -5.731720 18167 16.085388 -62.834518 -7.118477 18168 17.113007 -61.891296 -6.947342 18169 29.312805 -62.316406 -6.704803 18170 37.274353 -61.881393 -6.460030 18171 48.230759 -60.204590 -6.352844 18172 55.905334 -62.097382 -6.277153 18173 29.375656 -63.064743 -6.399750 18174 14.641541 -64.569794 -7.064949 18175 14.970573 -63.695312 -6.983642 18176 20.348068 -65.133560 -6.115776 18177 27.909966 -64.866104 -6.011673 18178 28.989929 -63.935349 -6.182129 18179 27.064339 -65.280228 -6.169830 18180 28.409088 -64.334778 -6.770996 18181 14.967575 -65.890366 -6.527542 18182 15.767456 -66.278168 -6.900207 18183 16.807251 -66.253967 -7.047699 18184 18.385117 -65.968246 -6.086792 18185 18.539886 -65.620956 -5.240333 18186 19.346992 -65.469894 -5.615707 18187 53.369492 -65.688919 -6.472595 18188 41.006012 -67.594376 -6.853363 18189 41.775970 -67.286224 -6.160583 18190 52.157593 -67.251816 -6.878631 18191 52.194519 -66.485214 -6.291931 18192 25.009468 -68.663910 -6.415314 18193 25.100456 -70.215027 -7.119987 18194 43.435516 -68.068283 -6.561584 18195 51.315826 -67.453918 -6.587013 18196 39.804695 -68.104691 -6.369285 18197 43.537643 -68.918121 -6.585373 18198 42.873230 -68.078720 -6.044022 18199 44.154037 -69.025360 -7.210312 18200 12.189636 -70.749222 -7.459007 18201 12.331764 -72.147095 -7.618721 18202 12.722137 -71.857086 -8.155807 18203 12.916917 -69.938309 -7.239868 18204 13.670212 -69.805527 -6.696922 18205 25.298126 -69.344833 -5.526260 18206 25.281281 -70.547577 -5.635658 18207 39.569061 -69.872528 -6.005203 18208 44.016830 -69.840805 -6.995903 18209 43.592667 -69.940674 -6.421173 18210 49.795715 -68.700958 -6.574020 18211 25.034241 -71.310608 -7.109619 18212 44.375656 -70.947571 -6.763183 18213 20.545341 -71.952301 -6.516052 18214 49.241669 -70.603760 -6.639969 18215 13.099663 -72.871475 -7.825966 18216 25.033203 -71.548752 -6.506668 18217 25.084587 -72.620132 -6.828812 18218 45.184296 -72.014923 -6.709961 18219 47.450134 -72.377396 -6.974228 18220 36.353149 -74.419052 -8.507675 18221 40.405243 -72.965576 -6.633438 18222 48.007126 -71.716507 -6.560707 18223 46.971375 -72.660065 -6.459602 18224 15.895508 -74.498352 -7.396133 18225 15.978683 -74.857101 -6.591614 18226 11.312149 -76.442673 -8.530380 18227 16.291573 -76.276184 -7.956802 18228 21.158493 -74.709167 -7.734833 18229 21.444580 -75.657990 -6.910225 18230 9.653915 -78.265747 -7.092438 18231 10.678192 -76.959702 -7.742241 18232 10.232239 -77.496857 -6.279587 18233 13.658112 -76.823517 -6.861778 18234 15.983940 -76.692719 -7.081543 18235 28.664246 -76.499207 -6.620155 18236 28.595161 -76.922150 -7.227386 18237 28.338608 -77.255234 -7.614593 18238 46.779572 -76.756516 -5.996277 18239 9.814606 -78.251083 -5.907555 18240 21.451492 -77.246033 -6.569229 18241 21.900719 -75.903854 -5.517128 18242 27.637123 -78.113541 -7.748749 18243 9.677307 -79.196564 -8.027634 18244 26.699677 -78.707428 -7.070846 18245 27.622871 -78.257217 -6.658325 18246 28.421783 -77.521072 -6.814163 18247 17.009811 -79.938431 -8.127014 18248 17.077225 -79.729614 -7.131546 18249 19.972687 -78.597397 -7.010788 18250 25.750565 -79.687332 -7.383819 18251 11.044099 -80.847977 -7.639442 18252 6.246803 -81.747818 -7.917488 18253 5.893982 -82.669113 -7.785362 18254 7.261978 -82.404373 -6.574013 18255 20.615295 -82.363800 -8.523376 18256 19.472824 -82.228180 -8.193504 18257 26.278542 -81.892563 -7.802505 18258 37.547409 -81.845474 -6.421356 18259 38.323029 -81.573257 -5.621017 18260 39.026283 -81.730011 -6.810760 18261 39.116127 -81.787643 -7.992958 18262 40.080963 -82.007797 -7.521805 18263 6.740173 -81.546539 -6.671974 18264 13.271507 -82.927094 -7.166084 18265 16.545876 -81.619751 -7.733505 18266 19.192520 -81.748154 -4.963715 18267 18.318680 -81.769485 -6.135399 18268 19.825211 -82.012726 -6.209389 18269 21.179619 -82.290878 -7.429672 18270 20.443619 -82.058838 -7.851105 18271 20.182602 -81.994263 -7.209328 18272 26.965790 -83.003174 -8.383194 18273 27.007751 -82.443359 -7.777023 18274 27.472145 -82.797195 -7.705208 18275 37.727074 -81.946854 -7.817306 18276 44.715118 -82.440536 -6.104935 18277 13.302666 -84.107208 -8.572754 18278 27.888313 -83.721313 -7.992950 18279 6.249527 -85.002304 -8.866364 18280 10.971977 -85.157608 -6.973373 18281 14.064437 -85.166763 -8.952301 18282 23.831367 -84.783401 -8.108444 18283 37.050690 -84.268158 -7.767136 18284 37.561981 -84.561676 -7.075523 18285 37.921005 -84.748856 -6.169830 18286 36.889534 -83.791458 -5.799583 18287 43.722260 -83.187103 -6.585831 18288 43.812469 -83.453003 -7.090324 18289 14.979645 -85.913330 -9.023621 18290 28.322021 -85.996613 -8.496140 18291 28.062080 -84.947296 -8.426559 18292 28.014885 -82.771103 -7.093491 18293 12.778656 -86.672775 -6.902794 18294 17.020462 -86.610184 -7.122421 18295 17.545815 -88.471359 -7.876114 18296 22.519218 -87.497574 -6.742157 18297 22.743820 -86.579483 -6.395523 18298 22.521362 -86.748154 -7.380524 18299 28.843361 -86.534348 -7.526321 18300 42.123581 -87.584076 -7.835342 18301 14.159821 -88.096268 -6.928368 18302 21.739311 -87.935822 -8.171387 18303 42.045303 -88.235092 -7.948852 18304 9.193192 -89.393143 -8.621727 18305 23.532562 -88.313324 -6.515030 18306 32.920883 -88.951904 -8.356735 18307 32.200020 -88.678085 -7.663452 18308 34.121689 -88.949585 -7.814026 18309 35.436920 -89.338211 -6.864914 18310 36.852272 -89.824097 -7.411774 18311 37.244461 -90.208710 -7.639000 18312 40.744080 -90.651398 -7.213272 18313 7.645202 -87.851654 -7.686096 18314 8.445183 -88.785751 -7.171692 18315 15.185760 -90.716522 -8.407120 18316 28.019791 -91.078186 -7.625198 18317 26.964401 -90.093948 -7.312637 18318 37.347443 -90.252869 -8.448746 18319 41.382751 -90.025070 -7.404068 18320 41.712158 -89.195465 -7.421570 18321 41.608368 -88.581665 -5.839134 18322 42.060196 -88.257553 -7.042877 18323 10.831451 -91.071609 -8.775665 18324 10.287399 -90.298721 -7.154739 18325 11.310364 -91.551819 -7.158539 18326 37.685333 -90.811905 -8.308792 18327 37.397728 -90.656921 -7.743927 18328 37.649048 -91.631821 -8.592430 18329 15.173759 -92.377106 -8.391693 18330 18.326508 -90.492035 -7.786728 18331 28.547424 -91.748337 -8.541199 18332 29.300903 -91.512405 -7.115166 18333 39.405609 -91.982758 -7.200943 18334 12.359894 -92.635666 -8.600990 18335 16.418274 -95.242630 -8.951935 18336 19.008705 -95.011505 -9.021637 18337 17.508011 -95.274231 -8.468506 18338 19.857849 -94.177216 -7.858749 18339 36.266983 -94.884155 -7.753281 18340 34.961456 -95.621964 -7.947845 18341 13.519623 -97.794189 -9.525421 18342 20.645004 -93.799347 -8.341545 18343 34.055420 -95.952225 -8.805359 18344 32.810013 -96.562378 -8.622681 18345 22.116058 -98.668747 -8.758759 18346 23.000885 -98.436646 -8.987923 18347 24.347305 -99.494446 -9.513451 18348 22.766014 -97.600769 -8.217873 18349 21.995255 -97.823669 -7.619881 18350 24.561707 -100.020813 -10.210899 18351 30.765594 -97.984360 -7.802826 18352 22.000992 -99.711639 -8.701721 18353 21.597801 -101.434509 -9.853539 18354 24.091171 -98.709091 -8.929092 18355 28.014938 -99.205460 -7.887253 18356 26.696594 -99.423248 -8.825302 18357 16.119019 -101.056839 -8.593826 18358 16.823097 -101.561310 -8.628693 18359 21.762398 -101.938980 -8.799194 18360 22.345322 -102.142639 -8.366180 18361 18.096802 -102.099167 -8.641342 18362 21.138992 -102.675247 -3.872650 18363 22.650879 -102.317078 -4.125824 18364 22.544815 -101.989807 -5.277801 18365 10.098625 62.802032 1.011932 18366 11.122063 62.318039 1.333160 18367 9.964378 62.254852 1.155579 18368 14.613319 61.956177 1.950607 18369 13.851669 62.286087 2.006638 18370 11.146408 60.545044 1.713348 18371 9.764252 61.291519 1.137192 18372 3.597694 60.374222 0.668022 18373 5.025589 61.405838 1.571129 18374 13.713821 61.733597 2.517479 18375 13.368057 62.178497 2.103104 18376 15.980377 61.525223 1.867935 18377 16.830185 60.694122 2.495606 18378 18.117661 61.231216 2.107712 18379 19.095139 61.134827 1.510872 18380 18.936722 60.480408 2.419800 18381 3.682198 59.797974 1.743324 18382 9.668365 59.576004 1.192383 18383 8.639259 59.691727 0.884888 18384 3.615051 57.401306 1.884499 18385 3.632614 56.322220 1.734467 18386 4.203758 60.965179 2.225029 18387 3.543961 58.403778 1.629746 18388 8.950684 58.603394 1.733597 18389 8.628548 58.698303 2.724671 18390 7.920707 59.033630 2.276215 18391 10.957367 59.204376 1.468720 18392 11.980133 59.319382 1.871979 18393 11.543999 58.406570 1.535889 18394 7.063095 60.012222 2.356278 18395 10.529785 58.229385 1.517441 18396 9.921234 57.847366 2.396263 18397 12.539482 57.787888 1.994782 18398 11.483292 57.731003 1.577698 18399 22.653496 57.352219 2.703522 18400 10.921776 57.484650 1.852753 18401 24.817307 57.664856 1.444550 18402 24.901993 57.289658 2.049439 18403 11.605049 57.301880 1.906571 18404 28.176498 55.453888 1.572510 18405 27.229713 57.002686 2.848328 18406 28.125214 57.483765 3.724976 18407 27.414459 57.660339 4.018082 18408 28.672211 54.984695 2.219803 18409 28.546440 55.962875 2.543762 18410 28.522308 54.223099 2.546784 18411 39.957703 52.413910 3.110993 18412 39.396805 52.978638 2.986954 18413 3.503014 52.553192 1.321930 18414 26.873344 52.112091 3.455177 18415 27.553116 53.399506 4.432877 18416 36.887772 51.653595 1.288422 18417 36.422493 52.093964 1.977364 18418 38.675705 52.766449 1.711388 18419 38.905365 53.106445 2.452057 18420 40.730026 51.862656 1.586525 18421 22.513214 50.815460 0.557739 18422 23.141594 50.927460 0.895401 18423 41.373657 51.118484 2.078720 18424 40.591766 51.833176 2.683060 18425 2.796372 49.644180 0.782959 18426 2.802467 48.838196 0.609192 18427 35.884811 51.279388 1.768272 18428 42.244095 49.564484 1.529419 18429 3.716858 46.717331 0.268311 18430 3.234093 47.721161 0.531502 18431 23.487015 47.816833 0.850426 18432 9.881470 47.294418 0.956772 18433 10.829971 47.958527 1.991715 18434 9.403625 48.490387 1.622688 18435 10.073577 49.635025 2.646530 18436 24.343330 47.349869 2.215004 18437 24.509529 49.438065 1.764099 18438 32.480774 47.753098 1.660904 18439 34.240265 49.715424 1.690415 18440 33.020355 50.120148 2.807037 18441 4.355911 47.066711 0.725494 18442 12.042847 46.256470 1.605797 18443 24.080292 46.486084 0.972183 18444 43.297653 46.096527 1.051376 18445 41.957489 47.305756 2.578766 18446 41.096436 48.416077 3.129822 18447 3.805595 47.270294 0.776322 18448 30.991959 46.068863 1.747345 18449 30.195419 45.168152 1.392708 18450 42.843567 47.197495 1.577896 18451 42.369980 46.104431 2.041390 18452 11.735451 43.978836 1.639816 18453 11.532059 42.864288 0.587509 18454 25.369354 43.867767 1.266434 18455 29.541832 44.460312 2.415352 18456 29.048920 43.742767 1.867096 18457 37.441254 43.355423 1.309685 18458 38.540070 44.102295 1.654862 18459 41.677246 45.531036 2.275536 18460 41.971069 45.296097 2.021805 18461 42.693619 43.931152 0.933365 18462 42.568634 45.085449 1.490418 18463 3.616943 41.596466 0.480644 18464 6.439873 44.707764 3.450684 18465 5.289414 44.801498 3.718132 18466 27.750145 43.393951 1.116226 18467 38.556946 45.330048 2.809769 18468 3.138054 40.806473 0.872528 18469 8.619102 42.301361 0.668198 18470 8.236237 44.678040 3.332428 18471 7.190827 44.850418 3.673157 18472 10.854050 42.400726 0.728188 18473 10.813187 43.453552 1.837105 18474 10.888657 42.926666 1.249611 18475 34.555000 41.953690 2.066864 18476 34.716232 40.695358 1.048981 18477 34.339943 40.377808 1.339829 18478 2.599808 38.448837 -0.144462 18479 34.544037 39.590286 1.058968 18480 34.425323 39.583649 1.875336 18481 35.976753 38.356110 0.785828 18482 38.120888 37.454330 0.848061 18483 43.690292 36.640503 1.041573 18484 44.195206 36.556427 0.932633 18485 43.924500 37.551697 1.266480 18486 45.065979 39.582123 2.741531 18487 43.864853 39.029724 1.968781 18488 45.288666 38.395325 1.519447 18489 45.896210 37.437256 0.938599 18490 46.611084 38.228577 1.396957 18491 46.680237 37.128281 0.805321 18492 49.316147 37.139954 0.954895 18493 47.835785 37.511688 1.056198 18494 3.744675 36.215332 -0.237854 18495 2.795426 37.130585 -0.270866 18496 4.428642 37.171173 0.562607 18497 4.717545 36.419678 0.266800 18498 3.590164 37.801971 0.438820 18499 39.074753 36.855896 0.808472 18500 43.138519 36.784302 1.158417 18501 44.879791 35.758087 0.822373 18502 46.003418 36.099884 0.684548 18503 45.000015 37.028305 0.936699 18504 47.252884 36.170685 0.529724 18505 6.566582 35.700241 0.261658 18506 7.425003 35.945465 0.695267 18507 5.520767 37.114349 0.913010 18508 40.250305 36.661972 0.933640 18509 40.667236 35.625214 0.200424 18510 46.857925 34.961349 0.483185 18511 41.493698 35.018173 0.008499 18512 42.065552 36.046005 0.786163 18513 9.738251 32.428070 0.800491 18514 46.654861 34.152328 0.554108 18515 46.392212 34.036011 0.634537 18516 52.478821 32.808807 1.080429 18517 53.300934 29.823227 0.546600 18518 53.130951 26.985275 0.712265 18519 2.022003 24.358856 -0.184387 18520 2.602509 24.177414 -0.733475 18521 2.241547 25.358810 -0.103683 18522 2.947853 26.674484 -0.199768 18523 3.993828 26.205872 -0.807083 18524 4.481316 27.757538 -0.244858 18525 4.829559 26.329071 -0.982193 18526 53.306274 28.888199 0.921875 18527 53.010040 27.989868 1.191345 18528 3.269768 25.210281 -0.866631 18529 53.015442 24.585098 0.560402 18530 52.228790 25.208817 1.287949 18531 2.929161 22.790512 -0.867645 18532 52.141693 23.501099 1.230423 18533 1.979797 24.090469 0.477921 18534 2.279961 23.519806 0.006958 18535 31.340553 23.255020 0.122940 18536 34.809021 22.671356 -0.305916 18537 52.952026 23.716415 0.182160 18538 3.194183 21.768341 -1.384605 18539 2.856018 21.688721 -0.659744 18540 29.470901 22.985046 1.000351 18541 30.340919 23.646255 1.143463 18542 28.938156 22.402557 0.611656 18543 52.534119 22.319077 0.341087 18544 28.414139 20.742508 1.482658 18545 29.276276 19.505737 2.119476 18546 29.444260 21.037659 2.497910 18547 27.700890 19.943604 -0.563957 18548 28.101120 21.168518 0.494186 18549 40.778229 22.019897 0.282593 18550 42.058716 21.766602 0.650299 18551 42.053650 21.138702 0.174805 18552 41.530807 20.536301 -0.432404 18553 43.533905 20.082413 0.362732 18554 51.744263 20.849731 0.790863 18555 27.684166 19.242828 0.172882 18556 27.759384 20.052856 0.527542 18557 42.663971 20.262100 -0.083328 18558 51.040863 19.670258 0.755020 18559 44.309158 19.841919 0.868965 18560 47.461136 17.884109 0.742760 18561 28.217667 19.124817 1.000221 18562 28.674805 17.778397 0.849686 18563 28.449249 18.218414 0.868691 18564 48.882919 17.255783 -0.403442 18565 35.918869 15.307190 -0.273010 18566 3.448686 11.986474 0.020455 18567 3.037233 11.688337 1.762735 18568 3.290562 10.735518 0.995265 18569 32.012634 14.771179 0.271782 18570 32.278824 14.536316 -0.031982 18571 3.378548 13.564606 -0.354622 18572 4.116364 10.559588 -1.539628 18573 3.766393 10.602084 -0.543857 18574 3.912804 9.075361 -0.492708 18575 3.813647 11.451096 -1.045578 18576 38.250687 10.610931 0.105408 18577 38.956718 10.365601 -0.941376 18578 4.332133 9.546517 -1.673330 18579 4.695335 9.027869 -2.343411 18580 39.720818 10.327362 -0.608154 18581 43.493881 9.107513 0.215820 18582 42.621429 9.370865 0.053604 18583 44.055084 9.367126 -0.872978 18584 44.917755 9.336136 -1.121399 18585 45.180511 9.021149 -1.078392 18586 55.618164 8.440994 -1.078285 18587 4.530026 7.487778 -1.532902 18588 4.835165 8.082294 -2.332034 18589 4.415966 8.613399 -1.568742 18590 44.759613 8.555695 -0.364075 18591 55.660568 6.735001 -0.176392 18592 56.320633 6.339569 0.278961 18593 55.622375 5.619186 0.269730 18594 57.498688 6.390915 -0.269852 18595 56.763092 6.891968 -0.346214 18596 57.156235 6.152557 0.276283 18597 54.595184 3.403610 0.276886 18598 5.478477 4.527105 -2.513534 18599 4.584176 5.168420 -1.416699 18600 5.032703 4.337447 -1.923790 18601 4.478822 2.911481 -1.024330 18602 5.062706 2.281310 -1.615580 18603 39.330879 2.519241 -1.608749 18604 40.761246 2.545166 -1.539795 18605 39.899048 2.681686 -1.484879 18606 44.896118 2.912506 -1.333061 18607 39.099579 1.678528 -1.357422 18608 39.907722 2.149170 -1.003922 18609 39.211105 1.832321 -0.812622 18610 42.254410 2.026840 -1.433929 18611 43.563431 1.630569 -1.224442 18612 43.661621 0.774612 -0.423927 18613 44.475189 1.310181 -0.485642 18614 44.542938 2.097061 -1.127258 18615 45.217667 2.877243 0.179634 18616 5.167760 1.005191 -1.501387 18617 5.301961 1.666738 -1.799330 18618 4.472266 1.674769 -0.661181 18619 40.635880 -1.450119 -0.260452 18620 40.078064 -0.435272 -0.676315 18621 4.711350 0.632584 -0.733445 18622 5.397570 -2.876977 -1.262498 18623 5.227722 -1.555307 -1.095815 18624 5.927694 -0.197250 -2.380599 18625 5.730925 -0.644678 -2.056549 18626 55.550629 -2.376389 -0.557190 18627 56.596909 -1.750854 -0.634857 18628 57.483353 -1.194382 -1.108864 18629 58.407669 -0.203888 -1.034538 18630 42.749771 -4.203644 -2.506241 18631 51.602997 -0.255432 -0.288483 18632 50.688690 -1.587311 0.006226 18633 50.026062 -2.579895 -0.172577 18634 49.925751 -3.237534 0.380051 18635 55.069855 -2.942154 -1.280403 18636 53.464935 -5.133438 -0.372131 18637 60.188171 -5.790894 -1.490944 18638 59.613434 -5.203522 -0.482376 18639 41.916428 -6.740311 -1.804108 18640 5.154356 -6.219026 -0.795364 18641 5.484798 -7.436374 -1.480334 18642 39.454758 -7.521271 -2.875442 18643 49.249435 -4.823975 0.169273 18644 48.820969 -6.247803 0.345711 18645 5.138350 -8.519207 -0.560091 18646 39.142715 -8.623688 -2.295258 18647 40.099182 -8.026367 -2.142830 18648 45.930069 -7.872070 -2.171829 18649 45.265808 -8.408752 -2.147461 18650 46.356339 -8.151093 -1.655373 18651 45.704987 -8.356949 -1.677338 18652 46.441589 -7.755188 -2.131210 18653 56.525146 -6.989883 -1.465012 18654 40.346161 -9.440308 -1.084000 18655 41.381317 -7.981323 -1.390907 18656 38.498138 -9.166840 -2.148575 18657 38.280151 -9.503021 -2.088669 18658 44.880493 -9.084167 -2.103653 18659 37.389160 -11.234192 -0.857475 18660 43.565582 -11.619446 -2.543243 18661 61.227020 -10.516541 -1.275467 18662 43.986725 -12.391235 -1.598244 18663 43.460419 -13.982697 -1.398636 18664 42.731293 -15.357178 -1.461044 18665 42.510071 -14.699432 -2.261124 18666 61.560745 -12.540894 -1.764885 18667 62.377502 -12.937683 -0.370178 18668 62.300720 -11.570084 0.251175 18669 61.765244 -11.630707 -0.881325 18670 5.841555 -15.251345 0.106620 18671 6.165360 -16.349636 0.029213 18672 41.135742 -15.561615 -2.479706 18673 37.244522 -13.516129 -0.401482 18674 36.514168 -12.129150 -0.378540 18675 41.736694 -15.260666 -2.562836 18676 62.406158 -10.961716 0.993759 18677 61.766479 -10.592560 0.210922 18678 38.451271 -13.840851 -1.513893 18679 39.154419 -15.914551 -1.390724 18680 38.031174 -15.710678 -0.462601 18681 42.188538 -15.533539 -2.117477 18682 41.572357 -16.292587 -1.653458 18683 40.110550 -16.127686 -1.817413 18684 49.067184 -17.811356 -2.771667 18685 62.251328 -14.619751 -1.112144 18686 62.213730 -15.736755 -1.448433 18687 47.865814 -18.734863 -2.959305 18688 50.722260 -21.089859 -2.986191 18689 62.197052 -17.457748 -1.785576 18690 7.176891 -18.438864 -1.105902 18691 7.534773 -19.170330 -1.272220 18692 49.616516 -19.726120 -2.785408 18693 49.320587 -18.718430 -2.619141 18694 7.748037 -19.830757 -0.983815 18695 48.824570 -20.652359 -2.819443 18696 48.551331 -19.629135 -2.671249 18697 49.721802 -22.195572 -2.856369 18698 50.387604 -22.605789 -2.721161 18699 60.771896 -20.454956 -2.099686 18700 51.138580 -22.810135 -2.558121 18701 49.134232 -21.600998 -2.851379 18702 52.238892 -22.585083 -2.609848 18703 8.173262 -20.407370 -1.546264 18704 48.824478 -22.605759 -2.672523 18705 49.680054 -23.101089 -2.588219 18706 53.773560 -22.789001 -2.423721 18707 58.073044 -23.896118 -0.651833 18708 58.524796 -23.437164 -0.616074 18709 58.836792 -21.971481 -2.421158 18710 8.671738 -20.657204 -2.434370 18711 8.413181 -20.574108 -1.999196 18712 50.411133 -23.994461 -2.140617 18713 51.561630 -23.998993 -1.891632 18714 58.824371 -22.850113 -1.427269 18715 59.465378 -22.420059 -1.339417 18716 8.905752 -21.063862 -2.395117 18717 47.549759 -24.276642 -3.319885 18718 63.512634 -24.838684 -3.428642 18719 9.237477 -21.397669 -2.549414 18720 33.280804 -27.845598 -4.910587 18721 61.230042 -26.938797 -2.753601 18722 65.395691 -25.793655 -3.055206 18723 19.213100 -27.517843 -2.682019 18724 20.872738 -28.843744 -1.820439 18725 21.875244 -29.369688 -1.617274 18726 20.452675 -27.804472 -2.796307 18727 20.055470 -28.519396 -1.880686 18728 33.160904 -28.898621 -3.742909 18729 33.139484 -28.471565 -4.210394 18730 33.183517 -28.137554 -4.580499 18731 48.096573 -24.212128 -2.819519 18732 9.515544 -22.072599 -2.030026 18733 10.174586 -22.603971 -2.385108 18734 11.434896 -23.627565 -2.697912 18735 15.595397 -26.136986 -2.704255 18736 15.278596 -26.477667 -1.891260 18737 15.617882 -27.142780 -1.065317 18738 16.461960 -26.916126 -2.083489 18739 49.613373 -26.636566 -2.218124 18740 49.653091 -25.480087 -2.122635 18741 54.834335 -28.904694 -2.154533 18742 52.628296 -28.678864 -1.519814 18743 57.658142 -27.761032 -2.990883 18744 62.979675 -27.448471 -1.819260 18745 61.546890 -27.704117 -2.013641 18746 10.978021 -23.437719 -2.289650 18747 11.217429 -23.857206 -1.879423 18748 12.144755 -24.469898 -2.057996 18749 13.148952 -24.726191 -2.859656 18750 23.130934 -28.345579 -2.955438 18751 34.347057 -28.896084 -3.952446 18752 24.145700 -29.616816 -1.973018 18753 25.137716 -29.990782 -1.847009 18754 26.042061 -29.630411 -2.330411 18755 32.005184 -29.403822 -3.106845 18756 22.517006 -32.301529 -4.075485 18757 21.535690 -32.136322 -4.079330 18758 24.215754 -30.146687 -1.503850 18759 28.437260 -30.241486 -2.098308 18760 28.293482 -31.190475 -1.279998 18761 27.387077 -30.607590 -1.677557 18762 30.891186 -30.254723 -2.229159 18763 30.642487 -31.106356 -1.437032 18764 31.655668 -31.205303 -1.385873 18765 34.538055 -31.531082 -2.887390 18766 34.589859 -32.529694 -2.952950 18767 62.365875 -30.972992 -3.075058 18768 15.611076 -33.039474 -4.313797 18769 48.359756 -32.513657 -2.231888 18770 57.710678 -31.783524 -3.010613 18771 59.951752 -31.057770 -2.623947 18772 61.034775 -30.681519 -1.970139 18773 63.684174 -29.637360 -1.204178 18774 13.119598 -33.924133 -4.938957 18775 35.019478 -33.744659 -3.437134 18776 57.008316 -31.989090 -2.778061 18777 12.804489 -34.232788 -4.564560 18778 12.277383 -34.791260 -4.681282 18779 23.783173 -34.046112 -3.520554 18780 23.102180 -33.277420 -3.681305 18781 23.781120 -35.029938 -2.793533 18782 25.237282 -34.300903 -3.888008 18783 25.673615 -35.257645 -3.414047 18784 11.949936 -35.822937 -4.281349 18785 46.954071 -35.189255 -3.422592 18786 47.709152 -35.973007 -3.628311 18787 11.771210 -36.697174 -4.706085 18788 11.392296 -36.787064 -3.965408 18789 12.633049 -35.723923 -3.300354 18790 11.849960 -36.481583 -3.030045 18791 29.334480 -37.248245 -3.146088 18792 28.058090 -36.837219 -3.067200 18793 31.586639 -35.918427 -4.998215 18794 46.800430 -35.995895 -3.039810 18795 11.673691 -37.583694 -4.482635 18796 11.119293 -37.633423 -3.712791 18797 31.752123 -37.363632 -3.847107 18798 32.085876 -36.796448 -4.424164 18799 32.924774 -36.862823 -4.535065 18800 32.665131 -37.397751 -3.953751 18801 34.791672 -35.539932 -2.897522 18802 35.293228 -36.691040 -3.724739 18803 34.658409 -37.490494 -2.944710 18804 52.367035 -36.848297 -3.625595 18805 52.918762 -37.261749 -3.720306 18806 12.462196 -38.584473 -4.619965 18807 35.726418 -36.830246 -4.513351 18808 35.059433 -37.704422 -3.974213 18809 34.560852 -37.929428 -4.244156 18810 13.411377 -39.425385 -4.753731 18811 34.698288 -38.431870 -3.778099 18812 60.816116 -40.258347 -3.426010 18813 61.218353 -41.615723 -3.920883 18814 62.722427 -37.390305 -2.608307 18815 61.333878 -37.101059 -2.185577 18816 61.701599 -38.475983 -3.053589 18817 65.022369 -38.495300 -3.064590 18818 64.603043 -37.319778 -2.493851 18819 63.873291 -37.899597 -2.971832 18820 14.352921 -40.891754 -4.484856 18821 65.642426 -38.354218 -2.307396 18822 15.714462 -41.743942 -4.854645 18823 54.659836 -39.446320 -3.620476 18824 62.075775 -39.559982 -3.599854 18825 12.742332 -40.306488 -3.702553 18826 21.705826 -42.779831 -4.250351 18827 22.851288 -42.119217 -4.653465 18828 23.682457 -42.264481 -4.344597 18829 30.049706 -41.914200 -4.621704 18830 31.766733 -41.780243 -4.998855 18831 16.129616 -42.961212 -4.338394 18832 16.261505 -44.073471 -4.001602 18833 18.845749 -43.142227 -4.533615 18834 18.909088 -44.752167 -3.463676 18835 20.142181 -42.764359 -4.721680 18836 56.132874 -41.449585 -3.203247 18837 55.542450 -40.515015 -3.056595 18838 56.409363 -40.945724 -2.811279 18839 55.926163 -40.261703 -2.680740 18840 60.005859 -41.626709 -3.510147 18841 59.281097 -42.166595 -3.558563 18842 60.739914 -42.026886 -3.938629 18843 30.921150 -43.608032 -3.988434 18844 56.367844 -42.823837 -4.580284 18845 58.084473 -42.552612 -3.836922 18846 57.134842 -41.693146 -3.111961 18847 58.219315 -41.637955 -3.042877 18848 31.903200 -44.375641 -4.250076 18849 32.709061 -44.363266 -4.721825 18850 33.049210 -44.869629 -5.042015 18851 32.948349 -45.745575 -4.881424 18852 21.866928 -46.955994 -4.051422 18853 22.922791 -46.443665 -3.878845 18854 24.675140 -46.750015 -4.319138 18855 23.760963 -46.524155 -4.187515 18856 32.711060 -46.896469 -4.633530 18857 45.452606 -47.088226 -3.217407 18858 45.893494 -47.009476 -2.411842 18859 47.914032 -46.580399 -4.465515 18860 20.301910 -48.452393 -4.125122 18861 21.178604 -47.782898 -4.896454 18862 26.456451 -48.588165 -4.489021 18863 32.532555 -47.961288 -4.854652 18864 45.082672 -48.818344 -3.896072 18865 51.904297 -45.667862 -1.153351 18866 52.580261 -45.849594 -1.308945 18867 52.277161 -46.519043 -2.553757 18868 51.009399 -45.788376 -1.580849 18869 52.747345 -48.202866 -4.519272 18870 54.272064 -49.264648 -4.873306 18871 50.123413 -46.380585 -2.969086 18872 53.554031 -47.477325 -3.429535 18873 57.526367 -48.584808 -3.423065 18874 57.512436 -49.570282 -4.152954 18875 63.085159 -48.925339 -3.438705 18876 18.158951 -51.667038 -4.733147 18877 17.433044 -52.481369 -4.647247 18878 18.142685 -50.913757 -5.418625 18879 31.325256 -51.117050 -4.946976 18880 32.056992 -48.704681 -4.423942 18881 54.169876 -48.381546 -4.076782 18882 54.713333 -47.630463 -3.308197 18883 56.128586 -47.633011 -2.932068 18884 31.042702 -50.406921 -3.877708 18885 58.237000 -50.242371 -4.458618 18886 59.337585 -50.471436 -4.258926 18887 60.597153 -50.758575 -4.175705 18888 61.534729 -51.091537 -4.719894 18889 62.354462 -49.533875 -3.495300 18890 49.896530 -53.265549 -4.741562 18891 48.832123 -52.325226 -4.872764 18892 58.834473 -49.367966 -3.604828 18893 31.141647 -52.278854 -5.101967 18894 48.795181 -52.993118 -4.248138 18895 23.434769 -55.532776 -4.845749 18896 16.126770 -54.907455 -5.396202 18897 39.120193 -55.261047 -5.671623 18898 38.889969 -56.200119 -5.295929 18899 39.959938 -55.559418 -5.374245 18900 39.266357 -57.644699 -4.490997 18901 40.093903 -56.383957 -4.721786 18902 41.130295 -56.692474 -4.711601 18903 41.154022 -56.095764 -5.250122 18904 43.985962 -56.903336 -5.788841 18905 43.910797 -57.707413 -5.447815 18906 56.870117 -57.223984 -5.258186 18907 55.674988 -56.637253 -4.860092 18908 57.300079 -56.568069 -5.690201 18909 16.266235 -56.352219 -5.027527 18910 43.238724 -57.853500 -5.186569 18911 17.518967 -59.683746 -6.145637 18912 23.619171 -57.355072 -5.358688 18913 30.308655 -59.644272 -4.899200 18914 30.450302 -59.441864 -5.387924 18915 37.538712 -60.480804 -5.424255 18916 37.445312 -59.112411 -5.603401 18917 56.070618 -58.412003 -4.690712 18918 24.333153 -58.663330 -5.327209 18919 24.620163 -59.660461 -5.159088 18920 43.589783 -58.471695 -5.487503 18921 42.653763 -58.574173 -5.454292 18922 41.680466 -58.160660 -5.008583 18923 23.887779 -60.969208 -5.397110 18924 24.796623 -60.663788 -4.364983 18925 23.716843 -62.400818 -4.250855 18926 30.179176 -59.988449 -5.607780 18927 15.336884 -61.833420 -5.951492 18928 14.445007 -62.815903 -6.192093 18929 17.330475 -61.180893 -6.453819 18930 17.195892 -60.479599 -5.855217 18931 16.474808 -61.292465 -5.995232 18932 38.140846 -61.406937 -5.682419 18933 56.644028 -59.893936 -5.422165 18934 13.162064 -62.783249 -5.168945 18935 13.572815 -63.585037 -5.959152 18936 29.589188 -63.045364 -5.652313 18937 29.703049 -62.163376 -5.774704 18938 14.172852 -63.836319 -6.541687 18939 38.356667 -60.354706 -4.909363 18940 39.429344 -59.371567 -4.615860 18941 40.575272 -58.256622 -4.675514 18942 55.533249 -61.869919 -5.160080 18943 22.688263 -63.136520 -5.549461 18944 29.044510 -63.080002 -3.731476 18945 28.350052 -64.146683 -2.923569 18946 28.723457 -64.449387 -4.468445 18947 55.796219 -60.235291 -4.691605 18948 21.561249 -64.426483 -5.419716 18949 22.251678 -63.949097 -4.523292 18950 53.422394 -64.560837 -5.493423 18951 54.178619 -63.926636 -5.465805 18952 54.875458 -63.078751 -5.388229 18953 26.670425 -65.578079 -6.218323 18954 50.219330 -66.463058 -5.836250 18955 49.323563 -65.247574 -5.209015 18956 50.477966 -64.976776 -5.140121 18957 48.080399 -65.247879 -5.031074 18958 48.941071 -66.560272 -5.708496 18959 15.690262 -66.391983 -5.906921 18960 16.679359 -66.411407 -5.358848 18961 17.520401 -66.316223 -6.204018 18962 40.219971 -67.494980 -5.871963 18963 48.718277 -70.150375 -6.149643 18964 48.007965 -69.250473 -5.797058 18965 51.256454 -66.089386 -5.792549 18966 52.118439 -64.822876 -5.265419 18967 39.345467 -68.074554 -5.738495 18968 41.943634 -68.098129 -4.878464 18969 42.879211 -69.202042 -5.500275 18970 47.765320 -67.730423 -5.609566 18971 47.016647 -66.723450 -5.245552 18972 47.896927 -66.400360 -5.478348 18973 46.104156 -67.313873 -4.559471 18974 46.708527 -68.941238 -4.831650 18975 13.058266 -69.547897 -6.729217 18976 12.941498 -69.392624 -6.500313 18977 12.758209 -69.560028 -6.528473 18978 13.130333 -69.497253 -6.413551 18979 19.626282 -69.226013 -6.218666 18980 20.078903 -69.583298 -6.506470 18981 20.152397 -69.152084 -5.859604 18982 20.557533 -69.411850 -5.850891 18983 38.888489 -68.846664 -5.159737 18984 49.423859 -69.920563 -6.527359 18985 11.556313 -70.231125 -6.597671 18986 11.280183 -70.905182 -6.497818 18987 12.160332 -69.878433 -6.503776 18988 15.014397 -70.087509 -6.911346 18989 18.518669 -69.077667 -4.329803 18990 17.312012 -69.694046 -4.286560 18991 18.004547 -69.701706 -5.490814 18992 20.776718 -71.394470 -4.903221 18993 21.034973 -71.348434 -3.869125 18994 21.315948 -70.578491 -3.880005 18995 43.423187 -70.561462 -5.626923 18996 47.352203 -70.681320 -5.315514 18997 48.843704 -70.824371 -6.355537 18998 44.307434 -71.902008 -4.944611 18999 44.477142 -71.734711 -5.853165 19000 43.621674 -71.357803 -5.153587 19001 46.991486 -72.089203 -5.816360 19002 20.375771 -72.400833 -5.401878 19003 20.590286 -72.960876 -6.917679 19004 48.401505 -70.992432 -6.163971 19005 46.453049 -72.666382 -6.063667 19006 45.634415 -72.206390 -5.192291 19007 12.338379 -73.054428 -5.621017 19008 11.404296 -72.400192 -5.059173 19009 12.169937 -72.679810 -4.423256 19010 13.838348 -73.640518 -7.013260 19011 20.811188 -73.832138 -6.720001 19012 20.446999 -72.914246 -6.295135 19013 21.267975 -74.385239 -5.535904 19014 20.537994 -73.286331 -5.558411 19015 39.973953 -73.562531 -5.853363 19016 40.536316 -74.144028 -5.858353 19017 16.610344 -75.544235 -6.703651 19018 20.848953 -73.435715 -4.615394 19019 41.801285 -75.109711 -5.269813 19020 12.182952 -76.660065 -6.942779 19021 16.498672 -76.128616 -6.974411 19022 21.949905 -74.735092 -4.760788 19023 28.166229 -75.688660 -6.542740 19024 10.937340 -77.013977 -6.188995 19025 10.753723 -77.753799 -4.643112 19026 12.020248 -77.047256 -5.533264 19027 12.781929 -77.487076 -4.767891 19028 40.474747 -74.295013 -4.825882 19029 39.909828 -73.721924 -5.277817 19030 42.553741 -75.883347 -6.436706 19031 44.859680 -75.997711 -5.516937 19032 43.979523 -75.879227 -5.303345 19033 43.088470 -75.825928 -5.609833 19034 45.917511 -76.165802 -5.589218 19035 21.273712 -77.442413 -7.708053 19036 28.762337 -77.031433 -5.919800 19037 9.808998 -79.468979 -7.060715 19038 19.159149 -78.644043 -6.098312 19039 17.887756 -79.365234 -7.417366 19040 20.773811 -78.021790 -6.189232 19041 21.570053 -77.191467 -5.629333 19042 47.485016 -78.670044 -6.001404 19043 47.630783 -77.424210 -5.216995 19044 10.318718 -80.248291 -6.145294 19045 20.797562 -78.143784 -7.100052 19046 25.883286 -79.913589 -5.659592 19047 26.752754 -78.788681 -5.805176 19048 26.151062 -79.043503 -4.541321 19049 6.491860 -81.485779 -6.616417 19050 25.772507 -80.591354 -6.870582 19051 6.232308 -82.211014 -6.319870 19052 12.651993 -81.421371 -5.562027 19053 13.161224 -82.080200 -6.233139 19054 12.505257 -81.617752 -6.611298 19055 17.713165 -82.030106 -7.599281 19056 22.255051 -82.723892 -6.400810 19057 22.331985 -82.497513 -5.017616 19058 20.843567 -82.151535 -5.224869 19059 36.750542 -82.704849 -7.303741 19060 36.748055 -82.657211 -6.038444 19061 40.557755 -82.156494 -6.593750 19062 46.159897 -80.791824 -4.759109 19063 5.888443 -84.491730 -6.696983 19064 5.840134 -82.678101 -6.790359 19065 5.710426 -83.191177 -6.144951 19066 19.128586 -82.069992 -7.078247 19067 27.154129 -82.067856 -6.900070 19068 28.536743 -82.664932 -6.248718 19069 27.819176 -82.035645 -6.163071 19070 28.950516 -83.452423 -6.284317 19071 28.675171 -82.800720 -5.514923 19072 28.675537 -83.600128 -5.411262 19073 39.483170 -81.819092 -5.718727 19074 11.885468 -85.497055 -5.390785 19075 10.193680 -84.404388 -5.320297 19076 23.906509 -83.961487 -6.443390 19077 23.356689 -83.051163 -5.407051 19078 28.653679 -83.613052 -7.071014 19079 36.732712 -83.615433 -6.994842 19080 40.764297 -82.115295 -5.478836 19081 42.223083 -82.744217 -6.190018 19082 5.908875 -84.416855 -7.974090 19083 23.919037 -84.818665 -7.431389 19084 28.597183 -84.474762 -7.535324 19085 28.906898 -84.459930 -6.571152 19086 15.055328 -84.149673 -5.953888 19087 13.792816 -82.569733 -5.453964 19088 15.191833 -85.200348 -7.690529 19089 23.498917 -85.744705 -6.728523 19090 24.371765 -84.885513 -5.724785 19091 24.092545 -84.843765 -6.679314 19092 28.684204 -85.376556 -7.452148 19093 28.949593 -85.626221 -6.384735 19094 37.808914 -84.728806 -4.993713 19095 39.005981 -85.275101 -5.992210 19096 38.739136 -85.167755 -7.020386 19097 40.361588 -86.684540 -4.495926 19098 40.811554 -86.376434 -6.088501 19099 41.300934 -87.183060 -5.609695 19100 16.557655 -85.333832 -5.924248 19101 17.324661 -86.068176 -6.100487 19102 22.081032 -87.611725 -7.650833 19103 41.441666 -86.800186 -6.582840 19104 29.138741 -87.252853 -7.354248 19105 41.841644 -87.529785 -6.642578 19106 17.936768 -87.254745 -6.164070 19107 32.861313 -88.402313 -6.840347 19108 31.581390 -88.146820 -6.471519 19109 33.537346 -88.505142 -7.155243 19110 33.105499 -88.636200 -7.587013 19111 42.133362 -87.682343 -7.389702 19112 9.307564 -89.389481 -6.926590 19113 17.944122 -89.863525 -8.188293 19114 24.034195 -87.961700 -5.061493 19115 23.141373 -87.521545 -5.338837 19116 24.977585 -88.858719 -6.695885 19117 24.543648 -88.405670 -5.689789 19118 22.761635 -87.597153 -5.984329 19119 26.253532 -90.044220 -8.650024 19120 25.882889 -89.442673 -7.576950 19121 31.211578 -88.603928 -7.705032 19122 36.352333 -89.594421 -7.429138 19123 14.729675 -89.442627 -7.965279 19124 15.290398 -89.691040 -6.806450 19125 15.728149 -91.261795 -7.012283 19126 15.984818 -90.370560 -5.992798 19127 18.344109 -89.719818 -7.028953 19128 12.192123 -93.167557 -6.733025 19129 12.888474 -93.891678 -7.970779 19130 35.935410 -91.354172 -7.438873 19131 40.060272 -91.410049 -7.053131 19132 11.827087 -91.315338 -5.496582 19133 12.472565 -92.592834 -5.167282 19134 15.696686 -94.521942 -7.871025 19135 15.462044 -93.713120 -7.860245 19136 20.524384 -93.214676 -8.239319 19137 13.277084 -95.152328 -8.408783 19138 16.393715 -95.092667 -7.970634 19139 16.906403 -94.830750 -7.247261 19140 16.055267 -94.422043 -7.414200 19141 18.133965 -94.446030 -7.285393 19142 20.352432 -93.478775 -7.753769 19143 34.896667 -95.518250 -6.883652 19144 36.108200 -94.752441 -5.714538 19145 13.312149 -97.079193 -8.127739 19146 17.249580 -95.157211 -7.666969 19147 24.455719 -95.063354 -6.348389 19148 24.847595 -95.916916 -7.350685 19149 23.693344 -96.355103 -7.352173 19150 24.590599 -96.663712 -7.858749 19151 25.638718 -96.459183 -7.389488 19152 24.924332 -97.681107 -8.095352 19153 33.433762 -96.206512 -7.663063 19154 33.487167 -96.040710 -6.492050 19155 23.848206 -97.258041 -8.172440 19156 22.529327 -96.890686 -6.834267 19157 29.374649 -98.692337 -8.095856 19158 31.989321 -97.117722 -7.836899 19159 23.670547 -97.988831 -8.577156 19160 13.998458 -98.683716 -8.540573 19161 14.599166 -99.555908 -8.871391 19162 25.457443 -98.986679 -8.599419 19163 31.588692 -97.650421 -6.929489 19164 31.085205 -98.147369 -6.364464 19165 22.712112 -101.340958 -8.683067 19166 26.678474 -98.917801 -7.776138 19167 22.988327 -101.267288 -8.271370 19168 22.662819 -101.790924 -8.320770 19169 17.395004 -101.615265 -7.519379 19170 12.526482 61.595398 2.115151 19171 15.036240 60.912094 2.606308 19172 13.660461 60.612045 2.647377 19173 5.403740 61.284851 2.703613 19174 13.033187 61.185181 2.568543 19175 17.865860 60.494537 2.647934 19176 12.573944 60.466125 2.266541 19177 20.030594 60.065521 2.461517 19178 20.154037 58.408539 2.786545 19179 13.276680 59.388702 2.302048 19180 14.393204 59.693787 2.630554 19181 14.237183 58.365829 2.365936 19182 19.258087 59.646500 2.758438 19183 15.560669 59.253418 2.649010 19184 14.000626 56.681595 2.519852 19185 15.502846 57.563477 2.436493 19186 4.161621 56.811829 3.513878 19187 3.999558 59.054871 4.062065 19188 5.153084 58.028107 5.799140 19189 9.624313 58.687729 3.635773 19190 17.507141 58.758087 2.706787 19191 23.998062 56.826080 2.652748 19192 5.221153 56.205109 4.656418 19193 11.151596 57.120438 2.625656 19194 11.860718 56.637634 2.525887 19195 12.049652 56.594971 2.973297 19196 11.914062 56.962280 2.218872 19197 12.572060 56.674164 2.555351 19198 16.534203 56.787079 2.464264 19199 17.975647 56.178513 2.845917 19200 23.101959 56.864136 2.669769 19201 25.080147 56.801453 2.616226 19202 25.812172 56.959793 2.359665 19203 25.835320 56.786270 2.993691 19204 25.976196 57.271240 4.111862 19205 3.860275 55.519592 2.404694 19206 4.456947 55.537643 3.468216 19207 4.203590 54.599945 2.917297 19208 13.185188 56.477631 3.554474 19209 16.585625 55.996948 2.485016 19210 15.576424 56.086899 2.514725 19211 16.557159 55.494019 2.812111 19212 22.673836 56.747086 2.819260 19213 22.966034 56.006027 3.103394 19214 23.038086 55.213974 3.840370 19215 22.647079 55.050064 3.400696 19216 23.770081 56.025970 3.857506 19217 24.862801 56.590271 3.519905 19218 28.718063 56.877441 3.526886 19219 3.701546 54.452713 2.025436 19220 14.288269 55.810806 3.239899 19221 14.760300 55.794113 2.774628 19222 15.533195 55.293274 3.381462 19223 29.270355 56.107300 3.832054 19224 3.678635 53.490723 2.013458 19225 28.851089 54.935425 3.335877 19226 36.349182 53.084793 2.767365 19227 37.905045 53.272232 2.701248 19228 37.869568 53.806152 3.632858 19229 37.151932 53.842255 3.757248 19230 35.418488 52.185165 2.507111 19231 36.032104 54.045822 4.092369 19232 35.190430 53.606201 3.526558 19233 26.236801 51.382202 2.234314 19234 26.315788 51.196396 3.484787 19235 25.771988 50.188553 2.691132 19236 25.523911 50.396912 1.976784 19237 34.454254 51.130020 2.506157 19238 41.619324 49.854599 2.449631 19239 3.331055 48.643188 1.185272 19240 8.391083 50.201370 2.260208 19241 6.711617 50.528961 2.223839 19242 4.181641 48.106415 1.222229 19243 5.969048 49.268417 1.769158 19244 5.085327 48.970612 1.680084 19245 4.351769 49.398483 1.824974 19246 11.155472 49.238129 3.130463 19247 12.138779 48.245117 3.247803 19248 12.739159 46.596130 2.951202 19249 27.526230 47.114594 6.125000 19250 26.651260 45.403656 6.084442 19251 27.590309 45.424591 5.319870 19252 12.723344 45.655563 2.130264 19253 12.684212 45.348038 2.608978 19254 12.411987 44.998413 1.732880 19255 24.187775 44.533798 3.337540 19256 24.001114 46.415131 3.468323 19257 4.201592 44.483139 3.690682 19258 3.718689 42.692322 1.649056 19259 9.026199 43.374374 1.764633 19260 28.243912 43.148407 1.999680 19261 37.271927 44.237045 2.293770 19262 36.140907 44.607422 3.052406 19263 39.916672 46.302383 3.136284 19264 41.262939 46.191681 2.641792 19265 10.126228 43.117767 1.595718 19266 27.036774 42.871353 1.928742 19267 27.245094 42.618378 2.849289 19268 28.161285 43.021515 2.840912 19269 27.745079 43.465836 3.787163 19270 3.472260 41.903336 1.832687 19271 3.653893 40.804901 1.728142 19272 33.874619 40.827698 2.150040 19273 33.511566 40.855103 3.009224 19274 33.760345 41.935440 3.163986 19275 33.760925 39.990494 2.865936 19276 33.686707 40.280624 2.342407 19277 43.657990 39.952667 2.815445 19278 42.811142 40.193329 3.179665 19279 42.690018 39.563873 2.427269 19280 46.255371 39.121094 2.036293 19281 3.489319 39.417603 0.973663 19282 34.501205 39.505615 2.952927 19283 35.837692 39.207947 2.725067 19284 40.246094 39.761948 2.750008 19285 41.414459 39.148956 2.226334 19286 41.570358 40.056259 3.049118 19287 46.369949 39.493469 2.650299 19288 48.904007 38.046646 1.771698 19289 47.530579 39.013077 2.511520 19290 50.416534 38.041962 3.391579 19291 50.277267 38.581879 4.052330 19292 49.574326 38.868256 4.065842 19293 4.496658 38.370743 1.170113 19294 35.777374 38.627625 1.512848 19295 36.804413 38.632187 1.968277 19296 39.358566 37.749847 1.473541 19297 38.107689 38.523682 1.952812 19298 43.735443 35.823364 0.871658 19299 42.526840 38.081909 1.599068 19300 8.318710 36.201447 1.242058 19301 7.050881 36.952072 1.299278 19302 40.955872 37.815430 1.528931 19303 40.059448 38.741821 2.114288 19304 39.164253 38.559753 2.057465 19305 50.221329 37.265381 2.061646 19306 51.304932 36.687881 3.166573 19307 9.601181 36.978165 2.233399 19308 10.591431 35.845413 2.014824 19309 9.836533 35.174789 1.372879 19310 51.382751 35.550415 1.754837 19311 51.975632 35.017944 2.870613 19312 51.924133 35.873566 3.944328 19313 8.842819 31.846329 0.997345 19314 52.072037 34.163910 1.837067 19315 11.124802 34.976410 2.472252 19316 10.610916 33.906601 1.852448 19317 52.400665 33.614822 2.664185 19318 52.409790 32.206528 2.557945 19319 10.180275 32.947571 1.486023 19320 6.370407 30.226105 0.608841 19321 2.165421 28.431290 1.449112 19322 2.244835 27.451202 0.413017 19323 2.961784 28.327774 0.401268 19324 3.183121 29.487442 0.756607 19325 3.891243 29.070419 0.348213 19326 4.117188 30.209015 0.862343 19327 4.707237 29.319916 0.339142 19328 5.264084 30.302139 0.791336 19329 3.685623 31.400604 1.443680 19330 2.912354 30.389404 1.352326 19331 5.522667 29.065735 0.141403 19332 7.193947 31.562714 1.328491 19333 7.702301 33.258163 2.714981 19334 52.868835 29.776352 1.643311 19335 2.437058 29.336426 1.085846 19336 2.152130 29.448990 1.524826 19337 1.901054 27.327301 0.777199 19338 52.905029 28.788086 1.615990 19339 2.031769 26.548859 0.468620 19340 52.428421 26.339462 1.274490 19341 52.311493 27.311142 1.548096 19342 1.920868 24.785675 0.437210 19343 2.471588 22.454544 0.588356 19344 31.543274 24.699738 1.881912 19345 34.036621 24.560150 1.403999 19346 34.856949 24.066330 0.958008 19347 35.799698 23.800201 0.884606 19348 36.525352 23.671738 0.781349 19349 40.274017 23.129700 1.220337 19350 39.394699 23.668320 1.103073 19351 39.146027 23.720306 2.168717 19352 37.771843 24.342697 1.705292 19353 38.715881 23.419525 0.792786 19354 39.660973 23.086777 0.615372 19355 28.485199 21.915970 0.520493 19356 32.860283 24.278030 1.144318 19357 35.066727 23.252045 0.285454 19358 37.391457 23.391449 0.593811 19359 41.168854 22.696243 1.489761 19360 41.277130 22.505005 0.930718 19361 42.083038 22.024170 1.540688 19362 43.555176 20.899506 1.669884 19363 42.905716 21.251892 0.909638 19364 2.766564 21.063950 0.459351 19365 2.518013 20.611664 1.663590 19366 2.826531 20.504196 1.062424 19367 42.784546 20.944489 0.396988 19368 45.132874 19.640747 1.513840 19369 46.005951 18.518875 0.784775 19370 46.562241 18.980423 1.730728 19371 49.993622 18.584305 0.685791 19372 48.830658 17.695862 0.341644 19373 49.777496 19.468140 1.889900 19374 50.246170 20.214798 2.066551 19375 50.762833 20.203491 1.521393 19376 36.383362 16.883545 0.798637 19377 37.305573 15.591797 0.342537 19378 38.183746 15.372589 1.150215 19379 38.411293 16.094833 1.704468 19380 37.733917 16.453995 1.116257 19381 36.366409 17.949844 1.327087 19382 35.126633 18.207565 1.292084 19383 38.105049 16.809570 1.944389 19384 2.638390 17.618286 0.720459 19385 2.983849 19.902191 0.295464 19386 32.994659 16.464310 1.387489 19387 33.049698 15.840271 1.226135 19388 37.402466 12.766205 0.488846 19389 37.789566 13.532074 0.946465 19390 37.055450 11.800156 -0.020531 19391 39.525452 10.398026 0.180458 19392 38.897820 10.462082 1.112587 19393 40.848999 9.881622 1.061264 19394 39.873154 10.004028 2.211426 19395 39.736649 10.315598 1.108337 19396 42.367935 9.326385 0.812927 19397 3.366766 9.138486 1.084015 19398 44.213287 8.592850 0.940811 19399 55.589691 7.527771 -0.704208 19400 45.099533 7.513031 -0.194290 19401 2.773272 8.131796 3.567329 19402 2.687626 7.330253 3.563666 19403 3.114539 7.823174 1.919792 19404 45.340836 6.286865 -0.368439 19405 57.829163 5.600235 -0.170799 19406 3.627106 5.176877 -0.135294 19407 3.918233 3.994267 -0.578792 19408 58.298447 4.308014 0.374077 19409 45.367340 5.018501 0.614822 19410 45.306152 4.380600 1.766281 19411 44.951996 4.783852 2.574516 19412 44.932632 5.497696 1.825836 19413 53.655441 2.419556 -0.380920 19414 2.431704 2.457849 1.793698 19415 2.268714 2.647769 1.598933 19416 2.319323 2.645530 2.175272 19417 2.718291 2.115405 1.585976 19418 2.082001 2.798636 0.796459 19419 2.839582 2.489107 0.928174 19420 2.777917 3.647704 0.356206 19421 38.968109 1.473633 -0.739746 19422 40.929230 1.579681 -0.695297 19423 42.264740 0.789780 -0.172729 19424 59.300613 1.593521 -0.223999 19425 59.332687 1.843964 0.682388 19426 58.831055 2.983276 1.035233 19427 2.497894 2.379433 1.934345 19428 2.515229 2.359886 2.189853 19429 3.834795 1.382904 0.473204 19430 3.791628 2.707453 -0.166666 19431 3.337128 2.315284 0.581784 19432 39.362358 0.766708 -0.644592 19433 44.974060 1.106506 0.837502 19434 44.295624 0.581085 -0.001449 19435 59.026489 0.692673 -0.421181 19436 59.261871 0.892349 0.298172 19437 4.257272 0.454218 0.143068 19438 5.124252 0.147202 -1.283939 19439 5.604307 0.386212 -2.018059 19440 5.543038 -0.071543 -1.888916 19441 40.090195 0.230072 -1.306885 19442 59.194366 0.538116 1.407265 19443 58.471970 -0.238480 0.308212 19444 58.075760 -0.891586 1.566040 19445 58.901367 -0.371796 1.954056 19446 4.803728 -0.369848 -0.630082 19447 5.331204 -0.803055 -1.413734 19448 5.324674 -0.272172 -1.546938 19449 41.549927 -1.524872 -0.580574 19450 57.788025 -0.842804 -0.325378 19451 4.437419 -0.729067 0.189283 19452 4.320550 -2.153509 0.817407 19453 4.735470 -1.958485 -0.127653 19454 4.096991 -1.137013 1.083600 19455 5.435668 -0.567257 -1.672671 19456 50.401581 -2.431747 0.579811 19457 57.283615 -1.260193 -0.372162 19458 42.718582 -2.694290 -0.553391 19459 43.388153 -3.394501 -0.723976 19460 54.540237 -3.371414 -0.001457 19461 54.526337 -3.505676 1.209549 19462 55.163376 -3.178024 1.499481 19463 43.482681 -5.450729 -0.517288 19464 43.236816 -5.298050 0.869232 19465 43.408783 -4.320053 -0.173340 19466 53.868591 -4.205185 -0.445854 19467 54.246948 -4.115997 1.121491 19468 4.694895 -3.086878 0.146108 19469 4.726800 -4.170340 0.136659 19470 49.611435 -3.929062 0.257111 19471 58.322983 -5.183319 -0.026009 19472 59.704788 -5.283005 0.521332 19473 59.163528 -4.902328 0.504715 19474 5.078562 -7.433390 -0.556720 19475 60.317734 -5.925568 -0.723381 19476 47.134552 -7.817322 -1.115265 19477 47.681473 -6.998657 -0.933693 19478 48.063599 -7.398102 -0.104523 19479 52.915802 -6.520309 -0.428101 19480 52.627441 -7.936798 -0.594543 19481 56.523041 -6.282349 0.178833 19482 57.399536 -5.285507 1.202110 19483 56.487396 -5.726974 1.260155 19484 54.631165 -8.661743 -0.789383 19485 54.368149 -7.697739 0.257530 19486 53.905579 -8.389862 0.043762 19487 4.738491 -7.926919 0.404595 19488 53.403336 -7.448242 0.265549 19489 4.819847 -9.109419 0.469319 19490 4.854810 -10.228294 0.726517 19491 38.525330 -9.918747 -1.322983 19492 45.972321 -8.718384 -1.248657 19493 46.429962 -9.065063 -0.862045 19494 45.888245 -9.282455 -0.923943 19495 46.608124 -8.580460 -1.114395 19496 47.229218 -8.837051 -0.396103 19497 38.072586 -10.901581 -0.351707 19498 52.962067 -9.439133 -0.968216 19499 55.460785 -7.559250 -0.536682 19500 44.128632 -11.382736 -1.842613 19501 44.673508 -11.051926 -1.342011 19502 5.640720 -13.158829 -0.668988 19503 43.834320 -14.747711 -0.403496 19504 44.893738 -12.899200 -0.164741 19505 5.553607 -14.088663 0.254677 19506 5.907993 -14.824493 -0.567381 19507 39.159309 -17.149063 -0.676743 19508 40.149994 -17.859650 -0.607330 19509 39.247551 -18.261887 0.056229 19510 39.420021 -15.155502 -1.962311 19511 40.241425 -16.957443 -1.258743 19512 41.275787 -17.675568 -0.619064 19513 40.641571 -18.812180 0.343804 19514 62.388840 -16.660431 -1.191658 19515 62.685516 -15.614166 -0.198433 19516 62.224426 -18.233017 -1.116119 19517 62.493713 -17.428818 -1.107964 19518 15.276258 -18.398071 -0.055734 19519 15.225119 -18.395950 -0.001657 19520 15.279585 -18.344742 0.002905 19521 15.325727 -18.401505 0.000410 19522 15.275076 -18.448822 -0.003580 19523 61.390121 -20.437210 -1.390526 19524 61.625427 -20.102280 -1.331604 19525 61.249222 -19.034348 -0.279312 19526 62.247742 -18.233749 -0.403229 19527 61.040298 -20.887314 -1.461716 19528 8.574159 -20.969715 -1.811372 19529 8.197307 -20.712006 -1.120414 19530 52.866455 -24.776367 -1.200912 19531 9.020025 -21.609301 -1.797076 19532 55.681473 -25.142807 -0.388550 19533 57.472504 -24.374374 -0.464020 19534 21.001684 -27.323418 -3.475387 19535 49.005630 -24.017624 -2.524658 19536 14.627557 -26.472734 -1.276152 19537 14.171785 -25.976057 -1.706355 19538 13.527058 -25.933678 -0.995197 19539 64.479950 -27.139160 -2.185219 19540 65.261414 -26.336548 -2.748207 19541 14.484338 -25.801580 -2.338809 19542 14.385060 -26.641239 -0.670265 19543 16.834610 -27.719213 -1.172055 19544 17.802649 -28.296642 -1.065890 19545 18.647081 -28.472418 -1.329940 19546 19.253788 -28.143692 -1.985577 19547 34.680229 -29.395447 -3.139885 19548 33.382683 -29.455832 -3.024517 19549 50.197830 -26.538712 -1.558472 19550 60.882355 -28.856964 -1.494995 19551 60.106949 -28.367737 -2.080856 19552 13.288729 -25.295940 -1.958980 19553 12.565292 -25.214874 -1.135608 19554 17.227356 -28.717743 -0.118220 19555 15.953314 -27.919878 -0.155950 19556 16.422457 -28.850235 0.718865 19557 49.939301 -27.094940 -1.961731 19558 51.155304 -27.870621 -2.401787 19559 50.515671 -27.522324 -1.594284 19560 52.114517 -28.400421 -0.322357 19561 51.375168 -27.800369 -0.785858 19562 57.982040 -28.680603 -2.366043 19563 58.996704 -29.229721 -2.092377 19564 64.984329 -28.314514 -1.886215 19565 22.633427 -29.282469 -1.929957 19566 32.254292 -30.019915 -2.469623 19567 34.645111 -30.436142 -2.949196 19568 23.142807 -30.183163 -1.197395 19569 23.632620 -31.385736 -0.244222 19570 24.539423 -30.718260 -1.064560 19571 32.396820 -30.804129 -1.753182 19572 26.101942 -30.700111 -1.412493 19573 24.997272 -31.438131 -0.565370 19574 29.500637 -30.763906 -1.717708 19575 33.705475 -30.709930 -1.821732 19576 33.994644 -32.150146 -2.050766 19577 16.980698 -33.042221 -3.643662 19578 20.376938 -31.953705 -4.249039 19579 23.468628 -32.580994 -4.113251 19580 27.844282 -31.957537 -0.630952 19581 28.968367 -32.139225 -0.535136 19582 27.016781 -31.500124 -0.905723 19583 49.650345 -32.310150 -1.913422 19584 51.113449 -32.377975 -1.741501 19585 57.641113 -30.605423 -2.318008 19586 61.971313 -30.710876 -2.194618 19587 16.207321 -33.653793 -3.385590 19588 17.566513 -34.029800 -2.653664 19589 16.145103 -34.629761 -2.620148 19590 21.625320 -33.071396 -3.569084 19591 20.460732 -33.043076 -3.521027 19592 22.370956 -34.180649 -2.964508 19593 55.284073 -32.831223 -2.244553 19594 56.521866 -31.566055 -2.064789 19595 55.970001 -32.375549 -2.454597 19596 12.788673 -34.836243 -4.042206 19597 15.103683 -34.222717 -3.404488 19598 20.668716 -33.775055 -2.973694 19599 19.442154 -34.068909 -2.514145 19600 34.372437 -33.140778 -2.582680 19601 34.380791 -34.099411 -2.498581 19602 45.999268 -35.248184 -1.902496 19603 13.814819 -35.121628 -3.279251 19604 24.907448 -35.900009 -2.526390 19605 27.026245 -35.664169 -3.640999 19606 26.117752 -36.109650 -2.914047 19607 27.309631 -36.296555 -3.284912 19608 47.201431 -32.993744 -2.279411 19609 46.271057 -33.392349 -1.672844 19610 11.088486 -37.288147 -2.829803 19611 26.919693 -36.867172 -2.519257 19612 46.623947 -36.586990 -2.344673 19613 46.454285 -36.931549 -1.346710 19614 50.662064 -37.202988 -2.523598 19615 51.807159 -36.819244 -3.172150 19616 52.509033 -37.320969 -2.812157 19617 51.470764 -37.202118 -2.521866 19618 60.300873 -36.909058 -1.864639 19619 59.880768 -37.749863 -2.438705 19620 60.588028 -36.641891 -0.684296 19621 63.760773 -36.581345 -1.866791 19622 62.357941 -36.343475 -1.377983 19623 11.463158 -38.855026 -3.653000 19624 30.966690 -37.659119 -3.092651 19625 29.655685 -37.870712 -2.091690 19626 32.117188 -37.815948 -3.425888 19627 32.043785 -37.954102 -2.715500 19628 34.833771 -38.391022 -3.389893 19629 55.025665 -38.366364 -2.552261 19630 55.541168 -38.057846 -1.573273 19631 54.422394 -38.040512 -1.880997 19632 53.224304 -37.977997 -1.692162 19633 55.704361 -39.332993 -2.682556 19634 58.348969 -38.916397 -2.791527 19635 57.958130 -37.767929 -2.034683 19636 56.541321 -38.373459 -2.305191 19637 65.195831 -37.557617 -1.948532 19638 64.620560 -36.866821 -1.889725 19639 10.751060 -38.234619 -2.755669 19640 33.743965 -38.612564 -3.157517 19641 34.528992 -38.779556 -3.376465 19642 57.073929 -39.097610 -2.694420 19643 57.570236 -39.849884 -2.895111 19644 65.601990 -38.811386 -1.642303 19645 65.581757 -38.065094 -1.641647 19646 34.136856 -38.779129 -3.150742 19647 56.578323 -39.897827 -2.676926 19648 57.414169 -40.831528 -2.924561 19649 58.778748 -40.796661 -3.075493 19650 59.249390 -41.678238 -3.162064 19651 60.796143 -41.459442 -3.618042 19652 65.626892 -39.926880 -1.932480 19653 30.580719 -42.732605 -4.078941 19654 58.853287 -41.577881 -2.972382 19655 58.753265 -37.301804 -1.535278 19656 65.659546 -40.857483 -2.289169 19657 15.259003 -42.983780 -3.946274 19658 13.948868 -42.722656 -3.064995 19659 17.259796 -44.493607 -3.904724 19660 20.048706 -44.069778 -3.340111 19661 19.769043 -43.623947 -3.870026 19662 23.398605 -43.135971 -3.636307 19663 26.404541 -43.229095 -2.890594 19664 25.713333 -42.576416 -3.415375 19665 24.986542 -43.667633 -3.085907 19666 27.412735 -42.948151 -3.101639 19667 27.372650 -43.751846 -2.744438 19668 28.257553 -43.574142 -3.042221 19669 58.834808 -41.998962 -3.206574 19670 65.297668 -41.723938 -2.080795 19671 65.223007 -40.711929 -1.470230 19672 17.491714 -45.362839 -3.586357 19673 16.587540 -45.175369 -3.765472 19674 20.752983 -43.652740 -3.639847 19675 30.541000 -45.385132 -3.589600 19676 32.416122 -45.090408 -4.312210 19677 22.455605 -45.879944 -3.323792 19678 23.634705 -45.272369 -3.262428 19679 25.014725 -45.278046 -3.057877 19680 25.831253 -46.235184 -3.635559 19681 26.405212 -44.651627 -2.915787 19682 28.709763 -47.945389 -3.558029 19683 28.878410 -46.813217 -3.537399 19684 27.264633 -47.556839 -3.958382 19685 32.319633 -47.730621 -4.185692 19686 31.770388 -46.917099 -3.782166 19687 47.064758 -46.595413 -1.841660 19688 48.437302 -46.117859 -2.490707 19689 64.740387 -45.700760 -3.020348 19690 64.013367 -46.416946 -2.046707 19691 64.457474 -45.347290 -1.975609 19692 21.056717 -47.515717 -4.044174 19693 31.623781 -48.006180 -3.756767 19694 44.685394 -48.350449 -2.941223 19695 44.661102 -49.439224 -2.819122 19696 54.987640 -46.763412 -2.349518 19697 56.108185 -46.427490 -1.728493 19698 64.177643 -46.995499 -3.192856 19699 27.825905 -45.684586 -3.325180 19700 27.024933 -48.888626 -4.190308 19701 30.970062 -48.977417 -3.570503 19702 45.140213 -47.681808 -2.493088 19703 58.154938 -47.263763 -2.212013 19704 58.669006 -45.713409 -1.116806 19705 59.512085 -46.567261 -1.507355 19706 63.602646 -47.461182 -2.470917 19707 62.685974 -48.135406 -2.280151 19708 63.300095 -47.185623 -1.695938 19709 20.111450 -49.702118 -3.917099 19710 26.517715 -49.240997 -4.419006 19711 26.598312 -49.786774 -4.076279 19712 60.213699 -49.644012 -3.303803 19713 19.030334 -50.854218 -4.564285 19714 19.773369 -52.468826 -3.405830 19715 18.848625 -52.300018 -3.766800 19716 19.770996 -51.982437 -3.025467 19717 30.992188 -51.589905 -4.047546 19718 46.169815 -52.124542 -3.590630 19719 47.656647 -52.624939 -4.066551 19720 61.621933 -50.461243 -4.006302 19721 61.228134 -49.946716 -3.351265 19722 16.469681 -53.717499 -4.785568 19723 17.495468 -52.947678 -4.168701 19724 31.030350 -52.665024 -4.142624 19725 45.385941 -51.316803 -3.499588 19726 44.698364 -50.696060 -2.676765 19727 45.007324 -51.895035 -2.820763 19728 49.992325 -54.346436 -4.129044 19729 31.096848 -53.638535 -4.192871 19730 49.196442 -53.650589 -4.073601 19731 48.226395 -53.552673 -3.690224 19732 15.785881 -54.613876 -4.790138 19733 15.810410 -54.474060 -4.450386 19734 15.596863 -54.751129 -4.539261 19735 31.039490 -54.589233 -4.277657 19736 50.771149 -55.244278 -3.914246 19737 15.853363 -55.121109 -4.500984 19738 24.530716 -54.430298 -4.257263 19739 23.587708 -54.362991 -4.389420 19740 24.597885 -55.813538 -4.727241 19741 25.521744 -55.175446 -4.333588 19742 30.958717 -55.681931 -4.454941 19743 48.983459 -54.274429 -3.646881 19744 54.114868 -56.078369 -4.550079 19745 25.786255 -57.763947 -4.544594 19746 25.634140 -56.351700 -4.562393 19747 30.999519 -56.686218 -4.669998 19748 51.870575 -55.800980 -4.032684 19749 52.894531 -56.315720 -4.087791 19750 53.439331 -57.422180 -3.807602 19751 16.308578 -57.777008 -4.415314 19752 16.240128 -55.646759 -3.613258 19753 27.235245 -56.566193 -3.946716 19754 30.658524 -57.587631 -4.454880 19755 52.050751 -56.952057 -3.555283 19756 54.834229 -57.337845 -4.298492 19757 16.725327 -58.444122 -5.219116 19758 16.346909 -58.810257 -4.614303 19759 16.835739 -59.541458 -5.324898 19760 25.370224 -58.844971 -4.749679 19761 26.404900 -59.067062 -3.759674 19762 30.085388 -58.802353 -4.178001 19763 54.625397 -58.493607 -3.967011 19764 16.692245 -60.485413 -5.358360 19765 16.300865 -60.201248 -4.964462 19766 25.414612 -59.617859 -4.361504 19767 38.050583 -58.481598 -4.755234 19768 37.902657 -59.445999 -4.765678 19769 38.988113 -60.268112 -4.776001 19770 55.399475 -59.235703 -4.268776 19771 15.708359 -60.362091 -4.876846 19772 15.850594 -59.663971 -4.527771 19773 29.647041 -60.363983 -3.964203 19774 29.965042 -60.872192 -5.095367 19775 14.143768 -61.556473 -5.083275 19776 15.456078 -60.970398 -5.283699 19777 16.185455 -60.698166 -5.232330 19778 24.819084 -61.446198 -3.321335 19779 25.670090 -60.345291 -3.372101 19780 23.498596 -62.177536 -5.214317 19781 28.937157 -59.136597 -3.268921 19782 29.587006 -57.687515 -3.577194 19783 27.789261 -57.968979 -3.521034 19784 29.641670 -62.121750 -4.673386 19785 38.474808 -59.567398 -4.445129 19786 38.790939 -59.961624 -4.510757 19787 54.535110 -61.108887 -4.235016 19788 54.437057 -59.795120 -3.947067 19789 23.231552 -61.882034 -5.794723 19790 54.477921 -62.238388 -4.650665 19791 12.677139 -61.794785 -3.982407 19792 13.785561 -60.786774 -4.049042 19793 12.934998 -63.986969 -5.350830 19794 12.186386 -63.441696 -4.440796 19795 29.381775 -63.401932 -4.952377 19796 51.940613 -63.102890 -4.322510 19797 51.020905 -63.816269 -4.578033 19798 53.585922 -61.851135 -4.157967 19799 53.379425 -63.221817 -4.763847 19800 13.334016 -65.116608 -5.246475 19801 50.079727 -63.881439 -4.578064 19802 49.073639 -63.319016 -4.186813 19803 50.246521 -62.744827 -3.984627 19804 48.268875 -62.429459 -3.651695 19805 47.480423 -63.567871 -4.036057 19806 51.130737 -62.880478 -4.108154 19807 52.599976 -62.065765 -4.042664 19808 20.608170 -64.863037 -4.456512 19809 19.101883 -65.266205 -4.505691 19810 18.204109 -65.543549 -4.544235 19811 18.441711 -65.521881 -3.723511 19812 28.045486 -65.419708 -4.516189 19813 48.661682 -64.305145 -4.691345 19814 49.495514 -64.316101 -4.787750 19815 14.377235 -66.024216 -4.854835 19816 15.707924 -66.591415 -4.330139 19817 17.718246 -65.986984 -5.279190 19818 46.596527 -64.974426 -4.491455 19819 46.153992 -66.082138 -4.700973 19820 45.256516 -65.348709 -3.802200 19821 47.189514 -65.905487 -5.083267 19822 25.435585 -68.274948 -5.511490 19823 44.980804 -66.027222 -3.904427 19824 45.397034 -66.242355 -4.226791 19825 45.181946 -66.599792 -3.612473 19826 39.100533 -67.381775 -4.430313 19827 38.820908 -68.064377 -5.053055 19828 41.085892 -68.191422 -3.179153 19829 42.017426 -69.048203 -4.187424 19830 12.039078 -69.622559 -5.887474 19831 11.309700 -69.988525 -5.737495 19832 12.924973 -69.452835 -6.287872 19833 13.526871 -69.115097 -3.475327 19834 13.987396 -68.215393 -2.584030 19835 12.696381 -68.109207 -2.484390 19836 19.363083 -69.150513 -5.417419 19837 26.021286 -68.582474 -4.627296 19838 26.029022 -69.914398 -4.599487 19839 12.615120 -69.232620 -4.501511 19840 11.995293 -69.415558 -5.318481 19841 12.944290 -69.592880 -5.820923 19842 14.426277 -69.958939 -5.578277 19843 13.779190 -69.654358 -4.658691 19844 14.466217 -69.984985 -4.704773 19845 15.573715 -70.213242 -5.709587 19846 16.350098 -70.205933 -4.867828 19847 20.773117 -70.225876 -5.806229 19848 20.559814 -69.109161 -4.812302 19849 21.218491 -69.802444 -4.562584 19850 38.337326 -68.063965 -4.130531 19851 38.600906 -69.850021 -4.232704 19852 38.154610 -68.825806 -3.624550 19853 46.448654 -69.883728 -4.075699 19854 46.020447 -68.927994 -3.682541 19855 17.166519 -70.059158 -5.350983 19856 21.177063 -70.467407 -4.883438 19857 25.400391 -71.577118 -5.665520 19858 43.092651 -70.934479 -4.647812 19859 42.622467 -70.070831 -4.414818 19860 10.683960 -71.098663 -5.460258 19861 25.527924 -72.755035 -6.249382 19862 26.054214 -71.168594 -4.964027 19863 26.124680 -72.269989 -5.391502 19864 39.685287 -73.081772 -5.470146 19865 46.462631 -71.605759 -4.801765 19866 46.202057 -70.900558 -3.711014 19867 26.320206 -73.220383 -5.837463 19868 26.984665 -73.071793 -5.288353 19869 39.510162 -73.121078 -4.406601 19870 43.677872 -71.549377 -4.240265 19871 44.720245 -71.850220 -4.008179 19872 12.932983 -72.864883 -3.655304 19873 13.797974 -73.377075 -3.463852 19874 13.738777 -73.683060 -4.809250 19875 14.664735 -74.214706 -6.081467 19876 13.446664 -73.602798 -6.055176 19877 26.973358 -73.883179 -5.822678 19878 27.779572 -74.057068 -5.366844 19879 16.231705 -75.754761 -5.902740 19880 16.498459 -76.080948 -6.344444 19881 22.353561 -75.304016 -4.580688 19882 28.539566 -75.527100 -5.591675 19883 11.411919 -76.988434 -5.710724 19884 12.988983 -76.985794 -5.983551 19885 14.310501 -77.235046 -5.717316 19886 15.811043 -76.669022 -6.160652 19887 15.842896 -76.176605 -5.035873 19888 15.379013 -77.051819 -5.151108 19889 47.172333 -75.967590 -4.203407 19890 9.593719 -79.147324 -6.172035 19891 14.094818 -77.685486 -4.351433 19892 28.256088 -77.867874 -5.807304 19893 17.712860 -79.212875 -6.376701 19894 25.780045 -79.759232 -6.365631 19895 25.415337 -77.791565 -2.454430 19896 24.426392 -78.569794 -2.409882 19897 25.488029 -78.822845 -3.306099 19898 9.709564 -79.835342 -5.367782 19899 10.199570 -80.729431 -4.670792 19900 47.271454 -79.341522 -4.890396 19901 47.697861 -78.453705 -5.214493 19902 11.268867 -80.673935 -6.277199 19903 11.924606 -80.963058 -6.337646 19904 6.626297 -81.675644 -6.441452 19905 26.315109 -81.075806 -6.113769 19906 27.018204 -81.488831 -5.428711 19907 37.255264 -81.603851 -4.832847 19908 36.602776 -82.721954 -4.999771 19909 18.001175 -80.904266 -4.618393 19910 18.216888 -79.968826 -3.519096 19911 17.737823 -80.042175 -4.130257 19912 17.423088 -80.021820 -4.927109 19913 17.093262 -79.950333 -5.623756 19914 20.533218 -81.984222 -6.674690 19915 38.664062 -81.480362 -4.944366 19916 28.495193 -84.744919 -5.244087 19917 40.749084 -81.760849 -4.603592 19918 41.549484 -82.152161 -4.839432 19919 42.902847 -82.366638 -4.823555 19920 44.089874 -82.121109 -4.676025 19921 43.600372 -82.746536 -5.659027 19922 5.727043 -83.864288 -5.834412 19923 9.160927 -83.846420 -6.815720 19924 15.711784 -84.563385 -4.605270 19925 16.740379 -85.049698 -4.484421 19926 39.091476 -85.409042 -4.926926 19927 17.581360 -86.501755 -6.139854 19928 22.716583 -86.987183 -5.740723 19929 29.354630 -86.840195 -6.236671 19930 30.042282 -87.291046 -5.880691 19931 30.263641 -87.673645 -6.453224 19932 39.952652 -85.897079 -5.561623 19933 6.879677 -86.722519 -6.596161 19934 7.684127 -88.002563 -6.701919 19935 15.137421 -88.404358 -5.576706 19936 15.423477 -88.041916 -4.774933 19937 15.088226 -87.566513 -4.664322 19938 8.488022 -88.731339 -6.148727 19939 14.390015 -87.327728 -5.187065 19940 33.967422 -88.706985 -6.327927 19941 32.711777 -88.463608 -5.461380 19942 33.673813 -88.658997 -5.522003 19943 19.071564 -90.403702 -6.471359 19944 18.934235 -89.681091 -5.928352 19945 19.423203 -90.243744 -5.719841 19946 26.246017 -88.621445 -4.780311 19947 25.383240 -88.698685 -5.629997 19948 26.121399 -89.208740 -6.296936 19949 41.300323 -88.389435 -4.589577 19950 41.166275 -87.736435 -4.706207 19951 18.718475 -90.651245 -7.145180 19952 36.575317 -90.090271 -6.924606 19953 35.820160 -89.937836 -6.376686 19954 36.221153 -90.415268 -6.553749 19955 37.070358 -90.608917 -7.371155 19956 41.445251 -89.833313 -6.633270 19957 19.458572 -91.411255 -6.759491 19958 19.779358 -92.618790 -6.297058 19959 27.851669 -90.306534 -6.012298 19960 28.624100 -90.928131 -6.182419 19961 35.597404 -90.604599 -6.474983 19962 39.964661 -91.623001 -5.143608 19963 41.116272 -90.053848 -5.528908 19964 40.628418 -89.983566 -3.940346 19965 15.948883 -92.671112 -7.026672 19966 20.006142 -93.375519 -7.121452 19967 19.668098 -90.821106 -5.783203 19968 19.447441 -91.456055 -5.166229 19969 30.975349 -91.071091 -5.574997 19970 30.159378 -91.116623 -5.444588 19971 30.185959 -91.384079 -6.090034 19972 34.051765 -91.628174 -7.550941 19973 32.781296 -91.642609 -7.522369 19974 34.845871 -91.218170 -6.858078 19975 34.567490 -90.238998 -5.785042 19976 33.602051 -90.830933 -5.916061 19977 39.554871 -91.837631 -3.315544 19978 39.972038 -90.968033 -3.095123 19979 12.795074 -95.085510 -7.181488 19980 16.074570 -93.718658 -7.085403 19981 19.343407 -93.426804 -6.435455 19982 38.594437 -93.166779 -6.416351 19983 26.381058 -95.053192 -6.255218 19984 25.693970 -95.430054 -6.805839 19985 25.449051 -94.424149 -5.784584 19986 37.380379 -94.230652 -6.775841 19987 21.934525 -97.863373 -6.914001 19988 26.488602 -96.046036 -6.687973 19989 32.407654 -96.863205 -6.783775 19990 31.985140 -97.460953 -5.678062 19991 32.896469 -96.479187 -5.711014 19992 34.495514 -95.520905 -5.671020 19993 21.854797 -98.746429 -7.654808 19994 26.453354 -97.279144 -6.831528 19995 13.892128 -98.180557 -7.448486 19996 13.393646 -96.899673 -6.632080 19997 22.922104 -99.472534 -6.601570 19998 22.701080 -97.494400 -5.530624 19999 22.300377 -97.723724 -6.299896 20000 25.967384 -98.250519 -7.641083 20001 14.906860 -99.201187 -7.495972 20002 26.752075 -98.286362 -6.973984 20003 27.540161 -98.833969 -6.943718 20004 30.064072 -98.699890 -6.499527 20005 22.170441 -99.392441 -7.542885 20006 22.097763 -98.687515 -6.925941 20007 28.431580 -99.247787 -6.778160 20008 29.063019 -99.157074 -7.103310 20009 16.304718 -100.524200 -7.502350 20010 22.858856 -101.244217 -7.555344 20011 23.773888 -100.824921 -5.734894 20012 24.103668 -99.532990 -5.120300 20013 17.014618 -101.058990 -6.851990 20014 23.037704 -101.170990 -6.506615 20015 7.473663 61.177307 4.129212 20016 6.750031 62.299515 4.982330 20017 5.963181 62.078247 4.288315 20018 4.935967 61.854965 4.344223 20019 7.853546 59.622864 3.022644 20020 8.478859 59.671631 3.628906 20021 9.197372 60.488602 4.598244 20022 10.251740 57.687637 3.086647 20023 28.435440 57.593018 4.659996 20024 10.813797 57.743332 3.573044 20025 11.850601 57.102005 3.589295 20026 21.925186 56.881958 2.915390 20027 29.189507 56.853348 4.066444 20028 20.441338 55.869858 3.173218 20029 21.933517 55.412231 3.250351 20030 14.656219 55.900040 4.314957 20031 15.421097 55.274796 4.295487 20032 16.605988 54.975906 3.220375 20033 17.199371 54.731598 3.520409 20034 16.507248 54.746948 3.634712 20035 17.421478 55.126511 3.153687 20036 18.110909 54.673386 3.534531 20037 18.155502 55.136841 3.131332 20038 19.024101 55.060425 3.269104 20039 22.044052 54.641418 3.723511 20040 21.163132 54.875381 3.583695 20041 20.074593 54.641052 3.754776 20042 23.972885 56.918213 5.028381 20043 4.004662 53.783722 2.596497 20044 19.022583 54.498062 3.706886 20045 22.678719 54.760452 3.723770 20046 28.350365 53.895798 3.342285 20047 32.296928 50.723389 3.467629 20048 32.928314 51.652206 3.621689 20049 31.514084 50.782806 4.201935 20050 35.019302 54.294846 4.449982 20051 38.525917 53.386337 3.627442 20052 4.322090 52.706467 2.439522 20053 3.837448 51.477219 1.757477 20054 6.009522 53.167084 3.164963 20055 5.323448 52.416138 2.745483 20056 5.080040 53.250366 3.075241 20057 7.110016 54.203888 4.061020 20058 7.300263 52.297836 2.906654 20059 8.404755 52.095840 2.902893 20060 8.593628 53.110901 3.603241 20061 8.894913 52.454590 3.218407 20062 9.005676 51.725998 2.973190 20063 25.716125 52.200653 5.440491 20064 26.519211 53.986389 6.372085 20065 34.342598 52.741760 3.350800 20066 35.289711 52.931854 2.979248 20067 5.075111 50.873047 2.176560 20068 6.107109 51.968750 2.627548 20069 9.380775 52.445129 3.530258 20070 9.854698 51.345154 3.415283 20071 39.302856 52.530136 4.033264 20072 3.687950 49.131866 1.600433 20073 31.737490 52.127090 5.040909 20074 40.206467 49.642944 3.772019 20075 40.043213 51.302734 3.883530 20076 40.907532 50.822662 3.114555 20077 11.051819 50.640259 3.815613 20078 31.784296 49.945343 3.507149 20079 31.872103 48.630798 2.772461 20080 30.669693 49.114487 4.043350 20081 31.575562 47.210648 2.091187 20082 30.680435 47.085297 2.946304 20083 40.751572 47.231689 3.234955 20084 25.118195 49.136658 3.356400 20085 29.776138 47.541672 4.113472 20086 38.775955 46.573486 3.545151 20087 28.644608 44.805984 4.073990 20088 28.957352 44.264832 3.370789 20089 29.587585 45.674255 3.442505 20090 37.211021 45.313782 3.189758 20091 3.681984 43.212708 3.130722 20092 9.552147 44.751953 3.376412 20093 10.375900 44.329865 2.809143 20094 10.701965 44.911072 3.565720 20095 10.108047 43.820984 2.238663 20096 11.919281 44.890381 3.021713 20097 11.696564 45.940033 4.311447 20098 12.366211 44.712372 2.298004 20099 25.223915 43.474609 2.390556 20100 30.290314 45.547882 2.400139 20101 35.105988 45.332748 4.140350 20102 36.399048 46.242416 3.984024 20103 3.677330 44.188599 4.997376 20104 10.861511 43.907608 2.273804 20105 11.107887 44.322281 2.708191 20106 28.750000 43.542297 2.745133 20107 34.301971 45.866226 5.228951 20108 35.146095 46.807098 4.998016 20109 34.781082 43.722870 3.328705 20110 26.104126 42.702744 2.748436 20111 25.905884 42.655090 3.652962 20112 25.044220 43.164658 3.837433 20113 26.794456 42.502228 2.540024 20114 34.103546 42.831848 3.182694 20115 26.654922 42.374512 2.834282 20116 6.224503 40.422806 3.416458 20117 5.368668 40.362045 2.898804 20118 5.575012 41.297363 4.428604 20119 33.623886 40.506485 3.538849 20120 33.800179 41.374207 4.300514 20121 39.125946 39.248169 2.559708 20122 39.115028 39.784561 3.578140 20123 38.103729 39.445511 3.006210 20124 40.271606 40.170654 3.424484 20125 40.996246 39.741608 4.136269 20126 42.308777 39.871704 3.981789 20127 43.730927 39.777527 3.858917 20128 4.420387 39.944122 1.902886 20129 5.436257 38.871521 1.823929 20130 6.383843 39.178925 2.448692 20131 37.088806 39.519104 3.278938 20132 37.209991 39.119827 2.549545 20133 45.018707 39.375061 4.182739 20134 44.464981 38.200134 5.020355 20135 49.100555 38.762939 2.981361 20136 46.398392 39.352692 3.793182 20137 6.387535 38.085617 1.761932 20138 7.712234 38.208038 2.377960 20139 36.298447 39.708527 4.218239 20140 35.190308 39.649506 3.725494 20141 48.267639 39.375580 3.339920 20142 8.138657 37.124237 1.775101 20143 11.212982 37.076309 2.934784 20144 11.053574 36.134171 2.461090 20145 50.713394 38.175568 4.106964 20146 51.267456 37.402069 4.620583 20147 50.993790 37.616821 3.811516 20148 9.531013 32.963669 2.266693 20149 9.772423 32.352631 1.390930 20150 10.313980 33.570755 2.580368 20151 2.993164 31.300537 1.590889 20152 3.045021 32.141815 2.142761 20153 2.732613 31.300339 2.223915 20154 4.508789 32.183411 1.787201 20155 3.653542 32.382843 1.960571 20156 4.687248 31.170044 1.229584 20157 5.704163 31.596466 1.439217 20158 6.459114 33.357651 2.605393 20159 6.480698 32.586090 2.105164 20160 52.287048 33.114090 3.635338 20161 2.346100 29.846878 1.508011 20162 52.272400 30.803528 2.593109 20163 50.698929 28.332870 2.510681 20164 51.375031 29.235718 2.652611 20165 51.662979 28.082275 2.091095 20166 52.322235 29.092957 2.132111 20167 52.481354 29.900864 2.322327 20168 52.038696 29.916351 2.647888 20169 1.933395 26.988876 1.372917 20170 45.427734 29.732147 3.969811 20171 44.072906 29.597321 4.507820 20172 44.834808 29.994019 4.808136 20173 48.498779 29.576340 3.243240 20174 50.144974 29.713654 3.107437 20175 49.731522 28.267700 2.589157 20176 48.633881 26.942474 2.206947 20177 52.473236 28.199463 1.765785 20178 46.853378 29.244751 3.085983 20179 45.669556 28.334091 2.763764 20180 46.788254 27.854462 2.354370 20181 45.793594 26.950928 2.552605 20182 47.048904 26.385757 2.228165 20183 47.570221 27.512177 2.198448 20184 47.789917 25.378677 2.144699 20185 48.543671 24.551651 2.172226 20186 1.928253 25.767761 1.201195 20187 50.915985 26.645065 1.911957 20188 2.036911 26.666229 2.333458 20189 1.823914 25.844055 2.918274 20190 1.974289 24.728897 1.486130 20191 30.459099 24.307465 2.530914 20192 31.121658 25.022629 2.731110 20193 34.896980 24.903503 1.960709 20194 36.505646 24.869492 2.332245 20195 35.704918 24.539780 1.616608 20196 35.636795 24.961105 2.193726 20197 36.636932 24.277039 1.337067 20198 45.829773 25.324295 3.011673 20199 49.843842 24.744598 2.003075 20200 2.090683 23.645035 1.494766 20201 40.930405 22.391968 2.757691 20202 46.994751 25.037231 2.467682 20203 51.126907 24.597214 1.713722 20204 2.273644 21.616760 1.941322 20205 30.219452 24.231110 3.602745 20206 30.737015 24.866486 3.673821 20207 29.015793 22.538055 1.471947 20208 47.611313 24.390427 2.410278 20209 49.205780 23.053238 2.392334 20210 48.983765 21.248672 2.599197 20211 47.700012 22.301910 3.021652 20212 50.687454 23.284393 1.957520 20213 51.279892 21.895462 1.640701 20214 28.576889 21.869171 1.168739 20215 52.089767 22.135513 1.130447 20216 2.952889 20.381012 0.762894 20217 50.303513 21.006805 2.132233 20218 50.205017 22.104996 2.208923 20219 28.987793 21.908539 2.047058 20220 33.988663 19.048080 1.615456 20221 32.911331 19.056473 1.847504 20222 33.763824 17.987335 1.301216 20223 34.836418 19.512848 2.128861 20224 33.516052 20.049545 2.412880 20225 44.722092 20.600220 2.648987 20226 30.959602 15.756927 0.581696 20227 36.265953 18.685333 2.102219 20228 37.248398 17.566177 1.737808 20229 37.177521 18.241333 2.665817 20230 48.680420 18.161591 1.237915 20231 3.074204 15.659348 -0.187759 20232 33.402435 17.146179 1.281181 20233 32.861076 17.138794 1.544403 20234 3.058861 14.574936 0.272606 20235 32.122108 15.170929 0.798988 20236 38.015007 14.388077 1.698143 20237 3.551947 10.244782 0.233650 20238 37.336792 12.863708 1.772583 20239 37.066490 11.597870 1.048554 20240 36.766785 11.722702 1.995239 20241 3.088108 10.183107 1.934404 20242 36.882080 10.948700 2.107620 20243 37.712029 10.653992 1.302567 20244 2.966548 9.072235 2.639066 20245 42.145950 9.174927 1.899490 20246 43.358536 8.840363 1.481491 20247 44.395264 8.209137 1.464539 20248 44.059967 8.586823 1.586166 20249 2.918105 6.566786 1.953098 20250 3.402158 6.539464 0.698532 20251 44.820724 7.623215 0.659363 20252 44.447327 7.479218 1.550285 20253 45.000000 6.463013 1.065979 20254 56.624268 5.666527 0.611366 20255 57.411499 5.211311 0.664810 20256 2.941905 5.229340 0.913749 20257 55.573746 4.146431 0.807953 20258 56.660248 4.669418 1.060143 20259 2.032160 2.877786 1.561602 20260 1.712072 3.038323 1.431029 20261 2.110492 3.011462 2.380314 20262 0.866913 2.404205 0.041412 20263 1.781802 3.630704 1.692453 20264 2.389792 2.611909 2.720926 20265 2.146812 4.144206 1.234947 20266 39.170059 1.400772 -0.490578 20267 39.801682 1.308594 -0.330887 20268 3.292700 1.360769 1.533741 20269 40.724319 0.857300 -0.012207 20270 39.882591 0.477814 0.262680 20271 40.885162 0.093628 0.703560 20272 2.654927 2.111533 2.291636 20273 39.449417 -1.356552 0.305389 20274 39.381699 -0.282532 0.256401 20275 40.051788 -2.548340 0.515625 20276 44.841583 -1.381775 5.087616 20277 45.180847 -0.741302 4.397400 20278 44.407913 -1.676773 3.694367 20279 44.515701 -1.010361 2.377892 20280 44.427856 -0.223312 1.333145 20281 42.321243 -1.024429 1.906113 20282 43.578293 0.139389 0.413910 20283 44.399765 0.261948 0.470993 20284 2.621634 2.153036 2.685389 20285 2.900492 1.629925 2.504120 20286 5.446931 -0.319932 -1.757479 20287 5.559096 -0.354410 -1.914298 20288 5.586998 -0.514670 -1.951686 20289 5.547581 -0.570758 -1.876615 20290 41.603409 -2.439056 -0.088341 20291 57.237961 -1.347992 0.438706 20292 3.723762 0.176500 1.487280 20293 5.463729 -0.482548 -1.788759 20294 5.531191 -0.535881 -1.912155 20295 42.328995 -4.804886 1.559074 20296 42.616852 -5.464523 2.036835 20297 41.614029 -5.209824 2.091080 20298 50.633179 -4.919022 2.447403 20299 50.065796 -4.630478 1.490173 20300 51.032806 -3.454697 2.353684 20301 55.856018 -2.242874 0.465134 20302 56.495209 -2.257233 1.737946 20303 5.497538 -0.527732 -1.870013 20304 53.860199 -4.303772 0.298859 20305 4.408615 -4.658826 0.941679 20306 4.265144 -5.105912 1.329253 20307 4.654357 -5.844572 0.337887 20308 49.809464 -3.973175 0.775971 20309 53.839447 -5.127151 0.857849 20310 4.834679 -5.186777 -0.106842 20311 60.159973 -5.960037 -0.117332 20312 59.931976 -6.029251 0.626511 20313 4.837840 -6.838587 -0.040017 20314 42.259430 -8.767090 -0.515953 20315 43.037155 -8.647141 0.198998 20316 43.046143 -6.994644 -0.215271 20317 53.425415 -6.108185 0.405327 20318 4.340375 -5.621027 1.110020 20319 4.359073 -6.069457 1.091929 20320 60.834961 -9.079865 -0.080772 20321 4.566150 -6.848038 0.642269 20322 41.479156 -8.970688 -0.906502 20323 41.557602 -9.617706 -0.560654 20324 53.066742 -8.984070 -0.553032 20325 53.853546 -8.982468 -0.398575 20326 60.023712 -8.362457 0.805885 20327 4.437287 -8.415057 1.481229 20328 36.427826 -10.351166 -0.358612 20329 36.100830 -10.207840 0.039871 20330 36.252563 -9.763153 -0.019913 20331 36.587822 -10.080933 -0.031876 20332 43.304901 -9.301834 0.921211 20333 42.871124 -10.670746 1.163010 20334 43.622406 -9.790283 1.533081 20335 42.255768 -9.939072 0.122551 20336 46.488464 -9.694305 -0.491348 20337 46.290619 -11.661346 0.336014 20338 46.338531 -10.917191 0.005318 20339 47.290985 -10.391617 0.421982 20340 48.279236 -8.925598 0.702202 20341 53.305573 -8.456024 -0.058716 20342 4.492949 -10.322519 2.118578 20343 4.891397 -11.389972 1.098122 20344 36.251526 -11.104858 -0.271591 20345 39.162247 -10.782516 -0.338394 20346 40.216873 -10.904190 -0.158844 20347 41.154160 -10.567566 -0.154587 20348 45.782913 -10.753448 -0.333160 20349 45.082031 -11.341049 -0.645859 20350 45.659973 -11.414963 -0.103348 20351 46.340271 -10.403564 -0.282883 20352 47.086792 -11.768295 0.908539 20353 61.251862 -10.007141 1.246903 20354 35.873169 -11.979889 0.034332 20355 36.806923 -13.613953 0.356331 20356 36.140701 -12.902237 0.246735 20357 5.216694 -12.870665 0.688993 20358 44.768524 -14.357880 0.528687 20359 42.431625 -17.205719 -0.084961 20360 43.805969 -16.575745 1.350876 20361 42.871964 -17.710999 1.338097 20362 43.037552 -16.080643 -0.349121 20363 44.350464 -15.429962 0.797997 20364 62.760422 -14.291321 0.053818 20365 37.354263 -15.884796 0.448982 20366 37.232109 -14.755539 0.346115 20367 7.565713 -20.078278 0.097980 20368 8.016993 -21.015553 0.247938 20369 8.006216 -20.677984 -0.463182 20370 62.455627 -17.219772 -0.251411 20371 62.746704 -16.129074 0.707398 20372 62.965118 -15.492065 0.702484 20373 15.274694 -18.395706 0.047148 20374 62.037460 -18.046707 -0.097961 20375 61.018219 -20.873215 -0.772476 20376 59.999573 -21.843918 -0.502335 20377 61.501251 -20.112640 -0.894768 20378 8.498301 -21.356560 -0.820510 20379 8.585066 -21.249147 -1.380293 20380 60.344727 -20.667038 -0.068245 20381 59.216156 -22.799698 -0.516968 20382 8.824280 -21.663542 -1.230880 20383 9.156068 -22.192326 -0.910513 20384 9.804984 -22.648510 -1.574205 20385 51.172943 -25.592300 -1.286453 20386 52.384247 -26.608688 -0.333939 20387 57.960617 -24.125626 0.358872 20388 13.513814 -26.383204 0.000531 20389 14.789931 -27.178448 -0.146920 20390 50.852737 -26.815414 -1.021202 20391 51.469681 -26.826706 -0.595963 20392 11.246708 -24.087879 -1.429519 20393 12.786304 -25.786573 -0.192805 20394 10.471056 -23.310310 -1.612128 20395 11.615231 -24.625288 -0.872039 20396 56.530396 -28.729507 -2.516289 20397 62.604828 -28.267731 -1.390259 20398 63.820908 -28.376556 -1.342751 20399 18.565916 -29.314856 -0.262276 20400 14.629292 -27.572983 0.739387 20401 14.639421 -28.013119 1.394159 20402 15.208699 -28.314335 1.165390 20403 19.684685 -29.246702 -0.912591 20404 33.131519 -30.137064 -2.251299 20405 33.978790 -29.661514 -2.187866 20406 51.243332 -28.176926 -1.470566 20407 60.212982 -29.931213 -1.756714 20408 61.727966 -29.050323 -1.217598 20409 62.921280 -29.086212 -1.072342 20410 63.656311 -29.042801 -0.974716 20411 21.989027 -29.996799 -1.024431 20412 20.977777 -29.718206 -0.944398 20413 32.771927 -31.973190 -0.784142 20414 54.871109 -31.920883 -0.561897 20415 54.413742 -31.851059 0.331558 20416 54.341858 -30.623367 0.234017 20417 55.896957 -30.351868 -1.800537 20418 55.641113 -31.623703 -1.518967 20419 61.150787 -29.933655 -1.322327 20420 59.052658 -30.595978 -2.301308 20421 64.060226 -29.041870 -1.054451 20422 64.627060 -29.108170 -1.541489 20423 21.842379 -30.623112 -0.350433 20424 20.757742 -30.439859 -0.098131 20425 20.195339 -29.967752 -0.355313 20426 22.747007 -30.950468 -0.358811 20427 62.197571 -30.051849 -1.414528 20428 23.277798 -32.475533 0.805926 20429 24.288736 -32.250816 0.280972 20430 22.316851 -31.634054 0.430143 20431 18.990540 -35.041550 -1.546097 20432 27.982813 -32.598495 -0.170200 20433 28.063210 -33.478264 0.414643 20434 33.747459 -33.310043 -1.649643 20435 45.247040 -33.773376 -0.968948 20436 47.022690 -32.480988 -0.846252 20437 50.592468 -32.162537 0.175797 20438 51.693115 -32.335052 0.025940 20439 52.357056 -32.791260 -1.757515 20440 55.433350 -32.420227 -1.469452 20441 16.354362 -35.967606 -1.472923 20442 14.977310 -35.581223 -2.437897 20443 16.891724 -34.853760 -2.145554 20444 20.985275 -34.764603 -2.158295 20445 33.616096 -35.017227 -1.374786 20446 52.157288 -32.774612 -0.910889 20447 52.836838 -32.961823 -1.363358 20448 54.451508 -32.642868 -0.798492 20449 54.983002 -32.760529 -1.434906 20450 13.341682 -36.796616 -2.248100 20451 11.726456 -37.255844 -2.028648 20452 22.366257 -35.511154 -1.783768 20453 23.955414 -36.434952 -1.497406 20454 22.396667 -34.862381 -2.412170 20455 33.889633 -36.700668 -1.919670 20456 25.794388 -37.021835 -1.833374 20457 33.867455 -38.243011 -2.670914 20458 34.500748 -38.521408 -3.038887 20459 63.266342 -35.903732 -1.139175 20460 63.829514 -36.033997 -1.146561 20461 28.098907 -37.556427 -2.169426 20462 27.140564 -38.052399 -1.106804 20463 26.889679 -37.406342 -1.905708 20464 51.995178 -37.652557 -2.016098 20465 59.608734 -36.991119 -1.470085 20466 61.375275 -36.452209 1.139465 20467 61.958115 -36.159546 -0.237564 20468 64.470718 -36.629196 -0.886322 20469 63.677094 -35.889359 -0.653305 20470 33.866119 -37.603592 -2.191025 20471 47.384399 -37.443680 -0.424988 20472 46.463440 -36.916275 -0.258232 20473 47.202347 -37.632797 -1.213669 20474 48.183136 -37.790161 -1.115784 20475 50.955399 -37.942734 -1.838699 20476 52.124390 -38.169678 -1.362030 20477 53.006363 -38.692917 -0.241875 20478 56.696503 -37.846573 -1.543579 20479 56.427826 -39.072250 -2.532372 20480 58.889954 -37.188919 -0.422508 20481 57.575775 -37.611664 -0.986893 20482 65.114807 -37.934555 -0.654923 20483 10.745071 -39.294205 -2.624313 20484 10.502289 -39.047867 -1.932816 20485 31.153503 -37.726852 -1.702469 20486 32.873581 -37.535110 -1.723946 20487 31.881426 -36.941422 -0.449005 20488 30.755569 -37.134308 -0.356811 20489 45.769348 -36.339310 -0.562454 20490 49.084106 -38.147522 -0.900223 20491 11.463242 -40.341095 -2.670448 20492 10.612251 -40.168396 -1.782532 20493 12.463974 -41.712097 -2.361252 20494 22.034737 -44.404297 -3.226616 20495 28.007591 -44.082932 -2.790550 20496 64.522034 -42.880096 -1.684876 20497 65.325653 -42.947510 -2.867729 20498 64.863800 -44.337219 -2.400436 20499 13.854004 -44.345901 -2.100632 20500 13.205170 -42.982025 -2.063667 20501 20.685951 -44.765182 -3.116478 20502 16.929321 -46.556168 -3.362808 20503 15.316467 -45.264069 -3.203453 20504 15.824387 -47.245468 -3.135452 20505 18.081329 -45.994202 -3.293480 20506 28.608322 -44.512802 -3.073914 20507 27.618393 -44.566376 -2.913742 20508 32.208130 -45.973495 -4.060661 20509 14.231445 -46.041397 -1.859421 20510 14.990768 -47.022797 -2.584152 20511 24.571411 -46.077438 -3.573456 20512 16.573059 -47.617706 -3.224274 20513 17.583374 -48.242081 -2.950470 20514 18.177414 -46.958450 -3.083954 20515 18.989571 -46.361832 -3.132568 20516 20.450272 -46.575623 -3.335365 20517 27.856827 -49.238220 -3.625366 20518 46.363480 -48.176758 -0.830902 20519 53.893951 -46.619125 -2.375267 20520 15.469246 -48.530106 -2.401291 20521 19.269211 -47.601105 -3.157867 20522 19.244675 -48.803558 -3.144875 20523 30.301498 -47.662796 -3.454147 20524 57.300629 -45.765778 -1.088821 20525 59.789520 -48.398666 -2.616997 20526 58.593567 -48.435806 -2.984833 20527 29.479294 -48.799850 -3.259834 20528 30.232300 -48.948563 -3.128143 20529 30.158531 -49.632751 -3.191650 20530 29.020981 -49.895645 -3.155396 20531 30.253021 -48.551590 -3.238113 20532 19.746819 -49.763748 -3.311821 20533 27.985855 -51.372437 -3.278343 20534 62.176697 -47.242935 -1.403488 20535 62.842697 -47.274994 -1.417656 20536 61.278534 -48.882462 -2.639236 20537 19.729561 -50.746399 -3.648376 20538 26.910095 -50.396255 -3.616882 20539 24.843910 -53.015686 -3.829628 20540 29.962387 -50.791061 -3.293106 20541 30.011787 -52.056198 -3.382126 20542 45.232468 -53.305862 -2.225433 20543 44.496460 -52.132767 -1.661629 20544 30.407333 -53.036209 -3.498055 20545 44.485123 -51.396637 -2.193268 20546 19.977051 -52.588791 -3.127937 20547 30.425087 -53.837967 -3.553291 20548 17.532425 -53.574646 -3.652061 20549 19.641068 -52.900223 -3.138031 20550 25.726616 -53.706924 -3.736618 20551 25.327560 -52.676422 -3.543594 20552 26.506104 -52.714523 -3.450035 20553 25.715942 -52.623978 -3.482964 20554 26.661209 -53.771057 -3.651543 20555 27.591637 -53.508774 -3.500298 20556 29.220093 -53.322769 -3.304337 20557 30.063332 -54.833740 -3.567734 20558 46.787842 -53.546936 -3.139008 20559 15.749359 -54.746567 -4.301956 20560 16.419006 -54.621185 -3.779579 20561 26.886337 -55.023056 -3.906677 20562 28.198067 -55.694321 -3.651962 20563 28.543289 -54.672409 -3.539803 20564 48.058609 -54.420532 -3.199013 20565 16.517059 -56.741821 -3.312576 20566 29.236931 -55.616867 -3.444107 20567 30.207054 -56.375839 -3.753143 20568 49.322266 -55.339371 -3.276367 20569 16.304138 -57.855362 -3.280334 20570 28.755234 -56.616516 -3.508713 20571 47.972397 -55.199326 -2.756554 20572 50.821808 -56.284363 -3.374023 20573 52.205200 -58.001297 -3.340408 20574 53.097717 -58.905243 -3.522553 20575 15.947159 -58.797882 -3.766617 20576 29.121063 -61.590668 -3.513779 20577 28.670197 -60.512131 -3.013001 20578 38.488754 -58.823471 -4.417259 20579 50.988190 -57.521439 -3.027763 20580 52.674454 -60.526398 -3.652908 20581 14.434410 -60.232437 -3.436928 20582 15.257874 -59.686707 -3.835121 20583 15.437141 -59.686966 -2.902679 20584 51.552979 -58.924973 -3.105255 20585 14.878494 -60.427261 -4.458755 20586 26.695908 -60.425949 -2.717506 20587 49.857727 -61.217560 -3.286041 20588 50.616638 -60.068222 -3.101616 20589 51.289001 -61.736023 -3.736984 20590 28.642426 -61.353943 -2.921608 20591 13.283089 -60.766449 -3.250450 20592 49.142731 -62.019257 -3.561173 20593 48.172150 -61.290634 -3.119667 20594 48.972290 -61.072571 -3.115234 20595 11.542953 -63.080353 -3.472336 20596 11.967125 -61.738327 -2.935188 20597 22.509186 -63.886688 -3.208763 20598 24.194260 -62.478317 -2.927567 20599 45.301468 -62.622574 -3.043655 20600 44.444305 -63.073929 -2.416786 20601 44.827271 -62.117874 -2.564362 20602 47.359375 -62.023605 -3.285561 20603 11.638016 -64.518967 -3.855469 20604 12.437279 -64.528366 -4.671844 20605 24.165588 -63.099518 -1.867149 20606 23.526047 -64.036621 -1.092773 20607 24.512100 -63.557663 -1.008911 20608 45.652802 -63.681519 -3.485672 20609 44.712646 -64.412308 -2.711586 20610 12.825286 -65.488892 -4.128098 20611 28.289917 -63.082550 -2.588821 20612 11.126480 -65.037155 -3.390640 20613 11.026566 -65.455505 -3.033966 20614 11.810669 -65.514069 -3.408882 20615 13.650360 -66.205322 -3.562119 20616 16.489731 -66.460312 -4.326180 20617 17.377129 -66.075134 -4.176895 20618 27.558098 -66.330124 -3.879517 20619 26.761337 -67.378738 -4.327980 20620 46.201950 -62.242981 -3.156593 20621 27.145020 -67.403091 -3.729507 20622 38.241714 -67.482010 -3.536697 20623 40.637665 -67.372910 -4.513916 20624 44.866577 -65.953995 -3.581696 20625 45.930527 -68.358932 -4.119804 20626 11.294036 -69.283691 -4.410149 20627 10.476379 -70.147064 -4.822296 20628 12.080681 -68.765869 -3.320671 20629 19.577057 -68.718781 -4.304878 20630 21.216583 -69.110687 -3.388336 20631 20.154594 -68.264297 -3.452347 20632 27.383163 -67.246368 -3.044563 20633 26.997711 -67.924438 -2.032196 20634 26.928001 -68.783203 -3.530586 20635 45.652679 -67.800873 -3.474396 20636 10.356621 -69.458710 -3.879288 20637 9.998947 -70.189209 -4.111733 20638 15.150757 -70.167999 -4.721382 20639 10.153793 -70.855652 -4.657226 20640 10.408920 -71.409470 -4.632507 20641 15.645172 -69.882553 -3.705811 20642 16.508530 -69.998871 -3.934708 20643 38.570839 -71.291519 -3.518494 20644 37.752670 -69.267731 -1.801209 20645 10.841522 -71.857025 -5.058899 20646 20.443268 -72.100464 -4.342339 20647 20.737503 -71.698914 -3.857750 20648 26.955048 -72.043304 -4.738914 20649 26.995399 -70.769913 -4.055443 20650 27.744522 -71.929001 -3.870682 20651 45.905243 -71.745346 -4.265533 20652 20.497444 -72.741516 -4.429047 20653 27.813965 -73.021957 -4.702042 20654 38.616783 -71.818802 -2.120331 20655 38.104370 -70.796906 -2.165504 20656 42.915787 -70.842484 -3.572266 20657 43.755753 -71.249771 -3.001434 20658 45.480530 -71.976288 -4.238693 20659 28.505707 -73.156357 -3.940521 20660 28.892006 -73.559631 -3.887192 20661 28.891441 -73.912399 -4.189400 20662 28.533020 -74.081360 -4.762581 20663 40.632690 -74.264984 -3.560516 20664 40.132050 -73.749298 -2.358795 20665 39.294250 -72.903122 -3.032089 20666 15.414642 -74.908310 -5.123398 20667 14.819107 -74.348801 -3.721031 20668 21.529373 -73.825211 -4.167877 20669 22.357986 -75.873581 -4.736633 20670 28.873177 -75.018890 -4.474762 20671 28.723495 -76.764923 -4.829750 20672 45.814941 -75.565445 -4.329575 20673 44.729370 -75.469971 -4.218445 20674 22.060356 -76.502579 -4.700279 20675 20.970634 -77.581558 -4.797562 20676 19.423195 -78.486725 -4.358696 20677 43.450073 -75.361938 -4.101654 20678 42.182343 -74.859482 -2.911430 20679 9.584016 -78.957214 -5.163185 20680 14.866760 -77.479523 -4.711143 20681 15.437813 -76.998016 -4.173042 20682 9.660416 -78.243439 -3.280533 20683 9.370483 -78.959045 -4.100685 20684 18.171722 -79.379349 -4.128937 20685 17.888252 -79.224274 -5.333160 20686 26.722580 -78.341751 -3.471573 20687 27.470581 -78.137390 -4.035156 20688 27.422508 -77.962143 -3.163483 20689 28.089249 -77.838303 -4.808220 20690 48.025162 -77.013062 -3.801804 20691 25.810883 -79.785797 -4.940536 20692 47.777618 -78.229507 -4.381439 20693 11.153046 -80.811050 -5.519699 20694 11.328964 -81.195419 -4.790359 20695 11.836838 -80.880386 -5.729652 20696 25.981781 -80.435028 -5.082016 20697 26.368515 -80.998611 -5.184662 20698 45.355667 -81.580536 -4.988373 20699 46.840118 -79.423996 -3.725723 20700 47.300385 -78.762558 -3.497185 20701 6.754265 -82.866867 -5.764511 20702 6.013420 -83.148102 -5.662567 20703 11.880348 -81.091919 -5.205376 20704 20.892029 -82.157104 -6.289123 20705 27.976685 -82.041550 -5.339149 20706 28.005066 -82.588837 -4.751327 20707 36.439911 -82.222427 -4.143021 20708 36.724136 -81.501465 -4.011704 20709 38.066696 -81.350327 -4.825806 20710 44.793503 -81.508286 -4.028580 20711 46.492920 -80.037003 -4.097511 20712 19.316238 -81.353256 -3.881149 20713 18.737823 -81.278015 -4.241516 20714 23.353600 -81.229980 -3.208923 20715 21.936737 -81.094498 -2.692657 20716 21.681519 -81.929626 -3.801743 20717 39.603859 -81.386337 -4.609695 20718 45.539337 -80.761948 -3.808830 20719 6.635552 -83.445404 -5.126663 20720 8.097595 -83.610291 -5.359795 20721 24.616623 -83.427734 -4.933472 20722 24.707108 -84.163849 -5.213943 20723 36.530289 -83.550201 -4.272759 20724 42.178558 -82.353912 -4.893471 20725 5.993179 -83.853210 -5.365494 20726 6.001747 -84.672485 -5.580109 20727 13.705116 -82.430405 -4.254753 20728 14.404999 -83.596939 -4.262177 20729 25.279442 -84.939423 -4.314156 20730 25.152443 -84.038788 -4.674057 20731 6.326752 -85.702484 -5.820702 20732 17.778717 -86.060730 -4.651924 20733 28.788910 -85.832718 -5.370529 20734 38.452942 -85.300858 -4.221817 20735 39.632774 -85.906616 -4.496498 20736 39.103683 -85.651413 -4.256317 20737 6.849442 -86.708862 -5.330307 20738 7.494087 -87.743286 -5.742706 20739 13.025620 -86.315567 -5.409935 20740 13.615669 -86.963684 -5.795044 20741 18.211250 -86.788605 -3.553490 20742 18.504486 -86.821655 -4.173569 20743 23.120300 -86.340591 -5.620071 20744 24.146400 -85.958130 -4.747055 20745 28.731537 -86.656403 -4.525940 20746 29.810303 -87.109863 -5.316826 20747 30.697739 -87.546448 -5.527946 20748 31.464462 -87.769409 -5.536819 20749 8.158035 -88.399185 -4.557732 20750 18.487411 -88.528702 -5.621475 20751 31.865267 -87.977264 -5.527771 20752 34.994576 -89.611450 -6.040443 20753 9.758942 -89.483322 -5.664886 20754 15.690536 -89.436401 -5.689796 20755 19.004852 -89.640335 -4.860397 20756 25.038605 -88.271683 -4.954773 20757 27.020172 -89.584671 -5.771072 20758 34.187622 -89.252472 -5.513878 20759 10.867462 -90.500320 -6.076530 20760 10.935127 -89.929550 -4.734848 20761 19.507172 -90.692841 -6.217285 20762 29.477676 -91.052368 -5.700127 20763 16.683052 -91.392624 -5.540176 20764 30.127083 -90.561462 -4.818451 20765 31.682650 -90.276947 -4.592270 20766 32.279251 -91.041168 -5.839416 20767 12.510712 -93.625168 -5.468552 20768 16.528435 -94.255386 -6.919556 20769 16.935181 -93.454849 -6.491630 20770 12.468552 -94.361099 -6.163208 20771 17.126099 -94.361267 -6.905838 20772 23.266563 -95.735931 -5.725372 20773 24.531662 -94.300934 -5.551468 20774 26.198166 -94.413361 -5.635376 20775 37.573456 -93.923676 -5.589935 20776 12.821259 -95.362396 -6.106628 20777 24.668640 -93.786087 -4.637566 20778 23.842316 -94.531937 -5.010002 20779 26.634514 -94.771484 -5.576248 20780 26.933411 -95.595612 -5.971596 20781 33.556305 -95.934189 -5.747772 20782 13.367081 -95.957489 -5.301102 20783 22.626633 -96.702713 -5.736084 20784 27.504868 -98.011810 -5.975410 20785 27.004013 -96.426468 -6.235336 20786 27.343628 -96.234924 -5.581116 20787 27.261810 -96.992432 -5.812393 20788 27.725784 -96.675293 -4.629455 20789 14.134171 -98.127289 -6.756523 20790 14.436348 -97.502838 -5.860153 20791 17.352524 -99.214920 -5.964165 20792 17.024384 -99.581070 -6.375275 20793 16.239471 -98.707138 -6.127037 20794 15.194542 -96.723801 -4.828888 20795 17.532150 -98.213272 -5.218689 20796 23.427681 -97.821533 -4.817871 20797 28.142036 -98.885941 -6.143165 20798 28.711517 -99.168167 -5.955002 20799 29.747528 -98.768753 -5.272446 20800 29.220543 -99.177780 -6.189697 20801 29.150894 -99.071182 -5.550873 20802 16.894470 -100.197952 -6.611671 20803 17.421776 -100.120102 -5.941116 20804 23.956993 -101.413315 -5.085945 20805 17.625710 -101.614609 -6.488037 20806 5.421173 62.378677 4.726090 20807 5.955269 62.512970 5.042488 20808 6.473335 62.744598 6.090423 20809 5.175263 62.235779 5.432968 20810 4.249855 60.804733 3.523659 20811 4.323952 61.078110 5.040535 20812 10.860413 58.602829 4.232765 20813 10.244979 59.558655 4.567368 20814 11.573662 57.852203 4.107926 20815 11.786133 58.475494 4.618012 20816 22.628738 55.673004 5.072037 20817 12.598969 57.713013 4.534561 20818 29.037094 56.773743 5.200546 20819 28.382889 57.777756 6.112945 20820 25.296234 58.422150 5.890228 20821 23.376915 58.306030 6.115020 20822 29.299667 56.729416 4.472077 20823 29.380554 56.229401 4.550713 20824 4.513176 53.749710 3.026344 20825 5.282837 54.540451 3.648171 20826 6.166359 55.437805 4.657677 20827 13.897476 57.218628 4.938629 20828 16.177399 54.912506 4.263596 20829 21.600838 54.777618 5.012566 20830 22.443802 54.774567 4.286636 20831 28.977936 55.575714 4.699341 20832 8.454773 54.526031 4.742218 20833 8.604126 53.894089 4.227081 20834 17.354599 55.841583 5.824493 20835 16.415588 56.942154 6.127258 20836 15.918259 55.721008 5.155243 20837 17.257065 54.606812 4.057251 20838 18.341095 54.477142 4.321571 20839 19.328262 54.198532 4.136322 20840 19.078316 54.242737 4.539871 20841 20.094742 54.398453 4.708107 20842 19.457443 54.051697 4.380814 20843 21.090927 54.286591 4.065529 20844 21.782333 54.411728 4.297348 20845 21.191406 54.200623 4.450638 20846 33.425156 54.087402 4.999954 20847 33.117645 53.220078 4.513092 20848 34.194855 53.884674 4.300858 20849 32.340202 53.874283 6.161521 20850 34.116592 54.581070 5.479019 20851 37.791367 53.785583 4.318855 20852 35.536743 54.436249 5.499252 20853 38.216270 52.882263 4.898865 20854 39.006256 51.442261 4.781067 20855 20.865417 54.066528 4.352577 20856 37.819214 51.610962 5.485962 20857 27.496834 54.936569 6.413543 20858 11.492569 52.551697 5.582115 20859 11.553436 51.580444 4.714317 20860 10.856064 51.886063 4.403969 20861 11.895660 49.804825 4.039230 20862 25.823044 50.519684 3.937515 20863 28.253822 54.745743 5.243157 20864 28.461487 54.340118 4.211586 20865 12.748032 47.679016 3.754707 20866 24.704208 49.616699 4.648422 20867 25.288589 50.522491 4.713295 20868 37.871941 48.151672 4.492432 20869 38.765427 49.225601 4.531677 20870 39.404083 47.870178 3.810791 20871 12.714516 48.549728 4.633087 20872 39.363617 50.324081 4.523865 20873 12.635834 47.010498 4.137337 20874 12.531799 45.910126 3.449249 20875 23.427917 47.298370 4.739716 20876 23.229408 48.432465 5.629920 20877 23.940880 48.824341 5.033875 20878 38.203728 47.219238 3.977692 20879 24.404480 47.962906 3.829193 20880 23.965981 47.513107 4.265579 20881 28.641373 46.660706 4.872177 20882 37.759079 46.297607 3.657166 20883 37.278961 47.204727 4.263847 20884 4.574928 44.948257 3.889954 20885 26.955788 44.254379 5.054810 20886 25.682625 44.379944 6.119903 20887 3.784973 42.762039 4.570358 20888 10.187225 45.974152 4.993950 20889 36.278076 48.063416 5.010361 20890 4.058174 41.611786 2.887955 20891 22.867783 45.759323 5.058197 20892 23.265099 44.453674 4.795517 20893 33.746201 42.985443 4.266975 20894 34.000572 44.503662 4.825104 20895 4.588738 41.625977 3.974701 20896 26.408096 42.415771 3.224594 20897 26.560272 42.696136 3.692604 20898 33.680878 42.429108 5.309502 20899 6.298271 39.912842 2.887657 20900 6.765373 40.811569 4.291168 20901 7.120865 39.702087 3.202118 20902 39.801773 39.745239 4.136398 20903 40.258942 38.504059 4.830109 20904 38.961464 38.535309 4.823296 20905 37.795586 39.492737 4.259323 20906 48.664917 39.299545 3.959824 20907 47.773865 39.324982 4.042343 20908 48.909897 38.921417 5.218857 20909 9.838440 39.674927 4.215683 20910 9.142517 38.423538 3.022614 20911 8.358383 39.275818 3.393776 20912 10.242448 38.110138 3.200928 20913 34.328354 41.773102 5.604110 20914 35.143082 40.547699 4.962853 20915 34.258507 40.103989 3.780319 20916 11.364159 38.310364 3.694496 20917 12.470474 37.858109 3.969818 20918 12.143707 36.940155 3.511330 20919 11.769341 35.849335 3.092766 20920 12.189140 35.891846 3.858574 20921 52.347000 34.433853 4.041580 20922 52.223145 35.806854 5.304192 20923 2.970482 33.183975 2.895180 20924 3.640030 34.087494 3.137619 20925 3.010681 33.820496 3.667664 20926 3.198364 34.434875 3.903694 20927 3.314392 33.029373 2.393196 20928 5.400139 36.167999 4.817490 20929 4.697601 34.908936 3.563011 20930 6.329178 34.390472 3.435074 20931 5.252472 33.286423 2.465561 20932 4.008301 33.055649 2.297684 20933 7.569222 34.498077 3.833130 20934 9.357658 34.786682 4.111504 20935 10.790543 34.215240 2.957054 20936 3.037171 32.558014 3.665627 20937 7.150543 35.653931 4.713242 20938 2.820290 31.242844 3.209274 20939 2.544930 30.098495 2.306931 20940 51.413086 32.061859 4.082810 20941 51.306915 30.516235 3.171478 20942 2.255333 27.760834 2.591354 20943 1.914658 27.259872 3.805542 20944 47.049957 30.584900 4.376793 20945 48.480164 31.329468 4.652550 20946 49.456619 30.782166 3.866425 20947 44.087311 29.215042 3.798287 20948 44.438965 28.600754 3.283348 20949 43.524078 28.603271 3.772751 20950 47.688416 28.385269 2.558762 20951 2.668816 29.135742 3.590767 20952 43.901184 27.640457 3.554077 20953 43.208069 27.875381 4.114609 20954 44.781113 27.613815 2.957794 20955 29.645050 23.003235 2.357033 20956 31.872042 25.506821 3.473984 20957 32.661407 25.296463 2.627594 20958 33.976639 25.381195 2.815582 20959 34.866852 25.565216 3.600098 20960 35.478203 25.358902 3.893494 20961 35.427834 25.240540 2.919426 20962 36.422707 24.922791 3.840088 20963 37.768433 24.374390 3.172920 20964 44.681580 26.452484 3.420853 20965 42.414856 21.672440 2.460266 20966 46.671814 24.013824 2.962723 20967 2.030292 23.254444 3.229874 20968 1.957344 22.659973 2.403061 20969 29.574524 22.040405 2.771675 20970 29.916992 23.627472 3.393501 20971 47.810104 23.474686 2.655800 20972 38.842407 23.516495 3.590668 20973 39.734238 22.859421 3.539673 20974 46.888123 23.055511 3.211685 20975 49.581543 20.244934 2.312775 20976 42.267136 21.769806 3.551949 20977 43.400223 21.160538 2.935616 20978 2.803909 19.534882 1.291092 20979 2.491369 19.561558 2.273461 20980 30.477493 18.562515 2.286636 20981 29.585861 18.120682 1.964310 20982 30.570816 17.138779 1.819344 20983 30.403336 21.650269 3.337051 20984 30.708145 20.176392 2.662857 20985 31.685976 21.099106 3.522270 20986 33.895256 20.746658 3.315567 20987 34.529442 20.287598 2.854477 20988 34.694443 20.531815 3.599213 20989 35.613144 19.799408 3.211258 20990 36.738953 18.889526 3.318253 20991 48.999344 20.263672 2.570160 20992 48.390137 20.268143 2.770134 20993 31.631098 18.996033 2.125656 20994 32.176346 20.095047 2.563988 20995 32.925667 20.868835 3.490257 20996 36.305038 19.351929 4.128723 20997 46.033951 20.058578 2.569664 20998 47.926682 18.691818 1.909775 20999 48.717255 19.462723 2.351059 21000 47.911118 19.196609 2.427002 21001 47.855591 19.747025 2.713104 21002 49.015488 18.719299 1.730141 21003 28.861084 18.262924 1.476868 21004 30.933578 17.635498 2.161789 21005 31.476089 17.910889 2.005402 21006 32.215233 17.063354 1.707337 21007 32.639893 17.931732 1.674927 21008 37.341873 18.248566 3.524796 21009 47.179901 19.502747 2.443390 21010 2.626515 18.181759 1.600779 21011 31.415802 17.103699 1.930458 21012 37.818352 17.434540 2.989670 21013 38.437500 15.464752 2.056732 21014 2.571223 18.598215 2.093373 21015 32.008972 16.054260 1.406441 21016 38.358047 16.276505 2.649887 21017 3.086022 13.268007 0.935841 21018 2.784200 15.089138 1.517719 21019 38.096703 15.328720 2.956909 21020 37.298897 14.055664 3.135079 21021 2.506484 15.831882 2.987461 21022 2.831286 10.357423 3.084320 21023 2.562756 9.830272 4.743672 21024 2.681599 9.256826 4.092157 21025 37.301399 10.383377 2.200920 21026 38.720917 10.168091 2.140305 21027 37.978378 10.152924 2.490662 21028 41.238739 9.548630 2.712692 21029 2.688773 8.616433 4.103003 21030 43.912216 8.170120 1.894272 21031 2.585475 6.346032 2.977112 21032 44.157623 6.557648 2.051643 21033 44.021881 7.477875 1.953438 21034 44.285034 5.407135 2.658440 21035 57.620224 4.408676 1.116753 21036 58.179733 3.733261 1.326164 21037 2.347252 5.450110 2.775779 21038 2.578760 5.478210 1.888691 21039 56.371475 3.663925 1.461655 21040 57.362610 3.621742 1.716698 21041 2.041564 3.566804 2.962129 21042 2.041693 4.171124 3.010672 21043 2.122701 4.616656 2.639612 21044 55.472382 2.854248 1.462547 21045 56.568817 2.934456 2.024887 21046 58.352753 2.951607 2.054054 21047 57.499237 2.574310 2.653763 21048 53.421463 0.143234 2.329926 21049 51.888062 -0.636261 1.176499 21050 56.106583 2.089066 2.490738 21051 59.178329 1.943481 1.935249 21052 59.309769 0.868958 2.603317 21053 59.185928 1.706482 2.756653 21054 39.883926 -1.125259 1.902977 21055 39.796097 -0.666153 1.445511 21056 39.231499 -1.156082 1.166931 21057 39.862167 -0.255630 0.948761 21058 40.567764 -0.603256 1.476616 21059 59.153412 -0.092941 2.422348 21060 2.271171 3.073182 3.339188 21061 2.562329 2.302585 3.167647 21062 5.500605 -0.420675 -1.864376 21063 43.089722 -3.387558 4.411316 21064 45.115799 -0.504837 2.277390 21065 45.269257 0.734573 2.665238 21066 51.122269 -2.022873 1.528107 21067 3.255668 -0.004228 3.193222 21068 3.628536 -0.816496 2.273629 21069 5.471644 -0.471208 -1.850908 21070 5.514628 -0.496483 -1.906555 21071 57.404678 -1.739166 2.520966 21072 58.443481 -0.972122 2.593758 21073 3.891247 -1.862187 1.861359 21074 5.476105 -0.500270 -1.863110 21075 38.992355 -2.390198 1.139618 21076 38.902374 -2.217026 1.989220 21077 42.613892 -4.301834 0.854195 21078 42.547775 -3.478424 0.202698 21079 50.377747 -3.237930 1.210190 21080 4.158864 -2.760195 1.378805 21081 39.220734 -3.533691 1.478760 21082 4.195808 -3.663232 1.459040 21083 50.107391 -6.027405 2.158463 21084 49.490875 -5.846344 1.130013 21085 58.550522 -4.818329 1.292603 21086 59.273392 -4.954056 1.241516 21087 59.623337 -5.565002 1.379517 21088 59.749344 -6.992676 1.215668 21089 59.626694 -5.914719 2.283096 21090 4.314898 -6.471097 1.234671 21091 49.352127 -7.577805 1.655815 21092 55.103485 -6.939682 0.613159 21093 55.474945 -5.925720 1.436989 21094 4.327836 -6.882940 1.283807 21095 43.779419 -7.949844 1.167053 21096 43.374039 -6.463181 1.924111 21097 49.103088 -9.361404 1.696488 21098 54.201126 -6.412018 0.990997 21099 55.587860 -4.791473 2.295647 21100 55.016159 -4.643585 2.309364 21101 54.653717 -4.903015 1.798363 21102 4.377882 -7.348214 1.307455 21103 4.380538 -7.795735 1.443979 21104 4.140911 -6.856646 1.913811 21105 4.199413 -6.566666 1.591896 21106 36.284508 -9.410629 0.259644 21107 36.149269 -9.498077 0.368340 21108 36.232170 -9.212143 0.498894 21109 36.349709 -9.467697 0.433014 21110 4.468249 -9.348637 1.745286 21111 36.321014 -10.132324 0.430657 21112 36.234489 -9.403030 0.566940 21113 37.165527 -10.991714 0.129509 21114 48.485092 -10.310181 1.385643 21115 49.754242 -9.290771 2.898773 21116 57.913574 -9.594177 2.068382 21117 57.966614 -8.831253 2.116379 21118 59.100342 -8.711716 1.702629 21119 60.306473 -9.193451 1.081024 21120 60.068924 -9.785828 1.833130 21121 35.916451 -11.189133 0.427292 21122 36.485718 -11.173508 0.604454 21123 37.189346 -12.142242 0.669441 21124 62.053360 -10.491592 1.122940 21125 4.685393 -12.360747 2.560889 21126 4.840811 -12.125531 1.692832 21127 4.500615 -11.331244 2.700008 21128 35.398506 -12.022034 0.551727 21129 38.319061 -11.645813 0.210587 21130 38.782211 -13.190231 0.859863 21131 39.627808 -11.862198 0.283234 21132 40.880432 -11.800690 0.446823 21133 41.821045 -11.160065 0.463211 21134 47.928757 -11.548737 1.417809 21135 62.881348 -11.909561 1.223953 21136 35.267639 -12.600830 0.704018 21137 35.547531 -12.567184 0.316025 21138 41.176926 -12.770233 1.216019 21139 42.065735 -12.050034 1.356011 21140 63.139709 -13.478989 1.134262 21141 35.541092 -12.877655 0.505524 21142 63.069138 -14.771484 0.848633 21143 37.643181 -16.786606 0.496475 21144 38.285255 -17.423218 0.142349 21145 54.957275 -16.210419 1.548851 21146 55.880539 -15.894745 1.528732 21147 55.080017 -16.879074 0.912880 21148 57.894470 -16.271133 0.708344 21149 57.579926 -15.299805 1.855988 21150 58.664017 -15.808044 0.976425 21151 56.937119 -15.779724 1.064110 21152 58.705063 -16.154037 0.603500 21153 59.443802 -17.126526 0.559441 21154 37.521851 -16.480118 1.302536 21155 56.499039 -16.807938 0.682778 21156 55.748779 -18.520844 0.440491 21157 53.957138 -17.273972 1.369492 21158 54.595520 -16.537872 1.527252 21159 59.502335 -15.527405 1.734970 21160 60.555222 -16.341080 1.074951 21161 61.447983 -17.289566 0.399948 21162 5.536838 -15.064727 1.259665 21163 38.250534 -18.386841 1.210449 21164 37.788513 -17.599548 0.970688 21165 41.886307 -18.103989 0.345352 21166 61.474487 -16.322296 1.316986 21167 62.208496 -16.655167 0.772965 21168 39.156364 -19.299179 0.902611 21169 38.759750 -20.456070 1.613800 21170 38.202293 -19.582596 1.910782 21171 54.410904 -18.261978 0.526894 21172 53.143494 -18.603317 0.770294 21173 54.908295 -19.669403 0.458778 21174 53.844055 -19.421707 0.432221 21175 7.058349 -18.803722 -0.120596 21176 52.286316 -19.493225 0.906990 21177 53.078003 -19.445969 0.529511 21178 57.398651 -18.833450 0.479767 21179 59.118851 -20.047806 0.339783 21180 57.757263 -20.692657 0.669815 21181 52.181290 -18.818970 1.494049 21182 52.907333 -18.040787 1.611549 21183 53.115234 -20.281616 0.732269 21184 54.168396 -20.376633 0.640381 21185 54.916199 -21.091766 0.888023 21186 56.100296 -20.419785 0.721237 21187 57.032684 -20.490112 0.706711 21188 61.167862 -20.241959 -0.377884 21189 5.914773 -16.231300 0.906026 21190 5.714281 -16.133045 1.706116 21191 6.287860 -17.325920 0.782561 21192 59.464661 -21.446167 0.315247 21193 8.423252 -21.491444 -0.210729 21194 58.586288 -23.110565 0.366898 21195 8.675704 -21.915916 -0.104909 21196 9.807329 -22.966875 -0.868861 21197 57.171738 -24.948914 0.316818 21198 11.314141 -24.813284 0.155717 21199 10.815608 -24.262215 -0.160303 21200 10.529001 -24.311356 0.696649 21201 10.643600 -23.807753 -0.875417 21202 12.093861 -25.298826 -0.164478 21203 56.821198 -25.443665 0.625534 21204 9.866467 -23.266434 -0.362796 21205 10.241770 -23.635382 -0.471024 21206 52.544250 -29.064651 -0.485367 21207 60.952820 -29.445526 -1.248230 21208 15.872677 -28.909395 1.328224 21209 15.620199 -28.263838 0.658227 21210 16.435776 -29.790224 2.028364 21211 17.494143 -30.167892 1.551374 21212 17.071896 -29.447617 0.965795 21213 19.597992 -30.538111 0.560604 21214 53.174072 -29.536102 -0.414429 21215 54.471069 -30.424362 -0.901268 21216 53.790985 -30.034973 -0.168671 21217 17.919226 -29.748606 0.679981 21218 18.681391 -30.162357 0.663254 21219 18.520628 -30.918123 1.661452 21220 19.497988 -31.868460 2.035333 21221 20.463928 -32.235649 1.850217 21222 21.316032 -31.988646 1.185526 21223 20.303820 -31.478451 1.178024 21224 54.845886 -30.830902 1.120331 21225 21.044405 -31.132238 0.480510 21226 26.030855 -32.065361 -0.313953 21227 30.034557 -31.657093 -0.924254 21228 55.214172 -31.712296 -0.976334 21229 25.191372 -32.775414 0.432250 21230 24.335989 -33.323303 1.113570 21231 25.132906 -32.121319 -0.056354 21232 26.986765 -32.633057 -0.045099 21233 29.755102 -33.237442 0.495511 21234 28.936287 -33.201679 0.274160 21235 29.010548 -34.130360 0.859118 21236 29.919130 -32.425568 -0.201854 21237 32.169998 -33.069778 0.391693 21238 32.819084 -33.741684 -0.397430 21239 45.522003 -32.764175 -0.504746 21240 48.585052 -32.165955 -0.260933 21241 17.545937 -35.115448 -1.793976 21242 42.404007 -34.957596 2.336655 21243 42.585114 -34.039795 1.751862 21244 43.273422 -35.152618 1.587952 21245 43.351135 -31.940552 1.185059 21246 42.649979 -31.319122 1.841171 21247 43.205444 -31.155609 1.683647 21248 52.613510 -32.984085 -1.030914 21249 53.280655 -32.596603 -0.421982 21250 44.597351 -34.717041 -0.355301 21251 12.320786 -37.614532 -1.607849 21252 16.636810 -36.407822 -0.192825 21253 15.898376 -36.770599 -0.288772 21254 17.197510 -36.090057 -0.487503 21255 22.288345 -36.469055 -0.617950 21256 20.716278 -36.564621 0.158753 21257 20.721024 -35.760071 -0.994186 21258 32.668709 -34.816208 -0.130188 21259 45.052994 -35.675613 -0.169907 21260 62.939713 -35.864838 -0.451881 21261 11.035248 -38.319504 -1.649261 21262 15.017632 -36.818832 -1.806107 21263 15.492714 -37.203827 -0.987457 21264 14.709717 -38.087646 -1.576401 21265 25.452927 -37.834137 -0.576172 21266 26.719254 -38.597214 -0.405396 21267 26.861862 -38.852951 -0.110748 21268 26.177139 -38.595764 0.656944 21269 29.875084 -37.684845 -0.814941 21270 50.037918 -38.464447 -1.343246 21271 51.703064 -38.611084 -0.971725 21272 56.199158 -38.099426 -0.663178 21273 11.176743 -40.233337 0.118126 21274 10.151878 -40.706573 0.180008 21275 10.580338 -39.828354 -0.916183 21276 14.046783 -38.869400 -1.607910 21277 14.727058 -39.155624 -1.568649 21278 13.255478 -38.169373 -1.558853 21279 15.452347 -39.160431 -1.124275 21280 28.650101 -37.948532 -0.903168 21281 49.507874 -38.465149 -1.071175 21282 50.818390 -38.745529 -0.788658 21283 13.125160 -39.011337 -1.212509 21284 14.007370 -39.415070 -1.354576 21285 14.691338 -39.871796 -1.167969 21286 51.714386 -38.902100 -0.144058 21287 64.791916 -39.550278 -0.661934 21288 11.159882 -41.402832 -1.479515 21289 62.302124 -40.779327 0.146111 21290 63.542221 -40.522644 -0.409790 21291 62.441711 -41.377075 -0.607056 21292 64.408920 -40.801437 -1.003876 21293 63.122711 -43.652191 -1.134697 21294 63.490662 -41.823441 -1.076050 21295 64.654236 -41.565231 -1.416046 21296 12.087250 -42.507538 -1.350884 21297 12.951843 -43.530655 -1.477539 21298 58.814178 -43.365356 2.224915 21299 59.746521 -42.441177 0.641220 21300 58.260635 -43.475662 0.518570 21301 61.302841 -41.887848 -0.360107 21302 62.160522 -42.490707 -0.970840 21303 61.024414 -43.311188 -0.899292 21304 61.906555 -43.755005 -1.048843 21305 59.360291 -43.287888 -0.382446 21306 59.628601 -43.480469 -0.768463 21307 59.573563 -44.188263 -0.687363 21308 60.110565 -42.853912 -0.523392 21309 60.998978 -44.738327 -0.945213 21310 62.189682 -44.904846 -0.985954 21311 63.111755 -44.867050 -0.918335 21312 64.123840 -44.512436 -1.388229 21313 21.567154 -45.753403 -3.191269 21314 47.995117 -46.017715 -1.381577 21315 48.474274 -45.729080 -1.460289 21316 48.884506 -45.677826 -1.434029 21317 49.788086 -45.776138 -1.230942 21318 63.956818 -45.566544 -1.390160 21319 53.343018 -45.924713 -1.315079 21320 54.659058 -45.879303 -1.204491 21321 55.949097 -44.926361 -0.107010 21322 57.716553 -44.613174 -0.366630 21323 16.312393 -48.164764 -2.986328 21324 18.448471 -49.902649 -2.581009 21325 19.386993 -50.922455 -2.648804 21326 45.273529 -49.409943 -0.561714 21327 44.770538 -48.844254 -1.658508 21328 59.882767 -47.339142 -1.883759 21329 61.110321 -46.411407 -1.277344 21330 61.165833 -47.742813 -1.913284 21331 16.469475 -48.884247 -2.718712 21332 17.065117 -49.657501 -2.457870 21333 16.188248 -49.535492 -2.355499 21334 15.670837 -49.892212 -1.565666 21335 16.470596 -50.157455 -1.981422 21336 14.397263 -47.699173 -1.548111 21337 14.731094 -48.972260 -1.298431 21338 17.314453 -50.755569 -1.584793 21339 18.602158 -51.103180 -1.865448 21340 44.416672 -49.824005 -1.673294 21341 44.491714 -50.776337 -1.131943 21342 52.233398 -51.363312 -1.145935 21343 52.594330 -50.507523 -0.631302 21344 51.701843 -50.798264 -0.787521 21345 54.489929 -51.685974 -1.336792 21346 53.166916 -51.399139 -1.255821 21347 53.580933 -52.367050 -1.533615 21348 19.294662 -52.196869 -1.693558 21349 19.762398 -52.865509 -2.509964 21350 53.718689 -50.340149 -0.264801 21351 55.767609 -51.493607 -0.856033 21352 55.893631 -53.076874 -1.573746 21353 56.494324 -52.367554 -1.282761 21354 56.811981 -51.868637 -0.457504 21355 57.392258 -53.133789 -1.163704 21356 17.424408 -54.989563 -2.825623 21357 17.794205 -56.269943 -2.204864 21358 16.800262 -55.757782 -2.878693 21359 18.885033 -54.089722 -2.400162 21360 54.419495 -52.967484 -1.598068 21361 17.505753 -54.231689 -3.157829 21362 45.890900 -54.174759 -2.409515 21363 45.328613 -54.284698 -1.976685 21364 45.891251 -54.961319 -1.983368 21365 46.949585 -54.607498 -2.626373 21366 47.067688 -55.455612 -2.281609 21367 54.828156 -54.131546 -1.296005 21368 57.252884 -53.997681 -1.546951 21369 56.540619 -54.636734 -1.419640 21370 57.586777 -54.637329 -1.440659 21371 16.603874 -55.234177 -3.154007 21372 58.358490 -54.350967 -1.076141 21373 48.189392 -56.063126 -2.492264 21374 49.558258 -56.740417 -2.757568 21375 49.546066 -58.343689 -2.635513 21376 48.003540 -57.190048 -2.135872 21377 46.876587 -56.298477 -1.902145 21378 27.716049 -59.634476 -2.965500 21379 46.845795 -59.289001 -2.079300 21380 46.647903 -60.643250 -2.602356 21381 45.401138 -59.543655 -1.516296 21382 48.527588 -59.919220 -2.715408 21383 47.536682 -58.373520 -2.052147 21384 12.572838 -61.145477 -3.203552 21385 14.119836 -60.887466 -2.257164 21386 12.745422 -61.039490 -2.573898 21387 44.954773 -60.509491 -1.794815 21388 45.544342 -60.410217 -2.140091 21389 45.408188 -61.300507 -2.486542 21390 11.100403 -62.686066 -2.720024 21391 28.549934 -62.131210 -2.864700 21392 44.514893 -61.482697 -1.595978 21393 45.437317 -62.071396 -2.896591 21394 22.383591 -64.437744 -1.874222 21395 44.368286 -62.252930 -2.149071 21396 10.590546 -64.136887 -2.699455 21397 10.471939 -65.975235 -2.332687 21398 18.373177 -66.259827 -2.830582 21399 19.406967 -65.327271 -3.238869 21400 44.797424 -64.893143 -1.854965 21401 44.364136 -63.857391 -1.811371 21402 12.698532 -66.095322 -3.044678 21403 16.713097 -66.721725 -3.393723 21404 17.356140 -67.400650 -2.640106 21405 26.980011 -63.546616 -1.514793 21406 27.604492 -65.042892 -2.111214 21407 28.140335 -65.281677 -3.399651 21408 27.713440 -66.133133 -2.740662 21409 44.950500 -65.763794 -2.818970 21410 13.562630 -66.938477 -2.614273 21411 14.637764 -66.708908 -3.450363 21412 15.668602 -67.037094 -3.073883 21413 38.383736 -67.021561 -2.681969 21414 37.594498 -67.332581 -1.555985 21415 38.138214 -66.460464 -1.243546 21416 37.859207 -67.974426 -2.651260 21417 39.649696 -67.126221 -3.136566 21418 45.552002 -65.789398 -1.775833 21419 19.063187 -68.315063 -3.481888 21420 20.738983 -67.678558 -2.384361 21421 19.141251 -67.374771 -2.615364 21422 40.166199 -67.324036 -2.076088 21423 40.817108 -68.147400 -2.049149 21424 50.446152 -67.956299 -2.539337 21425 49.568695 -68.715881 -2.298622 21426 50.305817 -68.931442 -2.482224 21427 50.281860 -66.349609 -1.997787 21428 49.383377 -65.973129 -1.808891 21429 49.162842 -67.352875 -2.195923 21430 10.845154 -68.742233 -3.134644 21431 19.288483 -66.366623 -2.252365 21432 27.430618 -70.172394 -3.070969 21433 26.996307 -69.097626 -2.068161 21434 51.450562 -68.251953 -2.461830 21435 50.968338 -69.111816 -2.343758 21436 52.396820 -68.073303 -2.007790 21437 51.541367 -66.924286 -2.109650 21438 51.886078 -69.268021 -1.981491 21439 51.329956 -70.197174 -1.347542 21440 10.070961 -70.884155 -3.741806 21441 16.557571 -69.402908 -3.210907 21442 15.585014 -68.726807 -2.695686 21443 14.561798 -69.781830 -4.000557 21444 20.276291 -66.301300 -1.909927 21445 46.310760 -69.600281 -2.793686 21446 50.167587 -69.740463 -1.580948 21447 21.617096 -70.120850 -2.677536 21448 27.606873 -71.012329 -3.583328 21449 42.044724 -69.741196 -3.197968 21450 45.957428 -68.301346 -2.865997 21451 10.965195 -71.773544 -3.922958 21452 27.735153 -71.150513 -2.977379 21453 44.718338 -71.257187 -2.609703 21454 45.465271 -71.571182 -3.557121 21455 45.546997 -70.990204 -2.440346 21456 46.051819 -70.507385 -2.413269 21457 11.941209 -71.958038 -2.991943 21458 20.727577 -72.134735 -3.449890 21459 21.187576 -72.732254 -3.136719 21460 22.014252 -73.272293 -2.881958 21461 28.677567 -73.987122 -3.616104 21462 41.104065 -74.284454 -2.214134 21463 15.632774 -75.579697 -3.877594 21464 22.420433 -74.421005 -3.641480 21465 28.529587 -75.588638 -3.617554 21466 22.629059 -75.673279 -3.900955 21467 23.371185 -74.854156 -2.933502 21468 43.420700 -74.960953 -2.541779 21469 44.435028 -74.981461 -2.833290 21470 45.552734 -75.000870 -3.085465 21471 46.521973 -75.138351 -3.221420 21472 47.432434 -75.073761 -2.505180 21473 12.021912 -77.760010 -3.544502 21474 22.153778 -77.380875 -2.153542 21475 22.308380 -76.665939 -3.330505 21476 20.770859 -77.731857 -3.243095 21477 23.162033 -75.859314 -3.136841 21478 48.147415 -76.001144 -2.684311 21479 48.203827 -77.003571 -2.725517 21480 14.605942 -77.685654 -3.391525 21481 13.241241 -77.828690 -3.428253 21482 14.813690 -77.647354 -4.155525 21483 23.356705 -76.275803 -2.725479 21484 47.891586 -77.873322 -3.330902 21485 48.282318 -76.457336 -1.379524 21486 47.491516 -77.780411 -2.104996 21487 47.587860 -77.139328 -0.734177 21488 19.288681 -79.009460 -2.875931 21489 25.103897 -80.072113 -3.747711 21490 25.655930 -79.846466 -4.352341 21491 27.825729 -77.609955 -3.186111 21492 28.174004 -77.021500 -3.636978 21493 27.377289 -77.041122 -2.800545 21494 9.441223 -79.755997 -4.603424 21495 26.012108 -81.162231 -4.315163 21496 11.220093 -81.848083 -3.731522 21497 12.213287 -81.471436 -4.574455 21498 13.190552 -81.830551 -4.666290 21499 20.271568 -81.718399 -3.905960 21500 27.233505 -81.763168 -4.656097 21501 36.756134 -80.688858 -3.597519 21502 38.138382 -80.618820 -3.978607 21503 39.250618 -79.989014 -3.510521 21504 40.444977 -80.722946 -3.797768 21505 41.189011 -81.554504 -4.106682 21506 44.825134 -81.090820 -3.552017 21507 7.401566 -83.472733 -4.506752 21508 27.487137 -83.483337 -4.444496 21509 26.966721 -82.223541 -4.273544 21510 27.487495 -84.819275 -4.221870 21511 27.848969 -85.760345 -4.071396 21512 28.332436 -85.535873 -4.619659 21513 41.214432 -80.937943 -3.666840 21514 42.036041 -81.416107 -3.954872 21515 43.157990 -81.521637 -3.915253 21516 6.199707 -84.289017 -4.749664 21517 6.516113 -83.253616 -4.335075 21518 8.148438 -83.721970 -4.426086 21519 23.614586 -82.468201 -4.241829 21520 25.639755 -82.532288 -4.089890 21521 26.008514 -83.981049 -4.296120 21522 35.502686 -82.588531 -3.314652 21523 6.371178 -85.628571 -4.939598 21524 9.222351 -83.646286 -4.065056 21525 37.277809 -84.943253 -3.610313 21526 16.011467 -85.057129 -3.590149 21527 16.981888 -85.353500 -3.576691 21528 36.015625 -84.008881 -3.268501 21529 36.005829 -85.418015 -2.599007 21530 38.073723 -87.046371 -2.382355 21531 39.473152 -86.939240 -3.228821 21532 39.480759 -87.503738 -2.673492 21533 12.895164 -85.667908 -4.222153 21534 11.855782 -84.805664 -4.083664 21535 11.165100 -84.673996 -4.660431 21536 13.772247 -86.467133 -4.645103 21537 18.462082 -87.173859 -4.895027 21538 23.337036 -86.786606 -4.900009 21539 7.284775 -87.479691 -4.815597 21540 18.553345 -87.624802 -4.128433 21541 30.085297 -87.568527 -4.472145 21542 31.373528 -88.019455 -4.849968 21543 9.452431 -89.378006 -3.551529 21544 8.576416 -89.123718 -2.266373 21545 9.080734 -89.763489 -2.310249 21546 15.791039 -88.788437 -4.868393 21547 23.782333 -87.376297 -4.572487 21548 24.897461 -87.625000 -4.243500 21549 33.557663 -88.974014 -5.182968 21550 33.057236 -89.404907 -4.790161 21551 31.937143 -89.117264 -4.269409 21552 30.902504 -88.314392 -4.010307 21553 31.004486 -88.893295 -3.694504 21554 33.758049 -89.766068 -5.213760 21555 11.214584 -89.793884 -3.016907 21556 16.202728 -89.866745 -5.171753 21557 27.843430 -89.429626 -4.678429 21558 41.200790 -89.092102 -4.639397 21559 12.883675 -89.959381 -2.837234 21560 13.925247 -90.538895 -2.748520 21561 13.127640 -91.439514 -3.893860 21562 17.976608 -91.049301 -4.328445 21563 18.806320 -90.477539 -4.269623 21564 17.964661 -89.856934 -3.832100 21565 19.460732 -90.510956 -5.081802 21566 28.843575 -90.431641 -5.136009 21567 29.222229 -89.800735 -4.264267 21568 33.225563 -90.173141 -4.945473 21569 30.433792 -89.482559 -3.877777 21570 32.762932 -90.560013 -5.025467 21571 12.041054 -90.251190 -4.041351 21572 19.247986 -92.452438 -5.370201 21573 12.918472 -94.633942 -5.158707 21574 18.170074 -92.628113 -5.503563 21575 24.452454 -92.850037 -3.340317 21576 25.298553 -93.364105 -3.887993 21577 27.105087 -95.355255 -5.057373 21578 26.075813 -94.138138 -4.636475 21579 38.522385 -93.131897 -4.759499 21580 37.319794 -93.868179 -4.347443 21581 36.109116 -94.560349 -3.707901 21582 36.606354 -93.944092 -2.155548 21583 37.661049 -93.099716 -2.606911 21584 23.452301 -95.174622 -3.854858 21585 34.513687 -95.459885 -4.846786 21586 35.133789 -95.119751 -4.801041 21587 27.037842 -94.978134 -4.005989 21588 28.578506 -97.197556 -3.238930 21589 27.597168 -95.356812 -2.878174 21590 32.855125 -96.934326 -4.330704 21591 33.818924 -95.943558 -4.888473 21592 33.423172 -96.923172 -2.830589 21593 33.862823 -96.198685 -3.798325 21594 14.229935 -96.134781 -4.698135 21595 16.493233 -96.464172 -4.334122 21596 17.518204 -96.226074 -3.697983 21597 17.894989 -97.255325 -4.283142 21598 28.737442 -98.423920 -4.998047 21599 18.503349 -98.245926 -4.474953 21600 18.050301 -99.234207 -4.986221 21601 30.935852 -98.280045 -5.038826 21602 17.426590 -101.107941 -5.604210 21603 17.251099 -100.905228 -6.304687 21604 24.428177 -100.685547 -5.009094 21605 19.439552 -102.539703 -4.899506 21606 17.841896 -102.722672 -3.842041 21607 18.577927 -102.995575 -3.721283 21608 23.531342 -101.843597 -4.532791 21609 17.573761 -102.269226 -4.494980 21610 7.950218 63.350143 6.538574 21611 7.551643 62.430511 5.400719 21612 5.373596 62.180618 6.489799 21613 7.789337 63.835663 7.519004 21614 8.724823 64.258698 7.609451 21615 8.766846 62.205322 5.434372 21616 9.825325 61.539932 5.344208 21617 10.560043 60.618332 5.173912 21618 9.891434 62.530487 5.901701 21619 10.910583 62.001724 5.892654 21620 11.496048 59.516403 5.007706 21621 11.849899 60.879898 5.725013 21622 12.771523 59.852951 5.642334 21623 12.439697 58.803619 5.069504 21624 27.612717 58.439774 5.752212 21625 26.716125 58.747498 6.028305 21626 26.890213 58.156998 5.043167 21627 27.514023 58.760849 7.025604 21628 13.432861 58.667801 5.435379 21629 24.154762 59.305084 6.851364 21630 28.369209 56.591156 6.595253 21631 7.409256 55.594528 5.354820 21632 15.049835 56.931335 5.494392 21633 9.976593 53.435226 4.779755 21634 17.219032 54.960052 4.929154 21635 18.459839 55.031647 5.370689 21636 20.557678 55.716309 6.007232 21637 21.678864 55.487411 5.704254 21638 33.567200 54.892059 6.647285 21639 36.970261 53.851471 5.027039 21640 37.317734 52.894440 5.663162 21641 36.435966 53.601761 5.945907 21642 35.507561 53.940933 6.626251 21643 10.840179 54.224533 6.073043 21644 11.283081 53.639145 5.994850 21645 30.743378 52.233994 6.350937 21646 30.442650 53.137787 7.488021 21647 29.121872 51.396179 7.703598 21648 11.962486 50.851532 4.850891 21649 11.853157 51.680801 5.225479 21650 30.298233 50.586151 5.494125 21651 38.253502 50.308090 5.033875 21652 12.413925 50.106903 4.769661 21653 12.480302 49.399597 4.333504 21654 12.705826 49.668182 4.974716 21655 24.799805 50.612534 5.204529 21656 36.371452 49.419891 5.553604 21657 37.066513 50.436462 5.596428 21658 37.391266 49.235504 5.030640 21659 24.259171 50.507095 5.580750 21660 28.681000 49.094055 6.224395 21661 29.546860 48.707458 4.978409 21662 12.185738 47.505035 5.245041 21663 12.607269 48.644714 5.450668 21664 12.001656 48.787872 6.055992 21665 34.805832 47.968399 6.028572 21666 21.838554 45.158844 6.759933 21667 22.171906 45.260132 5.980560 21668 22.749939 44.389542 6.078056 21669 27.966858 44.751175 4.639267 21670 34.153328 46.767639 6.034988 21671 4.439186 45.005524 4.629440 21672 6.505447 45.679703 5.116112 21673 5.173813 45.818558 5.797348 21674 8.963898 45.762787 4.794449 21675 7.893096 45.828995 5.055237 21676 22.546051 47.401382 6.025428 21677 22.937592 47.188019 5.288025 21678 4.121964 45.164215 5.885368 21679 11.205383 46.694443 5.541672 21680 21.969955 46.112183 6.278709 21681 27.639511 48.733170 6.889999 21682 27.009300 47.958420 7.068740 21683 24.466049 43.140961 4.660545 21684 23.901733 43.673859 4.850922 21685 25.947739 43.265778 4.586639 21686 33.689499 45.497070 6.188262 21687 33.772293 43.626846 5.857971 21688 24.918762 43.155792 4.792008 21689 4.547394 42.106918 5.196869 21690 3.915573 42.795319 5.932266 21691 4.555206 42.593185 6.547783 21692 43.105820 38.489380 4.827698 21693 7.521805 41.296127 5.152580 21694 8.028984 40.419403 4.257576 21695 11.219078 39.322998 4.240540 21696 11.368858 40.265869 5.147049 21697 12.259262 39.043579 4.525932 21698 41.986542 38.525513 4.821732 21699 41.157806 38.236786 4.932449 21700 13.144852 37.914795 4.588501 21701 47.307739 38.655243 5.305954 21702 48.553162 38.416901 6.499664 21703 47.660950 38.006104 6.445785 21704 50.332550 38.393784 5.710899 21705 50.483658 38.257782 6.720336 21706 49.581177 38.603149 6.448226 21707 50.209641 38.562332 4.689118 21708 13.417404 39.085999 5.209122 21709 12.707535 36.782227 4.246018 21710 51.403320 37.364029 6.091018 21711 13.182129 36.891968 5.200470 21712 51.179230 37.665588 7.521163 21713 3.446098 35.043579 4.109131 21714 3.992333 35.938370 4.563255 21715 3.465233 35.623627 5.063278 21716 3.852982 35.091721 3.712936 21717 11.377563 35.015717 3.624252 21718 49.792725 31.846954 4.632004 21719 50.418884 31.022827 3.786377 21720 46.167679 30.552185 4.838173 21721 2.429062 28.189713 3.519714 21722 43.048065 28.606689 4.362930 21723 43.455933 29.116669 4.248276 21724 42.708786 27.830566 4.993546 21725 31.302795 25.420685 4.562225 21726 33.013535 25.783646 3.651711 21727 33.837448 25.827499 4.187615 21728 34.401962 25.723846 3.783341 21729 1.991547 24.345364 3.028086 21730 45.269623 23.787094 3.928070 21731 44.367798 25.159744 4.216667 21732 40.305878 22.368942 3.618546 21733 40.619781 22.233337 3.796646 21734 29.778687 23.058105 3.357788 21735 35.693329 25.097778 4.685524 21736 36.486588 24.417618 5.548760 21737 46.186981 23.277237 3.488907 21738 29.936493 22.541214 3.401436 21739 31.247452 21.770828 4.314736 21740 32.420914 21.302551 4.911804 21741 38.323624 23.705658 4.368553 21742 46.101654 22.391891 3.710251 21743 41.176270 22.390350 4.453652 21744 47.049133 20.858749 3.083969 21745 30.454926 22.429337 4.315170 21746 43.322662 21.551544 3.872933 21747 44.446915 21.180099 3.564682 21748 44.265823 22.395508 4.409210 21749 45.539688 21.445572 3.756035 21750 45.610199 20.790756 3.248459 21751 2.435140 18.413345 2.784134 21752 2.487848 17.251877 2.602888 21753 37.516670 17.621719 4.369820 21754 37.998978 16.460510 3.841339 21755 2.845497 13.028188 2.138026 21756 2.503001 10.681702 4.981063 21757 2.715164 11.545787 3.380166 21758 2.518295 11.890780 4.482571 21759 2.641945 13.209975 3.182411 21760 36.162888 11.973969 3.334564 21761 35.776451 14.480057 5.107269 21762 37.173630 10.242340 3.554039 21763 36.176865 10.745239 3.648750 21764 2.417804 8.095411 5.845430 21765 41.584503 9.173981 3.425980 21766 41.247162 9.529602 3.514496 21767 42.089828 8.585892 2.800812 21768 43.009354 8.370819 2.193070 21769 42.760468 7.588593 2.519875 21770 43.524353 7.505508 2.199539 21771 42.190552 7.555069 3.008133 21772 42.152664 6.542374 3.073685 21773 41.799683 7.324799 3.448074 21774 42.637421 6.835602 2.688759 21775 41.588135 6.609772 3.462708 21776 43.222015 6.689209 2.404656 21777 42.697479 6.091064 2.691628 21778 43.427567 5.812988 2.654030 21779 42.658966 5.433563 3.188881 21780 42.255768 5.860428 3.003906 21781 43.612488 4.993118 3.533829 21782 45.155365 3.363953 2.910545 21783 2.417038 6.643431 4.415726 21784 2.268076 5.506171 3.719000 21785 2.182267 4.876166 3.987625 21786 2.277219 5.686005 4.727598 21787 58.611679 2.240952 2.823425 21788 54.352768 -2.028564 5.277939 21789 52.181961 -3.337021 3.739655 21790 52.256592 -2.045837 3.062256 21791 58.837967 1.233200 3.531166 21792 58.131958 2.040665 3.372330 21793 2.157017 4.224420 4.052538 21794 2.580375 2.110162 4.473943 21795 2.733512 1.799081 3.544922 21796 2.470737 2.657092 4.257834 21797 3.119862 0.855333 2.948854 21798 2.438606 2.737447 3.779129 21799 2.265064 3.647297 4.466066 21800 2.818490 0.603897 4.780188 21801 40.818192 -0.957443 1.949082 21802 52.190308 -1.074509 2.309937 21803 58.965485 -0.456406 3.506744 21804 3.276997 -0.865702 3.539996 21805 5.484319 -0.474458 -1.881956 21806 58.015564 -1.980438 3.583359 21807 59.269516 -1.588104 4.506928 21808 59.245224 -0.732391 4.274025 21809 3.538625 -1.685984 2.905352 21810 38.449951 -2.972382 1.728180 21811 38.133743 -3.141129 1.990921 21812 38.311432 -2.922623 2.108322 21813 55.081055 -4.156464 2.212799 21814 56.093597 -3.716080 2.559296 21815 54.631363 -3.913635 1.725128 21816 56.878479 -2.735291 3.005081 21817 3.235102 -1.561435 3.997592 21818 3.747288 -2.728531 2.584960 21819 3.728289 -3.568070 2.865839 21820 38.388596 -3.406906 1.905411 21821 39.833992 -4.809479 2.200607 21822 38.751953 -3.872589 2.189118 21823 39.006470 -4.602493 2.917076 21824 40.813477 -5.114609 2.044357 21825 41.138031 -4.124832 1.245766 21826 4.097517 -5.402097 1.816948 21827 3.915896 -4.474629 2.384279 21828 39.648010 -5.709747 3.043785 21829 51.285873 -4.516754 3.165161 21830 50.925537 -5.918365 3.357544 21831 57.680542 -4.640564 2.314835 21832 59.229645 -4.777618 2.409393 21833 58.347870 -3.815125 3.518372 21834 59.366348 -4.297562 3.321884 21835 3.895441 -5.474520 2.515587 21836 50.490234 -7.247009 3.158386 21837 56.548126 -5.212112 1.940468 21838 56.573181 -4.564850 2.519547 21839 3.823690 -6.114636 2.936067 21840 3.982515 -6.389182 2.367010 21841 59.011795 -7.252396 2.639649 21842 58.111176 -8.283524 2.530304 21843 4.104566 -6.072598 1.851344 21844 44.166733 -7.575836 2.292236 21845 44.286377 -8.067581 1.746910 21846 44.457153 -8.105316 2.083222 21847 4.035975 -7.327431 2.535757 21848 44.155640 -8.845520 1.880203 21849 50.207870 -8.245621 3.889618 21850 4.147373 -8.384375 2.540244 21851 4.087432 -9.134958 3.197725 21852 4.184073 -10.252712 3.434154 21853 44.519501 -9.112366 2.862488 21854 44.499619 -8.207764 2.708618 21855 57.006027 -9.099670 2.824875 21856 58.840866 -10.187592 2.305359 21857 57.891327 -10.325653 2.154007 21858 49.239014 -10.418457 2.365982 21859 48.673248 -11.357697 2.043587 21860 57.048035 -10.344391 2.541535 21861 62.356384 -10.815964 1.988312 21862 60.841522 -10.328140 2.568832 21863 62.221756 -10.698730 3.361878 21864 63.265686 -11.698730 3.121506 21865 63.089401 -11.168182 4.001488 21866 35.244583 -12.184433 1.005982 21867 35.538254 -11.792862 0.927002 21868 36.118210 -11.836777 0.862305 21869 36.240936 -12.780960 0.840164 21870 35.546814 -12.662598 1.173523 21871 35.572784 -12.851456 0.849167 21872 43.094513 -11.480225 2.040001 21873 43.934326 -10.248749 2.447044 21874 42.864868 -12.301071 3.109398 21875 57.937943 -10.736267 2.620483 21876 35.291931 -12.554886 1.095459 21877 37.341759 -13.753906 0.758606 21878 40.237320 -12.862747 0.912407 21879 38.048050 -14.748535 1.195572 21880 47.242996 -12.468079 1.399330 21881 46.719177 -13.203949 1.456497 21882 46.241425 -12.657455 0.833649 21883 63.435730 -12.579025 2.186051 21884 63.158997 -11.674835 2.120834 21885 4.958204 -12.961411 1.793332 21886 4.804670 -13.237728 2.816235 21887 39.171532 -14.972885 1.797241 21888 40.085556 -13.980850 1.512184 21889 40.971588 -13.608566 1.755234 21890 41.838730 -13.166718 2.398193 21891 45.720322 -13.672348 0.987686 21892 63.552124 -13.484375 2.180298 21893 5.205372 -13.855562 1.512902 21894 5.039476 -14.218541 2.710063 21895 37.382782 -14.948563 0.950302 21896 40.776428 -14.384735 2.391022 21897 41.319458 -14.057419 3.290161 21898 45.553375 -14.671707 1.553932 21899 46.538803 -13.881210 1.800583 21900 63.466141 -14.435043 2.070480 21901 37.243073 -15.582657 0.910523 21902 40.198730 -14.866760 2.372025 21903 38.855934 -16.289047 2.896286 21904 39.720535 -15.552612 2.901733 21905 58.759506 -14.842148 2.700379 21906 58.520676 -14.800476 3.550598 21907 59.820511 -15.058884 3.524185 21908 63.128387 -15.428619 1.433319 21909 63.374481 -15.298950 2.255524 21910 45.313049 -15.666550 2.401657 21911 60.664764 -15.819519 1.779709 21912 62.388672 -15.938889 1.803375 21913 63.092148 -15.652542 1.993507 21914 37.550064 -17.210754 1.167496 21915 5.862129 -16.910587 2.106498 21916 6.025686 -17.634396 2.499756 21917 6.209237 -17.876488 1.860017 21918 6.315846 -17.959066 1.371150 21919 6.326552 -18.536516 2.556264 21920 6.308662 -18.248920 1.886814 21921 53.651901 -17.491272 2.329788 21922 6.616777 -18.264620 0.610995 21923 6.599485 -18.643101 1.185346 21924 6.774247 -18.712063 0.616936 21925 6.437610 -18.118362 1.061056 21926 6.435355 -18.495457 1.692723 21927 39.975082 -20.214584 1.266037 21928 41.825302 -18.772659 1.261612 21929 51.625549 -19.592712 1.547814 21930 40.974350 -19.643265 1.261124 21931 51.898941 -20.405685 1.207169 21932 50.504028 -21.316055 2.084381 21933 51.275894 -20.393982 2.431656 21934 51.337677 -21.509155 1.457855 21935 52.673538 -21.381042 1.091431 21936 52.079742 -22.412704 1.394882 21937 51.237701 -22.702972 1.449234 21938 51.186462 -22.333405 1.372833 21939 53.844070 -21.327850 0.984665 21940 55.713348 -22.137939 1.315392 21941 56.983490 -21.870621 1.021683 21942 58.375763 -21.978592 0.721787 21943 53.358810 -22.417084 1.451752 21944 54.510132 -22.363190 1.445938 21945 55.294861 -23.557007 1.991707 21946 59.238068 -22.315781 0.234360 21947 8.393528 -21.810297 0.796322 21948 7.241426 -19.760530 0.776733 21949 50.163818 -22.886566 2.005966 21950 57.547302 -23.444305 1.224037 21951 11.476319 -25.241203 0.971393 21952 10.875580 -24.728336 0.955155 21953 11.805398 -25.346741 0.495712 21954 12.275404 -25.902994 1.096454 21955 57.187088 -25.119247 1.420380 21956 8.866792 -22.209917 -0.005180 21957 9.186545 -22.669657 0.182052 21958 10.262057 -23.777744 -0.133700 21959 13.941389 -26.952906 0.514596 21960 53.694031 -26.241333 -0.108673 21961 56.709808 -26.203720 1.204437 21962 56.963593 -26.248230 2.007431 21963 10.199468 -24.261465 1.573065 21964 13.191291 -26.503670 0.750537 21965 51.870636 -27.509918 -0.233421 21966 52.634003 -28.067154 0.134003 21967 54.483002 -26.901413 0.345429 21968 53.442413 -27.531769 0.420700 21969 55.190796 -26.913712 0.510147 21970 55.893829 -27.002365 0.966728 21971 53.194138 -28.247452 0.492722 21972 54.702240 -28.257843 0.940949 21973 52.688843 -28.925888 -0.066376 21974 53.539261 -29.124924 0.340698 21975 15.273540 -28.784910 1.821930 21976 14.226859 -28.134884 2.154032 21977 14.684324 -28.682505 2.404923 21978 53.620209 -28.280579 0.667786 21979 31.303976 -31.880690 -0.713211 21980 54.494080 -29.788773 0.857285 21981 15.443998 -29.245049 2.320520 21982 14.772945 -29.012764 2.802828 21983 15.220548 -29.380659 2.790042 21984 14.488279 -28.130384 1.775085 21985 15.686964 -29.702221 2.723415 21986 15.783489 -30.169107 3.301682 21987 17.433493 -30.740986 2.331888 21988 31.720366 -32.510712 -0.029274 21989 30.543890 -32.162945 -0.412576 21990 44.494827 -31.652344 0.845123 21991 44.571060 -32.266724 0.297562 21992 43.997620 -33.348572 0.287048 21993 42.582642 -32.854858 1.685158 21994 45.867371 -31.817535 0.491074 21995 48.108948 -31.608017 1.145966 21996 49.582458 -31.688568 1.197296 21997 25.961653 -33.526386 0.765355 21998 27.030388 -33.464310 0.522741 21999 30.781244 -32.739098 0.240172 22000 30.641970 -33.456131 1.103043 22001 49.867157 -32.229233 -0.396576 22002 52.360199 -31.747910 1.276375 22003 53.583511 -31.693146 1.355621 22004 53.996078 -31.978622 0.737129 22005 22.202690 -32.588249 1.335901 22006 21.872608 -33.281006 2.097108 22007 22.888317 -33.526550 1.841418 22008 17.827972 -35.721619 -0.912796 22009 17.821220 -36.073334 0.100350 22010 17.232086 -36.256561 0.299156 22011 19.025253 -36.089966 0.109215 22012 18.831558 -36.576065 1.201935 22013 17.851456 -36.549133 1.277268 22014 23.708298 -37.360825 -0.147552 22015 32.703644 -35.785538 -0.253220 22016 43.661514 -34.603989 0.674652 22017 44.199890 -35.334061 0.760941 22018 62.753143 -36.032990 0.603897 22019 62.765015 -36.383362 1.928940 22020 63.754532 -36.099380 0.149971 22021 11.638824 -37.787430 -1.524323 22022 15.680893 -38.676895 -0.425354 22023 16.115540 -39.558533 -0.445335 22024 22.670563 -37.329071 0.409203 22025 21.749725 -37.018082 0.469429 22026 29.919373 -36.972824 0.449677 22027 32.544876 -36.599518 -0.261185 22028 31.987764 -36.020111 0.328583 22029 33.120644 -36.562103 -0.903000 22030 45.814819 -36.159134 0.798782 22031 44.885223 -35.768799 1.072579 22032 46.195587 -36.596283 0.194397 22033 59.756027 -36.892029 0.443405 22034 60.421585 -36.653564 0.568810 22035 62.105499 -36.910538 3.053497 22036 12.059661 -38.443283 -1.228180 22037 12.400085 -39.137924 -0.836380 22038 11.716225 -39.381317 -0.667892 22039 15.394615 -38.083023 -0.597870 22040 29.099770 -37.429016 0.325554 22041 32.670441 -37.032669 -0.697357 22042 49.291580 -37.709991 0.455986 22043 49.404495 -36.720200 2.117355 22044 47.443634 -36.669312 0.925736 22045 57.175781 -37.784012 0.354477 22046 64.623840 -36.982864 0.601685 22047 64.925949 -37.931717 0.529511 22048 16.856033 -40.313065 -0.355949 22049 16.591110 -40.460968 -0.762787 22050 15.725311 -40.650223 -0.828712 22051 27.165359 -38.541031 -0.093735 22052 27.830948 -38.158615 -0.160324 22053 49.689270 -38.520248 -0.216431 22054 52.365479 -38.828140 0.694260 22055 54.663788 -38.489594 -0.532684 22056 55.479416 -38.442017 0.366570 22057 64.271851 -39.203369 0.349671 22058 63.985672 -39.742538 -0.073418 22059 64.799652 -38.583557 0.181046 22060 13.189369 -39.699738 -0.769081 22061 16.252480 -39.727631 0.617355 22062 50.071747 -38.773453 -0.522171 22063 50.724579 -38.606735 0.289497 22064 51.639191 -38.863556 0.556351 22065 54.928055 -38.757370 0.166176 22066 63.391479 -39.902771 0.441368 22067 10.294334 -40.995819 -0.673058 22068 16.966141 -41.247452 -0.500687 22069 14.274361 -40.491165 -0.707573 22070 10.343124 -42.595078 0.476822 22071 12.106033 -43.283203 -0.871307 22072 14.249527 -41.306381 -0.053688 22073 16.124352 -42.208740 -0.130798 22074 18.247917 -42.356369 -0.065781 22075 18.709579 -42.923798 0.087998 22076 17.562683 -43.138275 0.024963 22077 60.484268 -41.941803 0.105064 22078 61.283890 -41.461502 0.812958 22079 17.397461 -42.145157 -0.288544 22080 63.570114 -44.549530 -0.985413 22081 13.475586 -46.736801 -0.462647 22082 12.510986 -45.853577 0.439865 22083 12.703461 -44.715012 -0.587090 22084 11.022217 -45.018967 1.994370 22085 47.760315 -47.572449 -0.018082 22086 48.739944 -46.923111 0.341980 22087 47.675079 -46.683975 -0.643303 22088 48.471649 -47.808197 0.417915 22089 48.794983 -45.945038 -0.675537 22090 52.563019 -45.482101 -0.249130 22091 51.140137 -45.586792 -0.312469 22092 51.764801 -45.584610 0.787926 22093 53.843018 -45.383987 -0.163048 22094 54.731873 -45.227356 -0.203026 22095 54.587631 -44.896835 0.735123 22096 55.384949 -44.457138 1.125374 22097 62.967300 -46.185638 -1.187065 22098 59.997955 -45.666626 -1.050392 22099 63.628876 -45.180557 -1.023735 22100 16.378983 -50.462357 -1.499550 22101 49.446732 -50.688934 -0.689812 22102 49.268463 -49.827744 -0.284119 22103 48.913971 -50.531372 -0.522736 22104 50.587616 -50.539581 -0.585350 22105 51.805237 -49.973373 -0.027283 22106 50.694107 -49.340332 0.372376 22107 54.832932 -50.593033 -0.314957 22108 18.194901 -51.789734 -0.944260 22109 51.089417 -51.824982 -0.849030 22110 51.419647 -53.301895 -0.463928 22111 53.209259 -53.414673 -1.113937 22112 52.487793 -52.305054 -1.183044 22113 56.250061 -51.088715 -0.182640 22114 56.578705 -51.042053 0.650009 22115 55.732635 -50.384293 0.503647 22116 57.689972 -52.730667 -0.043121 22117 18.813843 -52.545273 -0.581894 22118 19.379944 -53.027649 -0.815247 22119 49.866653 -51.389832 -0.677788 22120 58.479904 -53.591980 -0.422424 22121 19.605301 -53.447113 -1.436562 22122 44.500275 -53.259048 -0.864792 22123 44.564453 -51.917450 -0.383743 22124 49.250092 -52.583878 0.015740 22125 53.656326 -54.468582 -0.728996 22126 52.309402 -54.414276 -0.305725 22127 18.284447 -55.159729 -2.267593 22128 18.829285 -55.508987 -1.723640 22129 44.932709 -54.576797 -1.248894 22130 57.595825 -58.759949 -0.732285 22131 58.402328 -57.842087 -0.592697 22132 57.565933 -57.105408 -1.001755 22133 55.635651 -55.268219 -1.111435 22134 57.924728 -55.607086 -1.148270 22135 59.148499 -55.432816 -0.402237 22136 58.838501 -56.206894 -0.797142 22137 59.096207 -54.359024 -0.334022 22138 16.971916 -57.619339 -2.503555 22139 46.311768 -55.659668 -1.866814 22140 45.508301 -55.987640 -1.347649 22141 54.512466 -55.426666 -0.649185 22142 56.603912 -56.046936 -1.107193 22143 18.148811 -57.739136 -1.587357 22144 44.799164 -56.873077 -0.402405 22145 44.592987 -55.647949 -0.312767 22146 55.585938 -56.207993 -0.789627 22147 58.453033 -56.796234 -0.882866 22148 17.216476 -58.644272 -2.108223 22149 46.075928 -57.347122 -1.444366 22150 46.016464 -58.491302 -1.556381 22151 56.243912 -57.476913 -0.763275 22152 59.111084 -58.117264 1.943649 22153 59.455170 -57.454926 0.980438 22154 58.811356 -58.346680 0.386856 22155 16.356750 -58.656219 -2.765121 22156 17.903000 -58.715363 -1.650345 22157 58.320526 -58.690857 -0.322372 22158 16.404343 -59.737244 -2.189079 22159 17.485764 -59.780396 -1.585075 22160 44.926514 -58.174393 -0.548157 22161 12.685394 -61.453934 -1.505020 22162 15.485474 -60.840652 -1.937424 22163 25.585068 -61.643768 -2.256622 22164 26.840164 -61.504135 -2.060829 22165 27.828659 -61.126266 -2.546516 22166 56.471497 -60.155014 -1.138245 22167 55.548355 -59.746368 -0.832031 22168 55.640686 -60.884369 -1.045036 22169 56.397736 -59.107590 -0.858200 22170 12.072884 -61.372269 -2.146980 22171 11.342377 -61.973846 -2.014023 22172 14.957169 -62.056046 -1.196167 22173 44.627319 -60.298386 -0.862068 22174 57.264618 -59.987442 -1.082840 22175 56.909958 -60.813721 -1.220558 22176 57.538620 -60.816818 -0.889465 22177 57.796570 -59.917618 -0.674820 22178 10.717621 -62.812485 -2.225876 22179 10.342743 -62.824936 -1.250221 22180 27.558395 -62.282837 -2.058273 22181 44.139435 -62.519302 -1.657066 22182 54.284241 -59.846756 -0.568283 22183 53.692749 -61.181900 -0.723068 22184 55.545471 -62.167709 -1.208298 22185 56.826370 -61.839966 -1.063423 22186 43.881775 -62.986588 -1.849770 22187 43.705719 -63.086136 -1.650208 22188 43.837280 -62.925018 -1.557877 22189 55.850769 -63.307556 -1.066208 22190 54.451828 -62.896439 -1.020813 22191 56.483414 -62.768265 -1.150070 22192 57.574738 -61.480148 -0.259209 22193 56.991180 -62.749649 -0.836258 22194 8.597137 -66.149414 -1.011948 22195 10.201912 -67.641876 -2.248116 22196 43.940491 -63.261902 -1.723091 22197 56.741974 -63.354980 -0.494278 22198 20.736397 -65.086899 -2.564835 22199 53.508362 -65.737366 -1.522568 22200 53.710083 -65.078751 -1.493477 22201 52.946274 -64.839218 -1.383835 22202 53.717834 -64.713959 -1.361214 22203 54.274719 -65.102509 -1.146408 22204 11.551773 -68.115356 -2.584900 22205 11.692001 -66.018127 -2.735573 22206 19.536774 -65.761368 -2.378700 22207 27.196564 -65.901688 -1.646759 22208 39.097481 -66.617691 -1.993774 22209 46.558273 -67.263077 -2.097740 22210 46.597885 -68.178253 -2.284508 22211 47.557693 -67.253708 -1.993721 22212 48.218201 -64.060104 -0.662842 22213 47.582428 -65.533035 -1.303337 22214 48.878113 -65.092804 -1.289230 22215 50.072449 -64.784775 -1.271088 22216 48.499191 -66.238174 -1.809464 22217 51.248688 -65.343201 -1.553391 22218 52.343307 -65.779053 -1.700638 22219 51.995926 -64.895401 -1.380753 22220 52.939987 -66.849899 -1.709274 22221 54.113052 -66.634567 -0.702553 22222 55.320679 -65.190735 -0.031372 22223 14.851364 -67.515808 -2.671097 22224 16.426620 -67.269867 -2.781212 22225 15.896431 -67.678482 -2.562630 22226 16.554810 -67.624664 -2.531960 22227 27.154953 -66.811737 -1.859932 22228 38.727448 -66.073196 -0.730446 22229 38.876396 -66.251862 -1.346420 22230 39.719498 -66.613281 -0.956802 22231 45.767975 -67.039047 -2.521317 22232 52.678192 -69.080811 -1.397003 22233 17.638504 -68.524933 -3.026581 22234 46.522888 -66.419220 -1.736511 22235 48.369644 -68.439011 -2.035095 22236 53.285400 -67.883224 -1.306374 22237 9.778999 -69.411896 -2.773445 22238 8.946198 -68.134766 -1.554359 22239 14.674026 -69.283890 -3.175209 22240 41.596893 -69.128983 -1.827148 22241 47.421021 -68.476196 -1.943481 22242 46.876465 -69.337250 -1.711823 22243 47.785980 -69.056976 -1.413933 22244 48.862091 -69.264648 -1.589073 22245 53.321106 -68.695206 -0.535217 22246 9.903809 -70.562439 -2.665894 22247 16.583633 -68.793594 -2.662872 22248 26.973206 -70.276245 -1.902885 22249 21.788696 -71.118347 -2.028366 22250 22.162453 -69.725632 -1.866394 22251 27.322906 -71.355911 -2.100403 22252 42.766068 -70.431488 -2.214005 22253 46.330261 -70.078049 -1.908096 22254 49.257339 -69.775604 -0.771149 22255 48.351547 -69.393723 -0.585465 22256 52.166565 -70.011169 -1.099976 22257 10.358902 -71.193878 -2.963547 22258 11.010757 -71.382477 -2.553917 22259 13.063858 -72.221848 -2.203339 22260 11.603539 -71.033020 -1.395081 22261 21.181992 -71.350159 -3.070343 22262 27.845528 -72.547577 -2.774292 22263 38.203522 -70.816452 -1.179779 22264 39.242096 -72.173157 -0.560570 22265 43.830902 -70.413132 -1.194519 22266 42.617096 -69.577774 -0.651665 22267 45.082367 -70.455902 -1.093925 22268 5.782105 -73.168396 -2.020905 22269 5.265389 -74.260483 -2.682671 22270 5.929024 -74.154007 -3.034493 22271 6.598190 -73.709015 -2.983032 22272 7.341019 -73.822906 -3.117157 22273 7.234108 -73.234497 -2.404068 22274 14.975586 -74.386261 -2.740364 22275 14.880219 -74.126694 -1.961182 22276 15.223960 -74.993790 -2.170860 22277 21.162186 -71.930328 -2.562454 22278 27.714661 -74.342499 -2.572182 22279 26.934235 -73.217712 -1.917130 22280 39.414436 -72.898193 -1.871773 22281 6.938164 -74.881638 -3.159119 22282 7.835449 -74.238174 -3.090988 22283 7.872192 -73.735825 -2.827286 22284 8.264023 -74.119492 -2.707153 22285 14.370972 -73.452698 -2.318741 22286 23.241287 -73.252701 -2.057930 22287 22.429108 -71.988022 -1.748505 22288 5.625282 -74.899490 -3.085953 22289 4.904472 -75.075256 -2.382080 22290 4.757301 -76.292801 -2.019302 22291 5.665512 -75.873566 -3.024910 22292 8.179962 -74.737000 -2.735413 22293 15.381546 -74.896225 -3.104340 22294 15.649155 -75.557617 -2.884888 22295 27.499832 -75.884064 -2.753891 22296 42.864105 -74.500061 -1.188072 22297 42.799118 -74.211746 -0.514130 22298 42.031250 -74.358704 -1.318741 22299 45.056839 -74.465515 -1.817001 22300 46.236877 -74.414505 -1.528183 22301 47.439392 -74.586426 -1.231277 22302 48.187744 -75.262909 -1.454285 22303 8.410973 -76.339661 -2.014633 22304 7.548081 -76.889603 -2.449860 22305 8.396484 -76.932877 -1.798286 22306 15.434151 -76.753937 -2.907150 22307 24.056580 -75.680222 -2.574089 22308 6.734093 -76.483658 -3.035355 22309 15.493866 -75.976852 -2.233238 22310 5.590126 -77.214417 -3.017006 22311 6.582153 -77.775497 -3.056290 22312 5.661293 -78.729568 -3.215042 22313 8.556503 -79.022888 -3.033859 22314 11.097374 -77.730652 -2.840057 22315 10.377274 -77.870010 -3.237534 22316 15.265961 -76.625839 -1.961945 22317 14.769867 -77.219345 -2.015160 22318 27.493927 -77.633224 -2.862061 22319 6.730888 -78.900925 -3.137047 22320 10.067307 -77.709564 -2.295128 22321 9.011536 -78.186417 -2.378227 22322 8.258461 -80.151367 -3.256485 22323 9.145081 -80.008041 -3.809784 22324 13.815636 -77.583191 -2.290154 22325 14.740074 -77.560013 -2.604019 22326 36.264053 -78.726898 -2.196655 22327 37.115669 -79.358429 -3.004616 22328 35.882751 -79.718338 -2.738220 22329 39.101997 -78.671967 -2.690842 22330 38.206146 -79.022995 -2.918037 22331 38.305161 -77.952332 -1.814362 22332 40.113007 -79.086960 -2.909317 22333 39.737762 -77.945358 -1.807510 22334 41.373550 -79.765076 -3.133255 22335 41.054718 -78.325302 -2.183182 22336 42.407532 -78.895370 -2.336723 22337 45.964127 -79.135651 -2.574615 22338 5.461128 -81.509277 -3.415611 22339 4.784149 -81.446869 -2.466629 22340 5.125420 -82.492920 -2.688042 22341 6.280396 -79.715286 -3.523834 22342 5.486366 -80.011826 -3.331223 22343 7.135620 -79.914047 -3.276672 22344 24.013496 -76.989838 -1.989151 22345 23.170998 -77.177338 -1.944015 22346 23.190262 -77.976379 -1.818741 22347 35.405373 -80.854111 -2.997665 22348 36.113716 -81.568619 -3.564049 22349 42.822571 -80.277847 -3.178795 22350 43.475845 -78.314697 -1.601624 22351 44.024246 -79.528824 -2.539955 22352 44.061020 -81.046585 -3.512947 22353 4.978180 -81.949753 -1.573853 22354 5.403313 -83.345917 -1.843353 22355 6.416992 -80.768799 -3.613022 22356 7.689483 -79.385376 -2.896591 22357 7.742645 -81.470779 -3.401665 22358 24.266357 -79.875626 -3.073837 22359 24.704071 -81.013718 -3.501724 22360 24.549438 -81.765152 -3.515732 22361 25.218842 -81.613739 -3.630608 22362 34.778625 -80.152496 -1.930405 22363 35.444305 -79.122330 -1.864975 22364 34.822205 -81.662643 -2.868576 22365 34.359924 -81.102554 -2.401718 22366 44.875320 -80.405426 -3.155945 22367 4.709305 -80.270447 -2.350922 22368 6.518112 -82.050797 -3.844872 22369 5.908455 -82.730194 -3.896713 22370 8.896484 -82.598877 -3.291306 22371 9.463074 -81.366943 -3.537369 22372 10.157181 -82.765350 -3.353912 22373 11.267831 -83.032806 -3.209808 22374 12.304871 -82.860321 -3.141754 22375 12.738037 -82.056534 -3.815537 22376 19.577087 -79.749115 -2.028687 22377 19.046066 -80.035339 -2.584526 22378 19.890884 -80.827316 -2.548691 22379 20.035194 -79.960358 -1.696060 22380 18.733780 -80.708633 -3.408836 22381 24.854530 -81.491989 -3.397797 22382 34.826981 -83.986481 -2.569107 22383 33.894547 -82.353409 -2.162506 22384 35.463470 -81.645447 -3.245544 22385 7.349579 -82.741791 -3.804382 22386 20.824951 -81.842896 -3.558876 22387 5.980026 -83.970505 -3.788757 22388 15.196945 -85.672333 -3.364159 22389 15.847992 -85.656357 -3.184021 22390 33.662216 -83.722672 -2.084229 22391 6.359879 -85.465439 -3.988480 22392 10.785339 -83.951111 -3.893662 22393 12.139053 -83.992050 -3.308945 22394 14.572983 -84.722321 -3.400986 22395 13.949249 -85.578445 -3.563042 22396 16.342041 -85.604858 -3.118492 22397 17.528488 -85.681686 -3.261230 22398 12.577744 -84.921021 -3.564713 22399 26.409851 -85.002136 -3.898376 22400 27.086182 -85.548462 -3.795151 22401 6.828911 -86.620972 -4.338745 22402 24.106110 -86.846497 -4.252716 22403 27.335907 -86.425201 -3.708153 22404 26.254845 -85.822006 -3.645584 22405 38.803062 -85.983719 -3.599632 22406 7.263199 -87.430389 -4.022949 22407 14.874962 -86.680771 -3.969681 22408 15.791466 -87.785187 -4.034729 22409 27.954262 -87.548752 -3.719353 22410 29.133842 -87.761566 -3.941338 22411 30.078239 -88.439056 -3.763992 22412 7.403786 -87.559265 -3.096451 22413 16.129379 -86.458450 -3.222885 22414 16.963730 -87.834518 -3.285736 22415 18.529251 -88.679504 -4.079140 22416 25.306305 -86.050262 -3.799561 22417 24.852997 -86.705460 -3.899353 22418 26.256607 -87.189362 -3.735374 22419 28.876419 -88.768799 -3.816299 22420 40.546082 -88.188797 -3.619370 22421 9.515991 -89.856384 -2.838348 22422 12.567688 -89.767136 -1.454094 22423 16.825752 -89.442062 -4.179199 22424 18.801376 -91.257645 -4.346573 22425 27.395432 -88.361038 -3.937180 22426 31.386276 -89.452042 -3.882980 22427 40.215027 -89.241852 -2.626228 22428 39.995705 -88.220535 -2.535278 22429 13.484879 -93.446579 -4.250977 22430 18.782150 -91.817871 -4.696594 22431 32.617432 -90.000366 -4.573517 22432 18.498428 -89.506027 -3.931671 22433 38.345856 -92.978287 -3.560661 22434 39.140633 -92.427917 -3.793198 22435 40.313385 -90.151566 -2.912712 22436 13.505188 -94.674057 -4.366821 22437 26.184265 -93.302628 -2.850677 22438 23.713959 -93.773926 -3.723694 22439 13.222672 -95.188904 -4.710564 22440 34.771454 -95.488998 -3.899376 22441 35.547112 -95.003708 -1.994637 22442 23.095200 -96.474716 -4.782745 22443 18.253448 -96.683426 -3.378258 22444 28.239716 -95.064102 -1.303436 22445 28.245026 -96.323471 -2.081955 22446 31.952791 -97.754974 -4.324448 22447 18.732437 -97.766800 -3.581177 22448 24.817963 -97.665146 -2.633919 22449 25.370590 -99.012070 -2.652039 22450 25.233978 -98.767288 -1.533020 22451 18.730835 -98.708725 -3.930313 22452 18.106461 -99.604156 -3.789993 22453 29.939194 -98.240799 -3.745201 22454 31.372612 -98.155334 -3.646873 22455 17.559845 -100.333099 -4.793182 22456 17.096077 -101.411484 -4.534042 22457 17.152954 -100.548126 -3.807373 22458 16.443466 -101.350006 -3.715698 22459 16.526093 -100.739685 -3.139412 22460 17.898354 -101.943619 -5.509460 22461 24.740196 -99.829010 -4.252441 22462 16.039627 -101.329880 -3.019737 22463 16.076523 -101.816254 -3.270432 22464 23.618042 -101.978699 -3.570267 22465 24.454926 -101.129181 -4.188202 22466 9.127319 64.916901 8.639366 22467 7.922904 63.838440 8.591759 22468 10.648079 63.437317 6.564642 22469 11.578781 63.125412 6.481872 22470 11.626801 64.175125 7.151245 22471 10.463272 64.980942 8.034698 22472 9.432251 63.521729 6.582243 22473 4.657303 61.484085 6.146369 22474 12.257996 62.274658 6.314155 22475 12.393898 63.409302 6.883140 22476 13.331299 62.775299 6.900802 22477 13.193954 61.304977 6.239089 22478 14.460236 61.773788 6.827789 22479 14.195084 60.075928 6.137588 22480 16.768646 58.661423 6.395919 22481 17.185059 59.537613 6.427330 22482 16.263718 59.536041 6.585312 22483 17.817444 60.089020 6.482299 22484 18.586777 60.137161 6.632339 22485 17.873093 61.063507 6.909927 22486 19.799881 60.336243 6.937347 22487 21.076981 60.075729 6.824516 22488 20.882469 61.103073 7.507957 22489 4.348900 60.320236 5.979416 22490 15.527412 60.551270 6.686065 22491 15.146599 59.401413 6.293762 22492 14.590919 58.420242 5.830719 22493 15.661430 59.595566 6.528671 22494 20.449539 58.300568 6.387619 22495 21.806885 56.963974 5.993873 22496 22.268623 60.801498 7.830413 22497 21.750153 61.632751 8.800156 22498 21.166809 61.598724 8.265503 22499 23.857704 60.318878 7.898376 22500 23.106323 59.603317 6.879104 22501 4.365608 59.265060 5.753860 22502 15.676300 58.811569 6.442413 22503 15.169975 58.638412 6.196319 22504 16.172043 58.731628 6.485122 22505 16.909676 60.769775 6.812591 22506 17.881775 58.658508 6.349349 22507 19.078018 58.427582 6.408363 22508 21.988388 59.087555 6.537765 22509 25.399765 59.951294 7.987671 22510 26.354294 59.194351 6.926841 22511 4.816620 59.640335 6.607757 22512 16.245621 58.061539 6.413040 22513 15.475357 57.914276 6.112068 22514 17.103508 57.778473 6.410949 22515 18.103821 56.944611 6.335014 22516 5.768974 56.853073 5.629118 22517 7.028435 56.977432 6.479324 22518 6.238121 56.273117 5.413536 22519 19.553169 56.917999 6.371688 22520 20.543335 56.776108 6.331039 22521 21.377853 55.988144 6.071502 22522 21.892677 55.953293 5.789428 22523 8.437546 56.013550 6.257064 22524 8.874802 55.102295 5.544983 22525 18.251778 55.864853 6.093597 22526 21.005005 56.271652 6.252265 22527 9.893623 55.291000 6.635696 22528 19.146729 55.764496 6.004379 22529 34.678986 54.803741 6.492950 22530 34.080444 54.959366 7.485794 22531 11.176933 54.269470 6.935058 22532 10.729179 55.235733 8.218231 22533 11.125084 53.865967 7.693412 22534 11.795700 51.447571 5.925567 22535 24.819427 51.246307 5.570267 22536 36.374985 52.136490 6.253227 22537 11.640915 50.188599 6.348617 22538 12.341621 49.732697 5.944206 22539 12.362915 50.271484 5.527687 22540 35.222359 53.110626 7.132743 22541 12.647629 49.398041 5.504463 22542 22.909042 49.176422 6.539314 22543 22.744728 49.861847 7.232574 22544 23.213684 50.656799 7.039154 22545 36.040901 50.405762 6.080032 22546 35.619476 51.188232 6.658149 22547 27.917130 49.897095 7.723480 22548 35.330688 49.303009 6.117149 22549 35.281456 50.358261 6.578590 22550 10.646744 49.347565 6.757644 22551 34.694519 50.008728 6.901428 22552 34.382584 48.985443 7.172477 22553 10.610657 50.675720 7.043380 22554 27.083099 49.018814 7.789993 22555 11.553588 47.509064 5.997451 22556 22.338051 48.322235 7.007339 22557 21.826019 47.158600 7.007782 22558 33.681595 46.423538 6.785324 22559 34.100845 47.444519 6.956970 22560 26.213226 46.638885 7.294891 22561 25.780212 45.336533 6.865814 22562 22.227570 44.428711 7.268569 22563 34.259354 44.873932 6.982543 22564 24.347061 43.320435 5.268105 22565 23.853233 43.787750 6.256752 22566 24.866173 43.641983 5.707931 22567 5.464661 42.083191 6.063156 22568 6.577591 41.659653 5.595429 22569 8.613251 41.158844 5.302506 22570 33.965988 42.597321 5.959701 22571 9.903664 41.862625 6.705253 22572 11.214310 42.319427 7.678398 22573 11.856903 41.235397 6.363479 22574 7.994102 41.971252 6.368255 22575 8.765380 42.515259 7.379409 22576 36.798523 39.321808 5.393387 22577 36.073128 39.982788 5.438995 22578 35.844925 40.628998 6.104072 22579 37.773170 38.811035 5.115677 22580 37.098663 38.301941 5.626678 22581 12.571106 40.092773 5.460770 22582 36.406891 38.637558 6.503585 22583 36.245567 39.759903 6.401779 22584 39.978630 36.528000 5.457436 22585 45.873749 38.479370 5.028000 22586 46.749664 37.730225 5.952041 22587 45.740280 36.971771 5.903060 22588 45.209106 35.885132 6.463745 22589 44.771881 36.451080 5.663711 22590 49.671844 38.202118 7.500038 22591 14.292877 38.866516 5.868118 22592 14.430542 37.802963 6.196472 22593 13.870529 37.840454 5.398270 22594 36.662064 37.564743 6.085868 22595 40.864105 36.828354 5.334572 22596 4.481812 37.108536 5.683525 22597 3.701553 36.479187 5.682006 22598 37.206200 36.778809 5.690055 22599 37.197868 37.554810 5.668273 22600 37.879776 37.496674 5.387703 22601 38.844383 36.271484 5.563271 22602 43.760025 36.279327 5.655944 22603 6.041954 37.469635 6.252853 22604 5.217560 37.535828 5.961898 22605 5.288178 37.168259 5.644439 22606 11.677856 36.017685 5.045792 22607 36.490631 36.482803 6.539642 22608 37.927933 36.106842 5.614242 22609 37.231598 35.739441 5.995162 22610 41.764114 36.625992 5.445847 22611 42.685699 36.874878 5.358849 22612 44.579453 35.692413 6.044624 22613 3.367195 34.342590 4.877228 22614 9.703712 36.419754 5.869720 22615 8.108269 36.831772 6.085861 22616 36.653748 35.660065 6.489593 22617 37.124344 35.134094 6.623641 22618 38.202133 34.981110 6.506378 22619 40.965912 35.302948 6.302650 22620 39.581917 35.034454 6.434753 22621 42.575577 35.431610 6.277267 22622 44.099823 35.364044 6.530487 22623 43.473328 35.290710 6.424667 22624 3.265595 31.561554 4.021652 22625 3.943932 32.148483 4.992561 22626 4.182800 31.382156 5.179825 22627 3.729164 31.294937 4.508087 22628 52.548645 34.153763 5.503174 22629 49.003342 32.033401 5.445709 22630 49.636719 32.256714 5.451965 22631 50.385696 32.267349 5.420334 22632 51.432022 32.482269 5.574631 22633 52.128510 33.250229 4.790558 22634 52.308960 32.946579 5.973587 22635 47.618668 31.230728 5.291924 22636 48.249832 31.656113 5.548172 22637 48.651764 31.740692 5.940841 22638 3.227585 30.596146 3.984970 22639 3.837456 30.815491 4.985642 22640 45.723999 30.223267 5.283753 22641 46.828369 30.694244 5.426315 22642 3.273522 30.160156 5.646644 22643 43.777115 29.636093 5.130112 22644 44.236877 29.848541 5.137543 22645 44.862610 29.827484 5.580910 22646 43.203766 29.086380 5.201012 22647 42.307617 28.492813 6.105766 22648 42.148239 28.614258 6.919754 22649 41.242569 27.563232 7.180496 22650 2.175514 28.351425 4.351326 22651 42.071671 27.401871 5.894195 22652 2.250397 29.101715 5.429047 22653 2.407127 29.788147 6.496841 22654 2.468174 28.074602 6.636419 22655 2.050971 26.121275 4.646916 22656 2.192499 27.239941 5.305778 22657 31.150406 25.510895 5.681167 22658 32.658813 25.847229 4.898758 22659 34.801292 25.507523 4.491921 22660 33.974594 25.610001 5.476296 22661 35.202347 25.001617 5.643722 22662 43.505157 26.546875 4.461258 22663 1.942276 26.042944 3.846354 22664 30.417755 24.644440 4.786415 22665 43.376373 25.226608 5.110230 22666 2.055343 22.042528 3.940930 22667 2.136437 21.564320 2.958370 22668 2.038930 21.812033 5.069406 22669 2.057072 23.442541 4.816231 22670 30.065323 23.846848 4.269661 22671 30.313614 24.357910 4.144898 22672 37.449326 24.177063 4.536118 22673 2.142287 20.798512 3.722793 22674 29.949493 23.122528 4.064026 22675 39.268341 23.077911 4.674797 22676 2.086523 20.055538 4.756144 22677 2.068925 18.674877 5.645589 22678 2.132268 18.405626 5.064449 22679 30.993736 22.137939 5.367264 22680 30.297180 23.069397 6.166976 22681 30.159515 23.515335 5.181481 22682 30.900970 22.126282 6.435607 22683 40.207367 22.558182 4.318794 22684 42.581070 22.439240 4.823044 22685 2.034379 19.353756 5.914111 22686 2.035909 18.370443 6.375657 22687 2.189027 19.698929 3.955646 22688 2.296162 20.445232 2.796600 22689 33.944565 20.836761 4.373169 22690 34.705353 20.164124 5.467423 22691 33.550018 20.752838 5.455795 22692 2.076940 17.188921 6.454128 22693 2.216165 18.903233 4.071920 22694 2.280815 18.518902 3.706657 22695 2.326618 19.190880 3.196120 22696 35.313248 20.119904 4.347382 22697 36.083496 19.165726 5.187035 22698 2.168298 16.863602 5.489611 22699 2.156162 15.545378 6.369103 22700 2.228325 18.277508 4.205245 22701 2.179838 17.570324 4.930760 22702 2.251665 17.202597 4.491875 22703 2.323765 16.492449 4.262361 22704 2.344167 17.723436 3.557907 22705 2.223594 17.836626 4.423059 22706 36.917831 18.567078 4.340126 22707 2.309666 15.643454 4.757239 22708 2.276545 14.733545 5.474291 22709 36.904724 18.185272 5.249176 22710 37.675484 16.824051 4.806030 22711 2.366705 14.083112 4.843671 22712 2.230866 13.484796 6.440302 22713 2.482718 14.629133 3.652766 22714 2.498245 13.779051 3.899150 22715 2.427655 12.866971 4.799448 22716 2.602746 14.573427 2.856715 22717 37.504288 15.427994 4.171066 22718 2.276368 12.804094 6.206925 22719 2.244413 12.067159 6.668591 22720 2.200720 11.508780 7.682627 22721 2.215986 11.518796 7.179841 22722 37.158783 16.171036 5.175568 22723 37.738640 16.238892 4.607895 22724 2.316181 12.127879 5.972610 22725 2.222163 11.759635 6.827487 22726 2.254776 11.716783 6.613702 22727 2.217423 11.591821 6.907876 22728 36.176147 16.787720 6.341385 22729 36.155800 10.342773 4.334610 22730 35.589180 10.995255 4.073959 22731 39.288330 9.504395 3.809807 22732 40.632751 9.533783 3.511780 22733 41.627716 8.327515 3.605698 22734 41.169739 7.279877 3.917847 22735 41.721634 5.694275 3.627014 22736 41.198380 6.313538 3.659157 22737 39.469131 4.346130 5.060608 22738 39.395279 6.012619 5.089661 22739 41.016281 4.679352 5.011353 22740 44.498718 4.697876 3.210968 22741 44.814102 3.970375 4.226166 22742 44.356110 4.200905 4.487541 22743 44.380096 4.361908 3.895561 22744 45.192307 -0.585510 3.292130 22745 45.153748 0.594376 4.737908 22746 2.244018 4.868148 5.311460 22747 57.124390 1.842743 3.377159 22748 57.990402 1.522568 3.917442 22749 55.564224 -0.024765 4.405678 22750 56.801697 0.994675 4.083511 22751 56.992599 0.480835 4.846527 22752 55.525330 1.148499 3.019196 22753 59.038239 0.047119 4.395676 22754 2.552726 1.273043 6.073612 22755 2.711092 -0.539850 6.148661 22756 2.775185 1.347463 4.205686 22757 2.980102 -0.303596 4.553392 22758 39.342201 -2.586823 2.698380 22759 39.842148 -1.835846 2.449951 22760 40.685364 -1.419800 2.318756 22761 53.562698 -0.761307 3.428818 22762 3.008658 -1.038119 4.783221 22763 40.770081 -2.776199 3.207214 22764 44.350494 -2.576813 5.112923 22765 58.704300 -2.738373 4.259628 22766 3.382619 -2.246898 3.698995 22767 38.291428 -3.293030 2.194443 22768 38.689896 -3.261322 2.544144 22769 3.349132 -2.965661 4.107647 22770 3.456971 -3.964955 3.948022 22771 39.306328 -3.741455 3.300232 22772 39.004852 -4.743500 3.522843 22773 39.488556 -4.893387 3.974457 22774 52.708115 -3.713486 4.688110 22775 51.754456 -4.802567 4.143364 22776 2.999285 -3.092553 5.702784 22777 3.378443 -4.804399 4.469980 22778 39.199020 -5.493958 3.638519 22779 57.032623 -3.557907 3.286148 22780 57.062088 -4.128189 2.938721 22781 57.511017 -3.002228 3.640549 22782 59.915634 -5.213745 2.949860 22783 59.939499 -4.641785 3.390549 22784 60.220840 -5.213928 3.550964 22785 3.656269 -5.068361 3.377124 22786 40.788666 -5.789505 2.671097 22787 41.990707 -5.860092 2.621986 22788 42.695435 -5.908875 2.489021 22789 59.768570 -6.033722 3.261376 22790 60.161636 -5.712952 4.069626 22791 39.529770 -6.128296 3.724732 22792 40.531097 -7.586166 4.409073 22793 41.476593 -7.226303 4.046890 22794 41.431213 -7.691162 4.628708 22795 42.649048 -6.357681 2.975594 22796 51.331696 -6.253830 4.828903 22797 50.939011 -7.120361 4.022637 22798 60.170471 -5.570419 4.993759 22799 59.281189 -6.771576 4.241737 22800 3.815421 -7.592222 3.590156 22801 3.554130 -7.335681 4.696649 22802 3.749152 -8.338078 4.311120 22803 43.304306 -7.102936 3.424515 22804 44.162430 -7.693054 3.350540 22805 57.635742 -8.077652 3.927658 22806 3.486318 -6.246629 4.492778 22807 55.629669 -9.473373 4.062042 22808 44.403488 -8.429657 3.740013 22809 44.509796 -9.564713 3.602249 22810 56.259323 -9.794067 2.774124 22811 55.752777 -9.875687 3.149078 22812 56.068359 -9.469055 3.132774 22813 56.030060 -10.353760 2.880859 22814 43.547150 -11.380569 2.878578 22815 44.052979 -10.615372 3.850723 22816 55.471100 -10.412842 3.451996 22817 59.821365 -10.279236 2.407623 22818 58.638626 -11.011475 3.660759 22819 59.710602 -10.539001 2.963989 22820 4.179747 -11.214455 4.219669 22821 4.475523 -12.265826 3.588336 22822 35.564072 -12.245178 1.150772 22823 43.614731 -11.578934 3.465294 22824 49.115662 -11.334747 2.818161 22825 56.153763 -10.987946 3.276825 22826 57.377045 -11.176575 3.237427 22827 56.666794 -11.553085 3.841690 22828 57.574646 -11.505783 3.800728 22829 58.574203 -11.225800 4.972565 22830 57.432159 -11.584106 4.444573 22831 60.623978 -10.570694 3.888474 22832 47.956055 -12.599503 2.656876 22833 63.570419 -12.152008 4.777008 22834 4.573716 -13.300655 4.216445 22835 46.634293 -14.555847 2.717743 22836 47.360733 -13.632751 3.884590 22837 46.897293 -14.696304 3.758049 22838 56.997131 -15.288620 3.039429 22839 56.182861 -15.842728 2.693955 22840 57.748703 -14.842041 2.976868 22841 63.706696 -13.379593 3.538147 22842 5.297633 -15.227824 2.595182 22843 37.562347 -15.589828 1.294914 22844 54.881256 -16.547806 2.268494 22845 59.636719 -15.074692 2.645401 22846 60.442749 -15.380295 2.576721 22847 5.523835 -16.177856 2.714492 22848 38.184135 -15.885880 1.822769 22849 40.365570 -14.967331 3.490898 22850 38.149094 -16.752823 2.266068 22851 44.722687 -16.393509 2.703323 22852 61.310196 -15.773926 2.221802 22853 61.633118 -15.554581 3.313202 22854 62.096222 -15.449234 4.316078 22855 62.695923 -15.465179 3.748367 22856 62.910858 -15.585831 2.744759 22857 63.349716 -14.900101 3.444931 22858 37.900467 -17.518845 1.923630 22859 42.612579 -18.378510 2.904404 22860 52.710571 -18.487015 2.480690 22861 6.671724 -19.392750 2.728814 22862 6.353473 -18.904764 3.429316 22863 41.545364 -19.592087 2.065903 22864 51.886169 -19.264160 2.229553 22865 52.102417 -20.511246 3.779389 22866 53.246719 -20.426346 4.197632 22867 52.636017 -19.538177 3.271774 22868 7.023822 -19.470259 1.085622 22869 6.820038 -19.061544 1.072703 22870 6.600264 -18.978975 1.931502 22871 39.232491 -21.559753 2.022255 22872 40.176910 -21.108261 1.818581 22873 40.764160 -20.421677 1.833725 22874 41.245514 -20.447693 2.575653 22875 6.846523 -19.467173 1.850660 22876 37.471588 -21.519577 1.913879 22877 37.156494 -21.654861 2.188583 22878 37.309113 -21.128662 2.261932 22879 38.076111 -21.400162 1.962860 22880 37.990189 -20.569214 2.084946 22881 40.756805 -21.162552 2.345703 22882 49.357101 -22.608582 3.145966 22883 49.705261 -22.019592 2.893433 22884 50.241821 -21.449554 2.821472 22885 37.550003 -21.878967 2.189835 22886 39.599831 -22.163284 2.945877 22887 38.932564 -22.417831 2.879181 22888 40.143036 -21.682129 2.358917 22889 38.129883 -22.358139 2.813820 22890 37.109299 -22.226578 2.893128 22891 51.622421 -23.282394 1.713310 22892 52.227249 -24.175156 2.138306 22893 51.337189 -24.118149 2.016190 22894 52.815811 -23.445389 1.860703 22895 54.070145 -23.818878 2.150063 22896 56.375031 -23.340866 1.719566 22897 10.727682 -24.792055 1.516433 22898 10.465461 -24.555458 1.578573 22899 10.483112 -24.659050 1.862038 22900 10.646981 -24.830887 2.055843 22901 11.028761 -25.016129 1.426433 22902 11.233313 -25.255285 1.789280 22903 49.456207 -25.271744 1.981522 22904 49.404083 -26.919708 2.438797 22905 48.477142 -26.209808 1.963638 22906 48.888748 -23.287552 2.704117 22907 48.719925 -24.307663 2.113091 22908 48.194168 -24.084106 2.953125 22909 9.120907 -22.967068 1.251117 22910 9.555629 -23.483101 1.209828 22911 9.495746 -23.245394 0.660302 22912 9.745446 -23.355610 0.167290 22913 11.100605 -25.318094 2.444600 22914 11.520868 -25.766418 2.530310 22915 48.444016 -25.400848 1.857010 22916 7.443854 -20.363464 1.193100 22917 7.810931 -20.936945 0.959364 22918 10.071385 -23.827194 0.562034 22919 13.260805 -26.847073 1.368470 22920 12.314890 -26.342260 2.049533 22921 12.785240 -26.946283 2.390500 22922 47.686783 -25.254990 2.264305 22923 47.937042 -25.960876 1.848831 22924 47.868103 -26.425278 1.919373 22925 13.778434 -27.498337 1.755871 22926 47.533432 -26.198654 2.050713 22927 56.074600 -28.045425 1.728661 22928 56.523376 -27.114471 1.466690 22929 56.709213 -27.105515 1.992630 22930 55.665985 -28.956909 1.614151 22931 55.941833 -27.961456 2.913284 22932 56.713699 -26.875229 2.571846 22933 14.047573 -28.239265 2.573005 22934 13.390646 -27.688532 2.678185 22935 13.986582 -28.444828 3.016067 22936 55.182281 -29.746185 1.410782 22937 56.056244 -28.882034 1.960312 22938 55.670685 -29.551987 2.288757 22939 56.086304 -28.689178 2.279862 22940 55.346344 -30.520370 1.748009 22941 44.210007 -30.836411 1.679459 22942 45.088776 -31.341537 1.163559 22943 46.053772 -30.860321 1.660584 22944 46.987030 -31.463318 1.154770 22945 47.354065 -31.884125 0.382546 22946 50.976685 -31.711639 1.307045 22947 54.474457 -31.458832 1.432297 22948 55.077393 -31.063278 1.740585 22949 16.561737 -30.738056 3.193096 22950 21.157356 -32.871357 2.084359 22951 31.429337 -33.160736 1.068817 22952 17.189371 -31.193714 3.115688 22953 17.614151 -31.317398 2.852403 22954 17.578262 -31.602415 3.239294 22955 18.197968 -31.817825 2.929539 22956 18.826134 -31.982798 2.603800 22957 24.020756 -34.238144 1.893359 22958 25.159983 -34.301872 1.516252 22959 32.035141 -34.109482 0.754128 22960 17.295555 -31.886620 3.876255 22961 28.390818 -34.812569 1.116112 22962 27.422932 -36.147339 1.901900 22963 27.547606 -35.671349 1.612972 22964 26.292046 -35.016270 1.599932 22965 29.678535 -34.343571 1.267006 22966 32.217545 -35.177399 0.482124 22967 19.670212 -36.806854 1.231400 22968 27.174953 -34.270649 0.988810 22969 30.886841 -36.291321 0.842522 22970 31.505302 -35.036667 1.425232 22971 63.787842 -36.383194 1.345566 22972 15.303925 -37.405563 0.064102 22973 15.454361 -36.972198 0.912422 22974 14.859268 -37.429947 1.070610 22975 16.195625 -36.689697 0.671288 22976 16.811440 -36.509750 0.858170 22977 28.335663 -37.766373 0.397530 22978 60.059814 -36.804337 1.816116 22979 64.390671 -36.714752 1.381470 22980 64.647781 -37.050980 1.547386 22981 15.214348 -38.414246 0.688675 22982 23.379623 -38.109573 1.202408 22983 22.146500 -37.655746 1.341904 22984 20.860916 -38.233490 3.761299 22985 20.702545 -37.968567 3.184113 22986 21.558899 -38.289383 3.322884 22987 24.673981 -38.321976 0.623543 22988 25.045792 -38.776978 1.441452 22989 30.040573 -36.532364 1.182541 22990 58.618851 -37.128174 1.392677 22991 59.093811 -37.238022 3.205910 22992 58.247253 -36.923126 2.597122 22993 64.847519 -37.816895 1.419113 22994 24.244217 -38.628464 1.550751 22995 24.408005 -38.824020 2.365685 22996 25.397247 -38.535263 2.306107 22997 49.048248 -36.735382 3.344284 22998 48.397766 -36.136520 2.970398 22999 48.163452 -36.201141 2.401253 23000 50.980194 -37.802475 1.369949 23001 55.870926 -37.738281 1.555901 23002 57.223785 -37.376190 1.808930 23003 57.901855 -37.049484 2.147598 23004 57.360779 -37.178757 3.283341 23005 64.631546 -38.752716 1.085716 23006 17.243713 -40.662659 0.317139 23007 27.383179 -37.891403 1.260117 23008 51.762497 -38.494659 1.092651 23009 54.376495 -38.715500 0.471817 23010 53.323914 -38.472336 1.122696 23011 56.212387 -37.065018 2.888168 23012 55.304276 -37.080276 2.681267 23013 54.582489 -38.243774 1.268547 23014 63.453430 -39.850449 1.146431 23015 63.946503 -39.379013 0.952011 23016 9.714767 -41.330887 0.566818 23017 9.849106 -41.033905 1.008476 23018 9.489655 -41.654022 1.429184 23019 9.939590 -41.330734 0.023857 23020 17.988724 -41.573944 0.295517 23021 62.604584 -40.486847 1.027588 23022 62.458435 -41.230499 1.774101 23023 12.815734 -41.754303 1.169151 23024 12.310104 -40.849609 0.560593 23025 18.896568 -42.345795 0.603989 23026 57.701355 -43.409470 1.854210 23027 14.590416 -42.593689 0.825859 23028 15.867584 -44.098785 1.361511 23029 18.876144 -43.807785 0.269791 23030 20.109741 -44.007492 1.061073 23031 19.311584 -45.198380 0.565682 23032 56.091125 -44.085327 1.110375 23033 56.894867 -43.939743 0.552353 23034 56.904007 -43.703522 1.614678 23035 12.122902 -46.309280 1.338867 23036 12.735490 -43.417374 2.764137 23037 17.814072 -44.492371 0.514786 23038 50.219482 -46.324554 0.615326 23039 53.306839 -45.300827 1.353043 23040 12.824226 -46.542862 0.462578 23041 12.960594 -47.530060 0.678757 23042 48.049744 -48.864426 -0.055450 23043 13.992065 -48.408569 -0.436493 23044 47.269272 -50.244751 -0.047882 23045 44.659882 -49.734436 -0.899277 23046 49.338745 -48.461731 0.563202 23047 50.862732 -48.245834 1.511772 23048 50.278809 -47.343475 1.349777 23049 49.655457 -47.486755 0.949577 23050 52.195496 -49.120941 1.185272 23051 52.006653 -48.599472 2.024231 23052 14.899124 -50.100342 -0.297066 23053 45.062973 -50.175385 -0.332886 23054 45.925446 -50.386017 0.069718 23055 48.363708 -50.362717 -0.279175 23056 52.796844 -49.815659 0.290100 23057 53.536865 -49.374054 1.184181 23058 16.262451 -50.760178 -0.864029 23059 17.170258 -51.447510 -0.575302 23060 45.376068 -51.816803 0.408844 23061 45.051514 -50.912766 -0.093857 23062 48.142761 -51.357483 -0.041183 23063 48.966400 -51.188293 -0.431931 23064 56.540558 -50.143326 1.753616 23065 56.967529 -51.249634 2.209763 23066 57.071777 -51.989304 0.798210 23067 19.506149 -53.672333 -0.646194 23068 51.225098 -54.988785 0.304962 23069 52.415817 -55.355423 0.081268 23070 50.251556 -54.172501 0.349480 23071 51.235413 -54.242371 0.036972 23072 57.455505 -52.846359 0.908646 23073 58.223465 -53.451279 0.545006 23074 19.337898 -54.733368 -0.451584 23075 19.454193 -55.729645 -0.535522 23076 19.720268 -55.356339 -0.727997 23077 19.439835 -55.380081 -1.131653 23078 44.615601 -55.150375 0.536728 23079 44.499817 -54.350922 -0.074600 23080 44.696930 -53.065811 0.288117 23081 48.018921 -53.312088 0.893768 23082 48.623230 -54.414658 0.996491 23083 53.339005 -55.149414 -0.310036 23084 58.901077 -54.022049 0.304062 23085 59.306671 -54.835129 0.581772 23086 53.386810 -56.045349 -0.059341 23087 59.148575 -56.949081 -0.109116 23088 18.567467 -59.028885 -0.939224 23089 18.908661 -57.766281 -0.681931 23090 18.939957 -56.521088 -0.881165 23091 54.686981 -56.826782 -0.428474 23092 53.271698 -57.203903 0.038826 23093 54.730499 -58.426193 -0.446671 23094 59.675247 -56.143112 1.017677 23095 18.172455 -60.221191 -1.088623 23096 16.437271 -61.219742 -1.456467 23097 18.548378 -60.053558 -0.762970 23098 18.751076 -59.199203 -0.085403 23099 18.552704 -59.880280 -0.212318 23100 44.670410 -59.243164 -0.160156 23101 44.717545 -58.407059 0.386978 23102 17.520187 -61.103287 -0.974945 23103 58.136917 -59.355911 0.083511 23104 57.822006 -60.419174 -0.074394 23105 11.900383 -61.520279 -1.599197 23106 11.642349 -62.034348 -0.866318 23107 12.673294 -62.293167 -0.437782 23108 13.749207 -62.164001 -0.860382 23109 16.629868 -62.407120 -0.276009 23110 15.812393 -62.238113 -1.083618 23111 44.463150 -62.251938 -0.807350 23112 52.637558 -59.384735 -0.068458 23113 53.764587 -59.026505 -0.201042 23114 57.546753 -60.980652 0.603584 23115 57.596313 -60.004135 1.048874 23116 10.644669 -62.417007 0.025269 23117 15.631386 -61.714706 -1.489456 23118 18.228973 -60.706421 -0.501450 23119 17.669861 -61.462463 -0.185486 23120 25.497650 -62.362381 -1.570145 23121 26.409210 -62.314667 -1.623886 23122 44.866028 -60.088455 0.246483 23123 45.002533 -59.128448 0.584030 23124 52.490906 -62.344208 -0.720749 23125 51.266602 -60.528290 -0.074295 23126 53.581573 -63.979279 -1.103333 23127 51.556870 -63.795441 -1.001434 23128 25.541718 -62.998047 -1.206123 23129 43.810150 -63.106873 -1.479004 23130 44.201080 -63.133987 -1.244873 23131 50.578949 -61.959549 -0.278984 23132 57.285095 -62.372162 -0.336075 23133 57.112656 -62.914688 -0.389351 23134 9.424530 -64.430984 -1.428604 23135 9.136200 -63.202942 -0.153534 23136 22.747147 -65.182266 -0.801987 23137 44.951797 -64.076279 -1.085953 23138 49.208374 -64.004776 -0.810165 23139 49.854172 -63.143173 -0.534660 23140 48.747101 -63.044617 -0.346664 23141 55.096039 -64.223755 -0.897339 23142 21.347183 -65.524094 -1.450729 23143 26.122910 -64.967560 -0.690567 23144 45.410812 -64.997391 -1.235458 23145 45.654312 -64.544418 -0.853775 23146 46.017776 -63.528854 -0.415360 23147 47.154877 -64.163300 -0.630676 23148 47.479004 -62.676727 -0.096481 23149 46.288406 -65.061386 -1.093796 23150 56.091599 -64.106552 -0.447739 23151 9.707382 -69.945541 -1.548721 23152 9.116699 -69.136398 -1.449661 23153 9.344994 -69.334595 -0.344505 23154 12.443092 -66.645737 -2.324364 23155 11.617813 -66.452942 -2.373497 23156 39.327057 -65.927368 0.112808 23157 11.771759 -67.219025 -2.231812 23158 12.495552 -67.147064 -1.940582 23159 12.885567 -67.048538 -2.011490 23160 13.112900 -67.496002 -2.095818 23161 21.425735 -67.067535 -1.425644 23162 20.934555 -66.208984 -1.381584 23163 23.218704 -68.617950 -0.734009 23164 23.492874 -67.765472 -0.337868 23165 22.569199 -67.354858 -0.697456 23166 40.195374 -66.477997 0.125237 23167 40.722290 -67.864944 -1.107788 23168 8.648148 -68.606888 -0.491035 23169 12.603210 -67.493546 -1.986649 23170 16.587234 -68.147842 -2.521606 23171 24.449982 -67.139450 -0.134926 23172 23.332336 -66.422058 -0.155716 23173 38.057785 -66.099350 0.239777 23174 37.475433 -68.089417 -1.709076 23175 53.729492 -67.795731 -0.612671 23176 21.697266 -68.625519 -2.147820 23177 22.409332 -68.548355 -1.333008 23178 23.177139 -70.044098 -1.163841 23179 37.271774 -67.928757 -1.117752 23180 37.174904 -67.983475 -0.279678 23181 37.571182 -68.812210 0.315720 23182 10.393776 -70.784790 -2.005325 23183 25.920853 -71.321426 -1.221069 23184 25.900909 -72.711166 -1.523262 23185 26.865929 -72.118118 -1.749908 23186 45.850235 -70.432358 -1.531517 23187 46.431000 -69.951859 -1.167206 23188 47.103729 -69.325241 -0.183258 23189 50.970245 -70.544891 -0.383850 23190 52.410126 -70.235565 -0.130478 23191 52.757645 -69.614899 -0.496437 23192 26.919655 -74.088913 -2.004791 23193 38.644203 -70.913879 0.218941 23194 51.748276 -70.581589 -0.491364 23195 4.731773 -73.244705 -0.738701 23196 4.910889 -74.106537 -1.854569 23197 6.908699 -72.683533 -1.256866 23198 12.918610 -71.130188 -0.601166 23199 13.242448 -70.930573 0.171982 23200 13.583969 -71.454971 -0.033157 23201 21.523445 -71.994629 -2.154922 23202 8.210449 -73.605499 -2.078545 23203 8.663002 -74.314697 -2.187927 23204 14.456802 -73.011917 -1.299530 23205 14.674988 -73.535919 -1.406952 23206 24.729836 -74.131653 -2.049934 23207 24.564377 -72.349426 -1.229248 23208 26.137711 -74.151581 -1.962143 23209 10.810616 -75.924423 -1.197548 23210 11.235794 -75.858002 -1.014160 23211 10.899101 -74.867126 -0.470200 23212 8.703224 -74.913773 -2.329987 23213 9.318573 -74.784073 -1.554848 23214 25.576813 -76.268524 -2.312424 23215 26.807770 -74.900162 -2.214706 23216 40.624069 -73.589386 -0.902672 23217 40.383621 -72.976822 0.344711 23218 39.901871 -72.444366 0.506401 23219 44.657501 -73.852798 0.092224 23220 43.740143 -74.451370 -1.297791 23221 48.009979 -74.751221 -0.264160 23222 46.772202 -74.243073 0.523087 23223 8.215927 -75.659027 -2.403343 23224 42.860199 -74.725693 -1.794098 23225 48.480194 -75.644287 -0.417763 23226 48.316513 -75.300430 0.756256 23227 23.193527 -76.743225 -2.317039 23228 24.053009 -76.399490 -2.314110 23229 4.769539 -77.925262 -2.103104 23230 12.314056 -77.591553 -2.409706 23231 20.605057 -79.008820 -1.627243 23232 20.773216 -78.034409 -2.210602 23233 21.525978 -77.933624 -1.615295 23234 22.243881 -77.769547 -1.585144 23235 24.619995 -77.546097 -2.075272 23236 26.604065 -77.718994 -2.807259 23237 37.243149 -78.292435 -2.144089 23238 37.272453 -77.765488 -1.415863 23239 40.280746 -77.757507 -0.757690 23240 40.929688 -77.694931 -1.401169 23241 7.664734 -78.000381 -2.248375 23242 12.824989 -76.582977 -1.268913 23243 14.117920 -76.696411 -1.365059 23244 35.079102 -79.562775 -1.083252 23245 35.614899 -78.859375 -1.076660 23246 36.402153 -78.182465 -1.270569 23247 46.677292 -77.760208 -1.120468 23248 44.741608 -78.470093 -1.681175 23249 44.435425 -77.732864 -0.615395 23250 45.673035 -77.871567 -0.908661 23251 4.843865 -79.182465 -2.549919 23252 7.285416 -79.010620 -2.772003 23253 8.236618 -78.443008 -2.373573 23254 18.647278 -79.905838 -2.947937 23255 22.950363 -79.724777 -2.260216 23256 33.997093 -81.083450 -1.635551 23257 35.806213 -78.588196 -1.642395 23258 5.491509 -82.890396 -3.435242 23259 8.078285 -82.594254 -3.325592 23260 13.367860 -83.883667 -3.138329 23261 20.836220 -81.515457 -3.090393 23262 20.937790 -81.061234 -2.373672 23263 21.567154 -80.502319 -1.958527 23264 20.716019 -80.792999 -1.977013 23265 33.412239 -81.805298 -0.919136 23266 33.002350 -82.415527 -1.294724 23267 21.713150 -79.477570 -1.541550 23268 20.689194 -80.200531 -1.673965 23269 33.016464 -83.304123 -1.361000 23270 5.591965 -83.819504 -2.816940 23271 8.189064 -83.280334 -3.769943 23272 34.527733 -85.855164 -1.719749 23273 33.898209 -84.626678 -2.046715 23274 13.231888 -84.765182 -3.202179 23275 13.331146 -82.887817 -3.463409 23276 17.001358 -85.851822 -2.952972 23277 13.140045 -85.311264 -3.543167 23278 13.783662 -84.599731 -3.002686 23279 13.900223 -84.956146 -3.142143 23280 17.840805 -86.091629 -3.258461 23281 33.178108 -84.522903 -1.318596 23282 33.617416 -85.330231 -1.432014 23283 37.315323 -88.269485 -1.563347 23284 36.755829 -87.444473 -1.842316 23285 6.852348 -86.552917 -3.322800 23286 37.352364 -85.884613 -2.846466 23287 36.703835 -86.522842 -2.253998 23288 17.975235 -87.819412 -3.334076 23289 17.449478 -86.647308 -2.979126 23290 39.699524 -88.552841 -2.066406 23291 39.179176 -87.899979 -2.104538 23292 17.806488 -88.882950 -3.561005 23293 8.096176 -88.410110 -2.774071 23294 10.071030 -89.903625 -2.897140 23295 10.456192 -90.220917 -2.370033 23296 11.139252 -90.306870 -1.568726 23297 14.294731 -91.459976 -3.098496 23298 39.297546 -91.486252 -2.222534 23299 39.548470 -90.911087 -2.017990 23300 39.832367 -90.203796 -2.222542 23301 14.229211 -92.402893 -3.452225 23302 23.506714 -92.843277 -2.677872 23303 23.812996 -92.028046 -2.554108 23304 24.751953 -91.839417 -2.352486 23305 38.800812 -92.233170 -2.658112 23306 14.725967 -95.012924 -4.046089 23307 13.698654 -95.389633 -4.466537 23308 16.144951 -94.595673 -3.328758 23309 16.905350 -94.348328 -2.924583 23310 17.125908 -95.228622 -3.289047 23311 18.729370 -96.851395 -1.812088 23312 15.080673 -93.469208 -3.292969 23313 18.148300 -95.514099 -2.571907 23314 33.684700 -97.025146 -1.690895 23315 34.045273 -96.606430 -2.241608 23316 34.426224 -96.063461 -2.801216 23317 17.605164 -94.231857 -2.402504 23318 23.877586 -96.617874 -3.468094 23319 24.319611 -98.253647 -3.938545 23320 28.646439 -97.121704 -2.277054 23321 18.591873 -98.549881 -1.652741 23322 18.606895 -98.727463 -2.737839 23323 25.044014 -98.942276 -3.421066 23324 31.091484 -98.118988 -2.407585 23325 32.289871 -97.688156 -3.163879 23326 18.865631 -98.243393 -4.065720 23327 31.246834 -98.088913 -1.272934 23328 30.094643 -98.076660 -1.518326 23329 30.198257 -97.737167 -0.527695 23330 25.173386 -100.086563 -3.341629 23331 16.762901 -102.280334 -3.395416 23332 19.548721 -103.019562 -3.508919 23333 20.628708 -103.025818 -2.234337 23334 12.920425 64.473831 7.722427 23335 6.990219 63.273590 7.385009 23336 14.467285 64.987717 9.108841 23337 13.059509 65.644714 8.860367 23338 14.421730 63.405975 7.615196 23339 15.932495 62.400879 7.438751 23340 11.700905 64.967804 7.711395 23341 5.584663 61.067688 7.489883 23342 6.658974 62.517059 8.228043 23343 17.251785 61.926392 7.311203 23344 17.028320 62.749146 7.938139 23345 17.317398 63.160431 8.864548 23346 18.372986 61.963577 7.884696 23347 6.023758 62.450546 7.178634 23348 5.619515 59.440247 7.336151 23349 19.049538 62.209991 8.646896 23350 18.668587 62.415070 8.815697 23351 23.552635 61.129425 9.326431 23352 22.326797 61.371704 9.433975 23353 15.264137 63.696777 8.180679 23354 21.708160 61.705383 9.371643 23355 27.528641 58.743088 9.465775 23356 27.407555 59.528290 9.504860 23357 27.466171 59.201675 8.572174 23358 27.985794 58.052856 8.031174 23359 28.251892 57.839874 7.019393 23360 8.723831 56.592148 7.198661 23361 9.143082 57.268082 8.199646 23362 10.281204 56.599777 8.718033 23363 9.764565 56.258942 7.819168 23364 27.392311 56.428772 8.122894 23365 27.866287 57.287857 8.313345 23366 34.180878 54.699493 8.405556 23367 33.626282 55.238724 8.404083 23368 34.816406 54.597534 7.064773 23369 11.543320 53.458832 6.584900 23370 34.665627 54.122360 7.599487 23371 11.317017 52.767044 6.943862 23372 11.418549 53.644913 7.106399 23373 25.255501 53.985916 7.733383 23374 32.750137 55.079483 7.816772 23375 31.232086 54.351120 8.055557 23376 30.317200 53.714935 8.322411 23377 34.352875 54.066208 8.365372 23378 34.468384 53.229279 8.150970 23379 35.139557 52.130081 7.217285 23380 24.041122 51.488647 6.560577 23381 23.572128 50.053406 6.094078 23382 11.045090 51.458313 6.928024 23383 34.469177 52.128647 8.183884 23384 34.823730 51.047943 7.367477 23385 10.855865 47.925903 6.491249 23386 11.005234 47.163818 6.242384 23387 23.359398 51.654984 7.720016 23388 22.790298 50.717499 7.958648 23389 10.435074 47.327026 6.490386 23390 22.592438 49.154099 7.089424 23391 34.358978 50.218109 7.723022 23392 34.432045 47.878540 8.054276 23393 34.412582 49.615921 8.480896 23394 8.995338 47.875732 6.476966 23395 6.450104 47.397339 6.592803 23396 7.416435 46.559387 6.023056 23397 10.442596 46.877029 6.073883 23398 21.413284 46.129120 7.500839 23399 8.301750 51.070206 7.735839 23400 6.815567 50.628571 7.701339 23401 21.457962 47.063416 7.739769 23402 33.478981 46.015320 6.713974 23403 36.840057 45.304657 7.452857 23404 38.069717 44.975189 7.111267 23405 38.669266 46.288452 7.514266 23406 39.638702 45.401337 7.251449 23407 40.175507 46.281555 7.614135 23408 21.640671 45.047714 7.680419 23409 25.131836 44.828445 7.349266 23410 33.679100 45.901871 6.932075 23411 35.416168 44.883636 7.379730 23412 35.603027 45.651428 7.864996 23413 34.828117 46.199524 7.943481 23414 34.277130 43.068878 6.335266 23415 34.544739 42.452881 6.181915 23416 35.085953 43.362274 6.632308 23417 36.264275 43.961731 6.922683 23418 37.617340 43.582642 7.075256 23419 38.882881 44.598419 7.198791 23420 39.019867 43.019073 7.832145 23421 39.993584 44.478119 7.509765 23422 40.223907 45.391769 7.397842 23423 41.035919 45.402039 7.773345 23424 3.519241 43.631744 6.228584 23425 24.487221 44.207962 7.143844 23426 23.754730 44.011414 7.290588 23427 23.087326 44.044342 7.289352 23428 34.302155 43.653687 6.567672 23429 36.265289 42.510941 6.698745 23430 25.493584 45.480530 7.862915 23431 35.309135 41.744415 6.127090 23432 37.866302 42.397766 7.601303 23433 6.627068 42.502213 7.134048 23434 7.149223 42.988586 8.093185 23435 7.911026 42.777161 7.726860 23436 36.022415 41.401001 6.626869 23437 13.483200 40.391083 6.303009 23438 12.458725 41.664642 7.288375 23439 13.570366 41.216736 7.307304 23440 36.406631 40.682709 7.140251 23441 36.579086 39.513336 7.606140 23442 14.352203 41.054840 7.990097 23443 15.239868 40.440216 8.172012 23444 15.068832 39.906464 7.286880 23445 14.837158 38.490067 6.431991 23446 14.685089 39.483932 6.550766 23447 4.948891 37.819687 6.419891 23448 5.274582 38.208084 6.861770 23449 4.648224 38.214249 7.093063 23450 13.779633 37.191742 6.205047 23451 13.396713 37.444550 7.543205 23452 12.540756 36.960693 6.609619 23453 36.300644 37.545212 7.066070 23454 47.316803 37.524536 6.952346 23455 52.177124 36.475494 6.854797 23456 52.802582 34.920532 6.733596 23457 10.531731 37.313934 7.163437 23458 9.135864 37.370911 6.857788 23459 36.472824 35.560928 7.346916 23460 46.140594 36.481964 6.832580 23461 45.779236 36.240753 6.615966 23462 46.633942 37.008087 6.856315 23463 52.519745 35.846313 7.915893 23464 51.963989 36.906860 7.909194 23465 3.669541 35.512573 6.325248 23466 44.678528 35.472443 6.567085 23467 4.131500 34.119888 6.460357 23468 3.851906 33.257355 5.325668 23469 52.862000 33.637192 6.390533 23470 53.195862 33.599655 7.189506 23471 53.158325 34.481827 7.625068 23472 49.505341 31.647552 6.048805 23473 53.195679 32.331116 7.807327 23474 53.223419 33.453140 8.272797 23475 5.031723 31.816895 6.745063 23476 4.556740 31.805405 5.831993 23477 4.644554 32.869629 6.419166 23478 48.176514 30.720108 6.053619 23479 50.640869 31.655014 6.194335 23480 51.777222 31.520935 6.664680 23481 4.293121 31.046127 6.118469 23482 46.767731 29.784790 6.066909 23483 43.978180 29.443787 5.825653 23484 45.666229 29.568604 6.074234 23485 44.140274 28.737457 6.785362 23486 44.922852 29.081726 6.353210 23487 48.408951 27.061157 6.320968 23488 49.253967 27.093597 6.101776 23489 48.294769 28.411560 6.353714 23490 49.750519 28.050674 6.182212 23491 50.290436 29.758331 6.539938 23492 40.122711 27.791016 8.088837 23493 40.732758 28.034683 8.145920 23494 47.499146 26.895493 6.839096 23495 48.810974 25.818420 6.387290 23496 49.243698 24.373657 6.301826 23497 50.047089 24.956375 5.987808 23498 50.666458 28.080704 6.502960 23499 50.307617 27.245468 6.223327 23500 2.004688 24.919735 4.162685 23501 42.667496 26.250061 5.492539 23502 51.474365 28.631424 7.307090 23503 51.250244 27.129150 7.192428 23504 50.361786 26.102417 6.167930 23505 51.579346 25.356293 6.627754 23506 30.271446 24.684937 5.558556 23507 50.054382 23.894028 6.067291 23508 50.756744 22.906921 5.877693 23509 51.183960 24.198212 5.948059 23510 50.896820 25.154022 6.000656 23511 30.319824 24.694946 6.546524 23512 42.622162 24.561127 5.851333 23513 43.872574 24.026154 4.941437 23514 52.413177 24.107574 6.429603 23515 2.034906 20.507055 5.505318 23516 2.028468 20.764395 6.275310 23517 2.016016 19.758873 6.285183 23518 2.048529 21.118078 4.779766 23519 2.040507 22.090370 5.575901 23520 38.147797 23.669464 5.737983 23521 39.258713 23.175339 5.550995 23522 43.243713 23.265976 5.293640 23523 49.345642 22.934387 6.520553 23524 50.377975 21.825363 6.094703 23525 52.038406 22.848740 5.794364 23526 53.297043 22.925705 6.100868 23527 2.010384 18.518377 7.201472 23528 40.160583 23.091370 5.481361 23529 42.557770 23.378571 5.660293 23530 51.400482 21.570297 5.739440 23531 52.742630 21.224487 5.786232 23532 53.601990 24.040771 7.079711 23533 31.734415 21.509201 6.098175 23534 30.770432 21.328674 9.033524 23535 29.723480 22.271637 10.228735 23536 30.131744 23.125122 8.632637 23537 41.500580 23.591766 5.890525 23538 51.695038 20.631393 5.797561 23539 50.670807 20.430450 6.138931 23540 54.019257 21.944244 6.065704 23541 54.535797 22.915894 6.720832 23542 53.969482 20.936691 6.188202 23543 54.845444 21.471237 6.778579 23544 53.329102 20.198029 6.233840 23545 54.234909 20.055847 7.240303 23546 2.084832 14.290125 8.031399 23547 2.042978 15.951822 7.723424 23548 2.048463 13.792990 9.233622 23549 35.442421 19.247803 6.201660 23550 36.357025 18.196320 6.016586 23551 32.701248 20.353470 7.284835 23552 33.695038 20.283508 6.368873 23553 33.754143 19.254120 7.578186 23554 52.157715 19.755981 6.362937 23555 2.149179 13.712093 7.408236 23556 2.168387 12.117969 7.946022 23557 2.119675 12.292934 8.664204 23558 2.126913 10.998583 9.749403 23559 2.373926 11.691416 5.655544 23560 34.674362 13.023987 4.602036 23561 33.774719 12.895004 5.126831 23562 34.124008 13.696625 5.353088 23563 35.110168 14.824326 6.514740 23564 35.459831 15.571350 6.711998 23565 2.262555 10.983918 7.145129 23566 2.228801 11.398860 6.984360 23567 2.273223 10.229397 7.331442 23568 2.374892 10.756593 5.999259 23569 34.515755 11.842407 4.790405 23570 33.669662 12.287811 5.350632 23571 2.367184 9.460175 6.474640 23572 33.580917 11.669525 6.206619 23573 35.408844 10.629425 5.073502 23574 34.513565 10.916367 5.942619 23575 36.631340 9.577560 6.067184 23576 35.357590 10.301178 5.937118 23577 38.326920 9.127747 5.031601 23578 40.060516 8.530228 4.628365 23579 39.439064 8.233032 5.079895 23580 41.244446 9.163330 3.807983 23581 40.706070 8.607727 4.160477 23582 40.253220 7.475662 4.674263 23583 51.769287 5.991272 4.896240 23584 52.676865 6.613831 5.423721 23585 51.448792 7.032898 5.678833 23586 52.709045 7.875153 5.893371 23587 50.865814 5.751534 5.295143 23588 51.842529 5.144501 4.886429 23589 52.532257 5.655518 5.144386 23590 53.702850 7.331360 6.507263 23591 53.734772 8.467743 6.281311 23592 53.418457 5.638435 6.482116 23593 40.731857 6.141602 4.205307 23594 39.319687 7.356064 5.416473 23595 39.707016 7.330383 5.132530 23596 39.377213 3.562683 5.686737 23597 38.609283 3.754906 5.357468 23598 40.235443 3.789688 5.672332 23599 42.615341 4.672050 4.512909 23600 51.304077 5.251709 4.879364 23601 51.095169 4.410042 5.418137 23602 49.613708 4.383881 6.372756 23603 50.252487 3.330841 5.883476 23604 52.525803 4.689758 5.497772 23605 52.376160 3.582993 5.822319 23606 2.303762 6.325267 5.732657 23607 38.461105 4.601410 5.137413 23608 37.928276 3.958298 5.396362 23609 43.757965 4.359230 4.559509 23610 45.073380 3.513199 4.256897 23611 45.057129 2.460052 4.504555 23612 44.975616 -0.324203 5.447525 23613 58.227524 0.754318 4.817200 23614 2.541475 2.021770 5.297124 23615 54.994339 0.333405 3.487267 23616 56.242142 -0.243179 5.136520 23617 2.405920 2.929635 4.963235 23618 2.310632 3.772780 5.758032 23619 59.904831 -1.036621 5.347496 23620 60.292740 -1.076614 5.901123 23621 59.748489 -0.586182 6.329727 23622 3.051537 -1.966220 4.995544 23623 59.427277 -0.665924 4.769653 23624 43.885239 -3.502441 5.665908 23625 58.026413 -2.889648 3.929588 23626 40.118851 -4.051010 3.882393 23627 40.963135 -4.111633 4.121079 23628 41.821457 -3.985565 4.236015 23629 53.123138 -3.662689 5.359619 23630 59.430618 -3.360123 4.483826 23631 59.667831 -4.106155 4.002640 23632 59.959778 -2.932205 5.072083 23633 60.277466 -3.939484 5.158447 23634 60.264313 -4.834885 4.208298 23635 3.677217 -6.231037 3.617880 23636 41.712311 -6.564941 3.349854 23637 40.861862 -8.019135 4.966324 23638 40.253494 -6.665710 3.755089 23639 42.389160 -7.020721 3.849609 23640 42.559082 -6.716873 3.489876 23641 3.318361 -6.455764 5.459061 23642 58.320908 -7.482803 5.010544 23643 57.479111 -7.963898 5.030159 23644 44.438629 -9.094635 4.319611 23645 50.696686 -7.717743 3.978958 23646 56.359024 -8.406433 5.383820 23647 49.846771 -9.171799 4.533112 23648 54.805161 -9.167221 5.753631 23649 3.805513 -9.273764 4.669277 23650 49.517807 -10.271988 3.784851 23651 49.095718 -11.363220 3.536415 23652 54.307281 -9.943085 5.109787 23653 54.028290 -9.689514 5.753509 23654 3.991087 -10.262313 4.390156 23655 55.172424 -11.029327 3.958023 23656 55.068008 -10.404144 3.939987 23657 55.835693 -11.370209 3.867081 23658 55.697845 -11.701172 4.610848 23659 43.520370 -11.563644 4.210022 23660 42.763519 -12.202408 5.217651 23661 4.254073 -12.178358 4.771805 23662 41.448364 -13.876846 4.834137 23663 42.084518 -13.278000 4.194786 23664 46.841705 -14.024017 4.678970 23665 40.642517 -14.402008 4.618866 23666 57.629562 -15.408066 3.986549 23667 4.893227 -14.520076 3.922690 23668 46.278809 -15.445999 3.491394 23669 56.641495 -16.483109 3.874512 23670 5.183333 -15.522344 3.655171 23671 43.970581 -17.051987 2.834580 23672 45.279510 -16.062790 3.798126 23673 54.606033 -17.313080 2.962463 23674 53.891312 -18.042740 3.107391 23675 60.939117 -15.309708 5.269638 23676 5.428080 -16.289295 3.425190 23677 5.689404 -17.045647 3.330903 23678 5.360146 -16.372490 4.099442 23679 38.331848 -17.203888 2.963974 23680 41.780151 -19.138351 4.411766 23681 41.780212 -19.649963 3.024811 23682 55.010208 -17.823578 3.481690 23683 57.242310 -16.467484 4.524155 23684 57.309082 -17.839233 4.726402 23685 5.906641 -17.844416 3.733962 23686 6.129922 -18.321623 3.370937 23687 37.960617 -18.411880 3.061432 23688 38.593887 -16.507675 4.302361 23689 6.554285 -19.437052 3.782404 23690 37.490128 -20.204941 2.811569 23691 37.248672 -19.550156 4.055222 23692 41.407516 -20.367584 3.501183 23693 41.135834 -21.053101 2.960014 23694 7.131814 -20.105230 2.140875 23695 6.911002 -20.018690 3.262539 23696 36.746567 -21.639130 2.605530 23697 36.369263 -21.614532 3.101273 23698 36.696526 -21.220627 2.823746 23699 37.001740 -20.895203 2.843277 23700 36.502007 -22.107346 3.139542 23701 37.273605 -23.041245 4.252564 23702 40.220612 -21.883453 2.971817 23703 40.697296 -21.561340 2.970291 23704 7.969418 -21.437424 1.629070 23705 8.278482 -22.040283 2.112787 23706 8.718618 -22.425297 1.244527 23707 8.778764 -22.761599 2.154551 23708 10.176270 -24.415661 2.218539 23709 10.259395 -24.625654 2.863267 23710 47.441864 -24.770752 3.065582 23711 47.059906 -25.334244 2.605682 23712 52.026001 -25.132950 2.524414 23713 50.751999 -25.011353 2.265320 23714 53.085068 -24.723557 2.573349 23715 56.027588 -24.633331 2.488724 23716 55.251709 -25.427856 2.937500 23717 56.778854 -24.453430 2.028038 23718 46.853195 -25.338821 3.031174 23719 55.939178 -25.285431 2.836517 23720 56.444534 -25.799332 2.595352 23721 9.858341 -23.876776 1.477538 23722 9.289160 -23.380476 2.040796 23723 9.649763 -23.912386 2.562758 23724 46.853058 -26.117538 2.637169 23725 46.742783 -25.715210 3.697662 23726 47.218094 -26.235458 4.871506 23727 47.546143 -25.257462 4.440247 23728 50.340103 -26.163116 2.464455 23729 51.488007 -26.412933 2.947403 23730 50.568115 -27.141525 2.921814 23731 46.234528 -27.513702 2.668854 23732 47.445023 -28.241257 2.471039 23733 46.461670 -29.001053 2.419983 23734 47.791901 -27.025177 2.285469 23735 48.885651 -28.343887 2.777725 23736 56.415894 -26.917450 2.910446 23737 45.068237 -28.481247 2.729538 23738 43.908203 -29.334625 2.675430 23739 45.279114 -29.683655 2.198982 23740 47.842194 -29.442734 2.607010 23741 46.994049 -29.755280 2.447540 23742 42.707199 -29.774139 3.461731 23743 42.252182 -30.986191 3.030914 23744 42.533630 -30.329926 4.071007 23745 42.993652 -30.591461 2.215119 23746 46.403137 -29.968460 2.224411 23747 14.483042 -28.993982 3.173683 23748 42.958511 -29.870239 2.855957 23749 42.339600 -31.178665 2.273407 23750 47.616074 -31.072327 1.845009 23751 48.433228 -30.566269 2.459572 23752 48.665680 -31.235321 1.943863 23753 55.328888 -30.678101 2.194382 23754 15.025032 -29.533062 3.297250 23755 42.285110 -31.887512 2.160156 23756 47.278015 -30.343918 2.268242 23757 49.511551 -30.862030 2.441193 23758 50.422852 -31.169266 2.209595 23759 51.548050 -30.877701 2.519394 23760 53.107025 -30.844498 2.522171 23761 52.238892 -29.716812 3.329193 23762 53.289948 -29.643478 3.393814 23763 54.252335 -31.071625 2.262230 23764 54.912750 -31.086792 2.139313 23765 31.222595 -33.895233 1.724671 23766 30.674988 -34.083450 2.196152 23767 31.084579 -34.486740 2.315277 23768 30.172329 -33.974552 1.425466 23769 15.718851 -30.808504 4.276806 23770 18.998409 -33.184395 3.741121 23771 20.148125 -32.926796 2.708617 23772 21.182981 -33.970387 3.030098 23773 29.502617 -35.427704 1.499817 23774 30.105896 -34.836456 2.129288 23775 31.151367 -34.976059 2.266014 23776 16.270615 -36.916992 2.524841 23777 27.655947 -35.177708 1.358505 23778 28.811134 -36.329132 1.589844 23779 30.834869 -35.420074 2.062828 23780 43.131577 -35.705841 2.616791 23781 44.249786 -35.703827 2.009903 23782 42.203461 -35.379593 3.174423 23783 45.597870 -35.920273 2.194046 23784 46.907852 -36.119385 2.137207 23785 20.891136 -37.264450 1.323731 23786 28.560837 -37.267960 1.365959 23787 29.422012 -36.797333 1.213104 23788 30.000587 -35.911438 1.751961 23789 50.372894 -37.129623 1.760941 23790 50.482193 -36.833893 2.482971 23791 61.057083 -37.135773 3.163811 23792 60.189056 -37.376831 3.551003 23793 63.726807 -36.626526 2.500031 23794 63.011826 -36.787048 3.096665 23795 64.307709 -36.696548 1.925568 23796 64.518524 -37.380981 2.422928 23797 27.833496 -37.281021 2.104553 23798 51.349167 -37.100922 2.589279 23799 52.453918 -37.735458 1.914414 23800 52.478775 -37.006073 3.111115 23801 52.496521 -38.489548 1.269638 23802 64.809204 -39.146301 2.440155 23803 65.460037 -39.253510 3.396362 23804 65.070984 -38.910248 3.615593 23805 53.778992 -37.661148 1.996201 23806 54.746460 -37.549316 2.033325 23807 10.771729 -41.161377 1.332024 23808 16.481827 -40.673096 2.151672 23809 16.579636 -40.289810 1.327347 23810 14.898315 -39.481781 2.615158 23811 15.797691 -40.543869 2.619423 23812 64.079651 -39.491196 1.491501 23813 12.752922 -40.305435 -0.164848 23814 11.848419 -41.951828 1.890930 23815 17.547668 -41.010986 1.253601 23816 18.450211 -41.903473 1.543503 23817 63.558929 -40.211380 1.696793 23818 63.933365 -40.779312 2.387985 23819 61.025055 -42.549103 2.042023 23820 62.946503 -42.199921 2.493942 23821 19.464493 -43.126938 0.727425 23822 19.442505 -42.855789 1.693588 23823 19.912384 -43.247177 1.269898 23824 60.318344 -43.764908 2.847733 23825 61.220184 -43.473465 2.607590 23826 20.863297 -44.907700 1.280380 23827 20.338577 -44.948654 0.793923 23828 17.059601 -45.239471 1.265381 23829 18.065964 -45.600540 0.833969 23830 54.228668 -44.837357 1.528793 23831 54.784409 -44.604660 1.632752 23832 55.595856 -44.589798 2.404930 23833 18.735428 -46.348846 0.894051 23834 20.583694 -45.732162 0.880974 23835 52.013840 -46.832550 2.594956 23836 52.841797 -45.966492 2.382614 23837 51.778503 -46.076797 1.707436 23838 12.075996 -47.096954 1.829575 23839 11.278282 -46.369247 2.835106 23840 21.071609 -46.648666 1.151001 23841 19.924667 -46.742859 0.890167 23842 22.080376 -46.969757 1.968598 23843 21.167015 -47.900681 1.382172 23844 18.859497 -47.275116 1.454369 23845 19.711990 -47.908966 1.563919 23846 48.991669 -47.625427 0.670776 23847 13.642197 -49.019745 0.506363 23848 51.360504 -47.586151 2.351074 23849 50.938354 -47.104813 1.811501 23850 54.650131 -49.783554 0.911896 23851 51.895996 -48.078674 2.463730 23852 53.086411 -48.475403 2.472237 23853 13.612679 -50.647385 0.879486 23854 15.009644 -51.751205 0.487976 23855 54.493469 -48.936554 2.189270 23856 55.666962 -49.336746 2.013138 23857 16.243607 -51.471085 0.026016 23858 16.227493 -52.702789 0.706230 23859 45.542908 -52.873505 0.874901 23860 17.699097 -52.520752 0.173203 23861 46.978760 -52.231262 0.668991 23862 57.473129 -53.432388 1.493881 23863 56.739471 -52.533020 2.167206 23864 14.916626 -53.355652 0.604508 23865 13.762527 -52.461395 0.673500 23866 13.769150 -53.286011 0.460709 23867 18.891579 -53.490448 0.015534 23868 58.479645 -54.272263 1.410965 23869 18.073997 -53.533020 0.748962 23870 18.253906 -54.374176 0.752915 23871 45.103027 -54.063995 0.903885 23872 57.461548 -53.933945 2.068695 23873 58.104950 -54.754517 2.594421 23874 56.761169 -53.854401 2.663300 23875 13.749069 -53.869324 0.341103 23876 12.972763 -54.588608 0.342041 23877 14.588272 -54.741577 0.448776 23878 13.789993 -55.768280 0.168289 23879 12.778091 -55.739456 0.199974 23880 14.931824 -55.872559 0.459488 23881 50.020172 -55.390991 0.804031 23882 51.633286 -56.141724 0.399559 23883 13.327148 -56.937057 0.247177 23884 12.375519 -56.586075 0.442879 23885 14.706467 -57.168259 0.502922 23886 18.477654 -56.179199 0.418343 23887 18.815346 -57.320694 0.022965 23888 44.740067 -56.133850 0.575989 23889 50.232605 -56.477631 0.831032 23890 51.560242 -57.576569 0.384415 23891 49.890686 -57.321609 0.826973 23892 53.269440 -58.309204 0.004150 23893 59.412506 -55.414902 1.831444 23894 11.444962 -56.917404 1.256722 23895 12.539291 -58.184616 0.907013 23896 44.900696 -57.345673 0.613609 23897 59.712601 -56.951675 1.887650 23898 18.672218 -58.400436 0.112320 23899 49.213684 -59.336746 0.511994 23900 48.017731 -60.096405 0.606384 23901 49.467712 -60.623337 0.223251 23902 50.513855 -58.631500 0.412499 23903 48.806305 -57.911865 0.925392 23904 47.423935 -58.643402 1.023254 23905 17.877579 -60.638474 0.286369 23906 44.640381 -61.215073 -0.306641 23907 46.232025 -61.747406 0.327385 23908 48.723724 -61.687805 0.057976 23909 9.882858 -62.550369 -0.149414 23910 11.945808 -62.793121 0.474579 23911 15.769073 -63.187775 -0.087898 23912 15.580597 -62.823502 -0.552551 23913 47.307510 -61.124542 0.453865 23914 57.332901 -61.948700 0.565834 23915 25.443100 -63.945007 -0.605148 23916 44.891159 -63.076218 -0.612198 23917 45.209412 -62.206329 -0.094093 23918 57.084824 -62.919510 0.251251 23919 14.788422 -63.258591 0.223869 23920 21.892738 -66.212585 -0.914635 23921 24.355103 -64.041290 -0.553986 23922 56.518738 -63.859299 0.701996 23923 7.671112 -65.020264 0.436440 23924 7.171219 -64.290955 1.500008 23925 7.082184 -65.504944 1.266419 23926 8.490952 -64.379303 -0.265518 23927 23.919800 -65.443924 -0.047867 23928 23.844162 -64.541290 -0.424225 23929 22.531296 -66.257980 -0.538689 23930 56.340286 -63.529953 1.840042 23931 56.718979 -63.482529 1.316269 23932 8.058701 -67.625320 -0.407608 23933 21.306580 -66.195801 -1.201920 23934 37.849892 -65.574432 2.071274 23935 37.474632 -66.372086 1.520805 23936 37.711182 -66.527542 2.735581 23937 37.364670 -67.083862 -0.503128 23938 37.191620 -67.052551 0.563797 23939 40.085938 -65.798477 1.297897 23940 41.823196 -66.951630 1.636887 23941 41.122070 -67.404236 0.472885 23942 38.921280 -65.535126 0.977898 23943 54.679306 -66.518265 0.976601 23944 12.780922 -67.290207 -1.838211 23945 26.302177 -66.180008 -0.827827 23946 40.548950 -67.213211 -0.306061 23947 53.931458 -67.914032 0.472450 23948 7.463211 -66.550034 0.278938 23949 25.995834 -67.068771 -0.791985 23950 41.006805 -67.823715 -0.270248 23951 25.876495 -68.213501 -0.902954 23952 38.249489 -68.927185 2.226288 23953 37.468170 -67.752335 1.684151 23954 44.584045 -69.160538 0.456741 23955 46.013550 -68.693390 1.011795 23956 45.691040 -69.610428 -0.020164 23957 41.560486 -68.521820 -0.383346 23958 53.067429 -69.448807 0.594101 23959 9.108658 -68.684967 0.737366 23960 10.264709 -69.859863 -0.215057 23961 10.494598 -70.420837 -1.051651 23962 23.463882 -72.143082 -1.212730 23963 24.027237 -71.259583 -0.989052 23964 24.448441 -68.787491 -0.569679 23965 26.010925 -69.263489 -1.064804 23966 37.924438 -69.930252 -0.387672 23967 45.962585 -70.053772 -0.700180 23968 25.200073 -70.120422 -0.938499 23969 38.761467 -70.347366 1.466126 23970 38.095749 -69.820694 0.690682 23971 49.959015 -70.193192 -0.244049 23972 48.877747 -69.722839 0.546211 23973 51.344162 -70.648056 -0.774780 23974 50.345093 -70.640442 0.998398 23975 51.911758 -70.482880 0.663254 23976 4.963631 -72.150406 -0.162193 23977 5.503922 -72.294739 -0.776054 23978 6.141434 -72.362106 -1.047234 23979 13.901047 -72.303391 -0.970459 23980 7.820823 -73.094177 -1.497742 23981 8.320595 -73.355209 -1.323006 23982 4.552422 -74.900452 -0.905411 23983 8.787285 -73.789124 -1.279816 23984 14.536163 -74.383209 -0.998505 23985 4.644943 -76.115952 -0.434547 23986 4.605583 -77.012909 -1.157684 23987 9.508789 -73.650482 0.148590 23988 14.810402 -75.872879 -1.417221 23989 41.881119 -73.823181 0.067688 23990 47.604340 -74.746811 1.488846 23991 46.716324 -74.676407 2.407257 23992 43.401001 -73.980331 0.037506 23993 47.813705 -74.591568 0.604271 23994 9.047699 -77.357025 -1.669121 23995 9.654968 -76.154526 -1.568954 23996 11.859940 -75.734436 -0.808846 23997 11.113586 -76.781921 -1.556076 23998 14.793571 -76.712173 -1.526756 23999 48.140366 -76.692551 -0.543472 24000 4.603996 -79.134064 -1.302612 24001 8.318817 -77.426254 -1.636490 24002 10.011772 -77.017685 -1.622307 24003 36.936653 -77.757156 -0.976234 24004 37.712158 -77.924011 -0.788147 24005 38.985313 -77.955704 -0.818131 24006 41.577820 -77.611008 -0.687027 24007 41.049835 -78.072617 -0.062401 24008 42.052460 -77.935135 -1.454315 24009 42.932617 -77.678619 -0.575089 24010 48.398834 -76.352234 -0.360565 24011 4.603340 -80.132599 -1.093590 24012 4.631386 -80.925064 -1.698723 24013 7.771980 -78.797012 -2.562416 24014 8.326218 -77.718887 -1.669983 24015 8.425446 -78.005264 -1.940666 24016 22.002426 -78.380173 -1.420540 24017 43.770721 -77.651093 -0.056854 24018 22.524231 -78.857681 -1.624092 24019 34.884903 -80.729965 -0.514236 24020 4.849999 -80.871445 -0.808731 24021 5.411659 -82.772156 -0.910423 24022 6.067284 -84.719818 -1.903687 24023 6.264229 -85.261154 -2.948463 24024 33.102425 -83.980347 -0.291855 24025 34.090240 -83.499390 0.460709 24026 33.320816 -82.656967 -0.125229 24027 7.169922 -86.392044 -1.769829 24028 17.533279 -85.951492 -2.886436 24029 33.703491 -86.275314 -0.625977 24030 33.315948 -85.509476 -0.519745 24031 35.730209 -87.086166 -1.743980 24032 7.584633 -87.684631 -2.209259 24033 36.349594 -88.479858 -1.338318 24034 38.351822 -88.449493 -1.650208 24035 35.333939 -88.387375 -1.044411 24036 34.777161 -87.369232 -1.194603 24037 39.167114 -88.478653 -1.804878 24038 14.252228 -89.543396 -1.324142 24039 13.767426 -89.361115 -0.334564 24040 14.332413 -89.073898 -0.307312 24041 39.147278 -89.331604 -1.719521 24042 9.697739 -90.184952 -2.189163 24043 14.971420 -90.803711 -2.189178 24044 15.906815 -90.279724 -0.764587 24045 15.804718 -91.274124 -1.886032 24046 15.364128 -92.124039 -2.625168 24047 16.639778 -91.744217 -1.413590 24048 16.754196 -90.789902 -0.220894 24049 23.320892 -92.005661 -1.970428 24050 23.695602 -91.159271 -1.772285 24051 38.961922 -90.505692 -1.570023 24052 22.957916 -91.642731 -1.044128 24053 23.254456 -93.045883 -1.553452 24054 24.954765 -90.468033 -1.361511 24055 26.014297 -91.507294 -1.555511 24056 16.572083 -93.327911 -2.508141 24057 23.774292 -90.221085 -1.314392 24058 17.891113 -91.939819 -0.292976 24059 17.976105 -92.456558 -0.089531 24060 17.735504 -92.744217 -1.173630 24061 23.473572 -94.107224 -2.529373 24062 27.506210 -93.891357 -1.781647 24063 18.458405 -94.291733 -1.337441 24064 18.681061 -95.419357 -1.659157 24065 23.887177 -95.474442 -2.419434 24066 23.684380 -94.550385 -1.285858 24067 28.627144 -93.504623 -0.727982 24068 24.296112 -96.454910 -2.417999 24069 34.512253 -96.257812 -1.535500 24070 32.549515 -97.635834 -1.675674 24071 25.276947 -100.086395 -2.376839 24072 24.624306 -100.779358 -1.318543 24073 29.352615 -97.758041 -2.269417 24074 17.488281 -99.855515 -2.618332 24075 18.254623 -99.219345 -1.963570 24076 17.543816 -99.281403 -1.124359 24077 16.098389 -100.718628 -1.810761 24078 15.171371 -101.397827 -1.075699 24079 15.405991 -101.706848 -1.586327 24080 15.873276 -102.034683 -2.147011 24081 24.677605 -101.145813 -2.893372 24082 22.356789 -102.536880 -2.842140 24083 21.992622 -102.848831 -1.712952 24084 18.293381 -102.995224 -2.344650 24085 21.656815 -102.632248 0.304817 24086 21.376183 -102.970871 -0.864548 24087 19.898834 -102.795349 0.133988 24088 9.830414 65.448120 9.014725 24089 10.542793 65.709549 9.671570 24090 11.310638 66.079559 9.469833 24091 11.786697 66.354355 9.430283 24092 11.896278 65.685486 8.549133 24093 8.878433 64.659424 9.285187 24094 16.139122 63.733856 8.713074 24095 17.417252 63.476822 10.185623 24096 16.789452 63.919342 9.762253 24097 18.094749 62.737015 9.317833 24098 19.925461 61.718170 8.438919 24099 21.007309 61.739288 9.212662 24100 7.380425 60.371933 8.940308 24101 6.397148 59.793289 8.181297 24102 24.637360 60.812439 8.999207 24103 26.425468 60.337631 9.534958 24104 27.093987 59.856140 9.292572 24105 26.952759 59.880508 10.582237 24106 25.509285 60.794479 9.522263 24107 26.732315 59.687592 8.159996 24108 6.826096 58.555954 7.696731 24109 8.024414 57.605652 7.684524 24110 8.552429 58.421967 8.644081 24111 26.237595 55.475433 8.293808 24112 10.809998 55.015045 9.781921 24113 10.543640 54.022552 8.812668 24114 31.853914 55.282074 9.231483 24115 33.014191 55.643677 9.104431 24116 32.505081 55.887238 9.625534 24117 10.818192 53.175720 7.907669 24118 24.130554 52.663574 7.687942 24119 29.704498 53.017593 8.574593 24120 7.969741 53.761292 9.448700 24121 9.471680 51.155121 7.601287 24122 5.395134 54.943115 10.164978 24123 5.115021 52.896606 9.129677 24124 9.933411 52.924622 8.373795 24125 4.823746 51.636932 8.229950 24126 4.687309 50.490860 7.810714 24127 5.408280 51.075653 7.845077 24128 5.188843 48.870483 7.380645 24129 10.283722 51.734482 7.498809 24130 10.691605 52.404709 7.572654 24131 29.143379 52.285126 9.114632 24132 34.422775 52.956192 9.247849 24133 34.549973 51.256516 8.967758 24134 3.992912 49.268875 9.046204 24135 4.181366 49.819641 7.990036 24136 4.002922 51.347961 9.269852 24137 4.555313 49.572128 7.489135 24138 4.384422 49.015015 7.589683 24139 23.120590 52.049133 8.948746 24140 22.395248 50.352753 9.035706 24141 22.673889 51.207367 9.921249 24142 28.708481 51.499466 9.040688 24143 4.098091 49.000153 8.016373 24144 22.344040 49.315216 7.876770 24145 26.655289 48.760437 8.293762 24146 26.971802 49.238617 8.675613 24147 26.679810 48.841553 8.748108 24148 27.444206 49.737976 8.553658 24149 5.132660 46.986633 6.993637 24150 21.712830 47.931274 8.035294 24151 26.567909 48.029968 7.782043 24152 38.264679 48.390961 8.420013 24153 38.899559 47.883636 8.035278 24154 39.484863 49.100159 8.759323 24155 40.871597 48.825150 9.118484 24156 39.963287 47.714478 8.099716 24157 41.585541 47.213181 8.539053 24158 4.793289 47.536926 7.492080 24159 4.140183 47.977417 8.127563 24160 35.335007 47.311707 8.636024 24161 35.407219 48.752014 8.988693 24162 4.274094 45.950150 6.905838 24163 4.372551 46.842224 7.537994 24164 21.248672 46.859695 8.607346 24165 26.097275 47.418777 8.027328 24166 25.839958 46.934753 8.026810 24167 34.037262 46.455139 7.401535 24168 35.856171 46.354980 8.162476 24169 36.197937 47.166504 8.561752 24170 37.987144 47.463898 8.017075 24171 37.080727 46.723038 7.994201 24172 42.113586 44.452255 8.240692 24173 41.559677 43.033508 8.518204 24174 43.309723 43.164688 8.761528 24175 22.475212 44.331589 8.301109 24176 36.955261 48.112823 8.647247 24177 43.007538 46.521454 8.960968 24178 42.316635 45.729980 8.262779 24179 43.517120 45.110596 8.850037 24180 3.736458 47.885757 9.536377 24181 3.521980 47.353622 8.934219 24182 3.994927 43.321777 7.345901 24183 3.462761 44.454086 7.864242 24184 3.576180 44.902832 6.763496 24185 40.961914 44.195053 7.905616 24186 44.636276 43.839737 9.286942 24187 3.964645 44.196075 8.913727 24188 40.284592 43.453613 8.001656 24189 4.601875 42.942291 7.541168 24190 5.349014 42.770752 7.488708 24191 6.326164 43.334717 8.632622 24192 13.095299 41.850174 8.152374 24193 12.032700 42.443588 8.346642 24194 36.481323 41.595062 7.031402 24195 37.078751 42.162216 7.194389 24196 36.839874 41.383240 7.499702 24197 37.358025 41.711121 7.763504 24198 14.305237 40.516968 7.035812 24199 15.526443 39.577316 7.811409 24200 15.548630 40.155945 9.153297 24201 15.508270 38.979767 8.087708 24202 3.918816 37.221512 6.929870 24203 5.352593 38.563004 7.805313 24204 7.016533 38.166824 7.810585 24205 14.815178 37.969421 7.051742 24206 14.344727 37.935333 8.142715 24207 14.243866 37.513092 6.975204 24208 15.206787 38.824097 7.186935 24209 36.456589 38.392273 7.589859 24210 48.199326 37.922195 7.443649 24211 48.664795 37.875641 8.598648 24212 8.297447 37.875488 7.565261 24213 36.228424 36.484436 7.975326 24214 51.298233 37.476959 8.640854 24215 50.227692 37.908066 8.705627 24216 9.187775 37.983185 8.001480 24217 12.428604 37.523178 8.077911 24218 11.561981 37.524048 7.901878 24219 36.591118 37.544067 8.281548 24220 46.313507 36.593018 7.741226 24221 45.582275 36.124420 7.551300 24222 37.290009 34.732178 7.518539 24223 43.173553 35.152130 7.418899 24224 44.518066 35.543365 7.464477 24225 52.932831 35.086456 7.646133 24226 5.255379 32.563812 7.430465 24227 5.322685 31.811798 7.580703 24228 39.044189 34.370087 7.287818 24229 38.310806 34.217239 7.919212 24230 41.651306 34.763992 7.598396 24231 39.924622 34.321259 7.807373 24232 52.824677 32.472000 6.934669 24233 4.846367 31.274841 7.209770 24234 52.856873 30.350311 8.173882 24235 52.828140 31.141998 7.772865 24236 52.073334 29.930115 7.443099 24237 46.198807 28.300751 6.750122 24238 42.195435 28.382126 7.602630 24239 43.080505 28.749496 6.839454 24240 2.391870 26.509151 7.027346 24241 2.268835 26.273781 6.218933 24242 39.668396 26.998688 7.922866 24243 44.956604 28.059631 7.233200 24244 45.711487 26.313965 8.317123 24245 2.149199 22.224081 7.820531 24246 2.055811 21.135221 7.044778 24247 2.146525 23.250614 6.728900 24248 32.641808 25.816376 6.452774 24249 41.400238 26.307983 6.841354 24250 41.899994 26.216217 6.340156 24251 47.609680 25.167526 7.328628 24252 2.065921 22.285786 6.143932 24253 2.123223 24.972319 5.485936 24254 34.235168 25.197876 7.002426 24255 33.054886 25.659592 7.525871 24256 51.678101 26.047745 8.155075 24257 35.629074 24.612442 6.737426 24258 36.372635 24.196838 6.707855 24259 41.273407 25.243347 6.687835 24260 48.577026 24.404160 6.751709 24261 48.203278 23.656372 7.271331 24262 47.522308 23.611649 7.881027 24263 55.042358 23.824753 7.979751 24264 54.605759 25.113785 8.894150 24265 53.632507 24.718262 8.084076 24266 54.748993 27.414902 11.359116 24267 54.104172 27.822021 11.730385 24268 54.214554 26.935150 10.735870 24269 1.997068 19.745440 7.652221 24270 36.973038 23.951172 6.489288 24271 37.513489 24.067932 7.158432 24272 38.515137 23.896973 6.879867 24273 39.271774 24.411560 7.117393 24274 38.377495 24.413666 7.503562 24275 38.908081 25.113235 7.685751 24276 39.292450 23.603546 6.257507 24277 55.295334 22.531601 7.257034 24278 30.325241 23.207291 7.206352 24279 40.272400 24.233612 6.586813 24280 55.517944 21.510376 7.489547 24281 55.780090 22.388626 8.126572 24282 32.657166 20.902847 6.248847 24283 49.506989 21.225159 6.542572 24284 34.530365 19.722839 6.475448 24285 49.801895 19.515472 6.594452 24286 48.870544 20.286255 6.904220 24287 48.472794 19.136932 7.296943 24288 49.706207 20.324677 6.445509 24289 55.177933 20.646088 7.691162 24290 55.680222 20.966690 8.300667 24291 35.620956 18.361191 6.812240 24292 50.871750 19.220169 6.559768 24293 50.221436 18.602066 7.330627 24294 51.520340 18.854553 7.298385 24295 53.245651 19.433167 7.142524 24296 53.292206 19.721619 6.593444 24297 52.505035 19.142105 7.561149 24298 37.114975 17.304855 5.430901 24299 2.176845 10.265761 9.130449 24300 2.127590 12.831081 11.578627 24301 2.271376 13.135157 12.728949 24302 2.142564 9.507954 11.980139 24303 34.501587 14.341827 6.129928 24304 33.387177 13.958954 6.285621 24305 33.926666 14.664154 7.034790 24306 33.365501 13.341721 5.650787 24307 34.603622 14.758133 6.818588 24308 2.243265 9.659569 7.987292 24309 32.560646 13.471176 7.050766 24310 33.001724 13.363724 6.131942 24311 33.188705 12.687103 6.018463 24312 44.176483 12.530624 6.268768 24313 43.181885 12.245026 6.462989 24314 44.023636 11.311707 5.951080 24315 43.662109 13.508148 7.117424 24316 46.561829 12.896057 6.885872 24317 45.951355 13.040771 6.934684 24318 46.116333 11.979568 6.211227 24319 47.191162 11.839600 6.087974 24320 47.102570 12.430344 6.437942 24321 45.072693 13.072784 6.870544 24322 47.566528 12.744675 7.240806 24323 47.959015 11.880249 6.544815 24324 2.223075 8.866233 8.753736 24325 47.064270 10.922073 6.220008 24326 46.180588 9.957932 6.291748 24327 43.618011 9.891449 5.964767 24328 44.367920 8.774963 6.039528 24329 44.966385 10.323090 5.870948 24330 47.615570 11.346497 6.238159 24331 44.912292 11.961777 6.052276 24332 47.995422 10.716721 6.921936 24333 48.932693 11.669373 7.100288 24334 35.141235 10.221863 6.993087 24335 36.005096 9.773102 7.368751 24336 47.149231 9.990570 6.761993 24337 43.511703 8.103546 6.501564 24338 43.153732 8.904099 6.259315 24339 42.207626 8.331238 7.215088 24340 45.341812 9.099380 6.107307 24341 52.484161 8.643845 6.096809 24342 53.096252 8.776825 6.060829 24343 52.491974 9.351257 6.434036 24344 53.517349 9.775909 6.523063 24345 38.266434 7.586136 6.040908 24346 44.634705 7.849350 6.822471 24347 45.309891 8.399063 6.598266 24348 45.899948 8.889435 6.689911 24349 51.482666 8.623566 6.656753 24350 54.399826 9.367157 6.825088 24351 54.292953 8.387695 6.873214 24352 50.235260 6.442749 6.307159 24353 50.102585 5.399200 6.018310 24354 37.710968 4.496170 5.682144 24355 38.131592 5.184792 5.666381 24356 37.338058 3.795410 6.141899 24357 43.443176 3.949310 5.603607 24358 42.295029 3.991501 5.981468 24359 44.443237 3.744942 4.938416 24360 44.168335 2.962799 6.057182 24361 51.421280 2.867188 5.972564 24362 37.975502 3.475807 5.695083 24363 43.157181 3.497467 6.561813 24364 52.973206 2.222534 6.975898 24365 53.371887 3.814178 6.495666 24366 2.235079 5.212452 6.780081 24367 2.266665 6.759737 6.840618 24368 44.623001 1.791168 5.846420 24369 58.383408 0.907196 5.337326 24370 58.405899 0.955765 5.563294 24371 58.196533 0.743637 5.553948 24372 58.564590 0.740891 5.538117 24373 57.364624 0.077484 5.645751 24374 59.133286 0.052643 5.480087 24375 44.529556 -1.977814 5.891784 24376 56.228622 -0.666306 5.598328 24377 59.993942 -2.097275 5.149880 24378 60.426407 -1.836441 5.767822 24379 59.480988 -2.582932 4.746132 24380 60.356522 -2.746262 5.564423 24381 42.554718 -4.599731 4.839264 24382 2.893853 -4.340034 6.744588 24383 3.089170 -5.127680 6.032456 24384 40.615768 -5.022537 4.480835 24385 41.737610 -4.885651 4.758667 24386 43.496368 -4.218643 5.787841 24387 43.108246 -4.671799 5.457733 24388 52.344360 -4.827042 5.384796 24389 3.229216 -5.034431 5.246110 24390 39.951790 -6.238495 4.573059 24391 42.586578 -5.253067 5.623062 24392 42.579727 -7.637466 4.528305 24393 59.294281 -6.643066 5.943923 24394 60.394302 -5.000381 6.136322 24395 3.471929 -7.993008 5.591342 24396 39.964256 -7.305450 4.582642 24397 41.645508 -8.111969 5.413437 24398 43.688339 -7.740280 4.100113 24399 40.239014 -7.898407 5.068924 24400 51.749359 -5.819290 6.083465 24401 50.996155 -6.748352 6.109192 24402 50.644516 -7.519714 5.000565 24403 49.925720 -8.211319 6.370681 24404 3.551015 -9.221241 6.114251 24405 3.837674 -10.289534 5.312691 24406 44.471741 -9.739960 4.211929 24407 44.125488 -9.654449 4.758255 24408 50.432297 -7.500168 6.152854 24409 50.561035 -7.178497 7.512069 24410 49.115372 -10.640091 4.496002 24411 62.076996 -10.625168 6.064346 24412 60.578751 -10.539825 6.012785 24413 60.845184 -10.562073 5.140152 24414 61.942261 -10.663727 7.535797 24415 60.704758 -10.453186 7.685104 24416 60.758270 -10.507599 6.893867 24417 62.421204 -10.790604 4.723587 24418 63.075424 -11.168381 5.586517 24419 43.592819 -10.666214 5.395676 24420 48.694016 -11.495316 4.090607 24421 48.561188 -10.653381 5.248596 24422 54.450089 -11.343063 4.585518 24423 53.873398 -10.876404 5.028435 24424 54.642502 -10.523682 4.452805 24425 54.498535 -11.937027 5.007286 24426 59.641037 -10.846451 4.667351 24427 53.833740 -11.646774 5.034363 24428 55.479950 -12.338608 5.960739 24429 56.156525 -12.493103 7.085571 24430 55.544617 -12.978256 7.158126 24431 56.956757 -11.972870 6.820358 24432 57.333054 -11.671173 5.631225 24433 58.424423 -11.299377 6.944107 24434 64.033173 -13.141190 4.555527 24435 64.035873 -13.566101 4.493065 24436 64.182465 -13.409683 4.748772 24437 4.605661 -14.661722 6.074950 24438 4.858480 -15.542616 5.902483 24439 4.940029 -15.281737 4.863985 24440 58.933472 -15.264893 4.509239 24441 63.607193 -14.151871 4.787430 24442 64.028046 -13.592163 4.903153 24443 39.447578 -15.822250 3.738297 24444 58.029922 -16.333893 5.084183 24445 59.207489 -15.682617 5.513573 24446 59.837967 -15.848846 6.301078 24447 62.443405 -14.908249 6.335784 24448 62.650848 -15.061737 4.827026 24449 46.183899 -15.609024 4.075882 24450 46.554504 -15.032120 4.286697 24451 55.606018 -16.933868 3.338638 24452 63.107574 -14.606735 5.663032 24453 63.494843 -14.055099 5.939849 24454 6.144224 -18.719772 4.595765 24455 43.644897 -16.808289 4.903504 24456 58.262497 -17.553833 5.516548 24457 54.737381 -18.790787 3.786026 24458 55.720688 -19.364319 4.139824 24459 56.099731 -18.237808 4.036072 24460 5.664925 -17.498629 4.616033 24461 42.507904 -17.965103 4.890503 24462 41.557266 -17.867935 6.628601 24463 40.641846 -19.216660 6.143142 24464 49.644928 -23.128479 4.263298 24465 50.638824 -22.587967 4.571762 24466 50.107086 -22.006042 3.694542 24467 53.483032 -18.776901 3.360809 24468 53.833099 -19.507019 3.839584 24469 54.810547 -20.377869 4.447281 24470 56.909393 -19.376984 4.494392 24471 56.330002 -19.304398 4.218231 24472 40.992752 -20.378143 4.436356 24473 56.150742 -20.201233 4.520607 24474 57.175461 -21.061523 4.952377 24475 58.479370 -21.114197 4.980820 24476 58.136978 -19.534775 4.923943 24477 36.458252 -20.961136 3.714974 24478 36.107437 -22.097290 3.767754 24479 35.719788 -21.645798 4.196915 24480 41.022842 -21.116318 3.577301 24481 51.201263 -21.959030 4.376312 24482 61.549591 -21.058472 4.485001 24483 60.718872 -21.521210 4.538788 24484 61.825897 -21.956375 4.190689 24485 60.245209 -20.296707 5.112984 24486 62.655350 -21.301010 4.388069 24487 63.480759 -21.566605 4.579163 24488 63.442642 -20.947372 5.057510 24489 62.251282 -20.328705 5.196793 24490 63.296326 -22.304108 4.334747 24491 63.740326 -23.307037 4.215912 24492 64.233612 -23.077637 4.917099 24493 7.535379 -20.821171 2.021967 24494 7.329559 -20.778721 3.273349 24495 7.783682 -21.386858 2.541348 24496 7.925509 -21.789658 3.354924 24497 35.574280 -22.312027 4.437546 24498 36.581726 -22.589279 3.692284 24499 40.159912 -21.710648 4.066605 24500 38.679558 -22.731110 4.032982 24501 62.256195 -23.071716 4.096283 24502 64.252747 -21.987335 5.744354 24503 36.128044 -22.917755 4.649498 24504 39.767319 -21.433289 5.402336 24505 40.348785 -20.631042 5.141724 24506 39.929726 -20.503052 5.926780 24507 51.136047 -21.221756 3.711731 24508 48.799789 -23.335648 3.520783 24509 63.365662 -20.143051 5.820961 24510 64.181839 -20.758530 6.168853 24511 8.440928 -22.495708 3.025071 24512 8.973385 -23.211016 3.058348 24513 48.487183 -24.358459 4.290856 24514 60.145157 -23.946915 4.852516 24515 61.715179 -25.015503 4.311585 24516 61.994995 -24.074478 4.145905 24517 63.545990 -24.084503 4.118454 24518 64.289139 -24.050720 4.908447 24519 8.172915 -22.972042 6.003317 24520 8.497728 -23.664473 6.392826 24521 9.072390 -23.849798 4.893228 24522 10.361497 -24.993921 3.713223 24523 11.666314 -26.209764 3.178989 24524 47.254395 -25.000839 3.704865 24525 53.979584 -25.375504 2.996430 24526 64.166824 -25.020203 4.624413 24527 63.274689 -24.866943 4.069115 24528 9.399209 -23.874794 3.688265 24529 46.040955 -26.633530 3.609886 24530 52.977890 -26.167328 3.183983 24531 54.276505 -26.883194 3.552796 24532 59.033249 -27.489578 5.672271 24533 58.793610 -27.997726 5.790359 24534 60.114441 -28.692505 4.933113 24535 63.534088 -25.921631 4.221176 24536 64.350128 -26.016205 5.227951 24537 64.290878 -26.886261 4.516487 24538 44.856018 -27.687210 3.484482 24539 44.284271 -28.386963 3.071976 24540 51.397720 -28.209137 3.414757 24541 50.159302 -27.959793 3.043045 24542 52.366180 -27.279922 3.435135 24543 54.982971 -27.897690 3.620789 24544 55.284393 -27.020279 3.422485 24545 55.929337 -26.701645 3.076630 24546 59.443558 -24.924515 5.326157 24547 59.227737 -26.496124 5.491051 24548 61.518494 -26.149521 4.396820 24549 63.249191 -27.453110 3.929321 24550 43.812561 -28.529510 3.514267 24551 61.910858 -28.278625 3.965424 24552 61.715729 -29.283585 4.086205 24553 61.314514 -27.337936 4.328186 24554 62.875397 -28.972870 3.694290 24555 64.386169 -28.014725 4.413635 24556 63.907227 -28.587845 3.788513 24557 64.279617 -28.827667 4.027603 24558 12.536777 -27.159536 3.233450 24559 13.270781 -28.062313 3.529819 24560 43.219131 -29.204636 3.322975 24561 49.289078 -29.805725 2.886688 24562 55.071930 -29.314117 3.151260 24563 55.081223 -28.567337 3.510254 24564 62.451813 -29.982040 3.925354 24565 14.177861 -28.949404 3.571223 24566 14.845771 -29.795511 3.963779 24567 50.283630 -29.068039 3.272301 24568 50.421890 -30.280136 2.984795 24569 54.184555 -30.083954 3.021744 24570 54.989334 -30.435364 2.618485 24571 54.130692 -28.613495 3.613548 24572 63.058548 -29.694305 3.693199 24573 63.694138 -29.332367 3.815796 24574 64.191986 -29.162888 4.632538 24575 63.356094 -30.055771 4.098305 24576 64.086227 -29.129303 6.141113 24577 63.660919 -30.554138 5.104874 24578 42.011047 -31.676224 4.313843 24579 41.759460 -32.823364 3.093643 24580 51.223175 -29.704117 3.302780 24581 16.195900 -31.478905 4.551139 24582 16.514315 -31.901381 4.691087 24583 22.915825 -34.500744 2.562356 24584 24.872444 -35.361916 2.301950 24585 30.439148 -35.133667 2.446533 24586 30.654755 -34.603165 2.556702 24587 41.819458 -34.317474 2.968613 24588 18.897266 -34.353947 4.749318 24589 19.611668 -34.432281 4.326296 24590 16.997753 -32.501678 4.829554 24591 20.707302 -35.022442 4.076255 24592 23.371548 -35.158997 2.803635 24593 44.904541 -36.044266 2.893746 24594 45.601654 -36.339691 3.314865 24595 46.556137 -36.753403 3.461052 24596 47.921127 -36.649704 3.309280 24597 14.806854 -37.177521 2.141922 24598 15.384689 -37.232361 4.476318 24599 14.794975 -37.186157 3.378708 24600 18.065308 -37.211807 2.793884 24601 18.824799 -36.913620 1.890755 24602 19.764420 -37.502228 2.570381 24603 26.474789 -36.338371 2.207450 24604 27.868263 -36.933319 2.371536 24605 28.306496 -36.919952 2.039780 24606 43.991119 -36.253433 3.155899 24607 50.560944 -37.201752 3.654190 24608 53.446106 -37.049530 3.021568 24609 54.453827 -37.018311 2.939919 24610 58.256516 -37.212067 3.469498 24611 14.530304 -37.870316 1.960846 24612 21.307938 -37.819687 2.338936 24613 22.458298 -38.259918 2.375595 24614 26.826477 -37.610184 2.296265 24615 26.319809 -38.115601 2.134537 24616 27.266830 -37.435791 2.152527 24617 23.478806 -38.635605 2.387009 24618 64.416809 -38.171982 3.587471 24619 24.506203 -38.489883 3.569901 24620 65.073120 -40.214890 3.138321 24621 65.438583 -39.560547 3.160820 24622 9.475051 -41.819046 2.217194 24623 64.432648 -41.522949 3.171845 24624 65.081787 -40.639832 4.118469 24625 8.851227 -42.247665 2.151611 24626 8.881264 -42.209656 2.516358 24627 9.173828 -42.500595 1.756676 24628 10.928665 -42.062393 2.388397 24629 16.084946 -45.799774 2.433052 24630 14.185516 -46.100983 4.197708 24631 61.955383 -43.242538 2.554154 24632 17.497894 -41.515198 2.202286 24633 20.073242 -43.443893 1.753395 24634 57.251343 -44.391129 2.904327 24635 63.882263 -42.938400 3.139664 24636 63.672272 -44.126450 3.308334 24637 64.287735 -43.554886 3.852951 24638 10.950165 -42.638412 2.947601 24639 20.627235 -44.224701 1.796097 24640 20.330063 -43.803101 1.856575 24641 58.167206 -44.583466 3.275391 24642 59.152756 -44.702728 3.344223 24643 62.874023 -43.584137 2.838356 24644 11.321930 -42.989288 3.180328 24645 20.970520 -44.850754 2.101059 24646 54.351959 -44.938904 2.174744 24647 61.700104 -44.406174 3.037918 24648 62.915283 -44.704956 3.201676 24649 64.673920 -42.317963 4.275284 24650 17.481873 -46.704269 2.050369 24651 21.410858 -45.816772 1.819122 24652 21.122330 -45.501770 3.209290 24653 53.710114 -45.500381 2.519013 24654 22.837448 -47.838867 2.129318 24655 22.252487 -47.808334 1.625054 24656 55.118835 -45.671478 3.381607 24657 54.486084 -45.334290 2.914131 24658 53.703415 -46.522324 3.177879 24659 12.331108 -48.604263 2.001396 24660 20.168182 -48.979736 1.968720 24661 22.479904 -48.605240 1.697472 24662 22.983047 -49.644394 2.065941 24663 21.678406 -49.598312 1.839729 24664 53.321777 -47.612610 3.165268 24665 52.557465 -47.505615 2.924477 24666 54.292389 -47.861557 3.148956 24667 56.406219 -49.371780 2.334366 24668 57.013062 -49.481995 2.640503 24669 57.252686 -50.334488 2.504318 24670 12.317841 -50.606949 1.952812 24671 12.518097 -52.174103 1.264565 24672 46.120712 -53.449066 1.167992 24673 11.637260 -53.196228 2.213310 24674 12.201294 -53.654190 0.975678 24675 13.025215 -53.371735 0.587563 24676 15.910263 -53.485687 0.886734 24677 47.046295 -53.950638 1.309509 24678 11.865631 -55.062668 1.167427 24679 16.357391 -53.542587 1.012344 24680 16.081978 -54.286942 0.859116 24681 17.175240 -53.724533 0.954598 24682 17.357918 -55.195908 0.964958 24683 18.387657 -55.210312 0.665726 24684 46.010361 -54.201645 1.387848 24685 45.522598 -55.123764 1.243988 24686 46.367981 -54.605316 1.556244 24687 56.756393 -53.373627 2.181595 24688 46.949509 -55.285431 1.515038 24689 11.296487 -55.715027 2.264267 24690 16.022163 -55.528671 0.736130 24691 15.854919 -56.486481 0.660942 24692 17.036682 -56.442764 0.869225 24693 17.832428 -57.585800 0.738754 24694 45.677185 -56.262817 1.345596 24695 48.535492 -56.294785 1.191048 24696 46.854019 -56.452560 1.537689 24697 60.004929 -55.942047 1.782890 24698 60.050598 -56.290176 1.728333 24699 60.175934 -56.142990 1.963974 24700 10.758224 -56.915710 1.929573 24701 10.766800 -57.617844 2.008904 24702 13.830688 -58.479156 0.888565 24703 15.432251 -58.555298 0.876259 24704 16.289429 -57.486038 0.769524 24705 16.820213 -58.790909 0.974403 24706 17.949493 -58.526703 0.775551 24707 46.330170 -58.633865 1.166535 24708 46.170715 -59.774292 0.764710 24709 47.280319 -57.388779 1.315277 24710 59.994598 -56.375092 2.118340 24711 14.618401 -58.470352 0.813095 24712 11.491104 -58.229248 1.320221 24713 15.785294 -59.701767 1.217011 24714 16.755264 -60.384155 1.088760 24715 46.416550 -58.029297 1.334869 24716 59.459030 -57.470230 2.552445 24717 10.997353 -58.813431 2.259750 24718 11.971291 -59.160233 1.620415 24719 14.763062 -59.636841 1.417877 24720 18.026840 -59.407822 0.559158 24721 45.511932 -58.327911 0.990173 24722 45.957977 -57.274307 1.362579 24723 58.279510 -58.977539 1.433289 24724 56.939270 -59.946396 1.705383 24725 56.717484 -59.347076 2.396896 24726 57.527069 -59.389664 1.906868 24727 45.275970 -61.018372 0.356964 24728 56.684265 -60.966309 1.639984 24729 56.765518 -62.743729 1.317078 24730 55.794983 -62.159241 2.512177 24731 10.005646 -62.442001 0.399170 24732 9.565598 -62.632919 0.437386 24733 56.474060 -60.043808 1.942665 24734 9.054855 -62.689774 0.987053 24735 8.222504 -63.245148 1.317169 24736 13.360031 -62.994034 0.207176 24737 17.083191 -61.685608 0.666161 24738 16.336998 -62.743774 1.107727 24739 15.950912 -63.241180 0.478394 24740 15.429169 -63.584320 1.325966 24741 14.630508 -63.844131 1.128586 24742 24.876221 -64.667847 -0.219276 24743 25.521629 -64.457825 -0.304153 24744 24.978752 -65.966141 -0.119186 24745 23.794640 -66.066772 0.287766 24746 24.149742 -65.942215 0.300858 24747 24.281288 -66.313202 0.284744 24748 38.179901 -65.464340 1.440765 24749 7.319199 -67.061859 0.540650 24750 7.588730 -67.461594 0.453293 24751 23.929871 -66.436218 0.264336 24752 55.446899 -64.838928 2.047287 24753 54.630676 -66.501984 2.256729 24754 37.142578 -67.779907 0.734726 24755 54.242279 -67.477493 1.733414 24756 7.899574 -67.712997 0.993088 24757 8.231476 -68.119034 0.533234 24758 43.415924 -69.160614 0.321915 24759 47.552322 -69.076340 1.480576 24760 47.882019 -69.009521 0.680191 24761 48.232178 -69.122696 0.816223 24762 48.162445 -69.219986 0.290474 24763 42.384613 -68.398865 0.604813 24764 11.121330 -70.334152 -0.303070 24765 11.971466 -70.499390 -0.138657 24766 12.672943 -70.444016 0.503670 24767 5.507248 -71.901825 -0.151657 24768 6.531326 -72.112320 0.149719 24769 8.052216 -73.121307 -0.582733 24770 14.320694 -73.142410 -0.653763 24771 13.645882 -73.673157 0.143631 24772 39.566437 -71.881760 0.632324 24773 51.603302 -70.711502 2.106796 24774 8.122833 -72.928253 0.772247 24775 7.390610 -72.079910 1.691391 24776 6.659805 -71.654251 1.432457 24777 11.954536 -73.929688 0.643921 24778 12.089111 -73.154434 1.404312 24779 11.042664 -73.365860 1.236832 24780 13.737625 -75.469009 -0.743309 24781 40.997650 -73.451523 0.199196 24782 42.737946 -73.915833 0.267639 24783 42.759247 -73.462433 1.069969 24784 45.788498 -73.879700 0.120216 24785 4.697609 -76.871353 -0.222145 24786 12.753288 -75.399078 -0.598747 24787 13.127151 -74.665085 -0.158966 24788 12.197800 -74.750626 -0.151802 24789 12.755234 -74.132126 0.371582 24790 13.800934 -74.588821 -0.322006 24791 4.417145 -74.231354 0.574066 24792 4.712776 -77.856522 -0.502548 24793 47.948532 -76.896912 0.242607 24794 48.463074 -76.172394 0.346329 24795 36.832733 -78.110550 -0.645981 24796 37.233856 -78.684967 -0.245254 24797 38.280243 -78.917511 -0.134277 24798 42.083618 -77.766373 -0.056740 24799 43.107758 -78.154587 0.261780 24800 44.525223 -77.900406 0.282181 24801 45.448975 -77.665878 -0.011604 24802 46.634140 -77.507034 0.002968 24803 47.097076 -77.725967 1.201935 24804 48.182648 -76.611404 1.494331 24805 5.061180 -79.620804 0.580978 24806 39.723587 -78.644653 -0.053055 24807 39.971237 -79.836105 0.039940 24808 40.964386 -79.129883 0.195305 24809 41.888550 -78.442398 0.263588 24810 35.682060 -79.571671 -0.464897 24811 36.391708 -78.838821 -0.522148 24812 36.963348 -80.007156 -0.135490 24813 38.322845 -80.141586 -0.126938 24814 38.050575 -81.188263 -0.168396 24815 39.121704 -80.643387 -0.143669 24816 39.080292 -79.606430 0.021362 24817 39.953453 -80.969269 -0.160355 24818 40.895630 -80.526428 -0.013824 24819 5.283142 -81.660797 -0.239151 24820 33.928772 -81.794540 -0.118141 24821 37.647758 -82.203171 -0.020370 24822 35.987335 -82.496735 0.298668 24823 37.917465 -83.408386 0.424576 24824 40.491394 -81.772491 -0.014267 24825 39.138481 -82.070877 0.028740 24826 41.510864 -81.308334 0.093552 24827 41.327682 -82.193253 0.498345 24828 42.374405 -79.963913 0.407532 24829 32.893188 -82.765839 -0.738510 24830 42.089981 -82.036163 0.952454 24831 42.236298 -81.424576 0.527748 24832 5.892662 -82.861755 0.032097 24833 5.940331 -83.876236 -0.906868 24834 40.238586 -82.483994 0.649017 24835 41.641602 -82.345886 1.069153 24836 6.550240 -85.045059 -0.917130 24837 33.081139 -84.920792 -0.446732 24838 8.363084 -88.148300 -1.325249 24839 34.100021 -87.207779 -0.676460 24840 33.995483 -87.229050 0.317627 24841 33.919586 -86.266098 0.481339 24842 7.449555 -85.283691 -0.161072 24843 8.999832 -86.100723 0.078400 24844 34.506905 -88.248215 -0.543579 24845 8.812141 -89.388596 -1.530609 24846 23.340179 -89.692078 -0.857513 24847 22.554764 -89.910828 -0.125229 24848 23.440514 -88.959808 -0.096054 24849 25.429245 -89.312256 -0.593376 24850 26.318932 -88.365799 0.331741 24851 26.930954 -89.890121 -0.458832 24852 34.929855 -89.445358 -0.312996 24853 35.731339 -90.482117 -0.469475 24854 35.031784 -90.466141 0.155510 24855 37.317482 -90.099136 -1.134918 24856 9.358658 -90.040161 -1.405334 24857 10.253143 -90.456863 -1.694313 24858 13.164780 -90.068176 -0.085922 24859 13.199738 -91.061172 0.452797 24860 14.037933 -90.544632 0.586495 24861 22.453430 -88.922394 0.946922 24862 22.795029 -88.313751 1.343659 24863 23.495598 -88.359894 0.750687 24864 23.006714 -90.485260 -1.078339 24865 24.292618 -89.461441 -0.814240 24866 35.854950 -89.488876 -0.898026 24867 9.807479 -90.415176 -1.447945 24868 10.343613 -90.187485 -0.484055 24869 22.439011 -91.350937 0.118210 24870 22.582199 -90.747452 -0.631020 24871 36.455200 -91.634064 -0.583984 24872 37.241745 -91.397171 -0.856918 24873 37.627182 -91.376114 -1.067810 24874 38.330948 -91.529205 -1.607460 24875 39.117287 -91.122437 -1.685272 24876 17.382858 -91.498108 -0.191681 24877 37.297058 -92.453445 -1.271851 24878 23.050705 -93.329285 0.027069 24879 27.817108 -92.059570 -0.918022 24880 13.258537 -97.270935 -1.259338 24881 12.842552 -96.581955 -1.066406 24882 12.665512 -97.557144 -0.814507 24883 14.174774 -95.548828 -0.571907 24884 14.926865 -96.408249 -0.712723 24885 15.084618 -95.595718 -0.488464 24886 18.208168 -97.066025 -0.219131 24887 18.336960 -98.036819 -0.865517 24888 24.478348 -96.501648 -1.362442 24889 23.649323 -95.295303 0.098801 24890 28.493980 -96.227051 -1.157135 24891 35.228821 -95.212616 0.381203 24892 13.380371 -96.097626 -1.036972 24893 13.886581 -96.805069 -1.142784 24894 13.322571 -96.572006 -1.364174 24895 28.727905 -97.055038 -1.586639 24896 13.672493 -97.819107 -0.923676 24897 13.304337 -96.879898 -1.397766 24898 24.344849 -96.630402 -0.296684 24899 24.796562 -97.990631 -0.435783 24900 29.314636 -97.659302 -1.296341 24901 16.346733 -99.754028 -0.703682 24902 24.343437 -100.684341 0.184395 24903 24.884537 -99.562698 -0.212128 24904 14.601364 -101.482971 -0.353851 24905 15.279755 -100.035370 -0.541260 24906 13.909760 -100.145096 -0.080864 24907 23.149048 -102.218704 -1.535172 24908 23.733833 -101.894501 -2.486710 24909 16.136032 -102.765808 -0.433128 24910 16.829201 -102.766922 -1.708359 24911 15.814880 -102.980164 0.517037 24912 15.529480 -102.969482 1.164063 24913 16.953880 -102.803360 1.639519 24914 20.828110 -102.273682 1.435501 24915 17.888535 -102.863663 0.006088 24916 12.475235 66.298569 9.531837 24917 9.894310 65.567459 9.541374 24918 9.495927 65.201309 9.438972 24919 12.974113 66.416046 10.404121 24920 13.413757 65.994034 9.678452 24921 8.730988 64.190918 9.495537 24922 9.037750 63.365723 9.821045 24923 15.855133 64.701080 10.093704 24924 7.901954 62.629517 9.255142 24925 18.882576 62.058182 9.606506 24926 20.084549 61.489746 9.627243 24927 21.493828 61.439880 9.773911 24928 24.746796 61.306488 10.383354 24929 7.618240 61.525085 9.101425 24930 7.434280 59.394318 8.650299 24931 9.833755 57.605042 8.982626 24932 10.096123 58.469864 9.810684 24933 27.769310 57.928101 8.935478 24934 27.232933 57.594406 9.488586 24935 26.572159 56.635010 9.335892 24936 25.113213 54.851257 8.996674 24937 25.351936 55.570709 9.563599 24938 25.794952 56.281830 9.894287 24939 32.973618 55.958817 9.905563 24940 33.520508 55.658203 9.854826 24941 33.806961 55.129608 9.248962 24942 34.253113 54.174530 9.223312 24943 11.103836 55.948074 9.467285 24944 24.199249 53.798462 9.110779 24945 31.296242 53.161316 11.566994 24946 30.557709 53.006561 11.141441 24947 30.602905 53.672318 10.625938 24948 30.418823 53.978806 9.265717 24949 3.632462 53.237152 10.589020 24950 9.626785 53.752289 9.291138 24951 23.585732 53.313278 9.993095 24952 29.726120 53.306366 9.216110 24953 29.457878 52.955566 9.188004 24954 35.114059 52.701996 10.120407 24955 23.073509 52.277588 10.096855 24956 28.215210 50.531494 8.969818 24957 4.133400 50.201294 10.309471 24958 35.956001 47.751129 8.863699 24959 38.986023 50.076355 9.186630 24960 39.764313 49.994049 9.267807 24961 39.739876 50.482758 9.765701 24962 38.952866 50.752457 9.782150 24963 21.912880 48.928375 9.234070 24964 38.040146 49.296112 8.929794 24965 40.525604 49.917496 9.936256 24966 40.221085 50.713089 10.872078 24967 21.437607 47.583115 9.259544 24968 26.618027 48.002289 8.776062 24969 34.818092 50.118439 9.244110 24970 36.669052 49.585251 9.297607 24971 37.821098 50.583588 9.637373 24972 25.946541 47.170044 8.482269 24973 26.291122 46.859802 8.956268 24974 35.541862 50.059143 9.487244 24975 44.501617 45.208771 9.430191 24976 44.251068 46.463806 10.356895 24977 3.583466 46.173615 8.357832 24978 21.650879 46.529449 9.847000 24979 21.218712 47.024353 9.272728 24980 25.824249 46.356262 8.385773 24981 42.943695 47.750610 9.988632 24982 21.481346 45.464508 8.672577 24983 24.885086 44.357407 8.449585 24984 22.244591 44.526855 9.544289 24985 23.744766 44.068695 8.077225 24986 25.971802 45.165375 8.787384 24987 45.155289 44.961517 10.139275 24988 23.104752 43.981903 10.356728 24989 23.801132 43.793762 9.363287 24990 40.882050 41.651306 8.978317 24991 41.945892 41.748474 9.087265 24992 44.296661 42.629013 9.126373 24993 4.909058 43.473587 8.557838 24994 9.000092 43.513092 8.970032 24995 10.381982 43.192902 8.888145 24996 11.270355 42.980072 8.898193 24997 11.975555 43.024048 9.318451 24998 40.166550 42.600189 8.463722 24999 39.313492 41.337814 8.748863 25000 13.728241 42.044067 9.157806 25001 37.160141 40.760666 8.144684 25002 37.438232 40.482742 8.632782 25003 37.995415 40.688675 8.698929 25004 38.094536 41.710831 8.225830 25005 42.700729 42.110321 9.026054 25006 42.780289 40.936478 9.503891 25007 43.762436 41.607193 9.431152 25008 45.007416 42.273605 9.980431 25009 14.825363 41.319916 9.141647 25010 15.192581 38.757004 8.798019 25011 37.258629 38.581116 8.629593 25012 37.441414 39.869354 8.568512 25013 4.109696 38.222076 7.831863 25014 3.606423 37.680984 7.894851 25015 4.547920 38.609985 8.887283 25016 6.018486 38.771530 8.623589 25017 10.827896 37.779694 8.603127 25018 9.972290 37.998428 8.426300 25019 3.628983 37.016769 9.410789 25020 3.632218 36.797699 8.273819 25021 3.655464 37.915863 8.729950 25022 15.132263 38.347748 7.827879 25023 47.123993 37.239716 8.305740 25024 49.146301 37.842056 9.585236 25025 3.849686 35.857834 7.604454 25026 36.163620 35.609619 8.342575 25027 44.858292 35.950256 8.598572 25028 45.853638 36.454041 9.387039 25029 46.798264 37.073822 9.473801 25030 51.809631 36.747559 8.798904 25031 4.112488 34.860672 7.506851 25032 36.566452 34.965073 8.358429 25033 42.246506 34.974197 8.580254 25034 40.817505 34.437225 9.543533 25035 43.624741 35.410446 9.323624 25036 52.928223 34.787766 8.395622 25037 52.297424 35.631500 9.439461 25038 4.770287 33.811951 8.018684 25039 4.655449 34.256439 9.174881 25040 5.086723 33.387222 9.209328 25041 5.475800 32.576843 9.230698 25042 5.361839 32.466934 8.429314 25043 37.345932 34.299347 8.733879 25044 36.384308 34.805344 10.189095 25045 36.209595 35.189377 9.161201 25046 36.644768 34.551666 9.268723 25047 39.077118 34.075195 7.827377 25048 42.170792 35.004913 9.353432 25049 38.998016 33.960098 8.329384 25050 52.753693 31.274017 9.163467 25051 52.639374 32.780243 10.517517 25052 52.924103 33.765320 9.402840 25053 3.837853 30.769684 7.336036 25054 2.793477 29.136475 7.387013 25055 2.879028 30.257568 7.024566 25056 52.450165 29.691040 8.255585 25057 44.101593 27.840820 7.764877 25058 52.051682 29.080627 7.912216 25059 2.255291 24.012222 7.525385 25060 2.300863 25.288599 7.134221 25061 2.340854 24.454031 8.051647 25062 2.204017 24.738924 6.538841 25063 2.512131 27.256277 7.292737 25064 41.030792 26.243530 7.043579 25065 40.095795 25.769974 7.308692 25066 41.630936 27.934128 8.715141 25067 42.995941 27.935486 8.292007 25068 53.039948 30.753632 8.358932 25069 51.749268 28.770203 8.574371 25070 51.190857 27.293304 8.757492 25071 30.147095 24.881348 8.096504 25072 31.022705 25.826736 7.835342 25073 31.312683 25.784531 6.794677 25074 32.147888 25.992065 7.673736 25075 38.798706 26.011719 8.035095 25076 52.223984 25.462753 8.722290 25077 52.529648 24.945343 7.655258 25078 30.692497 25.966949 9.154327 25079 46.835663 24.393250 8.311249 25080 35.192474 24.941147 7.924369 25081 36.424652 24.503571 7.569664 25082 52.208115 26.471283 10.635239 25083 51.479935 26.556808 10.812881 25084 51.569885 26.259018 10.131844 25085 53.410278 25.178513 8.699516 25086 36.749138 24.040253 7.071334 25087 47.969330 21.755524 7.495926 25088 56.004639 23.540573 9.410339 25089 56.061905 24.669067 10.016891 25090 55.593277 24.530289 9.165863 25091 29.346642 23.549347 10.560883 25092 29.648697 23.693970 9.701582 25093 31.413261 21.417953 7.446449 25094 46.753052 22.683929 8.448395 25095 55.789291 21.533463 7.978714 25096 46.815552 19.590637 7.663391 25097 47.356720 19.591187 7.419738 25098 46.968582 20.417374 7.770095 25099 47.885986 20.181351 7.319290 25100 34.848846 19.171127 6.950019 25101 35.366753 17.785828 7.314392 25102 34.800797 18.505554 7.498397 25103 46.346924 19.649887 8.260483 25104 47.211914 19.214691 7.683136 25105 47.597076 18.860672 8.360062 25106 48.233917 18.590363 8.629517 25107 48.854706 18.539810 8.048004 25108 51.139145 18.522766 7.797058 25109 53.626495 19.355270 8.672043 25110 51.781097 18.904144 8.742523 25111 49.816925 18.494934 8.385071 25112 50.693848 18.518524 8.278076 25113 2.092953 12.208871 9.626545 25114 32.539764 14.380051 7.809044 25115 33.093033 14.395889 7.243171 25116 42.324768 12.404633 6.864990 25117 42.595825 13.238297 7.073814 25118 41.597229 13.152374 7.786209 25119 42.646545 14.446075 8.120863 25120 32.718636 12.151108 7.411239 25121 41.936508 11.684189 7.193328 25122 42.532532 11.441223 6.671112 25123 43.779968 14.391815 8.183075 25124 48.624039 12.396133 7.060256 25125 48.794327 12.894699 7.847046 25126 49.540115 12.532135 7.464958 25127 32.148773 12.876450 7.713912 25128 32.035027 13.503281 7.933013 25129 43.057144 10.856445 6.338256 25130 52.677277 11.570786 7.106864 25131 51.722290 11.857880 7.426452 25132 52.451782 10.627823 6.888656 25133 53.576294 11.288544 7.028320 25134 53.054749 12.387421 7.830856 25135 54.466949 11.407150 7.267791 25136 54.391739 12.016998 7.808013 25137 54.329865 12.601791 8.614044 25138 33.231544 11.378952 7.457092 25139 33.907310 10.924454 7.294479 25140 42.551468 10.691727 6.676262 25141 54.447830 10.561234 7.047790 25142 35.313339 9.715500 8.340927 25143 36.687561 7.684158 7.891105 25144 36.173187 9.170288 7.830696 25145 42.371628 9.887512 6.788345 25146 42.213425 10.821793 6.973280 25147 46.628418 9.268463 6.984268 25148 55.285126 11.187424 7.980133 25149 41.719238 6.542755 8.655235 25150 41.899780 5.847900 9.398216 25151 43.248169 6.451050 8.566956 25152 50.254303 8.878433 7.666503 25153 50.485382 7.662491 6.901022 25154 54.798340 9.022263 7.423599 25155 55.094391 9.973877 7.588218 25156 43.453232 7.341568 7.218910 25157 54.456375 8.175171 7.796722 25158 53.908691 6.967438 8.130402 25159 54.188339 2.954620 7.467071 25160 54.090134 4.255783 7.853500 25161 38.113968 5.994537 6.164474 25162 49.977020 7.953827 7.821762 25163 49.728851 7.037704 7.559723 25164 37.393242 6.439987 7.212478 25165 37.325562 5.005470 6.778656 25166 49.404861 5.783264 7.251892 25167 41.152817 3.719246 6.207946 25168 48.683350 7.552429 9.443573 25169 48.127731 7.323273 10.077652 25170 48.286194 6.502151 9.567276 25171 48.843384 4.569633 7.425804 25172 48.991364 3.659431 6.764312 25173 2.187297 6.252492 8.063549 25174 2.235772 7.636255 7.877995 25175 37.675613 3.136284 6.199676 25176 38.551033 3.173553 6.139328 25177 39.799789 3.205536 6.791076 25178 43.400177 2.942902 7.273712 25179 49.463516 3.252205 6.303924 25180 49.140854 3.005219 6.658355 25181 36.929733 2.999031 7.100990 25182 51.380707 1.653320 6.757087 25183 55.855453 2.861542 8.364029 25184 54.958923 3.039627 8.057579 25185 54.972214 1.514725 8.716751 25186 43.963104 2.114166 7.141067 25187 48.698547 3.066849 7.499206 25188 47.925247 3.006424 8.403915 25189 48.048843 1.937408 8.406128 25190 52.038879 0.793396 7.597046 25191 51.156738 0.892700 7.195526 25192 50.647858 0.083496 7.637191 25193 49.811325 1.119949 7.211837 25194 58.407043 0.793106 5.757606 25195 44.217377 0.625427 6.906280 25196 58.413605 0.219513 6.121109 25197 57.653625 -0.680374 6.687789 25198 58.814255 -0.940796 7.230087 25199 59.075409 -0.125000 6.365806 25200 2.394690 2.719920 6.164216 25201 2.269947 3.892262 6.861691 25202 44.522430 -0.960922 6.226341 25203 56.440979 -1.237869 6.441177 25204 60.441559 -1.408920 6.499809 25205 59.986450 -1.117630 7.159622 25206 2.341320 2.796714 7.000403 25207 60.557526 -1.945862 7.309631 25208 44.222031 -2.824905 6.081924 25209 60.750198 -3.020782 6.595611 25210 60.933548 -3.194824 7.330909 25211 60.952545 -2.857269 7.333480 25212 2.994314 -5.676733 6.849161 25213 40.658401 -7.033524 5.948623 25214 41.301880 -7.376465 7.020736 25215 41.769684 -6.451904 6.840690 25216 41.548065 -5.887894 5.561363 25217 52.628708 -5.006760 6.625457 25218 40.006927 -7.377335 5.236923 25219 43.703781 -8.489822 4.749878 25220 42.708496 -8.418304 5.544640 25221 43.409332 -9.797440 6.224411 25222 43.173401 -9.685013 6.747802 25223 42.741409 -8.950668 6.598129 25224 60.169739 -5.604950 7.045379 25225 40.323624 -7.865189 5.834548 25226 40.766388 -8.315887 5.778022 25227 41.229553 -8.405212 6.365020 25228 43.510468 -9.339493 5.569580 25229 49.114639 -9.488647 6.099754 25230 56.661209 -8.095551 6.708580 25231 57.649612 -7.732101 5.962913 25232 3.270379 -8.101100 6.925149 25233 48.321655 -9.950806 6.587768 25234 47.802917 -10.206879 7.017982 25235 47.806732 -10.857529 5.973258 25236 53.553162 -10.382721 5.606887 25237 53.808350 -9.773651 6.639236 25238 3.672105 -10.358334 6.442857 25239 53.107361 -10.645615 6.019630 25240 59.631027 -10.857178 5.551819 25241 63.277802 -11.831024 6.519302 25242 63.146454 -11.497635 7.861862 25243 3.955932 -11.351837 5.700509 25244 4.140978 -12.539358 5.996678 25245 47.854935 -12.012726 4.719238 25246 53.033173 -11.556290 5.690506 25247 58.701828 -11.176910 5.899803 25248 46.522964 -11.288879 7.085632 25249 46.776611 -12.003555 6.018753 25250 47.273712 -10.911346 6.671882 25251 47.070251 -12.987762 5.040054 25252 52.946869 -12.593857 5.772224 25253 52.923462 -13.701370 6.187576 25254 52.087463 -12.733276 6.423172 25255 53.867035 -12.483551 5.624206 25256 54.535446 -13.733292 7.017913 25257 52.256500 -11.762634 6.493164 25258 52.715973 -11.007294 6.626434 25259 64.021118 -13.168854 4.959915 25260 63.739777 -13.236359 5.535545 25261 39.496307 -15.054459 4.637917 25262 38.685486 -15.235428 5.198135 25263 39.059753 -14.515778 5.588028 25264 39.949142 -14.324783 5.468544 25265 40.846710 -13.831528 5.951881 25266 44.390106 -15.396057 5.699669 25267 45.113220 -15.476700 4.943771 25268 45.336548 -14.125153 5.714805 25269 45.719666 -14.812164 5.040871 25270 46.226379 -14.423630 5.016861 25271 45.977936 -15.300217 4.567146 25272 61.822800 -15.376266 7.274994 25273 62.458649 -14.964279 7.246383 25274 5.297579 -16.421661 4.634457 25275 37.639954 -17.951263 5.130112 25276 61.100861 -17.389084 8.223312 25277 60.537659 -17.121826 7.601905 25278 61.074173 -18.154205 7.492431 25279 36.567719 -20.238174 4.614136 25280 36.820488 -19.397644 5.122666 25281 58.129059 -18.396805 5.134270 25282 59.158829 -18.630234 5.599091 25283 58.901733 -17.655869 6.029861 25284 5.886308 -19.549398 8.508005 25285 6.341150 -20.243029 7.640142 25286 6.307069 -19.806965 6.805536 25287 42.408875 -17.214752 6.341636 25288 59.463989 -21.996246 4.857231 25289 60.663910 -18.940170 6.272453 25290 6.773652 -20.026323 4.460058 25291 6.239840 -19.283888 5.735652 25292 35.310379 -21.771301 4.827507 25293 35.714569 -21.198135 4.593224 25294 36.054993 -20.759293 4.780518 25295 52.235214 -21.365173 4.422447 25296 53.558380 -21.717834 4.922234 25297 54.758057 -21.853806 5.161560 25298 55.891449 -21.762772 5.182663 25299 63.918579 -20.124649 6.421325 25300 7.472472 -21.257559 4.313035 25301 8.391234 -22.662024 4.165142 25302 35.215096 -22.348862 4.890381 25303 57.169388 -22.971771 5.673828 25304 58.128464 -23.266220 5.537972 25305 58.114365 -22.273590 5.243317 25306 60.768448 -22.447815 4.443489 25307 35.427200 -22.759552 4.986534 25308 36.457405 -23.629959 6.207168 25309 38.857407 -22.270721 5.730293 25310 38.014290 -22.100739 7.347419 25311 37.647705 -23.089859 6.550292 25312 51.969879 -22.679306 5.137825 25313 59.947250 -22.985748 4.748291 25314 59.002686 -23.094177 5.169525 25315 60.929047 -23.299118 4.435188 25316 50.119873 -24.193756 5.232460 25317 50.703445 -23.310287 5.062630 25318 10.909332 -25.843632 4.136471 25319 64.116241 -25.073837 6.187599 25320 9.927304 -24.988546 4.879461 25321 10.543450 -25.799866 4.905675 25322 45.591858 -27.247498 4.601486 25323 64.432373 -23.616104 6.492767 25324 53.288757 -27.437500 3.635681 25325 11.770278 -26.734995 3.944927 25326 44.314163 -28.214218 4.455765 25327 52.742188 -28.457016 3.626122 25328 64.363190 -27.118912 5.519837 25329 12.471996 -27.484367 3.933534 25330 12.820684 -28.080332 4.362096 25331 43.235153 -29.266754 4.212708 25332 64.419342 -28.201218 5.381775 25333 13.723955 -28.804945 4.058313 25334 61.412140 -30.558914 4.575089 25335 59.836823 -30.773743 5.336052 25336 61.538376 -32.030807 5.654411 25337 58.734482 -29.899185 5.718414 25338 58.928009 -31.012115 5.746933 25339 62.699371 -30.767838 4.387589 25340 41.392853 -32.557495 4.061371 25341 41.266922 -33.045227 4.000870 25342 62.673294 -31.503403 5.072113 25343 63.732971 -31.638046 5.964592 25344 15.464890 -31.559580 5.448461 25345 41.308395 -33.907349 4.034889 25346 41.587799 -34.969421 3.687302 25347 14.529748 -30.847378 5.846528 25348 14.294606 -31.071030 6.385568 25349 22.153307 -35.306583 3.449077 25350 21.901011 -36.470692 4.304146 25351 30.863235 -34.918961 2.540131 25352 41.317017 -34.996979 4.453369 25353 42.048401 -36.112076 4.293564 25354 41.240112 -35.547012 5.336189 25355 43.616135 -36.992279 4.142777 25356 43.003006 -36.163483 3.498543 25357 44.806427 -36.762436 3.770691 25358 50.760147 -38.690430 4.823410 25359 49.903778 -38.175552 4.471100 25360 14.254829 -37.790756 3.143822 25361 16.239929 -37.190674 4.140228 25362 17.197777 -37.416397 4.020760 25363 16.507477 -37.652969 5.574249 25364 25.788958 -36.588715 2.685020 25365 24.720688 -37.043682 3.394038 25366 25.192526 -36.658310 3.021388 25367 24.349529 -36.163548 3.001734 25368 51.932068 -37.235733 3.918007 25369 53.244568 -37.273514 4.164566 25370 54.357803 -37.099518 3.995133 25371 55.307892 -36.975021 3.670670 25372 56.177719 -37.189697 3.966553 25373 56.701843 -37.827209 4.560150 25374 57.378494 -39.813293 6.036163 25375 56.496521 -38.864075 5.436325 25376 58.273712 -38.537186 4.924683 25377 63.751953 -37.237045 3.408005 25378 65.233948 -39.561401 4.143112 25379 64.376434 -39.233276 4.650414 25380 18.696388 -37.745758 3.951195 25381 25.328583 -38.236511 3.096230 25382 25.402107 -37.754425 3.692719 25383 26.456833 -37.617996 2.883301 25384 25.892326 -38.062607 2.982864 25385 23.936270 -37.391342 3.736017 25386 24.248053 -36.817272 3.381826 25387 23.889946 -36.607944 3.393283 25388 62.937958 -37.630112 4.054550 25389 63.698502 -37.796097 4.019631 25390 22.613632 -38.706482 3.652435 25391 23.667130 -38.866547 3.232643 25392 23.000801 -37.779633 4.338852 25393 23.378052 -38.888596 4.271500 25394 26.035690 -37.546585 3.380692 25395 65.465576 -39.775909 3.653832 25396 16.066460 -41.343323 3.207176 25397 15.438416 -42.105927 4.508164 25398 16.667389 -42.618149 4.029602 25399 9.596550 -42.331894 2.781738 25400 9.962097 -43.138702 3.311562 25401 13.801147 -40.825180 4.777611 25402 18.218048 -42.760223 2.999809 25403 20.019379 -43.983795 2.655876 25404 9.025192 -42.864685 2.484848 25405 8.969086 -42.605881 2.674492 25406 9.459320 -43.268890 2.436386 25407 19.926086 -44.987457 4.151825 25408 9.927254 -43.971115 2.590485 25409 60.394806 -44.811539 3.307907 25410 64.098892 -44.668259 4.221924 25411 63.497101 -45.214447 3.638939 25412 21.896362 -46.275665 2.793305 25413 61.142761 -45.630432 3.435852 25414 59.841873 -46.201813 3.639206 25415 62.495193 -46.289276 3.625168 25416 61.900024 -47.094070 3.557846 25417 61.206818 -46.950943 3.636803 25418 10.585770 -45.787384 4.149231 25419 11.655991 -47.235474 2.614609 25420 22.749252 -47.269241 2.794396 25421 22.355606 -46.817993 3.082558 25422 63.628494 -45.999863 4.509010 25423 11.731178 -51.658249 2.492684 25424 11.485015 -50.129730 3.768303 25425 23.211433 -47.968704 3.133026 25426 51.861206 -47.501205 2.691223 25427 61.671524 -47.588455 3.650986 25428 11.605759 -52.236313 3.781441 25429 23.348625 -48.747101 2.473854 25430 23.757645 -48.803299 3.493454 25431 62.145004 -47.487366 3.677002 25432 62.574097 -47.934479 4.080788 25433 63.007751 -48.074326 4.731217 25434 63.146530 -47.173691 4.452263 25435 55.582489 -48.279526 3.120773 25436 56.381683 -48.848236 2.914894 25437 58.293915 -48.311966 3.523934 25438 57.221588 -48.375031 3.401383 25439 58.376556 -49.821091 3.219521 25440 59.206696 -48.849472 3.387901 25441 59.052704 -47.669235 3.641449 25442 60.202698 -48.126617 3.565613 25443 60.702240 -48.925644 3.452820 25444 61.238403 -48.323914 3.703430 25445 20.353111 -50.691528 3.414017 25446 20.065376 -50.447647 3.292931 25447 20.908325 -50.494385 2.729843 25448 23.807724 -49.759995 2.910378 25449 60.020111 -49.422180 3.384522 25450 60.317001 -50.304840 3.977905 25451 60.941437 -49.296432 3.629341 25452 19.718811 -49.874344 3.135010 25453 20.611145 -49.821579 2.197647 25454 23.153748 -51.366837 2.900513 25455 23.309036 -52.356262 2.846497 25456 23.033157 -52.787018 3.588852 25457 24.551620 -50.494263 3.680435 25458 57.655487 -50.835754 3.083183 25459 23.582047 -52.679504 2.965103 25460 24.357422 -52.872910 3.282898 25461 56.891891 -51.902679 3.342941 25462 57.463089 -51.411942 3.482010 25463 11.581192 -54.508057 2.807808 25464 20.994385 -51.081192 3.949295 25465 56.119843 -53.400757 3.702797 25466 56.457489 -53.471298 4.261696 25467 56.474823 -52.752487 3.723000 25468 56.319824 -53.168137 2.749275 25469 56.200439 -53.448547 3.222817 25470 56.834290 -54.222900 3.527123 25471 58.133652 -55.285339 3.517067 25472 57.369720 -54.948654 4.093124 25473 58.080505 -55.486221 4.211639 25474 58.907013 -56.124298 4.116394 25475 58.557007 -55.902924 4.987412 25476 59.342209 -56.375427 2.872070 25477 59.933914 -56.031860 2.167114 25478 10.894608 -56.457962 2.221443 25479 12.188034 -60.208740 2.694557 25480 12.486481 -60.468170 3.058762 25481 13.318146 -60.251663 2.309265 25482 55.850220 -59.047653 2.813728 25483 55.127808 -59.286362 2.832199 25484 55.110977 -58.313797 3.700607 25485 56.605087 -58.718994 3.556908 25486 58.008301 -58.706543 2.975227 25487 59.060974 -57.909866 3.225090 25488 11.233322 -59.636780 2.769173 25489 11.828705 -59.749084 2.247559 25490 15.654976 -60.511902 1.583366 25491 15.024193 -60.798111 2.069321 25492 55.762482 -60.872269 2.335404 25493 54.839081 -60.512680 2.914795 25494 55.865097 -59.978821 2.334663 25495 8.914459 -62.493042 1.378342 25496 8.689941 -62.656509 1.341202 25497 10.184967 -62.715103 1.155556 25498 9.208908 -62.571747 1.488754 25499 55.214981 -63.185791 3.134247 25500 54.743530 -62.206223 3.234703 25501 16.025215 -61.576462 1.733994 25502 7.114258 -62.436523 3.425156 25503 6.677857 -62.783478 3.522019 25504 7.065003 -63.269318 2.554474 25505 13.525703 -63.721664 1.389755 25506 14.592026 -64.042725 1.629662 25507 15.515380 -62.889771 2.134514 25508 14.780502 -63.821976 2.229797 25509 38.258644 -65.114761 2.022049 25510 39.100365 -65.123611 1.926941 25511 39.862610 -65.136505 2.063919 25512 7.511986 -66.867752 1.266731 25513 24.005501 -66.175156 0.433228 25514 54.675629 -65.631760 2.890335 25515 7.009194 -65.716461 2.208519 25516 37.152367 -67.172882 1.354523 25517 41.940613 -65.636841 3.343788 25518 40.393250 -65.244995 3.041458 25519 41.523727 -65.416916 4.174309 25520 54.134613 -66.590317 3.036583 25521 42.293396 -66.265793 2.675942 25522 42.774750 -67.019943 2.044167 25523 43.440384 -66.976440 2.469261 25524 43.371307 -67.930786 1.383492 25525 46.036926 -67.967499 1.969208 25526 45.724197 -67.645416 2.706055 25527 46.647720 -68.423874 2.533249 25528 44.819702 -67.743317 1.923294 25529 37.334442 -66.969818 1.887604 25530 46.611176 -68.370651 1.772644 25531 53.533127 -68.574448 2.105690 25532 10.033539 -69.294205 0.675095 25533 11.450851 -69.735275 0.878662 25534 12.433762 -69.993866 1.113907 25535 12.806702 -70.368286 1.227356 25536 48.887589 -70.422394 2.086487 25537 52.734009 -69.845703 1.697441 25538 4.577606 -72.567230 0.842362 25539 5.395783 -71.706940 0.485619 25540 13.234741 -71.272842 0.854279 25541 13.813148 -72.308655 0.176346 25542 52.744995 -69.681366 2.816132 25543 52.003998 -70.555389 3.518143 25544 52.517151 -69.426880 3.831352 25545 5.073921 -71.380127 1.295448 25546 4.333283 -71.688354 2.622788 25547 5.955338 -71.188766 1.395897 25548 13.369080 -72.505539 0.878647 25549 39.628693 -71.293747 1.550293 25550 50.153885 -71.247528 2.449623 25551 40.921646 -72.490677 1.496452 25552 41.686981 -72.177750 2.713280 25553 40.719467 -71.494492 2.583572 25554 10.042274 -72.942062 1.691162 25555 8.998405 -72.891129 1.608795 25556 12.805527 -73.346695 0.943558 25557 41.312805 -73.264313 0.788681 25558 42.656998 -72.944305 2.488693 25559 44.423691 -73.716248 2.282517 25560 43.429657 -73.487732 3.667816 25561 45.490112 -73.781403 1.112549 25562 45.775345 -74.082260 1.978905 25563 4.590378 -75.312790 0.429947 25564 12.742493 -72.183701 1.546898 25565 4.743942 -76.566833 1.235535 25566 44.345749 -78.965485 0.821076 25567 45.687897 -78.125229 0.698441 25568 47.943909 -76.465683 3.126770 25569 48.173798 -76.653442 2.579865 25570 47.397690 -77.845306 2.899002 25571 45.795593 -78.998703 1.788864 25572 43.788544 -80.331329 1.080582 25573 36.493774 -81.429993 -0.003708 25574 34.906303 -81.800568 0.145981 25575 35.831345 -83.721451 0.551422 25576 42.863159 -80.919052 0.742157 25577 34.120369 -82.433029 0.296379 25578 34.849625 -84.744644 0.793297 25579 34.813919 -82.309296 0.409378 25580 43.007629 -81.357605 1.453064 25581 44.555878 -80.234421 1.556946 25582 44.744156 -79.708893 1.410553 25583 6.688896 -84.101379 0.142525 25584 34.831551 -82.818604 0.515015 25585 36.226219 -85.076202 0.880814 25586 37.274033 -84.568481 0.620140 25587 38.031914 -84.365799 0.587158 25588 38.479538 -84.337357 0.972664 25589 39.273918 -82.970276 0.977799 25590 41.035873 -82.426056 1.264404 25591 37.231049 -85.850784 1.083672 25592 38.048706 -85.132736 0.934235 25593 38.741074 -83.649231 0.965530 25594 33.691299 -85.153046 0.334931 25595 33.829384 -84.371460 0.468857 25596 9.262009 -89.257721 -0.683685 25597 15.161514 -89.351715 -0.232185 25598 24.796326 -88.527359 0.345749 25599 27.316177 -87.964676 0.857292 25600 27.251175 -88.555862 0.159683 25601 27.876389 -88.222092 0.564842 25602 27.876839 -88.795868 0.138535 25603 28.607605 -88.528549 0.830856 25604 29.295769 -88.877060 1.272202 25605 29.111626 -89.267914 0.598633 25606 34.145142 -88.006042 0.131424 25607 34.412476 -88.862732 0.324570 25608 14.671623 -89.087555 -0.287979 25609 28.425919 -89.331543 0.151383 25610 34.637680 -89.877655 0.522011 25611 34.679993 -89.263824 1.003006 25612 9.835342 -89.155273 0.037262 25613 13.917755 -89.748413 0.338829 25614 29.010956 -90.375549 0.170410 25615 12.056633 -90.531891 1.651146 25616 11.392014 -90.549530 0.522888 25617 10.948746 -89.811264 0.881744 25618 12.017845 -90.626358 -0.206100 25619 15.703018 -89.676880 0.289742 25620 22.504562 -92.336761 0.890549 25621 29.280052 -91.488937 -0.158127 25622 35.482574 -91.401733 0.122917 25623 35.836807 -92.278397 -0.201187 25624 29.691963 -92.386200 0.036041 25625 29.853004 -93.469849 0.100159 25626 30.030640 -91.264679 0.521103 25627 35.526665 -92.137314 0.185364 25628 36.253860 -93.320938 -0.870026 25629 35.772194 -92.829300 0.098343 25630 18.271988 -93.247314 -0.457214 25631 30.753433 -93.123596 1.069122 25632 35.511612 -92.058594 0.667114 25633 35.822556 -93.969116 -0.267898 25634 18.423294 -94.131393 -0.202820 25635 18.746490 -95.279449 -0.783188 25636 23.339828 -94.314468 0.430611 25637 22.899414 -94.488617 1.209023 25638 29.359879 -94.483719 -0.167519 25639 30.147743 -95.368835 0.660904 25640 29.167389 -95.896957 -0.263122 25641 35.849579 -93.135498 0.873375 25642 33.477264 -97.033615 -0.454338 25643 12.743805 -95.436768 -0.208496 25644 11.876160 -96.487045 -0.177246 25645 15.261658 -94.628952 0.045593 25646 29.515434 -96.928848 -0.164688 25647 29.089394 -96.963730 -0.745804 25648 15.939392 -96.020096 -0.165436 25649 16.701263 -95.138916 0.186508 25650 30.241104 -96.881973 0.461945 25651 14.587432 -97.386353 -0.832916 25652 15.518768 -97.285339 -0.353546 25653 22.856621 -97.399078 2.147736 25654 22.752243 -95.950287 1.808769 25655 23.857887 -97.105423 0.688629 25656 34.797035 -95.840256 1.757347 25657 35.672546 -94.784775 1.911514 25658 12.016708 -97.703705 -0.152618 25659 12.853233 -98.705673 -0.129997 25660 25.239624 -99.602005 -0.906006 25661 25.253204 -99.001740 -0.733505 25662 31.817492 -97.818085 -0.463158 25663 16.821136 -99.190018 -0.210724 25664 17.330246 -98.272980 -0.070343 25665 23.229927 -101.777039 0.326576 25666 23.886398 -100.865250 1.054657 25667 13.737747 -101.573959 0.759697 25668 15.243500 -102.143707 -0.964340 25669 22.365738 -102.602234 -0.743378 25670 11.974594 66.461945 10.061592 25671 11.918549 66.199280 10.948418 25672 9.738335 64.572128 10.059845 25673 10.759338 65.361755 10.597702 25674 10.044511 65.360062 9.945892 25675 14.005066 66.007492 10.295265 25676 14.853165 65.639740 10.501160 25677 10.272583 62.707855 10.554123 25678 10.802444 62.949020 11.256561 25679 10.527596 62.080032 11.370193 25680 10.397278 63.611191 10.679329 25681 17.838501 62.746689 10.748428 25682 16.738998 64.473206 11.339043 25683 9.529167 61.902679 10.166672 25684 18.029434 61.733078 11.226181 25685 20.856293 61.436096 9.763260 25686 21.898384 61.108719 10.257195 25687 23.768738 61.453506 10.228790 25688 22.958313 61.317383 10.443024 25689 24.652451 61.491196 12.777809 25690 24.546715 61.639740 11.528008 25691 25.732956 61.165314 11.796112 25692 8.780991 59.508926 9.385788 25693 10.197289 59.508698 10.163168 25694 19.089958 60.753174 10.335678 25695 20.723595 60.679840 10.222588 25696 23.881760 61.620880 10.832581 25697 26.632339 60.553665 10.510086 25698 26.060852 60.919144 10.545204 25699 9.471588 60.524551 9.999069 25700 20.590218 59.413956 10.885811 25701 19.541901 59.241364 10.355270 25702 21.872826 60.561478 11.238075 25703 26.860580 58.544754 10.846405 25704 10.778389 59.023560 10.988792 25705 18.445366 59.497574 10.549828 25706 17.764511 60.409836 11.520332 25707 18.631569 58.713028 10.195213 25708 19.030579 58.212585 10.328377 25709 18.392090 58.136093 10.251961 25710 18.097839 58.660934 10.434875 25711 17.858627 58.001953 10.638725 25712 18.604034 57.510269 10.672523 25713 17.646103 57.221497 10.954855 25714 10.953552 57.050415 9.829849 25715 11.382751 56.302963 10.087265 25716 10.903435 57.938080 10.916000 25717 26.641212 59.448914 12.440659 25718 26.503845 60.492416 11.989540 25719 32.386490 55.605484 10.446159 25720 33.448380 55.725922 10.771889 25721 33.133911 55.385361 11.527664 25722 34.498260 55.238617 11.937469 25723 11.153397 55.843979 10.366066 25724 24.735031 55.005676 11.159286 25725 24.798248 54.259155 12.041275 25726 25.617767 56.050262 11.949448 25727 31.312744 54.725098 10.252647 25728 32.043716 54.393341 11.539848 25729 6.325241 55.614197 10.436462 25730 9.042267 55.105179 10.932823 25731 8.754097 54.653061 10.446823 25732 9.690186 54.470963 10.144547 25733 24.059525 54.092590 10.044830 25734 24.610596 54.806534 10.089096 25735 34.263275 55.023544 10.428093 25736 34.969269 53.981583 10.436218 25737 35.130707 54.710037 11.332504 25738 3.438377 52.191986 10.346336 25739 3.579498 51.638611 10.418098 25740 10.413574 54.960800 10.668694 25741 29.731552 52.975342 9.816618 25742 23.122314 51.796524 10.944733 25743 23.523972 52.897430 10.754372 25744 29.382271 51.431122 10.154770 25745 30.126404 49.430206 10.594376 25746 28.601982 49.890076 9.864647 25747 35.171066 50.800476 9.626221 25748 36.204178 51.010406 9.843773 25749 37.900406 52.777924 11.097885 25750 37.224922 52.007370 10.372688 25751 38.568932 51.670029 10.717758 25752 36.939697 53.410553 11.282761 25753 36.068680 52.397552 10.451141 25754 39.476173 51.721146 12.681145 25755 38.637474 52.877319 12.088463 25756 35.326981 51.604370 9.944061 25757 22.144211 49.880417 9.873322 25758 22.345680 50.457428 9.874237 25759 27.642029 49.451813 9.244034 25760 27.076477 48.849518 9.117340 25761 39.473549 51.059479 10.620224 25762 27.293373 46.995087 9.435379 25763 26.756256 45.915253 9.164337 25764 41.968353 48.889603 10.335442 25765 22.098442 48.003830 10.382103 25766 22.329941 49.165115 10.618927 25767 28.083748 48.270584 9.720467 25768 41.269592 49.525177 10.263596 25769 26.105377 46.128922 8.897430 25770 27.689705 45.842438 9.409142 25771 28.284813 46.619141 9.699554 25772 45.790268 43.598312 10.551918 25773 3.661316 46.211212 10.050438 25774 3.531349 45.169861 9.208450 25775 21.569771 45.382568 9.536972 25776 28.602600 45.462097 9.507782 25777 29.532822 46.728394 10.028374 25778 29.348831 45.362061 9.628036 25779 29.862778 45.043488 9.989883 25780 30.721977 46.199341 10.624352 25781 22.136444 45.336975 10.313789 25782 22.582489 44.586288 10.542633 25783 27.527130 44.136063 9.327316 25784 25.832558 43.801910 9.113464 25785 29.038750 44.597916 9.567444 25786 5.829353 44.012497 9.669907 25787 7.608367 43.506500 8.949707 25788 23.705139 43.613556 10.308167 25789 24.925621 43.672089 9.136856 25790 29.390457 43.536407 10.113892 25791 12.714172 42.539703 9.027550 25792 25.272316 43.110840 9.750732 25793 25.662415 42.601990 10.447304 25794 26.598137 42.247620 10.266655 25795 26.579178 43.069275 9.517670 25796 24.995880 43.118073 10.698799 25797 27.630020 42.537476 9.708313 25798 28.363747 42.904541 9.655592 25799 40.478882 39.846100 9.430763 25800 27.844635 41.600327 10.490356 25801 41.791092 40.471344 9.496178 25802 46.084076 41.719543 11.708656 25803 46.356674 42.768768 11.469734 25804 45.884583 42.320953 10.876587 25805 5.480301 39.051483 8.493629 25806 5.352287 39.205475 8.729729 25807 5.149666 39.017670 8.584435 25808 5.562744 39.059235 8.860474 25809 41.603500 39.456360 10.006905 25810 42.725555 39.786652 10.556860 25811 43.510483 40.541077 10.021202 25812 44.262466 40.857300 10.451843 25813 3.856491 38.296234 9.405228 25814 3.650551 37.934296 9.506256 25815 8.065674 37.927399 9.130699 25816 6.762543 38.465256 9.112122 25817 9.315094 37.981201 8.879280 25818 38.679520 39.442490 9.087509 25819 39.611839 38.622574 9.785706 25820 40.754974 38.614395 10.584938 25821 41.787720 39.090012 10.593437 25822 13.159836 37.753586 9.305847 25823 11.853516 37.640564 9.012785 25824 14.606140 38.420700 9.614990 25825 37.167297 37.535400 9.260857 25826 38.291550 37.996719 9.755508 25827 50.680908 37.338715 10.151825 25828 50.458435 37.411224 11.629318 25829 49.632217 37.641754 11.291611 25830 47.840973 37.457550 9.892273 25831 36.142685 35.899384 8.955933 25832 36.531601 36.656250 9.184593 25833 44.766357 36.009888 9.367134 25834 4.099213 35.340881 8.913788 25835 52.413406 34.427216 10.592461 25836 51.899216 35.876328 10.819847 25837 38.329803 33.901810 9.155884 25838 41.677216 34.399078 11.123436 25839 40.542633 34.078735 11.190527 25840 39.382446 34.079590 8.982925 25841 39.041306 33.955170 10.021469 25842 38.179459 33.741684 10.106461 25843 4.894539 31.324692 8.336540 25844 52.778168 31.951843 10.194908 25845 3.288507 29.834089 8.048027 25846 3.760208 30.693268 8.873131 25847 4.670197 30.908569 9.703857 25848 5.357643 31.858215 9.305649 25849 2.990861 28.474113 8.566179 25850 2.683327 27.627724 7.868281 25851 2.411022 25.578329 7.794757 25852 2.521464 26.590616 7.768753 25853 39.135315 27.612305 8.779030 25854 37.864838 27.203369 9.070251 25855 38.225372 27.881866 9.723297 25856 40.243042 28.040543 8.835114 25857 40.584900 27.841919 9.673462 25858 39.359787 27.947617 9.711174 25859 38.580994 26.835144 8.452621 25860 44.033112 27.205139 8.757103 25861 32.475189 26.270477 9.153152 25862 32.929626 25.813019 8.330994 25863 37.651978 25.066101 7.981964 25864 37.562347 26.227539 8.653824 25865 51.195358 26.534393 9.362907 25866 51.743103 25.946045 9.177406 25867 2.359392 23.162508 9.035313 25868 29.495819 24.688385 10.360374 25869 29.879776 24.933762 9.366379 25870 33.615402 25.496445 8.093445 25871 34.326843 25.322662 8.322952 25872 52.805176 25.076355 8.482674 25873 36.031082 25.553467 8.663147 25874 46.088104 24.144073 9.102196 25875 55.623215 25.506622 10.150208 25876 54.536285 26.076553 9.898926 25877 56.166138 22.226593 9.245071 25878 45.126678 20.235611 8.385559 25879 46.057571 21.174240 8.348022 25880 45.008530 21.310989 8.676926 25881 46.907440 21.448715 8.050392 25882 44.251450 22.043121 9.143623 25883 45.572632 22.607956 9.089981 25884 56.027466 21.597015 8.626747 25885 56.207962 21.639130 9.118439 25886 31.768000 19.621460 9.055176 25887 44.211990 20.566071 8.599281 25888 43.656311 19.810471 9.061005 25889 44.415771 19.718430 8.604050 25890 43.264526 21.002121 9.078018 25891 56.062271 21.333328 9.906296 25892 55.132141 20.156281 9.001556 25893 45.249054 19.439896 9.012421 25894 54.621460 19.535782 10.260468 25895 2.017852 14.741913 9.295368 25896 1.996222 15.683981 8.885553 25897 34.857689 17.815216 7.756629 25898 44.341400 19.381607 9.384140 25899 45.087372 19.458282 10.661514 25900 46.675354 19.278564 9.840141 25901 34.999092 16.783997 7.644722 25902 48.943771 18.797394 9.211990 25903 2.083431 12.062400 10.742746 25904 32.159653 14.013733 7.829315 25905 32.232071 14.337296 8.770828 25906 32.608810 15.449463 9.877502 25907 33.326927 15.116211 8.349731 25908 34.574829 15.344055 7.473861 25909 44.665939 13.801651 8.093475 25910 42.224899 15.272766 9.152359 25911 41.445572 14.632523 8.816360 25912 46.039078 13.139938 7.917915 25913 45.198181 13.407059 8.923782 25914 44.723251 13.821411 8.988571 25915 50.812805 12.940430 7.837318 25916 50.941956 13.576065 8.494003 25917 50.048141 13.225281 8.258072 25918 51.926163 12.961182 7.968429 25919 51.679535 13.531021 8.480377 25920 52.571915 13.251740 8.765221 25921 47.505951 12.869171 8.853119 25922 49.374298 13.076202 9.334229 25923 48.256134 12.667297 10.232498 25924 50.130829 11.593384 7.511062 25925 52.192291 13.582413 9.106659 25926 55.327179 12.096863 8.848564 25927 32.068893 12.855164 8.713264 25928 41.312912 11.721390 7.886032 25929 51.188019 10.659042 7.368721 25930 49.947571 10.267792 7.802642 25931 50.894806 9.663849 7.362381 25932 55.905029 11.487869 8.926842 25933 55.958969 11.470886 9.939056 25934 33.073349 11.220612 8.765106 25935 41.642548 10.687134 7.521148 25936 49.053894 10.837006 7.579673 25937 51.704376 9.782608 6.984542 25938 41.184875 9.464233 7.895751 25939 47.583435 9.522812 7.596191 25940 48.506531 10.164413 7.734787 25941 49.117981 10.251953 7.967994 25942 55.890228 10.687271 8.889000 25943 55.564423 10.304199 8.196793 25944 42.282089 7.082504 7.944351 25945 40.794006 7.687347 8.627182 25946 54.801941 8.450592 9.680222 25947 55.322632 9.499542 8.486679 25948 43.225647 6.772858 7.772369 25949 46.048172 8.268860 7.770996 25950 44.649261 7.334686 7.562713 25951 43.951233 6.855011 7.828552 25952 49.066223 6.751099 8.515289 25953 49.393921 7.744873 8.522568 25954 41.869141 3.295181 7.455070 25955 37.800964 2.789322 6.626068 25956 37.617004 2.552917 7.217529 25957 36.764236 3.973763 7.205017 25958 36.598114 4.818657 8.124802 25959 38.470093 2.755676 6.936264 25960 42.898224 3.010803 8.009306 25961 55.412109 3.678162 8.542801 25962 55.661591 4.015976 9.324028 25963 54.206924 4.067352 9.442001 25964 2.088485 6.144479 9.764130 25965 2.106588 5.235078 9.310490 25966 2.135863 6.003892 8.926971 25967 38.528442 2.580399 7.821014 25968 36.959297 2.249939 7.812942 25969 48.685989 0.304886 7.798202 25970 49.474213 0.254303 7.249725 25971 53.184540 0.731567 8.266876 25972 50.002457 2.438751 6.486549 25973 49.920532 0.223373 7.248161 25974 49.561340 -0.213318 7.532989 25975 43.956192 -2.007477 6.979156 25976 51.682510 -0.741928 8.914612 25977 55.530426 -3.098511 7.694473 25978 57.312180 -1.929779 7.616607 25979 2.194268 4.279147 8.186680 25980 2.393701 1.750638 7.262763 25981 2.456705 0.516546 7.326493 25982 44.018646 -0.716888 7.196296 25983 2.420909 -0.179368 7.970897 25984 43.524002 -1.895615 7.854988 25985 43.112808 -2.699371 7.922210 25986 43.009064 -1.685303 8.621277 25987 60.865021 -2.533829 7.340156 25988 2.631842 -1.622072 7.158843 25989 43.511368 -3.672760 6.806404 25990 60.759766 -3.722076 7.388412 25991 2.690646 -2.767068 7.272069 25992 43.103027 -4.814606 6.355354 25993 53.271317 -4.019806 6.147201 25994 60.617050 -4.466141 7.040901 25995 2.801430 -3.508294 6.902308 25996 42.491974 -5.577286 6.598869 25997 3.185431 -6.780787 6.427769 25998 2.962276 -6.559834 7.687849 25999 42.220825 -5.592072 7.633186 26000 51.211914 -6.550903 8.592255 26001 51.998077 -5.806931 7.573257 26002 40.666138 -7.763977 6.415893 26003 57.422241 -7.745102 6.818511 26004 58.255020 -7.261230 6.955383 26005 41.972504 -8.399139 6.244316 26006 40.642029 -8.305359 6.337623 26007 55.438721 -8.578781 6.661064 26008 56.133682 -8.292984 7.731201 26009 3.409681 -9.698355 7.570858 26010 40.830200 -8.556671 6.316314 26011 54.641296 -9.020599 6.681297 26012 42.912109 -11.387421 6.583526 26013 43.213943 -10.373596 6.683776 26014 59.607330 -10.840759 6.494735 26015 60.610901 -10.586609 8.660156 26016 62.337662 -10.789047 8.801193 26017 51.310303 -14.366501 6.652252 26018 51.213409 -15.676712 6.539627 26019 50.372360 -15.351349 7.207206 26020 3.842416 -12.270343 7.745822 26021 4.071261 -13.393649 7.781352 26022 4.249583 -13.481692 6.625060 26023 41.355255 -13.174530 6.974716 26024 42.150513 -12.348785 7.069839 26025 41.812927 -13.219116 5.752670 26026 42.547150 -11.562393 7.436889 26027 45.215118 -12.802795 6.602859 26028 45.794739 -11.985931 6.773986 26029 45.189117 -12.108582 7.450592 26030 46.363647 -13.388168 5.486252 26031 45.836014 -12.813675 6.082626 26032 47.249878 -10.530075 7.514511 26033 4.547869 -13.924153 5.254036 26034 4.431800 -14.538662 7.143943 26035 4.775900 -15.669354 6.876929 26036 5.099896 -16.211479 5.565784 26037 5.020484 -16.278595 6.330644 26038 38.351685 -14.840729 5.774093 26039 37.768852 -14.719299 6.411888 26040 38.489265 -14.325851 6.239952 26041 39.659348 -13.942627 6.699798 26042 44.655945 -13.553406 6.845039 26043 63.098480 -14.470764 6.417137 26044 63.392990 -14.093719 6.741706 26045 63.603958 -13.337982 6.659187 26046 5.285647 -16.579294 5.076601 26047 5.213387 -16.798481 6.093064 26048 37.396225 -15.830643 6.745117 26049 37.197571 -14.656265 7.023222 26050 38.052422 -15.961823 5.761016 26051 44.328812 -14.604599 6.408966 26052 43.525208 -15.475418 6.875541 26053 51.164337 -13.483444 7.369644 26054 52.186462 -16.344070 6.783981 26055 50.978058 -17.142822 6.746902 26056 51.127106 -16.412064 6.556671 26057 52.281921 -15.092987 6.387748 26058 53.266571 -15.083832 6.779724 26059 5.434419 -17.255655 5.642991 26060 37.372330 -17.176773 6.327392 26061 49.952423 -17.443176 6.874618 26062 50.227142 -16.515579 6.958007 26063 5.759065 -18.173365 5.814930 26064 58.985123 -16.697678 6.142898 26065 59.796387 -17.803925 6.599060 26066 36.131165 -20.143021 5.491585 26067 36.503036 -18.727768 6.367248 26068 39.591721 -20.036575 6.811233 26069 61.602142 -19.616226 5.962265 26070 62.589691 -19.662323 6.160415 26071 63.493088 -19.538315 6.930313 26072 62.187210 -18.973694 7.007362 26073 34.650803 -20.827957 6.975311 26074 35.433281 -20.979095 5.630767 26075 34.875443 -22.312317 5.819412 26076 39.422264 -21.174545 6.205108 26077 64.801590 -22.494751 7.859405 26078 64.865112 -21.002319 7.921569 26079 6.987767 -20.945961 6.110475 26080 6.857798 -20.458660 5.421518 26081 7.577496 -21.686800 5.182538 26082 35.536079 -23.180069 5.555740 26083 51.403061 -24.078491 5.725860 26084 52.749023 -23.959473 6.001808 26085 53.112732 -22.874619 5.483849 26086 54.044128 -23.102921 5.797104 26087 55.140274 -22.875656 5.784347 26088 56.076691 -23.571625 6.050224 26089 37.832657 -23.175873 5.372604 26090 58.865723 -23.897766 5.422546 26091 58.098175 -24.005890 5.762123 26092 48.289383 -25.369980 5.056366 26093 49.448761 -25.328110 5.602691 26094 11.291478 -26.610577 4.718071 26095 46.866653 -27.323349 5.599869 26096 48.543198 -26.005005 5.584793 26097 12.001619 -27.387186 4.672301 26098 48.273361 -26.822464 5.866386 26099 12.312272 -28.054562 5.268047 26100 13.241265 -28.678928 4.658269 26101 12.700587 -28.482035 5.255349 26102 13.055587 -28.722830 5.045302 26103 11.211345 -26.871523 5.357758 26104 11.523360 -27.336397 5.566613 26105 44.064697 -29.170334 5.268379 26106 45.463959 -28.355026 5.589401 26107 64.164566 -30.679306 6.594497 26108 43.192429 -30.414459 5.182678 26109 58.721222 -28.738327 5.786338 26110 63.606293 -28.882233 7.618652 26111 63.561234 -28.101196 6.851822 26112 14.043077 -29.355362 4.461743 26113 43.014191 -32.019043 5.790878 26114 58.078690 -31.231262 6.084837 26115 13.633053 -29.299973 5.036155 26116 14.576516 -30.026600 4.710121 26117 44.163910 -30.987671 6.069519 26118 62.477173 -33.436722 7.246818 26119 63.064651 -32.720474 6.494995 26120 14.603657 -30.493799 5.328077 26121 41.613846 -32.952072 4.881973 26122 63.035248 -32.214417 5.857543 26123 13.901943 -31.195566 6.994056 26124 14.591383 -31.779713 6.643258 26125 23.605282 -35.644344 2.999954 26126 41.406616 -34.274170 5.485764 26127 14.103012 -37.699936 4.923874 26128 13.660294 -38.451660 4.073898 26129 45.563675 -37.408707 4.193398 26130 44.559296 -37.694366 4.350250 26131 55.468292 -37.801605 4.738373 26132 17.905548 -37.838074 4.972962 26133 20.063232 -38.111298 3.904694 26134 21.218445 -38.551041 4.474938 26135 23.286203 -36.213825 3.438830 26136 43.927307 -37.747238 4.424805 26137 43.379333 -37.704010 4.659752 26138 42.477554 -37.198914 4.939148 26139 47.438110 -38.721710 4.445229 26140 46.094574 -38.662323 4.555336 26141 54.320709 -38.068573 4.932526 26142 58.221054 -39.677094 5.884590 26143 62.004272 -38.045364 4.404266 26144 62.729599 -38.466400 4.697907 26145 13.349075 -38.066757 4.955277 26146 13.042526 -38.521088 4.931748 26147 13.209450 -39.225525 4.498291 26148 13.702042 -39.411484 3.923279 26149 22.412857 -38.928268 4.947891 26150 43.759216 -38.370743 4.853241 26151 42.801636 -37.914597 5.301361 26152 44.903183 -38.617096 4.688461 26153 43.799927 -39.696671 5.110611 26154 45.167786 -39.853256 4.778839 26155 61.062378 -38.401413 4.705246 26156 63.500168 -38.466537 4.488533 26157 44.788010 -40.747360 4.655434 26158 62.641724 -39.599854 5.471436 26159 64.845810 -40.122574 4.895096 26160 42.570801 -38.647385 6.327400 26161 43.951172 -40.871735 4.843186 26162 11.147079 -43.733429 4.009171 26163 10.243622 -44.008484 4.293144 26164 44.626266 -41.608032 4.667603 26165 43.596054 -41.780075 5.128449 26166 11.366333 -43.242081 3.403824 26167 17.704453 -43.779236 4.566109 26168 18.966438 -44.059219 3.794228 26169 42.740021 -41.886826 6.171661 26170 42.922302 -40.639526 5.967742 26171 9.730209 -43.864655 3.533493 26172 11.365768 -44.785110 4.767571 26173 10.860138 -44.215744 4.655609 26174 64.567642 -43.587250 4.923081 26175 64.650238 -41.272171 5.364296 26176 56.243744 -45.678650 3.647003 26177 21.915466 -46.686020 4.041504 26178 55.463043 -46.770676 3.695709 26179 57.669800 -46.347763 3.719849 26180 11.230637 -46.975632 3.231140 26181 11.340042 -47.643387 3.285202 26182 15.963394 -47.228745 3.897843 26183 56.140427 -46.339935 4.126404 26184 56.577698 -46.219025 4.132408 26185 56.662231 -46.585770 4.142487 26186 23.306221 -48.185013 4.358383 26187 56.226089 -46.705551 4.128723 26188 56.449203 -47.349594 3.756172 26189 56.405014 -48.254135 3.411591 26190 61.930908 -48.136276 3.836090 26191 63.457077 -47.248550 5.531876 26192 11.344635 -48.528397 3.612503 26193 18.540787 -48.537109 2.997688 26194 24.250656 -49.510391 3.853104 26195 61.838120 -49.042480 4.192238 26196 62.619431 -48.595551 4.540543 26197 62.657043 -48.987274 5.421745 26198 61.687714 -50.024582 4.945511 26199 11.685234 -51.085541 5.013825 26200 22.021484 -52.087601 4.172318 26201 58.595001 -51.180710 3.989494 26202 59.811188 -51.255371 4.510666 26203 60.787781 -51.017181 5.121643 26204 22.845139 -53.534012 4.631729 26205 22.360664 -52.898407 4.642670 26206 59.282700 -51.957550 5.311684 26207 23.813324 -53.348236 3.394974 26208 23.646652 -53.975693 4.145538 26209 26.072891 -54.512970 4.113144 26210 25.279648 -53.461884 3.811668 26211 26.420319 -53.178787 4.522064 26212 24.419411 -53.711731 3.606506 26213 10.541580 -56.910263 2.753861 26214 10.930733 -56.135483 3.452561 26215 56.964737 -54.324371 4.811600 26216 10.401123 -56.841110 3.561951 26217 57.643921 -55.240509 4.772522 26218 59.168381 -56.754822 5.020767 26219 9.497910 -57.266907 4.782456 26220 9.637054 -58.476135 5.129150 26221 10.249146 -57.801300 3.529282 26222 53.615356 -57.217514 4.470566 26223 53.174835 -58.022125 3.796700 26224 52.726868 -57.746368 3.979904 26225 56.187531 -58.512207 4.996376 26226 54.847717 -57.511887 4.770889 26227 59.117691 -57.511429 4.302322 26228 52.775360 -58.882492 3.745575 26229 53.789551 -58.249832 3.645706 26230 54.229828 -59.137131 3.231125 26231 57.598068 -58.667770 4.400009 26232 11.683937 -59.965088 2.728806 26233 53.685455 -59.981445 3.365204 26234 53.638733 -61.370132 3.490051 26235 8.813339 -62.641754 1.596451 26236 9.183350 -62.698029 2.235855 26237 8.003746 -62.456345 3.112801 26238 11.791374 -63.268646 1.550217 26239 10.947449 -63.246628 2.448151 26240 55.759216 -63.575150 2.678986 26241 6.700424 -64.499466 2.348778 26242 12.489914 -63.824860 2.279343 26243 14.501617 -63.133667 3.027832 26244 55.272934 -63.961060 2.991753 26245 12.364105 -63.840179 3.174255 26246 14.217041 -64.115295 2.058869 26247 38.419632 -65.249481 2.733025 26248 38.019333 -65.547333 3.514183 26249 38.652267 -65.174057 3.713486 26250 39.220230 -65.044449 4.396744 26251 42.739548 -66.338684 3.914200 26252 7.865881 -66.417404 3.178452 26253 44.237976 -67.048782 3.188011 26254 45.069229 -67.237366 2.795433 26255 8.571106 -67.751907 1.685333 26256 10.157516 -68.567993 1.926468 26257 8.431351 -66.510193 4.139053 26258 9.168823 -67.030945 3.833397 26259 9.182220 -67.540558 2.790527 26260 37.793976 -67.749741 2.589569 26261 54.104584 -67.430466 2.559418 26262 52.887573 -66.420853 3.591438 26263 54.094910 -65.756119 3.303314 26264 11.460258 -69.135040 2.098084 26265 53.495529 -67.636261 3.199585 26266 11.059433 -68.667206 2.991936 26267 12.192612 -69.934967 1.854065 26268 12.645073 -70.912643 1.809960 26269 38.555199 -68.501266 4.008316 26270 38.026611 -67.539780 3.894486 26271 39.761009 -70.320435 2.908508 26272 53.052948 -68.673462 3.421677 26273 5.134354 -70.778610 1.903198 26274 39.119286 -69.209305 3.572098 26275 39.654427 -69.655472 4.032730 26276 51.059265 -71.360168 2.970871 26277 48.789673 -71.652542 3.801941 26278 8.195198 -72.691422 1.670342 26279 50.228394 -71.731842 3.298645 26280 11.843140 -72.493942 1.991295 26281 42.378601 -72.474487 3.668076 26282 4.373398 -74.550354 2.569679 26283 47.520264 -75.065964 2.350922 26284 48.083710 -75.691360 2.201126 26285 5.575562 -79.415253 2.373352 26286 5.435242 -77.919968 2.892387 26287 6.081085 -78.835739 3.138573 26288 5.902672 -80.541534 2.142258 26289 5.922234 -81.655319 1.058609 26290 44.348816 -80.576553 1.932793 26291 45.212357 -80.021286 2.987618 26292 46.321182 -79.180130 2.945465 26293 45.009369 -79.990433 1.921829 26294 42.688721 -81.492737 2.734017 26295 43.920746 -80.899658 2.760307 26296 41.828644 -82.004089 1.753662 26297 6.473999 -82.879913 0.866600 26298 39.341583 -82.373886 2.032410 26299 38.837822 -83.683670 1.917534 26300 40.171432 -82.467880 1.470093 26301 40.894745 -82.175980 1.930000 26302 40.243134 -82.029999 2.128479 26303 7.467796 -84.464966 0.473908 26304 7.677963 -83.356262 1.146637 26305 9.102524 -83.865845 1.083679 26306 9.331512 -82.413269 1.691696 26307 8.278474 -84.691772 0.564110 26308 10.139175 -84.535141 0.893463 26309 10.020187 -83.491348 1.339516 26310 11.250809 -84.506363 1.138619 26311 11.490173 -83.008102 1.738968 26312 35.518806 -85.889435 1.119415 26313 36.338997 -86.008636 1.129974 26314 38.971680 -84.699234 2.825516 26315 38.347260 -83.629333 3.550819 26316 9.125703 -84.812103 0.635834 26317 10.637756 -86.699432 0.785530 26318 9.691040 -87.944244 0.136200 26319 10.966476 -85.507095 0.942841 26320 38.063614 -85.930283 1.276703 26321 12.088387 -86.185974 1.795380 26322 11.154068 -87.690842 1.368599 26323 34.675659 -87.068573 1.094101 26324 34.890366 -86.422470 1.180657 26325 34.536476 -85.737625 0.918457 26326 36.160629 -86.873077 1.405739 26327 10.965637 -88.853165 1.237145 26328 10.305634 -88.594681 0.599182 26329 28.035309 -88.058228 1.221588 26330 25.767860 -88.095764 1.114952 26331 26.866127 -87.783463 1.070976 26332 26.470947 -87.822968 1.249077 26333 37.865425 -86.667542 1.702103 26334 37.299133 -88.056625 2.079483 26335 38.641594 -85.547272 1.827133 26336 14.748367 -89.622986 0.378800 26337 23.536705 -88.282104 1.564468 26338 24.228516 -88.312057 1.091499 26339 25.018372 -88.777237 1.946961 26340 10.336349 -89.362823 0.464821 26341 15.749802 -90.130219 0.690163 26342 22.171623 -91.515442 1.085190 26343 22.143341 -92.173935 1.650223 26344 21.776421 -91.301605 1.905541 26345 29.546455 -89.573410 1.024399 26346 34.991180 -88.137589 1.115936 26347 16.297684 -90.198608 0.290291 26348 17.210098 -91.643143 0.577011 26349 17.746613 -91.839096 0.238487 26350 34.910538 -89.962387 1.155075 26351 12.098816 -91.013138 0.726441 26352 13.901833 -91.180359 0.594437 26353 30.016273 -90.326385 1.161591 26354 30.539139 -91.071854 1.421295 26355 35.284134 -90.891846 0.981102 26356 12.510254 -91.209869 0.531914 26357 13.946114 -91.607574 0.846848 26358 15.150201 -92.155869 0.737465 26359 14.398445 -92.451614 0.946053 26360 15.134445 -93.051788 0.557587 26361 14.270233 -91.184128 0.719681 26362 16.180038 -92.218140 0.709999 26363 15.017128 -91.185806 0.789856 26364 18.319931 -95.225998 0.139824 26365 21.883789 -90.258942 1.224808 26366 16.566612 -94.175018 0.302918 26367 16.011993 -93.442062 0.395722 26368 13.975761 -93.888397 1.027252 26369 17.864479 -93.252396 0.308159 26370 17.579865 -94.355850 0.388779 26371 17.426056 -92.391769 0.555801 26372 22.275406 -93.329208 1.911247 26373 35.883270 -91.943909 1.324677 26374 16.851089 -95.952133 0.187821 26375 16.962067 -93.288879 0.566094 26376 18.115021 -96.171234 0.270767 26377 18.619797 -96.104202 -0.311882 26378 30.539642 -94.181839 0.916504 26379 30.736786 -91.970383 1.329811 26380 31.330017 -93.793793 1.929230 26381 11.760925 -95.547913 0.037338 26382 11.609497 -95.048569 0.507767 26383 11.262009 -95.663101 0.432037 26384 12.471169 -94.396698 1.215614 26385 13.628860 -93.793365 1.987396 26386 13.258469 -94.162872 1.742935 26387 13.767929 -94.765594 0.272369 26388 17.528275 -95.589279 0.381577 26389 23.773109 -98.289154 1.300133 26390 10.951820 -96.549835 1.203781 26391 11.515320 -97.218994 0.354653 26392 16.992294 -96.884079 0.170296 26393 24.415268 -98.499863 0.476502 26394 31.040924 -97.690964 0.238388 26395 32.111938 -97.414200 0.570114 26396 33.699638 -96.672882 0.932541 26397 32.495071 -96.917465 1.483513 26398 12.938675 -100.158432 0.704941 26399 14.507660 -98.573669 -0.468384 26400 16.033707 -98.456589 -0.017387 26401 16.161606 -99.324142 -0.141785 26402 16.548569 -98.864594 0.088455 26403 31.084274 -97.441696 0.707604 26404 24.061569 -99.716385 1.143982 26405 12.853088 -100.961166 1.320595 26406 12.247849 -100.188522 1.868988 26407 14.980789 -102.517334 0.251816 26408 21.958328 -101.969833 1.640289 26409 11.855026 66.075546 12.559471 26410 11.411705 65.343796 11.564774 26411 13.148315 66.561523 12.419586 26412 13.944199 66.295074 11.297157 26413 10.906502 64.515732 10.997307 26414 11.150757 64.369019 11.742882 26415 15.492905 65.550751 11.431236 26416 10.948944 63.685303 11.396881 26417 17.308167 63.623474 11.740494 26418 17.161842 62.726913 12.660866 26419 23.470192 61.475983 11.764336 26420 22.597260 60.649124 13.040688 26421 26.528069 60.688644 11.184746 26422 10.379807 60.833099 11.405167 26423 17.197372 61.452545 12.592506 26424 10.633270 59.903015 10.927895 26425 17.622665 59.001678 11.168129 26426 17.269745 59.674286 11.952850 26427 26.405075 57.822983 12.146103 26428 16.958130 58.879700 12.046066 26429 17.220444 57.933731 11.304779 26430 19.723053 58.043976 11.181671 26431 20.962296 59.223083 12.033836 26432 25.575165 56.436523 10.901634 26433 26.198708 57.139038 10.738220 26434 11.126190 56.812195 10.800064 26435 17.190277 57.125397 11.408737 26436 18.171532 56.720306 11.306046 26437 25.208389 55.773315 10.659302 26438 3.427590 55.315872 11.955315 26439 3.499443 54.355392 11.352654 26440 4.046326 54.579300 10.636436 26441 5.351296 56.195602 10.683975 26442 6.087753 56.806839 11.122910 26443 5.132156 57.097839 11.254471 26444 17.515182 56.770660 11.292892 26445 18.939957 57.072876 11.223190 26446 33.458107 54.779572 12.420494 26447 4.329651 56.087952 11.097107 26448 8.245888 55.402954 10.859406 26449 7.201080 55.966400 10.871666 26450 10.785545 55.363922 10.731613 26451 9.803238 55.395157 11.204376 26452 23.948959 52.775391 11.676811 26453 24.140236 53.942062 10.861481 26454 30.085434 52.732239 10.701889 26455 35.815689 53.486786 10.782883 26456 35.939728 54.226166 11.409561 26457 37.824875 53.800934 13.417374 26458 37.274292 54.253662 13.074425 26459 37.734711 53.804657 12.415878 26460 36.790588 54.285248 12.268852 26461 37.955093 53.379486 11.751984 26462 3.548805 52.413666 11.184570 26463 30.764099 51.004242 11.162756 26464 30.751419 52.181580 11.298660 26465 38.316498 53.470840 12.302116 26466 32.046051 50.239059 11.809044 26467 31.612833 48.931519 11.256918 26468 3.819565 51.078369 10.259224 26469 22.638458 50.389282 10.804276 26470 4.431427 48.549011 10.466795 26471 41.943298 49.648575 12.991165 26472 41.524292 49.399094 13.927727 26473 41.063416 49.974243 13.593002 26474 41.160095 50.099747 11.860741 26475 5.338944 47.636520 11.084358 26476 4.604233 47.099228 10.922720 26477 3.434532 46.982407 9.513046 26478 30.933029 47.871857 10.713699 26479 42.915375 48.571136 11.090401 26480 31.638262 48.126526 11.119377 26481 31.581909 47.227570 11.197472 26482 43.603455 47.854599 11.060883 26483 44.766922 46.610138 12.213249 26484 44.130524 47.509735 11.784981 26485 45.585632 45.038086 11.663689 26486 45.252869 45.729233 12.754555 26487 31.641832 45.728683 11.694336 26488 30.631813 44.645264 10.825623 26489 4.057350 45.148682 10.056137 26490 4.202705 45.826859 10.649223 26491 4.845810 45.457901 10.671822 26492 4.921272 44.463089 9.898712 26493 22.988541 46.133850 11.146942 26494 23.455795 47.284729 11.501549 26495 6.782311 44.268143 9.934830 26496 7.890014 44.709991 10.224449 26497 11.392342 43.992020 10.143402 26498 12.879059 43.211792 10.136803 26499 23.198135 44.378265 11.006287 26500 23.508209 45.148575 11.345215 26501 24.302071 43.395477 10.256454 26502 29.789993 42.374390 10.941711 26503 30.514084 43.349442 11.368645 26504 30.000702 41.219147 14.088829 26505 29.913651 41.328506 12.570496 26506 30.558647 42.438354 12.437157 26507 45.531387 44.541779 14.674484 26508 44.560654 45.339417 15.686722 26509 44.473312 46.048355 14.873718 26510 10.235641 44.685547 10.416115 26511 11.025421 45.059875 10.817642 26512 14.428352 42.379288 10.657364 26513 26.074280 42.280258 10.738930 26514 30.265213 42.489777 11.532028 26515 28.738434 42.065491 10.289658 26516 46.240814 43.732117 11.449194 26517 15.264893 41.371201 9.999947 26518 25.812912 42.709412 11.340546 26519 27.239311 41.411743 11.289497 26520 26.543869 42.015076 11.398026 26521 45.180893 41.161087 11.374290 26522 15.614456 40.951752 10.278900 26523 28.581001 41.338928 10.792503 26524 5.230705 39.031067 8.947578 26525 43.647125 40.250305 10.600418 26526 5.553085 38.634888 9.502701 26527 4.164574 37.921600 10.363365 26528 6.678444 38.077423 10.050003 26529 10.199379 37.726898 9.117706 26530 15.417892 39.349365 9.931564 26531 14.993790 39.062271 10.566315 26532 41.847031 38.754089 11.505302 26533 9.404266 37.322464 9.532898 26534 11.231415 37.368164 9.524353 26535 10.565765 37.008881 9.675873 26536 38.513626 37.495270 10.529694 26537 37.353867 36.924713 10.477081 26538 39.371513 37.926514 10.518858 26539 39.932739 37.885071 11.401993 26540 49.028702 37.716736 10.477554 26541 50.863129 36.884201 12.398560 26542 49.735443 37.179718 12.633942 26543 3.733811 36.279022 10.446053 26544 7.371101 37.416504 10.361176 26545 36.349083 35.823318 9.894981 26546 46.820190 36.962646 10.294090 26547 51.263916 36.694901 11.583565 26548 8.428635 36.545685 10.833862 26549 10.037216 36.485046 10.161263 26550 11.465225 36.433136 10.611214 26551 10.093071 35.625519 10.931999 26552 44.820892 35.936310 10.085999 26553 42.217346 34.906281 10.098083 26554 43.038559 34.865021 11.119171 26555 51.975006 34.990906 11.625175 26556 38.119125 33.623032 11.357285 26557 37.134926 33.249664 12.714897 26558 36.470955 34.219482 11.771049 26559 37.297714 34.004257 10.058693 26560 2.438900 24.732117 8.585148 26561 2.598065 25.683525 8.900532 26562 2.520710 24.988743 8.977457 26563 2.543971 25.940107 8.376055 26564 2.658959 26.840137 8.343491 26565 2.740965 26.555552 8.998571 26566 2.830831 27.429510 8.738295 26567 3.385518 29.648468 9.058958 26568 51.259750 30.840988 10.702621 26569 52.136597 31.845795 10.744766 26570 2.975891 27.151821 9.707611 26571 51.431290 29.782776 9.835342 26572 51.898743 32.507751 11.388443 26573 2.514143 24.412359 9.293549 26574 50.877106 28.413910 9.619148 26575 50.511444 29.436035 10.579330 26576 36.493683 26.909103 9.457771 26577 36.411896 27.776062 10.483353 26578 37.277870 27.625961 9.818726 26579 41.637115 27.056061 10.128571 26580 42.999512 27.158264 9.435593 26581 50.678299 27.365356 9.745476 26582 50.290298 28.097092 10.329544 26583 50.376343 27.413239 10.297897 26584 31.623262 26.671326 10.442030 26585 33.620438 25.772675 8.847046 26586 32.828491 26.850220 10.268738 26587 35.054199 26.431427 9.491203 26588 34.629189 25.753357 8.968521 26589 33.890602 26.202393 9.388588 26590 33.826782 26.777267 9.916527 26591 35.110313 27.304535 10.371658 26592 37.413811 27.924606 10.580582 26593 43.145920 25.727112 10.374016 26594 43.740768 24.824127 10.433693 26595 44.431091 25.073151 10.256712 26596 44.387146 26.404526 9.521698 26597 45.288269 25.790619 9.541611 26598 50.854492 26.951355 10.570915 26599 53.498138 25.638275 9.298370 26600 53.325989 26.288925 10.165840 26601 2.205829 22.169291 8.863459 26602 2.078002 21.399549 8.398619 26603 2.033962 20.808153 7.861726 26604 2.039046 20.963253 9.002619 26605 2.001728 20.626209 8.783306 26606 2.097206 21.438313 8.976845 26607 2.003244 20.382751 9.281532 26608 34.976173 25.307587 8.575127 26609 45.701645 25.165558 9.438660 26610 52.772964 25.393097 9.007950 26611 52.429337 25.862518 9.627670 26612 55.094086 26.725861 11.021294 26613 55.513367 26.012360 11.975037 26614 56.089798 25.149811 10.233727 26615 1.996211 20.444166 8.423218 26616 1.964564 19.478464 8.439552 26617 1.948317 18.211527 9.096048 26618 1.963262 18.716143 8.134853 26619 1.964204 19.902018 8.907066 26620 45.573639 23.566086 9.559402 26621 56.063004 25.144653 10.839241 26622 56.105652 24.242645 11.034431 26623 1.969634 17.745661 9.935572 26624 2.000537 17.086699 10.438553 26625 1.969366 16.774477 9.763718 26626 56.119858 22.958160 10.933250 26627 40.134064 21.198547 9.513733 26628 40.773087 22.034073 9.717850 26629 39.584656 22.193085 9.968231 26630 42.121674 22.111816 9.633682 26631 41.830643 24.323318 10.529716 26632 41.176880 23.159409 10.117165 26633 44.843170 23.315781 9.679024 26634 43.920990 23.189301 9.772743 26635 43.286194 22.420853 9.484467 26636 1.958718 17.717705 8.502018 26637 39.069244 21.239075 9.881943 26638 41.071716 20.472595 9.546242 26639 1.983462 16.915836 8.188093 26640 39.862473 20.324738 9.703003 26641 39.433403 19.662994 10.256065 26642 40.518677 19.609680 10.639473 26643 42.438950 20.058517 9.686447 26644 41.497131 19.665863 10.069687 26645 43.614243 19.522400 10.619049 26646 52.918518 19.319534 10.871307 26647 2.047162 13.574329 10.331932 26648 47.895004 18.895828 9.295288 26649 48.130814 19.396545 10.535889 26650 47.023651 19.702332 11.189041 26651 47.619720 20.022888 11.956406 26652 50.381439 18.919403 9.451691 26653 34.297195 17.709473 8.153709 26654 2.025594 14.847477 10.342484 26655 34.004738 16.357193 8.497314 26656 33.230545 17.748810 8.987930 26657 42.833481 15.271698 9.049271 26658 43.451904 14.980225 9.028481 26659 31.778704 13.994354 10.039330 26660 40.698257 13.901733 8.727905 26661 40.500565 14.636078 9.636467 26662 40.059097 13.758759 9.306679 26663 44.289215 14.356293 9.017494 26664 44.034363 14.907104 10.010933 26665 38.465469 13.526428 11.015579 26666 38.927872 12.362213 10.259575 26667 39.471016 14.005814 10.376404 26668 40.411560 12.404373 8.743416 26669 50.698212 13.465179 9.291763 26670 51.628998 13.604584 9.230484 26671 39.648712 12.897095 9.576775 26672 45.937347 12.814941 9.666321 26673 44.850861 13.770935 10.109970 26674 53.631226 12.946686 9.259048 26675 31.612192 12.310715 10.623917 26676 34.310089 10.376556 8.194603 26677 39.675102 11.818680 9.504105 26678 40.037537 10.957108 9.111725 26679 40.755188 10.752197 8.385574 26680 55.796982 9.966202 9.740669 26681 34.264519 9.997864 9.228294 26682 35.543549 8.580338 9.046448 26683 39.918655 9.386688 9.075050 26684 49.050659 9.392975 8.212357 26685 39.001907 8.235275 10.007210 26686 39.120712 9.385590 9.799210 26687 47.689392 8.838486 8.458389 26688 47.123199 8.200958 9.242813 26689 48.679672 8.401199 9.004822 26690 49.637543 8.519073 8.344284 26691 55.834000 9.546539 10.669273 26692 55.517044 9.149399 11.531120 26693 36.935890 6.501205 8.028236 26694 36.980667 5.749214 7.866226 26695 40.823944 6.369400 9.170013 26696 44.874847 7.116989 8.554092 26697 53.550964 5.645645 8.470230 26698 48.613907 5.584793 8.417038 26699 48.358765 4.464172 8.245399 26700 53.626038 4.784378 8.821976 26701 53.110138 5.137299 9.881485 26702 36.288788 2.675995 7.828292 26703 36.190979 3.487701 8.421379 26704 47.926239 4.972900 9.273514 26705 47.976501 3.780624 8.532867 26706 56.608994 3.525826 8.437302 26707 56.761917 4.528152 9.617760 26708 56.664505 4.111267 8.879486 26709 57.862488 4.497757 9.282867 26710 57.565796 3.125908 8.748962 26711 57.550507 3.888824 8.699661 26712 1.978607 4.711146 13.333492 26713 1.945530 4.250480 12.701313 26714 1.970672 4.528649 12.209179 26715 35.923737 2.537659 8.212769 26716 42.324158 2.786453 8.893364 26717 39.998901 2.978752 8.068977 26718 43.346558 2.526062 8.174088 26719 56.638168 2.987228 8.440208 26720 58.338806 3.815277 9.056793 26721 58.802277 3.081200 9.604782 26722 59.002625 4.265923 9.825272 26723 2.141954 7.758492 9.766510 26724 36.137253 2.191010 7.945327 26725 35.902786 2.125763 8.248001 26726 37.700745 2.168686 8.660904 26727 36.798370 1.902145 8.975311 26728 36.886612 1.903702 8.344452 26729 43.646622 -0.061966 8.028410 26730 53.527267 0.091415 9.201416 26731 56.676224 2.306458 8.886658 26732 36.312393 1.946320 8.281464 26733 43.621170 1.716812 8.193756 26734 43.224518 0.996597 8.864975 26735 43.599716 -1.093140 7.957611 26736 48.846130 -0.498047 7.878189 26737 49.508926 -0.932617 8.267967 26738 52.955750 -0.825516 9.896599 26739 2.227760 2.715950 8.322538 26740 2.127374 3.596383 9.272093 26741 2.097910 2.613772 9.955273 26742 2.063058 4.976911 10.430017 26743 2.298094 1.302297 8.223984 26744 58.665894 -2.626175 8.375763 26745 59.775726 -1.796967 7.819824 26746 60.347382 -2.953674 7.896362 26747 2.174347 2.235471 9.035746 26748 2.243636 -0.109242 9.439472 26749 2.392774 -1.139570 8.618637 26750 56.937653 -3.383118 8.693398 26751 60.234116 -4.576859 7.926483 26752 2.649876 -3.805426 8.024977 26753 2.481461 -2.302649 8.495913 26754 42.604065 -3.812759 8.022987 26755 2.760046 -5.146602 8.018515 26756 2.840121 -5.066708 7.437168 26757 42.792465 -4.757935 7.322158 26758 53.737732 -4.220459 7.415924 26759 59.781418 -5.804886 7.893234 26760 41.658401 -6.632858 8.389967 26761 40.567886 -6.731995 9.897400 26762 41.079483 -5.262222 9.060806 26763 59.343994 -6.538589 7.197624 26764 41.048447 -8.070786 6.774406 26765 41.418274 -7.859055 7.210998 26766 50.209473 -7.904327 8.891365 26767 49.530487 -8.669128 8.357574 26768 58.567520 -6.658325 8.304993 26769 3.096809 -8.074682 8.059683 26770 40.878204 -8.450729 6.535102 26771 41.744888 -8.290970 7.045585 26772 54.892944 -8.985718 7.617057 26773 55.616943 -8.543991 8.941933 26774 54.741211 -7.889664 10.448776 26775 56.409943 -7.504776 9.880112 26776 57.387482 -7.710083 7.578781 26777 57.056610 -7.630157 8.756712 26778 42.897217 -9.677124 7.425903 26779 42.303802 -8.697266 7.902801 26780 46.596237 -10.857437 8.153633 26781 48.236313 -9.746231 8.591179 26782 54.149658 -9.665298 8.162460 26783 53.115555 -10.672424 7.830627 26784 53.707153 -10.502609 9.333221 26785 52.487915 -11.798218 8.944992 26786 59.769989 -10.756378 7.550537 26787 62.266708 -10.616364 9.424988 26788 61.620514 -10.807434 9.727737 26789 3.709568 -11.214697 7.245002 26790 42.355408 -11.628525 8.298828 26791 42.829468 -10.718185 7.814521 26792 45.830109 -11.471909 7.567283 26793 46.612961 -10.852783 9.356171 26794 52.028549 -12.001419 7.430496 26795 58.989304 -11.105591 8.530022 26796 57.796646 -11.748398 8.049133 26797 44.840973 -12.759720 7.243423 26798 51.414230 -13.049194 8.418762 26799 51.406616 -13.177582 10.093201 26800 56.843781 -12.306595 7.943252 26801 63.667206 -12.829468 7.778213 26802 37.365723 -14.091888 6.848091 26803 37.169296 -14.035614 7.100128 26804 37.366272 -13.884933 7.102996 26805 38.083687 -14.033417 7.002220 26806 40.699097 -13.518463 6.939048 26807 44.029083 -14.221909 7.290512 26808 50.706848 -14.233810 7.331756 26809 55.159576 -14.094238 8.335556 26810 54.923004 -14.891312 8.681641 26811 56.147034 -13.005661 8.345573 26812 63.527054 -13.915115 7.418350 26813 4.287845 -14.402664 7.951545 26814 50.537354 -14.619400 7.300491 26815 54.302277 -16.207718 9.100998 26816 53.360001 -16.859161 8.613167 26817 53.345779 -16.113754 7.647979 26818 63.046204 -14.589096 7.266464 26819 63.982773 -13.106995 8.875992 26820 63.547333 -11.931808 8.738075 26821 4.582854 -15.500494 7.998945 26822 36.822456 -15.653244 7.742218 26823 42.776825 -16.463226 6.984588 26824 54.015350 -15.216980 7.717476 26825 60.690521 -16.027451 7.075698 26826 5.286356 -17.251015 6.840724 26827 44.422943 -12.927200 8.235703 26828 43.824097 -13.425095 9.058670 26829 43.570511 -14.296631 8.401657 26830 52.839096 -16.788010 7.595108 26831 49.607697 -16.288742 7.933784 26832 50.332886 -17.984146 6.968841 26833 51.240463 -18.071381 7.442413 26834 52.378418 -17.150482 7.302719 26835 51.832672 -17.304321 7.023628 26836 59.862839 -16.630280 6.925682 26837 49.644562 -18.064362 7.101425 26838 49.392059 -17.377213 7.421005 26839 49.054626 -18.316849 7.651504 26840 52.074066 -17.679947 7.567382 26841 50.004929 -18.776733 7.576347 26842 48.490234 -19.491043 7.981246 26843 63.323257 -18.844513 7.912857 26844 64.418182 -19.407684 8.470070 26845 35.762573 -20.053162 6.311599 26846 64.375351 -20.152252 7.271240 26847 5.426527 -18.252541 8.320713 26848 5.330679 -18.416983 9.233910 26849 34.192001 -21.851425 6.817482 26850 34.223633 -22.411545 6.608612 26851 35.331604 -20.412949 6.544563 26852 64.739288 -20.151642 8.083008 26853 5.706995 -18.515692 7.183201 26854 7.482124 -21.922348 6.262000 26855 8.172371 -22.669006 5.232500 26856 34.372955 -22.930389 6.646881 26857 35.068497 -23.428284 6.424453 26858 38.847092 -21.088318 6.998626 26859 38.202393 -20.816605 8.004631 26860 37.752563 -21.448669 8.290482 26861 53.825378 -24.361801 6.370863 26862 50.848679 -25.178009 6.014534 26863 53.119537 -25.444550 6.648773 26864 54.929703 -24.255417 6.380493 26865 55.070618 -25.789398 6.818138 26866 56.168488 -25.206482 6.574890 26867 57.508194 -24.771240 6.048874 26868 9.218125 -24.520260 5.919101 26869 50.253448 -26.312424 6.289215 26870 51.988693 -25.198975 6.336242 26871 54.135864 -25.405991 6.743179 26872 58.079437 -27.140198 6.139145 26873 64.057083 -24.278061 8.833893 26874 64.563416 -23.737152 8.842857 26875 64.496246 -23.682877 8.099686 26876 64.078506 -26.179138 6.109542 26877 10.656513 -26.156487 5.301083 26878 10.090314 -25.660727 5.766430 26879 10.800194 -26.585184 5.773414 26880 49.234390 -26.329407 6.020736 26881 51.305542 -26.172943 6.545547 26882 52.236771 -26.622833 6.820579 26883 57.386826 -26.100998 6.380256 26884 63.509003 -25.903091 6.789871 26885 10.925534 -26.478983 5.260489 26886 11.066129 -26.657925 5.270492 26887 48.026840 -27.646576 6.240753 26888 49.255722 -27.470596 6.465042 26889 57.628174 -29.959320 6.194976 26890 57.844788 -28.993057 6.193954 26891 56.966339 -29.182693 6.553650 26892 56.393066 -27.100555 6.695251 26893 62.664825 -26.075333 7.699523 26894 63.417557 -26.976562 6.716598 26895 63.310852 -25.333481 7.507827 26896 46.930511 -28.070679 6.053100 26897 47.829346 -28.422974 6.458389 26898 48.555801 -28.230148 6.568794 26899 57.830566 -28.023376 6.231475 26900 62.779373 -27.661453 7.305389 26901 64.097443 -27.876953 6.116477 26902 62.051331 -27.028854 7.823112 26903 44.768661 -29.315735 5.853531 26904 45.513153 -29.406967 6.153930 26905 46.717422 -29.019363 6.271209 26906 48.815948 -29.896118 6.830604 26907 47.640106 -33.486359 7.524200 26908 48.964325 -32.342865 7.090820 26909 56.712799 -29.897781 6.531585 26910 64.218506 -29.852829 7.544105 26911 12.894665 -28.699120 5.267916 26912 44.139343 -29.966110 5.770896 26913 44.850204 -30.062790 6.146217 26914 57.106827 -30.714096 6.260612 26915 13.073963 -28.916599 5.337367 26916 56.098206 -30.651703 6.588676 26917 56.964828 -31.755630 6.332672 26918 13.773134 -29.684734 5.423400 26919 42.515350 -33.513489 6.292564 26920 44.722321 -31.737320 6.229331 26921 43.982147 -31.933746 6.249160 26922 45.229416 -31.549377 6.137512 26923 45.744324 -30.758591 6.330505 26924 55.843887 -31.920013 6.636917 26925 56.350311 -35.094711 8.326965 26926 56.134933 -36.585449 9.662079 26927 57.218079 -36.266647 9.695404 26928 57.721619 -33.394653 7.008148 26929 59.749512 -32.385376 6.362877 26930 64.327194 -31.808197 7.366508 26931 63.755905 -32.349243 6.579422 26932 63.901352 -32.759583 7.593544 26933 45.282745 -31.881943 6.283576 26934 56.717392 -32.602921 6.499389 26935 13.670617 -30.208107 6.296611 26936 13.599300 -30.435158 6.654411 26937 56.106766 -33.971970 7.353691 26938 13.786016 -30.684849 6.665171 26939 15.476949 -32.424423 6.201237 26940 15.141876 -37.691803 6.580848 26941 41.500763 -36.575516 5.535896 26942 41.266495 -35.046616 6.256698 26943 12.838455 -38.341354 6.134841 26944 13.908798 -37.917648 7.395622 26945 19.531853 -38.292725 5.209854 26946 41.926163 -37.367249 6.129013 26947 48.880890 -38.546951 4.458473 26948 51.614243 -38.388855 4.773232 26949 52.651428 -38.261902 4.869141 26950 53.520386 -38.333405 5.038941 26951 48.548920 -41.406662 5.154091 26952 46.071930 -41.789856 4.917824 26953 54.100403 -39.440491 5.550438 26954 53.276245 -39.310944 5.363396 26955 55.185379 -39.244797 5.576103 26956 59.900803 -38.527878 4.810135 26957 23.092674 -38.889816 5.114121 26958 58.720978 -39.741196 5.807601 26959 59.649658 -40.205765 6.064086 26960 61.016693 -40.041946 5.930099 26961 64.132950 -40.355576 5.600532 26962 63.595581 -41.655182 6.639450 26963 52.498703 -39.922134 5.442703 26964 51.439087 -39.876923 5.257050 26965 53.515198 -40.304581 5.837326 26966 54.573608 -41.103058 6.450630 26967 56.094833 -40.019211 6.115287 26968 58.432556 -41.002991 6.625639 26969 59.833771 -42.340256 7.364563 26970 44.349915 -42.923798 4.999840 26971 50.382339 -40.487549 5.273758 26972 51.906403 -41.171799 5.839241 26973 16.209320 -43.095734 5.041313 26974 43.162750 -42.998276 5.633216 26975 47.740204 -43.182373 5.345123 26976 64.510635 -42.607346 5.843376 26977 10.192627 -44.655579 3.949577 26978 46.914444 -44.226456 5.589859 26979 64.537064 -43.601456 5.807647 26980 19.665329 -45.625595 5.513657 26981 20.853203 -46.261276 5.178726 26982 18.832245 -44.807220 4.956955 26983 44.341110 -44.084091 5.134964 26984 43.853882 -44.099136 5.427384 26985 45.834442 -44.263306 5.508667 26986 44.978378 -43.985077 5.254372 26987 64.072220 -45.045425 5.949417 26988 10.944824 -46.866974 3.936905 26989 44.359894 -44.641113 5.528412 26990 44.824066 -45.188324 6.376205 26991 43.875854 -44.913208 6.049499 26992 56.385818 -46.441376 4.286827 26993 10.960266 -47.699432 4.378761 26994 22.697945 -47.389145 3.911018 26995 17.340164 -48.914856 4.962692 26996 17.048058 -48.005981 3.887329 26997 23.941818 -48.898132 4.489014 26998 62.624741 -49.535324 6.278106 26999 62.840576 -49.150406 6.357437 27000 24.359398 -49.349991 4.536820 27001 24.762466 -49.927277 4.494293 27002 63.083954 -48.412247 6.514228 27003 19.676003 -50.839188 5.740257 27004 19.884727 -50.436356 4.099701 27005 18.765060 -49.770813 4.837586 27006 25.130966 -50.658844 4.377777 27007 25.283401 -51.788681 4.129150 27008 57.566345 -53.692215 6.279006 27009 57.311310 -54.391953 6.343551 27010 57.948257 -54.201813 6.966217 27011 57.590485 -51.978699 4.340225 27012 57.421295 -53.093201 5.269348 27013 58.945709 -53.230530 6.716705 27014 11.583328 -53.491638 3.435761 27015 11.979141 -54.681778 3.492081 27016 11.658127 -55.288406 3.331940 27017 12.032837 -54.084869 3.807564 27018 12.524292 -54.848297 4.143417 27019 12.951935 -53.652618 4.714813 27020 24.783035 -54.414932 4.031189 27021 27.364540 -54.350052 4.547325 27022 26.564171 -51.822281 5.492127 27023 27.585190 -52.284653 5.758628 27024 27.412811 -53.010620 5.137085 27025 11.774110 -55.587784 4.071694 27026 26.799599 -56.131210 4.354897 27027 25.321579 -55.390930 4.327332 27028 28.327766 -54.416519 4.917511 27029 28.010284 -55.298264 4.502022 27030 28.620132 -55.113190 5.071411 27031 28.433365 -56.106812 4.961243 27032 51.335175 -56.112061 4.891678 27033 50.025162 -56.140808 5.040176 27034 50.695435 -55.800583 5.618659 27035 51.810425 -56.567993 4.409767 27036 52.382355 -56.399811 4.675461 27037 52.233887 -56.353241 5.506821 27038 52.502625 -56.956375 4.271820 27039 54.348846 -57.157608 5.140526 27040 54.363495 -57.119904 4.776047 27041 58.534851 -56.376358 7.209121 27042 58.672058 -56.648193 8.974014 27043 58.707993 -55.429611 8.279266 27044 27.993942 -57.305878 4.468948 27045 28.897522 -57.107880 5.751258 27046 47.106873 -56.431168 5.631752 27047 48.431641 -56.892319 4.845963 27048 47.335754 -57.059036 4.754486 27049 49.747742 -55.499619 5.519173 27050 50.083054 -55.491684 5.465530 27051 49.201172 -55.889725 5.670951 27052 50.107239 -57.593002 4.412636 27053 50.978012 -56.682022 4.485809 27054 51.727814 -57.619476 4.148865 27055 48.627838 -58.397751 4.440384 27056 49.948364 -59.144119 4.453621 27057 27.863190 -58.348648 4.195549 27058 27.028778 -57.872589 4.398537 27059 28.547165 -58.219681 4.653916 27060 47.375595 -57.775864 4.532364 27061 46.601303 -57.161423 4.980454 27062 46.247223 -58.058426 4.908569 27063 51.158264 -58.877899 4.187073 27064 10.684013 -59.197495 3.667572 27065 28.383224 -59.650620 4.394928 27066 28.217628 -60.464981 4.561051 27067 27.513161 -59.435410 4.402527 27068 28.266403 -58.995117 4.243164 27069 28.755508 -59.134018 4.784317 27070 47.185242 -58.848343 4.584129 27071 48.038513 -59.384277 4.542420 27072 48.974823 -59.648376 4.533356 27073 54.820984 -57.773392 5.663391 27074 58.465286 -58.443741 4.819031 27075 58.506226 -58.398392 4.015305 27076 11.697998 -60.132660 3.551315 27077 45.843979 -59.139236 5.319779 27078 47.018997 -60.356277 4.797836 27079 48.225708 -60.180496 4.515526 27080 48.144424 -61.057739 4.305275 27081 51.528534 -61.653473 3.935501 27082 52.732742 -60.295395 3.706452 27083 51.762375 -59.933090 4.038361 27084 13.738739 -62.086746 3.919151 27085 14.855011 -61.788788 2.648087 27086 45.064835 -58.145065 5.518112 27087 47.596954 -61.689423 4.365418 27088 46.743896 -61.775513 4.975571 27089 50.845688 -60.028488 4.307907 27090 53.962738 -64.101028 3.344994 27091 50.769897 -64.977417 3.917282 27092 8.917519 -62.411148 3.239464 27093 9.857300 -62.804031 3.318634 27094 49.007782 -62.393082 4.172333 27095 48.884705 -60.771805 4.419403 27096 49.883514 -60.607773 4.382279 27097 6.435600 -63.638306 3.128235 27098 11.156845 -63.428223 3.466034 27099 47.517792 -62.720367 4.628304 27100 46.812744 -62.658966 5.573303 27101 6.791039 -61.232605 6.156456 27102 6.029366 -61.734268 6.237335 27103 7.089363 -62.029388 4.693436 27104 6.242478 -63.209351 4.141243 27105 6.174301 -64.068726 3.577133 27106 6.354981 -64.282944 2.999237 27107 12.171097 -63.581299 4.153206 27108 11.919342 -63.196930 5.120590 27109 10.632523 -63.055771 4.389176 27110 13.666367 -63.947433 2.677216 27111 48.828568 -64.632950 4.306381 27112 48.155701 -63.512756 4.384895 27113 6.609436 -64.930252 3.351242 27114 40.852295 -65.027542 4.292305 27115 40.144791 -64.938644 4.607628 27116 49.539093 -65.619858 4.124481 27117 49.044159 -65.829636 4.469940 27118 43.874359 -67.626663 4.802254 27119 45.116882 -67.502014 3.478653 27120 45.170090 -68.129623 4.076508 27121 48.966583 -66.482376 5.113861 27122 49.925018 -66.612854 4.527359 27123 51.386002 -67.233002 4.251198 27124 10.191544 -67.875931 3.334023 27125 46.070847 -68.614410 3.582001 27126 52.627136 -67.914001 3.917519 27127 6.709679 -69.784714 3.525253 27128 5.231850 -69.374969 3.277123 27129 5.513260 -69.764862 2.803955 27130 11.675903 -69.469391 2.719826 27131 47.415283 -70.021347 3.270142 27132 4.818527 -70.204605 2.682739 27133 11.552811 -70.771332 2.777504 27134 11.716736 -71.841965 2.436493 27135 12.243317 -71.685211 2.186798 27136 40.065460 -70.100235 3.936569 27137 5.729286 -70.329803 2.327683 27138 40.666962 -70.693329 3.950630 27139 40.705078 -70.961609 3.186203 27140 6.662064 -71.049225 2.251289 27141 10.883614 -72.130951 2.433632 27142 9.585205 -72.062408 2.592331 27143 41.380432 -71.507950 3.421860 27144 49.996170 -72.080032 3.985504 27145 49.459106 -72.513992 4.735252 27146 50.335892 -72.238586 4.643654 27147 51.081146 -71.490982 4.050339 27148 51.869461 -70.653717 4.302445 27149 8.371712 -72.042007 2.421372 27150 4.533554 -75.123871 1.276917 27151 3.694954 -71.458527 4.391533 27152 4.087471 -69.980804 3.864349 27153 4.201668 -73.318054 4.678696 27154 4.462898 -74.907043 4.446030 27155 45.607925 -74.461929 3.042801 27156 47.439056 -75.577301 3.097176 27157 10.909164 -79.595016 2.765358 27158 10.077744 -79.770950 2.682434 27159 10.805969 -79.222305 3.335922 27160 8.934448 -80.779739 2.384102 27161 10.405983 -81.079681 2.100868 27162 9.899110 -78.816360 3.355705 27163 38.254684 -81.323318 2.990227 27164 37.648216 -81.355972 3.554886 27165 38.021851 -80.547821 3.541741 27166 44.397980 -80.581543 3.621353 27167 44.519470 -80.255951 4.828156 27168 6.813225 -82.251434 1.571945 27169 10.973526 -80.098526 2.453644 27170 11.737968 -80.838776 2.437042 27171 38.924706 -80.855835 3.028809 27172 38.826363 -80.120590 3.903359 27173 38.853889 -81.632233 2.595299 27174 39.747566 -81.489014 2.627808 27175 43.526108 -81.026749 3.777054 27176 42.296814 -81.423462 3.812866 27177 13.547661 -81.777496 3.068855 27178 14.087289 -82.189270 3.192421 27179 14.029373 -82.652161 2.741837 27180 13.237549 -82.553955 2.346970 27181 38.388466 -82.324402 2.892548 27182 41.083908 -81.604752 2.908432 27183 39.835953 -80.754333 3.670883 27184 40.852234 -81.292587 4.917992 27185 6.644569 -81.383484 2.122467 27186 7.409897 -80.647278 2.664940 27187 7.817749 -81.804092 2.038712 27188 13.697174 -83.656509 2.615967 27189 12.689651 -81.631668 2.486633 27190 12.270493 -84.669724 1.694534 27191 13.329399 -85.036148 2.586388 27192 12.202271 -88.536453 2.810379 27193 13.337654 -88.384781 4.479172 27194 13.309128 -90.247650 4.415390 27195 27.406525 -87.922104 1.843742 27196 38.789780 -87.095795 2.935379 27197 38.705269 -88.540329 3.288429 27198 39.076752 -85.824326 2.965729 27199 11.586319 -89.456696 1.819855 27200 22.374687 -88.618866 1.873215 27201 22.851242 -88.319473 1.811028 27202 26.340630 -88.091629 1.984444 27203 28.825241 -88.391953 1.978348 27204 29.875900 -89.443985 2.072495 27205 21.482437 -89.813171 2.026802 27206 21.811043 -89.283493 1.958328 27207 26.403519 -88.606979 2.744103 27208 29.616699 -88.785629 3.377129 27209 28.429955 -88.208817 3.127434 27210 35.803238 -89.309479 1.649475 27211 16.489212 -90.948181 0.550842 27212 21.467850 -90.414001 2.157005 27213 30.439056 -90.454590 2.153549 27214 35.688332 -90.281509 1.581184 27215 36.756775 -90.070831 2.021645 27216 36.694046 -91.193115 2.129265 27217 36.322983 -92.445450 1.779915 27218 12.956543 -91.413651 1.173020 27219 21.368706 -91.147903 3.045929 27220 30.719604 -91.024475 2.119202 27221 30.838303 -91.384018 1.847115 27222 37.585419 -89.331009 2.469528 27223 37.598068 -90.213898 2.538719 27224 37.862061 -90.683884 3.144379 27225 37.437851 -91.609238 3.173096 27226 13.689278 -92.151108 1.512253 27227 31.301346 -92.748978 2.326889 27228 13.865524 -93.076233 1.622994 27229 36.729507 -92.668640 2.787384 27230 10.221191 -94.400269 1.468308 27231 9.794250 -93.513382 1.976685 27232 9.716301 -94.431274 1.989311 27233 10.706322 -94.433609 1.169579 27234 11.252640 -94.530701 1.029495 27235 10.944611 -93.792679 1.655716 27236 11.895058 -93.447586 2.548676 27237 10.763062 -95.116776 0.987137 27238 10.160500 -95.273087 1.694977 27239 31.260254 -94.926453 1.859650 27240 36.067993 -93.634552 1.777855 27241 31.570068 -95.903473 2.068932 27242 30.824860 -96.163437 1.336998 27243 11.708984 -98.093277 0.876907 27244 31.275909 -97.045776 1.143417 27245 35.495468 -95.005081 2.914032 27246 12.202797 -99.240829 1.033455 27247 23.685806 -100.453506 1.854920 27248 23.576813 -99.866592 2.080765 27249 22.750427 -101.602692 1.720718 27250 23.266609 -101.114746 1.822769 27251 13.558136 -102.059235 1.737640 27252 14.563660 -102.517471 1.907784 27253 14.038155 66.598831 13.354019 27254 12.632217 66.516617 13.610199 27255 16.112717 65.424881 12.714050 27256 15.072174 66.032990 13.591492 27257 14.757446 66.284210 12.499008 27258 11.019958 64.920975 12.648972 27259 15.814423 65.401627 13.763466 27260 11.038345 65.749741 14.218246 27261 16.771698 64.808746 12.427345 27262 17.033646 64.348312 12.396271 27263 10.388809 56.219330 11.387047 27264 16.924370 63.925858 13.109306 27265 10.367218 63.195816 12.287392 27266 9.748917 61.523895 12.491837 27267 23.633926 61.468460 12.706772 27268 24.564133 61.075287 13.982452 27269 23.806152 61.271606 13.342049 27270 10.437820 59.738083 11.871185 27271 16.028221 61.824661 13.893425 27272 25.908249 60.665192 13.134415 27273 25.220520 61.083527 13.704910 27274 10.346146 58.768295 11.876717 27275 23.057289 60.445084 14.286812 27276 22.093567 59.872849 14.188515 27277 21.202972 59.120895 13.429482 27278 10.284714 57.609894 11.715141 27279 21.535980 59.304626 14.223732 27280 21.287033 58.848312 14.190430 27281 6.941170 57.273422 11.541092 27282 5.936089 58.335022 12.024261 27283 7.701393 58.257065 12.190422 27284 6.716896 59.850983 12.746094 27285 16.784363 57.628036 12.127182 27286 20.228821 57.924179 12.583260 27287 7.960479 56.661560 11.487656 27288 10.437531 55.378235 11.104645 27289 19.818268 56.856247 13.260689 27290 18.945023 56.649002 12.101151 27291 3.707924 59.397217 13.725861 27292 3.156921 58.434357 14.446808 27293 3.311508 57.596283 13.225342 27294 4.313675 57.823288 12.145454 27295 9.097351 57.044312 11.880356 27296 8.911591 55.928940 11.408791 27297 17.465775 56.499680 11.920250 27298 16.477600 56.458954 12.868063 27299 17.782394 55.692078 13.033806 27300 18.169037 56.351044 11.776802 27301 3.538315 56.620316 12.230179 27302 3.933159 53.736877 12.508125 27303 9.565582 56.113815 11.643921 27304 18.104401 56.140839 12.134445 27305 25.593147 54.994614 12.659477 27306 35.854080 54.775055 12.346176 27307 36.074791 54.746170 13.285759 27308 35.384827 55.040131 12.956833 27309 32.696259 54.041946 12.358032 27310 3.994270 51.217163 11.049240 27311 24.234131 51.560715 12.461128 27312 25.144577 51.367966 13.054840 27313 25.504051 52.349533 13.263130 27314 4.390503 52.070251 11.986412 27315 22.975006 51.048615 11.521561 27316 23.400497 51.644379 11.753723 27317 31.794901 51.507462 11.811768 27318 33.200195 51.812653 12.879913 27319 39.632126 51.453201 14.045830 27320 40.227051 50.723221 13.727066 27321 3.989822 47.213745 10.400505 27322 4.573975 50.393463 11.105881 27323 4.941597 49.502167 10.916153 27324 6.258209 50.009277 11.726776 27325 5.345856 49.933731 11.358391 27326 5.058060 50.928406 11.721970 27327 23.126511 50.390076 11.773811 27328 23.381790 50.987625 12.015442 27329 32.616791 49.087662 12.087250 27330 33.752357 49.552460 13.428711 27331 42.453888 49.238510 11.966278 27332 5.178001 48.687851 10.957756 27333 6.167626 48.518188 11.299850 27334 23.034729 48.416870 11.425575 27335 3.594353 47.091019 10.016853 27336 23.374771 49.444290 11.770142 27337 32.268494 48.099518 11.727043 27338 32.204529 47.036743 11.845169 27339 32.779404 47.453461 12.538429 27340 32.513596 46.452469 12.623474 27341 43.454865 48.365631 12.188011 27342 4.132034 46.453552 10.735413 27343 4.571076 46.223053 10.964493 27344 31.788286 44.678131 12.759956 27345 32.561203 45.748169 13.421371 27346 32.411591 44.726852 14.199043 27347 5.801773 45.046295 10.575165 27348 12.443481 46.318756 12.227867 27349 12.756256 45.088120 11.508919 27350 11.828903 45.189026 11.114761 27351 12.490433 44.336029 10.868492 27352 7.704895 46.657730 11.190430 27353 9.235313 46.097046 11.059616 27354 10.977692 46.216171 11.494751 27355 13.501289 44.115860 11.546585 27356 31.158417 44.381622 11.736221 27357 6.520081 46.021591 10.920654 27358 24.260796 44.000244 11.184715 27359 25.512054 45.231018 12.305855 27360 24.669685 46.260925 12.000244 27361 25.268326 43.458527 11.542694 27362 46.309967 43.455505 12.546051 27363 14.770264 41.823074 11.778175 27364 15.202805 41.381317 10.883041 27365 15.480164 40.818100 10.866386 27366 29.250595 41.262833 11.527313 27367 30.019218 41.891693 11.716469 27368 15.567856 40.237122 10.495575 27369 28.690437 40.536179 12.238953 27370 27.969559 40.410583 12.533684 27371 28.208237 40.977890 11.485481 27372 27.492302 40.887390 12.159164 27373 15.382523 39.655746 10.714348 27374 43.899277 40.111115 11.489861 27375 4.576012 37.777435 11.845711 27376 3.802651 37.426102 11.996391 27377 5.457817 38.002869 10.874754 27378 6.516678 37.327423 11.196075 27379 7.334915 37.014206 10.900139 27380 12.108887 37.327118 9.915695 27381 12.792549 37.373291 10.799217 27382 14.067566 38.379532 10.613464 27383 40.862595 38.084702 12.069946 27384 47.547028 37.084442 11.252365 27385 48.626740 37.440781 11.319672 27386 3.619194 37.149536 11.167419 27387 37.315964 36.585602 11.927162 27388 36.524628 35.672852 11.107971 27389 36.413055 35.595016 12.338455 27390 38.693970 37.320435 11.449600 27391 45.436951 36.028137 10.877991 27392 46.453522 36.457214 11.327873 27393 51.683716 35.810013 11.894043 27394 11.710159 35.445679 11.991898 27395 10.959259 35.213791 11.252142 27396 44.452209 35.415451 11.146301 27397 4.497238 34.279022 10.227257 27398 5.303803 32.685074 9.919403 27399 39.562668 33.900421 11.110992 27400 41.047852 33.947495 12.031296 27401 51.306290 35.196625 13.022026 27402 35.830765 34.862701 12.712280 27403 51.603943 33.593887 11.985695 27404 2.597287 25.286417 9.211739 27405 5.230744 31.655594 10.214020 27406 2.846942 25.726181 10.247194 27407 2.726939 25.299561 9.955427 27408 2.742519 25.909027 9.526695 27409 3.241401 28.078037 10.228975 27410 3.197460 27.074272 10.916075 27411 3.318175 29.031357 9.716261 27412 50.810913 31.885910 11.865936 27413 4.690193 30.652573 11.032921 27414 5.108482 32.453308 11.088013 27415 49.949722 30.295090 11.622604 27416 49.850922 28.577225 11.411865 27417 38.441193 27.861847 10.493156 27418 39.775551 27.284439 10.726357 27419 52.927002 27.144272 11.197594 27420 33.697311 27.320679 10.713333 27421 32.714973 27.176376 11.059454 27422 34.333572 27.579422 11.431000 27423 35.616623 27.745926 11.353561 27424 33.433617 27.518143 11.363327 27425 41.292908 26.015671 10.880051 27426 44.222794 24.150681 10.118011 27427 45.294647 24.365631 9.825020 27428 44.601578 25.737030 10.030670 27429 50.275818 27.640060 10.842827 27430 2.134068 21.524096 9.315008 27431 2.080972 20.887739 9.561554 27432 2.199900 21.788841 9.483551 27433 2.048445 20.208239 9.847784 27434 45.223038 25.241272 9.912842 27435 51.591797 26.986526 11.251198 27436 55.957443 24.925903 11.683083 27437 2.309132 21.944155 9.948412 27438 2.170481 21.342007 9.783918 27439 1.975873 19.779903 9.430588 27440 43.155579 23.888397 10.178940 27441 1.952236 19.117079 9.226067 27442 38.370697 22.222504 10.352615 27443 37.552330 23.157166 11.048828 27444 37.488632 22.199997 10.681618 27445 39.571342 24.384583 11.118881 27446 40.175797 23.186615 10.308960 27447 40.767578 24.054962 10.661736 27448 28.821404 23.112625 11.828720 27449 38.959465 23.228455 10.682648 27450 37.610504 21.260086 10.515076 27451 1.954041 16.796041 9.002079 27452 1.972202 16.007776 9.211294 27453 37.638542 20.144012 10.879128 27454 38.687424 20.297943 10.217049 27455 30.349907 20.476791 10.176369 27456 55.739990 20.215775 10.753403 27457 56.291687 20.970764 11.308708 27458 28.870316 20.971909 12.153030 27459 32.639458 16.389084 10.306244 27460 32.268356 16.234344 10.834015 27461 31.967272 17.470169 10.495087 27462 36.590866 20.106888 11.471558 27463 36.441162 19.671997 12.130386 27464 37.494400 19.451599 12.124084 27465 39.576424 19.352844 10.872940 27466 38.739090 19.492554 11.206596 27467 39.746819 19.391937 12.070778 27468 42.131363 19.596710 11.323524 27469 40.985245 19.771637 13.047913 27470 46.153030 19.700897 11.250633 27471 49.399567 19.318359 10.403564 27472 50.398117 19.591537 11.075348 27473 51.409531 19.267456 10.342194 27474 2.036369 15.941744 10.760328 27475 41.437317 15.298431 9.985014 27476 42.773987 15.484955 10.169136 27477 43.766632 15.467667 11.107208 27478 32.108025 14.796021 9.929321 27479 33.063049 16.376495 9.515518 27480 40.318115 14.995392 11.247803 27481 44.762329 14.897125 11.149483 27482 50.545578 13.051758 10.564713 27483 52.678223 13.243118 10.074722 27484 51.568893 13.261322 10.337479 27485 49.462952 12.668884 10.973038 27486 54.915558 12.584229 9.788033 27487 55.363708 12.261749 11.212204 27488 54.100250 12.847427 10.741768 27489 47.060089 12.455933 10.191589 27490 56.198654 11.269302 11.297653 27491 55.929443 11.743958 11.946762 27492 32.951370 10.276581 10.435455 27493 39.257507 10.629593 9.829117 27494 56.204636 10.416656 10.678520 27495 34.979691 9.369186 9.220131 27496 35.919746 7.206894 9.239098 27497 34.486755 9.038422 9.924271 27498 35.030273 7.561050 10.219574 27499 39.732910 7.944473 9.323212 27500 38.796013 8.974335 10.181534 27501 45.295715 7.033051 9.581207 27502 45.906860 7.657333 9.320908 27503 2.144270 8.141315 14.320351 27504 2.102063 6.937605 15.108692 27505 2.045159 5.517056 14.595108 27506 44.451889 6.484467 9.467361 27507 53.645081 6.850037 10.040611 27508 36.447105 6.060822 8.721786 27509 39.503693 6.684280 9.984154 27510 39.108047 5.908951 10.548935 27511 39.716087 5.674263 10.365471 27512 43.302795 5.955734 9.586075 27513 40.526657 5.856705 9.720863 27514 52.977539 6.257996 10.786369 27515 57.522964 4.898834 9.767090 27516 58.159729 4.906387 9.938139 27517 58.729935 5.109955 10.768028 27518 47.423264 3.431534 9.460167 27519 52.649673 4.437714 10.615639 27520 52.531921 4.997208 10.571014 27521 59.734589 4.617371 10.514702 27522 59.844498 5.201187 11.282425 27523 2.078950 7.166482 10.465267 27524 2.075606 7.260463 11.257902 27525 35.539040 3.622780 10.066689 27526 35.963745 2.359619 8.995819 27527 39.125839 2.551865 9.006477 27528 40.710144 2.924698 9.137917 27529 55.541016 4.092178 10.190865 27530 55.692963 4.140839 11.285477 27531 54.097855 3.635979 10.888634 27532 57.141449 4.813171 10.449837 27533 57.303238 4.996460 11.628609 27534 2.069997 6.482764 10.362957 27535 46.913177 2.170975 10.002098 27536 47.475372 0.802246 9.081421 27537 57.925644 2.229599 9.592987 27538 36.503067 1.907593 9.977493 27539 43.064011 2.032303 8.968826 27540 47.967911 -0.507614 8.538483 27541 42.985809 -0.291946 9.158989 27542 47.007874 0.037933 9.519020 27543 46.972198 -0.962479 9.441452 27544 48.019531 -1.557709 8.880402 27545 42.377213 -1.305847 9.733025 27546 47.217636 -1.789062 9.258507 27547 49.578156 -2.046173 9.290726 27548 50.998825 -2.017105 10.028023 27549 52.066559 -1.458130 10.120110 27550 59.392349 -3.936966 8.679184 27551 2.039897 3.064789 10.622355 27552 2.201212 1.067374 9.315136 27553 47.798401 -2.552155 9.462875 27554 48.871964 -3.087860 9.958405 27555 49.973190 -2.857208 10.377464 27556 2.439872 -3.201768 9.274832 27557 2.242514 -1.315522 10.068764 27558 41.870819 -2.915009 9.199448 27559 58.157074 -4.470932 9.295593 27560 56.567505 -4.432663 9.593048 27561 41.455872 -4.176071 8.892029 27562 41.834381 -5.034561 8.437088 27563 41.974091 -4.075470 8.507339 27564 42.325012 -4.682571 8.025024 27565 53.473297 -5.231354 8.942528 27566 54.781021 -4.341904 8.794724 27567 55.808472 -3.964218 8.925171 27568 59.238495 -5.255646 8.740425 27569 2.649321 -5.046002 8.785290 27570 52.124924 -6.052704 9.023209 27571 52.897125 -5.836349 9.715668 27572 53.884842 -5.731766 10.142204 27573 41.739288 -7.778503 7.751342 27574 41.966202 -7.896179 8.817337 27575 57.438477 -6.336029 9.764877 27576 57.990463 -5.427155 9.775711 27577 58.431534 -5.673401 9.335678 27578 41.515320 -7.572083 9.855698 27579 2.639975 -6.422324 9.854069 27580 2.734390 -7.142966 9.783661 27581 2.811385 -6.685080 8.824127 27582 2.946072 -8.082490 9.117340 27583 3.199931 -9.339748 8.641928 27584 42.675003 -9.680679 8.686737 27585 42.308960 -8.791138 9.134544 27586 50.753693 -7.188004 9.234192 27587 54.826965 -9.175461 8.521729 27588 3.415869 -10.954341 9.112354 27589 3.762709 -12.776134 9.168808 27590 4.052003 -13.694018 8.438034 27591 45.529816 -11.597198 8.607742 27592 58.413956 -11.666870 9.398888 27593 57.510651 -12.241730 9.098694 27594 41.501740 -12.794373 7.866943 27595 41.882080 -12.367783 8.235725 27596 37.457779 -14.258621 7.662796 27597 39.199692 -13.872299 8.308990 27598 38.513153 -14.280655 9.733353 27599 40.414902 -13.486908 10.135239 27600 40.688797 -13.325851 7.846466 27601 56.821426 -12.646225 8.782990 27602 57.033447 -13.036896 9.769104 27603 63.492279 -14.462067 8.543213 27604 37.007782 -14.798035 8.573730 27605 37.745819 -14.342621 8.787262 27606 35.977936 -16.320801 8.636993 27607 36.451950 -15.374756 8.972481 27608 50.477951 -14.635208 8.303741 27609 55.411194 -13.562042 8.096741 27610 4.207080 -14.444088 8.706829 27611 4.059489 -14.197917 9.368469 27612 4.432806 -15.507889 9.150311 27613 42.856171 -15.661026 8.641487 27614 62.632233 -15.015930 7.787475 27615 62.509857 -15.520996 8.328682 27616 4.913200 -16.381287 7.471858 27617 41.695084 -16.648193 10.000031 27618 43.109314 -15.453156 10.150764 27619 41.981628 -16.852402 7.987312 27620 52.650452 -17.403717 8.099190 27621 61.607224 -16.480286 8.307831 27622 36.916771 -17.061707 7.017257 27623 40.648941 -18.051208 7.580429 27624 48.875244 -17.565674 8.736275 27625 49.570160 -16.208389 9.134186 27626 52.933517 -17.771255 9.141541 27627 39.846085 -18.666168 7.696762 27628 48.468506 -18.501602 8.204086 27629 51.090881 -19.166382 8.555756 27630 38.873398 -19.568100 7.986633 27631 39.241661 -18.262726 9.090019 27632 38.591309 -18.881500 8.943771 27633 62.425964 -18.173721 8.328506 27634 35.518372 -19.331284 7.278198 27635 48.040817 -18.760330 8.952690 27636 48.287933 -20.482117 7.817131 27637 47.842834 -20.296967 7.790306 27638 49.191193 -20.526337 8.271500 27639 48.252472 -21.303635 8.106186 27640 49.888367 -19.696869 8.167618 27641 63.819397 -18.273407 9.221237 27642 33.789566 -22.486572 7.624687 27643 33.871468 -21.436310 7.626678 27644 47.644043 -20.901627 7.869277 27645 47.274109 -20.295929 8.390320 27646 46.882111 -21.313568 8.373383 27647 47.549866 -21.439774 8.009567 27648 34.419342 -23.474548 7.290267 27649 33.876602 -23.339081 7.876716 27650 37.439713 -22.958267 7.539703 27651 36.576447 -23.926559 7.424392 27652 36.174667 -24.172028 7.273559 27653 34.308380 -23.920776 8.122955 27654 35.383255 -24.082321 7.388939 27655 37.033165 -23.496735 7.216262 27656 63.845428 -24.558670 7.714645 27657 10.134334 -26.381586 6.965757 27658 10.076015 -26.573387 7.438529 27659 10.780417 -26.937174 6.468012 27660 53.827759 -27.578232 7.053810 27661 53.316193 -28.856232 7.420837 27662 53.821457 -29.121246 7.302566 27663 50.577682 -29.212891 7.263618 27664 51.575455 -28.952316 7.350791 27665 50.871780 -27.800156 6.880209 27666 55.648178 -29.005829 6.823669 27667 56.948135 -28.381363 6.588295 27668 52.218140 -27.969910 7.129562 27669 10.051941 -25.998924 6.479809 27670 62.245987 -27.838211 7.816864 27671 61.400192 -27.730347 8.394743 27672 11.755373 -27.990051 6.245561 27673 10.721741 -27.318199 7.215580 27674 10.603279 -27.563906 7.866042 27675 11.123986 -27.750244 7.090435 27676 50.292389 -29.807587 7.243087 27677 50.011475 -31.473404 6.953094 27678 49.621429 -32.910370 7.221313 27679 50.595825 -32.672928 7.195053 27680 54.399338 -29.024643 7.104263 27681 62.916565 -28.207428 7.550468 27682 12.749636 -28.853203 5.826861 27683 12.711565 -28.609364 5.456750 27684 12.329757 -28.845018 6.550807 27685 13.276277 -29.609203 6.105338 27686 54.352158 -30.591431 6.991622 27687 11.952635 -28.868694 7.256346 27688 11.548966 -28.350412 7.212307 27689 46.242493 -32.297287 6.846420 27690 51.223480 -31.124908 7.081314 27691 50.365921 -30.388885 7.104652 27692 52.056458 -29.968292 7.354599 27693 51.077545 -29.894440 7.329643 27694 52.536209 -31.294083 7.094276 27695 53.119476 -29.775711 7.354721 27696 64.535233 -30.941956 7.954177 27697 64.503769 -30.285599 8.854774 27698 12.536427 -29.441982 7.067836 27699 51.571823 -32.418503 7.129234 27700 52.254105 -32.852570 7.277176 27701 53.338806 -32.581894 7.225128 27702 54.707672 -32.685028 7.055725 27703 56.058060 -33.137527 6.864059 27704 44.249634 -32.944962 6.680717 27705 47.015671 -35.651947 8.349060 27706 48.199112 -35.704041 8.468216 27707 43.857513 -36.097778 8.771423 27708 44.580643 -37.117310 9.075195 27709 45.477539 -35.154312 8.097672 27710 55.174255 -33.661438 7.360946 27711 58.430832 -35.518265 9.039215 27712 61.009293 -35.035339 8.521568 27713 16.464270 -32.860752 5.596381 27714 17.307814 -33.301117 5.178805 27715 21.172188 -36.608913 4.932088 27716 41.220184 -35.920731 6.297790 27717 22.813671 -36.640564 3.876503 27718 41.378906 -36.632187 6.298584 27719 18.093948 -38.089432 6.166305 27720 42.109619 -37.464813 7.720367 27721 12.749405 -39.353317 5.279648 27722 21.276123 -38.761459 5.807815 27723 21.899275 -37.839100 5.204836 27724 42.686508 -39.684814 6.148666 27725 12.357896 -40.318176 5.644127 27726 12.090134 -39.366119 5.953681 27727 11.476120 -40.155945 6.313202 27728 42.607941 -42.615097 6.217453 27729 53.085953 -41.129990 6.095504 27730 55.489532 -42.872604 7.338211 27731 54.235870 -42.676041 7.084320 27732 56.732895 -41.521729 6.878616 27733 59.017624 -42.975540 7.610504 27734 12.123581 -41.669830 6.455635 27735 15.013306 -42.513123 5.400864 27736 43.282867 -44.282761 5.966499 27737 51.349014 -42.110077 6.083190 27738 50.113617 -42.613052 5.948150 27739 42.686340 -42.978485 6.238937 27740 51.477539 -43.264450 6.659889 27741 52.866806 -42.509552 6.704406 27742 10.549911 -44.592499 4.836777 27743 42.830887 -43.614456 6.338134 27744 48.972565 -43.393936 5.806205 27745 49.796692 -43.595779 6.182464 27746 50.509857 -43.741104 6.548057 27747 49.636597 -44.721741 6.496368 27748 52.595047 -44.199341 7.290740 27749 64.194092 -43.546631 6.607971 27750 10.407249 -45.115250 4.870178 27751 10.682777 -45.013474 5.139427 27752 12.460190 -45.498657 4.776886 27753 16.908447 -44.022385 5.657928 27754 17.856552 -44.611374 5.771240 27755 42.937897 -44.498322 6.521515 27756 46.176239 -45.222992 6.398925 27757 48.180374 -44.460068 5.925231 27758 48.553619 -45.203110 6.286819 27759 63.621124 -44.365738 7.283798 27760 63.618347 -43.397781 7.388969 27761 10.771362 -45.633301 5.140640 27762 10.909409 -46.806076 5.137543 27763 17.866852 -45.019760 6.528076 27764 18.694275 -45.406067 6.393631 27765 43.289474 -44.981583 6.463439 27766 43.657715 -45.318726 6.755508 27767 47.565430 -45.583160 6.727668 27768 18.608109 -46.104141 7.917205 27769 19.881256 -46.281830 6.840393 27770 22.370804 -47.625305 5.640625 27771 21.605530 -47.400620 7.161453 27772 22.435333 -48.102585 7.734581 27773 10.951355 -47.698227 5.178101 27774 63.814392 -46.581985 6.360481 27775 63.505707 -47.383881 6.702568 27776 11.181969 -48.603210 4.962868 27777 11.364220 -50.363571 5.158386 27778 16.069695 -48.236343 5.106033 27779 14.935768 -47.594147 5.131760 27780 14.979141 -48.901016 6.536819 27781 14.884491 -48.300919 5.958892 27782 16.174881 -48.964218 6.142288 27783 23.488892 -48.530884 5.309792 27784 23.656174 -48.736664 6.587409 27785 24.421280 -49.414597 5.429054 27786 25.433746 -50.624573 5.230675 27787 20.980515 -51.779587 5.326882 27788 62.007843 -50.271606 6.045410 27789 12.018768 -53.226334 4.215714 27790 11.335663 -49.694000 5.312927 27791 60.131897 -52.369598 6.475525 27792 60.950378 -51.501221 6.172416 27793 12.524445 -52.223419 5.086968 27794 13.780350 -52.627563 5.723312 27795 13.712326 -53.816910 5.413590 27796 28.047935 -53.623184 5.038231 27797 28.174416 -52.832092 5.607955 27798 28.524849 -53.504639 5.512306 27799 57.129715 -54.122452 5.758453 27800 61.121292 -51.997955 7.379028 27801 13.349525 -54.685287 4.907539 27802 23.914330 -55.244492 4.701859 27803 22.704338 -54.559525 4.990677 27804 12.547966 -55.451355 4.765869 27805 13.367798 -55.259521 4.839707 27806 13.117409 -55.236069 4.626610 27807 20.398796 -56.001251 5.026627 27808 19.549385 -54.879578 5.450775 27809 21.186569 -54.431229 5.376007 27810 49.927048 -55.293549 5.640869 27811 50.089874 -55.455444 5.780174 27812 57.741119 -55.318527 5.928161 27813 57.608017 -54.899948 6.701309 27814 9.887772 -56.008224 5.415329 27815 10.223389 -56.613312 4.401024 27816 11.238494 -55.737762 5.042069 27817 9.630630 -56.574524 4.981468 27818 13.159592 -55.440186 4.815155 27819 18.407242 -56.278351 5.271164 27820 18.168594 -54.688660 6.047683 27821 18.502090 -57.592133 4.936218 27822 17.137543 -57.498718 5.406082 27823 20.117462 -57.300659 4.883423 27824 18.903366 -53.741898 6.161331 27825 19.885979 -53.383316 5.934745 27826 45.983505 -56.558731 5.793823 27827 48.147125 -56.135468 5.993063 27828 53.588882 -57.156891 5.765060 27829 16.618065 -56.525757 5.955406 27830 17.244423 -55.471436 6.093811 27831 25.868561 -57.506683 4.771278 27832 29.055794 -58.277328 5.901000 27833 45.585052 -57.256241 5.346115 27834 45.146759 -56.667419 5.915077 27835 19.095398 -59.405823 5.147095 27836 17.794708 -58.612335 5.357750 27837 19.414970 -58.462234 4.874970 27838 22.347610 -56.441650 5.064041 27839 24.878647 -56.603882 4.853882 27840 24.470963 -58.347977 5.062409 27841 26.212372 -58.943863 4.722687 27842 44.578949 -57.273834 5.855636 27843 59.012970 -57.748337 5.584625 27844 20.068314 -59.498260 4.981278 27845 19.943573 -59.091156 4.876511 27846 21.245392 -59.043304 5.060539 27847 25.208214 -60.258133 5.078842 27848 29.136894 -59.388855 5.815284 27849 44.541199 -59.224274 6.258354 27850 55.670212 -58.926117 6.388801 27851 56.591217 -59.043243 5.829620 27852 58.832153 -57.659439 6.492065 27853 59.185303 -57.518967 6.178512 27854 20.041534 -60.479874 5.277908 27855 26.448708 -60.400421 4.831574 27856 27.340302 -61.034256 4.631592 27857 28.821152 -60.180801 5.026787 27858 57.740082 -58.704834 5.812774 27859 13.397041 -62.294769 5.097046 27860 12.744141 -61.386810 5.194077 27861 11.026611 -59.897614 5.205284 27862 11.956497 -60.626221 4.662537 27863 12.667802 -60.854263 3.850403 27864 28.040726 -61.541855 4.682449 27865 28.589996 -61.170105 4.966721 27866 8.908859 -62.321167 4.181213 27867 13.493118 -62.948532 4.744095 27868 26.717407 -62.130188 4.931320 27869 26.520538 -61.303207 4.903412 27870 27.475533 -61.840714 4.663246 27871 27.604767 -62.359116 4.864090 27872 9.657822 -62.467026 5.119911 27873 9.478363 -62.108871 6.214653 27874 8.432549 -61.820908 5.332947 27875 13.396088 -63.480087 3.838204 27876 46.321564 -61.893860 5.560036 27877 47.595871 -64.055206 5.162338 27878 48.355606 -65.411377 5.077995 27879 47.817062 -65.004135 5.854667 27880 6.172836 -64.116074 4.745171 27881 38.170563 -65.895569 4.703789 27882 39.267738 -65.081650 5.568131 27883 7.085281 -65.255219 4.874992 27884 8.106659 -66.003510 4.828537 27885 40.560913 -65.311310 5.504364 27886 41.660721 -65.990479 5.237938 27887 10.055496 -67.463837 4.562500 27888 37.882240 -66.893677 5.566879 27889 49.561371 -67.249374 5.157036 27890 5.261604 -68.456985 4.153168 27891 4.957131 -68.824219 3.853684 27892 5.635567 -68.832657 3.807091 27893 9.520103 -66.921341 4.598633 27894 50.479950 -68.298447 5.257629 27895 49.114685 -67.425781 6.008644 27896 52.628296 -68.709915 4.002091 27897 51.916000 -68.838608 4.489151 27898 51.322144 -69.549713 5.170014 27899 4.577423 -68.648285 4.771431 27900 5.845856 -68.637939 4.529511 27901 7.618423 -69.217621 5.001808 27902 6.726273 -68.773468 5.007332 27903 11.136681 -69.400131 3.561554 27904 38.028923 -68.093643 5.824935 27905 3.658661 -69.434479 4.682610 27906 39.056259 -69.043427 4.811012 27907 39.853104 -70.161026 5.013352 27908 46.461395 -70.314682 4.460007 27909 52.087875 -69.928253 4.405396 27910 7.533798 -71.192734 2.744446 27911 8.758621 -70.839493 3.418640 27912 10.195068 -71.221451 3.101921 27913 10.205505 -70.239288 3.840515 27914 10.428192 -69.298325 4.614914 27915 9.958481 -69.881363 4.553825 27916 40.735275 -70.959564 4.867737 27917 41.455261 -71.742020 4.534386 27918 45.221527 -69.188019 4.913040 27919 45.695648 -70.562119 5.541374 27920 8.132675 -69.880753 4.339333 27921 47.700882 -72.072601 4.985024 27922 47.389984 -71.255997 4.391358 27923 46.628983 -71.726181 5.818634 27924 47.560806 -72.686050 6.117065 27925 42.885117 -73.216995 4.339554 27926 43.124084 -74.345428 5.197609 27927 42.273773 -72.998825 4.821152 27928 41.763580 -73.841660 5.766876 27929 44.733276 -74.676193 4.153130 27930 45.698746 -75.720703 5.221893 27931 46.414429 -75.452301 3.920029 27932 4.817597 -76.321228 3.086701 27933 4.695694 -75.721741 3.955002 27934 44.392029 -75.285767 5.507401 27935 44.996445 -76.076431 6.679046 27936 47.442230 -76.639969 4.013664 27937 46.833664 -76.214737 4.932076 27938 9.949806 -78.193161 4.033997 27939 10.658516 -78.589493 4.313080 27940 47.389740 -77.973679 4.432419 27941 6.382103 -78.198746 3.593025 27942 8.480904 -79.258652 3.044006 27943 8.281769 -77.915787 3.637634 27944 9.188835 -78.177383 3.519501 27945 11.362236 -79.235001 4.170471 27946 12.016998 -79.968781 3.847092 27947 11.491257 -79.744995 3.126801 27948 6.332436 -79.683731 2.977547 27949 7.123917 -78.776108 3.412682 27950 7.163696 -79.773468 3.109848 27951 6.529717 -80.859375 2.570541 27952 6.581520 -80.392792 2.841866 27953 12.026566 -80.170837 3.126961 27954 12.493027 -80.678436 3.164040 27955 37.955391 -79.785141 4.465027 27956 39.168991 -80.262833 5.048782 27957 46.395584 -79.161865 4.199936 27958 45.750458 -79.382477 5.435898 27959 13.013985 -81.160736 3.171372 27960 37.128891 -80.393600 4.143356 27961 36.986298 -81.236038 4.041298 27962 42.765121 -81.293991 4.920555 27963 43.258499 -81.112671 6.155494 27964 14.424881 -82.682495 3.280830 27965 37.333267 -82.259140 3.967041 27966 14.374290 -83.154526 2.896591 27967 15.190628 -83.542892 3.963669 27968 14.746185 -83.419205 3.425163 27969 14.837219 -82.831406 3.971710 27970 14.762627 -84.682281 4.230805 27971 13.198517 -86.104233 3.029907 27972 38.812210 -84.447403 3.527443 27973 13.580521 -87.020111 4.192139 27974 13.943085 -87.716248 5.344185 27975 38.946396 -85.145844 3.665268 27976 39.121193 -87.868195 3.590073 27977 38.829422 -87.514465 4.330223 27978 12.414383 -87.174805 2.612930 27979 23.184479 -88.700714 2.325592 27980 25.736298 -90.429565 2.600243 27981 26.366882 -89.542389 2.954453 27982 27.214317 -88.221054 2.920685 27983 27.843727 -88.280182 3.823334 27984 38.863441 -86.184601 4.004273 27985 12.281219 -89.796600 2.732178 27986 21.554321 -89.875153 3.001953 27987 22.183884 -89.112350 2.745697 27988 23.859070 -89.492111 2.789429 27989 24.641960 -89.983322 2.577499 27990 22.911583 -89.340576 3.177376 27991 23.481255 -90.396851 3.617546 27992 29.072922 -88.365601 3.807510 27993 30.802383 -90.228714 3.582977 27994 38.296127 -89.734665 3.232292 27995 38.628441 -89.189133 3.971130 27996 24.117538 -90.206894 2.952782 27997 27.057846 -90.274734 3.847748 27998 27.052681 -88.928696 3.752289 27999 26.711388 -90.578888 2.990822 28000 30.675507 -90.837021 2.658722 28001 13.227722 -91.529831 2.210213 28002 26.570389 -91.291107 2.735718 28003 27.277954 -91.369186 3.261276 28004 30.943192 -91.495102 2.541061 28005 37.801926 -91.089462 3.859467 28006 9.191612 -92.866882 2.650833 28007 10.016059 -92.306824 2.633720 28008 9.020004 -91.596786 3.333634 28009 9.734528 -92.759827 2.229340 28010 10.270172 -92.927521 2.095703 28011 10.958260 -92.381378 3.232445 28012 10.092002 -91.677673 3.246834 28013 13.768143 -92.501007 2.261917 28014 21.693497 -92.316513 2.676346 28015 24.624336 -90.872925 2.965691 28016 24.508110 -94.861969 3.857208 28017 24.357925 -93.360550 3.789452 28018 23.702827 -94.700531 5.046997 28019 25.590561 -92.048172 2.844170 28020 26.902481 -92.001434 2.833450 28021 9.336792 -93.964035 2.459152 28022 10.500549 -91.483154 3.830719 28023 10.867050 -92.916367 2.391525 28024 26.891006 -92.857178 2.861282 28025 28.535439 -94.578842 3.942062 28026 28.849045 -93.157059 4.726151 28027 28.028267 -93.025177 3.677002 28028 27.682701 -92.247635 3.404495 28029 37.181458 -92.143799 4.001129 28030 36.184555 -93.799576 3.775810 28031 13.858353 -93.243835 2.206665 28032 13.683136 -93.520859 2.705361 28033 13.952408 -92.924530 2.713837 28034 25.797272 -94.474091 2.674461 28035 25.697853 -93.481079 2.799362 28036 25.059982 -94.291382 3.093918 28037 26.994507 -94.129715 2.864067 28038 32.172478 -93.518784 3.240730 28039 36.101700 -93.990433 2.665802 28040 9.669159 -95.022171 2.708916 28041 10.240555 -96.091782 2.307152 28042 21.100082 -93.684525 4.170921 28043 20.777908 -92.443436 4.273666 28044 21.204773 -92.217697 3.609741 28045 27.003319 -96.631302 2.941734 28046 26.783203 -95.896317 2.639160 28047 26.127121 -96.279068 3.038773 28048 26.386063 -95.260284 2.666168 28049 27.335770 -95.472595 2.878441 28050 32.539459 -96.263733 2.232605 28051 32.368332 -95.235077 2.783890 28052 33.525383 -95.778198 2.815033 28053 23.181030 -98.939651 2.314995 28054 25.327881 -95.455322 3.213181 28055 31.604616 -96.580032 1.735260 28056 33.647308 -96.377151 1.942993 28057 10.720581 -97.356018 2.772431 28058 10.096778 -96.198334 3.296677 28059 11.176544 -97.983688 1.960838 28060 26.097519 -97.534744 3.573532 28061 27.140411 -97.827164 3.534866 28062 34.482368 -95.826248 2.581658 28063 35.402832 -95.028366 3.539993 28064 35.724960 -94.721008 3.590302 28065 11.670609 -99.040665 2.008743 28066 22.262352 -97.991913 3.394798 28067 23.033943 -100.194763 2.815003 28068 12.572144 -100.988617 1.914581 28069 12.999924 -101.552383 1.813751 28070 17.268250 -101.994888 2.903061 28071 17.933723 -101.842209 2.550064 28072 18.624023 -102.291168 1.656342 28073 20.976501 -101.504440 2.947411 28074 22.408020 -101.251251 2.706116 28075 15.741196 -103.015747 1.927742 28076 16.302444 -102.995316 2.357124 28077 16.308304 65.085419 13.578239 28078 16.678894 64.723801 13.095009 28079 9.555527 65.280762 15.041229 28080 8.407036 65.370331 15.572861 28081 8.517059 64.621582 14.489937 28082 8.382538 60.307358 12.885384 28083 8.819092 62.464203 13.179855 28084 9.595764 64.219208 13.662170 28085 16.639488 60.117630 12.870995 28086 4.564049 61.279419 14.062454 28087 5.574783 60.651917 13.273392 28088 5.577751 61.711334 13.858269 28089 5.811600 59.618835 12.643913 28090 4.429482 60.364868 13.541405 28091 6.912392 61.908249 13.564728 28092 9.661530 60.321075 12.544182 28093 9.731369 59.502502 12.432854 28094 26.698471 58.380646 13.249329 28095 4.938271 59.438232 12.793472 28096 9.167358 58.737030 12.363754 28097 9.135483 59.727814 12.747284 28098 16.509293 58.739426 12.719643 28099 3.213867 59.466904 14.753731 28100 3.572106 60.683212 15.404800 28101 16.069489 57.846359 13.022758 28102 15.990913 59.054413 13.325783 28103 20.776070 57.857559 14.050034 28104 3.210716 56.182434 13.248283 28105 15.375434 58.488922 13.726608 28106 26.619186 57.061096 13.232590 28107 26.447174 55.520584 13.375816 28108 16.554138 55.741547 13.282784 28109 16.441040 55.399872 14.008362 28110 19.105659 56.027298 13.144836 28111 15.361176 56.993790 13.847565 28112 17.325867 54.971863 14.196800 28113 18.840286 55.383362 13.606812 28114 25.729401 53.990295 13.153885 28115 33.419792 53.584595 12.920898 28116 34.634979 55.008392 12.982697 28117 36.630417 54.539642 13.048515 28118 38.403786 53.378357 13.010033 28119 3.434021 55.110382 13.276611 28120 24.712952 52.991714 12.574921 28121 32.378525 53.227325 12.286858 28122 34.301552 54.371170 13.340996 28123 34.954643 53.034531 14.161827 28124 35.354111 54.458633 13.709908 28125 35.693153 53.827164 14.324760 28126 38.817139 52.817154 13.118568 28127 31.914278 52.363327 12.037544 28128 5.319977 51.661743 12.310120 28129 6.657860 51.055267 12.334837 28130 7.660797 51.910553 13.258797 28131 8.309021 50.907700 12.797356 28132 8.311493 49.230103 11.994347 28133 5.657097 52.416946 12.914131 28134 7.082489 53.171524 14.195709 28135 9.173400 51.484360 13.705399 28136 9.574883 49.625641 12.390663 28137 9.486099 50.336853 13.006668 28138 10.535042 48.695953 12.642258 28139 23.935768 50.343475 12.304871 28140 25.149666 50.603165 12.921043 28141 24.465340 48.386597 12.201332 28142 33.200302 48.329437 12.844643 28143 42.641861 48.885071 13.281021 28144 43.462234 48.242584 13.206810 28145 5.292122 46.323273 11.032669 28146 24.943253 49.512955 12.642319 28147 26.251007 48.674896 12.923225 28148 27.901398 48.963226 13.620148 28149 26.802750 50.058273 13.387428 28150 33.379913 47.233444 13.838036 28151 44.038666 47.490677 13.120941 28152 44.859177 46.154160 13.671494 28153 44.018890 46.945496 14.426727 28154 11.657043 47.426910 12.263168 28155 25.943886 47.294327 12.655396 28156 25.881447 46.265137 12.537506 28157 11.701637 48.497711 13.470345 28158 12.257004 47.865707 13.381607 28159 11.760643 48.128189 12.829796 28160 13.245827 45.250244 12.044670 28161 32.128952 45.599014 12.593224 28162 45.693680 44.780853 13.255409 28163 13.577194 44.845901 12.347015 28164 14.542305 42.612854 11.832718 28165 25.649246 44.136215 12.149033 28166 31.120407 43.614639 12.363388 28167 14.190872 43.227295 11.973686 28168 26.084000 43.451660 12.149879 28169 27.012344 44.363739 13.066437 28170 14.633057 41.241714 12.560783 28171 14.711548 40.076294 11.561668 28172 26.798485 42.665894 12.817863 28173 27.039253 41.468781 12.429588 28174 45.710724 40.944031 12.633850 28175 46.361908 41.966583 12.575333 28176 29.253494 40.601471 12.898331 28177 43.855865 39.564545 12.613983 28178 44.725739 40.207123 12.604248 28179 13.856262 40.348999 12.775879 28180 12.980698 38.996063 12.466782 28181 42.931488 39.157074 12.288956 28182 44.293457 39.479218 13.602486 28183 3.506973 36.466660 11.700142 28184 3.485413 36.672516 13.199432 28185 5.461052 37.362549 12.225700 28186 13.473953 38.306076 11.476173 28187 39.718605 37.394653 12.668915 28188 40.868835 37.681717 13.188065 28189 48.244064 36.954163 13.260666 28190 48.339691 37.146973 12.187851 28191 7.210236 36.748596 11.524313 28192 12.691986 37.637772 11.918167 28193 12.207038 36.695404 11.932152 28194 37.178162 36.316498 13.175209 28195 47.445663 36.769394 12.238884 28196 51.324844 36.181564 12.557167 28197 3.860931 35.358459 11.244659 28198 10.926712 34.741364 11.801598 28199 45.459946 35.704498 11.970581 28200 46.609375 36.236252 12.918877 28201 4.405060 34.066513 11.655266 28202 6.444603 36.760971 12.386711 28203 5.706154 36.872131 13.639549 28204 11.146210 34.703079 12.486084 28205 44.695953 35.215942 12.115631 28206 43.905090 34.773682 12.227501 28207 42.447906 34.071228 12.656425 28208 10.276741 34.865875 11.564369 28209 39.300407 33.342316 12.644066 28210 40.139465 33.715942 12.013802 28211 40.718491 33.426697 13.137482 28212 5.079880 32.657196 12.396744 28213 4.324013 33.878723 13.123688 28214 4.968414 32.507660 13.742584 28215 38.222122 33.138748 12.938042 28216 2.680295 25.289610 9.732090 28217 49.501633 34.477631 15.826218 28218 50.322433 34.981674 14.621140 28219 49.487732 33.391068 14.586349 28220 50.221680 32.672333 12.965271 28221 5.274773 31.113983 12.381599 28222 3.570961 30.150238 10.189041 28223 3.472822 28.953781 10.711018 28224 3.638481 29.638855 11.281738 28225 49.173431 29.348267 12.337486 28226 49.201843 31.049103 12.892715 28227 36.643425 27.873734 11.236656 28228 36.277695 27.528473 11.817604 28229 37.842522 27.188782 11.575195 28230 39.239899 26.990417 11.447548 28231 52.923920 27.984940 11.963860 28232 53.774017 28.424210 12.316589 28233 52.914215 28.730331 12.853691 28234 54.949509 27.559891 12.337875 28235 30.121353 25.935089 10.689613 28236 30.991837 26.804108 11.537071 28237 31.926668 27.082275 11.490753 28238 40.112823 26.302719 11.396935 28239 49.833069 28.215332 12.067184 28240 49.431503 28.586182 12.069855 28241 50.673798 27.695953 11.685310 28242 51.625366 28.093338 12.435165 28243 51.869141 27.521561 11.791840 28244 54.358597 28.408356 12.755569 28245 55.052612 27.139114 13.250267 28246 28.958359 24.787338 11.565369 28247 28.830963 24.352585 11.905174 28248 29.124054 24.817963 12.217918 28249 30.326096 26.158752 12.122414 28250 39.131798 26.568542 11.726227 28251 29.307442 25.106552 11.232750 28252 29.672867 25.540894 11.901161 28253 40.655273 25.118958 11.099869 28254 29.102783 24.288223 11.197227 28255 38.358383 25.384323 11.924126 28256 38.318886 24.191376 11.393652 28257 39.536392 25.633789 11.645325 28258 2.179279 20.794241 10.249481 28259 1.997349 19.397097 9.856924 28260 36.571381 22.074509 11.056602 28261 35.086006 22.010834 11.829636 28262 35.934471 21.065460 11.400032 28263 35.502953 24.567795 12.256149 28264 36.093201 23.298767 11.654716 28265 37.088783 24.636154 11.878662 28266 1.972757 18.550777 9.839025 28267 1.966037 16.063086 9.649477 28268 36.651039 21.266541 10.886307 28269 35.108185 21.067612 11.911423 28270 35.579216 20.155045 12.272865 28271 56.373413 22.114639 12.499596 28272 29.187515 19.333679 12.085556 28273 28.665207 19.753021 12.833054 28274 36.810974 20.706970 10.918427 28275 2.102934 14.728472 11.355478 28276 30.769073 19.491974 10.149994 28277 29.977730 19.448853 11.054047 28278 45.490341 20.024475 12.232368 28279 51.565811 19.588974 11.352379 28280 51.067902 19.884109 12.217400 28281 56.545975 20.560364 12.593491 28282 56.233200 19.392456 12.844139 28283 54.997375 19.430435 11.966202 28284 55.485977 18.913574 12.926346 28285 30.913261 18.635468 10.565758 28286 30.126854 18.155869 11.924889 28287 30.976456 17.917389 11.122787 28288 43.256012 19.769608 12.051826 28289 44.280441 19.873535 12.082664 28290 53.319977 19.361877 12.975517 28291 54.658081 18.981796 13.080788 28292 44.353409 15.735291 12.325928 28293 42.383560 15.643234 12.284988 28294 31.846590 15.216736 11.156700 28295 31.736132 11.162079 10.959717 28296 38.947144 14.419327 11.465240 28297 38.153618 12.395447 10.964371 28298 45.127991 14.193573 11.658791 28299 52.289200 12.977921 11.383163 28300 51.388901 12.805939 11.619484 28301 2.245592 14.943962 12.288794 28302 45.231720 12.751297 10.766579 28303 46.095703 12.075226 11.119995 28304 47.764313 12.044632 11.508362 28305 46.719223 11.580429 12.098709 28306 45.921539 11.562683 12.039276 28307 48.613403 12.412231 11.059845 28308 38.309509 10.848984 10.756142 28309 38.668579 9.705811 10.283829 28310 37.835785 11.725967 11.279449 28311 54.536682 8.170776 11.645615 28312 37.883957 7.125702 11.677025 28313 45.757172 7.300293 10.203674 28314 46.601715 7.618591 10.217384 28315 46.016754 6.924133 11.134117 28316 47.366470 6.788025 10.574539 28317 47.819473 7.795807 9.939323 28318 47.806793 5.878998 10.066101 28319 43.407318 5.774033 11.407082 28320 43.194977 5.664749 12.412643 28321 44.172516 5.924072 11.978050 28322 42.395096 5.581055 10.517395 28323 44.013702 6.105621 10.404716 28324 45.116455 6.677872 10.362984 28325 47.237823 5.184395 10.503578 28326 52.587631 5.559235 10.752312 28327 35.585136 5.905640 10.022337 28328 36.028984 4.779953 9.384132 28329 35.579872 4.787521 10.200661 28330 40.829224 5.465378 10.281052 28331 60.272186 4.375793 10.921616 28332 35.732040 2.361313 10.200027 28333 46.516785 6.286713 11.584122 28334 46.420486 5.086334 11.620605 28335 46.722748 3.984421 10.726051 28336 46.836685 3.111145 10.262886 28337 53.229919 4.037109 10.376936 28338 60.509216 3.223206 11.332466 28339 60.560242 4.664490 11.640678 28340 61.007584 2.964439 11.958527 28341 61.029373 3.869438 11.914902 28342 35.083954 2.715683 11.174858 28343 34.865555 3.669029 11.201233 28344 39.630615 2.384506 10.374771 28345 41.399078 2.665970 9.932938 28346 40.629990 2.689499 10.170380 28347 52.843277 3.700287 11.284164 28348 55.955414 4.341637 12.399986 28349 54.489746 3.529472 12.121643 28350 37.917511 2.094070 9.917610 28351 38.475891 1.768661 11.533112 28352 42.316208 1.852402 9.947678 28353 59.025894 1.876480 10.815292 28354 46.444702 0.945831 10.502838 28355 46.487488 -0.086121 10.297035 28356 56.983337 1.196930 10.078476 28357 46.125534 -0.827820 10.432602 28358 46.697739 -1.993210 9.779831 28359 54.497009 -0.154724 10.167152 28360 55.704773 0.585709 10.028282 28361 42.074829 -0.194290 10.688034 28362 41.958710 1.079391 10.882011 28363 42.591278 0.762268 10.068375 28364 51.798828 -2.064423 10.801468 28365 40.697708 -4.090561 9.420914 28366 45.420029 -3.042740 9.910347 28367 45.276520 -2.691864 10.311432 28368 45.045517 -3.239365 10.201439 28369 45.963257 -2.823700 10.023918 28370 45.365707 -2.005432 10.616966 28371 2.086789 0.960424 10.758055 28372 38.851379 -3.997650 9.996056 28373 38.095825 -4.319427 10.454826 28374 39.103073 -3.788406 10.555580 28375 38.809158 -4.584763 9.630020 28376 39.604034 -4.048981 9.831139 28377 39.782974 -5.308258 9.517288 28378 40.361755 -3.283676 10.406250 28379 45.452591 -3.665848 9.864838 28380 45.045807 -3.875290 10.012383 28381 46.248077 -4.231232 10.049629 28382 46.971542 -3.321838 9.823807 28383 47.070190 -4.048996 10.027245 28384 47.831299 -3.916504 10.287468 28385 55.755035 -4.880081 10.026154 28386 55.532074 -4.472488 9.518799 28387 37.302887 -5.263565 9.499733 28388 36.774277 -5.304230 9.984093 28389 37.300293 -4.807419 9.971046 28390 37.963943 -5.010254 9.576874 28391 38.685600 -5.526825 9.512161 28392 45.062897 -4.832291 10.126297 28393 45.137360 -5.972580 10.305130 28394 45.346085 -5.521912 9.925323 28395 47.025818 -4.506653 10.330734 28396 48.250977 -4.734756 11.535980 28397 49.079651 -3.838120 10.897499 28398 54.807266 -5.033981 9.816299 28399 2.567974 -5.587198 9.768387 28400 2.294765 -3.184242 10.475977 28401 37.175133 -5.855164 9.657761 28402 36.687271 -6.097366 10.073509 28403 37.916473 -5.873993 9.602875 28404 45.729889 -5.499344 10.246918 28405 36.332840 -6.869965 10.664856 28406 35.895546 -7.883423 11.563530 28407 35.392395 -6.761765 11.325134 28408 37.564835 -6.850800 10.381760 28409 38.976265 -6.593246 10.147896 28410 43.951477 -6.016113 11.047150 28411 51.396179 -6.690140 9.437454 28412 52.146652 -6.497726 9.930176 28413 54.608551 -9.378372 9.335808 28414 42.358917 -9.678329 10.090233 28415 42.647736 -10.627258 9.083870 28416 60.399185 -10.908630 9.850883 28417 62.839127 -11.172134 9.621910 28418 42.354187 -11.397430 9.403587 28419 44.908661 -12.310471 9.716667 28420 44.215668 -12.995285 9.568222 28421 47.540894 -10.517334 10.227333 28422 46.509064 -11.272400 10.375671 28423 59.084198 -11.236938 9.648132 28424 59.668274 -10.915741 9.422997 28425 41.361099 -12.855957 8.881172 28426 42.010040 -12.158630 8.979324 28427 63.793564 -12.357422 9.688339 28428 63.217926 -11.797073 10.375397 28429 40.521667 -13.379059 8.821716 28430 55.879623 -14.147171 9.522591 28431 43.592514 -13.856842 9.234764 28432 63.947052 -15.043945 10.049400 28433 64.042511 -13.719604 10.038589 28434 3.157748 -10.976002 11.200638 28435 3.438405 -12.058273 10.534290 28436 36.223930 -17.514114 7.618545 28437 50.188034 -15.314331 10.250961 28438 5.006109 -16.959496 8.206875 28439 40.984467 -17.347565 8.485390 28440 55.079483 -17.374832 10.487503 28441 53.811340 -17.421661 9.775955 28442 63.136520 -16.196960 9.368996 28443 62.145416 -17.232590 8.827423 28444 5.037182 -17.502733 9.100567 28445 52.067886 -18.208862 8.433678 28446 61.527374 -17.236816 8.556992 28447 63.040634 -17.423218 9.246284 28448 35.346359 -17.785965 8.600128 28449 40.129028 -17.853958 8.543243 28450 61.577545 -17.738098 8.372696 28451 34.621384 -18.050659 9.771019 28452 34.680595 -19.363174 8.342903 28453 38.064667 -19.717957 8.951790 28454 47.473480 -19.537674 8.910728 28455 63.925446 -17.305923 10.042519 28456 64.616547 -18.752380 10.031494 28457 33.883286 -20.514023 8.438370 28458 33.674240 -19.817154 9.507065 28459 34.152039 -19.353638 9.131516 28460 37.322105 -19.767303 10.168617 28461 37.384003 -20.478516 9.312531 28462 46.874710 -20.052155 9.634567 28463 47.455933 -19.398010 10.148140 28464 50.278503 -20.321732 8.873070 28465 64.971497 -20.125977 8.692719 28466 64.330978 -18.065140 10.172226 28467 65.083878 -19.857117 9.868652 28468 33.453369 -21.467651 8.439003 28469 37.751526 -20.707870 8.678047 28470 46.134476 -22.632904 8.621826 28471 45.158722 -22.409760 9.388786 28472 45.987122 -21.510986 9.221664 28473 49.047577 -21.445801 8.607361 28474 49.684082 -21.129074 8.953995 28475 65.179657 -20.444122 9.050278 28476 65.207458 -21.057755 9.462448 28477 6.773312 -20.881191 6.998708 28478 37.425049 -22.255524 8.323103 28479 47.421295 -22.015488 8.276443 28480 46.448669 -20.753693 9.396439 28481 48.294067 -22.268158 8.694168 28482 65.101990 -21.859604 8.830338 28483 33.317902 -23.388428 8.805298 28484 45.000717 -23.404556 8.627724 28485 45.424591 -24.083817 8.626755 28486 47.307938 -22.983276 8.735649 28487 64.787201 -23.054993 8.849686 28488 64.997070 -22.422882 8.859222 28489 6.965040 -21.451647 7.399949 28490 7.261768 -21.963272 7.240742 28491 7.588306 -22.499603 7.124167 28492 32.791809 -24.190308 9.999077 28493 32.447433 -23.157089 10.315384 28494 35.116119 -24.410858 8.575577 28495 37.056580 -21.142258 9.574448 28496 36.652184 -21.167526 10.370491 28497 36.920639 -22.111313 9.295685 28498 36.801971 -23.324844 8.365616 28499 36.115631 -24.183670 8.150688 28500 44.390686 -23.604553 9.115143 28501 44.133545 -23.148941 10.957153 28502 44.443924 -24.597382 8.691704 28503 46.560760 -24.207230 9.271019 28504 7.975325 -23.068777 6.904910 28505 9.505932 -25.216078 6.439461 28506 45.724213 -21.455826 10.270859 28507 62.783249 -25.267960 9.078156 28508 62.497772 -25.452667 10.830681 28509 63.444382 -24.614655 10.975975 28510 63.846710 -24.297089 9.797577 28511 43.788666 -24.539871 9.229660 28512 43.631927 -25.837051 9.121536 28513 45.234940 -25.424530 9.313744 28514 43.533539 -26.828506 9.282425 28515 44.443909 -26.750336 9.965675 28516 61.695435 -26.163940 8.543671 28517 61.497940 -25.790802 9.328156 28518 60.721985 -26.371918 9.393127 28519 61.043991 -25.918854 9.810608 28520 61.136093 -26.858063 8.511864 28521 60.628540 -27.142166 8.880638 28522 60.526154 -27.905289 9.045242 28523 11.414514 -28.765316 8.084425 28524 52.630554 -28.871796 7.385795 28525 61.659622 -28.823013 9.191040 28526 60.378693 -28.569107 9.323601 28527 62.527069 -28.437073 8.225204 28528 63.245468 -29.104218 8.805923 28529 64.044296 -29.479340 8.438354 28530 12.932032 -30.018759 7.154940 28531 41.493805 -35.311615 6.833130 28532 41.903534 -34.581848 6.755355 28533 54.589111 -34.979294 8.489357 28534 53.259552 -34.659470 8.494835 28535 53.459839 -35.515701 8.956451 28536 65.167618 -32.091385 11.223959 28537 65.024170 -31.730042 11.219749 28538 64.801239 -32.223297 9.767441 28539 13.464335 -30.534588 6.951149 28540 41.977905 -35.227814 7.177726 28541 42.965393 -35.098389 7.649284 28542 48.813507 -33.906067 7.753570 28543 49.922897 -34.065048 7.962554 28544 50.715286 -34.674683 8.469131 28545 51.331497 -33.791046 7.809204 28546 52.605621 -33.922165 7.905426 28547 54.017197 -33.875275 7.776016 28548 54.317032 -36.179398 9.131119 28549 55.226318 -34.313583 7.838623 28550 64.249207 -34.423447 9.408165 28551 63.132401 -34.408646 8.321564 28552 63.026230 -34.945389 8.701462 28553 63.965729 -33.536819 8.409668 28554 41.752487 -36.260971 7.086471 28555 42.283463 -36.421997 8.081276 28556 62.433578 -36.276169 9.517334 28557 63.155319 -35.458908 9.134247 28558 19.681803 -35.290352 4.958182 28559 18.803436 -35.398415 5.616524 28560 19.176399 -35.837162 5.714446 28561 11.498596 -39.174530 6.737091 28562 16.209656 -37.951462 7.653732 28563 18.080360 -38.100754 7.513824 28564 17.079117 -37.977173 6.928138 28565 18.242777 -37.582348 7.436953 28566 16.959187 -37.242771 7.748021 28567 20.872667 -37.555058 5.979505 28568 19.941492 -37.120377 6.282278 28569 20.128418 -38.265228 7.244415 28570 20.409716 -36.259937 5.239566 28571 19.705282 -36.231228 5.691149 28572 42.903015 -36.203308 8.582037 28573 10.222000 -40.055893 7.074333 28574 10.365227 -39.442352 7.729202 28575 9.755249 -40.181335 7.423195 28576 9.511322 -39.822464 7.953764 28577 10.721802 -39.902588 6.821121 28578 21.473717 -38.654587 6.623916 28579 42.602570 -38.469009 8.144020 28580 42.502548 -37.530472 8.633591 28581 10.556763 -40.690750 6.889358 28582 42.574539 -39.664536 7.123474 28583 10.474243 -41.658447 7.229331 28584 10.267380 -42.146317 7.669906 28585 11.108047 -42.395432 7.527374 28586 14.052147 -42.707352 6.223037 28587 42.933777 -40.968430 7.396583 28588 44.313309 -40.727737 8.765884 28589 43.255280 -39.504150 8.316618 28590 43.096741 -42.069275 8.373810 28591 57.050385 -43.018707 7.541381 28592 56.526474 -43.015030 7.501663 28593 63.340927 -42.755112 7.497253 28594 62.827774 -42.501801 7.494888 28595 15.676712 -43.716812 6.270950 28596 13.193115 -43.102859 7.142944 28597 42.659821 -42.683441 6.988693 28598 57.879059 -42.977737 7.507766 28599 63.967957 -42.712799 6.969253 28600 42.660309 -44.045700 7.159118 28601 42.528702 -43.322342 8.020676 28602 50.579803 -45.676880 7.119323 28603 51.395050 -44.863037 7.169837 28604 51.463226 -46.532425 7.681129 28605 16.906448 -44.699326 6.819557 28606 54.256210 -44.548370 7.554504 28607 11.500153 -46.091888 5.448273 28608 17.137589 -45.712097 8.321106 28609 17.866547 -45.379562 7.200431 28610 43.026917 -44.964569 7.111885 28611 48.854782 -45.683517 6.618148 28612 63.717987 -45.234543 7.238113 28613 11.817131 -47.721542 5.818206 28614 12.424927 -46.666183 5.532402 28615 21.049606 -46.950424 6.507919 28616 43.771774 -45.375473 7.658889 28617 45.607697 -45.837509 8.378311 28618 47.811035 -46.665115 8.341751 28619 46.842361 -46.890411 9.819077 28620 49.696350 -46.006500 6.967529 28621 50.359436 -46.506683 7.473739 28622 63.529312 -46.313034 7.301597 28623 11.546204 -46.831192 5.749160 28624 13.547470 -47.506424 5.706771 28625 48.855804 -46.381836 7.267234 28626 49.665131 -46.576859 7.364784 28627 62.860672 -48.027985 7.891899 28628 62.438660 -46.651489 8.408531 28629 17.643066 -49.568695 6.084425 28630 16.711380 -49.647842 6.902610 28631 18.550156 -50.078598 6.031166 28632 62.476044 -49.707596 7.340942 28633 62.968140 -45.304916 7.953201 28634 20.399796 -51.704437 6.014312 28635 25.613281 -50.621536 7.358276 28636 23.551208 -49.123291 8.137642 28637 23.154869 -50.494064 9.518967 28638 21.628761 -52.857880 5.211594 28639 28.977448 -51.779587 6.296493 28640 28.866562 -51.676376 6.380209 28641 29.065636 -51.576950 6.400779 28642 29.134354 -51.659866 6.399627 28643 11.630836 -50.240311 5.708671 28644 13.320061 -51.598724 5.854599 28645 12.606750 -50.577560 5.948478 28646 14.382828 -51.009521 6.692276 28647 14.521912 -52.626419 6.609054 28648 27.266953 -51.676819 6.403152 28649 28.336899 -52.001160 6.305206 28650 28.764816 -52.546555 6.388763 28651 29.037613 -51.890930 6.391952 28652 61.854691 -50.949295 6.968406 28653 14.068573 -53.641830 6.223053 28654 20.705582 -52.650742 5.853759 28655 22.221710 -53.634659 5.114105 28656 28.912323 -54.042496 6.157180 28657 60.184402 -52.801239 7.342453 28658 13.443375 -54.591644 5.734405 28659 19.834976 -51.986191 6.263374 28660 59.869431 -53.414673 8.027138 28661 9.086746 -55.839111 6.298652 28662 8.606903 -56.448669 6.028076 28663 9.133904 -56.532211 5.439423 28664 10.357773 -55.525467 6.892211 28665 11.490463 -55.347763 6.251503 28666 13.150925 -55.196106 5.151398 28667 12.469757 -55.184845 5.892807 28668 14.552048 -53.564178 7.233230 28669 25.202255 -57.437698 5.007980 28670 28.999847 -55.213608 6.060592 28671 29.057999 -56.048492 6.196533 28672 49.757874 -55.476196 5.833038 28673 45.213074 -56.272736 6.493637 28674 47.303757 -56.162506 6.792282 28675 48.288696 -56.256332 6.974075 28676 48.836395 -55.954651 6.296844 28677 49.738083 -55.952103 6.414825 28678 51.127258 -56.173874 6.289230 28679 52.225525 -57.009735 6.654251 28680 57.902695 -55.455170 6.806518 28681 8.813126 -57.288803 5.647491 28682 16.652092 -58.230896 5.637069 28683 16.193298 -58.940613 6.372200 28684 43.738983 -57.194183 6.263260 28685 43.264542 -57.340927 6.472579 28686 43.289154 -56.920670 6.707183 28687 44.265930 -56.638474 6.502967 28688 46.113312 -56.205093 6.948959 28689 53.879242 -58.059799 6.870162 28690 58.197205 -55.075821 7.377716 28691 16.026566 -57.714920 6.045761 28692 15.633972 -56.738007 6.464492 28693 17.341202 -59.782761 6.097511 28694 43.655716 -58.072021 6.402732 28695 58.936340 -56.801590 6.019210 28696 18.135727 -59.498779 5.530838 28697 45.468689 -60.340302 6.414978 28698 11.888062 -60.730286 5.554131 28699 10.596191 -60.363251 7.823768 28700 9.809265 -59.266602 7.185516 28701 9.525650 -59.429840 8.261070 28702 18.341873 -60.536179 5.875366 28703 21.604958 -61.390579 5.372025 28704 28.962982 -59.253403 9.737946 28705 29.335144 -60.092468 8.331100 28706 29.358932 -58.661942 7.683929 28707 43.326416 -59.403641 7.184364 28708 44.189468 -60.289749 7.482399 28709 46.165588 -61.247208 5.945984 28710 56.848663 -59.370285 6.434051 28711 57.228775 -59.669052 7.069786 28712 57.624008 -59.187027 6.804916 28713 58.333923 -58.065323 7.452598 28714 7.553513 -61.417480 5.587502 28715 19.366631 -61.763306 5.685302 28716 23.324509 -60.840546 5.370224 28717 25.669144 -61.543961 5.076141 28718 29.170746 -60.224121 5.689308 28719 29.027634 -61.291031 5.866104 28720 29.361610 -60.133179 6.656784 28721 6.029907 -62.814758 5.419533 28722 12.947876 -63.362930 4.765709 28723 13.060593 -62.102585 5.647476 28724 20.556870 -61.940430 5.445595 28725 24.442596 -61.830399 5.378647 28726 28.290771 -62.255768 5.190651 28727 46.320251 -61.944778 6.352966 28728 10.716019 -62.734070 5.588715 28729 20.064240 -62.767670 5.734329 28730 21.555862 -63.116272 5.693596 28731 25.400558 -62.767700 5.238739 28732 23.744278 -62.948593 5.573235 28733 27.216133 -63.377014 5.330505 28734 47.150818 -62.545944 7.301956 28735 25.054131 -65.608688 5.323578 28736 24.796707 -68.128159 5.101883 28737 23.177612 -66.341217 5.464394 28738 28.269012 -64.524796 6.511108 28739 26.764374 -64.765228 5.473770 28740 28.639450 -62.843567 5.987190 28741 47.539642 -64.464478 6.040924 28742 47.408066 -63.717819 6.313644 28743 25.231697 -64.004715 5.345017 28744 23.340935 -64.319199 5.596649 28745 37.961838 -66.265640 6.095932 28746 38.685875 -65.766846 6.583923 28747 6.400307 -64.477753 5.831619 28748 23.224915 -65.285324 5.587456 28749 26.319611 -67.006470 5.322441 28750 27.212372 -65.967743 5.709007 28751 27.511429 -67.559799 6.091156 28752 48.326706 -65.957840 6.123191 28753 8.950325 -66.519333 4.939316 28754 9.595261 -66.919357 5.447159 28755 9.970879 -67.485962 5.689903 28756 22.981117 -67.455154 5.267510 28757 22.415184 -68.929611 4.967514 28758 26.435333 -67.974518 5.276047 28759 5.267395 -67.119339 7.055175 28760 4.696488 -66.820358 7.231643 28761 4.302948 -67.456833 6.827255 28762 5.780892 -67.945236 6.064230 28763 10.713898 -68.404999 4.149521 28764 10.200349 -68.299911 5.316795 28765 19.205124 -68.942047 5.445236 28766 20.025978 -68.075577 5.498840 28767 20.462311 -69.518250 4.968689 28768 24.038818 -70.885971 4.927666 28769 21.892868 -72.041885 4.739960 28770 41.083771 -66.541046 6.773262 28771 42.367584 -66.777847 5.504791 28772 3.516815 -69.477570 5.488083 28773 4.245667 -68.302872 5.927337 28774 21.522240 -67.208984 5.448151 28775 21.111877 -68.314163 5.120598 28776 26.175781 -68.570374 5.165627 28777 26.834152 -68.607025 5.529976 28778 48.920990 -67.858597 6.678009 28779 48.827164 -67.288910 6.899444 28780 3.398285 -70.078171 4.730499 28781 9.245232 -69.908371 4.576180 28782 8.519073 -69.462723 5.135193 28783 9.850769 -69.660263 4.877037 28784 9.531998 -69.211868 5.334801 28785 19.065979 -69.890823 5.146126 28786 26.527130 -70.724991 6.102310 28787 26.229706 -69.382431 5.445450 28788 27.202866 -69.206940 6.358490 28789 51.813461 -69.700577 4.834061 28790 49.839813 -68.717850 6.128143 28791 50.604141 -70.172394 6.094924 28792 3.447632 -70.659927 4.538414 28793 18.312408 -69.391479 5.670570 28794 25.446426 -70.682739 5.312370 28795 51.525635 -70.486938 4.934502 28796 45.126770 -71.248062 7.153984 28797 50.830933 -71.539703 5.286408 28798 19.938499 -73.025162 4.669159 28799 19.834702 -72.081619 4.747559 28800 19.525574 -71.061127 4.914147 28801 24.830856 -72.135513 5.295899 28802 48.478943 -72.614304 5.253418 28803 50.077271 -72.468781 5.490982 28804 50.426971 -71.805359 6.387466 28805 18.246239 -72.323990 5.156983 28806 17.272720 -74.073746 5.058777 28807 16.666206 -72.796631 5.599396 28808 19.938324 -74.314041 4.545853 28809 21.153442 -75.049072 4.512367 28810 20.225281 -75.781128 4.527359 28811 21.589348 -73.983093 4.558365 28812 22.447838 -73.656616 4.707199 28813 23.287109 -73.790222 5.078339 28814 41.412445 -72.712082 5.410606 28815 46.077942 -72.300369 7.451004 28816 46.885635 -72.812653 7.242645 28817 49.248444 -72.915985 5.667785 28818 49.751877 -72.918488 6.448272 28819 18.681656 -73.691025 4.846695 28820 21.889793 -74.819977 4.637787 28821 22.160027 -74.551971 4.654183 28822 22.519867 -74.581299 4.701882 28823 22.336060 -74.736725 4.695015 28824 23.088470 -75.013504 5.226227 28825 17.684464 -75.515915 4.622749 28826 18.656235 -74.877029 4.671997 28827 18.803207 -76.104767 4.490158 28828 21.012627 -75.611221 4.569756 28829 21.378906 -75.526489 4.623200 28830 22.006233 -75.634918 4.867653 28831 21.496277 -75.724869 4.670906 28832 22.215271 -74.959869 4.698357 28833 5.163338 -75.656479 4.827057 28834 5.592522 -76.622345 4.154183 28835 6.284287 -77.521393 3.942230 28836 6.956383 -76.808548 4.407257 28837 7.193115 -77.722809 3.881432 28838 8.077698 -77.012451 4.203468 28839 8.848694 -76.695007 4.705338 28840 8.918747 -77.252060 4.111572 28841 8.016647 -76.023697 5.040764 28842 9.553276 -77.133041 4.896469 28843 17.906044 -76.764771 4.566818 28844 16.307098 -75.699402 5.042442 28845 19.898720 -77.767166 4.954285 28846 21.219421 -75.917480 4.646210 28847 21.222260 -76.679977 5.003586 28848 46.471710 -76.520294 5.921844 28849 47.355759 -77.075851 5.236221 28850 8.997337 -77.671265 3.742241 28851 9.508537 -77.680038 4.169067 28852 17.016190 -77.523727 5.033447 28853 15.617020 -77.054794 5.503258 28854 18.188583 -77.933594 4.702789 28855 18.786179 -78.641907 4.776764 28856 22.091362 -76.832596 5.926345 28857 17.935020 -78.951202 5.546692 28858 19.514709 -79.177795 5.119644 28859 16.392448 -78.393875 6.075973 28860 15.729622 -79.022598 7.459335 28861 14.752884 -77.819366 6.354499 28862 18.795189 -79.229904 5.098602 28863 35.590103 -79.864563 5.350403 28864 36.322769 -80.056305 4.613937 28865 35.790680 -80.608521 4.648499 28866 36.904205 -79.682953 5.202057 28867 36.060257 -79.589890 6.144302 28868 38.601547 -79.714249 4.701714 28869 46.504181 -78.880325 5.470368 28870 47.047577 -78.539627 5.131760 28871 47.383011 -77.851440 5.459251 28872 12.964142 -80.953262 4.155480 28873 36.462692 -80.679688 4.286911 28874 36.406685 -82.399551 4.622330 28875 35.429413 -81.668793 4.892029 28876 36.365616 -81.451263 4.369820 28877 43.852615 -80.401398 5.892730 28878 14.065308 -82.059326 3.949623 28879 15.248512 -83.398438 4.484848 28880 37.965775 -84.176285 4.472855 28881 37.201347 -83.347076 4.529488 28882 31.327118 -82.560211 6.159958 28883 31.715425 -81.910889 6.272567 28884 31.710825 -82.911026 5.405892 28885 32.315720 -84.399124 4.428024 28886 32.735123 -83.480911 4.903244 28887 32.854385 -84.391602 4.643425 28888 31.890551 -83.897842 4.660141 28889 38.543320 -84.478455 4.052597 28890 31.782244 -84.417892 4.409882 28891 31.307762 -84.423859 4.920120 28892 31.914400 -84.887711 4.434830 28893 32.693893 -85.260071 4.674637 28894 38.190521 -85.129395 4.619759 28895 27.143188 -89.415817 4.691300 28896 27.968872 -88.434067 5.100769 28897 28.582520 -88.241135 4.088249 28898 39.117798 -88.128403 3.881043 28899 12.897041 -90.724579 2.943619 28900 22.307678 -89.774490 3.712174 28901 38.878845 -88.489792 4.127915 28902 7.906875 -91.536163 4.383995 28903 8.335403 -90.305847 4.000839 28904 7.610847 -89.874756 4.584931 28905 8.646408 -89.413040 4.364182 28906 38.227676 -90.096268 4.028641 28907 9.150070 -90.413467 4.003647 28908 9.826370 -91.067917 3.786034 28909 8.516022 -90.857117 3.740555 28910 13.707504 -91.898590 3.200989 28911 28.065247 -91.836121 4.436142 28912 27.284225 -90.359604 4.997513 28913 31.977465 -91.267456 4.291870 28914 32.376114 -89.864838 4.970177 28915 8.536957 -92.732391 3.536301 28916 24.153633 -91.774063 3.663185 28917 31.490570 -91.967148 3.413712 28918 12.043449 -92.887054 3.841583 28919 11.175018 -91.948074 4.258377 28920 13.834412 -92.914413 3.372849 28921 21.049629 -91.570740 4.182221 28922 28.076630 -92.358841 3.819908 28923 36.611557 -92.901810 4.528000 28924 36.733047 -92.010803 4.903259 28925 8.997604 -93.881744 3.261131 28926 13.009171 -93.925293 2.313187 28927 12.956085 -93.478500 3.186821 28928 13.547578 -93.354492 3.356751 28929 21.920135 -95.014465 2.946793 28930 33.329422 -94.603226 3.681442 28931 36.139175 -93.471802 4.620987 28932 22.005280 -96.545242 3.262779 28933 24.032585 -95.813843 4.745018 28934 24.658401 -95.789612 3.920059 28935 28.074539 -96.656067 3.510071 28936 29.659668 -96.113464 4.905930 28937 29.159348 -97.770370 4.698090 28938 29.696381 -97.585632 5.206833 28939 34.592834 -95.066986 3.570038 28940 21.645073 -97.254532 4.155823 28941 24.830940 -96.773376 4.225586 28942 24.961235 -98.204361 4.610443 28943 11.309525 -98.932892 4.628494 28944 10.624100 -97.423935 3.941612 28945 10.579811 -97.404694 4.972847 28946 21.834236 -97.985565 4.228119 28947 27.844833 -97.852219 3.653282 28948 28.480148 -97.730164 4.120758 28949 11.196807 -98.646805 2.800842 28950 17.407623 -99.062134 3.194374 28951 17.018959 -98.330994 3.913506 28952 17.680908 -98.935806 3.508995 28953 17.774704 -99.222458 3.138382 28954 18.050499 -99.365631 3.509483 28955 22.655594 -99.169067 3.381928 28956 26.079391 -98.838242 4.557076 28957 27.477211 -98.679581 4.452355 28958 28.425232 -98.500183 4.749252 28959 11.747551 -99.782654 3.325531 28960 11.057968 -98.525131 3.574326 28961 12.437607 -101.002762 2.726021 28962 17.255402 -100.715515 3.326279 28963 16.582314 -101.661179 3.513558 28964 15.662445 -100.691040 4.300934 28965 17.847046 -99.818146 3.157715 28966 22.398071 -100.762131 3.637497 28967 22.350082 -99.988846 4.051178 28968 12.987823 -101.329178 3.649803 28969 13.367905 -101.898987 2.574791 28970 18.589615 -101.081818 2.821472 28971 19.510666 -101.003799 3.377846 28972 19.753159 -101.871475 2.117951 28973 14.261292 -102.019913 3.357506 28974 15.616470 -102.888718 2.502915 28975 15.271133 -102.507660 2.994110 28976 11.435837 66.067352 15.307724 28977 12.224503 66.453476 14.667847 28978 13.600082 66.318970 14.492828 28979 12.811356 66.217667 15.321442 28980 12.633240 66.518433 15.032883 28981 15.996078 64.760895 14.165932 28982 14.944969 64.904709 14.677673 28983 16.463646 64.483673 13.792702 28984 7.912323 63.549103 13.959129 28985 6.709854 63.314087 14.334579 28986 7.213043 64.454987 14.978226 28987 16.060455 63.673096 14.171326 28988 5.823464 62.576904 14.312538 28989 3.911598 60.674164 14.246193 28990 5.009537 62.022537 14.351807 28991 23.672302 60.884384 14.014610 28992 26.444077 59.495926 13.867569 28993 26.258255 59.256500 15.054893 28994 25.517639 60.448288 14.275726 28995 15.241432 60.035660 14.063957 28996 20.240135 56.865250 14.005638 28997 21.608849 54.829041 16.037392 28998 21.238045 54.342621 16.032867 28999 20.610977 54.691101 15.461815 29000 19.844162 55.789612 14.209694 29001 26.918976 58.057724 14.232445 29002 27.304398 56.499496 14.280128 29003 27.724915 57.478943 15.629883 29004 15.914383 55.952942 13.689400 29005 3.249085 56.973679 14.382874 29006 3.543732 57.778015 15.890968 29007 16.070389 55.292389 14.987709 29008 15.488770 56.067596 14.680092 29009 18.279991 54.920303 14.138763 29010 27.427078 55.249481 14.199783 29011 19.015320 55.050064 14.121231 29012 26.856209 54.423615 13.827682 29013 28.047462 54.184708 14.500793 29014 26.785767 53.316132 13.911545 29015 36.726944 54.013931 14.002899 29016 36.687195 51.682556 15.518303 29017 36.963814 53.000732 14.906555 29018 38.156715 52.707047 14.312485 29019 5.246658 54.099060 14.178650 29020 5.365494 53.304962 13.485405 29021 7.733428 53.808502 15.164581 29022 8.975693 53.060562 15.357483 29023 26.216354 51.296127 13.443321 29024 39.076935 51.676208 14.657211 29025 26.833267 52.227875 13.888527 29026 27.879105 51.393524 14.104996 29027 28.687523 49.909576 14.279335 29028 29.525215 51.178925 14.776077 29029 30.292740 49.789490 15.432625 29030 43.103500 47.802307 14.290001 29031 12.539673 47.325989 13.032280 29032 12.250916 47.569702 12.715042 29033 33.739464 48.403259 13.693359 29034 41.576996 48.545105 14.425201 29035 27.867920 47.190903 13.415817 29036 27.627502 48.034210 13.379257 29037 27.043701 46.078949 13.062515 29038 29.242111 47.963425 14.647728 29039 13.142609 45.435318 12.924393 29040 28.576004 46.504395 13.857018 29041 38.783737 46.251205 13.978882 29042 39.715248 46.834427 14.360924 29043 39.474274 45.884903 14.100174 29044 38.730438 47.315262 14.854843 29045 37.740448 46.227234 14.593460 29046 40.053741 46.280640 14.549194 29047 13.623299 43.978210 12.941315 29048 29.269363 46.689896 14.490448 29049 39.086380 44.860153 14.412766 29050 38.727570 45.198227 13.764053 29051 39.858955 45.380737 15.489227 29052 38.362000 43.754745 15.786041 29053 38.469765 44.415787 14.214211 29054 31.409744 43.259277 13.682121 29055 38.039795 44.809097 13.793861 29056 37.687317 45.371201 14.003685 29057 38.164276 45.559402 13.814575 29058 37.453926 44.802887 14.119247 29059 14.240570 42.411224 12.784088 29060 14.335861 41.491623 12.994347 29061 28.226913 45.369858 13.857948 29062 26.970627 41.499603 13.902260 29063 37.657059 44.073853 14.446564 29064 46.153412 43.575867 13.725746 29065 13.774277 42.966583 13.501694 29066 27.539001 43.544769 13.984680 29067 27.199829 42.700409 14.586060 29068 31.229088 42.361633 14.860909 29069 30.744698 41.338196 15.433350 29070 46.468689 42.318268 13.580475 29071 14.522331 40.585510 12.570480 29072 46.201538 41.189240 13.635231 29073 45.363983 40.206284 13.973869 29074 46.138916 40.694305 14.552994 29075 27.268097 40.632172 13.251083 29076 28.514481 40.178192 12.989204 29077 27.882034 40.019836 13.451241 29078 11.860641 37.737885 13.402649 29079 12.543022 40.885727 13.323654 29080 11.739616 39.150116 13.198586 29081 14.321411 40.937164 12.939667 29082 43.526413 39.110977 13.228592 29083 42.902542 38.668243 13.497688 29084 43.579559 38.870850 14.079636 29085 41.923676 38.294403 13.085518 29086 41.451813 37.726227 14.054382 29087 3.706436 35.349457 12.338348 29088 3.387322 35.714554 14.448029 29089 3.331024 36.861023 14.277870 29090 7.486130 36.091446 12.508698 29091 9.375671 35.255600 11.852791 29092 8.476479 35.555634 12.319298 29093 38.263985 36.896454 12.849106 29094 37.902069 36.577240 13.693497 29095 50.830124 36.328201 13.257126 29096 50.176636 36.642151 14.087891 29097 49.330688 37.046204 13.982597 29098 12.204018 36.175903 13.564642 29099 12.783470 36.347137 15.416458 29100 12.448975 35.350052 14.472244 29101 9.363091 34.936707 15.415413 29102 10.183731 34.600540 14.431610 29103 10.855782 34.522934 15.253075 29104 36.151855 35.528702 13.568298 29105 35.530792 34.824997 13.222054 29106 45.043381 35.202011 13.010323 29107 9.190773 34.960007 14.087212 29108 10.430557 34.638672 13.381210 29109 10.209908 34.683685 12.321861 29110 11.393692 34.655151 14.277809 29111 35.594681 34.141525 12.983421 29112 46.242096 35.913940 14.111137 29113 44.837769 34.916275 14.334564 29114 43.898804 34.443192 13.356583 29115 50.658432 33.864258 13.465179 29116 5.323265 31.913544 13.032219 29117 36.114624 33.415390 12.881958 29118 36.236916 32.832947 13.767433 29119 37.592621 32.703247 14.100166 29120 36.442001 32.311234 15.402802 29121 2.615635 24.862425 9.637506 29122 35.423698 33.435776 13.973740 29123 48.608551 31.544312 13.963387 29124 49.179672 32.373535 13.783150 29125 49.932770 33.101929 13.677551 29126 2.997394 26.376648 10.518297 29127 4.474197 29.332275 12.600571 29128 5.461815 30.074738 13.361565 29129 3.577140 28.087530 11.835114 29130 4.640518 28.379211 14.006844 29131 4.321098 28.589172 13.150955 29132 48.913803 29.717072 13.067909 29133 33.036743 27.076538 12.105263 29134 34.980316 26.986786 12.326477 29135 49.110962 29.124359 12.890709 29136 49.492920 28.705078 12.618317 29137 53.852112 28.710541 12.817818 29138 51.333084 28.975555 13.439102 29139 31.043694 25.951782 12.845657 29140 32.206047 25.998169 12.972420 29141 31.622568 26.817108 12.278427 29142 30.910004 26.671234 12.260155 29143 33.641624 26.041611 12.960831 29144 34.670097 26.147110 12.895020 29145 36.367508 26.846802 12.169624 29146 38.612778 26.235596 11.953430 29147 50.381882 28.336914 12.665466 29148 53.846146 29.014160 13.526588 29149 37.116325 26.007370 12.237167 29150 38.006226 26.245468 12.108955 29151 54.838470 26.219482 13.695183 29152 36.353241 25.308441 12.329193 29153 28.764091 23.928101 12.507721 29154 34.578125 23.237167 12.196693 29155 33.082108 23.239349 12.832253 29156 33.726974 22.029037 12.734962 29157 34.517731 25.388382 12.817398 29158 34.076599 24.295868 12.633385 29159 55.557907 24.105103 12.747108 29160 2.313150 21.200880 10.657484 29161 2.503526 21.586439 11.294428 29162 2.268840 20.284500 11.014822 29163 2.103513 19.889639 10.388216 29164 2.031205 19.003376 10.322908 29165 34.415146 20.896149 12.710953 29166 55.869904 23.083801 13.692749 29167 55.370499 23.463348 13.634232 29168 2.123566 19.271965 10.788315 29169 2.208947 19.028610 11.313490 29170 2.050688 18.153410 10.670897 29171 2.064964 17.000683 11.040680 29172 48.938019 20.145218 11.958298 29173 47.465942 20.534012 13.740242 29174 49.313828 20.501053 13.061890 29175 49.967102 20.215210 12.334221 29176 42.582809 19.968338 13.001854 29177 46.615112 20.101837 12.277039 29178 49.423218 20.448029 12.449867 29179 52.176788 19.645081 12.146454 29180 38.069977 19.185547 14.020073 29181 38.779877 19.303436 12.650543 29182 44.648712 20.450165 13.849083 29183 45.966522 20.457458 13.436104 29184 55.337891 18.620026 13.566727 29185 56.297272 18.782974 13.538635 29186 31.009506 17.399323 11.688110 29187 31.549629 16.474228 11.706787 29188 41.593994 15.494003 11.093697 29189 45.502075 15.477844 12.588522 29190 40.767380 15.206635 12.389221 29191 41.262344 15.356522 11.798592 29192 45.183685 14.821991 11.601234 29193 31.162361 14.922272 12.439230 29194 31.283218 13.962692 11.429848 29195 38.226273 13.978317 11.815781 29196 46.807114 16.454361 14.333641 29197 46.467484 15.348663 13.194542 29198 30.922211 13.194794 11.741524 29199 37.871307 13.101883 11.526527 29200 44.948578 13.173569 11.385033 29201 45.769104 14.386093 12.770531 29202 37.523895 13.300491 12.510704 29203 37.478256 12.151520 11.767471 29204 37.782829 12.416351 11.327187 29205 45.197906 12.268234 11.664253 29206 45.168152 12.926773 12.593666 29207 50.458801 12.574738 11.682343 29208 48.892883 12.196808 11.728806 29209 53.234253 12.779602 11.776649 29210 53.375244 12.223129 13.291519 29211 52.240997 12.404358 12.686356 29212 54.343628 12.405670 12.204445 29213 55.406799 11.818298 12.748886 29214 31.162476 11.431549 11.503983 29215 31.790934 10.450897 11.526886 29216 45.517853 11.756195 11.765167 29217 49.779922 12.153580 12.308395 29218 56.210938 10.897247 12.532349 29219 30.915756 10.827057 12.262260 29220 37.494072 10.731461 11.604424 29221 37.794128 9.741302 11.188614 29222 38.249191 9.742798 10.696945 29223 2.486122 16.622637 13.295465 29224 32.772400 9.434860 11.577736 29225 33.932983 8.641937 10.898880 29226 56.198608 10.141785 11.598564 29227 33.470657 8.093018 11.823463 29228 38.253227 8.842178 10.826752 29229 37.223755 8.815796 12.078163 29230 55.398682 8.892181 12.592613 29231 2.039812 6.463825 12.433477 29232 36.665451 9.721405 12.601425 29233 36.489304 8.987091 13.383987 29234 34.318909 7.333679 11.190872 29235 33.799683 6.343887 12.069748 29236 37.997131 6.055115 11.780037 29237 38.544388 6.040009 11.149155 29238 44.829559 6.307449 11.334908 29239 45.653610 6.505493 11.914536 29240 34.849686 6.319763 10.929504 29241 52.582794 6.175903 11.573357 29242 52.271210 4.893196 11.356186 29243 52.040192 5.781021 12.058113 29244 53.463028 7.227921 11.984047 29245 34.918571 4.854935 11.036598 29246 39.018372 5.569275 11.020630 29247 39.770805 5.228546 11.144669 29248 40.397827 4.969543 11.626358 29249 40.942200 5.222893 11.037445 29250 45.977158 4.200623 11.753845 29251 45.789124 5.796967 12.179367 29252 57.352081 5.202164 12.782677 29253 56.247589 4.661102 13.510918 29254 58.892105 5.593765 12.253563 29255 41.592499 5.383812 12.167168 29256 46.407654 3.108246 10.952011 29257 60.860413 4.786469 12.554581 29258 40.913544 1.935135 11.056175 29259 53.525238 3.198151 11.720924 29260 59.783768 3.524162 10.430367 29261 35.992630 1.772263 11.323051 29262 35.145233 2.060837 11.483345 29263 37.289604 1.777161 10.888588 29264 39.740021 1.762650 11.716179 29265 46.011200 2.212524 11.177330 29266 60.529358 1.491043 12.594551 29267 1.994164 3.946811 11.252962 29268 2.009104 2.614700 11.086302 29269 2.002052 5.037474 11.508905 29270 35.295837 1.358215 12.720116 29271 35.066971 1.800751 11.931557 29272 41.300995 0.597321 11.690842 29273 57.745331 0.670883 11.424408 29274 58.963608 0.896759 12.035538 29275 41.354950 -1.918549 10.806595 29276 45.959930 -1.739487 10.294411 29277 56.165283 0.064911 11.020439 29278 57.003174 -0.042603 12.168861 29279 40.427521 -0.075150 12.550270 29280 41.159821 -0.858307 11.813637 29281 45.522583 -1.181107 10.698868 29282 45.419540 -0.544418 11.092972 29283 44.944244 -1.198700 11.456894 29284 54.842484 -0.742294 11.292747 29285 54.264008 -1.427582 11.812424 29286 55.260193 -1.006653 12.085220 29287 53.168503 -1.440887 11.009476 29288 44.570389 -2.721161 11.451370 29289 44.692047 -3.820633 10.560875 29290 50.413925 -3.578262 11.787369 29291 50.994705 -2.619598 10.946877 29292 2.406438 -4.832242 10.570368 29293 2.457278 -4.320150 9.748758 29294 38.616150 -3.994400 11.323082 29295 2.146837 -1.834829 11.167612 29296 2.059741 -0.198695 11.632113 29297 36.101753 -4.774597 12.309113 29298 36.933098 -4.724655 11.089035 29299 36.059784 -5.746185 10.919899 29300 36.063477 -3.757858 13.841988 29301 37.071350 -3.940872 12.784851 29302 46.540039 -5.222519 10.807671 29303 49.295242 -4.321365 11.887764 29304 56.399231 -5.517105 10.247749 29305 57.376694 -5.166260 9.884567 29306 43.744934 -4.422165 11.460777 29307 46.047729 -5.842148 10.941010 29308 47.358032 -4.827560 10.867798 29309 52.964447 -6.417709 10.359711 29310 52.344864 -7.564407 10.565910 29311 54.847198 -5.555908 10.471252 29312 54.586975 -6.273315 10.652184 29313 53.726929 -6.732300 10.607246 29314 55.483093 -5.339386 10.381149 29315 55.462189 -6.117538 10.640053 29316 39.763092 -7.773514 11.240997 29317 44.800552 -6.693359 11.081894 29318 45.614166 -6.413864 11.140129 29319 36.896805 -7.645050 11.136932 29320 42.021545 -8.329697 9.814507 29321 51.399841 -7.108597 10.028381 29322 2.777179 -7.851038 10.198139 29323 3.055609 -9.240822 9.600851 29324 41.711014 -8.450882 10.565071 29325 41.470642 -9.329758 11.419411 29326 50.211853 -10.022873 11.164444 29327 48.923141 -9.914444 10.536720 29328 50.575760 -8.933868 10.396057 29329 42.571182 -10.638412 9.786552 29330 49.320847 -10.870865 11.303711 29331 53.945801 -9.811478 10.269127 29332 53.595474 -10.629135 10.206421 29333 53.069839 -10.553543 10.681145 29334 59.735245 -11.256729 10.185387 29335 60.664841 -12.041885 10.973724 29336 62.335800 -11.424103 10.450348 29337 42.335754 -10.917114 10.159378 29338 41.828232 -12.096664 9.984375 29339 45.766327 -11.539688 9.863068 29340 52.791473 -11.368820 10.168829 29341 59.222885 -12.529175 10.912987 29342 59.238190 -11.764038 10.382324 29343 58.296936 -12.373245 10.217476 29344 63.568939 -12.656387 10.735275 29345 43.603622 -14.383286 9.749405 29346 43.885696 -13.545792 9.711014 29347 50.895935 -13.579758 11.152390 29348 51.269409 -12.874298 11.031258 29349 58.172974 -13.230988 10.814331 29350 56.965027 -13.884689 10.607765 29351 37.200333 -14.856567 9.623306 29352 37.919037 -14.709290 10.551079 29353 40.812210 -13.023315 11.767487 29354 41.223145 -12.160324 12.202911 29355 41.500916 -12.361435 11.789146 29356 50.661377 -14.360168 10.901413 29357 3.219570 -11.954979 12.197395 29358 35.901566 -15.880173 9.472694 29359 36.361961 -15.458740 9.847160 29360 35.182037 -17.100052 9.524368 29361 35.523407 -16.574417 9.356491 29362 43.200089 -16.043594 11.285660 29363 64.078369 -16.063339 11.011032 29364 64.090073 -14.577103 11.324669 29365 4.656865 -16.548307 9.628103 29366 40.192673 -17.413254 9.670166 29367 43.001205 -16.750351 12.021599 29368 42.108612 -16.904770 11.651398 29369 40.992065 -17.164352 11.462431 29370 49.281403 -16.924271 10.530777 29371 33.925423 -18.936584 9.895966 29372 38.329308 -18.680740 9.987175 29373 39.342384 -17.886398 10.985062 29374 48.409988 -18.284622 10.380783 29375 47.905731 -19.226608 11.475098 29376 48.408417 -18.534332 11.697716 29377 64.435181 -17.841904 11.403954 29378 52.150284 -18.779282 9.432602 29379 37.016098 -20.579193 9.810669 29380 37.926758 -18.907944 11.326721 29381 51.382828 -19.939468 9.721863 29382 65.124329 -21.051056 10.695923 29383 65.162674 -19.729980 11.065926 29384 33.266266 -19.834595 10.263876 29385 33.599991 -19.228836 10.216400 29386 32.878433 -20.806030 10.129539 29387 33.306381 -20.780807 9.340027 29388 32.934586 -21.986191 9.418365 29389 37.402580 -21.348633 8.963417 29390 51.649933 -20.949539 10.650665 29391 50.385651 -21.146103 9.782181 29392 50.479004 -22.298859 11.019226 29393 6.499173 -20.836283 8.195366 29394 49.352112 -22.148758 9.597168 29395 64.957855 -22.307968 9.642212 29396 7.000569 -21.895130 8.224070 29397 33.901291 -24.366241 9.168365 29398 33.534317 -24.905243 10.050064 29399 7.649858 -23.036591 8.015263 29400 8.350605 -23.917990 7.370264 29401 8.917009 -24.570053 6.876080 29402 9.022134 -24.911457 7.186982 29403 47.989670 -23.601700 9.824539 29404 47.250946 -24.422897 9.974266 29405 49.149811 -23.172760 10.793404 29406 64.521515 -23.569275 9.495018 29407 9.573749 -25.648336 7.027559 29408 9.826190 -26.017614 7.050313 29409 34.812347 -24.631668 9.894928 29410 34.054924 -25.181259 10.299355 29411 35.837730 -24.222549 9.124809 29412 36.345451 -23.857956 8.950851 29413 48.302368 -24.368683 11.629082 29414 49.559372 -23.777222 12.234703 29415 42.322876 -24.773163 10.430786 29416 42.661469 -24.486145 10.378769 29417 42.901794 -24.828857 9.777466 29418 42.424988 -26.869949 9.307236 29419 43.183823 -27.417892 9.554604 29420 61.606857 -25.803482 10.318558 29421 10.856339 -28.081709 8.149187 29422 10.166672 -27.538612 8.757402 29423 10.231552 -28.102833 9.397709 29424 9.747461 -26.815706 8.596115 29425 9.915774 -26.691042 7.999432 29426 9.529854 -26.319645 8.310478 29427 41.612808 -26.207047 9.895050 29428 42.386932 -25.877380 9.420288 29429 41.220917 -27.089249 9.930534 29430 41.670822 -28.140442 9.780289 29431 43.041595 -28.037750 10.246536 29432 60.107635 -27.152847 9.590424 29433 10.330251 -27.021849 7.593645 29434 10.196852 -27.230516 8.221050 29435 40.378464 -28.532608 9.966461 29436 40.471268 -27.786255 10.124886 29437 59.578690 -28.135025 9.834137 29438 60.232407 -29.293518 9.898544 29439 58.881012 -29.435806 10.476334 29440 62.465759 -29.982635 11.406586 29441 63.004288 -29.483856 10.140594 29442 63.951996 -29.816147 11.280182 29443 64.015823 -29.596985 9.459602 29444 63.993225 -29.644424 10.305527 29445 64.476013 -30.280090 10.188507 29446 12.095588 -29.618370 7.982176 29447 13.182405 -30.582811 7.383059 29448 16.126135 -33.279366 6.186405 29449 17.759571 -33.793121 5.157303 29450 18.401445 -33.941040 4.777037 29451 49.077698 -34.902069 8.467117 29452 50.122314 -35.754456 8.859703 29453 49.422546 -38.250244 9.218781 29454 51.392120 -37.701157 9.560448 29455 51.976685 -35.541504 8.851852 29456 55.279282 -35.917999 8.941704 29457 54.925064 -36.907700 9.590523 29458 64.709900 -30.942856 11.235832 29459 18.637159 -34.910107 5.360045 29460 49.110260 -35.972733 8.842873 29461 64.130661 -35.615173 9.945053 29462 63.404739 -35.976105 9.497177 29463 58.232407 -36.357559 10.525070 29464 63.590332 -36.354370 9.950562 29465 12.946579 -38.129349 7.582817 29466 11.866814 -38.584442 7.850708 29467 15.222794 -37.763794 8.529770 29468 17.127808 -38.042221 7.927810 29469 10.826591 -38.840454 8.696579 29470 11.524956 -38.436600 9.408829 29471 18.701679 -37.423012 7.224543 29472 19.003466 -36.435040 6.297745 29473 9.163269 -41.738205 7.967720 29474 9.688553 -40.934769 7.433090 29475 8.910034 -40.397141 8.160187 29476 45.981659 -41.038498 9.077316 29477 46.046661 -39.893326 8.755814 29478 46.982544 -39.683167 8.632050 29479 46.917587 -38.173019 8.728638 29480 47.391556 -39.645935 8.644768 29481 47.854706 -39.681854 8.816277 29482 48.621277 -40.048325 9.287550 29483 48.325745 -39.212982 8.962280 29484 12.158539 -43.014313 7.634498 29485 62.151443 -41.705505 7.003112 29486 60.946976 -42.035126 7.184326 29487 12.019043 -43.564087 8.490570 29488 13.063080 -43.901489 8.245483 29489 15.889511 -44.958099 7.930999 29490 15.789642 -44.379059 7.150398 29491 14.551224 -44.091415 7.490051 29492 42.691559 -44.449890 8.247452 29493 56.831909 -45.046646 7.916091 29494 57.757812 -47.217163 8.571251 29495 56.616592 -47.742645 8.503784 29496 60.807892 -43.611618 7.870590 29497 59.938110 -44.112167 8.027946 29498 62.291473 -43.725555 7.805769 29499 43.514328 -45.244522 8.818695 29500 53.088623 -46.488052 7.802162 29501 55.348236 -46.596069 7.993209 29502 54.362122 -46.618851 7.889610 29503 58.814880 -44.822998 8.099075 29504 59.997253 -45.476181 8.469566 29505 60.964325 -44.989700 8.368233 29506 61.909546 -45.526108 8.429932 29507 43.647888 -45.330154 9.952934 29508 45.106995 -46.183807 10.642853 29509 13.525833 -48.901779 6.330810 29510 11.865601 -49.195007 5.897491 29511 20.643852 -46.982986 7.681343 29512 48.476303 -48.134064 9.489059 29513 49.565979 -47.146881 8.033707 29514 50.690643 -47.116882 7.862396 29515 52.191101 -47.645721 8.098511 29516 59.403900 -46.309784 8.591751 29517 14.794678 -49.563538 6.846527 29518 15.616898 -49.355133 6.851287 29519 50.460953 -47.697220 8.158302 29520 53.065338 -48.624924 8.193855 29521 54.835052 -48.440979 8.327606 29522 56.986847 -50.120361 9.366592 29523 55.461960 -50.884338 8.869202 29524 15.863113 -50.204819 7.341423 29525 18.027176 -50.555389 6.914672 29526 16.895935 -50.136749 7.301910 29527 62.010910 -49.546356 9.172485 29528 61.062912 -48.773911 9.680603 29529 61.904785 -48.024261 8.972687 29530 19.084633 -51.430130 6.660644 29531 18.543678 -51.519302 7.025543 29532 51.871902 -50.344711 7.926147 29533 51.182556 -50.419006 8.116638 29534 51.476837 -49.168015 8.250412 29535 52.576401 -49.931900 8.112648 29536 52.631607 -51.089554 8.104675 29537 53.771835 -50.242126 8.251045 29538 28.805099 -51.820221 6.634124 29539 50.922699 -51.215393 8.806763 29540 50.392609 -50.250900 8.702904 29541 51.654755 -50.984421 8.036324 29542 53.534927 -51.209915 8.182686 29543 54.319199 -51.420227 8.492088 29544 18.891159 -52.438065 6.633056 29545 27.741638 -51.620758 7.208000 29546 28.421387 -52.256454 7.641410 29547 51.819595 -51.502869 8.394226 29548 53.431366 -51.834549 8.724670 29549 52.426376 -51.915298 8.919983 29550 51.576508 -51.779114 9.098526 29551 60.714783 -52.808075 8.488678 29552 61.955322 -51.055832 7.867721 29553 61.530029 -51.753372 8.741592 29554 62.022415 -50.698090 8.722801 29555 13.438301 -54.629593 6.925651 29556 17.771118 -51.734192 7.336044 29557 17.772537 -53.319397 6.870231 29558 28.976166 -53.152313 7.527137 29559 29.268280 -53.739288 7.189880 29560 14.320869 -54.554688 7.699737 29561 17.124390 -54.503448 6.631858 29562 29.305817 -54.367599 7.215599 29563 29.338654 -55.279266 7.324707 29564 59.024307 -54.259750 8.084450 29565 8.439751 -56.090912 6.727615 29566 10.983093 -55.873199 8.811981 29567 9.620605 -55.782013 9.103485 29568 11.927780 -55.316483 7.473983 29569 16.129700 -55.406219 6.731811 29570 8.292114 -56.867569 6.555351 29571 29.333878 -56.237915 7.392227 29572 44.575439 -56.192520 7.449340 29573 48.804886 -57.234558 9.605942 29574 49.851044 -57.513901 9.959045 29575 50.306335 -57.756241 8.780914 29576 50.628555 -56.590500 6.982650 29577 58.247681 -57.421356 10.184555 29578 58.815536 -56.191162 10.599182 29579 8.629898 -57.934799 6.440094 29580 14.991333 -56.210236 7.143036 29581 14.133621 -56.911148 7.733139 29582 14.182159 -55.645935 7.816230 29583 15.012779 -57.763519 6.976669 29584 29.334351 -57.296234 7.453788 29585 42.754944 -57.489975 6.888939 29586 41.726364 -57.606735 7.668746 29587 42.507538 -56.886810 7.414550 29588 43.393417 -56.488052 7.378006 29589 52.492844 -57.842682 7.473709 29590 53.352234 -58.452911 8.360123 29591 49.006439 -56.907440 7.940635 29592 51.062210 -57.365723 7.602706 29593 9.240921 -58.704636 6.482490 29594 10.054459 -59.208374 6.119049 29595 42.470551 -58.577621 7.288368 29596 29.310394 -61.386536 7.548095 29597 55.113724 -59.104706 8.017059 29598 57.719284 -59.179810 7.906494 29599 11.456528 -60.540436 6.472662 29600 10.733482 -59.835251 6.562835 29601 14.577988 -59.224899 8.126366 29602 17.350143 -60.609283 6.460624 29603 56.395599 -59.247681 8.826157 29604 56.466553 -59.661697 8.000160 29605 7.961547 -61.329422 6.415329 29606 6.891403 -60.886307 7.184280 29607 7.982284 -60.990601 7.753021 29608 7.754530 -60.547821 9.070648 29609 6.883759 -60.509033 8.229446 29610 12.163528 -61.310242 6.310371 29611 12.717377 -61.736069 6.006614 29612 17.494492 -61.316406 6.652618 29613 18.260986 -62.165863 6.383346 29614 45.005173 -60.770081 7.649765 29615 45.834473 -61.539536 8.053587 29616 56.423813 -59.633072 7.216918 29617 57.098190 -59.721771 7.653204 29618 8.775436 -61.003891 8.783096 29619 12.705811 -62.271622 6.029464 29620 19.101685 -63.123352 6.145218 29621 23.580948 -62.028870 5.597626 29622 22.763702 -62.141403 5.606246 29623 29.219101 -62.133713 6.712158 29624 46.867279 -61.933762 8.283684 29625 45.269394 -62.026917 10.158951 29626 44.687561 -61.648987 9.346161 29627 6.199516 -64.041977 7.392561 29628 5.970818 -63.681107 6.034492 29629 5.661263 -62.636017 6.881775 29630 11.851807 -62.563507 6.193992 29631 10.700531 -62.374893 6.692001 29632 12.925354 -62.788727 5.459129 29633 11.844910 -61.988052 6.845848 29634 11.386856 -62.302689 6.964553 29635 19.927338 -63.903992 6.073150 29636 28.964798 -62.982040 7.017517 29637 28.774071 -63.259445 8.924103 29638 12.341606 -61.994125 6.369537 29639 19.063629 -64.036758 6.409752 29640 21.103241 -65.267151 5.849281 29641 48.082672 -63.554047 7.360374 29642 7.021309 -64.873764 6.209808 29643 19.259987 -64.901382 6.387611 29644 39.234337 -65.092087 6.375312 29645 39.680641 -65.026016 6.166610 29646 39.795517 -65.475571 6.626312 29647 7.899841 -65.502426 6.062027 29648 8.594307 -65.997833 5.751304 29649 19.482117 -65.799850 6.236244 29650 28.212570 -66.258362 6.600769 29651 39.698830 -66.204727 7.491348 29652 48.261627 -64.787659 7.032737 29653 9.094543 -66.434326 6.093475 29654 19.683449 -66.767960 5.957595 29655 40.246124 -66.773788 7.812950 29656 42.604187 -67.673523 6.477615 29657 48.600555 -66.661438 6.807846 29658 9.861038 -67.913406 6.209846 29659 9.480125 -68.463882 6.143257 29660 18.101547 -68.055862 6.293426 29661 27.956711 -68.114151 7.524551 29662 28.272446 -67.034058 7.046112 29663 28.468666 -66.107391 7.938766 29664 38.027657 -66.964417 7.117447 29665 49.246124 -68.354034 6.454078 29666 27.583130 -69.432388 7.238990 29667 37.492126 -67.924881 7.356246 29668 38.673370 -69.401154 5.832641 29669 37.818802 -69.092239 6.430313 29670 43.859695 -68.827972 6.259140 29671 49.055603 -68.385300 6.889335 29672 3.361923 -70.805374 5.179207 29673 7.381584 -68.439316 6.083480 29674 17.892700 -70.655594 5.555153 29675 38.065887 -70.236816 6.646530 29676 37.328064 -69.801498 7.106277 29677 39.082497 -70.810989 6.131439 29678 49.658905 -69.089920 6.929626 29679 50.216217 -70.161240 7.250961 29680 50.457367 -69.525436 7.881698 29681 27.010849 -70.563324 7.259590 29682 39.360870 -72.106720 6.671386 29683 38.344711 -71.697876 7.225830 29684 50.460068 -71.077484 7.306427 29685 16.437874 -70.615524 6.337280 29686 17.361816 -69.582809 6.207557 29687 40.395645 -71.750153 5.645599 29688 44.732025 -69.941498 6.217117 29689 16.884773 -71.693970 5.813056 29690 23.850937 -72.585693 5.097794 29691 24.667633 -73.480423 5.710998 29692 25.723770 -72.391937 6.112579 29693 40.016571 -72.603439 6.284202 29694 40.670227 -73.255432 6.223716 29695 4.109741 -72.503815 5.980651 29696 3.527207 -70.924164 6.275726 29697 4.492294 -71.882263 7.311141 29698 7.189293 -74.440704 5.414658 29699 6.602898 -73.831055 5.806579 29700 7.475189 -74.067047 5.741668 29701 8.402832 -74.256088 6.264587 29702 7.954574 -74.889435 5.529358 29703 15.624146 -72.159180 6.128158 29704 15.768753 -73.824463 5.496292 29705 23.990524 -74.719513 5.863143 29706 39.063629 -72.793518 8.065544 29707 38.251068 -72.420578 8.389633 29708 39.807823 -73.130219 7.053123 29709 48.473907 -73.156601 6.309890 29710 49.060974 -73.413742 6.674720 29711 49.167908 -73.202087 6.189102 29712 7.305328 -75.144409 5.201202 29713 6.402557 -75.797699 4.940018 29714 6.365570 -74.728256 5.444031 29715 14.820557 -74.759827 5.513352 29716 14.238800 -73.381210 6.097587 29717 14.502960 -75.973816 5.634475 29718 22.165817 -74.770233 4.722473 29719 5.523819 -75.097198 5.353294 29720 13.498070 -74.794495 6.014648 29721 12.898819 -73.902802 6.322631 29722 21.266098 -75.711014 4.662850 29723 41.104370 -74.224533 6.811157 29724 42.126419 -74.691971 6.310279 29725 43.141754 -75.191818 6.202942 29726 42.567993 -75.112778 6.896339 29727 43.940262 -75.563522 6.200462 29728 43.644958 -75.185242 5.749481 29729 4.799553 -74.680420 5.188171 29730 9.379288 -76.415985 5.779830 29731 14.683739 -76.901123 5.815796 29732 43.509308 -75.566925 7.001052 29733 45.215912 -76.858536 7.931167 29734 44.971512 -77.070770 8.660049 29735 44.408295 -76.581619 8.740112 29736 10.279648 -77.838730 5.010651 29737 10.265366 -77.171036 5.982360 29738 13.884109 -76.858994 6.131065 29739 47.467621 -77.430649 5.656898 29740 10.779572 -78.313721 5.215912 29741 11.241379 -78.761642 5.235291 29742 21.365921 -77.639511 6.096557 29743 47.086731 -77.374725 6.029464 29744 46.727585 -78.153320 6.261108 29745 12.004807 -79.678314 5.119843 29746 19.166626 -79.889771 5.906662 29747 18.444733 -80.002213 7.043235 29748 20.252853 -79.205612 5.661422 29749 20.654938 -78.799774 6.167373 29750 36.976837 -80.038101 6.494972 29751 38.020874 -79.763641 5.449898 29752 46.187912 -77.179276 6.861221 29753 45.999451 -78.759094 6.559120 29754 19.956223 -79.830795 5.917243 29755 33.518982 -80.306946 6.645155 29756 34.433060 -80.700897 5.606741 29757 32.737938 -81.577026 5.820259 29758 35.216110 -80.598389 5.033020 29759 38.180504 -80.570938 6.438026 29760 39.292175 -81.273270 6.283416 29761 44.387695 -79.912781 6.033186 29762 45.065674 -79.722137 5.649475 29763 45.221588 -79.312454 6.358932 29764 32.038727 -81.325668 6.405334 29765 34.309341 -83.011795 5.199310 29766 34.998695 -79.748215 6.316665 29767 13.829910 -81.567581 6.008850 29768 13.004211 -80.664810 5.824714 29769 14.081985 -81.347900 7.195282 29770 13.854393 -81.719574 5.120789 29771 14.750221 -82.565948 4.860916 29772 41.770859 -82.293594 6.604949 29773 30.688133 -84.443207 5.667083 29774 30.650444 -83.869614 6.020736 29775 30.993500 -83.433197 5.949325 29776 35.957596 -83.380920 5.042282 29777 7.314148 -82.669907 5.834869 29778 6.763542 -83.697906 5.561951 29779 7.910812 -84.180908 5.029923 29780 7.252907 -84.534790 4.881806 29781 15.310623 -83.555023 5.518051 29782 33.570938 -84.464569 4.983093 29783 34.418884 -84.354065 5.329285 29784 34.437248 -85.597961 5.375458 29785 33.528961 -85.341751 4.968460 29786 35.317337 -84.476959 5.429550 29787 37.175346 -84.310760 4.973618 29788 36.403595 -84.655777 5.401596 29789 7.544159 -85.416504 4.767807 29790 6.825295 -84.744781 5.189575 29791 8.412529 -86.676102 4.700592 29792 7.553360 -88.260101 4.945625 29793 9.391792 -88.186554 5.155876 29794 8.358360 -82.786514 5.866271 29795 8.623512 -85.394531 4.771317 29796 9.158524 -84.313858 5.364739 29797 30.863235 -85.913254 5.209534 29798 30.542091 -85.146866 6.002105 29799 31.764551 -85.522736 4.685669 29800 9.434784 -86.050644 5.106720 29801 30.831032 -87.514297 4.991531 29802 32.206505 -86.627686 4.937775 29803 33.336014 -86.040939 5.015915 29804 33.581680 -87.102173 5.346710 29805 37.261215 -85.277405 5.299042 29806 37.979599 -86.247238 5.077774 29807 7.139244 -86.580414 5.044968 29808 10.258591 -86.459000 5.892784 29809 10.321442 -87.644928 6.463371 29810 30.202492 -86.029358 6.125289 29811 32.103767 -88.219940 5.172409 29812 13.799515 -88.681244 5.593956 29813 28.986633 -87.599976 6.051071 29814 29.952522 -86.997360 5.499970 29815 29.554474 -88.125961 4.669098 29816 29.613678 -86.747101 6.326324 29817 29.330147 -87.240250 7.030136 29818 30.394402 -88.234436 4.839279 29819 30.913239 -88.392456 4.981659 29820 34.122101 -88.611618 5.599625 29821 9.399789 -89.593414 4.573525 29822 30.377106 -88.861557 4.480560 29823 38.118835 -88.931763 4.937172 29824 21.422501 -90.686569 4.137199 29825 21.792366 -90.121964 4.064667 29826 7.048058 -90.694855 5.510002 29827 10.243774 -90.498703 5.000931 29828 11.156342 -91.203873 6.270355 29829 10.459901 -90.173203 6.395690 29830 11.960251 -92.077042 5.281342 29831 13.483208 -91.847885 4.558739 29832 13.122299 -91.757477 5.314713 29833 13.444276 -90.585526 6.172164 29834 13.690506 -92.040436 4.021675 29835 22.273567 -90.892944 4.759918 29836 23.387833 -91.390747 4.407440 29837 23.001938 -92.050385 5.194565 29838 33.106575 -91.108749 4.979790 29839 36.756775 -89.821579 5.777923 29840 36.816788 -88.233612 5.984993 29841 7.979980 -92.690063 5.309830 29842 7.473129 -92.043747 5.934951 29843 20.555389 -92.505859 4.660675 29844 20.754990 -92.073242 4.678162 29845 23.650925 -92.366501 4.482956 29846 27.955414 -91.025070 5.728042 29847 27.292923 -90.245300 5.653938 29848 32.028221 -92.244965 3.901398 29849 32.703499 -92.184479 4.364739 29850 33.442894 -91.917236 4.888237 29851 37.503838 -90.768463 4.792885 29852 20.640442 -92.895325 4.569885 29853 23.341354 -93.421127 5.231468 29854 33.775078 -93.004288 4.611565 29855 34.059906 -94.198853 4.304199 29856 8.650467 -93.702148 4.627884 29857 9.495758 -95.057602 3.846855 29858 13.152069 -92.765106 4.158371 29859 35.663910 -93.969742 4.484665 29860 35.691940 -93.388138 4.908173 29861 21.208923 -96.089844 4.746780 29862 20.721115 -94.968399 5.342766 29863 30.195389 -94.234695 5.706192 29864 29.508171 -94.055283 5.135742 29865 34.918777 -93.860229 4.593613 29866 35.445396 -94.556061 3.986298 29867 10.039902 -96.237778 4.316994 29868 16.134109 -96.880676 4.501633 29869 15.602798 -97.295105 4.713554 29870 15.844627 -96.499573 5.108811 29871 16.306740 -97.518936 4.109253 29872 16.594238 -97.046906 4.314079 29873 16.753922 -97.435120 4.062378 29874 16.921982 -97.376526 4.484963 29875 15.073532 -98.010345 5.182816 29876 16.074585 -98.899368 4.139679 29877 21.489937 -97.811050 4.977501 29878 24.807220 -99.172775 5.289932 29879 11.071182 -98.510391 5.850204 29880 14.876190 -99.442474 5.239510 29881 17.051987 -99.325027 3.404305 29882 17.919647 -99.264603 4.520920 29883 18.636017 -100.135941 3.813156 29884 22.015564 -98.852859 4.450638 29885 19.171303 -100.581085 4.140831 29886 12.260895 -100.731262 3.629044 29887 19.532150 -100.904861 4.256378 29888 15.489304 -101.861313 3.753594 29889 20.214684 -101.147202 3.952293 29890 21.367966 -100.895569 4.362106 29891 21.918640 -101.175766 3.543335 29892 14.115105 -101.144775 4.643913 29893 16.371765 -102.522461 2.920418 29894 12.107011 66.251602 15.380592 29895 13.541725 65.581573 15.301750 29896 13.475418 64.487534 15.637161 29897 12.438797 65.546570 15.798462 29898 10.553818 65.412354 16.138474 29899 9.268173 65.590698 16.274734 29900 7.406525 65.340286 16.185287 29901 5.911224 63.585724 14.979843 29902 14.639984 63.792236 15.208542 29903 15.291748 63.801544 14.842537 29904 4.997414 62.686325 14.902679 29905 5.050079 63.458588 15.800034 29906 6.202515 64.541779 15.940536 29907 13.290924 61.537872 15.374580 29908 13.749710 62.940491 15.484482 29909 14.518677 61.643875 14.760712 29910 15.104561 62.923035 14.798630 29911 4.436668 61.983582 14.734192 29912 4.293030 62.248032 15.444939 29913 4.009369 61.432312 14.794800 29914 13.887695 60.387695 14.850548 29915 24.401031 60.235336 14.973961 29916 13.280823 59.403214 15.435272 29917 14.476379 58.573608 14.520401 29918 13.150604 60.587723 15.295319 29919 22.037094 58.913635 15.019196 29920 22.910782 59.941574 14.901833 29921 24.497673 59.861511 15.788292 29922 24.551163 59.446518 16.155396 29923 23.470963 59.562622 15.632507 29924 25.444206 59.483521 15.856674 29925 25.418030 58.726364 16.529953 29926 26.488129 58.738571 16.006470 29927 13.779556 58.225906 15.994781 29928 13.096954 59.007477 16.153221 29929 14.105179 57.866760 15.228996 29930 20.699524 56.790405 14.625214 29931 26.838730 58.109528 16.690659 29932 27.837097 57.453217 17.034744 29933 3.615845 55.723846 14.378548 29934 3.702080 56.410782 15.235207 29935 14.721565 57.109344 14.785507 29936 28.301628 55.639374 14.920128 29937 28.926422 56.762848 16.876640 29938 4.117310 54.800934 14.129028 29939 16.695351 54.921997 14.786629 29940 21.419388 55.910629 15.459488 29941 29.175995 54.524170 15.223831 29942 29.604874 55.634308 16.078583 29943 16.574944 55.301453 15.850716 29944 16.521553 54.959686 15.378128 29945 17.715073 54.801392 15.539474 29946 19.109612 54.591156 15.016823 29947 28.032272 52.820862 14.367760 29948 29.202339 53.354950 14.984383 29949 36.164803 53.191833 14.790268 29950 6.699707 54.611923 15.576813 29951 7.985153 54.097794 15.878906 29952 8.648178 52.325195 14.133034 29953 9.878342 52.404358 15.588043 29954 10.050262 52.203369 15.160378 29955 30.211021 52.452515 15.292313 29956 29.041321 52.242310 14.661179 29957 9.719711 52.044617 14.636353 29958 11.251251 49.108627 14.172188 29959 30.631760 51.313629 15.385490 29960 34.983810 50.714233 14.633446 29961 39.583633 50.981033 14.679306 29962 10.158295 51.016678 14.931534 29963 39.922752 49.558167 14.892303 29964 11.787117 47.756866 14.394943 29965 34.623184 49.504852 14.591629 29966 40.184891 47.896515 14.845566 29967 39.013840 50.788574 15.444870 29968 10.805252 48.825684 15.161156 29969 34.281906 48.506851 14.614700 29970 11.110542 47.272476 15.130074 29971 12.463913 46.618347 13.647575 29972 40.787720 46.662323 15.384552 29973 12.275482 44.646484 14.014343 29974 33.084259 45.961197 14.453331 29975 33.713272 46.527573 15.082443 29976 41.865417 47.355896 15.307083 29977 29.024040 45.962952 14.510254 29978 28.713081 45.139938 14.631332 29979 28.978607 45.876526 15.367035 29980 37.188728 45.436325 14.570107 29981 40.940369 45.770935 16.744270 29982 41.610382 46.420380 16.495995 29983 28.117172 44.418533 14.316963 29984 33.735687 45.166412 15.324585 29985 36.480469 46.064545 15.568329 29986 36.478119 44.654236 14.811256 29987 43.400665 46.427567 15.723892 29988 43.988068 44.754883 17.000732 29989 13.191132 43.349045 13.791023 29990 35.624519 43.562805 15.047546 29991 35.046608 44.495239 15.340149 29992 36.754417 43.401398 14.840179 29993 36.807953 42.793884 15.317505 29994 36.088501 42.730789 15.406395 29995 37.330688 43.087479 15.322220 29996 37.580261 43.474976 14.966972 29997 39.475250 44.394257 16.844955 29998 45.175507 44.297913 15.920486 29999 46.204895 42.682770 15.634476 30000 6.435066 41.485199 14.659325 30001 7.150421 40.760406 14.558594 30002 7.140511 41.745209 13.958282 30003 7.275353 42.966614 13.970978 30004 7.189026 44.761948 14.539299 30005 6.186089 42.771164 14.405357 30006 8.042923 42.458923 13.769127 30007 8.888145 43.513794 14.088776 30008 8.041962 43.887466 14.195625 30009 5.985901 44.975784 14.720482 30010 8.940079 42.133118 13.700180 30011 9.696091 43.179733 14.012390 30012 9.938034 41.941620 13.684319 30013 10.868240 43.356598 14.081825 30014 10.695114 41.905899 13.651939 30015 11.440445 41.863831 13.660477 30016 13.868889 42.336609 13.451347 30017 35.252853 42.923462 15.302444 30018 46.326462 42.876526 14.443626 30019 8.029861 41.157379 13.777359 30020 9.017899 40.612518 13.798080 30021 10.540512 40.254745 13.634125 30022 13.814743 41.505737 13.228043 30023 12.355239 42.720520 13.880096 30024 13.344788 42.321716 13.687645 30025 26.947945 40.575699 14.180573 30026 46.450119 41.638901 14.521645 30027 8.021332 40.274597 14.171242 30028 9.354958 39.555511 14.470116 30029 27.335266 40.082443 13.975281 30030 27.231644 40.073578 14.835396 30031 28.665985 40.065781 13.765648 30032 28.432159 39.939453 14.801529 30033 10.913658 38.725906 13.688629 30034 27.856613 39.830566 14.155006 30035 29.355751 40.103256 16.180618 30036 44.369690 39.250183 15.135994 30037 45.722397 40.171326 15.344193 30038 3.698273 37.292542 14.233551 30039 4.392479 37.411591 13.221054 30040 4.541969 37.360992 15.075684 30041 10.142349 38.939362 14.466942 30042 12.067162 37.202576 14.997658 30043 42.607788 38.286163 14.713387 30044 3.620522 35.216492 13.406683 30045 6.414169 36.382629 14.081100 30046 6.420731 36.514862 15.345772 30047 6.586441 36.344147 13.311256 30048 7.173523 35.998444 13.952843 30049 10.799759 38.272507 14.421715 30050 38.832626 36.750214 14.117409 30051 40.324585 37.269592 14.034256 30052 48.363831 36.910690 14.491463 30053 49.246307 36.657135 15.108635 30054 50.677185 35.869720 14.075829 30055 8.053176 35.509903 14.777870 30056 8.053299 35.635071 16.161972 30057 36.046501 35.355789 14.815674 30058 35.476547 34.667572 13.910645 30059 37.293594 36.131271 14.639359 30060 38.401855 36.418396 15.853371 30061 39.869774 36.899277 15.178413 30062 46.022644 35.728455 15.131401 30063 47.388245 36.547546 14.027153 30064 8.232208 35.428986 13.439247 30065 9.254662 35.013275 12.947197 30066 11.714508 35.034454 13.304405 30067 43.981873 34.309998 14.156464 30068 43.167053 33.953583 14.115845 30069 3.869980 34.282013 14.237434 30070 35.632187 32.858337 13.992836 30071 38.896118 32.776855 14.150299 30072 39.897820 32.951096 13.894051 30073 41.857330 33.545547 14.037804 30074 40.595245 33.015366 14.215172 30075 49.548080 35.648651 15.791039 30076 2.651838 24.880348 9.874823 30077 35.548798 32.754288 14.673470 30078 41.098526 33.249512 14.007973 30079 2.630385 24.271894 10.096539 30080 2.713606 24.250000 10.675209 30081 2.958052 25.375849 11.164360 30082 48.630127 31.385941 14.669258 30083 48.721527 32.202057 14.497589 30084 3.247727 26.560051 11.688931 30085 48.827805 30.519135 13.852707 30086 3.681053 28.447754 13.146904 30087 53.725983 29.479843 14.347626 30088 54.199249 29.011429 14.068535 30089 3.474726 27.061676 13.029877 30090 3.352947 26.448149 12.503248 30091 5.368767 29.240875 13.897720 30092 49.425629 30.740173 14.879196 30093 48.916245 31.514633 15.225464 30094 49.693268 29.382996 13.559967 30095 52.589417 29.735626 14.320618 30096 54.559875 28.182037 13.727936 30097 50.934174 30.242599 14.771835 30098 51.014771 30.962952 15.645332 30099 50.241119 31.022064 15.517220 30100 30.091217 24.780945 13.000183 30101 35.632767 25.946091 12.544380 30102 54.776276 27.288071 13.940933 30103 54.149597 25.042023 14.506668 30104 54.942230 23.863342 13.907425 30105 33.001938 24.398666 12.945366 30106 31.797655 24.380264 13.218758 30107 33.586662 25.074768 12.942444 30108 32.784653 25.184280 13.140173 30109 28.654633 23.061691 12.870689 30110 29.129715 23.808548 13.117004 30111 31.991686 22.424805 13.571182 30112 30.597198 23.092316 13.771622 30113 32.845551 22.058090 13.231667 30114 54.269730 26.319946 14.565376 30115 2.151659 17.986383 11.383244 30116 28.580429 22.320984 12.724075 30117 56.462296 22.547897 14.101486 30118 2.220658 17.368704 11.885044 30119 2.324723 18.543076 12.025444 30120 2.344045 17.086496 12.461613 30121 2.129283 17.074169 11.499308 30122 32.766464 20.634430 14.289330 30123 56.907516 21.818283 13.881439 30124 56.813766 21.468048 13.123169 30125 2.155945 16.060148 11.679836 30126 28.457626 20.356369 12.835709 30127 43.632324 20.114990 13.042397 30128 50.653107 20.168991 13.338547 30129 57.023468 21.216553 13.495316 30130 57.312256 20.848816 14.312698 30131 36.359085 19.341705 13.128067 30132 49.385330 20.519714 14.552376 30133 57.079773 19.624649 13.579361 30134 29.236496 18.621918 12.890114 30135 51.916595 19.816864 12.983345 30136 57.285614 18.857254 14.287071 30137 29.695511 17.738007 13.480728 30138 29.235657 18.348160 13.673843 30139 30.587234 16.663620 12.927742 30140 30.960747 15.634003 12.981270 30141 30.479797 15.358780 13.674347 30142 31.276566 15.740967 12.346443 30143 45.514587 16.610565 14.588676 30144 44.931458 16.213058 13.576355 30145 38.994446 14.643372 12.714546 30146 47.676346 15.061325 14.158386 30147 47.286407 15.577682 13.651711 30148 46.547729 14.494812 13.781044 30149 30.612991 13.933319 12.716637 30150 30.025360 13.344650 13.368523 30151 29.901199 14.163269 14.143318 30152 45.163742 12.681763 13.880905 30153 45.674438 13.633698 13.496971 30154 30.453400 12.281311 12.533592 30155 50.911285 12.206284 12.684769 30156 29.531464 12.748840 14.216194 30157 36.787079 11.218185 12.667007 30158 45.296356 11.800354 13.501366 30159 45.019867 11.836975 14.624550 30160 48.812378 11.692734 12.783371 30161 47.548187 11.338654 13.190315 30162 54.350677 11.950134 13.565865 30163 55.215332 11.392807 14.179848 30164 53.228516 11.465607 15.496391 30165 31.357025 10.257538 12.195984 30166 37.338898 9.760147 11.644949 30167 45.411407 11.783051 12.453690 30168 45.616119 11.103363 14.418533 30169 46.141876 11.334869 13.164963 30170 46.657043 10.887817 14.491508 30171 31.865396 9.807724 12.187317 30172 36.249428 10.070801 13.365158 30173 37.036720 9.971298 12.041344 30174 56.096649 9.751953 12.620010 30175 37.007835 7.679016 12.943947 30176 32.757896 7.089600 12.937241 30177 33.107277 7.586929 12.443863 30178 36.961212 6.629364 13.754623 30179 37.787033 5.376419 13.836136 30180 37.662598 5.569351 12.984604 30181 54.715729 8.311783 13.238922 30182 53.547821 7.557388 13.365974 30183 46.082336 6.739655 11.854485 30184 52.497253 6.661758 12.701233 30185 37.669144 6.065308 12.410400 30186 44.311890 5.621056 12.674026 30187 45.010193 5.984573 12.067030 30188 45.091629 5.592613 12.361298 30189 51.812317 5.860321 12.552765 30190 60.103622 5.471207 12.255379 30191 61.183792 4.596756 13.583496 30192 60.009720 5.606194 13.444916 30193 32.607300 5.838989 13.342941 30194 33.603638 3.553925 12.785332 30195 38.478256 5.401169 12.031723 30196 51.660706 4.831581 12.417427 30197 58.461945 5.662933 13.525909 30198 39.500671 4.906418 12.107986 30199 40.243240 4.944923 12.368538 30200 45.785339 3.215500 11.609222 30201 45.146179 3.880409 12.243851 30202 45.167480 4.962326 12.492355 30203 52.068329 3.689461 11.996994 30204 44.232788 1.097458 12.857361 30205 44.837555 0.024948 12.037994 30206 45.227539 1.317139 11.764404 30207 45.108658 2.760452 12.046463 30208 52.743805 3.013458 12.453217 30209 51.963287 3.120438 12.488617 30210 54.970200 3.873291 13.236984 30211 61.293549 3.373703 12.717155 30212 1.986047 5.342152 12.053865 30213 34.622849 2.320831 11.926613 30214 51.614700 3.614037 12.644676 30215 53.603668 3.052734 12.293877 30216 61.187805 0.289337 13.651718 30217 61.666550 1.259552 14.204376 30218 37.301697 1.539215 11.842575 30219 37.804237 0.994171 12.828957 30220 36.530807 1.170593 12.738579 30221 61.740753 2.566162 13.834869 30222 45.801147 0.152420 11.081757 30223 58.111282 0.389908 12.644737 30224 59.060623 0.260483 13.265800 30225 54.862167 -1.529221 12.760147 30226 55.939407 -0.506882 11.881386 30227 56.173279 -0.628311 12.690445 30228 57.313675 -0.126709 13.184845 30229 40.240219 -2.852463 11.442398 30230 52.024231 -2.614349 11.839752 30231 1.975750 2.857016 11.711084 30232 1.986088 1.766749 11.829302 30233 44.600708 -0.801605 12.581490 30234 44.523346 -1.645950 12.330208 30235 51.712982 -3.378983 12.931053 30236 39.407890 -3.547409 11.380775 30237 2.048164 -1.322274 11.985229 30238 35.105690 -5.801346 12.135452 30239 37.808060 -4.138138 11.882759 30240 38.752823 -3.781815 12.001640 30241 43.277390 -3.974762 12.552216 30242 42.617615 -4.530060 12.463531 30243 49.028503 -4.848846 12.727425 30244 2.102507 -3.417588 12.841982 30245 2.227718 -4.863409 12.476892 30246 2.287256 -4.530227 11.518227 30247 42.593369 -5.570847 11.873045 30248 42.940460 -6.453140 11.748489 30249 47.298370 -5.359467 11.742470 30250 46.454559 -6.082169 12.104668 30251 2.383442 -6.022163 11.942453 30252 47.363541 -5.783981 12.743248 30253 56.225540 -6.680435 10.421112 30254 2.650434 -7.718408 11.175209 30255 2.519064 -6.380716 10.969589 30256 38.604111 -7.531677 11.111160 30257 37.766373 -7.920883 11.487305 30258 40.935196 -8.022522 10.911774 30259 39.926567 -8.837769 12.123688 30260 38.787865 -8.831009 12.183899 30261 43.862244 -6.895096 11.845657 30262 45.088623 -7.128601 12.026245 30263 45.718506 -6.839310 12.315239 30264 50.975983 -7.698044 10.073103 30265 34.802155 -7.490631 11.967552 30266 40.665726 -9.378708 12.151077 30267 40.575562 -8.565491 11.723633 30268 2.845080 -8.658243 10.550043 30269 2.758080 -8.687986 11.425070 30270 51.477295 -9.830826 11.191681 30271 50.962189 -9.924423 11.225319 30272 52.577911 -9.434570 10.875359 30273 2.820069 -9.481344 12.057381 30274 3.012750 -9.655531 10.492954 30275 41.919159 -10.912903 11.034081 30276 47.221649 -11.411362 11.043915 30277 48.204956 -10.755859 10.962212 30278 51.266968 -11.374786 11.194527 30279 41.527908 -12.325974 11.110474 30280 41.628174 -11.648865 11.821503 30281 41.203735 -10.606644 12.092819 30282 45.865021 -12.158905 10.797691 30283 45.749420 -13.258377 11.550133 30284 47.222992 -12.371704 11.654465 30285 44.541046 -13.297073 10.470345 30286 62.539276 -12.237289 11.141777 30287 62.962494 -12.984818 11.739563 30288 63.784348 -13.539902 11.449371 30289 39.968445 -13.422668 12.388626 30290 39.869568 -13.941315 11.611221 30291 39.148918 -14.097351 12.413086 30292 57.973511 -14.221634 11.299835 30293 3.099181 -10.318478 10.701996 30294 39.041183 -14.356583 11.083382 30295 56.496429 -14.712402 10.707733 30296 57.076569 -14.489212 11.027451 30297 57.593140 -15.373291 11.429993 30298 3.978296 -14.951200 11.287678 30299 3.945201 -14.213756 10.245352 30300 3.570837 -13.308865 11.525473 30301 36.933899 -15.308350 10.866592 30302 38.013474 -14.718918 11.703773 30303 39.410828 -14.292633 11.712410 30304 44.422638 -14.609680 11.243561 30305 50.168152 -15.109436 11.258087 30306 56.077942 -15.971954 10.526817 30307 63.725021 -15.149261 12.328705 30308 3.673491 -13.109483 10.355616 30309 4.268070 -15.508150 10.264229 30310 35.643097 -16.386475 10.290504 30311 49.457748 -15.994186 11.607010 30312 49.718842 -15.079605 11.881622 30313 63.860397 -16.295853 12.712517 30314 4.408228 -16.399416 10.973091 30315 4.880837 -17.547630 10.166460 30316 40.367157 -17.199860 10.737259 30317 64.783478 -19.276169 11.912697 30318 64.043030 -18.543701 12.872986 30319 5.322553 -18.805262 10.059717 30320 33.722763 -18.632950 11.154106 30321 46.826508 -20.164490 10.741333 30322 47.194168 -19.951126 11.555672 30323 48.782211 -17.620087 11.611694 30324 53.059296 -18.420029 10.006332 30325 54.097519 -18.403015 10.530678 30326 55.609421 -18.731369 11.120628 30327 32.541641 -21.201065 10.583649 30328 52.331818 -19.257889 10.073647 30329 53.110184 -19.284256 10.502846 30330 64.923355 -19.003967 10.900330 30331 32.895096 -20.082718 11.112381 30332 46.404343 -20.624817 10.440376 30333 52.226257 -19.947403 10.385338 30334 65.083817 -20.225922 11.629585 30335 32.329498 -22.081726 10.794914 30336 46.075241 -20.913971 11.898582 30337 6.358836 -21.091366 9.330248 30338 36.108253 -23.213333 10.020332 30339 64.491058 -23.076935 10.659599 30340 64.687164 -21.363449 11.880272 30341 6.939200 -22.250278 9.119913 30342 6.645520 -22.414520 10.440538 30343 8.511625 -24.450499 7.825840 30344 7.824314 -23.829266 8.813879 30345 8.228968 -24.457375 8.632423 30346 32.488899 -24.801010 11.069336 30347 41.956970 -25.367294 10.168770 30348 43.043854 -24.167236 10.494759 30349 47.359863 -24.768158 10.879128 30350 63.946823 -21.823334 12.883194 30351 64.110962 -23.186951 11.958145 30352 9.314540 -25.277390 7.034421 30353 33.427902 -25.259262 10.703873 30354 46.782623 -24.955353 10.294647 30355 46.051758 -25.985519 11.167191 30356 41.974350 -25.020920 11.075943 30357 41.410156 -25.715088 11.040993 30358 45.828583 -25.780212 10.182220 30359 45.475494 -26.073837 10.157120 30360 46.178040 -25.318039 10.050880 30361 60.788330 -26.199066 10.283195 30362 9.037582 -26.142996 9.238699 30363 9.564865 -25.998936 7.675248 30364 9.131610 -25.293072 7.561382 30365 9.089019 -25.851969 8.632084 30366 40.976685 -26.402298 10.744926 30367 59.170288 -27.627792 10.581627 30368 59.621735 -27.258621 10.320534 30369 60.180389 -26.690445 10.380432 30370 9.532686 -26.915491 9.231920 30371 39.884308 -27.580521 10.788132 30372 40.379654 -26.974258 10.995926 30373 44.197357 -28.625504 13.441086 30374 45.203949 -27.268982 12.699989 30375 45.355652 -27.794724 13.825218 30376 43.381897 -28.592102 12.292824 30377 58.768707 -28.293610 10.579002 30378 39.894058 -28.174072 10.321899 30379 39.781982 -28.792847 10.430077 30380 40.609161 -29.034271 10.284935 30381 58.100937 -29.773636 10.767227 30382 57.975296 -28.920197 11.395203 30383 64.046570 -29.679153 12.213600 30384 63.324951 -29.749695 12.213654 30385 11.206820 -29.298721 9.043201 30386 11.698363 -29.749577 8.717245 30387 58.219208 -30.548096 11.305542 30388 57.300446 -30.240585 11.766487 30389 57.781876 -29.918213 11.079292 30390 61.428146 -29.864197 10.452919 30391 11.034644 -28.869299 8.875996 30392 12.163909 -30.032032 8.292654 30393 12.711644 -30.532347 7.975898 30394 13.555393 -31.356136 7.555579 30395 12.520848 -30.833340 8.488617 30396 17.768229 -34.512257 5.670675 30397 14.999913 -33.126118 7.124676 30398 53.376129 -36.948822 9.420883 30399 42.465393 -36.894379 8.560272 30400 52.447235 -37.388367 9.523544 30401 54.223907 -37.040222 9.447876 30402 43.157837 -36.914291 9.048569 30403 43.874466 -36.682159 9.197548 30404 56.833755 -36.684906 9.994240 30405 58.929733 -36.863205 11.485489 30406 59.925842 -36.497238 10.369164 30407 61.215485 -36.417587 9.811905 30408 62.061676 -37.003387 10.060501 30409 64.235107 -37.727432 11.768364 30410 64.466095 -37.126785 11.997231 30411 64.321732 -36.534271 11.164658 30412 12.967002 -38.116547 8.850845 30413 14.078171 -37.965942 8.618141 30414 43.798416 -37.073975 9.384964 30415 42.885834 -37.765350 8.978661 30416 63.200043 -37.184052 10.295082 30417 62.396713 -37.849976 10.491859 30418 15.664230 -37.330311 8.134356 30419 16.258307 -37.340240 7.946217 30420 19.024227 -37.160442 6.868368 30421 43.328552 -38.335266 8.959122 30422 44.539642 -38.801712 8.873436 30423 43.924667 -37.884506 9.248985 30424 43.925339 -37.428757 9.419624 30425 54.184631 -37.544952 9.861496 30426 55.120529 -37.559189 10.659302 30427 9.344208 -39.629837 8.988358 30428 8.060340 -40.152054 9.349213 30429 8.605499 -39.896667 10.461296 30430 10.181808 -39.163605 8.908051 30431 7.642624 -41.016861 8.730698 30432 7.343475 -40.471130 9.493057 30433 6.820313 -40.834686 9.578857 30434 47.391739 -40.635529 9.074501 30435 7.639915 -42.214218 8.469193 30436 6.268486 -41.887772 9.365013 30437 7.683090 -43.192566 8.530708 30438 7.658186 -42.859344 8.442947 30439 6.995819 -43.165970 8.776642 30440 46.765747 -41.508499 9.692764 30441 49.643646 -40.114838 10.158875 30442 48.381744 -40.965042 10.315186 30443 51.154388 -39.259628 10.489197 30444 8.595673 -42.928619 8.507812 30445 9.598183 -43.984726 9.224045 30446 10.297882 -44.219833 9.425812 30447 10.027885 -43.388657 8.843246 30448 10.114799 -42.595016 8.157578 30449 43.844574 -41.894653 9.945412 30450 42.587219 -43.024109 9.550613 30451 45.351913 -41.542984 9.873657 30452 47.593414 -41.377411 9.719971 30453 7.828628 -43.768066 8.758247 30454 11.165604 -43.112732 8.300323 30455 13.995560 -44.533508 8.574432 30456 14.937775 -45.031693 8.634224 30457 42.578247 -44.329254 9.700943 30458 18.897919 -46.871506 9.524597 30459 19.661575 -46.636993 8.238287 30460 20.259056 -47.249344 9.171486 30461 47.722351 -48.395828 10.787918 30462 47.313309 -47.658325 10.578728 30463 58.364899 -46.307007 8.444839 30464 60.815079 -46.913971 8.860519 30465 21.342255 -47.511093 8.250275 30466 51.246277 -47.699707 8.120117 30467 59.211380 -47.696259 8.961021 30468 21.468658 -48.254227 9.532600 30469 22.602516 -48.901047 9.074303 30470 50.607880 -48.378189 8.363617 30471 49.810852 -48.139221 8.528008 30472 58.195648 -48.836960 9.206551 30473 49.835144 -49.196991 8.865463 30474 55.583267 -52.094925 10.194023 30475 55.127640 -51.861588 8.974510 30476 16.964203 -50.737473 7.550277 30477 48.901947 -49.658371 9.943420 30478 15.954483 -51.530960 7.752716 30479 27.006210 -51.329742 7.934379 30480 54.501877 -52.087051 9.152618 30481 16.366104 -50.886520 7.818771 30482 16.827469 -51.431885 7.833396 30483 16.831924 -52.392960 7.719734 30484 27.589645 -51.767639 8.132324 30485 51.493317 -51.898773 9.694672 30486 51.053299 -51.622971 9.763557 30487 55.181122 -52.168091 9.258682 30488 15.199142 -52.465942 7.454649 30489 15.280807 -53.579193 7.756263 30490 29.275681 -53.719131 7.911155 30491 8.774139 -55.774826 7.644020 30492 13.191345 -55.376617 7.918213 30493 16.328323 -53.751282 7.477859 30494 8.090858 -56.430481 7.319259 30495 15.201180 -54.790665 7.570007 30496 43.444153 -56.163391 8.303741 30497 44.436981 -56.232407 8.482719 30498 45.664764 -56.416122 8.225502 30499 47.031204 -56.853256 9.298576 30500 47.170670 -56.470398 7.794075 30501 14.229736 -57.962341 7.794418 30502 29.138596 -56.250732 9.330978 30503 29.313828 -57.433426 8.981667 30504 40.970718 -57.191025 8.109009 30505 40.541199 -57.074020 8.466187 30506 40.961029 -56.756668 8.382553 30507 41.632294 -56.829788 8.059982 30508 42.455750 -56.445496 8.180588 30509 45.172119 -56.656281 9.408195 30510 8.042282 -57.282166 7.429062 30511 40.653564 -57.878906 8.580040 30512 40.210892 -57.139832 9.043945 30513 8.644196 -58.431961 7.804954 30514 41.350769 -58.838669 8.312393 30515 51.810471 -58.031021 8.490906 30516 60.212250 -53.732529 9.652016 30517 11.366531 -61.377274 7.279113 30518 41.493927 -59.681580 9.123024 30519 40.941391 -59.228546 9.032753 30520 43.070801 -60.205383 8.096733 30521 42.293732 -59.637573 8.135040 30522 54.173096 -58.812241 8.726562 30523 54.817230 -58.663284 9.362526 30524 55.668884 -58.744583 9.481415 30525 6.119911 -61.123856 6.965973 30526 16.286705 -61.155548 7.486038 30527 43.544769 -60.723694 8.659775 30528 57.100739 -59.462936 8.308220 30529 8.833496 -61.579422 7.124136 30530 9.859642 -61.832520 7.435920 30531 10.885712 -61.975204 7.373779 30532 10.515289 -61.407532 8.090797 30533 11.428635 -61.988907 7.236221 30534 17.386917 -62.362885 6.984359 30535 29.240921 -62.337097 7.508743 30536 44.469711 -61.092941 8.542282 30537 47.482224 -62.278824 9.296432 30538 49.130981 -63.802643 7.869552 30539 48.494720 -62.834885 8.482712 30540 18.017471 -64.069427 6.816665 30541 16.785858 -63.242065 7.617599 30542 5.377197 -62.984955 8.474052 30543 5.598442 -63.986465 8.907990 30544 16.008575 -64.038269 8.218964 30545 15.869377 -62.986969 8.419464 30546 48.199692 -62.241730 10.990265 30547 46.753967 -62.135849 11.267738 30548 50.166428 -63.667465 8.194595 30549 51.003876 -63.077316 9.078850 30550 49.744354 -62.815887 9.263794 30551 51.059906 -64.085464 8.032974 30552 52.021545 -64.649765 7.949691 30553 52.298645 -63.605698 8.709846 30554 7.442581 -65.097382 7.165954 30555 51.165863 -65.233597 7.845214 30556 50.282913 -65.689072 7.941879 30557 51.902664 -66.532852 8.451645 30558 49.115784 -64.560486 7.641418 30559 49.995209 -64.614288 7.804054 30560 51.937820 -65.497040 7.893852 30561 52.597961 -65.409103 8.159492 30562 53.168930 -64.603119 8.617294 30563 8.088989 -65.552094 6.986694 30564 8.541664 -65.927032 6.697006 30565 8.861824 -66.561798 7.074852 30566 18.383797 -66.055908 6.552917 30567 49.215088 -65.274734 7.746986 30568 48.445602 -65.936844 7.183959 30569 53.486053 -65.561920 9.039413 30570 4.246552 -66.857864 7.245445 30571 9.395805 -67.250534 6.512527 30572 17.225128 -66.828186 6.914550 30573 40.481903 -67.618515 8.122032 30574 41.697311 -67.900818 7.552536 30575 7.257370 -67.664490 7.156608 30576 8.658257 -67.912079 6.802070 30577 8.288162 -67.067719 7.560722 30578 6.136887 -67.084717 7.734519 30579 9.464081 -67.932938 6.587225 30580 16.547485 -67.682938 7.126258 30581 37.275223 -68.686310 7.078468 30582 42.787155 -68.915924 7.490600 30583 49.447693 -66.753372 7.691642 30584 48.690033 -65.667007 7.584015 30585 49.028015 -67.859116 7.254730 30586 3.825188 -66.948700 7.771621 30587 3.440193 -67.893417 7.726326 30588 3.481690 -69.009659 6.885971 30589 8.479354 -68.854065 5.858932 30590 7.936325 -66.010620 7.802398 30591 7.247841 -66.863235 8.137894 30592 16.025925 -69.121933 7.114456 30593 43.927002 -69.862595 7.202613 30594 49.187256 -68.483994 7.241836 30595 3.497727 -70.540482 7.507659 30596 27.447647 -69.565521 8.167221 30597 43.305206 -69.758698 7.745079 30598 49.684967 -68.387634 7.625183 30599 26.014832 -71.071365 9.035187 30600 26.410866 -71.902756 7.570335 30601 37.492020 -71.128967 7.525024 30602 37.081543 -70.339905 7.818283 30603 37.010300 -69.454025 7.697120 30604 37.072693 -71.088531 8.358139 30605 3.692734 -71.888672 5.361725 30606 14.775017 -70.979691 7.056259 30607 14.620155 -72.122849 6.488540 30608 26.531937 -71.692459 6.783485 30609 50.878601 -71.182968 8.464851 30610 50.519089 -70.490158 7.854705 30611 50.285568 -72.482651 7.720581 30612 50.680649 -72.428848 9.329742 30613 6.154785 -72.730804 6.699539 30614 5.236176 -73.707657 5.846008 30615 7.262154 -73.357452 6.244644 30616 7.939819 -72.895523 6.800781 30617 12.940208 -73.017807 6.566085 30618 13.711975 -72.150314 6.801405 30619 25.763565 -73.176285 6.816513 30620 25.403702 -73.538925 6.583084 30621 37.768196 -71.987869 8.007309 30622 50.263092 -73.069031 8.579971 30623 7.087799 -72.715408 6.665245 30624 11.749290 -73.481155 6.894386 30625 26.069229 -72.606598 6.972419 30626 40.389343 -73.800369 7.250961 30627 47.674652 -73.193649 7.080124 30628 49.338348 -73.421310 7.518646 30629 49.762146 -73.394577 8.348877 30630 12.363525 -74.687149 6.496246 30631 24.925713 -74.265533 6.651367 30632 41.708771 -74.752274 7.188964 30633 48.405838 -73.541687 7.422798 30634 12.794769 -75.974884 6.419235 30635 24.343628 -75.114090 6.886817 30636 41.040771 -74.381638 8.334152 30637 42.480896 -75.131592 7.757576 30638 42.271851 -75.199615 8.769440 30639 8.688240 -75.482193 5.897750 30640 9.719086 -75.378387 6.616150 30641 11.123718 -77.812454 6.208694 30642 12.793571 -77.750046 6.753738 30643 23.082474 -76.049316 6.354652 30644 20.903542 -78.256836 6.132576 30645 14.155846 -78.488297 7.141906 30646 14.255875 -79.214081 7.808067 30647 13.232994 -78.921158 7.220588 30648 23.598648 -75.706573 7.605331 30649 23.763710 -74.680283 8.620567 30650 22.430145 -76.059616 8.529816 30651 10.873933 -77.114685 6.599037 30652 11.941345 -78.637222 6.238090 30653 12.384399 -79.534470 6.188247 30654 17.201218 -79.288391 6.874305 30655 19.297409 -80.365646 6.796249 30656 19.789810 -80.274933 6.676841 30657 32.266159 -80.973145 6.624618 30658 32.687126 -80.608826 6.718063 30659 34.262596 -79.987457 6.430572 30660 44.434036 -79.499268 6.981048 30661 45.021942 -78.967743 7.145843 30662 45.478943 -78.887817 6.928741 30663 35.744415 -79.890045 6.913261 30664 43.739777 -80.345047 6.825729 30665 19.514404 -80.276749 7.832473 30666 43.294922 -81.014191 7.513549 30667 7.481491 -80.925430 7.063797 30668 6.236923 -81.892944 6.742401 30669 14.606857 -82.334122 5.933692 30670 40.224548 -82.038300 6.431549 30671 42.470383 -82.355209 7.902267 30672 42.846359 -81.791412 7.282058 30673 42.068085 -82.845291 7.711212 30674 9.337326 -83.006912 6.085075 30675 9.976135 -83.725601 6.010666 30676 10.184045 -82.796417 6.935508 30677 41.435944 -83.462692 8.123154 30678 6.333054 -84.573959 6.151701 30679 10.167053 -84.936951 5.822372 30680 15.569931 -84.814270 7.523780 30681 15.305130 -83.431091 6.782760 30682 15.317947 -83.333267 8.014862 30683 30.846733 -84.063232 6.440650 30684 6.026230 -83.309418 6.747718 30685 6.613739 -85.562897 5.547653 30686 36.403442 -86.128647 5.669723 30687 10.919036 -85.448212 6.727859 30688 15.425056 -84.960220 6.282783 30689 14.856805 -86.091339 5.620926 30690 35.123703 -87.161423 5.747039 30691 37.628357 -87.342407 5.518967 30692 6.475678 -86.295639 5.785766 30693 6.543472 -87.175766 6.066902 30694 30.216522 -86.555359 7.243896 30695 36.878845 -87.226440 6.012657 30696 36.229492 -87.343781 6.058860 30697 14.437546 -87.039108 5.808624 30698 27.634491 -89.634689 6.681983 30699 27.675659 -88.840378 6.403915 30700 27.301567 -89.491241 5.693390 30701 28.238754 -88.332443 6.757263 30702 6.514893 -88.472839 6.244491 30703 6.755142 -89.554184 5.628845 30704 31.199310 -89.139343 4.792999 30705 34.435318 -91.350891 5.363770 30706 35.568130 -92.177841 5.265656 30707 34.202194 -90.078583 5.534241 30708 13.099045 -91.595047 6.327636 30709 21.210457 -91.518448 4.913941 30710 35.458839 -90.345001 5.884895 30711 35.424271 -91.151215 5.751853 30712 21.542313 -91.924988 5.587143 30713 22.251099 -92.208878 5.876754 30714 27.537109 -90.198868 6.130119 30715 36.635162 -91.111893 5.458191 30716 20.819954 -92.756622 5.201981 30717 22.773308 -93.087433 5.995651 30718 29.681793 -92.479202 6.164053 30719 28.365570 -90.736588 6.756973 30720 36.216858 -92.843994 4.940079 30721 9.341003 -95.142670 5.966842 30722 8.342087 -93.606216 6.330871 30723 8.959846 -94.805511 7.104751 30724 12.614807 -92.095703 6.035438 30725 12.221786 -92.216187 5.954605 30726 20.700508 -94.155121 6.016952 30727 30.830093 -95.178955 5.858818 30728 30.549179 -96.138870 5.539383 30729 9.526443 -95.253555 4.808708 30730 9.977249 -96.230301 5.315567 30731 15.681335 -96.067459 5.693184 30732 16.094360 -96.243454 5.578529 30733 20.616966 -95.756424 6.312271 30734 23.460060 -96.605637 5.841659 30735 30.882271 -96.097244 5.850341 30736 16.502350 -96.775833 4.971481 30737 16.859520 -97.206924 5.115830 30738 21.020859 -97.460373 6.176422 30739 24.166031 -98.745148 5.476730 30740 30.280388 -97.143600 6.236938 30741 14.345818 -98.084030 6.221983 30742 13.808319 -98.168961 7.055442 30743 14.221924 -97.091843 7.227706 30744 21.429405 -98.955963 5.976524 30745 10.414323 -97.209946 6.002731 30746 13.486435 -99.474930 6.411064 30747 17.095070 -98.105408 5.121262 30748 23.737396 -97.898163 5.792671 30749 23.710510 -98.764771 6.107399 30750 29.099670 -98.293350 5.308510 30751 29.707458 -97.955368 5.619178 30752 17.500854 -99.090607 5.229065 30753 21.645782 -99.940689 5.246552 30754 27.937851 -98.932404 5.817863 30755 12.267967 -99.808197 5.810112 30756 11.458252 -99.026276 6.748275 30757 12.300339 -99.343460 6.863243 30758 17.611389 -99.919418 5.678085 30759 19.111610 -100.574341 5.324730 30760 20.117958 -100.978317 4.751389 30761 12.470750 -100.455795 4.515328 30762 13.184311 -100.756516 5.370819 30763 14.804260 -100.543655 4.997070 30764 20.703247 -100.659439 5.666816 30765 8.325043 65.612305 16.698051 30766 11.559128 65.811752 15.883736 30767 11.586655 65.199066 16.260857 30768 6.669510 65.037155 16.891693 30769 12.588051 63.744019 16.118370 30770 12.152939 62.512802 16.270187 30771 11.353302 64.146027 16.652229 30772 12.449158 60.721741 15.883865 30773 11.455650 61.425812 17.003387 30774 10.250061 63.168091 18.057487 30775 3.318993 59.973297 16.871834 30776 3.235344 59.908829 16.297676 30777 3.560074 60.932541 16.754227 30778 3.188049 59.176743 15.555191 30779 12.319725 60.001877 16.125679 30780 11.978920 60.449982 16.652946 30781 12.599564 59.892715 15.754219 30782 21.613922 57.351730 15.280624 30783 23.856842 58.749222 16.308495 30784 22.948784 58.872726 15.795059 30785 12.679428 59.529739 15.979446 30786 12.567932 59.777939 16.719589 30787 13.670715 59.207397 16.892685 30788 3.369209 59.176987 16.636810 30789 22.856987 58.006607 16.037743 30790 22.646194 56.670242 16.143494 30791 4.420830 56.470901 16.215889 30792 4.942581 56.919937 17.265442 30793 6.024521 56.191864 17.131889 30794 14.869743 57.130432 15.822205 30795 29.776039 56.250183 16.957581 30796 29.644699 56.333344 17.705231 30797 4.111862 55.736206 15.233963 30798 4.148163 55.299835 14.813950 30799 4.923340 55.287872 15.338829 30800 15.952538 55.963394 15.757835 30801 16.155479 55.279388 15.526657 30802 19.837875 54.173721 15.982941 30803 17.116470 56.184387 16.584160 30804 18.653137 54.247696 15.670280 30805 19.121391 54.141357 15.741951 30806 30.180794 53.961456 15.718864 30807 31.200348 53.020325 16.096794 30808 31.100006 54.425278 16.884071 30809 20.770943 54.177246 16.242355 30810 30.272568 55.748932 17.203766 30811 8.448167 53.736679 17.171288 30812 9.417862 52.541153 16.151291 30813 35.846626 50.273560 15.779915 30814 10.231491 51.840912 14.963310 30815 31.071861 52.043488 15.706337 30816 31.256439 51.081543 16.053734 30817 31.516220 52.061035 16.150375 30818 38.190887 51.290314 15.695396 30819 37.511200 50.685104 16.394501 30820 9.969810 48.056122 15.613121 30821 9.130234 46.313110 15.098099 30822 10.699265 45.734131 14.880890 30823 30.996017 50.071823 16.652412 30824 31.474625 50.750183 16.694374 30825 37.985703 49.827377 16.255791 30826 30.158867 48.724091 15.459579 30827 35.098091 49.404358 15.373962 30828 37.491974 50.263550 16.645668 30829 34.952278 48.171997 15.833679 30830 30.197739 48.808243 16.178329 30831 38.252914 47.752960 15.555618 30832 38.920776 48.276398 15.397163 30833 37.449478 47.165344 15.701782 30834 42.229721 46.662476 16.291580 30835 29.223778 47.403381 16.186302 30836 29.757111 48.656464 16.948898 30837 34.105072 47.423828 15.161209 30838 41.648270 46.856628 15.986572 30839 42.280212 45.705872 17.090088 30840 4.153603 44.230042 15.168716 30841 4.568604 44.198257 14.924934 30842 4.300911 45.147064 15.176964 30843 5.092301 47.103470 15.463440 30844 3.535332 47.100693 15.914185 30845 3.341705 45.895630 15.953415 30846 6.854225 46.856842 15.239838 30847 5.060326 44.991486 14.829285 30848 7.974052 46.721741 15.192116 30849 8.184875 45.296173 14.666046 30850 8.793167 44.790985 14.497070 30851 9.700241 44.580597 14.477562 30852 11.723915 46.273041 14.625145 30853 9.608093 49.801056 16.035873 30854 29.334183 46.691559 15.090515 30855 3.774849 44.534271 15.521988 30856 5.209961 43.558151 14.692375 30857 8.827019 48.707275 15.866676 30858 28.373749 44.907440 15.340698 30859 32.448303 43.418427 15.124245 30860 34.237167 43.331421 15.485443 30861 4.515274 43.193558 15.751053 30862 5.050392 42.769684 14.853722 30863 27.732628 43.901413 15.092888 30864 31.747789 42.093323 15.696465 30865 39.138718 43.798157 17.158928 30866 45.443207 43.665268 16.652596 30867 5.404556 42.694305 14.573227 30868 27.079407 43.399994 15.804749 30869 26.892853 41.797165 15.018135 30870 26.907227 42.453918 15.586227 30871 5.469444 42.279099 14.969353 30872 35.134171 42.363373 15.781158 30873 5.989105 41.815887 14.918831 30874 7.559464 40.195084 14.650932 30875 26.763550 40.911804 14.976433 30876 26.539932 41.704346 15.924789 30877 8.028931 39.940369 14.743309 30878 8.594505 39.858246 14.444962 30879 27.671867 39.830750 15.716805 30880 46.350433 41.113831 15.336319 30881 11.376221 37.943573 15.310875 30882 43.204391 38.505554 16.208839 30883 41.802277 37.812134 16.083099 30884 41.205704 37.488098 15.035187 30885 47.329346 36.381317 15.151802 30886 48.321671 36.718185 15.365471 30887 36.670822 35.707428 15.618843 30888 50.138000 36.034912 14.849686 30889 12.886200 35.153122 15.503754 30890 12.077972 34.702225 15.109146 30891 35.238602 34.455826 15.236694 30892 43.848663 34.296143 15.095695 30893 44.985443 34.943024 15.929161 30894 5.092392 31.818344 14.901382 30895 5.504585 31.186401 13.901779 30896 41.163223 33.228363 14.865410 30897 41.659698 33.125885 16.686821 30898 41.141022 33.150589 15.894592 30899 42.433258 33.599243 15.608276 30900 48.886963 32.297028 15.177658 30901 49.555939 31.963409 15.946205 30902 49.206696 33.336121 15.859818 30903 49.440552 33.164383 16.737434 30904 4.330391 33.259323 14.509796 30905 34.890617 33.295471 15.500565 30906 39.990776 32.674713 15.521912 30907 38.241234 32.096268 16.025711 30908 39.325676 32.081772 16.590050 30909 2.570667 23.106491 10.633060 30910 5.912872 29.841797 14.622368 30911 3.156069 25.506832 12.233984 30912 53.371857 29.817566 15.326653 30913 53.965683 29.213898 15.513626 30914 53.617233 29.250763 16.150322 30915 3.276912 24.941275 13.457285 30916 53.017441 30.153091 16.561462 30917 54.148819 28.918655 14.773758 30918 3.471802 27.878510 13.834312 30919 3.491603 26.651024 13.807611 30920 53.992996 28.580460 15.582527 30921 54.260101 27.503418 14.774765 30922 53.424133 26.503983 15.345184 30923 2.382604 19.864719 11.740904 30924 29.711838 23.431793 13.633041 30925 29.054184 22.162567 13.577118 30926 2.554176 19.372185 12.716846 30927 55.272949 23.448822 14.347198 30928 54.618042 23.973038 14.674339 30929 55.957321 23.157715 14.773788 30930 55.030182 23.769058 15.386604 30931 42.385834 20.338028 15.217918 30932 43.161011 20.402069 14.267212 30933 41.953445 20.185379 14.223648 30934 43.908661 20.484497 15.371513 30935 44.750778 20.562622 15.393120 30936 45.710892 20.543457 15.227684 30937 48.913116 20.499420 15.914948 30938 49.685577 20.449707 15.503029 30939 46.708206 20.528870 15.787323 30940 47.835281 20.545349 15.721573 30941 28.697891 20.407623 13.367729 30942 34.824608 19.472519 14.072708 30943 52.070511 19.798233 13.881485 30944 57.712738 19.657806 14.372391 30945 57.811310 20.034927 15.217026 30946 28.953354 19.172180 13.681549 30947 32.926865 19.523621 15.712692 30948 33.670135 19.519867 14.890373 30949 39.524490 19.536209 13.597000 30950 54.458221 18.857605 13.977440 30951 53.274765 19.295120 14.383171 30952 57.499817 18.613785 15.681686 30953 57.811432 19.158005 14.768913 30954 55.944031 18.303375 14.636292 30955 29.952545 16.762604 14.657539 30956 47.978699 15.672211 13.827454 30957 47.797363 16.138611 13.974113 30958 49.928528 15.665909 15.197792 30959 50.642227 15.872009 15.547318 30960 49.496384 16.475510 15.297859 30961 40.713043 15.287750 13.505066 30962 44.632584 16.519989 14.695259 30963 44.653625 16.775650 15.974350 30964 43.470551 16.254700 15.509247 30965 43.677704 16.064835 13.853218 30966 42.080261 15.716064 13.805695 30967 48.145477 16.656204 14.828331 30968 48.526947 15.774506 14.391457 30969 38.992226 15.069336 15.169075 30970 37.633873 14.123383 13.689186 30971 49.346634 14.775574 16.059639 30972 51.047043 15.261795 16.069862 30973 36.571625 13.058899 13.706238 30974 30.243004 10.723953 13.281219 30975 29.684723 11.652527 13.753914 30976 50.007996 11.634293 13.659737 30977 48.640533 11.181702 14.415413 30978 51.510986 11.764175 13.972580 30979 52.606491 11.995026 13.834656 30980 55.994110 11.060791 13.552658 30981 35.627686 11.268646 14.290642 30982 47.659851 11.018921 14.403664 30983 56.133926 10.648239 14.503281 30984 55.528137 10.933701 15.529907 30985 31.139366 9.925003 12.831421 30986 30.581085 9.738892 13.516876 30987 36.051453 9.685745 14.037407 30988 35.715485 9.259949 14.770676 30989 56.289490 10.182678 13.595619 30990 32.240082 8.591751 12.767792 30991 31.527916 8.417114 13.633957 30992 31.220009 9.192886 13.390671 30993 36.752930 8.269775 13.083824 30994 55.892456 9.246323 13.557106 30995 55.686203 8.815399 14.482941 30996 31.950563 7.289932 13.749390 30997 52.738983 7.086243 14.303818 30998 52.915558 7.364182 15.512672 30999 54.158875 7.841980 15.384514 31000 46.045898 6.479401 12.074089 31001 51.730774 5.826004 13.287550 31002 41.401123 5.683258 14.080688 31003 42.373138 5.693565 13.188675 31004 43.334839 5.784302 13.434792 31005 44.437302 5.080284 13.256348 31006 45.890793 5.020172 12.152451 31007 51.325516 5.899773 14.429604 31008 51.087860 4.244354 13.661285 31009 57.324738 5.287422 13.751511 31010 38.046036 5.155487 12.940041 31011 38.649857 5.003983 12.911247 31012 39.470978 4.927216 12.889519 31013 40.050323 5.213867 13.548073 31014 44.612640 4.385612 12.963982 31015 44.344360 3.537750 13.083984 31016 50.388428 3.503372 14.448830 31017 50.427002 4.173187 14.363808 31018 53.741714 3.117722 13.034592 31019 61.691483 3.548050 13.557228 31020 34.396698 2.011780 12.605560 31021 33.763885 2.167038 13.074295 31022 40.387650 1.086166 12.191299 31023 39.290817 0.728043 12.680733 31024 44.268829 2.262161 12.904572 31025 51.798950 2.987061 13.416283 31026 52.875000 2.737015 14.097145 31027 61.901398 3.331497 14.062225 31028 34.016045 1.420807 13.433441 31029 43.653015 3.046402 13.979660 31030 44.250793 0.300980 13.033920 31031 61.802689 0.226547 14.530342 31032 44.489838 -0.190002 12.758560 31033 40.420425 -2.158554 12.066498 31034 54.121857 -2.139450 12.905693 31035 53.566956 -2.101883 12.260765 31036 39.482719 -3.124237 12.170540 31037 39.378906 -2.344772 12.844658 31038 44.329926 -2.150482 12.533966 31039 44.120529 -2.741821 12.829102 31040 52.914886 -2.761017 12.986626 31041 53.684814 -2.374496 12.944992 31042 54.196686 -2.208817 13.811172 31043 43.794403 -3.465439 12.331894 31044 50.843552 -3.955322 13.043999 31045 1.999566 -0.690479 12.464558 31046 1.963266 -0.182415 13.388943 31047 2.182696 -3.043758 11.416870 31048 36.931549 -4.396759 12.085182 31049 38.387527 -3.408203 12.689873 31050 41.920105 -5.044708 12.360382 31051 41.940567 -4.639374 12.776672 31052 41.517319 -5.106888 12.815178 31053 49.962402 -4.332718 12.815552 31054 49.647614 -4.750961 13.487053 31055 1.996803 -1.309529 12.820444 31056 2.070661 -2.315010 12.310884 31057 2.148038 -3.375857 12.031910 31058 34.840057 -6.683853 11.819778 31059 41.656036 -5.713303 12.415085 31060 48.112213 -5.309525 12.689766 31061 47.902740 -5.682892 13.392876 31062 2.544046 -7.717273 12.368137 31063 42.063156 -6.349503 12.170502 31064 41.579102 -6.274857 12.636627 31065 42.629059 -6.712036 12.482925 31066 34.365067 -6.641769 12.446945 31067 36.872833 -8.409241 11.917648 31068 41.888840 -6.582687 12.573883 31069 45.450958 -7.164719 12.442360 31070 35.035454 -8.739227 12.434189 31071 44.450867 -7.186966 12.554840 31072 48.221100 -11.590881 11.494461 31073 2.608430 -9.062670 13.700584 31074 2.371601 -7.098231 13.567173 31075 48.209351 -12.175949 11.822426 31076 48.163925 -12.692001 12.042572 31077 49.201523 -12.200882 11.732941 31078 50.988586 -12.884766 11.343582 31079 61.644196 -13.371521 12.017921 31080 47.220367 -13.533340 12.248756 31081 50.203461 -13.213730 11.676834 31082 59.453796 -13.483612 11.517540 31083 60.513596 -13.277939 11.773964 31084 63.150070 -13.625153 12.241562 31085 63.607086 -14.221466 12.178001 31086 45.793198 -14.100204 12.074341 31087 48.818039 -13.386185 12.161690 31088 50.283829 -14.326202 11.581436 31089 49.457138 -14.306503 12.145210 31090 59.195953 -14.916367 11.930489 31091 60.408936 -14.228302 12.198837 31092 37.302704 -15.148361 11.831322 31093 36.855225 -15.468491 11.685333 31094 3.315098 -13.077952 13.186798 31095 3.697888 -14.291931 12.179855 31096 36.123596 -15.948013 11.604881 31097 59.293823 -16.262787 12.294937 31098 60.405823 -15.481689 12.627968 31099 4.038497 -15.866080 12.391352 31100 34.847870 -17.096283 11.588280 31101 40.196091 -17.393723 11.441299 31102 49.094070 -16.889084 11.679718 31103 56.876434 -17.827988 11.328354 31104 58.043213 -16.982727 11.735466 31105 57.366669 -19.332047 11.687973 31106 58.430191 -18.455200 12.094009 31107 4.761950 -17.790565 11.299749 31108 5.337457 -19.395924 11.018787 31109 5.784419 -19.942926 9.818748 31110 48.395462 -18.008530 12.377426 31111 59.583130 -17.683670 12.575485 31112 33.036026 -19.320160 12.666878 31113 37.265823 -20.020905 12.747337 31114 38.878555 -18.604431 12.562531 31115 54.271729 -19.761276 11.031464 31116 56.261581 -20.356369 11.409607 31117 57.869141 -20.103394 11.956802 31118 57.393799 -20.292007 11.709297 31119 36.931580 -20.018295 11.249046 31120 36.381912 -20.899399 11.654175 31121 52.895538 -20.196701 10.825912 31122 54.832184 -20.963150 11.355492 31123 53.159241 -21.139999 11.224869 31124 31.931063 -22.917343 12.241791 31125 32.388138 -20.965790 11.772400 31126 46.918106 -20.215103 12.401054 31127 54.331909 -22.111191 11.922050 31128 55.439484 -23.261765 13.054070 31129 52.940399 -24.002747 13.445015 31130 57.252167 -20.843307 11.617332 31131 55.738403 -21.535812 11.551170 31132 5.975208 -20.824463 10.523180 31133 36.028053 -21.974319 11.294067 31134 51.704742 -21.743561 11.147934 31135 52.063812 -22.398819 11.772980 31136 55.860336 -25.115585 14.590103 31137 56.982697 -21.607101 11.780266 31138 59.051147 -23.870117 14.320000 31139 58.441589 -22.437317 12.915680 31140 59.792267 -23.216919 13.765213 31141 62.578903 -22.056519 13.573174 31142 63.192184 -21.009567 13.551819 31143 32.182831 -23.938507 11.051155 31144 35.523819 -23.083206 11.611984 31145 35.143044 -24.199020 11.092552 31146 50.921448 -23.283844 12.348724 31147 56.058258 -22.310501 12.065483 31148 57.055893 -22.346390 12.226570 31149 7.296142 -23.636543 10.143463 31150 7.261096 -23.039289 9.324944 31151 7.081512 -24.145220 11.487165 31152 8.772682 -24.979980 7.971346 31153 32.328064 -20.842697 12.984634 31154 42.750885 -24.298721 11.405525 31155 32.940979 -25.391815 11.815498 31156 34.182938 -25.131638 11.058319 31157 34.534294 -24.735825 11.969353 31158 34.976990 -23.849976 12.118713 31159 41.769958 -25.077805 12.585205 31160 9.091969 -26.527828 9.664085 31161 8.698472 -26.142950 10.030130 31162 8.846020 -26.492218 10.172287 31163 8.480172 -25.343548 9.400955 31164 9.203920 -25.668776 8.007315 31165 8.987908 -25.349300 8.012144 31166 33.821793 -25.314468 12.063271 31167 63.374359 -24.171951 12.408730 31168 9.184814 -26.902967 9.980524 31169 44.073364 -27.694656 11.231491 31170 60.870346 -26.434677 11.267654 31171 59.689056 -27.171158 11.201996 31172 60.368591 -26.930420 12.156723 31173 9.729908 -27.416527 9.506145 31174 39.444649 -28.159592 11.054062 31175 42.316772 -28.977264 11.263771 31176 57.873169 -28.220947 12.890869 31177 59.090515 -27.328430 13.606384 31178 59.112900 -27.584732 12.236778 31179 58.865494 -27.821198 11.183418 31180 9.080223 -27.616970 10.994951 31181 10.203679 -29.315817 10.523212 31182 10.300366 -28.714392 9.922417 31183 39.284966 -27.754990 12.124329 31184 39.776596 -27.329819 11.661720 31185 39.374161 -28.862427 10.832092 31186 39.609459 -29.556015 11.313560 31187 39.100357 -28.800156 11.240372 31188 41.757462 -28.872711 10.357193 31189 41.029053 -29.376251 10.951157 31190 41.126373 -29.925613 12.126747 31191 40.066101 -30.492188 12.533310 31192 56.938583 -29.434814 12.233009 31193 57.200867 -28.828232 12.415810 31194 64.442200 -30.237564 12.258347 31195 59.957458 -30.486053 11.069832 31196 61.102982 -30.502563 11.378593 31197 61.603928 -30.410889 12.299782 31198 62.530029 -30.032928 12.240021 31199 11.230061 -29.758812 9.419729 31200 12.054284 -30.224058 8.634071 31201 60.538376 -30.772522 11.409531 31202 65.180801 -32.637329 11.288620 31203 11.141284 -30.038212 9.749002 31204 12.256030 -31.352978 9.146275 31205 12.923918 -31.643744 8.518105 31206 11.958204 -30.714098 9.131615 31207 13.293734 -31.558506 8.026022 31208 14.097153 -32.341820 7.589635 31209 15.740091 -33.699383 6.778274 31210 16.618517 -34.173458 6.310244 31211 64.964386 -33.729538 10.667870 31212 65.165756 -33.144135 10.958435 31213 17.954592 -35.254501 6.065555 31214 64.700089 -34.846954 10.954819 31215 17.678257 -35.949318 6.717620 31216 17.023947 -35.105038 6.580850 31217 17.224657 -36.680004 7.420190 31218 18.022165 -36.593609 6.971619 31219 18.467615 -35.811985 6.143888 31220 64.579819 -33.604660 13.467163 31221 64.962662 -33.613235 11.841301 31222 64.553482 -35.182358 12.554764 31223 18.469385 -36.533970 6.691596 31224 57.999222 -36.648087 11.297890 31225 57.831543 -37.177353 11.999039 31226 56.975174 -36.852066 10.715347 31227 12.792715 -37.213123 9.604101 31228 12.069946 -38.055786 10.122322 31229 43.425369 -37.572754 9.331985 31230 60.616226 -37.557190 10.925430 31231 61.277847 -37.287567 10.449921 31232 61.468582 -38.355118 10.848900 31233 62.719803 -39.181976 11.135452 31234 9.999557 -39.232559 9.796616 31235 10.620689 -38.796387 9.800095 31236 14.007600 -37.134315 8.870844 31237 13.382229 -36.175568 9.384914 31238 12.020238 -35.618740 10.472853 31239 12.091712 -36.518719 10.340483 31240 53.071350 -38.254349 10.449287 31241 54.096802 -38.141632 11.569588 31242 55.074356 -37.803986 11.903351 31243 60.288635 -38.310059 11.347908 31244 61.043991 -39.821594 11.276344 31245 63.144211 -38.135162 10.639915 31246 9.486023 -39.494354 10.358864 31247 10.066101 -38.981979 11.226097 31248 9.292900 -39.705322 11.341949 31249 63.110138 -40.783829 11.948235 31250 63.720093 -39.013428 12.201141 31251 63.699280 -38.049225 11.096983 31252 6.235695 -40.943863 10.205452 31253 5.619446 -41.404724 10.567062 31254 5.669548 -43.668045 9.537361 31255 4.987602 -44.526932 9.971777 31256 5.761444 -44.971344 9.867767 31257 44.908310 -41.657455 11.528801 31258 45.987289 -41.505142 12.211601 31259 47.021606 -41.376022 12.147423 31260 46.500153 -41.603470 10.987045 31261 47.651520 -41.360565 11.296272 31262 47.463684 -41.531555 10.330330 31263 7.053619 -44.723022 9.224693 31264 8.228180 -45.309509 9.231216 31265 8.246887 -44.556900 9.003616 31266 8.875854 -43.884872 8.931541 31267 9.211166 -44.782104 9.314095 31268 11.206238 -43.727524 9.069084 31269 42.438339 -44.273361 10.915932 31270 42.201477 -43.297348 10.668915 31271 12.193405 -44.126617 9.186081 31272 13.159363 -44.533463 9.275610 31273 43.076370 -42.135666 10.805573 31274 7.718635 -46.069244 9.789833 31275 8.822495 -45.775970 9.484787 31276 10.252441 -45.572708 9.808418 31277 8.926056 -46.592087 9.749298 31278 14.152130 -45.132599 9.525497 31279 14.988228 -45.460297 9.417358 31280 15.848732 -45.738144 9.334579 31281 43.313995 -45.332306 11.304207 31282 16.931587 -46.329605 9.919035 31283 17.884758 -46.383408 9.215050 31284 42.228989 -44.118927 12.280609 31285 41.984985 -44.382843 13.588066 31286 42.199722 -43.113251 13.409760 31287 20.355499 -47.724243 10.319244 31288 19.558441 -47.355011 10.419579 31289 19.601746 -47.866531 11.066696 31290 60.240509 -48.213135 9.407913 31291 22.065598 -49.449738 9.980568 31292 61.383286 -49.874527 10.203758 31293 60.868790 -49.425598 10.231262 31294 49.524002 -50.223190 9.524841 31295 50.051270 -50.913269 9.702721 31296 59.929581 -49.247574 9.981293 31297 28.442749 -52.964630 8.945045 31298 27.610840 -52.349533 8.924774 31299 27.555176 -53.468506 9.933777 31300 50.520203 -51.364731 9.784828 31301 61.469315 -51.154831 10.095970 31302 15.967445 -52.695770 7.834236 31303 26.412971 -52.642548 9.688026 31304 26.549164 -51.708008 8.721024 31305 28.967400 -53.465424 8.619797 31306 51.995819 -52.048676 9.636360 31307 58.733643 -50.347473 10.493172 31308 61.089935 -52.543518 9.583870 31309 29.145691 -54.359207 8.711090 31310 53.143906 -52.128525 10.146873 31311 57.016037 -51.478256 10.319672 31312 56.417786 -51.304916 9.626282 31313 59.931183 -54.303726 11.137535 31314 60.462601 -53.474014 11.151123 31315 24.070503 -53.798798 9.543488 31316 22.860672 -54.330322 9.019554 31317 24.036263 -54.819305 9.022018 31318 28.334747 -54.270218 10.014908 31319 28.870308 -55.112442 9.722054 31320 29.308784 -55.421295 8.573593 31321 12.134842 -55.919113 8.614670 31322 13.185234 -56.405594 8.422012 31323 23.946823 -55.728912 8.931656 31324 21.517868 -56.138779 8.699905 31325 23.169029 -58.962860 8.575806 31326 24.170303 -57.329712 8.914444 31327 7.876907 -56.588684 9.361008 31328 8.503662 -55.910797 8.959778 31329 8.587059 -56.209427 10.047180 31330 7.992889 -56.482529 8.217941 31331 11.866051 -57.047852 9.768188 31332 19.455719 -57.354752 8.749626 31333 20.742126 -58.779144 8.517609 31334 20.900558 -54.120636 9.206703 31335 19.860229 -55.010132 9.189545 31336 19.450668 -58.523178 8.769836 31337 21.731750 -54.364960 8.950066 31338 25.483871 -56.314056 9.808624 31339 24.851402 -55.054276 9.440269 31340 40.760956 -56.534622 8.846405 31341 41.328735 -56.081299 9.323425 31342 41.543259 -56.426788 8.710373 31343 42.423035 -56.051865 9.205338 31344 43.763214 -56.260818 9.285858 31345 59.266357 -55.159012 9.734955 31346 7.889122 -57.347824 8.445656 31347 13.481903 -57.809280 8.706711 31348 19.440926 -56.091293 8.939545 31349 39.350098 -55.459167 10.736206 31350 38.869156 -56.733490 10.815903 31351 38.311615 -56.101944 11.587990 31352 44.392212 -56.435806 10.195076 31353 21.946976 -60.064911 8.518433 31354 25.482330 -58.028778 9.702057 31355 26.098877 -57.380203 10.495117 31356 46.047516 -56.961395 10.045677 31357 46.630432 -56.602509 10.971481 31358 50.444824 -57.883377 9.474998 31359 58.136383 -58.207901 8.910728 31360 13.476334 -59.162888 9.504837 31361 24.671722 -58.712723 8.941925 31362 40.010071 -58.262756 10.040291 31363 39.782951 -56.980057 9.736275 31364 51.194366 -57.964554 9.431458 31365 50.811310 -57.583450 10.215103 31366 51.579559 -57.716476 10.165840 31367 53.935577 -58.233948 9.731979 31368 5.911789 -60.912842 7.857902 31369 5.259049 -61.454819 8.006027 31370 5.535881 -61.568893 7.341278 31371 6.098015 -60.541977 8.705795 31372 20.933121 -60.269028 8.654678 31373 19.760742 -59.709595 9.173798 31374 23.132233 -60.558792 8.709549 31375 24.284882 -60.350494 8.857132 31376 24.621788 -59.537155 8.907257 31377 40.614044 -58.779449 9.097832 31378 41.749649 -60.110306 9.809425 31379 41.328857 -59.752274 9.859741 31380 56.641998 -58.438370 10.126411 31381 57.324509 -58.925430 9.053513 31382 22.060913 -61.833923 8.920944 31383 28.986450 -61.205673 9.238945 31384 29.029724 -60.272308 9.514633 31385 40.854279 -59.284164 9.816101 31386 42.540863 -60.485367 9.227524 31387 43.688019 -61.212006 9.809418 31388 5.243347 -62.160019 7.913192 31389 5.514488 -62.936356 7.704284 31390 8.993324 -61.427399 7.953170 31391 9.685768 -61.420074 8.505493 31392 10.397079 -60.953278 8.754257 31393 46.701553 -61.909164 8.871323 31394 14.675994 -62.385223 9.250885 31395 14.397758 -60.764740 9.174347 31396 24.586540 -63.029160 8.414558 31397 23.778427 -62.955582 8.628418 31398 24.600128 -64.001266 8.375809 31399 25.158051 -63.152191 8.480286 31400 24.466232 -61.959717 8.819244 31401 25.612305 -62.838989 8.947098 31402 44.463150 -61.775620 10.111038 31403 24.660957 -65.117706 8.229347 31404 24.148819 -65.812622 8.316093 31405 25.104874 -65.930969 8.257156 31406 25.811707 -63.899475 8.799873 31407 46.331909 -62.246719 9.890892 31408 49.509064 -62.277466 10.802338 31409 48.788666 -62.495819 9.919846 31410 52.201004 -62.490143 10.122139 31411 53.604919 -63.797729 9.236023 31412 53.257019 -63.066010 9.609024 31413 54.372696 -64.579773 10.003418 31414 54.256424 -63.168594 10.349541 31415 53.383255 -62.495209 10.403410 31416 17.206985 -65.693726 7.133979 31417 16.510559 -64.806427 7.636886 31418 25.342896 -64.846390 8.419769 31419 25.998138 -65.245636 9.372238 31420 25.502823 -66.567352 8.496933 31421 52.972443 -61.785294 11.373535 31422 7.059052 -66.006180 8.740356 31423 6.762619 -65.052048 8.465111 31424 16.004333 -66.413773 7.570594 31425 15.045685 -65.150787 8.405884 31426 15.507706 -67.792618 7.605499 31427 23.804146 -64.987259 8.546326 31428 38.870346 -66.492340 7.754180 31429 4.360985 -66.598923 7.773895 31430 5.074928 -66.522095 8.040024 31431 8.928482 -67.173172 7.152038 31432 14.484337 -66.980682 8.244614 31433 13.450851 -64.862335 9.128912 31434 14.519760 -64.166412 9.063110 31435 22.550423 -66.885681 8.819672 31436 21.938034 -68.209457 8.443726 31437 23.022697 -68.109756 8.178726 31438 24.009163 -66.982956 8.185883 31439 24.905365 -67.493332 8.352875 31440 25.033417 -66.799545 8.129425 31441 39.541000 -66.927856 8.222504 31442 23.985237 -68.596497 8.305786 31443 25.520111 -67.063446 9.268547 31444 24.853592 -68.345764 9.142975 31445 25.246140 -67.846054 9.790863 31446 28.143349 -67.323654 8.978371 31447 38.670914 -67.134659 8.245949 31448 37.933594 -68.035370 8.415108 31449 50.982361 -68.260330 8.236275 31450 51.562164 -69.525818 8.772896 31451 52.426987 -68.570496 9.763557 31452 52.500793 -68.208344 10.481514 31453 52.704178 -67.560684 9.785368 31454 14.537598 -68.521179 8.035049 31455 13.262497 -67.924896 8.776039 31456 21.292297 -69.074707 8.094788 31457 22.643265 -69.585876 8.288521 31458 20.913147 -68.296600 8.578644 31459 37.168076 -68.699081 7.934402 31460 41.422897 -69.113632 8.717178 31461 13.294647 -71.484772 7.378204 31462 13.145370 -70.716034 8.029404 31463 14.310425 -69.758942 7.885666 31464 23.786278 -69.528152 8.681686 31465 42.752884 -69.772263 8.161491 31466 52.086975 -68.354660 9.009186 31467 3.344002 -69.356216 8.786804 31468 3.409950 -67.504913 8.601616 31469 18.554237 -70.392563 8.844727 31470 18.949554 -70.947296 8.163910 31471 19.480461 -69.700302 8.386536 31472 20.817131 -70.233475 8.019630 31473 22.141388 -71.232239 8.838982 31474 37.206390 -69.674911 8.741699 31475 42.629608 -70.480957 9.064720 31476 41.701569 -70.359634 10.338745 31477 43.682297 -70.620453 8.129417 31478 50.990997 -70.290207 8.330315 31479 5.582153 -71.976532 7.473793 31480 8.131149 -71.839325 7.664314 31481 8.015663 -70.980972 8.481148 31482 9.207672 -70.876755 8.809883 31483 6.970970 -72.092163 7.217918 31484 6.166809 -71.615784 7.779228 31485 7.064423 -71.138046 8.313065 31486 9.676865 -73.221527 7.180648 31487 12.300972 -71.502701 7.707092 31488 11.170898 -71.754120 7.939651 31489 12.051239 -71.228958 8.129799 31490 13.431610 -69.895599 8.307755 31491 12.598984 -69.887115 8.764481 31492 12.416504 -72.209534 7.173393 31493 19.215492 -72.078033 7.815597 31494 19.739075 -70.983688 7.866363 31495 18.066177 -71.860275 8.819641 31496 18.266556 -73.186859 7.794433 31497 20.589973 -72.125717 8.099747 31498 24.278442 -69.222977 9.065321 31499 23.698708 -70.186447 9.637474 31500 51.449921 -70.449554 8.969139 31501 6.195511 -72.082291 7.230468 31502 11.895172 -70.651062 8.638504 31503 17.360413 -73.576279 7.921615 31504 17.594116 -74.089401 7.615432 31505 19.490555 -73.460709 7.786865 31506 37.373344 -71.750900 8.287331 31507 44.506851 -71.717285 8.717926 31508 43.524170 -71.277832 9.301865 31509 45.468430 -72.308029 8.491554 31510 46.419083 -73.032059 8.735443 31511 16.834793 -74.331238 7.940567 31512 17.315605 -74.814697 7.772644 31513 17.505737 -72.987976 8.475372 31514 21.586807 -72.667816 9.481483 31515 20.385284 -73.641998 8.636124 31516 39.937492 -73.585220 8.219727 31517 39.479851 -73.228104 9.210251 31518 47.509155 -73.466324 8.251358 31519 45.716156 -72.855850 9.284851 31520 10.468124 -76.529785 6.669410 31521 18.332443 -74.641174 7.847946 31522 18.247452 -75.520798 8.679047 31523 18.777649 -75.180756 8.404381 31524 19.359955 -74.609390 8.332054 31525 25.290405 -73.458511 7.700210 31526 24.927490 -74.477219 7.289886 31527 41.386414 -75.028427 9.581772 31528 47.441406 -73.685974 10.070328 31529 50.220627 -73.110855 10.296532 31530 49.141037 -73.799500 10.081451 31531 49.539093 -73.463852 10.914467 31532 11.536400 -76.809433 6.799713 31533 11.177063 -75.112411 6.852722 31534 10.732880 -75.971878 6.921585 31535 24.510818 -74.744904 7.691703 31536 43.676178 -75.931503 8.249352 31537 11.647263 -77.558014 6.892730 31538 11.990181 -77.473694 6.991050 31539 12.152573 -77.707214 7.000045 31540 22.058403 -77.079300 7.207977 31541 22.847260 -76.448959 7.431938 31542 11.903008 -77.899902 6.803215 31543 12.560303 -78.885880 6.731521 31544 20.917801 -78.374802 7.395218 31545 21.290054 -77.105972 8.516068 31546 20.721054 -77.856857 8.570801 31547 45.942917 -77.896347 7.396850 31548 45.466797 -77.554443 8.207466 31549 12.957489 -79.814636 6.835861 31550 17.321808 -79.877808 8.214279 31551 20.337311 -79.669067 6.832580 31552 34.514984 -80.009613 7.157852 31553 34.439705 -80.657654 8.191833 31554 33.660309 -80.268860 7.669410 31555 44.613464 -78.672211 8.048386 31556 43.950394 -79.734390 7.856666 31557 43.908035 -78.841553 8.838074 31558 43.219238 -80.145859 8.788116 31559 45.442871 -78.405502 7.627388 31560 32.443619 -80.822021 7.395660 31561 32.994728 -80.380325 7.393951 31562 36.275307 -80.578156 7.410125 31563 43.568787 -80.409180 7.722160 31564 5.486305 -82.198318 7.570816 31565 5.331337 -82.448364 7.964187 31566 5.667763 -83.024231 7.910919 31567 5.394646 -80.834244 7.880508 31568 9.106110 -81.907608 6.853828 31569 10.218788 -81.780838 8.094589 31570 13.558281 -79.861679 7.577827 31571 13.852325 -80.414001 7.901931 31572 20.262138 -79.423279 7.996040 31573 31.944262 -81.455612 7.009674 31574 40.064240 -83.986877 7.717315 31575 39.691246 -84.643173 8.202065 31576 40.463867 -84.453568 8.411415 31577 37.290543 -81.259094 7.462158 31578 38.372818 -81.493500 7.045661 31579 31.451988 -82.621964 6.900192 31580 39.185547 -82.234070 7.050956 31581 38.191788 -82.311325 7.621673 31582 40.193085 -82.961639 7.071311 31583 39.107117 -83.191666 7.628326 31584 40.906906 -83.507751 7.310127 31585 6.343491 -85.805740 6.937995 31586 10.740807 -86.612823 6.771072 31587 31.873522 -83.962280 7.864059 31588 32.215767 -81.837143 8.054543 31589 30.806396 -85.212906 6.857910 31590 40.805756 -84.026840 7.765396 31591 11.550323 -84.669800 8.012115 31592 10.763298 -84.024582 6.797904 31593 15.297142 -84.940674 8.951912 31594 15.473373 -83.342880 9.014481 31595 14.929855 -86.537827 7.364044 31596 14.346275 -87.780807 6.532516 31597 28.866165 -87.919327 7.258972 31598 35.600288 -88.111725 6.023483 31599 6.904900 -85.437225 8.686234 31600 6.360077 -87.739639 8.285835 31601 35.539513 -89.176773 5.958145 31602 13.765862 -89.550705 6.065353 31603 36.060852 -90.894363 5.808700 31604 6.433891 -89.795822 7.037750 31605 6.601387 -90.310165 6.210372 31606 10.116104 -89.010056 6.261116 31607 14.079773 -88.789413 6.585518 31608 28.059479 -90.010880 7.347030 31609 27.989014 -89.217300 7.318862 31610 6.877640 -91.113876 6.688079 31611 28.782059 -90.545914 7.562072 31612 12.916122 -90.823502 7.351028 31613 21.451607 -93.238876 6.394743 31614 21.846954 -94.667786 7.487426 31615 22.275955 -93.471466 6.573623 31616 11.874649 -91.386475 7.154655 31617 11.952957 -91.031769 7.990554 31618 11.340508 -91.058334 7.869438 31619 22.856766 -94.502563 6.351310 31620 23.293198 -95.610962 5.882087 31621 31.753702 -94.465332 6.775200 31622 31.301949 -93.132309 6.818534 31623 30.814087 -93.804214 6.302375 31624 9.595062 -95.937897 7.285659 31625 31.721140 -95.561218 7.075927 31626 32.108963 -95.207153 7.739006 31627 9.891640 -96.278763 6.240325 31628 15.031509 -96.632523 6.020225 31629 16.407349 -96.787659 6.065246 31630 15.615524 -95.603073 6.663597 31631 16.040314 -95.579727 7.523712 31632 20.601410 -96.872879 7.447601 31633 20.479218 -95.667419 7.478706 31634 31.234756 -95.843353 6.483856 31635 16.093498 -96.894745 7.598815 31636 30.969704 -96.298676 8.024292 31637 10.715317 -97.884842 7.132301 31638 16.472061 -98.145187 6.428466 31639 16.771744 -99.292084 6.223074 31640 17.082115 -98.937500 5.656127 31641 29.248222 -98.241180 6.191665 31642 14.227890 -100.464432 5.532677 31643 24.081993 -99.303101 6.115875 31644 24.635696 -99.677780 6.021743 31645 26.607903 -99.406433 5.578751 31646 26.367737 -99.466919 7.080093 31647 18.034256 -100.727905 6.640785 31648 16.834320 -100.217499 6.863769 31649 25.453278 -99.618591 5.892486 31650 13.786011 -100.862030 5.557625 31651 17.332611 -100.799103 7.291061 31652 18.023193 -100.706985 8.230721 31653 19.359093 -100.615005 7.187576 31654 7.555588 65.516800 16.888069 31655 9.244728 65.312943 17.074089 31656 5.520310 64.206055 16.680138 31657 12.272003 64.652328 16.201057 31658 4.350556 62.657043 16.563805 31659 15.961105 58.905090 17.003059 31660 16.562569 59.142075 16.903732 31661 16.069778 60.180511 17.328659 31662 17.300606 60.038010 17.273933 31663 18.432503 60.127426 17.770805 31664 17.320511 60.990463 17.672127 31665 14.974838 59.127045 17.105301 31666 16.953369 59.544891 16.985718 31667 17.070183 59.000458 16.902260 31668 17.696594 59.173157 17.234489 31669 23.656235 57.268265 16.591469 31670 23.691673 58.024506 16.510368 31671 24.501526 57.943939 16.826698 31672 4.366585 57.584930 17.569580 31673 17.022552 58.104416 17.015656 31674 25.789383 57.642166 17.180183 31675 26.982910 57.639984 17.310905 31676 15.488510 58.036148 16.788979 31677 14.471428 58.221909 16.624756 31678 24.627472 56.818573 17.114357 31679 23.660065 56.080902 16.781128 31680 22.680740 55.173340 16.625282 31681 7.410309 55.815521 17.586349 31682 7.302536 55.377136 16.773026 31683 7.878990 54.731049 16.582870 31684 16.058365 57.043137 16.516090 31685 18.172562 56.926147 17.371971 31686 23.673172 55.240768 17.066788 31687 30.525421 55.396210 18.488243 31688 31.711748 53.940399 17.866760 31689 31.719240 54.010010 18.949745 31690 19.774757 55.648224 18.232819 31691 19.245384 55.188019 17.564072 31692 20.348221 54.473892 17.467941 31693 21.652786 54.317688 16.854683 31694 19.015327 54.423401 16.472168 31695 18.390800 55.561539 17.041328 31696 31.806520 53.162415 16.640526 31697 31.957712 53.255203 17.181358 31698 8.633118 50.464432 16.622803 31699 8.836746 51.653687 16.761719 31700 31.798998 52.436295 16.471603 31701 32.039841 52.467407 16.948280 31702 31.745577 51.538956 16.848068 31703 36.804214 50.144348 16.435356 31704 35.740433 49.342468 16.149124 31705 3.346642 49.865372 16.788414 31706 3.864739 49.599213 16.168350 31707 4.502991 50.808197 16.711433 31708 6.188744 51.447723 17.080826 31709 4.794968 52.502548 17.716904 31710 5.578438 49.731537 16.117126 31711 4.614189 49.240448 15.951279 31712 38.674187 48.927505 15.797165 31713 3.450310 48.282700 16.125504 31714 7.722778 48.428375 15.700600 31715 6.807823 49.340164 16.039856 31716 7.971351 49.742859 16.261284 31717 7.815292 51.001984 16.836220 31718 3.246773 49.160217 16.334534 31719 2.596993 48.096832 16.829330 31720 2.646568 47.119507 16.923126 31721 9.507629 48.979538 15.987999 31722 37.771759 48.309921 16.069527 31723 34.590385 46.678284 15.871765 31724 36.662956 47.654541 16.410133 31725 35.577530 47.412933 16.414185 31726 35.241196 45.599701 15.657341 31727 35.504303 46.517136 16.202873 31728 36.259789 46.910797 16.277397 31729 2.506188 46.113861 16.882133 31730 2.629372 45.404388 16.850586 31731 34.042831 42.095978 15.980835 31732 3.263237 44.518616 16.330406 31733 4.391502 42.894226 17.387810 31734 3.455078 43.757889 17.315346 31735 28.406937 46.004211 16.156738 31736 33.135254 41.654648 16.415855 31737 32.279503 41.626953 16.262718 31738 32.897415 42.412903 15.835449 31739 45.158554 43.562958 17.694771 31740 46.295532 42.552124 17.039444 31741 46.267639 42.640076 18.247154 31742 45.400970 43.236588 18.408325 31743 6.230118 41.447357 15.946640 31744 31.327835 40.864258 16.533905 31745 33.966553 41.620819 16.536072 31746 34.683868 41.834717 16.306099 31747 35.323395 42.070099 16.525208 31748 36.112610 42.401917 16.333214 31749 36.993698 42.751816 15.915192 31750 7.489891 40.303543 15.443459 31751 46.405487 41.066650 16.701012 31752 7.258606 40.739807 16.383286 31753 8.654465 39.663666 15.336090 31754 8.239548 40.240677 16.549782 31755 26.793182 40.409073 15.999878 31756 45.333740 39.733398 16.454872 31757 45.906525 40.019501 17.435188 31758 9.188461 39.619446 16.269043 31759 10.502197 38.569443 15.451111 31760 9.678848 39.156067 15.447090 31761 30.441757 40.097946 17.219643 31762 30.469177 40.174988 17.906441 31763 29.633804 40.191010 17.872902 31764 43.639191 38.612045 17.557388 31765 44.338257 39.094421 16.576614 31766 46.739517 41.959305 17.480499 31767 3.479378 36.900787 15.305130 31768 5.942192 36.859711 16.876366 31769 5.121155 37.263702 16.300766 31770 3.869972 37.540100 16.260269 31771 4.380303 37.613098 16.869942 31772 4.977402 37.197861 17.474564 31773 13.316284 36.187546 16.975136 31774 13.284309 35.706604 16.067543 31775 42.160858 38.051559 17.428474 31776 40.608963 37.254684 16.070442 31777 48.224030 36.042999 16.630707 31778 13.080627 35.722076 15.419029 31779 12.918549 35.655090 15.057312 31780 37.330582 36.040314 15.888245 31781 39.087196 36.596436 16.867844 31782 39.615936 36.794479 16.156502 31783 46.506805 35.811554 16.219261 31784 3.351563 35.420090 16.102959 31785 3.646225 34.533218 15.127563 31786 34.860001 33.892593 16.658249 31787 35.406387 34.737122 16.556580 31788 49.315552 34.891922 17.032761 31789 3.934280 33.705566 15.094009 31790 43.749268 34.052734 16.571594 31791 4.611740 32.502625 15.021988 31792 35.865402 35.261398 15.941368 31793 5.586639 30.574600 15.567871 31794 35.181900 32.479034 15.962318 31795 40.847488 32.645859 16.773384 31796 2.756276 24.173973 11.012308 31797 51.937973 31.154434 17.292183 31798 52.057678 30.591629 15.740379 31799 2.798358 23.948595 11.440254 31800 6.192513 29.847290 15.299408 31801 50.377426 32.430313 17.206726 31802 49.738922 33.203705 17.239662 31803 50.470032 31.385590 16.016693 31804 51.220856 31.251083 16.217949 31805 2.988012 24.505348 12.126602 31806 5.763054 28.899658 15.158234 31807 3.771767 27.241684 14.798172 31808 3.515186 26.088823 14.185366 31809 5.403908 27.874329 16.062531 31810 4.918366 26.576080 16.407753 31811 3.951782 25.765442 16.512695 31812 3.665756 26.336014 15.554352 31813 53.140442 28.132172 16.449005 31814 2.928976 23.174873 12.757763 31815 2.982488 23.926287 12.562893 31816 3.545103 25.627340 14.681997 31817 53.245682 29.420853 17.032646 31818 52.918976 25.522720 15.358253 31819 53.941223 24.296295 15.459831 31820 52.263565 25.293777 15.925346 31821 53.089661 24.814774 15.591965 31822 29.796638 22.779770 13.931885 31823 54.222260 24.288605 16.487556 31824 55.980652 23.352737 15.634148 31825 55.350327 23.801758 16.242508 31826 56.302734 23.180145 16.552055 31827 2.738203 18.839931 13.876713 31828 2.812695 17.920404 14.663490 31829 29.876968 22.007629 14.182701 31830 56.770523 22.393738 15.125603 31831 29.408432 20.275467 14.580139 31832 29.243469 19.365082 15.089096 31833 29.614914 19.309677 15.573029 31834 30.869522 21.417023 14.460632 31835 41.055450 20.019760 14.859375 31836 40.208511 19.781250 14.486549 31837 41.680740 20.239166 15.139740 31838 50.922729 20.124817 14.365578 31839 2.637351 16.531313 14.331490 31840 30.888542 19.988037 15.651222 31841 39.374886 19.526184 14.749725 31842 38.883888 19.116516 15.634323 31843 50.650909 20.173370 15.273003 31844 52.059097 19.790070 14.908607 31845 36.459610 18.885971 14.679413 31846 37.511658 18.725601 15.652344 31847 38.367233 18.549881 16.794998 31848 54.407471 18.673416 15.108078 31849 53.187897 19.240219 15.490250 31850 29.418457 18.497253 14.768288 31851 29.758972 17.565414 15.857956 31852 29.926514 16.586899 16.273773 31853 47.671021 17.306030 16.259415 31854 43.618958 16.506104 16.664101 31855 50.746613 16.947479 16.398361 31856 57.757858 17.266281 16.889664 31857 56.700516 17.283783 15.965019 31858 56.530792 16.181442 16.784180 31859 41.017075 15.439545 14.530396 31860 42.413727 16.106842 16.732018 31861 42.065430 15.852722 15.776283 31862 42.273834 15.833633 14.800568 31863 49.288467 15.502594 14.997833 31864 41.049271 15.490005 15.366203 31865 48.287796 14.818909 15.044670 31866 51.365082 15.775696 15.702843 31867 29.185806 12.933304 15.315811 31868 29.500397 13.838837 15.365303 31869 35.617432 13.396301 14.778542 31870 36.773636 14.184891 14.739769 31871 45.735657 13.423172 14.470276 31872 46.737839 14.083786 15.120216 31873 29.862274 15.268173 15.449097 31874 30.051605 14.145950 16.925941 31875 33.279816 12.678116 16.494888 31876 34.522430 10.991974 15.458832 31877 34.609711 12.836288 15.400841 31878 45.080002 12.606140 14.874596 31879 49.920471 11.180145 15.598763 31880 29.267853 11.940353 15.067490 31881 29.671921 10.924469 14.547028 31882 29.965416 11.230865 16.021095 31883 29.347908 11.760254 14.371498 31884 45.067108 11.271118 15.325500 31885 45.424026 10.874084 15.360657 31886 45.887207 10.772995 14.982010 31887 47.541626 10.786102 15.547272 31888 48.331787 10.772812 16.338219 31889 48.639633 10.873642 15.512749 31890 55.225067 10.801041 17.134346 31891 54.128128 11.051544 17.913231 31892 30.143051 9.960739 14.066078 31893 30.785965 8.962250 14.175323 31894 30.189865 9.867371 15.015305 31895 36.504143 8.105164 13.951187 31896 36.236359 9.148636 14.114151 31897 56.271347 9.676636 14.534035 31898 31.941942 6.231323 14.364388 31899 36.357895 8.817078 14.095268 31900 54.441437 8.079788 14.404503 31901 31.293945 8.004700 14.296951 31902 31.642092 7.594788 15.322144 31903 42.474731 5.894958 14.058052 31904 43.724731 5.830063 13.933495 31905 44.019531 5.630569 13.505013 31906 43.877563 5.334427 14.134865 31907 59.277023 5.891006 14.705734 31908 32.266922 5.021561 14.350159 31909 32.266777 4.049362 14.692795 31910 36.708153 5.737396 14.862862 31911 37.434425 5.135086 14.857391 31912 38.865479 5.129112 13.606606 31913 40.058426 5.004013 15.388466 31914 41.244003 5.545914 15.150284 31915 44.186096 4.364151 13.727814 31916 56.667450 5.008965 14.759995 31917 55.189941 4.104218 14.328918 31918 57.989029 5.614395 14.426285 31919 43.940430 3.763855 13.907799 31920 50.242523 5.080811 15.025093 31921 50.950546 2.945923 14.359123 31922 54.052704 3.306290 13.972382 31923 61.840973 3.295250 14.993286 31924 61.453125 4.185913 15.655838 31925 61.579102 4.086105 14.449516 31926 32.325592 2.946022 14.753868 31927 33.068787 2.163879 13.733589 31928 43.579788 1.844559 13.900360 31929 51.772217 2.430725 14.986916 31930 50.873093 2.514755 15.043587 31931 53.874420 3.286667 15.090805 31932 55.365768 4.348907 15.449738 31933 54.532013 3.893494 16.026100 31934 1.943041 3.516782 12.550503 31935 32.968018 1.468857 14.483444 31936 33.966125 0.833939 14.484352 31937 38.205276 -0.419342 13.706764 31938 36.667435 0.226746 14.083855 31939 34.833160 0.870148 13.761032 31940 35.721977 0.782349 13.638565 31941 43.860214 0.786118 13.706497 31942 1.946645 2.422890 12.416595 31943 39.440056 -0.893295 13.091278 31944 44.349258 -0.310440 13.316185 31945 44.122864 0.235977 13.587250 31946 56.131073 -0.884064 13.685829 31947 58.150482 0.205597 13.425690 31948 61.775879 2.250198 15.696198 31949 61.365143 -0.692184 14.317276 31950 1.973379 1.251711 12.738520 31951 40.276978 -1.351929 12.599358 31952 44.274460 -1.666946 13.329849 31953 57.764008 -0.367111 14.109451 31954 59.069809 -0.986771 14.318314 31955 60.339874 -0.540802 13.788261 31956 61.989929 -0.570389 15.478416 31957 61.609039 -1.493729 14.909340 31958 61.877716 -2.050552 16.081833 31959 38.511765 -1.888397 13.508804 31960 44.208054 -2.582077 13.386467 31961 38.477264 -2.737411 13.157692 31962 37.513962 -2.969345 13.528549 31963 37.682510 -1.829376 14.158905 31964 36.435829 -1.982819 15.069557 31965 37.169212 -1.901382 14.638367 31966 36.796776 -2.671143 14.412903 31967 42.922974 -4.009415 13.201912 31968 43.558594 -3.424011 13.243469 31969 44.032349 -2.948166 13.362175 31970 51.494781 -3.835785 13.836746 31971 52.511749 -3.250610 14.344727 31972 41.229523 -5.236389 13.408295 31973 41.315613 -5.782394 13.078102 31974 41.745728 -4.611572 13.394905 31975 42.356720 -4.277679 13.235146 31976 50.442596 -4.388229 14.171692 31977 1.994411 -1.790157 13.527342 31978 2.132879 -4.471505 13.388218 31979 33.619736 -6.548950 13.289330 31980 33.765732 -7.998962 12.767113 31981 33.057289 -7.464722 13.520966 31982 34.335770 -5.535706 13.338470 31983 35.164749 -4.816498 13.314774 31984 48.818939 -5.233337 14.126694 31985 33.070587 -6.603104 14.080536 31986 41.822739 -6.492050 13.450752 31987 42.956055 -6.689056 13.444374 31988 43.537827 -6.722382 13.451582 31989 43.611313 -6.867828 12.880157 31990 43.872116 -6.839203 13.441704 31991 47.173553 -6.094772 13.858025 31992 34.078125 -9.368271 12.920990 31993 44.489517 -7.004898 13.347755 31994 45.328079 -7.077164 12.905434 31995 46.123886 -6.670013 13.127548 31996 32.791718 -8.549667 13.651299 31997 33.321976 -9.162231 13.038322 31998 36.083267 -8.825134 12.282417 31999 36.787354 -9.509323 12.769135 32000 37.653458 -8.816711 12.264198 32001 32.918022 -9.499298 13.603500 32002 35.772339 -9.541641 12.833786 32003 34.957893 -9.842728 13.191618 32004 37.852615 -9.640594 12.822594 32005 38.722260 -10.427216 13.282280 32006 40.632996 -11.461639 12.639206 32007 39.954056 -10.113708 12.560829 32008 37.282188 -10.521301 13.685921 32009 33.452019 -9.776566 13.359901 32010 34.094650 -10.103424 13.700592 32011 35.734253 -10.475952 13.897713 32012 34.781754 -10.333557 13.869400 32013 39.751633 -11.079239 13.176743 32014 2.943235 -11.344644 13.774223 32015 2.925243 -10.545280 12.665836 32016 39.950859 -12.173050 13.553772 32017 39.227280 -11.382828 13.869537 32018 41.304138 -11.487808 12.254082 32019 40.485504 -12.559631 12.595505 32020 39.617081 -13.561127 12.851608 32021 39.935280 -13.067078 13.081535 32022 46.545029 -14.451553 12.564667 32023 48.144363 -14.370926 12.560310 32024 61.270920 -14.622665 12.656883 32025 62.540085 -13.510361 12.302727 32026 37.640343 -14.823547 12.506927 32027 38.254143 -14.456741 12.795616 32028 45.365631 -15.247620 12.346565 32029 47.299301 -14.179031 12.643425 32030 47.261902 -14.685120 12.837431 32031 48.843597 -15.320312 12.413643 32032 62.533844 -14.528519 12.709198 32033 63.188889 -15.502975 13.108688 32034 36.904648 -15.339005 12.537430 32035 44.337219 -15.587158 11.895554 32036 61.446747 -15.462021 13.059349 32037 62.353470 -15.971542 13.425072 32038 34.145279 -17.660019 12.368942 32039 44.343384 -16.712570 12.645203 32040 48.299088 -16.746094 12.585320 32041 63.197296 -16.005508 13.438423 32042 3.775130 -15.815410 13.930372 32043 4.018215 -16.695078 13.676174 32044 4.518890 -17.418312 11.910789 32045 4.357531 -16.897755 12.051222 32046 4.392455 -17.191343 12.215374 32047 4.473997 -17.557888 12.358740 32048 33.619904 -18.311707 12.386391 32049 35.678162 -16.208511 12.748108 32050 34.885834 -16.814438 12.492828 32051 40.366592 -17.813095 12.303787 32052 41.528992 -17.513306 12.391121 32053 42.676437 -17.604492 12.906609 32054 41.348541 -18.346664 13.468384 32055 42.529800 -18.995148 14.063042 32056 60.864227 -16.675674 13.124222 32057 4.898365 -18.756306 12.064278 32058 34.574387 -17.123383 12.425400 32059 63.876083 -17.382416 12.984604 32060 38.320053 -19.359818 13.340910 32061 47.946442 -18.830460 12.557259 32062 47.422516 -19.678009 12.481461 32063 59.694031 -19.022079 12.766991 32064 58.662354 -19.885391 12.342972 32065 60.731796 -19.567459 13.390099 32066 59.779495 -20.086105 12.985435 32067 59.411667 -21.120865 12.885559 32068 64.092087 -20.142456 12.923836 32069 62.992828 -19.250565 13.673141 32070 35.838242 -21.976578 12.871651 32071 58.034821 -20.923569 12.085770 32072 64.803223 -20.178696 12.158203 32073 62.856201 -20.218628 13.725174 32074 31.596329 -22.068604 15.287132 32075 32.055725 -21.482422 14.112373 32076 31.349319 -23.383484 14.153786 32077 34.956940 -23.355927 13.076958 32078 35.234406 -23.095596 12.374504 32079 44.777878 -19.899445 14.177368 32080 46.425079 -19.913803 13.295113 32081 45.385345 -20.827957 13.412926 32082 59.583725 -21.989395 13.082306 32083 6.553073 -23.052505 11.657398 32084 6.005026 -21.410139 11.307508 32085 6.255426 -22.232349 11.547550 32086 56.883774 -22.997177 12.972321 32087 59.928070 -23.773254 14.366165 32088 7.499571 -24.408665 10.659775 32089 31.853548 -24.167862 11.797401 32090 44.686523 -21.885986 12.969070 32091 7.862381 -24.605501 9.931204 32092 8.504410 -24.756021 8.328909 32093 32.330551 -25.687973 12.720093 32094 31.754732 -24.711136 12.655334 32095 47.953796 -25.412231 13.036575 32096 47.314819 -25.333633 11.975349 32097 48.730621 -24.589645 12.700127 32098 8.478871 -26.366999 10.840178 32099 8.322517 -25.571671 10.140642 32100 7.821953 -25.245741 10.951935 32101 8.732359 -25.397884 8.788822 32102 8.973598 -25.544249 8.384892 32103 33.019234 -25.502441 15.522766 32104 32.272858 -26.032120 15.653114 32105 32.593033 -25.887650 14.850273 32106 40.770340 -26.288605 12.050108 32107 46.680161 -26.141342 12.672791 32108 62.475174 -25.232666 12.483139 32109 9.305298 -27.324587 10.263147 32110 40.165100 -26.876694 11.931076 32111 61.471420 -26.251373 12.649376 32112 61.911407 -25.914734 11.516403 32113 38.973663 -28.336456 11.741264 32114 38.689888 -29.078720 11.889236 32115 38.686066 -29.896606 11.849480 32116 55.872971 -30.898117 13.103241 32117 55.820023 -30.202118 13.459465 32118 56.465256 -30.456238 12.668381 32119 38.768082 -30.852448 12.602226 32120 38.111725 -29.946045 12.297859 32121 10.960044 -30.589111 10.290239 32122 11.318760 -30.504612 9.811520 32123 59.115570 -31.137924 12.177704 32124 57.259247 -31.508636 12.778305 32125 60.470200 -30.834198 11.891235 32126 64.809784 -31.854828 12.616463 32127 12.784101 -33.085327 9.295689 32128 13.036967 -33.784115 9.263254 32129 13.437644 -33.742939 8.869463 32130 14.020202 -33.313675 8.164801 32131 15.241764 -34.148975 7.431169 32132 16.600155 -35.892128 7.294398 32133 15.934748 -35.062458 7.288866 32134 11.739116 -37.332027 10.478453 32135 10.860521 -35.275303 11.518778 32136 11.533074 -34.609543 10.846092 32137 15.242026 -36.357536 8.245687 32138 56.267212 -37.409576 11.757812 32139 10.919511 -38.028732 10.940369 32140 59.914948 -37.357056 11.295471 32141 59.488251 -37.755844 11.754738 32142 7.255768 -40.461258 10.665398 32143 52.216553 -39.076706 11.464592 32144 53.131943 -38.637741 11.751884 32145 60.418182 -41.303909 11.363892 32146 61.609116 -41.412796 11.424324 32147 50.352722 -40.054810 11.292816 32148 51.285309 -39.625427 11.664925 32149 59.513260 -40.389954 11.468681 32150 59.062317 -38.930389 11.943481 32151 58.234726 -40.346603 11.818100 32152 63.340286 -41.355743 12.809998 32153 63.539886 -40.412155 12.937943 32154 62.310303 -40.711288 11.390694 32155 5.062813 -42.421310 10.464577 32156 49.379517 -40.561310 11.196394 32157 48.516754 -40.865143 12.042839 32158 59.019623 -41.471802 11.453491 32159 57.698135 -41.366013 11.769119 32160 58.372604 -42.309052 11.567734 32161 59.078979 -42.236328 11.417694 32162 4.451286 -43.846283 10.636391 32163 43.695465 -41.732346 11.548843 32164 59.875931 -42.458389 11.571129 32165 61.022614 -42.249130 11.610703 32166 61.810974 -42.424713 11.750595 32167 62.466812 -41.801498 11.753250 32168 4.657364 -44.692520 10.357452 32169 11.300835 -44.505524 9.737473 32170 59.097824 -42.691727 11.522621 32171 11.585960 -45.231888 10.289154 32172 12.313140 -44.716370 9.974640 32173 42.450119 -42.375824 11.340652 32174 5.053528 -45.083206 10.315620 32175 4.665878 -44.987091 11.000679 32176 5.602188 -45.730835 10.952477 32177 10.185593 -47.035797 9.895927 32178 13.197701 -45.029449 10.075119 32179 14.806625 -45.854416 10.425232 32180 6.561462 -45.702744 10.081886 32181 8.033539 -47.157227 10.312721 32182 9.048157 -47.516327 9.893219 32183 15.927849 -46.380219 10.827408 32184 44.107071 -46.084473 11.828690 32185 17.808510 -46.884369 10.441544 32186 18.550781 -47.487549 11.133057 32187 46.344269 -47.200516 11.165741 32188 8.617844 -47.974731 10.426468 32189 10.047279 -48.497314 9.963501 32190 9.607025 -49.729111 10.494675 32191 10.354202 -49.588364 9.854454 32192 11.708275 -46.420227 10.604759 32193 11.240906 -47.638031 10.121681 32194 12.341904 -47.726822 10.762558 32195 20.487854 -48.637024 10.900238 32196 21.378723 -49.277283 10.514542 32197 11.589005 -49.495468 9.933617 32198 10.705772 -50.519424 9.975113 32199 13.000145 -49.845505 10.779564 32200 12.435486 -48.788269 10.393707 32201 12.901779 -48.523590 11.060089 32202 48.305817 -49.247711 10.808083 32203 11.365891 -51.285873 9.929550 32204 10.659409 -51.579041 10.408485 32205 11.656448 -48.453506 10.067009 32206 24.831841 -51.988647 9.574356 32207 48.746368 -49.905273 10.701225 32208 60.082016 -50.309174 11.007195 32209 59.396759 -50.887802 11.503609 32210 60.837814 -49.943695 10.644028 32211 61.275589 -50.396500 10.635880 32212 9.906677 -50.943176 10.787590 32213 12.009758 -50.673676 10.026459 32214 11.361221 -51.744095 10.123055 32215 11.962631 -51.621552 10.205132 32216 12.718811 -51.246948 10.496384 32217 49.415802 -50.462646 10.657326 32218 57.690140 -52.126068 11.681557 32219 60.960358 -50.793243 11.090498 32220 20.794762 -52.592072 9.808624 32221 21.835213 -53.147049 9.435989 32222 21.941856 -51.761383 9.918900 32223 21.052162 -50.642120 10.431450 32224 19.094711 -52.842087 10.495323 32225 25.520615 -53.059189 10.054161 32226 28.274155 -53.485901 9.775528 32227 50.025970 -50.760239 12.220909 32228 48.884567 -49.966736 11.479492 32229 48.885300 -50.038635 12.592682 32230 52.152954 -51.793137 11.579536 32231 53.725510 -52.414520 12.317764 32232 51.712875 -51.830032 10.353752 32233 50.721939 -51.314026 10.901955 32234 57.865021 -51.156952 10.678398 32235 23.142441 -52.534042 9.694305 32236 24.057373 -52.815842 9.811363 32237 25.378044 -54.151031 10.042580 32238 26.423492 -53.899002 10.266983 32239 28.680389 -53.614792 9.387764 32240 55.206360 -53.841614 13.349190 32241 54.606171 -53.040100 13.211800 32242 56.097382 -53.092834 12.608505 32243 60.933792 -52.683594 10.652603 32244 19.924057 -53.736725 9.607445 32245 24.703140 -53.131866 9.937317 32246 9.793915 -56.628281 10.691978 32247 18.943466 -54.495636 9.757462 32248 18.835030 -55.475449 9.413513 32249 18.218246 -55.475449 9.826561 32250 28.327271 -56.080215 10.634445 32251 28.771408 -57.163208 10.235168 32252 59.348450 -55.196548 11.359467 32253 10.577217 -56.323776 9.949043 32254 18.446159 -56.467667 9.378632 32255 25.695290 -55.188477 10.049286 32256 25.463524 -59.333771 9.529434 32257 38.525467 -55.027832 11.283051 32258 40.566223 -56.246994 9.467865 32259 41.466110 -55.389923 10.257156 32260 40.171860 -55.917068 10.110014 32261 43.211243 -55.798874 10.392082 32262 42.462357 -54.765915 11.106567 32263 43.742752 -54.712540 11.599159 32264 18.434967 -58.104584 9.546265 32265 17.064362 -57.523422 10.672768 32266 17.683243 -56.398331 10.056770 32267 17.122261 -55.914841 10.720795 32268 39.397423 -56.611130 10.261711 32269 44.956879 -56.750931 10.143639 32270 7.880607 -57.837524 9.624664 32271 39.191925 -57.500687 10.547859 32272 45.393036 -56.907547 10.235451 32273 47.743286 -56.487579 11.084061 32274 48.972931 -56.600555 11.293777 32275 50.294983 -56.760254 11.401283 32276 52.467438 -57.964081 9.818344 32277 53.532043 -56.507370 12.561340 32278 53.509857 -57.323334 11.287109 32279 52.616913 -56.584305 12.208176 32280 57.407440 -57.852386 10.812042 32281 58.014130 -56.758774 11.528214 32282 8.711777 -59.188156 9.200623 32283 7.812088 -59.365402 10.329918 32284 12.130302 -59.471497 11.119339 32285 12.630997 -58.326340 9.920959 32286 13.482758 -60.161514 10.009018 32287 29.143578 -58.096848 9.565315 32288 57.578979 -58.260025 9.903671 32289 5.300964 -61.565948 8.836868 32290 6.790611 -60.309341 9.143707 32291 6.003655 -60.556427 9.826202 32292 7.269631 -60.163727 9.928093 32293 9.624549 -60.312897 9.126190 32294 14.002625 -59.898773 9.219048 32295 20.001122 -60.771072 9.523056 32296 20.529686 -60.884583 9.045746 32297 25.180824 -60.167618 9.205322 32298 25.203445 -61.003891 9.222687 32299 28.376633 -60.640869 10.817314 32300 55.696228 -57.446198 11.301666 32301 9.581192 -61.000534 9.166473 32302 8.629883 -60.496628 9.639458 32303 10.104568 -60.977402 9.132156 32304 25.818253 -60.450394 9.890076 32305 42.217834 -60.407257 10.184624 32306 10.186021 -61.270187 8.848618 32307 15.317245 -63.144913 8.953186 32308 20.525002 -61.608398 9.454193 32309 25.821922 -61.835663 9.752083 32310 42.754929 -60.765823 10.092537 32311 14.829666 -63.394974 9.189499 32312 23.106422 -63.951752 8.879776 32313 26.191925 -63.207428 9.734589 32314 15.335648 -63.841965 8.732414 32315 21.923843 -64.000580 9.576889 32316 26.352005 -63.782715 9.264839 32317 26.325287 -64.202316 9.149620 32318 26.501686 -64.012299 9.325920 32319 50.749252 -61.886765 11.164513 32320 6.133957 -64.458206 8.566551 32321 13.858940 -63.588547 9.512299 32322 23.092545 -65.077713 8.954865 32323 22.621796 -64.788712 9.323425 32324 26.383537 -64.277008 9.453033 32325 4.172905 -66.295349 9.002350 32326 5.115646 -66.026138 8.958618 32327 5.720680 -66.367126 8.749237 32328 13.755006 -65.995117 8.691429 32329 12.626205 -65.977066 9.259750 32330 22.614944 -65.664154 9.224075 32331 22.218643 -65.093872 9.687393 32332 23.302734 -65.921082 8.654707 32333 26.415543 -65.820038 10.718040 32334 26.666595 -64.692017 10.976257 32335 54.114594 -65.578018 9.860443 32336 3.300179 -67.670609 9.917381 32337 6.455879 -66.438492 8.823303 32338 6.059235 -65.473679 9.417450 32339 13.219498 -66.821426 8.870575 32340 25.878960 -66.821625 10.264961 32341 53.441879 -66.380203 9.850739 32342 11.789291 -66.990677 9.806152 32343 20.389328 -69.005814 8.341690 32344 19.732750 -68.155304 9.217598 32345 21.196396 -67.205780 9.445450 32346 28.352219 -65.793198 9.768234 32347 27.803261 -68.565598 8.766136 32348 39.152176 -67.771820 8.720200 32349 39.917755 -68.455704 8.969589 32350 11.769821 -65.911453 9.717461 32351 13.383720 -69.147522 8.532600 32352 18.737114 -69.284531 9.171783 32353 18.375702 -68.517410 9.717529 32354 27.596489 -68.085388 10.145233 32355 27.804153 -68.200012 9.538940 32356 27.993034 -67.247604 9.902138 32357 40.015076 -69.017227 9.661575 32358 38.588882 -68.779968 9.838272 32359 37.306038 -69.967087 10.249191 32360 11.874718 -68.881622 9.474785 32361 24.515205 -69.159348 9.737579 32362 27.152954 -69.138367 9.535538 32363 39.582413 -69.113098 10.867317 32364 40.645630 -69.519791 10.246094 32365 52.148224 -69.243790 9.479568 32366 27.012085 -68.038376 10.686386 32367 25.947113 -69.180450 10.497475 32368 51.912506 -70.028809 9.630379 32369 3.756432 -70.838257 8.248024 32370 5.292366 -71.445358 8.297241 32371 4.342690 -70.674072 9.277573 32372 6.063042 -71.156601 8.584900 32373 51.052338 -71.992188 10.337593 32374 51.394897 -70.942154 9.963188 32375 19.924698 -74.658981 9.275803 32376 20.904053 -74.133575 9.907677 32377 37.245834 -71.622070 8.938148 32378 37.084320 -70.898315 9.228317 32379 37.765984 -72.093155 8.939911 32380 38.550499 -72.715164 10.153885 32381 45.000198 -72.524445 9.819931 32382 15.499283 -73.669708 9.423904 32383 14.529366 -74.288025 9.207253 32384 15.441269 -74.732834 8.726723 32385 16.662003 -73.613495 8.562286 32386 16.888824 -72.914673 9.673653 32387 17.407265 -72.023087 10.455223 32388 39.965973 -73.801575 9.738731 32389 49.858963 -73.404724 9.239799 32390 16.080246 -74.362427 8.431412 32391 24.112114 -73.161530 9.455360 32392 40.543121 -74.554169 9.945097 32393 42.462265 -76.025467 9.722282 32394 48.652588 -73.784973 8.959831 32395 16.450447 -75.082169 8.232750 32396 17.316193 -75.491043 8.459854 32397 19.021408 -75.382568 9.280273 32398 43.655792 -76.398560 9.256073 32399 15.684685 -75.770721 9.140823 32400 11.902359 -77.672714 7.053810 32401 45.049423 -77.748611 8.510284 32402 7.225296 -77.491226 9.039230 32403 6.454628 -78.755035 8.178757 32404 7.982879 -79.148941 8.449112 32405 5.264656 -79.329025 9.063507 32406 5.867081 -80.161728 7.705932 32407 20.144089 -78.667389 9.090698 32408 6.337303 -77.165558 8.780411 32409 9.070648 -80.618484 8.026871 32410 15.343093 -80.441788 9.663406 32411 14.955887 -81.865143 8.892029 32412 14.338593 -80.716934 8.415726 32413 14.302963 -79.931015 8.386948 32414 15.419006 -79.580841 8.672356 32415 44.095917 -77.442154 9.167061 32416 5.328285 -79.986481 8.109383 32417 18.512978 -80.401169 8.305870 32418 33.205475 -80.796341 8.291672 32419 35.375481 -80.474213 7.679451 32420 15.286804 -81.613510 10.465660 32421 15.217827 -83.368179 10.941200 32422 15.374947 -82.776749 9.764244 32423 19.902451 -79.681808 8.665436 32424 19.631737 -79.646240 9.453125 32425 19.498154 -80.181763 8.955780 32426 34.082558 -81.250671 9.306931 32427 32.790855 -81.515182 9.208282 32428 35.860970 -81.687103 8.673485 32429 11.058052 -83.281509 7.860641 32430 32.314102 -82.743973 9.097588 32431 37.270508 -82.407303 8.168060 32432 42.931320 -81.551971 8.349197 32433 42.760330 -81.113220 9.236542 32434 10.711121 -82.587784 7.967987 32435 11.931236 -83.967285 8.947823 32436 11.561615 -83.532791 8.519348 32437 38.091225 -83.305588 8.180954 32438 40.690063 -84.021347 9.854210 32439 42.352722 -81.963455 9.147202 32440 6.274147 -84.341797 7.767334 32441 32.348206 -85.303116 7.960601 32442 32.646530 -84.919083 8.410675 32443 38.975769 -84.100754 8.131348 32444 38.055908 -84.163040 8.762100 32445 37.620758 -84.743698 9.942413 32446 38.863373 -84.837921 8.835236 32447 42.073532 -82.789261 8.591476 32448 41.471344 -82.639893 9.757690 32449 12.082428 -85.350311 8.973145 32450 12.102158 -84.652557 8.956741 32451 15.526779 -83.758209 9.763786 32452 15.236389 -84.450699 10.247940 32453 32.587753 -84.063477 9.148232 32454 31.620836 -85.864075 7.769928 32455 11.219574 -86.263580 7.595367 32456 11.677040 -86.217224 8.552155 32457 14.100220 -85.489426 10.409973 32458 14.949295 -84.481705 10.838615 32459 32.461807 -88.934586 8.551445 32460 33.935219 -87.934677 8.807587 32461 32.701523 -86.980438 8.365143 32462 32.418076 -86.022705 7.993362 32463 32.828369 -85.844818 8.332016 32464 39.785645 -84.959106 9.237595 32465 38.797287 -85.267654 9.885300 32466 39.762878 -84.922668 8.563751 32467 10.823341 -87.409744 7.466598 32468 14.535202 -87.601181 7.447807 32469 14.227707 -88.303268 7.435791 32470 33.339844 -86.267197 8.694931 32471 10.493118 -88.629395 7.341476 32472 28.767311 -88.877701 8.001396 32473 29.267792 -88.925339 8.524445 32474 29.677261 -88.199783 8.180769 32475 10.341736 -89.543716 7.022453 32476 13.785553 -89.454086 7.216011 32477 10.835327 -90.505402 7.318786 32478 10.495544 -89.524704 7.492134 32479 29.878059 -91.312668 7.352859 32480 28.675003 -89.854935 7.929229 32481 29.611137 -89.455368 8.500229 32482 7.473648 -92.422409 7.146102 32483 12.092583 -91.936905 6.303253 32484 12.632469 -91.742508 6.667564 32485 31.285828 -92.158249 7.279891 32486 31.270187 -91.128006 7.903839 32487 32.551239 -91.832092 8.057190 32488 32.512840 -90.480972 8.359688 32489 32.290482 -93.106461 7.488204 32490 8.352249 -93.706604 10.103760 32491 7.442383 -92.296967 10.159348 32492 8.001525 -92.921707 10.917435 32493 20.541588 -94.764191 7.123893 32494 20.977219 -94.149231 7.033782 32495 33.346756 -92.834778 9.049362 32496 14.542633 -95.576553 7.804472 32497 15.095139 -94.681290 7.676010 32498 15.625084 -94.507919 7.850525 32499 32.606583 -94.153168 7.790556 32500 9.019028 -95.026917 8.160522 32501 10.100372 -96.887726 6.860435 32502 14.218628 -94.565369 9.617371 32503 14.705185 -94.352402 8.532440 32504 22.717377 -95.826172 6.902877 32505 10.072937 -96.886765 7.714790 32506 22.747650 -97.134857 7.147300 32507 30.307846 -97.139008 7.699752 32508 10.533783 -97.207047 8.638382 32509 13.726044 -97.685089 7.679153 32510 15.780701 -98.085999 7.986007 32511 15.755516 -98.969467 7.886413 32512 16.210327 -99.089508 7.130813 32513 20.571777 -98.697113 7.613266 32514 20.066818 -97.451263 8.801056 32515 23.233368 -98.742035 7.111625 32516 31.829134 -95.358932 8.939436 32517 31.759890 -94.514572 10.405632 32518 32.293892 -94.686249 9.473434 32519 13.344475 -98.558090 7.479156 32520 12.713928 -98.586700 7.821548 32521 13.161537 -97.771439 8.108437 32522 28.128006 -98.509018 7.329139 32523 27.047638 -98.784164 8.006165 32524 29.063965 -97.876892 7.896286 32525 29.434563 -97.965454 7.066848 32526 21.253922 -99.980362 6.164810 32527 21.036804 -99.674927 6.821792 32528 23.617889 -99.641769 8.200516 32529 24.572479 -99.673019 6.988121 32530 13.296234 -100.457108 5.900573 32531 13.760887 -100.470428 5.935142 32532 20.856613 -100.343292 6.611022 32533 25.107956 -99.642151 8.605957 32534 26.265427 -98.991135 8.622711 32535 20.214378 -100.630692 6.528991 32536 7.744323 65.169235 17.483002 32537 4.415588 62.732071 20.728844 32538 5.304176 64.039673 20.020821 32539 5.827217 64.351425 21.001274 32540 5.668617 64.062225 17.765900 32541 9.062302 64.633698 17.762909 32542 7.655944 64.513565 18.875412 32543 10.134293 64.568390 17.219772 32544 4.462914 62.784515 19.556145 32545 5.592926 64.036072 19.101883 32546 4.107956 62.179642 17.510605 32547 4.344109 62.365662 18.528587 32548 10.544762 62.295212 18.123993 32549 10.950867 61.777466 17.894585 32550 14.320679 60.533249 17.595093 32551 14.189255 62.957581 19.384995 32552 14.397034 62.442383 18.605583 32553 15.437248 62.561783 18.901421 32554 17.237396 62.003510 18.310600 32555 17.761292 61.564941 17.900871 32556 18.057640 61.780289 18.248825 32557 15.107605 61.624237 18.018623 32558 16.255562 61.712097 18.068710 32559 17.939819 62.270004 19.022179 32560 18.869690 61.414795 18.723587 32561 3.640175 60.379303 17.628029 32562 11.879654 60.811279 17.505447 32563 13.033554 60.416168 17.562271 32564 13.390976 61.272736 18.105164 32565 14.078629 61.742126 18.216995 32566 18.214485 61.162949 17.923126 32567 19.775223 60.127380 18.706749 32568 3.744988 58.752640 17.669441 32569 19.091675 58.279724 17.920654 32570 20.660248 59.043320 18.790207 32571 19.066551 56.459183 17.849586 32572 26.602081 57.023285 17.674446 32573 25.606689 56.387924 17.589333 32574 27.466614 57.223602 17.665092 32575 28.423492 56.739944 17.859627 32576 27.394272 56.596161 18.153992 32577 7.109024 56.280212 18.595413 32578 7.863449 55.665985 18.160645 32579 8.222855 54.954483 18.018013 32580 8.016159 55.292480 17.396835 32581 24.621124 55.392548 17.561577 32582 29.265808 56.199692 18.480789 32583 30.992523 55.041138 19.859489 32584 8.336113 54.765091 17.307915 32585 20.491692 55.345871 18.576210 32586 23.688110 54.635910 17.516441 32587 22.831268 54.280487 17.754509 32588 23.671455 54.263382 18.070168 32589 2.985420 52.019043 17.841080 32590 3.178642 51.995636 17.506020 32591 3.162026 52.617188 18.191963 32592 3.741295 52.070648 17.461655 32593 3.744980 53.124191 18.391975 32594 3.207367 51.092209 17.678902 32595 6.120606 53.219696 18.420349 32596 4.604370 54.108139 19.284592 32597 7.549088 52.504120 17.604225 32598 31.848925 52.281250 17.974396 32599 30.915680 50.798203 18.018044 32600 30.891937 51.667572 19.134735 32601 8.484268 51.121368 16.931107 32602 31.420593 50.675186 17.258186 32603 31.641573 51.216400 17.551605 32604 28.281067 48.690933 17.652138 32605 29.291649 49.198914 17.597816 32606 28.973694 48.279266 17.104439 32607 30.315872 49.702713 17.339005 32608 31.007690 50.246964 17.388123 32609 36.403259 48.669220 16.435089 32610 2.834610 48.804596 16.871124 32611 24.822540 47.869354 17.716927 32612 24.032204 47.480194 18.678543 32613 24.157898 48.391068 18.286476 32614 25.935318 47.043762 17.219055 32615 25.460648 48.356628 17.761803 32616 26.634628 48.338974 17.672867 32617 24.835342 47.258392 17.571663 32618 27.802834 47.396240 17.010330 32619 27.511017 48.452194 17.667686 32620 24.711334 46.478180 17.635536 32621 27.226822 45.090027 16.332520 32622 25.454613 45.102249 17.193832 32623 24.908653 44.939438 17.887199 32624 24.737373 45.597458 17.755219 32625 40.191772 44.943359 17.115387 32626 24.507339 46.138367 18.273277 32627 41.133026 44.912125 17.770790 32628 25.639816 43.512833 17.314026 32629 25.225754 44.305511 17.797951 32630 26.363907 43.707825 16.582321 32631 38.665009 43.227478 17.577469 32632 26.113708 42.590164 16.670029 32633 26.609894 42.742371 16.179726 32634 25.833633 42.484436 17.269089 32635 37.822502 42.605865 18.467232 32636 36.666931 42.609100 18.250549 32637 37.213737 42.737167 17.125389 32638 5.231690 42.297699 17.079048 32639 26.298203 41.455826 16.907486 32640 26.248634 41.992981 17.902641 32641 31.376663 40.659790 17.815811 32642 35.881615 42.469147 17.418015 32643 35.941086 42.787247 18.211067 32644 35.166733 42.786484 18.201553 32645 33.604233 42.652374 18.465317 32646 34.541428 41.973129 17.197136 32647 32.414734 41.144531 16.696381 32648 33.103531 41.379547 17.265923 32649 46.781982 41.614349 17.918251 32650 46.508514 40.656326 18.067848 32651 46.576752 41.691467 18.795387 32652 32.140877 40.805267 17.170792 32653 10.273209 39.196686 16.801140 32654 27.592209 39.909119 16.734932 32655 26.801628 40.406357 17.020638 32656 28.522072 40.027817 17.519394 32657 42.991486 38.133789 18.596451 32658 44.302032 38.473953 19.194107 32659 44.982117 39.299561 17.814423 32660 4.416947 37.593567 16.149529 32661 11.117592 38.430969 16.412567 32662 8.104660 35.731064 17.160667 32663 6.977989 36.225220 17.231171 32664 13.462753 35.676575 16.593994 32665 39.982910 37.050552 16.999817 32666 40.931122 37.559616 17.169159 32667 36.807480 35.753967 16.593048 32668 37.557007 36.140060 16.490219 32669 38.055099 36.096741 17.253838 32670 45.719986 35.148422 17.219734 32671 46.939484 35.669098 17.482834 32672 47.591461 35.534073 18.581818 32673 47.686432 35.890289 17.705360 32674 48.231216 35.676056 17.970154 32675 3.683045 33.876877 16.003960 32676 3.491463 36.953674 16.839226 32677 3.385704 36.125504 17.895721 32678 36.022728 35.190308 16.937111 32679 44.680527 34.448044 17.142273 32680 11.994904 34.519165 16.245399 32681 11.144135 34.220245 17.322418 32682 10.439392 34.572754 16.358124 32683 12.545540 34.190186 17.703583 32684 11.694099 33.706940 18.145950 32685 34.450897 33.389709 16.422646 32686 34.512833 32.918030 16.426926 32687 49.287155 34.016663 16.613068 32688 4.102615 32.956848 15.664207 32689 42.757080 33.147141 17.287186 32690 36.461243 31.267029 17.232025 32691 36.308548 30.806824 17.867455 32692 35.459900 31.410980 17.671700 32693 35.633163 31.833801 16.727135 32694 40.110504 31.986572 17.058762 32695 4.722809 30.762527 16.998558 32696 5.722733 29.353683 16.461815 32697 34.686615 32.396851 17.084465 32698 36.920059 31.662415 16.612556 32699 50.637421 31.671082 16.561623 32700 2.733675 22.862188 11.843744 32701 6.158119 29.750275 15.721886 32702 6.180626 29.420410 15.480392 32703 3.252449 23.165457 14.339022 32704 3.057572 23.243158 13.382441 32705 52.257309 26.079681 15.922508 32706 51.757111 27.503540 16.970055 32707 52.370392 26.970245 16.219505 32708 52.910385 30.138306 17.422104 32709 52.752686 29.453918 17.850281 32710 3.671603 25.308167 15.502775 32711 50.969925 27.808899 17.920471 32712 51.299805 28.447739 18.713013 32713 52.025742 28.404968 17.830276 32714 51.227112 26.379242 16.806870 32715 3.724296 24.507835 15.889856 32716 50.706955 27.166885 17.455521 32717 51.643661 25.606873 16.371895 32718 51.958466 25.143097 16.602898 32719 52.623901 24.840454 16.354942 32720 53.281662 24.518112 16.277122 32721 57.338654 21.574722 16.050056 32722 57.781738 20.385849 16.243759 32723 30.186859 18.955475 16.437660 32724 41.679550 19.767273 16.249039 32725 43.174377 20.070618 16.266327 32726 43.112579 20.415039 15.305336 32727 57.485916 21.390991 17.193443 32728 57.816574 20.153336 16.994133 32729 32.048813 19.946411 15.567406 32730 40.200165 19.560196 15.702202 32731 40.641449 19.125488 16.812126 32732 44.609970 20.207397 16.479301 32733 50.135773 20.028091 16.682388 32734 51.914825 19.752380 15.981018 32735 51.974075 19.530151 17.102203 32736 2.496287 15.302032 13.888968 32737 34.223030 18.963623 15.588638 32738 35.577713 18.557068 15.619057 32739 39.571831 18.882294 16.708221 32740 54.064468 18.431381 16.344337 32741 53.010864 19.160233 16.599831 32742 36.561569 18.466202 15.732651 32743 36.605469 17.977951 17.108727 32744 55.483139 17.484634 15.945160 32745 56.403015 17.741684 15.443947 32746 29.730927 18.424377 16.050941 32747 49.444000 17.408005 16.665359 32748 48.666260 17.116409 15.862915 32749 51.438202 16.283371 15.948975 32750 57.819855 15.879288 17.636742 32751 45.905930 17.375732 16.936745 32752 44.298218 17.026474 17.380783 32753 52.234741 16.725067 16.871674 32754 51.757568 15.732208 16.306450 32755 52.195847 15.721390 16.814758 32756 55.080017 15.964462 17.039078 32757 30.079453 15.657196 16.912163 32758 36.860245 14.934738 16.198143 32759 52.849930 15.762283 17.091934 32760 50.889633 14.631393 18.356155 32761 53.331268 15.040146 17.827866 32762 33.721100 10.820801 16.108345 32763 34.898094 13.855316 15.610680 32764 35.702736 14.296967 15.640182 32765 45.463470 13.086746 15.578568 32766 46.124207 13.538605 16.313965 32767 47.111725 13.934006 16.819206 32768 47.465179 14.208374 15.972298 32769 44.945251 12.020065 15.976883 32770 29.260284 12.392639 15.817017 32771 56.233002 10.259888 15.341942 32772 34.510307 9.204208 15.915665 32773 31.002151 8.234451 14.771431 32774 30.811417 8.825439 15.265442 32775 33.494095 9.956741 16.347336 32776 30.711693 9.777435 15.908737 32777 55.474655 8.577576 15.468491 32778 56.175369 9.398331 15.484901 32779 51.766327 6.777756 15.452583 32780 52.477386 7.331589 16.408661 32781 53.896851 7.908844 17.222183 32782 52.354156 7.423157 17.341858 32783 36.036690 6.471100 15.318581 32784 41.381897 4.875397 15.826279 32785 42.215561 5.616333 15.044365 32786 43.171066 5.829857 14.377892 32787 50.786224 6.187103 15.510780 32788 59.850769 5.961334 16.336296 32789 58.152924 5.789673 15.484528 32790 60.779449 5.208557 15.132515 32791 58.261917 6.239868 17.430031 32792 58.313416 6.039490 16.608185 32793 59.418549 6.401291 17.344414 32794 38.611801 5.076500 14.655708 32795 32.100845 5.983253 15.478226 32796 32.411781 2.082184 14.541519 32797 37.713196 4.729721 15.480270 32798 38.623260 4.569366 15.804848 32799 43.125809 5.358749 14.899811 32800 43.347488 4.216187 14.731911 32801 42.658234 4.957413 15.399445 32802 50.000732 6.085419 16.207382 32803 49.272186 5.563309 16.457413 32804 49.871094 3.488495 15.062714 32805 49.220093 4.214081 16.091888 32806 50.052124 4.057541 14.904587 32807 61.539673 3.458336 16.238258 32808 43.246750 0.922714 14.635658 32809 43.905670 -0.268677 14.085846 32810 50.182831 2.838684 15.278580 32811 49.630035 3.344200 15.472313 32812 52.588058 2.436340 14.964134 32813 53.005844 2.645844 14.986267 32814 53.748795 3.455032 16.186043 32815 32.298096 2.043594 15.355080 32816 33.078949 1.125153 15.872276 32817 42.411346 2.483643 15.357513 32818 61.921097 0.832001 15.685661 32819 1.943694 3.012402 13.116596 32820 35.094238 0.326370 14.753807 32821 34.120377 0.409882 15.445129 32822 37.132217 -1.070862 14.621811 32823 43.618713 -1.815186 14.359314 32824 57.739410 -1.218536 15.121490 32825 56.737198 -1.356125 15.806885 32826 57.455200 -2.445862 16.096649 32827 55.906006 -1.345383 15.200874 32828 60.194519 -2.261597 14.671669 32829 60.978104 -1.517578 14.431099 32830 43.231659 -0.659195 15.124100 32831 43.826324 -2.719376 13.738823 32832 42.520020 -3.484192 14.229996 32833 58.828461 -2.299301 15.056061 32834 58.646225 -3.458954 15.589256 32835 59.534195 -3.394302 15.202812 32836 61.199951 -2.173584 14.939987 32837 51.488235 -3.918686 14.820251 32838 61.100876 -2.975311 15.353050 32839 40.959198 -4.811218 14.088135 32840 41.122437 -4.120422 14.718895 32841 41.455002 -3.186371 15.585403 32842 49.769867 -4.810165 15.270103 32843 1.950646 -0.982804 14.898092 32844 2.011720 -3.324337 17.058102 32845 1.981212 -2.736726 15.936907 32846 1.975752 -1.173934 16.674608 32847 2.015023 -2.803699 13.987223 32848 2.253455 -5.899120 13.272181 32849 2.325392 -6.152564 12.766630 32850 34.413910 -4.274445 14.965752 32851 33.630859 -5.698746 14.145805 32852 40.086349 -5.538467 14.254242 32853 40.772797 -5.997070 13.974190 32854 47.911011 -5.786453 15.159454 32855 2.217254 -5.766824 13.567938 32856 39.963562 -6.178864 14.184395 32857 39.498299 -5.999359 14.594841 32858 40.003418 -6.865524 14.690376 32859 41.602112 -7.024353 15.589996 32860 42.893661 -6.828094 14.569870 32861 44.121078 -6.848236 14.250015 32862 46.727234 -6.325027 15.407646 32863 45.734604 -6.768936 14.078064 32864 45.542267 -6.754913 15.279060 32865 2.183324 -5.630785 13.949358 32866 32.952667 -5.873489 15.222694 32867 32.636787 -7.440765 14.457886 32868 54.774841 -8.838333 15.165405 32869 53.751282 -8.538986 15.550339 32870 54.224335 -10.475784 15.059052 32871 32.231468 -8.365112 14.783371 32872 32.175751 -7.408737 15.551460 32873 55.450974 -9.442001 14.662354 32874 57.550980 -8.660355 15.067520 32875 58.268448 -9.715927 14.398781 32876 58.790527 -9.050995 14.922722 32877 56.692474 -8.607529 14.811348 32878 56.690506 -9.444595 14.462410 32879 59.134583 -9.481766 14.712593 32880 60.621857 -10.414032 15.390152 32881 61.118011 -9.346527 16.588036 32882 59.643906 -9.151520 15.843285 32883 32.380386 -9.281769 14.601677 32884 33.136536 -10.109375 14.369209 32885 38.099304 -11.324387 14.399971 32886 55.699493 -10.347641 14.439835 32887 57.482162 -10.685852 14.246307 32888 56.580811 -10.855728 14.332626 32889 58.411133 -10.921951 14.374397 32890 59.329544 -10.213074 14.705170 32891 55.679108 -11.432083 14.760208 32892 57.320694 -12.035477 14.668762 32893 59.442307 -11.643234 14.887627 32894 39.893822 -13.045883 13.666519 32895 39.563835 -13.601135 13.535408 32896 38.861130 -14.189209 13.745827 32897 37.816010 -14.826859 13.648872 32898 38.509560 -14.563126 14.734253 32899 36.785576 -15.491013 13.838821 32900 35.881653 -16.270401 14.122688 32901 36.655518 -15.786316 14.646278 32902 46.521317 -15.366592 12.881073 32903 47.696686 -15.437714 12.867821 32904 46.723694 -16.421555 13.100723 32905 3.649244 -14.481775 12.826525 32906 43.955322 -18.797623 13.991020 32907 45.672852 -16.138168 12.880707 32908 47.205963 -17.478271 13.323103 32909 63.136993 -16.684509 13.578537 32910 4.252003 -16.835812 12.496218 32911 34.810333 -17.046799 13.229660 32912 46.263016 -17.210480 13.442841 32913 45.638657 -16.885284 13.155586 32914 46.347244 -17.850082 13.689087 32915 62.115952 -17.093384 13.659897 32916 61.120514 -18.173920 13.367653 32917 62.841110 -17.985382 13.634239 32918 4.241998 -17.156403 13.045502 32919 4.572200 -18.133785 12.736692 32920 33.932800 -18.055206 13.379105 32921 39.188660 -19.233322 13.764366 32922 40.002197 -18.490860 13.326309 32923 45.335281 -17.887436 13.618141 32924 47.966995 -17.932922 12.925781 32925 47.505081 -18.447449 13.324318 32926 47.372940 -19.221146 13.176323 32927 61.760529 -19.961502 13.769440 32928 61.847000 -18.999603 13.737549 32929 5.118772 -19.558247 12.238708 32930 4.711219 -19.047390 13.409031 32931 5.530562 -20.354979 11.641582 32932 34.964439 -17.199860 14.807991 32933 37.266296 -20.511810 13.956673 32934 36.638535 -20.972504 13.819649 32935 46.923035 -18.991577 13.609894 32936 60.649582 -20.649185 13.387749 32937 61.913773 -20.956757 13.708252 32938 62.585922 -22.956802 13.584747 32939 61.192322 -22.889648 13.679642 32940 42.632050 -23.866531 13.232132 32941 43.429443 -23.385376 12.557297 32942 43.856415 -22.926010 12.695328 32943 60.701904 -21.785324 13.385056 32944 34.137909 -24.256180 14.813934 32945 35.209564 -22.985092 14.645493 32946 34.945076 -23.807007 16.102837 32947 44.119736 -22.611618 12.765182 32948 50.711563 -24.314682 13.457115 32949 51.220428 -26.433853 15.075745 32950 49.973328 -26.080673 14.631393 32951 50.566925 -25.351883 14.381371 32952 59.874359 -22.521912 13.312607 32953 63.416351 -23.042160 13.042267 32954 8.083269 -24.572678 9.244238 32955 8.676960 -25.023848 8.285450 32956 8.811536 -25.267742 8.335735 32957 31.023903 -25.146271 14.492043 32958 30.793533 -24.183136 14.967041 32959 31.682543 -24.017410 12.208824 32960 34.567993 -24.230789 12.762207 32961 62.355133 -23.855957 13.425880 32962 8.472423 -24.997326 8.823732 32963 8.307363 -24.847694 9.044931 32964 8.629174 -25.101191 8.550240 32965 41.980850 -24.321655 13.794106 32966 49.384857 -25.014603 13.580666 32967 33.089264 -25.634308 12.846809 32968 33.996231 -24.933090 12.853188 32969 33.599350 -25.064545 13.801331 32970 34.340027 -24.129028 13.689468 32971 32.624306 -25.844955 13.890182 32972 61.729874 -25.645218 13.690521 32973 7.728541 -25.851603 11.911596 32974 31.836611 -25.732727 13.557297 32975 32.429474 -25.934448 13.162399 32976 39.846581 -27.062439 13.036987 32977 61.579514 -24.738647 14.053703 32978 38.810074 -28.271851 12.601723 32979 39.190880 -27.774261 12.932610 32980 60.321899 -26.876160 13.193604 32981 61.092056 -26.163544 13.975464 32982 38.146805 -29.043167 12.957565 32983 42.293274 -29.492798 12.476112 32984 43.140030 -29.452667 13.217354 32985 44.468597 -30.250412 14.511078 32986 56.500854 -29.019958 13.521652 32987 57.850769 -27.492020 14.319153 32988 37.406158 -30.112488 12.913094 32989 56.162186 -27.399399 14.825935 32990 62.638458 -30.019211 13.034378 32991 63.833694 -29.791443 12.890877 32992 64.310410 -30.324158 13.200722 32993 37.684387 -30.684509 12.620972 32994 37.224411 -30.780731 12.966965 32995 40.888489 -30.650787 13.183945 32996 56.247925 -31.336304 12.857162 32997 60.305954 -30.985413 12.978050 32998 61.498444 -30.453842 13.273102 32999 11.874844 -31.320595 9.582010 33000 12.930403 -32.330292 8.861025 33001 37.572021 -31.276535 13.117989 33002 55.929321 -31.466202 13.245232 33003 58.797745 -31.571304 13.245895 33004 60.726303 -30.735336 14.022141 33005 59.579361 -31.240387 13.968536 33006 56.316345 -31.720078 13.085480 33007 57.799072 -31.975632 13.858528 33008 64.461411 -32.625000 14.393272 33009 64.383438 -31.477356 14.829063 33010 64.262177 -30.614731 14.147415 33011 14.461899 -34.428066 8.184731 33012 14.999682 -35.172977 8.019995 33013 11.142908 -36.071457 11.225883 33014 10.003758 -36.026249 12.330017 33015 10.943280 -36.879490 11.276051 33016 13.148586 -34.488846 9.354908 33017 14.004839 -35.340588 8.841166 33018 13.836843 -34.316498 8.682274 33019 15.925797 -35.771748 7.610467 33020 58.849472 -37.623596 12.082275 33021 64.434814 -36.528946 12.438011 33022 55.787582 -37.831940 12.577103 33023 54.941162 -38.045547 12.742210 33024 56.989746 -37.819199 12.613319 33025 57.816422 -37.719910 12.590988 33026 58.374695 -37.886703 12.419891 33027 64.074844 -37.505463 12.743874 33028 53.724365 -38.354324 12.438950 33029 53.098297 -38.698334 12.536064 33030 54.386963 -38.065704 12.353188 33031 63.414886 -37.408447 13.905655 33032 63.843353 -36.194855 13.591362 33033 8.395013 -40.315994 12.211632 33034 9.925659 -38.868835 12.264046 33035 9.580650 -39.449066 12.379967 33036 9.492584 -38.225632 12.527039 33037 9.740753 -38.888565 12.598846 33038 51.985931 -39.289307 12.351547 33039 51.362579 -39.712219 12.492622 33040 52.562653 -38.945419 12.226768 33041 57.755524 -38.468033 12.602509 33042 57.733597 -39.472351 12.257072 33043 63.554565 -39.413483 13.453865 33044 6.103798 -40.907852 11.095274 33045 7.386597 -40.617157 12.036469 33046 6.635742 -40.838196 11.874268 33047 49.736099 -40.347015 12.288139 33048 50.676178 -39.987930 12.162643 33049 56.698914 -40.399536 12.262169 33050 55.463928 -39.424896 12.970169 33051 55.307693 -40.746506 12.583115 33052 56.855743 -39.138901 12.716072 33053 43.274017 -41.509186 12.266998 33054 43.028839 -41.805176 11.690887 33055 42.799530 -41.770782 12.414375 33056 43.864471 -41.568985 12.703011 33057 45.026031 -41.723938 13.082024 33058 47.744263 -41.173340 12.123993 33059 61.140121 -43.398270 11.963783 33060 4.353340 -42.742905 11.290207 33061 4.110870 -42.957108 12.268120 33062 5.367500 -41.683121 12.097435 33063 4.584503 -42.230682 13.082741 33064 42.310089 -42.405731 12.556229 33065 42.099426 -43.112915 11.754196 33066 56.190186 -45.708023 12.131294 33067 55.827927 -46.970810 12.414284 33068 56.620636 -46.895172 12.682983 33069 52.727280 -42.701965 12.454102 33070 54.331726 -43.703415 12.084381 33071 54.071350 -41.584030 12.622139 33072 56.445877 -42.614288 12.019249 33073 59.136261 -43.791199 11.823486 33074 52.845383 -44.703094 11.997414 33075 54.729828 -46.075928 12.075775 33076 62.970840 -42.100922 12.405563 33077 62.355484 -42.949631 12.198730 33078 62.812531 -43.051727 12.869232 33079 3.974999 -43.393875 11.424728 33080 4.045403 -44.280991 11.888992 33081 60.724808 -44.618820 12.276108 33082 12.639786 -45.471832 10.705719 33083 51.409943 -44.212921 12.207130 33084 51.779510 -43.402267 12.398727 33085 51.552261 -45.350510 12.134087 33086 51.685272 -46.384247 12.218330 33087 52.726181 -46.579697 12.005135 33088 53.854248 -46.653748 12.094986 33089 62.028778 -44.136673 12.921310 33090 4.725372 -45.517685 12.285835 33091 12.643387 -46.071442 11.164322 33092 13.745789 -45.449448 10.519127 33093 13.619979 -46.067459 11.294617 33094 14.821823 -46.828491 11.976242 33095 57.852982 -45.222534 12.072876 33096 58.937195 -45.313309 12.010826 33097 59.792877 -45.359024 12.307465 33098 6.816887 -46.496658 10.904938 33099 42.906860 -45.514496 12.750702 33100 58.787415 -46.033096 12.529633 33101 59.816986 -46.140518 13.174881 33102 61.036896 -45.486526 13.138107 33103 16.883972 -46.842346 11.138084 33104 17.581955 -47.217804 11.495445 33105 45.212601 -46.902832 11.912216 33106 46.477539 -48.180573 12.391068 33107 45.160370 -47.417587 12.830864 33108 51.580887 -46.908554 12.961067 33109 52.193848 -46.944366 12.202408 33110 7.496292 -47.709183 11.853416 33111 8.850395 -48.700638 10.944130 33112 47.109192 -48.073929 11.372398 33113 52.621323 -47.419037 12.661514 33114 53.622314 -47.581726 12.511368 33115 10.112381 -51.613907 11.005997 33116 20.910583 -49.517914 10.919106 33117 47.563354 -48.878082 11.673691 33118 48.214294 -49.534561 11.851318 33119 13.570053 -51.529236 11.274780 33120 14.127335 -49.978348 11.926651 33121 18.124710 -51.526962 11.289078 33122 16.732864 -50.656067 12.050308 33123 16.220612 -52.188110 11.857666 33124 18.978951 -50.406235 11.265526 33125 19.563980 -50.921387 10.870918 33126 19.941566 -49.703033 11.155716 33127 18.771126 -48.624329 11.611359 33128 18.760910 -49.698669 11.537628 33129 58.594421 -51.238586 11.411003 33130 60.284576 -51.220688 11.744514 33131 9.084404 -49.384369 11.562416 33132 9.581573 -50.188568 11.751595 33133 11.378006 -52.172836 10.594749 33134 12.375595 -52.371002 10.888618 33135 14.518037 -52.599121 11.857231 33136 14.979874 -51.273254 11.922211 33137 17.033142 -53.335754 11.586311 33138 49.665298 -50.744629 13.468857 33139 50.897217 -51.643860 13.524567 33140 49.519440 -51.368210 14.461594 33141 60.908264 -51.827988 11.375191 33142 27.407112 -55.160248 10.711845 33143 39.246658 -53.188400 11.994667 33144 40.117615 -54.102600 11.003922 33145 39.064575 -54.363937 11.165085 33146 40.382568 -53.252365 11.286621 33147 40.942184 -52.924057 11.480148 33148 40.897858 -53.490677 11.123840 33149 40.318161 -52.904129 11.619995 33150 41.476349 -53.380661 11.372375 33151 60.629150 -52.749451 11.605652 33152 17.365448 -54.532333 11.128952 33153 28.299347 -55.024460 10.495300 33154 40.447357 -55.009644 10.587479 33155 41.031189 -54.227097 10.934654 33156 41.733337 -54.204224 11.160500 33157 17.981262 -54.856689 10.358383 33158 26.282707 -54.869049 10.502342 33159 26.119522 -55.556152 10.476326 33160 28.617775 -55.511948 10.370117 33161 38.469940 -54.278427 11.570221 33162 7.922180 -56.431915 10.075531 33163 7.750762 -56.809509 9.980637 33164 8.005951 -56.892532 10.638000 33165 8.784500 -56.732788 11.065338 33166 26.554543 -56.302124 10.752724 33167 26.566254 -55.420670 10.765205 33168 59.684418 -54.234360 12.081718 33169 58.814331 -55.713455 11.760338 33170 38.555023 -57.351089 11.608383 33171 38.016304 -56.921829 12.497490 33172 44.526398 -55.956131 11.270851 33173 45.053970 -56.612259 10.785110 33174 8.715775 -59.932678 9.804077 33175 11.960785 -58.187500 10.552368 33176 16.119072 -57.624588 11.702789 33177 16.189423 -55.963821 11.585625 33178 14.747673 -56.987457 12.875832 33179 26.725616 -57.539627 11.019157 33180 26.287720 -58.927429 10.728142 33181 27.317093 -58.330276 11.354805 33182 40.146469 -58.762482 11.685226 33183 39.182793 -58.140869 11.557343 33184 45.777374 -56.753891 10.957275 33185 51.809052 -57.148224 11.162224 33186 51.464005 -55.442871 13.081055 33187 57.075104 -57.119720 11.792610 33188 57.036987 -57.525208 11.394341 33189 8.436813 -57.264069 11.731163 33190 7.641264 -58.112335 11.289726 33191 10.365768 -58.957916 12.614273 33192 10.768692 -57.792572 11.387039 33193 40.746994 -59.137054 10.959320 33194 56.667114 -57.921982 10.998451 33195 5.067894 -61.665222 10.089233 33196 8.348541 -60.044189 10.115593 33197 18.414856 -58.874939 11.482254 33198 18.223648 -59.139221 10.922668 33199 17.267189 -58.471573 11.415154 33200 17.899452 -58.736984 10.494125 33201 18.838692 -59.321533 10.183777 33202 19.628960 -60.125259 10.116554 33203 41.597595 -59.755966 10.689850 33204 7.899543 -60.410248 9.783691 33205 20.012421 -60.220016 10.744156 33206 20.126976 -61.118500 10.165337 33207 42.761078 -60.411453 11.234833 33208 4.950195 -63.070923 9.718491 33209 13.271576 -62.799469 10.126640 33210 12.227470 -62.642670 10.812904 33211 12.962654 -61.387375 10.639091 33212 20.106415 -61.833542 10.596626 33213 19.997681 -62.368179 10.591187 33214 20.211525 -62.133804 10.028709 33215 20.899658 -62.858231 9.654907 33216 5.163208 -64.515427 9.791496 33217 20.200027 -63.043289 10.488869 33218 26.668243 -60.790558 11.104256 33219 26.619141 -62.302368 10.923180 33220 44.342438 -61.428894 11.351852 33221 45.548874 -61.367874 12.589073 33222 44.456909 -60.930054 13.211090 33223 45.998032 -62.393280 10.671806 33224 48.895767 -62.383621 10.872047 33225 48.961334 -61.843430 11.761475 33226 52.039398 -61.631989 11.569153 33227 53.957520 -62.048141 11.331329 33228 54.840973 -62.423218 11.597603 33229 5.952026 -64.672073 9.180733 33230 12.547180 -63.826736 9.945450 33231 11.955490 -64.976288 9.749298 33232 20.795837 -64.420135 10.502739 33233 26.404999 -63.859650 9.567902 33234 26.336197 -64.080704 10.044365 33235 28.506607 -61.916901 10.482864 33236 28.234688 -62.762436 10.903030 33237 46.342560 -62.495544 10.621521 33238 11.732239 -64.153503 10.137398 33239 20.120728 -63.740021 11.125549 33240 26.660507 -63.467407 10.959335 33241 55.447815 -62.909698 12.020172 33242 55.209824 -61.987885 12.740051 33243 55.094971 -63.531219 11.232841 33244 5.142067 -65.523178 9.598114 33245 4.342735 -65.214340 10.111557 33246 5.540817 -65.974564 9.358345 33247 11.251373 -64.389206 10.326233 33248 11.010192 -65.383881 10.399475 33249 21.970856 -65.976532 9.713196 33250 54.284958 -65.641159 10.777039 33251 5.940651 -66.093567 9.327026 33252 25.485214 -67.352005 9.968056 33253 27.784439 -66.880096 10.572945 33254 27.938766 -65.371948 10.968842 33255 52.888489 -67.152710 11.515762 33256 17.463058 -66.995041 10.754150 33257 17.407768 -68.123718 10.271210 33258 18.585480 -67.387421 10.290627 33259 17.536507 -70.093445 10.125198 33260 20.067017 -66.849304 10.471344 33261 21.110672 -65.910233 10.351173 33262 20.422485 -65.747864 11.116264 33263 24.936539 -68.570480 9.977661 33264 52.077866 -69.259369 10.311058 33265 51.854187 -68.526306 11.085793 33266 53.965424 -66.342880 12.859123 33267 54.800140 -65.355103 12.951653 33268 54.499161 -65.606125 12.015007 33269 9.933075 -69.182709 10.191551 33270 10.815475 -69.024628 10.004150 33271 10.898743 -70.046921 9.299973 33272 11.783211 -69.887756 9.125458 33273 24.771240 -69.537781 10.413956 33274 26.394165 -68.148117 10.942078 33275 37.847015 -69.063461 11.114227 33276 3.604790 -69.822617 10.139656 33277 4.174049 -69.890030 10.713539 33278 6.482636 -70.581940 9.343903 33279 7.709228 -70.392456 9.325798 33280 51.784012 -70.073517 10.332962 33281 5.512550 -70.751450 9.420456 33282 23.278015 -73.004410 10.307144 33283 24.201523 -71.783356 10.243713 33284 42.741806 -71.103699 9.998215 33285 51.093964 -71.259018 10.919510 33286 37.469559 -71.424988 10.020531 33287 42.567749 -71.275848 11.053871 33288 43.376678 -71.620697 10.240738 33289 44.097961 -71.893509 9.842300 33290 46.047699 -73.236542 10.120636 33291 13.401520 -74.372665 10.069687 33292 14.089272 -74.743134 9.210091 33293 14.455681 -73.768997 9.742630 33294 39.414574 -73.296921 10.052040 33295 50.744873 -72.548111 10.254272 33296 14.737221 -74.970200 8.963539 33297 48.191818 -74.146500 9.806091 33298 48.109192 -74.132492 10.198280 33299 48.554230 -74.152771 9.863342 33300 50.074310 -72.972305 11.228668 33301 14.269302 -75.269470 9.266068 33302 48.304993 -74.293396 10.039017 33303 5.677979 -77.587830 8.794235 33304 5.770866 -76.480804 9.215210 33305 5.027863 -77.114502 9.528709 33306 5.025566 -75.899323 9.849747 33307 6.616097 -76.120621 9.497681 33308 16.016495 -76.459412 10.185074 33309 17.549957 -76.073578 9.954826 33310 22.536972 -74.238449 9.989548 33311 5.850151 -75.639709 9.648163 33312 20.549591 -77.281845 9.480682 33313 21.131660 -75.643143 9.868996 33314 20.046318 -76.547943 10.394653 33315 43.311707 -76.684662 9.704025 33316 19.850098 -77.722397 10.360390 33317 16.310799 -79.552887 8.571869 33318 16.629738 -80.047546 9.547806 33319 9.953453 -80.781555 8.874634 33320 17.405060 -80.344971 10.573410 33321 18.093483 -80.392578 9.528229 33322 9.548065 -80.208527 8.955696 33323 9.075996 -79.437317 9.144730 33324 10.705200 -81.308655 9.441132 33325 19.000519 -80.472870 8.920662 33326 33.129684 -81.522552 10.183281 33327 34.136543 -81.593689 10.451477 33328 5.399048 -81.966492 8.704649 33329 6.196922 -83.554535 9.225571 33330 11.401871 -82.769119 9.212784 33331 34.999733 -81.884018 10.070633 33332 35.565094 -82.289322 9.971954 33333 6.738747 -84.446930 8.890137 33334 37.019356 -83.412720 9.209846 33335 36.035019 -82.871552 10.141068 33336 33.160927 -85.259796 9.199417 33337 14.215523 -87.655121 8.280212 33338 14.107430 -86.784164 9.300507 33339 13.137337 -88.118591 9.282875 33340 33.863312 -86.273041 9.261986 33341 33.657494 -85.605270 9.905472 33342 39.840454 -85.018814 10.448135 33343 11.288139 -87.136612 8.240685 33344 31.136429 -87.635025 8.289932 33345 34.494194 -87.296249 9.379837 33346 34.299835 -86.595291 10.200203 33347 33.799477 -86.969513 8.796707 33348 11.066071 -88.293900 8.370010 33349 13.750710 -88.657761 8.304634 33350 10.750305 -89.508209 7.983222 33351 31.194321 -90.047638 8.430519 33352 30.720291 -89.073944 8.612991 33353 34.372803 -89.011551 9.091141 33354 34.808273 -91.302536 9.732849 33355 34.949234 -90.866226 9.708450 33356 34.091385 -91.146362 8.951202 33357 34.958420 -88.222534 9.515739 33358 12.208321 -90.018753 8.758545 33359 12.047951 -89.412567 9.329041 33360 11.716187 -89.420883 9.215866 33361 13.061951 -89.137527 8.909874 33362 13.243111 -89.610092 8.184937 33363 35.247833 -88.832458 9.979568 33364 6.826119 -91.178040 7.921669 33365 29.932274 -90.452026 8.108475 33366 30.395409 -89.854034 8.577827 33367 33.805984 -89.936234 8.815903 33368 34.924576 -90.031586 9.923721 33369 7.564873 -92.663162 8.129593 33370 10.994324 -90.444595 8.133009 33371 12.519516 -89.117722 9.287079 33372 34.374649 -91.833572 9.525757 33373 15.130157 -93.978943 8.416748 33374 15.552643 -93.671265 8.911346 33375 15.905167 -94.577881 8.780159 33376 20.936295 -94.587799 7.693107 33377 21.177902 -95.018112 8.415359 33378 8.331390 -93.806763 7.656814 33379 14.872169 -93.432419 9.712730 33380 21.599953 -95.329010 8.576645 33381 20.630165 -95.094437 7.951408 33382 22.031967 -96.083786 8.069618 33383 32.629807 -94.480347 8.726196 33384 20.198357 -96.701767 9.463486 33385 20.664230 -95.925735 8.664375 33386 11.219475 -98.621490 7.486816 33387 15.687706 -96.981155 8.787628 33388 22.160309 -96.961517 8.029922 33389 29.822678 -97.521088 7.592865 33390 12.071671 -98.653244 7.805969 33391 11.716225 -98.992722 7.408050 33392 11.591751 -98.528061 7.880676 33393 12.315231 -99.001785 7.447517 33394 12.864791 -99.090073 7.284561 33395 22.268448 -97.783966 8.050674 33396 22.436111 -98.918335 8.389359 33397 28.108246 -97.672897 8.512520 33398 27.546356 -98.309647 8.191864 33399 15.925186 -99.800308 8.015366 33400 20.439423 -100.035248 7.327545 33401 25.754486 -99.049927 9.635475 33402 16.689880 -100.640839 7.914199 33403 15.969368 -100.533905 8.773087 33404 16.718109 -100.849258 8.757050 33405 22.156281 -99.300430 9.154366 33406 22.880768 -99.676315 8.996552 33407 6.514450 64.650604 19.963570 33408 7.330841 64.722031 19.952721 33409 11.008888 62.391678 18.485504 33410 12.010574 62.200165 18.535118 33411 11.812576 62.939850 19.090317 33412 13.089386 62.497253 18.842178 33413 12.313309 63.339050 19.629562 33414 12.941223 63.272934 20.242172 33415 15.014832 62.856476 19.764694 33416 16.436424 62.389633 18.839218 33417 17.054398 62.470062 19.165398 33418 10.731522 63.192474 19.318985 33419 12.465340 61.364548 18.155724 33420 11.580795 61.570282 18.153465 33421 20.119774 61.689743 20.300339 33422 3.943199 60.423492 19.401512 33423 4.284088 58.585480 19.090721 33424 21.215591 60.123520 19.621231 33425 21.074074 57.693939 18.950249 33426 21.996994 58.885605 19.489037 33427 22.639954 59.741608 20.339462 33428 21.993164 61.055634 21.309410 33429 5.171028 57.850510 18.975723 33430 5.276825 57.204926 17.977043 33431 6.124245 57.131973 18.674171 33432 19.935043 56.880295 18.426956 33433 28.267441 55.973816 18.890755 33434 7.052391 55.718765 19.678741 33435 7.759918 55.377579 18.851151 33436 20.346107 56.150742 18.726692 33437 20.636459 56.779572 18.824585 33438 26.445976 56.107697 18.095490 33439 27.083794 55.758240 18.653397 33440 29.399155 55.850861 19.140770 33441 25.669083 55.494766 18.003265 33442 26.221375 55.266968 18.461830 33443 26.497963 55.126266 19.172173 33444 28.992622 55.605392 19.916840 33445 28.080795 55.424072 19.877541 33446 31.795580 54.119843 20.021683 33447 31.615252 53.953888 20.727486 33448 31.208450 54.698135 20.670219 33449 24.583481 54.615219 18.555733 33450 25.435722 54.829941 18.334679 33451 25.891273 54.826355 18.871727 33452 22.689636 54.328964 18.536545 33453 21.855049 54.342346 18.167435 33454 23.490799 54.565094 18.786407 33455 25.431290 54.634491 18.855049 33456 2.966698 49.370972 17.889572 33457 7.463791 53.683548 18.497429 33458 31.811258 52.942444 19.624023 33459 3.165344 50.266632 18.557899 33460 29.830238 50.839676 18.732147 33461 28.447235 50.497681 19.071503 33462 29.685478 51.365707 19.610138 33463 3.200043 51.152954 18.847046 33464 25.742485 49.157990 18.268150 33465 27.237274 49.393036 18.337448 33466 28.552856 49.557373 18.108994 33467 29.540924 50.119293 18.129425 33468 3.125572 48.260864 18.778023 33469 2.667656 47.171173 18.493843 33470 2.590538 48.143463 17.641266 33471 23.676361 49.018707 19.397827 33472 24.080811 49.692551 19.791046 33473 24.728851 49.548798 19.041374 33474 24.717621 48.916840 18.303902 33475 24.760315 48.423203 17.910286 33476 2.409500 45.852310 18.061821 33477 23.679436 48.326080 18.783920 33478 24.301704 46.662598 18.412758 33479 2.410072 45.276611 19.374916 33480 2.741112 44.352005 18.608696 33481 42.463165 44.547882 17.947990 33482 2.764008 44.721802 17.422768 33483 24.989319 45.392303 18.523254 33484 39.972679 43.881210 18.011551 33485 25.744949 43.610886 18.244675 33486 25.176468 44.543945 18.270432 33487 43.637573 43.884888 18.076630 33488 44.486755 43.395828 18.504982 33489 43.407135 43.389023 18.647530 33490 25.743225 42.840637 17.793571 33491 42.357178 43.538727 18.699738 33492 46.243652 42.462234 19.118835 33493 45.327148 42.951935 19.159271 33494 6.106194 41.846436 17.852631 33495 26.944031 41.105865 18.154709 33496 27.151840 41.852081 18.584724 33497 7.464920 41.149704 17.553398 33498 8.836700 40.633942 17.720398 33499 9.268021 39.978699 17.154411 33500 26.638321 40.947922 17.613426 33501 32.276321 40.862122 17.661491 33502 32.381607 41.394104 18.224983 33503 9.928337 40.191269 18.280777 33504 10.449448 39.850769 19.072121 33505 10.925804 39.345764 18.317894 33506 45.957184 39.866226 18.315247 33507 12.184448 37.773102 17.123398 33508 27.494263 40.410095 17.824547 33509 45.568985 39.442917 19.250412 33510 3.896935 37.552353 17.155685 33511 11.301910 38.768158 17.384178 33512 40.913956 37.472641 18.148773 33513 41.331421 37.762512 17.893684 33514 43.190125 37.583221 19.778816 33515 39.563721 36.501587 18.035156 33516 40.342667 37.168259 17.868103 33517 7.902648 35.654999 18.235893 33518 9.246826 35.072769 17.138832 33519 13.135704 35.161102 16.800003 33520 9.033585 34.846298 18.712875 33521 8.041801 35.149155 19.304115 33522 10.265549 34.559082 17.178474 33523 34.958885 33.068619 17.803940 33524 35.112587 32.365967 18.490265 33525 36.065346 33.170273 19.011345 33526 36.160934 34.413910 17.916306 33527 36.952637 35.402374 17.554413 33528 45.221802 34.347534 18.111305 33529 46.494873 34.778641 18.851494 33530 48.862289 35.386429 17.802010 33531 49.417358 34.753891 18.233826 33532 3.384743 34.391373 17.375488 33533 41.822327 32.340302 17.649376 33534 41.007751 31.864349 17.681618 33535 44.113586 33.333145 18.050896 33536 49.522858 33.854462 17.226028 33537 49.697845 34.189499 17.797928 33538 3.762955 32.935654 16.897964 33539 34.465485 33.140305 16.977509 33540 50.031830 33.390594 17.689125 33541 4.468178 31.891602 16.200012 33542 34.960800 31.850769 17.334953 33543 37.560074 30.820587 17.667229 33544 50.127945 33.862061 18.767677 33545 50.670990 33.241119 19.674866 33546 50.130737 33.947128 19.668045 33547 50.671921 32.899628 18.083260 33548 51.294052 32.154236 18.075890 33549 35.665207 30.778961 18.739220 33550 39.217583 31.208130 17.479530 33551 2.729705 21.523623 12.620243 33552 5.711655 28.024994 17.760986 33553 50.214142 27.473175 18.317535 33554 3.468375 24.330231 14.807524 33555 3.556699 23.055357 15.653685 33556 50.009613 26.610046 18.235039 33557 50.593048 25.852234 17.562454 33558 4.889023 25.814026 17.277985 33559 15.567961 26.612610 19.004171 33560 15.399435 26.580612 19.123953 33561 15.594671 26.707428 19.269232 33562 15.868093 26.713257 19.157080 33563 15.873022 26.549255 19.039358 33564 16.087332 26.608749 19.281393 33565 51.290497 25.453812 17.169418 33566 15.626852 26.460541 19.160978 33567 15.983198 26.456329 19.281149 33568 52.752411 24.988647 17.518959 33569 54.348953 24.679626 17.544281 33570 55.091095 24.228699 17.103355 33571 54.918655 24.566772 17.630035 33572 56.824127 22.616150 17.319756 33573 55.328033 24.299667 18.363052 33574 31.949907 19.457306 16.394768 33575 45.863144 20.101074 17.005157 33576 46.977997 20.270721 16.833931 33577 48.160477 20.121567 17.267426 33578 49.265167 19.802673 17.848633 33579 57.584579 20.841019 17.910774 33580 43.892700 19.637589 17.424217 33581 44.812439 19.650635 17.666794 33582 50.108994 19.544250 17.985573 33583 51.151825 19.332291 17.946121 33584 2.370741 14.025088 13.529612 33585 32.408691 18.613556 17.312180 33586 31.094910 18.773804 17.087364 33587 32.681931 19.143646 16.537659 33588 33.447021 18.788101 16.591072 33589 39.324341 18.207382 17.658546 33590 57.914978 19.290588 17.693832 33591 34.705643 18.277603 16.726288 33592 37.393829 17.337753 18.173157 33593 36.473686 16.853989 18.249580 33594 48.582520 17.477585 16.529709 33595 53.422668 18.528397 17.370789 33596 53.803192 17.628113 17.234329 33597 53.058945 17.387619 17.505615 33598 53.407990 16.690506 17.142120 33599 58.350388 17.770844 18.236343 33600 48.515823 17.934311 17.464310 33601 49.491730 17.886597 17.547874 33602 50.458557 17.923981 17.759964 33603 40.990372 15.601898 16.534775 33604 43.025208 16.664185 17.645325 33605 53.951599 15.819519 17.157715 33606 54.581482 17.322693 16.742409 33607 54.210663 16.703049 17.067604 33608 58.479828 16.835083 17.718216 33609 35.634972 14.958298 16.850853 33610 56.913605 15.085114 17.827477 33611 57.561584 14.963516 18.660728 33612 29.473587 12.406021 16.258629 33613 29.900879 12.634705 16.707954 33614 29.443695 13.165329 16.112267 33615 34.137070 13.907089 16.423973 33616 34.906700 14.375366 16.319298 33617 31.847780 13.559509 17.576279 33618 31.913179 12.373459 17.070564 33619 45.219482 12.831818 16.491798 33620 33.222977 14.378723 17.596710 33621 30.912262 11.881042 16.960701 33622 30.948395 10.438248 16.441116 33623 30.862808 11.005768 16.669075 33624 45.190765 11.146500 16.167328 33625 46.006378 10.798370 15.924515 33626 56.049591 10.177917 16.307289 33627 46.817169 10.902679 17.502243 33628 56.020691 9.216492 16.614967 33629 56.096802 10.015656 17.388046 33630 35.688950 7.686768 15.242790 33631 34.466972 7.541992 16.311378 33632 35.298553 6.752533 15.948692 33633 54.978973 8.331558 16.417557 33634 55.439606 8.831940 17.708069 33635 53.771576 7.725494 16.192238 33636 56.129623 9.497940 17.674973 33637 32.843018 9.020554 16.631889 33638 32.627106 9.777115 16.512772 33639 32.191910 8.764038 16.377563 33640 31.296349 8.898911 15.928650 33641 35.463242 5.850464 15.992599 33642 34.453224 6.222214 16.443581 33643 36.089256 5.769295 15.505844 33644 51.002350 6.783798 16.901192 33645 56.734009 5.240173 16.163673 33646 57.361465 5.766281 17.091248 33647 60.388428 6.096603 17.509857 33648 60.947906 4.669792 17.396400 33649 32.164627 4.927002 15.490761 33650 36.386345 4.946442 15.898605 33651 37.575798 4.031143 16.655289 33652 55.436630 4.593140 16.553802 33653 56.385696 5.313980 17.288475 33654 42.241333 4.247604 15.697449 33655 39.495262 1.701202 17.381798 33656 39.815872 0.134872 17.702446 33657 40.464401 0.332016 17.175453 33658 49.492249 3.145828 16.083672 33659 32.280533 4.107086 15.934853 33660 32.320328 2.978729 16.288544 33661 42.184464 1.014572 15.802788 33662 42.675156 0.749161 15.403389 33663 50.289291 2.305771 18.749710 33664 48.958466 2.543411 18.027428 33665 50.133743 2.468872 16.901291 33666 48.667389 3.254105 17.208138 33667 50.886902 2.340454 15.763359 33668 52.824097 2.767410 15.745163 33669 32.344406 2.036484 16.136833 33670 41.353592 0.947906 16.470009 33671 51.796127 2.496597 16.647720 33672 1.959381 3.104008 13.977777 33673 34.005005 0.049423 16.422363 33674 34.746567 -0.197189 15.795753 33675 34.759460 -1.126053 16.647812 33676 1.939677 1.140172 14.147266 33677 35.776527 -0.848465 15.393227 33678 42.389801 -0.354416 15.998077 33679 43.170029 -1.980698 14.955284 33680 61.927094 0.099136 16.674133 33681 62.040848 -0.874786 16.755447 33682 35.684547 -3.047440 15.103851 33683 42.626694 -1.930710 15.494194 33684 53.644379 -2.608475 15.725204 33685 52.857056 -2.927841 17.052704 33686 53.649109 -2.468765 17.549179 33687 53.650192 -2.471848 16.766731 33688 54.553482 -2.085907 16.663918 33689 60.376648 -3.471207 15.236717 33690 61.674118 -3.299042 16.334915 33691 61.035675 -4.008636 15.847458 33692 39.983704 -4.626160 15.275513 33693 40.510300 -3.368103 16.373344 33694 49.768845 -4.728836 16.408630 33695 49.716431 -4.655350 17.285332 33696 50.641571 -4.140472 17.141876 33697 51.927124 -3.573502 16.097046 33698 58.121338 -3.559113 16.018654 33699 58.906464 -4.586838 16.324356 33700 59.281281 -4.064987 15.562111 33701 60.027451 -4.224792 15.639687 33702 1.948599 0.164910 15.983795 33703 2.045217 -3.952521 14.391052 33704 2.100442 -4.721252 13.966675 33705 38.773407 -5.789078 15.249565 33706 38.730911 -4.890289 16.251724 33707 37.865189 -5.735138 16.028580 33708 47.125488 -5.811752 17.710045 33709 48.202484 -5.317596 18.111351 33710 48.151688 -5.403076 17.086815 33711 48.779953 -5.255814 15.904373 33712 50.699966 -4.269257 15.658875 33713 57.705048 -3.652573 16.489159 33714 57.298065 -4.320572 17.473679 33715 1.979551 -2.695701 14.915257 33716 37.121925 -5.372192 17.259537 33717 36.299675 -5.885971 17.504265 33718 36.848694 -6.568878 16.662201 33719 38.904373 -6.843750 15.036278 33720 45.889343 -6.604111 16.052841 33721 46.272858 -6.261063 16.811234 33722 2.049610 -4.558710 16.610161 33723 2.052774 -4.542255 15.684647 33724 2.025532 -3.917840 15.150269 33725 2.152475 -5.560077 14.741903 33726 37.959106 -7.251205 15.996857 33727 39.497200 -7.502365 15.493050 33728 38.135910 -6.510483 15.392548 33729 44.449615 -6.742599 16.385696 33730 37.819656 -7.989853 17.085953 33731 36.853874 -7.448273 16.933014 33732 40.373611 -7.445938 15.316856 33733 52.982056 -9.435013 15.251602 33734 52.718536 -8.557678 15.686188 33735 54.777161 -7.895325 16.022507 33736 53.993546 -7.653641 16.450615 33737 56.031830 -8.454193 15.310036 33738 53.066513 -7.935516 16.466202 33739 57.130600 -8.221878 16.343491 33740 55.764954 -7.868149 16.437386 33741 58.006653 -8.427994 15.788589 33742 58.581970 -8.689819 15.543518 33743 50.014191 -9.620148 15.921349 33744 48.914642 -9.958160 15.975975 33745 49.433014 -10.640839 15.581154 33746 51.731445 -9.479599 15.597641 33747 52.595657 -10.880005 15.423737 33748 50.904694 -10.250900 15.290367 33749 51.617676 -10.884735 15.348022 33750 2.313784 -7.082668 14.473328 33751 32.639961 -10.709595 16.474213 33752 32.091072 -10.199799 16.762688 33753 32.281616 -9.889618 15.693420 33754 34.141556 -10.729202 14.844780 33755 50.217636 -10.568542 15.334518 33756 50.804047 -11.398117 15.445824 33757 60.954437 -11.485428 15.326782 33758 33.062241 -10.593674 15.412354 33759 36.647675 -11.286865 14.855652 33760 35.133347 -11.236328 15.428429 33761 38.986076 -13.340164 15.099350 33762 38.388695 -13.472244 15.797752 33763 37.691681 -12.379959 15.549072 33764 39.066681 -12.271927 14.602028 33765 50.757370 -12.332672 16.254524 33766 51.704666 -12.063522 16.242401 33767 54.564148 -12.175232 15.605927 33768 60.481628 -12.312317 15.298187 33769 62.210449 -9.206543 17.326874 33770 62.107925 -10.965485 16.184357 33771 55.719727 -12.476334 15.168106 33772 58.492645 -13.062454 15.071175 33773 59.687546 -12.885284 15.323387 33774 61.528107 -12.299500 15.751587 33775 62.495575 -12.408844 16.200493 33776 39.631447 -13.085388 14.260124 33777 54.716370 -13.284134 16.073227 33778 56.247375 -13.569305 15.289047 33779 57.458786 -13.273453 15.008705 33780 59.310791 -13.858185 15.719292 33781 57.667038 -14.465881 15.522453 33782 60.686981 -13.325729 15.904335 33783 39.023407 -14.065399 14.697510 33784 39.339043 -13.716141 14.351799 33785 58.898788 -15.014328 16.508904 33786 3.584321 -14.633095 13.515869 33787 3.052588 -12.509239 14.563906 33788 3.278655 -13.822093 14.612476 33789 2.731416 -10.543948 14.596794 33790 37.343918 -15.188217 15.516273 33791 3.520487 -14.885423 14.294165 33792 32.676315 -20.112946 13.925400 33793 4.281014 -17.835659 13.867691 33794 40.385513 -19.284622 14.204285 33795 44.880585 -19.007767 14.148705 33796 44.510284 -19.279129 14.311256 33797 45.918152 -18.879257 13.855919 33798 46.871155 -18.297012 13.672981 33799 5.155479 -20.173323 12.982330 33800 33.461105 -18.841217 14.664734 33801 38.359016 -20.290985 14.300308 33802 39.687553 -20.021561 14.547920 33803 41.657822 -19.671783 14.483765 33804 4.330711 -18.605234 14.711260 33805 4.821751 -20.040691 14.277458 33806 38.731369 -22.007858 15.692406 33807 37.303955 -21.123016 14.755188 33808 60.859406 -23.732712 14.085121 33809 44.314056 -21.154587 14.010109 33810 43.364853 -22.378479 13.839226 33811 5.577760 -20.932384 12.284582 33812 36.261871 -21.788803 14.578140 33813 5.862313 -21.670202 12.210039 33814 6.064632 -22.432360 12.507406 33815 53.175003 -25.934769 14.941673 33816 54.486145 -26.215347 14.930161 33817 57.748535 -24.003693 14.235031 33818 56.596817 -24.008301 14.003983 33819 6.469035 -23.564812 12.588036 33820 48.613342 -26.197922 14.217728 33821 51.872696 -25.506027 14.616699 33822 56.950882 -24.660049 14.805237 33823 59.841690 -24.205780 14.727104 33824 60.608124 -24.289581 14.581322 33825 61.053650 -24.850342 14.636871 33826 40.704712 -25.593033 13.994125 33827 46.903137 -26.893661 13.873169 33828 48.221130 -27.219696 14.657188 33829 46.210846 -28.167801 14.508324 33830 57.266708 -26.204544 15.069191 33831 60.191193 -26.598389 14.295891 33832 8.015030 -26.903618 12.305210 33833 8.638452 -27.901724 11.950899 33834 38.815872 -28.063965 14.205025 33835 41.351852 -24.501312 14.271202 33836 59.293152 -26.831223 14.730202 33837 9.324284 -28.608040 11.337595 33838 38.032410 -28.892075 13.825699 33839 37.410034 -29.569229 13.706589 33840 37.576157 -29.099380 14.750557 33841 9.664493 -29.490788 11.376818 33842 10.293655 -30.346989 10.987448 33843 36.797066 -29.815460 14.408791 33844 36.823944 -30.726852 13.793274 33845 42.197311 -30.488831 13.597336 33846 55.159637 -29.861298 14.641426 33847 55.684052 -28.733978 14.687820 33848 63.523438 -29.971069 15.241714 33849 64.212143 -30.615662 14.961456 33850 63.354248 -29.955902 13.998993 33851 64.033722 -30.633621 15.545624 33852 11.068666 -31.257706 10.480059 33853 10.618634 -31.431057 11.072216 33854 11.791943 -31.630030 9.819086 33855 40.008392 -31.415558 13.453545 33856 55.566605 -31.010330 13.885178 33857 61.992615 -30.208862 14.091660 33858 38.220642 -31.917328 13.529556 33859 39.052406 -31.563705 13.351440 33860 39.165939 -32.064713 13.715691 33861 37.217911 -31.755676 13.768715 33862 36.454948 -31.871490 14.591705 33863 56.340118 -31.933792 13.712250 33864 55.473297 -31.823227 14.564934 33865 57.047791 -32.168625 14.853668 33866 57.039093 -32.131226 13.541023 33867 57.007629 -32.276657 13.955322 33868 58.760666 -31.639923 13.962463 33869 58.861084 -31.362762 14.809944 33870 9.072658 -35.564762 13.386772 33871 8.503734 -34.985550 14.046167 33872 8.301272 -35.791660 14.319096 33873 8.334402 -34.152145 14.192806 33874 7.743792 -33.653454 14.880074 33875 7.754975 -34.732597 14.967270 33876 9.183738 -34.692867 13.227905 33877 9.972264 -34.886395 12.384319 33878 9.471259 -33.795902 12.847765 33879 9.075492 -36.303734 13.365408 33880 8.530876 -36.920738 13.997509 33881 9.400826 -37.084702 12.888659 33882 10.158055 -37.285515 11.976501 33883 10.426943 -34.341965 11.904694 33884 12.704969 -35.069698 9.850760 33885 10.743233 -33.853714 11.534657 33886 64.049393 -33.584564 14.776459 33887 63.954773 -34.690231 14.079575 33888 62.957489 -36.521408 14.423355 33889 62.710419 -35.306396 15.229591 33890 8.816470 -37.734394 13.543036 33891 8.034158 -37.821671 14.595716 33892 56.309204 -38.471283 12.941483 33893 57.010986 -38.454880 12.825523 33894 52.465164 -39.630219 13.129715 33895 53.266083 -40.459732 13.177399 33896 54.036041 -39.492981 13.279839 33897 53.629929 -38.780289 13.114006 33898 54.282623 -38.276077 12.918365 33899 55.510834 -38.418869 13.065605 33900 54.716614 -38.661301 13.199692 33901 49.602051 -41.522568 13.661369 33902 50.384552 -41.190353 13.385277 33903 49.680389 -40.695724 13.216690 33904 52.681335 -39.022095 12.808807 33905 63.663788 -38.382111 13.367798 33906 9.029663 -39.954468 13.109344 33907 48.440781 -40.843430 12.972137 33908 48.957718 -40.628036 12.909798 33909 50.902069 -40.342178 12.984879 33910 54.399475 -40.310501 12.969376 33911 63.137177 -40.807724 14.361610 33912 43.191437 -41.520584 12.749649 33913 46.506653 -41.869324 13.360220 33914 47.811371 -41.264740 12.940674 33915 49.792542 -44.530380 13.068321 33916 50.460907 -44.445496 12.641579 33917 49.836777 -43.573547 13.190727 33918 52.486526 -41.457550 12.953964 33919 63.477570 -41.028427 13.360764 33920 4.276985 -42.946594 13.583473 33921 42.050629 -43.066757 12.565933 33922 51.541794 -42.393250 12.836601 33923 63.142151 -42.077240 13.281990 33924 63.355240 -41.376785 13.435860 33925 50.814163 -43.364212 12.720764 33926 50.364166 -42.276993 13.311745 33927 51.310883 -41.350555 13.216499 33928 49.342819 -44.457947 13.629829 33929 12.800323 -46.743469 11.393761 33930 13.568268 -46.893433 11.896500 33931 15.172333 -47.859238 12.878670 33932 15.896614 -47.304993 12.523438 33933 60.771133 -46.171844 13.839600 33934 61.476990 -45.752716 14.139191 33935 4.496910 -45.327927 13.628304 33936 5.016647 -45.983826 13.409775 33937 5.850090 -46.504044 12.578201 33938 44.128311 -46.646179 12.764168 33939 50.476379 -45.696381 13.092110 33940 62.084076 -44.685913 14.353851 33941 61.225952 -46.047760 14.422188 33942 13.100113 -47.664871 11.640450 33943 16.076889 -46.894913 11.783699 33944 16.797348 -47.249741 12.026016 33945 49.559189 -45.919922 14.646767 33946 57.499283 -46.413589 12.808815 33947 59.721588 -46.246826 14.179741 33948 7.926551 -48.561325 12.901802 33949 7.081757 -48.005768 13.510986 33950 7.438858 -48.565506 13.652771 33951 13.500366 -48.690491 11.766800 33952 13.841888 -47.674927 12.265045 33953 17.757202 -49.600739 11.988953 33954 53.378601 -47.971939 13.338715 33955 52.138351 -47.516602 14.154747 33956 53.328094 -47.955215 14.613670 33957 54.859222 -47.388351 12.887886 33958 55.736252 -46.871460 13.573746 33959 56.116913 -47.104385 13.007133 33960 54.080475 -47.971664 13.032333 33961 8.497833 -48.769302 11.971893 33962 14.995819 -49.058853 12.749329 33963 14.552383 -48.329422 12.907677 33964 14.125259 -48.587280 12.523827 33965 46.860962 -49.481369 14.288300 33966 46.583954 -48.857620 13.522926 33967 47.675629 -49.411087 12.983658 33968 48.722778 -50.155823 13.645287 33969 47.840134 -50.048660 14.305511 33970 18.099915 -50.394638 11.592445 33971 49.256744 -50.664276 14.073601 33972 48.703979 -50.608887 14.394478 33973 10.075668 -51.232697 11.792198 33974 51.221436 -51.403152 12.318710 33975 59.274765 -51.698395 12.152061 33976 10.602333 -52.145828 11.443977 33977 10.640640 -51.712982 12.800240 33978 10.310577 -50.260864 13.261070 33979 11.204819 -51.039841 14.177597 33980 41.092834 -52.144180 13.003716 33981 41.285187 -52.214249 12.348259 33982 40.556274 -52.534103 12.163467 33983 41.475204 -52.640503 11.888817 33984 42.083405 -52.314713 12.471283 33985 42.491623 -53.406265 11.779160 33986 42.851410 -52.078674 13.822174 33987 42.975037 -52.626999 12.482277 33988 51.528412 -52.823395 14.159866 33989 50.417770 -52.474579 14.366722 33990 52.146942 -51.846008 12.811615 33991 52.426147 -52.431870 13.591095 33992 11.453720 -52.897552 11.390747 33993 11.053833 -52.902817 12.515244 33994 11.518447 -53.423264 11.949760 33995 12.146645 -53.412857 11.690712 33996 39.755783 -52.374420 13.002769 33997 58.128586 -53.582108 12.872887 33998 60.193817 -52.253006 12.210152 33999 60.178619 -53.346115 11.988525 34000 13.212524 -53.063141 11.654129 34001 16.670944 -54.544189 11.658966 34002 45.021896 -54.091705 12.361687 34003 44.603912 -54.263016 12.087524 34004 44.124359 -53.336578 12.527870 34005 28.184875 -55.395157 10.748718 34006 37.441376 -54.227356 12.708679 34007 37.898209 -54.950699 12.050934 34008 37.217896 -54.947327 12.964012 34009 38.072510 -53.953979 12.174553 34010 9.331284 -57.574036 12.147614 34011 9.446014 -57.127365 11.574997 34012 27.687988 -57.090775 11.015129 34013 28.002975 -58.147781 11.323860 34014 37.471848 -55.956223 12.889946 34015 10.766328 -56.878571 10.570030 34016 28.540810 -58.131607 10.720856 34017 45.186905 -55.027496 12.150986 34018 45.204498 -55.899521 11.890518 34019 45.281708 -56.335953 11.505867 34020 45.854767 -56.032883 11.822937 34021 48.037506 -55.168839 12.783417 34022 49.414581 -55.272461 12.925934 34023 57.166779 -56.350571 12.420067 34024 46.663574 -55.239487 12.367393 34025 50.971008 -53.679642 14.166000 34026 51.916626 -53.979660 14.124199 34027 52.728821 -56.044250 12.980721 34028 53.417831 -55.424316 13.443954 34029 54.256729 -55.791916 13.127769 34030 54.474533 -56.669693 12.308090 34031 56.345703 -55.827286 12.904686 34032 16.211563 -58.096497 12.655785 34033 16.959213 -57.907486 13.343468 34034 18.410019 -57.992203 12.442986 34035 19.217178 -59.419983 10.901367 34036 19.592506 -58.799423 11.732147 34037 20.053360 -59.545547 11.292648 34038 19.604248 -58.184113 12.112267 34039 20.651932 -60.915665 11.631760 34040 20.490814 -60.219147 11.282997 34041 20.624878 -59.534973 12.314369 34042 27.097916 -59.455048 11.412918 34043 28.084076 -59.155121 11.183350 34044 40.775879 -59.143021 11.834824 34045 55.259842 -55.521408 13.024658 34046 6.712326 -59.846802 10.777985 34047 5.524613 -60.803864 11.236870 34048 7.982963 -60.142532 10.088989 34049 7.202156 -59.109299 11.145912 34050 41.360748 -59.439468 11.772337 34051 42.020691 -59.746750 11.607956 34052 20.343643 -61.136810 10.963493 34053 20.669975 -61.127350 12.321884 34054 43.171936 -60.454926 13.331291 34055 4.545136 -62.531067 11.080338 34056 20.156754 -62.478683 11.687233 34057 53.818115 -61.116623 12.670090 34058 52.800095 -61.002502 12.859985 34059 51.732117 -60.997772 12.959778 34060 54.516266 -61.619858 12.229240 34061 11.529633 -63.524887 10.620110 34062 11.967262 -61.911240 11.380966 34063 10.989204 -62.543884 11.629677 34064 45.532898 -62.027618 11.231094 34065 48.217209 -61.265167 13.042000 34066 54.583237 -61.209793 13.009476 34067 4.346504 -64.144608 10.731903 34068 27.348190 -64.055481 11.588989 34069 28.128677 -63.922638 10.995888 34070 55.064087 -64.435104 11.622231 34071 55.475189 -63.568710 11.890190 34072 10.183533 -64.171753 11.462090 34073 10.837646 -63.999359 10.881470 34074 21.672699 -65.071106 10.067993 34075 27.440910 -63.014786 11.455597 34076 28.397797 -64.559006 10.269768 34077 3.637047 -66.055008 10.732437 34078 5.713852 -65.794250 9.598061 34079 19.955589 -64.593567 11.948242 34080 3.954041 -65.109741 10.774910 34081 10.689270 -68.108429 10.413757 34082 9.981842 -66.516556 11.169418 34083 15.053436 -67.549255 11.043228 34084 15.568649 -67.038300 10.794510 34085 15.395935 -66.340424 11.250214 34086 16.318443 -67.197952 10.781090 34087 17.008507 -65.624069 12.029694 34088 19.225479 -66.606171 11.164505 34089 18.209793 -66.568695 11.185120 34090 19.960114 -66.347565 11.298485 34091 19.646835 -66.101654 11.853851 34092 25.410873 -68.116394 10.393501 34093 16.353043 -68.623688 10.527031 34094 8.444213 -69.168732 10.573242 34095 15.480423 -68.900940 10.988441 34096 27.361923 -66.594055 11.093298 34097 26.602684 -66.978424 11.005318 34098 25.990959 -67.858475 10.795471 34099 37.262665 -69.696075 11.696648 34100 51.207825 -68.740173 11.351982 34101 50.871307 -68.784698 11.572456 34102 51.312683 -68.207047 11.756111 34103 3.209198 -68.380280 10.803947 34104 3.242188 -69.031464 10.233765 34105 15.510239 -69.894104 11.759583 34106 16.294510 -69.564865 10.834137 34107 16.560600 -70.300018 11.221336 34108 38.600616 -68.893616 11.281258 34109 51.137344 -69.754059 11.198730 34110 5.361809 -69.471832 11.029089 34111 6.023262 -70.219559 10.061302 34112 6.859871 -69.803848 10.298500 34113 22.973953 -72.002289 10.221771 34114 24.086868 -70.812531 10.464363 34115 37.230179 -70.626358 11.187019 34116 40.570526 -69.450928 11.883484 34117 50.702515 -71.085144 11.498642 34118 17.056763 -71.300964 11.356728 34119 24.989166 -70.524155 10.377777 34120 42.215515 -70.810654 12.094498 34121 42.723526 -71.137085 12.297531 34122 42.881882 -71.454605 11.823875 34123 43.865128 -72.044540 11.051346 34124 50.613281 -72.207138 11.078896 34125 11.915298 -73.911362 10.679428 34126 11.315308 -74.949997 11.117523 34127 12.231705 -74.840988 10.446136 34128 14.516075 -73.245239 10.609077 34129 15.617874 -73.050674 10.976242 34130 22.022339 -73.308121 10.322418 34131 22.709328 -73.202408 10.442513 34132 39.215263 -73.649460 10.945724 34133 38.043480 -72.563812 12.355431 34134 37.694031 -71.667450 12.930740 34135 37.673904 -71.602936 11.561813 34136 45.219482 -72.977966 11.109520 34137 4.495796 -75.307556 10.968544 34138 4.509476 -76.458008 10.310051 34139 5.524063 -74.730103 10.419724 34140 6.235748 -75.183380 9.940231 34141 6.297371 -74.595688 10.460655 34142 6.671036 -74.491928 10.856033 34143 6.394936 -73.545425 11.527924 34144 12.569344 -72.965515 11.479660 34145 21.556168 -74.230881 10.272423 34146 47.716507 -73.068039 11.905869 34147 48.712982 -72.278198 12.482681 34148 49.224304 -73.000778 11.786179 34149 48.481384 -73.725250 10.814240 34150 48.476562 -74.129669 10.248749 34151 4.930328 -72.128998 13.481934 34152 4.269341 -72.240768 14.349167 34153 4.292816 -73.492218 13.748306 34154 6.903153 -75.221924 10.428879 34155 7.421135 -76.270996 10.136864 34156 18.948532 -75.850693 10.146523 34157 19.905273 -75.502533 10.121849 34158 8.525955 -77.380859 10.697723 34159 12.806534 -75.826736 10.754356 34160 11.558197 -75.908112 12.072517 34161 14.069351 -75.791870 9.810120 34162 10.878983 -73.785492 11.166885 34163 10.225952 -73.679382 11.420174 34164 9.895142 -74.585648 11.949646 34165 14.603942 -76.431854 10.441071 34166 13.251907 -76.506119 11.849442 34167 42.690308 -77.236938 10.059212 34168 4.312378 -76.402740 10.889267 34169 4.674477 -77.444366 10.910103 34170 15.724625 -76.722260 11.611786 34171 19.529770 -76.967300 10.966599 34172 40.005554 -78.541336 10.781807 34173 40.186661 -79.645828 10.843132 34174 39.386078 -79.424988 11.305313 34175 43.161469 -78.486008 9.613731 34176 10.113251 -79.740143 10.290329 34177 10.507080 -78.816589 11.943192 34178 9.658142 -77.939026 11.701370 34179 19.215469 -79.317505 10.886543 34180 19.003754 -80.183563 9.791748 34181 39.146523 -78.171112 11.443237 34182 40.844864 -77.500290 10.690590 34183 42.009491 -78.169159 10.241203 34184 41.204590 -79.127686 10.377296 34185 41.800110 -77.366806 10.535034 34186 42.434143 -79.264420 9.829597 34187 41.005920 -80.461517 10.568121 34188 42.216492 -80.374008 9.832243 34189 5.222405 -79.389877 11.408798 34190 5.390144 -81.134933 10.509171 34191 15.442230 -80.705887 10.577377 34192 32.501801 -82.083542 9.976860 34193 41.776978 -81.363724 9.989517 34194 42.386353 -81.220566 9.636917 34195 40.473450 -82.623337 11.561897 34196 40.905319 -81.582458 10.699577 34197 39.855988 -80.922287 11.436676 34198 5.750786 -82.510254 9.994644 34199 12.574104 -84.694977 10.172401 34200 12.647278 -83.510742 11.466492 34201 12.107910 -82.892197 10.760406 34202 7.291123 -84.710312 9.550728 34203 6.842041 -84.181274 9.526352 34204 7.724517 -85.212830 9.474876 34205 32.910713 -84.320404 10.356483 34206 33.087532 -84.269012 11.902779 34207 32.643364 -83.360245 11.256935 34208 32.473572 -83.125565 10.153793 34209 7.595032 -85.555313 9.336548 34210 7.963409 -85.415436 9.684021 34211 12.245316 -86.359131 9.545952 34212 33.317276 -85.059937 10.070877 34213 38.144318 -85.579605 11.072586 34214 6.970085 -86.228134 9.502426 34215 7.672531 -85.728653 9.878151 34216 11.699638 -87.341202 9.028305 34217 33.621170 -85.473206 10.956833 34218 35.135452 -87.992172 10.321442 34219 11.919250 -88.575562 9.275375 34220 12.368179 -87.464539 9.624855 34221 11.283363 -89.579773 8.730408 34222 35.328140 -88.329773 9.924294 34223 6.359764 -89.026047 10.104843 34224 6.511856 -90.111084 8.970032 34225 6.376785 -89.754868 8.109055 34226 7.316658 -92.111603 9.130432 34227 11.452728 -90.622269 8.393768 34228 34.552292 -91.495102 10.423508 34229 15.507217 -93.136581 9.679472 34230 15.768036 -93.622131 9.942467 34231 13.705887 -95.679367 9.349228 34232 34.063766 -91.984161 10.357285 34233 33.057716 -92.890396 10.563789 34234 33.386093 -92.175797 11.043365 34235 8.326500 -93.822433 8.793945 34236 9.226212 -95.235138 9.539337 34237 9.707321 -96.172714 8.525101 34238 21.235519 -95.425644 8.887833 34239 26.930237 -94.654388 9.644333 34240 26.986969 -95.050552 9.478165 34241 26.407539 -94.924469 9.895638 34242 27.419983 -94.860931 9.939575 34243 13.785446 -96.779526 8.197067 34244 15.913994 -95.880463 8.825851 34245 19.809143 -97.265778 9.531219 34246 21.739792 -96.893417 8.711143 34247 27.243210 -95.810669 9.440964 34248 26.767960 -96.405945 9.550491 34249 26.079353 -96.352600 10.938736 34250 13.029007 -96.757156 8.940636 34251 12.971809 -95.774307 10.153366 34252 27.388046 -96.898453 9.089798 34253 30.779968 -95.473083 9.979340 34254 11.407654 -97.380005 8.877518 34255 11.226554 -97.977509 8.082382 34256 12.041931 -96.551636 9.876312 34257 11.137849 -97.059326 9.453781 34258 11.152069 -96.698242 10.051804 34259 12.163261 -97.828293 8.405457 34260 15.485992 -98.886841 8.705917 34261 21.739517 -97.956039 8.926155 34262 26.910896 -97.777985 9.051735 34263 28.300171 -96.557999 9.384369 34264 29.546478 -97.144989 8.513557 34265 21.880646 -98.758881 8.995552 34266 15.434455 -99.726486 9.384689 34267 19.530952 -99.848312 8.377754 34268 19.415070 -98.760742 9.494957 34269 26.229523 -98.223740 9.817673 34270 18.485855 -99.916275 9.599808 34271 23.910507 -99.804550 9.466377 34272 17.194321 -100.600555 9.630508 34273 7.959213 64.517242 20.074097 34274 9.079650 63.997437 19.721207 34275 8.707092 64.439041 20.964760 34276 10.293823 63.862244 20.727890 34277 12.176910 63.640854 20.141487 34278 11.852951 63.657806 20.740746 34279 4.143440 62.586731 21.943848 34280 5.068276 63.763611 22.046974 34281 4.502701 63.292480 22.597946 34282 9.986375 63.513641 19.505035 34283 11.521179 63.502792 19.935661 34284 14.134224 62.844742 20.276199 34285 16.129120 62.579819 19.857353 34286 15.041786 62.464447 20.406349 34287 15.632233 62.082275 20.893387 34288 16.807350 62.600708 20.911774 34289 18.669785 62.539215 20.072861 34290 17.486694 62.721802 19.988091 34291 3.930786 60.612732 21.561607 34292 23.234268 58.522934 20.105125 34293 23.643211 59.300110 20.695152 34294 5.917564 57.671432 19.510178 34295 22.540100 57.873825 19.577217 34296 5.478462 58.034958 19.746109 34297 6.127525 56.240875 20.503166 34298 6.282852 55.404175 20.135071 34299 21.426605 56.124863 19.091614 34300 22.353516 57.006393 19.473534 34301 23.738510 56.959259 20.015976 34302 6.455414 56.926620 19.831482 34303 22.716774 56.132889 19.615486 34304 7.988311 54.434265 18.530884 34305 30.006378 55.548737 19.749802 34306 5.752342 54.074066 19.134682 34307 3.319100 53.643951 19.779373 34308 5.696068 54.757904 19.722092 34309 6.592232 54.145447 19.221825 34310 6.702286 54.863373 19.718910 34311 21.246475 54.898987 18.633644 34312 22.449776 55.053543 19.111046 34313 25.742065 55.211044 19.752678 34314 24.417191 55.435013 19.613243 34315 23.417206 55.543198 19.575447 34316 27.343536 55.322479 19.515411 34317 7.389496 54.626236 19.231171 34318 3.079239 52.191925 18.949600 34319 30.159958 52.251404 20.619934 34320 28.762177 51.752106 20.611496 34321 26.832420 50.508011 19.730659 34322 30.456207 51.844330 19.865471 34323 24.711990 50.072769 20.130562 34324 25.775360 49.920258 19.281853 34325 3.628876 49.392105 18.992577 34326 3.414780 47.183304 19.781929 34327 23.426414 48.232849 19.410797 34328 24.848717 46.540222 19.428970 34329 2.855866 44.262085 20.771584 34330 2.608749 44.500671 19.874496 34331 2.779160 45.338943 20.618980 34332 24.147392 47.173737 20.376633 34333 23.186279 47.684875 20.535629 34334 23.066933 48.456940 20.085449 34335 25.660019 44.533569 18.687195 34336 26.033508 45.252563 19.259010 34337 29.246307 43.946594 19.267303 34338 29.705338 44.062653 19.193176 34339 29.261223 44.983002 19.504486 34340 29.546501 46.589188 20.140266 34341 30.372574 45.103668 19.385315 34342 32.187134 44.832169 19.296745 34343 33.125595 45.910431 19.627281 34344 31.572800 46.710892 19.911560 34345 33.112709 44.751404 19.184341 34346 32.899124 43.828186 19.025291 34347 34.011810 44.545807 19.303757 34348 41.355835 44.053619 18.430756 34349 3.850784 43.200439 18.440063 34350 26.616356 43.862366 18.963348 34351 27.998756 44.618698 19.495605 34352 29.942032 42.794540 19.115891 34353 31.182526 44.177963 19.155594 34354 31.330368 45.128967 19.290604 34355 34.985138 43.568848 19.087654 34356 35.445465 44.626526 20.640114 34357 40.773819 42.921570 19.195778 34358 25.979111 42.765656 18.163628 34359 26.549042 42.772034 18.525368 34360 31.772043 43.634827 19.183159 34361 32.402252 42.039459 18.798470 34362 35.917358 42.963120 18.950920 34363 35.587646 43.537903 19.589020 34364 39.218369 42.751678 18.848167 34365 43.792206 43.123306 19.195480 34366 42.823700 43.069366 19.062553 34367 42.968292 42.878784 19.615211 34368 45.191559 42.592148 21.189163 34369 44.120972 42.968842 20.374924 34370 45.909637 41.971985 20.002022 34371 5.035996 42.519287 18.228996 34372 5.770317 42.119354 18.998085 34373 6.946320 41.473633 19.362144 34374 7.948364 41.517303 18.556686 34375 8.147888 41.412720 19.151512 34376 8.578697 41.247223 18.244164 34377 8.479141 41.504272 18.658737 34378 8.850250 41.170074 18.930977 34379 27.719101 42.864487 19.031479 34380 32.084946 42.740341 19.019806 34381 36.145142 42.886276 20.040047 34382 36.963219 42.124496 20.018997 34383 36.933212 42.215118 20.808701 34384 36.917953 42.402344 19.291779 34385 37.986206 42.123734 19.827751 34386 42.000549 42.858856 19.618217 34387 41.066116 42.614044 20.184128 34388 40.472366 42.397903 20.147026 34389 39.568573 42.286316 20.059799 34390 46.293091 40.528610 19.176353 34391 46.151398 40.137299 20.799789 34392 9.275299 40.871506 18.461548 34393 27.636551 41.081177 18.481110 34394 45.913406 41.681870 21.263382 34395 28.154541 41.816528 18.887726 34396 28.689674 40.910950 18.515495 34397 30.424042 40.950836 18.542458 34398 31.444366 41.694397 18.758682 34399 11.571724 38.715973 18.189804 34400 13.212341 36.743317 18.136909 34401 29.658905 41.069305 18.686295 34402 45.338486 38.644867 20.704552 34403 4.047081 37.111328 17.895554 34404 4.304421 37.532837 17.475342 34405 5.856514 36.707916 17.912041 34406 4.757958 36.588913 18.708740 34407 41.903900 37.446991 18.866707 34408 44.155792 37.375763 20.973122 34409 6.236282 36.089783 19.013885 34410 40.374512 35.786636 19.535774 34411 40.866760 36.775208 18.966972 34412 7.246178 35.608521 19.340721 34413 13.363754 35.380096 18.443649 34414 13.091049 33.844666 18.904594 34415 38.419846 35.221008 18.754150 34416 48.682053 35.058289 18.983711 34417 49.506653 34.473129 19.174614 34418 47.989822 35.247818 19.414772 34419 10.194336 34.354416 18.070793 34420 10.965637 33.988525 18.050949 34421 10.918800 33.722107 18.725632 34422 12.523635 33.443085 18.474472 34423 35.411957 32.163040 19.146065 34424 3.347633 33.251389 18.633438 34425 45.531845 33.181580 19.289841 34426 44.549622 31.970001 19.019623 34427 49.858536 34.195435 19.559235 34428 3.909950 31.803467 17.686218 34429 34.860214 32.065048 17.829124 34430 41.882034 30.801117 18.504005 34431 40.558533 31.024857 17.984764 34432 43.194672 31.693008 18.516266 34433 51.081543 32.727722 18.884903 34434 35.145363 31.610641 18.483086 34435 36.517685 30.088226 18.582809 34436 38.862885 29.933594 18.353722 34437 39.938354 30.245880 18.225662 34438 51.772491 31.478760 18.962303 34439 51.308258 32.418549 19.561577 34440 52.648117 30.306229 17.830330 34441 35.325104 31.473007 19.154427 34442 37.455856 29.535614 19.050575 34443 52.348297 30.405487 18.350899 34444 51.821213 29.755280 19.293907 34445 2.984822 22.451731 13.478148 34446 5.726753 26.937317 17.503044 34447 51.067352 28.859711 19.587730 34448 51.080292 29.517654 20.390274 34449 2.937712 21.785400 13.590948 34450 49.615143 27.803131 19.824097 34451 49.003418 26.882233 19.755920 34452 50.522186 28.144821 19.099442 34453 3.217555 21.636610 14.884758 34454 3.060921 21.794230 14.161478 34455 5.417679 26.279404 17.387939 34456 49.447601 26.120712 19.033371 34457 3.525416 21.856092 15.994936 34458 3.775119 23.900997 16.247419 34459 4.006995 24.483812 16.921789 34460 4.240578 25.467514 17.204155 34461 15.551970 26.555527 19.363791 34462 15.774397 26.622696 19.604834 34463 15.958136 26.707550 19.532125 34464 16.094992 26.560699 19.575468 34465 50.710022 25.514893 18.463219 34466 49.602966 25.480789 19.584541 34467 3.867000 23.532846 16.658236 34468 15.868994 26.477921 19.541418 34469 53.915451 25.051208 18.357597 34470 2.824443 20.533230 13.604416 34471 56.900040 22.348709 18.359756 34472 57.437225 20.843781 18.954224 34473 42.802979 19.241943 17.536507 34474 46.781891 19.846832 17.960945 34475 45.627380 19.322754 18.244507 34476 47.665421 19.625809 18.487320 34477 48.549210 19.694199 18.360947 34478 2.792044 16.154446 15.352453 34479 2.445892 14.343716 14.052103 34480 30.224892 17.785828 16.873589 34481 30.907906 17.706177 17.839569 34482 31.638979 18.157166 17.953125 34483 40.225052 18.548508 17.478615 34484 41.368591 18.747253 17.690865 34485 52.832275 19.022034 17.482002 34486 2.578946 14.903505 14.674406 34487 2.356529 13.334401 13.633118 34488 33.555817 17.949402 17.584045 34489 40.395416 17.927597 18.158646 34490 39.384003 17.374084 18.340874 34491 38.241516 17.831512 17.892059 34492 47.233765 17.880890 17.567337 34493 51.443085 17.489716 17.484093 34494 49.475235 18.365555 18.230934 34495 48.514130 18.659973 18.562492 34496 51.416718 18.027008 18.121910 34497 51.085480 18.411850 18.434990 34498 30.444839 16.680267 17.442322 34499 44.857574 17.572311 18.135895 34500 47.702118 18.328293 18.286804 34501 52.309601 17.946518 17.883553 34502 53.176361 17.990250 17.758682 34503 58.367249 16.823380 19.004921 34504 58.184097 15.730301 18.590988 34505 58.013702 15.565094 19.557198 34506 58.697418 17.110931 18.026360 34507 58.764282 16.818008 18.003876 34508 42.250061 16.246262 17.522751 34509 41.599396 16.047989 17.508301 34510 57.997375 17.079346 20.518921 34511 58.514816 16.437012 18.145264 34512 34.567917 14.813049 17.278290 34513 36.606819 15.529877 17.728897 34514 38.151733 15.720825 17.558838 34515 37.240654 16.340927 18.286591 34516 35.496399 15.820297 18.072723 34517 40.899872 15.846893 17.551994 34518 32.678833 11.233963 16.570862 34519 47.469696 13.733337 17.739098 34520 54.128067 14.350357 19.867622 34521 54.360886 15.033463 17.889214 34522 55.230377 14.670258 18.320946 34523 56.036621 15.089050 17.669098 34524 30.816635 13.475250 17.570435 34525 31.044083 14.271606 17.837975 34526 31.672609 10.798096 16.652809 34527 31.806826 11.608398 16.829849 34528 45.835587 13.135956 17.204758 34529 45.096771 12.338165 17.074783 34530 30.432220 12.943420 17.242615 34531 45.275192 11.457977 17.057007 34532 45.809616 12.204529 18.129196 34533 31.591751 9.728683 16.354607 34534 45.597229 10.935715 16.799606 34535 48.768570 10.866272 17.091965 34536 55.727890 10.320221 18.243622 34537 54.973450 10.679291 18.442261 34538 32.976929 8.500732 16.745361 34539 32.752953 7.754837 16.576057 34540 33.528519 7.894806 16.744141 34541 33.529449 6.942245 16.680489 34542 33.554512 8.824112 16.514328 34543 54.354767 8.324509 18.492165 34544 55.236313 9.099609 19.160538 34545 33.025986 5.554855 16.460922 34546 32.595352 6.772537 16.309929 34547 34.548805 4.922745 16.759232 34548 51.941498 7.339111 18.201828 34549 50.449371 6.822693 18.863556 34550 53.178818 7.739014 18.066208 34551 48.259857 5.516731 17.801674 34552 49.373627 6.268799 17.524529 34553 58.775742 6.501785 18.289162 34554 40.522171 4.134933 16.337288 34555 40.707535 2.894806 16.523575 34556 41.419662 3.802567 16.088486 34557 42.145599 4.992043 15.684837 34558 39.321060 3.716080 16.647697 34559 35.579086 3.663910 17.298767 34560 33.965408 3.751945 17.428467 34561 33.995125 2.153641 17.843552 34562 54.453918 4.039482 16.956772 34563 39.147705 0.396805 18.116051 34564 53.315643 3.404739 17.166679 34565 54.392120 4.274765 18.075874 34566 60.647751 6.051041 18.416901 34567 48.222595 2.896301 17.917160 34568 51.337555 2.466187 17.856468 34569 52.433823 3.024643 18.039284 34570 33.544540 0.802948 17.182762 34571 33.137253 1.482300 17.004639 34572 32.768204 2.159561 16.821030 34573 61.224808 1.232819 17.451546 34574 61.268494 2.971474 17.086746 34575 34.258438 -0.285995 17.685463 34576 41.114960 -0.372177 16.939667 34577 41.755981 -0.664734 16.581390 34578 1.967466 2.734456 15.121952 34579 55.905090 -1.905579 16.727409 34580 55.640884 -2.597244 17.860664 34581 56.534485 -2.806274 17.293251 34582 35.360519 -2.207581 15.949692 34583 33.398766 -4.707184 15.835747 34584 33.755264 -4.146118 16.154610 34585 34.157814 -3.670135 16.232773 34586 34.760925 -3.182724 16.068771 34587 42.010757 -1.658127 16.223175 34588 41.161285 -1.865143 16.715820 34589 40.309265 -2.575714 17.215363 34590 39.529007 -3.763428 16.962143 34591 57.113403 -3.332855 16.936607 34592 61.987549 -1.536392 17.569588 34593 32.996727 -5.167297 15.975342 34594 51.874146 -3.418915 17.441505 34595 62.058868 -2.812958 17.902901 34596 60.738251 -4.990692 16.486725 34597 61.808838 -5.529068 17.577454 34598 61.794434 -4.246002 17.123375 34599 2.104715 -4.990793 14.306076 34600 32.770874 -5.646118 16.171318 34601 47.583145 -5.827789 16.360077 34602 49.040070 -5.012421 17.196045 34603 58.316711 -5.730530 17.797661 34604 60.888199 -5.701996 16.964378 34605 31.973680 -7.075302 16.185326 34606 32.343491 -6.448044 16.105736 34607 37.357246 -6.360397 16.153999 34608 37.707245 -6.531677 15.709709 34609 59.831009 -5.695755 16.979462 34610 60.839050 -6.301636 17.413414 34611 59.530487 -6.458511 17.722237 34612 31.772219 -7.851013 16.572235 34613 32.075165 -6.927994 16.710648 34614 42.077560 -6.868393 17.778618 34615 43.142609 -6.801529 17.428658 34616 41.229370 -7.024994 18.661903 34617 40.724701 -7.297867 17.095512 34618 54.790924 -7.417191 17.294388 34619 2.150542 -5.970760 15.677082 34620 31.844278 -8.708725 15.837570 34621 39.279572 -7.713684 16.750778 34622 40.329987 -7.556366 15.992477 34623 52.034790 -8.451874 16.309570 34624 51.974121 -8.185623 17.193222 34625 50.765030 -8.888153 16.860558 34626 52.980591 -7.731750 17.416351 34627 56.304764 -7.803391 17.292160 34628 58.391968 -8.557159 16.571594 34629 57.066299 -8.107452 17.258133 34630 2.114582 -5.821324 16.819942 34631 2.309305 -7.421366 15.043488 34632 2.200335 -6.954846 16.269875 34633 47.808044 -10.003067 16.666870 34634 48.167206 -10.955124 15.881409 34635 48.982635 -9.542694 16.352638 34636 33.368866 -10.979202 16.106049 34637 47.047974 -11.073441 15.918602 34638 47.299225 -10.528473 16.156830 34639 63.094894 -10.647537 17.325485 34640 34.834541 -12.138824 17.406952 34641 34.573135 -11.621521 16.520401 34642 35.957855 -11.981186 16.194008 34643 49.273407 -11.949890 15.924530 34644 49.978149 -11.336334 15.485687 34645 50.163025 -12.038971 15.844025 34646 48.281250 -12.315323 16.110909 34647 2.282662 -7.663956 15.587524 34648 2.392443 -8.260902 14.941902 34649 37.739624 -13.344101 16.374725 34650 36.919785 -12.663818 16.551071 34651 45.838211 -11.332428 16.041962 34652 46.266174 -11.642303 15.978508 34653 46.206070 -10.747086 16.435616 34654 47.260590 -12.034515 15.990585 34655 61.941101 -13.406479 16.413208 34656 63.027649 -11.951630 16.679588 34657 46.028961 -12.625031 16.430611 34658 50.012939 -12.733749 16.821075 34659 53.133911 -12.296844 16.440445 34660 57.899200 -15.905472 16.108505 34661 62.909805 -13.242447 16.889297 34662 63.605240 -12.196060 17.572769 34663 3.183537 -14.124679 15.980787 34664 3.511898 -15.312299 15.045624 34665 38.740173 -14.111618 15.372078 34666 60.038116 -14.239716 16.516922 34667 35.822510 -15.102402 18.064949 34668 34.531967 -14.566635 19.242424 34669 35.658058 -13.860367 18.405411 34670 38.355515 -14.582214 15.451904 34671 54.742203 -15.980316 15.723740 34672 55.946747 -15.256790 15.552322 34673 54.828278 -14.621384 15.942017 34674 55.940918 -16.990295 15.719048 34675 54.177887 -17.259995 15.819939 34676 36.194717 -16.244675 15.102211 34677 53.680969 -15.677582 16.390076 34678 52.325027 -15.987488 17.443840 34679 53.141876 -14.509796 17.575996 34680 57.036392 -16.037048 15.729355 34681 3.886286 -16.979576 14.944504 34682 34.378517 -17.684113 16.346985 34683 33.055717 -19.274887 16.064087 34684 54.157227 -18.608246 15.930580 34685 52.866684 -18.528793 16.292412 34686 53.764526 -20.109192 16.828598 34687 56.455048 -18.545029 16.219818 34688 55.274933 -18.396378 15.884369 34689 58.187210 -16.478973 17.037498 34690 57.328751 -17.359985 16.322517 34691 57.818741 -17.872894 17.208405 34692 54.747025 -19.436279 16.249741 34693 56.586594 -19.592087 16.585350 34694 57.260147 -19.081451 16.941444 34695 32.639503 -20.197937 15.015778 34696 37.171837 -22.072311 15.745216 34697 37.963806 -23.043137 16.584740 34698 40.803101 -20.412369 14.920647 34699 41.368713 -21.068695 15.214333 34700 40.823227 -21.264740 15.298645 34701 43.002945 -20.523376 14.496948 34702 32.108711 -21.069321 15.330284 34703 36.166458 -22.520325 15.742744 34704 36.825584 -22.948227 16.593620 34705 39.786797 -21.009415 15.156166 34706 5.468915 -21.266237 13.197813 34707 5.342224 -21.513876 13.965853 34708 41.785461 -20.744171 14.958176 34709 41.787506 -21.689636 15.038773 34710 41.696793 -23.245316 14.672928 34711 5.859615 -22.571695 13.374765 34712 39.514359 -26.171310 15.438499 34713 38.754791 -24.248398 16.587257 34714 40.036865 -23.812378 15.538918 34715 33.770462 -24.816269 15.834061 34716 6.877766 -24.791203 12.798552 34717 30.904892 -23.166443 15.737602 34718 30.388016 -24.369019 15.739235 34719 31.067848 -26.078033 15.797485 34720 30.305588 -25.454315 15.720863 34721 33.332344 -25.235168 14.770576 34722 56.942200 -25.240967 15.123497 34723 58.683624 -24.799011 15.006546 34724 57.707947 -25.158508 15.103027 34725 59.498566 -24.571701 14.978333 34726 59.523941 -25.369720 15.277054 34727 60.380310 -25.000214 14.940964 34728 30.521011 -24.852005 15.126434 34729 50.541351 -26.884125 15.094521 34730 61.203125 -25.431778 14.488159 34731 60.633469 -25.897018 14.802231 34732 7.077693 -26.008522 13.419418 34733 7.491168 -26.962727 13.303204 34734 31.810488 -25.968979 14.662384 34735 33.128143 -25.626572 16.505684 34736 49.580261 -27.364792 14.999626 34737 60.045837 -26.355881 14.999146 34738 38.044495 -28.242355 15.887772 34739 45.727280 -29.226196 14.797836 34740 45.019180 -28.761780 14.401642 34741 48.647278 -28.272598 15.040962 34742 47.507431 -28.101868 14.782661 34743 8.916108 -28.868864 12.119526 34744 46.944687 -29.067841 14.897980 34745 36.348892 -30.227737 14.577080 34746 36.055435 -30.826797 14.914558 34747 44.956848 -29.277771 14.723579 34748 62.330399 -29.980682 15.158287 34749 63.685974 -30.145126 15.995636 34750 63.217545 -29.815033 16.161339 34751 11.820910 -32.228912 10.019127 34752 41.180176 -31.239410 13.839005 34753 48.317902 -30.767853 14.970612 34754 48.245911 -29.586838 15.002762 34755 49.002243 -30.629913 15.049477 34756 49.940277 -29.550598 15.284904 34757 49.669693 -30.908783 15.304474 34758 54.610931 -28.194366 15.419518 34759 55.010498 -30.955368 14.626656 34760 61.008118 -30.380875 15.054321 34761 61.321396 -30.214569 16.760460 34762 5.306640 -33.401001 19.069592 34763 5.376351 -33.141083 18.843493 34764 5.246358 -33.088539 19.176054 34765 5.438098 -33.688042 18.814249 34766 7.155683 -34.735405 15.794422 34767 7.182222 -33.236813 15.590923 34768 8.021096 -33.120178 14.466873 34769 8.622245 -33.442905 13.777021 34770 9.549040 -30.199942 11.890804 34771 40.013657 -32.628845 14.008606 34772 40.897064 -32.111862 14.111694 34773 47.050034 -30.545471 14.969223 34774 46.261871 -32.397629 15.323097 34775 48.536804 -31.950500 15.627663 34776 53.938614 -32.889664 15.729073 34777 52.975983 -32.712112 16.030289 34778 53.039368 -32.025314 15.881401 34779 59.974518 -30.874374 14.737366 34780 6.414034 -35.350830 17.108641 34781 6.904756 -36.027100 16.312122 34782 6.665710 -34.538673 16.533577 34783 7.498876 -36.017174 15.389229 34784 5.769153 -35.186085 18.545612 34785 6.028963 -35.108063 17.859230 34786 5.924456 -34.629616 17.967012 34787 8.944688 -33.046135 13.351656 34788 10.437861 -33.118252 11.733973 34789 10.832882 -32.856571 11.253956 34790 10.134858 -32.328876 11.895298 34791 37.378563 -32.376328 14.218529 34792 36.880630 -32.800491 14.810013 34793 37.548599 -32.894714 14.518494 34794 38.632401 -32.859070 14.151192 34795 37.894638 -33.515411 14.867012 34796 40.749298 -32.821884 14.259491 34797 41.423370 -32.979294 14.472610 34798 55.395355 -32.705688 15.437874 34799 55.747772 -33.390198 16.332237 34800 54.799591 -33.574341 16.095398 34801 5.329892 -33.711342 19.181662 34802 5.615826 -34.297333 18.622309 34803 5.769033 -33.775433 18.088411 34804 5.550128 -33.564236 18.515997 34805 9.899801 -33.339622 12.340719 34806 11.280662 -33.594299 10.937696 34807 11.372062 -32.718590 10.637440 34808 12.709165 -33.826706 9.586321 34809 38.906960 -34.529053 15.610107 34810 38.822968 -35.567474 17.056854 34811 37.816315 -34.762772 16.388550 34812 37.584717 -34.371048 15.892883 34813 40.773834 -33.643051 14.486504 34814 39.809067 -33.338333 14.207367 34815 42.171234 -32.055069 14.442795 34816 44.164001 -32.889511 15.092812 34817 42.565918 -33.676544 14.898911 34818 54.215424 -31.303589 15.312851 34819 5.334585 -33.924850 19.309065 34820 0.166632 -33.311783 16.376333 34821 5.420567 -34.164528 19.133904 34822 6.071464 -34.252213 17.553604 34823 8.027182 -36.431629 14.671787 34824 12.126156 -33.910294 10.161352 34825 39.532646 -33.834198 14.649010 34826 41.685745 -33.776810 14.683472 34827 41.810913 -34.646744 15.512817 34828 40.478119 -34.502747 15.222107 34829 63.612045 -34.339127 14.942680 34830 6.100247 -35.420902 17.778357 34831 6.207103 -35.881573 17.643148 34832 6.289672 -34.053818 17.108088 34833 63.512329 -32.052322 17.427872 34834 63.921890 -31.334793 16.102402 34835 63.913574 -32.593552 15.778076 34836 6.490388 -36.876671 17.226358 34837 7.156786 -37.611073 15.892084 34838 7.780513 -37.033840 14.998184 34839 8.947708 -38.976486 13.347496 34840 9.432617 -39.098434 12.926041 34841 62.583435 -37.262375 14.676193 34842 63.007553 -38.574448 14.374138 34843 62.445786 -36.424515 14.841072 34844 9.121727 -39.538239 13.368729 34845 9.403099 -39.574814 13.016426 34846 62.376572 -38.992081 15.449654 34847 62.677536 -39.856323 15.984871 34848 7.155533 -41.027283 13.243011 34849 8.145782 -40.798096 13.212555 34850 8.527191 -40.449646 13.328102 34851 52.102966 -40.589188 13.229210 34852 5.027908 -41.835266 13.330002 34853 5.726173 -41.622223 13.853935 34854 43.000580 -41.981033 13.252899 34855 43.935440 -42.067368 13.890167 34856 47.925125 -42.290543 13.893532 34857 48.746826 -41.214783 13.579697 34858 49.065475 -41.687622 13.900208 34859 4.192864 -44.543884 13.805389 34860 4.079956 -44.771103 12.909737 34861 3.982514 -43.872116 13.122063 34862 42.930176 -42.620056 14.357948 34863 49.070740 -42.665649 13.761383 34864 48.311951 -44.233475 14.448616 34865 48.679199 -41.846466 13.932938 34866 41.968109 -43.707748 14.597015 34867 42.100327 -45.457275 14.109215 34868 43.245483 -46.624054 13.866524 34869 62.797089 -43.189560 13.869644 34870 56.132996 -45.707199 14.299416 34871 55.062836 -47.026596 14.215271 34872 58.120911 -45.109894 14.854225 34873 58.624390 -46.017899 14.300827 34874 57.410019 -46.196762 13.744873 34875 58.578430 -46.320663 13.501434 34876 5.830948 -46.832443 13.631493 34877 6.405686 -47.250397 13.478203 34878 16.539490 -47.793121 12.612946 34879 17.594528 -47.781281 12.020905 34880 44.457886 -47.492828 13.718430 34881 56.436905 -46.560623 13.530075 34882 56.869598 -46.781494 13.165573 34883 60.654282 -46.095474 14.604126 34884 59.746658 -45.737701 14.932129 34885 8.031953 -49.117065 13.845070 34886 16.931641 -49.615265 12.346260 34887 16.140785 -49.483566 12.608810 34888 17.088516 -48.714844 12.387924 34889 50.828293 -46.725174 14.114937 34890 11.166054 -52.273224 13.651985 34891 9.146599 -49.360413 12.959953 34892 45.638489 -48.242798 13.547920 34893 54.215820 -47.871689 13.835632 34894 15.327232 -50.194870 12.308601 34895 15.424835 -53.443130 12.014427 34896 38.571152 -52.648880 12.960526 34897 37.776894 -53.228699 13.383469 34898 40.393646 -52.480392 14.299675 34899 59.605057 -52.284973 12.607590 34900 58.915833 -52.473251 12.575829 34901 11.725456 -53.895035 12.680855 34902 13.975051 -53.891037 12.141891 34903 54.439896 -53.465775 13.582588 34904 59.520996 -53.199112 12.592224 34905 12.859673 -54.605133 12.638077 34906 12.709747 -53.904358 12.109703 34907 14.935425 -54.200363 12.294495 34908 14.184097 -54.785767 12.529295 34909 15.017075 -54.662781 12.436882 34910 15.802811 -54.479309 12.050209 34911 38.981766 -52.474304 12.907249 34912 45.189728 -52.287262 14.228355 34913 45.484894 -50.896408 15.486458 34914 46.781342 -51.758499 15.065147 34915 56.254715 -54.497787 13.279007 34916 57.783463 -54.432800 13.291382 34917 57.153748 -54.085068 13.273987 34918 58.160400 -55.227127 12.699194 34919 57.206512 -55.131134 13.204918 34920 59.032578 -54.596252 12.390610 34921 36.727127 -54.264160 13.872604 34922 45.620575 -53.871826 12.941025 34923 47.004608 -53.443924 13.936226 34924 48.478348 -53.947693 13.907455 34925 14.903976 -55.453506 12.473419 34926 36.745598 -55.369339 13.851837 34927 52.582062 -55.530914 13.398819 34928 17.979370 -57.006256 13.701286 34929 20.556519 -57.767334 13.481438 34930 19.797333 -57.773132 12.519363 34931 19.697510 -57.186340 13.088051 34932 37.639908 -57.142807 13.573318 34933 9.595352 -58.118713 12.549965 34934 20.212479 -58.324234 12.312843 34935 38.467682 -57.804260 12.641594 34936 15.058197 -57.705750 13.778267 34937 15.766800 -58.120850 13.358780 34938 20.634956 -59.214447 14.032188 34939 39.417366 -58.586060 12.714340 34940 38.524681 -58.294220 13.651405 34941 40.750015 -59.349136 12.960587 34942 38.695412 -58.953979 14.562073 34943 37.658485 -57.883530 14.598679 34944 6.391770 -60.093521 13.085686 34945 4.756813 -61.556335 12.412338 34946 6.900139 -59.214447 11.928818 34947 8.265739 -58.113480 12.452209 34948 27.527321 -60.239731 11.502731 34949 41.336823 -59.934219 14.279259 34950 39.994286 -59.737579 14.777718 34951 42.084015 -59.777740 12.453041 34952 39.488632 -59.044128 13.717308 34953 45.115845 -60.879562 14.042480 34954 44.244415 -60.937134 15.566513 34955 27.608383 -61.792374 11.388161 34956 27.515991 -60.917130 11.545456 34957 49.264786 -61.111511 12.629539 34958 50.028625 -61.137848 12.388992 34959 49.799469 -60.765625 13.332169 34960 49.163620 -60.796326 13.737823 34961 50.646362 -60.904358 13.228874 34962 54.802963 -61.220917 13.710121 34963 54.292938 -60.872330 13.487160 34964 6.178757 -60.617462 13.939568 34965 5.490189 -60.960663 13.697723 34966 4.785477 -61.769241 13.689774 34967 9.590622 -62.117294 12.739853 34968 9.165710 -64.485245 12.176872 34969 11.549973 -61.143921 11.822189 34970 20.337082 -60.678421 14.052658 34971 20.675827 -60.724960 13.196823 34972 46.917847 -61.083359 13.606056 34973 46.026978 -60.837463 14.327087 34974 49.718430 -61.656723 11.801025 34975 4.142319 -62.483109 12.014717 34976 3.992043 -63.547211 12.140671 34977 20.450073 -61.812637 12.782791 34978 27.269806 -64.750504 11.661369 34979 55.429810 -62.157547 13.719002 34980 3.794609 -65.073227 11.680769 34981 18.708267 -62.207687 14.568275 34982 17.884987 -63.148956 14.215698 34983 18.589661 -63.479523 14.120697 34984 27.672043 -64.715591 11.549156 34985 55.514221 -63.294998 12.662430 34986 14.656792 -65.377975 11.740021 34987 15.509903 -65.413361 11.698120 34988 15.052933 -64.428665 12.343262 34989 13.858047 -64.976166 12.189964 34990 55.182907 -64.470596 12.759407 34991 3.507805 -65.821136 11.637047 34992 16.632385 -64.054947 13.037880 34993 16.100754 -64.211029 12.636024 34994 20.059433 -65.781586 11.714798 34995 19.829132 -65.603378 12.076187 34996 27.179840 -65.534882 11.345100 34997 3.406334 -66.274277 11.603653 34998 3.516953 -67.350967 11.480637 34999 7.919174 -66.492432 12.490013 35000 8.367844 -64.562988 12.715866 35001 18.766373 -66.075485 12.026070 35002 50.979233 -68.203018 12.785461 35003 51.774841 -67.715805 12.390945 35004 52.908600 -67.227753 13.419228 35005 54.666718 -65.507660 13.858719 35006 7.846748 -68.208115 11.625359 35007 8.812843 -67.759003 11.459160 35008 9.624359 -68.132431 10.873985 35009 37.886292 -68.941925 12.487885 35010 37.271744 -69.608139 12.499031 35011 48.350800 -68.740891 12.428940 35012 47.478943 -68.725403 12.837502 35013 48.177307 -68.471420 12.881332 35014 48.988022 -68.533493 12.934174 35015 49.081238 -69.236221 12.252113 35016 50.252167 -68.832230 12.155052 35017 50.044067 -68.475937 13.396072 35018 52.279785 -67.430984 12.651543 35019 4.294594 -69.496353 11.255981 35020 4.329262 -69.121750 11.486954 35021 7.072373 -69.039993 11.188179 35022 6.831772 -68.092957 12.102013 35023 14.306046 -68.683441 11.850533 35024 38.679947 -68.534653 13.310806 35025 39.112122 -68.862228 12.205078 35026 39.707176 -68.385330 13.652115 35027 41.268265 -68.767181 13.550339 35028 48.039886 -69.439560 12.421036 35029 47.008072 -69.389755 12.706566 35030 47.350281 -70.352203 12.764839 35031 48.765488 -70.349136 12.424080 35032 3.693451 -69.006256 11.158844 35033 13.134872 -70.415955 14.158264 35034 14.547287 -71.137512 13.975357 35035 14.292206 -69.957596 12.905968 35036 37.369774 -70.467285 12.596466 35037 49.994797 -70.313705 11.975067 35038 17.120087 -72.128250 11.434624 35039 16.360336 -71.880951 12.382141 35040 50.208710 -71.614380 11.918457 35041 10.598984 -72.834259 11.663445 35042 11.492935 -73.000107 11.379295 35043 14.280014 -72.813446 11.466034 35044 13.641228 -73.042496 11.148605 35045 14.809387 -72.943832 11.315475 35046 38.509125 -73.510025 11.929771 35047 41.634918 -70.417984 11.646355 35048 43.508240 -71.411972 12.329649 35049 44.612854 -72.366653 12.040565 35050 50.085327 -72.445435 11.764954 35051 9.819213 -73.456146 11.730560 35052 9.030945 -73.774155 12.014626 35053 9.691833 -72.405304 12.309273 35054 16.721581 -72.613419 11.228172 35055 39.653076 -74.508575 10.973152 35056 40.501404 -75.822845 10.743576 35057 41.682281 -76.706070 10.512650 35058 46.252625 -73.133194 11.614349 35059 45.378571 -72.946640 11.915787 35060 49.652603 -72.195740 12.211853 35061 7.257095 -74.434158 11.370651 35062 8.428329 -75.663651 12.057617 35063 7.730369 -75.584106 11.213135 35064 8.866547 -74.798508 12.229286 35065 9.080788 -75.405411 12.835258 35066 38.884193 -75.303940 11.825806 35067 38.883766 -74.279190 11.725494 35068 38.992844 -76.755753 11.708817 35069 17.566780 -76.532852 11.332184 35070 17.129257 -77.003265 12.548683 35071 18.940353 -76.346176 10.871208 35072 38.251144 -74.361572 12.417397 35073 38.476639 -76.280365 12.886101 35074 38.085892 -75.078476 12.822739 35075 39.840088 -77.113907 11.011467 35076 17.247025 -77.626678 13.759262 35077 15.461884 -77.271820 14.076210 35078 19.321579 -77.801193 11.377739 35079 39.903786 -77.750870 10.855141 35080 38.964676 -79.179352 11.783775 35081 4.956268 -77.889145 12.297935 35082 5.678581 -78.803482 12.806747 35083 15.689117 -80.442764 10.665863 35084 16.385895 -80.385178 10.822784 35085 18.302689 -80.314224 10.730865 35086 17.440681 -80.430084 11.695190 35087 19.017998 -79.367569 11.924080 35088 18.412346 -79.855133 12.241997 35089 39.250870 -80.059174 12.158432 35090 39.737495 -81.667542 12.064140 35091 39.423187 -81.266418 12.058792 35092 5.470490 -80.587448 11.547592 35093 11.430946 -81.442596 10.697495 35094 33.599754 -81.980621 11.753380 35095 32.769623 -82.287704 10.999649 35096 33.107903 -83.005478 12.373749 35097 34.773163 -82.086029 11.886076 35098 34.191589 -81.739227 11.225075 35099 33.487991 -81.641739 10.959419 35100 35.454590 -82.418808 10.916878 35101 34.799316 -81.902557 10.959389 35102 12.376633 -82.235718 12.062996 35103 11.793976 -80.786926 11.905121 35104 35.937912 -83.056137 11.034584 35105 6.210548 -83.197769 10.559074 35106 6.988503 -84.068008 10.546547 35107 7.906936 -85.198212 10.454855 35108 36.582489 -83.810867 11.053246 35109 37.092606 -84.846375 11.093849 35110 13.275360 -84.314133 11.709854 35111 34.786842 -87.327774 11.600227 35112 33.909103 -85.671051 12.708778 35113 6.525505 -87.296524 10.031464 35114 7.189064 -86.388062 10.855606 35115 6.364250 -87.948639 11.032980 35116 12.873810 -86.169785 10.173698 35117 13.917274 -84.641281 11.882225 35118 13.716110 -84.932480 11.193634 35119 14.535942 -84.465500 11.510025 35120 13.059326 -87.326035 9.842941 35121 34.849518 -87.247467 12.851700 35122 37.463181 -85.221008 10.921707 35123 38.951988 -85.855621 11.634727 35124 39.131348 -85.537643 10.897591 35125 12.674271 -86.922974 9.999603 35126 14.730194 -83.419220 12.600807 35127 14.160385 -84.105469 12.515823 35128 39.879776 -85.211563 12.090752 35129 13.291687 -86.701736 10.121552 35130 6.855225 -90.884201 10.033096 35131 25.376869 -90.827988 11.416512 35132 24.415169 -91.667801 11.364853 35133 24.249496 -90.216034 11.783508 35134 34.817902 -90.857895 10.549843 35135 34.854675 -90.144806 11.440353 35136 35.183594 -89.035278 11.337212 35137 25.237488 -91.773911 10.734955 35138 25.461044 -93.047775 10.551117 35139 24.386520 -92.760803 11.554932 35140 26.077728 -91.951004 10.864059 35141 26.716339 -91.165527 12.145630 35142 8.991151 -93.908081 11.658157 35143 9.308701 -94.980392 10.857597 35144 13.093796 -93.197311 12.173584 35145 14.067261 -92.117859 11.981476 35146 14.066238 -93.479782 10.958824 35147 25.437202 -94.314362 10.826317 35148 24.819443 -93.486160 11.337936 35149 26.848137 -93.908600 10.175217 35150 26.614365 -92.849030 10.553360 35151 27.262329 -93.145355 10.930084 35152 32.664696 -93.721817 10.075371 35153 25.247208 -94.178940 12.170509 35154 28.683228 -95.812729 10.271553 35155 27.920975 -95.646164 10.000433 35156 28.414993 -94.917038 11.036255 35157 10.008667 -96.462952 9.451691 35158 11.440918 -96.369781 10.448906 35159 15.589684 -95.129120 10.517609 35160 15.518037 -96.382187 9.739502 35161 20.686760 -96.173752 9.391006 35162 20.913025 -96.929199 9.508286 35163 21.286484 -96.005615 9.009247 35164 29.606689 -95.334824 10.956520 35165 29.682877 -96.238312 9.580078 35166 15.206543 -97.737885 9.701324 35167 19.672409 -97.824722 9.649063 35168 25.844528 -97.531296 11.686714 35169 25.684715 -98.333649 10.837837 35170 10.579971 -96.872406 9.668686 35171 21.198563 -98.641418 9.870895 35172 15.136772 -96.459915 10.682518 35173 14.840225 -97.162201 10.798073 35174 14.622940 -97.931992 11.114105 35175 15.191559 -98.827591 9.410767 35176 22.638199 -99.663910 10.219124 35177 24.914658 -99.342453 10.239189 35178 15.781960 -100.497986 9.412819 35179 16.232529 -100.753891 9.343092 35180 8.787415 64.550720 21.740631 35181 8.292694 64.704056 21.759697 35182 7.372276 64.723053 21.065048 35183 7.834884 64.523132 22.473564 35184 4.173699 62.689346 22.570320 35185 13.337495 62.656113 20.946060 35186 17.957245 62.900864 20.921249 35187 17.919388 62.893341 23.577171 35188 17.245667 62.928589 24.577393 35189 16.274750 62.755157 23.949654 35190 14.279724 61.893341 21.000519 35191 20.578003 62.188354 22.155815 35192 22.023842 61.521423 22.065987 35193 21.575111 61.746445 22.274933 35194 15.045532 61.645538 21.095131 35195 15.013428 62.012375 20.775925 35196 22.365387 61.264572 22.195908 35197 22.936043 60.689407 22.335587 35198 23.326126 60.082306 21.352859 35199 24.322197 59.221207 21.577347 35200 24.791634 58.834534 22.564644 35201 24.222473 59.369217 22.480972 35202 4.208443 59.236313 20.459824 35203 4.246796 58.796600 21.850754 35204 4.376473 57.663742 22.083687 35205 5.048042 57.718323 21.272507 35206 4.870979 58.328949 20.283371 35207 5.675507 57.765686 20.308357 35208 24.285339 58.300552 20.689781 35209 25.147186 58.288208 21.576439 35210 5.736603 57.104706 20.872276 35211 25.272217 56.388962 20.408585 35212 26.482239 56.192657 21.024673 35213 27.554810 56.215515 21.552948 35214 26.978012 57.036652 22.173454 35215 24.985809 57.437073 20.735497 35216 25.949524 57.341064 21.521759 35217 4.043121 55.250763 20.852562 35218 5.241875 55.624847 20.498154 35219 4.950058 56.692398 21.321121 35220 29.898232 55.254272 21.084412 35221 28.566322 55.852600 21.757889 35222 28.256485 55.602783 20.795738 35223 27.257339 55.664291 20.931068 35224 27.370560 55.290268 20.367935 35225 4.725678 55.047623 20.113945 35226 26.658218 55.417557 20.554550 35227 26.680527 55.150269 19.989494 35228 31.942064 53.558441 20.308838 35229 3.716881 51.667664 19.819481 35230 31.117218 52.432709 20.210648 35231 3.248077 52.837601 20.732590 35232 4.152023 51.869385 20.808449 35233 4.492020 51.522034 20.223991 35234 4.548370 51.012573 19.867630 35235 29.502930 52.483551 21.293633 35236 31.687822 53.230087 20.512550 35237 3.797966 50.526459 19.299896 35238 5.148552 49.744476 19.819656 35239 6.277687 48.087524 20.062462 35240 5.152207 48.357407 19.799660 35241 25.672012 50.651260 20.568329 35242 26.716187 51.354233 21.269592 35243 27.617935 51.139816 20.370010 35244 22.781136 48.336227 20.580894 35245 22.498451 48.187042 20.990738 35246 22.697563 48.899704 20.864731 35247 23.647766 50.014526 21.063263 35248 24.765472 50.644257 21.213387 35249 4.203255 48.355316 19.535263 35250 6.844917 49.346130 20.568977 35251 7.320892 48.204971 20.116409 35252 33.226959 48.122849 20.582962 35253 33.960571 49.334610 21.736900 35254 32.995979 49.822021 21.961670 35255 31.998491 49.180023 21.410507 35256 31.821947 48.240753 20.702347 35257 34.903976 48.455109 21.736748 35258 34.224968 48.472656 20.923927 35259 34.710709 47.612122 20.734230 35260 4.969933 47.321915 20.373787 35261 7.674644 47.225037 20.439140 35262 6.640137 46.542068 20.988075 35263 31.269836 49.482666 22.431892 35264 30.430214 48.153015 21.149582 35265 34.440704 46.301636 20.151024 35266 2.695274 46.222672 19.515388 35267 26.401993 46.466248 20.177048 35268 26.179779 47.322800 21.018852 35269 25.333931 47.056335 21.184143 35270 30.433632 46.822861 20.056313 35271 28.573334 46.097656 20.018486 35272 27.657379 46.472137 20.263420 35273 35.457230 46.554962 20.917595 35274 3.412598 43.400070 19.811813 35275 3.377792 43.252151 21.516190 35276 3.144112 44.728546 22.037460 35277 4.745857 42.588440 19.339897 35278 36.003716 43.154694 21.017036 35279 42.745361 42.960571 20.348450 35280 41.788681 43.153473 20.982651 35281 9.447021 40.676193 19.181244 35282 9.965881 40.249710 19.274132 35283 10.877777 39.309235 19.282555 35284 12.564392 37.542816 18.923225 35285 11.333755 38.861267 18.973312 35286 11.818115 38.329437 18.738831 35287 3.703186 36.487808 18.623665 35288 3.374771 36.185638 18.695381 35289 3.658005 35.447235 19.159943 35290 5.699509 35.512085 20.410110 35291 6.615578 35.679489 19.865982 35292 12.761642 36.698929 20.119064 35293 13.237885 36.600403 18.951645 35294 11.913589 37.325485 21.833595 35295 13.257477 35.960205 21.656898 35296 42.305038 35.961563 20.821373 35297 39.780884 34.991974 19.887367 35298 9.950485 34.039871 19.309868 35299 8.746101 34.238831 19.990845 35300 40.865387 34.978973 20.577530 35301 47.450729 35.089569 19.522232 35302 48.134521 34.589600 20.160332 35303 13.463661 34.561707 20.234184 35304 37.402687 34.086792 19.194740 35305 38.216293 34.461395 19.439079 35306 38.970444 34.393005 19.884117 35307 49.545273 33.778839 20.301407 35308 10.902367 33.315979 19.561127 35309 11.875404 33.218506 18.913673 35310 10.935226 32.703369 20.135933 35311 11.870438 32.775818 19.669418 35312 12.531830 33.073029 18.793488 35313 12.837311 33.141418 18.985817 35314 37.570755 33.064117 20.008667 35315 38.222122 33.899719 19.867294 35316 3.368782 31.852554 18.946289 35317 12.492813 32.913193 19.188179 35318 45.505920 31.717453 19.709015 35319 45.184250 30.890472 19.459343 35320 45.259659 30.322571 19.548630 35321 44.536438 30.321793 19.340431 35322 4.310127 30.147141 18.374672 35323 3.023377 31.250320 19.793137 35324 3.427757 29.779846 19.793991 35325 42.246353 29.132431 19.094566 35326 41.038589 29.626480 18.750175 35327 35.722412 31.231354 19.652756 35328 35.984169 30.495728 19.698647 35329 45.785187 29.845917 20.502228 35330 51.075012 31.776260 20.304634 35331 36.123749 29.993408 19.260567 35332 36.554916 29.663116 19.233658 35333 39.935623 29.275940 18.783836 35334 43.237015 29.605530 19.230545 35335 41.773010 28.563980 19.246223 35336 40.836945 27.984497 19.695816 35337 44.224106 28.801651 20.017937 35338 44.221878 26.871643 21.494789 35339 38.906265 28.631348 19.447815 35340 5.891663 27.333023 18.437546 35341 6.042976 27.205872 18.077744 35342 37.641846 29.056992 20.135406 35343 38.377335 28.263611 20.640472 35344 2.963101 20.263172 14.382910 35345 5.808182 26.926041 18.355263 35346 5.304176 26.037582 18.381599 35347 3.130180 20.070366 15.175804 35348 4.273644 25.243454 17.791046 35349 15.978704 26.598053 19.725927 35350 48.697968 26.072693 19.996422 35351 53.081924 25.404404 18.996353 35352 53.919617 25.350021 19.273018 35353 4.075612 22.986671 17.490076 35354 3.881292 21.300858 17.536564 35355 3.605321 21.231621 16.573742 35356 4.479118 24.919006 18.469986 35357 4.627211 23.967073 18.562620 35358 4.287308 21.631981 18.641027 35359 50.840149 25.309448 20.056747 35360 52.027435 25.340744 19.113449 35361 54.409225 25.271729 20.011116 35362 55.482513 24.370361 20.467377 35363 56.991669 21.566132 20.120514 35364 56.791779 22.354767 19.385574 35365 56.218781 23.436432 19.346939 35366 44.049698 18.630066 18.360825 35367 44.621490 17.958740 18.549011 35368 45.523804 18.366501 18.426399 35369 49.291107 19.154266 18.536354 35370 50.428162 18.804535 18.422226 35371 51.622925 18.608398 18.309647 35372 52.209015 18.919662 17.868950 35373 57.964996 19.332153 18.946518 35374 57.547134 19.963913 19.960228 35375 31.490555 17.631638 18.285629 35376 31.143112 16.944000 18.159866 35377 32.250504 17.040421 18.206345 35378 46.658722 19.150635 18.606346 35379 51.141388 18.811218 18.501137 35380 52.891678 18.525940 17.849197 35381 2.636697 14.177252 15.207623 35382 2.466586 13.732422 14.325861 35383 33.633636 16.950104 18.259583 35384 34.750244 17.497177 17.847549 35385 34.474350 16.294403 18.315613 35386 35.567734 16.986511 18.121674 35387 40.885010 16.724991 18.256409 35388 41.525650 17.854095 18.409653 35389 42.619659 17.460632 18.416870 35390 42.519348 18.423203 18.314407 35391 46.752808 18.332520 18.290314 35392 2.363954 12.277100 13.765940 35393 2.298541 11.026795 13.744106 35394 2.250371 10.937928 13.166925 35395 43.915253 17.483978 18.248962 35396 58.650345 16.971481 18.277962 35397 58.050049 18.397171 19.643456 35398 2.421882 11.928559 14.608028 35399 30.927589 15.653625 17.877396 35400 42.082520 16.537567 18.009583 35401 34.201431 15.309860 18.050713 35402 39.887558 15.735489 17.426239 35403 39.318481 16.392990 18.240318 35404 31.116638 12.815979 17.395004 35405 32.011284 15.007935 18.099380 35406 55.455307 14.062775 19.427727 35407 56.420120 14.384705 18.818504 35408 46.274628 11.242798 19.354179 35409 45.809860 12.009949 19.706024 35410 45.820038 12.118134 19.155121 35411 50.444916 11.139847 17.407127 35412 48.754272 10.888672 18.145744 35413 52.541611 11.132477 18.659798 35414 51.413544 11.025955 21.480606 35415 52.563675 10.661926 21.871094 35416 50.676605 10.884796 22.939072 35417 48.063385 10.883698 19.278358 35418 46.372345 11.130005 20.601654 35419 47.394073 10.853165 20.347122 35420 56.137482 9.924835 18.061615 35421 55.762222 9.736542 18.628593 35422 33.086716 4.179611 16.902855 35423 49.745026 6.668732 21.341484 35424 51.433487 7.132492 20.276627 35425 59.940826 6.554413 18.042191 35426 47.653580 4.398621 18.021370 35427 48.337814 6.255493 19.512016 35428 57.382812 5.887283 17.915146 35429 59.850449 6.722885 18.942093 35430 60.540894 6.196228 19.560402 35431 59.755310 6.793198 20.048889 35432 55.371521 4.765732 17.699440 35433 56.332092 5.425377 18.315834 35434 60.802307 5.328857 19.003738 35435 33.090775 3.188995 17.256760 35436 36.057739 2.232849 18.279091 35437 37.696136 1.883377 18.164406 35438 37.104469 3.015579 17.670479 35439 38.285660 2.951820 17.418518 35440 60.469574 4.236847 19.254463 35441 38.424103 0.887482 18.349533 35442 47.770081 3.332321 18.051796 35443 60.009567 1.584412 18.750290 35444 60.694977 2.992599 18.169426 35445 51.758881 2.924881 19.138550 35446 60.819138 -0.061081 18.825020 35447 60.308136 0.587204 18.657936 35448 61.619202 -0.468506 17.882706 35449 1.949342 1.438615 15.843670 35450 2.016894 1.668223 16.970045 35451 1.931565 0.849418 15.111872 35452 61.635910 -1.537979 18.935226 35453 34.651001 -2.566193 16.960289 35454 53.692474 -2.689545 18.403297 35455 52.734253 -3.048935 18.129929 35456 55.960876 -3.667801 18.339958 35457 54.601517 -2.920685 18.611664 35458 54.653427 -2.315765 17.780197 35459 33.837921 -3.972595 16.949409 35460 34.285057 -3.350616 16.876694 35461 51.512939 -3.756256 18.454765 35462 56.753220 -3.514496 17.517548 35463 33.271416 -4.855911 16.602188 35464 38.863342 -3.312805 18.140099 35465 39.677925 -2.449203 17.892189 35466 39.252426 -2.404251 18.418373 35467 38.559219 -4.242004 17.304604 35468 37.952927 -4.887131 16.997749 35469 32.826080 -6.069641 17.105141 35470 36.267426 -6.733063 17.197624 35471 61.136627 -8.251862 17.602562 35472 62.174835 -7.224091 18.150635 35473 60.546692 -7.239151 17.817345 35474 2.115615 -5.293636 18.015358 35475 2.033664 -2.937341 17.914351 35476 52.048737 -7.908096 18.306931 35477 53.742157 -7.509293 17.150856 35478 54.620987 -6.873459 18.579399 35479 54.350616 -6.049698 19.430107 35480 53.685120 -6.743240 19.090446 35481 2.506151 -9.269009 15.042793 35482 2.596643 -10.062774 15.365286 35483 31.455116 -8.495361 16.462357 35484 31.307312 -8.622482 16.679291 35485 31.447922 -8.424957 16.795494 35486 36.878555 -8.183777 17.574440 35487 37.591324 -8.426971 17.819481 35488 57.602325 -8.315384 17.230019 35489 2.172517 -6.641609 17.892113 35490 2.176018 -6.772807 17.331797 35491 31.462410 -8.829117 16.523842 35492 31.758394 -9.326706 16.662506 35493 49.125198 -9.357193 16.990250 35494 50.602859 -8.532257 19.071114 35495 50.460052 -8.123077 20.242508 35496 49.644379 -8.771255 19.889763 35497 59.207642 -8.382584 17.635658 35498 58.173859 -8.294540 17.707893 35499 60.275177 -8.585190 17.445747 35500 63.057602 -9.289505 18.344467 35501 63.070709 -8.182434 19.458473 35502 2.269094 -7.893254 16.991913 35503 2.305502 -8.061245 15.986591 35504 45.634781 -10.450272 16.945610 35505 45.197174 -10.819519 16.952682 35506 45.955276 -10.305939 17.407944 35507 2.430746 -8.728485 15.127615 35508 34.027191 -11.234711 16.128471 35509 44.431870 -11.711517 17.065948 35510 44.517029 -10.904526 17.766327 35511 43.687134 -11.597839 17.715790 35512 43.654419 -11.203110 18.095932 35513 45.426147 -11.562714 16.341759 35514 2.797805 -11.610036 15.806526 35515 43.344757 -11.519150 18.051720 35516 43.282074 -11.915939 18.240112 35517 45.533859 -13.483032 17.200645 35518 46.511566 -13.530212 17.005669 35519 44.756714 -12.721176 17.057343 35520 45.009888 -12.183105 16.579773 35521 50.877289 -12.763992 17.506882 35522 51.857849 -12.872208 17.966606 35523 53.586487 -13.354034 17.135117 35524 52.807831 -13.052277 17.896507 35525 54.025589 -14.260513 16.651192 35526 53.975800 -12.791229 16.388100 35527 3.014120 -12.982779 15.745260 35528 38.144325 -14.184753 15.983597 35529 47.639893 -13.162399 16.827461 35530 48.974762 -13.020538 16.892509 35531 49.628540 -13.288025 17.719048 35532 61.057999 -14.239563 17.012993 35533 63.387878 -13.906189 17.664513 35534 59.834534 -14.757965 17.668747 35535 62.370667 -14.488510 17.676987 35536 3.562705 -16.099424 15.822832 35537 3.367920 -15.174792 15.919945 35538 35.872841 -16.483780 16.082115 35539 3.991205 -18.085049 15.834442 35540 35.310844 -16.485733 17.397804 35541 33.899719 -17.351334 18.067024 35542 52.008667 -17.212936 16.806732 35543 52.967545 -16.926071 16.420921 35544 58.030624 -17.226288 18.273590 35545 50.647293 -18.482788 16.831787 35546 51.094406 -17.385834 17.350777 35547 50.155319 -18.079132 17.575294 35548 51.578339 -16.629395 17.609398 35549 51.481049 -18.466385 16.562477 35550 51.722778 -19.989227 16.692352 35551 55.699692 -20.047745 16.735626 35552 4.290405 -19.323851 15.833197 35553 32.421249 -20.340622 15.999054 35554 49.201630 -20.059418 16.685516 35555 49.675446 -20.172745 16.331123 35556 49.952362 -19.322540 16.738632 35557 50.116699 -20.022568 16.324104 35558 50.747696 -19.737045 16.469025 35559 52.592468 -20.430862 17.098724 35560 54.686310 -20.530884 17.010536 35561 31.816393 -21.148682 16.512672 35562 32.334320 -19.940323 17.125992 35563 49.450104 -20.612732 16.368256 35564 49.117493 -21.055252 16.850334 35565 50.039062 -20.697418 16.451096 35566 50.858810 -20.870651 16.892502 35567 56.682556 -20.507568 17.226875 35568 5.051967 -21.230158 14.705770 35569 40.418411 -22.151642 15.395164 35570 50.110229 -21.527374 17.171082 35571 31.240738 -22.110748 16.415466 35572 35.640396 -22.981384 15.987518 35573 6.171737 -23.739199 13.660204 35574 6.120503 -26.914680 15.998272 35575 6.685666 -28.822277 15.532154 35576 7.015208 -28.515722 14.910370 35577 30.347488 -23.692459 16.585579 35578 29.955818 -24.891052 16.590752 35579 30.033424 -23.766159 17.551704 35580 58.595795 -26.132431 15.140457 35581 38.894455 -23.206146 16.288979 35582 59.574402 -26.204926 15.246124 35583 60.126678 -25.776749 15.215408 35584 32.019241 -26.265671 16.831146 35585 53.862518 -27.016357 15.406319 35586 52.842560 -27.213440 15.474632 35587 53.849518 -27.605118 15.667633 35588 8.008146 -27.736563 12.909145 35589 53.729385 -28.056488 15.844589 35590 8.745382 -29.416874 12.651619 35591 38.757057 -27.663345 15.827904 35592 39.141541 -27.348312 15.521622 35593 51.952148 -29.596786 15.758965 35594 51.005615 -30.499741 15.621643 35595 51.394836 -28.029312 15.432808 35596 52.992249 -28.584656 15.857437 35597 36.951767 -28.970535 16.187256 35598 50.271179 -30.656204 15.449821 35599 53.844696 -28.648315 15.889786 35600 53.658981 -29.606659 15.692436 35601 62.602402 -29.760269 15.992752 35602 5.521072 -32.844704 18.465225 35603 5.925671 -33.194099 17.656805 35604 6.328082 -32.991638 16.888639 35605 6.775497 -33.485153 16.223606 35606 7.287330 -30.341799 14.979059 35607 8.110368 -31.195053 14.065285 35608 7.759570 -30.127495 14.284388 35609 36.408859 -29.825500 15.305679 35610 43.170120 -31.350159 14.524124 35611 52.298447 -30.975342 15.856216 35612 59.996826 -30.662262 15.607605 35613 59.811691 -30.706558 17.768394 35614 58.996170 -31.164398 16.409164 35615 62.631073 -29.865891 16.642838 35616 63.836533 -30.612411 16.120651 35617 7.073244 -31.548809 15.512482 35618 7.515261 -32.614014 15.054787 35619 10.663195 -32.172039 11.261002 35620 35.376862 -31.353592 16.572418 35621 35.641708 -30.590057 15.939789 35622 35.833755 -31.699921 15.650490 35623 50.505630 -31.507050 15.840439 35624 7.808710 -31.925308 14.576729 35625 9.042229 -32.281384 13.124109 35626 12.053282 -33.026100 10.015371 35627 36.312225 -32.699677 15.506721 35628 43.707642 -34.206009 15.388794 35629 58.585419 -31.497452 18.161407 35630 55.218521 -33.769791 17.086365 35631 36.922157 -33.361145 15.306511 35632 37.555206 -33.959137 15.478210 35633 36.847122 -33.717407 16.106361 35634 43.008209 -34.618073 15.600060 35635 45.670914 -33.638290 15.900925 35636 47.060120 -33.404861 16.394363 35637 63.432709 -33.828903 15.743057 35638 5.367182 -34.258316 19.473907 35639 44.696198 -34.223984 16.033546 35640 43.831894 -34.718185 16.024437 35641 45.711609 -34.207458 17.009979 35642 53.069489 -33.311188 16.306107 35643 53.902618 -33.655777 16.168747 35644 56.932907 -32.533386 16.570404 35645 5.209416 -33.269390 19.403917 35646 5.152109 -33.445160 19.841293 35647 62.699448 -34.168198 16.800621 35648 60.820190 -35.967606 16.366829 35649 61.033890 -35.260727 16.813927 35650 61.573914 -35.239243 16.172363 35651 61.540878 -35.825104 15.594437 35652 61.855362 -36.637131 15.161758 35653 61.084900 -36.470734 15.579674 35654 7.746457 -38.818451 14.845264 35655 8.525153 -38.558449 13.858639 35656 61.260895 -37.429306 15.536766 35657 60.750519 -36.821884 15.895905 35658 60.891876 -37.432343 15.979767 35659 62.064056 -37.929108 15.102989 35660 7.385376 -40.077835 14.989723 35661 7.085447 -39.061779 15.652874 35662 6.540009 -40.115738 15.762566 35663 8.382111 -39.752106 13.964653 35664 61.765198 -38.267776 15.566910 35665 61.567688 -38.248581 16.355026 35666 61.646362 -37.970978 17.577423 35667 61.004822 -37.582458 17.134033 35668 62.295303 -39.153107 16.281868 35669 62.865204 -41.182022 16.287643 35670 8.107651 -40.763748 14.044922 35671 62.765076 -43.027817 15.303505 35672 62.654572 -42.847641 16.895950 35673 4.877457 -42.293747 14.210327 35674 7.575241 -40.867050 14.625580 35675 6.591820 -41.148666 14.974739 35676 43.743881 -42.660248 14.918648 35677 45.009796 -42.776505 14.704681 35678 45.619659 -43.620468 15.343582 35679 46.690735 -43.434708 14.675476 35680 56.138489 -43.161102 15.296608 35681 56.129303 -42.209320 16.350777 35682 57.012344 -42.757950 15.815636 35683 56.974075 -43.354630 15.330734 35684 56.823730 -44.167877 14.909561 35685 4.450523 -43.704559 14.587006 35686 41.534622 -44.539261 14.511261 35687 41.321930 -44.557617 15.048256 35688 41.475250 -44.232178 14.922554 35689 55.670807 -44.141479 14.852165 35690 55.031845 -43.656113 15.233887 35691 55.402435 -43.333054 15.166916 35692 54.543640 -43.762192 15.708092 35693 55.060181 -44.926239 15.134705 35694 54.615692 -44.876236 16.065094 35695 55.158539 -46.165649 14.809799 35696 58.430298 -43.454208 16.287277 35697 59.164566 -44.034439 16.376709 35698 58.698990 -44.255707 15.765701 35699 5.441368 -46.450348 13.895096 35700 41.475555 -45.239105 15.326660 35701 42.333054 -46.637466 15.347488 35702 45.288406 -44.728607 16.751312 35703 45.896393 -44.969437 16.598785 35704 46.011139 -44.443741 15.882355 35705 59.793457 -44.810638 15.822144 35706 61.217148 -45.374695 15.220703 35707 14.414200 -47.786270 12.699883 35708 15.893242 -47.772873 12.906334 35709 42.097458 -47.215729 16.349014 35710 41.694977 -46.584259 16.461815 35711 43.884827 -47.977509 15.018341 35712 54.887497 -46.858276 15.021202 35713 62.163452 -44.204498 16.046356 35714 15.958878 -48.433990 12.859238 35715 54.295776 -47.606125 15.421623 35716 9.378503 -49.781616 14.906723 35717 10.033646 -49.588226 14.015625 35718 10.847595 -49.886368 15.023781 35719 45.873825 -48.913712 14.409630 35720 44.978653 -48.349380 14.413490 35721 44.989761 -48.937576 15.239044 35722 46.003296 -49.770279 15.209328 35723 11.357529 -53.412079 13.868614 35724 38.870773 -52.529938 13.561470 35725 39.555321 -53.357758 15.282234 35726 40.587708 -53.134323 15.371674 35727 41.679474 -51.976639 15.044540 35728 42.723022 -51.315033 15.775574 35729 53.592987 -53.281586 13.702057 35730 11.412079 -54.123001 13.530281 35731 36.723412 -53.533478 14.296692 35732 52.528290 -53.301392 14.197182 35733 49.702454 -53.490250 14.276093 35734 49.692902 -52.289520 14.647491 35735 54.295242 -54.423462 13.575073 35736 53.496216 -54.287735 13.885429 35737 11.954971 -54.753128 13.683815 35738 13.387817 -55.734406 13.170197 35739 48.176559 -52.459839 14.878517 35740 52.661530 -54.694992 13.848892 35741 52.556595 -53.948334 14.262459 35742 53.042435 -53.872437 14.150169 35743 12.505006 -55.841873 14.371704 35744 19.048286 -56.733704 13.470428 35745 20.133453 -56.286728 14.337624 35746 10.528725 -60.379257 12.688583 35747 37.033165 -56.244537 13.915611 35748 7.664367 -58.887817 12.984177 35749 8.965187 -58.664886 13.119095 35750 13.979347 -57.298843 14.128014 35751 16.200104 -58.154892 13.291077 35752 4.120850 -62.498871 12.928368 35753 41.993622 -59.868973 13.520607 35754 8.079971 -59.313736 13.554855 35755 10.649834 -61.465836 12.327148 35756 42.218842 -60.232361 14.437584 35757 47.875671 -61.055099 15.069046 35758 52.657135 -60.921158 14.344276 35759 51.451050 -60.950302 14.618134 35760 53.819061 -60.880569 13.990417 35761 4.340302 -62.600403 13.908592 35762 5.347084 -62.460724 14.485054 35763 4.600388 -63.275436 14.369820 35764 9.593704 -60.499649 13.460571 35765 8.544800 -63.375168 12.986046 35766 19.936478 -63.009171 12.988121 35767 20.225769 -62.426620 12.820290 35768 7.558991 -61.817764 14.008728 35769 10.627472 -65.547043 13.805016 35770 11.661194 -64.319000 13.482010 35771 10.678734 -64.339539 14.202644 35772 13.467621 -64.084778 12.737000 35773 18.592499 -65.375275 12.789017 35774 19.390549 -65.427673 12.473007 35775 19.114136 -63.985825 13.458969 35776 4.079842 -64.800583 13.262878 35777 12.766724 -65.084946 12.595093 35778 14.112358 -63.071182 13.248596 35779 17.456940 -64.327560 13.399055 35780 18.248924 -64.138016 13.808228 35781 18.115433 -64.866501 13.214058 35782 55.538345 -63.362320 13.685745 35783 55.195068 -64.459625 13.738876 35784 3.762772 -66.073120 12.430099 35785 12.796753 -66.088242 12.352295 35786 11.892487 -66.335373 12.991318 35787 13.279312 -67.149063 12.138763 35788 12.656136 -68.485031 13.085258 35789 13.863449 -66.053787 11.866669 35790 6.878738 -67.314072 12.746361 35791 51.852051 -67.877609 13.401817 35792 52.380692 -67.864319 14.316719 35793 53.877975 -66.507538 14.059105 35794 54.460968 -65.615402 15.251633 35795 4.409004 -68.294220 11.935188 35796 37.382233 -69.538834 13.051216 35797 37.496437 -69.886688 13.732040 35798 37.630211 -69.172043 13.618271 35799 38.093826 -68.761566 13.784172 35800 43.626068 -68.039993 14.133812 35801 43.800827 -68.717117 13.360847 35802 43.086609 -68.549667 13.622566 35803 45.541382 -68.024139 14.091881 35804 46.087082 -68.144135 14.429688 35805 46.421371 -68.350372 13.644417 35806 44.997070 -68.537277 13.421249 35807 46.310257 -68.856293 12.994026 35808 47.818207 -68.543518 14.014954 35809 49.201385 -68.757156 14.488586 35810 5.794685 -67.339294 12.890556 35811 6.849571 -66.845108 13.005463 35812 41.716492 -69.895508 12.537895 35813 42.657959 -70.542786 12.638344 35814 42.486633 -69.597900 13.178154 35815 44.424637 -69.549438 13.135986 35816 45.868073 -69.705307 12.978569 35817 44.766190 -67.894073 14.324860 35818 46.399689 -70.826538 13.074326 35819 15.477982 -70.946671 12.994194 35820 16.253113 -70.794907 12.038132 35821 43.685303 -70.395264 13.045410 35822 43.315094 -69.276337 13.323112 35823 45.229248 -70.861145 13.074341 35824 10.516083 -72.238739 14.136131 35825 10.461105 -71.790604 13.199051 35826 11.308937 -72.341187 12.531761 35827 48.244873 -71.353027 12.722092 35828 49.394348 -71.374176 12.375137 35829 5.840530 -72.246094 12.872116 35830 5.044693 -73.485397 12.091858 35831 9.892365 -71.721741 13.029579 35832 9.046921 -71.858795 13.204132 35833 8.039627 -72.959244 12.302084 35834 12.655183 -72.697388 12.947266 35835 11.780640 -72.650909 13.810890 35836 10.582237 -72.197861 12.169289 35837 13.605270 -72.757797 12.083000 35838 14.756668 -72.873688 12.079872 35839 15.866776 -72.720139 12.053238 35840 37.810303 -72.281616 13.623962 35841 37.821022 -71.002609 14.406654 35842 44.463058 -71.491974 12.797966 35843 47.249557 -71.380295 12.996748 35844 4.325188 -74.882767 12.348457 35845 8.161331 -74.554276 11.941910 35846 15.261337 -72.510330 13.095352 35847 45.398102 -72.254684 12.574936 35848 38.016388 -73.446320 13.349915 35849 46.538116 -72.048477 12.778305 35850 4.347855 -75.498627 13.728302 35851 4.315018 -76.149460 11.524368 35852 10.536232 -75.384705 12.308517 35853 37.929565 -74.369843 13.025337 35854 18.296692 -76.868103 11.907761 35855 19.042519 -76.996628 11.540970 35856 16.515442 -78.021240 14.829025 35857 16.862686 -78.819977 15.128159 35858 17.575333 -78.486893 14.335571 35859 18.731865 -77.602783 12.301323 35860 38.439552 -77.176239 12.456917 35861 9.265282 -77.052841 12.416664 35862 18.943359 -78.700012 12.169624 35863 38.631790 -77.774063 12.237297 35864 11.178131 -78.852615 13.057129 35865 10.708107 -78.222626 13.115501 35866 38.986778 -78.789978 12.500639 35867 11.106377 -79.893723 11.532257 35868 11.215424 -80.456772 11.097572 35869 15.718262 -80.827286 11.412941 35870 16.420670 -80.631439 11.899994 35871 39.298569 -80.922440 12.071877 35872 5.972328 -82.264481 11.222359 35873 5.806557 -81.292969 11.682388 35874 6.557129 -81.870651 12.516365 35875 15.953979 -80.717834 13.003891 35876 15.180573 -81.845245 12.598450 35877 18.381264 -80.168228 11.462944 35878 18.855286 -79.348114 12.334679 35879 11.502007 -79.772873 12.594849 35880 35.756706 -82.839066 11.908089 35881 41.009003 -82.304428 13.083214 35882 40.097290 -81.839676 12.486542 35883 7.853538 -84.529572 11.408165 35884 6.676064 -83.145950 11.727592 35885 7.350189 -83.876724 11.897820 35886 14.766563 -82.594376 13.403204 35887 36.946762 -84.548935 12.032295 35888 8.515701 -85.097443 11.760803 35889 8.231026 -85.779327 11.493584 35890 8.876091 -85.776703 12.145454 35891 13.660477 -84.239441 12.369072 35892 13.361787 -83.921661 12.442421 35893 40.377029 -84.210342 11.315933 35894 40.697372 -83.961182 12.710838 35895 7.392426 -86.534500 12.250664 35896 9.057213 -86.006470 12.633713 35897 8.907059 -86.217896 12.443970 35898 37.414452 -85.257629 11.742439 35899 37.875626 -85.709320 12.295494 35900 40.424896 -84.904053 13.692505 35901 6.522286 -87.617493 11.980141 35902 38.426842 -85.998810 12.085983 35903 39.064186 -85.935135 12.672897 35904 6.351898 -89.232498 11.160660 35905 6.315231 -88.804657 11.781631 35906 6.510170 -89.025665 12.593178 35907 6.641213 -87.544281 13.077484 35908 23.380249 -89.277847 12.587708 35909 22.803703 -87.826141 13.326706 35910 23.549164 -87.822586 12.521217 35911 6.737129 -90.347351 10.972412 35912 22.630447 -88.957153 13.752151 35913 25.175171 -89.348434 12.388733 35914 6.701798 -89.965332 11.863777 35915 7.217972 -91.142273 11.710213 35916 7.320480 -91.748428 10.928894 35917 23.662941 -90.813095 12.569992 35918 24.210869 -89.317657 11.998787 35919 14.656097 -92.589233 10.953712 35920 15.438263 -92.599747 10.806181 35921 14.933792 -91.861816 11.470901 35922 15.877182 -92.209473 11.816154 35923 15.579041 -91.522659 11.852913 35924 27.087463 -92.261780 11.458504 35925 34.005676 -90.968018 11.791595 35926 27.606903 -91.740494 12.689194 35927 27.658997 -93.952515 11.007111 35928 30.874931 -92.133530 13.465515 35929 32.200974 -92.383865 12.103844 35930 30.505341 -94.225586 11.896919 35931 15.591957 -93.483322 11.979446 35932 25.791901 -95.350662 12.873283 35933 25.662025 -94.127716 13.971008 35934 28.263092 -94.014954 11.893311 35935 27.912338 -92.965698 12.191895 35936 10.429123 -96.082565 10.627724 35937 12.315262 -95.359848 11.499001 35938 11.000534 -95.627625 11.788239 35939 11.795029 -95.567932 11.699028 35940 11.627190 -95.944122 11.037842 35941 14.962296 -98.781204 10.021408 35942 15.021156 -95.877487 11.520607 35943 20.105934 -97.486557 9.837471 35944 19.737839 -98.444641 10.285614 35945 14.995071 -99.369934 10.667290 35946 14.501190 -98.764908 12.001694 35947 15.581604 -99.873108 11.329544 35948 18.604889 -99.281479 10.549911 35949 20.219727 -99.208633 11.269997 35950 19.094315 -98.776825 10.437904 35951 19.131058 -99.047958 11.151405 35952 19.440979 -99.252655 12.571030 35953 17.738358 -100.007980 10.670593 35954 18.291313 -99.524368 11.659210 35955 21.432610 -99.593262 11.234032 35956 25.007751 -98.840759 11.393858 35957 15.943619 -100.318161 10.066719 35958 16.708191 -100.259781 10.701164 35959 23.910583 -99.648376 10.569389 35960 23.366531 -99.345108 11.636688 35961 24.357376 -99.248795 11.257698 35962 6.548828 64.238037 22.486397 35963 9.336884 64.262680 21.708733 35964 11.375793 63.510437 21.683121 35965 10.041656 63.635468 22.459702 35966 17.598434 62.817535 22.053810 35967 19.135849 62.741592 21.461395 35968 19.242676 62.791367 22.819405 35969 20.128922 62.268997 23.554253 35970 19.232742 62.623230 23.846909 35971 12.819099 61.773193 21.547821 35972 12.449600 63.017212 21.289253 35973 11.958458 62.720230 21.911140 35974 16.124832 62.119629 21.797302 35975 21.118927 61.689331 23.285393 35976 13.873154 60.585419 21.633659 35977 14.763580 61.176254 21.498665 35978 15.358856 61.451630 21.673950 35979 3.972611 60.472000 23.183060 35980 4.008232 59.263184 24.135910 35981 3.828468 58.899429 23.146706 35982 12.478317 60.300217 21.688644 35983 13.093414 59.390305 21.872459 35984 14.844193 60.868698 22.334732 35985 11.551132 59.185135 21.970367 35986 12.365676 58.147308 22.200775 35987 23.711426 59.860947 22.380371 35988 5.331604 57.171387 21.277840 35989 11.412224 58.254639 21.809792 35990 10.289902 58.117889 22.478600 35991 11.382912 57.780151 21.846230 35992 27.908127 56.520935 22.682686 35993 25.754593 58.041245 22.662956 35994 3.714981 56.658020 22.659248 35995 30.896660 54.208771 21.322975 35996 31.115959 53.246277 20.973137 35997 29.960991 54.268356 22.048508 35998 29.433090 54.233597 22.622604 35999 28.878265 53.019501 22.093552 36000 30.250732 53.257233 21.532196 36001 4.725487 51.472107 21.471428 36002 3.640907 52.294434 21.867310 36003 4.274063 51.477524 22.251205 36004 4.995445 51.175385 20.545052 36005 27.791985 51.864410 21.332298 36006 5.695816 50.641083 20.966026 36007 25.576012 51.332962 21.922653 36008 8.002586 48.282104 20.545601 36009 8.031906 49.068253 21.668350 36010 8.784431 48.623932 21.918777 36011 8.746872 48.224701 21.159668 36012 35.414185 47.384705 21.468529 36013 5.933083 45.902374 22.129936 36014 5.188950 46.510040 21.393913 36015 8.516861 47.512207 20.690247 36016 22.493256 47.673828 21.216698 36017 27.000633 47.327103 21.018478 36018 28.477112 47.398026 21.119514 36019 35.720840 46.884689 21.360718 36020 3.167420 46.262726 20.633583 36021 7.744628 46.408371 20.830544 36022 9.001495 47.482239 21.105034 36023 8.583160 46.621017 20.997185 36024 35.811775 46.605042 21.349075 36025 35.876671 43.756699 21.722412 36026 35.935730 44.552185 22.213326 36027 36.085098 45.704819 22.364876 36028 36.168076 46.948547 23.011505 36029 35.797943 46.762238 21.922653 36030 35.758606 46.077759 21.403496 36031 4.566223 42.171280 20.639076 36032 3.170754 43.829865 23.201218 36033 5.893128 41.314484 20.750298 36034 5.650566 41.963455 19.871590 36035 42.447510 43.823166 22.214218 36036 41.055496 44.042542 22.327255 36037 41.136505 44.948883 23.562111 36038 40.249115 45.099548 23.172173 36039 6.987206 40.510162 21.126724 36040 8.493851 40.507782 20.165092 36041 40.118561 42.847870 21.228355 36042 43.195160 43.441299 21.505661 36043 9.992004 39.654938 19.966980 36044 9.525925 40.352829 19.693550 36045 38.274841 42.179535 21.137436 36046 38.288589 43.078720 22.299759 36047 37.048027 42.904419 22.415359 36048 37.348694 42.417664 21.953392 36049 39.537201 44.115952 22.498779 36050 9.182922 39.294846 21.359131 36051 10.278061 38.809052 20.936325 36052 11.354218 38.459167 19.831398 36053 6.809013 39.967346 22.255577 36054 7.866127 39.597961 22.085289 36055 11.239212 37.983902 21.033112 36056 45.857910 41.024811 22.359261 36057 46.174011 39.812958 22.245102 36058 45.094620 37.716003 22.168747 36059 44.290955 35.935928 23.002594 36060 45.304108 37.475296 23.784904 36061 7.084503 34.960251 20.388985 36062 13.626816 35.522202 21.941452 36063 13.641777 34.800217 21.817245 36064 40.175629 34.157532 20.751930 36065 47.232361 34.406540 20.048439 36066 12.912354 32.978516 19.876694 36067 13.572464 33.191895 21.292603 36068 39.139130 33.258606 20.651085 36069 41.651001 34.258026 21.516365 36070 47.693954 33.767151 20.759300 36071 48.471237 33.548767 21.137451 36072 9.943344 33.398376 20.122253 36073 35.640198 31.894455 19.607361 36074 36.278152 32.475845 19.767464 36075 46.857376 33.446350 20.198769 36076 11.989761 32.064728 20.265121 36077 13.012589 32.026276 20.743317 36078 36.184799 31.808167 20.006798 36079 38.445702 32.120285 20.823334 36080 37.120987 31.985596 20.405121 36081 46.514053 31.989380 20.383247 36082 2.590164 31.641602 20.533463 36083 2.634400 30.765930 20.587120 36084 36.536911 30.964706 20.323807 36085 47.278198 30.903412 21.221100 36086 51.228394 30.440063 20.734764 36087 46.097427 27.798935 21.774979 36088 42.763687 28.023773 19.918533 36089 46.936310 28.661621 21.798271 36090 36.642227 29.905533 19.916618 36091 49.553101 28.817368 21.222214 36092 50.377609 28.856094 20.319122 36093 4.911804 27.775177 19.208412 36094 39.348572 27.403671 20.684494 36095 38.869507 27.799911 21.843567 36096 40.605148 26.133362 21.509117 36097 42.262634 26.880005 20.752419 36098 42.449249 26.201508 21.396622 36099 40.805145 24.924942 22.434776 36100 39.840637 25.162613 22.790344 36101 48.614624 27.597946 21.009491 36102 5.086617 26.122849 20.178482 36103 5.284523 24.907532 19.382339 36104 48.052841 26.511398 21.039825 36105 49.070816 28.168121 21.079857 36106 3.112987 19.060822 15.608685 36107 48.275223 26.001221 20.543152 36108 48.408691 25.695068 20.384293 36109 48.866867 25.366837 20.275566 36110 52.746063 25.656052 20.451759 36111 52.215088 26.135620 22.079880 36112 51.190460 25.614700 21.434280 36113 53.228714 25.987152 21.866432 36114 3.331298 20.104418 16.050468 36115 3.505449 19.953362 16.814571 36116 4.739571 23.204149 19.001295 36117 5.574501 24.047607 20.146255 36118 4.999863 23.111725 20.009628 36119 49.629684 25.111298 20.310371 36120 4.679087 22.125801 19.586506 36121 56.362030 23.044998 20.225372 36122 55.749420 23.564301 21.498802 36123 56.060822 23.416916 20.872269 36124 56.344116 22.303986 21.137253 36125 56.999237 20.612854 21.032303 36126 47.611145 18.908813 18.714722 36127 48.356445 19.279129 18.748657 36128 38.288498 16.911133 18.313187 36129 2.651974 13.144528 15.717178 36130 2.744520 12.689154 16.717937 36131 2.395025 10.975759 14.902567 36132 36.451477 16.066895 18.296280 36133 33.226387 15.689896 18.267075 36134 2.216344 9.537431 13.979885 36135 46.783859 13.132797 19.386955 36136 47.738327 13.834808 20.667252 36137 56.195068 13.889740 19.731590 36138 57.319290 14.496933 19.625565 36139 57.696991 15.174072 20.691589 36140 56.744934 14.015076 19.622963 36141 45.864990 11.567841 20.308792 36142 50.014313 11.118729 19.399063 36143 54.127029 10.704697 19.304817 36144 45.922852 12.301010 20.408714 36145 49.388992 11.067413 20.856003 36146 48.808960 11.005493 20.168159 36147 55.120804 10.300644 19.285851 36148 54.256332 10.101837 20.849403 36149 54.358551 8.528961 19.777733 36150 54.862000 9.283752 20.209152 36151 55.214783 9.778229 19.744904 36152 51.974640 7.379517 19.260109 36153 53.204376 7.827789 19.018677 36154 58.656296 6.701019 19.666870 36155 57.417404 6.008194 18.908401 36156 46.338333 4.592064 19.439140 36157 46.192108 5.305664 20.069756 36158 47.072525 5.393379 19.259499 36159 55.340088 4.897461 18.761696 36160 56.297012 5.486130 19.322136 36161 47.005890 3.606148 18.811295 36162 54.396072 4.435104 19.175041 36163 53.464630 3.774353 18.560005 36164 46.869202 4.623062 18.877556 36165 52.739594 3.473358 19.052063 36166 60.105072 2.932541 19.115555 36167 33.922829 0.823868 18.062256 36168 35.063805 1.332794 18.852280 36169 36.624428 1.030380 18.938545 36170 47.081451 2.565109 19.444679 36171 46.219574 3.352417 19.752701 36172 47.919067 2.660339 18.690826 36173 48.882141 2.103729 19.257156 36174 47.827667 1.996170 19.696144 36175 59.638062 3.369011 20.313042 36176 59.441757 2.206757 19.508072 36177 34.220108 1.292862 18.495850 36178 34.549744 0.455444 18.721252 36179 37.659973 0.885986 18.806282 36180 39.271164 -1.160004 18.413155 36181 58.927933 1.095749 19.629562 36182 59.518768 0.365692 19.475731 36183 40.327118 -1.081421 17.515579 36184 38.239685 -0.217148 18.840103 36185 60.150452 0.114075 19.138145 36186 61.276138 -0.716782 18.928383 36187 34.720215 -1.818970 17.920120 36188 38.830971 -2.343170 18.760628 36189 2.206570 -5.281179 20.026648 36190 2.172958 -5.517420 19.485443 36191 2.119551 -4.384561 18.995039 36192 34.399597 -3.445831 17.861916 36193 35.484200 -2.560104 19.053116 36194 38.011627 -1.621506 19.183289 36195 53.119019 -3.643967 19.333061 36196 54.592621 -3.609894 19.172943 36197 33.716110 -4.753525 17.557762 36198 34.318970 -4.495483 18.234032 36199 34.825607 -3.772675 18.687813 36200 54.960327 -4.752258 19.438873 36201 37.774544 -3.995682 18.279259 36202 57.649719 -6.609528 18.882599 36203 58.595932 -6.758224 18.324875 36204 56.664261 -5.503357 18.908272 36205 34.259781 -5.750458 18.039505 36206 36.474869 -5.038925 18.413673 36207 35.494202 -6.360733 17.764168 36208 35.595322 -5.388519 18.275764 36209 35.917313 -4.519943 19.024742 36210 48.398041 -5.430313 19.176430 36211 47.074509 -5.843369 18.928825 36212 49.645813 -5.676529 20.345741 36213 49.703110 -5.158951 19.548660 36214 48.665955 -5.871094 20.152908 36215 49.740326 -4.719208 18.286156 36216 62.417862 -4.544693 19.051529 36217 62.465881 -5.715851 18.357040 36218 33.261108 -6.803574 18.019897 36219 34.745850 -6.654846 18.029182 36220 34.138382 -6.807861 18.217049 36221 45.523010 -6.252304 18.442802 36222 45.112061 -6.414581 19.943710 36223 46.126526 -6.280457 19.852539 36224 62.909515 -5.697174 19.582161 36225 62.771637 -5.913071 18.866470 36226 62.967575 -6.803055 19.434952 36227 32.262253 -7.483612 17.561310 36228 35.950287 -7.418396 17.655228 36229 35.231842 -6.960938 17.880928 36230 34.947189 -7.588028 18.505257 36231 39.850060 -7.500793 17.874687 36232 38.589767 -8.049088 17.857742 36233 44.120422 -6.576706 18.163811 36234 53.533157 -7.290771 18.160980 36235 59.461151 -7.521103 18.155113 36236 60.313629 -7.991486 17.955864 36237 31.451401 -8.757660 16.852310 36238 31.767542 -8.624283 17.280922 36239 36.331749 -8.268921 18.365570 36240 50.965332 -8.556686 17.899811 36241 52.627167 -7.038818 19.305435 36242 55.813217 -7.277740 18.273666 36243 57.093369 -6.828751 19.263573 36244 57.378189 -7.303955 18.868668 36245 57.177216 -7.805878 18.080338 36246 37.065720 -8.517426 18.071022 36247 47.671387 -9.737427 18.081886 36248 49.603241 -9.070343 18.001358 36249 2.284061 -7.845549 18.312740 36250 2.374962 -8.931610 17.224319 36251 2.397548 -8.895802 16.097805 36252 2.464589 -9.539073 16.317635 36253 2.548947 -10.196772 16.566797 36254 32.034500 -9.760376 17.584496 36255 63.618973 -10.762436 18.321030 36256 2.607677 -10.781379 16.973314 36257 2.454184 -9.676798 17.938213 36258 3.290057 -15.250456 16.789629 36259 32.478493 -10.669464 17.547501 36260 33.461189 -11.369858 17.344315 36261 33.259308 -11.699753 18.695007 36262 32.840393 -11.127426 18.361992 36263 36.058884 -12.845840 17.384911 36264 33.998482 -12.254013 18.546638 36265 35.031113 -13.097946 18.397713 36266 43.756348 -12.524460 17.981461 36267 64.061600 -12.366028 18.305260 36268 63.968597 -11.603561 18.249626 36269 36.527458 -13.855347 17.665344 36270 35.873154 -13.300095 18.059151 36271 37.047455 -13.341934 17.044907 36272 44.545807 -13.551559 17.900604 36273 50.208633 -13.084641 17.857849 36274 52.968658 -13.607574 18.148193 36275 63.894196 -13.213303 18.064262 36276 37.437607 -14.159348 16.712914 36277 46.216599 -13.993088 17.450119 36278 45.523651 -14.284470 17.896255 36279 46.425430 -14.407867 17.896049 36280 47.137985 -13.934708 17.649826 36281 47.141144 -14.613586 18.623032 36282 48.378601 -14.340363 19.565582 36283 48.654343 -13.720932 18.280258 36284 63.750229 -13.889908 18.141998 36285 36.860901 -14.882294 17.086502 36286 36.360771 -15.735352 16.923294 36287 58.760178 -15.666428 17.753799 36288 60.106674 -14.503647 18.896538 36289 61.017487 -14.548477 19.341179 36290 61.124268 -14.645584 18.196388 36291 63.122284 -14.681458 17.990372 36292 63.514038 -14.379761 18.201820 36293 3.664251 -17.020977 16.447800 36294 51.928848 -14.196396 19.229408 36295 52.556122 -14.126724 18.555275 36296 52.285995 -13.497726 18.696854 36297 34.558746 -16.063385 18.667976 36298 58.323868 -16.391525 17.889473 36299 58.929092 -15.004181 18.904938 36300 58.260910 -16.113480 18.744881 36301 57.989731 -15.459717 19.812401 36302 32.463120 -19.089081 18.149971 36303 32.965347 -18.175201 18.318314 36304 33.206406 -18.609741 17.289490 36305 49.221680 -19.040237 17.455811 36306 57.912048 -19.111465 18.252602 36307 4.663551 -20.385439 15.318777 36308 48.522476 -19.009628 18.402435 36309 48.419113 -20.089951 17.372406 36310 58.003693 -20.910156 18.123611 36311 58.368683 -20.153229 18.654510 36312 5.579572 -22.606140 14.322504 36313 4.816916 -21.238617 15.597319 36314 47.327393 -20.221481 18.391312 36315 47.627731 -21.371277 17.463875 36316 49.013611 -22.195404 17.789963 36317 57.427307 -20.368668 17.585342 36318 48.224106 -23.331161 18.612465 36319 47.101776 -22.989731 17.602287 36320 47.099579 -24.528091 18.564049 36321 51.121567 -21.782455 18.224510 36322 57.923538 -21.899979 18.399689 36323 58.353729 -21.596420 18.323875 36324 57.156998 -21.666809 18.251389 36325 58.874786 -21.203918 18.744843 36326 30.693222 -22.668365 17.171555 36327 31.202789 -21.557938 17.609070 36328 36.161613 -22.866074 16.408966 36329 46.294540 -22.172165 17.542831 36330 48.724777 -23.396667 19.611481 36331 49.426331 -22.750565 19.115273 36332 5.586340 -24.135645 15.689739 36333 5.255458 -23.929565 16.582376 36334 5.877441 -25.312248 15.743925 36335 5.758609 -23.663273 14.792059 36336 5.239693 -23.207661 16.041952 36337 34.348137 -25.113708 17.257957 36338 45.497131 -22.573135 17.644997 36339 45.794525 -23.046768 17.420258 36340 44.835541 -22.830078 18.137772 36341 45.631226 -23.844360 17.732300 36342 6.445391 -25.600521 14.538338 36343 6.363103 -24.819088 14.129528 36344 6.499970 -26.316393 14.874067 36345 5.914247 -24.530867 15.057074 36346 29.567062 -25.029205 17.572098 36347 29.881729 -25.692291 16.343727 36348 30.107216 -26.083160 16.516258 36349 29.662323 -25.727600 16.916245 36350 30.744881 -26.428024 17.182381 36351 7.015888 -27.271713 14.374449 36352 7.720781 -28.047585 13.570778 36353 8.323237 -28.561272 12.870335 36354 36.239777 -28.235901 17.689270 36355 36.070251 -27.509811 18.103378 36356 37.082550 -27.775589 17.340485 36357 8.095284 -28.773153 13.330168 36358 36.047180 -29.629517 16.395828 36359 35.172638 -29.998062 17.456001 36360 36.181786 -28.878693 17.184387 36361 62.949966 -30.328400 17.723885 36362 62.257416 -30.228928 17.805771 36363 62.550217 -30.079437 17.205353 36364 5.189361 -32.654594 19.357332 36365 5.597900 -32.227547 18.161758 36366 5.271085 -31.981640 18.927799 36367 5.917986 -32.337341 17.522610 36368 6.027092 -31.581648 17.216644 36369 6.577662 -32.040394 16.348555 36370 8.784157 -30.149609 12.885525 36371 9.220246 -30.818823 12.540037 36372 9.797995 -31.111458 11.928329 36373 35.159027 -31.401215 17.443100 36374 34.705444 -30.838150 18.117271 36375 62.646088 -30.672333 18.440407 36376 61.609634 -30.660645 18.609268 36377 63.398712 -30.504379 16.848839 36378 8.518087 -32.548115 13.790684 36379 8.359960 -31.954069 13.893829 36380 9.738841 -32.539692 12.382460 36381 9.425481 -31.666052 12.540152 36382 10.109360 -31.723251 11.758959 36383 8.640301 -30.988255 13.333117 36384 35.945717 -32.517914 16.941139 36385 51.876862 -32.529785 16.406685 36386 10.543219 -32.454529 11.474985 36387 37.192154 -34.285706 17.623352 36388 37.591919 -33.892746 19.106262 36389 37.665573 -32.804718 18.790451 36390 50.085236 -32.745132 16.924477 36391 36.478363 -32.537033 18.449127 36392 48.393539 -33.265411 17.286179 36393 49.416840 -33.520111 18.582802 36394 50.522598 -33.383514 18.298073 36395 51.748016 -33.842010 19.140617 36396 50.406189 -33.948318 19.733871 36397 51.278412 -33.214844 17.558647 36398 63.272537 -33.247482 16.825073 36399 37.224152 -34.387741 16.398865 36400 52.479126 -33.604630 17.437889 36401 53.376328 -33.819229 16.747925 36402 54.189545 -33.993546 16.819412 36403 54.497589 -34.133392 17.511742 36404 55.340851 -33.443497 18.445595 36405 61.529663 -34.939301 16.986847 36406 62.084137 -34.781250 16.637833 36407 40.510025 -35.201370 16.220413 36408 41.750854 -35.542847 16.966652 36409 43.807877 -35.298309 19.420212 36410 44.550476 -34.844467 17.971153 36411 45.625107 -34.554489 19.320343 36412 40.514603 -35.874268 17.217171 36413 44.444580 -34.718948 16.816360 36414 43.163788 -35.050323 16.737686 36415 60.688797 -36.427216 17.273491 36416 60.805176 -35.627243 17.265358 36417 5.405107 -34.716038 19.542120 36418 6.082702 -36.099747 17.994366 36419 60.740234 -37.120651 16.584137 36420 8.129471 -40.512192 14.694252 36421 7.902809 -40.653198 14.948280 36422 4.550087 -42.900436 14.531616 36423 5.636360 -41.996613 14.925667 36424 8.042648 -40.833176 14.717285 36425 54.141388 -43.156708 16.214394 36426 53.672623 -43.258163 16.921532 36427 54.010498 -42.456680 16.720551 36428 55.017426 -42.758453 15.916901 36429 57.180161 -42.230789 16.757324 36430 57.737946 -42.866516 16.216240 36431 42.839996 -43.333191 15.445351 36432 44.786591 -43.991150 16.268196 36433 57.740219 -43.633270 15.554329 36434 4.699471 -44.831909 14.802338 36435 42.849060 -44.002502 16.617088 36436 41.751129 -44.377975 15.829819 36437 54.120804 -43.910400 16.338737 36438 5.043465 -45.770935 14.423401 36439 5.445305 -45.518417 15.697426 36440 43.842453 -43.406143 15.922920 36441 47.354645 -44.932938 15.574219 36442 61.196503 -44.452255 16.762733 36443 5.532524 -46.343018 14.841209 36444 41.473114 -45.928482 16.172256 36445 48.435562 -45.580231 15.515221 36446 55.008743 -46.150604 15.580078 36447 59.942520 -44.024124 16.994019 36448 60.786148 -43.925293 18.000923 36449 5.910851 -46.920792 14.407837 36450 6.455711 -47.633301 14.561516 36451 50.740234 -47.076706 15.352295 36452 49.176376 -46.552200 16.312988 36453 54.950500 -47.018158 15.478233 36454 55.196136 -46.880936 15.981934 36455 55.326904 -46.216965 16.766708 36456 7.044998 -48.704071 14.466637 36457 52.350357 -47.677231 15.756882 36458 53.332718 -47.811920 15.814674 36459 53.227936 -47.743530 16.605324 36460 54.339478 -48.002289 17.298431 36461 54.984772 -47.309753 15.798615 36462 55.152863 -47.455002 16.576668 36463 53.350739 -47.907150 15.401512 36464 47.063309 -50.094391 14.992401 36465 48.015457 -51.142319 15.057655 36466 46.699677 -50.633850 15.336845 36467 8.514359 -51.155365 15.199852 36468 7.882667 -51.986908 14.838264 36469 8.331359 -52.339951 15.469254 36470 7.470123 -51.308182 14.852882 36471 6.670021 -51.692825 15.554672 36472 6.010697 -52.399078 16.396484 36473 6.780830 -53.184799 15.414780 36474 7.645263 -50.048615 14.746956 36475 7.393524 -51.985809 14.793823 36476 41.033340 -52.413788 15.314812 36477 48.968109 -52.067215 14.934204 36478 7.469498 -52.507767 15.006493 36479 7.734085 -53.287216 15.267151 36480 11.706863 -52.149704 14.605629 36481 11.935883 -53.362549 14.957611 36482 36.222679 -55.066360 14.862854 36483 35.863708 -54.980927 15.830704 36484 36.251144 -54.001602 15.247498 36485 38.385849 -52.952469 14.745216 36486 40.390411 -54.061142 15.701378 36487 41.129684 -53.724350 16.200493 36488 11.408592 -54.167786 13.940247 36489 48.422913 -51.862717 15.181084 36490 18.803047 -55.701569 14.535919 36491 37.066879 -53.229279 14.733391 36492 36.549973 -56.070511 14.743736 36493 12.296280 -54.739441 15.124893 36494 14.240143 -57.132080 15.001709 36495 17.704559 -56.294174 14.576759 36496 17.002060 -57.181870 14.290222 36497 16.975914 -56.305679 15.253944 36498 19.897675 -54.877869 15.438393 36499 37.058876 -56.891464 14.534042 36500 9.407257 -59.551163 13.454628 36501 13.317238 -56.713409 14.092896 36502 16.048088 -57.747879 14.005768 36503 15.314934 -57.194565 14.995613 36504 6.856430 -60.595947 13.957108 36505 7.690353 -60.197250 13.868965 36506 19.665329 -59.978607 15.206886 36507 38.748474 -59.478119 15.280273 36508 39.106842 -59.968018 16.026878 36509 20.294151 -61.826279 13.439774 36510 42.792374 -60.602081 15.425888 36511 45.423065 -60.912445 15.339279 36512 46.271561 -61.025833 15.697052 36513 46.922638 -60.923538 15.131554 36514 11.692031 -63.191772 14.020615 36515 11.133041 -63.421844 14.276352 36516 14.309578 -62.062744 13.999786 36517 15.642891 -62.952148 13.478920 36518 15.344589 -61.742737 14.521103 36519 13.105331 -61.841965 14.560875 36520 13.524216 -62.402802 13.742775 36521 16.938171 -62.078751 14.629066 36522 54.747192 -61.558121 14.604279 36523 55.446991 -62.423950 14.448875 36524 4.076401 -63.507019 13.632980 36525 12.678116 -63.099838 13.622269 36526 15.817261 -60.818924 16.000473 36527 14.277451 -61.325531 15.107323 36528 7.280388 -64.231583 13.613304 36529 6.646431 -66.000320 13.468735 36530 6.057922 -65.018570 14.104607 36531 12.586243 -64.101044 13.063019 36532 19.757080 -61.960175 14.049210 36533 16.931427 -63.260498 13.812401 36534 55.450943 -63.415268 14.561073 36535 55.101959 -64.401840 14.760170 36536 11.478165 -67.649307 13.347221 36537 9.544319 -66.381912 14.678986 36538 9.210075 -67.660599 14.922447 36539 10.044022 -67.543472 14.158463 36540 4.546410 -65.996323 13.472580 36541 4.411995 -67.079620 12.728348 36542 10.671478 -66.900146 13.658684 36543 42.613571 -68.217255 15.287445 36544 42.365433 -68.278412 14.183861 36545 42.484283 -68.835205 13.560822 36546 53.632294 -67.188004 16.293922 36547 53.948608 -66.379852 16.306259 36548 53.253342 -67.383194 15.379005 36549 10.789780 -67.890030 13.776649 36550 11.426575 -68.492096 13.685654 36551 39.781998 -67.939285 14.670143 36552 40.343597 -68.069290 14.552681 36553 38.874817 -68.585861 14.556946 36554 41.163635 -68.288010 15.112053 36555 46.143234 -68.384262 15.205620 36556 46.778351 -68.395554 14.502579 36557 50.099197 -68.685638 14.284592 36558 50.972900 -68.470871 14.077202 36559 51.780899 -68.190475 14.245728 36560 51.839935 -68.439774 15.103065 36561 14.695969 -71.952103 14.466087 36562 15.177399 -71.837097 13.798645 36563 37.972855 -69.556839 14.576874 36564 8.133850 -71.848434 13.557304 36565 6.954346 -71.978699 13.378258 36566 10.456467 -71.905823 12.591133 36567 15.724060 -71.781708 13.237442 36568 13.888321 -72.868057 13.166916 36569 47.731720 -72.121490 12.764992 36570 14.372070 -72.710754 14.239288 36571 38.189651 -74.514801 13.732880 36572 8.912529 -76.307831 12.646149 36573 9.125618 -75.848251 13.488838 36574 10.534683 -75.888657 13.354256 36575 38.199738 -75.355988 13.436707 36576 4.540550 -76.535660 12.441437 36577 11.952423 -76.341232 13.317871 36578 39.005493 -75.542389 14.115021 36579 39.099106 -74.428955 14.562920 36580 10.209259 -77.878738 12.699913 36581 18.032425 -77.388931 12.830452 36582 38.713379 -77.682724 12.969421 36583 9.857063 -77.314392 12.934578 36584 18.307381 -78.301514 13.285904 36585 18.543839 -79.231522 12.932312 36586 39.497490 -77.164566 13.781181 36587 39.965286 -76.155548 14.365387 36588 6.053467 -80.335495 12.437111 36589 6.608086 -79.552338 13.249741 36590 7.073883 -80.713837 13.353447 36591 12.532898 -81.103470 13.417107 36592 11.957985 -79.435135 13.845345 36593 17.835083 -79.679337 13.552574 36594 17.434280 -80.161346 12.795601 36595 39.257881 -78.340210 13.308487 36596 40.396301 -79.440765 13.408005 36597 16.744331 -80.496933 12.632912 36598 39.589218 -81.009689 12.513588 36599 43.317322 -78.551468 14.411964 36600 41.164093 -76.868805 14.228653 36601 35.210587 -82.347443 13.074471 36602 36.459320 -83.324173 13.262785 36603 40.332245 -81.170334 12.995285 36604 41.267349 -80.964111 13.535095 36605 13.039856 -83.335800 12.394829 36606 34.031395 -82.289886 12.882156 36607 42.214294 -81.447678 14.116318 36608 8.049820 -84.330078 12.532318 36609 14.377136 -81.678604 14.372620 36610 33.489304 -84.161697 13.487236 36611 37.430801 -84.888199 13.173447 36612 8.824081 -85.387329 13.325653 36613 33.883286 -83.021835 13.942757 36614 37.141121 -83.874039 14.390961 36615 36.784042 -83.091202 14.805923 36616 37.095261 -83.374344 15.389290 36617 37.744659 -84.642059 14.828331 36618 7.244904 -86.685410 13.038879 36619 7.941551 -86.536194 13.072701 36620 8.410805 -86.256302 12.338501 36621 34.515228 -86.460144 13.794823 36622 34.066269 -85.212738 14.271698 36623 37.895844 -85.630157 13.131561 36624 23.935936 -87.046051 12.663147 36625 24.568832 -87.246262 12.881004 36626 24.053619 -87.567459 12.427376 36627 38.420578 -85.933426 13.115768 36628 23.476715 -86.744873 13.032990 36629 24.261719 -88.413818 12.356857 36630 6.684815 -89.206177 13.725548 36631 6.530457 -87.765961 14.259720 36632 35.114189 -88.322144 12.546211 36633 15.847366 -90.794067 13.062599 36634 14.888214 -91.002838 12.428078 36635 15.103165 -90.127487 13.444580 36636 24.121208 -92.086349 12.418289 36637 26.271622 -90.139862 12.649338 36638 13.920197 -90.915268 13.085098 36639 14.608429 -90.288315 13.224243 36640 12.801208 -91.897171 13.073471 36641 16.035248 -91.509247 12.377228 36642 35.006477 -87.797440 13.600487 36643 34.592773 -89.268021 13.046509 36644 8.140495 -92.385101 11.934128 36645 7.827255 -90.968460 14.736679 36646 9.287216 -91.816803 14.189568 36647 8.713806 -92.090652 13.159370 36648 24.324402 -92.792984 12.303528 36649 13.258026 -94.639450 11.047386 36650 24.587372 -93.249008 12.108627 36651 9.038345 -93.059875 12.553452 36652 10.157410 -93.722061 12.793716 36653 9.822311 -94.786057 12.221588 36654 9.484093 -94.891785 11.625214 36655 28.876625 -94.481659 12.141899 36656 9.947464 -95.515976 11.615768 36657 10.381409 -95.878815 11.515671 36658 14.765380 -95.199860 12.393692 36659 14.647438 -96.110474 12.062378 36660 29.217148 -94.977982 11.720686 36661 29.763336 -94.942078 11.768120 36662 33.059685 -91.374557 12.306580 36663 14.710068 -96.688171 11.517380 36664 14.160369 -96.882889 12.529541 36665 15.180115 -99.561050 12.531242 36666 25.367584 -98.149658 11.901764 36667 24.465561 -98.496552 12.279587 36668 16.847717 -99.881760 12.025787 36669 15.723770 -99.681229 13.245277 36670 21.595505 -99.492523 12.563034 36671 22.315536 -99.660751 11.604942 36672 5.496208 63.451309 23.187813 36673 8.787292 64.383499 22.319016 36674 6.622795 63.079834 23.730637 36675 8.651100 63.986450 23.019867 36676 4.037247 61.842621 22.659210 36677 4.923454 63.659668 22.744370 36678 11.249016 62.999603 22.314964 36679 11.416756 61.938004 22.295296 36680 10.833832 62.819916 22.639236 36681 12.061234 61.071671 21.895554 36682 16.384216 62.389633 22.846481 36683 11.328171 60.518753 22.173462 36684 21.985573 61.432800 22.736046 36685 22.497581 61.160583 22.633804 36686 22.502373 60.850204 23.014763 36687 3.905609 59.672852 22.448898 36688 9.784027 60.019806 22.937607 36689 10.495522 61.192612 22.717918 36690 15.566643 61.619019 22.422882 36691 9.678452 61.297333 23.165382 36692 14.121582 59.916870 22.337975 36693 7.680549 60.113602 24.188194 36694 8.644501 61.089447 23.694366 36695 24.926559 57.992767 23.678772 36696 26.514755 57.543427 22.703522 36697 11.343018 57.096130 22.247452 36698 10.304260 56.629639 22.716629 36699 13.649765 59.326157 22.733505 36700 18.798935 56.819427 22.455627 36701 18.803192 57.180893 22.716438 36702 19.370537 56.745270 22.816597 36703 18.192520 57.455292 23.201584 36704 18.459984 56.475952 22.560440 36705 29.175949 55.261169 22.609840 36706 28.356827 55.926483 23.500916 36707 28.962158 55.117950 23.453590 36708 3.761490 57.901031 23.237068 36709 3.648644 57.733490 23.851936 36710 11.147132 56.121399 22.817596 36711 10.169128 55.700836 23.335121 36712 17.859390 56.420425 22.816925 36713 17.898529 55.373749 22.701775 36714 19.280510 55.649689 22.764648 36715 3.138985 54.419434 21.756935 36716 17.456177 56.531189 23.477180 36717 17.206131 55.401825 23.480278 36718 17.906174 52.306442 22.507675 36719 18.738800 53.135101 22.442139 36720 18.768387 52.233871 22.215851 36721 19.321091 54.385132 22.744370 36722 17.481598 53.475418 23.085213 36723 17.305603 54.533600 22.998627 36724 17.920273 54.163193 22.540993 36725 20.701920 52.073730 22.851990 36726 20.551788 53.025726 23.053627 36727 21.558029 51.791077 23.042458 36728 17.693436 52.422592 24.077972 36729 17.669174 53.529236 24.453926 36730 19.714073 50.293243 22.058167 36731 20.671143 51.087402 22.497726 36732 20.750648 49.690659 22.083633 36733 28.898331 54.186813 23.150085 36734 27.872330 53.866547 23.718895 36735 28.627426 54.595383 23.735168 36736 5.209587 50.910736 21.977676 36737 17.501221 51.302032 22.768707 36738 18.467697 49.432526 22.036179 36739 18.674225 51.197510 22.165855 36740 19.758644 51.233139 22.307358 36741 27.518517 52.250580 22.151978 36742 26.590096 52.226288 22.614319 36743 6.235069 50.296570 21.569878 36744 17.685921 50.325714 22.331482 36745 17.202408 50.343750 22.946770 36746 24.449326 51.204376 22.258614 36747 23.361458 51.026382 22.495148 36748 6.929344 49.792709 21.812958 36749 19.672501 48.820496 21.853302 36750 32.224808 50.000305 22.315536 36751 33.603867 50.473236 23.606102 36752 32.776718 50.368271 22.727516 36753 34.583305 49.431671 22.656380 36754 9.221390 47.905991 21.856453 36755 17.584030 49.399628 22.944260 36756 21.387611 48.134857 21.601936 36757 20.468323 46.020828 21.734032 36758 19.110313 47.044586 22.094131 36759 35.318649 48.759155 23.088821 36760 9.359207 47.073685 21.440697 36761 9.653687 47.275604 21.907188 36762 9.721848 47.263260 22.732895 36763 18.691544 48.198669 21.926674 36764 18.192841 48.103485 22.440773 36765 23.904137 46.984833 21.386665 36766 25.625977 46.531769 22.123360 36767 24.539505 46.624222 21.877579 36768 26.429047 47.486053 21.533310 36769 27.332809 47.439590 21.845757 36770 28.393082 47.412781 22.369560 36771 30.182617 48.581604 22.734467 36772 29.272064 48.009445 22.107445 36773 35.558807 47.709778 22.523415 36774 3.584938 45.756714 22.003227 36775 4.070114 46.562042 21.136208 36776 4.591095 46.041046 22.197235 36777 9.183364 46.268372 21.480423 36778 9.635941 46.590576 21.965393 36779 18.480988 47.204193 22.980492 36780 22.701797 46.729706 21.531197 36781 24.140884 45.931763 22.027084 36782 22.378441 45.073700 21.731949 36783 26.411751 47.174850 21.965912 36784 7.141792 45.614471 21.993408 36785 6.600472 45.581161 22.494621 36786 7.830093 45.918915 21.250099 36787 8.596802 45.803467 21.437065 36788 19.308311 45.925919 22.064705 36789 8.064590 45.428284 21.888466 36790 9.099335 45.471252 22.343803 36791 19.733307 45.237228 22.347321 36792 20.632126 44.812958 23.499283 36793 19.582779 45.635620 23.159225 36794 20.638588 44.794250 21.859184 36795 21.407669 43.793793 21.986229 36796 23.409317 43.344940 21.851532 36797 43.193878 43.751953 22.243210 36798 43.558121 43.587708 22.229431 36799 20.384209 44.322052 22.429497 36800 22.132217 42.841095 22.020500 36801 22.977631 42.072357 22.323380 36802 24.745300 42.552856 21.853577 36803 25.501236 43.710205 22.227997 36804 26.119240 41.940903 22.174652 36805 24.914536 41.921753 21.831581 36806 24.171837 41.882172 21.996727 36807 36.482224 42.793427 21.790215 36808 44.212250 43.131729 22.113327 36809 45.290344 42.246109 22.166885 36810 5.091271 41.267822 21.528496 36811 21.438980 43.010895 22.705963 36812 22.050797 42.393799 22.446686 36813 21.857254 42.480591 22.941727 36814 22.559021 42.074829 23.104660 36815 24.959198 41.590530 21.959671 36816 37.175957 42.162292 21.511131 36817 44.578323 42.624008 23.122650 36818 4.086884 41.862213 22.159805 36819 4.949486 40.942780 22.505051 36820 5.915703 40.524597 22.046005 36821 46.283920 39.427551 21.710274 36822 45.657959 38.537689 21.884300 36823 46.013733 39.064255 21.484032 36824 10.228942 38.258194 22.310188 36825 12.423920 36.717163 22.775818 36826 13.060318 36.171265 22.602005 36827 45.655975 38.434372 22.900894 36828 4.830345 35.879166 19.841492 36829 6.793945 34.220581 21.248917 36830 5.601959 34.524933 21.272781 36831 11.388985 37.416214 22.955330 36832 7.852706 33.846283 20.945816 36833 50.847549 31.138657 21.184731 36834 49.857635 31.984940 21.376297 36835 3.477364 34.027588 20.585861 36836 9.087646 32.980225 20.810364 36837 10.137573 32.623489 20.502365 36838 13.594238 33.882248 22.406609 36839 13.435593 32.627365 22.647568 36840 40.906662 33.006500 21.565079 36841 48.190033 32.354431 21.373772 36842 48.947098 33.050461 21.386009 36843 3.002655 32.550537 20.412201 36844 10.941772 31.901871 20.519081 36845 12.464363 31.253601 20.628784 36846 12.976929 31.230103 21.042038 36847 13.395462 31.821457 21.639305 36848 37.723465 30.953857 20.956169 36849 39.730057 31.994690 21.343620 36850 2.884262 29.741074 20.687569 36851 10.002701 31.870331 20.949471 36852 11.705566 31.289490 20.568565 36853 37.193245 30.003998 20.701492 36854 37.640488 30.024811 21.138260 36855 38.860435 31.116318 21.367386 36856 41.561584 31.069641 22.271111 36857 40.877930 31.775116 21.846024 36858 39.972878 30.293686 22.043190 36859 48.513336 33.060349 21.521729 36860 2.515625 30.282211 21.667618 36861 11.044434 30.900726 20.986900 36862 12.068588 30.742432 20.920227 36863 12.627655 30.853653 20.964622 36864 38.362320 29.935562 21.453934 36865 3.479851 28.808929 20.384010 36866 50.257248 30.195969 21.446144 36867 37.818184 29.177750 20.956650 36868 38.341019 28.749207 21.385368 36869 46.460037 26.358597 22.028534 36870 47.406708 27.577682 21.825661 36871 5.792900 25.123077 20.189888 36872 5.877655 24.783707 19.950485 36873 5.943657 24.724472 20.338509 36874 39.252739 26.655746 21.893242 36875 42.431122 25.392532 22.114899 36876 48.382660 25.407440 20.986839 36877 55.044907 24.484283 22.076820 36878 54.218307 25.374496 21.295074 36879 48.239014 24.824799 21.947250 36880 47.566467 25.568115 21.727112 36881 49.035599 24.777313 21.330650 36882 49.161438 24.985825 20.762589 36883 49.916473 24.991867 21.141678 36884 50.248901 25.354813 22.251602 36885 49.245926 24.793945 22.088974 36886 3.212949 18.898603 16.155554 36887 2.994102 17.813158 15.654329 36888 3.296313 18.699102 16.589472 36889 3.764654 20.041464 17.729380 36890 3.992890 20.655693 18.207748 36891 5.470390 23.156021 20.353569 36892 4.003856 19.568272 18.748558 36893 3.555434 18.998417 17.447552 36894 3.504377 18.050947 17.708988 36895 4.543422 20.820423 19.851158 36896 57.544662 18.915283 20.852478 36897 56.839874 19.427139 22.020218 36898 3.026885 16.786648 16.322800 36899 2.990677 16.095709 16.451317 36900 2.553014 11.317221 16.572124 36901 55.655319 13.910507 20.567543 36902 52.678772 14.210632 22.842339 36903 54.438049 14.115616 22.482010 36904 56.809906 14.093353 20.317276 36905 55.722351 13.880615 21.672928 36906 56.157043 14.008392 22.534615 36907 56.846832 14.326706 21.506836 36908 46.332047 13.029068 21.059196 36909 51.796906 11.071030 20.420914 36910 50.440292 11.090714 21.185364 36911 53.148758 10.758362 20.240417 36912 46.205383 12.029449 21.580551 36913 48.189011 10.860794 20.226730 36914 53.015808 7.840073 20.271393 36915 59.171600 7.003952 20.103760 36916 46.808807 5.988846 20.674942 36917 59.028595 6.722977 20.526917 36918 45.643372 4.419510 20.245026 36919 55.314240 4.956253 19.816002 36920 57.231567 5.981087 19.856522 36921 56.309113 5.522232 20.440842 36922 60.483688 5.486221 20.034142 36923 53.508789 3.958420 19.662292 36924 54.388351 4.502060 20.222847 36925 60.107162 4.845001 20.775818 36926 52.630890 3.532608 20.029099 36927 58.609467 2.050674 20.573105 36928 35.683922 0.680038 19.286789 36929 46.759003 1.996719 20.374245 36930 45.408691 3.034286 20.698433 36931 51.771362 3.042953 20.821358 36932 50.856018 2.577271 19.949753 36933 35.030159 0.745682 19.197601 36934 36.665314 -0.311890 19.281296 36935 48.448242 1.646301 20.333038 36936 49.773376 2.029434 20.578140 36937 58.282288 0.855530 20.299332 36938 57.767868 1.195770 21.157158 36939 37.476410 0.311768 19.104942 36940 37.993164 0.420166 18.875732 36941 58.682068 0.323013 20.064720 36942 35.303642 -0.852554 18.878700 36943 60.063080 -0.236542 19.779648 36944 60.794266 -0.908264 19.964310 36945 58.180313 0.050232 20.956161 36946 59.198792 -0.185471 20.419693 36947 59.088242 -0.716736 21.417870 36948 36.590454 -1.664368 19.440674 36949 36.417450 -3.061127 19.632401 36950 36.505089 -2.374115 19.621040 36951 38.249771 -2.826935 18.901764 36952 61.708221 -2.901596 20.620773 36953 61.300797 -1.899277 20.408577 36954 61.985291 -2.788696 19.591507 36955 2.024120 -0.923854 17.887320 36956 35.564423 -3.711685 19.231033 36957 53.918030 -4.336670 19.804367 36958 54.193939 -3.946045 19.564537 36959 35.008392 -4.621582 18.623596 36960 36.991684 -3.734924 19.312805 36961 36.609406 -4.366531 19.152946 36962 37.030602 -4.526413 18.589119 36963 50.870483 -4.430298 19.308937 36964 51.789001 -3.941742 19.296875 36965 47.360046 -6.129257 20.003784 36966 43.098358 -6.541214 18.661491 36967 42.281036 -6.620377 18.760040 36968 44.033905 -6.482224 19.557434 36969 57.039993 -6.352646 19.294685 36970 59.876343 -8.170746 18.018967 36971 62.832886 -6.253448 20.352234 36972 33.728271 -7.421646 18.498413 36973 33.142166 -7.956284 18.848854 36974 33.935303 -8.002258 19.156311 36975 32.895584 -7.581299 18.352470 36976 39.574799 -7.680847 19.011459 36977 38.651581 -8.201126 19.735031 36978 39.707779 -7.892517 20.274773 36979 37.674805 -8.393204 18.791893 36980 56.592285 -7.024796 18.961952 36981 56.586578 -6.415283 19.305588 36982 58.255478 -7.643082 18.383507 36983 32.356522 -8.673187 18.449905 36984 51.645660 -7.673523 19.347000 36985 48.850983 -9.319962 19.120300 36986 45.574097 -10.310852 18.597420 36987 63.460190 -10.033600 19.832474 36988 2.681231 -11.479214 17.478218 36989 32.506882 -10.190964 18.821266 36990 44.134277 -10.877380 18.751823 36991 43.361877 -11.444641 18.693954 36992 63.991043 -11.594177 18.934425 36993 43.532959 -13.695465 19.092476 36994 43.915268 -14.970795 19.082748 36995 44.616028 -14.474060 18.494347 36996 63.990814 -13.373184 20.088989 36997 64.052612 -12.449066 20.865303 36998 63.982681 -11.916367 19.993172 36999 49.945770 -13.412643 18.645905 37000 50.544678 -13.108154 18.444611 37001 51.047150 -13.020691 18.431274 37002 2.907508 -13.059449 17.307816 37003 42.936462 -12.241074 19.432716 37004 63.875092 -13.477905 18.898079 37005 45.389511 -14.993973 18.357117 37006 44.692474 -15.515640 18.730682 37007 46.103516 -14.860703 18.251389 37008 52.138092 -15.024643 18.588867 37009 62.152634 -14.875748 18.938286 37010 63.082184 -14.702255 18.593857 37011 63.195023 -14.539215 19.790352 37012 45.811615 -15.692535 18.917809 37013 50.948471 -16.521393 18.747543 37014 3.462402 -16.783051 17.592392 37015 3.888177 -18.599771 17.141073 37016 3.162361 -15.072392 17.609741 37017 33.892075 -15.828186 19.584763 37018 41.764191 -17.908218 18.472771 37019 41.471039 -17.039505 19.412254 37020 40.755753 -17.881531 18.658089 37021 42.601410 -17.467209 18.311348 37022 43.125504 -17.161285 18.439728 37023 42.547211 -16.945343 18.781342 37024 43.556793 -16.222992 19.000130 37025 50.299576 -16.457993 20.089020 37026 49.380585 -17.808426 19.489006 37027 51.489532 -14.936447 19.564056 37028 57.770035 -16.748672 19.792442 37029 40.903320 -18.187332 18.334778 37030 40.478073 -18.296051 18.465179 37031 42.947632 -17.940811 18.512283 37032 43.960297 -17.861435 18.905098 37033 44.525635 -16.884338 19.006210 37034 43.685501 -17.239441 18.645195 37035 43.341003 -18.468384 19.097069 37036 49.564697 -18.122452 18.339630 37037 4.247266 -20.303339 17.196428 37038 40.804016 -18.731461 18.606331 37039 42.190247 -18.834991 19.049370 37040 4.409786 -20.137426 16.153578 37041 31.909998 -19.954483 18.250023 37042 4.685889 -22.228798 17.217901 37043 4.644686 -21.435556 16.538671 37044 4.541767 -20.733122 16.214252 37045 4.959978 -21.947422 15.786413 37046 5.142304 -21.931713 15.099295 37047 31.719110 -20.690948 17.718697 37048 46.449982 -21.220840 18.227058 37049 58.752457 -20.254562 19.344398 37050 5.337866 -22.438410 14.926107 37051 5.315035 -22.759947 15.345272 37052 29.918610 -23.160110 19.761917 37053 30.382706 -22.220856 18.715904 37054 29.674515 -24.029373 18.580635 37055 36.106667 -23.411102 16.734421 37056 45.551025 -21.895905 18.374298 37057 44.952728 -21.920563 19.000168 37058 52.931000 -21.827438 18.784470 37059 54.166962 -21.640350 18.375504 37060 55.039642 -21.440872 17.969856 37061 55.960876 -21.772629 18.380478 37062 58.492050 -22.124741 18.662880 37063 4.947523 -22.344685 16.259012 37064 35.822128 -24.457230 17.333374 37065 37.295929 -24.218323 17.197212 37066 38.466888 -25.584183 16.944046 37067 43.971802 -23.990753 18.273041 37068 43.264069 -23.392914 19.150970 37069 42.745178 -24.001312 19.290039 37070 45.321259 -25.012558 17.998405 37071 35.401932 -25.770767 18.239815 37072 36.622261 -25.300888 17.947777 37073 44.068787 -25.124542 18.113441 37074 43.118195 -24.978760 18.791603 37075 43.857910 -25.960602 18.725441 37076 44.652512 -25.697800 18.072281 37077 29.500252 -25.745407 17.557098 37078 33.046822 -27.798203 19.246902 37079 32.378578 -28.829407 20.566963 37080 31.002472 -27.582794 19.573364 37081 33.249184 -26.330688 17.867699 37082 37.615517 -25.708725 17.649033 37083 38.186035 -26.939819 16.984070 37084 37.558853 -26.684189 17.661278 37085 44.725769 -26.217026 18.361526 37086 29.858505 -26.163361 17.452805 37087 31.541420 -26.858810 18.242188 37088 38.915497 -26.813858 16.327263 37089 41.143036 -25.593826 20.580772 37090 40.671204 -26.132660 21.336494 37091 41.693253 -26.061935 20.687103 37092 45.231064 -26.661087 18.664948 37093 45.463516 -26.025238 18.269096 37094 7.506157 -28.388500 14.073477 37095 5.669425 -31.484430 17.875652 37096 6.149295 -29.555717 16.610258 37097 5.918942 -28.170694 16.712984 37098 5.655228 -29.205009 17.481119 37099 7.684994 -29.082075 14.077446 37100 8.195720 -29.347050 13.420893 37101 35.502945 -28.483810 18.039314 37102 5.392403 -31.330769 18.469198 37103 6.027116 -30.561169 17.044617 37104 6.502742 -30.798496 16.259359 37105 7.641839 -29.441477 14.260437 37106 8.195761 -29.989454 13.641228 37107 60.435638 -30.773163 18.617485 37108 63.290726 -30.933136 17.874214 37109 35.154724 -31.740143 18.623955 37110 56.087769 -33.236465 17.343170 37111 56.961853 -32.500809 18.310043 37112 62.901764 -33.364685 18.169800 37113 62.023911 -34.679092 17.991501 37114 62.841568 -32.499893 19.329842 37115 63.264648 -32.400528 18.469849 37116 47.097595 -33.879761 17.543411 37117 47.689606 -34.071426 19.175575 37118 53.511566 -34.061539 17.486755 37119 54.015808 -34.286255 17.305016 37120 53.867340 -34.313385 17.553017 37121 54.057739 -34.065475 18.073906 37122 62.455322 -32.981979 20.546112 37123 62.042847 -32.167816 20.238213 37124 37.985550 -35.788483 18.038605 37125 39.816666 -36.327972 17.974586 37126 54.097382 -34.355011 17.559303 37127 61.194672 -35.170120 17.472519 37128 5.046764 -33.682724 20.661186 37129 5.483790 -35.349049 19.456690 37130 5.294935 -34.808361 19.988287 37131 5.662516 -35.534954 18.958570 37132 5.947499 -36.379742 18.456751 37133 60.696564 -37.107941 17.228088 37134 5.483875 -35.708820 19.647049 37135 5.668845 -36.045387 19.143070 37136 6.182854 -38.110153 18.101032 37137 6.604489 -37.947250 16.951496 37138 6.585331 -39.126560 16.647621 37139 6.396790 -38.581116 17.376661 37140 62.454010 -39.472641 17.183281 37141 6.426750 -41.082092 16.883316 37142 6.321312 -41.694000 16.852036 37143 6.482658 -41.131454 16.154953 37144 6.037735 -41.920776 15.876221 37145 5.122559 -42.774796 15.527542 37146 5.178879 -44.080063 16.535477 37147 53.363174 -42.492554 17.328659 37148 53.834900 -41.914200 17.385857 37149 55.394669 -41.302551 18.243126 37150 56.380569 -41.673523 17.779884 37151 54.999786 -41.821762 17.164116 37152 57.623642 -42.113113 18.034058 37153 5.283310 -42.976990 16.624619 37154 52.983032 -43.231842 18.046280 37155 58.109467 -42.762680 17.024292 37156 58.988373 -43.446808 17.091187 37157 5.640198 -45.046661 16.660004 37158 6.093926 -45.770660 16.777885 37159 42.212341 -44.395386 16.988373 37160 42.749283 -44.977905 17.889946 37161 54.202469 -44.578262 17.435165 37162 62.045776 -43.742172 17.590935 37163 62.493347 -42.668381 18.056396 37164 43.735779 -44.157669 17.028496 37165 41.324997 -45.280457 16.517799 37166 46.626160 -45.316116 16.555954 37167 53.226913 -44.278671 18.577553 37168 47.747803 -45.842377 16.506905 37169 55.457733 -45.713425 17.782425 37170 55.846954 -46.073257 18.488205 37171 54.912567 -45.442017 18.582611 37172 61.493469 -44.100418 17.703476 37173 6.176903 -46.813507 15.703125 37174 48.112030 -46.591858 17.450882 37175 49.525879 -47.277969 17.644936 37176 50.696732 -47.306229 16.787155 37177 6.497414 -48.195343 15.553658 37178 56.608765 -46.863190 18.549133 37179 56.297775 -46.752823 17.768219 37180 57.077515 -47.687393 18.179657 37181 6.658180 -49.436737 15.548401 37182 8.928818 -51.595322 15.905006 37183 9.396988 -50.831436 16.047165 37184 11.753479 -49.912079 16.482178 37185 10.518082 -49.906433 16.466644 37186 44.158524 -48.928650 15.900780 37187 42.917450 -48.401154 16.333626 37188 44.849884 -49.836884 15.951462 37189 44.427948 -50.017578 16.323448 37190 43.961609 -49.598984 16.341499 37191 5.883041 -53.828186 16.533882 37192 12.400467 -50.005936 16.828842 37193 12.553993 -50.490463 16.259575 37194 6.811745 -50.556747 15.433060 37195 12.645493 -51.999069 15.780716 37196 12.588120 -53.484512 15.689178 37197 11.879715 -50.780151 15.327835 37198 44.110046 -51.429214 15.251961 37199 44.111252 -50.525360 16.120712 37200 41.135147 -52.738663 16.117256 37201 41.401825 -52.962143 17.100922 37202 41.497681 -51.964325 17.012428 37203 41.645172 -51.916458 16.032715 37204 37.301575 -53.357849 16.970345 37205 37.075722 -53.348022 15.792801 37206 36.055061 -54.168869 16.855957 37207 7.350632 -53.967651 15.258636 37208 6.678719 -54.287491 15.636078 37209 7.903282 -53.976471 15.525719 37210 11.648972 -54.147217 14.397110 37211 19.204178 -53.459122 17.431282 37212 18.870667 -54.398697 15.873177 37213 17.718269 -54.305237 16.779045 37214 19.831848 -53.880020 16.501877 37215 20.656860 -55.668106 15.723740 37216 38.371338 -53.455688 16.012032 37217 39.404694 -54.102417 16.101578 37218 6.864334 -55.266098 16.249176 37219 7.798934 -55.062881 16.218979 37220 7.475853 -54.567352 15.658348 37221 17.791183 -55.333878 15.491165 37222 36.143311 -55.839783 15.557022 37223 40.382935 -54.938751 16.051521 37224 41.552460 -54.992096 16.116478 37225 12.532524 -55.743225 15.188553 37226 20.638428 -54.723190 16.646667 37227 20.716782 -57.023453 15.278130 37228 35.963310 -55.858093 16.571709 37229 39.589844 -54.810730 16.761932 37230 40.480667 -55.630661 16.742393 37231 41.165588 -55.637207 16.062286 37232 41.795593 -52.979385 18.078735 37233 42.214340 -54.033661 17.403351 37234 42.270187 -53.477142 18.282692 37235 41.835785 -55.914597 16.061188 37236 12.918633 -56.336166 15.102844 37237 13.470428 -56.961884 14.881126 37238 36.769371 -57.145035 15.718529 37239 41.444000 -56.207642 16.607559 37240 42.239944 -56.473099 16.534393 37241 42.400116 -55.898651 16.270256 37242 16.257523 -57.100159 14.924576 37243 20.459900 -57.399155 16.374435 37244 20.951088 -56.168274 17.365898 37245 20.443069 -58.271149 15.270287 37246 20.709686 -58.021515 14.535461 37247 8.640327 -59.820892 13.886017 37248 37.894356 -58.668930 15.475319 37249 6.647972 -60.971771 14.313278 37250 9.182831 -60.098221 13.827629 37251 8.739685 -60.738861 13.779305 37252 6.537666 -61.358475 14.558578 37253 38.272087 -59.412720 16.047440 37254 6.066795 -60.967926 14.335640 37255 40.211151 -60.468613 16.255341 37256 41.433136 -60.409805 15.494652 37257 41.200378 -60.795395 16.682526 37258 49.953857 -60.982773 15.061104 37259 48.809799 -60.963837 14.813728 37260 52.555618 -62.135559 15.770515 37261 53.570984 -61.269745 14.953957 37262 53.999969 -61.977081 15.438843 37263 5.750282 -61.473984 14.423943 37264 11.757736 -62.498367 14.803864 37265 17.923737 -62.334396 14.643082 37266 53.668884 -62.502701 15.914665 37267 50.853577 -62.529755 16.199158 37268 50.992081 -61.429214 15.701797 37269 55.044495 -62.591385 15.218712 37270 6.412171 -61.978821 14.588455 37271 6.518875 -62.880127 14.409592 37272 10.643761 -63.281540 16.222298 37273 10.648438 -63.434097 15.154991 37274 11.536270 -62.545105 16.302887 37275 17.919884 -61.883865 14.904251 37276 54.817932 -63.866562 15.872681 37277 54.353088 -62.831268 15.903191 37278 5.624184 -63.857849 14.411156 37279 55.294098 -63.513626 15.191116 37280 5.021141 -64.982941 14.113602 37281 5.558754 -66.016083 13.746193 37282 9.888458 -64.869934 14.945946 37283 9.014282 -65.987518 16.250603 37284 8.635667 -66.781616 15.616959 37285 5.053101 -66.678543 13.379684 37286 4.539719 -64.099411 14.195633 37287 39.466690 -68.106812 14.655869 37288 44.100189 -68.066269 15.236435 37289 9.172173 -68.756104 15.343231 37290 8.157104 -67.875580 16.059853 37291 8.413162 -68.822083 15.899384 37292 10.416840 -68.595963 14.341301 37293 39.086349 -69.641083 15.719910 37294 40.272430 -68.883850 15.985916 37295 39.799477 -68.321869 15.225403 37296 44.031525 -70.260544 17.162842 37297 45.139236 -69.852386 17.837578 37298 45.280701 -69.425308 17.318192 37299 45.313126 -68.063675 14.926170 37300 47.056244 -68.762421 15.270393 37301 48.042908 -69.257904 15.816055 37302 49.339417 -69.470642 16.021820 37303 50.411285 -69.013275 15.279472 37304 52.431992 -68.462906 16.317528 37305 11.681320 -69.438492 14.101181 37306 10.556671 -69.734436 15.080162 37307 11.853790 -70.287811 14.751556 37308 4.706398 -71.652527 14.494492 37309 5.783768 -71.462616 14.208855 37310 5.296829 -71.372238 15.303940 37311 7.853805 -71.722260 14.831078 37312 6.597969 -71.341400 14.871185 37313 9.062233 -71.781845 14.256104 37314 9.788452 -71.712021 13.662445 37315 38.237564 -72.405106 14.711189 37316 12.909714 -73.163406 14.357048 37317 14.456024 -72.356949 14.769333 37318 31.432266 -75.480927 14.875359 37319 30.728638 -75.013962 14.528816 37320 31.479706 -74.311340 15.208199 37321 38.586304 -73.510330 14.523949 37322 38.942490 -72.827545 15.233963 37323 39.833443 -73.570114 15.097603 37324 4.611580 -76.154434 14.643425 37325 4.334351 -74.950775 15.646629 37326 4.192619 -72.948669 15.545937 37327 9.296249 -75.544907 13.585220 37328 10.970947 -76.384979 14.106895 37329 9.798256 -75.384262 13.123138 37330 30.464417 -74.063004 15.004135 37331 29.436562 -73.686996 15.572090 37332 30.249146 -72.878677 16.273834 37333 29.666519 -75.091736 14.680534 37334 30.447662 -76.343536 14.539223 37335 30.323044 -74.706985 14.498116 37336 38.865723 -72.255676 15.496597 37337 39.004494 -71.295944 15.635147 37338 42.481323 -80.221466 14.160431 37339 43.357819 -74.280807 15.442520 37340 42.602097 -73.320526 15.597710 37341 41.790680 -74.179016 15.096237 37342 41.793335 -75.551788 14.538330 37343 40.379974 -75.171921 14.663979 37344 5.055855 -77.306564 13.620926 37345 11.956070 -76.770569 14.575722 37346 12.679451 -76.591431 14.106903 37347 12.698730 -76.731995 14.741829 37348 13.635117 -76.773224 13.236923 37349 28.747780 -74.447769 15.658539 37350 28.369652 -75.679611 15.391434 37351 28.960159 -76.691544 14.400726 37352 44.174805 -78.032425 14.423370 37353 44.166077 -77.427765 14.503227 37354 42.532150 -75.345764 14.654427 37355 43.046829 -76.456650 14.494064 37356 43.302643 -75.307297 14.960716 37357 9.855820 -76.465454 13.699608 37358 9.372864 -75.832565 13.824875 37359 10.524460 -77.531845 13.872612 37360 27.328613 -77.917587 14.924637 37361 26.804169 -78.567612 15.294342 37362 27.293465 -77.697006 16.079727 37363 28.048943 -76.969925 14.702904 37364 28.069565 -78.327255 14.245865 37365 29.645042 -77.977875 14.343040 37366 44.343140 -76.398010 14.918663 37367 44.662048 -77.217560 14.785606 37368 12.178299 -78.280212 15.043633 37369 11.268173 -78.339630 14.065262 37370 28.886711 -79.226151 14.131310 37371 44.542648 -77.889862 14.888100 37372 18.145683 -79.051483 13.781197 37373 26.840332 -79.228699 14.741043 37374 29.807358 -79.225311 14.575699 37375 6.287560 -78.501587 13.796692 37376 7.390808 -79.548386 14.015190 37377 16.773514 -80.119507 13.691612 37378 17.088303 -79.599854 14.511177 37379 27.495689 -80.175888 14.136581 37380 44.359055 -78.642548 15.366333 37381 43.413757 -79.851761 14.690849 37382 7.316971 -82.098801 13.687660 37383 7.934692 -80.826187 14.487679 37384 16.063660 -80.123184 14.485146 37385 15.292084 -80.703903 14.358437 37386 25.952942 -80.722061 14.797752 37387 29.067474 -80.237518 14.404114 37388 28.140709 -81.484207 14.143219 37389 43.123550 -80.699402 15.232452 37390 43.870148 -79.499191 15.308762 37391 7.313431 -83.270111 12.972931 37392 26.441597 -81.986679 13.984840 37393 34.686371 -82.348953 13.954102 37394 42.328918 -82.219940 15.682709 37395 42.573669 -81.803741 14.841370 37396 41.921570 -82.582657 14.228348 37397 12.972214 -82.470230 13.129005 37398 13.528214 -83.355347 13.138275 37399 25.160385 -83.338425 14.053780 37400 25.324997 -82.035400 14.529160 37401 27.468880 -82.861084 14.076797 37402 28.478973 -82.520767 14.630592 37403 24.860031 -82.661316 15.376259 37404 23.965767 -83.778137 14.803986 37405 24.281281 -84.497345 13.934364 37406 25.550667 -84.962830 13.792114 37407 26.504578 -83.720337 13.945267 37408 27.686424 -84.286835 15.095474 37409 41.272217 -83.501129 13.556564 37410 14.120575 -83.380737 13.331680 37411 14.420837 -82.871872 13.670189 37412 23.094719 -85.181351 14.673798 37413 24.028900 -85.666397 13.528687 37414 24.969803 -86.255539 13.471161 37415 26.599426 -84.598373 14.187088 37416 38.154793 -85.388824 14.064034 37417 39.607132 -85.567444 13.544739 37418 41.020264 -84.244980 13.851387 37419 41.516632 -83.524170 14.403831 37420 8.768616 -86.267578 13.111511 37421 22.925781 -86.384552 13.817932 37422 24.168518 -86.476456 13.043457 37423 26.543121 -86.595734 14.969452 37424 27.018753 -86.014389 15.344772 37425 27.242531 -87.632629 15.449142 37426 34.279701 -84.051895 15.352692 37427 22.522247 -86.177734 14.589035 37428 22.314713 -87.069046 14.563431 37429 25.445312 -87.307083 13.774818 37430 25.146217 -88.190765 13.110092 37431 34.932579 -87.053574 14.507065 37432 34.646545 -86.103882 14.943962 37433 38.959000 -85.633072 14.132347 37434 39.019608 -85.930450 13.445518 37435 6.532829 -89.035614 15.133179 37436 25.531609 -88.765808 13.237701 37437 23.140106 -89.798447 14.195587 37438 26.120674 -89.161270 13.474739 37439 27.798599 -90.113770 14.239761 37440 34.973366 -88.064514 14.659416 37441 7.402489 -90.786758 12.800787 37442 16.239212 -91.360443 12.806412 37443 16.310577 -91.306686 13.208588 37444 16.148636 -91.190887 14.323433 37445 32.927383 -90.082077 13.687088 37446 31.258392 -90.462234 14.094849 37447 15.346863 -92.437851 15.473587 37448 14.839996 -93.139847 15.052628 37449 15.547821 -92.644806 14.099464 37450 16.079803 -92.060272 12.887482 37451 24.264893 -91.461655 14.015465 37452 24.826279 -92.944244 13.189926 37453 28.686874 -93.728912 12.709991 37454 28.861725 -92.995697 13.296036 37455 11.707558 -95.301559 12.163847 37456 11.841141 -94.912460 12.422638 37457 11.940750 -94.007629 12.523460 37458 28.289200 -91.961243 13.433540 37459 28.586319 -91.482727 14.155785 37460 28.993790 -92.187698 13.930908 37461 29.797516 -92.884644 13.494392 37462 9.407104 -92.851242 13.009262 37463 14.738121 -93.935898 13.798485 37464 25.425049 -97.025558 12.781769 37465 29.465179 -93.985397 12.807724 37466 29.084877 -93.618820 13.174515 37467 10.366936 -95.293930 12.250130 37468 10.371185 -95.687347 11.861229 37469 11.060165 -94.852417 12.553566 37470 29.595757 -94.646423 12.159592 37471 25.472107 -95.577988 14.466263 37472 25.588661 -94.885376 15.888069 37473 25.976822 -94.543961 15.093430 37474 18.016296 -99.301041 13.272774 37475 19.213150 -98.807709 14.094940 37476 20.632950 -99.469727 12.369621 37477 22.542343 -99.305725 12.477394 37478 23.329834 -98.718109 12.918503 37479 16.724411 -99.561783 13.491287 37480 7.717910 63.648727 23.368233 37481 4.812538 63.281067 23.136681 37482 4.435402 62.688416 23.114349 37483 5.577049 62.046387 24.107605 37484 4.942314 62.730545 23.565903 37485 10.156616 62.356598 22.981552 37486 8.989044 63.025635 23.401627 37487 18.471977 62.473221 24.663712 37488 14.701889 61.670166 23.834229 37489 14.952957 62.434937 24.559868 37490 14.219184 61.568863 24.292793 37491 14.132568 62.195145 24.935234 37492 15.276199 61.786270 23.310486 37493 14.431793 60.650894 23.274170 37494 21.865883 61.067688 23.376205 37495 21.194702 60.901718 23.821274 37496 8.079193 58.777756 23.969582 37497 22.192230 60.169266 23.516655 37498 23.108093 60.181030 22.971672 37499 3.996513 58.031647 22.723534 37500 23.635605 59.199585 23.240318 37501 13.242783 58.920197 23.330399 37502 12.914375 59.637863 24.552559 37503 12.737732 58.064575 23.486885 37504 12.144974 57.672760 24.507820 37505 19.485886 58.034576 23.441528 37506 20.262283 59.853058 24.131424 37507 18.418457 58.943970 24.327103 37508 22.165245 58.854889 23.878143 37509 24.351448 56.832153 24.441650 37510 23.459122 57.901245 24.081703 37511 17.185005 57.208282 24.366470 37512 17.547318 58.171478 25.285980 37513 17.649910 57.755692 24.010605 37514 20.556938 57.317520 23.574280 37515 20.824173 56.246582 23.584526 37516 26.316078 57.052490 23.745964 37517 27.081940 57.189453 23.123016 37518 27.351448 55.744781 24.149063 37519 27.426010 56.682785 23.593300 37520 12.090759 56.736160 23.271797 37521 3.094071 55.118210 23.278961 37522 3.378159 55.697952 24.111427 37523 3.272728 55.113586 24.036720 37524 3.407158 56.340988 23.760826 37525 11.177429 55.579819 23.783150 37526 28.432724 55.257172 23.868683 37527 3.277397 54.204956 23.938774 37528 3.087334 53.440308 22.772049 37529 8.371468 56.666351 23.985199 37530 10.189018 54.899170 24.099243 37531 17.192368 56.303986 24.527679 37532 17.485977 54.677094 24.368851 37533 3.090454 53.255859 21.813896 37534 3.712296 52.013657 23.159515 37535 3.183273 53.153564 23.541718 37536 3.596230 53.113434 24.199455 37537 19.741684 52.076767 22.495766 37538 4.097450 51.942474 24.700211 37539 5.791023 50.236954 22.559837 37540 6.960228 49.430115 22.944336 37541 22.670235 51.602814 23.098251 37542 22.075745 50.182617 22.188080 37543 27.809654 53.083649 23.000443 37544 4.589233 50.990677 22.710220 37545 17.521133 51.071854 23.976028 37546 23.939316 52.325653 23.439575 37547 25.425949 52.220245 23.100334 37548 32.143936 50.230804 23.291679 37549 32.105087 50.374115 24.683029 37550 34.948593 49.694550 23.590942 37551 8.522026 48.448029 23.177200 37552 9.691299 47.283386 24.338585 37553 17.156616 49.890274 23.106354 37554 7.016449 48.774384 24.263031 37555 8.091180 48.104462 25.570702 37556 27.264145 46.666595 22.496727 37557 31.204254 49.382996 23.995636 37558 5.198891 45.582947 23.194092 37559 9.916946 46.266632 22.657272 37560 18.734871 46.530884 22.727463 37561 18.128342 48.327927 23.481544 37562 23.793594 46.557724 21.850800 37563 26.065689 45.421432 22.459778 37564 6.922203 45.341034 22.844818 37565 7.692657 45.064499 23.100632 37566 19.068970 46.015381 22.592033 37567 28.142807 45.636505 23.117905 37568 27.507660 44.448914 22.879555 37569 38.811905 45.596054 23.143692 37570 37.749504 46.187286 23.579956 37571 38.536194 44.843033 22.964195 37572 39.388535 45.211060 22.973534 37573 39.389389 45.882828 23.576088 37574 3.428452 42.465179 23.148911 37575 3.355354 42.795715 22.444191 37576 8.782669 44.676361 23.455849 37577 6.846359 45.148041 23.450310 37578 19.171677 46.517853 23.406921 37579 20.275070 46.034714 24.011269 37580 24.227341 44.711060 22.056763 37581 38.567619 43.951828 22.693169 37582 37.633667 44.023682 22.908150 37583 40.377045 45.791443 24.633385 37584 42.060455 44.254333 23.476013 37585 20.805267 43.787811 22.803871 37586 36.528503 43.705688 22.507294 37587 36.763847 44.827911 22.950905 37588 43.256409 43.576355 23.014671 37589 4.160965 41.232101 23.766487 37590 3.189163 42.862946 24.337898 37591 3.014053 43.958496 24.150009 37592 27.152023 43.337372 22.544846 37593 27.853172 42.644409 22.626076 37594 28.541283 43.550598 23.064186 37595 28.989441 42.378906 23.296555 37596 37.292198 43.313889 22.702759 37597 43.948669 43.106445 23.207741 37598 22.333984 42.848740 23.797897 37599 27.837494 41.743423 22.622139 37600 27.266899 40.954926 22.471260 37601 27.254440 40.256088 22.650970 37602 26.317551 40.519638 22.446106 37603 37.658653 44.926971 23.190971 37604 45.233185 41.882339 23.027596 37605 44.670670 42.132477 23.642563 37606 23.833603 41.206818 22.543419 37607 24.964745 41.008240 22.320839 37608 24.386093 40.606781 22.835777 37609 25.419083 40.173935 23.005882 37610 23.252121 41.513626 23.067398 37611 24.527161 40.432068 23.432152 37612 26.535812 39.951935 22.906952 37613 44.939697 41.284256 23.851181 37614 27.300186 39.980133 23.193253 37615 46.047455 39.044769 22.235550 37616 45.883667 39.229889 23.043427 37617 11.588120 36.689911 23.805336 37618 13.385223 35.596863 22.383469 37619 3.513390 33.583984 21.528854 37620 3.236046 33.345047 21.236603 37621 4.471939 35.033463 20.687508 37622 4.331932 33.800323 21.680435 37623 5.258682 33.789886 21.857788 37624 7.185257 33.513458 21.491081 37625 6.126274 33.517899 21.888260 37626 43.016968 34.538757 22.354980 37627 44.725159 33.233459 25.081474 37628 44.163483 33.757950 23.797302 37629 44.886887 31.876480 24.299004 37630 8.045578 32.828751 21.408096 37631 42.606232 33.199799 22.395111 37632 43.424622 31.623596 23.155708 37633 7.081955 32.649200 21.996391 37634 9.004105 31.895279 21.392014 37635 42.086014 32.038116 22.237923 37636 49.263245 31.039261 21.862129 37637 48.431305 30.359222 21.902084 37638 2.633690 31.602524 21.285919 37639 2.646401 30.440918 23.172104 37640 2.491066 29.205505 22.561630 37641 8.048111 31.868332 21.908371 37642 9.963669 30.794708 21.505569 37643 12.792191 30.632446 21.677254 37644 41.231323 30.331284 22.496033 37645 42.465469 31.283600 22.611343 37646 49.230469 29.631729 21.955902 37647 49.334579 30.306152 22.037827 37648 2.917931 28.962738 21.371628 37649 8.871414 30.944244 22.016296 37650 11.011841 29.706558 21.571739 37651 11.822098 30.096954 21.304245 37652 12.242035 29.574188 21.819038 37653 12.795471 29.974213 22.789551 37654 41.202911 29.629013 22.853416 37655 42.389404 30.388199 22.955910 37656 47.356628 29.665741 21.665199 37657 9.749390 29.375458 22.714577 37658 8.840698 29.003479 24.205536 37659 8.116066 29.911148 23.718208 37660 11.725845 29.469345 21.492317 37661 38.862389 29.130264 21.867058 37662 3.763695 27.736053 20.906502 37663 10.992279 28.635498 22.236519 37664 11.706834 28.989029 21.898659 37665 39.381126 28.794800 22.367096 37666 40.279907 28.867432 22.904160 37667 48.335861 28.737442 21.804932 37668 40.738708 24.242767 23.382957 37669 40.163971 24.621948 22.796227 37670 41.933838 24.326645 23.159348 37671 51.196289 26.064285 22.787895 37672 53.955505 25.614716 22.831955 37673 5.367668 24.709091 21.262901 37674 5.673859 23.213425 21.000877 37675 55.456696 23.643524 22.134972 37676 3.174796 17.730396 16.498016 37677 4.977944 22.317581 20.612083 37678 55.690277 22.803406 22.106186 37679 56.077271 21.219147 22.127754 37680 3.223133 17.425327 16.915573 37681 3.198331 16.946682 17.032459 37682 3.603336 17.537579 18.371712 37683 3.951690 18.433714 19.208931 37684 4.376688 19.363577 20.124132 37685 5.027311 20.615461 21.272429 37686 55.136841 22.315750 22.952179 37687 3.244068 16.463976 17.412865 37688 3.730614 17.153503 19.149260 37689 3.968133 17.689692 19.717396 37690 3.286879 15.744446 17.972557 37691 3.534448 16.457237 18.743404 37692 54.867157 20.412643 23.248772 37693 2.908047 14.975859 16.457924 37694 3.637700 15.741764 19.590826 37695 55.992126 20.038040 22.585396 37696 57.495026 17.711731 21.796333 37697 57.798691 16.185059 21.609535 37698 2.808442 12.400259 17.678823 37699 57.663681 15.160309 21.492119 37700 2.392792 10.364910 15.926899 37701 46.985596 13.547089 21.993774 37702 48.957764 13.965775 22.734795 37703 54.992035 14.013885 21.571190 37704 2.276757 9.435792 15.313747 37705 2.416490 9.682158 16.884243 37706 2.290048 8.549804 16.374109 37707 2.179296 7.629845 15.839285 37708 46.312744 12.958527 22.009537 37709 48.307587 10.869949 21.165131 37710 47.836731 11.000961 22.429031 37711 49.118530 10.941467 22.331635 37712 54.099472 8.878311 21.177017 37713 54.321960 9.673569 22.099327 37714 54.276184 9.163940 22.429115 37715 18.946829 9.243195 22.805906 37716 18.719061 9.254730 22.920362 37717 18.820532 9.314056 22.974531 37718 19.005911 9.233093 22.887014 37719 18.664373 9.035278 23.061377 37720 52.146393 7.492371 21.267685 37721 53.116165 8.035629 21.497520 37722 59.867691 6.168411 20.930946 37723 47.753387 6.239670 21.486099 37724 51.179947 7.085800 21.182182 37725 57.657867 6.165588 20.960236 37726 58.833603 6.461258 21.299103 37727 58.052246 6.303787 22.027985 37728 59.182129 6.350021 22.073059 37729 60.334335 6.230194 20.249435 37730 45.661530 5.308319 21.005821 37731 55.212433 4.919296 21.072899 37732 56.386200 5.525497 21.951057 37733 59.834595 5.267548 22.951553 37734 59.832458 5.653107 21.983505 37735 59.661453 4.301239 21.942299 37736 44.806198 4.129051 21.420128 37737 53.576996 4.031662 20.948814 37738 54.396698 4.530899 20.954544 37739 44.415039 2.477783 22.025314 37740 44.056351 3.620544 22.574425 37741 52.649750 3.578659 20.874580 37742 58.953140 2.956161 21.687836 37743 59.289352 3.492111 23.043854 37744 50.775879 2.568649 20.757614 37745 35.326454 0.163818 19.225334 37746 46.664230 1.112061 21.474411 37747 45.554703 1.837173 21.233955 37748 47.735046 1.635101 20.250702 37749 47.659958 1.378479 20.748169 37750 57.494019 1.547440 22.055801 37751 57.987427 1.959793 21.602791 37752 59.893951 -0.705124 20.654778 37753 37.309540 -2.716888 19.358665 37754 62.128494 -3.705826 20.241623 37755 51.819275 -4.428665 19.882088 37756 52.776550 -4.913147 20.083481 37757 2.079167 -2.529662 18.900826 37758 36.345825 -3.845123 19.512108 37759 50.773849 -5.435623 20.235588 37760 51.864166 -5.319992 20.262985 37761 53.773712 -5.129059 19.864761 37762 62.318222 -4.577805 20.394493 37763 53.394104 -4.456818 19.959259 37764 55.634445 -6.294464 19.135773 37765 62.623535 -5.276123 20.150833 37766 42.535553 -6.651825 19.522568 37767 41.304077 -7.293472 20.241096 37768 43.155792 -6.970413 20.675865 37769 48.997223 -6.263107 20.786903 37770 53.268188 -6.067139 19.764259 37771 52.447784 -6.021133 20.080994 37772 33.062927 -8.658020 19.524734 37773 32.469574 -9.283813 19.200035 37774 32.746864 -9.584000 19.772232 37775 40.468292 -7.693176 20.849052 37776 39.678299 -8.399704 21.522675 37777 51.578857 -6.630661 20.188881 37778 62.962128 -7.318359 20.329353 37779 34.016159 -8.538864 20.169426 37780 34.767639 -8.230362 19.648354 37781 36.087936 -8.443695 19.691048 37782 37.628189 -8.541611 20.102257 37783 51.133667 -7.782196 19.925385 37784 50.968506 -7.330124 20.554779 37785 62.858124 -8.355347 20.912941 37786 36.946167 -9.074936 21.619247 37787 38.538834 -8.500595 20.797760 37788 45.037155 -10.522552 19.561371 37789 46.842041 -9.852844 19.798386 37790 48.539551 -9.193375 20.116226 37791 47.645706 -9.171204 20.939354 37792 45.359970 -9.189178 22.272568 37793 44.847443 -9.583710 22.264542 37794 45.400314 -9.737289 21.716621 37795 2.438073 -9.419689 19.387804 37796 2.255550 -6.876181 19.416265 37797 33.067337 -10.538696 20.372177 37798 43.674164 -11.022552 19.958679 37799 62.781830 -9.511642 21.910156 37800 2.540235 -10.556413 18.432327 37801 2.662529 -11.637581 18.809134 37802 33.069260 -11.581741 20.416946 37803 32.929482 -11.280136 19.423546 37804 33.350937 -12.262253 19.846390 37805 33.970230 -13.268753 19.574142 37806 51.077148 -13.547058 19.193726 37807 49.817352 -13.935425 19.773109 37808 50.850937 -14.024002 20.100204 37809 57.778717 -14.367310 20.696350 37810 57.319061 -15.836502 20.707245 37811 58.509583 -13.978348 20.238640 37812 59.304871 -14.117004 19.837418 37813 58.456635 -14.482803 19.816406 37814 60.203278 -14.182510 19.660568 37815 33.379936 -15.364120 20.581299 37816 43.039108 -14.924927 19.937408 37817 47.178406 -15.520874 20.149529 37818 45.031281 -17.544739 20.061661 37819 63.838028 -13.801758 21.027840 37820 2.980188 -14.083477 17.858471 37821 42.532913 -16.116638 19.850975 37822 51.396744 -14.194504 19.802971 37823 51.129089 -14.497711 20.190651 37824 61.880981 -14.825836 20.351997 37825 32.909302 -17.395035 19.354164 37826 33.590416 -16.630783 19.265091 37827 32.351196 -18.365494 19.164322 37828 39.608536 -18.592499 18.951706 37829 38.849197 -19.959991 19.092735 37830 39.964439 -19.524475 18.902374 37831 40.333588 -17.624878 19.399597 37832 39.155365 -17.842636 20.041115 37833 44.141266 -18.178894 19.408363 37834 44.519226 -17.720276 19.309952 37835 31.794931 -19.340057 19.049606 37836 37.655258 -20.557861 19.522644 37837 38.102356 -19.993759 19.066368 37838 37.879974 -19.423035 19.336243 37839 40.886383 -19.608185 19.251678 37840 43.402466 -18.688995 19.792511 37841 47.754547 -19.084854 19.863876 37842 38.344559 -18.535507 19.619705 37843 48.903381 -17.852615 20.429947 37844 48.198700 -17.990891 21.075890 37845 46.291733 -18.903915 21.728760 37846 47.247864 -18.822128 21.107407 37847 47.350494 -17.878082 21.727509 37848 58.320206 -19.628494 19.328766 37849 39.849022 -20.274567 19.433830 37850 40.740540 -20.319107 20.098221 37851 59.369171 -20.750458 19.552040 37852 31.252975 -20.543839 18.789452 37853 59.962479 -21.687851 19.312157 37854 60.358307 -20.970688 20.203758 37855 60.773941 -21.848923 19.656464 37856 59.257812 -22.436859 19.053459 37857 61.817368 -21.933975 20.372581 37858 4.904144 -23.417683 17.398170 37859 4.530801 -22.740240 18.392479 37860 43.841461 -22.906143 19.077850 37861 44.416595 -22.311005 19.115234 37862 49.347763 -23.175949 20.087990 37863 53.926834 -22.886185 20.403259 37864 54.962692 -22.374252 19.429947 37865 55.836334 -22.778778 19.807388 37866 56.773621 -22.654282 19.400543 37867 57.914047 -22.623154 19.119904 37868 58.584564 -22.595245 18.963524 37869 59.330719 -23.134399 19.469452 37870 60.460403 -22.892532 19.634422 37871 62.361115 -23.540955 20.603691 37872 62.852417 -22.737869 21.406090 37873 42.257965 -24.816315 19.574837 37874 43.012238 -22.938538 20.416130 37875 41.902740 -24.077072 20.323135 37876 48.222961 -23.994431 19.495094 37877 58.715729 -22.897461 19.258499 37878 42.665710 -25.931976 19.895866 37879 47.670044 -25.834885 19.059425 37880 46.508575 -25.814163 18.488548 37881 5.264619 -24.852102 17.203329 37882 29.536423 -25.563110 18.528221 37883 36.219429 -25.979935 18.365959 37884 36.811859 -26.432526 18.041924 37885 30.257019 -26.640793 18.313026 37886 29.646851 -26.478073 19.406509 37887 30.160538 -27.095581 19.174950 37888 30.671814 -27.111786 18.745628 37889 35.868446 -26.596054 18.435738 37890 44.505234 -26.625656 18.954887 37891 46.245941 -26.770813 18.807648 37892 47.903915 -26.677429 19.189705 37893 47.246124 -26.608429 18.909897 37894 6.296419 -28.630234 16.127951 37895 45.065552 -27.577591 19.604782 37896 45.483643 -29.418839 20.614998 37897 47.615158 -27.806824 19.893860 37898 48.827759 -26.517242 19.614983 37899 34.654556 -27.219559 18.597794 37900 5.020478 -31.982327 19.753347 37901 5.012113 -32.790817 20.144827 37902 5.097103 -30.995481 19.194412 37903 5.049933 -30.069683 19.055847 37904 4.825717 -30.224373 19.761017 37905 5.499409 -30.336920 18.054071 37906 4.775552 -30.673397 20.104561 37907 4.674307 -31.013288 20.714914 37908 4.864210 -31.422949 20.108282 37909 5.527248 -27.100670 17.302197 37910 5.659963 -28.156170 17.218359 37911 34.193024 -29.919937 18.943062 37912 34.607376 -28.737534 18.737709 37913 4.835638 -32.235130 20.781080 37914 6.694243 -30.017569 15.795401 37915 34.544113 -31.582779 19.726173 37916 34.239563 -31.032318 19.287331 37917 63.140594 -31.596802 18.572594 37918 37.227463 -31.887497 19.417168 37919 58.106552 -32.018051 19.472496 37920 56.660553 -32.628403 19.588142 37921 59.592499 -30.974884 18.566368 37922 46.124969 -34.274918 18.183067 37923 55.325851 -33.178085 20.064384 37924 54.184570 -33.570312 19.327759 37925 53.153809 -33.862259 18.672623 37926 37.551292 -35.536880 19.037941 37927 37.203476 -34.634644 19.036072 37928 42.837357 -35.554810 18.048386 37929 61.271149 -35.867630 18.051094 37930 38.934982 -36.395905 18.804695 37931 38.724785 -36.254684 17.940269 37932 41.336334 -36.049637 18.034241 37933 42.242615 -35.950974 19.137779 37934 61.718506 -37.042786 18.503464 37935 62.160416 -35.715576 19.378014 37936 5.196301 -34.952744 20.746033 37937 5.102899 -34.649937 21.468508 37938 62.274948 -37.333359 19.507584 37939 61.050369 -37.038803 17.696228 37940 5.324498 -35.287807 20.178576 37941 5.685415 -36.688877 19.437792 37942 6.039545 -37.209278 18.437424 37943 62.261383 -38.419098 18.552132 37944 6.216967 -39.140751 17.862444 37945 6.247009 -40.347412 16.632591 37946 6.143548 -40.102455 17.846893 37947 62.687698 -39.927856 18.518806 37948 6.232857 -40.721710 17.165771 37949 5.692650 -42.367874 16.726105 37950 54.198914 -41.367584 18.226128 37951 58.621918 -42.867508 18.025543 37952 58.047058 -42.557343 19.065269 37953 62.755264 -41.368607 17.711357 37954 41.777649 -44.783630 17.039757 37955 44.500641 -44.977188 17.683876 37956 46.040588 -46.796127 18.893150 37957 45.739731 -46.016006 18.293373 37958 44.081329 -46.422134 19.269714 37959 59.593735 -43.541031 18.046959 37960 45.793030 -45.350342 17.287376 37961 53.978195 -44.859558 18.700966 37962 41.358841 -46.115723 17.116287 37963 41.556534 -45.419571 17.455841 37964 46.864609 -45.951004 17.448647 37965 6.631516 -47.663864 16.590378 37966 6.507340 -48.783981 16.434372 37967 6.569313 -46.664368 16.788910 37968 41.720306 -47.399567 17.400833 37969 50.452087 -47.438278 17.622009 37970 51.038269 -47.584869 17.650345 37971 42.005371 -49.332886 17.675964 37972 41.480743 -48.202850 18.227043 37973 51.945679 -47.641541 17.206070 37974 52.984314 -48.036026 17.838219 37975 55.534912 -48.305573 17.585342 37976 56.062927 -47.601944 17.329140 37977 56.717484 -47.750275 17.691711 37978 5.950409 -51.436218 16.838989 37979 9.835815 -50.129074 16.179619 37980 12.085732 -50.256561 17.741806 37981 42.971405 -50.044510 16.580437 37982 56.908676 -48.776611 17.945320 37983 14.052628 -51.989136 17.254967 37984 13.838654 -53.309967 16.801788 37985 13.251816 -53.016602 16.286224 37986 12.791382 -50.250061 17.171150 37987 41.710220 -48.658371 19.163704 37988 5.683189 -51.908432 17.174454 37989 13.364487 -50.787338 17.177841 37990 42.030685 -50.951462 16.874748 37991 41.658218 -50.973602 17.980286 37992 58.103760 -50.447113 17.947083 37993 58.530884 -49.957764 18.273087 37994 57.771423 -49.795319 18.002159 37995 9.224022 -52.212158 16.545662 37996 56.790436 -50.379074 17.866104 37997 55.306213 -49.979996 18.165871 37998 55.066650 -51.295486 17.947197 37999 58.017181 -51.293198 17.790070 38000 58.738159 -51.866379 18.393761 38001 58.794937 -50.777786 18.528984 38002 5.556152 -52.820862 17.575226 38003 8.460693 -53.302261 15.955574 38004 8.240295 -54.275452 16.155815 38005 36.539780 -53.247162 17.990509 38006 37.644890 -53.381638 17.955650 38007 38.649567 -53.999283 17.238548 38008 57.991226 -52.527725 17.741707 38009 56.923843 -51.875412 17.566620 38010 57.214966 -52.826584 17.526016 38011 13.294327 -54.192474 16.301636 38012 13.262314 -55.535355 15.917664 38013 16.204514 -52.788208 18.917610 38014 16.621338 -52.858536 20.168449 38015 17.450500 -53.320801 18.559532 38016 57.491364 -53.764313 17.931320 38017 58.719940 -53.087784 18.782753 38018 16.611908 -55.375504 16.418457 38019 20.439865 -53.763611 17.553276 38020 43.798706 -54.490677 17.917847 38021 42.969421 -53.668198 18.553909 38022 6.132492 -54.635834 16.237053 38023 5.952499 -55.219849 17.073112 38024 7.738952 -55.711136 16.733818 38025 8.991310 -54.876480 17.262405 38026 15.968597 -56.421219 15.780319 38027 36.470802 -57.299179 17.532059 38028 35.771240 -55.592758 18.054337 38029 42.922943 -55.336853 16.812172 38030 44.181686 -55.792801 17.040352 38031 47.312988 -55.606613 17.488373 38032 47.802704 -55.060303 17.834770 38033 47.171844 -54.784454 17.991920 38034 45.432922 -55.722763 17.111572 38035 45.910095 -56.499008 17.049187 38036 46.524200 -55.697510 17.309280 38037 13.584503 -56.466202 15.607285 38038 15.502762 -55.458099 16.805756 38039 14.672440 -56.188385 16.065903 38040 14.327087 -54.992630 16.752090 38041 37.435837 -58.577667 16.902229 38042 42.030487 -56.722092 17.608253 38043 43.060928 -56.434235 16.734764 38044 43.939850 -56.746017 17.364182 38045 44.976334 -56.465347 17.001282 38046 46.146545 -54.781143 17.948776 38047 46.081894 -56.812042 17.249512 38048 46.961914 -56.525299 17.710808 38049 48.053268 -55.764572 17.721252 38050 20.034302 -58.336349 16.258461 38051 42.541138 -56.805756 16.951721 38052 42.923431 -56.885422 17.478813 38053 45.413651 -56.865601 17.807098 38054 18.538223 -59.644791 16.450844 38055 19.298653 -58.722153 16.838982 38056 18.198990 -58.834961 17.902267 38057 37.885353 -59.062561 17.989822 38058 37.318375 -58.558899 18.054420 38059 38.475250 -59.601486 17.119225 38060 38.930649 -59.570160 18.466988 38061 13.182678 -61.101257 15.791199 38062 14.260017 -60.867752 16.362877 38063 16.183479 -59.951736 17.663719 38064 15.915100 -60.179779 18.421730 38065 15.196495 -60.642853 17.564087 38066 17.875488 -60.907990 15.519333 38067 17.233772 -59.831207 16.937515 38068 42.087845 -60.814087 16.526772 38069 43.966293 -61.244965 17.508682 38070 43.033508 -60.954727 17.019730 38071 49.727753 -61.644470 16.210487 38072 48.807495 -61.843475 16.123627 38073 12.545837 -61.528534 16.617737 38074 12.349411 -61.559052 15.777069 38075 50.263992 -61.687302 16.099663 38076 50.683212 -64.076736 16.445190 38077 49.865936 -63.848206 16.327721 38078 50.041489 -63.230820 16.343918 38079 49.803818 -62.376328 16.379120 38080 10.106644 -64.097916 15.878662 38081 49.117889 -63.427170 16.407974 38082 47.530212 -63.289520 16.905823 38083 51.724380 -63.655502 16.364136 38084 54.412308 -63.348526 16.234688 38085 53.785217 -63.310577 16.305061 38086 54.384918 -63.679306 16.398193 38087 9.576385 -64.841507 15.865845 38088 46.633331 -62.654556 17.662300 38089 46.919678 -62.388123 17.097588 38090 48.196228 -64.546997 16.691360 38091 48.579590 -65.545105 17.383575 38092 49.613708 -64.687576 16.724861 38093 52.857925 -64.371216 16.966141 38094 51.633575 -64.620544 16.824860 38095 54.139618 -64.343582 16.614075 38096 8.169777 -66.910446 16.423515 38097 46.617386 -64.518845 17.194664 38098 47.239929 -65.415329 17.331017 38099 46.294571 -65.203995 17.379715 38100 47.358612 -64.506027 16.804420 38101 50.924103 -65.266922 17.399048 38102 54.414124 -65.179977 16.323753 38103 7.838600 -67.421280 16.754768 38104 45.061798 -68.746628 16.176102 38105 53.438110 -67.506882 16.327782 38106 46.174103 -69.188049 16.846794 38107 53.125458 -67.841919 16.583275 38108 46.298111 -68.803696 15.949776 38109 46.993439 -69.130829 16.216370 38110 50.106140 -69.537933 16.144157 38111 51.473236 -68.993927 15.999939 38112 6.074646 -71.028336 14.810989 38113 5.979904 -70.875259 15.049095 38114 5.769669 -71.044846 14.929634 38115 6.163200 -71.011658 15.153488 38116 11.352029 -70.492188 15.466721 38117 12.450768 -71.079681 15.505127 38118 38.082565 -70.225021 15.244797 38119 50.756989 -69.429962 16.273689 38120 51.570969 -69.182205 16.975403 38121 4.602799 -71.643906 15.257080 38122 4.315682 -71.990768 15.143494 38123 8.077553 -72.255142 16.183594 38124 9.436433 -72.427124 15.374054 38125 9.564545 -73.187180 16.963371 38126 13.893037 -71.808685 15.042534 38127 11.527122 -73.054871 14.809120 38128 10.605209 -72.838821 15.075493 38129 38.326828 -70.557449 15.470253 38130 40.683914 -72.755676 15.498428 38131 39.620766 -72.373489 15.621834 38132 41.745911 -72.341293 15.777420 38133 41.523682 -70.817673 16.306816 38134 40.494507 -71.615295 15.921410 38135 12.239441 -73.497101 15.363640 38136 10.972710 -73.308685 15.943527 38137 14.138657 -72.733093 14.982765 38138 13.715195 -73.191788 14.943146 38139 31.223473 -72.932297 16.535789 38140 31.247047 -73.364960 15.801750 38141 42.760361 -72.475403 16.062119 38142 13.066460 -73.450729 15.350510 38143 43.547791 -73.280243 16.040550 38144 4.865616 -76.342682 15.391510 38145 9.723984 -75.760651 13.721405 38146 32.010330 -75.210175 15.398804 38147 32.236740 -74.375671 15.949387 38148 32.471817 -75.296432 15.964233 38149 44.429657 -74.261124 15.954025 38150 44.353668 -75.271393 15.379112 38151 4.209160 -73.798859 16.657784 38152 4.303001 -74.627518 17.153793 38153 11.026627 -77.083740 14.550972 38154 13.583298 -77.018753 14.722771 38155 27.772758 -76.746811 15.484253 38156 30.681152 -78.272781 15.191284 38157 30.675629 -77.334976 14.845154 38158 31.916925 -76.571457 15.687798 38159 45.202454 -75.201431 15.885277 38160 45.121185 -76.151230 15.453819 38161 45.632889 -75.946396 15.974991 38162 44.996887 -77.065948 15.285065 38163 45.489761 -76.744080 15.941528 38164 5.077942 -77.043015 14.708664 38165 5.759331 -77.754700 14.468575 38166 6.997330 -78.347656 14.834625 38167 8.089462 -79.373337 14.736435 38168 5.681610 -77.336685 15.343933 38169 6.453430 -77.692535 16.020706 38170 8.236404 -78.348694 16.569443 38171 7.915123 -78.471405 15.780823 38172 6.425842 -77.480957 17.578911 38173 8.719009 -78.853073 15.999512 38174 8.622025 -79.690369 15.348412 38175 31.538330 -78.113205 16.188774 38176 44.911026 -77.698898 16.270370 38177 12.879921 -80.140030 14.658661 38178 13.894943 -79.788513 15.757584 38179 14.551758 -80.287216 15.398117 38180 14.490097 -79.268066 16.017403 38181 17.619736 -79.175201 14.374260 38182 30.281540 -79.352737 15.236298 38183 8.305000 -80.700607 15.420349 38184 16.572754 -79.891800 14.547112 38185 26.481369 -79.524063 15.842751 38186 29.866440 -80.044250 14.981789 38187 7.161804 -82.173691 14.815094 38188 13.725372 -80.564392 15.173218 38189 13.199074 -79.477783 15.488739 38190 13.456467 -81.341278 14.503227 38191 25.373344 -81.514038 15.310791 38192 29.528778 -81.141617 15.141167 38193 7.636261 -81.390305 15.246048 38194 8.637260 -80.151138 15.750244 38195 13.327362 -82.213684 13.945427 38196 35.646881 -83.002762 16.419792 38197 36.074333 -83.536118 17.140869 38198 36.423935 -82.971954 15.943489 38199 13.887352 -82.652130 13.990799 38200 36.208038 -82.708923 14.809120 38201 35.617676 -82.462021 14.209000 38202 7.294838 -83.263077 14.378952 38203 7.943237 -84.240417 13.970337 38204 23.257317 -84.227737 15.743355 38205 24.053787 -83.463913 16.028511 38206 29.402374 -82.455246 15.815018 38207 29.302849 -83.637726 16.642975 38208 35.191666 -82.808701 15.255997 38209 41.422195 -83.250427 16.598419 38210 40.930389 -84.176651 14.988167 38211 40.041290 -84.644775 15.914116 38212 26.536362 -85.407776 14.592262 38213 28.441849 -85.577316 16.755219 38214 27.586838 -86.209610 15.935158 38215 37.418182 -83.936234 15.442245 38216 7.237312 -86.879715 13.724907 38217 8.890839 -86.125717 14.132965 38218 38.757782 -85.021210 15.355850 38219 39.808121 -85.132797 14.671326 38220 8.238022 -86.560226 14.027527 38221 7.240631 -86.942551 14.995003 38222 8.870804 -85.826996 15.031540 38223 22.236183 -86.164047 15.681213 38224 25.935623 -86.347855 14.228622 38225 22.314316 -88.261292 14.602814 38226 25.680084 -88.254578 13.746658 38227 6.472992 -87.742432 15.356796 38228 22.361916 -88.914322 14.336548 38229 22.555893 -89.237640 14.266220 38230 31.570435 -88.858459 15.243492 38231 31.734156 -89.345703 14.630951 38232 30.726700 -89.064697 15.463730 38233 34.145721 -89.029312 14.483963 38234 15.229042 -89.911407 14.585701 38235 26.337799 -87.933929 14.402985 38236 8.112923 -91.597229 16.516426 38237 9.306778 -91.921112 15.787636 38238 13.125488 -90.596634 13.940399 38239 14.367470 -89.832840 14.158707 38240 29.044525 -88.856400 15.888504 38241 28.836693 -89.869400 15.087120 38242 30.253586 -91.958389 14.077126 38243 30.225815 -91.160034 14.352600 38244 32.334908 -89.046326 15.221298 38245 33.459076 -89.040009 15.302811 38246 9.840515 -92.397125 13.402199 38247 11.224495 -92.350952 13.412613 38248 10.879494 -91.364120 14.574440 38249 11.981575 -91.114975 14.033043 38250 27.992249 -88.573868 15.646393 38251 10.204498 -91.851608 14.017784 38252 12.285461 -92.879349 12.849915 38253 29.588989 -91.815262 14.263977 38254 29.362686 -93.453049 13.312141 38255 15.942383 -91.603043 15.432610 38256 10.311386 -94.743820 12.620209 38257 13.878433 -95.313370 13.974045 38258 13.469009 -96.763336 13.612434 38259 13.144547 -94.804214 16.729538 38260 13.238861 -95.627167 16.481667 38261 13.320694 -94.911316 15.690605 38262 13.160530 -96.204758 14.756531 38263 14.028886 -98.290604 13.384148 38264 24.198029 -97.877274 13.365112 38265 23.186218 -97.860199 14.083611 38266 18.275314 -98.401978 14.859688 38267 20.587662 -98.699326 13.980362 38268 22.182671 -98.747116 13.540314 38269 14.903587 -99.426544 13.252159 38270 23.187775 -96.980835 15.027664 38271 21.873901 -97.546722 14.925987 38272 7.863861 62.244537 23.894272 38273 4.578110 61.794189 23.604210 38274 6.675949 61.816376 24.313408 38275 9.129105 61.997818 23.531090 38276 17.006676 62.549637 25.598274 38277 15.796234 63.005142 25.825027 38278 16.045715 62.957184 24.990051 38279 4.786797 60.594116 24.265144 38280 13.733337 60.256805 23.930962 38281 19.567657 62.209137 24.350487 38282 20.189209 61.425873 24.244545 38283 12.403854 60.900665 25.713593 38284 11.971039 59.722397 25.434593 38285 19.275345 61.824982 24.820053 38286 13.379280 61.614944 25.360870 38287 18.799072 60.335205 24.900070 38288 19.398476 61.050827 24.804161 38289 20.914490 58.300064 23.848930 38290 22.018326 57.398041 24.034805 38291 25.357285 56.853867 24.275658 38292 22.266258 56.311279 24.264420 38293 23.149368 56.881927 24.430908 38294 12.274704 56.687500 23.952660 38295 21.805969 55.326813 23.996941 38296 23.308380 55.751312 24.468094 38297 25.452988 55.181625 24.436172 38298 9.339157 55.323273 23.965309 38299 8.659866 55.355377 24.232353 38300 7.787796 55.203354 24.604546 38301 11.932220 56.347855 24.110222 38302 20.461548 55.168549 23.350533 38303 8.984238 54.504700 24.915169 38304 10.565765 54.999634 24.852448 38305 21.200317 54.235062 23.568382 38306 26.564537 54.005142 24.190102 38307 27.785576 54.663116 24.079269 38308 22.376923 52.984497 23.620514 38309 25.426788 53.123413 23.953850 38310 25.516235 53.858368 24.363106 38311 26.617157 53.101212 23.545464 38312 23.103897 54.324020 24.224945 38313 23.477684 53.303070 24.055420 38314 24.497253 53.611267 24.238632 38315 26.911346 54.820892 24.366638 38316 4.666489 50.631210 23.597984 38317 17.407028 50.103348 23.676125 38318 34.927917 50.272400 24.420380 38319 34.393433 50.922852 24.846054 38320 32.769409 51.018341 25.212906 38321 4.535935 49.065216 26.340302 38322 5.221008 48.592545 26.605667 38323 5.918282 48.581177 25.704994 38324 5.779907 49.836700 23.261040 38325 35.955193 49.178085 24.529396 38326 5.576553 49.436081 24.181160 38327 29.467598 47.621063 23.070953 38328 31.642832 49.764160 25.478065 38329 30.619522 47.931427 24.087196 38330 35.888153 48.012604 23.451897 38331 10.287613 46.386612 23.484634 38332 10.479691 45.591858 23.736397 38333 10.105896 45.554260 23.140015 38334 10.469711 46.024811 24.413940 38335 28.819275 46.685425 23.156998 38336 30.030243 46.916824 23.795929 38337 36.643768 47.652252 23.870003 38338 39.219688 46.629364 24.653465 38339 37.519165 47.975342 24.863754 38340 4.048699 45.048477 23.803528 38341 4.263252 45.695312 22.906120 38342 6.293076 45.388367 23.146393 38343 18.960686 47.696930 24.024345 38344 18.475929 48.500565 24.124191 38345 19.969803 47.048340 24.373871 38346 29.492203 44.552368 23.616302 38347 29.708199 43.430267 23.623528 38348 8.092911 44.567932 24.257111 38349 8.336571 44.377594 25.840439 38350 6.433075 44.947754 24.485512 38351 9.685333 44.851273 23.470192 38352 10.252029 45.148468 23.605873 38353 29.878326 45.866623 23.887741 38354 30.952072 44.833893 25.000893 38355 30.780151 43.468842 24.940681 38356 30.402534 43.785156 24.216003 38357 38.450737 47.279892 24.844406 38358 10.212059 45.001526 24.291351 38359 3.154816 42.425842 25.205292 38360 3.231194 43.433502 25.594444 38361 29.623917 41.521194 24.386559 38362 29.001175 40.415405 24.520332 38363 28.258644 40.827850 23.269951 38364 43.491638 42.722748 24.478699 38365 42.755615 43.703033 23.982391 38366 5.346161 40.224304 23.442749 38367 21.407761 43.726395 23.656090 38368 3.485680 41.606506 25.008171 38369 3.973763 40.578552 25.030655 38370 23.824921 40.971100 23.267754 38371 29.709457 41.013458 25.716461 38372 29.211052 40.249863 25.458092 38373 6.212814 39.930664 22.938477 38374 25.162766 40.133072 23.616211 38375 27.819550 39.970917 24.119164 38376 28.479813 39.920990 25.345100 38377 45.649368 40.062775 23.479279 38378 6.960190 39.457428 23.193222 38379 7.879730 38.869095 23.617668 38380 8.817245 38.887543 22.706116 38381 26.184258 39.956573 23.897682 38382 45.469711 38.920715 24.242096 38383 13.242981 34.826385 22.811348 38384 12.695526 35.844254 23.252357 38385 35.838310 36.130310 23.808037 38386 35.503128 36.129501 23.818604 38387 35.893234 37.186264 24.353104 38388 36.508972 36.119202 23.982307 38389 13.115326 33.841385 23.164780 38390 35.172401 36.121078 24.004158 38391 35.506516 35.359207 24.131905 38392 34.263168 36.010269 24.556740 38393 45.145721 36.427002 24.701782 38394 44.677887 35.226898 24.624001 38395 44.936325 35.909225 25.440849 38396 45.568604 31.550446 24.743813 38397 45.403854 32.292145 25.256348 38398 3.447838 32.647583 21.980278 38399 4.295616 33.063446 22.266449 38400 2.805359 31.319672 22.363434 38401 3.585137 31.385071 23.438797 38402 5.062584 33.138062 22.244484 38403 5.851631 32.259491 22.681938 38404 4.461456 32.373337 22.790108 38405 7.187439 31.548569 22.541710 38406 8.176430 30.603546 22.695541 38407 7.036087 30.682617 23.467216 38408 13.336807 31.351135 22.452202 38409 8.072937 31.219009 22.226738 38410 2.479248 29.339996 24.079681 38411 6.097595 31.291901 23.328140 38412 12.278893 29.069763 22.452858 38413 12.490631 28.859680 23.414429 38414 11.757797 28.358093 22.680756 38415 13.111465 30.738129 22.610390 38416 43.450287 30.426392 23.478470 38417 43.185318 29.496796 23.860458 38418 2.971542 27.972885 22.155754 38419 10.587257 28.406036 22.664368 38420 39.585907 27.680786 23.034813 38421 41.681976 28.765015 23.629036 38422 42.095383 29.509277 23.325233 38423 3.879814 26.589249 21.782921 38424 11.101760 28.060577 22.843048 38425 39.105759 26.643280 22.834038 38426 43.843079 25.216583 22.638649 38427 45.189316 25.321091 22.724709 38428 52.101166 26.478241 23.227661 38429 52.930862 26.308121 22.788193 38430 52.936966 26.329453 24.248039 38431 39.373306 25.904327 22.687195 38432 46.849701 24.994629 22.623177 38433 50.288208 25.810730 23.287354 38434 53.938934 25.427597 24.048599 38435 53.526703 25.538071 25.150536 38436 39.861679 24.665131 23.058647 38437 40.080673 24.452423 23.156586 38438 43.077560 24.494843 23.090714 38439 42.965134 23.872650 24.069931 38440 44.388092 24.192932 23.942345 38441 46.900848 24.518097 23.508858 38442 45.807373 24.546722 23.665756 38443 49.512512 25.225281 22.972099 38444 5.701218 23.004730 22.314919 38445 48.233292 24.773483 23.131119 38446 47.445557 24.616150 24.023422 38447 49.269287 25.668503 24.296928 38448 48.165344 25.011612 24.199699 38449 55.140671 23.593475 22.764748 38450 5.728775 22.102600 21.651474 38451 6.142334 22.098892 22.311836 38452 5.906708 20.964172 22.793091 38453 4.574257 18.912142 21.228645 38454 5.654518 19.492203 23.143784 38455 5.982033 20.104141 23.604065 38456 4.148442 17.813549 20.329208 38457 55.979294 19.065445 23.089439 38458 56.933685 17.968155 22.820007 38459 3.057373 14.368849 17.534979 38460 3.176104 13.934414 18.585350 38461 3.549744 14.426486 20.233227 38462 4.194268 17.346317 20.885584 38463 4.568076 17.930544 22.093491 38464 3.247901 13.343173 19.631474 38465 3.011623 12.911049 18.674522 38466 57.335968 16.332535 22.956718 38467 56.948212 17.356506 23.467209 38468 2.670167 11.265035 17.843296 38469 2.522871 10.763984 17.098503 38470 57.469528 15.259384 22.055328 38471 2.536418 10.361923 17.632679 38472 2.596881 10.119461 18.178783 38473 46.936981 12.967911 23.101830 38474 55.425659 13.934723 22.296761 38475 55.023819 14.037231 22.431732 38476 57.001770 14.760284 22.732544 38477 57.249298 15.191498 23.628479 38478 2.140641 6.631217 16.088787 38479 2.286433 7.436653 17.281345 38480 47.086975 11.095978 21.580994 38481 52.309494 10.447922 24.765182 38482 49.894241 11.358856 25.384529 38483 17.335241 9.805634 23.471823 38484 17.001120 9.812683 23.611853 38485 17.260504 9.978851 23.652754 38486 17.587927 9.742615 23.613745 38487 17.001333 9.254791 23.440634 38488 16.535521 9.070450 23.626860 38489 16.736715 9.461029 23.679815 38490 18.089247 9.298737 23.276243 38491 17.776426 8.601578 23.325476 38492 18.884680 9.218109 23.046202 38493 18.527960 9.124619 23.305548 38494 53.580429 8.526520 22.430603 38495 16.672766 8.270248 23.594389 38496 18.160727 8.444672 23.578009 38497 51.249451 7.227646 22.026230 38498 50.506531 6.806549 22.759865 38499 52.345551 7.717133 22.778198 38500 16.487646 7.147018 23.395430 38501 15.881590 6.757568 23.588980 38502 16.177526 7.369736 23.859755 38503 16.294775 5.452698 23.558622 38504 15.812277 5.722588 23.418821 38505 16.391150 6.100845 23.352003 38506 17.666418 7.521729 23.488157 38507 45.052536 5.067886 21.814651 38508 45.688614 5.615883 21.851212 38509 46.251373 5.940506 21.559502 38510 46.837692 6.140869 21.609543 38511 57.257751 5.970589 21.945892 38512 15.741293 6.174240 23.556410 38513 17.158216 5.389572 23.789183 38514 17.533270 6.436508 23.357298 38515 18.125410 6.534637 23.800543 38516 15.718328 5.850067 23.649923 38517 16.044928 5.572845 23.820501 38518 18.094877 5.854782 23.590956 38519 17.565329 5.738251 23.414572 38520 54.478470 4.509628 21.657280 38521 17.922689 5.467987 23.762106 38522 45.391006 5.279556 22.465302 38523 44.593872 4.551491 22.658485 38524 52.843079 3.581879 21.855766 38525 50.871063 2.496078 21.848671 38526 57.358521 0.302567 21.682808 38527 58.367599 2.355774 21.641563 38528 48.289780 1.203796 21.529587 38529 57.279648 1.072495 21.811867 38530 2.062644 4.203539 16.594339 38531 45.099487 1.172943 22.116920 38532 47.162750 0.640350 22.235580 38533 57.314453 -0.351776 21.772133 38534 57.574020 -0.326050 21.496223 38535 58.098740 -0.632233 21.807693 38536 57.515854 -0.564285 21.803123 38537 60.214310 -1.391754 21.428101 38538 61.083435 -2.639526 21.474876 38539 2.108457 0.399512 19.078180 38540 2.129630 -1.115365 19.390850 38541 60.885406 -3.794708 22.525742 38542 61.737762 -4.217606 21.227737 38543 60.347778 -2.302475 22.586807 38544 2.184578 -3.397854 20.130127 38545 62.330078 -5.463638 20.942955 38546 61.810318 -5.720093 21.610275 38547 44.483200 -6.838272 20.790924 38548 42.374466 -7.751648 21.735588 38549 45.530792 -6.726929 20.776855 38550 46.514862 -6.629822 20.680382 38551 47.742340 -6.953857 21.003647 38552 50.765701 -6.591675 20.759224 38553 49.859344 -6.523407 20.877930 38554 44.040771 -7.579544 21.809349 38555 43.388947 -8.455765 22.516205 38556 46.211838 -7.020813 21.304161 38557 60.671677 -6.067307 22.624756 38558 61.300613 -6.841812 22.229393 38559 60.471527 -7.085495 22.811180 38560 62.313171 -6.924683 21.326729 38561 33.525146 -9.350220 20.665993 38562 34.335487 -9.274002 21.462349 38563 34.136520 -8.894104 20.833824 38564 50.365631 -7.343246 20.845901 38565 49.098877 -7.995941 20.857964 38566 61.901199 -8.287872 22.262436 38567 35.003746 -8.783417 20.799950 38568 38.443710 -8.739166 21.586121 38569 46.160034 -8.936829 21.909027 38570 47.325714 -8.355042 21.532784 38571 42.458984 -13.486725 20.336555 38572 42.220581 -14.465240 20.938126 38573 42.591766 -11.591797 20.300797 38574 42.595520 -10.980194 21.195412 38575 45.261429 -10.280853 20.655891 38576 44.161896 -10.224304 21.550125 38577 33.203751 -12.350235 20.952942 38578 63.595001 -11.079880 21.415100 38579 2.635569 -11.460554 20.275934 38580 41.639893 -13.532028 21.069145 38581 41.326630 -14.319885 21.479332 38582 56.639648 -14.834259 21.656532 38583 58.717804 -13.628738 21.047737 38584 59.647766 -14.209015 23.172707 38585 59.499741 -13.675613 21.855865 38586 58.485382 -13.343445 22.670937 38587 60.238907 -14.116287 20.562210 38588 2.898643 -13.729989 18.419584 38589 2.800494 -13.090096 19.314384 38590 3.054361 -15.411752 19.733397 38591 2.966158 -14.516028 18.987488 38592 3.025769 -14.676415 18.297670 38593 42.389679 -15.369537 20.723442 38594 49.074844 -14.871445 20.694092 38595 48.111786 -15.381012 21.012955 38596 50.877136 -15.331528 20.142906 38597 60.828949 -14.615738 21.914078 38598 62.262085 -15.145615 21.762360 38599 2.880114 -14.147161 20.123310 38600 3.162189 -15.618327 18.500134 38601 62.987549 -14.804977 20.884537 38602 63.728271 -14.675735 22.783165 38603 63.996277 -13.612274 22.252693 38604 63.400070 -14.691788 21.793671 38605 3.259730 -16.453653 18.862825 38606 3.437213 -17.278114 18.426483 38607 33.087982 -16.690689 19.998581 38608 32.631706 -17.010925 20.664162 38609 33.066833 -16.268738 20.652802 38610 33.396698 -16.181534 20.032867 38611 40.440872 -17.021362 20.423981 38612 41.466522 -16.165863 20.856888 38613 49.054840 -16.904785 21.130424 38614 49.460678 -15.825775 21.128860 38615 48.620575 -15.978729 21.370667 38616 57.785141 -17.933090 19.538177 38617 3.660966 -18.346367 18.309366 38618 39.402176 -17.226410 21.135330 38619 40.184265 -16.757767 21.283783 38620 49.651550 -16.771973 20.608437 38621 3.937535 -19.831669 18.487204 38622 4.276844 -21.266853 18.167454 38623 31.175842 -19.743607 19.898117 38624 31.724581 -18.722168 20.115234 38625 32.232712 -17.820267 20.235413 38626 37.501053 -18.558243 20.434906 38627 38.183907 -18.230423 20.195435 38628 57.874023 -18.874283 19.896912 38629 57.157532 -17.581879 20.992676 38630 30.830078 -20.523239 20.806038 38631 31.381195 -19.371918 20.962814 38632 35.969147 -20.438614 20.178894 38633 35.893616 -19.520493 20.935776 38634 35.252151 -20.347977 20.766632 38635 35.220589 -19.714233 21.338730 38636 36.689499 -19.381424 20.240479 38637 36.800537 -20.093948 19.640587 38638 42.058411 -19.551941 20.045456 38639 42.006256 -20.360947 21.348297 38640 45.790009 -21.003113 19.636703 38641 57.684219 -19.627625 22.656349 38642 57.447189 -18.997040 21.401138 38643 58.663269 -19.877869 20.722191 38644 59.123184 -19.839737 22.952332 38645 4.201461 -22.564938 19.844107 38646 4.646642 -23.908503 18.663698 38647 30.329483 -21.734451 20.293640 38648 30.705460 -20.841003 19.726624 38649 36.585648 -20.693466 19.739273 38650 36.493668 -21.488495 20.325859 38651 38.999908 -20.945999 20.095230 38652 39.883621 -20.692276 20.056282 38653 62.016998 -20.822693 21.100922 38654 61.249649 -20.746017 20.999985 38655 62.446075 -21.142548 21.041702 38656 37.823746 -21.584091 20.653702 38657 40.194061 -20.983017 20.935196 38658 44.094070 -22.338684 19.831078 38659 44.724350 -21.851913 19.707367 38660 45.185669 -20.821747 21.055832 38661 46.253265 -19.871094 20.933174 38662 62.498978 -20.753647 21.874084 38663 51.855286 -22.871613 20.513969 38664 52.861267 -22.767639 20.411385 38665 58.584259 -23.352859 19.744896 38666 3.809643 -20.595528 21.256008 38667 4.070818 -21.208517 19.445553 38668 29.538536 -24.367462 19.486397 38669 57.568756 -23.706467 20.160767 38670 59.470825 -23.928833 19.851562 38671 58.639008 -24.995621 20.260742 38672 59.759232 -24.879196 19.936142 38673 60.251694 -25.448212 20.070595 38674 60.771378 -24.545334 19.982407 38675 61.627228 -23.638611 20.108261 38676 62.749817 -21.532928 21.414803 38677 41.654617 -25.186844 20.192749 38678 59.609100 -25.470840 20.110672 38679 59.893433 -26.352051 20.703873 38680 60.901718 -25.595154 20.357094 38681 61.831665 -25.052246 20.631866 38682 62.673126 -24.155991 21.265640 38683 34.363907 -26.037643 18.168983 38684 48.620819 -24.951874 19.823669 38685 50.016159 -25.781174 20.140907 38686 50.276031 -27.306473 19.958580 38687 29.465530 -25.262558 20.206345 38688 31.304108 -28.310211 21.452728 38689 30.969177 -28.068497 20.583626 38690 33.927513 -28.703918 19.308182 38691 34.097672 -28.078278 19.158188 38692 43.746246 -26.861069 19.826462 38693 51.271896 -27.401993 19.883354 38694 50.985138 -26.512466 19.974930 38695 51.368835 -25.035721 20.678162 38696 55.292633 -25.946564 20.273537 38697 55.464401 -24.435776 20.996956 38698 54.248596 -24.449951 21.083046 38699 56.744827 -25.040512 20.530106 38700 5.373574 -26.071615 17.389885 38701 4.913636 -25.156189 18.287630 38702 49.285736 -27.769699 20.073410 38703 51.930252 -26.768402 19.968079 38704 52.024597 -27.833023 20.215988 38705 52.796127 -27.379532 20.001381 38706 53.003235 -26.014481 20.308540 38707 54.240845 -26.342789 20.164139 38708 53.863861 -27.518173 20.136200 38709 55.147369 -27.160477 20.064819 38710 56.213455 -27.743393 20.775314 38711 56.564926 -28.332260 21.820534 38712 57.431732 -27.918884 21.352631 38713 55.531860 -26.680832 19.963409 38714 54.793198 -28.557159 21.914787 38715 5.500312 -28.059204 17.533550 38716 51.892746 -28.499146 21.394943 38717 51.159210 -28.019241 20.427597 38718 50.357437 -28.389572 21.115944 38719 54.851685 -28.099609 20.624306 38720 34.449280 -30.928528 18.644966 38721 41.709167 -30.603989 19.359650 38722 42.230408 -29.768158 19.743843 38723 40.836731 -29.868698 20.104172 38724 42.597015 -30.264191 19.404076 38725 43.439819 -29.828262 19.900681 38726 40.839478 -30.718933 19.368462 38727 42.377304 -30.791687 19.324867 38728 42.891693 -30.790451 19.638420 38729 60.716309 -31.775284 20.200729 38730 59.428986 -31.417664 19.352715 38731 62.241882 -31.424103 19.334526 38732 38.104576 -31.770020 19.260429 38733 38.789520 -30.964355 19.821999 38734 37.920311 -31.201660 19.862312 38735 39.968880 -31.038177 19.447205 38736 39.979202 -32.235916 19.355766 38737 40.940308 -31.467239 19.337044 38738 42.000565 -31.478485 19.619186 38739 43.630890 -30.695038 20.059906 38740 42.957748 -31.506973 20.411110 38741 44.330460 -30.722137 20.867683 38742 36.116577 -31.737488 19.902954 38743 35.130447 -31.681686 19.993027 38744 38.902130 -32.056152 19.190170 38745 40.025909 -32.807648 20.019562 38746 41.125870 -32.235916 19.990982 38747 57.552338 -32.550400 20.496376 38748 38.800972 -33.078506 19.580902 38749 49.288818 -34.386337 20.583328 38750 62.609512 -34.005493 19.628410 38751 47.388824 -34.720612 21.060135 38752 46.579041 -34.455536 20.175186 38753 48.286316 -34.489349 20.759346 38754 38.601524 -36.331879 19.942101 38755 37.622452 -35.716583 20.158867 38756 44.797729 -35.115082 20.342781 38757 43.841522 -35.571060 20.850525 38758 40.202682 -36.500702 19.877068 38759 40.735214 -36.395279 18.940933 38760 41.485809 -36.217804 19.883575 38761 38.333084 -36.124100 20.866531 38762 39.735291 -36.485855 20.945877 38763 5.425755 -36.075150 20.264372 38764 5.849529 -37.885040 19.203518 38765 5.927492 -39.358231 18.970110 38766 62.614044 -39.369995 20.501724 38767 6.272408 -41.222900 17.569687 38768 53.216476 -42.030106 18.086678 38769 53.107315 -41.503357 18.996445 38770 53.912872 -41.196442 19.137337 38771 54.808350 -41.263565 19.129677 38772 55.990173 -41.576920 19.204559 38773 56.960358 -41.765808 18.752419 38774 5.404160 -42.890289 17.484436 38775 5.972679 -42.003128 17.751862 38776 5.523338 -42.463470 18.793655 38777 52.300781 -42.470901 18.982330 38778 57.506042 -42.006027 18.902039 38779 51.298889 -43.013077 19.815453 38780 51.256958 -44.019012 19.918015 38781 50.487640 -43.874939 20.525368 38782 58.927765 -43.253448 19.024475 38783 62.653549 -41.503845 18.981789 38784 62.096008 -43.121658 18.916687 38785 5.679634 -45.096451 17.568687 38786 5.159821 -44.403931 17.835777 38787 5.076416 -43.653580 18.166245 38788 41.809692 -46.296127 18.461876 38789 52.138260 -43.792313 19.209595 38790 60.014343 -43.778244 19.286980 38791 61.287506 -43.716354 18.935242 38792 61.605316 -43.791122 18.269791 38793 6.268158 -45.690552 17.565323 38794 6.550606 -46.192947 17.425552 38795 41.720001 -47.445084 19.317032 38796 42.507202 -46.907898 19.561089 38797 42.803055 -45.717361 18.884163 38798 54.277618 -45.389877 19.367416 38799 6.794968 -47.144424 17.495613 38800 45.255783 -47.841537 19.870842 38801 45.877686 -47.337372 19.335152 38802 47.154709 -46.684021 18.273155 38803 55.301239 -46.430817 19.679390 38804 47.266449 -47.471481 18.900208 38805 48.361404 -47.364670 18.303757 38806 49.242523 -48.194305 18.560524 38807 50.601959 -48.315079 18.331314 38808 57.078049 -47.334061 18.487823 38809 6.827217 -48.517410 17.637711 38810 41.433105 -47.532089 18.606926 38811 51.748306 -47.959518 18.041855 38812 56.914734 -47.544846 18.901543 38813 6.352623 -50.235764 16.835106 38814 9.978134 -50.964828 16.958153 38815 10.641319 -50.604965 17.538879 38816 41.914886 -50.163605 19.184624 38817 54.966873 -48.645798 18.082237 38818 54.009644 -48.751511 18.277824 38819 54.885345 -49.243683 18.363739 38820 55.755981 -49.198380 18.081535 38821 57.596573 -48.630066 18.815033 38822 57.979996 -49.291626 18.283752 38823 57.837845 -49.638565 20.141037 38824 56.375748 -48.282196 20.371857 38825 6.656296 -50.108261 18.989708 38826 7.504990 -48.333313 19.216942 38827 11.249458 -50.110855 17.473679 38828 11.233398 -50.772415 18.070412 38829 13.105499 -50.628006 18.519951 38830 13.741730 -50.514267 18.135429 38831 14.069962 -50.872528 17.991508 38832 53.785995 -50.973923 18.221237 38833 54.038055 -49.970993 18.391441 38834 58.482986 -49.564697 18.828819 38835 58.881180 -50.083725 18.685966 38836 9.822243 -52.081070 17.252556 38837 10.513611 -51.943253 17.902466 38838 53.056061 -52.857117 18.497650 38839 53.751343 -51.793320 18.173447 38840 52.747772 -50.953033 18.540924 38841 5.196854 -54.616501 18.570862 38842 41.467316 -52.070526 18.002991 38843 56.179733 -52.812759 17.717758 38844 58.285583 -54.501953 18.630333 38845 58.474380 -54.720367 19.315521 38846 58.733444 -53.997238 19.199493 38847 9.594940 -53.066757 17.367943 38848 8.912582 -53.549088 16.713638 38849 20.157936 -53.225250 18.441666 38850 54.811707 -54.063568 17.984657 38851 55.809052 -54.089005 17.889374 38852 54.628510 -52.940674 18.007584 38853 54.853210 -55.723083 17.994934 38854 56.045471 -57.305923 18.216347 38855 56.607544 -56.624588 18.187889 38856 14.086044 -54.053116 16.975822 38857 14.810715 -53.331726 17.474014 38858 14.784576 -54.307312 17.279449 38859 19.818985 -53.479843 17.026047 38860 20.752945 -53.433594 18.603928 38861 21.218811 -54.863358 17.880455 38862 35.938179 -53.854080 18.514297 38863 54.160339 -53.949341 18.186424 38864 57.153183 -55.470459 18.290565 38865 5.732124 -51.537369 18.070305 38866 8.235298 -56.096588 17.236610 38867 8.866577 -56.229996 17.615784 38868 39.660980 -55.121399 17.835449 38869 45.066330 -54.755341 17.913361 38870 48.977905 -53.285477 19.556961 38871 50.583191 -54.263947 18.835388 38872 50.093842 -52.796158 19.570229 38873 7.109612 -56.498230 17.395393 38874 15.766357 -55.915024 16.377106 38875 40.895386 -56.138901 17.852684 38876 47.863068 -54.616852 18.216759 38877 48.668243 -54.708511 18.418037 38878 49.481506 -55.953918 18.019501 38879 47.874496 -54.067535 18.857201 38880 51.712280 -54.069153 18.810883 38881 52.403870 -55.514771 18.169373 38882 50.896652 -55.819473 18.020569 38883 51.491333 -56.733536 18.036057 38884 53.402084 -54.417725 18.286018 38885 55.309952 -57.693954 18.333038 38886 57.303223 -56.730148 18.543877 38887 21.616257 -55.467728 18.737404 38888 21.460281 -56.194443 19.036522 38889 36.019112 -56.938782 18.664024 38890 40.211166 -55.709885 19.699463 38891 48.204758 -56.501785 17.868820 38892 48.753723 -56.883286 18.574562 38893 49.957794 -56.958694 18.355347 38894 50.543884 -56.571060 17.932716 38895 53.499207 -56.925659 17.990265 38896 52.528168 -57.240204 18.234390 38897 54.310043 -57.659103 18.287766 38898 19.121124 -58.173050 17.903564 38899 36.999321 -58.148117 17.691101 38900 43.090088 -56.839737 19.362862 38901 47.831070 -56.859360 18.450195 38902 50.833344 -57.136398 18.239868 38903 53.352936 -57.758499 18.293533 38904 56.890732 -57.573380 18.843712 38905 57.442673 -57.107010 18.999084 38906 20.030258 -57.608231 17.813080 38907 56.043396 -58.257431 18.849594 38908 12.722343 -61.106354 16.317276 38909 13.299903 -61.149017 16.667580 38910 14.107597 -61.108658 17.255852 38911 39.547035 -60.188324 17.260170 38912 40.557495 -60.662292 17.299492 38913 41.695099 -60.788742 17.815186 38914 45.802551 -61.670975 17.037148 38915 44.646515 -61.435974 17.255753 38916 47.267807 -61.683884 16.321854 38917 9.906876 -65.205124 16.739624 38918 46.193161 -63.532959 18.160454 38919 46.488983 -62.069077 19.021095 38920 53.337692 -65.214615 17.871437 38921 52.684082 -65.216309 18.013992 38922 51.963043 -65.069626 17.481697 38923 49.845520 -65.777786 17.865341 38924 45.339233 -64.804199 18.004539 38925 46.174835 -65.744568 17.922043 38926 53.793335 -65.568588 17.234322 38927 53.632294 -66.300507 17.934700 38928 53.600464 -65.708847 18.100487 38929 53.491302 -67.057220 17.132362 38930 8.103928 -69.110794 16.595909 38931 52.671417 -68.040436 17.937035 38932 8.303146 -70.033890 17.207176 38933 7.733444 -69.410294 18.018456 38934 9.134720 -69.530182 15.854561 38935 40.290894 -69.513550 16.335785 38936 41.464905 -69.356003 16.281181 38937 43.183594 -69.083237 16.341759 38938 5.857720 -71.022247 15.268326 38939 8.991837 -70.106430 16.566841 38940 11.257324 -70.998672 16.368500 38941 10.230972 -70.327087 16.044266 38942 9.815750 -70.932938 17.159714 38943 40.328217 -70.357712 16.182846 38944 42.505936 -70.186615 16.672066 38945 47.287796 -69.667419 17.275208 38946 48.626663 -69.872299 17.197098 38947 49.135681 -70.254608 18.118744 38948 50.123062 -69.778305 17.120216 38949 50.217072 -70.113525 18.199989 38950 50.749405 -69.930420 19.010330 38951 51.580292 -69.358093 19.235893 38952 51.389145 -69.387665 18.214432 38953 4.475845 -74.813309 17.776291 38954 4.603104 -73.877396 17.912453 38955 4.816078 -72.067734 16.298309 38956 6.059334 -71.290817 15.704697 38957 6.943939 -71.620972 15.880264 38958 5.548782 -71.596878 16.364052 38959 6.223785 -71.647842 16.536446 38960 5.915711 -72.115341 17.280380 38961 42.634933 -71.361496 16.430084 38962 8.024796 -72.740112 17.397591 38963 43.651245 -72.055603 16.642662 38964 13.493660 -72.918564 15.614143 38965 28.411499 -73.498886 16.413589 38966 29.108627 -72.790817 16.508636 38967 31.807207 -73.226044 16.374649 38968 31.907831 -73.667999 15.939537 38969 32.233521 -73.645020 16.600174 38970 46.060928 -72.739197 18.128052 38971 46.094971 -72.040878 18.719978 38972 45.449814 -71.449554 18.506821 38973 44.769135 -73.173691 16.771400 38974 12.291344 -73.252579 16.475143 38975 11.070274 -73.384338 17.363617 38976 27.891457 -74.472214 16.821381 38977 45.303650 -74.322662 16.383453 38978 45.877930 -75.123032 16.484138 38979 12.779419 -77.278290 15.244263 38980 27.751541 -76.031860 16.752449 38981 33.598869 -76.129929 17.192291 38982 32.699905 -74.574097 17.038063 38983 33.338730 -75.107895 18.868980 38984 46.424164 -75.888901 17.671959 38985 46.498413 -75.090088 17.447418 38986 45.940292 -76.147827 16.777496 38987 46.058350 -76.323151 17.511894 38988 5.281151 -76.619415 16.291977 38989 11.171471 -77.756454 14.602623 38990 12.973900 -77.974884 15.720032 38991 13.624855 -77.612442 15.677307 38992 14.487549 -77.462677 15.367615 38993 32.820312 -75.698959 16.352600 38994 33.728806 -78.098511 17.768456 38995 35.639328 -78.828888 18.897385 38996 33.909821 -80.471481 19.867790 38997 45.547058 -76.896103 16.557938 38998 15.390380 -78.120285 15.632942 38999 16.287666 -78.306076 15.437210 39000 8.562698 -79.504791 16.347130 39001 16.425980 -79.549530 15.131607 39002 30.805496 -79.037064 15.862877 39003 44.238007 -78.932297 16.087875 39004 16.294861 -79.123260 15.572594 39005 25.839737 -80.717880 15.754791 39006 30.371254 -80.015121 15.815048 39007 43.759766 -79.693909 16.164009 39008 30.600883 -81.029770 16.845695 39009 30.083466 -82.415390 16.950562 39010 6.133354 -82.369980 15.553345 39011 6.473892 -82.342819 15.306633 39012 6.537720 -81.597305 15.868240 39013 6.417206 -83.100693 15.436920 39014 7.295776 -84.557846 15.494705 39015 7.605331 -81.050995 15.784256 39016 13.753052 -82.028519 14.400116 39017 43.201248 -80.231873 16.874962 39018 26.070900 -81.558517 16.593452 39019 37.082932 -83.588821 16.456688 39020 40.379807 -84.271194 16.991737 39021 37.873230 -84.365829 16.420776 39022 8.383423 -85.105362 14.823814 39023 22.556122 -85.030045 16.176018 39024 39.137589 -84.751770 16.753471 39025 8.532303 -86.407181 15.097336 39026 34.392303 -85.208023 15.502266 39027 34.866852 -85.977112 16.147476 39028 34.678551 -84.902695 16.488037 39029 35.132431 -86.966843 15.460052 39030 22.572891 -88.994476 14.887245 39031 35.203171 -87.737808 15.848701 39032 6.407150 -88.368637 16.139053 39033 12.526390 -90.306961 14.738617 39034 12.764984 -90.428513 15.854149 39035 13.626358 -89.879425 14.943054 39036 14.491249 -89.522507 14.925079 39037 14.689247 -89.451920 14.665398 39038 22.521011 -88.416931 15.824959 39039 22.242981 -87.499985 15.918625 39040 31.624735 -88.745483 16.180122 39041 35.003036 -88.132385 16.385971 39042 35.258270 -87.597488 16.655998 39043 11.786339 -90.651382 14.929977 39044 15.839096 -90.572617 15.450073 39045 29.712296 -90.051254 14.929634 39046 34.540482 -88.511932 15.637932 39047 9.974243 -91.704315 14.758896 39048 28.845512 -90.294830 14.806320 39049 29.082146 -90.964920 14.530426 39050 29.014694 -91.670486 14.326782 39051 14.967056 -92.658005 15.920677 39052 16.327682 -91.255417 15.025597 39053 25.505783 -92.801041 14.740219 39054 26.081337 -93.702835 15.221748 39055 25.427414 -91.689667 15.609825 39056 26.335747 -92.719437 16.247299 39057 13.251564 -97.123230 13.971924 39058 25.054420 -95.419296 15.617249 39059 13.494934 -97.406250 14.528221 39060 24.319794 -96.938217 14.296509 39061 22.603134 -96.400818 15.768684 39062 14.876915 -99.160324 13.740959 39063 14.364182 -98.422470 14.296989 39064 15.627129 -99.046906 14.327118 39065 14.657082 -97.891312 15.360596 39066 16.992401 -98.016632 15.629669 39067 15.817200 -98.141251 15.678757 39068 15.759354 -97.318069 16.271812 39069 21.463272 -96.216644 15.910599 39070 15.027702 62.995697 25.645874 39071 14.126282 62.579208 25.721214 39072 17.429710 61.910538 26.031090 39073 16.798492 62.010071 26.595222 39074 18.236115 61.518936 25.407173 39075 6.113159 60.520782 24.580994 39076 7.391853 61.117599 24.282776 39077 5.784439 58.658401 25.109299 39078 6.396904 59.237381 24.761559 39079 6.597519 57.976822 24.777298 39080 17.896919 60.012131 25.544579 39081 17.464096 61.097168 26.344620 39082 5.006325 58.996231 24.920906 39083 3.988609 58.013336 24.657028 39084 10.618378 59.224396 26.432358 39085 17.491318 59.716003 26.904099 39086 3.730766 56.689087 24.507278 39087 5.658470 57.007675 25.059792 39088 5.478775 58.025879 25.150612 39089 6.748711 56.980896 24.743462 39090 4.543434 57.339706 25.024117 39091 6.498901 56.010468 24.848267 39092 9.359947 57.719025 27.095406 39093 8.214890 57.344360 27.886574 39094 8.768356 56.334305 27.555458 39095 17.128342 57.201950 24.911018 39096 4.372353 55.566696 24.746590 39097 10.961990 56.396362 25.270409 39098 19.135941 53.933075 26.516312 39099 17.383446 57.077850 25.378052 39100 7.686462 54.378296 24.957970 39101 6.016586 54.278564 25.135086 39102 9.994919 54.605179 25.005424 39103 17.970566 56.245972 25.916237 39104 17.690887 57.370667 25.935326 39105 4.203911 54.111176 24.711372 39106 4.451912 53.261246 24.886108 39107 7.624404 53.580627 25.683632 39108 3.912224 51.286682 25.870819 39109 4.153763 50.348969 24.930183 39110 33.594490 51.301743 25.262794 39111 32.109428 50.562683 26.165268 39112 34.289124 51.229187 25.507927 39113 38.343651 47.806458 25.402718 39114 38.020691 48.212036 26.078857 39115 36.225731 49.813416 25.880363 39116 35.217560 50.507980 25.728745 39117 18.172958 49.322998 24.171417 39118 18.200813 50.413101 24.796410 39119 31.380318 48.725220 25.384995 39120 3.813545 49.864716 25.880089 39121 4.654747 49.304947 25.351044 39122 6.771004 48.363190 26.822609 39123 7.549362 48.383789 27.324554 39124 19.093658 49.804779 25.150566 39125 19.140137 48.732590 24.629280 39126 36.994072 49.115311 25.947098 39127 20.532318 49.346283 25.466248 39128 19.816879 50.728073 25.967346 39129 19.896973 48.023224 24.782532 39130 20.792694 46.654922 24.567833 39131 20.989235 47.645630 24.995148 39132 31.138351 46.703735 25.118401 39133 31.269066 47.783554 25.229355 39134 40.882156 45.248611 25.854164 39135 40.121490 45.742371 26.308899 39136 39.662521 46.448013 25.790901 39137 38.865631 47.248840 25.908684 39138 10.400040 46.343262 25.404747 39139 10.525116 45.308167 25.155418 39140 22.119751 46.143463 24.813766 39141 25.550522 49.381195 26.065445 39142 25.626404 50.315414 26.119431 39143 24.952057 50.314575 25.970779 39144 38.261124 47.579193 27.107643 39145 4.671600 44.464111 26.380791 39146 3.500214 44.472351 25.039146 39147 3.246170 44.453812 24.225418 39148 42.179047 43.967194 24.820305 39149 41.430695 44.886688 24.712677 39150 9.263283 44.505798 24.400406 39151 22.259621 44.492401 24.482956 39152 22.171539 43.690186 24.222824 39153 30.174454 42.716660 24.323227 39154 3.080887 43.983704 24.741707 39155 23.300682 43.716766 24.726952 39156 23.612000 41.692184 23.884689 39157 23.911514 42.715988 24.721779 39158 25.342705 42.398529 25.514191 39159 25.130234 43.616699 25.473366 39160 24.122261 40.911255 23.736008 39161 24.584183 41.859070 24.740631 39162 24.954247 40.801193 24.274246 39163 6.142189 39.572296 23.789017 39164 25.268646 41.576477 25.157013 39165 44.933228 40.160645 24.734009 39166 44.240768 41.245560 24.977051 39167 6.802742 38.976135 24.365021 39168 25.912369 40.265167 24.746895 39169 25.867996 40.877502 25.429642 39170 26.917854 39.965637 25.343224 39171 36.118546 38.637711 24.563881 39172 35.641602 38.610138 24.866837 39173 36.076485 39.528107 25.015411 39174 37.018990 38.871796 24.816605 39175 38.506485 38.891785 25.491211 39176 38.016190 37.461853 24.907539 39177 36.809174 39.991196 25.151245 39178 9.108078 38.125580 23.885239 39179 7.677261 37.755417 24.864586 39180 9.050148 37.057251 24.863533 39181 9.857437 37.548920 24.515251 39182 10.510269 37.639236 23.747574 39183 35.037689 38.125580 25.455360 39184 37.296249 36.616760 24.301590 39185 33.948349 36.604523 25.348572 39186 34.506210 37.083740 25.355324 39187 37.332130 36.045380 24.174202 39188 36.885880 35.556824 24.220604 39189 11.874802 35.670334 23.955055 39190 39.480728 36.444427 25.398880 39191 38.075958 35.824356 24.753853 39192 45.172424 37.800919 25.533821 39193 12.429657 34.726349 23.579620 39194 11.152740 34.826035 24.307510 39195 11.893372 33.868820 24.019920 39196 32.951309 35.454407 25.177483 39197 33.530022 36.239120 25.451324 39198 36.708511 34.778244 24.787659 39199 12.564514 33.861450 23.608955 39200 33.432053 35.024902 24.439011 39201 32.860634 34.511826 24.747711 39202 34.155754 34.604446 24.338867 39203 33.412811 34.372513 24.383720 39204 33.538620 33.520844 24.761230 39205 12.953140 31.248703 23.407066 39206 12.719635 29.916687 24.317146 39207 44.405945 30.395691 24.084831 39208 3.248306 30.415390 24.606216 39209 4.900513 31.388306 23.579285 39210 12.592560 32.867493 23.748100 39211 12.143539 31.595642 24.584846 39212 11.669281 32.987778 24.398628 39213 10.767166 32.859634 25.267525 39214 46.526901 31.494751 26.342186 39215 45.880005 32.260223 26.063690 39216 46.005402 31.356110 25.263603 39217 2.484223 27.598190 24.150681 39218 2.519318 28.213211 23.184486 39219 5.726044 30.580536 24.293671 39220 44.555176 29.177444 24.999969 39221 45.439117 30.811279 24.621758 39222 9.719696 28.172318 24.208046 39223 10.563615 28.088715 23.391022 39224 11.687683 27.641663 23.958496 39225 40.540237 28.128510 23.517464 39226 40.276840 27.382950 23.989120 39227 40.211975 26.861679 24.820107 39228 40.929947 27.287766 24.887177 39229 41.433228 27.900116 24.292938 39230 41.964386 27.574402 25.338028 39231 43.009888 28.343857 24.867599 39232 2.992729 26.996674 23.019691 39233 10.632423 27.311279 24.458130 39234 39.535004 26.459534 23.982216 39235 3.816361 25.560577 22.752670 39236 51.118713 26.558136 24.388702 39237 52.070007 26.847763 25.968285 39238 39.159790 25.887100 23.450058 39239 39.359459 25.361023 23.428688 39240 50.973206 27.235382 25.727249 39241 51.181274 27.466888 26.233910 39242 50.577576 27.485657 26.336754 39243 54.523758 24.579239 23.342438 39244 3.775765 24.624542 23.405556 39245 4.647705 24.246048 22.713287 39246 39.861122 24.742401 23.993713 39247 3.005760 25.861206 23.917839 39248 40.751038 23.947174 24.666954 39249 41.133392 23.784653 25.690094 39250 40.396820 24.494873 25.823692 39251 43.814621 23.667709 24.892960 39252 54.413879 23.409531 23.812798 39253 54.058563 24.584290 24.535454 39254 6.032761 22.060501 22.780746 39255 54.031082 21.906738 23.739067 39256 53.449158 22.722305 24.642403 39257 53.718628 23.711624 24.908905 39258 6.166901 20.540527 23.434418 39259 51.822556 21.118332 25.032211 39260 52.971527 21.761993 24.410751 39261 53.102997 20.726486 23.883499 39262 52.692688 20.006470 23.828896 39263 53.491516 19.792236 23.905670 39264 4.906654 19.511963 22.393127 39265 5.641266 19.070862 24.027748 39266 5.452271 20.303452 24.475861 39267 52.578888 19.721771 24.220139 39268 54.585510 19.235382 23.959579 39269 4.931076 18.111847 23.538002 39270 52.212677 20.220657 24.210457 39271 53.535904 19.189651 25.130013 39272 55.190979 19.255142 23.479401 39273 55.479736 18.650970 23.852646 39274 56.398361 18.029480 23.678070 39275 55.976517 18.117661 24.416870 39276 2.837752 11.993528 18.439522 39277 2.515716 10.514835 17.357557 39278 4.130467 16.555357 21.245337 39279 3.959018 15.461119 21.337580 39280 56.844849 17.213470 24.306664 39281 57.434601 15.956528 24.517632 39282 47.739197 13.390793 24.163727 39283 47.130447 12.246964 23.928711 39284 46.897690 12.861526 23.976479 39285 54.834808 14.004669 24.020966 39286 55.371292 13.965118 23.044754 39287 56.575775 14.352188 23.838539 39288 47.032776 11.685638 22.810722 39289 2.183911 5.850842 17.161736 39290 2.103070 5.999473 15.953501 39291 49.031738 11.154068 23.997139 39292 47.930939 11.346512 23.544533 39293 53.832062 9.991974 22.987373 39294 54.365387 9.589050 22.875336 39295 17.208471 9.533890 23.815977 39296 54.381882 9.250565 23.030540 39297 2.203157 5.099134 18.284523 39298 2.126132 4.784933 17.538851 39299 16.731146 8.877625 23.870459 39300 17.479025 8.307556 24.087614 39301 17.909033 9.155121 23.686255 39302 53.392059 8.458847 23.900223 39303 52.309418 7.636536 24.548439 39304 54.069748 8.912384 23.185928 39305 53.970184 8.950928 23.835464 39306 16.685522 7.923401 24.138151 39307 18.030340 7.445755 24.049162 39308 51.374481 7.248505 22.826569 39309 51.261703 7.041550 23.612244 39310 16.593245 7.117188 24.400541 39311 17.275023 7.299255 24.507818 39312 17.782713 7.409485 24.415548 39313 46.612366 5.741394 22.441940 39314 48.406708 5.950928 22.994080 39315 49.596573 6.423889 22.744675 39316 57.110443 5.908157 22.797775 39317 58.184860 6.316864 23.020920 39318 59.279327 6.138153 23.067001 39319 16.141363 6.360222 24.097898 39320 18.139654 5.813705 24.128927 39321 45.572678 4.929810 23.475304 39322 49.914520 6.311417 23.816666 39323 55.265671 4.858444 22.633347 39324 56.099670 5.301620 22.859512 39325 56.471252 5.534973 22.890007 39326 59.541748 5.789963 23.848450 39327 54.457123 4.324623 24.049828 39328 53.988739 4.111954 22.503960 39329 59.709244 4.432953 22.933197 39330 59.812149 4.724091 23.854408 39331 16.599730 5.336212 24.085577 39332 17.768057 5.413559 24.348814 39333 17.176016 5.383003 24.656462 39334 52.116135 3.058784 22.494705 39335 52.306427 3.053810 23.453606 39336 51.486755 2.646255 23.288284 39337 49.687454 1.718201 22.413353 39338 44.628052 0.509399 23.149849 39339 43.926117 1.292358 23.092438 39340 50.547165 2.039169 23.663101 39341 50.648773 2.200958 22.774567 39342 57.211609 0.746979 22.591827 39343 57.435944 1.388947 22.808846 39344 58.175461 2.071686 22.778534 39345 45.964050 0.470871 22.703857 39346 46.566528 0.012161 23.802734 39347 46.907120 0.318237 22.856018 39348 57.547195 -0.411835 22.440315 39349 58.950241 -1.212601 23.010094 39350 57.934250 -0.602524 24.292892 39351 59.174225 -1.379440 24.800980 39352 60.512512 -2.932968 24.475685 39353 61.180618 -5.284805 22.090630 39354 2.243234 -4.933006 20.668179 39355 48.965485 -6.857086 21.025177 39356 60.706100 -5.057968 22.680885 39357 2.341604 -6.435159 21.060780 39358 41.053589 -7.846710 21.388901 39359 44.323181 -8.492828 22.513939 39360 45.252625 -7.282654 21.549751 39361 46.284637 -7.754028 21.740059 39362 42.360275 -8.871368 22.582542 39363 46.960083 -9.111877 21.574936 39364 2.383881 -8.233971 20.485365 39365 2.432876 -7.884050 21.578392 39366 34.183601 -10.316910 21.904114 39367 33.467697 -11.545212 21.358208 39368 46.459381 -9.609863 21.207550 39369 62.506195 -9.659531 22.868607 39370 62.072830 -9.255264 22.829269 39371 62.865143 -10.305252 22.950790 39372 41.627426 -12.347351 20.889023 39373 42.079834 -10.479721 22.186172 39374 41.197815 -11.339005 21.695694 39375 44.036240 -9.310852 22.517906 39376 43.124207 -10.020813 22.233177 39377 33.300430 -13.273117 20.826584 39378 63.556244 -11.440613 22.792892 39379 63.978073 -12.401352 21.860352 39380 63.937134 -12.475662 22.858444 39381 33.507248 -14.180557 20.470703 39382 58.375916 -13.229919 21.850754 39383 57.483688 -13.558289 22.035934 39384 58.821716 -13.256927 21.832222 39385 2.740790 -12.332366 21.483906 39386 2.796814 -13.235579 20.768995 39387 40.855545 -13.378647 21.436958 39388 50.430481 -14.544846 20.478966 39389 50.091232 -15.521408 20.724503 39390 41.840439 -15.138199 21.277275 39391 47.510742 -16.197800 21.336998 39392 47.867737 -16.962540 21.701477 39393 33.132217 -16.170197 21.825516 39394 34.258934 -15.179749 22.719482 39395 33.522491 -14.550522 22.243576 39396 46.359650 -17.087296 21.248413 39397 46.534012 -17.831879 21.910629 39398 47.128113 -17.025909 21.846764 39399 56.894897 -16.072617 21.296890 39400 56.443985 -16.206482 21.742584 39401 62.991486 -15.299652 22.395340 39402 3.402881 -17.492540 19.127619 39403 3.247825 -16.797688 19.718872 39404 40.701233 -16.598755 21.090233 39405 48.492706 -17.081390 21.461151 39406 3.525364 -18.228502 19.243628 39407 38.239166 -17.815842 21.049957 39408 38.563019 -17.204727 21.995995 39409 43.561707 -19.147461 20.833817 39410 45.228134 -18.647095 21.543457 39411 3.656873 -18.994268 19.543493 39412 3.423911 -17.956528 20.038359 39413 32.146179 -18.166718 21.427666 39414 31.791582 -19.334534 21.805168 39415 37.442772 -17.917328 21.765381 39416 36.563736 -18.537231 21.621674 39417 48.038391 -17.560318 21.548775 39418 57.684387 -18.883545 20.690033 39419 34.336884 -20.536697 21.425606 39420 43.815247 -19.699829 21.668861 39421 42.486603 -20.814468 22.411469 39422 43.463257 -20.513580 22.150284 39423 56.464661 -18.578156 22.384186 39424 3.792533 -19.957638 20.012999 39425 34.927696 -21.789841 20.894073 39426 60.349915 -20.153259 22.009087 39427 61.599487 -20.317917 22.054558 39428 35.984848 -22.748535 21.381104 39429 36.998138 -22.870148 21.824066 39430 37.007187 -22.240326 21.069267 39431 33.699768 -21.756454 21.256454 39432 34.323891 -21.457886 20.962158 39433 39.083618 -21.941345 21.653679 39434 39.778572 -23.116562 22.204025 39435 40.671707 -22.073166 22.250145 39436 44.374908 -21.717422 20.674652 39437 44.986816 -19.948059 21.747749 39438 29.775848 -24.011505 20.370491 39439 37.771561 -22.264252 21.502747 39440 50.315536 -22.843445 20.245003 39441 50.885529 -23.552612 20.944153 39442 49.617706 -23.278732 20.657516 39443 31.069702 -22.022797 21.621307 39444 31.051933 -21.145081 21.555573 39445 30.558273 -21.568161 21.193748 39446 49.051727 -23.818451 20.344254 39447 55.259125 -23.369324 20.780182 39448 56.452469 -23.374481 20.452545 39449 56.821625 -23.963150 20.653786 39450 58.561600 -23.945068 20.107834 39451 38.809891 -24.213821 22.355446 39452 38.023972 -25.179001 22.487221 39453 39.189392 -25.778824 22.026711 39454 56.126282 -26.639282 20.223862 39455 57.697906 -26.765900 20.689247 39456 4.924847 -26.310282 18.570261 39457 5.283658 -27.776773 17.973902 39458 41.024506 -24.804611 20.859360 39459 49.930511 -24.320648 20.719345 39460 49.591202 -23.671722 20.849281 39461 54.876709 -23.866196 21.413864 39462 51.744049 -23.708725 21.198318 39463 52.649185 -23.852310 21.045158 39464 56.218018 -23.983994 20.853447 39465 61.103088 -26.033768 20.661644 39466 62.487030 -25.355591 21.541260 39467 4.475540 -24.630669 19.485809 39468 42.897736 -26.887634 20.830040 39469 61.478317 -26.403702 21.274208 39470 62.345169 -26.280304 22.040131 39471 29.962204 -27.083206 20.013985 39472 29.560120 -26.379044 20.361389 39473 30.352753 -27.514084 20.462631 39474 44.006439 -27.694473 20.113106 39475 43.286697 -27.745255 20.576912 39476 58.808182 -27.838516 21.836891 39477 30.529465 -27.586700 21.320763 39478 33.431114 -29.030411 19.670815 39479 43.919937 -28.564026 20.193069 39480 42.314728 -28.840027 20.648903 39481 42.444016 -27.579773 21.332314 39482 41.933578 -28.126144 21.537109 39483 52.973969 -28.138794 20.586639 39484 53.218597 -28.568054 21.493782 39485 53.972214 -28.364365 20.845314 39486 57.548965 -28.524155 22.509338 39487 58.497559 -28.807831 23.184845 39488 5.156417 -29.589180 18.649609 39489 5.194789 -28.803099 18.398441 39490 4.904158 -27.625561 18.845217 39491 4.781500 -28.219152 19.332457 39492 4.892478 -29.105433 19.230528 39493 33.623604 -30.042007 19.949455 39494 40.972931 -29.161636 21.112793 39495 41.346985 -28.591339 21.587410 39496 47.249146 -29.080475 21.197510 39497 49.133789 -28.455719 21.006332 39498 4.645190 -31.469946 21.318068 39499 4.727501 -32.216881 21.939365 39500 38.155594 -30.772507 20.341713 39501 38.621170 -30.303421 20.966591 39502 39.592636 -30.219147 20.292336 39503 44.290878 -30.257690 20.209000 39504 45.190002 -30.172165 22.067192 39505 44.372070 -30.847519 22.281960 39506 37.252151 -31.037048 20.723068 39507 43.714417 -31.345627 21.425308 39508 61.416534 -32.973602 21.468361 39509 58.922958 -32.214127 20.475037 39510 34.032265 -31.012039 20.100189 39511 35.407745 -31.219086 21.127625 39512 40.825836 -32.679993 20.977066 39513 41.990295 -31.951920 20.185875 39514 59.099686 -34.231430 22.314835 39515 57.544708 -34.877716 21.914307 39516 58.127914 -33.304688 21.488884 39517 38.109383 -34.275055 20.740517 39518 53.371796 -33.865967 20.130676 39519 54.335144 -33.470047 20.169518 39520 56.492462 -32.850403 20.492477 39521 55.922165 -33.228546 20.911011 39522 4.867910 -33.201248 21.489727 39523 4.972221 -33.869671 21.353004 39524 4.883609 -33.534763 21.702126 39525 37.409767 -34.542709 19.856789 39526 37.267929 -35.077393 19.794579 39527 45.684494 -34.827225 20.504295 39528 4.945101 -33.854553 21.919825 39529 42.527954 -35.921722 20.576172 39530 62.584351 -34.934402 20.810486 39531 62.527328 -36.647186 21.125648 39532 62.600342 -33.789352 20.917625 39533 5.236658 -35.463928 22.334545 39534 5.301363 -35.901352 21.540346 39535 4.950235 -33.626266 22.693619 39536 41.113251 -36.272629 20.799240 39537 5.304513 -35.773796 20.906403 39538 5.562096 -37.060272 20.331526 39539 62.366531 -37.954636 23.010323 39540 62.263962 -36.601013 22.969322 39541 5.778771 -41.101715 18.918266 39542 53.206055 -41.347427 19.670860 39543 52.012283 -41.941498 20.212929 39544 53.130356 -41.542908 20.137688 39545 53.943481 -41.438629 19.860222 39546 56.153717 -42.509659 20.559288 39547 57.111649 -42.209198 19.602386 39548 50.483963 -42.790848 20.817635 39549 50.939087 -42.194778 20.993408 39550 51.397842 -42.110809 21.332092 39551 52.307922 -42.070267 21.286942 39552 53.452332 -41.900085 20.720100 39553 54.898254 -41.792953 20.223907 39554 4.988815 -43.394379 19.291428 39555 5.495804 -42.451599 20.274109 39556 4.873085 -43.744888 20.425652 39557 62.469955 -42.189545 20.366089 39558 5.178887 -44.727310 19.036423 39559 6.487961 -46.283096 18.401840 39560 61.410461 -43.882202 20.243698 39561 51.940430 -44.594254 19.909790 39562 52.574219 -45.526108 20.577011 39563 51.173065 -44.797638 20.589859 39564 53.137924 -44.836975 19.515968 39565 58.288559 -43.852295 20.690063 39566 5.836266 -46.623795 20.688965 39567 5.920456 -46.052277 19.671577 39568 4.968392 -45.362167 20.656563 39569 7.235413 -47.349777 18.842018 39570 7.093048 -47.522888 18.256859 39571 44.073578 -47.821960 20.243790 39572 46.654083 -48.142548 19.487183 39573 47.734497 -48.272156 19.114655 39574 48.330902 -48.023499 18.787643 39575 52.426361 -49.036484 18.468506 39576 50.976410 -50.379807 18.868607 39577 54.297348 -46.829834 20.908989 39578 55.069244 -47.388290 20.871689 39579 42.476654 -48.137741 20.140350 39580 48.567841 -48.850967 19.039505 39581 47.552277 -49.043671 19.502098 39582 49.614166 -49.480072 18.947845 39583 48.609192 -49.904785 19.446098 39584 58.794434 -50.322189 19.384430 39585 5.766930 -51.747391 19.790070 39586 6.511498 -51.273239 20.505432 39587 6.050171 -51.940674 20.898560 39588 7.476059 -50.540680 20.679596 39589 7.794944 -49.408966 19.938049 39590 8.546700 -49.567078 21.105873 39591 14.588722 -51.292633 18.486221 39592 41.793091 -51.434570 19.152405 39593 49.646530 -50.789322 19.395096 39594 42.096298 -52.163712 19.452812 39595 42.475388 -51.835220 19.980713 39596 51.723938 -51.835968 18.887711 39597 50.564468 -51.815628 19.331932 39598 4.728211 -54.491989 19.723091 39599 4.690941 -55.168549 20.000313 39600 15.249725 -52.301788 18.419273 39601 15.719208 -52.153366 19.517769 39602 15.962883 -53.231277 18.163788 39603 16.068604 -54.222046 17.441360 39604 15.286270 -54.862122 17.216042 39605 19.380234 -53.278305 19.511833 39606 20.464340 -53.251160 19.307091 39607 36.422958 -53.141602 18.897629 39608 36.692978 -53.083755 19.257538 39609 37.256981 -53.334854 18.936249 39610 41.756592 -52.262314 18.759811 39611 42.329651 -52.915817 18.954269 39612 51.465744 -53.119156 19.065430 39613 52.444412 -53.973877 18.579620 39614 58.879333 -51.631607 19.620193 39615 9.691925 -55.998047 18.349937 39616 15.923607 -55.017899 17.102585 39617 21.226616 -54.092209 18.648209 39618 38.655128 -54.233307 18.656120 39619 37.465660 -54.085876 21.368515 39620 36.018341 -54.750595 21.408661 39621 36.595047 -54.006973 22.274452 39622 43.919250 -53.668213 18.999557 39623 44.890839 -53.785736 18.954544 39624 44.307892 -52.432404 20.024040 39625 51.311264 -53.765671 19.042580 39626 58.883148 -53.485321 19.495193 39627 10.854095 -54.462097 19.064003 39628 45.962616 -53.900558 18.911873 39629 46.935364 -53.957413 18.906944 39630 5.662361 -56.186447 18.023872 39631 10.223412 -53.467865 18.122086 39632 58.094360 -55.402054 18.998154 39633 5.278450 -57.177032 18.723953 39634 6.145111 -57.225510 18.100250 39635 8.606735 -57.068726 18.216370 39636 8.262917 -56.612518 17.532799 39637 9.681854 -56.816833 19.038521 39638 35.769882 -54.799164 19.421394 39639 36.428207 -57.644211 18.634766 39640 41.468155 -56.575439 19.684868 39641 41.480072 -56.595612 18.850273 39642 57.689575 -56.337204 19.043045 39643 7.244232 -58.020554 18.761139 39644 8.439346 -57.719803 18.868530 39645 9.119019 -57.426926 19.145737 39646 36.897675 -58.099762 18.407867 39647 47.023407 -57.016434 20.371437 39648 49.567825 -57.388992 19.572952 39649 50.611023 -57.452942 18.881958 39650 51.667908 -57.658646 18.732079 39651 52.723206 -57.964020 18.706696 39652 53.634308 -58.377853 18.957809 39653 56.504089 -58.457230 19.863373 39654 16.980087 -59.338715 18.089966 39655 55.040558 -58.927856 19.450111 39656 13.313828 -62.497772 17.299652 39657 40.354065 -60.274414 18.303558 39658 48.540833 -62.065933 19.695053 39659 48.769379 -61.459274 20.254547 39660 47.811081 -61.567780 19.834000 39661 43.137650 -60.908447 18.747856 39662 10.922287 -63.158310 16.575485 39663 44.848480 -61.258804 18.993874 39664 47.267517 -60.840454 21.070557 39665 45.989212 -60.823471 21.056335 39666 11.107193 -63.972717 16.750587 39667 14.639130 -64.257614 17.756363 39668 16.184265 -63.941864 18.553902 39669 16.050247 -64.884445 18.185997 39670 14.127701 -65.841324 17.479126 39671 12.758659 -65.336929 17.306625 39672 44.325912 -64.490692 18.608948 39673 44.403137 -64.819260 18.198807 39674 43.792542 -65.007965 18.675713 39675 44.894287 -63.979492 19.513138 39676 8.132553 -67.333298 17.470573 39677 7.747160 -68.139145 17.156860 39678 10.976547 -65.957184 17.470886 39679 13.407600 -66.525360 17.500160 39680 15.591980 -65.931778 17.906914 39681 14.426331 -66.790146 17.813385 39682 44.503113 -65.259369 18.207146 39683 45.101486 -65.868729 18.495346 39684 51.905029 -65.672531 18.336288 39685 9.466019 -67.012955 18.343338 39686 10.909431 -67.031555 18.468079 39687 44.199158 -65.644684 18.593399 39688 46.113464 -66.477417 19.098724 39689 47.069672 -66.213867 18.452637 39690 48.064880 -66.124527 18.277428 39691 49.037170 -66.154343 18.381409 39692 51.003036 -66.046249 18.676987 39693 50.100525 -66.550354 19.403725 39694 12.332687 -66.961823 18.048027 39695 13.538666 -67.143326 17.932159 39696 53.295547 -66.897064 18.159889 39697 8.878143 -70.486450 17.171593 39698 46.081421 -69.839691 17.927582 39699 6.983399 -72.101486 16.874619 39700 11.123711 -71.690292 17.497849 39701 12.115593 -71.853653 17.134918 39702 12.075043 -71.467819 16.661118 39703 12.783187 -72.093430 16.355484 39704 44.759018 -71.632065 17.657089 39705 48.073486 -70.083450 18.172928 39706 28.185196 -72.674927 17.091026 39707 27.532120 -72.696152 17.654823 39708 28.066940 -72.152802 17.772919 39709 29.309097 -72.149246 17.558685 39710 30.687035 -72.637177 17.264008 39711 45.830719 -71.327286 18.886673 39712 4.508804 -72.992538 16.875046 39713 27.685951 -73.352112 17.196175 39714 31.671968 -73.105011 17.037277 39715 32.019615 -73.568192 17.368179 39716 46.012421 -73.997253 17.232994 39717 47.163956 -73.061218 19.045319 39718 46.910080 -72.392014 19.086716 39719 4.820282 -75.776535 17.352592 39720 4.725853 -75.102386 18.353058 39721 6.142243 -72.880707 19.063972 39722 6.141174 -72.548111 18.261047 39723 6.839272 -72.847290 18.725060 39724 11.916779 -72.488983 17.369438 39725 11.678879 -73.108521 17.509003 39726 46.781219 -75.291824 18.855782 39727 47.004333 -73.980530 18.777512 39728 27.630600 -77.105774 17.309052 39729 27.529625 -76.199173 17.966103 39730 35.208572 -75.749390 18.769997 39731 34.813156 -76.589157 17.806198 39732 14.364281 -77.946259 16.021385 39733 32.579529 -79.814377 18.588409 39734 45.469879 -76.742111 17.433937 39735 8.061600 -78.634232 17.270790 39736 8.663399 -78.754822 16.511963 39737 12.952248 -78.583145 15.710037 39738 13.752548 -78.617355 16.009598 39739 14.301881 -78.351440 16.378769 39740 14.669945 -78.218552 16.305290 39741 14.849319 -78.646896 16.228065 39742 16.137886 -78.685516 15.643005 39743 32.642883 -77.361389 16.693710 39744 32.530853 -79.127823 17.977753 39745 32.319305 -78.888519 17.573524 39746 44.493683 -77.328217 17.746399 39747 14.389343 -78.679993 16.355049 39748 15.512085 -79.395172 15.554596 39749 27.367104 -78.558380 17.350739 39750 31.405441 -79.191360 16.820190 39751 43.948273 -78.662430 17.177246 39752 7.247269 -80.091934 16.914162 39753 7.963333 -79.973770 16.674286 39754 7.772491 -79.472961 17.224937 39755 26.201523 -80.488159 16.251862 39756 5.582970 -81.566788 16.929527 39757 5.239014 -82.419830 16.769409 39758 5.755890 -82.374588 16.027870 39759 7.089417 -80.727371 16.339340 39760 7.998443 -80.407776 16.166168 39761 5.244118 -81.859634 17.434875 39762 25.390121 -83.176392 17.507584 39763 26.656662 -82.175781 17.802567 39764 27.076530 -81.117828 17.766006 39765 29.894409 -84.883835 18.698639 39766 30.473991 -83.998978 19.287331 39767 30.380341 -84.972595 20.128197 39768 41.449799 -83.113388 17.868034 39769 5.615746 -83.249054 16.239655 39770 5.230255 -83.181091 17.014259 39771 35.078117 -83.504547 16.485245 39772 6.501183 -85.108887 16.749344 39773 6.239189 -84.069016 16.101089 39774 5.630867 -84.099213 17.140152 39775 22.832062 -84.422318 16.647552 39776 23.442200 -83.927994 16.668884 39777 24.154015 -83.566391 16.869675 39778 8.230682 -85.817596 15.769012 39779 8.803833 -86.078903 15.731682 39780 34.717789 -84.129196 16.532494 39781 8.898193 -86.187210 15.545670 39782 22.090729 -85.583267 16.940514 39783 29.543968 -84.466537 17.676384 39784 39.900780 -84.440552 17.977043 39785 38.265854 -84.660782 17.902328 39786 38.933067 -84.841812 19.035439 39787 6.817017 -87.054657 16.698692 39788 6.635658 -88.318375 17.323425 39789 6.619606 -89.121872 16.771851 39790 8.599641 -86.291733 15.733681 39791 7.838447 -86.474289 15.862297 39792 28.641785 -86.705643 17.282425 39793 28.188354 -87.388199 16.436890 39794 35.248413 -86.877197 16.506439 39795 22.118309 -86.640518 17.115097 39796 6.457100 -89.148132 16.046608 39797 23.027054 -88.095215 17.374290 39798 32.835052 -88.969940 16.274178 39799 33.983429 -88.871338 16.359245 39800 34.620895 -88.510635 16.558929 39801 10.403564 -91.970703 16.264870 39802 11.226624 -91.929398 16.921974 39803 11.359467 -91.319885 16.176682 39804 14.771263 -90.171509 15.850761 39805 16.221893 -91.086441 15.253174 39806 24.270279 -90.055099 16.035553 39807 11.329765 -90.954071 15.436592 39808 10.431702 -91.592972 15.451553 39809 16.029877 -91.027985 15.697960 39810 23.057632 -89.103394 15.762154 39811 14.621445 -93.106262 15.900330 39812 14.149979 -93.873337 15.426498 39813 20.262062 -94.328583 16.095032 39814 21.177719 -93.795517 16.907845 39815 21.025772 -94.954300 16.146683 39816 18.766769 -95.054749 15.658897 39817 18.462997 -95.184692 15.858932 39818 18.782455 -94.813278 16.012131 39819 19.469604 -95.049515 15.802956 39820 19.427353 -94.311020 16.718231 39821 20.224030 -93.728012 16.630547 39822 20.284927 -94.967056 15.824692 39823 13.474480 -96.752594 15.567093 39824 18.772339 -95.568893 15.670441 39825 18.317429 -95.791748 15.913132 39826 19.359711 -96.291672 15.722801 39827 18.661865 -96.133514 15.746849 39828 20.343918 -95.780029 15.840881 39829 24.057396 -95.955139 15.559204 39830 26.143959 -93.936966 16.230782 39831 19.409134 -97.760178 15.171837 39832 20.486328 -97.156815 15.418236 39833 17.049309 -98.963455 14.578796 39834 16.012581 -98.594070 15.189590 39835 18.279190 -96.876328 15.767303 39836 14.420135 62.937469 26.385262 39837 15.060295 62.982376 26.404312 39838 15.836525 62.607849 26.587898 39839 12.404724 61.861038 26.988441 39840 13.489204 62.368179 26.764351 39841 13.995042 62.723434 26.571762 39842 16.943779 61.134064 27.219925 39843 15.939026 61.927597 27.658447 39844 11.516205 60.837097 26.415344 39845 11.145599 61.647858 27.788818 39846 18.022369 57.934494 26.889923 39847 5.031944 52.813110 25.322998 39848 9.535812 55.127869 26.290672 39849 19.356354 56.481659 28.080154 39850 18.723534 56.509216 27.190140 39851 6.074806 52.869736 26.045464 39852 8.685136 53.806000 26.207596 39853 8.366539 53.700424 27.028366 39854 8.244949 53.313263 26.598358 39855 8.213165 55.367386 27.796631 39856 8.447708 58.083344 27.721779 39857 8.715958 54.361908 27.107658 39858 7.054337 53.023560 26.642227 39859 6.379044 52.777618 26.828552 39860 8.185516 53.315338 26.154747 39861 4.837486 52.193817 25.917618 39862 33.034584 51.227921 26.247292 39863 34.084358 51.247620 26.211670 39864 3.684883 50.460114 25.660629 39865 18.701935 51.574219 25.521706 39866 23.005272 50.985306 26.417160 39867 24.139931 50.190918 25.970055 39868 24.828293 51.156494 26.434090 39869 26.131294 50.731720 26.566605 39870 26.029655 51.469269 26.950378 39871 32.469681 50.705902 27.106911 39872 31.999269 50.399200 26.907356 39873 34.881363 50.789261 26.936760 39874 18.934189 50.591248 25.453056 39875 21.625275 50.467728 26.177834 39876 20.716141 50.508850 26.113167 39877 23.082535 48.769516 25.671410 39878 26.457108 46.490936 26.140678 39879 26.227966 47.751541 26.297188 39880 24.882339 46.515686 25.618622 39881 26.730591 49.938873 26.688057 39882 31.917063 49.634125 27.090302 39883 9.636749 47.334641 25.642517 39884 27.862885 49.903931 27.956604 39885 27.101822 50.890869 27.547318 39886 27.378677 48.899643 27.342331 39887 31.683481 45.780716 26.190285 39888 31.933634 46.791748 26.704132 39889 27.819656 47.678238 27.666931 39890 31.841196 45.604813 26.929146 39891 31.505882 44.819214 26.819244 39892 10.268410 46.647949 26.716751 39893 9.300476 47.654770 26.591560 39894 9.539939 47.532394 28.025368 39895 24.506607 44.928375 25.310860 39896 41.474091 44.511276 25.708199 39897 6.571648 44.599030 26.026077 39898 6.838883 44.290405 27.137238 39899 9.977188 44.656860 25.361855 39900 31.126129 43.720306 25.941124 39901 8.310410 43.942551 27.585297 39902 7.478348 43.873413 28.149986 39903 26.395187 44.663925 26.151451 39904 26.065979 45.661835 25.940437 39905 26.460007 43.186096 26.769753 39906 41.882431 43.311569 26.249977 39907 42.823181 42.490723 25.854202 39908 3.159599 42.082977 25.932022 39909 43.400314 41.768845 25.678230 39910 25.641869 41.682037 25.660248 39911 31.284454 43.864502 26.792267 39912 30.821793 43.029831 27.000999 39913 30.482628 42.387283 25.555847 39914 36.279221 40.497910 25.392624 39915 35.661407 40.361404 25.764908 39916 36.241776 41.157974 25.986610 39917 37.032013 40.801559 25.665588 39918 37.271561 41.945770 26.687042 39919 37.996696 40.828583 26.138298 39920 37.728806 39.940948 25.481415 39921 4.693443 40.230484 24.511459 39922 5.434677 39.412018 24.830933 39923 26.043022 41.640594 26.435532 39924 26.377289 40.475800 26.376488 39925 26.287086 40.910080 27.291817 39926 27.879288 39.790558 26.460480 39927 43.970840 40.418243 26.009529 39928 27.983093 39.946228 27.815842 39929 28.916885 40.231110 26.561462 39930 35.449646 41.055618 26.706528 39931 34.951355 40.022873 27.031120 39932 35.027588 40.880280 27.747330 39933 44.830933 39.242218 25.534149 39934 9.962907 36.882996 24.874527 39935 35.349396 39.271332 25.591644 39936 10.631477 36.950012 24.492737 39937 10.396957 36.419098 24.804428 39938 39.505844 37.834778 25.827179 39939 10.934845 36.014679 24.431061 39940 9.871964 35.576569 24.905624 39941 40.540741 35.325302 25.961197 39942 40.805847 37.128967 26.387596 39943 10.365448 34.186157 24.827621 39944 11.089500 33.762848 24.510986 39945 32.390320 34.644974 25.230087 39946 37.897514 34.801178 25.403275 39947 39.388893 35.438538 25.309471 39948 39.535713 34.874237 25.708076 39949 44.380768 35.178528 25.608795 39950 44.454117 34.301178 24.986893 39951 45.184372 36.646973 25.687607 39952 32.380737 33.522751 25.189064 39953 32.139572 34.605225 26.066376 39954 35.076477 33.883606 24.905090 39955 38.789169 35.026459 25.412270 39956 37.101265 34.371841 25.522903 39957 44.030457 34.016357 25.798347 39958 44.888580 32.954285 26.282661 39959 33.015976 31.777512 25.241280 39960 35.369659 32.813049 25.971390 39961 36.091751 32.423096 27.054489 39962 34.708214 31.334457 26.580162 39963 4.388596 30.706558 24.504211 39964 6.126328 29.694366 25.492615 39965 5.079071 30.202454 25.246155 39966 31.426041 33.039200 26.775871 39967 31.737627 33.451859 25.832443 39968 31.752138 32.214264 25.455849 39969 31.908663 31.216187 24.957397 39970 32.250320 30.659729 25.060654 39971 34.331146 32.572113 25.451797 39972 6.991554 30.029449 24.526024 39973 31.600191 30.611893 24.958488 39974 31.348846 31.133499 25.200256 39975 31.094009 30.334793 25.419586 39976 32.918320 30.189957 25.989082 39977 45.894501 30.371429 25.018806 39978 46.303162 30.548141 25.566612 39979 7.022240 29.533554 25.315933 39980 31.820253 30.179321 25.296501 39981 31.515671 29.596542 25.910805 39982 45.281158 29.933960 24.764145 39983 45.775208 29.626358 25.475632 39984 46.543121 30.153214 26.322487 39985 46.084579 29.400299 26.195152 39986 2.590645 28.693161 25.515930 39987 2.761910 29.797028 25.062447 39988 11.228210 26.855591 24.672279 39989 12.453590 27.404999 25.402710 39990 11.730675 26.632706 25.134842 39991 43.100876 27.772537 26.064537 39992 44.314575 28.367752 26.047096 39993 39.917206 26.313004 25.123116 39994 39.368858 25.549622 23.965805 39995 39.625237 25.604385 24.750671 39996 49.899597 26.869781 25.898026 39997 48.571320 26.092117 26.090439 39998 3.420639 24.287323 24.138535 39999 39.866730 25.116241 25.452156 40000 47.447693 24.962494 24.914429 40001 48.238953 25.386169 25.009163 40002 4.500809 23.430679 23.438110 40003 41.846878 23.683578 24.749451 40004 42.935852 23.536331 25.119980 40005 46.464874 24.525879 24.717293 40006 45.322830 24.191803 24.820656 40007 44.770294 23.905670 24.781227 40008 53.498901 24.492020 25.665169 40009 5.368973 21.865585 23.662315 40010 44.446716 23.771622 24.786804 40011 5.937882 20.713684 23.687325 40012 52.495956 22.213959 25.206940 40013 52.581635 24.065216 27.992134 40014 52.978607 24.122772 26.885536 40015 52.124588 23.016144 27.433006 40016 51.661026 19.880905 25.039391 40017 5.457520 19.126617 25.081093 40018 4.441451 16.655918 22.531590 40019 53.008423 18.904999 27.163429 40020 51.416107 19.199905 26.236954 40021 55.081894 18.612946 24.672760 40022 2.999599 12.355451 19.148325 40023 5.436615 17.914490 24.845757 40024 2.839928 11.250581 19.009064 40025 4.730737 16.541943 23.773720 40026 57.349289 15.067825 24.181335 40027 57.381485 15.025208 24.830742 40028 57.630569 15.736725 25.405991 40029 2.507763 8.770437 18.283918 40030 47.065384 13.118256 24.016647 40031 56.517105 14.382141 26.388336 40032 56.276123 14.290665 25.190926 40033 54.015121 14.008759 26.043236 40034 48.173828 12.076736 24.862419 40035 53.652969 9.254776 24.528069 40036 54.203888 9.330780 23.497742 40037 2.353097 5.681476 19.159496 40038 2.415061 7.048569 18.745659 40039 53.179535 8.169617 24.925644 40040 2.271325 4.719222 19.191887 40041 2.159965 4.068872 18.408028 40042 2.196721 3.402926 19.316301 40043 2.100903 3.224127 18.430799 40044 17.120604 6.285683 24.693144 40045 17.888449 6.607666 24.434431 40046 47.001495 5.320175 23.750664 40047 47.911926 5.464043 23.999397 40048 48.745087 5.658630 24.462616 40049 50.063751 6.159546 25.437408 40050 51.038177 6.849075 24.688171 40051 56.302353 5.488220 23.903099 40052 57.354523 6.042007 23.591637 40053 58.248184 6.187103 24.287857 40054 16.626547 5.681496 24.478018 40055 17.087149 5.675919 24.933729 40056 17.392935 5.753296 25.001127 40057 17.559362 5.515411 24.890646 40058 17.771185 5.817337 24.665541 40059 43.884705 3.858170 23.501038 40060 44.509369 4.417717 23.673035 40061 2.054695 3.096138 17.547947 40062 59.853760 4.094826 25.733696 40063 59.916565 4.771591 24.922249 40064 59.557953 3.644974 24.436691 40065 43.452667 2.623901 23.563545 40066 53.085632 3.550453 23.467842 40067 58.888275 2.607834 23.935257 40068 42.698090 2.354172 24.710548 40069 43.028137 1.247787 24.367233 40070 49.483368 1.479691 23.406021 40071 58.377823 1.582657 24.542961 40072 57.490662 0.805359 23.799011 40073 41.817505 0.329636 27.239807 40074 40.900055 0.913544 27.644608 40075 40.977692 1.460434 26.834930 40076 48.141922 0.744934 23.126816 40077 45.086288 -0.077606 24.066841 40078 47.889282 0.411942 24.512291 40079 47.786102 0.294937 25.320946 40080 46.773514 -0.124344 25.278351 40081 49.461929 1.348114 24.405579 40082 49.926254 1.477036 25.517715 40083 48.710678 0.872528 25.551193 40084 57.760803 -0.674042 23.346840 40085 57.338058 -0.111130 23.493149 40086 58.994308 -1.162155 26.187103 40087 60.172195 -2.081039 25.623711 40088 60.591522 -3.923538 26.472733 40089 60.864792 -4.625504 24.926903 40090 60.846436 -5.620026 25.936356 40091 60.320633 -5.524261 23.097832 40092 60.025269 -5.879349 23.391960 40093 60.250381 -5.717117 23.760010 40094 60.631271 -4.720856 23.636337 40095 60.123123 -6.439926 23.162437 40096 45.193542 -8.308334 22.164070 40097 60.095749 -7.733200 23.468895 40098 59.983856 -6.621506 23.794258 40099 2.325621 -4.703526 21.395645 40100 2.687505 -7.551751 23.587271 40101 2.519237 -5.683347 22.697037 40102 2.816469 -6.625114 24.365023 40103 41.073334 -8.758148 22.243340 40104 41.624390 -9.817307 22.554993 40105 60.010757 -7.819275 24.372108 40106 61.235718 -8.964371 23.213821 40107 60.446503 -8.709579 23.510231 40108 60.779419 -8.015640 22.876534 40109 2.488988 -7.077871 22.343189 40110 2.568993 -8.427067 22.631639 40111 34.170670 -11.599136 22.364639 40112 34.594322 -9.571487 22.078461 40113 35.188385 -9.291351 21.959259 40114 44.829819 -9.021835 22.524712 40115 2.517780 -9.301387 21.638569 40116 43.116302 -9.280441 22.666870 40117 34.790886 -11.082916 22.666229 40118 39.660431 -11.290482 22.149124 40119 41.090042 -10.631439 22.285522 40120 40.028961 -12.730957 21.661316 40121 36.974716 -13.036133 22.456970 40122 38.125000 -11.999008 22.266876 40123 37.362640 -11.339157 22.523491 40124 38.450981 -12.886520 22.022774 40125 38.738823 -13.960739 21.987289 40126 40.085052 -14.305984 21.846481 40127 63.480362 -12.009354 23.782761 40128 33.708801 -13.059174 21.990356 40129 37.520523 -15.325836 22.551788 40130 37.445717 -14.476349 22.379509 40131 36.016441 -15.496216 22.816528 40132 40.072449 -15.391861 22.135376 40133 40.955963 -15.342697 21.706436 40134 55.606354 -14.561539 22.629211 40135 56.331223 -13.768555 22.502632 40136 34.688385 -12.236786 22.756866 40137 34.835876 -11.601624 22.838005 40138 33.221809 -14.414871 21.463615 40139 38.509888 -10.884155 22.445129 40140 37.862663 -13.713730 22.123734 40141 55.800125 -15.691269 22.249260 40142 56.649323 -13.333206 22.851196 40143 37.646767 -16.144424 22.703140 40144 40.405136 -15.864807 22.043106 40145 54.847824 -15.842728 23.141731 40146 55.022675 -14.478561 23.196632 40147 54.326828 -14.322113 23.928207 40148 53.667633 -15.857193 24.345009 40149 60.661240 -14.998077 23.237167 40150 63.915161 -13.413330 23.561005 40151 40.604523 -16.248123 21.620399 40152 61.436096 -15.233719 22.653450 40153 62.231934 -15.536026 22.822411 40154 63.067566 -15.545563 23.311317 40155 2.895510 -14.377451 20.826889 40156 2.982986 -15.115374 20.627630 40157 3.266334 -17.088531 20.622295 40158 3.114739 -16.076309 20.925352 40159 33.159935 -18.257965 22.629913 40160 47.407684 -17.254196 21.950218 40161 55.786758 -17.076553 22.411674 40162 3.537275 -18.761145 21.008448 40163 37.974113 -17.617279 21.874535 40164 39.618713 -16.332596 21.993385 40165 38.586761 -16.478470 22.395859 40166 47.109482 -17.426041 22.029327 40167 31.485062 -20.290939 21.643257 40168 32.287300 -20.073929 22.277046 40169 35.622345 -18.963394 21.996239 40170 56.538177 -19.323425 23.510132 40171 56.413757 -19.054291 24.599724 40172 55.935944 -18.941528 24.170616 40173 34.887909 -19.457153 22.110680 40174 44.225021 -21.030670 21.767303 40175 55.479324 -17.974503 22.900154 40176 40.951492 -20.932693 21.646706 40177 40.423630 -21.367050 21.824898 40178 30.444153 -22.973236 21.083122 40179 33.134827 -20.878845 21.848846 40180 32.191849 -21.549774 21.768707 40181 3.956980 -22.195465 21.091476 40182 33.178757 -22.677338 21.623695 40183 33.955048 -22.654968 21.369354 40184 32.021400 -22.930649 21.746666 40185 41.491364 -23.149506 21.656433 40186 42.640411 -22.000870 22.349823 40187 41.846298 -21.897629 22.558319 40188 43.424545 -21.972733 21.635178 40189 50.055450 -23.407349 20.881378 40190 54.595093 -23.580399 21.321396 40191 4.118125 -23.416515 20.604465 40192 31.131470 -24.229355 21.809807 40193 34.199242 -24.084793 22.202538 40194 52.076431 -23.465363 21.256493 40195 54.599701 -23.872299 21.567368 40196 62.896210 -21.425247 22.649734 40197 4.189403 -24.447439 20.502003 40198 29.522415 -25.104431 21.051384 40199 29.899155 -24.419861 21.084297 40200 37.758316 -25.826904 22.545212 40201 38.262413 -25.993729 22.331535 40202 63.047150 -23.625961 26.080627 40203 63.192245 -22.228088 25.893616 40204 63.251266 -23.928513 24.878860 40205 29.559433 -25.755951 21.033890 40206 40.110764 -24.566940 21.671028 40207 62.777374 -25.450989 22.193695 40208 63.070786 -24.031006 22.691437 40209 41.773026 -26.933228 21.535332 40210 41.962982 -27.614792 21.765869 40211 42.354492 -26.500504 20.976944 40212 5.062322 -27.613201 18.440649 40213 4.499416 -26.225248 19.766975 40214 4.692062 -27.113489 19.338259 40215 29.964005 -26.701187 21.111511 40216 29.905563 -25.788635 21.578804 40217 61.718262 -26.933334 21.983459 40218 31.038910 -27.448593 22.411285 40219 31.770662 -28.229141 22.403946 40220 31.994173 -28.767761 21.597328 40221 50.995453 -28.629898 22.942017 40222 56.127396 -28.760681 23.268486 40223 60.859955 -27.478760 22.152000 40224 4.522510 -30.466940 21.246956 40225 4.556776 -29.749441 20.658014 40226 4.384799 -29.623606 21.733522 40227 33.600151 -30.227402 20.914406 40228 33.036865 -29.025162 22.129509 40229 39.894073 -29.540176 21.248253 40230 46.201630 -29.614502 22.245270 40231 46.703812 -29.473495 21.543053 40232 48.354248 -28.794693 21.912209 40233 49.682724 -28.680817 22.746788 40234 48.906860 -28.769440 23.176804 40235 56.083267 -30.584305 26.834427 40236 57.860748 -31.687881 26.895714 40237 57.457382 -30.063461 25.679573 40238 52.528564 -28.649017 23.049408 40239 53.831192 -28.770157 24.276016 40240 4.750190 -29.557121 19.793333 40241 34.476624 -31.214523 20.631828 40242 36.249619 -31.235580 20.964531 40243 34.474899 -30.425751 21.918159 40244 42.904327 -31.798706 21.404762 40245 41.879318 -32.257477 22.002060 40246 40.541595 -32.889252 21.992805 40247 41.954834 -32.132004 20.840942 40248 56.853104 -33.066620 21.070892 40249 60.601608 -32.433121 21.280197 40250 60.547714 -32.696365 21.633171 40251 39.422806 -33.299942 21.148666 40252 54.818237 -33.808105 20.873909 40253 55.203278 -35.417145 21.676552 40254 53.699936 -34.590500 21.338982 40255 56.327850 -33.838913 21.421013 40256 62.315186 -33.347794 21.276138 40257 4.841508 -33.186874 22.040775 40258 38.707413 -34.152588 22.395378 40259 46.296509 -34.941086 21.091293 40260 44.952454 -35.930573 21.971077 40261 46.516434 -35.349487 21.827286 40262 47.404388 -35.776093 22.348129 40263 50.407196 -34.623566 21.136681 40264 52.455322 -34.503723 20.994171 40265 51.307190 -34.516129 20.893654 40266 38.112015 -35.484833 21.646988 40267 37.644669 -35.240326 20.605804 40268 41.731018 -36.281631 21.745079 40269 43.019333 -36.174500 21.903389 40270 62.319183 -34.107269 21.667084 40271 62.308823 -35.348770 22.128265 40272 38.967628 -36.263702 21.746284 40273 39.941521 -36.492706 21.904785 40274 40.715118 -36.404648 21.627518 40275 56.770477 -37.273773 21.231850 40276 56.518341 -37.250641 21.305832 40277 56.680252 -37.039749 21.362991 40278 57.032440 -37.246674 21.483627 40279 62.565964 -41.736755 22.119965 40280 62.197495 -40.061249 23.537735 40281 5.741806 -38.418751 19.947784 40282 5.597396 -37.790691 20.934160 40283 56.610077 -37.491776 21.476051 40284 5.782684 -39.599083 20.336391 40285 5.683266 -40.912415 20.661575 40286 6.050209 -41.437256 19.921295 40287 5.902084 -41.863205 19.683983 40288 62.236481 -43.163055 21.016350 40289 62.535629 -42.621979 21.387985 40290 61.589996 -44.698196 21.387863 40291 61.998810 -43.875168 21.625549 40292 52.861374 -46.784637 21.555061 40293 51.142181 -45.925613 21.509483 40294 61.000244 -45.402008 21.670853 40295 60.948303 -44.925659 20.952911 40296 59.997025 -45.320740 21.339584 40297 59.899170 -44.090179 20.133621 40298 60.075119 -44.518021 20.582260 40299 42.739471 -46.135330 19.207985 40300 43.187592 -47.414261 20.108452 40301 53.889404 -45.619598 20.051315 40302 7.039986 -47.200943 19.883926 40303 44.846710 -48.449173 20.253868 40304 47.423828 -50.158798 19.857353 40305 45.979965 -49.066528 19.979942 40306 45.759644 -50.778015 20.258789 40307 14.007751 -50.797058 19.429108 40308 14.064560 -50.695206 18.680542 40309 12.584511 -51.669098 19.583199 40310 13.466675 -51.093552 19.876297 40311 11.760040 -51.521225 18.671867 40312 13.217628 -51.754868 20.379349 40313 14.075302 -51.019836 20.071373 40314 14.573167 -50.975861 19.211319 40315 15.088547 -51.491791 19.308777 40316 48.588669 -51.034485 19.786179 40317 47.367844 -51.684647 20.041901 40318 11.813203 -52.926315 19.406715 40319 12.048759 -53.981857 20.231857 40320 12.633316 -52.716858 20.288681 40321 49.513657 -51.855438 19.731827 40322 48.629028 -52.156296 19.968460 40323 11.067429 -52.907974 18.673111 40324 20.964951 -53.549179 19.366493 40325 36.673637 -53.664520 19.700203 40326 49.344528 -52.529648 19.886482 40327 58.724487 -52.791092 20.131348 40328 21.587418 -54.805710 18.597961 40329 21.386444 -53.953522 19.794098 40330 21.699402 -54.662033 19.325050 40331 38.383774 -54.338623 20.144791 40332 42.937225 -52.489075 19.829346 40333 43.284454 -53.131119 19.376434 40334 46.812225 -53.013794 19.667061 40335 43.247681 -51.939529 20.315308 40336 47.771606 -52.979843 19.693787 40337 45.915771 -52.631821 19.790611 40338 58.489853 -53.971756 20.106575 40339 11.749733 -55.332626 20.664970 40340 10.583450 -56.060867 19.622124 40341 10.983780 -56.452316 20.811470 40342 21.813522 -54.500488 20.327011 40343 21.823807 -54.377243 20.995209 40344 22.154907 -55.120087 21.056076 40345 58.319275 -51.805832 21.020874 40346 57.862030 -52.870865 21.491165 40347 4.964211 -56.093918 19.179367 40348 40.550964 -55.698883 21.343269 40349 39.541122 -54.949951 21.339409 40350 40.458984 -54.932938 22.466400 40351 58.086609 -55.496567 19.902115 40352 57.818771 -54.560608 21.124992 40353 4.932610 -58.315048 19.537399 40354 5.840790 -57.946411 18.687126 40355 20.914162 -56.815765 18.844429 40356 35.674210 -56.169922 19.200745 40357 35.907181 -56.905014 19.531464 40358 57.434692 -57.076187 19.766708 40359 57.564972 -56.049377 20.903702 40360 19.192192 -58.228424 18.961494 40361 20.546463 -57.711197 19.609474 40362 36.254204 -57.458267 19.304680 40363 5.876968 -58.770248 19.212708 40364 6.720062 -59.172241 19.723854 40365 7.731308 -58.640839 19.975517 40366 8.549408 -57.973618 19.616013 40367 17.317047 -59.055206 18.647102 40368 19.817993 -58.363953 19.854980 40369 19.156265 -59.025589 19.869179 40370 36.825294 -57.980667 19.489372 40371 37.739838 -58.684875 19.044617 40372 51.129562 -57.983978 19.867699 40373 52.558090 -58.348816 19.475998 40374 16.438858 -59.628586 18.560219 40375 16.837463 -59.263214 18.654526 40376 38.640259 -58.965317 21.469261 40377 37.568558 -58.376831 21.400826 40378 37.606285 -58.413376 20.467651 40379 53.581787 -59.180756 21.334114 40380 54.742218 -59.529510 20.613968 40381 53.812057 -59.093719 19.999657 40382 14.588745 -61.341125 17.930923 40383 15.830940 -61.019897 18.705215 40384 39.976845 -59.884415 19.296089 40385 41.448074 -60.279434 19.526886 40386 40.260025 -59.821732 20.035851 40387 54.536270 -59.425186 19.957283 40388 55.904266 -59.295090 20.648697 40389 14.806412 -62.063705 18.262131 40390 15.798759 -62.090210 18.816536 40391 44.981628 -60.618103 21.082550 40392 43.339005 -60.309479 21.495415 40393 47.534195 -62.691620 19.717033 40394 48.578339 -62.804504 20.009239 40395 50.058167 -61.879807 20.947487 40396 49.597961 -61.469864 21.019302 40397 49.456177 -62.364990 20.474197 40398 14.445488 -62.893051 17.925026 40399 15.326393 -62.979858 18.378326 40400 16.612747 -62.886200 19.020309 40401 46.226730 -63.263885 19.472260 40402 45.622955 -63.704834 20.355888 40403 48.980042 -63.347778 20.945099 40404 16.958839 -64.788208 18.608559 40405 16.850555 -65.584778 18.283432 40406 43.526230 -64.406296 19.457779 40407 42.792725 -65.142685 19.456215 40408 42.438782 -64.384247 20.149170 40409 17.688416 -65.393631 18.668716 40410 15.775909 -67.428787 18.119949 40411 41.857574 -64.919434 19.894264 40412 52.743484 -65.696823 18.541641 40413 53.228699 -65.548737 18.344360 40414 7.733978 -68.211090 17.936539 40415 17.580872 -66.723083 18.319870 40416 18.794449 -65.485428 19.006767 40417 18.903343 -66.689926 18.672554 40418 17.238472 -68.856445 18.429955 40419 18.214035 -70.016159 18.447411 40420 17.609612 -70.289597 18.720154 40421 43.520676 -65.656906 19.106102 40422 44.197098 -66.139984 19.263931 40423 42.744659 -66.151001 20.018242 40424 41.054825 -65.503067 20.355415 40425 42.019562 -65.426208 19.810219 40426 45.175812 -66.571487 19.582367 40427 47.810226 -66.604446 19.226334 40428 47.023743 -66.746414 19.637199 40429 48.782104 -66.636292 19.462708 40430 51.765594 -66.123245 19.008324 40431 52.428757 -66.157791 18.942467 40432 53.230270 -66.157974 18.520508 40433 52.772476 -66.857452 18.894035 40434 7.933403 -68.383255 18.771294 40435 13.238251 -67.583893 18.604744 40436 11.513115 -67.523270 19.222496 40437 14.464180 -67.817154 18.606262 40438 18.956680 -68.056610 18.638725 40439 19.885468 -66.369232 19.469536 40440 52.447083 -67.492783 19.373367 40441 15.686180 -68.186584 18.445801 40442 17.442719 -70.851425 19.268112 40443 16.348633 -70.051987 19.555466 40444 19.744408 -67.984055 19.514343 40445 52.106766 -68.444946 19.364334 40446 51.862320 -68.259048 20.476540 40447 52.028412 -67.558426 20.223312 40448 19.438637 -68.890182 19.191917 40449 19.160461 -69.211014 18.705811 40450 8.655426 -70.766022 18.006073 40451 18.645317 -69.362061 18.471527 40452 45.586151 -70.848648 18.789513 40453 45.266724 -70.507690 18.257416 40454 46.301880 -70.703247 18.850853 40455 47.177429 -70.156082 18.500748 40456 51.181229 -69.538437 19.875504 40457 49.945099 -70.240021 19.966034 40458 49.689087 -70.330505 18.865753 40459 5.222397 -72.765854 17.887375 40460 9.702591 -71.852509 18.603897 40461 10.150742 -73.352585 18.284859 40462 10.904694 -72.714264 18.140251 40463 18.279434 -70.513245 18.671371 40464 29.545044 -71.862885 18.367836 40465 30.101944 -72.300644 18.210648 40466 28.525726 -71.718033 18.536201 40467 27.381004 -72.127899 18.627899 40468 29.205032 -71.727173 18.420547 40469 5.345986 -73.388367 19.230217 40470 4.904900 -74.354431 19.150330 40471 6.930145 -72.519318 17.885887 40472 7.799286 -73.093185 18.723030 40473 27.177261 -73.538971 18.093987 40474 31.130547 -73.025986 17.844749 40475 46.438934 -71.667023 19.018768 40476 32.144577 -76.075150 20.138672 40477 31.720850 -75.255585 19.455292 40478 8.978958 -73.369507 18.312057 40479 30.841904 -74.924942 19.570190 40480 31.479004 -74.512985 19.073463 40481 34.137863 -76.282425 21.019547 40482 34.894653 -75.525299 19.763474 40483 34.617538 -75.262619 19.071030 40484 26.564392 -74.316956 19.192276 40485 26.525642 -72.811737 19.260117 40486 27.292877 -75.051331 18.006332 40487 5.134934 -76.172119 18.198463 40488 26.925903 -75.735825 19.074127 40489 35.988129 -77.055435 18.583427 40490 6.787796 -78.110092 18.636635 40491 5.701019 -77.475388 19.715210 40492 6.282547 -78.613480 19.249245 40493 32.450066 -78.476425 17.283134 40494 36.860214 -78.072418 18.978699 40495 43.738495 -77.712524 18.143150 40496 43.535828 -77.422455 18.698822 40497 44.000641 -77.011276 18.558243 40498 44.964172 -76.503082 18.825905 40499 46.055817 -76.160614 18.308540 40500 7.477814 -78.212860 18.054390 40501 7.854064 -78.542145 18.003502 40502 7.594971 -78.893906 17.961411 40503 14.540557 -78.447205 16.485687 40504 32.343369 -78.154434 16.935287 40505 37.722649 -77.245117 19.767784 40506 38.075348 -78.148224 19.831711 40507 37.591042 -78.292877 19.380173 40508 43.176895 -78.966156 19.023727 40509 26.803909 -80.211304 16.878365 40510 27.433189 -79.863754 17.987129 40511 27.384735 -78.652893 19.230026 40512 27.383156 -77.154984 18.552322 40513 43.407867 -77.031921 20.710831 40514 43.828705 -76.814560 19.495255 40515 6.239716 -80.585693 17.381958 40516 6.766823 -79.388123 18.128548 40517 42.887817 -78.816803 22.119064 40518 31.681719 -79.860077 17.772896 40519 31.557014 -80.924850 18.540733 40520 30.734924 -82.091599 17.994164 40521 42.516708 -81.395996 17.737335 40522 42.750549 -80.752533 18.827362 40523 5.275436 -82.576462 17.965103 40524 5.275086 -83.527847 17.793846 40525 26.790939 -82.931152 18.628090 40526 30.116081 -83.210739 17.720886 40527 37.012810 -84.177505 17.831429 40528 5.382172 -84.005478 17.956276 40529 5.557953 -84.312943 17.969200 40530 23.944870 -83.929352 17.683655 40531 22.971375 -84.410324 17.594269 40532 23.186043 -84.616150 19.083031 40533 24.610207 -84.237839 18.776756 40534 35.178848 -84.338654 17.359184 40535 22.369400 -84.904922 17.321594 40536 35.058426 -85.857178 17.430130 40537 35.448166 -85.009552 18.434410 40538 5.961830 -84.933121 17.880783 40539 7.295784 -85.903351 16.372704 40540 29.105949 -85.908951 17.883408 40541 40.028870 -84.479187 18.846039 40542 6.818138 -86.072342 16.967224 40543 6.489815 -86.086914 17.738678 40544 35.163635 -85.898849 18.370872 40545 34.992310 -86.909012 18.242775 40546 35.202095 -87.033295 17.275124 40547 30.495026 -88.152954 17.601997 40548 28.966843 -86.745148 17.702797 40549 29.170959 -87.403351 17.371323 40550 34.823532 -87.930405 17.242798 40551 7.014267 -90.040680 16.364281 40552 22.148460 -86.779037 18.330879 40553 24.970924 -89.348633 18.043152 40554 23.917755 -88.121368 19.117416 40555 34.288696 -88.628464 17.131104 40556 13.807999 -91.411880 17.961632 40557 12.615173 -91.377396 17.202446 40558 12.984055 -92.094254 18.482628 40559 15.640228 -90.992569 16.160767 40560 31.973757 -88.645432 18.579575 40561 32.271469 -88.763474 17.307686 40562 33.776802 -88.347519 18.100594 40563 33.538651 -88.864090 17.087509 40564 11.782867 -92.137527 17.725594 40565 7.623413 -90.982727 16.271805 40566 10.348572 -92.432648 17.602036 40567 10.884277 -92.923035 18.947937 40568 11.774902 -92.565628 18.606155 40569 14.469543 -93.249512 16.680267 40570 15.108276 -90.962784 16.848312 40571 14.844131 -91.298660 17.594597 40572 15.228455 -91.911972 16.679634 40573 14.882370 -92.730682 16.554276 40574 26.793732 -92.206482 17.184708 40575 26.096878 -91.189941 17.044441 40576 13.714996 -94.027023 16.887329 40577 19.952530 -93.648666 17.059837 40578 20.472908 -93.265472 17.384109 40579 25.243164 -93.990646 17.597488 40580 25.426537 -93.080261 19.379532 40581 26.768639 -92.624130 18.859756 40582 18.305725 -95.207153 16.600533 40583 22.861542 -94.845169 16.844955 40584 22.387794 -93.279510 18.373276 40585 24.634850 -95.081421 16.381065 40586 26.698441 -92.782806 17.539993 40587 17.641220 -95.768768 16.627014 40588 17.099808 -96.585098 16.447624 40589 17.562660 -95.717972 17.353157 40590 17.862831 -95.989273 16.234268 40591 23.860916 -93.892349 18.210747 40592 16.071411 -96.295273 17.544693 40593 14.392204 -96.516068 16.833061 40594 16.067261 -95.845108 19.150711 40595 17.406830 -95.747040 18.552963 40596 14.484193 62.529404 27.421005 40597 8.691452 61.011658 29.040375 40598 7.626777 60.551819 29.080620 40599 8.204041 60.014236 28.345657 40600 10.789658 60.800781 26.961334 40601 9.128342 58.956299 27.361427 40602 9.226669 59.831192 27.647743 40603 8.440125 58.928162 27.827866 40604 9.978798 60.988037 27.838440 40605 9.564941 58.990433 27.087318 40606 17.723213 59.210281 28.193703 40607 18.499474 57.968002 28.299873 40608 5.583077 52.750076 26.980202 40609 7.786926 53.191101 26.442200 40610 23.886627 52.494232 27.244774 40611 23.402252 53.537903 28.312607 40612 22.485947 53.137253 27.725510 40613 25.307571 52.127670 27.095757 40614 25.286346 52.781479 27.711800 40615 24.544647 53.308228 28.316246 40616 26.230576 52.143860 27.853409 40617 3.463844 50.601456 26.360397 40618 4.466324 52.342346 27.079666 40619 19.827240 52.129120 26.591133 40620 20.839523 51.493271 26.598198 40621 21.555145 52.550690 27.288475 40622 20.414581 52.692047 27.066605 40623 21.875755 51.539459 26.707787 40624 22.543182 52.188019 27.093765 40625 25.874611 52.759232 28.180534 40626 33.726303 50.966293 27.391853 40627 32.832054 50.385651 28.233521 40628 3.562286 50.207977 27.228424 40629 3.338074 50.705078 26.862785 40630 3.599297 51.386749 27.165787 40631 26.870621 51.519043 28.853081 40632 36.180695 49.926025 26.911560 40633 4.851379 49.104996 27.546021 40634 37.423828 48.737762 27.089577 40635 5.832947 48.538177 27.026955 40636 31.917147 48.407593 27.799675 40637 31.691553 47.920380 26.495079 40638 27.267693 46.821182 26.736832 40639 39.696846 44.974747 27.326393 40640 39.012871 46.221039 27.196587 40641 10.526108 45.311310 26.230675 40642 27.101608 45.806976 26.542519 40643 27.856361 46.365463 27.556915 40644 5.682839 44.348572 27.874748 40645 10.623810 45.651581 27.491821 40646 27.376846 44.817215 27.221352 40647 31.997339 46.126831 27.036789 40648 41.072266 44.516037 26.483047 40649 9.969666 44.567596 26.504028 40650 27.147842 43.815979 27.716187 40651 27.477676 44.492676 28.010986 40652 40.580994 43.984619 27.197105 40653 3.479874 40.861786 25.890045 40654 30.235428 41.896561 26.845802 40655 35.353424 41.901581 27.540352 40656 36.095314 42.968750 27.892570 40657 35.997124 42.003479 26.953949 40658 36.773018 44.611176 28.738312 40659 37.790344 43.589096 27.797760 40660 39.039337 41.232971 26.919334 40661 38.833687 40.003632 26.207550 40662 41.038284 43.119965 27.240395 40663 42.537506 41.645645 26.691933 40664 35.309845 42.085312 28.545624 40665 36.184479 41.632614 26.476295 40666 38.825165 42.673447 27.454346 40667 4.393746 39.835037 25.246315 40668 3.863617 39.999512 25.759323 40669 5.343605 38.548401 25.706902 40670 6.427536 38.432968 25.225937 40671 35.128464 39.970856 26.319008 40672 4.268868 39.068588 26.022079 40673 6.815857 37.723022 25.363251 40674 6.027702 37.680710 25.755524 40675 26.966064 39.889648 26.612122 40676 27.367851 39.766479 27.222198 40677 29.621231 41.049927 27.214600 40678 34.900642 39.003525 26.407204 40679 39.471870 39.037140 26.216522 40680 40.322235 38.602081 26.675873 40681 39.829391 39.951218 26.853676 40682 44.082855 38.930328 26.720802 40683 6.926880 36.851440 25.491043 40684 5.890167 36.419830 26.153419 40685 6.968140 35.929779 25.704781 40686 7.001305 35.005234 26.263657 40687 8.117706 35.666763 25.420845 40688 33.839859 36.575439 26.265930 40689 34.527695 37.635834 26.499611 40690 45.066940 37.070587 26.187607 40691 33.026245 35.867523 26.172096 40692 32.785751 35.445206 27.088684 40693 33.370529 36.039429 26.949173 40694 42.115707 36.112610 26.568771 40695 41.933029 34.612061 26.257530 40696 43.353760 35.261612 26.234901 40697 44.498962 36.330139 26.276100 40698 43.408463 36.856812 26.956192 40699 44.453079 37.515991 26.678406 40700 8.614029 33.917297 26.267647 40701 9.397461 34.191849 25.367111 40702 30.855286 31.347076 26.069702 40703 36.206367 33.829956 25.535004 40704 37.742569 34.320465 26.080063 40705 37.002991 33.863937 26.232208 40706 38.753540 34.344360 26.303383 40707 39.855560 34.450577 26.201538 40708 40.758087 34.041351 26.776070 40709 39.564552 33.857361 27.059227 40710 42.899139 33.892944 26.223282 40711 43.552063 33.326218 26.830856 40712 6.278999 34.598312 26.952194 40713 6.089256 34.262787 27.717819 40714 7.725776 33.727783 27.543022 40715 9.558662 33.440704 25.789543 40716 10.190742 32.746567 26.356705 40717 36.271317 33.301788 26.351280 40718 42.068695 33.680099 26.648544 40719 41.538574 33.509399 27.881783 40720 32.112999 33.608658 28.155548 40721 31.039795 32.199829 28.320145 40722 31.717310 32.489929 29.502930 40723 42.746979 33.391449 26.578659 40724 11.770248 31.485672 25.379402 40725 45.970032 32.392426 27.186913 40726 46.690414 31.609802 27.287003 40727 46.319977 31.841660 28.137512 40728 4.097511 30.107697 25.635689 40729 3.213905 29.824387 25.673470 40730 4.996948 29.541748 26.234146 40731 3.616547 28.983643 26.889267 40732 12.273178 30.508682 25.454567 40733 29.887497 30.794998 27.042000 40734 30.548264 31.706924 27.270912 40735 30.280083 30.027252 26.133888 40736 46.894684 30.931244 26.973579 40737 7.844864 29.100449 25.164925 40738 12.683182 28.951614 25.811813 40739 12.598167 28.484070 24.547508 40740 30.806290 29.735260 25.730095 40741 30.068329 28.155319 27.011734 40742 30.150681 29.041656 26.500534 40743 31.158745 28.677444 26.720688 40744 30.702942 29.313278 26.089355 40745 7.831222 27.332611 26.767929 40746 8.864143 27.992294 25.352043 40747 9.029495 26.493774 26.400818 40748 45.445648 28.957016 26.194389 40749 45.085007 28.524750 26.894943 40750 9.860855 27.124039 25.363785 40751 12.671844 27.262543 26.999504 40752 12.002762 26.202438 26.303543 40753 42.536041 27.426788 26.911995 40754 44.060425 28.131226 27.295433 40755 2.464028 26.711411 25.192879 40756 10.997147 26.350708 25.568802 40757 40.973267 26.769958 26.153847 40758 42.208725 27.336029 26.088432 40759 51.054398 27.345413 27.032852 40760 53.034088 26.217667 25.581848 40761 2.783791 25.268433 24.856400 40762 11.635513 26.250290 25.577309 40763 41.102982 26.392746 28.548210 40764 40.788071 26.226257 27.362770 40765 40.708511 25.214249 27.359398 40766 40.295731 25.558380 26.479027 40767 47.662689 25.432770 25.749168 40768 2.877236 24.065460 25.333969 40769 46.802139 25.054382 25.952560 40770 52.974075 25.573135 26.623825 40771 3.960678 22.679535 24.530609 40772 41.256836 24.263336 26.926430 40773 44.597702 23.932907 25.530159 40774 46.458191 25.215622 27.233994 40775 45.640564 24.506348 26.175728 40776 4.610977 21.315765 24.721603 40777 3.047318 22.612137 25.749474 40778 3.676323 21.207932 25.716110 40779 42.594452 23.581680 26.005737 40780 41.873840 23.717133 26.229149 40781 43.538620 23.710220 26.044006 40782 51.697296 22.108810 26.357285 40783 52.884949 23.194305 25.873940 40784 50.677048 20.336182 25.756729 40785 50.693207 19.648224 25.785698 40786 50.102570 19.876877 26.260529 40787 54.953659 18.612640 25.404381 40788 55.123520 18.395874 26.357811 40789 55.998795 17.956390 25.322609 40790 5.128998 17.225433 24.498047 40791 3.128415 12.329604 19.838169 40792 3.439215 13.084309 20.765860 40793 3.122325 11.604402 20.268688 40794 3.378673 11.826658 21.295639 40795 3.829387 14.249372 21.683950 40796 4.272687 15.258041 22.882750 40797 57.505707 16.234070 25.415131 40798 57.070786 16.839569 25.383484 40799 57.325928 15.093338 25.877518 40800 51.224701 14.109116 25.065758 40801 49.044510 13.728638 24.979340 40802 57.152740 15.336899 26.850853 40803 47.351440 12.835922 24.488869 40804 48.112274 13.034897 25.089264 40805 53.089218 9.645477 26.371292 40806 53.345016 8.633514 25.593018 40807 53.504364 8.560822 24.776672 40808 2.415658 4.197866 20.495928 40809 2.266143 3.000155 20.150751 40810 2.154680 2.646506 19.394308 40811 46.887375 4.924271 26.426048 40812 48.307068 5.333084 26.737297 40813 48.540756 5.370346 25.706169 40814 47.542633 5.139175 24.825897 40815 2.077457 2.349902 18.410652 40816 17.306555 5.539322 25.054434 40817 44.975342 4.432678 24.418098 40818 44.063583 3.967789 24.465721 40819 44.799438 4.166885 25.673164 40820 59.587341 5.743378 24.765373 40821 2.183579 1.957133 19.822531 40822 43.048248 3.014191 24.461548 40823 43.418808 3.444229 24.272423 40824 52.221283 2.959473 24.214951 40825 53.217941 3.569519 25.011505 40826 59.246643 2.656830 25.130714 40827 2.280289 1.268758 20.783606 40828 2.165975 0.938207 19.878607 40829 2.081476 1.460224 18.702686 40830 51.449829 2.529572 24.170692 40831 43.130646 3.414597 25.431717 40832 43.807983 0.372482 24.202400 40833 44.161224 -0.193283 25.062965 40834 42.900787 0.333588 25.687309 40835 44.195648 -0.498611 26.227280 40836 42.951233 -0.336243 26.955811 40837 45.875641 -0.434570 24.617371 40838 57.454865 0.004608 24.305382 40839 58.323425 -0.667984 25.481079 40840 59.814392 -2.100037 26.874695 40841 40.593231 -10.040390 22.462051 40842 60.682816 -6.055267 24.788216 40843 60.213577 -6.754868 24.419281 40844 60.475525 -8.047348 25.225739 40845 34.927452 -9.807297 22.373390 40846 35.755051 -9.956787 22.466667 40847 36.741692 -10.250626 22.506393 40848 38.496979 -9.070724 22.073814 40849 37.904770 -9.945084 22.422981 40850 39.439568 -9.683868 22.346863 40851 42.475159 -9.761505 22.593956 40852 60.137573 -8.727951 24.128616 40853 2.519039 -9.992196 20.747725 40854 2.632635 -9.706616 22.617910 40855 35.062225 -10.503754 22.567238 40856 60.860641 -9.420868 24.019897 40857 61.012375 -9.876053 24.764793 40858 61.962418 -10.253265 24.156448 40859 61.927521 -9.646774 23.438873 40860 60.441818 -9.194107 24.782768 40861 35.718185 -11.544907 22.729843 40862 62.978790 -11.009811 23.731201 40863 2.697029 -11.118263 22.088699 40864 34.227753 -14.096130 22.630234 40865 35.140747 -13.247849 22.761688 40866 36.084778 -14.147781 22.705673 40867 55.778412 -13.624573 23.457619 40868 55.119659 -13.146683 24.676842 40869 57.253235 -13.275421 23.508972 40870 56.561600 -13.186615 24.519348 40871 2.886693 -13.669317 22.014978 40872 34.300896 -16.646240 22.864265 40873 35.428200 -17.206894 23.183571 40874 38.740845 -15.298065 22.305504 40875 38.073532 -16.901138 22.600945 40876 36.694183 -16.563171 22.997147 40877 61.508133 -15.517960 23.667717 40878 63.743057 -14.704712 23.837830 40879 63.270798 -15.399887 24.275986 40880 63.505035 -14.686813 24.856163 40881 34.452484 -18.059250 23.134636 40882 37.461067 -16.905106 22.863945 40883 62.305298 -15.833237 23.606689 40884 37.744812 -17.380203 22.443077 40885 54.896179 -17.419846 23.415199 40886 55.513458 -18.417587 23.665970 40887 32.251221 -19.020599 22.310234 40888 36.754471 -17.465454 22.710693 40889 35.724258 -18.106445 22.901291 40890 34.025391 -19.299591 22.557762 40891 33.224655 -20.112656 22.345390 40892 60.143829 -19.635239 23.695107 40893 61.331940 -19.824097 23.610138 40894 62.189240 -20.312256 22.795555 40895 62.383057 -20.353210 23.774010 40896 32.680214 -19.823181 22.679771 40897 33.092255 -19.463318 22.733536 40898 41.523285 -21.227905 22.264503 40899 42.313828 -21.284927 22.747734 40900 43.446106 -21.281677 22.296234 40901 42.912567 -21.186478 22.657150 40902 58.374969 -19.624603 24.074333 40903 57.349854 -19.353348 24.407494 40904 63.031174 -21.676346 24.396111 40905 62.245941 -20.112839 25.830162 40906 3.840776 -21.737970 22.100733 40907 3.847247 -22.505510 22.692068 40908 3.915091 -23.045420 21.859837 40909 38.575745 -23.107346 22.380127 40910 37.919807 -22.747726 22.112030 40911 37.247757 -23.980362 22.524574 40912 42.630341 -22.551758 21.598129 40913 42.473297 -21.612442 22.769554 40914 33.048584 -26.103333 23.084732 40915 34.042381 -26.045227 23.074501 40916 36.095413 -23.523987 22.171631 40917 4.276913 -25.351036 20.340899 40918 4.011574 -24.103998 21.325779 40919 29.938400 -25.066360 21.501663 40920 30.537003 -25.351669 22.033592 40921 31.832743 -25.351624 22.658821 40922 32.051262 -26.286148 23.191963 40923 35.929932 -24.086304 22.534454 40924 62.832672 -25.810562 22.896713 40925 63.190735 -25.273468 23.952019 40926 30.225327 -26.130066 21.918762 40927 30.889130 -26.215363 22.554008 40928 37.162704 -25.646988 22.791634 40929 30.410187 -26.836792 21.937210 40930 38.666458 -26.750443 22.363670 40931 38.162125 -27.800018 22.843521 40932 39.675339 -27.539474 22.288864 40933 41.472107 -27.838348 21.962883 40934 42.437164 -26.919067 21.342102 40935 62.229095 -26.990936 22.775757 40936 62.874023 -26.581619 23.939003 40937 40.869507 -27.404495 22.015106 40938 60.029495 -28.819229 23.525917 40939 4.513622 -27.673040 20.058947 40940 33.663101 -27.535233 23.092224 40941 32.347580 -27.461197 23.042145 40942 40.579498 -28.956406 21.760666 40943 40.669281 -28.291763 22.125458 40944 60.094894 -31.694839 26.719467 40945 59.685577 -32.656235 27.559196 40946 61.202423 -32.148468 27.371208 40947 62.122620 -28.124130 23.884972 40948 61.492569 -29.453735 24.646469 40949 4.521180 -30.887369 21.833969 40950 4.470609 -30.605095 22.547691 40951 4.599988 -28.771072 20.081142 40952 4.383956 -28.561203 20.948225 40953 38.861961 -29.636078 22.040962 40954 39.815582 -28.864487 22.121620 40955 47.263504 -29.181595 22.334381 40956 48.034332 -28.794373 23.546402 40957 57.434082 -29.157059 24.162392 40958 37.644989 -30.220078 21.951515 40959 38.127289 -29.490341 22.739716 40960 34.771942 -28.948822 22.917915 40961 36.368668 -30.666565 21.915154 40962 35.411118 -30.614700 22.291153 40963 43.362793 -31.506866 22.654312 40964 41.026169 -32.786118 23.141563 40965 42.315460 -32.107376 23.069298 40966 59.796600 -32.670578 21.370804 40967 60.377563 -33.025421 21.899994 40968 59.554535 -33.363297 21.974380 40969 60.440979 -33.742249 22.323906 40970 61.548981 -34.412933 22.436172 40971 61.403046 -35.781403 23.179764 40972 60.294220 -35.008377 22.849274 40973 48.598663 -35.379150 21.917023 40974 53.949966 -35.349884 21.928230 40975 53.132538 -35.449509 21.931198 40976 56.936218 -36.428345 21.692650 40977 55.921692 -37.105835 21.627747 40978 39.443390 -36.215469 22.643929 40979 40.194977 -36.513931 23.646080 40980 38.924057 -35.335739 23.419128 40981 53.903015 -36.081314 22.053642 40982 54.323471 -37.116379 21.927017 40983 58.263489 -36.218643 22.159546 40984 57.798889 -37.285095 22.064903 40985 5.184974 -34.885025 23.039455 40986 54.992615 -37.902634 22.204659 40987 58.972244 -35.426514 22.488853 40988 59.005753 -36.251022 22.538361 40989 58.367096 -37.793976 22.611855 40990 57.781448 -38.118881 22.610756 40991 52.923889 -36.804382 22.271133 40992 53.366913 -37.881668 22.390442 40993 54.136810 -37.934036 22.131973 40994 56.149628 -37.886368 22.140755 40995 56.867310 -38.297180 22.678673 40996 55.497971 -38.526764 24.035263 40997 57.039612 -37.804184 21.933403 40998 58.861557 -37.119293 22.725632 40999 5.757285 -38.559143 21.582947 41000 5.494768 -37.007492 21.854641 41001 53.854416 -38.327835 23.009674 41002 5.916969 -41.668320 20.403778 41003 50.513626 -42.568298 21.850372 41004 51.775284 -42.533417 22.174942 41005 54.809219 -42.546249 21.273018 41006 54.681274 -43.150665 22.134735 41007 53.343536 -42.495697 21.719574 41008 53.240723 -43.040680 22.582993 41009 48.670151 -43.446243 22.584198 41010 49.553741 -43.158005 21.775337 41011 48.962402 -44.107330 21.689461 41012 49.747253 -43.772171 21.134567 41013 54.512222 -43.596359 22.792114 41014 56.154053 -43.556351 21.759262 41015 62.371353 -43.184662 21.770973 41016 62.526260 -42.747192 22.026810 41017 49.856110 -44.843384 21.293312 41018 48.413727 -45.184891 22.161163 41019 4.707405 -44.194611 21.500656 41020 4.729332 -45.673874 22.326996 41021 48.214050 -44.305649 22.172516 41022 49.635406 -45.821838 21.977539 41023 50.251282 -46.718826 22.402016 41024 54.101227 -47.412720 21.496857 41025 53.193008 -47.935959 22.264175 41026 55.110016 -49.007095 21.913544 41027 54.700745 -48.133484 21.631615 41028 55.686768 -43.975281 22.629074 41029 57.271301 -45.282532 23.050209 41030 55.185486 -44.476273 23.442001 41031 61.615051 -44.741608 22.321892 41032 7.403092 -47.468948 20.827057 41033 7.896934 -47.960724 20.559494 41034 51.489563 -46.761673 21.981956 41035 53.854858 -46.190170 20.634621 41036 60.100967 -45.896606 21.957726 41037 60.484039 -45.796844 21.783295 41038 8.175842 -48.705627 20.237198 41039 7.589707 -47.678207 21.233353 41040 6.720253 -47.533279 21.571922 41041 8.445183 -48.607117 21.087364 41042 42.870621 -49.594543 20.431808 41043 43.302917 -48.254456 20.466904 41044 43.138214 -48.885010 20.650200 41045 43.307709 -49.268539 20.754234 41046 43.980011 -50.844772 20.609886 41047 44.119720 -49.270187 20.516403 41048 56.100098 -49.885712 21.891296 41049 42.820251 -51.066574 20.286598 41050 58.417862 -50.831757 20.479080 41051 14.610138 -51.124878 19.906158 41052 15.237511 -51.677414 20.214363 41053 13.416870 -52.308884 21.052383 41054 15.834778 -52.153946 20.308220 41055 15.581314 -52.534744 21.388000 41056 18.056778 -53.453629 20.417969 41057 20.706253 -53.710846 20.536728 41058 21.505928 -54.043518 20.733994 41059 43.663971 -51.636673 20.551117 41060 57.893890 -51.875214 21.772087 41061 57.538071 -52.001541 22.047836 41062 4.876526 -54.077744 19.630760 41063 5.239876 -53.123215 19.397079 41064 18.961487 -53.586731 20.600243 41065 36.173874 -54.466614 20.487144 41066 35.764923 -55.900314 20.271881 41067 37.705414 -53.687088 22.566658 41068 36.858879 -53.676895 23.371643 41069 12.427643 -54.526947 20.984055 41070 21.878578 -55.566895 19.929787 41071 4.615936 -56.006729 20.264671 41072 9.829765 -57.194702 20.285995 41073 8.769592 -58.270279 20.731499 41074 21.631577 -56.710846 20.030777 41075 41.451202 -56.280380 20.648918 41076 5.093392 -59.192535 19.583252 41077 4.604401 -57.173264 20.336441 41078 17.989738 -59.174103 19.165749 41079 18.341583 -59.874496 19.811356 41080 36.646255 -57.591522 21.653145 41081 35.765610 -56.094315 22.647148 41082 35.850174 -56.159775 21.420097 41083 36.280899 -57.227188 20.286606 41084 36.851761 -57.857086 20.432182 41085 49.124771 -57.458221 20.563339 41086 57.129425 -57.521332 20.819092 41087 57.155731 -56.604767 21.661209 41088 4.558022 -59.205063 20.053238 41089 16.962799 -59.492371 18.986053 41090 39.106529 -59.301834 20.027435 41091 37.558319 -58.352768 22.288773 41092 38.553841 -58.809692 22.888908 41093 50.105820 -57.751373 20.605309 41094 56.606125 -58.637604 20.930679 41095 56.756943 -57.796158 21.815102 41096 56.243546 -58.984329 21.723923 41097 4.778504 -59.953690 20.004517 41098 5.758896 -59.880539 19.802574 41099 6.579254 -59.938934 20.222054 41100 16.383942 -60.095947 18.915497 41101 17.204788 -60.357925 19.324020 41102 18.331055 -60.834335 19.894043 41103 52.485901 -58.677353 20.591705 41104 40.592529 -59.745361 21.112228 41105 48.114441 -60.995102 20.682358 41106 49.074203 -60.803024 22.281227 41107 48.613464 -60.617950 22.273224 41108 48.840530 -60.940765 21.399765 41109 5.082626 -62.421753 19.472054 41110 4.443924 -62.009674 19.992439 41111 4.810700 -63.394745 19.632019 41112 5.014908 -61.812088 19.677414 41113 5.720215 -61.990341 19.684845 41114 5.130180 -61.050980 19.936424 41115 17.105621 -61.673691 19.367165 41116 48.100830 -60.630844 21.587250 41117 5.807579 -63.087555 19.374672 41118 5.829880 -64.162079 19.402824 41119 6.397186 -63.580200 19.378166 41120 7.001816 -62.666718 19.889969 41121 6.676727 -63.985840 19.645706 41122 17.729332 -64.100739 19.082680 41123 46.481384 -63.678329 21.145714 41124 50.154800 -63.413940 21.795937 41125 50.295227 -62.379807 21.218636 41126 4.947769 -64.696686 19.873795 41127 7.787048 -64.928192 21.431244 41128 8.728867 -63.983292 21.016266 41129 7.537010 -63.963943 20.272560 41130 18.161087 -62.594528 19.652054 41131 20.287376 -64.860901 19.755859 41132 19.679970 -65.091217 19.437012 41133 19.590576 -63.782181 19.775497 41134 21.167038 -64.152344 20.335815 41135 40.714874 -64.437714 21.181297 41136 41.547104 -64.530060 20.434875 41137 44.598633 -63.990417 22.064873 41138 47.935516 -63.524277 21.078804 41139 6.274117 -65.136688 20.230476 41140 5.058685 -65.807098 20.481491 41141 39.618820 -66.250565 20.714943 41142 39.677925 -65.259811 20.893883 41143 44.307831 -66.869568 20.561615 41144 51.715302 -66.755142 19.671310 41145 50.876450 -67.102341 20.727104 41146 7.269425 -69.482681 20.131371 41147 7.367012 -69.758011 19.139359 41148 8.438110 -68.274109 19.976166 41149 10.533798 -67.554581 19.691032 41150 9.535538 -67.887360 20.300552 41151 11.409302 -68.209366 20.569275 41152 12.452782 -67.951019 19.431221 41153 13.472763 -68.268875 19.537567 41154 46.104218 -67.275665 21.058601 41155 47.952118 -67.069550 20.662903 41156 49.591431 -67.140747 21.013214 41157 51.597931 -67.174683 20.569290 41158 15.578102 -68.709717 18.985443 41159 18.972099 -69.992462 19.222054 41160 19.566391 -68.662842 20.308823 41161 51.455246 -67.690247 20.982925 41162 51.733383 -68.938873 20.029800 41163 7.260239 -69.492416 20.921356 41164 7.060562 -69.797791 20.918854 41165 19.229607 -69.784363 20.851921 41166 47.230286 -70.611359 19.050201 41167 48.342346 -70.531494 19.102867 41168 50.568222 -67.819214 21.824310 41169 51.039352 -68.919067 21.144882 41170 50.778168 -68.476135 22.343452 41171 7.828582 -70.673157 18.977402 41172 8.597778 -71.354187 19.009560 41173 18.223434 -70.884567 19.102196 41174 26.737366 -71.956497 19.126785 41175 26.511108 -71.835312 19.637283 41176 26.985741 -71.539108 19.478203 41177 26.188492 -72.171768 20.390259 41178 27.946426 -71.386658 19.829506 41179 26.853668 -71.214264 20.557114 41180 27.758156 -70.728058 21.247955 41181 29.279221 -71.942703 19.305168 41182 47.366913 -71.419724 19.437256 41183 47.972229 -72.731445 20.701630 41184 48.683411 -71.251022 20.349274 41185 49.812225 -70.514359 21.401520 41186 30.324287 -72.837097 18.854294 41187 31.598221 -73.841919 18.334534 41188 8.678794 -73.208633 19.624168 41189 7.883865 -73.181274 19.610054 41190 7.185333 -73.029160 19.518768 41191 9.547562 -73.358612 19.122032 41192 9.999496 -72.827652 19.052521 41193 36.835289 -76.205719 19.554001 41194 47.143616 -74.492828 20.722595 41195 45.967178 -75.769135 19.562866 41196 7.011780 -78.644211 18.543488 41197 32.895035 -81.652313 20.741364 41198 32.325851 -81.170731 19.712723 41199 35.787643 -80.428406 20.217278 41200 36.878761 -79.241043 19.494049 41201 5.690117 -83.999420 18.942596 41202 5.603890 -81.360855 18.328651 41203 27.546173 -80.548874 18.959106 41204 27.254333 -81.913315 18.696648 41205 31.319298 -82.027008 19.299385 41206 30.672684 -83.057816 18.809616 41207 42.215668 -81.905441 18.865120 41208 26.364845 -83.689423 18.887856 41209 41.174973 -83.377487 19.006844 41210 25.649330 -84.068024 18.922699 41211 30.160965 -83.915115 18.439758 41212 36.039146 -85.052490 19.239311 41213 36.287247 -84.549927 18.748787 41214 22.024460 -85.660583 18.080757 41215 22.411865 -84.922073 18.405937 41216 35.977707 -84.165314 18.057098 41217 36.096809 -85.451157 19.810196 41218 37.204720 -85.069885 19.648285 41219 6.166878 -85.706284 18.761566 41220 13.713455 -86.078262 18.137230 41221 13.537201 -86.110504 18.376389 41222 13.710091 -85.844498 18.293442 41223 13.884827 -85.962265 18.318085 41224 29.691032 -86.041153 18.816086 41225 40.134064 -84.256882 19.729454 41226 6.533310 -87.446564 19.080833 41227 13.796448 -86.291275 18.309258 41228 29.271339 -86.669922 18.085510 41229 35.416817 -85.914673 19.174767 41230 22.673553 -87.329041 19.021324 41231 29.705704 -87.008163 18.345100 41232 7.057434 -89.637619 18.020020 41233 26.640480 -88.758652 21.171936 41234 27.264732 -89.698685 19.979134 41235 27.606949 -90.032791 20.922081 41236 7.649931 -90.976913 17.332321 41237 27.294861 -90.691940 18.913132 41238 26.733284 -89.704712 19.203209 41239 26.356743 -90.201263 18.323586 41240 30.968262 -88.161957 20.012161 41241 31.875154 -88.752808 20.339073 41242 32.089615 -88.731903 19.611000 41243 33.155884 -88.525131 19.228256 41244 14.179573 -90.842575 17.157333 41245 8.104698 -91.657547 17.564117 41246 14.423531 -91.188049 17.859680 41247 14.801537 -92.570511 17.443329 41248 8.817139 -92.071548 17.485794 41249 9.510796 -92.468613 18.687325 41250 20.422813 -93.123642 17.920883 41251 20.753052 -92.874313 17.992416 41252 21.189934 -93.007751 17.809555 41253 26.934433 -91.545105 17.905212 41254 14.257614 -93.187851 17.855049 41255 13.373611 -94.747253 17.435448 41256 18.960983 -94.962402 18.280861 41257 20.150360 -93.783310 18.018547 41258 24.703712 -93.697525 18.605934 41259 14.953568 -95.940689 18.249374 41260 13.272095 62.005280 28.533524 41261 12.108704 61.853027 28.686737 41262 11.026993 61.329300 29.744524 41263 15.040833 62.021454 28.505669 41264 14.265411 61.955688 28.890854 41265 15.753464 61.398972 28.804726 41266 7.732727 58.205688 28.185959 41267 10.257812 61.762283 28.694885 41268 14.953262 61.261032 29.393555 41269 9.520905 61.589478 29.068916 41270 16.748329 60.590164 28.289688 41271 15.975662 60.419342 29.478653 41272 7.100975 59.228043 28.881813 41273 6.713417 57.400055 28.773193 41274 7.088410 56.137100 28.430450 41275 7.893150 56.472519 28.134338 41276 17.025650 59.732132 29.145248 41277 19.812378 56.893829 29.123535 41278 19.307480 57.421722 29.845774 41279 18.977112 57.667023 29.145134 41280 7.721359 54.257675 27.755608 41281 6.531738 53.527664 27.689995 41282 4.940155 54.007431 28.539810 41283 7.672805 53.406998 27.089462 41284 6.879555 55.255676 28.392998 41285 6.593857 54.461655 28.313164 41286 21.684326 53.229919 27.765800 41287 22.442680 53.866196 28.414047 41288 25.524948 53.059494 29.075417 41289 25.035385 53.310944 29.054497 41290 25.442490 53.069641 28.469864 41291 3.739342 52.806274 28.452866 41292 19.842865 52.814484 26.906738 41293 20.917076 53.715469 27.757286 41294 27.938057 50.526489 28.209473 41295 35.033829 50.420746 28.060097 41296 33.850403 50.580475 28.563110 41297 35.430702 49.818939 28.957420 41298 34.463150 50.212418 29.039436 41299 4.013229 49.707397 28.135910 41300 27.800644 45.693848 28.725777 41301 32.186920 49.214813 28.625603 41302 4.660927 49.901947 30.631914 41303 5.172722 49.564880 30.345362 41304 4.646149 49.737701 29.277763 41305 36.499191 49.240448 28.206192 41306 37.009315 47.723206 29.183441 41307 37.552155 47.957245 28.157890 41308 37.632462 47.068085 28.687103 41309 36.899597 48.498276 28.779327 41310 8.517746 48.196838 27.591049 41311 32.256706 48.533844 29.748598 41312 31.920252 47.583572 28.584358 41313 32.005890 47.528519 27.539505 41314 8.345116 48.562897 28.585907 41315 8.061783 48.651779 29.241623 41316 8.588478 48.176788 29.109230 41317 32.040115 46.794754 27.607826 41318 38.126511 46.807190 28.021782 41319 40.496964 44.959106 26.765327 41320 4.632370 44.367523 27.783012 41321 10.481705 44.971130 27.125694 41322 31.775927 45.986633 27.942390 41323 31.193245 43.979553 27.681175 41324 38.413361 45.037537 28.032654 41325 3.479477 43.031616 27.850677 41326 4.775543 43.633606 28.722389 41327 3.442604 42.019318 28.728096 41328 3.377045 43.176270 26.813187 41329 9.440468 44.202744 27.508507 41330 10.184219 44.590088 27.421494 41331 40.319672 43.034424 27.655098 41332 39.358414 43.791916 27.740967 41333 3.184601 41.516724 27.088379 41334 35.515404 43.051620 28.800148 41335 41.152435 42.160400 27.300316 41336 26.737411 43.087677 28.157700 41337 30.219040 42.365356 28.298546 41338 29.946182 41.669174 27.662621 41339 35.248611 40.576050 28.433426 41340 35.887459 41.131912 29.390244 41341 39.884842 42.175735 27.566750 41342 40.406738 41.020172 27.387024 41343 41.611694 40.695724 27.441803 41344 42.873413 40.028412 27.208633 41345 3.498543 39.998657 26.635979 41346 26.603256 40.220093 27.281769 41347 26.947296 39.886673 27.256882 41348 28.932137 40.512726 28.081848 41349 40.864868 39.677353 27.263077 41350 4.842392 37.772171 26.252678 41351 35.591484 39.202209 28.643303 41352 42.106995 39.109253 27.509010 41353 41.239532 38.376831 27.123337 41354 3.455559 38.951309 27.158089 41355 3.445397 37.936829 27.723396 41356 3.967423 38.051849 26.805565 41357 4.351067 36.731888 27.168877 41358 5.272240 35.843079 26.677826 41359 43.300079 38.187820 27.327255 41360 5.900192 35.303894 26.553894 41361 42.206848 37.586441 27.170792 41362 34.296516 36.399963 28.223511 41363 36.605240 38.184082 29.406380 41364 34.927063 39.093628 27.561325 41365 5.082321 35.114578 27.431580 41366 32.141396 34.471268 27.188469 41367 37.807533 33.790497 26.963829 41368 11.335579 31.287308 27.317108 41369 9.550788 32.969482 27.178757 41370 36.983589 33.283066 27.101151 41371 38.448189 33.212784 27.975182 41372 39.771652 33.102982 28.609650 41373 43.045212 33.400848 28.805267 41374 40.943268 33.011887 30.097322 41375 42.594940 33.368790 27.229431 41376 45.778595 32.493835 28.168945 41377 11.538551 31.459045 26.080078 41378 34.761810 30.008835 28.009605 41379 33.878342 30.005981 26.964050 41380 12.190079 30.231323 26.393867 41381 5.890793 28.701309 26.939529 41382 6.977112 28.849472 26.174629 41383 4.876465 28.974503 27.079948 41384 11.248718 31.311554 28.654610 41385 11.929764 29.750671 28.354294 41386 29.340042 29.526123 27.075729 41387 33.161697 29.588165 26.812675 41388 46.809525 30.286743 27.037941 41389 6.837608 27.907867 27.186577 41390 31.953638 28.485703 27.280266 41391 32.358078 29.140915 26.809425 41392 45.627838 28.856125 26.990341 41393 46.196014 29.494370 27.052185 41394 28.788055 27.813599 27.639679 41395 30.292183 26.624985 27.492096 41396 50.159256 27.324692 26.980354 41397 2.475388 27.543991 26.864838 41398 12.419327 29.172699 27.219002 41399 12.263550 27.731583 28.456589 41400 41.674408 27.063110 27.671989 41401 42.980698 27.828903 28.135651 41402 52.580002 25.426971 27.954163 41403 51.978546 25.694458 28.878769 41404 51.914032 26.534500 27.654686 41405 51.093384 26.592697 28.795883 41406 51.092224 27.030029 27.912933 41407 2.426476 25.693100 26.117088 41408 10.931442 25.247147 26.792343 41409 12.014931 25.386826 27.607780 41410 11.553802 24.520508 27.946289 41411 39.981232 25.820175 25.754150 41412 48.180908 26.220383 27.419159 41413 47.479248 25.717484 26.761497 41414 50.240372 27.060532 28.090820 41415 2.376663 24.733582 26.836220 41416 2.508621 23.505585 26.635765 41417 42.737701 24.136200 27.356400 41418 44.420929 24.230270 26.857742 41419 51.735107 23.392334 29.115623 41420 3.051651 19.911621 27.397346 41421 4.272904 19.653290 26.049454 41422 50.806519 21.856689 27.859894 41423 4.616837 20.456223 25.221451 41424 49.962494 20.637115 27.110390 41425 50.832306 21.220078 26.415535 41426 5.034256 19.145142 25.763176 41427 4.684479 18.426987 26.350906 41428 5.052551 19.774963 25.345497 41429 49.762726 21.165070 28.520370 41430 50.307800 19.361206 26.368080 41431 49.561188 19.587967 27.180893 41432 48.982452 20.149841 28.417198 41433 5.221413 17.490051 26.070694 41434 5.152428 16.472137 25.422592 41435 50.192291 18.931580 26.974358 41436 49.463928 18.961792 27.420509 41437 54.976318 18.404648 27.740257 41438 56.541870 16.934998 27.189827 41439 56.574493 17.293259 26.171753 41440 2.898564 10.766173 19.676580 41441 4.651447 15.602602 24.344606 41442 4.697403 15.186447 25.572792 41443 5.333992 15.293701 26.468651 41444 57.277496 16.199310 26.124771 41445 3.689624 13.053662 21.902039 41446 4.406809 14.490500 24.088560 41447 4.056725 13.783869 22.967861 41448 2.722991 10.064315 19.044348 41449 52.046997 13.886108 27.118927 41450 50.541931 13.640366 27.002800 41451 51.197693 13.287262 28.251450 41452 50.117020 13.881226 25.976593 41453 49.259460 12.840103 26.168907 41454 52.159393 14.000214 26.111732 41455 51.223862 14.041840 26.268684 41456 50.187408 12.543686 27.783630 41457 50.556244 12.561249 28.489182 41458 51.631699 10.882355 27.624123 41459 52.543015 10.213135 27.800400 41460 51.659607 11.227417 28.606491 41461 52.739883 8.527237 26.914871 41462 51.708618 7.303986 25.927818 41463 51.523788 7.484802 27.521866 41464 52.804886 8.011627 25.624802 41465 57.390076 6.011398 25.577934 41466 58.771423 6.122360 27.431549 41467 56.880234 5.771988 27.905991 41468 57.006317 5.811111 26.800774 41469 59.748367 5.637016 25.741341 41470 58.959564 6.213135 25.486618 41471 46.072403 4.661957 24.882690 41472 47.686462 5.427673 27.551956 41473 41.806305 3.691940 26.767288 41474 42.602768 3.983749 26.818001 41475 42.038300 2.697784 26.052124 41476 43.679352 4.504929 27.156158 41477 45.862900 4.377579 25.786469 41478 51.376724 2.363617 25.176407 41479 55.062347 4.713821 25.739464 41480 54.907928 4.659271 27.216316 41481 58.930069 1.703705 26.077843 41482 2.372861 2.460228 21.035282 41483 2.458325 1.209081 21.894718 41484 2.273821 -0.103460 20.848984 41485 42.277451 1.649628 25.332230 41486 59.539566 2.895905 26.285088 41487 2.555481 0.024785 22.701555 41488 42.362427 2.482773 25.348221 41489 50.634171 1.942017 26.321373 41490 51.641205 2.489014 26.341469 41491 58.046631 0.292953 25.422234 41492 2.329657 -1.561273 21.585022 41493 2.238469 -1.469881 20.751566 41494 45.128494 -0.538269 25.172783 41495 58.130249 -0.372955 25.986488 41496 45.884720 -0.556763 25.232979 41497 58.362137 -0.667786 26.123528 41498 2.348151 -3.108413 21.606659 41499 60.691132 -2.557495 25.402275 41500 60.048965 -5.265549 26.931877 41501 60.632950 -2.777542 26.151466 41502 61.022766 -8.636475 26.563469 41503 60.899246 -7.460007 27.093674 41504 60.900482 -7.060593 26.074944 41505 60.113464 -8.585312 24.681770 41506 61.579605 -10.407074 25.048210 41507 62.598923 -11.268311 24.759392 41508 2.752934 -9.176764 23.688139 41509 61.852631 -10.824402 25.950920 41510 35.079720 -14.404160 22.873489 41511 63.420227 -12.767456 24.853027 41512 62.751831 -11.897827 25.767265 41513 53.450989 -13.158829 25.182022 41514 54.932968 -12.434570 25.942482 41515 2.847772 -12.659157 22.565708 41516 53.159622 -14.433670 24.542686 41517 52.494797 -13.943207 24.969788 41518 57.414215 -13.356415 24.481644 41519 58.414383 -13.773529 24.401787 41520 63.799454 -13.901260 24.492233 41521 3.013385 -15.126429 21.614540 41522 51.735413 -13.795700 25.651909 41523 52.305069 -13.371750 25.243530 41524 52.538452 -14.892975 25.139626 41525 51.949005 -14.945465 26.184814 41526 59.002289 -14.266647 25.675468 41527 60.358658 -14.915970 24.609894 41528 61.913055 -15.589218 24.633995 41529 3.293325 -17.182384 21.767939 41530 3.170342 -16.043468 22.548120 41531 3.370084 -17.301403 22.959564 41532 62.110931 -15.852951 24.096474 41533 62.660019 -15.788589 24.213715 41534 34.919037 -17.905975 23.517624 41535 35.220665 -17.856339 23.483833 41536 35.210617 -18.196152 23.437660 41537 54.321289 -16.825363 23.908974 41538 54.412704 -17.251434 24.673767 41539 32.580475 -19.328003 22.691406 41540 34.998154 -18.676498 22.909477 41541 34.912018 -18.238113 23.459747 41542 55.524597 -18.006134 25.235855 41543 59.326416 -19.394791 24.670937 41544 36.013443 -25.016617 22.819023 41545 4.077406 -24.895515 21.152464 41546 35.104057 -26.496384 23.102814 41547 36.380096 -26.311050 23.120316 41548 36.587463 -28.085709 23.132950 41549 63.047516 -21.092300 25.527382 41550 4.099389 -25.526640 21.196293 41551 4.232675 -26.233290 20.739340 41552 31.515686 -26.837463 23.072113 41553 31.512802 -26.081512 23.041695 41554 37.858078 -26.506119 22.637238 41555 37.204193 -26.845078 22.949142 41556 4.321351 -27.211048 20.659473 41557 37.730171 -28.907837 23.067085 41558 60.028427 -30.481796 25.548576 41559 58.647690 -29.640198 24.578918 41560 4.277789 -29.217775 22.732283 41561 4.220918 -28.490622 21.944817 41562 4.116853 -28.108669 22.745350 41563 38.925140 -28.741882 22.652412 41564 38.341217 -28.793732 22.993919 41565 46.606079 -29.070786 23.662849 41566 47.364258 -28.672424 24.428108 41567 37.064941 -29.651337 22.753624 41568 44.431976 -30.919006 23.764709 41569 44.850769 -30.358047 23.121208 41570 45.532837 -29.838516 23.369606 41571 35.117180 -30.123230 22.714607 41572 35.897202 -29.766098 22.827065 41573 42.937317 -31.918823 23.685509 41574 42.039886 -32.436874 23.850426 41575 39.679573 -33.367020 22.737564 41576 38.203827 -34.884537 22.219635 41577 38.228287 -35.400192 22.502419 41578 46.261810 -36.208694 22.651642 41579 50.053665 -35.688431 22.121742 41580 51.037033 -35.403107 21.898811 41581 52.026169 -35.558533 21.923203 41582 60.528320 -35.856110 23.260284 41583 59.716507 -36.262390 22.989326 41584 38.569633 -35.800598 22.440895 41585 40.813080 -36.591248 22.635040 41586 43.148926 -37.013550 23.413803 41587 42.037537 -36.670013 22.760452 41588 46.998825 -37.298416 23.825203 41589 45.135620 -37.382355 23.736229 41590 48.442841 -36.761398 23.206154 41591 49.389084 -36.523758 22.858261 41592 50.195679 -37.040436 23.085754 41593 52.294876 -37.802261 22.804771 41594 51.303558 -36.895294 22.683624 41595 5.426751 -36.306835 22.661177 41596 5.415144 -35.819893 23.343061 41597 46.651733 -38.342545 25.738342 41598 45.542206 -38.061340 24.954399 41599 49.789551 -37.833054 24.123367 41600 59.685257 -37.575760 23.480240 41601 60.616318 -36.808716 23.553177 41602 5.685412 -37.604046 22.452438 41603 5.640956 -36.870605 23.187693 41604 58.698669 -38.263306 23.242035 41605 59.473343 -38.952454 24.078804 41606 5.990106 -39.818428 21.832226 41607 5.974852 -38.680065 22.668356 41608 50.588928 -37.808960 23.528496 41609 52.611420 -38.333191 23.370987 41610 52.445343 -38.718643 25.317932 41611 53.725998 -38.861023 27.128456 41612 57.783844 -38.827209 23.741356 41613 58.685043 -38.896835 23.719963 41614 5.938583 -41.762192 21.263580 41615 6.405130 -40.886585 22.731602 41616 6.132980 -41.935898 21.967239 41617 6.334328 -39.463146 23.317945 41618 5.455551 -42.804642 21.805618 41619 49.522095 -43.032913 22.959717 41620 50.665710 -42.911743 22.950806 41621 53.436157 -43.715576 23.355118 41622 51.776703 -43.268066 23.233002 41623 62.091751 -43.281189 22.916267 41624 4.720284 -43.921204 22.435097 41625 47.664352 -44.243408 23.031723 41626 47.827576 -44.737900 22.360184 41627 47.393311 -44.128876 24.756172 41628 46.537674 -45.006042 23.813629 41629 51.828613 -43.908096 23.971382 41630 59.423965 -45.805099 22.638779 41631 47.409698 -45.034515 22.754295 41632 5.150162 -46.246353 21.291031 41633 47.272690 -45.835236 23.080933 41634 48.640076 -46.243225 22.667999 41635 60.702164 -45.691910 22.478378 41636 61.375946 -44.909317 23.539406 41637 60.810471 -45.547897 24.421310 41638 61.226532 -44.828384 24.462067 41639 57.643524 -46.890076 24.653816 41640 58.873276 -46.506546 23.986343 41641 7.964355 -48.225082 21.931870 41642 7.215973 -48.416946 22.888123 41643 51.651260 -47.488037 22.467697 41644 56.103180 -51.151382 22.537369 41645 55.096146 -50.908615 22.925850 41646 53.633560 -49.035995 22.639557 41647 57.394455 -51.107086 21.716629 41648 8.181854 -50.792496 21.600868 41649 14.236664 -51.604752 20.765236 41650 5.486054 -53.122543 21.322090 41651 12.889435 -53.521118 21.167793 41652 18.872299 -54.053528 21.592896 41653 19.680374 -53.748550 20.949631 41654 4.792435 -54.209763 20.428299 41655 19.062424 -54.572647 22.670364 41656 17.267593 -54.257507 22.137924 41657 4.738327 -55.550446 21.941978 41658 57.116089 -55.322479 21.945915 41659 56.936035 -53.905441 22.147850 41660 21.752815 -57.956635 20.680260 41661 22.498093 -56.926315 21.128998 41662 22.238503 -56.052231 20.720512 41663 22.706398 -56.014099 21.499298 41664 23.221497 -56.795944 22.027550 41665 38.678032 -54.409454 21.385704 41666 41.507996 -55.828064 22.030197 41667 42.491730 -56.346771 21.348671 41668 4.239502 -58.877457 20.978119 41669 9.759506 -57.764130 21.463707 41670 20.516441 -59.023041 20.404404 41671 43.998901 -56.637451 21.406731 41672 49.492249 -57.480255 21.634239 41673 4.324265 -58.149155 22.486046 41674 7.420136 -59.451080 20.638367 41675 8.054604 -58.828918 20.693901 41676 19.455925 -59.981491 20.207603 41677 22.155525 -59.614609 21.175293 41678 51.340088 -58.174927 21.339218 41679 4.230087 -60.799026 20.634109 41680 4.234116 -59.791977 20.621979 41681 20.243706 -60.058167 20.509285 41682 20.909393 -60.219070 20.774231 41683 52.513458 -58.718689 21.450943 41684 6.410713 -60.974106 20.114532 41685 8.611038 -62.878723 20.454422 41686 8.087326 -62.094757 20.319344 41687 7.705024 -61.066681 20.656502 41688 8.745621 -61.782806 20.641312 41689 9.135330 -60.722977 21.148796 41690 19.861359 -61.418762 20.292419 41691 47.959167 -60.571304 22.747009 41692 55.553482 -59.537399 21.419189 41693 7.017883 -60.256012 20.604630 41694 18.316193 -61.652130 19.872276 41695 3.974487 -62.700043 20.705582 41696 10.033775 -63.465836 21.173378 41697 9.964493 -62.059738 21.021965 41698 50.405197 -61.747162 21.825493 41699 50.292419 -61.417358 22.868744 41700 51.236328 -62.381165 22.829102 41701 21.059540 -62.856323 20.564880 41702 50.797180 -62.603104 21.817459 41703 51.184555 -63.130203 22.178635 41704 4.101494 -63.853424 20.655975 41705 3.908165 -61.706192 20.949203 41706 6.749107 -65.887344 21.427261 41707 8.838264 -64.517441 21.926086 41708 9.527161 -64.177475 21.637802 41709 20.834671 -65.207886 20.113937 41710 21.374519 -64.761749 20.369133 41711 21.676041 -64.466156 20.692169 41712 41.935059 -63.972794 21.179741 41713 43.253418 -63.914597 21.018364 41714 47.936829 -64.694168 24.313263 41715 49.096039 -64.709793 24.353447 41716 48.711929 -64.024689 22.662735 41717 49.782898 -64.171738 23.025574 41718 21.275284 -65.181854 20.768089 41719 20.584839 -66.156906 20.465073 41720 38.730637 -65.191284 21.369705 41721 38.897499 -65.764954 20.864555 41722 38.236664 -66.042526 21.335236 41723 39.517227 -64.556900 21.849113 41724 4.459931 -66.170471 21.253914 41725 4.219215 -65.055466 20.866241 41726 3.998116 -65.538681 22.087448 41727 5.868965 -66.318100 20.994698 41728 20.082565 -67.315674 20.411987 41729 37.787254 -67.238281 21.655136 41730 37.581284 -66.028564 22.151970 41731 38.397339 -64.863281 22.758278 41732 38.652267 -64.811905 22.079422 41733 38.084702 -65.282288 22.105759 41734 38.815308 -66.318726 20.871918 41735 40.861847 -67.231812 21.053215 41736 38.950760 -67.152817 21.175262 41737 10.354256 -68.072968 20.832428 41738 39.558762 -68.366882 21.650101 41739 14.629242 -69.194702 19.955315 41740 12.934982 -69.026947 20.816589 41741 15.745117 -70.834808 20.662331 41742 14.566917 -70.240646 21.114555 41743 20.616989 -66.327362 21.975258 41744 19.844749 -67.761414 21.151573 41745 18.788101 -71.121506 20.160507 41746 49.075562 -71.606339 21.514793 41747 7.227768 -70.686844 19.934692 41748 7.947555 -71.569916 19.867371 41749 17.866364 -72.527802 20.582115 41750 16.599304 -72.510727 21.030464 41751 17.225845 -71.579910 19.989441 41752 18.006111 -71.428650 19.572090 41753 25.715538 -72.901062 23.161362 41754 25.703117 -72.334534 22.143097 41755 25.570023 -73.342453 21.644135 41756 26.053398 -71.573792 23.262177 41757 26.230461 -71.385330 21.812103 41758 28.699921 -71.511490 20.980766 41759 29.205002 -72.308563 20.563652 41760 8.860672 -71.888107 19.554237 41761 9.365555 -72.413162 19.658249 41762 29.655899 -72.730972 19.883904 41763 30.257645 -73.856216 19.656029 41764 6.445709 -72.915405 20.213806 41765 15.056755 -71.580521 21.733238 41766 15.561378 -71.338821 21.235435 41767 25.961456 -73.513443 20.401886 41768 30.308159 -75.106445 20.186592 41769 9.423683 -73.022186 19.667686 41770 26.051056 -75.154510 20.508163 41771 25.622818 -74.314529 21.244774 41772 5.343376 -74.057526 20.552406 41773 5.056557 -76.046036 20.817467 41774 5.177185 -75.893112 19.247810 41775 36.327652 -75.684250 20.622498 41776 26.537613 -76.915558 20.159058 41777 31.151054 -75.621841 19.877815 41778 30.856003 -76.043976 20.451485 41779 37.512802 -76.026260 20.324280 41780 37.630249 -76.383270 19.922325 41781 38.075790 -76.452515 20.493553 41782 43.873520 -76.229980 20.423698 41783 44.725739 -75.993378 20.167213 41784 45.926804 -75.370514 21.072029 41785 46.639771 -75.303482 20.075623 41786 44.258484 -75.956055 21.407227 41787 7.476181 -78.463364 18.346977 41788 5.942955 -79.985611 19.444244 41789 37.915031 -79.443649 20.998413 41790 38.474213 -78.255493 20.931229 41791 38.507263 -79.043533 21.850830 41792 43.367599 -76.905594 23.086212 41793 43.440567 -76.765167 22.076233 41794 5.823380 -81.163467 19.579086 41795 32.526855 -80.550674 19.240273 41796 37.843307 -78.885254 20.034668 41797 37.298401 -79.740158 20.298027 41798 31.915056 -82.054184 20.293594 41799 36.670410 -80.239700 20.300995 41800 27.615158 -81.465164 19.853058 41801 27.351273 -79.770233 20.465912 41802 42.654816 -80.848083 19.547333 41803 41.998840 -82.043320 20.099579 41804 5.861817 -82.239151 19.586525 41805 27.323517 -82.608932 19.466911 41806 31.058151 -83.242722 20.132973 41807 41.201691 -83.201248 20.108391 41808 27.028717 -83.463913 19.700554 41809 6.228569 -84.439484 20.870232 41810 6.050362 -85.767014 19.933594 41811 12.085587 -85.337784 19.697784 41812 13.023788 -86.214417 18.821701 41813 12.555496 -86.728806 19.235657 41814 13.747002 -85.339966 18.903679 41815 14.640625 -85.080444 19.298698 41816 14.627724 -85.580215 18.886925 41817 14.350739 -84.332672 19.883438 41818 15.116959 -85.571381 19.240768 41819 22.093018 -85.402954 18.997902 41820 22.388824 -85.038879 19.300331 41821 25.211502 -84.692215 19.768600 41822 26.346802 -84.337769 19.966095 41823 36.322098 -85.667221 20.475853 41824 14.262497 -86.185745 18.642342 41825 15.067238 -86.206970 18.996689 41826 15.511543 -86.041901 19.465805 41827 22.011841 -86.101807 19.103928 41828 38.927391 -84.774216 20.744171 41829 11.561699 -86.720154 20.188835 41830 10.254059 -85.762299 20.906151 41831 11.013184 -86.932510 20.676460 41832 13.591675 -86.824661 18.774559 41833 12.974243 -86.846512 18.862770 41834 14.642090 -87.168076 19.220360 41835 15.543877 -86.826477 19.455078 41836 22.159698 -86.753296 19.136490 41837 30.203491 -86.785431 19.583336 41838 35.631561 -86.167603 20.344772 41839 34.588234 -87.390930 19.742371 41840 12.995773 -87.264603 19.230553 41841 13.586838 -87.877914 19.927483 41842 12.477745 -87.462906 19.976814 41843 25.041443 -88.659058 19.235573 41844 7.215256 -89.496918 19.793266 41845 6.715180 -88.071426 20.552422 41846 25.902740 -89.243088 19.108200 41847 27.669281 -90.597794 19.820724 41848 33.093689 -88.489563 20.356888 41849 33.222595 -88.138138 21.726395 41850 34.116051 -87.790985 21.147232 41851 8.284393 -91.296585 19.028046 41852 7.949432 -90.404831 20.423615 41853 8.376244 -90.865143 20.531807 41854 13.897308 -91.819534 18.500908 41855 13.767807 -92.262726 18.880852 41856 14.453453 -91.569611 18.198746 41857 14.849594 -91.891479 17.863327 41858 27.250191 -91.871353 18.461853 41859 27.523544 -91.515518 19.187302 41860 10.179657 -92.853027 18.612015 41861 9.621185 -92.091293 20.292709 41862 14.371643 -92.262314 18.430573 41863 20.883301 -93.126038 18.533936 41864 21.349319 -92.880844 18.456810 41865 27.469093 -91.590210 20.178169 41866 11.849548 -92.926102 19.659569 41867 13.775848 -93.863602 19.302895 41868 13.733185 -94.054367 18.350868 41869 13.918488 -93.078171 19.138321 41870 21.182693 -93.752991 19.451790 41871 21.929535 -93.119370 19.371407 41872 13.935913 -95.246964 18.219330 41873 13.806076 -94.451004 19.170219 41874 23.997101 -93.309113 19.083931 41875 16.702774 -95.633163 20.160492 41876 17.299568 -95.683990 19.598930 41877 9.947670 61.768204 29.443062 41878 9.476585 61.241302 30.176271 41879 10.152084 60.502792 30.825014 41880 9.039078 60.111008 31.327662 41881 7.743209 61.025742 29.858400 41882 6.723335 60.460159 30.282854 41883 17.780701 58.814438 29.224396 41884 5.987396 56.186676 28.940285 41885 5.807350 55.069656 28.799393 41886 18.391663 58.257629 29.226585 41887 20.241089 55.455521 28.311531 41888 20.426437 56.244263 29.407715 41889 5.938484 54.275742 28.486900 41890 21.554222 54.742874 29.221573 41891 22.872978 54.042160 29.072937 41892 22.872505 54.194565 30.037386 41893 21.806381 53.706665 28.175781 41894 24.011002 53.547546 29.527946 41895 25.991043 52.511490 28.920883 41896 3.346512 53.539597 29.742830 41897 3.881706 53.990967 29.251129 41898 25.945404 51.343201 29.983675 41899 27.652817 50.834595 28.696426 41900 27.288635 50.457184 29.901056 41901 3.229576 51.413177 28.352745 41902 3.508591 50.402481 28.466141 41903 3.200531 53.644760 30.610529 41904 3.057991 53.063858 30.387827 41905 28.018265 50.244293 28.873444 41906 33.246552 49.861557 29.360146 41907 6.392136 48.828979 28.318939 41908 5.921097 49.098419 30.178537 41909 7.741958 48.648010 28.459335 41910 10.329620 46.528137 28.231140 41911 9.815903 46.994873 29.197586 41912 28.097023 48.915192 29.442047 41913 28.072220 47.745651 31.086473 41914 27.805573 48.966522 31.687449 41915 31.647913 46.342041 30.175882 41916 10.172829 46.262573 29.267662 41917 20.910805 48.049454 29.689875 41918 20.005783 46.972961 29.056793 41919 19.157509 48.468842 29.856203 41920 19.522095 46.000458 28.532494 41921 18.651512 46.826782 28.758720 41922 10.479538 45.650589 28.680115 41923 10.474716 44.971222 28.035683 41924 18.509460 45.827713 28.491028 41925 17.794052 46.451813 28.834183 41926 18.247581 46.400864 28.491089 41927 17.901794 45.702271 28.780815 41928 20.410339 45.990662 28.856499 41929 27.484123 45.234543 29.674280 41930 27.108978 44.148468 28.975632 41931 28.188599 47.150055 28.637924 41932 38.345932 46.004654 28.076248 41933 37.525223 46.094482 28.799095 41934 37.344482 46.919815 29.127235 41935 4.004746 43.948944 27.625267 41936 6.688393 44.170258 27.989105 41937 6.506180 43.863037 28.646545 41938 10.087204 44.490662 28.173866 41939 18.252136 44.779999 28.938255 41940 19.852013 44.729431 28.733162 41941 31.372986 44.972839 28.495247 41942 36.852066 46.843872 29.650095 41943 7.690254 43.138580 29.290237 41944 8.911362 43.645981 28.754036 41945 8.217194 43.598999 28.384407 41946 9.687424 44.173645 28.727600 41947 19.829613 43.409027 28.549881 41948 19.036308 43.555679 28.664680 41949 36.285782 45.725891 30.199991 41950 35.792038 43.775558 29.143623 41951 35.921494 44.657043 29.762522 41952 18.344086 43.153488 29.373657 41953 18.307571 43.867142 28.974159 41954 19.109222 42.423248 29.074600 41955 20.469437 43.151733 29.204254 41956 19.726814 42.706314 28.803101 41957 31.062584 44.829529 29.553757 41958 30.984962 44.149063 28.749878 41959 30.728134 43.363342 28.445312 41960 39.606819 42.945129 27.750954 41961 18.572067 41.615387 29.988092 41962 26.366425 41.862595 28.048981 41963 35.709824 42.854462 29.753962 41964 26.371140 42.530884 30.672541 41965 26.528198 42.745102 29.318771 41966 26.659798 41.140442 29.827372 41967 30.155266 42.509583 29.495880 41968 29.866180 41.895798 29.212135 41969 3.127998 40.191833 28.025185 41970 3.282379 40.878174 29.377548 41971 3.229225 39.609726 29.416237 41972 26.531723 40.571213 28.238441 41973 27.008026 39.955582 27.852867 41974 29.605316 41.336548 28.433189 41975 3.120155 38.935059 28.119858 41976 43.122681 39.094238 27.422493 41977 36.543091 39.887894 29.497253 41978 32.827164 34.857147 27.966660 41979 9.875549 32.548553 28.209152 41980 37.060104 32.455215 27.986755 41981 37.666290 33.253113 27.746994 41982 44.765442 32.910248 27.944466 41983 29.090569 30.393005 27.784721 41984 33.128319 33.902878 29.420197 41985 36.033417 31.316589 27.906090 41986 35.943054 30.269882 29.076683 41987 4.709580 28.101700 28.047592 41988 5.288841 27.084061 28.537468 41989 4.405655 27.113159 28.928947 41990 28.531891 29.548981 27.999939 41991 45.495499 32.283905 29.394722 41992 46.628235 30.656860 27.714424 41993 28.807327 30.220688 28.605125 41994 28.315910 29.618576 28.814537 41995 33.235413 29.085388 27.591431 41996 2.784912 28.090454 27.841805 41997 2.384911 27.433060 28.069580 41998 32.466492 28.762024 27.407913 41999 33.824310 28.885010 28.573792 42000 45.369858 28.909973 27.837364 42001 46.111633 29.761261 28.209229 42002 10.013443 26.061905 26.266258 42003 31.486435 27.753143 27.503281 42004 44.360138 28.535156 28.726906 42005 49.202820 26.782150 27.456306 42006 12.601288 26.538940 28.079254 42007 28.951828 26.285019 27.473267 42008 28.175308 28.724380 28.704185 42009 29.623566 25.609863 27.466148 42010 30.988556 25.736725 27.977730 42011 30.373970 25.644913 27.671638 42012 9.478470 24.964462 27.024353 42013 10.933380 24.465500 27.114319 42014 10.888885 23.971634 27.430626 42015 27.999336 27.412399 28.538757 42016 28.908020 25.600601 27.432472 42017 47.309753 25.838516 27.900902 42018 10.292183 24.274368 27.053223 42019 28.983917 24.985901 27.846184 42020 28.481506 25.718124 27.799835 42021 45.428040 24.779663 27.491241 42022 52.912155 24.783173 27.565414 42023 2.461411 26.309128 28.179390 42024 10.384750 23.555664 27.476784 42025 10.247711 23.116974 27.691475 42026 11.017868 23.266663 28.290573 42027 42.789612 24.749390 29.417778 42028 44.381271 24.629623 28.282188 42029 44.831635 25.108002 29.718821 42030 2.587334 22.020340 27.610535 42031 2.426811 24.337799 28.742477 42032 3.726280 18.399750 27.179977 42033 5.259262 18.430542 25.681221 42034 31.943880 20.400421 27.766762 42035 31.910692 19.633545 27.153114 42036 31.588806 19.041534 27.364326 42037 32.430168 19.478943 27.158012 42038 33.880035 19.611649 27.567497 42039 33.411018 20.937103 28.227158 42040 32.878189 18.599823 27.037773 42041 30.192215 19.495834 28.985649 42042 29.650543 20.488251 29.078003 42043 30.687225 19.906616 28.197777 42044 34.235535 17.995636 27.229736 42045 32.878723 17.604309 26.870453 42046 31.891024 16.729401 26.988464 42047 33.262558 16.818604 26.848785 42048 49.677826 18.429230 27.748398 42049 51.119202 18.564713 27.571953 42050 53.645142 18.851120 28.458496 42051 55.020706 18.540878 28.856140 42052 56.245087 17.241104 28.573715 42053 56.169250 17.204453 29.648699 42054 55.812134 17.926590 29.333183 42055 55.276062 18.368942 29.580406 42056 54.554810 18.644821 29.575279 42057 32.330757 15.822556 26.790100 42058 33.550301 16.012344 26.840057 42059 31.758699 17.793793 27.142380 42060 50.402451 17.953186 28.354851 42061 51.194061 18.206070 28.366631 42062 5.221672 16.394058 26.758553 42063 30.919991 17.986023 27.841736 42064 34.691467 16.773758 27.228180 42065 34.462112 15.498718 27.220634 42066 4.999626 14.536407 26.020470 42067 30.875870 16.881210 27.888817 42068 56.710052 15.379028 28.088707 42069 4.609948 14.053964 25.047874 42070 5.333382 14.294144 26.608139 42071 31.011536 15.346985 27.520966 42072 32.995689 14.352570 27.095703 42073 32.042953 13.901230 27.027603 42074 32.037872 14.211594 26.807037 42075 35.611862 15.122986 27.645844 42076 34.549713 14.412384 27.683105 42077 2.956730 10.107452 20.269054 42078 3.804580 12.366601 22.764626 42079 4.284762 13.071383 24.192175 42080 4.790108 13.248893 25.705338 42081 5.350517 13.386566 27.195190 42082 32.052292 14.823303 26.834488 42083 33.095589 15.253357 26.801476 42084 52.124939 13.799652 28.123726 42085 56.864059 14.663452 27.165047 42086 3.397834 11.050788 21.841286 42087 3.745767 11.340972 23.101437 42088 4.044394 11.877015 23.911570 42089 4.383866 11.849070 25.031321 42090 31.527985 14.143005 27.134071 42091 53.124695 13.835037 28.131882 42092 55.361450 14.167084 28.935471 42093 56.096420 14.327606 27.298058 42094 2.661981 8.477876 19.651758 42095 3.075762 9.054961 21.669310 42096 2.931408 9.307456 20.755045 42097 3.220821 9.962147 21.739803 42098 3.555917 10.614226 22.766411 42099 3.943314 10.584121 24.166784 42100 3.501610 10.000199 22.902401 42101 49.955368 11.871109 26.979523 42102 50.719406 11.578064 27.817253 42103 3.316548 9.088935 22.652788 42104 51.048248 11.051819 26.667557 42105 52.293579 10.483734 26.732857 42106 58.267090 6.221237 29.796511 42107 56.669342 6.172470 30.638765 42108 56.723740 5.820618 29.083717 42109 58.847687 6.169617 26.403816 42110 59.721603 5.467773 26.697990 42111 49.391266 5.850784 26.658508 42112 50.560562 6.550720 26.829201 42113 44.815155 4.596985 27.142517 42114 45.632187 4.461456 26.498055 42115 51.558624 2.624741 27.364296 42116 53.289215 3.730103 27.712601 42117 52.318695 3.208755 28.280380 42118 53.015427 3.452347 26.424026 42119 59.861496 4.041672 26.940796 42120 41.726974 1.441193 26.179192 42121 41.129364 2.676743 26.635353 42122 47.710602 0.433655 26.189682 42123 49.545715 1.371109 26.304115 42124 48.592163 1.143570 26.982628 42125 49.892380 1.832550 27.234467 42126 58.408386 -0.395050 26.640686 42127 58.704697 0.699326 27.296402 42128 2.407378 -0.813780 22.050262 42129 2.554703 -1.030679 22.954508 42130 45.656265 -0.464798 26.106964 42131 46.631104 0.155701 26.862885 42132 44.930908 -0.478683 27.010849 42133 58.686798 -1.250351 27.687408 42134 2.486939 -1.889505 22.614733 42135 2.616604 -2.520747 23.366022 42136 60.779526 -3.169876 26.834213 42137 60.497635 -2.749191 26.991852 42138 2.756563 -10.426414 23.246504 42139 60.980835 -9.706314 25.706207 42140 61.264053 -10.193192 26.542412 42141 62.261765 -11.692993 27.066666 42142 61.603149 -10.620316 27.108742 42143 2.989025 -12.567436 23.686413 42144 52.177383 -12.782257 25.863159 42145 51.169235 -12.735001 26.586365 42146 56.225677 -12.876541 25.593750 42147 57.445892 -13.394516 25.345512 42148 54.231659 -12.108047 26.721062 42149 53.186646 -12.239639 26.603714 42150 58.183685 -13.793137 25.449127 42151 63.085083 -13.012344 26.284752 42152 63.528061 -13.795746 25.330681 42153 3.039295 -13.832493 23.394505 42154 3.018862 -14.719668 22.541170 42155 50.872650 -13.850891 26.688194 42156 63.142838 -14.303146 26.171539 42157 60.378342 -14.813110 26.325371 42158 61.707825 -15.199997 25.730713 42159 62.785110 -15.294693 25.182114 42160 62.527771 -14.861465 26.431900 42161 35.040207 -18.058228 23.635742 42162 53.126801 -15.945694 25.500145 42163 3.563116 -18.787533 22.460472 42164 56.732864 -18.114838 26.104607 42165 60.543396 -19.287628 25.491508 42166 59.470428 -18.892548 26.197098 42167 63.081116 -21.000443 26.325882 42168 3.811957 -20.956472 23.034319 42169 3.964965 -25.146360 22.151758 42170 3.914323 -23.863056 21.874939 42171 3.926139 -24.388563 21.946388 42172 63.030106 -27.357056 24.845306 42173 63.218628 -27.665298 26.270515 42174 63.217300 -25.713608 25.438385 42175 4.128524 -26.793249 21.434814 42176 4.055142 -25.994267 21.597851 42177 4.210585 -27.725367 21.388027 42178 31.599510 -27.569321 22.936615 42179 4.078269 -27.254602 22.040295 42180 46.308868 -29.090424 24.421097 42181 46.742859 -28.866638 24.583145 42182 62.830231 -28.380432 25.037506 42183 4.650133 -31.690023 23.069708 42184 4.143792 -28.115864 23.424150 42185 4.075591 -27.664757 22.407976 42186 45.373352 -29.972855 24.168449 42187 45.876465 -29.580917 24.295837 42188 49.223145 -28.595657 24.355118 42189 50.254456 -28.498642 24.140808 42190 51.305008 -28.490784 24.574478 42191 52.347229 -28.525635 24.368874 42192 62.420105 -29.148483 24.929893 42193 45.036041 -30.271698 23.929550 42194 43.678085 -31.634827 23.984398 42195 40.075165 -33.378616 23.788460 42196 39.254951 -34.073181 23.778191 42197 39.901245 -33.761139 24.505356 42198 4.393356 -29.767088 23.516138 42199 4.242814 -28.601297 23.684614 42200 39.177681 -34.635437 24.538124 42201 40.096497 -36.203247 24.613861 42202 39.660149 -35.253876 25.081306 42203 41.608032 -37.211121 24.140182 42204 44.195526 -37.154449 23.433525 42205 42.123810 -37.783508 25.501366 42206 41.532028 -37.364273 25.437469 42207 61.667068 -37.285507 23.730736 42208 48.591156 -38.131027 25.098595 42209 50.613861 -38.257187 24.113922 42210 51.475433 -38.201004 23.834518 42211 60.658493 -38.116302 24.028107 42212 58.675247 -39.224274 24.031067 42213 6.856957 -39.958744 24.340258 42214 6.527428 -38.512722 24.622038 42215 6.905280 -38.763969 25.368238 42216 6.277229 -42.247726 22.484291 42217 62.193954 -41.785767 23.646461 42218 6.755615 -43.151184 23.916702 42219 6.783043 -42.299957 23.309105 42220 7.452423 -42.526810 24.037415 42221 6.067192 -42.859879 23.038010 42222 48.859009 -43.143585 23.162552 42223 53.069687 -45.021225 24.716820 42224 51.801758 -44.469467 24.547791 42225 51.563461 -44.919266 25.059235 42226 61.551910 -42.563538 24.513924 42227 61.427475 -43.938568 24.452614 42228 48.697266 -43.559891 23.716934 42229 54.538513 -45.088791 24.273254 42230 53.460831 -44.373123 24.022614 42231 55.890854 -45.795334 24.300842 42232 4.666489 -44.214722 23.355408 42233 4.560707 -45.013077 24.241417 42234 5.529495 -46.838516 21.637405 42235 47.580521 -46.880737 23.511696 42236 48.990952 -47.040817 23.035782 42237 48.600388 -47.571960 23.589149 42238 50.117096 -47.890396 23.302528 42239 48.742920 -48.541092 24.421783 42240 60.527344 -45.836044 23.474396 42241 59.942627 -46.298233 24.214592 42242 5.535538 -47.404709 22.502174 42243 4.766144 -46.971725 23.722870 42244 8.842621 -49.032166 22.339401 42245 51.911804 -48.837692 23.197807 42246 9.148972 -49.566315 22.105080 42247 9.007591 -50.300888 22.155640 42248 54.354156 -50.114761 22.863380 42249 7.122292 -51.932709 22.004150 42250 13.992516 -52.164658 21.665443 42251 14.607376 -52.236343 21.845825 42252 13.557686 -52.769379 21.724617 42253 55.248703 -51.976624 23.005096 42254 56.590729 -52.415588 22.396629 42255 14.097847 -52.929672 22.297516 42256 13.445877 -53.640518 21.978699 42257 56.213562 -55.015167 22.843147 42258 55.764359 -53.599976 22.757240 42259 14.890808 -53.005905 22.526215 42260 14.958649 -53.476791 22.933723 42261 15.473206 -53.850479 22.701637 42262 20.472359 -54.366013 22.255348 42263 21.653809 -54.421783 21.590157 42264 35.892334 -54.791046 22.427475 42265 39.013184 -54.013596 22.444351 42266 55.496445 -52.757614 22.836128 42267 54.691483 -53.138062 23.251045 42268 22.034821 -54.858978 22.963333 42269 22.683044 -55.374832 22.244926 42270 11.791573 -56.568283 21.950478 42271 13.013214 -54.909943 21.918823 42272 23.071259 -56.051483 22.130798 42273 55.184784 -54.384598 23.356705 42274 56.104431 -56.199524 24.671577 42275 56.222641 -57.523895 24.313049 42276 56.022552 -57.441666 25.509171 42277 10.568893 -57.121613 21.420776 42278 41.614639 -55.255676 22.902420 42279 44.243256 -56.438171 22.341103 42280 43.156219 -55.789764 22.848587 42281 45.373749 -56.666916 22.296844 42282 44.453308 -56.204620 23.008888 42283 45.536316 -56.277695 23.351456 42284 9.233070 -58.332809 21.502144 42285 23.198219 -58.176102 21.740746 42286 36.202026 -56.641724 23.539673 42287 36.951279 -57.677078 23.117493 42288 37.374207 -56.862961 24.584160 42289 45.022659 -56.745972 21.684708 42290 46.499298 -56.735184 22.570053 42291 56.665848 -56.538788 22.551575 42292 7.429962 -60.146072 20.908379 42293 8.000183 -60.068771 21.109009 42294 8.776047 -59.186432 21.337875 42295 37.646637 -58.146271 23.407669 42296 50.948242 -57.864655 22.587097 42297 51.426926 -57.760925 24.562561 42298 52.358353 -58.195038 24.495773 42299 52.193039 -58.232849 23.636086 42300 50.546600 -57.478973 23.702339 42301 52.664902 -58.649796 22.361420 42302 3.913941 -59.345688 22.086922 42303 3.895294 -59.961258 21.436783 42304 24.246971 -59.036072 22.853836 42305 24.406342 -60.321136 22.442719 42306 23.763306 -59.848526 21.863762 42307 39.860825 -59.315002 22.378395 42308 41.373749 -59.705948 22.897690 42309 53.753448 -59.022614 23.476822 42310 54.268951 -59.326111 22.470108 42311 54.727859 -59.544952 21.646164 42312 55.467834 -59.284470 22.361107 42313 3.870911 -60.786652 21.973251 42314 3.863541 -61.903152 22.004555 42315 10.509079 -60.982025 21.434959 42316 11.676643 -60.411911 22.029305 42317 10.217239 -59.803635 21.766663 42318 21.664719 -61.507156 21.038101 42319 23.287437 -61.321259 21.799347 42320 24.163757 -60.722076 22.040810 42321 49.604782 -61.132355 22.129082 42322 53.206512 -58.626678 24.460999 42323 3.881767 -62.942245 21.922989 42324 3.946930 -64.148087 22.123833 42325 11.869095 -61.755783 21.729401 42326 11.202438 -62.811676 21.408951 42327 12.717438 -59.655884 22.535477 42328 14.355591 -60.727310 22.747070 42329 22.119125 -63.542038 21.651573 42330 10.445938 -64.276230 21.986450 42331 11.385628 -63.742950 21.755325 42332 12.268097 -64.204178 22.059708 42333 12.575905 -63.113037 21.952332 42334 41.900299 -63.674393 21.916069 42335 42.431641 -63.654877 21.765778 42336 40.470337 -64.187149 22.204674 42337 41.340576 -63.930481 22.038200 42338 43.260605 -63.842163 22.240074 42339 42.862061 -63.665359 21.927444 42340 51.275040 -63.644775 22.696564 42341 51.585876 -63.171707 22.664124 42342 3.950142 -66.012024 23.070595 42343 4.013741 -65.068848 23.264030 42344 44.293839 -64.494080 23.922211 42345 44.954193 -64.274033 23.592728 42346 50.633713 -64.080948 22.941010 42347 4.183006 -63.894867 23.613899 42348 19.322708 -67.495575 25.270744 42349 21.223228 -64.498367 27.294319 42350 20.079468 -65.877106 27.087761 42351 5.122818 -66.546936 20.975426 42352 4.904572 -66.860748 21.571793 42353 5.508141 -66.889801 21.477898 42354 9.658173 -68.402069 21.397690 42355 8.691460 -68.743942 21.221741 42356 42.899750 -67.293167 21.173462 42357 42.027985 -68.321838 21.919731 42358 44.811325 -67.549423 21.728752 42359 43.945984 -67.417145 21.570724 42360 44.115341 -68.076569 22.290710 42361 45.262604 -68.780243 22.785057 42362 47.496979 -67.671097 21.886375 42363 48.785309 -67.627274 21.932465 42364 49.717072 -67.620224 22.014107 42365 7.786430 -69.122757 20.846924 42366 10.550880 -68.593826 21.647514 42367 11.025291 -69.386505 22.461243 42368 9.357391 -69.090958 22.100845 42369 19.379097 -68.577438 22.074997 42370 38.427048 -68.239563 21.628380 42371 37.810509 -68.143524 21.640594 42372 40.679535 -68.506195 21.760757 42373 43.204605 -68.508469 22.378983 42374 43.960846 -68.959488 22.823067 42375 48.133606 -68.320679 22.832207 42376 50.492874 -68.156509 22.586479 42377 13.668404 -70.290192 21.852409 42378 12.411209 -69.512939 21.960358 42379 37.889618 -68.656174 22.001884 42380 37.331085 -68.069122 22.115280 42381 38.675331 -69.380936 22.702797 42382 37.363403 -69.012863 22.832474 42383 6.941483 -70.528366 20.876793 42384 28.492737 -70.858994 22.064438 42385 18.999107 -70.632187 21.559952 42386 27.211472 -70.533173 21.963173 42387 27.567017 -70.366486 21.692459 42388 8.632446 -72.280548 20.151421 42389 7.802932 -72.614227 20.207108 42390 8.580620 -72.717697 20.264946 42391 9.006577 -72.738922 20.065323 42392 18.186081 -71.931458 20.146774 42393 18.700584 -72.181641 21.347488 42394 29.077972 -72.332932 21.618484 42395 16.486511 -71.294891 20.370674 42396 17.898300 -74.388641 22.797195 42397 17.068214 -74.568604 21.870056 42398 18.060478 -73.419189 21.593292 42399 25.773094 -72.506561 21.207397 42400 29.557983 -74.338013 21.048698 42401 29.373978 -73.157288 20.894745 42402 14.238106 -71.502106 22.398399 42403 14.955811 -73.453979 22.473991 42404 25.601334 -75.065918 21.517181 42405 25.534782 -76.238235 21.925613 42406 29.957619 -75.434387 21.010811 42407 35.352028 -75.841537 21.176544 42408 35.183540 -75.807281 20.582283 42409 35.962326 -75.532837 21.784042 42410 38.118462 -75.888428 21.496040 42411 44.134003 -75.948715 22.934677 42412 46.585266 -74.536911 22.629997 42413 46.274048 -73.665253 24.150406 42414 47.592392 -73.287109 22.889481 42415 26.718613 -78.373718 20.605354 42416 30.344711 -76.534790 21.437553 42417 31.374344 -76.687592 20.697807 42418 31.435921 -77.162155 21.084702 42419 32.355759 -76.950272 20.878471 42420 32.079880 -77.473755 21.278305 42421 33.035820 -77.517227 21.776108 42422 34.361115 -77.265808 22.819725 42423 35.032631 -76.243088 22.786072 42424 31.359894 -77.572113 21.668716 42425 30.354858 -77.662781 22.600922 42426 38.832672 -77.034729 21.617859 42427 6.974411 -82.427490 20.772110 42428 7.057678 -81.424408 20.960602 42429 8.124573 -81.463028 21.215721 42430 9.147270 -81.550644 20.514969 42431 9.588440 -81.333008 21.239693 42432 10.082397 -81.946457 20.327782 42433 8.719177 -81.225327 22.253723 42434 11.494431 -81.913956 20.420380 42435 11.328941 -83.176849 20.087135 42436 10.684867 -81.413361 20.800209 42437 11.891762 -81.664139 21.268265 42438 12.498810 -81.816559 21.147736 42439 12.345306 -81.913483 20.698013 42440 36.342896 -80.677200 20.682396 42441 36.065849 -80.871307 20.904053 42442 36.835922 -80.455307 21.188995 42443 8.293015 -82.487000 20.790436 42444 9.001205 -82.082108 20.481972 42445 9.552887 -83.199768 20.563606 42446 12.353455 -82.451080 20.298607 42447 41.943817 -81.661346 21.698616 42448 42.384460 -80.582367 21.900574 42449 42.585724 -80.558289 20.752739 42450 9.066879 -84.310989 21.096619 42451 8.114578 -83.365509 21.072014 42452 10.631607 -84.292969 20.362267 42453 27.536324 -82.468201 20.688812 42454 27.578400 -80.926010 21.024864 42455 41.384796 -82.671524 21.031761 42456 13.158478 -83.514847 20.157310 42457 14.130905 -83.501389 20.885391 42458 14.571556 -83.844635 21.260979 42459 14.732300 -84.143921 20.549149 42460 31.018875 -84.007996 21.153870 42461 40.425217 -83.636719 21.199623 42462 15.186798 -85.152771 20.138329 42463 22.146004 -85.553085 19.779785 42464 22.498886 -85.060211 19.981232 42465 23.108765 -85.038239 20.534538 42466 24.125969 -84.814102 20.043839 42467 24.913177 -85.124908 20.654541 42468 25.752525 -85.009079 20.663826 42469 26.615601 -84.835587 21.630585 42470 26.257370 -85.500839 22.759895 42471 27.013901 -84.995163 23.014488 42472 27.180206 -83.758972 21.037651 42473 30.928345 -84.903961 21.759460 42474 39.459534 -84.224655 22.316162 42475 40.208313 -83.438141 22.683861 42476 6.168457 -85.939865 21.186424 42477 12.130127 -86.651611 19.669701 42478 15.975998 -86.426849 20.129684 42479 22.456741 -86.544586 20.027664 42480 30.508614 -87.186432 21.021103 42481 16.075851 -87.214203 19.859680 42482 16.519623 -87.193878 20.329773 42483 22.450798 -85.608688 20.615845 42484 35.111908 -86.918121 21.539917 42485 35.987556 -86.144775 21.215294 42486 11.709473 -87.733154 20.791183 42487 15.502686 -87.681091 19.741592 42488 14.765060 -88.312668 20.275734 42489 16.250854 -87.951553 20.286896 42490 23.185913 -87.383209 19.892075 42491 23.962189 -87.683609 20.190529 42492 15.562378 -88.236633 20.180023 42493 24.711243 -88.160370 19.938202 42494 25.658768 -88.573776 20.064064 42495 31.358368 -88.270126 21.478477 42496 30.731445 -87.840057 21.105576 42497 7.114914 -88.899811 20.834610 42498 26.524521 -89.158417 19.905258 42499 8.927101 -91.146225 20.768555 42500 12.743767 -92.658035 19.439644 42501 12.671700 -92.845139 20.539215 42502 13.447327 -92.562653 19.263496 42503 23.219810 -92.917389 19.713287 42504 10.323715 -92.701477 20.400734 42505 10.199867 -92.844498 19.503189 42506 11.078583 -92.854889 20.259117 42507 11.874329 -92.888062 20.439476 42508 20.293457 -94.404221 19.272324 42509 22.992767 -93.113510 20.718208 42510 21.662880 -93.951523 20.406540 42511 22.035660 -93.590790 20.299225 42512 24.284882 -92.850235 19.938950 42513 24.888138 -92.575592 20.765640 42514 26.636711 -92.535126 19.876526 42515 26.122330 -92.405945 20.782059 42516 26.931381 -92.224731 20.485809 42517 27.268341 -91.818512 20.983597 42518 27.573837 -90.843750 21.781059 42519 14.166924 -94.866608 19.474327 42520 19.575211 -94.892487 19.988579 42521 14.851479 -95.395462 19.340904 42522 18.298874 -95.347870 19.456238 42523 20.139374 -94.606689 21.262115 42524 17.946243 -95.136261 20.905212 42525 11.969940 60.199661 30.286631 42526 11.394744 60.260498 30.474993 42527 13.858902 60.962814 29.732965 42528 12.619553 61.016830 29.749796 42529 16.334213 58.868149 29.940172 42530 5.697456 60.070374 31.773005 42531 4.840859 59.277695 32.496925 42532 5.089439 58.486328 30.628664 42533 14.804237 59.818954 30.014688 42534 17.972298 57.808121 29.988291 42535 4.220917 57.974304 32.327568 42536 4.021813 57.447449 31.443926 42537 5.260155 57.086182 29.550224 42538 12.241257 57.674164 30.080820 42539 11.435799 59.021942 30.564226 42540 13.082710 59.121323 30.160700 42541 13.202026 57.117752 29.877565 42542 14.515366 57.918579 30.095331 42543 14.241951 56.264221 29.855379 42544 19.912918 56.951874 29.854609 42545 4.820381 55.890793 29.538414 42546 4.510162 57.083588 30.234468 42547 4.018616 54.894775 29.843462 42548 3.611740 54.257492 29.837152 42549 12.332947 56.422485 29.874155 42550 11.315063 57.095886 30.512545 42551 11.094589 56.539520 31.210817 42552 10.623894 57.076782 31.121805 42553 15.934303 56.822021 30.190432 42554 13.047515 55.688385 29.832766 42555 20.173386 56.643677 30.029451 42556 20.494408 56.080536 30.188936 42557 10.542542 57.446198 30.833971 42558 12.420029 55.669128 29.803148 42559 15.118698 55.470840 29.945993 42560 14.991699 54.503357 30.018099 42561 16.526230 54.957565 30.528299 42562 15.188576 53.431870 30.300570 42563 14.029373 54.988480 29.929155 42564 20.865578 55.254730 30.912882 42565 3.941277 56.250748 31.158449 42566 12.499084 55.350327 29.994646 42567 12.078690 55.782318 30.162035 42568 12.742577 54.945709 30.643930 42569 14.038544 53.785599 30.385729 42570 25.103638 52.638504 29.748415 42571 3.110634 52.381882 29.444420 42572 3.384049 51.142670 29.411255 42573 34.527870 49.601898 29.864923 42574 33.967010 49.180466 30.819002 42575 33.175110 49.205780 30.400362 42576 36.212845 47.745956 30.100756 42577 35.677231 47.916138 30.761736 42578 35.101913 48.723480 30.598757 42579 7.198975 48.752625 29.628931 42580 6.728569 48.300537 30.801973 42581 23.741959 49.962616 30.346132 42582 23.974442 48.856949 30.335039 42583 23.356705 48.754211 29.972879 42584 22.607101 49.122040 29.999247 42585 36.068451 48.833496 29.414162 42586 9.139146 47.520813 29.447838 42587 22.471085 47.911652 29.898829 42588 21.723045 48.798462 30.024691 42589 16.530212 47.472412 30.113077 42590 16.585770 48.487289 30.251505 42591 17.495956 47.722778 29.550262 42592 17.060760 46.745026 29.566734 42593 17.614738 49.504288 30.370874 42594 21.313522 46.824829 29.429008 42595 36.378403 46.836868 30.228693 42596 10.242943 45.641556 29.368950 42597 16.791168 46.482758 30.251238 42598 17.462120 45.775742 29.462105 42599 21.119919 45.707321 29.425438 42600 28.169830 47.162170 29.706285 42601 33.248680 47.683075 32.524521 42602 32.549820 46.941803 32.652435 42603 32.327621 47.415756 31.720110 42604 5.179817 43.258514 29.776415 42605 5.004006 42.823090 30.207888 42606 4.338165 42.560776 29.855791 42607 21.239090 44.418869 30.053743 42608 27.735428 46.296967 30.521410 42609 6.209740 43.254578 29.558800 42610 5.718002 42.656387 30.284662 42611 9.854591 45.761383 30.038965 42612 10.092743 44.851837 29.222282 42613 17.612328 44.906921 30.060823 42614 17.971054 44.060013 29.442459 42615 26.655426 43.652725 30.241793 42616 27.054070 44.952835 30.826097 42617 30.806503 43.913605 29.763613 42618 35.762527 44.057007 30.270151 42619 35.867065 44.827026 30.449945 42620 8.791428 42.845963 30.018755 42621 17.871674 43.789978 30.260927 42622 21.001114 43.315857 29.707354 42623 30.444397 43.077759 29.284683 42624 18.102997 42.772293 30.276270 42625 20.948372 42.815308 30.186396 42626 19.947037 41.565918 29.722246 42627 36.862595 40.850952 30.047014 42628 36.648407 42.093201 30.572290 42629 29.489960 41.333115 29.471214 42630 28.292336 40.350311 29.076073 42631 29.053825 40.835602 29.111160 42632 37.888466 38.511551 29.973269 42633 37.576202 39.767578 30.052469 42634 3.088013 38.330994 28.759102 42635 27.213669 40.207230 28.859200 42636 3.284966 36.992493 28.890152 42637 3.876259 35.836853 28.085625 42638 37.694138 37.345306 30.213541 42639 3.409508 35.609390 28.885475 42640 4.137505 34.928589 28.535103 42641 36.303223 36.169220 30.251856 42642 5.200874 34.330658 28.518059 42643 34.778465 34.216721 31.027758 42644 36.497803 34.871567 31.723330 42645 6.652908 33.670654 28.787598 42646 8.788376 32.589111 29.435669 42647 37.770103 32.904541 28.169556 42648 38.003197 31.622009 29.637903 42649 36.958855 31.422058 28.778473 42650 37.691559 32.330643 28.542480 42651 29.772888 30.982666 28.402954 42652 30.454239 31.447159 29.443596 42653 46.186630 30.847000 28.975098 42654 46.058502 31.357391 29.685083 42655 36.808891 30.586151 29.811602 42656 11.538002 30.385147 29.220261 42657 28.847580 27.481613 30.610750 42658 29.423904 27.992249 31.271738 42659 29.136292 29.627563 30.056887 42660 30.047668 29.220383 32.321983 42661 28.262886 29.379730 29.097076 42662 28.206619 26.508743 28.169510 42663 34.716537 28.854248 29.586037 42664 45.497543 29.599609 29.432747 42665 3.441879 28.196747 28.229271 42666 6.105888 27.362228 27.954674 42667 32.368332 28.380524 27.676643 42668 33.329132 27.683060 29.210533 42669 32.713860 28.004211 28.223358 42670 45.882172 30.773514 30.035593 42671 45.033997 29.445328 30.588335 42672 45.474854 30.160690 30.679804 42673 7.017563 26.940933 27.658272 42674 42.092789 27.482132 28.733391 42675 43.320694 28.192657 29.550262 42676 6.624024 26.338593 28.236282 42677 7.345245 25.659653 28.018234 42678 6.242127 25.452240 28.877472 42679 27.862167 26.568268 29.006325 42680 31.946428 26.575119 28.476860 42681 48.235123 26.333435 28.415344 42682 49.165161 26.730972 28.712547 42683 49.885391 26.586670 29.626390 42684 8.365799 25.358734 27.394569 42685 12.482666 26.029449 27.673126 42686 31.426559 25.253647 28.537369 42687 41.436890 25.038177 28.411659 42688 41.056000 25.903595 29.272301 42689 41.113785 26.553436 29.444756 42690 46.066818 25.286896 28.490944 42691 47.270172 25.903473 28.841118 42692 7.092499 24.314636 28.916229 42693 8.945702 23.627380 27.847847 42694 7.958915 24.200409 28.277824 42695 8.469994 22.839905 28.786034 42696 9.734283 23.612183 27.426392 42697 28.543312 24.243729 28.442505 42698 27.959778 24.422989 29.370766 42699 28.081680 25.462769 28.677902 42700 30.356918 24.899994 28.028938 42701 32.634399 23.638214 29.789843 42702 32.224533 25.233002 29.326294 42703 33.302536 25.420410 30.254839 42704 52.712280 24.752808 28.089317 42705 52.361572 24.703812 28.652832 42706 29.585724 23.854706 28.336632 42707 31.166794 23.775940 28.920769 42708 31.832697 22.864746 29.218330 42709 31.146835 22.048187 28.707710 42710 43.571686 24.945877 30.532816 42711 51.904526 24.719528 29.606668 42712 7.862968 21.849487 30.295755 42713 7.689041 23.307327 29.065491 42714 9.508469 22.269501 28.564217 42715 9.959426 22.805252 27.980354 42716 28.635399 23.050934 28.971970 42717 29.918137 22.658035 28.716354 42718 51.099747 22.789886 30.336222 42719 51.439011 24.012741 30.732065 42720 30.033722 21.568588 28.712471 42721 30.630188 20.906982 28.388870 42722 33.904221 21.812164 29.125793 42723 34.191238 22.415009 29.963205 42724 35.351219 21.946564 29.656702 42725 34.970474 20.835236 28.412880 42726 36.129799 21.150970 28.957199 42727 36.173042 20.365723 28.465370 42728 35.611931 19.767761 28.004623 42729 2.614060 19.776871 29.400093 42730 2.862282 18.330017 28.650871 42731 2.507156 20.681870 28.363716 42732 32.592911 22.100067 29.056198 42733 35.469208 18.853958 27.717148 42734 49.020950 19.034958 27.949036 42735 4.534470 17.235031 27.070938 42736 3.551048 16.833008 28.184235 42737 52.169617 18.495972 28.532791 42738 2.702614 17.936188 29.409073 42739 2.890038 17.362869 29.340096 42740 35.967705 17.832642 27.706284 42741 37.371231 17.856659 28.194946 42742 36.587372 16.332504 27.760559 42743 48.771530 18.247833 28.210587 42744 48.245316 18.888321 28.672508 42745 49.394348 17.768188 28.445274 42746 48.565369 17.707581 28.590103 42747 4.351280 16.529053 27.651566 42748 4.840706 16.282501 27.457367 42749 48.271042 18.139679 28.508064 42750 5.397682 14.473877 27.453865 42751 29.925705 14.550751 28.874413 42752 30.794533 13.740189 27.889816 42753 37.877029 16.064697 28.081497 42754 38.921051 17.119293 28.535545 42755 38.541534 15.744843 28.477379 42756 36.415703 15.181458 27.855751 42757 37.367813 15.164688 28.278282 42758 5.018074 12.714203 26.713112 42759 34.708420 13.646576 28.333801 42760 36.033371 14.379730 28.207680 42761 36.040176 13.635498 28.931435 42762 56.019379 14.508194 30.592875 42763 56.379913 15.036469 29.669184 42764 56.524551 15.123718 29.051620 42765 4.730037 12.297850 25.930656 42766 5.310989 12.288422 27.239716 42767 32.108849 13.372574 27.855156 42768 30.944237 12.858109 28.462708 42769 31.685640 12.465607 29.188614 42770 30.523483 12.249985 29.615351 42771 33.552444 13.128998 28.417442 42772 32.816246 12.648178 29.026520 42773 33.554214 13.719711 27.805443 42774 50.896210 12.532471 28.789032 42775 54.392792 13.246857 30.455271 42776 55.017792 13.377075 31.324228 42777 55.413177 13.799683 30.497599 42778 2.871589 8.609558 20.915358 42779 4.344841 10.546914 25.455000 42780 4.783740 11.446959 26.375898 42781 4.840131 9.581503 27.272968 42782 4.688220 10.366123 26.560368 42783 5.087036 10.802135 27.611048 42784 30.490189 15.863342 28.549011 42785 2.766476 8.016989 20.689962 42786 2.819610 7.532676 21.235321 42787 3.038961 8.189505 21.938173 42788 3.605795 9.719051 23.445204 42789 50.797394 12.061066 28.578926 42790 3.324379 8.106097 23.114973 42791 3.657809 9.165580 23.858250 42792 4.026063 9.381068 24.958044 42793 51.762726 12.358139 29.326157 42794 52.380051 10.413727 29.180237 42795 2.990173 7.105845 22.162561 42796 3.694629 8.294682 24.340349 42797 52.992004 9.439056 27.420067 42798 2.601212 7.302676 20.059755 42799 2.583437 6.078449 20.539694 42800 2.602331 5.126081 21.259735 42801 3.364012 7.114462 23.664103 42802 52.677582 9.360931 28.254753 42803 52.134705 9.378387 29.708849 42804 38.610649 6.822113 28.107208 42805 39.382797 6.804825 27.395432 42806 38.844803 6.127884 27.301498 42807 39.895691 7.355270 27.939484 42808 39.913918 6.803528 27.351547 42809 39.293381 7.610367 29.152664 42810 40.385284 6.511490 27.525429 42811 39.677872 6.192657 27.197319 42812 39.221222 5.244743 27.197144 42813 50.621155 6.975357 27.998238 42814 49.787430 6.367401 27.841843 42815 58.678345 5.929352 28.597023 42816 59.673950 5.361069 27.708313 42817 38.526932 5.458160 27.304642 42818 38.162308 5.822563 27.673630 42819 37.176590 5.472672 28.619431 42820 38.141068 4.665695 27.738449 42821 39.981743 5.568085 27.248337 42822 40.550369 5.605957 27.455933 42823 40.183151 4.701767 27.185493 42824 39.245255 4.255157 27.374573 42825 41.198547 5.250626 27.486618 42826 41.075745 4.093491 27.023445 42827 41.967529 4.709030 27.324852 42828 42.735840 4.973198 27.649239 42829 46.635834 5.928253 28.646454 42830 48.730408 5.910858 27.784431 42831 40.019821 3.378456 27.175964 42832 38.683304 3.439087 27.848557 42833 39.503181 2.386505 27.955589 42834 45.557159 5.185516 27.735466 42835 54.844162 4.721085 28.385178 42836 40.370972 2.275131 27.069267 42837 59.410980 2.533417 27.467262 42838 59.378693 3.326195 29.387459 42839 59.809891 4.124298 28.045258 42840 40.396271 1.607437 27.506226 42841 50.317505 2.308868 28.270973 42842 51.394745 2.819595 28.451096 42843 59.112564 1.453445 28.570427 42844 58.603531 0.080902 29.285225 42845 47.538239 0.745346 27.235329 42846 45.681061 -0.178726 27.140068 42847 58.572906 -0.260086 27.668297 42848 2.796223 -1.395247 24.129627 42849 43.964096 -0.371902 27.819954 42850 42.710327 -0.331467 27.884216 42851 43.175262 -0.260101 28.621689 42852 59.106018 -2.553680 27.686531 42853 60.004654 -2.684143 27.355331 42854 2.557990 -3.991443 23.148764 42855 2.526586 -4.569186 22.905333 42856 2.590895 -3.277060 23.301287 42857 2.706261 -3.938117 23.998133 42858 57.438324 -3.814178 27.567139 42859 56.327484 -4.298569 27.257355 42860 56.374176 -3.234589 28.065834 42861 55.286331 -3.645737 27.737709 42862 57.389221 -2.961945 28.116051 42863 57.531952 -4.978134 27.094551 42864 52.891144 -4.240616 27.942062 42865 52.580109 -2.947784 29.456551 42866 53.733017 -3.065567 28.955032 42867 54.053070 -4.815704 27.011185 42868 54.388504 -5.533951 26.887726 42869 53.925781 -5.262558 26.858284 42870 55.171265 -4.816452 27.030678 42871 55.290405 -6.092728 27.160690 42872 56.310852 -5.621445 27.049400 42873 57.955719 -5.642426 26.963692 42874 57.292084 -6.112885 27.141335 42875 58.720947 -5.380692 27.099487 42876 2.788971 -5.121832 24.330513 42877 53.620361 -5.435852 27.276382 42878 54.402039 -6.151505 27.325325 42879 53.764877 -6.295334 28.267159 42880 58.321503 -6.337982 27.265266 42881 52.730988 -5.557495 27.949799 42882 56.287659 -6.661285 27.764488 42883 55.030792 -6.603592 27.904251 42884 60.530563 -6.408417 26.860313 42885 61.090912 -8.326752 27.546753 42886 61.042435 -9.657669 26.580338 42887 61.225861 -9.567383 27.394279 42888 50.133514 -12.856308 27.557930 42889 51.288269 -12.063278 28.043457 42890 52.280731 -12.153366 27.017937 42891 55.245590 -12.035889 26.703033 42892 54.836731 -11.977844 26.691818 42893 56.043762 -12.455292 26.801559 42894 57.138351 -12.953888 27.437271 42895 56.328812 -12.428940 28.139221 42896 57.835754 -13.140076 28.391335 42897 58.192841 -13.715240 26.256226 42898 57.225159 -13.163330 26.466171 42899 3.127322 -15.129255 23.270931 42900 59.232422 -14.213211 26.964859 42901 60.450912 -14.624054 27.571899 42902 52.863403 -15.635818 26.482460 42903 61.674576 -14.835602 27.310333 42904 54.189362 -16.492783 26.391884 42905 3.963647 -20.430883 25.159445 42906 3.812868 -20.265388 24.025433 42907 3.752055 -19.088680 24.386301 42908 3.718605 -19.882057 22.911175 42909 3.559296 -18.058493 23.814753 42910 58.274124 -18.845032 25.799828 42911 3.963209 -21.175488 24.729439 42912 61.833893 -19.531006 28.269386 42913 60.928787 -18.630966 28.592072 42914 61.131821 -18.807739 27.698280 42915 3.901845 -21.705265 24.122372 42916 4.063126 -22.102306 25.213774 42917 3.845497 -21.941271 23.284803 42918 63.006439 -21.504929 27.075432 42919 3.958682 -22.541330 24.441484 42920 3.873318 -23.188240 23.100830 42921 3.877275 -23.749310 22.804544 42922 62.854721 -22.914093 27.097359 42923 3.894861 -24.180628 22.409174 42924 3.956909 -24.955734 23.844395 42925 4.015491 -24.146132 24.487997 42926 4.031694 -24.847763 24.538010 42927 3.917000 -24.608990 23.194086 42928 3.907127 -23.845715 23.621387 42929 63.091888 -24.466537 25.812241 42930 3.953008 -25.644888 23.114401 42931 3.998597 -26.796505 22.871033 42932 3.996600 -26.232811 22.273977 42933 4.039219 -27.476971 23.221230 42934 4.000895 -26.187025 23.750376 42935 48.294220 -29.330444 25.837227 42936 48.239182 -28.720337 24.974197 42937 47.388855 -29.028610 25.292206 42938 46.539642 -29.659012 25.027756 42939 50.165527 -28.579330 25.399239 42940 49.181519 -28.922516 25.680359 42941 51.198288 -28.848602 26.068161 42942 51.882980 -28.803726 26.430458 42943 51.911530 -28.578217 26.152992 42944 52.281586 -28.583435 25.440849 42945 53.710724 -29.088440 26.184097 42946 62.831055 -29.178436 25.919472 42947 45.578278 -30.667694 24.733406 42948 58.491562 -30.416489 25.672264 42949 62.033096 -30.049683 25.749779 42950 42.872498 -32.632568 24.656052 42951 44.579285 -32.047638 24.929825 42952 46.178802 -32.176285 25.211128 42953 47.127228 -31.330521 25.262093 42954 47.347672 -32.309128 25.120033 42955 47.653305 -32.245239 25.187805 42956 46.981140 -32.284698 25.154251 42957 41.020355 -33.257736 24.497971 42958 42.513092 -35.387772 26.744644 42959 43.112579 -35.609375 27.845520 42960 43.747086 -35.043900 27.702538 42961 44.400299 -34.475815 26.905602 42962 43.660339 -33.652222 25.766304 42963 45.551773 -33.445724 25.902687 42964 47.565613 -32.995544 25.516602 42965 48.071350 -31.894608 25.415108 42966 49.528290 -33.168579 25.856735 42967 49.159393 -31.735413 25.762680 42968 39.464043 -34.163574 24.737595 42969 5.071226 -33.854927 23.684656 42970 5.417007 -34.823002 24.449539 42971 5.298211 -34.976448 23.732197 42972 40.287735 -35.870285 25.427307 42973 5.565113 -35.800259 24.076351 42974 40.759369 -36.932800 24.503441 42975 41.174194 -37.249786 24.819672 42976 62.220200 -37.231796 23.523361 42977 5.616743 -36.388805 23.679140 42978 5.886667 -36.970024 24.073521 42979 5.869470 -37.701733 23.256363 42980 6.157447 -38.149708 23.856937 42981 43.856201 -37.759064 24.383720 42982 42.837616 -37.860992 24.934105 42983 44.509995 -38.125717 25.065178 42984 43.673981 -38.161911 25.519958 42985 47.581985 -38.195587 25.168228 42986 60.665039 -39.289642 24.452896 42987 61.658218 -38.755783 24.049522 42988 61.435486 -39.704926 24.477097 42989 50.190811 -38.716507 26.082199 42990 49.176163 -38.860031 27.251289 42991 57.204193 -39.262665 25.324028 42992 58.669907 -39.882034 24.799332 42993 59.833618 -39.932709 24.696358 42994 61.538116 -40.256104 24.595665 42995 58.861649 -41.184464 25.812386 42996 57.930817 -40.221283 25.979500 42997 60.657211 -41.753891 25.228294 42998 61.552094 -41.118515 24.578690 42999 5.176155 -43.373520 23.199898 43000 5.810631 -43.331635 23.887634 43001 7.750457 -43.164307 24.388184 43002 7.133576 -43.634918 24.732872 43003 50.257492 -43.557281 23.917892 43004 49.225677 -44.330307 25.208649 43005 50.634323 -44.149048 24.595589 43006 52.118439 -45.483337 25.481300 43007 54.149155 -46.024307 25.238884 43008 45.928467 -46.253998 24.192390 43009 46.492432 -47.334686 24.411339 43010 45.384155 -47.081009 25.180573 43011 45.650330 -45.201126 24.462296 43012 60.214554 -45.936676 25.372108 43013 5.601997 -48.165451 23.411736 43014 6.337029 -48.215393 22.894424 43015 44.859253 -45.315521 25.259392 43016 47.235291 -48.145203 24.920212 43017 46.621216 -48.257843 25.490883 43018 46.109467 -47.766846 25.310707 43019 47.686676 -47.663315 24.102203 43020 50.406052 -49.190399 23.972275 43021 59.261887 -46.952057 25.187004 43022 4.609161 -47.442749 24.609123 43023 5.166657 -48.311844 24.313301 43024 9.316223 -49.742554 22.940620 43025 50.639130 -50.506729 24.600426 43026 49.935181 -50.433441 25.265594 43027 49.593872 -49.672714 24.857422 43028 51.427704 -49.966141 23.859726 43029 9.515930 -50.080917 24.055862 43030 9.851517 -50.361557 25.070389 43031 9.665482 -51.385849 24.520050 43032 52.671387 -50.401077 23.522835 43033 8.431168 -51.684235 22.835258 43034 8.441193 -51.219620 22.299210 43035 9.207771 -50.916061 23.159081 43036 53.819763 -51.853149 23.475075 43037 6.184761 -53.317245 22.919945 43038 8.966110 -51.812775 23.532372 43039 51.652985 -50.922913 24.218132 43040 52.479858 -51.877914 24.192657 43041 14.567574 -53.711533 22.838234 43042 39.216385 -53.226868 23.339409 43043 38.413307 -52.609924 24.135178 43044 40.039429 -52.996506 23.878662 43045 39.813835 -52.221725 24.426025 43046 40.201965 -53.892700 23.202362 43047 53.857635 -53.367249 23.723015 43048 53.222214 -52.995712 24.102875 43049 5.796585 -56.187241 24.443726 43050 5.696900 -57.450043 24.667931 43051 4.889855 -56.912216 23.541161 43052 5.478226 -54.212143 22.929634 43053 5.508370 -55.165512 23.672028 43054 35.862839 -54.883362 23.466721 43055 36.357430 -54.141434 24.346138 43056 38.261841 -53.303970 23.169258 43057 41.247086 -53.754440 23.844315 43058 52.674561 -53.024612 24.909584 43059 54.387894 -54.089355 23.694290 43060 13.866669 -54.030182 22.508759 43061 14.748260 -54.902420 22.852318 43062 16.156082 -54.865738 22.839554 43063 18.763046 -55.244354 23.356369 43064 21.356232 -55.136200 23.841232 43065 22.310608 -55.174271 23.829659 43066 20.051926 -54.904282 23.418617 43067 23.470139 -56.258774 22.818588 43068 41.139130 -54.554443 23.223991 43069 42.292023 -54.650696 23.698990 43070 23.050873 -55.762711 23.605667 43071 44.184204 -54.695908 24.738243 43072 44.521057 -55.756027 23.719360 43073 53.941666 -54.085938 24.446823 43074 54.732574 -54.692108 24.100533 43075 55.627808 -55.289444 23.896347 43076 55.207672 -54.695908 25.176674 43077 56.231049 -56.442917 23.593872 43078 12.429848 -57.271423 22.698067 43079 13.938858 -56.520020 22.847488 43080 24.006546 -57.435913 22.949699 43081 48.006317 -56.919022 22.893417 43082 10.020248 -58.461823 22.010696 43083 10.641068 -57.606308 22.130508 43084 35.736267 -55.746201 23.703629 43085 36.354980 -55.704453 24.651619 43086 46.766464 -56.372406 23.796623 43087 49.578323 -57.290253 22.951515 43088 11.325157 -58.976044 22.343384 43089 10.766792 -58.173859 22.428932 43090 56.194290 -58.155350 23.113159 43091 3.808189 -59.987595 22.178818 43092 14.433029 -59.261398 23.045471 43093 13.073883 -58.288376 22.866409 43094 24.374237 -60.743942 23.675980 43095 24.213257 -61.190598 22.548019 43096 38.582153 -58.204376 24.155861 43097 40.022919 -59.035080 23.718369 43098 39.726181 -58.128876 24.932457 43099 11.556808 -57.821014 22.537407 43100 16.920807 -55.969421 23.251450 43101 18.779419 -56.117294 23.880836 43102 41.397919 -59.443390 24.249008 43103 40.833038 -58.825928 24.908997 43104 42.844940 -59.640823 24.380928 43105 44.975449 -60.177048 24.991379 43106 44.184402 -60.022812 24.164307 43107 45.309082 -60.383347 23.415855 43108 46.819550 -60.541641 23.452591 43109 49.171478 -60.939133 23.250099 43110 46.084320 -60.500122 24.923035 43111 45.494263 -60.416946 24.972244 43112 54.400208 -58.952423 24.412979 43113 55.102966 -59.098419 23.534676 43114 50.465042 -61.566605 23.991814 43115 51.490555 -62.456955 24.463867 43116 50.619171 -61.782516 25.103859 43117 13.606599 -62.244507 22.325104 43118 14.049287 -63.419449 22.248123 43119 13.167923 -64.357391 22.222389 43120 15.687653 -62.708160 22.801521 43121 51.737030 -63.225998 23.479073 43122 14.160568 -64.676544 22.440361 43123 15.101364 -64.973450 22.694328 43124 15.000664 -63.993332 22.426544 43125 23.659683 -62.147903 23.129501 43126 22.625275 -63.429214 24.916359 43127 42.280396 -63.824524 22.479568 43128 42.949203 -64.417801 23.607048 43129 10.578568 -65.059830 23.162910 43130 9.588470 -64.625977 22.544098 43131 8.734863 -65.094421 22.943893 43132 11.535728 -64.587204 22.357864 43133 12.469406 -64.881912 22.460129 43134 12.110710 -65.365585 23.155891 43135 15.865723 -64.334854 22.771164 43136 39.005272 -64.564545 22.648895 43137 39.863129 -64.418808 22.898369 43138 41.218353 -64.249863 23.141968 43139 41.400574 -64.939529 24.198647 43140 47.113190 -64.237930 23.299103 43141 45.762848 -64.217148 23.328285 43142 7.445236 -65.945221 22.913597 43143 6.245560 -66.703323 22.161919 43144 6.731239 -66.775391 23.253624 43145 13.236771 -65.344864 22.908974 43146 15.816864 -65.200729 22.976372 43147 37.438614 -65.594208 24.543549 43148 36.437286 -66.276047 24.423553 43149 37.306519 -65.997101 25.505234 43150 37.712006 -65.490967 23.399460 43151 36.914505 -66.865616 22.785202 43152 51.344818 -64.038208 24.073853 43153 36.654869 -68.162949 22.878540 43154 36.057785 -68.582977 23.708542 43155 36.090393 -67.393188 23.578377 43156 23.990105 -61.896881 24.416962 43157 43.253662 -67.875183 21.878693 43158 46.783340 -68.370178 22.711105 43159 11.637634 -68.920395 21.596054 43160 41.264542 -69.179489 22.313698 43161 40.097443 -69.304047 22.390121 43162 42.650818 -69.791321 22.897385 43163 49.689575 -68.313293 22.822662 43164 7.613037 -69.976715 21.884956 43165 19.556259 -66.312302 27.243713 43166 18.863235 -68.959610 23.343018 43167 18.839417 -69.805695 22.501648 43168 19.114883 -69.669235 21.723579 43169 36.703400 -69.397110 23.608177 43170 36.697418 -68.864258 23.149986 43171 50.421906 -69.490646 22.522247 43172 49.632141 -70.866989 22.489563 43173 6.508995 -71.577209 21.735260 43174 12.724007 -70.456909 22.798225 43175 27.890610 -70.421692 22.046181 43176 41.026123 -69.901352 22.915901 43177 6.960236 -71.767303 20.689590 43178 28.939392 -71.557648 22.062714 43179 6.164032 -72.619675 21.179680 43180 18.587265 -72.633865 22.926956 43181 18.783089 -73.080856 22.148880 43182 29.239845 -73.417725 22.412376 43183 48.944214 -71.874619 22.460289 43184 5.030510 -74.554474 21.934875 43185 5.613098 -72.988556 22.120972 43186 29.426346 -75.114197 22.222961 43187 45.440094 -75.300781 22.595406 43188 45.978378 -74.696518 23.434532 43189 5.072434 -73.890625 23.470718 43190 6.222824 -71.928635 23.334343 43191 5.354996 -72.783401 24.354568 43192 18.436661 -73.469727 22.770668 43193 16.080109 -75.517517 22.131355 43194 25.512253 -74.441422 22.488472 43195 29.295807 -75.558731 23.604294 43196 29.291565 -76.087021 24.484947 43197 29.409279 -76.855942 23.486885 43198 38.114174 -75.204849 22.267174 43199 37.047691 -75.128204 22.116997 43200 37.891998 -74.662933 23.075806 43201 38.791908 -75.522095 22.956963 43202 14.547729 -76.355743 23.153656 43203 16.053452 -76.867950 22.634789 43204 29.577438 -76.345383 22.536057 43205 35.282776 -75.878784 21.938324 43206 39.244743 -76.267410 22.534920 43207 45.116241 -75.136917 24.124924 43208 5.647286 -78.578339 20.619537 43209 5.213585 -77.420685 21.147705 43210 5.008461 -76.409317 22.367134 43211 25.992340 -77.750168 21.224014 43212 26.110352 -79.108765 21.619720 43213 32.073486 -78.310349 22.521843 43214 32.157578 -77.795303 21.676712 43215 30.959671 -79.161331 23.829605 43216 33.596603 -78.265915 23.229126 43217 38.887138 -78.168732 22.762764 43218 26.048660 -80.458786 22.652504 43219 27.047844 -80.183075 21.609306 43220 5.805039 -79.731964 21.397316 43221 5.399994 -78.270111 21.975632 43222 6.281654 -81.082062 20.679367 43223 6.377350 -80.464188 22.235718 43224 7.057541 -81.035507 21.586662 43225 10.783363 -81.532059 21.846001 43226 9.324623 -81.726807 23.094452 43227 11.291336 -81.439743 21.027130 43228 37.807068 -79.921555 21.869362 43229 6.466629 -83.390656 20.942711 43230 6.114044 -83.248825 20.331337 43231 7.075630 -83.705002 21.273880 43232 12.853149 -82.254303 21.036362 43233 31.974337 -82.936218 21.474228 43234 33.965767 -81.613525 21.455154 43235 33.051147 -82.071014 21.503448 43236 35.452316 -81.086304 21.351151 43237 13.355988 -82.906952 21.437073 43238 33.364304 -82.449265 22.314415 43239 41.065231 -82.586609 22.462456 43240 9.864609 -84.317963 20.711960 43241 14.962387 -84.414902 20.961853 43242 27.522026 -82.854095 21.851898 43243 15.549042 -85.746063 21.313828 43244 15.227249 -84.930115 21.050804 43245 22.726562 -86.089035 21.260513 43246 23.014282 -86.368958 22.030640 43247 23.361588 -85.750824 22.136734 43248 23.027267 -85.466492 21.280464 43249 27.417747 -83.807022 22.638794 43250 30.878517 -86.864960 22.188179 43251 30.578049 -86.062927 21.295135 43252 24.059303 -85.305832 21.332443 43253 25.479843 -85.359634 21.798615 43254 37.756424 -85.339249 21.422684 43255 36.766647 -85.772095 21.374886 43256 6.211510 -86.767029 20.502182 43257 16.493233 -86.779007 21.034813 43258 17.171997 -87.727097 20.974770 43259 6.418602 -87.361526 20.467270 43260 10.549835 -88.429398 21.966881 43261 9.660034 -88.961990 22.304184 43262 9.135651 -86.974442 22.038879 43263 10.142356 -87.104599 21.479843 43264 10.823563 -87.405014 21.188728 43265 23.630402 -87.067627 22.065498 43266 23.346085 -86.484726 22.886856 43267 23.287125 -87.029816 20.951736 43268 24.799835 -87.792862 21.085602 43269 35.933067 -86.271469 22.425491 43270 13.863969 -88.775192 21.131493 43271 12.804948 -88.625427 21.237770 43272 14.690880 -89.352097 21.497391 43273 15.794060 -88.854416 20.849503 43274 16.813660 -88.622787 20.773979 43275 18.291748 -88.173676 22.023979 43276 17.704636 -88.674637 21.130554 43277 18.418457 -89.023804 21.540291 43278 25.796555 -88.006958 22.099831 43279 31.535683 -88.633087 20.787125 43280 7.593330 -88.921188 21.647705 43281 6.995270 -88.014267 21.549271 43282 7.639221 -89.617096 20.887154 43283 15.733574 -90.092346 21.920105 43284 17.316032 -89.598389 21.478554 43285 32.231094 -88.586563 21.194962 43286 13.486908 -93.003372 20.020988 43287 23.920837 -92.697739 20.557098 43288 23.247452 -93.093781 23.349556 43289 21.839195 -93.702530 23.152466 43290 21.983963 -93.246765 23.908615 43291 26.818954 -92.135818 20.958511 43292 14.016708 -93.934372 20.204269 43293 20.914162 -94.302994 20.340279 43294 14.667839 -94.861084 20.356781 43295 15.748642 -95.307938 20.509933 43296 8.448730 61.044525 30.420168 43297 7.591194 60.746628 31.111864 43298 6.916878 60.882874 30.914507 43299 10.902458 60.166229 30.713793 43300 10.481384 58.180862 30.897493 43301 10.256897 59.414551 31.077524 43302 4.241036 57.348511 30.822039 43303 9.647697 58.647415 31.529329 43304 10.135849 57.657990 31.408495 43305 19.291634 56.795654 30.458620 43306 18.422867 55.838776 30.998110 43307 19.759918 55.993591 30.920588 43308 19.492508 55.215576 31.374422 43309 11.704941 55.972534 30.817003 43310 17.626862 56.555511 30.561159 43311 3.523934 54.444748 30.777773 43312 21.962204 54.533936 30.784609 43313 13.283722 53.515381 31.517084 43314 16.177109 52.893433 30.578745 43315 17.163452 53.733597 31.005838 43316 22.706322 54.005127 30.897104 43317 23.449219 53.623596 30.513636 43318 22.955864 53.375854 31.078959 43319 23.822327 52.695206 30.538492 43320 3.229431 52.084503 30.546366 43321 14.438568 52.642883 30.499674 43322 13.861481 52.720551 30.899683 43323 15.172836 51.969437 30.526392 43324 15.124207 50.665695 30.850634 43325 14.312332 51.617340 31.016832 43326 17.270309 52.261429 31.033220 43327 16.996719 50.741669 30.732729 43328 16.099716 51.251312 30.615969 43329 24.538948 51.440445 30.351442 43330 23.141479 51.425507 30.842066 43331 18.092972 51.119949 31.082712 43332 16.124214 49.676712 30.656046 43333 22.306534 50.184219 30.596712 43334 20.782806 49.654907 30.576174 43335 21.402954 51.321106 31.329378 43336 22.389427 52.554047 31.297411 43337 25.044846 50.323196 30.490046 43338 3.946251 50.731934 30.572519 43339 3.662804 51.539398 31.898394 43340 19.063950 50.122040 30.848673 43341 21.845947 49.447372 30.264048 43342 26.382202 49.830261 32.910400 43343 25.855919 49.812271 32.447845 43344 26.944679 49.825577 31.797945 43345 27.061081 50.093048 30.884661 43346 25.956970 50.004730 31.125299 43347 27.622719 49.773438 30.773241 43348 34.992203 47.997589 31.422159 43349 25.665947 49.683929 33.236496 43350 25.491920 49.450546 33.672440 43351 24.694626 48.989014 32.997002 43352 24.624069 49.238403 30.988665 43353 24.333710 48.642944 31.540003 43354 33.204941 48.617783 31.468988 43355 32.423927 48.184845 30.758348 43356 8.539154 46.534973 31.267862 43357 9.259720 46.693253 30.295008 43358 8.029938 47.483322 30.645861 43359 14.977264 49.559326 31.471727 43360 24.138466 48.516785 30.874186 43361 23.579895 48.195679 30.458025 43362 9.842224 46.499054 29.777399 43363 16.094208 47.945312 31.088732 43364 27.600418 46.885498 32.132835 43365 35.895477 47.023483 30.861170 43366 17.211716 45.685715 30.217180 43367 22.301193 46.508743 30.457346 43368 23.139320 47.576584 30.691729 43369 35.855362 46.045181 31.406282 43370 9.686180 44.569458 30.780031 43371 9.562622 43.819443 29.800661 43372 22.080002 45.427338 31.440195 43373 22.654190 46.646423 31.693354 43374 22.434357 46.277008 32.384186 43375 27.416168 45.996796 31.449694 43376 31.056946 44.878555 30.604418 43377 31.297081 45.236450 31.241388 43378 31.076843 44.777161 31.195627 43379 36.053192 44.721039 31.291079 43380 31.453537 44.162994 31.590914 43381 30.630562 42.973343 30.333666 43382 8.012764 41.969116 30.600710 43383 6.866013 42.115814 30.541498 43384 30.082306 41.769180 30.306101 43385 17.876183 42.079544 31.118662 43386 17.885635 43.271698 31.092318 43387 21.019073 41.678711 31.330126 43388 36.121429 43.374954 30.770952 43389 29.017227 40.760590 30.374559 43390 19.992081 39.805847 30.290529 43391 20.016006 38.979782 30.572321 43392 19.297607 39.866180 30.268633 43393 20.304260 40.508133 30.319666 43394 19.886406 40.328033 30.003740 43395 27.556007 40.610474 30.577730 43396 28.037918 40.715668 31.703730 43397 26.995514 40.917603 31.145266 43398 27.663338 40.425674 29.808184 43399 37.660507 41.035217 30.709093 43400 38.425468 40.227753 30.730570 43401 38.676857 39.252884 30.512079 43402 39.154182 39.927979 31.128496 43403 38.744240 38.115799 30.533236 43404 39.751801 38.797394 31.592882 43405 39.465179 39.987152 31.706705 43406 38.665291 37.081314 30.938051 43407 38.820450 36.369308 31.970873 43408 39.397163 37.134537 31.423388 43409 3.570053 34.918777 29.376236 43410 4.253136 34.369736 29.482307 43411 5.497566 33.853546 29.849062 43412 7.219460 33.135406 30.425203 43413 43.003479 33.444458 30.796846 43414 44.153931 33.257523 29.826448 43415 44.461746 33.087494 28.993896 43416 44.406372 33.005310 30.997904 43417 44.838196 32.606415 31.834719 43418 44.058594 33.052948 32.069542 43419 9.766251 31.014191 30.176340 43420 10.595627 31.597076 29.469872 43421 10.256851 32.180237 28.983925 43422 11.162788 30.948654 29.588524 43423 11.365990 31.102158 29.238632 43424 30.070267 30.907547 31.478670 43425 30.705002 31.509796 30.565508 43426 11.272041 28.951508 29.600359 43427 35.957993 29.107483 30.769487 43428 44.536087 28.934769 29.839388 43429 2.840004 27.370560 28.650536 43430 3.705956 27.681931 28.766823 43431 12.015366 25.644196 28.969223 43432 29.824532 27.660461 31.874727 43433 28.145554 27.641846 29.386986 43434 41.473907 26.334183 30.135309 43435 42.019043 27.119995 30.929636 43436 41.905243 27.300613 29.729532 43437 5.942703 26.466888 28.532692 43438 48.128357 26.278305 29.694750 43439 51.107666 25.611450 30.327593 43440 2.384804 27.102875 28.422050 43441 5.212357 26.259048 29.004059 43442 46.448456 25.634521 29.645235 43443 49.060516 26.398804 31.050997 43444 49.062012 26.495377 30.482401 43445 49.871918 26.217499 30.942247 43446 11.645950 24.005096 29.513542 43447 27.904465 23.564148 29.743242 43448 41.613922 25.386658 29.631098 43449 42.477188 25.444794 30.929476 43450 27.966217 22.510803 30.279421 43451 42.847855 24.836472 30.307581 43452 43.724304 25.297607 31.580362 43453 9.325432 21.601578 29.584625 43454 6.841072 22.785004 30.356096 43455 7.140808 23.238495 29.612490 43456 10.438156 22.282471 28.623260 43457 9.365250 20.136566 30.945589 43458 29.308357 21.812485 28.937965 43459 28.727905 21.552094 29.499435 43460 2.736763 20.594070 30.760599 43461 2.931732 19.739426 31.132158 43462 10.272675 21.743942 29.201149 43463 36.874771 20.497894 28.863327 43464 50.231903 21.949646 30.806955 43465 49.185959 21.082321 29.910151 43466 49.153931 21.633560 32.067101 43467 50.448669 21.953415 29.434631 43468 30.725250 18.711060 28.558685 43469 36.820358 19.211761 28.324440 43470 37.682373 20.008972 29.004723 43471 37.083519 21.277588 29.750536 43472 38.345024 18.847397 28.745064 43473 38.620407 20.161270 29.617449 43474 39.971855 18.930054 29.193916 43475 39.861511 20.352905 30.349512 43476 40.878143 19.672867 29.941828 43477 41.070190 19.067932 29.358223 43478 40.966858 18.634155 29.051178 43479 41.782745 18.778046 29.118919 43480 43.942261 18.676956 29.574509 43481 42.916138 19.210770 29.527550 43482 44.012329 20.007812 30.534609 43483 53.245758 18.668060 29.321785 43484 54.067566 18.855408 29.188492 43485 53.923111 18.744293 29.603273 43486 4.353981 15.750137 27.989433 43487 3.477249 15.101715 28.997673 43488 30.748672 17.646393 28.550987 43489 39.768822 15.711609 29.322296 43490 41.136307 18.008667 28.945580 43491 41.323730 16.871994 29.469856 43492 42.714767 17.761215 29.366852 43493 42.558075 18.402206 29.122772 43494 47.425201 18.763397 29.202301 43495 46.515549 19.024109 29.642328 43496 47.683807 19.905228 29.732103 43497 46.967819 18.027405 29.495560 43498 47.875687 17.952332 28.951630 43499 51.115646 17.878967 29.069511 43500 52.182358 18.183655 29.744509 43501 3.098404 16.348602 29.337746 43502 30.796158 16.767120 28.943565 43503 46.675400 17.441345 30.153414 43504 46.112869 17.311203 30.830973 43505 45.428848 17.565002 30.271646 43506 49.205322 17.072906 29.931864 43507 49.049774 17.325211 29.065865 43508 50.010452 17.485260 29.155640 43509 48.587524 17.059784 29.397064 43510 4.603630 14.690735 28.303032 43511 5.110520 15.339600 27.595863 43512 47.871887 17.238815 29.710817 43513 56.551910 16.038666 29.457634 43514 29.984291 13.069168 28.845108 43515 5.280457 12.253098 28.131828 43516 34.748375 13.081299 29.060791 43517 37.292847 14.163239 28.964096 43518 37.088852 13.646576 29.543625 43519 38.164368 13.944275 29.757166 43520 38.573288 14.743958 29.168442 43521 52.223175 13.417252 28.995346 43522 56.288071 15.490692 30.447573 43523 33.772568 12.741638 29.119095 43524 5.329109 10.770844 28.687218 43525 2.719905 6.938694 20.979399 43526 4.407890 9.355350 26.114956 43527 4.608349 8.439547 26.995403 43528 3.000040 6.240068 22.592484 43529 4.102043 8.155884 25.663813 43530 3.720336 7.574553 24.720490 43531 4.242339 7.057035 26.472654 43532 4.889813 6.628795 28.218147 43533 4.763998 7.531299 27.654047 43534 5.338242 7.724091 28.667885 43535 2.731403 5.754195 21.632248 43536 2.828338 5.397854 22.294523 43537 3.772881 6.806768 25.176657 43538 3.340434 6.047450 24.038208 43539 3.902942 5.709371 26.013458 43540 3.595161 5.831768 25.015884 43541 41.160110 7.790039 28.305038 43542 40.319916 8.125702 28.792290 43543 41.170868 8.669342 29.529266 43544 41.895767 8.654404 28.909828 43545 42.045837 8.242905 28.551743 43546 42.804993 8.841232 29.164078 43547 42.381805 7.501694 28.553085 43548 3.420603 4.809957 24.808979 43549 42.305237 5.941132 28.055710 43550 41.283798 6.417633 27.856644 43551 50.974030 7.991058 29.309746 43552 52.132156 8.437592 28.361572 43553 3.071630 5.268484 23.358004 43554 3.007383 4.410599 23.467182 43555 43.716125 6.771301 29.068649 43556 44.262726 5.603973 28.448357 43557 43.283234 5.552460 28.233765 43558 50.016724 6.953461 28.865578 43559 2.604478 2.681862 22.243666 43560 47.855927 5.977448 28.503899 43561 48.815247 6.698288 29.200302 43562 49.251419 6.293350 28.385460 43563 59.643204 5.162369 28.554131 43564 59.693481 4.505859 28.832809 43565 37.119766 4.458008 28.187721 43566 36.477196 4.260941 28.530792 43567 44.959427 6.390533 29.165161 43568 45.756042 7.195923 29.914232 43569 46.780518 7.469116 30.312807 43570 2.600735 3.789378 21.867432 43571 37.239731 3.445015 28.489891 43572 35.748283 3.476105 29.191414 43573 53.248184 3.893295 28.838890 43574 40.265701 1.404678 28.718109 43575 39.153839 2.067825 29.001350 43576 48.938507 1.775986 28.174812 43577 49.360718 2.312714 29.258705 43578 46.775391 0.739792 28.013763 43579 47.755188 1.225937 28.111763 43580 42.407013 0.056458 28.767891 43581 41.371201 0.587967 28.733299 43582 45.087250 -0.154495 27.757034 43583 45.873825 0.231827 27.911385 43584 58.094299 -2.272003 28.253563 43585 57.783356 -1.272995 29.449623 43586 55.168655 -2.875610 28.819839 43587 54.278900 -3.541290 28.104988 43588 54.343430 -4.105103 27.426567 43589 58.370697 -3.197159 27.817192 43590 58.881882 -3.102753 27.927277 43591 59.203476 -3.053085 27.890465 43592 56.717377 -2.341675 29.045097 43593 59.753891 -3.246628 27.495499 43594 59.238739 -3.399124 27.840210 43595 60.485458 -3.156647 27.167885 43596 58.922043 -3.445145 27.875137 43597 59.001373 -4.091324 27.398315 43598 59.484711 -6.207077 27.230042 43599 49.713837 -4.429611 28.923485 43600 50.379486 -3.178543 30.133974 43601 51.394226 -3.529724 29.067902 43602 51.188126 -4.608459 28.148331 43603 51.708130 -5.349609 28.088913 43604 50.945023 -5.326401 28.091499 43605 50.408112 -5.240005 28.319435 43606 50.682053 -5.990921 28.863251 43607 49.682526 -5.652100 28.661835 43608 58.418549 -6.975403 28.030556 43609 57.531448 -6.839508 27.912292 43610 60.153946 -6.986221 27.481941 43611 3.059728 -6.411834 25.518547 43612 52.225510 -6.119843 28.969894 43613 54.569183 -6.399368 29.413239 43614 53.458618 -6.204514 29.730791 43615 54.720322 -6.682877 28.577148 43616 59.216904 -6.869232 27.748055 43617 3.192496 -7.677903 25.964209 43618 2.977535 -8.014490 25.017738 43619 3.314307 -9.519650 26.198479 43620 2.923828 -8.772449 24.676392 43621 59.178055 -6.900772 28.949669 43622 59.926804 -7.211914 28.194069 43623 60.662430 -7.610199 27.986038 43624 61.536133 -10.365723 29.074890 43625 60.988403 -8.259933 29.708040 43626 61.051102 -8.518585 28.503860 43627 3.013068 -9.754700 24.937832 43628 2.908739 -10.408593 24.256899 43629 3.189947 -10.828937 25.471413 43630 3.026104 -11.289372 24.608618 43631 2.903555 -11.468152 23.712515 43632 3.126968 -11.505826 25.074518 43633 54.297302 -11.943619 28.627945 43634 55.195312 -11.997391 27.413017 43635 54.592102 -11.585022 30.786554 43636 51.395340 -11.642868 30.533640 43637 53.730133 -11.086411 31.884439 43638 62.683960 -12.903183 27.342239 43639 62.250443 -12.370041 28.344315 43640 3.232804 -14.939152 24.144588 43641 49.131088 -13.123032 28.433327 43642 49.984619 -12.271286 28.690300 43643 3.228894 -12.386958 25.117533 43644 3.290961 -13.825740 24.887486 43645 3.389802 -15.082704 24.967821 43646 58.174698 -13.534668 27.327042 43647 62.994690 -13.589554 26.984215 43648 3.282816 -16.132673 23.630184 43649 51.281464 -14.647415 27.150192 43650 3.450715 -16.112911 24.743349 43651 52.137482 -15.157852 27.075432 43652 51.754395 -14.909973 28.200043 43653 53.126343 -15.533325 27.481873 43654 53.097839 -15.451874 28.755943 43655 55.346680 -16.172409 29.399277 43656 55.018890 -15.848770 28.879890 43657 55.578415 -16.258621 28.425957 43658 61.207062 -14.853546 27.964523 43659 61.621155 -14.791748 28.212433 43660 62.548218 -13.902359 27.605881 43661 3.454809 -17.035961 24.105768 43662 3.686378 -17.439062 25.192291 43663 55.524673 -16.850220 27.071106 43664 57.503464 -16.902802 29.211319 43665 58.330154 -17.254257 29.841921 43666 57.695267 -17.170807 30.124262 43667 57.643707 -17.781189 27.185318 43668 57.851822 -17.344254 28.216545 43669 56.686737 -16.960098 27.952896 43670 58.712799 -17.484833 28.996445 43671 58.928436 -18.132965 27.581406 43672 59.865555 -18.108047 28.791763 43673 4.052190 -19.940815 25.868559 43674 61.231979 -19.123627 26.891739 43675 60.313873 -18.616226 27.307449 43676 4.163326 -23.284060 25.488325 43677 60.381622 -18.470718 29.932100 43678 49.989822 -21.739334 26.792885 43679 49.754684 -21.876999 26.947342 43680 49.846008 -21.524155 26.962105 43681 50.224396 -21.615433 26.963806 43682 63.144730 -20.994217 26.827759 43683 3.957515 -23.312586 24.257318 43684 3.873932 -22.695393 23.592361 43685 4.293624 -21.644438 26.394747 43686 50.135849 -21.967285 26.956429 43687 4.463984 -24.176855 26.497374 43688 62.339447 -22.079163 28.419601 43689 4.203517 -24.846106 25.352816 43690 62.962891 -24.503632 26.785713 43691 62.682846 -25.312485 27.956329 43692 61.719208 -24.384354 28.700081 43693 62.437851 -23.712540 28.121277 43694 63.193207 -25.937866 26.811234 43695 4.031460 -25.494255 24.265368 43696 4.146415 -26.081993 24.763895 43697 4.002409 -26.871883 23.527826 43698 4.069132 -27.339647 23.782522 43699 52.421600 -28.845581 26.328133 43700 47.720016 -29.601227 25.818108 43701 49.213135 -29.728729 26.110077 43702 50.016388 -29.138794 26.120369 43703 55.768661 -29.344818 25.651413 43704 53.535751 -29.736359 27.097633 43705 54.425903 -29.675903 27.032555 43706 63.110779 -29.007431 27.078796 43707 63.069916 -26.759262 27.708107 43708 4.190844 -27.273140 24.430687 43709 4.372716 -26.411383 25.582621 43710 4.299126 -28.099222 24.454880 43711 4.397447 -28.648411 24.691206 43712 4.489727 -30.223288 24.010555 43713 49.245331 -30.574051 25.981079 43714 48.261169 -30.509705 25.769127 43715 47.320526 -29.918671 25.579498 43716 50.413300 -30.310211 26.247475 43717 62.641083 -30.178757 27.180412 43718 50.767487 -31.985565 26.035332 43719 51.052124 -33.424149 26.286179 43720 61.595581 -31.138580 26.717606 43721 4.520274 -29.665127 24.832264 43722 4.611379 -30.873421 24.336012 43723 52.223892 -32.459503 26.314224 43724 51.899658 -31.043289 26.536926 43725 4.841099 -32.289467 24.038597 43726 4.695023 -30.817699 24.846222 43727 4.628313 -31.340767 23.814964 43728 46.900528 -34.163818 26.570114 43729 47.584106 -34.045364 25.907547 43730 48.415253 -34.053574 25.947876 43731 52.194901 -33.657639 26.527061 43732 49.751328 -34.383881 26.655548 43733 52.992569 -31.443542 26.775597 43734 53.002014 -33.317215 26.543289 43735 39.605896 -34.531143 25.203217 43736 40.166351 -34.066330 25.199692 43737 41.519684 -34.177536 25.624184 43738 47.810944 -34.431259 26.337891 43739 48.576141 -34.601242 26.591797 43740 52.986984 -34.218735 26.968163 43741 40.942413 -35.575256 25.917252 43742 40.917480 -36.713959 25.319870 43743 41.535889 -36.589844 26.099617 43744 5.670149 -35.012386 25.201994 43745 5.367156 -33.945854 25.121172 43746 5.810550 -36.011395 24.735737 43747 6.237449 -37.156555 24.965868 43748 7.256424 -41.308525 24.296389 43749 42.917236 -37.960846 26.250702 43750 44.573822 -38.244766 27.109543 43751 50.940689 -38.523911 25.025749 43752 6.718213 -37.416115 25.968987 43753 59.724731 -40.951187 25.274887 43754 60.760300 -40.390930 24.882736 43755 8.063444 -41.217209 25.877380 43756 8.578765 -41.862869 25.998878 43757 8.141647 -42.339539 24.945663 43758 57.838318 -40.282288 26.959381 43759 58.449921 -41.244812 26.657417 43760 58.376465 -40.972900 27.461716 43761 60.540771 -43.263245 25.669167 43762 59.737885 -42.046158 25.835403 43763 5.252190 -43.909698 24.410225 43764 6.192703 -43.657837 24.567749 43765 7.871429 -43.515366 24.737701 43766 8.221344 -43.149231 24.979256 43767 46.598267 -44.040787 26.075798 43768 45.905060 -44.472412 25.049812 43769 44.163742 -44.559616 25.944466 43770 45.028854 -44.192978 26.077339 43771 50.649506 -44.576859 25.053467 43772 50.664444 -45.089478 25.741058 43773 49.711258 -45.017380 26.292946 43774 60.822937 -44.768875 25.230392 43775 60.113922 -44.960510 26.696411 43776 55.928268 -46.798111 25.193260 43777 44.972275 -46.397522 25.098480 43778 53.880569 -46.799149 26.546516 43779 54.984177 -46.894440 25.965424 43780 59.809265 -46.617416 26.389526 43781 4.716499 -47.852158 25.433212 43782 4.688522 -45.725479 25.521881 43783 4.518982 -46.664215 26.762512 43784 57.669983 -47.802628 26.504379 43785 57.699158 -47.614410 25.431358 43786 56.873764 -47.470398 25.577271 43787 58.391602 -47.533249 25.515411 43788 59.136658 -47.403152 26.267700 43789 6.648583 -48.915329 24.165413 43790 8.221207 -48.975906 23.663483 43791 8.155670 -49.626892 25.258087 43792 9.107132 -49.355179 23.659050 43793 47.163895 -48.596375 25.765419 43794 46.684357 -48.467880 26.083344 43795 47.929413 -48.924255 25.676430 43796 49.371674 -50.015427 25.519936 43797 49.032761 -49.929367 25.935974 43798 48.765564 -49.481522 25.524406 43799 49.743942 -50.376831 26.188927 43800 7.364151 -53.035950 23.530296 43801 8.165237 -52.236481 23.215515 43802 8.668633 -52.532150 24.084740 43803 38.965576 -51.655777 25.044571 43804 40.460373 -51.766342 25.232033 43805 39.566849 -51.157410 25.813484 43806 40.903351 -51.315109 26.639191 43807 51.426529 -51.838440 24.995544 43808 9.308708 -53.029663 25.438385 43809 42.294586 -52.296524 26.007080 43810 41.127930 -52.746124 24.547485 43811 50.458160 -51.133591 25.545235 43812 51.372375 -52.220001 25.758919 43813 50.964172 -51.727509 25.823021 43814 6.457306 -54.114075 23.995560 43815 6.653030 -55.140976 24.726456 43816 7.430283 -54.362411 24.903275 43817 37.068840 -53.181595 24.562126 43818 42.598083 -53.572235 24.727371 43819 16.248489 -57.789505 23.529816 43820 35.982697 -55.121368 24.284340 43821 54.550873 -54.651306 24.549141 43822 5.023247 -55.947800 23.466042 43823 20.117020 -55.782944 24.242409 43824 23.865326 -56.678574 23.628944 43825 45.711472 -55.735107 24.477257 43826 16.741440 -59.232758 23.569962 43827 24.178726 -57.225464 23.776642 43828 47.124191 -56.034744 25.141693 43829 47.875061 -56.542328 24.316147 43830 48.834808 -56.653122 25.420486 43831 56.922653 -55.586380 26.335632 43832 56.438858 -55.823090 25.739113 43833 56.526688 -56.253693 26.942863 43834 18.220772 -56.945969 23.957680 43835 24.280792 -57.918091 23.718376 43836 49.051712 -56.954453 24.040916 43837 4.117882 -59.784103 22.952110 43838 4.488510 -59.036880 23.734634 43839 50.130676 -57.203857 24.660339 43840 55.764084 -58.472015 24.380333 43841 4.907929 -58.212570 24.010437 43842 4.264671 -61.070282 23.413834 43843 16.878609 -60.115738 23.382973 43844 17.066452 -61.012024 23.301903 43845 24.035988 -60.009491 25.223373 43846 24.283920 -60.867447 25.325592 43847 24.311279 -61.116776 24.798882 43848 55.160461 -58.911255 24.398178 43849 48.122070 -60.768707 24.366989 43850 4.115563 -62.180054 23.067375 43851 18.519226 -59.724014 23.967224 43852 19.097748 -61.685043 24.451363 43853 18.527397 -61.141953 23.856949 43854 18.127357 -62.496964 23.970436 43855 49.501099 -61.216827 24.999641 43856 4.119866 -63.029800 23.090004 43857 17.469315 -62.016388 23.358284 43858 16.692688 -63.913635 23.215538 43859 17.211075 -62.999619 23.400146 43860 22.978401 -62.593735 27.443863 43861 17.220253 -63.971924 24.243271 43862 51.915436 -63.288376 24.269264 43863 51.851532 -63.285080 25.028618 43864 9.583069 -64.963852 23.210159 43865 11.551010 -65.886337 24.093018 43866 16.390610 -64.868530 23.193863 43867 16.812843 -64.579758 23.575333 43868 39.042130 -64.889359 23.562599 43869 40.229858 -64.838089 23.845123 43870 42.385071 -65.363861 24.771515 43871 50.271545 -64.468628 23.844116 43872 13.111664 -66.128281 24.193947 43873 14.229523 -65.633072 23.316223 43874 16.261719 -65.198776 23.971802 43875 15.328362 -65.452820 25.084488 43876 16.384361 -64.815506 24.969070 43877 15.996796 -65.432892 23.338745 43878 38.418114 -65.484360 24.689362 43879 39.465820 -65.227890 24.418747 43880 4.389557 -66.686310 22.467834 43881 4.681442 -67.505066 23.141724 43882 5.259361 -67.338745 22.480927 43883 15.301926 -65.616272 23.612457 43884 35.597641 -67.167511 24.506371 43885 5.079956 -67.845337 23.180092 43886 5.540627 -67.848511 23.424805 43887 6.183083 -67.362289 23.364098 43888 35.688049 -67.751419 23.958328 43889 35.413033 -68.208893 24.519196 43890 49.598648 -69.193985 23.540916 43891 48.758118 -69.396500 23.625603 43892 50.428436 -68.616440 22.854210 43893 37.459900 -70.381973 24.260651 43894 43.652710 -70.690659 23.246361 43895 43.134354 -71.094482 23.405251 43896 5.968170 -72.188293 24.452751 43897 6.728317 -71.999603 24.753952 43898 18.610779 -71.176575 22.758781 43899 18.302063 -69.890198 24.098930 43900 26.809433 -70.622559 23.115623 43901 26.434258 -70.677170 24.212357 43902 28.278412 -70.598663 23.253212 43903 28.940491 -71.242035 22.690376 43904 39.901909 -70.052505 23.310974 43905 40.678513 -70.398880 23.462051 43906 42.419586 -70.815918 23.296097 43907 41.547821 -70.677444 23.511833 43908 44.349426 -70.238876 23.344559 43909 45.622284 -70.471893 23.782196 43910 49.912659 -70.135651 23.203682 43911 50.047592 -69.246643 23.257713 43912 29.099579 -71.321609 23.151871 43913 7.834907 -70.976898 23.694618 43914 12.780411 -72.183792 23.948563 43915 12.881027 -71.265564 23.402695 43916 13.715034 -71.752975 23.025856 43917 29.241501 -72.043808 22.845581 43918 42.372040 -71.403946 23.794884 43919 43.434296 -72.047729 24.298347 43920 42.214737 -71.852585 24.531975 43921 48.668915 -71.732819 23.509842 43922 48.369919 -72.510712 22.811111 43923 49.295929 -70.968567 23.306419 43924 18.845497 -73.136368 22.598633 43925 29.296265 -74.155334 23.814064 43926 29.344360 -72.644241 23.917488 43927 29.343079 -73.053848 25.509720 43928 12.242828 -73.740982 24.750542 43929 36.968124 -74.513779 22.906090 43930 36.647026 -74.169449 23.480576 43931 37.360672 -74.207977 23.332138 43932 5.017929 -76.244217 24.170471 43933 17.599876 -75.420624 22.670456 43934 16.941849 -75.876923 22.292480 43935 25.288177 -77.937622 22.020630 43936 24.941605 -77.184708 22.877853 43937 39.425751 -76.275452 23.357910 43938 39.604927 -76.385788 22.971313 43939 38.471222 -74.984329 24.070839 43940 37.584717 -74.196564 24.084732 43941 16.766830 -76.605103 24.887688 43942 17.075798 -76.521591 23.247421 43943 17.562599 -75.357864 23.651810 43944 35.888817 -75.118820 22.860413 43945 38.890717 -75.928284 24.493729 43946 5.293701 -77.716293 23.098694 43947 15.361130 -77.076660 22.654053 43948 25.448486 -75.337402 23.431831 43949 25.236473 -76.294266 23.377449 43950 29.365021 -77.079041 24.714645 43951 39.459732 -76.743622 22.881187 43952 15.253906 -77.716660 23.080406 43953 16.217712 -77.939667 23.845795 43954 24.351852 -77.650894 23.664696 43955 24.901474 -76.908997 23.873016 43956 24.455475 -78.204880 22.808006 43957 39.247017 -77.283386 22.794235 43958 24.916435 -78.877625 22.301346 43959 24.057724 -79.215225 22.895340 43960 38.303596 -79.432251 22.604752 43961 24.920593 -79.776047 22.590103 43962 42.108856 -80.736282 22.954590 43963 27.286118 -81.439423 22.086479 43964 26.615372 -81.448959 23.222412 43965 35.005203 -81.869431 22.685966 43966 36.910072 -80.707214 22.619629 43967 12.418015 -81.950409 21.628479 43968 27.329506 -82.353378 23.055115 43969 34.159874 -82.586609 23.367996 43970 33.253082 -83.130966 23.353989 43971 37.129837 -80.782410 23.816322 43972 36.109283 -81.528091 23.589676 43973 41.655273 -81.740067 22.761208 43974 13.851868 -83.608810 21.950470 43975 7.060272 -84.608795 21.689484 43976 6.604141 -85.424774 21.808403 43977 7.969070 -84.408905 21.529549 43978 14.648956 -84.527328 21.828033 43979 31.770067 -83.668549 22.477951 43980 31.298981 -84.010452 22.011841 43981 32.460922 -83.198715 22.569527 43982 38.470657 -84.989319 22.221092 43983 8.838058 -85.339005 21.561150 43984 7.730880 -85.664276 22.145340 43985 6.840073 -86.240707 22.175270 43986 13.631615 -84.294891 22.703049 43987 14.377678 -85.579529 22.906815 43988 16.297806 -86.785812 22.285446 43989 24.705261 -85.685379 22.667816 43990 37.205147 -85.503448 23.069870 43991 6.414719 -86.127914 21.787315 43992 6.522041 -86.973862 21.404243 43993 17.407265 -87.360641 21.856941 43994 16.953552 -87.068497 21.544296 43995 30.881088 -87.649612 21.846519 43996 31.569313 -85.860580 23.074387 43997 24.696831 -87.240433 23.635414 43998 24.694778 -87.461533 22.458939 43999 25.731186 -87.730194 23.236519 44000 31.144241 -87.466568 22.638634 44001 32.229050 -88.008377 22.513306 44002 34.136444 -87.443466 22.403633 44003 11.689003 -88.694778 21.689972 44004 13.712395 -89.780518 22.026123 44005 19.196671 -88.609711 23.476402 44006 19.303894 -89.062592 22.364571 44007 31.407936 -87.903915 22.448730 44008 33.221764 -87.603806 23.083786 44009 7.653442 -88.020355 22.349289 44010 7.017113 -87.111038 22.248924 44011 8.528084 -89.741440 21.777351 44012 18.842529 -89.630096 21.877441 44013 17.122604 -91.114670 22.529602 44014 17.962463 -92.458939 23.264450 44015 16.625786 -92.537750 23.187195 44016 18.729301 -90.427032 22.349236 44017 27.545578 -89.369049 22.546974 44018 10.114594 -90.721039 21.908531 44019 10.738739 -92.144745 21.269035 44020 26.756790 -91.782150 21.804680 44021 11.887589 -92.352600 21.301575 44022 24.138367 -92.669952 21.387779 44023 23.425766 -93.149857 22.051941 44024 25.117195 -92.299393 22.437042 44025 12.900574 -92.292816 21.605942 44026 13.748138 -93.031143 21.349297 44027 14.127357 -93.765274 21.239525 44028 21.879379 -93.900436 21.304741 44029 22.293335 -93.702713 22.490677 44030 14.465866 -94.259735 21.253914 44031 15.048187 -94.761688 21.274742 44032 15.819351 -94.794159 21.778793 44033 16.613327 -95.141434 21.248329 44034 16.930069 -94.582764 22.239754 44035 15.881355 -94.202011 22.554779 44036 16.706573 -95.402786 20.702751 44037 18.056824 -94.447617 22.432487 44038 19.330383 -94.334549 22.450722 44039 6.715492 60.620880 31.500010 44040 8.216386 59.809998 32.159241 44041 7.370636 60.127899 32.361000 44042 6.519936 60.196426 32.550819 44043 3.897629 57.114212 32.132629 44044 8.942268 59.030579 32.080391 44045 7.868598 59.599976 32.765518 44046 9.524277 58.144135 32.482613 44047 10.605011 57.067505 32.131607 44048 11.789749 55.936462 31.835680 44049 11.403160 56.956970 33.218575 44050 18.237152 54.533905 31.326342 44051 21.309494 54.572388 31.470263 44052 20.367004 54.532562 31.679873 44053 4.276337 56.768829 33.256821 44054 12.728348 54.785080 31.993456 44055 3.447540 53.335022 31.845346 44056 3.787376 54.138702 33.119019 44057 3.971146 53.497681 33.399857 44058 18.100639 53.378723 31.413286 44059 19.500488 53.672867 31.762094 44060 21.564438 53.745224 31.537653 44061 13.674950 52.232452 31.512667 44062 18.919258 52.347626 31.615595 44063 19.130142 51.270294 31.454416 44064 20.727821 52.577545 31.724215 44065 4.228859 50.089417 31.858652 44066 5.064598 49.273041 31.227762 44067 13.510559 52.449127 32.301857 44068 14.044678 50.876129 32.013573 44069 14.503044 50.597961 31.261904 44070 20.006699 51.685883 31.651072 44071 20.022446 50.804596 31.263597 44072 14.615463 49.798950 32.614563 44073 14.085281 50.264267 32.473534 44074 27.102127 49.454742 32.723335 44075 5.727623 48.673325 31.176340 44076 7.756248 48.367584 30.015306 44077 34.179482 48.755951 31.359598 44078 23.720551 48.099167 31.534395 44079 17.129517 46.023621 31.086496 44080 23.030518 47.314240 31.448275 44081 27.759811 47.986450 32.365425 44082 33.928810 48.332092 31.934259 44083 9.166405 45.712616 31.228640 44084 35.527222 45.763580 32.508789 44085 35.248695 46.949799 31.874628 44086 17.742226 44.582977 31.073610 44087 26.714722 44.764145 32.411629 44088 26.480995 43.642166 31.681330 44089 27.111092 45.778076 32.291718 44090 32.102310 45.936066 32.237061 44091 17.882385 43.868683 30.864344 44092 21.489655 43.800049 31.473734 44093 36.781677 43.282333 31.706263 44094 36.223465 44.404678 32.537514 44095 4.945519 41.918182 30.606920 44096 4.154778 41.783157 30.290308 44097 17.947517 43.909210 31.198298 44098 17.916954 44.029968 31.816980 44099 26.506462 42.302155 32.014626 44100 26.616928 43.034088 32.834656 44101 31.285873 42.272232 31.484232 44102 36.601364 43.723541 32.660538 44103 3.677078 41.667618 29.850710 44104 5.971878 41.714508 30.909761 44105 9.070526 41.751343 31.740686 44106 8.798615 42.021317 30.970499 44107 9.461610 43.015076 31.244089 44108 26.657684 43.949127 33.081604 44109 37.514542 42.536057 32.325089 44110 36.890717 43.189514 32.810837 44111 37.597595 42.024338 31.366358 44112 4.052132 40.880585 30.418825 44113 18.360306 40.136047 30.635019 44114 17.930801 40.951843 31.034739 44115 26.538452 41.528351 31.214960 44116 29.979462 41.083130 30.765810 44117 30.657997 41.097366 31.333651 44118 38.023544 41.923172 31.871698 44119 38.604149 40.943817 31.649622 44120 38.048660 41.774033 32.640968 44121 38.672783 40.938187 32.921425 44122 17.834473 39.803986 31.527956 44123 20.584511 39.828003 30.911516 44124 28.817749 40.892426 33.169060 44125 29.208275 41.525726 34.229713 44126 28.315063 42.180420 34.065247 44127 27.104340 41.307846 32.271812 44128 29.962372 40.806946 31.111429 44129 29.934937 40.505707 31.989100 44130 39.550972 39.854797 32.755203 44131 3.275749 37.491501 31.103174 44132 3.998238 39.474243 31.072405 44133 3.836578 38.724823 32.695488 44134 18.674759 38.705673 31.022966 44135 21.394806 39.929077 32.142975 44136 21.748451 38.578033 31.970690 44137 20.944031 38.218994 31.118860 44138 3.216011 38.457855 29.907358 44139 19.530411 38.238373 30.688951 44140 20.102478 38.157181 30.682093 44141 39.376213 37.689346 31.071795 44142 19.557281 36.927643 31.502939 44143 20.160583 37.492249 30.843111 44144 21.679199 37.147324 31.032869 44145 20.940918 36.598755 31.012285 44146 39.743149 37.677399 31.479731 44147 39.844345 37.412567 32.165108 44148 18.218124 37.215454 32.793198 44149 17.817848 37.654388 33.058678 44150 18.016342 38.143570 32.244987 44151 37.647133 36.135162 31.165087 44152 39.519730 36.519104 33.051880 44153 21.334053 35.345901 31.148462 44154 20.460365 35.655396 31.509043 44155 22.633942 36.234055 31.296572 44156 23.928383 35.266754 31.307657 44157 23.321709 34.844940 30.828875 44158 24.231842 36.267807 32.407135 44159 24.697205 35.273575 32.292038 44160 24.407776 35.327148 31.774134 44161 22.253250 34.122238 30.977518 44162 23.350075 34.055267 30.844278 44163 3.233536 35.635239 30.088198 44164 3.627548 34.667114 30.160677 44165 3.993492 34.294983 30.185686 44166 23.051033 33.585251 30.902163 44167 23.856506 34.391663 31.096643 44168 4.478119 34.099976 30.278376 44169 5.052895 34.223450 31.223185 44170 6.195946 33.714890 31.071802 44171 22.789062 33.115097 31.128778 44172 23.664383 33.405869 31.744410 44173 22.671501 32.332611 31.820650 44174 39.315475 31.915176 30.662226 44175 42.079681 33.421509 30.339808 44176 8.512276 31.421890 30.705233 44177 10.648468 31.033768 29.840441 44178 32.286865 32.458084 31.144777 44179 33.561935 33.271271 30.800234 44180 45.874207 31.499008 30.117273 44181 45.401230 31.526932 31.195978 44182 29.795181 30.181320 31.591295 44183 32.199234 32.436142 32.801491 44184 32.898438 32.526718 32.092972 44185 45.135986 32.181396 32.094124 44186 10.794991 30.319458 29.907885 44187 28.481506 27.674988 30.012224 44188 37.117722 30.227737 31.000475 44189 40.056458 32.143524 31.307734 44190 38.167831 30.865768 31.502825 44191 45.128616 31.649887 32.568413 44192 44.767731 29.900253 32.047844 44193 11.211113 26.857025 30.090288 44194 33.922081 27.055115 30.228945 44195 44.141907 28.920868 30.761545 44196 42.975967 28.058685 30.803026 44197 43.609467 28.739471 31.759249 44198 3.587334 27.039001 29.107658 44199 34.815880 27.459579 30.853914 44200 3.190117 25.475494 29.557861 44201 3.203491 26.539856 29.144440 44202 4.159485 26.077393 29.433693 44203 29.263672 26.248215 31.710032 44204 30.501297 27.415970 32.601929 44205 32.970245 26.441528 29.596458 44206 50.503113 25.641357 31.652483 44207 5.217186 25.260529 29.490623 44208 28.121857 26.119308 30.002542 44209 41.844406 26.387146 31.012232 44210 46.657791 25.885666 30.725458 44211 2.451508 23.190933 29.903261 44212 2.457932 21.438141 29.792902 44213 4.329064 24.334564 30.423677 44214 6.120056 24.029236 29.787577 44215 45.760208 25.522186 30.364206 44216 45.103302 25.430695 31.217463 44217 2.863075 24.233658 30.166292 44218 11.352890 22.440460 29.669329 44219 33.935989 24.143585 30.847811 44220 34.220169 25.817001 30.936899 44221 33.603645 22.995117 30.260157 44222 32.994431 22.745758 29.794878 44223 42.201416 26.571625 31.813433 44224 42.650330 25.999176 32.359703 44225 51.066696 23.902359 32.131317 44226 51.078888 24.838623 31.652491 44227 28.077972 24.202316 30.965738 44228 10.706207 21.102753 30.275339 44229 33.404266 22.382812 29.716600 44230 36.487411 22.444336 31.082666 44231 34.836502 23.017975 30.815859 44232 37.838303 22.646973 32.223038 44233 38.322113 21.556244 30.916201 44234 28.447289 21.201447 30.304308 44235 28.202667 21.805130 31.111986 44236 29.608368 20.027649 30.113802 44237 28.980881 20.629547 29.890139 44238 46.755661 20.575760 31.129557 44239 48.097961 20.854294 31.059412 44240 50.978668 22.901627 31.454729 44241 41.686188 20.296448 30.745806 44242 40.799759 20.208160 30.548693 44243 41.855316 19.533142 29.749918 44244 42.688049 19.990265 30.351915 44245 45.248932 19.394928 29.927126 44246 45.582733 18.219269 29.789782 44247 43.974640 20.865143 32.026413 44248 44.523819 21.340775 32.724808 44249 45.231506 20.760086 31.641214 44250 46.356781 19.841553 30.108568 44251 2.916817 18.297440 30.715860 44252 30.037933 19.613022 29.679361 44253 30.586868 19.548370 30.491404 44254 30.994003 20.165024 31.642809 44255 29.970894 20.182938 30.961336 44256 30.759270 18.991455 29.638094 44257 45.527527 20.157883 30.559374 44258 53.673218 18.447159 30.102190 44259 31.247467 17.797150 29.411034 44260 54.759552 18.358749 30.127970 44261 55.459229 17.863190 30.139132 44262 31.255325 16.624298 29.686426 44263 32.089584 18.695587 30.623629 44264 32.268684 17.039749 30.252016 44265 43.029419 17.276260 30.022417 44266 44.220703 17.757767 29.937815 44267 44.421005 17.295624 30.810244 44268 48.364349 17.339722 29.061050 44269 30.542778 15.742554 29.521561 44270 29.733963 15.024506 30.343401 44271 31.173248 15.804993 30.829706 44272 50.785248 17.490173 30.009829 44273 52.254288 17.953491 30.777582 44274 55.760864 16.778091 30.937769 44275 3.359345 13.685196 29.320267 44276 2.805908 14.329514 29.898134 44277 5.148430 14.561050 28.019867 44278 33.566437 17.698517 30.811342 44279 4.197006 12.449936 29.063705 44280 4.998283 11.603577 28.865288 44281 4.196838 13.892136 28.741531 44282 5.014877 13.694275 28.186836 44283 28.536285 13.640442 30.111780 44284 29.093086 14.239471 29.833597 44285 29.112816 13.417297 29.398743 44286 37.411575 13.509949 30.395098 44287 28.668007 13.045273 29.834261 44288 36.069611 13.248474 29.731157 44289 34.985352 12.813019 29.814760 44290 34.311104 12.718338 29.495720 44291 39.507050 14.244171 30.982477 44292 52.096878 13.087921 29.567520 44293 53.251801 13.393677 29.576012 44294 52.420486 13.318787 29.617250 44295 29.209694 12.489914 29.851130 44296 30.685425 11.731842 30.574373 44297 29.800209 11.602341 30.782930 44298 32.445221 12.151505 30.043810 44299 33.776031 12.472382 30.154001 44300 53.036575 12.384689 30.438906 44301 52.435242 12.964203 29.831392 44302 52.013336 11.297134 29.376114 44303 52.416382 11.297516 30.085573 44304 5.254067 9.145599 28.528244 44305 5.257385 9.879852 29.265312 44306 52.466675 10.416748 30.412020 44307 42.236694 9.206650 29.796350 44308 42.891495 9.435181 29.726213 44309 43.454346 9.463242 29.729151 44310 43.579346 9.043793 29.446793 44311 43.971024 9.241302 29.763094 44312 4.364897 5.845622 27.291698 44313 40.156311 8.272217 29.602312 44314 39.614639 7.763885 30.379801 44315 43.733093 8.380844 29.476593 44316 51.082550 9.264328 30.954142 44317 2.722388 4.629640 22.101038 44318 5.396492 6.858490 29.094543 44319 38.154236 6.821411 29.254128 44320 37.336853 6.058670 30.342646 44321 38.585052 7.037140 30.261881 44322 52.077484 10.140610 31.314806 44323 2.765142 4.130064 22.593090 44324 2.783540 3.600608 22.845898 44325 3.033716 3.530928 23.881872 44326 4.366044 4.567977 27.983372 44327 4.122297 3.204305 27.695272 44328 3.882247 4.347711 26.501797 44329 4.815558 5.542454 28.671206 44330 44.242340 6.292877 29.128532 44331 49.504181 6.526154 28.639618 44332 58.805115 6.069839 30.433695 44333 58.215286 6.333649 30.815447 44334 35.834869 4.544037 30.039652 44335 47.571014 6.536057 29.429184 44336 59.173843 5.279655 29.730478 44337 35.974258 4.391403 28.981979 44338 55.636932 6.118408 31.682940 44339 54.744385 5.677917 31.873331 44340 55.178513 5.526573 30.841043 44341 54.548706 4.848831 29.879122 44342 35.635262 4.140015 29.281593 44343 53.159760 4.492561 31.241098 44344 52.606949 3.906227 30.087976 44345 54.297226 5.081245 31.049974 44346 59.086975 3.567245 31.026529 44347 59.001785 4.458420 31.111391 44348 35.243141 2.554962 29.704050 44349 35.676224 2.517838 29.167900 44350 36.382408 2.468170 29.093018 44351 37.394730 2.387939 29.157951 44352 36.845703 1.555222 29.855593 44353 38.340179 2.645432 28.706985 44354 50.671265 2.816528 29.292740 44355 51.961456 3.274384 29.187820 44356 51.212341 3.325638 30.238894 44357 35.670319 1.887939 29.649599 44358 38.276917 1.978973 29.598442 44359 39.572769 1.682983 29.933474 44360 47.926849 1.841080 29.254303 44361 48.468140 2.480209 30.316614 44362 45.964081 0.727081 28.748795 44363 46.772461 1.220062 28.997581 44364 43.140289 0.003784 29.153763 44365 43.173950 0.487289 29.769938 44366 45.031311 0.251480 28.622513 44367 43.981659 0.248703 29.170334 44368 45.295593 1.098206 29.807055 44369 59.071777 1.501740 29.897051 44370 54.360199 -2.514374 29.704760 44371 55.328354 -2.102753 30.003366 44372 59.056183 -3.242508 28.005074 44373 48.642593 -5.599457 28.868622 44374 48.431870 -4.930832 28.952904 44375 48.146576 -4.357773 29.711084 44376 47.795929 -5.305496 29.208038 44377 46.956985 -5.340027 29.963564 44378 49.100388 -6.323486 29.418823 44379 50.234283 -6.329071 30.433428 44380 49.108078 -6.617203 30.370653 44381 52.523712 -6.067581 30.459162 44382 55.548462 -6.717056 28.813705 44383 55.905029 -5.939987 30.324770 44384 56.991806 -6.678848 29.028191 44385 58.122391 -6.826797 28.883392 44386 60.314117 -7.373932 29.189674 44387 52.282227 -10.936707 32.197617 44388 61.963821 -12.116699 29.514313 44389 61.904907 -13.468994 29.231499 44390 3.645668 -15.507452 25.905993 44391 50.089478 -14.103546 27.934349 44392 49.255722 -14.113266 28.431946 44393 49.109421 -13.831543 28.353271 44394 57.219360 -12.603592 29.700312 44395 59.026871 -13.584244 29.474556 44396 59.448578 -14.037491 28.238106 44397 49.625641 -14.413803 28.787880 44398 51.595367 -15.030838 29.083916 44399 50.694931 -15.001175 29.092590 44400 52.204834 -15.284409 29.153923 44401 60.898605 -14.577408 28.412971 44402 62.033386 -14.417603 28.277306 44403 54.445984 -15.898941 28.095253 44404 54.290283 -15.802963 29.298981 44405 48.964539 -19.916336 28.731949 44406 49.948120 -19.208084 28.573662 44407 49.772797 -20.116852 27.849731 44408 51.777863 -18.902618 28.910019 44409 53.852524 -20.584778 28.931671 44410 52.702194 -21.319946 28.109276 44411 50.655090 -16.812393 29.487915 44412 51.802383 -16.795441 29.719553 44413 51.594559 -20.563217 27.890144 44414 50.028809 -18.355362 29.105194 44415 48.722168 -18.044373 30.214670 44416 50.003311 -21.020096 27.318855 44417 49.278778 -20.684021 27.713104 44418 50.711823 -20.197769 27.820457 44419 51.034546 -21.850479 27.383743 44420 62.897369 -20.772690 26.852142 44421 49.215363 -21.598785 27.375443 44422 48.764465 -20.885727 28.023781 44423 48.260727 -21.568512 28.075188 44424 62.062668 -20.678177 29.156242 44425 62.494476 -20.727081 27.708771 44426 48.334793 -20.759933 28.891235 44427 47.618484 -21.366058 28.885216 44428 48.378357 -22.555542 27.745567 44429 49.730408 -22.589447 27.320435 44430 50.767700 -23.180511 27.515404 44431 51.730042 -23.190262 27.546616 44432 47.360489 -22.236862 28.605911 44433 49.824417 -23.810593 28.073357 44434 48.687149 -23.411194 27.776253 44435 52.665115 -22.751282 27.658714 44436 55.760635 -22.395966 28.675026 44437 54.124573 -22.673447 28.082222 44438 54.734375 -21.608032 28.669258 44439 52.683258 -23.746277 27.912003 44440 54.153046 -23.571121 27.925751 44441 53.569550 -23.479935 27.840790 44442 47.515808 -23.581741 28.622490 44443 48.551788 -23.992081 28.269707 44444 51.407349 -23.876938 28.177780 44445 52.592499 -24.237823 28.731026 44446 51.803040 -24.266068 29.344315 44447 54.056671 -24.231796 28.482155 44448 4.062205 -26.700439 24.131266 44449 4.485697 -28.286394 25.453106 44450 4.702725 -26.267145 26.800383 44451 52.043976 -29.575470 26.681168 44452 52.897675 -29.275040 26.801826 44453 52.856598 -29.665283 27.097847 44454 54.947083 -29.353043 26.654396 44455 62.926987 -28.128754 28.256348 44456 62.908615 -29.391342 28.157928 44457 52.924240 -30.376312 27.045898 44458 53.734314 -32.445923 26.769135 44459 54.261124 -30.819351 27.133263 44460 58.420670 -32.688354 27.545319 44461 53.837189 -33.602524 26.826805 44462 54.452087 -33.018021 26.931351 44463 55.261215 -32.236618 27.154602 44464 54.678833 -33.563461 27.227806 44465 40.225662 -34.775360 25.626328 44466 45.695923 -34.342072 27.181908 44467 55.947617 -33.569641 27.715645 44468 54.794098 -34.953964 28.959137 44469 56.476044 -34.530945 28.488602 44470 53.830643 -34.302628 27.253296 44471 40.180664 -35.362640 25.660675 44472 48.057388 -34.671829 27.491356 44473 45.049225 -34.691208 28.562523 44474 46.750916 -34.440063 28.435310 44475 51.719711 -34.725754 27.691170 44476 5.074814 -32.558388 25.121960 44477 4.878553 -31.096535 25.417213 44478 42.173889 -37.073883 26.544701 44479 6.040518 -35.866982 25.536676 44480 6.383515 -36.370998 25.993118 44481 42.834351 -37.325775 27.574684 44482 43.510788 -37.682495 28.216232 44483 42.916229 -37.216980 28.225998 44484 49.223877 -39.020798 29.271744 44485 48.393585 -39.013214 28.122498 44486 51.191299 -38.855164 25.889343 44487 55.944183 -38.976868 26.859886 44488 57.227066 -39.540649 26.697380 44489 7.350055 -39.468838 25.822712 44490 51.234619 -39.064880 26.621056 44491 7.485558 -40.452728 25.346113 44492 58.012756 -40.290924 27.744095 44493 57.525009 -39.772018 27.487450 44494 8.664116 -42.707001 26.195084 44495 7.760826 -43.549377 25.437218 44496 59.134415 -42.112808 26.462898 44497 59.722626 -42.780411 26.255127 44498 59.470337 -42.841980 26.831825 44499 6.164696 -44.128769 25.914299 44500 4.864456 -44.575165 25.100555 44501 4.509987 -44.943466 25.026680 44502 7.192886 -43.834106 27.029900 44503 6.566986 -43.985596 27.293442 44504 7.842079 -43.588943 26.476555 44505 43.757034 -44.436905 26.489479 44506 44.132950 -44.127213 26.309517 44507 46.066299 -43.764328 27.561829 44508 59.907578 -43.486435 26.597755 44509 59.028702 -42.063721 27.447571 44510 59.690750 -43.559097 27.710083 44511 43.872650 -45.298050 26.375641 44512 43.315918 -44.685104 27.414360 44513 47.825546 -44.260727 25.961777 44514 48.751282 -44.591263 26.565948 44515 44.561783 -46.452835 26.189217 44516 51.475708 -45.689377 26.257332 44517 52.580307 -46.208435 26.318321 44518 59.618652 -45.149170 28.879257 44519 52.345184 -46.329529 27.042168 44520 53.019775 -46.639191 27.058472 44521 46.138916 -48.140457 25.957443 44522 45.589111 -47.630615 26.404297 44523 55.049438 -47.144135 27.169678 44524 4.666977 -48.435928 26.808922 44525 5.634842 -49.258423 25.430962 44526 7.068367 -49.866516 25.799217 44527 9.183158 -49.699295 24.885033 44528 55.872177 -47.417480 26.138245 44529 56.551529 -47.762299 26.243561 44530 48.674225 -49.502838 26.517342 44531 10.149033 -50.966370 25.316391 44532 10.155617 -51.596603 26.055290 44533 36.925911 -53.693710 25.378136 44534 37.685577 -52.069534 25.801407 44535 7.872566 -53.532608 24.557152 44536 9.849579 -54.370728 26.881699 44537 9.038589 -54.417007 25.895889 44538 42.009552 -51.702408 26.788017 44539 41.884888 -51.486618 27.497849 44540 42.602203 -51.957840 27.231918 44541 51.952179 -52.659393 25.624207 44542 8.353439 -54.066254 25.272690 44543 37.129547 -55.038010 25.485580 44544 37.403313 -53.991821 26.095261 44545 37.296471 -52.985992 26.538925 44546 52.506531 -52.501358 26.333786 44547 51.726318 -52.388596 26.047867 44548 52.907516 -53.106583 25.794235 44549 22.452393 -55.897217 24.422348 44550 21.423233 -56.565247 24.796509 44551 36.419693 -54.717361 24.914497 44552 53.689758 -53.701889 25.423920 44553 19.410149 -56.769882 24.431961 44554 19.821129 -57.394882 24.724258 44555 20.323296 -56.820984 24.775162 44556 22.597809 -56.897385 24.962334 44557 35.919846 -55.821106 24.164993 44558 45.228577 -53.856934 26.815796 44559 44.747162 -52.845673 28.197975 44560 45.999725 -53.457275 28.341843 44561 47.160721 -54.996292 27.336906 44562 47.836838 -55.419418 27.340286 44563 47.764908 -55.781815 26.484291 44564 54.372208 -53.054825 26.624680 44565 56.672913 -54.865005 26.500725 44566 55.838196 -53.877777 26.542122 44567 23.636917 -57.274460 24.482971 44568 23.038040 -57.615433 25.090683 44569 23.973190 -58.661209 24.899101 44570 24.270508 -58.915283 24.224609 44571 56.982040 -55.471146 26.776596 44572 20.441666 -58.506805 24.827820 44573 18.718781 -58.014481 24.222191 44574 48.859711 -56.282120 26.576286 44575 50.702454 -57.324127 25.769348 44576 38.773331 -57.072922 25.292847 44577 40.105881 -56.999771 25.895409 44578 52.408813 -58.135666 25.437439 44579 51.993393 -57.713913 26.976730 44580 53.406555 -58.324997 26.502777 44581 4.638275 -59.945206 24.166504 44582 19.731903 -60.348190 24.496536 44583 20.578232 -60.033615 25.165337 44584 40.639542 -58.080368 25.485733 44585 41.970245 -59.114807 25.158386 44586 54.117493 -57.918701 27.493103 44587 54.944931 -58.107010 26.372612 44588 55.084579 -58.572937 25.121590 44589 4.918884 -60.804092 24.739601 44590 4.590363 -62.341721 24.765663 44591 21.331238 -59.488113 25.580811 44592 20.641472 -60.377121 26.192612 44593 21.502846 -59.755981 26.547699 44594 41.648758 -58.379837 25.695190 44595 41.136780 -57.574722 25.982025 44596 47.108383 -60.547043 25.443626 44597 48.468552 -60.820404 25.897629 44598 49.475800 -61.262375 26.140312 44599 18.171127 -62.857910 25.350395 44600 18.873604 -62.292542 26.084190 44601 19.738693 -61.378067 25.411995 44602 4.304459 -65.070984 25.347992 44603 43.851028 -65.609543 25.326210 44604 45.112473 -64.799652 24.674553 44605 46.118378 -64.706558 24.594307 44606 51.848312 -63.348846 26.122887 44607 51.464767 -64.112625 25.322380 44608 3.956772 -65.943634 23.989410 44609 9.555969 -65.298309 23.836212 44610 10.434830 -65.581924 24.174896 44611 36.258560 -66.301666 25.691711 44612 40.196625 -65.722549 24.857773 44613 39.413437 -66.134872 25.383095 44614 39.607414 -66.521118 25.722023 44615 41.374527 -65.807190 24.983650 44616 50.270813 -64.839081 25.484772 44617 49.063202 -65.263153 25.749481 44618 4.233322 -67.012726 23.827858 44619 5.068619 -68.072540 24.195854 44620 8.536438 -65.796906 24.260880 44621 14.316490 -66.032410 24.648636 44622 42.331467 -66.308533 25.570930 44623 35.133179 -67.629669 25.392670 44624 35.621536 -66.762405 25.495117 44625 6.055534 -67.985153 24.620186 44626 19.248566 -66.868698 26.928864 44627 19.014374 -67.152344 26.878204 44628 35.857666 -69.934769 24.520004 44629 9.752396 -70.933197 24.129509 44630 10.191803 -72.584335 25.475983 44631 8.128479 -72.072601 25.280136 44632 9.302917 -69.926514 22.981277 44633 35.584915 -69.000946 24.396378 44634 46.373077 -69.498779 23.537674 44635 47.457169 -69.368820 23.593246 44636 11.321106 -71.807800 24.627113 44637 11.733582 -70.926941 23.727180 44638 10.942261 -70.130280 23.250626 44639 27.276093 -70.097397 24.233704 44640 34.987320 -71.033630 25.312683 44641 35.037460 -69.990433 25.128304 44642 39.012192 -70.504166 24.216492 44643 38.433701 -71.198700 25.292023 44644 37.584869 -72.366318 25.837006 44645 47.997864 -70.218948 23.983521 44646 47.093079 -70.749710 24.102524 44647 49.488297 -69.976395 23.631668 44648 48.691101 -70.711899 23.884140 44649 17.775818 -71.588959 24.396004 44650 25.948242 -71.421280 25.299271 44651 40.382660 -70.826904 24.212357 44652 41.433289 -71.391434 24.352348 44653 44.813232 -71.576126 24.006126 44654 47.984589 -70.857941 24.221107 44655 48.211029 -71.460419 24.152512 44656 11.994537 -72.515793 24.735634 44657 16.921715 -72.040619 25.604408 44658 17.278610 -73.645538 24.702431 44659 29.176941 -71.525955 23.676666 44660 43.968292 -71.249069 23.606285 44661 46.086182 -71.949753 24.295441 44662 48.169357 -72.247375 23.719917 44663 26.730774 -70.060181 25.245987 44664 25.682335 -73.801376 24.564079 44665 35.593109 -74.296631 23.817863 44666 34.989098 -74.268143 24.259850 44667 35.244370 -73.713821 24.389305 44668 35.035126 -75.248688 24.139374 44669 36.384613 -73.478104 24.420319 44670 47.439957 -72.107071 24.170586 44671 43.525452 -76.971573 25.091812 44672 43.922318 -76.265884 24.193687 44673 43.170471 -77.671753 23.927719 44674 5.520172 -78.358139 24.088387 44675 5.715942 -79.259598 22.804810 44676 14.457687 -77.725632 23.335724 44677 15.329269 -78.749680 23.991882 44678 14.689857 -79.150253 24.562241 44679 14.480164 -78.429092 23.794113 44680 23.648743 -78.495819 23.570976 44681 23.189377 -79.620438 23.345825 44682 29.728653 -78.077545 23.907715 44683 34.884430 -76.724060 23.950615 44684 34.434357 -77.792999 24.301773 44685 38.192337 -74.803741 25.228279 44686 38.461311 -75.747742 25.929131 44687 39.148499 -77.066223 23.848740 44688 38.209663 -79.451721 23.693527 44689 13.582382 -77.848755 24.252380 44690 22.870201 -79.120804 24.131500 44691 29.557632 -78.094635 24.931473 44692 30.030548 -79.125839 24.662971 44693 32.854660 -79.275131 24.141518 44694 33.878998 -78.661331 24.298943 44695 22.391731 -80.159378 23.950531 44696 23.022385 -80.458038 23.384171 44697 23.815323 -80.393784 23.156647 44698 42.573593 -79.356964 23.933365 44699 7.610855 -81.022964 23.125404 44700 11.806564 -82.235535 22.295845 44701 22.929749 -81.104614 23.915230 44702 24.111588 -81.124985 23.631264 44703 24.826759 -80.625717 23.183586 44704 25.383911 -81.415451 23.925507 44705 37.711967 -80.169586 24.535812 44706 41.913239 -80.507111 24.331886 44707 42.182831 -79.495026 25.295570 44708 12.670593 -82.410202 21.901909 44709 21.505409 -80.871750 24.779991 44710 21.708679 -80.167206 24.549980 44711 41.230713 -81.632782 24.054848 44712 40.933685 -81.320435 25.439941 44713 41.403351 -80.639191 25.399246 44714 12.673920 -83.336868 22.582809 44715 11.530136 -83.031204 23.098495 44716 10.620262 -82.430389 23.168182 44717 35.172546 -82.304718 24.070679 44718 38.619202 -84.540115 23.392021 44719 40.275604 -82.750320 24.062012 44720 32.400612 -83.756363 23.336624 44721 39.525650 -83.659958 23.668037 44722 7.418381 -86.520859 22.579773 44723 27.339539 -82.956940 24.153984 44724 31.594460 -84.502625 22.899872 44725 37.881012 -84.701859 24.459244 44726 23.830788 -85.974304 23.154785 44727 23.184143 -86.077713 22.652451 44728 25.628815 -85.843353 23.183830 44729 25.592712 -85.658417 22.639740 44730 8.057709 -86.477325 22.512115 44731 17.481812 -87.496979 22.508934 44732 26.310989 -85.717865 23.989044 44733 31.412949 -86.975403 23.033600 44734 34.940750 -86.812012 22.973953 44735 35.422943 -85.928131 24.281044 44736 36.742157 -85.197342 24.806686 44737 8.582619 -88.243301 22.440933 44738 8.018295 -87.165695 22.583801 44739 16.663803 -87.423828 23.121094 44740 17.868011 -87.992996 23.190636 44741 18.133446 -88.587326 24.103500 44742 23.896347 -86.960770 23.165039 44743 26.793808 -88.408936 22.884544 44744 26.609390 -88.224808 24.647614 44745 33.886955 -86.923859 23.890717 44746 33.213516 -87.232574 23.879044 44747 7.424927 -87.147980 22.598541 44748 7.931396 -88.899948 22.191238 44749 11.429382 -90.047562 22.287262 44750 10.521118 -89.551697 22.284775 44751 19.715187 -89.854080 22.641342 44752 20.091568 -89.528503 23.547447 44753 27.579453 -90.251022 23.239334 44754 14.633621 -90.424500 22.247406 44755 12.662750 -90.004868 22.199036 44756 20.124161 -89.970840 23.097221 44757 27.497269 -89.939102 24.110725 44758 27.644989 -89.444077 23.717216 44759 15.424942 -91.631485 22.736099 44760 19.833786 -90.761429 23.274040 44761 18.659256 -91.334610 22.910530 44762 26.405716 -91.486115 23.048035 44763 27.169373 -91.065918 22.837837 44764 13.765060 -91.465805 22.293121 44765 14.353394 -93.622101 21.832153 44766 14.690742 -92.833618 22.459724 44767 20.940422 -94.096222 22.370575 44768 15.021820 -94.014755 22.148270 44769 16.362015 -93.590820 23.057335 44770 4.685402 58.429688 33.558891 44771 5.828873 59.799393 33.270790 44772 8.476501 59.064713 32.820160 44773 3.895928 55.038712 32.767090 44774 12.542282 55.902832 33.121056 44775 19.297470 54.515533 31.696474 44776 4.091675 52.105118 33.478714 44777 13.615860 54.058701 33.297531 44778 14.162079 51.764771 33.338020 44779 14.157616 50.581177 32.878929 44780 4.770836 48.560822 32.324570 44781 5.243767 48.623032 31.618288 44782 3.901375 50.696472 32.965813 44783 4.097061 49.483154 33.122993 44784 4.613983 48.031433 33.337143 44785 5.153748 47.581039 33.032898 44786 5.762688 48.092468 31.680712 44787 15.529907 48.679367 32.277466 44788 27.310852 48.607941 33.278168 44789 33.768570 46.848663 33.072990 44790 33.961342 47.431335 32.764763 44791 34.648758 46.896393 32.680641 44792 5.620812 47.609375 32.343788 44793 6.652023 47.318680 31.922625 44794 16.843277 47.497910 32.654091 44795 34.292877 47.698624 32.298340 44796 7.742599 46.598679 31.944605 44797 8.474641 46.082169 31.922747 44798 8.850021 45.495590 32.299011 44799 23.116615 47.369003 32.849686 44800 23.682114 47.793823 34.654007 44801 22.070755 45.100647 32.727768 44802 35.785065 44.897308 33.241989 44803 9.352898 44.717163 32.057243 44804 17.700500 45.467651 32.314682 44805 17.925812 45.250473 33.786926 44806 17.822968 46.552673 33.489685 44807 9.596497 43.999268 31.718874 44808 21.613266 43.488327 32.702698 44809 22.042236 44.342926 34.114868 44810 21.884201 43.033661 35.079086 44811 21.702042 42.111115 33.532211 44812 9.344627 42.416840 33.640152 44813 9.545006 43.537521 32.724358 44814 9.463165 43.691513 34.156845 44815 17.686920 42.932648 32.381744 44816 17.472794 41.220062 32.334343 44817 17.183624 42.238678 33.724831 44818 32.171249 43.006317 32.361069 44819 32.441788 42.059311 32.316956 44820 5.474869 40.709229 31.474504 44821 4.919243 39.764450 32.337669 44822 6.736984 41.132263 31.415140 44823 7.569359 41.339310 31.221750 44824 8.351044 41.378510 31.515589 44825 9.310944 42.077759 32.555550 44826 17.233482 39.835785 32.701324 44827 32.091202 40.971985 32.054420 44828 31.166946 40.484055 31.869287 44829 31.811831 40.233795 32.079735 44830 33.872528 41.370636 33.119537 44831 7.616912 40.930176 32.050598 44832 6.580994 40.674072 32.471451 44833 5.674576 40.250504 32.731041 44834 27.143433 42.169037 33.127060 44835 32.379715 40.086288 32.426811 44836 31.243111 40.042145 32.332153 44837 31.900484 39.929169 32.377655 44838 3.219078 37.596191 32.427902 44839 21.978310 37.663834 31.544451 44840 40.350159 38.343842 32.533691 44841 40.250305 39.044739 32.511940 44842 3.360626 36.430618 32.170822 44843 3.314530 37.881760 33.025787 44844 3.417358 37.098877 33.086731 44845 20.033066 35.369186 32.403877 44846 37.745369 35.392914 32.298622 44847 36.974365 34.399521 33.064651 44848 3.307259 35.761917 31.251375 44849 3.523056 34.969177 30.896708 44850 4.058037 34.464874 30.819544 44851 20.847748 34.460709 31.746027 44852 24.293152 34.596207 31.734995 44853 41.719299 33.101669 31.334200 44854 43.489212 33.332794 31.702410 44855 43.406891 33.205475 32.219742 44856 42.646851 33.096359 32.155594 44857 7.586639 32.029388 31.649820 44858 7.089150 33.330658 31.795275 44859 8.109146 32.328796 30.602098 44860 22.120834 32.804657 31.360765 44861 21.217422 32.972931 31.915438 44862 33.629013 32.958450 31.806261 44863 40.696640 32.425262 31.634584 44864 41.310760 32.447403 32.629341 44865 8.835175 30.127411 30.888742 44866 8.179054 29.256622 31.542353 44867 9.115662 29.046936 31.113413 44868 21.850906 32.121140 31.873003 44869 30.820915 31.639206 31.732378 44870 31.252098 31.968170 32.559196 44871 45.257538 30.935089 32.289139 44872 9.964935 29.563110 30.464563 44873 38.172134 30.231720 32.794548 44874 39.634926 31.435013 32.410812 44875 10.045959 27.979324 30.869150 44876 10.472923 26.502853 31.016771 44877 36.197495 27.726486 32.146530 44878 35.409668 27.325104 31.534388 44879 8.879745 28.129547 31.596567 44880 8.507401 27.397797 32.264503 44881 9.657379 26.655731 31.772371 44882 28.274994 23.517792 32.196167 44883 28.591965 23.531891 32.749466 44884 29.145782 24.268799 32.810410 44885 42.675781 27.712097 32.154488 44886 48.100433 26.247604 30.996744 44887 48.996445 26.089951 31.810534 44888 11.105064 24.765228 31.222490 44889 49.236313 25.172760 33.302490 44890 46.840759 25.836456 32.442093 44891 49.893372 26.032227 31.686884 44892 49.903931 25.724533 32.278732 44893 50.504013 24.910614 32.511749 44894 2.406197 24.044724 29.829729 44895 5.756920 22.681671 31.245089 44896 4.246956 23.132599 31.492411 44897 43.243057 25.569397 32.265251 44898 4.639412 22.513229 32.020309 44899 11.628967 23.275879 30.490862 44900 34.749374 24.901077 31.694201 44901 6.893730 22.106888 30.993486 44902 11.792809 22.510193 30.527575 44903 11.655518 21.836502 30.629915 44904 36.714111 23.118347 32.177429 44905 2.855408 21.640717 31.467554 44906 2.594719 22.435150 30.878260 44907 11.020851 19.007431 31.781702 44908 11.563103 20.984390 31.595865 44909 11.745132 19.937943 32.815002 44910 28.639236 21.045822 30.894793 44911 27.785095 22.249298 30.924593 44912 38.962769 21.967789 31.941263 44913 39.574661 21.267654 31.297396 44914 39.851555 21.616272 32.093323 44915 50.787109 22.991425 32.466682 44916 50.273468 22.605728 33.163452 44917 50.404617 23.816605 33.184555 44918 2.989891 16.712265 30.585909 44919 7.887672 19.514633 32.207542 44920 29.075119 20.578796 30.640100 44921 40.664688 20.872742 31.387300 44922 42.905869 20.696274 31.644960 44923 29.347397 21.093567 31.562098 44924 33.879036 18.625793 31.546061 44925 54.240326 17.964905 31.003962 44926 33.577545 16.696045 30.956263 44927 32.858963 15.976196 31.531832 44928 34.184906 16.160172 32.126907 44929 42.763763 16.679321 30.814066 44930 45.945740 17.201492 31.825670 44931 44.911148 17.140488 32.708992 44932 44.023926 16.937164 31.872553 44933 46.286926 17.187103 33.219406 44934 47.843918 17.003769 32.347061 44935 49.417389 17.062027 33.274124 44936 49.842041 17.162842 32.093590 44937 50.959381 17.434647 33.020935 44938 50.353149 17.294281 31.020525 44939 2.986687 15.667068 30.193834 44940 2.878418 15.029877 29.948397 44941 32.468018 16.183792 30.793009 44942 32.051941 15.774033 31.440088 44943 35.026024 17.367554 31.693110 44944 47.931564 17.075928 30.985781 44945 28.697517 14.379608 30.911699 44946 42.752335 15.969727 32.283035 44947 41.323730 15.690765 30.721148 44948 2.709580 13.448715 29.888773 44949 40.238434 13.963913 32.591782 44950 38.476044 13.463638 33.167694 44951 55.898529 15.293335 31.763094 44952 2.681007 12.529816 30.418390 44953 3.077210 12.808151 29.591064 44954 3.131813 11.925018 29.760042 44955 28.239128 12.818604 30.615557 44956 35.718994 12.846313 30.988565 44957 41.398743 14.895752 32.019264 44958 55.902954 14.447678 31.706697 44959 2.847847 10.803528 30.758715 44960 31.479828 11.894730 30.409296 44961 36.685722 12.938568 32.406685 44962 36.561417 12.793655 33.472649 44963 34.840981 12.367462 32.878380 44964 3.131638 9.757767 30.394999 44965 3.627617 9.653214 30.109018 44966 3.645615 10.283386 29.952059 44967 4.606140 10.708267 29.380219 44968 3.630379 11.189590 29.676111 44969 27.862419 11.871582 31.380007 44970 28.747116 11.949799 30.687639 44971 28.803528 11.198990 31.438929 44972 52.851471 11.181519 31.422373 44973 4.349716 9.520218 29.921297 44974 4.972115 9.796982 29.645662 44975 44.038818 9.878494 30.312975 44976 44.577393 10.344269 31.049723 44977 44.727417 9.983536 30.646769 44978 43.901428 10.337616 31.126360 44979 45.539658 10.005066 31.532175 44980 44.667770 9.175583 30.269609 44981 5.381607 7.931839 29.367493 44982 43.032486 9.769913 30.658449 44983 41.753021 8.906372 31.471254 44984 40.526428 8.371063 30.492434 44985 40.198654 7.747162 31.624483 44986 44.761292 7.805481 29.852716 44987 5.396546 6.878769 29.947206 44988 5.378914 5.806152 29.678209 44989 39.171043 7.166336 31.275133 44990 48.869385 7.791245 30.515047 44991 49.954376 8.107681 30.411371 44992 49.826584 7.449524 29.717813 44993 49.462326 9.343750 31.892183 44994 47.871521 7.348419 30.257807 44995 50.382187 8.591156 30.653070 44996 3.409825 3.790127 25.184950 44997 5.026184 2.938271 30.105829 44998 4.710953 4.306046 29.680216 44999 5.465035 3.861938 30.540567 45000 2.853448 2.454687 23.540712 45001 3.158293 2.829097 24.655596 45002 3.501111 2.970243 25.800892 45003 3.240463 2.037706 25.217943 45004 58.652786 5.723221 31.416445 45005 34.964226 3.313469 30.900682 45006 35.352486 4.243011 31.328798 45007 53.809784 5.165413 32.124870 45008 2.721518 1.282421 23.267118 45009 34.718719 1.794189 30.677401 45010 49.757736 3.000412 30.567385 45011 50.587463 3.494598 31.269213 45012 35.655426 0.969986 30.414644 45013 41.070953 1.251678 30.201502 45014 46.779297 1.727753 29.872889 45015 47.457932 2.174576 30.267817 45016 48.478241 3.298080 31.792971 45017 47.540924 2.750885 31.172785 45018 41.431488 1.994385 31.673685 45019 42.724960 1.323227 30.749559 45020 43.916245 1.064270 30.364100 45021 44.093552 0.738602 29.849993 45022 58.972137 2.697937 31.131639 45023 2.888341 -3.200522 24.772280 45024 42.129684 0.606369 29.713694 45025 58.866013 0.847321 30.314203 45026 57.877945 -0.433975 30.681253 45027 58.300827 0.098969 30.740831 45028 54.192108 -2.012787 30.623529 45029 53.483032 -2.523819 29.926744 45030 51.524292 -2.663910 30.515100 45031 52.795959 -2.104782 30.970011 45032 56.405228 -1.430588 30.592852 45033 48.402161 -3.439636 30.931696 45034 49.287445 -3.626587 30.072123 45035 47.103317 -4.071960 30.853365 45036 47.612137 -6.280548 29.653887 45037 46.036041 -7.003922 30.715181 45038 45.960022 -5.159744 30.912500 45039 48.276871 -6.849045 30.407953 45040 47.389679 -7.046356 30.480814 45041 51.452942 -6.200226 30.061701 45042 58.381561 -5.829163 30.680651 45043 60.511902 -7.043564 30.777758 45044 59.777924 -6.473419 30.240007 45045 49.092453 -12.450470 29.406815 45046 50.412384 -11.430435 32.235611 45047 49.038345 -12.279526 31.230433 45048 48.589767 -13.047867 28.955727 45049 56.042068 -12.028351 30.479944 45050 48.397278 -13.060379 29.301208 45051 48.745605 -13.828232 29.023888 45052 48.270203 -13.230515 30.055857 45053 58.552094 -13.104492 30.356401 45054 48.337601 -14.514008 29.775286 45055 49.409027 -15.086700 29.460526 45056 59.366364 -13.425201 30.427279 45057 60.659836 -14.053314 29.249428 45058 60.059418 -13.741470 30.102861 45059 60.962921 -13.522202 30.253107 45060 61.572601 -14.399536 28.733231 45061 53.049835 -16.166260 29.723253 45062 56.320053 -16.586365 29.228622 45063 49.990967 -17.570618 29.377625 45064 61.294250 -19.160065 29.648951 45065 52.867035 -17.610626 29.804735 45066 53.829163 -21.578140 28.402794 45067 61.839447 -19.857483 29.605600 45068 45.313690 -22.075562 30.492952 45069 46.005188 -21.098602 30.874994 45070 46.774994 -21.525040 29.874895 45071 47.825867 -20.926163 29.682314 45072 53.756989 -19.515366 29.478195 45073 55.158478 -20.863068 29.247986 45074 55.543121 -21.412231 29.088272 45075 54.953125 -20.078415 29.662874 45076 61.259338 -21.563690 29.615061 45077 3.982148 -17.656157 26.505634 45078 55.068100 -23.487350 28.282753 45079 54.467407 -23.554611 28.072525 45080 56.218338 -20.650879 29.726015 45081 57.482178 -20.702286 29.924669 45082 57.333450 -22.276398 29.066895 45083 58.260406 -21.323898 29.671213 45084 58.816483 -22.534134 29.218941 45085 58.148788 -23.599182 28.742767 45086 57.245300 -25.235596 28.709465 45087 56.321915 -24.154663 28.648598 45088 58.215195 -24.699371 28.639923 45089 59.892075 -24.053268 28.956459 45090 48.140594 -24.361465 29.138542 45091 49.035080 -24.257172 28.707809 45092 47.223419 -24.195374 29.550980 45093 50.662094 -24.227066 29.145531 45094 49.710693 -24.296692 29.062996 45095 52.483627 -24.398575 29.453049 45096 56.094482 -25.323715 29.228752 45097 54.838211 -24.944901 29.391090 45098 57.593643 -26.583511 29.967913 45099 57.065567 -26.452133 30.388369 45100 56.721405 -26.081696 30.276735 45101 58.108658 -25.413101 28.739349 45102 57.433411 -25.913132 29.357452 45103 61.310013 -25.558105 28.843170 45104 62.436386 -26.456100 28.557861 45105 62.803207 -27.188049 28.438271 45106 4.522775 -27.134193 26.058676 45107 4.688036 -27.581177 26.507923 45108 4.566345 -27.937996 26.025246 45109 55.237228 -29.849564 26.918503 45110 62.607712 -30.326492 28.598679 45111 4.687086 -28.654341 26.121923 45112 4.655197 -29.688456 25.475657 45113 57.526230 -33.193008 27.675468 45114 58.549927 -33.626923 28.228180 45115 62.167557 -31.623657 28.146889 45116 61.249451 -32.913834 28.268883 45117 60.166733 -33.865845 29.014091 45118 62.046295 -32.602921 29.084229 45119 55.744476 -35.135086 29.447380 45120 56.851532 -33.845474 27.890221 45121 58.730560 -34.582962 29.679979 45122 57.444519 -33.937897 28.137482 45123 42.648865 -36.343231 27.616081 45124 49.145538 -34.938736 27.358940 45125 48.946609 -34.941986 28.114342 45126 49.477676 -35.119431 27.966431 45127 50.132507 -35.031555 27.835663 45128 50.824341 -34.996887 28.806396 45129 54.342987 -34.502121 27.873337 45130 53.850006 -35.029053 28.464920 45131 57.615005 -34.526596 28.892860 45132 5.081112 -31.882101 25.763412 45133 5.192118 -33.921516 24.431705 45134 5.140786 -33.367958 24.791456 45135 5.644294 -34.254532 25.755985 45136 5.902753 -34.908146 25.950579 45137 42.681747 -36.713135 28.094406 45138 53.269104 -34.859924 27.875816 45139 5.014556 -33.115616 24.350943 45140 7.180730 -37.088970 27.285118 45141 7.151751 -38.245907 26.339527 45142 48.003113 -38.639923 26.616577 45143 50.465271 -39.156509 27.894951 45144 51.993256 -39.151794 27.681396 45145 54.354401 -38.894501 28.764923 45146 56.111176 -39.301300 28.748322 45147 56.888000 -39.400299 27.626640 45148 54.372345 -39.198090 30.064005 45149 53.721313 -38.911224 29.977930 45150 7.615756 -38.798981 26.942654 45151 8.004467 -40.222855 26.635437 45152 8.205937 -39.643314 27.569986 45153 8.904068 -41.244431 27.764137 45154 9.077568 -42.294235 26.925461 45155 8.415158 -39.091877 28.517128 45156 22.619680 -40.806122 29.056303 45157 22.568533 -40.804001 29.110380 45158 22.623007 -40.752808 29.114943 45159 22.669142 -40.809570 29.112448 45160 9.013535 -42.628906 27.142807 45161 8.626144 -43.214203 27.032120 45162 22.618490 -40.856888 29.108450 45163 58.537308 -41.062439 28.507690 45164 59.300522 -42.479843 28.591217 45165 4.863144 -45.479706 26.992638 45166 5.951439 -44.316299 27.225906 45167 43.165619 -43.665665 28.563461 45168 44.155090 -43.938248 27.161987 45169 47.620209 -44.213470 27.044464 45170 59.640091 -43.552353 29.184898 45171 49.702728 -45.047394 27.173889 45172 48.949463 -44.463181 28.002365 45173 43.641068 -45.916397 27.766975 45174 50.831360 -45.540573 26.930237 45175 51.802979 -46.053238 26.898308 45176 53.530533 -46.901382 27.052109 45177 46.357956 -48.288483 26.605751 45178 53.770447 -46.794464 27.494766 45179 56.289276 -47.689880 27.011993 45180 59.043823 -47.527130 27.158157 45181 59.595596 -47.196594 26.953323 45182 59.484238 -46.631363 27.820297 45183 57.104965 -47.736526 27.943253 45184 57.572662 -47.685257 28.678940 45185 58.276321 -47.532028 28.215698 45186 5.318253 -49.924393 26.434837 45187 9.218216 -50.018631 26.224953 45188 8.290100 -50.332382 26.656471 45189 9.786316 -50.043228 25.802734 45190 9.915894 -50.259979 26.525406 45191 10.166763 -50.558914 25.931129 45192 47.434570 -48.777206 26.760941 45193 4.610222 -49.855453 27.661240 45194 6.201782 -50.219116 26.269852 45195 7.148117 -50.624313 27.013412 45196 10.158868 -50.811310 26.749870 45197 10.100578 -51.658417 27.569458 45198 37.227524 -52.082382 27.251770 45199 37.640228 -51.365768 27.331352 45200 38.864532 -50.993561 26.982033 45201 40.368576 -50.889847 27.920654 45202 38.642807 -51.243057 25.801704 45203 41.220764 -51.134552 27.601349 45204 51.167969 -50.458176 27.715767 45205 50.301025 -50.456238 27.003937 45206 50.643250 -51.058258 26.484283 45207 49.660309 -49.787338 27.396240 45208 53.221405 -51.633957 27.504112 45209 51.580872 -51.755493 26.490051 45210 43.876831 -53.209869 26.306313 45211 7.994804 -55.194336 25.533997 45212 37.728577 -53.805038 26.820122 45213 37.483871 -53.244965 27.504639 45214 43.478271 -52.363586 27.552086 45215 55.880630 -52.925323 27.562813 45216 55.271057 -52.183441 28.002274 45217 56.615494 -53.815201 27.610802 45218 55.762680 -53.330139 27.043045 45219 7.007660 -56.031204 25.169609 45220 38.134262 -54.771606 26.483818 45221 38.191757 -54.408920 27.776688 45222 37.221405 -53.676895 28.501694 45223 6.594177 -56.901276 25.152794 45224 38.107437 -55.891785 25.663979 45225 39.048325 -54.976181 27.106499 45226 39.099838 -55.850952 26.207314 45227 46.319885 -54.286621 27.431885 45228 46.190048 -55.020599 26.090057 45229 7.827026 -56.789383 25.830925 45230 40.247681 -55.736588 27.109482 45231 6.823700 -58.106415 25.605087 45232 5.680252 -58.761902 24.994415 45233 4.963493 -59.141327 24.492249 45234 23.335892 -58.559753 25.275635 45235 41.150284 -56.724258 26.594566 45236 49.691269 -56.763580 26.417793 45237 55.922165 -57.312607 26.656258 45238 22.177742 -58.332977 25.359802 45239 42.046173 -57.607529 26.455109 45240 53.874908 -58.595779 25.385437 45241 5.397896 -59.887360 25.114273 45242 23.508087 -61.099731 26.350143 45243 24.083633 -60.826492 25.653366 45244 21.961761 -59.368683 25.914993 45245 22.652878 -59.618988 26.430389 45246 42.922256 -58.656998 26.035126 45247 20.028412 -61.058655 26.264290 45248 44.352951 -59.531097 25.723579 45249 45.863525 -60.158920 25.894409 45250 45.315445 -59.085831 28.286079 45251 44.421524 -58.583206 28.062851 45252 44.258118 -58.624542 27.126289 45253 50.204529 -61.641647 25.840134 45254 23.937782 -61.542419 25.329544 45255 51.255829 -62.291901 25.860535 45256 50.347015 -61.619263 26.747292 45257 51.525696 -62.465744 27.324486 45258 16.562042 -64.009323 25.759529 45259 4.299477 -66.719650 25.385468 45260 4.140801 -66.622406 24.747986 45261 7.411057 -67.127151 24.967773 45262 9.611221 -65.838013 24.796577 45263 15.916817 -64.769150 25.571793 45264 38.536385 -66.445053 26.079552 45265 39.246483 -65.729080 25.081177 45266 44.961853 -65.400742 25.617310 45267 45.725250 -65.367447 25.662621 45268 46.868225 -65.222321 25.394531 45269 48.088745 -65.533096 25.854782 45270 51.827530 -63.643417 27.266891 45271 51.359116 -64.301132 26.193352 45272 10.638062 -68.411087 27.464142 45273 11.773781 -67.737381 27.030128 45274 10.918015 -67.222015 26.132355 45275 10.805840 -66.260712 24.992165 45276 12.076813 -66.651611 25.155647 45277 13.107979 -66.633469 25.602432 45278 36.735611 -66.391953 26.449593 45279 37.409317 -66.386749 26.489983 45280 40.604370 -66.934036 26.078918 45281 39.411148 -66.920990 26.316544 45282 13.693329 -66.346359 25.183495 45283 4.508682 -66.817230 26.392609 45284 4.734696 -67.926819 25.358353 45285 4.743530 -68.058533 26.806686 45286 5.514542 -68.527420 25.387604 45287 34.839104 -68.021332 26.441002 45288 35.255173 -67.241852 26.348694 45289 35.060547 -68.352097 25.072571 45290 5.081589 -68.420181 24.946167 45291 18.525024 -67.603973 27.005707 45292 18.089706 -68.366150 26.587959 45293 17.560738 -68.791412 26.847763 45294 17.129959 -69.120102 26.972191 45295 17.696144 -69.184921 25.895714 45296 17.764450 -69.706116 25.019516 45297 18.189217 -69.186127 24.922607 45298 27.509338 -69.577301 25.080154 45299 28.073799 -69.456161 25.392326 45300 28.185371 -69.954285 24.676765 45301 28.599297 -69.948547 25.380684 45302 34.802528 -68.590485 25.583176 45303 35.190224 -69.097794 24.968666 45304 34.774597 -69.445114 25.511688 45305 17.298508 -70.385284 25.465858 45306 38.662766 -72.088928 26.432457 45307 38.330711 -73.125534 27.066666 45308 36.127457 -71.881866 25.016037 45309 17.037613 -71.295044 25.546967 45310 29.034691 -71.174210 24.847458 45311 34.654602 -70.183060 25.587242 45312 39.611801 -71.418274 25.467857 45313 40.694336 -71.514114 25.071732 45314 47.751511 -71.270630 24.334488 45315 35.062057 -71.924026 25.217690 45316 34.361504 -72.115540 25.748657 45317 37.037209 -73.092773 25.227005 45318 37.428642 -73.857239 24.975113 45319 41.469208 -71.859863 25.095108 45320 42.292862 -72.478394 25.366356 45321 44.919647 -72.851944 24.681847 45322 4.954262 -73.322067 24.315727 45323 35.198669 -72.772629 24.913712 45324 43.542480 -73.032959 25.427322 45325 44.470993 -73.540344 25.433533 45326 45.176071 -74.179352 25.117447 45327 44.516129 -74.092773 25.827126 45328 34.546844 -73.864120 25.171143 45329 29.401031 -74.889114 24.954437 45330 29.404190 -74.363831 26.490211 45331 4.889237 -75.806580 25.432159 45332 5.039383 -74.054764 25.006889 45333 4.939667 -75.005371 26.166298 45334 25.405396 -75.809799 24.753937 45335 25.623367 -73.897064 26.830803 45336 29.476898 -75.878693 25.794456 45337 34.707779 -76.247864 25.045555 45338 34.378098 -75.145279 25.705872 45339 44.428345 -75.638779 25.163490 45340 43.953400 -76.240936 25.085678 45341 44.954559 -75.032578 25.075966 45342 16.094734 -74.731430 26.221199 45343 15.741455 -76.708313 26.639961 45344 24.565651 -77.646729 24.952225 45345 25.586990 -76.319061 26.499634 45346 34.798416 -77.016983 24.685371 45347 34.534996 -77.249588 25.404427 45348 38.657143 -76.995377 25.855682 45349 16.413574 -78.407516 25.141907 45350 23.557892 -78.344147 24.421600 45351 23.958946 -77.963074 24.169342 45352 38.727676 -78.166153 24.514801 45353 13.856827 -78.819000 24.685448 45354 15.907669 -79.118484 24.950073 45355 21.327454 -80.090393 24.987106 45356 21.228622 -79.691360 25.599243 45357 22.007362 -79.561188 24.935852 45358 23.275284 -78.782990 25.426163 45359 42.623001 -78.540619 25.816635 45360 42.886032 -78.234207 25.054825 45361 15.321686 -79.271988 24.613136 45362 32.951096 -79.911728 25.128326 45363 31.844240 -80.343628 25.065079 45364 30.684814 -79.965881 24.801971 45365 30.892868 -80.458191 25.566406 45366 6.255173 -80.005875 23.705894 45367 5.894821 -79.438293 24.839729 45368 22.157959 -82.128830 25.450500 45369 33.296089 -80.674118 27.865738 45370 33.631393 -79.866837 27.424782 45371 32.813812 -80.354721 26.328979 45372 33.877548 -78.792999 25.378174 45373 10.648376 -84.433380 24.230103 45374 10.772247 -83.370407 23.707047 45375 9.364265 -83.305206 24.670326 45376 21.107918 -81.617249 25.330704 45377 23.837006 -81.748672 24.509361 45378 24.874969 -82.222656 25.192055 45379 26.622055 -82.017975 24.074844 45380 27.060654 -82.682999 25.044121 45381 26.619720 -82.435822 25.161598 45382 26.756325 -82.372620 24.730919 45383 36.573685 -81.413132 24.786018 45384 37.790657 -80.038101 25.554710 45385 38.060394 -79.852844 26.602257 45386 38.101906 -80.399155 27.221199 45387 37.165421 -81.338287 26.497894 45388 34.176689 -83.080536 24.310028 45389 39.820969 -82.517624 25.399506 45390 40.354706 -81.899139 25.441963 45391 11.711510 -84.032272 23.512619 45392 32.744972 -84.598297 24.270828 45393 33.272720 -83.635880 24.163597 45394 39.382278 -83.077759 25.100533 45395 38.742523 -83.934601 24.613831 45396 38.147293 -84.016373 25.371384 45397 38.521202 -83.315491 25.831268 45398 12.876731 -84.784149 23.365494 45399 11.887985 -85.460739 24.189041 45400 13.366592 -86.077560 23.966141 45401 24.379211 -86.812469 24.149467 45402 24.090576 -86.400696 23.748932 45403 27.355675 -84.386414 24.038422 45404 32.512604 -87.052048 23.729179 45405 33.437469 -85.859207 24.620636 45406 33.245804 -86.756927 24.413567 45407 36.049103 -85.601196 24.891617 45408 15.006226 -87.056259 23.782570 45409 24.907661 -86.048157 23.662163 45410 8.161774 -88.759399 22.384964 45411 14.324791 -87.806610 24.638252 45412 15.399384 -88.082474 24.445587 45413 16.655594 -88.049316 23.968033 45414 17.360931 -88.927002 24.574516 45415 24.988106 -86.974213 24.550301 45416 25.604767 -87.357544 24.223648 45417 31.664171 -87.556290 23.028320 45418 19.106461 -88.919754 24.637177 45419 26.140579 -86.556961 25.278847 45420 27.333015 -88.857422 23.716858 45421 20.593094 -90.856934 24.475243 45422 20.357635 -89.558578 24.629280 45423 11.397324 -91.425659 22.054871 45424 12.406311 -91.353546 22.168182 45425 25.574860 -91.626450 23.935661 45426 26.678169 -90.700745 24.383797 45427 25.148727 -91.472656 25.341827 45428 15.795166 -92.763474 23.153786 45429 15.305840 -92.654541 22.945412 45430 19.112358 -91.937149 23.357353 45431 24.132545 -92.218399 24.494270 45432 15.487762 -93.402496 22.836510 45433 22.796310 -92.829422 24.486931 45434 19.401672 -93.450867 23.390198 45435 20.607620 -93.551361 23.387787 45436 18.466080 -93.605072 23.192635 45437 17.403946 -93.614212 23.083664 45438 6.449684 59.343750 34.380005 45439 5.688889 59.479721 34.150879 45440 5.179573 59.339264 33.688461 45441 7.384468 59.514084 33.423721 45442 8.944000 58.560059 33.803642 45443 7.696670 58.848907 34.719620 45444 10.256531 57.684143 33.433800 45445 9.973778 57.975311 34.833488 45446 11.026260 57.554596 34.337173 45447 12.322845 57.173218 34.704155 45448 13.274582 56.094635 34.126808 45449 4.831925 55.593903 34.273026 45450 4.519196 54.406830 34.000076 45451 14.924805 54.145721 34.736862 45452 14.333473 55.690125 34.982040 45453 4.294441 48.648285 33.180771 45454 4.254753 48.665100 34.198784 45455 15.989380 49.284912 33.565033 45456 14.887054 50.546158 33.739700 45457 15.479446 50.893188 34.465294 45458 15.127640 51.469574 34.322838 45459 27.480362 47.588028 33.179161 45460 5.921333 47.071869 33.052094 45461 24.416077 48.628204 34.744431 45462 27.309540 46.512451 33.409882 45463 33.052078 47.006561 32.951080 45464 34.696472 46.138931 33.235535 45465 6.952347 46.526855 32.942329 45466 8.059189 45.948364 32.816246 45467 22.513817 46.390961 33.244263 45468 32.970612 46.425644 33.098099 45469 33.795303 45.769928 33.484543 45470 34.787323 45.407104 33.630562 45471 35.329872 45.478424 33.347649 45472 9.014083 44.910080 33.642502 45473 7.543144 46.065643 34.104019 45474 8.615913 45.553375 34.981628 45475 26.717300 44.630814 33.281479 45476 27.029480 45.292999 33.418869 45477 32.902451 45.822617 33.204063 45478 9.199585 45.077057 34.751785 45479 17.871094 44.240479 32.855392 45480 35.921310 43.738113 33.571831 45481 35.350258 44.812408 33.638245 45482 17.508896 43.788651 33.974205 45483 32.968689 43.738068 33.062607 45484 33.168549 42.648773 32.992622 45485 34.406906 44.226608 33.717941 45486 33.936272 43.093338 33.590736 45487 33.912155 42.348892 33.426315 45488 36.912392 42.273727 33.598419 45489 27.725861 41.379074 33.168961 45490 27.797058 40.939957 32.653099 45491 33.107498 40.373474 32.666916 45492 35.646912 40.194992 33.987587 45493 34.068359 40.103363 33.231071 45494 7.484154 41.047272 33.484383 45495 8.524261 41.206589 32.471649 45496 16.895035 40.948547 33.653320 45497 29.811600 40.434921 33.107719 45498 30.675095 40.134430 33.112801 45499 37.981941 41.333572 33.482193 45500 21.894272 39.062561 32.596008 45501 31.981691 39.677612 33.082397 45502 31.359085 40.026199 34.154282 45503 33.175629 39.638443 33.046700 45504 32.172226 39.336716 34.120117 45505 34.522591 39.129028 34.001900 45506 33.027840 39.077118 33.830475 45507 4.718948 39.828079 33.847496 45508 4.441811 40.012634 35.173035 45509 4.090973 39.559952 34.843948 45510 17.537704 38.251953 32.930969 45511 17.256668 38.928543 33.003525 45512 22.391983 39.681412 33.641281 45513 22.573059 37.987167 32.463264 45514 40.248474 38.782532 33.283485 45515 40.221008 37.508545 33.470390 45516 40.066620 38.170105 34.382492 45517 19.036423 36.665100 33.042549 45518 23.821159 37.753616 33.540787 45519 23.403481 37.111008 32.439095 45520 40.199615 37.315720 34.475235 45521 39.530075 36.231720 34.667336 45522 24.570328 34.304138 33.046181 45523 25.110886 35.884109 33.396873 45524 38.675941 35.730515 33.156075 45525 37.892838 35.016449 33.190598 45526 38.338303 35.079041 34.103760 45527 4.151680 36.078308 33.002502 45528 4.034538 35.134644 31.795092 45529 6.195610 34.178253 32.087997 45530 5.265282 35.084106 32.649666 45531 25.288101 35.027573 34.768936 45532 20.260139 33.684845 32.943466 45533 35.804085 33.944962 32.535858 45534 34.692017 33.326691 32.996124 45535 35.990921 33.641541 33.738800 45536 43.418625 32.920166 32.769730 45537 19.961121 34.983566 35.304359 45538 19.925568 36.294800 35.432617 45539 19.963120 35.828903 34.722801 45540 33.250748 32.880341 33.182228 45541 33.102829 33.262894 34.668243 45542 33.994293 33.270615 34.300789 45543 42.381165 32.530212 33.445305 45544 44.428101 32.509598 32.715485 45545 6.403832 30.364105 32.848274 45546 7.063202 30.751938 32.248550 45547 7.057083 31.945236 33.274010 45548 21.247543 31.769165 32.339188 45549 22.088280 31.447845 32.776993 45550 22.124985 30.521469 34.245110 45551 21.107719 29.593185 33.693138 45552 20.956024 30.864655 33.122940 45553 23.142715 32.189285 32.974373 45554 30.353920 31.207382 32.322853 45555 30.677078 31.544479 32.483307 45556 38.964325 30.260712 33.848091 45557 40.781158 31.337616 34.255081 45558 39.521294 29.621826 34.884056 45559 7.762252 30.454498 31.505930 45560 19.788208 32.516922 33.536850 45561 19.800308 31.349777 33.530830 45562 19.145203 32.368408 34.600899 45563 30.084496 30.593567 32.502663 45564 37.418930 30.000427 32.165077 45565 38.774109 29.483978 34.411636 45566 44.120743 29.535110 33.612900 45567 44.572754 30.223267 33.659691 45568 44.677155 30.943451 33.854645 45569 44.956299 30.854050 33.054886 45570 7.879303 28.366180 32.113190 45571 7.141220 29.500000 32.185623 45572 36.822922 29.159851 32.124504 45573 31.096130 28.717331 33.380981 45574 43.469437 28.686234 33.150887 45575 34.878006 26.208252 31.455912 45576 37.330887 28.139862 33.276398 45577 36.625870 26.652679 32.996933 45578 35.592194 26.017273 32.184982 45579 42.743103 26.903305 33.124100 45580 47.756561 25.231262 34.568253 45581 3.185906 23.286896 31.061914 45582 35.445862 24.191010 32.275345 45583 34.789688 23.851013 31.557741 45584 35.438614 24.926575 32.345123 45585 44.565521 25.684570 32.774857 45586 2.886322 22.474686 31.462564 45587 27.924965 22.787842 31.404459 45588 35.680267 23.363144 31.841639 45589 36.400253 23.803680 32.669228 45590 6.701019 21.108109 32.037933 45591 5.529610 21.865036 32.286125 45592 11.725410 22.637192 31.217821 45593 11.512741 22.768051 32.563683 45594 11.588729 22.322815 33.500282 45595 11.734932 21.421051 33.160690 45596 10.608292 19.962616 31.032686 45597 28.734993 22.662933 32.530266 45598 40.708862 21.787842 32.792534 45599 41.878815 21.293671 32.345131 45600 43.356369 22.124344 33.735710 45601 41.724396 22.370728 33.802040 45602 44.657944 22.058868 33.842247 45603 46.171387 21.364990 32.663666 45604 47.493668 21.466675 32.692001 45605 49.505280 22.471207 33.861809 45606 49.859604 22.039261 32.868530 45607 50.272552 22.179184 32.147247 45608 9.960388 18.976395 31.436304 45609 30.095627 21.499115 32.699287 45610 31.807642 20.799332 33.037086 45611 32.688965 19.588684 31.936899 45612 45.258209 21.458878 32.875381 45613 3.545563 19.572464 32.971329 45614 11.659836 18.692078 32.759773 45615 33.966415 19.362732 32.305008 45616 35.237343 18.821136 32.660088 45617 3.161545 20.670532 32.324135 45618 10.525024 16.920700 32.187683 45619 10.168015 16.836380 32.143272 45620 9.886871 17.496292 32.183167 45621 52.328094 17.779999 32.194031 45622 53.563644 17.865845 32.825829 45623 53.070831 17.765823 33.272202 45624 54.471207 17.424866 32.277100 45625 3.191902 16.871704 32.758270 45626 55.421997 16.345123 32.422813 45627 54.923416 16.853546 33.018204 45628 2.904801 14.630722 30.892344 45629 3.163269 15.722046 31.804148 45630 35.827591 16.623901 32.144424 45631 36.134178 17.112823 31.990839 45632 36.469864 17.002686 32.239166 45633 43.919022 16.705780 32.834747 45634 43.669617 16.282776 33.589813 45635 47.791382 17.046753 33.371964 45636 49.559708 17.134598 34.336136 45637 48.477081 17.114410 34.421097 45638 52.105103 17.572601 33.431854 45639 42.267822 15.064880 33.189880 45640 41.292206 14.409698 33.215614 45641 2.663185 13.643799 30.550676 45642 3.035050 13.176224 31.766092 45643 27.897812 14.170502 32.027031 45644 28.013458 13.668793 31.090403 45645 27.200333 12.921494 32.223755 45646 2.825996 11.855026 31.604715 45647 27.972549 10.921143 31.780993 45648 37.562775 13.384018 31.557665 45649 40.768097 14.292465 32.118515 45650 55.130112 13.463074 32.437164 45651 54.099319 12.491608 32.143105 45652 55.610077 13.933914 31.556864 45653 32.544189 11.861374 31.341562 45654 33.963989 12.300415 31.530252 45655 29.880447 10.354248 32.287056 45656 2.749054 9.139984 31.211275 45657 42.847900 9.765427 32.063881 45658 43.547913 10.312180 32.061005 45659 44.608612 10.719421 32.409790 45660 3.546715 8.880157 30.430315 45661 4.556397 7.994629 30.222292 45662 5.107994 9.026154 29.582901 45663 45.678467 8.433716 30.602106 45664 51.225708 10.297485 32.487495 45665 3.651077 8.009613 30.693804 45666 3.113144 8.182816 30.991991 45667 46.465088 10.510056 32.647758 45668 46.741272 9.645645 31.929621 45669 4.921173 6.600723 30.724047 45670 46.484695 8.823181 31.180635 45671 47.645187 8.602966 31.287676 45672 50.355042 11.309387 34.369293 45673 5.511704 5.851547 30.432878 45674 37.412643 5.988815 31.994387 45675 38.217842 6.410980 32.419327 45676 38.306213 6.603027 31.445162 45677 56.204254 6.567932 35.374535 45678 55.056686 7.014984 35.591202 45679 55.330414 6.609207 34.433151 45680 57.982452 6.014847 32.948250 45681 57.666992 6.408234 31.968744 45682 5.485245 4.977119 30.244028 45683 36.363693 5.197754 31.416986 45684 35.714371 4.666214 31.233980 45685 56.461044 6.471313 32.563843 45686 2.980016 1.866976 24.277836 45687 4.432816 3.685734 28.631742 45688 3.764921 2.857139 26.692032 45689 54.079620 5.762657 33.097435 45690 3.070279 0.160947 25.053074 45691 2.820132 0.066540 24.014162 45692 3.083378 1.002190 24.880457 45693 3.474887 1.571527 26.130682 45694 3.852042 1.889136 27.251219 45695 4.509328 2.623475 29.015327 45696 4.181740 1.879275 28.228004 45697 4.761941 1.860649 29.699202 45698 5.492088 2.829605 30.553217 45699 51.700897 3.893677 31.206064 45700 52.096802 4.395790 32.244995 45701 3.378858 0.102472 26.143244 45702 3.673656 0.721858 26.985224 45703 4.362785 0.624661 28.980494 45704 34.970520 0.725220 30.793528 45705 49.694839 3.801453 32.352272 45706 3.980031 0.831549 27.879541 45707 5.224297 1.678848 30.721926 45708 4.801852 1.112622 29.948069 45709 38.295937 1.432877 30.702868 45710 36.749084 0.604095 30.932032 45711 37.919586 0.867188 31.861460 45712 36.709579 0.079315 31.698946 45713 39.842857 1.701324 31.264444 45714 40.172882 2.126450 32.698250 45715 39.158211 1.600464 32.221436 45716 46.163498 2.235596 30.965525 45717 44.459808 2.783524 31.995852 45718 44.246490 1.764511 30.991739 45719 58.644165 1.486816 31.380167 45720 34.105766 -0.064880 31.715334 45721 33.194122 0.547363 31.959063 45722 33.833046 0.696976 31.524721 45723 58.537018 0.578522 30.775316 45724 34.454849 0.649033 31.166346 45725 35.485619 -0.048492 31.617693 45726 57.281265 -0.949753 30.659365 45727 55.136017 -1.581085 31.024820 45728 49.516022 -2.896652 31.251062 45729 50.562408 -2.479691 31.562502 45730 3.125424 -5.634563 25.855841 45731 46.287964 -4.018951 31.773607 45732 3.022675 -4.541753 25.462420 45733 45.106750 -6.136047 30.952524 45734 44.607285 -5.719589 31.755915 45735 45.182281 -5.212418 31.611444 45736 53.488190 -5.796494 30.850611 45737 54.428665 -5.803497 30.652910 45738 59.674286 -6.017395 30.899973 45739 60.085983 -6.292740 30.901880 45740 56.670319 -5.035461 31.529139 45741 45.314636 -8.820221 31.887423 45742 44.281921 -8.938828 31.772974 45743 44.266891 -7.792297 31.630144 45744 60.990631 -8.393951 31.101725 45745 49.307968 -12.194336 30.294924 45746 55.320084 -11.154938 31.862123 45747 55.890259 -11.656540 31.317614 45748 58.177185 -12.613785 30.968752 45749 61.440445 -11.743759 30.812616 45750 61.894608 -12.598969 30.062265 45751 61.567551 -12.869873 30.407434 45752 47.568329 -14.797699 30.616022 45753 49.781357 -16.139053 29.567863 45754 49.112396 -15.907745 29.769915 45755 48.432663 -15.497589 30.016275 45756 51.703979 -15.634583 29.598206 45757 51.007278 -15.952530 29.666048 45758 50.321503 -15.762177 29.538406 45759 49.194641 -16.783524 29.737169 45760 48.658203 -16.270432 30.047915 45761 49.890533 -16.802490 29.487602 45762 56.939301 -16.973160 29.989588 45763 55.719269 -17.122162 30.268587 45764 59.271805 -17.801987 29.990870 45765 59.779449 -18.268814 30.495600 45766 59.094543 -18.454102 30.705774 45767 53.492126 -18.599304 29.781954 45768 54.601959 -19.078690 30.039682 45769 48.627625 -19.999084 30.530558 45770 48.034714 -16.495193 30.581621 45771 48.583618 -16.898285 30.109705 45772 46.337433 -22.915924 29.470871 45773 58.304993 -19.610901 30.514589 45774 59.391083 -21.145081 29.918703 45775 60.550858 -20.513275 30.219179 45776 60.324020 -21.454620 29.875589 45777 60.195831 -22.382568 29.442276 45778 61.558441 -20.474030 29.924006 45779 61.430664 -23.107437 28.985168 45780 46.513702 -23.801575 29.550232 45781 60.463516 -26.587280 29.303383 45782 59.248291 -25.566940 28.998207 45783 45.916733 -24.166702 31.116068 45784 45.082367 -24.151672 32.196251 45785 44.479691 -23.155106 31.418055 45786 53.163818 -24.569489 29.448730 45787 48.931610 -24.534744 29.453766 45788 49.823151 -24.538956 29.956530 45789 53.895935 -24.762833 29.414024 45790 55.645905 -25.291656 30.360216 45791 61.647980 -26.738617 29.171867 45792 61.288055 -27.459442 29.618166 45793 61.313812 -28.344635 30.087626 45794 60.217270 -27.604034 29.909060 45795 58.921951 -26.718445 29.618494 45796 58.238373 -26.989182 30.304354 45797 60.206833 -28.215164 30.798563 45798 59.831299 -28.126144 31.270098 45799 59.337982 -27.725616 31.277445 45800 59.107254 -27.512619 30.438631 45801 62.392899 -27.327713 29.003281 45802 62.329575 -29.227142 29.481834 45803 62.090515 -28.021194 29.431519 45804 62.283310 -31.240677 29.974085 45805 4.830961 -29.598749 26.152847 45806 59.896271 -34.373947 30.518076 45807 61.436722 -33.513641 29.213150 45808 49.704361 -34.877625 28.850456 45809 5.307428 -32.644608 25.971573 45810 5.452658 -33.434116 25.798107 45811 5.921891 -34.037823 26.598604 45812 6.235775 -35.194000 26.524181 45813 43.242798 -36.519806 28.622749 45814 43.828796 -35.354340 28.531273 45815 48.420837 -34.547089 29.178177 45816 49.363968 -34.507141 29.876627 45817 53.099365 -35.060089 29.221222 45818 51.744232 -34.891464 29.458191 45819 53.973724 -34.978302 30.588373 45820 54.992096 -35.132996 30.262804 45821 56.667999 -35.004272 29.554031 45822 57.620758 -34.909317 29.947107 45823 42.742645 -36.971039 28.200836 45824 44.031601 -38.092987 28.214516 45825 6.665779 -35.938427 26.956556 45826 44.358932 -37.624039 29.122787 45827 47.148651 -38.753021 27.780716 45828 52.850281 -39.065643 28.432625 45829 53.452103 -38.916656 28.490974 45830 52.088852 -39.110306 29.115631 45831 51.244308 -39.181244 29.005066 45832 50.434479 -39.080353 29.514786 45833 57.497040 -39.869049 28.293427 45834 57.498459 -40.240402 29.342117 45835 58.459717 -41.330719 29.723902 45836 8.708519 -42.748947 27.958817 45837 9.017799 -41.910904 29.105682 45838 22.618116 -40.803772 29.159178 45839 59.044189 -41.910614 29.299927 45840 5.360306 -44.818359 26.725906 45841 8.003113 -43.469772 27.434624 45842 42.663300 -44.418243 28.335197 45843 42.820160 -45.094925 28.150162 45844 44.496399 -43.373978 28.438744 45845 46.646927 -43.240845 29.918093 45846 47.333984 -43.457779 30.198389 45847 47.048172 -43.553864 29.068748 45848 47.625275 -43.996536 28.196655 45849 59.403244 -42.655106 29.461838 45850 5.335610 -44.725479 27.760277 45851 42.755920 -45.578445 28.785034 45852 50.671783 -45.118652 28.241516 45853 52.380737 -46.096359 27.787796 45854 59.347748 -44.396042 30.171679 45855 42.942581 -46.080109 29.930010 45856 44.484741 -46.648438 28.993256 45857 44.393188 -46.742844 30.164743 45858 43.345062 -46.117889 28.835251 45859 48.739578 -48.059021 30.585726 45860 48.166550 -47.829514 30.615236 45861 48.485977 -48.213516 29.712168 45862 45.084183 -47.084366 27.652985 45863 54.517670 -46.422440 28.957809 45864 56.023453 -46.961014 29.327560 45865 55.980194 -47.279510 28.215714 45866 59.210861 -45.492050 30.026125 45867 58.496307 -46.476898 30.059931 45868 46.529480 -48.045090 27.604530 45869 50.328918 -48.846375 29.837061 45870 49.519379 -48.498123 30.443300 45871 49.727158 -49.113785 28.863998 45872 47.672546 -48.518616 27.908806 45873 4.485634 -46.817612 27.957718 45874 48.569489 -49.064987 27.712761 45875 5.670517 -50.854416 27.221283 45876 4.734169 -50.878906 27.573372 45877 9.474426 -50.776245 27.278732 45878 10.086838 -52.817810 27.236504 45879 38.048172 -50.883865 28.352325 45880 39.019012 -50.781281 28.803513 45881 50.544083 -49.107498 29.341667 45882 51.256271 -49.633621 29.049789 45883 52.902344 -50.373535 28.938454 45884 40.646271 -51.331879 30.291201 45885 41.328827 -51.271301 29.621447 45886 40.327682 -50.967987 29.239082 45887 37.232437 -52.631332 27.352638 45888 56.604401 -52.741516 28.807961 45889 37.074036 -52.575165 28.174194 45890 54.610016 -51.218842 28.795609 45891 10.038010 -55.102966 28.116425 45892 10.061462 -55.918060 27.421837 45893 9.192635 -55.833618 26.416061 45894 39.352081 -55.053253 27.849495 45895 40.336853 -55.795227 28.340546 45896 9.793030 -56.877335 27.082596 45897 9.033676 -57.366837 26.648941 45898 40.972427 -55.672806 27.453255 45899 40.806503 -55.641983 27.761253 45900 41.194397 -56.042801 27.173645 45901 41.395752 -55.995911 27.888016 45902 56.894958 -55.102295 27.597557 45903 8.156342 -58.128448 26.273415 45904 42.105042 -56.685211 28.204239 45905 41.481155 -56.527420 28.732246 45906 42.046417 -56.742081 27.270554 45907 42.660980 -57.187637 27.984734 45908 43.099030 -57.713776 27.217850 45909 48.723526 -55.763947 27.479439 45910 49.570267 -56.365234 27.174492 45911 7.625488 -59.166016 26.423286 45912 8.942506 -58.608383 26.967743 45913 50.628159 -56.916061 27.154709 45914 55.457321 -57.001282 27.814140 45915 56.194153 -56.330002 28.053795 45916 6.442253 -59.778992 25.996796 45917 8.351921 -58.897125 26.660179 45918 43.222244 -57.840378 28.225281 45919 53.059235 -58.019470 27.441582 45920 21.567001 -59.558350 27.858345 45921 45.687744 -59.392502 27.042007 45922 46.678131 -59.447601 28.048752 45923 47.458160 -60.145462 27.013054 45924 54.155548 -57.052719 28.419724 45925 5.566292 -60.903214 25.753815 45926 6.334175 -60.930679 26.834602 45927 5.488793 -61.845001 26.909714 45928 23.035095 -60.433670 27.451309 45929 48.750473 -60.456039 28.178146 45930 49.650604 -60.882996 28.831985 45931 48.877563 -60.781311 29.247704 45932 19.395607 -61.594376 26.424255 45933 47.668060 -59.914185 28.204422 45934 47.125244 -59.717712 28.817276 45935 49.102722 -60.898102 27.020744 45936 51.292633 -62.180878 28.834763 45937 50.730942 -61.786423 29.632517 45938 50.431244 -61.337021 29.012901 45939 4.722290 -63.121078 26.631561 45940 16.899429 -63.012894 26.618828 45941 15.608765 -63.367416 26.894142 45942 15.232712 -64.512619 26.276169 45943 46.093369 -66.533081 26.617027 45944 51.822998 -63.137039 28.243980 45945 52.006439 -63.059494 27.633148 45946 8.724487 -66.356110 25.267761 45947 8.715851 -66.920624 25.852379 45948 6.548470 -68.661469 26.480713 45949 7.434120 -68.813263 27.428970 45950 7.687400 -68.192444 26.801933 45951 9.657211 -67.893341 26.837402 45952 13.891328 -65.662933 26.410416 45953 14.362197 -63.382263 27.599335 45954 35.945129 -66.861099 26.738533 45955 43.942596 -67.027008 26.506821 45956 44.972412 -66.275330 26.301331 45957 47.106171 -66.260742 26.551315 45958 49.248779 -66.171387 27.196060 45959 50.312592 -65.655426 28.254768 45960 50.769928 -64.960968 27.109039 45961 12.356873 -67.146317 26.370987 45962 13.018013 -66.670700 26.768875 45963 42.444687 -67.485275 26.603951 45964 42.171875 -68.947678 27.907654 45965 43.613892 -68.146255 27.170280 45966 43.196899 -66.584991 26.017448 45967 4.704186 -64.086594 27.712021 45968 34.449829 -69.481308 26.372665 45969 34.947876 -68.633286 27.443024 45970 28.334503 -69.558426 26.122963 45971 27.485870 -69.418732 25.931915 45972 16.919006 -69.826202 26.551865 45973 33.928719 -71.042618 27.653946 45974 34.524132 -70.159256 28.351913 45975 34.089325 -70.070999 27.228775 45976 5.843208 -72.857300 25.316353 45977 26.613457 -69.760376 26.784157 45978 28.897797 -70.435287 26.088860 45979 29.224106 -71.561020 26.047348 45980 34.424149 -70.818787 25.901108 45981 8.257729 -73.907669 27.218781 45982 11.442841 -72.576859 25.015343 45983 34.054626 -70.960083 26.573288 45984 40.861588 -72.303955 26.037666 45985 11.817123 -76.487839 25.684601 45986 33.853104 -72.094955 27.103951 45987 33.909836 -73.255783 26.662468 45988 33.972275 -74.277420 26.414879 45989 37.895729 -73.702911 26.715034 45990 37.658737 -73.821609 25.842041 45991 43.823990 -73.714600 26.032990 45992 44.540192 -74.894608 25.788696 45993 16.157387 -78.261185 26.232506 45994 33.935425 -75.104340 27.096832 45995 43.839630 -74.325272 26.346886 45996 4.935471 -76.051239 26.217773 45997 9.640610 -75.416611 27.388977 45998 10.409096 -74.251755 26.266724 45999 43.824158 -76.274521 25.927177 46000 44.194031 -75.580063 25.953842 46001 5.329155 -77.725372 26.000725 46002 29.862610 -78.778107 25.703354 46003 29.661446 -77.374069 26.316383 46004 34.301193 -76.301697 26.593758 46005 11.147629 -78.242294 26.908234 46006 10.258675 -77.077759 27.407852 46007 12.737617 -78.732635 25.806793 46008 25.325256 -78.154007 26.541458 46009 24.449066 -78.399811 25.668518 46010 34.298592 -77.626480 26.394623 46011 38.458809 -78.639679 25.967834 46012 38.277412 -79.200928 24.835182 46013 14.129097 -79.774384 25.746552 46014 13.031921 -80.216400 26.802185 46015 24.362083 -78.805832 26.088860 46016 30.230400 -79.734589 25.364311 46017 42.988953 -77.466537 26.346977 46018 15.265091 -79.653809 25.406654 46019 20.868073 -80.247589 25.537025 46020 41.622437 -79.729889 26.337822 46021 42.180695 -78.711700 26.506233 46022 6.771896 -80.646912 24.804405 46023 9.548363 -85.144089 24.980850 46024 30.304077 -79.816132 26.252792 46025 31.277969 -80.848083 26.698822 46026 31.462502 -80.844757 25.676430 46027 23.708038 -82.467880 25.662125 46028 26.041565 -82.235947 25.005333 46029 31.886621 -80.814224 25.829636 46030 7.966171 -81.877640 25.065422 46031 11.553093 -86.791245 24.917046 46032 12.644966 -86.689255 24.595886 46033 20.370911 -81.010101 26.032043 46034 20.762405 -82.024368 25.922951 46035 22.922470 -82.807251 26.406776 46036 27.311508 -83.516724 25.244438 46037 35.415726 -82.764359 25.430870 46038 8.984711 -85.816849 25.649475 46039 9.448196 -85.963058 25.209030 46040 34.081932 -83.825439 25.213554 46041 33.837029 -84.720612 25.406075 46042 35.116791 -83.862930 26.063301 46043 10.574562 -85.786697 24.703583 46044 9.869873 -86.833710 25.669014 46045 8.320839 -84.800079 26.402786 46046 8.643646 -86.131332 26.458000 46047 27.189331 -84.931839 25.122276 46048 36.850533 -84.390915 25.968437 46049 37.534286 -84.412613 25.494446 46050 13.615204 -87.094299 24.439972 46051 25.006592 -86.447113 24.469757 46052 24.730301 -86.769241 24.631912 46053 34.870529 -84.911362 25.688126 46054 35.990860 -85.168365 25.424484 46055 26.510651 -87.442749 26.273941 46056 26.504669 -86.702621 26.596184 46057 33.215408 -87.050095 24.207161 46058 19.871132 -88.974808 24.352364 46059 16.329605 -88.919739 24.806305 46060 18.201820 -89.184311 24.839188 46061 17.503387 -89.743546 25.343048 46062 18.931007 -89.735641 25.732460 46063 18.905243 -92.792664 23.512444 46064 19.976608 -92.339584 23.751953 46065 21.151520 -91.526627 25.256783 46066 21.223022 -92.508530 24.492531 46067 22.042038 -92.925339 24.483742 46068 5.790611 58.722916 34.703468 46069 6.711693 58.798523 35.126556 46070 8.888855 58.458801 34.866943 46071 8.282516 58.444244 35.376907 46072 9.112740 58.048630 35.529953 46073 5.178597 57.388580 34.513321 46074 9.922470 57.682983 35.909439 46075 13.388046 57.002319 35.201607 46076 12.908187 57.402405 35.097160 46077 11.027664 57.486008 35.838509 46078 15.217300 52.710526 34.578125 46079 4.967873 52.354156 34.404396 46080 5.124481 51.483963 34.746887 46081 4.293297 50.119202 34.424118 46082 17.306625 48.651062 33.914040 46083 17.330811 50.038330 34.758881 46084 26.320724 49.399643 33.646408 46085 25.547470 49.052551 34.473251 46086 26.712692 48.612213 34.506065 46087 17.906036 47.708466 34.080322 46088 26.219421 48.596420 35.434135 46089 18.252022 48.845001 34.790054 46090 18.646744 48.012451 35.169052 46091 27.321442 47.508224 34.232628 46092 18.259964 46.706619 35.018761 46093 22.861618 46.810669 34.180061 46094 22.403679 45.809555 33.891281 46095 27.238579 44.361572 33.998032 46096 27.877029 45.604965 34.772507 46097 5.358215 47.338135 34.260010 46098 6.313019 46.613953 33.838089 46099 32.901382 44.970032 33.083069 46100 16.859154 43.019592 35.138351 46101 17.241165 43.969696 34.971260 46102 27.298553 43.208954 33.790634 46103 34.507645 43.211853 33.934929 46104 35.030121 43.242172 34.030846 46105 9.067474 42.794983 34.683502 46106 34.681656 42.453293 33.828461 46107 35.697678 41.620605 33.971848 46108 5.948181 40.630936 33.745415 46109 8.724480 41.463348 33.332863 46110 8.480072 41.835800 34.215866 46111 16.854744 39.841721 33.685616 46112 22.296356 41.457245 35.322090 46113 38.391190 40.224243 33.845749 46114 6.251312 41.222382 34.534592 46115 7.242500 41.854248 34.814438 46116 17.385544 38.885712 35.307396 46117 17.840652 39.313705 36.647789 46118 16.671555 39.680145 35.352791 46119 30.214973 41.045181 34.312943 46120 35.663010 39.219360 34.220108 46121 36.509613 39.209579 34.455872 46122 37.951416 38.909439 34.819328 46123 37.218361 39.955917 34.324493 46124 37.100845 40.981995 34.041199 46125 17.308075 38.669983 34.004898 46126 33.734085 38.637329 34.722893 46127 34.783508 38.444427 35.127785 46128 35.841492 38.576553 34.845512 46129 17.980804 37.640869 33.922295 46130 18.306793 37.126343 33.389435 46131 24.726097 36.869171 33.597717 46132 5.155838 36.372559 33.846886 46133 6.158478 35.419678 33.465469 46134 6.418808 34.677399 32.909569 46135 19.551880 36.554230 34.561058 46136 18.719940 37.259979 34.369583 46137 19.685867 33.636948 34.332268 46138 19.844437 35.264740 33.839470 46139 25.636124 36.069473 34.242905 46140 7.289330 33.944473 32.770538 46141 7.477608 32.938202 32.576706 46142 8.020706 34.421860 34.110878 46143 7.773727 34.132248 33.366623 46144 7.267655 34.916779 33.556213 46145 37.232956 34.224243 34.557098 46146 37.656517 34.655487 33.711983 46147 7.719558 33.384094 33.372681 46148 26.021576 36.204163 35.139511 46149 20.466934 32.132996 32.820236 46150 23.822891 32.951187 33.377831 46151 23.872948 33.213303 35.038887 46152 23.267357 32.247620 34.133186 46153 31.226822 32.319153 34.128876 46154 30.497467 31.396957 33.279381 46155 35.089348 33.519241 34.743690 46156 36.105804 33.668976 34.707024 46157 43.542969 32.421982 33.665573 46158 44.489990 31.746338 33.592712 46159 5.258186 29.993622 33.713684 46160 5.760079 29.753326 33.240891 46161 5.661476 31.034836 34.102394 46162 6.565254 32.202103 34.640358 46163 7.635757 33.173325 34.487167 46164 18.736893 30.952820 34.727188 46165 20.012024 30.200180 33.624489 46166 32.222412 32.943344 34.331680 46167 44.359039 31.390320 34.335144 46168 43.842422 31.878555 34.338516 46169 42.641647 31.919495 34.579941 46170 6.382515 29.320068 32.688240 46171 6.127647 28.695908 33.106400 46172 30.333038 30.565247 33.861458 46173 30.742722 29.818466 34.017761 46174 31.511749 27.766205 33.438560 46175 37.475601 29.404953 32.915703 46176 38.472778 29.436966 34.134720 46177 38.058609 29.353592 33.623344 46178 6.950775 28.458832 32.619896 46179 42.806885 27.761292 33.154083 46180 43.645508 29.112976 34.386864 46181 7.841781 26.914886 33.273376 46182 7.907211 27.172592 32.855652 46183 6.789711 27.459427 33.484276 46184 7.632522 27.710052 32.600723 46185 30.358002 25.671829 33.061836 46186 31.431442 26.689972 33.636467 46187 31.941034 28.468964 33.986900 46188 31.828081 29.508987 34.720978 46189 43.405945 28.458542 34.477577 46190 8.007080 26.420868 33.729187 46191 8.760170 26.547684 32.844109 46192 9.226067 25.551819 33.551414 46193 9.903717 25.554626 32.534004 46194 36.486664 25.042526 33.038254 46195 10.415634 24.330902 33.316032 46196 28.822403 23.531464 33.009254 46197 37.957993 24.743027 33.991089 46198 38.017105 23.552338 33.354698 46199 37.151154 24.053467 33.275063 46200 3.522568 22.434479 31.938562 46201 37.194214 23.402039 32.817474 46202 50.113220 23.146622 33.881348 46203 49.909790 23.909851 34.045921 46204 29.220688 23.486359 33.401596 46205 39.299454 22.610367 33.091377 46206 45.487946 22.263397 34.148727 46207 46.476288 22.238358 34.202507 46208 47.395920 22.300674 34.367645 46209 48.402832 22.124298 33.895706 46210 11.654404 19.102783 34.118874 46211 30.658569 21.926697 33.538033 46212 9.015388 18.702332 31.967829 46213 34.247086 20.229965 33.841393 46214 33.369980 20.036240 32.917290 46215 34.421631 19.603455 33.029564 46216 36.793777 17.621841 32.847221 46217 8.346329 17.565125 32.907127 46218 9.144424 15.745728 33.096840 46219 11.131134 17.610260 32.443306 46220 11.612534 15.771133 34.766350 46221 11.317642 15.205200 34.858238 46222 11.470909 15.886353 34.042175 46223 36.896805 19.003021 33.932602 46224 36.296349 19.745605 34.599937 46225 35.373665 19.608810 33.778412 46226 10.952911 16.659927 32.552368 46227 45.718750 17.066864 34.668922 46228 47.070801 17.224854 34.456131 46229 54.058136 17.404282 33.342506 46230 10.245392 16.305862 32.507683 46231 35.439491 16.165344 32.743149 46232 36.122757 16.438721 32.710533 46233 36.613594 16.776947 32.739189 46234 43.085373 15.611969 33.762276 46235 51.052612 17.307632 34.456245 46236 55.211166 16.249481 33.113953 46237 3.242951 14.578857 32.280586 46238 29.376205 15.008545 32.032639 46239 28.344894 14.525757 33.096367 46240 31.541374 15.432800 33.077133 46241 34.536827 15.892441 33.670631 46242 42.343262 14.949585 34.459229 46243 55.280792 15.452332 33.225655 46244 27.229416 13.744415 32.606781 46245 27.536591 14.055527 32.953949 46246 55.511948 14.356079 32.676392 46247 38.418472 13.391647 34.434921 46248 39.750320 13.756561 34.777931 46249 55.146606 13.857330 33.538139 46250 33.329384 11.889740 32.434593 46251 33.397751 11.669815 33.495102 46252 53.065094 11.480606 32.806870 46253 53.069183 11.784607 33.649956 46254 53.624054 12.086426 33.399048 46255 54.689728 13.341934 33.603661 46256 2.703438 9.834106 32.073547 46257 26.907883 11.214264 32.234520 46258 26.969368 10.194077 32.241913 46259 26.550446 10.316406 32.554779 46260 26.187531 11.562469 33.030853 46261 26.455872 12.092697 33.049889 46262 31.027023 11.318039 31.733347 46263 32.207520 11.279388 32.988297 46264 54.093979 12.770050 33.746979 46265 27.730515 9.966003 32.196205 46266 29.859474 9.280029 32.816223 46267 29.361916 9.411743 32.564117 46268 45.695953 11.044632 33.238770 46269 46.670441 11.002808 33.633675 46270 47.670227 10.385727 33.095886 46271 52.287323 10.824036 32.417809 46272 43.519653 9.975662 33.446556 46273 48.262711 11.432678 34.907761 46274 49.008926 10.978897 34.061157 46275 2.723908 8.068909 31.644098 46276 42.737930 9.128693 33.424103 46277 47.262604 11.383728 34.835190 46278 3.582092 7.200745 31.325930 46279 2.816620 7.541153 32.125282 46280 3.086632 7.084229 32.478874 46281 5.227196 5.640953 31.017351 46282 39.288849 7.016205 32.765747 46283 4.385689 5.734543 31.536829 46284 5.091019 4.951233 31.385744 46285 5.499283 4.920609 30.893000 46286 35.600891 4.788177 32.389839 46287 36.505821 5.656700 32.955864 46288 55.157639 6.229889 33.063667 46289 5.463448 2.651871 31.307848 46290 52.978882 4.828140 32.361893 46291 58.459091 4.963196 32.594269 46292 34.958191 3.997055 32.251816 46293 50.897827 4.037231 32.264519 46294 51.437546 4.776627 33.500031 46295 58.618149 3.775696 32.334747 46296 34.520493 3.356888 32.120369 46297 33.805130 2.635666 32.045837 46298 34.269333 3.832970 32.710999 46299 43.007568 2.313232 31.695749 46300 43.201599 3.102722 32.504944 46301 43.764908 3.715027 33.502815 46302 46.542282 3.747650 32.864784 46303 48.449509 4.483795 33.672318 46304 3.054455 -0.605317 25.109486 46305 3.808798 -0.524317 27.634743 46306 3.311119 -1.296198 26.155443 46307 4.273575 -0.950418 29.110624 46308 3.987183 -1.715907 28.445433 46309 5.589111 1.773483 31.790049 46310 5.635376 1.501724 31.416391 46311 34.032120 1.416901 31.444498 46312 38.815742 1.437378 31.539057 46313 58.334167 2.683640 32.678741 46314 3.119999 -2.341523 25.667990 46315 2.989225 -2.002012 25.088953 46316 4.619466 -0.479588 29.948351 46317 4.913179 0.417179 30.445871 46318 5.029595 -1.614670 31.621408 46319 4.990859 -0.651580 30.972109 46320 5.425919 -0.929871 31.864229 46321 33.519211 1.350449 31.856203 46322 57.845078 0.425110 31.773088 46323 57.745605 1.639526 32.919922 46324 3.642639 -2.043359 27.426353 46325 4.328623 -2.365531 29.571886 46326 3.969634 -2.905363 28.597000 46327 55.925690 -0.018951 33.008766 46328 56.913284 0.658875 33.073242 46329 56.738434 -0.095779 32.320343 46330 56.996140 -0.584946 31.455332 46331 51.566528 -2.002548 31.936480 46332 54.102615 -1.380722 31.878962 46333 55.694748 -0.821564 31.922121 46334 49.745010 -2.047684 32.901703 46335 45.588638 -4.598724 31.961176 46336 46.921295 -3.553589 31.715685 46337 47.595520 -3.177094 31.832201 46338 48.491989 -2.561111 32.494301 46339 44.526932 -6.266602 31.184969 46340 57.662582 -4.562317 32.220863 46341 56.325211 -4.314590 32.500168 46342 56.452377 -3.663300 33.634224 46343 57.290894 -3.591888 34.711136 46344 56.291245 -3.151718 34.794693 46345 59.833740 -6.020020 31.755167 46346 44.196350 -6.498062 31.674562 46347 45.235901 -6.758911 30.628115 46348 50.436874 -6.089508 31.620729 46349 51.599731 -5.840637 31.361193 46350 51.184311 -5.603119 32.471542 46351 52.182236 -5.231262 32.456146 46352 54.026276 -5.211655 31.889803 46353 52.902588 -5.493088 31.705751 46354 55.301117 -5.091476 31.711603 46355 58.761002 -5.048279 32.289200 46356 44.796829 -6.813248 30.931505 46357 49.139557 -6.668152 31.340937 46358 49.976730 -6.219879 32.470078 46359 60.779144 -7.369843 31.569719 46360 60.481812 -6.804565 31.921495 46361 60.513275 -7.532104 32.469086 46362 44.424011 -9.372894 32.118828 46363 46.566208 -8.274414 31.966349 46364 47.664551 -7.443008 31.640825 46365 60.638489 -8.590240 32.467339 46366 43.324432 -9.256577 32.780006 46367 44.902893 -9.909058 33.044540 46368 49.103363 -12.334534 32.382759 46369 48.072327 -13.294128 32.164391 46370 48.746017 -13.786438 33.172890 46371 60.872360 -9.941208 31.840738 46372 47.658081 -13.584396 31.127390 46373 56.443649 -11.950516 31.208307 46374 57.338684 -12.027664 31.377962 46375 60.866730 -12.746964 31.227739 46376 60.880402 -11.965729 31.898546 46377 60.736328 -11.156326 32.273300 46378 47.136261 -14.317474 31.147852 46379 59.258453 -12.963577 31.242716 46380 60.117340 -13.306213 30.896364 46381 60.095306 -12.956650 31.519739 46382 47.078461 -14.905899 31.307878 46383 47.426788 -15.743805 31.430445 46384 47.211044 -15.217255 31.791193 46385 47.793854 -16.758652 31.481630 46386 54.368164 -17.648636 30.196054 46387 54.560181 -16.425461 29.935312 46388 55.909409 -18.008270 30.718828 46389 57.200775 -18.022812 30.646677 46390 58.320648 -17.664795 30.506845 46391 58.246307 -18.286774 30.799913 46392 3.581722 -13.412746 26.282017 46393 47.974152 -17.314850 30.899622 46394 55.286835 -17.800827 30.549547 46395 3.931756 -18.727316 25.796934 46396 48.016830 -17.483276 31.195330 46397 48.963806 -18.565933 31.633631 46398 55.341400 -18.520889 30.465525 46399 60.527740 -19.371994 30.440409 46400 59.929260 -18.776627 30.658678 46401 55.521759 -19.496445 30.182367 46402 56.263245 -18.986816 30.539667 46403 57.147903 -19.570023 30.383867 46404 61.308701 -19.820709 30.122927 46405 59.587051 -19.634201 30.597689 46406 46.946136 -20.926361 31.257906 46407 47.751312 -20.875656 30.540209 46408 43.992523 -23.951950 32.560959 46409 43.009323 -23.203369 32.706490 46410 45.686127 -23.510223 30.300516 46411 46.528809 -24.141922 30.192636 46412 47.981995 -24.590012 30.635042 46413 51.157837 -24.487564 30.245142 46414 52.469421 -24.436295 30.317850 46415 50.346710 -24.693207 31.292055 46416 51.732849 -24.499268 31.263170 46417 53.882370 -24.741333 30.375727 46418 57.638321 -26.431519 30.776270 46419 61.907455 -27.377914 29.431870 46420 4.939889 -28.185575 26.999678 46421 5.040727 -30.060484 26.595249 46422 61.635376 -29.148941 31.369509 46423 5.074941 -31.131817 26.218277 46424 5.276202 -31.520288 26.650888 46425 5.279029 -31.993805 26.364798 46426 46.138367 -34.212616 29.972033 46427 45.291290 -34.471405 30.079355 46428 48.919495 -34.147232 31.084330 46429 47.347214 -34.202301 30.085955 46430 61.983337 -32.965210 29.889124 46431 61.156876 -33.852280 30.110178 46432 61.846878 -32.999634 31.010584 46433 61.245758 -33.685303 31.849245 46434 61.601059 -32.946686 32.104874 46435 5.542629 -32.579544 26.683083 46436 5.643508 -33.207146 26.505693 46437 5.949072 -32.968781 27.323050 46438 44.357803 -35.526825 29.914431 46439 50.470276 -34.651062 30.164064 46440 52.265320 -34.585205 31.179697 46441 55.746155 -34.965729 30.637987 46442 56.676392 -34.651840 30.962351 46443 57.656342 -34.505707 31.185862 46444 58.746872 -34.426987 31.227991 46445 58.227905 -34.864853 30.375750 46446 45.250488 -37.219727 30.901621 46447 44.315659 -36.630707 30.219393 46448 43.891022 -36.542587 29.615152 46449 7.582576 -37.041222 28.278709 46450 7.824756 -38.221317 27.897161 46451 8.148567 -37.863678 29.626162 46452 8.987900 -38.965240 29.452042 46453 46.439362 -38.359955 29.437515 46454 47.975861 -38.929260 29.066101 46455 48.012268 -38.600189 30.385256 46456 52.995789 -38.917435 29.540932 46457 54.989914 -39.133469 29.324013 46458 51.485291 -38.863953 30.648211 46459 55.385880 -39.565781 29.896723 46460 56.483948 -39.944641 29.895388 46461 9.823654 -39.878998 29.946581 46462 9.777390 -40.998032 29.306564 46463 7.840316 -43.072769 28.323288 46464 8.191910 -42.402832 29.074181 46465 42.427948 -44.840958 28.769295 46466 42.277100 -44.132858 29.240440 46467 7.182510 -43.600082 27.867645 46468 7.008278 -43.183090 28.501831 46469 43.868896 -43.046356 29.318283 46470 45.793488 -43.229248 29.249672 46471 44.717270 -42.974518 29.545815 46472 48.317688 -43.828644 29.603487 46473 6.155243 -43.704514 28.245850 46474 4.734512 -45.682938 27.925117 46475 4.978157 -44.353729 29.079796 46476 42.576614 -43.475021 29.716227 46477 43.205872 -43.130692 29.814402 46478 49.898102 -44.300629 29.503311 46479 51.233032 -44.432343 30.445505 46480 51.040894 -44.733734 29.297546 46481 52.422745 -45.255371 29.394516 46482 53.109680 -45.056686 30.617846 46483 53.813522 -45.602463 30.240915 46484 54.818314 -46.074081 30.840097 46485 55.694534 -46.552429 30.162989 46486 56.913284 -46.927155 30.368914 46487 57.495056 -46.685623 31.449129 46488 46.175232 -47.452057 28.836990 46489 56.898132 -47.388229 29.006607 46490 58.874115 -45.303848 30.685289 46491 47.460938 -48.082184 28.772461 46492 48.387634 -48.569763 28.619629 46493 52.090332 -49.559708 30.111658 46494 51.018646 -49.142258 29.789133 46495 4.300675 -50.803116 28.183372 46496 8.288277 -51.109344 27.736694 46497 7.058807 -52.305710 28.309921 46498 7.068787 -51.436966 27.862320 46499 5.938103 -52.037918 27.959305 46500 9.308609 -51.887909 28.331757 46501 38.322357 -50.748978 28.957558 46502 37.346481 -51.549515 28.319588 46503 4.779266 -51.669495 28.014740 46504 41.473785 -51.253403 28.522339 46505 42.719727 -51.822891 28.304321 46506 55.483429 -51.087204 29.771158 46507 54.248413 -50.493317 29.798899 46508 55.972626 -51.753525 29.082993 46509 56.727783 -51.906006 29.761438 46510 56.316315 -51.445602 29.793428 46511 43.884369 -52.115112 29.320869 46512 45.629700 -52.723190 29.518127 46513 57.197479 -52.680862 30.567163 46514 47.420166 -54.266937 28.447571 46515 48.019653 -55.114960 27.932755 46516 49.274933 -54.920929 28.708710 46517 50.124863 -56.070877 28.018677 46518 56.820480 -54.292953 29.292633 46519 10.115349 -57.138260 27.776627 46520 43.891037 -58.206146 27.919777 46521 51.277969 -55.518936 28.970345 46522 51.756317 -56.794296 28.157700 46523 56.403488 -55.650360 28.505226 46524 9.732918 -58.132660 28.246429 46525 9.622910 -58.009094 27.406410 46526 54.824615 -56.064468 29.199631 46527 55.813934 -55.866714 29.076813 46528 55.825256 -56.235245 28.613251 46529 52.466797 -57.595398 27.827225 46530 53.133774 -57.374817 28.174934 46531 8.483322 -59.605194 27.280624 46532 22.406799 -59.995224 27.873413 46533 7.422348 -60.512299 27.466530 46534 17.855331 -61.538132 27.409103 46535 18.488625 -60.332794 27.796875 46536 18.727272 -61.522034 26.984299 46537 19.683105 -60.576752 27.046814 46538 20.600494 -59.735916 27.486282 46539 23.277786 -61.273941 27.795387 46540 19.476913 -59.209747 28.303192 46541 50.240982 -61.297684 28.007179 46542 5.095574 -62.817413 28.025208 46543 18.038261 -62.373032 26.652695 46544 18.775017 -62.106918 26.576317 46545 23.263947 -61.913132 28.101898 46546 4.688995 -65.565445 27.608719 46547 4.991295 -64.707458 28.622894 46548 17.112213 -62.130020 27.326027 46549 22.993034 -62.354065 28.324287 46550 22.757957 -62.824966 28.273582 46551 9.698395 -66.593979 25.653267 46552 37.176888 -67.259933 27.684486 46553 39.098976 -67.532745 27.201447 46554 49.706055 -66.403000 28.285393 46555 8.574112 -67.639587 26.508095 46556 8.759186 -68.848053 27.805389 46557 10.267899 -69.289932 28.380241 46558 9.505905 -67.253082 26.227348 46559 11.131157 -68.897034 28.414307 46560 11.765167 -68.128296 28.036942 46561 35.499382 -67.716400 27.601425 46562 45.018234 -67.823471 27.106964 46563 46.192245 -67.850494 27.274826 46564 46.846893 -67.176270 27.099991 46565 47.811203 -67.024078 27.185196 46566 49.311157 -67.152908 28.682838 46567 48.526932 -67.593063 27.948830 46568 40.670288 -68.165894 27.385849 46569 38.584793 -68.194229 28.333687 46570 39.618141 -68.450272 28.138641 46571 47.086304 -68.042831 27.622902 46572 46.054779 -69.064224 27.980644 46573 47.841187 -67.908615 27.779678 46574 5.369660 -68.861328 26.647682 46575 27.815796 -69.332870 26.862717 46576 28.602470 -69.761276 27.238960 46577 34.639496 -69.390305 27.648483 46578 43.159409 -70.128662 28.719284 46579 44.696320 -69.984772 28.334518 46580 44.102615 -69.100723 27.838791 46581 47.865616 -68.432404 28.286575 46582 16.459320 -70.994843 26.695847 46583 29.129463 -71.107941 27.112198 46584 25.532547 -71.308884 26.799370 46585 25.758575 -70.609268 26.713928 46586 16.317413 -72.490280 26.508713 46587 25.442429 -71.908630 27.616043 46588 25.656212 -72.440140 26.309891 46589 29.161186 -72.243408 26.683075 46590 29.125313 -72.366791 27.818062 46591 33.926147 -73.078751 28.404709 46592 34.068542 -71.923706 28.693115 46593 39.607895 -72.548523 26.786293 46594 38.907700 -72.800247 27.159279 46595 5.552483 -74.114929 26.425827 46596 16.342087 -73.488831 26.247635 46597 40.544144 -73.299866 27.115410 46598 42.299210 -73.874619 26.742096 46599 41.395966 -75.121735 27.773407 46600 40.751038 -74.196564 27.548576 46601 29.177597 -73.179138 26.832153 46602 34.408661 -71.003021 28.885887 46603 43.452332 -75.375854 26.698532 46604 38.218094 -74.785431 26.686470 46605 4.942429 -75.553726 26.680763 46606 14.991707 -74.953735 27.475006 46607 43.352783 -76.477600 26.705467 46608 42.079788 -77.775009 27.425468 46609 16.152084 -79.119843 25.893646 46610 21.896606 -79.190338 26.039673 46611 22.675659 -79.063568 26.462196 46612 23.697067 -79.246231 26.621239 46613 24.728012 -79.106216 26.749237 46614 25.604980 -79.262787 27.713135 46615 29.599136 -75.387238 28.181328 46616 30.068100 -77.959885 28.543289 46617 38.814148 -77.846069 27.303436 46618 38.789970 -79.276138 27.475060 46619 38.789017 -76.789169 27.396065 46620 42.653671 -76.531708 27.363098 46621 5.386330 -77.080170 28.646133 46622 5.245224 -78.654388 28.066719 46623 14.980042 -80.270264 26.405533 46624 15.528625 -79.906693 26.160355 46625 15.820328 -79.585281 25.909409 46626 20.811852 -79.776627 26.645683 46627 30.000290 -78.822647 27.029907 46628 40.493423 -80.513779 26.771233 46629 41.411652 -78.935181 27.361565 46630 40.344086 -78.929520 28.127121 46631 6.862953 -81.106720 26.059357 46632 6.050598 -79.865555 25.698807 46633 5.929154 -79.888000 26.916870 46634 20.239670 -82.307755 26.597038 46635 20.008064 -81.783981 26.425186 46636 32.275742 -81.349167 27.337677 46637 20.990540 -82.717300 26.984711 46638 22.133820 -83.090271 27.198364 46639 24.740288 -82.836258 26.309433 46640 23.781372 -83.122192 26.920547 46641 25.752151 -82.738556 25.962860 46642 26.610291 -82.746262 25.579102 46643 27.371887 -84.347000 26.086441 46644 34.414864 -84.362732 25.844276 46645 36.262032 -83.000519 26.517036 46646 38.957581 -82.058075 26.588211 46647 27.179596 -85.251404 26.002853 46648 35.992393 -84.204575 26.247459 46649 9.834961 -85.952011 25.036385 46650 7.931983 -83.000198 26.603043 46651 25.108078 -86.725449 24.860603 46652 27.324966 -84.960907 26.530670 46653 26.834366 -85.733810 26.737267 46654 11.338608 -87.793900 25.483345 46655 12.890335 -88.033768 25.190048 46656 14.827789 -88.996719 25.201637 46657 10.495796 -88.336456 26.399193 46658 9.828804 -88.591766 27.753593 46659 10.752174 -89.323090 27.606850 46660 11.651123 -88.815033 26.105133 46661 12.690781 -89.468323 26.085434 46662 13.683685 -89.330765 25.721161 46663 14.568466 -90.195633 25.948761 46664 16.301994 -89.966599 25.506493 46665 19.909927 -89.351700 25.167732 46666 19.823608 -90.214630 26.555611 46667 20.067001 -89.846375 25.967583 46668 27.236191 -89.463211 24.484398 46669 26.730423 -89.593338 25.563637 46670 15.458572 -90.239120 25.758011 46671 17.384918 -90.817703 26.351028 46672 20.656761 -90.184357 25.414551 46673 18.213402 -90.437286 26.127304 46674 20.951614 -90.838013 25.220520 46675 20.711349 -90.526230 26.439987 46676 21.168839 -90.958649 25.834724 46677 25.867905 -90.555084 26.273216 46678 21.481689 -91.620972 25.881111 46679 22.145470 -92.657669 24.977425 46680 22.833168 -92.229324 25.603050 46681 23.947220 -91.748596 26.134766 46682 21.805954 -92.167282 25.490944 46683 7.375076 58.374039 35.502708 46684 8.161652 58.029099 35.722000 46685 12.907394 57.460220 35.675484 46686 12.907166 57.518188 36.246559 46687 12.433350 57.233261 36.484253 46688 13.335487 57.222855 36.259918 46689 4.896462 56.482956 34.411926 46690 6.972977 57.473236 35.547035 46691 5.829720 56.234573 35.062080 46692 7.022873 56.190857 35.643105 46693 14.134628 56.644363 36.102409 46694 6.631050 58.385269 35.413345 46695 5.995735 54.623596 34.968605 46696 7.353317 53.659912 35.289093 46697 7.395172 55.161667 35.565292 46698 8.539093 54.194351 35.743301 46699 9.486359 54.803177 36.578087 46700 9.367165 53.601593 36.615524 46701 15.497520 54.886063 35.590660 46702 14.975769 55.948090 36.350662 46703 8.180420 52.905716 35.490753 46704 6.087441 52.577789 34.976494 46705 8.818237 52.866302 35.907158 46706 15.959381 53.729553 35.460487 46707 16.818527 52.637543 35.722351 46708 17.684738 52.334320 36.102119 46709 17.640305 52.757812 36.711075 46710 4.882080 53.288803 34.298088 46711 7.483002 52.164398 35.697311 46712 6.329720 51.446045 35.743454 46713 16.841125 53.698822 36.568993 46714 16.211639 54.473755 36.092880 46715 4.709511 49.675873 36.937241 46716 4.646935 49.714905 35.995216 46717 5.207924 50.214111 36.844574 46718 8.333832 52.196899 35.835449 46719 15.958839 50.337570 34.385086 46720 16.283226 51.390839 34.892288 46721 5.307060 50.570068 35.770256 46722 19.438980 50.427139 36.290848 46723 18.946991 51.077423 36.306618 46724 18.808472 49.960632 35.573250 46725 4.055206 49.176605 34.642006 46726 18.362801 50.785980 35.509178 46727 17.679390 51.540421 35.613182 46728 18.453964 51.361328 35.876724 46729 24.801849 48.883636 34.685616 46730 24.841583 47.987076 35.912598 46731 26.369865 48.259796 36.316093 46732 26.954369 47.948639 36.753403 46733 26.198639 47.405807 37.460022 46734 6.481194 46.658783 34.790237 46735 27.474945 47.532776 35.828697 46736 23.037941 46.913620 34.978920 46737 4.288498 49.031403 35.268120 46738 4.912132 48.099243 35.553574 46739 18.006622 46.030121 36.083893 46740 17.636612 44.998062 35.089165 46741 25.385651 46.420959 38.292702 46742 24.913147 45.691895 38.421234 46743 24.527451 46.068817 37.597084 46744 28.697739 46.538651 37.346420 46745 27.481155 47.420212 37.179283 46746 29.080284 45.788910 36.200836 46747 30.090836 45.288467 36.965797 46748 29.569092 45.928391 37.140701 46749 7.625106 46.579422 35.945717 46750 9.407204 44.609848 34.862045 46751 22.582733 45.900162 34.859421 46752 9.109596 43.980774 35.560852 46753 22.426308 44.688599 35.692970 46754 17.022240 44.184357 35.815735 46755 22.172066 43.085388 36.111603 46756 28.204254 43.755783 34.594734 46757 29.287857 42.848755 34.908424 46758 29.115921 42.107376 34.534866 46759 29.187286 44.307678 35.433922 46760 35.666321 42.694046 34.033936 46761 16.612724 41.695358 34.797340 46762 30.060745 44.582993 36.240807 46763 30.276909 43.319519 35.767159 46764 29.601974 41.940735 34.692139 46765 8.278748 42.318451 34.935318 46766 8.399902 42.992615 35.474937 46767 16.470673 40.659821 34.520287 46768 39.382790 39.164154 34.070206 46769 5.915062 41.699249 35.328987 46770 16.575394 39.834137 34.454559 46771 21.881813 42.382278 35.641327 46772 30.116318 42.249268 35.138557 46773 3.929520 38.945480 34.206764 46774 5.138283 40.802902 35.301147 46775 3.692246 37.907410 33.750404 46776 16.227318 40.281799 35.031021 46777 18.057938 38.253296 35.112099 46778 24.334900 39.154160 35.493309 46779 25.603783 38.167282 35.735573 46780 25.322601 37.785217 35.027229 46781 32.026917 39.819519 35.021057 46782 36.762230 38.644638 34.793274 46783 39.289352 38.622574 34.742500 46784 4.098320 38.362259 34.763771 46785 4.336029 37.413696 34.341644 46786 32.856995 39.114288 34.964409 46787 39.267494 37.951508 35.385162 46788 37.783882 38.032928 36.170212 46789 37.009087 38.049362 37.608246 46790 35.847305 38.303696 36.284447 46791 4.082535 36.892929 33.709175 46792 24.751328 37.625946 34.381355 46793 25.469757 36.864059 34.380112 46794 36.818130 38.366562 35.324425 46795 5.030876 37.870773 35.035286 46796 6.658928 36.529221 34.478592 46797 7.877777 36.379028 34.864861 46798 7.709915 35.634232 34.342003 46799 38.448776 34.939209 35.519165 46800 39.333008 35.562393 35.968353 46801 43.599365 31.329056 34.900146 46802 19.454247 29.572205 34.084518 46803 22.652298 31.529694 33.887253 46804 30.947342 32.252319 35.736115 46805 31.460243 33.055664 35.556129 46806 41.776703 31.243988 35.432930 46807 44.338562 30.753815 34.398834 46808 5.175758 28.728043 33.959778 46809 4.675629 30.063995 34.406052 46810 4.160797 29.302475 34.894173 46811 20.263908 29.237915 33.760017 46812 20.925629 28.512039 33.820183 46813 43.702454 30.061508 34.958389 46814 20.056190 28.244095 34.486320 46815 21.618073 28.536835 34.018326 46816 22.044525 29.231705 34.379654 46817 20.974823 27.812210 34.045174 46818 21.447945 27.843063 34.011620 46819 32.313934 27.596527 34.248131 46820 32.692924 28.533295 34.721405 46821 43.138214 27.735046 33.949852 46822 7.087402 26.318939 34.412170 46823 21.413589 27.075302 34.742577 46824 32.602203 26.347107 34.924118 46825 38.518143 28.568497 34.382065 46826 43.663635 26.824249 34.400665 46827 43.552902 27.757797 35.059967 46828 31.419258 25.210464 34.251045 46829 43.468292 26.084686 33.276978 46830 44.410919 26.132004 33.967697 46831 45.754852 25.946533 33.994270 46832 44.883133 26.359848 35.178085 46833 46.432602 25.847107 35.149269 46834 45.986938 25.791885 35.803322 46835 30.284470 24.222321 33.818039 46836 29.582382 23.928635 33.604248 46837 10.410690 23.651947 34.406670 46838 11.031799 22.997528 33.915115 46839 11.296188 21.873398 34.205727 46840 29.744095 22.681641 33.532166 46841 29.811874 23.500854 33.854836 46842 39.008118 23.911621 34.131752 46843 39.902649 23.268341 34.122833 46844 40.543930 22.603149 33.764351 46845 4.365120 22.006500 32.558311 46846 3.493057 21.611221 32.571518 46847 4.407196 21.136322 33.307831 46848 4.181275 21.568893 33.009010 46849 5.109184 21.347885 32.904411 46850 5.933197 21.251038 32.590248 46851 40.873077 23.282104 34.566582 46852 42.071243 23.475021 34.975479 46853 43.230682 24.411713 35.692200 46854 48.886948 22.735840 34.767303 46855 49.747757 23.270752 34.418434 46856 5.949539 20.533310 32.966415 46857 31.530975 21.994705 34.105774 46858 32.534103 21.333618 34.106201 46859 5.000107 20.517563 33.421555 46860 6.691971 19.522385 33.061310 46861 11.491959 20.606323 34.211823 46862 33.173973 20.658707 33.751511 46863 3.312492 18.286438 33.057785 46864 4.508637 19.907257 33.648293 46865 4.107086 20.511871 33.412048 46866 6.847786 17.884933 33.697784 46867 37.318787 19.659683 34.932167 46868 9.150963 14.321411 33.729202 46869 8.163467 14.632721 34.221054 46870 38.183891 18.119629 34.238602 46871 38.617966 19.130310 35.061775 46872 53.218536 16.978897 34.505379 46873 52.357101 17.177658 35.401344 46874 6.774872 16.674698 34.282196 46875 7.532501 16.121216 34.000793 46876 6.308769 15.913269 34.872314 46877 11.435136 16.759033 33.194138 46878 11.748154 17.778946 33.467522 46879 44.742554 16.903595 33.734093 46880 3.269905 15.979034 32.848892 46881 3.349907 15.402084 32.884720 46882 10.945023 15.904236 33.114120 46883 36.248245 16.348602 34.552132 46884 34.911140 15.905334 34.850021 46885 36.318161 16.430542 33.464699 46886 37.241943 16.917374 33.465942 46887 37.894073 17.341309 33.974846 46888 44.212616 16.112137 35.231659 46889 44.670898 15.858887 36.730057 46890 43.743958 15.368835 36.667793 46891 54.663055 16.398468 33.714630 46892 10.218819 15.370163 33.037926 46893 29.397400 14.919754 33.391785 46894 54.424118 15.345230 34.613113 46895 9.892456 14.692459 33.408707 46896 27.280487 13.437927 33.523216 46897 41.020859 14.310837 34.316505 46898 55.110260 14.570038 33.891212 46899 3.428299 13.634323 33.146164 46900 27.900436 13.894882 33.842560 46901 40.266663 13.932419 33.609291 46902 3.478340 11.106644 33.995071 46903 3.269653 12.038742 32.810867 46904 3.496674 12.584900 34.047340 46905 26.167511 10.865891 33.073425 46906 35.547577 12.327728 34.276848 46907 37.299789 12.820496 34.698067 46908 36.209412 12.068985 35.319855 46909 2.999985 10.858978 32.448975 46910 3.423340 12.847000 32.906700 46911 26.283104 10.019165 33.169373 46912 28.743103 10.185944 32.139511 46913 32.711472 11.164276 33.980560 46914 34.336716 11.785339 34.226685 46915 44.718597 10.976242 33.682449 46916 45.038208 11.169067 33.416176 46917 2.645859 8.769775 32.294853 46918 3.128929 9.506653 33.500732 46919 26.052292 10.231430 33.902199 46920 26.891144 9.467529 32.803375 46921 31.199142 10.314148 33.219971 46922 44.174072 10.524399 33.516479 46923 52.144028 11.551529 33.900909 46924 28.709839 9.238464 32.443115 46925 27.993256 8.682938 32.678177 46926 30.609604 9.270935 33.181946 46927 2.619896 8.038895 32.270004 46928 26.975937 8.542465 35.007812 46929 26.400276 9.390320 35.059723 46930 26.225861 9.471939 34.579613 46931 27.145836 8.385010 33.489243 46932 29.669586 8.161469 32.824402 46933 40.978088 7.849564 33.032120 46934 41.889023 8.462158 33.015305 46935 41.855164 8.213364 34.073273 46936 42.737564 8.832199 34.964806 46937 28.120026 7.517212 33.039597 46938 29.024559 6.687088 32.820274 46939 40.386368 7.417191 34.029861 46940 3.475960 6.290863 32.529129 46941 28.995636 5.490997 32.925201 46942 28.132782 6.428421 33.466484 46943 30.444893 6.317581 32.832809 46944 29.317665 4.358368 32.697769 46945 30.219894 5.161530 32.661942 46946 30.539261 4.337646 32.607246 46947 37.841446 6.626740 33.678452 46948 39.164352 7.301270 34.397148 46949 56.950089 6.186813 34.059662 46950 55.919327 6.464554 33.530083 46951 57.372192 6.466568 33.000610 46952 4.489212 4.341843 31.934305 46953 29.777451 3.409622 32.566010 46954 30.853539 3.555931 32.597328 46955 31.436798 5.221054 32.920471 46956 4.588440 2.941177 32.177887 46957 5.114143 2.034393 32.066734 46958 5.211815 3.983963 31.402048 46959 28.358765 4.335327 33.566933 46960 28.875145 3.480713 32.967690 46961 29.416214 2.371460 32.898842 46962 31.195633 7.295639 33.216957 46963 31.588158 4.271683 32.860283 46964 31.765383 3.374954 32.826805 46965 52.414108 4.893616 33.062759 46966 53.188034 5.277168 33.136894 46967 3.936195 3.611862 32.727646 46968 28.129593 5.502182 33.832581 46969 30.742348 2.486603 32.576294 46970 31.695642 2.540955 32.758125 46971 42.238754 2.842087 32.498070 46972 42.109268 3.327148 33.432487 46973 41.272156 2.687607 32.809311 46974 42.811996 3.389740 32.992226 46975 47.354355 4.732681 34.115639 46976 46.687195 4.665573 34.021851 46977 45.951050 4.821594 34.458000 46978 50.374359 4.436630 33.344543 46979 50.408875 5.424164 34.929611 46980 58.178223 4.486565 33.591499 46981 57.914490 5.322159 33.744896 46982 30.867584 1.431671 32.555931 46983 31.730944 1.787598 32.634140 46984 40.867859 2.796021 33.692543 46985 40.003830 2.254776 33.644615 46986 58.096100 3.669418 33.623451 46987 5.627258 1.201797 31.797686 46988 30.182281 1.750702 32.583725 46989 32.756607 1.535614 32.309250 46990 32.507133 2.720688 32.707207 46991 57.636673 2.867035 33.963989 46992 5.363693 0.370590 31.693804 46993 28.919739 1.690948 33.639015 46994 30.066261 0.912033 32.976608 46995 31.860018 0.398956 32.678871 46996 37.002617 0.150208 32.671539 46997 38.931793 1.464127 33.379761 46998 36.889633 -0.449844 35.177322 46999 37.658707 -0.539871 36.989174 47000 36.003845 -1.485916 36.334938 47001 56.810364 1.787720 34.333679 47002 3.320892 -2.744687 26.451811 47003 31.657412 -1.120972 33.702980 47004 30.731430 -0.326935 33.275574 47005 54.810379 -0.528610 32.918327 47006 3.684194 -3.501062 27.780582 47007 4.682817 -1.826942 30.478876 47008 5.029763 -2.696690 31.633635 47009 5.464485 -2.026154 32.388290 47010 33.212143 -0.212204 32.255951 47011 34.274033 -0.689026 32.549164 47012 33.768044 -1.165344 33.312698 47013 32.886726 -0.726883 32.914650 47014 35.741791 -0.657166 33.443275 47015 3.413651 -3.656217 26.930334 47016 4.669854 -3.472988 30.740381 47017 50.736740 -1.923050 32.684341 47018 51.482056 -1.480988 33.255028 47019 52.592529 -1.477936 32.518227 47020 4.046171 -4.286999 28.964165 47021 3.834746 -4.898907 28.344822 47022 4.282877 -3.518146 29.614729 47023 45.929688 -4.053604 33.004723 47024 45.688965 -4.601974 34.110977 47025 46.650879 -3.313293 34.220955 47026 46.908325 -3.200668 32.676010 47027 47.668610 -2.744629 32.645271 47028 45.034973 -5.056503 32.802673 47029 44.431763 -5.957504 33.825806 47030 44.278198 -5.926254 32.614677 47031 43.774704 -6.771866 32.646698 47032 57.956787 -4.215042 33.405296 47033 59.237549 -5.378662 33.452652 47034 54.727921 -4.134384 33.332199 47035 53.068481 -4.761795 33.171539 47036 51.844315 -5.068298 33.286156 47037 43.296890 -7.679581 32.723061 47038 48.185318 -7.537338 33.102486 47039 47.382996 -8.383774 33.312477 47040 48.856842 -6.877548 32.556946 47041 60.042236 -6.415161 32.945602 47042 46.188263 -9.213745 33.044968 47043 42.387085 -10.138870 33.349030 47044 41.947067 -9.352112 33.652977 47045 60.152725 -8.002304 33.212242 47046 44.086212 -10.734085 33.825203 47047 43.042542 -10.672729 33.651382 47048 51.951294 -10.360626 33.494270 47049 53.602432 -10.307755 32.938065 47050 56.119263 -10.669373 32.368149 47051 55.097748 -10.434769 32.568604 47052 56.589371 -11.616394 31.675951 47053 56.238800 -11.195877 31.944139 47054 57.257401 -10.945374 32.434982 47055 49.704529 -12.152679 33.177277 47056 51.407944 -10.861237 32.530022 47057 51.428101 -11.157547 31.853975 47058 58.549667 -11.578003 32.483055 47059 58.753265 -12.295349 31.883257 47060 60.034088 -12.435059 31.999712 47061 47.313553 -14.340073 31.806498 47062 60.372559 -11.755051 32.457024 47063 48.277344 -17.381210 31.706186 47064 47.932617 -15.506897 32.413544 47065 44.287415 -21.085434 31.709261 47066 44.398468 -21.720993 31.261507 47067 43.622864 -21.789780 32.192230 47068 45.159821 -20.958618 31.447695 47069 46.040573 -20.749847 31.468477 47070 48.311661 -20.720245 31.455164 47071 49.067322 -20.370712 31.610964 47072 52.974915 -24.441498 31.860437 47073 54.669266 -24.347809 31.793299 47074 55.735367 -24.566452 31.533739 47075 55.663132 -23.867462 32.362816 47076 50.724640 -25.326675 34.362556 47077 49.317566 -24.920990 33.106384 47078 51.482056 -25.042709 33.666962 47079 51.509796 -24.738068 32.422424 47080 56.484756 -24.210449 31.929567 47081 56.441086 -25.281387 31.067339 47082 57.365692 -25.170471 31.580065 47083 56.940369 -26.006409 30.799074 47084 58.466873 -27.026367 31.060419 47085 58.928833 -26.927505 31.714663 47086 60.277054 -27.875870 31.739344 47087 62.087402 -31.512634 31.892054 47088 62.181763 -30.020233 32.616966 47089 45.284180 -34.686646 31.165552 47090 45.762207 -34.204132 30.878038 47091 50.533340 -34.312729 31.503267 47092 5.558081 -31.984941 27.061941 47093 46.630798 -34.194199 31.833231 47094 51.172928 -34.083496 32.341850 47095 51.995865 -33.934601 32.651787 47096 60.863846 -34.041901 31.219812 47097 6.370797 -34.182880 27.472237 47098 6.273673 -32.319244 28.285334 47099 44.863525 -35.600632 31.360346 47100 6.625015 -33.539509 28.377352 47101 7.290442 -36.032780 28.316328 47102 7.681973 -36.156200 29.150288 47103 6.887173 -35.139275 27.988199 47104 7.766280 -34.644440 30.552679 47105 7.910934 -35.468399 30.993792 47106 8.155857 -36.332840 30.122904 47107 7.984670 -37.484287 28.949228 47108 48.993469 -38.587524 31.026720 47109 46.759460 -37.824265 31.625254 47110 50.001495 -38.685165 30.975000 47111 53.206055 -39.276627 31.192568 47112 49.319839 -38.126648 32.880615 47113 54.804855 -40.224030 30.904573 47114 57.258392 -41.198257 30.442469 47115 9.577438 -41.423431 29.319664 47116 55.953430 -40.317749 30.484629 47117 4.867638 -42.546707 29.723543 47118 6.065590 -42.198059 29.350014 47119 5.117447 -41.465958 29.943544 47120 5.646431 -43.007034 28.984665 47121 6.404945 -42.862396 28.812180 47122 7.176499 -41.934494 29.591637 47123 6.182655 -41.349640 29.812601 47124 59.027039 -42.325424 30.034594 47125 4.323349 -43.454102 30.387667 47126 7.169006 -42.647034 28.975739 47127 8.157455 -41.286835 30.171953 47128 45.409546 -42.975998 30.431688 47129 46.143021 -43.068985 30.148554 47130 58.826431 -43.184662 30.610140 47131 59.414032 -43.262268 29.987459 47132 58.377548 -42.094574 30.458078 47133 41.863785 -44.334015 29.899263 47134 42.115738 -43.796036 30.068094 47135 47.768951 -43.662521 31.547167 47136 46.415039 -43.260971 30.973131 47137 49.333511 -43.904617 31.083887 47138 50.172302 -44.002457 30.458048 47139 50.254852 -44.016296 31.023142 47140 42.218582 -44.990356 29.432106 47141 41.852264 -45.019516 30.240366 47142 52.449783 -44.757233 30.272669 47143 4.548180 -47.413025 29.512062 47144 4.737969 -45.651230 29.900957 47145 4.678635 -46.018784 28.878151 47146 41.720917 -45.669998 31.231966 47147 42.664337 -46.688187 31.564165 47148 41.824280 -46.445023 32.480217 47149 57.956589 -46.280869 31.592150 47150 58.108231 -45.368179 31.507616 47151 43.695007 -46.790955 31.007235 47152 45.836441 -47.260712 30.231089 47153 47.303360 -47.677795 29.904665 47154 55.969940 -46.448181 31.318140 47155 57.697296 -47.347580 29.323952 47156 50.874924 -49.029800 30.821390 47157 53.446243 -49.892593 30.760981 47158 52.899582 -49.717026 30.829172 47159 53.286713 -49.991821 30.111551 47160 3.997994 -49.824127 29.514496 47161 3.973168 -51.334518 29.065887 47162 8.103958 -52.082886 28.458076 47163 9.970581 -52.122238 28.358574 47164 5.281426 -52.879364 28.263489 47165 3.572212 -50.852585 30.312487 47166 3.693466 -52.037155 30.326883 47167 6.347824 -53.045135 28.353249 47168 7.729774 -53.200592 28.757713 47169 10.158440 -52.301758 28.073883 47170 41.733383 -51.685455 30.577509 47171 42.552551 -51.647156 29.670855 47172 43.506439 -51.928513 30.437204 47173 42.728821 -52.285583 31.080286 47174 55.140945 -50.627518 30.704828 47175 56.437119 -51.380402 30.685961 47176 3.705292 -52.921677 30.996309 47177 4.296562 -53.426453 29.645868 47178 4.427498 -52.609009 28.862335 47179 5.791924 -53.573349 28.416077 47180 36.730827 -52.970856 28.958145 47181 36.502129 -52.885605 29.394211 47182 36.981918 -52.204742 29.300583 47183 44.785568 -52.422852 29.387047 47184 57.129776 -51.916687 31.626535 47185 4.372749 -55.912735 29.825472 47186 5.435936 -55.081604 29.238304 47187 3.953865 -54.185181 30.749269 47188 36.581451 -54.808533 29.856623 47189 36.645126 -53.726334 29.571518 47190 37.395447 -55.249252 29.014130 47191 47.739426 -52.927689 30.427446 47192 48.316376 -53.620987 29.508308 47193 46.906265 -53.220566 29.548203 47194 50.634689 -54.522049 29.514297 47195 49.666580 -53.803848 29.914103 47196 51.230835 -53.887070 30.694162 47197 5.267815 -53.745453 28.744781 47198 6.547424 -54.149124 28.777046 47199 9.811478 -53.993713 28.371811 47200 38.880463 -55.416275 28.515404 47201 51.921021 -54.697861 29.893442 47202 9.935013 -56.392563 28.459045 47203 38.379227 -56.389984 28.931938 47204 52.390900 -55.367584 29.499817 47205 56.906281 -54.318237 31.429445 47206 57.049759 -53.965073 30.671656 47207 56.372574 -54.752090 30.665201 47208 10.051086 -57.383347 28.352188 47209 37.232803 -57.496628 29.483833 47210 36.484818 -55.899384 30.244356 47211 39.467529 -56.320755 28.906982 47212 41.488281 -56.936005 29.095932 47213 40.698792 -56.732697 29.020226 47214 41.417816 -58.001022 28.977280 47215 53.015884 -56.221634 28.957397 47216 53.455750 -55.135056 30.063105 47217 55.147583 -55.189667 30.778284 47218 56.111603 -55.013626 32.068169 47219 9.207878 -59.025452 27.878822 47220 8.587860 -58.928757 29.066521 47221 8.799118 -59.811600 28.196671 47222 36.218224 -57.314621 30.834513 47223 39.195084 -57.281754 29.111244 47224 38.473541 -58.594147 29.230133 47225 37.367043 -58.705002 29.304024 47226 43.756577 -59.359467 28.866600 47227 18.621300 -59.167999 28.437904 47228 17.768867 -59.298172 28.837143 47229 20.501915 -59.078873 28.893288 47230 21.839661 -59.869888 28.935913 47231 22.926193 -61.683624 28.632126 47232 22.380096 -62.493210 28.850914 47233 36.553497 -59.125641 30.009325 47234 37.456963 -59.472565 29.643267 47235 46.406097 -59.406982 28.775162 47236 8.388496 -60.374512 28.007011 47237 8.010406 -60.816879 28.412888 47238 17.001999 -60.817886 28.148514 47239 47.974243 -60.299194 28.978767 47240 46.959808 -60.342560 29.404823 47241 5.732285 -62.131516 28.214622 47242 6.432884 -61.440979 27.908142 47243 7.109390 -61.136765 29.051567 47244 14.880432 -60.980957 29.257263 47245 15.143845 -60.530899 29.520874 47246 15.658417 -60.775528 28.840271 47247 14.870224 -61.894241 28.347733 47248 16.007751 -62.185211 27.645126 47249 22.608047 -60.713928 28.655045 47250 15.150856 -62.695908 27.584091 47251 51.256546 -63.264297 29.607836 47252 13.636147 -63.105591 28.476349 47253 13.332047 -64.361084 28.241104 47254 13.360535 -63.429428 28.951851 47255 12.984413 -66.032669 27.879501 47256 13.171516 -63.988434 29.136139 47257 22.003235 -61.590225 29.366249 47258 22.157127 -63.225235 28.267937 47259 51.308563 -64.294189 28.543808 47260 49.617874 -66.985443 29.490829 47261 49.932587 -66.263489 29.322899 47262 12.476189 -67.239517 27.487755 47263 18.746750 -66.340698 28.233780 47264 18.765999 -64.580688 29.930696 47265 17.604805 -66.008972 30.024553 47266 48.750305 -67.902328 28.533798 47267 50.673340 -65.047485 29.483505 47268 36.053871 -67.245956 27.754791 47269 36.205811 -67.803802 28.382271 47270 36.144699 -69.387009 29.177269 47271 36.776382 -68.231476 28.792953 47272 4.847725 -68.715485 27.569008 47273 5.942124 -69.442764 27.470764 47274 7.059418 -69.510254 28.104279 47275 9.555176 -69.760834 28.899673 47276 17.298706 -68.130020 28.125221 47277 16.468781 -69.587128 27.673874 47278 27.603058 -69.134735 28.193756 47279 29.159760 -70.272812 28.282059 47280 40.591019 -68.946274 28.375458 47281 47.522034 -69.227158 29.350731 47282 5.249519 -69.402344 27.690193 47283 16.234978 -68.978638 28.849121 47284 15.716614 -69.766342 28.769821 47285 15.805710 -70.458755 27.955399 47286 25.754120 -70.377487 27.699318 47287 44.655273 -70.867310 29.051567 47288 45.939697 -70.229202 28.838547 47289 45.668564 -71.313080 29.804369 47290 46.262558 -71.154755 30.468264 47291 46.621368 -70.522751 30.083803 47292 48.819244 -67.976120 29.293129 47293 15.277435 -71.669464 28.240509 47294 29.409348 -71.360870 28.989372 47295 29.489426 -72.311584 29.952364 47296 29.172379 -72.508316 28.930153 47297 29.252991 -71.256821 27.995590 47298 6.699921 -73.403015 26.510132 47299 14.308364 -72.776581 29.011719 47300 13.556793 -73.763214 29.519035 47301 14.107567 -74.297333 28.531227 47302 15.633064 -73.376556 27.172928 47303 29.191315 -73.578690 28.613602 47304 38.454788 -74.112946 27.397423 47305 40.281891 -75.058609 27.910927 47306 39.389900 -73.960327 27.600029 47307 14.858444 -73.348526 28.056343 47308 38.701447 -74.941528 27.569351 47309 14.877945 -76.766830 27.666351 47310 13.986359 -75.975189 28.468880 47311 29.210098 -73.815155 27.585129 47312 33.848099 -74.150070 27.849937 47313 38.558029 -75.888153 27.055458 47314 42.377686 -75.337051 27.423149 47315 5.204537 -75.160110 26.960945 47316 5.223892 -76.129150 27.075195 47317 34.025703 -75.836044 27.792290 47318 34.202675 -76.420212 27.776108 47319 33.964348 -75.101013 28.371964 47320 41.788757 -76.967178 27.943954 47321 41.872162 -76.082520 27.878227 47322 14.379303 -77.410751 28.455406 47323 34.284760 -77.385559 27.612114 47324 10.420845 -79.170364 28.168083 47325 10.330986 -78.107010 27.633286 47326 15.558693 -79.780136 27.057785 47327 26.077332 -77.165131 28.146034 47328 25.970276 -78.203033 27.417389 47329 9.630577 -77.784500 28.390701 47330 11.719528 -79.758041 27.320015 47331 15.200349 -78.339417 27.877106 47332 21.438812 -79.463608 27.524864 47333 21.868835 -79.228653 26.889633 47334 33.970200 -78.894913 26.937927 47335 19.920952 -80.450302 27.132812 47336 19.944824 -80.183823 28.977753 47337 20.811462 -79.905914 29.636492 47338 21.418861 -79.692566 28.561218 47339 22.644791 -79.472198 27.531219 47340 23.614182 -79.604156 27.427597 47341 24.361168 -79.619339 27.520012 47342 30.366272 -79.823242 27.147926 47343 34.242249 -79.098511 28.976730 47344 14.099037 -80.704742 26.801277 47345 14.589043 -81.108551 27.690926 47346 13.981536 -81.198166 27.257576 47347 15.171730 -80.669861 28.415863 47348 15.082764 -79.829285 28.807579 47349 19.622528 -81.283875 27.099518 47350 32.560173 -81.573608 28.336067 47351 6.990715 -81.501175 27.655266 47352 7.486740 -81.959671 26.354156 47353 19.712120 -82.089401 27.163109 47354 38.939842 -80.573959 27.392120 47355 39.624908 -79.784897 27.806824 47356 19.238991 -81.796143 28.160545 47357 19.478058 -80.749710 28.011841 47358 20.129463 -82.618317 27.307915 47359 21.326736 -83.712051 28.806358 47360 22.984795 -83.314789 27.452202 47361 24.726593 -83.508682 27.497322 47362 25.680954 -83.460861 26.958733 47363 26.689400 -83.593369 26.401260 47364 26.471176 -84.766068 27.556152 47365 32.148178 -81.743500 27.736191 47366 31.743074 -81.630386 27.843575 47367 37.436760 -82.370575 26.986076 47368 25.561798 -83.989212 27.859833 47369 36.984512 -83.454208 26.657364 47370 27.086548 -84.651489 26.798630 47371 37.895020 -83.015396 26.674500 47372 37.693611 -83.759521 26.165733 47373 26.645676 -88.595108 26.738060 47374 11.801918 -89.925766 26.855545 47375 26.632553 -86.860901 27.815872 47376 13.621971 -90.465286 26.396667 47377 12.702751 -90.774216 27.059654 47378 26.460022 -89.655899 26.607956 47379 15.308640 -91.021408 26.222305 47380 16.201447 -91.030594 26.291313 47381 21.228210 -90.980804 26.487236 47382 25.931503 -89.702148 27.797096 47383 14.573517 -91.210907 26.861320 47384 15.564636 -91.507858 27.013214 47385 18.229553 -90.867554 26.614388 47386 21.452118 -91.367477 26.374176 47387 24.792313 -91.196640 26.526505 47388 16.833443 -91.532120 27.865646 47389 21.952835 -91.807465 26.328690 47390 22.761024 -91.646011 27.108040 47391 8.915070 57.443481 35.985924 47392 8.690605 56.080933 36.126572 47393 10.088577 56.976257 36.523872 47394 13.855804 56.416718 37.300903 47395 6.545158 55.593216 35.423035 47396 10.344849 55.720032 37.346565 47397 9.898613 54.438110 37.522293 47398 15.861816 55.248993 36.587341 47399 16.413368 54.652435 36.914101 47400 16.674408 54.172012 37.608971 47401 9.216354 52.784348 36.400673 47402 17.262344 53.198242 37.734093 47403 8.701583 52.244629 36.447044 47404 18.256538 51.946167 36.389374 47405 18.375496 51.953125 37.631691 47406 7.567040 51.862488 36.932335 47407 8.101303 51.886017 36.183060 47408 19.493530 49.846054 36.343697 47409 6.076141 50.968628 36.834724 47410 19.090256 48.958664 35.853157 47411 6.127319 47.290466 35.753677 47412 19.024841 48.079010 36.206627 47413 5.655441 48.138031 36.844994 47414 18.532501 47.106308 36.524307 47415 8.734680 45.751556 36.194901 47416 23.490189 44.426620 37.457222 47417 23.328278 45.521118 36.703163 47418 23.249069 46.514374 35.621147 47419 9.214447 45.134369 35.424461 47420 9.384155 44.685928 35.508514 47421 17.502792 45.241196 36.279388 47422 9.181824 44.893570 35.909111 47423 8.915955 44.883926 36.546249 47424 8.450492 43.579834 36.117371 47425 22.601036 44.139404 36.632187 47426 7.297707 43.394623 36.313545 47427 8.215439 44.159760 36.914970 47428 16.472023 43.395874 36.752632 47429 16.083069 43.429260 37.828629 47430 16.538879 44.375244 38.015739 47431 22.036423 42.218704 35.943909 47432 6.407982 42.436859 35.747185 47433 5.305916 41.996872 36.533981 47434 5.896950 42.963806 36.601845 47435 7.568070 42.596558 35.395576 47436 16.210419 40.988342 35.460815 47437 30.999397 42.239807 35.839668 47438 32.300827 41.974335 37.256912 47439 31.027298 43.783691 37.239647 47440 31.579285 40.938049 35.534874 47441 16.387039 42.022369 36.101593 47442 16.173904 40.391998 35.584091 47443 3.982147 39.082321 35.036186 47444 34.901161 38.737442 37.061279 47445 34.085922 39.482605 37.196236 47446 34.069458 38.796082 35.962532 47447 8.743088 36.231873 35.613220 47448 8.297256 35.510361 34.794891 47449 26.182739 37.273529 35.543678 47450 34.464378 39.982361 38.369194 47451 33.727112 40.218323 37.508537 47452 39.220184 37.011261 36.623688 47453 38.260910 37.534775 37.482079 47454 39.946175 37.360931 35.007042 47455 6.074333 38.469788 35.861526 47456 7.633911 37.313339 35.492851 47457 26.658028 36.389923 36.239853 47458 26.942192 37.198822 36.446533 47459 39.666046 36.971649 35.603294 47460 39.606071 36.209381 35.944435 47461 8.386436 34.445572 35.310730 47462 24.563118 34.157318 35.968285 47463 26.001534 35.467453 36.417221 47464 19.971329 34.864929 36.588844 47465 19.285637 33.646744 36.000267 47466 19.490601 34.510834 37.584076 47467 31.120834 32.970993 36.475983 47468 32.321266 33.517563 35.709473 47469 33.765137 33.884003 36.122269 47470 36.215271 34.026199 35.938202 47471 37.452370 34.316406 35.647255 47472 37.598328 34.536026 36.548782 47473 23.921516 33.612320 36.328667 47474 35.013275 33.877731 35.898666 47475 4.053787 30.001801 35.189613 47476 6.774246 33.020401 35.690987 47477 18.684006 29.258896 35.040230 47478 17.821167 30.330627 35.937408 47479 23.529602 32.995026 37.077621 47480 23.852432 33.459839 38.014854 47481 23.628578 32.168823 38.122284 47482 22.835480 31.661240 35.128464 47483 23.124557 32.251312 36.209801 47484 30.618027 31.497818 34.673767 47485 42.647919 31.568848 35.271080 47486 5.382866 32.140411 35.648643 47487 4.363236 32.015564 37.120964 47488 4.346489 30.855621 35.681335 47489 17.780823 31.613220 36.215721 47490 18.730209 28.521576 35.995018 47491 18.268974 29.038864 35.749481 47492 22.840591 30.777954 36.126526 47493 22.741226 29.571304 35.267754 47494 18.112846 29.460358 35.667824 47495 31.050781 30.846512 35.557991 47496 34.546402 28.688995 36.350975 47497 35.071014 28.865341 36.760818 47498 33.803627 29.864304 36.887581 47499 43.219955 29.589478 36.065071 47500 42.809845 30.333572 36.048950 47501 42.542206 29.783127 36.441971 47502 42.697662 31.000061 35.620491 47503 3.971832 28.120193 35.489120 47504 20.290436 27.359619 35.562241 47505 19.772705 27.673035 35.691010 47506 22.202438 28.387802 34.411423 47507 22.660278 28.692169 34.828018 47508 32.836197 29.153702 35.096916 47509 33.708778 28.513000 35.762733 47510 38.245972 26.628342 34.376495 47511 40.071594 28.176132 35.669044 47512 40.331238 26.609436 35.771927 47513 43.486176 28.775467 35.499985 47514 19.305382 28.124908 35.624809 47515 21.950531 27.832840 34.287300 47516 22.740845 27.795914 34.846893 47517 24.006302 27.752594 35.925201 47518 24.175705 26.645782 35.931801 47519 23.126907 26.701477 35.102814 47520 3.883377 26.610321 36.200150 47521 5.388275 26.549988 35.094208 47522 7.083695 25.473679 35.230461 47523 22.273285 25.757126 35.047867 47524 23.492737 25.583618 35.483139 47525 33.155441 27.588211 35.142334 47526 43.946838 27.071442 35.384338 47527 8.323067 25.566986 34.495026 47528 9.473344 24.709137 34.408974 47529 32.290573 24.983704 35.065506 47530 40.395935 24.806061 35.408539 47531 40.643784 25.610092 35.750992 47532 41.700745 24.984375 35.857559 47533 44.988281 25.809586 35.977127 47534 10.079650 24.189087 34.348312 47535 20.985222 25.937653 35.856651 47536 20.618439 26.868088 35.808945 47537 22.727699 25.076080 35.073120 47538 31.694292 24.149796 34.881882 47539 32.480606 23.695038 35.359726 47540 22.011719 24.756104 35.382744 47541 23.738129 24.717804 36.158806 47542 23.455887 23.812195 36.591019 47543 22.804596 24.077866 35.704559 47544 30.600914 22.995972 34.120522 47545 31.071106 23.901093 34.474037 47546 39.393753 25.259552 34.934059 47547 39.999527 24.072708 34.771225 47548 49.203461 24.052948 34.684311 47549 9.695985 23.739044 35.039680 47550 10.366776 22.463699 35.052467 47551 40.957916 24.078506 35.232681 47552 49.333893 23.117752 34.766594 47553 3.722748 21.092072 33.133202 47554 32.459579 22.311401 34.842407 47555 33.906143 21.411682 35.090645 47556 45.821930 23.400818 35.390266 47557 46.778473 23.390488 35.473946 47558 47.986740 23.105728 35.202812 47559 3.560463 20.496674 33.131889 47560 44.697723 23.872589 35.411072 47561 48.032379 24.172180 35.471725 47562 47.244720 24.138062 35.846886 47563 5.532135 19.431030 33.731125 47564 4.361641 19.279007 33.877563 47565 35.311752 20.333801 34.797241 47566 3.799255 18.704041 33.844589 47567 6.351288 18.804504 33.708183 47568 38.986359 19.996384 35.964310 47569 38.053223 20.160355 35.818237 47570 5.820000 18.478607 34.062630 47571 11.719490 17.594437 34.707069 47572 11.784072 16.839828 34.009834 47573 38.924606 18.234192 34.916367 47574 3.559845 16.446884 34.634384 47575 3.279114 15.735718 33.877022 47576 6.139732 16.922684 34.485619 47577 5.352188 17.667313 34.474548 47578 38.661034 17.558548 35.156136 47579 47.613358 17.174332 36.053673 47580 46.477234 17.142166 35.533653 47581 49.640610 17.219528 36.086037 47582 51.761627 16.950256 36.302513 47583 51.123901 16.748138 37.358002 47584 3.387650 14.695709 33.652596 47585 36.192459 16.309875 35.586853 47586 34.612923 15.791168 35.753723 47587 37.491043 16.835236 34.375763 47588 3.405960 14.882401 35.059364 47589 3.364578 13.751083 34.591339 47590 7.009972 14.772003 35.003868 47591 10.792847 14.905273 33.876472 47592 10.477661 12.927551 35.059036 47593 9.985924 13.721191 34.185898 47594 10.894279 14.151672 34.996094 47595 28.772217 14.292572 34.183250 47596 29.882721 14.730255 34.236862 47597 30.797333 14.653046 35.101547 47598 42.829575 14.591187 37.163544 47599 42.714325 14.977448 35.863602 47600 41.347565 14.395645 35.371689 47601 54.790085 14.187714 34.333549 47602 8.759079 13.193878 34.632187 47603 9.727798 12.491028 34.726166 47604 26.841141 12.558914 33.889809 47605 26.214676 11.448776 33.879105 47606 35.165787 11.518356 35.051147 47607 52.167633 13.758881 36.726768 47608 52.791336 14.795120 36.813797 47609 52.954422 14.219208 36.326668 47610 3.516358 11.751984 35.027077 47611 32.256393 10.368256 34.131058 47612 33.444641 11.194305 34.424309 47613 44.771942 10.665543 34.798714 47614 45.359497 11.078888 35.932083 47615 45.341476 11.187775 34.302048 47616 46.209839 11.332794 34.658745 47617 53.321243 12.611221 34.464813 47618 26.394600 9.294525 33.821587 47619 26.345871 10.286270 34.840919 47620 53.476379 14.100632 35.664604 47621 54.193268 13.939636 34.780136 47622 3.245133 7.042328 33.639404 47623 3.506699 6.035706 33.970535 47624 3.315888 8.087845 34.339981 47625 2.922951 7.980515 32.984108 47626 44.193649 10.142242 34.704285 47627 31.354050 8.303726 33.511543 47628 31.709154 9.313538 33.907310 47629 27.404617 7.379013 34.052940 47630 32.371216 7.517548 33.756577 47631 32.319382 8.493042 34.086090 47632 32.123215 6.303101 33.326523 47633 41.149948 7.720825 34.003273 47634 3.758049 4.970367 32.860596 47635 3.802750 5.054504 34.378014 47636 27.981003 6.442017 34.844383 47637 27.359833 7.405670 34.890770 47638 33.611130 6.788269 34.068398 47639 33.098907 4.637054 33.141190 47640 38.251923 7.584442 35.008972 47641 53.353546 5.779022 33.923973 47642 54.149506 6.232025 34.146637 47643 28.489624 2.942383 33.732101 47644 34.656738 4.762863 33.184830 47645 34.428131 5.738388 33.852280 47646 44.992416 4.461655 34.248856 47647 49.600525 4.711243 33.916466 47648 52.476349 5.394089 33.960327 47649 51.781067 5.843452 34.988342 47650 53.050537 6.146637 34.797844 47651 3.862190 3.570831 34.100983 47652 3.291214 1.954865 33.882263 47653 3.739365 2.448166 33.052162 47654 28.467461 2.210526 34.320450 47655 28.290741 2.749420 34.479668 47656 35.463058 5.698578 33.683556 47657 3.461121 1.378616 33.180168 47658 4.283653 1.422607 32.603928 47659 5.225578 1.157990 32.138992 47660 28.355507 3.567154 34.688980 47661 4.834129 0.023788 32.602409 47662 5.426941 -0.873291 32.494545 47663 37.680389 0.415085 34.182266 47664 56.416107 2.835419 35.939438 47665 57.158386 3.117065 35.009789 47666 5.128632 -0.972580 32.945419 47667 29.454483 -0.717239 34.378883 47668 28.992126 -0.232315 34.673691 47669 29.219131 0.439362 33.966042 47670 29.904541 -0.264587 33.569458 47671 39.044617 1.349442 34.681740 47672 38.363197 0.477264 35.534637 47673 55.172302 0.073517 33.693970 47674 53.525391 -0.820694 33.126717 47675 54.200592 -0.158508 33.860069 47676 55.869553 0.617203 34.017479 47677 30.965958 -2.055328 35.042572 47678 29.909180 -1.596222 35.359329 47679 30.341187 -1.175018 34.150146 47680 32.801544 -1.350815 33.709564 47681 34.636749 -1.377792 33.868210 47682 33.604630 -1.703171 34.258728 47683 34.596573 -1.070496 33.201317 47684 35.588806 -1.229477 34.700729 47685 52.383408 -0.919785 33.729172 47686 53.205444 -0.455612 34.041084 47687 3.179214 -3.750706 26.067320 47688 5.026368 -3.626640 31.846464 47689 48.669006 -1.486496 34.302307 47690 49.888489 -1.075134 34.503067 47691 50.582489 -1.513275 33.615707 47692 3.247611 -4.518186 26.401875 47693 3.347981 -5.229777 26.744265 47694 3.524679 -4.602376 27.351574 47695 5.368981 -3.690262 32.914795 47696 5.212082 -1.902237 33.217438 47697 47.639832 -2.390594 33.619125 47698 4.389609 -4.651425 30.014311 47699 5.054278 -4.604533 32.098972 47700 4.724249 -4.899646 31.053701 47701 5.201449 -6.643131 32.442715 47702 4.993828 -5.836747 31.923655 47703 5.402924 -5.441742 33.469444 47704 55.239151 -3.351852 34.530586 47705 55.390533 -3.120712 35.565460 47706 54.342606 -3.512970 35.244926 47707 57.219437 -4.039368 32.893723 47708 58.344879 -4.514008 34.421707 47709 3.759483 -5.991701 28.075531 47710 4.184728 -5.936340 29.381706 47711 4.138881 -7.392976 29.124014 47712 4.722623 -6.009296 31.037519 47713 4.500479 -5.807873 30.353334 47714 50.870621 -5.613434 33.483994 47715 49.724091 -6.451187 33.486992 47716 42.768677 -7.944641 33.430153 47717 43.315277 -7.076477 33.888893 47718 42.608673 -7.771622 34.473892 47719 48.907043 -7.084488 33.579033 47720 3.488582 -11.765144 26.391565 47721 42.318558 -8.480560 33.719818 47722 55.786484 -7.547302 35.717590 47723 55.244598 -8.244705 34.311363 47724 54.507874 -8.509384 35.103699 47725 56.668030 -7.311920 34.422714 47726 57.753937 -5.984741 34.864441 47727 58.443542 -7.567398 33.871460 47728 58.962677 -6.031403 34.136124 47729 58.139145 -9.030518 33.302048 47730 57.155579 -8.304840 33.502434 47731 59.705536 -7.062393 33.553314 47732 56.126587 -8.430954 33.561340 47733 56.588501 -9.647537 32.956604 47734 55.058029 -9.353226 33.320679 47735 58.962616 -9.832108 33.305527 47736 57.974335 -10.026688 33.045731 47737 3.553296 -10.732605 26.914484 47738 41.943512 -10.137924 33.589325 47739 53.610260 -9.430878 34.185867 47740 59.764481 -11.271606 32.816475 47741 59.903839 -10.363815 32.986794 47742 59.683777 -8.915909 33.236633 47743 50.270248 -11.377182 33.268906 47744 50.849976 -10.890793 33.228210 47745 58.788742 -10.704941 33.030464 47746 3.483837 -7.643602 27.095095 47747 3.512943 -8.457008 27.088917 47748 49.738312 -13.129700 33.966621 47749 49.417969 -14.548431 33.875122 47750 50.373932 -14.103058 34.335251 47751 59.570084 -11.888229 32.473839 47752 3.687162 -9.036421 27.607454 47753 4.006651 -12.653491 27.907970 47754 4.462279 -11.330951 29.482224 47755 4.465067 -12.910599 29.187243 47756 5.097358 -12.501913 30.855051 47757 5.533916 -12.758791 31.776129 47758 5.249864 -13.599225 30.954718 47759 3.474834 -6.742862 27.070429 47760 4.747232 -12.126662 30.088789 47761 5.022428 -11.212159 30.915487 47762 4.854426 -13.098437 30.157125 47763 47.705811 -14.195389 32.417969 47764 4.388661 -14.238008 28.686689 47765 4.977458 -15.478024 29.898775 47766 4.823908 -16.799141 29.287827 47767 4.471390 -15.590640 28.642391 47768 48.021454 -14.104019 32.713669 47769 3.960780 -13.894073 27.516077 47770 4.062273 -15.141688 27.549601 47771 4.831861 -14.097209 29.865343 47772 49.015686 -15.736389 33.321579 47773 4.344980 -16.387283 28.211052 47774 4.531969 -16.464664 28.695065 47775 4.154510 -16.539391 27.530453 47776 3.913396 -15.900023 26.913410 47777 4.497952 -17.109692 28.439100 47778 5.335474 -16.857155 30.444902 47779 4.663858 -18.773623 28.393763 47780 4.710971 -17.847567 28.771610 47781 5.077652 -17.939077 29.652464 47782 3.964799 -16.691401 26.893358 47783 3.837252 -16.409796 26.492195 47784 4.313016 -17.051271 27.955338 47785 4.355588 -17.973776 27.719042 47786 48.949585 -17.255890 32.502380 47787 50.057037 -17.093094 33.312561 47788 4.318142 -19.590717 27.083426 47789 5.073516 -18.995510 29.406898 47790 49.836792 -18.523102 32.454239 47791 5.046240 -22.393986 28.600679 47792 4.874954 -23.696297 27.883820 47793 4.627637 -22.575796 27.382339 47794 4.733848 -21.058249 27.998264 47795 5.204920 -20.006767 29.492220 47796 5.311922 -21.232544 29.498775 47797 49.610474 -19.756775 31.946741 47798 50.602356 -19.520477 32.596626 47799 50.755295 -18.449677 33.068398 47800 5.370458 -23.649120 29.123859 47801 4.756164 -19.791245 28.387726 47802 5.540556 -22.475220 29.782732 47803 42.542419 -21.949173 33.053101 47804 43.318573 -21.102051 33.475784 47805 42.345276 -21.416046 33.647415 47806 46.003464 -20.680664 32.272690 47807 47.515167 -20.821716 32.191429 47808 49.157104 -20.655197 32.588234 47809 50.286621 -20.287872 32.436287 47810 51.713501 -19.253906 33.709824 47811 50.811798 -20.213974 32.924408 47812 5.248339 -24.658485 28.649828 47813 5.798205 -23.676369 30.055792 47814 44.467224 -20.849838 32.429100 47815 47.120010 -20.706863 33.286186 47816 48.455444 -20.685623 34.176598 47817 50.329010 -20.610962 32.827385 47818 5.526678 -24.752007 29.239412 47819 5.918253 -25.119715 29.902170 47820 4.792959 -25.051065 27.380007 47821 4.968714 -24.623787 28.011908 47822 5.608523 -25.656404 29.171896 47823 57.358612 -23.671646 32.468964 47824 56.399399 -23.471436 32.637619 47825 56.673996 -23.040482 33.359482 47826 57.765213 -22.699951 33.442703 47827 5.140321 -25.151258 28.332403 47828 5.326254 -26.007273 28.468578 47829 44.647079 -24.427521 33.262779 47830 45.471817 -24.470215 32.962639 47831 46.546448 -24.602448 32.331116 47832 46.164902 -24.843246 34.113091 47833 54.060089 -24.159744 33.114517 47834 58.413361 -24.547882 32.278374 47835 58.462296 -25.927597 31.782351 47836 58.433548 -23.441223 32.789917 47837 59.069778 -22.542953 33.632698 47838 59.698608 -23.983765 33.014099 47839 59.349426 -25.256302 32.542877 47840 4.979062 -26.061562 27.644285 47841 59.509460 -26.312500 32.335762 47842 59.583679 -27.222336 31.931078 47843 60.278442 -26.903305 32.432175 47844 62.061020 -28.481888 33.285355 47845 61.294876 -27.353973 32.697968 47846 61.424179 -32.361908 33.054543 47847 48.284943 -33.888931 35.112480 47848 48.211914 -34.851562 36.053368 47849 48.495682 -34.028641 36.088837 47850 48.455078 -33.708817 33.422638 47851 50.020920 -33.744629 32.652039 47852 7.279777 -34.869839 29.054821 47853 6.970926 -33.800335 28.982092 47854 7.313728 -33.367348 29.999552 47855 7.674336 -33.453190 31.004858 47856 7.633239 -35.047523 29.791082 47857 52.886826 -33.927612 32.587410 47858 53.872421 -34.289215 32.131447 47859 54.811661 -34.694214 31.447863 47860 54.739685 -34.274338 32.270691 47861 59.909210 -34.131256 31.804354 47862 60.640396 -34.033524 32.006111 47863 9.439110 -36.440964 31.730158 47864 9.798889 -37.700821 31.326006 47865 8.973923 -37.366180 30.508402 47866 44.597534 -36.255234 30.855333 47867 55.556580 -34.043594 32.106239 47868 58.072296 -33.426971 32.438957 47869 9.949844 -38.725601 30.703814 47870 9.638184 -38.520233 30.314920 47871 44.874069 -36.329788 31.380671 47872 8.680466 -35.736771 31.371904 47873 50.614624 -38.376099 32.800514 47874 48.142090 -38.171997 32.056427 47875 4.483147 -41.649567 30.296961 47876 4.472588 -40.643295 30.965944 47877 5.510307 -40.672897 30.256075 47878 6.308380 -40.603790 30.239435 47879 5.711617 -39.384094 31.209772 47880 9.778656 -40.749405 30.307451 47881 7.074799 -40.323242 30.655664 47882 7.011612 -41.163055 30.044466 47883 55.860168 -41.309998 30.905855 47884 55.141083 -41.059784 31.118578 47885 55.821442 -42.623962 31.303804 47886 55.141205 -41.763168 31.212595 47887 4.070999 -42.130798 30.914507 47888 9.280998 -41.313339 30.069857 47889 54.654358 -41.197556 31.415514 47890 56.794952 -42.428238 31.059862 47891 4.553253 -44.516922 30.260904 47892 44.117142 -42.939301 30.566378 47893 42.701553 -43.350800 30.838480 47894 43.638474 -42.936661 31.990129 47895 57.346893 -44.998627 32.385307 47896 57.030106 -45.256775 32.966949 47897 56.644058 -44.652740 33.006599 47898 57.834991 -42.829834 30.970133 47899 41.748932 -44.187912 30.735346 47900 54.867905 -42.442642 31.546366 47901 55.283630 -43.287094 31.929819 47902 58.442047 -44.174759 31.095713 47903 41.517105 -44.891647 30.884562 47904 50.300323 -44.358612 32.148796 47905 51.352478 -44.782166 32.838081 47906 51.807220 -44.648178 31.820757 47907 52.440323 -44.696152 30.961809 47908 53.819656 -45.489090 31.545305 47909 56.891052 -43.924957 31.875956 47910 41.026428 -45.206787 32.710564 47911 40.837402 -44.777908 32.216141 47912 41.213150 -44.597916 31.743769 47913 44.869263 -47.254471 31.390978 47914 47.370438 -47.755478 31.283991 47915 46.150284 -47.584518 31.609278 47916 45.662048 -47.661789 32.343071 47917 52.005325 -49.737915 31.919252 47918 50.726929 -49.227997 32.071655 47919 54.047241 -50.177994 30.737856 47920 3.566513 -49.753998 31.386072 47921 4.118439 -48.189224 31.268747 47922 38.092590 -51.155731 29.263069 47923 39.292007 -51.221466 30.041346 47924 37.003204 -52.461884 30.146578 47925 37.987495 -51.800842 30.165499 47926 44.074295 -52.069672 30.456903 47927 43.886353 -52.565430 31.385118 47928 55.794037 -50.919464 31.664431 47929 56.573364 -51.295090 31.649340 47930 9.026199 -53.595047 28.940475 47931 8.210831 -54.583374 29.064903 47932 8.873856 -52.742905 28.763779 47933 9.751198 -52.798279 28.471680 47934 36.557701 -52.829102 29.797617 47935 38.791046 -52.956787 31.637056 47936 39.098946 -52.335510 31.417391 47937 37.791214 -52.867340 30.983088 47938 44.825256 -52.366196 30.454790 47939 46.453064 -53.082687 31.136065 47940 46.429443 -55.143692 32.313675 47941 47.452576 -54.354691 32.093002 47942 48.809906 -53.042603 30.599222 47943 49.132812 -53.164902 31.373072 47944 49.829773 -53.440704 31.098467 47945 9.167450 -54.293030 29.065430 47946 9.282059 -55.225357 28.991165 47947 53.574677 -54.479248 31.303576 47948 52.922119 -54.392548 30.861856 47949 53.292877 -54.848999 31.751459 47950 7.152512 -55.563309 29.061684 47951 36.747971 -53.169708 30.294580 47952 36.726410 -54.369476 30.631144 47953 52.357803 -54.261032 31.436304 47954 5.466454 -56.794510 29.316605 47955 6.600288 -56.652435 29.179298 47956 8.276596 -55.792603 29.222397 47957 8.838219 -56.759918 29.205101 47958 9.485199 -57.608231 28.866211 47959 51.589966 -54.268753 31.683840 47960 54.060776 -54.876373 31.308138 47961 55.942413 -55.335938 29.649614 47962 4.768585 -57.004456 29.542953 47963 4.165245 -57.103775 30.210726 47964 3.684235 -55.097595 31.141993 47965 7.685050 -56.582962 29.196053 47966 4.135521 -58.003494 31.219744 47967 5.228966 -58.011246 29.975473 47968 7.595932 -57.734299 29.422981 47969 8.758606 -57.784561 29.264801 47970 18.626991 -58.423187 29.449631 47971 17.584488 -58.168747 30.525728 47972 19.486679 -58.399658 29.631212 47973 8.426346 -60.327042 28.737114 47974 19.926460 -58.748657 30.287035 47975 15.450127 -60.072159 29.849504 47976 16.387558 -59.351974 29.892511 47977 21.260490 -59.401306 28.981537 47978 38.672516 -60.377243 29.864428 47979 46.637360 -59.721970 29.143616 47980 45.920990 -59.959473 29.227386 47981 44.989532 -59.690918 29.036705 47982 14.337402 -61.548569 29.462303 47983 14.008377 -62.310944 28.780304 47984 36.758987 -60.094299 30.771349 47985 41.175995 -61.609192 29.644533 47986 44.931580 -60.801422 29.462120 47987 46.274429 -61.585709 29.999865 47988 6.220413 -61.926407 28.905724 47989 7.976028 -60.811951 28.945770 47990 47.907059 -61.269318 29.877222 47991 49.013718 -61.377075 29.936136 47992 49.765350 -61.194473 29.540588 47993 49.839005 -61.721939 30.039499 47994 50.563812 -62.425262 30.119150 47995 5.095619 -63.721283 29.041710 47996 5.442566 -63.525986 30.362299 47997 5.514999 -64.761307 29.645113 47998 5.512192 -62.660233 29.358421 47999 13.619232 -62.780624 29.140579 48000 42.603210 -63.380005 30.056795 48001 41.096649 -63.528717 30.215761 48002 43.656555 -61.852020 29.602877 48003 51.223373 -62.371109 29.632288 48004 4.744804 -67.204132 28.367844 48005 20.947197 -62.962173 29.257126 48006 19.646317 -63.579575 29.876497 48007 19.855553 -64.837753 28.556137 48008 39.835800 -63.265045 30.554720 48009 38.962952 -62.114563 30.482424 48010 51.095154 -64.213760 29.580101 48011 5.065353 -65.606766 28.748970 48012 12.966278 -65.127563 29.521454 48013 12.009232 -67.659515 30.789286 48014 11.905464 -67.667618 31.786058 48015 12.427085 -66.658325 31.603167 48016 37.910873 -68.969971 29.235184 48017 49.379028 -67.342255 29.474976 48018 39.615082 -69.276947 29.171188 48019 12.447403 -66.845596 30.170237 48020 12.442978 -67.086288 28.752380 48021 11.721375 -68.427307 29.573418 48022 16.794601 -67.296265 29.842607 48023 16.334457 -68.239059 29.720560 48024 16.853958 -66.648514 30.732538 48025 26.303772 -69.556885 29.127625 48026 25.624252 -70.686874 29.751268 48027 26.151627 -69.815292 30.413286 48028 28.410919 -68.432373 29.609682 48029 28.693329 -69.317459 28.441040 48030 26.508774 -69.501129 27.953667 48031 41.314728 -69.898102 29.149338 48032 48.606598 -68.255051 30.411875 48033 48.739197 -67.796280 31.438829 48034 47.663483 -69.146545 31.598116 48035 4.856117 -69.179718 28.602402 48036 5.790619 -69.908279 28.520447 48037 8.350128 -69.822647 28.946953 48038 10.306396 -69.733047 28.949966 48039 10.878250 -69.504913 29.338219 48040 15.427597 -70.497223 28.617035 48041 25.528206 -70.902878 28.663040 48042 29.737114 -70.017029 29.665064 48043 42.249695 -70.749329 29.537186 48044 41.260956 -71.039154 30.169939 48045 42.237350 -71.718246 30.277170 48046 15.130966 -70.327957 29.575203 48047 45.796509 -70.835800 29.276184 48048 44.403549 -71.817963 29.977800 48049 25.465775 -72.563751 29.128578 48050 6.168221 -75.478729 28.970123 48051 5.824310 -76.019699 29.094688 48052 5.871483 -75.128159 27.865005 48053 6.852982 -74.241516 27.699631 48054 8.143990 -75.732452 28.804695 48055 6.897606 -74.994522 28.541344 48056 25.739014 -74.773254 28.521172 48057 29.246185 -73.090881 29.460678 48058 30.294624 -79.260468 27.946861 48059 39.290482 -75.802322 27.858292 48060 9.281311 -76.435791 28.201508 48061 40.685471 -76.523972 28.142334 48062 34.411591 -76.342361 29.408051 48063 34.332329 -74.275375 29.591537 48064 39.512566 -77.205734 28.095947 48065 5.226257 -79.146683 28.960510 48066 5.781227 -79.971527 28.335182 48067 14.418449 -80.089569 30.138674 48068 14.842133 -80.934326 29.338280 48069 26.461807 -77.708435 29.231850 48070 26.205399 -76.859909 29.334198 48071 26.201981 -78.322769 27.822731 48072 40.268753 -77.776230 28.395477 48073 41.124954 -77.836136 28.089622 48074 14.316353 -78.788925 29.413414 48075 26.232239 -79.740250 28.421890 48076 26.744110 -79.931808 29.272545 48077 26.438583 -78.727737 28.549362 48078 30.374191 -79.009567 28.577515 48079 30.474014 -79.046982 29.208183 48080 39.528427 -78.326828 28.192429 48081 13.488342 -81.526382 27.615433 48082 20.382858 -79.927307 27.847992 48083 19.135239 -81.063721 28.876701 48084 23.517609 -79.985260 28.454254 48085 22.508865 -79.798309 28.816948 48086 25.737778 -80.524384 29.030289 48087 26.517044 -80.920746 29.656733 48088 30.632797 -80.242523 27.704651 48089 30.667389 -80.037125 28.636665 48090 9.212715 -78.977142 29.282761 48091 9.794800 -80.271179 29.184265 48092 8.757797 -80.551163 29.723322 48093 12.393265 -81.093079 27.704819 48094 13.413994 -81.006760 27.222824 48095 19.697960 -82.545197 27.904846 48096 38.035820 -81.278900 27.193901 48097 39.563004 -79.151871 28.157265 48098 13.730392 -81.995544 28.146530 48099 31.094070 -81.136032 28.143906 48100 33.850662 -80.938950 29.760782 48101 12.796661 -82.090515 28.167114 48102 20.313217 -83.018921 28.164444 48103 19.512871 -82.730362 28.991043 48104 20.358223 -83.401062 29.226128 48105 23.641357 -83.948868 28.531120 48106 22.482681 -83.807129 28.508751 48107 24.959076 -84.327896 28.678772 48108 7.897186 -83.987473 27.395813 48109 7.905319 -84.799240 27.885345 48110 8.115120 -85.915512 27.449318 48111 9.500999 -87.905380 27.099030 48112 19.001236 -90.665222 26.854416 48113 25.039032 -90.682892 27.331909 48114 26.495804 -88.439026 28.436508 48115 11.496078 -90.271118 28.168144 48116 12.059364 -90.767166 27.624840 48117 21.274498 -91.291412 27.318619 48118 12.581497 -91.282104 27.957100 48119 12.468170 -90.997574 28.716377 48120 13.638725 -91.393295 27.493942 48121 18.195709 -91.197540 27.372581 48122 18.202164 -91.587830 28.632484 48123 19.325851 -91.230042 28.248589 48124 20.094070 -90.860992 27.291039 48125 20.343536 -91.189758 28.125938 48126 24.029678 -91.165527 27.387070 48127 14.802803 -91.493759 28.612305 48128 11.203201 56.742920 37.124336 48129 13.311661 55.662933 38.731628 48130 14.796211 55.243088 38.248024 48131 11.194000 56.147522 37.803459 48132 11.189957 55.595093 38.440483 48133 15.234390 55.736893 37.265701 48134 15.889420 55.143158 37.492500 48135 9.977005 54.179077 38.541550 48136 9.294113 53.457977 37.929352 48137 16.344589 54.735947 37.565872 48138 9.251221 52.866928 36.956970 48139 16.302383 53.565399 38.468521 48140 19.432556 50.600342 37.005188 48141 19.312065 50.514374 38.036766 48142 4.732658 49.024521 36.650734 48143 19.501526 49.389725 36.932632 48144 19.223801 48.635773 37.760048 48145 5.386749 49.551239 38.147568 48146 6.704880 47.502258 36.877457 48147 7.634979 47.344055 37.700890 48148 8.236038 46.816589 36.917168 48149 8.591858 46.421799 36.949020 48150 8.372269 46.468246 36.450920 48151 8.435577 45.804169 37.636040 48152 17.941391 46.259796 38.104385 48153 28.849571 46.037842 38.655327 48154 29.855843 45.437103 38.021530 48155 16.975685 44.708450 36.918419 48156 30.632294 44.220200 39.305717 48157 8.766556 44.183151 36.497185 48158 8.644371 44.767822 37.130852 48159 8.235458 44.890717 37.509995 48160 22.865288 43.194519 37.071388 48161 22.507065 42.182663 36.450302 48162 32.894394 40.246460 36.444595 48163 5.310845 40.893478 37.065636 48164 4.999130 39.833786 36.038467 48165 23.508560 41.241364 36.707344 48166 33.580368 40.907471 38.199089 48167 4.296028 39.488571 35.463760 48168 16.461670 40.802216 36.449730 48169 4.337967 38.814377 35.329033 48170 4.868103 38.958923 35.653351 48171 17.031967 42.482544 39.385025 48172 16.495987 42.139938 38.443565 48173 17.118240 41.057510 38.078308 48174 18.901558 39.205063 37.696671 48175 18.265015 40.039948 38.140862 48176 25.452118 39.289490 36.589348 48177 25.975281 40.088898 37.576996 48178 26.567673 38.423950 36.829140 48179 24.806213 40.354980 37.025467 48180 7.607391 38.510239 36.534927 48181 8.583229 37.444550 36.081108 48182 20.321228 37.291351 37.099724 48183 19.990402 38.283951 37.702461 48184 19.285339 37.693512 36.112869 48185 25.496384 38.668243 36.139954 48186 34.947693 39.151794 37.859695 48187 9.131828 37.381409 36.379143 48188 9.220398 36.957932 36.045753 48189 9.391129 37.039673 36.345116 48190 27.553558 37.577942 37.674210 48191 27.248314 37.407516 36.967194 48192 9.310936 36.645309 36.213181 48193 27.276718 36.675705 37.307404 48194 39.389587 36.538559 37.382179 48195 38.928299 36.958771 37.751556 48196 39.433838 36.027527 36.827904 48197 9.042694 36.229492 36.412048 48198 8.638901 35.259186 36.282318 48199 26.682602 35.851685 37.329567 48200 25.180161 34.752319 36.416214 48201 8.467880 34.405731 36.033745 48202 20.197380 36.202148 36.550430 48203 25.429382 35.021988 37.798309 48204 24.418442 34.172272 37.183304 48205 38.742081 35.319550 37.014107 48206 37.561356 34.999390 37.893188 48207 38.394348 35.720032 38.506920 48208 31.539276 33.475830 36.583122 48209 35.127800 34.250183 37.057228 48210 34.152603 34.749939 38.427628 48211 35.980858 34.940826 38.679840 48212 35.960526 34.321335 37.280212 48213 36.673935 34.453812 37.291969 48214 7.746513 33.441864 35.431656 48215 18.379547 32.488342 36.122459 48216 23.534653 33.082108 36.197716 48217 5.399208 33.172379 36.804321 48218 22.754959 31.518036 36.045723 48219 31.129990 32.248901 37.016785 48220 18.544922 33.593796 37.531342 48221 40.771179 29.902100 35.768394 48222 41.915054 30.418716 36.171600 48223 17.312897 31.207413 36.896866 48224 17.615341 30.033066 36.785477 48225 17.350342 30.510651 36.978882 48226 32.871559 29.551453 35.608772 48227 32.147972 30.140533 36.011696 48228 31.943789 30.851624 37.281708 48229 35.430573 29.675110 37.491135 48230 23.402557 28.688644 35.639259 48231 23.611763 29.643204 36.581604 48232 24.184372 28.787033 36.601944 48233 24.753891 28.393646 37.086845 48234 36.783768 26.333542 38.181618 48235 36.238251 24.999191 37.792587 48236 37.126488 25.116547 38.296486 48237 34.980499 27.719299 36.692543 48238 43.460999 27.652206 35.950317 48239 42.667236 28.702713 36.370163 48240 4.413628 25.870041 36.008255 48241 5.962814 24.747971 35.997231 48242 7.244705 24.488815 35.831726 48243 33.883240 26.806610 36.025734 48244 36.114449 27.629944 37.690239 48245 35.117111 25.802567 37.100517 48246 42.864655 27.658020 36.360359 48247 42.979111 26.458389 36.266129 48248 44.115280 26.685486 35.959343 48249 8.462730 24.413055 35.349564 48250 24.501480 25.914795 37.101852 48251 44.074219 25.670334 36.106606 48252 20.859467 24.598572 36.113052 48253 21.676407 23.782776 35.815689 48254 23.000015 24.718887 35.360359 48255 48.604309 24.201996 35.161163 48256 7.908546 23.596130 35.969093 48257 20.786682 23.619141 36.225296 48258 22.546326 23.381134 36.145500 48259 33.458687 23.519073 36.032539 48260 33.401321 25.032608 35.955246 48261 41.560059 26.228424 36.192757 48262 47.070847 25.082886 35.672035 48263 19.613586 21.758652 37.518288 48264 21.356911 22.790298 36.675201 48265 21.334259 21.991135 37.769714 48266 20.396271 23.232971 36.562096 48267 31.569931 23.107285 34.747749 48268 33.097916 22.704269 35.501350 48269 48.794235 23.463242 35.193192 48270 10.464363 21.349030 35.509506 48271 10.918900 21.289917 35.029648 48272 34.513664 22.726639 36.408081 48273 33.644196 22.597855 35.834557 48274 10.511978 19.806992 35.775070 48275 9.754531 21.498230 35.852493 48276 9.280472 20.653671 36.421570 48277 35.315262 21.857513 36.655235 48278 34.748260 21.698868 36.112541 48279 35.491158 21.010956 35.967262 48280 36.710518 20.341171 35.631912 48281 40.080795 19.538254 36.467049 48282 4.660851 18.497147 34.216858 48283 11.077789 17.943558 35.772003 48284 11.317094 18.685181 35.132401 48285 38.928398 20.891159 36.922310 48286 39.486977 18.370712 35.547775 48287 3.781563 17.731827 34.120232 48288 4.468956 17.852081 34.539108 48289 4.410660 17.133575 34.854713 48290 11.757095 16.357468 34.635628 48291 38.738266 17.279572 36.373940 48292 37.595985 16.812302 35.466911 48293 37.460342 16.653534 36.698639 48294 39.625328 17.814056 36.210472 48295 40.058350 18.391998 36.244560 48296 45.648773 16.774750 35.742775 48297 49.324249 17.102875 37.597298 48298 48.349640 16.860260 37.669380 48299 52.944397 16.618469 35.910622 48300 5.314865 16.570267 35.017059 48301 35.807465 16.119766 36.535568 48302 34.518234 15.642960 36.629478 48303 53.914703 15.073792 35.535088 48304 53.612885 16.017868 35.502747 48305 32.827110 15.390564 35.043800 48306 31.689180 14.587234 36.283241 48307 7.556351 13.465912 35.308975 48308 29.500885 14.112976 35.083092 48309 41.851562 14.372620 36.415024 48310 10.098236 11.889404 35.224495 48311 9.234894 11.349091 35.604584 48312 10.909821 13.611755 36.118530 48313 26.911888 11.495331 35.085068 48314 28.119972 12.981537 35.071213 48315 37.102562 12.287537 35.796188 48316 39.312668 13.294617 35.937599 48317 38.501045 13.255615 35.207863 48318 3.557335 11.028214 35.125847 48319 34.263275 11.057098 34.937225 48320 38.199982 12.524673 36.097633 48321 51.391769 12.467010 35.733589 48322 52.543762 13.012466 35.509331 48323 32.854370 10.830841 34.456444 48324 47.846497 11.948486 36.746498 48325 49.187103 11.868774 35.796021 48326 50.226273 12.546112 36.567688 48327 26.669373 10.422180 35.433456 48328 27.127502 10.422028 35.818237 48329 33.427238 10.326736 34.845268 48330 32.734756 9.318710 34.484299 48331 3.502998 10.107788 35.144440 48332 3.500519 8.980621 34.883522 48333 43.575409 9.545013 35.062592 48334 3.519371 6.933319 35.307510 48335 33.251221 8.267212 34.437805 48336 34.604935 8.343231 34.935623 48337 35.492302 7.965378 35.020676 48338 35.180077 6.990570 34.486626 48339 36.095024 7.630188 34.986794 48340 36.385307 6.682251 34.286171 48341 41.078461 7.839767 34.732857 48342 41.798843 8.305634 35.126350 48343 28.251930 4.980904 34.720741 48344 37.181870 7.797806 35.111572 48345 40.131622 7.805771 35.159363 48346 38.995087 8.336227 35.685776 48347 40.183182 8.841415 36.233398 48348 54.054245 6.752594 35.227119 48349 56.969818 5.753952 35.341560 48350 52.740234 6.827621 36.035576 48351 57.491333 4.511269 34.704025 48352 28.984703 4.247910 35.597244 48353 43.784195 4.370110 35.171608 48354 42.143524 3.459595 34.697319 48355 44.996124 5.002914 35.518547 48356 46.744766 5.157661 34.905975 48357 47.819733 5.420837 35.348747 48358 49.105133 5.475571 35.249725 48359 51.182037 6.649384 36.540352 48360 52.286484 7.357422 37.217270 48361 51.374176 7.681686 38.215591 48362 29.027878 3.246338 35.584595 48363 56.993881 3.934074 35.800720 48364 56.988831 4.911377 35.915703 48365 40.359375 2.287125 34.660156 48366 2.998253 1.036835 33.596718 48367 2.918617 1.365448 34.010330 48368 2.702843 0.856873 34.074509 48369 28.779175 1.425201 34.595032 48370 2.743363 0.166763 33.768112 48371 3.638275 0.110474 33.207886 48372 2.999336 -0.645981 33.583466 48373 2.524284 -0.565491 33.965836 48374 4.502861 -1.149612 33.216614 48375 3.644547 -1.215546 33.501686 48376 53.621811 0.185608 34.901115 48377 55.096069 1.283310 35.559845 48378 54.836166 0.373383 34.453133 48379 2.856316 -1.481934 33.973717 48380 4.163391 -2.379044 33.846321 48381 5.491699 -2.833252 33.318710 48382 29.253860 -0.744431 35.322868 48383 51.206100 -0.823105 34.560135 48384 52.380341 -0.373306 34.793503 48385 34.655579 -1.781525 35.064804 48386 34.537140 -2.314850 36.184868 48387 32.384247 -2.134949 34.901382 48388 33.625122 -2.259842 35.286636 48389 47.575043 -2.083740 35.200279 48390 48.356079 -0.936646 35.501373 48391 47.968475 -1.104630 36.606476 48392 48.555908 -0.433456 36.076866 48393 5.520653 -4.584488 33.965843 48394 53.592712 -4.011185 34.448753 48395 52.164215 -4.825607 34.604721 48396 54.408875 -3.654099 34.446495 48397 3.417109 -5.935584 26.968025 48398 45.423325 -5.515488 35.036026 48399 50.628510 -6.116531 34.677429 48400 58.903122 -5.191284 34.285233 48401 4.661199 -7.299603 30.689898 48402 5.095302 -7.518074 31.939043 48403 5.665764 -6.615326 33.703217 48404 59.608917 -6.166626 33.653755 48405 58.426025 -5.150604 34.719177 48406 3.715211 -7.388241 27.875208 48407 3.787367 -7.944087 28.060757 48408 5.488157 -7.634777 33.035610 48409 47.947052 -8.865295 35.042603 48410 46.827682 -9.422943 34.188103 48411 49.534668 -6.985855 34.459183 48412 59.582413 -7.893005 33.601723 48413 4.614039 -9.303052 30.221956 48414 5.116546 -8.478800 31.764883 48415 48.613907 -7.818558 34.371399 48416 50.340210 -7.478439 36.265839 48417 5.141390 -9.445354 31.602819 48418 5.306576 -10.465697 31.778589 48419 5.621658 -9.515857 32.802395 48420 5.745475 -10.358398 32.853699 48421 41.836304 -8.616211 34.819473 48422 41.376953 -9.411285 34.272247 48423 4.106879 -9.781174 28.796770 48424 4.063404 -9.212146 28.741550 48425 4.032550 -8.518742 28.714880 48426 41.144791 -10.213791 34.381264 48427 40.972046 -9.446259 34.908295 48428 40.633377 -10.242996 34.699875 48429 41.648972 -10.015854 33.923576 48430 45.808929 -10.234116 34.131065 48431 51.481766 -10.393570 34.207016 48432 51.789124 -10.193008 34.239426 48433 52.349304 -9.979935 34.387367 48434 3.738151 -9.602633 27.702721 48435 3.785538 -10.285553 27.748398 48436 4.041533 -11.312653 28.349043 48437 4.224060 -10.424921 29.022877 48438 42.074585 -11.029343 34.106201 48439 44.949768 -10.666565 34.013153 48440 50.449722 -11.246170 33.854935 48441 51.002365 -10.907333 34.176147 48442 3.770376 -10.992363 27.627281 48443 50.127319 -11.962021 33.935204 48444 3.759124 -11.636456 27.420185 48445 5.698291 -11.880990 32.415421 48446 6.273468 -12.113831 33.956497 48447 6.175233 -13.323388 33.023891 48448 50.363403 -12.600357 34.532990 48449 6.316583 -14.892765 32.719772 48450 5.754687 -14.164752 31.885962 48451 3.777094 -14.521672 26.756903 48452 5.305521 -14.677631 30.820482 48453 7.081429 -14.358292 33.680916 48454 5.717400 -15.671846 31.450487 48455 6.165701 -17.800890 31.998533 48456 5.838134 -17.021778 31.464178 48457 6.437365 -16.344017 32.724426 48458 4.403349 -16.756647 28.332708 48459 6.732632 -17.767775 33.088646 48460 5.600719 -18.528084 30.707830 48461 5.714049 -20.069681 30.677526 48462 51.474854 -17.297714 33.696663 48463 50.892883 -15.746643 34.052872 48464 52.187881 -15.426025 34.358688 48465 5.858819 -21.475578 30.714357 48466 6.236078 -19.137880 31.978182 48467 6.051506 -22.752672 30.820005 48468 6.179741 -20.559547 31.619528 48469 6.464101 -21.834555 31.922388 48470 53.171143 -17.081802 34.296120 48471 6.224923 -24.278082 30.730692 48472 6.487127 -23.211454 31.551188 48473 45.013245 -20.648438 33.850655 48474 43.702271 -20.822937 34.507004 48475 6.659428 -24.391472 31.482119 48476 41.803894 -21.844543 33.626831 48477 43.110901 -20.973419 34.476097 48478 50.326614 -20.580658 33.929039 48479 49.315277 -20.645660 35.035858 48480 50.037079 -20.667465 35.146431 48481 51.557831 -20.309402 34.665092 48482 6.489308 -25.967873 30.673311 48483 41.573914 -22.869492 33.495865 48484 59.938919 -22.038864 34.271881 48485 59.218262 -21.736710 34.617897 48486 60.785233 -22.786285 34.288391 48487 60.109055 -22.834671 33.620750 48488 60.650497 -23.432114 33.498810 48489 5.023431 -25.239367 28.011181 48490 55.827850 -23.410614 33.154724 48491 55.106079 -23.781891 32.980629 48492 55.520706 -23.473816 34.145470 48493 58.147430 -22.048492 34.577484 48494 5.956948 -26.924694 29.478205 48495 5.218672 -26.966999 27.967932 48496 7.118231 -26.872820 31.337946 48497 7.050713 -25.108704 31.835581 48498 7.581972 -25.829086 32.187222 48499 43.489746 -24.563904 33.905182 48500 40.970276 -25.430252 34.600601 48501 40.565399 -24.667389 34.101357 48502 40.827301 -24.495865 33.930283 48503 52.714142 -24.662766 33.344254 48504 60.821808 -24.142960 33.432938 48505 61.067078 -23.576660 33.795654 48506 61.241791 -24.098236 34.287231 48507 60.725143 -25.499023 33.162582 48508 5.632160 -27.743711 28.705862 48509 7.822029 -27.163706 32.002483 48510 49.135284 -25.101852 35.394791 48511 46.173630 -25.372009 36.400215 48512 62.024384 -25.730698 34.661842 48513 61.622925 -25.221664 34.293892 48514 61.846710 -26.366959 33.735207 48515 62.207977 -27.293961 33.965439 48516 61.938446 -27.337326 33.303680 48517 5.329663 -27.626755 28.161966 48518 5.161180 -27.839451 27.727934 48519 6.668656 -27.846884 30.444536 48520 8.413028 -27.749804 32.296841 48521 8.861732 -28.531876 32.473053 48522 8.041145 -28.617849 32.001465 48523 62.142395 -28.048523 34.604637 48524 5.382685 -28.115589 28.179031 48525 5.546673 -28.719610 28.321733 48526 5.920817 -28.782463 28.960155 48527 6.254458 -28.590263 29.576605 48528 7.384225 -28.784689 31.301573 48529 7.253937 -30.520350 30.803209 48530 6.941763 -29.695547 30.434065 48531 62.020203 -28.962494 34.580208 48532 5.223316 -28.409737 27.735903 48533 7.457764 -30.467438 31.215654 48534 7.685604 -30.724726 31.650618 48535 5.155484 -29.467371 27.189146 48536 5.282125 -29.008633 27.671141 48537 6.549209 -29.383307 29.860464 48538 7.130304 -31.705633 30.241999 48539 6.867845 -31.095814 29.918566 48540 7.514358 -31.976303 31.045599 48541 6.746501 -32.250946 29.260246 48542 6.643384 -30.615433 29.657961 48543 5.270403 -30.946190 26.885736 48544 5.467087 -30.498196 27.511953 48545 5.912923 -30.922506 28.233126 48546 6.296819 -30.561073 29.045128 48547 5.644298 -29.705965 28.190613 48548 5.936965 -29.979082 28.638996 48549 61.572830 -31.172089 34.047203 48550 60.318253 -32.073318 33.921524 48551 60.398834 -32.976349 33.265541 48552 62.091843 -31.159515 33.087044 48553 5.511008 -31.294949 27.308409 48554 5.821961 -31.753742 27.706808 48555 7.741861 -32.592499 31.581480 48556 8.030281 -34.498734 31.592005 48557 7.840797 -33.264130 31.931108 48558 45.471283 -35.171585 32.334099 48559 46.113144 -34.663727 33.106445 48560 51.096085 -33.181351 33.438553 48561 54.659912 -33.729828 32.713478 48562 56.828094 -33.114304 32.566307 48563 59.353577 -33.249405 32.834389 48564 60.627808 -33.502182 32.563866 48565 60.833923 -30.912903 34.757935 48566 9.562996 -36.724274 32.488190 48567 45.172287 -36.185379 31.997972 48568 9.228317 -35.573776 32.318069 48569 9.463127 -35.983017 32.483841 48570 45.724213 -36.733948 32.489746 48571 8.455743 -38.754456 31.958193 48572 8.939011 -40.416061 30.976557 48573 9.519470 -39.874649 31.259699 48574 4.079048 -39.736389 31.849497 48575 4.514404 -39.342957 31.587732 48576 4.120331 -38.944229 32.453506 48577 7.107819 -39.014465 31.551065 48578 51.905533 -38.828613 32.934975 48579 52.897308 -39.782639 33.031609 48580 4.554878 -38.112091 32.507950 48581 7.210754 -37.367554 32.597626 48582 7.965438 -40.034882 31.078333 48583 9.922508 -39.980789 30.825968 48584 9.726288 -38.736374 31.490236 48585 53.877655 -40.740677 32.005066 48586 54.678284 -41.833115 31.433664 48587 54.293640 -41.830200 31.755602 48588 3.757805 -43.075790 31.706430 48589 4.151520 -44.098740 31.152987 48590 45.034790 -43.103592 31.654459 48591 46.204834 -43.464386 32.709267 48592 54.368011 -42.661346 32.060043 48593 53.898193 -41.925140 32.395729 48594 54.047302 -42.654602 32.483650 48595 41.857773 -43.671249 31.759859 48596 41.282776 -43.716995 32.691475 48597 40.870087 -44.394012 32.602608 48598 42.594666 -43.178314 32.023163 48599 53.976196 -42.363113 32.948402 48600 54.704224 -43.205368 32.880959 48601 56.027985 -44.187820 32.885567 48602 55.543762 -43.848694 32.475388 48603 4.496719 -45.110382 31.192667 48604 4.952255 -46.111252 30.707895 48605 4.875923 -46.002426 31.554041 48606 5.174996 -46.140854 31.125154 48607 42.525269 -47.020905 32.495750 48608 52.243958 -45.037125 32.647812 48609 52.843124 -45.044800 31.763788 48610 3.970978 -46.223526 33.502106 48611 4.191162 -46.910233 34.426590 48612 3.949654 -48.120346 33.173584 48613 56.805069 -46.714508 31.467501 48614 56.739319 -46.292221 32.308830 48615 54.973328 -45.927414 32.696198 48616 57.481537 -45.786926 32.335434 48617 43.601562 -47.347656 32.535416 48618 44.838852 -47.598495 32.626610 48619 48.669495 -48.130371 31.239466 48620 46.872894 -48.108902 32.560905 48621 48.422455 -48.406647 32.213364 48622 49.731567 -48.669006 31.643427 48623 49.591415 -49.157959 32.690392 48624 53.433655 -50.026794 31.557619 48625 50.744080 -49.745102 32.872879 48626 3.700173 -51.981537 32.372559 48627 3.794022 -53.051865 32.560616 48628 54.623260 -50.412796 31.640566 48629 53.965851 -50.387177 32.453995 48630 39.034164 -51.802292 30.910028 48631 40.008347 -51.553635 30.866282 48632 40.905548 -51.899948 31.148767 48633 41.794556 -52.515472 31.603807 48634 40.000961 -52.064743 31.399233 48635 45.011246 -52.840118 31.608004 48636 48.241577 -53.334656 31.480036 48637 57.602493 -52.361633 31.408831 48638 57.633163 -52.696350 31.327074 48639 57.768509 -52.529160 31.573427 48640 37.634048 -54.367371 31.631014 48641 50.621414 -54.047745 31.649630 48642 50.904602 -55.656250 32.378510 48643 52.225433 -55.518219 32.247269 48644 57.322021 -53.343430 31.491808 48645 57.613037 -52.751205 31.729929 48646 3.683411 -56.202545 30.934816 48647 54.270493 -55.718628 32.351959 48648 36.789276 -55.665771 31.320673 48649 3.681152 -57.212601 31.141069 48650 36.243065 -56.463120 31.048098 48651 6.300537 -57.631042 29.486084 48652 18.739197 -58.332581 31.365526 48653 35.970673 -59.253998 30.750124 48654 36.161591 -58.532913 30.726099 48655 6.457832 -58.443420 29.808832 48656 7.335205 -58.697601 29.763826 48657 6.507721 -59.131363 30.165094 48658 7.356697 -59.483475 29.944368 48659 16.140793 -58.859711 31.574007 48660 16.836128 -58.258545 31.427629 48661 20.892792 -59.637939 29.886637 48662 36.147156 -59.580566 30.755175 48663 4.917008 -59.004761 31.104532 48664 5.719803 -58.883621 30.281206 48665 7.842216 -60.287292 29.410568 48666 15.565720 -59.667343 31.090242 48667 19.803070 -59.945328 31.248270 48668 6.448197 -59.844208 30.429064 48669 7.092911 -60.374741 29.952608 48670 21.749062 -60.561844 29.562813 48671 20.724976 -61.201614 30.252535 48672 14.865768 -60.776321 30.445711 48673 13.856453 -62.253708 29.606363 48674 48.975494 -62.367172 30.476168 48675 5.294434 -61.507904 31.581423 48676 5.434204 -62.515945 30.532267 48677 6.044289 -61.845520 29.961191 48678 14.205414 -62.027710 30.487589 48679 13.542252 -63.360901 29.943796 48680 14.008179 -62.934204 31.113840 48681 19.800613 -62.350388 30.656481 48682 44.975250 -62.204147 29.955790 48683 45.808411 -63.313934 30.601351 48684 46.631409 -62.665833 30.543451 48685 47.469742 -62.521240 30.596918 48686 13.345642 -64.277252 30.684610 48687 38.247650 -63.170151 31.669168 48688 37.330788 -61.473938 31.453226 48689 39.751205 -64.429031 31.649782 48690 44.242661 -63.339340 30.220858 48691 44.818237 -64.605957 31.048151 48692 46.925140 -63.352646 30.972757 48693 48.079163 -64.252472 31.709749 48694 41.624268 -64.918274 31.310114 48695 43.478027 -64.707565 30.974184 48696 45.835663 -64.691956 31.470476 48697 45.206970 -65.727234 32.215858 48698 50.581726 -64.323059 30.348780 48699 6.151947 -64.976746 30.245073 48700 5.927124 -65.519684 30.051432 48701 18.252197 -64.714722 30.999086 48702 17.760880 -65.372177 31.078211 48703 19.119164 -63.417023 30.900667 48704 18.694626 -64.032623 30.981905 48705 44.152374 -65.722153 31.954233 48706 42.987198 -66.110321 32.505348 48707 40.492889 -64.118835 30.820795 48708 50.031143 -65.508545 30.459558 48709 5.003571 -67.043671 29.981760 48710 4.624939 -68.468475 29.965075 48711 5.692932 -66.395828 30.528948 48712 5.350746 -66.023682 29.503014 48713 31.513474 -65.561584 31.106569 48714 31.117439 -66.300934 30.494417 48715 30.426132 -65.851028 30.664263 48716 31.658052 -66.611420 30.867373 48717 29.020737 -67.338577 30.381235 48718 30.058563 -66.811432 30.291491 48719 29.961517 -68.373642 30.079088 48720 30.679153 -66.488739 30.285471 48721 30.958496 -67.186935 30.467173 48722 49.373901 -66.987091 30.386873 48723 49.593079 -65.951843 31.191820 48724 29.244293 -69.266983 29.138565 48725 15.642181 -69.112015 30.104136 48726 25.948517 -70.654999 30.774782 48727 27.254318 -68.723709 29.817759 48728 26.742294 -69.058838 30.578379 48729 35.300430 -70.567078 29.742937 48730 36.272194 -71.059784 30.723543 48731 37.102341 -70.874207 30.711275 48732 5.121185 -70.118393 29.029945 48733 4.737877 -69.792740 29.450615 48734 4.298462 -69.159470 31.504061 48735 4.971924 -67.482574 31.263651 48736 4.410706 -68.056396 32.827042 48737 7.138771 -70.587570 29.776606 48738 8.525787 -71.324097 31.222422 48739 9.409959 -70.969513 31.204493 48740 9.246872 -70.505951 30.139208 48741 10.217018 -70.044373 29.617182 48742 15.036438 -69.719620 31.271311 48743 15.715439 -68.525574 31.448793 48744 15.920242 -68.206711 30.711519 48745 38.177765 -71.035202 30.766092 48746 39.295067 -70.390594 30.299814 48747 40.348175 -70.405426 29.984697 48748 48.290359 -67.759781 32.665924 48749 5.091438 -70.451828 29.640940 48750 5.713348 -70.513153 29.412827 48751 14.341621 -71.496826 30.386103 48752 29.973175 -71.082169 30.635378 48753 43.292877 -71.221039 29.604372 48754 14.001312 -71.397873 32.117073 48755 13.362900 -72.491241 31.414995 48756 29.419174 -73.097931 29.971628 48757 45.257019 -71.789017 30.468767 48758 43.951660 -72.667236 30.730051 48759 44.737335 -72.245850 30.879946 48760 45.811890 -71.438110 30.719355 48761 34.655991 -72.723221 30.138659 48762 34.821510 -71.417801 29.887362 48763 25.632500 -73.852707 29.756952 48764 25.778275 -74.569504 29.734529 48765 25.587029 -71.533905 30.382830 48766 29.531540 -73.891541 29.822687 48767 6.568726 -76.502396 29.918062 48768 13.396973 -75.065460 29.144386 48769 12.717567 -75.094406 30.194208 48770 26.038132 -75.619522 29.843287 48771 8.913239 -76.771912 28.818886 48772 8.450226 -76.873810 29.346085 48773 35.226318 -73.764465 31.241472 48774 35.068527 -76.901764 31.289034 48775 35.081886 -76.001114 31.328737 48776 5.772499 -76.621124 29.593384 48777 13.998703 -77.954834 29.133095 48778 14.488937 -78.150436 28.701630 48779 5.419945 -78.118332 29.911753 48780 5.776459 -77.242325 30.102320 48781 5.133240 -78.365112 29.166260 48782 8.954773 -77.699142 29.124207 48783 8.437881 -77.949677 29.720598 48784 13.162827 -75.966919 29.324341 48785 13.439949 -77.086578 29.323891 48786 30.175713 -76.751663 30.181276 48787 29.974548 -75.006622 30.669741 48788 7.064270 -78.042175 30.568720 48789 7.917511 -78.217972 30.223276 48790 7.869590 -79.292313 30.439936 48791 26.836655 -78.461075 30.047380 48792 26.396561 -76.947998 30.174242 48793 21.838264 -79.976349 29.742281 48794 31.197754 -81.137115 29.151268 48795 10.824493 -80.803436 28.556358 48796 14.893417 -81.221634 28.654045 48797 24.615936 -80.240753 28.740921 48798 6.429657 -80.547104 29.139687 48799 11.623413 -82.007263 28.515076 48800 14.387619 -81.868896 28.958481 48801 18.917168 -81.815964 29.399719 48802 19.144608 -80.920395 29.747240 48803 31.017525 -80.145386 29.982943 48804 32.774971 -81.701141 29.556900 48805 8.109558 -83.279770 28.436073 48806 7.541069 -81.252182 29.345779 48807 8.739075 -82.133301 29.197952 48808 12.379364 -82.809235 28.710495 48809 13.369019 -82.805878 28.859283 48810 31.795641 -81.679657 28.869598 48811 32.016174 -81.469742 30.159304 48812 33.319618 -81.711655 31.062654 48813 11.450745 -83.055054 29.190536 48814 12.573898 -83.588898 29.523666 48815 11.546738 -83.797653 30.128061 48816 19.702072 -83.633881 30.071024 48817 25.845879 -84.686554 28.485153 48818 25.601654 -85.411392 29.478638 48819 8.794907 -84.488754 29.567444 48820 8.139450 -84.870239 28.731094 48821 9.351524 -83.357635 29.266815 48822 24.285355 -85.115005 29.979387 48823 8.012238 -85.691574 28.336792 48824 26.308136 -85.663086 28.666565 48825 8.327423 -86.559967 28.211121 48826 8.765701 -87.005905 27.253090 48827 26.149048 -86.743942 29.742205 48828 8.937157 -87.545502 28.537430 48829 26.513504 -87.622162 29.175705 48830 26.023438 -89.141327 29.152328 48831 26.226517 -88.331711 29.622210 48832 10.951416 -89.690659 29.512520 48833 24.608490 -90.418777 28.562447 48834 23.119598 -91.087891 28.541046 48835 23.797882 -90.563370 29.522430 48836 12.991058 -91.459885 27.781471 48837 18.982025 -91.489655 29.251808 48838 20.963577 -91.325790 28.413040 48839 17.451477 -91.505753 29.509865 48840 18.327209 -91.432480 29.797838 48841 21.453796 -91.447510 28.260910 48842 22.061600 -91.454865 28.107338 48843 12.150909 56.254349 37.989769 48844 14.019943 54.875992 39.090919 48845 13.057327 54.919388 39.533104 48846 10.527527 54.841507 38.486374 48847 15.879639 54.529083 38.172256 48848 8.769714 52.595123 37.302475 48849 8.335030 52.747513 37.927055 48850 7.478340 52.474701 38.241966 48851 6.472931 51.662415 37.945740 48852 18.315102 51.530777 39.164963 48853 4.986130 49.953873 37.507347 48854 4.773956 49.558655 37.405273 48855 6.787216 52.772308 39.409950 48856 5.728958 52.029144 39.776237 48857 5.728760 51.268021 38.794952 48858 5.540611 50.611023 37.722900 48859 6.317886 48.776337 38.882332 48860 6.480805 48.219055 37.890816 48861 5.886177 49.488281 39.536522 48862 6.618500 48.746902 40.022812 48863 7.766181 47.379471 38.887032 48864 8.218552 47.051285 38.346069 48865 18.345009 46.488388 39.607208 48866 19.015327 47.229324 39.978752 48867 8.419136 46.748749 37.675255 48868 26.205719 46.219650 38.719650 48869 25.448105 45.947189 38.674072 48870 27.627953 46.529449 38.419548 48871 29.369446 45.332611 39.254898 48872 19.284988 48.528290 39.279488 48873 22.949081 44.281860 37.065727 48874 7.105835 44.782028 37.822006 48875 5.767143 44.644760 38.461983 48876 5.904953 44.293488 37.944565 48877 17.113525 44.871643 39.438866 48878 17.635712 45.652832 39.478592 48879 24.450661 44.490616 38.241837 48880 5.983986 43.738846 37.354652 48881 16.272217 42.237106 37.500259 48882 16.188210 42.995117 38.482910 48883 23.600655 43.429230 37.720001 48884 24.422401 43.150360 38.244064 48885 32.192093 42.822189 38.817299 48886 31.667894 43.144470 40.124733 48887 5.252289 42.935837 37.446426 48888 5.370148 42.183640 38.527420 48889 23.022934 42.187363 37.010437 48890 23.689392 42.332458 37.483017 48891 33.165344 41.759415 38.940895 48892 24.384483 41.402420 37.462051 48893 24.717606 42.139832 38.060661 48894 25.310303 41.189377 37.904335 48895 6.252030 39.717209 37.069336 48896 28.063858 37.643158 38.396645 48897 27.713715 38.926086 38.524261 48898 8.599289 38.666656 37.777229 48899 8.400528 39.713470 38.957573 48900 8.307121 38.803711 39.129753 48901 34.889755 39.949097 39.698967 48902 34.210114 40.618134 39.642235 48903 7.706047 39.682297 37.969788 48904 8.227539 38.809601 37.166824 48905 6.517098 40.795410 38.504173 48906 8.607574 38.038544 36.757095 48907 18.987030 38.667480 37.103020 48908 28.133369 38.770569 39.806305 48909 28.222420 38.098358 38.869682 48910 35.805138 38.638702 37.766350 48911 36.473511 37.682037 40.753319 48912 36.421547 38.546539 39.678627 48913 37.795212 37.267700 39.000778 48914 9.033539 37.217987 36.901726 48915 36.568375 38.418594 38.634811 48916 8.494972 36.364166 37.311508 48917 7.775390 35.118317 37.075737 48918 7.703674 34.325607 36.665375 48919 8.212852 34.499908 36.450363 48920 20.747513 36.707703 37.778809 48921 20.663803 37.406342 37.679871 48922 6.683815 35.226852 37.721107 48923 5.946846 35.473572 38.418793 48924 5.534874 34.357758 37.906540 48925 18.745697 34.481857 38.714912 48926 20.328697 35.691010 38.018318 48927 19.623215 35.214996 39.085777 48928 26.179611 35.414398 37.478165 48929 27.048592 36.186401 38.170021 48930 26.278091 35.661499 38.351326 48931 38.951759 36.308853 37.987480 48932 32.164238 33.888565 37.162979 48933 32.851883 34.488541 38.071465 48934 6.794815 34.130493 36.904182 48935 7.799095 33.885742 36.108406 48936 24.523979 34.351761 38.414879 48937 31.241142 33.168930 37.148354 48938 31.521317 33.532028 37.284477 48939 17.481842 32.368759 37.685555 48940 23.152283 31.674683 37.078995 48941 22.818405 31.525620 36.476974 48942 3.660133 29.502594 36.241440 48943 18.313095 29.255997 36.682571 48944 31.354248 32.032532 38.191269 48945 32.906586 30.617096 38.174904 48946 35.770035 28.634552 37.281052 48947 35.743256 30.393967 38.594620 48948 34.843353 30.509918 38.282127 48949 41.296326 28.777466 36.329262 48950 41.674515 29.555084 36.408485 48951 3.483902 29.549332 37.536041 48952 3.231659 29.002197 37.180511 48953 3.292870 28.485458 36.683403 48954 41.811447 27.550461 36.333115 48955 24.965942 27.441254 37.291656 48956 19.255226 29.214142 38.619209 48957 17.991104 30.825287 38.917870 48958 17.821335 30.095093 37.654877 48959 3.330490 27.567490 36.704407 48960 4.883270 25.316071 36.109848 48961 3.946739 25.223465 36.895454 48962 19.861908 27.512527 37.035515 48963 25.506386 27.775040 38.278893 48964 25.208260 27.066956 39.133301 48965 46.106964 24.724091 35.947807 48966 4.870041 24.361115 36.697487 48967 20.280548 25.662811 37.275192 48968 23.969620 24.583801 37.742226 48969 24.401764 25.655457 38.988335 48970 8.981720 22.848022 35.767212 48971 19.922150 24.143066 37.130508 48972 34.306671 24.170517 36.576073 48973 35.470413 24.000977 37.254425 48974 7.920288 22.665939 36.321228 48975 6.837952 23.386688 36.399872 48976 19.739349 22.972382 37.138702 48977 8.582001 21.670105 36.381821 48978 20.518021 21.164215 37.932312 48979 22.819107 23.071304 36.816383 48980 36.147301 22.559631 37.347176 48981 9.647942 18.157928 37.123062 48982 10.465256 18.203568 36.447296 48983 37.571487 20.870239 36.683220 48984 36.610840 20.925156 36.546539 48985 38.692810 22.587143 38.099724 48986 37.750885 21.794952 37.582153 48987 41.561996 19.654037 37.698853 48988 40.446747 18.217438 37.249146 48989 11.425842 16.244568 35.391586 48990 10.620987 16.517624 36.595207 48991 11.067062 14.974426 35.963799 48992 39.759796 17.115417 38.422707 48993 39.565620 17.505829 37.174942 48994 38.760544 17.075653 37.404243 48995 46.452728 16.836029 36.525253 48996 50.188568 16.771744 37.829224 48997 3.329178 15.699280 34.934914 48998 5.403710 15.650665 35.387794 48999 4.457993 15.901581 35.458099 49000 3.676201 15.583374 35.398018 49001 36.420052 16.110001 37.537590 49002 35.094238 15.633102 37.404518 49003 45.475845 16.386597 36.581474 49004 53.290909 15.409912 36.245224 49005 5.931198 14.812195 35.548141 49006 33.150391 15.280960 36.356621 49007 32.419495 14.677963 37.174652 49008 3.544670 13.807144 35.907005 49009 3.365166 12.681519 35.429214 49010 5.051285 15.003830 35.784821 49011 6.415085 13.649170 35.971565 49012 30.080475 13.136185 36.547523 49013 40.699585 13.702972 36.337402 49014 5.109009 13.967743 36.248024 49015 8.076447 12.112579 35.782845 49016 10.688629 12.229645 35.966530 49017 10.690842 12.976532 37.176277 49018 27.744492 11.426666 35.852142 49019 35.858604 11.181213 35.696747 49020 10.200165 11.261505 35.870796 49021 10.687469 11.363174 37.004005 49022 34.969559 10.160233 35.356003 49023 36.722069 11.535614 36.071259 49024 45.796646 11.721848 37.872543 49025 46.553009 11.575958 36.247398 49026 9.247406 9.909851 36.716423 49027 8.040894 10.443283 37.003883 49028 46.747711 11.791992 37.307831 49029 26.700485 9.648895 35.458588 49030 33.756767 9.283615 34.942215 49031 36.455566 10.394653 35.990341 49032 36.058975 8.852646 35.431168 49033 46.989853 12.033554 38.106125 49034 37.507416 9.352417 35.993202 49035 38.047882 8.376617 35.625801 49036 38.330078 8.973389 36.014053 49037 43.053589 9.166702 35.735413 49038 44.296005 10.266144 35.975563 49039 3.460343 8.138367 35.810585 49040 3.909882 5.750809 35.501038 49041 27.345200 9.415085 35.943153 49042 41.027267 8.277145 35.660332 49043 54.944473 7.302841 36.136002 49044 54.219421 7.275452 36.292526 49045 54.891830 7.441727 36.572113 49046 55.587341 6.925095 36.514442 49047 29.081329 5.606995 35.854599 49048 28.746643 6.995453 36.071487 49049 27.846703 7.534683 35.577972 49050 55.736511 6.606369 37.626793 49051 54.690903 7.526306 37.751816 49052 29.532745 6.425278 36.397606 49053 45.929794 5.376038 35.581024 49054 49.587250 6.587265 36.955330 49055 42.831146 3.719101 36.468033 49056 45.561234 5.478020 36.791428 49057 44.192169 4.717628 36.515099 49058 47.122559 6.139496 37.085800 49059 46.654251 5.618500 35.954453 49060 48.393387 6.236969 36.665871 49061 48.044861 6.926804 38.364044 49062 3.895043 2.222336 34.915817 49063 41.575684 2.897110 35.668945 49064 41.542786 2.507568 36.687447 49065 40.761276 2.154633 35.831406 49066 2.440735 0.015274 34.590561 49067 3.129006 1.221710 34.779724 49068 28.730270 2.424698 35.136902 49069 39.717224 1.466339 35.656891 49070 28.927689 0.440201 35.009262 49071 53.999054 1.437378 36.810814 49072 54.835266 1.995041 36.946335 49073 2.170563 -0.841629 34.336937 49074 2.052811 -0.598679 34.758217 49075 1.906075 -1.041458 34.740547 49076 28.969635 -0.210480 35.226036 49077 50.170563 -0.174789 35.892784 49078 49.122681 -0.575775 35.536819 49079 48.950974 0.153793 36.887947 49080 52.562378 0.218124 35.708237 49081 53.417648 0.754227 36.080414 49082 2.102211 -1.659149 34.529739 49083 1.857224 -1.498184 34.968391 49084 29.318817 0.004562 35.944794 49085 46.893341 -3.504028 35.389099 49086 51.457993 0.071640 35.953491 49087 3.826447 -3.724960 34.413788 49088 3.856049 -5.155197 34.941376 49089 4.736633 -4.522400 34.532265 49090 2.773682 -2.727402 34.516930 49091 5.116989 -2.879257 33.785774 49092 29.746788 -1.124741 36.477692 49093 2.832504 -4.088150 35.013405 49094 2.137215 -3.401962 35.292023 49095 4.681229 -3.492569 34.134285 49096 5.302139 -3.821808 33.975128 49097 48.298065 -3.845383 37.779861 49098 47.415802 -3.376144 36.471802 49099 47.321457 -5.091034 37.096230 49100 56.521576 -3.144562 35.632088 49101 55.982758 -3.167816 37.064476 49102 55.680511 -3.121872 36.476555 49103 56.716492 -3.612762 36.506783 49104 57.132690 -3.527985 35.598701 49105 46.272064 -4.314804 35.005592 49106 53.393646 -3.953613 35.573242 49107 57.556168 -4.459885 35.437408 49108 5.590721 -6.372177 34.316147 49109 57.056198 -4.747940 36.633842 49110 56.784302 -6.375671 35.478409 49111 57.195602 -5.487183 35.795166 49112 5.826630 -7.177719 34.176903 49113 44.050461 -6.724121 34.956192 49114 43.204163 -7.320724 34.845230 49115 44.909546 -6.812317 36.047630 49116 43.128113 -7.847855 35.714417 49117 51.947021 -5.536682 36.022774 49118 5.936974 -7.921951 34.336304 49119 5.691096 -8.630390 33.293201 49120 6.118317 -8.575958 34.393173 49121 54.636932 -8.724503 36.052246 49122 6.195015 -9.513138 34.334259 49123 53.768768 -9.124741 35.347275 49124 52.861023 -9.941818 35.260788 49125 6.209091 -10.346725 33.826424 49126 6.554672 -10.338776 34.236855 49127 40.418915 -10.141830 35.119110 49128 48.016830 -11.382706 37.270927 49129 46.541550 -11.922806 36.562981 49130 47.025772 -10.367615 35.677864 49131 48.638947 -9.335037 36.389717 49132 48.493561 -10.307739 37.058983 49133 51.736649 -10.725937 34.866440 49134 52.325668 -10.995377 35.586990 49135 5.909838 -11.144816 33.106323 49136 6.380715 -11.022690 34.201912 49137 40.465652 -11.322601 34.858078 49138 40.055420 -10.462952 35.851051 49139 39.626862 -11.293381 35.677376 49140 44.920685 -11.477692 35.081398 49141 39.324661 -12.498749 35.708458 49142 43.421677 -11.301041 34.378761 49143 43.140350 -12.058899 34.905983 49144 50.478012 -11.684448 34.401161 49145 40.298401 -13.015686 34.820343 49146 41.629944 -12.495956 34.710808 49147 6.885185 -13.836563 34.076698 49148 7.082466 -14.317200 34.087837 49149 41.314575 -14.102417 35.052246 49150 40.231232 -14.559418 34.782059 49151 40.035980 -14.021271 34.754265 49152 50.938049 -12.910248 34.851814 49153 51.465729 -14.000381 34.644981 49154 52.475616 -13.840683 34.938995 49155 51.913147 -12.282700 35.240173 49156 6.996521 -15.169174 33.943962 49157 39.489334 -13.651047 35.011162 49158 39.398590 -14.742447 35.079018 49159 39.005936 -13.886612 35.386490 49160 38.696411 -14.640839 35.397865 49161 53.472351 -14.872879 34.809166 49162 7.179352 -16.548126 34.043457 49163 49.883362 -15.636063 33.869148 49164 54.785645 -15.859634 34.932076 49165 55.118652 -14.103806 35.543762 49166 57.011627 -15.373199 36.138527 49167 56.695374 -14.219009 35.943008 49168 6.638363 -20.331657 32.703632 49169 53.425629 -18.655090 34.666756 49170 54.618469 -16.972519 34.700394 49171 56.309479 -13.518204 36.014610 49172 55.299225 -17.629288 35.092705 49173 55.900833 -16.691833 35.285477 49174 6.813447 -19.051811 33.298214 49175 7.423782 -18.064362 34.221756 49176 54.237915 -17.769562 34.674675 49177 52.680374 -19.727081 35.187332 49178 53.738403 -19.219849 35.711411 49179 54.634094 -18.509415 35.365273 49180 7.015304 -23.146425 32.549503 49181 54.689331 -19.002090 36.804085 49182 55.300751 -18.687393 35.923782 49183 6.924405 -21.466974 33.127178 49184 45.481461 -20.703705 35.419624 49185 46.820892 -20.559128 34.895729 49186 47.433304 -20.609772 36.486778 49187 48.334076 -20.492493 35.616348 49188 7.591522 -22.986923 33.642151 49189 7.561562 -24.429190 32.854160 49190 40.949844 -22.119293 34.373238 49191 40.730652 -22.844284 33.940468 49192 41.759949 -21.498642 34.197571 49193 42.477982 -21.232788 34.578392 49194 50.798141 -20.562012 35.319733 49195 51.844696 -20.294388 35.659264 49196 42.203888 -23.912048 33.516289 49197 57.061951 -22.586594 34.208580 49198 40.139618 -23.098328 34.416466 49199 40.018829 -22.528625 35.056610 49200 41.344101 -24.162003 33.826454 49201 40.658875 -23.785278 33.902519 49202 56.939880 -22.507034 35.363182 49203 8.221100 -24.933472 33.606537 49204 8.329178 -25.538284 32.864632 49205 8.706612 -25.569122 33.345398 49206 42.262177 -25.054199 34.552574 49207 44.589966 -24.762207 34.123383 49208 53.780701 -24.368896 34.303032 49209 55.643295 -23.378220 35.246284 49210 54.621582 -23.903885 35.219032 49211 8.577850 -26.798477 32.531639 49212 52.345032 -24.919601 34.725136 49213 53.470215 -24.448975 35.266838 49214 62.202484 -26.513260 34.497711 49215 8.617050 -25.794983 33.742195 49216 8.785538 -26.607880 33.250862 49217 51.590729 -25.309586 34.357079 49218 51.380157 -25.330185 34.861153 49219 9.006111 -27.540909 32.613892 49220 9.171341 -27.529022 33.123611 49221 9.310501 -28.016678 32.850830 49222 9.278381 -27.957031 33.236664 49223 62.111679 -27.224060 35.058640 49224 61.976318 -26.252579 35.412766 49225 8.409271 -29.428024 32.367325 49226 9.119308 -28.705185 33.245712 49227 9.116501 -29.492615 32.797592 49228 9.180145 -29.499954 33.225090 49229 7.989384 -30.070501 32.071453 49230 7.959419 -31.860031 32.348595 49231 8.643051 -30.473495 32.833046 49232 8.519196 -31.687988 33.324478 49233 55.747803 -29.268677 34.680580 49234 56.500580 -28.949493 34.657303 49235 56.594635 -29.399063 34.180008 49236 57.220734 -29.031601 34.730659 49237 57.103058 -29.645493 34.105247 49238 8.603035 -32.673172 33.002296 49239 8.494812 -33.438049 32.412064 49240 8.985611 -29.995941 33.229889 49241 54.510071 -30.650833 33.951019 49242 53.773163 -29.425964 34.903969 49243 54.713440 -29.182602 35.038872 49244 56.478088 -30.683380 33.769783 49245 62.080429 -29.988220 33.799461 49246 52.456482 -30.632996 34.179680 49247 52.917847 -31.610626 33.695587 49248 52.164673 -31.328049 33.854485 49249 53.350510 -30.302643 34.137932 49250 5.375704 -29.710430 27.658731 49251 52.434540 -33.023605 33.374046 49252 51.707245 -31.991364 33.937973 49253 58.488022 -31.660294 33.738098 49254 55.310028 -32.586380 33.110123 49255 53.764053 -32.918365 33.171509 49256 59.190002 -30.187241 34.922569 49257 59.903320 -31.009354 34.686340 49258 8.767380 -34.671890 32.542007 49259 46.895340 -34.207504 33.412025 49260 45.794662 -35.420303 33.354080 49261 45.451080 -35.940414 32.839951 49262 9.856140 -37.641174 32.033417 49263 46.566147 -36.780548 33.434219 49264 6.283302 -37.838730 32.230370 49265 5.376412 -37.335007 32.587944 49266 47.400375 -37.623978 32.900261 49267 48.234253 -37.574524 33.579140 49268 3.675873 -41.326569 31.775820 49269 52.345322 -39.165253 33.947380 49270 53.768250 -41.057449 33.670395 49271 3.541412 -42.121597 31.718180 49272 3.362045 -41.702866 32.115067 49273 3.847969 -40.479202 32.052025 49274 3.376289 -42.232849 32.243172 49275 42.796097 -42.781952 33.058075 49276 43.663300 -42.770523 32.936440 49277 44.572525 -43.032150 32.958275 49278 3.843140 -44.241547 32.478439 49279 41.994217 -43.232941 32.631638 49280 45.407471 -43.125732 34.664413 49281 46.723618 -43.876724 33.936737 49282 48.694061 -44.128967 32.706818 49283 47.494904 -43.956772 33.072945 49284 54.359955 -42.341492 33.509430 49285 55.407043 -43.917557 33.151947 49286 4.211266 -45.482727 32.499924 49287 50.532990 -44.900711 33.677856 49288 5.038384 -46.418365 30.991365 49289 53.234314 -45.427155 32.824638 49290 56.936096 -45.691940 33.133286 49291 4.724045 -46.810211 31.298944 49292 4.386452 -46.694977 32.319115 49293 53.867630 -45.723129 34.468628 49294 56.391937 -45.854355 33.482552 49295 55.820480 -45.545914 34.483627 49296 55.244202 -45.576157 35.718483 49297 57.509766 -46.371948 32.033173 49298 42.541626 -47.023041 33.448288 49299 45.747925 -48.062759 33.415306 49300 48.180511 -48.954437 33.353767 49301 47.397446 -48.933060 33.933159 49302 46.892242 -48.526123 33.497681 49303 3.741409 -48.854477 31.999460 49304 50.688904 -50.229630 33.744698 49305 49.586548 -49.678268 33.650536 49306 51.409943 -50.256027 33.114441 49307 53.060074 -50.259491 32.627686 49308 55.005737 -50.760986 32.749046 49309 53.740189 -50.642044 33.704491 49310 56.380585 -51.373322 32.633530 49311 38.236305 -53.440231 31.678095 49312 39.789284 -53.008209 31.826311 49313 40.881073 -52.626923 31.749949 49314 42.422195 -54.616348 32.214401 49315 44.388031 -53.790009 32.132782 49316 45.470032 -53.997665 32.053085 49317 48.297607 -54.999496 32.316994 49318 49.440598 -54.649078 32.102234 49319 57.577026 -52.422043 31.807924 49320 57.127106 -52.736908 32.545845 49321 56.664474 -51.833939 33.730453 49322 39.521317 -54.485916 32.202904 49323 40.735443 -53.859268 32.131500 49324 41.564148 -53.177994 32.053169 49325 53.265320 -56.333923 32.585144 49326 55.095734 -55.366623 31.914598 49327 56.923706 -54.024887 32.213440 49328 3.631493 -55.369049 32.267876 49329 38.092743 -55.853577 32.188759 49330 36.760925 -56.998123 31.863138 49331 55.105194 -55.794998 32.576309 49332 56.479919 -54.309525 33.408089 49333 4.158180 -55.622818 33.024445 49334 4.571892 -56.777695 33.018677 49335 3.745651 -56.667297 32.063446 49336 55.562439 -55.578812 32.459061 49337 17.339142 -57.826416 31.490633 49338 17.774643 -57.835007 31.545031 49339 36.394058 -58.349380 31.809504 49340 37.296722 -58.375351 32.684586 49341 15.274254 -60.579773 32.000038 49342 14.763794 -61.569656 31.520334 49343 6.305313 -60.811157 30.368029 49344 5.528946 -60.030914 31.085154 49345 5.760979 -59.370667 30.646021 49346 19.504868 -61.349365 31.545984 49347 19.900925 -61.256516 30.938959 49348 36.207207 -59.411575 31.549349 49349 19.238495 -59.435837 32.236908 49350 19.183273 -60.016861 33.009804 49351 19.375549 -60.420959 32.175369 49352 36.793427 -61.407242 32.553665 49353 37.194092 -62.311539 32.693443 49354 36.718338 -60.453537 32.487038 49355 14.410446 -62.265472 31.353151 49356 13.630051 -63.605988 30.870134 49357 46.668396 -64.197632 31.389078 49358 49.512375 -64.897690 31.401049 49359 49.973679 -63.498077 30.739214 49360 6.148148 -64.445847 30.703745 49361 5.829788 -63.686203 31.609285 49362 7.514114 -65.056824 31.887735 49363 7.584633 -65.528503 32.072662 49364 7.153069 -65.563339 31.635317 49365 31.684565 -64.287704 32.385063 49366 30.684662 -64.793655 31.413935 49367 30.562820 -63.903351 32.044380 49368 38.456985 -64.030746 32.439651 49369 39.364746 -65.046173 32.892944 49370 6.470871 -65.441879 30.860216 49371 12.947098 -65.362534 31.128138 49372 17.411407 -66.104263 31.335535 49373 31.330772 -63.005127 33.180626 49374 31.776293 -63.416977 33.327950 49375 29.861923 -65.269608 31.408472 49376 29.857178 -64.370560 32.189911 49377 46.549774 -65.368011 32.396645 49378 28.059845 -67.728561 30.880816 49379 28.519409 -67.014664 31.515963 49380 29.369873 -66.199829 31.202181 49381 30.396637 -62.843964 33.045158 49382 32.200317 -66.203323 31.705767 49383 32.047829 -65.339722 31.703562 49384 16.368515 -67.422241 30.801836 49385 27.579590 -68.251770 30.559435 49386 31.579498 -67.374512 30.862864 49387 31.976961 -67.310043 31.458963 49388 11.559288 -68.530106 31.076120 49389 27.166061 -68.526245 30.684565 49390 30.673203 -69.693787 31.161074 49391 31.326698 -68.281769 31.176317 49392 31.723719 -69.144943 32.674438 49393 49.008240 -66.449921 31.963274 49394 11.164001 -69.276550 30.345362 49395 10.662598 -69.979828 30.349100 49396 16.352585 -67.307404 31.589235 49397 16.076675 -67.745682 31.427210 49398 3.931107 -68.782913 32.340950 49399 10.158646 -70.379700 30.314470 49400 10.962761 -69.504776 31.301561 49401 26.165802 -71.798218 31.582064 49402 26.691116 -71.932159 32.747475 49403 26.898499 -70.712082 32.621834 49404 35.517578 -71.059479 30.462618 49405 4.725884 -70.051117 30.345652 49406 5.653267 -71.025482 30.540392 49407 13.913879 -72.631699 29.712770 49408 39.349625 -71.313553 30.927202 49409 40.189636 -71.339996 30.710978 49410 13.606003 -72.748703 30.245737 49411 29.898109 -72.261612 31.172564 49412 29.652161 -73.060806 30.620928 49413 36.241081 -72.245193 31.389544 49414 35.513184 -71.761398 30.803286 49415 35.466217 -72.733307 31.212694 49416 41.051773 -72.231186 30.922869 49417 43.386383 -73.210648 31.148630 49418 43.217987 -72.846619 30.776293 49419 42.256134 -73.226974 31.138628 49420 43.227203 -72.222061 30.383150 49421 44.322235 -72.711929 31.437609 49422 44.705231 -72.308868 31.620203 49423 45.128143 -71.734909 31.766626 49424 13.127319 -73.524246 30.432833 49425 35.882538 -73.125305 31.665056 49426 25.774033 -73.006180 30.639994 49427 25.602478 -72.236465 30.457117 49428 34.964012 -74.999771 31.069521 49429 42.979538 -73.856323 31.808222 49430 43.937714 -73.045242 31.214365 49431 26.039505 -74.251892 30.988543 49432 26.192902 -75.179062 31.055262 49433 7.746414 -77.051056 29.900965 49434 12.381713 -76.359512 30.309328 49435 11.818138 -76.584763 31.252169 49436 12.773102 -76.396698 29.830812 49437 30.612869 -75.921188 31.866266 49438 13.507598 -78.125427 29.826380 49439 30.547318 -78.453110 30.118692 49440 30.827774 -77.722992 31.444788 49441 5.345329 -78.916718 29.644808 49442 8.465408 -79.022247 29.975779 49443 12.699722 -77.439911 30.325251 49444 5.760040 -79.672165 29.516464 49445 20.848740 -80.327301 30.554117 49446 19.949417 -80.271622 29.986895 49447 27.433830 -79.697983 30.687693 49448 27.208038 -80.683243 30.141405 49449 9.634857 -80.990631 29.480164 49450 10.048935 -81.031326 29.225197 49451 23.666138 -80.546753 29.757723 49452 22.822876 -80.190887 29.592186 49453 34.618225 -79.974731 30.680971 49454 10.055069 -81.988571 29.199989 49455 10.466995 -83.501938 29.684877 49456 14.322723 -81.607742 30.360865 49457 13.930588 -82.879608 29.887270 49458 24.687401 -80.968658 29.883799 49459 25.704750 -81.307175 30.106989 49460 26.782440 -81.443344 30.502474 49461 31.761965 -80.565186 31.493853 49462 31.045715 -79.268433 31.045046 49463 34.679474 -80.755692 31.177927 49464 34.333290 -81.401779 31.196932 49465 18.847870 -82.516464 30.261057 49466 19.641624 -84.747269 30.713869 49467 19.033607 -83.551666 31.333017 49468 20.589355 -83.974411 29.758524 49469 20.943146 -84.671326 29.940462 49470 22.102615 -85.320816 30.186106 49471 9.705025 -84.034286 30.061197 49472 10.491959 -83.864578 31.106974 49473 13.358536 -83.478027 29.560310 49474 8.437042 -85.970383 29.159897 49475 15.466812 -87.167480 30.151682 49476 15.697617 -86.788544 30.539797 49477 16.167465 -86.759949 30.178888 49478 16.387329 -87.204849 29.695925 49479 17.295242 -86.716629 30.398577 49480 17.458771 -87.498093 29.657389 49481 18.356674 -86.821518 29.673464 49482 18.433716 -87.368607 29.535011 49483 19.053696 -86.497131 29.745363 49484 19.093842 -86.883820 29.523865 49485 18.989212 -86.020309 30.584291 49486 19.639862 -86.410095 29.810457 49487 19.727188 -86.906128 29.677835 49488 20.195221 -86.587357 29.922113 49489 16.560120 -87.957047 29.728380 49490 15.825325 -87.820847 29.771303 49491 19.251625 -87.453873 29.933748 49492 20.130859 -87.184265 30.189135 49493 26.316544 -87.630295 29.835192 49494 9.814323 -88.573868 29.452339 49495 16.147110 -89.116608 30.369921 49496 15.126541 -87.977676 30.084932 49497 14.822540 -88.605972 30.250574 49498 18.310318 -87.948395 30.135653 49499 23.656174 -90.248596 30.414133 49500 24.592491 -89.890350 30.122133 49501 25.428589 -89.705521 29.241356 49502 19.530624 -91.318588 29.262947 49503 20.389618 -91.167496 29.214821 49504 21.612579 -90.620193 30.761873 49505 21.782967 -91.175903 29.092194 49506 22.846977 -90.728317 29.954363 49507 13.318008 -91.517120 28.415070 49508 16.301933 -91.238281 29.833780 49509 11.193192 54.926041 39.496788 49510 12.105804 55.444397 39.180511 49511 13.807617 54.421265 39.439911 49512 10.446114 54.315964 39.706215 49513 14.800354 53.958160 38.993172 49514 9.415703 53.820465 39.415009 49515 15.586198 52.715668 39.019638 49516 16.993103 52.471588 38.686325 49517 6.546478 53.257507 40.292976 49518 7.245102 53.544830 40.889198 49519 8.304092 53.183731 38.903969 49520 8.431900 53.549286 40.527496 49521 14.356742 52.688477 39.448647 49522 13.207825 53.722168 39.853867 49523 16.015991 51.658829 39.304916 49524 14.980896 51.824631 39.271820 49525 17.075089 51.887070 39.241653 49526 5.559204 50.648178 39.671486 49527 13.333191 50.839111 39.949020 49528 14.116302 51.621643 39.580414 49529 14.645523 50.632629 39.732559 49530 19.358353 50.165131 39.199585 49531 7.116043 48.077850 38.885887 49532 8.464157 46.645279 38.215561 49533 26.960342 45.265976 39.425880 49534 6.184441 45.358902 38.949684 49535 7.396225 45.964752 38.761497 49536 8.095154 46.676422 38.673004 49537 25.565125 45.240814 38.921005 49538 25.968796 43.823456 39.227638 49539 5.234322 43.712738 38.442734 49540 16.462883 43.784821 39.018677 49541 16.108643 43.729248 38.377029 49542 25.364044 42.745880 38.641197 49543 25.604782 41.957001 38.467468 49544 26.381577 42.313629 39.170364 49545 26.318909 41.162628 38.485863 49546 7.899917 40.636169 39.609474 49547 19.455948 39.519821 38.620064 49548 27.307884 41.194641 39.402542 49549 26.992081 40.038849 38.278809 49550 33.743019 41.252365 39.466377 49551 7.959701 37.334518 38.476181 49552 8.639832 37.635162 37.942039 49553 20.878036 38.452576 39.156441 49554 19.067368 41.321747 40.224365 49555 18.345505 40.896561 39.282608 49556 20.077621 40.148560 39.939171 49557 27.548233 40.139572 38.949554 49558 27.882233 40.151947 39.703186 49559 35.873711 39.122040 39.826271 49560 35.360367 39.514038 40.086166 49561 35.596405 39.177673 38.961487 49562 28.285721 37.549988 38.723419 49563 7.463959 36.170975 37.900276 49564 6.855538 36.888885 38.785736 49565 6.616234 36.033737 38.296539 49566 20.908730 37.440613 38.458427 49567 19.578308 35.850128 40.451118 49568 20.270187 36.022614 39.762543 49569 28.138931 37.267151 38.642868 49570 27.664673 36.899048 38.384354 49571 20.875687 36.689575 39.367386 49572 31.439934 33.400238 37.990875 49573 31.371223 33.203888 39.210175 49574 31.994623 34.293304 39.012924 49575 32.900276 34.995163 39.835190 49576 32.071602 34.199310 38.127731 49577 33.873932 35.192566 39.940865 49578 34.681808 35.241089 39.870888 49579 37.489861 35.689240 39.342690 49580 4.467339 33.201675 38.506363 49581 4.627358 33.210495 37.941795 49582 4.954910 33.820312 38.664246 49583 17.782761 33.820831 38.748306 49584 3.867386 30.570435 37.269562 49585 17.323441 31.055267 37.816612 49586 17.245964 31.830490 38.707710 49587 23.927505 30.569016 37.821465 49588 31.790789 31.126068 38.300339 49589 36.417114 29.246475 38.150665 49590 36.597763 30.315353 39.258705 49591 24.544724 29.260986 37.512535 49592 32.187378 30.730164 38.131012 49593 3.281258 26.481781 37.495621 49594 3.335327 28.212677 38.067932 49595 25.004669 30.210602 38.864655 49596 25.008560 29.598862 38.305992 49597 37.282867 29.202591 38.853531 49598 25.318039 28.581757 38.083839 49599 3.275223 26.395538 38.992554 49600 3.324280 24.936279 38.320824 49601 25.798401 28.284637 38.952850 49602 37.122574 27.930817 38.478981 49603 4.184105 23.082703 37.834953 49604 5.356514 22.489227 37.309273 49605 5.498596 23.452454 36.821541 49606 23.477066 24.589737 39.634933 49607 23.355881 23.805283 38.630363 49608 37.907288 25.672943 38.715584 49609 19.776772 25.427582 38.448120 49610 23.396774 23.483749 37.599449 49611 37.137405 23.850708 38.085365 49612 6.161080 22.579605 36.893967 49613 7.204949 21.880981 36.775375 49614 8.029510 20.510559 36.955803 49615 19.049240 23.638367 37.838188 49616 18.982605 24.562042 38.796349 49617 18.590210 22.768402 38.290260 49618 37.288712 22.641785 37.893562 49619 6.120583 21.680054 37.284058 49620 19.735199 20.893997 37.495789 49621 22.161217 22.435638 38.711929 49622 21.307510 21.530396 38.918579 49623 21.765884 22.240204 39.835846 49624 22.492477 22.695648 37.602631 49625 22.906158 23.088028 38.460182 49626 36.999863 22.139709 37.680641 49627 6.894112 20.893433 37.256996 49628 9.107896 19.644821 36.864456 49629 19.116913 20.401993 37.781326 49630 18.584831 20.136505 38.106735 49631 18.359894 20.888245 38.384262 49632 18.425705 21.839127 38.392746 49633 19.919518 20.317429 38.027977 49634 19.180450 20.945374 37.568451 49635 36.076492 21.478317 36.851128 49636 36.884842 21.578003 37.242477 49637 40.894501 21.575760 38.025314 49638 42.449921 20.672379 38.256760 49639 42.596039 21.868988 38.755852 49640 20.709747 20.390289 38.890572 49641 47.205231 16.793335 37.330353 49642 45.478760 15.894608 37.576691 49643 46.361664 16.419724 37.512390 49644 52.649734 15.891556 36.797768 49645 52.019623 15.988373 37.349335 49646 4.182716 14.764938 35.867271 49647 10.596413 14.600693 37.047569 49648 9.786743 16.051971 37.717529 49649 33.616257 15.087433 37.540421 49650 33.529999 14.376068 39.034149 49651 34.618668 15.005585 38.379486 49652 44.466644 15.239471 37.685196 49653 52.369415 14.946320 37.208046 49654 4.402481 13.666382 36.610130 49655 4.191719 14.021317 36.339127 49656 31.487198 13.590546 37.687805 49657 41.808777 13.889587 37.280342 49658 43.649673 14.960785 37.418015 49659 3.532578 12.629547 36.506599 49660 6.907433 12.125000 36.624794 49661 39.747147 12.680984 36.890762 49662 38.844284 11.994339 36.885223 49663 41.166153 13.103546 37.513695 49664 51.781631 14.892578 37.691391 49665 51.129639 13.585724 37.462746 49666 3.381813 11.286316 36.111900 49667 37.407669 11.957825 36.238342 49668 37.886566 11.154297 36.465752 49669 39.542923 11.952744 37.236206 49670 49.123276 12.634842 37.511375 49671 50.037979 13.570053 38.379944 49672 43.881042 11.205215 37.651192 49673 28.000977 10.215973 36.371811 49674 39.287941 11.189911 37.080475 49675 38.903473 9.791519 36.458763 49676 3.385384 9.943512 36.392776 49677 3.505661 9.135513 35.875343 49678 10.063965 10.418106 36.518280 49679 10.011642 9.295059 37.439125 49680 28.414627 8.583878 36.414314 49681 28.825188 11.451202 36.637047 49682 28.908356 9.980194 36.950638 49683 40.300949 10.219452 37.016197 49684 41.292786 9.374527 36.700134 49685 42.058929 9.607880 36.936600 49686 42.087387 9.296616 36.646011 49687 43.006012 9.699219 36.515175 49688 42.032806 8.898621 36.006653 49689 42.908600 12.607056 38.480293 49690 43.815216 12.343201 38.747513 49691 41.080017 8.751312 36.226341 49692 3.622429 6.151688 36.723839 49693 29.638779 7.357864 36.797844 49694 53.352295 7.514114 37.108818 49695 53.051086 8.045456 38.346878 49696 54.021378 8.119400 39.122147 49697 55.475082 6.645905 38.473007 49698 55.146729 6.616409 39.327164 49699 54.994431 7.297836 38.994286 49700 4.726814 4.453384 36.017784 49701 5.078545 2.969109 35.644562 49702 46.937302 6.581787 38.144928 49703 45.981125 5.972252 38.335632 49704 30.591629 5.888550 36.800461 49705 30.086670 4.533073 36.312767 49706 30.669167 7.444901 37.348930 49707 31.185425 4.724808 36.816147 49708 56.144379 5.915344 37.123360 49709 56.500488 5.810501 36.273903 49710 56.350983 4.485062 36.975616 49711 29.913658 3.405006 36.148697 49712 31.458351 3.567024 36.803596 49713 55.820267 3.485809 37.544289 49714 55.230774 4.406433 38.714050 49715 4.790886 1.487106 36.052872 49716 6.331680 2.129395 36.542587 49717 6.187752 0.721405 37.058502 49718 4.115929 5.232132 37.045441 49719 3.658592 1.060547 35.746025 49720 3.822182 1.583420 35.393761 49721 3.840759 0.363312 36.453430 49722 2.973419 0.203476 35.702034 49723 29.596802 2.347626 36.003967 49724 30.781807 2.335159 36.657692 49725 56.176178 3.256882 36.867233 49726 29.159988 1.312469 35.618881 49727 30.151466 0.954407 36.734032 49728 39.120728 0.604187 36.768265 49729 40.373230 1.524353 36.742477 49730 55.645767 2.531631 36.819717 49731 31.527191 0.355545 38.080383 49732 31.455017 1.413330 37.171005 49733 30.315399 -0.554367 37.436829 49734 53.188232 1.153152 36.901299 49735 2.220169 -0.973495 35.599777 49736 29.752441 -0.203598 36.745499 49737 38.715790 0.053024 37.913605 49738 38.186356 -0.677917 38.411636 49739 50.291107 1.285507 37.862282 49740 48.320190 -0.100296 38.015770 49741 52.216080 0.952698 37.011559 49742 1.900498 -2.307755 35.451241 49743 30.501038 -2.277206 36.083008 49744 30.048309 -1.940460 36.347702 49745 34.415627 -2.932159 37.246147 49746 35.336975 -2.335449 37.158768 49747 35.458572 -3.224869 38.610825 49748 40.021942 0.843079 38.179749 49749 39.116005 -0.320236 39.095917 49750 49.025742 0.977661 38.187668 49751 49.050232 1.202988 39.728691 49752 1.810211 -3.309692 36.084427 49753 31.658381 -2.686172 36.271576 49754 33.177185 -2.794449 36.291985 49755 54.443161 -3.613388 36.482872 49756 56.142487 -3.651733 37.459518 49757 2.691910 -5.385544 35.544296 49758 2.055412 -4.344666 36.149330 49759 5.318268 -4.580017 34.386703 49760 4.681610 -5.343292 34.798302 49761 47.740448 -5.242111 37.618141 49762 53.439896 -4.080902 36.378433 49763 52.826309 -4.511078 36.031631 49764 52.171997 -5.975494 36.948425 49765 56.782776 -4.137527 37.244469 49766 5.259110 -5.324402 34.457626 49767 46.364258 -5.015778 35.891937 49768 3.578003 -6.532013 35.547325 49769 4.771347 -6.224274 35.033226 49770 4.633720 -7.210327 35.395050 49771 5.520538 -7.261520 34.814087 49772 56.742142 -6.144516 36.849449 49773 4.426407 -6.639114 35.401299 49774 41.805573 -8.924438 36.098541 49775 54.798309 -9.993591 36.739845 49776 55.600555 -10.027176 37.050072 49777 55.947479 -8.812698 37.127869 49778 56.453537 -7.332214 36.852638 49779 5.210495 -8.472549 35.111679 49780 5.312355 -9.980347 35.188179 49781 6.293831 -10.459671 34.658661 49782 40.815094 -9.491974 35.704033 49783 41.311737 -8.976212 35.463554 49784 52.984833 -6.110107 37.986168 49785 53.034103 -7.771729 39.071068 49786 53.818329 -9.826813 36.126152 49787 40.191147 -10.479004 36.781227 49788 40.879425 -9.781433 36.542664 49789 54.706024 -9.249649 36.585587 49790 5.457680 -11.512543 35.035439 49791 45.321106 -12.553223 36.123810 49792 50.963898 -11.818314 34.831818 49793 52.785370 -11.683929 35.837982 49794 52.999573 -10.752686 35.943123 49795 6.382706 -13.011993 34.466324 49796 39.577744 -11.230408 36.427887 49797 39.417686 -12.149063 37.021645 49798 42.730835 -13.068726 35.226830 49799 43.303223 -14.001236 35.765114 49800 44.078491 -12.811188 35.653862 49801 53.391891 -12.984970 35.483276 49802 53.990662 -11.449799 36.182426 49803 54.436493 -12.772949 35.823227 49804 5.953148 -14.012894 34.756432 49805 38.507812 -13.927353 36.053215 49806 42.289062 -14.906815 35.594803 49807 55.581940 -12.327713 36.320358 49808 55.178650 -10.912125 36.661163 49809 6.027168 -15.688782 34.705757 49810 4.774361 -16.959000 34.959358 49811 6.759232 -17.364731 34.587662 49812 40.262848 -15.147720 35.125221 49813 57.096313 -12.865463 36.748360 49814 57.004333 -13.666138 36.247482 49815 7.411072 -17.382156 34.185532 49816 38.704857 -15.358826 35.400017 49817 38.293030 -15.076019 35.737686 49818 38.453377 -15.700821 35.713394 49819 41.204742 -15.891495 35.820427 49820 42.439423 -15.623032 35.944405 49821 39.289177 -16.073929 35.820160 49822 57.337692 -16.830078 36.048393 49823 57.489868 -13.954453 36.647324 49824 58.121277 -14.361572 37.937782 49825 4.740608 -19.017532 34.566742 49826 3.957504 -18.117859 34.922012 49827 3.975693 -19.062759 34.725571 49828 4.814056 -17.936035 34.738335 49829 5.630814 -18.414536 34.669937 49830 56.562302 -17.551056 35.622391 49831 58.403290 -15.492264 37.572823 49832 4.807846 -18.352249 34.617470 49833 6.946846 -18.836502 34.437714 49834 7.172287 -20.017426 34.079689 49835 55.779495 -18.249985 35.613800 49836 56.036896 -18.554672 36.441811 49837 56.743500 -18.072769 36.101151 49838 57.093506 -18.094971 37.014137 49839 4.066010 -20.058655 34.701576 49840 3.337631 -19.036621 35.099174 49841 3.043579 -19.756622 35.615791 49842 5.893021 -19.978989 34.513290 49843 3.161018 -20.950897 35.553558 49844 4.007233 -21.476547 34.669571 49845 4.052055 -22.282822 34.704636 49846 3.219002 -22.229218 35.338615 49847 4.978027 -20.973938 34.471718 49848 7.002709 -21.150665 34.290062 49849 7.417374 -22.044434 33.872650 49850 43.272537 -21.196976 35.616325 49851 44.404861 -20.958496 35.527122 49852 5.015091 -22.014694 34.558144 49853 5.993301 -21.321121 34.502190 49854 41.399780 -21.899994 36.231339 49855 41.542755 -21.579056 35.151047 49856 40.614777 -22.123398 35.630943 49857 42.309692 -21.585800 35.998657 49858 58.882919 -21.603195 35.507957 49859 58.017181 -21.850372 35.473663 49860 60.037949 -21.811829 36.736046 49861 60.668350 -22.435577 37.704315 49862 60.090698 -21.805557 38.242065 49863 60.038788 -21.853729 35.186249 49864 60.424530 -22.395874 38.430946 49865 4.269821 -23.430664 34.842728 49866 6.698723 -22.724777 34.328430 49867 7.621795 -23.906189 33.855263 49868 39.452332 -23.503082 35.048515 49869 55.523193 -23.269073 36.250671 49870 56.912323 -22.417007 36.504471 49871 56.275024 -22.721039 37.117203 49872 60.950012 -22.867264 35.447510 49873 59.444702 -21.470078 37.962891 49874 59.058151 -21.525131 37.339493 49875 39.978615 -24.616074 34.515785 49876 8.131348 -25.566910 34.061356 49877 39.642998 -22.846115 35.855591 49878 38.838318 -24.056992 35.757507 49879 44.538101 -25.682617 36.224808 49880 44.970581 -25.881668 36.751160 49881 43.445648 -25.653244 35.524040 49882 44.620422 -25.121643 35.161224 49883 53.913589 -24.016937 36.143814 49884 61.472763 -24.690201 35.823753 49885 61.334854 -26.362381 36.598183 49886 8.357011 -27.744141 33.817772 49887 38.703156 -25.408463 35.551582 49888 39.611397 -26.175735 35.200478 49889 38.522064 -26.716385 35.985901 49890 39.159584 -24.830917 35.056282 49891 50.660355 -25.316895 35.072510 49892 8.283264 -28.681976 33.927765 49893 7.982399 -26.409790 34.067360 49894 8.142075 -29.586884 33.880081 49895 8.352356 -30.695740 33.636032 49896 52.717163 -29.879456 37.113762 49897 53.027893 -29.295090 35.870834 49898 51.757980 -30.464844 35.555870 49899 51.759827 -31.106018 34.293396 49900 52.839981 -29.778687 34.859940 49901 57.440887 -28.389877 35.928932 49902 58.801208 -28.174805 36.449516 49903 58.090302 -28.935471 35.265678 49904 57.966568 -29.899292 34.474777 49905 58.724609 -29.292145 35.279587 49906 53.448669 -28.851242 36.828407 49907 61.444214 -29.862244 34.948685 49908 7.917022 -32.966187 33.688896 49909 8.636597 -33.612961 33.124809 49910 50.585236 -32.173645 34.381165 49911 50.493469 -31.545273 35.550491 49912 51.161987 -31.358063 34.666412 49913 49.116135 -33.067703 34.895561 49914 49.856232 -33.018677 33.960342 49915 49.835876 -32.389526 34.935707 49916 8.807869 -35.714569 33.036995 49917 48.843628 -33.453934 36.048752 49918 47.360291 -34.945511 35.037399 49919 6.214180 -35.445633 33.481026 49920 7.288139 -35.718002 33.338028 49921 6.390457 -34.491684 33.812874 49922 9.103264 -37.000015 32.861763 49923 9.570633 -37.533203 32.411011 49924 8.134178 -34.485413 33.421021 49925 46.484268 -35.001175 34.042198 49926 4.624451 -36.781036 33.087593 49927 4.352669 -36.102478 33.702156 49928 4.160339 -37.056946 33.456184 49929 8.346222 -36.872559 32.905106 49930 9.041748 -37.729462 32.467812 49931 8.972992 -36.508392 33.034065 49932 45.809937 -36.151199 33.324722 49933 46.157379 -35.876099 33.841797 49934 4.080299 -38.285797 33.830215 49935 5.290123 -35.801453 33.477325 49936 6.216965 -36.420334 33.001450 49937 46.771088 -35.897614 34.480354 49938 3.804421 -36.530533 34.491386 49939 3.909203 -39.710815 32.950661 49940 47.455933 -37.151215 33.914558 49941 47.234589 -36.579178 34.499542 49942 48.037140 -36.770401 34.831215 49943 49.119843 -37.271317 34.786240 49944 50.389969 -37.866333 34.559883 49945 51.189301 -38.380249 33.997040 49946 51.848175 -38.690002 34.224731 49947 3.539917 -41.253021 32.788643 49948 4.119492 -40.300064 33.915070 49949 52.842743 -39.800751 34.308105 49950 3.879356 -41.454269 34.015617 49951 53.440353 -40.132797 35.022369 49952 55.260010 -42.711304 33.981140 49953 54.728806 -41.793854 34.163315 49954 3.743050 -42.463623 34.566223 49955 3.493340 -43.928116 33.951096 49956 3.495957 -42.750381 33.090439 49957 41.716232 -43.008926 33.597450 49958 42.416260 -42.428665 34.550232 49959 43.716248 -42.658646 33.877075 49960 54.739487 -40.964478 34.834389 49961 54.042984 -40.498016 35.022392 49962 40.933273 -43.850418 33.914719 49963 55.634857 -41.592606 34.701988 49964 46.771393 -43.953888 34.864487 49965 47.492447 -44.149628 35.622086 49966 48.083801 -44.347275 34.457527 49967 49.386505 -44.525192 33.591446 49968 55.385117 -43.578400 33.678749 49969 56.035767 -44.189743 33.936325 49970 56.334351 -44.609390 35.319336 49971 56.573563 -45.164627 33.864853 49972 52.030396 -45.295349 33.784264 49973 50.926941 -45.322662 34.882935 49974 56.505295 -45.586166 33.984558 49975 56.737152 -45.607101 33.685944 49976 11.688324 -47.545120 32.962975 49977 12.426804 -47.319702 33.609467 49978 11.943878 -48.481552 33.061470 49979 41.135864 -45.005356 34.523834 49980 41.547638 -46.048477 33.608711 49981 10.873833 -48.198654 32.856094 49982 11.020889 -47.142654 33.181564 49983 43.728775 -47.706406 33.524963 49984 43.295746 -47.559448 33.503738 49985 44.474213 -47.776184 33.583069 49986 9.781433 -47.753159 33.198242 49987 9.489822 -49.118225 33.081573 49988 11.045448 -49.277420 32.793686 49989 13.265640 -47.653015 35.065338 49990 13.288345 -48.136505 35.122330 49991 13.030510 -48.555344 34.442474 49992 45.278687 -47.981049 34.824463 49993 3.518196 -49.165848 32.523727 49994 3.542946 -49.879318 32.826813 49995 10.482025 -50.277786 33.094803 49996 12.088921 -49.644836 33.303070 49997 11.327225 -50.069885 32.969955 49998 47.985596 -49.214935 34.276291 49999 47.402710 -48.999466 34.616425 50000 48.715271 -49.493683 34.316948 50001 52.239807 -50.513626 33.647636 50002 8.403320 -51.053238 33.703461 50003 9.306808 -50.486893 33.311836 50004 9.886505 -51.718613 33.752731 50005 11.740250 -51.153641 33.851891 50006 51.375290 -50.533859 33.675232 50007 55.462646 -50.868866 34.506172 50008 56.642960 -51.683792 34.787354 50009 56.229218 -50.996689 35.539864 50010 44.776962 -56.477036 32.629005 50011 39.711166 -56.375290 32.459099 50012 38.751617 -53.933502 31.985537 50013 40.992584 -57.464111 32.570381 50014 47.507721 -56.558777 32.667549 50015 42.044556 -57.752502 32.655418 50016 43.135544 -57.445084 32.679031 50017 46.448334 -57.582962 32.946915 50018 48.564926 -57.121216 32.869400 50019 50.800385 -57.942657 32.996033 50020 51.547958 -57.256607 32.714325 50021 49.797180 -57.477448 32.974976 50022 52.390015 -57.620468 32.859634 50023 55.556808 -55.728027 33.481499 50024 56.021378 -54.982300 34.234161 50025 37.533340 -57.213135 32.549484 50026 54.125381 -57.096558 33.277222 50027 54.804352 -56.299530 33.096725 50028 53.285049 -57.973984 33.277420 50029 3.710014 -57.493042 31.697504 50030 38.242439 -57.134277 32.685944 50031 38.438728 -58.020660 32.836197 50032 39.712646 -58.533234 32.839828 50033 54.726837 -56.865265 34.309555 50034 54.348251 -57.666718 34.100327 50035 55.204956 -56.096283 34.655991 50036 4.499840 -58.771988 32.575714 50037 15.868301 -59.522812 32.759949 50038 16.730438 -58.616409 32.888519 50039 17.623917 -58.132233 32.316513 50040 43.972229 -58.482925 33.041901 50041 44.799103 -58.205414 33.085320 50042 46.441498 -58.915985 33.587822 50043 47.492569 -58.556534 33.606506 50044 53.889679 -58.199615 34.287544 50045 4.786026 -59.925766 32.185020 50046 36.671631 -59.307953 32.497643 50047 41.179047 -59.363449 33.074982 50048 42.648224 -59.281616 33.057098 50049 43.852448 -59.826797 33.414978 50050 51.573715 -58.920654 33.299698 50051 52.571976 -59.086288 33.557106 50052 53.301987 -58.866882 34.087776 50053 15.106056 -61.363846 32.385345 50054 19.360367 -61.376831 32.513992 50055 19.328506 -62.486496 31.762255 50056 5.260033 -62.808670 31.262804 50057 5.101051 -62.746597 32.397156 50058 14.676132 -62.416245 32.449387 50059 37.379288 -59.830627 33.247772 50060 37.513107 -63.204178 32.573776 50061 13.682892 -63.901352 31.728540 50062 15.641022 -60.858459 33.559052 50063 37.861420 -63.570099 32.393097 50064 6.916321 -64.623581 31.666346 50065 6.721130 -63.786636 32.668114 50066 18.522400 -65.469177 31.899477 50067 29.646393 -63.517059 32.939522 50068 30.066360 -63.579239 32.354492 50069 48.784515 -65.227524 32.096397 50070 29.364357 -65.355591 32.333199 50071 32.349007 -65.388565 32.284142 50072 48.438553 -65.847351 32.684853 50073 6.180611 -66.494186 31.839190 50074 7.202812 -66.081711 32.314285 50075 16.814529 -66.899261 31.563616 50076 32.455322 -67.155197 32.639381 50077 40.879181 -65.814667 32.875206 50078 42.101135 -66.639481 33.765564 50079 41.080383 -66.915192 35.172791 50080 41.931610 -66.024017 32.523232 50081 45.702789 -66.319321 33.277779 50082 28.902100 -66.360748 32.658020 50083 27.984711 -67.672745 31.870935 50084 32.052277 -68.056381 32.238022 50085 27.424484 -68.513123 31.498438 50086 48.612488 -66.785034 32.807640 50087 20.470695 -69.371902 31.634432 50088 20.563416 -68.528473 32.142738 50089 20.825668 -69.601822 31.926897 50090 20.004379 -66.654480 32.575851 50091 18.730118 -68.613632 32.213165 50092 26.668991 -69.953537 31.505838 50093 31.153717 -70.292770 32.598259 50094 19.864594 -69.327209 31.655085 50095 19.017624 -71.061478 31.516260 50096 20.238747 -70.310684 31.577326 50097 20.026306 -71.324417 31.417704 50098 19.225861 -69.931717 31.600634 50099 30.571198 -70.679764 31.747698 50100 4.680756 -70.784668 31.376696 50101 10.153488 -70.473038 31.145037 50102 10.627312 -69.971069 32.318275 50103 18.466064 -70.139877 31.964396 50104 17.669746 -69.792908 32.692505 50105 17.738991 -71.072388 32.439186 50106 20.314156 -71.975952 31.699327 50107 19.270157 -72.168640 31.327875 50108 20.565308 -71.120773 31.721689 50109 47.484482 -68.737640 33.275536 50110 7.184410 -72.039566 31.910059 50111 9.523758 -71.139282 32.294350 50112 14.638062 -70.493729 32.132149 50113 18.248947 -72.201248 31.706476 50114 19.659492 -73.189087 31.355509 50115 30.315254 -71.545135 31.715998 50116 36.627258 -73.118896 31.828012 50117 37.238327 -72.040146 31.385714 50118 37.307396 -73.126511 31.861307 50119 38.118362 -72.909546 31.675776 50120 39.525665 -72.455170 31.275438 50121 40.535156 -73.718414 31.493784 50122 46.224792 -70.766602 31.685839 50123 17.823273 -73.308151 31.711107 50124 17.341797 -72.441956 32.692093 50125 18.577797 -73.149292 31.265711 50126 18.962669 -73.943619 31.249468 50127 19.608017 -73.926865 31.289499 50128 29.899422 -72.988602 31.397249 50129 12.721069 -73.725159 31.115511 50130 12.108673 -74.577011 31.578592 50131 13.082054 -72.487564 32.403046 50132 12.649956 -73.233765 32.271095 50133 18.207169 -73.881729 31.341829 50134 17.843246 -74.031830 31.668276 50135 20.546310 -73.052307 32.172539 50136 20.264755 -74.366455 32.347832 50137 20.013527 -73.848587 31.639551 50138 26.157532 -73.146210 31.757074 50139 29.920959 -73.721756 31.233385 50140 38.903992 -74.188766 31.866686 50141 42.135651 -74.705841 32.007652 50142 43.766663 -73.192078 31.774790 50143 18.406380 -74.538345 31.776926 50144 18.158142 -75.687653 33.266174 50145 18.065689 -75.097153 32.506294 50146 19.313919 -75.322906 32.535942 50147 19.493088 -74.405472 31.661516 50148 41.266098 -74.623581 31.813982 50149 39.918724 -75.440445 32.132233 50150 41.152863 -75.678207 33.016731 50151 26.350021 -75.950058 30.994066 50152 30.397903 -74.312393 32.132782 50153 30.852020 -74.795883 33.034081 50154 42.602875 -74.644608 32.564384 50155 6.152847 -77.262451 30.588785 50156 13.286484 -79.034592 30.795427 50157 34.924751 -77.962784 30.919405 50158 6.078606 -78.009033 30.612787 50159 5.840874 -78.976990 30.268869 50160 12.257553 -78.051971 31.103289 50161 26.908646 -76.989227 31.600725 50162 26.636627 -75.136627 32.112030 50163 7.196182 -79.187424 30.714357 50164 27.205978 -78.497482 31.225367 50165 27.401695 -78.018509 32.185379 50166 34.934662 -79.126831 31.052248 50167 7.687706 -80.233597 30.248285 50168 13.833832 -80.566681 31.129900 50169 12.922340 -80.633972 32.148865 50170 19.312180 -80.989243 30.851137 50171 20.824936 -80.934021 31.876535 50172 22.475601 -80.670044 30.780550 50173 27.614067 -78.967377 31.810862 50174 27.990753 -79.903702 31.988001 50175 6.759842 -79.884369 30.270769 50176 6.495705 -78.869293 30.667582 50177 18.594048 -82.040955 31.504541 50178 19.184319 -81.155396 32.192276 50179 27.678314 -81.053406 31.184267 50180 18.738167 -81.633484 30.199244 50181 23.813263 -81.074387 30.650522 50182 24.709656 -81.493851 30.841951 50183 25.794312 -81.899063 31.010782 50184 27.945328 -82.093964 31.796602 50185 28.508934 -81.281891 32.530411 50186 28.276489 -82.389755 32.335663 50187 31.491837 -78.927719 32.186340 50188 32.301895 -79.789886 33.249619 50189 32.315842 -81.566299 31.262926 50190 13.991409 -82.546509 30.731287 50191 18.612534 -81.794662 30.697298 50192 26.973145 -82.182602 31.408152 50193 32.652512 -81.624313 31.939173 50194 13.233994 -83.638000 30.099909 50195 13.385536 -83.196472 30.789530 50196 20.266022 -84.564178 30.216097 50197 8.715974 -85.444000 30.304316 50198 9.257843 -84.399826 31.239946 50199 8.816360 -85.794968 31.460657 50200 12.523438 -83.745865 30.554003 50201 11.704613 -83.599121 31.435755 50202 20.323013 -85.645004 30.208139 50203 21.449677 -86.547363 30.869448 50204 20.846786 -86.515320 30.393724 50205 23.696640 -86.311478 31.507326 50206 8.875443 -86.941437 30.055063 50207 14.768196 -87.544571 30.621675 50208 18.124283 -86.405350 31.963701 50209 18.702835 -85.969269 32.578636 50210 18.890076 -85.800262 31.787104 50211 18.775055 -84.036789 32.597176 50212 19.149597 -84.919449 31.576944 50213 22.128494 -86.774063 31.528620 50214 20.743401 -87.508057 31.262880 50215 25.958443 -87.823715 30.544870 50216 25.690063 -87.004059 31.045107 50217 14.502747 -88.072266 30.436647 50218 19.366852 -88.120193 31.037912 50219 25.196335 -86.186478 30.777445 50220 14.326347 -88.569733 30.597750 50221 17.378471 -88.412552 30.357515 50222 18.372208 -88.710464 31.212648 50223 19.884132 -87.639206 30.559587 50224 25.545227 -88.482513 31.188860 50225 25.337128 -87.805069 31.639750 50226 14.644783 -89.394318 30.488214 50227 15.555145 -90.412674 30.393641 50228 14.274323 -90.606186 30.030382 50229 25.560265 -88.990158 30.331964 50230 10.504860 -88.875305 30.951616 50231 12.131301 -90.317917 29.705454 50232 13.154083 -90.735840 29.621553 50233 13.584869 -91.208084 29.195076 50234 13.210449 -90.263214 30.218309 50235 12.679794 -89.803406 30.896685 50236 15.268661 -91.102859 29.901155 50237 19.500328 -91.065033 30.351717 50238 20.499298 -90.492218 31.570742 50239 11.906967 54.461594 40.155296 50240 9.955231 53.808609 41.066818 50241 8.105469 53.635223 42.079971 50242 7.188034 53.537247 42.534187 50243 10.992462 54.010406 40.737686 50244 6.059967 52.823959 40.221146 50245 6.326073 53.241211 41.213181 50246 12.927551 52.165497 40.251183 50247 5.579781 51.216049 41.854408 50248 5.667534 51.922516 40.783897 50249 5.656685 52.555725 41.999733 50250 11.130707 54.482086 40.159340 50251 13.548721 50.061249 39.951767 50252 17.134583 51.314224 39.961090 50253 14.050446 49.718979 40.382050 50254 19.017029 50.892822 40.064743 50255 18.288689 51.225983 40.240562 50256 19.438797 49.764923 40.683083 50257 13.306259 49.691803 40.294647 50258 15.898148 50.644836 40.152626 50259 15.057220 49.965973 40.476700 50260 15.876892 50.085098 41.109253 50261 12.884972 50.054993 40.353401 50262 14.822723 49.410370 41.605713 50263 7.211289 47.689316 39.867958 50264 19.636215 46.280518 41.312683 50265 19.685944 48.164200 40.991631 50266 18.015160 46.002640 39.688469 50267 19.472305 48.465210 40.203903 50268 7.398666 46.817505 39.440224 50269 6.626968 46.159027 39.504791 50270 29.211174 44.677139 40.091042 50271 5.143906 44.681488 39.594597 50272 29.882378 43.899414 40.741348 50273 28.938881 43.868988 40.971375 50274 29.029694 44.264130 40.624802 50275 30.837685 43.693695 40.261230 50276 5.196213 43.273163 40.051422 50277 32.837402 42.081207 40.118507 50278 27.387482 42.744690 40.127029 50279 28.029457 41.462372 40.647171 50280 33.455856 41.612549 39.781090 50281 6.756477 41.747284 40.161453 50282 7.585800 41.727234 41.313934 50283 7.910011 41.245712 40.730721 50284 8.282745 40.803772 40.593536 50285 18.018066 43.606796 40.613716 50286 17.359482 44.344086 40.327469 50287 17.024803 43.842590 39.931091 50288 21.320450 41.021835 41.277237 50289 20.593033 42.125290 41.302383 50290 20.012405 41.370667 40.726242 50291 28.317513 40.063202 41.000137 50292 28.003922 37.458740 39.163429 50293 37.238022 36.536819 40.200211 50294 6.018997 36.995819 39.772888 50295 5.705834 35.926422 39.132797 50296 6.139351 36.277878 38.811485 50297 7.164169 38.105835 39.696609 50298 21.285759 37.429245 39.322151 50299 21.492279 37.811615 39.902687 50300 21.440941 38.861969 41.015762 50301 21.229637 37.202087 40.137901 50302 21.315186 37.636658 40.578064 50303 38.502029 36.409134 38.880943 50304 38.139000 36.305481 39.293976 50305 5.486099 34.976868 38.933388 50306 25.145752 35.081680 40.050064 50307 26.891342 36.424454 39.268944 50308 27.546387 37.519379 40.265129 50309 26.569336 36.642517 40.440231 50310 18.625381 35.188904 40.090714 50311 24.077072 33.315628 39.144005 50312 36.631737 35.742081 40.090652 50313 35.517746 35.795792 40.688324 50314 17.064011 34.212585 40.077492 50315 17.629135 34.903778 40.279816 50316 17.961441 34.577637 39.500465 50317 17.083466 33.012024 39.216827 50318 4.815567 32.408157 38.680618 50319 4.113205 31.303238 38.021675 50320 24.523712 31.431030 39.395332 50321 24.316162 32.832825 40.193619 50322 4.236122 30.111481 38.577759 50323 31.603502 31.879242 39.175331 50324 33.262878 31.136292 39.669617 50325 33.976868 30.720840 38.567963 50326 32.265572 31.043365 38.887505 50327 35.019775 31.104431 40.030434 50328 25.864563 32.259171 42.827271 50329 26.680710 31.686584 43.088516 50330 26.088699 31.624420 41.973412 50331 25.623779 29.358124 38.927628 50332 37.016037 30.972290 40.589844 50333 37.627426 29.738205 39.546837 50334 38.594528 29.639496 40.449287 50335 38.183800 28.291016 39.328697 50336 20.169510 29.115173 39.805130 50337 20.127106 28.065063 40.140541 50338 38.029099 26.836166 38.906494 50339 39.318237 26.994888 39.833618 50340 26.073608 28.223267 39.981537 50341 24.081299 26.259338 40.932930 50342 23.849777 25.448273 40.108894 50343 20.006004 26.572327 38.766281 50344 37.907768 24.740646 38.615738 50345 39.335052 28.128983 40.352608 50346 39.728607 28.758942 41.281021 50347 39.100388 25.828125 39.370758 50348 38.773460 24.960648 39.047493 50349 6.988152 19.885757 37.597580 50350 8.082611 18.870300 37.607048 50351 38.771255 23.974274 38.785362 50352 3.698212 21.628143 38.747284 50353 4.391937 21.373322 38.243927 50354 18.611099 23.665787 38.526588 50355 8.662445 17.291351 38.127258 50356 8.030487 16.769287 38.707085 50357 8.699464 15.640854 38.802917 50358 5.179504 21.626953 37.722519 50359 39.890579 23.124313 38.743019 50360 41.757080 23.225403 39.312897 50361 40.731155 23.076569 38.913193 50362 43.539551 21.653366 39.181595 50363 43.434280 22.843658 39.947319 50364 6.065659 20.698380 37.669518 50365 5.147766 20.399536 38.202049 50366 18.963615 19.509521 38.514130 50367 43.197586 20.980515 38.679420 50368 6.040962 19.705948 38.080093 50369 18.319183 20.080811 38.442841 50370 20.099976 19.451050 38.732094 50371 42.432449 19.519043 38.381706 50372 43.149780 19.985825 38.766640 50373 43.788635 20.608154 39.162720 50374 6.698250 18.732117 38.221825 50375 18.180389 18.044724 40.583038 50376 17.531693 18.769684 40.631699 50377 18.002899 18.880554 39.668839 50378 42.646118 18.755432 39.283585 50379 43.749603 19.457321 39.681259 50380 37.898117 16.385818 38.224922 50381 47.212769 16.195694 38.413750 50382 50.437866 15.508194 38.784180 50383 49.332123 16.412766 38.583023 50384 38.768478 16.039108 39.650162 50385 46.257523 15.926743 38.290115 50386 49.449310 15.401535 39.228630 50387 48.365753 15.539124 39.011703 50388 51.645721 15.999420 37.784012 50389 51.174072 15.910217 38.103027 50390 35.651962 15.513092 38.161728 50391 43.594345 14.468628 38.058159 50392 45.644318 15.198502 38.608322 50393 44.507446 14.100281 38.719650 50394 51.183823 14.792145 38.242836 50395 50.753616 14.347595 38.505089 50396 3.920433 13.490250 36.556923 50397 9.887764 14.165436 38.182541 50398 32.518188 14.202484 38.318314 50399 42.625992 13.741547 38.078033 50400 3.859078 11.979935 37.230133 50401 3.414864 11.695236 36.983559 50402 4.620987 12.829956 36.881859 50403 4.867134 11.504822 37.672180 50404 3.610535 10.505615 37.691963 50405 5.839775 12.908615 36.648125 50406 40.708008 11.671661 37.506577 50407 41.855133 13.543152 37.872749 50408 6.264572 10.466949 38.123199 50409 4.873459 10.582932 38.407364 50410 5.780403 11.977570 37.205818 50411 29.572861 11.690781 37.190521 50412 30.792122 11.617844 38.164398 50413 31.403305 12.464111 38.838676 50414 42.003860 13.128906 38.160408 50415 48.024200 12.656189 38.428444 50416 47.259750 12.368164 38.872200 50417 48.919281 13.267838 38.727455 50418 2.855606 8.633057 38.342697 50419 3.275864 8.816956 36.939987 50420 7.769302 8.684433 38.799782 50421 10.788559 10.947006 38.279297 50422 10.697182 10.131989 37.668610 50423 41.754700 12.408127 38.087708 50424 42.192200 11.582336 37.968819 50425 29.972931 11.721695 37.482712 50426 29.737312 10.660751 37.466019 50427 30.692139 9.777420 38.082237 50428 41.911316 10.421982 37.296486 50429 45.914185 12.548065 39.039169 50430 46.548401 12.178497 38.786743 50431 2.533218 8.591751 39.053619 50432 2.480393 8.220871 39.018356 50433 9.037254 8.815216 37.878906 50434 29.805870 8.918640 37.319611 50435 3.091637 7.214096 37.388542 50436 30.826157 8.529739 37.855247 50437 54.629059 7.727417 39.048820 50438 31.667147 6.530777 37.416466 50439 31.605303 7.674225 37.893509 50440 46.971436 6.645706 41.070763 50441 47.301056 7.015015 39.791214 50442 48.174042 7.536621 40.679207 50443 46.798416 6.665039 38.885231 50444 50.418671 7.165894 37.690399 50445 49.766800 7.588760 38.846809 50446 34.753555 3.900909 37.706627 50447 32.926041 5.167007 37.382500 50448 33.464966 3.025940 37.429092 50449 32.444153 6.783524 37.841957 50450 46.244034 6.252365 39.759399 50451 55.875565 5.666748 38.019089 50452 4.741013 4.585953 37.308662 50453 5.515350 3.920715 37.545898 50454 32.237953 2.130341 37.159859 50455 34.896439 4.991089 37.791306 50456 42.426758 2.841873 37.988503 50457 44.190796 4.418503 38.257889 50458 6.148148 3.191971 36.788605 50459 45.332733 5.328842 39.733772 50460 44.538376 4.296890 40.059845 50461 7.073410 2.383026 37.187584 50462 6.853111 2.874451 38.017448 50463 33.402687 1.798004 37.840645 50464 34.864807 2.511093 38.517197 50465 36.369240 4.598907 38.518120 50466 7.213089 1.546387 37.224152 50467 32.370247 1.291138 37.635193 50468 41.173767 1.824341 37.707253 50469 54.167923 2.072113 37.637543 50470 54.888748 2.805786 37.905579 50471 2.452828 -1.496170 36.901169 50472 1.938789 -1.913116 36.442474 50473 53.106049 1.809784 37.899261 50474 2.186302 -2.374268 37.314400 50475 37.671860 -1.171814 38.329269 50476 36.857452 -1.956909 38.246780 50477 35.990227 -2.144653 37.540527 50478 48.094940 -1.890488 37.598122 50479 47.899841 -1.009933 37.478020 50480 48.020599 -0.993500 37.846657 50481 30.804367 -2.225357 37.471558 50482 32.552406 -3.294266 37.232994 50483 33.559128 -3.336502 37.442795 50484 34.276398 -3.453964 38.145073 50485 55.417984 -3.295868 37.178627 50486 2.051003 -3.541092 37.377098 50487 1.881332 -4.965332 37.882401 50488 31.704462 -3.043716 37.183792 50489 53.407669 -4.801010 37.134399 50490 1.892647 -5.640457 36.594498 50491 46.877075 -5.033722 36.528778 50492 47.890213 -5.769241 38.225616 50493 56.373428 -4.853500 37.981529 50494 56.701492 -6.304764 38.919922 50495 2.278023 -6.427780 36.088516 50496 1.769302 -6.438507 36.747902 50497 43.997116 -8.229828 37.001625 50498 56.848694 -7.314377 37.907509 50499 2.623955 -7.111771 36.069260 50500 3.185112 -7.885498 36.013176 50501 42.775635 -8.902039 36.966057 50502 45.087524 -7.542099 37.113350 50503 44.698761 -8.347763 37.831284 50504 3.411636 -9.320770 35.997673 50505 46.172729 -6.391022 36.891113 50506 3.810989 -10.462418 35.730812 50507 50.119141 -9.347366 37.618881 50508 51.486084 -9.640076 38.758728 50509 56.074432 -10.800262 36.983139 50510 57.744919 -11.745087 38.195488 50511 57.913254 -11.301971 39.114304 50512 57.602325 -10.635345 39.149109 50513 3.320595 -11.250275 35.912613 50514 3.675194 -12.632278 35.745041 50515 40.059814 -11.205353 37.342087 50516 5.599808 -12.827927 35.063416 50517 38.571854 -13.575592 36.873810 50518 38.903557 -12.996536 36.701561 50519 45.053635 -13.709213 36.425163 50520 46.235352 -12.960419 36.888428 50521 57.276108 -9.568420 39.293938 50522 57.006104 -8.592087 38.626694 50523 56.932953 -10.143311 37.899330 50524 2.369438 -13.481689 36.509758 50525 2.233109 -12.281616 37.153099 50526 2.216889 -14.382431 36.286026 50527 3.480766 -14.782974 35.512634 50528 56.784119 -11.589127 37.099991 50529 57.895126 -13.192780 37.659500 50530 2.861199 -16.665787 35.603859 50531 37.999420 -14.896713 36.268532 50532 37.697250 -15.327576 36.836380 50533 38.253250 -14.458206 37.106087 50534 43.276154 -15.040207 36.054428 50535 44.042938 -15.431870 36.619797 50536 44.321747 -14.660446 36.352455 50537 45.440506 -15.183365 37.273232 50538 46.550629 -13.953262 37.334396 50539 46.702637 -14.740845 37.692558 50540 2.190582 -15.423126 36.422966 50541 2.166710 -16.493042 36.323639 50542 2.869263 -18.132782 35.733337 50543 2.407387 -17.182388 36.310638 50544 37.372742 -16.411514 37.490578 50545 37.833336 -15.409439 37.863457 50546 38.142227 -16.033051 36.401909 50547 43.180450 -15.792679 36.367439 50548 58.827621 -16.077301 37.970863 50549 58.301025 -16.447266 37.060204 50550 42.536774 -16.925568 36.989403 50551 42.703873 -17.400650 37.687637 50552 41.617981 -17.289719 37.207123 50553 42.415894 -16.381088 36.453194 50554 2.764290 -17.864716 36.915733 50555 2.878021 -18.989670 36.403435 50556 40.268082 -17.171204 36.789963 50557 2.891541 -19.000778 35.610519 50558 57.496185 -17.611649 36.441116 50559 46.352051 -20.808014 36.294792 50560 49.855469 -20.461716 36.332703 50561 51.227600 -20.274796 36.410889 50562 52.783844 -19.780212 36.885338 50563 2.920754 -23.157364 35.446304 50564 40.515472 -22.757980 36.875816 50565 42.086502 -22.439575 37.357079 50566 45.419144 -21.250168 37.038055 50567 44.041275 -21.654739 37.167534 50568 58.197220 -21.845886 36.526062 50569 58.315140 -21.721527 38.032036 50570 57.207245 -22.184128 37.425423 50571 4.933487 -26.496445 34.804535 50572 6.282219 -27.275955 34.568993 50573 6.631455 -25.111542 34.391235 50574 39.214729 -23.555923 36.623306 50575 2.946838 -23.930710 35.366852 50576 3.286972 -24.487885 35.198380 50577 54.380600 -23.589478 37.258110 50578 55.419830 -23.075607 37.344872 50579 48.403595 -25.286514 37.651680 50580 49.873291 -24.874985 36.784035 50581 50.038116 -24.752884 37.902184 50582 51.087555 -24.917679 35.860298 50583 52.635971 -24.506668 36.029243 50584 53.195953 -24.054657 37.052635 50585 3.959198 -25.437714 35.139732 50586 3.925675 -26.756973 35.338234 50587 42.210617 -26.624649 35.843422 50588 40.729340 -27.223602 35.583336 50589 42.318787 -29.116394 37.057205 50590 42.611786 -27.828110 36.801346 50591 43.267609 -28.780807 37.638573 50592 61.733963 -27.071777 35.969032 50593 61.103455 -23.342346 37.155579 50594 61.061661 -22.900330 36.434090 50595 4.802811 -27.387390 35.124184 50596 38.873322 -29.334503 36.315681 50597 38.068077 -28.276627 36.420471 50598 39.552841 -28.144226 35.942627 50599 44.258575 -28.339127 38.248405 50600 43.979996 -26.791229 37.011818 50601 44.843567 -27.413437 38.313721 50602 60.929031 -25.491318 37.191986 50603 5.371903 -28.491257 35.431465 50604 7.005379 -28.598312 34.403343 50605 6.618538 -30.775894 34.393585 50606 5.179352 -30.163544 35.458916 50607 5.330139 -31.319702 34.889404 50608 38.398163 -25.045319 36.803993 50609 41.489822 -28.299011 36.319313 50610 40.564423 -28.275711 36.004089 50611 61.500580 -28.233032 35.785469 50612 54.184494 -28.699921 36.052414 50613 55.282959 -28.549988 35.886276 50614 56.381821 -28.459091 35.762817 50615 60.489594 -28.002060 36.564575 50616 60.151764 -28.982040 36.045670 50617 59.427597 -29.328934 35.602882 50618 60.312988 -29.986832 35.326820 50619 60.927399 -29.248642 35.737831 50620 6.365952 -29.536148 34.679855 50621 4.427490 -34.820877 34.542557 50622 7.651725 -31.709076 33.939201 50623 5.751549 -32.615189 34.419884 50624 49.584518 -32.680084 36.053925 50625 4.341934 -31.745651 35.418129 50626 3.468613 -32.506042 35.645164 50627 4.013069 -33.218323 35.323273 50628 3.403282 -35.859222 35.895020 50629 47.439087 -34.221848 34.264801 50630 3.490471 -34.390045 36.677254 50631 47.618622 -35.890884 35.316193 50632 48.802460 -36.041992 36.070770 50633 50.298325 -35.259262 37.090515 50634 49.011322 -34.930328 36.862328 50635 50.314575 -36.967407 36.162415 50636 51.541534 -38.375381 35.018318 50637 52.332047 -39.014297 34.873352 50638 4.153641 -39.388565 33.772011 50639 4.554062 -39.292084 34.528725 50640 52.930984 -39.477982 35.284294 50641 55.634277 -40.228638 35.434067 50642 56.811935 -39.430832 35.540359 50643 57.697479 -40.203873 35.184914 50644 58.311157 -38.875244 35.815277 50645 57.517365 -41.311401 35.094131 50646 58.176300 -40.815475 35.257141 50647 58.409470 -40.032806 35.372345 50648 58.604614 -40.660858 35.781715 50649 58.769073 -39.744431 35.815750 50650 54.559906 -40.064392 35.708008 50651 56.677551 -40.908127 35.055115 50652 56.630142 -42.411209 35.000595 50653 57.951996 -41.736771 35.751305 50654 3.772614 -43.509491 35.451958 50655 41.332870 -42.827545 34.628159 50656 40.908157 -43.111740 35.229500 50657 55.906464 -43.390167 34.325676 50658 56.437683 -43.616241 35.056793 50659 3.764816 -45.043716 33.464531 50660 10.906601 -45.974930 33.966492 50661 10.172760 -46.301682 33.919960 50662 10.924240 -45.655136 34.486412 50663 10.944817 -46.392838 33.611496 50664 11.565948 -45.950394 34.073792 50665 11.792198 -46.556625 33.623215 50666 11.788780 -47.023376 33.217087 50667 49.559692 -44.901031 34.753326 50668 50.022598 -45.096268 36.200546 50669 9.049774 -46.990173 33.662880 50670 9.320023 -45.856995 34.789024 50671 7.956939 -46.863937 34.103210 50672 10.168083 -46.935379 33.437164 50673 12.568939 -46.304520 34.602058 50674 11.789612 -45.654373 34.504105 50675 43.619415 -47.334839 34.631821 50676 52.252701 -45.688248 35.329796 50677 55.937683 -45.266235 35.661598 50678 6.945221 -46.561417 34.908768 50679 7.448654 -46.178101 35.351418 50680 7.927581 -46.288315 34.891327 50681 8.057297 -47.902252 33.532173 50682 8.399110 -49.991974 33.379150 50683 7.849853 -49.145996 33.441795 50684 43.932404 -46.961105 36.276291 50685 42.785172 -46.266296 36.173943 50686 3.557213 -49.112701 33.125580 50687 3.855148 -49.328278 33.489029 50688 6.628151 -47.444641 34.258881 50689 6.708107 -48.801392 33.867439 50690 8.278427 -47.233017 33.621048 50691 12.925690 -50.050644 34.445923 50692 13.148223 -51.117081 35.384392 50693 46.557953 -48.609650 34.303192 50694 3.557129 -50.926880 31.957941 50695 7.330513 -50.182266 33.745773 50696 12.431015 -52.446930 35.184151 50697 11.608788 -52.525024 34.276756 50698 51.368317 -49.995529 35.963203 50699 50.240524 -49.585205 36.373871 50700 49.838928 -49.819870 35.038811 50701 51.257477 -50.430359 34.485420 50702 53.050964 -50.598373 34.856430 50703 52.199539 -50.474091 35.080551 50704 54.022827 -50.565704 35.138374 50705 56.802200 -52.933640 34.305084 50706 3.849388 -54.201370 32.766068 50707 56.157272 -54.147583 35.058853 50708 3.894394 -54.896561 33.069687 50709 4.090225 -57.649002 32.317329 50710 55.519638 -55.330444 34.966217 50711 37.763214 -57.696274 32.794617 50712 16.050087 -59.718124 33.786568 50713 16.404404 -59.082642 33.801895 50714 17.780281 -59.007278 33.895035 50715 16.887886 -58.759018 33.827499 50716 18.375290 -58.520889 32.857651 50717 18.883331 -58.928986 32.700981 50718 45.553726 -58.390259 33.226555 50719 38.545013 -59.459854 33.317917 50720 39.986870 -60.074265 33.466492 50721 39.304077 -60.589203 34.103851 50722 44.804749 -59.106140 33.376671 50723 45.704895 -59.308746 33.784058 50724 50.524841 -59.558395 34.037483 50725 52.818817 -59.523056 34.479454 50726 4.876885 -61.968307 33.149460 50727 37.300545 -60.705856 33.708878 50728 42.056763 -60.548462 33.388123 50729 41.170685 -61.128616 33.974815 50730 42.975906 -60.566696 33.459518 50731 44.849030 -59.818878 33.914612 50732 48.855698 -58.883698 33.850174 50733 51.427277 -59.827072 33.651077 50734 51.613251 -60.136780 33.937164 50735 52.009750 -59.853027 33.646912 50736 52.397110 -59.909683 33.991081 50737 5.033859 -60.754929 33.557312 50738 37.012344 -61.404953 33.455444 50739 42.623657 -61.329269 33.886978 50740 43.942017 -60.732254 34.107430 50741 52.075439 -60.193314 33.995544 50742 19.462448 -62.408981 32.625107 50743 19.631920 -61.447937 33.570251 50744 19.832924 -62.769363 33.166428 50745 29.152542 -62.751678 34.170044 50746 30.095741 -61.743713 34.256180 50747 30.770447 -61.926636 33.866730 50748 30.966644 -62.427124 33.454269 50749 37.304260 -62.293686 33.951157 50750 37.366806 -63.007980 33.321579 50751 5.039101 -62.642258 33.327034 50752 5.811348 -63.006409 33.134407 50753 14.272415 -63.721344 33.056129 50754 19.902679 -65.055450 32.642502 50755 19.207306 -63.831390 32.098663 50756 29.146851 -65.584259 33.156677 50757 29.117912 -66.049194 33.914825 50758 29.181396 -64.575043 33.819061 50759 5.768372 -63.441772 32.429886 50760 7.591675 -64.914749 32.692894 50761 29.391846 -61.664658 35.397820 50762 37.758232 -63.616089 33.077400 50763 38.965065 -65.420090 34.075691 50764 38.608536 -65.077393 34.959450 50765 38.275284 -64.475967 34.401695 50766 38.332138 -64.326004 33.469315 50767 8.086090 -64.468536 33.724297 50768 8.212753 -64.536407 34.776352 50769 7.420075 -65.453201 33.914948 50770 20.463943 -63.833984 33.617233 50771 47.413620 -66.000122 33.240417 50772 47.168015 -67.101440 34.219254 50773 46.346298 -66.627686 33.945625 50774 13.192459 -65.282410 32.695435 50775 17.924278 -66.959686 32.174927 50776 20.727005 -65.341461 33.244957 50777 28.392883 -67.391815 32.720406 50778 32.702393 -66.055923 32.975922 50779 32.523811 -65.038193 33.134125 50780 32.150711 -63.904129 33.927177 50781 46.551270 -66.046082 33.270851 50782 48.089386 -66.915237 33.390450 50783 5.185623 -67.197174 32.270233 50784 7.572128 -65.753738 32.462776 50785 5.560776 -66.892059 33.262543 50786 17.597939 -67.899963 32.540886 50787 28.411346 -68.148041 33.751602 50788 27.889366 -68.326584 32.712280 50789 32.528885 -68.139282 33.487747 50790 33.258408 -68.176453 34.836777 50791 32.631287 -69.254745 34.214874 50792 39.983292 -66.107941 33.911758 50793 39.861580 -66.446060 35.058449 50794 39.460014 -66.113220 34.422272 50795 44.331741 -66.584229 33.316803 50796 43.240631 -67.032791 34.303391 50797 45.288116 -67.102890 34.498726 50798 12.200943 -67.082184 33.129311 50799 17.039246 -68.819061 32.834198 50800 21.220047 -67.567108 32.967590 50801 21.567139 -68.413788 33.099106 50802 21.355782 -68.513306 32.559631 50803 11.421280 -68.606140 32.445732 50804 15.716217 -69.086380 32.475914 50805 15.045029 -69.767960 32.345657 50806 16.700912 -70.370682 33.277718 50807 16.916260 -69.568176 33.199516 50808 16.898842 -71.412735 33.253464 50809 21.237656 -69.332306 32.363274 50810 21.526230 -69.094254 32.811256 50811 27.403046 -69.419647 32.630470 50812 47.579651 -67.924576 33.965706 50813 3.942215 -69.368713 32.385368 50814 4.221024 -70.164185 32.125916 50815 21.387268 -69.709412 32.793915 50816 21.004303 -71.008728 32.558540 50817 31.169922 -72.329285 33.798752 50818 31.358421 -74.033386 34.203987 50819 30.771713 -73.682068 33.159935 50820 30.772453 -71.369553 32.619232 50821 14.585999 -70.917374 33.137955 50822 13.544701 -72.040588 32.797905 50823 13.132233 -72.700394 33.290871 50824 27.070831 -71.446182 33.532806 50825 46.531555 -69.752640 33.488884 50826 5.385956 -71.966049 31.971407 50827 4.279427 -70.155350 33.370644 50828 4.528679 -69.945908 36.302841 50829 5.016441 -72.700821 34.303833 50830 8.495248 -71.771622 32.164062 50831 14.136871 -71.532120 33.262238 50832 30.374878 -72.787704 32.231201 50833 44.202316 -72.454132 32.251541 50834 43.702698 -72.356781 33.177719 50835 44.350250 -71.750504 32.953957 50836 43.209351 -73.505737 32.890976 50837 4.587250 -71.243378 32.284950 50838 8.644363 -71.949875 33.388687 50839 21.163757 -73.891373 33.492889 50840 26.478127 -72.772659 32.485382 50841 43.140778 -72.654892 34.007301 50842 43.788452 -71.694733 34.105782 50843 17.377914 -74.104935 32.506691 50844 20.531128 -75.369125 33.047836 50845 36.021210 -73.815643 31.873217 50846 11.340401 -75.428101 32.303223 50847 19.090401 -76.087418 33.529144 50848 26.550896 -73.774139 32.406654 50849 30.997551 -76.817657 32.313904 50850 31.395973 -75.932068 33.495224 50851 35.732864 -74.473679 31.865335 50852 35.820839 -75.337234 32.042900 50853 36.966240 -74.388763 32.052559 50854 31.393303 -77.542252 32.709396 50855 36.113281 -76.566116 32.166252 50856 36.632774 -75.676804 32.294846 50857 40.117767 -76.449661 32.541306 50858 42.094101 -75.179581 32.734802 50859 6.476593 -77.414459 30.644320 50860 11.752960 -77.978073 31.522440 50861 27.109970 -75.853073 32.917282 50862 27.027756 -75.071411 33.152702 50863 37.815681 -76.040085 32.240646 50864 37.275665 -77.869202 32.611465 50865 40.043213 -76.985855 33.212173 50866 38.980850 -77.109802 32.595139 50867 39.130310 -77.855759 33.675171 50868 11.167221 -78.008041 32.147202 50869 10.957703 -75.556717 33.460197 50870 10.484184 -76.250626 33.227264 50871 10.685333 -76.802490 32.776360 50872 31.835276 -77.144730 33.833885 50873 38.454262 -77.991333 32.945847 50874 11.992668 -79.151566 31.983446 50875 35.781082 -77.637100 32.014236 50876 38.127907 -78.674011 33.576439 50877 7.449707 -79.716202 30.599413 50878 12.926849 -81.760040 32.489891 50879 13.426132 -82.037613 31.619280 50880 32.173828 -81.327225 31.841036 50881 32.478195 -80.988998 32.562714 50882 35.827347 -78.720123 32.108047 50883 19.905228 -81.215958 33.232925 50884 35.397400 -80.044662 32.034439 50885 22.245926 -81.283920 31.903872 50886 23.633636 -81.535309 31.613260 50887 34.950516 -81.210037 32.100784 50888 11.538666 -80.822052 33.293564 50889 12.460533 -81.590637 32.916252 50890 12.257294 -82.548019 32.519012 50891 12.667755 -83.175766 31.433313 50892 18.487091 -82.850647 32.378983 50893 18.381104 -81.890488 32.774467 50894 24.862122 -81.984314 31.585657 50895 25.825607 -82.430557 31.841753 50896 27.498947 -82.882645 32.283363 50897 26.644012 -82.783798 32.008873 50898 34.289467 -81.692825 32.013939 50899 34.667427 -81.341705 33.813141 50900 34.680305 -81.554352 32.830246 50901 33.556320 -81.533920 32.795380 50902 28.432541 -82.856369 33.221313 50903 9.095657 -83.806549 32.823158 50904 8.769287 -84.618942 32.366699 50905 23.028168 -87.270584 32.147186 50906 16.129135 -86.798599 31.009806 50907 15.321686 -87.107681 30.964128 50908 15.495224 -87.232605 31.828287 50909 16.761681 -86.907867 31.935167 50910 24.899368 -86.933273 31.762255 50911 23.961975 -87.220200 32.225182 50912 9.438553 -87.562988 31.113413 50913 9.166077 -86.775345 32.238190 50914 14.291611 -88.056885 31.149233 50915 14.781860 -87.502747 31.343126 50916 13.983246 -88.847107 31.119974 50917 17.770432 -89.427536 31.298586 50918 20.676506 -88.732742 32.130295 50919 20.025505 -88.358490 31.777018 50920 10.258018 -87.891525 32.528389 50921 10.257782 -87.098053 33.980034 50922 11.258789 -87.759247 33.983963 50923 13.268631 -89.052872 31.791468 50924 12.274567 -89.308807 31.740046 50925 13.665604 -89.675095 30.766359 50926 13.939461 -88.435272 31.867281 50927 24.846069 -89.265503 31.048082 50928 25.275742 -88.917908 31.184938 50929 11.603912 -89.634460 30.856943 50930 17.709740 -90.631393 30.794764 50931 16.415390 -90.437820 30.568071 50932 22.971207 -90.236145 30.934946 50933 23.892082 -89.600479 31.268816 50934 19.295448 -90.579788 31.551462 50935 11.682175 53.201416 40.991081 50936 9.203400 53.417648 42.382034 50937 6.267395 53.309265 42.284203 50938 12.283165 50.794312 40.892487 50939 11.636627 51.904755 41.614655 50940 10.753021 53.500778 41.503403 50941 5.548142 52.565231 42.718979 50942 5.572441 51.910461 42.778641 50943 12.466705 50.002304 40.800354 50944 18.730011 50.814560 40.780685 50945 17.829285 50.785217 41.229904 50946 16.705231 50.621216 40.844849 50947 19.222122 49.997864 41.943794 50948 18.490234 50.380814 42.039680 50949 18.778648 50.493713 41.382431 50950 5.949684 50.021362 40.865211 50951 12.153839 50.007751 41.355965 50952 12.044937 49.489136 42.136444 50953 13.061928 49.404358 41.197723 50954 6.785538 47.991394 40.742249 50955 6.457794 48.792877 41.271332 50956 6.300354 47.874084 41.512970 50957 20.138489 47.836273 42.091400 50958 5.315735 46.222946 40.744095 50959 5.673630 45.759338 39.888145 50960 6.414932 46.897400 40.452034 50961 5.527786 47.055847 41.618805 50962 5.367256 47.559631 42.396492 50963 4.870773 46.846466 42.451714 50964 18.606232 46.053009 40.480263 50965 4.935402 45.437988 40.545639 50966 17.876106 45.099945 40.345383 50967 28.338242 45.403748 39.555031 50968 28.035660 44.184845 40.270241 50969 4.924339 44.479034 41.219086 50970 28.488083 42.959091 41.175774 50971 30.875290 43.164322 41.102791 50972 5.703217 42.425156 39.945213 50973 6.005287 42.595276 40.726593 50974 18.218460 42.103668 40.223763 50975 33.612259 41.225616 40.386490 50976 31.886095 42.248978 41.337387 50977 8.310989 40.113739 40.123726 50978 23.173294 40.985550 43.429070 50979 23.196396 42.205292 43.774818 50980 22.469078 41.731232 42.449287 50981 28.962296 41.526443 42.197090 50982 28.403458 39.714844 42.466682 50983 29.018799 40.547729 43.454361 50984 35.682983 38.921860 40.645866 50985 7.620880 39.467758 40.656387 50986 6.310982 38.470932 41.010956 50987 34.635735 37.308594 42.573303 50988 35.282501 38.241913 41.779312 50989 35.708893 36.915649 41.591003 50990 22.282898 39.297119 42.566559 50991 21.207947 38.108887 42.978851 50992 5.525261 35.777222 40.101646 50993 27.077545 37.421936 41.493561 50994 27.467606 38.414230 43.207939 50995 27.967377 38.606049 41.366776 50996 37.784531 36.449310 39.681694 50997 5.680260 34.248718 39.613235 50998 25.374863 36.228210 42.352142 50999 24.715538 35.166031 41.985001 51000 31.628626 34.414917 40.322250 51001 6.411461 34.355560 40.700569 51002 7.087738 33.767075 40.878731 51003 6.711365 32.868927 39.874382 51004 16.640198 33.339905 40.478378 51005 7.369988 33.648788 41.369888 51006 7.851699 32.937790 40.921608 51007 24.220192 33.730789 39.909271 51008 24.340500 33.785416 40.240608 51009 6.087456 30.632080 39.390259 51010 7.654022 30.475388 39.784996 51011 7.146950 29.374634 39.762413 51012 17.301254 32.134094 39.859657 51013 31.529022 32.555176 41.421059 51014 32.095390 31.720428 40.256119 51015 32.146622 32.012207 41.405159 51016 31.313980 32.947845 40.393150 51017 7.465729 31.546356 39.767838 51018 7.927505 32.277481 40.209557 51019 7.853271 29.768341 39.834946 51020 8.493546 30.140518 40.602661 51021 19.257370 30.284851 39.790215 51022 18.255028 31.303909 40.021996 51023 24.620712 32.840042 41.103455 51024 25.240532 31.742188 40.877769 51025 32.993011 31.778839 41.367516 51026 38.220764 30.848541 41.285286 51027 38.857697 30.259186 41.226234 51028 4.170662 28.507462 39.360558 51029 5.052765 29.340546 39.494202 51030 6.018372 28.946381 39.842430 51031 7.998840 29.255249 40.003075 51032 8.735519 28.637497 40.631622 51033 25.632057 30.138763 39.642128 51034 26.351967 30.906616 41.193153 51035 27.033508 30.443146 41.639244 51036 26.588196 29.927612 40.666359 51037 26.177742 29.172073 39.693886 51038 38.962753 30.331360 42.093689 51039 38.947189 30.273285 42.862160 51040 38.471519 30.836533 42.851624 51041 26.554398 28.988770 40.548965 51042 19.869919 28.245255 42.199249 51043 20.577103 29.221161 41.852364 51044 20.506973 28.846970 40.141830 51045 40.258545 27.246735 41.214195 51046 40.118576 28.057953 42.041672 51047 39.866333 28.858643 42.037888 51048 19.196365 27.077515 41.500511 51049 18.916168 27.497177 42.432396 51050 40.504303 25.907074 40.310059 51051 3.292702 24.951782 39.803284 51052 18.187103 23.495575 39.455391 51053 18.205467 24.719269 40.630669 51054 19.329163 26.141113 40.036118 51055 17.761429 25.430603 42.075752 51056 18.552223 26.060928 41.342598 51057 24.843170 27.181366 41.151154 51058 40.197372 24.429413 39.390152 51059 3.277924 23.742706 39.131401 51060 3.745133 24.723663 40.898148 51061 3.299782 23.227158 40.635498 51062 22.502808 23.276123 39.733765 51063 43.525070 23.687714 41.076744 51064 42.665039 23.964020 40.347656 51065 3.350563 22.565979 39.212822 51066 3.258232 21.278412 40.105186 51067 41.598206 24.795212 40.323715 51068 43.979614 23.270920 41.011185 51069 44.490814 21.587830 40.050468 51070 3.215530 19.698486 40.267525 51071 4.054009 20.049194 38.969055 51072 17.913010 22.052826 39.532784 51073 45.286102 20.024384 40.937782 51074 45.302795 20.998566 40.834755 51075 44.682983 20.222519 40.176224 51076 44.232895 20.399628 39.612320 51077 3.588348 18.793015 39.610359 51078 5.212738 18.744019 38.718796 51079 17.650513 21.052979 39.710815 51080 17.874939 20.068039 39.255630 51081 45.063995 22.176361 41.139816 51082 44.447983 22.747498 41.218124 51083 4.211792 17.922958 39.457878 51084 5.050469 16.830444 39.529076 51085 6.291153 17.379822 38.978310 51086 7.464668 17.611923 38.453331 51087 18.969574 18.499496 39.023926 51088 19.739395 18.351181 39.093651 51089 7.366364 16.318314 39.116272 51090 18.988052 17.863968 39.589432 51091 19.985977 16.966537 40.082024 51092 41.440765 18.222549 38.575768 51093 18.935837 17.286819 40.115196 51094 40.767639 17.235809 39.372910 51095 41.766327 17.622711 39.791153 51096 39.977432 16.567352 39.660805 51097 46.574020 15.592957 38.933517 51098 37.194626 15.431015 39.501038 51099 36.626770 15.711258 38.471970 51100 35.735481 14.973175 39.139984 51101 47.312469 15.263000 39.207085 51102 9.042114 13.665588 39.439743 51103 10.292671 12.293823 38.439178 51104 32.577644 13.491425 39.716774 51105 33.317810 13.833771 39.946724 51106 34.562614 14.506989 39.328476 51107 43.490326 13.657318 38.640633 51108 44.762115 12.639099 38.839943 51109 43.846649 13.100128 38.920021 51110 46.611572 14.838776 39.258896 51111 45.956818 13.774994 39.203705 51112 50.402084 14.484955 38.900040 51113 31.843493 13.163361 38.997910 51114 49.962677 14.608459 39.135056 51115 47.742752 13.834808 39.246262 51116 47.587296 12.804352 39.078224 51117 31.815645 11.658783 39.774323 51118 31.602266 12.414551 39.448120 51119 10.806793 9.871185 39.062912 51120 10.592056 9.128448 38.321472 51121 31.736284 10.322952 39.022720 51122 31.901842 12.594238 39.820717 51123 31.629610 8.977707 38.389381 51124 32.698654 9.320709 39.067162 51125 10.604370 8.418152 39.339348 51126 9.970322 8.204865 38.488777 51127 32.514053 7.998596 38.348129 51128 33.355797 6.833588 38.119965 51129 53.411682 8.490860 39.213699 51130 52.860352 8.546143 39.348946 51131 3.182778 5.587814 38.349518 51132 33.410660 8.146103 38.721779 51133 51.092422 8.227753 39.757439 51134 52.121841 8.282196 39.139847 51135 49.688278 8.089844 40.663948 51136 34.336647 7.273941 38.520874 51137 35.316475 6.067352 38.303772 51138 35.397537 7.775253 38.975868 51139 34.243149 5.956757 37.968895 51140 36.298180 6.600327 38.670280 51141 37.102951 7.557266 39.188011 51142 36.248703 7.658661 39.057274 51143 37.192108 6.165131 38.711823 51144 38.213661 6.485550 39.187355 51145 4.202072 4.358246 38.319221 51146 37.654922 5.402420 38.813507 51147 55.416275 5.817841 38.933334 51148 38.146774 4.248566 40.611526 51149 38.892723 4.728767 40.466187 51150 38.674667 5.270020 39.718384 51151 54.102539 3.770081 39.562134 51152 54.519409 4.559647 39.925293 51153 54.168793 3.221390 38.930496 51154 7.685920 2.047516 37.844994 51155 36.956001 3.738808 39.375359 51156 37.662262 4.445007 39.412308 51157 41.468811 1.600861 39.169601 51158 33.934792 1.547318 38.446808 51159 49.545013 1.684753 38.810135 51160 49.931946 1.953674 38.776649 51161 52.772842 3.000046 39.535233 51162 53.844284 2.515549 38.452599 51163 4.749725 -0.337387 37.309784 51164 3.286720 -0.836319 36.911140 51165 7.491226 0.578110 37.716644 51166 7.775192 1.377625 37.625191 51167 8.148682 1.280548 38.221535 51168 34.068123 1.308533 39.364777 51169 32.985687 1.059448 38.408859 51170 51.617523 2.089966 38.759995 51171 6.586624 -0.464417 37.813049 51172 5.743797 -0.419983 37.621796 51173 8.528824 0.119003 38.835670 51174 30.938812 -1.108856 38.572975 51175 32.669815 0.271027 39.560768 51176 48.392288 -0.991760 38.382088 51177 1.802460 -2.685303 36.624786 51178 5.349136 -3.311279 39.133759 51179 6.470757 -2.489166 38.727501 51180 6.883804 -3.558640 39.225174 51181 48.992065 -0.115784 39.690117 51182 49.195938 -2.037704 38.821922 51183 49.170807 -3.654953 38.464058 51184 49.753967 -3.270950 38.951958 51185 55.119568 -4.048721 37.669838 51186 31.961466 -3.233994 37.891739 51187 31.668154 -2.347641 40.307709 51188 31.494072 -2.642014 39.599960 51189 32.332024 -3.336517 39.862991 51190 33.219978 -3.682755 38.756607 51191 33.515785 -4.078140 39.747566 51192 33.065964 -3.938858 39.759735 51193 49.406403 -4.829193 39.103989 51194 49.940186 -6.297592 40.510857 51195 50.566299 -3.900742 39.917587 51196 54.802032 -5.095688 38.585503 51197 1.848869 -5.686020 38.731804 51198 1.696266 -6.374283 38.020561 51199 48.207504 -7.058807 39.572113 51200 48.688782 -4.985901 38.509552 51201 1.842651 -7.277267 36.961128 51202 1.648987 -8.757355 37.485382 51203 2.273361 -10.301926 36.818939 51204 45.797974 -7.514740 37.861923 51205 46.959290 -6.387253 37.737305 51206 56.688965 -7.189789 40.074051 51207 57.024826 -7.445175 39.324486 51208 56.862900 -8.467575 40.279770 51209 44.583817 -9.793137 39.339180 51210 43.457230 -9.600891 38.312851 51211 43.552979 -10.582184 39.373970 51212 56.232117 -7.626144 40.613510 51213 55.800476 -6.730453 40.073051 51214 1.426613 -7.371765 38.204239 51215 1.338104 -7.834991 37.840683 51216 41.335876 -10.375183 37.600548 51217 41.830536 -9.472778 36.963669 51218 42.163025 -11.602814 38.918518 51219 43.364044 -11.828598 39.667313 51220 43.144897 -11.202133 39.553085 51221 42.310516 -9.576569 37.513077 51222 50.359619 -10.114120 38.239693 51223 56.161377 -9.898132 37.302826 51224 1.510788 -9.831772 38.092278 51225 2.392632 -11.476212 36.694031 51226 39.944542 -12.186035 37.830200 51227 2.235886 -14.228561 37.491486 51228 39.334068 -13.507385 37.876221 51229 40.695892 -11.564194 38.097839 51230 40.730621 -13.051422 38.660423 51231 47.857651 -12.896820 37.796585 51232 57.965759 -12.861465 39.392982 51233 57.939941 -11.795471 39.203583 51234 2.292519 -16.505997 37.198441 51235 39.065079 -15.192673 38.904991 51236 2.267731 -15.364731 37.720055 51237 46.264603 -16.059677 38.412445 51238 45.089539 -16.603027 38.291260 51239 43.686554 -16.463013 37.266510 51240 58.003021 -17.162476 36.708656 51241 58.745514 -16.645172 37.780678 51242 38.004425 -17.423401 37.297417 51243 37.436317 -15.982315 38.346588 51244 37.408867 -17.704025 37.828377 51245 39.028473 -17.429337 37.060974 51246 40.429382 -18.386200 38.264664 51247 58.103592 -17.341049 37.446541 51248 58.644180 -16.704987 38.719864 51249 38.496300 -19.037766 38.654999 51250 36.817406 -18.200500 38.407967 51251 2.983910 -20.304474 37.057968 51252 2.726250 -21.385681 37.514458 51253 2.678513 -21.800018 36.654930 51254 54.978760 -18.965485 38.875931 51255 56.153824 -18.576736 37.732582 51256 48.650085 -20.577560 37.122978 51257 47.919113 -20.817047 37.506203 51258 49.789215 -20.662125 38.171951 51259 2.501846 -22.740814 36.197548 51260 43.022202 -21.808395 36.850388 51261 44.979340 -22.135788 38.516258 51262 47.052658 -21.216324 37.918816 51263 48.554230 -21.074493 38.573395 51264 41.319977 -23.523270 38.299683 51265 43.163483 -22.295059 37.805771 51266 60.889618 -22.502792 37.045647 51267 2.360535 -22.512039 36.890373 51268 2.210655 -23.024750 36.875839 51269 2.349793 -23.619629 36.166626 51270 2.544228 -24.930389 36.179726 51271 51.953094 -24.245850 37.342865 51272 50.759766 -24.516800 37.142403 51273 53.571274 -23.707809 38.901146 51274 51.891266 -24.198608 38.813400 51275 3.142250 -26.299866 35.946686 51276 45.362091 -26.025146 37.272308 51277 46.536652 -25.938538 37.844742 51278 60.949417 -24.444183 37.415466 51279 3.541618 -26.970398 35.904953 51280 4.225418 -27.473419 35.831337 51281 37.461029 -26.720871 37.114372 51282 61.390396 -27.287109 36.547264 51283 37.244446 -28.048126 37.153725 51284 54.060349 -28.337570 37.188110 51285 54.829056 -28.083450 37.010155 51286 55.695648 -27.931335 36.867828 51287 60.159943 -26.691177 37.399414 51288 58.542542 -26.350143 38.589500 51289 60.941025 -27.196533 36.916687 51290 61.108887 -27.678558 36.595627 51291 60.830383 -28.706573 36.128319 51292 37.415314 -29.222488 36.951729 51293 39.632782 -29.273483 36.242172 51294 38.135567 -29.367020 36.486374 51295 40.455688 -29.266022 36.369064 51296 41.478668 -29.724594 36.847923 51297 53.649353 -28.904633 38.014839 51298 36.434898 -30.367142 37.820297 51299 37.289825 -30.216583 37.287766 51300 37.964615 -31.361908 37.915413 51301 38.439148 -30.296600 36.903152 51302 36.337296 -31.218491 38.270676 51303 51.870758 -31.130020 37.018105 51304 51.004700 -31.360580 36.462959 51305 3.406563 -31.973694 36.183624 51306 3.179131 -32.500504 35.918442 51307 5.003624 -29.259262 36.598984 51308 5.210800 -28.817795 37.508057 51309 4.929024 -29.969269 37.797043 51310 3.264320 -32.852127 36.553207 51311 48.782440 -34.139847 36.693520 51312 56.791122 -35.955566 36.409447 51313 55.592804 -35.427155 36.810036 51314 56.664642 -37.334946 36.160919 51315 57.431152 -34.973999 36.870300 51316 58.088699 -36.025864 36.437492 51317 58.666779 -36.019669 36.908157 51318 55.945602 -33.504791 37.340431 51319 57.497101 -36.212830 36.311890 51320 3.379601 -36.696152 35.544098 51321 3.754959 -37.460739 35.293762 51322 58.316986 -37.129196 36.342888 51323 59.189255 -37.444229 37.243790 51324 59.278732 -35.737152 38.030579 51325 4.428772 -38.422867 35.144569 51326 51.405533 -37.821014 35.977669 51327 4.196831 -38.133514 36.115433 51328 54.863968 -39.077057 36.113525 51329 53.678391 -37.536896 36.723129 51330 53.828629 -39.405685 35.963898 51331 55.337646 -37.886353 36.357521 51332 55.875641 -38.806747 35.909424 51333 59.308182 -36.800446 38.369263 51334 59.109375 -38.773178 36.136055 51335 59.067795 -38.274399 36.380531 51336 59.308441 -38.721115 36.345589 51337 4.851631 -40.167572 34.846367 51338 5.323860 -39.238831 36.160103 51339 6.152657 -40.256424 35.901726 51340 5.431236 -40.197052 35.338165 51341 52.613129 -38.552872 35.938690 51342 59.079514 -39.109146 36.332130 51343 58.874084 -40.011032 36.602509 51344 4.369454 -40.776642 34.513809 51345 4.575966 -42.108673 35.490364 51346 4.847107 -41.109131 35.082130 51347 51.673157 -37.334915 36.843399 51348 52.440796 -37.823761 36.659210 51349 52.604950 -37.472000 37.024918 51350 53.937531 -40.098175 35.557190 51351 54.494766 -39.582352 36.076363 51352 58.697586 -38.597321 39.007423 51353 59.080658 -37.759048 38.258713 51354 59.041443 -38.847809 37.409332 51355 41.509918 -42.417969 35.662918 51356 42.527191 -41.948257 35.631577 51357 43.706940 -42.211136 35.170990 51358 43.515289 -41.643814 36.158279 51359 3.676560 -45.239639 34.576035 51360 40.931122 -43.894562 35.510635 51361 46.628998 -43.679993 35.647751 51362 46.581787 -42.722763 36.529701 51363 57.328445 -43.218323 36.708672 51364 3.736054 -44.872437 35.629601 51365 11.871857 -45.377213 34.988327 51366 10.845306 -45.198532 35.143784 51367 11.834030 -44.780655 35.798759 51368 48.111237 -44.428406 35.596985 51369 42.137848 -46.110641 34.881828 51370 48.758041 -44.693634 35.561539 51371 4.672562 -47.787811 34.521088 51372 5.434929 -46.564407 35.241562 51373 5.524719 -48.301865 34.309776 51374 13.123535 -46.995956 34.931076 51375 13.039032 -47.312180 34.408195 51376 45.407532 -47.723206 36.387115 51377 45.528412 -47.476654 37.927826 51378 44.139160 -47.101273 37.728233 51379 51.185608 -45.587067 35.744591 51380 53.989868 -45.631180 36.911789 51381 51.668289 -45.562729 36.713509 51382 4.240181 -47.958847 34.148178 51383 44.554657 -47.480362 35.528671 51384 4.536957 -48.931046 34.001083 51385 4.260872 -50.765732 33.494370 51386 5.823158 -50.453506 34.027420 51387 46.806061 -48.568085 35.539711 51388 46.493195 -48.164017 36.378685 51389 49.957382 -49.251755 37.071213 51390 50.864182 -49.322342 37.526886 51391 49.373810 -48.780746 38.078491 51392 48.273041 -49.194489 35.227318 51393 47.191101 -48.345520 36.517960 51394 13.516434 -51.464752 36.175896 51395 13.289848 -51.916397 36.158218 51396 55.695953 -50.575287 35.982872 51397 54.787949 -50.365891 36.139175 51398 4.252213 -52.191986 33.588242 51399 4.431671 -53.189621 33.773247 51400 5.245415 -52.314484 34.130798 51401 6.380928 -52.343201 34.255081 51402 7.381714 -51.838928 34.049934 51403 8.579956 -52.112411 34.021362 51404 9.323616 -52.957336 34.203545 51405 8.313988 -53.216125 34.212318 51406 56.662857 -51.604828 35.675056 51407 4.431053 -54.611969 33.561844 51408 7.315399 -53.583282 34.190132 51409 6.300987 -53.780960 34.188034 51410 10.295685 -53.071716 34.112465 51411 10.977837 -52.491089 34.002419 51412 56.809875 -52.331497 35.241379 51413 11.400620 -53.642288 34.573692 51414 10.493912 -53.860519 34.218857 51415 56.539612 -53.068970 35.412140 51416 4.454109 -53.932434 33.785881 51417 6.216553 -55.461914 33.856979 51418 5.216042 -54.024796 34.022339 51419 5.126526 -55.528244 33.567947 51420 7.262726 -55.333115 33.940132 51421 9.249603 -54.170135 34.189377 51422 8.357040 -55.089493 33.990082 51423 10.490570 -54.985687 34.180847 51424 9.947282 -53.781235 34.238373 51425 11.596710 -54.868484 34.714981 51426 5.733727 -57.264267 33.569122 51427 11.442947 -55.523361 34.548637 51428 11.451744 -56.463501 34.618187 51429 11.133850 -57.421005 34.449471 51430 10.240266 -57.028076 34.152489 51431 11.918808 -57.402802 35.178513 51432 12.385414 -56.620010 35.880524 51433 12.390366 -57.292816 35.967720 51434 4.784714 -57.860489 33.075218 51435 5.242798 -58.779129 33.565948 51436 7.108841 -57.473419 33.911362 51437 8.071564 -56.863235 33.893097 51438 9.016228 -57.075958 33.977798 51439 9.410980 -55.594528 33.988823 51440 4.709808 -59.225494 33.404755 51441 4.611443 -59.667908 33.217171 51442 6.275025 -58.652695 33.991127 51443 7.245529 -59.638306 34.440735 51444 8.406830 -58.657288 34.251053 51445 9.696793 -58.531708 34.481590 51446 11.006958 -58.142212 34.975105 51447 18.682564 -59.159149 33.373993 51448 54.883514 -56.058167 35.588051 51449 54.308197 -57.724213 34.832031 51450 4.946991 -59.674042 33.732216 51451 16.862755 -59.057159 34.286011 51452 19.037155 -60.027328 33.903366 51453 45.018143 -59.231384 35.698799 51454 45.737854 -58.559219 35.665565 51455 45.582184 -59.220245 35.042023 51456 45.723389 -59.478638 34.430016 51457 46.404053 -59.061142 34.986404 51458 46.625000 -59.249634 34.282394 51459 51.865936 -60.063477 34.679764 51460 52.390045 -59.493011 35.834274 51461 53.829727 -57.992737 35.711838 51462 38.205856 -60.716217 34.335815 51463 45.057648 -58.646576 36.241943 51464 44.951538 -59.961334 34.826439 51465 44.598969 -60.833160 35.212898 51466 47.830795 -59.075943 34.960594 51467 49.336533 -59.725815 34.767487 51468 53.336151 -58.850601 35.265541 51469 16.437317 -61.165543 35.114334 51470 17.032013 -60.152832 35.315239 51471 16.439331 -59.813675 34.518951 51472 19.534622 -60.804413 34.458107 51473 19.992859 -61.906311 34.987709 51474 20.170822 -62.507629 33.997856 51475 30.672058 -61.498016 34.356850 51476 31.093521 -61.817413 34.462608 51477 37.516747 -61.426987 34.382607 51478 39.439049 -61.371689 35.142281 51479 40.090454 -60.951553 34.061836 51480 49.994629 -59.988251 34.779961 51481 4.759468 -62.475006 33.197975 51482 31.431061 -62.608841 33.939560 51483 39.748291 -61.113190 34.451134 51484 40.277924 -61.423050 34.554688 51485 42.404663 -62.108475 34.578537 51486 41.122009 -62.139511 35.238205 51487 43.751678 -62.580917 35.121613 51488 43.705658 -61.679535 34.589096 51489 5.527054 -62.055145 33.886963 51490 4.899574 -62.342545 33.539635 51491 7.764068 -63.831390 33.385094 51492 7.255829 -62.573853 34.017433 51493 8.299896 -63.567642 34.236908 51494 8.684998 -62.498932 34.824196 51495 15.616241 -62.798325 34.460350 51496 13.348740 -65.814758 34.403885 51497 14.289673 -64.459518 34.086082 51498 14.209518 -65.739258 35.547104 51499 14.432739 -65.068237 35.040825 51500 32.838577 -65.343323 34.342003 51501 37.801369 -63.401505 34.346413 51502 37.768036 -62.259140 35.023071 51503 21.171677 -64.890991 34.131828 51504 29.162231 -65.804688 35.172699 51505 28.608978 -64.835052 35.574661 51506 38.221748 -64.252838 35.411049 51507 7.364014 -65.826431 32.914696 51508 6.665291 -66.198608 33.148598 51509 21.273071 -66.227325 33.754143 51510 29.140251 -66.820526 34.730026 51511 28.796921 -67.127838 33.779541 51512 5.020210 -67.350983 35.077011 51513 16.623215 -67.776337 32.187485 51514 21.004517 -63.833755 34.984436 51515 21.334579 -64.597702 34.854889 51516 44.229507 -67.261108 34.832054 51517 46.589539 -67.996887 35.125526 51518 46.860504 -68.877945 34.530739 51519 46.123413 -69.012436 35.811256 51520 3.939499 -68.903839 32.857948 51521 4.105660 -68.824890 33.323944 51522 11.460495 -68.316177 34.109535 51523 12.261566 -67.179230 34.964516 51524 21.517654 -67.616516 34.065025 51525 21.449806 -69.710037 33.808052 51526 32.939438 -66.971054 33.984535 51527 46.206207 -67.257553 34.719055 51528 10.937584 -69.336258 33.392609 51529 16.268921 -69.537674 33.198631 51530 15.406005 -70.239624 33.160851 51531 27.919189 -69.178619 33.674011 51532 32.204941 -70.871323 34.741379 51533 31.685366 -71.233582 34.277359 51534 31.840944 -70.250168 33.837379 51535 10.341240 -70.274979 33.432343 51536 21.440628 -72.241455 34.204285 51537 27.470825 -70.275681 33.597496 51538 9.702988 -71.023636 33.734695 51539 31.291451 -71.050873 33.458771 51540 45.122803 -70.920334 33.461449 51541 26.959000 -72.879791 33.506653 51542 27.222298 -72.042252 34.241264 51543 4.945892 -72.035614 32.947922 51544 5.997192 -72.949554 33.135284 51545 7.408531 -72.844772 33.494682 51546 8.219223 -72.602386 35.273445 51547 12.567291 -73.366180 33.505264 51548 16.664154 -72.105331 33.482483 51549 16.659393 -73.164383 33.389137 51550 43.332687 -71.821899 34.949532 51551 43.719147 -71.412613 35.114502 51552 11.862076 -74.193405 33.024742 51553 16.720551 -74.037689 33.201187 51554 21.795685 -74.914734 34.292290 51555 21.946121 -75.845459 34.430710 51556 21.273643 -75.531448 33.738480 51557 27.006363 -74.282196 33.326050 51558 42.635132 -73.511505 34.201340 51559 42.867966 -72.569397 35.328400 51560 16.651474 -74.660110 33.350533 51561 17.243500 -75.186462 33.190918 51562 42.196823 -74.597092 33.618393 51563 20.059494 -76.079926 33.400223 51564 20.732010 -75.994431 33.455383 51565 10.553665 -78.041702 32.870140 51566 27.679329 -76.955353 33.452133 51567 31.982180 -78.357895 33.487534 51568 40.448914 -76.531815 34.251366 51569 40.918579 -75.701721 34.507690 51570 41.425781 -74.932709 34.625359 51571 27.981659 -78.697662 32.938370 51572 36.724365 -79.629364 33.157654 51573 37.614502 -79.505188 34.034119 51574 28.479851 -79.894547 33.034698 51575 38.659332 -78.270447 34.795349 51576 18.286453 -81.753006 33.877502 51577 18.476479 -81.585220 34.656380 51578 19.022476 -81.360703 34.094345 51579 18.869766 -81.250916 33.249474 51580 28.670670 -79.205063 33.987755 51581 29.034164 -80.599991 33.849037 51582 29.435982 -79.837341 35.052277 51583 37.056808 -80.027328 34.219078 51584 36.394066 -80.476181 34.056839 51585 10.792496 -79.125305 33.064804 51586 21.753372 -81.441940 32.429413 51587 21.285164 -81.702133 33.088951 51588 22.885223 -82.006546 32.671516 51589 29.154251 -81.810669 33.712059 51590 35.570518 -80.862717 33.244644 51591 18.217300 -82.901001 33.549339 51592 24.620575 -82.348358 32.355385 51593 33.003220 -80.741486 33.556870 51594 33.817223 -81.042862 34.030090 51595 9.845520 -83.623947 32.382446 51596 10.854584 -83.038605 32.771843 51597 18.976341 -85.249527 32.514702 51598 18.879852 -84.766800 33.205223 51599 27.421188 -83.380585 32.945831 51600 26.198944 -83.154556 32.765396 51601 27.221100 -83.921570 33.766487 51602 11.491287 -82.052979 33.334602 51603 8.676208 -84.296829 33.391388 51604 8.724770 -84.118179 34.131760 51605 8.733971 -84.711716 33.982536 51606 8.845459 -85.600479 33.090004 51607 15.707695 -87.381943 33.064903 51608 17.384659 -86.860306 32.937416 51609 21.968430 -87.980484 32.115692 51610 9.530609 -86.828156 33.257965 51611 11.555298 -88.385010 33.116440 51612 11.342796 -88.920425 32.015762 51613 14.586914 -87.833633 32.072304 51614 19.356537 -89.126190 31.947153 51615 18.509789 -89.390366 31.835802 51616 24.632591 -88.218842 32.179100 51617 24.559708 -87.685974 32.219391 51618 24.776649 -88.739273 31.699854 51619 23.519989 -88.458298 32.178680 51620 18.788452 -89.990524 31.849199 51621 22.773956 -89.756500 31.632891 51622 21.654716 -89.480576 32.019951 51623 10.161926 53.398361 42.091568 51624 5.845627 52.946579 42.716743 51625 6.492752 53.140900 43.246437 51626 10.769829 52.795181 42.140526 51627 9.996536 53.052460 42.751625 51628 10.882553 51.811371 42.760406 51629 16.792023 50.199738 41.794044 51630 5.776802 50.155319 42.093941 51631 6.078644 49.383209 41.902855 51632 15.987396 49.701996 41.985481 51633 17.718338 50.011963 42.779800 51634 19.723595 49.152176 41.742722 51635 12.502777 48.957474 42.007584 51636 11.546951 50.690521 42.313560 51637 12.984390 48.759796 42.254013 51638 13.825920 48.846024 42.219940 51639 4.851639 45.892395 41.549713 51640 18.807396 45.027618 41.013405 51641 21.204979 45.876434 42.594170 51642 19.439056 45.091400 41.411797 51643 19.343590 42.516541 40.933510 51644 20.066467 44.984955 41.748199 51645 20.858131 43.589584 41.885963 51646 19.408615 44.103149 41.300407 51647 29.269417 43.464432 41.413780 51648 29.974030 43.141617 41.725662 51649 5.840187 43.271484 41.581863 51650 6.859512 42.394989 41.481659 51651 30.692741 42.194000 42.390228 51652 32.938377 41.460083 41.266487 51653 21.559875 42.296951 41.862724 51654 32.038857 41.305298 42.449257 51655 34.109047 40.007294 41.398384 51656 22.449814 40.367294 42.289803 51657 7.931564 40.863831 41.406380 51658 6.996582 40.029053 42.032097 51659 33.937973 38.455688 43.051376 51660 5.396736 37.134827 40.999557 51661 5.135460 37.998871 41.731766 51662 4.940300 37.199432 41.626366 51663 20.310257 37.008911 41.442085 51664 4.974144 36.237747 41.937782 51665 24.464203 33.648331 40.692688 51666 26.136108 36.593521 41.331245 51667 5.789238 35.177429 40.760040 51668 24.651245 33.925598 41.687195 51669 31.312103 35.139694 41.203789 51670 31.014488 35.167908 41.601120 51671 31.362930 35.605011 41.942039 51672 31.059570 34.276062 41.361000 51673 32.129272 35.470123 41.233650 51674 33.684845 35.788864 41.258682 51675 36.472557 36.499786 40.855095 51676 34.649925 36.446259 41.970306 51677 5.966927 35.079620 41.479195 51678 17.105255 34.952530 41.027725 51679 16.410294 34.408325 41.712898 51680 17.118797 35.614975 42.186417 51681 17.821182 35.406097 41.055344 51682 16.366127 33.452240 41.360382 51683 24.619370 34.681458 42.718895 51684 8.364929 31.485596 40.476501 51685 8.392593 32.279984 40.664574 51686 16.953659 32.787994 41.021317 51687 16.725891 33.188034 41.834869 51688 17.964981 32.058624 40.940300 51689 30.985626 35.040283 42.295723 51690 31.147392 33.757111 42.597267 51691 31.109558 33.243820 41.394104 51692 17.758789 32.881042 42.169617 51693 32.209961 32.772552 42.867111 51694 35.707275 31.700989 41.575478 51695 34.322525 31.872604 41.965637 51696 37.481216 31.469116 41.460121 51697 36.728149 31.722610 42.063248 51698 25.660446 30.777740 40.336365 51699 33.872284 31.435089 40.813698 51700 9.485184 28.263565 41.437408 51701 9.231422 27.653107 41.165108 51702 20.296494 29.604874 40.631325 51703 39.226746 29.742233 41.335342 51704 5.053879 28.255585 39.945496 51705 7.035378 28.151108 40.087608 51706 7.758064 28.601059 40.039009 51707 6.037727 27.634735 40.374451 51708 8.989258 29.437592 41.476654 51709 26.227112 28.537140 41.410568 51710 39.588348 29.416016 41.933624 51711 3.675598 27.400009 39.455956 51712 4.318169 27.543411 39.967331 51713 7.923545 27.912888 40.295410 51714 8.505013 27.592499 40.697006 51715 25.597153 27.696045 40.658676 51716 7.490357 26.996765 40.759926 51717 5.686661 26.116776 41.098213 51718 25.331276 27.940918 41.876060 51719 41.039154 26.103119 41.405571 51720 39.856903 26.614624 42.708542 51721 40.312134 27.394440 42.015480 51722 41.360641 25.614227 40.773582 51723 41.801331 25.228973 41.356827 51724 41.154663 25.293594 42.271820 51725 42.949799 24.171234 41.376053 51726 42.367310 24.589264 41.116623 51727 17.426086 26.097351 43.247932 51728 18.152672 26.748627 42.488846 51729 23.648178 26.587112 42.561028 51730 23.042709 25.886902 42.590752 51731 45.232437 21.736298 40.863106 51732 17.337029 20.544662 40.288780 51733 17.316055 19.670090 40.252220 51734 21.433685 20.920670 40.197586 51735 21.432159 22.745010 42.459549 51736 21.602669 22.104645 43.131058 51737 21.750305 21.377274 41.801109 51738 44.543060 19.084122 40.890182 51739 20.970947 18.700409 39.657890 51740 3.121681 18.749695 40.355316 51741 4.246163 18.851837 39.095924 51742 17.344986 19.088974 40.299950 51743 22.099968 18.118881 40.074013 51744 22.188316 19.583389 40.994568 51745 22.683807 20.637970 42.726151 51746 23.249786 19.430344 41.878448 51747 23.124207 18.266037 40.648674 51748 22.848808 17.336151 40.062241 51749 43.781067 17.144897 43.388565 51750 42.494934 16.407684 43.540176 51751 43.280716 16.902252 44.791946 51752 42.954102 17.986481 40.654709 51753 4.050835 16.858109 39.948532 51754 3.154190 17.545105 40.633339 51755 6.208649 15.659500 39.832825 51756 19.085632 16.944397 40.367577 51757 21.692177 16.781738 39.896736 51758 40.879486 16.714844 40.347626 51759 7.718307 14.887131 39.724861 51760 23.003448 16.154694 40.001060 51761 23.524948 14.734833 40.684502 51762 22.811401 15.276794 39.993576 51763 22.176056 15.605743 39.961395 51764 39.771713 15.969162 40.551910 51765 40.503952 15.992065 41.375458 51766 41.812973 17.201035 40.500328 51767 37.131409 14.778122 40.983063 51768 37.950684 15.300949 40.313614 51769 38.644127 15.283066 41.405769 51770 22.318848 14.993240 40.234833 51771 22.109055 14.663574 40.750809 51772 34.032776 13.981247 40.128593 51773 36.210258 14.674744 40.178307 51774 35.139740 14.242493 40.217560 51775 35.832199 14.154861 41.281853 51776 49.129913 14.250824 39.175522 51777 46.897308 12.820587 39.222305 51778 7.866210 13.700699 40.294922 51779 4.138672 9.997711 39.007645 51780 4.455696 9.178513 39.973511 51781 3.431816 9.243820 39.622765 51782 10.413712 11.090942 39.363075 51783 9.718559 12.135223 39.689674 51784 3.275704 9.604919 38.822235 51785 5.260399 9.750732 39.157982 51786 32.490845 10.730743 39.933830 51787 32.510803 10.180313 39.486176 51788 33.260620 10.137711 39.887436 51789 33.250938 10.741882 40.594261 51790 2.830406 8.979050 39.135811 51791 5.437271 8.788254 40.101746 51792 10.806473 9.080856 40.315659 51793 34.135788 8.986130 39.341988 51794 34.525116 10.293869 40.563316 51795 35.266418 9.228333 39.678551 51796 36.234253 8.652039 39.502571 51797 36.089546 9.788727 40.289429 51798 37.407616 8.999496 40.046112 51799 38.111038 7.903809 39.570763 51800 6.353653 8.942169 39.488907 51801 10.836380 8.134598 40.469658 51802 10.191452 7.625870 39.163361 51803 37.129898 10.057953 40.928253 51804 38.447113 9.687256 40.872658 51805 37.826843 10.544632 42.063202 51806 52.222961 8.614380 40.109985 51807 53.294617 8.393585 40.088440 51808 9.125130 7.753983 39.046104 51809 8.146866 7.689819 39.798767 51810 9.187393 6.993927 40.309448 51811 9.831375 7.566010 38.924446 51812 38.955521 7.422150 39.663589 51813 39.349831 6.424377 39.760757 51814 38.837067 8.530548 40.162354 51815 48.551529 7.568756 39.747696 51816 54.339630 7.313721 40.080208 51817 53.291626 7.671356 41.465149 51818 52.589417 8.528168 41.011696 51819 2.530365 7.561996 38.983238 51820 9.795532 7.317368 39.410309 51821 39.989922 7.546539 40.301491 51822 39.961250 6.400635 40.184265 51823 48.519089 7.686920 41.841751 51824 53.765472 6.125153 41.438477 51825 53.035370 6.706406 42.548882 51826 38.164368 5.395203 39.134674 51827 41.109009 7.280029 41.096344 51828 40.454376 6.257416 40.865562 51829 41.212006 6.345612 41.750336 51830 54.773315 5.695190 39.955307 51831 2.586823 6.526627 39.018608 51832 5.590973 3.444107 38.597794 51833 5.777184 2.777206 39.315575 51834 3.942413 3.120209 39.690201 51835 4.870888 2.189087 39.952255 51836 6.493729 2.926392 38.771721 51837 7.620689 2.372864 38.446007 51838 7.206177 2.072861 39.227051 51839 7.982681 1.926926 38.599060 51840 35.510262 2.202728 40.205009 51841 36.287537 3.144547 39.485664 51842 43.094543 2.756592 39.961380 51843 50.374420 2.286591 39.542961 51844 50.512115 2.568436 41.558807 51845 51.457550 2.713760 39.721474 51846 8.286545 1.219421 39.158913 51847 53.553802 3.996407 40.331261 51848 52.430023 3.684906 40.847511 51849 8.226746 -1.366882 38.709991 51850 7.583679 -0.533844 38.195854 51851 40.291855 0.195374 39.798904 51852 49.470520 1.523636 41.162247 51853 31.624483 -0.476166 39.287163 51854 38.368919 -1.891205 39.670753 51855 5.658287 -1.542404 38.176758 51856 4.004379 -2.074875 38.182800 51857 7.040665 -1.497147 38.329124 51858 7.623199 -2.489746 38.851906 51859 2.889038 -1.875381 37.595856 51860 2.864502 -2.900787 38.132607 51861 2.793007 -4.317062 38.841934 51862 31.076607 -2.186310 38.899490 51863 51.525757 -4.243439 40.903259 51864 52.108521 -3.130692 41.199554 51865 50.239624 -2.421906 39.514351 51866 50.521210 0.276016 41.693253 51867 49.160553 0.797577 40.691826 51868 31.746065 -3.054108 38.784081 51869 51.128693 -2.344055 40.396835 51870 34.384323 -3.681992 38.839073 51871 36.506927 -3.016830 39.033112 51872 55.786087 -5.567154 39.272453 51873 53.394165 -9.270844 40.162392 51874 52.545074 -9.230164 39.433411 51875 44.866516 -9.232529 39.113014 51876 46.152176 -9.122437 39.796799 51877 46.722778 -7.425461 38.686462 51878 49.377960 -10.673233 37.910530 51879 45.244415 -8.542679 38.668259 51880 1.937554 -11.069809 37.921982 51881 1.262222 -9.270874 38.074821 51882 2.527458 -12.058456 38.780602 51883 2.254242 -13.069031 37.734085 51884 50.654968 -10.914032 38.724983 51885 49.361237 -11.790604 38.286751 51886 49.772659 -13.020615 38.970390 51887 48.722549 -13.949478 38.599655 51888 58.200958 -14.177460 39.569496 51889 58.618530 -15.498749 38.915329 51890 38.123413 -15.991791 39.382584 51891 47.685150 -14.455688 38.139030 51892 48.582581 -14.678741 38.791573 51893 46.897995 -15.344086 38.108673 51894 3.981598 -18.369537 39.949638 51895 4.435028 -19.219284 39.314362 51896 3.937752 -18.802383 38.958649 51897 36.774002 -17.075821 38.272476 51898 37.021729 -16.402695 38.381027 51899 44.053345 -17.267075 38.348114 51900 43.388977 -17.290695 37.875618 51901 47.093567 -15.828094 38.598145 51902 3.472054 -17.801987 39.675652 51903 35.871849 -18.420090 39.016815 51904 36.272888 -17.441284 39.053398 51905 58.620117 -16.231659 39.863281 51906 58.832214 -16.183456 39.217453 51907 3.342880 -18.750183 37.914764 51908 43.239517 -17.824005 38.465118 51909 57.387329 -17.952530 38.426186 51910 56.566620 -18.414536 38.526993 51911 56.092926 -18.630020 38.600746 51912 3.098084 -21.287933 38.167183 51913 36.708008 -19.269882 38.841141 51914 35.926895 -19.599792 39.210403 51915 35.907379 -19.192627 38.900490 51916 53.718628 -19.317291 38.140160 51917 51.120270 -20.228729 37.744965 51918 52.512756 -19.783600 38.851616 51919 53.659302 -19.278671 39.033852 51920 47.052307 -22.138382 39.747604 51921 47.837524 -21.573364 39.084389 51922 50.931412 -20.500137 39.252930 51923 46.049377 -21.842651 38.519630 51924 56.063141 -22.669647 38.104630 51925 57.176392 -22.142578 38.398293 51926 2.297432 -23.725433 37.308380 51927 2.491798 -25.120651 37.542740 51928 39.753899 -24.006287 37.686226 51929 42.665466 -23.106720 38.637062 51930 42.332825 -24.060364 39.492722 51931 43.427200 -23.496994 39.524460 51932 43.850189 -22.648346 38.650558 51933 54.833557 -23.164642 38.128418 51934 55.042404 -22.983261 39.086609 51935 56.335953 -22.464981 39.322060 51936 60.473236 -23.408463 38.523117 51937 39.138519 -25.055237 38.279030 51938 40.768219 -24.541656 38.947449 51939 51.025818 -24.359665 38.002777 51940 52.608154 -24.170303 39.810822 51941 2.597405 -25.954819 36.783295 51942 2.290299 -25.403595 36.819603 51943 37.908752 -25.823288 37.856346 51944 3.534683 -27.022995 36.746262 51945 2.971245 -26.350540 37.554543 51946 37.123116 -26.691040 37.749443 51947 37.336151 -26.359665 37.778000 51948 3.541626 -26.882202 37.723755 51949 4.703354 -28.096436 36.636887 51950 4.503143 -27.597061 37.755196 51951 37.013779 -27.397003 37.767220 51952 45.371155 -26.600830 38.021667 51953 59.953186 -25.223007 38.614212 51954 36.778030 -28.461121 37.720490 51955 54.584808 -28.023544 38.214775 51956 55.424774 -27.674103 37.894615 51957 56.762177 -27.342468 37.738106 51958 39.624908 -30.117661 36.681908 51959 36.493843 -29.415955 37.685425 51960 41.614639 -30.719116 37.273392 51961 40.715836 -30.689789 37.122887 51962 42.140976 -30.174988 37.291779 51963 44.497437 -29.134094 38.925148 51964 43.856949 -29.674988 38.614616 51965 42.690643 -29.926361 37.602623 51966 53.169907 -31.079910 37.877869 51967 53.224564 -29.864273 38.083939 51968 4.191246 -30.728897 36.870728 51969 39.562347 -31.973419 38.507431 51970 39.594627 -32.481491 39.285469 51971 38.583305 -32.476135 39.388138 51972 37.610878 -32.887955 40.329269 51973 36.743111 -32.234940 39.307625 51974 39.569626 -31.160141 37.470367 51975 42.226471 -30.994278 38.059494 51976 50.338898 -32.124069 36.532578 51977 3.353546 -31.813614 37.259460 51978 40.932037 -31.644333 38.292114 51979 41.388885 -31.175232 37.600525 51980 51.088120 -32.202545 37.074997 51981 51.718384 -33.573273 37.447510 51982 50.130096 -33.318527 36.975624 51983 52.140930 -32.123932 37.529900 51984 54.769531 -32.078873 37.914917 51985 53.287491 -32.762665 37.676407 51986 54.503540 -33.713303 37.359116 51987 57.506378 -32.833725 37.884216 51988 57.071350 -33.348999 37.461197 51989 58.096313 -33.736496 37.686378 51990 56.675507 -32.118073 38.176987 51991 58.146729 -32.586517 38.668228 51992 58.965134 -33.998581 38.591972 51993 3.289513 -32.357330 38.157768 51994 49.248093 -33.522964 36.755226 51995 58.683517 -34.887589 37.475746 51996 3.407654 -37.299225 36.899902 51997 49.394531 -34.221786 37.090492 51998 53.272186 -34.102295 37.473389 51999 54.016800 -34.984238 37.161873 52000 52.620270 -35.662659 37.273422 52001 54.195984 -36.074280 36.930878 52002 52.421997 -36.941254 37.161682 52003 3.375649 -35.978012 38.119881 52004 51.378906 -36.535599 37.074936 52005 55.170029 -36.834045 36.620880 52006 59.256958 -38.539200 36.715836 52007 58.617798 -40.232391 38.093201 52008 43.627045 -41.085815 37.211876 52009 43.356461 -41.314529 36.814919 52010 42.984009 -41.615463 37.565178 52011 44.421722 -41.243256 37.129311 52012 4.240082 -44.143387 36.796257 52013 3.862885 -44.178406 36.231033 52014 4.529556 -43.315552 36.466011 52015 5.203308 -44.033218 37.348671 52016 4.953964 -44.137955 37.258728 52017 4.973663 -43.729050 37.061180 52018 6.221871 -41.403503 36.059235 52019 41.371368 -42.688538 36.575974 52020 42.295959 -41.901306 36.561958 52021 41.902740 -42.705521 37.395027 52022 44.947601 -42.034332 36.128456 52023 45.855179 -41.494492 37.185440 52024 58.436111 -41.375885 36.852348 52025 10.548058 -42.699875 37.102692 52026 11.567932 -43.104813 36.875359 52027 11.311127 -43.857925 36.565384 52028 40.993256 -43.074844 36.037003 52029 41.299835 -43.555801 36.714241 52030 47.538177 -43.393845 36.759552 52031 47.298401 -43.736053 36.316483 52032 56.941803 -44.186249 37.903297 52033 57.520432 -43.650681 37.950310 52034 9.829353 -43.699570 36.848473 52035 41.652390 -44.990814 36.452469 52036 48.403015 -44.088684 36.590607 52037 55.986725 -44.900238 36.918304 52038 56.360641 -44.752060 38.428162 52039 8.133270 -45.768402 35.566803 52040 9.081604 -45.122467 35.938835 52041 10.339767 -44.822830 35.748932 52042 13.172707 -44.370300 37.418144 52043 4.455147 -45.064423 36.276443 52044 4.209152 -45.885696 35.287666 52045 5.899101 -44.422089 36.976410 52046 7.071671 -45.693985 35.967163 52047 12.884056 -45.615631 35.771004 52048 13.077255 -46.826096 36.067123 52049 13.427277 -45.812637 36.689331 52050 10.772491 -48.338333 37.685371 52051 10.455727 -48.905624 37.405602 52052 10.863708 -49.260284 37.348671 52053 13.105835 -49.796051 35.581268 52054 47.940338 -48.757339 36.232178 52055 47.866882 -48.336395 37.397385 52056 49.113373 -49.127258 36.475937 52057 53.188660 -50.179230 36.358894 52058 55.475418 -50.532684 37.109581 52059 54.561584 -50.244431 38.075287 52060 56.129288 -51.196243 36.818192 52061 56.480286 -52.279083 36.149384 52062 52.220428 -49.624222 37.422791 52063 55.947250 -53.332764 36.477142 52064 55.192657 -54.695419 36.444016 52065 54.365997 -57.045761 35.753624 52066 5.795006 -59.884918 34.210388 52067 46.427979 -57.670227 36.141174 52068 46.780228 -58.481995 35.496269 52069 45.947052 -56.666672 37.131447 52070 45.424484 -58.002640 36.605080 52071 47.651611 -58.001541 35.941376 52072 7.809066 -60.658249 34.724327 52073 7.282242 -60.582932 34.782265 52074 10.755891 -59.358734 35.610344 52075 17.175911 -59.411499 34.772499 52076 17.821014 -59.454361 34.781105 52077 18.619850 -60.092514 34.896713 52078 48.908325 -58.835022 35.895653 52079 6.596741 -60.633652 34.703041 52080 9.373856 -60.156052 34.920547 52081 11.495697 -59.105087 36.542305 52082 11.265205 -59.571854 36.805740 52083 17.677277 -59.785828 35.178543 52084 19.391716 -60.970795 35.183517 52085 44.840271 -59.994995 35.811600 52086 49.015274 -59.535034 35.357384 52087 50.390762 -59.843613 35.500816 52088 8.318878 -60.189514 34.584999 52089 8.344437 -61.337006 34.660728 52090 9.372879 -61.466232 35.287102 52091 7.308518 -61.270630 34.694305 52092 30.592026 -61.637466 35.933090 52093 30.620796 -61.564301 34.966133 52094 31.655519 -62.511215 35.360931 52095 38.022110 -61.460114 35.074326 52096 38.483955 -61.272522 35.208405 52097 51.184875 -60.105911 36.013504 52098 51.583969 -60.054398 35.736481 52099 5.587128 -61.312271 34.356171 52100 6.334099 -61.474579 34.546364 52101 20.576019 -62.881042 34.685814 52102 38.618271 -62.041672 35.950462 52103 28.383415 -63.667542 34.943764 52104 28.084274 -62.581085 35.405418 52105 27.795639 -63.529541 35.538780 52106 42.459503 -62.740021 35.324661 52107 44.691742 -61.742599 35.453957 52108 21.391190 -65.311905 34.853493 52109 43.302032 -63.243988 35.807961 52110 44.712509 -63.224503 36.071640 52111 44.732849 -62.545212 35.518959 52112 45.429504 -62.234741 36.204384 52113 32.446701 -63.954437 35.134552 52114 33.366592 -66.678452 35.544891 52115 38.725922 -65.234406 35.864098 52116 6.308647 -66.188354 34.528824 52117 7.371597 -65.394135 35.386139 52118 6.413727 -65.953125 36.551758 52119 13.502007 -66.576096 35.993828 52120 21.407318 -66.319702 35.017426 52121 39.097549 -65.828674 35.027946 52122 21.210892 -67.274506 35.889954 52123 21.447655 -68.518692 34.871567 52124 4.364678 -68.754501 34.175499 52125 28.970245 -67.842300 34.886482 52126 42.402985 -67.254883 35.359619 52127 45.781693 -67.616180 35.445198 52128 43.586090 -67.607986 36.231659 52129 10.650116 -69.515320 34.692932 52130 11.435913 -68.279602 36.086044 52131 21.424011 -69.636841 35.006653 52132 28.577126 -68.966980 34.814415 52133 33.640152 -69.764389 35.549538 52134 32.644272 -70.177994 34.759216 52135 10.105835 -70.423645 34.267830 52136 15.951561 -71.325745 33.731621 52137 27.988083 -70.029739 34.602234 52138 46.182327 -69.605576 34.962608 52139 15.160950 -70.910294 33.658363 52140 14.909576 -71.461868 33.864418 52141 27.568054 -71.177658 34.568649 52142 43.180695 -72.134811 34.600311 52143 44.395370 -70.943695 34.997810 52144 45.467163 -70.268265 34.899002 52145 9.623734 -70.825089 35.257011 52146 8.995316 -71.544479 36.118996 52147 12.212334 -74.158310 34.336983 52148 11.599487 -74.614838 33.897881 52149 14.193199 -72.385086 34.059723 52150 16.212250 -72.351410 33.890610 52151 13.377243 -73.624695 34.663589 52152 14.232590 -73.131195 34.716827 52153 15.968491 -73.147476 34.120018 52154 32.381699 -71.857529 35.220383 52155 5.805565 -73.543808 33.866035 52156 6.671249 -73.585861 34.277016 52157 16.337471 -73.998459 33.733177 52158 21.580429 -71.685669 35.484200 52159 27.474426 -72.685867 34.861023 52160 27.474655 -71.962112 34.838699 52161 27.474274 -73.858658 34.645531 52162 41.992920 -73.835144 35.242439 52163 5.246727 -73.847107 35.062691 52164 4.954552 -73.259674 36.201675 52165 5.781609 -73.931442 34.508957 52166 6.360512 -74.137405 34.923737 52167 11.608688 -75.172775 34.697830 52168 11.028549 -76.105179 34.772057 52169 16.154892 -74.645569 33.895882 52170 15.797272 -74.006714 34.280258 52171 27.472565 -75.212723 34.058456 52172 32.325798 -76.330948 34.996971 52173 10.471970 -76.535156 33.756172 52174 16.393723 -75.248886 34.092308 52175 15.775391 -74.700943 34.381027 52176 17.301437 -75.731918 34.009132 52177 18.352905 -76.320175 34.768768 52178 27.989174 -75.978790 34.916870 52179 10.223907 -77.961151 33.752525 52180 21.006447 -76.365875 34.121880 52181 19.851654 -76.518509 34.440926 52182 32.042938 -74.908096 35.142059 52183 39.773987 -77.308731 34.283302 52184 28.267006 -78.046783 34.086571 52185 28.867233 -78.473663 35.024773 52186 28.457428 -77.103394 35.107643 52187 32.853294 -77.383286 35.407059 52188 32.370209 -77.620834 34.477196 52189 37.522247 -79.421524 35.133293 52190 38.146149 -78.845093 34.826477 52191 39.159172 -77.602554 35.153297 52192 32.925850 -78.694214 34.824387 52193 33.402580 -80.094467 34.530762 52194 9.803101 -80.031128 34.540100 52195 9.280609 -81.620911 35.443787 52196 9.846329 -81.890305 34.570488 52197 8.796265 -80.469635 35.661385 52198 36.566177 -80.160370 35.046974 52199 36.807724 -79.364349 36.216057 52200 12.023178 -81.816132 33.215027 52201 20.522354 -81.715195 33.732056 52202 20.040573 -82.085800 34.944351 52203 35.536049 -80.759415 34.707718 52204 21.147987 -82.211456 33.984093 52205 21.619812 -83.011108 34.785851 52206 22.572281 -82.743439 33.851028 52207 24.339325 -82.989655 33.299606 52208 24.025948 -83.836411 34.399475 52209 25.588638 -83.914200 33.884483 52210 29.286392 -82.757599 34.213631 52211 9.030510 -83.640472 34.041733 52212 9.783798 -82.991135 33.733276 52213 10.597351 -81.830856 33.847183 52214 28.613510 -83.936264 34.482162 52215 18.575134 -84.164627 33.633659 52216 25.214066 -84.605225 34.944733 52217 23.921326 -84.656342 35.585213 52218 18.676086 -85.501511 33.485168 52219 18.207397 -86.368912 33.320816 52220 9.084885 -85.387970 34.201012 52221 9.312996 -86.198196 33.921944 52222 9.686615 -86.634796 34.033142 52223 13.828828 -88.221298 32.876579 52224 14.638947 -87.722656 34.116714 52225 12.820938 -88.053513 34.116516 52226 12.007324 -87.606766 35.022308 52227 12.483452 -88.747772 32.687103 52228 20.066147 -89.887161 32.072304 52229 8.279541 53.311249 43.370468 52230 10.313110 52.518219 43.030121 52231 5.704949 50.819489 43.004059 52232 5.065003 48.695984 45.576271 52233 4.574936 47.471207 45.561905 52234 4.760887 47.778412 44.486763 52235 5.532761 49.133148 43.208115 52236 16.637344 49.700409 42.633652 52237 18.743073 49.958893 42.694244 52238 19.554886 49.153976 42.807961 52239 18.650574 49.516708 43.563896 52240 6.090500 48.594681 42.167786 52241 15.820419 49.268158 42.796921 52242 14.772607 48.766510 43.041245 52243 19.410294 48.770111 44.120064 52244 20.228714 48.021271 44.438629 52245 19.446640 47.654938 45.367859 52246 20.963226 47.164780 44.722343 52247 20.572510 47.774902 43.422989 52248 5.840431 47.867035 42.154610 52249 11.268799 49.879730 43.503227 52250 12.230042 48.833084 43.008240 52251 13.992523 47.783203 45.188438 52252 12.919968 47.854675 44.921600 52253 13.423203 48.381271 43.594749 52254 5.362396 44.066895 42.324219 52255 4.800438 45.358536 42.851799 52256 6.050102 43.525528 42.644722 52257 5.558174 44.115540 43.407776 52258 4.968971 44.927933 44.118996 52259 5.454872 44.304504 44.193321 52260 6.687325 42.888428 42.560310 52261 6.309807 43.358459 43.541008 52262 22.380707 42.954132 42.651718 52263 22.416466 44.275452 42.930725 52264 22.879501 40.055084 43.202400 52265 23.188141 44.166046 43.693428 52266 22.890778 44.794067 43.762917 52267 29.252457 42.830414 41.885483 52268 29.775749 42.439011 42.309258 52269 22.333672 45.197250 43.186775 52270 23.169357 43.442413 43.835716 52271 29.859360 41.996231 42.667328 52272 7.404953 41.888672 42.416779 52273 7.532539 41.038330 42.406425 52274 4.667938 38.450989 42.719063 52275 5.766068 40.121613 43.171494 52276 4.602173 39.492096 43.779305 52277 5.016785 40.963120 44.719070 52278 6.216263 41.736023 44.021896 52279 5.820404 42.252792 44.682579 52280 5.756249 39.078461 42.111191 52281 4.685005 37.418213 42.037041 52282 33.973862 37.573837 43.192505 52283 26.364113 37.200043 42.608757 52284 26.488495 37.659836 43.846375 52285 18.588379 36.057831 41.749191 52286 24.788429 35.505142 42.963936 52287 32.206802 36.102020 42.573364 52288 33.333588 36.927277 43.179771 52289 6.609085 34.175461 41.677719 52290 7.435440 33.218170 41.759590 52291 16.406082 33.766052 42.343216 52292 8.065102 32.308701 41.722076 52293 8.464677 32.149139 41.111099 52294 19.246765 32.017349 42.160515 52295 18.864807 33.036469 43.465401 52296 17.704094 33.608459 43.567673 52297 8.453026 31.337799 41.417023 52298 19.235733 31.108109 40.867508 52299 24.945488 33.805344 42.923874 52300 33.406189 32.308914 42.805153 52301 36.824158 31.506500 43.637993 52302 35.468819 32.052872 43.344902 52303 37.807053 31.335663 42.356293 52304 34.479965 32.576202 44.107178 52305 33.614899 32.717834 44.357727 52306 34.319427 32.374115 43.410393 52307 8.451744 30.280121 41.885582 52308 25.189934 32.652328 42.055267 52309 27.127060 29.985199 41.649849 52310 26.798454 31.018814 42.076454 52311 9.298935 28.865341 41.374039 52312 20.336639 30.601105 41.914444 52313 26.871582 29.458618 41.575829 52314 5.011490 27.216293 40.423149 52315 9.599304 27.666107 41.633987 52316 20.654671 30.206573 43.151726 52317 4.102730 26.220200 40.371826 52318 7.080002 25.579102 41.640640 52319 8.428230 26.132568 41.773956 52320 7.689361 24.660126 42.613861 52321 6.868874 24.504242 42.223961 52322 6.946442 24.828613 42.045212 52323 8.698944 27.002670 41.174103 52324 9.215302 27.085388 42.080460 52325 8.990433 26.325943 42.453232 52326 18.992676 28.102631 43.029030 52327 39.354553 29.037903 42.828644 52328 6.203468 24.770325 42.008263 52329 5.126923 24.741653 41.852364 52330 4.482437 25.191879 41.307518 52331 22.992935 25.141556 41.291878 52332 24.507446 27.467194 42.545998 52333 30.936188 25.052994 42.336189 52334 30.587486 25.938782 42.932076 52335 31.924883 25.129639 42.355850 52336 31.372864 26.736603 43.545837 52337 33.263412 25.068359 42.069595 52338 32.555984 26.479782 43.223015 52339 34.318512 24.735962 41.931236 52340 34.053162 26.044357 42.856781 52341 34.972511 25.169067 42.414772 52342 35.163177 24.158554 42.083382 52343 34.632805 23.923126 41.849731 52344 22.401314 24.008545 41.077843 52345 31.143364 24.335938 42.684174 52346 30.003113 25.156189 43.013367 52347 33.025818 24.105515 41.983459 52348 33.946777 23.952454 41.874474 52349 42.054871 24.049835 42.421509 52350 17.572334 22.915848 41.110886 52351 21.767868 22.652496 41.102852 52352 21.748199 23.742722 42.169792 52353 32.448654 23.680237 42.630821 52354 34.871628 23.010971 42.422264 52355 43.268646 23.745926 42.141624 52356 43.914490 23.296280 41.978180 52357 17.409714 21.447906 40.821548 52358 44.962952 22.328690 42.225220 52359 44.283554 22.766144 42.524551 52360 45.465485 21.606842 41.737984 52361 3.295921 21.764130 41.645683 52362 17.199921 20.193634 41.390831 52363 17.087585 21.536957 42.547119 52364 45.747711 20.904404 42.627281 52365 45.289490 21.727081 42.768074 52366 2.973862 18.914352 41.688118 52367 3.224564 19.867493 42.878784 52368 3.208572 18.987625 43.130119 52369 45.728714 20.390152 41.819489 52370 3.178299 20.478577 41.758995 52371 17.259232 19.271729 40.863419 52372 23.186920 18.961517 41.257584 52373 45.114365 18.787979 42.130196 52374 45.394928 19.504257 41.576553 52375 2.787720 18.035751 41.668625 52376 2.675560 17.545197 41.732880 52377 18.593788 17.284195 40.740776 52378 23.976196 16.873077 40.678413 52379 44.085175 17.985474 41.989899 52380 3.574089 16.303223 40.319016 52381 19.222855 16.861984 41.076202 52382 4.247460 15.904129 40.176697 52383 5.018852 15.489929 40.132195 52384 19.934875 16.828171 42.331993 52385 18.615799 17.763260 41.811790 52386 21.239212 15.516846 40.629257 52387 20.315689 16.107498 41.390518 52388 24.691391 16.032806 41.179573 52389 24.788437 16.969604 41.342705 52390 41.656479 16.735535 41.306046 52391 41.064606 16.024124 42.777328 52392 42.702133 16.886963 42.238060 52393 3.196304 16.122589 40.776909 52394 3.641373 15.606949 40.597008 52395 4.269760 15.087296 40.643188 52396 5.226608 14.507355 40.698570 52397 6.714867 14.146362 40.567978 52398 39.712738 15.601334 41.314812 52399 39.809631 15.475296 42.148247 52400 5.683930 13.161972 41.694511 52401 7.177933 13.082062 41.059418 52402 8.450668 12.472687 40.756042 52403 22.344437 14.116150 41.403450 52404 21.475571 14.894409 41.537720 52405 21.765320 14.466675 42.554543 52406 22.384232 13.389587 42.400925 52407 36.525162 14.377625 42.367531 52408 37.924057 15.322052 43.055435 52409 38.994194 15.522598 43.135399 52410 23.828087 13.533844 41.019279 52411 24.436951 13.569885 41.453163 52412 23.902481 12.985825 41.556610 52413 32.283432 12.518005 40.643463 52414 32.342422 12.242401 41.330841 52415 32.798256 12.659027 41.587830 52416 33.238251 13.366135 40.817993 52417 23.186935 13.442841 41.407990 52418 9.725594 11.126770 40.632835 52419 32.234390 11.840179 40.893257 52420 10.459404 10.152740 40.256760 52421 32.599899 11.270355 40.780594 52422 2.721878 8.268555 39.784607 52423 3.686737 8.546509 40.460197 52424 3.192856 7.635269 41.141617 52425 4.930428 7.715378 41.337349 52426 7.195068 8.057556 39.938629 52427 6.276939 8.044739 40.577934 52428 35.973824 10.454834 41.205017 52429 36.823318 10.478836 41.588737 52430 39.902664 9.366226 40.962234 52431 39.146667 10.343796 41.804321 52432 40.812851 9.874588 41.532173 52433 40.893051 10.325348 42.043579 52434 40.165436 10.419479 42.034134 52435 2.703583 6.822662 41.715797 52436 3.550263 6.609818 42.106323 52437 10.336769 7.425354 40.126312 52438 10.767768 7.501160 41.256248 52439 40.898636 8.488861 41.004417 52440 40.786774 9.311737 41.166519 52441 51.350388 8.631210 41.333954 52442 52.370453 8.369263 42.005264 52443 2.915352 4.493881 39.736404 52444 2.477066 5.726959 40.005104 52445 2.418144 4.979340 41.110268 52446 42.162033 9.505264 42.776505 52447 41.842957 8.143768 42.019409 52448 42.679871 8.176910 43.415283 52449 9.442146 6.243698 41.402733 52450 8.501862 6.472046 41.195183 52451 41.311584 9.158096 41.473419 52452 41.632294 6.999283 41.900337 52453 45.988251 5.761917 40.820320 52454 2.457665 7.046463 40.450836 52455 2.398277 6.931458 41.344742 52456 2.387764 6.198975 41.237892 52457 39.860428 5.266388 41.808876 52458 40.675842 5.768219 41.644234 52459 45.384277 4.937744 41.210564 52460 44.509567 3.826004 41.355949 52461 53.922653 4.926498 40.853508 52462 2.641327 3.526596 41.095375 52463 37.070877 3.470146 40.261658 52464 39.519226 5.430313 40.501320 52465 44.714844 3.399216 42.650764 52466 43.764465 2.026749 42.690720 52467 43.605438 2.664764 41.593056 52468 53.092438 4.379684 41.252510 52469 5.996796 1.888565 39.938187 52470 6.821014 0.492294 40.758316 52471 36.397125 2.882919 40.310379 52472 51.453217 3.073654 40.525719 52473 8.110382 0.795639 40.033455 52474 8.766647 0.464142 39.618179 52475 36.384140 2.910126 41.325081 52476 35.364899 1.778122 41.751923 52477 34.404800 1.108002 40.867752 52478 9.070335 -0.123306 39.587265 52479 33.553314 0.711990 40.189026 52480 33.109673 0.256271 40.391235 52481 42.487885 1.313263 41.452667 52482 41.851059 1.313034 40.380157 52483 41.154327 0.832748 40.152992 52484 50.072845 1.536728 41.850044 52485 9.170593 -1.142334 39.593140 52486 31.367943 -1.553192 39.764351 52487 31.993090 -0.820724 40.379189 52488 32.839432 -0.430191 40.931351 52489 37.243568 -2.947357 39.439484 52490 39.506027 -0.971115 40.179375 52491 48.777374 0.659302 40.072144 52492 8.971558 -2.503677 39.370026 52493 50.374664 -1.234299 40.298134 52494 8.263611 -3.512207 39.278519 52495 9.749580 -3.383148 40.419197 52496 9.629265 -4.384583 40.076965 52497 9.129822 -3.925461 39.663864 52498 31.775423 -1.639481 40.685089 52499 2.226868 -5.309052 39.056419 52500 9.124069 -3.340363 39.518646 52501 9.644974 -2.178680 40.175735 52502 51.983215 -1.624069 41.752663 52503 7.612625 -4.487488 39.642242 52504 8.468750 -4.339035 39.613571 52505 34.353088 -3.971375 39.798660 52506 35.730164 -4.208801 40.346558 52507 36.556366 -3.716919 39.649231 52508 37.931473 -3.845001 40.502289 52509 36.682922 -4.258743 40.299812 52510 50.967865 -5.278259 40.873047 52511 55.079208 -5.491943 39.357941 52512 1.895958 -7.539200 39.616180 52513 1.431099 -8.256256 38.703735 52514 54.338287 -6.051514 39.217087 52515 55.201431 -5.984207 39.658524 52516 54.733154 -6.639389 39.757790 52517 54.225235 -8.205902 40.306938 52518 53.608643 -8.242691 39.860222 52519 54.743256 -7.321259 40.113106 52520 1.460884 -9.238708 38.704376 52521 2.195496 -10.384109 39.568260 52522 44.775970 -10.435654 39.824966 52523 52.194016 -10.673309 39.754211 52524 51.348892 -11.681458 39.379379 52525 57.110168 -10.120712 40.582542 52526 57.611115 -11.530273 40.077736 52527 3.045059 -13.339172 39.077263 52528 4.242455 -12.218170 41.344795 52529 50.475937 -11.954224 38.962830 52530 41.403534 -14.511734 39.355453 52531 42.038742 -13.417572 39.228897 52532 42.865433 -12.724106 39.426323 52533 51.062759 -12.511108 39.463898 52534 51.436569 -13.478683 40.336914 52535 52.029495 -12.180298 40.122215 52536 3.737557 -13.650131 39.943123 52537 42.258636 -14.439148 39.635574 52538 42.978333 -13.782730 39.748871 52539 43.950775 -12.919724 39.954102 52540 44.710938 -11.599579 40.126358 52541 49.583160 -14.912338 39.759392 52542 40.322403 -14.724075 39.193115 52543 3.030014 -14.808975 39.144165 52544 2.645729 -16.045547 38.443420 52545 37.343781 -16.235153 39.037827 52546 41.235062 -15.608047 40.062286 52547 42.003265 -15.183167 39.893730 52548 48.022766 -15.391922 38.854523 52549 48.913559 -16.267120 40.394562 52550 48.342377 -15.955505 39.616089 52551 3.004120 -17.237640 38.393250 52552 36.805695 -16.696411 39.118996 52553 36.478806 -17.151718 40.064865 52554 47.229218 -16.194473 39.163063 52555 46.193024 -16.873520 39.323456 52556 58.213562 -15.005127 40.468307 52557 44.913757 -17.528641 39.395729 52558 43.916183 -17.847366 39.057816 52559 42.208725 -18.454590 38.913742 52560 43.275574 -18.261063 39.242493 52561 56.605408 -18.530609 39.541397 52562 58.030029 -17.562973 40.086929 52563 3.780304 -19.903778 38.456902 52564 53.519501 -19.390030 40.021606 52565 52.023865 -20.093735 40.221878 52566 53.035477 -19.790039 41.268379 52567 57.218887 -18.434402 40.943878 52568 35.533829 -19.150558 39.247490 52569 36.589828 -20.189545 39.905151 52570 40.140579 -19.542572 39.622795 52571 2.540810 -22.433563 37.589668 52572 49.733124 -21.084320 39.661140 52573 59.060120 -22.216248 41.156372 52574 59.306305 -21.905853 40.285469 52575 59.751144 -22.488297 40.382896 52576 59.077820 -21.614594 39.067223 52577 59.939651 -22.217270 39.345345 52578 48.584076 -21.736069 39.996933 52579 57.735474 -21.921036 39.241219 52580 59.186691 -21.691437 39.845215 52581 55.419739 -22.887680 40.302650 52582 60.038727 -23.130081 39.896080 52583 50.812988 -24.682327 38.898911 52584 59.829834 -24.172729 39.879669 52585 3.121262 -23.136536 39.041138 52586 3.285034 -23.630112 40.717667 52587 3.004212 -24.614777 40.291199 52588 38.772499 -25.891541 38.768929 52589 39.386726 -26.354202 39.325119 52590 40.276306 -25.618958 39.377632 52591 47.547852 -26.211014 38.896347 52592 49.624451 -25.284271 38.976257 52593 37.702209 -26.752289 38.556717 52594 36.799034 -27.983261 38.599106 52595 45.629654 -27.234512 38.826714 52596 56.470184 -26.679260 39.113831 52597 57.319580 -26.400665 39.375755 52598 4.800095 -27.840439 40.929619 52599 4.799034 -27.731125 39.884438 52600 3.557999 -27.079788 40.882881 52601 46.304962 -26.625748 38.650108 52602 55.557159 -27.538513 39.432800 52603 5.424522 -28.602737 38.312996 52604 5.862763 -29.240845 39.644257 52605 4.899712 -27.804520 38.827782 52606 56.622864 -26.735535 39.888779 52607 35.671555 -29.496262 38.365334 52608 36.222313 -28.798325 38.290627 52609 36.731567 -28.207672 39.394966 52610 35.878708 -28.702713 39.183899 52611 54.455536 -28.451248 39.114815 52612 3.820953 -31.440353 38.407684 52613 35.323082 -30.475845 38.463699 52614 43.128662 -30.171524 38.203148 52615 53.523682 -29.429428 38.473503 52616 34.222458 -30.995041 38.968979 52617 35.519783 -31.528839 38.820564 52618 43.316299 -31.091110 39.422066 52619 53.757263 -29.955856 38.627953 52620 54.394119 -30.712036 38.477318 52621 55.585861 -30.823715 38.682068 52622 54.787231 -29.411667 39.338600 52623 34.928589 -31.988235 39.461441 52624 35.682632 -32.190628 39.447937 52625 56.765869 -30.864059 38.984573 52626 57.747421 -31.438873 39.195206 52627 57.561905 -30.288788 39.960098 52628 58.678055 -32.891464 39.526207 52629 58.828369 -33.727371 39.832939 52630 59.098221 -34.958023 39.412025 52631 58.229828 -34.708313 40.806496 52632 4.148865 -38.611511 37.306519 52633 3.281845 -37.635345 38.866867 52634 59.243744 -36.031982 39.078781 52635 3.383011 -38.342316 38.105156 52636 8.174774 -39.765152 38.159042 52637 6.795097 -39.590256 37.234596 52638 7.167236 -39.694992 39.042564 52639 6.105034 -39.392868 38.002937 52640 7.307991 -40.362625 36.775368 52641 58.882629 -37.026154 39.426842 52642 58.416809 -37.737106 40.277489 52643 8.476532 -41.363251 37.190338 52644 43.824463 -41.164322 37.793427 52645 44.726944 -41.187180 38.539139 52646 45.474548 -40.966690 37.978287 52647 47.236862 -41.440659 37.696571 52648 46.376831 -40.948761 38.197495 52649 47.284393 -40.955795 39.279121 52650 48.168335 -41.083374 38.348282 52651 48.300903 -41.630173 37.682236 52652 4.978928 -42.496262 36.067688 52653 6.378487 -42.790375 36.755547 52654 8.388168 -43.165695 37.045197 52655 42.674942 -42.702667 38.387581 52656 47.982361 -42.619919 37.196991 52657 58.121979 -42.020752 38.339508 52658 7.076569 -43.745880 37.174217 52659 9.894455 -44.393188 36.412224 52660 48.861084 -43.104630 37.549873 52661 49.184723 -41.831726 38.170135 52662 49.463989 -43.053238 38.062309 52663 48.672028 -42.180679 37.577232 52664 58.030655 -40.656143 39.473793 52665 11.631584 -42.781876 37.101196 52666 57.812973 -43.133636 37.903442 52667 8.840508 -44.342453 36.702606 52668 4.687943 -44.469681 36.982239 52669 8.142517 -45.175964 36.309570 52670 13.164886 -46.226135 37.498962 52671 41.905457 -43.957779 38.125153 52672 42.382782 -45.950027 37.268127 52673 41.895569 -45.501572 38.109016 52674 49.408737 -44.630676 37.206886 52675 48.965912 -44.112595 37.354950 52676 50.496155 -44.813980 37.653648 52677 52.478012 -45.239777 38.464943 52678 55.305847 -45.273621 38.549522 52679 54.189453 -45.613358 38.556000 52680 7.549164 -44.452286 36.924347 52681 12.772667 -46.835266 37.394119 52682 12.332886 -47.458008 37.295189 52683 43.219910 -46.510864 37.162636 52684 12.849419 -48.284302 35.980988 52685 45.929535 -47.598190 39.265732 52686 44.769135 -47.611755 39.299454 52687 11.855392 -48.434235 37.095596 52688 46.525543 -47.931686 37.146606 52689 46.668167 -47.703522 38.321556 52690 47.889313 -48.106400 39.011215 52691 51.871887 -49.227600 38.393661 52692 13.238693 -50.938324 36.422783 52693 12.359352 -49.836929 36.884773 52694 53.246780 -49.678741 38.150421 52695 53.751434 -49.839142 39.505440 52696 55.879486 -52.163361 37.544418 52697 13.451729 -51.586792 36.515747 52698 55.993958 -51.463089 37.664497 52699 12.996048 -52.547165 36.465645 52700 12.285141 -55.525528 35.605995 52701 46.616852 -54.666016 37.008331 52702 46.306671 -54.390488 37.472557 52703 47.165527 -54.488770 37.226875 52704 46.698410 -52.940552 38.803543 52705 48.305176 -53.704468 38.043098 52706 48.253525 -54.871979 37.130814 52707 49.206543 -54.822830 37.796616 52708 55.567520 -51.193375 38.198318 52709 12.609802 -53.524246 36.297470 52710 12.318832 -54.499512 35.627625 52711 46.447937 -55.287704 37.075424 52712 47.377472 -56.249084 36.631302 52713 54.442413 -55.898331 36.895172 52714 54.311569 -55.098618 38.048714 52715 54.669174 -54.764145 37.432327 52716 54.250549 -54.623062 38.802719 52717 54.113068 -54.306381 39.719025 52718 54.888245 -53.672516 38.272682 52719 45.362946 -56.520386 38.621140 52720 45.437134 -57.743317 37.697090 52721 49.760086 -56.469849 37.506943 52722 49.879410 -55.155884 38.754669 52723 48.805099 -55.831223 36.965408 52724 48.830322 -57.306793 36.541985 52725 45.576538 -55.285263 37.865852 52726 53.805328 -57.136490 36.949371 52727 12.018524 -57.762985 35.864510 52728 52.910873 -58.297516 36.988884 52729 45.024673 -59.045853 36.760208 52730 50.144348 -58.460602 36.714935 52731 51.501038 -58.840652 37.090912 52732 51.260437 -59.651886 36.299484 52733 5.776833 -60.809769 34.473953 52734 17.827805 -60.416245 35.618065 52735 17.312714 -61.156540 35.847855 52736 17.960648 -61.021667 36.002098 52737 18.618774 -60.949142 35.720642 52738 19.559952 -62.777573 36.476555 52739 20.507240 -62.899536 35.697624 52740 27.514748 -62.377121 36.026688 52741 28.106354 -61.783722 36.670059 52742 29.775757 -61.700699 36.840881 52743 45.341431 -60.647888 36.665749 52744 50.678802 -57.667938 37.946541 52745 51.772675 -58.104767 38.200066 52746 9.615494 -62.336563 35.865669 52747 8.843093 -63.496140 35.407944 52748 10.565422 -60.778305 36.585289 52749 10.253189 -62.235519 36.918991 52750 16.980637 -62.317596 35.768684 52751 27.128220 -62.314133 36.650879 52752 38.167114 -63.181274 36.006210 52753 9.512711 -63.301178 36.644920 52754 8.339928 -64.560715 36.374023 52755 16.641403 -63.589996 35.736748 52756 20.732697 -63.700409 36.312675 52757 21.131149 -64.504807 35.635056 52758 27.245010 -63.213501 36.227440 52759 32.467125 -63.329529 36.278473 52760 42.116547 -63.065857 36.252640 52761 46.451096 -61.949661 37.429420 52762 46.725677 -60.297272 38.677811 52763 46.072495 -63.145676 36.903412 52764 45.572006 -64.020828 37.417336 52765 15.481262 -64.296875 35.189178 52766 15.293533 -65.346512 35.736031 52767 16.343117 -64.690201 35.882416 52768 27.990402 -64.257629 35.776985 52769 27.565018 -64.060776 36.107849 52770 33.026291 -64.713074 36.004303 52771 31.995180 -62.656265 36.909332 52772 40.365479 -62.438004 36.787430 52773 38.514778 -64.304932 36.728622 52774 5.089874 -66.637299 36.609810 52775 7.420212 -65.251236 36.339561 52776 21.077286 -65.412277 36.193779 52777 39.298546 -66.089859 35.849945 52778 21.123878 -66.265686 36.128281 52779 40.055923 -66.743073 36.327003 52780 39.133629 -65.731949 36.965790 52781 4.625748 -69.721863 37.926247 52782 4.619309 -70.634033 37.929131 52783 21.200256 -69.119385 36.357292 52784 29.336426 -67.039215 35.793472 52785 29.481140 -68.733444 36.633026 52786 29.511803 -67.164978 36.685951 52787 33.834686 -68.151703 35.892723 52788 34.001694 -67.243637 36.921143 52789 33.506332 -65.844177 36.654541 52790 40.890747 -67.301727 37.171326 52791 42.098938 -67.667191 37.201775 52792 45.766708 -68.254303 36.235565 52793 45.891510 -68.836395 36.554688 52794 28.606018 -69.730942 35.563248 52795 34.454216 -68.272797 37.754837 52796 34.682365 -69.550476 37.440300 52797 34.353836 -68.859375 36.685257 52798 45.563126 -69.784592 36.025505 52799 10.514915 -69.416962 36.127289 52800 28.208328 -70.655472 35.568092 52801 32.867920 -70.782349 35.213615 52802 33.426910 -71.033844 35.709435 52803 43.856689 -71.302902 36.160362 52804 44.631531 -70.468033 36.595268 52805 15.461845 -72.254517 34.180740 52806 15.071259 -73.212128 34.543701 52807 27.927711 -71.823685 35.845573 52808 43.392944 -71.800171 35.717255 52809 14.520866 -73.922348 35.062180 52810 32.175171 -72.830994 35.502258 52811 31.722155 -72.948898 34.923775 52812 15.318428 -74.154037 34.737808 52813 21.862091 -73.833633 34.889740 52814 32.098740 -73.625671 35.432297 52815 5.890701 -74.284744 35.640327 52816 15.446404 -75.066269 35.092697 52817 22.243210 -75.051849 35.029480 52818 27.948235 -73.279434 36.478821 52819 40.864838 -75.271286 35.377724 52820 41.590836 -73.615891 36.610435 52821 42.244385 -72.918839 36.652702 52822 10.421570 -77.070831 34.815002 52823 16.779526 -76.045792 35.221756 52824 15.552902 -76.074310 36.010002 52825 27.948128 -74.841263 35.667870 52826 32.658554 -75.394989 35.866997 52827 40.429871 -76.025482 35.328506 52828 21.159210 -77.225647 35.207886 52829 22.132156 -76.800064 34.789574 52830 39.817215 -76.876999 35.265335 52831 9.836807 -78.237701 34.891212 52832 20.587410 -77.404922 36.449066 52833 19.726173 -76.875244 35.763275 52834 22.253220 -77.461029 35.046951 52835 23.133797 -77.427261 35.610512 52836 22.233902 -77.823730 35.504410 52837 29.102615 -77.712067 36.224518 52838 28.779175 -76.825928 36.091942 52839 8.894226 -81.334564 36.251205 52840 29.832169 -79.543823 36.061432 52841 30.124466 -80.539917 35.939240 52842 30.264526 -79.677322 36.873573 52843 29.752518 -81.656372 34.943306 52844 19.013519 -81.550400 34.766861 52845 34.183762 -79.493820 36.020248 52846 34.884888 -80.144409 36.112434 52847 34.928482 -80.430435 35.605988 52848 34.459686 -80.682037 34.855080 52849 18.049393 -82.298264 35.044479 52850 29.759521 -83.293839 35.190765 52851 30.237061 -82.632294 35.907402 52852 9.402451 -82.888092 34.952194 52853 19.154007 -82.269913 36.346436 52854 19.787636 -82.803772 36.807091 52855 22.792755 -83.811600 35.093933 52856 18.735947 -84.812195 33.682320 52857 18.453613 -84.814835 34.278305 52858 18.124008 -83.681046 34.563431 52859 26.379166 -84.568588 34.566284 52860 27.438225 -84.708389 35.075218 52861 28.523705 -84.596924 35.273911 52862 28.909866 -84.563354 35.764816 52863 29.270844 -84.196823 35.447609 52864 9.156219 -84.231110 34.976082 52865 9.836769 -85.885437 34.990242 52866 15.765274 -87.260864 35.194199 52867 14.310577 -87.636978 35.301971 52868 17.291336 -86.870575 33.972595 52869 18.162949 -85.973282 34.750526 52870 16.067368 -87.246170 34.280952 52871 7.483887 52.976379 44.177330 52872 5.907662 52.544342 43.467880 52873 6.300911 52.152283 44.699600 52874 5.872604 51.660675 43.904083 52875 6.620758 52.686554 44.317955 52876 9.351929 52.694168 43.716164 52877 10.299850 51.859146 43.601585 52878 5.812355 50.548157 44.497971 52879 10.785873 51.047928 43.455376 52880 16.790169 49.330597 43.558441 52881 5.287964 49.331818 44.646553 52882 15.838295 48.734955 43.963013 52883 17.822754 49.337494 44.099487 52884 5.604149 48.204102 42.637291 52885 5.657189 49.793427 45.555054 52886 10.708618 49.486649 44.728081 52887 11.535599 48.914490 44.003014 52888 11.444427 48.530243 44.729332 52889 21.597603 46.678131 43.778000 52890 5.119789 47.848267 42.853943 52891 4.774017 47.242142 43.346489 52892 22.305573 45.736038 43.752495 52893 22.579834 45.160187 44.846451 52894 21.974289 46.210602 44.565414 52895 5.850685 43.781342 44.251572 52896 6.780617 42.465363 43.483429 52897 29.894012 41.490768 43.157806 52898 29.956429 40.710510 44.118469 52899 30.854996 41.277069 43.371315 52900 29.171951 40.492310 44.186943 52901 28.752686 40.066956 44.130928 52902 22.434715 39.216614 43.641724 52903 28.384102 39.564774 43.540138 52904 20.549805 37.873657 44.238449 52905 21.587463 38.479523 44.335350 52906 23.112572 40.150421 44.056702 52907 28.243629 39.309052 44.467918 52908 27.514702 38.713287 44.458847 52909 4.432533 37.360474 42.420723 52910 4.066033 35.789703 44.161758 52911 4.983910 35.158386 42.645195 52912 5.674759 35.046783 42.039490 52913 19.941338 37.414810 43.590439 52914 25.802711 36.882629 43.826935 52915 33.510353 37.758072 43.678658 52916 4.694634 34.310211 43.214073 52917 16.299683 35.234360 42.919899 52918 16.600960 35.815308 43.207489 52919 17.071274 36.089432 43.072052 52920 17.703903 36.319489 42.966331 52921 18.584648 36.939087 43.682442 52922 31.282478 35.774719 43.103188 52923 30.931770 34.978760 43.255768 52924 7.626495 31.293106 42.391739 52925 5.710960 34.247833 42.403671 52926 16.331848 35.506836 43.840179 52927 6.589676 33.294357 42.276100 52928 5.462914 33.174469 42.935455 52929 17.084068 34.359726 44.567245 52930 16.584274 35.384216 44.810249 52931 16.349373 34.628357 43.450119 52932 30.948967 34.416321 43.865448 52933 31.022614 35.642914 44.348434 52934 7.348221 32.484711 42.204521 52935 6.425118 32.109222 42.791573 52936 17.039948 33.415085 42.659180 52937 20.479828 31.470413 43.051765 52938 19.990448 32.506134 43.422981 52939 24.947121 34.974304 43.640213 52940 25.433167 34.024750 44.209923 52941 25.439560 32.987625 43.164040 52942 20.656700 32.102890 43.844757 52943 20.431213 32.595245 44.077271 52944 37.853348 30.979385 43.387383 52945 7.804260 29.743256 42.839851 52946 20.692833 32.172668 44.709694 52947 20.697388 31.153336 44.180359 52948 27.047852 30.366592 42.672676 52949 8.689568 29.294022 42.333382 52950 9.216393 28.661224 42.008453 52951 37.403671 30.468002 44.199257 52952 38.029587 30.377274 43.817871 52953 38.063812 29.313995 43.976074 52954 9.443985 27.896210 42.063332 52955 26.587334 29.319427 42.428513 52956 20.303177 29.293900 43.114853 52957 24.909233 28.003754 43.093910 52958 25.824142 28.657104 42.740166 52959 26.492569 29.586227 43.485786 52960 25.510567 28.682266 44.354523 52961 38.521683 30.267639 43.357452 52962 24.099770 26.942657 42.324394 52963 8.700592 25.608826 42.785583 52964 4.210625 23.841339 41.803917 52965 22.328659 25.106049 42.561897 52966 22.202003 24.574341 42.067375 52967 29.302170 26.365356 43.841522 52968 33.192642 27.563400 44.413017 52969 36.010010 24.732239 42.555855 52970 35.933151 23.411606 42.322067 52971 36.889984 23.612961 42.544762 52972 37.028870 24.661270 42.868149 52973 17.006706 26.158752 44.527550 52974 17.579788 27.386230 44.044815 52975 17.487396 24.114014 41.991447 52976 30.134651 24.484222 43.555931 52977 29.300888 24.885544 43.706680 52978 31.617846 23.766373 42.974350 52979 30.975456 24.010162 43.692711 52980 37.824860 23.924149 42.809036 52981 17.011635 23.023178 42.970657 52982 17.052689 24.630142 43.545914 52983 32.187073 23.545059 43.596992 52984 33.556229 23.328003 42.389656 52985 36.728752 22.182312 42.749199 52986 35.864494 22.540039 42.439461 52987 37.938774 22.471588 42.766304 52988 38.777420 24.639038 42.964691 52989 38.691498 23.307648 42.735191 52990 40.049286 23.758331 42.872894 52991 33.863525 22.866180 43.551575 52992 39.036171 22.415955 42.921547 52993 38.815590 21.551376 43.496353 52994 37.816170 21.466553 43.501411 52995 35.790222 22.056488 42.886528 52996 37.062653 21.386276 43.626053 52997 36.336609 21.663437 43.550835 52998 35.643372 21.874557 43.618721 52999 40.049255 21.932434 43.613823 53000 46.059662 20.435638 42.444473 53001 46.058136 20.120056 42.351135 53002 46.190308 20.224609 42.568542 53003 17.679642 18.962219 41.659134 53004 17.402618 20.046051 42.925179 53005 18.452393 18.801956 43.195030 53006 24.307800 18.170609 41.684395 53007 45.729813 19.621887 42.420341 53008 46.046906 20.038834 42.662651 53009 24.137772 19.588852 42.785500 53010 45.427948 19.059692 43.293839 53011 2.902145 16.374695 41.557602 53012 25.450287 18.411179 42.927185 53013 25.358231 20.196655 44.347427 53014 26.598068 18.747345 43.769226 53015 25.411545 16.545624 42.230247 53016 2.680893 17.093262 41.498886 53017 2.795639 16.897202 42.316360 53018 3.296028 15.449142 43.129524 53019 25.810013 14.488770 42.902481 53020 24.904648 14.832489 41.636597 53021 3.513291 15.108734 41.366982 53022 4.284149 14.542175 40.978912 53023 20.931442 15.473572 41.537827 53024 44.796997 18.042343 43.318474 53025 21.123062 15.788239 42.550476 53026 37.451645 14.856064 42.219688 53027 39.966568 15.580536 43.060944 53028 3.607887 13.816208 42.978012 53029 3.892418 13.111023 43.973366 53030 4.561730 12.820496 42.860107 53031 4.354286 14.044006 41.435905 53032 23.247917 12.633896 42.308197 53033 23.257271 11.930374 43.282082 53034 22.353638 12.511230 43.299164 53035 25.456894 13.228790 42.918137 53036 25.134644 13.618713 42.186951 53037 34.446228 13.654053 41.454468 53038 33.560226 13.063507 41.875259 53039 34.303795 13.119339 42.692955 53040 24.583878 12.424164 42.764114 53041 25.163422 11.949387 43.841171 53042 24.705879 11.633255 43.799561 53043 8.593102 11.320404 41.859596 53044 10.128456 10.255615 40.998543 53045 32.764450 11.939377 41.716667 53046 33.568314 11.095245 41.576248 53047 33.429108 11.714432 42.480537 53048 34.922211 10.745300 41.814926 53049 36.175804 10.639404 42.438042 53050 42.106750 10.806931 43.857857 53051 40.731415 11.555618 44.331955 53052 41.008041 10.604248 42.866890 53053 10.386032 9.543427 41.277161 53054 10.712692 8.418396 41.709206 53055 50.073441 8.484955 42.024498 53056 51.643295 8.590759 42.543137 53057 50.921814 8.666885 42.524078 53058 52.684784 7.728149 42.541946 53059 7.522537 7.322647 40.767006 53060 50.362640 8.534302 42.784035 53061 49.555847 8.113251 42.871269 53062 10.305305 6.656906 41.584068 53063 10.561188 7.219528 42.740173 53064 10.678925 6.546417 42.508949 53065 42.843170 9.455261 43.364548 53066 46.425079 5.778473 42.280876 53067 39.021255 4.688446 42.058449 53068 39.043457 5.083885 42.886238 53069 38.964539 4.641129 41.265701 53070 45.742371 4.633240 42.722702 53071 53.268005 5.142357 41.910065 53072 2.627693 2.395233 42.025444 53073 2.923760 2.213333 40.989021 53074 51.655899 3.563232 41.626656 53075 52.332275 4.264542 42.006416 53076 52.814224 4.725540 42.075386 53077 37.350311 3.680161 41.382156 53078 50.824600 1.746307 42.757576 53079 51.073578 2.719727 43.108315 53080 3.820061 1.691925 40.534821 53081 5.063088 1.026978 40.710625 53082 3.775490 0.575867 41.551895 53083 34.726334 0.891144 42.118813 53084 8.119026 0.116196 40.676430 53085 6.884338 -1.411255 42.249580 53086 8.427414 -1.083267 41.332985 53087 33.583061 0.198990 41.123093 53088 34.142502 0.307022 41.923500 53089 41.141602 -0.080154 41.051086 53090 8.894936 -0.302582 40.250641 53091 33.807259 -1.009293 42.368629 53092 34.623329 0.037415 42.729301 53093 9.334953 -1.395096 40.495422 53094 40.146835 -0.757751 40.643036 53095 49.664017 1.059906 41.455093 53096 52.804199 -2.452225 42.081207 53097 9.539383 -2.206329 40.961845 53098 40.116089 -1.868835 41.030899 53099 39.115082 -3.017410 40.660042 53100 3.819763 -3.469696 38.970871 53101 9.042648 -4.631287 39.846481 53102 4.368134 -4.774780 39.745461 53103 3.021607 -5.324539 39.611320 53104 3.823982 -5.970047 40.413101 53105 9.986115 -4.580307 40.699379 53106 33.340744 -2.478668 41.839989 53107 32.518623 -1.428711 41.366104 53108 32.332214 -2.491302 40.917091 53109 36.838554 -4.643814 41.114052 53110 39.084236 -3.749023 40.843544 53111 40.012024 -3.485153 41.305199 53112 41.269196 -3.968338 42.123894 53113 40.151794 -4.466476 41.782166 53114 52.939453 -3.754944 42.017479 53115 53.093460 -3.255508 42.264763 53116 6.479057 -5.071274 40.023956 53117 8.354660 -5.103165 39.918839 53118 7.600898 -5.252380 39.975494 53119 9.341049 -5.406738 40.384193 53120 10.082069 -5.462524 41.268440 53121 33.350845 -3.662827 40.582741 53122 34.687546 -3.718628 41.674171 53123 38.214096 -4.882065 42.048027 53124 51.913452 -5.256302 41.848312 53125 52.364639 -4.123520 41.708679 53126 2.498497 -6.274704 39.706497 53127 8.099098 -6.156174 40.493530 53128 6.739037 -6.509125 40.838921 53129 9.156700 -6.221954 40.600349 53130 55.452484 -8.034576 40.778198 53131 56.189407 -8.242706 40.924683 53132 56.153534 -9.233109 41.266556 53133 54.838043 -9.579483 41.377800 53134 1.887192 -8.897018 40.010605 53135 47.794327 -8.990433 40.768997 53136 49.127014 -8.412704 41.300430 53137 53.625641 -10.846176 41.175926 53138 52.983490 -10.632706 40.471283 53139 43.883575 -11.074600 39.783707 53140 45.694885 -10.602966 40.368332 53141 3.354408 -13.814438 39.336494 53142 46.069397 -11.557571 40.814980 53143 45.394897 -12.679108 40.585571 53144 44.886948 -13.646927 40.565392 53145 46.072235 -13.660172 41.307976 53146 54.258606 -11.662338 42.030373 53147 53.062485 -12.425491 41.289383 53148 42.814240 -14.888168 40.166191 53149 43.857773 -14.262909 40.405312 53150 45.717575 -15.244110 42.236855 53151 46.315002 -14.517090 41.947990 53152 45.014740 -14.685272 41.290825 53153 57.806000 -13.818710 40.639755 53154 57.183594 -12.859070 41.369659 53155 3.692124 -14.810532 40.578026 53156 43.403564 -15.593094 41.203285 53157 57.343872 -14.786545 42.025070 53158 3.021980 -16.167419 39.287506 53159 4.279686 -18.749771 40.280121 53160 37.388580 -16.615799 40.054886 53161 37.018402 -17.351654 41.624481 53162 38.286461 -16.924118 41.083527 53163 40.265167 -16.064713 40.355095 53164 41.218536 -16.323257 40.966934 53165 42.133636 -15.824509 40.626900 53166 47.660309 -16.876953 40.197250 53167 46.308380 -17.932190 40.718399 53168 51.936218 -15.100296 41.838440 53169 35.615799 -17.733246 40.790619 53170 34.690353 -18.712753 40.680817 53171 34.616501 -18.041107 41.734062 53172 35.643257 -17.559830 42.104225 53173 35.807602 -17.724091 39.734711 53174 43.961517 -18.274658 39.839111 53175 44.791718 -18.327225 40.410629 53176 58.199448 -16.335632 41.411156 53177 35.325119 -18.534607 39.806656 53178 35.282082 -19.638290 40.054359 53179 43.077469 -18.785217 39.929008 53180 4.403298 -20.153107 39.165176 53181 4.694939 -19.825195 39.728439 53182 4.658424 -19.271240 39.905777 53183 37.566376 -19.896698 39.296165 53184 41.174713 -19.243469 39.687454 53185 42.273651 -19.602066 40.702408 53186 58.024368 -17.764786 41.529434 53187 57.215408 -18.422043 42.297363 53188 3.815445 -21.049866 38.932915 53189 35.556808 -20.596878 40.859230 53190 37.531898 -20.332703 39.792351 53191 37.557640 -20.738876 40.629776 53192 38.651260 -21.025223 41.553352 53193 37.668030 -21.227051 41.899529 53194 38.282852 -20.286209 40.010017 53195 39.610344 -20.368652 40.599602 53196 51.751129 -20.548523 41.232491 53197 4.015587 -22.736328 40.782639 53198 49.733322 -21.589233 40.863235 53199 58.340820 -21.856720 40.392548 53200 59.501770 -23.457916 41.274605 53201 45.765152 -22.472412 39.487961 53202 48.027039 -22.356827 40.783409 53203 47.154251 -22.975464 41.298988 53204 48.894882 -22.086761 41.047028 53205 56.276947 -22.552719 41.024124 53206 56.156555 -22.477646 40.190231 53207 56.938232 -22.171310 40.263451 53208 44.694061 -23.132599 39.838646 53209 46.006836 -22.948868 40.432198 53210 53.324982 -24.096573 40.514084 53211 54.552124 -23.246170 39.845718 53212 3.509903 -26.261230 38.981056 53213 42.152405 -25.066544 40.157288 53214 51.700104 -24.637939 39.838028 53215 54.331482 -23.696671 41.054314 53216 59.418304 -25.019272 40.037933 53217 58.988617 -25.553543 39.763878 53218 50.722168 -25.228714 39.899216 53219 49.843079 -25.958572 40.085327 53220 2.896256 -25.854691 40.953812 53221 38.653725 -26.485764 39.071228 53222 48.612488 -25.662903 38.794968 53223 47.878311 -27.175537 40.156273 53224 46.622467 -27.263504 39.470375 53225 48.816559 -26.158112 39.654877 53226 58.264618 -26.021774 40.235443 53227 39.956833 -27.604553 40.507622 53228 38.889374 -27.146164 39.611763 53229 38.799202 -28.046051 40.293999 53230 37.640465 -27.868546 39.619926 53231 39.536560 -28.256790 40.947876 53232 45.402679 -28.392471 39.407928 53233 46.839325 -28.154480 40.438545 53234 5.451508 -29.589066 38.492691 53235 34.401703 -29.463867 39.161095 53236 33.665482 -28.694138 40.266846 53237 35.020462 -28.545853 40.407646 53238 53.936829 -29.178894 38.828079 53239 4.409546 -30.666687 38.156860 53240 33.019974 -30.036865 39.106331 53241 32.919762 -31.160721 39.066879 53242 32.047516 -30.556885 39.147339 53243 33.720367 -32.201096 39.728737 53244 44.631409 -29.924484 39.740784 53245 56.268997 -29.640152 39.764984 53246 31.703295 -29.656433 39.746712 53247 31.359848 -30.440781 39.456604 53248 32.135063 -31.233932 39.081245 53249 43.394409 -31.894257 40.976311 53250 42.436478 -32.142090 40.339493 53251 31.356583 -31.324982 39.396637 53252 32.272423 -31.975693 39.386131 53253 32.445488 -33.150620 40.065407 53254 40.484344 -32.470581 39.570084 53255 41.510956 -32.221741 39.553497 53256 42.127777 -31.703339 39.099312 53257 58.326492 -32.091125 39.668236 53258 58.189911 -31.242096 40.215881 53259 58.020844 -32.738068 40.844604 53260 58.202087 -36.586044 40.970505 53261 57.975204 -35.650574 41.319252 53262 58.375656 -35.707947 40.904556 53263 5.051239 -39.356247 38.233658 53264 10.833679 -41.359650 37.971283 53265 58.122482 -38.709793 40.405640 53266 9.533569 -40.340790 38.331207 53267 43.651520 -41.834335 38.546005 53268 48.810745 -40.755264 39.416634 53269 50.599075 -41.058289 39.051598 53270 50.177139 -42.690994 38.497780 53271 50.586670 -39.658600 40.044739 53272 50.984436 -39.067017 40.663734 53273 51.564270 -39.394424 40.355247 53274 51.748581 -40.836380 39.138641 53275 51.657135 -40.135010 39.670464 53276 52.413330 -40.761475 39.657906 53277 58.260437 -39.611725 39.447830 53278 11.766426 -42.308167 37.473755 53279 12.228271 -41.816788 38.071251 53280 10.716156 -40.293701 39.485573 53281 12.132500 -41.296005 38.947746 53282 12.632156 -42.397369 37.734192 53283 13.087074 -42.136658 38.513176 53284 13.535301 -42.400101 39.085854 53285 13.524971 -42.999985 38.314224 53286 51.884796 -41.646652 39.203758 53287 57.705963 -42.615997 39.491623 53288 57.682312 -41.653976 39.977783 53289 4.561142 -44.119843 37.093834 53290 12.315498 -43.109924 37.209473 53291 13.136444 -43.000687 37.745598 53292 51.244751 -42.691391 39.060326 53293 52.130829 -42.741486 39.542526 53294 57.733826 -43.231216 38.673798 53295 6.906250 -44.194855 37.264748 53296 49.454208 -44.040878 37.755493 53297 49.992386 -43.740021 38.205307 53298 50.936371 -43.919189 38.655518 53299 13.464653 -45.516357 37.548302 53300 41.956146 -45.006729 39.188957 53301 56.877289 -44.295624 38.866745 53302 57.326263 -43.868790 38.621124 53303 56.085800 -44.618774 39.772934 53304 54.865036 -45.237244 39.702667 53305 42.735092 -46.635269 38.239159 53306 43.404388 -47.518768 39.309883 53307 52.144531 -44.008209 39.540131 53308 53.887711 -45.444946 39.401451 53309 11.667580 -47.862610 37.542160 53310 46.752533 -47.707092 39.246277 53311 10.089523 -48.932922 37.664185 53312 9.488434 -48.272415 38.457176 53313 7.992843 -49.083527 38.642937 53314 9.618270 -49.679184 38.004349 53315 11.015259 -50.150528 37.688141 53316 28.490845 -49.109940 39.130066 53317 29.424286 -50.395218 38.054871 53318 27.944244 -50.726486 39.427559 53319 30.424026 -50.058533 37.891098 53320 31.316734 -48.891968 39.010567 53321 31.490601 -50.808380 37.936447 53322 29.987274 -49.344101 38.165901 53323 52.588898 -49.363846 38.282570 53324 10.205292 -51.039764 38.463188 53325 12.833069 -50.997559 37.305840 53326 11.870712 -51.038925 38.147110 53327 12.745209 -51.679184 37.843292 53328 29.296814 -48.960602 38.531342 53329 27.857674 -49.528763 39.857368 53330 28.177231 -48.728424 39.918701 53331 29.898148 -49.884567 37.830978 53332 30.508423 -51.451767 37.771019 53333 54.975616 -50.817688 39.400101 53334 13.166824 -51.782516 36.989983 53335 29.794464 -51.404755 37.736923 53336 32.394608 -50.495529 38.696548 53337 33.367577 -51.366119 38.437912 53338 32.743912 -52.015030 37.831421 53339 33.267281 -50.703644 39.894867 53340 34.053772 -51.503799 38.844780 53341 31.588318 -52.173325 37.792717 53342 34.342422 -52.474030 37.957932 53343 33.721115 -53.632721 37.762421 53344 34.772636 -51.921600 38.831543 53345 35.448669 -52.165466 38.955612 53346 35.247391 -52.318954 38.294846 53347 12.441879 -53.742462 37.610725 53348 12.561699 -54.636566 36.784676 53349 29.951942 -51.948853 37.975266 53350 29.434814 -51.496017 37.996994 53351 30.792542 -52.869324 38.578407 53352 32.322151 -53.266464 38.022659 53353 35.442543 -52.968277 37.874374 53354 36.205940 -52.644135 38.673058 53355 36.453445 -52.494370 39.552597 53356 37.387253 -52.971756 39.543480 53357 35.148605 -54.208984 37.750107 53358 39.020340 -53.753586 38.702240 53359 38.903275 -54.898529 38.137756 53360 37.967102 -54.581406 37.983765 53361 44.884705 -53.564606 38.023369 53362 44.320984 -53.678116 38.361900 53363 45.113220 -53.162949 38.440742 53364 48.033432 -52.922028 38.659340 53365 55.276611 -52.084183 38.907372 53366 31.920519 -53.962006 38.991417 53367 33.115952 -54.486343 38.587570 53368 33.377182 -55.498642 39.529999 53369 32.368813 -54.964249 40.131622 53370 34.155807 -54.529129 37.974739 53371 34.482056 -55.359100 38.571136 53372 36.259979 -53.682419 37.810974 53373 36.351166 -54.689301 37.717712 53374 37.038025 -54.364243 37.774155 53375 37.316513 -53.575241 38.311165 53376 38.941986 -53.405014 40.321617 53377 40.380219 -54.629227 38.457146 53378 39.542847 -54.741486 38.274940 53379 40.638245 -53.523056 38.981857 53380 45.377747 -53.964249 38.030014 53381 47.635132 -52.579636 39.050911 53382 48.234741 -52.795792 39.181725 53383 55.300385 -51.377914 39.128769 53384 12.377861 -55.718369 36.921844 53385 34.211678 -56.029495 39.582726 53386 36.050697 -55.735260 38.284912 53387 36.465515 -56.699783 39.019386 53388 35.314774 -56.486664 39.415695 53389 37.154167 -55.318832 37.982246 53390 38.169220 -55.734985 38.229958 53391 39.690857 -55.980713 38.716888 53392 44.579941 -54.635559 38.351837 53393 49.251282 -53.898788 38.891785 53394 11.923187 -57.136627 36.939171 53395 53.902985 -56.168472 37.848961 53396 53.259918 -57.030762 38.345100 53397 11.611191 -58.419357 36.261658 53398 46.875916 -58.607513 40.034798 53399 46.510254 -58.733673 39.399536 53400 47.132690 -59.176788 39.942162 53401 50.421600 -56.343094 38.684227 53402 51.254654 -56.825760 39.655701 53403 10.303703 -62.881577 37.998230 53404 10.136658 -63.167786 38.894066 53405 9.248383 -64.239075 38.849007 53406 19.274155 -61.634964 35.819336 53407 18.273560 -61.968353 36.223038 53408 26.860710 -61.859467 37.824417 53409 28.916595 -61.987167 38.011627 53410 17.664291 -63.236359 36.305214 53411 18.495567 -63.080933 36.715111 53412 18.759331 -63.873932 37.269081 53413 19.607803 -64.076584 37.627151 53414 27.696220 -61.688110 38.372215 53415 31.142853 -62.158966 36.957184 53416 39.065384 -63.064636 37.568832 53417 39.039627 -63.603683 38.652748 53418 39.566132 -63.112610 38.951805 53419 20.337448 -63.109741 36.435982 53420 20.203552 -63.513367 36.909538 53421 33.091949 -63.728683 37.203255 53422 32.537430 -63.046417 37.449066 53423 47.057800 -63.308472 38.002975 53424 47.346375 -61.942978 38.588463 53425 9.210434 -64.009583 37.535400 53426 16.514709 -65.965866 36.324905 53427 17.249451 -64.465500 36.312386 53428 18.048111 -64.098740 36.819336 53429 20.850586 -64.526627 36.660187 53430 27.202095 -64.121796 36.546791 53431 26.405388 -64.077850 37.339340 53432 25.361679 -64.254700 38.600426 53433 25.507385 -63.138947 38.359291 53434 26.425873 -62.724609 37.380104 53435 33.442886 -64.757294 37.097641 53436 42.032379 -63.268875 37.470268 53437 40.961578 -62.817703 38.198235 53438 41.976517 -63.272461 38.549622 53439 43.611389 -63.727127 37.025482 53440 43.012161 -63.735992 38.360077 53441 44.326721 -64.170059 38.224030 53442 46.511246 -63.798462 37.324615 53443 17.629807 -65.297241 36.934113 53444 20.566246 -65.018906 37.625427 53445 20.403793 -64.234177 37.277672 53446 27.537392 -65.046066 36.973221 53447 28.957535 -66.065018 36.552429 53448 28.398041 -66.171997 37.645622 53449 28.444031 -66.588715 38.157181 53450 27.115463 -66.516373 38.730316 53451 46.466888 -64.105667 37.491867 53452 46.780930 -63.916077 37.610886 53453 7.348892 -65.589645 38.173950 53454 6.399338 -66.113678 38.421341 53455 14.941925 -66.519196 36.214188 53456 15.975594 -67.275635 36.441727 53457 16.693375 -67.026489 36.539864 53458 38.932220 -64.581284 38.081985 53459 4.598717 -67.609390 36.570824 53460 14.912155 -67.944382 36.929047 53461 17.320541 -66.882416 37.248764 53462 39.928612 -66.732330 37.946701 53463 39.204773 -65.782043 37.956512 53464 16.002075 -68.219360 36.758453 53465 16.655579 -67.845261 36.773125 53466 34.011635 -65.783661 37.790749 53467 44.907883 -67.650024 35.908020 53468 12.527603 -67.889267 37.311378 53469 12.540947 -67.329178 36.419518 53470 11.810379 -68.385117 37.650391 53471 29.575134 -68.305496 38.486099 53472 29.177017 -67.104019 37.712440 53473 29.475723 -69.860809 36.881813 53474 29.656708 -70.061844 37.323578 53475 34.540550 -70.253036 36.663071 53476 34.219185 -70.918320 36.322472 53477 9.983688 -69.928864 36.880280 53478 9.297607 -70.881149 36.996338 53479 9.808258 -70.387070 38.193016 53480 45.641357 -69.227722 36.761726 53481 45.159775 -69.684097 37.085197 53482 45.024994 -69.026260 37.506859 53483 28.911575 -70.698257 36.720901 53484 28.865387 -69.969193 36.268501 53485 29.225067 -69.841995 36.680397 53486 34.619156 -70.950287 36.756554 53487 44.055618 -70.354675 38.192528 53488 44.501923 -69.652512 37.890923 53489 33.575134 -71.692688 36.137001 53490 32.956680 -72.680923 36.054993 53491 35.891037 -72.366928 39.187325 53492 35.728943 -73.673553 38.895973 53493 34.915962 -74.353043 38.241020 53494 43.084854 -71.972824 36.963203 53495 6.971596 -73.975662 35.594391 53496 14.141960 -75.221176 35.816574 53497 33.088737 -74.060440 36.389191 53498 33.447166 -75.966064 36.548965 53499 33.977585 -74.009201 37.263153 53500 41.064743 -74.544510 36.097054 53501 7.766357 -73.780243 36.832405 53502 8.642136 -72.098984 37.033340 53503 12.666648 -75.012115 35.463448 53504 11.213379 -76.794296 35.931892 53505 14.593445 -76.927658 37.033585 53506 13.153519 -76.176117 36.391525 53507 22.705505 -75.995651 35.301147 53508 22.582031 -74.356339 36.461548 53509 28.503235 -74.825882 37.352745 53510 28.272194 -73.663284 37.642227 53511 10.318199 -77.718369 35.886307 53512 21.789627 -72.600800 38.368767 53513 23.188629 -74.706635 38.405884 53514 23.473679 -76.211105 36.214882 53515 28.478821 -75.992584 36.051552 53516 39.883270 -76.177673 36.232513 53517 40.417908 -75.469284 36.080986 53518 11.260529 -77.640945 36.774651 53519 18.711060 -76.895477 36.657143 53520 17.679710 -76.625824 36.231148 53521 16.536636 -76.788834 36.736015 53522 33.538322 -77.857224 36.218445 53523 34.843597 -77.470581 37.785622 53524 39.290085 -76.957062 36.142929 53525 38.249908 -77.791901 36.439934 53526 10.626175 -80.159668 38.286728 53527 10.609605 -79.393021 37.639214 53528 12.001190 -78.827469 37.899399 53529 22.724640 -78.308609 36.176674 53530 21.581444 -78.005722 36.593300 53531 23.487907 -78.288452 36.073265 53532 23.520584 -78.883743 36.680672 53533 24.312408 -78.061523 36.775528 53534 29.696426 -77.358948 37.902260 53535 29.008202 -76.462509 37.040039 53536 29.414612 -78.853683 35.825081 53537 35.609596 -76.771576 38.824913 53538 35.735901 -77.318787 38.700371 53539 8.851288 -79.750931 35.674355 53540 9.453491 -79.048233 35.909348 53541 36.817123 -78.231216 37.644157 53542 8.650826 -80.566803 36.297928 53543 30.284454 -81.606934 36.131577 53544 35.657120 -80.140427 35.921371 53545 18.701584 -81.836899 35.534248 53546 34.992310 -79.151611 37.060478 53547 9.391663 -82.845993 36.834694 53548 21.187408 -83.283707 35.687012 53549 21.978172 -83.829239 35.744820 53550 9.836533 -84.632782 36.369682 53551 20.655930 -83.176666 36.340599 53552 30.206024 -83.340607 35.800529 53553 17.865135 -83.717529 36.715012 53554 18.152954 -84.583298 35.433250 53555 18.034325 -84.815475 36.264450 53556 17.905151 -83.341354 35.561333 53557 22.877075 -84.531555 36.577209 53558 25.056885 -85.287491 36.163322 53559 25.654152 -85.418289 36.846382 53560 25.970337 -85.421692 36.275208 53561 29.898186 -83.760437 35.911911 53562 24.046021 -85.046783 36.720062 53563 26.185379 -85.056168 35.542351 53564 28.206169 -84.611633 36.230453 53565 11.084091 -86.954285 35.181381 53566 15.502251 -87.042526 36.586090 53567 14.165298 -87.337509 36.433929 53568 17.219818 -86.815186 35.064156 53569 13.086845 -87.463318 35.864868 53570 8.358948 52.958878 44.209862 53571 6.157715 51.481567 45.024422 53572 9.883835 51.141510 44.538094 53573 12.228653 48.301300 44.183815 53574 16.982597 48.724167 44.651306 53575 18.575462 49.211578 44.283958 53576 18.312729 48.714371 44.816399 53577 10.601639 48.741226 45.870644 53578 14.805588 48.284332 44.428772 53579 15.915222 48.048340 45.349983 53580 11.969696 47.970535 45.381485 53581 21.276459 45.978561 45.601852 53582 4.560524 46.618958 46.625648 53583 4.834549 47.992508 46.392059 53584 4.618187 46.116348 44.021141 53585 23.239906 44.144196 44.583923 53586 23.233406 40.765671 46.090416 53587 23.264267 41.711426 47.185944 53588 23.172318 42.848831 45.796951 53589 6.951958 41.234451 43.060852 53590 22.901245 44.216080 45.600563 53591 3.947441 38.784302 45.214218 53592 4.120857 38.648026 43.672371 53593 5.439812 42.254028 45.074371 53594 29.169380 40.111572 44.722015 53595 30.083237 39.896515 45.215248 53596 31.761751 39.854401 44.086731 53597 22.649857 39.558105 44.939026 53598 32.960892 37.583054 44.202217 53599 32.764374 38.351715 44.356117 53600 4.153946 37.515900 43.248856 53601 27.009232 38.195740 44.765564 53602 26.293579 37.331818 45.097763 53603 3.854866 36.843689 46.373131 53604 17.101028 36.284729 44.041191 53605 17.133492 36.225220 45.606865 53606 31.893480 36.592270 44.029037 53607 32.512985 37.196320 44.340820 53608 25.357224 35.316528 44.722466 53609 25.226013 36.008224 43.825653 53610 3.917435 34.190430 44.199371 53611 4.863838 31.670456 43.722076 53612 4.207108 33.080505 43.764206 53613 16.863037 33.932312 43.379128 53614 19.559387 33.691559 46.030739 53615 20.903549 32.549820 46.052155 53616 20.395294 33.487732 46.824669 53617 6.342430 30.437744 43.467323 53618 18.427841 33.845734 44.921982 53619 19.887642 32.984299 44.632637 53620 26.247604 32.798920 44.113495 53621 31.368393 33.706741 43.901230 53622 32.047134 33.577271 44.953796 53623 34.853226 32.405472 43.945068 53624 3.989052 32.228546 43.929138 53625 7.086350 29.000000 43.912766 53626 27.035217 32.184235 44.405449 53627 36.486557 30.739563 44.871758 53628 27.276291 31.340469 44.042831 53629 27.113754 30.485062 43.949150 53630 19.375839 28.954834 43.760025 53631 27.177406 30.506500 45.824608 53632 26.644211 29.996246 44.823830 53633 27.327835 30.903564 44.941284 53634 36.621391 29.358185 44.834991 53635 38.603050 27.944656 43.653664 53636 7.887664 26.511230 44.670998 53637 7.438248 25.598801 45.000572 53638 8.498695 25.709549 43.907227 53639 8.585297 28.174393 42.986412 53640 19.124817 29.389954 45.364395 53641 20.083260 30.051666 44.415092 53642 38.140915 26.851440 43.684601 53643 8.649208 26.691818 43.455658 53644 18.315781 27.635666 43.126625 53645 18.382996 28.321594 43.937141 53646 21.830963 24.467743 42.837357 53647 30.309967 27.180420 44.269615 53648 38.390686 25.820465 43.327469 53649 8.705643 25.064117 43.264442 53650 23.766098 26.796844 44.174004 53651 23.588287 25.601288 46.899651 53652 23.160370 25.868225 45.877602 53653 24.428291 26.438675 46.244400 53654 35.498550 25.905182 43.069565 53655 35.000046 27.126678 43.925377 53656 36.615746 26.655731 43.712135 53657 36.867783 25.586990 43.220772 53658 37.593063 26.102859 43.592140 53659 37.682816 25.634644 43.397057 53660 8.519081 24.913422 42.853317 53661 28.250999 25.190552 44.506721 53662 28.391876 25.953613 44.035027 53663 28.945435 25.502258 43.639206 53664 27.287964 25.343079 45.701645 53665 27.370651 26.029358 44.957642 53666 37.763741 25.043732 43.132790 53667 5.449799 23.730469 42.454094 53668 6.602348 24.134583 42.460258 53669 6.609329 23.502686 43.151352 53670 8.412308 24.660858 43.221176 53671 21.457214 23.616653 43.079857 53672 26.449768 26.180038 45.938965 53673 26.974884 27.117111 45.590691 53674 41.424805 22.159821 43.675293 53675 41.858292 22.846680 43.148857 53676 42.972031 22.782867 43.259987 53677 3.700966 22.572250 42.074677 53678 4.505989 22.676193 42.679024 53679 5.463318 22.759491 43.222527 53680 6.210091 22.889175 43.962967 53681 5.337639 22.178894 43.928764 53682 16.595398 23.200241 44.771957 53683 21.139221 23.008133 42.962357 53684 21.148598 23.114716 43.269287 53685 21.017891 22.891510 43.150703 53686 31.577835 24.096252 44.921417 53687 30.579819 24.213501 44.636528 53688 33.040764 23.500366 44.490990 53689 3.999443 21.190903 43.278801 53690 21.176445 22.668625 43.017014 53691 35.029282 22.198486 43.276390 53692 41.028015 22.805695 43.153572 53693 44.352844 22.031799 43.496719 53694 23.815987 20.527344 43.588860 53695 23.001808 21.429779 44.149994 53696 22.136215 21.827698 43.823700 53697 39.522766 21.347504 44.233063 53698 40.798126 21.627655 44.518387 53699 45.229645 21.089951 43.515762 53700 24.043640 21.003891 44.493385 53701 40.107407 21.433731 44.390205 53702 46.044617 20.348663 42.752090 53703 45.714508 20.150909 43.145454 53704 17.972595 19.908218 44.552406 53705 3.025833 17.879868 42.760460 53706 26.414642 17.262161 43.310165 53707 3.609383 14.301971 42.176369 53708 19.588219 17.694550 43.084991 53709 20.994202 17.087616 43.819077 53710 42.386780 16.430695 44.381973 53711 41.535721 16.272125 44.226562 53712 26.443054 15.813126 43.583824 53713 36.949562 15.159698 43.650368 53714 36.428719 15.064789 44.382576 53715 36.098450 14.314667 43.772957 53716 36.173203 14.644791 44.702576 53717 4.279076 13.508652 42.133560 53718 25.806557 12.545547 44.609932 53719 24.875748 11.686218 44.932022 53720 35.357040 13.730423 42.738571 53721 34.949860 13.190430 43.537689 53722 5.895004 11.959900 43.165245 53723 7.199364 12.021301 42.081291 53724 33.489548 12.519730 42.559708 53725 9.661201 10.329971 41.759590 53726 34.336411 11.063446 42.783684 53727 34.020630 12.007294 43.357742 53728 34.602493 11.472809 43.851173 53729 37.404709 10.984100 43.868347 53730 39.357048 11.016739 43.326118 53731 35.137520 10.689423 42.445061 53732 41.494476 9.645721 42.042030 53733 10.013168 9.375244 42.552811 53734 43.399017 8.897873 43.846245 53735 43.289307 9.862137 43.972710 53736 52.092209 8.181091 42.864372 53737 2.605858 7.241577 41.310326 53738 2.735794 5.542023 42.055901 53739 3.547737 5.198059 42.821770 53740 6.390411 7.392731 41.403152 53741 47.354385 6.739487 42.380112 53742 48.338760 7.324570 43.153534 53743 7.267197 6.504715 41.807549 53744 9.809738 5.922531 42.612213 53745 47.383240 6.380432 43.349327 53746 8.593903 5.900024 42.017029 53747 41.658646 6.724289 43.008827 53748 40.788147 5.805252 42.477257 53749 40.937408 6.094635 43.467010 53750 53.189362 5.817337 42.419174 53751 40.070160 5.639038 43.237770 53752 38.208481 4.399811 42.114159 53753 37.064392 3.726273 42.712624 53754 36.109352 2.452316 42.595261 53755 36.654953 2.560989 43.702103 53756 51.460449 4.425049 44.833359 53757 51.614120 3.750221 43.102089 53758 51.434784 2.202377 44.700333 53759 2.736450 3.305412 42.493690 53760 41.897247 -0.026657 41.852013 53761 3.145416 1.351379 41.226257 53762 5.018601 -0.972565 42.345772 53763 43.676208 0.747604 43.152481 53764 42.671661 0.264984 42.432205 53765 51.618896 0.653214 43.334244 53766 9.237717 -2.870911 42.035896 53767 9.993103 -4.359573 41.820709 53768 41.142456 -2.771957 41.802086 53769 41.785034 -1.295776 42.050232 53770 42.359253 -4.164917 42.985321 53771 42.105255 -4.768402 43.083183 53772 41.712494 -4.668427 42.689201 53773 53.259979 -3.829254 42.390663 53774 9.701111 -6.193954 40.913513 53775 36.166656 -4.522430 41.922035 53776 39.162918 -4.339798 41.328156 53777 39.580139 -4.860474 42.245422 53778 40.731003 -4.802734 42.606346 53779 53.263199 -4.411285 43.132835 53780 53.903503 -6.552292 45.309364 53781 53.748474 -5.521454 44.358681 53782 53.255890 -6.542511 44.071205 53783 5.395897 -6.188522 40.721794 53784 37.012238 -4.950638 41.888603 53785 39.725571 -4.626907 43.855690 53786 4.526161 -6.983887 41.339188 53787 4.741013 -8.281219 42.600174 53788 3.242317 -7.549026 41.199059 53789 6.444000 -7.819595 41.859184 53790 7.479179 -7.210861 41.144814 53791 9.168365 -6.824478 40.943810 53792 8.371902 -7.268539 41.012421 53793 9.198395 -7.826996 41.566849 53794 9.984703 -6.679321 41.840584 53795 10.015320 -8.021545 42.757622 53796 7.953521 -8.104309 41.572258 53797 48.491760 -9.859192 41.800919 53798 46.992859 -10.288605 41.020805 53799 54.567978 -10.741226 41.921486 53800 56.467575 -10.368591 41.657860 53801 55.808105 -10.081772 41.895393 53802 4.311447 -13.545593 40.731323 53803 47.144135 -11.429413 41.412102 53804 48.024338 -11.811981 42.142860 53805 46.920319 -12.604218 41.558044 53806 52.785843 -11.525299 40.600739 53807 55.974014 -10.887222 42.193977 53808 56.763474 -11.408997 41.649460 53809 4.687630 -13.250183 41.102325 53810 47.958008 -10.853622 41.872681 53811 3.542641 -15.350845 41.404861 53812 3.223724 -16.092392 40.921806 53813 4.443695 -14.111771 41.435333 53814 56.100067 -13.691025 42.593513 53815 3.244629 -15.782791 40.043167 53816 50.276520 -16.422455 41.540733 53817 48.825607 -17.113556 41.170845 53818 3.202950 -16.741318 39.908432 53819 39.263290 -16.485718 40.625740 53820 53.079681 -13.865143 41.971870 53821 58.130798 -17.092545 42.224792 53822 58.191177 -16.549103 42.132812 53823 38.305634 -17.759918 42.862587 53824 35.442200 -17.561142 42.986664 53825 36.388229 -17.700333 42.906105 53826 40.386032 -16.969879 41.709900 53827 42.030640 -16.692398 41.890610 53828 49.685913 -17.393814 41.990074 53829 48.744522 -17.826431 41.819588 53830 4.318527 -19.520798 40.961899 53831 43.745987 -18.986771 40.718620 53832 46.488724 -19.296829 42.449608 53833 45.015808 -18.990845 41.368713 53834 4.379707 -21.113922 40.213776 53835 34.268707 -19.767960 41.058105 53836 40.827026 -19.966354 40.549454 53837 43.678070 -19.825104 41.834106 53838 56.269287 -19.050659 43.132393 53839 57.068787 -18.527206 43.544174 53840 55.091660 -19.180756 41.544296 53841 57.933884 -17.808624 42.306610 53842 34.915222 -20.243668 40.667435 53843 41.205994 -20.661957 41.767410 53844 34.764336 -20.585434 41.238403 53845 36.544388 -21.113586 41.640533 53846 50.787750 -20.882401 40.561539 53847 50.797684 -21.329910 41.670731 53848 57.359055 -22.237656 41.438194 53849 56.652267 -22.683716 42.019386 53850 58.291107 -22.119400 41.620934 53851 58.999268 -22.643600 41.969688 53852 58.677750 -22.272247 41.926437 53853 45.510193 -24.051208 41.377480 53854 46.927078 -23.584595 41.936668 53855 48.436768 -22.592621 41.580154 53856 55.574020 -23.108231 41.866570 53857 54.808533 -23.830536 42.671791 53858 43.705643 -24.183182 40.414032 53859 52.546631 -24.629974 40.771568 53860 41.362869 -26.012741 40.341522 53861 51.634857 -25.245407 40.771111 53862 58.958145 -25.504883 41.016899 53863 59.447052 -24.666245 40.839249 53864 40.268921 -26.679825 40.027824 53865 41.466309 -27.046310 41.291237 53866 42.502411 -25.854660 41.026688 53867 50.669891 -26.084717 40.799484 53868 49.447266 -27.077118 40.962875 53869 51.566193 -26.108414 41.492180 53870 52.449493 -25.382217 41.831940 53871 57.577438 -26.800735 40.726799 53872 58.365814 -26.303223 41.399094 53873 47.999115 -29.033707 42.536469 53874 47.979660 -28.300018 41.357437 53875 49.524841 -28.183319 42.257690 53876 5.441551 -28.415436 41.459251 53877 5.878388 -28.738617 40.662498 53878 38.069077 -28.509506 41.067261 53879 40.372345 -28.074310 41.364265 53880 54.991974 -28.340988 39.823303 53881 55.330780 -28.089233 40.156113 53882 32.432838 -28.745148 40.439339 53883 33.030342 -29.214905 39.611397 53884 36.614059 -28.414917 40.415848 53885 38.942688 -28.467361 40.949097 53886 55.516205 -28.643265 40.160278 53887 56.286743 -28.556046 40.458046 53888 56.639404 -27.670959 40.557465 53889 55.773483 -28.048721 40.360008 53890 5.055985 -31.012070 39.466400 53891 30.656548 -29.696442 40.684921 53892 31.037659 -29.059860 41.067627 53893 31.394463 -29.053040 40.552780 53894 30.738647 -30.539276 39.837135 53895 57.295441 -28.991165 40.705597 53896 58.208801 -30.250595 40.762260 53897 57.944672 -29.672043 40.768387 53898 3.621071 -32.305405 39.021431 53899 30.096985 -30.697968 40.436211 53900 30.210541 -31.862091 39.975891 53901 29.633888 -31.369781 40.849251 53902 46.185959 -29.698547 41.564926 53903 44.543991 -31.012741 41.041534 53904 30.207947 -30.488510 41.540146 53905 29.263474 -32.550446 40.917824 53906 31.190765 -32.754761 39.627426 53907 29.952911 -33.506866 39.950119 53908 35.246269 -32.694595 40.579781 53909 36.649155 -32.840866 40.655426 53910 39.612732 -32.837006 40.208382 53911 38.623657 -33.077881 41.132118 53912 40.533295 -33.003784 41.069275 53913 39.742294 -33.151291 41.442505 53914 58.181793 -31.027588 41.385406 53915 29.778015 -34.992889 39.809769 53916 31.142044 -34.178055 39.808388 53917 30.801537 -35.304459 39.719109 53918 32.217651 -34.244705 40.497337 53919 31.490784 -35.080978 40.074226 53920 4.014145 -34.653137 39.056046 53921 28.835648 -34.121445 40.779449 53922 30.186356 -35.877594 39.723297 53923 57.161224 -34.051865 41.502640 53924 3.631775 -33.252457 38.564964 53925 28.575195 -35.866226 40.469513 53926 29.796524 -36.604446 40.251495 53927 28.482117 -37.425674 41.051155 53928 29.512550 -35.872086 39.843719 53929 28.670181 -38.577713 42.240433 53930 27.459610 -38.740570 42.218643 53931 58.751022 -35.825348 40.143295 53932 31.025475 -36.112045 40.181725 53933 30.923950 -36.910385 40.743660 53934 3.374794 -38.865921 39.459961 53935 3.262177 -38.652908 38.813393 53936 3.849533 -39.227341 38.799561 53937 6.005829 -39.889069 39.583771 53938 9.201004 -39.672729 39.200050 53939 4.761139 -40.115479 39.982880 53940 8.218658 -39.574051 39.262009 53941 8.726760 -39.459198 39.312622 53942 8.605606 -39.431320 38.947327 53943 8.780190 -39.683823 39.925499 53944 9.576805 -40.018021 40.584038 53945 49.691345 -40.125717 39.916931 53946 57.784256 -37.744934 41.581673 53947 45.517502 -41.554626 39.601395 53948 46.424896 -41.286972 39.849686 53949 45.992081 -40.947906 39.018639 53950 52.486359 -39.744278 40.569458 53951 53.005524 -40.667572 40.292778 53952 53.254837 -40.173889 41.003807 53953 44.499283 -42.124146 39.361443 53954 52.867920 -41.910919 40.023605 53955 57.803665 -39.686951 40.634583 53956 57.405701 -40.625427 40.934319 53957 43.423157 -42.877640 39.146034 53958 42.632492 -43.402145 38.808121 53959 41.911438 -45.819382 39.880058 53960 42.702667 -44.837082 40.265289 53961 57.141998 -43.572571 39.641846 53962 12.912064 -45.232773 38.795982 53963 42.757416 -43.920685 39.334358 53964 56.475861 -43.537781 41.116753 53965 13.127136 -43.996490 39.473007 53966 41.961212 -46.277466 39.090187 53967 54.643921 -45.541824 39.138885 53968 55.537048 -44.422211 41.062981 53969 11.999596 -46.645691 38.446976 53970 11.502724 -47.527908 37.989967 53971 11.903763 -44.742371 40.173500 53972 11.676147 -45.682541 39.600151 53973 53.070038 -44.937561 39.736427 53974 55.042007 -44.854584 40.461891 53975 10.616539 -47.409042 38.581757 53976 10.723419 -46.392502 39.518517 53977 29.622055 -46.782074 40.854347 53978 30.351341 -46.774185 40.100662 53979 29.191101 -47.434540 40.017136 53980 29.997986 -48.414017 38.733841 53981 30.220108 -47.642532 39.355499 53982 42.527069 -47.598083 39.644997 53983 42.788376 -47.963669 40.408882 53984 44.264023 -48.564087 41.351883 53985 29.169502 -48.132019 39.199158 53986 42.480148 -47.133438 39.151062 53987 49.219299 -48.449646 39.255859 53988 50.804626 -48.919479 39.547440 53989 7.226891 -50.239899 38.432281 53990 6.087090 -49.677948 38.815880 53991 8.308983 -50.945221 38.396187 53992 9.146935 -51.969528 38.545235 53993 9.823013 -51.883270 38.750473 53994 52.582184 -49.302094 39.076340 53995 10.328751 -51.973648 38.930084 53996 11.128555 -51.759140 38.935272 53997 52.628525 -49.396027 40.311501 53998 53.581024 -50.082352 41.046906 53999 52.719833 -49.707275 41.616798 54000 54.521393 -50.240982 39.376869 54001 28.869507 -51.320496 38.448830 54002 12.740266 -52.659515 37.607239 54003 28.516693 -51.605957 38.829750 54004 29.335587 -52.068695 38.538483 54005 28.334106 -52.113403 39.253647 54006 45.310410 -52.596390 39.363228 54007 44.368286 -52.852676 39.134865 54008 47.319122 -52.474335 39.160973 54009 41.906631 -53.504730 38.965103 54010 41.210037 -52.925079 39.822876 54011 43.113449 -53.146606 39.079636 54012 42.126877 -52.749359 39.656075 54013 48.678955 -53.182465 38.884445 54014 6.135841 -54.961578 37.894852 54015 4.914116 -54.867645 38.212151 54016 5.033074 -56.380005 37.828163 54017 7.814193 -53.441360 38.235062 54018 6.421219 -53.395599 38.239235 54019 5.409264 -53.455139 38.349403 54020 7.298874 -55.585648 37.757111 54021 8.300217 -55.221817 37.871002 54022 11.360207 -58.617874 37.331215 54023 30.268646 -53.266281 39.743065 54024 29.336296 -53.085938 39.867561 54025 29.415039 -52.726395 39.219765 54026 43.040894 -54.571884 38.710770 54027 41.563232 -54.448685 38.614983 54028 8.254379 -57.053497 37.807938 54029 6.129738 -57.430817 37.692215 54030 7.204437 -58.976028 38.190880 54031 9.295654 -54.452438 38.229027 54032 9.108124 -55.761093 37.883301 54033 11.799149 -54.634140 37.918518 54034 53.826172 -55.533478 38.818375 54035 4.431091 -55.966080 38.516243 54036 4.430245 -57.059692 38.114769 54037 9.554840 -56.540939 37.886070 54038 10.376740 -55.426437 38.092278 54039 11.571091 -55.878448 37.721146 54040 33.152374 -56.105957 41.467812 54041 32.716492 -55.615601 40.979019 54042 33.451660 -56.033585 40.442734 54043 37.234726 -56.320648 38.515678 54044 41.488846 -57.644333 40.610733 54045 41.188263 -56.904358 39.728828 54046 43.270416 -57.354187 40.880173 54047 44.369019 -55.474594 38.786629 54048 45.857208 -57.781754 39.097282 54049 53.168167 -56.071396 39.885269 54050 4.866387 -57.577438 37.697548 54051 4.368698 -58.239410 38.139687 54052 5.056358 -58.255066 37.720695 54053 9.719376 -57.572525 38.024551 54054 8.947380 -58.653320 38.288231 54055 10.868835 -57.714706 37.806862 54056 10.716248 -56.690689 37.858246 54057 38.167892 -56.525574 38.698547 54058 5.310730 -59.096008 38.086761 54059 52.542435 -57.927551 38.241287 54060 52.339096 -57.372147 39.114899 54061 8.319855 -59.692276 38.662331 54062 7.282684 -60.477798 38.936256 54063 45.655380 -59.011566 38.036743 54064 11.006149 -59.635605 37.811264 54065 10.717224 -60.605789 38.372147 54066 10.803436 -61.732895 37.811325 54067 30.333778 -62.383362 38.053802 54068 25.873253 -62.218201 38.312553 54069 29.447701 -62.704361 39.005775 54070 30.608978 -63.037567 39.083679 54071 31.779009 -62.910583 38.445663 54072 40.417511 -62.830627 39.009148 54073 39.989197 -62.717148 38.381638 54074 33.115311 -63.288574 38.570717 54075 33.794876 -64.225876 38.191666 54076 47.704010 -61.108871 39.377419 54077 48.059708 -62.021301 39.569916 54078 18.227104 -64.706940 37.376877 54079 40.071671 -62.581650 37.822098 54080 47.533966 -63.613251 39.138023 54081 47.724289 -62.824326 38.966927 54082 46.950867 -64.090958 38.865128 54083 7.559784 -65.216660 37.089691 54084 8.333954 -64.872055 37.893654 54085 17.997574 -65.654007 37.595383 54086 17.883484 -66.445389 38.351357 54087 18.633347 -64.953552 38.159584 54088 26.438332 -64.980637 37.558510 54089 25.894661 -64.899429 38.026253 54090 45.735443 -64.484070 39.115616 54091 44.874817 -64.700378 40.132149 54092 45.747772 -64.904770 40.193497 54093 43.852203 -64.242676 39.538597 54094 46.532150 -64.104797 38.054291 54095 4.698563 -67.073059 37.453644 54096 5.441460 -66.490540 37.816322 54097 20.626312 -66.149246 37.709785 54098 28.416031 -66.876282 38.443970 54099 34.372261 -67.192795 38.292557 54100 14.256310 -67.086380 36.672516 54101 16.986679 -68.723801 37.425545 54102 39.329475 -65.713135 38.883224 54103 39.954636 -66.823883 39.665390 54104 39.437965 -65.662231 39.987030 54105 13.580994 -67.449631 37.009651 54106 16.491158 -68.789948 36.991447 54107 30.108742 -69.764496 38.430756 54108 43.321609 -68.148041 37.720657 54109 42.412781 -68.523468 38.944016 54110 41.032837 -67.666428 38.636467 54111 44.661194 -68.248276 37.125916 54112 10.895943 -69.132568 37.619362 54113 15.813942 -69.056458 37.106827 54114 15.761154 -70.040894 37.501266 54115 16.482819 -69.720444 37.421364 54116 20.816635 -67.522110 37.678345 54117 43.949524 -68.775574 38.205063 54118 45.517365 -68.724472 36.961319 54119 9.186630 -70.855957 37.834969 54120 14.826424 -69.377258 37.551117 54121 29.477730 -71.186020 37.949051 54122 30.383774 -70.901703 38.941925 54123 28.115273 -72.286560 36.929214 54124 28.507408 -71.699677 37.109406 54125 34.477486 -71.681824 37.404510 54126 34.720795 -69.153854 38.621384 54127 43.723328 -71.104584 37.710304 54128 8.557556 -72.972549 37.980545 54129 8.606812 -72.064377 37.785057 54130 40.141663 -75.079636 36.936493 54131 40.843185 -73.844269 37.345825 54132 41.551590 -72.959839 37.837608 54133 42.320175 -72.210510 38.082443 54134 6.606163 -74.681824 36.692986 54135 21.386589 -71.311554 37.410324 54136 5.656845 -74.528519 36.773788 54137 11.993118 -76.012665 35.795700 54138 24.088310 -76.225174 37.568535 54139 22.101608 -73.276749 39.303253 54140 29.258759 -75.731064 38.519684 54141 8.855667 -79.985870 36.414925 54142 12.329300 -77.100128 36.802017 54143 13.329453 -76.993729 36.960793 54144 15.343796 -78.849411 38.961853 54145 13.884933 -78.901230 38.503662 54146 14.649940 -78.070114 38.020714 54147 19.749382 -77.299881 37.172050 54148 18.890610 -77.571152 38.318939 54149 17.718750 -77.234924 37.531097 54150 24.053596 -77.001007 36.585663 54151 24.483429 -77.167419 37.162437 54152 28.936356 -74.652634 38.696579 54153 22.326141 -78.868591 37.720039 54154 35.633705 -78.645889 37.601013 54155 37.823212 -76.879669 38.005814 54156 38.130478 -75.809723 38.364189 54157 38.610565 -75.865448 37.875565 54158 20.625458 -77.733261 37.595085 54159 29.760086 -78.662521 36.791870 54160 8.593292 -80.105606 36.044701 54161 21.234894 -78.287064 38.247849 54162 20.496651 -78.034988 38.620934 54163 24.442245 -79.317215 37.132492 54164 23.606476 -79.802444 37.655350 54165 25.237503 -78.825607 38.020729 54166 25.133560 -80.504471 37.939743 54167 30.471252 -80.792587 36.892395 54168 35.028305 -79.817657 36.497528 54169 35.812614 -79.407303 36.884987 54170 17.908722 -82.542618 36.104332 54171 18.135895 -82.021759 35.985931 54172 30.234528 -83.235474 36.328072 54173 18.283447 -82.384415 36.832901 54174 21.530685 -83.966095 36.930084 54175 30.674301 -80.890884 37.524216 54176 30.176910 -82.269348 37.265572 54177 29.248688 -84.167542 36.238586 54178 29.820389 -83.566330 36.616158 54179 18.111374 -85.484879 35.916801 54180 22.270187 -84.541122 37.935516 54181 23.896049 -84.705429 38.370140 54182 26.702011 -85.073334 36.463036 54183 17.838104 -86.207596 35.832626 54184 11.192139 -85.703323 37.014725 54185 10.310539 -84.318954 37.861710 54186 12.035530 -86.962982 36.052078 54187 13.485992 -86.936417 37.047668 54188 14.367706 -86.728836 37.673958 54189 16.981865 -86.662354 36.113129 54190 16.767487 -86.435211 37.080383 54191 6.523857 51.670990 45.452103 54192 7.299477 51.870544 45.431526 54193 8.453964 52.309952 44.785339 54194 9.395004 50.293213 45.713379 54195 8.587495 51.410950 45.498451 54196 11.476151 47.772766 46.668831 54197 14.911545 47.841583 45.372749 54198 17.560005 47.817780 45.716286 54199 18.605721 46.820587 46.256874 54200 17.737465 46.614990 46.458977 54201 20.421982 46.835785 45.628105 54202 12.964752 47.225876 46.739304 54203 4.657578 45.972382 45.143745 54204 5.246880 44.266281 44.983299 54205 5.699844 43.147156 44.908768 54206 21.921463 44.721909 46.087379 54207 6.228783 42.895020 44.261620 54208 12.625084 42.173462 45.451546 54209 12.121689 42.156525 45.832092 54210 12.910065 42.798553 45.786812 54211 12.262390 41.422333 46.987518 54212 10.993951 41.451447 47.446983 54213 11.009361 42.268112 46.648865 54214 13.132004 41.759232 45.891090 54215 14.243248 41.320557 46.193199 54216 13.862762 41.313660 47.511917 54217 14.159531 41.926788 45.530273 54218 14.214584 42.820038 45.652267 54219 15.355302 42.691254 45.664680 54220 15.938599 41.815811 45.525375 54221 16.418335 42.363617 45.564507 54222 15.383034 41.442581 46.089966 54223 16.505753 41.674408 45.958275 54224 4.945862 42.587219 45.789352 54225 4.537064 41.250793 45.809357 54226 16.423721 41.408417 46.788422 54227 15.804504 41.341858 47.413750 54228 23.304291 41.010895 44.772652 54229 29.047745 39.489792 45.690651 54230 30.710701 39.057922 45.836472 54231 29.927147 39.521637 45.937164 54232 21.819099 38.820740 45.308380 54233 27.809158 38.785248 45.422562 54234 17.652176 36.942169 44.855049 54235 18.214653 37.362961 45.044075 54236 19.367325 37.593872 45.217377 54237 20.599693 38.112213 46.308769 54238 20.872421 38.218750 45.204842 54239 31.753023 38.545609 45.246689 54240 32.214478 37.735916 44.981079 54241 25.735016 36.339035 45.055939 54242 25.875824 35.414734 45.986366 54243 31.257721 36.718918 45.135567 54244 30.758347 36.097534 45.956604 54245 31.819979 37.190857 44.991432 54246 3.772606 34.365982 45.331360 54247 3.569786 33.188660 45.087105 54248 31.051071 34.656693 45.029869 54249 3.551979 32.406464 44.575989 54250 16.850891 35.048920 45.621887 54251 18.243050 34.657074 46.549469 54252 31.313110 34.394821 45.951729 54253 31.934061 33.945648 46.537422 54254 34.895508 32.179199 44.684273 54255 32.997253 33.064850 46.163246 54256 32.288284 33.327881 47.488571 54257 3.870506 31.753571 44.427727 54258 27.424660 31.879898 45.511520 54259 26.966202 32.930481 45.680908 54260 35.866470 31.649750 44.589256 54261 5.132309 30.038925 44.895844 54262 4.109940 31.053375 45.095963 54263 4.462509 30.472549 46.103134 54264 6.083489 29.350754 44.523865 54265 20.609329 31.101059 45.633179 54266 35.952362 30.084442 45.549866 54267 18.601036 28.874985 44.564835 54268 18.131561 28.383972 45.334229 54269 31.974825 28.087540 45.335144 54270 32.025665 27.377319 44.287041 54271 31.205254 27.571808 44.660400 54272 34.233490 28.454987 45.354462 54273 35.324432 29.329056 45.672890 54274 35.701530 28.180359 44.648956 54275 37.106415 27.908768 44.161003 54276 36.064857 27.375366 44.099113 54277 7.515137 27.618378 44.573845 54278 17.109840 27.119507 44.906487 54279 30.554832 28.348053 46.055458 54280 16.654572 24.402054 45.889542 54281 17.108368 26.578049 46.087601 54282 24.934952 27.587860 45.399429 54283 27.353622 28.032639 46.333061 54284 27.974701 27.658447 45.773079 54285 29.103729 27.760086 45.520988 54286 8.302803 24.916992 43.980888 54287 22.675537 24.753662 46.284485 54288 22.476440 25.082855 45.121262 54289 22.130341 24.711685 43.757584 54290 27.926712 25.960709 44.399200 54291 7.989440 24.386963 43.687859 54292 7.353104 23.869965 43.801315 54293 22.318451 23.126892 44.995537 54294 29.360550 24.691269 44.521835 54295 30.139328 24.373795 44.407349 54296 4.835533 22.025055 43.345276 54297 6.858017 23.331772 43.891518 54298 21.186432 22.773865 43.318756 54299 21.533401 23.094147 43.728226 54300 35.023773 22.149216 43.943489 54301 5.551109 22.755676 44.953606 54302 4.858566 21.650497 44.399124 54303 16.717606 22.024063 44.635033 54304 21.755432 22.428436 43.964432 54305 34.639099 23.312836 45.161926 54306 41.863800 21.907684 44.460167 54307 44.340546 21.187683 44.386276 54308 4.803612 21.672455 43.739517 54309 35.797699 22.171158 44.539429 54310 34.833199 22.498169 44.369354 54311 42.978088 21.623199 44.840317 54312 36.775269 21.544235 44.305916 54313 37.648079 21.491730 44.522629 54314 38.696228 21.417480 44.479782 54315 43.919327 20.562576 45.324509 54316 45.117844 20.030792 44.249687 54317 19.852196 18.295120 44.188293 54318 27.231651 19.887939 44.777122 54319 26.497391 20.898956 45.856445 54320 29.410927 19.983002 45.874077 54321 28.411552 19.878845 45.268417 54322 28.790054 21.155396 46.828964 54323 27.576767 18.722488 44.043655 54324 28.070602 19.300110 44.419762 54325 28.099915 18.677673 44.166092 54326 28.446869 18.796616 44.662209 54327 20.016220 19.058884 45.567421 54328 19.011658 19.056458 44.564018 54329 27.177269 17.710861 43.764175 54330 27.825714 17.573898 44.419426 54331 3.083710 16.852692 43.048195 54332 21.664391 16.107407 43.681808 54333 44.526031 17.698410 44.899361 54334 45.168121 18.655396 44.382706 54335 44.697693 18.573212 45.797729 54336 45.038559 18.478394 45.130081 54337 27.925568 16.510422 45.617508 54338 27.220131 16.020721 44.614082 54339 27.048965 16.749146 43.889755 54340 21.826271 15.249039 43.814011 54341 37.786987 16.387192 45.191231 54342 40.051849 16.107605 44.264534 54343 39.711838 16.911728 46.449104 54344 21.617142 13.679718 43.935936 54345 26.686646 14.456009 44.609444 54346 26.327667 13.377197 44.618919 54347 25.995888 13.386856 43.805191 54348 35.882401 13.941071 44.700317 54349 35.497665 13.601013 43.870338 54350 4.419296 12.406586 44.932159 54351 3.929161 13.614868 45.197098 54352 4.158501 12.762146 45.694466 54353 21.735947 12.461090 43.958229 54354 20.841637 12.377960 44.583191 54355 25.446129 12.601456 43.528038 54356 34.391045 12.715210 43.569374 54357 4.786057 12.220520 43.943939 54358 6.987740 11.499130 43.029419 54359 7.881469 11.107819 42.980698 54360 22.330124 11.654663 44.773354 54361 23.953880 11.572159 44.095062 54362 43.041199 11.110336 44.874283 54363 9.017929 10.382767 42.916039 54364 19.523888 12.433899 45.278282 54365 20.316116 13.097214 45.012665 54366 35.304337 11.514832 44.563835 54367 35.496933 12.366180 44.921043 54368 34.764679 12.218460 44.246475 54369 35.333786 10.578888 42.967583 54370 36.083878 10.559906 43.639603 54371 35.292366 10.766479 43.813408 54372 44.034119 9.812119 44.883110 54373 43.752930 9.126968 44.301376 54374 50.965942 8.118591 43.477127 54375 49.415070 7.642670 43.925110 54376 4.550049 5.918709 42.695686 54377 5.579392 6.217072 42.524872 54378 6.110764 6.897278 41.977089 54379 6.457863 6.134979 42.366425 54380 10.486603 6.269821 42.475990 54381 41.977753 7.126511 44.643265 54382 43.619263 8.440796 45.205078 54383 51.630905 7.290436 43.983215 54384 51.040924 7.707794 44.320412 54385 52.220734 7.346100 43.274574 54386 49.405533 7.195679 44.812012 54387 49.210876 6.775375 45.319397 54388 48.296265 6.389984 44.693405 54389 7.333939 5.545692 42.534309 54390 46.393707 4.620163 44.014946 54391 45.661224 4.015060 43.496567 54392 52.262741 5.598679 43.364174 54393 3.515007 3.527512 43.391602 54394 2.885971 4.401428 42.642632 54395 2.522980 4.348175 41.982307 54396 6.308945 5.416473 42.860954 54397 38.013794 5.081741 43.756119 54398 37.126579 4.265358 44.336723 54399 44.600189 2.825165 43.186218 54400 45.248413 3.188583 43.623184 54401 2.932198 1.302078 42.021996 54402 3.392120 -0.151123 43.037910 54403 35.637596 0.951721 43.057823 54404 43.140900 -0.807907 42.938362 54405 3.751724 -1.486115 43.390236 54406 52.262115 -0.770920 43.230438 54407 9.075691 -3.234650 42.920609 54408 9.487106 -3.905914 42.909988 54409 42.524918 -2.697861 42.710640 54410 53.044128 -2.323517 43.103935 54411 52.742615 -1.567505 44.113365 54412 44.081177 -1.589981 43.766403 54413 53.327637 -3.023102 43.967628 54414 53.157394 -2.223434 43.970703 54415 8.090187 -2.048599 42.397217 54416 53.768738 -4.224960 44.335785 54417 53.549301 -3.727036 44.067406 54418 10.187637 -5.542068 42.243782 54419 37.361099 -4.862396 42.679337 54420 36.723732 -3.948730 43.366730 54421 3.501877 -6.612000 40.776772 54422 35.649391 -3.914581 42.606812 54423 38.334976 -4.960266 43.153526 54424 41.447830 -4.916901 43.158615 54425 3.517319 -8.567474 42.281876 54426 51.158127 -7.077728 42.223457 54427 50.281509 -8.264313 42.085167 54428 51.284241 -9.492249 43.805473 54429 51.736023 -7.812897 43.273476 54430 52.291504 -6.561279 43.070839 54431 2.966438 -8.413513 41.658646 54432 2.447456 -8.339554 40.949623 54433 7.488693 -8.510727 42.032158 54434 8.228241 -8.905609 42.140709 54435 7.451431 -8.933655 42.646080 54436 9.489700 -9.128845 42.798859 54437 10.100838 -9.219604 43.880836 54438 3.022141 -9.522995 41.649612 54439 9.434724 -8.688416 42.106003 54440 8.845154 -8.666061 41.787262 54441 8.983246 -9.111084 42.229942 54442 49.787292 -9.642029 42.513390 54443 49.225525 -11.182327 42.852081 54444 55.274597 -10.503540 42.086418 54445 55.179611 -11.193909 42.353775 54446 48.449738 -13.329269 43.390320 54447 55.173035 -11.910599 42.545227 54448 54.587860 -13.049469 42.505409 54449 3.395477 -9.767410 42.653473 54450 3.702225 -10.518097 42.670395 54451 4.924431 -13.241867 41.466652 54452 5.104042 -13.030426 41.732269 54453 5.084656 -12.991974 42.008293 54454 56.003342 -12.399704 42.383804 54455 55.887253 -11.563019 42.427109 54456 4.910812 -13.579437 42.128357 54457 47.094208 -13.817856 42.168091 54458 54.137085 -14.644409 43.080482 54459 44.619812 -15.679993 42.019989 54460 3.919273 -14.828354 41.369637 54461 43.584885 -16.451736 42.445732 54462 47.024384 -15.040451 43.144432 54463 57.839981 -16.341583 42.477310 54464 57.099625 -16.034424 43.424789 54465 3.158577 -16.038864 41.985222 54466 3.824013 -14.894333 42.134277 54467 3.557373 -15.342209 43.106812 54468 3.007828 -16.743866 41.336273 54469 3.147019 -17.026443 40.732224 54470 45.413239 -16.158264 43.112350 54471 34.664246 -17.683655 42.770866 54472 39.215370 -17.220245 41.865425 54473 33.776642 -18.835754 41.654800 54474 33.654602 -18.236221 42.681152 54475 47.855896 -17.688538 41.165489 54476 49.534225 -18.140976 42.715202 54477 32.884094 -18.977539 42.595573 54478 33.273506 -19.691833 41.938194 54479 45.035706 -19.732910 42.421822 54480 44.179459 -20.603027 43.269562 54481 53.793762 -20.177490 43.211517 54482 55.226471 -19.716858 43.589592 54483 4.352310 -20.838165 42.399193 54484 4.673660 -22.016754 41.531097 54485 34.027695 -20.537582 42.049652 54486 32.838852 -20.317017 42.961975 54487 32.642647 -19.624207 42.551849 54488 42.465118 -20.219101 41.768555 54489 42.691284 -20.753571 42.707344 54490 52.820038 -21.325882 44.240105 54491 52.248108 -20.769455 42.521370 54492 53.512772 -19.868301 42.118973 54493 34.072006 -21.033096 43.692291 54494 35.225311 -21.095963 42.191017 54495 39.823914 -21.073807 41.883118 54496 40.549011 -21.465393 42.966835 54497 39.472084 -21.512634 42.790527 54498 49.560928 -22.213776 41.973022 54499 59.002686 -23.221130 42.519165 54500 43.796143 -25.091080 41.287857 54501 46.750000 -24.191132 42.336769 54502 53.378174 -24.588959 41.723396 54503 43.519180 -26.378708 42.329582 54504 45.885422 -24.962189 42.510208 54505 52.310654 -26.184280 42.724968 54506 52.023438 -26.152542 42.052734 54507 54.056702 -24.397232 42.556549 54508 59.246964 -24.862549 41.947861 54509 3.044716 -24.553375 41.699593 54510 2.568695 -25.512756 42.166046 54511 2.646507 -26.452942 42.094368 54512 3.115486 -27.326736 42.210762 54513 4.080567 -27.817474 41.733681 54514 42.294525 -27.984985 43.072319 54515 43.789078 -27.548065 44.088272 54516 50.763000 -26.829697 41.452019 54517 50.444794 -27.492615 41.864273 54518 51.432465 -27.012985 42.400314 54519 50.601852 -27.837158 42.434372 54520 58.268723 -27.466278 42.164925 54521 57.703827 -27.995438 41.217438 54522 58.700699 -26.061569 42.859879 54523 4.818451 -28.054428 41.542305 54524 31.750345 -28.648346 41.249222 54525 32.329758 -28.333618 41.135094 54526 32.966194 -28.315399 41.192757 54527 33.957108 -28.259491 41.371490 54528 35.863747 -28.284912 41.371536 54529 34.936386 -28.145203 41.713631 54530 58.164368 -29.350143 41.804184 54531 6.454964 -29.246567 40.326881 54532 6.525429 -29.447571 40.180756 54533 6.661011 -29.467194 40.417450 54534 39.618210 -28.752518 42.143250 54535 41.045410 -28.207077 42.183723 54536 5.964623 -30.227631 40.383011 54537 6.420769 -29.645081 40.421555 54538 5.420097 -32.282944 40.570412 54539 5.009628 -32.258209 40.059700 54540 5.616760 -31.182465 41.143776 54541 4.160881 -31.868134 39.371674 54542 4.105522 -32.591644 39.479736 54543 4.612747 -32.233765 39.778610 54544 44.005676 -31.886383 41.910919 54545 45.409698 -30.812729 42.156120 54546 44.880676 -31.377426 42.311310 54547 4.785004 -33.271927 39.969841 54548 4.070999 -36.043182 39.496307 54549 29.535362 -31.667755 41.836273 54550 29.067734 -32.641953 42.016190 54551 33.687576 -32.973236 40.579002 54552 33.048798 -33.554001 40.829399 54553 33.916138 -33.303131 41.262665 54554 34.410362 -33.799850 42.182358 54555 36.452087 -33.078339 42.002014 54556 37.774918 -33.177841 41.015549 54557 37.202690 -33.108627 41.101532 54558 41.529388 -32.660583 40.945625 54559 42.736481 -32.499878 42.555847 54560 4.943161 -35.369431 40.158897 54561 4.843453 -34.390823 39.993042 54562 28.696419 -33.290787 41.610306 54563 31.961405 -35.336197 40.752945 54564 57.182709 -35.169266 41.678528 54565 3.561051 -36.652908 39.207207 54566 5.406372 -36.231476 40.637726 54567 4.752937 -36.392014 40.179886 54568 27.342598 -35.474258 42.417168 54569 27.814636 -34.973129 42.745506 54570 27.913086 -35.101471 41.657425 54571 4.020455 -37.174225 39.907921 54572 3.572182 -38.187134 39.875252 54573 28.026138 -36.678360 40.629395 54574 27.125961 -37.651199 41.369797 54575 27.509232 -36.603302 41.069374 54576 31.637056 -36.366104 40.910255 54577 57.702179 -36.828262 41.769798 54578 48.384186 -37.634277 42.724098 54579 49.103012 -37.285156 41.979668 54580 49.072113 -38.865997 41.750351 54581 50.323257 -39.037598 40.658958 54582 50.692001 -38.541306 41.131592 54583 57.620041 -38.859192 41.571747 54584 6.989838 -40.282364 40.820755 54585 6.889526 -40.794952 42.150772 54586 8.003326 -40.585419 41.898285 54587 8.082520 -39.953461 40.489265 54588 8.823158 -39.916183 40.652985 54589 49.928223 -38.708969 41.089684 54590 49.703827 -39.421310 40.662003 54591 51.762558 -38.737091 41.250671 54592 53.165634 -39.057800 41.942856 54593 4.279038 -40.190109 40.104431 54594 3.927078 -39.692047 39.961250 54595 12.012215 -40.824677 40.177124 54596 12.960800 -41.798599 39.681740 54597 47.157990 -41.834351 40.550262 54598 48.216949 -41.036163 40.540840 54599 49.003143 -40.120148 40.651909 54600 48.794571 -40.497009 41.620995 54601 53.506927 -41.184769 40.760391 54602 57.259781 -39.663773 41.798538 54603 11.275864 -40.262146 40.467522 54604 13.365601 -42.427521 39.694221 54605 44.377853 -43.466248 40.287659 54606 46.149109 -41.913910 40.181328 54607 46.121094 -42.727814 40.624756 54608 45.351532 -42.365311 40.032211 54609 54.001968 -40.769211 41.683029 54610 54.192383 -42.134293 41.297020 54611 57.129852 -41.499390 41.231293 54612 13.453476 -43.133636 39.161217 54613 37.851807 -42.585953 40.609550 54614 38.563019 -42.779083 40.784027 54615 37.713409 -43.117447 40.416626 54616 54.036194 -43.601761 41.005112 54617 53.203033 -43.107712 40.531723 54618 53.587463 -42.284012 40.663345 54619 57.180862 -42.509644 40.641243 54620 37.042450 -42.862244 40.910713 54621 37.023453 -43.980621 40.352631 54622 38.077126 -43.817520 40.489227 54623 56.537842 -42.165985 42.060448 54624 37.603470 -44.874130 40.324249 54625 38.537224 -44.668488 41.040642 54626 38.166092 -45.572342 40.882339 54627 52.642609 -43.275665 40.105667 54628 35.474770 -44.497589 41.129486 54629 36.410110 -45.221329 40.209778 54630 35.431175 -45.708344 40.253906 54631 37.230827 -46.063995 40.438370 54632 36.079132 -46.474243 40.262482 54633 54.055573 -44.809479 40.341003 54634 53.120728 -44.099640 40.360268 54635 12.696381 -44.490570 39.870628 54636 31.183746 -46.456192 40.228432 54637 31.301804 -47.193146 39.757454 54638 31.944071 -46.603973 40.224136 54639 34.966537 -46.642120 40.293472 54640 34.421570 -45.751419 40.645401 54641 33.908569 -46.668060 40.404564 54642 42.008728 -46.974182 39.879562 54643 42.192047 -46.162796 40.644928 54644 8.501060 -47.198288 39.724586 54645 9.772011 -47.119019 39.330673 54646 28.560760 -48.165268 39.719711 54647 32.767639 -48.913681 40.703476 54648 32.371841 -49.696487 39.721298 54649 32.761581 -47.478287 40.265129 54650 34.238449 -47.379318 40.523796 54651 42.233368 -47.611115 40.089661 54652 42.211792 -47.322433 40.634857 54653 45.586609 -48.054749 40.481895 54654 47.088165 -48.074036 40.409599 54655 4.408081 -48.438477 39.979973 54656 4.310089 -48.876465 39.482979 54657 5.194534 -48.544189 39.555527 54658 3.812866 -49.142288 39.978279 54659 46.186584 -48.596420 41.813492 54660 48.988815 -48.359741 40.168709 54661 50.310730 -48.819275 41.344955 54662 49.365662 -48.822495 42.544556 54663 48.663162 -48.386261 41.399139 54664 27.649200 -50.003540 39.870735 54665 4.463608 -50.820084 38.943558 54666 4.364815 -49.541214 39.213570 54667 3.557999 -50.117737 39.663170 54668 3.331528 -51.973221 39.787407 54669 4.571365 -52.226318 38.779846 54670 6.336182 -51.665085 38.489555 54671 11.786621 -51.758316 38.859665 54672 12.242188 -52.057617 38.483627 54673 54.323502 -50.478546 40.372208 54674 32.851959 -49.816711 40.891701 54675 32.965546 -49.521591 41.507736 54676 33.349861 -50.380646 41.767387 54677 34.345688 -51.539398 39.668205 54678 35.154442 -52.077469 39.768036 54679 55.043640 -51.576553 39.696167 54680 9.727432 -52.864410 38.657257 54681 11.851547 -53.147156 38.491913 54682 35.884575 -52.322769 39.493317 54683 39.878441 -53.228561 39.730339 54684 40.492340 -53.053589 39.858383 54685 42.831039 -52.553467 39.987518 54686 45.650085 -52.605026 40.366913 54687 46.646881 -52.828568 40.888428 54688 47.577911 -52.627396 39.700279 54689 54.620667 -52.585144 40.016998 54690 10.698929 -53.859253 38.491623 54691 10.913467 -52.658310 38.938599 54692 11.642899 -52.311874 38.956741 54693 27.334976 -52.178864 40.220398 54694 28.318542 -52.853333 39.929291 54695 31.333252 -53.971786 40.172745 54696 30.523170 -53.730438 40.699959 54697 37.469200 -53.462326 41.182907 54698 43.670868 -52.568115 39.860764 54699 48.690201 -53.272232 39.903053 54700 49.743500 -54.486664 40.171768 54701 54.603729 -51.375015 40.533791 54702 54.120697 -52.187378 41.576469 54703 4.212410 -53.601089 38.928429 54704 4.300972 -54.872635 38.867142 54705 31.969332 -54.715744 41.151268 54706 50.422852 -55.592804 39.593010 54707 54.087265 -53.383194 40.848640 54708 41.589020 -55.360321 38.757851 54709 53.596405 -54.633438 40.844063 54710 41.667130 -56.124023 39.214516 54711 42.695435 -56.423767 39.750259 54712 42.946777 -55.719925 39.190819 54713 44.101242 -56.317657 39.598885 54714 45.219696 -57.207504 40.161850 54715 10.344116 -58.783798 38.203636 54716 36.398865 -57.293884 40.134079 54717 37.531387 -57.053986 39.301010 54718 35.212479 -57.000687 40.457069 54719 38.539589 -56.926346 39.048370 54720 39.426521 -57.084518 39.335426 54721 4.166977 -57.317978 39.113747 54722 3.879822 -58.665222 40.224022 54723 3.714806 -58.775818 39.211334 54724 38.528687 -57.415878 39.570595 54725 39.742165 -57.805679 40.319504 54726 46.805511 -58.549591 40.910484 54727 3.843094 -58.437576 38.709724 54728 4.071236 -59.256760 38.602463 54729 4.737213 -60.100357 38.564056 54730 5.970604 -60.245667 38.525406 54731 8.383018 -60.579468 39.269981 54732 9.030304 -61.022507 39.659035 54733 9.651451 -59.950821 38.921234 54734 10.586227 -59.686340 38.500389 54735 52.244720 -56.873932 40.025848 54736 5.003769 -60.827377 38.949387 54737 6.117806 -61.252029 39.209511 54738 4.030296 -60.131592 39.380417 54739 7.567085 -61.999039 40.035896 54740 9.302383 -62.088348 39.879417 54741 10.488327 -62.039917 38.821442 54742 26.789902 -61.515427 38.964104 54743 28.302689 -62.353058 39.367508 54744 27.201111 -61.835754 39.822899 54745 10.817291 -62.199158 38.243866 54746 25.237167 -62.452255 38.939560 54747 25.505066 -62.008179 38.913239 54748 26.040878 -61.738754 38.919563 54749 48.272079 -61.183609 40.243683 54750 47.718628 -60.166718 40.008919 54751 33.763504 -63.522690 39.052216 54752 25.536903 -65.142227 38.773376 54753 34.217705 -64.024521 39.257866 54754 39.357819 -64.306931 39.665825 54755 42.276672 -63.518143 39.748489 54756 19.436722 -64.749298 38.445068 54757 18.218201 -66.055679 39.269897 54758 19.019897 -65.311813 39.088608 54759 20.045273 -64.640839 38.084763 54760 25.006142 -64.756958 39.646576 54761 4.763657 -67.431763 38.804100 54762 26.238800 -65.528198 38.262863 54763 34.491692 -64.967636 38.929337 54764 34.674660 -66.159363 39.073410 54765 13.679710 -68.450623 37.633942 54766 17.359192 -68.326279 38.398949 54767 34.784973 -67.803314 39.519386 54768 11.157738 -70.028580 39.064293 54769 12.202332 -69.857651 38.993546 54770 12.047089 -69.147476 38.442093 54771 34.535812 -68.071564 38.563538 54772 4.499336 -69.196945 37.753250 54773 4.472237 -68.314026 37.667610 54774 12.724472 -68.615860 38.010460 54775 13.396935 -69.909027 38.339073 54776 12.068634 -70.968018 39.420303 54777 13.761436 -72.107452 39.012161 54778 29.876846 -69.058929 39.603203 54779 43.505722 -69.559479 38.899734 54780 15.024002 -70.915604 37.959000 54781 16.140961 -70.898346 37.799240 54782 16.895477 -70.427155 38.265930 54783 4.517647 -71.807343 39.161591 54784 4.608658 -72.114929 37.622490 54785 4.495606 -70.335541 39.248512 54786 4.456184 -70.378403 40.514503 54787 8.936203 -71.329193 37.635979 54788 16.133568 -72.005676 38.387756 54789 15.676407 -71.589371 37.989609 54790 15.162178 -72.033371 38.400688 54791 17.330170 -70.500458 39.847816 54792 30.603271 -70.243103 39.327171 54793 8.726845 -71.712479 37.733353 54794 28.760422 -72.764618 38.078766 54795 30.208084 -72.154221 39.459892 54796 43.002930 -71.494766 38.352242 54797 42.344543 -71.380081 39.458405 54798 16.490608 -72.898895 39.034691 54799 16.983940 -72.945190 39.402649 54800 17.115829 -71.972580 39.207397 54801 20.953903 -70.430756 39.053696 54802 21.156410 -71.291428 39.787056 54803 8.016769 -74.505310 37.991928 54804 9.055847 -74.049667 38.805733 54805 38.554947 -73.805481 38.557663 54806 38.498100 -73.006836 39.288826 54807 39.480927 -74.166656 38.146271 54808 40.737961 -73.244934 38.306511 54809 40.201035 -72.834854 39.359970 54810 41.085159 -72.787842 38.751961 54811 41.438370 -72.286102 39.413223 54812 7.182480 -74.895523 37.537086 54813 8.654312 -75.308517 38.798195 54814 28.582703 -73.933411 38.257248 54815 38.269455 -74.723114 38.485794 54816 38.005280 -73.705322 38.763237 54817 39.292137 -75.994827 37.104553 54818 6.026749 -75.152679 38.127571 54819 5.052460 -73.864548 37.449883 54820 5.143654 -74.616440 39.526955 54821 5.584473 -75.530899 39.264984 54822 5.948959 -76.011566 39.272018 54823 6.601997 -76.217224 38.894630 54824 35.652328 -75.632584 38.925797 54825 19.910172 -77.690872 38.292168 54826 24.846626 -77.504623 37.963333 54827 29.691681 -74.801025 39.557968 54828 10.467926 -78.690994 36.988121 54829 13.422493 -77.795471 37.479515 54830 35.651611 -77.750732 38.422607 54831 35.836922 -78.081329 38.102089 54832 36.324936 -77.592133 38.491547 54833 30.290161 -78.664948 37.857635 54834 30.670303 -79.846725 37.841919 54835 9.056786 -80.973953 36.928772 54836 9.650101 -79.896729 37.229362 54837 25.680466 -81.981567 38.025589 54838 26.086304 -81.517242 38.019325 54839 26.738770 -82.445389 38.275513 54840 9.638992 -82.483002 38.511139 54841 9.941910 -83.382202 38.422050 54842 26.822311 -81.620819 38.363083 54843 25.387917 -81.496979 37.923027 54844 30.745590 -80.766617 38.343170 54845 18.423523 -82.652145 37.996712 54846 18.946960 -82.537445 37.431854 54847 17.973404 -83.052307 37.894691 54848 19.381195 -83.114273 38.442078 54849 24.796585 -81.817398 38.606209 54850 23.855507 -80.761963 38.604782 54851 20.523003 -83.524826 37.422577 54852 29.768494 -81.647552 39.294601 54853 29.639084 -81.188522 40.757484 54854 30.466408 -80.806000 40.568733 54855 28.887260 -83.722137 37.197815 54856 27.348541 -84.311432 37.399055 54857 27.803268 -83.329666 38.005585 54858 29.042946 -82.832443 38.119820 54859 17.659698 -84.211319 38.769585 54860 17.609833 -85.452805 36.902710 54861 22.270454 -84.524139 38.995811 54862 16.636002 -85.741501 39.045273 54863 17.153610 -85.211929 39.001236 54864 16.987076 -85.733063 38.147110 54865 24.835831 -85.266602 37.194176 54866 25.791534 -84.700607 37.775215 54867 12.592491 -86.567184 37.110542 54868 12.518646 -85.594742 38.565643 54869 15.437318 -86.674408 37.856277 54870 16.187836 -86.558151 37.648399 54871 6.579781 50.766235 45.933571 54872 7.359100 51.112274 46.141060 54873 7.536118 50.550430 46.508926 54874 8.116364 50.875977 46.127136 54875 8.576401 49.529770 46.964577 54876 14.968246 47.161865 46.386269 54877 16.621155 46.967010 46.372154 54878 19.785492 46.167633 46.203056 54879 4.708191 44.676575 46.409714 54880 20.566483 45.052673 46.368721 54881 21.161758 43.679184 47.209984 54882 19.643280 44.291229 46.643005 54883 15.809525 44.157410 46.344025 54884 14.511070 44.327316 46.599297 54885 17.557343 44.217438 46.220390 54886 17.298126 45.630554 46.571350 54887 18.612381 45.308090 46.486443 54888 16.599373 44.799057 46.461189 54889 19.640778 45.214203 46.491882 54890 4.515762 44.448242 47.931671 54891 4.528732 43.190430 47.540962 54892 11.526215 43.491257 46.542351 54893 11.536514 42.795746 46.102753 54894 10.826370 43.056381 46.648758 54895 17.283737 42.669113 46.007645 54896 16.567299 43.529388 45.936249 54897 18.461975 43.565643 46.451836 54898 4.217362 41.199463 47.107109 54899 15.709641 45.120651 46.781235 54900 9.536133 41.951126 48.337341 54901 8.675049 40.035919 48.787033 54902 7.251381 41.099854 49.417107 54903 17.968567 42.414642 46.919090 54904 17.092888 41.820221 46.600395 54905 4.220940 40.428543 45.830391 54906 13.070236 41.216400 48.599220 54907 21.616425 38.739853 46.175514 54908 22.525497 39.484344 46.135017 54909 23.083931 40.412292 47.242096 54910 22.604172 39.850861 48.089546 54911 22.892639 40.840469 48.210823 54912 27.225342 37.835571 46.351486 54913 17.817352 37.096512 45.629051 54914 18.333168 37.375290 45.672966 54915 19.710037 37.575150 46.719986 54916 18.424622 36.808990 46.533241 54917 26.312752 36.604782 46.598473 54918 30.987991 37.667191 46.049904 54919 16.698456 35.539993 45.627144 54920 25.642990 34.709946 45.231300 54921 17.475937 34.569611 45.668503 54922 26.228424 34.149796 45.886444 54923 30.862061 35.100586 46.218140 54924 3.196907 32.584976 45.046288 54925 3.197609 32.641083 45.373901 54926 3.051384 32.454193 45.255981 54927 34.210617 31.978455 46.088608 54928 3.198494 32.274689 45.125221 54929 3.518211 31.873383 45.272781 54930 31.433380 32.878174 48.829323 54931 31.606218 33.971527 47.799026 54932 35.484421 31.085693 45.645065 54933 34.853256 30.699707 46.519432 54934 19.824524 30.180847 45.530807 54935 26.714310 29.996613 45.805565 54936 26.268661 29.347412 45.784447 54937 27.484039 31.114349 45.780357 54938 5.729775 29.109177 45.583298 54939 6.517853 28.419647 45.243317 54940 5.974762 28.419037 46.403244 54941 6.438530 27.516449 46.037971 54942 35.415092 30.176483 46.076172 54943 6.904419 27.617325 45.447990 54944 17.443726 27.590439 45.413132 54945 28.128098 26.762909 44.753426 54946 32.948715 28.451416 45.686035 54947 25.710213 27.144470 46.007729 54948 7.412415 24.477585 44.577873 54949 27.857056 24.925247 45.355888 54950 6.650711 23.609253 44.577118 54951 17.007141 25.656799 47.200325 54952 28.558105 24.891830 45.431412 54953 28.504822 25.299835 46.576294 54954 29.955223 24.894272 45.804077 54955 32.117889 24.507339 45.926910 54956 33.079178 24.130051 45.661194 54957 32.779388 25.173645 47.233826 54958 35.989731 22.989731 45.555176 54959 35.725418 23.996475 46.381042 54960 23.353134 22.828979 46.330132 54961 23.606537 21.924896 45.391792 54962 34.096687 25.815933 48.780640 54963 33.063843 26.000122 49.067001 54964 4.059036 19.894135 44.266342 54965 3.577492 19.720886 43.642578 54966 4.518051 20.799057 44.673424 54967 17.126945 20.934723 44.406906 54968 24.601074 21.353394 45.328995 54969 36.923203 22.223587 45.282860 54970 38.465721 22.297226 46.090561 54971 37.556610 23.580673 47.377098 54972 36.856201 23.245529 46.264595 54973 39.845848 21.586929 45.163681 54974 41.330383 21.572159 45.679993 54975 40.084442 21.826385 46.386253 54976 41.229401 21.359543 47.255928 54977 42.576889 20.931030 46.293167 54978 18.248199 20.337326 46.211563 54979 17.457748 20.881058 45.946274 54980 43.774506 19.662094 46.527458 54981 44.820297 19.338730 45.270309 54982 3.954758 18.655258 43.980965 54983 25.401413 21.339752 45.866531 54984 28.946930 19.154068 45.225380 54985 29.338791 19.141159 45.640526 54986 4.624252 19.853088 44.885170 54987 4.383011 19.265854 44.566490 54988 5.258202 18.860855 44.832138 54989 6.501396 18.671692 45.362419 54990 6.200508 17.828400 45.010933 54991 4.722092 17.856964 44.198738 54992 5.478317 17.710693 44.544815 54993 20.966995 18.105774 44.946320 54994 22.171387 17.162933 45.275337 54995 28.736168 18.101501 45.669151 54996 29.934059 19.431198 46.572212 54997 3.783592 17.073090 43.690613 54998 4.872322 16.921097 44.375267 54999 4.192108 15.937775 44.315216 55000 5.734535 16.933685 45.167061 55001 3.399666 14.097687 43.659477 55002 3.568932 14.183563 44.216553 55003 36.633926 15.674683 45.041313 55004 43.077133 17.378677 46.501328 55005 43.977081 17.498840 45.942596 55006 3.898987 14.865341 44.727737 55007 22.009926 16.188507 44.614464 55008 22.069336 15.349197 45.698341 55009 22.433670 16.262878 45.364311 55010 36.339783 15.115082 45.107986 55011 38.477280 17.119110 46.208733 55012 41.033463 16.623215 45.410522 55013 42.161743 16.743134 45.357681 55014 36.282715 13.291504 45.632835 55015 36.201508 14.466202 45.464310 55016 20.870453 13.271042 44.633163 55017 35.276367 13.042236 44.438324 55018 39.403168 11.836426 44.977760 55019 38.585464 11.385345 44.430191 55020 40.479248 12.297241 45.856888 55021 43.135208 11.988739 46.023041 55022 41.868927 11.975082 45.521591 55023 7.034012 11.194168 43.849846 55024 8.256409 10.544220 44.029945 55025 9.280106 9.380615 44.091530 55026 36.434608 10.874054 44.488800 55027 36.997879 11.351959 45.003677 55028 37.926811 11.798004 45.293320 55029 37.068558 11.778976 45.491257 55030 35.937744 10.584534 44.206230 55031 10.148590 8.363861 43.169891 55032 9.354080 7.613846 44.740524 55033 41.378754 6.460220 43.975273 55034 50.319305 7.604202 44.529144 55035 51.113892 6.967087 44.636497 55036 10.484947 6.363190 43.007698 55037 50.071335 6.734879 45.392952 55038 51.054001 5.766136 45.238495 55039 5.561501 4.936798 43.269241 55040 8.496078 5.242569 43.004181 55041 10.216789 6.629013 43.719238 55042 10.096939 6.028107 43.556206 55043 37.489441 5.438354 45.169640 55044 37.083084 4.643036 45.774696 55045 39.213974 5.891869 44.291206 55046 38.246544 5.923325 44.858070 55047 40.655411 6.336365 44.411690 55048 39.898285 6.535614 45.296501 55049 47.190704 4.837097 44.968269 55050 48.426697 4.654968 46.317970 55051 46.888504 5.500854 43.813148 55052 4.541153 4.383148 43.526375 55053 7.019898 4.546753 43.567276 55054 8.195900 4.791565 43.963799 55055 9.297646 5.596558 43.920525 55056 8.191619 5.560608 45.068527 55057 7.794372 4.517487 44.542809 55058 5.805191 4.020042 44.547218 55059 7.676742 4.322525 44.021484 55060 7.350250 4.194519 44.359238 55061 44.644089 1.832306 43.609879 55062 46.247345 3.704163 44.504517 55063 47.691299 2.635818 46.378151 55064 46.617828 0.589966 45.514778 55065 46.594894 2.647949 45.303223 55066 3.065537 1.732880 43.444389 55067 4.497284 3.427963 44.465584 55068 3.274223 1.531067 45.097412 55069 3.724930 2.618439 44.670860 55070 37.309021 3.283859 44.956703 55071 45.740799 2.180389 44.444901 55072 45.109314 0.321487 44.270737 55073 45.359558 -1.233246 44.765015 55074 51.702484 0.128830 45.300987 55075 51.027435 1.015030 46.216072 55076 51.074310 2.002090 46.130310 55077 50.889832 2.660782 46.323547 55078 2.986565 -0.131775 45.122177 55079 3.086517 -1.232803 44.182137 55080 36.785484 0.945251 43.846397 55081 35.252762 -0.823608 43.365700 55082 36.230110 -0.112503 43.702911 55083 36.295563 -1.308395 43.994751 55084 37.193176 -0.270554 44.224457 55085 37.433067 0.778656 44.234581 55086 38.232864 0.540665 44.697418 55087 52.129379 0.074707 44.262726 55088 44.642136 -3.216446 44.454445 55089 44.194138 0.116165 43.574074 55090 52.487320 -0.804382 44.134270 55091 4.355057 -2.071609 43.321297 55092 5.028893 -2.212769 43.060638 55093 5.825050 -2.717117 43.383774 55094 7.407837 -2.615891 43.059044 55095 8.438057 -3.007767 43.045952 55096 34.256493 -2.437561 42.652496 55097 35.583405 -2.004074 43.698700 55098 35.386490 -3.013885 43.134064 55099 43.337982 -3.650925 43.720604 55100 7.803756 -4.282684 44.439438 55101 9.393753 -4.895950 43.859947 55102 8.893631 -3.752594 43.480034 55103 34.808167 -1.903885 43.220108 55104 9.900162 -4.994431 42.893791 55105 36.443451 -2.681656 44.011093 55106 45.899689 -2.418137 45.065567 55107 45.725876 -3.571838 44.833138 55108 37.271851 -3.232758 44.391327 55109 37.032089 -2.723068 44.483170 55110 42.115036 -4.675766 43.873154 55111 43.502197 -4.734894 45.075447 55112 53.859711 -4.792755 44.284760 55113 10.103539 -6.294434 44.797165 55114 10.383957 -6.489075 45.883873 55115 10.791550 -7.399490 45.485909 55116 52.454361 -7.931442 44.034691 55117 53.438019 -7.798187 45.282410 55118 52.719696 -9.104568 45.312714 55119 3.392922 -9.289963 42.851608 55120 3.954994 -8.868668 43.425896 55121 3.484345 -9.383652 43.736855 55122 8.504028 -9.445770 42.884972 55123 9.221390 -9.696884 43.418961 55124 4.085121 -11.361053 43.000328 55125 50.245117 -10.473785 43.259468 55126 4.366264 -11.910965 42.921890 55127 4.851517 -13.045471 42.447212 55128 50.491028 -11.423264 43.989876 55129 49.848663 -12.629852 44.124748 55130 55.238037 -14.373871 43.156670 55131 56.209671 -15.025269 43.324425 55132 49.654373 -13.740524 45.452873 55133 46.754303 -15.908981 43.650764 55134 47.613098 -15.770828 44.594498 55135 4.371582 -14.252884 42.385460 55136 53.172333 -14.748932 42.564354 55137 53.266159 -15.481155 43.122925 55138 54.149719 -15.620056 43.968376 55139 53.499344 -16.181534 44.185234 55140 55.191010 -15.439301 44.141716 55141 3.325646 -17.694748 41.540344 55142 3.183045 -16.381271 42.958206 55143 3.296234 -17.378036 43.599991 55144 52.277618 -16.374557 43.133041 55145 50.989288 -17.231781 42.919228 55146 57.239166 -16.843704 44.172920 55147 56.935715 -16.318573 44.318001 55148 34.152817 -17.923004 43.650452 55149 37.264084 -17.760132 42.890068 55150 39.695374 -17.721497 42.848404 55151 41.020142 -17.613235 42.956512 55152 42.587341 -17.552734 43.477730 55153 44.390472 -18.101654 45.202698 55154 44.444305 -18.473846 46.061165 55155 45.281143 -18.068741 46.028557 55156 52.344208 -17.167206 44.366203 55157 51.131317 -17.936783 43.910957 55158 57.566223 -17.412766 43.152908 55159 47.847992 -18.412643 41.987808 55160 57.206421 -17.980865 44.694351 55161 32.960823 -18.504333 43.870544 55162 32.179489 -19.506424 43.482704 55163 48.242554 -19.097229 43.135010 55164 47.054291 -20.097122 43.898613 55165 45.661682 -20.368500 43.524353 55166 49.752350 -18.754593 43.672462 55167 43.125275 -21.221802 43.760101 55168 51.388214 -22.481033 44.382278 55169 54.444839 -20.261246 44.240608 55170 55.209534 -20.278412 45.086945 55171 56.473129 -19.277252 44.718819 55172 4.816559 -22.108597 42.712349 55173 4.808235 -22.551132 42.087624 55174 35.950294 -21.453827 42.498344 55175 37.195847 -21.522232 42.721588 55176 36.438232 -21.549927 42.825645 55177 38.332748 -21.615204 43.559311 55178 41.581146 -21.246582 43.034134 55179 42.593048 -21.827148 44.664307 55180 42.260925 -21.433319 43.672409 55181 9.532852 -22.438248 43.681343 55182 9.602600 -20.987488 43.525276 55183 10.765938 -21.926697 42.802132 55184 11.582283 -22.997101 42.213524 55185 12.091461 -22.099930 42.574554 55186 12.324165 -22.805313 42.299545 55187 11.773392 -20.967560 42.866783 55188 12.975143 -22.671890 43.177032 55189 41.408966 -21.848465 44.331100 55190 40.064087 -21.924408 44.439476 55191 50.763565 -21.900879 42.753151 55192 57.955399 -22.728821 42.652657 55193 56.428253 -23.087280 42.950775 55194 3.872360 -23.476059 41.733696 55195 4.497627 -22.838165 41.725868 55196 12.498001 -23.542068 42.318001 55197 11.694107 -24.383087 42.147072 55198 10.505661 -23.385086 42.814034 55199 48.147873 -23.397324 42.516136 55200 57.062881 -23.260681 44.039734 55201 57.922195 -23.264404 43.880074 55202 57.565125 -23.429443 44.453163 55203 58.574173 -23.446472 43.366135 55204 11.378540 -25.670563 42.119667 55205 10.459099 -24.609467 42.793640 55206 13.095268 -24.632584 42.580681 55207 55.567596 -23.516922 43.034485 55208 59.056122 -24.179321 42.902176 55209 12.721359 -25.670761 41.954475 55210 12.296677 -26.406052 41.956772 55211 44.839310 -25.318832 42.159889 55212 53.293304 -25.498520 43.397621 55213 59.067657 -25.062607 42.836334 55214 12.876358 -26.495926 41.947861 55215 13.294113 -26.382339 42.173538 55216 13.609406 -25.694412 42.583611 55217 48.085785 -25.185501 44.697334 55218 48.693451 -25.155792 45.412621 55219 49.110413 -24.666336 44.895767 55220 45.167847 -26.155548 43.330246 55221 47.002502 -25.060379 43.482903 55222 58.737625 -25.089081 43.577568 55223 11.612274 -26.665604 42.328461 55224 12.847000 -27.280319 42.644821 55225 13.549866 -29.597061 43.691956 55226 12.570961 -28.709915 43.433968 55227 14.020752 -28.556778 43.602356 55228 58.392593 -26.677292 44.244537 55229 58.357239 -25.837967 44.422127 55230 5.913185 -28.929321 41.376297 55231 33.102936 -28.472961 42.322693 55232 34.199890 -28.194199 42.499481 55233 35.029434 -28.191025 42.664047 55234 35.736618 -28.238251 42.257790 55235 6.451622 -29.373047 40.649178 55236 6.050377 -29.693436 41.169601 55237 32.371864 -28.322617 41.665527 55238 36.898315 -28.551697 42.211693 55239 49.243881 -28.727280 43.338921 55240 31.195992 -29.333984 41.794601 55241 30.405212 -31.259705 42.895981 55242 31.208572 -30.151947 42.732101 55243 47.099945 -29.806610 43.176079 55244 57.969635 -30.723114 42.509758 55245 5.467781 -32.411926 41.446877 55246 57.345947 -31.951050 42.203827 55247 5.282135 -34.235092 40.955185 55248 5.437111 -33.153961 41.020226 55249 41.774719 -32.816467 41.985802 55250 41.512390 -32.912613 43.762978 55251 41.543930 -32.868637 42.610878 55252 56.561615 -33.177261 41.913445 55253 57.081573 -31.246094 43.771828 55254 33.184814 -34.933960 42.234894 55255 32.994247 -34.331909 41.424423 55256 37.674423 -33.125961 41.779167 55257 38.324333 -32.975296 43.067932 55258 40.513275 -33.078827 42.732071 55259 39.389084 -33.117371 42.466827 55260 41.216400 -32.991028 41.872536 55261 52.794373 -34.189499 42.404121 55262 51.966827 -33.953430 42.472008 55263 53.131073 -33.278687 43.641472 55264 51.225220 -33.684479 42.997147 55265 53.704559 -33.831726 42.573860 55266 53.592712 -35.092133 42.318596 55267 54.552109 -33.969467 42.270592 55268 54.511627 -33.181091 42.881462 55269 55.407059 -33.414459 42.276947 55270 55.892242 -32.506882 42.930817 55271 55.620193 -34.762299 42.086357 55272 5.343079 -35.652496 41.288910 55273 50.137207 -34.312317 42.620941 55274 49.180466 -35.073334 42.455994 55275 49.126709 -34.246994 43.375793 55276 50.606781 -35.404419 42.077705 55277 49.199066 -36.134415 42.149391 55278 51.090057 -34.322342 42.253830 55279 51.796051 -34.618729 42.188965 55280 51.530869 -36.479446 42.196419 55281 50.234741 -36.821854 41.863678 55282 52.525818 -34.922455 42.287903 55283 5.671936 -36.184570 40.942451 55284 26.953934 -36.063446 41.946541 55285 26.836472 -35.814133 42.753380 55286 32.432823 -35.715881 41.694321 55287 48.378967 -35.741959 42.907860 55288 52.467773 -35.658188 42.357376 55289 57.460495 -36.157791 41.790443 55290 4.883545 -37.041016 40.539299 55291 5.415993 -36.593704 40.994278 55292 31.597107 -36.859451 41.669296 55293 32.992561 -36.102737 43.259911 55294 30.912262 -37.664703 42.433838 55295 49.991058 -37.954483 41.521439 55296 56.311829 -36.219376 42.410469 55297 4.186592 -38.033752 40.597939 55298 4.891228 -37.340469 41.092834 55299 26.565811 -37.011765 41.708603 55300 26.369926 -37.956375 41.878868 55301 30.233902 -37.469147 41.291260 55302 48.418488 -36.695602 42.634880 55303 52.289185 -37.656311 42.291176 55304 3.673157 -38.905624 40.169456 55305 3.982880 -39.191635 40.961128 55306 26.324982 -39.427124 42.806213 55307 25.287575 -39.844238 43.131798 55308 25.433067 -38.909973 42.688568 55309 48.720078 -38.476486 43.125526 55310 51.058105 -37.714584 41.686241 55311 4.246613 -40.134689 40.681755 55312 10.603532 -40.242508 40.840164 55313 12.588303 -41.541733 40.434387 55314 38.864227 -39.574066 42.470741 55315 38.660889 -39.241470 43.341415 55316 39.317062 -38.965149 43.234047 55317 39.541000 -40.011749 41.843666 55318 40.541565 -39.428894 42.406464 55319 40.445374 -40.691711 41.925308 55320 39.919678 -39.085144 42.588013 55321 39.210274 -41.032867 41.382156 55322 5.812157 -40.626648 41.389343 55323 4.662361 -40.649033 41.613640 55324 12.128227 -41.383255 40.957253 55325 38.017670 -41.081085 41.802376 55326 38.121735 -40.098679 43.373138 55327 38.183151 -41.949539 41.003189 55328 39.519302 -41.826584 41.368683 55329 56.568115 -40.535400 42.528839 55330 56.125351 -41.466736 42.792542 55331 55.728027 -40.859665 43.036942 55332 11.642555 -42.039886 41.417496 55333 12.615784 -42.669754 40.435234 55334 11.353180 -40.705307 41.211563 55335 37.431915 -41.934418 41.165016 55336 37.008484 -42.163879 41.528549 55337 36.993103 -42.140488 42.218094 55338 40.804413 -41.991028 42.453384 55339 39.613785 -42.750763 41.555519 55340 48.472290 -41.954880 41.650780 55341 12.350815 -43.941864 40.405838 55342 47.337738 -43.047302 41.316910 55343 49.245239 -40.945724 42.566605 55344 36.308014 -43.285751 42.067665 55345 43.642639 -44.745255 41.044762 55346 46.200394 -44.541779 42.378326 55347 46.062485 -43.686935 41.256699 55348 44.811584 -44.471085 41.513298 55349 47.277542 -43.931564 41.969757 55350 48.735825 -43.500687 42.588547 55351 49.764511 -42.046616 43.167465 55352 49.975143 -40.464981 43.830414 55353 54.895630 -43.269089 41.725609 55354 55.085571 -42.074966 42.265221 55355 10.974060 -43.631531 41.317307 55356 10.499458 -45.232056 40.532761 55357 39.030396 -43.678970 41.249252 55358 39.269371 -44.453461 41.836754 55359 42.868988 -45.598358 41.212112 55360 32.879486 -46.098511 40.755081 55361 31.620310 -46.082840 40.682938 55362 31.622263 -45.647491 41.837334 55363 33.595474 -45.229202 42.046722 55364 54.710052 -44.506943 41.001083 55365 6.840958 -47.981567 39.685188 55366 9.687775 -46.242218 40.123589 55367 30.637146 -46.190887 40.991791 55368 38.112778 -46.459686 41.456879 55369 37.847595 -47.291031 41.840622 55370 36.987656 -47.089142 40.931549 55371 42.620575 -46.828430 41.710320 55372 4.894920 -48.029999 40.238220 55373 5.773674 -47.393906 40.599953 55374 4.587387 -48.386658 40.934319 55375 8.897888 -45.694321 40.790497 55376 8.136276 -45.050125 41.841553 55377 7.353470 -46.525391 40.711044 55378 28.452759 -48.138336 40.419365 55379 28.912926 -47.519821 40.821701 55380 35.551659 -47.614761 40.973198 55381 36.927612 -47.733444 41.572418 55382 28.545715 -48.478073 41.280159 55383 32.666550 -49.740128 40.346878 55384 33.457230 -48.662994 41.529442 55385 33.200249 -49.044083 41.718071 55386 34.001358 -48.189240 41.148087 55387 42.489502 -47.867706 41.183029 55388 42.939407 -48.378723 41.419472 55389 45.500580 -49.305862 43.122772 55390 3.401566 -49.637177 40.116707 55391 27.629715 -50.063919 40.462715 55392 28.011063 -49.168564 40.678093 55393 51.712402 -49.156281 41.009125 55394 29.307289 -48.996201 42.965744 55395 28.001678 -50.178146 42.206894 55396 28.964111 -49.844513 43.064140 55397 27.230835 -51.121643 40.819321 55398 28.975189 -48.504410 42.105026 55399 34.581276 -51.750214 41.194267 55400 26.760139 -52.648926 40.903450 55401 26.748749 -51.984543 40.979187 55402 36.046852 -52.611420 40.384453 55403 40.582001 -53.481857 41.040352 55404 42.028793 -52.837387 40.691025 55405 43.431900 -52.759750 40.935402 55406 44.598907 -52.586441 40.338287 55407 54.036697 -50.959793 41.565323 55408 27.442856 -53.292465 41.126938 55409 28.836479 -53.364227 40.689377 55410 28.660118 -53.911758 41.874596 55411 29.759552 -53.392700 40.444504 55412 29.871872 -53.845184 41.573906 55413 39.202034 -54.314560 42.346748 55414 37.628342 -54.255615 42.591568 55415 44.968903 -53.300125 41.928520 55416 4.011894 -54.363922 39.731308 55417 3.511788 -53.341034 39.702194 55418 4.386566 -55.723068 39.312576 55419 32.890152 -55.611374 40.274315 55420 53.631104 -53.539322 41.830551 55421 53.087219 -55.032028 41.815063 55422 53.173706 -53.871796 42.780838 55423 4.715599 -56.508118 39.806091 55424 4.951561 -55.468048 40.158203 55425 34.377426 -56.568085 40.356895 55426 50.588196 -55.622726 40.569420 55427 53.129395 -55.641785 40.895035 55428 4.514832 -57.338730 40.148766 55429 34.161682 -57.005539 42.484474 55430 33.653160 -56.562683 41.993683 55431 34.455032 -56.981720 41.369720 55432 37.985764 -57.799942 40.448639 55433 38.950432 -58.512482 41.592819 55434 37.813629 -58.322815 41.577530 55435 45.313919 -57.848358 41.594101 55436 52.298706 -56.281342 41.080910 55437 4.572838 -57.765381 40.897270 55438 39.960281 -58.445908 41.344521 55439 46.272430 -58.290176 42.240623 55440 47.089417 -58.981003 43.096153 55441 47.583008 -59.399918 40.501862 55442 26.073914 -61.461426 40.086731 55443 48.044281 -60.158981 40.912918 55444 5.938965 -61.951233 39.756973 55445 4.852059 -61.369507 39.603340 55446 4.989853 -62.037827 40.131149 55447 5.822029 -63.276169 40.965759 55448 6.054527 -62.604584 40.378197 55449 4.813835 -62.578094 40.759781 55450 9.564331 -63.333282 39.687378 55451 25.247879 -61.983414 39.668747 55452 24.819153 -63.261826 39.640816 55453 24.477859 -62.215881 40.633499 55454 48.366577 -62.003555 40.253853 55455 29.066895 -63.078308 39.923637 55456 30.040047 -63.395813 39.753860 55457 31.373947 -63.743118 40.096436 55458 32.794014 -63.419601 39.827057 55459 33.447594 -63.263290 39.530281 55460 33.863510 -63.492477 39.796585 55461 40.418030 -63.279282 40.029045 55462 41.305176 -63.013290 39.305008 55463 41.320709 -63.197037 40.206474 55464 47.945007 -62.938751 40.022964 55465 9.017265 -64.275925 39.943016 55466 24.495514 -64.198242 40.571350 55467 33.464157 -63.365265 40.028152 55468 34.341705 -63.842255 40.150169 55469 34.754715 -64.441574 39.934647 55470 47.040436 -64.222885 39.889954 55471 47.552002 -63.506790 41.147614 55472 8.149971 -65.286636 39.139633 55473 19.870232 -65.190521 38.600639 55474 19.672165 -65.973206 39.237083 55475 20.273949 -66.993698 38.879242 55476 34.909622 -65.267227 39.747482 55477 42.842743 -64.175613 40.708702 55478 43.918060 -64.674545 40.961090 55479 46.328247 -64.788528 39.989319 55480 5.663925 -66.651352 39.020309 55481 6.349564 -66.357269 39.271439 55482 7.965530 -65.412262 39.957794 55483 7.018730 -65.855011 39.885124 55484 8.491669 -64.897720 39.907776 55485 18.779160 -66.206879 39.878342 55486 25.617798 -65.789886 39.440338 55487 35.143356 -66.050842 40.433922 55488 17.855499 -67.092133 40.379562 55489 18.644989 -66.927872 40.627975 55490 19.573029 -67.025726 39.952484 55491 20.516029 -68.616730 38.955200 55492 28.906288 -68.312881 39.532173 55493 28.283081 -67.569016 39.056511 55494 35.207558 -67.280792 41.152863 55495 4.612785 -70.256973 38.630280 55496 4.491379 -69.154419 38.890648 55497 10.248245 -71.099396 39.317322 55498 11.043159 -70.861969 39.634995 55499 34.683640 -68.656433 39.695747 55500 34.602791 -68.902374 39.564827 55501 34.682076 -68.764313 39.339226 55502 39.961105 -67.169418 40.882271 55503 40.930389 -68.214279 40.301315 55504 10.857140 -71.850052 39.709625 55505 30.403885 -69.722672 39.398209 55506 34.729813 -69.170410 39.522095 55507 34.957260 -70.223618 39.486473 55508 42.193848 -69.888626 40.082802 55509 43.239349 -70.658615 38.960526 55510 9.048477 -71.556351 38.263878 55511 17.227676 -68.797424 41.045998 55512 17.579361 -67.737823 39.513786 55513 30.663620 -71.009216 39.669907 55514 13.950790 -73.782806 39.802025 55515 15.253297 -73.188232 39.188011 55516 30.739410 -71.614700 40.570572 55517 30.805557 -73.224503 41.023186 55518 30.686798 -72.043198 41.790352 55519 37.231247 -72.524185 39.644356 55520 37.281982 -73.143127 39.069809 55521 37.351967 -74.247253 38.855194 55522 40.376282 -72.436111 40.839035 55523 41.115417 -71.292175 41.397278 55524 4.699478 -73.469360 40.099228 55525 4.657745 -73.502625 39.336182 55526 9.713058 -72.529022 39.148392 55527 9.605934 -71.321457 38.869987 55528 17.390625 -72.704346 40.039337 55529 16.553024 -73.854050 40.004684 55530 35.281967 -70.881775 40.361435 55531 36.434586 -73.748856 39.023216 55532 7.455734 -75.742752 38.413254 55533 35.799942 -74.487854 39.006096 55534 36.435791 -74.990524 39.092339 55535 37.421387 -75.766174 38.669609 55536 24.038124 -75.782059 38.713791 55537 22.395699 -74.500427 40.993225 55538 21.639511 -72.820953 40.481056 55539 21.528564 -73.257568 41.220085 55540 8.339218 -76.661209 39.149246 55541 24.550346 -76.669647 38.974396 55542 30.264069 -76.200592 39.684998 55543 36.373444 -76.503937 38.916519 55544 37.074089 -77.108719 38.433807 55545 13.353638 -80.066086 39.583282 55546 14.584442 -79.760086 39.581360 55547 14.628418 -80.710159 40.740456 55548 16.298279 -77.806396 38.136932 55549 17.722832 -77.851364 38.713120 55550 19.854691 -78.173340 39.361977 55551 25.050903 -77.424377 38.805367 55552 25.293884 -77.979660 38.768143 55553 35.908798 -74.971497 39.175522 55554 11.824005 -80.733063 39.563965 55555 10.487076 -81.047134 39.109123 55556 25.916428 -79.689941 38.835922 55557 30.400818 -77.700394 38.921738 55558 30.763779 -78.714508 38.874908 55559 30.994675 -79.678940 38.855415 55560 9.662674 -81.267654 38.081535 55561 22.427567 -79.872604 39.361237 55562 25.652275 -82.365448 38.302315 55563 30.965828 -80.159775 39.770042 55564 26.526443 -80.822601 38.724609 55565 25.570518 -83.052673 38.755661 55566 24.406815 -82.848984 39.937363 55567 27.411224 -81.663116 38.895004 55568 18.658394 -83.442841 39.956993 55569 19.938850 -83.447159 39.957123 55570 23.544334 -81.476669 40.022545 55571 25.912704 -83.838425 38.472755 55572 25.248535 -84.003967 38.816467 55573 26.583000 -83.648026 38.162773 55574 28.230225 -82.362289 38.720230 55575 21.068039 -84.000259 38.685890 55576 24.540741 -84.092850 39.516190 55577 24.975891 -83.527176 39.476997 55578 22.721283 -84.273895 39.961906 55579 23.753738 -84.106522 40.050018 55580 11.386353 -84.794373 38.836197 55581 13.312195 -86.350723 37.895782 55582 13.788544 -85.973877 38.828888 55583 15.165710 -86.181351 38.821960 55584 7.225494 49.944153 46.842224 55585 6.013664 49.150085 47.089012 55586 6.492622 49.039032 48.065979 55587 5.979675 48.728455 48.183426 55588 7.386231 49.394775 47.434685 55589 7.895584 48.943390 48.096710 55590 7.021057 49.132111 47.958641 55591 10.198883 48.039932 47.505295 55592 8.813187 48.352295 48.356148 55593 6.917854 48.640335 48.630447 55594 7.719467 47.839905 49.293159 55595 7.956893 48.492691 48.716980 55596 11.541199 47.022415 48.010994 55597 16.121674 45.999954 46.772186 55598 15.003326 45.932846 47.077057 55599 4.898682 47.875732 47.334564 55600 4.610237 45.608353 47.897003 55601 4.686295 45.050171 49.192169 55602 13.876755 45.605194 47.340233 55603 12.663559 44.475555 47.058502 55604 11.889801 44.823334 47.834030 55605 12.916344 45.874771 47.696388 55606 22.343430 43.425339 46.897171 55607 22.381042 43.886292 46.437859 55608 10.323517 42.922302 47.305344 55609 10.748215 43.577240 47.164124 55610 11.377281 44.084991 47.342850 55611 19.413010 43.036896 47.484375 55612 20.600533 42.595825 48.697800 55613 10.346977 42.146118 47.305038 55614 19.386429 42.394363 48.782425 55615 22.469849 42.672562 47.553909 55616 16.751732 41.575897 49.745178 55617 17.019943 41.763535 47.950401 55618 18.358643 41.833298 49.411659 55619 11.935440 40.793167 48.410439 55620 11.762756 40.196869 48.829041 55621 11.254845 40.079697 48.409424 55622 3.828919 40.057220 46.579956 55623 3.861473 39.549042 47.381355 55624 29.704941 39.190002 46.333153 55625 28.700424 38.640182 46.627563 55626 20.578049 37.810333 47.567375 55627 21.286896 38.119507 48.275787 55628 21.531654 38.589371 47.317314 55629 22.336884 39.300781 47.118477 55630 29.976486 36.768448 47.444778 55631 29.981781 38.621689 46.586571 55632 16.855423 35.557907 45.987556 55633 17.419464 35.491959 46.339798 55634 18.091530 35.739868 47.113663 55635 19.599014 37.056030 47.743858 55636 27.097961 36.964355 47.881950 55637 28.351707 37.471634 47.693558 55638 29.619591 37.975464 47.068909 55639 26.251022 35.635834 47.267067 55640 26.169052 34.973068 46.747536 55641 30.563774 35.695953 47.082336 55642 31.060455 34.795456 47.222649 55643 4.060280 35.102768 46.195343 55644 3.951782 33.437042 46.268257 55645 3.566238 32.384964 45.911087 55646 20.599060 35.975510 49.939789 55647 20.050728 35.694824 49.284401 55648 20.815948 34.667114 49.505173 55649 21.038231 35.772278 50.664108 55650 19.294144 34.543152 47.583694 55651 27.031860 33.693268 47.338814 55652 3.204369 32.331741 45.443352 55653 21.179977 33.057648 46.934120 55654 21.529442 32.630005 46.794662 55655 26.608627 34.882721 47.570961 55656 32.953194 32.101166 47.601730 55657 3.858765 31.443909 46.056267 55658 21.630646 32.235474 46.996841 55659 27.582542 31.379974 46.950462 55660 27.366608 32.596619 46.687744 55661 21.351440 31.580841 46.896400 55662 20.912140 30.934387 46.815529 55663 20.129189 30.056702 46.840340 55664 27.100372 29.908661 46.787849 55665 26.702728 28.978180 46.675797 55666 34.969368 29.900818 46.410263 55667 5.136719 29.588394 46.066048 55668 5.531052 29.107773 46.577377 55669 26.204361 28.787201 46.191795 55670 25.761185 28.390976 45.715057 55671 27.446289 29.170578 47.290901 55672 34.488083 29.367462 46.275543 55673 17.891037 27.673233 46.841805 55674 26.501900 28.171539 46.258492 55675 29.264420 28.928986 47.222977 55676 30.058655 29.099106 47.460281 55677 32.102081 28.940338 46.688354 55678 33.472366 29.164764 46.451080 55679 7.047829 26.833832 45.403709 55680 6.235954 26.221252 46.019424 55681 4.224358 24.583801 47.209213 55682 4.066872 23.563690 46.992088 55683 4.609757 24.034088 46.408333 55684 5.969742 24.451233 45.550446 55685 29.335564 25.675598 47.483032 55686 26.637589 25.754807 47.238716 55687 27.841835 25.026306 45.958038 55688 31.334511 25.104111 46.779137 55689 35.717712 24.784424 47.489548 55690 34.491959 24.783234 47.020767 55691 38.631134 22.896011 47.649872 55692 38.099503 23.451935 48.344231 55693 16.296600 23.210205 45.736259 55694 4.842598 21.714050 45.528076 55695 4.615883 22.220184 46.642868 55696 4.928406 22.997131 45.935135 55697 16.615433 22.070938 46.127281 55698 16.344635 22.625839 45.779716 55699 24.295677 23.767670 48.101906 55700 25.314102 23.334564 48.495338 55701 24.857376 22.855392 47.702942 55702 39.776093 22.084488 47.621712 55703 40.691467 21.402023 48.313599 55704 5.051315 20.566193 45.596397 55705 16.932053 21.467789 45.752937 55706 25.899063 21.916565 47.054016 55707 24.487061 22.257034 46.546417 55708 5.234100 19.817230 45.299530 55709 18.888901 19.589951 45.473068 55710 27.642426 20.684784 45.946472 55711 30.027756 20.112122 46.206764 55712 29.990173 20.624146 46.612228 55713 30.296280 20.177567 46.526215 55714 7.263474 18.869370 45.953682 55715 6.345986 19.966675 46.115143 55716 7.524277 19.621948 46.319298 55717 21.701218 18.449341 46.157936 55718 7.590530 20.071564 46.738365 55719 8.003189 19.096207 46.672302 55720 7.614830 18.144241 46.507004 55721 20.758614 19.600159 47.035339 55722 23.248772 18.304077 47.464653 55723 21.951027 19.087524 47.092484 55724 4.400879 15.399170 45.242050 55725 36.163513 15.285858 46.158623 55726 36.524704 16.163849 46.033478 55727 44.439301 18.000641 46.121780 55728 6.496506 17.179184 45.579269 55729 6.098877 16.852448 46.102982 55730 6.958031 17.845139 45.688965 55731 23.047272 17.451233 46.475723 55732 22.817459 16.568817 45.993813 55733 26.484390 13.344162 45.554436 55734 27.129181 14.367294 46.219940 55735 26.557922 13.360504 46.938759 55736 27.357651 15.340210 45.562637 55737 29.237061 18.105774 47.080849 55738 37.864426 17.154816 46.478889 55739 41.734909 17.167816 46.883293 55740 4.931290 16.100998 45.183823 55741 36.747360 16.702713 46.736008 55742 37.337646 17.009247 46.564827 55743 5.323937 16.333344 46.230606 55744 20.806549 13.909119 45.415779 55745 19.621597 13.351318 45.746361 55746 36.288666 11.747452 45.154121 55747 37.241890 12.446808 45.900185 55748 18.458206 13.495972 46.993462 55749 19.246063 14.132919 47.426201 55750 19.887253 14.002472 46.532936 55751 20.731995 11.310272 45.437248 55752 19.609581 11.012604 45.778351 55753 19.744644 11.632172 45.256516 55754 37.287796 13.234985 46.682541 55755 4.682510 12.298843 45.823700 55756 5.793533 11.702423 44.922241 55757 18.625259 12.707611 46.101410 55758 18.558151 11.417892 46.131325 55759 25.614532 12.402969 46.140938 55760 35.859154 10.947342 44.554146 55761 38.801643 12.703247 46.668678 55762 44.044708 11.122772 45.561569 55763 44.177856 11.779541 46.489548 55764 23.920624 11.597107 45.725548 55765 24.782013 11.848740 46.056053 55766 44.637421 11.104233 46.066414 55767 45.060669 9.758530 46.584450 55768 44.999695 10.998260 46.942879 55769 44.723404 10.241333 45.779175 55770 8.136475 10.275558 45.305893 55771 9.162483 6.327728 44.841812 55772 9.802513 6.367554 44.245880 55773 39.832062 7.076996 46.338127 55774 38.828781 6.560883 45.733658 55775 44.558350 9.266357 45.836128 55776 42.495819 7.673782 46.310242 55777 40.982498 7.082535 45.901932 55778 50.013824 5.559212 46.316833 55779 49.197144 6.050491 45.931335 55780 37.848328 6.232819 45.813065 55781 50.766434 4.852295 46.038055 55782 6.862602 4.086952 44.427231 55783 38.111862 3.753006 47.158379 55784 37.703888 3.912003 47.014236 55785 37.833549 3.720894 46.367043 55786 50.832733 3.721992 46.243057 55787 37.460342 1.740082 44.410866 55788 38.666351 2.072479 45.271141 55789 39.562836 2.762192 46.148468 55790 40.240616 1.599838 45.848579 55791 38.113068 -1.041229 44.734268 55792 39.097290 -0.576141 45.227234 55793 39.628433 0.555695 45.501091 55794 2.706688 -1.652023 45.940796 55795 2.821549 -1.720200 45.057213 55796 37.202515 -1.880264 44.465630 55797 37.973953 -2.125626 44.900452 55798 40.884399 0.835526 46.246948 55799 40.454239 0.503159 45.937592 55800 40.530548 -1.180923 46.475998 55801 46.384415 -1.187576 45.394791 55802 47.377197 -2.166412 45.460846 55803 52.263153 -0.857529 44.726021 55804 3.510239 -2.326111 44.239334 55805 4.586907 -2.659012 43.597885 55806 45.971222 -2.972488 45.055763 55807 51.949173 -1.929123 44.824738 55808 50.674927 -2.383942 45.097542 55809 50.992432 -1.481247 45.493828 55810 52.854187 -2.435898 44.444527 55811 51.735794 -0.971451 45.278618 55812 37.473450 -2.658569 44.734619 55813 50.211502 -3.319595 44.850166 55814 49.544586 -2.821167 45.150597 55815 51.266327 -2.847870 44.785591 55816 49.537262 -1.794357 45.693344 55817 52.121796 -2.986099 44.759445 55818 53.135498 -3.591278 44.784943 55819 4.342278 -3.167831 44.308586 55820 3.177445 -3.287140 45.789703 55821 5.989800 -5.264877 46.179550 55822 5.116554 -4.054642 44.968658 55823 4.241394 -4.728516 46.150719 55824 38.121727 -3.859772 44.269844 55825 38.098953 -2.907211 44.875000 55826 38.059677 -4.607285 43.581856 55827 46.619019 -4.026367 44.831802 55828 46.514587 -3.094757 45.048340 55829 48.537796 -2.759232 45.287468 55830 47.652756 -3.661301 44.937538 55831 48.935638 -3.689697 44.897522 55832 51.093307 -3.662491 44.857155 55833 49.706787 -4.592606 45.124390 55834 52.022430 -3.813965 45.171272 55835 52.775055 -4.277969 45.675575 55836 53.716660 -5.046951 45.508324 55837 38.879547 -3.325806 44.946205 55838 44.893799 -4.445267 44.742325 55839 45.927139 -4.862427 45.050400 55840 47.380325 -4.944611 45.177223 55841 48.434235 -4.589127 44.982788 55842 49.469604 -5.476837 45.819038 55843 48.634644 -5.444183 45.811081 55844 50.339722 -5.129837 46.070786 55845 9.080093 -5.398056 45.214516 55846 9.662659 -5.904099 45.760590 55847 10.141785 -6.318405 43.284439 55848 39.790718 -3.148132 45.539032 55849 41.133118 -4.226471 45.485809 55850 44.862579 -5.170242 45.199356 55851 45.535751 -5.627197 46.107361 55852 44.449799 -5.499893 45.924049 55853 46.699753 -5.584564 46.079918 55854 10.729523 -7.734818 44.734879 55855 10.422729 -7.783279 43.994308 55856 6.440758 -8.994385 43.336258 55857 4.472527 -12.675537 43.098946 55858 4.436981 -13.799698 43.089493 55859 3.729881 -12.106461 44.406403 55860 3.417626 -9.956726 43.403694 55861 7.623901 -9.548401 43.498695 55862 7.065971 -9.730682 44.748306 55863 8.460648 -9.958725 43.898544 55864 9.912941 -10.094910 44.781525 55865 9.358932 -10.017761 44.126686 55866 50.685516 -12.512527 44.839035 55867 50.372971 -13.201630 45.434998 55868 51.321518 -11.813232 45.560089 55869 52.357025 -10.449600 45.879791 55870 50.838593 -12.852066 45.741531 55871 50.421188 -13.216141 47.080956 55872 4.010063 -14.581985 43.013557 55873 3.888039 -15.976486 44.035370 55874 56.345169 -15.931793 44.382118 55875 3.365921 -19.085373 43.015503 55876 10.208541 -17.539276 43.431694 55877 10.393875 -18.648315 43.395142 55878 8.963623 -17.364960 43.842903 55879 45.385193 -17.213455 44.329712 55880 45.649933 -17.682739 45.270393 55881 46.606995 -17.157761 45.252625 55882 46.647934 -16.424011 44.140663 55883 47.478683 -16.381821 45.144714 55884 51.986786 -17.715439 44.521744 55885 9.421928 -16.108109 44.257561 55886 10.422287 -16.103424 44.495117 55887 10.296440 -16.821396 43.896362 55888 34.865234 -17.636978 43.471863 55889 34.774811 -17.806046 44.015427 55890 44.099152 -17.076126 43.449165 55891 46.748016 -16.840775 44.676872 55892 52.986389 -16.642746 44.276611 55893 57.016220 -18.085846 46.125092 55894 57.137344 -17.536819 45.653000 55895 3.048317 -19.481552 44.075806 55896 3.194939 -18.670837 44.674644 55897 11.152573 -17.717133 43.766190 55898 11.961868 -19.073303 43.914070 55899 31.841158 -19.080627 44.541321 55900 32.385643 -18.595825 45.350311 55901 35.545914 -17.797989 43.764725 55902 34.733932 -18.130386 45.147102 55903 33.702515 -18.366684 46.712112 55904 34.824181 -18.334595 47.227440 55905 36.923401 -17.997726 44.019394 55906 38.321060 -18.324493 44.519951 55907 39.190460 -18.147415 43.770058 55908 40.141953 -18.165039 43.889488 55909 41.268631 -18.202423 44.206970 55910 43.202194 -18.239883 44.772072 55911 43.893280 -17.707092 44.167511 55912 10.179916 -19.878952 43.254135 55913 10.729530 -20.720581 42.965576 55914 43.908325 -21.580826 44.700424 55915 8.688538 -19.264603 44.071632 55916 12.693787 -21.281281 43.380196 55917 11.375732 -19.865036 43.115685 55918 12.268204 -20.230194 43.347084 55919 32.258041 -20.822357 44.304825 55920 32.030838 -20.216675 43.749580 55921 45.982544 -20.914337 44.564278 55922 50.101334 -18.924454 46.682549 55923 50.964752 -18.404739 45.892494 55924 51.140457 -17.908951 47.010429 55925 53.805817 -20.780945 44.655464 55926 54.425766 -20.570969 44.906052 55927 35.642151 -21.436508 43.342010 55928 35.301109 -21.274612 44.670258 55929 44.991699 -21.130905 44.357071 55930 4.584137 -23.105774 42.681938 55931 13.225174 -23.744125 43.012383 55932 36.679276 -21.544968 44.066711 55933 49.950745 -23.834259 44.675896 55934 49.793793 -22.997391 43.343460 55935 3.788323 -24.029587 42.901985 55936 12.723320 -20.453186 43.998184 55937 13.007889 -21.033066 43.937187 55938 48.733459 -24.206177 43.925522 55939 56.021973 -23.745773 44.152328 55940 56.626068 -23.788300 45.017319 55941 58.094009 -24.328445 44.566643 55942 10.837540 -26.386566 42.556778 55943 10.334259 -25.614487 42.885574 55944 14.193695 -26.017120 43.526917 55945 14.382401 -26.640823 43.421593 55946 13.868393 -26.562073 42.816391 55947 46.032532 -26.308365 44.399811 55948 54.464432 -24.579041 43.709000 55949 55.215393 -24.000580 43.692490 55950 57.257889 -23.686096 44.895096 55951 2.851097 -24.838150 43.256432 55952 47.086609 -25.765854 44.740982 55953 50.415634 -28.335495 44.222046 55954 50.611633 -27.971268 43.154915 55955 51.916107 -27.072983 43.886124 55956 10.337776 -26.511292 43.169426 55957 57.895721 -25.696136 45.420258 55958 57.543823 -25.132050 45.918930 55959 11.263931 -27.594025 43.201378 55960 10.406509 -29.017441 44.866524 55961 9.828079 -28.368118 45.111130 55962 10.215073 -27.499359 44.144928 55963 11.805649 -28.962036 43.780403 55964 14.326881 -27.362625 43.592194 55965 15.028564 -28.177597 44.477852 55966 3.708366 -28.106781 42.920616 55967 4.809982 -28.995071 42.874741 55968 4.792153 -28.378860 42.143898 55969 32.068924 -28.684586 42.033272 55970 53.973297 -26.285583 46.428612 55971 52.920166 -26.747833 45.371635 55972 54.153397 -25.430756 45.006210 55973 58.295288 -27.489761 43.902466 55974 5.565621 -29.176102 42.053528 55975 5.349747 -29.546921 42.620888 55976 32.177765 -29.268875 42.652985 55977 33.863037 -28.503250 43.010902 55978 34.586052 -28.526535 43.244843 55979 34.957397 -29.076355 44.070030 55980 35.816315 -28.573212 43.251823 55981 38.986710 -29.177521 43.014717 55982 39.635406 -29.241989 43.220291 55983 38.245255 -28.918762 42.727203 55984 41.052551 -28.742020 43.101944 55985 48.116364 -29.385345 43.522629 55986 49.006149 -29.148941 44.328323 55987 58.204407 -28.606583 43.324867 55988 5.422043 -30.301483 42.250519 55989 5.036903 -29.873749 43.024376 55990 40.286926 -29.115417 43.113068 55991 40.423233 -29.204742 44.035828 55992 29.656586 -32.474167 43.006927 55993 45.797470 -30.931213 43.705116 55994 57.945282 -29.806229 43.534683 55995 44.342316 -31.879929 42.898598 55996 4.835640 -31.840546 42.449463 55997 5.068085 -33.260635 41.895599 55998 4.737412 -34.378021 42.193466 55999 4.995667 -30.652679 42.897423 56000 11.408005 -34.292648 42.436371 56001 10.923309 -34.367554 42.869118 56002 11.504723 -33.568192 42.619347 56003 11.556122 -32.534988 43.123695 56004 11.446793 -31.800476 43.749184 56005 12.440369 -31.444550 43.476768 56006 27.897385 -34.954056 43.815262 56007 28.764687 -34.472214 44.505798 56008 28.572395 -33.914703 42.802292 56009 28.382385 -33.971802 41.672623 56010 37.429169 -33.005508 42.570793 56011 35.390572 -33.964706 43.558174 56012 36.999390 -33.139709 43.542526 56013 43.368744 -32.645157 44.573662 56014 42.430603 -32.999130 44.828262 56015 44.268250 -32.081192 44.038925 56016 12.123566 -34.244171 42.287346 56017 12.690552 -32.949249 42.645424 56018 13.440720 -34.203674 42.556305 56019 12.765190 -35.266922 42.306664 56020 13.589478 -33.227432 42.692245 56021 13.500076 -35.096985 42.437950 56022 14.235756 -33.252350 43.516098 56023 14.211105 -34.187485 43.416489 56024 34.581909 -35.397980 44.889687 56025 40.548126 -33.061508 44.626656 56026 39.523155 -33.014206 43.920494 56027 48.897461 -34.359238 45.674911 56028 49.323120 -33.636169 44.840103 56029 48.467102 -35.007156 44.029251 56030 52.708984 -32.906113 45.193184 56031 53.535858 -32.861099 44.992760 56032 13.551643 -35.619705 42.544975 56033 13.191551 -36.117447 42.582672 56034 14.122932 -35.152344 43.322098 56035 48.534088 -34.953705 43.081383 56036 50.179626 -33.469040 43.998764 56037 51.787918 -35.357422 42.236000 56038 11.667038 -35.006973 42.494232 56039 11.200180 -35.326584 42.862816 56040 12.159744 -36.112366 42.801071 56041 26.325638 -36.466736 42.562271 56042 54.285522 -37.352386 42.870872 56043 55.971527 -37.531235 43.248947 56044 52.811249 -36.543777 42.570862 56045 55.105011 -37.853790 43.592552 56046 26.009254 -37.283661 42.274712 56047 57.099579 -37.081009 42.377846 56048 4.316689 -37.790878 41.958351 56049 4.986252 -36.690948 41.668602 56050 26.626602 -36.009583 43.838425 56051 25.646835 -38.034958 42.447273 56052 56.833939 -38.623474 42.768906 56053 56.099518 -38.403381 43.580269 56054 3.927246 -39.175537 42.161209 56055 3.645660 -38.552490 43.458031 56056 3.890480 -40.103821 43.272385 56057 3.752556 -37.227875 43.508156 56058 26.140152 -38.706635 42.255699 56059 29.574356 -38.055481 41.987709 56060 29.359039 -38.683517 43.982803 56061 31.013657 -37.858749 43.539703 56062 30.707977 -38.178299 44.436295 56063 40.487411 -38.931793 42.733002 56064 4.050728 -40.066040 41.808655 56065 8.850365 -40.276794 41.308136 56066 9.761964 -41.045105 42.242760 56067 10.748046 -42.137787 42.132896 56068 11.167999 -41.329849 41.804031 56069 28.241531 -38.935120 42.444061 56070 41.662979 -40.122879 42.833076 56071 41.255188 -40.875381 42.340569 56072 42.219559 -40.703049 43.178635 56073 41.751465 -40.948914 42.814247 56074 49.127838 -39.732544 42.793457 56075 53.078827 -37.813232 42.652344 56076 55.756104 -39.311005 43.438248 56077 7.469925 -41.240875 43.266014 56078 8.804703 -42.081757 44.041573 56079 11.700349 -41.260513 41.436127 56080 37.419342 -41.769257 43.162796 56081 42.609665 -40.490601 43.626801 56082 54.807495 -40.084808 42.856186 56083 55.686829 -40.292313 43.190613 56084 41.443222 -42.889008 43.930046 56085 42.389618 -41.391953 43.893059 56086 40.780975 -46.743942 46.897903 56087 40.895828 -47.364273 48.193794 56088 40.145569 -47.710373 46.991920 56089 55.863251 -42.655731 42.313255 56090 55.567749 -43.154190 42.067001 56091 56.132019 -43.174957 41.953651 56092 55.843933 -42.059235 42.606873 56093 9.503822 -44.660217 41.409149 56094 10.149490 -42.885681 42.621056 56095 9.477394 -43.914261 42.383011 56096 39.903603 -43.530365 42.163452 56097 35.283348 -44.469193 42.512573 56098 38.974060 -45.502304 41.986572 56099 39.876083 -44.673065 42.894699 56100 39.286415 -47.958099 45.082710 56101 39.975052 -47.297501 45.789230 56102 39.149467 -48.546600 46.323776 56103 43.789398 -45.617752 42.001442 56104 45.010773 -45.119644 42.395668 56105 47.765213 -44.561386 43.040581 56106 46.739975 -45.170990 43.660347 56107 54.944366 -44.078812 41.445251 56108 55.639465 -43.782959 41.680984 56109 6.330200 -45.953659 41.663879 56110 5.930199 -45.200058 42.757271 56111 5.302269 -46.088120 42.502853 56112 30.531601 -45.882263 41.937820 56113 32.187340 -45.623260 43.334030 56114 33.284622 -45.568924 43.793312 56115 31.203995 -45.796021 43.163521 56116 34.589386 -44.732727 42.156487 56117 39.468552 -45.781876 43.094727 56118 44.588654 -45.864532 43.108994 56119 45.592667 -45.263290 43.126587 56120 5.280457 -47.131653 41.679214 56121 7.202744 -44.772827 42.853043 56122 29.242508 -47.409653 41.606873 56123 29.920837 -46.527039 41.791008 56124 38.767487 -46.743790 42.731888 56125 42.584518 -47.998474 42.030869 56126 42.711060 -47.451233 42.585136 56127 3.969742 -51.253281 42.196350 56128 3.313240 -51.674683 41.544601 56129 3.518486 -50.266006 40.809921 56130 35.154793 -48.429871 41.997574 56131 34.005783 -49.008362 42.382835 56132 36.336731 -48.218384 42.099609 56133 37.694977 -47.921753 42.738716 56134 44.494537 -49.360428 42.801506 56135 47.587479 -48.474594 42.039642 56136 48.452484 -48.517181 42.221298 56137 48.281097 -48.905945 43.088104 56138 3.004265 -51.726425 40.838142 56139 43.879395 -49.197540 42.909698 56140 43.136353 -48.531906 42.542702 56141 51.730957 -49.336243 42.124489 56142 50.745392 -49.193161 42.796494 56143 52.551666 -50.042191 42.835892 56144 51.696030 -49.670349 43.106537 56145 53.410095 -50.596237 42.439316 56146 2.836769 -52.393738 40.608398 56147 26.649612 -51.778839 42.031143 56148 53.829163 -51.429276 42.463264 56149 3.270317 -53.201981 40.523125 56150 26.494377 -52.545471 41.506096 56151 36.025330 -53.054153 42.055931 56152 46.540802 -53.495392 42.403931 56153 47.480042 -53.372314 41.866211 56154 47.795532 -53.084473 40.829605 56155 2.868881 -52.528778 40.341888 56156 3.840370 -53.550735 41.475105 56157 4.559998 -54.274338 40.914551 56158 26.673965 -53.047974 41.370079 56159 36.885017 -53.760956 42.031067 56160 47.843079 -53.882675 42.680443 56161 48.736252 -54.065659 41.799278 56162 3.192497 -52.705734 41.281174 56163 31.257507 -54.269226 41.771919 56164 36.797760 -53.945419 43.014633 56165 37.230637 -54.359451 42.846268 56166 40.629089 -54.423309 42.520393 56167 53.428528 -52.347931 42.952576 56168 53.027069 -53.152618 43.508423 56169 5.614304 -56.746841 40.639984 56170 5.422226 -54.929428 40.805046 56171 6.241516 -55.439651 40.789551 56172 8.362701 -54.622726 41.772118 56173 9.106140 -55.045853 41.595276 56174 8.385398 -55.629288 41.233719 56175 5.964211 -54.337494 41.690155 56176 7.209290 -54.567764 41.715271 56177 7.481278 -55.533493 41.009781 56178 32.342148 -55.200119 41.156097 56179 50.358063 -55.333420 41.923035 56180 6.739739 -56.170029 40.677277 56181 9.722000 -56.242767 42.506454 56182 9.553833 -56.720932 43.959183 56183 8.362717 -57.035950 42.764191 56184 33.746498 -56.518661 41.116905 56185 51.218567 -56.185043 41.343018 56186 52.377670 -55.688675 42.446236 56187 52.721527 -54.829254 42.837143 56188 5.320252 -57.719254 41.849236 56189 6.513458 -57.368256 41.747459 56190 35.601166 -57.483597 41.239944 56191 36.869110 -57.886002 41.258324 56192 36.042191 -57.889954 42.167633 56193 35.389542 -57.664307 43.137505 56194 36.444641 -58.221771 43.072159 56195 41.074799 -58.333878 41.521172 56196 42.639725 -58.383926 42.246185 56197 41.595688 -58.948410 43.051865 56198 42.090134 -57.901688 41.272469 56199 45.501862 -58.529282 43.097946 56200 48.074188 -60.304260 42.170364 56201 9.965179 -61.023315 39.306099 56202 8.656502 -63.210159 40.437729 56203 26.596977 -61.806015 41.196480 56204 25.122360 -61.493164 40.742073 56205 25.637192 -61.404541 41.391556 56206 3.885079 -60.918549 41.001884 56207 28.042145 -63.016983 41.026787 56208 26.888313 -62.324783 41.818535 56209 48.292984 -61.773727 41.047173 56210 3.576332 -61.904999 41.943970 56211 3.993294 -62.445541 41.441353 56212 6.126465 -64.234207 41.404007 56213 5.295929 -65.001938 41.922264 56214 5.864151 -65.365936 41.620354 56215 23.855743 -62.349884 41.481079 56216 24.102066 -63.210510 40.967209 56217 41.484390 -63.888901 41.193703 56218 40.104874 -64.314255 41.360359 56219 24.013115 -64.328690 41.850677 56220 33.690948 -63.656052 40.661575 56221 32.676590 -63.936401 41.067932 56222 34.841988 -64.156647 41.229439 56223 35.129478 -64.952484 40.496140 56224 40.940277 -64.892136 42.613785 56225 32.363525 -65.163910 42.480309 56226 31.537773 -64.606079 41.408028 56227 31.379761 -65.260590 41.942657 56228 39.412659 -65.175674 40.897636 56229 48.086166 -62.126709 42.276901 56230 6.069512 -66.523560 39.805435 56231 24.819809 -65.507385 40.810051 56232 35.461220 -65.088531 41.364525 56233 39.533607 -66.207977 40.900932 56234 45.270233 -64.906662 41.206207 56235 46.470642 -64.659073 40.727837 56236 46.515381 -64.337250 41.795448 56237 5.209427 -66.973236 39.980408 56238 5.079475 -66.583450 41.793594 56239 5.061531 -66.971924 40.807632 56240 5.836212 -66.509399 40.648643 56241 7.043808 -65.289978 40.979088 56242 6.268005 -65.852554 41.149689 56243 26.496246 -67.635040 40.061043 56244 25.198120 -67.188736 41.285309 56245 25.646484 -66.648315 40.125298 56246 34.878143 -68.952148 40.357536 56247 17.502380 -67.592682 41.145721 56248 18.954941 -67.996689 41.452759 56249 20.340790 -69.507507 40.394829 56250 27.504852 -68.704910 40.385376 56251 26.078339 -68.430466 40.884613 56252 40.183853 -68.056793 41.696426 56253 28.888878 -68.808105 40.205460 56254 28.554947 -69.783813 41.260132 56255 29.491516 -69.135300 40.440308 56256 29.981247 -69.339584 40.307129 56257 34.679718 -68.922791 39.801407 56258 35.091064 -70.002472 41.309723 56259 35.272446 -68.368683 42.027687 56260 41.047638 -69.564575 41.556252 56261 40.756592 -69.877960 42.499016 56262 40.316544 -68.943787 42.608238 56263 30.360764 -70.107803 40.268166 56264 30.333694 -70.907303 41.393806 56265 34.751503 -69.691956 40.569832 56266 34.650497 -69.916901 40.405548 56267 34.749847 -69.785919 40.186729 56268 34.813301 -70.179565 40.233498 56269 4.861221 -73.603394 38.518593 56270 11.939651 -72.587906 39.733963 56271 12.839981 -73.523636 39.827072 56272 17.549271 -71.704254 39.752853 56273 17.568619 -72.134720 39.705162 56274 17.703430 -72.008835 39.871941 56275 36.342911 -72.047043 40.458572 56276 17.631943 -72.236115 39.912361 56277 29.114288 -73.928314 38.989754 56278 35.518585 -71.345093 41.124794 56279 35.972076 -72.014282 41.370201 56280 37.784622 -72.573273 40.596901 56281 36.727982 -72.413177 41.230461 56282 37.378571 -72.728439 41.903687 56283 38.505844 -72.823318 41.707237 56284 39.258080 -72.700531 40.643143 56285 4.693955 -72.521149 41.001396 56286 10.125763 -73.863251 39.391594 56287 10.720001 -73.073959 39.702736 56288 17.407669 -73.464218 40.759506 56289 29.899597 -73.631805 39.663559 56290 11.305603 -74.410095 39.867126 56291 15.260071 -76.101776 41.821762 56292 14.944267 -74.985428 40.646133 56293 13.930260 -76.760513 42.307602 56294 23.342606 -75.132141 39.774162 56295 24.407837 -76.648987 40.501320 56296 30.633194 -74.725830 40.549240 56297 9.849915 -74.937973 39.306190 56298 9.346222 -75.957565 39.319252 56299 9.441658 -76.946335 39.831200 56300 10.367249 -75.889221 39.861496 56301 23.457840 -75.658066 40.999916 56302 7.236359 -76.846573 39.208115 56303 7.057266 -77.667953 39.912086 56304 7.625267 -77.976181 39.680893 56305 7.691497 -77.509033 39.420380 56306 16.890671 -78.623886 39.425629 56307 25.631744 -78.683136 39.578239 56308 25.054756 -77.557983 39.559395 56309 25.142387 -77.841263 40.635063 56310 6.346245 -76.717285 40.015091 56311 8.378677 -77.825241 39.779083 56312 15.886063 -79.695129 40.128929 56313 20.713562 -78.332138 39.197182 56314 21.497536 -80.552780 41.734779 56315 21.333557 -79.794113 40.936935 56316 22.355804 -80.765793 41.011124 56317 21.376106 -78.781281 39.197128 56318 25.631805 -78.639725 40.644997 56319 31.071884 -77.600327 40.311569 56320 31.259018 -75.867172 41.168930 56321 10.848907 -81.813263 39.912369 56322 9.994766 -81.839966 39.150352 56323 17.276627 -79.321198 40.443253 56324 26.101784 -79.437759 39.630943 56325 26.456657 -80.024490 39.554398 56326 31.119499 -78.962204 39.679955 56327 22.898651 -81.711548 41.216148 56328 27.244812 -80.837173 39.955734 56329 18.317764 -83.140121 38.688400 56330 28.358551 -81.648529 39.627632 56331 10.626419 -83.894241 39.236183 56332 20.941071 -83.761276 40.135048 56333 21.710747 -84.128967 39.813538 56334 11.467621 -84.107986 39.871063 56335 16.110146 -86.243149 38.440804 56336 16.012016 -86.027740 39.009964 56337 5.303703 48.296570 48.039452 56338 5.108208 46.108032 49.692322 56339 9.755554 46.910370 49.107567 56340 13.996254 46.522186 47.241859 56341 12.386749 46.383743 48.027733 56342 5.037697 47.225494 48.485237 56343 11.875488 45.560623 48.304703 56344 11.133194 46.014984 48.684219 56345 10.473122 44.387604 48.390358 56346 4.352768 40.535950 48.481834 56347 4.670555 42.352844 49.021233 56348 5.452789 41.413681 49.545250 56349 8.712845 43.735565 49.475327 56350 9.347047 44.930283 49.592667 56351 21.603241 42.691238 48.282845 56352 18.468315 42.343109 48.085304 56353 22.278015 41.775757 48.647484 56354 21.484940 42.301865 48.896454 56355 4.796150 43.959290 49.484634 56356 7.196701 42.742950 49.814484 56357 22.988731 41.650970 48.017677 56358 3.799538 40.270370 47.268990 56359 3.940849 40.349457 47.658829 56360 10.872360 40.805267 48.030075 56361 14.903474 41.251175 47.217163 56362 15.338715 41.499634 48.572227 56363 23.250832 41.188293 47.760506 56364 10.237030 40.125198 48.304512 56365 3.932198 38.078979 47.261284 56366 3.787048 37.279724 47.174309 56367 21.812210 38.702347 48.331223 56368 22.162888 39.128586 47.933136 56369 27.922005 36.510361 48.657074 56370 20.543533 37.067169 48.962975 56371 29.057831 36.433105 48.523445 56372 3.942352 36.907257 47.132721 56373 4.421661 36.246094 47.153473 56374 4.665596 37.568481 47.920464 56375 4.594887 39.128571 48.513412 56376 5.686325 38.343872 48.672867 56377 4.059059 37.252747 47.452255 56378 7.719581 38.083481 48.407249 56379 8.645966 38.440689 48.393837 56380 8.689758 37.242493 47.946770 56381 18.752525 36.287750 47.732025 56382 26.578438 35.639267 47.962921 56383 26.649033 36.251007 47.888268 56384 5.591454 36.006943 47.658226 56385 4.864578 33.886917 47.271637 56386 7.814544 36.687851 47.720978 56387 7.586990 35.726501 47.612877 56388 6.801430 36.885834 47.931404 56389 6.816666 35.084442 47.760803 56390 8.540657 36.019928 47.765480 56391 8.958908 36.559219 47.713188 56392 30.155754 35.534912 48.365166 56393 6.972679 34.061096 48.596649 56394 6.018875 34.116928 47.886871 56395 20.685585 33.803009 47.920158 56396 21.560097 32.821686 47.545959 56397 19.856644 34.843277 48.700111 56398 4.385742 31.720428 46.981209 56399 5.065636 32.084778 48.135849 56400 27.502640 32.824783 47.759384 56401 34.245247 29.967224 46.837517 56402 33.869164 30.908997 47.194107 56403 21.844879 32.175125 48.135384 56404 20.619652 29.926971 48.140739 56405 20.757629 29.930252 49.204422 56406 21.404739 30.965302 48.182098 56407 19.977234 29.330597 48.259056 56408 5.013710 29.898621 47.137878 56409 4.921608 30.790894 48.038162 56410 28.288391 30.229156 48.009056 56411 28.139641 32.429855 48.780640 56412 32.930054 30.727295 47.915466 56413 31.992571 29.946716 48.035545 56414 30.865814 29.434296 47.704559 56415 30.830177 30.535812 49.005455 56416 17.481720 26.744888 47.882233 56417 18.940964 28.706238 47.213257 56418 27.218391 28.553223 46.856491 56419 28.111633 28.577972 46.867226 56420 33.126038 29.855011 47.302727 56421 5.699364 27.385742 46.872803 56422 5.038612 25.695328 46.812798 56423 24.683701 25.476990 47.693565 56424 25.547867 26.127640 46.911751 56425 23.681564 24.570602 47.576691 56426 22.939049 23.789139 46.655960 56427 27.595459 25.395416 46.718216 56428 28.066582 25.828705 48.151276 56429 30.313499 25.562973 47.371758 56430 31.987032 25.920609 48.830940 56431 36.482437 24.190033 47.164146 56432 30.965080 25.862015 48.275597 56433 37.485504 23.972260 48.347481 56434 4.326904 23.079636 46.470596 56435 4.133919 22.893860 46.816254 56436 4.199677 25.536774 48.110298 56437 4.784195 27.424728 48.150276 56438 16.291077 23.203323 46.192924 56439 23.788589 23.426407 47.337715 56440 4.924996 21.281128 46.302261 56441 17.877823 21.139771 47.301819 56442 16.577911 23.075500 46.845032 56443 17.242378 22.152344 47.555237 56444 18.524307 20.804382 47.596733 56445 19.319489 20.035065 46.870071 56446 26.814377 22.476532 48.213150 56447 27.315140 21.542770 47.021210 56448 29.529861 22.455231 48.414864 56449 30.191696 21.324432 47.535057 56450 30.593750 20.426834 47.276917 56451 42.442001 20.342209 47.667488 56452 41.458572 20.612610 48.542503 56453 5.482254 20.876678 46.536850 56454 7.943313 19.731293 46.693558 56455 25.877548 22.602402 48.030083 56456 29.958580 18.745865 48.182640 56457 7.503738 20.671158 47.467064 56458 44.338287 18.622177 46.501999 56459 43.797089 18.368500 46.962555 56460 43.127014 19.283524 47.783913 56461 8.059875 18.536682 47.336372 56462 7.478653 17.963226 47.399643 56463 28.551567 16.929916 46.873779 56464 37.375031 16.952072 47.676544 56465 38.499321 17.184326 47.028625 56466 40.891830 17.484161 48.382278 56467 6.827149 17.365433 46.567970 56468 24.129211 18.119080 48.424507 56469 23.340912 16.969406 47.377304 56470 23.490112 17.527267 47.048370 56471 27.842407 15.558029 46.637543 56472 36.103195 16.106491 46.905968 56473 38.864342 17.073303 48.620743 56474 4.666168 15.649292 46.089905 56475 4.157295 14.796310 45.981628 56476 4.485970 15.719620 47.757378 56477 20.981232 14.684601 46.732430 56478 36.213623 14.274582 46.289551 56479 35.941628 14.578079 46.989380 56480 17.656265 12.406891 47.082535 56481 36.256317 14.046631 47.023293 56482 36.611221 13.754456 46.630249 56483 4.283905 13.419662 46.654564 56484 37.772423 13.181564 47.646339 56485 40.394806 12.809631 47.121803 56486 41.355286 12.634857 46.806541 56487 42.526413 12.563583 47.004425 56488 43.615814 12.359589 47.001213 56489 7.261612 10.947571 44.848869 56490 6.982346 11.148346 47.311478 56491 7.665771 10.319702 47.388710 56492 7.798889 10.287918 46.564812 56493 6.943703 11.138443 45.972191 56494 44.788513 11.810455 47.743515 56495 44.381256 11.996429 47.328331 56496 20.300095 10.728333 46.389084 56497 20.788635 10.682220 47.230652 56498 21.512123 11.195770 46.536407 56499 24.632370 12.197998 47.041275 56500 22.958832 11.787613 47.002411 56501 44.450775 8.935272 47.124390 56502 8.526260 9.233643 45.753387 56503 43.473328 8.224533 46.645538 56504 8.358627 6.796738 45.591545 56505 37.719162 6.972656 47.117798 56506 41.562408 7.655304 47.555405 56507 37.002182 5.811417 46.647469 56508 38.988358 7.356323 47.117943 56509 38.265709 7.668488 48.084885 56510 47.195358 3.753983 45.589180 56511 7.048477 4.747330 45.141617 56512 5.817368 5.159042 45.915466 56513 50.125671 4.502136 46.802750 56514 5.032921 3.518707 45.102448 56515 4.355324 3.467377 45.719337 56516 3.615601 2.344742 46.259895 56517 5.253975 3.952629 45.504326 56518 3.284256 1.160599 46.032074 56519 3.620064 1.356674 46.920471 56520 41.006668 2.243317 46.762810 56521 47.367676 -0.851135 45.877502 56522 41.221436 0.720184 46.624580 56523 51.309891 0.121689 45.956337 56524 3.057579 -0.850388 46.725189 56525 3.256355 0.394089 46.535759 56526 42.090683 -0.795502 48.201546 56527 41.738251 0.760712 47.225685 56528 50.387817 -0.742996 46.126022 56529 51.218918 -0.556549 45.771889 56530 50.819778 0.031113 46.310654 56531 38.921448 -2.044968 45.283905 56532 48.447800 -2.085312 45.684875 56533 48.395111 -1.284210 46.032356 56534 50.981232 -4.359131 45.310257 56535 51.676605 -4.520737 45.946388 56536 8.363876 -5.642883 46.256683 56537 9.141471 -5.152710 44.649460 56538 40.838394 -3.223190 46.569809 56539 40.377472 -3.025726 46.162033 56540 51.336884 -4.943497 46.926132 56541 52.683868 -4.827316 46.716507 56542 42.178558 -4.316513 46.800827 56543 47.699844 -5.626755 46.272209 56544 53.878601 -7.498932 46.362717 56545 53.890259 -6.516617 46.680763 56546 10.971222 -8.152222 45.090431 56547 3.852394 -9.154922 44.586906 56548 5.156593 -9.024689 44.294121 56549 4.396172 -9.153625 45.294579 56550 6.427734 -9.911224 46.184990 56551 5.387528 -9.503128 45.656303 56552 10.871254 -10.372314 47.329811 56553 10.052406 -10.891769 46.903229 56554 10.153580 -10.428467 46.001411 56555 10.732513 -8.638092 44.698517 56556 3.352379 -9.529587 45.282715 56557 3.306778 -9.951645 44.478844 56558 10.599159 -9.583282 45.150810 56559 3.533760 -10.792145 43.909233 56560 8.890564 -10.326843 45.159218 56561 7.705749 -10.366058 46.138321 56562 53.459793 -8.598724 46.597633 56563 3.791832 -13.717148 44.955177 56564 4.146050 -13.460495 43.968765 56565 52.048752 -11.525528 47.921158 56566 4.110031 -14.628479 44.047920 56567 48.920044 -14.495667 45.466942 56568 3.842171 -18.729370 45.441063 56569 3.325516 -19.152969 45.484207 56570 4.660645 -15.312988 44.600357 56571 5.952507 -15.932617 44.478851 56572 5.761505 -15.276871 45.175674 56573 6.785767 -15.927505 44.469261 56574 8.137482 -15.928055 44.431213 56575 8.754990 -15.489578 45.085983 56576 9.844254 -15.683762 45.081963 56577 48.233887 -14.922058 44.685204 56578 7.526665 -16.786118 44.175537 56579 6.257843 -16.926010 44.519730 56580 4.495331 -17.292297 44.713005 56581 5.255051 -16.034973 44.577362 56582 12.026047 -17.805847 44.552574 56583 54.427307 -16.009888 45.039894 56584 55.702759 -16.138382 45.681671 56585 56.830383 -16.821213 45.274918 56586 56.380798 -16.829941 46.803680 56587 11.390732 -16.803604 44.855659 56588 47.206802 -16.809921 45.183670 56589 53.424179 -16.527954 45.402626 56590 52.189972 -17.542328 45.154175 56591 52.611877 -16.981369 45.944046 56592 7.560242 -17.830353 44.322830 56593 32.941544 -18.423752 46.273010 56594 39.333031 -18.479782 44.675797 56595 40.245270 -18.581894 45.171967 56596 41.509109 -18.716141 45.686829 56597 42.286118 -18.400238 44.842873 56598 46.277222 -17.500244 46.028885 56599 51.607422 -18.016815 45.025314 56600 3.221710 -19.808289 44.785828 56601 31.491989 -20.046967 44.560791 56602 50.538208 -18.736221 44.763214 56603 56.998840 -18.736496 45.397743 56604 3.548782 -20.259155 43.811111 56605 31.253662 -21.056396 45.085754 56606 31.956652 -21.457367 45.283539 56607 47.055084 -20.840103 45.215622 56608 48.807022 -19.696014 44.512405 56609 4.059937 -20.957123 43.744797 56610 4.577400 -21.565521 43.934830 56611 33.930832 -21.315445 45.228577 56612 36.207047 -21.335526 45.462433 56613 37.413544 -21.583603 45.622009 56614 45.233276 -21.619080 45.597603 56615 53.494385 -21.503311 45.600052 56616 5.079277 -22.755783 43.945778 56617 5.146706 -22.056580 44.713112 56618 8.278557 -21.196106 44.496826 56619 8.412994 -23.049698 44.606071 56620 13.399124 -23.607422 43.843826 56621 50.729752 -23.736969 45.728180 56622 51.417175 -23.244934 45.696106 56623 4.638291 -23.814072 43.930824 56624 5.912155 -22.766190 44.941353 56625 5.695053 -23.897186 44.950600 56626 9.603409 -23.853745 43.715454 56627 2.334679 -25.804794 42.978302 56628 2.278626 -25.600067 44.245506 56629 3.651924 -24.491150 44.325829 56630 9.787224 -24.919601 43.571678 56631 13.501740 -24.334579 43.504318 56632 55.188446 -24.657150 44.952377 56633 2.869042 -24.823761 44.258835 56634 2.820007 -25.096832 44.991959 56635 9.779587 -25.935562 43.796906 56636 13.763115 -25.134048 43.553543 56637 56.084564 -24.394455 45.533073 56638 57.011963 -24.425156 45.740463 56639 2.537003 -26.868912 43.334244 56640 46.527802 -26.358383 45.340385 56641 44.397675 -27.681229 45.419235 56642 45.466751 -26.978592 45.316345 56643 44.967499 -26.969131 44.477509 56644 14.308189 -29.331390 43.766891 56645 42.678482 -28.475037 44.429581 56646 4.050362 -28.874985 43.534081 56647 14.401031 -29.797714 43.880165 56648 15.148079 -29.388199 44.515190 56649 14.740509 -30.376953 44.105324 56650 33.498047 -29.275848 43.496483 56651 32.198853 -30.023621 43.415161 56652 37.242180 -30.614746 47.838806 56653 36.025856 -30.534653 46.843216 56654 35.708221 -31.292694 47.605293 56655 37.246017 -28.855209 43.658707 56656 38.672073 -29.211166 43.882637 56657 41.773239 -28.770065 44.035164 56658 41.444336 -29.173660 45.613029 56659 49.999298 -28.701401 45.084000 56660 51.841858 -27.881088 46.231232 56661 51.315903 -27.963425 45.195137 56662 57.761841 -28.607529 44.852783 56663 57.892502 -26.931458 45.318268 56664 32.743462 -30.451599 44.225464 56665 31.561653 -30.982697 43.863518 56666 46.807953 -30.677490 45.724403 56667 45.887146 -31.295151 45.240921 56668 47.623505 -29.935791 44.532661 56669 49.075485 -29.270706 45.491127 56670 57.302032 -30.075165 45.004158 56671 56.917297 -30.918167 45.032249 56672 11.490402 -30.888016 44.216072 56673 13.825783 -32.417603 43.113312 56674 13.296051 -31.776215 43.186241 56675 14.060013 -31.237686 43.692459 56676 3.411987 -31.942856 44.195641 56677 3.446083 -30.423325 44.811356 56678 2.772408 -31.612213 45.223976 56679 4.361534 -30.719696 43.566040 56680 3.893898 -29.477463 44.140198 56681 10.648483 -32.582687 43.826637 56682 10.876022 -33.283829 43.107376 56683 10.847443 -31.663712 44.375381 56684 14.453873 -32.136047 43.888519 56685 30.826248 -32.156158 44.190498 56686 4.227059 -33.246567 42.743317 56687 3.942383 -32.251862 43.300011 56688 37.758896 -33.141037 44.655670 56689 38.707695 -33.042496 44.682030 56690 45.175674 -31.707550 45.018929 56691 54.437454 -32.550705 44.871147 56692 54.746582 -32.678360 43.779373 56693 55.774780 -32.113358 44.375824 56694 3.868507 -34.187698 43.070732 56695 10.380554 -33.780823 43.507790 56696 51.520233 -33.147888 44.362244 56697 4.060188 -35.699249 43.030952 56698 13.877388 -36.290451 43.010971 56699 10.291854 -36.918625 44.992584 56700 9.557831 -35.287186 44.586479 56701 10.733139 -35.652344 43.732185 56702 13.192780 -36.810913 42.975624 56703 14.439751 -36.366806 44.039413 56704 27.319962 -35.424805 43.154358 56705 36.521362 -33.909744 45.133018 56706 48.227188 -36.644547 43.586830 56707 48.652771 -36.014816 45.099304 56708 25.666031 -37.204773 43.078690 56709 31.996469 -37.439697 44.345009 56710 53.021912 -37.275589 42.775955 56711 55.565689 -38.246231 43.724968 56712 3.165238 -37.438446 45.003838 56713 12.412476 -37.268478 43.592163 56714 25.196091 -38.147766 43.107353 56715 48.297928 -37.645599 43.436829 56716 25.174728 -37.627350 44.243103 56717 24.397766 -38.256454 45.389931 56718 25.519531 -36.627045 46.088058 56719 24.836967 -39.035110 43.351791 56720 29.655273 -38.396454 42.907822 56721 29.604675 -38.621155 45.095436 56722 31.177368 -38.011322 45.421745 56723 40.745331 -39.033249 43.472534 56724 48.666046 -37.580368 44.139816 56725 4.172028 -40.708771 42.462402 56726 24.683670 -39.818604 43.434479 56727 26.238914 -40.088089 43.513939 56728 27.530609 -39.462906 43.785507 56729 28.486801 -38.927444 42.961761 56730 49.467789 -38.827377 44.194092 56731 54.993637 -38.586685 43.516022 56732 6.049851 -41.099823 42.725098 56733 5.045166 -41.087708 42.577248 56734 9.808388 -42.164719 43.184174 56735 10.219246 -42.035538 42.674133 56736 24.866119 -40.368286 43.625824 56737 37.600739 -41.004028 44.394897 56738 42.793762 -39.620605 44.479401 56739 55.524170 -41.406158 42.837318 56740 4.484581 -41.034027 42.455429 56741 36.277084 -44.042191 43.483376 56742 36.788437 -42.820374 42.825127 56743 36.992599 -42.855743 43.316696 56744 40.523071 -43.498398 43.089767 56745 35.243958 -44.824600 43.267838 56746 8.654678 -44.054245 43.258125 56747 8.860626 -43.253738 44.407471 56748 8.488113 -43.589111 44.967499 56749 8.059021 -44.081589 44.178001 56750 34.428726 -45.115189 43.163719 56751 50.743256 -41.656891 44.324486 56752 50.682678 -43.616623 44.442070 56753 30.200592 -46.272751 42.552429 56754 30.715347 -45.826584 42.612083 56755 34.243530 -45.751236 44.595505 56756 45.672958 -45.866058 44.044327 56757 5.109329 -45.388931 43.586250 56758 5.054321 -48.213882 42.060471 56759 5.218269 -47.297302 43.006744 56760 43.452576 -46.631485 42.857933 56761 5.440132 -48.213165 42.592110 56762 29.848022 -47.458435 42.828903 56763 33.255814 -49.608887 42.189270 56764 33.518387 -49.687149 42.732170 56765 35.112923 -48.952087 42.922195 56766 35.891113 -48.755936 42.797913 56767 36.759979 -48.662918 43.104782 56768 42.699173 -48.027283 42.658302 56769 47.071808 -49.082794 43.256744 56770 46.613312 -49.788269 44.383362 56771 49.985962 -49.257675 43.594635 56772 49.093384 -49.219254 43.754478 56773 33.291451 -50.040710 42.457985 56774 3.998154 -52.806732 42.115883 56775 26.959770 -51.509613 43.219421 56776 26.140091 -52.730591 43.125870 56777 26.314774 -52.522400 41.978592 56778 25.695206 -53.022583 44.335701 56779 25.784561 -53.992737 43.708237 56780 26.214874 -52.551895 42.319016 56781 26.552200 -53.306427 42.185661 56782 52.953674 -51.115845 43.501144 56783 52.482468 -52.373703 44.371414 56784 4.938904 -53.729156 42.083923 56785 4.632073 -52.301483 42.764450 56786 5.103561 -53.071777 42.739998 56787 9.273987 -54.432083 42.058029 56788 9.528137 -55.629745 41.753159 56789 9.933533 -54.937637 42.096870 56790 27.653793 -54.080490 42.404488 56791 26.967079 -54.474533 43.167267 56792 29.614334 -54.213913 42.778503 56793 28.737892 -54.548325 43.277046 56794 31.666826 -54.631165 43.068886 56795 32.491913 -55.213852 43.878441 56796 31.361664 -54.802612 44.195663 56797 36.080109 -53.061523 43.866791 56798 42.376419 -54.062042 42.710815 56799 45.713013 -54.048721 43.398903 56800 47.286926 -53.653366 42.596252 56801 49.753265 -54.941971 43.367622 56802 8.986481 -55.649979 41.418823 56803 10.047112 -55.591721 42.115952 56804 32.526917 -55.332809 42.153023 56805 40.132492 -54.857056 43.073433 56806 8.626556 -56.332443 41.645721 56807 33.208229 -56.107559 42.228661 56808 7.290375 -56.525665 41.083267 56809 34.936493 -57.467682 42.216270 56810 51.062378 -55.427292 43.203629 56811 51.746048 -56.154465 42.203278 56812 51.136948 -56.032166 42.133759 56813 4.132042 -58.582245 41.863762 56814 7.566986 -57.055130 41.855736 56815 37.043289 -58.292068 42.158821 56816 43.569580 -58.117752 42.105598 56817 44.358887 -58.020142 42.169548 56818 37.782364 -58.656631 42.781876 56819 40.190308 -58.899246 42.446777 56820 39.015503 -59.121170 43.038200 56821 40.865067 -59.337570 43.609550 56822 39.958008 -59.426010 43.679268 56823 3.754486 -62.684219 42.647034 56824 3.585045 -60.906342 43.396576 56825 3.791786 -62.287704 43.942093 56826 6.882668 -63.319107 40.931435 56827 7.822776 -63.431015 40.837921 56828 24.345001 -61.534561 42.058266 56829 4.768761 -63.617523 41.787384 56830 23.391724 -62.078827 42.327057 56831 29.949821 -63.944580 40.643593 56832 47.441467 -62.883881 43.133987 56833 47.954208 -61.873596 43.301231 56834 3.689209 -63.118317 43.468941 56835 4.019112 -63.239914 44.194962 56836 4.106110 -63.950821 43.334801 56837 6.535568 -65.056458 41.349716 56838 8.331512 -64.236786 40.573433 56839 8.977158 -63.873291 40.290573 56840 23.510391 -62.992004 42.189491 56841 33.836487 -64.016434 42.150955 56842 34.416924 -64.187195 43.205475 56843 34.998550 -64.110718 42.567596 56844 35.470062 -64.465485 42.096977 56845 39.612900 -65.248047 41.930717 56846 39.780930 -65.336517 42.577301 56847 40.056061 -64.945221 42.417023 56848 47.319778 -63.459686 42.221886 56849 7.748992 -65.080673 40.543983 56850 7.265610 -64.379959 41.096542 56851 27.964813 -64.210236 42.754402 56852 27.919937 -64.709030 43.598885 56853 28.250687 -65.251175 43.331131 56854 28.737015 -65.499954 42.725685 56855 35.844864 -65.334763 42.846199 56856 35.540817 -66.076996 41.642677 56857 41.793365 -64.636566 42.180626 56858 42.717087 -64.742950 41.958977 56859 45.571533 -64.762833 42.437668 56860 29.829742 -65.107208 41.946571 56861 31.432419 -65.875412 42.590881 56862 39.338715 -65.763565 41.484100 56863 39.402992 -66.207977 41.583824 56864 44.149887 -65.162048 42.566353 56865 4.637749 -68.022263 40.559067 56866 17.991226 -67.276306 41.229538 56867 39.658752 -66.776993 41.974915 56868 17.445984 -72.104126 40.708031 56869 17.169632 -71.104843 41.584122 56870 19.775101 -69.352554 42.043045 56871 20.678802 -70.632095 41.144394 56872 26.349854 -69.268509 41.102295 56873 25.340790 -68.783478 42.047646 56874 29.696793 -69.587250 40.784332 56875 16.850693 -69.769302 42.041443 56876 16.932632 -68.861481 41.935966 56877 26.248062 -69.945877 41.710609 56878 27.106316 -69.648727 41.087585 56879 29.787804 -70.092300 41.187378 56880 34.826248 -70.090805 40.615318 56881 27.213921 -70.094543 41.534256 56882 17.565369 -71.907196 40.065475 56883 30.913712 -73.310638 43.127228 56884 17.618439 -72.718048 40.626457 56885 17.623856 -73.025070 40.555931 56886 17.727615 -72.959076 40.742653 56887 39.297340 -72.820526 41.684814 56888 13.011719 -75.050766 40.505684 56889 17.649353 -73.147705 40.755798 56890 21.630753 -73.595291 41.956543 56891 20.929001 -71.772995 41.968491 56892 21.042770 -72.393524 43.022568 56893 39.762978 -72.703705 41.396011 56894 5.582840 -75.645035 40.136665 56895 17.165283 -74.458435 41.133919 56896 16.377319 -75.017410 40.947769 56897 11.641418 -75.932999 40.497803 56898 10.765091 -77.064423 40.723251 56899 12.264931 -77.018845 41.660065 56900 12.639580 -76.149948 41.163528 56901 15.980522 -75.748734 41.611961 56902 16.928535 -75.360184 42.009262 56903 31.610567 -76.780457 42.114212 56904 7.623657 -78.297455 40.144997 56905 6.914757 -77.876083 41.219170 56906 9.528763 -78.259186 40.743973 56907 31.309784 -74.577164 41.872421 56908 7.880577 -78.863327 40.776276 56909 8.400574 -78.617783 40.317429 56910 18.464584 -78.483200 39.836403 56911 19.974937 -78.985184 40.560074 56912 20.600212 -78.564026 39.846214 56913 21.133377 -79.077209 40.088310 56914 31.374443 -78.878845 40.690132 56915 8.663956 -79.240082 41.083847 56916 26.235931 -79.551361 40.585983 56917 13.128616 -81.124329 40.541443 56918 12.077774 -82.022079 40.629494 56919 28.302414 -81.182449 40.633492 56920 31.082977 -79.813736 41.256630 56921 10.274208 -82.807053 39.501862 56922 24.626122 -83.557816 39.898148 56923 29.068092 -81.511658 40.261322 56924 17.448425 -84.017700 40.935493 56925 16.855736 -85.004837 39.903267 56926 24.285736 -83.647217 40.155411 56927 18.424454 -83.424255 41.196442 56928 18.018539 -82.699112 42.354401 56929 12.376053 -84.695236 39.841713 56930 13.308861 -85.290863 39.680710 56931 14.605988 -85.480072 40.012077 56932 15.909515 -85.114578 40.636734 56933 15.913742 -85.679398 39.633240 56934 15.000389 -84.698700 41.278343 56935 6.081238 46.444931 50.450874 56936 7.677886 46.627747 50.260735 56937 6.619537 45.787811 50.867950 56938 5.726349 48.231461 48.638748 56939 6.151749 47.898575 49.113457 56940 6.130974 47.131714 49.698189 56941 8.951340 45.891724 49.993950 56942 9.906265 45.678055 49.341080 56943 10.458931 45.813873 49.020149 56944 11.856949 46.244781 48.399925 56945 14.169861 41.471588 49.024139 56946 15.109985 41.498184 50.400238 56947 17.905426 41.240509 50.815216 56948 16.650070 41.211090 50.958282 56949 10.811111 39.278458 48.501762 56950 11.520035 39.477127 49.291298 56951 22.170464 40.555435 49.155357 56952 9.697952 38.432541 48.338493 56953 22.084061 39.364716 48.888428 56954 8.872161 39.089783 48.577980 56955 8.184464 39.133759 48.788063 56956 9.303833 36.668076 48.006737 56957 10.026520 36.819107 48.563568 56958 10.735420 38.169434 48.784943 56959 11.195510 38.027740 49.606918 56960 21.530708 38.377258 49.459190 56961 27.213013 36.493652 48.597679 56962 26.944664 36.441452 48.395447 56963 10.654205 36.930740 49.135399 56964 19.481491 36.231247 48.605629 56965 8.997650 35.589020 48.656700 56966 9.867371 36.022568 49.351677 56967 18.474197 35.388641 47.572533 56968 27.215889 35.687134 48.582466 56969 7.940811 34.946350 48.166504 56970 27.176666 34.557449 48.406509 56971 30.845879 34.362244 48.631683 56972 30.025589 34.774231 49.271820 56973 5.672272 33.148239 48.260689 56974 6.289177 33.513687 48.381844 56975 27.894989 34.673859 49.197746 56976 27.643379 33.702515 48.629517 56977 21.508690 33.350677 48.681908 56978 22.443054 32.455414 49.715500 56979 22.104752 32.920105 49.324074 56980 22.254906 31.998535 49.174759 56981 5.399185 32.600616 49.162323 56982 31.882586 31.146210 48.659195 56983 4.873757 31.178574 49.211739 56984 4.468216 31.315689 50.158882 56985 4.203552 30.213425 50.308609 56986 5.415695 28.646942 47.348938 56987 19.371605 28.719513 48.937233 56988 18.240646 27.811798 48.744278 56989 17.284805 25.793381 48.398155 56990 25.745209 25.627228 47.998901 56991 26.841507 25.837555 48.343719 56992 30.042831 25.918976 48.692337 56993 29.153419 25.956924 48.457565 56994 34.907814 25.778687 49.487396 56995 35.222641 25.297699 48.582817 56996 35.629311 25.118942 50.326172 56997 4.182404 23.938187 48.134216 56998 16.929565 23.264236 47.903854 56999 17.275978 23.824371 48.675987 57000 16.957062 24.482651 47.798668 57001 26.296135 25.717758 48.153656 57002 36.556259 24.499878 48.382683 57003 4.326508 22.886337 47.429398 57004 17.113876 23.043823 48.330124 57005 5.235802 21.528229 47.023537 57006 30.466583 22.355453 48.539810 57007 30.545883 22.934555 49.280556 57008 40.098969 21.728668 48.677406 57009 39.023849 22.332596 49.114334 57010 6.293915 21.369873 47.520218 57011 27.239151 23.798767 49.326553 57012 28.058983 22.464447 48.249138 57013 30.581818 21.894775 48.221558 57014 31.264709 22.101242 48.899643 57015 8.219453 19.847656 47.348099 57016 19.354492 21.011902 48.603058 57017 22.251045 19.668503 48.167435 57018 21.050941 20.317703 48.295601 57019 21.913376 20.924561 49.619293 57020 20.128250 20.369858 47.951012 57021 31.260544 21.104019 48.541893 57022 8.406953 19.102127 47.258171 57023 8.393173 19.000336 47.796593 57024 8.566849 19.376129 47.638954 57025 29.100746 17.276031 48.560181 57026 29.713684 18.293182 49.579765 57027 42.520767 18.235123 48.071541 57028 6.640961 17.780853 48.019157 57029 5.845413 16.957397 47.185913 57030 28.350502 15.923035 47.961868 57031 36.219749 16.436890 47.766388 57032 35.616104 15.362610 47.886406 57033 35.797493 16.148254 48.621071 57034 36.395737 16.564636 48.667168 57035 4.671455 17.204300 48.961479 57036 5.097488 17.946335 49.552803 57037 4.216042 17.271896 50.267784 57038 28.047333 15.027451 48.719955 57039 27.477341 14.505951 47.687721 57040 20.094727 14.523529 47.409645 57041 20.898041 15.063019 48.056808 57042 22.046814 15.555069 47.509254 57043 35.398460 15.786362 49.074524 57044 17.472153 13.090958 47.699310 57045 18.556801 14.117737 48.105141 57046 35.859634 13.909729 48.106247 57047 36.827316 13.606003 47.474709 57048 37.107086 13.183105 48.814224 57049 39.780785 13.093231 47.964424 57050 38.763672 13.138824 48.658867 57051 41.458618 12.937119 48.707825 57052 43.814774 12.388412 48.053345 57053 43.927521 12.254654 49.449135 57054 5.498787 12.077240 46.781876 57055 18.826889 9.350754 46.827591 57056 18.201141 8.991837 46.993790 57057 18.075951 9.997406 46.769051 57058 17.209152 11.025848 47.483658 57059 22.731117 12.106796 48.322166 57060 23.872482 12.505493 48.204910 57061 25.743286 12.808884 47.361412 57062 19.240273 10.265396 46.530396 57063 20.052917 10.079376 47.137581 57064 8.431915 8.503143 46.146652 57065 19.554916 9.295273 47.124664 57066 44.981949 11.321442 48.334526 57067 16.430824 9.110657 48.608429 57068 16.341873 9.774551 48.514297 57069 16.634552 9.323380 48.105362 57070 18.930756 8.362000 47.295715 57071 45.181366 10.098541 47.517357 57072 45.106766 9.952408 48.477539 57073 4.987206 6.050735 46.654533 57074 5.705055 7.007401 46.951408 57075 4.382881 7.081131 47.720184 57076 7.073219 6.784180 46.270721 57077 6.278229 8.003525 47.349106 57078 39.642715 7.721542 47.758575 57079 38.954529 7.723618 47.949715 57080 40.435944 7.476364 47.188217 57081 40.452942 7.814117 48.716980 57082 43.127258 8.209473 48.068108 57083 3.964752 5.519096 47.179062 57084 8.009323 7.932312 46.344292 57085 21.364822 7.088318 47.307564 57086 21.449860 6.141785 46.905846 57087 20.653778 6.057739 47.291519 57088 24.298355 8.025208 49.659706 57089 25.064003 6.881989 49.098816 57090 24.351639 7.002914 48.288200 57091 23.921509 6.398285 47.532280 57092 23.116272 6.258850 47.113892 57093 22.794144 7.528091 48.079735 57094 23.676636 5.640854 47.170296 57095 37.476273 7.544952 48.282425 57096 36.969650 7.198944 48.245216 57097 39.756210 7.456848 47.056206 57098 4.847817 5.133408 46.381355 57099 4.959549 4.392212 46.016289 57100 4.154869 4.419647 46.623245 57101 19.243484 6.841095 47.859985 57102 20.160187 8.108719 47.534180 57103 21.745903 5.173447 46.988251 57104 22.210136 6.259720 47.017143 57105 22.872620 5.235695 47.040443 57106 24.091843 5.659286 47.457916 57107 49.245239 5.397987 46.519363 57108 20.870972 4.219696 47.675064 57109 19.903198 5.496063 48.052956 57110 49.415649 4.870239 46.780525 57111 3.440109 4.470901 47.536171 57112 3.599678 3.504478 46.938065 57113 20.456192 3.577896 48.275902 57114 20.070847 4.391113 48.661652 57115 36.142502 4.844719 48.448875 57116 36.275955 5.733414 48.075745 57117 36.795662 4.809525 47.122597 57118 39.955185 3.030960 46.669540 57119 40.031601 3.364792 47.422768 57120 39.030884 3.389755 46.920731 57121 37.246704 3.991989 47.660339 57122 49.430664 4.031082 47.097420 57123 48.779297 3.276321 47.032799 57124 40.475922 3.784592 48.238434 57125 41.330750 3.391289 47.859581 57126 50.244049 1.876907 46.904251 57127 49.932556 3.080017 47.052055 57128 50.127365 3.852806 47.029182 57129 42.227753 2.270676 47.830856 57130 42.371277 0.909103 47.829285 57131 42.905075 1.239899 48.442627 57132 50.216034 0.474487 46.718964 57133 50.236710 1.091766 46.914986 57134 48.211472 0.023285 46.386307 57135 49.456345 -0.324722 46.447662 57136 49.327393 0.941864 46.953743 57137 50.236984 -0.111282 46.489807 57138 48.120270 1.227707 46.670792 57139 3.390762 -4.512802 46.362808 57140 6.949410 -5.983887 47.236687 57141 43.617645 -5.276550 46.491135 57142 44.256287 -5.645081 46.560410 57143 51.929031 -4.820755 47.773346 57144 44.810699 -5.698730 46.644073 57145 45.378265 -5.361908 47.550056 57146 47.281128 -5.421051 47.517052 57147 46.324081 -5.575623 47.190025 57148 48.589569 -5.475494 47.424492 57149 49.441376 -5.623245 46.654877 57150 3.789871 -9.206635 45.399117 57151 3.831452 -9.653397 46.257782 57152 37.059799 -8.976730 46.518768 57153 35.997757 -8.517166 46.958702 57154 37.164345 -7.993759 47.691811 57155 36.093254 -9.574097 46.187859 57156 38.182724 -8.949097 46.672104 57157 38.640656 -8.003006 47.761833 57158 39.652847 -8.892319 46.961044 57159 40.189819 -9.967834 46.232880 57160 39.138527 -10.070190 46.199028 57161 52.792145 -10.560104 46.841606 57162 53.099854 -9.770996 46.659546 57163 2.982025 -10.049103 45.187828 57164 3.008392 -9.871063 45.663742 57165 2.804344 -10.215775 45.531868 57166 11.065475 -8.574951 45.712502 57167 33.639084 -9.581299 46.607697 57168 33.168938 -10.564911 46.645500 57169 32.473022 -9.722565 47.208267 57170 35.447983 -10.439346 46.052330 57171 34.647171 -9.801559 46.206047 57172 34.556534 -8.703888 47.213654 57173 35.344696 -8.983032 46.528938 57174 36.244240 -10.655243 46.173416 57175 37.650116 -10.517593 46.290451 57176 40.893295 -9.617462 46.577187 57177 41.217773 -8.934357 47.586494 57178 39.831749 -7.993744 48.238220 57179 40.941589 -7.801880 49.218796 57180 41.147858 -10.574036 46.188095 57181 3.068787 -10.735001 45.158081 57182 33.783218 -10.088089 46.180161 57183 33.945526 -10.538467 46.176880 57184 34.709412 -10.891357 46.347717 57185 40.244232 -11.247955 46.166901 57186 39.058624 -11.030273 46.101341 57187 42.151138 -10.389404 46.626732 57188 2.804100 -11.363983 46.197021 57189 2.855614 -12.914276 46.504906 57190 33.847298 -11.113815 46.673683 57191 35.604263 -11.037384 46.358406 57192 36.393471 -11.374680 46.924370 57193 35.320168 -11.350220 46.881248 57194 44.851257 -11.138672 47.137421 57195 44.764114 -11.836365 46.445717 57196 43.783661 -11.456482 46.515182 57197 42.213104 -12.159760 46.354042 57198 45.448456 -12.293304 46.796013 57199 45.623444 -11.028946 48.113937 57200 39.206192 -11.767044 46.598625 57201 39.908157 -12.421066 47.235733 57202 40.873840 -12.576523 47.057510 57203 39.054039 -11.970993 47.545456 57204 44.628784 -12.477539 46.239922 57205 46.382431 -12.324875 47.414886 57206 43.873688 -13.020645 46.233574 57207 44.998123 -13.417862 46.374916 57208 45.435196 -14.453049 46.765839 57209 46.130295 -13.453583 46.890739 57210 50.321365 -12.954514 48.916031 57211 50.090607 -12.838959 49.930138 57212 50.966095 -12.469772 49.573959 57213 3.510506 -14.163559 45.960495 57214 2.780930 -13.864441 46.629723 57215 3.014267 -14.301392 46.698067 57216 4.493012 -14.666885 45.348984 57217 4.562554 -16.065842 44.499580 57218 7.228043 -15.320358 45.244415 57219 8.037125 -15.303452 45.128868 57220 44.345764 -14.021057 46.508278 57221 43.437454 -13.757950 46.715157 57222 44.465729 -14.611542 46.941048 57223 10.140244 -15.769592 46.080856 57224 10.768906 -15.914825 45.391563 57225 10.775368 -15.905289 46.106812 57226 47.984467 -15.448303 46.381859 57227 47.325623 -16.670532 45.927643 57228 12.031372 -17.366623 45.095612 57229 54.558472 -16.175110 46.383957 57230 55.562805 -16.370514 47.052391 57231 4.830956 -18.816284 45.534599 57232 5.747574 -18.077866 45.094460 57233 6.692772 -18.028931 44.739029 57234 12.166977 -17.768585 45.127029 57235 46.856384 -17.122391 45.964104 57236 56.905014 -17.319519 46.249001 57237 7.399551 -18.723724 44.655342 57238 12.144226 -18.478348 45.078049 57239 32.581726 -18.749252 47.369026 57240 31.604296 -19.047043 46.759705 57241 37.183029 -18.248260 45.369942 57242 38.724655 -18.552063 45.952888 57243 46.662994 -16.858719 46.686302 57244 45.699554 -17.589111 47.096474 57245 51.867477 -17.584167 46.084831 57246 3.172157 -19.422577 45.294357 57247 6.600174 -18.871887 45.119926 57248 7.476090 -19.759872 44.909157 57249 12.308022 -20.037415 45.146103 57250 40.442047 -18.762253 47.013557 57251 42.441895 -19.097382 47.519997 57252 42.740570 -19.087997 47.598000 57253 43.128326 -18.768692 46.449455 57254 44.640411 -18.435196 46.837769 57255 43.791626 -18.715454 47.689392 57256 49.665115 -19.412323 45.763176 57257 56.590057 -19.090958 46.345642 57258 3.941605 -20.730240 44.691353 57259 11.242860 -19.579788 46.789742 57260 11.923196 -21.514038 45.980637 57261 30.700287 -20.572540 45.548569 57262 56.020615 -19.974548 46.100693 57263 55.213394 -20.783478 46.582138 57264 3.969437 -19.848694 45.500824 57265 4.879433 -21.115829 45.227943 57266 12.685165 -21.372299 45.192650 57267 12.992630 -21.501831 44.366875 57268 30.647659 -21.288864 45.635185 57269 31.193054 -19.532211 45.565559 57270 32.913040 -21.299438 45.018944 57271 34.976364 -21.461029 46.201279 57272 39.198395 -21.956345 46.306450 57273 46.377563 -21.445526 48.555069 57274 45.704071 -21.929138 47.587051 57275 46.848480 -21.186478 46.837830 57276 48.318756 -20.327560 45.828690 57277 44.778473 -22.265182 47.634865 57278 45.283875 -22.031433 46.813423 57279 54.386566 -20.901794 45.627243 57280 54.251770 -21.476929 46.669556 57281 4.701050 -24.515121 45.097519 57282 13.175858 -22.860703 44.429939 57283 31.224884 -21.659103 45.743340 57284 40.928314 -22.309250 45.731247 57285 41.989212 -22.247940 45.961174 57286 43.178192 -22.156387 45.864182 57287 44.074921 -21.972733 45.690323 57288 51.892990 -22.932190 45.832268 57289 53.318130 -22.114120 46.651848 57290 52.554352 -22.241760 45.558464 57291 52.455475 -22.856277 46.706795 57292 12.750137 -23.666214 45.334053 57293 12.798264 -22.281342 45.169327 57294 12.450783 -22.562790 45.622910 57295 13.261917 -23.631882 44.490433 57296 40.194183 -22.272598 45.697769 57297 44.088913 -22.213593 46.827538 57298 6.933258 -25.441650 45.991592 57299 7.910217 -26.941772 46.153862 57300 6.256355 -26.172379 46.794739 57301 13.482742 -24.476761 44.408493 57302 49.500244 -24.722122 45.934555 57303 50.411316 -24.451187 46.840385 57304 8.859024 -25.196182 44.662354 57305 13.962907 -25.763702 44.723610 57306 54.794022 -25.628937 46.378960 57307 2.201325 -26.753006 44.570061 57308 9.463562 -26.723419 44.597267 57309 47.789108 -25.732376 46.091347 57310 13.910767 -26.138321 45.581314 57311 14.424774 -26.632278 45.470139 57312 14.607971 -26.716858 44.380676 57313 3.071625 -28.179276 44.260681 57314 2.351647 -27.515747 45.146675 57315 2.652039 -28.355804 45.337242 57316 3.171936 -29.198364 45.063965 57317 14.993843 -27.418304 44.604248 57318 43.260422 -28.444763 45.472733 57319 43.920197 -28.306213 46.236382 57320 51.414520 -28.265427 47.174637 57321 53.044342 -27.331879 47.201965 57322 57.287781 -27.718628 46.391144 57323 57.418961 -26.884537 46.383072 57324 4.537872 -29.542526 43.476883 57325 12.342216 -29.985794 43.843681 57326 34.064590 -30.197876 44.836273 57327 35.738983 -29.443253 45.047264 57328 36.178314 -28.925980 44.301346 57329 36.782211 -29.524292 45.829407 57330 35.351761 -30.219284 45.868523 57331 11.123581 -29.262451 44.295296 57332 13.307952 -30.584091 43.694244 57333 14.057388 -30.308441 43.805763 57334 15.173462 -30.320251 44.580132 57335 13.298645 -31.186096 43.490959 57336 14.884430 -31.211136 44.535698 57337 15.362869 -30.256958 45.422302 57338 15.127594 -31.398010 45.300804 57339 32.501770 -31.658539 45.300652 57340 34.044510 -30.885010 45.697495 57341 33.791687 -31.419708 46.138763 57342 56.446884 -31.473969 45.071762 57343 14.625870 -32.339172 45.196999 57344 29.808182 -33.538910 44.572762 57345 3.389237 -33.218933 43.683182 57346 8.106476 -31.200119 47.000473 57347 7.836044 -29.047440 47.298210 57348 8.817909 -29.328568 46.416893 57349 39.545837 -33.385757 46.068420 57350 41.501678 -33.151886 45.241165 57351 44.288300 -32.403732 45.519272 57352 50.765411 -32.921753 45.426353 57353 49.989838 -33.068146 44.984375 57354 53.829529 -32.463959 46.178986 57355 55.389832 -31.879379 45.942657 57356 51.818375 -32.796417 45.608673 57357 9.901276 -33.768036 44.142532 57358 27.849350 -35.276505 45.365585 57359 9.157990 -36.737976 45.692375 57360 8.310546 -34.901703 45.519188 57361 8.922859 -34.830902 45.015800 57362 14.807213 -37.543488 44.628555 57363 14.592880 -36.583099 45.737900 57364 2.981018 -35.093414 44.680267 57365 3.163956 -36.146484 44.871094 57366 13.794464 -37.426712 43.683434 57367 15.204880 -37.320358 45.268364 57368 33.445419 -36.515915 44.724380 57369 12.905426 -38.197556 44.166687 57370 13.958473 -38.615952 44.452126 57371 15.260948 -38.040970 45.345360 57372 14.868347 -38.693390 44.885414 57373 32.872116 -36.912659 44.368484 57374 3.142372 -38.593491 45.063660 57375 3.351555 -39.453812 44.459572 57376 14.410995 -39.450104 44.997009 57377 13.535316 -39.676086 45.165192 57378 29.661575 -38.614166 46.139961 57379 31.086792 -38.245605 46.916573 57380 38.865097 -39.040924 44.552826 57381 44.113358 -39.299698 45.866783 57382 42.862640 -38.818054 46.054474 57383 43.603577 -38.696213 47.405312 57384 38.201126 -38.811432 45.743660 57385 37.820053 -38.953064 46.353516 57386 39.059120 -38.766037 46.819115 57387 24.365234 -39.715698 44.223343 57388 37.796928 -39.796814 44.521042 57389 41.148239 -38.775024 45.650047 57390 50.026443 -37.795731 45.707787 57391 49.154724 -37.378159 45.101479 57392 4.418938 -40.979965 43.040756 57393 25.543884 -40.646469 43.790024 57394 26.891037 -40.559586 45.952126 57395 26.461838 -40.522446 44.541412 57396 27.553101 -39.728470 45.166199 57397 43.163300 -40.603012 44.240860 57398 50.366180 -39.302582 44.940201 57399 24.895935 -41.153015 44.221855 57400 25.680557 -41.241699 44.461258 57401 37.571213 -41.844803 43.892990 57402 37.673958 -42.169968 44.365662 57403 43.416016 -41.030960 44.668198 57404 51.729553 -41.659393 45.527771 57405 51.107269 -40.174728 45.280426 57406 37.273621 -42.721527 43.824364 57407 40.664062 -44.308609 43.990067 57408 6.338333 -44.592621 44.270721 57409 4.944588 -46.149185 43.190636 57410 31.194527 -46.438950 44.113831 57411 30.494476 -46.452209 43.317451 57412 30.461258 -47.244247 43.950043 57413 35.333656 -45.261093 44.180908 57414 37.303375 -43.627472 44.636879 57415 40.049957 -45.517990 43.950401 57416 48.153717 -45.144821 44.069221 57417 51.225418 -44.996994 45.472328 57418 51.755920 -44.119843 45.391869 57419 49.066742 -44.577240 43.717407 57420 39.475998 -46.570847 43.883560 57421 44.313370 -46.971527 44.216019 57422 5.969841 -48.544479 43.245277 57423 38.831131 -47.694962 43.988152 57424 43.152191 -47.717285 43.200874 57425 5.378204 -49.098831 42.603302 57426 5.985420 -48.273727 44.100075 57427 6.520477 -48.867188 44.086906 57428 37.634537 -48.768692 44.193153 57429 43.580551 -48.757339 44.055931 57430 4.532890 -49.749176 42.068954 57431 5.395249 -50.551132 42.938446 57432 4.537926 -50.767593 42.559509 57433 6.004837 -49.590836 43.058533 57434 29.547859 -49.739136 43.789970 57435 34.613167 -49.298920 43.342506 57436 33.963089 -49.587311 43.135864 57437 34.487930 -49.961441 43.612076 57438 34.255806 -50.927475 42.994591 57439 33.675720 -50.154282 42.875443 57440 35.860199 -49.436996 43.984238 57441 37.000061 -49.899139 45.522263 57442 44.383575 -49.779037 44.008102 57443 48.137177 -49.690414 44.650543 57444 47.259308 -50.138229 45.350540 57445 50.945084 -49.754211 43.871445 57446 6.268784 -50.236710 43.314468 57447 28.678024 -50.441147 43.498329 57448 43.632095 -49.770523 44.881042 57449 44.916367 -50.607590 45.300697 57450 44.027969 -50.415649 45.227844 57451 45.514893 -50.013260 44.470467 57452 52.031433 -50.296906 43.810875 57453 26.633202 -52.101883 44.488152 57454 27.869713 -51.227768 44.141556 57455 29.068741 -50.786911 44.469810 57456 53.522964 -51.332748 42.981590 57457 52.314819 -51.080658 44.235542 57458 9.282791 -53.237793 43.833069 57459 9.133057 -53.953781 42.646400 57460 8.042739 -53.855942 42.728195 57461 11.185646 -54.285858 43.251472 57462 10.632729 -54.786987 42.565132 57463 10.034195 -54.223541 42.541550 57464 26.201546 -53.936447 43.034271 57465 25.328781 -54.147003 44.728027 57466 6.072624 -53.428162 42.797836 57467 6.964264 -53.845871 42.584824 57468 10.066292 -53.711304 43.124115 57469 27.800568 -54.596725 43.195152 57470 30.654388 -54.308731 42.963959 57471 35.194824 -52.013947 43.385689 57472 44.332764 -54.236435 43.388542 57473 47.066254 -54.006470 43.287910 57474 46.484192 -54.647522 44.524582 57475 52.642593 -53.955566 43.644745 57476 10.483940 -55.487869 42.523415 57477 11.050385 -55.214508 42.961365 57478 26.264191 -54.591293 43.569626 57479 37.392441 -54.340149 43.323051 57480 37.220802 -53.898895 44.226486 57481 39.949112 -54.969513 43.847206 57482 38.426842 -54.415802 44.212517 57483 40.862427 -54.790543 43.336937 57484 41.219635 -55.022369 44.405190 57485 42.506287 -55.007874 44.682755 57486 43.591003 -54.723572 44.209267 57487 48.173111 -54.563690 43.847412 57488 52.057983 -55.064606 43.491386 57489 33.630859 -56.198792 43.344131 57490 39.937836 -54.879486 45.361702 57491 38.823517 -53.759384 46.521721 57492 39.975304 -54.483231 46.783875 57493 51.231094 -55.855759 42.590988 57494 51.783127 -55.763077 42.879051 57495 50.990311 -55.036179 44.387070 57496 7.260788 -57.514297 42.639481 57497 10.783997 -55.916077 43.390648 57498 34.251236 -56.940338 43.260742 57499 50.675293 -55.000916 45.422379 57500 49.554855 -55.040466 44.917099 57501 5.073204 -57.860260 43.443298 57502 6.361984 -57.636475 43.068100 57503 3.970482 -58.431061 43.348923 57504 34.637123 -57.295914 43.062416 57505 43.918152 -58.591141 42.993851 57506 46.368057 -58.868622 43.951096 57507 3.598259 -59.414658 42.801514 57508 36.850403 -58.344543 44.103935 57509 38.112198 -59.040421 43.853004 57510 37.946152 -58.793427 45.214188 57511 42.937622 -59.130295 43.831184 57512 47.948608 -60.110077 43.582024 57513 23.318375 -61.614151 42.778328 57514 48.216125 -61.065002 43.076317 57515 3.626274 -58.935745 44.205490 57516 25.947052 -61.893509 42.715561 57517 25.104225 -61.595428 44.126793 57518 25.972412 -62.232391 44.377846 57519 46.520294 -63.986816 42.905869 57520 23.164597 -63.762741 43.294006 57521 27.176651 -62.889771 42.366852 57522 32.821671 -64.425690 42.153488 57523 35.508118 -64.459457 42.770996 57524 24.471573 -65.714371 42.063110 57525 23.886070 -65.255890 43.118767 57526 4.643936 -65.196396 42.699837 57527 28.920868 -66.167725 43.528397 57528 28.358086 -65.156723 44.273788 57529 32.690781 -66.072891 43.762367 57530 31.557236 -66.447006 43.090363 57531 36.029327 -66.778030 43.522346 57532 35.644379 -66.920425 42.449310 57533 39.449043 -65.977127 41.941269 57534 39.688034 -65.935165 42.546631 57535 41.613220 -65.637299 43.553017 57536 42.089920 -66.055145 44.286797 57537 42.772659 -65.593674 43.412834 57538 43.633850 -65.609650 43.857635 57539 45.263916 -64.652924 43.633957 57540 17.436325 -67.894928 41.861008 57541 18.032104 -67.459763 41.741371 57542 29.349518 -66.057785 42.757805 57543 30.457977 -66.834961 43.397469 57544 40.021423 -66.770447 43.512100 57545 40.076782 -65.607651 43.009529 57546 20.172180 -70.306274 42.523987 57547 25.411674 -69.815582 42.323166 57548 24.596275 -66.877472 42.805496 57549 39.651871 -67.844986 42.994644 57550 25.924606 -70.345123 42.434227 57551 29.631271 -70.475693 41.714966 57552 16.905472 -70.786575 42.986465 57553 25.442795 -69.994202 43.019783 57554 26.136833 -70.677063 43.134262 57555 27.241898 -70.798553 42.616844 57556 35.528717 -71.290283 42.040337 57557 41.045624 -70.421310 42.124565 57558 40.596909 -70.634033 42.853996 57559 39.769119 -70.508286 44.278481 57560 40.274979 -69.717300 43.341873 57561 17.594398 -72.900146 40.909676 57562 17.464806 -72.863831 41.475235 57563 39.714264 -72.453308 42.243652 57564 5.423386 -73.126007 42.258133 57565 4.853058 -71.552689 42.422409 57566 5.301750 -74.296524 41.158897 57567 17.553146 -73.829300 41.479774 57568 17.623367 -73.543518 41.968689 57569 36.297241 -72.317444 42.096268 57570 35.815445 -71.654312 43.127510 57571 38.180283 -72.604797 43.326485 57572 39.745316 -71.636032 43.292931 57573 6.054779 -76.117905 41.329941 57574 17.574821 -74.312210 42.341805 57575 22.808456 -75.352921 42.300911 57576 21.703293 -73.950577 42.850426 57577 31.726534 -75.541687 42.350288 57578 31.652224 -74.722977 43.003563 57579 11.671356 -78.335388 42.583374 57580 12.912483 -77.184525 42.297989 57581 23.926239 -76.365387 41.788406 57582 24.611794 -77.197556 41.674103 57583 12.439316 -77.501007 42.368431 57584 25.417419 -78.398972 41.840836 57585 6.525124 -77.055725 41.903870 57586 7.033028 -77.456528 42.430977 57587 8.738007 -79.618835 41.585083 57588 9.457184 -79.448318 42.063072 57589 18.390228 -79.633835 41.158417 57590 31.574814 -78.087692 41.737366 57591 31.606661 -78.863922 41.502831 57592 16.503281 -80.521698 41.423027 57593 20.223618 -80.389191 41.788803 57594 26.379364 -79.568573 42.112953 57595 27.354706 -80.493027 41.333717 57596 31.392365 -78.893066 42.182159 57597 30.593460 -79.628189 42.461464 57598 8.209625 -79.244247 41.946304 57599 13.687096 -82.029648 41.374329 57600 15.118698 -81.337601 41.697235 57601 14.931915 -82.041321 42.066444 57602 18.344147 -80.977554 42.272949 57603 28.738953 -80.789825 41.766586 57604 30.035522 -80.514832 41.738419 57605 12.240005 -83.338440 40.763847 57606 27.478302 -80.102036 42.937195 57607 25.888992 -78.661896 43.842964 57608 28.995422 -81.259445 40.861572 57609 11.241119 -82.685867 40.461899 57610 23.539612 -82.539337 40.890099 57611 11.027245 -83.425507 40.100197 57612 19.219742 -83.205154 41.158310 57613 20.389763 -83.269485 41.063423 57614 23.859634 -83.361603 40.597694 57615 19.597427 -82.649612 41.992401 57616 16.671692 -84.757416 40.823616 57617 21.620972 -83.565201 40.921455 57618 22.965179 -83.347900 41.015709 57619 13.574493 -84.488724 40.784561 57620 5.680657 45.940964 50.612572 57621 7.565872 44.134705 50.302910 57622 19.902924 41.699615 49.881996 57623 21.325500 41.693695 49.416573 57624 13.620743 41.437454 49.761986 57625 12.730957 41.025406 49.670708 57626 12.129265 40.409210 49.412910 57627 13.429428 41.417633 51.889259 57628 13.439500 41.352081 50.845795 57629 14.466980 41.428040 51.735016 57630 18.895279 41.434280 50.543785 57631 19.787148 40.761795 51.085114 57632 21.092590 40.761719 50.228310 57633 21.690041 39.570053 50.054161 57634 4.808945 40.258377 49.174217 57635 6.380211 39.442307 49.347153 57636 5.695297 40.028122 49.389854 57637 7.090965 40.120209 49.421486 57638 6.835602 38.688599 48.845695 57639 7.441849 39.526077 49.156509 57640 7.519264 38.988892 48.905174 57641 12.262299 40.448364 50.666656 57642 12.139946 40.620972 51.833542 57643 11.619186 40.025253 51.596100 57644 21.403976 38.614563 50.605980 57645 21.061020 37.194550 50.466072 57646 11.271667 37.585953 49.819916 57647 10.932785 37.079269 49.796997 57648 10.484932 36.385590 49.566925 57649 9.940460 36.393997 50.209328 57650 28.860512 35.356873 49.235519 57651 18.900421 35.617722 48.150780 57652 19.280830 35.385864 48.548080 57653 8.009590 34.726913 49.064034 57654 28.506851 34.645981 49.639023 57655 29.589005 34.641006 49.645851 57656 29.084839 34.496002 49.719742 57657 30.699219 31.577103 49.466049 57658 7.264557 34.485611 49.587402 57659 6.586487 33.919006 49.455627 57660 6.181015 33.397858 48.998589 57661 21.648827 33.862122 49.731750 57662 28.492966 33.819107 49.510368 57663 29.891731 33.641510 49.531723 57664 4.680901 32.378632 50.471489 57665 5.712425 33.862305 50.276970 57666 22.493858 32.024338 49.648399 57667 30.446411 32.542511 49.549553 57668 30.546371 31.013504 49.538208 57669 22.064713 31.686111 50.135918 57670 20.771423 30.198807 50.528618 57671 20.633514 30.324265 51.269478 57672 21.389442 30.991730 51.422752 57673 4.827850 29.492508 48.649139 57674 29.426437 31.828369 49.379204 57675 29.718338 30.132462 48.554276 57676 4.042862 26.393890 49.494667 57677 20.046364 29.208328 49.118141 57678 17.512436 26.781448 49.782021 57679 26.300491 25.342178 48.875183 57680 27.294205 25.624390 49.136093 57681 29.094719 25.522446 49.351250 57682 28.097488 25.470428 49.414963 57683 30.267021 25.322449 49.919312 57684 33.817810 26.086273 50.298004 57685 31.137360 25.921356 49.773689 57686 34.637268 25.900894 50.088913 57687 31.953569 26.086151 50.408020 57688 24.853531 24.424377 48.484703 57689 25.415710 25.178558 48.568726 57690 17.426620 23.118423 48.712250 57691 37.425400 23.827637 49.406090 57692 5.203598 22.157059 47.655724 57693 4.096573 24.874542 49.559288 57694 26.142227 22.837524 48.520256 57695 4.901505 22.888412 48.263054 57696 25.638687 24.013947 49.009567 57697 26.280350 23.382904 48.958061 57698 28.429977 24.150101 49.430367 57699 31.908342 23.991562 51.089874 57700 30.815437 24.078857 50.218468 57701 31.271545 25.118469 50.614586 57702 7.698242 21.582321 48.671783 57703 8.529533 21.607086 49.513351 57704 8.567932 20.871872 49.011124 57705 8.254074 20.627899 48.148750 57706 18.378571 21.877686 48.694916 57707 31.680353 22.577286 50.135719 57708 31.837297 21.637421 49.370644 57709 31.933268 21.604309 49.937126 57710 8.445465 19.784988 48.468498 57711 20.534470 20.938034 49.154770 57712 22.951431 20.128204 49.180153 57713 23.978920 19.067596 49.203064 57714 23.412262 20.543976 50.046791 57715 30.754974 19.914520 48.224678 57716 31.286331 20.507858 49.568764 57717 31.757509 21.153229 49.634293 57718 40.435059 20.981522 49.372398 57719 30.518585 19.491302 49.545303 57720 5.512421 17.435059 48.486809 57721 7.582520 18.728256 48.642418 57722 6.991509 19.166122 50.059181 57723 6.132446 18.461243 49.582802 57724 23.669373 17.263550 50.255928 57725 24.315964 18.355042 50.422150 57726 23.986359 17.658646 49.135353 57727 24.346794 18.322601 48.919502 57728 28.746857 16.333923 48.751083 57729 41.196838 18.607635 49.674339 57730 40.116394 17.633041 49.718811 57731 22.912949 16.374939 48.464645 57732 35.017654 15.233170 49.198013 57733 34.976456 14.324905 48.871933 57734 19.604439 14.723480 48.505585 57735 28.509155 15.687622 49.112617 57736 4.271828 13.852142 47.959801 57737 4.227158 14.477341 48.812378 57738 17.653168 13.750977 48.583366 57739 16.958786 12.512466 48.576691 57740 17.025154 13.620453 49.908463 57741 27.194069 14.313187 49.219078 57742 26.409698 13.497696 48.182884 57743 34.864349 13.696136 48.931633 57744 35.150078 13.761337 48.572441 57745 35.202332 13.389160 49.031334 57746 35.981201 13.020142 49.451256 57747 40.039917 13.339294 48.507874 57748 39.768250 13.482574 48.726318 57749 39.530045 13.353348 48.554932 57750 40.090210 13.341675 49.005341 57751 4.662445 12.957092 47.665543 57752 5.309754 12.524612 47.982635 57753 17.724335 14.392731 49.937233 57754 25.225555 12.944824 48.264938 57755 25.748596 13.704010 49.413956 57756 37.887543 13.004608 50.363213 57757 39.730362 13.149963 50.536011 57758 44.981644 11.054047 49.627861 57759 44.135498 11.762375 50.958122 57760 43.031677 12.573593 50.425415 57761 6.113228 11.902954 47.881905 57762 21.612518 11.389984 48.057190 57763 23.119034 12.629929 49.199593 57764 5.876587 12.361435 48.843704 57765 6.831360 11.371536 48.600494 57766 16.431213 10.959991 49.115273 57767 7.410362 10.371140 48.106941 57768 7.099251 10.513443 49.384911 57769 7.789283 9.349869 47.152176 57770 7.065384 8.559296 47.487968 57771 16.683907 10.141174 48.027618 57772 17.298431 9.417145 47.488564 57773 20.602753 10.198196 48.014252 57774 20.078255 9.401505 47.623230 57775 21.143570 9.755188 48.931358 57776 21.001106 10.901199 48.793037 57777 21.097061 11.036209 49.470673 57778 6.293785 8.755814 48.119667 57779 17.965294 8.442749 47.504044 57780 20.522095 9.187180 48.080917 57781 5.396973 8.358917 48.203285 57782 18.266647 7.701508 47.874352 57783 21.255363 8.345779 48.074173 57784 36.657608 6.570526 47.972633 57785 39.024155 7.779587 48.874191 57786 43.061371 8.210052 50.160019 57787 44.109787 8.673325 49.331520 57788 44.458206 8.943802 48.501770 57789 44.994034 9.656738 49.616409 57790 3.424408 6.050766 48.470596 57791 3.361611 5.193375 47.905830 57792 17.219414 8.338501 48.675201 57793 21.919968 8.630798 48.729599 57794 24.502045 6.463318 47.855591 57795 24.799622 6.432831 48.268272 57796 41.749573 7.917587 49.382019 57797 3.426216 7.522156 49.161514 57798 4.277641 8.402161 48.856087 57799 18.259621 7.060577 48.643494 57800 24.441376 5.901520 47.880829 57801 36.190369 6.332794 48.707886 57802 36.535782 6.817276 48.911247 57803 21.431290 3.109879 47.619034 57804 22.280197 3.911102 47.437630 57805 23.917152 4.793373 47.931892 57806 36.086029 3.923286 49.077583 57807 22.894775 0.969101 48.888771 57808 22.137505 0.698975 49.633507 57809 21.583481 1.064774 49.404137 57810 41.307327 3.869736 48.445625 57811 42.164276 3.550171 49.019295 57812 48.925262 2.150909 47.058800 57813 22.048004 2.896759 47.701256 57814 20.870094 3.077538 47.934639 57815 23.170288 2.759750 48.177872 57816 38.684723 3.509384 48.104050 57817 39.709915 3.619583 48.146301 57818 3.730522 0.235641 47.451286 57819 3.571144 2.834152 47.390160 57820 3.770866 2.156860 47.339355 57821 21.483986 2.284332 48.239273 57822 20.488434 2.859985 48.447754 57823 43.490448 2.612671 49.254875 57824 42.821411 2.557907 48.497971 57825 43.023682 -0.163345 49.123993 57826 3.570572 -3.307022 50.434265 57827 3.414764 -3.512314 49.356094 57828 4.391319 -2.169312 49.347855 57829 2.807961 -2.299423 46.985458 57830 2.692368 -3.439880 47.180885 57831 2.972954 -4.354263 46.940529 57832 41.145935 -2.838516 47.231926 57833 41.261658 -2.008972 47.604507 57834 42.062683 -3.049164 48.124008 57835 3.647034 -5.037888 46.873268 57836 2.849747 -4.145569 47.781677 57837 3.491707 -5.257385 48.035851 57838 52.851395 -5.343033 47.944550 57839 53.502518 -5.618607 47.014862 57840 4.522591 -5.496460 47.246445 57841 5.583321 -5.984314 47.724045 57842 9.301659 -6.103058 47.374931 57843 9.803848 -6.671661 48.543602 57844 10.219620 -6.477203 47.454903 57845 9.878845 -6.172852 46.601135 57846 10.906189 -7.301453 46.670242 57847 44.306183 -5.336639 47.218269 57848 44.188141 -4.235748 48.443413 57849 43.357483 -4.883423 47.392334 57850 50.267303 -5.292267 47.306999 57851 50.988342 -4.964981 47.833603 57852 51.209610 -4.799896 48.540451 57853 51.972382 -4.922424 48.606079 57854 42.881638 -4.266190 47.874680 57855 49.540512 -5.530182 47.529640 57856 53.360733 -6.417419 48.057762 57857 52.980515 -5.842484 48.560791 57858 11.362076 -8.623734 46.716415 57859 37.570160 -7.079620 50.839630 57860 36.145561 -7.473846 50.033508 57861 35.947617 -7.382156 51.042870 57862 53.569000 -7.771622 47.783066 57863 53.009048 -7.328766 49.333061 57864 52.596878 -6.161743 49.218849 57865 2.849144 -10.310287 46.175285 57866 3.076714 -10.230057 47.159126 57867 2.675125 -10.657471 46.928719 57868 5.337120 -9.910645 47.041389 57869 4.046730 -10.276199 48.169762 57870 6.690659 -10.342041 47.249710 57871 11.073708 -9.586731 46.365814 57872 30.780151 -9.718643 47.652931 57873 32.137375 -8.720642 48.412682 57874 33.325119 -9.036621 47.443604 57875 53.043381 -10.386475 47.491364 57876 53.237320 -9.422791 48.163689 57877 9.156830 -10.812363 46.558258 57878 30.893097 -10.463181 47.241234 57879 31.503159 -10.942429 47.394020 57880 43.100235 -9.744507 47.684013 57881 44.185394 -10.552216 47.302170 57882 30.680206 -11.978165 48.314812 57883 29.760132 -11.825928 48.285561 57884 30.029724 -11.309006 47.825043 57885 30.446350 -10.614548 47.409149 57886 34.476746 -11.481293 47.182327 57887 33.102341 -11.773438 47.971893 57888 35.355057 -11.665375 47.802444 57889 46.592148 -11.390625 48.537155 57890 47.045227 -11.931412 48.311317 57891 46.920990 -12.311813 47.819710 57892 37.826523 -11.607681 47.216179 57893 38.201332 -11.471207 48.493355 57894 40.326797 -12.669189 47.216766 57895 41.964233 -12.381973 49.451027 57896 40.963516 -12.490036 48.347076 57897 42.354065 -13.391510 48.161537 57898 46.935913 -13.198746 47.454872 57899 3.522003 -14.546204 46.479851 57900 4.100662 -14.927841 46.721336 57901 5.248718 -15.294113 46.742607 57902 6.761070 -15.654755 46.903969 57903 7.877456 -15.387939 45.845627 57904 40.356247 -12.595657 47.581665 57905 42.475983 -13.457703 47.110100 57906 43.389420 -14.024307 48.501411 57907 44.000000 -14.684067 47.734428 57908 44.159515 -14.605682 48.823593 57909 46.867828 -14.530731 47.223450 57910 8.961235 -15.660309 46.104691 57911 11.209198 -16.401398 46.002197 57912 45.559174 -15.267136 47.199699 57913 11.240768 -16.916168 46.677391 57914 11.753234 -17.498871 45.779457 57915 46.743515 -15.924881 47.056328 57916 53.488739 -16.391052 46.949112 57917 53.399017 -16.293289 48.201439 57918 54.673111 -16.327393 47.919640 57919 5.809433 -19.070709 45.464401 57920 47.313156 -16.347626 46.630615 57921 52.323975 -16.892105 47.435448 57922 56.693237 -17.493469 46.932587 57923 36.892380 -18.286087 46.834160 57924 35.944702 -18.350250 48.384346 57925 36.863861 -18.360748 49.414627 57926 37.752716 -18.336319 48.369339 57927 45.460388 -17.373077 48.124016 57928 44.935699 -18.221817 47.835686 57929 50.060410 -18.520172 47.709854 57930 56.446289 -18.088684 47.470276 57931 56.414917 -17.343140 47.472206 57932 6.557137 -19.938049 45.435532 57933 7.240723 -20.689743 45.172691 57934 11.742165 -18.648880 46.091728 57935 56.202271 -19.824249 47.042847 57936 56.155762 -19.133377 47.863594 57937 5.454514 -20.076630 45.679497 57938 6.793984 -20.766830 45.473038 57939 6.843041 -21.829636 45.235237 57940 30.989746 -19.953918 48.087440 57941 31.690142 -19.136520 47.845062 57942 48.843506 -19.750656 47.064560 57943 51.246841 -17.323349 48.257210 57944 55.839600 -20.381287 47.055069 57945 5.676186 -21.856216 45.262703 57946 5.813011 -21.185089 45.586823 57947 6.327637 -20.740555 45.634071 57948 7.193878 -24.222763 45.273804 57949 10.229126 -20.888733 47.700554 57950 10.956924 -22.573807 46.904938 57951 30.265488 -21.096848 46.083565 57952 34.865005 -22.517273 47.592911 57953 34.814972 -24.039520 48.220085 57954 33.668091 -23.915070 48.088043 57955 35.829880 -21.538818 47.217201 57956 36.410873 -21.354675 46.541962 57957 36.541077 -21.450134 47.338943 57958 37.421539 -21.590683 47.308121 57959 54.865875 -21.431732 47.697914 57960 6.429939 -24.699249 45.654205 57961 5.612267 -24.781158 45.739304 57962 30.475891 -21.623169 46.330284 57963 30.076889 -21.178696 46.532776 57964 31.206482 -21.944916 46.385239 57965 32.677887 -22.103485 46.454315 57966 32.290291 -23.355789 48.111389 57967 31.065994 -22.149292 47.357140 57968 40.370300 -22.349899 46.529205 57969 53.065186 -22.778625 47.603203 57970 13.236115 -25.066345 45.232468 57971 39.900818 -21.917572 48.153854 57972 38.390137 -21.681732 48.103798 57973 45.153961 -22.039841 48.424789 57974 43.901352 -22.084839 48.748047 57975 41.172272 -22.202271 47.684731 57976 42.678864 -22.203461 47.604080 57977 51.495514 -23.684937 46.919937 57978 52.332672 -23.402954 47.621964 57979 3.623039 -25.131744 45.760490 57980 4.711716 -25.210571 46.164787 57981 12.617676 -25.329910 46.248360 57982 11.475449 -24.208725 46.933716 57983 2.259003 -25.513748 45.169235 57984 2.057152 -25.986923 45.132149 57985 2.411270 -26.025345 46.052048 57986 13.443924 -25.785919 45.631256 57987 49.243347 -25.362381 47.582794 57988 56.935699 -25.418182 46.628036 57989 56.346039 -24.982666 46.436104 57990 55.610962 -25.187851 46.350586 57991 2.073006 -26.709946 45.409897 57992 9.050323 -27.102859 45.257721 57993 13.748306 -26.613205 46.428604 57994 46.124573 -26.632629 46.247055 57995 46.668488 -26.414871 47.391792 57996 57.458771 -26.109497 46.268890 57997 9.283066 -28.589035 45.747513 57998 14.950928 -27.190170 45.247398 57999 15.210739 -27.757172 45.243355 58000 15.444626 -28.602768 45.401360 58001 44.483398 -27.827637 46.383736 58002 45.069214 -27.282745 46.233505 58003 2.720299 -30.461563 45.936287 58004 15.776039 -29.146973 45.254959 58005 15.761200 -29.510178 45.194962 58006 15.956688 -29.335648 45.416832 58007 37.310791 -29.132477 44.881332 58008 38.729004 -29.364975 45.457359 58009 42.964233 -28.954956 46.773727 58010 50.470306 -28.576096 46.056580 58011 56.872894 -29.139832 46.491104 58012 56.504761 -27.825394 47.726021 58013 56.736633 -26.633698 47.241035 58014 3.081726 -29.761261 45.550346 58015 9.945900 -32.461823 44.672791 58016 9.997772 -30.524902 45.312050 58017 15.787369 -29.525879 45.570473 58018 37.642807 -29.385864 45.951218 58019 37.616348 -29.238037 45.592224 58020 37.456818 -29.799942 46.584320 58021 48.193161 -29.810287 46.192917 58022 2.694046 -29.165771 45.958916 58023 2.294541 -29.569183 47.150223 58024 33.138321 -32.125107 46.479065 58025 34.511200 -31.566177 46.925476 58026 56.470856 -30.736908 46.136826 58027 56.308472 -30.039856 47.165726 58028 2.694367 -33.074799 44.819687 58029 14.309669 -34.045425 44.682281 58030 46.864212 -30.785950 46.753365 58031 45.770859 -31.710205 46.762260 58032 9.277626 -33.794403 44.685852 58033 8.830062 -33.049576 45.396950 58034 14.019264 -33.189743 46.077202 58035 31.096008 -32.843552 45.377441 58036 29.324951 -34.529099 45.941277 58037 30.567551 -33.817810 46.194107 58038 38.286644 -33.393097 45.769661 58039 37.541672 -33.497467 45.550186 58040 40.870132 -33.316940 46.173996 58041 43.293060 -32.952713 45.800224 58042 49.995789 -33.067413 45.698982 58043 49.609283 -33.480209 46.088310 58044 51.646637 -32.876770 46.880348 58045 51.493652 -33.385223 48.553833 58046 52.571686 -32.940399 48.118179 58047 52.671722 -32.677307 46.650558 58048 54.730164 -31.751801 47.667450 58049 3.137741 -34.273804 44.038101 58050 2.530052 -34.210663 45.198914 58051 49.445038 -33.972916 47.038658 58052 49.234894 -36.389648 46.386429 58053 7.889976 -35.977814 46.029739 58054 24.806900 -37.442123 47.195763 58055 25.442383 -36.400330 46.995750 58056 26.362366 -36.128357 45.242783 58057 48.900574 -35.085571 46.945641 58058 49.030945 -35.753784 47.551674 58059 32.696442 -37.199554 45.203232 58060 50.468964 -37.146194 46.910004 58061 49.848145 -36.805862 46.628723 58062 11.647675 -38.147827 44.902504 58063 12.849762 -38.900146 44.831184 58064 23.842285 -39.273422 45.101974 58065 23.686844 -40.245041 45.091118 58066 37.685211 -39.269226 45.415352 58067 37.792686 -39.124237 47.467949 58068 39.731522 -38.759018 48.063484 58069 40.496643 -38.651031 47.521301 58070 50.898956 -37.971039 46.339874 58071 3.761910 -40.336243 44.649780 58072 28.479828 -39.147354 44.809738 58073 37.340401 -40.080215 45.261398 58074 24.157227 -41.101562 44.550880 58075 26.131187 -41.317459 45.224648 58076 43.874893 -40.373627 44.996300 58077 44.856049 -40.498962 45.890678 58078 45.126404 -39.444122 46.180298 58079 50.824539 -38.800583 45.719994 58080 6.073212 -41.703232 45.882385 58081 4.443886 -40.954514 45.424828 58082 4.662270 -41.117981 46.351089 58083 7.224915 -41.766510 44.737366 58084 24.562180 -41.930298 44.720734 58085 25.432816 -42.049942 45.239166 58086 37.152328 -41.053482 45.870171 58087 37.923820 -42.163254 45.369537 58088 43.204880 -41.733536 45.197945 58089 44.004120 -41.054703 45.354088 58090 52.139023 -39.921783 46.608086 58091 9.451538 -43.041168 43.500168 58092 23.428619 -43.509964 46.472084 58093 24.214661 -43.321075 45.760254 58094 24.393951 -44.041443 46.204727 58095 24.545288 -42.659241 45.331886 58096 25.255341 -42.934647 45.870010 58097 42.266693 -42.569183 44.874840 58098 23.469879 -42.275330 45.943626 58099 24.871918 -43.550552 45.937386 58100 41.600342 -43.799255 44.997246 58101 4.582947 -44.962509 45.866516 58102 4.706780 -46.207794 44.052597 58103 36.312256 -44.935349 44.528946 58104 52.267883 -44.374710 46.046661 58105 52.743362 -43.943405 46.806221 58106 52.388290 -43.052933 46.492371 58107 7.721786 -43.880096 45.384102 58108 4.329865 -46.281860 44.872017 58109 32.232407 -46.184418 44.535553 58110 33.198380 -46.099884 45.039978 58111 35.413666 -46.002502 45.666519 58112 35.957016 -45.525055 44.948814 58113 40.720886 -45.199921 44.945358 58114 49.052490 -46.198456 46.234688 58115 49.583755 -45.317993 44.991081 58116 47.460358 -45.778702 44.898071 58117 52.045334 -45.307510 46.675621 58118 4.893196 -47.780640 44.708855 58119 31.363190 -47.292480 45.041443 58120 40.069275 -46.378769 44.853249 58121 45.903641 -46.441940 45.223839 58122 47.341354 -46.333160 45.964569 58123 5.620064 -47.875488 43.751579 58124 39.532646 -47.242554 44.704353 58125 30.398758 -48.369797 44.241135 58126 38.661072 -48.484375 44.952805 58127 6.690254 -49.589340 43.721794 58128 7.023384 -50.391525 44.200302 58129 6.735329 -50.554108 43.755318 58130 6.242951 -51.011139 43.508148 58131 30.781128 -47.352478 44.489624 58132 30.337296 -50.059784 44.991562 58133 35.969162 -50.564819 45.028885 58134 49.744919 -49.810669 44.686234 58135 4.760513 -51.477402 42.844559 58136 6.845596 -49.662186 44.514854 58137 46.318115 -50.524292 45.624542 58138 51.350067 -50.843582 44.992409 58139 5.830895 -52.142105 43.273621 58140 6.849747 -51.509109 44.425728 58141 7.381607 -52.893295 43.717430 58142 28.565346 -51.569000 45.249054 58143 11.592789 -53.423889 44.187958 58144 11.484253 -53.680923 43.690865 58145 10.786377 -53.452606 43.736710 58146 11.905685 -53.867188 44.052681 58147 26.059677 -54.894653 44.413925 58148 51.852280 -53.084854 45.654747 58149 51.934082 -52.051514 45.339790 58150 30.123611 -54.666122 43.987282 58151 29.328674 -55.045609 44.753326 58152 36.612335 -53.599365 44.097809 58153 44.881165 -54.739197 44.506584 58154 51.997055 -54.081863 44.672646 58155 12.154991 -54.553650 44.280296 58156 12.036797 -55.204041 44.162109 58157 11.594536 -55.217957 43.577484 58158 26.917755 -55.052307 44.225952 58159 27.987694 -54.989639 44.127998 58160 31.679537 -55.451370 46.962807 58161 30.684280 -55.166595 45.598686 58162 32.278008 -55.205276 45.430458 58163 48.363052 -54.975555 45.256119 58164 11.609344 -55.629730 44.060226 58165 33.217728 -55.546204 44.783684 58166 7.676704 -57.472992 43.348404 58167 8.126778 -57.256943 44.116516 58168 4.350266 -58.128815 44.421501 58169 7.132851 -57.606750 43.295341 58170 34.799240 -56.941330 44.083939 58171 35.774902 -57.692322 44.049980 58172 35.619110 -56.864944 45.629791 58173 41.769379 -59.548203 44.639877 58174 46.914429 -59.035324 44.107025 58175 45.681946 -58.935287 44.092285 58176 47.323013 -59.440918 44.181686 58177 38.990135 -59.418610 44.176834 58178 40.716614 -59.631516 44.536613 58179 39.854179 -59.761856 44.828285 58180 44.587219 -59.106277 44.123421 58181 23.487045 -61.289413 43.646790 58182 22.819504 -62.134262 43.333076 58183 22.562256 -61.396622 44.531509 58184 22.112839 -61.915359 44.375526 58185 24.218903 -61.283127 44.381241 58186 24.639198 -61.329529 43.421341 58187 47.830338 -61.147003 44.067261 58188 47.426605 -60.280106 45.030121 58189 22.302849 -62.737610 43.977600 58190 47.335114 -62.256943 44.206192 58191 46.272339 -63.519272 44.229012 58192 26.994507 -63.013245 43.523293 58193 27.675217 -63.923294 44.158676 58194 4.310288 -65.219055 43.819572 58195 33.528915 -64.712494 43.244278 58196 35.281342 -64.571182 43.661789 58197 35.967903 -64.888519 43.678375 58198 34.403320 -64.479263 43.769547 58199 34.388313 -65.071487 44.588036 58200 36.237137 -65.306656 43.950760 58201 41.984680 -65.131119 42.770927 58202 46.320038 -62.672821 45.637466 58203 45.010773 -63.705643 45.839249 58204 45.374420 -62.862976 46.845650 58205 36.286568 -65.994797 43.932510 58206 40.651489 -65.838608 43.525780 58207 41.154694 -66.350174 44.234741 58208 44.597229 -64.724136 44.815834 58209 45.288055 -64.273026 44.642738 58210 44.292007 -65.248810 43.892349 58211 4.641884 -69.250214 42.669846 58212 17.998398 -67.650787 42.003334 58213 28.789230 -66.294037 44.435913 58214 31.629274 -66.703598 43.376656 58215 31.855700 -67.080200 43.967644 58216 36.283936 -67.582382 45.205261 58217 36.412415 -67.271194 46.232750 58218 36.138031 -68.423630 46.329987 58219 17.843384 -68.779938 43.049896 58220 18.068451 -69.771484 44.157539 58221 18.790939 -68.974930 43.036980 58222 31.571991 -67.611435 44.327667 58223 30.861389 -67.837570 44.489197 58224 35.702606 -68.020920 43.345337 58225 39.338974 -67.871262 43.464073 58226 39.556435 -67.619217 43.633865 58227 17.137314 -69.816772 43.547379 58228 17.784203 -68.107422 42.356049 58229 19.359337 -69.770813 43.555733 58230 35.416534 -69.794754 43.008575 58231 39.442635 -68.108231 43.477425 58232 39.824371 -68.649551 43.775162 58233 17.057655 -69.090271 42.626068 58234 23.941360 -66.370972 44.160645 58235 24.950302 -68.563721 43.673279 58236 4.759842 -68.532104 44.114342 58237 4.505562 -66.822357 43.414551 58238 17.368881 -72.745865 42.724731 58239 17.095947 -71.956528 44.024841 58240 20.402359 -70.906342 43.075867 58241 25.148560 -69.419556 42.777443 58242 30.508133 -73.287781 44.489044 58243 29.853882 -72.773956 44.355988 58244 20.718452 -71.489471 42.883133 58245 26.658226 -71.218460 44.040268 58246 29.460976 -71.477570 42.720055 58247 35.505096 -70.363495 45.203140 58248 35.600174 -70.889572 44.233101 58249 35.791473 -69.047134 44.677544 58250 38.978737 -72.812149 42.380066 58251 5.596184 -74.006210 42.120132 58252 17.389206 -73.025787 43.941978 58253 17.676292 -74.025787 43.726837 58254 36.446526 -72.282761 44.386932 58255 36.752548 -72.535553 42.977692 58256 5.954613 -73.801514 42.480698 58257 6.372200 -74.772537 42.264397 58258 6.921570 -76.296677 42.386078 58259 31.620638 -75.835938 43.634117 58260 30.716232 -78.225250 43.439278 58261 12.868378 -77.503998 42.693054 58262 13.095787 -77.902405 43.182869 58263 13.886528 -78.285721 43.846992 58264 15.767471 -77.917984 44.230309 58265 16.334305 -76.509415 43.028885 58266 22.165604 -74.774475 43.568176 58267 22.846184 -75.750381 43.474266 58268 23.924942 -76.896988 43.427071 58269 31.492249 -74.519135 43.888390 58270 7.444672 -78.353043 42.515747 58271 20.134369 -81.780548 42.220238 58272 17.032570 -81.505539 42.425865 58273 17.786179 -81.741409 42.763428 58274 15.952591 -81.726181 42.193649 58275 29.414368 -79.994904 42.951881 58276 11.768219 -82.681046 40.801292 58277 14.379440 -82.753494 41.957153 58278 13.577080 -83.314865 41.444992 58279 21.697906 -81.453003 41.872009 58280 22.715027 -82.361298 41.533440 58281 21.674469 -82.582565 41.784203 58282 20.697754 -82.817017 41.740677 58283 16.155067 -84.522415 41.438026 58284 14.509674 -83.725311 41.786888 58285 15.472305 -84.019211 41.941628 58286 16.496368 -83.582718 42.076653 58287 7.457367 45.963547 50.838226 58288 7.181542 45.776764 51.018326 58289 5.441155 45.098236 50.400185 58290 8.038727 45.799377 50.526009 58291 5.382195 43.767838 50.315117 58292 4.984436 43.277832 49.873878 58293 8.346962 44.890350 50.213295 58294 7.374313 45.257187 50.796638 58295 5.598930 42.986954 50.027466 58296 5.449722 44.284088 50.461060 58297 6.323670 44.265259 50.591827 58298 13.859497 41.146515 52.927002 58299 13.884079 41.343750 52.455551 58300 14.703049 41.025070 52.764221 58301 18.773750 41.116043 51.121262 58302 21.012817 39.641235 50.996231 58303 12.782730 41.073837 51.611252 58304 20.257599 39.578949 51.931656 58305 11.202667 37.734619 50.267479 58306 10.758926 37.785828 50.940132 58307 11.323708 39.000824 50.830261 58308 10.289680 38.501801 51.659805 58309 20.997673 38.356476 51.448746 58310 19.567352 35.556442 48.950783 58311 10.726021 37.127426 50.436111 58312 9.967208 37.077957 50.938286 58313 8.464172 36.568253 51.119980 58314 21.203033 36.740463 51.553490 58315 6.601540 34.264481 49.853683 58316 6.825905 34.686188 50.163582 58317 8.151474 35.458771 50.126053 58318 6.440476 35.049347 50.859123 58319 4.964684 34.945389 52.217232 58320 21.575424 34.745438 50.723389 58321 22.150246 33.381073 50.392921 58322 28.867271 32.941986 49.524338 58323 4.266739 33.700195 51.900101 58324 3.887413 32.428528 52.294258 58325 22.236031 32.053238 51.525299 58326 22.416245 33.094711 51.411377 58327 30.109673 31.002090 49.425415 58328 20.816452 31.365082 52.560959 58329 21.785454 31.846893 52.342941 58330 4.110230 31.432983 51.046341 58331 4.080826 28.214142 50.359169 58332 3.824173 29.485886 51.649429 58333 19.905785 29.355835 49.913582 58334 4.068329 25.663208 52.013069 58335 17.938599 27.969635 50.072510 58336 18.857643 28.688049 50.005455 58337 18.234161 28.838593 50.797325 58338 27.572235 24.911285 49.645195 58339 26.943863 24.886810 49.464340 58340 17.541725 25.063004 49.345390 58341 25.666916 24.706268 49.005417 58342 26.349442 24.342606 49.267548 58343 34.815079 25.312881 51.474770 58344 34.487617 25.695251 51.019760 58345 4.905357 23.575989 49.314430 58346 4.447128 24.422745 50.525383 58347 5.077492 23.868652 50.462502 58348 17.861710 23.830322 49.361465 58349 18.296112 24.644241 50.166344 58350 37.325623 23.032196 51.259308 58351 36.458557 23.326538 52.064018 58352 36.679810 23.972534 50.959694 58353 6.096558 22.459946 48.703178 58354 5.911385 23.221222 50.025749 58355 7.148056 22.580643 49.822174 58356 17.922318 22.843109 48.959641 58357 8.127350 22.120193 49.680336 58358 18.682655 23.205780 49.781898 58359 29.680069 24.123642 49.632828 58360 38.520462 22.054871 50.332870 58361 37.878502 22.990204 50.326210 58362 8.485306 20.280701 49.639572 58363 19.200623 22.077789 49.588028 58364 39.385071 21.081787 50.349564 58365 22.799179 21.765976 50.857216 58366 38.426605 21.436829 51.116570 58367 40.313263 19.810547 50.549828 58368 39.605598 20.462570 50.875175 58369 42.152237 19.482361 48.757996 58370 41.281036 19.836548 49.533722 58371 7.859878 19.575012 49.790825 58372 4.205444 16.568405 49.112305 58373 29.153801 17.145172 49.586502 58374 28.837517 16.519684 49.663559 58375 29.339035 17.519226 49.577530 58376 21.909500 15.774994 48.808205 58377 37.134644 16.687469 49.326691 58378 36.025475 16.223679 49.694275 58379 36.789505 16.497787 50.470680 58380 39.102158 17.339554 50.313545 58381 20.790833 15.476776 49.431870 58382 19.659554 15.195175 50.065392 58383 21.829391 16.130249 50.177704 58384 22.895004 16.536713 49.568527 58385 27.968506 15.038757 49.795311 58386 35.233147 15.750900 50.265259 58387 18.538773 14.565521 49.307053 58388 28.375320 15.684082 50.149437 58389 34.629066 14.736420 50.318642 58390 4.782265 13.315903 48.857300 58391 16.800224 13.324051 51.096672 58392 16.481796 12.425354 50.082893 58393 26.572433 14.407745 50.276772 58394 34.262421 14.477676 51.484711 58395 34.926331 16.003738 51.860725 58396 39.575127 13.361053 49.055077 58397 5.451958 12.961182 49.896301 58398 24.413475 13.102142 49.254738 58399 23.513329 13.137512 50.195671 58400 34.670364 13.648102 49.825356 58401 35.185776 12.919525 50.074883 58402 43.413162 11.759430 52.193794 58403 44.180389 10.870087 52.004860 58404 21.326973 11.541946 49.108658 58405 22.038116 12.045746 49.123871 58406 16.489250 9.519531 49.310570 58407 16.568344 10.254150 50.325020 58408 7.241928 9.565125 48.385056 58409 4.217568 8.935028 49.570496 58410 4.983109 9.164017 49.589737 58411 6.760841 9.171051 48.532486 58412 6.117951 9.368820 49.349670 58413 21.528198 10.755646 50.077454 58414 22.105087 10.777832 51.000748 58415 22.539139 9.233841 49.801186 58416 37.862518 7.591446 49.045128 58417 37.106842 7.327835 48.895561 58418 38.358917 7.200745 50.069313 58419 44.950073 9.629547 50.888351 58420 45.092316 9.670135 50.394119 58421 44.452942 8.964325 50.431419 58422 3.636139 8.485291 49.567467 58423 3.298676 4.595924 48.947792 58424 18.829315 6.518951 48.652588 58425 3.452698 3.610519 47.912132 58426 19.271027 6.127304 48.578949 58427 19.605156 5.483574 48.889175 58428 24.908264 5.876297 48.798340 58429 24.822220 4.917320 49.632500 58430 24.250618 3.731216 48.779762 58431 35.651344 4.664902 49.590485 58432 36.147629 5.760872 49.444908 58433 39.880188 3.578751 49.027931 58434 40.950043 3.841728 48.932686 58435 4.124329 1.477203 47.686905 58436 20.178467 3.464096 48.741409 58437 24.610977 2.512222 48.803764 58438 37.272629 3.453796 48.613419 58439 37.943024 3.172073 49.095085 58440 36.920860 2.711609 49.886108 58441 38.873375 3.265793 49.354996 58442 43.268433 3.737183 50.234451 58443 4.194504 2.840118 48.632774 58444 5.254715 2.652420 49.260139 58445 5.418518 1.789963 48.652405 58446 4.797165 1.452759 48.162064 58447 21.322845 1.506866 48.937416 58448 44.304077 3.224213 50.340149 58449 44.523514 3.611679 51.011429 58450 43.990021 3.865158 50.975899 58451 4.486328 0.658218 47.933372 58452 5.435745 0.366333 48.549843 58453 20.468048 2.269745 49.084671 58454 24.913757 1.483047 48.519691 58455 24.114944 1.511826 48.439423 58456 23.679245 -0.928818 50.531326 58457 23.389961 -0.261063 51.450867 58458 22.871140 0.155380 50.170578 58459 25.876717 1.517563 48.961311 58460 26.977112 1.373108 49.549736 58461 26.939621 0.434830 48.950417 58462 25.116531 0.410141 48.539467 58463 26.214813 0.576233 48.551613 58464 4.407700 -0.382980 48.199936 58465 26.421257 -0.237061 48.479958 58466 25.900047 -1.107452 48.784500 58467 43.743500 1.026352 49.386078 58468 3.602501 -1.402664 47.969223 58469 24.307922 -0.758316 49.373909 58470 26.650818 -0.949219 48.623543 58471 26.966537 -0.644882 48.803864 58472 42.451553 -2.227722 49.058319 58473 42.616928 -1.155579 49.262573 58474 25.193413 -2.263489 49.624374 58475 26.187035 -1.963379 49.373917 58476 42.956039 -3.261673 48.926910 58477 42.961533 -3.864075 48.396210 58478 47.798004 -4.117874 49.372864 58479 46.587616 -3.881393 49.300690 58480 46.396637 -4.755692 48.499573 58481 49.902847 -4.965012 48.566917 58482 6.330856 -6.365082 48.195831 58483 7.153923 -6.427765 48.216461 58484 8.218895 -6.266479 47.775299 58485 11.228622 -7.525665 48.577530 58486 10.875221 -7.120651 47.779617 58487 45.465027 -4.629150 48.515007 58488 52.426773 -5.435211 48.865417 58489 11.506104 -8.099426 47.612747 58490 27.449310 -8.295822 48.153870 58491 27.347183 -7.091797 48.895828 58492 28.258789 -8.088211 48.112724 58493 28.667946 -6.737823 49.390236 58494 28.688400 -7.455139 48.586487 58495 29.298889 -8.920929 47.930099 58496 28.177582 -9.296539 47.986435 58497 35.466202 -8.013092 48.026611 58498 36.271820 -7.635361 48.950562 58499 37.684120 -6.930984 51.892914 58500 38.655212 -7.341171 49.657227 58501 53.120071 -8.442612 49.246017 58502 33.645699 -8.397903 48.428398 58503 34.530357 -8.228699 48.176361 58504 42.034698 -8.552460 48.530205 58505 42.075684 -8.052353 49.402756 58506 43.002045 -8.624512 49.128441 58507 2.785637 -11.223145 47.813248 58508 8.141228 -10.797134 47.440994 58509 11.658524 -9.622284 48.336128 58510 10.881844 -10.840042 48.398788 58511 11.555260 -9.205170 47.336266 58512 30.012970 -7.995316 48.729424 58513 29.280312 -10.334930 47.875381 58514 43.781754 -9.281036 48.661835 58515 43.746185 -8.857605 49.357323 58516 44.368256 -9.197723 49.437065 58517 45.216171 -9.810471 49.475960 58518 44.518295 -10.083878 48.213547 58519 7.083954 -10.810089 48.349342 58520 52.938843 -10.461014 48.206146 58521 9.715851 -11.170929 47.944511 58522 27.961670 -10.254562 48.708244 58523 27.406281 -9.183228 48.342506 58524 34.386482 -11.789932 47.887657 58525 29.038399 -11.364899 48.647263 58526 36.712601 -11.495132 48.295265 58527 35.458328 -11.500793 48.856949 58528 35.980026 -11.127136 49.691498 58529 39.319191 -11.668640 48.576752 58530 47.368011 -12.635773 48.218025 58531 3.049126 -15.289886 49.249771 58532 3.559937 -15.799500 49.093887 58533 3.521500 -15.471207 48.155251 58534 39.954269 -12.173584 48.132072 58535 47.905487 -12.499786 49.134361 58536 47.255768 -11.717026 49.055008 58537 48.061066 -13.338715 48.425339 58538 3.198608 -14.727722 47.351761 58539 7.871482 -15.740250 46.619858 58540 47.524597 -13.605301 47.810410 58541 48.183807 -14.229401 47.756691 58542 7.705467 -16.106201 47.351891 58543 7.506409 -16.472244 48.419357 58544 6.722420 -16.402191 48.935738 58545 8.543983 -16.100403 47.153816 58546 9.556137 -16.108261 46.996025 58547 10.557083 -16.290070 46.782501 58548 49.144699 -14.301239 47.024109 58549 45.618362 -16.305649 47.639297 58550 44.949463 -15.630478 48.664177 58551 55.835938 -17.117569 48.052948 58552 55.082474 -16.746002 48.941315 58553 11.365524 -17.751831 46.837708 58554 45.392731 -16.595840 48.542755 58555 11.339035 -18.521835 46.900040 58556 32.390030 -19.296112 48.751022 58557 33.534637 -18.685226 47.708870 58558 34.222527 -18.731750 48.621887 58559 38.658226 -18.555939 47.381653 58560 41.901306 -18.945892 47.136497 58561 43.034317 -18.959900 47.626465 58562 49.156479 -19.069046 48.392517 58563 50.159073 -17.931458 48.912750 58564 30.396103 -20.406906 46.745621 58565 55.766418 -20.142609 48.119698 58566 55.485947 -20.824524 47.625977 58567 30.175827 -21.306992 47.122711 58568 11.969429 -22.835861 46.106781 58569 31.558128 -22.888916 48.318977 58570 39.117889 -21.680115 49.401382 58571 47.847717 -20.209091 48.570915 58572 46.898636 -20.862122 49.663368 58573 52.747025 -23.427826 48.510139 58574 53.508209 -22.737976 48.477806 58575 53.959869 -22.072311 47.675583 58576 40.203979 -22.226608 47.218246 58577 10.487869 -23.555649 47.473061 58578 10.116486 -24.928284 48.513901 58579 11.516059 -26.460449 48.390396 58580 11.890114 -25.569427 47.159714 58581 2.452217 -26.860855 47.519821 58582 3.061730 -25.826797 46.940315 58583 4.789749 -26.371765 47.546616 58584 3.869087 -25.640488 46.928757 58585 5.552689 -25.465881 46.455475 58586 6.239929 -25.296158 46.124153 58587 2.189346 -27.684891 46.156349 58588 47.888443 -25.901642 47.322456 58589 47.739868 -26.158813 48.271858 58590 55.423920 -25.824463 47.214119 58591 56.173569 -25.667542 47.062569 58592 55.882874 -26.249741 47.642227 58593 45.433121 -26.934525 47.161156 58594 44.773163 -27.479691 47.028549 58595 14.920700 -27.718719 46.104507 58596 44.136398 -28.258728 47.289513 58597 54.837799 -26.836288 48.036530 58598 56.401321 -27.047333 47.976006 58599 15.793732 -29.164566 45.626549 58600 15.351395 -29.143997 46.254608 58601 49.751373 -29.095062 46.991325 58602 49.751556 -29.178421 48.146545 58603 48.603210 -29.720093 47.518539 58604 14.848267 -30.258133 46.894302 58605 14.916519 -31.218231 46.105110 58606 34.762436 -30.917740 46.288567 58607 36.440659 -29.943634 46.371269 58608 39.164505 -29.800476 47.279388 58609 41.297760 -29.701904 47.913528 58610 42.309982 -29.935318 49.013763 58611 43.127548 -29.605698 48.932678 58612 43.162537 -29.246460 48.170258 58613 47.589752 -30.286499 46.824203 58614 47.418015 -30.519928 47.605331 58615 2.459496 -31.467987 45.921738 58616 55.706268 -31.256088 47.000984 58617 56.067688 -30.704239 47.096382 58618 2.258247 -32.438797 45.840874 58619 2.176880 -33.493683 45.697556 58620 33.101761 -32.906265 47.601143 58621 44.829025 -32.736435 48.246315 58622 43.755508 -33.212769 47.990021 58623 44.065674 -32.831558 46.889374 58624 2.265396 -31.508789 46.633476 58625 31.936029 -32.888153 46.411514 58626 50.462341 -33.285721 47.005882 58627 7.837112 -33.351822 46.108475 58628 13.690521 -34.571686 46.206177 58629 14.327126 -35.332047 44.839066 58630 37.360237 -33.997101 46.496063 58631 42.366730 -33.336258 47.075188 58632 40.777267 -33.713287 48.035858 58633 38.372696 -33.858017 47.138588 58634 39.282204 -34.152191 48.486244 58635 41.813599 -33.719177 48.388138 58636 45.981506 -32.150696 48.947083 58637 2.187042 -34.103653 45.953606 58638 7.458572 -34.743271 46.071480 58639 7.218582 -33.627625 46.456207 58640 13.603256 -33.188843 46.721283 58641 13.105675 -33.350327 47.148575 58642 28.600372 -35.240250 47.466423 58643 3.079765 -36.343079 46.760201 58644 6.748741 -34.263504 46.754967 58645 13.217239 -35.857193 47.071358 58646 26.676964 -35.783249 46.732605 58647 35.766296 -35.304214 46.820061 58648 35.568459 -36.083908 48.414818 58649 34.638390 -36.465424 47.775131 58650 36.996292 -34.661636 47.502037 58651 7.906723 -37.089401 46.591774 58652 15.230751 -37.400574 45.677231 58653 23.828979 -38.692413 47.125854 58654 24.296722 -38.320831 47.960503 58655 33.876961 -36.505447 46.145454 58656 3.508728 -39.934708 45.973206 58657 10.485779 -38.029938 45.790321 58658 32.432281 -37.458862 46.332207 58659 49.743622 -36.406830 47.549736 58660 50.738861 -36.927017 48.108856 58661 23.704193 -39.120422 46.056572 58662 28.522400 -39.158127 45.717995 58663 32.268639 -38.440750 48.195137 58664 31.129387 -38.762894 47.999046 58665 36.952042 -39.882050 46.461685 58666 44.811874 -38.871811 46.677345 58667 45.101227 -38.786835 47.582687 58668 44.436066 -38.791931 48.554520 58669 45.674606 -39.335831 46.821251 58670 51.531036 -37.817932 47.259338 58671 51.493896 -38.862564 46.291855 58672 52.008514 -38.753098 46.879532 58673 13.518799 -40.592819 45.842445 58674 14.319412 -40.126678 45.539810 58675 15.006264 -39.324493 45.959724 58676 23.246094 -39.700058 46.895348 58677 23.189697 -40.700027 46.112137 58678 27.722427 -39.661758 46.135323 58679 45.699188 -40.076569 46.301422 58680 45.913773 -40.719376 46.599693 58681 52.420181 -38.573029 47.701073 58682 5.210625 -41.128098 44.041138 58683 12.520653 -39.713959 45.655334 58684 26.843384 -40.896332 47.297112 58685 26.250412 -41.606277 46.342720 58686 13.468918 -41.500198 46.476372 58687 12.498436 -40.861053 46.440170 58688 14.550278 -40.878601 46.695717 58689 13.837929 -42.160675 46.979149 58690 23.831512 -41.579498 45.156052 58691 25.899704 -42.663498 46.779625 58692 37.707458 -41.739807 46.302689 58693 38.383743 -42.112228 46.317329 58694 44.222855 -41.720215 46.282860 58695 45.284683 -41.273300 46.649918 58696 46.221817 -40.094269 46.862648 58697 7.919425 -42.793137 45.525482 58698 22.913025 -42.542160 46.880608 58699 22.877205 -41.503479 46.885048 58700 38.058212 -43.799835 45.678345 58701 38.800613 -42.873108 46.234100 58702 52.613464 -41.231308 47.116463 58703 42.755081 -43.131592 46.082947 58704 7.363815 -43.441650 46.728165 58705 6.581238 -44.120651 46.572769 58706 36.869110 -45.179474 45.555374 58707 39.200920 -43.601532 46.926857 58708 38.668953 -43.826935 46.300301 58709 38.167412 -44.982010 46.767258 58710 41.645966 -44.706085 46.040703 58711 52.685181 -44.566513 46.904213 58712 3.747688 -46.515656 45.653870 58713 40.712418 -46.060104 45.894272 58714 32.336914 -46.614716 45.436569 58715 33.076660 -46.601868 46.056206 58716 34.083542 -46.303299 45.792580 58717 46.371368 -46.987579 46.608948 58718 45.420822 -47.648407 46.876503 58719 46.098892 -47.616684 47.567924 58720 50.735123 -45.874802 46.479187 58721 6.120735 -48.983200 44.752914 58722 31.209595 -48.698990 45.509544 58723 38.091248 -49.065521 45.489418 58724 43.942963 -48.204254 45.530830 58725 43.505249 -49.162369 45.459648 58726 44.964767 -47.391739 45.848671 58727 6.494827 -49.912613 45.059235 58728 36.366211 -51.131714 45.668251 58729 35.198212 -50.770935 44.203209 58730 38.044449 -49.569077 46.477013 58731 6.904221 -50.469742 44.750282 58732 29.634949 -51.361877 45.601837 58733 30.620605 -51.127228 45.978218 58734 49.049988 -50.159790 45.729538 58735 47.869659 -50.629654 46.544510 58736 50.095657 -50.471466 45.902847 58737 50.512482 -51.634659 47.268799 58738 49.707718 -51.386612 47.821335 58739 50.159943 -50.982086 46.826607 58740 35.889519 -51.886307 44.860558 58741 37.002533 -50.926819 46.349586 58742 36.667191 -51.911102 45.934380 58743 44.277130 -50.973892 46.547150 58744 43.718842 -50.711349 47.152786 58745 43.606064 -50.132614 46.115349 58746 44.051086 -51.033234 47.508789 58747 49.311340 -50.700928 46.751877 58748 7.643783 -52.450287 44.761703 58749 10.783630 -52.589096 45.321365 58750 9.855286 -52.758820 45.397980 58751 10.788017 -52.509842 45.742027 58752 10.900124 -53.011032 44.712593 58753 12.139618 -53.808670 45.181099 58754 25.911316 -52.549683 45.207764 58755 25.204086 -53.241669 45.346825 58756 27.574142 -52.045273 45.757050 58757 28.840683 -52.119034 46.451027 58758 26.539703 -52.332916 45.778160 58759 8.460426 -52.799591 44.689140 58760 24.875977 -53.852921 45.279686 58761 36.712387 -52.924026 45.136154 58762 36.340462 -52.048828 45.521767 58763 24.960915 -54.494537 45.432152 58764 37.718979 -53.397537 45.556503 58765 51.367859 -54.599106 45.409599 58766 51.712921 -54.003311 45.522057 58767 11.917839 -55.208191 45.067123 58768 27.800888 -55.536774 45.310875 58769 26.812805 -55.528931 45.368362 58770 28.695999 -55.447769 45.323555 58771 43.683105 -55.263672 45.830147 58772 41.443146 -55.090591 46.474991 58773 42.811432 -55.384964 48.094017 58774 45.496078 -55.289917 45.946594 58775 46.728638 -55.073868 45.737419 58776 47.463348 -54.869568 45.135643 58777 10.944031 -56.130203 44.356964 58778 24.829659 -55.227859 46.358192 58779 24.196350 -55.607300 47.499374 58780 24.027176 -54.703064 47.098831 58781 25.750778 -55.282730 45.564445 58782 50.032150 -54.795303 46.285866 58783 5.451462 -57.563873 44.493324 58784 6.190796 -57.480484 44.287292 58785 7.127113 -57.446869 43.956146 58786 8.753418 -57.233170 45.766846 58787 34.117188 -55.961151 45.150970 58788 3.834435 -58.388077 44.877861 58789 3.713738 -58.686646 45.018219 58790 4.976250 -57.765869 44.361122 58791 36.948959 -56.885223 47.062515 58792 46.103821 -59.406891 44.928192 58793 43.455475 -59.581482 45.373878 58794 5.144341 -60.122574 45.650932 58795 4.411461 -61.115356 44.869789 58796 4.035370 -59.508743 45.152786 58797 38.966331 -59.660278 44.831848 58798 38.790627 -59.623764 45.212952 58799 39.302910 -59.854752 45.242523 58800 39.978897 -59.840195 45.745842 58801 42.892090 -59.363861 48.355637 58802 42.445526 -59.674057 46.593582 58803 45.152161 -59.731812 46.835144 58804 46.777344 -59.961655 45.972672 58805 23.302734 -61.363480 45.015213 58806 47.265854 -60.844025 46.018677 58807 47.270401 -60.334076 45.991318 58808 9.492371 -62.605545 44.212379 58809 9.142349 -62.340942 44.461548 58810 10.036545 -62.308884 44.569130 58811 10.094002 -63.093277 44.161301 58812 21.769814 -62.625153 44.776329 58813 21.965576 -61.817337 45.297501 58814 24.612137 -61.935715 45.272606 58815 26.939606 -62.993637 44.833939 58816 47.146240 -61.577850 45.416527 58817 8.844193 -63.235229 44.358322 58818 9.996094 -64.150040 44.020813 58819 10.868141 -63.921875 44.218742 58820 11.014191 -63.071411 44.697327 58821 45.876190 -62.353394 47.056107 58822 46.471497 -62.031494 46.596062 58823 10.949570 -64.962280 44.170883 58824 9.955322 -65.204025 43.958900 58825 23.183609 -64.959564 44.169121 58826 28.218628 -64.017166 44.900177 58827 35.470093 -65.022507 44.823448 58828 35.959885 -64.995316 44.321159 58829 36.181931 -66.005417 45.193153 58830 8.799652 -64.498627 44.282898 58831 8.792259 -65.512726 44.224907 58832 10.748215 -65.940826 44.013565 58833 9.759986 -66.191208 43.959564 58834 28.771225 -65.784042 44.966507 58835 36.300751 -66.812881 44.423141 58836 42.943161 -65.833237 44.862747 58837 43.793411 -65.244598 44.895805 58838 8.644302 -66.323944 44.224770 58839 10.583107 -67.077469 44.052734 58840 8.953445 -67.109558 44.104362 58841 24.131653 -67.364120 45.083862 58842 23.554321 -66.409653 45.075363 58843 29.346382 -66.958069 44.327667 58844 33.872757 -66.020599 45.382362 58845 42.615784 -65.819870 46.344658 58846 43.292496 -65.139557 46.026535 58847 9.555389 -69.304596 43.692078 58848 10.783539 -69.070633 43.883003 58849 10.684944 -69.898849 43.942139 58850 10.721840 -68.319901 43.992836 58851 29.992889 -67.513229 44.483757 58852 36.049904 -67.665039 44.242615 58853 39.508698 -67.991638 43.767059 58854 40.078613 -67.831375 44.492264 58855 40.886398 -67.099274 44.723175 58856 7.484284 -67.987885 44.366287 58857 7.543060 -66.840256 44.454269 58858 9.260765 -68.145523 43.898979 58859 11.414078 -68.732834 44.827103 58860 11.254700 -70.325668 44.954140 58861 19.919312 -70.368698 43.713409 58862 31.739267 -67.940369 44.836006 58863 4.822563 -67.153336 44.463463 58864 8.015945 -69.112289 44.056107 58865 8.333771 -69.897751 43.819336 58866 10.978973 -71.020676 44.039688 58867 25.750870 -70.122620 43.995926 58868 25.318130 -69.167511 44.347649 58869 39.809410 -69.122025 45.923866 58870 39.953339 -69.532501 44.237427 58871 9.097534 -70.831085 43.610672 58872 11.527855 -70.868805 44.469955 58873 17.159119 -70.770798 44.326225 58874 20.643341 -71.373276 43.532219 58875 20.233368 -70.908264 44.026741 58876 7.027512 -70.296844 44.021896 58877 7.581421 -71.709229 43.543716 58878 10.447754 -71.974243 43.652481 58879 11.198577 -71.939285 44.418793 58880 11.042755 -72.700241 44.057510 58881 17.060928 -71.496750 44.669975 58882 17.237717 -71.881470 45.015411 58883 21.393501 -73.417328 43.719421 58884 26.278374 -70.569504 45.026833 58885 27.399185 -71.746155 43.991455 58886 28.914841 -72.275421 44.339226 58887 28.179688 -71.786118 43.724602 58888 39.102646 -70.717804 45.520859 58889 38.498672 -71.803970 44.945122 58890 5.395386 -71.466034 43.452789 58891 5.713760 -72.287842 43.051338 58892 7.066460 -73.229080 43.003517 58893 8.985221 -72.381210 43.335075 58894 10.380455 -72.929337 43.587860 58895 9.500259 -73.803284 43.398178 58896 28.065536 -72.318130 44.864532 58897 29.025360 -72.878220 45.461487 58898 6.323967 -71.628616 43.615494 58899 8.506706 -75.530273 43.214569 58900 10.748337 -73.695572 44.320015 58901 10.159561 -74.846283 43.844627 58902 10.651978 -74.611343 44.441536 58903 10.430283 -75.156799 44.502411 58904 17.546600 -73.686829 44.681664 58905 7.687469 -76.838196 42.958092 58906 17.519226 -75.366013 43.485245 58907 17.487717 -76.426651 44.445892 58908 17.921387 -74.949753 45.441612 58909 22.615425 -75.607040 44.407791 58910 31.268967 -75.064133 44.655029 58911 30.812759 -73.941498 44.775833 58912 7.741928 -77.762100 43.165703 58913 16.780388 -77.167709 44.173172 58914 24.490280 -77.472351 45.065796 58915 25.685089 -77.939240 45.926849 58916 10.672852 -79.938644 43.672722 58917 26.912811 -78.595322 45.120087 58918 27.321060 -79.239136 44.243401 58919 9.468430 -80.268417 44.166603 58920 8.949112 -79.733475 43.194969 58921 12.179367 -79.197388 43.776596 58922 28.414764 -80.115570 43.465294 58923 28.437721 -80.427124 42.867538 58924 29.233955 -79.067749 44.278015 58925 28.880722 -78.345642 45.008308 58926 16.674995 -82.444885 42.527046 58927 15.511322 -82.880264 42.228394 58928 18.920410 -81.886444 42.536118 58929 17.309509 -82.124863 42.742744 58930 18.313766 -81.737686 42.736481 58931 15.876381 40.999176 51.909195 58932 16.760910 40.345230 52.675919 58933 15.831123 40.483246 53.039040 58934 17.354149 40.698456 51.897873 58935 18.670120 40.620697 51.802986 58936 19.548470 40.359283 51.836723 58937 10.974960 39.447281 51.848351 58938 10.114235 37.678497 51.288132 58939 7.723709 37.124359 51.918686 58940 7.315521 36.565689 51.705780 58941 9.096191 37.631058 51.714455 58942 6.864410 35.898651 51.417992 58943 6.236336 36.615662 52.623337 58944 21.699585 35.514801 51.700150 58945 21.395508 36.458588 52.499908 58946 21.395088 35.686920 51.180794 58947 22.131760 34.283829 51.558449 58948 21.808121 35.019897 52.775040 58949 4.059990 34.322952 52.616676 58950 22.270355 32.808319 52.398232 58951 22.285919 33.792679 52.359161 58952 3.815712 30.603027 51.798241 58953 3.814293 31.436096 51.973915 58954 17.757141 29.757446 51.706161 58955 17.263481 28.055008 51.072388 58956 16.806641 29.461273 51.842529 58957 19.538452 30.163025 51.520683 58958 16.278671 28.537598 52.231880 58959 17.188370 27.113586 50.678535 58960 3.909302 25.982224 54.313438 58961 3.987061 25.160187 53.465149 58962 17.289993 26.704010 50.963013 58963 17.039505 27.194138 51.101173 58964 17.848724 25.835541 50.576958 58965 31.693651 25.742477 50.799103 58966 32.814537 26.047760 50.509514 58967 33.644943 25.826599 51.189125 58968 19.214050 24.086975 50.487762 58969 19.078377 25.173340 51.115494 58970 20.482445 23.761871 51.099503 58971 19.849716 22.777130 50.311920 58972 5.064995 23.991913 52.232811 58973 5.579628 23.626266 51.243805 58974 4.794388 24.293518 51.325989 58975 7.949630 22.424454 50.431854 58976 6.635033 23.041901 51.145493 58977 7.391098 22.773193 50.666206 58978 20.691063 22.657837 50.775352 58979 21.558472 22.464767 50.966850 58980 32.152390 25.097000 51.311073 58981 32.002525 22.524948 51.878944 58982 33.201309 24.142654 52.171661 58983 8.491791 21.903595 50.175179 58984 37.941818 22.334885 50.988350 58985 8.548615 21.147369 50.215126 58986 19.928986 21.633469 49.708267 58987 20.764481 21.840088 50.213402 58988 23.568237 22.673309 51.785851 58989 23.807816 21.309143 51.029076 58990 39.043907 20.665558 51.198029 58991 22.422600 23.113739 51.647133 58992 24.441841 20.052368 50.822006 58993 30.944359 20.336884 50.539268 58994 31.607088 21.347626 50.543167 58995 7.215485 19.631821 50.818886 58996 25.076561 20.423126 51.855652 58997 24.548012 18.814590 51.714699 58998 25.071030 19.717209 53.015617 58999 39.880341 19.449234 51.226761 59000 39.579765 20.073120 51.244370 59001 5.134087 18.523941 50.671234 59002 6.191422 19.233215 50.927956 59003 7.924902 20.333008 50.880447 59004 30.014343 19.282257 51.064354 59005 29.176010 17.553833 50.531784 59006 39.563263 18.417999 51.111374 59007 37.858414 16.870483 50.322342 59008 38.419991 17.340958 51.172905 59009 3.822991 17.813858 51.523468 59010 3.618126 16.868500 51.332802 59011 19.417465 15.573975 51.226234 59012 20.608521 15.998657 51.067139 59013 36.050720 16.346756 51.096367 59014 4.403420 14.327805 49.861290 59015 4.096794 15.608917 49.490166 59016 18.543694 14.971176 50.660713 59017 4.827141 13.555313 49.925636 59018 24.637695 13.681702 50.277046 59019 25.536636 14.136597 50.494736 59020 27.371872 14.702271 50.119934 59021 26.014954 14.939896 51.469025 59022 6.625412 11.949280 50.017776 59023 5.956062 12.990204 50.831329 59024 6.779373 12.732666 51.458984 59025 22.348877 12.532669 50.099091 59026 22.717430 13.053528 51.232613 59027 35.843895 12.547318 50.681198 59028 36.786690 12.717499 50.336990 59029 37.169540 12.809204 51.383194 59030 37.769920 13.228699 52.333954 59031 7.162926 11.875610 51.094406 59032 16.492287 11.480331 50.779388 59033 16.495285 12.426270 51.044205 59034 21.531479 11.741119 49.858490 59035 21.898987 12.021606 50.892670 59036 34.670563 13.239761 51.097664 59037 35.183334 12.639313 50.733177 59038 44.975922 10.441483 50.706352 59039 6.856148 9.694534 49.233826 59040 6.705765 10.133652 50.406075 59041 3.268135 8.111237 49.563179 59042 4.151863 9.033966 50.450012 59043 22.910873 9.824966 51.069878 59044 24.856735 8.944397 51.325615 59045 23.671532 9.058319 50.709190 59046 17.234573 8.915604 50.307106 59047 17.365875 10.254364 51.703522 59048 25.564850 8.160522 50.525482 59049 25.500381 7.483368 49.938049 59050 26.350342 7.712509 50.816559 59051 25.770004 6.544220 50.429909 59052 39.659500 7.539902 50.129555 59053 37.120132 6.929886 49.597412 59054 40.742523 7.642670 50.242775 59055 17.878189 7.305649 49.256287 59056 18.893280 6.589096 49.669968 59057 19.954262 4.910049 49.851974 59058 20.142014 6.179703 51.173325 59059 25.466965 5.386047 51.409607 59060 35.574997 3.326126 50.083282 59061 35.470993 4.121567 49.889694 59062 4.203209 3.545319 49.953819 59063 4.839844 3.216118 50.007225 59064 20.095840 3.425201 49.430977 59065 24.825394 3.666351 49.679840 59066 40.999207 3.652451 49.942772 59067 42.121078 3.871918 50.512810 59068 42.960083 3.977753 51.382027 59069 6.274071 2.090210 49.337868 59070 5.673149 2.838989 49.980659 59071 20.169800 2.953690 48.871902 59072 25.420044 3.476654 50.647980 59073 25.082153 4.376846 50.687210 59074 25.522171 2.688873 49.770264 59075 39.622398 3.135338 50.355423 59076 6.259743 1.182312 48.841873 59077 6.574211 2.583481 50.260681 59078 7.328949 2.418900 51.123016 59079 7.614006 1.652679 49.929550 59080 8.420624 0.980804 50.109093 59081 8.350075 1.410202 51.067055 59082 20.827965 1.498459 49.550323 59083 26.413132 2.018127 49.770584 59084 26.196243 2.427521 50.347809 59085 38.265076 2.892578 49.828575 59086 44.540085 2.118362 50.084023 59087 7.045921 1.228195 49.164963 59088 7.752685 0.803543 49.420105 59089 7.017670 0.101593 49.295776 59090 8.166840 0.894592 49.725624 59091 20.371979 2.259338 50.246666 59092 27.186172 1.778488 50.438911 59093 27.810913 0.577057 50.022888 59094 28.100784 1.256607 50.755684 59095 43.956039 -0.801483 49.806396 59096 44.894318 0.739594 50.214149 59097 3.102646 -3.077087 48.201172 59098 4.965530 -0.958847 48.731003 59099 4.341393 -1.251999 48.538216 59100 5.970070 -1.070557 49.364433 59101 27.340637 -0.509018 49.437294 59102 3.116150 -4.350571 48.750336 59103 26.839508 -1.390793 49.314369 59104 42.916519 -2.573883 49.455757 59105 42.998199 -1.738007 49.621506 59106 43.054108 -0.914719 49.596313 59107 24.028549 -2.068741 50.291893 59108 3.129616 -4.518326 50.067871 59109 44.859680 -2.566208 49.646042 59110 43.619232 -2.599136 49.466736 59111 45.680115 -3.711243 49.204239 59112 46.532074 -2.986893 49.835342 59113 45.773407 -2.624115 49.853523 59114 49.475891 -4.196136 50.380615 59115 48.310242 -2.898926 51.121895 59116 51.189148 -5.130295 49.703682 59117 3.336662 -5.891800 50.627701 59118 3.272362 -5.364624 49.336876 59119 3.726616 -6.006943 49.324898 59120 4.499207 -6.102722 48.595421 59121 52.094162 -6.578552 50.370277 59122 51.247650 -5.738861 51.060242 59123 10.734695 -7.244797 49.511375 59124 26.241898 -6.805969 49.361885 59125 25.757263 -7.702042 49.471321 59126 25.566559 -6.149765 50.218979 59127 26.787903 -8.116150 48.630898 59128 26.407478 -7.317245 48.938553 59129 50.323608 -4.738602 51.271347 59130 11.843521 -8.828384 47.885406 59131 11.791290 -8.430847 48.400505 59132 24.601257 -6.956329 50.053421 59133 27.813705 -6.246796 49.851860 59134 31.182060 -7.679672 49.701271 59135 29.195145 -6.236420 50.724113 59136 34.687531 -7.915741 49.201485 59137 34.711334 -7.731903 50.363579 59138 39.694496 -6.807465 51.038956 59139 40.822037 -7.144257 50.870216 59140 26.699821 -9.506058 49.822685 59141 26.053116 -8.911865 50.050140 59142 26.915947 -9.330078 49.207260 59143 31.052208 -7.046829 50.671951 59144 4.833382 -10.688309 49.319420 59145 3.941795 -10.788513 49.530945 59146 3.233933 -10.872009 49.029778 59147 5.667305 -10.438797 48.300949 59148 32.866226 -7.563782 50.639450 59149 52.758789 -9.252167 49.767387 59150 6.185356 -11.157776 49.427330 59151 8.309036 -11.335770 48.600616 59152 4.692322 -11.694031 50.248306 59153 11.287674 -10.825989 49.521957 59154 46.875427 -10.688583 50.122826 59155 52.560623 -10.351822 49.395737 59156 9.387009 -11.959839 49.331848 59157 8.043655 -11.939209 49.731522 59158 29.741180 -12.020020 48.821503 59159 34.412682 -11.775131 48.667938 59160 39.042389 -11.218582 49.293564 59161 37.139465 -10.988632 49.467300 59162 38.114014 -10.647781 51.538483 59163 38.986313 -10.955170 50.072212 59164 40.227539 -11.390121 49.875214 59165 29.426285 -11.804703 49.765472 59166 30.559959 -12.341553 49.374550 59167 31.749872 -11.943878 48.060104 59168 31.614702 -12.312469 48.651367 59169 2.387238 -12.748322 48.642242 59170 43.472076 -13.376892 49.536964 59171 48.434143 -13.106201 49.133842 59172 2.358582 -13.902008 47.938705 59173 49.043488 -13.596848 48.450333 59174 3.888359 -16.006714 48.642006 59175 49.199951 -13.067963 49.545624 59176 48.588196 -12.531952 49.953453 59177 49.457733 -12.658554 50.364113 59178 2.529549 -14.575745 48.796158 59179 5.663376 -16.166733 48.741592 59180 4.511185 -15.899689 48.285324 59181 8.251350 -16.425323 47.991982 59182 9.185783 -16.533340 48.051407 59183 10.076385 -16.520187 47.609543 59184 10.776878 -17.021118 47.417610 59185 10.122406 -17.100754 48.396004 59186 10.823715 -18.142929 47.791908 59187 52.402100 -16.505386 49.152451 59188 53.987885 -16.415878 49.262032 59189 45.362427 -17.238846 48.861153 59190 55.440582 -17.424255 49.122391 59191 10.556168 -19.378769 48.075325 59192 35.265732 -18.702133 49.976120 59193 38.377480 -18.395950 49.674583 59194 37.122810 -18.516052 50.987839 59195 45.144135 -17.905045 48.645523 59196 55.816986 -18.195435 48.691505 59197 39.506691 -18.600403 48.469093 59198 42.145386 -18.734818 48.856377 59199 39.862366 -18.551208 49.511208 59200 40.478302 -18.495239 50.183601 59201 44.342773 -18.393936 48.725060 59202 55.482452 -19.242249 49.371399 59203 55.212891 -18.119873 49.782654 59204 30.277466 -20.845810 47.787750 59205 55.250198 -21.027344 48.636215 59206 55.347519 -20.290878 49.384758 59207 30.355011 -21.453796 47.797989 59208 36.558769 -21.937408 48.213188 59209 37.618774 -21.452484 48.030617 59210 37.457962 -21.357437 48.272842 59211 37.236572 -21.491913 48.098579 59212 37.700546 -21.484406 48.375641 59213 9.415848 -22.905090 48.107971 59214 35.652649 -23.361465 48.513245 59215 47.583359 -19.911514 50.134018 59216 54.315338 -22.091599 49.014877 59217 30.975708 -21.519897 48.556282 59218 31.918344 -23.368301 48.328789 59219 32.346764 -23.583603 48.944870 59220 31.930323 -23.319382 48.690567 59221 37.797737 -22.522354 49.994858 59222 38.162079 -23.334549 51.055832 59223 37.435944 -24.532623 50.710388 59224 51.818878 -24.075668 48.303375 59225 3.357315 -26.463989 47.888794 59226 32.986847 -24.015961 49.126854 59227 34.492996 -25.366699 48.801270 59228 33.587006 -25.140457 49.212997 59229 50.785461 -24.608932 48.035233 59230 50.309967 -25.244293 49.068283 59231 52.262909 -24.211121 49.346420 59232 2.106644 -26.947113 46.800743 59233 12.629669 -26.560150 47.360809 59234 2.132996 -27.804459 47.202858 59235 8.839294 -25.834290 49.883171 59236 10.368896 -27.691437 50.871979 59237 13.951630 -27.768372 47.598061 59238 44.936310 -27.507904 48.125900 59239 45.667542 -26.833588 47.904404 59240 53.526123 -27.512665 48.698433 59241 56.024918 -26.717209 47.983055 59242 14.505356 -27.605820 46.928474 59243 14.874710 -28.287247 47.007904 59244 43.742386 -29.181183 49.054733 59245 44.200272 -28.550247 48.558609 59246 52.350403 -27.940308 48.325089 59247 14.691467 -29.094635 47.609024 59248 50.953491 -28.587799 48.181396 59249 56.077499 -29.119751 47.944252 59250 55.663330 -28.002518 48.576485 59251 55.953033 -27.210892 48.242409 59252 13.842743 -28.556793 48.523224 59253 13.856094 -31.702454 47.467697 59254 37.489731 -31.187195 49.127274 59255 35.833893 -31.962402 48.737724 59256 38.703957 -30.378799 48.728180 59257 55.629669 -30.509674 47.942970 59258 55.269653 -29.285477 49.131561 59259 2.055924 -31.799988 48.082405 59260 2.076668 -33.381897 46.715820 59261 7.208450 -32.555389 47.166229 59262 35.899086 -32.887817 50.187241 59263 36.896004 -32.514725 50.577118 59264 36.747047 -32.110672 49.745026 59265 34.679237 -32.056992 47.833961 59266 6.781769 -33.463501 47.009705 59267 12.549149 -32.870819 48.043945 59268 53.567596 -32.457581 47.842026 59269 31.441757 -33.882736 47.352318 59270 37.645798 -34.217514 47.389641 59271 43.033386 -33.587738 48.528496 59272 47.221222 -31.421417 50.022865 59273 45.905014 -32.854874 50.769928 59274 49.914246 -33.793457 48.007408 59275 50.548615 -33.630402 48.455727 59276 53.364349 -32.781006 49.242332 59277 2.595001 -34.877167 46.272514 59278 2.292542 -34.114655 47.479919 59279 6.635994 -35.821732 46.827744 59280 30.188751 -34.560684 47.306526 59281 30.051819 -35.130615 48.666145 59282 49.310104 -34.646042 48.696487 59283 6.080376 -38.326248 48.534378 59284 4.949272 -38.156311 48.562599 59285 5.243065 -37.596252 47.900322 59286 5.862213 -31.388306 49.245819 59287 6.330193 -30.866776 48.957481 59288 5.739166 -33.427338 48.103111 59289 13.843750 -37.276428 47.444107 59290 14.142288 -38.897003 48.432716 59291 14.733772 -38.674911 47.189972 59292 25.821503 -36.070648 46.902977 59293 33.976547 -37.217758 48.606972 59294 33.457245 -37.147491 47.356079 59295 36.601562 -35.485672 48.588745 59296 8.924393 -37.822586 46.645912 59297 32.424469 -37.711853 47.327057 59298 3.084297 -38.172791 46.693741 59299 9.883514 -38.245743 46.414551 59300 13.981186 -39.909393 49.400124 59301 13.154053 -38.839722 49.867294 59302 33.102821 -37.650803 48.172409 59303 50.576218 -36.542831 49.417778 59304 49.475952 -35.546143 49.623360 59305 49.477158 -36.015640 49.123894 59306 51.869431 -37.468399 48.481995 59307 3.530914 -37.296509 47.635170 59308 4.182686 -37.860397 48.175400 59309 3.386971 -38.804306 48.067566 59310 11.157471 -39.524704 46.567566 59311 9.585358 -38.653488 47.046265 59312 14.974701 -37.890747 46.289223 59313 28.532806 -39.184616 46.709190 59314 30.277039 -38.672119 47.733116 59315 29.566940 -38.705658 47.167694 59316 36.732071 -39.706985 47.906578 59317 37.597633 -39.468140 48.955933 59318 45.342285 -38.885483 48.370178 59319 52.692047 -38.140427 48.737251 59320 11.208900 -40.932220 47.602303 59321 9.624847 -39.441452 47.776123 59322 14.898445 -39.741287 47.349602 59323 22.882599 -40.367096 46.838440 59324 22.819313 -40.784958 46.831375 59325 27.614197 -39.882568 47.223808 59326 27.355629 -40.308014 48.314568 59327 28.827774 -39.226791 47.737740 59328 53.106506 -39.666214 48.617050 59329 4.356758 -40.960159 47.229652 59330 36.113342 -41.243500 46.815636 59331 35.961700 -40.428909 47.317390 59332 35.322510 -41.183441 47.211662 59333 35.042709 -40.624908 48.075813 59334 46.426392 -39.626587 48.119217 59335 45.318542 -39.224350 49.371620 59336 46.499634 -39.554047 50.063835 59337 5.551163 -41.612686 47.004318 59338 14.609589 -40.564697 48.281647 59339 23.941315 -44.563354 47.072754 59340 36.916656 -41.927673 47.274902 59341 46.137787 -41.365967 47.548027 59342 46.511612 -40.503143 47.243980 59343 52.620331 -41.281799 50.882233 59344 53.146622 -40.351501 50.438171 59345 52.885727 -41.711700 49.138123 59346 6.716675 -42.466965 47.102463 59347 6.998512 -43.177689 47.685944 59348 12.509224 -42.286270 47.221802 59349 11.211135 -42.374741 48.317108 59350 24.974243 -44.270889 46.678017 59351 25.373459 -43.504211 46.538254 59352 25.723602 -43.813110 47.611069 59353 35.138008 -41.780823 47.418571 59354 34.865311 -41.349121 47.463066 59355 35.937866 -41.897202 47.276047 59356 38.187637 -42.090164 47.176575 59357 39.053055 -42.420547 46.928047 59358 39.300415 -42.848984 46.767776 59359 39.505554 -42.854004 47.281052 59360 45.082321 -41.888885 47.239578 59361 22.865242 -43.161987 47.474075 59362 39.892258 -43.355042 48.085411 59363 5.754631 -43.783722 48.002144 59364 4.649147 -44.035538 47.994423 59365 23.109879 -43.993362 47.515999 59366 24.839676 -44.896729 47.715836 59367 23.918106 -45.464615 48.488213 59368 24.530624 -44.486496 46.537262 59369 39.278999 -44.464111 47.587471 59370 42.781494 -44.318451 47.534523 59371 2.950554 -46.541656 46.516273 59372 3.299080 -45.582718 46.356232 59373 24.600334 -44.683914 46.875679 59374 41.541336 -45.638794 47.076385 59375 52.460785 -45.485413 47.605804 59376 52.710037 -45.018250 47.444748 59377 2.624420 -45.658020 47.303444 59378 3.297600 -44.832199 47.123917 59379 32.884354 -47.712677 47.192078 59380 32.405510 -48.541000 47.224976 59381 32.641586 -48.495987 47.525436 59382 33.730820 -46.880920 46.756241 59383 34.681297 -46.662735 46.637543 59384 36.717285 -46.019531 46.767105 59385 47.937729 -46.770569 47.018631 59386 47.150909 -47.439606 48.094696 59387 49.110291 -46.824448 47.587486 59388 50.133499 -46.507889 47.352081 59389 50.878326 -46.286850 47.438858 59390 51.610580 -45.781067 48.191719 59391 32.140640 -47.456146 46.110100 59392 32.972115 -47.032486 46.629158 59393 35.558609 -46.614807 47.002373 59394 36.297729 -46.742996 48.233330 59395 3.292656 -48.091339 46.432617 59396 4.034279 -50.325226 46.296692 59397 4.389267 -48.955948 45.651627 59398 5.479469 -49.948914 45.502609 59399 32.026512 -48.685913 46.583817 59400 44.564072 -48.168488 46.737694 59401 6.406731 -50.752991 45.294724 59402 5.977318 -51.127090 45.803825 59403 31.414215 -50.267639 46.209938 59404 32.494080 -49.493774 47.377075 59405 43.785980 -49.158203 46.720207 59406 5.736763 -52.275665 46.533142 59407 6.427590 -51.757874 45.611443 59408 37.497490 -50.180054 46.626328 59409 43.650772 -50.070023 47.287979 59410 46.599136 -50.964218 46.779594 59411 50.868027 -51.374969 46.399841 59412 51.500885 -52.025253 45.966568 59413 7.165047 -52.355560 45.329170 59414 6.766525 -52.493927 45.936432 59415 8.181915 -52.766968 45.605560 59416 10.931007 -52.595535 46.520935 59417 9.405106 -52.783676 46.578293 59418 11.407944 -52.777695 45.704727 59419 25.712830 -52.839569 46.319138 59420 26.798798 -52.710190 47.081497 59421 30.516571 -51.919434 47.108963 59422 31.164841 -51.304504 46.536819 59423 45.480072 -51.096695 46.653656 59424 7.345978 -52.746994 45.833199 59425 12.387405 -54.466675 44.872276 59426 24.656342 -53.907104 46.120865 59427 25.058929 -53.205582 46.128334 59428 37.264015 -52.129120 46.336937 59429 37.939911 -52.504532 46.833946 59430 51.337860 -53.959137 46.152168 59431 50.866852 -52.866867 47.005577 59432 29.584694 -55.496109 45.973015 59433 38.422089 -52.327789 47.807907 59434 47.790344 -55.180115 46.108093 59435 48.944275 -55.122467 45.991539 59436 50.925369 -54.614380 46.032600 59437 50.734131 -54.110809 46.689255 59438 10.456978 -56.416733 45.163185 59439 23.886162 -54.337616 47.224319 59440 24.224167 -53.963913 47.120163 59441 25.653671 -55.985092 47.113586 59442 27.744415 -55.974579 46.665276 59443 26.734039 -55.969925 46.752014 59444 28.882477 -55.880249 46.674721 59445 33.280083 -55.335968 45.849068 59446 33.909286 -55.469238 46.877365 59447 35.216339 -55.552002 47.899406 59448 45.557861 -55.681931 47.167740 59449 46.833801 -55.461029 47.124344 59450 5.069336 -57.863770 45.045677 59451 5.920868 -57.671280 45.235641 59452 7.094963 -57.574173 45.184181 59453 38.387657 -58.483841 46.598129 59454 4.331429 -58.399124 45.363197 59455 40.666351 -59.428894 46.981079 59456 39.878906 -58.800415 47.752853 59457 39.318291 -58.938980 46.986946 59458 39.160393 -59.416138 45.963844 59459 41.028046 -59.816467 45.650055 59460 42.068024 -59.801361 45.675217 59461 44.666443 -59.903442 49.183556 59462 44.934814 -59.688019 48.117233 59463 4.341255 -64.218597 44.388565 59464 8.117385 -62.317719 44.762489 59465 7.582024 -61.340622 45.292915 59466 9.256218 -61.696854 45.050430 59467 10.648956 -62.102371 45.683601 59468 22.541962 -61.461334 45.352104 59469 6.359207 -62.432602 45.078125 59470 5.844383 -61.243454 45.350067 59471 9.444244 -61.159805 47.356491 59472 8.908478 -60.737686 46.052048 59473 8.350128 -59.343124 46.960602 59474 11.536812 -63.122116 45.275887 59475 21.317993 -62.599731 45.501991 59476 46.737259 -61.348938 46.836113 59477 46.671814 -60.476837 46.833572 59478 4.965004 -63.338608 44.890778 59479 4.767410 -62.292801 44.852814 59480 7.314087 -65.118362 44.621162 59481 11.614822 -64.209320 45.066628 59482 22.337006 -63.802719 44.392776 59483 21.569283 -63.722946 45.104019 59484 25.901855 -62.685913 45.654480 59485 27.982094 -62.844406 46.514267 59486 28.628891 -62.390518 46.564384 59487 28.674019 -63.120255 45.780907 59488 29.710922 -62.190414 46.938782 59489 7.378471 -63.113068 44.758583 59490 6.211258 -63.570816 44.985748 59491 7.725692 -66.004105 44.461044 59492 7.458893 -64.001633 44.655914 59493 11.561859 -63.273438 45.770142 59494 22.310211 -64.796997 44.904732 59495 27.728050 -63.258102 45.328575 59496 29.050522 -64.636185 45.386543 59497 4.522194 -65.059891 44.503479 59498 5.135986 -64.422714 44.904457 59499 4.913643 -65.365662 44.787926 59500 6.320366 -64.433960 44.923897 59501 22.314804 -65.498367 45.386642 59502 21.514450 -64.796524 45.557846 59503 23.078094 -65.666275 44.905342 59504 29.044388 -65.757996 45.411369 59505 35.202568 -65.454300 45.602386 59506 34.516342 -65.555069 45.641991 59507 43.935471 -64.379471 46.036346 59508 4.543602 -65.986221 44.371231 59509 5.262756 -66.184067 44.808701 59510 5.791908 -65.256073 44.916695 59511 22.861557 -66.063126 45.453667 59512 29.547302 -65.657455 45.908012 59513 30.663208 -63.932571 46.537888 59514 35.651520 -66.028564 46.215858 59515 34.616837 -66.156906 46.128784 59516 35.315933 -66.892410 46.890884 59517 11.586266 -66.041428 44.882782 59518 24.905045 -68.496124 44.845840 59519 29.177612 -66.520218 45.207535 59520 36.175667 -66.580811 46.520599 59521 41.879700 -66.595825 45.255997 59522 6.541817 -66.119370 44.767586 59523 6.084099 -67.231522 44.733627 59524 29.586334 -67.378967 45.209282 59525 33.064346 -67.577225 45.950615 59526 40.822571 -67.585144 45.086281 59527 41.319687 -67.298157 45.475021 59528 41.741913 -66.810501 46.593391 59529 6.089783 -68.275894 44.730370 59530 6.566254 -69.086716 44.511879 59531 11.614532 -67.598175 44.751747 59532 30.352646 -67.935059 45.418320 59533 31.488449 -68.084976 45.343582 59534 40.836014 -67.798157 45.803688 59535 5.457749 -69.040054 44.590721 59536 5.967651 -69.730347 44.445038 59537 5.462364 -70.209732 43.954681 59538 11.414291 -71.226059 44.631088 59539 35.815636 -69.888992 46.168800 59540 4.958824 -70.768799 43.309059 59541 25.505516 -69.452515 45.050377 59542 35.674072 -71.401749 45.251404 59543 19.304924 -70.762009 45.164391 59544 20.731094 -72.011826 44.502029 59545 25.890961 -69.736481 46.298866 59546 26.827530 -71.381500 45.117798 59547 35.557579 -70.744553 45.845497 59548 11.138016 -72.697220 44.814117 59549 17.383980 -72.725311 45.062729 59550 27.289040 -71.921967 44.903717 59551 17.581810 -73.647339 45.623779 59552 21.710396 -73.921204 44.767395 59553 21.173630 -72.689316 45.787895 59554 37.398239 -72.486420 44.885338 59555 36.709869 -72.486832 45.509117 59556 8.496857 -77.049362 43.635048 59557 9.257545 -76.506714 44.037262 59558 9.046539 -77.117813 44.290527 59559 9.852768 -75.818848 44.201317 59560 8.264343 -77.911438 43.688690 59561 8.649567 -77.627396 44.120529 59562 23.362831 -76.565186 45.284439 59563 8.092293 -78.767456 43.316376 59564 8.405862 -78.343460 44.190681 59565 12.852585 -78.603531 43.612762 59566 13.143295 -79.028931 44.144562 59567 17.222000 -77.445541 44.937080 59568 8.570724 -79.435547 44.359589 59569 14.298935 -79.029861 44.677353 59570 29.224640 -75.875076 47.579597 59571 28.830002 -77.119690 46.723297 59572 27.732986 -76.953293 47.788086 59573 12.591553 -79.728333 44.491913 59574 28.236679 -79.578934 44.067764 59575 29.176208 -79.515289 43.811066 59576 9.320206 -80.165543 45.351723 59577 10.262695 -80.507462 44.748924 59578 12.834610 40.923187 52.783241 59579 11.205688 40.139679 52.589539 59580 19.281387 39.952194 52.397537 59581 8.368782 39.421387 54.563324 59582 7.446426 39.086151 54.396118 59583 7.695999 38.896667 53.725288 59584 10.223083 39.384567 52.390144 59585 10.253868 39.844070 52.919067 59586 18.050529 39.612579 53.144234 59587 9.184280 38.657623 52.431091 59588 19.578773 39.313202 52.784470 59589 20.520493 38.136505 52.671532 59590 7.640579 38.064758 52.852478 59591 8.421448 38.914719 53.272568 59592 21.789047 33.643585 53.411179 59593 3.817101 31.235794 53.254631 59594 19.715088 32.336533 53.701881 59595 20.459961 33.131058 54.270226 59596 21.049042 32.650452 53.653687 59597 15.367828 30.702148 52.208046 59598 14.819946 30.692703 52.608124 59599 15.237381 31.040009 52.366043 59600 15.886215 30.018555 52.250641 59601 16.737282 30.761780 52.421600 59602 20.628174 30.578964 51.729424 59603 21.422775 31.946899 52.989426 59604 21.772255 32.478729 53.051682 59605 17.737915 31.707092 53.184082 59606 3.875549 28.275650 52.831573 59607 16.912170 27.265747 51.902512 59608 16.331375 27.722763 52.703278 59609 17.958618 26.457657 51.872604 59610 17.315704 27.008560 52.596031 59611 18.017471 27.725967 53.942116 59612 20.884613 28.144485 55.066086 59613 19.477097 28.715942 55.727234 59614 32.260208 25.792480 51.080666 59615 32.972275 25.414764 51.454735 59616 33.999832 25.280060 51.698486 59617 22.000183 28.488434 55.586731 59618 21.530937 28.746887 55.817017 59619 35.089371 24.548370 51.852654 59620 20.886917 25.061142 51.993660 59621 21.544479 24.262482 51.854347 59622 21.543686 25.207397 52.317673 59623 20.394073 24.875931 51.626419 59624 21.551880 23.363708 51.524185 59625 8.241769 21.883453 50.915535 59626 8.153107 21.219070 51.237839 59627 7.544960 22.476868 51.422050 59628 6.673355 22.639801 52.705055 59629 23.034073 24.585709 52.459084 59630 32.744743 23.083557 52.939735 59631 37.510208 21.979858 51.929970 59632 24.633270 21.870239 51.907021 59633 25.505524 20.733917 52.388023 59634 25.353920 21.593796 52.314873 59635 30.996536 20.878052 51.700874 59636 38.400681 20.477768 51.946411 59637 37.282745 20.666138 52.970947 59638 36.496696 22.207581 52.959679 59639 39.083755 20.223602 51.577499 59640 6.719475 19.970963 51.884445 59641 39.181862 19.567932 51.658783 59642 4.420120 18.416885 51.393387 59643 37.844681 18.981339 52.561241 59644 3.530060 16.179657 51.865143 59645 3.997124 15.562408 50.855026 59646 22.795319 16.805084 50.766624 59647 29.290085 18.326447 51.695770 59648 21.798843 16.680893 51.562698 59649 22.780853 17.207306 52.017685 59650 23.695190 17.575272 51.267715 59651 28.409470 16.345230 50.933861 59652 28.570312 17.312347 51.885384 59653 34.022881 15.248154 52.630814 59654 37.215752 16.902298 51.339760 59655 17.483307 14.439163 51.011993 59656 17.216431 14.240158 52.343010 59657 25.497147 15.277679 52.522408 59658 26.519730 15.952560 52.585365 59659 27.493332 15.228088 50.772095 59660 27.487778 16.089569 51.841705 59661 34.358177 13.921616 50.661140 59662 4.914787 13.949493 51.073532 59663 23.760925 13.701019 51.180588 59664 24.739998 14.198898 51.253761 59665 34.314926 13.989655 52.343277 59666 22.221878 12.636078 51.847862 59667 22.109100 11.899857 51.805603 59668 36.614502 12.904922 52.221001 59669 41.915665 12.763092 51.139336 59670 43.115295 12.287201 51.481804 59671 7.077881 10.985794 50.643112 59672 35.294464 12.654114 51.325729 59673 36.530762 12.582428 51.318756 59674 35.904915 12.648651 51.801102 59675 5.692734 9.728912 51.161499 59676 6.034645 9.713226 52.543800 59677 5.034500 9.412994 52.348969 59678 4.304878 9.207733 51.664131 59679 44.691269 9.977097 51.515625 59680 3.360176 8.204742 51.436020 59681 3.297829 8.013641 50.166420 59682 44.389282 9.204208 51.524223 59683 17.763870 7.740677 49.785583 59684 18.182457 7.973618 50.723717 59685 19.115326 7.641876 51.454826 59686 26.537796 8.697113 51.674599 59687 27.355850 8.488480 51.784340 59688 27.061317 8.024078 51.492928 59689 39.974640 6.800888 51.813599 59690 41.953400 7.612503 52.710274 59691 41.702957 7.635361 50.995239 59692 42.784485 8.014130 51.517403 59693 43.742935 8.534882 51.255501 59694 26.289108 6.350830 52.938553 59695 25.670494 5.358658 52.619339 59696 39.099060 7.075775 50.820236 59697 38.426926 6.541794 51.052124 59698 27.695282 7.871796 53.555382 59699 26.939041 7.403229 51.810326 59700 27.596649 8.119232 52.158913 59701 37.165077 6.100845 50.533440 59702 2.894631 6.165710 50.871880 59703 20.890137 5.344482 51.730423 59704 20.849030 6.172287 52.595741 59705 35.811523 4.067642 50.891563 59706 36.674850 4.072784 53.077728 59707 37.799736 5.223038 53.106415 59708 37.786926 5.491837 51.920197 59709 3.172783 4.737854 50.234520 59710 3.656670 3.990685 50.004906 59711 20.363014 3.761635 50.704765 59712 20.651787 4.877533 51.183685 59713 5.857231 3.043488 51.143501 59714 25.766090 2.862778 50.500183 59715 38.190063 1.355255 51.900604 59716 37.934814 1.916672 51.014694 59717 39.562744 2.422256 51.789490 59718 41.352951 3.530579 51.438858 59719 44.875732 2.969444 50.988419 59720 27.595322 2.006989 51.666946 59721 26.680725 2.983734 52.322990 59722 27.500023 2.666229 53.147079 59723 35.830444 2.242432 50.555321 59724 35.367165 2.645584 50.747398 59725 36.801926 1.400009 51.422653 59726 35.685730 1.869156 51.245872 59727 38.379562 2.518066 50.521194 59728 45.396606 1.893433 50.906929 59729 8.663956 0.833481 50.426224 59730 20.545662 1.731033 51.345291 59731 21.361710 0.988876 50.323067 59732 21.223961 0.979980 51.160957 59733 28.441536 0.773331 50.665398 59734 28.385040 0.203629 50.896294 59735 45.867981 0.741562 50.899178 59736 46.696854 0.167206 51.658936 59737 46.112473 -1.222977 50.496071 59738 8.259827 0.391602 50.193481 59739 8.661392 0.794662 50.715210 59740 22.129845 0.632233 51.327095 59741 45.442841 2.776978 52.098015 59742 6.987190 -0.962692 50.056038 59743 6.506699 -1.432266 49.965759 59744 7.619812 -0.390091 50.361671 59745 5.728294 -1.793106 50.148201 59746 4.933891 -2.230576 50.237122 59747 24.354980 -2.869675 50.033165 59748 27.575310 -0.981094 50.602119 59749 26.315704 -2.436264 50.309006 59750 4.191635 -2.410873 51.028915 59751 23.921013 -2.904480 50.330795 59752 26.934685 -2.646347 52.316689 59753 28.348808 -0.206940 52.375008 59754 46.235931 1.523407 51.808868 59755 24.155029 -3.564865 50.398590 59756 24.956558 -3.414658 50.248802 59757 25.565750 -3.063766 50.233162 59758 47.269196 -2.603134 50.391991 59759 47.519897 -1.325241 51.842148 59760 48.606354 -2.845535 52.519241 59761 49.403351 -3.794922 51.716576 59762 28.271133 -5.944717 50.302750 59763 27.203308 -5.795929 50.720207 59764 29.065910 -8.014420 48.229958 59765 4.399811 -6.522461 49.996109 59766 5.525192 -6.588806 49.263397 59767 6.573456 -6.656677 49.113663 59768 7.824005 -6.704941 49.308319 59769 9.404663 -6.864929 50.292946 59770 11.621323 -8.590714 49.499466 59771 24.008011 -6.933578 50.290123 59772 24.094215 -5.993622 50.380669 59773 26.782028 -6.345551 49.823029 59774 23.086014 -5.626022 51.072906 59775 23.048843 -4.170929 51.350304 59776 23.681931 -4.473679 50.719948 59777 28.561714 -6.163956 50.001358 59778 24.353271 -7.793793 50.790390 59779 23.595779 -6.703217 50.609077 59780 34.583725 -7.650787 51.144463 59781 42.510071 -7.482269 51.264442 59782 41.568146 -6.921417 52.145592 59783 41.834000 -7.601715 50.183960 59784 23.123634 -7.316177 51.766525 59785 23.195572 -6.796677 51.142197 59786 42.656830 -7.989655 50.088829 59787 43.707718 -8.357025 50.484589 59788 51.505844 -6.786469 51.550262 59789 26.992210 -9.750122 49.802643 59790 24.877266 -8.505295 51.866982 59791 25.821930 -8.891815 51.139259 59792 44.879547 -8.988510 50.736633 59793 45.942245 -9.618179 50.841782 59794 52.232727 -8.103287 50.928085 59795 2.745010 -11.581100 49.156227 59796 7.366058 -11.328033 49.181671 59797 7.106598 -11.728180 49.854164 59798 11.826996 -9.939697 50.408669 59799 27.501343 -10.100708 49.841530 59800 45.995422 -10.398361 49.489128 59801 52.070755 -9.568161 51.073395 59802 7.659011 -12.672318 50.500832 59803 8.980255 -12.822495 50.718483 59804 10.333969 -11.472076 48.908966 59805 28.310669 -10.852234 49.651634 59806 29.861176 -10.876923 52.256966 59807 29.132736 -9.883057 52.809624 59808 28.278526 -10.181885 51.317284 59809 34.643234 -11.451828 49.759384 59810 33.326828 -11.947128 49.629089 59811 35.044067 -11.040802 50.748894 59812 38.056656 -10.853592 49.902908 59813 39.749031 -10.608841 51.794426 59814 43.778564 -11.770050 52.473663 59815 42.843170 -11.283417 52.195717 59816 43.772415 -12.348434 51.308243 59817 47.934662 -11.670410 50.129707 59818 47.952011 -10.791840 51.419662 59819 50.907288 -8.770081 52.838409 59820 10.358063 -11.849915 49.568756 59821 30.570892 -11.941650 50.957863 59822 32.308182 -12.093216 50.986649 59823 32.247864 -11.621567 53.122032 59824 30.131454 -12.305634 49.944908 59825 42.802444 -12.203812 50.340866 59826 42.851044 -11.780228 51.094490 59827 41.937225 -11.469513 50.841888 59828 51.435013 -11.864944 50.070236 59829 2.041840 -13.632050 48.879234 59830 1.924118 -13.921310 48.741165 59831 2.787712 -12.539703 49.949661 59832 31.886957 -12.314774 49.573563 59833 45.009399 -14.891907 49.864243 59834 44.774048 -13.693298 50.816093 59835 2.055618 -14.143448 48.715736 59836 45.527161 -16.127930 50.452553 59837 45.606369 -15.149017 50.890480 59838 45.341934 -14.495407 50.798355 59839 3.977318 -14.848022 50.343071 59840 8.402496 -16.739731 49.065430 59841 9.294655 -16.941116 49.162071 59842 45.338104 -16.376663 49.327507 59843 53.150345 -16.754791 50.664711 59844 10.440285 -17.803360 48.881302 59845 42.935883 -17.858932 51.782585 59846 43.711182 -17.858887 51.523911 59847 43.449738 -18.239960 50.628983 59848 45.065735 -17.491776 49.809952 59849 50.190903 -17.371140 50.106743 59850 51.134872 -16.983643 49.433586 59851 54.683624 -17.149582 49.846992 59852 10.547279 -18.614777 48.807793 59853 45.146423 -16.631638 51.649139 59854 44.316132 -17.554977 51.476921 59855 51.421265 -16.616287 50.478271 59856 10.392914 -19.228134 48.805260 59857 39.360306 -18.370377 50.522949 59858 41.194122 -18.443924 50.484467 59859 41.905716 -18.413177 50.527885 59860 44.052979 -18.247833 49.834633 59861 42.590302 -18.351624 50.604034 59862 48.189789 -18.921936 50.884239 59863 48.888840 -18.756989 49.645683 59864 49.233978 -17.938721 50.749977 59865 10.117935 -19.795761 48.768242 59866 9.486572 -20.410919 48.879257 59867 31.560425 -20.483856 49.271393 59868 8.889389 -20.361130 49.915878 59869 8.617401 -21.377518 48.745796 59870 37.316177 -21.519669 48.439850 59871 54.771240 -21.108002 50.083221 59872 7.048996 -21.725723 49.321609 59873 7.055824 -22.873810 49.066711 59874 8.045647 -22.493515 48.672791 59875 7.958511 -23.482895 48.906036 59876 32.033722 -23.027451 49.265213 59877 32.493622 -23.193390 49.488869 59878 32.065598 -21.913681 49.811058 59879 37.006538 -22.197464 49.114868 59880 36.515099 -23.255569 49.222916 59881 37.655838 -21.787491 48.871933 59882 42.369232 -21.711609 49.634399 59883 45.301819 -21.622162 49.655975 59884 46.288864 -21.368286 49.508911 59885 53.747833 -20.655975 51.919327 59886 54.758636 -19.912735 50.573906 59887 8.683762 -24.438614 48.975769 59888 53.283508 -23.353271 49.703369 59889 53.679672 -22.528610 51.330048 59890 7.782959 -25.128113 49.848618 59891 31.618547 -22.646576 48.985550 59892 52.563156 -24.325150 50.288185 59893 12.815460 -27.618851 48.355034 59894 33.829964 -26.177216 49.349915 59895 51.352905 -24.672882 49.041702 59896 51.395355 -25.021744 50.069946 59897 2.938294 -27.548203 48.772217 59898 2.406693 -28.496323 48.404617 59899 3.828590 -27.179031 48.698997 59900 6.355194 -28.176331 48.166779 59901 34.508392 -26.314331 49.300079 59902 34.622429 -26.688492 49.752502 59903 34.002670 -26.739151 49.513969 59904 35.320236 -24.753189 48.768585 59905 35.414932 -25.848175 49.567589 59906 48.874207 -25.842514 49.163536 59907 49.899719 -25.684326 50.223343 59908 50.934967 -25.499924 51.222824 59909 13.131287 -28.414856 49.080566 59910 46.151337 -26.881287 48.785240 59911 47.458893 -26.461044 49.532852 59912 54.285339 -27.617157 49.348763 59913 53.707733 -27.889420 49.732697 59914 52.952484 -28.079041 49.541077 59915 12.352402 -27.858215 49.109474 59916 44.756805 -28.393402 50.074585 59917 51.874191 -28.444260 49.388535 59918 50.530289 -28.912872 49.153831 59919 54.951691 -27.982361 49.209938 59920 2.851166 -28.707306 49.813156 59921 2.435150 -29.299072 49.535088 59922 7.304543 -29.792862 48.044914 59923 14.378159 -30.119141 48.008835 59924 14.209976 -29.393768 48.611191 59925 39.727554 -29.976318 48.434738 59926 39.510513 -30.199478 48.972946 59927 40.270828 -30.198502 49.037804 59928 47.263962 -30.964005 48.666451 59929 48.906326 -29.737503 48.754799 59930 48.729431 -30.164749 49.922478 59931 37.856598 -31.828735 50.430557 59932 41.233139 -30.218918 49.274796 59933 43.179443 -29.698547 49.696533 59934 54.792969 -30.822998 49.253426 59935 7.056305 -31.312057 48.099937 59936 6.761917 -29.811722 48.633682 59937 7.500183 -31.683716 47.559486 59938 13.634834 -29.115875 49.267929 59939 13.224350 -29.452148 49.887291 59940 13.763977 -30.157837 48.995483 59941 2.433930 -32.151184 49.518661 59942 2.311417 -33.290100 48.440315 59943 12.935211 -31.610229 49.075935 59944 11.950821 -32.361984 49.283852 59945 34.924332 -33.031662 49.439583 59946 34.226288 -32.946533 48.646851 59947 33.152954 -33.872620 49.104988 59948 44.884094 -34.075699 51.690140 59949 44.340164 -33.795425 50.543465 59950 53.198486 -32.984543 50.369675 59951 53.690811 -32.349060 50.397705 59952 54.182220 -31.976654 49.210556 59953 2.018044 -33.327682 47.686981 59954 10.313560 -34.184738 49.099861 59955 10.839622 -34.149399 48.682236 59956 10.874832 -33.140686 49.502251 59957 12.329529 -34.570877 47.506615 59958 32.129120 -34.021118 48.311211 59959 34.142548 -33.523911 49.515480 59960 37.840225 -34.563705 48.292526 59961 42.357269 -33.878723 48.861763 59962 41.653198 -34.108292 49.596695 59963 42.369949 -33.656784 48.212685 59964 44.053375 -33.404419 49.160706 59965 50.036407 -34.075195 48.956802 59966 50.756836 -33.989532 49.560211 59967 52.524384 -33.340149 49.697830 59968 3.200081 -34.694946 48.005524 59969 5.122406 -35.786697 47.517532 59970 5.547478 -36.817139 47.379562 59971 31.141159 -34.555237 48.326324 59972 31.112267 -35.028732 49.285202 59973 38.514671 -34.697052 49.363289 59974 48.907806 -35.283691 48.212868 59975 6.741913 -37.543747 47.520897 59976 11.926193 -35.606659 47.936516 59977 11.355011 -34.890198 48.264305 59978 12.444611 -35.673065 47.547279 59979 25.638229 -36.717194 48.795280 59980 25.837807 -36.237350 47.620789 59981 28.576996 -35.633530 49.821930 59982 30.469421 -35.591141 50.293442 59983 37.658981 -35.220245 49.459045 59984 37.796402 -35.525848 50.376564 59985 36.964462 -35.897934 50.076988 59986 49.212936 -35.898026 48.412720 59987 49.075180 -35.484268 48.952438 59988 3.959541 -35.948578 47.727295 59989 4.620522 -35.050507 47.947891 59990 4.522774 -36.922424 47.693588 59991 12.510971 -36.326157 47.923065 59992 49.906433 -36.358276 48.575745 59993 8.337830 -38.235550 47.354874 59994 23.748245 -39.250534 47.843071 59995 51.044830 -36.623932 50.644089 59996 52.053802 -37.348907 49.574440 59997 52.173279 -37.460800 50.727684 59998 8.904984 -39.663483 48.665047 59999 7.745422 -38.781631 48.402794 60000 23.099800 -40.521820 47.682907 60001 29.626518 -38.874374 47.856453 60002 41.850906 -38.669571 47.440163 60003 38.941788 -39.115250 48.592415 60004 42.338257 -38.893417 48.608215 60005 52.954239 -38.263596 49.592026 60006 53.057953 -38.520340 50.586082 60007 23.852776 -39.814026 48.670685 60008 43.337189 -38.951721 48.933136 60009 44.038864 -39.324341 50.119881 60010 42.274094 -39.283890 50.391212 60011 53.450745 -39.005753 49.629349 60012 4.099396 -40.873840 48.419083 60013 3.396408 -39.816864 47.448753 60014 11.897446 -40.958984 47.008369 60015 14.324670 -42.214554 47.966316 60016 26.993301 -41.293060 48.786224 60017 26.452988 -41.833420 47.539383 60018 35.966454 -40.133591 48.104080 60019 47.428711 -40.480347 48.341797 60020 47.593811 -40.013351 49.265846 60021 47.906815 -40.742447 48.847069 60022 46.924011 -40.660919 47.804367 60023 12.006569 -43.501541 47.930687 60024 14.042267 -41.462418 49.783737 60025 14.240959 -42.864258 49.888641 60026 14.339294 -42.943710 49.138748 60027 13.331673 -42.159622 51.327148 60028 13.928902 -42.764969 50.443336 60029 34.372925 -41.448181 47.889053 60030 33.775803 -41.556931 48.296768 60031 33.061890 -41.565125 48.870338 60032 33.725723 -40.761505 48.581673 60033 47.247314 -41.376114 48.525391 60034 6.982590 -43.703018 47.529747 60035 12.836487 -43.759476 47.651405 60036 13.532837 -43.164459 47.477333 60037 26.526138 -42.703827 48.526939 60038 26.225113 -43.841202 48.781044 60039 34.164955 -42.155563 48.469704 60040 35.661499 -42.304916 48.177422 60041 35.760796 -42.674072 49.532089 60042 34.611252 -42.616119 49.338860 60043 36.869003 -42.521454 48.914085 60044 39.157326 -42.462906 48.045914 60045 45.356277 -42.223282 48.084747 60046 44.234955 -42.848495 47.730789 60047 46.169327 -42.462097 49.134109 60048 13.482857 -43.998215 47.821754 60049 13.200790 -44.427429 47.995621 60050 14.003716 -43.540726 48.264694 60051 22.987045 -41.936508 48.226295 60052 3.826897 -44.313385 47.713524 60053 13.697037 -44.403946 48.486130 60054 22.909874 -43.378464 49.126411 60055 23.114517 -44.798645 48.402809 60056 39.883820 -44.479095 48.521889 60057 22.426910 -45.001801 49.964516 60058 23.152130 -45.715652 49.457466 60059 38.749802 -45.513382 48.176933 60060 38.567276 -46.016754 49.264061 60061 39.596512 -45.271957 49.448647 60062 52.704041 -44.029739 48.331940 60063 2.459267 -46.949478 47.531059 60064 37.606544 -46.015411 47.657608 60065 37.795517 -46.312561 48.549026 60066 40.475555 -43.639404 48.964218 60067 41.440628 -46.422165 47.949059 60068 49.940186 -46.864777 48.897018 60069 49.878281 -46.926743 50.501068 60070 50.635071 -46.133774 50.015266 60071 50.729614 -46.420349 48.309151 60072 52.399200 -45.479980 48.235146 60073 52.678345 -45.118347 48.143532 60074 2.473595 -48.846939 47.652428 60075 3.064102 -49.623520 46.799568 60076 2.450935 -47.868362 47.688850 60077 48.289398 -47.175903 48.104500 60078 49.023254 -47.288605 48.740341 60079 40.002579 -48.470535 48.223785 60080 38.807159 -49.636642 47.679253 60081 45.318436 -48.105209 47.671707 60082 44.535690 -48.768921 47.735672 60083 45.214081 -48.603287 48.447098 60084 44.077576 -49.609970 48.051834 60085 3.147957 -51.345245 46.977310 60086 3.997742 -52.361023 46.913712 60087 37.997101 -50.968323 47.493210 60088 38.026413 -50.031494 47.126144 60089 3.176071 -50.455215 46.736885 60090 31.892275 -51.100708 47.221176 60091 46.206390 -51.321625 47.785797 60092 47.121674 -51.077698 47.445206 60093 48.774490 -51.077194 47.728584 60094 47.501083 -51.468933 48.635193 60095 7.642555 -52.994843 46.702690 60096 12.130219 -53.334183 46.715942 60097 11.812378 -52.666534 47.650620 60098 10.476913 -52.570724 47.591850 60099 27.861557 -52.558914 46.965477 60100 28.641563 -52.771088 47.683243 60101 31.120255 -52.416275 48.539688 60102 32.117233 -51.779877 48.217850 60103 33.116272 -50.674973 48.300186 60104 44.763092 -51.156128 48.107841 60105 4.550392 -53.739777 47.784416 60106 6.293053 -53.718170 48.201996 60107 9.105377 -52.932159 47.591225 60108 12.473053 -53.368179 47.799110 60109 11.996635 -54.808929 46.455704 60110 24.574806 -53.587570 47.983971 60111 23.907646 -54.269806 47.765068 60112 23.874619 -54.030197 48.984642 60113 24.940689 -53.319305 46.945946 60114 29.419235 -52.464493 47.378296 60115 39.539574 -53.768372 47.717690 60116 40.450165 -54.338303 47.951553 60117 39.740501 -53.255127 48.911644 60118 39.008675 -53.075607 48.022316 60119 38.928940 -52.375946 48.770699 60120 49.918823 -54.126465 47.533806 60121 10.664742 -56.231857 46.298637 60122 30.354568 -55.802200 47.314621 60123 11.785301 -55.165497 49.184395 60124 12.411270 -54.238342 48.506386 60125 12.384735 -53.906357 49.626846 60126 24.856110 -55.841232 47.137352 60127 29.597260 -56.319809 48.031219 60128 32.726830 -55.269485 46.670494 60129 44.412323 -55.738831 47.520508 60130 46.828537 -55.742783 48.388237 60131 47.227066 -55.427963 49.264832 60132 48.340057 -54.891876 48.379913 60133 48.106598 -54.663986 49.559006 60134 48.733429 -55.042206 46.980095 60135 6.225830 -58.329422 46.000015 60136 5.260193 -58.276642 45.790352 60137 9.320618 -57.164948 47.419647 60138 11.041145 -55.942398 47.634491 60139 12.220734 -54.495834 47.566345 60140 7.346329 -58.488968 46.270241 60141 6.831658 -59.965836 45.991455 60142 5.515984 -59.160034 46.095688 60143 6.408821 -59.036499 46.219391 60144 40.862061 -58.710922 48.643433 60145 39.847054 -58.299469 48.403008 60146 45.814011 -60.072006 47.860985 60147 4.698578 -59.394836 45.885399 60148 8.569656 -59.373291 48.041092 60149 22.636169 -62.238876 46.215675 60150 21.144882 -62.692261 46.183670 60151 21.654182 -62.152847 45.892426 60152 26.978531 -63.156204 46.326019 60153 29.738747 -63.187317 46.102676 60154 30.693703 -62.443436 46.555954 60155 31.355576 -61.648956 47.408417 60156 31.351776 -62.080521 46.753380 60157 31.215370 -62.560150 46.552582 60158 31.862726 -62.397293 47.069603 60159 20.919617 -63.620590 45.792000 60160 20.362869 -63.712189 46.511063 60161 25.954391 -63.247971 46.596817 60162 19.695366 -64.052597 47.585274 60163 19.958687 -64.889694 46.876656 60164 44.509399 -63.213959 47.384338 60165 44.078476 -63.746857 46.759453 60166 20.745377 -64.886169 46.216103 60167 30.217438 -65.735687 46.713135 60168 33.122162 -62.245499 47.896957 60169 32.225975 -63.720337 47.929901 60170 43.190170 -64.110580 47.626266 60171 42.229462 -65.642349 47.464920 60172 5.247704 -68.072266 44.670425 60173 11.673096 -65.103806 45.730362 60174 20.777344 -66.204346 47.075798 60175 21.992630 -66.072098 46.074150 60176 23.181664 -66.656265 45.580666 60177 34.214287 -68.268616 48.566223 60178 35.459450 -68.263031 48.576797 60179 35.042679 -67.755829 47.690361 60180 23.235420 -67.234528 46.127838 60181 24.566643 -68.344711 46.061073 60182 24.265137 -68.392212 46.998085 60183 23.372269 -67.974380 47.173615 60184 29.708313 -66.823715 46.099625 60185 11.715668 -67.059448 45.597954 60186 11.839310 -67.871933 45.314018 60187 29.802353 -67.564835 45.828217 60188 36.356339 -67.186615 46.943314 60189 41.399719 -66.115128 48.364746 60190 11.425423 -67.831528 45.808418 60191 24.984253 -68.995209 47.176849 60192 31.459114 -68.274155 46.645584 60193 32.484711 -68.571869 47.261505 60194 35.993011 -67.785797 47.335678 60195 35.797134 -68.315216 48.079285 60196 36.248985 -69.294693 47.647476 60197 36.340424 -67.684525 46.813713 60198 38.538406 -70.521881 46.829880 60199 17.916641 -70.478775 44.897209 60200 35.754929 -70.688217 46.333733 60201 9.324921 -69.916397 47.117950 60202 9.057861 -71.282288 46.845230 60203 10.238815 -70.647568 46.318405 60204 10.922089 -71.850067 45.428490 60205 17.699730 -71.116119 45.319603 60206 26.730629 -70.859940 46.075546 60207 38.396408 -71.403122 45.981644 60208 39.016029 -69.625305 47.749588 60209 17.790283 -72.921951 46.533798 60210 17.897919 -71.791702 46.250671 60211 35.843742 -71.302887 46.166161 60212 20.487793 -71.743515 45.731316 60213 27.384933 -71.776505 45.925110 60214 27.306419 -71.327438 46.902428 60215 27.809845 -72.372513 45.707672 60216 28.260696 -72.672394 45.791084 60217 36.198418 -72.081482 45.844788 60218 37.308655 -72.187469 45.870163 60219 37.966888 -71.862411 45.915863 60220 10.788742 -73.106781 45.267342 60221 21.732040 -73.803909 45.894638 60222 22.400383 -75.237305 45.750046 60223 22.095116 -74.281128 46.810608 60224 22.832352 -75.484161 46.923286 60225 30.027161 -73.294312 45.153107 60226 10.172867 -74.359283 45.273140 60227 30.551605 -75.041092 45.713966 60228 9.474869 -75.696198 45.456192 60229 10.086533 -75.605591 44.910217 60230 9.495529 -76.517410 44.798172 60231 8.951065 -76.705185 45.435188 60232 23.254204 -76.298523 46.434990 60233 29.884811 -76.771881 45.873573 60234 29.872574 -75.658310 46.692535 60235 29.810722 -73.665543 45.930496 60236 30.771362 -76.522125 44.830452 60237 8.763992 -77.549713 44.838608 60238 8.153427 -77.560165 45.966331 60239 16.893250 -78.188644 45.158630 60240 17.792175 -77.894363 46.161896 60241 18.429520 -74.829315 47.692329 60242 17.902542 -73.923401 46.669250 60243 8.366676 -78.496292 44.986816 60244 17.991943 -76.602615 45.622330 60245 8.434174 -79.085052 45.701164 60246 15.900299 -79.957626 46.283524 60247 14.299072 -79.775452 45.357193 60248 14.052353 -80.418533 46.214874 60249 11.449814 -80.414032 44.870407 60250 12.821395 -80.280029 45.150230 60251 8.961586 -79.536606 46.669876 60252 10.624413 -80.449402 46.369148 60253 12.271217 -80.590179 45.702759 60254 13.854187 40.772888 53.535210 60255 11.692833 39.979401 55.408630 60256 10.977264 40.419617 55.008804 60257 11.433029 40.481247 54.000771 60258 12.820496 40.425430 54.313446 60259 10.523552 40.419403 54.485039 60260 14.843025 40.341034 53.793839 60261 9.426598 39.543579 53.353401 60262 10.289536 40.128448 53.710304 60263 16.678055 40.020111 53.272820 60264 15.815605 38.733521 54.881783 60265 17.458923 38.415588 54.511223 60266 15.848358 37.318512 55.282776 60267 19.430466 38.912918 53.212669 60268 19.303970 38.287430 53.755478 60269 19.001389 37.373810 54.611298 60270 17.676178 36.694580 55.175446 60271 20.718376 36.567627 53.803154 60272 4.549820 35.621933 53.886414 60273 21.308044 34.933029 54.070374 60274 20.729851 35.668304 54.691170 60275 12.401566 31.882812 53.279831 60276 12.016640 31.376862 54.067497 60277 11.755051 32.333298 53.714020 60278 14.293236 32.123352 53.086403 60279 14.187730 33.652039 53.957085 60280 15.695923 32.698746 53.630180 60281 16.634621 32.065125 53.243782 60282 16.117935 31.664932 52.839020 60283 12.237976 33.989029 54.235741 60284 11.195862 32.961914 54.237160 60285 12.305496 32.638168 53.353004 60286 13.084351 32.549973 53.303101 60287 15.399726 29.108521 53.051651 60288 13.353088 31.009872 53.457344 60289 15.247124 31.590210 52.737938 60290 15.416260 33.952835 54.451683 60291 16.727310 33.772720 54.617401 60292 16.827927 31.603455 52.898537 60293 20.959763 33.830200 54.301727 60294 15.767731 30.969330 52.413452 60295 18.391953 33.401657 54.554428 60296 14.463852 29.881378 53.427040 60297 14.134422 30.052094 54.621956 60298 15.133423 29.214371 54.176140 60299 15.913620 28.207962 52.995384 60300 16.863983 27.349731 52.885201 60301 3.893540 27.268982 53.942337 60302 19.976730 26.050812 52.496445 60303 16.191727 28.531586 54.307968 60304 15.769119 28.350952 53.557358 60305 16.395615 27.844299 53.430481 60306 22.084282 26.223938 53.212479 60307 23.486626 25.909180 53.390167 60308 35.062874 23.418610 52.934357 60309 24.267044 25.076874 53.224174 60310 24.448929 23.724350 52.648010 60311 33.802246 22.972382 53.777603 60312 4.647095 24.284561 53.444267 60313 5.920349 23.349213 52.108871 60314 25.484665 24.659851 53.932121 60315 7.443077 22.241989 52.225883 60316 7.837348 21.813019 51.849892 60317 25.443283 22.801773 52.954880 60318 25.708916 21.522522 52.857086 60319 32.156372 22.507858 53.153946 60320 7.575127 20.968124 52.029243 60321 36.420898 21.243484 53.592010 60322 25.996750 22.120087 53.563835 60323 25.668823 20.844696 53.698692 60324 25.994316 21.775574 54.677155 60325 25.606354 20.621765 52.858368 60326 30.094368 20.117004 52.805000 60327 31.230453 21.507141 53.420929 60328 5.289803 19.270706 51.985855 60329 5.877113 19.967743 52.869324 60330 29.486366 19.086563 52.339348 60331 24.374802 18.609680 52.823013 60332 3.401573 17.302429 52.435135 60333 3.513741 18.110489 53.589821 60334 3.144440 17.160583 53.726685 60335 23.618820 18.247986 53.446587 60336 24.207306 18.908936 53.902771 60337 28.498428 18.609360 54.599724 60338 29.113403 19.048904 53.436981 60339 30.106689 20.285309 54.896332 60340 28.876984 18.269989 52.538872 60341 20.727249 17.005493 52.785378 60342 21.954765 17.198929 52.720062 60343 35.406113 17.487198 53.095558 60344 36.426529 17.015366 52.153015 60345 37.863510 17.675079 51.976555 60346 36.832359 17.847534 52.725143 60347 4.024002 15.088501 52.121094 60348 18.195480 15.362259 51.931458 60349 19.393562 16.179596 52.228027 60350 26.684242 16.534042 53.501854 60351 27.879547 17.374557 53.130730 60352 5.886238 13.454468 51.972099 60353 24.726959 14.713821 52.235847 60354 23.965622 14.173004 51.978249 60355 25.710342 15.869476 53.370537 60356 34.016541 14.741486 53.418457 60357 33.678345 15.708344 53.516479 60358 4.933815 14.034576 52.727371 60359 17.235847 14.902100 53.630775 60360 17.448730 15.408401 52.960724 60361 23.182320 13.742157 52.176483 60362 7.156571 12.883102 52.457367 60363 7.472977 12.199203 52.144753 60364 7.297844 11.248291 51.687355 60365 17.043289 12.396133 52.118469 60366 22.603294 13.159775 52.292488 60367 35.943558 12.962845 52.513809 60368 36.140671 13.606842 53.475082 60369 35.221779 13.153381 52.275139 60370 39.080574 13.400421 53.212502 60371 40.959015 12.751495 52.920845 60372 42.477783 12.210861 52.350952 60373 6.957581 10.599731 51.323738 60374 42.385468 11.296356 53.681374 60375 43.879852 9.928955 52.586731 60376 6.591904 10.225143 51.353943 60377 3.778809 8.706726 52.369003 60378 3.335915 8.175644 52.381531 60379 4.310280 9.128937 52.328842 60380 23.700027 9.685944 51.624138 60381 22.871170 10.982666 52.176712 60382 24.326424 10.241425 52.666092 60383 25.869446 9.820786 52.916634 60384 27.349289 8.877396 52.085800 60385 27.680649 8.711548 52.247375 60386 18.413376 8.362778 51.653107 60387 17.823311 8.836090 51.341957 60388 20.069183 8.007065 53.028168 60389 26.988388 11.484711 54.993561 60390 28.471344 10.355042 54.285172 60391 27.480637 9.477585 53.009041 60392 43.322159 8.738617 52.590515 60393 2.996849 7.421494 52.241180 60394 40.910370 6.975052 53.419495 60395 39.634811 6.471909 53.748268 60396 3.300400 4.520660 51.114449 60397 20.964859 4.861687 51.728294 60398 4.325478 3.707970 51.097572 60399 20.316483 2.914978 51.393715 60400 20.260597 2.643723 52.306885 60401 20.698997 4.247894 52.491676 60402 25.725822 4.108124 52.016281 60403 26.332779 2.803177 51.184624 60404 42.848114 3.855858 52.596619 60405 44.232315 3.742599 51.763580 60406 44.318924 3.673050 52.957153 60407 45.285950 2.833145 53.605431 60408 5.622826 3.262589 53.346016 60409 4.968376 3.666016 56.165619 60410 6.665070 3.339767 55.678955 60411 3.832787 3.613785 53.821503 60412 25.828003 4.802238 53.257019 60413 46.218887 1.994995 52.814850 60414 46.285172 1.400009 53.825745 60415 35.400299 2.540787 51.291023 60416 41.307419 3.218811 52.691475 60417 21.201492 1.165649 51.742615 60418 20.636002 1.726105 52.472214 60419 28.416336 0.933838 51.426369 60420 35.850548 2.260117 52.330643 60421 36.103783 1.393509 51.809204 60422 36.453918 1.069412 52.538048 60423 36.121552 1.429657 53.438736 60424 35.997681 2.281021 53.581253 60425 46.770798 0.903809 52.707497 60426 7.063477 -0.791458 51.319153 60427 8.004723 0.046814 51.449776 60428 7.431290 0.245621 53.300392 60429 6.598770 -1.377625 50.541122 60430 8.308762 0.934174 52.121391 60431 8.255905 1.710144 53.188828 60432 45.933228 0.975388 54.690125 60433 45.238068 1.988831 54.724739 60434 23.736946 -1.606613 51.835167 60435 23.913666 -0.705826 52.170624 60436 23.589325 -3.098022 50.990173 60437 47.366928 -1.937744 50.993729 60438 5.131065 -1.934433 51.001183 60439 47.558090 -1.364822 53.459694 60440 47.229706 -0.176788 52.639366 60441 24.920265 -4.687271 50.701462 60442 26.269958 -4.326553 52.090714 60443 25.642494 -4.580139 51.423889 60444 25.729843 -3.696091 51.062576 60445 2.788048 -5.024734 51.099510 60446 26.040039 -5.157684 51.355904 60447 5.190376 -6.967804 50.600594 60448 4.292351 -6.786972 51.272995 60449 6.417687 -7.003326 50.527817 60450 7.752380 -6.947128 50.630524 60451 8.332695 -6.691864 51.812950 60452 27.222252 -5.105606 52.104164 60453 38.835007 -6.809006 51.169991 60454 39.809128 -6.651459 52.167824 60455 10.891388 -7.500671 50.527618 60456 11.749252 -8.481705 50.774529 60457 35.641098 -7.281433 51.981033 60458 34.219681 -7.464996 51.842323 60459 42.743164 -7.010025 52.929779 60460 50.791428 -6.508453 52.488449 60461 50.680145 -5.651550 52.013657 60462 30.607651 -6.063324 52.036255 60463 26.871338 -9.528152 50.509560 60464 44.633362 -8.290176 51.948158 60465 7.315994 -12.160248 50.203232 60466 6.476936 -12.580582 50.466682 60467 11.631882 -10.855042 50.346069 60468 11.908218 -9.393234 51.393303 60469 36.454269 -10.708511 50.787193 60470 40.923767 -10.906296 51.309761 60471 38.575760 -10.310455 54.226883 60472 41.884735 -10.541916 53.120445 60473 42.855133 -10.773026 53.729950 60474 42.112122 -10.383072 54.017944 60475 46.944702 -10.076874 51.360039 60476 51.822815 -10.689011 50.851562 60477 4.180885 -13.008469 50.724945 60478 3.648903 -12.245941 50.450279 60479 11.355164 -11.337372 50.450668 60480 33.672249 -11.556961 50.816750 60481 40.661880 -10.453125 52.710220 60482 49.184753 -11.863800 51.038704 60483 51.645935 -11.354843 50.656425 60484 52.072052 -11.230621 49.808258 60485 50.696503 -11.198029 51.596375 60486 51.357956 -10.145126 51.919624 60487 2.324196 -13.704926 49.525452 60488 9.976791 -12.329330 50.171120 60489 10.778214 -11.902039 50.284515 60490 33.058258 -11.685486 51.939613 60491 34.227478 -11.162582 51.727715 60492 50.857971 -10.124542 52.513206 60493 2.039208 -13.999573 49.034500 60494 50.343369 -12.325531 50.563385 60495 2.756523 -14.539902 49.999054 60496 4.272667 -16.070587 49.410606 60497 45.580536 -15.573029 51.929794 60498 51.613831 -16.615021 51.538460 60499 4.879936 -16.307831 49.304581 60500 6.478165 -16.053894 50.225677 60501 7.547768 -16.517624 49.931969 60502 8.862869 -16.707443 50.723557 60503 9.924255 -17.423660 49.641235 60504 10.365700 -18.150879 49.598457 60505 51.136383 -17.005890 52.587143 60506 51.297806 -17.265457 53.331558 60507 50.406006 -17.232574 53.435989 60508 52.430054 -17.039703 51.985756 60509 38.441025 -18.456284 50.979263 60510 50.190536 -17.084518 51.463104 60511 54.422150 -17.771103 50.584457 60512 9.880676 -19.848373 49.700462 60513 10.323242 -19.076797 49.595657 60514 33.495888 -19.152451 49.830711 60515 39.121185 -18.386902 51.561829 60516 54.677734 -18.750549 50.673927 60517 47.667297 -18.921631 52.143845 60518 47.301743 -19.676956 51.395180 60519 6.016037 -22.477402 49.564590 60520 6.008011 -21.390961 49.971970 60521 5.150963 -21.661209 50.418144 60522 7.764297 -20.860764 49.789993 60523 6.936455 -20.597946 50.783302 60524 32.641907 -20.157242 50.371498 60525 40.781647 -21.584885 49.714653 60526 39.913330 -21.350677 50.533211 60527 46.158386 -21.156403 50.287872 60528 52.331909 -21.707916 53.655243 60529 51.807724 -19.222321 53.852875 60530 5.215408 -23.294571 50.385300 60531 32.986511 -23.130753 50.122559 60532 33.276108 -21.666031 51.252190 60533 36.284805 -24.881302 49.672348 60534 35.878342 -24.504044 49.116486 60535 39.026749 -21.897461 51.073402 60536 38.770561 -22.973175 51.650246 60537 39.011276 -21.608353 50.258629 60538 41.512695 -21.217484 51.119377 60539 40.725922 -21.276550 50.844673 60540 43.993774 -21.453079 50.788254 60541 46.552765 -20.434204 51.227379 60542 7.493057 -24.362320 49.557281 60543 33.507736 -23.232574 50.721825 60544 33.965637 -21.415985 52.277473 60545 34.105362 -22.232422 51.794823 60546 42.697281 -21.160400 51.384186 60547 33.180351 -26.198166 50.231331 60548 33.539871 -24.577057 50.386368 60549 53.053360 -24.008102 51.133629 60550 34.123459 -23.539673 51.375801 60551 33.986053 -24.784225 51.191017 60552 33.641785 -25.781586 51.660446 60553 52.128922 -24.868118 51.025314 60554 36.457260 -25.791626 50.573738 60555 36.899399 -24.304199 50.019409 60556 48.499329 -26.267075 50.456390 60557 49.514053 -26.126938 51.528961 60558 3.755081 -28.148682 49.685638 60559 4.782929 -27.887711 49.017632 60560 33.444214 -26.788666 49.711868 60561 32.914955 -27.289948 50.225960 60562 47.145889 -26.789841 50.810028 60563 48.098511 -26.659515 51.851288 60564 5.397560 -29.677856 49.754410 60565 4.630997 -28.474045 49.777596 60566 11.784134 -28.039474 49.820671 60567 33.624870 -27.984665 50.814613 60568 31.926027 -28.415054 50.772552 60569 33.917992 -27.149277 49.996834 60570 46.247772 -27.078781 50.041779 60571 54.387939 -28.526718 50.031631 60572 45.189728 -28.788727 51.804642 60573 45.691162 -28.003815 51.545067 60574 50.042816 -29.365967 49.902489 60575 51.228271 -28.957382 50.421501 60576 50.164154 -29.696289 51.070061 60577 52.521393 -28.908859 50.788155 60578 54.622818 -29.759796 50.148888 60579 54.115295 -29.449738 50.715309 60580 2.233955 -30.069168 48.927711 60581 44.065033 -29.769363 51.598663 60582 13.480339 -30.971451 48.978287 60583 38.691940 -30.878235 49.838135 60584 39.481262 -30.450684 49.545685 60585 42.967560 -30.438919 51.455521 60586 43.332169 -29.851822 50.673149 60587 42.001617 -30.421066 50.499725 60588 48.532852 -30.801712 51.225090 60589 54.209686 -30.654266 50.559769 60590 54.431259 -31.363174 49.867332 60591 54.112595 -31.626617 50.342186 60592 53.495636 -31.389206 51.386177 60593 4.258370 -32.493881 49.819267 60594 5.320412 -31.601730 49.614464 60595 11.535919 -33.678635 48.429535 60596 33.926132 -34.056396 50.245750 60597 40.421265 -34.347900 49.893562 60598 43.028809 -33.996460 49.836319 60599 45.040955 -33.020981 49.543488 60600 51.615128 -33.849045 49.949951 60601 3.124626 -33.160965 49.350403 60602 3.063889 -31.267319 50.437698 60603 3.241959 -32.182312 50.208221 60604 4.264069 -34.521622 48.248520 60605 3.982750 -35.121185 48.038101 60606 4.057457 -33.779541 48.811661 60607 10.660172 -34.903931 48.719147 60608 9.949799 -34.999435 49.357430 60609 11.190239 -35.970993 48.846581 60610 32.045441 -34.536682 49.224014 60611 31.895807 -35.087402 50.184914 60612 39.299446 -34.818665 50.368919 60613 52.170593 -33.802383 50.865486 60614 26.868500 -35.841644 48.704704 60615 30.946854 -36.051407 51.308861 60616 31.832514 -35.591904 51.157600 60617 12.599922 -37.382584 48.968010 60618 24.962677 -37.859756 48.984657 60619 34.886566 -36.713730 49.136513 60620 35.872482 -36.379181 49.795158 60621 50.134888 -35.504700 50.569824 60622 5.248482 -38.924210 49.350883 60623 4.190376 -38.764908 48.867363 60624 24.773087 -38.772675 49.733482 60625 24.310822 -38.916031 48.805527 60626 51.105087 -36.794617 51.608887 60627 52.506332 -37.895660 51.338860 60628 30.196365 -39.415421 48.610886 60629 28.364761 -39.702621 48.583618 60630 29.371033 -39.881958 49.765533 60631 33.501633 -38.171463 49.383614 60632 40.688629 -38.981079 48.978462 60633 53.597076 -39.526642 49.447449 60634 3.399902 -39.891479 48.211693 60635 10.190063 -40.733047 48.493843 60636 8.983665 -40.460892 49.537247 60637 27.892151 -40.286133 49.484856 60638 30.899002 -40.432571 49.781654 60639 31.799364 -39.524246 48.600853 60640 33.102081 -39.505478 49.089485 60641 36.092148 -39.842804 49.363045 60642 37.307083 -39.662369 50.614037 60643 39.612595 -39.342651 49.930748 60644 45.186401 -39.822662 51.177200 60645 47.506729 -39.672440 50.283546 60646 3.949173 -40.648438 49.283981 60647 4.323708 -41.272369 49.381447 60648 31.493820 -40.302551 49.030014 60649 32.479378 -40.540237 48.863609 60650 34.395699 -39.901810 49.411018 60651 34.942711 -39.229599 50.707336 60652 48.049896 -40.043564 50.081345 60653 48.188599 -40.518051 49.502975 60654 53.300751 -40.503586 49.403000 60655 53.507309 -39.975266 49.562653 60656 5.549759 -41.879211 48.018692 60657 27.232704 -42.112732 50.337479 60658 47.549805 -42.247467 49.589951 60659 48.232239 -41.335220 49.458794 60660 27.604965 -40.962067 50.318687 60661 31.995615 -41.142853 49.487953 60662 37.927902 -42.306854 48.455444 60663 38.760521 -42.425217 49.517021 60664 40.504486 -44.225723 49.612190 60665 45.108734 -42.745972 48.710670 60666 6.509613 -42.769928 48.071106 60667 11.338333 -44.112274 48.899681 60668 14.144646 -43.935684 49.091103 60669 33.207352 -42.281647 49.432228 60670 33.805244 -42.590652 49.338753 60671 39.846886 -42.601791 48.910583 60672 44.609436 -43.065430 48.755455 60673 44.123749 -43.606659 48.762260 60674 2.678078 -44.785675 48.002884 60675 3.203896 -44.449097 47.841797 60676 6.603821 -43.893143 47.695862 60677 12.512009 -44.419983 48.169594 60678 25.663467 -44.627716 48.524178 60679 2.277649 -45.275894 48.138359 60680 2.226906 -46.063202 48.218056 60681 12.515869 -45.092499 48.894043 60682 11.830933 -45.560349 49.383667 60683 13.172150 -44.813721 48.540115 60684 22.683502 -43.855759 50.435486 60685 25.469864 -46.656525 50.795334 60686 25.066788 -45.705856 49.322220 60687 26.304268 -45.829147 50.641617 60688 41.239227 -47.521469 49.390099 60689 40.813721 -47.940628 49.212914 60690 43.580215 -44.568863 49.034439 60691 52.202667 -45.042221 49.034309 60692 42.460938 -45.576965 48.567528 60693 34.296890 -47.313370 47.937958 60694 33.761383 -48.431442 48.698952 60695 34.378464 -47.695206 49.126747 60696 35.658356 -47.409576 49.842743 60697 37.473480 -46.756683 50.724358 60698 37.488503 -46.593460 49.519455 60699 41.854355 -46.767426 49.265762 60700 40.225998 -48.869064 49.555733 60701 39.554367 -49.473984 49.018089 60702 46.067383 -48.126404 48.521965 60703 46.873520 -48.301392 49.709412 60704 49.304291 -47.432571 49.842613 60705 33.260666 -49.339981 48.213394 60706 33.133804 -48.430496 47.914795 60707 39.054321 -50.520905 48.956718 60708 44.680603 -49.183716 48.634453 60709 44.015488 -50.509232 48.012421 60710 2.567604 -50.332962 47.571381 60711 44.521820 -51.072739 49.884811 60712 44.542633 -50.294250 49.277565 60713 44.730316 -51.229111 49.357872 60714 48.820160 -51.622025 48.740616 60715 46.326309 -52.005432 50.117836 60716 45.633148 -51.578201 49.195137 60717 2.871369 -52.603531 47.703209 60718 3.490181 -53.299881 47.469154 60719 10.035858 -52.694687 48.533623 60720 33.286362 -51.654465 49.313332 60721 34.186096 -50.823212 49.660851 60722 50.216415 -52.242203 48.017883 60723 2.460877 -51.532684 48.081367 60724 2.859436 -53.442169 47.884308 60725 3.376152 -53.785736 47.883453 60726 7.026718 -53.375244 47.438400 60727 8.263962 -53.302887 47.700310 60728 24.947487 -53.561707 49.139038 60729 25.638618 -53.183777 48.017822 60730 26.666519 -53.367050 48.938828 60731 27.569778 -53.463089 49.245872 60732 27.663025 -53.051147 48.134216 60733 29.761681 -52.787430 48.562866 60734 28.495323 -53.368652 49.361404 60735 32.182236 -52.287018 49.325272 60736 50.082733 -53.109436 48.206917 60737 7.714790 -53.461426 47.521324 60738 49.227539 -52.634521 49.108917 60739 49.413361 -53.782974 48.652893 60740 48.835236 -53.982895 49.246246 60741 11.769966 -55.289673 48.303322 60742 23.551254 -54.954086 48.417267 60743 33.768509 -55.281586 48.459625 60744 38.985565 -56.312759 50.716003 60745 37.747688 -55.501312 50.980522 60746 38.200409 -56.295654 49.350868 60747 34.497574 -55.191544 49.520020 60748 35.879486 -55.196213 49.166573 60749 25.738113 -56.564636 48.674400 60750 24.709503 -56.294388 48.315140 60751 23.572914 -55.921738 48.836288 60752 26.688019 -56.496887 48.261009 60753 27.680878 -56.466110 48.043793 60754 28.674553 -56.422440 48.007607 60755 32.703964 -55.454300 47.895638 60756 31.585464 -55.858871 48.500053 60757 36.382507 -55.744324 48.212563 60758 38.683105 -57.734558 47.829468 60759 37.353935 -56.294006 48.212540 60760 39.404724 -57.547073 48.873962 60761 40.834534 -54.083191 49.311485 60762 41.839432 -54.690384 49.518524 60763 41.464966 -54.878525 48.256599 60764 45.666489 -55.952469 48.237946 60765 11.055496 -55.873184 48.691406 60766 43.615509 -55.773956 48.245293 60767 43.984924 -55.918213 48.399338 60768 4.651230 -58.857559 45.870888 60769 8.320573 -58.105621 46.904144 60770 8.725449 -57.621841 48.702202 60771 8.440712 -58.528946 48.407829 60772 8.538071 -58.325119 47.730797 60773 8.794921 -63.417419 47.916656 60774 8.995636 -64.195679 47.591850 60775 9.926353 -63.585220 47.237869 60776 10.966415 -63.988083 46.579041 60777 10.939072 -63.020660 46.484657 60778 32.543030 -61.453842 47.498787 60779 33.102005 -61.014587 47.868523 60780 33.188217 -61.388245 47.654953 60781 32.341919 -61.039246 48.169182 60782 33.668350 -61.386383 48.169197 60783 46.041718 -60.778488 48.045052 60784 22.204651 -63.229919 47.395699 60785 23.268021 -63.044525 46.940331 60786 20.997635 -63.088593 46.998230 60787 29.203995 -63.630478 49.244965 60788 29.013229 -62.932007 48.518997 60789 27.869286 -64.065918 48.181038 60790 29.555115 -62.215302 48.145203 60791 30.500107 -61.760864 48.299187 60792 45.973007 -61.691895 47.836502 60793 23.691673 -63.876022 47.550491 60794 24.623398 -63.040878 46.561966 60795 45.142960 -62.291016 48.202599 60796 11.483856 -64.116959 46.073097 60797 19.308334 -65.596680 47.652473 60798 25.185349 -64.289871 47.506119 60799 24.800598 -63.770554 47.076332 60800 25.499413 -63.692612 46.979446 60801 10.912903 -64.995132 46.485588 60802 26.400955 -63.862213 47.272522 60803 9.472397 -65.069061 47.254524 60804 8.662003 -66.082474 47.585648 60805 10.538223 -66.667038 46.575294 60806 11.490021 -66.013733 45.910370 60807 36.070190 -67.014236 47.095871 60808 22.227158 -67.064865 46.886528 60809 30.262756 -67.592484 46.470551 60810 30.397964 -66.672165 47.139679 60811 31.213333 -65.426208 47.783707 60812 30.829552 -66.621094 47.881950 60813 10.215378 -68.649918 46.495354 60814 9.998672 -71.923828 46.236450 60815 25.749557 -69.735611 47.598541 60816 31.681032 -68.120346 48.148560 60817 32.001587 -68.640991 47.668556 60818 39.902405 -68.577927 47.947227 60819 40.747971 -67.657410 47.594719 60820 7.982543 -68.116623 47.755905 60821 8.633850 -69.124359 47.498138 60822 26.513199 -70.499252 47.510193 60823 36.268143 -70.716553 46.985893 60824 18.498734 -71.084854 46.154137 60825 39.470642 -69.086929 47.773781 60826 18.542435 -71.290146 46.660461 60827 18.690414 -71.549805 47.013374 60828 19.151901 -71.239227 46.585785 60829 20.039062 -71.543579 46.547447 60830 20.749344 -72.079041 46.498039 60831 36.218048 -71.582748 46.603897 60832 37.312103 -70.886536 47.354752 60833 37.898880 -70.235504 47.962250 60834 8.008194 -71.252670 47.216141 60835 8.152557 -72.372711 46.881027 60836 10.268814 -72.865692 45.761757 60837 21.602646 -73.198914 46.555954 60838 21.193138 -72.580322 46.772720 60839 28.343002 -72.726395 47.157822 60840 27.200241 -71.405640 48.003525 60841 27.312668 -72.177521 49.243416 60842 36.662720 -71.974182 46.470123 60843 36.635773 -72.314896 46.042175 60844 37.524521 -71.588821 46.586632 60845 8.023407 -73.697830 46.637459 60846 9.234482 -73.028091 46.202019 60847 8.794830 -74.647995 45.994698 60848 7.659606 -74.932983 46.645149 60849 28.095078 -73.114227 49.309723 60850 29.658325 -74.324265 46.989601 60851 8.362579 -75.965988 46.084091 60852 7.247772 -76.236374 47.325157 60853 29.733116 -75.059860 47.351135 60854 18.413284 -76.336899 46.967484 60855 24.192520 -77.109253 46.342865 60856 28.855545 -77.738068 45.977936 60857 27.564766 -77.980316 46.193390 60858 28.077301 -75.770050 48.822174 60859 29.219070 -74.818771 48.061287 60860 15.710571 -80.448715 47.053902 60861 16.648010 -80.120209 47.108994 60862 16.200790 -79.003632 45.534302 60863 27.712326 -77.583939 47.017685 60864 12.521263 -80.602859 47.014580 60865 13.861588 40.130478 54.453712 60866 9.594589 39.913635 54.554642 60867 10.075737 40.234192 54.486046 60868 14.590607 39.331833 54.920815 60869 16.147873 39.609314 53.977119 60870 14.301849 35.548767 55.024796 60871 16.084778 35.207565 55.078049 60872 7.068131 38.675980 54.060066 60873 14.789467 38.333282 55.420013 60874 6.232140 37.776535 53.950310 60875 20.404694 35.597229 55.119171 60876 20.108490 35.415375 55.242310 60877 19.582901 35.999863 55.068787 60878 5.278351 36.735657 53.846352 60879 5.080788 36.854889 56.511887 60880 4.593483 36.261917 57.299469 60881 4.284287 35.140503 56.941498 60882 3.928146 34.071869 53.290504 60883 3.803238 34.404846 54.783394 60884 4.217865 35.584564 55.258759 60885 11.264297 33.611496 54.313377 60886 13.049576 36.472946 55.567932 60887 11.324356 33.956558 54.458168 60888 14.939500 34.596634 54.675415 60889 17.027084 32.790970 54.068115 60890 11.256958 32.111938 54.347427 60891 16.759529 32.339066 53.633011 60892 3.833649 32.655655 54.448738 60893 12.608308 30.803284 54.161652 60894 3.906441 33.846161 55.975464 60895 13.114471 30.579178 54.595749 60896 15.507553 28.703232 53.779938 60897 3.964317 29.831879 53.567093 60898 24.457405 26.933975 55.439270 60899 23.117226 27.346893 54.623627 60900 24.541275 26.069229 54.206741 60901 4.067841 26.147797 56.024216 60902 4.339913 24.579620 55.268585 60903 25.103882 26.322113 55.351410 60904 26.044998 23.236526 53.788155 60905 26.282654 23.770905 55.062729 60906 5.630913 23.037338 54.153816 60907 5.625565 23.425568 52.972878 60908 6.791489 21.936783 53.642578 60909 7.250519 21.712006 52.799149 60910 25.927780 25.347427 55.104950 60911 25.431442 25.761581 54.912064 60912 6.783714 21.333191 53.707878 60913 26.307396 22.631271 54.229805 60914 32.165291 22.118073 54.163582 60915 32.776085 22.751633 53.710068 60916 6.687027 20.726959 53.087212 60917 35.329559 22.101578 53.943520 60918 36.477402 19.586151 53.675125 60919 5.055115 19.635284 53.136185 60920 4.181542 18.723450 52.764122 60921 24.504074 19.536209 54.528374 60922 35.395332 18.660614 53.893715 60923 36.446762 18.468079 53.252609 60924 3.450585 18.151199 55.008789 60925 3.319275 16.669922 56.182343 60926 3.095001 16.953110 54.704643 60927 4.535996 19.654205 54.045174 60928 3.870789 18.932739 54.107094 60929 22.769234 17.715485 53.135201 60930 23.676422 17.937042 52.390266 60931 25.031723 20.223633 54.682213 60932 34.122879 16.520889 53.277275 60933 34.195656 17.855637 54.084785 60934 3.369652 16.113251 52.901016 60935 21.798233 17.804398 53.820610 60936 18.174301 16.118439 52.903717 60937 18.943954 17.056229 53.581657 60938 20.466995 18.369003 54.891640 60939 17.583191 16.308563 53.997711 60940 20.624718 19.548065 56.680023 60941 20.467865 20.370285 58.204834 60942 21.676437 20.323456 57.840332 60943 27.264328 17.347290 54.364334 60944 26.133392 16.532196 54.303535 60945 5.944542 13.362076 53.389160 60946 4.779862 13.717651 54.263725 60947 17.721252 15.209839 55.121338 60948 23.798462 14.386414 52.931793 60949 24.653305 15.127350 53.363029 60950 6.601173 13.214844 52.523491 60951 7.486992 12.629074 52.862900 60952 23.193954 13.300323 54.203613 60953 22.979736 13.507095 53.314018 60954 23.836563 14.377213 54.277252 60955 22.605408 12.433411 52.789963 60956 7.720779 12.110840 53.045509 60957 33.981102 16.009918 55.665741 60958 34.299500 15.095871 54.822807 60959 35.496216 14.818451 55.151245 60960 34.840622 13.827515 53.146156 60961 37.856659 13.731842 54.030022 60962 37.081520 14.161774 55.136322 60963 40.606934 12.494614 54.551239 60964 39.601517 13.250946 54.356255 60965 6.904320 10.367584 52.256813 60966 7.616134 11.347824 52.766434 60967 23.613205 11.797195 53.750816 60968 25.072563 10.952591 53.911758 60969 18.157867 9.079468 52.032112 60970 18.318375 9.773499 52.666893 60971 18.890137 8.794586 52.573578 60972 18.699585 9.825592 53.218620 60973 19.219559 9.703308 53.677299 60974 24.792862 12.295944 54.996719 60975 28.014236 8.694199 52.854385 60976 28.447792 9.385132 53.562149 60977 28.385216 8.746948 53.464035 60978 2.520996 6.694733 52.211159 60979 2.345245 6.270935 52.047546 60980 28.761322 9.088882 54.552849 60981 42.692993 9.688416 54.188271 60982 42.590576 8.525879 53.912102 60983 26.468826 5.438934 54.649673 60984 26.027710 5.414383 53.714500 60985 2.344460 5.826080 52.207306 60986 2.724190 5.035446 52.144005 60987 21.115486 5.521484 53.695625 60988 38.754005 5.857368 52.906708 60989 3.545982 3.995522 52.475967 60990 20.784317 4.052986 55.026855 60991 43.466827 3.835411 53.528824 60992 7.538315 2.507233 52.509575 60993 7.975738 2.129944 51.807289 60994 7.540634 2.728546 54.946457 60995 7.575287 2.518768 53.741753 60996 8.337845 1.809402 52.316498 60997 20.204208 2.318634 53.179840 60998 20.205490 2.998695 53.048386 60999 26.426086 3.726501 53.254257 61000 40.638260 2.350616 53.645233 61001 8.481155 0.681503 51.144722 61002 21.888496 1.214035 52.669662 61003 23.076859 0.583115 52.227013 61004 23.030045 1.060074 53.134109 61005 23.824799 -0.095901 52.376930 61006 23.851471 0.480484 53.250221 61007 28.339859 1.455048 52.531914 61008 38.969337 0.991058 53.711304 61009 39.004272 1.487518 52.747658 61010 37.687836 0.699677 52.869415 61011 23.480690 1.057968 53.781441 61012 36.806206 0.612457 53.517494 61013 5.950539 -1.355469 51.309380 61014 6.213165 -0.760651 52.390892 61015 3.359245 -2.480148 52.407372 61016 3.311546 -3.124161 51.507332 61017 23.128082 -3.179138 52.372444 61018 27.865173 -1.754105 53.948792 61019 27.329514 -3.149460 53.942772 61020 4.651703 -1.292496 52.858551 61021 48.266357 -3.113937 53.597092 61022 2.898110 -4.088470 51.369759 61023 22.646240 -3.967072 53.216850 61024 22.517029 -4.771851 52.232063 61025 27.047852 -4.033813 53.163528 61026 49.141907 -4.145142 53.150414 61027 49.354797 -3.822083 52.471275 61028 3.238663 -2.038086 53.465279 61029 2.688095 -2.572327 54.180328 61030 2.679367 -3.143829 53.211761 61031 2.561081 -4.394241 52.552025 61032 2.563515 -4.821045 51.704391 61033 49.834808 -4.605377 52.350197 61034 4.302544 -6.803497 52.194511 61035 3.474907 -6.278549 52.128189 61036 22.596062 -6.272736 52.018707 61037 28.437561 -4.936554 53.286308 61038 30.302757 -5.140366 53.839897 61039 29.021957 -4.756088 54.484970 61040 49.811020 -5.569214 53.183159 61041 2.742638 -5.449203 51.925858 61042 10.005356 -6.893280 51.693054 61043 22.246872 -6.513611 52.958710 61044 22.167023 -5.650711 52.866570 61045 51.260635 -7.456314 52.296860 61046 4.378899 -6.323883 53.303795 61047 5.305016 -6.939774 51.930893 61048 6.428017 -6.959381 51.953995 61049 7.190750 -6.978317 51.432968 61050 11.679390 -7.890228 52.277191 61051 11.858047 -8.348572 51.622299 61052 11.227417 -7.601562 51.582626 61053 23.691986 -7.990906 52.472397 61054 22.716797 -7.157242 52.771263 61055 36.988747 -6.873398 52.942009 61056 11.838081 -8.734787 52.323906 61057 43.650818 -7.720642 52.140472 61058 26.790741 -9.282593 51.555534 61059 25.913025 -8.835983 52.463623 61060 45.512604 -8.856796 51.867653 61061 46.582245 -9.212769 52.480003 61062 3.340454 -13.391190 50.631020 61063 2.698341 -13.716537 50.339211 61064 3.435722 -11.432022 49.891052 61065 35.266441 -10.757401 51.503891 61066 49.269562 -10.711624 52.389404 61067 47.469543 -9.984863 52.199203 61068 5.121468 -13.264786 50.738327 61069 11.333771 -7.853699 53.711319 61070 10.962112 -7.200317 54.303581 61071 10.984177 -8.198288 54.798698 61072 11.562515 -10.645615 51.165398 61073 11.004333 -11.649231 51.181068 61074 41.696259 -10.883270 51.962601 61075 7.713600 -13.799942 51.106712 61076 10.188530 -12.446121 51.047791 61077 44.906845 -13.196167 51.904022 61078 48.296234 -10.052155 52.824753 61079 6.117485 -14.561813 50.814117 61080 8.882217 -13.670349 51.637619 61081 45.522781 -14.379089 51.691780 61082 45.411346 -13.702835 53.052086 61083 45.306534 -14.129776 54.407593 61084 45.051941 -12.260651 54.700050 61085 45.637817 -14.777786 52.529037 61086 9.076904 -15.617767 52.106613 61087 9.420845 -15.545822 53.146690 61088 9.729354 -16.928680 52.364243 61089 10.068817 -18.132996 50.819992 61090 40.234314 -18.172348 51.559074 61091 41.376923 -18.120178 51.382927 61092 42.100571 -18.067825 51.431290 61093 44.403229 -16.563568 53.132469 61094 48.811066 -17.967819 51.814987 61095 49.679016 -17.293304 52.686966 61096 33.705063 -20.471542 52.419403 61097 33.498283 -19.866547 51.789032 61098 33.938622 -19.204636 51.067436 61099 35.426285 -18.713348 52.107864 61100 38.333313 -18.223709 52.648544 61101 53.662689 -17.884003 51.556046 61102 53.704926 -19.089630 51.957123 61103 3.956040 -21.988922 51.226311 61104 4.466980 -22.031494 50.838692 61105 4.402428 -20.439163 52.027199 61106 8.084351 -20.341812 50.790169 61107 10.191650 -19.303940 50.495255 61108 9.772995 -19.815674 50.638344 61109 5.734055 -20.658142 51.085434 61110 40.297882 -21.479279 51.874420 61111 44.801086 -20.824478 52.393295 61112 44.401688 -20.451416 53.125061 61113 43.695770 -20.907349 52.326080 61114 4.248673 -23.093552 51.024277 61115 37.867554 -24.666214 51.239372 61116 39.336548 -22.334702 51.948502 61117 45.357269 -21.083847 51.340370 61118 44.547394 -21.163391 51.809654 61119 38.472763 -24.564255 51.903091 61120 6.631363 -23.646713 49.592583 61121 6.566010 -24.985596 50.640930 61122 53.138580 -23.815414 51.968391 61123 52.135880 -24.858749 52.265762 61124 34.747467 -22.584244 52.431313 61125 34.858902 -24.339355 52.236504 61126 7.792022 -25.858612 50.468628 61127 34.346985 -24.923538 51.758530 61128 37.439529 -25.776489 51.638260 61129 50.567764 -25.848862 52.424477 61130 35.099487 -26.938217 50.574005 61131 46.092743 -27.466599 51.033844 61132 46.909103 -27.276978 51.891487 61133 49.235046 -26.370636 53.369545 61134 3.676605 -29.231812 50.535652 61135 2.954300 -29.345016 50.516968 61136 4.463142 -28.855560 50.217262 61137 9.023270 -27.586960 51.892906 61138 9.734406 -28.027527 51.839455 61139 8.668274 -26.735458 50.868614 61140 31.184982 -28.180099 50.780891 61141 32.024628 -27.243942 50.867661 61142 53.545685 -28.611130 50.454994 61143 6.312561 -29.530655 49.030357 61144 12.796693 -28.679047 49.750923 61145 12.219971 -29.080399 50.697929 61146 30.872940 -27.797134 51.564178 61147 30.478363 -28.851807 51.066902 61148 31.122452 -28.696701 50.662270 61149 2.375069 -29.848114 49.878006 61150 4.147141 -30.344574 50.632355 61151 4.530853 -29.448822 50.519417 61152 4.727242 -31.156158 50.289352 61153 12.976677 -30.454529 50.214462 61154 31.109619 -28.969772 50.835518 61155 49.688980 -30.122894 51.793236 61156 2.298843 -30.995087 49.623741 61157 2.284004 -30.287140 49.790428 61158 39.421242 -31.315628 51.069199 61159 38.524010 -32.063858 51.465919 61160 39.255524 -32.005737 52.089645 61161 39.474487 -30.721588 50.238739 61162 40.403076 -30.616714 50.243439 61163 12.357101 -31.027039 51.588593 61164 12.254608 -31.523788 50.455742 61165 47.195297 -31.953476 51.115685 61166 36.701927 -33.041031 51.320351 61167 10.608459 -32.680328 50.806480 61168 9.685921 -33.184647 50.994438 61169 9.824699 -33.848755 49.924332 61170 34.865234 -33.528992 50.304802 61171 34.793228 -34.063919 51.218750 61172 45.738480 -33.791763 52.357117 61173 52.809052 -33.320847 50.820663 61174 8.951973 -34.740356 50.185997 61175 9.427582 -35.968430 50.170639 61176 11.164001 -37.036697 50.049004 61177 32.948975 -34.533234 50.177872 61178 32.871109 -35.081100 51.117798 61179 38.382294 -35.116394 50.147881 61180 41.248093 -34.646255 51.087074 61181 42.274460 -34.431366 50.901405 61182 49.572128 -34.984894 49.910545 61183 50.018799 -34.540024 49.954742 61184 26.263290 -36.289352 49.884789 61185 27.109955 -35.879959 50.288460 61186 10.012726 -37.008377 50.911987 61187 25.714302 -37.137360 50.134148 61188 34.347900 -37.478851 49.895470 61189 50.699860 -35.841949 51.939781 61190 35.083847 -37.033997 50.163475 61191 51.673935 -37.412582 52.019310 61192 3.709267 -39.827423 48.903946 61193 4.309105 -39.558212 49.668625 61194 5.056770 -40.218094 50.487961 61195 6.740868 -39.420944 49.737122 61196 7.993301 -39.488937 49.248497 61197 25.215408 -38.122757 50.284416 61198 3.987175 -40.155518 49.704315 61199 13.415001 -39.936584 50.332436 61200 24.315681 -39.710571 49.659317 61201 28.610016 -40.317932 50.807838 61202 38.511673 -39.558060 50.196953 61203 40.592804 -39.377533 50.757355 61204 43.383835 -39.698212 51.264824 61205 47.056656 -39.625641 50.863029 61206 53.501556 -39.455353 50.111153 61207 23.722595 -40.738602 49.221916 61208 30.091354 -40.401947 51.135071 61209 38.226013 -39.478180 52.266586 61210 39.430634 -39.595428 51.065491 61211 48.504745 -40.638016 50.370529 61212 5.026528 -41.980942 49.108368 61213 10.313271 -41.654434 49.121407 61214 32.527344 -41.830170 49.767532 61215 52.787933 -39.725861 51.623123 61216 53.151123 -39.336090 50.954208 61217 5.950836 -42.810303 48.555801 61218 10.565118 -42.733368 49.313896 61219 33.368324 -42.543915 49.818924 61220 37.701996 -42.555344 49.474304 61221 36.414124 -42.599167 53.247894 61222 39.066345 -42.731339 52.349213 61223 37.455704 -42.923538 55.637939 61224 40.019928 -42.596832 49.824478 61225 40.385529 -42.982788 49.080544 61226 40.630676 -43.279160 49.783142 61227 40.429901 -42.894806 50.924347 61228 45.083405 -43.192627 49.379654 61229 45.566467 -43.788116 50.321609 61230 44.550949 -44.024521 49.737366 61231 2.323296 -45.030014 49.455032 61232 3.153755 -44.247025 48.504654 61233 3.161217 -43.877808 49.270164 61234 3.933228 -43.774261 48.814758 61235 4.734352 -43.266098 49.361237 61236 6.594109 -43.443420 48.088127 61237 9.697769 -43.394485 50.379494 61238 13.605927 -43.893402 50.998749 61239 13.332047 -44.628830 51.904648 61240 13.047791 -45.689041 51.216522 61241 27.290009 -42.897522 50.899826 61242 27.408356 -43.612198 51.562691 61243 26.858696 -43.500626 50.050598 61244 34.322327 -42.490402 51.079636 61245 33.774918 -42.576263 50.058060 61246 40.838409 -43.706970 50.376144 61247 40.574738 -42.895859 52.510086 61248 40.419525 -42.795135 51.831718 61249 41.181961 -43.341965 51.894936 61250 43.941132 -45.734650 50.708977 61251 48.579300 -42.231110 50.041702 61252 48.049927 -42.848328 50.352470 61253 48.745239 -42.981064 50.687599 61254 52.414383 -43.077255 50.009041 61255 2.892181 -43.604752 50.080360 61256 5.427605 -42.896896 49.083694 61257 26.205368 -44.700806 49.656395 61258 2.411842 -47.714157 48.982216 61259 23.861832 -46.096527 49.742950 61260 24.417503 -46.535263 50.454803 61261 44.328400 -47.441406 52.488304 61262 42.855408 -47.739319 52.011345 61263 51.461945 -42.882828 51.182434 61264 52.300568 -42.150772 50.731934 61265 2.670830 -49.378571 49.137405 61266 2.338539 -49.427933 48.458603 61267 34.960739 -47.231110 48.899406 61268 41.467087 -48.081573 50.529312 61269 40.565704 -48.335785 49.416122 61270 51.269913 -45.130096 50.186859 61271 3.140488 -48.849136 49.508835 61272 48.173340 -47.708481 49.399757 61273 47.730942 -48.134735 50.359505 61274 33.974442 -49.560776 49.049881 61275 34.542465 -48.475677 49.622635 61276 38.672043 -51.535141 48.702148 61277 44.734894 -50.979507 50.424759 61278 45.481964 -49.011154 49.472313 61279 2.526756 -50.562241 48.827011 61280 35.021698 -49.620651 50.251968 61281 39.498245 -51.762390 49.712158 61282 2.378449 -52.481033 49.017380 61283 2.470024 -53.313309 48.477318 61284 10.802521 -52.472717 49.377563 61285 9.819801 -52.765045 49.515480 61286 12.274986 -53.057953 48.618134 61287 47.447662 -52.067657 50.049034 61288 8.544617 -53.219315 49.636078 61289 7.798095 -53.533234 48.324226 61290 7.385574 -53.701813 49.192757 61291 8.937927 -53.094330 48.535736 61292 11.245438 -52.517349 48.570702 61293 25.756554 -53.432053 49.115150 61294 30.892471 -52.841293 49.894791 61295 2.820015 -53.772964 48.318184 61296 3.454773 -54.103775 48.595085 61297 6.701111 -53.626022 51.013321 61298 7.503792 -53.578125 50.160675 61299 6.228264 -54.005310 49.548027 61300 12.370026 -53.077164 50.706215 61301 11.849258 -52.726608 49.576454 61302 10.974396 -52.494095 50.609428 61303 23.200348 -54.515839 49.250206 61304 29.609116 -53.330978 50.052643 61305 40.343399 -52.822052 50.308434 61306 4.397568 -54.451843 48.819870 61307 5.306824 -54.270462 48.664223 61308 30.519753 -56.373108 48.840088 61309 32.960716 -55.633621 49.516029 61310 31.533646 -56.451157 50.098579 61311 36.921616 -55.623718 48.947388 61312 42.714066 -55.083618 49.912643 61313 43.646423 -55.597260 49.215340 61314 10.873009 -55.832260 49.677910 61315 9.966156 -56.592026 48.913277 61316 24.948364 -56.977295 50.217041 61317 26.509674 -56.996246 50.132919 61318 28.580460 -56.873306 49.397270 61319 27.605789 -56.894592 49.516418 61320 29.660538 -56.775726 49.357216 61321 44.601349 -55.935898 48.866028 61322 45.479340 -55.922546 49.534103 61323 46.294510 -55.896973 49.105530 61324 40.172363 -58.030960 49.112808 61325 42.656128 -58.875916 50.949898 61326 43.598267 -59.907013 51.301254 61327 42.311005 -59.209869 52.558922 61328 41.927856 -58.718124 49.775795 61329 43.151077 -59.244568 49.804138 61330 31.460808 -61.201797 48.643539 61331 31.900927 -61.477905 49.634766 61332 33.339935 -60.779846 48.763466 61333 34.335938 -61.099701 48.870674 61334 34.308334 -62.285538 49.092224 61335 35.254639 -61.004807 49.476311 61336 34.278259 -60.351181 49.908554 61337 35.353867 -60.035294 49.843925 61338 45.133575 -61.092941 49.231277 61339 7.369324 -64.446213 48.099625 61340 28.739075 -62.533264 47.455536 61341 8.995758 -62.345840 47.993423 61342 20.926628 -63.648331 48.016579 61343 31.606966 -66.681686 48.754707 61344 44.203552 -62.860840 48.500542 61345 43.432739 -63.013916 49.238373 61346 5.110344 -63.783951 48.712082 61347 4.933075 -65.188248 48.732231 61348 8.403229 -61.401642 48.476952 61349 18.534454 -64.797821 48.187027 61350 18.957458 -64.100937 48.626122 61351 22.231155 -64.162582 48.441727 61352 21.145996 -64.294846 49.127426 61353 40.546967 -65.831848 49.972031 61354 41.221558 -64.615524 49.790024 61355 23.612099 -65.118073 48.875320 61356 24.326797 -64.621429 48.019508 61357 25.154396 -65.130753 48.303085 61358 26.322693 -64.649384 47.924438 61359 26.499702 -65.628998 48.830963 61360 8.877678 -67.228043 47.424492 61361 41.974426 -64.715393 48.538322 61362 19.017563 -66.412766 48.248703 61363 18.468460 -65.789169 48.201897 61364 19.404762 -67.131332 48.875046 61365 18.338028 -66.518036 48.916275 61366 20.248978 -66.965302 48.237534 61367 21.919289 -67.703842 48.026344 61368 30.854118 -67.460968 47.562912 61369 40.269104 -64.583054 51.445656 61370 24.178833 -68.746124 47.717110 61371 36.150871 -68.840378 48.621078 61372 32.742996 -68.538239 48.461594 61373 33.171791 -68.441315 47.621178 61374 7.005112 -72.919403 47.509369 61375 7.206627 -71.717239 47.469391 61376 6.100433 -71.578171 48.438400 61377 8.003265 -70.191544 47.569702 61378 7.271484 -70.879730 47.647537 61379 36.702660 -71.429337 46.948174 61380 38.562317 -70.087051 47.832108 61381 19.428505 -71.757675 47.348267 61382 5.948509 -72.809311 48.905678 61383 7.084618 -74.190338 47.132530 61384 6.409691 -73.989426 48.185997 61385 6.663277 -74.934479 47.579132 61386 18.537567 -73.414444 48.045601 61387 19.234879 -73.137558 49.099548 61388 19.446091 -72.478989 48.335480 61389 20.535172 -72.287537 47.591530 61390 21.648788 -73.205856 47.535431 61391 28.958603 -73.903549 48.124535 61392 18.568916 -72.222977 47.392113 61393 7.008820 -75.028503 47.073608 61394 24.077591 -76.430328 47.869797 61395 25.240326 -77.388321 47.142426 61396 18.264282 -78.121933 47.949905 61397 7.565811 -77.620636 47.624817 61398 7.563362 -77.501617 46.938629 61399 18.739632 -76.206345 48.570358 61400 18.579559 -77.362015 49.102303 61401 25.986847 -77.050507 48.064491 61402 26.589722 -77.616714 47.099022 61403 26.840523 -76.623047 48.782013 61404 8.353745 -78.590546 47.829620 61405 8.028549 -78.369278 46.800133 61406 13.815437 -80.557220 47.335800 61407 17.221619 -79.313690 46.837822 61408 14.369614 -80.385864 48.370697 61409 14.791122 -80.558060 47.327591 61410 11.877869 -80.270859 48.544350 61411 13.096984 -80.104828 48.690697 61412 16.445496 -80.350540 47.591774 61413 10.324432 40.164017 55.214630 61414 10.977478 40.225784 55.499603 61415 6.890221 38.726959 55.406860 61416 8.187103 39.290771 56.079895 61417 9.715271 39.447632 56.037079 61418 13.077011 39.528671 55.317566 61419 14.118530 37.362000 55.608459 61420 5.685074 37.001892 58.037323 61421 4.975708 36.772781 57.640823 61422 5.142815 36.906891 54.831192 61423 20.511002 34.868698 54.837502 61424 11.260971 34.582642 54.992340 61425 10.811928 33.574280 54.901146 61426 10.573577 34.802887 55.854706 61427 9.817841 34.609879 56.947540 61428 10.384277 33.284943 55.946777 61429 17.972015 34.878769 55.135544 61430 19.456909 34.740326 55.103714 61431 19.922234 33.735275 54.600822 61432 10.854538 32.627228 54.763939 61433 3.796303 34.700317 55.557495 61434 11.295685 31.936707 55.533081 61435 10.644806 32.729065 56.750122 61436 11.426430 32.162704 56.865417 61437 12.368774 30.948578 54.973434 61438 12.258255 31.221451 55.775421 61439 4.347687 31.024612 55.277496 61440 4.491509 29.567108 55.465424 61441 4.399315 28.571991 55.762360 61442 4.121842 28.550369 54.546425 61443 15.157875 29.697815 55.203354 61444 15.904625 30.490967 57.512924 61445 15.451004 30.769394 57.869675 61446 14.926422 30.609146 56.978226 61447 15.926567 29.270660 55.153900 61448 17.139877 29.192093 55.613342 61449 16.036079 29.934067 56.337311 61450 23.276268 27.977295 55.465851 61451 23.769127 27.601318 55.575378 61452 26.158630 24.820007 54.893440 61453 4.059128 24.996094 54.111107 61454 4.795380 22.348724 56.181870 61455 6.413841 22.321686 53.842751 61456 33.044884 22.488800 54.358459 61457 31.527496 21.561752 54.446655 61458 34.449181 22.215515 54.500481 61459 33.718582 21.993881 54.714630 61460 26.357002 22.600113 54.826004 61461 34.618469 21.323685 54.689590 61462 5.662109 20.483398 54.012993 61463 6.408211 20.957672 53.911339 61464 25.440514 20.946228 55.040527 61465 34.753586 20.340408 54.724899 61466 35.715729 20.645279 54.175713 61467 35.273407 19.631592 54.342789 61468 4.914528 20.452377 55.047333 61469 5.397659 21.198059 55.161499 61470 5.024139 21.237946 55.648712 61471 36.577484 20.501480 53.703735 61472 23.567291 18.605087 54.222183 61473 18.280968 18.062363 54.928688 61474 22.860870 18.281586 54.188065 61475 3.220421 16.116486 54.064377 61476 19.564720 19.157104 55.981842 61477 22.080002 18.693878 55.156601 61478 27.697800 18.155640 55.395691 61479 33.460815 16.649658 54.304222 61480 3.984184 14.875000 53.629967 61481 3.547585 15.252380 55.111206 61482 17.251144 17.255219 55.144897 61483 17.336319 16.789383 56.114594 61484 25.025253 15.798706 54.327583 61485 25.567551 16.354462 55.057861 61486 33.514610 15.533783 54.083084 61487 4.035874 14.402512 54.599274 61488 24.397873 15.229294 54.212250 61489 33.652756 15.434174 54.654678 61490 33.356003 15.988632 54.728935 61491 33.972885 15.007599 54.225632 61492 34.778397 14.435669 54.085068 61493 38.750351 13.664856 54.257622 61494 38.502045 13.721664 55.069122 61495 6.944771 12.950562 53.218147 61496 7.424790 12.464447 53.517250 61497 7.462296 11.488586 54.146194 61498 17.523911 13.547562 53.582748 61499 22.945694 12.716537 53.744133 61500 7.510025 10.568207 53.423401 61501 18.130692 13.193420 54.433113 61502 18.286331 11.301941 53.497940 61503 37.882568 13.864380 56.474533 61504 39.391205 12.951721 55.672272 61505 6.834023 9.717285 53.548882 61506 18.906052 12.173401 54.843033 61507 19.286728 10.803757 54.504990 61508 19.885925 11.271851 55.418442 61509 5.433014 9.015503 53.415291 61510 4.425430 8.914078 52.854614 61511 28.392471 11.203857 54.951157 61512 29.261337 10.856995 55.394684 61513 28.584991 11.692169 55.658279 61514 3.779373 7.941528 53.505569 61515 5.072121 8.277222 54.657425 61516 4.121498 7.626907 55.027771 61517 6.338890 8.903549 54.574463 61518 6.984146 9.068924 55.238617 61519 6.523491 8.708191 55.201126 61520 28.878494 9.714554 54.088470 61521 29.154312 9.988190 54.742058 61522 2.750252 7.040680 52.958130 61523 20.032166 9.734528 54.556084 61524 2.339218 6.355194 52.786598 61525 21.237228 7.123856 54.034157 61526 28.166595 8.333984 54.641167 61527 25.811440 5.588928 53.202103 61528 41.652618 7.509140 54.010483 61529 42.172607 7.907990 53.916885 61530 2.347977 5.527885 53.244492 61531 38.204819 5.794998 53.990852 61532 40.522614 7.490295 55.128662 61533 21.591537 5.810493 54.643158 61534 37.341721 5.040237 53.755135 61535 2.726257 4.479858 53.214134 61536 3.157791 3.912010 53.237541 61537 44.138824 3.499046 53.928207 61538 43.404083 3.612999 54.042915 61539 42.440506 3.403847 53.716812 61540 42.019287 2.942528 54.372353 61541 8.328949 2.026123 52.775551 61542 28.438599 2.103470 53.507225 61543 36.185722 2.914864 53.405663 61544 20.761200 1.865433 53.912270 61545 22.455734 1.455368 54.597084 61546 21.477936 1.878479 56.137299 61547 20.908875 1.923126 55.163544 61548 28.939804 1.084656 53.387360 61549 24.367065 -0.053146 54.085144 61550 24.008675 0.836090 54.660545 61551 28.992371 -0.029663 54.201653 61552 29.364944 1.052322 54.048912 61553 37.354691 0.224930 53.577065 61554 37.932327 0.304016 53.768120 61555 6.000305 -0.443710 53.610146 61556 24.114227 -0.718430 53.117050 61557 38.522049 0.446503 54.744308 61558 46.960999 0.189285 53.469139 61559 2.873711 -3.397385 52.250870 61560 23.314857 -3.124130 53.788322 61561 23.898331 -1.992355 53.749413 61562 22.225494 -4.552124 52.973175 61563 22.142883 -4.955902 52.909210 61564 3.056236 -5.511673 53.269974 61565 2.618141 -4.117889 54.098892 61566 31.948946 -5.845200 52.949661 61567 3.656700 -5.855377 54.092094 61568 4.215523 -5.637650 55.051941 61569 7.731750 -6.268814 53.438766 61570 9.212677 -6.321396 53.438858 61571 10.849854 -7.117813 52.986107 61572 38.336761 -6.646286 52.756012 61573 41.195221 -6.489029 53.446854 61574 50.310883 -7.014847 53.293053 61575 7.174866 -6.694824 52.369972 61576 11.598557 -8.048904 52.973198 61577 23.236488 -7.512039 53.914276 61578 22.589737 -6.768066 53.914513 61579 33.255180 -5.752686 53.864235 61580 33.373329 -6.869476 52.449013 61581 34.886185 -6.895859 53.025185 61582 34.789505 -6.370270 54.248428 61583 36.629387 -6.694138 54.144394 61584 35.589249 -6.342850 55.372101 61585 43.655670 -7.307510 53.077988 61586 49.392700 -7.860703 54.164764 61587 49.267151 -6.360474 54.094887 61588 24.122520 -8.220352 53.691071 61589 27.064827 -9.097824 52.277763 61590 44.403717 -7.633026 53.119942 61591 45.510773 -8.244308 53.088837 61592 24.710144 -8.583344 52.749672 61593 27.717621 -8.965225 53.207726 61594 26.730133 -8.749512 52.916161 61595 28.983147 -8.964905 54.120171 61596 11.551956 -9.771835 52.246994 61597 11.036652 -10.821884 52.184013 61598 41.011612 -10.098358 54.503555 61599 39.754745 -9.819183 55.834076 61600 47.582489 -9.582794 53.051453 61601 47.301941 -8.739853 53.913177 61602 10.384384 -11.905457 51.992722 61603 35.414558 -10.816757 52.497787 61604 43.848877 -11.459808 53.491493 61605 33.716599 -11.395996 52.594681 61606 34.105209 -11.291763 53.436188 61607 44.550919 -12.352478 52.821411 61608 50.186127 -9.954895 53.024948 61609 5.235985 -15.913162 50.069130 61610 7.653625 -15.505707 51.074997 61611 9.645935 -12.843399 51.874687 61612 3.062111 -14.255753 50.560234 61613 8.490860 -14.718262 51.735023 61614 8.477509 -15.676086 51.556526 61615 44.973175 -15.912231 53.104500 61616 45.288834 -15.021774 53.384552 61617 52.251434 -17.880646 53.003868 61618 39.782036 -17.764191 53.331100 61619 39.778900 -17.103058 54.850021 61620 40.887421 -17.034882 54.683334 61621 42.958588 -17.140274 53.393684 61622 43.842148 -17.110138 52.918907 61623 43.630646 -17.541275 52.248665 61624 47.509979 -18.399414 54.332642 61625 48.484253 -18.070511 53.191200 61626 49.729523 -18.020370 54.288177 61627 10.197586 -18.124741 52.248589 61628 10.089272 -19.197968 51.593163 61629 34.160278 -19.182175 52.034927 61630 36.952805 -18.323059 52.762444 61631 36.314400 -18.210358 53.529068 61632 39.327301 -18.245651 52.278603 61633 46.680389 -19.612259 52.612808 61634 45.486832 -20.198456 52.823608 61635 4.337586 -18.671127 53.392746 61636 3.397087 -18.908066 53.425133 61637 6.658897 -19.681412 52.990082 61638 8.271606 -20.122910 52.227554 61639 8.126045 -19.801788 53.478020 61640 9.212395 -20.029465 51.541687 61641 43.203964 -20.125793 54.677612 61642 42.738297 -20.373184 54.455261 61643 43.224640 -20.458511 53.647766 61644 41.770279 -21.008636 52.910324 61645 3.150169 -21.805069 52.036484 61646 2.593773 -21.478790 52.556725 61647 2.518837 -22.523071 52.551674 61648 35.505447 -23.998779 53.128014 61649 52.022278 -22.933594 54.119591 61650 52.649185 -23.575821 52.990730 61651 3.255379 -23.493591 52.122696 61652 3.685585 -22.907562 51.513901 61653 6.627007 -26.197906 52.450226 61654 7.712646 -26.501343 51.442879 61655 32.700844 -26.553284 51.388405 61656 52.279358 -24.479156 53.211655 61657 5.299378 -25.957153 54.546082 61658 5.848290 -26.240585 54.035492 61659 5.258675 -25.957870 53.322296 61660 31.928988 -27.071976 51.755806 61661 36.195724 -26.944260 51.695480 61662 47.693726 -27.218155 52.939880 61663 2.622902 -29.436707 50.223885 61664 46.225433 -27.635193 51.836395 61665 11.586814 -29.234573 52.022850 61666 29.638901 -28.389496 52.114594 61667 34.856178 -27.962051 51.657722 61668 33.893158 -28.637115 51.779556 61669 51.525604 -29.482300 51.671303 61670 2.880318 -30.113235 50.425110 61671 29.351166 -29.256790 51.483353 61672 28.371445 -29.090210 52.478668 61673 28.919296 -29.801346 51.780396 61674 29.917213 -29.686707 51.275764 61675 29.320740 -29.785782 51.358414 61676 31.058640 -29.460724 51.429085 61677 32.685280 -29.161606 51.795242 61678 31.663958 -29.883606 52.405823 61679 51.630035 -29.814651 52.430923 61680 52.454056 -30.164719 52.146164 61681 53.496613 -29.815811 51.191528 61682 29.411514 -30.075867 51.595917 61683 30.040436 -30.074890 51.711128 61684 41.064941 -31.233368 51.749069 61685 49.272522 -30.728180 52.466530 61686 49.905350 -30.993713 53.545815 61687 48.737167 -31.771942 53.692085 61688 11.438995 -32.164413 50.416634 61689 42.282028 -30.952515 51.853668 61690 43.320557 -30.768753 52.565071 61691 47.653702 -31.811554 51.731926 61692 48.114044 -31.727356 52.461464 61693 37.645004 -32.508804 51.390945 61694 37.599777 -33.038940 52.287811 61695 46.890198 -32.800232 52.275696 61696 53.100830 -32.649200 51.335907 61697 8.312897 -34.208374 50.948318 61698 8.801720 -33.312622 51.751953 61699 7.535042 -33.807114 51.907951 61700 9.018646 -33.897263 50.613007 61701 35.745422 -33.517288 51.251389 61702 35.688217 -34.060745 52.206367 61703 52.503677 -33.312485 51.812073 61704 7.632949 -35.138199 51.133461 61705 33.843597 -34.545471 51.166519 61706 33.721031 -35.132004 52.081261 61707 40.251984 -34.941528 51.206863 61708 38.490723 -35.482178 51.060654 61709 44.172470 -34.290283 51.455750 61710 43.352295 -34.490189 51.465302 61711 50.998459 -34.489426 51.078011 61712 51.855133 -33.987549 51.978653 61713 8.418228 -36.098267 50.882141 61714 26.566154 -36.592224 51.262764 61715 27.439575 -36.062576 51.207832 61716 28.184998 -36.018768 51.090080 61717 27.757401 -35.791367 50.656647 61718 29.271454 -36.191208 51.329666 61719 30.231003 -36.109543 51.170425 61720 37.566856 -36.039154 51.107796 61721 39.426781 -35.740326 52.176498 61722 9.064148 -36.474838 50.775871 61723 27.822357 -36.551315 52.342796 61724 36.543205 -36.518768 50.969833 61725 35.662186 -36.974838 50.790901 61726 34.985939 -37.682373 50.979149 61727 4.328255 -40.127869 50.115623 61728 12.184532 -38.035873 50.305069 61729 7.837097 -39.758591 49.814522 61730 12.428055 -39.107803 51.136391 61731 13.026184 -40.599472 51.175774 61732 24.950043 -39.245087 50.848480 61733 33.928581 -39.039795 50.054237 61734 34.293961 -38.385406 50.582512 61735 40.245270 -39.645401 52.155296 61736 44.171906 -39.773605 51.238022 61737 52.506226 -38.652130 51.846939 61738 4.346596 -40.794662 50.054466 61739 24.307144 -40.623489 50.551300 61740 36.797165 -38.189224 52.528397 61741 37.071930 -39.173294 52.531029 61742 36.294777 -39.338959 51.471725 61743 46.411255 -39.830200 51.275482 61744 47.052032 -39.818954 51.368996 61745 47.776001 -40.012512 51.058418 61746 48.490356 -40.441574 51.208748 61747 46.934723 -40.224106 52.117287 61748 48.916260 -41.526413 50.325539 61749 49.252533 -41.270370 51.475426 61750 4.494377 -41.919571 50.175217 61751 4.979271 -42.575577 49.673019 61752 23.666824 -41.821960 50.035553 61753 49.803345 -41.398148 52.691833 61754 48.704529 -41.107010 52.974648 61755 4.613335 -42.673492 50.025581 61756 9.794632 -41.929031 49.841507 61757 31.766542 -41.373444 50.667229 61758 33.015617 -42.199341 50.408340 61759 37.090866 -42.641800 50.783951 61760 39.092010 -42.534348 50.677406 61761 41.289566 -43.231079 52.943962 61762 49.450623 -41.165588 53.766602 61763 51.750580 -41.353897 51.970428 61764 3.861176 -42.813431 50.420555 61765 2.874886 -43.116089 50.986923 61766 3.748596 -43.412170 49.650520 61767 3.411194 -42.625229 51.192238 61768 14.233231 -43.688583 49.702087 61769 47.085526 -43.541687 50.852448 61770 48.223251 -43.537354 51.136749 61771 49.281540 -42.425140 50.843910 61772 49.304459 -44.001266 51.566238 61773 51.846558 -44.131958 50.153412 61774 13.490074 -44.854034 49.661774 61775 21.864746 -44.948868 50.646446 61776 22.221588 -44.394043 50.663857 61777 40.492813 -44.721130 50.659729 61778 41.074463 -43.733749 51.063034 61779 41.248322 -44.369217 51.801552 61780 12.606041 -45.587326 49.366577 61781 12.506104 -45.988510 49.892090 61782 10.636505 -45.332596 49.907631 61783 21.935257 -45.757874 50.786797 61784 27.064270 -44.817719 51.270714 61785 38.957642 -45.913223 50.473297 61786 41.456940 -44.824677 52.720619 61787 41.778015 -43.924149 52.849716 61788 50.141418 -42.725601 51.393120 61789 50.582962 -41.833740 51.987198 61790 50.576981 -44.115860 51.278946 61791 11.508774 -46.374908 49.960037 61792 12.117989 -46.679138 50.490829 61793 22.997978 -46.482925 51.096237 61794 21.987503 -46.351486 51.239685 61795 38.656013 -46.304840 51.681755 61796 37.602814 -46.822296 51.627068 61797 50.077347 -45.134674 51.414925 61798 49.801758 -46.197556 51.315475 61799 10.292374 -46.634857 50.416229 61800 11.258636 -47.181931 50.583084 61801 26.317261 -46.764297 51.450043 61802 3.134194 -48.224594 49.691650 61803 4.036881 -48.522461 49.943832 61804 6.613350 -48.533722 50.484787 61805 5.412102 -48.130920 50.310509 61806 6.709580 -47.288712 50.915123 61807 40.158524 -49.991272 50.406769 61808 48.481400 -47.687012 50.751625 61809 49.355865 -47.372421 50.688896 61810 3.746933 -50.004135 50.050255 61811 5.917351 -48.698303 50.091530 61812 5.611946 -49.172836 50.342979 61813 35.408142 -48.388321 50.489868 61814 46.040863 -48.914154 50.680595 61815 45.148651 -49.833908 50.956169 61816 46.999176 -48.086975 51.355545 61817 2.331421 -51.539673 48.941780 61818 36.509300 -47.695892 51.332039 61819 35.918549 -48.977997 51.077370 61820 36.495834 -49.035751 51.829056 61821 2.666046 -51.420715 49.607994 61822 44.892578 -51.506287 49.991180 61823 9.508530 -52.758499 50.506851 61824 33.032753 -52.120438 50.136002 61825 32.190659 -52.512817 50.356438 61826 33.991333 -51.785477 50.740952 61827 35.062088 -50.983246 50.962357 61828 45.441666 -51.886383 50.067039 61829 45.105118 -51.798141 50.703766 61830 45.596832 -52.123260 50.472794 61831 45.799103 -52.448654 51.108574 61832 46.969070 -52.677704 50.804054 61833 48.263260 -52.001892 49.571541 61834 48.023499 -52.869598 50.272781 61835 2.352028 -53.300934 49.083931 61836 8.219933 -52.992004 51.337646 61837 30.222504 -53.393646 51.064697 61838 31.492233 -53.007217 51.516708 61839 40.339386 -51.426437 51.106522 61840 40.720947 -52.304352 51.514183 61841 2.669090 -53.736984 48.974236 61842 3.166611 -53.982956 49.607910 61843 5.105576 -54.419891 49.397507 61844 5.221893 -54.072601 50.496147 61845 12.566597 -53.681229 51.619118 61846 12.466263 -54.072479 50.687988 61847 23.069946 -54.076187 50.081940 61848 25.772026 -53.630386 50.291763 61849 24.200638 -53.562988 50.617714 61850 25.133499 -53.576279 51.547302 61851 27.374451 -53.753281 50.727692 61852 42.154633 -54.516876 50.676819 61853 48.516663 -53.678879 49.836479 61854 3.792702 -54.406052 49.379562 61855 4.451729 -54.458115 49.713623 61856 11.776138 -54.916550 50.425140 61857 22.568542 -55.153870 49.709091 61858 36.825165 -55.259216 49.974739 61859 35.507828 -55.043427 50.466309 61860 41.453217 -53.564362 51.051193 61861 47.925537 -54.044159 50.273720 61862 47.269318 -54.883118 50.186485 61863 12.196426 -54.441849 51.393791 61864 22.690788 -56.439316 49.952271 61865 23.412956 -57.820419 50.840462 61866 21.432716 -57.345001 50.658096 61867 42.691605 -54.721817 50.863976 61868 43.500671 -54.848999 50.905945 61869 44.677307 -55.473953 50.205338 61870 44.697418 -54.374146 51.611633 61871 46.286148 -55.503204 50.065376 61872 23.863693 -56.680038 49.623177 61873 30.523422 -56.719086 49.700821 61874 32.705383 -55.966888 50.625114 61875 7.663726 -58.470428 49.647858 61876 8.167007 -58.408691 49.046692 61877 8.125107 -57.691483 49.881531 61878 39.700584 -57.264267 49.897148 61879 8.279984 -59.116211 48.763603 61880 40.783936 -58.084732 49.945198 61881 33.205811 -60.550461 49.658394 61882 36.059181 -59.764893 50.194824 61883 35.832176 -60.308853 49.684906 61884 36.305908 -60.775818 50.109291 61885 44.494400 -60.312927 50.352997 61886 43.847244 -59.560471 50.430099 61887 30.966019 -61.627426 49.216461 61888 31.473648 -61.183807 49.205803 61889 4.345955 -62.298279 48.962524 61890 5.013756 -62.204971 48.908745 61891 3.922806 -61.502823 49.553703 61892 6.030304 -60.907761 49.296577 61893 5.005760 -61.071869 49.329865 61894 6.362793 -62.527512 48.649506 61895 7.324501 -61.311737 48.912399 61896 7.305481 -62.639908 48.487030 61897 8.072922 -62.531906 48.368065 61898 29.911407 -62.623016 49.167175 61899 5.717545 -65.723083 48.449257 61900 6.520729 -66.692032 48.293259 61901 44.023468 -61.074997 50.773132 61902 44.334503 -62.001694 49.607101 61903 43.133423 -62.348022 50.489082 61904 3.869606 -63.070755 49.433426 61905 19.132988 -64.180695 49.905258 61906 20.020889 -63.959656 48.825623 61907 17.958618 -64.613617 49.207344 61908 29.154427 -64.708771 49.852028 61909 33.383949 -63.518921 49.112885 61910 41.303268 -63.639771 50.602905 61911 42.217972 -63.562897 49.656723 61912 3.995148 -65.867981 49.355217 61913 4.851036 -66.156158 48.899185 61914 17.302376 -64.494553 50.291374 61915 17.986855 -64.070511 50.105904 61916 21.178772 -64.844788 50.143944 61917 22.204819 -64.980194 49.592201 61918 32.728806 -65.913010 49.968857 61919 33.888565 -65.698212 51.151909 61920 33.115486 -66.846313 50.577812 61921 32.422318 -64.945847 49.044441 61922 18.016815 -65.515778 48.616592 61923 17.573494 -65.811768 49.170128 61924 23.021164 -65.586304 49.967178 61925 23.953445 -66.040451 49.928802 61926 25.002831 -65.981506 49.273499 61927 27.611343 -65.705261 49.176155 61928 27.173309 -66.609604 49.772163 61929 40.299744 -67.049637 49.219910 61930 5.873085 -68.157898 48.555893 61931 4.821686 -68.761597 49.229607 61932 5.694466 -69.255966 48.697975 61933 17.255730 -67.235489 50.248146 61934 19.196960 -67.793488 49.904961 61935 21.174431 -68.026596 48.950035 61936 25.957176 -66.851624 50.131203 61937 32.349823 -66.814667 49.797371 61938 32.598312 -67.758438 49.606491 61939 20.285851 -67.884979 49.385063 61940 39.867859 -68.027328 48.851669 61941 38.857262 -67.889618 50.012604 61942 39.497246 -66.805023 50.433823 61943 7.031677 -69.125885 48.039612 61944 22.067039 -68.798752 49.461166 61945 21.111084 -68.492691 49.751160 61946 20.447937 -68.672760 50.458229 61947 19.440651 -69.513672 51.684677 61948 23.351425 -68.950500 48.634308 61949 33.471359 -68.353195 49.530113 61950 35.911240 -68.562805 49.458168 61951 6.463852 -70.281006 48.226891 61952 24.928009 -69.758148 48.533081 61953 23.943329 -69.886246 49.641129 61954 22.984985 -69.436035 49.769073 61955 21.275620 -69.485367 51.182991 61956 21.753098 -70.463608 52.159653 61957 25.881042 -70.163605 48.258575 61958 33.522949 -67.698517 50.572975 61959 33.472618 -68.138184 50.105446 61960 37.003296 -70.234467 47.897736 61961 37.203094 -69.443710 48.774414 61962 39.386971 -65.860199 51.375587 61963 37.665558 -67.175690 51.675003 61964 6.688545 -71.099289 47.893173 61965 26.041992 -70.915543 49.139008 61966 24.863716 -70.411224 49.709709 61967 26.193161 -72.014603 50.587585 61968 38.303894 -69.762344 48.432251 61969 20.327927 -72.705978 49.018974 61970 21.209824 -72.816452 48.439285 61971 21.965584 -73.505035 48.588448 61972 27.289612 -73.299896 50.551712 61973 22.610855 -74.659042 47.967232 61974 6.492981 -75.253876 49.887466 61975 6.555855 -75.296112 48.644241 61976 5.961098 -73.855423 49.677994 61977 22.543823 -74.289673 48.989029 61978 19.206573 -74.588257 49.801460 61979 28.356697 -74.406052 49.304886 61980 18.727158 -76.413116 49.789726 61981 24.255310 -76.155151 49.651062 61982 24.209274 -76.346008 49.014091 61983 23.334656 -75.511642 49.148674 61984 25.091110 -75.908646 50.550926 61985 25.866714 -75.278732 51.404495 61986 27.009064 -75.325500 50.240952 61987 25.302956 -76.538177 49.129501 61988 9.525627 -79.627762 47.772072 61989 17.897552 -78.978943 48.744888 61990 18.246048 -78.221893 49.088165 61991 10.490845 -80.167679 47.836861 61992 17.184677 -79.712540 47.935753 61993 17.147598 -79.272827 49.066605 61994 11.314774 -80.493408 47.645248 61995 15.761620 -80.107071 48.344757 61996 14.795624 -80.049911 48.965591 61997 7.538574 39.227478 56.146118 61998 10.777756 39.924683 55.831757 61999 11.004890 39.371216 56.206299 62000 12.046158 38.600372 56.122467 62001 6.475594 38.285202 56.627731 62002 13.482620 38.390289 55.749649 62003 7.633163 38.626282 56.852356 62004 4.765144 36.374802 57.804779 62005 13.351120 37.517212 55.884720 62006 11.495071 36.531281 56.031311 62007 12.724533 37.556229 56.045654 62008 4.082420 35.141235 56.059204 62009 4.207359 32.413727 55.865952 62010 10.128723 33.429520 56.769928 62011 9.167953 35.160034 58.037323 62012 9.029778 36.289474 57.686401 62013 10.642746 32.800339 55.224930 62014 4.360268 32.900726 56.816391 62015 4.641693 31.708618 56.881927 62016 12.229271 31.555267 56.594330 62017 13.397362 30.774048 55.985779 62018 4.487389 28.613129 56.450348 62019 4.298454 28.118378 56.409088 62020 14.743233 30.194260 55.798950 62021 17.548042 29.885529 57.034851 62022 16.726509 30.124191 57.835663 62023 22.675262 28.283783 55.732941 62024 4.106125 27.405182 55.443069 62025 23.114151 28.073914 56.469193 62026 24.037827 27.276077 56.550385 62027 23.214989 27.330933 57.489380 62028 24.932938 26.519012 56.286957 62029 24.559814 26.841629 56.494583 62030 3.921654 22.870316 58.848770 62031 3.990143 21.832123 58.179245 62032 25.531044 25.748962 56.301788 62033 26.156441 24.976807 55.769745 62034 25.943375 25.150742 56.527496 62035 4.063118 24.047882 57.593567 62036 25.895058 24.496521 56.712921 62037 4.163124 20.893723 56.976349 62038 6.085098 21.641510 54.452148 62039 26.099655 22.591644 55.724792 62040 31.906725 21.043549 55.225983 62041 32.840309 21.751892 54.822388 62042 31.130272 21.140808 54.763962 62043 31.045052 20.826492 55.347260 62044 33.475456 20.382370 55.080963 62045 34.273186 19.090302 54.594933 62046 33.216599 18.316360 55.167801 62047 32.163071 19.538452 56.212433 62048 31.063965 20.455521 55.950684 62049 4.121346 19.741577 55.472870 62050 24.749519 20.959534 56.241760 62051 25.383904 21.821289 56.308197 62052 30.991180 19.989777 56.764832 62053 34.479095 19.807465 54.761276 62054 3.582741 18.765106 58.124695 62055 17.361740 18.064514 55.084656 62056 17.111145 18.061401 55.338470 62057 17.536385 18.524200 55.548279 62058 23.451111 19.145935 55.194443 62059 22.518356 19.595947 56.524750 62060 3.159294 16.289688 54.915962 62061 17.175537 17.986755 55.994507 62062 26.528992 17.201920 55.425140 62063 27.369713 18.224426 56.459229 62064 26.386337 17.406830 56.721405 62065 33.202461 16.863312 55.233154 62066 24.991684 15.900085 55.285400 62067 24.492035 15.275940 54.979286 62068 24.067764 13.505157 55.085449 62069 23.577271 13.521210 54.603661 62070 24.415337 14.467651 55.536621 62071 35.364120 15.487106 56.207794 62072 36.469864 14.864288 56.319870 62073 36.639877 14.732666 57.607620 62074 4.915375 12.847107 55.600830 62075 5.725082 12.867355 54.602592 62076 38.659546 12.386475 57.104172 62077 6.734383 12.631851 54.051941 62078 18.569641 13.635925 55.200943 62079 19.691612 13.138535 56.056137 62080 23.226486 12.620667 54.149818 62081 23.677116 12.792999 54.527496 62082 21.496284 12.677078 57.593109 62083 20.741257 11.585846 56.421127 62084 7.559349 10.113556 54.327911 62085 26.766235 13.505508 57.021820 62086 28.309265 12.547699 56.764923 62087 29.440071 10.111420 56.229218 62088 28.798065 9.191483 56.275452 62089 41.151917 10.322693 55.799469 62090 7.231033 9.397873 54.518738 62091 42.479034 9.161697 54.730949 62092 2.717407 6.585709 53.764244 62093 2.391457 5.614105 54.710114 62094 20.838387 8.714691 54.566704 62095 21.860657 8.740112 55.673080 62096 21.990570 6.727524 55.110764 62097 22.585892 7.275177 56.520630 62098 27.185188 7.267792 56.697845 62099 27.521408 7.839767 55.851578 62100 27.875031 8.279144 56.952576 62101 27.668274 7.911591 54.951599 62102 41.959702 8.452133 54.855484 62103 2.381416 4.841019 54.082962 62104 21.956169 5.995544 55.041443 62105 26.895523 6.807617 55.225128 62106 37.372055 6.233459 55.071411 62107 36.295715 5.161758 55.225159 62108 36.173203 6.877960 56.006790 62109 37.165649 5.434219 54.409233 62110 36.763474 4.622513 54.195099 62111 38.871964 6.695847 55.094269 62112 39.390312 7.410934 55.988525 62113 2.609665 4.353638 53.949570 62114 21.811172 5.502548 56.058167 62115 26.398697 4.428787 54.154915 62116 38.018944 7.358887 56.167023 62117 3.005730 3.973618 53.906906 62118 35.765198 4.949966 56.174744 62119 36.279091 3.872101 55.748245 62120 36.331474 3.210602 54.445419 62121 43.384872 2.959610 54.713867 62122 27.021240 3.523705 54.139214 62123 27.943130 2.912193 54.333900 62124 44.524292 2.978607 54.465775 62125 20.264091 2.906563 54.071915 62126 28.549911 2.758301 55.310242 62127 29.038696 1.951797 54.353333 62128 36.121353 2.000366 54.182831 62129 41.783661 2.323120 55.018219 62130 44.415375 2.608398 54.906052 62131 20.307930 2.353027 54.979088 62132 40.191833 1.439316 54.978149 62133 29.611481 1.059357 54.773178 62134 36.502731 1.239105 54.465019 62135 36.309326 2.114609 54.714485 62136 37.279434 0.337875 54.382950 62137 36.898888 0.876160 55.428604 62138 45.398956 0.356644 55.423584 62139 4.350868 -0.537964 54.965111 62140 3.416527 -1.445923 54.516159 62141 37.627167 0.288971 55.498322 62142 24.493088 -0.901871 54.360550 62143 23.942368 -2.876938 55.024078 62144 24.754974 -1.572540 55.483719 62145 47.617142 -2.872162 54.322899 62146 47.106155 -1.716431 54.439552 62147 46.679565 -1.722977 54.919693 62148 46.556000 -0.304184 54.498184 62149 27.471130 -3.986725 53.939789 62150 47.070374 -2.602905 54.824875 62151 43.140625 0.084198 57.240906 62152 44.003418 0.110855 56.702316 62153 44.768768 -1.203079 56.433060 62154 2.598374 -3.459061 56.260712 62155 2.687142 -2.613586 55.320908 62156 2.603279 -2.087692 56.536621 62157 24.267097 -7.671478 55.412109 62158 25.246094 -7.579208 57.118347 62159 24.250076 -6.948608 57.094543 62160 47.039474 -3.915298 55.030853 62161 22.395493 -4.976913 53.813477 62162 31.528557 -4.871246 54.183960 62163 30.696251 -4.692413 54.884155 62164 32.340012 -4.834732 54.416183 62165 32.252388 -5.190430 53.775711 62166 22.242172 -6.089890 53.667816 62167 22.741249 -5.895798 54.811340 62168 6.176216 -6.446762 53.343384 62169 10.750443 -7.046906 55.574341 62170 10.183861 -6.397400 54.624588 62171 38.318909 -6.407883 54.921188 62172 37.050079 -6.585754 55.223724 62173 38.850800 -6.477676 53.740463 62174 42.409180 -6.366180 54.259613 62175 32.991669 -4.823441 55.134277 62176 34.154831 -5.405243 55.455322 62177 43.705475 -6.771210 54.051361 62178 25.123917 -8.614426 53.423477 62179 26.225380 -8.489426 53.910133 62180 30.094727 -10.203033 53.368797 62181 30.380920 -9.307373 54.817810 62182 45.133362 -7.225235 54.240776 62183 45.861526 -8.018387 53.965469 62184 11.328377 -8.920685 53.421608 62185 11.114388 -9.923111 52.957848 62186 25.028610 -8.284256 54.419304 62187 29.212341 -8.170517 55.762421 62188 30.921997 -8.405731 56.470840 62189 46.359192 -8.495361 53.672325 62190 49.965424 -8.942200 53.726723 62191 48.190079 -9.395416 53.705971 62192 48.360138 -8.434113 54.434654 62193 49.143127 -9.395966 53.680161 62194 9.463806 -10.262939 53.817139 62195 8.247971 -10.130707 54.419106 62196 8.352936 -11.513199 53.785820 62197 10.462585 -10.523804 53.053482 62198 9.604370 -11.797104 52.955444 62199 30.758591 -11.220810 52.732246 62200 36.459686 -10.683487 54.021683 62201 10.389374 -11.198273 52.569862 62202 31.069916 -10.702896 53.852371 62203 31.726038 -11.190948 54.284538 62204 31.665071 -10.539795 55.103424 62205 35.085907 -11.076660 54.033134 62206 35.292664 -11.297318 55.508545 62207 33.934448 -11.555466 54.807983 62208 32.554657 -11.440720 55.017242 62209 9.213028 -13.963089 52.654129 62210 45.098251 -11.336655 55.918350 62211 44.501709 -10.977600 55.672897 62212 9.073555 -14.506592 53.691360 62213 43.683670 -16.587219 54.035309 62214 49.520126 -17.463348 53.455383 62215 51.707108 -18.180649 53.806969 62216 51.151794 -17.661087 53.763100 62217 10.150833 -18.755859 52.719566 62218 35.191483 -19.171951 54.115135 62219 35.488007 -18.565323 53.529045 62220 34.404259 -19.404129 52.922821 62221 37.302948 -17.797363 54.229668 62222 41.577545 -17.646317 52.798676 62223 47.915070 -18.202209 55.522522 62224 49.331451 -18.351288 55.410522 62225 34.384026 -20.686859 53.082008 62226 3.675728 -21.738129 51.581650 62227 2.293335 -19.585632 53.933777 62228 1.709694 -18.295975 55.734467 62229 1.707222 -20.780579 55.282669 62230 9.062920 -20.303421 52.238594 62231 8.988640 -20.286316 52.585915 62232 9.367172 -20.189438 52.475296 62233 9.757576 -19.554886 52.562920 62234 47.202545 -18.892014 53.311012 62235 2.942764 -20.450897 52.811867 62236 9.201447 -20.405945 52.503372 62237 39.841454 -22.431015 52.591942 62238 40.748566 -21.959641 53.485588 62239 2.787575 -23.623535 52.602097 62240 39.395844 -23.546539 52.452232 62241 4.717560 -24.603577 51.771439 62242 35.811546 -22.060181 53.815903 62243 36.352448 -23.942307 54.116104 62244 51.143158 -18.199905 54.026878 62245 39.700592 -25.080078 53.498207 62246 40.156631 -23.165756 53.106422 62247 40.339874 -23.922302 53.335373 62248 39.926865 -23.966949 52.961288 62249 33.690308 -26.575348 53.221298 62250 34.662918 -25.609253 52.841072 62251 35.582787 -25.545212 53.987167 62252 38.238556 -25.914230 52.670120 62253 51.141418 -25.387909 53.328865 62254 50.306503 -25.918884 53.615646 62255 50.262589 -25.363800 54.343002 62256 51.948273 -24.838974 53.270164 62257 50.350067 -26.000916 53.174477 62258 8.187500 -27.059402 52.715027 62259 9.024345 -27.627884 52.748199 62260 32.715454 -26.762878 52.396317 62261 31.493301 -27.570145 52.725235 62262 32.718155 -27.269272 53.457741 62263 35.717102 -28.188507 53.013390 62264 37.187729 -26.911362 52.839325 62265 47.763550 -27.656204 54.723709 62266 30.423660 -27.884460 52.321915 62267 30.139923 -28.104965 53.080086 62268 28.604958 -28.292404 53.760529 62269 46.374619 -28.146698 52.799332 62270 10.822792 -28.731293 52.805817 62271 34.576401 -28.665085 52.453499 62272 33.732918 -29.269653 52.664352 62273 36.754204 -27.713684 53.695534 62274 3.890892 -31.579880 50.528648 62275 12.329590 -30.141769 51.704742 62276 28.507935 -29.827301 52.236313 62277 30.633835 -30.153152 52.247406 62278 44.510071 -32.017151 56.401306 62279 45.788300 -30.640900 55.901566 62280 44.588760 -30.930878 54.680687 62281 44.841095 -29.813400 53.036438 62282 51.624634 -30.063217 52.729233 62283 50.688202 -30.153992 52.555977 62284 52.291824 -32.006958 52.733681 62285 28.026680 -30.497360 53.235626 62286 28.014114 -29.855759 52.739868 62287 29.221817 -30.449020 52.594215 62288 27.288834 -29.853058 53.718178 62289 11.553535 -31.792114 51.635376 62290 40.093811 -31.744476 52.276680 62291 39.600418 -32.386383 52.988533 62292 40.859024 -32.046646 53.165131 62293 42.189621 -31.499451 53.070183 62294 43.107208 -31.308182 53.387405 62295 10.412506 -32.346939 52.380951 62296 38.526855 -32.501236 52.276787 62297 38.655838 -33.012039 53.245842 62298 47.536682 -32.735626 53.404785 62299 51.570953 -30.631500 53.076614 62300 5.969116 -34.108490 52.482269 62301 36.643700 -33.516632 52.242752 62302 36.604492 -34.034531 53.163940 62303 6.858376 -35.860840 51.483734 62304 6.097778 -35.340408 51.854889 62305 7.689865 -36.221283 51.434250 62306 34.717896 -34.554947 52.143990 62307 34.483932 -35.179504 52.949348 62308 40.779327 -35.343292 52.251068 62309 43.537415 -35.215729 53.114105 62310 42.122543 -35.056519 52.208405 62311 44.163269 -34.640625 52.164421 62312 6.208130 -36.207428 52.046806 62313 32.760551 -35.584167 51.955536 62314 38.249115 -36.133224 51.917252 62315 6.978348 -36.451874 51.875717 62316 8.804855 -36.832016 51.538704 62317 25.690720 -37.815521 51.365616 62318 29.284393 -36.891541 52.903946 62319 30.354080 -36.516266 52.053444 62320 31.767954 -36.290115 52.229843 62321 35.953445 -37.301498 51.571815 62322 38.617950 -37.834137 53.856285 62323 38.519333 -38.727066 53.733551 62324 37.758972 -38.431168 53.189995 62325 37.134491 -36.864227 51.976204 62326 50.773178 -36.534622 52.162071 62327 10.092453 -37.762848 52.142303 62328 11.269241 -37.895767 51.198235 62329 35.550354 -38.355225 51.709801 62330 34.804794 -38.485504 51.191437 62331 38.230743 -37.031097 52.893921 62332 51.020935 -36.850662 52.178383 62333 26.308525 -37.317825 52.810959 62334 25.440796 -38.838364 52.361488 62335 25.902252 -38.555252 53.759872 62336 5.582016 -43.280136 53.696129 62337 6.073608 -42.575089 53.156593 62338 6.250290 -43.976074 53.219254 62339 11.295853 -38.845139 52.256516 62340 41.379333 -39.511383 51.624275 62341 41.345840 -39.700668 52.313965 62342 49.965698 -39.962433 54.634216 62343 49.495911 -38.375854 55.919159 62344 50.428802 -37.928665 54.772224 62345 4.557053 -41.193680 50.840981 62346 8.866088 -41.518906 50.516579 62347 24.896362 -40.415665 51.974831 62348 28.180679 -41.372833 51.791252 62349 37.109306 -39.581177 51.888412 62350 42.390945 -39.778351 52.159882 62351 42.950729 -40.122391 53.765526 62352 43.955658 -40.067688 52.415161 62353 45.110275 -40.437027 52.906525 62354 45.951981 -40.197540 52.121758 62355 48.070572 -40.537292 52.082962 62356 52.494324 -40.542709 51.615822 62357 4.088669 -42.103409 51.514015 62358 7.762848 -40.380524 50.451378 62359 7.503067 -41.391830 51.638626 62360 7.102249 -41.901398 52.241524 62361 6.382149 -40.969086 51.511681 62362 12.601784 -41.138321 52.078758 62363 12.386139 -42.292023 52.722687 62364 24.276291 -41.623535 51.416466 62365 27.718430 -42.611938 51.801445 62366 32.556572 -41.823975 51.629356 62367 31.335808 -41.155472 52.333794 62368 52.101700 -39.841080 52.395454 62369 8.352645 -42.199326 51.438416 62370 7.608116 -43.192780 52.473351 62371 22.775352 -43.863235 51.552673 62372 23.563568 -42.843414 51.067307 62373 29.191826 -40.588409 52.007919 62374 2.271507 -43.898636 50.827583 62375 2.434219 -43.567566 51.548592 62376 2.117554 -43.938812 51.350159 62377 14.019699 -43.640671 50.216797 62378 27.794556 -44.526031 52.638313 62379 35.218391 -42.518219 52.320091 62380 45.945633 -44.609344 51.403976 62381 45.857483 -45.667862 52.058838 62382 46.981018 -45.194122 52.148262 62383 51.418152 -40.132004 53.028748 62384 8.928093 -46.803391 50.691902 62385 9.067916 -45.242188 51.049332 62386 11.596008 -47.208496 51.463867 62387 21.794167 -44.590256 52.289261 62388 21.176193 -45.545471 52.440819 62389 20.854614 -44.991119 53.579086 62390 21.975510 -44.539764 51.222351 62391 21.651810 -45.272629 51.262604 62392 23.853935 -43.110291 52.310448 62393 23.291611 -43.633987 53.219589 62394 40.301727 -45.572693 52.089905 62395 49.955170 -44.434891 51.662544 62396 2.226517 -44.467285 51.319382 62397 9.635452 -47.388824 50.728531 62398 27.136024 -46.384033 52.133911 62399 41.202774 -50.390335 52.089134 62400 49.134033 -46.901031 51.364906 62401 2.220390 -45.612625 50.933746 62402 8.726685 -43.623520 51.560928 62403 6.266449 -45.569031 52.307877 62404 6.908791 -44.631882 52.798141 62405 7.706405 -44.925415 52.197227 62406 13.069305 -45.272858 52.344536 62407 12.314484 -46.306778 52.690033 62408 21.636887 -46.011749 51.338554 62409 38.144501 -46.709412 52.297195 62410 2.339867 -46.485992 50.232849 62411 3.090271 -47.375641 50.316177 62412 3.427544 -46.456329 51.579491 62413 4.125572 -46.465927 51.854301 62414 4.131943 -46.756958 51.475998 62415 4.148499 -47.325653 50.794785 62416 8.002975 -47.288925 50.742287 62417 7.783737 -46.281982 51.274445 62418 8.308243 -44.148315 52.052109 62419 8.798706 -47.566299 50.794525 62420 10.418869 -47.485718 50.773247 62421 10.848763 -47.641983 51.053505 62422 24.035179 -47.369629 52.919556 62423 22.523430 -47.011398 52.985458 62424 25.797195 -47.348999 52.175018 62425 24.615875 -47.052429 51.700623 62426 7.910705 -47.963531 50.874451 62427 7.784454 -48.559387 51.429901 62428 9.613449 -47.924057 51.737770 62429 8.646454 -48.093246 53.119789 62430 9.588409 -47.711502 53.436203 62431 3.074661 -51.321747 50.427811 62432 3.551087 -50.802078 51.040443 62433 6.706291 -49.136261 51.250771 62434 35.929382 -50.030823 51.315628 62435 41.380386 -52.298172 52.234848 62436 40.943481 -51.492691 52.082886 62437 41.237564 -49.264313 51.685410 62438 4.196663 -50.164398 51.324142 62439 45.677872 -48.821152 51.891426 62440 2.619362 -53.285492 49.668457 62441 2.741776 -52.330276 50.195427 62442 9.785844 -52.479004 51.582321 62443 32.936775 -52.447693 51.179314 62444 33.840561 -52.315903 51.933502 62445 44.873932 -51.010117 51.443893 62446 44.945801 -51.965118 51.794609 62447 3.207825 -53.291275 50.894943 62448 30.298660 -53.722916 52.299408 62449 31.369141 -53.519226 53.021439 62450 46.476196 -53.229141 51.423782 62451 43.902863 -52.048660 52.847656 62452 45.335785 -53.197250 52.003510 62453 44.425949 -53.199982 52.587692 62454 3.553093 -53.408691 51.955940 62455 4.355484 -53.708130 51.632454 62456 4.001297 -54.114487 50.320770 62457 12.582260 -53.050903 51.647751 62458 22.025009 -54.282120 50.777824 62459 21.464874 -55.080475 50.515305 62460 21.105644 -54.687943 51.327553 62461 22.904388 -53.520081 51.582275 62462 28.944588 -53.846054 51.529861 62463 47.200958 -53.841675 50.892654 62464 21.636337 -54.032730 51.836830 62465 34.024094 -55.536133 51.123055 62466 36.806000 -55.056442 51.907242 62467 36.915810 -55.140778 52.645035 62468 36.168236 -55.209839 52.851608 62469 36.537033 -55.024689 51.003304 62470 46.263397 -54.093185 51.489586 62471 10.018204 -56.317871 50.169449 62472 21.461403 -55.966492 50.416588 62473 20.886169 -55.424683 50.970947 62474 20.666809 -55.338821 51.717163 62475 20.556488 -56.309219 51.502373 62476 45.649826 -55.016266 50.961777 62477 45.497849 -55.616196 50.258728 62478 46.554596 -54.814545 50.811432 62479 9.064377 -56.897354 50.025002 62480 22.045456 -58.549210 50.503647 62481 27.604492 -57.308563 50.751312 62482 28.363632 -57.277542 50.491798 62483 29.372215 -57.390823 50.782234 62484 30.448044 -57.113022 50.512550 62485 31.231110 -57.175705 51.585457 62486 21.325195 -58.479584 50.433548 62487 21.411674 -58.997406 50.343597 62488 21.064163 -59.020035 50.753517 62489 7.047577 -59.411636 49.694992 62490 7.884864 -59.114685 49.232391 62491 6.162270 -58.299469 50.827072 62492 5.824944 -59.416901 50.097435 62493 20.667053 -58.344498 51.321274 62494 20.354980 -57.401184 51.761063 62495 21.670135 -58.890991 50.309288 62496 21.678284 -59.420212 50.791237 62497 22.680023 -59.556213 51.276764 62498 37.194702 -58.796951 51.425446 62499 37.100159 -59.655029 50.920685 62500 36.341454 -59.039261 51.131653 62501 37.595383 -60.410599 51.651306 62502 37.004410 -60.790588 50.818169 62503 41.530243 -58.200073 50.791862 62504 4.199844 -58.530075 51.078354 62505 3.726975 -57.849136 52.308296 62506 3.235443 -58.721359 51.794067 62507 4.464760 -60.324829 49.737755 62508 4.862175 -59.365463 50.272255 62509 3.810982 -59.501984 50.543282 62510 5.278969 -60.224716 49.684891 62511 7.236755 -57.857910 50.717117 62512 8.157288 -60.105698 48.773384 62513 21.100540 -59.571014 51.270004 62514 33.059799 -61.062927 50.612289 62515 31.700052 -63.639359 51.793068 62516 34.060318 -61.105499 52.426758 62517 35.244812 -59.640991 50.940361 62518 3.792725 -60.384171 49.875610 62519 33.731674 -63.136215 54.709511 62520 34.624557 -61.675430 54.815353 62521 32.409592 -64.027267 53.321533 62522 44.631165 -61.059189 50.152222 62523 2.707504 -61.086639 50.923737 62524 2.869354 -62.383377 50.565666 62525 35.635803 -62.374435 50.449249 62526 36.548538 -61.444260 50.610016 62527 3.173966 -60.313477 50.409332 62528 2.905396 -59.531326 51.247902 62529 3.709869 -64.700500 49.808014 62530 30.549065 -62.602005 49.816406 62531 42.924011 -60.976456 51.925026 62532 17.133148 -65.381149 49.726730 62533 18.347420 -64.156830 50.662621 62534 28.334351 -65.433105 49.402267 62535 29.852448 -63.536163 49.858421 62536 34.409805 -63.315750 50.058548 62537 36.224922 -62.749359 51.526337 62538 35.664307 -63.236755 51.265976 62539 40.849396 -64.039261 50.775772 62540 41.864288 -62.687439 51.520012 62541 2.864594 -63.190964 50.735825 62542 16.434418 -65.474075 50.604599 62543 20.348358 -64.341034 49.746658 62544 28.666122 -65.944427 50.066841 62545 33.823761 -64.474289 50.401886 62546 3.266441 -63.841858 50.268051 62547 3.590187 -65.801102 50.046623 62548 16.050735 -65.272430 51.476494 62549 17.109779 -65.064896 51.471252 62550 27.966354 -66.245987 49.700096 62551 24.806076 -66.533936 50.162498 62552 29.546814 -66.277527 51.241737 62553 28.066170 -66.760544 50.306236 62554 28.223091 -67.287552 50.820457 62555 4.181076 -67.136414 49.925430 62556 15.686249 -66.545578 50.722824 62557 34.514633 -68.080627 50.350807 62558 38.725906 -68.937134 48.928307 62559 37.374901 -68.463409 50.071014 62560 4.277260 -68.931259 49.901352 62561 5.065727 -70.183945 49.524796 62562 4.255295 -69.678329 50.777397 62563 5.316437 -71.729721 49.730675 62564 4.905632 -70.918747 51.081894 62565 28.524429 -73.536911 48.745880 62566 13.066132 -73.792313 49.568222 62567 13.871246 -73.052383 50.187431 62568 13.935509 -74.348404 49.530830 62569 19.635330 -72.706299 49.117836 62570 28.346039 -73.663345 49.425888 62571 12.845100 -72.139160 49.989120 62572 12.951485 -72.900467 49.777397 62573 12.126724 -72.733719 50.357346 62574 12.114883 -73.961288 50.328453 62575 13.635117 -74.760818 49.189217 62576 19.715408 -73.178009 49.529892 62577 21.282440 -73.218109 49.333588 62578 22.038361 -73.746323 49.451942 62579 22.588516 -74.681747 50.114166 62580 12.183701 -74.752594 50.167969 62581 12.978989 -74.990540 49.493118 62582 6.105507 -74.013367 51.110886 62583 13.702438 -75.278549 49.149834 62584 14.107910 -75.202744 49.385811 62585 20.418625 -73.520172 49.977821 62586 27.654198 -74.301178 50.377251 62587 13.165565 -76.270660 49.800842 62588 12.617615 -76.268021 50.283020 62589 12.428382 -75.468445 50.195518 62590 13.794800 -75.759216 49.387306 62591 26.740967 -74.382965 51.229935 62592 7.525528 -76.915573 49.073753 62593 8.904755 -78.500153 49.143127 62594 10.172592 -79.563278 48.917900 62595 11.020309 -80.143890 48.490585 62596 6.584709 37.714233 57.517685 62597 6.989456 36.707825 58.702240 62598 9.930161 38.598892 56.917816 62599 9.091034 38.498840 57.004974 62600 10.722047 38.444580 56.597717 62601 10.136658 37.672852 56.967560 62602 10.076653 36.267059 56.806107 62603 4.575295 35.632172 57.800140 62604 9.380310 37.344482 57.321899 62605 7.920990 37.277054 57.973663 62606 8.623276 37.677368 57.511505 62607 10.244157 33.549225 57.567535 62608 9.733070 34.356308 58.068817 62609 4.377785 33.966782 57.387787 62610 13.479904 31.475159 58.814774 62611 12.332626 32.128418 58.713654 62612 13.183167 31.464478 57.640503 62613 4.798584 32.740173 58.181244 62614 4.651718 30.137451 56.945633 62615 14.047653 31.012970 57.218140 62616 14.657837 30.911392 58.429871 62617 18.988449 29.633759 57.688370 62618 18.359390 29.865860 57.474899 62619 18.602448 29.271454 56.460754 62620 4.606667 29.115875 56.400635 62621 21.784256 28.664093 56.485260 62622 20.222008 28.973557 57.136688 62623 22.420685 28.157043 57.348328 62624 21.497147 28.282700 57.664429 62625 3.909210 26.428619 57.551971 62626 3.971085 25.359833 57.350861 62627 13.162757 25.140152 56.516693 62628 12.939354 25.110321 56.639679 62629 13.041077 25.349945 56.744614 62630 13.409691 25.271759 56.763016 62631 13.249847 24.956177 56.761963 62632 25.912460 23.437180 56.577454 62633 24.176743 20.124908 55.908417 62634 4.649025 20.975189 55.901489 62635 25.540298 22.740677 56.976562 62636 28.777275 19.281006 56.273682 62637 29.186081 18.953583 58.656769 62638 28.719162 19.372253 57.550735 62639 30.045975 19.592987 57.525345 62640 30.183304 20.123932 56.354889 62641 17.667152 18.911957 56.350571 62642 18.497437 19.325867 56.351410 62643 18.009705 19.371017 56.643768 62644 21.510742 19.250656 56.219101 62645 23.392593 20.066010 56.728989 62646 32.322571 18.332214 58.216888 62647 33.599098 17.094894 58.563431 62648 32.669128 17.665176 59.235260 62649 4.076035 13.961487 55.579987 62650 17.314377 17.516769 56.764526 62651 32.947517 17.748138 56.158600 62652 25.734306 16.663757 56.943100 62653 25.351646 16.156738 56.654434 62654 25.532028 16.478302 56.033722 62655 3.454910 14.424026 57.364609 62656 24.949226 14.383774 56.260162 62657 25.028641 15.417160 56.132233 62658 34.690292 16.159439 56.732986 62659 35.666977 15.616333 57.155777 62660 18.044235 17.032654 57.326065 62661 19.163574 15.780167 57.121429 62662 17.959656 16.137787 56.439423 62663 4.087624 13.149628 56.618668 62664 5.901642 12.245850 55.360443 62665 6.558144 12.177368 54.810242 62666 24.822327 13.530792 55.860931 62667 40.235474 11.645874 55.846161 62668 5.665718 11.890106 56.015594 62669 4.786110 11.665863 56.884247 62670 25.726898 12.864548 55.982330 62671 29.707970 11.658203 56.714020 62672 29.789429 11.224426 57.791687 62673 30.207603 11.442627 57.190872 62674 7.339439 10.433777 55.159698 62675 7.265526 9.725815 55.526047 62676 7.497437 9.672043 55.009644 62677 6.600212 11.405792 55.497131 62678 6.678734 10.248138 55.970978 62679 30.301048 11.387131 56.855804 62680 30.239929 11.109528 56.576263 62681 20.834381 10.071945 55.529678 62682 28.227478 8.517776 55.681213 62683 41.933014 9.485916 55.400452 62684 41.283234 9.681152 56.067764 62685 41.191620 8.925156 55.881088 62686 5.995041 8.665161 55.745590 62687 28.394440 8.883896 56.725006 62688 3.179848 6.890671 55.056839 62689 37.029434 7.802277 56.918579 62690 36.934219 8.517136 57.967300 62691 38.112907 8.490555 57.399872 62692 40.174088 8.698303 56.457291 62693 2.505692 5.923126 56.192047 62694 3.195786 7.067322 56.308105 62695 21.502220 10.675201 56.529877 62696 26.782753 6.296082 56.799622 62697 26.661148 5.699081 57.056519 62698 26.733650 5.355789 56.257568 62699 34.825684 6.848694 56.215256 62700 35.103470 6.100647 56.410477 62701 34.420311 6.890335 56.702377 62702 35.206154 6.846344 56.072647 62703 39.926849 7.887894 56.232025 62704 2.746887 4.320236 54.727036 62705 2.384575 4.888855 54.824432 62706 22.673782 6.247711 58.230103 62707 21.891052 4.896965 59.256195 62708 22.614410 5.580299 59.428391 62709 3.532684 3.748383 54.839897 62710 27.347107 3.946289 55.559143 62711 36.089874 4.357620 56.669983 62712 36.417252 4.222839 57.544479 62713 36.656906 3.321198 56.779449 62714 29.441498 1.901688 55.464874 62715 29.785423 1.099731 56.241714 62716 29.863693 1.080261 55.428497 62717 36.580246 2.196228 55.594055 62718 44.370544 1.801254 55.371155 62719 7.832778 1.017090 55.425964 62720 8.107552 1.704773 54.480446 62721 8.222961 2.007431 55.734863 62722 36.877243 1.405167 56.191254 62723 37.087273 1.959412 57.048691 62724 39.464279 0.643570 55.901459 62725 41.550415 1.763718 55.831512 62726 40.772781 1.237717 56.416534 62727 46.035858 -1.389526 55.413574 62728 7.397629 0.917343 56.567154 62729 6.531136 0.713638 56.929306 62730 6.512245 0.266769 55.168945 62731 24.739685 -0.130600 55.194977 62732 28.603088 -1.597961 55.680740 62733 29.533646 0.163208 55.504608 62734 38.817062 0.179779 56.787018 62735 37.982147 0.190094 56.485748 62736 38.503311 0.194443 55.793213 62737 44.272690 0.602219 56.187958 62738 42.989624 0.949036 56.793121 62739 5.305557 -0.373947 54.508049 62740 27.820786 -2.713882 54.879349 62741 28.285355 -3.067505 55.819199 62742 28.055634 -3.897308 54.756958 62743 45.875031 -2.504669 55.833893 62744 46.568542 -2.650314 55.288513 62745 23.209534 -3.920532 54.573265 62746 46.191711 -3.498032 55.588593 62747 31.671328 -4.375626 55.791351 62748 47.165619 -5.666336 55.093491 62749 45.994034 -6.473038 55.063019 62750 45.750168 -4.776917 55.549347 62751 48.355804 -4.769943 54.273926 62752 8.315765 -5.716812 55.141724 62753 6.949616 -5.757401 55.188751 62754 7.878006 -5.244812 57.200684 62755 6.011742 -6.035019 54.596817 62756 9.294937 -5.842590 55.278839 62757 23.230110 -4.969147 55.507767 62758 29.021881 -4.431717 55.230377 62759 29.844894 -4.762238 54.886581 62760 3.235077 -5.246826 54.644714 62761 5.265198 -6.083923 54.390259 62762 35.700020 -6.064621 56.717880 62763 36.619949 -6.464035 56.142258 62764 40.842010 -5.958908 55.450272 62765 43.025299 -5.772781 55.322037 62766 44.579910 -5.932068 55.153961 62767 46.348953 -7.783752 54.450134 62768 48.362518 -6.717316 54.727715 62769 36.555176 -6.106293 57.374084 62770 48.622574 -7.642456 54.719093 62771 48.217773 -7.570755 54.879005 62772 23.375916 -6.629242 55.585922 62773 25.891678 -7.950485 55.776245 62774 27.510941 -8.114822 55.341812 62775 47.400162 -7.387039 54.840157 62776 10.598694 -9.691620 53.706558 62777 9.170876 -9.510681 54.781166 62778 10.015701 -9.480087 54.432869 62779 10.681900 -9.093948 54.466812 62780 40.389572 -9.452927 56.782532 62781 40.520203 -9.401535 58.074158 62782 39.036758 -9.813568 57.230576 62783 42.544830 -10.292114 54.779243 62784 41.830139 -9.807556 55.611450 62785 7.080696 -10.893372 54.305046 62786 7.407646 -12.235260 54.059486 62787 7.363754 -9.683868 55.141678 62788 6.451042 -10.103607 54.871834 62789 43.759506 -10.938248 54.744858 62790 8.125061 -12.442795 53.893509 62791 8.703201 -13.101746 53.676109 62792 8.974166 -15.590439 54.298752 62793 9.594757 -16.561447 53.586189 62794 44.815552 -14.811752 56.695129 62795 45.492752 -13.427765 56.779846 62796 45.284210 -13.805038 55.658539 62797 9.956909 -17.677353 53.283218 62798 42.019226 -16.963165 54.331337 62799 42.845154 -16.423401 55.247971 62800 44.392166 -15.526840 54.912315 62801 50.389877 -18.992203 55.033798 62802 36.409012 -18.423874 54.989761 62803 38.637970 -17.374481 54.624313 62804 2.423615 -17.870499 54.343956 62805 5.271317 -18.528015 53.695107 62806 1.682259 -22.151581 57.951981 62807 1.804367 -23.325089 54.924362 62808 9.216461 -20.280670 52.730553 62809 9.130928 -19.819611 53.189232 62810 9.651375 -18.680267 53.696938 62811 9.221878 -19.223022 54.175949 62812 44.319183 -19.919861 54.228958 62813 45.973969 -19.311707 54.061066 62814 46.247681 -18.737640 55.366425 62815 1.883125 -22.302963 53.750359 62816 2.218765 -21.362320 53.293488 62817 36.412430 -21.601669 54.589760 62818 35.884964 -19.690903 54.804222 62819 35.568619 -20.334579 54.349457 62820 41.493820 -20.945969 53.917023 62821 41.202881 -21.224335 53.784645 62822 42.146729 -20.697189 54.177246 62823 2.130257 -22.426727 53.059113 62824 35.029633 -20.396454 53.832603 62825 34.583954 -19.703796 53.617744 62826 40.834564 -23.166641 53.880051 62827 41.524200 -22.297562 54.899750 62828 2.332993 -23.402603 53.257401 62829 41.499893 -23.551956 54.838097 62830 40.800995 -24.102188 53.988701 62831 51.563095 -24.115005 54.190086 62832 2.921288 -25.129135 54.024117 62833 2.391762 -24.352081 53.814308 62834 2.204239 -24.589081 54.534813 62835 3.466950 -24.762222 53.068153 62836 41.990829 -23.869598 55.995453 62837 41.250519 -24.639954 55.129074 62838 38.255470 -26.751587 53.840698 62839 35.219223 -21.946274 53.236572 62840 37.340385 -23.416504 55.152069 62841 37.046989 -21.380478 55.237549 62842 6.421089 -26.315033 53.722679 62843 7.956161 -26.406448 54.113358 62844 33.670715 -27.192566 54.371666 62845 34.636543 -26.502060 54.206970 62846 37.399261 -27.265549 53.692093 62847 46.191833 -29.551910 54.625397 62848 9.861954 -28.046616 52.586754 62849 32.001495 -27.688400 53.604942 62850 48.981659 -25.818054 55.206787 62851 11.377945 -29.531113 53.071175 62852 27.503693 -29.243484 53.115334 62853 27.046051 -28.988403 53.800804 62854 27.524399 -28.636047 53.498146 62855 31.218338 -28.241852 54.145996 62856 34.623047 -29.152023 53.369759 62857 35.250381 -29.237076 54.423859 62858 11.862213 -30.259354 52.782623 62859 30.995819 -30.628967 53.361961 62860 32.680191 -30.076767 53.417938 62861 33.841873 -29.660934 53.599007 62862 12.237564 -30.811188 52.404190 62863 11.958435 -31.024887 52.871254 62864 28.514694 -30.956650 53.559525 62865 29.858429 -31.262558 53.963646 62866 29.091812 -31.099045 53.592590 62867 31.872843 -30.909378 54.443092 62868 50.777710 -30.768555 53.544983 62869 50.897522 -32.620712 54.458130 62870 50.485962 -31.450027 54.226753 62871 51.266876 -31.370834 53.748718 62872 11.519913 -31.524399 52.809280 62873 12.017853 -31.305328 52.382332 62874 43.825287 -30.967361 53.565010 62875 9.146805 -32.529053 53.214943 62876 7.963439 -32.836975 53.043465 62877 40.226120 -33.028656 54.439514 62878 51.729858 -33.460709 53.137093 62879 5.184441 -35.086182 52.345299 62880 4.673836 -34.509918 52.949524 62881 4.650787 -35.676071 52.848778 62882 6.828507 -33.011581 53.258644 62883 37.583473 -33.496689 53.210022 62884 37.491844 -34.028534 54.080719 62885 51.162476 -34.664948 52.952301 62886 50.993469 -33.989273 54.289940 62887 35.576691 -34.679550 53.257027 62888 5.410866 -35.881638 52.315094 62889 33.200851 -36.144272 53.175873 62890 42.287048 -35.605148 53.316139 62891 44.905884 -34.651321 52.948456 62892 6.624069 -36.879684 52.644409 62893 7.755249 -37.178558 52.605034 62894 30.181335 -36.985565 52.850853 62895 30.941940 -36.974930 52.881241 62896 50.970001 -36.688370 52.734863 62897 50.912750 -35.776077 53.241150 62898 8.926193 -37.486694 52.504021 62899 9.519714 -38.084274 53.077332 62900 26.163803 -37.459091 53.668022 62901 31.855188 -36.919968 53.160393 62902 36.256027 -37.670624 52.107147 62903 51.368683 -38.272400 53.168777 62904 50.850159 -36.638626 53.968727 62905 12.098541 -40.025650 52.144920 62906 50.861923 -39.599426 53.816589 62907 48.805695 -37.342346 56.708282 62908 49.710922 -36.887360 56.038925 62909 4.966782 -41.206497 51.508026 62910 11.947342 -40.909683 52.801834 62911 11.248596 -39.895050 53.071388 62912 30.092621 -40.733368 52.586937 62913 30.699677 -41.392624 53.956055 62914 41.311523 -39.805893 53.322899 62915 40.731247 -39.533844 54.605057 62916 39.596558 -39.376968 53.708260 62917 46.060211 -40.658447 53.272530 62918 47.178070 -40.934860 53.683784 62919 5.000847 -41.984680 52.665825 62920 7.812606 -41.136688 51.150734 62921 24.755829 -41.566147 52.458893 62922 25.366699 -39.828949 53.205040 62923 32.270462 -41.535797 52.510483 62924 32.317108 -41.903320 54.697037 62925 32.311096 -41.566879 53.353935 62926 34.246864 -42.145905 53.770554 62927 50.633850 -40.984329 53.142853 62928 3.147743 -42.837250 51.791763 62929 13.106308 -43.413452 51.998886 62930 24.304443 -42.356750 52.185829 62931 33.250244 -41.965027 52.509964 62932 35.705566 -42.398697 54.701439 62933 34.207962 -42.284882 52.467712 62934 40.494141 -43.070328 54.460114 62935 12.699524 -43.985168 52.891678 62936 42.223434 -43.822968 53.673141 62937 41.833313 -43.421188 53.830597 62938 21.745132 -43.866333 53.845406 62939 27.674538 -45.460083 52.588387 62940 28.051102 -43.488541 53.008888 62941 13.350159 -45.277832 51.833725 62942 21.458588 -45.601517 51.804543 62943 39.209930 -46.701813 53.069046 62944 40.365860 -46.084381 53.257385 62945 41.233032 -45.614426 53.615677 62946 48.059784 -44.696899 51.953613 62947 48.915634 -45.695892 51.915726 62948 2.601173 -46.357635 51.061623 62949 2.707138 -45.419846 51.893738 62950 4.976608 -46.638763 51.581772 62951 7.858047 -44.012100 52.505341 62952 21.709145 -46.368774 52.074188 62953 21.453766 -46.648361 53.150085 62954 21.045639 -46.051376 52.977409 62955 47.819626 -45.934708 52.328354 62956 25.060913 -47.467072 52.736267 62957 26.609161 -47.170670 52.102760 62958 27.092484 -47.278534 52.643555 62959 26.558853 -47.568771 52.767265 62960 37.355659 -47.180862 52.156372 62961 37.164490 -48.146255 52.489609 62962 37.941681 -47.287079 52.740280 62963 45.742081 -47.753204 52.408951 62964 46.770187 -46.690445 52.313576 62965 48.062057 -46.942978 51.829498 62966 8.367226 -48.469193 52.140213 62967 36.914581 -49.366699 52.409370 62968 43.440460 -48.317490 52.912338 62969 6.138458 -49.565750 50.998528 62970 5.412582 -49.740570 50.765839 62971 6.980110 -48.510071 52.866829 62972 41.906754 -48.584305 52.020676 62973 5.969414 -49.505295 51.555389 62974 4.918030 -49.831116 51.195229 62975 36.519852 -50.035065 51.978218 62976 44.728836 -50.144424 52.318466 62977 45.009659 -49.336258 52.316101 62978 3.056213 -51.804199 51.320404 62979 3.533005 -50.486755 52.110092 62980 35.930939 -50.955078 51.936676 62981 3.112564 -52.701843 52.151665 62982 2.831551 -51.497528 52.478859 62983 8.941025 -52.530029 52.397049 62984 11.191063 -52.401459 52.248611 62985 12.040154 -52.654434 51.528236 62986 34.905289 -51.756073 51.958359 62987 34.250008 -52.502884 53.312912 62988 44.568298 -51.093613 52.460594 62989 22.186646 -53.718979 52.469711 62990 23.825897 -53.260376 51.635277 62991 24.401009 -53.341019 51.812790 62992 42.614319 -54.095078 51.580490 62993 5.749771 -53.579849 51.982430 62994 12.643890 -53.298141 51.957802 62995 10.717087 -55.671661 50.940773 62996 11.473381 -54.942810 51.737778 62997 35.602180 -55.088120 51.721169 62998 45.595703 -54.212006 51.695412 62999 9.556870 -56.254074 51.259247 63000 32.542801 -56.400055 51.786072 63001 37.682129 -55.480225 52.386368 63002 38.802948 -56.036346 51.845604 63003 39.269547 -56.637451 52.689102 63004 38.429169 -55.947510 52.780731 63005 43.673767 -53.479599 52.408844 63006 8.822998 -56.424515 52.033203 63007 8.234222 -56.968628 51.171921 63008 9.454918 -56.089783 52.139900 63009 24.740135 -57.539169 51.326225 63010 25.740952 -57.517746 51.462372 63011 33.682541 -55.924347 52.574043 63012 5.150101 -58.473770 50.852509 63013 4.501984 -57.886780 51.640999 63014 5.326462 -57.632431 51.864349 63015 7.369324 -57.158630 51.643150 63016 19.979935 -58.261612 52.844833 63017 20.113327 -57.027969 52.823212 63018 23.919434 -59.726532 51.980804 63019 27.014633 -57.558395 51.690559 63020 29.630783 -57.913101 52.244011 63021 28.375900 -57.672211 51.820190 63022 30.293541 -57.566864 51.520607 63023 40.319534 -57.282822 51.487732 63024 41.681625 -58.163818 51.719887 63025 20.743851 -59.057129 51.286453 63026 35.109665 -59.565262 52.243286 63027 35.811935 -58.937241 52.115044 63028 36.970856 -58.442032 52.300209 63029 37.553589 -58.552048 51.882896 63030 37.890411 -59.688095 51.782364 63031 37.877884 -58.945633 51.918900 63032 2.612946 -60.130859 51.137657 63033 21.455933 -59.868042 51.258888 63034 24.897339 -58.331558 52.028664 63035 25.347015 -59.796783 52.990814 63036 36.853622 -61.610519 51.397415 63037 37.649597 -60.999924 52.388145 63038 37.094269 -62.246094 52.566956 63039 2.545273 -62.753281 51.091972 63040 17.755806 -64.064804 50.555748 63041 17.854431 -64.411667 50.954979 63042 30.395721 -63.726547 50.483437 63043 35.400436 -64.200424 52.092331 63044 35.013054 -63.533325 50.918846 63045 40.859146 -63.533157 51.691513 63046 40.061371 -63.576843 52.957321 63047 39.411873 -64.270493 52.977318 63048 3.391144 -67.601364 52.420074 63049 3.433304 -68.410873 51.640831 63050 3.527008 -67.682144 51.253937 63051 19.235985 -65.103058 51.392639 63052 20.196579 -64.708908 50.516548 63053 15.645142 -65.664200 51.324196 63054 22.129364 -65.608719 50.694794 63055 20.875198 -65.321381 50.975624 63056 34.454269 -65.659592 51.867538 63057 3.084457 -63.945923 51.253906 63058 3.469818 -65.280045 51.376320 63059 14.689453 -66.979584 51.018845 63060 14.610001 -66.387207 51.766632 63061 15.137070 -66.135330 51.409920 63062 23.211876 -66.063751 50.609077 63063 23.984772 -66.535309 50.818542 63064 31.478531 -66.143753 53.495422 63065 34.348618 -66.860596 51.681305 63066 13.856583 -68.073761 50.885605 63067 15.505493 -68.225571 50.869781 63068 14.536499 -68.912552 50.709091 63069 24.945572 -67.115417 51.031799 63070 26.088623 -67.913330 51.701035 63071 27.246124 -67.438126 50.756042 63072 28.048286 -67.858597 51.108994 63073 27.764526 -68.303040 51.718796 63074 3.819061 -68.588028 50.752548 63075 13.824234 -68.949600 50.558556 63076 12.936958 -69.316513 50.738815 63077 15.286987 -69.772964 51.400284 63078 14.089966 -69.717590 50.797409 63079 17.093643 -70.498428 52.521858 63080 15.593048 -70.705338 52.067619 63081 21.420540 -69.007355 50.344376 63082 35.276688 -67.709946 51.753098 63083 36.130028 -67.552017 52.197517 63084 36.146591 -68.040268 50.898941 63085 12.163345 -68.814880 51.848267 63086 12.797020 -68.221390 51.768188 63087 12.697411 -70.842392 50.268684 63088 12.239517 -70.002502 50.570580 63089 13.638405 -70.681183 50.568550 63090 22.215576 -69.449463 50.486229 63091 23.147499 -69.970093 50.552155 63092 11.820831 -69.618118 51.404861 63093 11.910369 -70.546097 50.714912 63094 24.095016 -70.447464 50.561554 63095 25.087601 -71.101318 50.554359 63096 5.242577 -72.041046 50.753281 63097 5.459801 -72.678177 49.981026 63098 11.974022 -71.512161 50.553856 63099 13.509445 -71.702881 50.219971 63100 14.227661 -71.765701 50.897964 63101 5.541779 -72.910446 50.755798 63102 14.608826 -73.733215 51.025543 63103 14.495682 -74.637939 50.163391 63104 20.533447 -74.345901 51.329506 63105 21.494843 -73.894974 50.302681 63106 28.061096 -73.735672 49.940781 63107 11.870927 -74.912567 51.155296 63108 15.017349 -74.576462 51.118698 63109 15.163185 -75.542770 50.645096 63110 23.587585 -75.629349 50.282120 63111 26.576111 -76.153137 49.563797 63112 12.335907 -75.961136 50.791351 63113 14.011070 -76.421494 49.633812 63114 14.546432 -75.852783 49.796402 63115 14.554885 -76.736038 49.854454 63116 15.232117 -76.581696 50.311356 63117 23.755081 -75.596008 51.182343 63118 24.355301 -75.466202 51.821747 63119 13.780396 -77.915024 50.141968 63120 14.390213 -78.665619 49.951668 63121 13.089447 -78.745575 50.063416 63122 13.862320 -77.120010 49.937683 63123 14.850594 -77.594452 50.118263 63124 18.083862 -77.588867 50.037315 63125 18.387871 -76.174255 51.142540 63126 8.409012 -76.907364 51.386559 63127 9.742714 -78.549927 50.343964 63128 12.752060 -77.185791 50.601639 63129 17.864937 -78.573990 49.463638 63130 10.639053 -79.252426 49.811646 63131 14.977509 -79.482407 49.378571 63132 15.984955 -78.647537 49.828064 63133 17.352432 -78.449936 49.887337 63134 11.118073 -79.793045 49.230957 63135 14.083939 -79.625931 49.394226 63136 17.486938 -77.237122 50.836288 63137 17.114975 -77.901276 50.372253 63138 16.237587 -77.343002 50.618546 63139 5.885033 35.871643 59.166443 63140 5.086853 36.230225 58.279419 63141 4.956520 34.655014 58.598694 63142 8.351578 35.908722 58.757263 63143 4.447487 34.819397 57.702377 63144 5.360092 33.057983 60.067535 63145 4.907242 31.812897 59.506622 63146 11.210289 32.670883 57.781982 63147 10.630188 33.463135 59.237671 63148 12.084244 32.040466 57.560318 63149 18.002411 29.764740 58.246338 63150 19.336487 29.130951 58.378632 63151 4.399780 30.368576 60.908951 63152 4.022034 29.585968 59.936005 63153 4.532982 30.739044 59.724503 63154 4.378220 28.849518 57.215591 63155 4.035645 27.541412 57.232391 63156 22.290779 27.552017 57.895905 63157 8.782227 26.772217 59.996201 63158 9.390732 25.711273 59.418427 63159 8.787834 25.879181 60.177795 63160 15.213729 26.881256 58.391510 63161 14.535156 26.227631 57.728577 63162 13.967514 27.211746 58.434265 63163 13.202240 26.063141 57.437241 63164 24.340652 26.327026 57.306458 63165 12.031212 26.267593 57.633041 63166 12.461441 25.095749 57.243958 63167 11.475526 25.701782 57.534332 63168 11.438507 25.189819 57.525894 63169 14.293144 25.042679 57.278534 63170 15.689636 25.869095 57.807281 63171 15.191772 24.284729 58.061050 63172 14.101700 24.250641 57.977600 63173 17.936340 25.438629 57.782745 63174 17.122841 25.529587 57.916962 63175 18.486633 26.319199 58.397461 63176 18.253014 25.368729 58.001541 63177 25.724213 25.183838 56.925613 63178 10.585701 25.452942 58.385681 63179 11.513443 24.833435 57.869217 63180 12.155762 24.399811 58.494858 63181 11.185532 24.627106 58.706604 63182 11.050186 24.544556 59.467651 63183 10.455772 24.854660 59.584564 63184 13.153267 24.270004 58.024048 63185 13.413727 24.587311 57.266663 63186 15.948746 24.743179 57.680679 63187 17.159294 24.639633 58.385681 63188 16.171417 24.266144 58.214890 63189 17.837265 25.075729 57.956085 63190 24.649796 23.627472 58.082901 63191 24.096313 25.287552 58.102539 63192 25.127396 25.161896 57.429260 63193 3.805710 20.789841 58.809875 63194 23.920448 21.125580 57.493851 63195 25.117462 22.538513 57.425262 63196 24.695450 22.070267 57.517853 63197 31.474060 19.303497 57.433746 63198 17.823746 19.071548 57.106781 63199 18.249474 19.526733 57.129974 63200 18.860428 19.932465 57.665436 63201 19.658112 19.866913 57.166992 63202 22.898178 20.773499 57.878815 63203 31.049072 18.824860 58.662354 63204 17.604858 17.763565 57.357300 63205 17.461914 18.311310 56.891953 63206 32.397575 18.552917 57.103149 63207 31.903444 18.156097 59.200653 63208 27.290421 18.134430 57.865234 63209 34.878799 15.922516 58.750977 63210 34.377342 16.449814 58.643036 63211 34.687462 16.346466 57.802429 63212 33.491661 17.246124 57.180862 63213 18.879318 14.465927 55.966614 63214 25.772507 15.776901 57.292282 63215 19.437897 18.135956 59.248077 63216 18.527229 18.641296 58.636154 63217 18.176689 17.987137 58.060944 63218 19.516006 14.475311 56.490540 63219 25.612831 14.600128 56.883163 63220 3.720276 12.692780 57.796631 63221 25.508041 13.757675 56.464905 63222 37.177147 13.458954 58.160980 63223 5.924904 11.091797 56.316467 63224 5.626968 10.026428 56.761444 63225 21.324944 11.612488 56.995422 63226 27.797745 14.531662 58.616974 63227 28.321609 13.421417 58.005554 63228 22.212601 10.588257 57.008667 63229 29.296730 12.646667 58.095276 63230 29.899536 10.862061 56.199097 63231 30.283875 11.151062 57.020996 63232 6.807991 9.405167 55.849182 63233 22.924805 9.019150 57.140167 63234 30.059387 10.803146 56.743484 63235 40.580750 9.608185 56.478638 63236 6.298126 9.430801 56.278839 63237 23.014069 11.044174 58.140594 63238 5.669861 9.003113 56.595886 63239 35.038071 7.380661 56.562103 63240 35.017380 8.007538 57.398422 63241 35.943695 7.936981 57.137512 63242 38.998650 10.094055 57.490814 63243 3.840073 7.499710 55.947662 63244 5.055000 8.485413 56.657944 63245 4.665779 8.025742 55.935181 63246 34.277031 7.393402 57.487305 63247 34.668884 8.094330 57.966095 63248 39.201698 8.258316 56.767273 63249 23.230087 7.820389 57.744049 63250 20.948029 3.591553 56.883484 63251 21.411087 4.517609 57.977325 63252 27.449234 7.606522 57.543137 63253 34.573044 5.899727 57.716736 63254 34.222427 6.551361 57.289108 63255 2.585236 4.725174 55.718719 63256 36.897049 3.642395 57.570923 63257 20.258652 2.936478 55.223099 63258 28.999786 2.748672 57.182373 63259 27.757454 3.977722 57.333130 63260 27.152687 4.570099 56.979095 63261 8.121887 1.823959 57.047028 63262 7.845809 2.890396 56.642853 63263 22.144455 1.883698 56.877197 63264 22.563309 1.767090 55.982147 63265 23.739304 1.914261 57.146698 63266 24.683212 0.966766 56.499420 63267 24.421768 1.742340 58.050858 63268 29.219482 3.774460 59.531815 63269 29.846573 2.650101 59.178436 63270 43.001587 1.756851 55.896851 63271 41.989761 1.482239 56.461212 63272 20.622772 2.668411 55.958664 63273 21.149445 2.402725 57.382111 63274 22.970901 1.957886 56.691956 63275 23.499718 1.540527 55.903442 63276 5.229103 0.239395 56.234726 63277 4.304787 -0.109268 55.964081 63278 25.264870 -0.456894 56.386856 63279 29.555634 -0.472336 57.034119 63280 37.295128 0.854950 56.517853 63281 37.755447 0.461929 57.189636 63282 3.049629 -0.409454 58.878464 63283 2.770813 -1.367081 57.700714 63284 3.213600 -0.335602 57.727600 63285 3.447975 -0.770004 56.310822 63286 25.799133 -0.926910 57.387283 63287 25.651520 0.126038 57.489456 63288 28.988098 -1.712555 56.865234 63289 43.921051 -2.630524 57.153503 63290 42.650543 -0.895599 58.009705 63291 45.424957 -2.471024 56.206329 63292 23.931076 -3.855911 56.003983 63293 28.769058 -3.893646 55.915558 63294 45.280273 -3.336243 56.140366 63295 45.014832 -2.478973 56.483063 63296 2.808724 -4.244812 55.265289 63297 29.924896 -4.252563 55.930542 63298 30.520256 -3.511505 57.676575 63299 33.340576 -4.547409 56.632263 63300 3.296143 -4.745209 55.936737 63301 5.537224 -5.520020 56.035645 63302 8.947815 -5.462036 57.123627 63303 10.020752 -6.232285 56.885284 63304 43.917923 -4.516220 56.362091 63305 6.670380 -5.173462 57.472229 63306 23.172478 -5.802063 55.685547 63307 37.355904 -6.383316 56.770370 63308 38.354630 -6.288071 56.050125 63309 42.500000 -5.159210 56.345337 63310 10.640427 -7.888092 56.163116 63311 23.804291 -6.240219 57.097458 63312 23.510605 -5.691711 56.423889 63313 29.849869 -7.544144 57.435669 63314 8.348633 -9.456726 55.207703 63315 6.447632 -9.565155 55.549271 63316 9.087402 -9.030685 55.886230 63317 10.093872 -8.882980 55.400146 63318 40.887939 -9.728638 55.477310 63319 43.330811 -10.183655 56.039856 63320 44.625488 -10.729218 56.992920 63321 43.287399 -9.914993 57.910095 63322 2.665894 -11.532684 55.164062 63323 2.609940 -10.990891 55.771484 63324 2.194840 -11.931656 55.631851 63325 3.407356 -10.910492 55.244293 63326 3.339432 -10.300003 55.887299 63327 5.584778 -10.019821 55.378571 63328 4.330483 -9.984970 56.001038 63329 4.653030 -10.979507 54.955002 63330 32.603806 -11.119553 56.061539 63331 36.589966 -10.817535 55.823669 63332 3.244797 -12.167709 55.005096 63333 5.220444 -13.962814 54.620865 63334 5.647232 -12.380493 54.489182 63335 3.498901 -13.752960 54.821533 63336 5.927925 -10.813660 54.679382 63337 32.393616 -10.246796 56.523132 63338 31.557373 -9.512924 55.848297 63339 2.036972 -13.214676 56.373566 63340 2.227684 -14.857864 55.485535 63341 7.984733 -13.079559 54.116486 63342 6.112549 -13.645828 54.555008 63343 7.128319 -13.766632 54.504204 63344 33.539345 -11.691605 56.523026 63345 8.356544 -14.163605 54.286812 63346 2.738960 -15.813583 54.572624 63347 3.243439 -14.928864 54.606949 63348 4.461197 -14.729767 54.587723 63349 5.339455 -14.663544 54.752449 63350 1.884422 -15.928528 55.416138 63351 4.238297 -15.722534 54.490997 63352 8.053482 -16.325912 55.146515 63353 9.196014 -17.188828 54.433159 63354 2.357292 -16.676849 54.561737 63355 1.792107 -16.877350 55.420074 63356 3.999008 -17.245743 54.159721 63357 5.462319 -15.310730 54.778648 63358 5.652603 -16.510254 54.761673 63359 36.993729 -17.590363 55.140686 63360 37.545738 -17.258392 55.357971 63361 41.749634 -16.564178 55.442810 63362 5.396042 -17.512207 54.444962 63363 8.846634 -18.501892 54.784721 63364 40.933411 -16.321503 56.332657 63365 48.713837 -18.417084 56.104218 63366 7.488136 -17.202789 55.378601 63367 6.630737 -17.950073 54.713974 63368 7.661956 -18.103806 55.351730 63369 8.080537 -19.518936 54.139694 63370 7.552887 -19.634445 53.857666 63371 8.288101 -19.088379 54.643684 63372 8.133461 -18.615219 55.151505 63373 46.697906 -18.612259 56.653076 63374 1.739220 -15.800018 58.047577 63375 8.901947 -19.172745 54.530121 63376 8.742630 -19.534454 54.101631 63377 37.145645 -19.754501 56.088730 63378 37.870682 -21.692444 55.848907 63379 43.608521 -19.961761 55.808167 63380 42.552795 -20.624954 55.467499 63381 44.877136 -19.370773 55.359039 63382 41.564301 -21.249710 54.551041 63383 42.115662 -21.541718 55.806580 63384 50.892715 -20.381546 55.232391 63385 51.101273 -22.238861 55.268188 63386 50.358429 -20.935272 56.193542 63387 49.894531 -23.917465 55.870239 63388 49.565445 -21.710388 57.004944 63389 4.047608 -25.594315 54.370964 63390 39.412010 -26.851013 54.990562 63391 9.142464 -26.483322 54.629044 63392 9.136581 -26.826035 54.259338 63393 9.242569 -27.349579 53.603943 63394 10.258301 -28.187286 53.937210 63395 34.626358 -27.117783 55.333344 63396 36.493713 -25.228973 54.934746 63397 37.341782 -27.781296 54.554497 63398 48.073944 -26.303848 56.637894 63399 9.826027 -27.036682 54.970009 63400 27.486710 -28.204575 53.973808 63401 26.980743 -28.316696 54.254379 63402 27.403122 -27.806534 54.540825 63403 30.930603 -28.725586 55.119202 63404 31.676531 -28.688324 55.344421 63405 32.654556 -27.709427 54.360901 63406 37.606522 -28.373749 55.671631 63407 38.346436 -27.570023 55.111298 63408 10.651596 -29.580963 54.166603 63409 11.391815 -30.252411 53.507454 63410 27.812134 -30.743332 54.165215 63411 27.683853 -30.829819 55.158569 63412 27.152542 -30.213684 54.803246 63413 29.915085 -28.307343 53.902573 63414 36.271782 -28.581741 54.651222 63415 36.892044 -28.429565 55.214645 63416 10.078270 -31.060608 54.851196 63417 10.895470 -31.211472 53.768677 63418 34.436516 -29.653503 54.253090 63419 33.638702 -30.204636 54.566071 63420 11.609779 -30.890732 53.272179 63421 26.614212 -28.944550 55.006653 63422 28.793060 -31.320892 54.742554 63423 32.728256 -30.731491 54.875626 63424 10.154510 -32.097900 53.816216 63425 30.941116 -31.576584 54.920837 63426 29.945724 -31.895020 55.464523 63427 43.009521 -31.761139 54.224640 63428 49.669907 -31.730057 54.487419 63429 50.698029 -33.623398 54.997665 63430 50.243042 -32.005981 54.750221 63431 6.436318 -32.211868 54.379333 63432 5.861038 -32.907303 53.682373 63433 7.479332 -31.931351 54.546539 63434 9.500542 -31.870636 54.574928 63435 8.494080 -32.151520 54.198792 63436 10.375145 -31.749512 54.421509 63437 41.656586 -32.256790 54.081963 63438 47.501785 -34.164078 55.507446 63439 48.670929 -33.144028 55.447586 63440 48.566895 -33.649017 55.883072 63441 4.839729 -33.404297 53.721863 63442 3.848122 -34.751343 53.706795 63443 38.568268 -33.517044 54.189049 63444 38.248535 -34.122299 54.947281 63445 39.166306 -33.798462 55.154419 63446 46.274078 -34.207626 53.901657 63447 47.889847 -33.048370 54.511108 63448 2.725136 -36.510742 54.755806 63449 3.355515 -36.159897 54.008263 63450 2.911247 -34.726334 54.616554 63451 36.589996 -34.471588 53.965378 63452 50.310059 -34.537582 55.332764 63453 34.836319 -35.844391 54.152962 63454 33.528633 -37.499680 54.963364 63455 41.415237 -35.705856 53.088745 63456 41.592438 -36.224243 53.967384 63457 42.861649 -36.019699 54.126205 63458 44.020966 -35.826828 54.369614 63459 45.456390 -36.076050 55.572403 63460 47.791412 -35.169205 56.432892 63461 44.833115 -35.248001 54.036522 63462 50.819977 -35.302444 54.223785 63463 7.344818 -39.165588 55.410919 63464 8.030502 -38.194733 54.120613 63465 6.640366 -37.895279 54.035309 63466 26.429558 -37.117874 53.673836 63467 27.105698 -37.016586 53.742043 63468 34.661499 -37.720367 55.764572 63469 34.996468 -36.876984 55.312012 63470 39.477074 -36.984940 53.720276 63471 40.506882 -36.155762 53.416069 63472 41.063293 -37.810410 55.234772 63473 42.155396 -36.869049 54.926979 63474 42.274323 -37.574280 55.628326 63475 4.234192 -36.592590 53.504684 63476 4.736092 -37.629456 53.965576 63477 5.502853 -36.927551 53.165436 63478 8.699921 -37.845734 53.282104 63479 10.398987 -38.769745 53.148537 63480 26.467949 -37.623169 54.299057 63481 28.175522 -37.034363 53.765137 63482 29.068665 -37.376953 54.352974 63483 30.213203 -37.340683 53.628395 63484 30.847229 -37.722488 54.239456 63485 31.166367 -37.381180 53.568237 63486 31.937029 -37.516739 54.282471 63487 11.263229 -41.277893 53.847313 63488 25.138107 -40.923035 53.167328 63489 29.252838 -41.235321 53.183029 63490 42.103500 -39.815186 54.784218 63491 6.096329 -41.737915 52.552765 63492 29.049446 -41.967590 54.084343 63493 28.408478 -42.318375 53.157608 63494 29.591904 -41.508362 54.122139 63495 44.187836 -40.470062 53.997063 63496 46.085052 -40.966339 54.444969 63497 46.516861 -41.105438 54.822227 63498 48.245789 -41.231705 54.129356 63499 3.764664 -42.731659 52.684563 63500 2.959251 -43.825714 52.367889 63501 11.941422 -42.895554 53.654945 63502 24.772865 -42.311600 53.407303 63503 42.024979 -44.506226 53.619003 63504 7.350403 -44.078766 52.792007 63505 12.543427 -45.161819 53.303658 63506 23.061211 -43.706421 54.809204 63507 28.092590 -45.280273 53.482635 63508 5.073486 -45.822266 52.483772 63509 12.039131 -44.137421 53.942970 63510 28.057526 -46.245010 53.503510 63511 41.951340 -45.114563 54.465019 63512 3.317574 -45.794189 52.309845 63513 3.447037 -44.989792 52.809395 63514 4.152733 -45.825348 52.493530 63515 5.112160 -45.038025 53.113091 63516 11.207275 -47.335083 52.562874 63517 45.342041 -46.593307 52.213425 63518 21.769165 -47.015900 54.154930 63519 20.593719 -47.259338 56.726334 63520 20.867096 -47.076492 55.730896 63521 21.717003 -47.472000 55.725159 63522 44.811111 -48.423981 52.839584 63523 10.543930 -47.379684 53.378464 63524 11.513611 -46.828903 53.474403 63525 25.949341 -47.846375 54.105103 63526 23.419556 -47.654236 54.950661 63527 27.051865 -47.646591 53.347290 63528 27.606583 -47.187714 53.303383 63529 42.501770 -48.554031 52.590866 63530 44.195038 -48.081741 53.038681 63531 44.103378 -48.574387 53.231987 63532 38.182503 -48.193069 53.362434 63533 41.939545 -49.315506 52.525764 63534 42.748276 -49.101196 52.955711 63535 44.395447 -49.292633 53.052597 63536 4.972061 -49.426025 52.318680 63537 5.154503 -48.403992 53.707390 63538 36.832169 -50.461639 52.627769 63539 37.485229 -50.334641 53.199188 63540 37.477814 -49.369873 53.015541 63541 40.271606 -48.587967 55.514008 63542 40.113724 -47.835510 55.220306 63543 39.466705 -47.908951 54.409470 63544 42.710342 -50.219513 53.011086 63545 42.001724 -51.480347 52.727615 63546 3.709816 -49.207855 53.591187 63547 36.988213 -51.419662 53.668427 63548 38.469849 -49.947769 54.196175 63549 9.922836 -52.291565 52.629478 63550 35.839684 -51.638611 52.910049 63551 35.667343 -52.384308 54.232689 63552 6.934830 -53.099106 52.437500 63553 7.971733 -52.616241 53.034164 63554 10.784271 -52.121078 53.660774 63555 11.702515 -52.630615 53.267502 63556 11.860458 -53.328873 53.599503 63557 12.221130 -53.137604 52.386192 63558 23.832115 -54.129349 54.011688 63559 24.984039 -54.142227 54.143867 63560 24.869370 -53.712631 52.820793 63561 22.971603 -53.544632 52.807358 63562 23.795395 -53.387589 52.477234 63563 32.692322 -52.810074 52.503479 63564 32.460258 -53.226440 53.899185 63565 33.375290 -53.126831 54.835007 63566 42.476746 -52.855118 52.434944 63567 5.023087 -53.398163 52.867317 63568 21.050728 -54.783600 52.452065 63569 21.646484 -54.152664 52.737556 63570 22.468338 -54.130356 53.442703 63571 26.287735 -53.977982 52.246567 63572 25.715424 -54.056564 53.495972 63573 27.760422 -54.286499 52.856926 63574 28.841034 -54.308289 52.828392 63575 44.085632 -52.903564 52.885216 63576 11.954285 -54.126358 52.584229 63577 11.261444 -54.773346 52.860115 63578 21.119354 -55.582733 53.480667 63579 21.839645 -54.993073 53.739044 63580 26.853409 -54.263168 52.835503 63581 26.696144 -54.297760 53.534241 63582 29.534286 -54.204407 52.851723 63583 30.342407 -54.118057 53.401047 63584 34.908737 -55.587936 52.943703 63585 37.648148 -55.904755 53.470139 63586 10.315132 -55.545670 52.391037 63587 9.030556 -56.010391 52.893471 63588 9.659431 -55.386887 53.961967 63589 20.548195 -55.970383 52.778549 63590 34.069847 -56.018860 53.570366 63591 6.534737 -57.223694 52.068481 63592 7.834724 -56.617859 52.561386 63593 6.884102 -56.483551 53.605614 63594 40.119385 -57.401779 52.711746 63595 4.501831 -57.265793 52.842308 63596 26.271614 -58.165741 52.614067 63597 27.630554 -58.050247 52.950256 63598 28.550583 -58.766205 54.185333 63599 26.794029 -58.835999 53.563667 63600 30.644028 -57.732544 52.428123 63601 31.735712 -57.258331 53.149605 63602 33.085670 -56.551529 53.396332 63603 37.952362 -57.392624 53.372299 63604 37.100609 -57.882858 53.481758 63605 37.232521 -56.813995 54.134270 63606 37.682396 -57.960114 52.835892 63607 38.397980 -58.225449 52.841148 63608 37.765381 -58.331253 52.302429 63609 41.090897 -58.038651 52.597008 63610 41.272720 -58.617844 53.198502 63611 35.038925 -60.611847 54.024536 63612 38.462067 -59.801620 52.894867 63613 20.621681 -59.188293 51.970993 63614 35.135574 -59.965393 53.250603 63615 35.603516 -59.246292 53.324547 63616 21.653183 -60.037766 51.900322 63617 20.559219 -59.741928 53.127380 63618 23.046631 -60.863770 52.492851 63619 38.071167 -61.179611 53.240883 63620 42.441315 -60.318527 52.994286 63621 24.188896 -60.922958 52.645920 63622 24.823059 -61.503235 53.194145 63623 36.792892 -63.243103 53.251228 63624 3.544197 -63.857666 52.770073 63625 2.582489 -62.179169 52.193542 63626 35.359123 -65.808258 52.884346 63627 35.639069 -64.742371 53.043983 63628 16.393661 -68.014801 55.188141 63629 17.801704 -66.187286 52.945251 63630 15.356918 -66.902496 53.546730 63631 19.943069 -66.199158 52.590347 63632 21.313690 -66.043320 51.754990 63633 34.762459 -65.665619 52.224655 63634 39.239670 -64.987122 52.411736 63635 40.843475 -62.682755 53.022499 63636 13.848259 -67.105698 51.887726 63637 38.455017 -65.728485 52.556656 63638 13.262543 -67.663620 51.766838 63639 22.901878 -66.359375 51.379128 63640 30.303726 -67.462006 52.568184 63641 30.746857 -67.775742 53.277451 63642 23.853127 -67.058151 51.822388 63643 24.854843 -67.548080 51.948097 63644 27.126541 -68.903763 52.758095 63645 28.704330 -67.541534 51.176941 63646 29.115410 -67.723969 51.490456 63647 11.388435 -70.726700 51.607986 63648 14.614791 -70.722031 51.298195 63649 28.528122 -68.107224 51.415962 63650 28.759384 -68.357208 51.830498 63651 28.573578 -68.923309 52.712669 63652 11.332466 -69.828522 52.248863 63653 22.326782 -69.970581 51.240425 63654 11.671890 -69.274460 52.694412 63655 12.301582 -68.580994 53.057564 63656 23.206017 -70.487640 51.421631 63657 24.215424 -71.044968 51.370331 63658 11.514122 -71.912781 51.279160 63659 14.625183 -72.758530 51.509880 63660 25.043648 -72.155518 51.824310 63661 22.057098 -74.649338 51.528564 63662 11.419273 -73.220642 52.020439 63663 7.001328 -75.583710 50.942551 63664 6.570656 -74.691879 51.808319 63665 15.183395 -73.698288 52.039452 63666 16.107056 -76.202621 51.355019 63667 22.995468 -75.214050 51.056473 63668 25.100555 -75.579193 51.605835 63669 15.602547 -75.049759 51.840767 63670 16.557541 -75.333237 52.640022 63671 17.192810 -76.704590 51.329269 63672 9.670769 -77.640015 51.885094 63673 10.529587 -78.163498 51.347824 63674 11.799385 -78.198044 50.961998 63675 12.073898 -77.279602 51.442886 63676 10.800964 -78.783829 50.516190 63677 11.798096 -79.338440 49.842041 63678 7.301834 35.483398 59.899933 63679 8.471786 35.295639 59.616150 63680 5.625267 34.550232 59.825409 63681 9.258865 34.892883 59.008606 63682 6.438690 33.868484 60.922287 63683 11.938843 32.086060 60.049347 63684 11.245132 32.601578 60.563049 63685 13.968689 30.966110 59.362366 63686 4.727417 31.140350 58.299667 63687 15.901932 30.427704 58.434631 63688 14.744690 29.975769 59.556549 63689 13.797867 30.545776 59.709793 63690 16.721344 29.421036 59.124146 63691 15.622345 30.186859 59.190811 63692 4.383858 29.882324 58.444916 63693 4.021423 28.766083 58.390884 63694 20.519363 28.281387 58.268433 63695 19.538116 28.241379 58.800827 63696 3.691834 28.558136 59.132202 63697 3.753456 28.050034 58.354248 63698 21.403809 27.209290 58.219925 63699 10.662506 27.191223 58.647766 63700 10.469376 26.555771 58.376373 63701 9.850067 26.770035 59.067657 63702 15.028976 27.783493 59.069366 63703 20.390495 27.427185 58.565964 63704 22.666275 26.205566 58.283539 63705 3.679794 27.535782 58.873260 63706 13.809158 28.220825 59.167633 63707 12.045944 27.823792 58.903168 63708 11.164719 26.531464 58.078705 63709 13.407867 29.544373 59.661621 63710 16.747543 27.573853 58.982269 63711 18.034439 27.835205 59.124298 63712 19.598785 27.086395 58.625824 63713 19.593353 26.283218 58.362793 63714 20.509827 26.339935 58.425415 63715 21.521385 26.339447 58.356735 63716 3.712158 26.331085 59.228867 63717 19.558121 25.652985 58.416153 63718 18.619568 25.123718 58.680344 63719 20.253967 25.473587 58.748856 63720 20.665977 25.348999 59.348068 63721 19.750870 25.102081 59.388184 63722 21.349564 25.723175 58.802261 63723 22.130135 25.045898 59.450836 63724 21.256973 25.329590 59.491180 63725 23.365555 24.856857 58.820358 63726 22.952057 23.569031 59.787415 63727 3.781983 25.036575 59.754990 63728 16.594070 24.301956 58.694794 63729 19.578156 25.197235 58.709442 63730 3.805977 23.872925 59.751984 63731 12.952484 24.256897 59.130661 63732 14.699464 24.355408 59.356827 63733 13.732552 24.258545 59.188354 63734 15.958931 24.471680 59.443878 63735 3.796112 20.119614 61.054840 63736 18.702805 19.868927 58.350708 63737 19.107986 20.181137 58.559570 63738 19.602150 20.311920 58.215683 63739 24.239632 22.288452 58.200958 63740 22.455673 21.514786 59.205444 63741 23.029770 22.437988 59.543060 63742 23.527374 22.219391 58.763016 63743 18.131470 18.542679 58.159821 63744 18.322350 19.247406 58.021393 63745 28.187607 18.970322 58.134613 63746 28.192825 18.197693 59.043213 63747 27.938293 18.906067 57.265747 63748 30.113174 19.064758 58.628662 63749 17.818542 18.465317 57.646698 63750 27.518646 17.091217 59.041870 63751 18.940643 19.484406 59.058838 63752 26.463272 16.939575 57.812225 63753 33.246185 17.001358 59.429413 63754 19.526840 19.555069 59.823059 63755 35.626465 15.444199 58.280975 63756 20.611649 15.477936 58.119446 63757 21.008278 14.369934 57.865265 63758 21.435562 14.537750 58.548859 63759 20.266663 14.387222 57.147797 63760 26.499207 14.800735 57.786499 63761 37.650177 11.774231 58.449646 63762 4.389374 10.141434 57.770660 63763 3.931374 11.487366 58.135254 63764 21.685799 11.423218 57.095947 63765 4.964317 9.096802 57.126663 63766 28.697701 9.375931 57.829498 63767 29.513809 10.652130 59.657944 63768 37.814163 9.211975 58.247253 63769 23.852280 9.113632 58.707153 63770 34.107040 6.940689 57.074326 63771 2.733200 6.858139 57.284607 63772 3.862648 8.285706 57.332291 63773 27.915276 7.954773 58.507538 63774 27.218597 6.724823 57.992142 63775 26.838112 5.950241 57.538422 63776 35.461617 5.143341 57.434250 63777 2.599320 4.943359 56.974976 63778 26.917099 5.304520 57.387177 63779 3.507080 4.066223 56.904434 63780 3.410950 3.939903 55.691071 63781 4.344277 3.816345 57.317566 63782 4.843155 4.077553 58.016388 63783 6.787308 3.654434 57.030334 63784 7.690856 3.541626 58.088867 63785 34.811264 5.525032 59.082718 63786 36.019318 4.605377 58.613388 63787 35.721115 4.647377 59.890747 63788 33.936806 6.375671 59.585052 63789 34.112411 6.663101 58.501465 63790 37.091843 2.939316 57.688477 63791 4.013382 4.093124 57.929398 63792 30.114883 1.579163 58.414551 63793 29.923080 1.061340 57.338501 63794 8.275879 2.709824 57.899597 63795 22.754776 2.215912 57.927460 63796 21.525223 1.896332 56.996353 63797 30.256668 1.883377 59.315033 63798 37.517815 1.103287 57.523026 63799 41.715088 1.189529 56.997131 63800 41.672821 0.284180 57.940033 63801 42.053436 0.786438 57.380981 63802 4.256966 0.091782 56.758240 63803 30.198395 0.414673 58.229156 63804 39.811714 0.576553 57.156296 63805 40.957260 0.802597 57.413757 63806 25.369949 -1.713287 56.852631 63807 38.259201 0.164047 57.296448 63808 28.816147 -2.689529 56.839203 63809 24.778496 -2.769958 56.475845 63810 2.448784 -2.591110 57.284027 63811 2.487152 -2.303284 58.128754 63812 2.477120 -2.930313 57.814117 63813 28.665558 -3.428680 56.487000 63814 23.916351 -4.787476 56.896072 63815 29.329338 -3.603714 56.928848 63816 2.937050 -3.762665 57.248825 63817 4.139710 -4.869324 56.936890 63818 5.170281 -4.992020 57.683685 63819 34.436401 -4.987381 57.018616 63820 41.512756 -4.762512 57.625793 63821 42.718872 -4.610352 57.050476 63822 23.939552 -5.540482 57.490433 63823 35.003319 -5.634155 56.576202 63824 38.562622 -6.059250 57.335007 63825 37.402466 -6.230637 57.354767 63826 40.034073 -5.803085 56.863525 63827 31.215668 -7.752457 57.794937 63828 30.830475 -7.201462 59.048218 63829 28.120529 -7.535797 57.051590 63830 10.681984 -7.064560 56.955444 63831 26.738144 -7.751755 56.279663 63832 27.205429 -7.628510 56.489349 63833 4.380356 -9.411957 57.515579 63834 5.865402 -9.257462 56.672211 63835 7.160004 -9.114685 56.262512 63836 8.144226 -9.072388 56.090973 63837 9.870193 -8.407257 56.646790 63838 10.400192 -7.599731 57.376831 63839 32.118561 -8.519592 57.723709 63840 40.969925 -9.525696 56.065491 63841 37.859764 -10.260391 56.409485 63842 41.911530 -9.505035 56.859573 63843 32.119987 -9.265167 56.880737 63844 37.697937 -10.298676 57.582672 63845 38.472427 -10.001740 58.399170 63846 2.106690 -11.602341 56.408661 63847 34.452820 -11.736893 56.085571 63848 35.498642 -11.673553 57.178879 63849 45.385498 -12.120132 56.318451 63850 32.990891 -10.984726 57.296967 63851 34.974426 -11.730347 56.452881 63852 6.093811 -14.499878 54.761116 63853 7.971237 -15.009003 54.773468 63854 6.853882 -15.434296 54.944450 63855 6.979370 -16.593521 55.149200 63856 8.268814 -17.577850 55.287384 63857 23.585785 -16.347626 55.997025 63858 23.208878 -16.076859 56.388306 63859 23.966248 -16.109589 56.215485 63860 23.871834 -16.398895 55.997375 63861 24.245285 -16.420395 56.271576 63862 38.044640 -17.171265 57.028046 63863 38.801498 -16.625992 57.015228 63864 38.232574 -16.890747 56.086487 63865 39.226791 -16.618469 56.034332 63866 40.145386 -16.531693 55.910019 63867 43.354736 -15.849152 57.454803 63868 45.360046 -13.879425 57.788940 63869 44.957916 -14.785370 58.302658 63870 45.215393 -14.122589 58.590973 63871 8.238663 -18.258286 55.324646 63872 23.600098 -16.623657 56.303223 63873 24.672607 -16.961975 56.710114 63874 23.597504 -17.084869 56.895813 63875 24.358002 -17.645538 57.270355 63876 37.032806 -17.569260 55.740387 63877 37.510483 -17.239563 56.202789 63878 41.926361 -16.174622 56.711426 63879 44.618958 -15.093979 57.684662 63880 7.433647 -19.160553 54.347412 63881 36.470421 -20.025711 55.233337 63882 47.882233 -18.442795 56.557739 63883 7.579208 -18.656036 54.972656 63884 45.345093 -19.011093 56.426422 63885 46.654999 -18.955338 57.777176 63886 45.817108 -18.990952 57.443573 63887 49.778076 -19.140762 55.869553 63888 37.949234 -20.431839 56.519684 63889 37.723419 -19.775085 56.793137 63890 44.413696 -19.488922 56.422028 63891 43.871399 -20.126404 57.219360 63892 48.902283 -19.271301 56.892227 63893 49.963120 -19.979538 56.258545 63894 42.158127 -22.070999 56.146149 63895 41.946442 -22.133606 55.754211 63896 49.664764 -20.345886 56.842499 63897 2.121544 -24.596268 55.666046 63898 2.859970 -25.243225 54.943924 63899 38.622604 -22.200668 56.489578 63900 38.667618 -21.185883 56.918884 63901 38.258545 -23.079330 56.031601 63902 37.916367 -23.938293 55.861389 63903 42.080902 -22.768372 55.978424 63904 37.447044 -24.917892 56.029312 63905 38.285217 -24.772629 57.579620 63906 38.352058 -23.957703 56.624176 63907 48.692505 -24.825729 56.483246 63908 48.929672 -23.899200 56.710281 63909 49.235001 -23.163269 56.921692 63910 2.672485 -24.911652 56.401215 63911 2.737953 -25.189728 55.681641 63912 4.484306 -25.480759 55.716125 63913 5.623589 -25.513351 55.753601 63914 6.440697 -25.915573 54.815231 63915 26.438187 -26.470642 55.416809 63916 25.879280 -26.400696 55.609924 63917 26.228317 -25.984482 55.732178 63918 27.187408 -26.972992 55.439026 63919 26.626801 -26.009201 56.031509 63920 27.320999 -26.402069 56.477234 63921 36.437248 -26.037155 55.817413 63922 9.250359 -25.717987 55.542755 63923 26.535156 -27.542755 55.019379 63924 25.865189 -27.606491 55.561417 63925 25.248260 -26.551666 55.966217 63926 25.315132 -27.434570 56.293243 63927 28.017181 -27.186401 56.215332 63928 35.570503 -26.347641 55.131317 63929 35.672768 -26.926468 56.317993 63930 40.826279 -26.053619 55.877014 63931 29.282646 -28.027618 56.238098 63932 28.370728 -26.931396 58.028534 63933 28.308197 -27.758865 55.187943 63934 33.641922 -27.668030 55.350220 63935 32.587051 -28.234039 55.279724 63936 33.596840 -28.155701 56.297073 63937 39.076279 -28.010162 56.339691 63938 25.937782 -28.367279 55.990753 63939 29.863953 -28.381866 54.939178 63940 30.979385 -28.728180 56.067673 63941 47.205826 -28.567383 58.471313 63942 47.539597 -28.611221 57.614288 63943 46.742981 -29.984222 57.247559 63944 27.018143 -29.965302 55.915253 63945 34.538727 -30.087799 55.397949 63946 35.625893 -29.591278 55.987061 63947 47.134842 -29.196106 55.767883 63948 9.524208 -29.842468 55.583649 63949 31.990435 -31.578369 55.674637 63950 33.320587 -31.126617 56.073547 63951 34.719727 -30.864777 57.144821 63952 46.553375 -29.954803 55.818665 63953 48.911102 -32.368195 54.818954 63954 2.609673 -33.458969 55.627151 63955 3.170540 -31.651550 56.101868 63956 2.406410 -32.649719 57.035797 63957 5.411957 -32.010574 54.729424 63958 10.109764 -32.036469 54.446091 63959 42.139511 -32.737823 55.221237 63960 43.461395 -32.084717 55.320862 63961 43.130157 -32.730957 56.061981 63962 49.746460 -32.654572 55.207016 63963 3.849213 -32.730042 54.859665 63964 38.583862 -35.057083 56.348816 63965 39.982620 -33.917572 55.817719 63966 41.214661 -33.512131 55.995972 63967 42.336411 -33.238098 56.276276 63968 50.287979 -33.428772 55.324677 63969 2.186180 -35.172134 55.601318 63970 37.222809 -34.716736 54.866875 63971 48.534363 -34.155609 56.177078 63972 2.106117 -36.199234 55.663696 63973 36.047974 -35.147629 54.330750 63974 36.341003 -35.992294 55.430481 63975 47.586548 -36.704300 56.797699 63976 50.337616 -36.148911 55.148697 63977 49.655670 -35.526245 56.189056 63978 40.655243 -37.053391 54.455025 63979 43.525803 -36.351379 54.971283 63980 43.462982 -37.022568 55.675385 63981 3.830956 -37.426575 54.216988 63982 5.353317 -38.104523 54.450111 63983 39.688408 -38.261520 54.532372 63984 3.591110 -38.686279 55.377991 63985 3.458817 -37.996277 54.995163 63986 2.731224 -38.029282 55.926849 63987 9.446564 -38.863235 54.106575 63988 25.742218 -40.530167 54.579094 63989 26.419861 -39.575821 56.229553 63990 26.416840 -38.616165 55.300720 63991 30.019730 -37.737930 54.651550 63992 10.570679 -39.753647 53.826149 63993 40.006607 -39.105194 54.678207 63994 42.913025 -40.119186 54.753174 63995 25.416260 -42.299667 54.589699 63996 25.936653 -41.776947 55.478485 63997 32.765511 -43.006592 56.654968 63998 32.165779 -42.353287 55.864670 63999 33.526543 -42.307037 55.438812 64000 31.000130 -42.265091 55.449158 64001 29.760513 -42.182236 54.779465 64002 43.486755 -40.311844 54.764275 64003 44.406143 -40.283279 55.557312 64004 45.257141 -40.702362 54.383316 64005 48.701050 -40.862366 54.969292 64006 4.017822 -43.707443 53.391403 64007 4.957039 -42.984756 53.586906 64008 35.601952 -42.634995 55.827942 64009 34.766418 -42.325607 55.221024 64010 47.309662 -40.992477 55.225677 64011 47.999313 -40.488678 55.969284 64012 20.722229 -43.959106 54.241745 64013 21.006592 -43.407532 54.531906 64014 28.409416 -44.542404 53.907593 64015 28.888901 -43.304886 54.417381 64016 41.879547 -43.430069 54.959595 64017 4.999191 -44.011932 53.633766 64018 20.210999 -44.515350 54.803787 64019 21.764771 -43.292404 54.893242 64020 24.491158 -43.321899 54.442734 64021 42.263748 -44.037125 54.513412 64022 42.300476 -44.867050 56.343842 64023 42.210403 -45.063019 55.385864 64024 42.054199 -45.954346 56.126862 64025 4.330399 -42.775864 53.336868 64026 4.268471 -44.761627 53.319595 64027 11.897583 -45.566193 54.260323 64028 28.461281 -45.517593 54.159332 64029 42.252823 -44.047699 55.536072 64030 20.930992 -46.246780 53.910233 64031 28.699158 -46.332230 54.438019 64032 40.377838 -46.636368 54.145065 64033 41.379761 -46.333252 55.122360 64034 11.066025 -46.710678 54.531311 64035 20.936295 -46.744431 54.973427 64036 28.260086 -47.225693 54.186134 64037 5.904694 -47.473572 54.936958 64038 7.920395 -47.413269 54.680229 64039 9.161980 -47.360825 54.600838 64040 2.833908 -50.474365 53.098267 64041 2.560059 -50.071503 54.353836 64042 2.484223 -51.160172 53.375687 64043 43.551941 -49.249725 53.230370 64044 40.743866 -47.437820 55.506622 64045 40.396240 -47.201126 54.976295 64046 44.032852 -50.301498 53.043617 64047 2.846909 -52.113297 53.182060 64048 38.925079 -51.147537 55.425964 64049 39.916504 -50.031433 55.773621 64050 5.960442 -53.057846 53.346375 64051 6.920410 -52.627319 53.911880 64052 9.140991 -52.121353 53.632454 64053 32.147041 -53.815704 55.285309 64054 33.114502 -53.785599 56.118423 64055 34.448105 -52.804352 54.701645 64056 35.045586 -52.985733 55.541779 64057 36.694748 -52.308914 54.646179 64058 3.886307 -53.065231 53.097969 64059 31.073425 -54.095993 54.423553 64060 10.693611 -54.914948 53.535873 64061 21.597748 -56.433517 54.891624 64062 28.016098 -54.722244 55.112305 64063 29.410873 -54.476227 54.070969 64064 30.362579 -54.695175 55.450485 64065 35.973930 -56.035690 54.361938 64066 36.911758 -55.514694 53.391563 64067 10.639252 -54.536224 54.653488 64068 19.696648 -57.490402 53.998924 64069 20.295883 -56.782303 53.776672 64070 20.815262 -56.405945 54.091309 64071 34.689400 -56.181213 54.376511 64072 38.281273 -56.520721 53.359665 64073 38.912331 -57.305191 53.170258 64074 39.594009 -57.321075 53.057198 64075 5.608757 -56.863403 53.270721 64076 2.625481 -58.577194 54.763420 64077 2.242684 -59.692871 54.671562 64078 2.380562 -59.816650 53.627060 64079 28.857376 -58.142456 53.033485 64080 39.901978 -58.389771 53.291260 64081 36.927811 -55.982422 54.148697 64082 3.093804 -57.755676 55.850250 64083 3.199211 -57.652328 56.763031 64084 2.996292 -58.854080 56.625549 64085 2.563011 -59.822586 52.130379 64086 2.988037 -58.253265 53.350441 64087 19.428619 -59.005112 53.755554 64088 26.182816 -59.880859 53.742538 64089 30.254089 -58.078217 53.513840 64090 36.276970 -58.573792 53.526863 64091 36.479492 -57.924408 54.513474 64092 39.765160 -59.803162 53.940613 64093 41.109985 -59.248734 53.664383 64094 41.746964 -60.091934 53.647980 64095 9.611450 -62.162613 53.127609 64096 10.258118 -62.271149 53.215256 64097 9.804832 -62.796402 52.758774 64098 21.888428 -60.868591 53.307541 64099 22.954834 -61.686584 53.879723 64100 23.948196 -61.822708 53.343575 64101 2.416412 -61.031799 54.279465 64102 7.783859 -63.614380 52.753197 64103 7.826271 -62.501495 53.624596 64104 8.967033 -62.931137 52.849411 64105 8.843536 -62.011551 53.819847 64106 9.600510 -63.567917 52.662704 64107 10.225662 -63.435272 53.155121 64108 24.738342 -62.334335 53.828354 64109 25.905884 -61.746124 54.061958 64110 41.748199 -61.378357 53.183533 64111 8.884964 -64.079041 52.790192 64112 32.391930 -65.700897 55.394104 64113 32.619133 -64.755554 54.455734 64114 3.493370 -68.458252 52.523071 64115 7.852676 -64.923203 53.218460 64116 6.609390 -65.078125 53.216850 64117 7.069046 -64.387985 52.695251 64118 9.063034 -64.974380 53.676163 64119 9.627350 -64.190063 53.011803 64120 33.176559 -64.501709 55.433197 64121 36.179016 -64.199188 53.365219 64122 15.704262 -65.894867 52.181961 64123 31.711977 -64.720978 52.911957 64124 37.199478 -65.868530 53.362038 64125 38.163879 -64.703079 53.533615 64126 13.164886 -67.714355 52.942467 64127 21.205086 -66.730515 52.858612 64128 22.544823 -66.784363 52.245667 64129 35.405731 -67.101425 52.559204 64130 36.268929 -66.700180 52.991722 64131 11.300788 -70.106537 53.135269 64132 14.080650 -67.111404 53.102829 64133 14.550873 -66.580887 52.502022 64134 22.305161 -67.296646 53.148254 64135 23.213547 -67.285187 52.677528 64136 24.194031 -67.772781 52.857529 64137 3.630066 -67.899399 53.217880 64138 25.187279 -68.059128 52.569870 64139 25.970749 -68.677368 53.017952 64140 3.794869 -69.079193 51.885773 64141 4.381882 -69.906631 52.190025 64142 11.093796 -70.872360 52.755119 64143 11.136108 -70.266602 52.408905 64144 15.833466 -71.189041 52.626137 64145 15.115837 -71.752106 52.127350 64146 29.465164 -67.960312 52.088829 64147 5.565125 -72.185760 52.054306 64148 11.196289 -71.693848 52.218948 64149 15.575417 -71.773453 52.838150 64150 23.509109 -71.413895 52.373970 64151 11.196106 -72.022095 53.687515 64152 15.076500 -72.706314 52.278595 64153 6.375412 -73.802048 52.686882 64154 26.201149 -73.257172 51.616974 64155 16.025131 -74.229172 52.954231 64156 21.095673 -74.321899 52.851547 64157 22.218361 -74.389862 52.977745 64158 25.808319 -74.252365 52.072258 64159 7.267075 -75.238373 52.414078 64160 11.996643 -76.283783 51.618477 64161 23.221741 -75.024780 52.098015 64162 7.067810 -74.420197 53.551559 64163 17.416634 -75.941757 52.167130 64164 18.532349 -75.131561 52.865280 64165 9.489395 -76.433212 53.294044 64166 11.181953 -77.225967 52.150940 64167 10.195419 -77.240707 52.664398 64168 10.430519 -76.621750 53.132248 64169 6.276657 34.963776 60.191315 64170 8.965469 34.977982 59.744904 64171 9.473396 34.477997 59.806015 64172 10.567795 33.205963 60.631546 64173 9.709656 33.786041 60.563324 64174 12.921218 31.061417 59.715363 64175 15.747955 29.645035 59.542908 64176 18.221672 28.775116 59.116776 64177 18.798058 27.754715 58.901459 64178 3.670441 28.602448 60.105286 64179 9.855621 25.125977 59.306488 64180 14.593384 28.750870 59.520416 64181 10.486870 27.669525 59.323303 64182 10.738838 28.516602 60.055450 64183 10.497902 29.393478 60.973267 64184 11.972733 29.714035 60.205231 64185 15.659164 28.775635 59.473267 64186 17.656235 28.276337 59.389282 64187 11.543861 24.444092 59.395264 64188 18.850563 25.092514 59.942688 64189 17.748428 24.883804 59.656754 64190 16.892883 24.569168 59.259338 64191 21.905441 24.385422 60.486969 64192 11.256813 24.825439 60.552307 64193 12.307785 24.614563 60.070068 64194 13.849060 24.796158 60.829102 64195 21.148315 20.947952 59.636078 64196 19.834930 20.287155 59.336746 64197 20.418411 19.998047 60.683258 64198 29.061523 17.595581 59.782806 64199 31.472885 17.720596 59.806213 64200 30.276718 17.896286 59.647308 64201 29.095535 15.200424 59.903229 64202 29.490196 13.810928 59.486359 64203 27.922241 15.797852 59.364182 64204 26.951424 15.808838 58.485046 64205 20.314819 16.639084 58.792419 64206 21.208694 15.937958 59.224823 64207 28.270866 17.437759 59.682281 64208 33.898659 15.926468 59.721252 64209 3.215515 15.916626 58.727875 64210 22.255196 14.590652 59.601456 64211 29.999557 12.421112 59.673904 64212 36.203827 14.483643 58.681625 64213 3.389671 12.142776 59.106018 64214 36.174347 13.667053 59.214172 64215 36.663086 12.621155 59.146759 64216 35.239044 14.586868 59.536194 64217 35.701073 12.880554 59.897400 64218 34.700775 13.385742 60.463791 64219 22.505615 12.900726 58.737396 64220 21.971863 13.681427 58.669342 64221 23.457466 12.652344 59.524796 64222 28.594391 9.025848 59.569534 64223 37.690536 10.754456 58.741577 64224 23.962891 10.838074 59.034454 64225 29.305313 9.524857 60.714340 64226 3.697617 9.486847 58.571838 64227 28.717819 8.783890 60.390869 64228 36.799286 9.285156 58.857758 64229 37.491592 10.034729 58.831345 64230 23.582764 7.615173 58.701706 64231 27.751602 6.009003 59.489746 64232 27.420029 5.919220 58.825104 64233 27.778740 6.779739 59.261002 64234 34.366440 7.983856 58.764023 64235 33.743332 7.403961 59.681580 64236 34.847855 8.839935 59.537857 64237 35.577339 8.566940 58.441818 64238 2.739014 7.512482 58.361603 64239 2.363899 5.914093 57.797516 64240 2.347527 6.720367 58.022461 64241 27.092117 5.772926 58.069672 64242 27.415146 4.945999 58.158783 64243 34.818146 5.112625 60.491364 64244 34.045105 5.818848 60.299362 64245 3.201294 4.858131 58.485565 64246 27.848938 5.309059 59.278900 64247 36.904022 3.645042 58.418488 64248 7.714676 3.899078 59.806747 64249 8.261147 3.054131 58.837646 64250 21.047722 3.387482 58.463531 64251 21.218979 4.137665 58.838959 64252 37.021866 2.959297 60.044312 64253 37.770111 1.284912 60.257248 64254 36.929405 2.361877 61.248642 64255 21.363022 2.726929 58.661285 64256 21.807793 2.330826 58.254837 64257 23.679634 2.160416 58.073700 64258 23.593346 2.382065 59.215546 64259 25.103371 1.514679 59.515961 64260 24.138351 2.600677 60.724167 64261 21.838272 2.022400 57.546295 64262 25.171661 2.043503 60.974579 64263 25.246300 1.097214 57.975082 64264 25.791611 0.535126 58.582413 64265 30.643242 0.952820 59.754730 64266 3.750778 0.050049 57.463470 64267 4.628227 0.538605 58.063828 64268 8.002380 2.244766 58.880463 64269 7.209053 1.377686 58.048889 64270 26.256004 -0.933212 58.913757 64271 26.139305 0.373734 59.533371 64272 38.112762 0.575272 58.007462 64273 38.941383 0.246262 57.850494 64274 40.145599 0.270630 58.315674 64275 41.232544 -0.259277 58.680023 64276 25.827148 -1.781219 57.838745 64277 29.415436 -1.845200 57.717224 64278 25.385361 -2.587708 57.519928 64279 24.897995 -3.688797 57.656601 64280 25.834946 -2.585403 58.548599 64281 25.818321 -3.765411 59.652756 64282 24.607681 -4.821930 58.369278 64283 29.570747 -2.911072 57.709824 64284 32.251251 -3.864578 58.218140 64285 33.959534 -4.434662 58.200546 64286 35.472488 -5.249146 58.305542 64287 42.719727 -3.702271 57.727753 64288 9.256607 -5.746552 59.420410 64289 36.715988 -5.638153 58.742477 64290 40.364410 -4.702637 59.299759 64291 41.077652 -3.102798 59.468597 64292 37.748993 -5.881332 58.319733 64293 40.127289 -5.510422 57.952621 64294 39.306709 -5.560394 58.713806 64295 41.911331 -3.467056 58.531189 64296 26.623024 -7.581345 57.126740 64297 28.283943 -6.919662 61.081604 64298 28.819061 -7.134338 59.301239 64299 29.332703 -6.647049 60.554092 64300 26.965073 -7.540634 59.329193 64301 27.275047 -7.442276 58.260239 64302 7.129364 -8.603012 57.484070 64303 8.032501 -8.586258 57.156662 64304 8.948586 -8.500687 57.108826 64305 9.661957 -8.028595 57.772903 64306 3.077637 -10.365067 56.749649 64307 32.835281 -9.620926 58.277588 64308 32.593307 -8.479156 58.699356 64309 42.106934 -9.390640 57.823822 64310 41.051010 -9.541428 59.861374 64311 42.081268 -9.483353 58.624130 64312 42.782532 -10.195999 59.600800 64313 2.086632 -11.689926 57.556274 64314 3.035721 -10.215073 58.139893 64315 36.693420 -10.894012 57.302948 64316 39.104828 -9.599197 59.509918 64317 45.347198 -12.014175 57.647583 64318 44.761719 -10.871231 58.260925 64319 44.978683 -11.588379 58.741608 64320 34.671692 -12.250214 57.654114 64321 34.555191 -12.323547 58.158142 64322 34.094978 -12.021973 57.928528 64323 34.509758 -11.974564 56.973312 64324 19.382019 -12.632004 58.107635 64325 20.226433 -13.459991 57.497787 64326 19.624344 -14.387772 57.858292 64327 21.184219 -14.060928 57.188126 64328 20.341263 -14.030838 57.189209 64329 20.509689 -14.586136 57.034027 64330 22.067184 -14.864883 56.874359 64331 21.290787 -15.405457 56.934708 64332 24.018295 -14.699081 57.935455 64333 23.124680 -15.043671 57.056595 64334 22.953049 -14.018921 58.192612 64335 20.375473 -15.070129 57.097321 64336 22.266022 -14.271164 57.333344 64337 22.394714 -15.699142 56.710388 64338 23.879280 -15.627258 56.652588 64339 24.764198 -15.895142 56.896149 64340 20.280350 -15.578949 57.451599 64341 21.150169 -16.262512 57.631531 64342 20.410179 -16.059998 57.817490 64343 19.614647 -15.447327 58.823395 64344 19.659447 -15.357178 57.937927 64345 19.946945 -15.813385 58.009430 64346 24.145813 -15.217026 57.200562 64347 26.031631 -16.644653 57.005707 64348 26.883797 -16.071167 57.501770 64349 27.187469 -16.845947 57.041290 64350 26.979416 -15.348724 58.535522 64351 27.995071 -15.333588 59.203766 64352 28.273575 -16.618668 57.904724 64353 38.163559 -18.104324 57.629089 64354 39.226860 -17.434723 57.986359 64355 39.901970 -16.405334 57.215027 64356 40.927811 -16.312180 57.631714 64357 41.835388 -16.369629 58.011383 64358 22.498230 -16.532852 57.026886 64359 25.814240 -17.931259 57.355347 64360 24.921913 -18.116074 57.773376 64361 24.171059 -17.866440 57.960632 64362 27.180878 -18.417511 57.359543 64363 26.953506 -17.667892 56.902039 64364 27.760902 -17.476059 57.016876 64365 27.682152 -18.107605 56.961548 64366 28.530838 -18.043411 57.433044 64367 29.564697 -17.560471 58.047119 64368 29.302414 -18.117935 57.703049 64369 47.652969 -18.989182 57.465546 64370 49.226807 -20.270447 57.276245 64371 27.860283 -18.461761 57.274780 64372 37.282135 -18.108414 56.529663 64373 44.855042 -19.557053 57.550797 64374 45.940903 -19.565536 58.359589 64375 44.984055 -19.937271 58.552826 64376 38.895035 -18.921814 58.023529 64377 38.656372 -18.137405 58.038513 64378 39.808701 -20.706512 58.540573 64379 39.230110 -22.065018 57.546188 64380 42.531738 -21.190567 56.397995 64381 38.476273 -20.025879 57.297089 64382 42.510834 -21.952911 56.750290 64383 48.840637 -22.600159 57.569244 64384 38.817024 -23.012863 56.946991 64385 41.868195 -24.803970 56.668274 64386 42.473618 -23.366592 57.479309 64387 1.572098 -18.398010 58.665070 64388 48.377350 -24.153137 57.151230 64389 48.541809 -23.424957 57.378647 64390 10.251144 -25.501465 56.534271 64391 9.893021 -24.906418 56.763596 64392 10.073395 -25.219193 57.621735 64393 10.008560 -25.508759 56.053421 64394 24.779648 -25.353378 57.252991 64395 25.282715 -25.693100 56.226334 64396 24.732727 -26.013962 56.379700 64397 42.154114 -24.806808 57.921341 64398 42.584366 -24.216446 59.407364 64399 47.979065 -24.884338 57.559875 64400 47.916885 -23.903748 57.961853 64401 3.428688 -25.357330 55.681046 64402 6.473374 -25.428955 55.774551 64403 7.531464 -25.216263 55.840820 64404 6.302178 -24.865250 56.720078 64405 10.067757 -26.152634 56.033691 64406 25.514374 -25.317337 56.623734 64407 25.976120 -25.672760 56.187500 64408 36.979416 -26.086853 57.028229 64409 47.407959 -25.718994 58.429169 64410 47.358551 -24.496002 58.683456 64411 9.803215 -27.142426 56.582214 64412 10.059158 -28.356552 55.360626 64413 24.200470 -26.154587 56.836395 64414 24.572746 -27.057022 57.176544 64415 23.494644 -26.398697 57.407349 64416 24.756256 -26.648193 56.429993 64417 36.153946 -27.086639 57.390564 64418 40.343307 -27.158783 56.522888 64419 40.009415 -27.089127 55.866028 64420 34.585846 -27.595184 56.314148 64421 34.528412 -28.071686 57.255219 64422 40.970688 -26.772064 57.171906 64423 26.340347 -29.017883 56.184494 64424 30.353394 -28.424820 57.150055 64425 32.470573 -28.590851 56.266708 64426 31.965227 -28.796448 57.398346 64427 36.678497 -28.948395 55.883789 64428 36.442825 -29.645325 57.032471 64429 37.592346 -29.038269 56.735245 64430 47.646698 -28.256378 56.653870 64431 4.687622 -31.115417 55.455078 64432 4.086220 -30.221512 56.446014 64433 3.888001 -31.336777 55.669586 64434 9.405853 -28.494873 56.325134 64435 9.400711 -31.007492 55.309555 64436 10.078674 -31.791077 54.694138 64437 5.535050 -30.924759 55.437042 64438 6.471695 -30.769333 55.573013 64439 8.606583 -31.009018 55.354279 64440 7.642463 -30.512756 55.767471 64441 28.108406 -31.003113 56.232956 64442 29.152573 -31.798080 56.046417 64443 29.850853 -32.227417 56.846878 64444 30.982689 -32.329803 56.705063 64445 36.810928 -32.401672 61.575607 64446 37.271454 -31.689133 61.995712 64447 37.144455 -32.265396 62.398926 64448 2.071037 -34.231201 56.484650 64449 49.450867 -33.775879 55.832581 64450 40.519180 -34.477341 56.963043 64451 49.757355 -34.595474 56.032990 64452 38.257332 -36.453705 57.442383 64453 38.670410 -35.955933 57.413971 64454 44.477905 -37.488327 56.294159 64455 43.191422 -37.894714 56.163330 64456 2.396286 -37.015594 55.599152 64457 8.526894 -39.204727 55.088776 64458 27.600647 -37.544296 55.212570 64459 26.998962 -38.113312 56.203461 64460 33.994263 -38.261017 55.925446 64461 35.866135 -37.408905 56.310120 64462 41.881195 -38.456772 55.847061 64463 40.759506 -38.828690 55.258881 64464 45.912903 -38.235794 56.709152 64465 4.472122 -38.123840 54.600105 64466 5.604477 -39.324554 55.609192 64467 29.134201 -37.759491 55.540863 64468 28.260666 -37.648056 56.331177 64469 30.660515 -38.057434 55.481873 64470 32.160843 -38.380692 55.768677 64471 34.992348 -38.358185 56.578964 64472 36.448853 -38.126495 57.257751 64473 4.481323 -38.788635 55.219742 64474 10.243484 -40.195129 54.639946 64475 33.217049 -38.539307 56.028595 64476 33.976578 -38.831696 56.715240 64477 41.402542 -39.423233 55.355835 64478 42.166382 -39.282791 55.727615 64479 43.134872 -39.782928 55.534790 64480 48.040283 -39.798828 56.497742 64481 48.075256 -38.565979 56.669250 64482 48.845795 -39.724182 55.870621 64483 10.620537 -41.321289 55.120056 64484 9.963188 -40.578217 55.563217 64485 11.351875 -42.726791 54.599472 64486 26.261604 -40.821106 56.102264 64487 45.914917 -40.660873 55.609253 64488 45.166641 -40.216263 56.279114 64489 10.862350 -42.275070 55.657654 64490 11.199028 -43.157532 55.192612 64491 25.442795 -43.029099 55.393616 64492 26.320221 -42.383331 56.529785 64493 34.400337 -42.787399 56.328217 64494 11.548958 -44.007690 54.888916 64495 20.303230 -43.549393 54.944519 64496 20.837006 -42.802841 55.527908 64497 22.412086 -43.380402 55.762894 64498 24.451134 -43.840851 55.516815 64499 25.457565 -43.673584 56.314316 64500 30.019470 -43.624390 55.700211 64501 39.514435 -43.199783 56.780823 64502 19.684120 -43.922302 55.643066 64503 23.492455 -43.930145 56.018555 64504 22.747101 -43.531555 56.810669 64505 29.056465 -45.110855 54.911575 64506 11.505295 -44.736908 55.620972 64507 11.201553 -45.352081 56.306244 64508 11.369186 -45.921112 55.421509 64509 20.334167 -45.752853 54.924217 64510 19.880447 -45.993790 55.791107 64511 19.738083 -45.157791 55.768631 64512 29.242607 -46.361176 55.097351 64513 6.960419 -47.538818 54.489182 64514 10.095154 -47.234650 54.393211 64515 10.258621 -46.534271 56.008698 64516 28.985847 -47.260696 54.852997 64517 30.010818 -45.744934 55.906616 64518 3.150322 -47.906052 55.398193 64519 3.004379 -48.534943 54.821648 64520 4.101982 -47.718262 55.194443 64521 27.501770 -47.839050 54.159386 64522 28.369362 -47.999557 54.813736 64523 29.436737 -48.187775 55.704010 64524 2.643791 -48.222687 55.523895 64525 2.379898 -48.982422 55.319702 64526 4.937615 -46.784439 56.651947 64527 27.524414 -48.327896 55.095749 64528 28.390244 -48.416214 55.414215 64529 37.701447 -51.800415 54.862244 64530 2.590965 -51.450180 54.000595 64531 7.899131 -52.114349 54.468803 64532 8.900269 -51.665115 55.102722 64533 9.974960 -51.678635 54.678474 64534 10.974556 -51.831146 55.273132 64535 11.576477 -52.549988 54.338730 64536 3.193573 -52.252808 54.028351 64537 5.012138 -52.845184 54.152916 64538 4.014626 -52.402512 54.713165 64539 5.965088 -52.577621 54.627502 64540 11.364761 -54.199890 53.792885 64541 36.921181 -52.680481 55.699432 64542 36.037811 -52.743683 55.368423 64543 23.036774 -55.262405 54.745857 64544 22.397499 -55.799164 54.724258 64545 26.002281 -54.489883 54.663452 64546 31.295944 -54.337387 55.461868 64547 8.140518 -55.944916 54.035995 64548 8.866074 -55.395889 54.945580 64549 33.753021 -56.534653 54.299164 64550 3.465881 -57.371201 54.696472 64551 3.767166 -57.322388 53.587044 64552 4.699402 -56.737366 54.503654 64553 7.211395 -56.051712 54.539284 64554 32.581459 -57.410919 54.621292 64555 31.368103 -57.790222 54.181702 64556 19.402031 -58.202789 53.730469 64557 27.073318 -59.877609 54.339989 64558 28.024376 -59.854538 54.954575 64559 36.255249 -58.603424 54.438461 64560 18.692780 -58.248642 54.428284 64561 18.428497 -59.800186 54.658257 64562 27.525322 -61.385910 55.137817 64563 29.188606 -59.791534 55.414093 64564 35.856514 -59.109894 54.606094 64565 39.699211 -61.111084 54.278000 64566 38.774628 -60.813782 53.851723 64567 3.121559 -62.349762 54.065544 64568 3.014183 -61.137238 55.497437 64569 35.413910 -59.879791 54.387085 64570 40.684158 -60.113159 54.182869 64571 11.713211 -61.425827 55.063995 64572 11.851173 -61.991211 54.364243 64573 11.551064 -62.132431 54.103722 64574 20.918793 -60.750702 54.216087 64575 19.863327 -60.034821 54.112968 64576 40.602356 -61.735382 53.976891 64577 40.914383 -60.847198 54.100662 64578 9.791397 -61.545547 54.071220 64579 10.853836 -61.660126 53.907845 64580 10.925201 -62.622757 53.695808 64581 21.993210 -61.538635 54.569283 64582 33.710922 -63.735550 55.937271 64583 38.241135 -62.326889 53.846657 64584 39.718750 -62.545624 53.911850 64585 4.620468 -63.025436 54.077095 64586 5.040459 -64.688782 53.312393 64587 6.856201 -63.786102 52.653770 64588 6.619194 -63.058212 53.286942 64589 6.231491 -64.059738 52.895027 64590 23.917557 -62.657532 54.781189 64591 5.905808 -65.995605 54.211853 64592 5.556679 -63.450211 53.329643 64593 3.868904 -65.176331 52.675034 64594 11.484367 -62.841049 54.362267 64595 11.799339 -62.343582 54.552513 64596 25.086807 -63.020737 54.555519 64597 37.389809 -63.778625 53.855301 64598 36.710556 -64.866562 53.808983 64599 35.911224 -65.041077 53.519699 64600 4.758988 -66.348389 53.919861 64601 5.630470 -62.940735 53.700584 64602 9.976913 -64.358871 53.718658 64603 38.843102 -63.558868 53.778198 64604 3.651077 -66.456039 52.154999 64605 4.209396 -65.888168 53.200638 64606 8.037148 -65.793915 54.482147 64607 7.025597 -65.813919 54.137177 64608 3.859444 -66.942017 53.278938 64609 19.474823 -67.260605 54.059326 64610 20.707626 -69.466812 56.345917 64611 21.955750 -69.000549 55.732086 64612 20.909073 -68.253723 55.059860 64613 22.226379 -68.588501 55.214890 64614 14.450829 -67.338043 53.839027 64615 21.282181 -67.426025 53.811569 64616 22.486893 -68.163239 54.366447 64617 23.237198 -67.773346 53.460678 64618 31.088196 -67.613708 53.796097 64619 4.171791 -68.862686 53.564156 64620 24.230415 -68.764572 54.253098 64621 25.045853 -68.508591 53.401596 64622 29.810661 -68.698456 53.103188 64623 30.521378 -68.521317 53.815659 64624 4.995575 -70.795013 52.512924 64625 4.784844 -70.070419 53.301804 64626 11.193466 -70.880066 53.443336 64627 11.424240 -70.770889 54.147873 64628 25.753654 -69.389938 54.201218 64629 26.721497 -69.442673 53.766685 64630 27.809418 -69.738190 54.063477 64631 29.040436 -69.489258 53.892807 64632 16.074081 -71.626053 53.067360 64633 18.694458 -70.482254 52.799942 64634 18.520027 -70.915222 53.181725 64635 19.955505 -71.284424 53.269928 64636 18.505112 -71.749207 53.639641 64637 22.179199 -72.554840 53.943550 64638 21.361893 -72.501602 53.930450 64639 22.147987 -71.743408 53.324745 64640 29.802734 -69.239731 53.774490 64641 6.026146 -72.440948 53.696709 64642 19.461548 -72.570694 54.046906 64643 23.309013 -72.180038 53.248413 64644 25.586151 -73.342178 52.196465 64645 24.860596 -73.694504 52.589340 64646 15.765198 -72.676865 53.052391 64647 24.128967 -72.612930 52.911057 64648 6.613457 -73.459702 53.926033 64649 23.608482 -72.775925 53.440590 64650 23.675064 -73.615814 53.327316 64651 11.093292 -75.534393 52.943222 64652 19.377441 -74.994125 51.694550 64653 19.912521 -74.525040 52.841644 64654 23.142662 -74.399200 53.084808 64655 24.082458 -74.667053 52.653915 64656 25.044540 -74.972900 52.169525 64657 10.359650 -77.693680 52.110603 64658 8.149673 -75.332352 53.749168 64659 17.447258 -75.261795 53.075134 64660 6.758896 34.735184 60.634186 64661 8.273605 31.990997 62.337524 64662 7.354416 32.915451 61.878540 64663 8.617409 33.376190 61.614197 64664 8.541153 34.684845 60.416321 64665 9.302826 32.117767 62.161819 64666 6.306160 32.442047 61.625244 64667 5.197060 31.309692 61.168518 64668 11.498215 30.112000 60.824005 64669 17.403358 28.628326 59.385376 64670 10.983192 30.461639 61.228302 64671 9.693298 30.273911 61.790070 64672 10.399110 31.462982 61.716217 64673 8.505142 27.701202 60.848557 64674 8.624985 28.545471 61.432800 64675 9.521584 28.476273 60.706345 64676 9.561630 27.727203 59.966873 64677 8.257004 26.972885 60.595963 64678 8.350876 26.416199 60.545502 64679 19.652573 25.119492 60.060989 64680 20.565681 24.973877 60.469452 64681 19.715408 24.937241 61.844482 64682 19.301109 25.267502 61.250671 64683 9.457916 25.227966 60.204910 64684 10.176308 25.132965 61.182404 64685 13.185295 24.536850 60.075912 64686 14.972900 24.973267 61.057129 64687 16.933968 24.868607 60.177246 64688 21.309570 24.351303 61.180267 64689 20.567932 24.074493 62.108551 64690 21.809265 23.465149 61.296783 64691 22.612076 22.382507 59.963593 64692 21.941277 21.799500 60.176880 64693 22.159958 22.548553 60.715134 64694 21.371765 21.589935 61.098175 64695 11.788315 17.542908 60.011688 64696 12.512786 18.344757 60.517441 64697 12.331955 17.286133 59.952621 64698 11.502716 18.419403 60.764542 64699 12.085304 18.815750 60.619598 64700 28.577011 16.557129 59.883331 64701 32.541512 16.914505 59.989578 64702 32.129494 17.699783 59.695312 64703 11.887817 16.452118 59.840912 64704 11.210434 17.103210 60.343491 64705 13.206253 16.760162 60.443054 64706 20.859924 17.290833 60.226883 64707 21.786400 16.214417 60.477905 64708 3.134606 16.404068 60.692902 64709 13.228424 14.375732 59.547607 64710 13.237839 13.357117 59.259155 64711 12.581291 13.675964 59.248184 64712 2.881149 14.745117 60.297211 64713 3.006912 14.314835 59.133453 64714 3.171448 13.338272 58.776382 64715 11.707123 15.313385 59.667297 64716 10.965935 15.658600 60.591232 64717 12.144257 14.466553 59.415848 64718 12.665787 15.472412 59.632874 64719 13.533585 15.399109 60.065460 64720 11.403061 14.381485 59.931320 64721 11.993568 13.434586 59.494186 64722 11.468491 13.226456 60.104492 64723 13.970810 13.396301 59.709900 64724 34.339012 14.537613 60.328781 64725 12.706451 12.776489 59.227722 64726 12.220200 12.106323 59.669418 64727 11.559280 12.456924 60.342453 64728 13.676056 12.425385 59.292175 64729 24.626373 13.561584 62.369354 64730 24.322044 13.883759 63.287506 64731 23.916611 14.269516 62.981140 64732 12.935097 12.022095 59.234116 64733 14.600586 11.715302 59.617615 64734 14.338486 12.591614 59.655991 64735 13.459572 11.279053 59.380035 64736 24.302513 11.575287 59.723145 64737 23.210693 14.744110 61.436920 64738 36.461716 11.142151 59.537903 64739 3.641525 10.705994 59.031097 64740 24.439529 10.806274 59.505905 64741 25.089737 12.724976 61.803589 64742 25.313103 11.899902 61.736145 64743 25.326996 12.601837 62.637527 64744 36.713882 10.015747 59.280792 64745 35.776184 9.743866 59.638824 64746 12.579895 10.918335 60.104889 64747 15.479248 9.635910 59.706055 64748 15.065797 8.342606 59.375763 64749 13.926300 8.858963 59.686676 64750 13.770142 10.089630 59.629807 64751 14.628967 10.664276 59.420319 64752 15.305466 10.851028 59.765289 64753 24.926033 10.873703 60.451416 64754 25.361893 10.069473 61.590607 64755 25.421829 11.047333 61.737305 64756 24.410446 10.086182 59.510681 64757 12.841995 9.749130 60.742691 64758 12.075562 11.238220 61.159424 64759 15.276023 7.016418 59.760315 64760 13.865280 7.493942 59.492584 64761 24.114395 7.912506 59.796524 64762 34.161659 9.514557 60.741440 64763 35.027847 10.705673 60.526489 64764 3.175942 8.562454 58.778351 64765 15.384712 6.206268 60.249176 64766 14.915070 5.943268 59.995605 64767 14.015152 6.641571 59.318741 64768 16.003029 8.413239 59.809387 64769 24.746063 9.195038 60.342667 64770 23.845474 6.820572 60.426208 64771 23.488045 6.934097 59.317047 64772 23.100449 6.113495 59.590179 64773 28.401611 7.817169 60.107544 64774 34.023071 8.378250 59.928009 64775 2.266571 6.857178 59.479065 64776 2.276367 6.768814 58.742615 64777 2.649498 7.883377 59.582031 64778 12.936722 7.986664 60.626068 64779 14.426102 6.145569 59.470200 64780 2.435181 6.097931 59.178070 64781 13.494019 6.690918 59.477966 64782 13.674667 5.883598 59.936996 64783 13.032814 6.634201 60.039703 64784 13.009705 5.786713 60.205566 64785 36.207367 3.715126 60.873779 64786 36.568794 3.990295 59.515945 64787 4.220955 4.397850 58.724365 64788 5.036110 4.566223 59.315186 64789 6.222107 4.204971 58.566452 64790 37.062195 3.295654 59.228821 64791 28.273720 4.279427 58.839508 64792 8.240730 2.971436 59.467621 64793 7.871566 2.812515 60.139954 64794 22.162651 2.825638 59.332886 64795 28.215584 5.104645 59.752075 64796 5.974281 1.027557 58.228043 64797 26.384773 0.805695 60.881180 64798 37.486023 1.949722 58.676117 64799 3.623047 0.204330 58.477158 64800 4.168228 0.688797 59.255280 64801 38.746902 0.400787 59.071991 64802 30.119888 -0.810165 58.754303 64803 30.821625 -0.772278 60.120178 64804 41.448715 -1.034363 59.026718 64805 42.104446 -2.266861 58.688324 64806 41.091995 -1.724442 59.544403 64807 26.700607 -1.728271 59.914566 64808 27.061661 -0.993027 60.782654 64809 26.326935 -2.371262 59.526962 64810 3.466416 -4.004044 58.021042 64811 2.809502 -3.061356 58.325638 64812 30.137955 -2.238464 58.588943 64813 30.498047 -1.673965 59.482147 64814 31.212646 -2.682541 59.462646 64815 4.372452 -4.366150 58.426682 64816 8.554070 -5.053085 58.476013 64817 7.581711 -4.752182 59.099365 64818 8.581924 -4.922958 59.319611 64819 9.842880 -6.817581 58.457550 64820 10.425644 -6.995438 57.766357 64821 24.460701 -6.018127 58.484924 64822 32.426651 -3.317261 59.736038 64823 35.117630 -3.934540 60.859985 64824 34.573959 -4.255936 59.608795 64825 33.512787 -3.289703 60.732101 64826 33.320892 -3.868896 59.371124 64827 39.511703 -4.629440 60.243011 64828 39.863174 -3.500183 60.496918 64829 5.862038 -5.124878 57.650497 64830 10.680473 -7.148499 57.510895 64831 40.216446 -2.138062 60.351074 64832 40.647293 -1.858139 59.953537 64833 25.043747 -5.135269 59.662033 64834 25.025482 -7.102570 58.341766 64835 24.933029 -6.638031 59.337463 64836 37.669479 -5.283325 59.656128 64837 38.759567 -5.230682 59.678757 64838 9.937805 -7.491516 58.258789 64839 31.991243 -7.829849 58.669144 64840 31.934198 -7.384872 59.535202 64841 8.619995 -7.718826 58.821442 64842 7.416199 -7.645615 60.806274 64843 5.906708 -8.538773 58.805115 64844 26.079674 -7.557617 58.309753 64845 2.040550 -11.582108 58.860321 64846 3.033287 -10.139267 59.730469 64847 2.144470 -11.570084 59.681976 64848 37.355087 -10.410873 59.545349 64849 37.047539 -10.794907 58.377289 64850 44.270691 -10.375305 58.199905 64851 19.557190 -11.072830 58.521545 64852 18.731972 -11.549301 58.717041 64853 18.738365 -10.568558 59.027832 64854 19.933029 -11.867065 58.070358 64855 20.394623 -11.589645 58.425385 64856 20.443970 -10.827255 59.181122 64857 36.158081 -11.449890 58.117065 64858 19.358582 -11.732056 58.178192 64859 18.429657 -12.331085 59.033569 64860 20.762894 -12.681824 58.055389 64861 33.458694 -11.521240 57.904083 64862 33.177872 -10.858902 58.381500 64863 35.510178 -11.901001 58.302277 64864 45.440216 -13.494446 58.543060 64865 45.356598 -12.696686 58.618774 64866 18.723564 -13.332565 58.883392 64867 35.000687 -12.202652 58.062744 64868 21.939537 -12.817780 59.025238 64869 23.166466 -13.541122 59.598785 64870 21.878830 -13.592621 57.904602 64871 25.789574 -15.392319 57.933289 64872 24.782852 -15.122162 57.740540 64873 44.206833 -15.353241 60.055511 64874 44.677841 -14.767136 59.225830 64875 43.767212 -15.806305 59.133102 64876 44.341644 -15.352417 58.372467 64877 21.940536 -16.848343 58.400253 64878 23.289459 -17.360931 57.683426 64879 29.501007 -18.628067 58.214203 64880 29.691910 -19.337799 58.879120 64881 28.812691 -19.308258 58.986069 64882 25.582954 -18.369797 58.050049 64883 29.452026 -16.780594 58.452393 64884 40.188049 -16.663239 58.035599 64885 1.834877 -23.873886 56.611496 64886 26.820755 -18.665939 58.777924 64887 25.062363 -18.220551 58.659256 64888 28.069107 -18.799484 58.042175 64889 25.894028 -18.270676 59.703796 64890 37.808563 -19.096741 57.150482 64891 43.054535 -20.937119 56.918762 64892 43.577103 -21.027908 58.048615 64893 44.297485 -20.463150 58.461884 64894 44.041656 -21.776596 59.414673 64895 48.539932 -20.176025 57.772018 64896 47.965973 -20.553833 58.434036 64897 47.347992 -19.608719 58.235245 64898 40.202179 -18.710571 58.725342 64899 43.133652 -21.971588 57.948883 64900 48.490128 -21.588242 58.080414 64901 7.480362 -24.302567 57.088593 64902 38.842545 -23.730850 57.493057 64903 39.243088 -22.978455 57.812561 64904 47.857040 -22.730347 58.417450 64905 2.117691 -24.489197 56.631668 64906 2.395081 -24.136429 57.679596 64907 3.495628 -24.884949 57.016449 64908 4.793671 -24.911285 57.108841 64909 10.155136 -26.039734 56.893738 64910 26.184608 -25.487595 58.288391 64911 26.357285 -25.629150 56.995865 64912 43.139099 -22.845078 58.840622 64913 8.812134 -24.370575 57.021591 64914 23.650116 -25.767731 57.355438 64915 42.034317 -25.445465 58.551315 64916 9.605865 -24.278854 58.717102 64917 9.531830 -25.433319 58.782471 64918 9.761383 -26.171707 57.727753 64919 22.901115 -25.905731 57.687897 64920 25.712700 -28.214081 56.896545 64921 25.416031 -28.211136 58.380463 64922 26.955559 -25.869431 59.127533 64923 25.827675 -25.529465 59.651459 64924 37.745483 -25.874756 58.446808 64925 41.617432 -25.867767 57.572327 64926 47.586212 -27.297943 57.984863 64927 35.345001 -27.536072 57.151382 64928 35.581070 -27.785034 58.317719 64929 40.149307 -27.705887 57.369202 64930 5.390213 -29.825058 56.207733 64931 5.632698 -28.428040 57.457611 64932 4.233391 -28.738861 57.968018 64933 4.814964 -29.147980 56.923859 64934 8.471100 -29.172943 56.465897 64935 26.550514 -29.221313 57.073578 64936 30.607903 -28.410629 58.255219 64937 29.924927 -27.864700 59.322968 64938 31.014252 -28.477676 59.298721 64939 33.433914 -28.525497 57.269745 64940 33.112724 -28.807144 58.360168 64941 39.354309 -28.356323 57.393875 64942 38.570999 -28.919937 57.531540 64943 2.934578 -30.609634 57.696213 64944 7.266281 -29.155533 56.655151 64945 27.263779 -30.084442 56.834198 64946 6.321098 -29.189133 56.616730 64947 27.714409 -30.204208 58.067535 64948 28.988937 -31.672821 57.190552 64949 35.630554 -30.124039 57.095978 64950 45.668396 -31.289154 57.065445 64951 46.076416 -29.797287 59.707458 64952 45.153229 -32.013535 57.417786 64953 31.055870 -32.861603 58.369263 64954 30.337135 -32.580566 57.860077 64955 32.210777 -32.223679 56.772293 64956 33.230782 -32.667175 58.063446 64957 31.848497 -32.793961 57.657776 64958 44.475525 -33.047073 58.044754 64959 44.761169 -33.521332 59.137619 64960 45.183792 -32.484222 59.541534 64961 2.316353 -33.591400 58.034592 64962 2.089363 -34.200058 57.359604 64963 42.056061 -33.937836 57.067139 64964 43.253464 -33.215134 56.991577 64965 37.314468 -36.877975 56.893372 64966 38.193146 -37.641159 58.048279 64967 43.122772 -34.213257 58.053101 64968 49.093872 -34.730972 56.395782 64969 39.370979 -35.886612 57.664917 64970 39.674065 -35.095032 57.270050 64971 48.891785 -36.385880 56.743484 64972 2.399803 -34.735596 58.228470 64973 2.171333 -36.223083 57.196716 64974 27.549194 -37.771240 56.480896 64975 26.694710 -38.681564 56.310425 64976 44.179932 -38.491974 56.588165 64977 48.636017 -35.645248 56.751816 64978 29.170815 -38.104141 57.067520 64979 43.053909 -38.832047 56.160217 64980 3.666580 -39.085342 55.786407 64981 4.537544 -39.392044 55.659714 64982 8.278572 -40.175400 56.296417 64983 9.353447 -39.863388 55.370148 64984 31.023613 -38.666397 57.094849 64985 31.742540 -39.639786 59.586136 64986 30.802383 -39.341370 59.807388 64987 30.946884 -39.840363 60.532745 64988 32.887680 -39.084366 57.222443 64989 41.481506 -39.069382 55.706238 64990 43.849106 -39.385056 56.264282 64991 4.161293 -39.697830 56.151550 64992 2.731835 -38.785995 56.904785 64993 10.319847 -42.034821 57.457779 64994 10.735275 -42.423965 56.519623 64995 10.124275 -41.316101 56.413452 64996 26.284378 -41.574219 56.118332 64997 26.908875 -40.278320 57.349579 64998 44.783356 -39.440308 56.561050 64999 45.760880 -39.810181 56.561920 65000 11.147125 -43.418503 55.791992 65001 19.855026 -42.075409 56.637512 65002 19.929123 -43.031006 55.733780 65003 19.269958 -43.150497 56.477905 65004 21.475052 -42.521790 56.314209 65005 20.847458 -42.050095 56.629883 65006 22.039230 -42.947784 56.274292 65007 21.702591 -42.905060 55.692627 65008 26.589943 -41.324142 56.699356 65009 31.309662 -43.077682 56.409897 65010 35.461319 -43.730774 57.537476 65011 47.007721 -39.916779 56.421066 65012 33.742546 -43.447098 57.339203 65013 38.519600 -43.234131 57.277420 65014 41.663422 -43.651871 56.279816 65015 40.793945 -43.308914 56.763916 65016 41.309326 -43.388855 56.976974 65017 42.073181 -44.557556 57.203979 65018 23.924927 -44.222107 56.847626 65019 24.534485 -44.196899 56.335693 65020 26.411652 -43.413452 57.343658 65021 19.138428 -44.387177 56.834152 65022 20.299362 -46.568878 55.787109 65023 31.211060 -46.030350 56.930923 65024 30.747971 -44.341766 56.604492 65025 7.019913 -46.890869 55.704956 65026 7.968933 -46.741272 56.274323 65027 7.430588 -46.482971 56.498611 65028 6.988823 -46.407364 56.763016 65029 8.812744 -46.961456 55.877960 65030 22.837051 -48.037643 57.124939 65031 21.652718 -48.013626 57.502075 65032 30.368164 -47.259872 55.966492 65033 31.266464 -47.895279 56.467438 65034 30.566856 -48.170685 56.061737 65035 29.625504 -47.042694 55.427399 65036 41.601929 -47.242218 56.327454 65037 3.151672 -47.679901 56.177475 65038 3.991615 -47.115173 56.325012 65039 25.295792 -48.137604 56.452332 65040 26.699867 -48.366913 55.822479 65041 30.734497 -48.884933 56.683136 65042 2.666878 -48.413116 57.377380 65043 2.432114 -48.486130 58.478210 65044 2.553925 -49.487183 58.451782 65045 28.202316 -48.677917 56.391876 65046 26.685242 -48.504547 56.924164 65047 27.730576 -48.806244 57.627777 65048 29.493423 -48.932190 56.627655 65049 2.498573 -49.936142 55.926971 65050 40.059387 -51.246719 56.904099 65051 3.024094 -51.413834 54.992439 65052 9.719833 -51.317490 55.516724 65053 10.308273 -51.381760 55.371185 65054 6.759232 -52.100403 55.338409 65055 7.852218 -51.654099 55.958527 65056 5.095818 -52.051178 56.072510 65057 11.471893 -53.367798 55.010605 65058 34.033180 -53.251953 55.582184 65059 38.175980 -52.373062 56.106598 65060 10.543243 -54.070023 56.019501 65061 11.359962 -53.288971 55.972443 65062 11.547379 -52.490494 55.197464 65063 11.143814 -53.143829 56.583359 65064 24.901047 -54.849823 55.274063 65065 24.021164 -55.309036 55.365143 65066 35.877853 -53.404785 56.614822 65067 9.764267 -54.892731 55.124588 65068 29.340523 -54.802414 55.101227 65069 29.447159 -55.021179 55.794174 65070 27.770935 -54.872025 56.565353 65071 26.255386 -55.063950 56.235794 65072 27.110825 -54.961731 57.258316 65073 6.268929 -56.137650 54.908241 65074 7.767585 -55.572495 55.508423 65075 6.741646 -55.550720 56.727753 65076 30.305466 -55.204819 56.740082 65077 33.964233 -56.851715 55.009155 65078 34.896866 -57.081512 55.377975 65079 36.684631 -56.334686 54.579643 65080 36.367455 -56.955261 54.921715 65081 4.041664 -56.726730 55.904083 65082 20.240250 -56.913116 54.796143 65083 20.919983 -56.731033 54.761124 65084 20.817421 -56.939026 55.274811 65085 21.042404 -57.218536 55.978867 65086 20.002884 -57.105255 55.935089 65087 22.789429 -56.547409 55.535431 65088 17.375351 -58.873138 54.911613 65089 17.775635 -58.020538 55.244476 65090 18.983757 -57.286789 55.325714 65091 30.979538 -58.578186 55.138550 65092 35.194138 -58.816391 55.996582 65093 35.674080 -57.960007 55.526276 65094 35.688400 -58.866562 55.536743 65095 16.561661 -59.362473 55.248169 65096 16.759842 -58.797226 55.682846 65097 30.579941 -59.997238 56.154480 65098 36.097290 -58.549759 55.014374 65099 11.427383 -60.183167 55.109070 65100 11.550674 -59.330261 55.936966 65101 11.914032 -60.052917 56.035965 65102 10.878387 -59.739578 55.348297 65103 16.829910 -60.047958 54.973724 65104 16.136917 -60.035721 55.910416 65105 17.298187 -60.922012 55.162415 65106 29.563309 -61.054871 56.219376 65107 28.575546 -60.876328 55.658401 65108 35.149490 -60.645340 55.092026 65109 34.980141 -59.808411 55.832047 65110 10.621078 -60.711578 54.753296 65111 9.467674 -60.867111 55.580078 65112 16.364166 -60.640625 55.252136 65113 16.627609 -60.804871 55.074158 65114 18.444847 -61.430267 55.726349 65115 17.322662 -61.885208 55.993591 65116 19.823563 -60.910400 55.107239 65117 21.095337 -61.678802 55.446487 65118 2.307091 -59.300552 55.186493 65119 2.391342 -60.065338 55.290070 65120 6.945061 -62.402817 54.267189 65121 5.992745 -62.601959 54.454109 65122 7.960891 -61.983368 54.533417 65123 7.406677 -62.154190 54.486893 65124 8.580727 -61.605377 55.219574 65125 16.488937 -61.226242 55.787933 65126 22.808563 -62.155472 54.937836 65127 34.350967 -62.508499 55.164413 65128 5.127808 -62.174622 56.006165 65129 3.808441 -62.154678 55.200653 65130 3.913132 -61.517868 56.221603 65131 10.836548 -63.675369 54.412231 65132 26.039398 -63.562790 55.030426 65133 9.890907 -64.959152 54.985886 65134 23.832382 -63.483002 56.219009 65135 22.904297 -62.741776 55.895218 65136 26.705994 -62.837601 54.845062 65137 27.500626 -65.069122 56.303070 65138 26.907074 -65.503647 56.558563 65139 26.454185 -64.685944 56.016541 65140 27.326538 -63.621002 55.588226 65141 10.978783 -63.944534 56.013931 65142 8.948334 -65.527115 54.657555 65143 31.824945 -66.645248 54.806519 65144 36.212723 -65.767990 53.583176 65145 5.076874 -67.117477 54.909912 65146 4.759262 -67.912247 55.238892 65147 4.470894 -68.007248 54.658470 65148 4.227326 -67.551254 54.003296 65149 13.086922 -68.546738 54.664444 65150 12.343613 -69.690552 55.332443 65151 13.134262 -69.168686 56.158173 65152 13.810028 -67.643845 53.949318 65153 31.132210 -67.789902 54.694862 65154 30.131241 -68.893143 55.584473 65155 29.671837 -68.713425 56.531937 65156 30.408707 -68.557312 56.232361 65157 5.406983 -71.080872 53.562523 65158 11.870140 -69.615173 54.052299 65159 31.045143 -67.942398 55.916656 65160 26.862579 -70.173294 55.038559 65161 27.735512 -70.244141 55.189346 65162 28.592148 -69.646606 55.678665 65163 29.871307 -69.167282 54.539467 65164 27.751572 -69.233139 57.237854 65165 28.686890 -68.534103 57.180252 65166 5.771416 -71.269257 54.810349 65167 10.714935 -73.325943 55.535187 65168 11.465164 -71.623413 55.495636 65169 10.860413 -74.121231 54.091698 65170 16.683655 -73.539627 53.750244 65171 16.948425 -74.611725 53.456360 65172 17.510368 -72.680710 53.903664 65173 20.419189 -72.668106 54.009026 65174 11.778458 -70.482117 55.016968 65175 16.580368 -72.048599 53.471275 65176 18.617294 -72.842422 54.154182 65177 22.886192 -72.699921 53.688171 65178 19.176224 -74.226929 53.760353 65179 18.332291 -74.548904 53.786652 65180 18.434540 -73.770157 54.118896 65181 21.280838 -73.534119 53.812012 65182 22.383270 -73.444794 53.763229 65183 7.243561 -73.779144 54.763443 65184 17.751236 -74.822220 53.560806 65185 17.595703 -74.101410 53.934402 65186 20.138458 -73.630905 53.847931 65187 7.444832 34.380737 60.986984 65188 9.857590 32.621658 61.755432 65189 10.626427 32.567810 61.271271 65190 11.254089 31.815186 61.106567 65191 9.949631 33.193146 61.274246 65192 11.693710 31.918701 60.713684 65193 11.811111 31.041412 60.718048 65194 11.231857 31.145432 61.252945 65195 4.155953 29.789490 61.081467 65196 3.910179 29.150391 60.996979 65197 9.024033 29.333527 61.720032 65198 9.421753 28.873230 61.205719 65199 7.939285 26.860352 61.387619 65200 7.334976 26.561035 62.330093 65201 7.288879 27.410767 62.287460 65202 4.490135 27.057098 62.740646 65203 3.914528 26.248611 61.640137 65204 3.933991 27.871643 61.220428 65205 8.630035 25.810699 61.082123 65206 16.235825 25.097458 61.368851 65207 17.995728 25.228424 61.004440 65208 19.325264 25.237427 60.543304 65209 9.335205 25.295593 61.165070 65210 12.946274 24.899567 61.001099 65211 12.191742 25.135376 61.625153 65212 17.214554 25.029938 62.422546 65213 21.736816 22.509857 61.459839 65214 20.537735 18.586517 60.856232 65215 20.853729 19.314285 62.105347 65216 12.160042 19.191681 60.898422 65217 13.809570 18.795547 61.899658 65218 13.364456 18.307739 61.127579 65219 12.989746 19.765945 61.607147 65220 11.693169 19.615387 61.425049 65221 11.983856 20.514343 62.105713 65222 10.667442 17.250137 61.409546 65223 10.598550 18.091324 62.411591 65224 10.996429 18.833893 61.731583 65225 21.533241 17.178955 61.455612 65226 21.106598 18.076752 61.783234 65227 30.022713 16.266357 60.324280 65228 30.755760 14.902328 60.649918 65229 31.365318 16.546188 60.424896 65230 31.723192 15.496384 60.862717 65231 30.994080 15.778015 60.760071 65232 13.996468 17.724487 61.825439 65233 22.427979 15.463135 60.517731 65234 22.400574 15.831482 61.033096 65235 30.966957 13.550949 60.653656 65236 32.668846 15.704895 60.524750 65237 2.968308 13.135483 59.998108 65238 10.581223 15.050812 61.593628 65239 10.468147 15.975403 61.714478 65240 15.151779 13.443924 61.391418 65241 14.386520 14.605698 60.827850 65242 15.302208 14.284348 62.238953 65243 14.398674 16.362793 61.826813 65244 14.960831 15.407410 62.374786 65245 23.317932 14.710022 63.284119 65246 22.755417 15.421844 63.046722 65247 33.533890 14.878525 60.566132 65248 10.988678 13.999619 61.045563 65249 14.779411 12.833679 60.361832 65250 24.529099 12.627686 60.880264 65251 32.416031 14.351273 60.962601 65252 33.754517 13.849777 60.852661 65253 11.245110 13.011505 60.614990 65254 3.161713 11.326324 60.628448 65255 11.893471 11.780273 60.441101 65256 30.858170 12.587906 60.823456 65257 31.082840 11.926758 61.309570 65258 30.273605 11.747147 60.578705 65259 34.732399 11.997253 60.705078 65260 33.960571 12.886047 60.971802 65261 15.413361 11.672318 60.388519 65262 15.496307 12.472290 61.172058 65263 15.903503 10.697937 60.367432 65264 30.373718 10.777252 61.105911 65265 3.220703 9.539642 59.704285 65266 16.995270 9.901672 61.001740 65267 16.628014 8.933273 60.309784 65268 12.598281 8.966064 61.704651 65269 17.158859 8.894470 60.867432 65270 29.588585 8.689651 61.437073 65271 30.550667 8.159714 61.947723 65272 29.374771 7.390396 61.249084 65273 16.677002 7.974182 61.000107 65274 32.995216 7.878067 61.070053 65275 28.354881 6.131897 60.168381 65276 33.492050 6.654510 60.456284 65277 3.211578 5.872559 60.500549 65278 12.403992 6.602325 60.942780 65279 14.361862 5.764816 59.832428 65280 15.649582 6.494385 60.914169 65281 16.062546 7.093643 60.874283 65282 24.685509 7.958878 61.059479 65283 24.462044 6.920502 62.002716 65284 33.523941 5.992371 60.839508 65285 2.590065 7.068283 60.344238 65286 5.018349 5.134460 60.577362 65287 5.806213 4.904465 59.969177 65288 7.278053 4.923203 61.021851 65289 7.809173 4.349899 60.954117 65290 12.301376 5.361710 61.177612 65291 12.652420 5.826370 60.537277 65292 13.170357 4.962769 61.194489 65293 14.435188 5.600914 60.760284 65294 13.822517 5.280304 60.929840 65295 35.420418 4.390411 60.989624 65296 34.705154 4.495247 61.419586 65297 4.115921 4.929596 59.820770 65298 21.392258 3.985916 59.438782 65299 21.896561 4.482635 60.016220 65300 21.413422 3.284088 59.340485 65301 28.778114 4.976471 60.207413 65302 29.700302 4.771660 60.859970 65303 30.341789 3.613586 60.705688 65304 5.201691 1.298904 59.776688 65305 6.849884 1.867508 59.804565 65306 3.496658 0.349319 59.480377 65307 30.452759 2.276123 60.030914 65308 31.411339 0.451706 61.039276 65309 38.130386 0.078873 61.176422 65310 38.795044 -0.144943 60.287872 65311 3.034317 0.012512 60.441223 65312 2.669342 -0.128891 61.243774 65313 2.746193 -0.967987 61.008606 65314 26.576675 -0.139542 59.992737 65315 30.845688 -1.745743 59.993927 65316 37.508713 1.223633 61.176147 65317 40.132874 -0.798599 59.708740 65318 2.893578 -1.849670 59.375427 65319 3.461144 -3.403931 59.020844 65320 4.341744 -3.842010 59.764771 65321 5.825829 -4.568283 59.117035 65322 8.401031 -4.801834 60.178375 65323 36.611534 -4.739166 60.177277 65324 39.608398 -5.119125 59.582886 65325 27.427231 -7.352982 60.372009 65326 26.561859 -7.601929 60.113647 65327 32.483551 -7.907135 59.403931 65328 4.121979 -9.232178 58.771469 65329 4.464638 -8.766983 61.533890 65330 4.158531 -9.002380 60.778381 65331 5.593102 -8.256027 61.165070 65332 17.584351 -9.765656 60.175735 65333 17.454758 -8.662384 60.185486 65334 18.344055 -9.549896 59.436874 65335 17.651642 -7.705276 59.986115 65336 18.220215 -7.384888 59.974365 65337 18.314392 -8.330673 59.594788 65338 19.076050 -7.922150 59.948822 65339 25.773132 -7.377441 59.448837 65340 32.942993 -8.663818 59.654999 65341 17.944351 -11.104660 59.984436 65342 19.028320 -8.801483 59.365509 65343 19.533554 -9.705322 59.318787 65344 19.452759 -8.717941 59.577759 65345 33.157669 -9.291290 59.237823 65346 33.180923 -9.639648 59.121704 65347 33.282745 -9.473801 59.385788 65348 39.845825 -9.892151 62.274689 65349 38.725616 -9.703156 62.602875 65350 39.309868 -9.474014 61.019287 65351 44.113083 -10.935364 59.270447 65352 42.190460 -10.848511 61.300766 65353 33.148102 -10.199036 59.275955 65354 33.197258 -9.651855 59.513428 65355 4.148407 -8.756592 64.616257 65356 3.638657 -9.608932 65.196869 65357 3.864487 -10.517212 63.847076 65358 20.982925 -11.806412 58.917587 65359 33.687553 -11.296066 59.006042 65360 33.244583 -10.489838 60.333984 65361 35.997055 -11.391312 59.103531 65362 34.719193 -11.907562 58.836197 65363 18.875046 -14.141464 59.944611 65364 18.246124 -12.816299 59.857971 65365 35.063042 -11.407669 59.899292 65366 34.197784 -11.320938 59.886856 65367 45.063507 -13.516861 59.265625 65368 44.778976 -12.386902 59.626190 65369 23.953735 -14.170944 58.886475 65370 44.084778 -13.917969 60.787903 65371 43.576431 -11.706009 60.587769 65372 44.262726 -12.193344 60.227676 65373 1.942787 -13.377777 58.892593 65374 24.875275 -14.672989 58.680695 65375 26.998329 -14.583282 60.001160 65376 27.855682 -14.736816 59.995575 65377 25.842331 -14.655762 59.388062 65378 20.633095 -16.325363 59.420517 65379 19.580017 -15.408890 60.475983 65380 20.536041 -16.254486 58.374863 65381 42.301758 -17.047913 59.240265 65382 43.459488 -16.390213 60.117523 65383 22.054855 -16.943069 59.682663 65384 23.472839 -17.570175 58.833282 65385 23.287994 -17.383865 59.972702 65386 29.221962 -16.038132 59.310699 65387 30.797699 -17.965714 58.917206 65388 30.224091 -16.784164 59.277084 65389 40.827606 -17.178391 58.504364 65390 42.782150 -17.328857 60.298859 65391 31.204773 -17.049698 60.058929 65392 31.684793 -17.772705 59.701935 65393 31.651720 -18.480240 59.312897 65394 32.162537 -18.068253 59.834229 65395 41.230911 -18.152084 59.241150 65396 32.661942 -19.542801 60.839844 65397 32.465134 -18.490509 60.234833 65398 33.019875 -18.022980 61.515533 65399 27.913208 -19.148682 58.775391 65400 30.602104 -19.206863 59.092270 65401 45.151367 -21.346924 60.077576 65402 45.988876 -21.189270 59.935669 65403 45.765228 -21.618286 60.301147 65404 46.929443 -20.535370 58.921555 65405 47.728485 -21.473648 58.733276 65406 46.739883 -21.830399 59.617523 65407 41.238647 -19.516846 59.897583 65408 41.624817 -19.999573 61.188538 65409 42.049484 -19.073700 60.966553 65410 39.614395 -22.416565 58.624786 65411 39.149109 -23.687698 58.401703 65412 39.512642 -23.373642 59.510132 65413 6.678032 -23.967041 58.077194 65414 8.023911 -23.708191 58.030182 65415 9.074219 -23.647186 58.370239 65416 9.641434 -24.205933 57.743958 65417 9.988617 -24.552734 57.735168 65418 46.975433 -23.015289 59.339035 65419 47.382034 -23.632324 58.773804 65420 3.038826 -24.492310 58.098877 65421 3.701218 -24.483414 58.363007 65422 4.614205 -24.355515 58.555161 65423 5.558479 -24.447205 57.892334 65424 21.849770 -25.399948 58.803406 65425 22.381088 -25.581924 58.044128 65426 21.808083 -25.953354 58.068222 65427 22.245216 -26.095932 57.829468 65428 23.382523 -25.244522 58.417725 65429 22.725739 -25.002594 59.727188 65430 24.882614 -25.179001 58.765366 65431 38.701599 -24.725159 59.036819 65432 38.150764 -25.776367 59.543716 65433 27.469139 -26.257309 59.821304 65434 36.806595 -26.757278 58.120178 65435 41.709320 -26.078583 58.461273 65436 41.087982 -26.855392 58.256790 65437 9.239494 -26.952927 57.701263 65438 21.812683 -26.483627 57.964783 65439 21.352135 -26.362427 58.377411 65440 21.000069 -27.328323 58.790009 65441 20.902878 -26.035446 59.238190 65442 22.549316 -26.603470 57.922577 65443 23.654770 -27.095917 58.117462 65444 23.734894 -27.895859 59.136047 65445 22.819130 -28.806702 59.467926 65446 22.426758 -28.034470 58.851334 65447 36.775932 -27.308289 60.368118 65448 37.901405 -26.249954 60.658218 65449 37.021667 -26.916519 59.336868 65450 46.533905 -26.882919 59.693649 65451 7.973678 -27.334152 58.246613 65452 6.698509 -28.199371 57.493500 65453 6.498573 -27.596100 58.406082 65454 9.021851 -27.839325 57.121185 65455 21.722656 -27.051697 58.254639 65456 29.119034 -27.207504 59.708069 65457 39.766800 -28.216309 58.429047 65458 34.280495 -28.434128 58.080627 65459 34.270401 -28.584641 59.128174 65460 2.802353 -29.145721 58.924911 65461 31.775042 -28.774979 58.638031 65462 37.488258 -29.762955 58.303101 65463 38.596817 -29.141174 58.369415 65464 39.246162 -29.670898 64.721924 65465 40.051514 -28.727798 64.550262 65466 40.083832 -29.081192 65.001083 65467 35.901237 -30.588654 58.074097 65468 36.534164 -31.131256 59.635010 65469 29.263138 -31.578644 58.493668 65470 45.689819 -31.571228 58.349274 65471 29.737617 -32.248245 57.922775 65472 31.998339 -33.274628 58.887817 65473 34.115585 -33.237305 59.123810 65474 33.486938 -33.663361 59.399170 65475 40.496155 -35.503387 57.951111 65476 40.254608 -36.419327 58.390991 65477 41.575089 -36.282440 58.978500 65478 41.826248 -34.984390 58.038986 65479 44.080933 -34.464600 59.128052 65480 42.982025 -35.434555 59.070953 65481 28.205177 -38.483719 58.229706 65482 28.146416 -38.105865 57.483398 65483 27.298958 -38.625458 57.173309 65484 27.629593 -39.492264 58.323288 65485 28.058632 -37.869614 57.008911 65486 29.164795 -38.606750 58.861145 65487 30.580978 -38.991730 58.748901 65488 29.969147 -38.506729 57.868896 65489 38.308990 -38.644470 58.761826 65490 36.953979 -38.630371 57.963547 65491 38.741280 -36.608749 57.876053 65492 34.177940 -39.599609 58.063751 65493 33.991020 -39.211853 57.312836 65494 35.276886 -39.029938 57.558350 65495 3.977432 -41.019272 57.442688 65496 4.877495 -41.852707 57.924408 65497 5.553475 -41.106934 57.158875 65498 6.587616 -40.349762 56.603500 65499 6.419876 -41.040756 57.266235 65500 5.027657 -40.392105 56.563492 65501 9.369965 -40.528687 56.322968 65502 9.040970 -41.122711 57.473679 65503 35.692245 -39.729538 58.606323 65504 36.796112 -39.244186 58.399261 65505 3.619034 -40.094803 56.886810 65506 2.463501 -39.837631 58.136551 65507 18.818710 -42.232407 57.309845 65508 20.511871 -41.568176 57.223694 65509 19.849007 -41.166718 57.752060 65510 20.946838 -41.767990 57.269806 65511 27.059013 -41.411346 57.597321 65512 21.402145 -42.261978 57.269852 65513 21.942566 -42.834763 56.903854 65514 27.217300 -42.465179 58.050812 65515 31.651522 -44.101456 57.189438 65516 33.599091 -44.501831 58.267517 65517 32.607750 -44.031631 57.728134 65518 36.958740 -43.535919 57.557770 65519 37.771515 -43.312592 57.410522 65520 41.404663 -43.791412 57.388474 65521 41.574432 -44.891113 58.342667 65522 10.995079 -43.772293 56.790085 65523 18.720749 -43.220078 57.256775 65524 19.093613 -41.418900 57.674240 65525 26.475922 -43.895569 58.174500 65526 25.248001 -44.199432 57.355743 65527 25.522095 -44.334076 59.292831 65528 10.795837 -45.115128 57.257660 65529 19.625626 -46.024551 56.698761 65530 42.226135 -45.903809 57.252762 65531 6.203110 -46.593719 56.634201 65532 10.115676 -46.206985 57.518723 65533 42.205170 -47.308884 57.715317 65534 2.432449 -48.594299 56.075531 65535 23.955872 -48.058380 57.020859 65536 25.905502 -48.644272 58.454742 65537 32.122482 -47.416458 57.120789 65538 32.236427 -46.217041 57.779297 65539 32.988091 -46.945084 57.829651 65540 32.158249 -48.744537 56.881866 65541 29.658875 -49.225754 57.719284 65542 33.527542 -48.894196 57.460114 65543 32.946976 -48.161392 57.188156 65544 33.773453 -47.710480 57.876480 65545 32.908417 -48.896286 56.978607 65546 34.348953 -48.318314 58.031876 65547 42.235031 -48.165848 58.309021 65548 41.354538 -48.995651 57.097763 65549 41.818481 -49.028992 58.514374 65550 32.052612 -49.596954 57.707596 65551 32.818184 -49.305862 57.206955 65552 3.310654 -51.279907 56.153503 65553 9.108718 -51.257217 56.580490 65554 10.187973 -51.368546 57.047714 65555 10.277283 -51.319733 56.110626 65556 10.857498 -51.789597 56.654388 65557 2.902207 -50.287262 57.155197 65558 3.900459 -51.909760 55.625458 65559 4.063675 -51.762344 56.221588 65560 6.711548 -51.661331 56.972275 65561 11.018166 -52.496201 57.008438 65562 11.385513 -52.554443 56.023483 65563 37.237717 -53.201401 56.732025 65564 37.991898 -53.073639 56.794479 65565 33.405182 -54.621262 57.477142 65566 31.684221 -54.645935 56.543396 65567 32.186485 -55.205887 57.677460 65568 34.341591 -53.660645 56.498154 65569 38.762070 -52.725128 56.955917 65570 9.091263 -54.892883 55.953583 65571 9.585571 -54.356216 56.946991 65572 28.990356 -55.209808 56.930664 65573 31.171654 -55.733566 58.072327 65574 5.318359 -56.100082 56.110031 65575 24.817307 -56.182053 56.386887 65576 25.852791 -55.925110 57.019867 65577 26.435295 -55.370987 57.259552 65578 3.528916 -57.028320 56.557495 65579 17.668823 -57.789871 56.236313 65580 18.638535 -57.207520 56.123947 65581 19.145180 -57.095901 56.079941 65582 20.565567 -57.624817 56.931946 65583 23.683067 -57.432770 56.596756 65584 23.694153 -56.243439 55.746216 65585 33.488708 -57.642105 55.546631 65586 35.796432 -56.949448 55.254242 65587 2.585907 -59.071655 55.689087 65588 32.574097 -58.407349 55.834167 65589 32.375427 -58.030228 55.361206 65590 34.071243 -58.628494 56.079956 65591 12.238861 -60.504089 57.712341 65592 11.736496 -62.436234 56.686081 65593 11.651260 -58.583130 56.810852 65594 10.850616 -58.891937 56.282791 65595 32.132095 -59.351364 56.241806 65596 10.065826 -59.902573 55.933350 65597 28.236282 -60.341660 55.348236 65598 2.808800 -59.935486 56.077530 65599 15.915695 -60.830826 57.049316 65600 34.772598 -61.274048 55.962906 65601 11.585487 -62.847595 55.206268 65602 16.583878 -62.318024 57.032959 65603 17.930824 -62.758774 56.900726 65604 19.786591 -62.366425 56.682434 65605 21.625626 -62.854095 56.766724 65606 22.107773 -62.168304 55.545868 65607 28.479393 -62.258850 55.962830 65608 7.061386 -62.136536 55.490204 65609 7.517464 -62.110611 57.396118 65610 6.342507 -62.243896 57.298615 65611 6.992775 -62.451065 58.241333 65612 16.900352 -63.345398 57.365097 65613 25.087692 -64.029358 55.828125 65614 34.299713 -62.571030 55.808517 65615 10.602753 -64.741119 57.902252 65616 11.255020 -63.524994 57.464691 65617 11.205811 -63.627182 58.523148 65618 22.961990 -63.788666 57.139801 65619 33.432159 -64.427658 56.079132 65620 10.407837 -64.812851 56.064926 65621 9.948799 -65.307709 56.193130 65622 8.693642 -66.012222 56.062012 65623 28.367859 -64.025848 56.292725 65624 33.029358 -64.860596 56.316666 65625 6.517395 -66.678787 55.696991 65626 33.418488 -64.228775 56.566681 65627 31.732515 -66.898254 55.680969 65628 14.311317 -68.660461 56.091064 65629 14.556000 -67.872040 54.681740 65630 19.671677 -70.249146 57.428665 65631 21.107422 -70.256241 57.002029 65632 4.792969 -68.731842 55.048599 65633 5.043312 -69.939819 54.476944 65634 23.457169 -69.511063 55.789856 65635 25.452347 -69.968506 55.596390 65636 24.751724 -70.321136 56.639313 65637 5.503555 -69.690979 56.065918 65638 6.179642 -71.435562 55.964722 65639 6.480019 -72.550415 54.919342 65640 16.598366 -72.727188 53.772263 65641 19.209885 -73.438538 54.154007 65642 9.034081 -72.003555 58.803238 65643 9.929543 -72.183228 59.005478 65644 10.048050 -72.534790 58.117416 65645 9.822174 -74.021072 55.962692 65646 9.939758 -74.573959 55.199188 65647 8.625168 -74.048889 55.787750 65648 10.265855 -76.136948 53.591515 65649 9.237152 -75.357681 54.560791 65650 10.155296 -75.499786 54.134041 65651 7.405846 33.695465 61.497253 65652 7.270859 31.870850 62.297668 65653 4.656738 29.649139 61.891983 65654 7.848236 30.452667 62.377441 65655 9.150833 31.196640 62.253326 65656 5.527504 29.290741 62.777618 65657 5.766312 28.712387 63.063828 65658 5.056374 28.226837 62.827515 65659 7.824058 28.933914 62.202652 65660 7.862823 27.971756 61.827454 65661 7.276169 28.253128 62.444275 65662 7.944160 26.048767 62.053146 65663 4.184097 25.266190 62.311829 65664 9.073013 25.522614 62.465485 65665 10.339844 25.432678 62.528702 65666 11.233566 25.282440 62.154373 65667 13.080139 25.182281 61.969604 65668 13.990189 25.090851 62.497406 65669 15.161804 25.121353 62.369385 65670 15.964287 24.784851 62.851379 65671 18.621300 25.136642 62.171448 65672 19.605804 22.234970 64.542557 65673 18.714417 21.892593 64.818588 65674 19.628525 22.907654 64.087372 65675 3.830422 21.689011 60.604370 65676 4.201050 24.205246 62.060303 65677 4.051453 22.902802 61.725677 65678 3.553108 18.092010 61.736816 65679 13.799309 21.137329 62.709106 65680 12.950089 20.858353 62.065002 65681 12.777702 21.301514 62.496063 65682 21.254059 22.525696 62.046738 65683 11.288773 19.825439 61.931030 65684 11.896843 21.226364 63.276917 65685 12.326134 22.375870 63.729675 65686 12.984787 21.938416 63.019379 65687 20.890167 20.944641 62.494232 65688 11.097305 19.684296 62.744736 65689 20.906097 18.437454 63.304993 65690 14.211060 19.702988 62.696548 65691 10.486542 16.901733 62.660583 65692 20.742607 19.709106 63.347595 65693 3.133873 16.394714 62.194611 65694 13.891487 15.755173 60.690125 65695 22.097656 16.351685 62.243073 65696 3.880379 17.442993 64.386734 65697 4.339737 17.147552 65.693939 65698 3.400253 15.969315 64.813293 65699 2.822029 15.008286 61.188583 65700 2.861954 15.312073 61.835236 65701 22.251961 15.847015 63.573700 65702 21.880753 16.356216 63.520767 65703 11.223618 13.582550 62.174835 65704 10.825066 14.521484 62.153397 65705 31.969439 12.820892 61.246368 65706 33.082428 13.191849 61.165924 65707 2.830940 13.386398 61.866577 65708 2.771568 12.384277 64.107803 65709 2.904221 11.646347 62.608246 65710 11.432922 12.605286 61.156769 65711 16.096657 12.837921 62.347565 65712 16.192513 11.442352 61.252747 65713 32.060791 11.633728 61.695709 65714 33.203674 12.178574 61.364319 65715 32.935570 11.495132 61.671082 65716 33.719513 10.981537 61.289658 65717 31.200218 11.263855 61.612549 65718 3.052712 11.739319 61.747528 65719 3.010964 10.798248 61.989044 65720 25.158630 8.895172 61.481552 65721 30.318390 9.514359 61.612793 65722 32.892761 9.966629 61.621964 65723 32.658684 10.891632 61.743271 65724 2.865639 9.054047 61.379532 65725 28.983826 8.518326 60.903290 65726 33.050552 9.101440 61.452316 65727 4.874436 6.042816 62.471588 65728 5.011559 5.512268 61.488281 65729 4.288254 5.560966 61.242325 65730 11.610474 5.993225 62.768341 65731 11.469246 5.707321 63.695618 65732 11.878342 7.055222 63.783661 65733 15.161972 5.930031 60.777832 65734 22.810944 5.142433 60.840042 65735 23.915298 5.438881 62.542496 65736 31.902529 6.478149 61.816528 65737 31.161911 7.266602 62.092041 65738 31.580795 7.914703 62.010132 65739 6.905426 5.476685 62.323486 65740 7.682945 4.639961 61.852966 65741 6.663216 4.794968 60.099350 65742 12.346466 4.451820 61.778305 65743 11.937515 6.143463 61.856750 65744 23.851830 4.765854 62.902405 65745 23.282578 4.431519 62.243958 65746 29.588814 5.896225 61.168243 65747 32.650200 4.584496 61.984039 65748 31.024513 5.135391 61.628967 65749 33.022949 6.138382 61.276703 65750 33.841621 5.208511 61.256256 65751 21.985336 3.870506 60.264450 65752 31.135277 2.231445 61.026901 65753 36.118256 3.023064 61.844604 65754 7.411957 5.016891 62.937820 65755 7.606483 4.172913 62.549927 65756 7.749885 3.583694 61.317505 65757 22.933456 3.296570 60.699799 65758 25.599792 3.718025 63.511627 65759 24.578072 3.634949 62.725647 65760 25.753326 2.737091 62.727478 65761 23.802139 3.337090 61.768356 65762 4.011772 1.030823 60.445038 65763 4.773079 1.642288 61.105988 65764 7.228340 2.646896 61.136887 65765 5.927353 2.204315 61.453323 65766 25.837585 2.027893 61.836319 65767 31.429657 1.316544 61.155548 65768 32.112480 1.532852 61.913071 65769 32.025642 3.159340 61.971375 65770 3.365105 1.250519 61.835648 65771 2.754685 0.414734 61.593384 65772 32.878838 -0.117508 62.372253 65773 34.254410 -0.877640 63.152695 65774 33.462479 -1.554214 62.568481 65775 31.144562 1.224014 60.717758 65776 37.156288 0.821625 62.015747 65777 3.219925 -2.232529 60.864349 65778 3.456909 -2.948807 60.001648 65779 31.637857 -0.794357 61.170410 65780 39.116486 -1.768906 61.041870 65781 27.691681 -1.509796 61.909515 65782 27.668991 -0.785690 61.815216 65783 31.402878 -1.769699 60.558823 65784 26.760956 -2.500046 60.492340 65785 27.295372 -2.290619 61.485519 65786 32.171936 -2.658157 60.509399 65787 7.096535 -4.297531 61.487762 65788 5.176582 -3.831284 60.877808 65789 26.817932 -3.494827 61.414062 65790 35.595566 -4.591660 59.955078 65791 24.944138 -5.902237 59.899490 65792 35.918480 -4.249023 60.822189 65793 38.250282 -3.722244 61.164307 65794 17.137161 -7.570511 60.424408 65795 16.808258 -7.904861 61.079086 65796 16.782608 -6.942612 60.894577 65797 25.384277 -6.629150 60.294800 65798 30.386024 -6.641281 60.362518 65799 31.423050 -6.957336 60.019623 65800 31.365417 -6.756378 60.583710 65801 17.507416 -6.808762 60.515381 65802 19.408150 -7.279953 61.066833 65803 18.454544 -6.894577 60.450272 65804 17.973076 -5.760727 61.166870 65805 26.005386 -7.366898 60.410583 65806 26.144081 -6.826599 61.328995 65807 32.331467 -7.610229 60.501205 65808 31.006470 -6.674072 61.446304 65809 4.492233 -8.883728 59.829269 65810 8.863846 -6.515060 61.139328 65811 19.437241 -5.845062 62.453979 65812 19.784317 -8.634918 60.197205 65813 33.050507 -8.259216 60.275131 65814 33.168900 -8.503036 60.146179 65815 33.217781 -8.444794 60.366913 65816 33.167542 -9.307770 59.626556 65817 33.010338 -9.412399 60.152466 65818 33.085419 -8.677551 60.355637 65819 38.092026 -9.752930 60.448456 65820 40.677521 -9.891983 61.470581 65821 2.622177 -11.177429 60.538879 65822 2.999199 -12.319733 60.731308 65823 2.290238 -12.456802 59.943878 65824 20.527771 -9.825760 60.357574 65825 20.329910 -8.535385 61.355560 65826 21.327240 -11.377731 60.092148 65827 36.926422 -10.142136 60.911819 65828 40.803085 -11.040634 62.921539 65829 42.041870 -11.994736 62.575363 65830 42.619217 -12.138077 62.087585 65831 1.855118 -12.321777 59.375275 65832 21.141914 -10.479401 61.149872 65833 33.096878 -10.931549 62.033478 65834 34.795135 -10.652344 62.251114 65835 33.976852 -11.058975 63.366745 65836 32.971375 -10.625107 61.157410 65837 34.356819 -10.890549 60.949677 65838 35.739670 -10.544647 61.396576 65839 35.945541 -10.844742 60.301117 65840 17.694756 -11.524857 60.831726 65841 17.527847 -11.046616 60.980362 65842 17.950447 -12.138977 60.790222 65843 23.390305 -13.333237 60.750305 65844 22.349869 -12.534500 60.548157 65845 19.081650 -14.605835 61.453796 65846 18.767311 -13.495087 61.803070 65847 23.030640 -12.540787 61.929977 65848 24.505753 -13.992584 59.991272 65849 28.599472 -14.984406 60.150269 65850 20.762436 -16.354889 60.588562 65851 20.728989 -16.368317 61.404205 65852 19.922997 -15.768723 61.463837 65853 28.754166 -18.026459 63.470367 65854 27.826256 -17.946136 62.555099 65855 28.812157 -18.749710 62.329010 65856 24.673584 -17.775284 59.961334 65857 23.798546 -17.346848 60.873047 65858 32.131340 -18.565079 59.629364 65859 41.742126 -18.227631 59.629379 65860 42.147308 -18.205246 60.158722 65861 26.860596 -18.366470 60.493988 65862 31.741823 -19.379395 59.753845 65863 28.012360 -19.187943 59.455750 65864 29.720947 -19.715225 59.738998 65865 28.784882 -19.378510 60.325287 65866 29.473373 -19.890717 60.812561 65867 30.730446 -20.066071 60.020050 65868 46.395691 -20.977081 59.552521 65869 45.374725 -20.637833 59.306213 65870 31.654566 -20.345276 60.573196 65871 32.378433 -20.574829 61.234497 65872 40.658981 -21.031570 59.952393 65873 40.145935 -22.055573 59.696289 65874 46.868866 -23.811096 59.471069 65875 2.110527 -22.359818 60.509842 65876 1.752411 -22.128143 59.643829 65877 1.669281 -20.246307 60.292603 65878 7.459343 -23.399811 58.787170 65879 8.403976 -23.294693 58.935242 65880 9.042327 -23.321442 58.993408 65881 9.304779 -23.557877 58.955902 65882 43.475372 -23.001831 59.822617 65883 2.263207 -23.252487 59.246735 65884 5.575028 -23.850327 59.295441 65885 6.738533 -23.547058 59.204956 65886 36.669563 -27.689072 63.902130 65887 34.571625 -28.591690 63.980927 65888 35.862595 -28.122650 65.339081 65889 43.523346 -23.585648 60.655762 65890 42.917328 -24.269150 60.912079 65891 45.785889 -23.153519 60.449860 65892 45.833527 -22.090469 60.432266 65893 2.916412 -24.096695 58.814423 65894 22.750366 -24.910812 61.114288 65895 21.450340 -25.116684 60.049515 65896 21.180191 -24.872482 61.184906 65897 24.159927 -25.226654 60.054367 65898 46.571045 -24.799911 59.753357 65899 9.162056 -26.334442 58.455490 65900 42.077820 -25.427094 60.943222 65901 20.456863 -26.833054 60.046082 65902 20.595718 -27.011993 61.641296 65903 20.387054 -25.899063 61.526703 65904 22.575851 -27.341187 58.470490 65905 41.672638 -25.985153 59.308502 65906 40.954193 -27.045471 59.093323 65907 4.526276 -27.543381 59.440475 65908 3.559097 -28.055588 59.211884 65909 5.532074 -27.619247 58.836777 65910 20.656960 -27.963470 59.475983 65911 21.744644 -27.721634 58.570892 65912 26.669022 -29.158066 59.729126 65913 21.522827 -29.830658 59.293976 65914 20.864349 -29.790466 59.809479 65915 20.804939 -28.976303 59.860977 65916 21.480507 -28.463593 59.015259 65917 44.834030 -27.807999 61.747131 65918 44.911850 -25.022354 61.393097 65919 2.665314 -28.169388 60.169861 65920 21.339584 -30.778854 59.261749 65921 21.054596 -30.512543 59.883240 65922 40.980179 -26.874619 62.355774 65923 41.175598 -26.661148 61.474823 65924 41.755676 -26.168076 62.259598 65925 39.837296 -28.175812 61.654114 65926 2.498627 -32.392059 58.846313 65927 22.682564 -31.685074 59.276306 65928 21.918045 -31.003387 59.127441 65929 22.880203 -30.302155 59.848663 65930 28.332031 -30.322388 59.863358 65931 27.569473 -29.756104 60.811966 65932 26.045868 -29.019943 61.110962 65933 40.205078 -27.911469 63.109344 65934 39.245270 -29.167084 63.295944 65935 37.990097 -29.842239 60.047638 65936 38.993179 -28.919601 59.447861 65937 21.418213 -31.786972 59.604767 65938 23.156784 -31.491669 59.956406 65939 28.794502 -30.545395 61.583649 65940 29.514793 -31.355270 59.941605 65941 28.808327 -30.926376 59.038742 65942 45.743362 -31.378815 59.616165 65943 2.283798 -30.438965 59.286469 65944 22.128151 -31.812408 59.025848 65945 22.385590 -32.760483 59.198303 65946 30.360977 -32.388489 59.323608 65947 22.382729 -34.260269 59.152908 65948 22.445496 -34.790863 59.189224 65949 21.847015 -34.744461 59.367615 65950 21.188278 -33.663849 59.588531 65951 23.137039 -33.915146 59.571960 65952 22.338028 -33.660706 59.127014 65953 31.598495 -33.352173 60.016403 65954 31.182312 -33.003174 59.486664 65955 32.820831 -33.430511 58.808441 65956 32.646561 -33.707687 59.380432 65957 2.658379 -36.901794 59.011475 65958 2.276909 -38.141861 58.594025 65959 40.457016 -37.131287 58.918274 65960 39.464432 -37.027802 58.338013 65961 42.643311 -36.504562 59.959534 65962 41.217300 -37.440582 59.830902 65963 27.441910 -40.553406 58.315369 65964 39.698555 -37.894760 58.985855 65965 2.137779 -39.069031 58.978104 65966 2.155312 -39.792465 59.382355 65967 31.849489 -39.225372 58.267502 65968 7.269943 -41.135925 57.618790 65969 18.351158 -42.606567 57.971985 65970 18.302628 -41.603256 58.579971 65971 20.784683 -41.553345 58.243805 65972 33.096848 -39.784668 58.862732 65973 36.699539 -40.233658 59.763306 65974 34.677414 -40.351089 59.619110 65975 35.704437 -41.114563 60.784454 65976 36.772598 -39.693604 58.872772 65977 6.016098 -41.549332 57.699707 65978 19.081818 -40.820831 58.744949 65979 19.854355 -40.832611 58.542694 65980 2.766556 -41.167862 58.678314 65981 3.760323 -41.765244 58.143188 65982 22.342148 -43.067535 57.821411 65983 21.587708 -42.323654 58.059387 65984 27.596901 -41.327286 58.506042 65985 26.974091 -43.338608 58.138428 65986 18.361435 -43.661316 58.195160 65987 23.845535 -44.077225 57.812286 65988 32.680832 -44.704895 58.230530 65989 32.135208 -45.084290 57.880829 65990 38.537666 -43.657013 58.259857 65991 37.682549 -43.874115 58.427048 65992 39.477539 -43.631195 58.101532 65993 40.542603 -43.756165 57.840378 65994 40.335312 -44.149643 58.711121 65995 40.373749 -44.897644 59.450165 65996 10.407013 -43.105515 59.464935 65997 10.211029 -45.450775 59.502945 65998 10.455833 -45.058960 58.443268 65999 18.719193 -45.330475 58.243240 66000 18.234894 -45.487579 59.677612 66001 18.039688 -44.272232 59.606888 66002 3.834137 -47.029114 57.211700 66003 4.740868 -46.674423 58.376068 66004 6.885445 -46.396210 57.783997 66005 5.898110 -46.519104 58.055176 66006 7.661285 -46.428741 57.213837 66007 7.899688 -46.581009 58.237244 66008 8.571930 -46.925522 59.225250 66009 7.010994 -46.762497 59.129532 66010 18.472504 -46.544281 59.324127 66011 19.382881 -46.906509 57.976685 66012 42.093842 -47.423935 59.045593 66013 8.706238 -46.734558 58.336365 66014 8.865158 -46.655045 57.300476 66015 9.553436 -46.441864 58.481842 66016 2.603470 -48.503998 59.521362 66017 20.373703 -48.115707 58.218414 66018 24.711128 -48.255203 57.636993 66019 23.969955 -48.502518 58.488678 66020 34.263313 -49.289749 58.486755 66021 33.220474 -49.705475 57.793335 66022 33.512901 -50.036591 58.491791 66023 34.800186 -48.306595 58.395706 66024 34.643990 -47.226578 58.575012 66025 35.268539 -48.331650 58.954468 66026 42.151031 -46.283905 58.491577 66027 28.039612 -48.974930 58.761169 66028 28.491852 -49.112457 59.795410 66029 29.513504 -49.340286 59.067322 66030 30.033501 -49.527863 60.647980 66031 32.877220 -50.084381 58.686829 66032 31.634676 -49.732239 59.202301 66033 40.480972 -51.702301 57.993134 66034 40.825256 -51.034760 57.946228 66035 41.253616 -50.176376 58.085754 66036 3.947449 -51.412094 57.180206 66037 7.853164 -51.281204 57.266724 66038 9.645142 -51.375534 57.708466 66039 32.965439 -50.036438 58.097855 66040 4.751061 -51.722412 57.957520 66041 5.693054 -51.792114 57.824844 66042 39.520203 -52.620285 57.744507 66043 34.877350 -54.095398 57.370575 66044 35.823860 -54.111237 57.829422 66045 36.868912 -53.841049 57.752228 66046 38.121017 -53.384384 57.593536 66047 8.219986 -54.922516 57.068680 66048 29.083672 -55.814911 58.359222 66049 29.982407 -55.745651 57.921799 66050 34.924347 -54.697845 58.273697 66051 33.989288 -55.285172 58.529678 66052 4.564606 -56.283630 57.056335 66053 3.801407 -57.089294 57.472931 66054 3.922951 -56.639175 56.739883 66055 5.853294 -55.798462 57.798218 66056 28.312790 -55.317047 58.005783 66057 32.718063 -55.928070 58.778793 66058 18.927284 -57.488937 56.943726 66059 25.706970 -57.197311 57.594238 66060 26.409592 -56.049011 57.686859 66061 3.213326 -58.130157 57.284607 66062 11.262657 -58.204208 57.061096 66063 10.726227 -58.349152 56.969025 66064 18.389740 -57.900070 58.404297 66065 16.812210 -57.937698 57.892105 66066 17.884415 -57.859756 59.197174 66067 18.360405 -58.247940 59.202545 66068 21.988762 -57.735886 56.714111 66069 24.693649 -57.389999 56.957550 66070 10.122498 -59.004333 57.061951 66071 12.104660 -59.151245 57.213470 66072 26.728226 -59.962799 59.264801 66073 26.598740 -58.964645 58.631210 66074 25.665352 -59.128860 58.536575 66075 24.490776 -58.397781 57.625366 66076 15.699562 -59.819702 56.558746 66077 15.507736 -59.963013 56.794647 66078 15.640472 -59.696426 57.010834 66079 16.228752 -59.069366 56.746521 66080 33.246750 -60.200989 56.682480 66081 8.688721 -61.187256 56.429077 66082 9.242851 -60.295532 57.356323 66083 11.902138 -62.274002 58.680847 66084 15.672287 -60.195328 56.656647 66085 30.446198 -60.812683 56.519043 66086 31.413193 -60.937210 56.775543 66087 31.760157 -62.539490 57.335358 66088 30.530396 -62.503235 57.061371 66089 34.092087 -61.067734 56.771637 66090 33.340805 -61.097870 57.105835 66091 34.207458 -62.137268 56.646149 66092 33.296265 -62.143204 57.176483 66093 3.587059 -60.226303 57.199203 66094 7.937202 -61.767899 56.440994 66095 7.258926 -62.087311 56.636078 66096 15.621262 -59.619583 58.140717 66097 15.601334 -61.772736 59.145355 66098 29.441971 -62.731064 56.598495 66099 30.283386 -61.526169 56.697372 66100 29.811317 -63.758484 57.081482 66101 29.096451 -64.234344 56.821930 66102 17.475685 -63.717484 57.685608 66103 24.389435 -64.777618 57.246689 66104 33.600510 -63.253174 56.796417 66105 28.366486 -65.451462 56.896149 66106 27.402100 -65.827209 56.834717 66107 30.763046 -64.115738 57.477814 66108 29.528313 -65.225800 57.292252 66109 32.417603 -65.334610 56.702805 66110 31.805086 -66.176651 56.629547 66111 5.229141 -68.012466 55.947495 66112 7.277550 -66.909119 57.278900 66113 5.717453 -67.655807 56.805466 66114 5.273674 -68.167862 56.721771 66115 31.208939 -67.244247 56.633850 66116 12.521835 -69.812134 56.099991 66117 18.198517 -69.143204 56.413025 66118 5.261253 -68.625931 56.564819 66119 22.077927 -69.882172 56.512650 66120 21.795990 -70.506119 57.617615 66121 22.997627 -70.444168 57.428604 66122 12.131042 -70.515121 55.975311 66123 24.000679 -70.435089 57.123230 66124 25.675011 -70.217102 57.108246 66125 26.699554 -70.306686 56.317215 66126 27.543388 -70.331497 55.846832 66127 7.113609 -72.540405 56.301773 66128 9.785507 -73.349243 56.719635 66129 6.477570 31.389481 62.175354 66130 5.963287 30.314835 62.351929 66131 6.618630 29.027817 62.737122 66132 6.833634 27.970612 62.788025 66133 6.745995 27.088882 62.922913 66134 7.058075 25.814377 63.321350 66135 5.669037 26.868484 63.342255 66136 10.092361 25.416641 63.457275 66137 9.449814 25.285980 63.907440 66138 8.382721 25.168182 64.125519 66139 11.062302 25.317413 63.468658 66140 12.429779 25.125977 63.128601 66141 14.871094 24.594971 63.202667 66142 16.811722 24.082184 63.588242 66143 18.192596 24.556595 63.241348 66144 19.343857 24.660507 62.687378 66145 20.539978 22.666733 63.137711 66146 19.433083 23.895538 63.347992 66147 4.076370 22.002014 62.190765 66148 4.161545 21.169724 62.410858 66149 4.126412 20.330780 62.453735 66150 20.546539 21.668533 63.768311 66151 20.388824 22.430099 63.864380 66152 13.795715 22.368744 63.263397 66153 20.517479 20.571381 63.825867 66154 4.118805 19.422256 62.802460 66155 3.346138 16.699677 63.365723 66156 14.409836 18.624725 62.703705 66157 10.711319 18.368713 63.679367 66158 10.988266 20.335266 64.446259 66159 15.052963 17.796112 63.394302 66160 21.320740 17.048798 63.651276 66161 21.416321 17.475449 62.531967 66162 3.950897 18.196457 63.414398 66163 15.548355 16.371964 63.673553 66164 10.670143 15.554138 62.779694 66165 15.603836 14.981064 63.270386 66166 25.018723 12.983017 63.260590 66167 15.764664 13.989807 62.954636 66168 11.850769 12.318466 62.320847 66169 3.100174 7.121521 61.941574 66170 17.416740 11.088791 62.203812 66171 31.515526 10.282440 61.776978 66172 32.033997 9.009995 61.853455 66173 12.374115 10.526169 62.253754 66174 12.341408 11.748459 63.177551 66175 18.099747 9.981903 62.028015 66176 17.710938 8.969009 61.691467 66177 18.564301 10.746185 62.991592 66178 18.505814 9.517914 62.680267 66179 25.278656 11.407593 63.269562 66180 25.399521 12.449631 63.181747 66181 18.023392 8.749954 62.529678 66182 25.426926 9.342300 62.400101 66183 31.089699 9.175430 62.015854 66184 31.256805 8.621872 62.141937 66185 12.343811 7.698990 61.815964 66186 16.154556 7.049438 62.039917 66187 16.853867 7.636215 62.066147 66188 17.435623 8.183548 62.306335 66189 25.112152 8.247299 62.102264 66190 12.081512 7.448471 62.820694 66191 15.063583 5.965332 62.059586 66192 30.647621 6.705032 61.800873 66193 5.952850 5.407227 61.380280 66194 11.849777 5.045990 61.756226 66195 13.669511 4.448837 62.606567 66196 12.904991 3.876343 62.693680 66197 14.359193 4.985840 63.456909 66198 15.720253 6.534637 64.366211 66199 24.875732 6.471405 63.303497 66200 31.810061 4.202866 61.966095 66201 22.515640 4.055687 61.143158 66202 22.748627 4.289246 61.593994 66203 31.268982 3.759850 61.568390 66204 33.958031 3.839386 62.125305 66205 35.196411 3.430801 62.009491 66206 11.668198 4.662621 62.565567 66207 23.047241 3.820160 61.737366 66208 6.939468 3.257469 62.568756 66209 24.822182 2.751526 61.827698 66210 36.241379 2.108810 62.260880 66211 4.136650 1.536667 61.408325 66212 15.550507 1.119263 63.115784 66213 15.550354 1.917221 63.185883 66214 16.321869 1.505859 62.562469 66215 18.255806 1.639328 63.049179 66216 18.309845 1.006195 62.196426 66217 17.403519 1.484207 62.313034 66218 17.871841 0.963882 61.739624 66219 35.995941 0.849014 62.873352 66220 15.735916 -0.023239 63.371490 66221 16.945808 0.314102 62.078049 66222 18.043579 0.436188 61.809601 66223 17.549545 0.827667 61.729004 66224 27.094444 1.346069 62.665344 66225 26.600388 2.818375 63.589752 66226 36.796997 -0.375244 62.770157 66227 37.924644 -1.208832 62.096542 66228 18.216782 -0.490021 61.956268 66229 17.233223 -1.074417 61.873688 66230 27.394257 -0.022614 61.796783 66231 32.585457 -1.847916 61.562683 66232 16.361580 -0.792923 62.628357 66233 18.402206 -1.703796 62.032196 66234 17.281960 -2.057587 61.812805 66235 16.468079 -1.798279 62.623596 66236 17.930084 -2.968491 61.733841 66237 16.647964 -3.021225 62.329895 66238 19.086136 -2.740662 62.704224 66239 18.706047 -3.720657 62.170303 66240 33.798340 -2.611145 62.044556 66241 4.033020 -3.233353 60.724518 66242 17.281059 -4.109528 61.509247 66243 18.088699 -3.820343 61.556824 66244 18.442032 -4.619705 61.749451 66245 8.809616 -5.009720 61.334137 66246 16.328911 -4.204468 62.230011 66247 16.669312 -5.022369 61.658554 66248 16.745308 -6.046387 61.334320 66249 26.997345 -4.324249 62.820297 66250 27.816437 -2.568451 62.696106 66251 25.830086 -5.285919 61.138794 66252 34.611351 -3.259125 61.730316 66253 36.140190 -3.103806 62.057129 66254 37.827263 -2.460861 62.195190 66255 38.434784 -2.468384 61.782928 66256 9.312134 -5.706589 60.975647 66257 9.177444 -5.644623 61.737244 66258 15.905174 -5.433289 62.996597 66259 26.133232 -6.128723 62.253632 66260 26.204849 -5.331436 62.390167 66261 16.336021 -6.807938 61.799545 66262 29.541534 -6.542419 61.371948 66263 30.101387 -6.466476 63.449524 66264 30.922836 -6.576874 62.562775 66265 31.264954 -6.729065 63.305496 66266 8.872650 -5.227936 62.582077 66267 8.837212 -5.975113 62.385559 66268 16.521011 -7.946030 62.145447 66269 20.183563 -7.407013 62.376114 66270 27.047333 -7.190186 61.224457 66271 27.085373 -6.908356 61.925446 66272 26.619644 -7.422348 60.780426 66273 6.842621 -7.566544 61.871826 66274 7.798202 -6.832428 62.608948 66275 32.992325 -8.312469 60.576691 66276 32.676605 -8.586716 61.070374 66277 31.977991 -7.546051 62.299347 66278 32.641830 -9.673706 61.056656 66279 37.872551 -9.587875 61.640610 66280 3.541382 -9.783722 61.535599 66281 17.240616 -9.731079 61.523651 66282 32.674034 -10.291382 60.981369 66283 32.267769 -10.308502 61.547882 66284 36.382507 -10.124298 62.825745 66285 2.515404 -14.434631 59.672913 66286 2.024773 -14.696686 59.273254 66287 3.170403 -13.725616 60.018433 66288 3.959915 -13.196091 60.678955 66289 4.157829 -13.964462 60.259796 66290 4.511444 -12.539810 62.224792 66291 4.572228 -13.072845 61.294861 66292 3.634873 -12.168030 61.591339 66293 18.310059 -13.088120 60.793549 66294 4.184349 -14.929977 60.221222 66295 3.195427 -14.923843 59.998627 66296 4.993683 -14.080612 60.604660 66297 6.286789 -14.559616 60.588028 66298 5.487434 -15.453003 60.625046 66299 6.956291 -14.160156 60.952362 66300 7.236069 -14.785309 60.613037 66301 5.854309 -13.465103 61.530518 66302 25.675003 -13.958572 61.018005 66303 24.260483 -13.437149 61.563965 66304 25.149002 -13.384048 62.486359 66305 27.959343 -14.187164 60.890121 66306 29.220001 -14.498657 61.255402 66307 1.848953 -16.756821 59.845123 66308 1.559532 -16.842651 59.184875 66309 2.504486 -15.240768 59.719635 66310 2.378044 -15.945297 59.953766 66311 3.384094 -15.788391 60.449341 66312 6.975571 -15.612732 60.785248 66313 7.942459 -14.571915 61.277100 66314 8.228485 -15.381363 61.030212 66315 7.775360 -15.320129 60.785095 66316 26.880646 -13.866196 61.422607 66317 43.021942 -15.033401 62.493500 66318 42.525681 -13.452560 62.679291 66319 4.480766 -15.817947 60.652924 66320 5.060700 -16.298767 61.507690 66321 4.168434 -16.203217 61.168777 66322 8.040070 -16.014389 61.461304 66323 19.384377 -15.194672 61.453110 66324 19.397964 -15.237900 62.200104 66325 29.445702 -15.357376 60.548798 66326 30.651695 -16.192184 60.569809 66327 29.977226 -15.931915 60.300217 66328 43.835983 -15.752777 60.802124 66329 22.095215 -16.836563 61.216736 66330 32.458176 -16.519531 62.353897 66331 33.383194 -17.003769 62.861847 66332 43.367523 -15.971939 61.746399 66333 42.877487 -17.381454 61.944092 66334 42.452454 -16.410294 63.087326 66335 43.253891 -16.825943 61.016006 66336 25.860985 -17.803070 60.947601 66337 24.796783 -17.384018 61.519409 66338 32.152382 -17.442505 60.721390 66339 42.591461 -18.015625 61.127106 66340 42.584244 -18.175110 61.914948 66341 29.158096 -19.418655 61.458572 66342 28.509445 -18.930023 61.261536 66343 27.808441 -18.845535 60.347061 66344 30.047775 -20.222504 60.610260 66345 33.420204 -18.987656 61.795212 66346 33.241310 -20.105072 62.018616 66347 30.734299 -20.622406 61.258057 66348 41.181885 -20.842056 60.992828 66349 40.640747 -21.914795 60.861420 66350 6.749336 -23.405930 60.385025 66351 8.938782 -23.565216 59.575851 66352 39.998138 -23.074982 60.683807 66353 3.661102 -23.618851 60.214020 66354 5.536354 -23.419830 61.185638 66355 7.737220 -23.283997 59.667603 66356 39.010880 -24.612000 60.336472 66357 39.094810 -24.868988 61.402924 66358 39.679932 -23.876709 61.405289 66359 20.587067 -25.538086 60.497314 66360 44.509064 -23.699158 61.217941 66361 44.390472 -22.830368 60.518066 66362 8.833755 -26.033020 59.306763 66363 26.417175 -26.069138 60.735443 66364 26.714897 -25.841537 59.878632 66365 28.398697 -26.760132 59.903137 66366 38.756836 -25.505997 62.411133 66367 36.570953 -27.561981 61.749329 66368 42.438248 -25.542770 62.262909 66369 5.473290 -26.933151 60.354355 66370 4.576660 -27.029327 60.471985 66371 6.895813 -26.823334 59.911636 66372 8.219589 -26.232315 59.988068 66373 9.022903 -24.829361 60.366211 66374 26.680634 -26.494263 61.863159 66375 27.688843 -26.607635 60.901550 66376 40.762558 -27.165375 60.091980 66377 3.754395 -27.283066 60.449905 66378 23.966354 -28.401947 59.896393 66379 25.017517 -28.474731 59.887238 66380 34.094116 -28.691086 60.282043 66381 35.709740 -27.960922 60.023163 66382 45.214172 -31.167511 60.753326 66383 2.013374 -29.463364 60.168915 66384 20.598679 -27.966522 60.614532 66385 24.107925 -29.143143 60.663177 66386 30.844337 -28.228485 60.582916 66387 32.420471 -28.759674 59.640030 66388 23.487152 -30.035477 60.674225 66389 23.657097 -31.264023 61.206726 66390 34.993729 -32.400467 59.118668 66391 37.672058 -30.756500 61.395493 66392 23.993820 -33.396667 61.694519 66393 23.820007 -34.451233 60.968628 66394 23.366806 -32.726395 60.131699 66395 22.946854 -34.792084 59.439621 66396 2.561150 -33.902115 58.731171 66397 21.169968 -34.716583 59.613297 66398 32.138153 -33.677490 59.845062 66399 34.432129 -33.646271 59.712860 66400 44.648712 -33.850388 60.137192 66401 44.548859 -32.326218 61.290329 66402 2.808968 -34.658432 58.924240 66403 3.052696 -33.885635 59.493561 66404 3.165367 -34.804947 59.308258 66405 20.802124 -32.546097 60.504044 66406 19.939682 -33.241989 60.669556 66407 23.451309 -34.835434 60.051682 66408 32.876457 -33.834442 60.545990 66409 34.154602 -34.199570 60.496460 66410 35.138626 -33.753052 60.293594 66411 3.780411 -34.895004 59.985046 66412 2.999443 -35.647217 59.095490 66413 20.280472 -34.781387 60.048431 66414 20.472961 -35.586380 60.803833 66415 19.122162 -35.182983 60.878784 66416 21.814316 -35.549377 60.291992 66417 22.448471 -35.277115 59.533356 66418 22.947159 -35.480789 60.088928 66419 43.807098 -35.390503 59.762604 66420 44.235031 -34.903336 59.940247 66421 22.440750 -35.593307 59.836273 66422 43.788528 -35.365997 60.832306 66423 42.445892 -36.806900 61.322495 66424 42.723114 -36.157867 59.448395 66425 43.306519 -35.916168 59.810883 66426 2.989853 -37.879913 59.952484 66427 41.929596 -36.953278 62.671661 66428 42.242050 -35.872360 63.054459 66429 41.281586 -37.808289 61.689636 66430 43.115524 -35.856674 61.982666 66431 28.068024 -39.007629 58.979187 66432 28.390076 -38.581436 58.992065 66433 37.900421 -39.414642 59.197296 66434 38.408470 -39.797119 60.019775 66435 39.815605 -38.775162 60.010330 66436 2.144341 -40.417587 58.836060 66437 28.219955 -40.247849 59.437653 66438 28.472305 -38.988144 59.345856 66439 39.432236 -39.582367 60.732162 66440 40.121033 -39.153122 60.894348 66441 40.619370 -38.761948 61.431900 66442 19.715752 -40.746368 59.666824 66443 20.828140 -41.617844 59.923004 66444 28.968697 -39.290298 59.761917 66445 31.989183 -40.284119 60.797821 66446 36.767654 -41.150146 61.185745 66447 3.320603 -41.908386 58.682999 66448 7.656127 -42.388504 60.708496 66449 7.092514 -42.466522 60.227066 66450 7.786636 -42.577682 61.634949 66451 10.542793 -43.000549 58.274567 66452 9.744904 -41.700302 58.430908 66453 18.063522 -40.649155 60.405380 66454 27.960121 -42.000046 59.262970 66455 4.053070 -42.272720 58.722351 66456 4.854973 -42.720428 59.270020 66457 4.914970 -42.329330 58.528229 66458 6.062882 -42.124466 58.767029 66459 17.657852 -41.747711 59.664368 66460 17.899826 -42.578918 58.914169 66461 23.437546 -43.838516 58.770004 66462 21.952988 -42.722366 59.028137 66463 28.215546 -43.178970 60.076416 66464 28.910751 -41.840271 60.504456 66465 5.696129 -43.028412 60.374893 66466 17.876175 -43.324509 59.182190 66467 17.515953 -42.808762 60.182129 66468 27.283325 -43.401093 59.055573 66469 35.816360 -45.341339 58.960312 66470 34.734833 -45.520737 58.777725 66471 38.859016 -45.331787 60.022491 66472 37.594688 -45.405640 59.865707 66473 37.822540 -44.539902 59.325195 66474 36.793839 -44.742889 58.956573 66475 38.445534 -44.179474 59.075134 66476 39.358086 -44.183426 59.036743 66477 33.089325 -45.622482 58.394440 66478 33.822357 -45.361557 58.776276 66479 3.616867 -47.129211 58.271729 66480 34.003754 -46.062439 58.775330 66481 2.963631 -47.706192 59.037994 66482 19.209305 -47.971069 58.583466 66483 18.749054 -47.391907 58.815353 66484 33.733215 -46.692398 58.403351 66485 18.663071 -48.092331 59.183838 66486 22.579468 -48.656372 58.793732 66487 21.472450 -48.583923 58.653778 66488 25.740761 -49.025116 60.494812 66489 24.675385 -48.972549 60.112915 66490 35.761871 -46.987610 59.236679 66491 35.875740 -48.106323 59.308533 66492 42.362000 -47.971893 58.790955 66493 35.703659 -48.744049 59.631042 66494 42.157532 -48.279068 58.897964 66495 2.602074 -49.425705 59.991333 66496 2.962433 -50.578339 59.550919 66497 3.297554 -50.775864 58.147034 66498 41.413422 -49.755737 59.231171 66499 41.482941 -48.549545 59.707733 66500 3.885147 -51.269852 58.036346 66501 6.453056 -51.611557 58.291489 66502 7.201225 -51.362442 57.949249 66503 7.766769 -51.253891 58.097229 66504 8.596764 -51.321991 58.111420 66505 32.886032 -50.064423 59.347931 66506 40.833069 -51.008926 59.054871 66507 4.199173 -51.478928 58.008850 66508 10.442856 -52.020721 57.711517 66509 9.580078 -51.768143 58.688873 66510 10.172531 -52.485489 58.534424 66511 40.185303 -52.237640 58.619263 66512 10.435958 -53.276367 57.550781 66513 39.089737 -53.271729 58.637070 66514 39.988091 -52.330307 59.698792 66515 39.129364 -52.978424 60.790512 66516 39.953079 -52.008667 60.617096 66517 9.322510 -54.211151 58.027466 66518 36.389877 -54.866318 59.162079 66519 37.824181 -54.056534 58.699356 66520 38.720924 -53.714890 59.617432 66521 7.268616 -55.154327 57.829468 66522 8.140762 -54.781052 58.494751 66523 9.079544 -54.146545 59.241364 66524 9.839996 -53.286926 58.854721 66525 9.340195 -53.242020 60.015503 66526 27.014336 -55.450500 57.921356 66527 27.605972 -55.073547 57.885910 66528 28.034370 -54.972137 57.349396 66529 4.813171 -56.436813 58.533432 66530 6.668717 -55.429077 57.831650 66531 27.255280 -56.565552 58.473129 66532 28.558746 -56.363953 58.938721 66533 28.189392 -55.810654 58.583435 66534 11.890762 -58.133560 57.780319 66535 10.918930 -58.059753 57.901093 66536 17.197533 -57.437180 58.864807 66537 19.877205 -58.082565 58.062332 66538 26.665436 -58.045990 58.442795 66539 3.241783 -58.958740 57.422714 66540 21.058578 -58.242737 57.786224 66541 21.903381 -58.665527 58.031952 66542 23.077255 -58.749603 57.783646 66543 3.490746 -59.172272 57.948227 66544 3.693215 -58.664825 58.602722 66545 3.814377 -59.579071 58.531021 66546 15.604187 -60.072235 57.107788 66547 32.586411 -61.295441 57.123199 66548 4.454079 -61.311707 57.247131 66549 8.315628 -61.497650 57.413757 66550 32.514435 -63.305038 57.471558 66551 5.163445 -61.787491 57.770996 66552 7.823158 -62.059753 58.413101 66553 18.694870 -63.735687 58.021576 66554 20.264122 -63.774185 58.136261 66555 31.993082 -64.051224 57.732361 66556 32.709869 -64.374695 57.184814 66557 31.535385 -65.115448 57.502243 66558 16.292191 -63.149384 58.001572 66559 17.218025 -64.314285 58.770905 66560 18.337784 -64.820602 59.283340 66561 21.761024 -64.431351 58.345078 66562 31.638933 -63.569107 57.664551 66563 10.629433 -64.705109 56.863571 66564 16.716415 -63.783630 58.020844 66565 20.252556 -65.378891 59.607086 66566 9.881615 -65.508453 57.010803 66567 9.298553 -66.008774 57.872513 66568 10.517746 -65.047318 59.289001 66569 30.409103 -65.569611 57.611771 66570 6.353767 -67.195129 56.948029 66571 23.279053 -65.344879 58.410400 66572 27.610886 -66.717697 57.415436 66573 26.258728 -65.747330 57.101746 66574 28.749481 -66.339798 57.364227 66575 30.696396 -66.569519 57.388733 66576 26.538681 -66.812561 57.841705 66577 26.801880 -67.671036 58.016037 66578 13.715775 -68.845825 56.559052 66579 30.559753 -67.442703 57.124603 66580 30.493523 -68.035629 56.714661 66581 29.743530 -67.642166 57.333221 66582 13.819183 -69.194885 56.962204 66583 12.792435 -70.003540 56.910980 66584 15.569763 -69.530197 57.508377 66585 13.785995 -69.790451 57.748611 66586 14.324814 -69.956253 58.236053 66587 16.964996 -69.688171 57.338821 66588 17.666420 -70.086182 58.129974 66589 6.088226 -70.630844 56.845184 66590 11.962860 -71.314941 56.922363 66591 12.892831 -70.733597 58.310593 66592 20.810570 -70.572647 57.739319 66593 6.580368 -70.687531 57.737106 66594 5.984139 -69.690674 57.530914 66595 6.560227 -71.441330 56.887054 66596 24.653961 -70.363617 57.774475 66597 27.517662 -70.023315 56.585999 66598 26.683411 -69.605957 57.492462 66599 10.942329 -72.520676 56.831757 66600 11.487579 -71.930557 58.105408 66601 6.131943 28.007584 63.099121 66602 5.702271 25.921463 63.697205 66603 4.791779 26.047379 63.239319 66604 4.519417 21.945831 63.243759 66605 5.464203 24.855865 63.807236 66606 12.661293 24.413040 63.920456 66607 11.728584 24.788818 64.186432 66608 13.626648 24.376129 63.482574 66609 15.689499 24.024139 63.541809 66610 16.797638 22.714203 64.317673 66611 15.936264 23.203293 63.908386 66612 18.121979 23.385330 64.164124 66613 13.043320 23.349503 63.763229 66614 11.869843 23.091690 64.644348 66615 14.710548 23.219620 63.596313 66616 15.652657 21.872620 64.048279 66617 13.049477 22.573654 63.345413 66618 12.145889 24.032639 64.354706 66619 4.708168 21.287628 63.609711 66620 5.187477 21.260406 64.428680 66621 5.256256 23.142090 64.083588 66622 14.643524 21.801819 63.425232 66623 4.486214 21.265472 63.203323 66624 4.493248 20.544464 63.411591 66625 15.967590 20.518921 64.504639 66626 16.244576 19.540024 64.776917 66627 15.146469 19.342194 63.789307 66628 14.880264 20.682587 63.565216 66629 4.944725 19.035980 64.891388 66630 10.834122 16.926575 64.374359 66631 11.342041 15.305115 64.293716 66632 20.447296 17.867142 64.373016 66633 11.197853 14.406921 63.125397 66634 2.882218 15.297195 62.959167 66635 2.875847 14.407074 64.217392 66636 11.325317 16.195007 65.412994 66637 16.338539 15.285355 64.352905 66638 11.633400 13.421967 63.050568 66639 12.040588 12.761261 63.349792 66640 24.567307 13.591980 63.323914 66641 2.843880 10.161469 63.987823 66642 16.360069 13.896393 63.611404 66643 17.648636 12.405930 63.589233 66644 19.190445 10.100998 63.641357 66645 12.462495 8.971558 62.767365 66646 12.641510 10.541565 63.904083 66647 3.021538 8.149490 63.260132 66648 18.097778 8.698425 63.863037 66649 16.880981 7.610214 63.096924 66650 25.304337 8.556137 63.508087 66651 3.835907 6.249588 62.043228 66652 3.885040 6.930313 63.377716 66653 5.936249 5.973694 62.830841 66654 11.610352 5.331802 62.136505 66655 14.056831 5.130371 61.926437 66656 12.231186 4.025970 62.330063 66657 24.680786 4.864105 63.335587 66658 14.800064 5.067940 64.668488 66659 12.003372 3.913071 62.927368 66660 12.129433 3.457329 63.742218 66661 23.674225 3.841492 62.397339 66662 33.045494 2.721115 62.393494 66663 35.729095 2.783478 62.342957 66664 2.923424 1.425980 63.141312 66665 2.647560 0.570236 62.618347 66666 4.523697 2.061737 62.328583 66667 5.728844 2.775620 63.229095 66668 4.476662 2.536270 64.052322 66669 6.450234 3.657425 64.259644 66670 5.550209 3.208916 64.536591 66671 16.316345 2.159790 63.155777 66672 27.520706 1.947052 63.884247 66673 35.300079 2.066711 62.756165 66674 34.214081 2.315598 62.736450 66675 17.727509 1.945450 62.864044 66676 18.722519 1.042389 62.803207 66677 3.599899 1.966324 63.122864 66678 27.969978 0.851273 63.638428 66679 28.028229 -0.660873 62.937805 66680 33.340851 1.357178 62.710175 66681 2.528000 -0.310272 61.946182 66682 18.999207 0.280685 62.857452 66683 35.722054 -0.501190 63.238220 66684 34.637154 0.477219 63.144577 66685 3.005180 -1.582184 61.959656 66686 19.568207 -1.738632 63.323975 66687 4.157501 -2.914963 61.655243 66688 16.160416 -2.573196 64.088074 66689 19.312683 -0.848465 62.931732 66690 37.215302 -2.705643 62.373917 66691 36.758560 -1.788559 62.747314 66692 36.748390 -2.506317 62.625366 66693 4.250900 -2.588257 62.999420 66694 2.851463 -1.289963 64.117584 66695 4.188316 -2.876587 64.225098 66696 5.482216 -3.477158 62.045975 66697 15.991547 -3.991959 63.654114 66698 19.508438 -3.680908 63.404510 66699 34.792374 -2.588715 62.513977 66700 19.175636 -4.537567 62.699188 66701 34.254250 -1.963577 62.802246 66702 15.684845 -4.716751 63.924408 66703 20.202026 -4.836227 64.329407 66704 20.089996 -6.006165 63.779266 66705 28.346909 -6.709641 62.240845 66706 30.843170 -6.677353 64.277664 66707 29.722145 -6.483398 62.411957 66708 20.101761 -6.650177 63.237274 66709 26.390053 -6.720016 62.167389 66710 27.008560 -6.508377 62.979416 66711 28.521767 -6.606537 63.517456 66712 20.794579 -8.520981 62.670151 66713 20.902786 -9.522827 61.749512 66714 31.993639 -9.202560 62.126389 66715 32.044296 -8.351883 63.345718 66716 37.724609 -9.633469 62.606964 66717 3.101685 -11.168213 61.510361 66718 21.346497 -9.501770 62.832764 66719 21.400986 -10.286697 62.044174 66720 30.881500 -10.634140 62.009613 66721 30.482361 -10.633591 62.260315 66722 30.949524 -10.079468 62.369812 66723 31.486664 -10.264313 61.925934 66724 39.620911 -10.374161 63.246521 66725 21.872284 -11.336456 61.653992 66726 30.555061 -11.276245 62.210236 66727 30.218712 -10.754196 62.910614 66728 31.630159 -11.095215 62.074570 66729 31.078987 -12.232010 62.583603 66730 32.507614 -11.766754 63.022736 66731 41.372070 -12.592224 63.502319 66732 17.735107 -11.326157 61.632797 66733 18.202164 -12.367752 61.748016 66734 22.470001 -11.443787 62.843079 66735 21.826340 -10.460571 62.826141 66736 30.514259 -13.801010 62.477295 66737 31.862070 -13.051727 63.595947 66738 30.388145 -15.323074 61.444336 66739 7.928848 -13.847641 62.388382 66740 7.130081 -13.825165 61.663986 66741 6.670410 -13.255920 62.591492 66742 22.812561 -11.321518 63.880783 66743 23.523300 -11.830032 64.382858 66744 23.148285 -12.127029 63.172821 66745 29.641220 -12.240875 62.491928 66746 43.148056 -12.373886 61.548721 66747 27.097961 -13.202621 62.797211 66748 27.764236 -13.521652 61.891968 66749 26.084885 -13.510651 62.406860 66750 28.848549 -13.474121 61.875381 66751 2.550278 -16.603027 60.764862 66752 3.394493 -16.498291 61.399155 66753 4.276184 -16.592239 62.098297 66754 7.315476 -16.343826 61.669617 66755 6.344620 -16.315384 61.742538 66756 8.991425 -16.011765 62.214935 66757 8.658386 -15.353958 61.527222 66758 9.140732 -15.329422 61.925385 66759 31.409355 -16.211136 61.415588 66760 1.917114 -17.907883 60.692871 66761 2.469887 -17.481873 61.872009 66762 23.408936 -16.982666 62.504242 66763 26.863258 -17.835861 61.784592 66764 25.804581 -17.147888 62.779358 66765 33.873955 -17.420151 63.076263 66766 33.733261 -18.055756 62.472229 66767 27.793121 -18.450668 61.484726 66768 42.314850 -18.819122 61.873184 66769 29.538811 -19.900833 61.511597 66770 41.984741 -19.670090 61.847336 66771 29.939148 -20.261887 61.474442 66772 31.674578 -21.043060 61.555695 66773 31.094589 -21.176804 62.405548 66774 41.460297 -20.556183 62.642258 66775 32.565353 -21.127670 61.973221 66776 41.065491 -21.635986 61.828796 66777 45.083099 -22.067337 60.429031 66778 1.796806 -21.372635 61.435165 66779 8.275604 -23.421051 60.843338 66780 40.457626 -22.758499 62.268524 66781 4.614128 -23.288559 62.219452 66782 7.105042 -23.156525 61.771927 66783 39.651062 -24.140503 62.190460 66784 43.836380 -24.211716 61.577881 66785 44.457413 -24.176682 61.577850 66786 8.273361 -23.209412 61.947632 66787 8.842499 -23.811462 61.899841 66788 20.525368 -25.129608 61.585602 66789 22.067184 -24.625168 62.146484 66790 8.175293 -25.799026 61.461914 66791 8.966072 -24.788742 61.912506 66792 8.673080 -24.996964 62.845062 66793 25.196526 -25.644455 60.824951 66794 1.902481 -28.631561 61.459518 66795 2.895828 -27.161850 61.818390 66796 4.597550 -26.574570 61.985657 66797 44.686508 -29.680466 61.889450 66798 28.009140 -27.071671 61.874786 66799 28.841614 -27.174667 60.835876 66800 29.695183 -27.581345 60.302826 66801 29.690933 -27.647552 61.090668 66802 25.127693 -29.200790 61.965393 66803 25.854126 -28.960373 61.818283 66804 26.322975 -29.397751 62.464691 66805 33.936638 -28.737259 61.139404 66806 35.145271 -28.385635 60.987900 66807 1.908714 -30.373825 60.182800 66808 20.919815 -29.830078 60.579407 66809 20.890640 -28.905396 60.937119 66810 32.415329 -28.637466 61.881210 66811 34.713333 -28.547104 61.723450 66812 21.100021 -31.204208 61.284882 66813 21.274681 -29.633102 61.829117 66814 23.737289 -29.971375 61.096191 66815 28.573914 -30.380447 63.373154 66816 29.793884 -31.081543 62.607193 66817 30.127708 -31.061325 63.783112 66818 35.787384 -32.719513 60.199951 66819 2.187164 -31.261810 60.004303 66820 31.201004 -32.785645 60.576691 66821 30.440460 -31.828110 61.345474 66822 37.749374 -31.239853 62.749023 66823 43.727264 -29.614822 63.255508 66824 44.038239 -30.812378 62.484192 66825 2.623451 -32.580551 60.409088 66826 24.238297 -33.065918 63.113235 66827 3.355072 -33.629669 60.219528 66828 3.566521 -34.080200 59.913696 66829 3.729653 -34.126907 60.384674 66830 16.300064 -33.614792 60.689407 66831 16.591835 -32.915314 61.383926 66832 17.161377 -33.961029 60.620667 66833 17.825676 -33.282120 61.178101 66834 18.026489 -33.920425 60.432709 66835 18.832726 -33.598923 60.684753 66836 18.795334 -34.423874 60.280518 66837 19.756027 -33.932556 60.142975 66838 20.380524 -32.565002 61.554108 66839 31.627001 -33.188828 60.838776 66840 36.023178 -33.660599 61.251099 66841 44.138336 -33.789719 61.569702 66842 16.137787 -34.058716 60.881287 66843 15.766968 -33.451202 60.979507 66844 17.335228 -34.755920 61.250015 66845 15.930344 -34.397888 61.612427 66846 15.137039 -34.700424 63.218048 66847 15.422379 -34.782364 64.018005 66848 13.963402 -34.366623 63.916962 66849 17.922165 -34.337570 60.289459 66850 31.981249 -33.489395 60.665115 66851 32.064484 -32.822754 62.048706 66852 3.877037 -35.984329 60.001190 66853 4.299507 -36.727341 60.583191 66854 3.481476 -36.775955 59.910797 66855 17.995697 -34.662064 60.545380 66856 23.570099 -35.356812 60.760071 66857 34.113861 -34.299789 62.026138 66858 35.062408 -34.393524 61.158813 66859 22.413925 -36.268311 61.735809 66860 21.109055 -35.967926 61.966125 66861 23.078461 -35.905869 61.148987 66862 43.184433 -34.557251 62.515594 66863 43.963257 -34.712326 61.617081 66864 2.387444 -38.762238 59.570984 66865 2.854447 -39.211075 60.518829 66866 29.949265 -39.354309 59.995300 66867 28.853317 -40.612793 60.486740 66868 29.190346 -39.982040 60.415573 66869 40.047333 -39.419403 62.216492 66870 2.164642 -40.590134 59.249542 66871 19.220657 -40.425674 60.953278 66872 20.012207 -40.870056 60.786987 66873 20.662842 -41.585693 61.386902 66874 32.919952 -40.240005 60.119614 66875 33.826096 -40.689346 60.381989 66876 33.646011 -40.266449 59.724503 66877 34.584053 -41.442032 61.262344 66878 33.101334 -41.111572 61.280045 66879 38.638641 -40.091919 60.768494 66880 37.740616 -40.520218 60.714127 66881 38.468155 -40.529343 61.631958 66882 8.348244 -41.604965 59.183167 66883 8.126656 -41.997147 60.550903 66884 9.891678 -41.938828 59.226685 66885 21.915482 -42.784393 60.814529 66886 37.665970 -40.982620 61.719208 66887 3.115425 -42.024170 59.515228 66888 17.149918 -41.567703 60.752472 66889 29.378906 -40.827820 60.925980 66890 30.140068 -41.800308 61.360413 66891 3.927124 -42.799728 59.817215 66892 23.513435 -43.910172 60.024841 66893 28.817604 -43.183533 60.674988 66894 27.238037 -44.272919 60.256134 66895 40.284470 -45.807968 60.164536 66896 40.850464 -47.043594 60.309387 66897 39.723167 -46.481247 60.664185 66898 4.027397 -47.045212 59.382294 66899 5.814392 -46.803360 59.427170 66900 4.966965 -46.906387 59.711578 66901 7.673019 -47.166473 60.128448 66902 36.379341 -46.046875 59.483246 66903 36.991219 -46.021805 59.830963 66904 41.387695 -46.015594 59.468246 66905 9.534210 -46.665070 59.189911 66906 9.533379 -46.783966 59.942841 66907 10.234634 -45.436050 60.790695 66908 9.526314 -47.030243 61.338135 66909 18.382614 -47.500885 59.532822 66910 36.723526 -47.053940 59.848083 66911 18.419876 -48.884796 60.351410 66912 18.351547 -48.249847 60.063812 66913 19.191849 -49.004868 59.586227 66914 36.260643 -48.089249 59.790375 66915 37.167603 -48.213715 60.663361 66916 37.795425 -46.731857 60.379852 66917 20.661285 -49.095978 59.420013 66918 21.711533 -49.109604 59.553375 66919 23.569664 -48.982285 59.897339 66920 22.603561 -49.397491 60.298630 66921 31.340462 -50.287384 63.306885 66922 29.015350 -49.657471 62.615829 66923 38.068810 -49.189392 61.814682 66924 36.812515 -49.307312 61.648346 66925 34.876129 -49.308777 59.665604 66926 3.976746 -51.423553 58.900787 66927 7.374718 -51.612061 59.056458 66928 8.625153 -51.743347 59.377808 66929 33.728561 -49.934067 59.402985 66930 40.651123 -49.714951 60.452972 66931 6.874359 -52.081406 60.434708 66932 7.869400 -51.994385 60.275711 66933 9.645126 -52.417847 59.461304 66934 40.258286 -51.132370 60.556488 66935 7.015259 -55.407669 59.053741 66936 8.747849 -54.169724 60.506836 66937 27.640198 -55.518250 58.310898 66938 37.729317 -54.459564 59.628387 66939 34.928009 -55.364319 59.065414 66940 5.882126 -56.027039 59.369415 66941 27.583641 -57.759796 58.836212 66942 28.347305 -57.144684 59.088791 66943 29.870651 -57.058136 59.220428 66944 34.096558 -55.885208 59.234131 66945 36.234100 -55.567429 60.677521 66946 35.850174 -55.647949 62.048843 66947 37.328171 -54.318649 61.667526 66948 37.270172 -54.842239 60.329803 66949 3.476540 -58.225403 57.924927 66950 3.978172 -57.567856 58.673904 66951 11.906929 -56.959961 59.183228 66952 11.762024 -57.386932 58.601059 66953 11.120239 -57.600037 59.777527 66954 12.343079 -57.038376 58.959198 66955 12.389122 -57.610382 58.529175 66956 13.067474 -57.443939 59.096024 66957 14.747383 -57.658401 59.296722 66958 16.385315 -56.577225 59.644165 66959 16.255280 -57.322571 58.827393 66960 28.417252 -58.375198 59.360168 66961 31.425140 -56.794708 59.319702 66962 32.344093 -57.471207 60.239883 66963 35.150513 -56.021423 60.072281 66964 13.571716 -56.612778 59.567291 66965 19.133499 -58.601013 59.248611 66966 20.809586 -59.119003 59.145920 66967 4.120857 -58.729156 59.872803 66968 9.947510 -58.927750 58.503326 66969 18.168457 -58.239563 60.103806 66970 26.920853 -61.200806 60.550323 66971 27.645355 -60.841431 60.236694 66972 27.494873 -60.436081 59.791672 66973 27.302116 -58.778503 58.886902 66974 27.686661 -59.554108 59.412628 66975 28.533203 -60.037231 60.329865 66976 9.249191 -60.071564 59.455429 66977 9.932182 -58.840164 59.526703 66978 13.285599 -60.497894 60.236069 66979 12.537094 -60.913483 59.334122 66980 12.984993 -59.719971 59.282272 66981 12.643143 -58.725098 58.482361 66982 22.354012 -60.409607 60.010361 66983 23.914833 -61.051987 60.232239 66984 23.922180 -59.931702 59.024109 66985 22.455399 -59.409760 58.784424 66986 4.365311 -60.784851 58.864014 66987 5.176621 -62.131851 59.060883 66988 5.662163 -62.180054 58.203156 66989 8.565750 -61.139191 58.445648 66990 8.321030 -61.684769 59.692963 66991 12.596359 -61.818481 60.205566 66992 19.325905 -64.635712 59.042816 66993 19.059624 -65.248428 59.832733 66994 31.451942 -64.158768 57.748581 66995 11.443787 -63.418442 59.392670 66996 16.401573 -64.346359 59.526611 66997 16.113541 -63.598587 59.189545 66998 25.228378 -67.031677 58.439743 66999 8.298050 -66.532730 57.366531 67000 6.279968 -67.824509 57.801331 67001 9.580772 -66.652786 60.257141 67002 10.939758 -65.590454 60.944550 67003 29.611847 -66.507294 57.569214 67004 5.604263 -68.627823 57.185638 67005 6.074989 -68.833069 58.143906 67006 8.164139 -66.930603 58.337097 67007 7.169693 -67.788742 58.809540 67008 28.680649 -67.374557 57.546570 67009 27.776459 -68.113831 57.658356 67010 27.112022 -68.667511 57.872208 67011 25.217018 -69.237335 58.501663 67012 26.300659 -68.497986 58.231155 67013 24.245750 -68.031631 59.392075 67014 13.672562 -70.088562 58.262909 67015 18.958130 -70.553329 58.296951 67016 6.603607 -69.615677 58.640518 67017 7.112053 -71.656570 57.522064 67018 13.261459 -70.972214 59.889832 67019 13.795174 -70.618103 59.208160 67020 19.993332 -70.612976 58.252045 67021 19.305908 -70.420685 59.075073 67022 20.909058 -70.272552 58.995483 67023 19.442719 -69.371002 60.370117 67024 22.329742 -70.417404 58.690674 67025 23.208321 -70.518951 58.527435 67026 23.810074 -70.557373 57.974579 67027 12.204422 -71.492920 59.472809 67028 8.553665 -70.608337 60.121399 67029 8.488861 -69.579117 60.798538 67030 8.991973 -69.995010 60.888733 67031 8.376450 -72.513031 57.560410 67032 10.852753 -71.932648 59.303009 67033 7.066429 24.406952 64.870300 67034 10.436958 24.944824 64.445801 67035 9.339462 24.791977 64.893311 67036 11.205688 24.047745 65.057465 67037 10.145187 24.411270 65.338318 67038 5.977821 23.996521 64.682800 67039 11.398270 22.444794 65.291595 67040 11.365768 23.146545 65.416809 67041 17.582565 22.074295 64.814224 67042 20.110504 22.197220 64.257904 67043 11.554123 21.816879 64.521347 67044 16.709305 21.499023 64.721878 67045 19.789497 21.184113 64.572754 67046 10.501205 18.922577 65.637360 67047 10.426659 20.599884 66.022644 67048 20.075600 19.362503 64.421265 67049 16.710739 17.742752 64.930695 67050 17.041779 16.510071 65.075897 67051 19.380455 17.814377 65.135406 67052 4.692246 16.400696 66.981216 67053 5.911408 17.481567 67.271118 67054 5.754463 16.325439 68.068527 67055 2.995026 15.571625 63.912140 67056 15.986832 18.640686 64.555695 67057 21.584251 15.863098 64.376221 67058 20.561264 16.758896 64.723740 67059 17.362335 15.449722 65.166016 67060 17.336121 14.052368 64.610626 67061 22.586075 14.770523 64.199768 67062 11.874390 13.767426 64.150635 67063 23.965805 13.493118 63.955551 67064 12.442657 12.376312 64.134003 67065 12.414978 13.171539 65.082458 67066 12.881271 11.792374 65.163300 67067 12.627197 12.845093 65.982452 67068 19.261246 11.874481 64.178284 67069 20.555504 12.024094 64.617676 67070 21.079277 13.523361 65.019196 67071 21.640648 11.921478 65.141983 67072 22.554367 13.074677 64.930359 67073 24.095169 11.786865 64.980469 67074 18.850670 13.694641 65.073914 67075 19.963531 13.510651 65.052353 67076 20.869583 10.883362 65.015167 67077 20.039017 10.687531 64.312195 67078 21.843315 10.784698 65.991669 67079 19.365509 9.659729 64.307663 67080 19.929832 9.945862 65.045853 67081 12.384735 8.577911 63.870056 67082 25.028610 10.352264 64.800507 67083 16.690979 7.239670 66.559479 67084 15.784920 6.318634 66.219681 67085 16.918015 7.764572 64.113037 67086 5.348534 6.619324 64.337708 67087 6.167694 6.610489 65.428741 67088 6.496010 5.997337 64.568665 67089 6.618485 5.771080 63.533630 67090 25.302650 5.855927 64.089233 67091 25.445152 7.239014 64.543945 67092 23.939011 4.273285 62.856842 67093 25.760979 4.641449 64.266907 67094 26.462845 4.040329 64.597809 67095 26.293480 4.667786 65.127930 67096 13.764725 3.914856 63.597778 67097 7.070717 4.767303 63.936005 67098 11.361954 3.479782 64.530212 67099 11.448425 4.343002 63.874390 67100 13.364471 2.963852 63.969986 67101 26.321884 3.673416 64.114365 67102 27.095909 3.132980 64.781281 67103 3.172180 1.749710 64.112579 67104 15.373428 2.376099 63.720520 67105 14.548843 1.996902 63.853943 67106 16.097992 2.841705 64.360077 67107 17.403778 2.210663 63.578644 67108 17.514023 2.791992 64.876755 67109 18.373718 2.742950 65.986176 67110 18.758057 1.732986 64.916046 67111 26.709869 4.007217 65.016739 67112 18.946365 1.087906 63.553436 67113 14.525894 0.852875 64.305817 67114 15.222900 -0.277771 64.734497 67115 16.913589 3.293839 65.297852 67116 17.721191 3.237457 65.973389 67117 19.858734 -0.379974 64.259399 67118 28.407822 0.091003 63.972183 67119 28.193451 1.185837 64.831802 67120 2.699333 -0.749405 62.944244 67121 15.957565 -1.220505 63.857010 67122 19.889549 -1.069138 63.723358 67123 34.744194 -0.469894 63.548584 67124 35.071541 -0.354126 63.563004 67125 35.212555 -0.775330 63.549332 67126 3.323143 -2.631744 64.897186 67127 28.842194 -1.066895 64.737228 67128 34.886253 -0.888245 63.527863 67129 35.233505 -1.574432 63.075806 67130 20.094131 -2.638550 64.443817 67131 6.025856 -3.980331 64.919800 67132 5.722984 -3.463593 64.025665 67133 4.851074 -3.516937 64.847351 67134 6.170456 -3.613968 62.981201 67135 28.436935 -3.212631 64.508911 67136 28.426834 -2.006866 63.683792 67137 8.280258 -4.669159 62.702393 67138 7.278610 -4.429962 63.995087 67139 8.393387 -5.055603 63.527740 67140 26.800552 -6.038239 63.904877 67141 26.741104 -5.625290 64.091583 67142 26.679626 -5.497513 63.390900 67143 16.039276 -6.932755 63.292801 67144 6.194107 -7.644318 62.723343 67145 4.812698 -8.608597 62.366302 67146 6.765228 -6.771149 64.303284 67147 5.189285 -8.095856 63.688049 67148 8.516190 -5.807220 63.197968 67149 8.296112 -5.619019 63.898499 67150 7.987297 -6.246185 63.741974 67151 16.918816 -8.468338 63.510681 67152 17.260986 -7.299332 66.029968 67153 16.246185 -7.117294 64.563324 67154 28.092438 -6.386215 64.809006 67155 29.610641 -6.645935 64.931061 67156 4.105026 -9.357376 63.133545 67157 17.747467 -9.718552 63.759125 67158 17.841339 -9.019806 64.854614 67159 17.315155 -9.612564 62.858124 67160 20.736229 -7.520645 63.699493 67161 31.275505 -9.371414 63.472015 67162 37.728844 -10.055115 63.491638 67163 3.445664 -10.613464 62.477936 67164 17.704613 -10.450989 62.722824 67165 21.292603 -8.673828 63.638580 67166 35.077271 -10.439178 63.102020 67167 38.651978 -10.738052 64.094650 67168 3.322617 -11.383911 62.098282 67169 18.153824 -11.484589 62.720917 67170 28.311089 -12.766769 62.704254 67171 28.778549 -12.143585 63.123550 67172 29.317993 -11.516251 63.399536 67173 31.536194 -15.089645 62.854553 67174 3.743271 -11.553986 62.628510 67175 4.497261 -11.971664 63.327240 67176 22.292381 -10.607376 63.630493 67177 21.810112 -9.621002 63.774948 67178 5.375031 -12.757431 62.781494 67179 18.712738 -12.448532 62.855682 67180 24.138260 -12.729752 63.148331 67181 32.374237 -13.299698 64.524353 67182 32.037003 -14.157425 64.037170 67183 33.078026 -12.223312 64.383514 67184 8.915268 -14.600494 62.228271 67185 31.414726 -14.053909 63.355682 67186 19.149940 -14.378006 62.672333 67187 42.115326 -14.911163 63.515015 67188 3.418381 -16.884277 62.270874 67189 9.465752 -15.260284 62.316742 67190 9.362000 -16.494125 63.037521 67191 9.715790 -15.650024 62.668365 67192 10.082656 -15.752411 63.180832 67193 20.307838 -16.164246 62.438873 67194 5.341011 -16.566711 63.350922 67195 6.864334 -16.586197 65.902313 67196 6.556564 -16.591019 64.822449 67197 7.923927 -16.955048 65.317139 67198 7.837326 -16.690735 63.209030 67199 21.322464 -16.808441 63.315292 67200 24.615448 -17.038620 62.749283 67201 27.001129 -17.463348 62.790375 67202 24.122437 -16.627502 64.671326 67203 1.853691 -19.110718 62.833466 67204 2.938492 -17.346954 63.241455 67205 1.754341 -19.418945 61.705963 67206 26.842010 -17.028442 63.607513 67207 33.942062 -19.023529 62.844360 67208 42.290588 -18.099625 62.791870 67209 29.688431 -18.952560 63.403595 67210 41.635468 -18.714737 63.764694 67211 41.362854 -17.185867 64.212891 67212 29.739853 -19.749725 62.309143 67213 42.025772 -19.384323 62.720932 67214 30.427055 -20.549896 62.401398 67215 33.551758 -21.168625 63.012573 67216 33.056686 -22.100616 63.413361 67217 32.691391 -21.691513 62.565125 67218 1.705772 -20.691681 64.575226 67219 1.657486 -20.683884 63.543427 67220 1.989121 -18.824448 64.090759 67221 31.908876 -21.618896 62.486786 67222 32.419174 -21.995163 62.828094 67223 32.101822 -22.095016 63.353775 67224 41.100357 -21.731842 62.543579 67225 2.502701 -22.751923 61.631744 67226 2.563812 -22.679535 63.036102 67227 2.542496 -22.822083 62.454819 67228 1.907936 -21.546295 62.569946 67229 42.971283 -24.811356 61.889130 67230 8.868881 -24.168213 62.853760 67231 20.980713 -24.724197 62.007568 67232 22.873840 -24.825623 62.112778 67233 43.717941 -25.046783 62.205536 67234 24.214142 -25.400650 61.730225 67235 23.302567 -25.008163 62.048325 67236 38.017265 -26.586136 63.485229 67237 39.060982 -25.411209 64.148071 67238 6.645851 -26.254578 62.178802 67239 7.922019 -25.579437 62.842407 67240 25.506050 -26.007645 61.660889 67241 29.052841 -27.478012 61.737427 67242 1.757874 -30.619888 61.263535 67243 24.101868 -29.930038 61.889221 67244 28.760910 -27.566330 62.763641 67245 30.143188 -28.008408 61.857239 67246 32.615921 -28.747375 60.752777 67247 21.123932 -28.186035 61.991180 67248 24.487160 -29.716843 62.622620 67249 24.151413 -30.091370 62.705368 67250 34.696793 -28.477478 62.739441 67251 34.143372 -28.746109 64.835297 67252 32.464569 -28.726883 64.264771 67253 32.672760 -28.772568 65.149033 67254 27.408096 -29.747070 61.718109 67255 38.162613 -30.906647 63.993500 67256 36.469887 -32.222198 60.760895 67257 14.171127 -32.168503 62.343964 67258 15.284454 -32.702652 61.590363 67259 14.426720 -32.864273 61.594360 67260 16.107399 -32.188065 62.309998 67261 16.809464 -32.379379 62.255188 67262 19.049118 -32.936920 61.945465 67263 17.601746 -32.607162 62.231354 67264 3.112953 -33.796738 61.371002 67265 1.845787 -32.304230 62.175598 67266 1.831764 -33.925186 63.356415 67267 3.996681 -34.696228 60.950989 67268 14.968338 -33.676575 61.486053 67269 13.661256 -33.024170 61.869812 67270 19.537079 -32.660233 63.016083 67271 20.152946 -32.638397 62.482330 67272 34.621216 -34.345337 63.629196 67273 33.637878 -33.384674 63.538086 67274 36.743896 -33.135376 62.160095 67275 42.727264 -31.803375 63.571320 67276 4.477112 -35.945023 60.755463 67277 4.340653 -35.236069 60.791626 67278 13.932724 -33.862564 62.295181 67279 36.213783 -34.474243 63.412598 67280 35.326492 -34.892120 63.036041 67281 35.743309 -34.987717 62.865143 67282 43.269684 -30.463943 63.619690 67283 19.969360 -35.656586 61.405685 67284 35.595802 -34.655746 62.263855 67285 4.676994 -36.678818 61.038910 67286 19.128769 -35.393036 62.149109 67287 3.851036 -37.435516 60.548737 67288 4.401024 -37.328720 61.351440 67289 4.123673 -38.064468 61.602539 67290 3.723457 -38.152557 60.959137 67291 2.505341 -40.788376 59.932816 67292 40.617676 -36.428879 64.577866 67293 30.092331 -40.369171 60.934418 67294 31.161613 -40.844925 61.310379 67295 2.887810 -40.677185 61.405197 67296 3.624893 -38.925552 61.718826 67297 17.070862 -40.861313 61.084137 67298 18.407104 -40.052765 61.875336 67299 39.210701 -40.004883 61.497421 67300 39.184158 -40.271027 62.725449 67301 8.837952 -41.626556 60.358459 67302 9.650421 -41.912933 60.130859 67303 10.217834 -43.266129 60.589661 67304 32.899940 -42.295074 62.217010 67305 33.847610 -42.131332 62.119202 67306 23.291855 -43.946823 61.428604 67307 22.472733 -43.161331 62.516998 67308 23.243729 -43.841248 62.495789 67309 37.073425 -41.588623 62.461151 67310 2.804451 -41.863876 60.587708 67311 3.241753 -42.636322 60.504181 67312 3.902931 -43.211670 61.040985 67313 4.656921 -43.149628 60.353455 67314 6.596192 -43.086517 61.246246 67315 29.517242 -43.457748 61.491180 67316 17.626228 -43.967667 61.168671 67317 16.996246 -42.461533 61.594727 67318 28.292191 -44.077301 60.882645 67319 17.952972 -45.076813 60.585236 67320 27.409904 -44.854889 61.295349 67321 18.204178 -47.326614 60.410614 67322 18.157043 -46.151169 60.771271 67323 38.863579 -46.776627 60.804169 67324 3.510925 -47.342056 60.149521 67325 2.980988 -47.805206 60.269623 67326 3.599823 -47.555054 61.150879 67327 4.595146 -47.241318 60.898010 67328 4.159927 -47.423004 61.671173 67329 5.638313 -47.096695 60.586868 67330 6.634178 -47.144409 60.493546 67331 8.581558 -47.354111 60.450287 67332 40.139496 -47.172958 60.902298 67333 39.539246 -47.269714 61.031723 67334 18.673889 -49.376587 60.582062 67335 20.001953 -49.833603 60.114594 67336 21.111778 -49.964874 60.641220 67337 22.521881 -50.035538 61.446686 67338 27.083290 -49.020447 60.290009 67339 28.347115 -49.226074 60.905609 67340 27.588623 -49.387848 61.946594 67341 35.828934 -49.105743 60.646118 67342 2.471848 -50.239136 61.682434 67343 3.155350 -51.413239 60.682846 67344 19.350357 -50.054855 60.635025 67345 20.055962 -50.318115 60.749878 67346 23.821182 -49.536224 61.269135 67347 33.038857 -49.896988 60.013748 67348 29.935455 -50.242706 64.145798 67349 32.538628 -49.832031 61.380188 67350 34.240227 -49.701263 60.901443 67351 40.241074 -48.104507 60.863190 67352 3.472618 -51.335754 59.796860 67353 5.370247 -51.983292 59.692749 67354 8.791893 -52.350449 60.351776 67355 9.255219 -51.963593 59.572662 67356 6.570786 -56.084808 60.548935 67357 8.147873 -54.774612 59.684723 67358 7.741150 -55.239075 61.201630 67359 8.540550 -54.197342 61.325989 67360 8.657310 -53.357574 61.235123 67361 15.288445 -55.796494 59.990601 67362 14.261665 -56.141174 59.851990 67363 14.281380 -55.236282 60.775772 67364 15.914688 -55.093552 60.524734 67365 16.607010 -55.416504 60.827652 67366 16.092377 -55.594498 60.025925 67367 38.122253 -54.218903 60.416779 67368 5.160179 -56.565048 59.676544 67369 4.521271 -57.139923 59.489990 67370 15.231742 -54.756851 61.094803 67371 13.429253 -55.887283 60.213898 67372 11.061310 -58.373901 61.591797 67373 10.074043 -58.919830 60.352509 67374 12.498199 -56.643738 59.799942 67375 13.403442 -58.555420 59.285706 67376 13.920380 -59.131760 59.821838 67377 17.430969 -57.321503 59.752594 67378 33.738785 -56.740128 60.075653 67379 35.425743 -56.285599 61.086243 67380 35.657471 -56.055313 60.551056 67381 4.097283 -59.394928 61.045380 67382 4.114510 -60.405045 60.518326 67383 14.729805 -59.170303 59.579010 67384 14.428238 -58.532120 59.683029 67385 29.451736 -58.754822 59.924805 67386 30.427338 -58.613922 60.346375 67387 31.136230 -57.769958 60.026230 67388 28.857132 -60.436844 61.405411 67389 29.639145 -59.895721 61.569427 67390 29.813934 -59.494995 60.652069 67391 30.549561 -59.319748 61.156311 67392 14.322906 -60.389160 60.396118 67393 15.154137 -60.308899 59.591705 67394 19.238731 -59.336334 60.379776 67395 25.447304 -61.038605 60.440170 67396 23.269768 -61.388504 61.039978 67397 22.001656 -61.232391 61.371811 67398 5.884377 -62.879807 59.508423 67399 5.103462 -62.777145 60.180420 67400 24.395554 -61.623016 61.313385 67401 27.717239 -61.060455 60.945557 67402 6.156044 -62.546158 58.635284 67403 7.068070 -62.786057 59.544495 67404 6.036186 -63.461060 60.507141 67405 14.936218 -60.999084 60.190002 67406 11.653923 -64.017166 60.488098 67407 16.729980 -64.846817 59.864227 67408 17.468887 -65.106689 59.770126 67409 22.007355 -65.793427 59.388306 67410 23.417892 -66.734024 59.361099 67411 8.292778 -67.520798 59.746338 67412 9.112801 -66.545563 59.080673 67413 6.494400 -68.547043 58.700500 67414 7.630554 -71.041595 58.722595 67415 13.839005 -70.290131 58.631500 67416 14.756569 -70.289474 59.015045 67417 18.455856 -70.444366 58.818359 67418 23.945007 -70.063812 58.783966 67419 22.973877 -70.113297 59.213394 67420 23.269989 -69.392670 59.617065 67421 24.170593 -69.133133 59.347763 67422 8.743958 -71.469269 59.387558 67423 18.034927 -70.108612 59.671356 67424 20.984276 -69.200775 60.170914 67425 11.658463 -71.307892 60.575745 67426 8.092690 23.937561 65.742828 67427 7.311546 23.241913 65.743759 67428 8.411591 24.532990 65.229156 67429 9.270233 23.806580 65.861755 67430 10.919563 23.279877 65.755066 67431 6.430023 22.097778 65.530167 67432 6.400955 23.402878 65.113800 67433 17.409958 20.425217 65.107407 67434 10.888168 21.649796 65.542572 67435 10.426453 21.511063 66.192200 67436 17.878899 19.412613 65.412430 67437 17.058990 18.983948 65.169128 67438 6.167610 20.399841 65.720856 67439 7.272377 18.857605 67.144073 67440 18.792450 19.799713 65.124908 67441 3.775940 15.842911 66.100693 67442 18.519592 16.312363 65.434448 67443 18.081955 17.431152 65.420135 67444 19.761971 16.387329 65.211426 67445 20.470474 14.549438 65.278702 67446 19.514114 15.086792 65.367676 67447 20.660957 15.485855 65.066055 67448 11.890945 14.574203 65.867096 67449 11.262871 16.244141 66.378174 67450 18.202179 14.765732 65.272766 67451 21.582840 14.599472 64.864044 67452 20.971558 14.608170 65.133453 67453 18.071335 13.850891 64.957886 67454 18.200546 13.079025 64.554352 67455 22.898079 11.396667 65.752991 67456 12.969414 10.595047 65.007736 67457 13.206834 10.991852 65.536194 67458 13.206200 11.482941 65.986053 67459 22.761879 10.750946 66.355713 67460 12.989410 10.333878 66.034286 67461 12.667519 9.412476 64.953094 67462 25.038460 8.942520 65.592529 67463 18.999153 9.260040 65.027191 67464 18.282806 8.640762 66.038452 67465 17.094406 7.917740 65.215759 67466 3.127373 9.924133 66.325714 67467 3.386078 8.590836 65.328003 67468 2.892410 10.730209 65.944183 67469 12.133469 7.862442 65.033035 67470 2.976624 8.537567 64.252594 67471 3.337784 7.793350 64.262207 67472 4.075279 7.447510 64.729645 67473 11.686554 6.634201 64.598694 67474 11.327431 5.577438 64.797424 67475 15.270386 5.470703 65.589691 67476 15.616623 4.619125 66.124634 67477 15.025795 4.334236 65.243393 67478 25.732056 6.030762 65.232025 67479 14.349312 4.125374 64.398560 67480 25.976768 5.203430 66.372238 67481 6.700302 4.511894 65.212280 67482 11.769318 2.763000 64.850998 67483 11.197678 5.521774 65.728668 67484 10.997063 4.243454 65.379089 67485 12.121811 1.877563 65.632889 67486 13.249939 1.892776 64.571625 67487 14.104233 3.365677 64.256073 67488 14.644592 2.782028 64.204071 67489 14.909256 3.437363 64.732971 67490 3.494751 2.267548 65.545410 67491 13.334358 1.079071 65.370239 67492 27.643326 2.579941 65.675598 67493 2.561195 0.526215 63.710510 67494 19.382629 0.596848 64.246140 67495 19.701317 1.210175 66.343811 67496 19.869743 0.459442 65.493073 67497 20.223770 -1.396652 64.607437 67498 34.983040 -0.621475 63.690186 67499 29.182640 -2.252121 65.485260 67500 29.331848 -1.543961 65.541046 67501 20.190720 -3.640625 64.639053 67502 8.011283 -5.205856 64.293396 67503 15.435546 -5.597641 64.345306 67504 15.549133 -5.066345 64.058731 67505 27.530365 -4.906921 64.452301 67506 26.938148 -5.379028 64.182312 67507 15.520981 -6.213409 63.986984 67508 20.402039 -6.627213 63.922638 67509 20.898529 -6.507675 64.758301 67510 31.784182 -7.375061 63.835678 67511 31.139023 -7.238983 65.118820 67512 5.189957 -7.512100 64.906250 67513 27.351891 -6.397980 64.024445 67514 30.511444 -6.673416 64.949692 67515 18.905258 -9.314590 66.230713 67516 31.868784 -8.090302 64.296173 67517 21.778091 -8.396622 64.793793 67518 22.528534 -8.247314 65.957550 67519 22.982147 -9.687256 65.570801 67520 30.142998 -10.421753 64.642838 67521 30.324738 -10.263000 66.167465 67522 30.918678 -9.580536 65.758820 67523 31.807741 -8.650223 64.050232 67524 31.311256 -8.714386 65.081970 67525 18.287064 -10.746841 63.764053 67526 35.162888 -10.475113 63.982193 67527 36.897797 -10.817215 64.854523 67528 35.966438 -10.374771 64.489075 67529 22.570518 -10.274521 64.565613 67530 39.799454 -11.209473 63.933838 67531 18.678551 -11.637146 63.630890 67532 19.251129 -12.414337 64.107025 67533 23.078873 -11.175537 64.576385 67534 28.196182 -12.145386 64.105026 67535 40.361465 -12.142700 64.043564 67536 7.537079 -13.277084 63.431564 67537 24.423004 -12.261963 64.602600 67538 25.939056 -12.671051 64.261230 67539 24.964157 -12.104675 65.320190 67540 40.632935 -13.146439 64.311279 67541 8.794983 -13.860840 63.404083 67542 9.778198 -14.789429 63.099060 67543 19.241875 -13.404221 63.358917 67544 41.313217 -13.949692 64.012878 67545 19.417549 -15.268311 63.386566 67546 19.402100 -14.323013 63.835876 67547 33.121674 -15.454834 64.216080 67548 41.018478 -15.361404 64.550827 67549 40.176208 -14.047348 64.883041 67550 32.693222 -13.998230 64.797699 67551 4.044022 -16.795822 62.948547 67552 3.514877 -16.828690 65.358093 67553 10.125717 -16.455231 63.925522 67554 9.101624 -16.972794 63.558151 67555 26.224197 -16.474854 64.786011 67556 33.855652 -16.891174 63.723236 67557 27.757629 -17.444473 63.534561 67558 35.215202 -17.718231 65.358124 67559 34.370148 -16.610840 64.796661 67560 35.228279 -16.196320 65.992126 67561 34.305504 -17.852448 63.718842 67562 34.660706 -18.996597 64.301849 67563 30.351593 -19.927750 63.407562 67564 34.139450 -20.089493 63.562622 67565 41.760147 -19.656342 63.341949 67566 41.249863 -19.496552 63.983398 67567 31.039391 -20.882446 63.624359 67568 31.456985 -21.668854 63.333649 67569 40.944290 -21.655350 63.408783 67570 40.562241 -20.172150 64.541626 67571 6.118965 -23.093475 62.885254 67572 8.034927 -23.361221 63.141037 67573 8.256332 -23.650330 64.322968 67574 8.603752 -24.155579 63.731628 67575 32.600952 -22.469910 64.309174 67576 40.300369 -22.546463 64.094772 67577 3.394005 -23.120010 62.510193 67578 21.311432 -24.333618 63.383301 67579 20.769623 -25.082428 63.718292 67580 21.313324 -24.274811 64.733429 67581 23.435623 -24.839325 63.391907 67582 24.071686 -24.929626 64.848236 67583 24.510620 -25.413971 64.643402 67584 39.844254 -24.019135 63.280029 67585 21.354538 -24.480942 62.596039 67586 20.677551 -25.029816 62.553131 67587 22.075539 -24.373154 63.034012 67588 25.365517 -26.075409 62.784882 67589 43.084381 -25.511826 62.570251 67590 43.825577 -26.286774 62.528534 67591 42.648651 -26.588043 63.122131 67592 41.540894 -26.769623 63.054993 67593 5.599434 -26.058777 63.584778 67594 6.480759 -25.993378 63.505432 67595 20.700333 -26.070465 62.775635 67596 21.146629 -27.230286 62.928711 67597 21.079170 -26.216644 64.296265 67598 40.845673 -27.378830 63.117432 67599 1.822487 -27.597565 62.918488 67600 2.607193 -26.607635 63.281952 67601 21.512764 -27.988708 62.973755 67602 27.041901 -26.900925 62.872437 67603 26.123611 -26.535507 63.941681 67604 43.636185 -27.604675 63.147446 67605 42.849136 -27.575378 63.757874 67606 21.701637 -28.865540 63.017242 67607 30.602478 -28.265747 62.907318 67608 44.043518 -28.664597 62.902374 67609 21.676529 -29.773636 62.700073 67610 25.140228 -29.920624 63.343536 67611 26.164177 -29.878082 63.855957 67612 40.288300 -29.734085 65.196777 67613 21.577408 -30.591583 62.521973 67614 27.720474 -29.948792 62.557312 67615 42.790207 -29.656006 64.181915 67616 43.019455 -28.496902 63.849594 67617 1.194061 -30.787582 63.077408 67618 12.650322 -31.737976 64.144775 67619 10.465042 -31.818741 65.069824 67620 11.189095 -31.610291 68.063934 67621 12.738571 -32.441849 62.517166 67622 15.323410 -32.022461 62.352844 67623 21.000809 -32.006287 62.536957 67624 21.431320 -31.364944 62.430801 67625 30.814835 -31.660538 62.712982 67626 37.133011 -32.777084 63.363892 67627 12.765030 -32.963394 62.085587 67628 12.097000 -33.130310 62.530945 67629 13.052025 -33.416550 62.126892 67630 1.497055 -32.729584 63.101593 67631 3.567810 -34.999084 61.785889 67632 36.433151 -33.920410 62.482513 67633 2.807556 -34.869553 62.405258 67634 4.235893 -35.744171 61.466675 67635 13.029648 -33.824203 62.693161 67636 12.231094 -33.956482 63.311172 67637 15.027664 -34.353958 62.446228 67638 16.610565 -34.878845 62.848236 67639 24.464989 -34.906708 62.839340 67640 23.834000 -35.646469 61.839264 67641 24.330345 -32.351517 64.042786 67642 24.151390 -31.064392 63.097748 67643 4.244827 -36.732498 61.879929 67644 3.247704 -36.354645 62.550552 67645 3.942947 -37.726959 62.175262 67646 20.371155 -35.775528 63.081329 67647 23.955383 -36.385284 63.231125 67648 24.887634 -36.045197 63.925598 67649 4.608391 -36.523392 61.378632 67650 22.557785 -36.479950 62.794724 67651 21.607407 -36.190994 63.434525 67652 24.654816 -36.657776 64.207275 67653 23.246193 -36.330322 62.172302 67654 35.513618 -34.708557 63.895203 67655 41.222076 -30.576706 64.938202 67656 42.240005 -30.291428 64.458557 67657 2.626953 -41.730942 63.441635 67658 2.650055 -42.390167 63.492523 67659 2.800079 -41.356766 62.744217 67660 3.037514 -42.451157 61.844437 67661 17.046745 -40.415070 61.648132 67662 16.466599 -40.581375 62.385422 67663 16.921371 -39.904160 62.516556 67664 16.699997 -41.229706 61.689301 67665 17.630974 -40.015182 61.812958 67666 19.534416 -40.624435 62.087219 67667 32.058708 -40.812698 61.357391 67668 9.243530 -42.141159 61.243317 67669 31.194298 -41.993942 61.759140 67670 32.040634 -41.543304 61.720154 67671 38.235519 -41.033203 63.119019 67672 10.296707 -45.654404 61.784149 67673 10.203934 -43.660172 62.126465 67674 10.318619 -45.260406 62.687134 67675 30.880745 -43.054855 62.074707 67676 31.913012 -42.665756 62.259094 67677 35.848862 -41.768768 61.936234 67678 34.845032 -42.453476 62.575073 67679 36.095993 -42.395599 63.158325 67680 4.894226 -43.541962 61.442795 67681 5.836166 -43.531876 61.665344 67682 6.649506 -43.419342 62.519775 67683 23.914093 -44.290955 62.100662 67684 23.847458 -44.014435 62.895157 67685 18.044922 -45.066315 61.802505 67686 17.296989 -43.447906 63.013443 67687 21.482895 -42.262131 62.548309 67688 26.352310 -44.887711 61.357605 67689 26.955978 -45.253754 61.929108 67690 24.833038 -44.521805 61.370895 67691 28.451485 -44.754639 61.925781 67692 30.532303 -44.099091 62.557755 67693 27.545761 -45.246490 62.024994 67694 27.914726 -45.268433 62.707977 67695 2.948776 -48.452118 61.601059 67696 7.539810 -47.553696 61.078812 67697 18.398689 -47.096481 61.506653 67698 8.449661 -47.663284 61.326019 67699 8.741432 -47.776016 61.957886 67700 18.524178 -48.426117 61.333496 67701 38.779266 -48.028183 61.172729 67702 2.953484 -48.414215 63.472351 67703 2.400108 -49.105530 62.729935 67704 21.535278 -50.633606 61.743134 67705 25.020020 -49.436630 61.704987 67706 26.317245 -49.397430 62.036865 67707 37.319244 -50.216522 62.650085 67708 39.009995 -49.059525 61.713959 67709 39.676270 -49.011703 61.359131 67710 18.946274 -49.790298 61.448517 67711 19.017090 -49.322968 62.404480 67712 19.115280 -48.410599 62.819061 67713 20.095909 -50.736710 61.971313 67714 23.311035 -50.145065 62.451935 67715 35.161705 -50.318878 63.339935 67716 34.163620 -50.082352 62.920273 67717 35.674179 -49.889359 62.331757 67718 3.911041 -52.329941 61.108887 67719 2.822525 -52.005478 62.018219 67720 19.189285 -50.066925 62.152832 67721 3.948174 -51.780716 60.061462 67722 39.239792 -50.272675 61.790222 67723 5.052818 -53.089218 61.925110 67724 6.272011 -52.543472 61.174530 67725 7.655296 -52.646942 61.406891 67726 39.610466 -51.711624 61.270294 67727 8.208359 -54.040863 61.935272 67728 15.975983 -54.664856 61.682602 67729 16.703758 -54.931366 61.926697 67730 5.721375 -56.535797 60.368454 67731 12.734497 -55.973648 60.749466 67732 12.025421 -56.617630 61.096710 67733 12.771523 -55.898438 61.547150 67734 13.351379 -55.477753 61.096268 67735 17.467484 -56.818512 61.187836 67736 4.964874 -57.315598 60.493286 67737 11.442001 -57.328537 61.200897 67738 17.149857 -55.408188 62.247070 67739 34.472137 -56.907608 61.086105 67740 18.309525 -58.782944 61.481705 67741 18.975571 -59.976151 62.293488 67742 19.130356 -59.832291 61.264740 67743 17.663383 -56.120087 63.394211 67744 31.527046 -58.613525 61.093903 67745 33.293701 -57.604919 61.094574 67746 32.484863 -58.123550 61.100311 67747 9.816391 -59.983948 61.302521 67748 20.364380 -60.469421 61.187653 67749 4.523522 -61.755386 60.168518 67750 8.929596 -60.909561 60.540436 67751 12.040939 -62.837799 60.052460 67752 14.526855 -61.751495 60.782257 67753 8.651451 -61.690414 60.952576 67754 8.063698 -62.559326 60.897308 67755 7.132477 -63.417603 60.981781 67756 27.139038 -61.477509 61.629181 67757 15.914368 -64.374939 60.659012 67758 12.694656 -64.628922 61.868256 67759 11.555672 -66.611542 62.253937 67760 15.254196 -65.257492 61.882828 67761 14.147896 -64.595093 62.113770 67762 14.988434 -64.121246 61.569702 67763 18.209213 -65.552490 60.294754 67764 16.854904 -65.765167 61.057953 67765 19.086227 -65.863815 60.411621 67766 10.304016 -66.661163 61.209641 67767 21.014847 -66.667282 60.211090 67768 22.242203 -66.885971 59.896790 67769 7.487610 -68.643707 59.881500 67770 9.700790 -67.080292 60.972839 67771 23.032898 -67.734711 59.891754 67772 23.545479 -68.568542 59.793610 67773 21.679489 -68.024643 60.311737 67774 6.891861 -68.827774 59.271194 67775 7.346413 -69.723160 59.588776 67776 22.141953 -69.488342 59.758972 67777 22.772385 -68.615356 60.032944 67778 14.453995 -70.646179 60.207275 67779 16.222794 -70.231812 59.437119 67780 16.977432 -69.936340 60.659378 67781 18.129959 -69.715515 60.590698 67782 20.499680 -68.530563 60.634598 67783 13.526947 -70.254074 61.550385 67784 14.843437 -70.181870 61.436859 67785 15.279900 -70.536377 59.840805 67786 9.699425 -71.591415 59.731079 67787 10.640060 -71.315018 60.480408 67788 10.377380 23.753052 65.755356 67789 8.286087 23.024948 66.211685 67790 9.112137 22.306305 66.535416 67791 10.265762 22.541199 66.099411 67792 7.515686 22.132431 66.268204 67793 11.023453 22.596786 65.740204 67794 7.179215 20.724792 66.536606 67795 18.097717 18.529846 65.395050 67796 10.767761 17.382050 66.078522 67797 3.488915 14.516220 66.471252 67798 3.236450 14.854446 65.548798 67799 2.978485 13.589813 65.540573 67800 12.381454 13.317520 66.773926 67801 11.899445 14.130142 67.137863 67802 12.965408 12.047989 65.992081 67803 24.086632 10.524658 65.891998 67804 13.289642 10.927551 65.986404 67805 23.845169 9.554596 66.725204 67806 20.727676 10.158417 65.962280 67807 12.522995 8.956390 66.200745 67808 19.536606 9.455963 65.986023 67809 20.638016 9.592529 66.944031 67810 19.380821 9.080292 66.902954 67811 23.272446 10.310349 66.576447 67812 23.312256 10.782410 66.245270 67813 4.812363 7.712311 66.181488 67814 5.628365 7.072449 65.589905 67815 5.961510 7.131027 66.364059 67816 12.089050 7.628067 66.377289 67817 11.649483 6.568634 65.747253 67818 6.689354 5.683220 65.564667 67819 25.365295 7.579163 65.881317 67820 6.443092 4.941772 66.196945 67821 11.043243 4.982697 66.311890 67822 26.774216 4.008133 65.732025 67823 4.791977 3.106766 65.247009 67824 5.719414 3.863365 65.785217 67825 10.895554 4.277855 66.490448 67826 11.081551 3.332413 65.036377 67827 15.976624 3.696960 65.525131 67828 17.085800 3.624092 66.385071 67829 27.222404 3.327332 65.681580 67830 2.576096 0.541489 64.836578 67831 10.899513 3.307053 65.503006 67832 11.130829 2.830933 66.085861 67833 11.767258 2.025803 66.975616 67834 2.411202 1.151459 68.191437 67835 2.733200 1.859482 68.504364 67836 3.045891 1.036057 69.031067 67837 14.230370 0.430603 65.459488 67838 14.798004 -0.108109 66.057663 67839 14.112907 0.373566 66.244537 67840 20.486771 -0.597229 65.864288 67841 29.051956 -0.543228 65.595337 67842 28.716927 0.143204 65.611053 67843 29.245056 -1.025375 65.696899 67844 16.014038 -1.299347 65.822571 67845 16.103325 -3.729721 65.027878 67846 16.368912 -2.755768 65.541153 67847 2.487785 -1.273865 65.382629 67848 4.088783 -3.188904 64.788605 67849 4.610970 -4.261566 65.906372 67850 4.903961 -5.574554 66.414154 67851 5.719032 -5.422592 65.968704 67852 21.488762 -3.441284 66.550171 67853 21.863144 -5.664764 66.366776 67854 21.875015 -7.105850 65.800568 67855 27.242027 -5.769394 64.560974 67856 28.112946 -5.694641 65.650421 67857 15.534012 -5.811295 64.887756 67858 16.021240 -5.973480 65.382431 67859 15.741989 -4.877884 64.737335 67860 7.847458 -5.861115 64.352448 67861 20.994781 -1.724121 66.146576 67862 15.385796 -6.131134 64.560974 67863 5.887505 -6.773392 65.367874 67864 7.326500 -5.503128 64.836761 67865 15.673615 -6.464600 64.530457 67866 29.357079 -6.761734 66.827881 67867 28.687660 -6.432007 65.787384 67868 31.157028 -7.706467 65.923996 67869 30.892502 -7.227188 66.005432 67870 30.407455 -6.778549 65.286255 67871 31.109055 -8.417358 66.324341 67872 31.208427 -9.040466 65.988129 67873 18.626427 -10.122528 64.907684 67874 34.386200 -11.205444 64.746582 67875 36.037140 -10.571991 65.120041 67876 4.450951 -11.637146 64.443192 67877 19.181747 -11.285919 64.840546 67878 35.387924 -10.689194 65.013702 67879 38.132797 -11.701614 65.176727 67880 39.286438 -11.882080 64.640411 67881 38.814621 -12.529221 65.227692 67882 3.756363 -10.608017 65.243713 67883 5.447357 -12.309860 65.052124 67884 5.889023 -12.642838 63.851898 67885 7.784355 -12.907806 65.130127 67886 27.539352 -12.196320 65.455505 67887 32.992798 -13.130692 65.044373 67888 39.711166 -12.955017 64.791504 67889 10.096832 -14.055740 64.470352 67890 10.423828 -15.283783 63.689163 67891 19.971931 -12.339767 65.445755 67892 20.078781 -11.247482 66.367386 67893 10.891846 -15.246506 64.329498 67894 11.351547 -14.481201 65.457275 67895 11.038193 -15.771042 64.860870 67896 19.721283 -13.499054 64.850479 67897 39.894974 -16.096817 65.486557 67898 39.755669 -14.910583 65.395020 67899 4.079582 -16.673492 63.797958 67900 6.176712 -16.348297 65.688446 67901 19.423523 -15.088486 64.921005 67902 1.771256 -18.909714 65.583527 67903 5.320793 -16.370682 65.057297 67904 4.532089 -16.450851 64.347321 67905 9.096878 -17.254227 65.643768 67906 9.095474 -17.281219 66.858856 67907 8.306984 -17.183151 66.710632 67908 19.831345 -16.228775 64.026413 67909 20.379280 -17.027740 64.588470 67910 22.262009 -16.931366 64.282562 67911 21.247482 -17.118744 64.354492 67912 25.149925 -16.038925 65.770782 67913 27.495346 -16.916290 64.392731 67914 35.433258 -14.961639 66.534653 67915 34.332771 -15.182678 65.630493 67916 9.053757 -17.094269 64.381149 67917 19.469666 -16.481277 65.284882 67918 28.578598 -17.342392 64.488007 67919 29.648933 -18.092041 64.412888 67920 35.456894 -18.959229 65.628082 67921 30.360733 -19.097656 64.347992 67922 30.449371 -18.215652 65.219757 67923 31.062057 -19.311890 65.263626 67924 30.933411 -20.025772 64.406586 67925 35.095718 -20.465485 65.401505 67926 34.423172 -21.032761 64.255081 67927 34.110657 -21.994949 64.297058 67928 40.607925 -21.454391 64.388229 67929 2.107262 -21.940094 63.771591 67930 3.145928 -22.604752 63.931366 67931 4.738419 -22.811447 64.198364 67932 4.301972 -22.237671 66.181793 67933 5.831879 -22.550400 66.295715 67934 31.813265 -22.051224 64.028961 67935 31.513588 -21.551575 64.253632 67936 33.270790 -22.849411 64.589035 67937 33.072800 -22.872391 65.038391 67938 33.447456 -22.558762 64.248154 67939 33.859123 -22.768616 65.051819 67940 39.436935 -20.792755 65.661087 67941 20.908936 -25.031754 65.020309 67942 21.124237 -24.484253 65.711044 67943 22.147675 -24.147095 63.900711 67944 39.769363 -23.930283 64.641785 67945 39.249710 -22.538132 65.863312 67946 24.939705 -25.864563 63.907227 67947 3.496399 -26.280716 63.138702 67948 7.227661 -25.605453 63.725159 67949 8.193222 -24.849991 64.048859 67950 21.160706 -25.422897 65.675659 67951 5.098152 -25.492447 65.437607 67952 4.381455 -25.976196 63.779968 67953 40.764969 -28.144119 64.057846 67954 1.958153 -26.615997 64.099701 67955 1.265572 -29.236893 63.014618 67956 1.487091 -27.191391 63.876648 67957 21.733170 -27.789795 64.046204 67958 27.558311 -27.234985 63.945312 67959 41.941208 -27.609024 63.841400 67960 21.901215 -29.980743 63.548309 67961 29.257828 -27.926315 64.038956 67962 28.058548 -27.459000 64.856476 67963 32.514313 -28.672150 63.203674 67964 1.180023 -27.959000 63.971924 67965 24.402466 -30.186249 63.141205 67966 27.188087 -29.819336 63.403717 67967 21.533112 -31.315414 63.291565 67968 21.746620 -30.842300 64.380386 67969 24.583504 -30.635284 63.730652 67970 25.063583 -30.577057 64.240570 67971 28.806404 -30.494843 64.759109 67972 1.178352 -31.867310 63.448349 67973 11.223747 -32.905792 62.770203 67974 11.398956 -32.305328 63.112610 67975 10.956665 -31.793213 63.944504 67976 15.441803 -31.812592 63.435669 67977 15.543144 -31.472473 66.177002 67978 16.862976 -31.951233 64.220413 67979 16.885185 -32.173080 63.011459 67980 38.424614 -30.944061 65.023407 67981 37.776398 -32.291718 64.819809 67982 42.801697 -30.537735 64.053101 67983 10.200912 -32.286163 63.926636 67984 10.440262 -31.785950 64.248230 67985 10.610641 -32.877609 63.055344 67986 18.395767 -32.365189 63.455048 67987 20.362152 -32.301346 63.368561 67988 21.107391 -31.951080 63.339386 67989 31.600405 -31.829117 63.609207 67990 32.769585 -32.387985 63.915314 67991 33.663994 -32.774979 65.068329 67992 32.967880 -32.078445 65.013123 67993 0.865578 -33.098450 66.124588 67994 1.209084 -34.532608 65.042191 67995 10.320465 -33.452759 63.079529 67996 10.023132 -33.010010 63.385468 67997 9.808327 -33.584885 63.494934 67998 11.109673 -33.540024 62.976471 67999 2.225678 -35.547348 63.267883 68000 2.024582 -37.045776 64.124390 68001 10.324493 -33.974442 63.467834 68002 11.203842 -34.217178 63.782333 68003 3.373474 -37.812347 62.881897 68004 18.963936 -35.267609 63.975006 68005 36.131645 -34.488785 64.671692 68006 18.501801 -34.892776 65.807129 68007 16.826309 -34.780228 65.164307 68008 40.699173 -33.644394 64.849747 68009 40.311234 -31.653046 65.260773 68010 2.861191 -37.473740 63.253815 68011 20.253685 -35.417343 65.362228 68012 21.955597 -36.204163 64.861038 68013 21.447433 -35.805542 65.965820 68014 22.928688 -36.641159 63.930573 68015 23.994293 -36.862976 64.188843 68016 3.556496 -38.731934 62.615295 68017 40.685196 -38.324326 63.306183 68018 40.207886 -38.953522 63.911758 68019 39.587906 -38.150635 65.491272 68020 17.611046 -39.657074 62.601257 68021 16.957932 -39.595047 63.265533 68022 3.181481 -39.880249 62.589127 68023 16.471458 -39.601517 64.444473 68024 18.085297 -39.798996 63.330200 68025 9.383759 -42.212631 63.821442 68026 9.633073 -42.082886 63.378769 68027 9.241394 -42.323395 62.815430 68028 9.144722 -42.310287 64.640625 68029 7.862671 -42.921112 64.132675 68030 8.717712 -42.367889 65.635040 68031 10.354492 -44.357666 63.342606 68032 16.227074 -40.294937 63.441345 68033 16.440712 -41.576187 62.671143 68034 20.602249 -41.457199 62.813583 68035 19.701424 -40.701965 63.612137 68036 37.277878 -41.901321 63.927444 68037 38.063812 -41.417206 64.252380 68038 39.533463 -39.593399 64.306396 68039 4.003166 -43.505234 62.377228 68040 31.678667 -44.002701 63.028931 68041 32.669754 -43.307907 62.785309 68042 33.729515 -43.181000 62.986908 68043 34.949890 -43.355545 63.828705 68044 35.410782 -43.447830 64.525085 68045 36.065918 -42.836609 64.475220 68046 3.166359 -43.208023 63.276062 68047 4.057030 -43.901688 63.720947 68048 5.346809 -43.904205 62.991943 68049 6.425110 -43.792755 63.759949 68050 29.634720 -44.576324 62.565491 68051 32.931358 -44.280975 63.866791 68052 33.926796 -44.036392 64.093063 68053 34.997711 -43.781830 64.824982 68054 15.584587 -41.447174 65.386505 68055 14.968971 -40.803558 66.714996 68056 15.169540 -40.423233 65.565475 68057 24.722885 -44.436661 62.705963 68058 25.952988 -44.836563 62.647186 68059 25.540695 -44.503845 63.594849 68060 26.747810 -45.177124 62.561981 68061 27.293381 -44.999130 64.020065 68062 18.238426 -44.958817 63.193588 68063 27.269516 -45.335602 62.647675 68064 28.800804 -45.086884 63.004395 68065 30.156662 -44.896088 64.054199 68066 4.729721 -47.637756 62.232834 68067 3.862381 -47.719284 62.048157 68068 6.121918 -47.601761 61.810638 68069 10.096283 -46.363312 62.335236 68070 18.586060 -46.110397 62.481308 68071 19.010376 -47.343979 62.794861 68072 4.036316 -48.000946 63.177826 68073 4.673981 -48.160065 64.579391 68074 5.979935 -48.372742 65.811981 68075 4.093529 -48.489761 65.660828 68076 7.683776 -47.928192 62.095474 68077 9.402542 -47.290131 62.771545 68078 8.453323 -48.045334 62.658386 68079 10.009201 -46.127945 63.195648 68080 22.359505 -50.744034 62.489578 68081 25.101257 -49.816132 63.628052 68082 27.409302 -49.835449 64.344925 68083 36.015511 -51.005066 63.610962 68084 38.483223 -52.231339 62.175873 68085 38.277527 -50.996368 62.635223 68086 19.556305 -50.131973 62.912354 68087 20.812668 -51.634964 62.908279 68088 20.306290 -51.334122 63.202545 68089 21.415695 -51.868713 63.606140 68090 20.831055 -51.892563 63.487686 68091 21.464554 -51.290726 62.658264 68092 6.730621 -53.146729 62.317505 68093 7.602615 -53.031799 62.252060 68094 36.988480 -53.383347 62.943146 68095 37.554916 -52.399490 63.015991 68096 15.395340 -54.307129 61.631210 68097 15.091766 -54.303818 61.705414 68098 15.271896 -54.143753 61.851929 68099 15.469299 -54.285904 61.955017 68100 38.085327 -51.825455 62.806091 68101 13.324600 -55.453186 61.842499 68102 13.892746 -55.037308 61.769135 68103 14.712517 -54.633804 61.805008 68104 5.800385 -57.175858 61.533691 68105 7.172989 -56.242065 62.480957 68106 6.826805 -56.483749 61.710480 68107 12.462204 -56.498596 61.962585 68108 5.220017 -58.314804 62.949097 68109 6.414414 -57.272781 62.723755 68110 33.697281 -57.417740 62.060699 68111 32.301331 -58.359436 61.949860 68112 34.792816 -56.619125 62.095123 68113 34.896179 -55.787582 63.073349 68114 18.031296 -57.794403 62.674957 68115 31.711435 -58.835510 61.778488 68116 30.996887 -59.080109 62.046478 68117 8.894547 -62.035034 62.067078 68118 9.194061 -61.089493 61.476181 68119 12.765427 -62.987610 61.154175 68120 18.589020 -58.977402 63.453888 68121 19.004395 -59.641113 64.495483 68122 19.245636 -60.504227 63.581467 68123 4.176247 -61.396301 61.386505 68124 13.524567 -61.671646 60.949738 68125 19.937195 -60.984055 62.611725 68126 22.344666 -61.966766 62.524750 68127 22.829071 -61.733002 61.753510 68128 27.690689 -61.040619 61.956329 68129 28.315994 -60.719345 61.376038 68130 4.565247 -62.511215 60.962158 68131 15.024902 -63.092850 60.799316 68132 23.630882 -62.062408 62.450653 68133 25.166351 -61.641281 62.867676 68134 26.336151 -61.562775 61.782928 68135 5.053536 -63.321350 61.058777 68136 5.540939 -63.794449 61.089050 68137 6.044273 -63.906738 61.217438 68138 6.553383 -63.813644 61.111115 68139 18.280502 -66.685364 61.139587 68140 19.625107 -66.661026 60.621033 68141 20.302673 -67.658432 60.719711 68142 8.297523 -68.606110 60.630066 68143 9.103668 -67.624390 60.804886 68144 19.098373 -67.921478 61.071716 68145 7.912155 -69.488266 60.329285 68146 17.918907 -69.051422 61.241272 68147 15.635620 -70.354126 60.621109 68148 16.145416 -69.378113 61.787735 68149 19.879211 -68.381226 60.855682 68150 9.760284 -70.426926 60.934265 68151 12.639130 -71.039169 60.664948 68152 8.242523 21.992126 66.633911 68153 7.767120 21.272415 66.719086 68154 8.534897 20.814133 66.949310 68155 9.795799 21.296188 66.589935 68156 9.568527 19.847809 66.870956 68157 7.729896 20.635147 66.899307 68158 7.787429 20.000336 67.124847 68159 8.566742 19.437012 67.340942 68160 9.298004 19.031311 67.358551 68161 9.073257 18.124191 67.606567 68162 9.951118 18.453064 66.936462 68163 10.367737 16.957703 67.289307 68164 4.136688 15.351562 66.991089 68165 9.287933 16.767822 68.213303 68166 11.262878 15.382187 67.175659 68167 3.957634 14.190414 67.359131 68168 4.982056 15.054276 68.057068 68169 11.193214 14.166626 68.066986 68170 2.902664 12.599533 65.634933 68171 3.277565 12.917984 66.635559 68172 12.828430 11.877060 66.742737 68173 12.083541 12.696045 67.772278 68174 2.887055 11.650345 65.715088 68175 13.185043 11.067719 66.403931 68176 12.971420 10.918396 66.796799 68177 21.679535 10.144043 66.744629 68178 22.461876 10.392380 66.658142 68179 22.651566 9.898743 67.034897 68180 20.220810 8.898636 67.763702 68181 3.863892 9.031555 67.090088 68182 4.670426 8.738937 67.953003 68183 17.357086 8.067413 66.351929 68184 24.348969 8.288269 67.060745 68185 25.253937 6.784912 66.750229 68186 3.557312 10.195343 67.674652 68187 4.047508 9.836487 68.232056 68188 5.573074 7.486008 67.608948 68189 6.426079 6.547333 66.319427 68190 6.096306 5.987961 67.188980 68191 11.310287 5.739014 66.496689 68192 11.732956 6.443771 67.261139 68193 15.710327 5.574493 66.567993 68194 10.794807 3.648239 66.162354 68195 24.950272 5.864716 67.763885 68196 26.561356 4.082260 66.737320 68197 4.415032 3.287781 66.170639 68198 4.723801 3.818329 67.104523 68199 5.790871 4.675522 66.916840 68200 3.774475 3.359985 68.374008 68201 3.563210 3.041138 67.045349 68202 16.318665 4.120728 66.503937 68203 16.202057 4.940735 67.145630 68204 18.503113 3.335518 67.696732 68205 19.232056 2.094528 66.712402 68206 27.196274 3.161987 66.363281 68207 2.742554 2.057983 66.977219 68208 2.967224 2.545944 67.996826 68209 2.520668 1.801010 67.823090 68210 11.134521 3.431595 67.133759 68211 12.591530 1.234940 66.268784 68212 12.768044 1.111877 67.169983 68213 27.993225 1.454788 66.511505 68214 13.486435 0.744385 66.275238 68215 28.893829 -0.415314 66.364288 68216 28.324661 0.005081 67.432251 68217 16.631393 -1.263275 67.421829 68218 16.090271 -0.363205 67.782318 68219 21.156937 -0.728455 67.101868 68220 20.497360 0.383255 67.016129 68221 29.282959 -1.746750 66.294067 68222 2.421417 0.574417 66.117462 68223 2.271340 0.764206 67.331223 68224 2.300804 -1.299911 66.954971 68225 15.266265 -0.171417 66.973724 68226 16.512680 -3.658752 66.223450 68227 16.768089 -2.451447 66.935181 68228 29.080048 -3.244247 66.413498 68229 29.136673 -3.586853 67.232483 68230 29.239418 -3.197647 67.203033 68231 3.074944 -2.831879 65.930634 68232 2.788414 -3.535965 67.447845 68233 2.374680 -4.320572 68.636887 68234 3.173485 -5.543869 67.528687 68235 29.175995 -2.399734 67.188263 68236 3.973999 -3.376724 65.259399 68237 16.151115 -4.733124 65.823242 68238 6.409355 -4.873886 65.386810 68239 6.434830 -5.940857 65.486969 68240 28.524956 -4.513641 65.967407 68241 16.404152 -5.689194 66.274582 68242 28.696594 -5.594299 67.158279 68243 30.345116 -6.963425 65.889069 68244 4.076927 -7.634933 65.937454 68245 5.041145 -6.984329 65.754852 68246 5.511711 -6.261520 66.004028 68247 16.747261 -5.827805 66.767868 68248 17.352737 -5.681427 67.567627 68249 22.752289 -7.513916 66.719742 68250 23.543320 -9.338593 66.591003 68251 23.752487 -8.407578 67.407272 68252 23.266891 -10.912491 65.109192 68253 24.073624 -11.134750 65.708740 68254 29.018425 -11.373795 65.870575 68255 29.476425 -10.583084 67.188889 68256 4.341736 -11.545441 65.446442 68257 19.391144 -10.453232 65.814316 68258 19.733078 -10.217163 66.688416 68259 34.023773 -12.273666 65.468842 68260 35.109032 -11.272614 65.600891 68261 35.080994 -12.024155 66.023453 68262 35.900703 -10.882416 65.466522 68263 35.996803 -11.599518 65.869659 68264 37.118286 -12.322830 65.868256 68265 5.184776 -12.017273 66.548431 68266 25.649506 -11.708939 66.336227 68267 27.742905 -11.773712 66.619324 68268 28.801453 -11.389374 66.780380 68269 33.669464 -13.852524 65.433594 68270 34.588814 -12.914902 66.027863 68271 38.108086 -12.612167 65.618591 68272 10.844696 -13.396271 65.530579 68273 9.921630 -12.867035 65.807312 68274 19.966827 -14.030151 66.328110 68275 19.282440 -15.540985 66.273041 68276 20.185867 -13.101120 65.804489 68277 38.736862 -13.811676 65.622559 68278 11.635895 -13.300705 66.259155 68279 10.158646 -16.768494 65.113907 68280 19.569092 -14.835358 67.257172 68281 38.924187 -15.171310 65.949081 68282 11.007598 -14.796463 69.017014 68283 10.919907 -15.550629 68.307571 68284 11.327103 -15.430893 67.568726 68285 28.041489 -16.481979 65.635681 68286 26.908852 -15.958557 66.053833 68287 26.014832 -15.871536 66.070206 68288 27.972610 -15.770523 67.242950 68289 34.806854 -13.999298 66.246216 68290 19.981911 -17.191605 65.581055 68291 21.186958 -17.194550 65.352417 68292 22.466248 -16.831635 65.574615 68293 23.240463 -16.484802 66.798874 68294 21.869347 -17.040558 66.616196 68295 29.596786 -17.189728 65.532410 68296 20.477982 -17.526932 66.762985 68297 20.616272 -18.041168 68.065613 68298 19.848312 -18.102539 67.598709 68299 30.699486 -17.636459 66.157471 68300 31.047775 -18.394821 65.840149 68301 31.202255 -18.145828 66.425171 68302 31.612398 -19.021347 66.455536 68303 31.124435 -17.772308 67.328674 68304 36.565666 -16.839630 66.400024 68305 40.157669 -17.952652 65.142639 68306 31.758287 -20.716553 65.559265 68307 34.706863 -21.578415 65.011826 68308 2.468399 -21.869049 65.147614 68309 32.014191 -21.956772 64.911072 68310 7.146225 -23.223816 64.785873 68311 7.532471 -24.061646 65.809280 68312 8.009438 -24.125763 64.895096 68313 32.601303 -22.555466 65.283051 68314 32.606880 -22.174332 66.349060 68315 34.528786 -22.308243 65.219543 68316 38.558975 -18.441437 66.078583 68317 8.422867 -24.153015 64.371017 68318 21.316177 -24.584335 66.590424 68319 33.462219 -22.873062 65.970215 68320 34.468727 -22.642624 65.940491 68321 39.308075 -23.902649 65.777664 68322 23.581024 -24.393234 65.225006 68323 22.531212 -23.999222 65.054596 68324 39.221581 -25.028412 65.277206 68325 3.183609 -25.874847 64.912292 68326 1.300095 -26.946274 65.062210 68327 6.373558 -25.577347 64.636871 68328 7.343231 -24.952698 65.167969 68329 21.666306 -26.558105 65.634827 68330 38.879219 -25.796692 65.047104 68331 21.727402 -27.168335 64.881393 68332 25.423187 -26.045380 64.814423 68333 26.739250 -26.696625 65.294357 68334 38.190620 -26.563141 64.833969 68335 28.162674 -27.334167 66.112183 68336 0.790527 -28.116150 64.973022 68337 0.903389 -27.445084 66.046051 68338 0.852402 -28.770920 64.112442 68339 28.966003 -27.861404 65.108810 68340 30.982323 -28.415421 63.877441 68341 34.161102 -28.687622 65.863861 68342 35.022545 -28.142654 66.713257 68343 37.238693 -27.473343 65.147537 68344 41.915359 -28.776291 64.479095 68345 40.819855 -28.878723 64.875153 68346 0.724533 -29.487701 64.658356 68347 22.140678 -28.881882 64.229248 68348 27.291046 -30.199860 64.462128 68349 25.485619 -30.207855 64.209747 68350 30.590729 -28.275208 65.385040 68351 29.249298 -27.823364 66.391495 68352 30.000641 -27.817917 67.243591 68353 42.187332 -29.559631 64.628143 68354 22.214035 -29.681046 64.650635 68355 25.871964 -30.711441 64.976044 68356 30.083405 -30.836212 64.921753 68357 41.521851 -29.595078 64.899841 68358 0.766396 -30.778488 64.558899 68359 22.006371 -30.403961 65.460281 68360 20.934875 -31.533676 65.170654 68361 24.720810 -31.462723 64.368393 68362 31.272530 -31.284805 64.662476 68363 30.823532 -30.891296 65.694351 68364 0.799591 -31.712448 64.907440 68365 1.214058 -32.719208 64.014404 68366 9.582497 -33.090118 63.947388 68367 19.643730 -32.095627 64.427811 68368 19.513626 -32.428802 63.597656 68369 17.888794 -31.891296 65.188629 68370 19.374710 -31.718979 66.245605 68371 21.002762 -31.780701 64.043091 68372 24.584961 -32.430435 64.636047 68373 32.277817 -31.799805 64.540741 68374 36.905655 -33.739685 64.556763 68375 38.279953 -31.695404 65.371597 68376 9.435989 -33.619598 63.856110 68377 24.682449 -33.318207 64.588089 68378 35.167496 -34.296890 64.742172 68379 34.351410 -33.638184 64.738678 68380 9.424194 -34.157074 64.173523 68381 9.182930 -33.531784 64.298721 68382 10.297287 -34.566391 64.385056 68383 11.185905 -34.697586 64.809753 68384 9.377945 -35.081635 65.048569 68385 37.504883 -33.463837 65.649689 68386 1.465034 -35.533401 64.631317 68387 15.259918 -34.616623 65.079605 68388 24.776833 -34.378922 63.988312 68389 25.031113 -35.328018 64.191086 68390 34.814560 -33.830093 65.524933 68391 20.662659 -35.795197 64.100861 68392 2.724281 -38.729630 63.585266 68393 1.723457 -38.471634 64.671356 68394 1.807930 -39.911682 64.974884 68395 2.367859 -41.494568 64.245270 68396 2.700592 -40.485489 63.569794 68397 16.146927 -41.619110 63.997253 68398 15.488906 -39.756027 65.270172 68399 15.705048 -40.460999 64.677734 68400 20.411377 -41.212448 64.604492 68401 18.167953 -39.831253 64.973160 68402 9.951035 -42.606918 64.491608 68403 10.049797 -42.835510 63.483826 68404 20.616959 -41.345306 63.687668 68405 38.472031 -41.013168 64.311646 68406 38.906624 -40.515778 64.165100 68407 2.702881 -41.331802 63.467178 68408 21.138100 -41.768478 63.603607 68409 21.946663 -42.279526 64.102020 68410 23.049866 -42.534698 65.447968 68411 23.325348 -43.379761 63.693680 68412 24.478172 -43.958633 63.704681 68413 10.211082 -45.303955 63.306885 68414 10.106124 -45.383896 63.963821 68415 18.587273 -45.340393 66.216385 68416 19.651733 -46.187729 66.741745 68417 18.534103 -45.770706 67.156403 68418 25.373253 -43.940445 64.771881 68419 8.523376 -47.922974 63.830505 68420 18.838959 -45.552704 63.894119 68421 19.380783 -46.417038 63.809906 68422 29.344070 -45.043472 67.495178 68423 28.992325 -44.998062 68.113403 68424 29.876617 -44.992035 68.230545 68425 28.610405 -44.943665 66.185028 68426 27.265480 -44.713257 65.715851 68427 32.007751 -44.892593 64.611221 68428 32.821243 -44.905106 64.835541 68429 6.804398 -48.047333 62.935226 68430 5.624275 -48.009613 63.552856 68431 7.695480 -48.213272 63.075958 68432 19.674850 -47.971237 63.821259 68433 2.245339 -49.202560 63.865997 68434 19.736961 -47.043961 64.186340 68435 2.110886 -49.647598 62.844482 68436 2.010407 -50.286362 63.181061 68437 24.203659 -49.859985 62.621353 68438 32.993439 -50.381866 63.415771 68439 34.836182 -50.621857 63.884003 68440 33.968979 -50.911179 64.220795 68441 38.292282 -50.085190 62.404861 68442 19.899216 -49.125046 64.084930 68443 20.178810 -50.571869 63.992020 68444 22.938324 -50.707352 63.370331 68445 23.763000 -50.310532 63.620682 68446 37.402283 -51.544083 63.120667 68447 2.236443 -51.360641 62.791046 68448 2.037079 -51.179474 63.849457 68449 2.381607 -52.249374 63.581696 68450 19.897583 -50.778809 63.018555 68451 20.727753 -51.578888 64.074677 68452 2.706925 -52.799438 63.023392 68453 2.494614 -52.148758 62.785797 68454 5.925293 -54.279480 63.124725 68455 8.093758 -53.259995 62.020645 68456 7.608078 -53.574722 62.527191 68457 36.498077 -52.483643 63.660706 68458 3.463280 -53.208923 62.656464 68459 6.944603 -53.917587 62.932892 68460 15.168655 -54.284851 62.023651 68461 35.849937 -54.576431 63.173126 68462 13.836418 -55.398193 62.446884 68463 14.532410 -54.976257 62.607834 68464 15.381371 -54.579819 62.453278 68465 26.603821 -55.140289 63.202911 68466 27.116867 -54.696152 63.364746 68467 27.237335 -55.022217 63.140961 68468 26.438202 -54.669693 63.861481 68469 27.670853 -54.764999 63.422714 68470 13.247871 -56.187485 62.439178 68471 27.382263 -55.597534 63.234482 68472 26.123726 -55.890289 63.060059 68473 26.643143 -56.481430 63.021729 68474 36.017883 -53.533264 63.692017 68475 4.580353 -58.729828 61.650024 68476 7.506340 -54.658508 62.621155 68477 7.457131 -55.530609 62.473175 68478 11.909424 -57.308655 61.988266 68479 12.631653 -57.140320 62.579941 68480 14.454300 -56.030090 63.474304 68481 16.479294 -54.899414 63.025330 68482 17.185791 -55.291656 63.280273 68483 25.915855 -56.571793 62.992126 68484 25.502151 -56.188385 63.274887 68485 25.539719 -56.806717 63.349503 68486 27.737885 -56.715561 63.379700 68487 33.947548 -55.809113 63.721649 68488 33.926025 -56.769150 62.994049 68489 6.824043 -56.670609 63.178741 68490 12.287750 -58.417068 63.096710 68491 26.416855 -57.286499 63.326736 68492 25.361572 -57.344315 64.044189 68493 26.019920 -58.419861 64.050339 68494 18.308823 -58.916580 62.487762 68495 31.160690 -58.444229 62.985489 68496 32.619240 -57.604919 63.070526 68497 4.127327 -60.021683 61.636597 68498 29.683258 -59.125320 62.768341 68499 9.967102 -61.007156 62.686768 68500 26.655762 -61.201263 62.709045 68501 29.961876 -57.953781 63.603485 68502 31.312263 -57.705658 63.621613 68503 20.398613 -61.488342 63.664581 68504 27.380325 -60.292389 62.892914 68505 28.538040 -60.155090 62.217957 68506 4.541840 -62.622940 62.012451 68507 13.867157 -62.756439 61.395218 68508 21.105881 -61.531616 62.519577 68509 27.980896 -58.451904 63.332489 68510 7.877563 -63.152390 61.986816 68511 13.631744 -64.042831 62.066193 68512 13.430206 -63.552475 61.806992 68513 14.221001 -63.660706 61.733429 68514 5.451828 -63.704590 61.711426 68515 6.628014 -63.783066 61.842667 68516 5.573761 -63.470673 62.941315 68517 10.019128 -67.436035 61.614456 68518 15.536827 -66.553467 62.311646 68519 9.328232 -68.850510 61.341309 68520 16.913101 -67.357239 62.014236 68521 17.957672 -67.877075 61.575439 68522 16.317612 -68.309250 62.353302 68523 17.130226 -68.458038 61.919754 68524 14.546967 -68.954819 62.483856 68525 10.960602 -70.356857 61.590744 68526 10.120864 -69.541000 61.758789 68527 12.225662 -70.422592 61.660217 68528 15.480949 -68.365417 62.638580 68529 8.305092 17.552490 68.117035 68530 7.367798 17.388977 68.224548 68531 10.171120 15.465256 68.293823 68532 4.343071 13.896301 68.026917 68533 4.815453 13.288162 68.857635 68534 4.007141 11.341980 68.465469 68535 3.844933 12.821960 67.798462 68536 3.293823 11.290421 67.099518 68537 12.520737 10.445053 67.551010 68538 11.703018 11.608246 68.747269 68539 11.934265 10.265533 69.081055 68540 12.262657 8.770874 68.662872 68541 12.085526 9.173325 69.461151 68542 11.420808 9.697205 70.112061 68543 21.804337 9.677765 67.260651 68544 17.774246 7.970673 67.139252 68545 18.867111 8.300552 67.600708 68546 21.395386 9.268875 67.621887 68547 23.024323 7.938950 68.223679 68548 22.585510 7.033417 68.907166 68549 21.652878 7.714798 68.812149 68550 22.694786 9.089752 67.512955 68551 12.270813 8.154175 67.501099 68552 21.512100 8.559052 68.208252 68553 6.177322 6.851471 66.895782 68554 11.516876 5.536972 68.235107 68555 11.215904 4.905640 67.343246 68556 16.385544 6.072327 67.420166 68557 25.762405 4.495697 67.664200 68558 24.458015 4.700035 68.777893 68559 23.659225 6.199142 68.732727 68560 17.040619 4.158859 67.284409 68561 16.797661 4.745522 67.774506 68562 16.552979 5.313179 67.894836 68563 26.732834 3.066246 67.396942 68564 27.801056 -0.347748 68.305511 68565 26.943077 0.220413 68.696411 68566 27.032471 1.424866 68.035492 68567 12.265678 1.632660 67.947174 68568 19.723938 2.054825 67.834473 68569 20.027390 1.383102 67.306946 68570 16.823051 -0.853882 68.735016 68571 14.126884 0.546616 67.230026 68572 13.160622 1.222794 68.283691 68573 28.651611 -1.482422 67.843628 68574 28.943924 -1.239029 67.105103 68575 2.430344 -0.029556 68.259430 68576 2.431275 -1.586304 68.546402 68577 16.978142 -3.606873 67.339264 68578 4.026070 -5.707291 66.955399 68579 4.001419 -5.089981 66.824295 68580 16.696289 -4.768509 66.879578 68581 28.846519 -4.264221 67.426453 68582 2.363579 -5.415512 69.104553 68583 4.426666 -5.710587 66.766312 68584 28.667953 -6.170349 66.418427 68585 28.465271 -6.616898 68.782196 68586 28.435287 -5.116928 68.619476 68587 4.332672 -6.347275 66.598221 68588 30.506760 -7.541519 66.745392 68589 30.588448 -8.483383 67.258301 68590 3.101181 -7.931915 67.165436 68591 3.546906 -8.682831 65.860168 68592 29.648552 -8.049744 68.052261 68593 3.283760 -9.557037 66.440430 68594 2.784042 -8.833542 68.322144 68595 23.360382 -6.693253 67.765747 68596 30.815048 -9.307785 66.646927 68597 30.389168 -9.944702 66.919128 68598 3.795876 -10.852249 66.171753 68599 24.589836 -10.621613 66.775238 68600 5.523987 -12.114288 67.727936 68601 5.752091 -12.361084 67.234894 68602 10.637222 -11.986099 66.686157 68603 9.027725 -12.133316 66.984375 68604 11.644524 -12.281586 66.602295 68605 11.446289 -11.387054 67.098007 68606 20.552109 -12.577225 66.727203 68607 25.439178 -10.878021 67.439774 68608 26.712463 -12.190414 66.010773 68609 28.308334 -11.257050 67.346100 68610 35.796997 -13.073654 66.323639 68611 10.947510 -12.714600 66.080765 68612 12.470596 -12.694412 67.376022 68613 24.494324 -9.754868 67.476685 68614 26.726242 -11.865524 66.747040 68615 37.796082 -13.129684 65.940308 68616 37.178589 -13.826782 66.280624 68617 11.887421 -14.198730 67.399155 68618 11.174210 -15.713898 66.175171 68619 35.472717 -14.055511 66.631012 68620 36.110931 -14.209702 66.657990 68621 37.978409 -14.870544 66.259979 68622 24.342545 -16.048828 66.371826 68623 24.208328 -15.930115 67.189453 68624 25.358711 -15.637970 67.192383 68625 26.600006 -15.603928 67.001373 68626 28.687302 -16.135056 66.590454 68627 29.256912 -16.519958 66.305084 68628 29.628311 -16.305618 68.370850 68629 29.515640 -16.392303 67.113358 68630 35.927582 -15.821609 66.532013 68631 36.774681 -15.232010 66.610565 68632 10.034134 -16.904968 66.250885 68633 10.638344 -16.347641 67.098663 68634 22.043625 -17.184708 68.376373 68635 30.147812 -16.967117 66.507996 68636 35.984413 -20.820221 66.759537 68637 35.442841 -22.086624 66.631317 68638 38.339745 -16.293930 66.242828 68639 2.140968 -17.273331 66.108521 68640 2.584549 -16.745056 67.054657 68641 1.706947 -17.622223 66.834259 68642 9.791992 -16.921616 67.154083 68643 19.272919 -16.872818 66.519180 68644 19.369141 -17.656845 67.174652 68645 31.939035 -18.905457 67.410767 68646 32.207787 -19.876282 67.777191 68647 1.529060 -19.173981 67.303970 68648 1.609429 -18.073059 66.331360 68649 32.026695 -18.859741 68.282196 68650 37.322441 -20.156097 67.256210 68651 36.756248 -20.596161 67.190674 68652 36.521935 -19.668289 66.640411 68653 34.918213 -21.848618 65.665833 68654 37.776672 -22.174820 67.096191 68655 37.925079 -20.963974 67.002655 68656 2.334023 -21.356705 66.458023 68657 3.220932 -21.927185 66.165848 68658 3.562004 -22.374023 65.173279 68659 7.058197 -23.229858 66.442169 68660 21.706009 -23.976486 66.182343 68661 25.000534 -25.143494 66.048004 68662 20.808517 -25.088364 64.478424 68663 38.615273 -24.726379 66.439575 68664 1.964890 -26.131943 65.643127 68665 2.497856 -25.479874 67.435089 68666 7.207733 -24.650970 66.134979 68667 38.568512 -25.803314 65.786621 68668 21.635208 -25.591782 66.768265 68669 22.228729 -26.790222 66.684784 68670 37.743240 -26.781616 65.938263 68671 22.314354 -28.333023 65.686844 68672 36.958038 -27.535828 65.838104 68673 36.433258 -27.045242 66.996933 68674 37.796219 -25.795929 66.848633 68675 0.612297 -28.471390 66.059692 68676 22.846794 -27.581192 67.682587 68677 31.471054 -28.110718 67.237854 68678 32.422676 -28.656860 66.102295 68679 33.477898 -28.679626 66.611618 68680 39.273659 -30.365158 65.362289 68681 27.480064 -30.566330 65.965393 68682 31.339088 -31.018799 66.570740 68683 30.415955 -30.642639 66.588837 68684 29.364151 -30.508423 66.134521 68685 29.684677 -30.593170 67.192062 68686 29.043373 -30.536758 67.240173 68687 38.984360 -31.266266 65.553101 68688 39.980637 -30.660538 65.476974 68689 9.649002 -32.064667 66.406799 68690 9.206680 -32.837326 65.089081 68691 16.737534 -30.916077 68.784821 68692 17.852844 -31.034790 68.479721 68693 17.649002 -31.394058 66.978119 68694 21.230438 -31.253860 66.452545 68695 25.083748 -32.218246 65.354431 68696 32.140961 -31.457779 65.615860 68697 32.223557 -31.574432 66.677597 68698 0.870293 -33.677521 69.355362 68699 0.947609 -34.601334 69.643463 68700 0.897629 -35.102814 67.325684 68701 0.553146 -29.986389 67.592194 68702 34.255814 -33.498718 66.164276 68703 33.679398 -32.878571 66.249481 68704 8.759445 -33.911560 64.876709 68705 8.357948 -33.704056 65.748444 68706 8.451706 -35.403397 65.546860 68707 8.743896 -34.679077 64.898590 68708 12.227066 -34.409729 64.626389 68709 14.560905 -34.415726 65.697311 68710 14.392562 -34.264847 67.010681 68711 13.105508 -34.489182 66.005447 68712 35.224319 -34.166336 65.638000 68713 36.691483 -34.167206 65.335693 68714 39.341026 -34.384079 66.005508 68715 1.073814 -36.657242 66.539307 68716 1.137268 -37.961807 65.980042 68717 8.207458 -34.611938 65.522415 68718 15.799850 -34.298706 66.859344 68719 20.647125 -35.399292 66.306610 68720 19.467270 -34.911438 66.925812 68721 25.047668 -34.620331 65.032516 68722 25.120972 -36.257553 65.129105 68723 35.783157 -34.406372 65.475708 68724 36.303482 -34.439133 65.436615 68725 23.574631 -36.965698 64.997543 68726 24.420532 -36.959656 64.716797 68727 30.949524 -39.722137 65.968414 68728 30.621338 -38.571716 65.729706 68729 31.854670 -38.752396 66.098145 68730 30.787476 -37.947433 65.566208 68731 30.512161 -38.009964 65.531738 68732 24.479599 -37.173904 65.335587 68733 30.203796 -37.428726 66.072174 68734 30.416931 -36.593414 65.921600 68735 30.880325 -37.214630 65.762680 68736 2.629158 -42.996170 65.222824 68737 38.119904 -41.140274 65.055191 68738 38.748886 -40.166901 65.389160 68739 38.717484 -39.257492 66.023743 68740 38.339264 -38.276123 66.838837 68741 37.684601 -41.631210 64.902313 68742 7.868621 -42.981003 65.975143 68743 10.314011 -44.001785 64.436249 68744 21.163528 -41.574921 65.627106 68745 19.589905 -40.526566 66.271133 68746 36.949982 -42.016541 65.231628 68747 38.531464 -40.721375 64.988190 68748 2.785797 -43.115356 64.051971 68749 3.235230 -43.582214 64.240295 68750 6.285004 -43.995163 65.297058 68751 7.268295 -43.464478 65.602936 68752 5.701676 -44.261978 64.213379 68753 4.901665 -44.323700 64.171265 68754 10.305298 -43.203766 65.312408 68755 10.374901 -44.224197 65.274445 68756 10.335403 -44.163162 66.049652 68757 10.164856 -42.877686 66.253845 68758 24.434868 -43.120392 65.528229 68759 24.173172 -43.422455 64.638138 68760 34.442245 -44.087051 64.750214 68761 9.893753 -45.635910 65.346481 68762 17.656097 -44.404144 65.084045 68763 19.534103 -46.213257 65.103058 68764 33.517021 -44.530167 65.296356 68765 9.577591 -46.718918 64.021149 68766 31.435562 -44.720078 66.944214 68767 32.445526 -45.075912 66.419128 68768 32.610817 -45.027802 65.746857 68769 19.730438 -46.504959 64.389709 68770 3.602921 -48.237595 64.485077 68771 7.082855 -48.258560 64.056885 68772 8.081985 -48.049484 65.460739 68773 9.068832 -47.203003 64.923355 68774 26.516953 -49.961517 65.832397 68775 25.413055 -49.981644 65.296188 68776 28.908264 -49.935303 64.077728 68777 30.055038 -51.294739 64.973282 68778 28.989883 -50.577484 64.919983 68779 22.230743 -51.323395 63.656052 68780 21.717880 -51.690338 64.775848 68781 30.889908 -50.932816 64.544662 68782 32.880417 -51.700500 64.708664 68783 35.360573 -52.034164 64.397919 68784 34.887245 -51.219971 64.349396 68785 20.842575 -51.067169 65.051666 68786 4.169129 -54.638931 63.675171 68787 21.122513 -51.964340 63.987000 68788 23.064056 -50.985214 64.673019 68789 6.634483 -55.683716 63.402847 68790 6.792854 -54.516296 63.193939 68791 28.310028 -54.188339 63.879333 68792 29.103546 -53.526611 64.521317 68793 29.079788 -54.529724 63.921341 68794 28.096420 -53.671722 64.492798 68795 28.799507 -55.589783 63.694427 68796 28.287750 -54.907654 63.571381 68797 33.858139 -54.797882 64.294067 68798 34.922089 -53.919098 64.224274 68799 34.731361 -54.967590 63.757233 68800 35.535362 -52.963806 64.276047 68801 15.364381 -55.035187 63.365982 68802 15.350815 -55.420135 63.927063 68803 16.082840 -55.239975 64.063080 68804 16.985794 -55.342194 63.992325 68805 25.621796 -55.446060 63.769714 68806 26.434937 -54.242340 65.009476 68807 27.365875 -54.240143 64.081146 68808 6.602921 -56.634766 63.528778 68809 15.572739 -55.913315 64.477829 68810 25.151520 -56.408859 63.951233 68811 24.997986 -55.673737 64.804443 68812 29.308685 -56.784088 63.833664 68813 30.698723 -54.933914 64.328552 68814 14.138565 -57.462250 64.036041 68815 14.873131 -56.980270 64.558197 68816 33.123306 -56.613892 63.733688 68817 6.514069 -57.093750 63.351913 68818 6.120529 -57.479202 63.408478 68819 14.331192 -57.851120 64.515259 68820 18.448723 -57.403000 64.185364 68821 18.817009 -58.561020 64.601562 68822 32.057556 -56.719345 63.923370 68823 30.700256 -56.954727 63.982025 68824 32.753029 -56.453445 64.053101 68825 5.832687 -57.832397 63.262482 68826 13.373970 -57.396606 63.378586 68827 4.209175 -60.542587 63.039886 68828 4.015114 -61.319229 64.739838 68829 4.484818 -62.569641 63.925598 68830 11.313309 -60.837631 64.046051 68831 11.152054 -59.752243 62.910645 68832 26.537689 -59.689148 63.677490 68833 4.459229 -62.423508 62.977203 68834 9.509277 -62.510468 64.657104 68835 10.571335 -61.990143 65.995117 68836 11.008728 -61.692245 64.920593 68837 25.191338 -59.633118 64.884033 68838 26.642929 -60.535446 63.300156 68839 9.503372 -61.984192 63.286804 68840 25.936020 -60.649628 63.773499 68841 8.570221 -62.866577 63.155685 68842 22.888229 -62.409805 63.315338 68843 23.543137 -62.419601 63.506622 68844 24.114380 -62.175552 63.337051 68845 25.055435 -60.935745 64.346909 68846 7.314804 -63.561844 62.824219 68847 21.982674 -62.076248 63.926117 68848 7.256989 -63.414612 64.199310 68849 5.831764 -63.190292 65.226181 68850 6.895081 -62.925888 65.596146 68851 13.751556 -66.113846 62.517609 68852 10.609360 -67.786942 62.275208 68853 12.602921 -67.456680 62.834686 68854 13.767403 -67.583344 62.878250 68855 14.745575 -67.404083 62.794174 68856 15.761360 -67.590973 62.628601 68857 9.958427 -68.081833 61.922882 68858 11.500656 -68.005173 62.690979 68859 11.846771 -67.176163 62.780365 68860 10.156929 -68.646866 62.091034 68861 10.720825 -68.481491 62.500458 68862 11.059959 -68.769272 62.642944 68863 10.729340 -69.251709 62.268555 68864 11.522980 -69.384537 62.420654 68865 12.504700 -69.139709 62.500305 68866 13.412567 -68.772537 62.650513 68867 6.753609 16.679321 68.500824 68868 7.477432 16.829651 68.712845 68869 7.469879 16.261017 68.944641 68870 8.234024 16.604706 68.655594 68871 6.583603 15.293930 68.977600 68872 5.665756 14.314392 69.029053 68873 9.115219 15.814346 68.717636 68874 8.183594 15.274933 69.167389 68875 9.306831 14.847870 69.058090 68876 10.064880 13.820160 69.139954 68877 11.811119 6.912201 68.867615 68878 17.922424 6.947617 68.243866 68879 19.974731 7.585693 68.756973 68880 24.211281 7.096512 67.930817 68881 5.741928 6.803772 68.279602 68882 5.516884 7.494431 68.664551 68883 5.300949 6.891083 69.541351 68884 11.942757 8.257690 69.598022 68885 17.127670 5.750931 68.409271 68886 23.431091 7.104309 68.492813 68887 5.573959 5.938156 68.489639 68888 11.513176 6.084915 70.162415 68889 11.475494 7.365814 70.482193 68890 5.048721 4.683563 68.174820 68891 11.420570 4.985291 69.267151 68892 16.969635 5.066055 68.272110 68893 11.298645 4.013885 68.271667 68894 11.329147 4.815292 68.302826 68895 17.440979 4.430908 68.141968 68896 17.448952 5.083450 68.613190 68897 3.769348 2.888916 69.497421 68898 3.285339 2.278152 68.967529 68899 11.784973 2.643494 68.309326 68900 25.567154 3.080223 68.588226 68901 11.579887 3.596619 69.159363 68902 24.503830 2.419846 69.325363 68903 24.472244 3.508263 69.139206 68904 15.176437 0.339828 67.987747 68905 16.460815 -0.191345 68.982666 68906 15.774940 0.349548 69.035400 68907 19.936630 2.431824 68.470703 68908 20.646088 1.334229 68.214569 68909 17.129257 -1.750671 68.180023 68910 22.297745 -0.233917 68.684387 68911 22.168068 -1.473969 67.929962 68912 21.421623 -0.031433 68.054901 68913 27.265709 -1.371704 68.923645 68914 26.217705 -0.328812 69.086731 68915 17.448219 -2.763168 68.358643 68916 22.542183 -4.822952 67.587982 68917 2.453407 -2.932037 69.209152 68918 17.297638 -4.431839 67.942291 68919 17.389793 -3.625229 68.090393 68920 27.774666 -3.164932 69.018158 68921 27.006958 -2.411667 69.284607 68922 28.839081 -3.097427 67.900482 68923 28.158478 -1.854355 68.474152 68924 28.510521 -4.105118 68.558105 68925 3.422150 -6.832123 67.059143 68926 2.741928 -6.715744 68.166534 68927 18.862106 -6.712128 68.532135 68928 20.264938 -7.485275 69.532181 68929 19.881302 -6.006470 69.937363 68930 23.847488 -3.508392 68.830231 68931 25.023392 -3.623306 69.378098 68932 24.864594 -4.868042 69.356567 68933 3.380463 -10.284134 68.498901 68934 3.603401 -10.533707 67.286499 68935 24.779892 -8.520630 68.323578 68936 18.993561 -8.299210 67.423843 68937 19.759178 -9.505280 67.501602 68938 30.172379 -9.317841 67.562744 68939 12.233566 -11.543137 67.205505 68940 11.765533 -10.784195 67.493271 68941 12.602936 -10.761963 67.766205 68942 4.437828 -11.381882 67.982727 68943 10.602577 -10.649582 68.107910 68944 11.872116 -10.231613 67.953537 68945 12.847626 -11.659515 67.677948 68946 20.243408 -10.495285 67.350006 68947 20.677719 -11.372528 67.499191 68948 25.191757 -10.057114 67.996155 68949 4.334053 -10.898087 69.114456 68950 21.036278 -12.265778 67.686127 68951 26.846405 -11.236008 67.526947 68952 6.852478 -12.284698 67.442139 68953 9.640869 -9.910202 70.023148 68954 8.266740 -11.356735 68.708862 68955 20.604759 -13.546875 67.389542 68956 20.982269 -12.884338 67.535004 68957 20.106194 -14.241562 67.269592 68958 20.179276 -14.204544 67.986496 68959 21.044159 -12.879761 68.472122 68960 5.888855 -16.395615 66.700943 68961 18.969223 -15.902023 67.381805 68962 24.100624 -15.922073 68.119095 68963 25.431900 -15.288971 68.447464 68964 30.148743 -16.561356 69.536407 68965 28.950714 -15.623138 69.523895 68966 1.692871 -17.626801 67.702515 68967 2.506821 -16.684677 68.136002 68968 7.369461 -16.793762 66.785767 68969 6.740578 -16.608902 67.972565 68970 18.343880 -17.764664 68.386856 68971 18.548271 -17.023605 67.962799 68972 19.002182 -18.011093 67.981201 68973 37.857880 -19.333847 66.488464 68974 37.874695 -20.050522 66.892883 68975 36.595695 -18.384369 66.283234 68976 1.784378 -20.790955 65.622253 68977 32.464531 -21.324585 67.800339 68978 37.757309 -20.255615 67.267578 68979 1.748154 -20.368683 66.509552 68980 3.469528 -21.593384 67.444275 68981 4.925751 -22.024750 67.398529 68982 33.060837 -22.825455 68.288651 68983 32.285767 -21.983841 69.615234 68984 34.399284 -23.079971 66.901123 68985 33.515244 -23.020889 67.089005 68986 7.152023 -24.034744 66.751770 68987 22.937057 -23.749466 66.753815 68988 35.347153 -23.483749 67.635345 68989 24.666786 -23.580261 67.622284 68990 24.256691 -22.794647 68.592377 68991 25.396469 -22.870361 68.727600 68992 38.084961 -23.374664 67.019714 68993 1.667961 -25.864410 67.910980 68994 1.298698 -26.311584 68.203827 68995 1.353195 -26.555069 66.964859 68996 4.164566 -25.136734 66.981262 68997 6.441773 -24.853180 66.384399 68998 21.450638 -24.773712 67.226746 68999 37.299164 -24.577774 67.712372 69000 22.314621 -25.877258 67.857239 69001 0.736053 -27.958237 67.111115 69002 0.920921 -27.335785 68.121368 69003 23.427658 -26.161835 69.312119 69004 22.667831 -24.920044 68.879425 69005 28.910400 -27.344711 67.408981 69006 26.903564 -26.096924 66.991379 69007 29.148788 -27.904449 65.695969 69008 30.511131 -27.489487 68.455109 69009 32.716049 -28.441330 67.077789 69010 34.204987 -28.566162 66.669800 69011 26.086525 -31.425430 66.437439 69012 25.807556 -32.171097 67.287781 69013 25.377365 -32.450500 66.411636 69014 28.334282 -30.602554 67.073242 69015 31.552856 -31.511917 67.452728 69016 9.471984 -31.993393 67.291840 69017 22.309731 -30.091034 66.582520 69018 38.731003 -33.434921 65.959213 69019 38.744400 -32.438065 65.543579 69020 8.612335 -32.856293 66.752045 69021 20.304848 -31.525787 67.195282 69022 33.050461 -32.275955 66.232925 69023 25.119324 -33.432358 65.838257 69024 35.028297 -34.067062 66.368713 69025 36.574959 -34.297211 66.181244 69026 38.006439 -34.203033 66.479752 69027 7.971176 -33.523529 68.120468 69028 7.831336 -34.351868 66.700455 69029 11.773895 -34.802139 65.621063 69030 25.552002 -34.778152 66.272247 69031 25.586861 -33.224487 67.036255 69032 25.924591 -34.317566 67.302612 69033 35.620544 -34.245178 66.171280 69034 10.494217 -35.178619 65.613678 69035 11.657089 -35.040115 66.632721 69036 11.131507 -35.412155 67.730377 69037 12.962799 -34.520325 67.786774 69038 31.416687 -36.482590 66.177887 69039 31.785479 -35.253647 66.952255 69040 32.842575 -36.927170 66.969269 69041 7.817703 -35.318344 66.166840 69042 7.958251 -36.186478 66.476074 69043 9.197250 -35.837585 65.959259 69044 8.860664 -36.541367 66.768860 69045 22.890564 -36.591415 66.256973 69046 26.188095 -35.450180 67.172943 69047 26.333549 -36.274445 67.169952 69048 25.833649 -36.402802 66.558380 69049 30.696365 -36.091095 66.084808 69050 30.232109 -36.174896 66.559509 69051 30.828163 -36.510117 65.863007 69052 30.875961 -35.457352 66.619934 69053 25.031639 -37.276703 66.340485 69054 33.564682 -38.934601 67.012756 69055 24.074112 -37.254288 65.918091 69056 30.078140 -38.444595 66.529327 69057 1.227814 -38.853149 65.509857 69058 0.990608 -39.233719 66.895096 69059 15.994522 -39.139328 65.933044 69060 30.311111 -39.504105 67.335205 69061 30.266907 -38.516220 67.622635 69062 30.328049 -39.326172 66.247864 69063 32.291519 -40.704773 66.562439 69064 33.363861 -40.129868 66.854431 69065 33.517929 -41.456085 66.970795 69066 38.667587 -36.646103 66.669098 69067 15.125473 -39.779282 65.948761 69068 31.597275 -40.050476 66.060120 69069 31.260574 -40.542313 66.345322 69070 1.847694 -41.482086 65.373825 69071 1.273949 -40.864182 66.487579 69072 15.540817 -42.439056 66.320312 69073 30.592812 -40.257263 66.697983 69074 38.247742 -40.665619 65.651245 69075 37.580780 -41.075241 65.853119 69076 9.644272 -42.389526 65.412292 69077 21.701874 -41.604828 66.566681 69078 36.502625 -41.256912 66.414597 69079 35.934341 -42.509033 65.833374 69080 23.151550 -42.145660 66.688065 69081 35.332794 -43.345001 65.379822 69082 10.261063 -43.979645 67.275177 69083 9.970459 -42.334854 67.156433 69084 16.407959 -42.731857 65.001984 69085 4.126236 -44.168564 64.890808 69086 5.298508 -44.407928 64.893066 69087 26.400696 -44.303055 65.571686 69088 25.303772 -43.381744 66.165314 69089 32.819031 -44.823761 66.299911 69090 34.468262 -43.920288 65.648315 69091 9.567207 -46.497009 66.783569 69092 9.114372 -47.186844 66.031464 69093 20.339783 -47.202469 66.098999 69094 2.886131 -48.476929 64.337128 69095 20.119781 -47.768494 64.965454 69096 20.742645 -48.735886 66.099823 69097 2.009369 -50.135971 64.444885 69098 20.565300 -50.032166 65.357178 69099 24.193001 -50.337509 64.943817 69100 2.204865 -49.332474 64.713333 69101 2.054421 -50.972061 64.608658 69102 31.702662 -51.507782 64.762802 69103 2.285973 -51.887161 64.794830 69104 34.202667 -51.891830 64.733292 69105 34.575218 -52.874420 64.727905 69106 2.670166 -53.814728 64.609299 69107 2.249893 -52.675980 65.669525 69108 21.452576 -51.421982 65.810379 69109 21.068451 -50.634766 66.025330 69110 22.092773 -51.388107 66.339935 69111 22.699890 -51.403702 65.777161 69112 22.978737 -51.091812 66.612885 69113 27.004181 -50.533432 66.534882 69114 28.034500 -50.761154 65.767029 69115 27.587570 -51.950531 66.771088 69116 31.026260 -52.009750 65.008469 69117 30.179260 -52.786194 64.863953 69118 31.177597 -53.197311 64.859802 69119 31.984163 -52.619675 65.055038 69120 32.074097 -53.793243 64.836029 69121 3.220131 -55.575897 64.843567 69122 27.321396 -53.666077 65.150299 69123 28.096474 -53.033340 65.410583 69124 28.949570 -51.954132 65.381500 69125 32.907913 -53.202652 65.046143 69126 33.706055 -53.759323 64.764496 69127 32.896576 -53.924225 64.876343 69128 33.684738 -52.722183 64.990341 69129 5.307320 -56.104385 64.028183 69130 25.431877 -54.909607 65.841034 69131 24.629402 -55.935852 65.789047 69132 24.782867 -55.578522 66.538513 69133 25.693871 -54.869598 64.653687 69134 32.723335 -54.544235 64.587158 69135 5.981796 -56.146255 63.954620 69136 17.508499 -55.750961 64.568237 69137 16.623917 -55.693802 64.842529 69138 17.575455 -56.217819 65.464294 69139 18.101288 -56.326599 64.651855 69140 24.753479 -56.719925 64.923737 69141 32.796524 -55.736801 64.173462 69142 5.397316 -57.620987 63.803650 69143 6.081551 -56.742477 63.745087 69144 24.428993 -56.962036 66.075226 69145 24.955795 -57.923767 65.137756 69146 4.642052 -57.432541 64.380310 69147 4.498673 -58.639847 64.014954 69148 13.415405 -58.653580 64.282715 69149 14.556839 -58.224579 65.230530 69150 18.527512 -56.980438 65.524597 69151 18.875748 -57.901810 65.391907 69152 3.736084 -59.625824 64.820312 69153 12.236153 -59.779633 64.039124 69154 10.335587 -61.604568 63.938568 69155 19.260262 -60.439041 64.451294 69156 19.800972 -60.997284 64.428131 69157 20.990936 -61.447586 65.132507 69158 8.188377 -62.684128 65.756577 69159 9.422165 -62.461426 65.862671 69160 22.609589 -61.833145 65.185944 69161 21.862297 -61.388977 66.233139 69162 23.867905 -61.892853 64.324188 69163 23.006424 -62.411255 63.989471 69164 22.856781 -62.210022 64.452454 69165 5.423859 -63.495468 64.232727 69166 7.465622 13.734741 69.716553 69167 6.284691 13.687073 69.559036 69168 5.608582 13.584930 69.351685 69169 8.779205 13.777832 69.617249 69170 5.614655 12.726608 69.735733 69171 6.480949 12.190765 70.271103 69172 4.924019 11.658661 69.525238 69173 8.337463 12.066254 70.542374 69174 10.137955 12.636475 69.679535 69175 9.386597 12.883560 69.899597 69176 11.017807 12.774261 68.982330 69177 9.562782 12.208389 70.124603 69178 10.390518 11.390320 70.050095 69179 5.476410 10.650269 70.145920 69180 5.591278 11.783203 70.020752 69181 5.235245 8.647659 69.427795 69182 4.624825 10.103638 69.061554 69183 10.188461 10.060242 71.033981 69184 11.899025 8.966080 69.879150 69185 5.006516 5.334793 69.451080 69186 21.182648 6.715836 69.317398 69187 18.968063 6.352448 69.224548 69188 18.159233 5.557259 68.932373 69189 22.417313 6.042267 69.303345 69190 21.366882 5.761887 69.632553 69191 19.971878 6.150269 69.516205 69192 20.675552 5.910309 69.654282 69193 23.254814 5.175102 69.254623 69194 18.058060 4.516266 68.593964 69195 18.968010 4.440125 68.962708 69196 22.056351 4.894058 69.595490 69197 11.760040 4.034721 70.126556 69198 19.936813 3.412292 68.943329 69199 20.347229 4.859467 69.549713 69200 21.333305 3.560318 69.464294 69201 12.571945 1.924164 68.838654 69202 12.438934 2.853317 69.819611 69203 20.906448 2.344254 68.969391 69204 22.025986 2.448334 69.384369 69205 25.829849 1.257858 68.954147 69206 14.474754 0.920212 68.790573 69207 13.673080 1.883484 69.865662 69208 21.855835 1.110992 68.891510 69209 23.214478 1.643967 69.416077 69210 24.569183 1.231903 69.381348 69211 25.224091 0.376175 69.244934 69212 14.529762 1.833847 71.238068 69213 13.989716 2.321564 71.197205 69214 15.155731 1.051941 70.265518 69215 22.910278 0.400909 69.130676 69216 2.980362 -1.726440 69.673233 69217 3.107994 -0.467056 69.353577 69218 23.521133 -0.812347 69.058441 69219 26.189651 -1.722916 69.322586 69220 25.058235 -0.715271 69.329468 69221 18.144699 -2.747849 69.857483 69222 17.496063 -1.668503 69.524261 69223 23.420883 -1.925354 68.723480 69224 22.882446 -2.739029 68.246124 69225 24.650803 -2.279282 69.209839 69226 17.851372 -3.759338 68.880951 69227 22.797668 -3.815598 68.062408 69228 23.698120 -2.584717 68.779861 69229 23.545792 -4.991074 68.486816 69230 24.623642 -6.570847 68.918320 69231 27.963364 -4.433517 69.234680 69232 2.291710 -6.895523 69.938187 69233 2.658241 -7.595688 68.367035 69234 25.930206 -6.248795 69.687149 69235 26.486267 -7.611588 69.666519 69236 25.519653 -7.564240 69.216614 69237 12.865623 -9.071472 69.457428 69238 11.952820 -8.697937 70.108215 69239 12.645241 -8.550430 69.935242 69240 19.908569 -8.548233 68.534302 69241 25.690613 -9.752045 68.454651 69242 2.792992 -9.516861 69.407776 69243 11.886246 -9.570999 68.780365 69244 12.680557 -10.012024 68.298111 69245 13.275116 -10.627853 68.292694 69246 20.651184 -10.239731 68.402512 69247 25.954575 -8.780518 69.050873 69248 28.991470 -9.410233 68.498047 69249 8.508102 -10.441040 70.092346 69250 7.746109 -10.987701 69.829971 69251 13.227135 -11.280762 68.112289 69252 13.712944 -11.235733 68.937256 69253 13.542107 -10.113251 69.017700 69254 21.007736 -9.124344 69.532074 69255 21.115685 -11.548080 68.376129 69256 25.949142 -10.577805 68.081223 69257 26.877686 -9.944748 68.718185 69258 28.188751 -10.497345 68.159668 69259 28.046951 -9.842026 68.797882 69260 6.235802 -11.947067 68.440887 69261 5.317116 -11.587982 68.762207 69262 6.026405 -11.596497 69.115082 69263 7.044586 -11.925873 68.462372 69264 13.250732 -12.558273 69.449539 69265 12.662163 -13.136261 68.671387 69266 13.196945 -12.138748 68.442841 69267 10.709496 -16.030914 67.926331 69268 9.881729 -16.021591 68.807281 69269 12.423645 -13.020599 70.041397 69270 11.921356 -13.815659 69.143646 69271 18.682152 -15.849014 68.374207 69272 19.230835 -15.045059 69.257507 69273 19.399658 -14.992386 68.219208 69274 18.273140 -16.136124 69.408112 69275 26.734222 -15.207214 68.305389 69276 27.617828 -15.060257 69.936707 69277 26.049088 -14.984970 70.526245 69278 25.921738 -15.091568 69.405853 69279 4.430100 -16.266144 68.567184 69280 24.811302 -15.485626 69.113281 69281 31.385742 -17.972427 69.127304 69282 7.748886 -16.966751 68.020844 69283 8.428452 -17.292847 67.607132 69284 5.891220 -16.438614 67.996887 69285 9.081581 -17.010208 67.963196 69286 10.039589 -16.551407 67.808029 69287 23.701912 -16.065872 69.447708 69288 18.457565 -18.145935 68.962769 69289 22.498047 -16.800339 70.672760 69290 23.634628 -15.980408 71.445618 69291 22.800919 -16.432922 72.279022 69292 31.000900 -17.571823 70.354492 69293 31.014847 -17.823059 71.059265 69294 30.507507 -17.224808 71.174500 69295 19.538361 -18.432999 68.943802 69296 19.963127 -18.449631 70.044022 69297 20.728485 -18.130508 69.072128 69298 32.003281 -20.736328 69.680969 69299 31.850954 -19.365814 69.754547 69300 2.270775 -20.719467 67.649658 69301 36.623718 -22.855331 67.466827 69302 36.671730 -21.577301 67.182068 69303 5.870537 -22.293777 67.487946 69304 37.066833 -23.654877 67.828262 69305 6.515587 -22.713852 67.210693 69306 6.933426 -23.297745 67.309265 69307 6.204407 -22.916977 68.024216 69308 22.300827 -23.474274 67.685989 69309 23.090683 -23.180511 67.950195 69310 25.883331 -24.712784 67.405151 69311 25.899933 -22.230087 69.695404 69312 26.707153 -21.866379 70.464905 69313 26.925224 -22.413162 69.885315 69314 25.887314 -23.793228 68.190903 69315 21.719894 -24.979492 67.622177 69316 22.074600 -24.599182 68.252747 69317 21.831306 -24.118439 67.439972 69318 33.546051 -23.858765 68.791916 69319 34.193703 -23.752167 68.002319 69320 34.072899 -24.562531 68.820404 69321 33.074493 -23.544739 69.140839 69322 35.130249 -24.751175 68.478226 69323 36.355316 -24.067963 68.059860 69324 5.382202 -24.844055 67.053131 69325 6.616295 -23.901367 67.544647 69326 5.980270 -24.376434 67.651917 69327 26.810471 -24.754852 68.236237 69328 29.014343 -25.846268 69.564575 69329 29.797043 -26.320480 69.789719 69330 29.711761 -26.800980 69.179321 69331 28.044083 -26.790619 67.518921 69332 36.187363 -25.553757 68.139740 69333 37.002167 -25.771744 67.600342 69334 23.332718 -27.846497 69.050232 69335 32.694473 -27.714661 68.277603 69336 33.811905 -28.193573 67.431671 69337 33.824051 -27.591034 68.387054 69338 34.908783 -27.485809 67.950302 69339 35.586334 -26.569458 68.271423 69340 22.487259 -29.962555 67.629150 69341 22.785187 -28.974899 67.189087 69342 22.878815 -28.930298 68.317734 69343 27.294785 -31.055206 67.336716 69344 30.498459 -30.985214 67.440369 69345 9.064087 -32.373840 68.030487 69346 13.103942 -30.786652 70.760803 69347 11.623337 -30.914169 71.791809 69348 12.959778 -30.255432 72.158905 69349 18.573792 -31.359009 67.557495 69350 18.845558 -30.998093 68.838638 69351 21.142525 -31.126755 67.597809 69352 21.888359 -30.728592 67.378662 69353 26.412613 -31.621811 67.558395 69354 19.441116 -31.480316 67.576950 69355 32.372131 -32.334320 67.360718 69356 8.716980 -32.940247 69.801422 69357 9.540115 -32.176254 70.836472 69358 10.103394 -31.834076 70.040787 69359 26.074760 -33.516571 68.005981 69360 33.163467 -33.473816 67.177872 69361 17.647888 -34.368149 67.351669 69362 16.754120 -33.836990 69.119385 69363 14.938881 -33.876755 69.301407 69364 20.059784 -34.666565 68.245743 69365 20.577423 -34.361481 69.282181 69366 19.635086 -34.004852 69.609711 69367 30.509354 -35.261200 67.225708 69368 31.031746 -34.662415 67.366791 69369 31.853579 -34.121872 67.591553 69370 35.822876 -34.681580 66.941498 69371 34.604614 -34.964218 67.456680 69372 38.766876 -35.340042 66.496658 69373 37.303757 -35.402420 67.103378 69374 10.105659 -35.880417 66.722824 69375 18.784119 -34.233093 68.498810 69376 23.106636 -35.906799 69.721939 69377 22.255234 -35.658188 68.671539 69378 23.672180 -36.936249 68.340485 69379 26.482010 -34.737656 68.092331 69380 36.146973 -35.854309 67.747421 69381 35.468506 -36.537659 68.158493 69382 7.337280 -35.518433 67.071655 69383 7.062195 -36.516754 67.526062 69384 21.437027 -35.566284 67.311066 69385 26.367584 -36.792236 67.346375 69386 25.942429 -37.343994 67.368622 69387 34.021103 -36.368820 67.728119 69388 34.348282 -38.023727 67.581757 69389 32.996635 -35.136536 67.383606 69390 7.829628 -37.128204 67.421234 69391 9.249695 -36.698929 67.820862 69392 8.177757 -37.491531 68.152634 69393 30.012451 -36.746689 66.918106 69394 30.189713 -37.485306 67.413116 69395 15.059631 -39.359192 66.641968 69396 15.336052 -38.755524 67.078888 69397 17.473877 -39.197266 66.628357 69398 16.105865 -38.613083 67.070557 69399 24.194992 -37.324768 66.899002 69400 25.127060 -37.705399 67.928284 69401 38.469986 -37.548965 66.895401 69402 20.690231 -41.122559 66.492035 69403 36.591568 -40.076126 67.080353 69404 37.534279 -39.200546 67.009155 69405 37.290390 -40.348969 66.605286 69406 38.075989 -40.129257 66.226562 69407 1.672928 -42.138000 66.172821 69408 9.450623 -41.835251 67.157349 69409 9.618988 -42.014160 67.717880 69410 9.672646 -41.806244 67.305923 69411 9.440765 -42.148056 66.456573 69412 14.988327 -42.391190 67.678101 69413 18.753212 -39.800720 67.983810 69414 16.858597 -38.722000 67.764664 69415 8.610123 -42.382965 67.693909 69416 9.696121 -42.352463 68.730225 69417 10.163345 -42.938644 68.151871 69418 31.494164 -41.461884 67.138489 69419 32.540543 -41.672379 66.935165 69420 35.642471 -41.850082 66.613708 69421 6.898468 -43.600479 67.119553 69422 16.020248 -44.019867 66.434662 69423 16.222061 -43.317322 65.878723 69424 15.719650 -43.239197 66.420578 69425 24.146065 -42.697952 66.306747 69426 34.588455 -42.683762 66.562790 69427 35.099831 -40.301651 67.174713 69428 3.023544 -43.928665 66.925934 69429 3.964516 -44.169876 65.962067 69430 5.697121 -44.116455 68.349060 69431 4.980133 -44.258926 66.899231 69432 3.402039 -44.132492 68.446808 69433 17.051895 -45.229263 66.547455 69434 26.766006 -44.163406 66.806732 69435 33.365005 -44.032120 66.474762 69436 15.276375 -46.422516 66.287384 69437 14.830475 -46.193802 66.584900 69438 15.203033 -45.796753 66.537704 69439 15.931931 -47.009995 66.361969 69440 15.930969 -45.975113 66.490265 69441 14.810875 -47.259506 66.436157 69442 16.934021 -47.767059 67.131287 69443 15.772758 -48.120300 66.223511 69444 20.549210 -47.246307 67.238876 69445 2.880974 -48.763092 65.046219 69446 5.676285 -48.312149 67.676773 69447 4.444603 -48.586273 67.391495 69448 14.455597 -46.218658 67.352600 69449 13.993622 -47.451355 67.569702 69450 14.726013 -48.712585 66.042023 69451 15.063766 -49.639847 66.104553 69452 14.372269 -49.668381 66.023621 69453 13.976532 -49.268463 66.406860 69454 2.396088 -49.506866 65.424469 69455 2.518997 -49.953751 66.524185 69456 2.243378 -50.564835 65.365250 69457 14.102814 -48.285446 66.650299 69458 15.657104 -49.067627 66.174255 69459 16.294983 -48.821716 66.564606 69460 14.040253 -49.927032 66.261475 69461 24.502243 -50.384033 66.081635 69462 27.306015 -50.111008 65.771408 69463 25.591232 -50.311905 66.561172 69464 14.519744 -50.442001 66.485764 69465 15.283813 -51.396713 67.573456 69466 14.239334 -52.475769 67.414490 69467 14.222412 -51.405869 66.876617 69468 20.914139 -49.885132 66.174683 69469 23.624496 -50.836136 65.980011 69470 21.964584 -51.686157 65.742188 69471 2.599136 -55.570709 65.597351 69472 26.279030 -54.088593 65.990753 69473 26.737137 -53.765976 65.681778 69474 27.042496 -53.421082 66.385040 69475 25.159164 -55.286987 66.972473 69476 3.996201 -56.433777 64.656662 69477 16.026337 -56.743347 65.455566 69478 15.727791 -58.524292 66.579834 69479 16.657211 -58.537567 67.569794 69480 17.138268 -57.982132 67.148621 69481 3.818550 -57.995987 64.917313 69482 19.749588 -60.244705 65.438614 69483 19.176590 -58.936310 65.658051 69484 3.630921 -60.483704 65.806168 69485 3.250458 -59.667984 65.831635 69486 12.739937 -60.623184 65.751175 69487 14.388367 -60.587418 67.503662 69488 24.479553 -60.805115 65.101776 69489 24.221878 -58.478668 66.662064 69490 4.442719 -62.451126 64.932617 69491 22.929489 -61.068298 66.343964 69492 23.637268 -61.309174 65.438995 69493 4.778404 -63.165924 64.676819 69494 5.166771 -63.427490 64.857712 69495 6.642387 11.030319 71.029434 69496 5.840462 9.688156 71.156891 69497 5.267075 7.899689 71.170761 69498 11.611359 8.648132 70.273743 69499 10.786964 8.640076 71.219788 69500 5.968567 8.742950 72.224792 69501 4.933373 5.998230 70.350418 69502 4.920494 6.787323 70.875122 69503 11.592773 5.069321 70.799973 69504 11.347900 6.152420 71.175888 69505 19.192245 5.426468 69.413116 69506 4.673889 4.870872 70.916412 69507 4.302567 3.872787 69.685425 69508 23.207886 3.633186 69.447815 69509 11.589195 5.315079 72.136444 69510 12.502151 3.871613 71.535385 69511 4.058930 1.714462 69.919403 69512 3.769600 0.404434 69.581787 69513 13.406068 2.785675 71.251984 69514 24.038574 0.362778 69.369019 69515 4.886086 0.199783 70.279617 69516 5.231499 1.373016 71.408920 69517 18.119034 -1.858887 71.447266 69518 17.766037 -1.654160 72.874756 69519 16.784561 -0.869339 72.923706 69520 15.451797 0.819611 72.327393 69521 16.681725 -0.352997 70.385376 69522 4.135666 -0.580612 69.945969 69523 4.310700 0.410782 69.832916 69524 3.476173 -1.095688 69.876221 69525 2.745300 -5.592621 72.463257 69526 2.391113 -5.649475 71.568573 69527 3.264443 -4.674637 72.036530 69528 26.310455 -3.259308 69.478729 69529 25.811821 -4.271057 69.687805 69530 18.169289 -5.044479 68.848068 69531 26.475609 -4.084335 69.764206 69532 26.540390 -4.603012 69.884186 69533 27.140839 -4.193817 69.599213 69534 2.456764 -3.922516 69.967453 69535 18.751709 -3.951218 70.051041 69536 27.265976 -5.369583 69.639313 69537 19.093681 -5.298492 69.599915 69538 27.553154 -7.522537 69.671753 69539 27.180847 -6.617554 69.699005 69540 20.666649 -6.606232 70.336121 69541 27.537582 -8.324844 69.642792 69542 28.486923 -8.182648 69.128265 69543 27.802223 -9.118210 69.168091 69544 2.354607 -8.442154 70.138519 69545 10.909912 -9.422089 69.565369 69546 10.751724 -8.928757 70.890518 69547 26.859680 -8.683945 69.465118 69548 3.456535 -10.249893 69.407288 69549 12.742432 -9.560562 68.766403 69550 14.074341 -9.618195 70.105331 69551 21.688278 -11.058075 69.871490 69552 21.922401 -9.219086 70.657455 69553 14.232635 -10.694946 70.053055 69554 13.941406 -11.545227 70.124695 69555 22.546944 -11.253937 71.795502 69556 22.490547 -9.988388 71.710815 69557 22.166702 -12.056015 70.800766 69558 6.870308 -11.475861 69.282684 69559 13.655106 -11.990082 69.355988 69560 20.257217 -14.113388 69.086594 69561 28.126839 -15.380310 68.666153 69562 1.931816 -17.043442 69.752441 69563 2.560333 -16.557800 68.903412 69564 2.890892 -16.342056 69.400421 69565 1.678406 -17.513687 68.693237 69566 6.057144 -16.452728 68.727631 69567 5.892601 -16.353973 69.265533 69568 17.916046 -17.400650 69.239990 69569 21.124496 -17.831146 70.135437 69570 6.863350 -16.260620 69.587433 69571 8.318352 -17.144348 68.251617 69572 8.407990 -16.511368 69.071915 69573 17.435822 -17.625839 70.334183 69574 17.511223 -16.772156 70.487167 69575 31.613176 -18.506378 70.099213 69576 1.718605 -19.912125 68.364487 69577 1.391335 -19.328247 68.391235 69578 1.356705 -18.630173 68.329422 69579 1.251930 -18.975983 69.414368 69580 2.899017 -21.075836 68.196609 69581 2.169663 -20.657288 68.854919 69582 3.149529 -22.106613 69.357666 69583 4.310204 -22.117844 68.540741 69584 3.187256 -21.434601 68.639572 69585 5.373871 -22.215576 68.106003 69586 5.333672 -22.654175 68.601288 69587 5.813095 -23.108490 68.535950 69588 23.177399 -23.210724 68.775848 69589 22.565453 -24.005569 68.811203 69590 23.429428 -23.974884 69.512177 69591 24.638702 -24.589371 70.857117 69592 24.702164 -23.002426 70.352692 69593 26.630180 -23.323349 69.118011 69594 5.941322 -23.694321 68.262985 69595 22.318115 -23.685959 68.248169 69596 32.430183 -23.157303 69.764984 69597 36.929565 -24.006531 68.049561 69598 3.637291 -24.664597 68.340927 69599 4.990257 -24.295639 68.201202 69600 4.139572 -24.167343 68.956482 69601 28.086044 -23.292679 70.147018 69602 27.822067 -25.860291 68.417725 69603 27.938271 -24.628845 69.352966 69604 32.857498 -24.631897 69.702850 69605 35.238487 -25.817627 68.733612 69606 1.043610 -26.492249 69.359863 69607 23.527344 -24.910477 69.737244 69608 23.131790 -24.969543 69.358185 69609 28.802139 -26.735596 68.484116 69610 34.744377 -26.594498 68.790634 69611 0.637421 -28.321976 68.020874 69612 29.581093 -27.287079 68.261139 69613 31.530838 -27.453201 68.673309 69614 20.243515 -31.083298 68.458710 69615 21.777618 -30.258026 68.840576 69616 21.347198 -30.013306 70.424042 69617 22.463623 -29.347351 70.513290 69618 23.693901 -27.746384 70.460693 69619 22.979233 -28.852798 69.430969 69620 28.977119 -31.106857 68.352875 69621 27.172714 -31.721970 68.458618 69622 14.814316 -30.889267 69.391174 69623 14.941330 -30.331879 71.003555 69624 19.671227 -30.750015 69.621429 69625 27.925049 -31.835342 69.379517 69626 30.746857 -31.692459 68.369446 69627 0.710236 -32.109970 69.417419 69628 25.836884 -32.758560 67.751373 69629 31.686541 -32.229843 67.995972 69630 31.965105 -33.072510 67.875778 69631 31.358162 -32.604523 68.456940 69632 7.303841 -34.735901 67.935928 69633 30.676743 -34.881241 67.929596 69634 31.086456 -34.286377 68.073639 69635 31.318451 -33.552765 68.392670 69636 21.188110 -34.956024 68.529877 69637 26.656296 -36.086685 67.951447 69638 30.423759 -36.083481 67.889862 69639 34.680923 -36.212509 68.049103 69640 6.806816 -35.723587 68.445312 69641 10.719574 -35.640121 68.956696 69642 21.668213 -34.767456 69.649277 69643 36.301170 -36.676620 68.112518 69644 37.207581 -37.351318 67.577042 69645 8.506523 -37.307266 69.945389 69646 9.660507 -36.054321 72.154816 69647 8.324005 -37.062683 72.265472 69648 26.235992 -37.739487 68.536407 69649 26.652206 -37.051712 68.160156 69650 30.890099 -37.211716 69.008423 69651 7.490456 -37.714600 68.416321 69652 15.561218 -38.661697 68.347443 69653 14.928001 -39.543121 67.860336 69654 36.376465 -37.966354 68.008148 69655 36.217094 -37.305435 68.154053 69656 1.120773 -37.851883 68.885071 69657 35.543434 -38.079010 67.985077 69658 36.416840 -38.907440 67.569519 69659 0.897247 -40.125412 67.916458 69660 1.286354 -41.979202 67.074600 69661 20.579437 -40.926056 67.321793 69662 22.357391 -41.716309 67.691010 69663 30.734795 -40.646851 67.615921 69664 30.839447 -40.273773 68.563171 69665 30.897339 -39.215866 68.974457 69666 1.006706 -41.134201 67.813660 69667 5.043938 -44.380417 65.659821 69668 24.648483 -42.771759 67.274429 69669 31.582581 -42.933701 67.885101 69670 31.174377 -42.700699 69.110199 69671 31.114731 -41.444092 68.433533 69672 32.691742 -42.813232 67.066803 69673 1.824539 -42.935928 66.930527 69674 15.334991 -43.255737 66.995880 69675 24.426254 -42.541794 68.511963 69676 26.618446 -43.835312 68.157379 69677 25.867989 -42.783173 70.725922 69678 24.297073 -41.935013 70.924744 69679 25.301155 -42.160522 71.663757 69680 15.060958 -44.223236 67.329498 69681 14.992523 -43.322784 67.597275 69682 15.568779 -45.079849 66.721375 69683 10.017586 -45.220123 66.710190 69684 14.865067 -45.406464 67.086121 69685 16.715271 -46.402451 66.717529 69686 26.566788 -43.485077 69.539368 69687 27.101013 -43.307602 70.617523 69688 28.156296 -44.690720 67.635818 69689 9.734193 -45.722122 67.769623 69690 18.469620 -46.245209 67.823303 69691 17.581345 -46.313309 67.231216 69692 17.882919 -46.959290 67.945190 69693 19.523453 -46.393417 67.950073 69694 20.784927 -47.257629 68.654388 69695 19.513283 -46.923462 68.979996 69696 30.969055 -44.552963 68.496597 69697 31.289597 -43.873276 68.399612 69698 30.657104 -44.892883 68.296387 69699 9.171844 -47.314758 66.872940 69700 8.675255 -47.855530 66.931870 69701 13.996246 -47.180527 68.888214 69702 14.139008 -46.509949 68.133606 69703 16.620522 -48.919174 67.061096 69704 3.169098 -48.988327 66.373383 69705 3.105782 -49.279907 67.907593 69706 13.706436 -50.154495 66.826538 69707 16.012047 -49.839172 67.057816 69708 16.932846 -48.929382 67.756317 69709 16.703949 -49.873901 68.530441 69710 13.571632 -49.017334 67.669907 69711 21.395409 -49.905533 66.812256 69712 21.357788 -48.463135 67.556091 69713 13.214569 -50.322708 67.724777 69714 13.840881 -50.878876 66.683060 69715 21.546967 -50.907242 66.508530 69716 23.926559 -50.493607 67.453369 69717 26.405411 -51.063797 67.883789 69718 2.406342 -51.050171 67.783661 69719 3.023018 -50.214264 69.520477 69720 3.017243 -51.409698 69.149719 69721 2.062134 -52.309814 66.635086 69722 2.278786 -51.366455 66.154175 69723 15.071838 -52.816055 68.498077 69724 22.259026 -50.681885 67.010406 69725 27.185181 -52.006683 67.972412 69726 27.045776 -52.048828 68.838928 69727 13.314835 -52.606079 67.583084 69728 12.689178 -52.631485 68.231918 69729 12.941154 -51.484848 68.157425 69730 26.760422 -53.237823 68.386841 69731 2.146721 -54.864792 66.585709 69732 25.957016 -54.438705 66.959808 69733 24.932465 -55.435974 68.247620 69734 2.060158 -53.517731 66.391464 69735 17.018288 -56.955948 66.195770 69736 18.025230 -56.912308 66.265381 69737 24.433960 -56.174545 66.652100 69738 2.850327 -57.014282 65.918900 69739 18.540550 -58.011368 66.889313 69740 17.329208 -57.495850 66.698944 69741 19.730827 -59.514038 67.114380 69742 24.215851 -56.813660 67.499054 69743 3.115257 -58.740005 65.887558 69744 2.607781 -58.235916 67.088104 69745 3.248787 -59.608994 66.742950 69746 16.024643 -59.414856 67.822174 69747 24.028519 -60.166458 66.045471 69748 21.985748 -60.650848 67.354965 69749 22.131821 -59.917053 68.265182 69750 23.253471 -59.725449 67.420380 69751 4.400856 -61.671097 65.842148 69752 3.988449 -60.675110 66.653564 69753 4.898682 -62.826019 65.334839 69754 15.731529 -60.154465 68.728333 69755 22.810425 -58.788620 68.768494 69756 6.095177 -61.718063 66.662552 69757 5.185845 -62.228790 66.075775 69758 7.199097 -61.913040 66.592743 69759 7.472054 10.781311 71.549530 69760 8.860046 10.658035 71.320190 69761 5.509178 7.362518 72.715607 69762 4.912644 6.894684 71.816696 69763 4.787430 6.043091 71.440643 69764 4.997749 5.441017 72.555084 69765 4.072723 2.955948 70.094238 69766 4.524452 3.175735 71.046143 69767 4.969650 6.349411 72.519852 69768 12.238449 4.269821 72.794067 69769 14.542786 1.065750 73.589264 69770 14.115540 2.167847 72.426178 69771 6.437828 1.507339 73.282608 69772 6.730354 -0.483002 71.847733 69773 5.177048 -1.345749 70.439636 69774 4.009773 -1.780334 70.263840 69775 5.883591 -0.392822 70.821671 69776 6.123222 -1.525681 70.793274 69777 3.262100 -2.788116 70.344482 69778 6.591431 -0.981415 71.044312 69779 6.855126 -1.693054 71.344330 69780 5.916794 -4.018723 72.946259 69781 4.897591 -3.040100 71.347656 69782 6.686066 -2.586044 72.159912 69783 18.628006 -2.841690 70.743744 69784 19.252991 -3.234055 71.432587 69785 19.675514 -4.590210 70.577850 69786 20.130493 -4.227249 71.546509 69787 26.006424 -5.098480 69.822296 69788 20.453262 -5.371231 70.915558 69789 21.186768 -6.544113 71.110870 69790 20.767441 -5.200928 72.251312 69791 27.019989 -8.050003 69.776947 69792 2.429703 -7.409836 71.693329 69793 2.672066 -8.507675 71.729675 69794 21.948105 -7.840012 71.404495 69795 22.118011 -7.268219 72.051453 69796 21.612213 -6.553467 72.013367 69797 21.223648 -7.873596 70.396149 69798 2.635582 -9.251038 70.559814 69799 11.991333 -8.262146 71.788361 69800 13.174454 -8.584671 70.571976 69801 22.489365 -8.883133 71.832367 69802 3.235657 -9.957336 70.305206 69803 9.694809 -9.118622 71.571106 69804 21.401604 -12.897964 70.094879 69805 4.239533 -10.560135 70.120514 69806 5.641670 -10.968140 70.003540 69807 7.941406 -10.303497 70.780518 69808 13.619675 -12.141800 70.074585 69809 21.460350 -13.379959 71.190933 69810 22.042397 -12.755203 71.162506 69811 13.164856 -12.481674 70.336914 69812 11.156525 -13.625000 70.476593 69813 10.000061 -14.472046 70.370605 69814 9.693405 -15.270218 69.832611 69815 18.989731 -15.140717 70.215057 69816 18.183456 -15.694885 70.998138 69817 20.198013 -14.243896 70.548035 69818 24.857956 -15.430161 70.041199 69819 28.718803 -15.412903 70.290985 69820 27.110672 -14.927017 71.218979 69821 27.451721 -15.259735 72.079254 69822 26.598091 -14.969208 72.025360 69823 3.273941 -16.249039 70.053101 69824 2.606705 -16.600937 71.169022 69825 8.528870 -15.158997 70.655243 69826 6.981621 -15.180695 71.439499 69827 9.068832 -15.797638 69.687225 69828 20.008804 -14.301025 73.003204 69829 18.916321 -14.977798 72.213531 69830 18.902588 -14.875305 73.599487 69831 23.894722 -15.880096 70.517899 69832 29.629120 -16.167587 70.496643 69833 17.885971 -18.071320 69.798920 69834 18.611702 -18.480774 69.839905 69835 19.177505 -18.788681 69.649368 69836 19.035400 -18.782455 70.046707 69837 19.487503 -18.777557 69.738388 69838 21.319824 -17.447906 71.324463 69839 19.259308 -18.915253 69.883713 69840 1.295250 -20.698975 70.127136 69841 2.383331 -21.373734 69.408722 69842 1.443741 -22.308960 70.684555 69843 2.123283 -21.906860 69.927429 69844 4.686783 -23.052948 69.017456 69845 5.302994 -23.378067 68.694275 69846 24.939789 -22.434143 69.598572 69847 24.066574 -22.898209 69.414185 69848 3.834229 -22.967880 69.334534 69849 4.726296 -23.754959 68.937973 69850 31.249397 -24.816330 70.488922 69851 31.264252 -23.794083 70.545242 69852 2.573044 -24.476471 69.131989 69853 1.719025 -25.577972 68.721130 69854 3.457428 -24.331192 69.015076 69855 1.522552 -25.005951 69.926849 69856 24.570374 -26.294586 70.954773 69857 29.696548 -24.601379 70.403137 69858 33.475578 -25.656754 69.531372 69859 32.842384 -25.834274 69.730743 69860 34.218750 -25.549133 69.114212 69861 32.199532 -26.679565 69.427643 69862 33.560181 -26.638321 69.101318 69863 34.299744 -27.190033 68.678314 69864 30.728271 -26.573608 69.644867 69865 0.963509 -25.773193 71.275803 69866 0.620491 -26.974747 70.452423 69867 0.574036 -28.081757 69.461578 69868 7.124107 -34.715714 69.715149 69869 20.588715 -30.595856 69.665054 69870 26.329056 -32.527802 68.251648 69871 27.193199 -32.444946 69.220734 69872 29.504166 -31.454224 69.709335 69873 28.805450 -31.622269 69.877594 69874 30.053162 -31.659866 69.215469 69875 30.698944 -32.755295 69.333160 69876 27.069870 -33.704987 69.242294 69877 17.836533 -33.890091 69.202240 69878 30.871864 -34.649750 69.040649 69879 7.652954 -37.766052 71.915848 69880 12.024567 -34.843018 68.622910 69881 27.027710 -35.333771 68.838959 69882 6.772812 -37.415131 68.276749 69883 6.242310 -36.771271 68.800262 69884 23.885834 -36.756699 69.725067 69885 27.073997 -36.446198 68.913589 69886 27.462555 -35.573196 69.795074 69887 26.877686 -37.205109 68.841431 69888 30.751732 -38.131256 68.591965 69889 30.961441 -36.133545 69.640839 69890 5.922829 -37.637833 69.111816 69891 11.117966 -35.243500 70.489502 69892 11.811234 -34.579086 71.887177 69893 25.100807 -37.862000 69.421112 69894 25.645798 -38.191940 68.982590 69895 34.782532 -37.072311 68.068146 69896 6.629143 -38.145630 69.574860 69897 26.868622 -37.254456 69.695206 69898 26.036194 -37.854904 70.122925 69899 26.068420 -38.140671 69.523041 69900 24.475708 -37.217941 69.873444 69901 26.207474 -38.044342 69.134003 69902 19.543137 -40.111542 69.728577 69903 19.323746 -40.093781 68.954102 69904 18.193001 -39.047928 69.799805 69905 18.957481 -39.541534 70.365982 69906 19.698914 -39.865631 70.607574 69907 1.040054 -42.036728 70.152527 69908 1.264183 -43.177048 70.324600 69909 1.613487 -43.278839 69.153473 69910 16.749802 -38.494598 69.123291 69911 20.740273 -40.834274 68.882309 69912 1.264427 -40.296646 69.821365 69913 1.586937 -41.290253 71.607727 69914 7.200165 -43.352402 69.090576 69915 8.360565 -42.527191 69.208206 69916 14.880699 -41.073990 68.650177 69917 22.549370 -41.713028 68.788361 69918 30.997498 -40.744980 70.388321 69919 1.208984 -42.219528 68.362427 69920 2.029289 -43.462738 67.950821 69921 14.906158 -43.539413 68.366913 69922 15.089844 -42.420059 69.212128 69923 14.694962 -45.109421 68.262512 69924 14.973679 -44.276413 69.258026 69925 2.915985 -43.992722 70.000793 69926 5.161652 -44.115829 69.411011 69927 10.076477 -44.588486 68.648422 69928 28.502388 -44.500290 68.816986 69929 9.058014 -47.201004 67.652649 69930 14.361633 -45.938904 68.144531 69931 13.656364 -48.224609 68.776093 69932 8.702477 -47.882080 67.616119 69933 18.090637 -47.979660 68.970932 69934 3.136551 -49.124451 69.178406 69935 2.755615 -49.685532 68.738037 69936 6.652474 -48.215271 67.666809 69937 7.702316 -48.183289 67.215759 69938 8.415596 -48.100418 67.529083 69939 20.375046 -47.160736 69.794098 69940 21.648926 -47.683731 69.798157 69941 13.502457 -51.329788 67.198456 69942 16.074562 -50.730637 68.042160 69943 22.267502 -49.652634 67.692932 69944 22.091537 -48.476471 68.663422 69945 25.297470 -50.547379 68.965118 69946 24.623322 -50.082504 69.892395 69947 23.802780 -49.892868 68.954620 69948 2.084328 -52.791153 67.365204 69949 22.933868 -49.580139 68.378052 69950 12.953735 -53.653625 67.790207 69951 13.731926 -53.548264 67.599457 69952 2.110222 -53.880905 67.589340 69953 2.222160 -54.766769 67.861237 69954 14.337822 -53.718018 68.011353 69955 14.709351 -53.760483 68.581512 69956 24.210037 -55.444061 69.626129 69957 25.262932 -54.445297 69.761841 69958 27.013306 -52.612701 69.307007 69959 27.156807 -52.637482 68.835938 69960 7.479782 -54.742004 67.931885 69961 6.899460 -53.824875 68.248505 69962 7.793258 -53.781937 68.249207 69963 8.437965 -54.974380 67.581635 69964 9.169769 -54.948624 67.758270 69965 8.457703 -55.614365 67.574280 69966 12.275208 -54.453781 67.898453 69967 12.098618 -53.435104 68.409485 69968 13.343689 -54.726074 68.193848 69969 26.163330 -53.409851 69.932831 69970 2.342522 -56.042389 66.523468 69971 10.253647 -54.638351 68.294952 69972 11.491203 -55.558029 67.956268 69973 9.863998 -55.789429 67.552979 69974 11.424850 -54.389938 68.290665 69975 2.215309 -56.715988 67.066010 69976 8.803680 -56.888702 67.515656 69977 10.303345 -56.842361 67.645920 69978 9.608467 -57.632339 67.522156 69979 17.529716 -58.169220 67.627747 69980 24.658287 -55.900269 67.245697 69981 2.298767 -55.792099 67.712341 69982 2.237534 -57.417603 67.147537 69983 9.623749 -58.119156 67.697220 69984 9.625946 -58.554947 68.045685 69985 9.005622 -58.106277 67.678650 69986 10.354660 -58.959610 69.099274 69987 10.308823 -57.904938 68.253448 69988 11.134865 -57.742676 69.810272 69989 18.173248 -58.493057 68.136169 69990 23.732162 -57.900055 68.106934 69991 23.255219 -56.874588 69.278473 69992 19.152626 -58.949570 68.195282 69993 23.639709 -58.711029 67.862335 69994 3.982094 -59.962372 67.517822 69995 4.874863 -60.927139 67.003448 69996 12.926926 -61.377701 67.196625 69997 13.082733 -61.484512 68.184341 69998 20.846069 -60.683151 66.683563 69999 9.369324 -61.775223 66.961670 70000 11.417397 -61.546463 67.449539 70001 11.955978 -61.331268 69.039154 70002 8.040131 -61.543900 66.961746 70003 6.616921 10.458832 71.547623 70004 7.852661 10.012360 72.085693 70005 6.760971 9.880127 71.955292 70006 10.084183 8.028717 72.250580 70007 9.145401 9.041626 72.263153 70008 10.796249 6.980911 72.014694 70009 10.633073 5.883888 73.144272 70010 9.519760 7.301544 73.067139 70011 5.067535 4.253128 72.556335 70012 5.297577 2.929459 72.690903 70013 11.583717 5.000725 73.047302 70014 7.246178 -1.460754 73.020172 70015 6.805679 -0.031418 72.911621 70016 7.241387 0.147003 73.784149 70017 7.373856 -1.361313 71.628601 70018 7.464531 -1.639084 71.526642 70019 7.584549 -1.590637 71.704041 70020 18.865860 -2.762650 72.712585 70021 3.384125 -3.930496 71.407654 70022 3.213394 -3.605377 70.913422 70023 7.355538 -1.795837 71.860596 70024 4.341004 -5.312134 73.140533 70025 2.374954 -6.418030 71.825958 70026 19.635361 -4.275818 73.597260 70027 19.875153 -3.790543 72.379166 70028 2.544617 -4.818985 70.816360 70029 22.040985 -6.827347 72.625015 70030 15.453171 -9.306519 71.821625 70031 15.537048 -9.994583 71.724487 70032 14.930626 -10.106598 71.120911 70033 4.085259 -10.235275 71.014404 70034 8.721031 -9.757538 71.143677 70035 22.049774 -6.993958 73.386353 70036 22.428741 -7.864578 72.562302 70037 22.333542 -7.874100 73.530365 70038 3.453507 -9.518265 71.653152 70039 4.732811 -9.910645 71.916229 70040 13.661179 -8.214127 71.956024 70041 14.501213 -8.923935 71.316498 70042 22.452698 -12.241577 71.696106 70043 4.975304 -10.452621 70.987808 70044 6.999947 -10.656982 70.651337 70045 6.053810 -10.064285 71.726944 70046 7.625961 -9.747711 71.890839 70047 13.543015 -11.901672 71.164490 70048 14.426392 -11.149811 71.249268 70049 15.324615 -10.644989 72.280609 70050 11.840149 -12.957489 70.895721 70051 12.511398 -12.526321 71.105347 70052 9.801849 -13.651611 71.501892 70053 11.272675 -12.768188 71.747223 70054 19.228958 -14.867035 71.134521 70055 20.894180 -13.817719 72.026733 70056 19.897972 -14.451660 71.803329 70057 24.858246 -15.382996 71.269867 70058 26.021133 -14.940582 71.449707 70059 28.389832 -15.537964 71.220978 70060 5.742592 -16.183563 69.672333 70061 5.164894 -15.852554 70.778793 70062 17.413986 -16.251877 71.664673 70063 29.506676 -16.639175 71.659302 70064 29.616669 -17.844986 72.367218 70065 28.099411 -16.659607 72.990662 70066 30.425232 -17.997620 71.742493 70067 1.234756 -17.800903 70.451477 70068 0.976799 -18.208832 71.404358 70069 0.771049 -18.524628 70.453354 70070 0.716400 -19.372070 70.610016 70071 17.235046 -17.231522 71.756531 70072 17.845024 -18.097305 70.735474 70073 19.346046 -18.765686 70.132446 70074 18.973373 -18.426590 70.841461 70075 20.209793 -17.998489 71.498016 70076 18.907394 -18.039978 72.510315 70077 21.063324 -17.349747 72.429535 70078 31.204941 -18.549469 70.983047 70079 2.632042 -23.057083 69.744995 70080 3.490761 -23.823898 69.345093 70081 26.629242 -21.908707 71.467621 70082 27.485748 -21.743118 71.212372 70083 29.595657 -21.662537 71.580994 70084 28.914612 -21.113281 72.232010 70085 30.368103 -20.032349 71.696747 70086 27.702774 -22.215240 70.554688 70087 28.505814 -22.640015 70.715912 70088 28.524582 -21.959335 71.393219 70089 31.328697 -22.570648 70.671417 70090 31.386627 -21.492096 70.765869 70091 4.229759 -23.622696 69.250610 70092 25.718933 -22.156357 70.564850 70093 29.683281 -22.911789 70.934875 70094 25.634781 -24.931992 72.543411 70095 26.128220 -23.378723 73.176697 70096 25.666924 -22.847427 71.489044 70097 31.609194 -25.696198 70.098572 70098 1.886520 -23.763580 70.105225 70099 26.604500 -22.329544 72.425812 70100 1.272995 -23.830811 71.114655 70101 25.158798 -25.620575 71.653259 70102 30.013031 -25.792938 70.152740 70103 30.627274 -25.399643 70.472595 70104 30.702370 -25.906357 70.234436 70105 23.099823 -28.428101 72.071411 70106 16.602585 -30.148117 70.844284 70107 18.917664 -30.450623 70.066299 70108 20.082695 -30.139297 70.689026 70109 22.210045 -29.264084 71.549225 70110 22.199463 -28.951431 72.165619 70111 17.850113 -30.531662 69.793823 70112 26.823761 -32.569336 68.870483 70113 28.260986 -32.653549 70.257141 70114 27.532303 -32.606201 69.637650 70115 29.973709 -31.959763 69.957397 70116 29.803757 -32.784210 70.527786 70117 29.376343 -31.889877 70.331299 70118 7.673240 -34.046799 70.943756 70119 6.655411 -34.813995 71.707855 70120 13.101944 -34.306961 69.132965 70121 12.095238 -34.674179 69.548920 70122 13.197266 -34.122253 70.497421 70123 18.641747 -33.650146 70.074005 70124 20.720665 -33.857925 70.685516 70125 6.177818 -35.628418 70.927383 70126 5.100197 -37.262589 70.152985 70127 6.109375 -36.112320 69.912994 70128 30.508423 -33.869644 70.352478 70129 30.699028 -35.272308 70.712540 70130 5.354485 -37.822952 69.537781 70131 5.647118 -38.172714 69.456284 70132 30.989182 -36.266418 70.810852 70133 5.049606 -38.171371 70.004364 70134 15.363434 -38.388275 69.842773 70135 14.913513 -39.776947 69.823654 70136 14.816833 -38.594482 70.626984 70137 16.921738 -38.027023 70.322144 70138 17.357880 -37.802795 71.128815 70139 25.628052 -38.219772 69.553467 70140 31.304741 -37.207687 70.711670 70141 31.375175 -38.212097 70.017700 70142 5.627289 -38.457733 70.132660 70143 18.193451 -38.452103 70.984833 70144 31.643595 -38.643326 70.853851 70145 31.753847 -38.194092 70.764954 70146 18.550690 -39.099060 70.563110 70147 31.346054 -39.224945 70.424652 70148 30.774849 -40.002167 72.065857 70149 31.239761 -38.999222 71.578735 70150 21.620407 -40.927872 70.335785 70151 22.208199 -41.447144 69.575775 70152 30.619705 -42.943924 70.354279 70153 30.406494 -42.096878 71.403381 70154 9.013855 -42.312073 69.272369 70155 9.783478 -42.772903 69.859772 70156 8.636818 -42.728577 70.625946 70157 10.040573 -43.057907 70.822266 70158 10.153839 -43.269958 69.141647 70159 15.088394 -41.430740 70.053558 70160 24.089371 -42.178986 69.714401 70161 22.906921 -41.479416 70.513931 70162 0.921738 -39.140228 68.923828 70163 15.165833 -43.415604 69.570541 70164 14.982170 -45.320908 69.930084 70165 14.455444 -46.142502 69.032074 70166 28.744545 -43.550995 70.615173 70167 29.986771 -44.473862 69.191620 70168 30.037354 -43.872559 70.093353 70169 30.805679 -43.845535 69.321518 70170 14.400436 -46.965240 70.109009 70171 18.692139 -46.736389 68.401184 70172 22.943054 -49.049347 69.111435 70173 22.562195 -48.366211 69.698395 70174 20.861633 -47.703018 70.809692 70175 7.673605 -47.713120 68.648254 70176 6.253586 -47.894821 69.000854 70177 8.429382 -47.771286 68.035156 70178 9.000610 -46.563721 68.924973 70179 2.931084 -49.469849 69.409576 70180 4.177742 -48.624634 69.502991 70181 5.064407 -48.212173 68.619629 70182 13.040588 -50.012009 68.833282 70183 13.374741 -48.969559 68.793991 70184 2.810959 -52.812958 68.437347 70185 12.404526 -51.926727 69.149414 70186 23.355820 -49.103317 69.908203 70187 15.965759 -51.409866 69.044479 70188 26.332153 -51.192093 69.560303 70189 25.612930 -50.614929 69.826416 70190 16.101822 -51.725281 70.512238 70191 16.911545 -50.933701 71.505249 70192 16.153625 -52.234482 72.118439 70193 7.035004 -53.255951 68.396027 70194 6.346199 -53.209778 68.777222 70195 6.963478 -52.903763 68.876053 70196 7.419449 -53.119949 68.585083 70197 7.844696 -53.215897 69.114624 70198 2.616730 -54.078568 68.336548 70199 6.126816 -54.228531 68.548492 70200 8.884949 -54.127960 68.403076 70201 14.852645 -53.767868 69.394379 70202 6.670250 -56.082001 68.291107 70203 8.412949 -54.510757 67.859314 70204 14.354202 -54.392151 68.632935 70205 12.669052 -55.914490 69.098206 70206 13.313622 -55.647003 70.511642 70207 12.165665 -56.681015 70.289093 70208 11.382095 -56.866226 68.710052 70209 2.366051 -56.948578 67.990997 70210 2.238106 -57.673508 67.657028 70211 7.661705 -58.111908 67.898285 70212 7.288582 -60.222641 67.518921 70213 6.468720 -58.783493 68.112701 70214 14.023163 -54.916031 68.779892 70215 13.738846 -55.225723 69.348480 70216 17.335129 -58.441788 67.991150 70217 3.308945 -58.870697 67.903351 70218 5.750740 -59.902298 67.778427 70219 8.958893 -59.370209 68.039871 70220 17.243240 -58.864929 68.324356 70221 19.912735 -59.529404 68.349731 70222 3.982720 -59.385544 68.069366 70223 8.706207 -60.732513 67.625519 70224 16.924675 -59.440552 68.816666 70225 20.921227 -60.033081 68.068024 70226 21.615295 -59.612198 68.868652 70227 4.645386 -59.580643 67.992004 70228 10.221878 -60.605225 68.446503 70229 13.164017 -61.482483 69.149292 70230 13.448792 -61.024429 70.104919 70231 14.445595 -60.963257 69.053589 70232 14.763138 -60.689713 70.191437 70233 7.263359 8.928864 72.758636 70234 6.239472 8.155518 73.010849 70235 8.235352 7.998627 73.256744 70236 6.794960 7.376053 73.655273 70237 8.252960 6.969055 73.759003 70238 5.660317 6.308929 73.414246 70239 11.815659 4.380539 73.366776 70240 12.713699 3.673187 72.709702 70241 13.173759 3.074303 72.641312 70242 7.385384 -1.389740 71.987610 70243 7.384621 -2.712753 74.294937 70244 6.839218 -3.118118 73.322266 70245 18.155975 -2.039764 72.836899 70246 17.582260 -2.752213 74.181854 70247 18.705811 -5.066956 74.911392 70248 17.395157 -4.494431 75.379974 70249 16.409996 -3.742722 75.638504 70250 21.453262 -6.116257 73.097610 70251 21.930038 -7.355682 73.923065 70252 14.927841 -8.222534 72.863449 70253 8.736160 -9.094727 72.416626 70254 9.724335 -8.569687 72.964874 70255 10.594498 -8.582108 72.142883 70256 16.078011 -8.976517 72.655914 70257 15.941620 -9.742126 72.268158 70258 16.477905 -9.491104 72.803497 70259 22.377876 -8.911057 73.207901 70260 5.349617 -9.173615 73.043579 70261 4.234146 -9.366653 72.665634 70262 4.340836 -8.856293 73.306580 70263 6.764404 -9.089951 73.063568 70264 22.253342 -10.144989 73.330612 70265 12.588165 -11.944809 72.482361 70266 14.272217 -11.328430 72.905060 70267 22.641998 -11.910309 72.412933 70268 9.656372 -12.610062 73.139832 70269 9.926895 -12.851654 72.480072 70270 10.930756 -12.162308 73.158676 70271 22.002365 -12.939026 72.246796 70272 22.502975 -12.376465 72.310806 70273 21.136436 -13.501007 73.338226 70274 21.887924 -12.784454 73.409241 70275 8.207329 -13.574615 73.040985 70276 6.045891 -14.861526 72.693130 70277 24.116089 -15.800278 72.793945 70278 25.614388 -15.237152 72.384109 70279 26.671944 -15.500870 72.882355 70280 4.200867 -15.695145 72.666504 70281 17.885406 -15.641266 72.110062 70282 21.912506 -16.930115 71.932739 70283 30.866196 -17.889771 71.395294 70284 0.589416 -20.622864 71.939606 70285 17.943924 -18.038055 71.777710 70286 17.514587 -17.686417 72.970764 70287 27.727051 -21.497589 72.462372 70288 30.497772 -21.804474 71.247116 70289 0.791847 -22.374832 71.987183 70290 11.984512 -22.786377 71.929855 70291 12.229485 -23.197678 71.552338 70292 11.587601 -23.200836 72.091949 70293 13.119446 -23.852386 71.486710 70294 12.203552 -23.637283 71.517120 70295 12.798775 -23.042313 72.067551 70296 1.077538 -23.732239 73.283493 70297 12.349091 -24.296875 71.909134 70298 13.525833 -24.924576 71.671265 70299 12.826553 -25.120499 72.366302 70300 14.304298 -23.931198 72.242371 70301 14.654793 -24.642380 71.716599 70302 14.054153 -24.539581 71.495712 70303 13.347229 -24.479614 71.420425 70304 14.410568 -25.063919 71.721863 70305 1.176651 -26.184570 73.482727 70306 0.764534 -26.889069 72.020447 70307 0.605698 -26.833801 71.306183 70308 24.596176 -26.959183 72.087433 70309 25.068336 -26.247803 71.749954 70310 0.562279 -27.584015 71.236786 70311 0.595337 -28.535278 71.137024 70312 0.548500 -29.347916 70.184357 70313 14.343010 -29.967804 71.950897 70314 18.589890 -29.886490 71.143951 70315 17.705353 -29.390213 71.944397 70316 19.057892 -29.019653 72.485779 70317 21.875763 -29.612320 71.082672 70318 21.330978 -29.326752 71.814270 70319 0.699997 -30.383514 70.590851 70320 10.248306 -31.669922 70.762238 70321 11.062660 -31.337448 70.553314 70322 28.842957 -31.999298 70.399307 70323 0.617584 -31.097672 69.864334 70324 7.091728 -33.926834 72.797012 70325 7.500107 -34.077011 71.810867 70326 29.023636 -32.445572 70.604752 70327 19.548981 -33.409164 70.910309 70328 15.653183 -33.174988 71.200836 70329 14.623482 -33.421494 71.072174 70330 17.662308 -33.356995 70.535629 70331 16.569199 -33.255569 70.790115 70332 18.748077 -32.941467 71.660858 70333 28.482635 -34.517319 70.843506 70334 22.431862 -34.589493 70.942017 70335 22.462845 -33.828873 72.017899 70336 23.497322 -34.678360 71.830994 70337 29.027588 -33.219193 70.855621 70338 1.164070 -35.285446 69.946991 70339 1.169861 -36.371475 69.283722 70340 24.347618 -36.139542 71.111267 70341 31.677965 -37.842361 70.744995 70342 10.506363 -35.113327 73.276718 70343 12.314941 -33.839294 73.307632 70344 10.820114 -34.117416 74.897476 70345 15.144875 -37.789719 70.882172 70346 15.992279 -37.813950 70.470093 70347 27.757149 -36.165009 70.769714 70348 28.421677 -36.108475 71.870056 70349 26.875763 -37.068237 71.191727 70350 4.769081 -38.513504 71.197998 70351 4.380608 -38.127777 70.540466 70352 7.257523 -38.168976 70.992035 70353 25.519714 -37.336243 70.740448 70354 15.081551 -40.927963 71.378342 70355 14.751968 -39.230957 71.311035 70356 20.547943 -40.405853 70.373596 70357 7.198906 -43.342850 71.967438 70358 8.917739 -42.520340 72.202820 70359 10.511353 -43.686478 71.356720 70360 9.991348 -45.146667 71.282944 70361 9.924202 -44.556625 70.100098 70362 15.406158 -42.774948 70.867126 70363 15.510391 -42.079163 72.129700 70364 1.226082 -42.486740 71.254562 70365 15.319977 -44.208435 70.486908 70366 29.932831 -41.881027 72.134857 70367 30.313866 -41.071136 72.047272 70368 14.715729 -46.135971 69.948181 70369 19.419212 -47.213913 69.609909 70370 5.137695 -48.069550 69.420288 70371 5.588890 -47.951874 70.383575 70372 13.865463 -47.995010 69.947327 70373 17.229950 -49.981384 70.137146 70374 18.635895 -48.513885 70.625961 70375 18.297150 -49.765594 71.905029 70376 22.405159 -48.271851 70.782166 70377 13.389114 -49.072937 69.888397 70378 12.810699 -50.441269 70.225647 70379 24.159058 -50.052444 71.928345 70380 23.890358 -49.397980 70.865265 70381 25.441483 -50.833649 70.662323 70382 26.804832 -51.998535 69.725311 70383 3.690468 -53.898315 68.774216 70384 6.564262 -52.659348 69.929779 70385 5.012764 -53.036758 69.274490 70386 7.480820 -52.905365 71.346237 70387 5.948403 -51.959076 71.356812 70388 15.479599 -52.624084 69.634003 70389 26.694519 -52.449341 70.096008 70390 26.400116 -51.780640 70.291397 70391 3.809807 -52.975708 68.966675 70392 3.028412 -54.914551 68.584122 70393 3.832901 -52.149551 69.463821 70394 8.139465 -53.227097 70.270813 70395 4.833725 -54.735031 68.866058 70396 11.131897 -53.534836 69.206039 70397 12.027206 -52.054123 70.358246 70398 26.662735 -52.976425 69.715988 70399 3.857811 -54.659180 68.900238 70400 3.886215 -55.223160 68.994156 70401 4.603630 -56.108078 68.955780 70402 9.465729 -53.813095 69.438217 70403 14.352600 -54.673065 69.304001 70404 3.168015 -55.982758 68.717560 70405 3.432472 -57.066025 68.797440 70406 2.699478 -57.823181 68.106873 70407 3.476608 -58.052658 68.551483 70408 5.523430 -56.982361 68.695679 70409 6.349968 -57.623535 68.357452 70410 23.056343 -55.094116 70.734283 70411 21.830452 -54.697357 71.535019 70412 22.977921 -53.101791 72.440567 70413 5.056259 -58.243637 68.515076 70414 4.097488 -58.192276 68.680649 70415 4.071510 -57.716919 68.862427 70416 4.564262 -57.151352 68.935211 70417 4.052506 -58.743378 68.362091 70418 18.481361 -59.035339 69.245590 70419 22.276978 -58.240067 69.644928 70420 19.673645 -59.221512 69.072662 70421 11.491989 -60.022598 70.133408 70422 20.597137 -59.493057 69.085052 70423 12.369263 -61.059143 70.004944 70424 12.685303 -61.441681 69.601166 70425 6.631050 6.415634 74.072632 70426 9.378723 6.093079 73.732071 70427 6.004891 2.920067 73.612839 70428 6.231354 5.190704 73.742325 70429 7.958175 5.881363 74.131424 70430 10.354439 5.132462 73.762604 70431 11.180969 4.975632 73.459747 70432 9.283813 5.134247 74.129166 70433 11.217911 4.263351 73.751526 70434 6.136231 3.828903 73.695343 70435 10.138184 4.235153 74.180328 70436 12.227303 3.423355 73.513748 70437 11.132919 3.451416 74.141998 70438 13.776093 1.013397 74.282257 70439 13.244598 2.117859 73.765060 70440 7.919570 2.316284 74.585251 70441 7.953216 1.005478 74.563263 70442 7.687232 0.217163 74.480789 70443 15.267616 0.535934 73.369034 70444 15.755112 0.038696 73.392792 70445 14.494919 0.090820 74.263702 70446 15.162903 0.197784 73.788895 70447 15.966850 -1.572311 74.434723 70448 15.554962 -0.521057 73.988342 70449 7.714073 -1.660797 74.280060 70450 5.737106 -5.018707 73.726715 70451 6.611374 -4.394043 74.276169 70452 7.836059 -0.699448 74.439178 70453 20.677948 -5.546616 73.765396 70454 3.296249 -5.181366 72.715042 70455 3.270210 -5.585052 72.884872 70456 3.094421 -6.382309 72.847992 70457 3.242752 -7.600266 73.024506 70458 13.082656 -7.568268 73.796768 70459 14.526047 -7.206818 74.306702 70460 16.819031 -7.289780 74.921616 70461 17.132462 -8.238937 74.444214 70462 16.367897 -8.319321 73.718674 70463 15.540443 -7.431198 74.226654 70464 3.531632 -8.684982 72.816132 70465 7.873916 -8.970901 73.100342 70466 8.691681 -8.328842 73.896484 70467 10.967484 -7.931137 73.557037 70468 16.815163 -9.069504 73.325104 70469 16.860176 -9.678635 73.342010 70470 17.268944 -9.491898 73.840973 70471 4.828240 -8.282471 73.800400 70472 16.171463 -10.281601 73.137100 70473 17.024048 -10.286407 74.281342 70474 15.609665 -10.822327 73.164108 70475 15.222610 -11.041931 73.123474 70476 22.221268 -11.316299 73.477554 70477 12.184357 -11.657379 73.787170 70478 13.192673 -11.441635 73.783661 70479 22.334061 -12.243668 72.995026 70480 9.723679 -12.331253 73.980103 70481 21.157745 -12.827286 74.417023 70482 18.204163 -15.382858 72.901764 70483 18.026260 -15.466019 73.621338 70484 24.012985 -16.039673 74.022568 70485 25.367653 -15.960251 73.915070 70486 2.171433 -16.733597 72.644135 70487 4.093964 -15.625671 73.973602 70488 3.227997 -16.004852 73.448639 70489 16.986511 -16.785385 73.787354 70490 17.465355 -15.873245 73.924973 70491 17.384445 -16.121017 72.846619 70492 26.702759 -15.987885 73.627808 70493 21.900833 -16.826172 72.903778 70494 17.001160 -16.983521 72.842041 70495 20.104530 -17.659439 72.813110 70496 18.306946 -17.865036 73.670563 70497 0.753098 -18.430954 72.876434 70498 27.201370 -20.777100 74.781204 70499 26.548111 -20.165375 75.523254 70500 27.101059 -19.121475 75.020645 70501 0.595818 -21.934433 72.973984 70502 0.493675 -21.713379 72.236603 70503 13.321732 -23.027054 73.367447 70504 11.853516 -25.049210 73.261612 70505 11.786278 -22.420898 72.899963 70506 11.799431 -21.982681 74.136703 70507 25.375183 -25.924896 72.562225 70508 11.077354 -23.823303 73.086731 70509 10.910110 -22.818237 73.044586 70510 14.580978 -23.734772 73.246643 70511 15.591072 -24.470154 73.159821 70512 13.782768 -25.535599 72.325027 70513 12.737679 -25.705490 73.193817 70514 13.489494 -26.537521 73.429108 70515 14.710014 -25.498718 72.037781 70516 15.126465 -24.964447 72.120819 70517 15.271477 -25.662247 72.213531 70518 15.986801 -25.648132 72.680328 70519 16.852272 -25.195312 73.583878 70520 14.703583 -26.074478 72.572723 70521 15.416580 -25.971664 72.483154 70522 23.966484 -27.444672 73.374390 70523 23.908005 -27.190155 74.206070 70524 24.437958 -26.840195 74.231796 70525 0.874557 -29.352280 71.757660 70526 0.932449 -27.907440 72.538452 70527 1.350044 -28.990250 73.324081 70528 17.827232 -28.466080 72.845367 70529 16.582664 -29.250092 72.244720 70530 16.525681 -28.062775 72.981232 70531 19.281174 -28.143967 73.415131 70532 2.409905 -37.974503 70.712708 70533 1.439659 -38.792618 70.032333 70534 1.300919 -30.414566 72.513794 70535 0.963623 -31.474487 71.165192 70536 15.578194 -29.771057 71.835739 70537 20.007004 -29.386429 71.914246 70538 10.175385 -31.647354 71.500763 70539 1.189728 -32.652252 71.238007 70540 8.460327 -32.871964 72.123199 70541 8.529053 -31.674805 74.658585 70542 9.088882 -31.631744 73.846100 70543 8.135667 -32.358200 74.026413 70544 13.586548 -33.528687 72.044586 70545 16.575264 -32.631287 72.457153 70546 15.094559 -32.845413 72.537994 70547 17.611511 -32.785934 71.880676 70548 19.303734 -32.432693 72.711868 70549 18.554161 -32.301956 72.820251 70550 21.478012 -33.512466 71.808746 70551 29.703339 -33.882645 71.039062 70552 30.290482 -34.452621 71.048615 70553 21.861145 -32.963364 72.952774 70554 23.264832 -33.683121 72.874390 70555 29.735245 -35.154831 71.510193 70556 7.310547 -33.078415 73.823593 70557 30.473816 -36.644745 71.944672 70558 29.570129 -35.958267 72.049347 70559 3.775055 -37.751678 70.847000 70560 3.747276 -36.437897 71.605133 70561 5.340401 -36.284531 70.986603 70562 5.460007 -35.767899 71.701599 70563 5.185410 -35.123276 72.610626 70564 25.912323 -36.063217 72.810822 70565 24.646988 -34.857819 72.832382 70566 14.789223 -38.050980 71.322021 70567 15.031738 -37.552094 71.488525 70568 15.637436 -37.397415 71.464874 70569 16.477692 -37.466614 71.188766 70570 27.068520 -36.676834 72.433716 70571 27.033752 -36.497192 73.628815 70572 31.261078 -37.835693 71.712738 70573 30.875656 -38.086563 72.305161 70574 29.312096 -36.456512 72.447723 70575 29.405182 -37.161377 72.999603 70576 28.218201 -36.704269 72.985535 70577 1.981667 -37.006912 70.632507 70578 3.522064 -38.464172 70.957336 70579 19.108276 -39.069397 71.298401 70580 31.640810 -38.123093 71.187363 70581 2.414650 -39.096329 70.863907 70582 2.324440 -40.847916 72.800797 70583 2.456230 -39.983688 71.784119 70584 3.524757 -39.024017 71.923203 70585 7.114777 -38.130814 71.851395 70586 20.356277 -39.771973 71.445312 70587 30.417656 -38.984268 72.733032 70588 21.427887 -40.411301 71.394241 70589 22.456482 -40.903946 71.395569 70590 5.121384 -44.037125 72.449890 70591 5.723549 -43.853195 70.715530 70592 10.647499 -44.044724 72.072571 70593 23.418564 -41.366333 71.442627 70594 1.289803 -43.169235 71.108597 70595 26.113556 -42.448547 71.651321 70596 29.855774 -43.559036 70.601166 70597 1.828781 -43.629211 70.933548 70598 15.286713 -45.537659 71.866821 70599 27.237701 -42.286804 72.005890 70600 29.159004 -41.519379 72.471405 70601 29.672699 -42.572540 71.655441 70602 29.909218 -43.096252 71.017548 70603 15.704910 -44.049850 71.771133 70604 8.042694 -46.911926 70.657074 70605 14.880669 -46.202805 70.719727 70606 9.249916 -46.147064 71.712738 70607 19.546692 -47.601959 70.299927 70608 8.508377 -46.709000 71.852539 70609 14.169273 -47.767136 70.767273 70610 14.490250 -47.268951 71.606232 70611 19.743927 -48.334824 71.533630 70612 21.366104 -48.709610 72.229309 70613 22.885223 -48.837677 71.780670 70614 22.739235 -49.514465 72.770386 70615 3.460968 -49.349899 70.012085 70616 4.089485 -49.119232 70.834900 70617 13.752991 -48.639282 71.300140 70618 4.779045 -51.028381 71.440811 70619 4.013832 -49.999313 71.002701 70620 4.732864 -50.072205 72.328308 70621 13.202431 -49.655899 71.125107 70622 4.798607 -51.823151 70.360733 70623 3.853363 -51.077103 70.256012 70624 5.554459 -52.207748 70.241196 70625 11.748901 -52.332932 71.528839 70626 10.702789 -53.396332 70.368134 70627 15.367889 -53.098190 70.772919 70628 14.415161 -54.519730 70.497406 70629 9.451294 -53.727341 70.611481 70630 12.039932 -52.003311 73.640930 70631 11.491287 -52.377304 74.264191 70632 12.034309 -51.435379 74.701111 70633 24.486435 -54.341492 70.762390 70634 25.336128 -53.148376 71.043228 70635 13.926605 -54.975174 71.642059 70636 24.291153 -54.945312 70.240326 70637 21.940567 -56.309204 70.563065 70638 21.944427 -55.599976 70.815872 70639 21.614006 -57.576691 70.296387 70640 21.553360 -58.452484 69.968018 70641 12.562912 -60.448593 70.719254 70642 15.743790 -60.320648 69.924133 70643 17.057678 -59.666809 69.794922 70644 20.721581 -57.607529 70.765457 70645 20.365425 -58.586975 70.143341 70646 19.940735 -57.489380 71.245209 70647 21.591576 -59.003403 69.508148 70648 18.417747 -58.672363 70.993927 70649 13.274620 -60.205200 71.220703 70650 12.601944 -58.855545 71.725128 70651 14.289215 -60.278641 71.143646 70652 11.378082 -58.345490 70.646362 70653 6.821861 6.920715 74.134384 70654 7.292244 6.785461 74.109375 70655 8.219865 4.132599 74.343719 70656 6.983688 3.044693 74.151688 70657 10.073402 3.182220 74.535599 70658 8.882133 3.000580 74.780396 70659 11.644699 2.159882 74.477417 70660 9.751488 1.712616 74.936554 70661 12.921417 1.328522 74.510590 70662 8.160553 0.114105 74.846619 70663 13.402634 0.091400 74.869720 70664 14.622063 -0.940933 74.752060 70665 8.636314 -2.948990 75.865082 70666 9.064697 -1.699814 75.776779 70667 9.448257 -2.748260 76.217865 70668 15.916351 -2.646454 75.309174 70669 6.108467 -5.285538 74.242584 70670 21.334167 -6.761841 74.125946 70671 5.592056 -5.900116 74.101212 70672 3.929993 -6.752716 73.599609 70673 4.848534 -6.554977 73.991592 70674 20.422302 -6.397568 74.718109 70675 19.892220 -5.439453 74.509293 70676 3.832619 -7.471039 73.694199 70677 4.494583 -7.442902 73.984009 70678 20.707504 -7.645142 74.873886 70679 21.717377 -7.977829 74.228500 70680 3.998253 -8.109558 73.550385 70681 9.779587 -7.966660 74.136520 70682 12.811508 -6.788330 75.285583 70683 13.895935 -6.571289 75.229401 70684 7.418808 -8.207870 74.114899 70685 15.254082 -6.381363 75.391769 70686 17.274719 -8.863495 74.136505 70687 13.928268 -11.094910 75.080536 70688 15.572076 -10.880859 74.222290 70689 21.230179 -10.339615 74.590652 70690 10.734322 -11.715576 75.869629 70691 9.871735 -12.017426 76.782349 70692 9.285721 -12.150543 75.801285 70693 11.244698 -11.697601 74.655930 70694 21.874718 -12.126877 73.930450 70695 20.972298 -11.552673 74.840942 70696 8.616669 -12.650192 74.861313 70697 9.856766 -12.065399 75.015106 70698 5.196884 -14.980148 74.206879 70699 6.380196 -14.183807 74.094482 70700 7.240471 -13.460327 74.743042 70701 6.408005 -13.868973 74.957825 70702 19.673820 -13.937042 74.881760 70703 18.172127 -15.278519 74.522141 70704 1.403763 -17.241302 73.565964 70705 2.351608 -16.517868 73.686340 70706 4.484459 -15.906143 75.574097 70707 3.187904 -16.155502 74.429642 70708 22.688301 -16.547379 74.121902 70709 25.131279 -17.286621 75.486496 70710 23.971970 -16.543686 75.004181 70711 0.729576 -18.067001 73.727356 70712 1.120949 -17.690964 74.280380 70713 0.808281 -18.466599 74.380920 70714 22.103218 -17.209610 75.793320 70715 21.271057 -17.005310 74.906937 70716 29.135780 -18.459244 72.916977 70717 19.417999 -17.634888 73.708435 70718 20.920639 -17.187500 73.701019 70719 19.885971 -17.386200 74.914627 70720 28.566261 -18.276535 73.435120 70721 0.469276 -19.756943 73.548080 70722 17.465614 -17.560776 74.563995 70723 28.555557 -20.006012 73.230606 70724 27.898956 -21.052841 73.485992 70725 0.629845 -20.864807 73.955170 70726 11.472137 -21.922867 73.548172 70727 10.791634 -21.978409 73.863144 70728 27.262604 -21.749527 73.607086 70729 10.167046 -23.005447 74.111862 70730 16.495178 -26.733322 72.971054 70731 16.971924 -25.989395 73.076279 70732 26.829079 -22.050995 74.428345 70733 17.754837 -26.182663 73.689331 70734 17.811859 -24.986755 75.220657 70735 16.309868 -24.502640 74.350632 70736 16.029785 -24.203842 75.867157 70737 25.730499 -25.447769 73.314758 70738 25.820122 -24.736343 73.895554 70739 1.806183 -24.737885 75.528473 70740 1.952591 -26.188324 75.772446 70741 14.630905 -26.885620 73.289993 70742 15.491043 -26.393311 72.871124 70743 17.226883 -26.549088 73.138123 70744 25.035233 -26.473358 73.426682 70745 25.520531 -25.908844 73.344223 70746 15.530457 -27.348831 73.174911 70747 18.453590 -27.346939 73.622772 70748 17.400421 -27.285950 73.219635 70749 20.555153 -28.481659 73.165604 70750 20.134041 -27.537491 74.128265 70751 22.103333 -28.330719 73.143707 70752 11.942940 -30.250977 72.875977 70753 10.327591 -31.137344 72.917160 70754 11.307259 -29.823822 73.992889 70755 12.848427 -29.862961 72.892944 70756 13.724701 -29.519989 72.892914 70757 15.192031 -28.797134 72.877182 70758 13.981087 -28.556152 73.565186 70759 1.564629 -31.701126 72.597961 70760 9.102295 -30.543091 75.327454 70761 1.797569 -32.784729 72.544724 70762 17.682495 -32.242111 72.974579 70763 20.274857 -32.875458 72.348022 70764 21.022690 -32.303284 73.645264 70765 13.813583 -32.929703 73.402252 70766 12.985352 -33.026123 74.181274 70767 24.068069 -33.666763 74.114151 70768 1.648071 -34.142471 71.423157 70769 25.027512 -34.515228 73.943481 70770 2.066216 -35.806534 71.161041 70771 2.724335 -34.996323 72.327057 70772 3.761948 -34.565582 73.187866 70773 25.681366 -35.226028 73.848358 70774 15.034172 -37.845032 72.176575 70775 16.333511 -37.048981 72.374939 70776 25.966583 -36.808395 71.762848 70777 30.259918 -37.834061 72.790588 70778 6.302384 -38.340469 71.399780 70779 4.421845 -38.583847 72.845764 70780 6.887879 -37.926804 72.469940 70781 5.710617 -37.961136 73.023071 70782 2.835564 -40.229492 73.080170 70783 17.880402 -37.381699 72.510742 70784 19.742599 -38.632690 72.653809 70785 21.251625 -39.673325 72.503052 70786 1.968910 -42.302795 72.812988 70787 1.661652 -42.172760 72.246918 70788 2.026848 -41.653961 72.791443 70789 14.828049 -39.467209 72.516190 70790 22.303864 -40.362137 72.392532 70791 23.287903 -40.858124 72.346771 70792 30.115509 -40.197617 72.694855 70793 9.108353 -42.376648 73.103149 70794 7.986236 -42.898422 72.943695 70795 10.092438 -42.712006 71.846497 70796 10.636322 -43.059998 72.772125 70797 10.721642 -43.288452 72.013840 70798 15.270477 -40.905304 72.972687 70799 24.352013 -41.474960 72.168243 70800 25.171669 -41.709885 72.412201 70801 25.981346 -41.641449 72.726151 70802 28.039413 -40.542160 73.618042 70803 2.062332 -43.117889 72.196960 70804 6.731201 -43.536270 72.988861 70805 10.647926 -43.943237 73.031586 70806 15.816429 -43.179398 72.249573 70807 10.123734 -45.115158 72.316559 70808 13.311021 -49.744583 72.211945 70809 13.916077 -48.634796 72.844208 70810 4.793732 -48.549088 71.269135 70811 6.062164 -47.913269 72.078949 70812 7.616920 -47.159866 72.413559 70813 4.504402 -49.229019 71.890442 70814 19.764214 -49.563202 72.818176 70815 12.691940 -50.731323 71.386810 70816 18.738625 -51.286758 73.457306 70817 24.543594 -51.192993 72.351929 70818 25.237328 -51.544388 71.553314 70819 5.716103 -51.099197 73.159119 70820 16.070015 -52.966248 73.349426 70821 15.120514 -53.949188 72.637482 70822 24.771362 -52.347382 72.021881 70823 26.102875 -52.378860 70.614044 70824 8.607483 -53.467178 71.207977 70825 10.415428 -53.567291 71.232849 70826 9.518859 -53.767410 71.588806 70827 21.120369 -54.028305 72.509521 70828 20.078354 -55.843140 72.014374 70829 19.601440 -54.249786 73.160568 70830 21.930107 -55.218628 70.994736 70831 14.103851 -55.102875 72.660416 70832 13.464386 -55.547897 72.074142 70833 13.351883 -55.516998 71.442200 70834 21.410919 -55.651978 71.056473 70835 11.543083 -57.515427 70.688263 70836 11.249985 -57.851257 70.525360 70837 12.914711 -56.116714 71.531860 70838 20.880951 -56.592926 71.064804 70839 20.940567 -55.394852 71.590973 70840 13.451340 -56.480789 72.666489 70841 12.229408 -57.267242 71.430023 70842 17.974182 -57.762970 72.344955 70843 19.100037 -57.194397 71.998566 70844 15.557327 -59.994965 71.016418 70845 16.726181 -58.860397 71.938736 70846 16.765823 -59.644501 70.778839 70847 7.954795 3.179474 74.644211 70848 10.294426 0.065887 75.449982 70849 9.094070 0.331818 75.156387 70850 11.308945 0.672943 75.173340 70851 12.322311 0.863312 74.932404 70852 8.617477 -0.694855 75.205078 70853 12.317200 -0.369202 75.365341 70854 9.505234 -0.661530 75.598099 70855 10.414474 -1.641800 76.003128 70856 11.299507 -0.546204 75.646423 70857 8.135192 -1.959549 75.127960 70858 13.566910 -1.830780 75.626678 70859 14.878265 -2.608963 75.775818 70860 14.417152 -3.475021 76.202560 70861 11.955125 -1.648209 75.904999 70862 15.008179 -1.909271 75.240128 70863 13.353600 -3.628418 76.309464 70864 12.509399 -2.757568 76.157516 70865 7.053337 -5.211639 75.194199 70866 6.363121 -5.753799 74.673813 70867 5.962372 -7.453735 74.218460 70868 6.988907 -6.443451 75.128265 70869 7.042397 -7.374191 74.822662 70870 19.658020 -7.030670 75.278824 70871 18.800430 -6.318344 75.370850 70872 19.587982 -6.082611 75.039734 70873 11.655724 -6.908997 75.192947 70874 12.366867 -6.319458 75.915497 70875 18.078354 -8.474167 74.916763 70876 18.382423 -7.238281 75.348236 70877 21.091118 -9.051300 74.646423 70878 19.598427 -8.234680 75.236130 70879 7.965354 -7.216232 75.068008 70880 9.198730 -7.394791 75.063644 70881 10.293182 -7.167618 75.065811 70882 19.473160 -10.092911 75.263870 70883 17.897820 -9.680511 74.634430 70884 12.618042 -11.295929 74.668182 70885 18.035324 -10.698013 75.369583 70886 15.401169 -11.320969 76.471054 70887 18.658844 -11.850433 76.159409 70888 17.912598 -11.309982 76.011063 70889 12.316284 -11.250198 75.867569 70890 20.487267 -12.720749 75.194794 70891 19.928505 -12.017242 75.597687 70892 17.613815 -15.325516 75.995285 70893 18.437332 -13.503387 76.413025 70894 5.963944 -14.293991 75.323547 70895 5.511566 -14.981140 75.841782 70896 16.688248 -16.708344 76.678329 70897 16.372635 -15.586548 77.655899 70898 17.219696 -16.126877 74.754395 70899 26.524933 -16.655457 74.379517 70900 2.001885 -17.092209 74.637497 70901 16.879501 -16.899841 74.668610 70902 0.546661 -18.888229 73.892914 70903 16.988556 -16.945862 75.569351 70904 17.403152 -17.653549 75.624130 70905 18.608032 -17.635513 74.525269 70906 19.661339 -17.583954 76.020676 70907 19.912125 -18.110718 76.916458 70908 18.910522 -18.077927 76.851517 70909 18.375580 -17.678299 75.713043 70910 20.814529 -17.602402 76.150726 70911 27.171806 -17.611923 74.538742 70912 28.014923 -18.539032 74.010483 70913 26.316734 -17.284836 75.073578 70914 17.197601 -17.790375 76.772247 70915 27.778000 -20.286942 74.163696 70916 1.119179 -22.129120 74.788635 70917 1.307747 -20.746429 75.691452 70918 1.729195 -21.667786 76.213257 70919 9.793564 -21.983719 74.505829 70920 10.186348 -21.559204 74.534592 70921 10.696121 -21.337631 75.104187 70922 12.936142 -22.718369 74.980865 70923 14.753326 -23.803268 74.294952 70924 26.119720 -22.676254 75.080048 70925 25.885567 -23.901688 74.674820 70926 10.580841 -24.568405 74.689011 70927 18.963104 -26.310455 74.557007 70928 11.687469 -26.616592 74.652588 70929 25.466133 -25.670837 73.978714 70930 24.964447 -26.157852 74.402878 70931 1.543129 -27.667572 74.439087 70932 13.841644 -27.625946 73.779083 70933 14.658310 -27.794144 73.434479 70934 19.394394 -27.273132 74.064697 70935 19.971695 -26.681961 74.721497 70936 23.081451 -27.988449 73.255157 70937 23.073776 -27.086029 74.525528 70938 1.920563 -28.911194 74.506989 70939 1.869698 -29.790619 73.891449 70940 12.754784 -29.127258 73.677017 70941 21.151810 -26.826263 74.852600 70942 23.196724 -25.529968 75.902863 70943 24.163712 -26.148239 75.147171 70944 2.588081 -33.586563 73.108231 70945 11.920647 -28.447311 74.498108 70946 10.180412 -30.095306 74.714386 70947 11.008873 -28.557266 75.140488 70948 13.401138 -28.310120 73.929047 70949 2.115631 -30.861374 73.907013 70950 15.926071 -32.092590 73.732727 70951 14.811516 -32.252762 73.910583 70952 18.452667 -31.814072 73.916992 70953 17.270782 -31.805191 74.028015 70954 19.746140 -31.988815 73.816101 70955 22.927094 -32.845901 73.891968 70956 22.038544 -32.326736 74.183685 70957 23.234497 -32.787689 74.746048 70958 22.718147 -32.417206 74.578690 70959 6.112457 -34.368881 73.054672 70960 5.007027 -34.025818 73.804382 70961 2.446495 -32.154663 73.729950 70962 3.582802 -32.882233 74.384018 70963 26.313522 -35.838409 73.756195 70964 5.218163 -31.400192 76.400375 70965 6.150459 -31.813660 76.029037 70966 5.002022 -32.492081 75.277237 70967 15.390366 -37.027435 73.364670 70968 16.039467 -36.508102 73.435104 70969 16.887161 -36.488235 73.463470 70970 26.264496 -35.953537 74.616257 70971 7.234345 -37.223694 73.340118 70972 9.398361 -35.810638 73.395752 70973 8.437531 -36.239410 73.749176 70974 7.175888 -36.359924 74.981079 70975 17.554390 -36.535492 73.478943 70976 5.331978 -37.654495 74.423828 70977 6.246155 -37.121155 74.353409 70978 29.368393 -38.144714 73.388306 70979 3.805885 -38.992020 73.095779 70980 3.280464 -39.543610 72.948822 70981 28.197769 -37.256195 73.752563 70982 29.131386 -39.517319 73.438019 70983 14.839539 -38.101868 73.306244 70984 21.153549 -38.438110 74.131271 70985 22.105331 -39.700729 73.313599 70986 14.989960 -39.318069 74.145859 70987 23.132797 -40.149796 73.487091 70988 24.046265 -40.775330 73.145721 70989 27.834732 -39.459595 74.288086 70990 8.041656 -42.372208 76.007904 70991 6.773392 -43.050873 75.069672 70992 6.530609 -42.757828 76.281143 70993 9.869003 -42.400513 72.798767 70994 15.847397 -42.437439 73.293930 70995 15.730148 -41.189224 74.512909 70996 24.981995 -41.072617 73.225983 70997 25.772270 -39.996414 74.379303 70998 27.058578 -40.367737 73.932190 70999 16.198380 -42.921036 74.904831 71000 3.237801 -44.000336 71.402588 71001 3.302208 -43.908493 72.614548 71002 8.370316 -42.463226 74.721268 71003 10.536377 -43.345505 74.018875 71004 10.290145 -43.594589 74.866318 71005 10.067673 -44.804718 73.634705 71006 10.674759 -43.142822 73.498566 71007 4.069214 -43.865143 73.569412 71008 8.994949 -46.219055 72.738373 71009 15.904099 -44.361130 73.465057 71010 15.382614 -46.048447 73.790283 71011 5.681900 -48.518616 73.511826 71012 6.599625 -47.717468 73.359314 71013 6.676315 -47.827789 74.914978 71014 21.893456 -50.055069 73.348328 71015 20.772995 -50.292542 73.343994 71016 5.075752 -48.650879 72.384979 71017 22.688293 -50.184952 73.373566 71018 12.701958 -50.934219 72.488007 71019 12.626373 -51.038742 73.640976 71020 13.324799 -49.861572 73.499817 71021 16.601135 -52.297211 73.354370 71022 17.250580 -51.380005 72.825989 71023 5.197968 -49.939468 73.334534 71024 11.979256 -52.110901 72.746368 71025 24.034760 -51.918533 72.649612 71026 5.935211 -50.866669 74.185684 71027 6.299484 -51.304703 74.326294 71028 7.184876 -52.490631 72.949783 71029 7.474045 -52.307632 74.245926 71030 8.341301 -52.949020 73.874313 71031 6.724602 -51.836929 74.031937 71032 8.662918 -53.409164 72.405319 71033 21.733047 -52.599396 73.128082 71034 24.137711 -52.722794 72.262268 71035 24.217186 -53.506165 71.638229 71036 10.558998 -53.388931 72.328339 71037 9.558731 -53.765915 72.247864 71038 14.591728 -55.182922 73.391968 71039 19.221199 -55.919617 72.598450 71040 17.686295 -56.663895 73.259354 71041 18.576584 -56.750336 72.686905 71042 15.081680 -59.243347 72.211365 71043 15.085190 -58.426407 73.037872 71044 15.851234 -58.157471 72.972565 71045 13.758972 -59.159515 72.330124 71046 11.392456 -3.354050 76.320770 71047 7.771881 -3.859085 75.362549 71048 10.178024 -3.409256 76.353485 71049 12.422134 -4.154114 76.394485 71050 15.384048 -3.372238 75.950119 71051 15.349228 -4.506149 76.201859 71052 16.404892 -5.085327 75.837936 71053 7.954391 -5.662643 75.667633 71054 9.024139 -4.525894 76.141174 71055 15.663719 -5.496826 75.982422 71056 15.121094 -5.389465 76.134537 71057 17.503357 -5.995667 75.463486 71058 13.184464 -5.954727 76.011368 71059 14.222092 -5.140015 76.164459 71060 16.295288 -6.101685 75.600922 71061 8.653320 -6.571655 75.718933 71062 11.764465 -5.453003 76.189285 71063 10.527589 -5.440552 76.063675 71064 9.425575 -6.260803 75.884308 71065 16.944817 -11.033844 75.736084 71066 10.278137 -12.094498 77.602188 71067 11.348541 -11.720047 77.153870 71068 17.647598 -11.621506 76.490341 71069 8.530197 -12.488068 75.744308 71070 7.846969 -12.922928 75.734314 71071 20.035751 -12.960663 75.528778 71072 6.800835 -13.648254 75.925217 71073 19.472099 -12.915955 75.872482 71074 3.113632 -16.732162 75.429779 71075 17.317032 -14.046280 77.293411 71076 23.072929 -16.924911 75.589371 71077 23.807465 -17.210785 75.919418 71078 26.202713 -18.006012 75.436417 71079 1.343559 -18.412857 75.223312 71080 0.828972 -19.602112 74.737244 71081 24.752182 -19.660995 76.593216 71082 24.827217 -18.494385 76.227798 71083 25.806717 -19.090042 75.922318 71084 11.157486 -21.341873 76.180450 71085 12.011856 -22.137939 76.150330 71086 11.685059 -21.774078 75.311340 71087 26.635406 -21.276794 75.303162 71088 26.277664 -20.840256 75.762680 71089 9.470322 -20.534012 76.334625 71090 9.816406 -20.912811 75.688019 71091 8.822464 -21.380264 76.028229 71092 9.718170 -21.378281 75.070755 71093 9.218628 -21.832672 75.112900 71094 25.792694 -21.609192 75.885452 71095 8.982544 -22.686600 75.742493 71096 8.958534 -22.078674 75.427353 71097 9.371979 -22.539902 74.981247 71098 25.484253 -23.716263 75.495544 71099 9.652161 -23.416489 75.090439 71100 24.876144 -22.925156 76.162354 71101 9.346924 -23.848846 76.014740 71102 25.211517 -25.037750 75.000610 71103 19.802223 -25.415390 75.768784 71104 12.852783 -27.770889 74.115799 71105 23.927750 -26.922714 74.615891 71106 24.456650 -25.108688 75.703232 71107 2.366387 -28.352188 75.641846 71108 10.430412 -28.737747 75.687485 71109 2.891838 -31.420181 74.739990 71110 2.580185 -29.963379 75.040848 71111 8.071228 -31.915710 74.923309 71112 16.359848 -31.426910 75.000153 71113 17.345291 -31.204483 75.694992 71114 19.236023 -31.457626 75.182083 71115 18.187355 -31.397293 75.075348 71116 20.265030 -31.537903 75.155945 71117 21.127373 -31.884262 74.804565 71118 21.341164 -31.959152 75.802887 71119 20.824051 -31.579041 75.606018 71120 13.940765 -32.228867 74.697464 71121 14.707428 -31.931580 74.626633 71122 15.373795 -31.742355 74.694122 71123 22.311050 -32.416046 75.271164 71124 7.413620 -31.889343 75.338623 71125 12.131691 -33.427963 74.591888 71126 12.808746 -32.606293 75.510315 71127 23.568710 -33.657867 75.629349 71128 25.092667 -34.803253 75.053772 71129 24.411194 -34.726288 75.955963 71130 6.392059 -32.751251 74.926956 71131 6.182465 -33.581680 74.010651 71132 25.885010 -36.979889 75.418869 71133 25.649216 -35.912659 75.416931 71134 9.244446 -34.814117 75.692032 71135 10.034393 -33.771255 77.007416 71136 9.379364 -35.394348 74.345718 71137 18.101776 -36.520584 74.356262 71138 15.946213 -36.493286 74.462692 71139 27.101212 -37.100250 74.527618 71140 14.989044 -37.612289 74.316650 71141 4.710548 -38.208649 73.991562 71142 4.159485 -38.695801 73.793137 71143 3.777786 -39.288788 73.966629 71144 5.700272 -37.130844 75.354782 71145 14.998077 -38.283203 75.388992 71146 28.090546 -38.252823 74.211029 71147 3.337708 -40.057938 73.974655 71148 27.681396 -40.087906 74.198349 71149 2.960198 -41.142075 74.025711 71150 2.379479 -41.430313 73.359650 71151 22.418213 -39.325409 74.162598 71152 22.447205 -38.474274 75.068268 71153 24.329323 -39.986038 74.294296 71154 2.465027 -42.267151 73.405426 71155 9.864105 -42.503601 73.918884 71156 8.535004 -42.575867 73.721817 71157 9.470215 -42.375992 75.491257 71158 16.090469 -41.928146 76.283829 71159 2.932739 -43.293839 73.348358 71160 7.340378 -43.051880 73.882568 71161 5.177818 -43.199707 75.351074 71162 3.680245 -42.745346 74.552002 71163 4.530701 -42.176758 76.154831 71164 9.007126 -45.962631 73.876236 71165 14.725342 -47.244034 73.337128 71166 7.783523 -46.899368 73.681091 71167 8.205933 -46.308075 74.971710 71168 9.554779 -44.978058 74.743652 71169 13.951279 -48.734924 74.534744 71170 13.706123 -49.149902 75.447540 71171 13.990616 -48.580826 75.790741 71172 14.822670 -47.182938 75.763062 71173 4.980248 -49.236053 72.915390 71174 5.395630 -49.315353 73.844116 71175 23.563934 -50.713501 72.941711 71176 17.430206 -52.217499 73.865509 71177 22.463104 -51.956192 73.301361 71178 22.584900 -50.972229 73.453415 71179 23.220779 -51.705765 73.075912 71180 20.345131 -52.196152 73.442154 71181 11.270477 -52.811951 73.397186 71182 21.619568 -51.423599 73.468201 71183 9.625198 -53.648087 72.796722 71184 9.243050 -53.414642 73.375854 71185 18.543671 -53.907898 73.822220 71186 18.447319 -55.415771 73.336258 71187 13.848038 -57.868668 73.068344 71188 15.025497 -56.249390 73.804535 71189 16.900421 -57.539230 73.093933 71190 13.818451 -58.535248 72.972565 71191 15.043214 -57.491135 73.558212 71192 15.990936 -56.858521 73.776611 71193 13.154663 -4.930298 76.387970 71194 12.550201 -5.501648 76.309143 71195 8.731064 -5.839172 76.041473 71196 13.310265 -11.122086 76.550537 71197 12.579224 -11.333282 77.116821 71198 14.128517 -11.319336 76.860779 71199 14.418304 -12.330460 78.301834 71200 13.393402 -11.559311 77.669495 71201 16.718018 -11.627808 76.790512 71202 8.615143 -12.589996 76.561813 71203 16.116928 -12.193817 77.613724 71204 17.488998 -12.504166 77.090317 71205 15.680405 -13.019119 78.347702 71206 7.667037 -13.130814 76.600769 71207 6.429901 -14.512680 76.910995 71208 21.925339 -18.676224 77.098038 71209 20.618835 -18.967407 77.508347 71210 3.755402 -17.292282 76.423492 71211 5.344200 -17.206253 77.111069 71212 4.642456 -18.809631 77.280777 71213 2.444824 -17.902634 76.024567 71214 16.270844 -17.272095 77.606689 71215 18.116371 -17.960480 76.741837 71216 24.072556 -17.912689 76.268906 71217 23.069641 -17.900955 76.512207 71218 25.498314 -18.150742 75.878021 71219 1.373810 -19.588211 75.850708 71220 1.850861 -18.948105 76.240860 71221 23.876984 -18.875092 76.736557 71222 25.551414 -20.504395 76.186737 71223 9.524063 -19.554276 77.790787 71224 9.770065 -20.187897 76.967346 71225 8.531563 -20.097641 77.048325 71226 10.363937 -20.755798 76.313675 71227 8.372406 -22.597641 76.667953 71228 7.365830 -21.331421 77.266235 71229 24.462814 -21.487549 76.696884 71230 24.663742 -20.544586 76.720093 71231 1.912132 -22.423309 76.286057 71232 7.740051 -22.591614 77.258133 71233 1.811920 -23.344284 75.778488 71234 14.274628 -23.623993 75.433151 71235 9.179153 -24.732483 76.705200 71236 8.132271 -23.625839 77.193237 71237 9.946693 -24.724609 75.847031 71238 14.359970 -23.712982 76.262054 71239 14.679948 -23.748856 77.115982 71240 17.187027 -24.634933 75.808975 71241 24.817780 -24.183167 75.826294 71242 23.839890 -24.321411 76.267899 71243 17.424400 -24.395813 76.293365 71244 18.643509 -23.838547 77.156601 71245 22.141106 -25.746246 75.845718 71246 10.165909 -25.620621 75.940338 71247 20.210587 -24.089996 76.999252 71248 23.920242 -25.362915 75.836197 71249 2.625542 -27.031174 76.561035 71250 3.590538 -28.341248 76.959778 71251 3.110855 -29.511017 76.085373 71252 8.239456 -30.283020 76.410355 71253 9.259216 -28.788254 76.629562 71254 9.935715 -29.057541 75.882996 71255 8.252533 -31.355469 75.399918 71256 15.507973 -31.266113 75.814514 71257 14.835793 -31.288788 76.130692 71258 14.715225 -31.610916 75.316467 71259 16.376312 -30.967239 76.565414 71260 18.363449 -31.296509 76.824188 71261 20.214668 -31.850845 76.468414 71262 14.026489 -31.670044 76.101746 71263 3.664368 -31.098358 75.692963 71264 11.787621 -33.192551 75.498795 71265 11.203232 -33.209885 76.230591 71266 16.604858 -35.848068 75.379440 71267 17.327423 -35.504456 75.548737 71268 24.857346 -35.932495 75.913910 71269 8.267120 -35.633606 75.235779 71270 6.354126 -36.703613 75.249664 71271 26.724457 -38.572845 74.844208 71272 4.754524 -38.035797 74.873993 71273 4.260574 -38.736435 74.855957 71274 5.085060 -37.681183 75.358978 71275 15.152237 -37.185745 75.278061 71276 3.946167 -40.943176 75.752960 71277 3.794556 -39.839508 74.999252 71278 4.367203 -39.256470 76.236649 71279 15.390839 -38.251175 76.734222 71280 15.248627 -37.427689 76.141037 71281 22.299774 -37.187515 75.808365 71282 23.249161 -39.213287 74.719345 71283 25.643158 -38.165268 75.507401 71284 25.858780 -38.937408 75.202728 71285 3.442780 -40.496933 74.731354 71286 15.456223 -40.017975 75.220840 71287 15.140701 -39.202652 75.175476 71288 25.027977 -38.945129 75.266907 71289 15.813293 -40.842133 75.485275 71290 15.782692 -40.338547 76.401550 71291 10.237350 -42.721558 74.814209 71292 5.642891 -43.748795 73.927231 71293 4.558556 -43.687057 74.369263 71294 15.738625 -45.646759 74.846313 71295 16.126396 -44.362061 75.747070 71296 9.096756 -44.862625 75.832993 71297 8.185455 -45.850723 76.238312 71298 6.045448 -49.057907 74.835861 71299 5.774529 -50.136215 74.312347 71300 13.080475 -49.974213 75.143570 71301 19.871307 -50.652176 73.467560 71302 19.072151 -52.836136 73.708801 71303 18.163879 -52.770523 74.048553 71304 8.836365 -52.867020 74.712967 71305 9.319672 -53.176514 74.090485 71306 10.170586 -53.290649 73.540756 71307 9.869392 -52.878540 74.689804 71308 10.825859 -52.829132 74.277283 71309 16.859154 -52.944168 74.060333 71310 16.258034 -53.913712 73.934204 71311 17.515625 -53.758728 74.207352 71312 15.495026 -54.857376 73.820923 71313 17.941040 -54.642776 73.941895 71314 16.835968 -55.448044 73.941040 71315 16.889984 -56.637695 73.628998 71316 14.359238 -58.497406 72.997711 71317 15.317375 -56.780197 73.939087 71318 12.483086 -11.941437 78.289856 71319 10.881287 -12.790573 78.695999 71320 9.226624 -12.730301 77.735916 71321 7.282906 -13.726395 77.265747 71322 8.095947 -13.160553 77.329468 71323 16.672180 -14.225510 77.905960 71324 6.666809 -15.264740 77.821030 71325 6.593826 -15.926178 77.931046 71326 5.954277 -15.781876 77.149612 71327 15.838074 -14.218552 78.441437 71328 3.280052 -18.366730 76.789459 71329 15.485703 -16.753357 78.603043 71330 15.391006 -15.536621 78.723068 71331 17.870483 -18.595779 77.735107 71332 2.555023 -18.907455 76.701584 71333 16.539886 -17.948334 77.684052 71334 16.913231 -18.290573 77.938660 71335 23.013107 -19.075531 77.091187 71336 2.206917 -19.918045 76.739960 71337 2.216347 -20.965866 76.833267 71338 8.472473 -19.016815 77.855362 71339 10.282745 -20.122772 77.692490 71340 23.656403 -20.261856 77.104843 71341 1.994911 -27.220779 75.625381 71342 6.854912 -19.044846 77.564362 71343 10.447670 -20.585220 77.159424 71344 10.872658 -21.041397 76.977280 71345 11.503082 -21.651230 77.204178 71346 23.327599 -22.800171 76.856537 71347 22.883072 -21.445740 77.365417 71348 22.640594 -20.594635 77.565018 71349 13.183022 -23.064240 76.142990 71350 21.126846 -23.687637 77.180466 71351 21.846786 -22.568695 77.384689 71352 22.316910 -24.188110 76.660950 71353 12.478920 -22.540985 77.076752 71354 12.085800 -21.950531 77.986816 71355 12.911621 -22.598465 77.820435 71356 13.568832 -23.203812 77.082718 71357 15.583466 -23.733444 77.627197 71358 17.014236 -23.955856 77.187469 71359 16.547577 -23.429199 78.110687 71360 17.471695 -23.591415 77.861313 71361 21.125679 -25.034164 76.351776 71362 10.107391 -27.408737 76.262756 71363 8.952187 -25.800858 77.150909 71364 7.395165 -25.549957 78.072662 71365 8.131104 -24.722198 77.561340 71366 3.748467 -29.798431 76.567841 71367 4.433731 -30.643890 76.549850 71368 4.515785 -31.463470 76.036362 71369 6.916199 -30.552643 76.880539 71370 15.174805 -31.158096 77.428635 71371 5.994621 -31.078247 76.761093 71372 12.028205 -32.687958 76.366638 71373 12.992950 -31.931641 77.137192 71374 11.514221 -32.631958 77.280472 71375 22.676277 -35.007202 76.439697 71376 21.696503 -33.140274 76.396774 71377 23.778221 -34.556808 76.201920 71378 8.252884 -35.110153 76.469376 71379 8.981255 -34.578476 76.810287 71380 15.756172 -36.420898 76.061371 71381 16.044800 -35.994705 77.448746 71382 16.824219 -35.313614 76.485687 71383 16.660797 -34.660828 77.745300 71384 20.424438 -34.419968 76.852707 71385 19.454651 -33.122147 77.608170 71386 20.151398 -33.313263 77.446121 71387 18.450058 -35.134583 76.182693 71388 6.410454 -36.492966 76.579483 71389 7.406403 -35.708130 76.343292 71390 5.981224 -37.531006 78.295746 71391 5.205376 -37.796387 76.661133 71392 4.708046 -38.252533 75.660034 71393 21.493515 -35.826035 76.362427 71394 20.417831 -36.340790 75.705658 71395 23.425484 -36.519257 76.334595 71396 23.276962 -37.377655 76.032761 71397 24.365463 -37.458008 75.871506 71398 24.148880 -36.320480 76.315353 71399 23.945946 -35.442917 76.369034 71400 15.575142 -37.219727 77.109222 71401 23.160812 -38.116867 75.589371 71402 22.583618 -37.984344 75.577896 71403 24.033646 -38.814224 75.282166 71404 15.394119 -39.223007 76.052322 71405 4.455879 -40.157288 77.140442 71406 15.597610 -40.797150 78.211319 71407 15.681274 -39.353348 77.546951 71408 6.559937 -42.421692 77.321945 71409 7.464920 -42.469833 77.113663 71410 8.978355 -42.327789 76.438782 71411 10.113686 -42.836533 75.527084 71412 5.578995 -42.303497 77.067444 71413 10.143097 -43.300720 75.644165 71414 16.492325 -42.788940 75.778839 71415 16.499092 -43.269531 75.636810 71416 16.631447 -43.071106 75.906921 71417 8.450256 -42.345749 77.022400 71418 9.898148 -43.978485 75.528809 71419 9.472160 -43.179276 76.429077 71420 16.478477 -43.374969 76.082565 71421 8.735092 -44.490036 77.415009 71422 7.209343 -47.233719 76.156235 71423 6.687149 -47.923218 75.918427 71424 14.596817 -47.122620 77.278015 71425 15.033279 -46.527771 77.338074 71426 15.731186 -45.824524 75.721252 71427 15.623703 -45.824966 76.612564 71428 15.436829 -45.819611 77.473160 71429 7.418106 -51.498474 75.250702 71430 6.340164 -50.790619 74.844666 71431 6.877380 -50.102646 75.741470 71432 7.038635 -48.513367 76.482849 71433 7.907974 -49.839569 77.136414 71434 9.187546 -50.350677 77.501511 71435 8.662445 -50.914978 76.579178 71436 10.287804 -51.369186 76.401047 71437 10.300751 -50.848312 76.969315 71438 11.725082 -50.661835 76.358398 71439 8.094818 -52.448166 74.813324 71440 17.520859 -52.881271 74.247757 71441 8.903168 -52.290787 75.351440 71442 10.649017 -52.043381 75.399155 71443 13.390488 -11.945404 78.410767 71444 13.249603 -12.389816 78.852585 71445 16.650848 -13.277237 77.896103 71446 12.411812 -12.982422 79.256180 71447 11.716690 -13.517288 79.526337 71448 7.324219 -14.651749 78.112442 71449 8.098953 -13.683441 78.107681 71450 9.131073 -13.757401 78.777390 71451 14.982407 -13.486084 78.870499 71452 14.600189 -16.123901 79.382553 71453 14.403076 -14.695374 79.387131 71454 7.041138 -15.734528 78.237961 71455 6.809891 -16.816895 77.908569 71456 9.344208 -18.452103 78.809937 71457 15.926376 -18.020920 78.524948 71458 3.426628 -19.613388 77.243515 71459 8.015991 -17.774841 78.306046 71460 15.286522 -19.317734 79.323639 71461 16.754501 -18.923828 78.638214 71462 17.762093 -21.098221 78.689499 71463 15.916077 -20.665695 79.235062 71464 16.620773 -19.880188 79.062225 71465 17.599777 -19.594360 78.569489 71466 19.183929 -19.406601 78.077698 71467 4.570152 -20.464752 77.582138 71468 3.821823 -20.940033 77.568039 71469 2.973663 -20.643051 77.289047 71470 5.765411 -20.658997 77.623001 71471 21.246063 -20.665573 77.813660 71472 20.195038 -19.861877 78.183060 71473 22.548645 -19.847702 77.469528 71474 11.015556 -20.802246 77.894043 71475 10.684189 -19.667465 78.853439 71476 19.708611 -20.435379 78.394760 71477 4.666977 -22.446640 77.829361 71478 2.921059 -21.719940 77.253906 71479 11.539963 -21.413696 78.039612 71480 19.637764 -21.491104 78.282944 71481 7.122971 -22.735382 77.611267 71482 20.246414 -22.678146 77.674026 71483 2.886063 -22.784912 77.131607 71484 7.141220 -23.999008 77.882538 71485 17.837784 -22.870621 78.182144 71486 17.155594 -23.230560 78.261520 71487 18.892357 -22.426880 78.127304 71488 2.822159 -25.132477 77.016251 71489 13.961746 -22.993408 78.113541 71490 14.699158 -23.630402 77.825272 71491 3.045342 -23.919434 77.142731 71492 8.564064 -27.173553 77.587479 71493 4.921753 -27.876541 77.931458 71494 4.497070 -28.716843 77.493896 71495 3.833428 -26.770142 77.665085 71496 4.426087 -29.531113 77.077698 71497 5.361740 -30.421600 77.049042 71498 5.237953 -29.222946 77.604126 71499 6.148712 -29.836716 77.513657 71500 6.994896 -28.977066 77.815186 71501 7.799423 -29.319260 77.417130 71502 16.587715 -30.642426 77.319717 71503 16.457512 -30.515823 77.585373 71504 16.183426 -30.688278 77.389816 71505 16.659904 -30.657486 77.664154 71506 6.135033 -30.596939 77.118210 71507 8.514946 -28.678955 77.330200 71508 17.108963 -30.924561 77.253723 71509 20.561172 -33.058594 77.095688 71510 19.963303 -32.577728 77.435867 71511 10.696960 -33.003937 78.218964 71512 9.121887 -34.258957 77.462814 71513 17.163712 -33.633636 78.222260 71514 17.826645 -33.359848 78.008377 71515 17.575760 -34.342560 77.350479 71516 18.655830 -33.839294 77.376556 71517 7.643989 -35.239273 77.306213 71518 8.402618 -34.843231 77.897171 71519 9.317581 -34.060349 78.278305 71520 16.143616 -35.072113 78.294479 71521 15.635246 -37.070892 78.217407 71522 5.232414 -38.116180 77.866989 71523 5.352097 -38.919754 78.750900 71524 7.218445 -35.722137 77.746964 71525 4.838127 -39.161530 77.633408 71526 4.894989 -41.119186 77.577469 71527 15.359863 -38.947662 78.965378 71528 15.610199 -38.142853 77.936630 71529 8.173149 -42.689560 78.288620 71530 8.935852 -42.773132 77.394058 71531 9.024460 -42.504303 76.894241 71532 16.465103 -42.895325 76.223694 71533 16.080711 -43.313934 77.148941 71534 15.676651 -44.886673 77.530319 71535 8.811157 -43.277527 77.850525 71536 8.642685 -43.625580 78.380829 71537 7.931495 -46.424301 77.289078 71538 7.445717 -47.433365 77.097931 71539 13.339111 -49.117874 76.324188 71540 13.663055 -48.262543 76.982971 71541 14.125763 -47.517517 77.391235 71542 12.757347 -49.717285 76.451080 71543 8.503342 -49.017685 77.933121 71544 8.645180 -49.774796 77.862915 71545 9.096542 -51.679596 75.982864 71546 13.470215 -13.250534 79.270523 71547 11.095436 -14.289444 79.711823 71548 10.002937 -14.215134 79.409348 71549 14.249710 -13.528580 79.219696 71550 8.193924 -14.514145 78.727142 71551 9.017975 -15.001190 79.305771 71552 13.761597 -14.002899 79.563736 71553 7.977569 -15.944901 78.733780 71554 9.113686 -16.132858 79.465225 71555 14.178940 -17.628174 79.691833 71556 8.819611 -17.081421 79.115326 71557 19.776093 -19.897903 78.384720 71558 11.972031 -21.009659 78.753693 71559 16.730011 -22.587616 78.549789 71560 6.236786 -21.980194 77.781860 71561 15.811714 -21.809586 79.028137 71562 6.262924 -23.072632 77.941833 71563 12.885300 -22.039978 78.505432 71564 14.556053 -22.698257 78.733673 71565 14.888222 -22.263367 79.019730 71566 15.511688 -22.879807 78.553482 71567 5.909485 -24.545090 78.226807 71568 14.796158 -23.322220 78.242676 71569 14.024704 -21.265900 79.152756 71570 4.231926 -25.147690 77.942993 71571 3.055161 -25.985291 77.201218 71572 6.146271 -26.017349 78.560669 71573 5.332955 -25.575073 78.480820 71574 5.089798 -26.469940 78.378769 71575 7.749191 -28.043228 77.961548 71576 7.147675 -26.905487 78.383270 71577 6.075363 -28.527405 78.043350 71578 6.065094 -27.284164 78.461777 71579 6.860466 -27.877441 78.315887 71580 16.254005 -30.698334 77.730865 71581 13.567566 -31.427322 78.286087 71582 16.534836 -31.042175 78.054382 71583 14.506378 -31.393112 78.777664 71584 17.437119 -31.186249 77.947250 71585 17.961884 -31.721771 78.080612 71586 19.100204 -32.032791 77.572372 71587 18.387039 -32.670181 77.967773 71588 12.213287 -32.063431 78.433685 71589 17.254761 -32.520569 78.491150 71590 11.226700 -33.040451 79.310760 71591 12.130058 -33.017899 79.905350 71592 11.334641 -34.632507 80.254822 71593 9.906860 -33.562531 78.137390 71594 7.698295 -35.310440 78.117828 71595 8.948151 -34.737854 79.192368 71596 16.195221 -33.601822 78.829071 71597 15.856033 -34.919357 78.945206 71598 6.966423 -36.543045 78.613525 71599 15.743423 -35.960251 78.572891 71600 4.718651 -40.142944 77.794846 71601 15.487289 -39.832352 78.701645 71602 7.150192 -42.290695 78.120193 71603 6.261925 -41.902557 78.298950 71604 9.110588 -43.334015 77.354187 71605 15.616020 -42.238174 78.360306 71606 8.627113 -45.907944 78.442627 71607 8.769852 -44.603607 78.659622 71608 9.477112 -45.244019 79.551407 71609 9.456024 -46.726562 79.223724 71610 8.464355 -47.590012 78.163330 71611 12.103500 -49.066757 77.705185 71612 9.611435 -49.642700 78.121613 71613 10.716599 -50.151886 77.576767 71614 12.668816 -14.498474 79.805130 71615 10.264664 -15.603394 79.833847 71616 13.531448 -15.962021 79.911087 71617 9.945389 -17.191101 79.697144 71618 11.521622 -15.475494 80.164597 71619 12.398384 -15.925034 80.266495 71620 11.443924 -16.710083 80.265610 71621 11.143859 -17.966797 80.106018 71622 10.312309 -18.488983 79.531342 71623 11.186737 -18.935165 79.728668 71624 12.236900 -18.710800 80.113770 71625 12.241272 -19.816101 79.527039 71626 13.190734 -18.395645 80.151718 71627 12.599693 -17.738251 80.270569 71628 13.513062 -19.216461 79.800629 71629 13.354362 -32.501984 79.820343 71630 14.528259 -32.021744 79.428268 71631 14.500137 -33.466782 79.806839 71632 15.831009 -31.845840 78.743912 71633 13.423599 -31.682053 79.119614 71634 17.056747 -31.556671 78.450531 71635 12.390076 -32.256805 79.360245 71636 10.063004 -33.581024 78.880356 71637 9.561424 -34.113388 79.255081 71638 15.396965 -34.316208 79.443298 71639 15.429024 -33.439758 79.473145 71640 8.091690 -35.771088 79.196808 71641 15.370399 -35.457626 79.295029 71642 14.961311 -36.842117 79.382202 71643 15.363327 -37.893570 78.868622 71644 5.240479 -39.908829 79.108521 71645 4.973702 -40.013916 78.354019 71646 14.964584 -38.142624 79.552979 71647 5.195664 -40.635376 78.688690 71648 5.588554 -41.267624 78.598221 71649 5.544235 -41.740311 77.950195 71650 8.049697 -42.550919 79.317230 71651 7.248116 -41.797150 79.233017 71652 15.517838 -43.191620 78.667496 71653 15.531967 -44.022583 78.395889 71654 15.025917 -45.842087 78.141617 71655 14.170898 -46.726364 78.274338 71656 14.529022 -45.877716 78.680939 71657 13.168129 -47.742798 78.182404 71658 12.900635 -16.815063 80.243927 71659 12.735580 -33.579636 80.225037 71660 15.349602 -32.733948 79.381332 71661 10.304047 -33.930359 79.654938 71662 13.528786 -33.493408 80.162262 71663 13.282372 -34.813660 80.239273 71664 14.578384 -35.234924 79.770706 71665 9.829590 -34.709000 79.951324 71666 9.129913 -35.480957 79.991226 71667 13.712555 -36.540741 80.164246 71668 14.150421 -37.904861 80.073990 71669 6.929978 -37.630157 79.662216 71670 5.588554 -39.527496 79.482697 71671 14.707642 -41.538513 79.572205 71672 13.583160 -41.002457 80.284042 71673 14.492081 -40.027802 79.731918 71674 14.539352 -38.847900 79.870071 71675 5.741104 -40.380280 79.411606 71676 6.249153 -41.282898 79.178070 71677 14.704224 -42.718292 79.548111 71678 8.843231 -43.467804 79.442520 71679 14.722275 -43.844299 79.355850 71680 14.803482 -45.014252 78.785690 71681 12.752869 -45.875229 79.573303 71682 13.756821 -44.798965 79.600037 71683 13.863991 -45.869247 79.042389 71684 12.990311 -46.831314 78.955948 71685 11.984605 -46.822678 79.403275 71686 11.944084 -47.774017 78.806915 71687 10.222047 -48.442169 78.653412 71688 10.227875 -47.374847 79.358200 71689 9.515564 -47.635178 79.027527 71690 11.087570 -47.390381 79.320953 71691 10.729431 -49.436005 78.175995 71692 9.997849 -35.928421 80.471451 71693 12.259521 -36.547348 80.521271 71694 10.983002 -36.650635 80.735672 71695 8.938126 -36.557129 80.352722 71696 6.528229 -39.231781 79.859039 71697 7.838943 -37.065964 80.009781 71698 8.535034 -37.998917 80.713425 71699 9.885216 -37.557098 80.801498 71700 7.457352 -38.170715 80.417297 71701 12.986862 -37.719330 80.445480 71702 13.352875 -38.863098 80.354370 71703 11.598907 -38.257202 80.755402 71704 12.455818 -39.980392 80.591080 71705 6.563194 -40.751358 79.690460 71706 7.480553 -40.726089 80.094925 71707 8.411102 -41.959457 79.968338 71708 9.420441 -40.073029 80.691010 71709 7.617012 -39.865829 80.498337 71710 13.601448 -42.037567 80.230087 71711 12.058357 -41.337555 80.643600 71712 12.426559 -42.410706 80.582184 71713 13.370148 -43.378754 80.151428 71714 12.141136 -43.034393 80.594452 71715 11.794769 -43.812515 80.488922 71716 10.475342 -42.593567 80.492065 71717 10.218918 -44.172607 80.269394 71718 12.476440 -44.794693 80.062332 71719 11.030914 -46.036835 79.775803 71720 11.278336 -44.791061 80.326080 71721 10.426010 -45.069839 80.161789 71722 7.763473 -39.086639 80.631042 caret-5.6.4~dfsg.1.orig/testing/Human.colin.Cerebral.R.71723.surface_shape0000664000175000017500000644517211572067322025566 0ustar michaelmichaelBeginHeader caret-version 5.5 comment sulcal depth, smoothed sulcal depth, folding (mean curvature), areal distortion Cartestian standard flat vs. fiducial; lobar flat vs. fiducial, spherical vs. fiducial date Wed Mar 28 09:19:57 2007 encoding BINARY EndHeader tag-version 2 tag-number-of-nodes 71723 tag-number-of-columns 6 tag-title untitled tag-column-name 0 Depth tag-column-name 1 Smoothed Depth tag-column-name 2 Folding (mean curvature) tag-column-name 3 Distortion - Cart Std Flat vs. Fiducial(areal) tag-column-name 4 Distortion - Lobar Flat vs. Fiducial (areal) tag-column-name 5 Distortion - Spherical vs. Fiducial tag-column-comment 0 column 1 comments tag-column-comment 1 Column 2 tag-column-comment 2 Column 3 tag-column-comment 3 Column 4 tag-column-comment 4 Column 5 tag-column-comment 5 Column 6 tag-column-color-mapping 0 -35.000000 5.000000 tag-column-color-mapping 1 -30.000000 5.000000 tag-column-color-mapping 2 -1.500000 1.500000 tag-column-color-mapping 3 -1.500000 1.500000 tag-column-color-mapping 4 -1.000000 1.000000 tag-column-color-mapping 5 -1.000000 1.000000 tag-column-threshold 0 0.000000 0.000000 tag-column-threshold 1 0.000000 0.000000 tag-column-threshold 2 0.000000 0.000000 tag-column-threshold 3 0.000000 0.000000 tag-column-threshold 4 0.000000 0.000000 tag-column-threshold 5 0.000000 0.000000 tag-column-average-threshold 0 0.000000 0.000000 tag-column-average-threshold 1 0.000000 0.000000 tag-column-average-threshold 2 0.000000 0.000000 tag-column-average-threshold 3 0.000000 0.000000 tag-column-average-threshold 4 0.000000 0.000000 tag-column-average-threshold 5 0.000000 0.000000 tag-BEGIN-DATA ?T:>:?4Lj= ?? V>?y^>{>-?<>4? զ=o?Ɲ<<[>})?Ui>R="?MR>>0ˁv?=F>0>$YG@s> ?ID>=d4]@uA>s?{=ďTyO?; >.>u%W?ј=q>>BP(ᓿ ?˞0=$T>5T= s?$'>'if?;ҾC?׈=4j=5 >‰ǠUP?Q]=*U>s?=?a>K>\S ?>R ?߽о6?D{>]>i=5Y@9 >Qg>?'p@I0oe>?'~>O~`@b~AN>jr"? <'j?]p>|? b= @>( >T?3vi>\>?0j?`Χ>_ >/?&>5>ʾ`k?R=^>"+>O i^[?l=o>s>o۱?e"=N>z>+M 8?`=75>*u=- O9?u2s=lIF ?+=!>5r>E6wKj? >G>>| A?M@QZ>x><EݾČ?ߌC@>X'1>:a?L>p> <&T1?X={>IX=+=*Nr?Ø=>pG=}qǟ>{O>$>y%>e4PA5S >Ab>>4>Ab? (~>2>qE>PD=08?=?>_Q>6lh-[>=*>? o|9>S>?n?.>K輽?ӽp={l=>?kϾN}V>lb?½DCҕ??>? KWr.?D˵[>>>ؾ[%Y?uOGrP>eXd>ϵJ^?2@>=w\* ?lD>5\>c.es+?‹;C>I=!?C+=>7$z?ԾH>N4?_T ?/C:>,>mAv辷e@⠽ՙ>b[u>w=g?8>AER>l,-ȿ?19=?\KW"ӄ?N3k= d?,~J=<ڼH?莾J>|?*=9eH?}>r:>[_?uF>,v>L0Wr @Ȃ>3?9>z㼟:X?e뾆=JL>HRYqs>?5>^=@d>p>@(þ4?ź豼= >W5R]P@I]>><>.^ ??">/>~RHL? e>U@0P0_l+ ?_n>O=轌*?/w\=>R>)ͽ9~>BվD_>a=)k>y>E $><(c>sQY>H| վ>JU;>Wy>ӷR]*ʣ=>xT>à@7j-/> > >=MM?[X\QF>y>R&P ?=\bx>b0>]F\?eÜ>f]s7e>vʊ0j?`8ʂ>W=n>-¾?ӄ>?QH=sF?_=Qb(>}>y=<ɾ)%>]>>~Y=w9 >W=mҾIy:lt2>^ >j>H/=?>Ry>;?d &>f^=,ON ?0Oh>E>#ȽQ﷾A>9<`=4k>dž<<`/-sn(?X>% >|?>G=?qs>>C[{W>\>=?'=v=9>?R}>Ѽ%% ԙ?xs/>*Xd?(߽>.=d%%?=$_>{g$6G?&>b_c>F$M?+>K? >F>QN?sR>5aN=Ƚ]?쁾U,>\H>_<4> a>x>ؼý"`EM:&? =:=m7&Wu>\>IΪ?=)l>)[>Zɰ`̼?!x>.?s>E>_?sH=;c>xhw?"Q>tA>?HbQ;=6[(*1@>^aP =Z>%猇F}?gÿ:> >?W?_/>&=ųn: ?>߃B >*&_??^><>ib>>CC1>Y[= u:Կ5>0>X=s(tý>">g>Y!J㾴Ѧ{g=d=x%<ȣ>uoٺ2l> ,=:jS뿽s!>.Zy1 >0;ם H?ɧb>q7='827?bO>2=Bmμ<\=d=S>Fk? G\K@2> =#]1`dJ>L!\>>Kݺ<|aF=>Ӣ{͞WzD.{>cz>{K=?ޠ?|>'BY=RG?k8>5>¿fW+b?.H>r>Jh-#սd9?L?>>/0yy;?XS>>)?z{-=e>L.Z?uLf=i>L=n\ս? S>AV?KQ=лo>??5^4>v?LFR> >?/^=O7>Dt=a1Y>s8p=[('D>=X>=ѱS? 7yB=J? 6/>UO=J?~>;.>L=f)m?${r`p>h??b?f>xG>k??wsm?~,L>$=8=.(4=+!`H#⿊wm2?A>>Dt>eր/?L >?H<}}B#[{xZT?\s>SE>8e?u>>н=R7?p}?=q =E?W>A=ϫ ={?4ƿ[=IO>[B%0ϽE?&;>A$<%J4C|?w⿇A>Hg>jcn#)=&?,>>l<e>8?¿ W?!?>.>?}g>/#ϥ_@>@8>K~? >̽>K>Z4ل>>U>J6侣ˣ?ݼ> N?<;<ƀ<_p>Lqܔ? y<̔-?^)>H\?u=ګG=Mu>v)P=tumD;>L4}=@_>K%-;>Tڐ|ٮ=>u>gg*Aӳc=>@V=<޾S۾?H>~=i>+쾺:*}N>*ns>l۾i]os>>x> V|5>]>> 0J@%1`>o>jw>Q>3o=\t?.I<99T?u=A?*PaF?+>rD>Uھʢ^ԁ,?D1 >? ݾH>?1@ۜsb?-$>s?*N @f!\>?S`a??'lY>0?<ד޾O?C>>c=h׿"W?L)/>Q?c&g[?- 5>?2A-h>m?cs#!>=l>y3v#?AL>a?׿-@?Ӌ@>'>B@H?/?F#>8G>п ?a%O>'$>6H?Y8>k>Qy!s2nR߿ O?s >>z>Y?<>{4>Dx/T?=)(>%=ޔ5M4?e<=9[L<ٽt6?8>/Q>M>f.2=B^~d>P[=XةUovm:ni4?vx:???Հ6>NE=?_K>Hk>ێҾ<?6>N> 1?vjf= ?;9>>?wic$>|?VG?W?T?:~nn3> B>*g=>7c?^>G>ֲ=>W?q"Q>*ZV?Kdr?+,?O?Cp?$y>>#>Nh8=U?r/>?:>~? ?h>z>;>Kg?Cew>O>Idc>.?oi>f><>]?z5]>5R=<ܾb fE=<63Z<}>>X>I=_ >?6>-?>I>"ʛ?b)>!F_?`=eX?9?I><#t?:=pI?35'>7}?v<8ˎL?x!>3t6?w>kv?붳>#?>p@:z?ɚR>?>%?l?bd'?Y>.8<  ղ=_?=h3?1n >±?X>| )?ǕͿ>/?+?['?y> ?[>}>2oQ>-?\=^*8>4=>0?=NBJk=6 #>@?@AD̿?akf>T ?>~4;?"Vm>ֹ?>? x?p >h?H(>z|K?bɒ>M^J?m>>&@H[>x?>Uο?%=s?Ɔ>4ʾʐ>Wgv>%p?=>oY!3`=/?rl+^[L)>4X?j<>6V 1DD|c> T?cuWiZ}?qҿ>P? >ƾZ?02>`-???#:y_>>p?/>=`ݾM =?H(>?ﴁ>?h>eY6@ ?>?b>>Q u<,>?>oLl b??+>㴾 Ai?h$>NT?n^?1#?` =&_=9\>2r>F =@ 㤾yWb>/Q>2&L Wn>"x>-C>SN=na>N>܁,.7_?ͳ1[p>eHɛ>bat*_ٛ,?A?%;I'ga?A>PL BF-oz?txu?( J&3X?h >uLF\YI?]N+h PFi@S?F?@6">QýupTύֿUئn>(K?"!]F ?=,{Q?U?,>?!DD?+J>? vI0 t?&->?:mv) H0{ &F?:?+5>&m&x*?dN=L0`bz ?>߾ThOh= p?Ə>̉> U}=|?p?%+?,? |1>s?CB>S>Z>3>?>=2/'=8>,?7>,=?-<|>X>>2m\!a<=0K??;>(T@d=?@?%^?OC=? > L<(c?)>p?BIR@JW=a=?SL?[K>է?|TXT>3>bi?v` => þz5?ǫ<>7>y K(|OT?=>\p"V >vŽ*M $XRVz>7[򾃩*6TP=V><ϯtq=6hp=5~?!b9h 9?=>?OD뚾7>==C:\?_nYd>Bއ?Ѣ?QҞ?X:?L>??x.??%>ր?q?I??SY>L]?o?1ә?C k;jp>?"?M?ma`h=>>.>>:>lf>Ic2B(?8>? ?_D?}?=k=ݾ&?2&$>>j>j?v>ĝZ?m>Bb>H? Sxu>><{F>zg?j?nծ?,R>h:>3?„>>;r>z? ?e?dZ>m>?C=jP??|z=?ݿ>j??Kug?W 1?? n-?l>?8>LQ 5? ƛ>EN?f>%?M¿l>?? =CF?cS>&?J= c Z? n>wZu?:>ֿj'?s`>,s?/?wĨ?|z4>xy?Y?NR9ư?_>X?W?5-6?ߠ컙>`-?Å?Gڽs.?5P^>3Q??O>ґ>?LȊpkC>x >[e#?E޿iJ^Uz.#>P?qf=?>: >?9zsz? Ч7>{S?~>Q쒿(?_#>(֑?n=L˿8?xH->`?7or?px>Ì >?f>HkB'r>dm?O >qi(G>H5Y?D->uC*>:RD>5^?JM= _)?4>d)>?I̸>-1f?i=&>x^> m.[j =)0>.,=,U\SDv=>{K?J>&[?:k>x#t?"D>TT?]?\y2A?ffs>GR?7=Ť&dž?X=P>d= ׿,K?q 6= >O=Q??]>lH?{S?O*?e>(???G0] {=蒫?CVͿ?A>m ?=Q4!r/K= ?˼7?{>7fA?tu=<4?>zC?_$1=Մkۿ-< ƒ?= TP7ᨻ?IܾjxO1 >`?Ҋr?/'Mj9>-S?r>c­@f:>u6?e> pMr?#Ϳ/>?6??D>m?T>0?w򾱔[>,շU]> 龛PL0_?>}CO07?L?%>Щ%&>:_=2YXѿFVaxb= J?Kxt/ս!!?*n3vV{?߾>`v>>m:UX? C2/U>b?O@վo/>-:9=?9e^ݡ>5ٶ>*#:?.ɎU͸_VqL?h??>܈ $O=d?A聽{e,.;>Q?Nj=}Q/J ?|ǖ>K=)<e;Si׾~?yh>0W$Y -?eoT4;/{q{C?FVF,kHK Y? OL<Ç?=Qe[7<?z۽k׾b$ Uq?v>lUkʿ nB| /%N?6~`=Yվv<2#ս7ȿ98=>/#=y=3>c=@4 ߜ%BAlu\?X] >c?p~GA |>\X>>K [=?뾂¾-T?==dЯ N?.t~)q=Ӫ>m>P`y;C=9龇? Les=??5;?3 >=>>=DC>:=yf2RH>_]\=Wd?>P>ZQ?HD|B=[?"F>>h-?R7j=o>>t>9Ť?^끿g=><>{ >@ȿ>??Qv?x@M=H)4t澲>O-? m?\?h^?Dc<>u?"d?V"?>m>>彰<>1v?t.{>Q?^>S~><>>Q?Q=?*2?U |2U.>0f壼ﲫK˿!뿚8WپI)=*<뾧bIVk?AM^>If>݉> >?{|P>Z?2>?D?">?>f㤿 3=">׾hZ!m+?$ >ڿ]?=? }> ̿1 =n@>=6=>FĊ'?dM >ܜ?6>}VM4?#RD>A ?-vW??_2Ys=c>>Cw)?PV=Mf>W>3S7F?ޠ+=T>x>-?= =ó>>a|?D~=[d>ۤ> ?7>? ?;bMi?>Ǭ=]+?H?Y=j?W2>;'?#?TCĽq_=>?A)?qw>O?>>!6a?(?y>ֿa?]=> g=(<9X?bR=? J>ݿiiM><+?< Dktt?@nr=0>e>~>΢B1=K5?~?LC$?=7=H>í>Ϳ?r=Et>X>I ?:~>*??A퀡(aA$զ>d?K>˾Er#38>G?hR?>M8YI*>KS?O'= ̿=H\>U ?>eJ=*>Q]?q>SXՕ?&>?`[?d>܆f`?0#p> ? >n;=?un=?>.Ǿ#!?t? >={> >ؿ[- >q"?QqJA4,B-> ?=.7ᅢD8G,>>+?|{>U}p$}D=*?/? 4v[)8#>H?\}?qB-C>-?X}>%i(J>[?^?jfP>$,^>u??l> >Dx">?I?6)=6>P>z?[><5rXLE:>h??<<)2H>?$ ?a'_>"2c>M?,>Izx5{:>4ʒ? =Hin(M>/X}??; 1>;sKAhR=^c?I?=)?خ>J> Z??ľb>%,>*(IF=M?F 6_ٿ1gxA=?!տHJ8$O>?=,I'S EH=?ZMOF2?0)~-|NE9A00? =} X(g>?Ѝ?͊-Kq9C?1ۼԂ8${!s.=l?6r? d1>ꖾ>V? s>Ly-=A>K5?Dt>aO=U >mp@!Q=?Qc$N#߿mXC =>l?@?׍?>~^w?/<0ژgt\4=g?u)TV.BQaFe;ŗ?Gj?{E0>yd?žyriIA?ڋL>=3$oy]W?X==&θdo;?YO>B>cUuUYͼ]ү?>p=|?@^>=O?#(cH?΍ o>P>b Jodn1?q;K"f5(k?{&;3,龊a7rNe^?l>U#}̾>?b=w"?>=R&>ÐC ?~>0?ؾHo:y?HP>K?Z࿱>GV>>>3Ù御 ?>md>ۘhῗce?{+??2w^Bfo?y?e?<>dgpH=5?16?(>l<3NzC%>=lg>.8e? _8={?H?W>W^*>EA|<# W+=> 3/=_~~_>=I>ʩz= o?>:2?vh^!G===U&-%YU=_iWj>?>?G.??S}?f =X.? >>?:G?Q X=x>W>},>?]>I?-!??J,;@;>?s?v?vm >n+?gԍ?H?S뽼<>ˊ??>JQPbj>5ds=&> >מ0=uS=\پ,;"?%j{=1 ??i#?b?.Z=:?>>s>=s\? (>!>b?G=8X?RL? ^?0=̿p>o?]?Gr?W?%=ŢQ=,6s>;=U̅<}ȾхjB?k|v2>?I_?[?dȊ?Ѭ>Z>>t!?/7T?T>4?f?%?s)m>?);?* E>!V>T>v+_ >Ӫ>@>->ͼ>T.?Ft>|>>?Au=_>>VS?@={?/>ݾ_N?~s=ݣ>=>؏!?߿”>i?'%?辮c?>-G?'v?++?\>i?]?)w2?0+>0??b ?a>R?>bZ߻>~>b?'?WBMYH?+H>~>V>FM?>L?R]=?.??C=dg? <>ŢQ싨>X}~=]z??^@Ax?xK=Um?Z>HZ N?9Pj=Ѝ>>x?o>1 ??]w?֌>> ?-?KpJN8?)|_>.?`_?> ?]%t?(7??N?ɴa0>82?P>hA&֬C=: ?2D&S+)=sd>0˽Q6?MP>M2?i? V\?m >0?1?!?t/>$?FȢ>\>?IZ=b93'$??>AI?U> ?TS3>L?s >U漿):,^(:q=+?rh伧APΒ7H<8>7s <4P~>K~Q ~ >bM"'>~6?V>]P?"'1>?'?<ڡ>IԼxf'>87?@ة>z'?jH>Y ?X3>[S MRh2>]2?E?<,c>d?yh>pw&>*=D?i<=ei+Al:=)?o쒿H09PK5~l?>ӿrѿ]=9=??ݽS-op3>:n?h?i="C=T ?o->gZ@?Prc>h7?B0>C[1Pq>pe??*e= {w^"%=~?\? x=4LXj0/?>w%< m?p>zW?q>#%@RQ==u?y:̿8wV4>4L?*V>NI\GpV>d.U?u?EȆ>T?< y?ڽ3?2{?>F=S:a_;I>_]5?NIrҾ?A4l>x?.dԾt:ݬ@=S?_ ؾ&b?1#>H:>02T!{6x>~,>h?Ajf>:T>!*?-]W>]+>`ٿGÿc?Wƿ~>GN===!n?u>> >B">m >3>G3>\!yXKz ?xþAݿ8kƶl-?-u=*S]f? $=\:RRJ?=C?L d>g?TZ CJP2lc/Q?%>O rDNщ&?\?'=48Lnjn4P?>1$?;O>Ρ?z=> ?7zc> ;O>Ie=ݵپ44xR־?>D,D1 oxw`H?|>{NGD(!?=+oh?z>Mb"(k)Dg?RJkk9SH!f?=f--C> ?=#%P^_Xz~5˜?qm> ?ñ6>?eRz=!C;w?ʾ)kP%h>߽=i>||H1Y뷽o?[mE⿿J_Ŀ־OD:`PA m:j;Wp5i$63׽#/p5z>h"Wl > 8?"~=o>y_>e>}K"=:>=>1 k¿g膾F.?4l=U ? F$>Ƥ>1=1r>>? 36ĺ5>)I ->18"J˻=<==^?~>]?.E??[=\ =p؈?X?I?}?z.=#>s>Z:?9ɾH>M?E?{<`? K[ξ ݵ@'?&{ =A o?I?qx6>&H>SX>玟?/M>>p<2M=a>?: >>6۔ZO>kY[ A>Eq=>>(/>M>%sd>`?E?;q?Kvq?CNf?ӿ_;;=5>Ø>V?",>f=G>?*> {>pT>̙п/I?>*>3n?oz?ͼ>D>܋e?  ?@V=W?:?_?o>?|?<߈?輿= >H? ?ɸl=>>K?M>9??82B?@Y>,?9m?!?_>!F>?`kl?$m=? G?i?gm=o>헳> ?8>6?o?qqm?\L>*?GX?GD|?!E>B 1?fF? $p?!>?v?H-h?}> ??;y1.?u}Q=P?9}[?R*|+?ܿ>ۥ?3\?'M\B o=!?F|>=o@+57"=Wr ?'4matW$6i=E?a Zd?7H={?8?6*g˾߽P ?|?Y>c ?s?›?q=d=L=q?}?;־dI?C=-?#>d? A=J?r>٥D1?m>4j? +>c;T?/>#c?w>S܄?Q]P>=&t?$F?b`Ɔ0>?3>Rҿ/> # >pjn?3wl>ʒ?5=(><Y>kj5> ?W> +E[q0.>LLY?)>p ?ٺĈ>k?A>CľI%=9?9O;W >DU?ly=sa: =?k]>V+h"3D>i>Z{ /a>"WC=>;E>bо??}Ñy=p?i>ξ}P{<1J?2ɾ༾KsR^Vz>w?Ȁ?@j]>G_Yw >T??1>)c[=I^?=;.]a>|? >FqKK`徊?v>P/>y2[_?= i{cI?Et+u]U0w8b?E>[?Id >O?z=`@jJ>?>0 8eW>~[B?nz>۱;:&!J=b?>_.I=*cF>m??>E==; ->nv?o/XEe>}?𲅽b>=a>%lCrj_umR?`>@=L>Ct3u>\>(`.t.=*=>F1> p0=߿(1=l">;lBbP|F?$J>~tk'C?._,晠[?J,S MY?Y)+>kh>Y*3Y"EnJ=>*>󴳿SW=a=d=S *gѽ9?&hE!0?>K¾?G%H>M>,?7?p>>߿^J4ce`?0>wu vW?M{>߾>: ׇH?->}?"' l`W?Z?`?[|aW?AD??I7fI?G>S?V5۾o?Fy>b,?U΁n?.'(>?п`l>{>,">ش[)en>fץ?J ?3d>*Z<|W(=3>(>= V(d|=h>F>Jkk`KϘt>e/@>#zоT>]xb8xE=@^>`gϾQ׾>^Ʀҿ[v.?Opz= w!gӾq?0ٶI>=Ծ;W=y>>]=7&>Z| __>47lE>ӻA=>ܤ!վ0M?Bm> ?9]`sv>H>nP>\>={ >x>U>) ޿g t=YEF;_忨k<.ܿo { ==.(g̾s ^=}5=;پSjj=%=Y>m[K? 4 ==/Z:x?w(>;>\vB<Ȇ?o4> ?=>f?>p >u>7(a<><1Q>}sB#7>e>m7>c kLt'ľĺIQfA t2G=_P>/>D og>Dy>gI?S[>H!=RY?ח_P<>>T&>J?)a?Ť>z"}>?\@-ZA>͚t< >H?(u>;> %>֓\}Ǽi ٥=E@F>_)yFQ>=(?C?%5?Lb?T~Z<&p=2;->`32q(|=.:?+ܿ_=] -?ў >.?2"><><@D?0>%??cpH~Z='>>О?:~b=|>=ޖ>>UJ;GV>n$y~q>H ꖻ*=z>f3>=A7T7&=fb5>9>q <9(*V>CW>s<DQv?q>rX?2X?^?o`?S#>>CW?bv??S?:h[`=L|>1>??,aU={Y?C? 7;?4OÓ> >iP>z?~T=p=Z=>ح%?Z~*=@ =è>7?W`#=Yzˆ>"W?.E?#;>qU?'B>.?Mi?'>Hs=>6,?`?h`=N,eɾD>)?K+{c>qP??Z=q?=? =ﻕ>>7>a1=p?>I?,?%>?w?4?a?D >I>C(>y?!>K>>i>dA?-ڽ_>!<­=,b>*ZQ~9G><>'>UP?(?m{>{#>#i>?>ݐ>Ǘ?aP"?/ ?cjR>x?aư?)?>xϗ=M]> >1la? ? S.>"6>Nb?4>("<=ri>*ؿfz>p*5#W.h^>ę=/v>z>E#p>.?'w =eon?HB>L(G,=D,=>> o>e?rT ?IO?x>J 穏>W?>d?Kܾ>dsX>)p>2{>`p?W+g?l7;%X>Ή?Mi^?0|ȿ=J'? H?k>vI;وp>U?}?S>\3=疽k<|>q?zp~ >8> A>ñ?S`?xh>X>>q>^?,/O!>r&>2>N?(Vq@-M>ZZ?0"F?Mؕy@ ߪ>^'?GE?iOj!1f@N4>Q?A?fξ5?,D >!Q>?_W b?䆥=+k>?>ֿ?(=:>`&??$׾A ?ODf>>>'P?6憿y=IM>>Ή(?,=>'?;?P<~k?^ ->NR?7+? p,?2>?(A?o7?.O"ǻ>m`> mj??@-oo>?C?EokN {j?BF?l4uM{o>q ?3?x9Kb0?W ?]Z>?J?8ؾ*?j>??\4?a5>?#?R)O>,?O?Mg9ɿnӉ=?7 >Q>=?SL?ww)=;׃=4?%?T>t?p7?/??j+=1?^>4*x8K>_??2X N=Q?P?Z_? s>20?yl?K6=iz?2 >!OU?va?V?X#W>?m?C=S?>^?U>6T?|B>/??G>e>^K?I0?~>ٶ?fV>BN?A?>E ӿM^P?u??*m3ͯK?0 ?yl 7yٿU<@??RLU?H?>?,(?>&V>ռ=p3?>>=o ?І*>m? ?ke=쿞R Z)?H?Ǵ=+[yO?0?),>+[)(վ ?5?>7.M*FE3?E?k>ZY}2b%{U#?v?L>hap5<^?t<yA]> =ɱ?>>DX*Q$zc?u=ֿ??;}t+=k6z?>qo4-8??OX+@r?M?nƾbEGGd?RT>Td/&WC*kD?\>gjreo[Kw*?zF> -KgF۽z?I >0wIR= =R?.A==G?Cr>}?/?/8d?*o'>(9G?P3???T?>Yg?]?0&iw,=R B??Gk=3N.9 ??p=`^ýl/?["Kz^L(̾ !?w4*1ŵ>71=Xo>r`̯^=ڶ?HjOWu6Ity>6?a>݊?K@Ac̽Ӄk=뻥?HB>0p3< F:?'4?d>R}b3(>*?u>DxFڔ/jQ^H?3‡?? ?SJw)@q@$ ?-?b c>K >O?Q/?9Gk?6zJNU?X? J?1a?vm-pѷ3L^?'cE$@g>Z?@?>(J=p(=I?>"kI=s?ƙ?U>, \c<?9?0f>c[g{>_?hM?r?EZR<ޮ?>޻>ew\T=Z:?R>%>*;'PI>=? E>b5>"E`>n?<˾ҜܿӞU~=4>4s6=/=>X%ho J?>5 o>/U?C>>/8I\ma?EܾC0׿9`cgt= ? ?nэ?5 >[p>K;M=y^[>o>KSn2c?+|>qn t򾿉@@?(>M>j\6C?>}x>;?lw\ |?T>s>q%W -?^ٿKCy1?ہp.0E.+I?JBh+agDE?Qٿ]n'JD?b9Hb? Yɓ}pq|?7NW?Redo> ?J+Z>?=4?"$6. IuY?)=<9uEr&½>c [Ob?>#>^*>-ؿ )s'>4?&r?wl> wpv|?OxF=>?Re$>v>uK?/$>Y{>Ӫ\16Y;0i l>(D?0.?A>_˜þx`?b>0?0']?}k>T? X&Mbʾ c|Ev3}>")u;& 1?&=a.>!e uSĬؿXHǿEKHsҿ}>p#P80IS>doJ};*7gsòEB<Р,ί $C>~>?ߏ  y?-gU> ?DCYa>YSr==d+,>+>9־⾅ >; =4?,!*Y}<>$;>_?%^1>1/M3u=ީ?"r/>tm?y=X>|t>5P? l/X3B=ʞW>>׭2>>>w?n?%]=Z>0>? ?`G,>ی? ?*?>H=Ɲs>>??>bE#>,>>í?*==يe?)?ƹ?P:?1Q=q?O??:|DZ=/?>??>[>ϥe80=>v?<غ,(;.>ȸ?UT(=(>/>?Aw?P>&4U5>\W?T>?=ц>>F? d>*+?&#>i?^?@-:>)1?f$? ?x?I0>?C?V1?K >==>)$l?ޱ>G=ZEN̉+>N?Q>>>ZL>?3X~]:>Pj=:%>?>>R>ٻI>?[a>N S=>im>f'? Vֹ`e0W>9?0>q?e0?>%>>@?R?Z?qm n>=:>o?g?" |G>na= 6>q>>jQ=e~>C??L?m >"->g? ?gu?/>u] =U>@">O>?eA@ Na>T?_?;R?D}F>1?9?WC@;`پ>GÓ>`?Y ?<3>? ?a4&\@:!e>Ep>4?Oa@4@l>NSe>ͦ?$sb?=p>#>?C[?F~=?![W?gUd>IM>!?v?D6 ݽ@:y>6\?,?!>t={")>5?A?r=9DE=[W?{l?^<2F9?9X=|>‰3?Ƥ?>d>c9??B^R? q>n?*R?Q2?z >@]?YB?F9?s >?,b?{?}L>@?Ĭ?G;1@ Y=6۔?˛?q ?7; Bc?kP?+d U??>?9a>_?U?fPNb>p3),>??t0@ =?h?B``n ny%??bq̭?/e>52?zp?x@[> vIGu?7r>">"Jb>$)?ps?ZZr;CBk+ ?ύ?a ؾ,>2,$|??T<Ѿ${H=?F?['@>ٽ?>镫?[>pn?>M¾=n9?T?\.}+>ˊ?v?W:: n>oY?m?>9zn`=>\?.M?XtZ?t>.$?)>[b9?t*>?! [>;ߓ;T*>>I,?#28>Cྉn7?!:>?0:>?GM'XG=?uǛ=A`A3nEu;s#y>_&)WҿI|;f>пLh8y1Bm=Hy>z`\FeM@8=?2>KT->aJL |LHbUc??W>=@;\?q>B[bQPaj=Ρ?~Q=p8wzI=*?i>G$Sdl۾y_?.d?r?>P v!?eQq>cc,Ͻ?mtc O??GE(>'}e=D?7?>}kB=Z`?vd>x><:g-[?)R?*,>{N4f>0?=>9>3H)]bJ2n??KI>"rO`>v?ޔ?#;2>BY>}U}[QL`?@/?pF?>mS\>V?,?z>2+f;|?WlξUqP>>_w)?r>ޱ> jUr,>I?s.>B:Xi4,+?Ȱղ͟dwv?+> #d|:T?'#=ee>R?/>>/w>9K>[>ݿ3 G> o>"-X/A1g 6¬>H=b1Yr(&@>Bx?ľt#s:nz??3v>z f>zQ6B>n/>t2)%gnMr+(Ch|@} =˸>I"B<.wk>F|2#?^)=>oL?&)Ay?).6>n? }!o?x=>\ ؿ1¿=t֡>u>RD<wu)?F,w+\(=ɿ +?WCW.#ӚV8?AT r?E?iuvcuľ?=0Ji? _)?O> >g 7?*?EC?69?ejgrIq?>Cc`?'+>>߿g>G,>?>߇B$sP|?F>~?([:>Fk>?!}ԿrL=V>E>Q =YVס¾.0^x>? =D>XRPN3?587>?Hck@*n?>d??N8Ta1f"A?,>p?"D )>:=X->su@_: j= W>*kOlgbr>g?!$>>Gc{=^=뼊׽04N>o?1?k>k#ugEfu>mŽQB>ؼPI=?>a>'9> g< %>Iӿb=ټ? ?P?> >a?3?;B?K< >QP?S.?f9 ?nH#=p@/Y;$>gi*(_ڽ/>spi6/<"<伅N>(3o%B p='D>'==U>a?e0\>??|d?+?hS]38>NM??xh?8s=L>YX>+I?82uw!J>Gξ!-9>z!+9=>p>3Y6?&+,A=Y>>D{?%*_'<%>ʋ>u?5C(>7GZ/>T?Ɩ_0 >?'>ߵ?^?es,x>b>>Q;?Y?;C>g J?F4e?A{??>?p=4Xѿ{>dL >"?5Sٽ@<=^>ڑ2>o&?;bT^ >^҉?#?L?x=/_=->a%>:?=ض>a>+>? 3?c=e]",>6ļQ >c?!\>>>7?`?L. .4>;Qv>>^?c?_>KC.>k .>^ ?+3?M>D?@S?%"?ʘ >x?O?C??D@N]B>ql>H?=kfǾ?>y|>?0 ?,Z-@ @S>7> ?.>(?8x *> ?ɴ?1lm/?=CB$>a?ć?TھuQP=3U=8?Y\?6X?Q>L8?6?޾?L>[S?d?Su/< 8F9?n?[= &_=?Wb?RD sh-k?b?‡?ֲ?R@E>?e?=ѽP@?<i>h?|?jD~?>E?m?dYMQ|ٽ@)?m[6?龴a1 ӽE-f>@>>t6`z?L;?eU;Ѐ@hz?(9?E /տv<}?D?!>6 ?T:>_ ?ܭ?>g j ^a?0?A>Ӟ I/q?:,/{?Z>4W!#4P%D??#R~?U=/+>;Nl׿4?Eo>?q:P?4.ho>'?xx?I ?R>u]?d?>ɽUei=T?@?in=&", V?V@?+ 0gU}Ё-'Wi?>}?R>[Oavd? ??}$<ﲫݓ>j?>?.k>[h?!>lUiw?`Lj$>-(?\x?:2+1ws1}?0{?p<[mT? >=m0O߾"?վ ?jB>\?|?;:y\LO3? ?wI?ZÀg?[?;>.'B0>B:?G?W>!=k& >'K?0 >2,>=q?[?]f>)kU ?><=`BƩB =9u?^>ѷP4K.>+B??+X=>7ˣ>%?D#!>oF0|6>?X`>+p@`=wB?C&V) $pX_f=Z>;XOqB+P?( )A`oX=7&?|^=& R_=ᛑ? 8i4x B?Of"Akm6eٯ?00Ǿ>ݱ?C>y qA# >?8>O >&?N>PAwO3?=IU%:*?C-WMUXO?B4D k8?NJ7[\jmP>?ZPP>ymӀѾyw= l>3Hḹy?J>߃> 9B=YO>]=E򀿇vL1b %dI־NX?SJZ<|"?܄? C>?.پ-?>{x ϫ8<>uI꿚 TF)gAl?[@ ,ȫ9a L? >DݽѿBxؤ?֝>6>7>B0Ç>L>7 #ԫ`Q6>'B=%ĿeqmLLj H!ͅ?"> ٛ,H࿌|O |7;;0+E??>e4 P> /6>>q=e&ǿv=}>*0>q=0 ՙ??;?!|4j_J?+3> ?M4ɪ1Ho=?Sq< X>[>ٞ>Ksp"l>>?!6$ِ,=4>^+Q=X?>dW۟1f4/?Jb=u׈llfB6_?>&N=3>cOSkU>%#-쾷=sCW>,1? qT?v>88>/ѿ<izB?=N3j>4'/,s^<=u ? ?$X?! 7ֶ? a>\?*>U?Ąq|?'>t?ZbF=Ҝ?D?_#h?e@5"T-{3A͜< |m^_!R:=n> h">[2N?? ?`[9E?>z?<&7k=Ω?? a?b=8>?[&?mb?m߽is>2?)??ytW3Z$տӀK|-?fE>P?"lОP=bZh? fX'1=?;S=CF?MB>-?4?l4G>o?>^*?$4;?63;>8C?,=e?b;s >>+?= 9@&1^<=o=9R? H6iϺ>:<^m?:xU<7m>a?+>yR>^>}?X*@$O,˟>B>8> ?n@X/>Y? gf>ج~?^&:~W臩>l??nE,>ͅ?HA?Тҫ=&l+=;?vq<ƿJM5>'}?#5?Zx}Ђ<=?J=ѿ>ɼI}!e>;@ p-w>>1.гw>>}?<ċ?Ѝ.= =*t?O:=T>QӪ>?)8￉B>F?">?x꯾o=P>7>X?3 ~k>?ZL?P3?( hs>ww?71?7?xBt==:>E?(tT}">q?&?'?%)o?1z?SX>\= 4>MY ?<8(uG>y ;.>־žf(F>_}:g >x>>;?bA?4h>YS=֡> ?% >Q>/I?ag?>M&t>&??t?m>B>?P]?m?#e>y=gTm>?2?JKT>Rn>bH>@?_Xm?I$/Z>|f=G>욿"`6U=W=D[?=WT>/{?uz?6 ?>^??ty?a⾀ ?=>v c?/@?cEоh?-8>*x>= ? .?N8>['?T:?e齄>(=1?7Ϣ?˾F?6 >*>;?47??>5?4?WUr=Ht=?i?>^>u.=0w??>?l">t??Ja?#>B>>?D?3>f??=gI? Go=>??⽂i?G3>d?;@?U O;?0U?D>4d _?z?G׾| %p?ĉ?>wK\X?hf?=?J#Ѿ,b… }'??> ~]<*?8?^͎8g~?C?}0=,@ mʾo?9?^7?$K>u?D?A 8?">>ϭ>K8]?F$*>3g?60?<@c?{u>?u@W?mTJd i{a?{?=ÏM=;!??7>0+3=G>ĵ>h *-/?c>g͒] q*???Igٙ7 *??Ec>JIA7.;?]\?y۩="4=_4 !>n3'?y9u?fxPs0v=/Q?6? zl $WgZ0?h?%۾~}`pQ? i?*/Bf'BU&->?=?V82g=l'n?=μ>T=>?!Uײ=]>dq9 >)>}$>އ='D2ܺT?~?2k>W,a??"8?kqne=>N>6&6q?ԙB? ?]?g=>oL>3m?"~t= x>T<ⶮ8sm?!?#>Wd4q{b??>S m:-?J>UDRҾ{?h@?WuTP嗾(_??1=T߃?) ?_g>FV 6h:?>`[ 氧Djcs?GV>m2QIL l?>uY,?Le>+bd`W,dž??=l+dxOLw?&ls?: O>w)??bgb=<. s\$p?&>򾧮W㾷ݩ?,>bncJ\{ S?j>S r]T^5]0'??ܽ*,b:??$>,\?>d=HV!\xO?P>sm=Aa_T0[œ?n/>`UY 7 ?F@>n;prz98=??*->'G !?#=;n>#p=k?L?ξ?imxj?j>SmփbxpϢ?a>Sh˚(f=i8??Fμ=z1[k==u>?j >l &:ӑ?T}ÿ0e(O3?c$O 2]uЭ?,^p<+'Ffbhɂ?|ѷ>˅Kq->?CF?]O|=#>:IkA6~>Ic?D[:>oklsK3n/?зD0 ؼg1?m?}@/3"h \bN'NISaU||=&=qiWh&ӷ>\HN=HSi=?>I>N4F?#-pPz?{91/(2jU`-?7i*dXQl?eCB1{|a?L^=H 6& >LA=q[ d7uSrG>D:>LOp5Q%>>;? %-ya_>P>b~炿W NP%ț[>̚>X?U7 YU?Ld?qT?_bc$B%,?M:?oH?iHկ`03D1w<~\ >nDF (Yh>j>?A;?#>P=?/?Ⱦ*>%@w!3 ?=TνF>LY]м>ɟΏ*IOhcھVI >2֌Bnk :h+>¤muR>]?w??Uȓ=*^?* ?A(?exw/7NɸEֶ>p|BX%?b>YG>;*F;KdZ?>K?Oz š=}K>@O?z?OG#HQ?@?W?nA ?5>wQ>׊+>$?#[-^=ݒھv6=N1b8$_=]Hq>$yH-PE> :=37?%bJVF(h>Y@'03>@Pz>sY6>xƓ?7Ȏ?!>è>S>>EEžc>b@qX>>#>ϒ?[z?82)=Sھ>0?v?%1=n>7>?ل=u `k>K?.a|>K >߹>ga>?\/@'=>@>~>?CM7~W>r+|??!?o3#-< _=y? ZZǗ >'B>{>?Qc3 Sc6}? 7.A=zvS;?&>=>W>'?ua$>8v=|??TL>>9>}5?\m?~A"\>ؽ܈a=\? FD=n6 +k> ) I_=1tξZ6=?@n>>?f?P?8->lʾRMM<H>ak?<^>Ɏ>N?r=>1?Lj e;M>/D>X?u>*?m9C?*=[>}A>z?Y*?>" Б=5?3?G|>?}|m7>{$?Q> ,>G!>ۯ?>[O@O>D?g?_=?ԛ>#?H???bx=z?dv?p+h?D|P3>@>7?(^N#>>Q s*>? ?/_?CN>oF?]?au\ ?}>Tw??)?>l>> 9`> f>GR>f,?/¾ſCDd>{x?C֕?9Bl>?j?$ȼ2~>? F?>K8W=.>&1? ,1> >?2?YVvi?]&c?v=pܾZ/a> ?50?8)ھŽ.?ʴ?ZNjXi*" ?m?bd'B0ξ^-??VWh_4zK?'?:P@g B=֤>>UD.HE[7>R>%ĿA5zC`?='?Vv}_Y!U0>>%{>>>@"ͼ>aC>]>!?i[=>ϖ w/q:&" ?S?cN4?G.j?98Կo)%>⡔r5EPeù?% >ꧾKOֻOD?h?+μj?|Y>6v< 8#>2Z\kT޾?;=-Jd]]=Sf?w.>(~4?Z,=E>=!)0j?g.#=Ń?)i>v>?g`|bx=Ž?Um>\ ?]6&%?9?> k(?>H|1xf߾i?U= n"A[e?>Gw)ZKfy?P&>/7/Y(VWY?3(UTǖ:<22=D??>F=%(@=?P>w꾆C2ڡ=@?m?>Sdg/=خ>'@>F0Y]V҅a?X ?]i{-`7?9?? Q3igNHM>sYؿB,=.??@>=薾U0_=?8>TyϚge?z>R5^u?9>|<;=*bW5<_ӿ$b?%jE ?IZ>Aک=FT/?ln>F0*v2|g;i?An7>Nr򮾒9?e>uw%zEY=p}оa?>[n= !fw?>e>n](TD?7>:L= _XWE|?Xր_Yq]>??&rk:?Sݿ'gt;] xgzXCm/b0>F//:)~~ !>b܏|5>>z\H¿;пw?ڶ?o?;0?ipmҿ;,b?= QD؈CT?E pԾ??\7r>^SVh?S 3]ʿ<|s=XNGM#pgG=>>gY:u.%O> >2MQ%DYA,>J =x㬿rfbR K?>l?Kb?1\S59>Yd=|9>;2@2،sg( ='t 9>/>@?;>9r2>"[19>!yQ@=4?kJMo_g0?Dɧ> (RgΧcՙX>^ꚾ` q9o%,?D½=>=D?l7?Q?u\>TアC??/I?-ɇ/AN > <*?;cp>2Z= ?x꿅?f?]P?{_?0"@i>>s&?PI/d| Xyy`= =Ζ?+V)ھ9>a5ߗFp)k|ǂ?gT<' ,o"? ؽ[>CF>=;m?/>'?0=1 C=tԉ?,܇=?XI/>oa>>ezqoOb?Cna >:bFUe?~D1>O>m*AO9 f{>/ZGЯ>:_?SL8*>\Gluu>!+_v?YH=>jRJ?U/>>JOU?cm@>5aq?ԟA>A1>> ?R@Bf>?%>!K?o 1Jv?J?E?_M8͚J=/>q?/?lqBԻLEB >ѢoF:< MT>׃mA~Ao>wy>hW?@?>8>8"2 IH>o?[4>`>=S@Dc-Kj>??j2n>`;?>0I?K ?;>>>=? ?=E>>|=!? ]¿A ̯>M>^?Rd4tM>>Z?L%9?tZm=*?3aֽ/U>c?32=qڿ\N;;:>?վ=p>WT?1%?5g<] =˝=??j?.>>>2D=? P =Mʎ>T>]?[b?~t}=hϾf5>ʩ?_8??O=>_?a?y4?dbU=-{>O=?T=?u,h>/>ȣ/>͈?mg/ >jQ??d?`^S>s>n>k?I{ o>kj>>/?\v*r>[g>\aR>fY?BXS>K =M=o?u??I>r>d>i?nc?")>Y:>wJ>?qo?(W>F>t*>YS?p9? A!>>&??y8?G>1>D>ھj?b^?%Y> >2??O?)gZ>D>??"K?n/>==>i?K>""=\ ?y?̦">?Q>?gb?;?>"u>=N??ׄ>C FC/ =F=?T?J>Nc龤F+!>Uu}?s?>月?庀w>?O?b>O? k>qv?bs?=0wl6??Wq>RB0 ?7?c>n9?!a>2>?.SC?Oh8-r>=>+>#yb?W?&&*>@~=u >9TrVnbxC=? E?+Ϳ}>]10\>^>?ߨb.<>?t>i?7+ǂʟg:>?.Y\,md?C$?@f{&|>l?&S3?K-ľ %>Yv?'>'LL~Ee=u?$?2w>Ֆ q"Y\>0?"~-_f?#H?@y SO2m>^S?6; j/2E@O?%?;|e?@6E=V>[ٽ{+9<ɾ ??, 6/?~=U>o>_3.?hH#=,>LM?u?rM>unYY?!d?>%4vdd&?2d?=fl `# 0?Yu?t>L1\ ýu??]F>Hvvl4?2?>)Nо…?d?{pE>OO?O?v>^ 7zMT=c?\n?V3{(e``;6?n7>D}$r`dEt?Rr z>g%.I=>O'z&6T ha>k?4? >#k%5>%?q?1/>a:ܺ@=?@?z>K?fپ{?.?x=UeL?9=Intߋl&ľPB?e?qz=(_Ũg?u? _?*E j8=>Qe,5gfڽ>G pqg>Ovut:]=v?7>W&6P.W>?i=VXij\h?^?*E? _FqCt!?\g>NDgbI3=?QT>rK NŦyY >Yy! "A=?E?0> d}5oX>)?C=OFQZyLn?R>^8?g9k>,<>Y=!%9?D 1>#>TLuΚy<[^L@?p6ۿ⽿x=&ʅ?@>2r`*G?lAt\{=r?Iq>|пᾚK?+>H-t¢*s?~N=ȿ<1=c?1>ܿ=R?> >T{Mg=鈐??>z#}Ll=3+GA?_jr>v3g\<0ȊIv?E>P}>?tʴ?2Y)?< x[hAT{?=.>0/@,?: ?HA?I664[;?>6* } ?G@uڽ w=K-?ZO׿=o*>нHQ{fAϿ5vu>5?lY2? -b0&ݿ?%??+\t;?pb=W=?i;쿱NU=ƿ[]?7=˿/|T>+;`h?qԄ>ueV>!Q?J}>-@)>2?v?fZ8"<𲅽?@"h>S:4?@-ܾtlxB?a6 ?Gޔ>YU}_??)!>'g@>k#?.>ۿb> 5Cs?L >i>B~>ĽT?Zjf?E >@oh?8,>]M>+kv? x> ?=u;*x>="=`>=nþ'?8'?o?FdNa^l?^t??jƽ.ῳϘ>s>֌>W?HkEܾ}> jj=? ~FkP?#>x?i+QP>9?~mc3=N'?0l"J)ɓҾ??<>G?7`][J=>l? nl󥾕>r>T?`0_'x>ş>?dHAI}̾X=RW\>즨wP?JqG >3%iyg4wD[?_ϒ;1z>,Z>>S3?Y?? @4@Wѽz>rE~J>\t>B?tZ-U>P>3?1) Ԫ?j=s>6Tu>?ߵ+>"Yj> ?S>3]{1>~t?&`Q>HK!=ϳ? нa>\"U.=3>qv>1́&L?l?B?#?Q^){>_>XI?)ϫ-M2>Si>?K˴?TE.I>?=?0?ߠC> ?eL>?Z;Ҧ> $? ?/FV?t׶+?.I/>- =A?u?#?bJ!is=%>`? M?]]QOF)=?T~<={o?п¿:M>AV>? Oщ>\B>ly>F?<>z->L?&?M]?$$n?+?` ?=2TȾ?`>㎏? #?7&?a4ŀ?'\[?[?.`\Dk>W?>-`Oȼk>w<>`HZ?@C.5q=>>>B>Ԯ?HP#"}~V>s,>ˇY? t?k+g5~bv?f.??/S;$A>>i?0| [@^Լ>*>5!?5ܔ|l ~Wꍨ=$O??W78>c=4P>>ƿr,?s?~lB>:>o"?TbpK^PzV7=(jM\l۽`>:ե)D>$K>vY>d??8k=>"?*H- 2r;eoPVŽ>ϖ[' ۼ:=ô?n lpv>AR*?/f>GVDP'=?3?<}?!>"Cݿ=e?M?Ϳ>Y6=>̕+Aco> B?N?*R,^82==w:=1?&ϧ?`8d=q>NLQ>F p?9!NG=>N>`?,DGқ߾W*|=?'>u.\Hk$->[?8.w?i=ON"%>[?!'?3HH=LM>o?dg>Jc7"?:?2x#=o7? ?T?g߿D="l3?q&??h@q=o>㋬?nA?="F=sC@>/ڃ?'0? ]> QDvl=v??Z=Ԁ=?Ø?N:0>e=V?I A<ŗ=̲>?OS/A+=> ?Du=8+>>?_ܾh> >Z>bi???Ͽk>:ژ>9?*\ cQH>>,Z>h?bc9>E(ZJ? ]5#F>A =U&>?I^HX=;73+&>s>UG>=,>'-?Z&-?k,>w.>m/?+?h oe>e?E{??W?(=>I?h??zy.= >H?1"B?E?5%)>L>pi?{??ڃ-[>4??^8?a?~>"?:?F>ƹ?&-> >W?$&?%>7>??z?,>Q?5n?TYᖖ?R=+??s?K?]=?)?{?c^?K#>?)V?>>}>4=?C?a>.~C=p ? ?>dB>IM?5?> >\(^?? ???DN>P?{?>u?-` > .?,Ӎ?^@ͽ Ŝ??f'>%rX D?%D?u?L>;T~N???\ydסXs>j?cx6?=ӕc"`@J?j?> u> 8h>D=GI>)k4?(0>{Ŝ<ô>k~l(>C?_ ؀E$7?'?ǾI S`ekϾR?)?g>O kj?@ k8?2*n[Y??j?:jH??@>̿a|KI?6@f?9$R h?U?&̣0+~>>>ʿ #\=p?+?RK8U.=]?\y?BۓG*A]-=%vG?A"?^Par%=>Bߓ= ɿ> =;;~?LȊA. >]?nTq.=MW>>Gq wmS8?Oa?oӽC2Ͻ >2>1{>K?9~9=?+>x3?uҢ=.?G =s*>n =$?hl=K?/>vK*-?P?#>+jakg;-Ǿ۾?S?;?qd@?;~>0Ys`oѫ?ƨw`ٳi^-8_>A%(LJ\3ud>әJ>&=">F=Ak?$g{ m=fs>zɗ?'!=S>bA=8 ov`ľ ??:>wuU5K ?4?6?7~>,>>pi=5J\>r'D> )>x=*Z"7H c".j??r>JIT??w?#ոV?-?ȥ?F7{q4?P1=P߽˵[ Yvysd?)cTDE@sB#?AO=L;Ҝ0k?6*>q J`i< ?ֲclg7'>GlH44FR6^BS=r> ~YڿAo>?=X|8n=pn]/?#<4u% 5?Oӳ>!A{JM;P?!Bܾ>?=?HX>%<}=?)=x'^꿹xO/8f?Oq>mDV P~ܾ޹?@><> Bp{<Ѿx?c?> ׾p?@>>] vLx%NE?s $>]B<=I>!?Z=9tڿ^>?{>)T> <*L>v([>R>ȍQ H?)==?.dž=M, ?s~R>K=w>:1/X (=|??>9?}?U?|N?#_- 倾}>X:R'߾@B?WI=4t=+AJ=ȿ* ?"L0>F Cп%>':y?H,>@→^W>9?h=? `¾O?6?[? KuJ?d?T>حG @qo=:e>cBms7H? ]䟾BK;Vj>C>wr1١j?iT3?C`b>x},?L>1?5?t?-F3+V?l==H,^![g>Ns??yڸi>L ?S=ujR?d??iZ࿣(Q?L3?t*?T:`i쾳?^>?{B?5 0?_V?I?[}qsPb1'>ZL?K$c9.MN!o΁>2?V­=P%P߿ '=|5>y>W.:I>-u?+>o9H[?{?l?,yѾg?_J?V?Cѿ‡> SZ>h>,Q =u>?>4R=s>hf>d4~s?E??Oz1%D ?%?X;?$l> "2> \ ?;#>ᙻI^&co?(?^?E .?? B>#?_fc1?+&#Ktw=??R5pN=7r>K=<kL?>x>Ȅ>>-9T?2\? ,eAϾ ?0'R?s?Kj%&ɾ` ?M?{?ouE-4ȩ>>9?Ry@LF>>o?2A az?Zb[D>D=>&?;?/yWq=+>I??F0K`t>OD?!J?fO=z->?=H??|C*= V??_?o?H LpT{?~? ?qv!Ru!S7">G0>N_?)]-zϟ?UR<z>V-])^5>W҅? $1>ZfV,*a >>s=̿u>S.>o>0nM7>_FžV>.r?lEF?}?3V8>G?F??IkP?X?d?4+AF ? ??6b#Ȓ?3~?4]t?c jPq`>Ѵ>?rJ` F< =k=WHC> ?!K;>=GH=>_?g=>F v??Kj/?jT@"dQ3?X?Lh%*"~ ?R?}0?w羫*?>½x(>W:T[}O>z}???*^OZ?6?9@h?z/7⿻.!x?&_??V伾>>?EZ plH>!l>@?VHy-b?Wb=Y([>?'8CvO> >ҼS>"-=EL?7?a?T޿+Y?W$S?J?2~>|8K>4?Ġ?"W?*o?aү?W)~q>?'?G(d`b$?=\=E?%P1k޽u=?X:=:? ?v=~>(c>G=V:?R/>c? h?5:?쾧ݟV>g>*?~?p`膿a>(>r?(?})A~=$?H?<5??@;>}3Lp>q{]Yj=5Mھ#b >;Xbc=OG=fE? `{@_=Rqȫ=9`? 'Կ ̽x(>嫟6ӢGA==!>ٶ?)\1 1V,<@=> ?/V>:Ὼoa=\?O2̈́f;~?qe>]d?D9?fF?=,+ >? j?@Ŀ+=?E6?>_?"H?ῗ\> kn> t?Q?9>Mʿ>?H[> `Fap(>k`?:v!E~T= #>M?Cu6=ͽ;D9>ؐ?BN0Cs=ǂh>LS=n$>jH =>c>fM>?U0ew(p>n>H\>qn7?DU5~5A>4>;@>?Jsn y=ӻ>˞(>W?x?-{ =L<35L>}?Y?3ax3=U>d0?8>=sɽO>se?=?k'=u =1?y>D>>?a?dG=pr>"??`?*=G\>D?,>R=>M??G>Z7%=>K^? Z?Ҟ> ?>]>)>?qu?;@T>Jq`B>z???r6> t!<|>' ?Y ? ;>=3Q?8*?ax7޹>.h>?Y?>Ax>$>0? ?S=` 3=&?L?>>9bc>-?f2 ?0b>+>Bh>;iU?9 ?ʼa?E*>sK>hі>iF+? .>y{wGQ|W=?Fy?&=ZP=?W?W:=P+I(k>+$?s{?&x>tQ?.O->ͳ?3?>CȿZc%=:P>)?&\<\@2>(?`J?x azIz?@C?%Xrd?=?B <>I 5D>C >B? 9:;?#?'?)Q,% >e!>.D Ad;~G>?~AAZ=?1?Ѽi࿩5b=\>.?#knrC W==-? _D=C=h=y5v=p/s>Tz[0/x?F|@C?Fk@þH>?@ ߋ>Mbe8?޽#??&!+=?n?\nE v?J?њ0|M['?H??)5(>^:J _;}К=S?F?Nt>=n~??J tH'=q?I?9:Hq> ?"?O˾ˮG?O|>=9u^&UR;)?@?ciDu?g?}>>3?}AZ=L>f>6akM?g#.>1>(zDݵ eRXS=wZ??s>&;?\T=U?>l ?Nve=x.>ȽG:JM?X! =l>1>&-|O>Y6??!??Y\>+O?F?D?.e?ȱ?p?~>"[??'?o-򝽩2??+I>оg??$?6SbC??F?Er帨q >Oi*s>tXrYT?'3DMf?*z#O=³>Խ:!}|b6Me=[P>#B?,8 6 Xu?'A)=\x2uS"?'G0$b { Ж?[B5>iDct43L?s.>fv= ͽ` ?l|>TO=Q+=+>8A>y\ܾVxA-? q󾯪zx&=>!H;o=>y<7a @] ?%>:>.ˀF?J>4V޳ =$>&=6C7m_>$>l0ozyR~`+>PDk? _=&fEYY>?B&>k>+%SqC>I?q=Wg"I>3|W?=^cdM!Z`>?\>|>CW?W?!%?_>^pI=!?)V>S!f}N?QԼKѼmGy&$= $?es}\=?< '{==?I"`zh?W?;.=nDP?8>_$|/=?.R9Fk? =Q3R?!ÿЭ> G= ?7'$? L鄰ڡ`>d?ݾj ө*>/D R?,V/$=Q$1>uhH?>A1>ͼ?q;:?T?0>>?sr??^E==ί=/I>Ϳ?2ٌ?A@S ?? ?yz fd$ >&>׀?*\eM>?炾O7>zWk>; ?K>F`NT4&x>U>V2?g+D?7>f=SfTo.ꉾ+?ܶ=I>+H? S?^?"uy0=ĵ>\>]> = >H??22\d<;>Vhb8>`>?b֪.۾A_?CȰ> R`Pz}Ǭ?.g߽>%ɩZ=>#mU=Y<9Je>6?0=G? ܺON>E4z? >uL/4>9k>f@>=\jD=ۇ>H?-?T{j ?+N?V7$羨U2? R?.3?l?g \U>~ƽ> ?MB>K_o1ܺPiUGFEnY>D,>5B.>=?y= >Ͽse=C>V>C?$] y9^>p>?{ Ϙ=K=X>, ?3¿*I@??:)?aV5v>rm?%?q?7>R>m?&>b?.%0ܢ>^9.>>% ?M)xRRi>n&?t~?uw`?"Z?U ?IĖ@htֹsžBK>bp nT#=9?<ܓv'cu+?/?? t>T<@V>"K4R؛Z=RH=P>3?%lĠ龍>'F>&?vٽG'=:>>c*?-/>>0? _1?"yi¿> ?O?(,?=HED>Xm>.?XX?4>0>hi>?^ib (E<>?9O ı=sP>1s>d?kyBqy W[=1>3f>?I;dO;N=<> r?*J';n$w.q?VS = ?X?DŽo;6&>]ĿDi>SV?.u?A;]>iէ=sC?W޿z1>bb>>?fLbr?lБ?Y?@%;սO=G?%?;|g>#=>D%?+?0^>9\> m??@>Q&/=R?F1_>\>!B?)?TKO(>i>? ?n/ < >=)? Fa9=N=_>3X*?1֮~hM=,>PL>J?qB?q=e>FE>'mU?"0 j l>3<>? Ȃ?6>x5n=њB=o]?-?:~N+=$ݵ>GP?-?b5=e>ӷ?gh{?~cZ= a=? >>U=,k=S>Ӯ?lrG>>;?%|?a;*J>^\O>>?ha>$$T=fb=vX>ş?_f?s)/=?>zk???n}-=7=zW>;?b7@=>g/w=~>cȰ 5>e<Ტ>_Ws:9>$>m?3^Xh7h>tT>/?Bٿ>UG=B>u?+?>? 29Ի>pc?r;?h@>X㿣|C#>&?>c?%O #@Fw>>e? H|' v!_m>E]_?7?bWѿwW>`J?o?ҎG>ץ_?Eo?ʰ?ս>¿/>>>> s>W`Gj>'V>*+>Zeh7s=wh>Y?j¾̿0K>'&? P?8@)ݳuN+?4y?eA=g=5ŵ?*?tx^Ⱦ3+?ZL?m/V{ MQq>ܵ?:ꖾ[hM!1? s?[_1>ЍL>1?1.O=?:xl?V&kpI<7g >6?r9v@Mm?H>>V?<c`#y?̿غ?lX8=% K?)@?$ǛI4 =0>dZ>MӾ``/K>j<=м&C>i%IA>rt>R>+> >y)b!]6>y>XK>lN1>AF?>&"?Q Ѿ^4?I?.äe==>]?*Eh(U$?ƽw}?UD1𽼧?6?@ڻU=`0 >s>É>XJz?",.>P> >$*?^?4dSr=jBpc?C<%9?tC"Prһ?2-?@#1Ϋ`G~x\??ة>مRdz?>?K>ЅIpr??+>_Y盾_$?v?c>?}=S?>6-\_->!?YB_?%=œx?l||p=6?'n>C_n>{?$?N>`=<7_?S?fs>*|@B=C><?Mb>+]xhce=>mf?Sz>!*Rh x=?{õ?>!'J ž-?v?'?KO/?/!== 7?`w"A=b>GR=ƾ{%^lؘ/4 ?y?b?I?E%1>:>Fsmn>Ie(>QЅ?ʼ>tY=[5>± %>B>;=a['_4Vl=Usd=G?A>)S_>u`?5>\-(=9;J:Q~> >r;C>u?!_>4`$<5ƾV1Q@>#i>= xO ݱ?]7>Eg?-=Ĥ gY?HT=3_=a߹ٔ?# 3ucsęB'?VsLdN:ھ@V?Lh#ng=)nY>]T!v=k?(=<_΁Ywp=]> o>=~Q>ȄǽC#)GL+?MIk}>~G={ۜR=!thg=h'1?>hL˽]xȽ:;?b=1=$O:STL?j(=?:>1?"9"=˾ h?>`g>4?A>I>C5?*{Ҟ=ع1?6 >p?"{Ŀ3r=|KK~N?%IR>޹?(|x=)ă?a>Լj}[=ZS?A}>>?@ =ѓ>.do?Bt?"~HV{!l???z:]X5?.E,?-9C? g5Κ=W?Oym>?[1=Z> _l<>? >y-)?bv.>2>Sƙ<ީp~>I?W]>')?6=.G>½>Ӳ m?#?2?<XgQrB?2(F?<P?7r'N!XvQ]uy>&&-?&Q>Ur*Z>j? >u?4BV0= 1>Ծv>?":*^iƾ>>Z?}/C}R̢U?E)?qϚ?A!e(s?UL?s?S0/n?ɟ>H>v,?C?2i<>y_>JH>{?%f>>>ʸ>u?59?hE0?G??e| rg>E>q?"Ƭ_jp>RH>?0^|> >g0?sRV=w\> =?*h/2=̷N?)t>Rǹ|=i?z*>eY? 7[?%ʽ\W>Fxf?4&a;V{m?A=  ?B~=bE I~>?M8>}>sfZ׊=>q>P?bԼC>ic>?b(Qf3>aV=o4U=a>Ex>I( ga;s>QixK>>XY`LG>">g@-Z>[?Cy:>E>I$l>u?=->5??ee= o9=M@>>:?6* ؾ>??mR& @:>[??mXuGe>? "?@nK 9Zg>3??@nEV9=~>b?JpxdeJ2/>eR# mڼ?E(A潗>>+?rXht0ao>t6?>*@뼽=QV>Ru%?>!?i>>q+>WHA>Tv;D>2>_u>@?RL=aRPY=FMf @>o]f :=i?"msoo8¼Z=!)?N'>Du>fU=l=`3?O>֕Aɟ>>Uu:> pC?$A>aP>_>?\zD> νZ漋>"?EͿ}C$r>B'>/? ^?U>>6J>A? bk?͚`= = J>j>d?eſ) m<ӌھsi==?Eݽ'Կ=?H:>-?+$1? C>0A'pz=C-?]?FF>3R8 >9?r3Ef?=ȷ_>*?<!0<<3=,>?Xo@S=#Q)D>"ϿNj=뾂1k$>x?qCU=ؾݔ>T?/?>ĺ>6lc¨>g?nf>tm[`k>nL?x>^lI>?73Au8&=ĵW>'?k9}ܭ=i=>v?kϿkT=06> ?0<%= jr>[W>i0w=ȿ$c->uS4L=n^?>b?U={5.>$)E,I=a>rn? c?GVOF>m@>O[?շ?}-? Z =kW ?^=L @>>+I?"_?Zx)> Yu=1>r&?k?z%i>?Gs>? ?~.?C)<>C>__?V?L?1q*> s&> ?Gf?-oL>:H0>vX?"w?<?4>7>sK>g،? $?4TIF>Qҹ5>?P N?a?X>ƼH>Vo?[ˣ?'>>S U">K!?dj?>$%Vi>B>ٺ?l\Jh^?~?4?٠0>J́Y>F?u\?>kl0OU>???*V??̤>XF;؄>tX?]>?!>07W.>m;>8>{Q.=Z>$>?5: liQ!>T>?[뚿6|>g>^x??N9ڃ}?=8>Ժ?|{i=C?E?, x->fx?Pk?SǓ\YE ??fsZ9~?O3?qCɂEB[g>> ? pڿ&!za?.I/`? @??>ǾP7>>Ф]>pYCd 3l>3>׌>K E\>2n>;m?[>~ýƐ~<ı?N$>&5ˀD?Ɏ?S">s<9c>@>->ؿ&x37L>>D=>;Ԫv'AŚ?q$7 >uoXT?c6|):>)?l/j,8Ňϛx?!˜?[WqCP/= ?"t?E9SIǽW?-6/?/a#+?lN)5>$?C>*V4/PC??^H.pT9:.?A@?gȡ!M澊?Jf?>W2p].Tv?Ak3?bk/=*?">?]d>,?al!=s?!ֿ> <*}G>$?? >dc2>b?T?n>?y9t!Qcg?U%9?Ĺ)%?$#r >M?j$&B=?O>ݽ# 'a=|?? ?#ߓ?h?`>7 H> {??pƤ>@"==?^?>`>(x?"=>sھaMwd:?-? xF>P=0O>`>7!ռ?a>?8J>f>w$T?>ݮ/@|$=oP?2=/Oau??L?4~01>>U=D,DIbV=E>n8_߿3<Ƚ/(c= >A?QBp=B1=+qD?; >hX}r=(14@y~M8T>ܦәVR AJ0'PD?*ս*&/" E?kb =>$R,^1>>(E=ʮ)CYF??>d>ѿ?X{>Q>6%B_~yW?b#?]}># >2?VTa?*R?O>2K4>XjQ>>>1f5h=էҾbA//ґ 0W&= 08? 9X=eҿ67z>N=97>Oj+?D=)p? 9C>r,֙ҡ?d=l>*q>QL?X;=w>Z|r<ċ?G>hn>40Wv>w>Vq;\|~TM>`j¾ٶp%6 K]>U="U*ؾE9? O1"\c?c=l>c/ He4?s>>Kf]TQ ?G<t5+?iB> e>Bh?H=?Ex>(>u?#Gٮ=E>z_>ˇ{m0NJn?c=> !y?Yi=`>Ntv. >Ȃ?a*=W>17x+0!b=:?R>w=?k >$b>Hc,8mz%= O??o=,>4>n zC^),tV>_N+˾]z۾1>iI|l=ǰ?gt>FO?|m!lS?2&lpsіIV?H{=t!?[B3߿mY, ?C?cG?E7!R~?c&?Z?4 Yhwþܘ>!}?W!?Xq4@=0BS>2?'u.6 %K>~&)9?~>:?6hn_vKǾ_-k?Y\~s'?~~>?+=o ==,4>#? $}܄b>njC>3?Y`?N>?ȓ?ug#J>??VnsC߃p>??]=)}-:??>?SIj3+Ɉ ?qI>7x| *?]>K?!Zb=W0>yr>6?6yy>>ƛ?+?HRF|/Z>G*|>?5r&@Y>F>x1?3srfK<*<_g?0˾0I>ȲN+>A>>Ǿ>PgV\pJ>\?bJ?c3<#1>S>?=S7cgþ?&?I?ʒ柿\3[̯>ZW^>4<>6>?Z= =B>>?]~CN>n>ǽ >T>I=> F>R?4 o\=ͅ>y?fujQ36J[`ֿX|5=Ɏ0{t>Αsvq9X b>őg Vhc >3jqRȾ>QDԨDO=Qz>M2>T?`o>@ 9>a> _?o玾o \>;+>M> ?ο2b_>CCt>>u?tЁH>\>[}>Dx?!cGv>Z?? ?Ց2@J}=9e>>w?h+>(??(?8j"^h=CƾOD>̼J;_={) `>́?7ax1=e>7?#>ˉߋ>=f>D?׿=G˽Y >%p?Pu?s^>8L_*>'?Kr;~o=>n+?h62ۡ)(Q>? _?J\#=>q?*$h?ۘT > =>{?4#eX>ۃsQ>(?D?g:=Y>]4Y??rw?wť3>>=? ?yR"!2> >+Y?/^?G>'tiW=p?w?yQ)P=䜲a><?>?h?-}>e>X?)eo?f?K_%,> g;^>2?_&l?v}3>5u<>?bWCB:,>L*>hn?,.4D.>x=||?.?e0>@XX=;> ?s'?9ND>7k¾E=cV>3_:1>>?6?]>_DN/<=/>LL@AM>q ;L=?T>iVi> I>nO?ꞡ>9ė>V0#>?ܜ>:ҾZ=?AG>f=>QK@_ >F B@ >w޿ Ƚe@ I^M>z O7b@@7>"! {6ּx?.4Ԣ>J*i{#?g>A&cھ?>*^=?L|>5V=Q~? >hU>_w)>?B!>}Ơl =%=@?[d!5>>BA>H> j<>Uy?(U?>\3 0[6>^??I Eg:>>cR?{%пx{]'=a >ߛx?q׾<}qL͟>4K+?(?>u! @M6>w:>K? I<-K>\t2?6?加?'`|J>B?4P?ϴ?3$S =:?X? `>|oC>?"?W>_Iʴ=(t?}E?>t[pBsC?Q?~?1tU@??.?qf'ںaFTL>DJ>P[}>iDG@D[>!^? O3?u8zFQaX#>|Xh>B?/ˈG/>u>o9>إ'I6^]>s>8?^u2Yq>}>Q=?K?6е\=>Wy?|_h[⿥3Tv ?MB-?`=!lgo=2K>e?U[y#HVz>=l>qL8g`1>.N'>4=? =criqT=H=/w>e\ @=%4>?Lp{>k>C?z׶WO;d?y}(ʩ >&?yΎ>_N(֚>j?*o=s;?-42aΠEb?? >놱D6>>Բ>7տ}:\)>LH>=DĤJힾ1?W?=}sR~@; =*?}? 3#\"C=,>>os?x+'|>*1?3d>,=@d  V>:>}?-?9>Ŭ>?j?[>XZ=J&_?[?ی>9`KE?<\Ź?Ofc?63?w>ts?sf?>E=oć+?HL?e>5kDP/;s>@>]>Jm?x5%~=q?>|= ?q-;>n/{?E?>3q[>V?S?t? Қ|> |?":?_?+?ƠȾn?\[ī?T೾&?2[?Ic>3fa{?)O?G=h0~ {??S?kք>;cѾd{?o9\?u>5+i^?=:? >No^B?6ru?4=~c>eE?? ?M5iĢh?},{>OG?,g??Q,奾@?c?+9S?; ,?UFJ?3+?1 Ij/D ?S?U>Xn;׷z =w?? ?<Dtzz'?pl?!NQg8>?^ݼp??1"@=1>P1c?["=>ӷ>#^>$;2=l&>1 L?w?R?l;$'9Se?ύeP>j (_("Q?H89?O"Rv  9G?kG?VZ@/N?O>;Qא@?+`?,;A >֡?63'vv=?B ?w%>FVcJ ?Rȴ?~B>ŋs [=>z?Q>}P1y=^>}\?D>/ > t?>?>_U#@O???:qoc(o?ϰ?;?,b?[[??FIq??3v?0+?K\ixv??R?b?)>~>Al?e?X?I(&> =>1?\??B'B.GA?3>Ĥ>bE?eu>υ?>?j8ƛk>z7n?od>‡@t9??$q O?UQ >CN>v@?R>>VP@0K0?A`>">E ѽ?IG )> .Z?72{wvȾpj4OV2<>ޜ(AO=3=U` uo@S>y?>l=%==+Dy>pT?>>ND>ب<T>)Ҿ7z,m n>׌4]"ZpL-yHHDl>?W>'ʾFͯ;G|>dA>u۾ .ý>Ѐ;#> >Bt>@u>?,_>>>t~;<>hȬ>=Z=> f<˿F>=:|c.iýK>F侑?l|>&)(=g> |fo= Y=HIھ2;A 8b־*5=G>_K}f>,=|lMcύ>-b|<`c*!]|J=cN<0/u`V>a==~,ZΣ1~8̧?q>>gW}>VC>?o" >_JV>Gobhpu>$>N\7DɆK|>C>|D=k>Q"gw>>6X?6B>$>8;j<=F?==p>P88.w>͟>&=HO->!`>c 2E,=Av>>Trƽ|>{?r=]><$@&KOa?g{>$6>)#+^??<=>8ltd,>,>~e?A>!=f0=?>=N "<Ɛ޾G|>,>Qv>S Uz=LS?c? *Hu> ?%M?<"?*8H'?56<>$FBBBBBBBB@u$?)?H\?F9(*A?Ͼ >> F=YِzK>A>ȣBBBB ._l$΁> m?pt>gE?0],ЁMS?3?Sb?hBU0{74>o!->p?_>L=P?/>Ȇ?c?$~Y=M>? o?YCӾ?zB? {F?q5;Z?U>ݰ?N&?3d=>P??d׍ ngZ{11*`:MK'+,A?$` =? Ʀ>!A?dE>v ?-Dt;7Z>'>vGg@o ?M>?֝Unhp@?!45?)5=>ʯy?)?p'? XC=y>Z?C?rq>~=}>d>G?c6eպ>? ?euþ^?Xb>zr|oNwz?B2Y>(k"[;f[>.ݾх=FtNe\Y>?dˑ.>п>M!=B>7A>W>a=Z:>q?HR?aF>C :=? _??ޱ?>uQ>Lw?lQ/G>abF=>$?U,>o?g< ~C2>?)]>@W?dw>͵ R=O>.>?}h=ژ ?=??Cs^ н{ٽKZ=̊?6f +5>U~>+?m@p L>|g>\?yd q{,| >XK~>umn>VTx>>[^V>m>A4H)H_Os齠6 9ni|P=c|bߓ*\.?)l>?Lh>4I><;>=f? >A k>h?kuTy>!/> |?y*Ra@UË=s>x:?|?/>D=y >> ?{3v'Q<]n=>m)?RH+^Nc=M?w?E?o{N;=:>$D[/>6>28T=Ҫ>n>?q==?/s>?=7v=v>>?Rv=#>&?I?h?j}=s*>XA>[!?oOl =vW>:f>~ ?gO(_7k>I9>箼?? tH>.=.>Wr?(ྃ m>Ał?>U?8뼶#?>77?*>V?* #j>\h?1>0?"A>1Q?;ջ??w9~^>->&>?:<=&J>c?9?M){=]>?!z?+?xCm>$=ͦ>qNH.E==?uiQhe<Mi>஗@i+58n=?ſ/e==ֲ*,=`?ĬDH=8>@?+?> =yHVfDؽ6r>ŀ?_Ս==>5?BY0ۙN=c=l,>xs?+%ĽNο܉v=>Ï? 3?r?!?}: ='{=JA? ~??ܿ=%ս?;<1>ۖF"m> >DR? N?@>cx t=7v? 俕|!W=@2U>?LI?n+"/#=>8?,u?+>S$V> ~VS\>~.?5?LW~ >,b>s?D ? OH=z&x}>?B/? ">s>K?A[?2A&=%=? ؐ?5:>O?|?w?z6>k>L?[Uz?> 0>%_֕>?Tfo(4z>F>K>p?3?E *!->0>\?<[?ʧ?\>NrK>H>?J>rT >=r6>N?.=qe>u6> ?>"DI^>b>ͼf?I=F>3Q>H>h]Vq=7!-4>t>!O?yx}=\;?>pN>{?$ =_\-?I>Dk>">?A>)=8>=?ŐC%s>>1>f? b$>MN=b(??E$>H>#>J?1#>u>D/>?ТK>V>P >?U>tڼ=M?\$+>v՝>Ɍ;>O|=M8>'?!)1M*B)>V>ц?~t0s/>>s?R:VH>FU>~(?fu>Y>?.O4Y{>L>i?nӾ{_ >cM?ė?Op[>n?c^?nB:S3='?>Zm̿_ =o$?"G?Eb>$?ov?7"qVsA?$B?A抽1W(N=#*?C7?!>zhn= 9?%z0v>?%7>2v<(m璽'?/?R7=(2D=OҦ=N½DԿ$u>8>v?4>~N܁O=(?@ ?l +'??GiS'>2ÿS$=мËdI?}*>0O?Y>=hdP>-f>rkXj]Sݽdf"4fQ1fY>=ž߬%E<^Ͼ )?xx& =>H(=΍0B?},i>=>>:ree_>f{?θ@?" b?+4??sNP[p?Z%>)uM >>X}RLQwg/=??=//@uAG>j>vKEPsM+?G? = KG|=M?h??v-yH?&l?Ϣ? !3Du'?Jgs>ؾ@?Q?Zw>#xy?R%?W>#U? ?)6>(RuIA?cʸ?l> 1M?`?p>4k=d3 ??\ ? 's6茰.?*;6?LOJE:E?7i?)?7?$u%= =L?Vq??gKU=?T?r*^?A6Pr??u?sfqDfM2>\?b?Y)?>t)>dК>?B>E?.Ͽʍ;>jCB?S>nE=t2>vB>?`U>C38oL=+?@>X>}̿{3`F<?]>Z>G=":=rQ?-7=0g#qM/?r===Mv>پ={4`zl? o߼sy:ݤ= #>ł5Z:&@t/?5[Hi.;?%#f|Pm㽾;?n??(8:o>>=z[=釃>}4pi=%>2ēHxr6>?K>>h2U娾=P?/+V>Q>q8ٔ?I=n=S9=?KǾA=;k>@{P` u5L?0g>3'$>d9Z⽋.?= )==T=lg>ݣ<8EV5ptWZ?n>0>u7D?>[>^>AR;=bI>">;?3v<"=0>W<<>6=UUݍz0VP׾?>>>\D>.?q>whZ>>N߿";$µ>>17L t?IuK>-> q|4?e/>y>/ $n=?IhQ>5ƿ=Hv>'B>Xp*9n=G[>O ?d> d$>G<>D?8v>M>=gF< ,9&>q=t>Db% >U"}w#O?Z?=M>/&>I >q`3pv=-(=lxd.UbQh=u=5_=DM>?p}N

3>^?JK=@>'Qp`!?O5=9>M>4j?f}x>'x?i>kp =:ZK8>??# .X?h2>>>Fw̾2>斢] 5^ʼQ?xW>u%?!GkWP#F>aApOn=r r~>߽I=:|΃\=V?.w>̿M?A_t(~jʾ3<|t?ex>S>X.rJ꾕?E?+^?t^?g?? > *(=b<݅><$?E??&=+Z>z` > ?O=)euXG=09e,>~?dA(V,>g>I?lzP{}Iܾs7>ёpz뾜Խb>">پ}? ->-? *6=:>[m>^?Hg!.q=3>(?f+9>iU? ??E]`c?!޻`5>mq>X=s򇠼1>љ~=S> |>&?Sf7?nowRTox>qy}$_[< +>??>/z=6&>=3?@s>%)=ap>ʴ>{?`y>DowBNY0\>Ow Y=[?L2?y?Uu>K<ŗ>ۜ>?Z>0N<W?-+>?\=W!>E>f>Pa?lb` Q?3>?/4U >D\>,?0?L3ǽ6??5&1? ( 3w:xp?KU?5E?IM A"ܼ>??jM>F"Eղ>+>01? 4>MU?9K_^= Ƶ`=Ib?>UMI=z܉ P>̙YI(*|??9`?ݠTpY@J?Fy5?~a?,c <>?շ?(ց{X`?L="Ӛ|??οfy>E>6?TO~<>S>͕?ZoƿAi{>Ԟ?f??@fÿY>i@>hM? ",>/?1? ν(>??I0g!#!fM9=֌?FqX6#?8?xW>$t>H!)> ? ?'>>Ym='??eF>"(VFn>g?4S46>??<">>>>=? >ZK`Ũ>ȸ?^D>Mk>P<">l?kٺo !S>$ =!l>?}g%Y>C=N>?g،> ;>e=@}?X?|٥>ml =>r<{g=5>1??;K>Rd|>oKf>Ni=`? ?OhZ> |~>+?W?]4!|>)>GI?]|3|>[>3?z?.\-@>>m?Sn%xO=>H?< ?;/$o><7>Ƭ?v @=O?t?3u=yRhw>uR?D?6 e(>N>Bs ?K?C?t=8v==#>??E Ӣ>6>wĠ??Rna =]> ?# = =z={?f0?.?X>1>4??U4?{ ==y>?*b? `>0H>l?}?D.? >VG>6?+w}?]?D >5١>,>"?+~?X (=3ۦ>|~>y+V k=?S?9?J==6i>w?B? I>Wy>Jw?5\?frC>9C=T=m?AJ?,7ay><斢=t?"?4C6/ >[?gm?~?-OU=裡Т#/r=|?$u[>+sB$=8>vSC?7X*>7J4># SK(%>= ~>V>z >!K0>l}NR=>+ (>} $->>r?8kr;=ᚄ">M>? $C=VW >|>W?y =t>i\> ?Pm@.L> (>֕>1<.z>sP=\S?,>[>t:?$?:5? 6:P>>ܔ?O'?a?%@F4WX>Ra>fZ?0Y?G??E/s>ݭ>נ :~=\Lܘ?g؝i>_J??7.:su>uo>R?oYȖp}>q{?/)?)o9|B>g[>ѫK?Yվx J#=?agQ3M}_=>J(ɹC=?fD_>yz-=@>?xV>')=Ơ?NUm!}>q3Ř=_ ?k4Ҙ$>*^??=-=sy(Q_\>%?52ƾ+L<,?WA:GMƂHh=/>54zu}>h?=2Q>?J?c|>WP?GZ3>?..>Ҫ> x 9-Oj#>:>>h 0=Oʼ ֕ %$???! 3录??MQ?pai<;3i 5?v+E1>V=oa&Ⱦ=d?НI?dJԨ?P? V?ı݊Wk??]?h?F?Kn>o<'`R|=6:x-8 x`?fF|%/=uX> Ǿp?M5B`?g?$aO^Iڙ?3-"?4icc9ຖ ?]?f~3 ~? $?T&<*?VC#=ύ>?}<R29Q:=>?8 >RXlھ/?(?QuQ'>Fh> }Ap>%x>0R>=i쾏qCP''<>ZrW]> $=ý>_弉/$ɿP|u='|??h>&O׾4?"*? 8>E xcIa=>{ >^l$`?@q?>۔>ܔ.b>Oq? ?.?+jOݵ>(8??;?Հ?-FNؙ>>e?A%&/վ<~?s?v?TP;Z*Hz)?"V&>>: 9&9??'"??3&4?+?7? 2[? ?z?? lC9?kc>f>6FdeԾI?!cE>!>TSs> x(5e*||:}N=?3>A>@ygd<1?/ˣ={o=rH?x>_t>_PrT kH?n2>> 7;Iv {>\{Fo2G. ?Ȩi=%H$P[QE>[<m=8<]l>e=vW=d>.uu=á >dH:05#1/=F5>i>I>Մ>4e=B==2@4'@Cl>R#j&Т۾H"y?GU=t>9,5JZ-)??Ƚ*7l?X>|>>o7=u>;y=V>W9-E=S>^S<t&Ǫ)Nq:?Q? ?#u+N.Eؕ?>j?O.zij?in>?gf$F_x? >ӕ? aH?E>2qz>: +=릭- x>?)(P3&{=d?dL>>'pGI<=\8/rB>{D~Gh}>Sb龏WU8s5 |>&Q3>A@XoȽ8Z>g}m|-NgId{-<>lWQIP-"Y==<nFoYs a<:mÓ>>=>bx=kn P[[>$=MN->V?\">-wJ|>E=T쌹=+ >2lL{xF ~ ʎ<!s>>08 s!?H$=0,w??_p=hf>_D v ]>c^ <0>? F0忚&@'(z21(ӿ1P a@j2;"Z+8 qƒ$@)m=׺zWbKYtz+xWCJ8(Z4k3ǰ-X`ڡ# 웿0ՋH#B{o?QF_>3@?>L0>Fb_;^/ژ>>#nA%9gmY>V>2v2>AL#.O~Z>>E͒/I=>gT?|`>1=\ɽod_y%>I>@e=iU.]h<&6 }1({5RZy&Rb$Շ/R7'}qE> ^>S?Khl`G?*TR >dz["3徣0? 7u>[$"+?tJ>nZCwhZ>Q=ł%bZgy]>>'!6<ϒ{1<>2=X>D^9qmqy_>:*>?=pPp>>澔q=?W!s>b>3׈>F i >:vhw,@hq󧏿p/ 0 _ڿ:g+O(|Nt[E`p= >2ؽ?p>M?U9:>>7;$>D=nw>v<[u6xpT;\mK>W>_>Qe*&=,$>6q>\Ͽı8x #$FD1oizԢ n X~sCwܾ=#/E>vZ?9a>ARn>?`Մ˫:rX?˸??P=>}b>%lE> >Ab>a0Q=<=_cߵ,\{=>% >gCR=piz=Ӝ>_˒mU=UljH>>>ltED>F`r>V?>K:i,s>7e[>A_=Uh=B&V׌=m?>Wvjz>4>%rX>Â#`B>>Jwq>E?NltE$?F > `?> ,E5=,w=H=n?1˼=?3?1.?)"Tz?9?9??E_c<5Y>? ?GH0!Q? NWU>Y!%GZ>剭>H4ob2\Z>>^={>1MYca=8?ϥo#ȼт>Yʖ >_taNGi=o#卛3W8v=d>6>>%q = p>N >Y9e?<> $t=?!>Ǵ?7v>( #w=?6Y>?@-T?=*A=PU:[?Z @P>>6?ËſR9>4?B׾&Ed=?W% ǤqнaAp >̅Q=z2+>ty<\b>VpE@>>&N:N>|Wnm,hza[?3?K>.> ==H>D ۄ'{=>V=?Sje d8L>Ҝc7<]AB=t?g<./>&6*?E >/M?Ir*EF>u?e? ?Oa6 wr*??J?1>v>G>>x? !`4!`>N>E<޾<>Q />.z>Ȭ>O?',Q>??  @_>-V>a?K?ϯ>8>UT3>? t?D <>i>}R=? ?l +,>h>ǟE>t5?!=?$s='d(>?0?>`^3? =?8?H?C\>>>V>/?D,tlZZ>oy>O?VC>諛u>A+?L=D>.?>7Z l>=/>ue>b?/EZ>vS>9L> ?<U> >;?~WC?M=3ϼ=>M>d=?};K=->X?#ѫVV=oμ>?\vX( S-=jw?=>1@?/07aLE=XM>u:O=] > =?U([8=3Y>? ?m% :B=5>4x7Lo><_~>sd?,_=/׿qC﮽ ϖ=n6/Ͻ<^K&o>?BqĽ=m>r`>z?u?>Z*R>ݾ =?)`?U|I>.4=>?Pu7ZX=Đ>G?G ? H=۽>>6?kUX?W>ƒ>K>޼b? ?33=B<>z5?u#>U >??la?/>r +=">v+? ?SO==OU>Mn? ?R'п( J=)d|\x`IX=B>h迕@Y<ω5^l=>35{> ꞿ7{=ȴ9>G=/&_>C 'QH>ElQ>v4͊6>Z/X=A5C9`>KA:f<}E9]? 4#2>8>}Z:?V?W?d$:n~>*D>s>s ?g?lQ9.M|<4҉U2(>%>,w-ѻ>*o,I>֝>?#X'r>+jZ>>2>)>z;p? ?x>r2@>bſ>d>C=4Q>ɓ:C=߰>@K3>0_7>q >Ej:8>>.M>uu7V>@sD}ݽý =\%=S>H?7)> &%>_нe?9S?H)>7H>ڴ?`#Z>lJ?;?OI>0]>Vn/?? ͟,w2o>0 ->^x?hj?d4/g>HW>l7??[?gp8{>?-? "=Z=Р>??l6]=>k>??M{!m=j$t>>? =]^Cg??/?N ='n?(?%AeM2)>{?|B@[p?>HA2 N>K????w޿Z!kD=~M>@QD?" ?Oel۽D ?@?z?5?ۡmH>'K=&.>x?C?inK>U>?ו?Zއ? B(> S??h?r*:>>yt? -?Dl>"u>b>?1ڌ?j?&:$2>,=Ȁ?o?oG?E?#$>q>Vd?L?D?9u=L8?F?(/>z(پ>?#7?W?T?{x'X>G?;?|=?[6?]j{">> /|?H]?1,k.>b,=?=h?s7,(\?C??1>՜%>CWa?N\?),&2=, O0>>A>T$#w)>cw=J9?>GYwl0<ƾ(>>{>+=OھpL>n>C>}e:=2=? z?(>d9rT=z > >H9=:=??? M;;W6>j?Hr??d;k>%wS>'?7.?MB@} >g?S\?9=r+?㤿̤>a?T8;??`i?=k?^}><?V?<S@A>-??Z$?">/ɼ@?`?>8?=4@ M^?oL?%?~)?o߿G>V>(?2ᾴ@>!>C?G?Qu?es>As=X>ޓuh{=u> c>Q^>zZ=rfG>KIX>=K>~V>2?>Bi>X?*?"ϔ>H>n?s@%B> ??vEV ?=D>>2?97G@ t`<>??dJA"+@ /ɛ>t?M?\!@ Ç>l? ?fkx>L?Oʾo@ 5>& ?L?>U;]A>S>?+iz%+i>"B>̾?]ݾg9A|>d1?0S?x {pr>-7?I? \p`e˾%m?;??3A3adˊ<+?>?>Q mibB*?]Dx?t>z#eJ?f9 ?>sK(_jB=>?B gH>[u?D}UX(Dib??]M?K>/(fh?`?`?M>@$ >q?Z$?H?`=@G\>\>x>.)P FaѷZ? kf?dsaE!jG=;??ci=A g>~c>U>ɿ}`nT|1>:y GN1=Eo?2{?^? C( 6A<}?Q0f >փ'#?!?B4D=>a :U>%?&/Z>۔=4"G=5>{-??d>-/?(4>>^ >5"80k0ƽ;~=`+\:?$?K8Dj?"Q?2a>!pPpGg? ?>%?Ty1>@ >P,ݾ}C?ry->D>AF>?,s< y?O|0L=خ2>y#>O^lj<?ֽ,?LTf>T?:J{&#O='R>l =,%WcJ?e!?v8e4URGa-:??d{*o=v> @!Z=8b??L?b#>W[?ڌ?>7?')>Lr?l7>*5?ĝ4j*>4f?1PU>=A?Wb!Vھ}?ҕ?[o!pt|?kv>p>0v>(==fSkd5v"=>Aq?= $?~?#?QЦR;?t? ?u5V{>+G?C?}?ߓ_>`Nb>f?.=o;!>>Qe?.jU>%{WF,n?4P>lj>3pC_>M>*?I>౾F0 6>7~?L@>Wӽ#FV=0 ?<->>6u>A6Y?U >ݎe>ʯ9˫dž?}?R?A-ݯ>B?9?B>2zg)U.>^5 "?,$_>i{>4 v1'_2f? h>c2>$& -i=V>Pr=N<|xb7_> ^!4=?A>m>.A>4v0=KI=dо9P7? 07=m>xA<Ƨs;> *kL?dEV>q3@F='Ͽ2>Ծ(\}ek$w>>[;$I?97??U0?Q?bV3i?h(N>[S >m[>)4!q?n?>\>,࿋A=&>Z>W/==RH>"W>{_=AYUf;O:=kʾe* EoHWi=>v G=iF/ o"lW)^",>pv!DF1p>>PM [uh=S>> Rhۻ,y0)_?Jr=>Kb0<(5ֿ~Z-xjw >#),'0ζ1ِg>m)q&FsW {p٫=?F9:>9#? zO _>U]/v>L>[c0=\_/ !;<1 E>? g4H!:u?(C{.F+о.E^G>Z"œ"|x.9=\XI8zYg.?=>0H0H?>?>GbD={0rN[]h>Rr?=S>`p@MF8.( FIzc_9)9`R&T>J?&0>E4>=?d>Z0>j?g0Qk_Y(?>=?pÃ/c? |_>A[f>Ӿ@&8ZGx>X=*|>+ǿ֩aR.>1V\޾н+BHҾ4ƽk>5T?Pe /욾^RU>4=9>+E>s+so>W>H0>s |[>`><8>R3ME==":9 >Gb@=oi>B>W?Nu`ྟN>r ??}"Jx %پkl>ۛW??V>?dV֘@nf?j>1j?A\W?c>u?4m8z=lY<{mg=>Bʛ:=Ңu= =CRh>>]̾:Y>c̿=Ko>q,(1B&ZvU>>.>=yS>O=&>VOv>^(%q{ >">o4>"=g>}?w}>,[?뿚i]D>>r=>$տ8@QG>T>o/>|:뾪{??%?,@>>ʹ?[Ԧ:?,/='?z)Ucg=><?a%>龇>Bz>Oq;=϶>e }>+?VpK'>4L>>'?>[E=V>=v^?l >} 4=9>*<`?dCpA>D? Go?Gxƛ˾Ã3f>ϥt BB=dM? _1|{>Y>4k?`W4>ꉹ9>@9R">UP.~>>4JM =>sщ ?Zu%r^>V;= N?zHϾu%>̽>7?&9h= >4?,?Ȁo<@J>9c>t?nCqZR;? ?[/?RLu:*d>TIt>jc0pQ >v(=6>BWfGx<ѿ>Ѣ@>c>4=?R>N?arRl2j>{?A?kd=j>?;Ui?#~\=͝>?M?+X Lg=>O?Fp?[?@*l:?c-?1>,='?B ->?>>6=?V>s?> D=9?7=/|$?=)O;s>b=5?/41K_>=M? ubA*$,C>W>%QP?ľk?C$y>i}pbR>,W>uS?Gx?ۡfY>H>?2x?(1ke:rM?f??ͳBi_2.ӾUݐ>g?$+?csJq*I?1?g?3D> (=+? `?>6E=> q?:>N'[?%;Nl=> sT?d41I>o'?xɆ? ? Fay}6}J>1?3>^n"?b[-=>O?Q)V>X?+뷾Bu> 9??z=O%尾)z>_Ȱ>?@y.X!5& > ?3?meb3=L>ڢ^<~_?<1%F>B>@?9)݃<>W>?+)XO">3k>??lG9Vs>p>dǰ?"$?7^Mz>w>S8??xE+>PK>?$? ?!>F>u?2H?%r`A=ʑ=q>?Y[8 s?Fx?Q??. L-k֦>f,b?{?A~ža> ?y?o?9x> V>1@>T9<f>8*,^&mv=5U>>u?N?g?uۃEk>K7>f?S|? >y=#e>l?~9m>thCľDs>ǹ'>k߾Ǿz[mz=)wW >*e?,\@#ORJ>b?V?{?46<>>u? b? n> Xھ=PWN>=>+}?NS?ٽ4!?y5>w?@?pG@?_?O?O?UA}!S>#9>I?_^S>4=]?+?}Q=`5H$>=??V:ǟTpP>|5>w?:9? [d\һ>.>3V??|VuV.]>0=s?W?oW!;Sh>[?&#$|O۽p>1RbV!=@W>%"d$<j>P{>률?VèH ^[\>8D>?Q=輖ke>>JA?dRa=u_l=M> =Ȏz<>m?x{'ϿB9>S>?'}1? Z= bw5?Et=jN j?]>cȿ6&^S?>6ʾo;Ĥ ?q>hvC&0>>nv?XH>ZMӽ [/F>tuU~.="=EZ}? =?{=1*6? j?+==*=0<=>PH?| ?:-?~>\?59>Ft=]A=ި:?x#>P>'_=jM>|=/?eJ?z+ ?>??7?WH`?#>@ ->m?jq\>?Ӏ=;>?N?7 ;k>=o?^?og\=>.%>+D>'=>`6=`f?Tl?j鼿E;żG>?뽊}{Z%>?Y?ko>b<}<(>$>ʗ?6>s==|!=> J>>:@ٿ{l>>?36?h{V<<>P??#/_>?P?$?xac1=>\>?vĂ9>Kib?'?4:=a|=ǹ?\4?n]|4M>8"> ??q?D>U)??!53?m?"k>(? ?һ?n>>`l>? ?Vd?j =">?;Ӏ?]#>?3?~ t>K? ?2L?{S< ?^=Y?[G?w} ?S#>? ? #?s[>'??lɆ2w>"?7?,A?H,=Gv>h?/7FO>sO?7o;?c|$>Lw>!? ?+6i?no>wƾC?{?I#> !e>du]? ?V?!ca>L>$?{?YͿ$3c?-@Q@ ?y?``>?.?_x6=ˉ? ??K?'B,> #?'?X?n߿>>P>??k??L#yy> 8*> ?? 1;m>kB?N4v?7z?ϳt.m>Ѝ?4I?L>ٽr?%> >+>T?@' >=4z>d?#ݻ;"J >jZ=w>H>?;?P?ϳ???Br=Yu^?1`?!Ξ?(as=?0@[?_^#J=>¾Ӯ>>n&<*gӛ?A?z?Q?j?uX-%,\>>E? ?=*>Tz#B1>2@gq?[ ?J^>7%z1>YJ?>%?N|J:k+u>^fE?li?z,)> ؾ ?|O?/ARK+>u[k+??GZY1Q>o_p?b?lA$ 6g? V?!K? M<=$O: ?\?9h?"V==?oO?=ؘ-*])>}]h?MH? 71> H?0b?-B?v;G=Q k?ub?6u> '>߾Z?b?Za?23>3@?Dl>:`ӍHE=v;A?>:?y{EN=z{eZ=U>kph2+=fؤ>M>տإ8eA=O)d|̿?,t>G.>5L> 4/R< l2??<.P>:-Lý)#:,?6g?l׿8V=-m¾>"p*>ҿfV~=|xE $7I>>>% C`=a==? ?>Q]>0>ܢU?N|[?^:;>=ѿ [?_ >t=d??`__>=x<>P%J#=п<?Zx? x>7(g=]T?/:B>E~׺_ @?e >s7þ=jߺ鳍?G>GZ o־_x?6>ukե)uC=>"u?& > `/λVXR?J4Dà=4L|1;DiQ?u><þ_0^?>D?}>l>H:j'O?Ay=&>+`sL?_k>;F<6=\? %>N<Kv=j'>?Rr>xʼ%J>x>TT?J>Ky~,M?`=L>HG>$d>צ7?K0?W! 2Y=HY!=?ɖ9;>\z}j8>X?>M8?`ݿ>J ʾzw0 ?S>%hb4;wKn9.?>*>%=K>?י ?>?:? !? >?7#h?G >?>݋?*Fͼ?hi@~<>4>/>o ͼ?$(y>MՑ,>9\=Gi>~>?4tHI?om{>ɺ>8?3W?}ǿ}>@>=>8޾?;g>޸>e?D>w??-?L:X?&>}?8?JU;?a=>I>:0[ ?RGa>/;fQ=$r;=?ǃr&?u?&?m4>V?Dμ?J? ?,=>C1?Jk>j??@=B?> >Y??$Uڽ?"DL>37>gЫ?<#>D[?dH>PЫ? =1?&> ?Ŀ|>=?`>R羵2@N—?nJ?@?N>+?߿>Å@?9?L3w‡?6_>OQ?L.?fIO?`?"4U?L?l4?>>?ֿf>=?0?Kg?>>ԙ!@>S>)V?zl?s7= J>E=欿"Pa?|`==7'=H\%2??=S> >~f/?f =ÿ?*?/{?Fx=}R?.=OT> t>%B_?;{l>~ R@j&?k?^z?"_?,~> Zd>;X-v>2>? ??*{>M@hԀ>]J>6JA?>?}n>8.?9F>1>[?RZ?R:>[?rY>х' ?~>W?/ ?'":?Ϟ0>?B"?k \@>V?W?C?QljE>ñ?)×W@ `j>X?. k?m1f>[uћx=2>©>ܿ(غ?}=yc?X?P#Bh?!~c=??@??&O?N"W=՝?[?D%\?C>lz?U?&d)?g俣>t??FkQn+s>8)=?>iY>Ma>¡=Կ?8Yu>WXp?B>23?8\?k*9j?7>U&?O?,>+ٮy=V>$>׿B>9D?$p>'? }> =7<>>:?J7J?Q"2<>u>MM>ʏ;?s2?>B)?1?.  =s`JBõ>:!>,?eӻ=*|? ƿ>@??D?-?CD=l?4??&? i=Q?K?.ޱ?+?@=? r>?}I> t?3?QHw=e-?m"1>K?mk>Ó?G?hw=`?MK>@va>O>&?=ؾ{>Ib=\:?4>*$1>|~>g?(?\c=L[=R&]>!hy>ľG>A:=Ӧ?9>-#I? q>-L?n>:\?0E>~?S?u >g>~a =6+OfZ?ؿ2=?K={ 'Ȱ@?>o?(?kl?>ƨ?.?=B?4Q鷮>bVz>[?5]?Fk>>?DQ=47z> >Y?X}?]n>QA?3H?H=|?퇾 >u?B?>Q`? Aɢ>Օ? ?M~>~㶚>4?wp?G?Fܿtײ??n??c@Ĺ?w??y?OaT?Q?u?xh?D_91l? ?E?Q>>@QPB> c?8R?>N퉿>ĺ?0?W>?Qۓ>>5x>?Jツ`p?ƛ>v?M?=d:YMb**>h??#J}iL<:j>j?!ɓͭ2-t"=+>/?A >r??7~4>/ې>w?ܾh1>b>?it/am>s˜>?MwmDAzT>?[W.ҿ^>x? ?\=18*==J,?Z|?'=ZK,s?_?(GN=P<0?n>`?6:6:>1n?^W?kf>ZC?>:?5?L'?µNb=Ь;?Rq?K=ôpQ,R>??:?Av5u\>>ͫ>TI(Fw>$cɬP|t7Ї>q5???Xo7>K >,g?Lb?)c>M|}F>:yy??(?''5o!q>0?c?yh?GFk`=a>&?C,*̿(yn =y>?B'pP4y+=(>>k2' )>MoT>g=,˫an (>i>E?@p>&վpj=վCz>>};ﺮIq/b>4O>@??Myn= F>RmH?/%b=?yB? U iw6> =%? >]WH=Q?;h?"zB~G IwAD6>K>~{zY=d?pT =?%ipLཉo}=>>Ԁcw޿~I>Sv?^?>->-7~??v3>^"*=??Y>L!=p?'8?w)ӿ}=?KC?5/=&ciP>J> =de w"=v>} >Zɿ?tv=mҾ`ٿ\㊿1Z>lO?>?:A^u6?N?c(>]z%>P@E52?%7?νT?.C4p>;>= OL{?>>V\ gpt>4 >J>yѾ!`>HV?'1> f>?*Y?,= !H?.V&D$MI@{Bt?^?t?*>*? c??o߾V> ?0??u$x1>=G?`m?p,>j_R1x=>OU? dCS?;b>^?Y?3?#s;M X?B{}t(c?zݿ#R_?Z=E>w>ow7q1F>v?>K?EN=-?.'0п9o= ? ?.e(=RcڢtK/`o=t:>]=*c>|:>6>N#>.wBQi?;?P>]bPp x<*?yQr ?*Fkvp Y?4=r?w1W<\>7?<=.kdZ?7C>?V?R|*&=1w>j=Ɋ"J<彅F ?8)?G=\= N???S ߺ>x ?a?b?q~ٶz>BJ??? $.>??wp?./ ۍ?\=h?`c>Ύ1&7U???U/fP[?[L?YN? ?+D=<=wu3l?<<,=UQ> !d͘9V^ =Mm;?a?ċ?W/=?p??"4/hWs?82?3f>Ⱥא.R?^>x=> ">U2>j3=-P pXX6?!?5e>eg*OH>5=~̾=n>v+h=*t~>g<A%oW_?"X?E>?F4-I=v>"=)= c?w~/N>f>j>Gi>%?\ x.*=>[=<ٿnf>&=,R?h>>B+B>2˿?c">LfR d>>d=5s{{)>w?re>r@F@n>*=1=~|?_,"O=i>f=P<,ý^-yW?;j>PҾSw?piD"{X?WZu?i0'!f,I?a4o?3Ŷ4?ox?b x? ? ?&>l21']akjӦ9-V?X? w0X?ٮ?ԍN\_?U?Ej>?g3?f ?W.i?0?R;?r?=.1?ӹ[;,r?;?Ti?ZK_?& ?k^?B>?[ ?>c2-ǻ=Uɾ`*U?'(?' ?9p?Yup?t'> d?$H|>m%9>;?P?n^=sH,/M;(|=bEൽy> (T=?Fgw=p,x6<8~=R<"hy򾕧>tf?FV?..of<>m")>;>ժ =>>Ҁ%>??/a>Ƹ? ? |$= =[`e~-:2i>` HZ;׾ţw-þ39;>_=o.04 ->|Լm>53lHuB? =>`>>cPEQn =x"@[=Qt=bqEU߇-r=˿Qolj@B#io>s>1ί>>=#=>s>ԧ> >|-(%? =ʰ6a"T>ʬ==MfZj?>[ Pcg޾'yo꾽I>TTk>Ѣ6U> ~s mCl>b>E<@7>ԍr<>u)>kV0'l=N?/I=V>vw !b:>K` >7&!]h&Ax =G@1>h<(*z1?+>*?/芿CB,"<[,:>?!h/(=k}>a(?]?|6W9(> 6?>?I? 꾽A<?B>Dڭ>R(?j?* wu\y?LI>&+Y?k>aY+5+*?lr>pl$1?@ޠ?'q7v? ?--E` Q4:뽌޿rGY%m2F9>.2?)*P=>z?R2o˿>ۅb?(?APG3>ș?S?m`H֕?~>?[ ^??~?pᾬ6?t> ?oHMu\>2P>(4U>멏(>Pᆱ?AĽ?4lhP?ؼ.>.,?:e=v?{<&`_>oL'F>lk-?>8?~Fv>jο yl.C=>>,$>>i?Bd?h&=o=ې=>k?<:!5lQ>?)g?, *}wg<뽾?]%e ?(? r?zy_; 1>U־f>CvD=>RI>}LR=>`f<=־r> >@HH>A>acG>k~:&= RY\:xW>Hsy?'>؏? Mb=>QibJ>`DȾ?˼dq.?%h>,6> >ԧ/>/i=s~>v}x>ư>-Zh>?1S>a?NBR~>I? DJ>W?v<*>z(>%~`^U>6~>LVz='x  nҩa>9>H-&d>िB|T>n3>)>䛿^!V\O>p{>gL0><=ӂ=?q?{w:?W?? c?`*^;>pf(>k?vͽ^>V?>dNc;D> e>Vjc)Y=9ƤJ%q&=nJ^=t&g<2>\B=l A_`U:jU>zt>y-=Z=>Q@%?fZ=qHwd#-=ߑ`? {?$l1l ?>S?Mph=A\!>z?5?Vp EB>.?EL8~E+쫽a>7?`i=5o≠>lD?bN{ nP=E=5H=\cK=dcb -,R8sk=jR=$oÃ<aњ*37>j>!=>O쾶Af&$>?>?_9h>(K?gj>o?ZanD=#d?|o>\k?yA%=4Y>2(?*=;إE=?=?F+̗?'?#Zd?1 }b?SU?C?z[!_Z=R7=_t>?_xhtmKoh>;?kp=$j{>#?:ˁ=پ >_=}or1>얿AXp?F\"S&>YSz.4$e>>$J>/{?6s Vw2>0;~=)?cTJma.=9PP`>2i?Oo?6R >'R>>Zu? rXF=ȸ#>p?FKw@^t?Sq??߄Ci#>=.>?IeL>X>V?Gj?QL<8zF=T8Z>?4>]=*c>q?<%?wgA/Ro>P_)?r=P"`F?ka>o?c?Ai0SC=fV>)?Ki_m=AQ>ؓ??Q)P20= "|0>3Y?&Y%0ۻㆽ>?V?v$ >E!o3FuMQ=2>?@i?!E?% =4F>A? 1L'>[E>T:?(d?|RPI_B)=N=S7??_=D_5(=r>@?#9?j2(XP=??K>=e}>e?h?B>H=?>[>b$?N!2=yO2>?@:[ľK >]?N?wl?^? ؿ+?P>+Q+ÿkW?{IO [Oƿ8i>Ia<>o>?C>*=I=>ϧ?难mH?W*?5??տP;H? ~>M>&p>R>EC(C=>6Ao>Wxֈ>>d%B9>C [??_&?|Wm>x6C@{?_>AZ>nD6۾?leI? ƿ#90eMA=O<2_c> ?1j$7 t=O>{F?@?= a=?0ByO=Zk??e?g<+=n>n ?t&?; e>Ls? <?E$?򿭾%> Ť>7U7?/!?2>\>1?K<;O=Ѳ?.<;>>y>_ =ѽ?#<>?HMIk?LA̿ſ"g(AW.>n?a? .%=eXBAU ( 5Y=n>]?{W?[> `*y>s+? m?i5>{Go>JEv`t!=*?CX#t?P(>aw9ػe>>"!>2>vS> ? x?:2i=O>DKo?lQ"?z/>`=t6??Gm.!<޻w=Jw??=[ W:>ľ@~?J?p/?|==p"?OD?f2`$>}?0?H?I\.y>sY?e?~gp3:?`?Ò?Q7fn~5>]>?)_?);<`k>hj>hZ?~?Zo2ZJ`?@@ ̿2d>+?yU?" ?2#4=J??:u?0w>>J??.00L==ω?` ?Xd%_'4xwh> ??u~O+羡?I`?@?Q/@}m#?$?2?#/5i>.l? iM?#?dd-G?@?_͚?x?7>±? Mr?Hi>n$g<>,?br?dw?AvL=>?? n={ԍO>ڎ?,">}S?n?>l?yq>$3>+?o<.?̿|4\?D"?߭*?eÿع^6 mL?@?.&pڶ?l"?]?45??ʦ?a$._=k$?1?U c?9/%Q>?R&?~#?;3wi?(i?'?u ^9Ѐ=^3'??[ݺzJƽE>Y?6?|V7UI >h??pNx$h>We?"?i do<";u>L?v:?o)?HU?!?&t@C > ?E?#?쾂 >?39?[?a>G9eE>Je>8?#?s>r @p>;1?[}?1?A:<>> ?V?C>$ e#=`-? ?Vz?  6=Sȟ!?;^?-̸0Cp=~Tq>>G=? >'>*?o?z>c==?H?~Vq;:=x[u?HMU>f?=If<a?*?h>ۥ>>sX?i?Ľ=q>aq<?jM?!KF> Hg?Ҧ?B˿Bi+I>>!?:\?3͚Eۇ,>>t*?3Ϣ?cV>.=>?C J?")>` =OY>W\??? c==?5?upC13>ھe=\ >]`z}/lD>lZ>OJ>5_%ء>^N'=?m;?o6>} J? 6??F/p>>?-?[>dV>_=Z??imw-.Z><œ?G?X0~6x>[ǹ?R?>gb@w<ս"?_)?~>W> =a?K?oc(]Dp1s,?(X? n0:< .> ?7~?6 _fP`tdĵ-=wܱG5m}V>=>%C|<<<㿧<9>8\?f??Qҿe^}W($>$J$?M>nʾ X!>Su<>">%c=>p7YgE>D>]aq>hjQ>i>w6G=O¾>0C>'¨X>Zr뽄 >X>wW?c=r? ?a?v]>=?`?o?IM`&' >d>~Y,=簾V)R>=>Ou>('> J#Xf)!lX>-ֽs\>>.=IPvKX>,` m>Ҧ>뼓_J=ގ>>`9v;%"D?Y?M?e; @=>?}?/ 3`JG=]>>8C@&_p=P׿ØL 9<zK`(&>5m>==t?{3>z>2]cn?F {>:Vsmv#KX*W?nCGGo^CT_97ԿGkJ QEj|;z?#+H>=>}ܥ Ui>3>!>&0콮I*=?>>Uu\`>6 p>2? ?x;^}Bfk=Y>=>q.>q$)!޼ۃFT=T ^(ټ>b>ڝuW7= A>`>D~: <9Q>yd?7t6?M k>HK=/cv<>!wr ә5&>>? d>Ue>M 4F=駾oOQ?y3>0'Y?m#$ h=?*kw,?Ti8=Б=K(?co$>:}Dᾗ7vz[?M=LdؾK"?e>QWワZ`DR>pr?=N=ʿxt? {>3V#?A>: )=>X?;{//> 0F)b?]'=숤'ZS:q?=ߐT򮾒֪߽?q~>"ژ#7=y?> ᾷRTH=?O N'> 컾Oo 3Q? >1tŽ">$W>C?\d>dH=Q?oZ?ղ>Ң?4U.>y|=>2U?$?Hb> k?"?k|=h>Z>Z>y臇? l>i>% F?0vy?¿r">???&~`?!>>Ć_?[ =c?~K&5>>|1a>?޿u>u>?*#˫?^~H>f>>js?v{h>at? ?? SX*=5X>>f8? }p|?y=>3=Qy3&)?H>Fb>>(c>?) >/^>a>uɾ+> +=o>+[=2f?ٲ>ͯ?]?=sɾsW`?aS>>>uaN@2?eb^>?-l?s?G^?t?wK?j5rμ?vQ? f??V:\?Z`F?H$O?nH?`,T=%H$?H?k?w>,#>hs:>sX?9F?^=>2BB==?vK>h)?/]y*=>n>R ]=ۇ=>>ڿ f*"!;M>H<,fWj?, ?,:?e>>?$p?~۱K?\_9ýI>t?Oy ?KtXk>t;'?m?$bA?eq>XY?K?${D$=܃>>^;ӾȨ ^->3=j> V;?f =)ܽk?Hr?7?xCl>ޏ??B6=fb5?i7;X=z?#?ni>x{>|x>]?ċ>gzVX5Ap>y??3qb\>Khm>)??oZ>v5?Mąf>L?n}F?|v}9&?mq>OU? ?@>>)#X=<ȁ=gf=p rv?}?C?=?>}?C=N ?\?:M=1eE<^?6==1D?ſxF>Z(5?HX>G\ѿ?";O>9"S?N?Ko f> j+>*>=u<*{bJ=/?+[>=>c/.?8ƿǤ躸l>Q?'?T? =1m>D>y.We. >>á?%?}(t="4?*<=Luſ'~0Y>>?)y;&F_=d=x)>K ;ϊ6Ű>A>X?L!K;/?DÚt=O=>:??d >47?>h?{LB~>1b(>/<.?D6Oag?f=۴>ʛ=T޿'9=@!>L׿^2>]#ͼV>-K>=aN> ܥk=U==LoV>Ԁ$=Ƶ?d1>¾\y>zp>-e??W>1V= R>Gr?B?.: K%>ע;{?L?q>>1?c>NG2=@{>э??˖>/= =LZ|D(ل>?E?Bp=Ad>J`?W?m >C1?d>T?!?2DW&<>g>"2⹿+o=>8޾Q?YC>C򿎃%5=þK?_=\<3S?>p>=q= } ٲ>7 ?f;G? þa; ?ij?D?|>׾?=?+?s3"=4r>tX??!hHu}V>B>!=|v>>>1b&A{tc=濇>1[!h>+?}>,?G>} `_>MB>8>Ȇ=9;!*^>I6?= `U $ TqY>ɘ? &\Մw<9>z>,b6.=~_=RrKgwnؾ]!y >*L?ڶ?Ǜ9uwa>g?A>@cK0???JP=ԮC2l>64>i=jjP}=3>V>OJ~5?f?l>EJ<8qɽ:6?cK?">A^q@> Iw=UO?u&>: ??ᱻIq> ,>M?f43Ҷ>K>d?x7>GR>1??bR?>673?5??ry>Ս?A>lt?f?g>4> 1>A?F#Uv S~=!}>ܸ?Bʾ*|;!>bm>W?vpwp ?C?? >'7>p?s?+iU>kf>O?_?>4jX-=иJ>% [h NCx=<}ᾚ<.+IV =Y=˄[^S1r8|4?d??~>)^>p? > rSa=6?A\>ý` }M>U?j,w?$=鿥b!>?#h>ZqV(1=?1D>ҰɽL>=#?Pu?=P >Dկl MI &=)-V?fy?&=q>DK% S=p;?8k?%<4?Gs=0I?5&>r(pڿԉ>P}N?.;G>jc~$i>?!?Ck >p7o~Ho>t-?Xc?t>1߹4>K?>ո?>{?g?="?vJՒd>'?IV?M=7O>H?,?.)'>wgZ>U>m>J+^? :m>P?w?ʗҿ??s%?.t=鿛l?!-?D?k>1f! ?>q?h?>c'=>Z?\4?h<鎿t!*=b?%:>½ NK*Y6ۋ?ᱽRu?0x>cнV/o>,m?4<>=/wl/.o>2??Wxy>Β!>o ?]tO?K>MA1?Gd|>*??=?ك0>}?{?>bK#U>q?dȽ?=Et hpm>?+>RdNj<#!?ic?.^>A"=t?W>6*TA>VF?`?s?Rz=Ѝ?iA?(}>!H=?k?)k>[6^, >N?j@!->B>(1?rF(?Մ^f>b;y>?ݩ?O]-?Ƙ6>GZ??=I>V$>0b?Y?,<^8V=_J>.#?e~>d='>s?d<] a=LCp>}N?]վ8Ȭ@>i/>0?s?K>?IU?~>{ ?Q>¢^?6?F>Ĥ?qHt?*w??[?fo =m?k=?O0s:˾0'=2??\ͧ=eZ0 >?{X?Lh4=u9~c>*9??e>3FܿrՀ>e??I}>AV7R/-??v˸>ilm>y????DHXy>.?)?m?ho1!>U>?C?+pm@ >8>]?}$[j >㑴??'?4:&J? n?p?^S?{ >VS?9?>+?X=d=ɱ?4 gk?>=f?5Yվh?m6>% f?L?=WwK?@E}>?n?>u̅w| >? K?vPײ>JA>?rv={s>g>?l%؂(q>VU\?"d?j=pia/M? ?=??WB>"?H? ?eߠ>R??+(?hٔ4c>z?榱?x?'Z4?>i?! W4Gɵ>\ ?o??BD,>u?5%?>ɻſ8C;Ҫ\? >ÖѾdA7=?\???@c>Gv?m?]>auV>1*>v&?kT>|qi=$ ){ܭ>^>^?f&?zeZ>CW=Y?5??r?2>;!X2>?X?y-> l0#=?. ?< ,^\rW ?%?>ȿ?n7~?x?I>mo>]w>5G?w]?x>T;n3=΁?MaN!=ӿyeV=>O?z? >пRU|0=?U?ɼ? 掿f=D1ԦD=LQ?M?/>Ϋhs>,?>d==_re> ?`bo?>C>伌j?P?C?9>}>|a>> ?F?=aᅤr$?? ?'RDotw2V?I?.0?5-wf>]>)t>t%c͂Ƌ>ۼ^}ak<~]?!`4bYX=Go{5>2?/>?K$<@T> R>X?k? $>rڿk7>8P?V?J?/&>ڡ?v?>o qG>&?v?%>ɛN?xm ?x??֡>?3{lh??3r*?э?}}?>7eE1>f'?@?"?#M'^BE>Z|? ?>>jj?[?L?(J|0=a=??q>\ě =/>?/x?2> SqZ>p=M4=.1{1_1=/s>+{>A)% C>ǽ>>rT<&E^>Y>ڙ>=!F?^>m@?4?+?e Z={=MT?y6p>])>5z>+E>=82>E>=Co={>yp> >J̒6ץJA V1rnpyܔ= nqP `n?bi7?E]?#a"zL?Wɬ_?[/ѬO:yh=/w?2}3U=>V=y,I(<>t?M?D?մ0"=h?!?>:LY? >.?t>g i>1s?l??*=)qMr>1>Տ.=|?1/=>pB0a4-[>D1?ǭ?BX%H;¼??H+cKYKv>}?f?wt͗_;>?F?_ '^3=q?j?. ;=M>P?E?>_V??,וhzľ?+?v}%M>q>>9s?,3±=g> 1X&2W#<ۿZ?;>m/:>M?&#:??>:4<۱>5\SF lCh>d Կ?{>,(Ko?濩]?}?bs.cg5=$῎?k>'m=?6={?Fܾz u>ſR;??Kq=濐?1_>SuCHi>#,b;??5ɽ*(=147>/?K?"I~? z#?? ̿?s5 ?ċ?v\=.#?շ??aOs>mv8? >4_?$q=OHf?'_?$>N/0ؘ{6!V\>+K@<&. qF=RH ?2{>Yć>TΒ>ͯ!]>}?B >3t6>x x ?1>>H~>A>!#>C >8M4r=Cp?7v>)08=>Mb|?,>d=7+E79!W>%l?v?Ie|LR)ܾ5?*C>4?NUa?$>?}RGr@=޾k F<&#r>m=1h=h_^#%5> kQTR$սۿ.I><>ӆ ??z'#k?P?=zpZ$߮6??w5T?iv?,zi?>Z6=>~'Vq?+4=pr>}[D y?<>8{W>:5LI*eϾ#Ű+y:ݤ$Č9i-b =R+/ʾ`,Nu#-S?AI?IQyYTy`??Zl0˿P5?]hs?%)ѿ[[p>("6.:/ę+䊽aF?!,^38Zɾ(?(ݔ.Up,0@?>\? k(*h K?j>> ?DX:>>`~b?9x>d?#mp&W?/*> k>;?B>.Q=rC>q?q?{'<9JoL+R?[>?/ex?`[eylA? ?Z;x x>m|p?;u$1Rх?%<;D>S~8b<)E>bg=r>ͷFľ2N R=֨3p)aH黾޽k?)QLYv?7,?3g6h`R+?p>S YſDLW\vPqA;Ҳ6_c? U?#`M,gY`ݿ$ xaH=L\?pKn$و Rgpz)"S/{PJL>a?sm:*0Tc?q kC=ı섶Fn~A&W>1S>l?! ?ƾ0^?N ?9'UuimL?،? R fȿAJ=K-ChQ>}:`>?u,ZsH˾jD? ?GL?# p߾>p~?Q_>8f?<\yٝ6i;LǾ~\O[+EP~7a ⰾ= , =-.ؾ];½Jܿؾ'|ٽ0;-Fir=׃ZF|Wv>>;>?sĠǾrz>8?)#?%  r,y? ?JH?Ȫǰ*sY,<7 JZg<޽VԿ SzċpDx=Ҿ=ٿp=U>ο"'?r On{=+WU%TC_:g< .B!꾍My4<%I, Miȴ>,`F=g:>O@|>?"`=>%??bؽƱI>? ́>6?&[I] >sZ>[=L?ĽKmՑ> ;?>E? y\R?S,?S?Vq"ѾBx?)p?c?P&ھ[>_>?ܸ?F;=\Ѽ{tr>Xpa>dSԂҞ=Pr #! HgKbx= Aon>s8>k'?C˜?Q?dv`t=s>t!?l.=Ĝ='ԾH=Z1Į =<>LTƂ>!Ӝ9S==ʰ$<3!2Ƚq? xp>/b?ؿ``pT>ч??_ۦVq#>b?P4Z=h{?] ZoatP3ٻϽ>vKvgmd5~>J;1=e>#)=ruG9z=?:G\6?5ޭ?~z󙾜Z>w??T}?>+S?1=])N> CGgrY>=_?O:=?I'Fʽ;?(ةO'? A)>2N>}k?;0`;g> ȸ? dx=ȶ=h? ?rZ9>We>F#>Lb??.?6̽JϾ=UV?"u?{?63?*7 =:?.?=??XY0==,ck>ey?od=&>7k>_A? (?;y?js?!? /]l/ށgXE#=մg>7?t?> \?qf?'w?C?Ș=h8!f?Y?3??> @?KNf??=*$>co>?H6?,0$>В%>?vC?mpMB= >?J?oi}@ƽ>?g?cj;`<س>}?_??m?/X֢"O>E?HB??ȗ?ƨ~> ?I?0]??ώ>\:>o>?*?>z  |>>b?3'?^?V >>?L?}_>i x?Nt?'?nj"?`>P=M=Up?>8?יG,>پ>j?&{Z C=ؾ$ >??F?YZvՕs>H>l?fC?C(?"ͼ8<`N=4? FA"4"?1{?qcs6=TXG<Ɍ;?j ?mH=許7?&6?ZJ'>7>)pr?g?0<ޘNx=e >?ud?)kzP3>k?a?$>?>?\?N?zh>0E9<9>5e>?c4{g>&p]>^?j? kwqX?eA?ߘ?ʲ{[D7>e4>>#i>G>Mo>G>J&>^?y?uq?[x6<0Ц>Kf5"Li >J?X!b>Z@>B)?8 >+>t?4??d˿Ωa?6 ??{ ?NW?7V!??Ro>Т?^?<?wQ:z>H?? > rֽΖ>>?D 4tE> ?&v?#Ӏ?Wa?U:`?A? (=º"?lj?1?p.@==94j?,?7?x} 6>L?v?}?$4߽HZ?@J?/^NžN>b(??=e0I>|T> ? )(/I=V?D??N+k>E?+ ̿)ܥ >Jc,0?O< })>k_?^[ῚB5[==%0 p>?L?AZAE?F?Ɛ`?_RA*Χ>m??k|1:&Is?0C?>?yq);*M/?? ?NF0 Y}>rW?Jw?o;u& ?g/E?9?Ȝ;d-6&>{A}>V>?4 @=}>>&N\h>g=o)N>>I?Y?ݾDzFN>Q?MWſq>\#SoҹoYhU>ơ?rv?`B>P?3\v=rNoT>*?0??aiCx-͚?@p?HR?}_:`CnD[>*??dO>>>?QQ?EF9ż; -=_?YP?9W>=+=i??mPv!B4C=>? ?WPC=+o='2.aо V=+>a>qTM=n<>%?m۾EE>:?s[?H&e;mZa[=q?Jw?i3?D9>m>N1??4>]T<yq>G?DqaU4}=l}?Qs?0vbWXh܂PDk=]>8r~!Rcc<Tg>5C<=r??B!]Q=R >Y?V?B^`ͽ=& Gx18>BJk?f,?̚?q;=`%9?Ck+@1?m(89=??g8?M.Bgg=c? 6i>S qo>P@/>Tj7*>Z=5v+¾P7>"2=K]?(u?#ď>tT={<%&?W?VTON+0{5= >Q>Z`־> _>^>9;݃=U޾5]/+A >YPv>eyƽFJyCdk>ru?\?,f?1)r`=G=|t_y>%>;>U+ A>?C{?\W !HK[>V2?+x?Fa?, *(="绕u)3-aF>|] .>J>%#:W!?W?E?` D4r?l3?ӷ?W/ >xK?/v?K`?u=y5aū8?R=ZG$þIh/6ݩ>L>0b?G7?? 4Kܾ07(~[ >`dV>V>?N>,H=B7Cx>lrR<=b>@>.=]>`݃G=>F@?V$>T{ə=w>8 @i^>DrqŽ -=w> 9ў>Sſ3-8X6?>NLLb>?92Y>&׾=⾎?z$-(=#O1޾G}?lr=ջ)ӾN߾*?=u兾V0?v>Tc`>fk>?Y>%jJ<>s8N== _b =F8=lCo ?GJs=lӿD: `?7 7=-<> ?_ 9>7*Q"ٶ?<Iw=ɿz&t>@p1/>X>bܾ?큿>'>fe>)< Min@P9"S>J=!Z>"!?HZ >C1?=᤿2.@VCx>ǺE?>Ҿ @пA>d=?0:!>>­?a>)>>?;Qɴ??D>q>c5?si.@OO>`"?\6>̮ @aHoi>?5~>6{)?dX>"? <> *?~W>T)?qc>mAB?~M>?i?*?m߿Q>f>>(c?ui= x>>G>-?k¿Q>l??/oL?ϚUs?o?LV?Y9=JV?!V= _>SLC?}"d=ʛ>:Kjrm?D_a>Z1>>FL?=_Q>y>%x?*Hؽr?}?d $>Q>?"93?^r>,>>S?BY">i>n?]?.waF=>>h?C<=u,>=kB/'> ;r><5?;~f3>\վL?C/Ε>8E$=>4/>FU *_lH?`R6(F? x=k]?鼿=)? ?,>>۾P?8T&>>E=tiz?Yd:>w=I=`J?ͼ>@t?#>W\?/Z!z>B4>J>v =N?%C>6>I]پeƿmb?㿠Q>L?>JQ@?iD> F?T*$?!-DA ={=cx=Ǭ7cÿ˞Aҹ< N=[=1:{:٭Ŏe=8Z?? 5߾E ܜ=7H+߱?11n?q?I?#|5w:]=钾'ȿA (={=:#=c>=em?%?O>R8?->ȾNf?㿽=p>>⹿?Lۣ뼟+>\>l}(=2Q>u>dԿƓ 近 C=;?R?G=tV`;?`h>\ Ƚ9ڿR>r??>ف?&]:??8x1=3;1<=]?qsT>tIU \=O> >Ѝd<4v;D?"&)(4MBǤK#?G=@?4ۿȥ/<>Z>wj@s>>a;>e}LǿxB=c5>>/:lA?$_?f}#qD?G(?ƾzlEx&r6D>R=O>^7?>9f긿C<_-=H;>pg- /<p>Ǩ>ϹԖ5t=v}> V?!= `t>U?"߁&| !? HN8 R2YS&<1{? ^?gF=mS#^ikq/>??Cvq>`ydFu)<I>!P? VQqaM>;2>?!>CCq[>4>ǽ_壡Wgyl>s2=6/jgY.A>ZK>¼D`>Gc6cǿ->Qb>\P#A7; >F>3޾>i VfĎ>%> w?=>^?lYSNa9y= `? ?H&=$3^>| ݼpžA;&)%`DF>\꼝 W9I>=-"髿 G=>y:>yMQ"ɿH>??C>it?)>(?5??5%،>?ک?8?n/HJ=u?bF?*>1E-O=FJ>L^+fÿ2?'>~>J=svٺ=B>*mj?L_U>>eK??>BڿC-E=5?PI>nz&>?I?>f=oGC=>=ZS3 j=_>bn> '@#>ՙ? ?n-=>%Ӻ:bg>cfjr\ԀM>i?}HE>6fؿ ]=>t(JDi#|=;?7>4hǿCC>ή:?!q?WE>J{">!\?_??>׿ϕ >R??hU>e>B?r?B>3?XNƿK^l?7x?a>$^?_݇;ο=h?]l?5>K = >9?JjDuտrӿ ?rG?if?4n!˾??kx%?>?U=_?i?*<*h =[>X+?X.T~Q¼\S?`>Aȿ@8=k?ƌ?{>񈿑x;Ԋ?P?k>C\9???H/=b~=?L>>ebnaw ?\Fc?!=B:폾X?~?~?) q^>&|?/'> ;'LXi= ?>^%Eo<@T?-N>.jdd$u?e >2|ma/3j+^ G> kF0Y>??>~5>t?k?W>*X~>Kn?D>.=PcHu=o?>nLyF?¿m>5>L?z{7i#i> g?ԾL >h.>ŋ?Q*ؽG! ->u?ފ/?s?9 ~)5r:?uw?$+ R>{[-??Ee^>ǎ9=??RH? T>-<6eA\>0???0/%>C>/?UR&㛲=Ó?4><)?qb?3=op; J?{3?>G$>{>2V6?A?L>ݛ=2.? A>ğ=>`c?}?HC`">c?z=? >j&{~'>?M;?>a*?c3a>eϽU;?h8藦?!w>e]_J0?#O>S?e%>+|x>qe?TSn/ >:u>zfTL= #P?+PIt` оIuzn;?K >|5J8#??k>=rP?Ӽ^?Ƶ?kaZS>Ww?C/?M=Zd=?Q?}JEo>#? ?U"O>w?wh?Q? Ƚ}&l>eV?L%l?r>O}t?XCoe>oz=)?.?B$?2>褠=A?>B6?~3>K>&?S\u&?<ġb>˴=5+?/-?'< >՛??1>? >]T?m?ł>> >X? A?>W0>#1+>?)??$&oj8=??7?v꼓ˣ=?Z?>6?Dz0=H?t?F=چ]>y>(\?D?}Sz>5+p=E ??vɰ>槿hja=p?x?T)(>#t4W=}>N?? 8>#\ hQ>? %?~_>? z>ߛV?l??7'||,?G?$hK+ؤtkQ?xX?`C>0?۩>ݾp8>oB?2i{>5?>yJ>?&?r?ؐ?Tu =>?zF??CGV=?ݥ?>S>G[a5=G??}x>~ DL{c??>+=?,/Q?F?O>K=?@%l |`>5>P@:?j>0?a??2F|%cp.b?A?p>U0> Ӎ?0?M? 73*3{NUm<7w??>ԙ q>~2?{?[?!>2q>MY?u!Ez=G>_??G? ؄?bKdh>xnu6???? Bȿ![l>۔??? /et >ߝ??l3?^n @'Sy;y=*>(?߾dz^+>??*?3=k J> q>+>+g|B|W=ޏ4F6&OX VHU?}#k?"9<%;=Qx0?:=77?p^̰n( ?=頮?t$/-<@>>Ӵ-ï2L?>$?#jp;?U=?mhx 8;%?-o??Z3=1Iz# >S?xQv?(g?Ѷܸ?S4>bR?u6saK>"!`?Z >r>}>T?P=/=G|>.ؽM%*?=78>=m{~8藋>%?1?lq?@IXm> ;7?~tM =b>l>?gMQ>"5r>=.?)Ah#^l?!J,C?i@Qqe>k>2 ="ps\*>[>9.=iv>ȅnYeo?Iܔ>X>q>P~.o?3>0d|>G=?=t?q?ci>W?5u\?j}?}~x?ht3ds>*g=[o3E?#1 a?2>' >?"|?nH?֝ l>>F? Y?M)=&V>2,?B?|Ac W?-(P0#U*?>?W4rG= =lH\پab)>6'-?Wf>~)t~#<=;0?gͼ:P{c.?S?J?޾?:_?}=?p>`]wu>8=pξ+>#"=r?m>jyƬd>s3?+??h:D-U=?`-?D=4?8.?{?3TӪ'hs?[0/<'=0 =̠<#?)MWID?P=̅??FD ;Lf?Y$T?ڙ|Y 4 (?R0dGIk?E?O>N8x.0=32pH?>:.?Q 7?BEPIJWTP?|J?o4?J j~=lL=b?DKw???gB)e?=?bEL? ?фbzL=3/?!=  ==?3q"=Mqo=~??["=Jd??J#}7f =񮿓|x?>?71?hE?G?Պd?+cw>w>?~s?ʿ8 K>ȳվuX??'__ߘ.I=Q?n?l3$?wP9>: ?^???c(?vx? 4P-=gԿQ??9q=ɿr=?Q?2 ?ܕ\?ت\?<0&?=V?2?Q<ǹ==y`?}9?\o?JR"p?z?-~'I`x7??NՁF$=@F??gŕR,Z@Q? O ,r= ?¹>#,woRϻ HRa?>jeU֧?h&?]DF#Vξ*B=`??pC8!9]=\OYF? >סAV>C4?A?ܶ1bej:6??M>ao&r?I|>8?Z_u>p?>@~>9w/Pjw.o>=>c?v'>v}=E]-=RAD>:>&9>^??Ͽ>=?p|c?i{O`U2=s>>Kwlx[F?{Ŀ\.) ?q>s?I?$6?2="%> >aoX(BtECl-yh?63g>/cük5n|<ÿ_,)J?Z? o??x0R?KSr?>??5&? ?,u`??(DP?|?xyp?j4`t(8-?&G\R ?aA>S~? bg[羑XS?M>v?*qk]=B}&'(>L>q2?W>D=? ?60gA_#?0I1@?vk"h>0L{*ژP4rӕ6y`;;Ε>4?~=žG͊;-읿=?U^?x9=J?ܔ<{;hAľ]=?cl:/IHY ;y?^" >|=?F>ȨPʆ"=ax'=X;dvR??[jb>G?;6ܮ=Ă>ր??]?_6h=x>?=[Fi$H>{?2??gr>A@wξڦnócL4|̾$?_?N9LOA2>>=>ۼ,4@> =>W[; >B=5a>W BN??X??ap~J>(?5?ya?҂f^*?|5H?x!ݸˋc<`̽9?c{?iqЌ<>`>>- AU>=>ܴl<Mo?4?з??߰{|px>t.>= ?e;~?"?oP?ӿkc0@>N?I[?s?{2B<[>?G6Cz">{ud?7?( >3> Q>3'=>@k.>/o?">]:`?e>* ==_>n^>'=hMi>zV=N@>]xN>C5pOGW>2>z! CH=/ *= u=<,>m? z>U?/>0/n>? >6?/>/>;Q?">?E -=>6"mm?h=>k=Ѿˆ+?U+`/'Wu>>Gs?R-< e>n=?={^XtC=%rPeIuMD=K5=Xһ>Lv>1="EB>Z L"3>7 C>ƨ3>g? y>$p">5ƿq?=v߹>O9K?MAS5{?Yď8I,R>%?ǟ@Q{P=t~=쾉Q=\Og=Up?:/ cU4Gc(>)W<;g7>: Xi8;y?F,>?C!8\ ?+>4?.Nh׺d?( )k?t3}5T? ?O@yd`pbυn>?#w}IaX>L?1>2?]Q^K=?j>B?,9y??j?Ң 5񾞫z?f?h?;Lt ᤽ >p?>Qa>2>!g:Czp翓 j*E=Y??U>? ?\=)?p"!U? \.8==?~j-8kH=Ip<ӓ%?e?cmٲ_oxS?d?^;>3|vRkDc?0>zƾ}7RLZ=5 $PؾED9"= =ƻ>?}8e6=G> ? 8?z.!=+=(>?tiQW.<=.>n?"6?0`&lC> ?<0F>RF$PKl4KxF1>`m' -VOp$w:>v)Utο' H#? >‡?O?XT$E?+&?C$?>T>R??E@c?}>Fs?`:k=/>9?RI?x.AE=\Q۽r>G?^MXWydA>?D2JKŇ;=>:%?46?{v>>O>:?`Z?m? W[>C(t?8?Y.>?Z2?&? mx>@9=?Yn?yUgP=]>ω???E?IC=JE|= >?k=?^_(>]?J?C-Y???6KS'>_ɼ>V>DqY[;O=c*B>Nx CaY=Ո>65>&?)?p?ae/>f|(=>?P_&̿ JMwe> ?3'g?oz?PW~ڶDo>6(>yl7.Z>f^?t??ԅ˿0?? [?;?8/>?g?t?o:澑e>Ԫ? ?-+ X= 1>'ߠ>:W!>`R* w|X=٩?O 5W)\wWD=F>&|?pW=ͯ??{h?AJ}A!䛾 پh>?/JKL>B[?l?"X >"}??YKc A?'7?'?5v8Q]zJV8?`I;K{>#C>ڐq?w\@=|>EH B?K7r+>~> =xOӿg?, ?#r?p*ˤzW?0gZ׾,ZԢ>k?`|>Ť=?o?aB=3m۽6L> aT*$=о0M$=F!a=>掾юu>:?G >= >o?C6 xI=?5ZK?h`?uKNmZ?n?0? uJ1';lU?X??+rT8 =?d+?=.AOLL> 9?d{$?FMefN"=O:h+j^;s. 辟/,XfPBs ?KI? 斚='?s?i3i>Ww=>i-=6-r>8/>B?ͥ?BS>$w6?.w@%N?SPe =-7>l-`9>4aAEc>>S(m>sF0`o7q=wyf?@?$>3> Z?KJ@4?+ʟw=GO>>|bqޤ;?'8?+E/]B>7%1/;OH2{;nD apy7XL$]֪TCSHDO&f&վК>; >s`e8C?[>#K>?߾L+Ya4az4=|or=$=(x/r#"w\HTVG\ }=)ǿG6UP_D<gǾlA>yƠ>=??zt&~ =ӝ>E&?r0?k-=X\ ?lv?ECI;$?@$@?Ł? D=?澒>2=.? >=>B\&>+4=+Lw?a?J> =6H=y?[?t>5 >=t>uз?5?CłI=o??9i@Ta?ԑ m5>0s>^>l? Mb=V=Q??o?& =<3}?^?V;?$=ļ˞??G>3=t ??+ 7/;a>N?\>zOO>>m?7?5]aI(5> M>Y_?T?} Z>Cq>!?~g?>&F=?glY>O4x5= >>ګ?ax G=lNr.ӯuSS.?Qv=)o~@[uh^ix>~>.?! ?j? $=ʜV?qo?K+/@R->Y?ݺ?;F[Z>> ?ӭ?3Y>b4>c6?4>оwL Db=>JaA?}?X?O9= MV?aU Qe=տݾ)AS?=o=fA??KE(?&*=\ɂ?=?+m?=== ?bZ?_F>'N=?>9q?tJ? !KH|>plv}?;?:ٌ K4>]c'=\?yTv?=~}=*>H4v_?-?2j ao=>RH>鿱d۱>Rkr>~?(/?, Q4բ?]1??O?<=ۺӃϾ1T=/1M> p>??`%Z>ix??+>$`(cE="?/>!:^>KS>yM??|.#QW>x(=?}Si?ۭ`1>hμ?(? ?Nx} N=H cA轣IP>/>??^2s_x<>{J>OoSr=]?[>k/?p>/ݾ"8<|B?4>c`1S=512P>>־>$b>r7CgA=r:kAt f O> Myݿ9G#?;c$>!?D3x/?u@->4OHh?0Cp=-˿SC"BBBB?Yd!ղ=WKܿ)oBBB?k2>8}6DT&}BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB@ `>Ծ熽ZwՈ@ = #t>|g>4 ]F@(7?*Y2>=l<@?">n_>-u.@0ABN>lv>\o4@ o@>>{<j{$@ ;)>3>Poi<T??CC>$>@<;Q=@"U> 7?!~?H,=z>k<=)HK+?ʥ߿Z_B>3/?=;B<;?yѿ[.=>{؈s:=)Z?{򽂾U?Z/y>f>XX,mZ=ῂF>&S?J>X?d>? ݿG?j->u}>ľg?ɴ9\>s>SC?HyV?B;><>d?Q ?iӻi>Ӑ!E?1<=$ >ӿa; B|1e>:@#>Aa>{>~k?\O[>TҼ?">&]?.7^?E`>ˎmh>XO|l?Q<>V><?GWK@?ڜ0<>>m&>Q鯿FU?پ*5??FtK? Eþ?? >w?-> k?%>f>R/?Y6a?F=#$C=ꅽ>.Ql<<$>>`ܿ2@]Ƣ>z>f?ё>>g4= =a?؄>ԍ?6>;Ց;|Fl]=^S<>վ/!(?f<(γ8\oz>񽇖}>H?4b8=>1<|'(p=w>>(0Nł>g>GPz y>9b0> >L59ÿ08=Ƨi?2?,ꞼW+> a>ۤ?b>6ƾ1jZ P>? ?0=d g>0? J?X>>kZd=&' >l?##h`"~?4;$'>>с\\y?Q;'Z?>n̾?e(Y>O>F%k 1.=8EV3@3Ѣ{B>©>k_2vƿBSb>:={tT=b<><>oL;PK6&>rF>k>иоa# Yu>4wC>*:> =%ٿ 鿓(?CPU8h>&=Sa>ɸn Fi8@[[=M>)3 *,B ?7a>mRć?>fn:H<G?Ԣ߿=DHo?,yP&п 3a(??A7Zu!?*?;*908? E4Y?5?ܾf $D>W 1Kb>6~>kadAW>s|>2U;qV4D>a*R>;Ml>}8?h?<@)= XD->)k>H:(w?׿H=/>{>f!,Ͽt\p0</>=3?Z@>':6v>=%>n?3=ST;4>w753>J>H&K*ɼ Y!f?Xl>:Q|Dh?F/=ۭǰ=>>e kXZO_ AL?p>9>Ӯd &ힾ O? ? iQ8仡?T>žfÿhfՀ>r>82&Q=p2Uי?*?a|EIc,<M>_ۿRN?>O8>䊾;GP@U"P$>>>݉fYAI>с>@n`N.B=Gv>݀οZ>M.0={*6=Ћ| A7m>я`? =E5T?H韽3>`?"-[?Oʽ?#B?QY.ł6'>.> Z P ,Pr~:>aDF?8b= ޿\ @z>Y?N`/HDȣ>e?;(=NNw>8q*<pH?XC>9B=?A>)? CNhZrm?'?Uv>G1 a<?ċ>D,o95%<η?1*0;aC/!?L>߯@Xr-o=QY?v`>q ,D2>n?j>~@￿7]J>ۯ?k>|{̾PkW~?a?:@1>r;?>{OaUc;>8&>˽ھݟ{= D>Ԩ?4?y;r E?)tO8g>?(i>3׿as>C?>C5>u?@Ln*;)k=~K>x>i #=m>}?+C)|Qe?_Z?:>7 :g\??m? <`-/?u?Ui>s忓k>Vi? F>bf?使z<>|&PwG4?Ti>rjf5gȩf?14>5W@|P,?J?9>[Hu޽G>o?~֪ jS%7={8??LYU H=V |? ;?RJ%v=N0D>c?>ĿƆ@^=Q??> >[44C1?G?A>~ݿ6?'? =k俷pzI?>H?t>;Bb=$`g>Nw?;-^ʬP=?$fN8Mchx{|g3<xW>#>>hIi"8_zp` HĽē?j?r>v=Z??)V?&0/|C?v>d>$?@h>WV;>ҕ? 9&>+e3?282?cϒ?i/> o"~X?1 ?A'>\ <]/2?G?\?=DŽ<̘>B>:e)5G4 BȄ=*k>~&%> ?K>w9Lj->Q?+x>ُ9ta1>?ZEa ;=>÷R?010N¿Mj?ϧ ?6?Zx)=Uߨ -=W,>?a#W`S{FY??{U{q ?=п lv]cN>(Eݾx/qگ:Q0?0,>þrg#=?p?"=sm6>5t?X>^nqOHQ}>?" >/#k QXɽ>C?VGտ c)c<>Q?smʽ䱫+:/=m;m?Am>ײ0c]a<64?}>CR[?֝?)>~Jα %?1>f% &?@>/1=*?DsfQN=$? 7?^[!Xd)=X?>Yfֿsl=&-H?2>E#-+uu/=2?NR7?YAIWı??>??Tґ`'ۍ??ˆ?}R?uёB0>X??d? w'> x???*4eʅ<"/>?rcA?{>S8>u~?U.?t>4t+*Ɔ>?|?z{};p?+R?xO?eM?!쿮'BC>>?{??$?>]WN>z̿d6>?jL>z>cw?f;%-?%_?͖>(|> ?Pw6?>{-_>k?q??3'=<vxK>M>G?G~>0=Qi>?= 󾟕>|G^= B?f> X~0+Z^?Ș$??-IYL=Z?b?p>^6Xc:m2??5?m҂<# ?8?"B?3?~pޭ>|X>??$a\?J!n>x>{?.4-p?X>p6D^? ^Aȿ3 cN>T V?>G=<."x@@gf?jsC0?5H4>lCWGb?y?82;Yֿ>n?g?[?md|?!@=?A?>W@??zz=,?+$?sd4e=r4?K[`?Cc< W5+ԼYh?̸?A?bg<.>Do?rQ?>ٿL@ٲ.d,?)?>KZΔܢ>v?U3?A(J>q?VU.>O? ;?e=Y >꽨?}=r!8>??u?Wo[g>j?'9?۽?Wr,D=3?b?2 =˸;4=?bg&B>.|d=k__?oDA[>* Ł<3?~!Bh>E>?$q={ s?6r@f>[&j?9r?d?*꽈?!þ-f?K?]S ? !?N¿>˾>տ;* *>t???<ր9 $=x?<*5?F>n9[=L>Ҕ6?&>oW.U>X| ?E$??FcO}}c>~?@?wdZ??ʬa>T}=KM>,?>KdTѫV?`?@W?$d0 T?ϓ?+?`_$J? ?'?;=7@=bK>+>R/C?S,?K">q?)Tl>s2 ⠿1YZt8ʌ=s0?k5>0+( PD>]v%??? .j`x>?o?X?ۿ}s>3{?M?>{_i}Λ'?#!??tq\1X?[??P)ڿSF"??gt>r*п+`>1?S?5H>~h C=D?T?˥?yi8a?Yi˿ P6:| ,?qCo>'P4?`+0">0'<9 IC~?ZdѢ@?-,=8x#?D>t@ؾg=^3n׿?V?)x?O?5 C>f?9C?o>=gń>Hs?9.? ?A,= ?ax??%F1>?Bt??I2NGoD7x v M?Vn(?/.&4?Gv>Aρ{uK=~z<>HTG(J X>=???Ro>?"?1Y?et{xLB>>CPI#fr>W?>t? ]Vp"D?D>V?,SmviP3?q?Qيx<5x??-`>}U;>#>̫hnyWb?3j?Sm?5P,R@d=9">}[%>qڽ{>S=nK_=Y x I>oq=>ϽvȌھiK">p]>4>2ѽH? (:>2~>DF> 뼭x>^&>x=C, )KyWi=hGJ>TҼ#A4>e}CB>@m =b3bM ?F|@J>f+?boV|>e?Y&?b&?_X>̣?V?z-?q\` V]>2?,_u=2>rq>az? ]7|@>(=sԮ>@@S=r?<#꾡/o5 O>b>+$>o>}R=L2>VzS>c:=kudA#wG>r>0?Y׈>9ȉY>?>5?{WW[> K{̽i?/jeF=y=̽嶼 >>7Mݿ\K>#_W?e?@|KXCD_? ?~y?Xs?[9=<Ͼ)ԕ,(?Xz===KQoxy>1S?\>􉱿׿W>ۿ1?q? a?]?;gR?|R? %;u=J"_@&)gUp?Y%$b:Ȃ+dpE1H<>iË?f?S<?Ei)x>a?1*T??i'CgX??v?7 ?8N*?!QQ]hT??r?->T;Ļ6Ap<:6 H)c?+-p? &P?WX?S`P?㿃Y>Eq!h? S>տI=>7b=.?HI=:L5n?6|?6Y?)r? "?f.?y[pH>t{$|?Z0?FE ?{?I&(?/$?0'e?JI.H,?¤q?@?j6=?Rdž#{=D9 7؀?D+<}ki=6Z>5ڿn$>H+\?h4?#b+1>|?Ҁ?`O?ٹȀ? ?2?-E=cꅾ&?F|= >׽=gG$.G>@=??7?wT>- mnοC2_>!>?%?+?y98?#zɆ?y>>?@oiQP1?(5?iu?K :Y?*M>Z??j*>CH 侗OA>3f#C|߹>M=nΚ θ?dxQ\??8܇?(H6?z? X?hRy^?!*>LJ=U>쿆"")=޷Eà?Nd_u==M>\?[V?/K+>=70=];{PC`Ovd?i#5EB,LA??:^?tXBgx6?W>=>mD>=LƂӾ9ھCj?i=[bǽ\fk<?%>q=du`r!}X>_>3a?e1?NrIw> ?D?z?#=e>C??R?҉ [=>$W?N?E?L8A̰EʰR?Xþ~P{ N㾷@|[?FJpþ_?@C? ?6]a?7?yh?+cտy>CC?AG?|)?Ӻ-=ɾ{?Eݐ?W~9#)mxW=7]]K87IBվE?6Ծ_?4-?݁?䀄V*>ӻ???G>;YX?${?Z+?fZW?F6 ?Ɏ'=Q>´?;?~v<$">w?P?zI0.{>k2>/@DAu>>?? S?s0Tܔ>>kҿ4z:? `? . S8< n7)oT E1>lQ|ѾE>?D?9.{5? 8>[BnȾc(? bʎ.>M-'>>!xJi,>ھ[l= V'=wu ';cE+٥='SY'Ծ(x#O-{| x뼰Bm&f¿֦Yx]t~пD zvn?}=P>?XL>E&>== ؾ >VυA@n;̖aP>* No:2?IS߱? V7䤾@> ><Hm\-?Z >`v?NZ?H"=G>Q>92p$=y<`ɽ [=_Z=z# >u%o;>6?B/? v?j?L>i?5e??`erɽ_ >\:?=z3p>`gI>8UT^>u6>7)>>0>dC ??  >?>w?3LBzK?:<$?CЇpZB+>?v\>?2H =>M>??R/̑`LU_J>> ?y=CB=fj<>o=>%Cw>p>9&N>]=׈|>LƂ;>=e^Ͼ>>!9+D(>rMM=7;'>zl]?6])>m7>3>%qL?kHMO>?`K>?;,>qù?m:W?Dr? ?u=UҼ͡#{-1ng=շ5曾/sPӞ=mVeWi9r=~?>>?jʾoyM>(?bOv>L'?n=sղ>'O?P?%?ŽYi^:= Ս='}LY?L8?}>h?t;>S>?>?dz)#>l2=^? ?l?Hv=<(k?%k?/?y8;=8? J?/v?#?$?;`|?QS?7` _}=Mxg:ɴc>or*>>?[mWA@U>?|u>8=QG>e?f. i+==S??j Gv>P NQZK\TT=UAtZj]?EeӀ/9>BK?B?vq?%]Mzw??lƪo]IL>,?E6r?RS>y<>ۀ$?>?hc"ܜ>T ?Ku? -?Up1W\>?km??۾*>ր?"m??ۜLx?$?? GTw?i,?3:NX5Y?l?"?>}w/wپxܽw M>W=>q>R>$QC|=r.uy->K,=/U] @NU>}#ܿO tͽ>B=6>^1??|п2[>> >?G#F?`o#><>?wDN?GoăTH>邈??Abd?!?j?<"ͽ[윲1Gio;qTm[H`^L=XQeӞ(~g;E>-N>̫=YUQU̽¼f>v?B?g'=%>N?N?=F*>?T?~?Se??ff,;=;>b?!U??nޱ:'=D>d?[x?jfA<ᨾ>]?(}+PA?1" ?-'N?qN 2 U?2??_c1Ac?]?!d?s&57'?E?? 8Qc0YW;(((vg0ा4@7l7nͽ=\|(>Ti`$d??P/?? m<]!>'?^IM?,2z.<`E>IϚ?#n?|i@#޽#Z>?;L?g0&ԾI>? 0nuI=%>??= Jqaҿ W-^}OlLvɿl $3?Ы ?9?Z?R? C齨;>?J?`U_g&>?Vu?ja 2??0[$]ʎ%>?^3KhHZrE4Wžf 93ۜ??I?rvJfؾj)eQfF?FM??Ư3ٿ&ݾ̆%D2¾=:y},U>+ÿV8H?>Q]>eF۔>>Yk>ڝǾ =?KR>|]c!'?DV >]_Е)=&-Pbq>X9|t]>ў?.؀RU\>~ߌ뾟Js?lW;>~q`ُ=d >n?@7P?Qgpk]M>O@=?h?տD> 5?^?'?#S~Ȃ>μ?ҿ?_LZlz>q???i;߮۽/Sx?>w??ֿb`??-?s?߫r؀J=U?P' ?bS?O[$-~>!?q?mԓauG<Ծۜ0{.t'<)2dgOT=Ⱦ{پw ݿocU=㾟Lk+4"P?KK/>]ʿ \оm4t!Y=Ɋ73Lj¿үgU= =X(>aoN3>&=žbN ̽Ï?;L=>2ƕ>16=M>Ⱦw?\Des>2gϾ.I޿o]sy???ukyT?=ur޼2??@Xdժ>V\??~gYLK+> =W?*?giI<ž־J>}D=͖ pHU?8:R>{+p%h´SrЁϽXq>T??S0^A=2o7?Β+ۺ=plbL _*?Ҧ/>A ?+!|-?Cp2z>:M<,ץD׿LC=>>Fb5?4 ?| Xo!'% о?FU=< vј{?96d>>#53ylǂ< >O=Ci>~=?l??Zژ'>g8-v`8 }х\>pi?Qz?MpH@g??~Ap7>wu1tĸ|gf=_=P?$?%?}P>6=ghZ?Z?oQY]>>`=? l=q=]+?!܃y>,s&<Ʌ??^>!p>BPr:??YFRω>䘁?4>?PxdUR |9y ȿI'ty>ƪU>F6m>#7?_-?~\N>>B?'?Z8|m=m>6?^?d^_ K&RB>›? ?=ɓ?5~= 0ۿ&QLa%_>RY;͛=r$nc ?7zr=BW=8\??lS ^s=r>і>,S A("4?!?`??yB_`E,y?:F?p7?ZhB羍=_>>ߝo?9y T=hj@?1]?Db?1t?[==2??^mj>D=C=ŬG?E?o?"E=q~>??t?> բ={=*W!?}?W-,=s>7?S=>YPAn>.,?U>IE&8~o->c?n?>|=SH=H?]?nߵ}G > X?v??yF= L=ɾ=a>`=o=?uL?-v=F,2=U)y]?J;?Tν0) =&n> =_;I/>ŵ=,??J>?dDc=Y2>>9e?Dd> ;=>4{:>YUq8Z>A$= j=`%9?sy?4G<`V>lUC?o_-?]?8oW>=z?7>| k<,ܾY?Hj? h@-9An=H?6>2ӿÓNV>V2 ?*>Oa"}dل=B`$=j=*?s9 k>e >?g?M13?l ;2>K>>? f)ρ= ne?)>4?sE S>D=f>l? =jO)U=83 >N=X影4=.>ώ\>\ :>οA> i8E7K#>k ̿2Xq>='=*=2*(>3F$>|>%?F>uE>W=Օ?R=C( >QbB5E>xDV=JPr ;>%>W=;>8",@>2d%5>{=1>A>Cv ^ ȿ#WB=1$\=g&x>S>y;+y>Cv> .8&B?"),>࿠םi;?߃!Я> ,#z$U?"4>wQ? >K)̿ NbrC?*n>IWͿ/Z:N?. =){Կ}uB?cք2 >`57ÿWϿ>)> p@g>3ۿJǾBBBBBBBBBBB?~K>&U RM@[>~Y#[E@Xqt>v\&R? ÿM=y>ztz:?|_,=һ (I8?{4==ʻI?% =۾GA8{?H]BV =IwB?=jeB _?u`Q@h=ɡ?&=M3p>ovfݜ<?7ڽIUA3 m5?@Ȋ>->q]]ļ5[>*.q|>c>s<?_->\b)?ҿ'jQ= uqH=6.>P ?C6=љ"ˆ?&.ÿf>??M C?tIE6׌ZS>Iiӽ=r>urT?5ƿ=݌m>}䥜U>퉿 >i?Kj/> Ü<;[ӽDpy>xqx;x>R ?J>/{>KC=V>z_'U!Opx~@Ay=} >޾-ᠿa\= ؿ4K>ޒ rҿF3$t<ת>f˾ |x<Ѩi3@<>߾vEr@`xHܾ->=Z@c? ΐFN>__?D>? ?`|)>;>p> Y ?:T>O?d}?;;?$w'>y? 5>#-(?X>?U?OY_B ,u?`}N?*ԾiS>?o>4Aݿ}*=PY6uJ:⿕<4ʾ`EF^h9|mw8 u=dWtyȿi^> >'#k+i ͽ|=٧! kc^л>PۺS}f'Y?c"ҿ5㨿l:$>j≠]g5i&?'p>W'?.U>qq?BcҜ??kT"A *=&ù?7>Ⓨ;olnzl?,?qbNn,??$(W65Dn>)|? >_ nPC|b6?F1=4/ >s=?>澄`̿y!> ?zx>Nfٿz | ]=$?<>ZѾlPr=A>fgNXn0@$>#"? .<1Էyхl ?"ù?6"qQ֌:?? ,ϿFu?r?{>fkx5Bj?.?#-,jힾ"?c?Q5b־hzJ?`>8qe?%9A>m+iѿ42Q?E=S>H[r?.OX>p0a>!~_ 8k?>%7 ?=E{5A =!3l>X]4?D҃=ۥ>֜>!?I*ڶ>6.M>I?$4?F!-=q?>>|>(V>'R>AuKBj2>H">AZѾB?5);=>&۾?GA>YI]>Z* SL¿崽VL>JlVBN>"A6>; ȿ&пzX?Y;?\>]p>ֻ?8:l? _=qƾ'=տ_]t?y>`>' U(> >2}ÿwdQD_=ދ>D@"0sldcs? 4?3>#u`>?+> g_xGjS>>;c DFj#d=[>~>E|Xx1N=W>%澰$OAxpیX"=9>۾g, ,KC>7.Ű"dۃ@Mr>bؽV^FBgE>ۣD9ž>[I>Z?kP+\Yw>D*Ag$ݾE_>uGL!#?)Т=D3>Mh>ۿDM?_Ϊv=(P=Πw>p*MN{jz}>Q>Sz9Q `>K=숤ɡKoJweK{>Z)f$HD>%$>}c>H>~-㿵 j?>b9EV4"V.?$3?IE>ཿR>q>Ҿ(Ij1Yd$>>ھm]]ǿS>U;S8yB1U?Z>=UI鿃,AYG>`As(J/INyB>X$;33rE*U`?;?@ٿ)$DE ?d?UVu]g^>Ѣ>7Ca򿓜|TX^?,U?U7y0Ի\ kH"b>>IoHau>(>FĂ?2I0|;1\d=̛?;cNZNTY??U`![=>>`q\>U>L^tUY>e?9>N0e^N>o?Q$>2=iqW\>;?6t>6w̍`>`k{>%Ծ]z~AF>z>3<؀ȣ>:re02f3>p>/Nw'ۿ9~ >޿BL0>>,<ςB =$Jb>=3پ~Pd>ˠ?}+>4񿢅)f?Q?3R=LBB9ǟ>?J>CR?+?_>$3BVl>W?C/=|p D7$O>D>Z=w5"ßGkG=қ>ؽ)b5 A=n? Q>SAڥ>:QM?p2=d? ý?JD]X``'?`?O366J|>b?l]> 3/wOo=3>=B X=6/>T<4& FVm=x>/=X i'>7>Z4y,^>M=޿=[S>; k>@8>,Ǿq#ݿ> >Ta %>dt>ɽ2jH=?e>wD1T;*m>vK֗JYnx>ZC-< <>=ǚK%޳?>p VGu>-j?t?]>E"l=?M> OjTMD>̴Ǹo=GԾd>j]DHtl=~5:KU>7>nTˡN?#޾Ո;bp8z>/?;I8 jy}>-8?*!LRS&=u@?!>cO@$r7=C>ʛ(A?BO?Մ>_^qA?:T?в?:(_+oK?AD5>΃fuѿ龕`B?X? c>}̿~{>iR?-k>r[e8D>@h?k? >&zٿ#P>)?:?">E47:P6?#k}y !u6>(?EyT_z>a>!g~?TU?T=KwU?t ?(>ȣc68,=f>U>jV!Q=j> ?=FY1b=9R>ሐ?V.H ?Xi>Qk ~NR7Hm>@=.~Z j>6ŏ7v Y_)>|>)ƾe Kqދ<??y.b_r=/b=? }7{S~^= %9>q?&vymk٣>D==? 5߾dRӼ T>B?~BJ`l 1>D>]!6?,`Nn?Q8z??V> @½I>y/o??d0^?QiEC?`?>[˿JA>? ??>nT}v>>?p>a Bl˃??><3M"K?}U?Q=ud?y;N?2r?f?/[=}?_nr?9">!|N>!{?{u?5>bے=a??iL? 8c[!> ?=\??<"iǑ=?lI?7H>Vؿʃ5=a?)? :? = ?K?? ? ==غ?,?ۺ?/Z}I=7??S?U?PwG*>tu?c?s>)$=?V"?>n|I>? ?cR>ǿA>DR?s~?>S?=>Ⱦ둒>hH>ʿdx<>m?sMrV5|_-H?p?0>-0W>?±>? >?^H9߾?? >0BF?n?{˜>)a߆?,@@?'?șR* v==?4?gQ9Iu2=VG?X?hҾ.*n=<”?=k?=Pon?.?E>RK?8\o >K?&?>$S @=> 0?H$ľݥv}>}7;>M&?A><&'[H@X?X??VlH^s`?#?>~Ԯq_<3 ?>J>45&՜G& =M;?p?~?`oH(>d?R?:??bo2iBN>n׿TC#>W;>g?>V,:.?p/1>oa ?foݎ=o' >XF< ?5׿@=G>K?k8lο<e>?Ov?%>d@?Xu>?UZ sQz&&5>ol'?s&l??UL<} 8?E?ZK?ܵϮK]? ?3?sѾn??!?7V?lr?N}?+x?=*?x>MF?dҢ6N?DZ?RǗK?,m?:?Vڼؾs?+ ?~||>)A?>P؇<-o?R֪1="h&?9>c_??#~DUN=t=ۃ?$>?@'YV?5r?,s0h>k>?=G>d?}u>3?y?U> 5ൠ?y?f?tK[?v?5H?:ݠ?U%H<>'?>౿Gŋ;Ċ(ٽGuu?^J0=Nk˽2.?T;^$>|*=1G ׾&- =>_?A>[fs J>v?3? ?kQӾT?@ g?{Qc 6߿81?NM@6?*]?$t@$@!q?ߝg!ݿ"׶?G~?xO?/WM=??خ?pkv  DN?Qv?j?`>߽?/@Q?f43=B?ʏ~??98 dϽy?")e ?C 0u2/^!#=1> e>ՙ}W;&=>b? |>(=؀F>I?e>^>TU"nhͽ?hZ>d?7wEhYl?"2?Rf?ӬcG?>X 1?Q;> >I ;Q>>Zo=G$EQQ>T*>;}<ėwO{<= *DA?#а<>a==_?&z^پ3M?Ȟ?k?2 <ZԽR~RCBW=Z6]a"Ĥu-=n7ԩο; j=ȼQ &)k\==շ>?g :,(>ͼ>T3? 9m?X?^/?C iҾiI>l?? ]<Ϩ?U$鎹?O{`RJ?q?&$yD=<Z>i(r ?kpSo?`?hK4?xS\t??±?|>I= [Xh+?9?~?r4DZϾR??qs?xdE9"><>s>cwFt?߂EDH?8<?>K?ŤUh:?[,?Z?Q RzD=i>HM4*oNxl%t4??s?{>>_=s88Sn˂@H*?Iw?87y<矾܆ϿQx?L ?s?l?S?!B5>a> =ud>ud?v=b*ԾV|?Ű"{>( >L=&>>T ?=սt,?鵷?=C~R a'?ۙ?k=3ľB ?,,^=r?+.M=Eď n[!h?z"0?_5+(>.8> ?w? }^?'1?A=*?6!> $@>>?Mfx i3n 8 =S<+m?p?\}??'??LKfZEyPSGh!v.὾?EǛ?FL!?F;>ء8;ܜW#wv_BǢ?O8R39t}>>>G ޘ3u%?^>Z ?gQ~T?-<>r3Y>[J?-s(?34?M ?MI^/?cZ$Ij.]X?'?5?<?خ?f??[t`?1W?Vϰ`!<=t?J?d5rW?1q>)MQrC>hV??P?J(=5ڭ?s?=?X>d/?]o??PPT#N> F?t?v1<%U?T@??}ʌ ~>a_?Q?{O9uQP>m?#?L t`޽Rr?Fg?P? =6"/9e<< _%bAWuOo-'"5̔ZſUv^-(1O?Uְ??_?wA?s{>Fc>yh>z?*OA>?U?J?qX??n?O?{?!@Sv` 2d<ʸ]贾 0,=>>\>G$ڱ%T(>0(A?'?XΎ???}':M>q.k7>N?Bp? KxyEq>O{?)V?a( ?!w;&?U8A W?(<Б?U|<( 1{;U_9"+\꾽?,D?"}j=>w]W=>DzFT ? Pu@f>S??'g^?Vv.u=`>ne?fsv>M%?!Xu?S] X=.II=u+3v=8ֿq=B!@'=-=g 3:O;׌CrH{ul޼BUޭ`x cgOHm_?yl ??3@~?.UF=@> v6*?4D)N< ?{t?z-Dk'?m%a?7P 8vV?˴=>?g]¾J>W2>dPF">&{ ` ;r?<]>g?= F*=I#`4zٶnhЉ<ſ1'(D߾V>?UG?= L˾\=j<ʿE >hj?=hkYuxԽ׫yQ=JϽĔOҍ C("=6᜿fbX?%u>>>y??O>>7y=Puh>{TN(> =ж1?p@e<>>G?oMgƽ#X\?*_`N#]>?P? 4tC=5;?n?iKtnrPC>Ta?&r=uEm>u?^ ?GIs=~>Ӿ=cƹ.GH=+X&$=]dT=QZpk$3Q>c=pC?48>)˫e[sb '>n>횷[?J>O?4=]?(=>6ֿ'?O(m)7L>+??qj;5?sz=Ct!:ֿq͒{h/_=8-O⵿;ǿӿM]= P =ʱO6>Q>(e>h;?>gď?>`y=&ۭIö^=9Ҿ: IϾ8<>&>u[<>x(=/~>xW?5??~y=K.?.[S>/j?>*?a>v?"⿀r>1?\>x?s9=p?.$%>u? ArR= ^?Kj?T?N``3?!S??e!d򲾰=fV>?IkՐwm<,>Y?1O?j?=<ݵRTaPMAP(M &"tg VPA̾=>'? Uuֈd{x>/?LujG9IG>Y?HM? [ Nw68IVE^%=+ɿi۽g쾳>ƠGؽ˒r>57?3xZƾg >?3'$?uvАeeEo>?Y7?"l)%\` 5ܾ0 0hl0:!Y!Ԡu۹о7gS{>>b>??DjIyO;'>A%?dNW.W=()J> ,^>8b^`! Њ&> ؈>ox+I=>VUreX>?\hQ?z??r&d@վ—}??H?<>$>??rPef??J- .=M?O?T޼W?{? l?Awg`<ʂ&b7\̊W2?J"C;T>܇?A?WiBA>zo?L??-ØZ}AZ}>:u??x:/=?9hb?aJ?UGE?z?e?qu<?}>] ?Y?>4">U> -?EH?G<ӑ !>@F??gNQ>!?>@??T WRKV?bh?3?ߨs罔G[8>28\yQƾ .>L>d'њ]"%>%>>М=?6+I.}>Y=bp=QՀ>7r=vOH>bJS|<>:>:y?-=(>W>R0y:{Y>>;Q> ? k>n>Sr>W?0i8p=Dg>)P3?M!?R4Nd4>mv?g?F_^>>6?bHR?;*?MW2> ?[?n7ϠMDk>n#?i?z Wz_2{z`v+>"=+>6C>F(psc>^r٤{FýN¿Dx }pI,>I?h#?/˾O|> t?L?O4=T"=u:?J~?XB3EJ>}YO?l+? `,(">vu=>"LqX?c-?P?̘͘>ugE Ol>YL˾ e=0o>A=ڶ>!wm>Fo>{m =wt>ds?j^?<h>"??ܿJA㰾 o?%?V?.?K?Ƌ?& [:?Jb$??5: Z?&-?? W:esa="ߓKYy<^<8ˎ=>!Tg+=c NQʽ.xY2=i z0ohi->p8;>>Gfj>ڝA>~.>c?dw>pX>>ӷ?((ᾷL+=R?.o?HEco/7f>T?k?|DW߾D>9N])Խ~$=Ə>~U뾅m?+ ?Z?/ؾ?M,?;b?0$0Ĥ֪>7n?J?p%) gM>ۥ??)Uap?M?@?GǤk߽0AF}~̽q7=v$氽= >>qh%Wyfjh>? ?J ?[ gw?>B??=gB>P>Zh>z>.n]<͋tH>"i?R?0?ҿ$*5?b?$?w0?#?? obN>j8?J?ODY`曾,s>+=??T*gl=.RTS?@>QpP,:8~?\!?$[?jcͽ ?6B? u;,B%8&Ɗͷ>'??Ťv`BA{rM|q轊Ϋ=Q+\2=4z[=?x}?]$܇UDqq> a?f?"~ހ '<?fKf?jCp!e S= ??`t?Ay>K uɘоR\`=,M[)>ə>fv󾙣n=>F0vhོϯ=w>q@MPcea=/8 Qf+^M^O. (`j𽼠W:N?ү=ޣYlYuο~0=mU? +>С>8A< VϽH>. ?$=Xf^,0{si?4@!-= gܾ{ $?:&RX 婨 J$`K/=ۼљ?T?W>GDe=g>?ݼ ?lZ| =xE =߾#>x=I;~>! t=ꄾ>?P?q <8NCX>/>}WyPᇺuc>\>>r>#=v4= ? V?rZ%?6>+=jQ*Hv=>>X=>2?y?wP^H(>@|{,>rX>e?R{'=/侹=kB>$=I?HG ?K4>!0k==7k??b(5.s>9\B:?V E> nNb>-l/g?N9P>n?7H>;G$SvjU >]S>>/p?O?}>1_=N=7H?H?\D9/=gB;k?rvB?:{VCK}A?4"?^`AQ&>p*>as[oWy>Us:;2E>>lC5T>o>_??@F*A@>>]M??Puλ# 뽾?o?<>2Q?=> rK>z?$ɼ ɧ>7N>.B>)Eus&U>M{=B[J) JZ?&>D-gý!Sǃ>}>L?oXڥ>%>t??Mn ?>,?\=f*YSο&xOnx=fyh>Dx>|7:u>>ԿNZ> 9~azC>[=ힾ޹сGu>:>][>\] ֽUNJ>O`I!I0>d1>!tmƿ.:;b;t< 2= ݮ>> |>&$=gY>ذ>+=W=vZȏC>> ӊ~9g<>1_̾z>Ls>᜿M?U>ʿj׼M)S?}i=\^пuxE˛?$&B>=/41> Abh0++TZ>jlȆpx>SP{52/?c>ȿ`Kq?\O=@d\ݿoj?wlܠ>X˿Nʿ? >X0:z D >°,>߾?> =՚1 &=7T >RD>GCg?@UT>>~.T>BfJ?>+=6=jN8>Q>?I5>0H>>Ρb?8:.>OӾ ^?Twy8?>,05M۾>n =t~`>,>ɽb?H">z;,>|>]>}> `?!>I? H#[>"?G? 1>KJ-4>Y֮\X?U2>꼶w;]><;y?V{-?/;ɽ}|-6O>⦆sX?4?k?`9'p>T0?k>?"B->4b4?2o??mC(6??{=&?2?&0?=*??*?>+.*>dؽj?Q?nB@KwO>Ty2?؋"Y>^$S3?޾ >;S65縿͂?jd>BB O?3<>A1=E:q18?}f(=`GsSX?3>◾fk¿u`?j>YXھv?*>LFcKwE@ j>vjU 3s@$)>>MD?Hk7-Y꽉 gu>M7׽݉HqiҿfV<@)C:im>XU>~>kIZ?VP >e RVu=? l7zMdY2>? FG>U8>q?2d=+h{wbN>?S}R>p?tV>?,АMzc\[r>><Q(=? "a὎㿯Z> Ĝ>߬UIsiH?])>?=E>U+?F(xs>D?4+>$ ی?_trJ>c?->N?c=7>è?|?+˾y?"Z>5=?9,k>Qؼq|݃=?]>U"`F;8C>x?B,=PNDlY>j?* X\<:COl>퍾ɎtX=>'xtqk&pؑm> ?> OXۿLg >_?M>X[iB >p?|ی>D6<=~>aʿmپ pw<O>>LU7`}}d>|<-Ia.jL@E>w>,39#p>ֻ>R?Jm&>ju/>?zc?D,p]?>?/?8=Yq9ۗ=s?ܽO2 @܇*>FB?=޽'8c7z*>з0yV)Eu?9{=fzJT޿ ]A?-=es;>?K> 7忎!X`=ɩ?$z$,?&-F>>%{dp",\0+>>h!޿W )??|pU;ѽ9?/=pU>dI?e>xi@ml" >?r%>rwj߃hE>x?ڽ9ο35>+? TTN<ҿgڒD&5? ExBiCJjD?+>–[rֿK^? W>ھ@"Ai胺?S`>k$ۙp=?{>3M{ ȟ_4?nq>Fٟ4ҵľg !.zX=79TdԿ/=> ?G7C=OL&N$&>iM?c>l4;y\B"c>V?_?"s<ֿ`$Y>?E>TMf~Ի~?jCg>.0Pݭ?([ri;qv;C4VT>k?`>i}kf>xhW>GP<@pi3 >H:.ӿt}!??Cx_KW>S?K Dv;Vޏ>>F$M n?c>Q>0u+?`:S$?R{ ?R'k>~H>Pu??T>sOIe,M J>$P?=S9v&$W(&>0g?.>3(h^= 4& P>?}>?=>d>&?n>I(;l>B,\>e]>䎬nT>݌+\>wG>O X >Q #>?N>ҽu˾!j"=>d|Da:)>?af'>w/oU>Z=t Q^)*I?Y?P>V! Tȶc/@k ?m?5aDR?>OR?}>gNgCBkV> >8-ڿPy.W7>>þU2WB9{>f8% w++>\&QkH=M)>}5#پ5Tȿ>=E><ӟ*9} >s>?%_Kfنt:>F>1b޿7FK;ڡ>W>hKB=A>Nwڿ1!޿*شC_-??K>GQѿ끾bZ?G?A=Bҿ>??g>F} >Dž>Mq@18eR??C= C?@>#CCl?wB >V4=&!Ln>t*q>Q抽 迁7?ܿ>Lq ʿ}?C$>P潝yQ ? =>=뛪M-?vG9 >BF>>r+ z\C=V>Ϋ>C$;qrn? >G_/ b0?P ?;M= Z>n/{>̾Q=Y =? s BվA:Ci>n>=mD$p~z><\plkDDg>-Vh!31bE>}k#>7!վ'u6>D4>GAѿ,A>1=i@l?J4/>/>U;Y63i?¿p=Ѕn=gc N?">1>)$.># \ >q>Xm"B\F~c*=4>*TSD]>I>fҊ翈8>=5ƿYL9Oaz+>NmY2>p>hͧd=K@0>\5Y:`)Qx>]l:< HēS?,,a!XtxLe>eྉͿ,丿#>I =>B=?t8ҿZ?A=s>zBr2 -u1 x?|^?>9Szm7M]?a?{ =ǿuZ>'oƿBT習Ci>Ҿ )tv>Ŕ,"l>H:>ćI8>'x>>Y)?>{{Cw>N?k>iD=?8>0?:>Zwh?M.p?>'`? =䤾ƛ?a"0>8(>Lꎾ#ȟ?G1M?bѿ >av&tK?m=H >X2`w?\)=f>OA6o GOf^>QʾbWQr@R;!>,,?1'?`>8xbOV(>o?q?@d>@?l-0=ӷR>9.f#{07>S}>0׾l7p^)>?i>' ľUൿx=>Ƶłӷbs=>oaJ \8>m?>} [݋$R=p>ɹ0.lh= El<=u?,>q¾%m3n,>'9>0K?`z 'I>~Se>2U?$hn<Uں>C?_+>hEދ]1 Y>??=ߚпi/`c9W=Ҳ:?uH>_p3>!??{>$B[K< =%=W>Qi+e ?2M>#ܐ =>ϫ:/_Ծ.M l6<>II?6[?jT? >P]Ͼv?xY?Z>j6<ӀEK R$>j!!QY~_|ֽ.A??Y>O[`m|=*x?K>L=*]5weˡn?s? f>2:riC?7\?>fh=ñ?Vg>= @@ p?`?N?VJ>-b?u?@>tڿ~M{@:=`?b?($?hs0}=<>ڔ?;&JkȽS>h=D[CT>ƛ=:?l ?ϻ_?:P>ɽvR7Ⱦ/=r??p?}$eҿ z)=t>??{Ľ6}5S >L ?¦+YY! ,G>L?HKᬽ&oRF >TDh8&T>5&>(ۯxrPxR?C>=~b)$S?F:>F5=|H?LJ>ޱ=">>4;>6?>Tּo@V<>?<d?7\>s_>v?>Dc(;ɣ>}?WAwdB<%>y?I` Wjj?>:;>cL-kQv|?6i><\u}b*,? {>j2n>xu?ZDO]=^>A?=w@=wBCD?A׾%9u5 iHu?R6*> 8iԩg??knP? $t >1?^`b6>?o\`a#?_c?BΫ=,Xa?ў?n>r~ȼ?l ??m(mr.?t?T?)';I(?+? ?jӰ/O>7:y?K??IZ9M2?K??jYm?p?6>ЂpU]` 6=??Ȏ?P_Z*?\?>ݥ m=??Dv>ǁX@ >1Q? v>a2㱯=??>`hOhq9>/= 1S%N= k?r?Ï>+g?cR>J}>`[?6>GI?߿x>?,M?>v>9Ӊ>?X1Y /vH<~A?u?|?(Y`̣@>:>KoTʾ8 pݑ> >gd >:>>InkC> E(?}?ߘ>st67>?f?>>ِMF_>x!??{J?=>rF>??hm?V?[=<ޘ> h?[}=vIDAK>/V:?g[<"I.?? 5>oMԷ?h? ⹾RBbAٮI?r?>]?Pn>N? ?v1@>-?q=j>$ 5aE=rqC?=z;?]g4?=^=*}/;V?VAp?|g=s0 ?`$-=4?Kp 6>:j>?#cٰ?6l>a,>+9տ?<=Ƽ j>(޿@׿$V>?s?0>uX>:@>QP>g]?m0QZ72p{#B?u=(,S?/w?Ø??Q?Z6?`aܔ?!Qrs: E ??d,?_O???=k%?=ܔM=y?i/?? c=m? @p?«I>"i?@?Ыړ`ɬ>^.?A@5;@IR(y>TS?YC@׈@42h49g?\?0D?tj ۯҼEɣ>b> ;܏ja#<_T>Օ?;=u'% Oj?ʍL@?w[(_?cbN> 2 .s?tAH>Qᱽ:?₿^>Y$Σ>q?;=gì^+>=|V>wP"?~S??AἈ h] > :G 3QKfw>/*Ska =^1H??ɽ)(?V/I?v^?=fG>y?)m";8J?LMV?Uڝ~x%v$Q?Juh?{m$x4?Y?x @B  l,R?>?.@b\sd>!>?c,M?p*?D,?H?G:>@ >XC>+W>Ɏ>P.8><> >u>yH4C?+W?>ƛRx=hfIb]gI^+?^Cm"d >? =nֶ?b?7eu7-6/?{ U[g`53>2= =4͞WZ>==GEa>o>UfI=͋;IksžQoTTSlR?* ?$?ZWF ~y?6>c? \5y֊FkpȾA[< x?6<?eb;S&?H[DT(? q?.?fQP~'3?[\?>%?[Z[40x?S%?6o?VE:08?3?.8ny( *[ރ? G>?)jk}(۾Vc>>x >lBܨY+GE=ݐ;="6Qd +4V>)>gW>>?2MrT۾B?;? ?Odܸ w?pl?Of?}Y5.X; >>}>q?/=>7 )?*-?%0?뢌ߩ?+ͯ?OYձ`?SJh?!h?~ۇ?O?JP?N ?΋?Q?b|?Vm?x??0޿Q? ?@?Ps??H?4D ?"i?. ?sU?9?tA?(c%?O#?^ ?J}?/{%l?x?V?! 5?-O?D?'8?&0y?c9(?%?xU;2=Z=wv >B?u=F9 =;?k@=z>)<;>? ?O'=?&%?)?-?P?H-1Y?%=d-E?*Jz xKAHO Xv#`m [?ਾ@!S6^[$X$gY\ d?A|Z#3k?h)]e$@W:8q??,|".30>=Y>>=?*?*?[.?e2??/3?+Nw7?#FVJ>.\$xͿl?TѾvK"0澽wP/o)N^.˿?KL?~?L`7~*>ʿ4=N>u&>8\=©>*x2¾=R~>=ٔ>&?.Kx#| g,>GI4KT.ƿ(_?D>"?..?Hȝ?n6&ת=s׼^aJ8=Q>0=~L׾Bcۼԡ/?,(?Hs3>_?O?@ >&"&8]47>/@?Ta??5??o*?om 8=??=0?zW/=N>?V?h?u2\6"?W??[h9=!_??C??Ŧ\?E??s͸ ?q?C?|q`/t$?*??̴^us??m?b`<=ӵ9>>Ɗr? 1@al"? L>m?Y4/#{)c =FF8(O@jHo?Ոf?`5,L?)e>T3?/6"H&ãq\R:=jw61)0nB9)hx>S?y? ?h7?GA?d71?'1?GH@E:3J?/wG d ߽R]Z$?;M?R ߉jݠG8a> ?Y6?#p =iIOr~chj=ͽɾDj=2H%=׽T>{G?t=eT&[w6? IE=G9;va[OE$>` t!%>?Z2?\xt WKC>ėS?B 1پ 6@!vKwz8Ft>? R?or;?-6z> >o>+?=C"xv?3?>u??zRf?/>r?r`}R c>>X?||R^$8\Gp>ky@r?ogo?*x=#ؿD #>il;UQ׽bpW>pTSɾ@뾯f=]?6Y!+> ܥ=u=e5cm?>O?|?n ga& >I(?^IRBjz50Ň`q9=jw L辆o=80a¾~??IM?8~RW筎?#|W??BnW5>ϼ׾,>_tw=>z!d>':6?{~(t`=h^?24U?.0f?&tO`j> ˰=2+7>Dt>kQYhۛp ԕQij,k=r?3(??:y׽QU A>PWs\>kq>8>0}g>๾N/B<[>i9}>[^:횾=b̴Hϯ>\r=H_>,%L2>"?(TAd=SW>s>׭ATW> -w>BA>9sA<2 q=*>d4v)I>,g?t/q\!B$Gf>?D?T!2j>O?h?SWUv>1?qz?$먠^NM'?)?r6mzZDؾ>?Of?>ѾW7g?'i>V?d6?uNpcIjVW!?0?gOł?[r??`|=|? ? ?i==.>V~>ě ?8g';&?ab(?[?EzpW">M>)>qj?0.Qn>l>ğ>q&>> ?+,j_0>??C&оI7>ݻ8ƏK ,?/j?XP =҅n e =ٿhPwd>&>>?P7I>!>/>h?ք>*>4(Ծ_Gs>?/0=w g>ј?zkr?|NBYAľs;>4?XT?]Ŧ=\վOZ> o=:4u=3n=GR>>+> -7=,\= =>0G<=:=>(>ȨLdk>,a=>I _}w>Rc=P+>?>e#a =k]>k+?!%>c=p? l?S>T"=l0I??@qa>v=U??TNƼo =g=?J8?"-8qۼ->:?P ?&I3>?#?k?́k?L$_?7?n: %:?3>?-?x&g@:H|=>W0>XS>L-<=ElQ=e>!Wp =V8T <>녿Okl>.>K? dB=,=͒V Y`?? gQ[?s?f8T'N3?;?]5?{ 8?h?VK?Ex!"j8)>B?DQ?:<`%;9ܾ1tŽ=_Y^>~T_h=6$S)A>t:<ɾ6>&[P>O#Ϳ 9Q/ 8wHy>?4?? y.l?gI{?{5?/M!`???)_CYH|M#Gm*?CJEJS>S3]W|t<> ?LY?@{2Mj>͈?d?S-I ޼>z>ӭ? ?vA߽>S~??oa3??p?zaUu=m>D?]?fjX<^?w??áwwք=>z?P?Ӝ9?}gH>?|$?ҠiN#>>?H??;>3hH?Cl>~dC%Ǩdk>4 >?Y?聾x@>>ש??i쾒 !>?&??0f0&|>$v>?.?vx=5]>S.?c?ʴ޳p<܌}?R@?r8tfo f>Zx?Ï?{l(t>v??ϩq G=%J??Jjs^?QI? qA xľ p5}#FCĿ nrK??B>䗿cþ=E?̚4>% \t }S==IJ1??\KpmXqoDx侥>>??yѿD,=^<?[E?xmŵH>z?Ǔ?PJxp%a>\S?Yh?~OPn}?v?!t@tl'kD?D@?) !: ӳ"C2+v``D??6hӾG&f?;>/7;TT?9?,EiO=ܞ? F>T.V!4oZ0=E?K?;Ǔ?F>č~qlսkM ??nߎ;LY|?I >ߠ=g=GJ=) =sK?hl?LVbOw)0LU\jij$_[4j]'6=Lj?>"R t>TJ?= =Qz%5!?!I4TLlhʴfb ӄ(]UO˥Ez'|8%lq.j`j W6dܾv= C>~#>u罁 a5?Ab=D,#1W#>t>B?z^LQ=p?]?K;2KZ=Yt)?"?3^/=f>P>z= hUT>͊3>Pz:0<8>>=!y? uy=_th;Y>3> [󾌱>{@)(>r>;TƑb0>_J> a "=&i=3P?&?hd>'m?ׄ?-X@Yd>yd=jG??AN<= ɂ= ??eGkiL򌾅>>;8P?)Hr>ξkl5;ppL=S>+[-?x??(F>9#UZ6>;>">ս?2>#-><>3!>>;>T(> _!޿ 1=7:=?Y?jh>ŧ!!>[ܭ׾qG=9ٙe0>>k@ oaو-92n|tY ݾ(&"WVDEZٮnD Bͽffsҿ"E,ͧҾ+X7q#Ga1&"X>B>M{K_}t>=sk<==Z>?M?'>~i>9k3&-?#>OzJ={=.@6i¼d>#[&UҾG!qO)Uc›sX14:!'>> ̾n볻>o>d&/>VA__>Z G=.=@??g')>Eo>v?F?{J$z=I>rb??JXr >D]?M@>=߽0<];SL>ReN+?c y>_? _B9NTh׿_"@?C1_=>^0 Ծ=aV>g?5b I*0>b=#K>!?uX&?7=݈<>?{qVer?-ת>;辩] f==EF?8X?SPJW>v W}>W=N3~_D,侮r=`=8 HlF>`?rm?XEg%t>J,Y>%W?.0?`K>SCb>?'?`MfT&=Gw=> q/:#Pӽm?QC?/c=@GI=ieM?`??k㿁P۾,v>d?k?g'WR>,w>;r?GE==v>f;,3Z>k7h./>?}=?xl>}Ƚ> ÿ"!K?F>=Ξ%>.Xn>wAM([o1 ?=Gl?~>`Z=1 WX? T?ׄk@M`>u>>{<`J?~&T? ck>D<[=pp?>־:=>"_??ɿFRBE>~G=Te?tN?GW]>FV{-{e:DtK>}A>列ľ9?>%>bOx}yTʿY ? (O>3DJ = (>(>=C=upb>7>ZZ6ᆱ>>U>5$ґ==E=L?+Y)<񾙫>>fܾT ̮d>>k6>z5>7~?k&?N!<̷3m>t 1?>h+96>~n>k=?~}?]E1>*>t>B >ޒ>׌)>pX=O,?/?%>,6>_<;?X?ya=!B?5?(> .>ZKd>ܳ>>* /W??9>Z?GDN?DV-= >9P??b,!2:u>j?f?3>Lx27>=y?/4?'Ғ>62>Q3?? 7>2?i>?u/?q6>=6?B>ӻ?J?w:%8>/I׺>`>$_>̇w5?>#?Xi?Uf'?"( >½UR?m>_幑FԀ?ۦa>eM%`?¾R>ýO+tW?Wz>GT?q?卛>i<{̾W?m >Q(;;?{6>H<񈾜oHE?aA&>\6{(1?~>=v=FP?X=.(c셿7<i3Jp> sZ?G輿wwl=d='4$>r<] [>egp2 ֈq^}&?je8>[?ך1K>;~wx?紿S>>XI&؀|Vm?'_%hHz >E?MCz=> Oƿs'F>N:<[>=;j^E6#e>>Te=L> ?bV`BE>>_˿?T/>% F>y:>տJ?bXaA>z[>>*^Mu=:ya;>=JO5>> S?"0NE?ݿL>-e>e=2[w2_󾹌~? o>Xž AV4>X>TF/ܿ\>>Kȿ]_nQք?) ? ?E>_?"aJ>]0@?4w0>ȏ?Y1w>^d*Z>y>:.̒+% Np?v?>?t\>]?>G{|I(?BG_$> [?>^-Gqg#n>=7Ht!픟hk?I˼?'JcW4@%Q?j?Rʽr@m`v`tiÎL?-q~?rd?8IQ=&>bTP钿|ELi>UT>,R ==>t.>=o>_ݿp=.>q>BwQT>8:0>LU>f@dI(μ*Z>5sO!qP$پY6?'<ʿ=ӿ: ?4W? K=ym?R+(?.9;0ߜRcZ?[-?/پJQ#Kbk?%M=Σ-p"ƨf?3=֝=پp?8 >j{˭?`p>ۿθ0ۿؾk?&>޿ 5yAB?(ϯ=_M7& ?r}>?O)|-=E??>k_8q>GN>6(Q?C? 89?_M?6˾* B? ?N>!73;?P?8=]75~=I?j?(a=Q<}<>#m?z?:Z=KӾP>xn?Yә>qiux >6??F>s"4+0 k?f"?=/D/?)?[h?>fL EQ>,?>-*} ͫ??&ו5?N9X><?>= ft>(>gCf!=RQ>W&?Oi>K$~͎┣6v?LN>f0SEп9$ 3?6y=쐂ݿ# ( 5m?6=w >>F:=~¾^cZ/?M¿c>N=~AN?xCe>l~>;ž1><}E|>rTa0{d= ,(>a2=f Y/ ?-A`$> >L羔:ک?=ݥ<3gP?=:>D<͸?S3>? ?$e?^Qm>пJ ?]ؿ>|?D1?S+4?4; {N>?:H?UK}K[?#??) _Xk>@I?/>߽-HPY@> t ?<=aDD>,d>>hX=y';um:>z>Ϛ <22]e?=FǾ: 0,->j ~1O0j۽)5? |=,G|J4>{{C SfEzѿ Lf>#>+&=>p7=ȏOW.<K볅aO?ր>*o?=K΢X1nT *,c?z?d(>ZH M=?K ?0W< !7?{!-?rc=9n7>LD? 曽?2+C>Y Wwgp?7=syRgYZ:s(>eM{X*=[ԝZ[k?]=L|0ӿ 哿~}?!-=XT1oM{h t??(p>wҢr?o?9>U'<? ?ܔ>">P9?&k+>S:-asd?S]=G.ز~?F݁>>y>⠿n k~2?\>#)}??D>8MB_fb=>FڿAJr[:P`>MwwڿNW>&3\#V:`Cb=ܾu FRj?tB=X>[\6q?J>= y6Yz;GlWj>E,? 簽|=*`1f6>>]^\N>ȼZj%ٿ/X]F? M=+ ^7m!?c$ vW=m=YZK?Ð*0>o*6&쿌?B/=u?)kQ?謹܍>b(??O?Ii>q@>>i?'u!߅Q/i?, ?;{PJ25,??1>Hޱcf=Q=5ڿ'>rh| ms, =6|2쿰ӿYly>lܽH LkX!y8">>>70Mw!)>\=+0VȣX~R_MQ=姏>0`]&#}+UB>ٍ>Oa 6 ^`NZ>r~=( <I觃L>M#?=Ck?NF==._=9>߾>rI:zj>~S=mՑʍCEĘQ(>)p?*/>EX!Um?!=O<=Fs˯P-=冇SmMp,>0=m``=UT\ yVb=pCg.VA)R???Zֈ> 3V??J??CB;>LHk??f>V4g%?ݘ??*?#NwH ?1?h:>rp>@?r?b>ρMh> $?b>=\?/4?$?=d>#?)==qˊ>yAP? <=I> {5\?,P=b== B;?]M{=>TlN*9<"@1?/?/?#ξ? ?P>7/wト?8?(>c+?$>D?!q>>3Qv~>o? Z=񕾠@&|ѽ??+(ty?(b>3Ce0ւAcgE=\%??U>M#>-Z?qi?2>>{*YڡI>9 }?6?K%G?*?FIoN- t;mH?}?GmSQ[('?E?jA="3f< ?Q*A>`ܾ;cj>}gp4]NWg6='N=9>tP/$ļOMr=Go>=Mqmf4?/lH8E=e=<.RO?I"x?&$?h=+9[{g?2?x[ſi>(;R>XCS6P2=˜?'?\Ɠyb?i?]>.Ͽ*3XB<,o?3>@gh'c?gQ>M=ߥLԖ_jɾIA?D1?R >V?$$=_@7lS 8f, P>? ?Hc4;\'=j&?'*(>*p r6Xm?&B?>zt> n>p?55s:!p/HI?0?;M>=ѿ察yۘB?E ?3>7iõ|}?o???|Cn>dw?ѳ?">W6i=q!?hJ?>H}|EF=?BB?>k͸N{??>Lw;֘" Ec>Z?F;>8=pr&x_>3_? k>J8/Nп߾L?,.?13>WgO-o=?O?G?f?:@h>#?&WKx?h>?'˜ :ɟ]½NJn?|B?u?AtG=_t? ]>'}.ѿd,>F>=U\ؙZ'>c?l#Ⱦ&ƛ%ĩzw>8?8?<_0t*aȾV^?!?fA>Uq_z='>;?͋aNu2Y'??Nxƨ> (97+su??Lm>C#N?[}t?d> T<4>.?sW?>hDAO>X?U?ht?&&YU>E>]l=0>)翪Q=<>Sr?jFё?f2¿3>'??>C_) =C?s?_ P>)?dIwھ~=p?<;>W<0Vpa>f$??[>=26V>#?U??0?LQCx>F@Ң-{?#)>HԲȣ B?Fb5>Δ%0z>lv2??j?wFQ ??j?tΠ9z?W?zS?=B><>==׾FNau0=f>_h{?Ӧ/!=?V>ŗ>hvyj_&YX>A?Q5v_r`0+>J?4> @դ>B?0?p>f?FZ?$?Z gWΖ??u ?5ro#۽m~?ws?+:>~O>?JVi>%=A=?I>=_P->?:>; zI=>6=辤/?>y#>Y?>L&C=Z?3r?z>Q R]?}%?^?!Yqh=6~??C?@Rigw>>N=<Fo)>_>;=r@Ҡ=#>ݽf辠xB=?-?beV?Ő/>:>Q?ag';v>R???{)>%# ҕ>,(=/?uy=/} C i'?O?]?^h*Nr"X?g?f>P/ CV>tO>h> (:h?D ?'X>2?ܾ>C>=9t>??7?[= tR>?=}?w?a{5>(Rr?Y?T?j">8??m>ݼf!>`>1}(?s?e>ѿD\<?;?=x}r1:>;?I{?t>2>u,r>z>SC?@h̕:9yѼc?v6?`zZ?>>RG?vk<p?=C=>?|>?I;e=>.?>mTTR K=af? x?=g Y:`=Ã>>*X pђ>t>T.>*T?E~$=$Ѧ?=H?1Xx?#o?t2>?:o>S/` Q=6a?s ?>v>6-?d?|L?D?oo>a>q>J`[#>T?!H?8>"p?y?&t?\$v =]O(dR?z`U>ac>4>a?*?>d(پUf?j??kj~?V??kNɡ佊)?A@P>޸c>I@?&Pm,|x10Q???\T$/??*?bQ Lkþp=W???q  OK??P$>#׼??Z%ʽy ?Rg>2A|*=9?vl?k4̑`yAپ,N>t A[,A3 Xv;?{?6Pla=B??,> bʗ?"??͟$N#U=d??)?Ǐ@t|?HxZ?G t2zN=f^>Aeqkи= BglS{V>8e>N=׊=] =>do>+M<ͤϾEil" *s?MI=??n?ex0<$D?)9ɾpT?s{߽`=?=Ti\ mik{ 5Leo3S=s="{Sf>N]:>?E:?X?8,>$?b~S?D>R*>4= $ xOGn ]?D >M?ߴYP/?Qx=?$`vҪ?8о6?^-0TUW?i? ?.<(c?0?@(:}?d8"2]?;y3]ě >E>x.='Vf^I>U=R>!+?p>OQ==aN=fIpwA$`>=}zKpih$ A9￈?l?wDēA?g??&`w?>V? >'}>.'>o>J?Fw< >82=^O3Xr?0f!% fJY[!ۼ2> >U>t= >!S>B?=q# w>p>>Ng&5o>P=Cuؗ 7c# >` >]S>>"D=A=9 61˾(¤TYm[o;B ?rOA|=ؽߏh8d=H q~x>.'>ʗ>抓52?#PӴٽŽY =Fڛ l`> `N=f]I?yz?=@h2v-M4+,?p-?Ǥ1?;1x?\jP o>>O>A l彄v'2n( ?([> >P>&V&>-H?,D?K<&?ھ=]%v= ==#=2 м_/%S.Z?;=$ :J=*?cվ{>ͯ=> $¾^J>to=zvS>iz;|%Iη>->? 5v'pH>t%=4>[B[yý#%=`j: )Qyr= Wu2=MQϽ7Mྈ@떾'q?++>!"=ϐ1= ~?n-'R1b(V0=4]hy%@hǾoxQ?-M?i4)?7?#1w?ׁ?5?>I?$? @?Z?đO?Gk9d?]J)qS=I^L>h [~x,ı=(ؼ&>/R_UX3_縼TZ`~?h??ÇL??ÔSx? 'D?1!?Q?9?.<"?rNW?D3? ?K? `=>s2oY/l!?޵N5?c?iQ?Ae?w~??B)X?q?%?9~հ?i?3U?[6-4p?QPP?|?9%D?Tf%~>{> #F=]T;i=8?O'?;n?g0?]堰?A?=KW?g^ ?*(?s*?|Y6y?8/(?g/(?]MP`)cVc[%IͿt[}?!}KxW`(Ľ`&n=>;<[$chOA?]; r(,?RY? 5?Z4D?9CǕ?8MQ?i'%nx?||=S>mZ`&IK#S?' |9AP?&>o?\A?Q <C>wTk'N6?>:?qb=e/'?~y9=cǾ8=?)0{?=2SĀ?P(V>T?ޘ??Mbh'&cV>U?T= 1 *x=?]S (=BSP naS=??"?;I?.S=?k?S?0 a҇?{Y? Ԯ?C=7?4? t?Zj#?L>n?ĖOt ?A>소?V\ם>J?Z?Nu?a9a;>aq?]k?C(?` " =^[>Κ>>DtCX*0Co>??V,,OkӼ5M\

;"`x/kE7ak"b?7+(N<ˊVȋ7.b?Xå?y 7=u?9H?̚؃p|R8?{>>F?rTyh^;=@ |qo =J6]=G<+Q߾Dw$j*oɾ+ҿR=(p/տ{j/_'˰ǽ6"{fc@OTG.?n ?1?`f=[c?*r7?l 0=7e>XU>t>>&$ ๾= (&-ܾT >7m $!S̾긦La?E[h d?5H>2H^3 >>>x 0"ǾIi^2ٸ*) == Tؾ=V3D= %ᮽ] h5N0Uo&=ci\s-]F3?*?Ň?UĎ?g~=jsq>AK?2qinu>@?R ?mIZ[- =gW>*?C3"?$| vM'ӼG H $xRGƗv@< “Z~RŸs=7r@>p?] `>߿X XoQ0>영?: ?v|x{TC>?[h?Gw/{^̾2w>HI=S>e?:?T?*?"KQ K>K?=KE?*>?pډ_'γ>q?$@G*>P?_|k7־Y/?A^?7?rqmؾL>Pz?K?rV"=\}?*6?'{xv+#>C?Zzt? Yb=M<K >b]x =Q_G<־Y0<>_JԗQ;"K=.Ź>^YƬ>}Kyyoș9(E|=:=#P<ɚ -=x)JAs [m?d?f?'4lھ}c>?u6? $HoѾG>?Y^?spm-i>?x?piQ`A?73"(ӮD _"%*˿jp>վK>0}FX>?h)? h%=%>?5m? nվ>ܥ?\?)i%뫼? h?p p_ gE>3?g1 ? l(nY??iIe|Խ>`?]}?t%-ifھ?W?6"?#"Ѿ^>.׾>Z1@$ǿfM\'al!?>G=?>>2ƾu*|lmQ+p=6z>&c>?r׌Jz;?NB?o;dh$/=wk>@@j=>,/@=J>ٽޢ'W!=> N]>_;8f>A>:>f?L?*(G>.$!ċ=S&?.)> gC;`ޟ|Z7`|>>?(%9?o SNbX}9g?$?r;ӽy=]B kQ>O S>7 7>6G1h3ƿD>?ܜ0?'z?Xڐz=1Y?@=H?Em?n)C>exL>羺?hX'z=n?1p?j{PP%?}?P?85==Ȕ>Cnp=6 G\_|>Mѿ?f?uJ?|gjH???CduD?.J?8?Y[R>f>$>_>c;'ŬB >OO<è>L59?N?0*?[DU(>~??QM[b?!;??Rjhf<>ޭ>C?(t<`MՕ>OBalaw>IQ>41S>U*=p?I?p/>(>')?`?C@Aᄏ@>)?uP?㶱K%$N?&l?x?ԋn{=>f,-=2C׾] 1Gm%g D{J<ש>>ơbYBp>?u]?T7o%MM\S>?eʟ??$$F\poNY<>A/>t?Fzjz<>,@>܌?!i=n<Yq??>?j<>Ϳ%)=7?o@$p뾞z@Xc=<;xʛ=( *@><+]=8 +c =ai4{>na=W~>0?(T/#y0;=>Č ~Jk>>|?q$#Q%c6;j=s-? ?BU;a߿I>-U?DI?a_zx}I>Vs?}?p_׀YK彽&Y?dj{V>d x߅LfZ)B&۾곾wϢվ^= I?e?<4rwB<<8?)G>IY_57WK0d?h(?w !:lր?Q:`?@ b(?$w>*:&ۧ=]=>n%?~> N c>& ; p&>i=Aё?bu?ypP(7/=,薾P?DF? A /0]h??tro>@*>~;?|?xps;e??+R%~ڝӉ>&?v!?;O.#!*ca>= ??yWw>](?>?_av߾*m<,^>=rq|y)v|((钿 ԑʝr߾XqA|-?9>Bl?fVUEK>ֿ?S?,m>#? ?;'ǀk߿A_>N>ь??Փ*>8/6 T?b#Z=e`e<> Pv?;>˰=M"ɾ>x>M1=\jnv?z)><:n~sq=>A As>ҫᄁ0d_kֽ׽hA>:qo8h>W>7v?ߵ/kyM<@w=΢??g>7wElQ??&ŀ;'W@>?NV?(K&߉׼ZP>2> |1=>M=,D>PJR -=GD=@L׶=m@>357]]?o[? f{>b7~??(P7>-%Sp?\ >ӳقE7Qx־~> z1HZ[>3@?+ ?@xYH%>RL?OL+?H_п?Qv=+s?5?4Գ-O<>T>]>+s-e>W>Jl>䚙w:*o=uƾ?V>nz\1<Ζ>os~?Nw? Eq<+E%5;qlva.bzWu>*>N`o)ܵ>k Eƾc彽}9>e>E8R3j%=lAp8EeO(>}S>K@P$=>?6"=^>kXѿl@|ڼOpD-f=>Qqf> r7>hk$0=R$sX>q&0f$BC<+?iK{?ISiqz6>D?^?(zO@=gǾZq?JQ>ZS>=xl>E>i5->$*>I=T?%$p>#Rr/#K^<=?(Y9y:PZ-=:8>?9BߚKlV >?oiW!O.Z=L>IE[W(?>`!<>y:q9_wd-̬*>]>8M=YɾE?>?  = kHt?1? Rb.<` <)/4>}=MC^O>_.Ͼ2>b=D$1]Ϋ>4P>~N>e4"=k]T?CR?0qGNɴ>΢>}I?_<(?;?>?`Lr=<0?*>)>`>d>-TH=>̞#>V?KT*>t>`>>K#>3K !EWHY>@X޿LI8">u=r>dC{D|`=I =7 >#[> 9U >.ٿ\I>1.>ԕ_c"awupB>':@>N>UB8?#=fv?)p.?W6e=>r=z?hǻ0?,h?=+*)=|WJ򄾈@}Ǭ!t8v=e0? j?пɟJW> 7b>ʘ>-?9ݒ>ŨԲ=s IPe?׻9> a[FYP?>QLAЅ?;m9>fA.5LhL=*;N*=K쿐=[wOq] Y>4>JZ>;3A[?l `>ž~=>~t=>hICVúwW=N>e+p&?Š >_o[1rM[->)(&u) ᅱ$f?m>=6޾?\l>&Nکqڿh>`?->DBx> #!?X?G-(7D{> L?x^> ?D >9M?M>O?o>y?=E^Pr?4S>5GZ?h!v?>>>+\:?R> yh?cF>@s?4>T!ɰ?Eρ>?Knƾ7 пH?<}[=6>Wyi?}?0>m>j!w]c>Vc?b?R&>c >>?™J?*H0=sRǫc>b7?=ñ?d= x ۺ(>,?5>!(s?!`f[>s?B>N ?7῅>S?>G+K?=p??sm?4Gn$T?-? 辩Mo|l> ʗ>њsHoloX!n;'9?莽隿APozB> 򮿑١96 >@5?>@.aJ91 >?V? T?=?N㴼EqHk '>6?{>A2v=:|s=FL?3fKxͿ@>e=<>v6S-#>¾OH>Z?A>a:K=-o?u+>@ Rͺ,ތ: = ?_ =JտE1>Wy?o>1mn?>vǨ > ?:{`bEd9)c>?2>-xo]j=?w[w߿>nϧ?!O? ;ReA>t?n;>AIǾ{=%z> dR?*F  #>Z>J?N1=s!JӾ߽-Q=G>[辋w >4*?R|J=\ѾWibD\?8)??uW/bA>y??C=h>?^>>?U> pN>5/?y>({=|av΅? z>f EP?u6?p|>Olj}w =>+G4@>,?u92>?Ѿ׾yD>)>z5,Z'V9'Ŭ/>*ʼ>{or:G>x"> >;y>xo >>0>_ ǾnTu>&+=۱>Bl,c>>Ue>lCpLu>uʏu=J>uO%nٿ$?$#>:>ڦѻ>k+?5GMV>n?>hsSPsاH>p>#z1hO>D6>|Ҽ0QA;?7>ۑqCh8>;2?ҍ>hlA&ͯ>uс?| >F̾tTBg0-=e#?a>q0Y"tY`=a=ǎ }Oj# 0=~F>HS;]\<Ě> R>メ^9>GȲ>F>˾?0@?m>.>z`%>{PAn?>\Yu;5Y=?Ho>+wY=>8@Fo;M?i<=Gns?ь;>X> u~(:-? ?h>8"7F90i?`ԙ?()`i_g=6>Ӿ>u+'y==u%?Zdl^Ng>?[ >Yn<?/@=[dAL>8?*H?8x!=,|!Cd=w? i*)0" 5>%V5>ŬG?v >ԑ<eXx=5?/><۾cEJ޳??ZE_>}ܬ:Z?>C>AV@4]ER%?X?'x6k3¿P۾b?v?{,ί;<4?>ՎCFN)!Cq=G?7? SB_ 磾.s>Cɾe.I$1Of>sKp&N"`>rqx cwپ ?v@?ADVL8+iIL>??P>J70A>M׾ J4p" &W=/Jܽp:CfND uG>Fd~ +9G=;mGV?}ٍ>">z[Y%ZG~=0=IӕN?}>;Ud M|a?ڡ>Z-ǿRv?H¿=绔N׾߿pqPO>B?N? >,My[Z<\?<%-\4=E=?6,=vNf>N=X?5=!`俲`&rC]? >Q 庑΁>ק !~?+9<ھ.C0f?'C>V;S4翧0+>=_F$"B|-b@ R?.h>轫?ȍ"̔y>>=q.<տQn??>1>wR<#>]lv>>k>- >rAz>o>v?Q ({=?8>9 .>>%=#v8qrX?h?>;%wO` O~Lk?^=8־v׿:wDԾSo">r>>IM9`%? ?a?0)Tq0E5?o?ޭ?*!掾O?g?s>]Rb?>#>VN 5sM=6>COMQrXK^o>¤=CWؿ:]>B>BK4Y0?t>o*=TPmP?Aŵ>-3<dƕ-Cm?!?g'>/E0 ?C ?k>v9m>> >-jhn[.=Z>^=Q1¿M-\z==aᗿR6LJAV=> Q:5j{:Anf>P7>U((+8߾T?2?>M#?Vq?$>XE? ?c>y%='cԢ@#?}?.>Xf!s>F?Y>Ӧj=^5h~1x?i2??{ >A R&>̹?,d# 1W5抽h??^?] SXl$:-?=A >,pgx1U >DU7jzcW\>CUο jO9>A>5Ҿҳ98>kY!)|6W?/_>ý`I%x>`ټnØ]> ^_>=Cd;G2N>$z>껈>%"׻?5=*=Uɾ펨S`b=s;>4!t&9w/e>s6kg@66?EA==oǀC?> 9?h”nMպqBh>ʆ?@@Q]=?K+o 5eп=6><.? qv[y_!>?}CqxVi-?9:.?g>5Q ?18?{p>іFP?oD?!->zM=Q>zpBľ$K>6 {^j>ֻ>aV 򿾹ۉw>έ?~(ezХ[?K?=hɆAR4??Q1zܼq潋j>P=99 rG?>3BhľEaC>O̊^@g?;+?z=(wc'!B?t[?$VP`{tC?_?Pl> 6F|m8>/-<>V:ͶW>= o+bVM>{>BS&>@NұJ>]9?h^վ;,.^=3??K>u=<>Ƌxv?>wF?{\>>?>>J82kܾX?G%>H Xq>Zr }_>ʑu= :wmew->G$f=>?PԯO[O7?L?42=%'b?9f>ѯnʾFiI?r?G񽝊l(Iv6?f? Ch#X?;:?i=?Qdm澝?u?V?6@=WNf?3>Aռ5[P{> W{|{?!3)?+e?v>JGg`.4V>P?fT ٲ?PH?qP>2#`C?/?J=`= ȐqL?u?[J?* d˾P???VN>?$$?|>/>JZ),nw>>5"=$X =Ӣ??uA?9]p=e?V? ?` 3J|v?J?lñ?":`p6=bdiwɾҿT!2> XK`?p7Y=ʧC?"?g冿>U>-?u#h?V>ѾF@ Θ)>^>>-^&>w3f?jVυ7=OxtC>.0ASU@>T?@?T*= dm>?k?>2)>{i?'F?^>dc^6>??r?(ݨ? >XC?\?[(?Cw>?<뉾Z;k)=*EN?7?>0%Q\G?B ?:^?!1=??Lm?43'\L=?I-?>mՑЈ>|F= ")v>W?f>w޽ͣZ>@R=ཕ>5"ԝ=8>l? D'>tP'=5>X%> w?7|ty >!=݃>!6?3w9>/;;/>h:>]{T;>(=>БкA, >̫?~>l! ب??a ? />-vh>z==u@?Tz}_ۤf>?>_-<-@%9 =Ls@7AJo>A+)^R?mxn>GT>9Y>rh{?pM>kGA>?  ߼0@]=ŕ6*?&`-x't!>N>?>z) PU󜕾d?Pr? p˼(u? ?5\B?F$|1ܼĂ?>`?l'~?C>Pp ֌??=0? >و>@m?> >=/@?yFþctC>h>@H$?>3?E@q&?MY%&s=%?pP?ſ|!-= >>??Zw?+@ײ?Ppʪ?#@ư?ݥmʬ?4?NH?Ph=MYO?T7.T?J X=w?#q*?+q>d=_%?3?N H??Q>?m+=Ήpwt=>;U>ž,۾bw>&T>si?>G> ?̒?*?gj mr>n>b+?a?r?l+U>,=d?'?+?*f= ~$?Se?>L?+~,H1>=w4@#?cҕ?}?U>u2d?3?%>oM|5>pa6@#?oG>mU>??jO?O>p> J?m?&A-*JsT>c>?c,?6l]Jɽ? @B?/|G=?'1E?#096|x= >y5>P= D{rJ=> k+>a}-E>qMq|t=8=>g@ ?f`߷>N?1j@&R]@.;" <??=FS>0=7@?J)|X0w>Zb ?o?8a: ^=/]s?4P>=O_>v?/#@3' @AEx>A& ?@3vq@ lX,>?@>J@:o>Le?@l@ڡ>C?+Z@ ?/zt[=+P?I֡?¿@8?@__2k<=x>]žV꼊 > 5>TU]Us)=;$?Cȿ%??l#k>=*c6VzY$>u>k= ٽEi =w9G>T?a0n{=R0?M ??q. =& ?N>?T+< u?a?;?L,vi >V.>V5=eei> Jk3*?y4H>Xӛ úV0>?2J'?>ꐊO>a>;>>.,=8%#NVܾILč?M@?_axxLe#?y(?xMlY`==B h۔eXʂ>8>A=)`=崽iAV\IPv\>-V>.==V oL9?al?=ъ?L>P?r=F?rz>i8?IR4\-H>7ve?'Te hĽJ=8?,K?Q>0?<282vM侧^?gJ_Ⱦ ?t>DJb?!wi?oT>=˛?2<;"־~aN=#`=>1#|=WЍ`j>JJ>)=uO={>|0 Y=>"a -Kjȴ9Rf?w0^>>>GZ $w.x-w?D0:?T.q`?J? 4u=ge4>>9>v'?ѯ+?$?HV <Ң=17Լ<.v;,,>"_0ܾl=Nm>m2r<x=ף= x>%T?x>s=+񷞾1j9?@!=j½%]g"B!I?$@?0*?,]>,^-,1Fپqv; E>+p&> 7FL.<$?1==!X޾6?ʁP?ý?\?` rX?ѭ}0?̥T/fI>y,$d>:6>?MLWǾizN@|: b/Ȱcվd#؀z { .&ijJ"^pȿKk?P???[! @?4i=㽀?>-?WH ?<?xʢ?C<?5״?|?: ,?"n? W?/c8?e0 ?ZŽAN?yxg&x:1 >Uuh-+m߽^)B =5YJaP3߽ܾ-<|P޽WŽN?c;e`x!X὾@l;?x (?q6=nH+l `e&7x"}ۃIp:ྐ?-ng=YU$?=??B?|?J??P?j??םA?8֏G?=Ї?ةD?M?}M?S{[[ _*d&6J9*>ʾ fM^(@-ID?q Md'A+X?4Ue-`?^_3N?E$XZhp?@??b|F6x>?zX=,+(?:=GV(龬Iw9?S.cr+p.|<1 xk(.V⿦ASp,??A,0W>H?lA?KU?s =K>>X%???Ho?=![>)?M?¨|@*<>Eȗ>>>??VTˠ?rN>4?D?sE<\?w>b?pS<{>g?? >h-F _#ʾ.ľ*Hv.ξf¾N/+k]_1+ъ+P4L8娿lke0h͖~ ;3$v)?cmxp<sTҿѾjw?g| k=I1VҿID ?3l_?P׽9z>h>> (vʽ* >-&>G>Ԅ0Q@*Vm]=ɾg@># G .kXuOQ F1g8*ɾZ簽n"-G谾bߓ]Ül ?o?vhq?U0?/?AS2KHsq><4>W%l%(ؾH8l~0?ml" Ⱦ))l׾ѻy[>;3>5Td>`>Mpu>gE?hv} k=璿+ ?簾IwD?1?F,?Ԝxž >?~?g 3#b_]<{>(H>xOf>?j1>ǂg?cbd>}Tʾ?c|T> ɿ,ʾ>l?9*>Zy?9BH> Y?*?3u=0ā#=dm`HK"=%3uM>` >(tcRz}u>(2)*>20@a=???+?~gED?X]?y?=}'C?@? ?n*az5?8?? 8,sH>G?Zv? u,&BT!q Oʽv紿'eۜ<0^ 2"(dCi7rI@c=g m¾=ΠlC؎C=bj =.#)?kj>lf?G=Pn?\>γ?uAB⽵$>>?nag5L>.s?%??&j#ŋ=IþrZ4j @eWT;>?{?og`N[> mu>̖ j=s;=i_f>i'po=:>]NUC>(v]F?-?*]о >?nn3?`wIΎ?ͣ??/?*#d0=Yf %򝿠Be>"k?0?~AZ[[=>j>8&"/?')>?Hz?Ĩ},0??e4?(RO>ct =k Nd<.!E׽L\Ϟixu1ƽk8hZ-? =?#\K?f7AE=3'>>e|?DA?6-=+0 (k#p?Z-=RWRlEu<7v?>PY?d?L.<>,;?>a?[n/)ÏcB ==b9>e6Yb(=T#=cx=T>Ib>f: > þu, k{?)"1=L7Q ;=yC;>=t<">/MLMR>གྷ͚>E%̿0Y}= J57{ 2 Lv)>aq,T>Yu9^>f7!پ>C @JA>-QZ>T.:BC>[2?'F?8>,0>T>FU?qr?i>77> A> ?e?}9R=O=%C>pHJ8r=0ZqI< 1>m7>)>,l~_?&?E>$5>wN?,շ?Bx'hI0?E?? gOD׽>9<8???o?@;b(t>_[/N#>| Yh w>f-W?DA>𾿙m>n=Öq?4d$?WK0P>h> ??_a$X(8=Т??Vs>k?X?=dvWD?>v;n2m<8 *Ja+wѾ_h{u.0"="H2raþQ2*+3LS=S=?>#=X[>n|J>oa?o뎾@:?Dc>.,_G˜s{Y=hȽ*_?M?areJڿfJ;?V~?#}$S=?h?4RrV\=?|>QZ>K wxGdOHak^U}6 {Ϳ퍽 ?݃3>eWVy!g>^˸?x?7pP۾k=2?u?sWHԾWÓ>7n?ǾYf{g>A?,г>>=>3Sb.#)+8?F?:OQe,1??mj?4=C<7?"O?4?!">spqξo =tjZ¾TcI?Dm?,S;?D#L?>P>=X>? }?$ ?7h>1[>? r%>=W?6%[>q>/>?$t?al${5>u=Tm>9>_p7 ;=Ua?u?e6^܇fZ2?i>O?M+`A>Bkr>!ɴ??UU ="!= 97=P+>rq`<PB!B=Yd>N@06=Z"?-?k`mBݲom>5FN? ? lH?ݽ?oND?MJ=@c1]??Z[>>i?5?f O@^x>lԪW?5P?XK edsg?>;!>K=ţ]?*?F:ҿ|< R=H??f"Hf>ޠ??s<~Ki4j?PGo?"!=N׽ 3`>>W_7jvq! y_$FT{FfY?Y4D(8b ," h?vqlhd=%?<>NlUr<ٮ ?ݾjC}KUzx$iR;:V/侭n#tp5 Pզ3V.+-S>(_>lLy .x>Y; >@>=<>>=K>ӕ u!>6.?/? Tln=F=!?/8?B|YEء=3?>rU~{BZ.ÿ w;Ϳ#9֟Qי=J? I?8弡h0/>X>e'-an=7yOpXz7r>Qe?7?3i4sHza C۾C| A5hܾkC>fQ V;J!=av޿'7>]=#># !>;>*D>CR$~>5>Is># Jwv A9i?t+Մ=t~^CCŽ??+$>=Iy[?x ?c@d=f>:?`j?P"Bˊ;)i=e??prk=0y}>ʶ>~GfsYyChS3G"[۾*=bq` tG`6Zq~j{HF >9AK(=rX_J4+F? ^p'p<ÿjv=X>­?i?q~<>a?e(?x>> ?G?y{Bv%=?{?_yiuɽ;U?*ʊ?}r{r>* j>w>| >>t>yppr>P: _>S>}?`-\>M.`ľof}lS~lu=? ZK>}p:`@>$E>Y>n>Z˿ʾ=?[#T> OO"?4#$>n3mٙV?~3&g>ǟ#^F?}&Pj>a9U8s;|=?s}A*? ";%B=k3=1#== Txt =>^p?6>`^OI?zFR>إ>bpY=-t?> 5?Bɟ>B@tٶO곿.6e9=)?->-NbD=X q>;=Xy4w[=ൾ?6&?۾>q|bt={>'?I?"S'=F2=$B,Aar~=wCdC?֡!a>:^q"K0?(? gu 2?3Q>Eh(վC_ }=8C+>2>3ʿ\ N|n>h>d5&^ \=b>۪7>!B:=F>Jm>Siw>Zu>C68(>]+oD%,w{9=pDk&>:>&g}-{==w>Rs>pO"?>d q ? m>ܨ;9P>>U'ӿ]N=₿ >bRM=VJ>E3n=FJq+$=1侷+E>^?6>z[v?>6jU ??8|Oɼ$H>B>,<⿋EQ>E>>>L'=f,*x='|= >&RW&Y=o>gb>ԋ뽀3+=Ɇw>#7?#1#sm>O?^?f#<=PBj#>>7?#3J2R?2?i>yp? kL>K>#> R:`>;=b>>t?'K|+?'=DŽ>&>V;A1?X>ێ?=?7;\x!?;? ,?^?\@/>a=>f>E"AS={%ph;8k>U.!=D1=z=;Ϳ}Of=ؼ?>>e?,ޠxG>=2>I>E9?Bwo?]>?GW ?=?u=Cv?mH>c?%?"Т?xm>l >'$>I>l~!%>=OO>R">;Z=.8=ȋ=J82?|J?9<=bV>w>Ť=34>+ؾ>l>3T~v8H+>L'&>a>ɿLD>Q'-i>Ц>卛8 rG>]>rG>>6&3oX=(ƒ>^>v08 > 8NC$>Vv!>e˽4+=:~yO>DB>k> d/0'=7:f>w>Ǿ=>F=,?_? ,(?u?=??Va?Sv=N>xp>I?9??蛿>A?>nR?4?7I8:!\>c=u?,g?["Fy?$>I ?,?,`FR>%<ӽ?oT??AO>C==E?ep>>>4;?DA%>. KXK@ ?ұn>ݾaX?D>G>ֽrW?N<>ۭ=ll{?I>9(>3=7ڿE"FrX=ڭ=#ݰ޿uC?n>{|xΟT>zxY>!Ҟ=лڿڐ?oVT>9f8LO tΎ.?w!h>MD1=">K ="ɑ?[!>۾Ӏڿ9⿍A=>Ƌa?a xZ:>g+?X^ 8/Q6+?}|>WO?YFԽU 5?,y&>T*$?(qOڿa_?cI?> ]?e>R??7X*Ϸ?Կ}>j3?F>D?Ŀq&>E\?=틤?4@>!\?(R>R>q v:=v?׶5 RW'me=OQ?l=:P࿗*<^҉="VͿcN=7> fdrܜ>9?'}AϿ_>X56>7 ?d<ҿ%?>N?">JB ߿֐=?X l< ,!œ?=*?-kUr [O?$d > $?[ WͿ7?"?>\]>վex?#;J>A7=G˾޽T~>;˂俒 ^^?O`k=&h83?{>¿?(оd@?&ܥ=.>AG3 rt?wW>ߵ?Lل=M~? `reT?`Eۘ=?2ԾMuI7?.GͿGemq#ݾns?x>yoM ߿a=%?֝>Xs6Fγ<{?K'[D_#5?e߿[Z>? />$ڿLMV?]I=\^='B?S>W'-?Rlv> ?'>9=!=eha>@>ǟ8.:G|H=>տ%>vS>U>cǽ ݿ%F=Ln?>Xʾ3 ?1h|l> ?b>?4MU9r ?JI?羃-Ї =΅4?>mM= l/=B4"?0Ⱦ4ݾsK=?&*þ1⛿8}Nn.=ev?&Q'2ܾ = ?a=4l#? +#:>aGǾϿć] !>"s?bl>r"ͣ]U㽥?s~>ʔ@> ɓ?4As?~=#ϳ?/E=R?)JV]> ?P$=gc>,o>0?-3>ϧO=t?C=>ǫl=q?8,=8?)U?1x>kCR?:>Ȇ{%1pV=?[>m h#qq=I ?v>qEݿ޾Uf> ƃf=Ƃ?3q=PV>8IE?b?9RD=fy=M?w5?,g'<=ߧ>&$Iݱ K:nn?=\w5~>>qۭ=Ǔ>ALؾd?B?"-ʬsz$3O*?[>A-ޭ{<}?QN<> _5"81.={?+3ʽBn0ݺ>п¾fDD+>+?>˿23 Z?ed?e=-?,9:ʾ%FMq; >pH?+O<;6>>?;a>zY? ƿ\h>9?)N=X $O6$=C?p>zmuO0$Sew?K!->q:x!y=Ƃ>ģƾ 9ղkH >.c> D8$>|=Jy? b>]1N>C\&5>>VW)$Ʋ?6~?便(A7M 6?^>NTʝA(4RZQ?ׄ>n$=9u>]?2nv2o>Z?#LT-}[=>:dEÿՍ?ȼ7׽x_n}>)g7k>r>i9@b6޹>GKL_">M]=J?&9@"I0g=ύ:xMם@= T>ʟ N8 ~п,i=`̣N{y NFxO?3*+&m1־jN?$=i<[h)O%gZ?gЖ</0>A8;Cܵ=}F>0$?>a=*C5>5PY{W>"h<ҍ?Xh< o*; Gξj=r?]&>ڶi#?Pn>!+?!?D?M?/V2?p?ؽp.Vd7?ز] &bIcԦ?Q>F$7NPM'> @?Jo?ǽ{V%"[e?Bg>?6&r7Z)f?-=FHQQ$K2> _=HqoKǿ!}>$$>Q1v޿;ܿS<=ÑտOw\I5DX< >FϿ"?ώe>2B_Wҫ,z?4>d= L2 C|l=>*ᾘ5Y03@(wW=@E>lIh"L>Kÿ$>Amn>$?U5L;ws{>ǽy51!= ?_o>9]:*v=u?z#> /KFӀ"leǾDo9^=b33>\}0e=?Hs>>D&Rҗk=>7?kD}=x&=?)==~龲$=J>0+AePt!AH~~? > Tk/g{?e>. uoqyGf@? =~N?̮! c>a>2 6:4p=5>ѿnaNS?=kf/?Q7> zAq>/?.Ͻj6e?yR;Tz=x(vc=]bQ AD=r_xeg4̣7i=#:+Ksg!愾=!?H>6P[>Krſ:^<>&˿9*ڸuO>W~:\v&&\)=d>+ - Q@gbeZ:1;YZ%B[>!<m>'S3Ġ=>7}?( /{<咖n >¿Vm7k0fI=G4c~A=ǭ>NYyfex ;x޾\KFn0 E>>7>t=Tz>!n7h6'>|>(a>vDRQXu(~|>S>?Or`JJ?>X"?-tqynjb>?oŜr8ϿY.?EO~x"I>.dž?K=ܙQ>2>x"='3pQ!#?CR??>5^`uiM ;4e@ssn>mP R}=X?Xdr;/hԹ>} @V >>K/Wh&$atQҿE(q? ? 1=(gb3V(OO8>S.8?%l>J ,R1=>P׾Ich==ؾĢAi3U =O>@5>ukowbR?pf>L=}?[~텽??vީߵU1ņ??>>TFi>YGCg⽲#> !D?>7>ZSr6V?Β??5qK@??S?jky)⥁M2?@?R)ߘX¾??>ދKd˾ǹt >_:7 ?OphsX+GAypea*_xy<ٜ>?-??O!IO@Ϻ˾Y?=}?G>[7oX*'?A)?5a>NmHqǾ}p~i:5/!>[:4|N>dc}gֿ;!v>`?0Q>$y7o=w>R. r`>6u^5vGUh= c>Zyw!׉=?SH=gk>v?N Dkj ?[Sr>njc/؄:i,M?l$?Po V?}?0S0MV?G>ھ5<‚>Һ=Df @8ƾ+?]Q?8?&8=4%??>6Ii4va5?|?z>.ׄ??dt!??T!==j?w?B}?v> "־K8?L? z? ƅ@=\h=!Hy{+;Bh?'g?|(>4.8H>??>c06>#? =_Q(%=Mw?>>c>9I|%o=s)?n>s>~,8=?P>P>L5[p=j? >;> pA=TO? ?>?!l@ rl?Ü?H|?`"5xR?b 5?>?]_V?b5?,?z|#ս>[W?E?L<p1?R^??1l/閾w?6.?5?K4D}?(?(? @վ9C[? 0??bZ5'8. =f?#>=&F&`cm=i>y=D%l칻>X`>8=C9q"0@F>? L>d8I ?>9H>T=hJ >;>S ~B y?o@ m?p9?=?W?dDP"h?t? |?%žyt?r>4=i' O]?۾nT>W;>oi?2y=׀Xw%?2@?A@HZ-?Te@.?I0:f?G?qJ=h#B~ ?? 3-G50=(???ķ/:P=A?M?Ȱ?;(.ͽO?z?x?K-7!q?>??DO='?w??g68Cm>X?gD΁????@kM|=?v?˙?P?q,V=s=J%SUL?#nd>"#??B>M|=Hk?3@?wn>rN?_:@ @}?a,>k1?S@ ?| XG>4??R;?d,9Nr>l3>Ëi?[?:G<L>C?!L?J?gw*RB>V?9+^?u?KAUa=֕=%?>{[`R{>}ba?>R?CU> G?vd??I3O_> d??ك0?PHR<< $?Ex?zp?@x? ?}'?.} p, ?9?c>eE?p:=iY`-;Sh >|!>`?@&?<=ل??'*Z_C?]S??xQPBK|> ?B?͵B?4V U]>,S?ř=?π?a`p=?.??XR2WT9=U6?^??b_Zl>N??4@wc?Ԯ?}V>~? v>҉>ԑ@ o?hQjqXٌa??$Xg$>7|F?w?*һoי<,?@?(, *Mř?r? $?f05X2ԣ>??h?ڲJ?QEv'??h?uh ^^=c?A?V?ޜ `Up@=Ϛ?w??vY^X%&?fM? >n=<ooo.>ޚ,?Kf?ixTe >1r>,х@{?l@gp>?ˣ?_@lH^9Q??Y>sGԾp?q?Plw/3>9I@1b?@M[8)?(??R[6S?*?Ǭ?j@5'/<$?r??rl?q2ѻ?x3Bdf>0 ??MN]cCB>41?u?Q$\Sjo>GK@%?o> h#$@? p"<=H?@,@!PI=?K?>?ꄝ(lk;z>,(??ZB#e Z=n???N?T~?n(?|a?ݥ_=@?@j> >1@?0w>v?(@1@ЀoC=?T@ac?mz=th?F??|(YX<0Q?^)?O0;>ɜ|=}[d=mP>Y`>` v?>>>&c>< aw>UO??uxN>f;>.">? ?eRFlX=`K?6??H+=\eǾ@s?#T:J]?yl?Gtu %_J?0?,@ {?T?*@ b޽AL n4vbx??:o?Y\:5ҽM5?Z?›J@ |+);ύq?,˾?H'co4>KB>>e>F dr>i>x>1=U޿˪?>r>ݐ>D>SHo<= S/mJ`NS(toW?ʑ*;??sr>>}> W>B ?JL> gmƾ?M>νY>Ał>!Ӫ=ST;>-8>`>SM5Ir w>N>>RBJ>o>>Ҟ>&T=]=*̿?? 7@4>>8؀=kXk{TG`YM._> X=.>9&?7R>=)ȗ= ~IFF#%<΃ +g=wC2J?N>x>Kf>85=>r$&q>(ZO0E>:8CM=s>K׍Pš=ѼKG;|+gN=M=<9L=d^Wq^>U>E>D>3>ƽ1!྄>¼>0b>ռ#?ª~,>=弍>&UB ?\?ϰ?I6?zV? ň?k ?o +P?kPmayr˴b[L#sU_ji{?/#a>﷽7m'$?7S$??Vɥ?L#34?0;qW2OałB%1w?0:>fǽe%V>=^ XM^36 ^ [m%A59;ս8><\>L>O@BHg1>=|>t|??>Á?c9 ?8_h>(g>ρ^Q?kB^ ?ʼ =Y1ƽj?9+y=淪3'n? cO?i?\8?P8<:Ѿ=G>vv!?,X?c2?6 8?P?M 2)IϾ~RAK_=ŝu )¾Ko-\jא<ex"mZ<姏S9>V?==r徾z(K?k/?g ??Q`?tIz?n Jy> y?A#=1 HfQ{g?=_Wtt??`Fܳ? gPd>?隿 V?kB=Պ>$q?e?!?T~с`Q=\?2>n?>f> ?E?[?o"01NLD4l93BNos'0/sf>)E?P3>?w~b=Y4>;r?tAj=旯?GM?qEs?c [>>?P,,?>E?:`cd=d><2>8{?gq`=4L?D>W6?6-b sD;V>>u8>W{ d;>P>-(>B1:C+t'T0H̾'= ,=?yrl=oQdZ )`?nw`Jx)?.;7??1A/ᒾ酿 =+vq];\(/"e( UP2+ھ=\tl%)KAe`54 G~K=_vp6bZn^c=i??aP?+ ?USc?W7|pܽ4-Q4dp")wb v//@>vɾ̿s~Ծ$ hbؙ>c>AfV2>z5 Ç>vB_? ?[?bfT&t?QW?-05) 1>K& >l57upK>t%ý>-v|b3 G>؈;"?n(N Z->=AS??|x>z[>|1>??/<|N>=l^?>`5?z1?T>P>ԍ?#t?!??|`?;?Z? zF@ V?'K?E? ?h# =Kz?JT3?,4(Gд> ^[>L2:U '>n9:>?t?s > )|= >b?tq?>*?eE ˽`=l<\BjYi'|>}м)?W?J[?ܸybe?F?0?.ˈ>H>oTlP=r >W }=>S3;5?q:Xf?kE?, ?N?$׽v?3?5?&a=>*?AN?BȾc >?A\?h;0Hm=ޟ%M(AGߟ7< n)P$rpꞿ48޼EVH=":? ~>d&?%p?Z?>?#k=3QFR">l?J}? դ9?c>k?DFhHȕ>4?Rr?@~<[+V?!?m?ݮOh8|&??rG?Ը({ZW?L?|*7L?F?\?t$pKҽri>>?<1b5 >ʛ>R?8kw?w?g?!>,='>Xy(r?i2??|Cgp뾛k <]$b_:.M]J,=c >$mۿSei¿޿J>lL>r>tSAmo<ӕ>ɧ>>Y:p|;O>? N#K=,u>?(KO?V}.{%?Vg?j?m";Ksd?*?UP?DH}k>o+> ?]}ٺMx9=P+0)ghE=U$7ӑ'֣]S>u߿lc2X`5Βp.>>#0c/2=s>EeԮ?$h?:+9?s)_vtS<E1]\yL^>}!yAxp?K>>A>HtC+8?)@ @>Ϝ ?@;?Ss::I>14a?0?-,qýzF>Ab>qٲ>ZpG{ >>q?u#D;?,??\e;^D=>`>LM(/>>C>d{[sviHW>ՃbuQλC=>p&=uBF@J3gKm>`jg_41'[lX1>P8YKr: fT~?*^??'A>6>u92>`x 1+{)=}Kpj;6ㅥD1+u}˼9"U>ҽu4dE=9# QP^>{,C>P>W>h [>=;>?$!$ >,?K?:L-=Y> >!; ~JBF>侙p.=݇/?r@4>u9z)i#>V=(V&>>3>\ʿ>*V?L?rK㓽?P}? *4-A;> 5e?#?QXEȾJ _Ztq=M#Nw_ rdTzg?yB?*q�׾" D۾Tw6/Z 3U.c\[%DWlgt^=τ&w&A>^%)pcxy>~RY>?>h.Ϳ 2_>F yl=)=*0\(c$c!8@N/ɐJܾ4"F"$=?Lb)%?9RL>p>I?388~?h!?jU>tǰ?{?C??k??S?㰊?6^$?ڃ??l%^L= >2ͨݘ C<[}>&>a?f#)X?&= >>ݘ)?> ??M@5p>">??`o?&l?D =7>~p>-EM]~;Znv?{ ?"nf> ?9C?PiUf>4?]?T#?I"y>=)T">:Cd>=܃?c?=H6:yҿG;?]>#;>RN?Zv?3=>=}')>>U>?-ǽk׾D$>ٻk>R@>b??I| b >? ?+y2>Yư?2? ҾǾ0>;>R`}r:0⏿&['Q-&=)◾|_(p2=cp?6X>`N3I6-dW@*j n[:|\Z>>U =[k+Ť?(:>TÏ5=]v?M#O>v]=n &[!f qNtU>;"'Sw>&>b5/tO=VҪBZ Y>\=O ݾi>" u漿$>F5}[Sz >h=QP}>RY\?4w?$s$J8>8??/N Xp^4+>`_=SHo$ϒ>.TPm=`od18>>|.j>^?HȬ>>6Q >U;y>">>r؆<8>> DDu8:Jrț5n^<0} Cf TΧvY>LcpQR^Y=N>Xwxٿ;;|#?bӷ?QS>$):@9>J;kWFH*>q?= =V5M#>=N+|gr۞>w=݋>)=Q? I?c>&8%$?(tG(K2:4>FQRJ8.&x?? Pa}3?;͚?%==u=Ah4?&]> J>m5t> 9zP=I<;?6W$d4*jӿ#IQ7NR̽i;Eё0AX2>q>cXM>||a?9˼>؟{>Hϒ?MC#6H?[b ?ZJe=M?D>+9>=->eFN!UZlk<2D?R?LpwAF+k?H?= YdR=7r+) R|{ǰn%G龅@F?n"ծ?txppK<9C?n.(>ۇ~U~ܼ CB>._/U=>=㹿F2? ֝r%2;I x>`ľ (=ߔ>-][o=I,R1H?@ 2>T0b Y *4 q>,>L8OX>})>D>q/%=E81w>S !>M>56/Aj>`"ǀL>2 K?;>|> b>>>[>\>h\>D ~>1>\:>Yov>!d|R>>bc?ArG=˿Ah@t$wO:@7>@>{Fx=}wS4ƿ?7,:>/\ g˿X?N1)>LQ޾v}5 &?9$?ce˽=?#,4?8n8WT>L>.l0t‡=Z6q2>>op~=㾧Y>c>\yɗ=_>؞>a^w׿[>>HQ~Z>Hm/$ȽeA >1@>?8? VOaOD>&=CH>> ݿTc>LJ?$?y[?F&1>`!ѾT>NJ8>l ?ھ< '=uCi>\>6??^'=>x4>5*=1&>.$y=Pj!>&|=3]=aCOL>zW>?2?1}JA>>l?,?3-={x>٤8?l?"I?w/?6ZG©7&>? rz;t>h95~^s(gr >Z>B"b =;$dw8>!>翑}>g?<?a?g3+__s。Diw>iN]=*==>ģ>3>ם >/1>:9/!>??U?X-L>-@%>-?x?x&K=28}>;1\zq*>Dr>y?Kb?zX=NFJ[>>Fc.>X>ɖS?/w?%B)=h> f>܆>QD`=d>d>va?td? s.=‘>\?Vr"?g(1Zg<¿PI\)`FpXLtyzNSu= G3j?H\%xu>GW<>|>Ĝ? rl>֡<M>{3>r!6f?ߠ?þp'=$%d> ==WC67T=4>O>Ñt9\%=(2yy=`=4z9zt=';P>Q>J1X=c> :?v?$Ҡr"y>vϿ?L~7Bj>>iG{+)H=v>/9P`ȿL;>W]W-Vm>y>m@=2>b槾`Ĝ>9>`ÿ >>wp>j?..?3u}D>.<`>>'ݿ"G4? 'a>d0>Gs>iZr>)5hcоc?]ZS>8%->ʠ> QѢ>6+>Buh>y?aFT`c>q>>O{G[<ּ!.>=_ľ @B=?Js=8;~l3fߢ@CF0>{^P=X*=߄Eu6@k>4>> ?pd>s6'(@?=Pb>IÿN{\%?ofL?W6 $64@>DqS>X%3ƾFte?Yy:d>]#ʾؼM<=+D? Qo=drN?s?{fA_|>C, }?It激ZĿ;-"=*=R]>J˾G=> >d.I>Ma6>'m>tT@MU,úptL>Dv0A?Y#p>_9>" >S?<]d>`p=][>>̭6?S&^>i=>l>/^?;W>-S<>=/?&qS>b&CF=c=W2[uu=J+ξUi?/ :>%F⾼͋?ag>Ǿ~.w?b =>I:4D&h?5; 1>#OM7.?>c־ݾF2?j=I1` !?ҧS>SJE˾H?")>x>}8>ȸ3/?a1>HǾׯ꾠w"?a>uGk?ڡT>JɾZ憽ߓ??D[=hL辿߾=;? h=?aˏ?F?= 5.î ?BG>K.Z]V. ,?s>}lA/v?C>'~3'k ?ap>=o >'i=G?]Pv>mҾՙ%+ԽƜg? LQ=޿+?{=3LR"+?E>J?O U?>I-=T?-h@+ =Lxy?<>l8a?uC>*>m4>/#>7??(P>T𕾼<}Y0b?> 3t!ALf#?%%>t8Lx?] >>gxW>D>u?L>Go>憃? >X?]_h >'>Ky>/w>m&?֝0n>B;"پ ?XDQ=8^Pnp?ł/#>zCͦⰧ?jb5%h>gU,i>bAs>]P8@$PM>(ZHQ|NBcE>o=}PgϿ?L^?5Ϋ>\));!??-/>+IT<?.%+->[ڔSG YP?ثl'>3WWῗK0?<> i?pw6 V?˟ >!x9?a$>RZQҿÆ? bg>XڿPs?ף¿밫?,7p&@꿱.?Ҋ=]2>ɿؗ1?ˣv>,Ⴞ=UiX?俢@>etɿ7!?q<}>%ٿ u}>4|>nQNmf?(?}>8qH?zc >п]8P0z?b>v(T}?$>-i$[ݦ߿П?¿>Ic%p0b??-ÿ=)N"pc=?h~oa>{HMۙNql?@=8nzy?OaF =^ڿ⨿ ?/F>J8i?p߿h>/:ƿ?IqL>@V,aY6?_*=A% 鿴n^@~>G>-s[O߿8?Uؙ>mqsul;??ÿ>]`(忝? >?;Mr13?kP=#^tɿզ@߿>7Ծ8_J翊@󲿬>8oH>GX*?4>^43'kI0@?>g(/@Ԫ?6߿v>Gii ?(c>JĿwu?S~>21@7IϿf?? |4>Vb5ƾ0#?œ>0b s#ȿ? >F>y=MM8ڲ?c:7>;2H?>L޿(">;5%=HКqo>,>>.>;r?^Zt? Ԅ>=bmjտF+=%x<;& >\h? TL{fH?;A>3(?>nLh?V>h?94KQ?k}m>} ?>6nh?>u?N>T[?O>*?>X1'q?i>?v >]n]?pC4>H?Xz1@dMGпa?k>HA B =%@?5hstLa=?h5Y=;c?YR=@>?o͊<" ?>'?vW?c>?b#!?܃!>\r?zT.Oo?dYC? =o]?ZC~"{-?#>=q<>*~J'3`;0?zZ>?xySPw)<BB?>>~R?O=z?;N?\9'ZԾN?r>t.?tƒ=%?Qᏽ' \YH?u>Fjv=ɿnX]?? \M <4?a\o>Ƚu%{_fh?> |{o}2?>{xPV־h$O?>@l?ކ>?!>7,=f<"W?$On&*#?X{=_0> w'?/>jf?0! !?޿.>/?5?F}?p]?,a&i/8g?~>&lI~ ?n>v*Y+gFk?>Wg,+AW?QѢ=j̒!pX?%7U4uXqa?4yսad>&'/=^?_E|=dY?:=ߤ?ҕF#,>xq?=Ƶ?N)=x` lid$o?":ۆnDz1qUs뾐F>?!>p@?<轈>Ih?KlLKʿMϿy==k2> O)].ǹRÇ?Y=\? t=>` ;T'{=Xk?1^>1U+~N¬0?Ns>[ݿ qީI?>זm;*W ;ֽxh?O*=; @P/AB{yV]!?h> =c{пB_=(??=XĽ>-J=R?Ho>(觿 xp?|e?+Fr#?~>.sKP$?8l~i'b0?#:&C7ʼx>j^aJ1C>ߺt>>ul/>w=> JzG?FC>p{?7=r뾻?`>k"? f  󿯐?_?LztGV~3>T@:?,Jǿ>^1?3@=㾶4?DZ=>_q,??:>b,>jT$??I>Yp?x텝]*]??M۾}"68Bt?2>־*sw`l?8=:( oi1?8C=]S涞-=qi/q >&ĿVX~XXdA QK=%Ŀ`}q>9uP> ?>]t> >e6?W{J>==u`?[>#>>T$?ſn>B?<%?9?W:AN>g>>>uͿBX?V?>ˣDCYybA'R=?#Яiw&?qRD>NB? ?#O 3HCnMKj?K>P6ER#!?8T=\yFN%-a,>ቾj긿0/gJ">6`ۃd[?ȿ>?Z,?Z;e=oP"4jb>ێmZ)+uO y̾ ?l(K@߾O>GEƿ$w>0h/=>?g>ј<$͜=P?S>U0=#?b1>6^f>suѿ=XOL>xO`[}*T>5ё= >>)0$,U(c@Kh?}>,o^ZK"`8>AG?aZ2 `|>~G:P++ u!@3?:]=r(>h},>s?ù?"m >i?tm?*u%ՙ9e]-e#?;64켬3yOx?}f>>p{u]+x?<>sP>$:`ѯJF>M>Bk/>K0<h>1Lf>I? E@\:dX>G4C1 ?>>l=B¸cO?wս>>rɿC5=%>!5>7щ?ք{>Q>)h׾?>)?}\N<>oL>]d?lz/F V<'TmZ?F>ѿ`=G.;> T>Ӊ:dfMO ڡ>UοYt?aEh>¿a4g=A)>Xc<&cܠ>>5п3C1Vb?0=~P1>ା96?WG>̇;`I,(B> ᇿwS?]ެ>>9쾍89q?;?>>L!޾ NE@>Wi?".>3˜? }7>9`?$J0>G.'F~ 0= >Qkο'Ja_(0տOFcu?N>Ie,?K>y>W'twv?=FJ8dJ'?j}>=Xx1>k?V𮾬I,Sg?&?9 >X`<,rE18>?J;y/?:ͽk/sG-2?m=0=<MϾݝwJ^1Ͽ?&G?s=t8L->l?о@lV?r?<DzF>X>ܽ<`_ށ,<ظ(o-VrG=2>zy5]{c L8o=O>~z1zII=>)нں?,#> >B=v>ټ +=>GMhӿdpc?H2#?O >3gL6"?V>ΒteaA?Ǜ?B>Z0SB?B? ,[?j>%=Ɏ>ti.#f8o;3r>S? ljH8lS?T>+=˜t>H? =t>kd=f>ac< ᄊLu?k#?1;CJSH?2?[u/ 5 TKpO]?:>/Ok q>I+4;q9ܞ#0_ LCp=IZ}$#k.mo m /Ow~ʝ `^⹾*Ϋ>л?6qiؙPi%̾*?=1#?[>"lkB?` ?M>`mc#ݺzԾT?\?.=?O3v н><">~u\ȗZ"9?|?.>gM?st/tڿZ'dgT [(9~F`M~eY!A@-i }m]> ^.7;=|>s\. }kyF1? ?=q׸IzT>]?s&l!Y_z?oH?Ec>RmpYnx?5?p*kѭ9)ll(1re}5L$\W8d-IoJ^2d|]^$m~ˁsOJ^}t<4>A #햿jj>;[=/7 j7??T?7ihr޾?e?+ $3k?(Z>t[huT$+R p 8#o,~_l8"k_2^b PIҿ^h+] 1!8羍}g@ 5=ԙJ0 s%vżTQ>z!+2pAXX>d?? MG)E>M? aԾ pv?^?3Q=3 Yw/MT?m?#<;@o@pC>.=e|9'KD>r@_4:;8I> Z37[E ὙT>Dx?IӾn'Zӿ?1׾H Bqn?z9?,>Onƾ??}=>C$sqf?`?Qsu>Q!ob> > >(,%D|W?i@?Hp?=X)@GFI?!>>t!-@->mY>= @D'?QA?*9? x.' d>9uP`5Ta!<&>?,>߽1E ~=7?M?O]?,9m>=t|p6.R>,M/w1'p^?6(>I׾6}Q<?!G>Ϣ?OH$-OU@??O?%]=?>R?sT=ʡ>:=1M>XC?f>G=d qܼ9>k?w>8sQ=j??G?8yý>#l?1H>-\d"[Ǿ???@v+>D y 뒿*,MD>MȾ1 ?/!(=Eg羿g7S?J?F=u>7? D>C)<>+o߇ԋ>s>uŵ>{i> >5L? }?><%> ,=>?>hY2eni??㋬?U-DD E=h?'.>>`$N =-A>p>LpA8e=r&>>&g$>A?)MD>n>v>-sC?{|p><3>oK>ʾ,na,> "?=*?ț?3 *^>w?> Ti=崼?a?&?5];??@?j`oA>^>?ދ ?L>@;ʆ>??ToKٔan?1?gM?Z?Mav?R?ò5?*?ڇ]N ^>k?d4?a?]Pc->?]O?*?Pjtd$;?R_ ??3?'YlfZ> k?i?p?$B)m!=I=6HKZ?'XC=%οZwj>j>QR־Sr?'-?>1҂>6=f;q\>#9)ҾZ|??q.?C$*3,=ƅ?Oj??.&v,/$H/?G$??ş?CGd;=ut?l?p?KX=̌P?x?2{?PQZe=??i)t?P??OIi&U5<\%??P@?#`gƒ>H?MU? ?jeAk >V?ZG?~k?лZiM?-b?!?Wאh߽??W>·ȼV{? ?,Z'a @:!?di,T7>6?E?^FJmke>???Ɯgm nV>7n???|szpC>m\????MrR>7?@֪?!Qt'>R??eqBW=RW?v@?c`I`>,P?R@?MO?A >6{?׶@(?`azL׾C>\?[?f'zr^=?6~?txJp>(C?S?B?vu>{?5? ?=vPvҐ>t|t??qtO?]adz)??ӷ>~?Jqk=&нӕ=+4>Gñ>b?t@&?q&?"O>:*NZ??|d@w:># ?l] ?HA?t){a>O??%?0thx|>E?A??[p= ?"? \>*3ؘ>1=0{?>? .AH=Ɔ???>r8> ;>'n>UszZgGw< C??p?(@r>=]7~?L?2/?vx]> ??l?Y$y > #?Ü? ?jvzI>G??`?u?=s>??%>?&l?Tw=¿"P;XoOb_c1su=?>e@F0j'?j1??#``;u*?FH?Hw?ʒ|4{=?m?$@Ҿ?R?F7/=? ?ު?H}+=.??Z?ĿB?k0;;zua><)??8x#MMϖ?.?f?ItmU׺>=?c&?׺^#iy3?;3?u?elH)8a?k?I?wfp'hZ? ?U?Fx ;??%)@ =}g4?-?d@I8*(<^?ܱ?R@qNy=6?i g/>M?L4 _?[C?!tj=}= h,4??)=S4@|?, <ưS @.{?GjY8jb?ϗ?Ct( Ag ?i?uLTl?d?2ay?P=D?o?߃rO8? ?o,'?j-?ږhd`>T?b?Үmh4c?k?w_b= Jȗ?8@ }}%,3@?>-@.-{jp; Y?Zn??ȕl0<ʫ?%>}?RPqRX*\=][%?B?LRP; ?A5?\C"=!tϘtd3pYڼ6ڽ1pPɣ. { <"p.ܾ\O\ >տR(K"Wa?fU_?Y4*q־ >>A>2 Z0k8 2ͫ76Yp;GA>3>>솭%?%E6?=4?WH ?ګf $?›Z$?qS]?4LJ)(D(1?ؽw\&=-Ց{`De0H='w/ᠾFSk;:PudYHr4ZJk*>! W?R*2h 5H! ᾒO%W=XL'&^/M{w< 2&=w%p?O((=$wyV>N"Xpe>v;u>y _\h?ջb!`|?UTT0?'>H?["g?-+` =(I˾o dN D= =镫(,??3@q=;)|?^Fp-7Ym C1]>>ŵ=> JO=2>c>>fzk5a׽6L>S}>$>":/>(>>k]8b<n۽DR=l:==h,=, `lufy!=:.?!,f?SL/'I>lQ=o>Ԧ=2 =͌* ,4;>+J\X=s\>2gKpy=6?>PO=ti>܌E=;Q3:"=vgB ߽&n==P F>OB5>͖>>}?œ?4 ? T?SH(??h`??ɇr!Ot?`5tR"{N=:/=k>?=6>mo>T>y>p?q??Kq?MϵH?\&?T'8?(N'?b ?F8?B-'?O"3 >; 8>pe^b=G=e>HGuB>>`>P$?9?>n?a'Tmہ.a?_u?R(?=C?|?.u=`\ˎF#K:[>(5f">$\6 G>S={>GhXd!>&Q=ί>8,Z꯽N\O½~<&~=>׶>t>ի5$ FA%jz=%/ pI>%C0(g{65 a?ml/?@?#R ?lnnEp=8<&;i~@ ez=2ʽ·M>?#o=Կ6ʿ4  ?!?b% *?SD81?#)M>!0?؈?8??(r(?|?i"R?Z_B(gp?NDc)=x?E0?9Lz>]T >PrK3?@?A?y? 9?F;>?[ka=S$}b?Yp?QG=>f?g˾?dԠ׳>. ?k? ?,RꥏՅ= ?&}F>.KE?w+$?d?wI?<?ƪ>lf?5R; ( ?'Ac&?K?c?L0̘"@?? ,?eu??#L<7?Kdr\?x$d?9>؄?ZQL@,o<.?o0辵 ?%s 彏? 0"?7TQK=]=.+x%V:dJ m'!ռ;=NeAap3˾ q J$ȽB<#2wDǩHT9)kA->gEBxF]6kyϢ> (>:@9(ھq=eu:;=1lHXy`x*]lH?;>=`o8?o D=5T2#m9]>\)?>߯?6r3z>ڈ? >օU?եG1bfqi?^d~վ#?V~?x?ʽsq?iY5x|3;T=!&> E/]׽}ؿr;;#C}?,ס/v+=J*v(2t38kZ{ =N=濚=姏>e> k?GSOBp=Q>0> W?S4elO>;9i>dI?'L=}_ɿ 0˾x?;=4!+,<-5?d7?>?ʎ<AA]>>0M?f g>9X>-?|}+45>>z1bQvd>i ڡ>df=I?>I8?Ihd=>P>W7?g_忿L=>+>W?yY:~=?f?R?cȑ,?[??I3;ւ?@?3WO?+A}o??:?h+nԿ"C><ޘ>,t =YR>x>Vz-:ƒ`%eb?E/<>͕W7Ϳ9'@>Yi?2]? ?&#@>`? $?xB?J=e>j>|?l̼M,A:}>>ݼf?k 2n $>?u? P*?//?*?;)5> ?~s?q Y]lv=R>?Ei+%9] ? $>ni?E&(`|?\Z?$)?e)\例L>b7>M7m??K?@Z=>N>ApK@p?ڈ??Նp >Q?v?0'Pr>e???H>5ղ=%_k~K4%?'m;x)=b&{d6E~M>aI??\#_9=_ >>Q2>oZ&P?!?, t_ܽ2>o ?H?ht'U>~>?_ :~m>.Cb>J"{󿄔LEWJu!u<v>H>XnZ纪<5H>??{RHZ Y?@>?(ln>4(&/إ)Ol켝8<5=Z*N1G=2}?2?M@0@=a?dv? ?d?&?=0?} :ɞ===>V>~.xw*> >`?!"X =%OB>jdTϿ'-GFT>0׽if?7<?E± };^> ]t>?T-,W F3??15?i+9K>U? ?J-\[Ձ>R> ?Ͼ,?c?}Q?1m7XKb>%ᾀWJ0Y>F.;Gk>R>6y>8]t+=>*.?{.{>6.R=>#2舿>??DonGؿ*zm(Ӭ/㾄哺20jNr04(Կ nj#!{X ϿN.x-sXMݾuA5;=?p97?P*߇%>(V?tO?>?*?/yٽj>g?0?_ ̾\=?K?Go J=MK?we?/o]̡Y <4"?f@:1>쾳JW =1׾Er>ֿ9/)"!.>Y? ?%!pId A`?b?0ՠ ν.=>~ܼ0&RLŇd\}=~Up1Ծ٨H?ze5>^a T&?=>?4Ue]Z?+>y5?i>=%{8xȾp>=+*4z1R>*> ==ÿ4Q"?#/Cl> >>Y%>?mx)Z>IH??/?<2`>[Fk>3Q>t`?6>>NOil?l]?|?H$=¾>-? L?/$K=dE?#,b?3>=7naD?&?D D=?b ?in?@;yL> t?i??s˿5 =8 8'R=Q=쳢@ `(=?tq?w])=!IǿY!>I>2쿈 '9=N3mR~\C=ѽ-?El?G54@w;qM?\>?^jYthЋ?X>?#>5>@j?A?B-f`_)K$s?T?6Tq澾J?1?eZ>AK0?->֡>A7P׆n6;=?6?xVr9u>?77?Uv7n?*?O?>\9^1;6)F>qx܇Ht>UQ i~_;͎?R+$> پ>|??-?d?#=1l=\>><)ދvO=}Ⱦx> >YgUgM>?=;\>ܨ~>9*>o< M2?'e?& :Q䎊Ы.> >.>0Z?+0/=L>Q8& i >JJ>/#?ԙ?b6].>JQ e?DC=>>A?q->"%Mb?.M?0?.>==?e?inY?o=}K?>?Jy"U ~%b>>kS'큮>>j3Bf4?RI?\%>#70e=>^>RTk7 >)>v?Fw7*9Kb? ä?,?u53?"(>npo> >s!?`&]>h8=#A>*C>¿>Ͽ5-r=i1??ox2W4r9>t>*l'>jydFJ>>?*OA}p>(E>?73;νgE<;=>۬ >K,=;>>7?1pdg:t(=“>5uŽܨ~>8> =BHv==͚⶿85>t:???GH=D15>z>B?wW?yBɟ\>a>5Lœ85:_&ܿ1J_L|D[ȿ!9C:s[a@@%`*DmpwQRT,m:C#hbҾn )=GǀȾXھZ6tCEȾW̾TG₿]N.Ud:>?$?LQ?jy"j=羕H??eR?z=0#D==SmJgܾޟ>cZ>ڑڿTC;ӿ8><%>uBс齥*v;?}$?`e_z>? >;1 0@$+>>=?,q3ᆭ}>.>(X>^ rE(\8s7u2񴻾ӁR [8)VU=V,ZY_D;OsAܨľN^hpΫNe=/#DӾiD/f>h;V eo=,>˽ 6M?8 ?'$f:Lx?w?^*O&1R=>F??0C9&T .PK^gQ >@d>+J>TBX0oT#tÿ0r^B5g{׮=\I` _"[[J>M 6>>ǀV<>W>?i22>eԽz"?H?M4?K<0,s=<2= ?`p?f?`;%v='[K0? C?$-FRYͽ ?f p?TF`x ^7Q6|>=G?(:?ExemIL:Ӧ?/>Ϳ1n:ް!۾U¿ 2Z=5?"?u =Z<?c?\U2 ln&?* ?|? >V=R1!?ƾ>ؙ|=˩IuO4>7W?-8?#6?q:@>Ծ?)1#?6l?ASH6=B? ??4=%W>s' .>?2@?u>3/|n2>>>PƿN <'$>N>'J>&=ŰH>[>͚ؾB!=I?m?J#ZMB><=ftI4#̾g9U6!?7ѻ-=>>a?>G*7 ==A?#?)K>q?)?ĨIE|7d~$<y:n]e _꽺s.=һ]/>r?H?Nw:OU >r=,YY>}|>*^?)?YC_!`^ ΁=,)=*A>Ǿ;_ hn?3= ?'p?4*\;N?-?5&>R>2>Ӟ ڽ&V?T?u q&?.%B?X?đ*߿|=?x*?mxK7>Z,ҏ0'́p>l7?1窟2I<>p^a>�D>>d+YjKHԾ͏P Ť<پu2%}1=Wu2>dh?~n?>^0f=;?:?#+Ǘ7>??4@JN3zQ?*r? 6 FWȶ??J?)ǬOBw":=x?v?a;[㼺E>@S?\l?Պ=K8>cu>F ;fl+>>P@=B>?6?8eY>{0?+O?)}(j?^Y=.pj5/t +)<ǿb>>u%ZӀѿL=I>2><Cm^>DY!q tiDFxFi̾ Oʽnjbe, =WtM?/]пDv)x%s"[ŗ=m,OA)ҽg^N-^=!h:O:[Vkw>C]=*j?`%?K ~x<P#T;S=dE< =@ wo+`VTP"G@`Ž$J5{ ԂGxnL<=˾g쾪=5 5=ܜDzѫ/\UqHϾeTa>+|> (;Cg >c>e7"=Y?6>ۼq=b=:/?X?P61f==쾫m=E=w:<6aͿE?tr~)>)1q4/s==%>ǟy? ?">);0>J>A?Z?m>uEgU>3 0> >[@1=?KƗ=۔>)/?GN=%>/4>p^_5;>9S*M/`>5⛽sI1//6> RʾȒG:Uһ>t3>nvc>2!:+>?R?!)$1a=,$w>yF?p;YIjU=BPJ>Q>ҿ0@YTB>8>?+]>.ùԀc< G=wѹ0>N|J>s;]>MܽB->G>g"2M>dz>???uO=^xJYe/>B_=[e73>wX>dEhyk=ʔyL7ai"TX>j`sZ=\6ޘ>̒>}-ZZ>t? d?> n`&[>?3]?G-*=G5~?D?YG?4,R>N?>?>v>:T=;?CI?Qp>u=Q>l>Ȱ>[+l'i=ݧļN==|j>>ᅥD53=?)O?A?p"Dyj=c_>k>APl'yX==R>Ŧ>~;SeG?u6?*? |bj0=ؽ>(==ɿ8^e>>H>鮒>/4]>1J;>k>P>Yd >$>پ%A=J=~>+$n<>r@t(Z=P=>W >F%c>B>b$"9Y<>SZ?#?3 0L>RmH4@>f#>y>ci6>Ӎ`W*=)8~Dhp >*E?f?(ZA=Wk xKiUyRֿ>]'>SC>*.ÿz~L=a_KNo<>m]>J?%p]>x->\=ޥdP[t,>8X>k`(>CM} >A_F>:Қ>>?gM,>8m/=HSc!|,=>/2,U^Bܜ|<>j㛾WG;0>[f0=]>ς,>fI#;_>(=#>m>e [Yy:>QǽO%>>? ;>XGɾz ?FE$ >3z>Ȭ=vdU~:#>d|=Wz>᥇> (>،k>鿇A:D+3ՙD.ARvY>>5L G~X>伃Y=;x>u@O7=XYɾɸEAL#":m?; 5=KJI(?>mm)1=UPj(`'Q<vZ? >jnΘxq?Mf-a>{$zɣ?# b>D7]޾K'?1+~c>,BHži@@ 3>mҼؾ|پoM>vzӾe4B_cÕvN>Ţ׾Ǔ޽׾jJnU>bEȾ:ֈZ=X=ji@t柾X0w> R,ZQiQ}k>( uݽI^FY=Q+9Jq=]־7?f9>xaȎEx?%>_i˾:/|@D>[0sm :9Ҿk9aU=F57X b|g'<f$ %z<.3=-{ܿ+̒e1=DLl?{>gaADhEOX>qQ=?)rͿ.4½dQ;69ᆭN7=ώ~ξϗчh~g={a> ,=rBc=dV=vp"T=fp#7FC=H:H]!={_ $l6aq? >>/cѿJXs?v.J>YXڿ횾>6=bFp G=LYc kc=4[2?2dr ;^=5 (~986?'|>Ik4=jH:+.?JJ>yξw8 ?C>J<*uxw?2>'H:a|#44;?JA>+>r>>0?>NF?ޖ8C>eZ0I>"#W{?>]p<3׽k?רO>g>v> y>HK?\ >}N??,H?$?`Y)>'C+悿qڿW?^>)zO:ノ#K/=>҉@п*F?J} >G='ٿgo P?xı=^}NShU? E>[|H񿁮nd=0 2> LϿ}Ji= $>gzUn,?.m>)IHw%>5>J <*M >6&>P(ɿy>>":\ҿlЯ>/H UN ~_=%I3W6-?L00>xSx=K =3Oo m1V?8 >Xcz: *=:>;$<" =0'=?ND>/II=iwX`>⃐ۨ=$?1>t>bþ]a)R}?B&>&&Y[5? >*<}{bf ? [>apN!h?9M>1IVz?ܱ=WE@@e>`<Ͽ(t?j>{)ru?>=a$n@a>89h,#@ m߿g>+j@%>; Q]9u?GcSm=_4㿪п>?w!V>,}FVN0?>^xlQD[@Rj>41[68??K>$a'W?޾a=Jמ࿷Lfh?]ژ>9Xj#_R?俉j>]@% m;va|^s?ÿw>AcgYd?!.4> {g^?a>7LM'w? >vL? > Y?.s> >P=c:ڿ\#6>CtNp;/~V>+<ſl? ?IH >=q?=>"̿3<ז!k?M1p>Ⱦ$O >KD{(u>  =>UKf~ mL|ʴ>"w "Oؕ>y3O3B-%Wl>r~%꥾>Bn>3zି̖>0ญ>~?Rwp<́(+?d?.4> ?~>l|?T~>?E&=%y+>})"=ۃ>&(a鿎 %˼cd=m|p]-DY0$>Nm?=;ѿm2#곾'?u)>;$>5 9>g/w?=kO ?ff>j?z:~L=?e>L?sd>HӦH?jj>j?6ab{U4k@??%ۘ'e$w}W0?>䬾1?ą>Y:?{&M?}yd>3C?uSjK>Y=X?mUͿM 9>*yy>f5?D>$΁?l 1.4?=$>#W?doib'9?w}>+?"IoV^?\M=>Ǭqֿ?^B>hu?퍾v`:?𝄿>c>xݾ|u&1? ÿ>%2>ܾ{ ?>>JE? -׿a/EZ?9qC?1]>Z?}>/,>տ @K?>k=>[|ƻmSf>+D>]꿗(hM@A?F썼F61OG]1?Dv=v*uu;uuZJ?'2 Hkٽ?b|ao?2}=޴ ?3ƾqqG,(⥵"o3nڐ?w>ҹrֿX޿)B}?uh> tXCp> セ xyx>W:掿g→I1?3>]>3I82M}+o?{[>E3TLZ2bx?ϫ>H=6S묣R@?4𷽾ӕTCѿx!?L>@ 'п?y>wU~ B g?Tk{=4G`i?l>(#Ovۦ?K=|U$*JJΎ[6?h>R\ ?|?/u>,X=M?jh>^̣b@gs(-8?9e˿<1 =?lLQ(Aꁿ-!?Z>M˽ȣ_/˾B?M}=%Ǖտ-{q?UU>A_Ŀ[=]9>xCa?ݿ،>eM>b;  o?+?a⛾#kӿҿÿ?x)?*?pc?+|P3@ؾž+?5])- &x+$?rPIS߿,>y}=,R?d;ӿY>bc#"8x<`g{?r(.xy9e Z?[!->333Xh(G=? ԕ%/f0<7˖?!Vm5q?cZ=ypQx*݇Y?>^(>0V3A?½mPvIґ-dR?T>ye w?1ʾ0AkHd>"lQ xnF?'>5ѯ j=$Wʆ:ƺ*?aD>͖ 1 zNW?ݭ=ʾ́%IrҖ?]>٥XԀ;"v?Ɠ=uG4zM뉽a*V?<ϵ1=2>K, pMEc?6ֽ~̿}o_ ֻ>\WQ߿_ CF >Gs*M+὾i:Kn:.լ޽>b ?"ځ$=.>hU>@?CD[=C>ھWȿ._?0~>>#6>6 7]J̒?)r<ޮiwe0ʆIDAc0M>uIZͿÉ4%,h#)J>?KVN-Q>d?!>K8ƾa>Y,08J0\ݿͦHd? p=ھ,S V=#&qݷRse?@=H eW?Aa=敖St|~_?>6>ٽ1Q!?<> =tðPֿ& Z=m>7>i׿:aJ6 < >v>ˊ*x:= ~>%>\Glg e>i?  xI0P7?$?LS$@mR??E>T7 n{?XX>{P'ls\?]?> LHqfў>'辛ҕ=Ly'R#?I??a:?a(/'>:?l%}*b9>?=WzNn6^վAy>?Nwu g-M>r?!GG?lk> HJ=?)U.>[^[G",z?=>=ս֬d'2J>M?׿Cg?v>- *xK4 Jnu?P%[> }:6?)~&>e]>r9T?Dk>>];t~)N? >)hM@qwbè=ƤIA^?ByF4>/>o3)\J@?V?vNTo6gi*0>߾<╸>>þc5 R&IwZN3?g>x[=.4?g<>a>3coib~$ݯ?*`=?LN^Q?&?YnX=f_?V=9"P > k?6|>$Dᾁ6m8>E{>iWͿ$J0=1=z[nRk/Ώ8b>biY@ݵmx3Ƽic>JnH/72)lپn??E(?˼>d`g &;=p˰>($"wvl"7?/ >\/fTL u.?D_?;9Qv?J>l>2y>q&?=*AU<̘_>mgY$K>=n?,=>;=GzpܘH=C=Տ>&3>X->SǾz-oZ>O3?=gIr2=V=վt\8@Wvc^QV& ,i?mޭ>D_`hL8)?!Lf=ln~T=6>V `> >)`Fg)S9=>xV:=d^NY^AO^[?Q?P>*&MHoe?*?9M=9B\^?G?wS>go=>gM SHz<$ZۃHv>ȦU?8νVI+r=\%?V=ѾR)c̢y>?=-ۢF=`"&(#ٿ} |ñ !-!M{e˽{ĿŗͿd ># r>+hxͿ!(: ="?8>O?*>k!>eO?]>7=?z? ?&l=Hu?S"?}|=TO6??iV>]Ͼ)??=}D?i?? FLd??Z;/qX} =b9'Rp u CJ>Ŗ8ȾF h>;Ҫ\yX־$A@CtڝOcͿұGں=?nT=຦L-uj?$>?o?=y?4>C4z >J{>瞝UVSP>(?[=`հľ*ݿazF)@^'?ɓy?>#0L˾?[?F/>]??gb> TPy¾C?`C>Cu*=K <<_Y޾AKNN`ĿB=f>?f>=? i'=>?>EjҿM{>?P"!99^@?2z XXe]_?S?5>"X+$&>h{?<~sCؼ{??pD>!??a١>!E!~^/ʼnk~ Y ?2w-?(X> < \>C7n>0:2>S_?Oٿ>> ?t>0=bg=\g?W*?1R> =>+?~<?-q>>b>r6?>?k)?P?4 > :Z%?P?Typ>~ $|~xg'?M?B>I׿!$TD"a^}aR>>+= #YzBt=edL>=o??ݭ>*G_f&?w?~ ;niG-7 17P˜ |>={= .(/`3G5?u?bB?lN).L0-qT?Q?lo?^!+~?52/?m? IS;=)AB:ƾV*>K? 8?*>>RHU?7?&?#># ?Q?AW?Hi+H1l[%?Y@?5K?2//@uS>>>ʟܩi?a?>p4#852?C7e?*?4@[/K-(+;1?OI?xF?iOb$>?| _A{Y:'?[?>>mC%Pj> B?U?i>>D+>?e x?0??S{_^= >>!̼ʒ>1OE뫽uy>^_?= pmj?\?ܲ?D;ŧÀ>B槾h!GXt>*ؾ:+4 vA]_=>mI>0JizEm]>G>zV}ԑ>^='$>*о6H(?Z?ɺ?΁-Ap >V?_?] '*/?1?A?Ω ![+^ݔ?i?p? k*3???ܾZ=>+\a&j=v>5=2j9|>1HW1?#پ $?[?3?ք)B9?JZ@?ZY>%N?@?y3[;߹?9?f4?3y8???&? ɰvy>=h|謹Bc>帾OT= >^?'k?"K*T\1j?z@9?K@O9H<?{x?sK?8CVH6@?G=??oeWLg3>L?l"?|?fQD#&gT ?,o@D?ȥ/<9sW?k3?ł?qpZOɧ ??fV?5nPol=??#?ћwT,sI>%Ĩ?n?d??Ht=:Gv| >t???ٻ ;<˛?(?EOR??D>í*=R?7?=6\̿x J=/@^?Ź=p>!>:E?T?u+\ >? ?{u?4yB>?}?JE?H>t=j><ӁR?&7V>Lck {?Xdz>\ҋ3a>} >y4|t:: O:=L?/?^?">"F?B? =:j>p*X=?=:>͡>x+{;>*Z>K/\ {=7$pZ0 fTl?汫?!@ ?4Y~?S3|?qe3 n+=S!0-q<>=ϵ<0=g X<9>c>5n=̿>D:=My7=4.U=5V>X> =UЋ~?pvr @k?b5? ¼0z?f?j2XŽ@?w?4|h[mԿ^?a?7~E6¾/(A==?A?$ڠ??Z@ 2-1>?>‹q?Qy3??` o??2j>?}1?ax0"$==œ?0pe? B_$ӽ;q??.­?5n\-?K?@ƾ_?D|?/@Wkh*=Y4?'b0?5J&;d7%ws9}a=PaA=cз=H =3=ܒX>;灄i`m?(M?ci?1>?Q~h4<??"2?R?B t*?ÿz?_ea)-[?i??"/z(7Z%=r ?,?2j?{=>P=p ʿE?> '=$=t:=Wy2=>?W-?SQ]A?KQz?xgFh=v??&?tN^1?SP?ز1gZv?5ӿغ?TR=9!^'`9gqV\? RRX?z'(F ?[q$=r |p`*dÿ>i}J>/D =L=,PD9>yZl>SԮ=Rr>9>?p>?7~U=S=:$o@X},4M?7C? |=b8ZWQ>ŽH&5=TTm>$o߾?=SW>?NmY?:E?S2x>7?f?0?# ??x?&+!q?> ? 5=̨=0K½K>8 ^U>j>|>Y5>1f>a?4?"?Fj?}t?D| ?S X i>+|B >!2ds>]s?g?T?r2=ʈ?o ? u? }msw)>?5?h?iqH?+???j>>?K?;\?cbph ?>?ž#/>0\c݇u؝>"?ý??\}}wy=m>>́?Rvn>5?O>?##g?r?R_U??$8?#S>$Օ>0<=t.>Ջ"=1>81> >Lx%==ϴ>=H6e>Eo;2ͳ< \cTm=PYh<=Q>_l'>2X>BE`<ث>GZ=ц>Q{&==t<>?! L4>j}>A?=>:>B-n6?sx!?|n??в$?s&?ٴ}\:?eV?No?`?s`?o?ޱ?)K?Z}X?z[?OH? 8?)Th?mH)?_F&B?V\ҾFk=:p)򇾃s>9X>Ek8 >^>1>?"w?=;~H>R5> G9=>4C?,?;?.??'1?&?,?`+?F-̾@>)9>wu*μX=i[>h2+k='="D_/>y9o#/=<=}Ծ$}>O= >>u? 5~]@P=Č>3~ >GE;;zh>"y?> ?Fd?y:>=v=/ o>$| 3?D><>0 (>/??k8?X}@6XV>x>\:xq>)>'T4\WH> ꯽d>ft1>%z.>K80轲 :( f"nP=ނQ>^ =P>?AF>25>La>&\>u8?Z>q@>5Q8< aެ/x<ھ9Ũ# <-K'>Cj>>iX0=e==>jɰa"'=}=_N<>[o]?ې?C=?/2HAgо~=8H4>~H1Խ4-86LDE%=|%֌ ?*-=ÓΕ2{pBpf>QL=#?W?D,=gɾz\aH;T[P=ؠ ?FeahtK0?{24?.A?r`E>gL>ӢIq>5OP>j= k=??_J=a.WU7?{:A>?M2>'?*$? ??@>)g?ՀL[?Kc>?H$ψ?½?Qu!?C_ @1+?1? p??sD?@? -k??U?,T>wS]>-?+P+A?FNP4j&eA.񽜨]0W?@Xj?ZΐA?2 ` .h>燋%?` 92Ƭ(jq?Mp?> B?~^>0 ?lhs#y?g7?Z?r+?'M$Uk{>Oj>ax>]Uȗ>˴ ( -6&>PB?>`fA>'3*(U>p@<]B>d C=,=>K=k>u`cp>a=T>|q;G=i?>+T\8+$ >ƾ`8\>+R?u5>A>c?($A^>43>P=(1?2E>,>}5> ?=9i=5?U=?5/h-:SBh<cC/A`7hʽ 57e>_ 6 i^5=2TF>>˼>?kVTO>B>s>ܙ?j}V&I>4>/> ?b||=Z>إ>{?mӾX>???j߿ 8>Gs?->f?z-#?:?Y?&b߽ =>>Q?L7a"{ y>?&?sXY:G>9e?:?ghh=yB >=?Eꚿ=>>>_?s)nL<>hE>b?QH &>>?Eo?m,-lcdq?ZP?Ɔ?G˿7}>S?\?$?X:@r?`??/>@>? ?wd|Xh4?%t?w?Lj7?X??͌8~9Z?Y?v4?yLO?8?*?WF?c4={9!KPa/㕾4M?8?R3?շe?n89=tKpNX?2?um?)d^?+X?E?MFZ>,>R??, @>+(I|_9Nr^<v@!g`>T>Y.ŧ+>>)?D?jhkLu>.U??8q pl??l?Nd>(??Ҧ>yj=o!?=<=Z>]a>;``E>s係DtVezI>!>%}?+!N{f>-71|[ѽMY>^hJ>vegcN0(uG>Z?X?%꾲BU>"2ǝ>Vz>ԑ0 8b?t6?1`?h">D2={>%2>`uq>71>~? |0C_-ؾ>@DUI~k>ϯ?~,?Nl]fV >S>?&;>A>Bp>Et.>@F~ >T*VDbdR}ϿwaFC4ΖuoQ%=%<pjY}V1>%@-yQz?OM?w- Z u3?i1?tq`p.w)b|>O,!|hau??>^%;{u_8K][qImSH&p#h0"\4#tK?0*>龧Y>WT>t8v?N?MK{<;޾<$?Sz_Ӿ!o?[K+>C>?/`ש%=q??<`iѿƫ޾? ŗ>Ov.>1I?1?SfDhM>+"=?>B}ؾ?n>/!@ l>#"!h =8X>CRϞ8H╾ is*I,=z [ z0|ȿ,5*>?h?kD#hوVNI>Rv=L@=9>9?>`^:dMR׾ɱ1 ;?%7Z>-_F?H$?L?xC8C9>X>$?A?8> X|ܿ>V=hK@\Fch?&>A\Ա?U>>2xGо>ɽՌ =Zݜ> mսq=u>]Lw>OU*^E]=2>pH+-Կ3Կ[?:wG`$>~v4? ?IM?L9A~=fj?/?7\=Y>GgMqa?.\?›?ݔ?~꼾*> ??DPTʾ˝微߃?]>iU.89bD>v= ( X~5XhT1Ǝмs޿]FI B az#dI>!W%)P=G! ՑŨ=v>9.Ԁ[d(>'! j>>W%j::P#->|=.6>>r8[I>(c>sg?F=Pm#b+}*w =˿S,~|h?%#Q&>5G?f?(i>vY>SaS?D@?Wc?FBKz>;G??'MW>vl>O>(<)H/oy=ɿI鎿t!?}6\-=Я`)?5.s?=GB2EPz:flh>Ɨ> ?/? >jfܾFE>)>E?'0@B V=ƽ>O>$6QBOXo.{>I'4/>ehn>m> l}>P~R?U>E'Fӻ>< '?,? T>=?.#?K]sz> ſC,6 ]x=Y?Cc @S]>27LUCv}ͧA΁?T]ȾQ?3")?/a?鉭&@%?1?'b `閿.>u/ `(.>Z:>&G4Oh<̾M85%Bݽv оT0Ra˟DR2HII־W1 J辜=u=9+o _KA[ȿS-$ӓod;=W =Ǜi=Т˾2MFi?LXQ+>=2k>>q?19S*>E'բQ>> >DUT=6 ɴ>c>W?⓾?+D?0nϯ=[>͝>+7JOm>fQ=Csw"y3kӿSŽ_|u?&R?/Ɨt@<?7??W1Y=.4?D>A>a>\Iw~V>pX? )=#jr#?$}dh˾5T>#?XX?ckn?Js?)?8[[F(UV>=Xۃxy>i}iM>e>h>;齱l>p>pg2>,>%1>:`v!(= $->m>>_=nB=93]=ǟC$@*=p?@?R K@iZ>VGua ` =F> w貧Z D&Nd>G(+><1>4v4>-ȓٽ[=Sr=T"g`N>ot>>pLZp^>$N侐8U>_Wb> [-o<~|=?3Zܩ>q?[N? ?4>rqZ>(*.=j/I>)U=>m!sP>EZ>Q@;+9A= b??hi,k'=?-?B޿Z?V*N?h⿉Pt>Y !B=ڟ2+>Cw/C$>ɾ$M˿=>s%FX&7Nł>!PU>>K<_>O !?13?@>=X7. v6>> Fz>Ǿ8ન5 `z>:_cj6=>9=>yB:=*>"PX:gW^_c>OȰ b N="b2>Y{8=3>?P?hN_Yxt/)K:}$>=>2? O=G`Z>e>?;h-:>7e>#>v>u=h>ʌX?JLջ/E>pNb?D?$_R!=-wLM>> 8qO>ֽl>3? " _\D>F(̾E>O>+,#@0o۽R??rqifo=~wսR>>nr<g>.7ڝj/MM'(<$d>$p?"i=IrN>go?Ag#?Yƿ.FX@>bo? tix_= >E'> ?_< 2 >6>!)&<=S9>6>i^<Ǘ~c]I&pӤ=X9 푾Nb{<>>z䣃Bj>?KL?b○QDdD=WbC[-4a W2=$9\O"@M=RT?ֲ?[_=mض>2?&b?{113xZ>1'pI >6>+gQZؕS=gM83>>v B^=e[F>oB0[=㾼ƧF5~RO=+˽8>!=꺿>&bV>Z`=jM=:~m>؄>ʣ?]?uACH>r#[>)3>C"lBC~Nwо>>lw0>WC>/pJF_>m> >SKj> B==:?ģr9>6.dVK;&>.p;@(>3>#[`=Y=0"3>O>upL@ >-5O>!>ͼ 5J=ZƓ:Dc~$5?Ȏ/>$Fl=4?(p9WC>(۾mL?Qn-k>pu< R>c>:p]dC߹9{Hs%p9>4,>u.> Կ:l<==hS8H Hྷ„G󌾕LLf? -J#>RP/uRƾVhE>s\[ *20 j/j> |3sb ˁwE>3ȟR;L׾ѿ?`==)_f*|0Qpֿc|xW2=ɼFJӾ -h*7YB AȾ!!=l80}gLj?h/>IF_ľ̿I|$>iv|#1S} 6ۃK%<ҿJW B`5׾ >9<>ж1>>O;𽅣]=!=.J>6ȴ>X> )`wixOS*M<M8b%w%<*sX#N>Bξ8γ%6daA=Jȿ(n$y?S q>EFſ/LDt?fDt1> @6p(?h}m{>qBG˿0n?Mo>-ÿ![hd%?[Vxď>u$lVg? Y|>;.[B>Tx>|Zľg; (4;y">Qܿ忱Xڿ>?@(>^Dп%xV>l::d׿=I%Ft>>K-jэQ[=ֳ*^ ‹ pRnYj>5 m`Y@0$>>>}? V>| ڿ =$(?{apR>/*п#s˜?pzi`F>n g.UL?Çr>`>aH\d>}K>\uY7>>OGx>5s>]տ>!ѿL/+t\F> տh@п>04r=*,=rv>rJ=<}=ȏ8\4G>?ac?a?J?wZ:>xm/Ow.\!>K>Ѕ׿(= >v-0紿 sE>BB;Q¿h^mP>ϾXؽ٩T>ip;>щo3~^>ƿZR":s<5_L Կ`?>z15̨3HݑlB>P`km"l>'T3GZN@WL>u}髰3l?u%F=>>>|? >=J8>Q}>e2>4ξ Iz%XݿEZt>.P>uHgJZcĆ%H>>ѾnU.lͧDtT>sپi^wվqhʂ>3Gl#^bzq>g#pHak.>?!-ڮmו+C>끾i!?>>Ѵѿ)/@S>FM#>Tv8m=9L=:>y=H忘>uĨ>i#ľ%58k7*=Cڿ:=?b[??=>Z<dJ6?=Ci8>#aV ׿ɺ,Ç>]> >+YkC@&L=7>G%/ӿ ؄wu= ? Ⱦd>{ ȟ>+i۾Ŀp+pg?&>M${u=ٿsQ?_:>vͽ[p9:?}n>B=EyXsx?Zzĝb><6?>=/FĚ?YOHGwd9j?_ΊB=-0j"+?\d=Ļ]9ҿ?>~cf@ п>_ݼ-+(@p;>A]<Ͽ?~ÿ_>!NP?.g>KI=p n'(?Di>i<Ϳ*۾`?Ya=>D'/4 ?|>׈>6Y<}uWV?x> ɾKndo޹?% =lRοZB5?$=wdQ~ UJ?j>+ӿ, ?nI>KyF \M??>)T\>?~a>Hj]=P X>?{^>}i?6~R>(,?>lLM>>| ?>f'?W >d??Rʾ3VT?W{| `9>?i>sX,~v( ?b{>2/L#?=,"=w>?">}F2ƽ>2K?+9>ʿUL:^9N>ξSPio߿Dk0? 0ux0@Pj/?Bг> M_?#r>?fO>2d>r?3=R?[>V? q>6 ܿсO=#>IUڭ= .>inY?n>B?/">t?>PU?}>L?L=*蟿,>Kտ3>Z[>S&>;?ƒ]>?5 obt=?q? >](?)ؾ֮lEx"Nn> ,A>\c1O[.=qt>p){./Yu?Z?zwnTr?[=~? پ6??P ? vl>R?L=bU??<=EA>v. 6m<\b=zQΒLF> [a 6j@vOxu>"0Ep P2׾W ?@bۿ)x崾U?xN>NJi1k?]>mä \Q4?>F1V~?*N>+qWOf{J? ?ca 0j[ѿr?i^>2Hؾx[W8")?h*>ne0]5?s[>TH!jn5s?r>b  /?K> h,;>y5`F?,oֹck o?sl>k5n=|HCD?`E>п]/?>G%'?_/w>#w݌LRׄ/.>3_=k?9S=ϖ>7\apE=gi^;C>QHxƨ:_>R?F+>T>F~A7i?C>2x? ʰſl?1>O1+?.'oX} B?ѧ>Aٲ>J`4'1?luOH>2?>p4`?/I>>0>wZH?v<>s>O>}kV>p熡>Bx>>$GR&y<+>8>lWAJ?>c*>N=i{b;}>/NdIu> p>w=xKÿ($\?9Z>.ĽKuS7>=vw})?O>k-btF?>XaJa >?}g@%,/-掿PnT;?X=ƂԿMѾ(NFӪvԔ-?I=!> I>p='>1O>D>kTcdr f'>حG9?TԿ>1?:>-e<6?]yu>?3Mj>]_t?r{>$%?!`1̦1>ξ|p?>Idm(5b: R??Vg-(.ƾwkP9#&0)>A1a{ٿ,LYǍ.b?L>#?ÿ>OU?.V=ᄎJiWBݾ&?.>ƾ[FFоD??=¿_F5?_\>P\?coz=>O+c? D 3>O>>ؿSs~8oI߾(?E?uH _=y}J?5=ruqc%l,?u>6z 4"=F ׿PXwy>?*-bAN?&I>(觾V=?Bi{ ==.=ҿͿ[&?vHrC>)8>k+(JiYބOJ?0=0mbŰ?8>7F|tN?%V{L]>Ⱦ"\> Ao&վlT㽿 x ?@zL>{>C L?C>>s>!{ ?4k{k>` >󝀽LKӿ=O>JT>B=U$Eg))>cq>9U.RS=h)J=G>ZiDF *E@>ÇK+s;O(̽g>˃k?# =l?,0?ϒ>ϽnXK:J?s?Pd>mYžP?Bp>( C?ĿA>y>Z:ҿ$07 Fͯ>8>%3rFC"h>84>4Q˰=.J>TV>)PO3`#>I? Vܲy^!?Y>^꾹uU9?g?l1>͒u!yUCD?L?sh>T ?5_>c*?}٭>?? x=Xr2 S>/w>C_>-j߿m K/f8>k?Qbǎ=u?ĺ?n>EMw} ?!?y>+s!9?k?R>O;޷?q?Q> =UE^;\?-q?sj0{Jw_ 5>v>?2^Wg;C7 H??k>hA%$xշ=>$[g4x>>187>8;V5>E 㒖>)<=lʣN,6,AТ?{?pdQl2Og?&?vBC\Z?.?7>kH㕿?qau=)<$-ͯSu~<=}|8e)C!4?l>d^V=}>ܨ_pt?UH$>H=Q,gmu?Qe,> }BhM}[6?*EN>Ԣ ¤%Tc$8'$1)RT: 횿?a>?C>rc@A7;p?;Q>>R^}R{N=$}þ#Pl)ܽ|X=&پ'H( ^FL<'>Pa@! iy= *#%ο[:iӽ[)~[&<86eEΞ*\*9Oh@S>Dz[QX?0~+u=ج6%Eb1@ ~>ɇbO,8E>:W!;i?!2>fj?nO"~ٔ%O]>D?+5 hlf>~?j(V M$}j4=@?/>j :J>،_2'9H>^) G6I =!nz=D?Bӄd,M===O?TX*}NƗ?%?KWJhn>3{9k<=$>A Pۇ{[=^?>HW*Rox=DڐSa?ſa1Ag>'*?D%-*?i/?$=E?`?uL>ؽ# x,-?\d?,?:1Q4߾=DZͿ.7%Ѽwվ/>@Xѯ,~þ=gU/O ,p&/s;-:8  +tkfk渽  U[ )3',NB|[7iD?U >\(>@?ھyh/Σ=7K? -2?|i>>)?X S;JbvF?6ٺiUk<)?.a }>f?qo_Θ&$p=:-B_9 H=H/>`cZvy p8=>uԬzc?O>>J?x=D(x` cs?GQ7?>v~~>n?rLQUT=޽駿prnw*Oƾ}8? ?{N=`ܴ bjÿw!S)ԿGt*U\E(,()( !+*ES|MhȆY6^́V=>px 5?jQl>?-~?ȶ?va"z?y?>ѮX&{ƿ 2U|:J' <Bl^J?<=2?1&>–=֝04D\c>;*^mɿ?b?Y?,6D~$Ba?gM܊>?"IM?$>PaT݅gS&;2Xÿ~|>]p. ;;f>5ֽ<]K8_=S!?e=>>. MAn?>4>Q<)At???"9 &yǾU'_? ?>_ =&6*><ӞCёl}:? ?>60vcEθ>7?k?L}́Mf>?o?4 8܄?4uc??C ?Qk0N[>h?%>f4>Vgyb>9>:>I>d}7> >.>\w'>>!>?ǟIJ8~?UrG=sO>Ұd?3>f5;s,??õ>3X'Xܼ ?w !?f5?j3d(\%?6/?W?;CTϒ=ER>u7|'c$QYH> 9>Q=n #8>>ʿVy`ְ"->.D̾׌4~km!<&=4NLKOm=H>)>oIIR0̡@=$>+>1 | E>Cw>k >6@xx>> > l>N #n=tH>q>"sG{+>ɬ>*{ >N?=sxh>7 5>H*$|>J?` >K2ˣ|?@?G@*R?u??KgkI>B4"?"??{ r=#?0?0?H-ph>=*<bcV< =۾$)O~Dֱ)>K>Gƹ -bڊ> > QA>u|Ծi7vw翖n~8;?"(?ڗ ?e/fbf6>?>u.q+<)u?{?GZ?vw>d?y?) @ xxy>o?0?˂f@z|u=_??Q?` xm4z>B ?K?O@0e?n? >:>80^.T=+m>? /4(ŇJ*A?#?EZ?[Ph?)Ց?:a??/@x{>6??>\?ST6 3r<?&?e׿E;ڽH>ȣ??ym.>??-c p> ?~>3mijfF?A?V?Xԝv"y?c0??R >d G=.>X>~Y 6==m*#?&?EĹ> 5r<')O?;?8Կ#?BQL>Q ?Ŀ?iz^OQ?X?ʎ?@E>@ f?@%t >m?`?z:@,?f,?=?i^B8=>1?s?u\@>T{<6>D{>kϼЯ<둴?m?j@)? =EXd>h%]8iX?nwO?{οԀ?6? 7?!6%vPo?! ?cI+?y?ũ}*m ?N/? @R8?F>>mzf=>6>;>.ij ?P ;p?Q?:Ν*@ '?C@HOBP缿0j?;?Ui4V?kE?DD?Y<.?>ܾ>}L=g> &>+=ӕF X=>Ap>D>zdDv?i#?[=]tO?->0?k=?_>n?OpP4Ed?-4|X;=9?(c??2\>NB[>ç>Sa>ѭ=@m :=_^@9>]>S>>CL+3>.ׄ>>!>-@=Ơ =2?@X?jH`?g=K@з=T?ՕrCb??iN?`/=˽P=Љ$>9>>>P> ݂< =( <?X*0?nj?2?S?t3Lc9%?S|?ٿr~> M b [=〈BBBBJz?Gc?XS?Yf?iK?BFS??N\p?q >?fzt? qDv;9?{Y?u*>O"νX=*cu p>Wn=}ݱ\?˩*k?ٝhl?&B'@4;>YGI?=\@?gk{l?b1;>VC=ܾx)?Ej?ڴ4=6 @ F= 2?Źl@=%@ P?Aȕ>z =N=>_[?dRA?ҪZfQ?jd?҅U?p?(x{(?Ol?3YO?/@rz?c?β?Ľ ?rZ-?}[du?T?LE9?6?u??2?H?j!?d?)ZX?FNJ^?oXք?4o? 9:>EؾyB=i ,OU>~cKE(>@Fxxmr>Q5>>r?4U?MIz@?{v?ǰ?aJL?pXd?rTDF?<?k,a p>sd>>>.??^ ?)|f? ś=?+CZ>/_N>>?9qmn">?5/o?*V?RVᅰ}pOv>qa?=? ?6@usq==\j<>?Ѝ8?hfr=dV=_=R>,V?!NDk>b0>h>>)k>˃UU*>O>逑>a_?wSt˼?T ؾ?==k? >?UM@0 @:t>)_>?0z>?AqH[ 5=c=co;ċe>?-w=QH>e>Tq?I&5zP ;zw?=|?+?<;2 ?CPa>'>#=>՝?77b>=x?0f=^>k\:_3>}pu *}>nD>K1>zot0=ͽH> VR)%=-"V$> ><>HȰ%>>~M^>-?6O7;>C>/ >Ǹ3O=斢>U=h? pP+S>=F>B2*(V.?^?N?B<2>>?M3<'=9>SgSa>OhWw<>\>>ߋD{6>i,>{)<9X>_H>F>ZGwS?8A.>$>M_c] >>S><԰[>A>',>_?}8Q> X"d@3<dC>=F?r"(*;J>}!#0Qkz5g ŜcJQШBdVOj̒K>21@@*a1>[>]B? ]+@{׾>&F94j>7G=9'7Q>#+`?нe2$.#jD?P?Qa`?2?S.0?nP?_9"h?s5 ?htC?\A0?I>V>)l?g:T?ز5i?$I? ?~D?H>P(p>.W> [^p>g}?+ھ4?x  >H?xRu?DJ>r?%A1-?bJ(ó>eQX>WVP>]>i8c=b?9=cQ߿8)G:>9?Vcs>v?B?Dw/?1?L>}?{տ?k0QG\K>$hN ?0'>V>%?7n>w4+=_L=;X>AL?>̡=a(>+=C?Ldy(?Vhͯjn>:T?Rr>Rx?`?Xq<1)>'1?-H@N=Yd>]1;?(^!hg?##=<?H.U ŨO<>j.>~h;Y>۝? O@?eµ?`?NN?Hʩa?.F>2?I>td?R>?OyS?v?1\>>:>^c?M@=?u!LZd=/=<з="&wx>5U=L=70/]cfؾ<뾕 +[$,(V> dg>*=oKP;KEM>(,?10>E9@ξH>`?%W>_l@@JTz=&>l>h ?xM=55>W?&n=R* dV#SP4+˭Q>][h?~k>?^N3-,㼴*L%oH3<þ5Ц>(оs><U=UfU*;UFW?1i?vsi}>|=>5&?C?o Bْ? ?df?Մp npg>^?Y~?"X;\>?Q?5LT7|*='>W?m?hEV xe=a(>Oݢs?V?a} f=??Tx1?Љ-<>C?B?aQm;X??xl? ם:? ?'? _R2 ?6?>u?5 Z!<>eE>齥?Mh[e$;67>)>?$ھ?%?q?1پ*|=xO?FDt?`o &龢?b`?r?x; ?k??L?a;P>[q 9]:`??֣/?#H;??=?ak?x@.>;.Y"pr'd(>-E?R?jq}{׾>?l(=?`Űv~_׿(ÿDR>T1Si?Q? /}a}r=_i(|VڳV>dG?b?zP/1Y;?J?.?q\_<>g?xB?N>~O%>Ԯ??:J\}>>ĿΫza ?;X??bZǑ;?X?%?X"ЁFEP ء> mPTS:Ƥ>Q? >?Vn > Z??T?gc d>C> >H?6i}A>VM<7i1/ v>j>KIz%o#ݿ=5PTB>߿ݿWXH_>o+\7*b_|N#>f>]>:! E^?Z'W>>~ߗ (c Zo?"l?6C`S߽(74<=$}>?%? vdA=<>_+ =n> e˾N?[]? KSKث־|=XM@̀ <B;T?$ľ{V??e@a>9>7>u?Y4r>UE1 =M>0O&?:VGA>#P9L ?=hM>I>M?>R/>f? | ;~L?@==ˮ>`$?DP>r<\>(;g8Ɇ$ټZ'(>u>^7mpwՈ=y7r `_ˆνG V}<MϾɝq<?%P>2ֈ#->&>].~RuDT`ݿDܿ/<ڿH0k`< 8d˿ΫC(In߾>+(TN:0s?Yx?yWlHk>y?u?3o ?2)AJf>r.>x(?i?O/ u=$X.l=Dd`<TW6m+T>X6"<> b> 8fd> RƂD>0[:8t=3׾o6"V<d 2cA> N6>Yq>? ?̎>n KJ>5>?A?OX-= 7,?J>"DY=g?>ɏ(==?'O>ڽ63S>>>˫e?u: f>d>:l>Ŭ>=lG>jY>]^x>5'/>Ѱ>=6h>' H)(0QAN3? =fn?7?U>17EWh>>ϿIvdP^=Tֿ>V鼽G6+0=̾><2> zl7@ ]> Ͻ=P"?\[> C>oY+>n>ޔ/=ɼ=Ei?:2`> >@y?=?Q+>V>Y=?X?lNq;= վY@ 0+Lr;mP73d}2'jZO=v3ξ'-r4e=C[p~(=Ṿ6=;!_>c& R}W?Qv>P)W9Lm< gc|>l=E?] ?oS=H~ ~*t>LkHQ>qMr>hC&=V7zq=9=m+V=vȴkw=16ዾ ;ݿ-!ysG>rw>JE?c"?tby{J>oa;3?@'?K 7 ܿ2~cGxoњB:= $5 ;[ap)ܽcᇿ`ryG8fK"Wf׾/E݋Po=F9>>I`xD%'=?>CIb{>p>Jñ= r=˧>DYS3&=-AW·M5;=+| Zq @qs>=~>fws>3|;@>\`qI<z&,O =d11_=L+N3>HZ =E.=F齍i'ܘj=;o*ރN(e,=䅡==Dr޾K>?.N'?G|5ͯ þ'0>.>d?6]?>;\0>[H>:jʿNiT>>_AX 2MBH>h>>A?5FW> z!jY]sl@>#A=[2>>\>f{>= Ң^%7]"PW=@gb>)k=k$>r#>ӈ?+?4yO5)>ѻ=LQ>!ҽp~>H^>>gk B>A ?[<1>9з>GVͿѺ^mru>#ȿ_Կ=2{g">>>>BbiU >qa&8<?]joi4Igx;6awDp>>Qgֽ;*>?0=CM[FÁUi>u?n"?\P]'5"==L!G"=5n͎BrIϾzZK>r>j[[RǾJ>{|>i=*dþ־%w,R>yfs<=cZ>^ Ȃýx|X<ھ,IѾ$?jo0>t[?Wl>]_rrU?I|c/>HRSʿKS+>[$w8>o64*}V>a>M vnY>%IH88 Wy|O>տ@~9?tR>jv{bN>:sAxD^pQ=A!;eRP~R=֮}dL=B[l=7뾸eؽjJk?xe6>/3T}UW6Y?/`r>@|Bv5>;Dۿ:ek>4;Ws?`qg>ȿ˿SmĠ>|2>;u=9>v? 3/?Dw>35e>I>ʾ>e|r0{>jc>?$V? ?h[>atp ?'^=^I^b0˿hw=Khy>JL(p"m>57;Oq} >sC+sҿ} xBm > >z#nw>?9pl>4!>"fT6Pn>Eg8=q>(!>>O??$7h>G-伽F>o>I?@P/>"uhZ EAd=|Q@>Qv뿨~t:gX|->vX?'} Q//>u"꿝~X#Nf>vRο|r%Ou>M+1S%>)PZZoc2e0p>l~uĿii=(}>Gܿ77ڿAN¿8􄿧R~}>k^omn~5|>C׾yXd +R#QDLQVY@hs+A8G,~2n>f ? cD̫>fRժ;?lDeM>Q ?Cr>a׏&m??ORDj2j>e7ھ#d$B>l=oOx"e6e6cRͫf:0 S76=dJ';C=G`H7þ]~>ȕe8;0'6V>i>|?HM>1xp#Vz{M xQY.?0@`>'"r[>}c̾p1tٿ>vD9 1>Kn-=X$Ƭ< 8Bl>(˾A,d?( łف84Ҿ8ү0jb=>>`F`5+Y(jQ?[>oҾf?}PL>Q+ղaĴ?MbZd>nx`}p?::_>=hq>޺TF_>H^oȿu1=~_9 R&! O{.:5ξ]y>s>:ֈ վ|- =>y|ĬM/pY1=r=j>l>B>:%$}+\߭?Ft~h7>$#پ04=h:>?U un,=Y|_lR 4>m&pl_?}F_>ET4?̅?v8^(?B=1[1Q?JB|ads>'qS￵Q v?!g>s?;ժ ~bR1>[:&SF$tLV~&W>VVDĽ=P" @>TuEW..>տ:8οhͿ⾝{>w-;b>>$=>>2(m׾?EO:P>[A±>uxd>_"T6~{#>%oV0>YD⿊8pu]?na>;> >w! #}CNI,Mؿ+o39~a$lj>˴[>']SR@tui>x__8K-8m&>Kw,^-IZ޿\g~>3<7ۿ䏿,Lۿxz'>jfhCC|:.8i $e='x> <vd s!ѾDs&9 ,0 H-Z-BSpv">`S1࠿e 9b>МÿO:S"g Ue=پȢfUbtC([>sʸ?Կt.` 6>?7ֿ{n`_Io*.>3PL*۱_>9ϫ?1~[!>9>ɗ>~>j2>9>GR>#F\>?GjbF>}l.ܾeQT>\E<7(A>j)0+>5W~%#xh>!$>\2fڲCpN*>0R־bؕH;73>fM¿B­8-8HA?P&Fp">">9>Q>8??">ψ3>l? n>ޗ? =?o>\ g?F<`?O>(o%ZQqP>'FXa{|h=pŽ'~(ZD k<"O??پ  7ି(J>F5B銿V0?t'_>W ɽ3ƿ7M{9,?`n]׌>u{Pn%&2 ? %>JE>?ҿl>'m+Y?w>ݠ¿6܅M?X >7ξ 忲?>!ž n_LFSL@9> |fK<@ zl>IʿlH?cy=SiKQU?>ܿhM'?㿌Hk>MᅯOM?iI'>>hm&?sq;_p>l9>޾Rt ?>>y>,~?n0=Z>;?7>+>0j+LFL?kO2>5?<ɩ1n?aDV>^>Ҿ%sE?m >ھg+ O ?Jr>Ǿī ݿθ?ru=;Cb?RS>&6$ȿS?ZFٮ>>+ۡ=c\4ߜ<>nGܿBl?*WEX>>(g>@ƿ6Y=<QؿU;V#\bY?|s>чῢ?a?Jk>Fc2¿%~;4' B[U>M6?%9`e0;L?7=}C>2r?Qc>+SP?PD| (>X?Gk>xF?ReL> ?Ho>:ѿ(?c>?>^>$ٕ>ؿ%o?>J<"%B?~p|>, [>TL>CJٙF?Wp?9q>?1Q>>HN>D7>ҧYM{翯C,#ם?>1QX,\l:J?R=a=|NB+ż?k/ܼ4`;ɿ8=^!?<ËnpL ddG?,$=zQg\iQSݾPP?%z= S]m+QIU?nZk>bDŽ?J/ʿjv <>;2?S\VK#]^J8= G?<ҳlO<,ǽ>j?7}>NR(\6>6?>xȾ)/%/,>9?a>O۾^!BqX<;j?]9>2LQ/Dhw?1n=zx`>%,->#&?i(!?vkl?" Ǘ>dp?gƽ(_?ÛB >?gD,jV)YSH? +tg2|cn[ d>zmt>{'o0Ix8;>m8˿لhI9n?)?Rs p ù|?:>R~u w?E?݆#Yq￴g=?Ң>վf<>S.mο;>A9M%Ӻgj?nd>" oPH Q>(ӿywGǤ><ߓ)i?Q>qGM. 2?>7! 0[:l?w!>vJ*? a>90?=޾p?DQD>O#?>4zᾫd< 'R?#u=Q?$>d?r>Մ4D뎿{> = Ѣ/=˖|R>1Q=ҷx;`AU=ِ= Uyo᤭=e8,,ؿƴgqA6>Y=zxevQ쾯=:/O??UC(=.ÿ޿1 ?>܅Lх:&?P5?d=/[KP׿r.?)>t:`ҾO?{k >{XĨ?>f, ɿ"_?z>`k>|R= 1>_ 3߿b0~,uX??X޽Q/?\<} >e>l":K'%oJ?n? zBn8"?h;==?]$?Qсk=hE=z 7b[h7?gj!\Cx?Ǿ/ԍ؃H l?a>dmMkbl?&h"X g^E/ڭ= }ؿP? g>6 ?.j>4M?s'xx>k?, >Mo?c>?Q>0<ͰW /%=du2l : c>ZQ#E8c^<"=~?6>*})|p1ݔ?=q2{5u>a?cR?>y R#;?]>:Cpq?Gx=8<9 >H/>^>+%>t,"IxS=l> Uɶ"U࠽>2=>˜̿A Nǰ*=l>Kg>T8TX3B L%>8>Kj?$b‹T?;=m߾NYPc5L?bt>kmVo-=  ^3oS=C>RI>-Q'gjax&$??@y>YgT( ?6"ǹ?5ؕXU#?EU?Z>2nIfN?bپ>6ap;?z?V>Y%@tfV?z?L>N>/=ţ]RS/b6`5?2Hꅐis^?2>oʽ猠??`4>' רpܥ~]?~?? nPU"?ʂZ?}X>C0K>*;>X+ RX>?i=WZ`b-ӿ3l?uG?[>r_?z?ZO?@mrA?B)c>#}=굀#[>d^9b?= ޿(.>? ?2t>`B*T>~C>gq?xɾ a,03>^l?]0Ϟ.="l>/Q&$c??뾂1>;=pj?I L?O?@%3?N>?{4-~?DK>.;:=0Y?29> 2= S?NY>I'Ծ@3On'q<=[b?5 )[tT3H ;vl?$!؝)D0??WFg[0Fy?x?y>ǟ*ٽ13_yQ@3(<`BݽrzppiQC>gϾ,#.G/f>=S.{o?*$>>?;H`?f#)o> 9??%[=>.D$>Q>?im)`P+\>1P?Ioʾ>;W?MS0=z:>;'H9 ~mU=G#sT|=X??>J 4nJBٿFgwzDWRt<-Y>6 4+co_m?%?pc>3QFu?i?(=W6L =j?#2>9{Rf;;i`PҳpNR>ՈH0hNeq>k??So>2A&r>=hPQ㿙>=閷!1#??? 'xǰ?K>_x6#;Ԁ>ܢUݜ(Rr+>??6<>kqGý>Xd?pWֿt>ƪ<=:%}/b>J|"(_ܽ?^? >}b c0 f$%>O+>}-t?sY>D>/B5?u '~ ?U"?M?.^ힾ???2HA ?'g?J#>'dV ?^?ղ? S#@R|`T)8?%>1e -!2d3F>d7hPP!*e]?=Z6]0 gL=J? Y>ӭ?%J?(>N?vVzֲ>>r?PvO?KM>X?;?Y>T*0,pC92?>O7,]>%ŵ.Q #m>y-eiICMli}1ܾ,俈ddzJ;߻ql|,b[ݿcgj+M"y^c }ynzٿ.U@#d;Y,O8؇>Q;MIos8 J*,>fo>!{?|>q?6?>?=#> ? ;jL)X?ynz?>  rˁσ?kM8?>hp[ 䠡??)?>@ZqrM5́CtC;?Ǘ? GA?bC??G8ocE?A5?F>ivXvn>P?d鴽ѐK?磿>?8'?њJ?*lQPrSҪ?;:?a>,?eȆ-=Ǩ>?(>DR`NW#?i?b>I(iܾ4 ?Ig?5>dLK\mD?4?7?xhLUHFINY DK?k`?@&?9_/D4=#?t?D_?=xCHK>S;"+:9e=h/DSؤ<3 U =9Hk>U=*>6?;?>\"le!޾_G>ݗN?؝> "-cBB>`?>h? >#tM8JF>J?Jè?5?sjA>2n?i>Љ> Zgg$7>C? @>0{>ThEb+G@=~(?9><>%8<>1ͣ>G>Ԥo*>? s?9J<;MtQ픽_??r~?9ZeX!@> >UwS`c~L)>NQ>> 즇R 0}==:]bO pH>@vpRK#?[xy,>=>>pUfp?+?yy>Fl(h=Z9?%?S?JrIi?L??Ϙ~nqxL+?a?C?tkǽ^?in?f?n 8{z>_J γ5C,bҌ>A>#ľ?Muҏ>>RHN]"B>?>$_Fտ@E>$@g?z%)>,X!`3)&T?s{>jn6!> a?uw>3ݽ`>Gn~hml>~g??2ۥil?4u?ͳ?jnvsH\-???W?O *>x_Z|Ź?LI??m&x˼X??n?S|=Bl?0#?l?`f!?5r6?׀?0 npnq?(?3?6E,0~WJ;?ӑ?3?ɸ93?U??q=G=(7>u%>cF&/=L?ĺZ??@~c=4???[lUxc=  V==7$?67>͖[2'6=g?8 >!=;4ʬ=.?.?t?Dz3>;E(?Rv??\rR>D?=f>%?y>>u?'F?E?y} O>"s?mU?(1H?A?K3a?Š?^?z:=??/?as>ۇ?v?-?%_$>W?W> ?9Hdy15?K?-? |Cz<&=?r[B?L>9SC?$B?o ?D>/?>M4=>g>܀c>0>}4]=4>?If>5T?sOL 7=??cv?w??99??X. ?& nx?Kؘ7Eɿ?<\?NX19?GC>>x@Xg?6?LUw@6d?pD?!\P(c? >/&)>c>>oV>P>~gQW,??EM@b?`@";Eͩ>%?FV?U@@>VC<O[m2a? 0?0#V?dYD?^\=IW?T>c? @?p;2p?eet<`~Z?Ԫ?TLJRN=j?=,>>A[>w= = >B?'?lCN?Bc@?N??VPX?:tV?,gn?NMk7? I?l6TL?$.?0U r;A?-?Q-d?_˼?j^ >9>T>Ip>?µR?MfQ?V?CN?ru:Б?T?v???X?a[?k??VDL?^?H?P SA?7"=:P?d w?ֽ?!-= ?[4? x?F ?{@?,RF?Ě?̿ ?zʗ>&< <'>@[?s>q?Gٝ?tK@?3al0?ffdu?a h?Y`?N`?Rnr?d?sI?aq?;: ?` ??m@?Ș@?f,c?U;?4H>IkFI<Ƚj8EJ>8e\} !>;`yӳoQ y>s}UW?)?Mh?s~_=^\Va@5>*2tyN/Wȯ>yl9y շb>t~|*Ioʟ`t>x`W'`c"xu>G|1rrm>o2~t¿"M)a> FȰd?9?@q? ӟf>F?vIfkS\@6?=@㗿 o\\!>"ڕB㏽Z \P>EGZ>>R>PY?5>@> >_?*)O7g=q?%>??Y*1>B>]7>1 |? Lۿhr=><>>_th? $N@?>y.\ɾ.>o>j?9? mP'&$>NJ>>?!VؖUD o>F77=5B< >‘u ɸI=}=< >hc> c̾c0=\>z>[S>?#O a<`Ũ;z>bxټbs=_n->h=d>-D:>h+>q>?@+>`>H>>}K?!J,A~`"#Ij=2U0,˻=߃=>`>u 6pt==Q >_Yx=?[`xB=iSa;|(U=?d?`=:z=&پ?A:K<셽ܾ/> "p2>C#?&; AO.>+t49}c?>'?Fj߬8^=P,>>AMr?& (  >~o=O5q>`VE<ٚ9 ըNO/uSބI0=?U4kL>*`JĜ=FztDJa>V~=ž ?E2 =>E[ti>>(?IY7־fg˾CWj4EVO9)6=@!? c=y=<>#?J$,?6 2?*? B">2<4ʼͱd>X?|w>^>?VT;?RdP>4o?wvh=ҷH'?|Ë>EWX>T=<`> g?*M? N@>TFҠ?秇T>FJP>kaV>i[ɘ>ٙ|? W>I?7+!=[[P0anz:i:۾!?G0p?eA?KM7">"A>?asC>j?rBP >tv)?'x>(?At>.?(_?Jۥ?R[B>an>w'8 ??Kpzh˾ BpD(vD齅]>9ҿ?RD{έ={Y?+?B>}?c?귨=s?:%>?`l @>^?"=j*(A}?*1b?NnyAʬ?8I?bE?]L)>1?5>?|J3~1>̃?E?o?2o;`BL >Or?ajBJM. = *=re>1ƿ@"K=== >s~A!YxT>z>?C4r?>=(J?$u.>;?rbHBf=>q {;.>=)k>g*P$o[0>>&e.%B@83E[bd>ƛ54.ٺf>3>ߜ.۶V:EZh>ν_eF8 I(<=Ơ>sj2I`+=>)- "<޾HR*K*8$N}>LK1=VžY=+M{@~Tx7#:>$?:H?(Y?!ѾX+>80?'T?:?2=i%;lξŠS>s*Cڶ'p"?> 9/=  D%.+o(>PG?(-?;o*?1?I0R=0s>B|DY꽇x2=_?? ?rͽ#r=²}>? ?f?e0l> A?0?q?+o?8=տ`~3l?6ύ>_0΁Ku=ij>?2?f';=)? a?9+;ŗN >*?]}g,? ?)t`ٻ>?\T?w60i:?+?#?s P.?=?.Q? v ??)@ L>??7&?q$8zG?u?A@a?C:=q2Hhƿ욀{<x>%?-^?Q^!<Θ>H?G?&Fr?<>?N?~ ?b? ? PsM/?,@(@ ' ?<_|HQHg7v p7qC?p,o?oi?\}(g >?z?J@D>!?k'?9?@I>v/զY?cG7>}0>h迡e5_>,ྣ>Y?1S >+Qz?#)N?)S*o>aؽr?=4?FQ;1GV>%?h[:?+DV>*L?Xtd?j^bAljM=j߿ l>\.w>Ob}=9ſE4=F=%=]>>x>鞶S=, ->`>D^Ű=?Q?^6"S=E>>J??{,:Ϸ"==j>w2˂=I>y_>?3+ &=,Z=>u6>\} ^IǾ"?OiM>*_1R7'D\>A˾ս0>?l>0,X(>9&Qds 7q=l=‹#+P3Zb>?J09~Ǚ>)=>a9f>U?` ?uV~.Ŧ̾b9=>'>y:@>2H GZS$W{E3>/">/>M Vv9؇WUI#'JjĽR>|| DYy?M  eb>>K{ !>ޜ>vD_>t>G B~?:\>[: [y,Z"_G5ݾȷþt_p=~x8 ̾QM>뎽T=y>a7IH>ƽW?M?OoڂAh^ =%>>~VO>VaV?Qؕ?V'8 4ھ>Y>m/$8YcAPY?>Js+(ӿDN->=Xa>0D>S:hb>1fb_ >1Z+Qп}= ؈?U ?gC 0C۾=]=U>/K>+9m#>Ix= ("-=?>2IzྦྷrMӾdkп@% G.QwQH=s?=204$:w8=ھYJԯO><>E >=?y?~x$~oWI>q>eZ&k 85? (>V&XH3JFfD|plDY-ܾ܌GٿT~{>KG kΠѾvp=пBES)>RZ½2ƿ.#:;$%gÿR: [kҗcG?K ? l&* X޽?_J>"I@'1 ?2i?]5r]4ѿ) _8 ?$?$`W>B90|f'$?0>9h=G>jc?xE?EK=pX>/?gy?4c7PL^(N=,V? !kt ҾqҞ?b>{7nn =~?G ?w=\p?Hw?M ~]T4F{pd:<xȿ.B|"pôt6/= {ݾ90==(; |NE_> >4pѐKƘ=G/?R?( MX%>89.X ?=վ;dP;bǿ ><8,ھɾyI>LZɽ> {О> ۺ0jwzJf=(pX)Z1쾏?gb?=ViR5>0^>DIjQN> ϿtKpD*=Yqt)ZQ{ ;_>.ә?"gQ?5\S ΃jA߇<N 0ٮս>Ͻ[q&a>A?C|?Up v'>NU?B?&K>=>2pa%dyļ4>!5P(fCϬ?>@8B=U0> q~8 ¤@>2ʾJF|i>>*?jd?e4{$<\)=4rW<1 ,>;-=]:D>(5=گj}>yKh 1Im >Z>^? $?e}ZMͥۼH|:4Z7o=6>3$ȿSyIXyH=H@:> $d x>HNz>vS> >}>\żipW~Ṿ%aw2umaoF>??E",= ڿYSHy>e >L^->ÿ2҃>`[ߏd`'R M=ԿƾuC6y񑾌๼=!{/QqE==>z>003H>>o*>J?+q =>T& o/:_=Џ>4?ܾ>-Kji7|@n>yH|=ȕJUsd> =C ;u> c9-o}^63=뿎7=-fqb=߾p3qG=W)>=ɇ>SxKz>U1Ǜn<ZwySƛ5D<™پ["rB[D)<ľܪڽGX0˿ E>Կ <>#g=ewS\l;'6q]L>r{>]?%8or8>W7:>?/pZ$ M>[>1O4rV|@=4>8? 0ׁ2=?(t;N<O,!v޿EI(ԿYC>俰0?-0}=m䆾4&@p$踿ʬ("rvsi>,j>z>>׶>C?/p >EONfAq DnZd<¾NγwbcV*;=r;r:>@>\3rrr=Vt֡=.<ZqfW=|9:`wOY}t;2'$ȖxgbsN:Lh ž =X%VN'=\lnҾʖ#E_>Ў[5;R6Bw=޿b? nzߓv;~#& #>v TTDU=ND>%)>ñ/sT^i7>l^>A~*0><ǨwAJgrv0's>E>cX\=0lDAf~=>L9'ԾC'$iBN>;ͽ0D=<Ĭ<ӂ^\>𙿈Zɿ+D-A=Bmξ B>eN+>~ĤH˽½>Fx>Ml= qn>+b>51U6W;B9`VK/'TCPMf*许3I8_~?Nc%wƒM׵?[>oغ2??QD><tU<,Ov qշ cW>uRlLWSE]1Q!>?b,Z>d%Hi>$ۿVp]1hZ=ې :!!P%}?<`m>=Pe !WNʿVMt<^=ZG1 =~!>>w*p =pv !׿I>i}>q-Fa*N/W6hM ?1'>'k<-ڽJhB=U=ٙ0fVP**> 1j3:l>N5ƿ1tGVN1818־-> H>>wrA/T";2ʽ^?ꐴ%Ti>2pP7_&l?ƅ0v>5ܼf=&<IÿҚ}=kn{=7:3*^N=7a>-@%O59N޾OD=>$fy+>Цɾf?msP> 0"&?2T>s~E8G?XyL>󺾐*=>xb'>½վNn>wTL=;޾ M?; 9OO{>uξ>orоݎɾPsȼ8žH&$Q$l!`:T|0-&t~J=w=ZB?R?>/{WT?V=M;? 4 Ŀ/t?}D A>I7=l=g;=S=)X?[>`xE`RPf9S=uȿ U?uu'?O>W&NnnM >@tE2!-b ?u>!,:4':>*ZP>k[k ڿ%l >2Af)=4("KSe>rC4N0^ +Z>T &=u["BS|>?mTA=/) Կ^9'8U%; :_>4S,2h^{>GǾ6\p~s*|Bqov>Dd>of|;=hV~"Oc D$濞l 9Pn 7>!MłH䊽aڿ8>/rm=짾,ITer >}!^$-?Zh=8ҿ#}&R#Lb1E?@W>GIRST`0j? {>ebm*1ҕ>ë}\a177@pl=vĿoοDx" z*=K^s?ey>i.8?7od`hQ>Ra&n_H~=D7<9ᅣ< R2=i)$g0D~=>}> m0xg,sO+F=4~0DuV⿍^|Ȱھ= gp.ڽX#l;?oAl3>>>>`,M?">gu=#`=ڽM5?+J^>\HVg"c >ɛB̾BQ1>d>+sLս 4r i;7ᾟ2{]F QE xE_G췿! go@G){#(i:>@1= AᅵAP%,;1Ce50n?>Z ?&ȴ 0S;>W?: =;iprI~G.>? WXeR߅ABa>!> 諭+{<裿!=(>%?9K Oh7#S> II8BĂV?)>,ĵݾO6i>G>L4j#:Ȯ$Z>??! b==h>M>MœlSSNF>2=ns~Emf^ D%KӑLh?yO'Ѣ><#::u?Dx>>n++>;>q>h5nSD?Cg_?>O'Ͻ;> K >73>(j۽WG?c Fޤ>> #ݾriٯ?azŌ>`#>!Em p^?pVֿ>c> ?o;ag;}?Z>"xKWYVBW?]&=NnQο2?㿎К>;`ꞿJ N?uq'<8=(CͿ4?kj wbTֿQ?"> >qHg?.>L!<WhQ ?E=]> v"A^?hB<ՆD?W*`t!T?cN,=z R3 ῗ2@y?ि =~ts [ٿ!?r~U>p6'?>Q>Rſ@?jW8>ρb?@=rD-?쳁P>O? ˫v}z?ܿP4>? ޼ۿe?Z >-,>G!#?R>|>s??a=f>n=B?%.>yF>3=lomE?ր$W>>1@ Nc?릃l¤> >`@}zF?%v">!Y=H?@셿h>A>r8-S>4>TD=!G7?+PeCCJ9>SאQv)۾S?L>)&ȿ>H?u>>F0??>V{_ΣQ;& ?(a=&? wu Z?6<5E>NU?i?,^4rFL࿸R??ƽX> ?>va辨E?cx^& 9n?V?:Y̿gj0?T~/6Ŀ64~?b4۽HT~DxS=uL?>eg/?j8Nn>8 `?~@Q!GZPz"S?>D;r?D5?|xKJPсE~C$?5+þw?-1>}?Z~!,?k;>~?Lڌ+֕?5x)f>p-?IQ!8cq 1wlY^F>V6)MҾ??jrdc*Ml]=\?Z&sI?=| >7?7ǤDxgӾ?Z=!ɿwrPTV >.X{cp _ZPa?~i]:A, >j/Ïl)hzkK?xڲ?<q+?iSDHIO~Tx?^N~2T)a>w*r01>g>',=ܾ-D߿9ؾg+ڗwh࿣qg>1; t̋~m?z>au~lӾئ|xM ?S=_ᰫ>W=?1tè?>N8?#>ִ.[C֫Oa?,Y! CF?U>> >g._s?FF>f#>>rm\\Cx=.>rb7PN>BH/Q3]>f>LM^_^}>y? (+uYkY О>i>,DRgB f>]>ҿUƠra&>M?/~o9bL>39 =' 3>> F ?#>k?'xh=eI\l>?( m4AxY_ײ7u?*z>?冾ERMb{>z?E3YbfE ?v:¿X/e'ȿ~?#2#js>!>'ٿIp >ң? #F=5¾w3# c>EF?y<ݾyUJ3=F=ӝ?:/t\ )BV>:=?7 ?PAD_?AbF'<=Y?Ǵ'jy8g>gj?I5s*\7l7m?y#?I> 2|a\!?X o?`>ު\?0!>C Ĝ0bT ?n?=@n/>В%?N>Dg5I>*=}?4E Q"a8P8Gܐ$?c>A=/sfl?.K>䎊>U6o>`?Z3Ъ"? .>>qL?Ͼ\S>/>>@}?fRh4>KDU&Jxu;a=ΖP_. '=ʹHT0 xFXbBJ+uՀ(G)PGt^pXþl;1F_G<`WU/>2Kg. fdB~B>P*޸yʾ2?I@>kM5ɤʾs=ṰXeW6*c9%>cI>/"x•O=ʬ>rf2⵿Zv>g)43X$VM>'Z * =S u>ecw' =6?XD>%#Fȿg??I?4\@?;?@:>/>Zlß >*#~Y0{?=13.M>r@ѿ8(H%ῤ竿REuu?">P߻g?`2=>R?yJJRiZ)A#Ei>u? >L6WO>48R}?U›5$)>1p:KW `[ x)Zume0'&H%5vZSGE.ܾ0aEK@AվS{QPk Lӿ Կ}8C)ɽS>=\|o_=BJ'n u]'?/>x??? 1">qWu> z1&cq?v`>3#??O? fpD=6ί VaQB?Z*N?6?KX^j:>V`?"UL>8>>to=TQ?!1D?Ԣw?K PoB?!O?>h<:ľ ?@z? (?.cO( T7?u?M?\Ҿ * H<^C>g??-LDܷQVѳ?1?:?ӻ>@R1\0v0? ?’6? ^8DXȾe"?]?2?tALE>k?>*|>}luA"=>n2^=룇>>B=t;,_=#>*9>?=ˊkf:^?l?SN?Mrm6U=v>=vom^1u>@!?&>i>Nkh+>>6>"@<v[@+9=y>#p%I098>Ҽ** &ȺP@>LIʿ]$m"0>#OH\%=bNY~'>ᠾt 2G2=%=>;>!5>T8u1 =GC ?t??yo=ì ? ??g8אsT: ?̧??ZE(q<>2=Z:Hw>W R =P=n*= sfGx?=(O x>6jIu8>r2:x][>4r|$OsaY>=PcZ=L1wu$VQ{NhF.M?u?/?t5ݥ ><FǗH= =s>>|ݿj)XO?Ŝ?k?˷(Ƕ=~?hI??d>?)?:@yf=f>ek>&K] ==>ѻ>@ 4 [Xߐ`=?|>Q>aо֫z?dh>Z?e?-0?3rf>7?>?K?́Z@H=7>a]O]/b?{%9?Z,P?>K|=M==h@> ӉTr?? [R?{?wB ?R?zJ@ +m `=TM?$>?gncAB=+>=P?>ph8<御?7>;?G?79C?Ò??eO=%h?T>c?w/Ux>=?[K?>,?4_[>e>[?;X>HA>:>> 1>V?'y7m>WP>)'gTzf57="?`;>5?0Q?a#?b/P@?[>>>??D"!?xl?^$KKU?@l@Hky<>~?Z?dc?|C=?4>^?_"%>1Q>g>> =>>}<>s>,7%?A@?ý@*d?=?$?i+i?U."a1?-s?`D+ $?A ?eҀ?wphh;+?7z?"Ihu&=?-_̾b:? ,>>J>G?C<?41?[->TX?C^?|3? 2Ln?-{?{- ?x*>?P,?s:4?<gB_>s>>#V>C?FE?Bb?YK9?X*?b>?s|7?Ƌ5?B{f<5?IAپ{?!w {Q?Xjz?1~4E?߾,E?pļ2#?`ƾZ?KX?-j{+0?fE?ˮ? ?x ?x ?Ò\?>O?@ =ǯ!<܃*~=joQِ=R71>(L>ka 'CCe><Q6 >^)9+n#>D,+qv.l>;Lh?FxO?J Pʾ؆?U> ?}d>nc">Aa??hҨ?v?D 7? 2?>> ? ?1J |>}$f0 _Df? O'ޠ]p>oYIo>??s f?&*@!2ʽx>HNKs?}?#20#{|3X>Y-3U Qac?a\?-'?z?,,+o>ž=i#X!5W.*^>UtjG$=I!y=O==+>O辂` >al>>͒? ?O>>vB>˳ ?*>Vq>>s>Q>2=Z>'=9=#X*>JT}?!u? (1o=TKwT >?u`P<>!u>>EAtL> ^5>f>>>c>ԑ>W>o?io>5>>8?IA==ˮv>g9?gc9'1_a$==E>s 0 =,>P?]GVX>>5ƾ"2D: ?>yR{>l꯾T&x\5ν' G?Qz7%?|LG?BBBB|9 =>*P,qsoRvpEU'B)U [CO$H?RDcP$k>>x>"7>b>%=>H=1 >y4 oxfwe-⽸゙?y3*gCw f?TJ@Oѷt^ WE W=F=,hY=ߛi *=Op5Ր:JVN=:<=T=L>?v+ `=F zJI:h;퀡֧&Se7/Spk1-ضV? W8!a=y_=ċS?؄0z>!tiRm> B?Gy>8dy >=+0?59%ߨ?@OͫK*y潥ھAЅ}Ыo/AΣ_=X.zݾE | ?[B$4 >]>S>9>]9?Uྒྷ6;!wþ()Ơڌڽ6]?B#Q>9=r=j>?~i}0>-er4(="Sp(>?>4>$Gþ!+`(=iJ?c?4?^>X >bX>3fI>mnQ>,jƀ>js>.q~>k'w=0?G?x>N??8?Ew >N{/@B§?/-Pe$ ފ/sɽl>P>1S=R<#!;1 >}?eIߊ=???~i=9?mW&? 1?K!J=??@m?@Bq(A@Y?5x,OB- E>|?z9?Y,>l?>?<ssZB>>/>!V?=3=$Fj=!?] @l=MM>= oT> ^= Sv>=S>wPE'Sw rz>>mҽ?Q"b% >t:>R?#̎١>\?> ?hN> m?/3"??TPBU JI>&l?j ˿͑>?#V?$?/ w'=T=o.G)7;>>E>e5,0;#=~>ru>JQhAþHK><)|>!0%B}>??ɛ?#?pǿ)|E>*>}?/ 3? 88?.4=ؾF|j׾IVa>[p&?5?S?&WNEU?'P?s8>87TxG#h>?$=ՀgLeKoeC1>r?<->¿%h ('u==&-?B?1C9?mh@oY=???4?yJ(BG!g#=p>QE =|`=˾NPEo>K?4?~)>v>8c=Շ׿?<`QVĠ>uh=D( Xó?l P@>H,o9_Q bL=>Z?'C?>$~Ws=$> ?H?H5 _c>EW?'`?y??}C>K1K^1wmn/=Y? z?@+?r'S??v?\b?Prz,ӿVt|>?(?[?Sq޽0]?+?pEV?n:-rT=?'?Z;?ۂ`_? d?1޽rK>qe?th?c>~n=T?T?W ?~? cAJ'>>G鿘sj>;3^?.l?9?KM_>T?PM@NfD=nI'p=uf=7t9\>0? ?P q(Jr?Q??a~=u>eLa6Y ">\P_>ufxiދvP'n=; . >>p<^9M>_k>,Rt<?4fM?Eא6p>R?:N =B1H4t>vx3оZmC _>9wBX#ݾ11@z> ^He@-JK}Fu> >v>qDLэ>4-b>>ː$=*⾒J>Ȃ?y: JtEe=?QA?`8 qpz.R=H?O?^5Po5< >?.M29>Q9>LV?OY/TLϵ=һ=`>0{ƕʾ>l>?JhyFFx>ɾR>ѳ>z,VZx F= ~>2y)ԗ>j>v?"+²Jr>}><0>:bUaݠ=i׊ɾ᤾V= 7@T Qk=wSkG>䆾>d0>;pl>0"SW޵? 3Y-pr٥~ ܐ| ٥܃MV.>Lf ? y? qZq0ľ}=>i9#8=!Yj վ)Ҧ_使I>P܌?p&? *Q ($ᬾV. Xھ4ǂԾtx]J=!.=%[>-Ad?= >$>ҵ@m }'j0">>0G>?/¿dc?O>0N?5?=3Dy^,ͽkn$(_ ۾M K=jqX xu@e,u=zϿ^ K&]>zG>X> >qϗJ>??eTCgL>=?S?c F(ؼ#~?Fr2?*dƾ=B?j?( Қt\>??u֌o{)=wn03G=3k]J@ /mz/>>h+_ N^=+0/p>],"ͿɾE|>ý>Ns9 I[sG>,0)?}о[~ >߾7YBo&P&ިͯ?(>--dg=~=?,is?/={9<)q} ={<_??,\_׷n2*,?"Q>:]bTT=Ij?>P? r>m=mU?Z ?laȿ~M>> G,? H?2Ai@=Uma? d?p7)ŋ3=H*>̹>1l|=ʆb\>>ij>g6~ 4;? ^>*xڔ:긾ɶ>V=ئ㟽߾G==RVZ>)6(إjxZվ? ؾN@^{ >Mkf>}?jC5?pN8d̟)!u>g:cͅ, >e7u6asǓ>>?/?,mX{<ͽ5q]= iR=t%>7.긾,QV>>|"~}py1D>*>:WⲽK=T>d>i>(K>d=q_ྫN>;yg+=Y} P5=w~ *.|>z?^}Қ`5=8&d}cپ.˽8=NB\/ӢpTu79>V >?ñxY .<={>Nֻ>-8ˎ>Cw\>qJ6-^t?BbAU>=>GhL2 0? 3=>E8&ܾ~^rڿ@g2?>>D_7 T>3z>? 'Ho=ClξuWz?$[[Y>Wey?|N>;Ta> 3aݾ#>r fM>Cj> Y>j'a?*ez>JIҿ6)t@>zsa>< LڿZ{.U>j!dSXPVM7]>& ȿA1҅BOW. =9 йVH$Wɛ#Z=ތH2'm3'U>Gqx=_c;tb=o>j@E=A>.tm>Q1 ̽9`@a]ڽ>>Toe #>-?37?6If*TV>b?'8?B^{C9q;>S=,f<'>տ_lUaz:_F=9?T>hf>vCv7z'fsgz>yp>*Xic<彪m>^>4΁$l>6$ w:m~6>߿7r$-͢k7~O>ӌT>?1%E:=1Ë5GB?!GG> l Jǿ&D15$>=>VG:vYUp=4K >᤿y- 0LJBdRc2CY>)o*(⠾P=zVD@Bex:>V߃>rDHJjr>AW>5i@;X]>ɟ>,>j'--o=c;s>2>X*?Ԭ= 潭;xiӾ 1Y0>"?% }Of=>\_'YC >?q Kx*>77(lBnQ$/=R,RI]2O x ȗ<.zQ3Gؾ"=~ >J>t?7y>G@>c>z>s?=9R>eL>'[>ې>>QY-=+0/Fm1?+9;I&=jo eK#>)Omqu]b[9=cv2uwV7k"l=8zѿ~,Zr//M.ؾz<֣{l0XNH?tGJ>,侅+wO%}%0Hn~>x}EuQLf<Co|c>.G㊾٢@J= ><>y!=9!.)wu=9<>K>-8=o>X>Fi>ؾ!˿,?e=Gb?_4w`͚?FI ?0Q/ ({> NM=H{(2< 0q^>N??N0cTi=ϧ>L>81).ùCf>H?t2?(?,"p>Ͼ|í:#ݿ}_+d\d(bӾZɾ#>zL3Iuu0i'_=V*^a|Oz(x?!9=K l+>ϸJ׺>&`(p\CK>m|cq~6HdL>MrudsP!-8fN2M-2t ԾReVһ@3(PS4 ">x%]}BᬿLL=XyqeB1P>tQ R¿,^O]p>+k}=Œ1AR+6>f?>*=Oa>lck> >&J4>ɾ ӽ+$m?SQ? о?nm1=VK: >Qcg}y!P8A=\:>&.<2'?=̒?%p(sd?>˅ W?Dÿs>KP>y?wſ;X?9K{eÿ替(_?Tc|? ?>ѿ=ѿB>/QF M]>г P>vμ˾{ >?] ->WS-,N e?ÿ&c?$AN#?Tu۬.?*I&?uC/'>Ա +Z6Tbs>bsgMWW>v:cDC><}[U&=aI&xp!>3UGg{U+~@)cC=.| ~ZpmS0JbUL14Zq?>PѷSF3<a?=lHà6$>@s=dN 'ٙ'<fF>zȣ.yy1YWt%3G=?(x'\=!@D 鿠(U A;I>߃{志_2[Ҁ=Ϋ bs?L*> 9"BO.#=&hu>>D ݹ /#9'c> ?LV?=gU&M9=ڧ ۿ6 (Cw=goe~ÿ""#L2W>iv6?NHܱF=,.,53эnHM}ZK +ǿj>nq>(h,MZ 8^#jϾw:aP;I*h<>1oa+N=g?,JLQ۽h#LB%!G] njҿ4KU#:Y8GNL 5=} pNƿ4Z'5Uš{Iuq)EjТ .g48>{S> .^Zy>\> :E!޽u>/Rv>>uKbx?Hu>n-b)5&`>4>8"9q h& w޿?& ?D/<>=6r{/ƤC dZͿyo5#=y/+r*bO󾜉5n߿EJY[#5߿^lE)_H? ->QRn#~-,N>ſ %5I?_~|>iT">T( |/Q?:H>V>]Pjx ?/Y޿=?PcEz>{*E=HЉM^W=׿x'+?ŋr]gJ?ȿ"K=*1baBP?@)ῙD>@6zbQ? >Y>I"?Y`i>'(p;? >aȿ?F`M#>R<>B 1ơ@?*|Y>Tv?X ÿ` ?{??|lvΉ?]@>B>Ъ;~1?[>/?.rfW?>>2F]}+?\u0>>?!?棃>n>ZTm?{9>|r\>Cn8>)=oeis=|?(뾎-_}?#/= FǾP>Q;m==*~$bLRƆ8 [%>=z23r=}>s=,?V>2?=)E2l;([>%aF"j¿W"nY?@Pti;`i\?`*>f8F ?3f>N恈S(Ɠʧ?oڶ>uHP[ڿ>2>pXV >Ց>_t>&;io ҽ-?)OWh>vѽ>)RZP?%W=>nE?;!I߾g?O@*H^CYz>?撿D:6'?d>+# y:\D \7 ?u>21(a;䂾Y?HC\Kf>J>?tT=s Ŀn/@=I?/=VUEB/> +?r&H6P>8`?b#Ŀ-r?z&>i?ms hy򿎈?9:`>3V#z*0V?=8ǿrlW#E?mN rԿ9R MTu_9'hZi)Kw?e^D˿QR->& ?Uν8k4 \=؇f?=fc;>4|?TP>tm|Tz? >?m ?fSe>?s>?>?>&tlkz?{0׽5Y1B3fྦ?[ 5ET(?y[654h/ƏBn?RJhwg4G?=CR1??*=% Ӡb ?Œ<\h壾`?;Dń+x Xa?%Bi+ ?f=֘x?\6z=13VCP\1הlx?>rA>őR ?%82ϒB?3>B_&?6&>H:_B?#e>\!?I(JvqD9=S߿f=m?V~1=JؾU?E?} xO=Z>αzcF? N>w/w>:Hs?bR˴|?>tPD1Ip?i>(4A5|>9*ҿC5䇘ġ?L=di׾ҿz ٣?hYS>y%)?$ 7>0?Pc?'7v?Nt>?t>ڿ#f?c*n>>>(ؿY*A?fw>V>@>^W*L'>..=C;e|ySO<>~@lT ]][N#|U=dcw?(K ӕ>GNf?J0_Կ 9v=>> zstfdf>? )qjƾ)>t>߿2ڽԣwu>St6>mDH^Ŀ,> >4? R=7,R i$??@N׾ܾ ]gٝ/??T; Wo.ßw>⢡?)p*=>ɠ?L '>}Y?p<o&R>I?q=Z] J> >ύRE߹iU$=վ >D`S(^=KD-b>a@&du=*? lv:HRTfN{?5?~ \PHK^>?E< \??pLLbC^n߾J?y?Ҿ4_O ??zNL+?O>R>nr?TcA>gEW>Z p.?!.|98P$O>NK˾?Cz ; '?aw>v=bbͫ??>cvD_Խk?Z>&=>&?@=~ g=?SG>f=*? 3E">>]ܥ?q^?9K;L>8>M?ʽJx >=Մ5>ux?+K>D柽(A>?Y>3=Ξd=2[?fh+>ְ2>1۽qq?6 G4>>.s?U U>䭛3rlD.x?Aq >s8qG:\Mk?l=,)?P==bW|9mĒ>拠/M=:/'> n?E>v>)U.X?3H +>?.:?U>U'?}J)>??9=?3VT14>? ́?=?b1!&>>?:(о ??=C^;C?s>c=:I=01x;E=:ɿPT:JDěS>`Ծk[@Ę)1>C`x,!vUn|=U1DC#dUR>C 04 \>>3썾A[y \>>>,ȼp K>oz?cA> g=w:?2k@ >^ >B=QS??>Ԥ+> c5?(w?!>*?*| > >`ZJ#24^>J<3P#3߿2E&:zqXI@!+7ٙV\ ,2Ra?PѾmlr_=y[?zP>->>TE< ?•}?غ? >x=xA%> $υ?=U=KM1=3j\)(Gf=0jfW>#h_ܜ? =*I@7LѽŘ[>s۾l'?b pg>*S ̿1,d >,?~Y?O/>3FFr n/>׿>gI-\t R 5">?=;>L> &> Qn?T'?b>_ 5 ` =Z?9r6>)>K"?;W>Q? >r2=s7.p@5X> );皮Ns6?w?Y-?uk@3.?qq?Ud?^W?u>޺?3?)>],JD?;|?[=D_~#4ƨ;2ׄ\˿<%Ͼ?,T>$=%nAU?Q> >Mq5xTҿLOxc?0@:?Ő~>`f9=[p ZJ-? &xN>_ڿWgz>>lsWWG?k\}D>>kKA3< >o=x>!?-w? F>d=KI? ?3/?:jN➽`*@p3<B;ּkf>?˴>\@R.pa ?YS?{?m[3?Sz?z?bٰLq??u^l?xmX9v(4??o ?3OվDN>ahcZkT$hg'>^[Ƚ$n:D8 =b0m{B<ջ>0@?[>[TͿ1?u?1?nI>dW?A?dĜ?c,bhJ|=r?b?]W?YZ=r67wQk(`=%ڝ һHe">'IOVPr?X?bt:?m$ox?"?9*?`ttc=o\)?{??}eTY`ۿ?i?m?Sy -D<>O>X=LvBN1<>p=Oh 1C=ׇ?>>L; =[`\3l>8lf>Q'CnQ4 ?N= >LtzIz=4>5nHz*EQ{>-f K0:x }=ԫL{q;#EGR=/4>0Kr@ȿQO?xA@?ynmJ?h??vlL־4z???ryK:?N@?z:?=fz=+=6;M@"_`V=^ϾԬmG4/=kE>z}Sv=膾1xݽ/?X??f8Q}1?mn?Gm?콉?xx?T?@\Z_m?L7?%t?#~<??y?D 8%٥8+{>>6*$HU?>zڽ˒gUD,T>E?/?$ÿ> ?Ժk?4&4m=x?{??nx4??ߜ?80b0>(t>9^>Yh`j>1E>.>#%?b~=?? _ >?=?w@ nH=f??`?ܐ/:%=i??j?Ü~o>P??z?pov=S ?p><?@mD?dY?*??GH?^=?9>>60f?Qn&;UN%u?/LӾ!ῥ ?7[;.> N?v6?쟛=\>'> xLU=)>| =1M'A~=?>h>%? }=D??63>}?.j>VnD?i?b?6H?!{~O>+6?G]?\@?)P?;)_=T?QSH>3>?S x>w?ff?? ?{!?`a1+W??4$@?fT= 1?0Y?L ?T~$=< ?'{>P> "<?,b >>OJV>>`>i4?F|b>`?S?4+?0/ ?J!?>L?!?'=R"?N>L? { ?V:=j>SŽR>tbAG>m?`>?PeA,>T?ST>N?ck>Gj>T&>>!>$= :?b?nT?npBt>?u>y?*<>Z>%>A>>?c>w?1? ] C=>4?Eg?y?}]> C=>yy>X>x+>=G>H>>6?(х~@>?5?+b0?^d;^>? !B?r?Hn(P\vN?Gxo]>1>5N<S=B4">9?%Io?N?%J?ו9i?h?W ?x=Em]?{RT?eb?[z Xs>A===>fP=q==>%?T#1?H?w{4[=>`,>d? 2 ? s ́ ? R3ѩa?4㓿`|є!?N?\l?`?Ö)fǾ3j???X<䴾Lao>-iJ˾L\>Q;4߿Lw=g?'̿ DZ?CJ4҆迳Vx?3?X?Z@??r?r.Ȭ?{?8Y?W>Z?CHоk?=>?םc(^5?O?rT<<?g; ?>\ѫp~? t?(˽|I?:u?/g9?ċ? N;>/?i'y? D?ũ4ox?8=4?Z9? H?^V?%Vb?3b`DM?-辎]:?41`,wW>k'P?~JLNr.?5Vh1` O>@>Ϟ?1g1>Ǘ>p?a ^(H>=˾@kƾ3nciB>?d8v=_>f@?䀪=/5,y>x= y¾o`=סz=.璽<>6">ᄄ=Fxe>1= ;~>5 &8K==|N=>`=C?Ҟ?2M?as_= ->5=>K f:???"?.^[?BD}U=dZ >e|TG[Ey x>!mc91h*B k`0i=GD,9G&J8> =m>KQb?xRU? Y|?FܿP@=0=+d#5:5aH?E6zX=qG>k־W޽H>%徸 jAx@Q=dkCBB;=~7߾nƃ _i27d,>Gp{B = &IǾǽ,?~F `?mH?qCx?gc%WP?AsZi%C=;T=[JTa>82>$1k0:Uwnv꾯6a eW޾[lqNj?qJ>B Bm?b3>DIνd9>v?Yw?x{$F?DF>@>l, I\[=?KnK'>>YC>`T>?V>-:X$F;>+>j?b|dhY04&up?MŇ)?9[F2?),L4u>):0 +>)1>U??,rLZ>6!<=3>v9?SOIP>X>t>=kxh>?C9_=>m~>7g >Š?]>>Yq޽?o?o??aJ>I >[>Q?a>^>mS>z5fsp>M#BMM>g|X>MY?=._?'a?B9΍? Ji7>?n<>n}8> C@E=>{G( (]u\>>HF~l>c>ɪ//;U>>>?>??2Zo?=+?y>{?E?=l?\e?? > ?E>f?dc|(>=L'O𾞟>>w?Wkh1iY=w=ӕ=_5>r=+C[><^t4_?Ȩa? ^>H0>'1>C1?EnB=*>9=B<>'I$&SH+>nK>B>>D=v)="*,= K>=\=O󶾇pd{?Iu>YYrXpT}=V=IU=az`J;`Ƶ>ាj?"E=*>0%7P?hGw>[>j>ceE> ;7>t=>$Q !W==ޙ齻-)%I2={[q:@%8<\q>'>?}=M07< |=^.>fU}mP| s޾eS>2z3Qi =.U+?v(xE0>f~A4L~L?4c|X>Vɾfngc<>Š?+i?T2f;sf=+> ?/e?ZZTHv>f?MbGNxFl?&?iJ>UjV=g>h>٤{? ?PLEp=>?ͽn9.RHH\\?!O?n+> ?@By>P O"lٿ"O ZG?(\h?5n?%M!S^?KQ?x1?I!zg>6?-??nW?w}e>>e?Z?Q,xo=?[?1#`?K?P"wR?C?`?w<>ӊ?LN?l5>8t?;?R3 T)Lj>!}?Eke`/agA&c?((? f?޾C>yW{YOMNqCs}=}??Q@5?lU<I*k>Y?0k?W x sݺG}ؾzQ>>ɓ LHZh>82>$ڽ!>ZO>?w->Hf>|q`11eM?x?K%@^=qt>Ǹ>k)pRo>?]-?d'c?ET>s㽿BUtf><?4,?l?!5(>3<>[@,Fu>>ǯ?,لP3>zXq`c̿YF>"]?2? ?FhsyX#>2?N?LU?(>HsiؿyC>"ܿqۿf˸ga>ՑABc>To> f'qɾ)J\>3㿤G Y<+=L~(=T>ܞg<>%>>?ӑG> ^>q#>p?l>Ü;=-}|>Och>ϿBœ=%=]3\j=侂>C_>>2@BV},>R M>u>fO+k=0e?2?:i@?P'?uX# rzk>P~?f'?r*:<\k>fE?>IшO=u?Y#?f"T>K>A>Jʩ(=\+$PH-Z+>PeN>[>O>>4cu3H=7!>>q5G:8I1w>"0>=~:=`1]>ſ> _mrGs? [?(ed? *]=7h潹085ѳ1W&_g/JZ9z2dIl@ZFpſؿ^aо B FoLb|PIdl m/ᄀIvfSP⽗Z) 龂]/<C þes>ㅃ?R?Qw78(:?(?/O\Kv?T?&Խ;>?_B_(*.bL^/fܺk`f?V?Qw!L<{>.>/oS˽?K?YU8= XK?!m?-)Q]zֽȏ(췿&*^44=k?E4&g#SR̙|=F%boR, ֝>h}x>ne>O]>v?>q">t$=Y>*A6??՝L0Sk+?R?\mU? 5?6"&(MZ G -Uz=I.5K $4U\B=yD2׶ʡ=/=AWt޿pb&>$u>Tݿy.*=[ F=>5/>?_#z">:=.H?^}?i߇1s}>=>I{?k?")1m?Z`?j`}??&ټ(TG&,Ӿ=6nֿ ؾw.'<1{=ʿCp)W,J`ڽb=Y?"?/R=f{$}ÿ0. ՒR$dAۿfQ~e?SP>6Eb&Qb*>>$V Ծq<%nv =PIW? N?-'&DnQ ?}m]?@(޳h>):?h*5?+3Xރ Dͅ?(>G\|x<- Ͼ^!}pY%>@>$*$?t{?nwu>x1>-?x[l? 6پ#>Q>*?U^?.%Umrf=QT6㓿0s@{q>f=;?h2?x!+ ו,xd><?, hb=Xgwk:E_=R{-#>C>70'>@K`սPlʿϷ |>(#>f?W?up?F77õ-=> >4Z<;? >l%r UC>O>]y9aԾtt>w!>g|r9Ir>żf>#d?q޽,m>>,;-~><.4>/;>A(d8>`~SO>0A-?θ=G=P?#?:j#.H>>+?d^?}J0d=@r?(`?E[ρ5> >'l?_7?x^P=9=|?E#?bI=&xA=[A=\= лp>>m=+(Ԟ<-,XHs.#??%r==f*?7?Xh><.??.7sm=K$gmmD%kF5<%\+,48W s޿Onqe_F>ٽjw?G?)R{7qCW?2/~k> .>G>S.Y<˽?=?. 7J9s>T>V^X }#isf.xOA>o=qA3G_~>@;>?* <Ɔ_OܽD= c>9{5>Sz?-?goǿV$TOO>{龒9`T$9=lw텽>D5a>yC(Axu> nP>\վmQrmP}+?>d>u,ȝ Nz =T1۽`>>gZ1 >?k>3?8?:ZI4=H&?D>ۜ0x}ԯOW=}]D\y=ı9(쾹0<\daQ(о4' pP$Nh>㤿.2<]w%e $ TxWٙٺ=lg<;Ӏr? %3${LT"\7?#'ݿM7JO<#Ŀ>*F!>{>6vqLObszq=𳿒P5pr'=￿,Ҁ_xh3tH<yn^ >O>S\>kvhᾏž=>(<>-Gi;q>R>-=`> >F_^F>U"꿕樂ǿR=濗+T&XB=X濘h-pL};J>*>|k('kC1`_Nb1]}h@>Y t>YG='S>)]ODcN'.k1>)~3iq~UP|t⽉:w?|(Ǩ>K6=վ۾+= 0ld oJ>>TxzL*о< >N'7]*پ`>A>2yo޽S$S>p>+h3Kݾh |5LT;3_=k=|>v7> l)P1>>3DVe3(ZqX=.=j<CHe]Ihu.Mӿy1ŗf[M62pæ$/#KֿpdܿlT _ɕ>7E{Aܿ'΅J6A>->-zY^=H[6Pvd?W9>*ܿ!tSni?7@pL>"zKu*Ic#a f8g𾩹Ŕ=Û?* r>sq˞>sa>x4v͎o>b>h?? >kͽ p>8M=Ǩ=*;=z=ދɶˣq2>/>|" n߾Ŧ@<2>>h:Xz>@>wID&從kL>`g>ei8Of.>lyx>BlA*=蒫=Z?;?i>HW* AJO>ɗ>I^>t tOAS 2A̾:?>jN>yeoI6ƾ_v= >Rn>^`> >=>F ?w5;=Ҿh<ߘ?m.bJ==St_辐=6B>iˠ1dؿ?7"?R >RW=& >*!P>D}>>fS=Г=B 1>> %/ )_=U>">ą^h1zտ*e>,ݔ>>NH>>>O>>>E?)Lvg"T_c'>.sSC nne?b?>FLǿM)Y?}CA__>QzF%-Wi?YJ8>%QP7/yٿAF?OyE=KIQ]Ey\<>gI=H xOA?~˜>꼿X,?㟿ǀ>`!1cV?t:CȾ>b >1K>* AN>Hؿ{g(GR>H8 y J|6%qGe=xܿAl/;!F;=DAl/~^/-E`&õ?tǎ>Z8? >Ȱ"Ht>6I7l'>uѿB@꿄壿g*(v= ,B9#d~1*= *<#=W`9ڡ o v!eA -0@1=>!h;VʗBܾ¾mI?GC >vþ]8?O$={Ij= R ?.>cAB$?0̛>y f}?X̳>R} W\Y.P*|>85pPAhe>C̿!;iF43<kB/ڞ94w>f>J=wFSP!% ?>"PP?5>Dɿ z8?>; [>bԿC( >M4/>'ȿJJDS=u=ɾ &N75(" < _ |Q$~>64=->g>E$_9˿I>H>y B?¿ >LnQ>o¿NJ>݋ЪT?&t?̾lրLϾ񿾰uC>+k(傿">pSr<R>choQ=8`'k b'?@쫬>qžyO/¿E Z<H>NL>?u:w>"L?ɼ>&ù~$O|?%>oV= 濙0>u>o(lf{gtV.>C@>MMEwvkVJ>k>˿-þ١7uϾMԄ>n61ruw꯾*?2f<[>! y#aB~?ߚJ;4kW+>.? i3Vm3TC3R"=kU˴23##3>0}NP׾JW.=o F~Ⱦ|{̾?L .>,à.ֿ+GBA>$?4oa 7$P=8$4>#6¾8e`>,>CR"yb#\;`M)!2'"$<\p ȿ\ph?Q>#<3 lMU>Rh>>y/2龂,߿ }-,p×ݾ翮3ο'=.qi)o=EZدOL6i2` D"ӿ\|zj>mT@+Ŀ.K&PKdRտLj=/$̻㿁6οR =c:I&< >6>0VqxW?p;Ӆ> FzCIf8?oy>!AcI4?s;Lhg{⑆>B?Y>p 9X>p>tJOʿJۿz{C=0>A cY.9=χ'֝%> #[#࿥/#.矾'+ |濋Q>VwNʿ.a 9`=k)`{'r\A˼veksu0>yʎ> >N4mrK4#B=t^>2rTO{_辫ྷzܿ ?t>Zh= <}?v >Lj>ͽJ RBn&'~Sj H>e>G.\˼=3^=qT/Я%~>ޥyHOL黥?%u6or?6~:=\-qs?r= Rz{?R:{>]>pſ-m(>{?꿝lϦ?xKAc@r3>3iw󾩿˿?wd >0={6?=>C?;`=ῥ'?->>E?`hVq>b? '?)=iS>8?g?9>(X? %վ=$??&>>Iyd'T?㿄>Q? ̄?? Κ>:^>5Tl2k+nƼ?ʆ>^W]7?z=֙>TXWs@п?dQD>@2?\e>׭K p?zD?)̸k<,=LlU~?\Q>:^5>; z4?y>IE?iG9>I?oi<$ÿz?dc(>w?9>&?WĠR,=0̼ \Zʼ=:i俺zc,==jǽ@@Lp ?3Z=Xe K%\?/d9=fep ծ<ȧ>1lp@뿑ᠾ?s>ҿ ?#8p>E#?:=!0xл2Ϳ =_|>#2j2]?E&?Y>f`i׿h?> 6a@?W??]=k#}|Pi?C~,>=9T =B[>R-?í#D5^A>P^?^!5`ȿ2; ?(M=$ekK ȿH)?k#VO7=ži֮?=n[q ?9PDyAWs=.?'9̏ ݾR 0=,?u-57U;=?8pmM7=.5=9md^9޿u6$?=Y\kUq.if?<= NzVAlj/?._'L?n}m B>=S>,ؾ޿3\^6HT>K6?T3 ~Rj? ;y<+`k?HᄎTſb{װ?ǎ?N/CQ-5 ?WfԿUT3pR? cS?Y>$B>i|?]>*@>q\d67Vf?wi)6$c?gO4M ݬw=Tj?uVEBgAY<>HTr&>&>Ev>mR;Z꿐j?"= >>>V%cct&L[:?gM8+?&8 *=>--y 5Y>Ӿ;D\y?0I>\?(ؾj@?8G>k>c>pοI:H FW&>e׈>ad/C =(>M>0q|RFb'n>:>8qaoCB{pm{pb}lC-~\$XGK=s轢ƾ&WL=Ggͽ<>'οvcP)>`>_pOG09{>;[>-'> loz<>B3>p$>D^y8t2Lw@k=KJ{ω4\/1=94EF˫Nb?jF28??O rzP߾r>cR>ſt'Oqe>aV>a?J>U&L>? 5KտPF>0>X@l'YCb_=ę>S H8*I=y>n龓MIC&?9_zc>Հ=?D,0>Z(>?<;?4u[<a>>2x?Z3a\a(>jf? vD$Md\>D9X>?wQ6f.<\>5?*q [k==?(z:1_9`xQOԽ4^>9&Cg>N;ֻ<>NFR^Ariɿhcebxr=v\6t@ =,> 9iOn~@>>Lbߵ?40d?>?K?d4dC1??xz`{Ao=켌ma?'/VNHor,=8C>,??4Ź1p~ l $%>"S?6C2g5vo>ܴ?Q{[beԦ@?2~?z)p˾}V`->[BykaȾ>Xy?8܇-t"=Gغp>ɖ|˾ N<ֿfE1TB-MEc Z0L=ͻZjÇ_Mv yu<&lZտjli?o >~Z{;Z?9&Y$>/s>??Rg 63YNs.E>}Ƚ:ق\|ݿ_?(K>UB&\ƿe.˾?!>0e[X!(][:mr>(: :{ ~辉@y>dG[ ~ཾ>>ݜ}IId"`v6>5ҽK k>>-?OK>βJ=87e .>'B>"`<] mf>,?ٙ>dT=f'?>>GxZ Bf4Gڿ>Ȼx00v]F>a{پ ,5"]V־a>/Pj>8pPC{>}AI%x*V/?&ڡ>EZ {&D_Ȱ>xV )}$??>|eFk}>0ꧾCc#?3 <p˿- >J>d=Bp? FbP?<6iB(\_1(j?4<>a55)xE-><-:`b@tds3?*#[>8omnѾe?.|>>kfR,>/=d5i 9<>>?*I2r?i!)>5>:& TF'?>M=ܝ?olD%^N>2WUOJxRp)JJR̿*>w-t= BŠ>4a)/ƒ4ؾg=ZѾQUѦ,X0I{c jlck? />th?#%;>4z=7ؾ=>X2?Vf>^ $>2r>?L?P>c|?- ?&>)D,7Yh=? !S+,>D6?*+RRa#LϾM?%b|?> h1?T??;m2VBB?e)?0?e1+ž^G?jI?6a?VFLFԿ1j?ea|8JKؐ> 彾_{I9@K>?0\ɧFly?QT>h|HlƲ'm?hI?%K8>m6,L7L ?}=Z1!OJZ?^l?q>-XIF^QX8(\"P[)uVZkS.axاlnCθѿ]l1bn<^ɾ}C?%?o>3*ۿ͸Q?Sk?ț>}㾾!uMɡ4?U? D(>+=>k >?2>h=?y@">6YK?>v=q??$v>0>j=dTe?P*>*ȣ?9>J>~b* #?q??.y"̾bo?C?? gh/ھ> t?>SAja(5EY>?>t}AJ@.0>C?Š>K`>Bs,ھ>~1ˊ X8.ᦾ>*Jq2_7~_J˿?t7Lw? ,>ERk &`?(D||=U "^Nƽb~?s6?3{?XcҢg??l? ?t>D]~>tj=m\?&D6ZG=0? ~>=?~|D>?=>C>ET3D;>?>>,о̞? ?63>׸o?KMw>0?>=Ru"߿ 6~??ݱ1>\KP ¾h>=?_=4޿,~t C<; ѽּ(},?p?TSԄ?'r>E=ˣ?aR)9?`1>G>hb<#RM ?X??M uƽ7I(vI`˧>4p =#?P?T.?>HeAE((%ѢAc۽sn?X??s#Beq>h+V"b]p?}3=fbf SĠqVfLdg???s;R$<ї?4?n?ktKXOM>ґ?*s?z?Z?;7jN{?b>?"msW??5?PxLN >}?u?w?{Q`=X? '>{>0nD8=#?>^<=ah*(8L=%??>04>!/QOx0ptq(Wq+ Hwt#;ۃ'5;L RtbPE?]?{?zJ=pa?>>>l[0;,3ʽ⛾ΞZd?ǽpjkҷëAOB5&(fv(BCF_#me?V@n?s <3A?D%?-?nz=v?>??%{5=???·;~t=]W?H???^˯8>P<a10>Sʾ %{-{=t?p@#?ΎXʬ=x?@U?ĹO?@M?~<m?>??6P~2AG?*?w#? -4 >E7HE+x =rпr>% _S$ȿSbs0<>ɾh3L(w>A52?%?gU? Z>n?8)k ??s? PF?5bJ?4??t`{@jb?W\?`@ M$ >v??"@\0w?o?гW??H21=߃זN M)vp=D9nHǏv{ V>>kqqb>P>-9?]?)R=]%>$d??O7>a==>4MȾf<L?? %_(y]??\?FprXEV?#?j?h!?V?Į!?O'a1=,? ?N @u!6PX*=X:I& 0r??? 0??[?t:V?i?rj? _@=T<)绞ݾ\_l=K쾪KBy/S 3{?D?y; ??]?{(Q??OY?ñup> =?? ?$ZImgw?n[?5?Ya@&@^&?Kdk?&?UWhL@k?~/?5?_1~=o?Scӽ= >{> [X)ÿ"?\lcA?e[r@O_? (>??!a><-?M?bƽ? >K>)?yȸ??R5?HI>?L?4?GZ~%3=o?um?K??6>?Mv?g!?Lf?HtK?M?v?ә_`Ϊ?^?n7?t~ a_?j ?a :?6" ?5 F?ŵ ?k 0"l?#cN!k/[o%;u??Oo+.>~>? ?&.?)? JV6??z?'@"r?m?@=ըSjF??t@l>*>?b?*#:?3?ds f?ی>z?ΰUd0?cA?9?>b >>T#>>1U?H?v>???)vGܠm >W?.?0;/?]!su?J;p=[-?B9\?-=z?#(???:͟hs@G=J?'Y%_>?3?-K?=/?k$i?.Ӿ?<=n?xŏ?_xN׾H?5?,wI?D0??YMGS>? > <?g{doq;5ſBĿ^}? cBL3O?4)^?0?W#c(?'m?5H?4;sw)?.0 ?'{|C?>,?!h7Xn [?1=?{iD>⽠G?^<*?\._Yt漩=>0Ia~?4 5X>o;/{{6CXc?94N;?0[BXGtX ?{ B?zt ?K?:?< pk;sl?S٩>Cٽ<)=5=`>i<ƀ"?B[`ϖL/d?,Z> ׿B2o/E }`Bb=3>39~Oƽ:WNs?=O4lmaπ>/¿ӳ򿹧ʿTB[9,> ڔ󿀄j+<ݾ%?S=;m?k[t _?N;?a?K܊a?`=h?sKQ& yc?*>?t,?QD [?;XTþdk?MJ4?-69(lM=Y?y<7?]_*?s?ov7?2-®Z%>ܘm?|ff>ž^>^}< Jɾf_>j{ek?Z]4?9:A?T4X2#}>>m?.&0Gom>a>u? 1 Dӿi;NHѠ)"ּM)ZăI'9ɱr>8>M{R>'i#]0';>R5?n=$(Ծ׍P5gUC?Oa\;X>>[?bROH=Q>N=0w>; =T>>?C)=m;y>xX!½־ Oa>j =Kc Ͽ$D [qE>q<=B-=ћ>lp S?خtp?ZM+p7<ėt>*=]y?C &>L4>->Kx?(P6"t>QO>+v=d> +"DH>`Ũ=`>TgPjEr4??I?hUe):>\<+ud">no3>8?tLԾb RNH](򾢭.,YX16>hgf>ܢO2H-~ı%?,>J̒?<V=井XO׽=3=g=!\>C|rĹ>#F;:>~ܝ>77Q.=|ja>Cݼ=Ki>e\> .Cؾl_ >)l4"F@-?'>?GM?v?f?i?D+?OQbLaܦ"$侑XXr"=O8ʂ^ J`?R*?e9 `?mk3 (?k8qڸ?[k]Y?Y u?I)8?8?RmNx) !|O~4IwT4KYɾ+0 DP^>㴿EQ" F9 Q4DP!B 82gQ8qݬit پ+΅?x?|gId?s?B*?8i0?-FIr!;l=T=١>-W)bRM =Tv=%)>{oMDV!GIsPWI*8CU.u_h6RlwW_{Mf'%6`=O"}<>~-;|sRxW&̇>6Ԁ픯㽘6" l㽽=O?'tEo?`?~=< ?AW? fdh>FC禽y7Jbx@U96HAr6nt0彝^&p-Ø )>!W&;O?!XP>qEq>bR??Onz?_??=C>>8>i?+нm=>׶>\?]'-=̯>rT>V?+1B=>f>POn? 6З=0>1A =:1>1K!j/=V>>2e? EX=>1>, >]>c(>mh>dIVi>~l>ioP>i Jn0H>[ &L0ŔH [<{>z>_=,]k ='-;C>P/0Ù ?C=Ф]?6/>t~?V}<ņ>W=h>0 HJ p >=o>d\=' s _l>v?G?TO<>u1IW=+=+__=<>zD0> vh>OV!;2s=K4> vٽ j>-8>!>ñ|GMgfYy >>Ce #'+(>> >46vg/+=]>3A ?3K?s?YͿoD$>G+?n?_2H?x5&'D >2d?"?a?`%j"ݼ>I x><|a-D *1?H#IO'@:x;:P 4D=ゾ}pPV*6~=_"fyD'LH(>>އ?6fK9o]4N+>xFg==*V?.I8)7dO+$>b>??ZJV83*A>}>H?EW5H7oɾkU&=C=$H? 3*e? ?R?o]8yh;>?H?r9 0eX\Du?s?sp?tX8Pco>-D>-J? !H ;!?(9?)?%1 x#>>>d?atxzv?A?@?%ӠtVD/?:*??k>kt>Y!? AN9R4==H> $ЖQGe3O=êz=_[=>Hs?F?Ti7ih2XRrC޿Gh?W;Ə=>澬q=x@qG>3)=>;?E:=[=I? fC:Տ{(=>?+JM\*`ȾK>>?GL[5* l>Y>i??F=5PuD>>?`* ½К=6=c?ڔѽ:տ[;e Va9L#FYe˝dW.S96i0T Q֦>ws1D 8;F5)x=}IC! =3>Z '͆@= ֈ(!&woa<&nzakNHG&XT`$>a|_?F=PSI@>߿&Ӧt0R}|X|Ra=d,qY>w ~^4[? 3ZP1x>o>!Z?.+F(ؽ^T7>o*\Tp\dpj=A j?)?c%?˖JD\W>? 㰾,ZN| Fᘾ=ͯ>u)T JM60>oξ@pX@L xm/Q=Ǜ(tfSH8<^>B5?8?6'9:]=}2?2d?^?0% ԕ9T ?>?G?^?QN >ǿÿ_w|p@,M?;~??vA[?#??@| ==q&??}<=? >?^Y8=GZj#7=4a~C̿}漿4gZC}=}NԶA:2^k>teᅰ*gU >P"^SMX?dL?]Y[a=?t%?? Y%A>8??$qPxu>0O=;3>->Cn'=$Jb⾣{)<@g5=%LD^N7>P׿?:f= "6־,lamm=??o/?\c6|yWO;>v3!Tǽ۱l*A>ȃTD SK>/+eˁs>P/Ա_4ʹF48Gy)=s2>>nwoJ\S>Q7?x6?)/"2>)ė><?O7=M#];?AZ:?H P=t޼?EB?L XV(=M?CJ?PtO>0o&=c?`;?gA` c=A,?L@?RN8*SLp> ?^K?e` ◽?&ak?0NQ#쾂oa>#?bֈ?k^tOj֝=K?S(?_*C>GB?m[?v%O>Ca?FS?Nw>sC ni'o\l|! i=~0e-s쾝ҿ FsjžMoT”Lk 4^ׅC.^CWS]yNRp-떾?.#?6 P!]d?? k+1ѽ4W>7v?f :c~7r?X?"AUb{^n+ 'BP=4r({f JTD['P>NK?='4U8Zb\NF*f%]߿GUǠGY.> Fg>?G?V:\<J>Q> J?>ڴ1q> V=?(?>-&n>>KnP?G?W;gsd>t~lL?3>zH5zxZ>?=n?2\?`|Խb̯?,Tz?6zfPDX鯿䏿ݿ2t j f`M=Jo#>>>=`/nV>;?#)>i>ξ{a>FtG>B=OBJ{{r><?=>BR%="H|>]>]zj>=?>d|=::,?p֖p >*$N>>E:?) <D>&>>hw>z>w?s?Bbg [7Me?:#}?I*\;[%᾵a<;~- ap;30B>0ۿ"KJBG>0.->U>i>d+?><1 t>kh>c?7Kb?||>9r=C?#t?yqo+.=о.>>g`iN佝;>0 p% 5>^ɟ3>im>.>YÇ<> R@d=U>ݺ> pxr>a[ :mƾ?>ǐ)>bPu.?> Hs?bK>Jh>>^:j>(׽C> >4.>VK>S?.M?&-"f¾,1߽"?)@5>6w1x<-?>H?|c5~r(>+,?4?@x=.>Ah?i?3G"(Ѿ>V?h ?3N==}:>qv?s:?I?)=`L+6Hؿ,kF=pv x\p=⪟:w'7\} O=l<?KcN?^SZ:ZY? y? ȸJ_x=?9U?K+O㽬qϚ?%?8C|K^i?>0+-LMM-<=x~$ >UsL>\&C;~%iL=>WT?BC?S Vl%"GE>>Iآ8LkH!)>©>0^G, k+3 >dc>dIGȗ']8>|?2l ??O.8n>@?S ?@t>@c>G.9 m ̼7Q@%C??.8v*.)?ʬ?+.{R:!)?=D59z?1?KĭKs=0y>d@>,W^%K>Kb>th?dノ5/>i>>0 Rb>X=6>xY9rV>z?S>?Hsi?6b~><Q>>U Zx>?>?8v}? _Ҽy~ܽD?O>>? &<>eTV>MQ>.=Η  s+,>r<:>>xs>< g>W>\顽'p.X!*s>\>:>( hHk> K}>M0=>:֟I>*>h`»v0??'4 Qfs W7>%??)a(=]:>">,3Y<+8 >!Xwqt=>D>Wy?h8>}0>\wJn!>|=YFXzӽ}>>a _ ?,?Qi 7]B?;V>>Cc[ *)A'~>l>tz[ju?>zѿ-1B-y>PB[1J?Kkp ,뽜K&??0{όUTUG>%?I?u7oo(=gd#]>?b?:Y U%O>">hGCVeC=>o#>Pjž5=)Jgi>X۾${p 28g>zÉ-̾Fo? υQ==$S) & >%?[9m>m?'+Ǵ1@S>?`?<.|9>кb?jj?Eh3@q?>(M>xHN. =>5>|h>ؾ))ニls*?޾M8=4;mVi+R>bX,>Vfׇj)e>6ZQ?=Sh>>>@]j>A`>Z>e%c>O<.?9]?>vÓ>U2;LxPU=˥:o>`?;dyQk 贾AD ʾƽ;=>w$Y^zApao=>fb>s~w==q5r>vd&?W>&?$|(⠾d=۽W>>>?+PϾ9=I>,~kҾPzcҪ=->E>Fz tS=V;>u ^>VE:=Vzv>h>l?>ZYgۼ`>k>a ?L>Y&Ⱦeh=뚞 y\ȾD\6=>p?I>>9K߻ؾe4G>d #~,=A=5T>*=w~ ,^dsצ߾簾1? 6D~>1a=N6n>ㅃIݘ>5B$K"ȣraG=(p;~(@)>2L1CE J=/ (=م>|\=z=>Lxd>Vr&> X)>?.<b e:> >OfV>?9C?'],H7Ã?>X?8?>2#{Wb>>v86| ]u? #B?uU?`sCr=ݿ Oh`>RZh>zFUB_o"K'> |?%?0r|R c>A?8?\@zq=.8? -b?+PC=q;>??.I?.qiq{&o&>EP?]J? PkK0CԾ25 L>n:mˡ>="2K>nk7#=GD,Co> 6@O=TFɿ(Nc-⾧=:=ޚp?6?, 懲p-.> E>E>Sq>{Oa<"G;e>1[o)J޻xG!= _7%T>6I>>7># &>Dh?? 8rn:=j>#S>崫om9*>N?P?JSuqEi׿'!j8}>޾AὛFT?%㗾I>=M'*^.>U\ỌsUο7> v &OQ7-,='8w>%#տ1hp4>،6Z<6IF`ľSJˆ_F+ǾzWfk0ÏCm'=TKukuCaP<*\_<RnA*R$Xhwِ=Kpyɿ_8d>)?c^SYRř~Dt=s>!iBoS&l+;!{TmЫLþ4ǒ>d>+x0Y=T\b OH/Y辇MV>½wMx<0>>tTv{}==Mx2XX >#?> {Rܾ^=R>jY>CD~43^:x=Pn=j"ofsܐ hn6rg>6->&4=/^>5>̟! :kP>H2dD^])=#`,=w\+vḦ́=>>hD𳾇e4'>9ė> \1ǂ(~===\yAR/~T{9G:Sz^羕:n39 \X璾NC #M^B>vG>Ň'?H~ʬO$=+==!>#7@>MqL7*kS78y>KiU` 8C {eEJw)u5&=>9>3ާnet>JN>"}p$0M뽚m<>~*'P㴿q~8`A>01C/ Pj=6R[Vӿ3@0 AJ>?e?2n?| N=R== ]?,?-=P<-Io?9C^>,m(uF38uXu wWF!?CY~=P=P>t>P?h傿>?M,|x?[Bt>=տ%5>>^=5C ReҾo< )=D n_%Ո̟ل^2hQCtO'uSſ i/g\k>BZ$Jŏ?O=nL\*?+Ml=`磿;g\>r,߭71(3>t񾛶8*K۠h=;A|_c$_>jvپO i>h<(m>C Ȩ)n>F!*=,D=ͿW?!yh>wsCiy? K>9HpD'?R>6꿫}*V?5>Z% I>Ni&iC8߭=vBePPa=h@ pϿROؐ=7^#qT<_a/s#>?}7)m, [ѽ{ym#fB7  =k iEgȬ8;ۜs1ϾlLs@?="6Dx Vx`=˽ܽF S'$ꃡ> ѦYR1=eXT5D1:\be\ֿHVjq" B$]WҿMw?z>^MUqX^-zl7>@߿|=ϼ^>οלZժ%"!=$WU ;ndiyF>nr lTL]#K]?}D[w^ۺ߽j'(5C_x~n'I?>4U/IL||>磽is.o=ڿTտj@c>X<={F_k=wyX6 hLV i>_X}=!SQ'\6 ȽチC>k =Q>=(==jY?s$=dKZ!©־~A> n<Ɋ">#>a>??M޾N>,>wsY￁?[>= SIa>1>+^JW"N>?>/@#ѿQL>CϽ9 F߿9RgQX=u$\DWxLg=ʿH$7g'2>u b>3=3!5pD6>=$CD-*AM/MUj6뒿,#{T q3‡* Y[#쾢J>_8" >r?)N>>1 j>E>W;YN}7H3>,>g=d>axV>>ݕݽi@hEhᾮӑ8,0::әj?`@{>(1Y>HB=?;!6-*?~Aq>?)N?X |22p9<њ>Hb j??1߿2>>SLOWg<`&μ_FTNU-8b "i۾z_c/.龏,R$R;-Y 5e ɿ8?=QaȎ=Py=JӿBJI>%zZם0~> On<.lNX?PvK?tGE=GND6=Ĺ?{_%>YS>dq[?e>!?N4N?{> k3>ֿ)EA1۾6势=q>X!ֿgZ?Bÿ W=XYmr4L@?B9y=5 >>P̼>Q-*!?q~y>> \@p$>P$>,Dk } ,?s>>h>=RIgxy@>TW:>]bV_?7d>|F>k r"?|t==_8b?d 9>6υ>!\*̿YK?>H=Âg?||r>>sZ=. t?{z>%g?<?Y> $ l/?ҨHs>?[h>~RH?q>q?6*5ܿŇ?As >>f>;f0%ٿWY;;޹^;%"B B?TC1+=>ϧhv`?|!=? L&`?j} b>}>q>+l?>Y`zH0=-s5+?>S&>/>z=S} G?C^ȿT=?Ko~+AcoֽwG>(dEnat*;_> LBx+a+>mSH>= ~?0ېs^>rJk4v Z>, l ^>E @zA^=Օ*οDo5=Կ<((3 (f~>͊>{? zM9x N>>`==߽ǔ]?}1>ԙzuG3_>f)埿v~q~->Irn#h>j%AT; T?>*2D:*N:K>>hm꾈% E]I>!;1ޠ!ty f9x>dY\>8Rr?W 5qf>b5?P>X4L1IT9>"u?eԕ9Q@1i>M>>9;ܹә>n-=J> ݽKܿEZf{?l+>TLAHAl)==U?e=%[UO oT>?=ͼ^N_|Hk=@?qZ:5"ԜKW>'˴?$>Pľ{N>@? 1=U0f];DG?oP(k@P,?<e?t)?9x =A?N UP} By=?fdk>mzTCGQ?J>y7 ?>pxIvM?z?t>jt~@qi9H?f2*1Y$QL?>#d0?K$)>?P㽜x0ko =?S.aNr N+?2H>&ʴX8=?Q;>>XB|\t?B>hX6֨Tm$ؾa?>k}c=b?̿U =¶(?]վESJ ?%=E)?X _*^z }?]Z-G%-@vd?E=ð>-bjo?b0>mrk?;~>P5>PQV %1>GT>b=8ɿB5~x?A>]ǚt?u!\D661@1b?%?&|y K?>m13@[j@?ݔ-l/'z,x-?>ƾ dznuC?ս؝ Vqn(>#WGa j)#S>/f]%u%&=gY?$'㏿` M?CCqYOx@ G?jIvY>p>T~r;#~>- i>1>9='Z%>>y1>M=# ݾ?}Ŀ1`;BP̛?AF=e| _«c *?1tͿ?y=u>FGW?Jn >,͖>]0M࿜`55> Pn>6=(ک-j?ԍ =z%h?7N3o]Z 7I*W?!p־!!p< ?4;z_7V6n=HV>M=++)RB=<۾Yt>uqHIdЛ{Q?wX:~)z[? to>u8> F>N_٠isu>!!C><:?m>^/Q>.>˧??J;}~F)>8>ٮ (ܺ<}!? 2?>7z?6th?3C>a?zѾ>gg0+?>̴?z:K>+Rm^>> ?}辋Jxi>?ز?nkE>F$>s#6?h^vSo>i?'W?uu x>T/>K?eȾľÄ[2쾭1wJvo~AJoS0OžEpVp1Sn;E!>-9urlLphJs<ҿ-YkV^)9D龐ma_+d|ZWItkϿwԿve4z;tLO+SU?F?<>2{eg? ;A=P?|< LD<.=η>vҿHĽ?"iX>ƣ>UH?O/?-=Ce[>->?MPhU|t=E`>-?, @FpN<:U> ??#uy麦3z>:>D/迀+ýi)1# ̴Xw%=] ?goՀC~ޕ18ٿa־ 48p3;m%s,R:Ƚr[1>U?Fk73>U?Zk _ }b>W?ag!}5wK<Ă{ pso&>#!۾\>l+;+Ss ߏ$dV9G+I?"jYӦ>>@?q۾5>FIS>d>^?qϾ] _>GԾYPhx۾>G+|[ʗ vU ? 4e+ _'[?)>07־{\Y.i?6>W"[Z?I~V`> _>N=[8?o#O@>i'?(Q>)>!}?(?>9X?T>fcоO{[>pOagĮa"?I>)K8E> $>cn?>5(?F}$>?Uz>2/=y7>uH>)?K=@WE>F9>,?;+~>DC>$S>x5?U mXVH->4v)?\K/P:>aE?]j8E悼7=C?޾ 1N}>?I<}2W+Yh>,A?F0b @Ѿy] >qh0?z4pǟf Ƚ\6>2?վQrQ> ?׀6zT`5Y>?JXfCSTJ}? >jEƛ?C?w=?oY=,>. =`N?Ă%=E>jqy>29c=^= l?rξ مH=on>F@?K^%Ud<=[?v]) c~;>! >]?G̊?\?j>+r@fd?gV2?8?;F?(Y?ܨ>Կ LZ>b>yt?޼ۯSgN'Z> ?N׾uCDX9">Z?:=>KGT9? Q=EpE>n ;:޾I>(!{GII%??ύ>v\C QIR?T8?7?gCnx5=F*c@c sy?A>Vm>P?TB)d}?*>Y>'+L̢>E龄9޿L,[8=c8 l28)P෿IU8D~?м{>aJ<8=Mu?;J<}$Lw?`?"?/G/$̿ERmz?J:^9??:8? 9iTV󾱐K>?ոE?ۭ?8oH@ռ?p?+>?&_]F> R>BwĽj输 ?dRL>>=s%h:. ?^@?oif?9tX>{>+>@sXQkV9`?@//ܾcN>Ue%>>>L>#Lf? ?R?fM@ ?!`@ ?:!%X> 8Ѿ&c0%7?P@}N?[p7g>r؀>"E-f@iKC-?W?*u?N.o tkhl-(?3?8 ?ўsPX8!l?\A?0q?\hf|S2pi>7>b7>,5]{sX>E>)> P7dR>=j,=c`{Uǽ?-0{>ѕ%>%{,LjoV>Qi>I>,@[s?W?z?u>⨾$ {$*@z|`ZP)??j4v?}]nb;?5?=`?<6|ǘR>S?}?H?O|/S>?:?>?c|gcE:NN= {ev?vٽJ>ڠ˽msZM';qoD=0=往`۰>XK>Y2=9xu\9RŽ\D>Q6ў-Ͽ ~[ժyvaU??? ?j8x?_eِ?wK?O"?D(p)?">T?Nkjb>T=}>`)xL>ʰ>)4=fow(Ce7;>9m<ƗWwApX>Wp, վ }1Wi4gi?s?TC?qɾO\? ?`)?ww%Ϸ?lz?J?@,g;<$^>տ ɿ<>29@U= öL`>f= ć Y)Gs>&=ҳb2 @IK>kmʿVoŅ>n,ܾ(qaҿ5kݜ{4Y?ej?B%c? fܭ_?P?ql?v\B>7?X'?/f?{/=k<ٿo=X(Z`QJߠ>. 2HAkDS&MIE+NHw>b?r?X`I8;>/{?i?9C9tľ?b?~?Y"?J?ϩ??Y@Dp5s Y/?x}?⥭@ 5k>,S?/?U?!7`G=)@?I@ I+VX?i??rs_) ?u?[?M=>pi>ݞ=&-ǿA!)=+@ľh"/ lFAe=+??ajdOp[S??#?rץ۹=R>1> =Iu= 7?>v?"4n?g?Y?G:n辅?V?Ø?S&8`?{?D? I+ ?td4?B?gԐ =?s??EpP= |?TL?A?T]? V?VZ>?_?&>:L?_I(?e?C.>7?t@?w?8!%+>?0V?.>p4p?'?'??xt:|??a?Ed@es=m?p9?58?Td=?K?Y?S]6t>y?>?[?cٽ82;?w??bFJ4=+?L?γ? =>^>[?q??4H?o־bx?;T?J?zl\jF=>^>R0?4M_>0h>ި>d?-Q0>+>>W=?*j;<%>08P=9T>K>.˼-ӾtK=^N??$?l=7:?S7??x>Xl?k$?s?ckC<0?4K?7>ƜP"?J2? ">0~L?j ?c?d"K2>N2>> ?۶?ZD?u ?eFNP, ¯u?j~?N?qRh )=ӌT?;?SC?Q4 O? 0?-I`I:?ǻb?P?aYO?>?h}?S?Ǒ??)? 8L??$|?Ez{='?iY?+?@fP#? \>qz?0QX7$>I7>$>=5>:w͔mz?k?MO?Fuhg0'% F?ȟ?V?W,bl?^?0?>5AMy??S.?_K??; A?P0ܾh??/њ?=7c?s>?Cـ =?9">Ħ>Bl?OS?j*? Q?*?D?Z\ MKM>!>>i>>SC? }?-2r#,Ƚ>?Os(Ub?4R>0>#l+?;>* >@9>Z 97=,Ǿd(?<ciǽ-<q>i@y?#$?E44v>H[?7,i?\R>~?S;{?vbBj>o?$?:ٌWCt>͝?)?ANgL#%> E>wb>㉔ =$> >zP>[%P '>҄?x?(d>ouS><6>?2.ZY>j2Mp=?1?(K?d`g%5?&P? ?,>8 ?9-,? Ȏ>CB?\:>?KHI8Zυ ?oP?(t?C8R\\?,b??:xJkj???4cG쾑M1>]pN |Rȅ#l<2>M-]Iz>x>yS?.f$?>??Db?Xx ?d9Mg=߯B?[񽢃M?kyeG>e?&qk?;U([yp~?Z@d=$?=.A?<?pdQi.ؽ(?C;A?7Vd⋾h?g>r?d6qsԑA?FOD=h?M*(1CLnVh<>ؽ+q9C֠M+Gv>E>US&P<9z?1RBl?;c-?)`t?4~>?6 V??EkLPQ>Ⱦ?[W?4FRi>L?"+3?:zpʰ7^0zH7?}п}fJ$X>2v%TboaH|}TQ??H?Ɠy,y" ?=>^?OpD~ z-?c5>*?[Fpf?轘k?+= ?6du >>֦uzݿa7q<(==yMVP+ @l=pb< ½0=qտD^͸a==ɾ̒E>l9_?NjLӿ, e?r!?ZVKZ?.IԽ?<&4MOf?TP>|=?+px?q??b9a( x:=V{=9G/L8徃QzeY&Xփq%l׿wofd bQbq罻a5+b۾f bM=Ⱦ|Nt2 =7^e8CB$=HV>l(  ;z?z0p۾.s`LiK@-Cm=wG*> /쿘>L?ľJ8=8vR?{>V9P?*\d ?`> GN?z l&9f?Hi@=LXh?^|99Upޱp ` (&Ne;<]&7սH$fL>v bM{c_Y 2~Ey娽G* s;61/ʂҶпOjD6vRBB<ӽ>EnP O>8> Bվ{">|k>@|_<ֽ犽U>w5%ޠd{Fru>28Y9=G >w7N6>eqG>uF??2#?l+1j`%ʋ A>=c>L&"|>U>R?-lZ>~g>a5?Ǿ>ی? ?I=?>?L/QzY>?/4?;==T>PJ0>0?C0*l|7>CB=-?-4<&y4j>:>O8?$9)X->=*? Ejՙ=5>F>6N?g|Hջ{f4 ᤽~lGt5 txE8xtX>&$z5`Aguq3߾; }p$kT (#<y6ƾ2`qT>3iw_ i8>b3sw>==ƺI>DJW_p\qۺ#$9="ٿ2,Ep^')=)翌`TcBp0=ܿ@GQi{F?R^= d=r&G??V\p?aAPXdj bX?y݈?s;d%?Ai2P+%>.Κ@IbQ;ʿ h,,}+cNf|)nƿ:r&p :L=*=Mu>{k?}_?SlP?_\3X?OrP]п&6M#-cNIū yG'$;%4OK@QU?˿,VK\SϾl~o W pC=N?0EFe4zS>w;=֚ |Y⽷>16Y>~=o,=x>\uP>RH`M"CwXX=qZKG ȿ*q/ag&xlͽ0^z=r9վfD>@V6">"};<>WDѨ>VgKKս)>߾.߾ l"(VZ&> ??$?Ec5x>=_Wwx>;E8N8񀾍^L68'PѽZ> V-$5nU~=b1̯KW?=!']PD<`u<>dj)%v8fYȩ7=" =ֲ)>G?̅Fb>_C>H>~?m>O UF(=?=V=6>?+=`?0?Ꞑ??q)??G/?3k6<0?&?yE_?4zKܿz:Gs>&%|LѾ tտAI׾˿LIrtX:3dԾx~4)^'_M=Rq zS¾7OyپR.?d$?mr??Ỹ?+g:?%oBH?WdEyȓUb׊:1D7xdj}Ӣ/\@۾gCs4Ź cV(4ra˿/yF(( 1뚾<;Y5{=)wɽ mN>l.0;`4nv9=E# =k\WD>:=`fPa=a =Y>SXGOr=O>]>3<> >7>PۣC<=Y>{[pL>&$R@>8;c>j40>pmLsT{0M><:>]d>DZ4;0X>S?'t??v [@5F=~˸>>@>vq0K>,+ؿ!ؿ'ތH?SMx>Q7>EH>o>Ħe۩=HIE>2>U?fa={)? R ?S4?;U?h=5>?G9?m=Y>ݥ?^1?ur>if=Yyd=Pw b>>#B Rm= 8 >D>?wG !:1>>X}>G Ct;HGxD>>@?W.zL۾ۯ>~>eI?b;yr~IٿA:>=>i?lh_)C==4t? ZB +gi]k>>*?G]@^rN;>)e̎=mR~=>B>s%P# ^u>ܤ+?>vMYJ^3'>RGQv/>DTX l$y>@"SlaԷ>HM8S=jM=x(?& c[NQ!]Myp>-S|M>>,?_tX>4Wv?8ѷ?y?؟?p?+{Ob?M?jM??v>LJV{>^t?A?A?C)'ɽJ?>?V>/!-+]'&> ? n>FC=}> E>E8)1r6 !7= 'RmxͿ9:ֿNKz=ܿq2ĤAC|5|1<;d?hۿ?+TV>I2$4ɾd>i?_??>]N [8>q?gk]?d?*.x*gk>?0v>OpXQH[ rQ;T́wp>B$YiHE>RIZ"G͙>dzHx^荾0Oa>WNQMM~a? Ǹ g=뿤.˿M?OqC>?0)?? 5>6P=H|?%p? ?{8qNCT>g7?o SJpBVLi/>:W!>^WlpP.)_r@`goet R>S!`Oce;CR' ~>vU ?&oFYu k@? pȤ;pr|5=,H(<?5/a>Fſ{ٿ&V?VN˸>ȿ3>6ԡ?=BK=?BJ??z`tO; m>gl,dl8O `FG+z_==J'?&dCļA[^پ >c_D0.r=]2=<5? E*NNsQ)!}Y@'ǽܾ><>ۺ?J-G$\>D>?N?T#M>W(q&@>>N`h?= )??ePO8_ȾU?;?5U?{> F<ۦ?pD?]?"=.H;?8+??Jo?^K?g?J2 @ʾ '??B?^?O/w?_HA<۾i>>?mWPT @}>>!>Τf?b])C:ZYU=J=? xJ<?W??z.JQX=?[>?`?Q D:i?Eb|?.?±}DYy=q? ? ߨ߽d,?c+?GbN@q&;>-8?\?V,E*,,`>R>-#ϭm4?#?)0$t$yߗ$mb(0sPMX>j?vԀ?zF.x~žY?7?;?)0aڿ!q\?+?b?,?3MI?7v?R%߾B > ??&rp%<޾$<=-0#ˁ(V4-=5?0UrSo`/=9ڿCҿG&2hK1Zl|g[+=b:곉1@^"VP>=пB;ҵ_4~>Fѵ,L>Q$r)X!Ͼ> dWpʂQYC> ͼpZտz󾗂$>r.c0iD#7>Mꉾ kT)=`2;eq &@;>yư?zL?X,}NH?>&';"K<7>r -;,|??!.\ Š@#^ !@F=(A`v}>Ș ?([> Ԓ^y>=*?)h>=e>x->? ?Cf0/_V~N? I?g?J? _[>'‡> C?5R>ۭ:=i`=Q?Sݩ?]"PqR^N>(yeT3Bޚ>n2>?#?nrv>!i)?K"??{ c>k]F= X? >Y\lM>ҺZ>ֶ9?>?E]m">  㾇n!>;Ɓ$mP.P%:=j#&9fܾRP=>2>f>ˊ?=<:>*Z*77CcU#>jr=t?'? T>mbL蒿^u ]m&@Po<?pb6=%Q>ptd k'{ѯ>5x'tZ.>@>C>iI<;a[>,? >>T>>0?->&?NM<[.>cLD>>~= W%>z:>S>i?9rz^R>wA>Z\> n=E=oP?, ?Ja1;9,>W?>ںS߭=<-'Q=9'ؿ%:2+n鱇=,&|4 t(V>0CmaHg/(>kG482ʾ4!?)=yJ>~=7e<| ?>C9O[?+;>=? R>Joj>=0=NG,>&˛>ͤj>C-> xZU>R)E>9>cH|oN>4& >=Wdk>'KǾqV>q=Ge=Ɔ>>ȟA>=vս@>V>H=.'f,vS ˁ>^2={Pr*о>Mef>0%->a>?H?_3>61>=kpR&ȾV>d>ULT0> >|:gT6>Z2>Oe=*=EL?TxB?b߻ɐjt5> ?K= ME? ?"bRqyK=:?I?KGxz-Z6i)߾*_NF>E >޾&[d>xp_>g컽®>qX>teb^u!1rᄅ,(>> TUssq~ 5 >P>d>Zsp>>e'mo{1{>^>EvFHȑb=ө?(h?M>ݾ/ܾZ{ Έ>>J/=l?s>4=TֽL>ϊ+>,iҽNY ?1Q?' 6*EN{W?"3j?>Of5>M꾙 5=_J?>S>H5\; >_@?>gQ?.qX$&W= hn?B>{ оo=_?r?2Z=">">APxݓ>{?J?:mYԣYi2ߨsru=I ? ?wSfY l>9;? ?eRt>9?S?.[դǻ>><>URzd=~ھ7WO>w>ĂIgϽ7N?&+?G)?ibHH> ?H?c_Qa'>s ?:?7õa I>+?J?<ؿ:ne>?~?DhҚJI6>qz>!_>0<">w>, =Lf?3}?V]epzٽ-??2+94=/ O><>:(BlYq Wm=0f<X'|˸^=qM?3+e[)">,=":e9ɽ00= (>>9wA>9 :?3> >gsapJ<#>>%>?5^g=pż!쇘<]P=~(ue}P=ؾ+,5RzO=KU0tu<Μx)o">.b?T?{9R=`?9?^^wOfҪ>q?_?+ThSr$>3}]0Z̐b=`=D ?$>DMCi=>j'(S>;T=G>v j>ѳ?qZ?Z)Rb>W?czN?:91TBr >Pg?&=???["[U,>>gG>'пzxi)>g=>">p">Gl >}#ҕ>4={W%!N>e/T:=E=<,>O>nC5>g,>YSA ޠ=3Ut>-8>Kl>K=Hqv>a>=7nT>.>X2>>*xd?@>>?SC,>BĖF>~ ?]l?$B>?OZ?) L\w>G3$O]iӾW4>oӽ"=X%/E>(==@0<> F;l*>ɡ;P$p>>d>MV:.>ω>)>71/~K>o?;ʺ67;4>n<<9(`>moulvd\&=6O>?U <6=]??@I#><ҳ>?0+@H">>V>B<>Mx>d9޾:9K:_;*>ӿr>:)>.>8:es6߾V4U817>H>Agf>̓GZdzľ(&d.8=o7>>Uo|_нe=A>t>y澄zN= u5m]==)h>C쾚7H>!J>(x H=۽ffpA6>~Z[={hwK]>Vh;oFz[>ݰD>LO4>m $=ؿ}dT>uO>2#?T ?>G9ħ/>3?4?[#"[BxkYP~=ɛo8&ݿ#Zw>Ug}M? ,puhWp>85Y:>wWO{g{Noؿ`#p:Ov^iԾ>;S=t.>8Ly5><`̾ݜU=ډ1ŀ>>rK??A ;9??;ԓ=O>*?)O7?Od>y}?E?BNP >v.C=>$??}KbݿTi BO]žWK1n;j#<ûA-b +^B4rvdN0j/W,=ݿC,M˿EpbI>)?]?R>E+b5u7aAlznҽ. gC"P_پ->X^??:mU>9 !@B7F(>>!?N;W=tz[! .FN^IR:GB ^}-V*OBŤ~?3?4:0-#~wljf1p#dދT4_AS2v;}\#Bp;߽j:=e>5 ȡ<; |<"y?I^5a(ɐ9*G=>p>LS3{)D4]R?6>~T -zU4#tJv;E>Ahs?g?g8˒kl=پj E$w= ;yȽD:i<>оK¾-w=K>;xX :=#>PU>J > Ӿ8Y>TMsw> p6`><|| z >9l>fbl"7'l>!۾d?,FD>bt 3~V>S>m]>-iA}{=徤 5Ύeع=޾&=t~>.׳h+f4Y=C>%@Ą@="]>Q=vS[}0f&'jYD `GȨҭA _lL] -(%==)8=f?Qa1=snƿkhZ~?Or;>O7ˁ)-'@jr>dк*a>hb?h*(>ä''F&w?1b)R?6]ῂ1q~'ӢAow?z;D>.;2@d)Mb6$D֢>:O[F$AdGEضh!%=sFs%QQ>([!sX5Vd~>d,==>&O>}i7z>̣s?/>G3=q=`ͧY=m?'JW.=K{4㛿ZC!!qoʾY$ǕiTڿf!2v}v!Z=5ODw>q`Ѩ>=[U ӪVGA?4>8m>>9$w=Ыȿ&EԿƉPT;bԾ׫2¹/fs خ=+, 2,Eanie-=hvqg >lrzK#_,4Cٝx;D^>Q gf=R ۼoߨQ>0>v谿1ۿd$D>`l^ k?=Zx( ޿x:= <}&?%H$>"D>޾!>sƧ= sj@xV>$cnk>,=QSz<=f?y6D>迆scqC?/v">fԦ㓿(2=> cgȎ{=6rWֿ4_?UXdD>ܿYod῁K?6?ؑ}>!N֪4 ?'B8>0ڀZ #:>*^3'+ÿ;4 ]=f˟]-jY>9>ZĿ+бhϾHh#n=zԲB_;Z ̾%'2Zb%VG{dEzyy?;`>rZ>5h6vz?{> `ƿ}o?ǂܡ>28qJ?x>V+M/yV>R?& ʯW9?(V=>Jw?$>.0I"N7(?=־¬u)f >=|ypֿ\>&>W20˿>F>Io>l>ߥL>L%v/">aҞ=db1*6I>c>=:iE"a>θ>`G=mU>e>=]Kj*?G>>`c9ʗ?W}1w>mC>=*k"׀EN>?n '-oi PE)cU)Kuܿs# (H}R>DտwH^qP27Қþ#Ϋ0V4jU~?>>WڥƸY:&ýIh_?E_ >nH>O$ٽ~0#!ם]%i>1'."Ŀ>p;V8;=?`Կ[)J ? [>OG)L?C$>y߿)D:dN?2ʿ&>eVz: {?H>S>mo;/?: >K˾~HZ? }>?4ҳ?켄>?+ؿh!?俷N>/>Wfo%M'?d=Z>e=i(>a> 鯟ç>Y=DV{r?u=>5?}0jYr<х>?[}|]m<ƶ?zKU=}>Z?U KG?'=s@` g?wB==Z?r>yA09eHhz@*>B=yl)}?/?M?vO"<?'nA>>f"?,6迃?~O>]?rI>Z|[7?AP<$t >b--?J=H^`*uվ3C?Dp"9f6>/2M=U;)= ÿ"?}g>Z>1<>]?t<6=S?*-bkrFZPW6 }?%y ` ~u>>ҽ1V=&':<>)>!=c&0Mm ݷ>o⤾jn?~>B ?|˾7㿞;? _?,j񘯿Q?H:A55?| >a˿2KEp~dI?Tv<O_]̪l ??9*o=:r2#5 gl?[x=j'N;>;?N>=ċ=b-m8e0G >>@=F-)->}>!>MB %H>>)\Y|jb +>Z Ή ^?6? b?SmzzvUn >˰>q>cJB>6T>ݽU W`kр ? >?hTay:8s>dd?Z޽0/Q6C>*?61Ņ{?.VY~}I >4?Be8fM׿Oʎ>p57>!ͿbF+Z>Q)E'FC_==i+޿2̡u>O=GApX\=ac>7"`=٥"=ON1>I,QP0?Sf>H_ a5Zr?`>3# T㽿Љ_B.)?m(=fʊ?&k[O/f ^>Կvʼ?"V>#S>Z'$bA?->t0+?Sd ]d?>>#sڿS"?)bT\>?>ͿC'x?0=^>>OY>}-Zn"q?:>XO7BC =?x:R>=֝=8x$>?!w>ܱ5GP a?z<⡶l?1o>}?%>Հ/ ;3ZB?=!ERJHr L)?Te.VP u?=)NΉ?j=3o<Ͼ?=UX?(^)R">]><ۿ{ԍy?>9޾ `;%>%]`cá i?󒟿f?\IA>yO?Qo=*˿d:~>">@td=4J@D4>?>*EWAyOjQ=>=l@?7˾Կx xKw¾ u$_/~ B??!ֆov=kf><߿%t?)c?j3a`l"&a<о|Q?=_8  "?j$M_w6>Źc? ڿ h/B+L?2d鿃Q<ѵs{?8=TCtN`m;I{t|&gGV =)+?s&-4"->]>K %hsaQ)ySa/ U:?)0pno_o BIx6S%}BT14bF4=~>撴$.@9>Q_??P=ؾơW7>wl?ha>}bmib:\S>Z?;q?鼒lD0i>[2H?+\=Y䫤,h>+@<ټ4? 3O=>7>w@;Z=(п  |0sȎ?s?"?hw}>)>Vu?ƾ8k׀>W==>,G]<ݷcZ=ҫHsd(}۾*撿vAľlyx>|?;X?e =|?ekc=>2= =?E6D-m(Ѡ >G|G*ץ>CV#>G#E6>NSL%~4>KhN3;+g]5?Ib=F_: ?*r> u(9j'g >e47h? >0A>F/Ӿ2Q>7o>MF,>k)J4>>8=#hj< (>Md>;þ<(QPTq==_?_ t3VԷ?$ͧ=FrdC =C?]=r:ļ2Q쾲xK>+V ?:w>gOƼI:>"2?oT>.2E=-a]>^2>G< ?d$fe6?rZ(v)_}>fE>=Vm?lek!Zd$ @F>/ ?K9uhM>QB?fnUMm:*>{? jx3'_֕>5?1濾&= \6,I8>y>&{u?9o-\>E>^<_?$%V>?>I}J:Ũ>3>dӿ>`k5j?W$>ho>$>BH-R|?Ҿf j_ݾx>0?~,@z2>) 0B(μOs xg c>/WW%,࿤M> ξNG?i0~=*>qsa?|+>V]}?6v>}S=G ibJ??=OME3B u=W7? _-=g>3mpb&V4/x:>G1?6A1r>e4?m=??5ĵ>&Kf>ļ\ ?W/G)>{=t?Oa? S?>I?:0=y>>L= ?D:>Go?õ>m >* 3 ,0@ĿS芿=6?y2F5B~>>;V<[?A>>/=%:?w>Di=>=$?W&>>GVAbij2q>["K?:>H?^^F(>hK>.s` ޭ?T>>T>u>L3d _Mh>$ >}/<]tb:]$(>g??%NKV>BK?7>̼L=&T>:G?ֶ?&<]پ`L>(?`>䂝 &rU?l@|?ίпZ&F?n"@n&?Xr`y+`?>m>dg˽e4>yPbR|T2*?+p>>(OӼ+ ,?D>Ǩ;8ѷ?I@+?r{YT^<3>a?ƽ~_LY?|5> d>plTN<R&<+,~O>&o>GёYf+4abd|#`, O?'>?"T}Jr+?\Bc?0-I?a+eG8whZyZ$l>=zwpz2j>6>uw_RYlPNgP)N?'>,o?.d=pppb|>T;I>=n ڌ>W&>7? aU7=< >$KJ>V1/۾۶F-pr?Q1S>z|=@>Iq-1?{?e?LUj;?:~?[r?ŵ-,K>׉@>?fWAȴ?CN??v) 0J#>M>?+Cox??%>b?5A kg}>&Yѻ3>MR,=,??x3?=!9">I?Uc?(+?^[dM>V?]U?17~?~u=TT?,?&?e|.>N+?z:?dF?!S依g??l?pb>=oW>F>4L좻]?m?}?:pb;O9?SJ?!?~8=#?EŤ?Z?q]kx&>??)YH=? ;>bE?A(9:hSd?M9>ȘN>l?5t7J,?ǔ? 5>?PA1`6??>?>r?T5>%2>;>4?5Ct2>\_>߹>@N?K4: x>K=F=>/5)xY|?K? >o?ZٮIl>&+?(? D>\JO=1?7њ?%>޾ >P?*?@h?f>?,ϯ?;Fg?sK^?," >R?N?Mq*?,~_?Cއ>g>ѳ>SF?*<s>>> 4;?+A˧<灄?>?!}>/V?>q?;?O?|(>/>QH.9?B?T0?٨O{'#?pT?pma?^݈k>΅?C>*?'jSJ;>>>be?G,>D>rC>0M?2Ũrv{?`?Xk?N> sE=\Y2>>>}tw`9?Z?4?J0U5[z?Q->m?c(Z=B?>>)E?lO>?*?%/?9`}=*?I$>НI?rRtIj>*^?kr??;uih>,?SA??mM}>Jݜ=Z\u)>n𓐾 ?d4?0?>re$A?%>? .V:<(>Ɲ0>;>gI0?W"? #p?wp?4[|>t?_?0Kk]?m? ?);K}Ab >N? ?(>= t=ҳ>>J??T+A?f^?XS2f?j yH?1nuDFV?Zq?7?1cˁ?:* <ї? q>4+?n"?4'.<>8j>{J-r>>_8ў>BW>'?~7>r>D?4q???T"?hXh>aA=>w-?(ة?W%?m!5tI>S?\Z4?cX:BPc`?G\>s?RD,p<@x?fT>1?j3@A:P=M9?5?Is?0HY12?xO??#izo>R!G&=??P{> ?&?L/9?Z?*j?<l$>.m>m>'_`9Em.#^ tgjQW>P>n>x$ ?#rqj$>uy>ɠϿÀR>ke$wy>u= u?uO@V<>->bP?-8z-=cc>ZB>n?or?{U=$>%s?0`k>\?Ҁ>?/:=h?J7>x?x7 H=[?;$==X?Tk o"qZ?l>?/fV`7q?N.x`xUD?L?\-I?#ؘւ ]zJ$K'"ځ7X]]L~ڔ>fA0''6g?5p;+c>'ȑ*J?ڽQ?8#!<(+?O8ڟ˾Ga:=վі C_5;Ksä!>J'īܾ> 3>"D/G{Ŀ7/˿)̾% ׾=siw(/bhQA-,|y>.!?q%?! ?~_$?, ~ҽ7<[>YiJ=>7>Id#>XL>c%^.=Z@پV>?O> ?EÝ4$>W-A?(9#{X"L j>B=>8 7=`51>+)$ztdWQ=!ӣ=&>&y>_? AH. >1r?q=h`,3[{Y!+&{b=Yл6;_?)=𵪾 (>/p Hξ ̿[D ťF2 Nl, cZ+w6d<#r羅dvC˖6;"d Xi>ľ7羳"(VžBq7:=x*p`5>"O"hQ>3h*i7g2-v6TjGW1c1]˕5X=la9>%`%N>q f=v3 QQ?L L>~T[/Hސ5=Bh-Lw $ oR=̍V*5w$a= 7IHT7O>]ٿ\(vF?\\Y;L=dɿB{X9ǽO'P(=JpANJ{&w e4.@vg=dni$!Z$FM>C=ّX>h@= 04;YX}a >*\=(iLz{_>a,١׽0]=덦>= E׾j>{ M(־oO޿-: M9Taq>[k02g-Fg>1p?`WzJ>eȾz#~ = EԀQ.(9Р=AWJe3>Y>=ka E>pM۾͹\y>| ]޾E=iw3?ʛXPs;Oͯu`?g4Mg$|B@PLjQ떿Ã.)xqp>6.z>-{ƈ>U!?MB 0?\r]>O,0rmX>ZwP>9 t>E =2a@=M%O[􈾯 =ƆKJタW߿v?k#<?)e?Ĝ>?O?+ ?T@[,F徬#1#dAn$a1\= xU(p=bW+嗼>A#53=j@7<5>x7.?P? 1`8?4K/c?=Hp?`cOq0>^̽ p>E={>z>n,yz>ܩ0 0<ҏWS>΋x*>0ns#p>@Fj>B/j1lR{`>+r>'OxCeedH>bq{==޾>[\??)'@7=CH>W>t> @A<>]:?J>2xQ׽?Ծ2>Bzs`Lb1Sf ;>ߌ/H$>63H?\??;%.`3?S?R?M"M I?a=?YsT?>?<?,$y4?`?x?|Oy=>$> ?%1 7=X?^?]o?W=cqWSaq=z@jL4Ɣ[ľ9"d >*>1b>197cD>M,2SO7ЛR>6~Uc,>Y]A!׼l4(=>HUNp<=ᗽv>H:2>5>>S?t~=-b:fUW= D >/Jp# rؙ>-D?Vz?Wd?_T༧ m=ǿ?z]SWΖC x9_ݾ`vT̫e>dB b>ݾ?OnP?N&?B+np>* ЦV>S}[?rqz?k?? ?CzM<)?Ua?t?ѧ"?ˤ@&@"V> n3>0=T.UD@9EH;>2tT4[._=q? :u3p.V? =F>sYu?yH6>?z?]?Rz T@^Fte0L쿡Vs\SirͽxX\ d#G>@[kaN ؾ=?{B$>@~Z?sX???i#>>B?2?۩ ?&TIHҽ5in>?:0NT; f_=k.5o3=6v> K>t ?C\L8F )>H =ePPre4>w]3bdMer+>!` "mPR2>0 ? ~\)v?_N,l???oib8<;?: W??q3m"?=n??N=~?M?RF(S? >9`?T?µ P꼯r>1?GG=y=fa(;C>m⤽6lv>>#,P='RlS?. ?}.1&=?6?6 mU= $̿M濼sN>DI⿗ÿQ((=CH˿F*3!=(̿v)Au)U?\F A=][?bgQ??`J?,:?k?`=>?N])?P.0< ž_>?>̓4(H=Y2?G?Mf68P~A2t> n?[5?])>f>:<Hʾؙܾ>Qa> r%tKin?y=x?E?{?kXm0HQ߾ >,?7*?8+nHJ0>?y?|3+?9K>h?U?XJ>ڸ^3VU`<; D,T𾞲>csXP>T>hL̼X9>A`>;Tf{տsi>6>`z?V'/DB trsB$>tEƤ Aa 7>>6mT^=!Y>+п(bԿ*8z?}>$ٿiQPlR??8>qDp_>vu>Uӳ 꾁]-?*r>ǛϿlip% oq g>&?S??(!>F?d^??@}> t??˞8?#k>*?s>Id<8_ɓ\_9e_>}>?T/?!dxW=I>W!?)G?2?m n>AL#>N?~ ?sc)d>)>?gx?l.usG>"(?h?qX'=L>?G?7APX=א?9? Lq%tL>Ԉ> C|=X̽̎>z>ՉH JIi=uQ>*o>OD 5Q3X*(Z=>3?@?0!l>ZjUND AНT<(9yv y'L2=򎓿9f2$ -^>@nҾ&`ゾc>> Zp=P?a?j6 C?&?2WuO0˟>\lC:z |%Oh>9=[?w->0'H=R?Vf#?evQU'=A-?MS?X'(k>?^?AW6(?)?7Y/;.>rKM{B՝InP>ӀZC><K>Z6>&?.W>>~ Ms>n=?(u>Л?#}RB>y#>>'l;0>&O?4M#?2 ^NgM>>0gg#%=]{?P?a-V4 >??5|8=D3rA Zv\Q>駾ܔpt\8Jm?ڽ>HV>Ѯ\[>7ݷ񼙶?>DGM?<:?3S?|>v?UlQ?Kkݾ5}>'W?Wg?lLHE>>.I??r)\T(*?x>hs,(Y}>8>Bs"P} >=}csopƍ@=> =d]5c߱>!??RPb>䲷=!>rxF=zN{=;?>#z}RJ=tD*>s>}_E# 6>>}hcҾW>"?N?j_$.~c>L߭?ar?z9޾̅>>Ld>:I>=ί%QHh!'F>ϣ"ofϾVl>^>mܥ vQi3>Љ>}厽 >_t>\ȾM>ǻR>&>&p.O_Xy=lckD> =]1}o{>W>ď=\ҼʐG>h>7x盾t6$>>߿D>KV GA>>W.S>H*?[d>aV@<[]w&D>w>% >=? pC??06>S?=V\ыGj,=J{켹um? CR&_ma>^>FFJMR>{>>s2?c(?9p ,=?^-?8뾻 2+>=J>,{>}foO=A)IVEt$S23',>h}=qJ4>4(?Kr?sƗ; ޾R>=\ؾn>>/>=O>>^__xKoa>?a+?>LNGR>0J>m<> LJ=h׾jWk>:_Ⱦpcwp8(*û? hZ?:d> w?7D?bi(=l'>z5?FY?wEsı>?`_?0@xu_E=:=\b>cF>X￵n>:`w[FW2>/>>teޔJ>Qr>Szc=SXT>>4D[;XQ_>":`zɾq>pM1w^~LgB9æA>7(xWc6<`> h掾S=ڼĠ>ׯd?%==޷??/ܾ龕=<ſap=(R8-b$M$alB|T=>KG=?kʕdR{9q` Qti=ݾ=+>q>]h>Iܾ(x}"ͻ;>C>d?_>К辯JX<D>lI ľWvſWBFK3>@ݾVھHN0>G%> l??DԐ[>]g4>xgj?z?MQ~VV/j"s`2D>9 侇Ƚ)}>#>Y}NnPq=+=(PPi\>t?1?v?Z0>Gʿ<**@#=2䏾}r6j>F>9y>?7=T>n;¾Z>l?=?h=wmr>;>:;? u}?0֑|C1_>EͿƾTء> GL=fm^ }J>n?A??-uw>ѿ]sjW>ec`BHhw=B/? TV_r>rmK_B<;ž8k<5/8;M>cv 7p>ddž. c\=ǣw}xľa&ƏK"" jӿ -!<ܿ'ۿBx0=>pU>N3>c= 9DX~.T>oO׾^][&GJ,5K<>>- f1>0@>J?`k׌<>>qſ(b<>UĿ prAhڷ,>r8T=.I1!>,hf9ס3e>᜽B;w>.:;) S0U4J=ib4>@\3ew$ =nӚ9rT.S=辽L۽<ٙuMk7>F>až5N@ x㾒tTeO،9= y龔̨ŠQ>zVX A=>;_;7[;ۿx]Z>?NΑ?nҿ ܌?Ґ>{I T#M< **>Ta%uO6ο+ 0@=u=|NcS?#5=;)_:d= ɢ%Jپ:8/yRV![V#E$Ss=pgrHr o(AѾ]GF1kS>zظ>lNfws?Bއ>ޏٌcbH0B_s義t'<(Q/-![2J Dþyh?yX֡2vRVsY>2yz{$->n"m0H0w_`>GQ&crPbNhR;v;I>&i>> $=Y >O@>VHwjȞV̿>I/=>8/JdoE8]Y>}F Fk<R.o: 3mbo '!O0?>K輿!U.5[1>jSv ] {L!=cAO +w?;ʗ>ü>Q3>̺sھջ_ L4¾ ^9 'T2#eϩ!4; JѴ%#VC W)>>ľ4ex>5v&?%%VBQuPuQ=替PndD ;aM6# 0lx}=Y˾9}oa=>> )_>.LQ?lC=?BOOsfl|~=(>[ܭ?<26>If(ƋM?霦=vhE/5P!b,~b(c%$ #`&">[dZx}r@<—.]g4TiTp&m쾻 Ӭ.K#b~DN/,薾;;Ct0.? )>>x0([D?q?V$%?2?Rr>!2*[ȿ`ns1?,=Yɾkj0'?jÿ\==2qԦ71=k[dw+snϽ%2=CpVP<4 yϿ"t\??m>3?T:!>Ͽ01d w?}F>xѿ,?a87>^fE NϿ?> kn?]9=Yq󿉻Rj=>H>ɿKX\}$%`o~?v}?PC?+[p@#N ??e\??UG=uPDh@> ?E{?@>@N߽=h\-0'lT>mNYhY.?h1(|و$ѿt`"Iþ0"Կ?lœQ=rY2PeMh4sf J?w:=n$'9p?B5 = ;^BL~9?xݿ>i?l? #Y޿2].A8PP>+*ҿ'h8?8ҿgo=. KOW>.?<Kg79@>^}ؾߴ? ^ӞIB Eo?־z\@ 47=a>tk<>7*c>D,;7y_Ӧ>7 Rs> pg>9>ρ:>Ɉv=-ҾA(?q:$;*=?8O5??q >?H`$V` 0@t<u>fk 0㍂>jbln>KE>hg5>1(KQ?K>4a1?Y#!?8.w>+Q>p6,q?_)>f% >lĬMֿC{?ܜʴ?0>-GB_?X=<8ˎsאt:?Yyw=aR?l㩨>>&ݿm?afȏ=۱֪;?K|pz>?Zm>z>hr>`G `ٿ>p, >}?i*q#> >ŀý+X3r> 1?N>g=)/_e}5=K= V6f=u$:>m/J?޿>?SE=BZd?׀w>9?/?a9,7&>I>⼱]pI>>/?2ʊ=[9>(т>=>6=70>V4ؿ7>+ >ז}>L%>*+Z ?8`co>Q>>'߿n*ܿj??>[>>]Ped>tAٿm/o~料wz>Ӫ7\=CJ>+IW8?>?e>M9T N>u?1׽ix5 -? }p@;?# R"E=5?[k=SRV x:i>vBQ2\]:%m>Zsdn}jww?,"hiz2?d!z~ۭ?7v֙m6f=\w?dZm&%1?#پ>G7*ڲ?^_># ,{#C=)?=>9cQ?Z>>zqB10>? >WhW00= ?Y/+>~ Ӛ`9?WT>?ڞ4Kj> > Ċ7Whܿg4z>g?D>w}>z"^W< o>i |ÿɝPc>>ꅿFH>y>k/翺W>7׮ ?.-+1?77>e?L{mO>܌ 5+><>c{"K)X|=@ FV,Jp=rnjbÿr K.P?D>(yľ@Tu<0?=F ݨz?Ta6$>2?y4H=Uɾ?}92>W?v)=s\h?$z>~?ɾpY?fo޵?">4((LNM2o?oS>(Ơ?&>fb>큾vZ-s?6.F>? RFq&7>6>ď?>W޿9J>fw>?*x>:?Y/^岒?~a.۶%?UC#b_> ?xuAD{U0>bE>B>CUvx}&>>1> ]up0X!}(?{=#pIpؾoJWzL@%)NЯÝujZnE zn~QD%t(l@9=w>/cmP4=n%B>J4yѾ?2aIVTW:>;>I(d&t 6[~.?S)Yy?uTCH=w*>+?2S>G9ſ:)> Բ=tX-qva/u>?&)>1¿>6/ ϾD?bxZ0&8#?f>ZE>*H>zU>?ݾ̧PO:M>t>m¿TO澢`>>d"iAQil>֣?;4U784`?p[=!350`r?ykϿO4PԺ?t8%?Χֿg9iGuFx羯ԿqȌF7>Jh>;ɿ]ҡ@Dj>@AF>́Ͼ8Sϒo<~>i>yg8^Ȃ;3@>#R>\j9~~4+A>tu>0?|=rǗj<ޜ/'=_̿#Zl=x=?;/Q۾?6<_=k=-<2|>r?)l?R<6wp??^ 3|'پȝk?!$B*o|( +`(Sʸ.dv1T}=q>`SjH@:pʧ>kax=?6 1¿?罭Ik:r >=_ʿh.>KRY\1T>#ƒ5`:?"‹>8| #:n1ypi<|>w0 ž-xS=`>k"!>a=h<s~S>sVedRH;}v>‹<ʎ8L2g:H^iy>>} B ৤Bh+>67=MM##F\ =_>O8auKjr@D#>>`>6Wum\1njSA>Uc=/a5nf=+>}T?ztul>Hs>$?YI~n}==>X?t9LD04z=)~>}?ZÇw=Y>l?lFؾ$S0vRp>؄п1l yϽ'(c>]3|-`i n>ozվOm3Sbz[i<> !ξ;{ar =e>3Ͼ|= @ ?KE=9=s\_t d~ֲ)>m?tk߾ >J?uL _<]:>E?nrlƽi& +"p>Aݾ.I TBF,2>|[QeHT>:׺gpj3\0L+eھ6?L?o>}{BݾQ??f>=`F?/h>#;µ?si9.Q>*>j~G?aF J>)>\ܭys4>b{p>1 I%F>^-? @?q M0>us>T?!?Gɛ2 ]p> N=?|?(W<>*w?p>W-z=Cƽ:"p?v>:O)^fE?͌>=y?aVs>?> ==p8>j>0#>ˆ=HP m=>%,Ϛ>z]N6Y޿ks;>>ľApֿ99ڿX.챫={???N>?.{"PFk>I=e@ ~?ܾ<>H>?F?x `"w]ٰ%>9Lv=˜ _ˍ0} >>OZ>806j|>pҽhg!+{=)Y?|@%? Ca=>]??ot~pG?`2?/?c&T?>>f| e??!?|?gYM>SھE `,T5~D?>m?">lRF$>#>?H=>iE o?9? *?E@|jl?L ?#??Ys:Ѿ?VP?+~?`oK:6iƾ<hI=9 .ؾ3>*W! <$-F棾=0@V@},DM:cAUpP*`z2=_ >|gZuN+ :.2Y?Az?|?Q$hK2Q?#(>n?2݋1H&t} k;Gx>z%qTʿ ^J=oRd"Oξ*6e>往Jww>Բ1>?#K?:O0x[>m;SLv=?t2> ?4pmB?j'Qn?{BW?B?sOE(?_[>Q?B0,s? >5a?Oտ ?>YO?0']=?CH?(rK?tlG7=>y>˶>_c? 9{C?$>>U?Ƭ6?4+>5=>by> ?}d0??TwWT\?mr__?ο?o>|=>~>X&=_go>崿>L?3*?-w?Ⴟu\>*?(?}*?x>?!Ȩ?0?8=>~ ?4C?A?; G>|$?7r?>B?.FL!>6?E??oyޡG?vBa?>Od?W8\?P??G2 P#?1?P?2]^?:yy> 3?^|SC??3+?GZ > X>d>c ? 4X#?> ?hٰqx?oH>X?ưI0O3uC?c?P?8 \J=V? g=T?(ةw>I ?o>+E?1y>V?>Pr?(i{>y >u>t?eL 2>% ? >?S"%>>hOzN^lw?)0??_:(w>t)o>\>XZ7?637QӪ?[ء?T.1??ji?R?H ~F^xU>}j?p=l`F>8?)Sj@>k?ǿf=_=@>iy?Y^xW>D'?|? x@>>])=?[>?e'Eh6c=œ?#?7?+9y=*9?,?B2R+Q1  9#>S: >ݽ9<$>>7>>G(?`:,=|L>Y>?O?X!*c(U?%=??J =AU?UI>$?r{M(YL"^_?JV? =?(q)A?h?׌?ưc> ??wŬ?V[}0Ň??G4?O/oLy)iny> L>L<o=n>짿|>IjØ?>K?8lW$???7X8>?Vj>M7>z~s5Jg=K\,d;`>U١C> |=ܦʾ׮>[ʄ8>#+??iԾ)>,>?.t`t&*=cP j=-D=<;=U8>!nq= %V'!>w%? l3]?}̔?=1Y?QS՗ B /1!&)S#")T&ʸ<,׀?)l =Ti?]4>\>d>"?ok{gj=Q=ی>?,0^v`WKoϘ[>,^!?ќ}@Rֿmj>3ca?A>cC?z? t9?:149;?u=u?UFl ޿Zjb<ę=dԾ>)cV#!γ=kTqH>)JۭO,vCZ=Yu&B^L|4@AS>B> E5=^1?||g;q?}u?E=?`F~NҿG0,IGrȿ^6~ĕv.?*EtIм]`b6>r@JMFܿ9z޿(AHg= 96nۿƿM}Fn&= J;*ſ`B>|!pCK=7 ݃><O>l>2ukv>;*>EзND么y?)? |E#+iP$*h$@$-br뿯,A4>}=Zۥ>bo'PXv>G;.N>7?3(M?D501J^M =1 Ҿ@Ȁ?p|X>$/=` PY=־> >x>#>{g ?Y8?d%P?TD?n"?t3X=BR=`~K>+}Lz4ʿ>`GRY???b&? _?U?C׊??"DHUֽA=jr/FB%Yq*H4");񣐽W3ܾh˾Ѽ! Xz=&ffM:>h/Q+:> Sʾ߹]Vm&=A "@P?l?p? ?(?D'!?w?/IQ=u > ?'9?9@;]?+_0>Zd>dWx>Gxܠ=]A{;xBϰUüQx>1vV⼑/Ӿ>'g][ֲ\J8XDt>=?%?.?S~\cu+9'!2><9 @">?$?$v?~`>{4M'F>`nŻ> @Ui>_"D>]Z<=ƾ]^Ap?zN?7?]d?w`tUӾ 6Ms @>[)?{N?A}?pT&;/Z>>i?:&?+??O? 1??ƕl?n h.ev ??yN?l?2C`S]`>v?Q> `_>??8.>E?WD<>x?{uu?^?l0b:fv'X聡>8*Z)zKM2=p?]9=>?ݘ?―?]?6>?d??Q>*>u!?ؐ?v>A1Y>t3?#z-??Bk8xy<N?;ͼf6@1@=?%=5HG|0Eݿa;ɾyW*>k?D1>?|T?V?տ?Ʃ.\>?m??XQ8Cm>0?]\B=osOBE}r~>?8ɽ U{0GC=(?m?X3?\F= 8UhF^BῈ+I$7uHS/Mq-wqS|{Uq;U!`D.>TYS?? #K?f VH&1=$>>v?eM@?0"=?"& ?9?WxmpR6o >>[nֿ!.gscP[ʾ҅v>c&4?'1#=0=???Hi.hRÿ*;>Ǎ.3E<ċyt'mv$ {̷NE9#>Xi@:_v>4rÿ"p#S>!qf&E|oh=Ii׺S>PqEϿi>7'踿8,>F}-V>%4?<Ǝ>%p?8z>J,>E?gMN+ZX2>18]QPpV=mQrwY6*W?A*=*>!!?!>G!?r>p?NT?< g?E>?l?fXqP+?_?3a?'__/F? ?p3318>4?Vj?Y2T@V=L?ns??@>߽=?TC?Y?u!$.b[bRN>?i߇??C\>Y $>M{?n?4Β]tmNqoD?'?m?qMA W>"ͬ@Q%U>vtk*5p >}PlhνNQҽ>"y0X޴c>BوT`%}J˾oK>'8aEp, #>Z48.Z=:q??c=?@w K[oLS\Pͻ]N  .\޵徕Q~>G=Ӻw?s^I:2 h8&=B?PI?OW8oc >'?p?Cx63PwL? U?_B?w6(#->?f?۱wH?_??r-Fk?O^??ufi=k?lz??/bÀY<?? ߾ωg(i[$)<ʗjari:𑿎dRֿTYP_ Ƚ?Ks??c$Ox+=H|?|g???)wY2> @>???q)0n\>?#h?+D ]L7?;@b*)0fݘžܾNG|0.%꿂󿁝7HEzݿ;@!=TM׈,bf 0>BkR;PRjbZ_ Ϲ;ǿ[HX D@N-gS/(IT<\;qZ9>}` >~ٝFAkD׸ ͼK=]SH_=G> ωE>>3YQCU4>Z\=v?>Uz"A@ƾtc>?Ve?1p̅.>9ꇼ̤OMMb{ȼ¿R!O:0Wh*s%>W\?*?naC=i{C>G %U?=ۂÿTѿMW/>[7U0,mn>n 5cZ2XBe>mʿQIoC!ԘP='oXܾlf8` =׿5T7 ocw?TX?m4ټ=脥о8ٶp)Z,M>b>:>G]>f<A_>\>6UDR=`=>u ?l?9YPP^[i>8L=q?` ]㾊N?o > hcp0依$6e#Qk"kW)->>q@ǾV8>>1Pjde;hHo>Ɔ>`ƒZimzQ>>,>3jTԥp-0=!Wi?ư>|7 YI> ҾrS͚DMjF\>ǿQCu >,>ʰ0,> %XCM#>Y ?>8e=X4\A ߾G>#O@?4N/?ibQw[>WhZ?&>{5>=rG>dg?k3?1,(???M(HJ}5> a@I?ެ޾,>F=ڪ/C>2<#ՙ ˾!q==?8\?'fA>=bN?$?"!PwgB#>9?>[Dǹp>,; =.ijm/pg==EnӀAt=i,+R>U>d4=\bu>^[>CYQ=˾=Ɔ>=hLo>+?L4?nBi=R[až5>C!=2M ྡྷvQZS]N>Z?+?:L><?U?)i@aAH 5=A>VT>LX?K\'yBv+{j>uc=!>?@:1>Pܕ:m]?AY>Ow=HDpJ` >W?9?bl0Wl=ý?.S?T?G:>YWl'=żbZ]7/{b=S3fS`Kv-@n⯼"Ed>Ӿ -*>v>K NG0>/s=l>x[+ 0V? ?W?*3(D#;|>#>?:" _z0V< >&?(j>QM ޾彾NnPz>)9Q=a="ɾF=2O=_$b>ZK%wvE _>2?lɬr9`ӄ>WTm'_=24=>d?-?^^x%[;Tf@!ž[4VBᾶѽl\dwuEF;'5.Dy1>>u׈>i $ϯ~zS>AOHa"=S=o'ۭҿ$qh9=Z(2=m7>)>~+żJd'پm=(y쾇p 1@=a_Q߿@Ի\.()5뉾xWp7 ~8iF.]хI0m= =_W-o|0qP_1վ)OlJ^߾% kc$K'NzƾR _~m$M1ƾs駾:qE5?%_>B?>4>p%C@ ~??B ?>i C=h>>{>>TBEg>C>? >=ɴ>jw> >|zJ=2>4bc>k8>ϼ>M(V>L>OM>G>Š5|ƾ;%$)ѥ"r,`>ZQ]=>q?>;v2>Å$ۻ*Fپ>0s8O>@ *?d>};>.dc(ϞA[/4W^=t6D*="L]=>Y%>͝? >+J_=۩>oQ?/>.wտ&>=?!=K+.=U6+0>ǜ>mv?y?H $>Ͼ6B>.j۸ѳ>ɿ10@̔Q |[>ڔL6T==!P>ϾR?bk=ԅ ϯ>xq`x;Dc= >b #%>Fp=F>YP>,N? 3+0>wBۖ>S@>sѿ31>)Ŀ1rL>S"0>a233DPQ/s=i;u`2#{9/>;`+ BB:ܐàGiE&4O>\=閷>`>>{_a+UリW^~ߤXOlm+o;8*=z>~aJ1eRZvWi⋱LܿC/F-с'79>< "L@L)o|N> "Ů!U/xui#jPp3>$hE?d,T9yz>hr ,f=?U4/p=G>G̿a/>QVu&2D"*E=ѽg C{K6/A)=EpġϿ4.[ ^]?q"k2f,SQ# gfes"bDR\q8F3@<0` ƿTs%aƽL!׿>vsHC9?l=k#!t-> y4i'R*3> 8)9!ć|z ;$=ѷ>X1 =C< /9[@^ 53-^=e2|gB-f"@B7_>eMʾ9>U =?O;K>vc> YS>RrVf!D``>b_>!??8`=Ӵ<b=I20َ= >vK>>ے?0H4?O ڿz >nW=.>m+>?Qޢ?1ۿ{ݺg/4h~F=Wgh9&N!o.Tj`8XlX  Cb+I?, `=qa)Y;q#Y~OQtLAhĹtXͿ<7.9|ȾZ\%DF}|k۾%<d^Y&,< (<?d<)>,3+@RP?">#/E/Y{?i߹>m<*gI? t>ᛑ$hH5iT*ꢐOS1# -f{.%wR=hIRѾRW Zi/k.*Hw{su!] /&l!8]gs2 9I?nҿӍ>@rG*!>~=3/)wv2P;=Ex>+&>["K}({8=O> >FZjA˖GTߜ6eq94j&ln*`EF4gJ&r߿4ۿF1 U='þux K!(P=4缌Rv'd>ex=,飾YɓJ, ޽y1>7|>YOj>N `eB=>">c>OSA7)jt=y>J/Ik:6M$>>sMٿ )g J4&9迬ÿy PK.ahKPo龸u>%q>K5D$>9>X}>Co~>c>I$>3'S1]Fѿ~üAn:*8V.=>Z2Xi=oU0>:m8:1O߿)X/XrТ0Nr&(Z<@! Y%}ͨ 7(KǿL&/8۾TiEJ^*a\A]-IIu=>>ܱ¿==[7 J:G=ҾlrƼӉ(6m>2'=}9;` I@q=gdUa¬mfT Ζ)`b4;K>a5vFb~9?辩>qF_Q 9>ea>\?2X"H.=E_jbovR!m=]ky)*ׁ>8H )2| ÏPǓN=\W0Q>e>Xڿ [<خڿT̫g ?逪=.Sg?Dڌ>#>YtR "lUe "+RX`y4jʿxN׿XV(~߾6\aC an@D(s WM^CBoz=J7&AB&LWDic>6 ؿKk/=0½V=ȍm@M( >}GАq/ӾyHT}<9kj ~EgǿegVC>"-Pz~]># >Oӿq=Tc`T>vS;,хY);~.)Ĭ~|!K>ӿ`k҇?>p">9>@ D ZQ ?ߠ0^J>)w>i9CM~\Fcʟ=>x6!`u>ݿ.=W=9}пl K?@`|=fE;7_?1? ?tɗKSM@>C4>.?k??B?2S/#?WM?3/?+@ ?RnR>?2-ܾ$i𿴔->{$>IIƿ|"-ླhc5̋>X>S $Ib?xႿ=l?,|RR_~ֿT@>Y? ꯽$Sd >IbAt =Z`> I>wb<]ɬ>T14*nVv =ti;sڿ$&BF>kZu܃= > ީc] R=-&e=xG>1);+w=t<%#AB@=ɾs~><6I$aQ鎾?Aھ<,>[h=ˠb>Rp2#?ڌz>U=}vh8 S==dD* VzƊY>&ȿI#9=iֲ~-%#)ɰh?*Oۻ6F9#*=?%>[<Ud?s0=y4^p!EPf^?[W>b`ؿ?> [}#7T+W~縑? k>\7ךJ?n.> #ժ3z8Rٝ6aA)O̱+5 %m?Jٌ>)me/g?L>4PנQ^4=I\?yG>;G3u+?a?}=*7Dx)4ݼv>f){1X;t@9&= \?i>NYh'c"=6? >(Kc v>,?g|? `1S {%p?(F/ ˜B$>tǬB`3>׆価] R۾XC>a^E_v>#t6d?u>X qH$ZrS?5tSڿgx #X?78.t0""r?\5=%@@ '־f9>&Y%f|-ڥbL?*D?`teD>>34'꿶=C i@>""?Y@y>V`ǟom?*)o@ž(R?~)n1rЅ! ?E sfK>,>aHG;f _t>|OK>{ yFglX"y>?N:6)?/JD1H>a6?N#*%?"GB>?{f=dg]?AO>?O /*ڈgCF=0n?w$_>_>z(5?F#]>qk>`"W?vQH$>Xl=l ݇ͱu>%_} A~?>u=߳six>d{$>\ٽ]OF3>f8 Ks(VI$ >μ?5v>b?IX[㾔ɾd`BUwBlr/+>fl>*=n=9`==X½{¾d4=;bQÿ濝+wK>qn>E9䤿IA7A оڿT&m7ӽ81,iz#፿=&>UCW C;s#y?6a ^;@ˊ A?O.Cg'w*8ܿn=A>Oc+&ӝXu>>y$."%I@ >>@'ďXM>:U*>=[>@ mHVs> >ڲ?oyaa> >?mQ7*վh>,ֻ3/%LH>?AMܱ?p KQ!8?޵-H.K`پNr?\hT灣C'?7@XR>a?- ? <>%?8 ?4 5P6q,6=ŵп!:p=IxO+ԠǾ׿0߿-_?n >#¾woqT>w> cX^>?>kJۡD>(? XO=۾0#=>QRn>pk E ڕBx>eM>+TKU|k>>(?p8:VJ=H7;zp*i8>EL%XTo >?<'A:==r~B 2ޚ>$>Ҿ|>} >aIzFvQ>+J:- ^Ϳ9.g->F1;Q39%?l?WyMw>0td<6=>̘ '?P>>jk&9?.VIk>~|=K<vC=ie>R?S;pH0n,>m:FR"h0Zy>Nv >q= $ѰUi`Yg>6*[ -)܃zy_ >K;,i<"`<."2y!]'2GE= ?[IWT>mK?eV\-A׸c*4--o=Nϧ>q ^&t,r\1?!Ft>6(|Sew?G*=腐czĿ#a0l=0?`lQ s&j>? C^ e?Zb i?`:˖=hQjR?vD6=[>0fڈ(?r}K=2=lZz*оa>?=S?e<s=>pT^mD.uK_?"?4/>F brG? ?\=_*?aZ}I2j>^>%d>VO>>Zkؾ//h 5?Ey?4>MxjY=?渽{; &}9>:[S$?s>#Fp;>Q=?v%?2C (,>1IB?> ÿlK2>:a[ ٮ? >6ſ!)1(=?=~=V=>=h? 9=B"#7<=u?I>E_Et:>6 ?/<=rqHg>ToX>GQ?t>2@*:>>M(?/> [`c:Py>Bq7?m>f{料?}5`V.q8?rSXd>E]II>d>)=Zao+/B>a>Nk?Ɠ?ϳ=ρ/&F?h>Fc?Q?(O>z$>w*??#D>dg>Z?>~w=e=b,E˼>l<=l?CR?+=4]<S.˿b|v=څ>Ho%XS=cu >%]O>O1>5oO~k>^ r%xh%l>t*> >E$`꼕~>>Zm>Vl}\[Q ?>cZ>aĹV)=]q'>W:.3'^Dv>;>54=Pk(J>G5O7Jx3V`>x ;ك;qeI߾,Z> <)>gX|@;w6>=ڽV?g?~?}c&tΫ=EbE->X=K=s0S >xOp ؽCK9h7v'xF> mҾFGn5[[W6>*;?,/([.>3c S*ֽd>$?7ȸ2 'T%>[=#V^j/,b_>O-?㍤?d*o<_t??`￉[ͿODQ!%>*@@?36(Ҿd}>L=g:7PߠdվJYg6.>VϽp&'W[>b(GԾX5v`@> =zEpNb">_m=إjfN@2n>=_Ƚi>2v>]a?v>4?:7 >uG?(\>t?W"#>ǰ?%>j?OX>>>R?$X>].Q>U=#>tb>l> |>L>>,>7 d֕;*?>lj{\rA??I<=X>,>l? hE\t>NJ>k]?n]q=?(x?`ם?Ȍ>b?J?n?o20?;?S?"=??r.?9w=N?5P?iD?xRP=GN?`>*9?+=?>?vW?: 1=ގ?d^?G?'WaA=R? d>5?6"`>B?èE8E>~.?U??Dd!> J?0?2a? =T#>>>01>b?v>E?d_?T?-n>, O>>> \>g? ?ԉ?#,R?N ?S>V>B??$ l?@DDZ> սKVi=GeV=4=%p=(Ku?>[?? "?*FH 0I>o/>>ˆ?0Y*>?~R>T>zh,?{'i?s*-?T3??>?%W??dA/?=2@7?#?dl?9,>ݽ`V?CHB?*2Pw=Dy>NoFg>x`>z.>$?,?.?hs> >k\:?-?v>OY??#eE?V.?1?),0???(9! ?ȴ ݾ?[W>9?_>>G<ӽy{=Gp@>?C?oT?S?R=P>֣Y?v?I43>O? "B?"Ҫ?hC(?Zuq?RA?_? cY½5y?lBȾ4G?׿7>M>s?$?X4r=>:>??;=r>Y?y>!e?Z?j?yxp ?0j^? !?Yf> G?՘?8p<&>Ч??Vh+q??ja? CP?3#?U?9p/=ݱ!?l?+m?r1n>w??p@o>v>>"L<.x> ?nP? ĈCOƾl[>F=lp0O>Qh>2?6˧_f{_90>?u>u@F>=1&>r(V&>>T4]>6<>k4 $>>ۿ(>-C:Bld[>mvl漺{=,>X\??\ O?4ø@=&? ?H?e9)> ӉSa>b> 9?N?l?>?$?D.f?  _?俗>/>7>ͤ?Okr)xv:2j?v2?l?eQ`l=?W>?|`upj{; c?֪=?< Ȍe7pX<$W,7e`Wb"!8&O$Fr@O?"QLv:*R Cc=@>v e7d?d02{/z\_޾Obt>߃(QՏ־ ]̼Xz>;?l TG= ]n=ˑ.Lj?x?ĄtGZ.?Dýtd?>w`;>5?B?y?ٻh??Vs?}07>%n&??:?~P轃eE??C?duX}L$?;>sJ?fVEN-q>hZB? ˎPAD|/Ͻ;yQmC/&ץ5ތG4='l>Ք).~ ?' 4U=>z8?"!:?\wI!HA>z%jLG<;= و>=)?.k?=8>f4*?h{ɓ":Q]p> T`@> &?.h|K>pf8? 0h)h>q>0׼\?:@1$A̾=>G4p!?/qbCW?/@0>E=(x?h.<ŭ>,>$=b?ܘ3AF>N>=|~k?r!>t>dž>6?HwBBBBBz?YZ>=jRF?,vֶ|> oms>3L(l)X>->KE>?AgOD>邪(_h>\qQ? ?Q:XPA̿ʗ`S'@?I{0=H"y=迃K(&>OKqF=;&P?h7^JS۾ b\A%.\·?+?_`?Gc7e>2/۔.Km=>= > J>)? c?e/?ڡ?v0?ܜ h? LS ⽁׾>I(LOjhBNX%f`ljY>P=f=\R=Prs0??OV?Ӫܯ??$% B4ȿX>h>Xr<:AL/ZW(e{>>=bPU> ]B8?g>x>?Sj;]kȆ>F/;>Q!_=oνbS>MU0g=ʽٕ>.#l [d>}l˾m&t* ?J Ѩ;BH,TjϷf>CF3?>>80?0|@?#x5p gM]?H?m>*Vм(V>Vڪb% Zq=t>?td?VAW=*.<>\>1?N3=~Z?G?2?,c0>_p H>&ўYm>\,C=t~qHPg'<Ⱦ3>evG  > ==m>!t97>@1Jk*t=(k9=A? .??b_0=@> $??Rvx< >?w?NJ7<[?#y?m?puk_Ͼ:p?q?S S?[yd(4y:?.??s-+*$B>zW?f?^?Ɲ>,n>K>j??W?"8G>|?:t?4g?۾YR>ZT??5?'Z^=x>O?n ?t7xٞ|? %?wJ?uaVY@?Kb0?JQW61Iri>ƿ(V鎼;3={1kfCeE־N+>ZVXrkr=ɰ>{(?X]?Vf4e==>?3Ɨ>Q( &Q }A>z?B>b%%7GR8>j ?Iz>b-`+{L>u?B>{Ďh Lؾ>G:n]վ}þv^>?2>|J?t??u0-0b>3?>T>}4pb^*U߾6>]_dcאʼ˛#? zAaf=F=<?Vi7,55_>@>>-?mG\,>#E> B>~?C+Vm 88>!<>>?PkԿ>v2𾞓Eŏ=ڿX%nu@v=44]L2HC2>ީA~$JRn>Q>j> ?) >5>^)?n?'\RoBCF>H?"j P?Q@t~?h =da@J\&t_=W?^oR*fVkD>2 / [=}=A= >jD%| ʩ>">`6> k?9T=^=໎r>`1M`&0=s!?>"㿽ӑG}n>9=L^>l3H,>uDp= i>Ru=΢=7v>S>3l)x{5[dUL>aoRe $?)^>?f0?-l'ARTȿC> Dg? _pb $)>6$f>09`'=NFJ$<\1ھ1>> |l5tʿ}g>}zh>݃P'Xok`Q꒿TL=e>fL G\f'=FSX߈Ѿ% V޽*N9pֽ&.տ9k3Y?-⾯bR*>u)hɾ 5^Zy} J=7i>>U^N10WwL>E>-?X{?[KϸXϣѾ^-w>VK0J>q*3 nY7b=M]>g8?e?=A,<>M{?X>KU&GD< T?HM??sphwSa?CL?]?.g"!fz?/:?g?zD.߽>?I4?>Ytξ>?m?hGp,>u?T?Pݵ0X">/\?76?.Th~ž]>?X-?W? \!? ?n%1P>">?^?0p͢w&U >~X> 2/>@GQ;>"[,>fվvH%> w?I.?2?f?yޏtˣ?;?>;S(lq>Ƃ?՝?FR1$(.?:?j?ՙP>?|?gi91C>?g4?[3f@p>-??b?3+](,> b?<`?3KFIFlf=҇?Ge?>"lxdm=2f>i/>8 A=`;@?%E?,8o8g >|?N?ڃ:"@O-i?.}?*%*=htd?nv%'{sx{g.x?&9D>y!GfEgHz>W>QGSz>YX>X>wֿeXfUÉq\1GGbؾڐ'u>>> {=ؕ?92?d?64HセZ>{?{2?{+ )#~JRƬ;Xb/zF5#>lgFBEC֑ɾzu<>zfHIGoJ#we>.p]D[AQfI?8v?'?V,>q?-7?-?Q+s@i<>c?_?v P=?UjQuNN@>O?=5T>lho>6rsN<>k?/?,Y8xq^>Zd?fQ?c~:p2Y过ֿ=* H3d<O.IT$O |&>}i4n)(|>k'̿4 -P(%E1j>]>=uˁB<=2DAt>%=Ct)xX?j??ùu ҿ07X 9)$Ewz CpB Jmÿk,>=73Z*"hA>~>?V?ऻ8T?>>M?::>N>K.?P?+?,Q"?*?n[!(Ũ<??w?NrR=07C5Ⱦ]?> |> ?#>!mWw?V? EP+]A1>j?\'?X #);^<:[?X?LP<:4;s??b0&!hnP/>o?֕?O) ="7ξȵ18>Ҁ& FȠ,Hi~=W]>?;1=D?ɰ?${LӾ?j??_a$l=3 [\)cd=dݾ 6F _=%B/j<=->H?S?J8F;H>'5=;?>X`=!>?yG?8"͋QU=[Ы d=xK ?\- U9D[u::P>˸?]z?"d=Vis?ͣ?]?Psi ES>[?['?$=i>pۭ?:?L p7?=/ʾſ$Dc$H?,=?G?WHM?Zs33?K?S?}3-TڼcGcY\`dm>=0`vߧݾͳ6u`@ &?>"!'}NG;?)i?y?TUw8:%<~x??V?JPr'T>R?+?"z4ľi=09&=ic˾i #=='=c?>do@b|G]>N Lɽ齰D>>>uPS>2>>*OHx6?!gbav Ad>2.Aecpጇͯ= ?>F0P|4A?=j K˿:b2*(y>dؾ>l>IK47 >$2s~(X t>-/>3Ǿ o>N<=hz/0>J=غ>>I`?k>J>\Cp0>'yP?5p>K6>。(F.F>2@?vKV3'~=犿+=}/˾m@=Vⰾ꫾ w#=Ʒ&ſdA3=ᨿ?)!I5% EzS>5q ->ޱ<1[W6ץ:Zþ <eԿ ؾ 5SV=]-,>`{5o' nLFƒaKf0g$Vʿz =@jV==?;ڥ'/S@ 9CQ =Fއ 6;2>WЯ>:!6HkF\>M>gZ>>Uqɀ%_>,X%?,J?\(/KK󁶾.YupH4=߿;T0=I=Q@(Z91lJ=%3+=M>Ǣj>oV_>xZO>ڪб:ɿp \? xfNϿMk,_D|⾤~k ľC$8Z>E>je?.?`N<|;tX>G>?k]翔޾ϴK8Pح>ir5#`>6Axα#W־">B|>/>5>;9pm>l@K=~zC?Ζ?- ?Ṿ?*ӄ9.KM쁽/+=X*9cKQ`=g>&>uZ(,@Iv>3>>M (>BRO 1<6ő=U>Q?$?V!C׿===?{ ?3cB< >qx,E=>Eә='>b<,oaxE&=I<ݦ>MǬ=n~TETLX5d( Mg=S Խ?=U ;+>Y > >/>c/M(Rνd7'`oHfp=gI=&پ9>fǾ큾tF iY>">1>O\D>T;d><(p>-MI^BВ -9# u`_O I` !KWR.}缨ؽ.j={)> &^J-0=)>gV?|'{Z2** < : )>2=)_>GAx>>i3?1?BTaܰ|>xSϫͼ=R> ȿ)za83Y >z =o/;O(G>lZ<'=>RD?JC5T='J>. ?(?7ZtT=6=>6e?`iYosܘ P@^ 9>%<>3j >o=%}>v?hy><>>?NY.<*Gg<%>?X2*Uҿe1[O- >2Xa]=&p[i>9FoL>i'N.;Ċ߿RN{2KU~u.kϽhR85Hiv21˿.QLEÔѻ=F鼟>>字!M4r@=;>6 5νtzNT07ӿ'>I>z =xpTrɹ>mf>p>S3?,#֪dz>".A.>\\SKEi<^1d<$(ڷܿag3O ȾAtN%6}oO@3gAQlW\2_31uؾk~N tPYp6&>fl+E07@d-H>ɂ>=@ܾ /ɾJGпE mS0?u>HԷCa㗾4׾@h>~>=g>(|>_cM0ͽƬ![W=R Kl߹e``FǾ:ӼvCКܪ<=J>!>z*6D>Z ?x:>gGyyF\)?PQeH0>N(* x04;?L]OU>YfEgWx2&c>Zi8Ya|k4'o&۱-?x W2#\9=E>*> >~)V.=]>I>h-m6@}c;yΎwQ.YO; ?!Hģ P'0?o%Wֿiw\Eg%S A4DᆺҮ)if:Iw"a|LJ>_=5=]p7=UŽ'.ڽ==Sr=4[ 7>+ϥ+ϧ!&3T;>?ma@2 >Q=&s%C=4>Z3;ɿ0boJ&;.>Ux,D(EB?nw->P>/\eLc Q/8c'Q7˜>lt>{6><,aW=>)=8v> ]*>8>#>hf=[=m72X>jGbf$d?fjQLw)I<\blI5^x2jEc=M]q0:n=&K\?S]=j>ӿ/O6'b оnۿlTz,]MŲ @`(W8vUKi@m`f3>\>3_>`Rý_BE f3h_S,־a̿ĿˆtRs޽XL>ٿOk'B4悾}Uu<'1( Qн2;ل;]W#+; ꫿dM?zU>0fg] ="c>OrqΊbroR=ھ^=<{ c4K..>>x>bv8>P9>W=zp=H˖7&>܇=:[?M3]8&N "k/ԙkKBSDPmTSКd,D vmP\'x\P:+<,=lQ/?= j*Ϳ_?>'ݿg?z}>Y-#ac 3.'8V/8L>Z!<޳MJOOqUfݿngsU Ib%Jҿɿ;l}tQh@RE_)IT+Qi:.7bU`e^v*nBcfc/j;z%s09tMvhxp?6IFRQ.&Nk h?.bF>0y-7qy)O?>I1Pʿn՝>>%V?t"GxJbFžu>*V|(f5ˣ89r] О7ʿi@?h>#;uLۿ*ÿ$ Fܾ1ߠI½ !ǿ#>n޴=$/0`<'Iڿ +!=пឝ߽ /HMq) ?bJ{~Y*=vO95D!?ӆ4>>e|>K@1bf?8>A=2>w迥}V<&eϿXqY)!9U%JtT;> Џ8i=̘>tYZL?]!>Ă>F=,\ؿC==2>C>o羱Ϟ>SΧ> Aھ ?}>o=s+ܿ.s,Ծ&J̫義>ծn>ӄ?2rN_t?ԓ!>m)V>龭 =?0=?Dw>g>t= ٿg=9jR>c}`Tǟݿ2 =s`?k' >?#[>S>3>ΉZ=fBbwѿu6;g>aPvT?~6>?/=BRfNY?oN>?0=f -cv?a_>N?H>0Kh(? ! 1j&uË>dzp⬿@}='>C렿Ϋ (?)*?Eῂu>{DC >a>y[E` d?C|@7ifE?g07]*<L"?;|FK?\t?jLw ɾ_Ft` r>KѫB]EYU>j׾& " ׾ ? RiϿ!3¾CR?2($%NQ^f_ ?V7z=4;q5W'J?>ֽȰYj|_l?Gr҉?+؂(?(NAe3#bg >񢾨`xjSiJnv>UF tvh #?S"rHT@X\D 5>ɿb)__pG>~خڿ)񄽊gb=FHֿa,Zb_>???@3@et{g+?*Ծ`{[`M"ÿn?O>[#@?^H>sf@gϿhMAB=x`?Oa`L ==eMb>%)WmH%D= ?ȿ*'=ɗoZ>?hȽ&6]?A>?G t&ƿCd>U2?=/>ԃ#&(5E5>A֌>Qd(_!2s;>>Yk+=l?k>H^?C>%JcѦ:2~W:Ge>pEXqlgھu=SXe0>9=MNt0@>&1/d Uh% ?g>@.tY>e%F=`$z:`D?;;(|aԿݏ-M=>`WW4v/7U:bg>>kظbb S tbR?{4>F>??FS^%>? >KT\`='>c,b[dį>i=I>J}$u?h:t>Vl+>AcL+?\1oe>Y >1s1/t=h<ٞؿa=?&ў L'\ǟ꘼>ZSGI 1} ?)ᅦP^Bni?J?II]oF>>CC俉; `Ҽ>+o y ?>fs7뿸f`^=>Ŭdb,: %ı?$K"^wS?< OR?Yz)n#%ϐ?)? =b"( :޿vs>5>?u Ny<8*Ǻ=|:|>2qTg6>?v3A½&=Vl[o_">2?R53m=PX޿IV>z۾?a"1]T(l>ݵ? M.K𩷾3?u}Jp?Z)h [s9u.4NhBB3@@=ǿ`}\7|T>;>?YiMι kE\!?@?Fh WB> 0>^%DܕȾ?o](9M/bo,p=k쯿 Ēش_ =!d"B| 9@LǾh-8ePR|?L# [ah6?>cxoe,\g?yaǿ(M*0tQ䡽%[>?u6k;RQ<%vG>:?T4HDDf=4!>t?f8C-8?=ĸ>|?)J =J=Cl/>#e?#z=6&Q`GT?2a?*>ܾ>\>.!:4>y+>.踿,!fA>tC>l<#{V\$_=O=>?zgLC=Y;>#?`rD`R??R*&=L?6;Ĥ (FjP=?ʽAT 4~>;;:P:ڻ'W}ADy>4 VL>4Sp MD>6.<0*fjeT;2>?CA%`ib>n?i; A= A? hODN/svc> `yg;Ha>>RgO/|iv۔>*g?zɾL (>`[?!޾o菉3>ސX?xO??NH8>>ĽBnE?N>o9Ѿ۟r?KS~>E5>dɾEo6˾4>49X?2vn ?aE?>{t0Uw?+?=卑"$DPU>ք>?S&MH>8P>8?/>hnB>> =%?χ'>aUl=O׸0s?$᤿QR,>1>?_c>tEҢKf=k<=?wUo3auYa:0|;.?־Sw<=s#?[nST = H?R>\>? F> S=2t\'3+?7>l?E?6iQi> Y>qGܽz_ W?=׼c޾/sI=6>!F5]&=h{>Jt>lu>G/>Ҧ>="Y<2l>?&U>|R>LayU>I>>k=%~=?["2=<?׶>}Qub>1O.Ͼ[־f?NiI>%J>Ax-?^>>QVE|f4ƿ#W%`5<50=A/O4e+棾Q%(!mÿD]8ĬM#tx'>7>K>3< P+0pKXuk酿v%" Wxt/!տ#F5$̯TmDbҕX03xם$ɸϾ'l1Y$ ~g2a=bRh#nٱfBk8Ѱv`+[&ʿU9`z=1?> t<þA#\?WAD{)?>Ev=!N?f>VLo2Y=qTL٥?L>zJIT\?'ٺ>`g?&0Ep?>.?%pjmFk?>>d;~U?>t>{$f0Vm?2}>> CNjOf7>Qjv9E lh:!B;:1׾K>Կ[׵ =ヒ??$vV:_<>/0rKZfX³-~ԿQo=Ŀ/8ROG,A@;>5? ?8µf ξli?_?]V~?b"fuZۃ?.`>6L?+AS?d?s_=?ib>&1{ hБ<|A욿2$,=&Nbܿi'͍aU=N%O=rT=?]}$?> v>6Xžnҿ0=s?_?yx?z>ǽǬg+>@?,wnoɄ>,DF9]kƗ=ʒMѿ(r???V?߃ 6@>\>wh=xn;> >Ň>> R>,kJ = >'=K>D ~8>dF=kB>U>c>>*q>(M=>tZ@B0׽󑒾.=*@*>`=ֽT>_`4S>z[>z=h >8f>~> >1>1>V"ĽuóȿU7? |"?#>?/;DႿTJ2U?P$?D 1n>C>Z?0d_>[?>.>R?? c~=R>\?>8 ?*լW{-?B?z?rmwO?_?6;?{㿻?ax;Y??5L?]/?P?z?Zٿ<?CeoxG)=Y?u>?2!R@$>_I?C&?0~?hPC)>??i ?H:@??K4?h?s2`-?~? @L >):>)>#? aE[>rg?L{?3t?kgBԠ\>j>:G>Z~>^H>?~?|?T-d>|?s̟?z?au?@?=?4W?S?3ti>HF?ty?kti?"?Kj:?&@?U>#W?;m3-E?y?"}ý??Xr?<%Gx?>{?Q:?kHaν^y?Fl>ZO?^2Ͼ?x?;I?U( F6?}=>N?)y7Z?tp]-?ɸ} ?1yR퟿?(>?|ᅨ;TGrh>Ut>3>h>gps=v>[>4>s(yb>޾?׿u"X sX>>tln? ? _pƸ!>UCl<7>q=ln`YU=X`uۺl @}6 >":>=>*> oe>?:>0? =5'?<~?D?2A?g?9&?.-=='i>-`cV=߷>m*??6׿???{H+>!Ac>ó=C>s[Z>Q?q2x?%h65=Z?ڡ?J(o76;G? >*??:i/X==F\?6>m?`L +=@td>߼=?`pҾžKОz>m?sD<+>v>2?L8PӾG;ɽV> _?# ?N׿C?^1h= =]y?v ?&v?UFT"sX;dJ>-? >U? R?(?ǿ5>v?& ?A?kc?XM=>z$d>d0x>=(<Ȇ&J==W^U8;^[WD*;X얿C?I? =?ئ>o&?:i= (? F==j?%G=ք? dؽ?  !ž]=h h:)>Bտ9=1Hw>N'>bZ?]KI?6:2!>=r(>U* *&}xT4wTh?>SM;)[Hk>˰>o2>ؐO?t>x?V$6;fQ>r⽣?;d??A?{ xakѫ?=tl?>c~t6\>>D$>V+Z0+I +>LJǿ\}?j@U?}<|ֱ Ko?S>oE 9>K=[G>H>dF?=Bx>Uf"> (E=Қ?D?א? b!=V>鮒?'\=Z?+A>#?a<+>?? %?].pb>L?,>BA/=>GI>.?Nr"SH' $q&4۾FZ&EmD֚DPP߿<?JIsd =H5>#C,,d>Q3? j<"z=c>`5|вF> ?>.ǽ=h c>D!*R~R=֌>=!޽->. 6۾w>ʽj[S?PA`֬>.1H? X?%\=?iog?& >> _>mP?='ē>w? g??~5r>y?Z:???!B2GV>[67=3=']? ~pB>{B;hN >= Va>ྔ>Sk<>n쯾H>P?ݔD1?$3 5>s=l⹽c,ĕ'>>3a>܋" ?>{?o?n@ ˿s~ߨX9;ha8o M=7#!+>>qB@?H?s?Ds t<\;>3hgX=q[>'X9>޻?I?-h?1nq?.\=GO3^;=)?_>^\'1'}H>t=mz *?2?dA?PǍa?ud?wj@@+kUϽxݾ6q>ԝmn0:OĴ)Dj>6u>y)$|1!>n'w#>Ü=/%ZQ>޾"=?H>7W>2>)N)p?R! ?a_X Jy59qL<4 .D/X2r>l?v?p?j5W;6>L?X-I?D{W?7 p6*?JA?.?'!=6Q<뼑>|W%"@$|=j?4?=?u]v>kr=5~=g1>G0`;>A;!e0>fi?$>T4>R%t>ij@1>i",=.{-D?R $y?bZ%P?lis5`?CZf>P2ȂB=O=QhsA?3 Gj?&6?HO `ς޺,(,?Po?Teg>:ld>q?pW{ݿd_4x5uBx1 owѾ֘>^mž >Pv8Wc=ͫd|N=%[oJ>_\E5>%W>L>)?9Y(*3_>+? ?~?~swѽ,>26??R4 $H>DTX?j?qYqU <6>)??>Q_%>L?t?bV%\{̿] [^ԉIJ[>>N'>\>%[?@{T&B>p>->X?a]77U>?Q3?AA1? /0K???U? ?·Tw=N9>z@?p| ?_>:O">?\`?%l?I =ޡ?\N?7lHxޭ}?3]>t\=Ct?#I?oL? TGHqJPQ˿%=ѼܿD gqVHRҗ7%徒>Cx% ^M> ɣ4Oʒ>h?~|8C3ɾ?5=R?+ >i<@*1ߏ(=?u$>75x.v=?EK>=b2ߕ=D>=K?T|Н>RHv!^=+^[3Cs[}p>nY:Q/& \wyl>:}/ a8>n Fƾw^ z^R㌾5?[=bNV^8&> 8>&ej7A=d߽DiQ?]+z=帽 .?b>TWAǾݾb>>ysh>- /]p$>^2꿻Q>^KP-#0+7k >N+>v&> y=l!\>kxhs*]l>U(>#ä?A_=+ۿOf(HGh=u:䗾[>U۽D>q"2cjU.?=`%[>K ?7 ?/w{0Pt*g[d>^b  Q"?Ƌ!sLڍ.ij(>˓u2kdH;>=#=O?=S:,Pؽ6Ծ'>Oh?$]=߫>"?H >.?͡<"D>9m?U[W??c?#$3;!>T*$?"o>o# >9~?}?`M%p ۾?IL? 5?+ET>⿊㽿ĵA k?kpg>}$dп߿:o>s9>P%}R?A(>Xd>]$꒽L>?k"}>u2aqI<?œ?o?l?[=(?*5?b?Du%3=+>G?[>ñә 5>Y6?TI?b?W8KJ~t?7??cI(@?>} ?aI?cݺwL 3>t?y?6v: NRl=?C?Abн+0'

q?7@>L'p/A=l??y}(>Oّ6?@?%?tѿ|P:5v> X?e?D?uv?aU?Az?#>?2UQ>R9?"#?X!?UOKW ???>0 k{=E?@?;@1 U{v./ʿ;C~=D \R[9Yy%X YX?OѼ?6?v:4I jӾ?9 t??2;td>?!?Eo?#' о$ =WMY???;2@f?G?y?{pbKJqzZ?c??x[-Ԕ[b>>~<>N䟿SxV?>  nƿ]}>׿\bY*T@Hξ'?7I8?l?e mۺR?Z?\Yjw¿AbC޻~Ap)y7~9$1-8Ic>F??*2 ?a㨿bT ď:U]p?G+V?`B?_h-Hr>j?w?-A==Ǔ>|=n`:YG>_?]S>T'Я>C[ ?J?H9>?my?dx=4?9?75&'T> q?yw?sdCw>)?cK?d@H@ ??$E A=:?8?;*Pfc\[>at?~^5?3P~)LuP":>Bt?\^>9?X_?/0gA|>=8m?bu?mj%e>!?K?Sx6eҗ<Lۿ jƾzb7 > j<=r?Y>{"(=>a??*O>3?~?EP\==%XM'p5C4_l>>6?o_N?R"l䑽^>r?Y%5?i2W4= $E1_c $Rx=h&T3=7 2&##=4?5}Ne4>+S??إ?A0Y,,*"Y\> H?/?UF.E>^M?A?b9b09lY>#n/zk=\>;:se?~=iWQH?D->o<.>?ݿ~32>HT?*??<,b>%>zO?,v>=ğ^=jY3Al-ƾԾZy5>B>?;ZS> )=f? ?(0=9~ܿ!ѾʎIˌ=Uf [\2ab=Gm0aؿ!hp0ɾA>.U?w|?ɽ*ژ>0>1?,A>,%EȾ >G)Wo>>}'o>m>U0? >M)GYC=Կ u x)ܐ>>{)\?N<ھ.M3ʽ"r綾6 |%%EYu[=Wç~M\N߿>r35>D =>>(_>sq;Z>3*>P]=:|G7Ტ2>>"xjB>6??7++zW]>O5]?9?DƂ D;NxӿjEkfM\V  !O/uC@”=\D>F> i5w!;>?>D0>*>C?.>+/F>!f>=?B? 6$> />G?<9?|KlP=7&><>P-Vj@|>~?s? #p+ >m>"@QK>L?T`?207;х>^3?,u.?^dm Ft?f?%RԲj8.Lĸ2{+tmgwG@!=a>>o?MmKEIs>T%K{8~>~G8@Bq/ 3)>ӽq\=^]薁=d =սd=qM>OJ>$yս?>\>=ֆ=gs>V> p0 1/>JM?17?c=}=,Vm3+<)>?Q)0|p5>=-??G<򾗯èa= >ξ/1&>Ln =g$\.>Q=g>m [Sn^^ؕvb={]>~J>-vE/?Z>\j>r=̿z/`>>F5>ȗ=u.=gap5+= > >0ߜNsw޾O< >n<>3<`J.m]xS}Ԥ @? ߿ lC0P>q=`p⾫C> )>>59>'? q?1j' x G=>?(('|Ф+y >[W??B2g؟}>`7?1{?:IJ>">>,?N _ey>>w>P/)).K4>b>T1.ۿegfS?DSAʊm&< _&#CVʸ>s* cϞ|hL:_>tW;Z>e>/>?=J8B)ް>>쨠==\5X^<>w?9H*4=q >8?Xq.DZP<>>ky$Ud7˧ V ׿xArC1Hs#ygBw4E%ӿ<w0*ǽC Ŝ@ N PED4=( ɔ>ϫ>r? :?5-6L·ʒ>!ͻw>-Y0A#yG2]=`N=곿 piy^,T'P<u g@T>+2==> ŭ<!ƿ! d6 s翁3+Td0 ʿf,X\ZO|LZ :*{y/ O)b>I>ۤ>Mg1K>#u#k/$ =n>>=z<0͐ eǿv,a{񍬿 ›JCY߼Mw=i>|+;(O2sk=>W>I[2>m>?('0`0ۑھ5_]>6/cN&Oۿ0ۭ,oՅ2>Cxh?N*N?lT???*S#B>U"j4z's.R&m>xjOc,h>uٹ1;-?=(Q,J=>?9?Ts?sr`,&o >?֦?.0>x:6>9բBO=0{SDp>H)> n߿Ag˿:jMC>a1O7>/撿MFEIVm>BYX>bv#9+ԿN?aĿ#`>O>LԿ͸/f?K PGk,=ǽj.f;!^+кJ=86,?bӻ ty:l[K#)@Z:4F9>6B>IWB7V%΍v2*9mҿʼhL1 о4>9o9c̿8N{=''k%f=dF$Sֿ\YSE,v<: >ƽ> b>q*A=r>f#>>}>q/pȶR X=1S>Hc|j1{?aV!>-4?Z >d?ܿ+>7L>zabL40辀^>\ӿwi#+9.QU㿋࿗f08lǽ֐><=32`?6? *I?*^?0=ڼ=f|l?6H GOeM0ܿ}+X ,uJ>|g>8JQ>we.>9@8(mG9ҍ>d?d;-3>i|Hm;?nj=>^I^G?^A-=(>ֿnpàY4}$k dJA JPA莾œ*N`Rҿm&"|S\@1F(9 M!.,sm=齄d;P<tDJ>> =T> @lD'B=-A<}Ri=||Rc>w/^=X>{,Q^SڐCf(/!!˾i' Ͻ@x>)K׾&=9uy>üMB]>}*v)d+-BT&aPB9F3zX̚"Ⱦ !BnZxͿ oϿZ07 [->lw=ƀ<$:?*`W4`Cƽ? ؝@UQrGnܿ;5?kuٶRO쾕^&5 O/o3ڿmUׇ4~[ww:R2Cv:|L}N.^]pII]b!k>r?7dпҪD*T"׿2=ؾZ:i N(Ѿ7s"lӷ;y>'jr?N!s-bt=%L# {6*.L"F1&WnY2X<Ӿpl4 E?W=m|KÓ_>3>Um? :;d9k)Z+ekqg w8~*X 90CuFT 7 Jo|x>u=GVpxž>LI56>>"Wr.ĿȾQe>4@iޔֿD==ӢY=2-l;T [>l}Cؾ?ԙI >#@O[dM/ Eb>0U`L<1޾$OrqY?3|>e%??r`dTr+V>",>忎JؿBTݡwv?XsUBmXǂ?)=¾k@:l >ʿWxFA@з={[<(8ڿLU޾{>>d^ZE=@$e|:|"LǿP>x>^>JYC>d?t{>>x,>V>ѾӼe?L>??',>޿ >ˊ? K4p>=K?>BK=eY:0s:?<:?X=ϗh]>?{BԄ>>_ml8P?𿼮=?ڭ>/=??L??!?>5?|>?r>x?7>AW!?ŋ7>?an>B/F?J->M`>Fu?>?7?:#Pӿ}*o4> '1U/>ywY`>- ?y3ر%zY?t!SP"Pe>cѿ}F[T>ܾʡQ2 M> >_'u=J>{>(q%[2=:=EԿR"ܿ}&9< J=Jd9Ir?#?9|Q]pM??+[7>_?h?@̷o" =S>=ޔt)Q<*>t";ty->0 ؿ,п` 쾻h>yݿ>7P¿o'>@w%YghC |x< 5o*I\_r<ۇ&迟`F >BC<dR)#>1 t͖ )S0>%=ۉ^վй? Ծd9>rTmLK ?D=`SV(ſ0{e>쯾a*;A Y= DR#`E? 'Nyľ?;ڶٽ@\R 3#?U[W5 S ^?)psbn+>O<.?9j׿dH|U~E=Ȱ>߀,&a}8>]D?^F8ٔ )= >zYP~o>?OQHznFK?[J>mL?l$Ѧ>:h8>?_Qtq&? JT>;?`S^XhF>F>г̉osㆿ{?W`鿁?S-> P>3s?hp=ST@wwjH|>2>I[ PXsClLn>7>L-\yBiyS=YC<ox=x%=]:@)>S'C'b>M1y٠-^>L=Wa%޾H޿: =NzzFT=LEȾ,-M2_<>!>f#]༄P.U=/>ݾf%P}=>}񾲿u"`߾/=]=I{vCF>N?1!W@#TCݾ[aq=#i4ˊ׭Ѽ9{9`b>#0-9-ֽc=uՄ @P]<$)>G@᜿XGgBbS=G?1*8}=%6=K>^60 =<>Ku%|J j{L>̿iؿ+sn<' >]3ƿV !m;> W2SV&>g??WCc^tQV`F9ƾ{?;qpZ@?qՈANNp>I>ʱ-?~ǾuMЯ?꿧Bqa+=>ka}X2">>Q?n U`%~|>/4fˬ2o>Pο,v Bv\=:h? ,`x=PSCe&.=U>q?7aٔZhaҿC4? >JK`#8GA?`\6Z&+prX%>tXw>`r{=V ?A`?>Pvg>H?bZEѽ>?܌n߹P >{>]g4)p43= 9=ھWҍ<:;=#Afy X>D?)=M^{>5^i> > ޾u]pCk5>fAp> Ӿ;ZbØ>T%=*{վb|dG&L#?sH$ q(yҳ<ۢ?N XĬRt?,壿&~莽]|=z?fl%M`8l6>2+,.'4g|g> ዿE(7=H+zx/ljѿ#؇>Z[?y)_Ⱦpٔ?J^?|NB#"I)?"? >n$IՅY??t?Ϫ>?Y1QS=d>:*dý$?)|P=Z׿ ھV̚?Z>#?=A pcj>@=0?(gŸ#\D>>>?յ>Rn(WA1>3>y:?#>:Bf#B=?`$?RV?O3ju> %x5?fE,<1<ʛ#?^Z,qq?Ui=;`A?* մW[ݜ>x{[?^Ⱦq8`&?x&Gq3渾\:?G) B[0??=.*zO>VvR?F4_A ,?(^?A=[c?33=a@W5K=܃?۔>6P!}~<ܵ>8"<н+MCl=>Zi0@˿?>.Ӿ& -Ri?x\>SF' $J8F >s3v٩'7h`5eI>vNzjIMcN=L񾜍;הN{>׻0=h,=WaF 4n<ƣ3S"cK죥?>jy>oAͯٽZ<$zXfGe`c3 4J{YN~?~m?Mڌ? ;eD5>B>>`2#@ >>:K>xp\? >>RzwfvU:?v-?9a ?Qs9T?YP?w?1xho7q?,D>շJ>kQ &jٽ{1>=l>.\[Ͻ`>0k{ʽTZǬS1 п6l>0*"=y>ycѾ'ΘN69h׼[ ̟Z?<` ݼL?1?*˰<1?n?y?TYbfc?f?of?>.={{lvxvRxN_t>-8+kXH=|ؙ>䂼(Qe-&I~>P6==K۾YDJD,q>,:C><Ƚ$ l14 _>غ=<?#,&T>a>?)q;U>04>q>-?D|=T?"[>\?-#>? >5?t!P0>>>6>SLu;>P>>J>7?|>k=1wΙ >'ȱ>_Ǥ>}<=v>KGk>4&>8i@ľFxd>+;@o=)>> n>̃=y>Z>g>Rs^ >(??>?ht>S>PB $ =O=Y{">h>5xRe#>N>o_Խn{2>Y>p"=v6e,k5>N3>,Ź$\Y(>~n2@L.tLQ?.I,?Tz?J h+ J?B??pp|)x >5 >7?nm >܉n>?`;K=/>23>CL^>UZ>kM>>Uc>8J>Ll>N 2<?!=d(N?bg>%?2#,k>e>P`x<>U)=>œ?>?@xٿ?9IHYjR>Iw>,۾?jX>6~>k@>T? ?~a?kI*>S>|=1Q>V=3Ӿꧼ$t?eu?D4Y?d?Nd ?*? ? |@9?-W?"qG?TL?#LA`>:??j??lVO7p\=R ?\)??zt\?:SF~=G?H\?=E?Xg>???q<_t>C?tCp?{]?à O]?h</?Z.ܟs0=?q?]A?@y>Jm?^?B?n]! ?R?r}V?h;2=?D.E? ?Pał=p?d?O&?-!6E(>?w1?z?sRͩ>!g?4?v^?e=Sh'>9> ?A{=S?>m/?!"="?>?(?a)x>D > ?K?Vz?[>&>?6?A?>M=>k?'?d?A1&F ?AF?U1O?p*?LdA?i?4UW?dI?M> ?YDxtO>u8?? ?~n%4?t/B?8?r> QQgfgB'>=7?:=5\x>&о #x=^J?9 >]?Y(?[%o???5Dp?.&_puG=ڵ=>[?lYi@&=Z>>f?Q9C?_5~?iL 3}e>_[2L?zʾ ? R?5wl@>#F>90>|D>! =RTD(>/1#03U)=?Y>?|mu?^8^O^<}t=/?6hEyüݵ>= a?$0<>iMgSY?PȊ ;>!>6T>h?i$?v>˷?c(c?V?#<>ڶ?0l?Lx?iQBc;\>>E?iQד=i'>?Z?hC?Jr\0;3>"p>`39#CO+m=Ҟ^j<=Y>d?K >-CJ=ҿt > \>4$>  I>?-W(o$R>U?q.IϾľK>-TT}F#>h^>tG?[k{됿*>T??t afiU=4>:??E?Y B?Ua?u3)Gݱ ձDxc/لH(6(i$$I\Q'Zn)\ͯ? ؿ\;ڔ?1$LgEqDk>y ?NO G>#>8[?LU,AP>do>)1?Go*BDh>cf>b?U2քa3m]>.>?k}tBNp3 >P>˻?nsJxb= r`?SDžXſ}9ڿ"7Dg'?ѿɶZm >u>$? N#??8\??p2ga e =ɹQ 4+= hf>'* m>>6q>T>>L>aj>w\u8 +>ÜRy?">S><8?=GV?f֝(\vZz4?$ h(>>l&hb,>6#T>s9 == z=hǽHVr>=լLC-y9jj>>H>K?Fҹ?R=?AemheX6>|BЅ?>R" 9Qa德q">x /M>= 7 ѿ"1QUZCZE /ŜVtBB!rm퍾׈q>[Ӏ [.Aߖ>(?LY*l%X#seÿI** {(J! ^վ?+^c>gkKUMf.=$Ko1e>O]?@B~א>ZS,?qY'M>咖?>j"P \<5==Hd?,^Հ>kv>>?RԼh쩾F>>?#F.63^#>~x=4B?@S ߽Q>H;e?,$|DoR)9[uS,6;p#i=!08od:?7*2Cmw Lj>RF?.MM :GO>c?p )o >_iPo4׿q@e =TJRH8t=H4x%Jl֙[[>k:kLǾH=pA#lUVv0  ~r/>s$0 Ei+>>tvzNCCN @<. =@!{f>I=$Z? 6?-^?P >mxľ" N>Po?؟ԇ>Xu> rx^>v.p\y?9="5>} ?o?{O?|? X? 8.T=ʬ>mnμl>I0?>{Y?cgVl6Y3ͼ?*?n?p?8>u> 9> E>ƽߘ?!?<'?+?p??vzK4k/?)??y7_-F>> ?6@4Qɾx?YD?9q?;`?[y?R @?=j@?yE (QX?f70S?X$EX?i-f,w<8>Uw?`?I/?*O@?^)S@>yj@?gB?Wd9?bPX? SMa?SL?s^ >u2YX$uCH= y=eֿ}y ;y0Xݽ#HowG> X1R?^= v:x/Cj>ϕ>w>!)2Y7L;Y"`?$5/Q0gy>L-ھ@=.ü?9l +DOezr&>#dWWEZ?? ? ?:JPB}>>I>b>G?<+xݾVUIyp>@\

?K?.ߵ??! e<\_?及?c@㕼 ,?q?g v?8? _ =+Ѿ ?3p?,Sh쵼z˾?-z? .W彊-0&>ϒ:tN0;D>!Hw=??;e>$=W4澵{?F ->˛?? ?sq@rya̼@>}N?? ty_ɨv'?$?;(L) Yd>??٩4S&Uڵ=ץ?Y%>9B&/K=<)??"BFiH1gj DW:?uP?3HҰ/@?(>c"F$?%!bTFih]o{x>wc8T N>e>Ƙ[ )'\~R>'>$?,G?l3?5?؝!?N?^S???$W>ן?@?6 ?y;o7n?0?\?j;K̠?Dq?7?ÿk#>XK>td?:i?vТQS~ľվS?3?(S=~%>??g:>`HK(=Vb$?  r@ڇI(v=q>W4[dH?6Y?%?BN5Rf?r??^5pZ x?*?NJ?Aca:HGھun=c8q='_ɹR?!,=L>?F">$*q0h翼x (!07*(+|Vz+B<$'j閿D= cwdǿnƿ^d տfsԢ"}s>cؿ,1{?1g!&Y>~?,>R!>#b5>R?`Y>.bQ_-O4 QLUN3E.{CȿBUȠ`M贿&?&1dҀE$ c)m})vr B:*Cٹe19#:*ؾ%&203~Ծ$W+M񖷾 SpPwlŨ=OLb0}$!O!Y>{BO.@pė I˰+ZOڿQZV=|-e裿hxoDJ>\x3{7ྺm1>j׿MwٿMV33/~]0k8?/m??+uARtO1e0gp0$cJ0bjHO.Z Ac3[ZKM5da`1_Nʿ/>1 3ov$->ԚDK 꾁}=Ęr/0޾<'r*6ο7ՄΙEZĿSTvKaXC7>@ ? ?Y?Y>>2>$*>؏!?mI?lB>ЍP??K?27| Mi-:ڿE  CMw=Xn!=WB CȎے ='п_ja6ֿ $jv>q\k[a߿\6>D\6?e}?' ?h׿#64=?1?~ ?9VK2N>/?~o?x>?t0J>f?Moe??1@׷2X.>?yP??p'\,='p>oX?pOL>J.=c? Z?t>(!3h=_?\?o?je p7Ɏ]>r?lզ>p4 ±ggL ξWT"hY^9.D>xDGg'ו{>;9 _@>9GId+X0>`WH@+ǾsvC>|IӪ۾3XȲM>T} "W5o֕>43?q{> t7иk>U?S>Cɇ>@5ο<~o>ha!*o" >aJ77뾜Cx>E&!ɿ˾{@1>wG@ Hy_2>sDM,þ N6=G>>$=AV2<e>6ͳ>F p>_ ?6bV>rJ6!`!F9>ԏ<;^L>hH88-FK# 9;2=cD=(>K־W=5*T gFP~h MX>fE<#-a$$|=8VAJ E 8)X`>UſcSq > Iz3FFP>%a.~38ȴ>>*ɾ)3>D=~ڿK+z:60Lf=ȿ*$%, a-j=ɿS_Q^:#l=ǿ,$p.FV;ш=(,վԺR$`U%:?=?~?9#X 2{w2=nv̡%8m/8뼿0#6ּX =&[8=@=*5[T!(x='RT%#玾>a)n>u>?Me,?n&\=׾6>n6 %o>1w>5?>>ʣ3wx쾎QU=-H?~&>OvS=;1l¾)>s2?@hE?f1oͼ#`¾9;mBW4Ez5"(= Ip0uCJ>y>+fʔO4r\=e>)!:>PZ>rA`?&?8pvd5, \t>k{>NJnH,j^$bZt=PtUĉ@6t4.? ɰh>?u>n?!޽>?;?TTJ>Ah?;e#?> ;xI/[>z;X>Ѧ:!ʞ0 ݱ@7>0>,>Ƙ(ݥ>w1 ?9?i\4DB<>?3G?d fE־.22>,H.^BJ7k>?p>R"5W[))=k>>|>!n۾n?$?Ja?=Wٞ澸Ľh!rdh2tKѦic\m\uxX"wna,_WהBSt[Yſ/( ƾ*ɘ+ɼ*#S>N{>xBo <&> >?wn>4k>M?=kُ$0ڿ ,===M׿ '>{e5ڶ=Oj%*d>N/w >MM#)>w6{>SQD=b /*|v=:2akQ=שm>Q{B=Լ~2=U<%>j+ݍP;~? ?j}?|7t_)|>R;?9.A?lAA\TM<3=p >?%5>u  ٽn^)C>|B֓tX=t>1> p0¿r=>"2_#=\{=> [*x>Ϣ}<߱>9``9Hw<,>p>C9~Pj>BH>iM>w^WǾXn=U>>[\Yp?7?\s?unY\ZS>.?H}>پ^M>oV;腐YX>` >3L8 ;/?#.?v?? ,> ſC¿5& `$t>x>?82ϓ>-{F>B[u^>Ia>s>E?B t?u('>lշHm>W>a>W%>?)iz>j>jn>+?=8>_eV? ?00?GC+<8P4->^>>|?!8X!j< >->q꽷U=Ac;p=g>+ =${^1+wb2 uh9˼Ň=\@&h&=D]MkɿվYѾ ZP>*s>}w>`(>mU1<ͳVAvſS߿C~Eٝ^aD4.#8UCtG=bZ k(P@>!p %rb~=l>|<+ND̿!Id*FԽctҿ?Rۙ`׿?ݾ"=9@+=0f<_=J> &F|ѮW<տ_%.00=>Ȯ2>H?'axl!>d&hӿ%[#*>`u>"[*!1-Fa.}d2.ʬϘ,].M<1<Da0Vqص$ ) 9tۜ=Q?? '1?Q/?W>ο8˿.=7*QioԾ5e=?X1>Б[bQW`Q,`6a=EZ]ñ(ѭメe>Oۿ 1=.C+?!>L5`%?\CC j=>okN`MվxVA>#$_&x>_?;&|>">#9yr0 >s>>C*|':.U=J..16/sqKZ=̾IܿgR3tɿ0|MY`+8[B il77']>>rr>q>ІhHP=HyBQ!Nw`=@F OjfnU*%!?w=<ٿJ@Jxo]I`9Q>e/|M4<.>Y]ŝwsG 6&k?l>o>>iQ?OE>{2=>i>`A~B5>ž>k>v8gO>X>~^h>Ah\ؙ<=;)-*[->0ĜR 8(>RؿRGoh?z*?.Z>fAD,#W??,HZ≯ J$>$iD4_ٽN8v_=[F>fJF0DsbC),TD?XE>=`?2Qvd+[>ҷ<]b&œ=z)G"_^LCin=2 1,0J熾34duopˀ6<ėGo*_;.\1M'`6|ᅮ*.=13jmѿӛf>osX ZED>#N3agEY˸7#Ͼ &;ؾd |b%`*MXvKz@Y! xsOއ'/Z^UVn LR*kw}.w￯/lu2=yg˾A!?Azn=?9D!Qܩmn'֕Cr!A= x@x׾g+cx 0=?Glξ`hA#>&?0/=v CB>1?>e3R7To$ؿfI6F7ߠ˾F>8>9[: C gk>.>Sp>*7iPn,Nw>N߽gi#8;zt@OYyp.}ؽ0վsf>I(TR=OQ^辴~>jC=Fϼx 5!@d?B.'1v7>hw*E7Z/6Rԑ>v3p3T)ž3j>!l⿜*`V>VJECY@nϾҿYJh8~V=D|Z'9fF ω8￁F5$Nbhmdoxl/)۾ҬC34$aAX@T盿F dZя>>/=ٙH龘)kFfչfȨ>U #d?r $>V(@{kYݿWTc U?N>jt?9I`7XT%^'9县oCy]V17ǽ}߇E!c^}f^cH08A^T?N)'1=wU_f9_$?=G1 |񿆃?89<%=B VDe_u7;>?;+hjyv>=_.炿zxG?d\p=M<- y۾9p0V=3o>_q>Uȿ 0#HA1 X2>)#^MhT*6=y/+w_rt,<6@nD>_ 컺SϿOT=-}|xpֻ+܅^J?0pv==e|=YB]>eoj'($10YCy8>HZ>jο#h3)YyȽ"Z>DR kk>2+b п{[:žK'>ܿWɿmʍ >Ƚ~ E 0D !þ¤? vѿI{िl_?/?޿g>a>6տ.?M(9=?Z!>>4w?@֡9< ?g? '1>}=_>=N?C11m?S~O=+̟)!!?#>P͂ ?6?>6]ωI^?\tT>`dƗпJ8Kd(?Ͽd>aYžr#?Dd$>$q>h׿ҳ?3= >b[?́>1?(4]=^?>c?6>1I(|?v>iXS>Q~\dk:h!:=\>¾ߘe < >羕 jƹ >[6ݿmԘ=pi=?>{SW濌XOLšg=">۾"EwѠ>IwN>пhם:K@ٟv'9>sCȿtK^_L\>_$*o>sA>́>Cȿ>wL *> l;~N;@>s>y'>QE>>ڞoQT{|%> ƿU+!S=.Z>;:*A*Z>QU=LU_B^4׼=5?ӿk)>mE "#])mUɬ*ܾZ%R$dY>6=~_s`r&=kMYl@Vk $u{> пq޿!T>K]!DЍ>w?V;g!B?/V(>??Oıv)=xVV>^ ?*YwdF_S">]K?C&[;6;Li>Z82?vaм/ UER!-<k轐@:(|]Nm4>0Q>jO~S=\=tԲX@=L>ir~ēP= >ȫ.bA}tH}g8>oz>ǿnuȆ'?6I?1hǾҼI`s=F>kC^[{1}Q:= ?8WO6QOʾM?'?/r&=>> 7)tTC?* ?4d;ap2S]5Of?. ݾ̿+#W~\u=!f?mbQI/(]}<S?iE|NjwLǾE9*Y<,>~gHq<̼>ʿuO `lh<09򻿝!.fU>19>c-S2qsU&ҿG`E>gyal@ K9'?Biƿ-9eʼ?CϾ=:yn͐b ?KtK@A*Rp?3sؼ`b6>sm]ѿϤb>j>e^?gq1hsխ>nj7o7=r">&?%>̒u=JB_/=6BP7ؾcC1Ġz_@'b>O{1 9>m>ʴ?I.pH gB/_g[2оHJ>Vi} 56=?<n߱'>?YRYrqq|$?D>{OnpK?[玾S;eJܾJ*N?qvƿ?hP_x>&5]ِ|p^>3ӀUn@ ?9q>\[Z>**>?t/|>-I>{?AoA)>OL>.?l#F9G=]vhXTE9vA2/>?NOʾ#rW2a;|x?) %e^Z!b= (_?Zbg \? ֿU-$t.!s>"9`?}y\-o&=YɾkpEz̿P=þ%Vҿ6󿈜4+(>?:~ɟ|D=܇<ξd $Co>>FoP^いF<\>˾PS?MAX[>6r<þJQ}|?A[>G>L? Ǘ>=+b>e>M>e?l%}T?>mC>U;x N8'E0<]?^wK-gpT‹?0?j3>9?}T= (dž¿#Z5tSH??5y=&|1j{5?>v?΂b>b Cx?>i=? Am0j*gp|>>׶?? %}n?>P<>1B-?\WM?̖?M=v`'iQL?`-> =ڠEH(g>?]Ar˧@oH?Hi> >YX"?>& ?+?0P>-> 繾A?H >hb>މ0h*1>_ܼ_|E?E> ?!ۯC?m>]1>$-4hs\?0/>.?n{ݾw?}\1?B?aj+qVX>L8=<6Z  i8)(`ӿVcbxA.>T?1>>n>S_g?:u>ַE>j?x?T.?z(tm}?d>N>%\n{=@>&=/> =h>7`9{&|]%??L0?@I=11?n?=?wuz6=q?:? k??Y<#>ջ< = ]}<> ܐ<@dFZ (X9K>3>ME,:~V>$jSʸ^tYHg!??umL?47 q^>p>"-="su!T<>lm>~=I$7>F %= ꣾ />u=>b4o߾/ d>9>ϝ=,?LZ濚R?N*6>p>>#"l>=.n>c>G=gb>ㆿ?vDtt?so?~b?}r?t%>.4>">(#}={O>$hN^9?=>P?$9e?Y?<,,?pY2b?inKR>֞^???*s'i?44?HI?m?GhY>!u?Lk?C$?jZH%>1o?a`?S?Uae?|{?s@?U=O?z?iҿ?Rj=L??xX?nHj1??E?fp@m*= ?l?d?}fH???x8 &?~Z?yLw?\v??QH?i8ᄡT???]d^?h?\ ?vm#hyDSI?gR?Zb?nNqppML??l?._$k<^W?;Z?5?E%OH =Ǔݔ H?Y 8?y? >?h\@>??-{? 5{aM=S>D c>;>??}?ZT>"??x?ˊ?ܱ 7?/ ?pH"n?"8?-&~$?/f?)*?uq0lc?$/?6в=3@?v)>3?2;Ya=M{??)?K_??f]$>>gM?iLfC|Ǔ<"r?.a? v?JAT ?'彠|?V >E>a?eB1g.>f??oJA8 g>??f$]Bu~>>H?e,N?/?}c? Km?ACNd?QP 6"=fܿEx >+ԍU>U t>M@H %?M׾f?'|4E0Y>e>ʫ&OCFܱ݅?uq?zt,=?+ ?Fk8.E/9~>u%l?L(89`~>6v=?_P?>>ޠ?d 1ggU>*=??1\??!>p?>%?㨿Ã(=F|?3?+a5?҈?6@wG>?@hf,ܾk/?|9?3 ?x¢<?Ċ@?On,fǽ=Klz='?+ZS{B_>ʾh^>,>q;?Vj ?LE?.E>jrz? ?Uh>{=y%=@XS7w?+>O"?P@)/?X?0R?n>;!4>V>!׾U>tQ~B9)??>p%8(S >9>K?`iC,>b>o?[Zm@vپV %?ǟ=ZO?PQhxFZ/>P=q?F1<`"N=rGE=[ ?4K]%r>F>;vq>fbx?5]pC)=?>#ք>H?;h}u>!+Nv1E>>}>T-Oj>P> >f˾rf\/>ݭٸ"q-g^pEɎ' ï:۫ɾ6ο &Xֿɺ 􄿵oLn߿n\y{T\q࿰fE f #*[پUV(nO.t>;irGl-|n>nҾhzuս@oa$ >>'?ElAjT (ˉɾ%߾9:{W* V= >LaRL>jb{['35LwYhg> Zy> ?/8Tv۽R>?$+ēB>/?> >)R齍S>؈>>]=>?ŵ0???Sʻr>=\Wr)c%2)ɓ4>QH=cZ>RV>8U>{(G>? kta> [ٽ~J=.[B>9'?L>9ib=&6->]?B?f0'?% >Hɸ?WJ>fl+>WwѾ9.>"S' @>$M=2k>Sy`>PQD`>'(6Հ>`'n\?>NT.==?y .?R> x?9>[=Hl쾮>ok]e\@=n>T#&> ǭ,I>I=㾓.>򂾘.!H>sؾ4 ں>{-V⾅>KZ6(*>^?,?(?? w>6? >?l? "o>.t1>(JUG==,E=-J?ӿ~>=x>>T>Q?Q,3|W>?86?3?I̾q?>G4>?}RLy)?"?n?Q?0f?6v?D/p =>r5/6?9&?M9H?'?<?dtA@v*^>M?2*~7>sY6=9?V`"䦾->+p? 9iVo#>%;?E)EU(yA?+w>BBnP6ʾ˒*>׹_L*Oid>eaP3j9A7O>OJ-VIe>jp V7 "K>d<(\ '|Q/?Ye!H:`q>'RT?1m]6~'r\>R>y<"W&=` 5=csm =؏AwW>"7+E>4h@:0돛< P>,*;ۻj >,=ᾦg>=/y>s=ӳ>߅Seg?@W??vA>aV >hkusJ>R?t?[u??"}+>Ɨ>q>ʹ >,?-?02~I>e?Al>[?_bYk/?Wx?'`@;6>#=ĊY?,S`9t?>?WE2(6s뾢 $JQeE>9 >6ȴpi>y&85gG=e&S t\ytIx9F;?0>w?|Ҁ/28T= >-SA7?l??7R?@WD1@7Pf?{>Y?i5DȜ??$ɐ?B`8о`#>B> ?Hn;c2`9h{?>Ƕ?\v? !?(?'?h8?©?.?b|U?t<ֺ|H݄&+?]0{о-׾N >f~TZ1_b>`):tP>_lvPe1f>zj<=jv*a?B`=j V0f>Y>b>HuH|XO 0R\3=4 >W!Mj=G^kq>bB,F#>'t>~*>l?;?;(A>?:!?%?;Mp?F<0?DEqX?4aҼ:{=?!\?;DV=r5<ܷFx?\??s7v6Yϸ9=};*r??f̥x=Ͽ2?oˣ?'ۚt5~?t >*$V% Hb>1b5d?;e򈽌h#>u?V`H}fVu>>5T?YF,>@E|HK3<@5>O:V y@ >2va[mYg=4=>A??q~?~F|mb?͇?lk(?d?#& ϟH[?BE?(si RU?N?> uJK1U=67?^,>(T3^>?W6lT8O)Լш?䊾dTy9 (f>9Oo<l>3Z=x'?:A-;y;y>^>K?ejHxi\ѽ}>X=(|??L =lʿ%XO |="g{Hf;B> deh2#>?e?X?,x/(=M,8?~G$?s?;XD+M>?x?{B?wr ol#ľ?z@ )i"E`>[6?@->&_3dR蒾[K>?K!QƁ$s=x@4Ta>4.ar>b\c=K d0>[=.Win ^Cz>{?*7_=>j‘SݽCW>yM?@?PsoѹYd>?P ?·3O0@<) m?>ia??nK 4G<>?K?9Rx9g??,K,>-A=Q?%QL5s^>>'?2k1-lw>vL+S߱= ~Z >N+DHYս;ju=ħ/ːO9)ދ=DUN01?M?B?qD)QȆ?^}GR]>M>6?< mXC|< s6>zt];>N)=?$=*~Gr>J4>zA?::̠vlhl=خ?_ z>?r ?z?o8򲾋>T"?y? 4ŽK>?2?l?@!#=>>߾?/|!л< Ã>˫9!Od=?\eb>5T]Qh[?X_?eA>Kg>H?Xl٩=ZW?S?L'Fbw3 e0־莿_|4p^lW<1'? ?ƹ,B>>)п4.#)*;>c?f>N= ](A>p?KSP>!D>U%[<߽V>-k p>2)^-=qU>BJnXPQ HGߺc|ܿt3uyIkɿffnD`a}ےDⰾQϘRTai䛿(tT'%n2MQ %x+GrgMEϿE*=C9CVSR"R7I"ͺ*ǿpKbÍ\Oxy}~񾑵BM{ҽ},s c/IIzxHEC>ƿP6"SlxwH=HK^WQX C>ᅌ ^h LŽ1>*Y}?|I#?K?l>$2>émx/QG n=78'c7*(G>rM>6&-kh>+IHtd8dn=EeA64^;;U0 t >XG%?:#w2c>?c >G̴LQ>HZRz) =Wr yxpS ZሐE=QGgsA>31H';<0!6>x;t~h> ڴ$>%"5>iֽC>Xf3LǾ7O/1K#O6>ڲ?d.>Q1=? ??52E>* 10:ɾ U>\W' 3rG3>'?F/Z>.w9ĿB߿Fϫ\&,,(IPE4^\<7XɿoBƪ< ZOGWE9ǑSAW84Sa3{/>m|V_ 1nDV ?P= tgS u;Jz<`>CξJ >h+`f>Xɾ==eP\>j<"]R~{g)=#E3龔y j#H>agN!3Y z >p߿c)Gfw A5>G0/+yڿ*5>tm.i0Bx=B>J?.7X>I8}X 7`8<=SSJODɽ{$d6kC蛿5zO*R*=!E/2Y, kp&>ܬ<+WUs%(9>NMe 8#+= BgLE?:=])5b~x>4-Ͽ\"O+*|MB>=j?i>\S@UvaڿW'7U׼.e#/EQ<gQQ4Y>=>OAyMLD2CKj>J:>[ =Lp.#> >&R?\?%lQ)i/O>~=q= Wt>237=n?gAy)&;V>@!v'xh8=ՑcJƓ Orb,H>^ǿ@!:>5=10>B=60d&AgK7&J>~jJkBPz!=z)?o?!.U߾_>;?:?\. d[@>4?F?g係}R>¾n>jVf= ;U&+7~5=e%ʿ;,Yʶ1=mA2 aRQ⽟1#%[>l>r?N-0>> "N>T>! >>)M{"y_P2>S(4;ө?¾#=K+wh">M&<>*5>:Y?>?]>?4=E >/>Q>?<$->*#>9J>urD[>N<>"Bо9> 8\86 ǨA#> $? 1?D |-[+&lU< NibkX,F7HNw<Χv?7cy>ٿ2JM=IZ>P櫛3>G,HP""L>1.9oZm<]=">ҬT.q= >j# /y>/E0>r =P 4ċ&*}U>>=s;>k?O?>*;BU=j?Q ?+}?+>B>?L>E=x<5aA-,\=!W=1Ͼ`^)s5CE =Zp?@y>>2f>0?*w`90}W<^>*>N@>{p&nf>4w|a>P>>`?"+Lg=ξ6m>z>{ײ>C>?9],|f>])ܽn>l<,>ޮ\w}6ѽ0>Kh>>>C tm54ТD? ?So;? B%?z?b7?vj@\s( n=(>|>QR6¾ȾeAaW>>X?L3/mWԽL>s&?<}?hxunѴ!<: /#.HDŽ4$DGIw;OYcE*<`"P=׈=]>BQ}=*L6/9煾=o住 (J<=ſ4׾uڽ$5D>Q!*ccG(F+=W>6=LB>C'N>.uuq`;%?>"h?"BJ? 0p|hZ5?R?z1?XrnT?A1??zL~:?&_K#Q_Rܽ[Z]*c=KfKd%87PQ߾tl3 x>t>]O>n Ec-XÉ-'.I>D>E-fӴ戾Z [N>ďu>8>E>?(=s>uŽі(v*0>5 E>P,'cf">eJþI=E΅}Z־k){k>(=b+9Ҧg> K0eDQVy=:?/?85i?ԑ G=i??0N?%WZ=Ra??/5?@)>Wj>|B>l^?R> !>:w.`h= (>='>OIϾx{e>3W>ӺV>°FؽJc==>S? ~:X.>>m?=>>~JB T#{ >IA>(ɷ>DغHs'>???^\?n={1dE<t>6`ںF>a>vS?>sReE,>|1j=y !*I>N{=-zwu)=$꾡!%2*ݘ3wgXiRa'Ľg>m;m>C9?;XE^#Z=ێ>EA*kF>D(8~&˦ڽQ׿b|JOT?Tz-ұ>4h˿7־Y,V >5;Q91إPb>G,=;$>)>Gs?r.>:y) O5?L> ,/@?x#>>:.?5z>ڿ=!yf뿼x<r? en&o = |g>.pP?濴g.-X9|k_- ^㾝&=.Dg$ع@q pB(x>? oP?2MN-GXoءP3V2=n>w5[PEd(egAݿ \W5\h? |vf˿ @W?ZvĿv{ S? U$9|8L,vѿ9־𨏿O5cP`ݾ-d~=؏=>R?WCǴ>#%F #?0E>&ld?2"T>K$9lz}?Ug>aپ)zv2>7ھC5D?/پL;ЍA/텾Wμ:wN8#ۿeKdM¾Rɾ'|æc EGH:m&6Kz =|D\/J%N!B78i>_WONQ0W>_J2{տ#&6*&w|>,兾W}gto=#p=8?cH@S>Dµ.,Z!)Ͼ>ۘ>zL@Bo(/F9q'׿!yhLI>L;^m>.+>>giEt>=R;)>JC!.d:m.=}m?&>=~_Կ' ̾=Q>a=!>Gd>+=?>ddw\#?KVu>>=0j x&Pм׾帾 9ka$񦺰|>> 6:X./<'w\g-M)a=_5N`ǿ.>? ?M"qzT=?S?!=@{!=q>w> ꚾT@/_!ł?>Sz=U+ X!2?l=w>-Y!?3>*=I+GY$Dq.ľز X]&ZiX%o'v` Q `)NsO UpH.MힿDOŏΗDSYZ7>pҿ^HB HfsDgWLһ#Za )DjHzkǿmJۜ=뿁?d}t??$A q2>?Tr>y_!K?* >J?-,>>fӳ?v)P>?>Y>K];!>?|?N3>;?% 2>?7cN>} ZVjH? >Kd>>5?,H <Ǿ>Gx?o?0Lub( C=eP햾3^&Ϳ7hQFwӮUh [ 1?Z!=chfE&N YZpa}E=.ĿW0I#-kfH*E?cN5T>,?1H=C?>޹5[>-dR?=0ھ&j>HM?WNU>ƪ S|վ ??a? .Iji/?~,q>׀>p~BCXh*>>JA>{Cnz>,>?  [ھ쿂򿈃[p^60bs"l ~OC8푿JqitV?E Sr~0AA >)NNg?)p;>T?=)7=>?l[>Mr< >>@?X?-;>Hs.QL>-bRN@C[&n>?)oir>>Gֿ# @"/˧>FN-|Ŭ+D><"[DoD/in>uG7#ݿX;:Q,i^8,FH!/ӘҾq*w2"˾):`63.D:C ل{<, GY%%1u{##euE:2ۿ ?10?.?PYPEf04exEߵ)RTk>}BcZK^CҾҿ,|~ 6Y?Iu>Hs'41!4V!tq'-?@!>?<>ϸNxWCl пǟ# cC$پqC>-6<`R"x{?-;N'=?E = A '/6KwP8Ҿ>*m˕08žco~> #ebG >JÓZGLN&XӻWb&=z>B_9uCTj<>a>GFg|־{>>>̭?=7=?Uz<྾#f}=uә>m۽3b=8m/H>=A]>!54^>׿-ܿP}}F?()=W?mt=qP0Y{4.3rw"⿄ԛ999e9;Kx(٬u⾇_2vRJjpvjؾ ʣGPՕ=Vɾ7¾q7>7v-e==?dZ=钾gB̯Tʾ2D뿆!)-E} 9m OBB̿©DAf!Ə=Q;C>Y;Ài =<랾 ̾WD,}VutLLcپW]{?;>;LxT~ <>L{?z>MplDbM@BH>lB1d=7>EQYFl  pJaFoiH"wX?jLb${̿ >ك =@[#*OD>Bi>QC޾Ȉr o>C׀rb$C .s=N>pVQ㿉1Bjoy[SpWL> E=)-V=L־Ȩ+xSYx?gƨ@=^+l}?R>v&MnM~?g>`?9s6̼`=h>tP?5 ܭ=D\Daؚ̿7|s;y0Q׾u';%E#>ɬ?Wˁ.<>wBW뼦a("[> =%8i"vqRtmYKN۾ۿ*ЁsnrNmzٿSk7>=atu]$%~=W&4 ȿ9m? `=ÛE$Rƿ-+K.žjx}Lγ7f>R׶:!%E y>^˶m61fQ>b9,kS뿇X7̥7;8Jڿs۾2?>I'4aX'^C&>ӾChw6X^?>)އ>'8)o"5*A; =K^m?Pq?m*ǿY> =:ɸE;= |=b⹾N%BVG?uf>Q=R>K0=evG>x/s>oL]3߿wu?aM^=Ɋ>OCv-6ء>c(t?F?}>Y>kjϾ(}p?#?`9>s=:g\?qw>;Z!ۛE>.3Vd_.I?󀿹>I?,>9hC?,cI>*?_=Ϳ`G>=N#>$ݿ<=D=>VͿ?Vg>>ʡs ?>44>jXOa_?AT~=>za??~S><? @<0zBf=7s>c:( >Ƃ=Ԣ4>2ƾ2j_ľ ˊ=A=>Nk<3>:G!u:<}ڠwdGÿpegQ;1?.35Jvr&x=>ž ;%Bud0?,,#WouB >,.?-ϾdKoȎ !=԰[>Óп&~)>?ס?-P)a =>-IdSX=л>俦_)W>L>i/d=L?,>>  ?/U>!d࿟PgAL?LsXP _.2=>.S@6$+$?vr>T&N/R?avy"\N@M^>Dmƿ5b( :6>>T>?>8?t?>g͊ > >4?. BӿWa=p3(2=o>f*!տ@&)#h=v>B |ĿC?G~J>;>omCcpf$Ss?>6yFcI#?sp=ε-mF>:R?a_>>zxʩ=q:>ǿaNЁO=o7>BgD ><> >y翻~===> 3Κ=>C\[,俵>:> .4> 5?z>L>†rf@`MV*?S̽M8R?LǾ!N?"we8ߜ?k&ss>]Fҿ-=$>=g4.B#==r-A K#=hWm>ȋv=Kx;lTオb>١zh!ʾ?? ߾ֿ&}?8Bvoas` xX'1?龰 tTZ87e>PPtKC کԾBɼleSi>wĿs! ?A_ݾ0 om"/Gi0˼O@#򿟂>>'&=¿u`>uH>?>>)hN=ŀ={>X?^>s 7W`K?%z? 9GHqEy)>QU>Js \¾?P:d?BzBPstxr>Գ>Q7.tl_`,='k?!⾘UI$>'X>B||`ƂTh> F>|1Ӛܾ(?-V?5;#Zh3=% ?R*$ >پ? a?+'0:,ܾbu_V!` >ɽ௣4p8C> V e@(fH༫S?H[AgՍ*g`_?NQՀ)a=[?I>~@qE?-Ƚ>(!K0k.b?t=f"B!;ú4zNlvqg?^Ս=+x;_}Or?撾_>R7uzx>=>T\Tq @>i?_B)."kl$Ͼ-f=cu]:@+ľ؍ mBOy >C=&7~uZ3J?aNJ>& ɰ5=\?S$]5372>?{k]hHwLĹ=?dATҿu `<.?WОgs}v T>~Q)q&?J>IuLpྕ#-?W=jѾ<-? ;~ 28;W0=l=_4 ?,0/hw!;^$=Ti?5G *[S-.?E |?Vm>:P7*>ѻi:q4U9 Ï?6&  l׽N]n>eEe0u撻g=9?,X —=9?e>K@If A0dS?Y>"ȑC?w>n=pu?.*Ri)qf] ?/z1V;+xl۾*J?D">>!ٽԎ?ˎ>ɭ뽟PDř\.45T˿3/=P _U=œ+!$3:G$>o1nDþJP-Ft>:Ϋ] Y3>k8ՋMNU~=Y;M{g|> AB>SϾTϵGI%>,?ľJ{S?!?>a@ؾ>X?}42[?7뤔y8xE2L|RBfEgrYX>r=Z?-V*`{>,=$?|b2Xyվ=d>(Wҿ+*7 Ndo?DC>*j _!8>Dp`/|"3ƽ&f4 G I =~Jc`j>=^"?4%4G>???-=`$:>Z>?92(w%=`=$?y:c@E>>+Ib"0TP閾=f=h޾\=_Vk5Du]˾yOubw>Q˾@?wW5`˒:\?DI0yL wvk Ơ9|74/&!jgm hAセ*0<^~ c̿ZωpEž>j+ =?-`Hz>:q7  pLf{?I fGD(V=-?uO>ڿDIw> ?ۀ>_[?4 Xϼ=?A==GR_V?n`?+?1| F?w?`?H~mR?SI(>i>ψvgC~.w?;>>8>fA>R]=bg=4q?<3>x>lN?B4>>Yc?]4>>;N@y?_>6]>|[t ?Pa?Q*>ݗp>\!hi^?W7>%S>B=`E N?^=Bt? Lڿ"??=-?GP` ?d?-?3Z58?`y>g?>B#z7N?4C>n>c71 $sIc? >lh>;Y+W#?Z??hO;u9?;K>)>uu%X ?c>A=?*(e>q޼W<I+/nf*?Oyk>/>GmM>__>?[~DK?#/U>?:?TZܾ4>=>_>h{jR?Tغ??5i彧>=>'5{<;+>=-I>f&(yhT旯NQ y%7 > Kf\?t{?@?ob.P`=oF=> ?8T7|B?HͿM?6?W?^"ξ?'?+(?6"4??uM?TԬc .;H>Cٽ̼ȿn?MSHdX??T.?jDvP.>!>>E>XyĿY?Lj]c?X:uk?^Z%}Se?l?:vu?n]B'?M?>?M~sKV?Xd?O`?'$а-?N}??OgfD̨>c?%]>>bVA)w>Z/>QCEE?Ra(?Z#"?Rx}.?M>I[?t>e ?n >R>\>>r={?4'?C$?1 B ?eB ?T,MA?SU?O:yoX>Vq>q=)>^9>6v>z=P"W>췿~?lI?p?\qpm?h[K]?hI ?gGؿ?\Zeb?a/4@>TJ>Qr>*.>ѡ<?n)cb?s0bQ>lt>>e&>r8T{>H?>? G,?q 1?xxfM?j@ٿ}?qƏ?x7?km _> ԙJF=l?w~?q<%?%,?t<> A> ~ԽrR>YFb>>>? 78?}[yみ?op?&п߮?G|>~>a0)uƽ`=V\?Ϛ>O?0GUn?6da?;>?)03=Z?R>ڿw?"}@>|A?Y9T?L?uod >s?W?M!?m{="??B?6@?MzپA?N(?BvS?S72S?|?rE ?,ht>,>>&Lp>}>B>ML(p>T>c<>uS p=P ?3d?, ?@fQ#>K?C??P?J&Xb>G?ֿ??#Vm y>,k?A}?C;?Kf҈U>Xu=ݓ?J>`8)=8 $L@8?eAԙ=ƯG?p3?T?k|ɫ2>:G?? ?vz9`Ϛ=@>|`=%>=?<?:?~Qis=ac?V;?/@O?Ye?+ 3>L:C?o?mR?<&?3M? ?_??xlξV>I>=^0>[P>Da0O.1>.>~äM=9@>B>?$)N;X2t c98.EID>Y>) <.>IA.S"?H??F_ A?Amp 6"?G>D?KI4vPͦa?!?1F_X}?gsM<?d pyL>*>AS4a?AP l?O )}q">i>Κx6v*>3*-]; =v>+p]?%ƞ?]54Y?F g\O?V péop?u?6(?yo s\9?y?6?=!꾲?$??>?z*>oH?O2?b?uGs>˴p?gR?|?ý_z>?S?du?o? <>~>uJ=I?+]tO?<5`%>wN?0z?=pC|>&/Z>ޱ>?|<&>>Լ>R?SK% ?L3=?_Z?`t!?')b>>}F}q>m&au:>UU>䑰dz>I?a|!@?%%3)yrG> Q_/@;"-Q?>z)=U,=[?);?=ؙ?)T?@yھ?SA?x8d>Kو>⛾q1>nvN> >N`>Zѿ?@AA$/* ?)2Xe#>N=6Ǜ>7vq>Du料z<(,ĸ>> e?OewC>:>@?'̟ɂ.=n=G?Ha}߿ Ԣ>jt>L?`IY0>T&5ο 5k>gȾCQpyuΦ>>A?/н->?r?:ypu,bR<7q>?aPʿ ?eQ?(ΨZQ 0V\s>k~wվ=/`@r?s=@?Ow6a <>zB>O?cQ@==ĺ?Bh OԾw>x^>>?V!?_@御>>?oUdKoO ]?Jf=@yӐվ7M=gk>ַ>>F/>Y@5m?yݾ=>?b!gŵZ2>e[>' ?1B%ԉ5>  ~Y) >`FpƂmHG, ?sd> >>yz_5>n?t꾎p?uy>5V?PrKԨ#:sƔ>kZ|<↽Zv? Y\{Bʎud}K?rҿw-?ES&>S;>$0J>;> Acw>.0~o>Y=o?96]b>* ?sm&Ɗ׿8=׼fK<>?u>>Rn>%>?2VXm}V>>0{>K?P`k>==R7? 8pxkB?>4e?Qt[ ޜ;i|>K=Ah.Qu >?/a??>^! ?#N*%^H>PQ%͓LHI>=PBhEݾL>FGoyu))>53?B.?Xw?TaTnʾ>"v9? 3@iU>2n=bN?R]ȁB5\>=?]6DHW|>p?L3?Go Q?C>T;?>̧ Tg?>?vܠ8w 1?'w>?uѾ>ս=M?Mb Häž>?>S?vvbBɾ;G? >5?tQxC۹RL=ND5?3{>--Ё>H2=nK?M*qx7f{!<䆭?wx Y>| *?7bӰHk FB|>ų[׹pྜྷ_Ĥl>'BS>3=Ӹ?[{)j0ĴǾn'Me,>}0Ǘ"s<a>y^=OaI>|T?rɾiY>Bd$C0׾Š>T;.Iǀ9ļ :K>#j@5(4`=;w߇.Ϲ@ %=9MT#>3yjn?-a#?UG]"?_k@?fu>?tr?Q޾㲼ϫ>71Yt4W>F|[/h =#C? z\KྮOv췾m>cWQӾE龫 >D jS qс*)Ym>DJQl?X/?fFo?t]?j+c^?/r?%dW܎DܾZpL?m9i?h'D?ysn?M_?jG??j`ZǞZ=n?y?-"\da>R/>4?[^ J?>Te? ?0_\_?t>э?"(9;>w>b=(5?(5Z>u>;> .?#a 6$>5?z>>?ac;#>\.w>8>$4?"8 h:>b5>\/@;Iu)? 5ʻ?^>K>oy?M0?xp?m?tG&`;>+>O>?F?J3H,;{=?#a?>?o7v=ƨ? R>7>pA?L(;r>>>`~?V!#_@>E6>wy?J3?+?|}⽒ྺG$m>jz/<3KV˾C> ,֪u=q>chqH`=RYYh?@ ng;0'>/nV=<מH,>2AEV>?f@?NsP?SC(?݀?K?8?nv?G(?ۘ1n?V8PX:@) ?$w/U?(?j'_,?9 #?L?ƛO?!W9? f'X@ɽ5?%9 3?sTx>#~m>mU@>kax>N 1y W!?˾7 nvQf AF? bNqVXcl?O¿ >ɿLTX\C(E>p/= ?@ >dO7>`<@?9?$) >C>?j?AL>bE?:?ExqN=׾|??` ?46<?!? Uu)=3JM.Ǿk>˜xy=6侑@#>ˠ辤¾8 HB>=R?)?1WX~uQ?65?P&缩?*?)T*l εpJ,??ϳ? %;ni?,U?cm"1"8Na??T8d$#ѿ6?F?^lDX(U#ݔ?t?IQYNj/ >]l?>r>l=W+˾۔/Üp=2-Kko [>VI㾤/=7<>azվ`5=2#tQ*?F=?j_G@5+??xSbG?rX?Xz:lXԍ>p߾0K>d_?ݥ=˼w/w?Y`\ >S=] gbh ?_kMC6ӻ8`M>lNTH}>޿ )/7=6~ 1ލT|>5퍾7;>I/D>E >(g?:M=Iþ}J8>/?_;_ ?R?\;CAQ> ;=t%?a/ m8=/<ù?B+e8<=>dZQX >"fe==<#38>/ھY; >HU.TOl%0j>n4Iq:U>C~Dɮgs{XѼ>%?>?r??UY>?a! \? (?kl?z?N? ?5?Nj?|c>a?wS>[?!??xTKs> >;?'1ᬾྰlz} Ԣ]1W.cJ577=OGq>w%H.6a=8n;>vTP?O 1>4&Aa'>e?? }d3㾀_lDG"P߾i>2UgijB?۾L#>b?F??8qώ*>5?`?jS-ͧ>I&>U>~*t ξD=Ϳjakޱ﹀.kLϿ`UV Ƚfþ]:.<,<ռ5>"u?j4>g7TU\>=5'>NGN>!?x>²[Ph r\푿GFܾ<>'['&Ͼr*|+?=~?? C+.ĨfW>?pa>`H6_^2xu-e< >??6>&|c+`mV}"dz/R" y¾x2Ͽ%#վMO෽VC)Cf9]fCxPzOHL_2X͍޽Q"f97 " >ѽѷXuU%CT~@=7€(>0H?\?u>| Bt. --w@|38FSQ6QD(=йܾQ׾: ?=%).-#` V A ?E X0a(o( |=p>4)Q>BͻU򾠡}>fhF=Q)B̾,l='0['>|?aG>ɿ{jܿ ޱ-q2-0$.uW6P/E2Q Sېp.U=d/@QW;eE(Ϳ[ Q>f8ֿU&Bla5?h>Ӷ8.[y>?\I>cb/6>?[VC>kiʴUBWkײte>}qbhPJϾ]l4xb۾]lD6$$pxli<%gҕ {37D1 hzcYhȍL-T!g䛿oс>(j["">6ƿ[)@zlDiO@Hl= u>XPYC4p( Hi >"h*V?>4?",>-~-uV>@Ï?/:>l<cEYRLkUYC5D 0r4@p 3`|J=*esV;>tM}>dnEUž6&E ;#i4>Wk{%-2ƾ0U=A}D,S&` *j;us>^5iU'c; =7n?z Cd&wö>ȆE7Xa<߰=~->Mߴ"E>X >|LY?M%Ѿ/ǾNw=%ϾG=>QT;=2?'t>V>\O==>2?\1u l>>r?4>oL.>BŽI>o뽪mm=WEQ>2`d-"r QRnགྷHL"h>徧a" Uj>H[9-;־";h13ȼwHvȽk..5P\>J >/Fܻ> ڽ j=Zz=[?!S>=9<.>\Z#,E=kE%yyŽjw>2=`1W$Y >5~2*{\> ?:\?\2@XԾu>?F?kx%<9O2Y@M۾xu>^BV=,=s.>sgwN Kwo Of1㿋ڿڿ$d46<ŠWT<:i{|G%=0N1:I{=a[?:?,К-= [վ2& >G(l(3Q'֯>%>?.?ZGw? >u?o?k3>ҳ =龽jݐ >ԁ >2[1r>m?)Q@! t2E(= >?# =!r Ū<:}3u}zLb9(#ǿ1"zurV"ǿ u!>L~>!X2 ?V56K?>/sOYwMྜ5\>:^ Pf¡' t8 1kLm: x!hjj̯Á/K9<6b$i&R=\? > WA)'r >t㽿D$>rƬl>+tZBS">FA=&>J.>>VG >5z;񢾜[)?!{1?f^?2*#4fj?,3?qk?6s`XY@yi9(ꞿI, ຿6%;>f?2>"E?{?=޾ |r?JI?6?3#>Gʧ>?'8T:־M.>5s???+(ޔD>.Tq>֌?$?OG4ȽHIw%ϫ3'j=>ھF;k+>.=˖>.1""=Ѝ?|hf?ȸ??}`п $>؅4R|lP=H>?#j3ŵX Ӿ?{)`f x+[pWž m;*>>" -_) <ͳ="S>~_>#0i/=BN>?(4 P̦&44P>+ >veޖݾgέѽ\)nξq M_'t*>*-0 <$΁sN(93̾&=g>'NP;½q>uOxC"N={>k>o?7?Vn?>r?G?4s?hBDz=‹>f?v&w>{ϾdL#>(>>)>C뾆KE>,>l>o6iGVFR{d`Fq>*>ƛ:]џy¨*U@پ`>J.>?Ž!>? }$>{Ey(ԿM?j>10￧ h<>9HgajQ&.#7ȾD;Fgo$D>#>%è%ᬾJ༉G6z #pƂB>>?%mҿaAk>t YOۿiB>-(RDm8+#Iǽ>x:A+ľԙᇾGdODMw ؾVJGHٲ!o=JN}h󪾆Fw>MjEJ>zߵ>*W}x GV>^>#M5sx߾l L߿F,>[׽.)t T!;6,jn=5[ؿhiLh޽<C@AQDdQD4PἊO.!v)/PZ\վ$+bk ſLD L=gm1UYX9L% '%U\A>ncys!r>9UqDCzխ\tm=f,C@ž þr¾iΎs>| W~h >}">2+30Ó@T̾R> >V?-Da^X???A+?m&\>Q>y5j{9p(oDݾ*V*QMC$ڪ7֗MۿZ2,z7u&S)],QEo@l-b(VJAސX ;v{4>O`ᭆI3<3=U>hM\j6BQ=h>oL+ƦXudkn v]뼿 ˿L9ο_+wܐ(ZoO $EFSdIaqZ޶R*?B0?`x=,ϕ':ʿ$V-+ݾ-A+$layyNfDQ~|b`qx&` VPWAeܿG'T~W/{=+7#G01cUN0jcx_a^Tq0$H8U2f+龼5Tѽ!TC ?cN%z5>>V`=kZ꿒o-??Q?# F_p>?d?@IE>-#&ЮXے\ܿ]JŽȿ28|RH%8\hwht,?M_}9Pغal?G} wS>+?/^><Wξ`?y|aG$T01-Zv=RG˿#F>:[WpI6ƿ5 DI ܿþغK۳Y*7CHpK>7 8J_XOd@:|k߿J<\;ѾFZ旿x}NݎǾրNڿYl0FJd,{8-IDl,IZ ~c/ؐ?=)'><M?A>*\,? .E44䗏2'w_-bX*,JS,:/NV_*L4>n۾,= ۂ2M> lb-2υM?2}L{Z>8pO>6 T,`=V{:U2jgoxO(AUnYm%=Rttd8fy1!nnIo"fCD@><ѿ.ſYqՈIk/" V;pzx> {6u =?Q{f;>H?>C$|B>2f?Oj=뾒tJ=@?$򿾙:+y2"ýk>Ie`?dR>#-8?OR>ť>?ץL?=>ڿQQ׿l`R_lʻcX*>YhQNF]3+>E= ʶU>>'w=/%\CF򤘾|4,p?g.0>*V”BپT> 8=|>z$F!69}ȿ>?d"X`Tq 3>uU>&?+ؿ-w_ x?Jv`iߘۇaӮ<^>YͿ}$Gw >_=L+rC?|^ &> b7{;x?N=CztO@? =~\v%24 [a>ݿ{ ݿ4P @zx2Iw]D=XG~d p3k+>(=@5]؞0H :Io;Q;nc²\>^6n> #K> *xĹsl>B?+XmT=뤔ٝDBLٿk==i& V?*>i0=ѿmgiڼ>bʾ!XۿLႾ(|'>X7濃W?ʼ>;q6abu?=;ݹwY?ïSJ=@掿.vl?^jr\=od.Ǝ?&Ƽ>Q?#=#\?=-5qC?ʎ>#|}$Z=0 =[B@(`g=x>7D ?a4>"=^ ?RSP>[>ؾݤ2?l%f>~a>h\Bjz>z>P=`@}>?`.Zh>j >?<=f;Q6wp>6?-kV7?I(>K?4=qLgAJ O>\>{(R>1>>?{)>/ç><,u>>gv?&?!O?G&=-?;Kc*пxF>Ks>/p?e>Suu>==1v "g>X}? w?*|?3wl4;*U)> x?V⿁\?&@K[>C?_>xC>J>h?*v(FxKR>?d6]N>1>VQy2SP>m<@,,>>Tpe])5bv>>bQ;X3:/>Æ >_+YK}lӕ=8=RrCS{^>?⿎Pz`$wl>8F?z>.39='>?W!=},ҽ<>0q>?>5]=m_ba5?VW2?HUھ+˾p#=?f>P݃%iω?+?#X`B?^?,=A##迎࠿ھ WA>_4 ? QgQ>d>+Ac+ ?rX>W??<&;} nqX?W>:c¿m?rTa`uh۽fV?2ҪM9ڿ:!{@˾ }&@Vɾ 1N 92JnuԾK{>,E>i= FAlnd#?+rl¿@6m:3`?GcoJ,^Y0D.`_`|>>Qҿ+13't=̣#}H>Fkaj:վV c=eoq&,qV=J,"tt4?9Tm!_۸>oNMY;_{m?zѾC:Ɍ?7%[pg@i辎)=lv}Ԅ=Q!#y*%9qTc ^>フ RA>{3rL7UCytPu?F=-x>*dtV{P Vpx>ɾd4GAA'd?^m>c@_=#!>ApzG)q>X> H迊c|sV?p>)> b#jmg?5>]? P~.R'Q>+X>]b=-r @?.~ڿ(ZpxpK?]-?i>2N32>`;]:qՐ½}?~9t <3?Lr?Pc%<)pE?m>`#/Y?NVi>C^ /~c>߾A1T=>YLƿ}_m =Vm>g%9v1S>c>PYҢhn+ H<ŗ>^Gܾзw~L> >+þ㗿F+J`>bf4?$ `9!AwB> !>2&HQ9>Y>#>?U9eaphG?V?>}Bľnp8PǽJtP !a#?>D)!y+տ?)*ٿ a=c?7BN >G[?>LT7V'ǼKE?!"µ#q=E}?m og}z ?A]{;j> ?@9bp鼎?k>Wڽ/8/ƙWL?NӿB%o `?(F4r9YSԾiYI??@q.6&ў?z5>[!k8$?#D_g<ӮFD玾hEX?a̿QeV&Um]x>?Ʒ?-MLR >?¾;P5>5>?m;4 r7*>8>?I,?͂V1?~?B=O8F<>~?좾g#*,z`ȴ>?^y8p?Kh>*9b+dO@\%8i>ľ-g??>R> e=\Ѿs?Qһ>lr>ͬin?ܐ=Hd>?_ƹԢ`c=>z?ZeKܯ\>?XBB^SV?=Zѽ,__Hھ >[D_g{Tboн>>n+c?*|Oh>e>tOס?S>N>pVzVK7r >{ >B?3)P)翃?= * [__4c\S(-?%A>imL>6IM?T>>s=Tf;?eOh>? c>}N= K@}I?'i>,>P?W>>2=;,D?hzPK>_w=2۾k^L}PW~=t#dLӾH񽯶?=v#VhQ6?.V\r!2>]AH?=%= w|=&>z= 08GbwG1h0?ą>^P۽2>>y x4?F >">W1㈽B?ij>\>}ky>(=%>8]t @ݱ?)>/ S>cx= >:EL>AF>O";h>!%-}"=a?J=D5>j@HG<(&$=sS=yacM"?U? cx?WV5FҾu?QrG?A? e=i= :y%1UM>C>h];=T %n> >ԾF=T;h! >\d>lU>C8Cg>*~>u=6I>d_ >r?27>>ƘpM>8t!>gF43 I>">;?=!=:/c>%>z=mJ>I:.>r.=`>m+:`= >=BmH?qE1?< -?hkCn_>>fF PپTF>dV>sɽץ=2RL>? +=*>~^?y?6%??1?o(~>$>>ٽ&A) l=]t=TⰾN#ܿX2>=2Jk 4B?Eܿ?>Ĥ;\?PPŅ?:?-^G>.>G0= =2yR>?*$>&>>6[,"@>q>n&77q= S#R=̰}QdtOP>I$ž71>LY2?5R?TjG>IV;>>!V\>)B4+>!><<H0~>= Hܿj׾sCWk>3s.)-\k>@l;nPg>P~(j?Q?L?OD@%ͽ C&2WiտE\HZ_=Q) =PbT7[>1ޭ>%1>S=Жp} ݾtmSHlF>G7l3K0 t>qylƾf2׾߹h)>F,7tV><} w>޿Ҿ5 8>߾7& vL*&>;A%#H?x:?m 0?zc-O>=>>>WOw>PrK>t>]>d(AP<>{=R>zJ=?";>?v͢,P=>]<^>*) >C꫊H53?ya?YO?J ?X]?_ H>r=>a3 Κ?JN? k8?Su(x:;>ڳ>T>8aC~>S7>A>\> > 9T=ٽb=ֻ=?xS܃<?(k?J?Z8"[1<>s>O>φ]\"?0>Z?`[F?SGc>K=JV>ٮbBRGZ>ծ>xS>ی; >O >M7;>oFt=9=Ŝ;2>! -A>>^> JA=I>5\=ۍ>zY>$m?U,?J?fwv>%?IJ?A6P?[sN-?"?t?-Z?ϫ~>V?=?0Q?Nl_=Ñ?3nP?*i?BE b?Y=|9>dA&>gJQ>oo>U+׌/˽Z8| E>GI&>%G^>lL$ľ<= U>>?U>ߋpG>›Nc>>Dj4fE>%t4>ɼ7\9>rm_t=}Gzpl=Ќf?0>?Sq =?CUX?:K?S|>?n?f?.Iq>>v>p3d1?h?p?{^" ِ>iR >z>|r޺P>!>>ڭ?z=ض!>/I>R?'޾=` ~>7}%+ b(;7>k=d!G(lX>|U>T=ۯ f>rebZ=>^ ل?PWA>Ž>73>n ÿ'?/ ?:9??=a>t?[?\B?bOK$>q>>>nWGP>Adg/TLXjX5=t_>6U\=U]_>Rߓqd>_2?p?[ܾ?U?*?ǟ=&­>ڏ;>YR?x[#`U<>*>F?/ߠ?k<ZB?PEt>V?(?+Wq?>g6i?%?U?@?GYr a>ҍ>] >@?n?*SG;>F?t?wCB?>r>?x>>؀fqP? 2?0i?g9-  =F1>R( *=T.=z:=r;9Je0ޢ(F;Ͽ,P>_t?Y2?1b?, x=go?D?)S&?秿 }=1>h3>=?QCJ>gj>S?&z?5?˿*?;l>ؾO4?V”un>fPC? hD>+vQ?=%5=a?%|=s?4f;b>&F(?: W=t?Gaݿ?b\=H<,c(B%>fQ@>Fako>6/Hg#%?lI??y􆽉ʟ#Wg>0KobH[u>a\?s)G>|X>[?f]?Use //>X=Y?K)_a5Y?=?WSa? G>砶? ].?:w? [)?#=?WbȾɫ*?9?(K?ڝ h?.? ?̅쾨@>f>/4?gӌLU>ya>$?b8>>g1 $ľ>fE=V޾y);R0w?i>%|=4b>< M=BQ P+U +x@>L8Ex?$נ%I==_R&>vGώ8bU/>P+^?,IB׾R>R=Tq?QME=꾋#≯Z`?ـsJ8 ->Hx 9+\}>T\&? xX:I(c.> .( j8%>ANM^ #O=^~?$?? 0j=> =X??%-8(㶉iJ=f~'IA=K>yMvѾ3? %R<_ >SOՉM5E? uڿӠ?G䏟?y܎n¼=ֽ;q>y2ӂ=R;߾>~炿J?<4Ŭǽ>~- >mݳhǧ=^;=*&ï:0پLwW>6k0?7R^??>g{?oY?ʿ?Ftx<:!?  >.?r4>n>U>?J;X?>?oǦ]>H=?6$͸z>=u?SF `*"R> YMζ=n)0? ] *>ȇf<1?Nw6$p??/a?K?9T6A?oQ)A?J̒?#Z- vC̾b?ad^ >&B>{?}X0D7*TnIG˿o.u='jrFC>#O=$HZc>lV`.>SɼA I>+!H5T>K#W|>bwh*?>U=#Ѿk`>X_# w>>Cp?q28>z>P߽8? 2->SC>b045?>Y?IA??A?A_b𾪳>EO{=e1?Oas?u]cgI#!}[>]0I3[Iྶ1>ˬuQ=̾e>KaL=CTX>,r3TU=;>N}>8lljf/P,hb> N-^iip>@qZɾ@>ϰ 2bܽނQE?qmaپ=J"-¸e>Lgp6F>1U>=?1tEv4^s>BcY}^4>߱wǮ?>WlNk-3=T>܆'6&p=ڔ6>G=} ?HT2&bl7kiN>nI >Qs=V.j=$?VUkn>3=׽?M?(nDj>J[=l7=# ?/]#@@-?LC-?`?*=n\5?(pc'>Hhw=@4?"(v\>X<fbɓ?bT> U t1>̔OHQK`> !6e>BVP?> 钾mv%pH>1DJ.>2e(d>Q5UE>>+>N?_2*SAT?*?m(?K?2HXMQO&?PT_ND#0WϿkjbiT"?Bȼ](W#>"E,?G=NWRy?s?A%?i4?OR,Q<>-T?E"2>*FpUSMYH?p~ 0V%$>XO?N_Z@=ž ;?Y?m> xK8A>"!? ?qU5˟B=Q??4/36U=k=ѾBp*? xE>$>iG=@O?MT3k>78=.@S?0E~D^?0#?#ͫp60D[>O??`GydK[Ľ*>@? ?D~Q|1=l0x7J= Fx$>@u J>k= 0;D?L=\ExĿ:zǷ={#WQIk ͫs>ǿT_ȿ̿>!{y3V2!Iq>Ip~>XO?>̿G5K_BpAa nv>$Ko?g?ssmfA>M@T4= ^?">}[R4>Zzھ73>nP4H{> (>5B?5/<`^$>A쒿ADž9?Aoy?KȾ4Lq>T>p>mοIU貧=%E=nAPzl>4-^ =*@{>3_?x'>=[h>Q?FW>|j0ͽ<>u=D5>/ɼ?:]:|1ѵ(Y¼Z>z?lqjb=,Z908?E8(n7<=~>? ޿3G}a!7,8M>r.!,g?:??{?9pa[0= ~;>澅/ٵ5U>*>֚N?}̪ >>> >ܱ?E0|ƽL^Mw>E$=lZ@!Wj/\bxuѿHDHư <6&PةM&P:8&-?E1?r?lA#GN>u?i_?heA1?Cq? g?y _2_R-d|D5]O2, پT >|t??c@޾'>!q?7?1] }<à=?`F=I![>"?T>SXY<ܾ 1>6~dv)̾ Y>+\Y΅ɾYF`c*5>1? )>oFg㚱1NϽ?&?.1Hޘ^о¾-* dDxpɿ) t(柾:4ߧTO.B5ƿB91+P+? ?T>G2;ȁ??"[?y>r(^9;^!?8 ? B[fI+\>,=h>,|≯d9>Ut?0݃?DeG xY( >VE>rPsFg<>ָ;Pooѽ!ZKZ͸u 4=hޱ!521{,>?Q=6V`֘xkfZ>f@;dVf9~8nt=hE5'/H *FisC@Ѿ.oe=3 Կ5>2־Y7,U>aAc?0<\1.J>˸?R~=(hIAx94ڡI=|=1!94=//>>7?e>P7?/8@>΄'?`1Y>enmU:mi0L4X/XK?->n7?;R>[iVýĬsʿu_)Aymvjr:,g pE_xf8<6;77l1I鼅h>&?d>0,5=h>?rx[>.mK4=?MZ}??բv`/=J>0(?*#>%AB=[!g6.q{=? :Px-)>A?/w> kMx]5&|,5MFg->s¿PD;ֿ{HM(cy FBbOO]4G>^?3c?YO>_ו8n>m??">kc1H=r>?HF=UiB2>0>?W<=*ǽ8\>?<}?=>A/O=~7>YN?/μ3P׽N?4 OJ󽫜0TF\D3>Y>~T.?8ac:H>mS>W~?@9iA'.=h=t?]>nJ,bvR7>"ӄ?'/U=*(>?A>w`S^ i>_ З[O>b̿24D8TzT~#)q Z ^`Fc?oL4wg6]4Qp}=^>L3lꧽz%@%>j4>4?fe<8=5e>Nг;v>w-xSJG<1+=>; ?>!o iM@p(L6m> Ǵ?~=V*䏼KBY'-Lk)F=v/ ŽT-PiC7óἄuտw^kвؿD>ɿ9J$?4vN[ #+i%tž[r=Sޝ5A%y:K=vnrZQFEsp3 ⬿>'0nM=3$>>nD?!>y{Q0྾FS@ >/!x꾗>e>G `Ÿ2JZe@8ҷ>;b򑾎/=^t>m?' Std(Կ@/z$-2Ӿ uG?DM(>um=Ӳ>Y? x`L꯾h>T HD( >E?0p?UQ1l^>E?Sא?|T?Cb>quѾ{GI>^?%hi>'޽IU?Ii>&\pA=Kݐ?/>|$l>i⾆$?{v=eV Y,7T=2>ۂ?a/m$sVT> |x?s?/&y\B="%>ޚ ?>->jf򑾛8= ?Co>;ֽ2)=>[B:|tN>a6>9]w0/?@??isǾ޵G1^=;rhXj5߾~kƽ2Dmi"[h'Ab'lPag=zȾ퉾Tpp(o:PFb# t-eobB83SB =_JN'/ ȿ?={ 0Kď.@?>ѿC?I?h?EДL=p>^><:x18i"yb V>3>w+s>w_F@-AP>0D=_̿xҬ!GPӣwھ" >F>w}PY NWEu)տ7f,x &Ǩ=4̼=ƃ=u%Fڶ< *I uÓh>(=Xm=(>"&>:{f?|>2Ȃ ÿ@>P/ =+|=b»16/ = <:r( $4>GE:XL>}KBFU>A;C$-L9|=6.>qqAT s`>j>(I՞q"1V>n>zM . ԿHM9P$Ǜ4>X>5?Ӣ?`oH՝dR=[N>zo<~q;ufU~:L H@Ss&o O۾BN-=sb =B>biC.Ϛ} >ȾB?<\Y>z/q=t<>;b>TS{=?X>c:MB>-a?mPj<>N+<򌾡bпw1n?{Բ>:T6%y)%ݾ׿ 9TfP{aF6>ka0U̇Oa>a8x-yj?#]>(忝W k} >jMyO*侅x 疿gr?l|+NJ=x0[-wbA?:*h<== 3I{DiOXfLb&C- $3ҿ,i=JɎ@n(Idǿ8&!:02>ak/Ad,XJ!> `̿6Mn#Oƿ`c#ʿ@hT~$>2} [NfB?w}>Ơ+NaQ;) =WѼb?%{"'cn v"&WJ=-7rE-;~f_<8fN>K"=Xb,=Te=c0?I0,,>i>MF,677;"d8R?rq>c=@Z: l` a<AN߿t ̚`hZlt sd]>C䊿K1 hRW*Xz]}BPn_!%z>\vVOI㧹=n&kP3>d='>G=ܿ?{5>9%>쪹=m@I?1>Sm?0]>h־שm?9?xW?U$AHS9?;?h>F'"!ښ_?T?>s=M=@ޝn举FgHlYX⠿ OR־/OþZ:ҿ諿Ƭ cӾzk׿+Q?M:i=>@)?/?f=A?ƿf>8> g?o7 .?f(f=ۊ?/8;Ͼ<1l_:PCc%'K)eCf/࿗~ DVc-KrlA~=h@>G?t=4Q"^V+kTq5C3>ǿu=}.> *@59?)9,๿56\Sf_C >%B6ۿh|RU7잾i>^VnO"AxCZzB?!$tGq:?-ӿ6Fk?0,7r` 2>MUak7ʿƿyF> ?d9>IpR ș+e9=cS߿2]3zL<أ/f:*:=̿B%!97P57> п}ёȓW)K8V=syz5m3˾?>\ p r8Y/r&dP=a~i'_<ބxK^=k`=>cV;Xfd'[꒿9G8NqŽ&Ï ;GNwZKᗿ!e+οXwk_b0>UmwO$|>C|zY>`~+a!NM?]12C5hq)|?BVҿ?M#.k>ݥyЅ$p2S]y1kj>3QE>3sc ̎=}Wqa;we61AǴFw)=2A`P5 NKfk(gwnrB 8=8CZ[ȿA?U; = ^k/xg{?^ C>oǿpLo d>- (EN%9=mvz>3#y>꿤l99#>>渾IGI>Qn.at,ÿ#ݾh6}<+w='Dat"p]r*=>=_tUӿ0y`O+?z+=B? HKM?m>yF? 8*?N >>bth>ahM>l[eMrK^K?Z='$薿j?ɴM8> QDǶrpn;?񿪲=4IfL4?ެ>FY\'`?׿>i S|w?,E=$d>S?l>?sk+>, w?H^>̟?M6> Ue?~,>( ?,rm>G$?q@p>%?"B=>Lf,??l>j>7vtq?)6>?K> %?]?=M>*)>gG>73?#a=+G2?;Ԃ=d>'4tO>A>'4?`w>{/?;<5ƿCջ>3_>3 ?? =>]d$ӿ,v4>3 >):?)_-=H>h큮H?g=>IT?)_sr?PE>?bc=?,K;*>?B|(`Y?k4> %>Ѿk9?&?>4~>'ƿ3fjjb=Ŭ= @sU#B<>>8"GәX> <ɶ,>_] ^PT  zhD[?(C?ʾN@Uо`??! r޿G|>tѦ>K/`s=:ܚ>Ȕ?'W f=/Ӊ? ?t2V66uc>ľRY?O?I=-Qau澧zb:|#>V?kEWk:XFJT)lep>=C>쯿h2dyX>Dt>( ԿGrI>,<|a>LǿNDy>=Gc?+3QJt>żfQ l`=c=>l?L>!:q l9~ V;?ɓ?)g-} >u?dg_Ŀ˜oZ ?/7.EF:#qܾ?&m_ۿ3۽>ïuQkd >\p>e?,gOu:>=>5& =>+?q?w濫1>Q?61?g?Ͼ ͖>"F#7)N(>m|/wl>v澾Zyqv>=i?5@?>vJZ>R?XJǾL/)?ŢQ=_uᅤ#>(E? J?H=غǾ ߎ*?h?8>9ҾR½C`C?(L? >97@>? 9[XZy;7~>?YڭH 7"m׿| bW>}?;5*y* B=c5>HÿH}".BS>G>V*~ >%,>Կ,Rܜ~> =URNYuX?>TCJDȿ^Ͽi =>ifR,,/l=? 4?"`p|ȿo>C>c*?, ]?F p5"%Sbw>>μ>yοvB=\y>)|?M{a&1=w2>?qX^'Ѓu"hEwQK-e>ƿ?.=K'7";?}x?L>z}ޫ`?4/4pdYN>VLґ?C87A^azB =9>fX?D 8;>#b'=2to-nq<]d<6ۿ0 f>Dp6Kx xEߨ?WUb >:ſпWyZ}7>;4tn;ŽEAl>%p  D>u>XM?30 i ڌe>zEN=s? ~o3ӿ8\>>e$:?Lꆔ*>S?==,3J>ta>=?4S YBB=m>^|KM5>i/+Cڨo]>ľҪ>ԑ*QU<߹9>gI }x=L>zO>y?fɾ^.=>=f?$Uooԝ>=˼賳? 5T,J00zw),.X?C<@ͣ0{=ѡ?^: qŨ?>G&l=Qv?Vg>"t\ #hꐾD?H>P6Cե3?e: >\?>/Fkf׻@G(c?ݿ=A[ ^๽?6N+\C3;U?3][@A=]HE?Xg`>=h%?}5o;WT8>*>:?¾*Eeԕ=gE=?#P1ٌׄ>l?ļeH<ل@.w=܌ ?l>uvF׾??N]=VW/Dy >f?kH.5-? <.z=>_Jlt=;h0M=ض>6~? uF``?>qc﮿2J?VXgf>Mk#=<3>b!> Q!:ڶ>K?"r?>%Cl(R̃> ? W&~=TQ>?~,6H >Cz>'Wl>ϾRd^j!;>˾VKI8vwi="sl9=\ѿC A =d*H?Zg?~>:> WWߓ\=0?hnT?=:>#K6EGl7>9Gw п"5BFieo3>tOLc(jq(-| +6kC>[,I2b> aS>:B>~=8;wLM̾_>W?`x>ؾcr>ṕ? = >jn0ç>u>`\r\\%y>:|[> AZhKϼ=p*<0.Z?B6>i?&+S@ gB?.r>g>4PT>ۿ->Ml|SEѽ ? bc>>  ;e>g' | (}Ԛ>Ur>AQ]9=½?L'>?G0H=MF>nn<=KXxe;= EI#?'>oH>j`=bJ> C=>hj<H8?S>Ļ? __.nhJA>Ҽؼ >2}F!&y > >ȴ>[~>tp>~+?XX?fI?/V;[> >&=->FN=>|3K<}/sԼbkֺkOס1_&l=z*ԾD7r>g N>:ߵCF0CM\>>Ϳ#؅nxd=Z'(=Ѿ˽G>'(> \N+#͖>u-ؿ ^dI->:0.nO??;u$jR>e?4D>.>MIg>K#? 9>P>gp\>}?">i>$}{U@>?>} >^^_>e?>F>[> >ץ>>U+Nz S>Z? G>+>?o{i>dqe [`|>>*E>@igHH=xW><+< a=?3}'>=c'g=,?aj>tξ{65=C?;ޔ? D?8 nV=2sG},$>?!"2>Z?M/qs!>EԼ`ib:킺1=ۭÇGpPd~>=\* [->@=t Jؼڲ>Wq>_u?~}43>=Y۩vG}(2Q>\->X>s>'ܐ>rPپ:־JN>p=c<c!9>O=Z5־k39Cڷ_e>vLeg uć}k> >{7CŊ%_8C>-vho⾢+eO]>k>"%>Pe> 1?&?{\[&s?v$8"?ih'=y>j>3>[lI>>>czգw>7>hP>ba߾s?`BS?3?eXD>23?*.>O@?((?U2I^>>+>xw o?(>?$ D) o;?+>ԃf?;9dJiP>|羥ݿw19K)T!+>{+$z[>%lN>m%hI=0AAL`^>s/E߾l1r> >=>@x70>[>aU89D>_{D쒽lPr1>=?k>n />b>7ѻ>I*p?>cz㾞Z=k'ث>L5=aҾ>)>0f>=zH0>IQ < s>Y>MZ<QKxTTQc>tBȿe6ݾBQ3>7Հ;3\HH>mF*K6و ]@.>m@>ܽpJ>.|EU.>NaӾy,w>D=@>@_ P>B> =l?~(<>>o9K=>9dNG>!:>ӎm>">07>sUede>F]TZ8>#6HyVXZh^>ɿ5iNd΁>1O+g]Կ M1H'>U־g$ԮO~r>LX=#پ(>eTsB>D|=[vq>9t\1> p~R߾n"=I,&4>;¿۽V=E$=@d={>3C@S;>*ྌH@6KK>꾎<=*E#>3#iQ=0,=#T==޿v>>)hk{_>:a>l(P~> ٲ dt3$>/F2:dk>X>j>bxZ@ݽ|>'>R>6[1r>>??i0M>??X?|Vek= >>a>gZ:`N>?2*?/U?4-dCz>8Ң>?N>#.I>@;?Nƿc^t#?9?@(?Efr` 6>? ?;?#+ p=\17&9=F"!+>34;G>?H *?c i=ɞ;b*,=ڿ4<Ukt:????;XjM@N?(??T>??\?VO;>7r???`_Y=>i>K?R >?6q&?._?|"&>V>eJ>k!| =.V=Cl >cAX>~?=?GW?>cv>T>Q>??nd`F;:@?2_?E ?G= > >>?~o >hg>?>= !??Ә LD<^;7=3k=>T>ϧox>zɰ?w>?%}V>?"ʛ-?8x#Qو>@t?#X.#>>ܼjV>^?ӽ8.?2 =>z@u>Ĭ`9C=iz->Iz>:s{,>vn?3d=?W">@XX?nb齆:>v>D>BB>md>1zÿZ?W>?pys+[Azy_ſ>} /d>%p7PCn4?"D>?qGQ< }>h+g?, t#?pI?Ĭ Y>=z>Nt 4q>x!=a>6=;A=S7>=wK?>+9<.]=DN= $g_-> W^zc?=a ?Zgs.p~>=ʾҦ>m =y=fTei>=afHf>h_@>+^n&&2~>RȶؾA>4P>龹5Ŭ>V(>6mH%>Y>F>[:0>ޠhI9>#iiơ=zikHTS>r(3?hH;;>^2t? х?y?b1Q?х/p ?k?Q?˪Pp߾ ?9?&?57 0'?1kU?N?MK}A"Zm~Iu2jE?"p#F=Vӷ3N?=㽓fX"?x J= ɾ->q\d%)P>/=2/'{>!?3 y>5>NW>r??6}?s>*?c ???D3?j?_T?e@W?ȿ>?犿?ۿ?  HE"u>_}^>)>>"?**=?x?8?E?Gs?(pʮT+V>+x>e2>ߜ Ȫa百D\>i@Mھٱ>A]-quK供3>f3< ->/q">(l?5ER8\o=:?? cþ]?z5>M6?s<Ym?s>M\?vS3["F>-4R>>л>T?]3>aˊ>k>$O?O]?f1Yμ5h=p,n+?D" zؽ#⠩I N?(W=dk>;=K?E) Pќ:Y<7ଽo?=?s̸I, @e=x;1]d>~/GkP9Yӽ&JX? HuU<:=/,?4@/B oh :;]|p>2unɽ6߾M?J#" 2(uվr>UQ=uB>AE=?Pib=$d? >i8?> C:}= =YRL>S'$=ͧ?Vake<}aex?k#ɸNW=ݾэ>YS=jp4>Őɉe>O?A-Nljg>_x>G ?\Nq>Q=A`? tb2Ͻf#ŬGa1f?@Ң>O ׮,(==cE}>!O>_T&>`ٔ4>+&ٿ V>0]a= 3ܿN^ ,>fК ]p>@:~`>mƾٖ#>;>t ߿*{N>J>+)3=?8>fϿ>hkX V>þpCC>T>esd M>s&=6? ?ǂp?'?,(P"}[? 5>T?uT!m&;>LNCM>/`d,o;Gk<.8U>m#?np;ޠG:=4ՕDBu ]d,F:>ZҍC>=?a/ܾH ۃх>KdA%G3U?d3&+>sͧ~>gb>juͿ)4NQ=aN?)G?qDS3THh>X%`<U >SC=* #`Mr=O.> :K1b>:؄'>bƾ??6> B:?r??Y?a ?B@?aqj?^\R5оcW?6hU=ˊm?R࠿R>=8ξ9¾?\'?itTD=M>խGܐDTq=b˿ =>82p?p>0k>FI:I>8¾ctԀ>2n6> >V:?r&g^>h=>S@^?CrYt/a={p?PcR,>[_\l;>y:YL=[վyؾĥ>RK=]w>&A>J>=,?ľ6h>!)p;>s0O),>2\x7mB>n`=$Ƥ>`_gͩؼu)D>[0ɻ&3ֿ;U>o7S|&= %C7{}yd?*>G߿R=CJ>Mvh,| A~>Wv=7?M+o?\>F.p\;Q3N4<>?}^ =De2@ =AzLb%p5>KHN>Pղ>o_clK?<^c}>̼!GX?9j?3]=c帾%2a?OGx?4q ?maւT#>]h=?NinhcI># g8;7>Z%XA>=`>6%0?/>sK=%U?^:!> ̾P ?!/??wG\>% >ԝu\>U<޽X?5E]>]P:J'!n>s(B&>$>>VRz?RC5(DS>g!k@>ćۿ6?GǾs&qm?ǿ >FV%??-Z=h=ȓu?"< S>Hξγ5'>ԄUÿ 2 =VjgnxV>@wWCi>(?!6槉?J8?2YK?4U`fs>R?>|DxW ʿbR>f?BF>˫će!iR?4?!? 5?1h?^uGO`?/#;Nr>">i=ս?Qf};f>X>_ >5?X sp=Śtd }c(|+>G~>>6>6?Ke=O5:?+gRP>>+>F?ƳP<ӿQn>E?SZW=H?]C?HKZտ? ?8vfK>#uDA>j'(?%&vEȸk>v??z:; W;|qֽT?Ir\H_>?@~,>oӽn!>1E>u6/>ߞ5>64q'ƒE>Pb>=P"?'-'xȼJ? 7*?*3OHL1ʿ?8\?&f`;4 EN<\6??q#p]8i Of?ʴ?ojx=;p)>P??B=P۾#fؿlQ?d{x?[M.`>{ֿo^cu"WxY,?K-?J+>Ƶ _>gޔ];Y ?<>>l2r,g*0?FA#uu>l>l)9?7=F>Q|(?h}D>!:_ο`9 -@U w??qs?k?L٥?`!J?p?%? >@) >\->Ս?T>[<~+ʬ>A̾SP>R!fs nRa1? V_pjo*k@:NegUizὦ>>?'w쫾/?Q ?8?] H/F(>:ѳ}s>9.EDھېdd>A bPIE>Ym>zs.F)GuF4->H0>cAL1p>77?/?}pоʊ?8??ݜ';ٿFdAQUaxpl5О x>"e{0bZ>-Z\=ݪ? tyh+ v.>?l"?GyB`jyRO+g=-^m=>: rq~8>w>W::+>D>I>_)҅3<`?;ƾ*?@r?'#T b2h;ѦP>>Tq]pۼӾ5t& 75?*8"? $5>b?? qCfvŋ0I_Š9C(Uش[*"N<'w%Y澨@:{i4?4KMſ5=-SX*}Idg> >+E/t]=;˞8T98F >3戾6Qn4.w$QDիᄡ0Kг%ڊY5#pQN$='===0>]pa<6pT&>u=& :\>^oBn?=_>"B?"쯾PR?c=>Pr>1w?lc==`BTԉr;t̢L>`S??~V=ɚc=M?g>tK?K?><ץ8q~>W?U?x>O@L.W'f?x ?O">N00 &̿ ि 75cGB#>S>?eZ<'k.;j?&?>mZA.ypP>?V>0Jj-sh>?Sƹ>bH,P>?F>5H-;뾂>OG?4oi>-#O\Pzo~=6]3Dj/#}=@!TorkRpluE>Dp] Zծ>=׈FB&3HW` F3  M= C?6??)>6a>-">M?.<3a~,O$S?.x< +d>(?&s=&^* F&<9f>irQz-0q=Dž/&ܳrD@A7*>UsH7M> ?龙U>z?(H.? V@>x?7\}@ j=^>Ce?$=>D^>?+?>pJ @>>[?2L.=ދ>˾z-t*=!>)ᾪG8+;\u%>e28(<վ^>?^ H(k kO>y4AY>,<x>zf,9<g 0?۫нƾ&0>!?!9B[>?o>E@,=p"=?>?o:1+>>P/s?/BF/z$(]m>ɁG&K{g=Ծ8D'Bnw bO>?q*>0=oK[&98>;ݾ>͘4:P>`ja){]*"=}eC>#c''$>PW3BȾɖ=i>ͥE{簾 97ֵN>f=sӢ=޿UKz>|+@r0LY>N>?fÿ@[>L׌>3?B<<}=Eg?U.IΔf%ܺɗI=@ļ>z:>ۘ*>5+N%|~k>q.Al=&>$? ?V>П@%D>U>1?2>psľ>x?o?3 =g >>?-At>>y> >O7">[ҾL`ӽGRyБ}$󾑐󾺙=Ϛ7!۾u)>/t* P 4y}>Ŗ :%YX=C ?xGɾt=>+(=`osC>J? w?7zAݘǸ,=?{?/omC(DVL;K>">ƨ=6?/^c?#S?R@} +??wt%?~C?ҥJqz>?R3?~kof˾6/n3>hh? >?;K<@xI>>? =?e2??m?8>E)>3QY 򨇽O*> >Q&"~,>kݧ犱M¾k= $ >l(b[>>'AJ>ٽD̼[>~>R7>H47 Ͻ>!,k^#pxomEg>lavI{t>-k>΂Q?:y_֕? X?'?wY8;*C>>?B[>S6+q8ze;"=LBz6e5vз#Is^*\oi[!ݾ>>˾-m?dWo>>\e=;: /="h~ 񿒣迺kM=8zSi+2fڪ)aǂ[dտ2 &N侫nզ1޾#$ƽA"s {?`>.?>p Q ̛|s󛉾${qҿ4 != DȾ.RRa 5\ !0,w.tSݽ/GSSP#3HR̕[eh)NJ ̿b|,'/AtT߾о%Q¾ Aj-膿ug1 *>gc:GQDݿP6?MM/0JoES r. odоI]O] ޤbh\kd"v`- mocZ z9}Lǹ["WǾCJEF!dU3j]3R+'[iB7۱`~DZ]}P߽wQ63νŏK@^Koo' (*0j,s=q-a'*I*r=Vu$_>ֿ.'i(γ>#HE=d~WTExB|jPf-=00 ,: >cND=Q">H+INde[qɿn% 2kn~=8:&UPumւjټH)ܿxlґ=T3 :ۜO.j">qᆴ 9k>Mxھw(fh \> cځwp jq?==&x=^s/d==SRӿQY6m_\տ]0q,IQjSm>===ۿfh;>{#jƾ(98z=~7L*4>Dض>S.? ߽Y <"l>=M==Fk0? g>>>.8=L JI>?0M+m&[aobN߿r Oj9CQG=j?< MCzHbqM6ɰ:%7W/2:>KQL]=]?὿k$:^t;>4TZ}:;@p&̾cL+oL>?U >h6 c/p4U>9#1{0kS eF~9 R`tS[ᗿ+]$NKmx?)ݾ{s^ zppR2DjM[:i/Tm=?OD o!uYCj 3+ҾI=ڽȾx<=A\Bu+o7P$B>Xy?\> -EMJ8>?6=Ⱦy%SM"2?$^&~`Y>dG?=>@lPҀNEGZ?K0ᾭuRkr$a1DŃ8'=uqԉ@@1"3*&zRu>{/R +;[w&Ƙ%uѾ꧜@.I$9⽤ _3CI;-Pt?xu?>CRJ^>?|z>vWu:{нK0_[ѿ8$I =`=)g;nv%)%"\4>5ھ䤿Rwu 1>M辏v2+>QGk!>6CFT6XֿK?@>%@LþF;/{B?KbcSJ[; l=0>bM:~\`<0hӿelHiaoDοb ?>9 >U>lz,ǿ:;࿗e>="K4m>PS]MUZ B>>q<@ik'[zHWq)>ݽ ̾,@^pտ_?.y@UPNf񾛨(~1E>} TW~xktX)C="`|鴿Ͽ}DrT)>kq2:i{<&?8YI=U fH.{:>XqJ \膿ܿ<>p>ߘ>\U@?H>t짾HAƿi^>w<`yF>6T>@OG$ )w?sTm>hSHYz2r?=[v<#.>5OB9?RaI'b>0#Ŀ.Y+_|DԾC <Slj9P >KY7qaS>He4>Q϶ǾV?>==(J2hO>{=нY^L9 ?M6> j+?Us2> j¿KA:~?5οD>11=bT 7`?na>%IsKKi ?w>tm>Xp(?]_Dp>!<)d<ۿ]D?e, >8&=,C.yyE?m пק=`J&z\v)nn?=}P{x ?X>>5]濈)?Rhf?3? >?H&ݾ5?ρ,?`F??@6>>dпl|?ݣ>4_>MP쾸L?p>t?R>&O>ʏ!=R>`aпQ?Q=O=̧ ^>>zժ>u>j2F|+=F?N>I縿'|~ +>wG?xx>n葟=WH>>??5|{? 0x>2?bo@yu:ۗ==M۾ l+=>àglH=OvcZؽp >Gz弈w Z>?;t6CYgUfv=\>;nOxx2>v~~>s ʿ@Մ?ӿ˫G1?YY'>K?c?Nl>>{?BP) !=1~)>2n?p=Sֿ t:M-?"<]A:wi? yO/ij.˽梱>6>z9E,>:I?. C=d\<.>?aa7>iK?OQ.s>l&W?/Cٿ wϾEb>ۡ>?8UTX`g>>9B7Sb >|&lw>!>:;?q=ž&F_>Qe?(A;޿ ƏoՕI?siU؀/>O7濉߲@ǫ>e:??jszBg>8>|?j꾋b P_G>^ҷRb`-u߭>O,? Ǿ޹Ke4yvX6>-?nҾ;_o#rԙ>?M+п?Ǔɩq;>Hs>jr<&ľ&IԼ%пr뿒Q P|&=>;1)E=v3'>%T>I&> r=߭=)SޤKT7`Γyz~1EǬs!p=Z>h8?ZGCD3mw:?BTX;}(AY.WT3J?m?^N>RA#4݀>?AvW R.Aw'?cQu=%>Tt?>%Jo*o*Ov>O>G5 >|XiaPgs]ƠrHؿ]^:ҁ8ǷȽEy@@0`>1?>ft>}y> QVI?_ԾYy x>px404q|?F>4P M=hg'?R,h >j[>N%K;jx t>~~ XvM` )L8P?n>01ֻ@99O酿K<-<1p>owԧr,m>>c>𹻿B;+E;ᰊ?GI;:ZlA5?7;T<Tz>B'?oĂȽ;8=?XZgQO34=c#Koa}!꽏IϿB5R;pPe4Pj>hk R d}hF?8G=cӝ^ r+d?/qj/u/-c?h4䆿"\[O=Ӽqk>P׿|xgqy>t=?]y-79>P>Yp;Qki俼d>R䏾!aӭN99⾚> пY AVgM?4|#̐?'>k>@dÈ0{>,;}%Ј8>~1>$?83>>oS?WŽ|=Q>Y>\?짾/X}jR">~>z?l&> @S>79m?]~x?强>Pu>?t?pC>#O>Gx=?r3󝿛~g>SQզ?džQiݠ>x>?21+U6W>IV?xsz5ҀWO<Ɵ=h:F4l>=<Qzݿ]<{!=ĢwL?©8.PkF?a<~#@:m̿%ZKaʀꣾu .A?h}SgE=;-f `oNM<ؽ"-Q?.am+R<d~>XKĿQzp^%J͎}m\p*üq8Td2<ܾܿ.r? M>!\d>6L8rd?lN=n .]l@k/Gd~޵?_X, lYh>) ?{mnR er+]F>u^l?=x-_I>Ԫ?ݘ>׫j[⾓~o>Q?ɏ>^NPkM>94[X\>>Z_n]U%̾LI?E>T+u+Vyξ? ak9TaZu?@0>?BB=ڭ<莿V#)Z}o=US:&>;uD d m>`Fjw>?059?RK>. 3?b %Io㽷1?_=E>pBͿ8`g?__>lPrgz>?,g>;=>p{ / |D>*( X=Q@s7> ?B9>> ? Jv>倡? %h">>1UX[?mxs4@?1>ĩ&>j=L_=&>Q==H%@_H> >=5>~a2+?d>:}>]\>w:>92Ͼ&\h >16>'u @aA_M8>@>@S>Tu>ɡKܭ?04>GR? @H޾[ ?*AN> ?"'F y?'}> ?^<:>x>jQ>[Uih@[?4 >&?,xּ>I=ٳI@ 9> =r>g;| ^?]X>L+>>L>>} rY>~? >$d>ϱL7$I-=5 rKXK$_7uK><Ԅ=}F2A|>v=zmR;qi>-ǽ7>1q+mP>?e?&=?:V&ZܼrϾr04!ʾ)$?sS>+p& '`ʿ(?DA~>j=?CaxLw)>zk&5 Ͼ/ )3-~̂8R=Cgؐ=xTz9w> >>QrH 偽z=~֪+?[Ns`g><>8pTȊ=ɩ[JD>`?2>9?R>VK>=>ab=:>{Ѿ @=8p=]57>K-M?Q>? )>IH>)g>$b>*c~>I :?z>*o?O()>>{ >f*^8n?]?>PO>;0>^>iǽ(>{N_/>)>/ >cR)>>")>P=@h:>X>pA>,x> ڔ‡`V!2QhÈL=Cٿ pwe>^_jGla>m1w=w1M'>.5Ӿ/r>x>f>uZ@\u>nu'2:SˈWj>DM /¾^se=b}>0ɿ#D9VVe>-zݾil3QM>xS=>i!cva{=膾1Y[d>@4_=wCGJ>Y>_l'<M^>9` >e>5Y>R?#b_D><{<=9>|ߠ>>*=>L?pµt>?>^&>:C`g> >C>'OW0>3]jè޾YuF* >E= =BpFv=Vgs"̈́MbO=UeB 3r>=a@Dk/ $/>@п5F́>X6[dh߿~5>8lS~۠ǿk˭>~7nƿl eRD#B>>>S>)#I>u>Ȃ>iYG\\=>((8u>FAY>HR18οbˆ*=B[>"N>|>&?,0ZP=h> \= >85Yp> >E>x>IEa_> ~7J9_l`:K=ݠ=F!>qҀ>=&)xa>"L$->1>ÿqL~as>=Q/TPۼkI z >ucXvj=Pe:FN),𻌬K/dO_> 2>h^2=L`>d=X2DU> (Z)&nD> J:~a:Y_>S󽺤vwB=qh7Z>>`Ua+<悾k-L 8Ojb>A!>>rՍ>{af=>=s ?k^3>.d>G4r޳!=}>=ɚ?fg"U;Gz>_eV=W>_#F>[y>i88佈q>W/>l%>&$=龘 61&۽[>7T>b>S 6㾙>=? !H?0b>ʉ>9I?#t|;Veee>F9+0=x '8P'> ⋱æ> ǰ?b ,?&>?S? զ?%١\U>yW>g>FoHPB=<=dl=sz>TxB?!?\?(\#B8>սAFE|>=B'^>w=Vgh/>,a`6g{? ? ?Z`=2y&=$QI>m? b>l?H|bP=h>;>P?CjQv=$}þ=Un> a>?,@>6r81D8=ਾ|J.%=p=dS2A䵻=2˜@?=l^-Ѿ+1o*=Ά@&9/>%4A&>"n>K)_>e*H-D+>*E@}>f"y/=2=T=}Ua@!b@ r2?L?zP ?r?=um<==oIϿg<ϓ8>>u>?f@>t~GR۾Ae>Kѳ>oFԾG;>=yq>SP?'F>$-?v@gQ?‡?v9 >>bŧ>zUr,=aC k6KQ>b>P>4T?9N%B> V=.8=Y~V?" ?=`3>y">k>fo>C1>l=?>4$;>=ë?3' O>P?E= AK`>P_?O,l ƨ>\U@> / ?s?b#?|g><>0>l{ !üX얾LbQ3>4E6?(b_=FO?DJ`?>q;=XF>Uk0+=>f7%r>l8Xv>YF?GN>C?$>rfw? l>?C *>"W>]>?A1.> 9>ǰ=wg9z?W!>`?t}A.?192>d|?J_ wR2?f? a?l >>cr?O>2ZtmPn>Hm7"}=D=?FPS= \'\ѽ(x?gffg?iz=s;>wBa9?B 6tpM=,>녽Ҭu?1v('= >"pF? Np?Jq?-a?+ )5J>ѫ*> h?F0oB?8 ThU?)??xOq@f=<<? !>CV,>>'=d>:?#-'??}c?z `RlǾ)7z>B#z l?AQ/?J?.;E!޽;.?zM=a>K,ǾMVm?c` =1f>$o>G?KhM=9[6>S)Bn?>8?/ǐՐb=S3J3?VO9zW>2>I?H>X*eI>>f?[(|IK8?a1PY?>[? &f>43>p?o?(m>>A>?~'>>B=G^=?j`M1>CH<>23>֕?#â(Ƽm>np݃>9L7=wB>+3S>= <@o<>h'sĄp=jHs=}羲)>S9H¶ل>#?5 ))65!Y>P=f?S7"F̼̽+? Մ4c(>I>W?m?Q=4CG4׾QXIGL'==_??,=n`'<܇\>τEQޠz3z<ɾh>2x"=MY=>v<>hɽ=xܾ=_ Ŗ)9ⰾͽl^-? 0n:?OnO?inb?zŻ zB,s>!O=使F>t~kο&Y=,U?r?,xR>P=M?4=fhF>=dE?0_n;tQv>ag#BNY?j'O( _>~A9Kѽ۾u@F6>$,v~B[Dڐ?D|t~[E? p$> *>o?J?sЌ9\>O=?F |#HA=.?0Y1+j>nk=z?e/oМ_jp?~gI>#N>Rx-i>b=*?QS0i=Sh?Yt C;dRA/ yFNNj X>(1PD9!>ֈ{Ul/齐7P?52>,9b=qIyDg>CVevdFUԾYྶs>ñk<ȽȽiT?&FF ?-#=FZfՍ6&?1!D_?ޔ1~?ntQTC? >Px=l8eVK;a$BFQ~>%ľUs!«>LdKg>,s >>(N> >O+t^ ?vU;? ?RYSپeAȾ.>piy>?=2d?X :?bI@>(q'Wu>Iz"=4>>V|lWa f=3ݱX>r Em=S{:ux?->Aӑ=Ľu?(ߋ >8wU7X>ǔ7:Y>|xȸhɖ:$?m7 ~r;>征 J>ʛ߽>2M*?ȃ?tqgS'A{=>З0jx;sN? ?p?9E3?9I>(4??ʴVص>~?>J-OUhU> 牾& *>72]>7͊xռޢM=,q Օ?% _f{l.>{O=3]>1V=/g,?D k(E=^ʷ={O>*=ɿ "N7j0>sX*? >NF?Ԕ6__^QT? =rP>hP?hµwV=c1]F?nc?]0>`>+EXp?Z?9<>a@:V>gND, r>}Pun?6>1[,>1oξ?>!Xq> ̾->@n |>i8y[=dcUD=7TG9Ύӄ<=*fL[cV !=X )-\Dfў?) (?[ۥe"Bu>PޏkaA͒1t[i>Vq?@\??f}P>O?O(?GMi: :F#?3?bH N??ޭW^?)Yi? GoVGp?$ȿ>}BĿUo"cvؿ߃>ȿ.6@N]Ee?/?P*H~ |㿱;?l?m=P?/sNf/.??l?gj0uNJ?a?_?SO?'Tn߹]abC=#B;)q>>qd<]ѼH>R>? %s>뽖B>}`? (x>y>E?=I=x`=tZ= c0=^?ҒYC=t>֑>0Ph>?Cm?&,?|!H?AE?ahb?0?.?ቾ"k? y?Iu:????=>">!'>ԎG?ZkQ>Wb =\Z>>?>n 5?X}%þ0Uu]A3S N˾r>ͅf>bZZn\g8(;V> *)6/M\"+4> ?JE?2~;?li hb12 1M \X>.M KY޾w!^>>4ؾߓ3=kοD7<ILBϾ'x4>?=!?I>*F6;N?G?>,kt#X`$>_Y?Cz? SӾI#>?g?2>|`X>I4d!e"STҼzEK%>+>A?XTPR@F>>B?NzB)*Zbt\8Z?^J>'9/;hؾ_뎾[=2HN> vK[F9?)>BsK\˴>Vܠ?N?6=:q%*.l,?ʎ>;4Ϩ2yF=O?6@>5JBi >wy־=A y>Cپ6Y>W>zg,F=,{>fp#f#t~xnﰒr~ypk dQ;ʣ'=z>?nYJ.ӿBKw2Ǽþrhg=ο竽!LR<.9Y/sIC@_L1Zbl3=j莿cL¿A?dde>Q^}v޾D=E> ^⤽>S"E*?.'>3ӯ?Jf4?>bq&=gb=d0*$5*V0;>:>%D ).>EYGA!+>>|;;.ᾗl _>P =A>i8;~y>q=>(<> 5uh=Q>)?l=bW'ھȽ>%*Mp?Zh*.tC=?&?)ؾBLAZ3M>)z~=\͖k>/L%f?`n]>ze>X= 0P$ټ=6>Q5D5Oj=ʸwv>pF-<>šU>?t?3?w5B=Qmp]TE/2=z~$ٺ^fR@ľʾ뾩="(ufh¾Ɔ>06p ˊ>8ATd pI96ؾ׿с}ET;G}O Dp"'_ˣdD&E':^pG>x@b,лV<_g=[W2F'J~;>3YֿD~ᾚ>6>+о~t>[9`e0I>Q?PR?>'z.&>f>1?# J7,=f=~J? }Z$X%_,$=xM|K >X'OU ز4Pq?>'>J?9((.(L1Y>$>}-E?6/IY`)Cz p"5#g>jUE=GguѾ >9>o>W7Ԁ>PΈ3>W>Т?z:⵿1?>>|F?6 w'+Qa= ? ƽ '|ݽ|ٽl>Y:& k2I>ewG ھS<>el%>>C?Q=1?? ?g?]۩>Lr?@?' |?y?e˿sΧW=j<~X`>W;.w>?2?X? K2$->k*e$} j>)cύ D=:k$xyCǾ M>I? 1{D>MV >6Tȣ?X7>2<2|>8??<ۜ7*>Uؽ>^wO,H/D>žg>f?+>\ߨ!6뾣j>HxV6>t?$= qvίN08*=mCe%I)Dݿ!Z|Ks#==2B$ҫ,d?qPv?&?_E>WYh$Ĝ>=06>ChM̧@pY\y,=r>ۜ8P/䅟WMi-CŷRꗋ?bؿ]UP$>@CKySZ:ޜ#C'>w`2K{Ɠ=o$J .p.=.Ԫ t>ʊ?OWQ*=^5>8Ň? W}8=6Z)>o"\OѾ OOQ>vJoS1)Rz>P<v?=k>O? >)o>0Ms> 4:=lʾ@>a<tu_>>5Y:])hVG;Z@`>8q0A<N?"%C>L!> i+?X\>&>3a=k^)"E9\=6> Pzi&q~оVmᠿ%>x>;J: !>>Hgj>]>OZ=DI=:>to>ԕ>?:$y?_X ->-o=IK;goõ=y=Re" #ibB¿! '_MOOQc8b anz>tD8ҾxK>x zq-aNM8=q\d*ǾA$ݵ9뷿%"A[92=Q96&&" ?cg.*=~FEt*sS ׾lUw>b<=Qi/zٿb/'#-(G^-saAEl~17>Ftݼ%ݾ/>a̖{>_ l I0 x>w><3/?Y7m1j>2fjw>^M^pe $hi,V0'w^9.hȾ0} k|Q3à'hIh&ŏ ٦f>tʼnHīžIng䗾"p.i; Zcuq "lOi־{O*Dt5nUiG>fv(gs>=Z=&=[]f>*͟(hscpYo>1?t.iX%"~*忇]%qew5s8LpE&j3=VITV|g\}s"ly>Eý2)x lWn4r> Wy[`^Ooc>N>~=*=։DXl>bR>R7>,Z>dJfh>-4~J<'K"Sik3>]&YTb9oB>+>Jh>9>]D]0Zzݿэrbob2=`uKk\W] >a?u'= ;奘>QS4[̾rWuZ;=E$_Z/Q=^aMF$CU>=#tG"ա"P꾇BM%N mƂ1f&58& Q-I{RؾV#RĠxDKޔSJu,`=4]i7 ɾ)v+(=C?OH?F*:V޿5̿aE\;5y .>rek=<>lr@- nP2 Ǽom>??a>=AMH*9?5au8VzvGExି)mo\}>"?0a1>O$gk>?͟>y Z5]"n&x>EG?m>AGߠ:Y8>0HZ?hU= RpaB<+k ?nTiQ Aqq<:?%) P!ΧY>SZѽy2s9>?% aGgl]hb pɧQ)(ǂV!k+qOӾW[ҿ4w Y:?C>>}Jh ~|eQ+4%ՑI^@FA>;?n?Ȇ"(ִc>%JuhryZGs [^$Q>=?=T̫> Q])m]u7AHᾱj'>>ɟZaQY== L\ݿ2kͻQD&4ѳe Tm#x 8ܧ/?X >:E6?A㿫>Yr<2 Qb+O dM>˒<%cm}tI#=FS󿥞'+>Z\OFl$>i5A*k= t6g؝ y1¾sO@ ETS*hf*>z1=mr@ٿZt 1RY<!%5LAʿ{\<-輝{3:kt8?;:fg ڿXdH/=Dm`(?#*>? . ~Ԣ~ ?h+]>@0ο>ty>v<˿,Xx'>nΣ>"3pKͿB{j>Z⾸\SaFIU>EYy[G?/U&>[ɾSlܩjc0>|{̽諿)Ee8@+Ãg:Xn?ES&>$Yſs= >q=2k#b=b F?)>F =DR=|=n4??>?D=B`?>/?N5@ ¿->Y?S>q;?}4>U?.>!"uD?qsg>I??>0M{?eE>L]?P_>6?j>A)??뷾Z?͚>>|߭Ŀ?[>?>B_ x6 ?>.6CNnɚ?b}? hۚ[¿$&?.#>˳BXs|a?@>uXd?>? x7]|?{B>'^>ZNlӿC/Ѧ>a ɿq=>Fp㾡쒽?>]?2?2Y; ?P6)h8>b?om>%9>$'>e?LV`=j.1?8*>,? Rn?27e>V?ury?C;>|X?i)A6R]<Ҋ>1v޽`sr-[->_>3vjar0>h踿iU?/i=m¿8E?yg+ >R?R!u=u-#?I@>]?>Pl (?O:o>Z?,*3fsMb >@tE$ q= 1(w/_žL>*Ў޿W4k!Uu"鯿Ŀ a=>u PD%(?%@>mo9 }"G=:w`ȣ<[w޿*Zbwt> yѿz ({ з?>^w= _9>4DV[u2 n7>%Et-=q_!>#pP>9x>Ÿ,vwp>y>V]4j4ſNr??? X޾!sX>ʒ>qK>eXm={[>տ8?GC>)?'B'fi>$)?s >E>Z>??[]'T_>t?!ʿL?%Q>Y?"-ʿw썰9/?/\K?[@f[S1<%?4>BlJQA 2>`􁲿KV@mݽ?*C?)Ɋ~Y>a>ho(>I>ZE-D c=О>XE>^5F,lD{e3+?p?ی;MK5Т?>HXWwL2j>b=>ƄI&-aP!?4lLJ n$O]?#%pidb>O }>?y>2x?@̼4nI0$vnJ>ߝ,>Ĝ?g쾓vtP>(?-?.F#yB̾#?F?3 ~zBO>?n!VYh5"d>.I q4M16?ʗjѿD t>)?V3濜5 <>'K>?$t0?տ;;,s/U?U]ļӄw Lrνp2>s >,n>1e>kQvοod=k3=DUGr;*oG=z6v\>uoJZ=5 >a oEZr>?>r} ==}<߿yy0?}o%>I5>; w?pifzR? JDh-VP;MM]>%پO'U#DD,D?!#L@E5#>8?9]տ( >t?:.E=p >>0C쿝[* g>'4?HV>p U= l?kuQPR>yyf=ܞg=\ͿMH0e$nT$NL05>`^7>D&6PH=?@:K'>&wJZ=>;5A(A m>ϧ?>V澖e8M 3N<?3d('~<?/!l8 y>z7i܄bǿVqIKS>1U>;6?3 .M>n[>٣nRr [Y>=>8y5Ё ?Ga_xBF!YO'>a]a?0`Sbn?撾{P>r.11?`w;_n}lڞԽK?tJ?},md[E=Vg0oO>M㾘;CH?DcEL>-;\>έ.Lb_=w=|p?+;! x(` c ?0t>S%Ven;>i?P?=H "U+,?F@ :;)ZUxy?.ſ"drtN?>ߵZs`澳h?lE?`=yp@Ѿe?y>=tPhgT?.4=z4D\r ɾӪ?#->LOfpܾL?X1Y[Ub]?xNQEN8ه!6=ὦvCKn(77?+sr?}u=j{;[3l;>X>6T g9jgq>qeU2;KH>uas2zzDa?g^???>Xd;i6@ ? h@9?.-E>?5?ְB>` Jm?-?a?>z>4 N>foo\y#>Q>ܿv>p">*{AQF>3QQ迮W=h>m>EN?Uz;y>m>?L0=eo=?O?= >P˰??=Y^>?l??v|:bg=e9u6㿈]O>>Brmv\>vd>l<ҳF`>\> \&F4]H:>?K{MćVO=?IK?s>Miܛ%ýt?;lH 0`ѹ >y_5p[=h>ZO%L[>2ʾkH0La>+^T>J H|r:g]Of>X]'Ӯ"ɛ=S=W {O$(~=Z?.M<=iBmHѫ>O8s%E^=q <.w;fy<v<(?SLf?+qHh>OH=?lK?TRN\>JC$ܿ9JFE|UH?PN*;棾xtC5`ӌ~>־@̼ p<;۽O>¾s]J_߁' c?k׾[S E[FtO?˿>X_,+*o>|Z"mSA:ehf?,>-x_Y&ݾ M?j>qy\>?m>>m>Tm >e >ys]!l?6!>ݩ>4l$?>>Ո>h4}j?=@>$? ^PU_?B=>ڌ?zXReb>hb< R=]l:^= ? >U>wO9aͽm?#>>ܒ%i($>xcs=a\ߟB>GV> >媓׌IH=N~?F?pa?90hs>P>=nr>'ql<8l>ɬ= >8"TC_Op&>`==*c>dj6`RorL? =>i+}?/ol˾>/M{8.>$q =>xI=SL>w{P)>'W?3w>*$?#:LB4>m_W?SDN?a??C.]!1f?)l>Q>*^{P= >Z=_>*ξ ># 7<ω?M;cN>R?"#iD9x>,犾28b?[a>FyF':* &8<'>?>':y>f,^lFؾ='!=#>z =,aV6m=t#y 5T-<Ѭ>S;pG+` >@E0h?pl(>ֈiI? h]>o%7;8 ZK5Ѥ+x>I?8>>2A˔5:>D>>@>ܥ3gX(?I?O>dc>M!o=_?$΁n~>$$ ٕ8>=?97$oР' u>m>Ľ*>GῈM#=\ 6TJ ?v]} :?pqʐĽ>^][?Jo>>i8+,y=>6m>DZ=1>xh0&g=t pNB0t=c\/i!R:>(>ok=37 X>Hؽhؾ!?LyǾd?O>? g^w4>>>1{6W=I? >8"?KcV=>8>02U>hn˦>5#->yp>B8>5W?g > a>q7=>-I^R\3>-q?=elEb;>z¾)k8YV~1=u=}> 9/$5U> >G?6;Z»`?)7>>?LV 0 hc>y' =壾()>Z x ]h>T>'=? c3>/=wS>'r>f`}Z6>i4&<Զ>GgR>S0Qa \@=U _=;F<l=b,D!I8\<7]1= %x>~ wIk>YEtp9w>٬>4۽>4r;S>&9 nSv >-be=+n h8=F4a8u*A 4uJ"{=Kw/ e>)\>T-A1NB}ʎ>cfؾ{> &Z cX8>\ !U+?TDqCB= jf)<ͣFub!c2r>O=k? ri :< S,=vzmB=A+`0p5?ž[B>T/O)ҽ>ݠ=?C#z>h^>X?4 ND,K>LL뫾HIK{1>i 2Ӿ=pj?H>EfIb,4iLDv =Կ _<־0 =;Mj8žDd>"~%/^V@b@d>9\%оxf=m-H=@v GŀW>N Dp%:y lV (`;>r0;sBh> .h.F(mQr1:>s+eM>i=d? (=|>B>2{>a~ly??Uu?'Ftu? a?0?U\FN+~>>>iwx

yO>pX>h^ ھ6m7>O>3U>{Kf>pS?hQ?Y?rY>c?>r ?KpN?b=Hb>Ot>,B >\<~?9 <?C ?P]Kb?f.ӽ >!{=Q>AE(5?!P?}A?+1`=>1ɴA#05e>˻>=cn?{Ռo=N|оov/~ $vg>.K}R; &|<'X2(>)g>D=iD?#Q&np6m>>2@&-^>. +%xR=;:a9%`=1I"rS5=Cbx? v?A?hR=wQ>+j>?Et=Y>A>K=^>UrX>=s=e>>$@>sL>@i0?Gzⴖ>iPD? ~>/޵>m>얉OW>&CJ?9Ѽ?|ih>t?S"=?gs x<6Qs@>1~VZW>¿IJ? ,!>\?7*(=?Kʿ?|{?=W@th> ?J>?a..1:> b=bj>)=7-F >B\Pھ&F?mU>'?Ee=<>\W\>?T9GjE=eU]>m8=L?x>>!k?P;H˿})? ?*?m Ѣ>7=U7?P0 <> J; ?=jY]?:h⿺?s?;~?8tA96)>>d?8k=3=Ѿ>4;>D>{=?WR_=޾nƾFݭ>m>Z '!68ȿ>9#k_M~.G>j>?Td5 >2>#lY?IaN>e>>%?푿vre?~??]EA?Tt=>=? ly=>sܼ>=%,=;?|>,"%<=>=4>>l >Fپ>ik2?!Ξ~>.>z2?? 5 >_z>eNJ7?'T2>5Cp`? $=>꾎H?}0=&=$|?~?,Ƭ?C?y?DI?h3QY>6>J+Z?5ֵ|Ǧ>}> Ͻ^->œ`>?ud᾽=O<>1@O=}2>$X?0?.?Sٌ>PY!??q?>s==|=P?}_|?𿝥?܉_E0Ȱ=Zu_h=پ-^>O74<޾;ې=w3=I(I>sFU<'[>LR1vq+>bE=??r'F.xS> >Wv>?H]i?]Q>>R؀?0X09ܾ/o?^5>#?@F'a>r<?et0Ӿ.G=B?Pi迣C?pD=_"IBHoJj=F?'G>?I8hC&>ژ>^6?(X?YPn+PnDmv>̮'羞݋>z<ˣx=$vlipr;>SP]T=h4QD'&2Җѵ<7<.W=5j{8 m=%vGDtd>e=99ξ>uL]AM>W['> ' 2I2Fm> ΅Ϲ0dE>fNPwd=֚ %@>'B0mvt"=޾"?wlZQ߾*w>5`B>ȋ'>7ŽaM9]y?'>7@=}`?P]?R{?ӕ~k>Uz)?,_:&߽j"h <R? H+wtZپ@{?A̸%24e^>1ݰ"tv)Gþ?M<X&=4,^?-T_UH }n?L޽PƊSoF2j=O1ˉ;$=aX?94>G <&X?\ ZSxl&Xž#>䕞6R B;iӾAG(?LG?O/BiU 3>r([C c=䴽}O?2\e? ~`Fp+8?j?&?{Jxg?p5?>o?+I ?F|8`ܿ>}-nfs)1/` >_]5fX> nc=>E{<þ[d$oH>3ɔ`=4<}Q?w}f=Y>O3??R9>iļ4e?^}`H?ˣH?d)KI=෿k=/ྈ?)@/?Ka?T~v]!>= =$Ci8=.Qٌ;>/ElCW?$?u_M`Mpʿe>B?>=%^?%h-?kA?bR^`?(jc~WT>2>Qx>6(>SѦP?cA>w?9\B? ?'~B >s> t>)(?ڌ >38& <($)?L1U4ԷȽ,m>?7iQu?*ky ?~>X?6}S>|=C?]31U%6>҅ h <(\H0i%̾ vv=N]>./8 W> 쾡H]=Aҿ=yiRߓ7?%=οu埿1@~;>`MeMYdE_^>$?S?Oi?7~P~ >'?v?K? Qg>B [>j>?FXaf i>?tq~Q4>f=P?W`X}B?M==?4P~ V\>>}l{0R_HѾL>͒uvS=q([',^J>0Z a)${q *lv;?QM<=>{wqC>q>a^TeQa=c)þ\>ϻ ~S|.A+ ?ۿ)Sz1>9=c?D":.I,%? ?8?u>WuzRTIK3v>ʹov}rsR?>817z=u@>Ƥፈ <(>->;>d{C =>w>~龅t ^S>B>rQqվ >˒?J&C?(>?:˧?'> _:>K\91-? /??y?'>=?$>S+qtu!x>n>xڿ(1H>SUSdZ羊* !Q g>$?`>en7Zi ׾'ODeǿ`t Z/7#=O~?9?L?` <=j?^8?Y?;@SXb<]?1s4厰RHMw>Rϖ>D1?vOO=4<&>Z z)b~>s7.-P>Se?)">ަy=e> [y>hwh'qr؟载z/yѾb Ms>FؿB>$Je47C>? ו>,u?h@͗NSG _=Ъ"??>_NL۾7?D?:LOlj>x?V\?nzS>kiTz&$tq=:=>Xᄂ׾%=}}9>>7>Bwzp>-9qm0$dؿg>w5;?6?iQ>xM%>3 5Em=m`cٲ=P?>%1sɾc̿="> >2^F/8| D=6?\]@ =b/> ?X?+=UGnT?;X hB?edQ @QȾ*MJ'=nfҴVн> r>)cC߾?5z=ޣY> |II>ۜ?A?= Vd=_*?EI? >KZF뾛6;'H,AnN=%?m?-=ZXtAי.mzS=' >< 49{|RsNp>ie>?L8!Dq9Ap>:>cB޾WE>E=?B p*b0>?@!3 ^j==?,I,bDꎾ'o;>P _<;`~>tPmr ¾XXZX>I>>v`A'<#ǽȾ]P>KW޾nR<.>gY2A=?z=ڥב>iR0:>>բ?J+9S?n/96B3U>D-=+tXB02q"2>m?D@??+==Y>G$Y>I!p> J06佄~о\_&R A l_ =7;nS>nj5QP>?8Z> u>#>>|sW5¾20>SC^;Ex๽-A>iƾ-j'>[y1G>CRdX` >Y~< 柾\>K?=sRngl[G4㏾٥qY'u }-/<oe>kA-T lZ{:9sd[>yFuLU~Tſb!{&Yܻ?H)]r a= Bȣ`пR ZCM?|= DX˦=nP>\>? 4-r=¾m7y X2Y]).۾e.)u d<Y=X?-?e#a=' *7t bC/aeh پ漾>O{R>{5<=ĪT?at=IP"0fC*2v>e>3M-X ~#=DR?>FV&(96H ~>2Twp<#>g0<x=">e[&OY4˳>vh>6vdPVeu}>1(>pj?$d?4ؙ>>K>r;c^?6=g DÇ3<>2d_7o@S>~;|=((>む0:>4=K w%}NI0I{dI5C>=H=O>Xķe'1`=>-7~ռ˾KE~%?_dI=}=ޘؿ8+9>uֿ ̾@h>¾̾BCcQ>C>Ǜܻ7xݾw`@> $>ݥ,ܿEo`;q&|>W/?B>;־~gn~>]I?&]>@k{khZt>ֲ>Vɽs2޹i>H@MU,m>qY>oq >btCE;&)3ѾFhO>_dsSM4Dtk> 6vۄU:#,j>*a9 zal*>\&CpνɽSU _>-?);/!hrK>N>>%|>ITXr-=漾dC;oHw>Ok]>ݢ>v> >%>A>DzpX?@>$h>Ŝ>0˿f>3x?>|=Gs=>+JQ@wh N¥}J8s%=@)?$Մ DۃtD˽L0?iQR8T  ?7οN40 ?)hUXlǴB>Qs.\a/Ͽi13q C8ab*RZ;^Lmu)rr>T8cfb7Pw =,!)+1A?*޿ j^ (hl? a_4{>a=t= ?G1ML@2@5?@71h7>$R|@¤U? :7CZukM<"?7e<_￿ -UB1jAؿIXb[Z*1o9MJM^Yt^.,jfHt\S&cbjux@Nd=m?r>'~@=??`=Lw r=*ǾEA>>0>K{xM*VL۾nP>o/ܾL@JO-@|>K<>Z=pc>D35@D(JOǰWO<}ԿZdW&l+>ξdYCZ?b¼ؿ1!>08qJ߿.7O:b͊Hǿ2 tl*ٽԌ.)Z8~[ u|>B5r?[? %>z+`?Y0>п;zG~'[)mĿ4# wA?/?>axU>y ?[?ɬ>HPѱ|n0;xI7)wuatOq+ zW0P;S4fGxS>af>?? O>(!Z>U??=;K>AuJ=>%=;}JVc=i?+{>=Hx{=VN6ҿR@=g?6?>ҕŤ>U3&>PҦAdJ?-/>"ä{•/׾qpX9.׾WG[`ib7QʿI X`B;g !E:q_oL؜=>Uo.&Pe? 1jHÿ^BwIN/a0簾Ξ?<ݣ:Ce4DC:CKL&紿MjSjXԿJ!S)!h1&xSs&տ,rTy'57>2>꯾,ſ3-2>xw%? =ŵ&>43>ܽ쉱R=T ;d>i+AED_R߿??2?`c?-8:۾֫?A0I?6:> x)~Z=_A Iޱ%2{翕]D$o־:m#C|=!ne>V>3@=~y>oW>u4 >D~J=O{VijS~l[S!l>Ⱦ{1(?u!>orjZEԿW*?s*Z#>)z@ɿqF >+v>c`ZS?g> };]/D.Sicxj= 74Kc Qi0=qC>Ls|߿}~R>\0"ᅦRL >}ؾNH(k'=-%F>z 駿mݐvW> %`鿈S;f?+ >Jj>e=yF~1?`> =2+\gA?u)F>5>D矿U?NuGU>vh׿ky_W?Ȏ}=>>>*K?q+ý1k>Y>l?Tu>)ދ>տD xw\>S[?W2>EyHj?dw??_|> =pƿ[Ąjq?o"?ƾ>u>?{>u{+t>= ᾲ˿|?-,>><>Hd¾o-&=<TI?A>??v-s=`Z/?n\?N>eE C|=+o+ nоlz?B>_ 18&on~ v%{s;K>?l<MrH𿡯>r]>>ۿlnĠm |cbῤT 7~Q<(&KwAaоV5! ܿP!mwjMɌGN@k4?K˽SFX !>z-oS>ԓB,%.jD>>Cl@܏>/4- 1[ @>R q\z^k4pe?. ^c `">+)BV>??ezZ8vpS>\?%+?{m ]P>Zgb>ծ?7.oEt?~?IUN+ J40=>?Qp^.><??( ")Ca(*?՝=ۿ2[b'Y<0ngg@U>?/Q&ۿ,:>i>c?6$Cֽ,8>>P.^5c>])<>a6>Cn=¾\?8Q?&ݳ9ŏ7 Wm>˅zl:-Y?$5qb]um~=>m,8?4, ]Qp [0?'J߿M>eswO=]l?5b IG?Ku>04>V7Z?u>o?%{b?|p >ׄ?!jš\?6s>OV?Tֿd?x]n>1r?iAii+>t?a/Ro=$&>Ɩ>b9`q> ?y+/?v}n>?Fj>2=`HZ-/>Կ˿,^߁'?Q$S~3*iz7>x?4j]?07z nQԷ>fؾƿpT%!>]>0J0?)q u?|qY>5?*EY?-r >I,?񾰪CG{?3Gr=&>l?s9=R=pʿU&Rs2!?t=pe=?rZ6LB>qC>?Xt*X]>>>m?1m vЧ2?(.>?d v^>>Xc|$D[A9*;?E5;`Ψ?B V?uw>$=Կ9p?u̧>pzR@*j?Pu2>$=KE@8?(H}Ĝ>&ؿ y?fKu6=M辍B`ҴU&?/"-,8 "4{?+}d>#7VC?n4Xyхd>>~?wx}|L>L>q?,ѿ 3>n¾Y>a]Yc@i׽坙ښ]տ@D{}|`zODYG7W>bu? (&=8n;4,>ˆONўKpMPɲ<=yeYAub2]15۾ZeUv #ɾ^?j5P>j98]9S<(?'k=@x??.i7*?$p=޿jM ?jf=m3>4G?Ll9=>3A-y?v'G%L" ~?# %r݀^?ԕ>A)KbG=پ=?ýnaFGu?`c6߿7> >~ֻMVzi=*Z?]dnYʽ>9r?M>پ2o~=l8}>,,_i>xCr \w*:>lL?kYfioY?;i84N ?j?B?Y>|%>"k>iJ>{>ȸ?鼺qKMQ>7>n?f{,=DZ>,Z?{7YmE>fE?@IR?$ ZLb:*9=?G5 SlnX=-?TR֪ޠW= =뢿"*??>=ͦa?Z?s?r)a?T&?> `>>=?R&;~6&8jNe>@@r8ƶ?>$>׾Ky MĢn=[ߏ> ԾG}Jlw>- =T? >Y>(5=O4ʿVMi6>EF :ɿĿ^1if=>?ϼ%<K?c?K=NPϳeY?peqKA==j'B }?4T>Zп b#wpoe>}A?,fվ7>?̚/ ~$a1?%?>(rfĜa32>{s?Qv{$=>=/66t=T+ڿ j@B B@;`#(2׿u?EHv>&d%]-3J5e>"-) ,W0i- >xa j,([\~z>|(SVR V>>mX(N?!P> $H? aU>Y>_)>*%n"> %>$ٿv>AD<4p >e"2CA> B }QpſOIIM\l=ɿ6.ÿ$XB@!>l׿?b0?>1%?EM轓kL=ȉ¾q{nG`>MFؾt6v1{e`b >=B<>%c,@?Z>>>D`u1})?%>>:>;:MJľ/8=ymb7ۘ5Ű'>'-?='hhF0?1=N/>_2{s<>><TqS~e;I?,۾>h$>+>j|=#>CE>;)>Fd?_?)/?M(?>>b>d(<>>N>[`>3>C?L?`?t!?3c~P=?6s >7? Խz!d>1>I>(Ypg5b>G=g>OTv;unje?0>D|?T=Q=^8>,վ2{B>97ƾPoi><>Eh,<0p>=%>\% )% >hO=h#lZ?>xA>zi:rҡ0>㻖>L8"E_= p< "-\9=7;4 6? ?$ '?0 ?2JZ([?7hx?&?Cl">?JA>??/xQP[?a>W>jM>Pr7{?&>t>;uFB5F>ݽ6=? @.#>!`9?0.{c>55WP-E?o;P? ,8rțT^NR?6 |?H??\ ?R2?G#48!>;~=} >bl?}9>Kٿ?k@>ƫ2ݿ?c2 ?i?iP?.Qq =-kc܌1w|iB>P<>F@!`v= d/wLo5>ؾO)/c# *w)m ?>o'-2HӼǩE[X;h<{[=I)Ȇ G?^:|t>|$=߾1Hm \>ty>vʏ;=l'?dal;H>ú>+$> q2rRpz >ȑ:>c=|d#>A<9jU(X(H]>Y>  ?Q<i8V>mK>XCC<,HO:>c==lxxrm@oa?=N/G`x?{ @Y.> =37ey}f=ϾĿDN6"<'=W2`K<=Pj ! o2#NL@Jf=UXoh' Q=T>>#j>-6?u(?=g>a<%>F=ScʾSYmS V>ŖB>.#h>^J@O(>ܘ>=% >%[Ɏ8۽x5>=j>GyrdjH>FĂ5\G}Ll>rbU4Ң _-q>/]6 m( =5B>>>}[?aDf0G><>_=>U>A!J kvm@p=T57 ד>/D &`(V=|O>Ы=.7>?w̲=wֆ!'l,(I=U!]>b˧8 5F:>Ź>?x>3i WW]B"t|t>Ż!=PPO<Ȑ>>-R;>$zȻ(ʿ4>f]}O<6N=R>u>q>H\=/>Ң> W>޷f|=gž/Ͽ|g)B,>aF< >UPy=½ lCRH=>V8=>s@@9V\o>L!Ch qQ>*4>sV=I>矐'~f>>TD?,׿}Q>]/,vǟ6=z-#&VXƈ==C??Z? dV=+N>W>l?Z}/z>L+ؽv꾃=OGH[^*=d=/7_<'|%@%?i=$r;H>%{1<Ҿq<44=n=ְ% >Z>UkD?@m'p8{>Į!>$?3GAXrn?8??EnqI3>>>Ѓ%p>S;66R0=+);=>,囀=w*>? o>?Ns?+>qIȧ&>>k˽l?q`> >G;2>Ӭ C>>meG$>Тf? vB>|(xa? r?<>n?3 b=?;y8?a?i?qlB>ab>8?o>̀> kj?66>>+r??9^4>=%=Uf>\+y>wvy񻻫]$>g !⾥>zw?(fY??J?$h?G?|?Gtپ^>Ѝ>t>?NTm?!(??/6>ƹ?+ ?L?7{8E=1b>m2>ٛ?#=Ug9j< \5-A> Rɑ>,u>ٿ0U?c?V?qDyE>>L?I0>ڹ,=7>޿U><=>K>뛪4=:>>#P>*.:wR>")Q/=C=d'> R ?:?ӢN??/?-\>3#=K3J̤>M,Ծ>nRʛ\>,ྚJ>e)a?4?`x0?õ=⾯)=ȿ~Ͽ>JhA\>2?+?Wy;=]+?s?%b?;Ƥ?oP(>C1]?F>6K?[ cܮ<Օ'jz<0lU> =?>,;?)=_>L+`> H=<(p>i>8?|ˁ>C徆"!>s??Yi^?8~D供??t?eE> H- =F>"'S>FW21>fXq?Xڿ@?.{?l?Mb8}H/?y?'?0_G>0>׿?@[l 6> =x򽝲-?.U>dE )ܾ> >t-IAt1<>B2 )P=Ë=e?-0 >qY^1>(>R]>l<=?{l-`=>y>C? N,W> (l@s=}n+S> 8ouę>o>?p~j<:gui?/))> 6>&=q?sY/(2l<L؄? H@B=Dgݵپb>zX<>崿Ĺ&̽:KU>W+j⾊6;qZ?ט=ޕ>r>'Uz?@> >Se>Y|׃>Op>s@[?70 >Oa<>H7A%g8">f?V~/>¿ N׿3[ēB=%ݿ)'=EW"A=?FX8.A ʾIo?H#8L=_'?k=꾥{⁺>cs>P>ؾi> Ȇ^:[?xF>a?\IPDL?jw>|?[XFȵF">?<>?Ntckyf=\4*>Te x=%j>\>⺝,jr=Q&>9 W,89'?>ؑ?g אs=&,ީ?Ӣ ;<6ƾm V>Կp |=c"BJ>P/Y>I>u>YN]?Pt>?|[h:Lk?-N> ? !=SiXȼ?q 2WhuW>1?g)X=(>">}?*(?ff>s"ڵľ=`>ݡ[>RύY%=Eq?(L˒wWX4>M'ě >A$憼hYk?Y\?_Xb>&Ͼ AB>0> >"?Gq=; $Ľ><ę)#>ؔ>T+0?I4qjO Nӕ>&?iJjdHJBQdz>>T?I[QB"ؾJ>=7x?vE1RP?]>sK?sO^8=)?&W> ?Z% 9վ;[,>+v5Rs ?AC?o?9xS羥@?~> ? >R^ܾ8?OY>.?{L7"[$>$>K?Aq8TaT>v=?I.mc? LQ>?fr*=6t3H<[ =.>Q] Y>M t00c=uv:><;%d(>]#1!2>u ?qҿ_?`-׽EGA<p>MA tQv>e6?&B|M E$=_":<Ұn >>L>IbJ[M>ԑN??p]?%PϫM>ya>E.?'jyHV*M\=j4ހ5=:AVk)>,ҼBL@=_j?i5T ݋=?9hψE Og=zd?5!GA*bjW!:? "_ZC9=)t8?-u p(*K侩G^> Ѹ9ݽʾ >&quXDvR>9 2n?As_$N9Pz?C 0CxrN?dspy_;9]Q?(*M =ꭣԶ -?(ݔ>1O >$=y?I=m > LྩF>,Ez> HM>zg= b?f0&N?{?\,Io?2X-j>kq=~?V`B؋fB>?<5?NXQ7u?yܿ9?c>Lӽ^^?l8)?B;n?gM+hdӽ =y]?*Z tsfIq~?CM6;Ժ>w:D?h60P^>&?OmS>M>W?M2/ (SK>>տ~@ !P=bNY?I[yxlս10Y=Բ꫊?d-UI>S~,?CJj AN><\e񭽗mR>Qj`N.eylo.I? FSogEݵ="?:I24k>G>a?,)X>Ĺ>ZݜMu?~4%b{vg>5)xZmh/^r|]b}GCC=!{dg;/7i4dRYE= ma>>ax;>?Mo>>&ü,?F?&R}2\t~ >9zo"|Re>+ =:>U8?^?8 =shx[:?G=S=s>>.S?9^VuqHI%0> ;s?=ξzg،>Զ %=m(MD> vxv=|Ծ#L?W=Qk ?%F@5=r_c̿Sخ=2#ءZ=&`E?t@~C>[.# x->qtTd>\=q!T>?Re?>cվ? key0>DF? z{ >2gA/O?&c0?Qi?<`N=jn龋;?&E?zi<?e =Ы@`?{G0傾ڻE>PFZWgାC>?db5R>Aq?>ʵ?X0o=j3=*($?,T#@;?%̀?}3> Y=r.-TMKP][t<=f5 J\ZӦT>'iZRJzX xᄋ&xo2uh?D/T"v=Od{=i>fT+a_=0 |K2>0=mýͿ'y4I`=.hdOj~Qׇb ?1 =!8:<3W#trmjGSW lڿW>gBoPmPI2<#5g׾ =D[݄>G<򪾰s޾= 6'<Ӿ\:ɾ>*!.=<M+b>>|ϵC;[>ԹE&D^м{ĿTq<>p>u:ſXb P>xD+g>_?(?r>"gc+۾>@?*~<>^;^dXX<>!>>[ESk u< >m=_w(}(<>q?>@w¾>S$pA? g~yܾBg4>Jߵ? U>;| Dk)Q;Nn>s?œ?ȩq?A-vwdV=ͧ?/Xpu4Bkrs>{Pwmї><&ҽ?qf`>.>?RpF>o?S?;%?=*$sӡM>n?*}>ˮhΙx6; >? FoE=@?^04AA 72^>)|?}F?&1?|>2ҾB= x?rV>3VB|=m^??/rqMHhA ?7i>V?0>(q#]%i D!ر>=^J?y)?ۿ@=+@ӝs=E?}F??> ='>ߨ?86VQFPF07x?G>,QިM2=+}ȾU+N-cr)4-<7)_59~eW>ssHI<_ R㯸2T\Jr?w?zcs??b`kߪ??B?Uj\x}?=u??&,ܿ5ad= ?L?&?,ʂ!l˴?mP?/?~Cxpi?U+?$>O&#Ƚa ??" =uָ^1 A?p1qTYFCw>r$\@Ž8c?>=>ayP\w)EFZ?4Hk)PvfwW V?}?:d>|Fp@>±?Tݺ[F/H%X>o?޾t;qre"ྒྷ\&VX?sTGlE ?i}iDɾ2D?Ǭ.DJ"$MXӾ($;s ?ȾQ(#xKL*BK.MZ>ngϾT`Wǎ>>Rѣݿ vu=P? հ q><˖/.my">u (AH=$=?H a'付=C?݃ \F~F=,>8V*3|Ǔ=݂wufžLs1BpL>mhO]` ??W־h0VSgͲp=\?X.87i OuFԾ > qV)F=)V0 36 >ȆzM>_>?Q[E2>r6>v?\$#6EJ4]a&`@;@/l`2۾ɒɾZ>!,$Hؾa[1w=kR<z[S@/s>(w=o*оY>QSƦз? ? x|J !?A?{X,̾?5 ?*TJ!z-AyhX`C֭=+F8>1=97&\ca??ߑ`O&T5lQ?k?ޕlZsq:hX] p?:@ T>?ޭ&$+I>ʮ5[ =!=?#=-M=I.?c&~ȽJ>X>\>gNl]&N>Tz=b >U1۽?S~>Ov'u/=i>3Y5 ×x >-KUTE!p>Z &|= >P?J Z,]D±p>vF? 8:$L>1U\1H^G>+<)Y>>HV٘h߽L4>vG+>I>n,?0ґɿe=Iq>-t=^|JD龵Ny3Հl +0]A=%;>\_K/t#S='&F _JbÏ6>)h2=Ovt׮=%?jy%)><>? qQ`_N񾏽=#O`Pes1>;T TXGc[O=7=X!? i>4z>5+w>ھԷ ?+@_>b p>ʾX>cU>} nTq=2]V?J\>7ھn>7]W\y?HH>D>!>?S>>$?2>fm 1 D>*?+ej;=, -K[½4=O xm=Lf >¹IыnQÙ-=3eq־W1 6=l>Gw>M@^~=d-MQ`cAb!*$W==ۘ?ѻ oJizdC{*ikIR B>hop/=]p($վTٔPX ~Z#qxw^Y_A>j\j*YJ|zd$8 þd-5Ig8 Vo -}&xy= 1>2Q_ٿW>L`a_>_x=*}=#!3W0q\>)>ξQE"紿 PH?F:\N>E,=5T<=e#}OjӾnp(Կ/qCЏ%wQmAտD>S<o)UV>/t"F l:p;== >V<H;f6H6>aי⾉@4&Љ$>OR[:/EW|'=)Xc~hŗc,1q"uGgwC{8~8 Zɕ>L=Pbe5>x=%M=E(>靪kFxO>==G^>z+>/>>4W~? KZZ>;=u>> >>zC>?/&J3>:Ӿ*e𧤾3D@?Nc4N\]~a_? c$>wU򾐭\?*%BIU> F{Y>_S!>B$> =g5SiPw=A A+텿$^|>\ O ]+ܾ'A5i?Ap?S+EghZ<!?^o>0sJ gO?V?BDyf Fm;>(R&̃/>OMbu3 ?)??a|4wI齒<z3n4$yxFů]Snl0=Ƴ5xo=`/곾󿉛lZ>+?[=$e+-M5?|>sUN?)=W8DA usMH|uXnZOuI޶إj\wuu`P=K=mb>qry"ӽz(J:߿El"-="Z|Bl<2|=D, *I_$?" >ُg|?{jb>c|!v+?t W |wp.֑"nM{ ˾r?]?Io>O'p=W\?.|>5 >Ģ=P>:-Sb4)w>=cm7 5"-J^?ƼVNHܽQ>b7s~o+XrB>~j˿#\=&> d4NhLQ<>XLXtb(rҽp{=)5]:d!.VAb>Te/>qu\Ŀ8Hk>ΚtZ>ܿ (cE|nv>6"f˸u_S=?Q>6qAbg=\gGw3BP!=^:C9^T(^0pS>P&H=k F_H־\!r׺=@5:U&<&&$;[ޠ4C2&B[\#>>BV<.Z!>ne<[5/%I ژ[r>YO=(,*&gFWEcVgvை:;7>m8+3 %[3 g#t{jrB@Goq <:Cľ%!-6;C=/O]=b$ jqr"i0>d?n? 7]>;: ѾG uҿdI4vCg> jy Ernae=徹 5pzM= H얿nze|G*>_{럙{&?>O}Gp>kY:&k>DŽA">g X`=&cA=2k=?F?(rK>daknÿN"|>ܚ_<;m>n'?fe>>y8>, -fڿj4>̯?Y,|><V> ?J>"#J>{ G>??D(>/]ؾy>r?x}>A= JA(>-z?& >@J}P}? ٲ=ϟE[`/񐸽Y><Qۼ(P>?I>Xiƾ"D>￱Q>1? ԽQM5DQ=y)ht*sm>ɥ+:=OQɸWL\FM9>g !w7d#te5? >b#bM?k@R*=Bq@_ +*>'8:+?5Z>SҞEC(?M&=[[ IֿJJk '>yO@/-I0/>fKC|? h>?ؾrWL`>>wR> $p@ES? (>=G09\f =?s>wYTQKs @¿>>Є迂?J>\ o> }Bqo?~~ >[}>C_л|9?^+>n>@ľh=6?w>X8>Gɾg-?>=\wy?ʡn>k>=csQ? c>`>=?l?uM>?{=0JL?ɡE>@? > @ [Q5T>n7>GKb?#̄'>.>%yc@e>B>F>p*F)t,8>pP>CL?D1T>i>/©?o<>?b{S ?734F>?wAhFs O3?={? UD=-P*x^-'?PG>yt`?ϾVk?m@g>?-^JJ1r}?z> ˽4u>C>/I# 9/e>_>>. x6/ (=C1 vqt %>xg=ʎs h,>>lz:ʿ%+F>@ =̚9-]<dA>>Ӊ%ٿfA~=(>@>2Lb80^=+,=Bv\H ­>xh=U=S|?5?!*9* "ž*` 3=!Ͽ?>= *>[g>dQ3>(+9?q A\ >XI>>'F!?.`*>wT>N>-!>?s>/dI>:4D:o,{[4q>M =`p:վBo>,|>*,wŷV뾝h>:umi؀ xK`x} ߾c<;#WFԝԾP?Q>C'e>r.n>>g >?%7!վ1? m>XS͊w>U>ם?m4zŠ>?K־cB?Z~>MU?\I`=W7Y? >"?S%Eu>K7?Ϳ^[{9>}??$o?>U otwG>b]2/ 믖>!7޿ҿs >> ?1ә?:ŷп0Ex b? )vX<>nN.ӿA3+;aмI/H?iTtf>G;?ξإοb?,s>H>? HR|>>D?Ny,/>ҿ6)@E=5D?d0?zsq>n=>?VR  re? i6K?_?@¤ܶ0baݽ&?˿;ܿ`AFDo>B iRnn?w0r>!y:>sɿݩwI=h%> ?hʾWZll<ʣf>E8bC׽\=a ("hƿ+<>>?w-Ӿ&J EJ8>'!B?^yn?-)??Y 4Ygي_ Լj?.">?[?1N&$?+ql>K>NDV_鿥^ >!d? ?|B)f{(>X??̽B|05 ?A?Ѿ߿uK@"l;?6 } @"=?,sz|HU>Kca>7#+Fy_=?>bJ)8M?^!uі>(?Y-6$؈E5=þf?M8W#<ݿqҽUrelDk>6r29 H1}h@V0#?p+6π"A=?J9v&P۶R?\=2Hl6w2=lP>X[ukWQ8LƾBB7L PH޿F+F~P2rC*?Ͽh閾8=1n@>u>R >=> տ1+NNv@=`F?Jn U >G?m:`Z cg >?+3`=?XLs-=>4]- Ύ>>? ?=j>?<݃?A>iBjF>Q>L?v  F(! ?En?Z6> #w-1r?`?৭>ˆ+-;VE׷?C5?˻>DIoڬ S>!q?rrɾ@G`=~>Y%x␊^БvP=$=4ܿ 翝uT7>]> !cSܳ>Um?)}?Eg>9`ӽ>NFоŬͿQlM߲>Nfο1fM=65>&E2^ϩR;>,zOPi]+o;ɾuZ U羅5?$?>!iQ&׈??>Y` .;=Xb-=&rͷ>|?,8mzBd@)(>.?Ӣ{>R33ޠ>({"&wm>LƩ?0s>JM>=\tsm|# [{rl>1Ͼ|@=t пhpx'?{V_[>q?ԗB>ڹ7H?z}1?q*y ??>4=t>b=81>Ҭ2>: ̻qg?y5mѿ^ݒ2Ҧ?>Djhi"S=uq?& =IsR48ֽD9пwA/j=xxkg?\>|>Igak#Z`N>I۩ȴ91ƿ+~R[FB4 :Dl1?>>M@8? >>$!>>=ʈj>]| s>h>>:lsȎ? Z>V!>eX7VA,r=XS*301٩;>.l=ڐ&j;=C>$=E>}%{8-M>U.?x>n>$4Ҿ证>I;P=?&%?:o ??J>l'y?7P>]>;/*j>* ??W6>ܿMt#(h? f`?0 ?O]E(>^k=־k2Ͻ&?UC{}>ľ# 3 ]=N& As,h>L>%)po}yocͽ/b|ϜyiE=L=ŵ! mba=}> .bVRژ&s9eu= ?pTi$>_T=2G `?g ?oqL2!>zW<}оak,w>w=j¾ej8~5LJx1o뎺/ >'Ry*>o>\Lq񠮾u۾Q.p>=?/?>t?+J>47?(Z>? Sql3=>=7a>u=AN>&>245<^v;>W=@ v08 >\3 $ mo>6N$xQ>q5۽}MTx|ho>O?dP=YE̾Z[}/aԛ<1sHѾ <ί>'"z=)]^;ۭ:,'Ė*<7ZADڐ͑=Ӿ0ƿ;?pCnd>v|2ԾӮY#X >^H<`:v=-=}-dw>TiE ?>>P_3*=/>>./> Po>2SwS<>d>N(?,>9`?D {\=D_l#UCbs`>-9$D>T<: @_ =;뾊l?zj>n.e(о~t=N>}xÿ>|xQ5> !DW P/ӽVQJҥƼGO8o]>C˿'ݿ9R>-#)(u‡`h3;ҿ>chX @`)},_>#?& W?q?(Z B~3=>Q>dċ>Q|=>D>>'f=n3>׆>Ŭ>L=̾-Dt$6=I>n>$>E\s<[S>=>u70Q =P{x||>'?л?))?vU^f>P= (\>b FTU_|#`H=>>ށ?i$E>Z_]ٝ+ֳ>>> >ـok >C|>c=1> h[qU>/(dEr:Y>H=YQ>hgϽGZ>@7,?z/@ >ӄ> զ>A6VG>> ^%D5>v>wSpԿ-I=|7JHd/?uHՑY˾B?J>Y?d>N >9=z{f>?+|>A<l>o<?IW ?i<{ѽL??!?^`?#i?=?3=&q=<-%h=q>q>U>xW>)fl&7:νGC1>K[rL_VֿUWĄ$J>3⽔j>M}|==¾5=M =GU7Yj?FI,T;ܐY>,EMO=X¤B ;b!> þ=G$ݔzYS)?$??6D4>we?,?`?=dDHx>4=Si>&=>%꫾`$>^ISQV*=+^S=%x<5>ОYpY:=q> N<E?KKo><@>)#->wY4c=Tfɿ$u,[,`W>`?>J@?C7A>M=eSG==)#].(=zs.=aU>H!<0=V>޵>b=O g'c?ǂ?+V(Ti+>':>kE->J_J=/5>U%9=A=2ck>fq? $U"?S;3> g>r6Tn~h>N0Ы>UP7>E>b+=?3X\7 <?R>~R?n^hxu=Z?g=>?8";a?~T>d,?@>? >?W?sme=ܽ$oP>ʸ0u=k<=k;>[ =)>W$?%&>@>׿?hx)W >=NX> k$!>O$S>_5ał?'`>y,>=G?Hu`#O<ڢ?}* ?)L?ULZI=E? C>q?3_>~üѦC S?qt! >[W>8d2}? fxX>&W2? c>?5jtJ?_?ٮm?)0M?MKJ?2Y*}>,>P T4> >>=B?m9 9|>x ?>V ?mjͺ=?>?Z?$ٿo@?~ḿ?W>8\1 h>PJQ>$ֿ&-=o =֒.YX1ͳ=!<=7"?>O?FVl =:?(8>{?T(خ [H h>`ɹ #F{u!4޽ʁ;z9f{=h@#=ǂoA-{<+(>_7=|Jץ q>p~>RFK=15G=:Z>A˩gCq>׽!S>yjk%=lnPw>#=H<$u > c7|U>b=#:? R\E5F=?O+=cP? ׿iB?n?7q?~}<潅칪>[F=Ϡ>?{er߽\!Ai/WEo>Z=Ҏ? x>Ӿ[ S-z>7Pth F<~=saY=?[b=d_[ ﳾߣ>h&(e)-=u?hmph\Ǿxc|f0?<0,o=] t>CL7?o F=1:*m>o[jet>$>u?kn_M8HGѽy=7*V?bμ һ=Jo *#_ba>/ZF>O<>!q ^>4p~P{%ݾ>Hok<s JvT>p=P?ɂ͘tDG?O? q?ϳlux 9??@>>?y1 h T_?o>2?YDw`*?8M>?pt[JN2>=ۣD?އ`=Ҿ6>L@:ھZީZ|?=-ν{ѯ>.uj~y:?`r\??Q0Y>C>A?.p:S>>"U*?pov?[? ?,׃ڈ}>jF1r?3؝yo>;W?'XKjtX=pum?_;=jc>&= l?`ޢVʾlL>z=+?ZxږFva= ,m?d@6 >1V?*r䜰ɔxcC>6LJw?F"~<~S>-#sq?h^o?$'F0?6X#?˾:&>?*;J>j>&?}O7p%p>!ѽEɣ?JinڨMB)>Ѽ?Gbt](AS>{=?k.jidI]EI͚ؾ(?Y~7YoN 1>2vc,|8m?#7"RGt8|= ?1k?{\>>?Qv>a־d>|{<g?(M???Y?l0?>?sQ8پ>=̧?my|Q=$ >˔Q<=ȼe6P^?AoHG=5W҅?-7F49ʪ>l@is>p>{?+,{C?y?/dfA?ya?/(oT<wi¿">QHS?`??xq ;^l-dDo=S=?0_[rO<==,?1UԤ;Vɽ >pIڝ>lݔ?/{NA<3=*3?ʣC-'>1?Mt`'׀}x>/Ύ">ͣ:>@(!?A3n?^=I=Ǐ&YXe1? ZOR`4l=+ }?F(@h(`=(#}ax>8)Zt=i *0>a\.(>!sZq? PvhD,uؾ*FJ>֩aJ} |駾x:?vջٿ@1…# |P3== v?E,O<ۃIPPzm6~q?=`ؿ9<Ϳ{<$?/?2?EH#ÙQ~IoL>տN׈?% %K]q? s\ʅ=?ST1[*[9Qƾ>Fr#>6?/?j?9n{[ b?1_7`?/l6Ҿ-=2n?+w}4KbA>?? ?--j>P'?jֻ?P?g>3|?R?J?8b}ˎ*>>?]:+N;f@!=6>&ץ F=5sx87=H+EeoNR=kпQgfr|j`lf=ɿc"k<H=.I>/E>ӄ?>ocd<_>L>j>a?QzؾZis-u? SKeH8b0To>xHQ}~ >SY=g4?SGJX9\=0Ex> 75?*v=-;XRr0?U??7?~7|@쾠} V;&V?cxtRF$H_A>exJp:z=k ?O]Xz(Cf=_5?">`lJ(C>)2~+q=5o"­mU> t%>tg;D3@vѾǂ2|5???6~?,,557X?J(?\@?paO==Eh?B[nO?Y?wc<t>^?2]?vzmʾԇ3=T?/%_f[t =S zW5zs>o\RB3#>;?=}>P%9¿E5najl>y:% gۿ8D;L?$]?e??ʿ6G>???w8͔\g?1H?jO?Ea p%15>?,K>}x >i:>?W7pôWX>? %>#` l1>i?D>Z6#%y=;¹>!=8 {9X>?+#>lIu+~=Ϋ>V= V+Q5>Q?U?;?X9?IO>HIU OqX?9AJ*>C3=A6 3$VK>?];?|>RkE` >?k ?>yyd<5x?)y?>[,ޚ=?? M?zW>7h>f?9@%?QLC=r?nv?ւs?e8P=g?y?ё>B޸3K>{?.=>)Q7U`n>M۾P>@-` ﯺ>"? ?: C>>"&> y)" thy:>?m)5?> pyvy_Rr>J?^@?R>ԇ8>=bQC龤IwW=ǁLοAwaV=^$?-(? >*ea1 г?gg?z->` 3??̌>ga6))?8@C?a*%{ľB?!)אubdXbqH ?پ>n&&Ձ(~(><>z>RA 7ƾeG }?b9?Kb>wBK"fKzg^?@?\_5v@4?H?\?/r?( >P`5?{?*"0Cҽ2k? ?J$)%l7T=aUP?i?辉]3y?'?2!?#P߾G>G>7?u-Up4::)E1:s.C+>9rwub>>>?E^f4Vr=? ?<\mƋ=> ?x tGcHwW4>Yk?1?y>C!Oyܵ?y??`\\lr@?q?tھ_,+?+F?),UYq[ O1u?G\?7*Q+޾GW?iB?2׽-XEֽC ?D?#tre =m?+B?Ɉn#i4/=Q'p?8?ȽG 2H\%< C?)8˾\0Ӿn1I>Ⱦ8=yJ#SX>ᧉIs?VP?,p]?A-?z ld>A?θ]ٞRhȬ?THO0B%5 r<1? RPV=&>~?) 2??ˁ0M ??=!%9pU?xy-?L7<l <>?4\2|/=? i'?W3^7><(9>$?k+ftG7;?!?\VnE=JJ)>N>>{܀龺=y& \ ?`_?c!(->5^??z>5%(>Ԧ?3F$p F5e?HGH'hC9<]=ۭ:v|A׿n?4=>>{hG>Yks>=;?Mqa-z$YὙ?J?bT}[Ps{?Jr?b3Xz$?K? J`ž?(J?P> )> 3辳Ԯ>_{ z>bu?"Žb9$ρD}1A>џk 0$2 >B"wQ)\#7>,]ل?^S?}`]:?(?43(tͼ=ƾ/>@J01/?>]?2=X֑bX$? ?J]T/??ΰu@ؐ[kk{)?&?нdՌ]7_?ew?HdBn+%xO'٥_|87=`gE9<햿"J.=>OJF>N>`?q6RoKd;/{>.Ҿ@e >Lϧ.=|=.#>}>e>gA=$k-I﷿N}F5/b|ӾzH0ܐi' B=ҩP^;ONj 4 ;]秾K =& NFrjJ8Rm{v\謹13 $=ą>dX/@B/־n:ǽԍ>>,2?>o>?z>67==<+0[>r>">VDؿ tg>p Hþl@<׊+>e,ȥDy>ݭ5=YL0:(x<(<>_ >>X? O?qfFt\=Դ>(_>d~?+e0'(=j=Xٶ=7??{>{S5+mֿX>1PEٿbt#N9~Rym;Xɤl<Ҿ-ྦ|Kca̽]=cfVضRҾ޾?h&U>lx1wV@F=)A;d5KV*%>7y l徣AK<Ш0ҿF F*^>%> ??kMŧܿW;UTz/dӾq@XH˾v.1 F - )c&`b =$WnB>44>8Oyݾ-[5>C\ZOgi;ܿta6 =/ŋh"V4<ϚIf˾Ս0|-ة+>ϫ =_q='پ'H\ϯs%=v$4tھyw0>:7߾ʗ=UË=~۾'a$kwP,3+ۣ:=,g eVe#")uiȤ]q<~ܿa ÿL7<g=D/O$9ܿ*e>_=[Ŀ9!&xm@>CQh=)=2 dw> VxO>@oi>̼'>F1/e !@҄U~9=pWKVlBэ)ҾR/>SBhϿoТ{8>( |zDT9S?t?v3=M۾ JLxg>6=??*$W Š ?8G> Q*EThXX??Ct޽8.˾O?[?bz[?XD>P6a=w?Vy>ey:N>D?Jv!>ӻטŇt>l'?>?!$ w>0Y?? QP@?߫?VP? an"Sa?r>*xIEx4^N}RIM$8qQG6H4#ܔpw> ˣ$5 rz>1mnw#=߾̎QXboC?T>Z|7;`neu}} 9? 5+bh:kx%=Odٿ 2D&llP=c4P0B.)?| > v1||H ??{ʧ>2Wbo? FR ?:>'O/`W?S>s s 9FK >L۾,Yt4)}>Ua)u >Hht/G >q˿k%:g?6>^=`'s>KZ&foa>ښ_L%Mf>x&3'@>'D( >*@ȿH%98~zlGG o>>޾Z \?>=˾Ya;𳾘m>ý=Hg꾆[>'=R0>{׿/nŏ>_ U.,| }o=C>is0]`L/U}F9B4BwLо&`:.ˍſQH=m鸿)Lw2/)Y6U&F4ʿ8PrP̾P۾<\[)ʈܩc?->{?#6[zz=:P9L0&~;cP/>dҾ@=ߏX>^w/fD)=n&25< E'v Bt2K4>s=4V>yz=ޓn۶ aЇwg<۽*B| }7}5=7>+>F 4^׿Y>P=H0YnZ>_m=C(p ?!~%:+j>4?Cڔ>]!\zĿg>?V >mL ><?7I>eo>uGTX?6?{a>x>= ܿ[9ݖ:>y?KA>߽׍PO=J?>PX𕿼[>?T> }2f>0?Qߘ>×x v[EĿ,, &C=3?;Fzxn<=سpb᜿J0z=&Wi㿤IE\m(<ͿwǤGq>"SNdO /Bj2>. Q>q~OY>5?G>DƤVyF=>?h>*o;¿>:yy? >8ɸ:!>Qw$ @* ? >{l3 f G??ٺD>9y{zTпb???P!wNy'M?DQ??4\ɾu>K?A?.cq>h sa8+K3z8>Iolo9^s>_[&}^F&|sV>Gԝ=BWW 3T=q@M2 8 ?JE2j>2}F$*dgj>JFA>}g>>O g? f=$>a֌ MI eĽ6O36huw{Q3>#d xa52 _S>U`xjŠ5LLd>47Si-REbT;>]S>!̯YU}jt>4ݿ^(63Q]g1>dƤ8P*=58;>7CsVgӿASzA.>:ZMϿ[>n9K>n 561Eῃs=:£l|Rn i>H&27οKR7 1s>I;?Ki/, >]1 UQ?1`=!>&`^?Mƿdk=^>N3`[?@>d=I=?Gs1fz׿nX/>Zvٿ񿧘VB$>Hnn:]e?4z>O7WпSti? :I? A0/?!:'?MV.얫?y f= =5uv0u'رݾDQvP[:?iH X>bF=2S?])>{>Y&W6?Mt>>d9 ݿ9rX? 謹U>n[>f)kڨD>=?I?Lܿ=yj=4,s6>Y==i3+|$>>j=m&7&&?̿>Eoe>PW?>?>e>#Š?m{>;?'>X,-C|?8=>>44Sڔ?ҠJ0>_9>c>DSnP?G=:>P=Խwizt#$>>4Q` K~=5P>Sm<=HYR=~B=8yľ@尿i?B>E0>? >Q¾Dp=>g:>O@w>b?? =>{)>YA_$]P=>΍T>J[? [}3><Ԫ>>P<܉nh .?Rn~??!?n:?A3?\-i=@Z-?6\MZ>>S">^:Yq2>At>YL7Q f˾!?]r?6۾eƨ<wu?>J>TX?R?>H8>=7>h9<{pQ f=$hXCľah'x=z5O>҅/%>>?FپB9T7oM?q4f5 ?߾xMbA0c<>SXd=c{&=IaG=`kZl][N~^=IEᅧƠyF&XɿO}5PH;`觿P`vydc>Usmǀn_/>f翛 =ߪ>Hֿyt?$k >vl?/\q:?ǂyn>?Ozÿ=?q>?&y0{XC=p3?>zK??Y<Χ?Ͼ >tY!H ~b=a>؝BCNd>\x>!ٿRf/GtK=FgsJE?*yI>NH?)h> ^>> IIi?.rE>5>a|9MMB=? Ց1 \0}= ->P#?' Un~gЉ>e^F||l;o>'.ڽQ<.}V?:#N &ݽ !<=xۿ@#-|j2p* >P4̌RL(O>w??+ؕ41 S?>gowWX>+u{ie8;>gcQu>ίm ?u˽%W>g&f*Py<fKDN17?$=# g?}o>9x?.Nl ?n>:? EJm"UV>[RD>H?#[`$T%;=Fƿ;wd$"F>*kt .?wpQ=wWYdc/b?ll>>ݐnv^=}V? '\+T?M< ̽77ڿ(A1:E;=eegC|1{J>?mc*?-,?FQо >UC?MYa1rz>1? p]]?d+s޿X?6vB= ݾ{16v7?[>v?MYmI=e^>?X]YY]Qͣ-0 =b'?Er9pCRNp>-J?bjʾ_`c'ŬE*u)F@k=mPuͿbLe(->s?ξNpi鴾6پ;X?=_pPT<4g{"޹A8}nMRrPk=ൾ >7̼E}ΐ ]>νsV ض`bG?C\[,[;:|3=B>Wb8h.U==yV HcI?ڌw z>4/?Xܺ/UP>%47?hH8e=HA=[iY$)^doN3>VT??Ŭ>Y//b>?E?>" JIl/=&>޾8?e8־)|>?Z'<́(=Bٿٿo,=|>;E6=HI|m?q?r=>-m*u..?%Shd?>]?9>% 9ㄽ>H"6i L 9==.V\ ?*Qm>*>6tw6A̿z=R>?"CWi?aھ?>2#N?>&֙7x}Zq;)Dп?.')ox'=oڃ?Ǿ-P^;>?l<}\=%>b?ؽe{|?5?`>jQ LY>썾!K@hd#>̠"x9@rK^꧿pY +[MSu)?7N?)>n/8O-->&s) 5+ b>ˠݾ!^8!r>HfJegp=ͽT>m?=_%!~a>+?;._sP >?DJ=bHl.R>Dfm1r6'Ӏ?IDSJ==x+I"O>fEֿd.}7*ܿ<^ CǴ6:Frhu}fm ͅ>%?J>%j0Y+Mv?w>9>?u\,RhM?2o>zh!)1E=r\ra@-yWA }<6vN'XpS?"f>Ĭ>>>t>wþ`F>}=>>anhlhP>=0L=H0?":u=s8V&cM!Q> \o=򏟽=K"$2F*>ϣU>Oy>@>p)SC>]>|(>ɏffŅ >ܼF='1'a>=u( 2? =y->1Qe+J>2;H"?սEz'F5 'aƁF ת̽>C >/>,0;?#~,>yh"G|ȍڿ4?' >?&ڥ>}=D>CcwX z%>U>?~>Kda<>1h =r~pjI>Y=\H>ٕTL>:>n>_ =v(> +==Y4g@coF>(_bg<ʆ ɿW0>v_=g8`zt^=Ӿeeˍ{~֩žLj soS\cY>$YA!>??B?VFVq>=me0oh>-{<־`E>w#>sq=J&˼Oʽ;r|!(=Rpm /Hk(c7U[?^?o7>x2> =><}v>Q>5#G;t=Q/!y>T=-m¾6^̾'q:ي`]b>s]_W,ܻt$߾j>>z>fM>S3>F5ov>v(?uΥpnI> >2e={ָw·ꊃIzB.`&x^<]5⹼!s8<輌jJs፽iq־;;9>"s2>ǽ=)1d<]k>_'>V~_>QϿ~'=+$!]ڢ¾*3{kB>Q>oD> u>R`'>jN=u\>Bt\ w>k=>1VVYƼ$>1>m t>T94Co3==%$> {)D='GB,5̻<̧=LIGHD(<:X<=a=M⬿T>AS>щ=>] G%J}>[>;,>Zg8_=a=x0^+)ڽطȭ=[?3>)>Xz? Z>%l>&W>|P>I5,j<ɐm4=V2=+nT=9[08=EE?7>X?4pf=sOT*؄ɓ=N $5t'B?rO7F'y>ۥ>]v?m+X%MPe> Gg>(w˴8#g^' x?<13H>̺0>4?_I(:o?v>ZO=U=om=;.Z0@;0QU5KjATuk=WGT=;?U\X%#z>>NC?j0 XM>`W<>BxA[y>>:l?*J-eC>2 $?>P@D>>%?6&pD +𝌾d0>\r?{<<e>[syNw=h_>5g!w? >J?D6vB\~u>Kh߽^ [WbpB=)u.*Mc:h>S3=Y>-3Np<վV.hV0"uE>F>Qr?J8=>>lz? ٲ|=>j>O>m >&/&=??j?5?MYO,_>|s=.Q2>b;?L >|>\?'>4vξ//?>B?=?P(>G(Z?5>QQ>FŒ]HP=ak4>ACW?$þQ>":*E{TͻM=pC>>R1͊оIR?7>23?`!?Z>E>W6={?t3D>p=y>C?Kc>gnD`1>-?>u.>=%~<>7 W?4?1 ?GMk޽>f>>|h>>Wj/=<>jF>>>)_x~>m#> >k?;Փz7?>?Sr?Q:b; 7;}> iQ%*>a>0> z[=>> '>L>D> >>;`>/I5SZ/`y¼<ťO>1+_00a1ZK>ё=2?!N^`=u!ɿ1 `ij] ?9?>k?EV;f hc=7>V\=?&J X='Hf =H0=e{pѿ;,F==#Dt>5L86m@=>x->1{ihE=D=>lv>{&ؾX0>dzE>!=?Mrzl?u?>R*?WM&|n>P>U򈽒Jk>qi>K>y>~wQr>2{> p=o?*d~$yE>K>uH# ?Pr?݂z?0|>=?WnN<a>K>_?n4h ?>d?5Ah{4?>4"?*#j?[>E?4 Žˊ]>=I>lkÄ>Hؽ' >ɶ,z>Z>y=/? +>d>ѷ;>Ӝszy8q{>7>8Y?0ihde>  >̲S=_?$RlfYX>t?!g>?`^` P[[+> >%E?3n 2&>R]?#>ۋH?9± >"w? T>?~2xTG2?6u? ?d16>4>R?#gϾǟ>>fHA? 3Ra0? >?7-#oz^5>->%>-? 0>WP+Ss7?c#y9Vf?Val% =@pJg>e?&>IAB?H[K`Y`= krS>yMEKv;=J{ p>W߫>7dk?{> ?sXӿ?L?3xuh?d>?0uΉM>1n>8Q>\_X2>V>l?z>c=gd>"Ԩ|ő>(-=CH>r7U=<>XCx_>dM=돛>`-U&G>"ZAhiTO=h>IW >! Gc4 ߵ-0>~>>;?\c(!P,nS>8><<@ p?;>#>z>333?w4/B>XpT>=qO>S]>@>=5e>& m>bٿT{̿l53>}"y2ǽ>I3>/>j?/4>OS0Zl>TP8>vwp>R>?2+} y8>0b=O{ď?oZ3>Qe>_:?;W*>* C9>ݜU~>켌 (=U== >ȕ>4#?4ѥ>=C>>4?%iM?}Ң>B$$=>Ž,R/9um=0־k>06=Web:>߃V>4D>=?kW>e\1=ǿ$!ٔ[?q.>y-Kj_JU-f?b\n?fkl(/;);.c_=%̴?#(>?¥_W=7Q=U\w? QX T=('1kf> ,=?>ǽ@d?Z;Xʝ侢=.>ɾmn;()g?g?˴LH81k=x KV?R`*]Br'>> 5?`|hٽݾ Cc7>:ObϯýIz'Vʫ=r> [?&>K*agԲ>=ˑ?CE۽OejYIEMC|y +r.JJg>'1r_>"$\dw>\>](?u}IE1=;Rk>>iK>$}!Ⱦ>ap଺B >JLhX6 ļӮ׮>U.愨ZY kN>eCщD->=)û>#=x? i'>*>D0?2׼n>E?{?nIHUFM* >ɶ=Я??,1j>yא?>|!U=I=nc 9?1?\>YwᾸe>ނQY H04>qÈ==L?tT=ԾL?X\DavS?wK ag>dl?v7l:1"u?QD>X?yY``H>?>ԑ?R7?ew>iSV>?iL>DxG>?Tuٽ3Р>R.T͚? f>sO?PlI4>m=3?3xw߾?>lè?0?C>4&]do>< RP9>J3=)x?cbaճ[82?4Ѧx[=Iྃ?]?:>ϣE>Gþ?i5? /?"Xd>,^<)9B_? tֿ?.2?j',?dAМҺȾ\ɿF>ŀӸ'ľi*=VK辡v=uN/?;ŗG=>H˾K?/&=H'u2H>LJHǠ{O b>v8IoUu?㚘̭0^>L<ޞ?Vmy2.@w? $T@o \8>{B \_=ߘc7?iBX7Ġ1ˊ?D\[=|1 &R@r~>kzo=]k+ l>ϋqV*'=?&aB=?Y^otaSžd?1 _:X>ƾ2~?tOLCUKbArX?2f7n`< J?WB0Ӿ<鎾Qq?Vgww>&=q?`\vѼ P?^xa!$:>z=>?io;;w>Ln=H?L tOB^S>a?:?XK3$-ی>ޔ>[!?xj>q?ij/ndž#?"&H0m:`i?H^~db>PU|c? (|=G=GiIF=?eFbxH>\>= ٮ? t0<?ĸXS:&N3A?0zpdϾ}ZY>(l s澪l?7?P(JUC&?:@',+q2߾^>?^x}>ud;;x?Z:?8>6"<˾|C?_.>~>[ ?,,?`\^%EcNXی?L?#gM䂽 knRWcX<^z;i["K?AyiJyㆽ;6?(jAjQ㾑]ds>pa\=<ހs>$5K\.:=F?3% -fNþ?-4j׀ =1w>^=٘?(u.Mv#=ꢡӍ=>cglr㾒>F~K{lZH0m>ɱ[=={^Ic?V{_=n=IR^?RQ#?}P?L?%jkB>a?1F?"?Y=r YZ?P}(wS?X:H?q?Mx?5? *L?e`1y܃?0/j0?VW%@?s ^=i]xW)?y%_>?gb??K>O,?J?^-Q?˿8a>9??~?||p>???пIb>2?l?H?xC+4ʀ"a?| 6Ⱦn&=F_?/\z>X ==b?XY[>aޭ?C?$?@|=,?8;F > \?Jw?\?x&=F?2v?e?= ?Q?j y?My<=`9>f>$pH}muN~c?e4u=c_ '?ОB9Ur?'x'ti? 1/qe=O,C}c]p=]ѿ`eӿ f <>t&_mv*2>X&PſhLGӥ>s>p;=S|>N>? x|pH/ڼMʽ ?4€G<ꋏu/D&-=G>ٿ PyоX?ې? x?Ⱦ/B`>RK(@ֽn-<\-W6>Bl8"<¾ڊ>R65;k<[L½If>QHQ:>P?)d? R;ml?_c?!?>V&T͐>>? 6>?۴p>_&'/Y%ǿc>?"h?4?.mg_ 9>(V?L$?[>+8;>S? k>t(Nq{K 9`پ> $cս1A(g{@<\mQ=+C+*wTt=O)ԾӐ!B>!ёVH 8W>_خ=lv?1H{@ͅ>>gD?Q\?s>gGP ؾ cTD>V?@?.fX}=?1?YX>taI$L7r n>S-F% ~>#>?g>Q>>$^jcsmC?Nr>I:ѿE >|t?:1?>C=Q{>i??1 ? {*>?:?/E>/F$?:>)b(o'>;ԑL\C>]p)߇8R/#>^?tK@f>atM@;R][\Ԙ:d!qV!=5c/<@b2NR>Ld*%>Z%?H?=qd G$X>scaO>󚿿"b,d>s l?V{dY5Yw>>i>=?"[??)I 17?)=?l=|r>?+9?4> X!mH=e?1C9?=zO@?}?>OX">>ӭ`SϿwy>@ &dv>(>dҿ"=FB>l>ܿ)"u"{pl`HjQ?H?>y"Ʉ~>/B?[o@&>3 ~>+?@>+ Ri;z=п?)=h=ÃAUP4꯾=d SOA?eM?I>\yPA1>E`B? @>Em<OEBŏ b >kD>+?%ȾOL>bWg>݃>7?@@Ѿq^=AW]>>l]?n{?z>b;>#N=>?jmD>SGN؊i?;? ?+R5!,?0J?=;=?7?V?'e}d8=?f{p?צjTl8Tеx?5a=RT?Al?꧿$i 23>>^p?}S*u6~W ?O4rH5žj1BI>$ y iHɸ> 1Zi=]=?r =F)jAE>(9I9v(ɾ>Vqٽ+ !<na/%Z^x:֪m=T:N> >k?`>eSi??Ԅ=uhԽj?3&?z;c[T&2Y>R>,?F h)>->G,?x*kj+Te> t>?fT_v%&< =?:FN2&Hd>_|K =VO9 .E_JQ췿Ӊɂ'PܐG8L?qv?L=zA?{g?=]ү ` f#|?|?/]{#8>.N8f,>ap^>$TX&`=ƽvC?ij?Ho0.EÞϾ(>NY)}z<,>q:i-}pld'=Ei8GǽmU9=H E7M^?br̽$d?wʧ?,|e&HV1M?6^x?R "8xta?O׿[ iB#ƈ{=H?&9i"c2j:m?׿ 9V" S-ډ=zBپvq>p-Z6hн1=^>#?jLG>@n>ʺ྄P..?ne$ԉ> >qi>+=aN̡>`˿K얾G>iヒ"=w$.$ӽ?eV?Ҿ{]Z;P#$?y Umz٨OĻ#|?oҦ?pdDK???ϫH\eL@N?, ?kYfN>?csa?$1'!>/w<1$Z`$^ݾW=Ô>e[O 4ɰ>d?Q+=R>-5?yX?F9so`G\ -o ?F?=!S9ebw>~UF?"?mt_H|YD(x>?w'|L8$??Hp*f վ >U?fL)\Ue?8?1ƿ<@e6]F?0<}?67 r9o>X&>_?$*5K+GSA)>[6RSQļ E?R?"oBHHU)dϭK>#0eds=kǿKrDJ<?7?vqiFץ^nU2??[r:m a}վ v??vKEdފf'\C-?+? Y|_*k v{@;v>3@EB T=PtX rJ>H M{H=xĿxclN ??-h9tLo P>ty>l_aP]Q1?S)?9ſ:X>1ݠ7><0>;j>˼>q.>/?q$>Nf> G<%[6>}=ξ׾klT{x?p=yxF ~rm7=:&]FRP6P?|9?w~Xo;,?Z=?a:ֿ1`_A A9?]? rW.> > }QL꽆C>Q>es:ZኹVTpoT3 '>罞 m"?->w񲽒[kY?2%>?ypT;gY\D?C/?[HcCp?[$t?f@7w`Fpv?h?}R.)dhSQ/?h8?>&B{y9k+>M+>?3.?,>> hI??Ȥ*BW> ==+o9\nvPH:ڿ%Qc>G4ey<ڿ'{I.>n>Vq#+ Ԁ<ٶ"IR849N?f ?Y 1?KFe(\`??XU2y%b4?'L?]WsE) h^Z#}?0?Z:;>>>z>? ??{)nD  LD>0þ9Ӿ>fVi?G,>S>>6XqK0'm:`?BF?|~@_l>A ?YѾPL->U>A>y^?!x_r=.(grweWͿ 9q{o>:QOv>j Dkr??k>,idTBLȽR+? c>9T+\S=н ? >sp]*??7?OWj 3x>S>fe>T>&>-? e=MY'< >UWXT7ν ??c?ѦcN2W5G?R?&RD#+)7?a ?5G998pxG?5? }gEQNW! ?Jk?7a{H9|?Y?,xB]UNҽ??uexRK q??N{JTW½?s-,?n|?T=&A*T& s=V4)2<4{E=.6l' P2>D>`>?*/EɌ>~&<=>ߓ6`!>5.$h?Tn?$W~,xRO{?s?Ż1xSp㽄n @^@n? ^T_{p?:?;>vBT>7@4!d@5a?aWa?t2?p㽿@DWq6i຦?bb?)DG0dd>os?H]?׿eQjR>нݭ?>ع gNi@A?,>XP0l@?{> ިRоr?ty?;QbJ;m@@ bV>ߑ`T5 >@`@ ?CŋWf">k?U?$U"U:ſqGk>GB? > xt.>(wh?qT?"mξ49=R7?bR?(L 5r= ?m?2i %MBxLb??QᱽT~f|Ľ,?G?leF>?€k?>PMV6 ?zE?8dzg??oNj[>R5(JI?I:? `A3'˼?Z#?Cz{JA{?h? >O5~7?T?*NMbLHA?M?6hnҿ}1>Wi2Xֿ UOT`v>h4 8ezO>%Wf?S ?>q9B3?m@?s>R!K,w1'U?F"?_/4InI?y0?2} LY^i6i?D?-iogU:d?Dt?pmaڅQ>Gٙ?A?L{g]zxX/24=7;?>nrw@=?#>>Xѿݜ@ #*?.0>)0m4Dq= 3?aD?b*[%xFv?w?:m& Of-9Xˋ?$a>ʴt:̒uʎ ~F:S\}w-gV1z 3/I]{Ҿܭy+0KuBpȝkV>{}>a?ľ) ?'ɼ >¾`n+?wj?‡щT0 ?0K>.,=NJ١)$/Û̾7ʧ!)(߭'M6(di쾪N{? > ׿9!6WyV>@Nq q~|=-^~(8S(\%rHԾɾM&:z#yn۾7o(fPa+*BҾ XIʄLǾ$nG1pNna cd-f ֠ܣ3(o71w"->ٍ>EҚ;C 4,_/@t81!G}վ߾_1{ɾe$vr>dؾD ؿ\L$W8=jnQbx!GZ6Y>V28`?2f=5R#fo]Ļ}A=$̿с*}ew5^[| J` ^#>eԾI >u>M?>$vr26N|>A?t>\Ѻl7>w>',*N>?>'>}後> Q3>tǃZ銿0>x?m±?%S2һg$>Wh?Gz>9$b= >F?vR>:GID&= B>9)L{=OvLI3H&5᜾ʳF]mj>j{W{:dWt=VҿK芿z>9؏T>d>Ѝ&JZPd64L="h 'iXMo!h =̣^?:" r=X=l('fB=$jJ˧ I^a >33?Od>t~{ھZI^ P>-=e^q؝?cD>1dmjm?xK>9 usj>x>3>>ܿ98= ݾ$?-a?8}>fVf@>>s~r 1j? .?Y>GOƒ]n0hgF.>2鿃޿?t_C>WT߽BI?:=*cRdË=Ӟ]+Vf=œ>Ͽ b囿]D>2ST\Ŀ;q=}(9[O > g{r=(R13>e 1Z%>Q>xS$?1=}p>>i\c ^^2 N'q)lnH 7 cJ'?˿r=)>"U?;?!1{=3 B>J,V;?4ۜc;o>6 ,X(Ӽ>]vhL&)0RU>j8)xp޿;U7̑T>fZ9i@F?MRn=>iG Nxݿ濄w?>v>3Zݿt>cr5D?):(Ks W^)?dA>(>!D^?%-X~5=;)_FMbN>`fÿf;#-Ov>W@یԿTQ>ȡ8NE> Y#?N> >Q"o?]ܔ?߿y=OY>NB? |>#>OQ:N 3:J>8D[>f3>H>7\K3)c8 =#Ļ @/Yj߿.5??E?K=M4=X2>R"ٺ +>c=/@Wѿ?%J>n!=@8!lek?n>=@B6Q b澓ܿ ?sN =?8=>sٮ&B ʿ 1?g>Suki:.;?[>*I>[%?O>>)ӿMr?~|[>?M_?.ɴ?Q>o?+Q>v2E? i>t>]۽ʿL?^>ē>>CY6@@c. ?+D_?ME? ?`|>?gb>?O3&?}>_f=seJhQ?.><)?DJ>9T"5>v{ =c=.<}x?1|9=-=Qn=Ϳur?|>)<j;Bc>Qɩ>=fk>c$Ⱦ!H?z=̜ >e>q@O?݇>r%>n? L%?7>]>>8m^p>Z6w>B)>_,>XT>?! /Y>sU>'-^>ǿt(?WGñ>cr?'!'-\FS<*+$=~(!# =B@J $-iBλ"Ǿs;zW ޽ܱ2F0lyO=?RF_,03="~>t%&Sp5~>->}㹾( ? |>5Ĩ"t>6>Mי?!B>;O>6>?m>ҿ qm>x|Xd$@_re=8^Ŀ7ھ3:!@3e󿾸<ѿKS zY'N=&侠X޿Zxؾ31>ܿ)UQL<ߨ>Z ݿ񽖜>f0ϿE?Mw>>")+)=G->H=18xW?)U>wd=_ci?sS{(>>>>j˖QwORz=}:>HԿ9C  bN<=nX>w#&=cx=??wT¶wUX@=%?̿_lCPX==?_xu6>Dl?Ծdn`娽xi=!;E9<bYMƿ m=TyuP}@=:>Yps6 |D>9x[1ͣ0?HWm6>Ü>0 ŵp>d# 3@>R?{)NrqZQm>2?(FJAo_?= 5}>Sq&=>[BWuK@ـ=:<3 $@~;=#;ҿ$0=yؿmο]x@a>2=@-wr/4ž>lA?b/k>G> =Ѿcg`](G?~2a^Th}W?GLD*7M]Q_?QMPX$BOi?=پÿm ~uzL>z+"zxgc?Pd9`ϣYnL>?U@yT\ _P¦>>bxWYm >j1g`dԿ7L?Pc&}!9T8zS< _Ŀ_:>V(d?#3ʾUҿAC'=&<>͋/f``;x6?=f2ߜ?h߽hu?La/TAi?LmHC%6EW#!>MQ?8vE$G>۹A ?2a?{>-v*LD>Q><_=]gx,=F?|X8;#=iR/=$i=ҩ־.=l?ܖFop7<`=;`?c~ zjDor>K=5gwKEP->?48L|a>qmn>xZ*,=0>Jsn>?EgojZrN@z<4>1ľli?)?Yk=гr0 NWM>Q2D3=L?!S?nD>e))Q?񽕎?ܾY^=[#>h?I@GiZ{ ?5@?>>C8?י=>9ξ}&A=rb>HBC CP=E>}c;Ω?(v=B||>(j`a\=>2qѳ F=6>U?ȽFi2>(>Gd(?+i#zZy>Y?_1?>(hH= >?½3:D >5D?׺J>7>b?{p'0ۊM>+ݾW,,L@[]>kD9Amn>W>xx>(YCb|>'`\>J>xsI8b o>sz>=-(ڶρ&wOГ1?!o?>/'Q6?*?>5,e1?n3?`>^B]$?>?+6?(?>(uX~?=?=QMuCΧ>Jm{ٿ?ND^%]k?_)=i o(TQE? z?[>G ɪEk١?7?U>s$˳@q?;?ɻ>udq b>GƾWjf<;N]Cg,}/6X g>zBjHR'|=r=߾W+4a,|l4¾<>۝^?\O>_d)=Fg>+cҠ} |5>N`rK37P!_ l׿'\\hͅYQ@ 00go?<ip|:>B|O5h"*lrL׽؈d10I0K (LW:5½`zG3bA9)84/?BBu9P^Sھ 7>g?>ebE2>7|?G>)0R̯>ˁ1\Y)盻>mn? >qz\%5Q???C 0& R&~k7>.νr=־[>5aԽ=`-!$jM+>3շ1$*>zp>!^aJP>=i$2/mb Fg/H4=;>L>R->>T>;l׾~=|<,>fm=L&ybJ>F;6={Pv8T>К ߭c;`#S.e~g^5ƿ%G = \> n/إ&ߘDߋ>|N@_{z>;=;?&=K3wE-=ŷJ8fegHA[!>#zyX=UXQ=nc͕WBDC=xw+:i< H̅ >]nH2ehxu>r>: k>/,?YR% ?X?bl?kG&ԍs-R:*8P̾3BJ.y;¾ X> =lq>#-ۼstk*=4 ׾xT{5=|x,0#PCH5Wlfv|(+#V }$dN |"`>p>s>NO>rO&>ڲ>=>N3n=gŬ>,>k>oe> >r>ti>ـpkd>ͫL@]5p6`.>?>v?$m =b*,yH1G7xd7>+?Ur?7?oW?\9=?1E?{?!lԼe>6">r>O>u >Q#|V &H'= ># >q4(I%p>w?I>na?4"p:m>k>> ju>l@> =g'>=t)Rj>U>V?3& ,=Z?G>(?3D>~I=ƻV%ݾXo/>ۭ=V~Ⱦ $F=a>s'$>>C[>7ea1?'? R;Jf>a=E>i!s=^,R~h @ 2;?=_ =Պ16Zu@=ك(nL4ݵ=YJ 7#]>v/NE;ڰB^sېut¾^?5>>͕O磽?>?8D-PD?>ċ?A gh(jоkS>ɾO.j=ո>?-<>g?yHJ .=/<\4d=)4~=t>5ƽO>0@VZ-=B >8a>O 8&?cL m=Wq>U>.RY>.XZ=R{->>hk>῍e>b^W=&)`-={>>bv2>i-f=T{$܆]=:Yl?T"V>v>-!">+ ;K%=CA?>$?+$=x>p>k>HgŽcp<Џe=/=@>8a;>mC>NM>!>SvoQ>h>:'X|Hl!>c>$~?[`K8dpL?OI?tO?@n=l>T>N>)Nng>=u=d?c,їfܠ>>?-2՟Xz>&=?B .T.>#lJ=g>>L>c/>>O>gWO?JV'>c>)=>WvlM>vt>x]=w݇>'-(>4<0g42>Se>{=>dNXfȾx?2I>&?l na܌=ܾ6a!tj *< /_'‡8>U)νK=;v.oJMO[ ^YpDB>n1׼yB>}?4@>t\j> 3$#>Gi>|,>#>3#z>U'?C_p=>xP27ο=s:۾v?@j?F?Uw2pоq??Ҧ?| W?ț>] ?gZ%D!B>d>UɽV>̧['fF~=qmB> Jni>jο$%:7*>;=fǽDڐ>T0=#-=Mྃ>5=?'_=eqxo=6f#?>^(?D4PpY=@_>%GZdz=C>QS">3Q,n>>j,>v4|>G=\i/>Tovt0>Ս? S>|?Hu(u=}>9">^l?>6=2=B">#}pϴ=6r<%]>t';=lD=x>>i2=>B4W>k<HGi+>|=־^'*k.,xr=˸ քOb8 < =Qjt~>>@,( 0(?œq?b=4*=SN?s>m?+Ɋ??N?1ҡyq =yt^>fw"M=㽍>@[ӻåfB=9;>۸waɦ=[>]>j[?|9okg=p=l>NpL7={=1>ۯ>/>V>]?VO>;=|?HY\=4B`ܾK|"w =г ^]/U>[;mec=$>F>L&>7>YE?8#f2b>ClY>\ ?!=>?9?>~?iR>I>{< ?= Q@"L><> )ݻ?"hؿ>?;??lԫ>i>^l=z?P zN=Y>@;>w#>᤿IҾQ2~>=Iؾ=YҰ0Ƭr 2>zy>\>&g(9>eq >>w ?'+w04>+ ?U>%?S?G[?Y>` >>.?U#>a!h>*0> NP[X`>=m> 01S7?1dh>'_=IǾvd?3EP=6>Y3,?4 >)?&>?=d0b0h$>.>'* ?=!k-9>4L>ݚ>Q? 3.>к?ERn? ?"mX?H>?*X/q>?پDVT> 9&b>%8x`VK1 |w>οXBȿn辌|b>S>㲚>ݩ?!Qb#>>ս*>6s`>H*=l?@*1t9X>=*e?g_>bVE7<HV>Vt,>3@(>ܿj5X=>3>"J{7սd|$w=Ȫ> оk0?%Bw>>n=Ǹ ?{6QP].G>~?>?(I0Vn>>Հ>a?Ko;G>&fTb弬#ty_>Ch'㰿m>~]$M>[<9p>pP5bU=4X>_Ȟ>bK>/ŋ<*B>Q|L>?>%?XFp>;? 8>v?IlY*p_Z>jo>Ƙ>%?M]X?"}>=ꗞ?!3]>=|?'Ц h>xK(%=kƾ>$vDǹy?1?>g>}ؿ*,<>>oz?:=g,_E|?})==o#ǂ?$<> ݾk"?<$J=(2>F=SX?U†D=]>f,?efw8pO=j>9Ϛ?:v#`00 ȸ>ګHۙ>23ʿ+|>U"d-P>'>h75yS?6~=}.?<_i>%Q>x3a?nbW2>_n>/X?ub>8>˾+>JKr7=iF>k99?} d>P`x>~wv?.`މvg>+A}s!C>E;[ A=Tv>#??m0>;`^4>?%;>  ?? G\ک>$Ӽ^XWwu>>E>یHϽFA,f>ӮV1 k>+- 嫮ŇhW=vc?%VW]O?xl#0Q4<gIk?M{jILV==ax?Ya~Q;?#XHeݽI7L>wKE?h?"{(>7i>UB?]P;^LQU?#aѧ17.>>PG?:iϿ^?b=??Ç^? >|E !p?CzpǾz>_?Re< xF?%ͣ>#!>0P9?B??fD-nƼc.?.ZD>gQ;Np;?VKlG¾v]='`[?yS|J!>Ay?(VGbr< =⾔?YR~xOY:=<@?IR bG?2v9>=[A:?QlN`[:>" ^?x!{Ò=q]pH?_Gsþ=bᾗ?V~6}_p3"l?w?:'#*?^ ?Uq?׿Oa?2b?Tu>?A\L;^1=ad?hh#X>P<-k?pNFnb~Խ6Jྸm?D*PHK<3$F?Pޱ?R]ض NBp?)˛ݾ>% =?,? a?/:lC >=%KI?&zc=q2a$J?ja[qƾ=Ӟ,?yS,ABKd&?\uU{?06ee gݳ9?IO%= YX?8>d?>>{mZ-?m\>E><7g ?=>7mU=gTa?fM]??Tzן?Ah9@?I? Rv==B?0TrH.`E99%>_MxSw=`0"6>b_X<=|оҿ*q>QS5Pe&V>fV^=4¾>$?;PQ> B<9CBG?<>V>E4}?HmK?ۤS e ><)cl7 >T1=Oa?i埿c> >~=?H OkL?1Bgu >G$>,|?y>=?CPV`c=(9>1>gժ?Yگ8B=V鼾21@+?mp+?Z)ʥ=*,>?;?9j3Q=0=rz>n?\A?WL ?Y3<>I??26?yпa>s?s??8<:w>!?=c?Td?Hl>r!>1=$?^eBo)="/vZ?>Ӏj>eA><~?T2հj?<G֙>L"hh>><>'&?}Ild>Du>8>0n?=.y\>g(>wN=?t9`=e^=h 5??_|=?}?:c?U7=Ӹ忔(ÿjcJ==KX~}F8R/l_i?aV??~HceŴ?p>ǏЅ!ֽQKȇ?e?Stk:J ־dh?$:Аu<5s pe-5eY9ֿR8 =#!rmNg7j%=q 7YOݲfo(=p->D>Y {mmќྦྷ{#>e#ޭ! п/sm@kLBh‰|5b龹>`=9^\d'>3?K?>Mam5>Yh?W??`>g/0ٽ >bE?5l>W,DRh{5C>COPCneG>>@;=; >>%?Ww#E*[=ÆM>EX![FATK??? r\ܠL>?3@H?G>VX:6~<6N>I>a?Os*OF*4 mA8nБ}bW}AAJ)aA3a??¤?8wŊ>zH?y?W>#C>t?_@AĹ>Z@%h)IF>@$j-> F5QF>91g;`_י>o?@ xW>D 9>qKZ?@> ھ#>Hu!#QMM盾ѿ=S%C(q#6 .U=Q}ƽא$ . D ˘c=Uƽ*;GUhpc/nH8=t[)t ݾƔϮ=œ.0$)2k6Q=Rr1߿LՍ>O>`j׿xuӮ kCvO %좽3Q ɗ=f?k?)>%'ެ\ؾiBվ>V|WIcb?>ֿ1K þȎc=ȓ2Y6^$KҾd&Ͽ/yb'Гپ >U]>7!j=7L9޿C?"o?L>.H.*?n;i>'>b8#Q?1z>FP/$/vr|"= ?w?>J8L>I?r?g<>fR= ?6?f񽵸i"G?G(6&k3z]?!8|xVl>[??0?*(;k?I?5RmLUo!:y?lrdizvk]FY~xL]1lf>q2\?B>kz?&꾶2G>E>o?8Kܿz 9>WTWӑ>.C&=ټ? ?ϯܚ]È?[ ?>zSS>4=ꕅ? +þ֠K^qx9ο?WjqX\&'K]:"yW݋a>܈{`=痉] p 8>Xž}E>@">KwSr>nx ׿ = o:$;>Kdr~X/#:=$O>=9/97娾rI.>mEn&>1/%4Hq qv?FV?Ă=G4L=?s?=`c>7?7?䓯>Q܌?]&?٪]6&?{nt-a<>=?|6U\h?>v3մb=b>?/lx/oX +(=E=?Zh=ſJiIBm7^ D5=)4[}//UJٶ=ԏڿCxn;+?`=PMf>p`-8=44q>:=j&,U:~=O BNbKVoF=J>-v뒿pTD1ĽAL=jK_f8* >ᝈ?Q{ξ.!???U%̿!>]yѿTݿR5a` x>.]1ו=?`X=, X9>op'>ehIE_=e.=lN5ǿN(㼍T=2?Q7IQv!>so='%>>OQn$Ib1/>O?í'!#!%>3#}+%j?9?.e' {|?h?ʾ$2d( ۼL%; >he=xzѾZѾL#>M>Ӿv=?ƾ龅#p>%),">7Xf0QY{>?O=6&ǽ09?0U?P۾[SgBD4=??7.]@=.=,,?u?A2@h¾e?0-?b,Ue t2=$e"Ųmک/b*;7>@ +R=ln==V+*(> NC>9~ܾ =8?]h>VHǾ˴>/ `rݼ/>d9,ZSv!J >})Z>Q8?#սF.M9 k>ѫ?NA=Z rG>?\u>Ej0G;)??#MZi靈>bo?pu}imcb{?0sGQ YͿ$>Ϗ&?Q=N{=()C7п ;x6E/~Ej8-=??@\)b=]#*9%>2\%ƿxp, ZVyIj^H@ )o Հǽz=˿ t%8 G*Ƽ>L2#L4@2ܐ<1#?{?۾44gD??_AlO(羋5ҿ -TnT@1i=%=wB?2gw q g/QN6[?Z'?r?$5YBaJGbCWq)']W lȿKRx=J=[> K>!>佾2'A E=0G^*;?X!?Z2$,l*8??yYk1U0j=ec?1@?WD )tlVx>; ?=̿7i_c CȾ<;\%X>O-S>5j>1? OBDkhi[? ?CW\;WBtXA\<=|U!g:KNkjs.eϾN msCcaƿ a*AgBz>o>?5:?=23u6>p>9k>01/Egiƺ({~ I0e@?c3?KJE0y?hpg6 =Lo: KIV;, L< Y-w?@Ŀ!%W&.˼۫"lY>zF tJsB]=.#=Z>ݿyGMf)M},>Qw!}iLƂ>H?k&u $̈́h0rvҞ+!ԫ"%Q;I>C$/<>ç= "< Y?ck?FG"eE6(@`5?o?]ƿ$̼=;ֿ3d<*N?sI?}>-ehc{@?d?B Ȅ%Mbʊ)ٺ 5 .i;i7 ?{R_>Q>s=⹿Nf?GB>=>Sjyv;0af}c>G!>"M>%ϫL@K4??=ծO3?c?AoUSi18Ah?at?õ\S*?klY?h8PV^8:X84"*^8 vdx L8Qg?^o]p&>}5=[h=>ο w>Ko=#=쓧>39>եU>SL>h?M ok{{l??[r k =F?I? .QTm@@w?"(.r >jc?G?H MU?+E?]n߾jf mt*Cl?!?}CnP8@_N@ԙ?"!کa,/:޾*RXLs)W <_|ZG>u0p$u'ӾZBMfh쾩hQNrl ᴻFg T#" oǤ`!!>6P?&ne?IǾ=}'=n? ?[܌%NX7M?=?nĤ}&.ZW C9~y>ai`)g?Ҿ6ŽY(TG_?C?nྗ5>{?n?>=!u =y??!<,#,J?Ix-?KRb=D5>n ߛܾ5><'>.E ľ2+=fI ?*? j9?>,W^2y1B>]B>b @` u? ?B!bCU?.y?*ch ΢`uQfbC9پt uWUe ^;6&j>ko]Fɿ2  =R>jI9xW=ÿ̯?D?$\_NÌ>6hڡ+,,I) xԒ_Kb::K^9'nT.KbZSPloC)$9. 'rx!kFP7pz;ſ sT㙳evtO<˾ީ}>x2=+ξ憾 D0:*p}BX`Z׻򥤿tCH{S Sݴ̾|:;CN s=H?FB9>C!F=I?W>=)e=S+?M((> %<[? >ڌHF:N,=?B>"ٿ=Ye>*#dA徘 ľ9J}yѽK{ȿ'>::>Z8W6)ؾ;Nw[=@*䰿IE4Y!)>4X>`>0)5TSMrX>C>$2ԿSb_?.R>}8\?>><~m_e0 *Xſ i3= Jb/3=9D$|Oʸ6%ULba=վ^@w=!/U >hw{>׿˼}^l>'IGᗿ6eR5>? >2bNn5[1>?u>Vuё41@>">MUXdM꫾Ӊ>R>E6z[?w6>>~Hb}cP;O0lі>*,=6ʿHA>L>ϫu<7=Ob>M>bNDhkmi׽.2$e>$A SP=io0ϾrQۘcDO0>L_>WeR_6?LH>W4o=#-DMƿ;.!Ob3Rx-ҏ:d;A/x _HxT>.ϖ9h-EAr3>1K:n_X&!>>"C7w]s>T3>Yݾ!Կnh&WJ^=/>xF_Q?,sh4>=:y>CwD=^ 0?Wؾ?==!2e*=N?{ c ,,0 >xF8 :@t>L>>#0%0>n"<>=`fd%N F=%?X"? -V?4I>++? ;>vS> dHv=9.aſrY >?/X>O'em=0>{B=>`$-~>_(>m@hColHmz ,]+#dK! '@!, S̿-?j>l۾H7&B<>5rv;$J:~ g<”o:-@8e=:}d0o]0(Z;=A<4Pf@;Fqi>; aJ.RzwH=}s>&t ^E~g@U2Id ò9>H$s=/N?nnS$X{]οpӿ>1+~Xpڿʿ{ 5Jj5@e&=8࿃p|>^_>iYHV=kR>u'#ZqzN}$?U=@zE%W?A֌=?< {juo={ Xyg+==iUھ>=W`3ֿ'b\nLAqK y[Q,LɰNW> 9Nn4s!or^u= rV\9z\=18R!oW> Qb>uCLw vu!q ʽ?1* hv&3Y.9uln"R c> G7gLFƏ>Z+W)>{=u}[<nI~-0>=d>NH:HF`ب*=ӱ>#)-?hYBS>*V`NQ"S?$G>_#-FUP>g˿PV?zC># >6F A%?yd:>k/gƿ<}P q?kE7<迚h= %i4Xq3¿'F? dR(Hȴ AB>^|?>iIh?X>CW>cО^>{?*}am>;(f¿&3ϫ:пJF2+g׼r;LW\ )о?pGf{>θe1T?w}=> )Q5,=802cĿ|?9?$FOkn6>q~O/?շb |==y TοhnT=G?[̎>:>$_?N>U<>s{9C/bV>-?eS>SK>5?O¿i>s =!/iPg=s\㮛>1N?νؽR3=+e>n>!١>N}>R`>H l4n?LD,>t >q c,N? Vw>A>ӿ?8T??lp?/*?U>iXSRȿd?$AyO> 7˿.?W/>>>+MIG;C?z>^?M>Z?>f0?N#>h?t >5?> >@?h>/=" =!Hu>Ow>%>j7]o[>| >hE? 4>SO4Z?ߏ>L"h>>ֿ9?ָ|>fF(;T= m?BN>wFE<<.Ĥy~{_S>=dNZ-.:&='=\vJcӿ~,m=!|e?b!>4?W?!Ծ?=_R>oy> >+.}?c=3H>?%?{JI4+=Ӿ)ῂ>ws?o>Nm> RX u>>c!i¾ uż#)Bj'9??>:ſY0v>pL>)|R]^=l@>5Y>#{ͿsGnAd4>H>߃{-:r>p>PJɻϿ>H2>V>Tھ0k{^f{H>uU>"ֿT;UY>r>5ڿ[;x gܬ>1>,Hk5&ڃoY? 7~>`d}>q><7X\&=C=6 Rƿp;VX/>*>'ؿGI2h d>?E=gӿ! [/lj/V>yW?9?-ܽ&cA8">5J>\?F\W>ҽHy;'շ=>7yrCwh>t>si0A[>h?B?eK L撽﷾/¿Ǔ(OGvkƿQE&=r> lM^mՄ>'E|HBbw`Am!ֿlQ,vپW 0i_`6>4)=S@=8L>:ɿ>n>Я>1r9`SOC8-8!W>ύ<\_&%>]?6Ծ;~r%[:>Ϳ'W**j>̮C?rD ŨcB_>!?W٩[BL=ң>V`T =Hi=[տ(Z2>2b?# uB=;??(A%z>$=] 93.=8z=YkvXè?*vض>Pa?*洿MHj>'s?#ǿVuy=>řG2 羝>4?J^9?])? ܿLy&l?RQ/>v|]>R?5is6v=Ó?+#%@J;[F?9Uɿx* 8c=\M?+w#U9l Q? s-ͱ=C?-ِB~`>;?Q#Tlo =&?%TWզ>4?h>  % > o?ׄ>nMnr@.>>=4~T6bE>AN=Lo5>B>5YrG`ț >l>m{?@$-45X>>l>"LsQ>>?#uqX=kn >п11Dí~̽w>+N>jJ> >tK j=Pfa|=7>oC㰿r h2eλ:M>?}j JbA?J7?@P%?{Re> z͘|?FWVYheQD?%վݿVENZ>y#6= > z.>kӕ=>.h>CtK=O=~39;A[V>>Lf? >?s?=J5x>>B>?y6x%+>^v?  +=_P>xȿ>Em>9>s?J,Vw>;">ey?b:>?YǾܐ6=8=`(?9NfYXS*=ƭO>}fՍg>&>|+?m$JA<䥜>G^?`ྪ6[=qri>B#?b҉] 1a8>1?, oz"6=\y>O?g%N_9<<ɸ?7X>?U=ԸZ?"Se?=*E_8?~e==Q>Rw=u:QBOKd>?!>?Lʴ|n>N2>i?~:sd= >`Uu?o$>a7>ю?ڽ:$}mޠR?+x ;5*Ӟn$y> ?bvqA{e>`6vT>\l>y)Cgt{7>;?Q?>[ ]>+>LB?A?G>DAu` {|3g<>< 6ra¾ _>߾hp?xSg>/{cd1Z{*>T?5 ?5>^r ;l>5`57U Ѿ"@1R2Y=1>,nnhak)|0> b>达67 ]>-?_F?Q>S> ??h=琸 gf>;Z>? Ⱦ"q>WB?[.?+s>#&ӱ >^?]}?R=w4>Cy1W߿v=>?Քla?+?g>F(F=R<֛>0I#?^$/CW?'?ƒ%>/Ž`>"?iQ ->-|?h$?Ծ{>ۂp<^;b|Z|c( Ċt=^>1t8Yy]|0>h(>H(=$i>A>Cɬʂ>gS&>] >߱X2IY{1>j?t.V~?ξHKʩ6?㰾P>5`߄isрM|d=2U sɎx=\=86`m=f%}O=&='W6>5? k/iD?ȗ?B=˪!ZI?2/?>Y2Q7֦>`2 LϽɛ=[ľ (?=}>2?ri=0Mk#h >VXp߿<<`=4ʾnK S 0Ex=ĩξم2U"͝a>u>!fA,W>R&=jW<2J?"èi =h=pH;Q齩m?:jʾA?$gE?!37|?؀b;`(;>$e G-1 =~^UP? ֦|&hib(?a?+>bX  > IW;5>>1'>!eX!¼P*? 3S&?nG_me^>r&?>D$wkjHU KW.FP(ߓ=2of9"o]d$kgWi˿&|> տ"1#r>>==;+w ׿9ꉿѿ!~x=[BF ؼq#;T;%2>kLBlZtlf$.˔a>@>բ;> >r2 >i%;X<俊x}&8Eнܝճy Z0-s>^ؽz=܎Bn_>DXͽ(=|qTڽK_о[`^Dc5>=K5>:/֠=M>W$ =d >CND=FRQID= ~;}a~,оodpʾ0=0.m߽+g={^PA̾ )_"z=)wˁz"m?anЫn嗽>, C>]>%8տj='DN?gT.j?\/k?f O?i1l=!h@_qh?>RHQP> }>=a>?#q\T>1*R?>c>) !p?o^ؑ ԏ%->>?H> Q0A{>3o?=ћN8_H>ض>\>V2?[_\>"<߾V[<Qr=%hqݾS԰,ʑڽM/?[ww6>>Ld4=޾>EB?p>>9>\8Υ]bz=߾ }>&?{q>>=֦>ォ!>ۇ> 2> OľYB? >m>O֡=">~t>j>=\(N?_?3Y?Mٖ{= L>>#>TV>?7? ?&C==^=>t;q<>.BdF>)>>FR>}o=i^Dt(3H\>g5>/>B>4,0>-?2d,>{?GA)+<*=C>}=>u!סY^ؼJ>=>>Z@I >gz=O>=4Î&Ľ>q[=v>BE0Bp>͸=>:9C,]b>ټ˽U>RQ=k>2g)kU< CJPdY@CIE>>$t>k=qSzC|vO#>y< }>sL%@>i@>.{! ,T&)TB W ҽ]lӿz̾1.A= N=Y%A ?]>.>%>^B=>l<N?>?'"Dc G>[7>/5pps]=k2[1>SV4t d+lFvJ2\=M?#>Džs?p&=|==|n#K>P>V<ݘ>eݹ>VP>[W=p^>>(A>Ò\͍H軡>9>`Q>iIJ=$p>>k>sVJ=>a>!m>h]U>) ?(:?C=?B\ 5>{? b>?!Z)h~= aؾ6>>% R`es13=}CƄ^ۿcm?V1? m?` =H/ ܥ>yAxn>GN>> Z>{ph z`?/U>q*?gY8n辈L?W3?&l?a[Xpcj=? |?R7?+=!=>t=׌? ?-\7>Zd>GS?@C>Y)@)>'>sL^8X*ǽ+N&8r>8і= >f< dET=+=sK>1TI>>/>r?D|_įF\->RxU>.!7>뾑/ w%B>1>>i4?YB!>>v)=b >;`[i@:3>e,>~dr= #>v < ?>`_qe?N>A?V>S>{D?Hp*)=(=:>&~B=s>Eսg>ypdPt.=kξ >'jt4l=Kfy>c7 &>݇>Tҳ?BKEZ~?#<>sG?yaԉ,fU=Uu?6~Z>V;M=C ~?=]Ͼ%q ?eJ?gщ?y|ҨPN\d>ϳ>9?8k⾓[O>> U2?6Ls=;b>a=c2>?/0>AՀ}=EP#;9? -I? }?"|Jf3=f>>>汁U> ?o*?W&?D>MTT 9>ikpn6ղ>=>? 5;0F>p;=?34%=<>Q`#R>4x<ǡ>.¾Hq>}ˁ5иJ>:H? D\3m=Z)>}>&k= 򌽕V>/v?ʰ˒?s*,' >zp;>-wX,RcY6>\W%L/=bt>?C>Ns?%tDc?:!l>q =d1;>‘L=~/>֍>a}? $t<>E?'N>.?L)(?6;jqe>s >=X>>!SVTuG=<9G$l>]%Q?TX]?g?5vh^>n~g ==AV*͘>¾| >Erg=Xڼzm">}E ̀t=Rh?ckuDj=R^ݽ;dE>q' Pq>~ $Kr?\A?|}?mp<> 2`>p̊45<>C=2n>֦I>5z5> >Y`?KÜ>5j{>SC>*S3? =76< =^=^5*Y:>;vr(>龥9oL>Ѿ>sQ=Ggp>~HQH>f9 >u>2\?Z>*5?I4XYF==L^7tlL0>c4>n=#>H2>x>o>z6?"ߵH?fMy?U:ϨM4B>] >h^>>l?CCxSH>g>F0=?u&=>B>=vApSz?Y?G?7>L!> #,@>7D~>@>/+御?\^tps>KL>6=oE?qD=pS>J=ܾH?2F9Tv>L}=w>(PTŪ]>@?>b?Q>[m>c=>+,><=om?rC=侻;? `n>>IoJ?XN >0g=߁?"}1?h>AV`"|~hB>ʿ91ɴ >> "`<[n ˃e=Ƃ?I4>.A?R.8>:G>:T>)Vd u+=>=>t?+I{@>n]$wGWY%MF?XͤJ̓=4=#޾ S>Gܘ>#MW?>JKQ >XGV:q>rOF=c$G^X%<+N?=6 |`;3r>T>&e?A_ʙ9>i/+>+>1?,7t=$=^?;d0i>?>?u>P$p?Ui+=+pQ=>:ZIk>yپ >'cW`? տ^9?;Kl0иu|n >s4u?>>_>zKU?|@lk@r>L>T>Q ?L=p>mz¿">n%ȿC\}?Oz?oǚò>&r>dHϾ'?Ge?6>l`̽ys?^=%>NaJ&>4iJ=?8(ʼnͿJ=ǽư>}|<I?vh=>"u?v+93W>9P>7?l;E@)@>=>&=s?n)E7m=C=FO!?KMj <1_9k>ALrx-/>cIn3> y?>^?3;Ӏ)T=>H=#??Sf>D|Ծ@,?ۍԡϽɾ|si|5>+Y IZ>"^҉?YXL58=s>>*?D?vM>V ł?%Xs% c49<= ~W ? ѿ]y?j$\6۾)/0>A>Ncg=.fZ<=،? ,E>;CRʿG=tt?ĿT9z?~?wy}?_Կ ?a<-ᾸH|= k^?D$A >9p/?}]B V>6?mѬFf> \+?l1% Z>TV"Jx> xս{>8F-4^=տЁ?gԉ+>'N?4a%8 >?hF!떾׳1?8wV9XԎG?2}8f%XGP?3A> \?3LC9@+ p?d ??哿$_?vs?n$\֪^<G?T_$_;뾴$>"y>}?95">K+=D?_s#6>v;?hZ<?{\`&>j`NȽ?,("̴= I?osH218=^yx? Iv=j?Q>M>)O%?z@Q]? (ڿ%>=?SP'?>R[?|*1>X}?M, \>u?ˎ,Pis-U??U,s{l?v>>v?ݠo>T>D^j?}7o?9Mm?a/ꎾO+?:BN?G :*<3:?l; gA>CS?pGPal$F"X?0?c`p?}.?s?vu`?1 ???8(=}ePp>6">'< ?H,G*@1=9'Ծ/j>ؙ*uh!`x>3>>asG?alVw>>~?j ~|>q>#?pCx B>C>t2lθ=?>>M=>N8>XR/?H>4>Y">aо ?R(i=w>&/>%O?J=v|(>Ѻ?̐WѮ+}>J<> ?m?ӾȬ>>Wh?} x?>F9P>\^-6?ݾp>>M4Y?B_??f ?gBT 1>Xp=ܭ?a.yʻ7t*gv>^ru:>ݠ>%v?wo/p! >>.?(!|c>WGR>$p@?]GLAs='9?1? K@n]h=*??:?ԾRv^^>Rj>{?\?t3Q'=TD=>">?V z$=2?3T??=6c,>Z>Җ?3?W4}U>?0+?:*?z>rQ>>??i\eT>>>Oh8?>sm>L>q?)?R?؝Te>x>&>h{? y>jrG>X?z-?H8?IM>՜p>W?z?s?\?b:g`>[i? ?0?XNܪf]o>>(k>UqL?kDNS>1!=o^3'?Q5|,Y4:>h>v>1f?7UW8=> ˼Ͼ:?2;3=$?!,?A>?d׽@H i/?OC?y?}Ww' 0??Zpm?p3qh;Koᄎ?-.s}Y(Yii*?'|l >0=(~L'?B1z,aۭ>ն>8z>}J?;=w> ?*?QX?f85MϽ ?P6?p)?^5? >PV&lb` W>9?>[5(iؖ>i=? +>%]ΨGh9>=_?10igM=/lU?1>g1 33<">7=?'=GbRڼX -.۾J#%)o+J> >?>7W2 >)$? B=j7D4lo=kN*? 0E;x;bNc9>Yjaܠ*Z6o;C=m 4((Z5ȸJ>JKʐrh>j2|#ٮՈuӾ=ƿ 4H>[?g@Vq? E79(=.v?A>j?L?>Yþ'2>Z8HˆY Uþs9YLPium>? @`?%Y>/?5@2U?)LS>\Y??Cl>N<;<^Vn?@әpqC4ƾ]>t_RI,>g3)oJO>n?Y}@#t?6m7lz,i?=+٩lg>~f>P .@>h??]t>s0&j>?w?rq>)>qZ7~>t>i?ڇ]<A>?`?<>l42'Is:.1? K]3."N#>*e/!v=ۯS1z3  ->5Ѱཛ?P1'?tGƘnsU#e?mʿsXu᳽Z~?#duR>Y>Y)>غ?f pkB">K>U?>Vy28Q'Ó=(&=?%?$IMcN/:=^]H> ; Q>Hؼ(9>ؿ?MM˽`)k>W.F͕|>]">]?Z V#EiI=Lnl=<Vw6kl𷾝?:yQ@> G>38 ժ=\>Fҷ=f]vhP$»f>-? Ҿ}˛n.33p{G*=/^? $z~8"ދ>>V?;S"$+~qK1<>T"c+n7ĉ?1>+W]_>! ,JZAx;Ӫ0QK=kdbnͿ> 1zCzZyh?^v>>f$W?0EZ<9>/?HK%Gߙ=g3>&ᾯ D>كؾҪ@= q](ܘI== 0W$F6'>sĿSR? k6Y>^?/v3$ዿ> 5? /y .=7?^)?}<>a-"$G;"?d\?NJ,kF& >(?(O42NnT =;Pn?L#>4ڌ=憾 $ =63W$:W&?r h?XѾ#נ r2=o<%~>1Z@7>8&>T"!z= )?p?+5^=/{?Y?Ѿ\MРsJdEn O4 (=6D>c9>>Bn0I2=¿3 8P A=!^ yOL:1uB>mQ+E< *(x>f˿Rqd &7K>a`↿ya $7|;PVſ2U!)XqIoD,s缿XX0t.=;?{5ۿ2$5[>{->h?'] a>ڽYվxS>r? ]>ѿ?؝Rp _>{.';Z">ۿ,&gV- ٌ =D> I #~==>-2Mp) =>>,:>{p~1A (;3?,8??)Uoo+6)>U3+>>)V? 꼿IwA>OyX?4H8"v?'>S>]U ,^l> w>ξ8P8L:Y?mO?~'d6P!޽4$M?#Q+"YC7}Ͼ5F3tr! EMor={t'<_s ɳ<:X>Wѿ~<ྲྀF(~౽n]1 i>ve>ч辋ջ6Ȗ<??l4?sꣾSXվcķԾm۽2? (s޽jf*ʾU1)>yh֙NX=N=.2>Kt\ M=qq=O>U?w-(O>UN> @5@s&? 1>s򾙈Ӿ* _^?5>+;u4\f7?{[zt~P{=+ =yBP6>7B #k?=P-6*me=l?CM?9h/D:dpo3$!UT6O=4a=/>HA?=K>IOBx'п*9Um>?dXyă_޾R߽<;;1Orܽ6E=jS߾m>w7Uh;¹>?N#|; B-ݯrH>߼{Bϐu?R̠ܲپY?ޔѽ1O? N@:.>?"}==+6zT+D$i<;?Q5?2@'T'^Qnm?r*?W:X,g*!?B?8G4/yzK=K?e"E>Ad;C k>U>O?4Nfپ>.ί=y>7z<>A#ݿ侁!h2M};?7+E?%_.?oCl> >J>b%/l>k>}F$.ƙB)6huϢ??lW0f ?Z8?+( n"f ?D?P4}s# ۾_W68~><_=qC= VG(>wv_=}=P>~K{٩nƽc̽??zA-xWm'anK?Ǩ?H7(no٬޾%Kq >U޾ S=+T-<?`?f0yJ_'E1?t7?n*UҀ:SNl辫rI/o<ൿ(U &t>:AB03- C<??KOdC=`?y/?<ĜbAϻ%D> ?B?>D&xˊ=5r?L?r=XoZL?3q?INm@yF=?[?U J?+ _=U?Y?}a_dV '>h%?G?s?S V>}? ?p>]$pe6?/?Owvra$Vz>\?4.wXξ>l?7ѿ:m.Z>&?u?вt?=0 ?Q?5 >>m> '(?Ø?G=KH(H?O>kZ8.M?>h5t`;V?IJ?.W$y` <ܯ-=6pJkT\j]ĽC (羹˾X#4!0Yx]!)rI|<񿾰KLkو>%yA Hq]Zl&>K)r7-=޾~$pz9?զ?[ _?N32BԀoH=Wu( Fک.7az>)gAջnlc7?>If@` >pg-<t!C dt$_fr>p*-S=;?jq>; R0۾1kQ b>w ԑ=C2n|O>=>@Wnw{,>`6>Hjmiu>%{>ʊqs,8^5>o)2?&>@>:qVXVm*>MJ>Eo{H$#>y? >_83Rܑ.>w=ETR0r5? qP>85;#3hP"S5(z͟0t> >@J| #>}>;<\,vlOnvx>n;8oaPrizI>J>۾9)$tm@@G >c;|=ZҪ Gʤ3>$hORzthzzS=XϿ,tJjmGZ>[TAlcӼO1+I>on?>νC>=g ]==)^]n "8CľHIma(q>!S5?!Z#1t.#>[ Tֿ*"ϘýV=?(>+棿AIU޾r޼NY|RD~t*)heu=R*=>A}U *?>Xr*> _A=R߾\i=p翜Y,#)P>Z*Կv῝7;#{ iJ=Dc忓zp ?3a0 p>2YOC"~Xr]d'`e>C 3rֿdDRDY>I~LिI;⿃ ] qB9jYDK"ϖ s曾`oj ;hfnt>)#XL W6S>M&W=, h?@>ĵ=!4? ۿn?dl`2wտ7\>>P[+ 辦{xVD>Y}VC>Mm>Q->R>󙳿8b> SڿZhUm>ѫdڐUS (\?G,)pDkFEO p缿@"JX=ؿIt۽U>t־CPm"Vrڿ7Q?#Ŝ<A\iӿ0#0>ˁ|B)=.A.e?޿Wd?1vH>*[6b-S?=O<>u$տ7wtDݭUkhiO-P$Mj=r>N#%>Ж R7'N*=="> C?4;=/>{̾+%>]>E1>UR6q*w8}>FbfؿWЯ#a?'M>^얿l+o?FHMT >L׾9#݊"Abk>73Y۾\ J  >h>~ijݾƇ+?H"H>[PE!>] II7a?\ǰ>? žVDR?sL+>_?.]Jm"LEI2H>> I# 1rڟ{==>'=>H}>Jbnp`5?;>$L{>A(pTY,I?m7œ> >ܸZ[>ؿ]>@P>14=$Q>x>ܧdcоZV?|B>фO?WL?"7[?>_?*#>?/>>;>$8* ⿴ء=w>%NnX2} z-CM'dA>q;⿮.<>F>P?R8A%s>>˿IKվ> q>) (`̾ud0>"S>Jb%h?z}׈>xMw?4?`2*a?ܿ%>`??0:q?ݽ>/Kb>'Sa>`=?>P=W>?C,_@%?ov ?MMٵcAƶ ?0߭?1'j@Qw??bKbkb@,=u;VſK.{gB<>f1>) (=6ܐ>X>^zWѿ?p?KnGa 9?r>ҍ:msqMh\=ɺ޿b?m&r2? ?<;;4G=j`~,'jI0Իþ_*↿KZF&"o=jr>[r?? ¿`xa=ݘ>m&?m"6/2#iGV>%LzM@Q=%bxI>>QW\I90)(|k>7i>?LtCX- >I[?H=?<-D5l>Z37?w=?1>pw9‹=M^>pe?';c otKPG:,g)  ݃>U>D,`o 6V:\.+1 i_0{>2> ZA_ZܽFia9T=H=6Vi% v>x>Mb>q:c>_矽ȿ/I.m "N<ɸ6ʞ3aa>[ϒ> 4caF6T>2?RK˾['Ⱦcs>?Y+Mƿ&>>ӄ-me .vI>q?+$RIR>sN>%pm Y+o!>T>?zX 13 >q"?!_1H#g>fw> >':ᅬ{yk>-?Ig#}>">=f?6 Q C?2ʾ 5e=>=>y? X(Kol@4L>ϐ?#<289">f77>ӿjrL͐@>>\d4Ξ}Pv@~=%l?7|5s#D??,R/TTf`x^c>[7?D^?y>>>ɍξ?$A~O=x?e"".F=?G悾F|8 F́N= >(5ҿ kL>l4;?<)ϫ ..>rk>VhIjŁ>Y%? Ԣ=>?Q㾺ZYޭ\m>y?\x!7OKl i>8!>.'R6>0{>w?bFZvu޿,>>ZI=?X㾓p >Qjm&?'[i3=U2=V֙5aY>0Pz3r>@@N>^j>m9'pn=@p=)⽾9u>Oqղ[U=>) +o> ,Ƃ+2<,$>_662l=u{?DC"l >S? =UOU>"ͼ`?G)C>=a?+ZbhvU>=S?Cҷ(X>E>x=kr k=? zrPڀ?/f>S >R^ݽ?^ȿP Q#>>ӹ?>\.h>`>׾~'p=Z?5MbE~T~{A>RD>jg=Lޠ>Cq8J3x>6?Ύ?= VE^B=>]>h_/0Rx%>>$SՑT5"=.>H>>s>Q>h#?ǽey $?Pr>n۾}c-zh>zΫ?/?<*[Cn>c?WF?{->zkʡnx>{[_ž2Q=T3>NU"U>Ӡ?]K? _>M\@>D?^}$?>ïl?d~^4~7u0->5>ɀ6iX8߽ *E?\?M>: XX` WHS;@>>T7iI q=>F:a $B =<{X >x:>e=vu޾w y)<岽C>ξדyGo>3P 4Р?oK?>(lO&v?E?>$\H-v#'ˎC50?{6 Z iKLs>k6z?_=meFL?>CpڿQ&x->;>5^ȿ~@ń=>F޹O׿@a=.Z=ſJ0?-+oX g>EaNVw-)sy~iI;* ?;?>rjapԑ-Vk0'A<4 =X{0A:lNÿEǿXq/_)=mu=I@ _;<">?.pc޹W>Ё?Ƃ>2F?l>Png>a^+?Uu\>o=z>$>A>A־m~NS?!T>}!> rſ"">>j>=Vfl+<"Z7i#=Ŗ?!?PN2?>2>[aG㾣_;# >94ȗ7#3+eB XSUe2Ho?M,}Ӿc>PzlG=#cྖ5= <>A?OW~/[R`p? Of>6>,)>k>W^ 6U=;>s=μ>m-,@ȽV>Fg4R; 0><>-\`H'u>=Ìq(Vr>}>, N0@H Y>-^@1=a1A6J= 6b=[3)뽳J;=,=3DUeeu$ЭXg>P)>v?}5iu>l>=>{?#]߃>U rEV>>@> x>=1<>V֙(=A=}ć>3aNb iU>R=re>m? np>!,Hh?kAc> (>1+=>m^@>>Lh#^H>j<ѽ>PC?-Ib?M9C?z%?bj"0]v>,?,>\?@e1>|>}N>Q?Ra>q>H>p?!!Ё />]>=݋>͚o+-=P>QIc >7xbX:<Z~>B$>? :PG}>? %>:K?"QL9$ܶ)p*`=m_Ծ  ~=߾S3Y#uS>OE=ot>Q2p=Rc[6 ;އ.5n>&>> niƾJB>>P>hB΁0]evG﮿ Q1쯻Z:,]kAtŰqV10>gt=3,' _K#p ⽫?(̾Ȼ|>=E>"!S>lvſw!~U?h>n"?QF[.n"?/4?C?.SB V>Į>_>ֲ#4>l>ebZ>5Ʀ>u=@>J'= >>z/>-Qjս ?P>B? cشȽX?>v ?gST=il@? >?< ">2c=2x>81M1>-u\=m>l"2>G>t?m)aȾk9P=BF䥵[Z =fSc=jľC7뾸>EFsڧm& -`> ń@Ǿ]NM*QB (={&,テ>H=T>tmB(?>?IQfMJ>>m?.eZ19\ {>X4 y2=5H (>BS=x=Zg>3?#>4?=Or5>$?>?!sf@>L >i{><:? K ƽ =F[d]֝=@mU{Ko*>n>N+I?# 0v޸y=D>Ȏz U?>eZ?w,8Ѿ! >rC>>r?7Xq4=,NZ>y?=><)!;r>/̴@2??ܜ?E?WxSH?&? r?!+,ߍ>>nA>Ob=_>֮.>]~7=]YmaN=+ E;󾤞#>=J?#WĢ\e>!疽>n?|>,=#a>ҭ6f ?5*A?^?NU?>vK#=__ >PM^?>y?GJu>Kԍ>f>Ի!E>1>-EK?!=>&Qb>,\u>}q?xd>l܇?* X>Aw>rK>9W?:BY=lF^w>fU0`<,b>w4 ) =C<`c>Y> C>K=*?)Tt=\xrq<}pc T&6~L===ck>N?ɿS?}?ʏn;Z>t>N?@PV>1!? %>?2H܌IN>Z>A:= ?)T>/?"2+>?s8,GG>;G?M?f?9EGC==[Ѿ>BMO=4=>;w>ϯU?|F?#ӿ?:Tϴ`t>>[?̰? k>>m?H} g~` = [>|mSfx=$k?Jju?%U>k>)e?:O}R?-!?߃>?q$">=ϛ$>Ek^ka,=^>^K@p>>-u?-xj?? >?S2Yk?(n>.87?? r3;xZ >M\Z?>{{>wvv>>ԏ=%?}sɿz?޿T\?zy>0? i/>? }T|>>a=ӈ"?j o/> n>R0b?RN[>h?%>?;8>YڿR}vHdt+> !>9P?o]xg >7>T@]?]UkQ9=*MYz*AC@ =U,{_ok>Ӂؾ໐s>i/>$- R>7 =b>Qܾ ?J{ty>F>;j?S#_Pi>?/8>?mmPu>P">BS<?yֿ0=Qk:bW<`= 4@)a+彲fЄe?Z>Հ?^Z .^B>5?Eܿ`?SbA?2(Fwʧ;>v`=2Z%9RqjcfA'=l`ĿH]=K,E??1޾Zt6>Dɓ>&>P->ʷ([>Wc?xg~;7.->ǯqݢYzS3?p2?ݺJ;?ɟ{Ƣ>d$>݋<};*?TX< 9BR>JS`bߛ,l0ȊF>DN{|!Y>B(/>% >1'˂@t>:э?B:Pݽ-8> >1?DJ2>9Kjտ/f>:mֺ>* ( >6@-=l >q?w(w-̊ϒ?%<`P+ؼO/׾?6¿D .T<聿FFkj@>` >"u?:'b'.j6;><(ǿ'zS>-Ӿ9?e@Q?E8=6v"H+>Uv8:;>f轧? N(5Y<'F_X>@J ) =<hW]>Mb$u>?g5G= <{\?L<\|{JxD?PKQ?0ݿC>.#7>p8d'.>IS]9P>GX3ST~־>hz<پv(F N>%a ͻ'Vb(|=>naC=WʿG?  ~?;Y?RKշ`߿SA}SY;dc Z>NV`N p=۱l#?.UVyJ=0PT?(0NQL=2yW?5v!>h%t?>=jX.!E)$>fwI#?a[B?|x?B>1?ͣo?wd$?2¾><½?G N>I1 6B,>maP?j(>4㓿@mr>Óc㲺Ӿ!᏾J?1N!4蒫>ɴ?Xqpyh=Ѿd^? ? nվ:>)5=b?T@4BҘE?0Rn~m!? %`a($>>I>?;ɂ6r? M/q+y>mL?OοD?P?F?pZ8 Sv> ]ɽ9?|ھ?- >Ӏ?xѦH>;Q7]?~j>$? n>?:g=gQk?fVը!2 ='xZ?WVÏtu.퉽;&$??^SbYƽ2=?D_Rܱ=9̾?p+c׬ھ-Z;MI?X>~>>xq.?@!c߾rʿ?,*WnK-=Fl.?ol0 i X?a+㉃< Y=C|?w@?[?^}ߏR~> 9%N쾒m&?P=`?8r"?1?^?ґ?7 ?!??l?M>7%` ?J?]>_>#2j_?~  ?|>؊\>3־ݸ?&‹{8?^`?\N?H?tɈ?g?I=s1>5Y?C~˝>N<(?;?=h'aԿv>M2?- U8>5#-?oqΰT&N>B⹼?w~W<_1??E>?i?Kh>=K?YC4Bɯ>o]?+ g8=I=c)/?bHD>JߵH^?Dj<&>?\a?ďA&Bu=2D>s?S _?S?߀x?iѷ?")?8k*Q>B?P$el=G>2?j}9p{>=h? u__&=j ?b5o~‡=e R E>۰z)>>r;9?"o]?>{??wWD[B=(? ? 0!OA̽/T>1Rn>?i7P>هƾu ?\UW/>n|ƺϾ?DƓ >>$ڐ1?Ё?JHa>>?/?W)?vX?B]>>SU>?'PL?T4&>c̎d΁={>@@ FLn">Ȓ>B?!`B?Ah?kYJ>{->FN??. hظ(<2O_?B_Ƚg>G=1n?wBXY"ɽ,?i>y)?bk=>Ab=ա?o΅Z8Y>>>y? p_@>E9>At>~?n?Kzo>3N>? *?jf>>c?;F?m?l_|Ef=G?*?X?^ſ_-X?:1?b?pr⿙7 =L8?cu"~?,?f=?]f8Ͼ=%?<[}?tj?eenE> ?5M?GkF=N?BQ??hi( Bu?&A?^?5tOҗѹC?"Y>cIfžCAT>ڝ `>q?X2>2d<%>^?>:i N?''f(>v='$?TwGȞi fI>6 >?fd,?lk>W?5>4̨b"2>?;>9xk =Hp˺ܾ'=g4Ui0 >~?HH>E:R>>! >Lj?#{>aF>u>bi?#Ho9.f:3m|@>,`T'1qv>Haij=IWO.>l =5 Rb8q">C4 h˫^ڿ #>q!!zH0=ſG=T?>l3/w|Qi>R;?~1@q?`{'v>">e,tZ#f>'DN~lGXj= ?)})2Xڿ ,=Xby<鴿 .,V?s->jNiI3*,gnG&п>mhH欈 Iǿ*HMlƽoߝ,GVT2> )B-"Y?JZ9Ҿ^ɉY^dUM=݊v>"?qԬ\>#Ծ֜>_ vxn9z;>>qXh\aN>K@qA< ?K^Ifvmt>>?9?γБhEΞ=í?bn"?&=lr^^0=T"<= ;A}MzT}=j=~̾h,ni|cʙ=CR"|9 Nyc=~$W̿/{`>֥>R{?`jK>Z`=AB>O"qS>J>?+=>=>=զ>7?PD[Z3O>'.Z= MJJ\X>W@ƿ pBI(c=n>z7N4>G=ג>۾8!Q>5>=L>ͪ=`MO=nʾP>WhF=Sf>ba.+=a>a4AE1%s>? d? hF[85i>9h>o1?Q#@!&>k?>?Y2{?cmY> en8=3)f^F>,V>>ѽ c=QbW'| T>y>> hbEջ4j? ?~ʾ/KH>;žE>=avY[خƾFJ>2#|W7I#H>3c[$W>S>I{Y,9Nm>7xl>bDDa7x_% l=uH&>fEl@<nd踿>eǾ;:<֔.t>|l">~4M`.%p>*A"=-cN>O;n|Jn?L= ,>OjoiU]֮г ,= U>h?R!a e\i=񤾿bX&NF ?X}nQ34>Û9MԾ>H=o]>p?7g>a־f^>Q09>x2=DžZ=/Ҧt> pٮ=ԿwW wZǎ\?`x>v>z?<&H?qG~>(>/?,ཀྵO?Q75]>ˬ>lɧ?S)BN>W%>>W%>?`ktcUC\o:>}REpS> ?|>J>hwg =澾B>ilC{=¹Nj?cF`knk>aK=?=i=,T?vf0@nH>>C ?0o֞5owFE>=>ˣ?a鿅?!Ra>U FM0Ip >:/،oϔc=̫?j?W*s lMʤ3Z?{kc=?3ozJ: O"}=^>A?.X|p(HQe* ;> A 1+Կ+>j?F#\>#>sA?:Ҿ>p>+{>=(`>pG%| 1+e=鷿'%Zr#[G<,>۽{,V=U)D z >|L?%2I =<d@>4 =m>Q?D-(=,`F>#? =Gq-8>g=?\վԍLmZ>待?#[!Hgr#>f=y?[KAfsҺ>{>&]?Y2,o|=񢥾s?ZXuc>R h?ƂOQ0q+@=8>?Fr>>C ?+AKpԖ>_>jxl?ք8tw>Z=?ʾť3 x >N= ,?|xPzhb<|>Asɾ4#<:Aç% s6>jYu=Aʍ;B2>z_d,E BS>SsSտPqG>`b˿  xS>zʊ-' &+>(%[#`̨3@9s?H?lu.>=?$W/Ay=s ?07[>"\u>չ߲h?ҿ3j8P$> ^2M-D98 ;(mr>mu\՟EbWv-=!]*t8y;G?Q?d_3 ݣ;_X?J?j-?`X 9cV󾏷鼰@:>AN"5>Q=|>|زfq}>:횽g==t? G{c>>H|?zf?0~?=`~F>>?e7PcK=k/#?5Y?]|N廿lf>= >#%?+H `n=o>%,?䗿q*:ge>V? .yh`ni>=3?dcrθ>i?I#HQ4s?">Ar?澫LIܾ'=1щ>5 el->1rch?o/]yv&=[ƨ?>!1r1>ApPr h?ƿu᾽=(?, RNo >ʡs?c7eSSjkI:7u= S2e㴾iPPtZ0ba(9ο u,>ƋP&F@>9`kV>|g>&Ne>1$µHOl=c,,04+)"',bXO>?G4*4bp>^:~]?T;HWK YN=>z?.8Xx;_bho=+7LF:5ձ<t(?x,^?W,ؾӜI=!?m08?V*t#y]=?]?N˿ j"&i[>mCI4?hU1& = х 6aH0tY>+X@} \}?@dF>SW]WѾoD9n^QAv=-}b?wc'5r+.DR>l9>( ?NuKk>Xm/>˝?U {>F3HAp=`?Gh?CvHv{_jV,>9">[\/@qlLm_>#)>xuF82<~=<ʗ%#hZ?F,?5޽?@?:L@0K0コ8>) >;/cN$0<>(k>$Vy ƻ?Y ?|龑kv} `>n?ʿ'r{K<>b>K?yfgߡ94<*=z?AOYi#:B3>s>x?x@[& MMG>I-8?_3Xy"m>{Qz=w[?Rai5g|joo?y;Iss6>X; .Q>%5uH?n?|Ѧ?riµQ=v?gwK?W&YŐ3r>>?&W\|5~?>UT?` }bB2>6>?t!:84صԿÇd=*s>.ɼ=@ UlIkU^,="%?Ǿ|=})v $};5i,G=o#}ӻP 0y>M?go?ҿW\:2?[>H?㊿]L3=,o>?W7=+EʿT-coS=tX1 d &9{L>?ϭ?U>h:8֝>K>?v4f55>)>Vi?~#K*-p:[>>ߏ?OHzҚ?N_>|b>C? #^xeR+>~x?i.kom?bt~??3UdA> ><,Mwf࿿ D>+,j{9|!>UL&7*SH:_>׿RFKU٠'>Z> GR<پɮ .>W??>CY=T?~?B1Z%^ӎ>oV??'=T as!?@?MxZg^>*V9I0&͎RyD>>G@:*??L0>@@C?xVPOT?@@L ?s&) R>?>Zy?wߠ8L&XL?4 ?~ƿ>ӄ>n?@?Ѯ? @=>a?cV?e?$G&R?92/?UFrNUU??n =jGl?>~?ʿξ3X>'cݾ2`(f[:? ;;(F>ESi?D ?=JL'#?(>if@ wq?"t?)g5(}6&_@?JowK/Y VD~W`=lM$;cNbg'==HVM3>sǾHT3A\(g62=<#'rR0J!!%^sv=\꾯m0e=@5z6?}>G>*[>.X> ?>O >5>w컽fƿY H >J=0{Mps.U>5=z Xfp`=>26 _v=>?֌?l'>ZT6r>gZ??q=?@BS?#}?N ?[U龮1r ֈbt[t>Xǽ$3>v2W >==o?>֤WȰ>MK'>ibl#Bq բ i9a M4߻z&i`9THKeJR4r㽦D=0Ir=jƢn=p)(: ,(M?e Lўc *g,*$ۇl:m SA[?^=|=X>y9?=><ŹtQvu%>+h=VԀW I<>&>n+j>.#3$E]G?\PY>4pBMӾ3$ar>  }TSLBW6?qt>+T0>뛪Q=Ӿv8dg\_j`>J7Ytk-O><<-' 0HY>"1ra)xW[?wL0>%=yN p=?x޿>m\>%c ?إD)h>ež*1T;?Bѿ>^Ɵ# Ѽ~gܺ׽5>pcҕ?v#>m>aI6FuGpI݋KkDP8-.@Fx l5iu꾁9~X(i5ٺkOоAoۿt$:H/1 eFrUξڑo,M[ Th>]_=0GZm&hn$![ZmDb9&0Mt^}$΅],Z>~H3C¿hU=Ծ y cdeS=qϾ$3ƨ^? {F,= >vPaD6,>VuU>GD ¾?ɸV>"ݾl-^l?fZX;%>1׾n9KE&>FھhsI?\Cd`A)<- "jӿ'>V¾輾̯ee=彬^-$Ĝ)!Qb2b𾉯H6e+jjUAݾf:Ǿ_k9gE>rͽ1ӷ޿?I$Ot>. EB6?z꿌->'\>Gkпl o$渾"s=4?˿-^d>!4HDٿ5/=V>>˴?qI>V_RmY1![?{ R>xB1>e~?9GBp>:j.|>DhB >n 9l?G>2>zTſbq޿y?u;>>5M](G>Gؿa>;d 7W!{ɽ>gց>ŧ C>S$ov $C:&?ͧ0?,^?Uu=?? Mԡ>n=#l?4l<>w>K([U>z$>N-= ~X}Ǵ@@{>?42?,d?A>G?<?(hf8L?>ak=#B$=v% z?9t=̊>*s> ~Oh?%ϧ>2Y\t<ҿZi!=)ZlPŨS.5v>fN>6>_!<¿+=Է&ʊ v[1>5~=(&$m^[m>9.킪>W$tmh[b!>ҕ NwY){̟3:X>Ց>.>ibTt>>>1Q=i> L<{F nq%I8[}="=zЭ?}:I>'>}v4"m?>>"P`> T>o"?#$=@s8g4T>Jj>>[뾡٘V>+?=e^>EfG`[=LGl~#>6|l<;|=󔸿qgN5uYҿ- &&W |s9TP>n?.M4~XB~þ >F?nnPP[c>h?\缾w^XR  xnai .X6Қ.ֿf@4=*IbeEvP >1oAHw1K>m=ɾ%KSPdWr4><۾S7`\ jWN7`ݠLv;/bҌ>!Çp]1Ͽs&`پ m{̾uڿB5/dc-4P/! V%+Nfo>y1>N-Ot¦~>)>>j63[?%L?=Ԃ2?JI?)L5 tQ>?%`>%Fa?c 6>>x ?5Gx3̿|>? iɛ\>x?-wr`>= ?5ǃ8ijP>=)?1۾xaD>9⽽_8?? J˿:Oal<yR>>̿{O=C^>F@.Zx="B'>֡[{9ot>%ᾙ>\Or*2>?e{)~@1xuBx>ny;U?# FQvo8, =\a >⓿HS/>d?_`(sm νk>?彗 c i>֠U>rŠ?W>Y}p>v> ?y~ >jzZ>\AoD?/#R"\?M>B?m?yӾ˿F|=?%*W&dk G>̫?i<Ԫ&lvD1>?Iu6rF>>tۜ?)>:@B'>=f-?_[>9W&\>f>-%cj=ǽq? \-Ak>"}D > +@w>,=㗿PilG?bN>cPLE-dm>V??K^9v G>p n,V>#>}FC?C7h>̫?9 ~6ҾD?`a>C3?Um=oGta>> c(?JQ7 ^Ӿ" y?Qܠ #ĠȾ?>נs hM?? =aS ??>j?k c?q>NP,ѮtlIw?ms>ݾ?G ~}>M >\oe.jU=u>4y?XӿUO>Tm@?,D?v>F;=>@?h l@L_5=9P~=˫>-˿%[>9Ib?"}؀܃a=>?㊼!=?VO?ѷ>sd=?Db,?m;> FkgJZz]f9BH1볿C1M$JKG뾛쿔v:MrY >'yL( K= >b=+?!p >?$}>?_ݽg.=H>Pt!?|m0 > u>]E ?c?? 6?>=޿\8V>x?1W? >:B>\d>p7?֮fff9j|:C>?(Ѧ9DZ?L?}>Z;h>GeO¿>Tk!vѿ0q>WAjNӿ6??|? }4F{a?@L?060"߶X> :) =>X:X"s. ˜k<>y) 轊?'BFret=r>?>_^נapK~Կ8J1QSWfM%@8$HPcR> *>Rn ;־\aRi= ?Bԑ?p>gA=ͳ(+\Adx??>IaI=oڿJj#j3jf>”?Ij!b%!|(-ZE(˰>N>hUKIzBF8?'ż-*ZO>mP[F6 >̿f{SKm?*&Ae'G?B}??;`T.2ϼC&[Y欿&$98@> ' ٿǝ$¼bd>/_NkaU$'=Fa["9Mg?%Lp`qھf>D?C>2MPYPK< >Â>RD? ]9=tcI?)4>&\@X=I;+>>&> TvVJN=Ҡf>? {HWu O>(>$N> xվ-hOԀ?2hMp?,S?>R#>hP钾ƽ##վ}5>A,kQ=6DX&ξ])>gOK=0/@$>? > >Pz _$p >K=6>h!!!h>0Q>s(>_$(HXM4>@*x=8*=3\=>;>BX־ ,=r.>#9=>4=O׽񾜖FD?QiE?Z#}9Ӿg>0 F?A >= E=k*̻dR["=naPϳG>J0=>~D$>$p>%3>\"afoI0a~?hb[2>iiM,lWT>0;>3#rhZLz:>k=>X>;~#>D=?cZh3j0=dH<{,wFýh^>>HIœ5>? -=SPcλ́Mt=c֑י>EX>q,=dU) p$ɻfK#=ڬT8;Pd|>ƼMI>/#m7>=+GA>2{v  >,=f>Gr}Ծ*l>Q=Fk>fy@vվ}>>}>h{oC>g>3H>&$$=<%1_l=eeHTV뽘d>p;p>jbmH> 8=ɕ%/>7g? jV.>1>ľ$Loξt a>P!>f4>)J,CL>W 33,ӑno3@,wy2`]"W>=^x[>T{ePa<]0= ,tE~d Tv"<wJ4I>Ǵ>3>ng  -;˧ l2>=U >_#?GY?B?T?W'|Z8S?n>=?>V {:>Ԯ>LE>?l9GY=D >i=h1>`O=dg=;߾2%=-<)齑=X >].l%;,0,c Sxݽ>A Zۅ(lnr>!>&>>a: >x=7>p\t=Тc=;i\Vs=H>88>.KI8N>}dj>O:(ּh¿TnVj羱>">>f'xvL>>p{>Ik+ ;>H(>>|$-u>->]>vOx H>][=>6K ^޿>2>5?ICc p>.ֽ>2{*yP= 6տj 0lݾ¾ i<ėt(Wɬ=,A"!`>/ξ +9>A=¿ɿJ~EvnzVX?!K>S>flO}%?*? Ž?, `< >_>fБ>/:Nڽ; ?z>:?K)^?e ?9q?kwޥ$>U> =?lفZn7?>ܐ`?iT\B?y0?LP?~:0&=b 辪>-rd63?75?f?=;ۼl*H?[u>? Bl=,o>|w#DR? >?@#qyW?)Lf>{?_xڻ>}=Վ?#<>%3 JE U|T \>هb>l>ܟX&> >?G*-=?Nd ?*?g#=9?S?0{W?p%@=>4>D?n+,A|(pUWX=޴ dhtc&Cz>G J>`Jw)8K>,=dE>3XPZqbN>]tI VŽN>zHi@@>R>4?9-4-<^ľ0n0U>+IZ?~D>hx1^qX=#?6>2e(d5m?po>y ܿټRSV+>ȓ>[?Yq}>>B?k'=HRƾv>@gI@;b̸>a|;v6? !Z ؾt>2>~ ?L9нl5N/>\Sm1պ 0X%Q x.">H2v?]C?y??- b\??Y?5\<8N>!%>{A>:>>h>>O>F(AP?0a?H3?O<<}m??@{?2 8# m>l>q? gt?`[5C=}>g=4r>~|ľ>=&F? 9i#?Z>?_hyIo mX\> D2aN?2 >s?x?f:= 1qE< ~(>>qzA??q)pG>=>. >3yl=@%>yk2>>+?rjOv:=Ǿ>ZwT~5>~>~^>?!0>i#6> =>R><2?(>{m>> =K5> `=&>l>l?7K*>>B?(> I? >?5 ăl=t>'>e?) > xO?+!?+?R:~͠@>,?%??R]h>?f^?\2?%zP1S=???H+H =Ũƒ>`gTCX=e>(h>>>?2\,p7p=M>=0, >:8)EZ=z~;?7j?hn?DkRR,>tu?(>,?z͢H#>:?I =z=>=S?$~@iF=5"=HjƬ?v:?ULʬ?-ߖ@> woyaoDAϼ=@3$̕]k¾D@>=NǽB(>74u6\ѽLaˊ=]\D=p .þl>%e0[vp?SDj> vP>>=B֪El>+hǑ<q<8j͟>|$d=>=j2?%+B>,=F`>,8<X>5q&><{q8=OC1.Bc=랾L뼾|=r>ᾩuK>^|>!Qȿm=yloXei,mۘ=KBίvu)= =D'>ܴb>@>=Ύ>w"G=m=>PϰȲ=ݐ>W==r>肌<ϖӾ ='">8Xz=.=6>sOg=a

R# /Ug=c<$>h=>7>6L? ^=>1 >֪ؑ4j[7>D[ϑ">W>>.?KǐϷxd=U)+>;G0WciUH>`ejbϗ"՛=e<: R>Ë&™=A>/3=JSv>ـNr?iW}?dD>gb>>f?`ǺzI>&$>zlyB~ƶ>r ? ”>?\|9a>>F>$d?1dzO=l)?Ie?#?T0}S=ί?21?k?v>7R>K@>5?b>I>]=?6!;>i ^7=wAJ~Zs>l7 b|-U=dLXдu>e>?EKԒt˽ >j>1?԰ ='$>GU7M?M^J4>yWG?.>?<B>_?xl>Y ?{@m>Kܭ>za.z1?rO>w},|B=xW=>>\N|1>PxFN>hi>1,=>#Vs?;!>  {7=R>vUek>I~۽,0u4zʼ>N=; Ro;!? NK>;='8-?Wۿ>CCeE&T ?`9H0<?<?1;?C58?ZW-?f#(?<پJ]>LK~p;ɾZ' _={?@z>[<=`X?7a=>~ ?Z`~ǻ=Yޘ? 5C=ڽꂥ}_?3 :=Ҿn_W>BE= qѿR@='C?Q.|(ݥ>=b?+zĻ?6>r\>,ټ 9sP?>87>ۇ=?@)|?>T>_;_R? bw< (>7?y-BĻM^?4VP]>=HgAv>x[@5e<Ϋ㾟A?"F<0JݔS`п,s>KU">UC܃#>8fzR4=8x1>m;񇵽>/˗x?e=?7> ,2HX?"h@>v>\ VQn>h>7(ּջ{ȾjiK#>y\I'!>H$˴to?$`>Ju˥8=:Gо?龌=\=?9?( >pj=$䆾 ?B=qdt>vy<2a?I1Y>1n4ʿ`?faԽ=|?Z>lRF??O9?9:? N_~hz6*N>nT{> >j˼0?~tX?8Ze;S*XC?c?̫ͪ;gM>/>qC?yhBcG eɖ>0xsN=wB=&?\1HSl=;=8?Q gR+=(N>"}O?qÿ?ҿ*?0?VK?ο|?nм"D>\3?d<% >Iѽ;}?_ԡ3]>=;?{i@e=Ծ5->^G?J>aT?~2]>80Q 4>}P[=ծe q?Up >- >?)ئ$|>7=+d?y؂:>i;? H ۏX?*>?Ț 5-jY>h=?jM@ޙqA >SĽͼ?+ߌ$5f=Lbzo?_VÍ>Y/`?A@?mC?aN_BNY, ?|+N=*^,?|ATO=7fQ+?wr?/z>Ѿ;?g(?p?kI?`?'ǜ?;G??Q?&z@?¸X?4F?4| y>Qʽ P7?-uyq^?6q7,j>X6=?VËn6>=` ?S;H;>H^>Z=.>K?HA5/#`=Q>{x>+?2%ӆ=.> 2= ?L39= x>Ó>dF?IM\A=ȋ>{>??AtN6SS=K?6>?>=Wҙ=Y]տ F2>7]k` ͚?{`=3Ĺ˿s>=2>u`>v=H?>>C\[ s 5?F`Ŀ&>[><ѯ:L?E+=?ГC K>lr\==r~>jהKK=>` >q ?>tlN?J>?yA> a[?&!T=r6% >@F=\Y?!7>YH=mjd$?<@ BB>6=>>#nn)Т>>f?0]2]/=|h3D?o=w=? g࿹ >H*V=p?vjۿia=5->[>Gm W?{@9`GYq??O?@?c(^M@KZ6?H*?{+?gp΄>$bþI??w`2?T?,Մ?i?F@P>|?Vѯ??nBGpH/0>y_>4?q?~M>?/?^?tAF@E1F])>j>a>'?? W>i>B??` zB=?6>/?4m? 7s?>?x?P[WOx>(?.G>Q?ajh>O>_?#?& :|e>?[e?W?@[?|5gU>d?c>F`Lb; .I[ܣ?C6pIY>M?32>1* )1>L?Ib>y?pT=g)":6@> 7b~>?Ai`l? ?`j?,{•d>?#?t?82D^>>o?Iq;?3n >8?>+Z? L1'=>8?3N> P@=#? ?dS?%AE>M?Cz>Ox(j ?x?vt?Qpa'>oa$>d,?,->?S2Z> >.?9z>2~o =>zm?t>d-p>QPU??l?)SOpԕ=r"? ?`9?iOOx>7н>lT>&?I8=Dz>W?Go?q?%B.͍>?eV?fv?R^s>H:T?H?WL?5|Uy̾.>lwD6XV> >ä?]@x'>HH|_f>6:>Di8X>?JH>>x0>V?!R>'U>m>>xi?.]n>[? ?d ?،iSr"w>>=?9׈>A+'?`?2??Cϳi0>Պv?-?M?9X>N>G?/>P6.0=>Ъ""]==*Wɿ3FM=|>7Z>ӪB>ω=S=C$?EEPhPJ=v /TBB =a?!{> E -$0מK8!%>i:_t3 V?{q kĵ ?&BH*[= *ߓ>NqG?T5h> =ӳ?2 :}6Ѹ=*g[Ľ? xX< jnKTXX~L`JD=_]Vcξ[ 0PF'햿3޽h,,!iSL ;;O哼ZB鸾䕞<ոeTOR=O>*xu V(-=>?>0m9T\a#Go?:뾟QeeTnLʹ>M¾lN l.랿'?} 5z5"+>-˛Z> ”%>c܌?]y>aP,O=̼KɛS¹?!xS>M˒G5?u==:i>:[v&M)V7? zC$">X>L>?+佾h)y>=W>Y?XG<&E>.۶>M?~=vq w@c>*>D?E>%rA{ܿO> oBu޿?3:y>j|O>F E +o>$/>y?@y澱'%+F>V>NE>T;Ffz;iC2?"վ^0nհ=lgf=Ӿ8^75q<チ6ƾN?>")EJ۽ >q>{?bGL;29@CF>;Q3ν)<;?EpBz=&=>yKx<(Ltu=5m FO<y=?R,H>[ԍ>[>k u:w>Fh>w>P>=<*>>F>?Y`>G54.=b>?n>KI`Tb-:=W?%N5>IH[?K%S=w23%>o%_:qQQI~<?oPF3>٘p?e$$U=d`g4:538U=LݿO}ؾUY.9@=y_qᅤXTe)C=ީ3O1AK>1n7$'Qiw 쓟=| e PɅ=h]a6[w>Ű /|>y6渿2>24>!u=QTA(>?3|O3 hf=`=J>;=rT=>Z?KEkc={>?Fw26濼T?JZur>~BS7޵A_?%"">\x=qX>53@:۝^).>FNH>F?.}V4=t1>*=w>mދt3W\P? O?nv=UKE/Aƽ.]> =gYӊ=?+Q?оQVx>uI0???W0V "[>.Ym?8?v>ol > I?⽾ bqE=&?Ab4FyN?GxC33aN[=Ň.Xu(!>d$?!JM.b. 73>?c=8 v)x8?}?kW=`Ms>!?.Ͼe],џ=>~?%3|~(&Y#?X?o>dhd>Y' ?r?tK\[(>1?hN?#?!uF? R@j&o;g>~H|>0 ?f"?]j;=^}=y?zS=bb̾_?YyLXX>??g \cT<> l?+yZ{G%?!? b@v>x {,(? >,?akH$k=_YͿ-/Ζf|l:Ž{B>V>#i=WF>D ?-Dnok<<́M?^?Ɇ<='=g䂽iv?0?>ij|p>t>)Ц?=v? v)(_>MFOuB]`dE>Z>|2>n S=}r>~x>a qy8Xt?#?9inOf娉yt?Y?,"ͿUm@g[ˣ?0?/=kad"d^?b>?Ve>plp=>ʰ?b0|06 $`?08^g}< k9 ?{ en">aiƏ~e3 ??/>U!޿(z￵;Dk^ۧ3=&>p72>F?&# }?/J?A y)3?.*5ʡsm<>)<ͿYk*PU.d>ǏG}iTy>M(> ?uOO=J>?Zv[X>T#?V,pٽc7m?:M<^oJ1mn? R ?ANQ\Es|ZSb%3׶[?S ghD~=>?%q43?O?οp^2?b?!VсqjSg?):?rB+RLZ="yɀJ@mn׽߾+WnaDePIi.bֱ`-C=,??Na oQe=ܐ?d Y$oJT9?d?][KQ-~ZIh@R*[ȨV=<3e X% sm#> !Nz;E?eiXv0lDsG?]#=@-nu>u<[h==v>v6?.V'>e=`Jhb\ e>SP>%?+&1;Nbf>wG˃JْS<2 ?9?\?sX>lڿ˾Ǩ>+cps\>V(N콪zBL<%=?¿cJIOY<տ?ѾޕS6X Hw+ؾD=?>O_x#ibe*2f$ݾt[;AOD*7쫿@V;h=>K׿A;қ;gt$e=bZ=ߋ>Y)%>QH>?1\8l3%N>O>T?=# VcN.;> W>A?&oPn1T89,nm<*>ʰfZ_92/ ;>P1?:P:=}'|-<>;->d"2lICy*>>^?FX`O:@f2ѽEݾN? 濤5X'=ўWǴj>N~ ʿ ">wh,>ڋ?h/4V0E>m>|?8Bfdtd:*?=>?~z>?Mu>pƖ#:(;$>Q7=_1>!ɿSi,9?`N@*f@re?-E>v%?!1D>2ʽ(tzw0>yR>M} _+0s]v>L=Q+fjt?0Ͻx >e?F׿O'+u>f>ވ>y2O g==~)*ZR>x?87?o:EF%\`>?{m?<h >!?6? м- 5>Yw?C-?a/^|l>jm%ؿ?VxBR?$>X=kO]_1#wmU?W?-޿@D }Pnξn*ipuXѾֿ rC% Y==>>zt>3ߜ<>8Jv".2U2>?8~[y';HV'?J]?0Zt9>$y>?^0**p8$?gZS?Sm4ǀpҾƿ PFwl|TY6׶i3gMDkߜ> )>DxpP (y&v-f,1dk=4Vgzl)>EDC-ާ#{|n6>b۾vqi=>C=аl[,ɷD=>>bxѿ?ۡl+>׮>>9?EI]=W8#zl7V^>p$z gh>mi[y v='=Óhl(pwYΤhH$>U#-cӾ2!a{4>cgH4Kmʿ#Y>^v.Pa#GW/4>6ﰴL :iO`>Wn'kҾdxSGR>=* kSr6bC>_ԾϽ]t`^= Կ"Q=Ы>g"="+^f},o>I>L>zJ!Vޢu>?C~h{m>]?/׿&(vMʿ^}o߼޵-A+eqqzI=j>}4Yf#\>=qHm_>1`>%žCݘ]P? ?:ivޱ<S6TQKr[>,r4\a 0z.=jZ$~b~Y>a=֭qj=Yz^>q==zҍ=QsQ>wnys1LH(>Y&ȾG,ܿ(T?zF>M=[>nlg>>K==VH2.?Ah?c~,s;+?)>7SvX>]G*Of{`/Z8>\O=`-)kQc;[N{}%ԕ o:0TaiQEdjBEM%ľH`> -=|0>#WJ, :1Ͽ3[K6~N4>yFSEC(LeTd2]>>Uy)>%za%u`X*e (w \R\oT##W]#}z?^fo=<} ws9n9;~>2>}4߾qA߿J>Um>پ^;Xo7=*A'|5C:?uc!Z?F~j>9.Q!qpC=Om 'S}c~>Mƾ\'??]a=vբ qض?&̿HI==B/8=i?dӿ^ =u=@q?o?7+Nܾ`k>D3smr.yY")>|0Ӿ[?wd'^&|>lƿ̿HJxV#ueZqXOU޿_^˾Ü>ӠX7Or>F9ɾS=x\`>߾H"ߵu?: B=>=dW?D|~F=`5>W`nI伐Rft|ѿR]<5Կy (Wr1ǽU%N?Y ݿ63>>ҦJ(=%"IHM=OO4p?vdK>A!)(<?UۺI#>t>Ry*>5>*(ZbQ7=zV޾ǡnmIM t>5[@i:߿7ryt >$D3 A A>;&p =l4vTX%#~>f04 FX>o>9 X\&?]S>CX#F?9\BT= TĿE?TFU|>Q2@ȿ(J,504>H>>2r>JI`>C?UҿM>D>-,˿[?nBi>!ID'_?U<C=e^EVRP%5?q+EI>E㗾2KҘ<?.G><\2b܌ <>a?!qb=~b=O> ?d= 1>10>nF*>I<>LWȿ%?ʣ>&?')-?q@? ?oul\W>U?Wu>W>w?U1_>K#ݾ;""O?f6=׾ 3#y>?Oc>q ?踽p܂?cQ7>%8>@}>Uo@dP<=gq`PzG@>CM';} >'T4@;F0>Z6l6S~ù?=p =Eƿ|@?h;ה>$t>1I0?>}<]>N>;.;?G=2&>>P)?U=ؠ COjM?Ьq=$y=cu?Z>=ٌSc۾¾(|?Gt?@%96?ա}$`?Mt ?@C3ջvaмMӾ0bNw>Ml>k? 6/?U!qő >c_>">3/=fͿ̭ >~9>>ڶ$9g>0>s{>k?dZA>.>r>#:g>׀>aӪ>EVX\~Ц=ɐm9xlF1Q>!'zH0`>=w>"=^=HAC⵾J>#v ȿL?ޠ]-=0'>!c5><ſ6 r.?[%>-{**r=oNM؀1\>x=xIM={>#=i'HTQ>i4>?W>s.6@=GܿV&[>hi=2=~>7b [_B *|=.¿+QQӿI= HAt -UGݾsl׿Po=t>uGۯS4, IE'ECl=$Ɠ[H>ߓ?J>Z>΢i9>]?gs-bXñ=>:>I,^_,[L.<>y?.4ҀRp<þ?#?PRIB$S?#wK?<?yEw?f?Бl%e};#=)6kts!>->;D;>>ZJK2%Ouر?:? R\c?ONӿ濯BFT2վƤ>~HWS+Χ>ץI*mu0Ŀ.>l0sDc>$C>ۮ>?wܽ+;+F?G?7]?Z>S;=.??!i>+?wٿ2K,> t>O?a[SP.{@t>xZ3>5?\&]<O8A='?ein9O=6~=?5Tdiл>kX?F0$>} <0g>>ty\dZ (6>qe~džCi!|龫3??Wy>g>s>s?B[>۾Z>\>D>qLgM:ޅET>.;? =z>N?(N V>B|?>>5HՃi@>8G?x=;h<>>{g>?kh+4`wKK??3>{ 7MV?UA?RQ0߷a>';Y _Ӹ5ag?Pl>!603"U>րC!] ?2>u 4֋=Y>mvN0;]>< ,P昷v?[T?=l,`aT<ы qd9]Pq>q>_F

Z8(>>L>pkW\2>ut>=*&.TC>ݜ>¾&綠 W*gGx7n>t.>[kʇ@zL<>۽8>]CEY@Ovl>>羕P@<}>>dµNjz;=2Rν0S5{5=.>;t<az ־9ھh4āF ڿj ep,=_u)}[A< >Jb>u`>ϻC<Y?Ӿ!>e>< 謹B|-w]xI>>H<k "(?ߠ?=W~ &0b0-<<Grkz#9FGx* h>'=rz ta>ɴ>LF?=;.gVYaT= BGEDS/H>OY?D"yHA?`t!=~=  ~>:>(_Jw[ =l쾔_]K8='= p@y^}VJvH 4l>KoI^N9?9>q:h@Nbܿ}W!>h5>;D$B(t?1b>ͼ ]Bw=v3;%@*La>$%=lӿŨ7!ǥI=~U;%13Te>>6j۾ ~=r(ݾ.$;W&G{==>O?+S־\E$=?՜IcLCZ|pʾt?>]+ t6=&t`._+|3>9=NUXH=.?4?I>*E>N?J >H~! ֯>m?#?r>Fg?C?F?bj>8Y@>ҡ?t?'b>$a@>?3 >YdA{$>A3=GZ2Ey@!x>x1>֕=v`;Fھ؟bh_e1i>9e?h^1Y2d">7=?7D ؿޤc=P]=X?9[K=">{pI4>񡺿 Y .;_>>mK0Pΰ%ՇF s=⬸?'&>F3ЗսZSeyև>Z}??EJ^>!VF b3>|wx4Z Y2<fw?)O`Pe?_NžY?Jf E>\@ w?,k{? }gB?RJS>ſѹN!(.Q>5ne+=@ƴ߾*|?~>0uX50ż%˼о ..,6:j>%B>P C%0̓;K>>rvH Pᾦ>Ġ%@(!鯾Gs$&3> O2>Q?i>̵W=(>MPl>?xtT>~,=dE(I>>ѳRSNԻ~/l!:H4@Y˾.LF[ĿuAL_׹uL.Md!`]S?,?*U~>7R>횽]cN?~^B>Yv>M<O<8=I>?ƽrKk`">bc=2fṕP3Y>nk=atL'L0ӯuq: kn& Kˬֽ"{ŜDFKQדSH vo`Z`l>οX?|Y9>NM>\9聡g8J==ރ?>Y\pD=}|>X?%S9.=? J?DF=R>x4 }L>}N?R>`?-YRL>?2=֮<Ҿ[s>W?B۶>K&8#0%P{x>3`?c$Z?p!,0 f/ۄ?$.4?>>|i>?=/MM8kO>nn? ?7~=7Gӻ^>F?u?#t>ƮO3'>@?\?>?\̾1m=͜k?]P?>S=8P>2ӿ&0ſؾ[?\@)>ME2"忆tw>Tܩ?+?k>3zV,=Zȣ?su?>!=+(?? ?'H,;:ͫ??O= 9xu8qV??i<"6?HRVz˿ \ٿ8hsh<>><1D5Sf^>㤿 ƿ~,'>/ρ?Tt?*>c"԰v??5P?#G,deIV?'??[ V5`zm? ?q?0D:vCc"?E?>/ؾi<./ 5?:\/[GݿJs4>)Zl?n?>fT%M??úo?=n?TL?Q?A?q@⌵V>]O߾qǛ.#6] Aξ>B1/ץ^㽴m 2B)!ÓM=[??5">?z??@?Q&b3HJ??PL?_/8? t?É@ԕ?g+X0ט >"Q¾}|Q Ckvh=s?ax?g >t8LDVl>9'cɿf@;Zp@jn>h=hZ.4W{~>#t=l O? <TLVιgY@x>7SSj+R4?,?^Pi$?7?dPt ?;?-5 iľ>ws'_-: 1mK4_Zy?&>AJ>p?I)Jw>547=ҽ˽=*5;EP+>$=Gd߾ћԾXAcj>ͳ=?4=!mY>pz:N/aU݋ҿ?ʸ>>EO<‹?=x>{>e|J [=>!-=>.H@JPn=(xdͽsVϾ0s>F=V=ˊc?PW?[5cC?S6rH?Fdu1?@PLa_5>\}?z?FLo5H?PlI?Wv(?/A?:*?Ζ=jn n~N>8=71#XǗ?cTP?lB>Gþ*h+p:T(JAB¤ J&U=dvlQ>vyc91u=[#ݿGn >i>'[?|v!@6L't[ =y3]6n;]<ߋ$=#ܕ$=u0=(BS&D{@ka&!;О$W| =;\>j̩ogy= Ai*ޚR&?*Vf)=Qs(1k1/ǿ>je3>gUnj6u韾D>l4Oz ,==ľm!?1=n{RL>79==jƋ>=˼l|T>GE=>p=&[d>ibi='QP.>!Fҷ-zNhQ>`t`|? '>?<ۜe`! 2ӾC>ղvǰ6X y-<콘Rһ>@ X!g}R&>\&О?b?M ?yyݾR&>AS=.>'K@ |)->zr=- 1?|3̀ha*RTq=ƅ1+=Ѿ=.j>sF>9%xNj->ÂXQ=?Ո??Ts?:֙?'?oW`>LE>kS ?[0L־-2>l>Zm>G(>=m?=M=<>;V?"E=悾>|vU/:)LKݾH>V>D?%4uоq?& y? y-?kdZ4R*Z?1?I?pEh@4>`> ?X>P>0>5 <3Q?2~'O='t>~0H#?L>id.=W=dԾC5>?ڎ74?>?]) !?辰>0ӳ?:|A>$( $?eyA??/?"?~L0θ=:?!5D??h">?+Ó9aGI>>O6v?A(9pL>jb4"l?$d}t>{F=3?/cg-A= ?%[ɿ L>p> ܇?n@3Γ4+9?*($>R7?o?4deo>u>OtZ?/xƝ\?3?s?@cc1L?T??G?U{DΒO?#z? G?.X?[?H?TՊ '>qX:b;C,,^>84c<K38>{ H=Zu>5/<<?o0(>;R2?IT+ѯ?X>D8?xX^q>= {?Tj(̖O&>xy>?<)5(J|d9=M_i?/i$nuĶc9>LEFէ=k׿rX ,?%hr;=cX4;⵿?SΖV>>?@{e=A6>S>>G?F?j@.>H&gQ(=<_NrTD>2Cf1 n?wO'"7ʒ01=?kp` =Ea;Tb8n>U92?P#X Hdc/>ߨP>^?O^x^R^>J#zt?N A?́GG>#7eO>}?$>p.21=pn>$cI>pz> 4n?#v g>s=8v ?<XVVE>#>=j??Tq;/EK?"HA$)>g?=f0f? >=o37?]J>msC{V>D?>b4g>|[UPbѾ3>l/b?D?Jj?fYT^=;]>D> \l?mh>k=. ?8G?{N=a.ٝ?5Ar:k?>J켘m?^^_[>AZѾH1>W=l~ ?87^APtdZѾ(1 %>ny%Q $Y=I`b F>?jQat;|>6(=?OmhB?T>ܜ=?׮?J>G>MW?g>5ϳ1mc?(B1Į>B=.s7T?:8p >^Mzp?P(>9> m ?O71z>Ø?jmn%=g6Yi?R->k=~k,?' %&>o0M>4\?E9⬒ֻ<> C?( N?зh{?cE|?[6Yp?2rC?XJ6=<ʾ9?id> V?-,>:=>Bx>@?H3@?ȿW?V?Ԟ-tO< Yu>sўFy22ƛ=uV(n(>N >Z>B۽ ?d T>9*Rҿ>5 > &},=P"Fԕ?mK0 G=WeEż?&P>J?.>?th?T섈K>3vվOL>}*ĵ>AGM¾z%?0J>1򾷢Ͽ'/f>Գր>L9*?) >H&Z?S.L>s1{پ}?9M6>J=&OUR]?L'>o?(ǟ>s34D?7>A=WX_Q?Z#d>?sm4?6Ƥ>L5=:7?esP>ڃ>E=gZ?%J\0K[LԙT8Ζy8ֳ?d9~9a=_<.>/f >j]?2gd+>T4&>ɓb>YTegi!?0>.? ;q>t1?ŷԦ>=?s81𾅞Ǿv>ْBN>h澍?7x>!>=?Y(=Ir잾Q?7ӷ=>V6m&Y? L>'.>?>m> k>P/?޿拓?^A N? 5~?X[?BP??•!X?W ̹=It'4R?H;B?Ue#?G ?J?@?Ea":>+|5nSe?4suB> S~?P ھ*>=?'gAh?8ӯ`NpHY>ɭd =H^zc?,#Jpw]$is? t>^R3ξ\?fij4/>tdMX!?d Zz.<\>RcRE?~plj=Jk=Rg?n$j?>^ѿ?qԘ Ls?@?2?Cx0 ~{E`?j?{?K{- CT;>Eni?)$ >&;զ?oP >p+?^'Йu~XH?B!Bňlwe>㰿A? Zp?M>$F?؛Zc>*ɬ?M1? i?{HR? ?j?B^o8ҾsH?/Nfw@?9h?zsr?`p?ۺU?Cf/?x]=gZ!j?,`1XN'?70s?G@hEoO`?? ?vO?.'?%[?T?G=)hn?D?hk?9!)>s>e?7;?~&?=jQ? ?\_? k(:þ_=*<Lj?+|"Zƾ& ?\l8b"!B1?%k`r*n$5 ?77 uc_? ]4Koiݾ-쾫?@z-(>A?6۔?x?сl-8іV-?#~پ$^սj^t?`si8RQ >ǽ"g?zĿ58.;mý?oYG??g)5-?vE??i$^޾HG0?7 mZ rWʾ~/{??ԝü=S ?%\>%>V>KQ>X?>u?$ UX>!=)N?]rYB7Umz?2[U`|>ȃV>@? o\(FJ=*e=⋼?_`gw?!hZ;<%ٻRuTv?X1>9kϾH(?BX\>>پF?2ȈQ>/T0?%V\Iwq>F?E?ė?־2vI QU ?WU&?,?JN\74ٽC1=4?b"ƶ$> =?#_A=Zy?v]?RH?! >f06?`с?>>M> )?]NԌ?6>p>}V?X:qf> c?Na?b? $ni=!>*?8?$EW*BQ{>͚?4>E\R??^2?- oԾw>f?Wr??WMS>>q>E?Zҽ/W?TLsDR>??L+?Q3x*U{??6?5?ݥV>?yF?t?#y>O*@>Hx >=ͮ0mO?^j?7?k9ˊ$괋L??f?+}>"Т?*?u?]kq?Y=Rr>0=hP=u>Q>˛>Jo',>?'W>vVP=:^b? zMT>HJ>d>6?4 YU {?J*o?L|?5Vû4Օ>>a? X M/?ղ??= iYV'?3?5?J_S>X2?! ]aP{J3'Ӊ?"0`Υ7zS@>uq?\!?-9??_GIq>߹Z>?4?7^t>cA?0?C=?\K5>*?0^?w?0y>YN74dܽ2kf\TL7{Gy,N?T.!byݾ䴾䮧O__<;8>⋾=JYl0C="04ϊ^y#¥a=2=?O Z=> >W?Dfd> >^;G?&>͚}m9>L>#? >On>s?%?6?R4<~1Ľ ,5¾g`ҾA9a \8*>O7V>>D_>C?R>RT>6~>r?ΐ%>>X>C>Z37n~B=/4߾'1n G>jcFV>O+?Q=tW_۾"f41 >Wx5W>8C=4?8JcSH> ˾BS? ¡R?f>y1>K?;MT}\p1=Ts=b(?DN}NQ i/%P*`?} R<߾?=2{?1hyZ4O?Apa?'?##?O]Hz>">>>r½uX?=>E>0'>6+}\sϒ)ӿF=0{zBO*T>b>5>'?im>Kzs?? ? ? pLM@C>7 ?L? c?&$,C>0qŽӏzθqI!L#>x?`=!zrH >>(?qD nqI >h>??=nIhc>Κ?0=4O2|Y><>?>侉xODU̽"[q>C"lp[>>ԇ>Dk> Ϣv]>?87?QѳJ2d>]>"0=>>zJ=̶n? />P[}?>TQO ^/>ڿ| h?+e>* k>Fm>/BR&}yѾr\>k|5^96uؾ㬾>Z:Y.ɟ0Nj>[[>r<dA>:XWs/>. )N=ϧjjQF } >޿Eȿ/H لs\>ǿԿCԿG!d{[>:;u& s-!>}qU?eN&WUFmJ.>x?O^tM>1baj> =S.{p۽>]Lп2tN d>Dvӿ@Оn!>k:r>F&-YvZ3%h>צY<(P?#?̶%=> i?%>20+>y[}>R\VxFg>ծ?O>`z>=g>qYCiO>̫FTտ h>e>վP/l>{]j>u6;TBQ"b`M>AѾ*PJAj>*mh@4km)>mIzh? |ݿ>)ab>s%2>ݘ^'o Ȳ>"Fpq>D(y [UeN>-fdڿ3Yl<>fʾ(|1qƾo۾+=L#ESH}<"F2u"-T>#V_޿0>̾Z>y.`z2t>1w>yOœiDX>ES=;%WC̿_$tNI^LfѿLAeX!*+c7NL0˾Дf˾ oe!7~!聾3{uB1B>^+l>%EyBžqfȾ꾚>I=8ttj!=?Ġf<. $`݃Zs=M/P)cVGV=Zۥ<>*sR]>%տ'1{O=̞#=غtq=fNoӀU {)L>/+>cǿ&Gzh_?>Հz9q"[Mi5΅JfwM+=6G!Ŀ`ھݰlc a5*8#ud\1v -m¾A ki^? `g2[{l>ӿa>辒辣SP=B}>QYy>h6nrr=P7RxSww|=}2ʾK?D?031'??bN*o>=)oZh\ m­}K|{v=z^{? >4>?aPp}N=;iMa|5ދ;]Խߒ>\v6=p?6οii Ntp^ľWVɾoa=2vzg;,X>*]oA俦!xfA1.AWj4n@?k\3r>*̿bQ~HqhI<"> ̿t~>]ERLI>6|g=zS>O/P9ҿ%Ψ=joL-"h si<]5fb.sz>Joq*&ѽu%9i=WBb9TK侃=q",\߭DeJ=('uXhSŹ p.._I5">[wQξ((<%$!}O |>8P:=&>pE⽻ꍨ=gb¯޿S-18DgC律о>ɽ<`M*ƭqnֿ.$>d=X?="ݿ:>W:>BiF>a󥾫uHǽ*>IFO>`rҨܭ; ; >EQIb-?"[>w0P*M \i>J8'_v=xĽ/>PJӳXlQǽ=#uy` ȿ.о#.ߴJP%D̽o*+ǾaczUҾȤIm L8\^$^>GX<.Wdľi>F$>Km޼_ %;|FL>I? Dn!8]jD>׶?4+LD2n$XGt=v! T )_u)=s ♾ 2H=l轒>=>9#>\:>J;ϯ>%徵?}ɟ>s@>d908C>G}>A:@>rf4J4i{/ =Q)2V+0ue-T龽$>K1=DB>VJ=>K˾Lz>h4n= t#S,Y>3uC%BJ=pgY) GQvw]̾1*Mض D_3ax )Vb0w7.ApV0N= aؾ$=zmhB h^. 5 M> =iӉsxI-<YO3,n|JϾ@=>4X:(?u} %w= ?ׄe>, uOH]3}n=G>HĘ ھ'46ۿ](`gxy=(< Y[dcq=~ӮGXO\7Mnv>t踾5-e?*ӷv=uX |t±6-h+o9*_ç1'ddgzZ#!Ū+`R:Ŏ8XlU=޿ٿ=/a+ؼ4JϿ"OR|1ǜ2rT࿇RVmP@V67ݩC}H^.>k8#D>>inYӾX[3>}=yȿ?s>0HF$i,2kt*=̔-99)dcoȰ>r{->I*<{>:~e>3]>9z{>u \ͧ>7~#攊I=?=O@E. ;hⰿwW>{%> վԀA*lTXGV:*>AXwԽwX&? Bt=콯V>;>ɿ? h>W:bzF?j'v?>,"EпY>4¼g3¿2ak>Q>?fRA(Ym>3Z䰾\O="<( >=W'=on?y5k>%>AϼӦ>mp?P=Gؾl&/IWm?7`9= g-Yƥ?P1> ==>bܾؾ%%?-W!>-,c%%Y?=:\i +?޿(>#.ҿ5N<%?>x{aNM@+)?= >y1+Z@⿤>o8>KySL .?Ӵ>v |y)g|$@4@Xy>ra%>L]|-U J>-]<^>5lQF_?#>n$5?M} ?K>?E?.ᬽj @=!x?4n?j=ۮ> >>??GsKe} =x?#?>A77>3,U2>/^?,?Q:M??+Uղ?<: >L>1>D O81Ob3> *|>>]!6>1]Z?2(;>? > v?J{Z?M?Q> 3>7V>7C>FS=)I[Bu$>?8YQ >=2".@V\n=$>|Ru /֕پvKvWIyWўx#ݿz0$5=:=$ U= 7 ܽ~ܿAN==Ӎu+Կb^C>Dݾx&`LV>t RzejmkپS;Z>>վD@F$ѾMQ> >ҾЭGM 5=>>R/[閾YCbuz^`>u> ڽ;R?LA]p>f? >ͳ >s&>++ƨ>?Jgw>>I'^4Ct+Z=H|>Չξ82?,>?9ܔ?x>?"Ŀk>0@?ql?>??i`B?xu>?22>?=| ?q=L!<⮰> b>¾2>{4>->uņ"h>vU>?1la?> >ew>uJ?C?4=ɂ{¿ pվbRq뿀2(пsi!>F?$$v|l@_~ =&>QHܠwgZ[=x ^#:>8 P>@y?g'?dǯQ>9??=bK> 3<>?/(?>[>A}? ?=?>Y>1>ZqD ;=?? = 26&H'! >?] J0ƒ+Zb9> r&@_{== >M:5k =J<=Fy7=Zﳿ <\Jb+=@5??e=(Jpھw?WGs>:_tr@Q=mҾ'pe t^0>Y^S7xi>O:hU<#B =𪨾.AEum/j B7ӿ!?ڿgm]><^տ0CUC +K=R:= 2vhAT?Z>ƾcp.>&HF^p3 c[=w%2P>r% I쾤ZľD>K2Ukf6b94 >?D?+Zd= _=r< t0N>??z?G =_ɿU]eYHEq=?<7_nVh^՝ >::^ ?]??|x>!_%$=Q R%0a

H8;_puhJɟ_ip(wGL3<7Yi.E7egI{|>T|=<ΉxG>; ʟ9^?>=?4w\>cA=?D㛾^RjQ"*$>hgZ9́?' ά-a Bվ>T>>u%kGYɽ'6>(Ndj $OԽ񋓽A^9IR/vd{{Y>G`>L(iom>iL >wl>ۇhəE0͒U܌>c>5+ @Ztžǘپ -AMK@S꫾^C+6\T&? Pn>"1?y=Uݐ^[c^=؀=s?HLj\B>0.=#?87.o>%>L>?CD!Wq+ؿ%r5u&O@'=!꼿YSf~YʚzNI)`ZJXdU#O\|AVL辴^?ڿ]?M\U>#aV>,s7e>ϧ̾X;澄}à@gc2$@u<⿃AĠb㾈#[hb,I@CK r(L쾰0b?FKNx eӻqLV@?_>M>O?\'>">a {{aR0VI˽"澘 1PqOifTo&"nT %TאmJR[բ<쑰|ͿNPֹeZ<1R*@Q έ;d9D,D@)2O}Ҿ= t`{?]5et==G⻪.KH)'Ri¿A=8>(?i_F>e=dvl> ~b>wl? i龀KVœL>?<j6]BbqG?2?}>VE必mLo>X}???JxlL9X(>^???'1J>l#?0]B?>_a>{ -???O7>6=?ew?Ņ{?K=??s>sg=Q?}>?T>͹ :RX+T$Oz}=1?#?1>.f>r H*=|m>!ML>л=%=riApʟ=l #p`7@ = ҃,gXvoN?}?b >ʁ/=I=ʹ˓d>קYMe_=pL>W‡‹nLeؿYɴ)>,?Ű??o|byY>]d?e?f>ը߾iu|J>,?q?30b>ۜh(!B?@?e?Mw\^P???>21?I?5?zĠì=zTŽWbp>>` O+c9>c1@+/ſ}c=>Z8ѿ Yko\>;?f?1>eo1?}R?{>.8*YY?|Y?>g"u:Ksp??w?9)~޾l?Z?*,?3%0EW?UK?>}f=425ƾ/a }={:$ѿ ]t#??,q?lH=8٣{&!K@x##?@S?2?m'ޠSڽW>y<EA!ٿbd{5=ݭ>h8>k>]ԑ ?w?M? !%é̾???E g $PȺu>V^>%C=ZwBm{>tύ{xJI .i(lț2(8~5п?4>c9>w pp«8Eݾ5Kj/_A]=sマ>.|t>SھfEUiR c ?EDY>ݹ;`K>⾒P?r?)?W'>/s;>">>SL_hZ?YO'NL0B>?[Y>Ԍ )=<%>^=_1>_/s=8Lbk;mU`^S?ZG^ p?ci1?Z qA?Ml|9z?=2a? ,=><%j'R]ژ?g#ye4?Xp?MEZ?kP b2?c5g3ekTml5n}JK?r/c?byW3= 2l:C? F=o7ݦƿR>ULf>e 4TL ?F>,_>ǽ=S<2~?/8mUyJeom/{| ϸ Eʭ濜R0q==:Ľ|c=ҿ(aN?4V?*B?@W!f?-jLQ8U>:C?Y?Dz>ҿ4>{> ?5BBBBBO=s[Ղ=s!=j=>y>b=о@e>ֹA71 R~_-f<޻wX}`<>WȎz qj bc=CT7"TD^_J>$>l޿5>$Pʨeυ/>YӾ> =p>F?|5>=?Hj >̴he+=ti*>S<ҾWyJ=KZ#K uX>>&@>>j{*>{=iR>)^f+=;⵾uy>Pz`ト'g& >Jĵș=9>mt=F2=K!m޾>MN"(K3=f;p%| g>2>0֋=!.QL>g-^Q#ֲaF=>p3Bx\=(R/c*п=H x?MNMl|pa?,> ?;gK7zpE_>rx7c.zο =ݵWhE_!>|>?SXXF>{g=P?%J^9ap>/E>(?= [>ݨڃ@=/>jPC?YھQ>>m?: >l]*$>'Jw>sd?(q (N<=_>:-??iL@0BB>%<8N?Eh ?$FkZ ?3u2?b?}>;P>Fz>97 X? B)h@(Y>tFtH?2 G$U>*E| ?8>^E>>r=y?F( X'us>_W=e?[jݘT{=f+3?I?$~f>XN>=P?K<;>)E?;Eܽz*>vhXEһ>Zj>J 3?%]X-=k>jFx?4"8:,W\>GeI?*_ .𾅅>S> o?^6@̤&? >:?l{l+ۥ>I>np;?:dž!=+>KJ@iK >e2LoJ]8]>(?a?# gbk>4 =kp{> MY?n>\_?i@iW>'>W?;!ܘb<7PaQ>PH wowRs\>y='T^>>´?0p=WE] >ݠ2??F,>I]G=徴U"=dL@WT S>sT$~վO7>MwHMl4=;H<{lF8vϾI/О&> yx8j:y >R?>S]?vخ>~>? XóA>\?9pa?5]*V?V`î7q>(5Y=(A?n|<لC~,[>>5N4L=CŽe3=m?*?/Ωvh?>@?}?@ϨPC? NJ>?vd dФҽiD?>?rS~E3<8>8u=?҉O50bǾ1>Κ=\l?ydw?Dʒ澴K?IS:lB$?*aJ>+?DaɾCf<Ԋt>?!2?63 /< ?#30wI>IB~?Xxľz>Zս\?Jͯ 1zX>b?[6R>Q>g8?JB/\ū18> >k?Wm!>{hL CJmѮJ>R??$he>64տx=ZPD?'h޷v<2 +>R"J@d ??M8>5?Nxk >N?Hj >82?~= +>pKyP3= J?:K& i<:2>R&>F?bMM'Lǽ1b>l3M?'ʲ>jYac? cx4$->];4?5HT>KO?0Rt9n>ҾPƿ)m>F͞=jZ\#y>U>>=3m?Gf >i=:?E>4r?5lڼy>]Q?!wZgH?;6=񲽺?H]"p͈>C[-D?n>3n m>(_=GYɿs.>%1ҿ9 {A\%>X6=t?Ңu& iY 5f>~ ɾEHkm3> _V>LITv /?}V^=hH}#+߅?QϨ;J?$ >e@?CD>}=h?GR" =z)*5>%HA˒S='=gXu?OPn2PPE; ?tGnyB>n=an5?Pa1L΁R=[BͿ+>[4͟&j>`*kµ=?0ۀm>u>h=Ɖ?87_>ÿ?1n>-迓?nޜ? Y>(~ɶN?" tA3>>=޽?iRnX_6۾K?5| h)Ƚߣ_+?BLݽ;L?"!uˆh j¾?:B/qaB=yc?L2y@ƪ=7m>>48 ?/sE1|B>U?;D>?Qm=>X6=ޣ?hJ& ѯ>K'\1߿ V? |K>&̿]gi>Td>c1]pE6`t>xk=bL?Z6(me=es↾?EZ:m7Ed?c?'Zp>1?=>]_? 9=ĻL?g!h>}>l7}?j?K?  ԠHa @>ȝ>õ9>ƽM?i߲>J, Q?C$t]D+g= ?P-CksqɾS?3K8>>*E2?j½PG+E>J?gꑺU>Gk?BXB=vq>'3?qe>L>'LBFm?Bs?zu7> >>SH?g8e>s->[?{?o(|= eؾd?+r;>tB^?% 11N=>!?_wAm=ض;.Se}?EV>$x?0.^w:?.As|?Ɨ@9?:$@?).1?V&&?@=2Q?aO?GET?6я??]PƯ6>[n;?(54)=2q7<,ypQK?Q^r/?z?IDÈ? >g?V򹾔t>Y}>&?Z6!2>9f^?da?>G?{@=ĉҾ{Z?/sغ-=t~ƿ?-&~i>=$[:q{?r,$x> G?p _>,"=c.?x@|=v% <~ᾞd?p')N# >$(Ծ94?L[񽀃E(?Nq@eרP>އ>E'?ytw6Ro?(Lf9f^_2Բ?Ixz3cP?"tu7߽7r?Cr ž apag?:䴽tĎi?;Ͽb|nƼW& *?6?k/zzÓ;QᠿD1>ۜRmp?Zyb?7㾔s|=U_x#XO>),c=?/ t?ƛj/?Owy?m w=.(gmAX>]?H$ @>>?K]?ӻZD_3?>:=տm W>6>+_#=Ym??/¿?Ti jg=?aqp"R'qWC>ylDF)0l R??v|I-sVqtGՄ+>lCPt.Ü-f> =]M?{LJǨƼr'?K`J=PN?bV?4\)&^T-0>f>d?~6]ؾ >1=Զ ?_gMf]Bu\ mҽt?KU^DJH|A?l?K?fYۘ=?O ?p?t=ڭ!;?p?ӄ?N\ ,Ծ5L? $_BAv? D>}?HJ-aq? >?SX Ya=<ƂA2r?pZ-#Kz_:?? m T>V>$,?VuA iS==wP?yW=Y>8>?oߐb>!>>B?fv,>o >>WX?>2 mFV> M>I??:?~hm(A>?_=? #1ʒQ;>z?P{? .X/O="0w>t,>m?lSpٷ3>nO3>b) >6?T q>,:;==^>g>>w{KO W>,>֙> l_˾?2?(?;xW-F>bo>k(>[>?PF?0 $Ngqٮ>?>t UXR>/>h?nDW۾$==-0?H8,>n+X?*>,?>R>Ua?ʎ2½>PGY{18pT?U!AQض>N^?>y::O;='B$ A>9KZ_\3B?5n=3w\@P=q #>K4"/o >Binj> ^^p 5y/Ȯu>ꧾ>ǃ{?>nF>=>R= >v>?*>v}PS>q>1?.>̅^u7m-?)\\CER? N{[3 i/ ?|zc̶r>G@V=&B>.>OE9ZF;,-=}>"3@="'t>>:>M>>&y5>+Z>E_.~ChI!>!>>;Aw?⽑a=Sx"BD"(+߽bU*"3߾?>OͫxJ'о#= 0>/CSU=X+.<(f==S ]n>ھe>C;58N`Hc Cu>qNM ^?d > =4>q>o;r>Nپ%o3>o9==gO>>-w<>Q>BERvG=v` > a-#0(>9־E5ʾd[Iƾhbb>> Y0^ξ1^}S=ojKL >m׽gQ ?+S@>Q,= =SE?Uh@$P'>@>}>?$iL>ԍ>z>P$?5**> =¹=I4&?\A6 >G=OuS:F?K4W/$?4>Ue>-?,A/->4=0=?_FJ~>=!>(ݼ"h"j=>x>B>C=A%T!v>Z1=a! [>^O==>ehb=>CgVtIJ0Xdګ>|wk{TG3>z.?%Xa F>GA?>ZB?OjP<>ox˾D-Q?7B47xF?>>D?:L4= c'z\(?t.,d>~O?C7"Q`&0>貧8*?$ >==l%??J4mHJ{r\>>/?B]-pB:>4==&[?Qg7/P> "";j>t[HIOj Z?(>f8JQc5=?r٩YJ>ZW=d?a*R<QP0}i >>ZU 6=&=_?ANݾ$ 6>kDUI2Yʾ|>P )q6>~>A?R{;9U>m>6?W﮾ڜx;kD>R~>-m?s˾D:ID.>v? _?B>-?҃>#`>+Z?`ݾaS&OF꨼6Z,1?xͿ-HFS=`>5FN2UؕG(:>M,^ҽ=J?߃=8&̄پ X_>D1f6>=;N>٭ɇy>]Pg>w2\>>?Sx83_1A>Ľ&?'$i>3<4ƽ>:*[v Ja龐þ_=E{<0dN`U2>?=? ]L@J=͵݂;Ի>D`>5Mb=x?QS>5> ?@ʂF/pv=Q/>ڲGx'(Xm>吟>$?M*H!bkK_ zfi>о Ծa;n>QNVʾ) e|>T;谎>=?-M/h"p&=I?m?Hy?jjӑ3F= ?Q8?14z?5WG\=8b>d4ꌾ2X@><%$/-;!>dA~$=9\uY=էҿUeY exnnTP5,y`e3>&ٿKPy? B>~=!? 0uׁW[>Jf>aJ?Q >77>py?0q"C?>>E5?i^ňj2?>ƃ?WpC?ؾ~7? \U>R]ulQ'Pu?L>L?3!)g#&QI?F}R/>gJPjHs>Hs8)ӾHerھ7Xn9x\Aݾ=zQro)$Ub[p:=5YLU>&S=)/Rs> M\Aѳ)??!)E>L?T "}#@??"~?5YxOͱ}K\?8>M>GCty ?+y>? D2 xO= Ax>J uo؉`8>t\-[/PRr:оSzSI>4#d>%9S3>!ǿl](qq> =a R8|[>R=>Fz(|N`<)Ծ Ev̡;aNj%pޏvNC. @# &T==L>%h6<豥=U> Կ*Z>+>)i=&"|YA*+#K02(ifQ'jF5kfU-< י'?m녾e `qFkld43¾)>&:>eg9ܡIV=I˿T &x1?= }?,?2v?lξj*s4=ŗg AW$`g68Ws=3<]WS=!yxb>?<5T{uuob5>=V7ls>ycs>Vu޾9%J9_3JwrT?;!> B_~ Ѿ5E<<쨠zc2`?=>sPe3Yk[E;2@:{H!K#HFc9[cGR B$HZ2$a`>?[潫ھ ?>]V]>!=0<=.>lR W>{>=K>e=:Y(>=y=Y >jS>>ew>o? {徚<[>ku꿞+oF2e=p־+ k 'ཬ?ľ8Dtta`6)R=7U7t0 * h FXIr;U`CB!*7)oqп$6(Խ8ҿ%umumտAՑ9<:c5fŠiSl\fQ)ƪCX;4ӄLa1>;HM\== !l 2n+ 1> [>~IlvK4>, r@=>sdCSL+[#=4?Ku)9yd=\tuO>2G&vb >3n>-oT(]>ZIɾS>*A_? P G4 ,*&%+ 񧃾 =i콇Ŭ>ȿ_9u]>>GmE D`a>t%>yBmQ4aj=b(=Mg2w>)c> ,d ,96'mG9J,1>ILDV)'Ŷ *9k:Q>7>ݿc Ac=e<=nFJپ>1>`i}{t6=uϠFz 8~_;$OQ>&_,ml_r:+˿T+I8挠]*mRkDRY y->2.=f.Mھm? ;9P>RH7>K2Q=Os!=;k3(&#=Nླjf:\!27p]pZ>(V _=>);Pvܿ- w $c[&!4q>N`F!>7>_̟A;?1cHӳa|w *|=I$lyr/t9xվtxվJĵ>fҿ8u?,>Q?Q"mDd渿XHqO=SGdH ,|f<_!>6>Rn=>~S^[l6!迪W,=[ݾ dATC?[ƿ_>e%Ы.WL'>G_Y;fo5i_'HK쿠J{ п?ѿrPp t=FDʸr5 |_> Ϸ>>D>4`F>||Uֶ.0'e>DLg=(^Ŀ~Yw%mmω=`6xQ= ؾ8;iV >Ӣi`5;dþ<¿v@W}Rt8">zw徵6G`-)=O$c!>1澥pſl@콤4>=7&Z =Ꞿ.EW6o&!eE>.<S! =O۾EY޵>&>B>f$g]_mſ>(*x>auHvDſ>[o>"sap.> m>1Vu`>A>uE|P$P-7c>ݱ7?f1@ğ{>As>X?5c?SI!= K?E(9+=u⾰gK޶[?34ƿu=k$q N?F@B=kPb?~ Q>2eMW?ǰ>L =@>p .=oWKCо>?yy=X?-ؿ>G>..oQ%{?_>WQKZ<ǂ {Jf?S>FIԾڽN͎1Z>=`h=Qf,V?4>t?!?:M?o->0?R>??7Tfr?Ң A=naHDbT6>XS>^?Ӏ >k]?V7?h >+?r>yF?V?h+@-n=[)p>v%Wc0Dxl?@?TP=Z=9>f=>]ϒ$)H;N>=]>:? >׶>N?KE=%fec=uh%ujd7?T~[>2: |7H^Vrnޛ=>ľ2#A@s=B>sMl>T EW{v<>'6j!p Z Dx=>H!4Ҫ>a?Zg|)C=sbc>E__Na=>u?< tf\>ѿF龓D>!:?m<ŗN>dп =XYɾQjHtԿ>}5>Zľcx}>վ]>B<$>ܿp~!p=˪Xh\k>V\.g>5)<E}œYۿ>M?\lk@ >עء<CW= ⃲"b@>1"nMX.+>4̈׀l~|9>p;x¤M#m=E>>?F[23۾ھ*nvAcV=(9>!Rb >m>w2Y`\ PmJ>-@,'>ý>۾_s]>>6I8v>ϯ>3/3rq2!L='>U2?A1vL=eX=T`¿#=k>3ӿS"Ta > ?}>P,H >NMÿx~=7na=V劾mH8*h޿o9\.yG?p&^F>pk{HNJtͿvt?̾dVK޾>.^1SbiF:>9i+Y%z3=[>Fc=ʉv=;>ۿ sCzz/ ˛iLDk،>]+F>F8Lk2HD=<O~=ABTſ ?wpjp5~>1]S?uBZiz>>H >1?R{`V\N,>*Dצ cm޼z(-ˆvI!G  04 >c?6& tyMYU:s>OD[\[sTo7! >".gbg$^^<_>3;dLN%/kY>_>L9? ~~q 6cܿoQ&DWdL)'k?4W*E>Pn]>{?Vy>YK8=s??= (HAĿQY.pP߾&Bx7oNLkKڃd?LY=UP=+"i#D?P=B>N!RTC&=B4"?`??TZ=?.?>]Oѫ+>-˼4[MA_̾ȸ !@'dܽ((ԿQ d#}=s?E ?>$)O}0KҾ'yUov>uʆp'=S: 0pNf]?/is>>&ľǹZ,ޭ?:?a>Fܽ^>|?w=+zI7T>K?I@mi^ %6`> n>>^$ 4s̼,?!?>)pʄ}>?ReZ yѽwA Ө.>-oT<6z١Klm;67~?"V=3ľ-2.>˟VATY]=rrauKi 뾒;C}1=pva_)N>m>9 ?-4;Znv=z}[>u?IB>>ͅN Ö>?z7>Y>L&>4P>\ hY V>/[`>a#~ $-Oq??D,? Wپ r>x??տ?XMҲ[EN>UYq?r;?>2d)>D?d?^>R*! L> ?`? ?)a~VeZ=>*?j?^>7+> 5?B?? ~l %47??>ԍ?]ӽk?t?+>bغР,?u??">F8ˆվ?U=!?>zbý0??}?,{nHz<>g?li>ʯ>O@sgu%?|x? >*-ĸھ??҅?,:Afsv?C?E>gjr!Z÷R??7?50yM?~o?>vB =j;~,^u=%m1w(=bl]i/=\:?iotل>b E&|5?z???N! [>O^OMuK=\-'b =H @B xQ]sY9?Vi >>1=Pqž?O???6]1l7>~=Ha ,CK*ÿ/BcpoV(D ,:>[ՙX|}ۘ3|3>IRYcP.#h>Z7>u q`W5+5{8>O+=azs|o=/>; \"BL= [پ$Ft@a?06>tLTj̽?i4>o=Bþ_s7g ?' >fe>#6 g U>n;׮WHpξɗs!1ZpAg#P r$ Ҿ+Լ鯾hz^> b_"W=᏾] ifVE*<(ȾthEJUA@I[O:?`;*4?C]Wg@y_>-rvH N>C,s GZu;q .$li4<پ{ b9>)^>\l>:,<2>.@E6?R>?RYECna ??2?>s-?f>?í{+?6@!T9~5?"s>?v|;̾r??/B?r1?H8.0`#R>ZA*=x:pLQR7?w.Y?{:kB?uso?IM@s?>?R=HԾ]ܾj/vd>BHF =;=M8> xOFŠ?ٶ< ?=)_]>2Y8a ܜ=c?I@?>0HwK|Wlί >L>v>mv>0%?=] [>>2?Cnf>2d쾍hoݩ=aN>%1=̽0<>5R3?g+v?m8j0/=$V`=77ڿhCl??佢a:n ^BBBBBBBBBBB}=\p׾<%BB`ȼ]վN =i; ۭCڶ7T> N=QBBBBBBBq<>_\2#=?KZ&;>u=Ԗ%?"P8">P =w?p=OKbog>z!BBBBBBBB@<Я r>19Bi@#`eqL=ƽ+|?x">"t=·5ƈ{?P.d<.Ǿ, ^_=ju ;?վ9=Rg1'oX> _ !F8xLYRIL>=ab4)6쾪=>^?6  !V۔9K>ׄ_"N0'Y>6rL.cX=?d>cf/><׾>)Af1|gT{kQ>gD.H=-ؾc>}Q?]=J=dDpuq>GؾBH=.A=uQi>CP??z8bAMY{.ྕ}>I^<%~I=r>H?d9=;67 ! X\> P?>U%>&.>@誾>iվ$>>H'?c)8>'F$?2ںppz[g5½pʾ>)>@Wþ>vReX?6MbU{=@?VML="3%?"|c>uK;?6Zh>n=uH?EȨD/I>OEd?(_C:Ҽ2߾]ϓ>g'A.iaV/>Z=Pn=A<ɾA> [ihW>>1q?2ƥ>̖>CJ?O],ţ?>%?qF8_=о9a=?]@o$0I>I*]Bx<ݾ=ҾIk <?L/l'=>O:?(ᆴL>el`w,L5> F٣QP>z?>?y4>E==d2Of?k{ٛǽ⾕> m'ݾiU>?ZNG|>#8Ϋ8U? >n??:|Y9=XIʽh?BW[!zvS>,0R?BT6o> @?:9ߵ?AIc(>P]=*e?m hր#GrſVx3+랾K$>:aqP1\{'Nc>?LBOQ6>N?¿o"?gY?`J?%-?\pxD"|R?5rL2Q9d4>w $7߾>7H>U.T6xn7Qh=Hؾ&?. h ?m3Z>NG$?DK?;u>[(ؾ@پ >|?X>039d[nP?h|X@>Q/ fo5l;->+e#>{d>_tƔ>?z]?Ũ̾x.?7'? ?;VӠþ>h>QW?b B־u?7 ??a|Z.9u?D3?-?IN4 (>>MhU(~A3?>qENO[^>ja:ݾ? xJ4 H>G+O>>ҽ⟝?V:\??> "KD>6À0fNU=-R?<{hQ̾\o7G`96>4B?[濜?@I8l">vb?2q&t34O>Mh@;[?=0Ԥ[?>Ip.<8:?6z=*2lv>w{= !5r?Y`ӽm->u=R? 6PtH<6q??-y;Z>dc< ?STG*ſ>K==?X)N>>`ȼ?WZw=0=gϾ \?4U~D>0k{=Ӹb ?H aF=9<s?,W*B>-Ž_[-?aŤN>iY>\Q=4??jS=0@:l+99dg署1@]3'>P҂;IοG>g@b5$ǹ8>6d8ɽQ#>o?~17νh ?l=e>?sſaA?:rN>lEb>e8v*[..r>f>c0>\'}a?Yο=Wg9?Hη>υ<~ɟ5%?  XL>y \_>)㰿g>3οc|x?g>F!gq=S]"[?gA8#ê? ( R<y=bX?Nx[@<=2$?[OK6> Z&PX tS>,:|:> ̿W >t?BxE "(>2P88 6?[hr7>a=m?NS?IEL<?_ ˙Ԓ¾ gj>m>pr>'.'3?lƿ=!=c?T`&< ?!DvA~> =^1;#?DR1ՃG>=6>F(F)q>&5>BG^ռE'>t>)==?~"\t>^=W?We_> K+>~%2S>ͽy쟕?+ɔ6>r3*3H>]ѿJm>N%n&}ʰ=ug>/8ɾ֮?izj1ULdy?zbV,[p`;`?V]ZY&%>O>dK?lEӎrE>iJJ 7>l2U[w>Ɗ=>A>'k?X$ʃj> >:&=t?d:"b=X[hI?_@LL>B><9?LQO=i;PEm?EeJIӤ_;?7 >f< 5g?DkŮ@9ӵ9?3ʸ&E򜻾9 >ͱH ij&/w`?"p?3^>?mg>>DTX=h 澘&?Y\AȔC>#T;<%1y?Ji?@B>>4P?͸2up9{>->"2Pr?ph/B6<;%5D>Am&=M Fu ?Q 2,6>=]Ѿ?cK *H>o>+SG;?s >^|Z_)?B͡Ȓ= 5o3 +? C>= +R+(?T۾n>>Gkˋ? #a=\߿U/>.0^?c>:`Bck> 9?&MM >{K0>] 6z?rXpVI> g?7#!>WLF ?Ikꊠ㊾m>`W>t9?r>%>_R=:6?z'>~,8G?WJJ? ? QL>7?8> >kh>|ֿ?IX>">P(?V@Y?3>|>`v>!>J;?VN>$'R? F> ɾӾm?LQVà>vw>?NCBP>tH? >?O ͘(>:L>=?ԑ=s>>#U?: x>>hN?@T>P>U>>?HI>ԗ>d=֡? Ca@X>*>=}?-V>cs>>?+[>>+R?r">?y>?&C?^g i> A? @>-#>K?ٝ] h>=>]>pX?+>#\> 8?|x^v>b>ɧ*VX=/¾ݾ?vY=ꙷ>rem?pa̬K=>78#B?>!=Ib_)=)?cZWf=+>p?e(0uJ=>HZ=G?q![==>}U?8!nH뼿C?ٸRC8>P?}$>M=?<󒟾B ?TQ=o޽Xmۋi?0վwg?e--!7e?)xrUżվ ?KHbkl?9?}噾Uhx?F!BVp7 3?'tݳKz?MzW?X@Jݭ?rP'(=c䬾?t((ֶȽ?<$hْbbڌ=>= ?߿t*+=?Y??s9G%>-c?2??c0r=>!Z>Q?'?tR?JZ*jB?|iK&EV%?,<=5ؾ2ۥ?s[n=#>om>w?=->G?aHE?)_?M?`0M]??L?{5)?Z?z?a_W⇾MϾHm]-? \Ux_cc>e݀V퇾r5EȾW*?Qm>[5T?.g.<־?s܌?l?Vpe(H;վw>(jF> yJc9;j? _\A?Q뼏@?LKMȨf> S <>,T,>+ > <=ER?oOD5>Q>?/1,57;>~2>B?1̒=z?^aO?8w>2>?sG+?Z%?ae=?\IhYűȼ,˽$Y?4> |O> >Mg?d8Vq>"F뾌}?+0agcё=8>?+bc?|OH~ >U?/>ܪc;>?C=\>1OV0O(DK>HhQx*?,?8? PCR>E>?G$o c >ܪ2>?ev >>i?R/#ιX>dBBF6mF0?)ؕwpϩ?>Z>'?˿~&/>/Ot0l_-=pԿ˫+H>6L8L6?}?j?ks? ?iB?!Le*ax>W?<>>|>1Y?">y&?.T?y?26L >?6]>u=*{վ@?]h꽨bWM"O?yW?ɑ2>/GP?80NQ~4?57<:Y?XIv~1D >ff?>]u{›<=t>S>O]a9=ts M>X=F)Ӿ J>D,7ݼ9G۪a>O>tL>;>3a`bV}>gy>i?p+hnڋ5=`m">Äy>4]^̿0 >@>>P׌>>>мr׿>ENk =>>>*kQ8vq`*:U=S>ݼ>A#m;l/>w>Q=qvaj =.%P>["Q\=$&ٿAtQ$y]=P췿 Jǿ/>+h5OH$=~kVPSge>M#`;>^orcE@c?e>(| >?>|֡<Ɍ;>0g>E=u b>J>>蔁>:a;o>=SBh=f8x@?>>>~~`D!0>;X?-Ƚu^؈kS>Q;caFtX>["M<ˏ>)ZʿA5k=e4_b><&>9T>S+>8:T=$>nH>vW\C>\W>?a>/~T=p >>TJt==[y ?1rp νݾM>|({ pҿRn>cd906m/9NSA>d>6 D%__>@=[;ghZʌN^>Yc># H%WC> >]=?iY%=~Z`>Ċz;s>?@t>D"@'m˼ZFBF?} ε y$/xi?{l/T=xOG \uOY' =G k8 /<>E>i{gž? (ߦ0#6qG>uhđ\E>@)Uڿ#<0'us>؊iI& $>iP3]HI$;>?R>18z=J {9?d?^N>slV\ N=o=:<?@Yu0L=i 2>L >輅/?@FAPF>e>G (>yw}ox?7!Ճ' >R=üN?V_j:{>(K<\FS=0>S4piG >̖!yf>9S7j!eײKj =ө*>?ƽ5XijĂ==C?HT:C=߿<\K2<|h=S߾|Hg>*x>j]=%z><.;=~>Z3wFN=>L˜>Y.(t.>Arx\KW6=Q> ?󪽤e^; >pj俁Izp4X?3Ϣ>r? 8 6`/>k>T?qOBxR^9^>>?v1FslѾC(>Źc>nApPAJ>P4OB x>O@L<6D>̒>Gs?=Z!̀i R>&4=$?UN>W>}>3?,\˩>%MA> @홷~|\?> >_=|.?"u޾gD>I #\`F>5BnB>U퍾 JMD="O{׼V߿/?{Bkؿ 1GsCes>Ŗ>u?4ʺp7~G>c>!?? X>[_>qo C,E?"x\>>-{<Ӹ>`?&=<ͳ>Å?7AVi>`@:_Կ @&5.>`d>W!O?*CV>%M+25C~,C>{o]`t!>nYz1l&@>~ɽi>[e>4-ϾX=Ͽ;*,.!w! $ 0Q0)ž%[#FU?)\pط/?>玿4Za>+X >)Q:2ս?k/9'Կ=? Wfi%F7"ғDJ-^]=ƾzz̽>W=Yھ˾a|={ȿ2]UT>ɾ*$t±puU>C۾֞{{>sU7P>?w,VeugU?0V>sRU=&!2>TS>lQV*)0x>(b;>j1>Nb>Ϳ9`Pow#S>if8=>UӿYV[L>+<`k){$q>7=*>-{+2,>ɽ7=㿊p >o=>f׿m >\K=>X¿rx>)>k=m>]d!lcȾ{SQMt_ bg Rk~ 0#Q~àQ>g?!n8n?'jj/6`}$ C{MYlu}`Pʿ /.~c>"[A@d Jž=.{UWrd2 > `D=娾P_ͫ ?_40=!)(>e]Ce^#) kY>nYM*Rl}=~'33| qN=DW>nvCٵ龷a>v|8{wŽ+j3|,b>ChIy=Dp@X'>(6i9>0b vj՟>r>nHIMf9%վ8#'zþ*C5%ȿccBD?D&J<`2)w (%2Ͻ?F;}K/<>V[$>/6?RY>GԢ8<}N>=ޫ<>x )I > 5>K=.U?ύ|A-=;; +ZQ0> p>AJrޫX>`>&տھ "Ͻ>T>($"rSHO<ս6&/8U Ƹe`={ F2H!l5aYG@t3'qR4Io˧₿{i7S _ L>`>b0&BA=E>(ȿ>tҾV>NJ> k/b)'t=|f>o\?%_gOa&=+I;BѾX?=rBIo>B_o9N>k~<dh u>>vy>$$оuXsj;ܼM1wyPr'_b,E> $*,Cx '#)E욀>C>>Qm_s*>>ȴ>z4Y[1> c6Rʿ#a:> >a> Ϣ'0Tž_|b*V= \>-D= Dǿ[!2^x=F,A1 SEй{ i([>.>T~8(́<>q^-7 ]NIlF: ľ [#Cl?;l"UGٛ Lj^WTF_B>n>1Ѕ=d>>ͳ?Mיt>Mg4M2(Vtnl3ض⽿er&vantR D}nq]Ѿ#V𿿙7kOM ;er}² >;V5]ܾg, 5YK~NFM¿Sӳ}?*(圿^jA>M(=g Ev:>:\>>S>2B>O>>L,>>6_棾b7*Gh8- H;'k)p'=C< LT*>}5||Jv>g=um>Lf e]pɟ?Bx>=fѿ=[>+pM><> ~Խ >ҿ1j1@>!>/#>Fv>WE1>bT־fMǞZ jCoW=]7὿X!D>l>L8췾)|>' ?SG% >1A+k>;뺍KT ;#?Y5pſ0?9{=xľ?)}c=h'=Ӷ)ZU?f>3! qF>=Y?};>N6 ;_-/`J?Ņ/>55zcY`?R>NаK4Q"ѯ?,V>3Sr$!Ut?$Ʃ=$SW?9V?r>4?;3Է>?<?z>RZ?o\)>=}?:?c^>?iw ;?> ?S?Fh=C?:N' =??$>}>6OM=̀cRʽCR>7#g^=GY%n¾AG>>?'ET~=ڽi/>TCX!= >P=޿C,ZuL>3>T\ҧ>W<'?+?&*ýH>?>Y>qA?K?:~!>>4?h0>?U#>]? !?zft࿋Q> X=n >׿V`8>8&>u ?!O _S;=A>y:8|Ⱥʁ<>cc>^?b@;e|Cr>OM˼K#>b5F΁gVWE2C5ZJ>Ex# \=W=Fo^R>>ϳtxH>>Z?gB߿B5ο7`Jmƿ }el{͚OT钾if>oo>i|~" \=t>|lIc/qTA5>Q ̼Ň!w>Os? ?Sa5zMY3mQ&YQ>:u>ond^=Gk>¶?M,Elr\c<(>&?m6 dh˾s>? \5a=ٞ?o?k=s(t B>&>*?a>~^>w#1Y}>#ͽH0 ߿l?48>Iv$4 ? xM>qA6,]?MCtVe>On?%[?<<=@-PE?d>=Pj_C{e0PWGƿ#pAOU޾JHs?WF0N!=I߿"`7 >+>V?h c('>q&a(? }2l'(=O;>90T# _,ؾ8>/%O'' uڽ3UfzSG6 G @klJa1?1{m> (9%׿k p@"j/ݩ<οr 0h3 >n޽ 1OeܿB K׽ވ߾QvE]6ҽQ= &sej>l@Ɋ{taE?m K2>\>j>P(?QIt>Ԁ=pM ?6Fq>$2ʿMcEk?5E>BA.jXOAıg:>^< H<꾾;?2@KǿA!O5l"=끿lg|> 9wm.O$yU>R-;s)0~|?Wj{B> /$оF; JE͔lh>.>QgTt>=r?N6*gKy>&??=,|?5Pی=p>:B?5K>)> Ƚf4Q >J9%: ҍͿ18 н޾4q.5s Caܾ6/u8}{>@>?=Fz%iǬ޽H "T&C}4J=L}[w.Py_D0?⿅0"Pƞ\<0$Vy=Or􃩿nJ0񹾙FJ0k˞T=\=?4Is2==pץ?Jgl=#O=jD?#n?>Qe@AHA81|3u^ƽP՚1C9gAa^ō׿Sޡ@)g>HEt+0zT=X>{3˾a& ʑtii^>qy裾$V= SeAqUa| ƽ]@($;׀qgi?  5icU>I?!U5?&?=Ѹi}¼>;2?33P-? oi?r=ݒ2KK=>iV;?qNӾiJJ>jh!I`Q=4#E~iaGk?>>y: ϘS> Հ/>HR}u\ņpH(>䴾aNf>oa?u;K*Wd>h|=mҾsD?Um>s^ >~HX8>R>j7x!% hk? ?o=&aú;>w?> J:KGܭ; 5?"?^>* +JO>,c( RvΘ>_9>>`/+)pr.ע>Th-˽7R>CM9 ))]%T4^ V>M# 簼P6wZ˾cN:տzSX 1S"?!J?>-R ?'@ ?P>Ƭ`>ю o?8غ >jk?ͯ?Q9u?T!=Z&?4?><)CȂA;??*<{" ]`l ?A?NU<ї=FP?\?=v=э??,= G6>& ,A$/>p6T˟Pq? 9?>u=M8md =?\>7>ՄLn}=HG?~#K>9>`RY4>_N>+ƾ4|1BZIf>y:>Foz@Q?Nۥ?>Vf P7(3@??LU>9x׾?j?u>xV<&|=0߾ڼ=+aް~o tk+ ƿϿ2@Y=/ ¿$$O_7=q{$x3H =NUeqd#=R?mZ)>) //?L?<>&,,m`>YJY@ߤ@?9lF>;FC> ο ^h>R.>A>~H/=p-"S3Xӿ'?NK>ٓ><52uy?KT>M>[&HT>R뾾b2{NM="G;?qH&:qվK?GǽSrtK>F+><țjo!#>Ul=?ZS?>E+?-d@Qi*sq?@_>1 0¾a5=)Pk_e=7?V>LQ>(K<޾1&CL Hݾݘg"h nu #cPy{Ho龽TФ:w-r=t7wKҾ@8>/><2LY5{CWCOj?D>2D?ڿ}v0½haZجf2jsdF$ 1=8D MXCVp$p=>9ؾίܽ yt9>Y]?'Kuu8_Y@y?rw`>!?Z2y@=z<6? ??fB^>AݾȰ><->-Ȃ:ͣ ܼ6 N=suCsY6]_?ݩ?aK7!`GgIxm3 p73>K>D>Q?;>m=>ѽW?̼oN=:+)>%9Buya>Y<>_ SQ2?u<3?jqa?UҞma?fè>_Jp=x]tpA4<{"K?{[>mx>.~=>'1 nM j-[.fž@-.:?>">f%9=c(>: >1>P$=}>>uyv3>Q뽢Ud f4o} j%L?^.?.jL׽g,5kw$Xlu~g(%J3>W,tR`r>yxd`?O@?H?[?7B0?h8?\7r?,?#ʬ?PY?BBB4*q>Z>Qν!>sa` =iϾ =N>躄>G?<ɗ7>8?#l>5?mQ/BBn: S&>a;vM4ж;3_={܃=#x .;ZqDоٝ=)z=)<{ > Ῐ14>e;ѽ>P 6 >_-=^Wf">>LnBBd y>́x =H1=XѿvWR<+f1棻غ>&>'IAo<>u>Y?>r>>+>_>#hq8O8,ؿN6Xd,Lk;<)hN>C=h>p >&Kpў>GgM='پ3>iBBBa溊;Z)*>6/׼9=񍬾l>8X^$u>1w=-h&:d4|zp>aR);iӮ>2~W5s2ľ>QPY޴ q>Aaq4'@v>H:mNMr> F.IpQϿ> _r*h:GԾ7 B>7f<0%,;a)>Yb8@u_>F_\0᾽)5` >D \!4v$d#Y=>˸/r6D=4Ird>^̿F7O< f8M>D{k5=sƿ>5^%9Wy5 >5h?>?3\mm=W*b?HA0s'! >ѩ> Y?Ld?$ ,yי{X>z (b>>?[bVn><2=i?EKZofc=t2B? >V?;3?0= .{>WFO?5 ?ߘ? J4#e`>N~=΅?%\`ؾ'>ͫ=F ?i^YC ?f @e>p >o/m?+O9><=,?`>uC= Ծ˷>ܺhP&=aR=m72?5 VA5T>0=?XT<=` h?Y>{ >?["^<>V.e?77u8?>pC?{?4 Jv>f^'J>#?}W#>VƵ!=K?}0{N:>:о˪"v!=Χ 4>>*?>n< = r?4?JN9<>0D|6>Xɬ?4^?Y?[ c]>D.?DٶZ`u! 6>U=?La{OO/<=Jfv?54Z`= 4?<\+GT =+?`5#?ð@p%>,<"U*?1`Gk%>2I >̒?|L80/X}Kku J h>{?ʿ&s@, cc>^5v&Y>"a?쯿?x+bA=qɽ???z@ۦ"wc? Z\?SbDeK'J>LMϗ$޾S=݊۽??J4CTʿO=7Bef2ſ7D>g?0$?2ҳZz= ?*]`4P>>?m4E" ͉>9?!0nw<ݾ?0'Em1><$?[<=i? u䤾IRҾG?&\mE=Pj?^:z6<>/?fbEW>>lsH pP>Ճb?L8P=>>Z1kV?$a?Y<]4=H4Lw>>[,ǿO\3@>WtҎ='=п=JEz?]ލv==U?J,>0=<?5&>v|l>r=3q?eV*ALソÍԙ?&])j$YS?Ⱦ\־2?(`bzfE_?j)qUSᄁ?'?>G1:־ÈD?TאN}~==|є}?V](V2[ >RnR8O>?&)h8\.>4?Dfњ-Zv=tG(?/zbK>s=XdE?a6g/y:>N<]?Wjrhbdrۼo=2Ӿ-3?k 51V>s?sܔ [.>֭q=3?e Y>ҽ/0?𽬈QH>T.=??Q&1$5=м{^9>hS?KoC?sސ4[=.'=;ՙGժ?X#ScZ cC-7?Gh\3,>S.e?t Ѹ):X> F=!?8ClEu/ =m?]4W`:FiϽ. ? fF?M#>=k?-"һ:>rܽDx?2@dB>ZMf;>T?HoFyG>&F=?)0x-?>a0t!A?ƿS>o$ qx!?ID ,M>R?d5₾*>" <|?@=WK> bR&モbT"+>R'ֽb>,}#|?ww~=5=KZ?Y?k6⼉V<ݤb?^#gS՝>>KY?`J> 9>[?u -7b>"2>>W8S?z' 2f>\g6?Yp,>u=٨ξ$_?g=U9 r?ǽVr=Z|g5(>沎i?EH?6甯?޹B?{Ӫ?&/hE'=۠ƚN?jo?[8>jj:m?jsl>>]U?|1@|p>sž p#?,mLh =Ѹ$8Te? $-dP?!!J?NT=> > t?EIV<)i=pC ?sbRR=x=۽ =?yd">> =ܮ?IJ\7=]A=::?a۰=l>Io*Q?|V.&Բ=sbc?i> J>%2@?#>F= E?v1^>O:%?,/`v>>?Stžt _=?gF !=܌oB?JD8$B>Ϣ>=l?xf>t;$ݾ]?Dγh͕_=`㾮.*3?}?W>׾>&N?>##r?ND%=ව>R)c 2+?K O>J>E=Ы?laث>i(>Uֽb?苠^>>L=^?>L1?(Jֿ >n>9?Qr2~sb=>D?bR?}C?06u=;꾜?O  .>!߾Ǵr?)=(:=.2v>^渾LP>=G,Q?I? f?d}?Ӏ,,J3CK='f?d~?\?wh>>z7r=]>MY>q>omH˿I?.o%~=ĝ9??Q!BHG,Q&?]@0)J+?0i FͽD"f?J*"$ha1J?C&ǀi˿4Jؿkg>u\A) v?4t+AD$H?Tf.<L{] ۭ>%o>7?Q ?/s`l=A >]?P?TᅬK$>-n=?E$?w ?b_=BȾE?q eSz&\=3> _?A+^?Z B0N p?$K3!>/ci?YYὊJWs?)ىa='Rs> 2 従Oƾˌ?[d;JA+=>b?1h?UC*1<.U>'&? \?6ѿ'(Y>&>{??G ρ3b9xV?E ??뼿"8u?Z?<:?.NEQ;>VmYY+@エ־3"?-jHV9j6>˫>M!?A5ӽ)V>>'-?a 7־7? ds Zн u>%QԵn=D;>C@9= |WK>rTYA1NJ4?77h1` >>`$?-E@9\̊K:?:# %iMZi?@0[.{Խ*=<*?Z:}>; %ȿ > O0> ր7>OT=i^LDM= >dB>$f)F'=$>+>$e =*:d>?>&1e^4ᾓ>D ? ? * վR>ń+?$>ٝ9UC澒^}5?(tx"c=O<?PIVS޾"?(?`Rrk\?Á t+¾&>!W@>%yҾ?3r?7f\>i><?-^}?Cx>1Dgq >2r>zB>|j>g>>+ 2(Jӗ1>Ӧ?i{>=2'N˒:>l>>\S&N"M=tC>n> B = e9>B>o>?>>.AfF*5Т Ȭ\XV*wj=ZW>7>>op]%6;̒,S?=+1] о;?e[ݑl^-z>xbT徫}c=5=?Lsy~Ó0j>QvWXkYY>bM >I3%#^>gn>L>iD>&C6>r*>_1=`W)6d#o=Uֽy[p7 6?XUXV;%e?+4T¾bRμǽ+?46eahHJ<޾P >ƴR Cn o>mb)JX^1e+>~ p\>=?cZ>t.>Cpզ)9>xyt=G,))g_>>Ld0'ɛ;ERI>$~J>FR>0j4++ >aG7>Y>)? >Yjd7>v >K?>̰[]d">W=> >f>\Y27_|9>>(?)M>~>1ºo>=]bsp/v>4Z8v\>>|?ym:(DCg>&6m}>`p G>ž >__>ST>/A[C >2d><>܅^>HaV\>D=>Ť>q=.>.=:>>V`_mXF>}>JB>m?]xW=%ĿgjOo 7=R* J'0w>]~?q^>%Ot?W0>Q%?v>phA?4Y0 >j1MQ5>Y6>T >X6k:{GG>| >?Ĺe>[O< c-<y3P=۪p>0ƿFIe`?OQa䛾>WUjQ8 ?K-ϾϔB>2Ё>0fr@mP с.,>|}+o>6p$ ԳĿ7=$Jׇj'>NM?=7@c;޾0:2^>.j=S@OsL*&e=3@F#Ѿ:%=Q+>Jؿi.4Թg>MfIS<1+<=">ۇ75H=8b\>⛿,r()-#7[>B*D+(N][,>wٿp]$N{><>?kW;?v>̧?m߇ Ŀ>G$>*I?K,ܽhmz>/E>p=zc?D$ppx><лo?65JM>k2mfZ0&nXmۘ>q|_?Z,AKl3JKu!>du``.*bw1= ?1ɾI^L?>,?`ͩrC>r.= =?ʿt\==eU="px {#> >oܿkFW(>ۂ03Q۾͗>S>?K5"}OJ>) p =>H g7 I>U]>)̣\=IA~ם)ދĺ4P?bJ6?-Z>V<ٞQ >߾n>NxtCrlIRg6Z33v>\ >14V=YyWx=3`X޾I=y&/Ov>7xmnrg` >v[!o$ z>[ƿNHo9}-!h53]Bk+U>?6)"M-͌Le<#iZ2*2>ya=ז$$[޾]y="E"#/ }cρrdm]< Iba> =9>pv_>ȣlۿ|!pHG>a顾P|̾X>͂VW{޾ž>ds\\>sT1'׀dnTY;=LߘY<'>hNR>ƾsqռIb6;> 9i=_i>)YbkL>]>?(оN>->!?=$%l_sX>~A?cI T"8E=㟙& >s=y7>*Cx>L=KR>nνK Ur>HT\1JZW{=J^ѵB a*=FW<r|=~Q9>wh;3 {W=ƾaR*%c>d>QG=M=D $yտMCG(> W!ؾO>?HmϾ<Rr]zJ;U;ȨXľ=<0-ZAh׾V>?>fV$ k,?`E?Zn#3ҿT? ?? A-$J>JC5?kM:xv?Z?Ws%8 73=> Cu=;ھSX_v,=SO -w{=,Pz@3|`L^ Nʿ"9?)?9T%+.=PgNmJ>ilEP `=Li/ Br6`wU=7,R;W)@c(;rZ%P\b-I ;qsv-ǿr.6f SmdL&?ݾzG$-KyS߾t!:gJwu;J0P]D/>E`B;[d>>>,l> ԿgJw녥>>W<>'Gؿ I5=uղk4x B bzнz9]>=^> >)=S>ٿA;.=G,RF(]l>",A抾~s"IG=ɘl \1ELy=-&lQOr p``>M=Խ=1?#Q℔>7=vAp;¬%`yJ>aP|s(<.G~fo=Σ=0j?GX=:>Mi >w>زd>x7:jo7&* hX<_c=g}!$˫6VIۻ\E[F{s)5PY!{C󀽪@X2 aؿ&B~>BF>3f?@I>K=E ؿX>b>mAt#B>,(Ծ/ 6 <[ܭ>L)=л]l&,=C۾!3>6b(=/4dXp<cn< H3@XPx? = ˿5?hiN>-XTξI!Sp#>}>W⿎0J9="Ǿx! 0i>$Ɇ>~=>l,T=`^=?B%9>egU=ʽ39~>UXDDO٩wӿ%A?f>xox`tG"Mbj^bHZOS=Z۾Y<2XdL2>vs?=󀼦C>~GX.>ύ>Q+>*s.>sHA!=գ'-I鼿?B=xv!uK:LEz~wW5K࿺#gm"h Lh+>~aIl%>CFT-aϽRc>E4޿=&cdSҾ+j qӀ=^ οZ[cC eE =0ExA+K,6\B,ʴ әAX+WTM(Ⱦ57LY+Fo3zg>>H>wb$B?$>q>a_W=P<\Y,=Yݾ@aA<澄Ѿwj:P}Ht`ŜZalŽ׿3"l=)J<{?$+ǿ8e>vv! eW Ro.fࣵ>B >>Ph?J>>K/f>Կ:<ؼ;FhÿΡt>N>=>5{Z㬣B$c$[$Օ>,=kп 9v>޽`H{@">(R=z[Hd$=+?sT=y◞?Iϕ>.25K$@?HRȧ>ZY"VXaS߿kO?S?{>?>Ï?:?sb>D?m>F#>?0hܽR>ň>EN>k>+w2?:8>Qv??W-=r?w}>?p?/>ڸ?$E=G>b,?- ?Հ y>.> ?*d'9ZT;=>>:>>m=#>FZ׿$I=+>izp. ? ?~=Kƨϯ aVƂc_pҀcW=o=+,>>@_;9ھ<G1v*2߿ؙx>b?Z髽&K࿵녾sm>z?,3J _) V!>l?>?!;*~ɗEU?J?>пhl>3-?x=)BN<7s>Ԥ Xl g>n]-h~(wO>cΧ?)O};'Ȃ7z>Mf?IICp .%?P?.M> ⿹3¿ ?'? >B>*,>v7g`xQ?X1s>߃-$qg}c>׶?:?>NR@ ns.t< =o-⾇dc=Q=žkRLgy>6{JjZk6^>aRhQN>^KExվ)tl8@٥>V⽡ɴaU>j=ӊ¾Կ:}?}/>N:@Nm]w2<=Sޤ)B@$ɟýMMƿ'?iQC=:d>wA5<;ſoIϿdeǿoi!o> .:;Yտ:_=U;v/CB=1XX.ܿH7J><꾽hb9^:bz>'ٙſ\xtf9=^_>!O]~s>6b$D=鎿9;>~_Z6R$U~y=$}+k,ˡ{)>ˊ˿*GjD܃&==܌[4`~?4 >/5辁T ̾CA><37.=[(n~6<ھ]a>r1ƿJ\͕w30@~#>)|ĿYm+d1@^yd>/9N F2<紿)ٲ6??eOE>>K9 u꾒1jo]<>.KU<ۇu[~=?9>m7!y}4L6 ^>Ŀ#KdG16=69U?RQ?=tV+=F=#?\Ƥ^dF> m.a"o|=hrquNh@9=[_H替P?(Z=;q~Ww??`w=x%( nP~ >+>f)?o:;z?;e={l7aPv1e,(`<&>>4ph8:>*9^Z!T<澙I7xо(]^ * y>М?oz=uѽ] 漾[>9ڼL "B`/X>=o#!w)?d˽H_3쾜ր)`w]>ھϘR>r< ??|>2:&u/2??Y>Rb Zfc#<*R-0„1=CU )!c\<}=ڽM8,QPɌ4Ҿu6/khI?*tJ=.ܿޱ8g`q_мL8.hao{=pi龖n>tu=|s}}#>à=0a?N>ɓ=D?X!=<dM+g 0o?V2?7> y?qDF>},{7<s]ρ?ض?=~&l{G? V?=uARԽ&g=@ m3飱 |l >ϴ?P_aP[3>?i)b>Z= =mPeJ<{$=;}^=g??=jQX‡=?':?8>CR8Gq$p>Iʟ6;X{ 4>47<2=UT gZ ?b=>v:>f9>Ve~> Nb??W>?>m=?9? >)-+_W>B?]> N>?A[H˼0 WJ440O.>"Ç<tտϿ.z*?>k>XK!Ӣho>c 欽 l?kX>>Ĭ.}=>۾:% KFeھ4CBx$@dQҿs < <M}*ؽmR*&~ؿ%)&=?9?1+?q$=\?w`?%?>)=??A>Dz׾gp؈ɆDy.bl+fQpɾ̣[20M 0$fZe쾸*xkw4r.\񕔽žʿ>J}=X?2?~V6>є[cp Wk>_=ݾ>}a@Pũ=!þTYyh Kcy>!ER9u=N@ `&O Axd6?}5>T7>Vte{} LB> !|D=G=ʗ?+?GGR>4a *=WS=!6ej'[ken>=!/J&B(>Iu񷿿>Ͼ5п3/>>f卛|uzz> ??=+q2=jT ?a? 23W??(?);Gdk??m?Hw> 辘ʂ(2.?U>%эDn]N&jHsKW&J0SҦѝ?$1>GN>7 '<>M⾒`NR=CL=]2>cY=&]~LDϿ3W*Z=#B?v>?w$' ⿾>~> X= >q45>"x6׽Icsu?Dhs?5="K?+0 0Y>]Xjy>}?v?']?H8Eaǂ l…=aND4>E41#r<_,|@Bz$DM=3u!Ua:c>FǾ RixUa8^[?k?O?a n6"?Vy^!u=E4EOzpMbiWUa }Z&c?L4l%4T)?s>M?Y:P)?olo?_1>fe#>1w>N>X>۵>k>>";>cQ?e6b?>;>gU? ;?*(5>Y 6>YmAP>MsRٌD2=%U&s>hֿ w>@<[3_ƿlHHp:7L15?3>y>W= x?p??`?AQP??+02?/2?<@1>qX>`>?@)\? ? $?ko?KBBK 2,;uJ=s#=\Tm@>>+=9>Kҷ b=2 ]@؉=onisRMa_=L=/@=i> *j\_Y>T~V4><$>*Xq>)ËBBBBBd)i羊b>r0=?/9w&e2>Y>~?1G?B>Ⱦq>: ?Kp> N>Qu0>|h#*Fd=ٔ[B_>Nd,` pfR>HYb@>ՕT<+Dk!<=_Nr4כ\\>p.=?62qwdŗnF>3 (˼lDܱ=aKInB#Ct=8MA\8Bqg#ŀ= V>ݭ,Lffe>L\>y?nL&཯k㾴Bc=D}'T'-s>@L`ݥA~-0>hK' T:?;>] پ"xK'sM>'0 8B0Օ=ϔ%1"6۾>:H ZCJ>%G2ˁ=P!u>$Z4XZ=ľ\>>>}=.|н?!Sپ 84>5a=-˾ꨨ>g >>f޽Ҋ羱 5s>"ǾQ+>T;s!>J,=]7>>+~+RH?#p>?j(r:j?H>:?iyQ*j/6>>>1G?V3]~0漞yh>BK4!?q)`>1zh?n8뾌at>=T/b?F *䊾ek=QNU>uB>({,=8 Q># [?:3<?1?FZE>6?^/XmacEL>UVL')C>=@!?Qſ) ΈeT>5ýf?P㾋,> h.gwt=2 ?2R%C6>a'?*?U8ɵؾ|`>I+=?(R䄼zzñ? >`?{߷> >>?Bp? >?d B?\UhR}%>F>]?o"㲀v^>6 >J?uONvX>y>.=Ĺ?P#1o@j=(w/urX?j*t<}?uGa=\=bLI? (=L5=W?/Peyӽ^<+?N?0,F=Aqa=GpZ>>[?Q~h6H1=?' L<>>m;?=0YL!ニn>]Ūg!=Bn#?&pƌ:*=d/?+*9R)ِ;>#}lQy(,o/?HZ9@>c>$?DSpǠϳ? }>I?v0پ? >?~oo=νv?h0V=8?>>V?o O$[X%j#>k#K=hA)?(Ԍ5&{>-ѼR?F 901:ߐ>(5?H@ )(4&%H>uG-(n&LsP> 9Ϊ/I>O[Zо0b'Z>#A~7=4׿/OQdxM?sM{>HwhPy f>>ཌྷY?BY`|u>0`5*:=Bnh>na Z>kE(\>iӾ6= ?H? ?= ~? ]$O*lxVcA?:>aN=zl?{I{Y4ĤV>or?-Ԝn< !K>F?(l?Ge h㳿X>Xifw-?_ VѾv >d8>Q7?1ӫ>`? V㾝˼;K?#ZCX?V>b~+=+/>Z!߰%{P5z>-:=k߾ń?A$Ynz#]>1j_b(?.UvCh0<K0s??ӢyґDxȾ￾'>˪YM.-? W^Zħ8N?a?"C̴i D? $ʡ4=Zq S]?,#-鸿[>##'$>' `;=';?K@w=$?T ;?3D ? >`X >|bٳ?ye,! >cyt s&?w(?|8pJ! ZX="ƿ(FZ=r=0Aٟ{F>^x>?t7"2 >a !?{9\V>0\z:¾mꉿޔ?Tdc>(Խ'?`7ӁHҔe`0>S/E?ҀF=̊>J˼?=C>/c=/ Et]>`^_? gQ>˿aWXC9hM>% = dE~8ҕ̾=Ca?I.;@>\>T>>/,U>~K=1~#}ULfI af1>A[>;NU?0=0M?.Q>!l?aU >k>=? }??8w?Mj6ѥvK4WIa|?! 1 ѿ(tuYH=aT:侩(gX> 8̕Jo;ѻ>ysTJaJ ,=!Ⱦ?IfO ϻ`Mֿ]gߠӉ=i X]o">jEP?:*N ?j8:?dXA:?*vהJl]8+i#-=3fC >9,I?(س=+|?3<>: >?)=C澑O?_^xLq:&=hȬ9Q?#C`]n=\d ?5cElfg qvMӿnܐ>dJ[S "KX>$046B=6mYW&>v*X&P{`!/0Q?NȾG>r=#?G#b=ț?v#KpHaqM|?=F=c?j8C&>G^?ɰ>v>Mw-?>[>ɾ9*?|rO>\>> 7?7TÕx{gvԿ^9?@K>4Ƥ><|Rlv?D =74Im .?34>=ns?D\>{p?X,>%>GRe?zz? \\|N xQ?kkdtvZ=>(K?L}= H 8?4l=h>uC?x\=R;6>'H?tMx7=>L5?m+=T~>V?kr?*"=l>/j?5ʬ5x>@sy?ZЗvINn>;@%TT?}l=F0?%z >P=S?AQ>om>.?/ߏ0\J`>!?x(>|qN ?H<>4?I_ؑE R?V?X@ޏ[m@? ?'9?\#$Q?V_t>?ݜ1 ſ ?B2>6?Ҫ"?m>BF5>?::>4/i?2m#!?Qx?ٵۿ*?Ps>CF?ZMb?v9??+?c>&|[?3o?V;?'2-$?/?vg?g?qt>X8~>G?Z?>P>GüS?o?/@>Q ?O?q>?ՈҾ?RKh=V7z #!>0#ؐ>U; \%>p>~F>b_$"X?m>,)Z?;4VfT?g ~$=H0bv?1V}q=?Dw,R%]>!yF,?A_'3=׹ྦྷ1ӈ? A// y>Ԇ?Hf?_FrPPIJྺ־>͠@7$ Sl>]pC,=YԲ>VzVBнϩ;=jH(=;X5e>;C?$>}j#γW= I>=E_3V >u? i>[}*WB_??a!?ji!?>;?ջ?9Br&t _? B?@?)X+ Z=;e?UC704tyRn޾>bX# ;a9ҧ>w+62>=y0Q F@!#>^Ԅ!<3/>g>n^?`!O<'#e >*=?g!ϯuͽ7>z= VPA#??b>,[Ѿi> r+>>ma?T> >pze{*ݓ>?q@>4m=DT *u>̚>>y MG+or`>=?_1>*\,UBh%>kvNP&ؾ>'9n/NݾYY˾>7m85-2T:㤾ob?'tlP}O{1?")<,pm I{?6H>3-;>r3>nʺ>>f^vnv >Uqm=!BO >r6Έ@=u\}h@=a*ˆ݁Z]NӽnQGֿ:s?e>>^LGl4?`?-5Jw)? @?U>">uHg[o".#>']c@Ŀzg%*>wҢ>+ >u>*{vF">Kܾ39iXS?}M&?=־jD>T~`DE=~>J;Zo-^vF<#9=_뿐F(#><>o~>ol?(>YYqg>s S>U?4>&K3f>D?==y]|=cB]ؙ>%D\޾> ='?X9>ڥ>e/W#kN>C=ULsHԿjpL5>D>O?d[=V M=:!>F?^&YZu%>ףw>M>?P -? {lu=Th>t?G.? X.I,`=>?,>Ou.={<>L> -N?I`>7$txM1>N">v?>: pL>akU>8?+c7VFI>N>?a|:Qyi@>D?U=  ;>-mF>׿(H>k"AmF?&?^+?2>QFHp?C?wz?@?N|F*zBz:W.>rnDMD7ă E? O6X=Ͼ/>b5n֖Y>,s,>gC">R~"> :q>SϿ.V6A%>&r;>>O"?о;np>?ƹpjS0@[@Ѿ$>P5'5eec=0qd+>U>Ŀ&7>p=A+>﷾>S?-<;`>(C>RH?lZ?u\@O> Y=!?T\*;E39i"-g 뭼P=in(>?t'#>>*j@> :%| ě$?v6Mׇg![>YCsV؟@>CqTw^SH(8 =$<x?'¿ 8;R=i2;?)vO\A=~C<>?W$FP,<> >Q?9,(ھ>wDG>L\꿛c$WdsE|B=;23Y>ލ/׽ɾnw>we}p=!u*h;?A5 }E"~.[B|>g,RS" m>d;>'i>=Ђ=3:><ej?6>_>!&?o<(>#>lN?4Ycޢ80>/¿^ŏx@tb>ܿ*{> 7C><&].0lK6=ƍemg53Z=Z:?"sbb#.Xf>g?H~о)Y=őƤ>kA}=H?XU$@>] j๿8&$aj2Q=B\:=뽔>ѥEϽkiɶ=zڈ^V=2>Iwm !⾝F <N"Ǜ#$)[Jqa(>jMK)'>{x{i>= d=]>~a?M4>[=^p>>>_>1ʾ>`n>3H|Ʀ>Z M<>;4.>]g8=J?lX`7;0ĪT?@[/$_uh ?#({:ƊvmQ>_/ +B䚾^N>胺>1r^h>s!q =C*f>݀^t*K=>g?QĽL%O裾U>Lma@YR?  ? \Ƙ?-*Y>cc*ԦXM4?>\>U (5M\>c\>1a:> c=wdԙ|i;E?tO=f&p?ᄃW ~68Ow= ?+ᾋϳh=_Fz>:uTL64:>ۉ׿ +ieNP>;k+> s?'mؾ̽ӽ>!H0Qb<P>71X`gq #S>?EWV>+x +{q<= yPc(>}=E6>]|f#Eۑ.Bu> zUʟyغ= >d|Y {rܘc= >׊WFmH27>ڷV?w=d"̮"%>N{h #'$>g"[$Iɂۈf=ċ!%Oホ,Y=.-#= n>YUjHi>*>Y >Лؿ,e龈x1=<4>0]v)=M=?H>'j_7Ս=X> ]!< Al,gTtUe{{>oQ ^vvXj>'/a=q"#ͿH>iAZ o=e.>R)Z^_y:Iþ>=>$N{;$x&ļ}Z <^h>6[MQɾg𪾖`>2ngk>~~ {rkпp!53$WGϾ0$=Mrn9hEun Q,=I,yOl:fH<!$ĿW!v-`Q.ATѿv)RH)!=>!q@yտ+@ǽH+`|nQOU&~?+$<w=ſFvj)<^վHі=Z#84r˧q"J:RaYXw<:8>e\پ ~Z A;GrGE!4>@w!wտ!,M~̼i)$FcN>K䊾pGC={Y!X$+c򶽣uJﳿx8םϿw>fm7>ſZ$2쳾#<=P;HV =?a?aYm<([>~Q˴4,避S5 0wÃR[)᜾ 0_!qIs/>y5pcu 6c=[BB Ҿ,/oj>οuX>m&Q9J #=a!ſC ĹQ(7=P B9BlDBm־U翢9SI{;2*m=CfmH>fcͧ =¾ھ[d6ڼz9\B L[n=떾ƒ$dE `;=x˿%ϾD;cJh{2=u1kQ %J>5/=(9}[[>Ո >`0QLw?0 K>NDB*H3*wP>0mN*ԽݵROƾq031 r?0a>$>2=ž9?ZͿ>;> }=hP ·nA=Zd\ ĕ@LѸdaa G0+1:`WſvϘ캞OLu;?!O:-OXCR`e V<hE举>C5v{_>>%~>^>Vӷ=B[V2W26CvO=NY^$#qW=l̊?!'M>B)c^Xrtr>RUm= Ӫ=lr(2ʽ^ɿ6QC8ֽ|>u>3>Ӈ5)=4=.,ؾ<|c;;?>QfZ>} #&o=q|#QKZ{#>?ȸ>?Q13w k=FE>OII==>璾CC>>~d,=q&>c? }==M#6O6'f00U" Xf:LeO0?@enROHW\>> z};qG>C>Y^a{t"1ņڿ0ſo:E'PT=OSK=w>/={a5d9 %a?`$=3NH `&a>?t;A60 [>~Ϋ>85 q6e~>ٲѠIk/~ZIfh0T $ѿݿIUVmn7A>'rIAe!,<#[`ᾍ&G U>*n3=_jL=Xʿ;rq>((ǨѦ@׸oڀ(=e + =Kɾx[d#D>Ͼ"Rg=l87z>'4 _jj=u7ʷSA(Nj)̼HZ=]G(1}@ݿO&X'CBSm*r=$;_[=,v)àl7C>@ӳ@=g:6HhPx>q~n=|o4&CVھwWZll3 `QAL¾4>>m=A> *ta=4K+ qm6;>=Rd;4{%X? y>}_-^W6?SH|>$k=Ѿ<=uվ!?!>?C_?@`;ņ?d~>j= >+> d>j G>#~>AG >t ݾn&>m> FH_=9>U?$73>xU~=ɓ{>BȊ =p7>tɾ c;&YPz>"&"1>i^{Bei=A=>洅 >50M=>;i?ɾ޿?K=>:?(&ҪY=y[u>)?98JbΩ0=2>6?lݵ߾j .C2v>G>Uy>冾c< 6E=i>? #i8.>dpB7ÿL]Cː>< >N{E>=N>oǤ>-ý=P-b>儐? w?7X> apz?HI=eZ>a?ZI =ͅ >7Ƚ,>ZWd>+o:TgyJ>su?@Xyz彫\>p>׾Ts@b >ӑ>[LH= =>f{͒2 >>o?e9?OG(>x07>g>H Կi|l>'=t?"hR=N~>HR>{5?k )C?6>w!O>h??\.}FJgQ>hn5+=/?y>)# Ŀ>/Ć ;>&]}u2>X?;?o>)Ϛ/Y$*Jy>(;_>̿"`_=1a;)W:A!ǎ:+Z\տ"uwV>Sͽ#}lӞ>P0Y>q.C>-.ؽ?uHKU=w.<ξWCiEԄIh?+X8!P>u;|<)mL W?>ra%"`q">O8J?)krIA0ƾ߽?RfA5>q)"j  @2>Σ8z3?]P\>I >_]>pY&tKj+n=?Hg8|i`>/[=D=B/8ν]>5)Wu:>S}c= >Oy5bוp*N>?b?=xOQe>]>0JqxfR5r{| kD_v!} =Er= AȾ迫5sKm^ EBDޯ%͂ ؾ!><=P/֟IY#?M>L7>w_\[>>>]w>+]>l}> v}|xL2>g>)x& m>\=ߊO.ep=>گy]FwֶC=7/w?e?ʠ>QYϼ> ?k?;d?S^g?/O?>2k;q~o???O>ps\>+ǽ%9u ]O }7=??:?>tz}K?`?>rO 6.?3j?z>/TT~>B<-d'`#n>=bc _PA  6):W+@p>k xX6>7޾V+( .$Js=X>厽j=k>c)=Ms>ֽl>]r6>}kJ@;?2_t?t>H>=ύq?dR?q>G5 P=?5g?u>tg=SC? E$?^N>k N1=H{>ʕ?zG t>E=T˟<,u\t~=侈>>Q?+>2;'/=C]z`t[->d ӽx}=>@Grt\T^,?\->1>!=~=/D?%=6G?/ >O":=o#J>=[%>gǾ*2=d+>(F>>~[]=?"z?>[,>?v?A5=&^?FU7ξ JG;꾩/q==NJ=r;>#BwK:1@T=>+ރ-TڽG|ė.;i-V>9'Ŭ=f -A_rɾ?>o*>cA*key>UC=~=AcR>-G?0?>DT\=蛕?t?{>"j6G<>h?g%,4> J?Sc?v>H.H=.A?:?=ڭ x@㢾=L`ݾ뾃rgzBiύ?Us>6]>[ebZ1 ʒp-% ,q VXD@7G(Ǿ0i<)6ؾLv2O??/?4vKR1r=] m?NO?>gTE&>y_$\ + z>P o>*k4i A][=?\?%?[[&n"?x? r2= ?>}>ѿoC>J8?I>E =m#VjHs?]j?>ƙh 0־j>SLXV ]xŭp"X_[q Kr|?\maxy=>O=l?[?=\>DY+!K?*\?|M>)@,9dL?:?>IRn`>]\18ZO>5L{R` !1 A1vP5'QXE0k OJjK边O/p@O<>&th>)%Ơ;I?LȬ>m=؄Ao?6u?= 9=yh΅4?Ywϒ>a_Ě>4Ҿ*m/nz>dU"ceM/#?i.?}>H+?~p8?=)?q*>i !;>?a?u>@Gs=Iؾ38;MQ=1oֿI᏿NV& kVX=Ƙ?3s~=S=7HoQR*??5?M_#wo-L#{n=4a_߇>- Jm7>z::?#S9!>Z¾w`=V?>>YpTyd?˜?NY?R<@v{𦾒i VԾ{6 ,Nb\澾Qn/ VgھȾ@nMD<+0P1F;[H=7?fI> >U_z}( n?TF񡺿 6ʿ xN7=<?x4=ް>KQ0k 9%Z/K@蜀8x/$<dҳ\ D+y :޿7DӼ?4>?8̿w9S\=}?9^I>|I=?q*R>p>[ ۾Y3 |Ŀ'¾a ׿#Z= ܿ BQ;='nL8=A5nξC-N==KUi=cRn[>M>xA>si!Yx>r>=%>6SHY=3W,ovp8 TL=оsݼO"KC=۾䆾;vt2q?}?e&?,sm?j^?/jE?Ms8"?wD,lZ?h23?o&|[>%>>D?S?%Tؕ>8c!UP Q@=A1>p>U> ;G>et|4n+,bFJP!B ?DVпa=v.b>9 %ɚ -=R>1xğ!n柌~=1k@>#=S֕>rA>u>k3>?=J>|?F7&??3?M)$?uq?E 3=F;n Ӏi8Ri=+(g>D龀2+=˾@Pe=vRu>#}?Bm&A;j9<˽ >y},\>.=?l8+{=!$,R>}J>M!>=ND\>%!|?c1RN>V>?8$/"aOt>>8??UP#w=I>Ea#eղ"ѿ<'[=:C>G*? ?*k?!G =;:K=NbSm>@5UTj< >>o]h." d"N߾^[>'/nUOG2>w7TPB+,^>p(T29EqCɾt>9:Fwo>sOo%[;ST<^>.^G9G>j5P\??%j@;a[+5+>~|> |?W9??>k=a? %4۹?u=8۾ ? ~U0r=ҝǾ"> =Ğ=*Ҿ(:"ez'(>Aٿ/27Y>ćUc8O?r">K?x¶jj>I;:=q6?'bѾ' Ľ!i>D0b>~>_-7?gd@F=TfF?w{p<O>;{(5>C>X?|a1+ j<>}<?4?Y*N? ᅠ!>->Ź?eBׄ1F>Q*7?%s|3*PM>=3?;v g8ǼI>~>县 .9Cq;?"%1z.ēfV>C=ϗh?JտHŰ>^;4?>@o=QԾVP>w#'?숴ʢol>7>?|8>" < ?*tBd=|[J?#}RpmMƠ)?~,e L=uZXSC#~m>BxЃK:;ϧm>S&?i/H@*Ari>>hXk!ĺ RB?Vs q޾l?i(t?}A?|>? ۵U}7ap(4T= ?=Rњ>Gӄ@Y>W\>=;&"=j?*|Q>BE"=w*q =˛\?.PE>Uq?&=c.,>$ y^<>RՕ49>->Z?? jо?ozǟ>Rx\>Kd:=q>AN>Pr?jTF:V87? \K<[B>⾼>AW@0N-#?;ΩE^>>%Y[?B?=??OS;]yk}YU># <`\>V R>B;y\Aֽ+0㵿"?!C>?CDT >=*?c6 >V?6p43݌>=a?s p^/Pib?>;?p]FA V pbS>)QrP 2cE>k>)=;GF98>*1Ci2Q?UE?: `?I&&#`=` ?Qէ4xھW=ꅽ33?]R)J(5>؋T \X;]u>m>o?P>8pD?} dȹ<:_X=0^JcVO۾kU?'@9?a? ;=E?L٘xЁIW;v>&zXꩾ;IKϿQDNH~uALJ>P޽? Md?!F^7e>bմF(> >J=ͽ2D=ЍՌ l>>?@ϝ8̎FܿC>UU?EDXV=x%?f.<(}Rs8>v=Б?0я*S>fȒ%?$ *?5' 4?>>sq?lHj 5?Dn?V? $W >^0> %Y=ݼNSy>)I0MپK<=i?s@U=};G鿌=;i?pLJxF`;濉P]_1)\žfw>qD=h< {v? >O?#ykB>D>UK?l v۶=v% a|f>s=(ؿ\rN>?QY >(8tMq>>WEQ¡> ΰuF'>ڿ>=򄝿 {lg>Y1Y?oc?? i?7HXh?˥k+?=?n64̳P>=.?=*|Z="( ɧz?J%zl6w%'8?(; }K]`>KWw@&̽Yq?GJ;X>=t?HIr޾!7m5h:=BfW7ٽ`򾏭*?BZln;<ǂ /O?Z@ ;=w;]F?dJ;qÿ"=.?\`憽k?:QL?>`-=žS?zi{\>>A;t= b=?xY! >T;.[?h(>_UV?VuVY>{B=D#x?ve s0>,29"T?ighO: =w=>rs,?IR>Fs?>ǽP? gP.>>sp?gxG(= ɾ?rNҀAHϾ0>v4?E.==Jᾀ:?^gPMS¼fA?K3X{;K܌ ?4j , = >_W\=?j]H7>꽹~?)to齝=cwt%?_dy@>ؼw\??Vl_r;'>R^?b=Dc=v?{W,K>j߼5j?bNpgP|>s;=?0 9>=? gF&V>J v?__Ð >y=؊?L?l>5 ?!ڥH >cy M:K? k>K_?q;U3>]Р?&w??Y>X z:?KD5;a?*??2˾E7#Y l?I0bE꯿.?ٌs駾Qʿ3y>8Օ{ IϿ ?RȖ K~>ʙnC$>̗J8I#s%8?Ou?j"=^꽺.?d D@$wc$>O"?av>qd>B)=/2??+c.>h>W+?3:1.?F@Ho6i<;iѴx?Yj8b#}(>>Tq% 9?Ƶ?P[NY,>,L~>I? ރNsh=d?gp0WP轍J4jH>9 l%vGNJB>7Ӡ= Y;#>EpsX=4#>r9ŀ=v'9O{cB=%JZ˽$>TY ?YH>y% k?=,!.4۾֩?۵֎==>ʾ O>X6=TqLt?jl l?-=n]?NM4t3?~5?r?l=.8Lw?7`?H?Jz_-k;z7i>+?-?EPk1HԾS?*?a?aS7NRf4 N8>vPRnS?; 6Q\˾޳<E~$?Ca5Pxľ?p6M8gJWY>!6x& L5Q׾HIp>?M>6=00LR,վ>:>ۑI>pq8zWd>: W0?)v?h?#N#E:>}?!>2Y +=->7=9H.H=2>> >@Ҁ.caþ4cLI77St+D<L+n>^8>Hw>ŸZ=DE?R9??*Io N񾾄Ͻ*~?% @b(>5< >[h#T>hc>z >eet>/>½?&A?5><_D> )}>ɎF4U%#ZӾ疾>փ[K:}厾>PLBQvޥ;V+.^?@GsPCn!ٽh#'$?)xeO>^<3?8Jr(?%?>ym >㻄i=n3Ks=2@[<ʲ8<ܩс> JBš: ˛>ei+?zh>RM=I>ZW?>ME l>tAP>i@M>m 1k>w?t??V>>T?5/depBK>LA>Po&?rdU!4R¾#e'H>/SѾkj/y>GW8K^5P>jX}E!A <~N8Y?5T擽>W=;?C n=vV-ؿ>Z>g>'_%_ql@>{5*~=>:Q==9>>r?b?0nJ"H~a>K?ZG?>!>^x F^ʼ^>EBJꅾ0,Ծf$cA>אxC_ t2Y>,,x=M>>w>텿 ݿ1>l> k>9G΅X=ĩ>J>B'g M>ÙgeA>z37>2]?_D?+knR=>W?Y?!Hdc?C;?> RAGh>B>?u8h-I==Cք?CW<:[杮=*Ӧ<>']W[39Kм/vK:iԕgן>R9lGgQм>WIxP){>)Cп`cGrm>X-53PCxa>د=Ʋ?,>[j>=d?>q*hI>@lo#F>9+ü^Ŀ% >>ɂ?P?dȊ >0o9sT>>?`[8Sg0>98>w?1?)> 1U5Ea=;+?8mPY@>X U4RDVY>bNg<#י/>>:=>'Ľt^ >N> 06Pv=R`=ν1n$ > բ>R=e@3<\Q2ӻ<ΎE;Kz%AI8>aי;!b0>2v~XA fFE 1>\O^-z`@v=Cݿ .z6]ls= 10>a [a]j>'̾=Ui5xiF =<:C>V-GG?~9dDժ3q?،CG^Ⱦe>BYGjJU#?r>)X0ſ ||;1ls&>pIA=_m({ K>l|RsՍ޿kɊ> (=p^Q1Te8g&R]Z⽼8»žp?ɽ'׎(:]KǠs)>|:Hq[>>/Ӿ0Pߨ>$KoIY>*>?eE5>r?+udH8a>.۽ϣ> AvGV e=C:S?:&>%n2tL z=ѯ $>A o+>;.i54kh;<޻w#O@h"X^N)2>>?r.?Q+A5'V^p>O9ҿKyQ6>x=G?^[=ƽU;>> ؾ=zBd~>g>=f> ??.{XO>0bͼG8ّ>$S?&E?µX7,>%?R?>8.}8 ,?,>jʾɂ_p]xվbn=ـ=3m>sTDYl(YBN{>*lv>,ཪ:|>|I> ]>*C5$ٿ7þS>vde>'*)yd>ωlGL>F>"ژ?'ñV=>qG˴l9l/͐>?p= ^H&5\< p>5&WQSQ~>)φ'"jJB>%Lfjg֖=p&Tо N߻.'\)V> Vs'ڂվjY>q?"uc>9[xM׾4=|Xi={տ\9JoDȾXZy=3\pupr=̺RڷV>-WA.cCݿ+:gU2&;+E>?޿db6ӿ/>=h?E:@J3x8?;u?N6Ҁ$a>? 2-t L m>?0(M< m=3D>kKP8>,vK%FIK^D=& |F/\sDÿnꚾ`>vs?>JV?=K~N&DGW=%ЊՈ$hCzS~A!qHv>Jm>Nƾjr>5>;ԍb8ڽH <]> / tm>2l*9A"q=ý;j3I<%pSH> +g=0.%ϾO>DǰI4c"h ?6'c=-Q-UibvR> ϿF2 U|twu7-=mn1/j2>֏m>?E̿>1xF>>Ee>eb |4sV^TT>?1׌|_x4 l>VTP=>Mo+06>Ek>Gn>e#[-1;([8<> ҩ=RN=zcT3YO3_c|Կ&ʼlґ$bK >׿#}޿2n8R|!=8/\)>3ϳ?1"&U=](.OMj\?)-Eɰ=q/24eO:(^оS32$72>Xv? O>`?=ۿ46! vj=-8>,0N[dK"%t$sKϾc^E==Wm>@%?v* =uEq A'/wb>z6bUN{_dN>=)Wsa{7?XPj> DK򲿼Z>DxKCپܽ 5l{>R&ľ[A}%m==ӿCh8]e>c4;U7L*R P6Y>8ؿ"۾HPE>ӿ(ؾ%I=⬸<NR~P&^S" ?UXua̸?AF>q2RN `r">5T=M=o*?̟Zh??ޔT>U.|ݿca"NY# m>#=Z>g-辷ʾ-*龠 XT>o۾ Z!3AڹGCkuX>MNž'E"Ђ?h¿>쾝1w~?;>F>q??}dO3>E> V>C?c{>rK=>?}> >G?'"*??>Ӫ>ˤ/?1FN.Y?hg>[>g?]̾Pr=.yj>*'#?hH>o>8?T?>h>j@?+X{W?b<,>u>G>Uz>5a$?3m>`>? 4%)ږ A-> )%[oѿ2f=HSývIԿdc'R/TL(>Ͽ2J3߿b0N>S'"w>v(>Y^>i?V ? ?D{W=4>UVB>4?@4+?>ԽX.Rx>Y?$g'?_>Mv~Ͽ r%S>ڿU:/}FV&q>JK$÷<潳>Ɉ,F'Q>?,f/Կ 6>^,CNӾ5,>#!N?B?l>o[>>拉?+Z=#<Ȑ ?z>?2=Ⱦ! >\d> ?ǽ9FK?>>?",ʴ;I?~I<>K1>&پ$AO< >%~g>'r?c =YM>I|9?x>O@q#߿F?};>Lh4Lp?nt>?7iBci?v'>TѾ뢿7 ,>1Q >CwAt!>^;ALf?2Y4:)T>2E On7lnNG[`t=x?5%Z{տIxP>-S?O5@[=I>K8> E! ?le>'Ó:wo?XXab>-S=ɉ 7?pfR>%c,!?'b>;V>Wi>:vG?e^>7>Li=S@)[ba9>w!'>}(1Ͽ)̿-dQ= ] VKfuy)6ƽ>$]%-Ҟ%%̦D>ZZG?`j P!cRT>LV?^w 5U&GG 3?$)KUNX>o=SaV?-e"=>,8>61/'?IN/4>V=>b=*0se{>{9>F?>ܚ?==o>:Z{ R'\ #`齫3U>%Q8ۿz[_o*I= 6=)f+Zi8n#>X@?? # ࿾cO>nޘ[8?罽m(>F)6>?( Ur>NU? IퟐavLGsE=]5e?Ht2BƈH}̾> ?=᜝c>>sd>H>"k)_@>WR $~;=z57>.ü?26ʏ\EBK>a>>bN<"lV>5O>U^=e3p/`= w'wԠj1̖>x;kؗ ʽs>^b&'ȟKjja>{Qվ7E|b>;Cޭ<辱Yrg>9*=P>$]Iy>>4v\1Yc~>Tm>)2+ϒX>D a>KF5=.Z7]St=>l>B?"=1''`n>ˍ>/y)¿ ?^W>ͶFE-`;&O<>&a[>&Q>zľlv!0=ZW? d?#>D<+WK.<,H,>5>Ľ̪w >jR-Ǿ >!d?G?>WԾ.^~>!e>r?n]>傿s0> j?`?J>_p>>@? De"m>057? ?>;CrRN>S>h2:Il>?Y?CB?N>&~{>'˴>VU\\P ̿[U-=OX4] {qaچ=e@̾w g?">5!W>?G4=*-5?j$~J=?6X-)sT?@P>r*>8oH$+s|=]ʽgc>~?Z౻sUQ ;J>7z?t<5c>؝;P羨$pEYB_rȾfB<& C=uꚿE/.TH=&x: ek,0IEj@RT>T=x> q{>aֽoʾGIYT|<͎?-?>]]*:j+3= ]w~R$Yԝ!d?ED?\)> [}=2?Vg>R>*=<2?^E=>G>/P2>;v?^>У>1g]?/?<>̎>?SB=KNx} m=f'J[j8w4j}c>yF1f,,"G= ?c?`>5y^pb>jk9G:>uX 0" x0_7EI^j>Z)=xaXZ>Nv~`zwydq.eY.Sh" cE Q/޵%Qg>3¾gBdC=vM/>>{>?uB%:z[Q??Z*=|")>(?!7 {QCtſyaZLݔ{J@@D?+C>nѿnEdž侜 (?*LY>S^t +s &?F>g~C2!> QN'>]5.>DL>~t/U?([h=?-oK= _?eE?Aә?6 Y?j?J?Dj"L DJ?w>>\?y:;~& &ʴi2=qzؿ TeJAqB=1_q~ ǿ?NTȗ>|8`Ӛ9=>dE =א>s⓾@jUyl\`=Qv?١K젾 EYh]f0ӿFQF4R=@/!Ql;}RgaIP={?Io=mL>obtHZ?3Y=???MTS SjY97 @w.??&~?s^4xB;)tgR BL*cuҜ ^о.R7a9\hNY?S"?y?>777轉.?},?L?U{<X?j?aU?Yq~ku>@axn3\޾"!>`5>i? uh1@jw݇>L^>k>MH04ۈm߼^c2?"?6?Cl _/e? E?gZ9>i~=_B>PqIL?$?"?Di׾RcS=^,H~/?bxf=5TҢ>Wi> ĵ-Mo~?eb0?XYW+??6rF0+?<?T?Iza>V>}>'>iq?kLg9?jAmO?yHx?{`KŽy!XzlJ` c ? O=&$p&|9T<>]OqP۾ -f?a辪R&xLl7/p\[F>8PW3'gP>eӛoة>4C܇>^>)H?%>\?<\`E=p>W>SU>>>IF=?.Ë>>H$?*MY>L=L> u=KĽՐ{=4YT3( (>>4n>ԿS`=ľ>\Ie=F<01>W{=?{[>3 ?=`FǾ~g'=Tx=+KT? >Y>s??7>R=0ᾅ0>YmYS!7U=b¾>k0%=ɾnpF<>H4>\yp?T@#?S=^=I? Bz8?>!`>k?U9sw6Qw=߾]J>!Z@$>2_=N½n>+ H,#t9q>=kP<(o7rIVi.;>ɾ@1Iǽ:kU;v!Y*>A1?X7 ?wl&?o<:M=.>7>c?SOdJo=kǺ8L>5;d?`9%q?l>Ֆ? 8L2> zP" *̾o>\8ZB9qLI>)2׽Wy?) R? V!(?cy+>"6x}>57 ?ꙷ?}?3B?Ǐm~'K׾l 0,0M>l6D>_|3?T? ?s'{l?#ĽOρ6v>A *M>>BSIY=޿>'?*<{9f>ϫ=bBJR>*$Xy<==6>?a/DxO>J? !?t 9>VY=.? !+U>vx:*V?0VD:8$d~>:X=d?$ >=v><΍!f>9\:K?reT>)<+K{>neBP >>?Vk?3|GO=K gEzWN>,D=roU*'9<o0-b4jM&=5A*?*ƿ9T>B=@)>`? "opYEaX>K*hgH*¾?Pl/{֘&= =O?Y3]{uu? r*!B?ޠ*ᾧ6Zլ?/&Ti?K?\tP=f.6f{ )|=Zq1IegX>lپC/Ǔ=J?I)ھ?r-?a[d/?2)&>xl^? #ľ'09~>^TJ@?J??,@]˿!U ?>b9?Z-->֥ >.?ǾJq ?> N4pۿ\>A v?6>"?:8KaԽe־U&?MQjWe?,6v?}?iWO/6^2۽K/jNϼOkrq>A9Y?>L?{GzĿy*ٟR8G >>t>S]ཌྷn?vˣ?I6aտ s2@>l΍K`N}6̴><.??slq*$|?$ۜh?ńо[H|F5H?"A?-P?Xm~>?| оX>tS=2?. xO"/[=a"X?_Bl=hb?j٫EVX o&?.TL5>1*o?KUĝ7 >KI=7#?enSA>}N?31Às!ם?7t!x*;r2?.$^I='e?l>|kͿR? 扇n5D?`پ=b)?{Ip(4H=>_=3?jDi ;?#Mg9=E>vW?>|`,a=K>@?H-x =>2;,?G{>[>-Lw6?"O=$>'??LQ<ーG?=ߖL?imD1ǿ?f4Ȏ0.8f侻??v1V.ɾpQ#? hblmZ aMC̿ TX??apH;_jçT?KS|=>PUd?BDtT0٬>s 8?P3#6>4'>?P?,?'r"QTOƾe^>#`޽v/6U>ۺwE1Q5>b=?Bn?Q==>8:??r>Iڝ=Ͼk?ydX?5?~RN?> =T?H 0;y>=@?l?(?:('5 q?Wu>>9?!/>=4rrC?y<H W\Qb:C?xO?!F4i?-CN,/?Ba>ݲ?Ӥ;>`"%ĽJ>,?Nژ?UsX?F|1&5=>Z ?Q? ?o'6==J{?[?R=/$╞G₾p >?@Ũ*?/f pe?(l<Ѿ8m>.ӱ{C)%>?s8.>'ewUv?/㿅+p*>[%-<? ?R JU5پk?.7>E?uTToTξʊ >撴` CAkU?/TԦlď>TοA>~ίͿ)>U􇖾>0I7~?p B*>E>f?9?giR]@`xh'?]:<@8辑vε-?>4>;d!db?T ?P:o>GӉ7?F'?>}Z>Z䰽 ?CF?R'>n9>rIB? 5>1"'#>sP=SÃ(p>#[ʸ/ݾ[XK>t?(Ti?/0Y.v 6>+?R?ܓ2= 9C-A>?* `> +Hk^S=3k3T"=| 5K> rP=H8Z-O*>C0>9xY8qiYPS7񎹾r>eS>kྴN>?R>p&̾MK>#ꭣ"}C,h۾'<>* Cgh10+#S =l- p7Q^B=R'J>vM^>2]©>6G<>֕1>2o0⽠ʼQ>@4+O"JM+E>~7=ZX'$>gU 'ľ 8Xיl24=72K7>ch =qgEJZ=~|OeG;h=?\j+mfPAOcY>~F?=2Lv=SH?U?>*M?"}?>%>Ǜ~O3>?tQb5a|FQ+?ii_<_> ƾ4?'s~Y[7;=]U>>xF>2> >(xܾ^Cg>?)m>TPMNjY=P>?Ao+=;T9KF>=v2̐\+0>2$`Bx={<> @%-ξ ? w?p?/fbHkJ>?b?mDyTL|G= >>ȓ?kMlrPo=@*k>I>!b=cv*)>twy>:wN>L>I?W>>`>bD>?9B?Mm=>cg?^Nv<^=D?F5NR=PHё>yaU<—=>?>EA4{H>6|>2:~($=PD >t߼``tu/~>ջ=ij_=>M='qɽ>SEKD0V +Ɔ`>;" k% >κٰ>+Bgg>eR?]=?jjMHo=ǽ ?!&>>޾bd^>LI4<uiC>>y% >z<=.U>XI>fa4> 忈GԿd9-hZ%>P5z pl}z>>ٿk'h&5~K?z5><4P>_cj)%$!?28=Я >q)Y1oJ>>bTڜ>>3.\=׿,i־ D?>=wI ==S>ׂ>H\?WY"}Jw*??>j'(KuVa>vo?Ja $62ߘ>5%FPL ¾x۾=YnB|^* `x+=<$w-7st6=m-˿@,ZJ+Vu=P翡E0QIw-tO=?pd=F2y|->Dś$ѧ]>q?_9D @%@y>Cip]Xヨ% ʹ= =ydŃپ53M< AN>?g=2([dځV~>8qy0>=Z>`ܽk6 >=_Ȳ%B槾P>ْ:E)ؾNծG>cfI' fc2=:.e@">vWudzHjՍ/ǗCpS.ޚ>8>tNQ?7!ֿ-¿" P30N"E<=4 pT,S=ξ,>rsB@XЅ -^(==mr<>ㆿ3. F쒽DB^cA=U"Au >_tq0=G? ᾣ>Y|t=>);1eA2f>w??khdcIny`QM/>?H!Kϝob!> ?ELǽ^ E>Gܿ Y|q$CnG>b*?<{%)gdQ+[>/?s=yN!/Pxd Y!ľF@>#$l:ľm=!Ez5IվU>%/i!2 A|pH&qԾ@Ѿ<Ǜ5dK%fF#Kbg>0 v!u;`>0γƾ x>.?)=Cʯg>?6տr>Gi쾨E>~9.`3=b =k=#D=??Fbx!2 =" ܾA=>Ϳ%<7n=P <콘?@:J!4 9=:K$A>WGؾO>CWY>ޙ?@kd>e*KFӮ/Zu35 㹽9 >o,0-QX==oJ>A4,e=˾RK]|׾,]<b;uᱼ: WヨR>Qr<_ܿ=_?2>sSϾK>{59 >Kt>?&~]վo>Wk?6[59>JMž:*>迴;:d,Vf ?<fz,'1`Gco=W7Tm?>DI ->Ck˿=S5~@ wܿ19]iMVh>>1eÿSw=?@]_P}a׾w2n&ӕq}Wg㏿zТ|ȿM?MϽ̜ G۾CԿ | ׿=yݿĿ,eOʆOyYѿ Կ(.Nlf#.Fe1R =7e'`5zž*R4\y @>3f׿)Bľ\W",S >ܾ=ٿGk>-@t=&}<Ց?9)r\=O1ml=󼐽=Ξ^-Te]M>OGl=⠿( J/Q?JM& =_ [1t>eIsPUX>B>pnJ!T N?;K*R=3Y4丿AJ4!ϼah࿱1Z#7&Ms"~6; cC*kc:h$[dڿgZϓ/6e(Q뾂cs9u)a9(WXr=;qߠyP`NrԾT8L=u ` |[?:|=:~9b>f8O ܘ*>e }=.]p/位9T>e{=݅>Za (EAGƿ5j-1nQOJTPח$ 1K|w0̀>2(ժ=_ݿ>8ecۿp U 0@C" eK ,;U޿3K V3콖ȴҾ薿DB'P?K&qڝUl<ݿ);žR׶nq޾4j<+W縑ɾM|2JBOn}L=̘_88u`>dG042;3fpE=nD>|=M&Bd-"O̾++j04 X۾V_thKd Ri¿߿MF ,= C r0 u`? ZO=Xx{#n?o4/>^ٿ:T?VQ}ni=zRC>gZ"yưc>HGF>Ve`q6%}>FË>I#`AYD>̃E@>Hv$̿)?P]?GS?>Կ,V}ݿw??l>8I5V5翋? >-\+%JiJ C? >w>4]S&Y ?63? w>H#Et?;X>>)oE=6>!1 _ g*^J>Ƽb=T{>7N I >̆jO*O=c?D^>O=~?h]'>Bg1aT5꧿]>8>5U=ाXIrR4+ 'WO~v3A8A%6@><2,:\}=ý|㰾ꉿU=`>/>M>0$6A->DL=M&)a=Ons\6{>s>7z> |x<~Ⱦ{>뾲c0ӿsR¾oK> > omy=H>{>Z>Dǰ! ˜5[떾7?*$`h#B,&>ڎ̟>+ ~77?)|,>l>gQ?r"?]>=?0? jc>t>/?4r@>H =uC=?:Vo?`>q>=E/1>39YK>dE? j?a&R>E)\x>ߏ聿=,|='? 0f=3F}t>?VJI?>>4ۿ9tv<˸= )NFWi>rn?7?N > DU=Rb?M@ǴBe~>="`>vY''>E }>?m߽3rO[>d>ru? pe{6gs[m>+Z>F> !:>>4>s?,[%>?I?#>!=;dZ.>1>?:?^aB==Єb= :>G m2>L=G=$ea><=;>/ݱ>/œ>C>+8?7駾L<v>X%l>ک?u&>^^>?%x>7?s#ɧ>>`?[ٽῤ)a>=>_;pv?V>wbtEHwD3SJɗ xh?>2Ϡ þ!!? v`m: N^>ˀ!83㾆˽`1?(5=>Aƾ<?>#RS1'/uvfy>b>>HIAQ=Foa_Ï8Ҿ>2?d"dvr>9\廀> cܾA>bď`x&@vYZQp9|? l@Y/+>2'vi>AQdo?<)*>/?]'= Z`1;>ø?p>: '`?h?b> Au>b?>&7GAkۡ=T? :CE=@rmg}F>!ҪiVEis9$)>g`9=ꠈ> >k<Ƶ=e=g>*? ae>3>>r_XI"i">ֽY?%gwfi4[HA>!&= p?GU Z>!Y?7Fֈ>?>=@2>*?g>Dmz ] >NYm2ZۯSX\>N`Ѧ==f= DP5ݽ?'k¾,Kw#H>2?pjfQϽN>8?'M`FCM>4a?VmMj#@|*? ; p|&U>nh?U([=E`d`[6=o_FN>u<߿~m۾g%>8y>;t*C]O>£?U>^b%@Dk>P?>/ɐ=>v5a?ZC=C tH> 澡*@>W >Dc?G1+F2=I:;,? = >o;Ծ* xog,>ɼhB>}s=1N>:>^6PѰli>/?P|΀ XX]pQ+#@7Hn>`2U>㏽}\߾Sj4M9e߽R}Es 0Pn=NX 6 V=_?>̽KUU?5(=f?N>=Xz>)=?O=nmdž>ZE?5|3=r=sd='r?N@!= Q&#T.>eWa31ѽdҳ>7>vˁ= > ">B>l?l>:=q>[>0"ݾTW~g)Qۻzxd: <վ#AR۽#>&?LiQD =F=͖gVO>T>u<8>T￟ }=Q1i?l3o%u}<>`Ű́7?K`>v='.g*E= N??E>AᳯCP>D-? c?>m{mPk龲FXDƱ6>?©E̿G?10ݥڃ\>:XX>3{mˠYjj ƾ˾]twP|о8I6!GʠG0]z 8Go&~;>a?s*>>X>iw>U2?N'>>\SUhp=>ޱ>l>/:Jz)3a1~Fi>>PZZQ2"jϊ?v?%w>hý%#3>bq=}f'g8TEO^t])> dc5Dx%?)*7?v ?/>Bh&@bڽ`hb>-#zа&$=p>1p(_Ǽ5m>M튋 ɓ?bN>>"e>?L?]?DHkuVܾ?o??bA Ⱦ%i4.ý#)@)ҿ4>]9>J?tw-=NVھuy2bܾo??I?E@{H)d=nQ >,=!s7sǾۿ$uS>F?L>h7Zu>?zqɣ><:?=t?>=I"?C?HM#?3 8؎7?+?y6?cb&پz?>>K躾5.\q33;rlLսp̼ GH+<V{=n>\Df,>f8*>8?/mC8i='=B?">?;g6I?Ĺ^?ik?RY(A K<$g1U>/) HG/>8E=?&+xKUh>Y=h?zG{/f=ͽ->XA нyi9|オ׾h RaKRB½L4 >vq"8H|Ҿ?V>&?qSpBپ>>5?8G=Fl>">K8?'T@I_=y%Or=iUPQ&+:+:> XHc]8mHq>eBSE+ˣ Ƌp_l>oAz3I>S>^s>^kl&Fc*r~yhx>!1 ȾR>HlW>PvdNl]um?>q>13NHY>?By>qs4"HþU5?Rrl>Ի\ fk=B?5ra><v>f=9>|`ZIi0{=`>`FAU9UqN>?1nRǹpϞ_0=p7>e,^Su콆\xQ&=X%`/׶?N?I?8PSnL>>[fs?2|xLeIqSƍ wGུDjA)?V)?\Z*b$>lm>(?(? >RRξɂܽRg5?K4yn(c??wE8aog>=߇<_=Z=f `dϻ0>m"ff>_/>l?"/xOuۭŤ gfWЫN"S)?ebo?j;?nn/?z &:?jh?7`['ZgfXF>5L Z-ӿ5?v>eLu#ѽhGs=Z>m>b|><&=F(>I^N?{cS&?i?l?Ze˾q=/M?XUv ̧ˁ1fANmz~=l۾]EG]@=޾qힾekE?KW,?doHL?@[?oXN?w}l?e?męp)_`=R] $k>jy=;E>۱ae?\:̾`H7j㊾|RԘt=޽Z =q=|&>f> /{3'WyԦ+ =@[`F c*w>|>q 4?"?7z>>^^-?k n>̅=_R@=㓾`B<#/EbD-U> >̒/#@>^%ǐhn.>q6Ϡ] %ϱ>xsy uvn=a!>{ǀأྡྷv=:?tޠ>1-l>ydBi2>j>?C: K;3"F>6>R?UMI7*VXP>(p Y-@5;8?B=>2 0t3;Is>~AE E5?"E_>4?ʿSX6>ˊ0?<&?tl*KU`pʸ>pvXS$9lSW:>y}tg0/޾d3QeE>2ӿO{=F;>Id?#:6?];h?'x>;;?w>a=al?Ci=4 >e?h'4P?~6vd#g>D> H>>g ?r=>K{=_&c- ;Ͼ F)ݠ>!:=?(t~c B"S>O48໾eR##s>gM>nb*O>'LM#Mٮ >>#<4ƿ D2=ьTPnC Ŀp'i76=Af'oȎ>?Kc>GV+3[?NÇL@d>`ſ,A<;9W?f8*4?g;)g+V>⁙?SY6>wپׄE$*=j x)=fn&ľӿi+>=\MlaE9;[>$5&!=C9l^[>{1 `?wBoacG.^Qnam=%_a ZMxڟ; $Nzڽ7?|>Vzgt6>L&-?p $B???)o>9>`<6D>E ?)EL>%;>ɿDy>-?xw=VO>:/?3X?E ?+\$^0P+>0b?'i(tԪ>`?jp)[ ?>7Z?>>O?'/?Aw?pr?}>o=? BhyӠ%>~.E?4d=\,4ƺTf2?QJSpOX-IT?Ex@?0qk@r4>款 #>H;˿?:$Wƨ?=>>^U?PRM='yL?h /w1/Ӿm7?*,MϾ v1?I!0{_ eo_?Lmi ?PDU ?eSpnz<=\?Y-7Prv?8zdDA閾m?M> J5>_Z?z ?(=a=? >P6?iM?$0>i?^>`N=1.?goU> ;S ?+q6%о.?>E$?[)R >{c?]> U=Z%ZU?}n<^ -k?4c9>?]43?bx?x͜?`Lj+n;˯>r?lU2?*0?i>%~G9?g_7:)dc>+?mqL?m3ҽvln>)ߘ?L V? 9:~= ?2?[2~/8=|>ޘ?w7?\Fl6"=r?iIG͙;iR jܾ>v|(? 2$՛5=41QaR/??#q =O_N?0S ?P>U>Hþڈ?D:E޸ H1c ?:տHZ>`h薯)&1vԿ77>8E$ <̿-i^u> 23 / >r=V? C?IIFֈ3>M< 6>?E+&>>?*#?NG?> sT,þ¾? d1ݽ<?wd2؈umd>İpӿ5>\(Zl)>{%>L&N>j=='r־r&?iB1>^={ՙ`G?lT.Ov>>Q?J?% J2>5D >>Va0,*>?1?/3ա<96aN=d͘1¾q>Ց?2o?(I3?1C>>bc=Ukj.s`>\>N ʾ轑>+t޽`A hY>Š gGס=f,Y>.YH=y9mP>Q~1r ݛ==> <[[1)y>,vѾ ؼ6vjH>^>(3i4:+Q$ K:JQ86>8>ֻ$>U9o] Rc_?n?MrCl?=M(0Pۿ>fL~077?dDԾo%>U>p>z=ICJ~d>ף=׮>Z7 |-5">&jØr`缾_`辢7MM("2? ?_+>n A-Uо4q.?C􈾩\=<:Cd{g%?+[`>i8> x}C?%@>eT>`3ƾ>?# "ϩ;==E>S=ݷkiF:\=_; ?G+<&=?@־w,?OK.C,=󕾇㾩a?I)=  >e8l#>=K*?4K&3h="fh?37>!}?G\>}Q _W?f@PNƬ>S M6Uy 2>$+H+)=I'\i޶=%f+Ġ=>rNx=);6>]HW9#??i?(oSvCrQm>XH|?dg>h{T>\?>{WH-D>S>akU5P0$ 2R>Yzhe`ܵK>t=_&<Jr0/?Rڒ;?"W $>83>ʥa;ܑ=Owl p->tM? kz>Y$> ?>Բ?+Ev;>t!:>zp ?,Wm>#iDReUH\h]q?`SYY=i?};ȆR{FDXp?":*4c< "@0;H0շa;I\g'9=/ZT>Nӿ?˞><\<>F =)>꧿>/f>8>*>Dqʆ>-H= > >U>u%sԉ> k,'>==+{>b彤ĺKw=u%}Lp>i#foZN8Ke#>H2GTQl@f>`?sMS>)`t?z?hOQ c>mu!{^8=/?>Dx$=>1V5>f">{s=eohlp=hg'BJg)$>R~>:YMM mj#-г*' o<bںڥH=$>i<?+>$jFGx>:3P = >=Z\IZ=Oi=_o$g<>ی0S>|e$"Y> pe>Ѣ2 PFd8!<Ъ)pw2پ>j5 KCj][F=k\ u>R漇>i:'>`QƿϾ?&࠿Ϳ>m1L =T>#wI= C`8@t3>D YIҍR;zcu[>]ѿ0<Ҁ `mŨ= 7 ?usaC˼9#U~VUeMd]Sl=GLI{,5H Vɾ#/P+{E?Ḱ>zB>>Ҿ2>Kyեvޜ>d=qziQ>`Ex>!?By=J >3=Q? _73A侁E_J;a!EͣLw%=d?> Ϙ_f>TY>o&'>"N4M>(P=6=$[cLK^kL=0'1BhA_={BG e> l>bB>W?"e|k@rr>/m>|+?2l")b>'%>~g`1>X>#>n?U q>>z;[S>9<3*/hu@پ>3@D=5쁽ipr>[F D :|.A=AoEo A=䛾H&BaX>!տ!MbDr*Kfwh0?&>p>(?ې<3=~nRY>d9m=ka>qҿ FR+ľŽ5Jݵ>G8,bz/A9>u0>Q:ۿRs*,9T쾗I>m+,m>?(U?/{Ma&SVf>wb3KO;o?98z](k䤾&^l>(DU2=<-5?7þ C?)#?=5 ]I?pv?f, H]O'?8v?㰾~x{xU?2S?>\2q7i1(A>g?l=a+p(u=pt?@[pOM!ϓz!!>L{S_Ļ/?8Z '6L),>ƾN, e~i6g]> ӑbWJI=%W?{5n$Y{L+>-VN>Gw#k<->h0I=j&>M t$F6h=~=Yz,N;T4sؿegifX`!E6־>AW<%n¾h=KD>59t>(7/i>'>=w?; bԽqa>f,j>Y=*?2]JJ́i_| i<;NtD]öՄ-b3>pR},> ŨqbFb>)j5v=}>[B>f˿ G.19=*N/A a>Ĥ*j>C(tkOS>!T>Yֶck?&> 'ľپ>D>/Yͽ%E?/: 0j9>Q7&=~Kd>T >+GX> V K>^4vڥ>>žRh :=X>>(Ⱦej6 ?6/?OvO> <MA>+K0>>%>6㾑q ʊvg A/:٣l𾉞AF):0!RFM#帼%86Ccy : W]>jN鿝 о0t8mD|{ʳhHӋpdEe=չHKL(@ a>n"GODĜ=>E+NX2܄0}F<+R,mYm7W? ,6=T,(˾k>f/ڡ=D$=6h#>b.=gE]oӄ:~m&<\ȻoKK_DR=>ur="@F(GʿYF">D !->:M~'i˾? m`i>D*g C|?5(s=` 6z5١ '"}`S@dhBľ[d " ˸DO9f*$c8AѾ#HMogs=gZ.)?7'<=]H1Sv`UX@>l_|>B\܇!oL>ih}J o3S9;>ws-ڿGlԝ0>Fù^p;B]>ҿ}(n]j?B;*?S=X+$T} ?N/+=dп'+gR 6?av,8>hxlXſi]䛽ޑ&(GhY+پp V*m߳->ҾӉkEܐg3>j:="ɿY>ݸ5M˾/<8=MnqȊF<2ԁ,KRH8A=N,> 9= J.>G43>3[q? "F ƾN'PV+* 2 (1+ޤӢYK6  h3䴾 ܾI޽!9u-D1 Ծk|fd|G=ip$@k7=c{0EgQcUY>Ă8X=Ϳjlӿa\g>y*E>Y?:?>1h,:2ID3u>ؾ/I 3?`|2<=/sh8`ֿN~D=$h>Ũ>j$F>.;׽=g>t> =7MJbJ?Y??/ ?wGtylb_#$@-"L@?zҴ|>nzP;W?SzAF>.47ž?Dӭ> D5a|>-uJZ>et=o*◽ȿ%,;==2 WͿ;!߿lMPatG>Cs:>(g`uCBzmʽlϾdBj>w.H>dp뼒/a=G>&2=h-{g'D>1>>'> ț>q> 7Wy>S Ծ ]>=~Er>7 Ⱦ>ÿ`>b>N=+>EJrS=¿F0? %o>/=:IբP36=Mfюe=߾W+<[>3>[ +s,i?ʸ> , >)J=*P=j>h0?.9ֽ±>p I>;>=?[E=+?N_C9>9>QA?RƾQ? ՝> >K?:M8p0'Bx>~=_`>yY?9>=9??5>Hgj=ϫ1Q?>. Ϳv >Xd1@>冼K>xy=<DbA>JD>S?+ T\?<>zZ;'>+ؾ#r?8>yƾ,> ƥ =yվ{bA>YmL H<> 龑@o@OZ0>DVq? d4i=8:>Ƞ ۩>?\M=) >nY) _-L@->j?&,*>^?E?vw?z? x}=z.w>_d>9k>T1Ϋ>W>cpl=d>9(?13n,?Cx>y9?#?* >AJXFk]>ߜc?fm>"A ,t??~a>E*Ԁ杝|?+:?x>I?XB?8?h:~3AJ= 1>B1ʆ>br>?r}?? b>3i4>s4>ʷ?*-;h %ʾG?\?DJ?KC?rv??-l<1։>?Qu=Öj@8wG>?pw>]zW?K盻:\=s>琸}GQ |>N?]>o$8UR?۱?MQ>[6>q>,k=>e?O_=x>C@>7{ *s??q?NQ~g?j?iwɾnU? :? >1kƾ^>? w?o>Fo@>^q>O>ܼ:?3>a>cS.?Gߠ>z8>/2{?J?a|nAl>D%)욿P-8?i>=5|?u>!4U"?W_=$=þr?v _}>&=A:pt?cZ:>0q Aѿ=un^~r>?v>zFֲf?Ո2# AZQ 3>?j@KUS+?L?ܭ>.u7*?D?m>vxEJj>n?.so۾_~˿S,q? g>˿E|W>+c?7=&?%˄&>?b7z> Sg>oL?G$= N&_GaFQ>Ӓ} 6PbB>,?[q="7ne8>Ϸà[YnG>t־T>_=G>[g=/<{;޾->M?(K b쾗>Ң?ǂ>y`*@ؾH> V?P7>@>Vͽv>NO>,[@?Hef>>!9LD)kZ>C=9ҿkžԗs>r ̿/$tzQ]>z=*?[NpA]G>s>Z}$?},j}bY>oI?@t뾯]5pqc0>$ok0=/g2;o;Y>`_l?>w-X>Q]/?h 5`>'?>"y0 7? ?~>QXY׾T`GNxVF(2W|$!W=><)ZoE?>*>[ ynh׾F??E>HEZN\?;Qߨ ?{l?>l(bG'>Y")1u=2H>^>VE4*=]1 .>z? >eƎ~ 2>̄sx1/1@S3=#?3h#' S9;iqž\WH:yh;_�Xh &i?&]>妃n 0'S8.>iS=p10}h>*>'ELBD>#̖߿Aa'Ah=o,0 ھ>HZ~>>w?}ý+|v`> <6>c>C!=2?4fۿ^M:[>c5?n6;j@|> l,Gֿf!>hE>sco?vd݇> >ޜ?#=j!!.<}58i)Z1> b_>?u9nDN<>%-mWԿ`9%t=b4`,qwM<3>Sg?G)ě5`i>?UĹ _>]V?L>&>S?c2;e͒25/@mr= #tT*=g6>4<̎>E]L0 }/پIMPI½V&]ӳμ@~>a\!A5Kt<۾g>O޽~V$S;]쁾igB?V?f>Sr0y⽟ф<Bb`\;P⾊2JdW0lP"cH '<ɾpھw6[xp-I Q8!Zh%о>hͼ`*'s."_ٿ>>Ȩ?vHs>I>~۶ho=p??Zq>W@^<{>£j>>9EBPW=Uaɿ_-R$;ܹ'ͯ)Xf59>l =%_Ff> G ٌzw>GbH @d =(?U?C>ߓ![`󾁣+ C #-/!0M;n5*-1fJD=0?U?Lk?<=??>z_tfX#B}=6>5rd` k`7ωQL7j=~ ?T ۾maS>qf8W^>&?W 0PsƄBT?|>?>(1þ??Т?*t(5X=Bwol ?&=>6佢t>? :-'PZQ#02u<[,+@B??(|?܅/.*Bl??v.?}_T{?u?$?̽@??? Ky!?p]?q?L0/efRJhn>s.EqiYe!`)޾^N=-p+7'Gcfa=[gL*a^=`<'ľ$!}>i0c%="Zhm[ekM^0=y8Q"'>C6>y=EFx=i>H+>]ƠMsRHh1#վ4&;=/;/ܾ"d(=E{2X1= >]]>Ah2h9;"| o>)R #B?Uz>H Q>7Mq7P#Fz?u&>>6$0??G?/;u8,%t?N?Qb?Hgc(}??f ?[o;5ymWɾ6n>6:7Itp=@>DAbt=s @=,>?]>G*9-+=Q>v`=16 >>>>F?@1Y>+=}>+LV>UԐ)+nP@\ Zm`4ڽnrږj\SX0-ꖾb5w=Hb@3tL>;q9ν룇Ⱦ@MUPJ=?MO>OV!>gnD> ?P>EZ?g#Rmn=?*ܐ<=y4G<~}?0?@½!vuqjs޾gF>b>?a[*4a ??[a? 8#=z?Gs?;V?dvlpz=/%FLjgDF(>?3?6?8tA>??J ?Z&_A Խwש; ǽJjp6M$Q.R)cØCmd(3ӿ gQXG:?+a?i?Rù`C'>>k]?^gQ>l>c>]h@bþ.A?E:?'?p*R2.=!Y?ݥD?;?=0&?a=??¿&3'?oqe?OV?Tnי(??pkJb+W>hjݾ{վ]sŤ>wso:낾/Yp`>P[1+3gӾ ڐFyj`7j ;qP)::X EؽIXT]̾".{dwa>܁ (>5LN{lϯ=|?Ɇ>~=D5>J* =^ v>Run~?mu}}$r>?wEg.Wdvɾ>>\olNԾ) )*0>_o !=vgp4XCbx>KbG)9뾒mjY}> /hh񹶾)E=/vp_z6%@ْc7Iaץ>Խ>?!x}=MQ=±թ>6F( l>+hI`/>~Nj?Vn`?tq`?}gr-o?Np0?r>?a_>Hی>?%ZH? gKw`?IV?jr?Yk$?@> |?APUd?l/?gn?Բ>w=U>>U>7m>U>?*&UIf? kD?qbv>~?3>?G=ff?13@(?c??2D]9? eO>>X>&?ݝN>6N J9S>fvaRg'0cTw;h t]㒿!x߷A>)*p`ܔi >`B;pYÿ =^<[OP=۽1? ;:@\{\h# HK=CHVSMio m =xѾR!6=ɨ  >HOX*>~ =3y>U2v޾ >?S>&_>gw}?HobVξ>O{>ld꾧&LVP=ik2gUaԾVB9 dkyT{b=>ri0YD.1>n$5=B?=E??W}Vf>K=?62c]M"Q4.>^ Mh&<2= H?&ON\EzԲ>N=?5ˈF=61>9>,?EZ{0?16=>H}2Y=,V`s=`?y``+XͳP)k>I,5YB@=r!_ ?P(=)A1&6C߰6aнfRzHR nd>>J?V;d=j> MI? ?ypv=`cO?H\wj>\QپYw>> )?Nf>%F,iE>g? ^FH$ q꾍> g +AžF>[>P`WTk'>!,b?@LTL?~`5ý[; >K]x<ayT~J>W;S!=M཯? |J>F1?#0>? @?SL?IZ>>K?'6?m4?ܭ;Y?)@F?\WAhvWu>\|?1ax}#Z\5AN>v|&= :? 9jX$ɽ+ >ϒ0i V>^=??O~_P?k}.>B|?)xBK0/Q~) >n`}*]پ >EY8 v%>_-{Plƾs?b}> ۜ=su?Tµ=ec#%? J[/ c`s>87־1i@5>0*Nܾ6Ǩat>F@+Agbþ1>}g>?wlt侬K+>=$B?A @[ n>A=/?AG= ?L`Gwl>%M>>(JGj=.բ?Mݓ!Z~,86>d+ve꾣>*>dh?j/~Su_>b29=u>2 =2ゾ!J? EK>Lx> >j?qG p=>>?V4UA<<j>> ?sEC;Mu>?; @)ϠGՙF=>\)6Rxq˿mPY ľHJ`忆B2{$Jfw>yiFᾪ+?/ȟA<=@C ;XV/=W'QVo 1 dD4@Y#"`\+.ϖt>35a?iOb=yO2hgZ삄wQ]>dw'u[/U쿱@)Ͼ??*'i>H0b< uxV?@پ x>kKmG=4U]#>r 6V"濕.Q>`l>sFV#]y=Է,7?^JO?G%8 ??I%>j2~bK>7u2C.?Z!Vq?-<;?1>O $=G9G(ʗ 2?<7B?J?!OL'?C%?/??y> y=\FR>n"/?^?`?3/?I5}?&n(\a<\>8d˾E-f?s!b=VSa?_ig >V%?ʨo]esr& ?$Jz|[?qTaLU侥+,>Zp M?><`3R=yP?mhb2A4A\>=?"2 4R%>ӏ7>U>h 9? yYȾ=s!?`84&οL>q& >3C31>> dR},>|u`,bi?"fdj=8*|B`?;y1d<:[)Jo?zS^?*>b{1o?iu0]/3>B|>D?w.au>p.f>[^S=d?=2%ш+z{c;)ᾰd?MjT¾W?P>2$?gX,>1Y?bTi=oqc5i ?<.P}sd|IJ>Ig=PD^?/X*s0W>7>dǾ?mnY}=C=/̸?b@QA>& PH+>t[̐L1=|a}IV?ͳX5>P]'x?Q?G!?P_? RXþy=|`?fr?ˬ˾5i>=j?/4J#Æ?4 g>yJ?.>>A=#Z?wr.?Q ?y@?P?h[wr >F ?y4E4> {?4 bR ?ePJ ͳg?+K-(>*|>>h=S&?53=r`pk>-#=$-/?=Ɔ>\>>)?)=5%/e>eJ?ӷA@/H1=u7?ck5M' x?Aý+{ٖ>}U?<& >ċ=́?ӑ>1>>oz=X?Y3}>ǻ$~?esIw>旽((>Qr;?þtkI=>Fa9&?> ^p>^Hb=1+~ ?on.>qk>k?N6?@3=چ>N?li?=nD>^'[??s>1V0=;?=fzSbL;EZ}¹? SEKOaa͵1?uc@־B{?x Y>X>?+g?B(F /'>>_?-a?BCuξվUR?PAV.B? HG ʼn;@1{c>c]>Ym;-?Z 6n>I>q&??5+_]4ދ>V>?3lH?E1(,>-? ?Cu~?6-؋bt\~ᨬ?Kos➐?EVKXXm$3QԖF;>0[>?>gP0Zq>#.?>g, 21]B=Ȼ = ͳɟȰ;~_(Ƃ>bg><q6mRP)ߘ>?>xiТ6=U}>h>1w{3 o2>^>tMߏ01!I7g>_.EA=_S$ qa4#VA>c>}5eںiiM>$L۾/$>cspI 9=T< e?Y/I%(mm? ˌCܩi??pUBF*ǴЁ>﨓(Dp:E=+'?PuPhdJ뾌?)|=h IoeA]?㿪D'>Tξ>sV!=E=fk@F>.l!=Ž&ٞRݾ܃>뾋? 8OriB=>ʬPp?FwM`p=?Rxx0eun~+c#S&=h>RGh>j3/>*>L#>rsEBwd>F?!>kV5IZ'>/o>4=eq N?j1>>J= u6*>~=$1>'=gK?gka$4r@>=7mBQd#G;Ŀ07>K48Fd!=iھd#]y?DU1\d Z?U<>F~A>Y?u}bc ?QDڼǼL߽j>!! ;x7? *K!.=(Rb ܽw79]-?;wPDV=`[>qu u09 >9;?#@->;CJP>L??WRlo;͑h@,?>{NV~M"㾈 ?ne<9ҾӾ5>( !Q3#>詗쇽q>(d ]⾛8>=?4>K>,>>(*ܿ4>? l>\O>?=?=C*vp 2ۿH¾;GJ5Z.Rr ;c< GSO|*.Z?#k%S I=?h32xV6AT y(S*G~-K⽾U=y>=Ob=> ~*lQep)kܽΪm=>=% kEm/D¾ ¾a| j>Z;P2%]澂8̼>.#%; 97= J 2Ě`#ži2 <œd ^ܿFz֑wASb:=Y-?6HhaW!<)?JX?UF>LMN vͯ?.JkHc$h>ꣿ$)z)> 9ОrF' ï=s鿭,j^=!uZEc(A >=i~ؽFʾ>:i{T;>yHV&CE= q6;*6d^*5?@9|_* >lQH=E}wu:s>*ct>4`Q8d>Ae z<4ԉLQ4 3>޿'Nu쁿4$( X |ۿ" [Oڦܪ˾3>KFP>-=*GԎξu=W ;]-]=3 V> 3S>]k=>䛄=lLRz=澈z=驗GzG,R>'=̾m@$ Ծ c>=5Gł{ev~=?*#&½(zˏ޿:5psK5Hr| Ł8?hG=!]PнP彔%{ |1)A>t;Tm +غK`~Z9!:}>E<޾<>Qq7FٝX? ͽ8>\9B6Vb]8;ſ].J'd~&H;u<(ê`㊿"L&^FD޾iW'__KFbƭ{\-9ڿL{̧$d۫> 2&;vAþtD>[G,Xp=Rݾ* ?+׃o=iv*<=kLL=t"TI]վTWg==P?*xBBi˜?yY 1=GC1w0¿,)hpD>﮾c=1ZI(1>=:>g ӹGQFǾ_gv= F{8W-k>7?LJ+£li >>3@ĉn꼐B>>_!>n+9+L?lz\>O .4$8PM t> >ɨ?5׾ HZ=8Ҿ>NP)(-#r޾>֥ d&| =X'-F<?$J?yJ~w$&D$>r :V=[5?#?YRMLj+$}X:HA%>[nJN"X}->'vh4f5"=ar/z{===>" DDÍ=׿,u-1$ѾeJ;3:ҿ8AWc= T(>\`{> 7< >lʾwῄԃ<>%ýW>g8&ݿ p>=}>GS2lf7krR= }A?%|:@5X 0,#ۡpNk‡9 }/55)=P=(j =l ӿH>*G$$}O>K 1%\=nrʁ. 2">P|Ծ@CUx>hݠA@-<7>G7ԾJ#)>D`j}ƽ̿2G*g3:&J =a8X1X >5<޿1'p)=75|N>\\W>"?HFsn1׾%>>bVCT8v=PjIþGs=Ǿe4Š=B?= =4sM =ʼ=ѫ>Q>>+ > g =jDr%Cl ؽRmZ\>8 .4<:!>|*rC>18V>>V5翮T?.0]`|>=j\Ⱦ6Yqᓾ$D jѿ gK=ξZمlb>ȾܺžK-=峞>'>C;;y_F ==v>hQHz[=ʆ>©?-#տ,/=>a[>\) =>\?;..wh#޾j@h8%聿 GZB~d@ ս.%WkarK&ܿ >>ih>&{W=rG>jewS+cԿ|>e">`>(IlGܾȾ1u1=k+iieN[D%)V[w=:MnԸ3vdn{[0*}gI_ݿ?U7Ȱ"<|C -?Eh,Y=!*M]Ud 6qta/Pc2H21>50.˾a ޲m&XxSةFkɾ>3D޿.f^lӾ݀^ƾ=]tOŚԽXG=XnTmjV照h\4OXYsdfs>}UQD|l _14dy1> =Rul }ڻq^Y>,Wi= @n=/I&žώvu9C>Z6776͒_ ] ?\%<>sįOucރZ޿>S"3 ѷJ#%>Y2+@v~HؿN@=dMۿQDCc<2O)+u/.zNNw<] ˁ{BBl>Cvu+D,+Ň*QAĹ=2>!閾 ؕ'ؾAlM<ځV=\ў>6P=ו:.Ӿt, ˧:Ӿj?V=pNhۿ#S3>T#1[hF?oDl>m5eD^n[?Yґ>qm*0?S?P>:o?0%MX_N/8Gmʾ ҢX'!> MO>Uhw65'~?+R?>Tv( Vd:=ܜi˫=7?9 ŵ=5GКFN?|x->elQ p?,> Ho>4=Ieo;x=E>/\>vl=fӻ>Ja[ =C>̜>u>^wu)>-澚|i?Xr>ME>&V?A%Ѿ >:|%;? >v >? F?N>x =?-s/? | ?Up>;>?B:í*~t>M?rk@>Ed:o3=K}>?7@p.t?\Ax1Q>m f>nHi!h>?dX> ؀?+S ?>ނ> Y]W>B? 8uZ>=>hbtύ=dB->\e>N?H8羮Ah>ha>%> /֕M{&徖?l ? >z8J={[y?>9??FA>J=?*F=G}a>0>To>:`'Mw5y>?b>3\Яx > MU? )J{B0cc@=7d=?<>$ߋ>Ӛ?V?J>­=rp*[>C?J4?W>:A>>R?1=@>H>? ?:(>vm]>žKDK|?&Ű?ѷ>J`;8?'t?td>`V;P>(F?wc>oWeؾp?A?>ENj?p?>Jsps%=,=},|?ID^AX>AN?-dؽ-gwqm>o?Mq=|L=<=}>7_X}a ="=!>l \=5> Q2ژ>5?c>a<{MuH>/=o=0ʸ S=B$=bR8>)ِ8(>{әYӽ˖>L?/1[WΤ =V;v>w?ȿw=G<>LM tA=M=Kx A6T5Q><׌?bllB>f??Q>Uؿ6>">H>??-=VM$>>?\<H:ʲ>?Ve? ?8=!.pr="XO>ދ>/使Z/>>Ʌj?OG0?_dk>1j󲾴)¾W4>ԏ?Qc5?W>>:?T?>, Ã=q>#@>B|UiL)=>ា?Ae =-ydka>-?B?W=L?/ki>I=sWf zí>&:M)о$ܺeB#"6o,Ź>u?y>XN w?U!?u>zis?M~?r>L4e=4H>t~?z$h(V`!K~>88~?H-{ifڻ?^=_l=bܽDz`~> ? P?>)J<>-GQ??j/>cU>g _~1 j39>W?G*=b_> ? dwcvQ;Bh8s `[DB>< ݼGzp6Ov-><9T۶\VIӀ>6=+$X˿Leܼ>wR=hQM~4>Sd|V*\|=>qVH==(V?aMuc6P:I=-k?=] ~<|c?f>d.G~b=x?F޽Py<|??d>k0𰼉ݾݱB=ݻ%O'p>]7~= G2tk>ۼo>)6@9 Sx?F? t?H-@?U?> DC>j?>N5ʩ{>ӷ?bz=ʗ>WiUM= |j>EWb >hI>2vW~z=TJþ#>瑂N>j:5mO#v>YvJ?@>y(,8W2@w-{>SQN p0>.a0^ M4-?}(>[ܿ*BKv"y>'FʿC?dl>_Ⱦp܂{Y3m>m>n?t2>-E_>1??C>{Q#},6=} >.?dӼT!Ç>?5>A}P>N.cgIu\+_?>)>`>2Gr:uu>ǟSk%j=>Vl+ ,]E>`B>U=$ <> 5%`2/ÓRr??q8&>!]Y?.F?:>&ehT>?td=h %IϾ?vi??_wiē?+c?% ?>2 C{>G&=!}>7v=*lNƾr|4B1>?#!ޮ\ Qvuc??`F>  h{?W_?Q>‹YûS;peM~KM_A)ipp{۾0}v{t (s8acؾq:>پ8C]=6??B4? xٿ)n6=̾nH- ?4Y>Du7Rʿa)O=>Ύv?D?^?>ҷ*q?,=??%>IY~#< nf,2j>޵ϾL hd$>%X_p>gd}>`뾌v68sP۾*OD?Lf>x#>F=H21u̞gmeެj79&N@w`SSɼŷ6ّor~_J=žz!A*H`:; ?D?O>kx< t?Um>t>[; ?0?5[F?ty=꾕9??,Iw?,I,Ԓy?xu> >\;ƾs> |>Se? {2)XZ4=h?OW>kz>?w),W:u=rһ?< >:=퉋Y$,?;`?ISz??6U - ˽a[\>- qrH='l߿FR.OSG<-dRh4$ QjY=í\|]N>fh{=wK˿96PHNQϾD>ן>?Q~Veap4&d'P@R&b@# )0>!ERr>/+ st>l>2~?5&2P#>?,:>?e 'θ>>?/˜ @~o>Mn>yW]7_fy>?1Y{1>=* ٫ U7zv.q,>@dgXҼpR 3mL>`<ɸ#>SGSq>p>'4=8u>20k;??g?"`U꾇G?~? ?@Tİ-۽ .Gnn60p}gw>@>>y?m8S࿽M0=ٙ" >[>j?Tq!J>>U >5?-<%n? >x>jD?xh1#>>f>r? <;OruI== P_!?/WƪJ?2w>? >q?! bӍo>vL=i>+tAكooY? t>?Ca}D^Kd 'v>wG>T?q^_!Ikv=z$p>uO`d 1?>?0fM0Ӊ,;,??P?؄V\,1{0??|x?a>Õ_>1?r?j.6>t*9ɾ|*xn%E?H|?]Jx]w,P`On>9{tOxJ?56P.s;9PN2??Z/Z>!pF[4$LGkl>ӾyJݾd6> ý*u>?]}ي>i7ҾN*=ưX?ks_#"l?|T?FK?Ho?.r? SS[?OnB1?oa?p?Wd{%?BvV?}s(?kJ&?MN4?kj?d~?k?/dw`?{O(zgwx2ˢ8>LUvdZׂԿH<{lǘNW.'0Pib`Hc ->jkGN"9o"Sx>HYA>_=)>kCU2 c=,lf?x\0C0=6 f>kQM6߾{>cO=ewK:>h=EZ}Wu)?vR%?4 X7M=wna>=7\U2D>@n=vWjh:b>ϢR>Ab>>4 K>BEB:?%y=YL!d I>;\_է=VH >?m1N>>?s?>?j|,>V!>=&iD{%Ŭ>nTmF}Bgr>H`,=.p=Uq3B%N= 9!ɿC" `=jӾMI A ?;iv.Dݾ{>hrt}O>˶BT&h]P"߽>1SN GV+>'_u\g>9C=zf?:@1) Tj[SCph><gO񾤖F>\Np";ͻQS>R>*05+%;Qlf>ܝ2@=^?!m+$IԾ*eϽjxG>ѐKm/|ھu>:^*9HAcxl&W>c C]=u>=n?Gk=f=Z%>C/hn >֙P( >T@@me(( U>IؿBVՙ=?">|?oLA1?T ?x?d?ݛԿuH,?#?'?A6? oCfw;߿ZEM>$>:=Z`?EJ-> ?6>?=I'=X?>V>ni?s">M>Z-?z݋?A}?ÿR=~q>W~?!1S⬽7?P>3?}S%Ǿi𢾍n>>z0`ȗW(><D-ӽ п,(=dIVmrx`9bT?:q u@)=}g'g?t>D>'{|?_$ sXuD>^쳁+$ꉾr=Wq p? f8!Fkg>~ =%?Os~ZEAx!\} >8V?+anOһ# ?Ds?b5?T?{Eg+>3꾜h>9טOrs>j'=)BCݾUm>տ^)ob?4>m?]4?sO?b?J?b&|k+A;f>ZM7?_>D?l!P[=9?>w?">aZj=;GFi'xI>`==xm =9R=Oƽy}о>jNh??D=?Xe?/#IA?t:?P?pA?tqc<}AA>ȧ-=/?9o±KֿdEVӴpx=(>:K=G/4>Q<>'m K>>ÄXP>b~H{GD ?CK=Iݾ?" [:b99$zb~Re?R?C1U?DPŮ۾CN>U<)?u49H5fܾ ܱ?QI?'0 FFAS(R?'O|=7FR?u0O=A#->FU>f}Rp>uw>}<6 ?;-Eмq>q=&~?HMwԘt>.?6H- ;>z}o{>/EZu>y#kB?Z=uq?.>d[P>%Q/>p"CW?w>W x?0G< s?Z%/]>@=2 C>۫C\nؕ>.iؿw>U;F 6>:%ľ?+'g9P<)c,AG=KϿ/L<3F=!pLvU=RX>%K-िP=]U<8jV}FQj .m>&UTTe_YL?L违5>`᱾+E=z@v}P3cu? ҿۭ>$9v#K=ךQT`΍#?Ec??TTx[ݾ? >#?BJR!~*A?>2?^)L VA>'> R?U?/zE?FD">NB2?-O?@iNY?QNX5>> ?fs?=;>!Qɽ%g*?>uC=ٮ17X>ȓ>U>͊}>ſ P+=jM$o>=L#>XBտDX>X?,}41> HBCa>{B&?uV?2q?o??H)yP.Kǟ#>E7#?Uw`jҿ>$2^‹?x!]Q>B @?wpQIᄀ>o _c?EwB׿u=WȨ#戾<,ྲ?Wl<tJd,??@M/%>OyB! >t?:}>1=2WtC?^$XK?x.?}d4?)x?n? \[N/-(Bt>ދ~?AmXYؽgQōXp?4~ dZuV/?+ݺG AĽwr0w;?9m> ">SpGG?|?$9.m=-5οJ >6N/>,EȿK>8v*dž>QLրS>lQ?ڡ3?%aL'>y!G"3H?=!-l/kP۽ZQ>!8?f?;O?txP>BH??)_o08ML>4>y| v?DaQHF|>=u'?`!#6>RDcaw?6H6s>[31l>t#> ԹL)(>Ys>mw`?E\tn%U>\<_?Dg<]{?Rh'۾T;>h4GV>> %?n[(?1:>>=4O0?Z=<D>/o9kaȽ?Zem?&3?p?X.X? X?F݋3ptl|>3TL?DN^.ܾטٿK?>3-lƂ> X?7?p<⿩ AG=>*;Z?tu$>B>x>.do?9?*%J b?@QU}BO??h^@ρd弬s&>Ĝ,=IG?q?s<5>!Xa ?[B t8?n;~Z==ELa?|H佋~N>q>0Q?X4>b>ͫ?DAW?U4T8w 8@ >5]?<0?1Y?/-\>c?z?7B,Cz=D=E=0m?W O$ۮ> NEVC?2&l>;h?D]B?>!=QZ/?u>>)3-?=%$*w?vZ=,;>nH▾NF?Bw4>FnD`|/g >šn>b5/AC>J>a\>ol8YO?Sud:j> L=>E?1U@:> sT=9!>?s@~=|>=>? ?>QU =>Oay>Y){?:'s? >|!$,þ?)| >ŽӧvG?=IAp>>%c?P1==>OU>yn/㰾F=!}>ə>61X>L>OmǬ0 þ>c(?5(?0 _=fuo-?Ej"p?*DDg)?) \?AV/"ݎo?Ǡޯ+z=P ?j)cC>~=#i?oKTiD[A:?/\=K't4?9Z2[:<1Bս+E!av7r.H>Sa=Jk5q=2C >tP=X@J0rԑ7 Q=C9.C6,#N#=*ѱNY;wD mL?G'x84DS x}"ξim1:3!3>E_<6ݽ (>rX(ȽU?Qt:c7>M>2?qz7ǿ<=r=3?q.b>>|>d<^q>>ޜ?p=G :1r=ϼ9o>TR=;\mRL4Ӿ}97䛾k?4b02a. տ2>9sFacAþ0HvP8>7 =?fvJQe=<*?z0?}K6>*i=9P8H3ABY\>I?*>Qq NH>=̭$q<ƾIa >YR4v/aノbf>O>)> *p <>˸p˦<|پa(? K=ܾÖJW>?BP?mcD@C??8>׾{?&Xg#~}˴>T.UP>Oͫ<{[IK>Wint>ܳ>\gc6 ><@t>>p W>>6ɐ ʉ >n>6 m>R{ĿM?S qPhn=_QL> >$Sc=x&t>=<\U0<`7&ѨiY=q.A&Q.>Z(O=. =SSt5?g?i>ޠ_SZ`Gn>=攊=j?.U/={TO)=ֆk= r]>齤9>:sfn&O>S(c>om&9>j>Dm"S|v= Ye9ڿο=q;n<>OBԾk=@U[>l=4^a>O,E0Ͼ֬<9kb>ѯ!⿣)EB0@>̉ }ڿڃc;`r=A>>OW۴= ؾ={dZiZlP $?4׽>@̽W۪g>1?K> R90ƇJOSH<\y("t<⾠{ݿ jE9"pڿUL˟P>,俪 CE =q>,Ǿ) >iٚ +} :~>uþJ=P"6NH^>wO=|N=_>@Ϟ,P`>xȬ<vߗIH?+>ɼo6gŽ@7 \43b,ĉ m"=TI r>4+L3D %>t~|,=g׽9Vqr>̚5_@>pּ=B>k >|KBʾ6z餾=%[\n?&(@>s='>mM>0AD g=-;G龐,N]>qRC \޾Q_̾L>sjP3>Ipw> d*kp>qB>% ,]d=ifI? =".^6>l4O-ؽ?lz 8> eK M>eT^p>6v=.>PATØ>/)nŰHYj8<<#gN>'|";eV=JW%.?;ib>&y||s8> |w%˖=GR;a?4 B@4Zֿj=P,I4MC4n>B*P+uQ$P>#*`XS=`;𝌾3@ѝ˾i辶N>$1>ve?zW،> NqSr%!Ծԙ>&= ivtwGTy=d Wv"h"ξAɽ?& Ѿ3ɾ:@>M[蒾 .=^?0˽xоcWDz%>1r? `A1><a>ɰG? 8z[>9龢al@=?`Z>ѾWZe>7c^nIj"2̿$x>s|?D]]FT>?Y0 +~ >>UJ?Ms2ɓU>>\?f&>Co!)=J Ѿ1jRnN 5I^ Vu>uG'BX2>B% ț=z(_>|I^ ">̴>>.9zn4v>z:aT -E>s~fҾu|>=OYŠJ<>(z=P?#;ZB,`jODqh+(_t=q6PO=k˾3=2A5 9>-?=Y?4ztw!g 4z=zF>US7=]9X<܋I'_ ]A&],|Z p+jWU&=QOm]<\l>3=Cl><-> zhHȊ?RҮ@4/>(,"+"aݾZ=_6~.Rf־mXVB >>`>\?$F '>> >@Puq> >B>l&Hy36Ќ\\>4=C>?5`>R=m>ֻY]_hǿ0JM(L8׈<<9*>l2>ۇ2ܩ=jEN0A\gR>,]Ar'pޘv> &vof'MϽ`%D ^ ҽ'|LƿFx[|^^C=E$7Lן>;GQAS.J/s;¤"O SHJ:=?2z.?= F0u)'O>޲0>|=*f=ѿ0\WN> FazK,ǿ-$Z1пOѿ5\1x+t>< Ѿ3:|)E>B0'~uB=e :6?<^+J=J˿+R5 3ſ{=0qB`׿> s4[?"z1>kU^8ݥ  b0Ͽ9nej5aVekʿWֿg'- п);@J;5K,TKN?4<2q=T\Uy=?b3z>~-k`?}߇&>5ېǟLh4C1w꾞ٝgL;?ov`]* ;~[&>X34aOi$8?lI>;x3X?t.^$ߵԾ:Э\@ZtpK-=w1GסpS/Y? g4l>6N@>jyھW޿>o? 9AuC>il?W28^=JR}<]/%> 6T_PrY9ξ_'U\^ƒ U?>2uGIcr?Hͯ>0mJ2V}"ϖqm?NۚA>lǠLU!?.z>[bJaVҿPë&x Uɿڭ<ؿT&W^ u' >wQᄎ}@ X?>@$Ӄk,WFؾ=޿)$(᤿9_N>? ߾>0p>>9?fAUο? v}اa>w \^G>1>@1۾޾b=^BܡI>Zý3h'Rwu sס ht4>Jlr=^m {2>R=)V-/3EK=[=t;qO]\v^=>A]p=N< >5=n>|>h>{=>lp|2/y> l>%#;Xo>q.>۩>b>G?u>D'?@{Հ>==jE?Uf؋>t:X{ii ?="d֨>4 ,jN?)C>Z3{MQؕѾ΀Z?޿ޢf>[D?:?BGO><Խ~d9? xZ>'¾$V%>A>8K?:F!?(| >ģ>Ͽ? [c5=>f;?8i]=q?0~?ļ >o/"ٌ>ٯ?ÿ >>3>@>#?]=?3=k>S?sP>B4V}=>?R=@>쁿ѡ'e>"?fp;>!-ϒ>Xq?Sk<=Ȭz x}= A?,柽18e.> {c=j>+A>'xq>v>L?+`kcs>ջ> p>PYd?D>0I`>c(%Tھ $!=?-i/?n,y>>Ѿ>,?oEt>;R?EΖ?ri{W= >xàpj=W<?>#Mv8>9>>XCY^>> >Ӏbo=ؾ??6>>`#s>7\/@>qhS>n=(<)>,lg'>/W.?5>6ҿž 蘢=缇?%ؿ"˼>x5?hb4U=Z?-S!WO%>!q?j>?u\??f>#4> RJR>B=UMK>YPN:A_=s??895U@y>TQ?\=t` >hQ>{?ޱлo? dj>?u";_uuaap=e9fX.tK>s?J?G6̫>e?-\tMA>E]_>S>`?b>.=Š.n>+pڽз==S~,?UA M!>]T>#z=u-?9]e=̾W<'x?w?ٲ>O[`kپ<2fzSſ~@<3rSTZ~b󽞈R. 7_v>K۾*'{[a=I?w?ҢM?Q(?쒽 0ɣ>ؿ ga=R>~T=!>`(>3Χ> >}G\;>8a>gi?+ dw>6?d5?C?Bw,=K>ü ?> !9B1..`殾*ؾDK63{QhӮ>G>{ռ=l g 5>G=?UE$#T=Q=%u:?Z lĬf'_?CAz>p?tI˽w6"9FmN `?6&}]+$WҀd;>u5>=eؾ5=aF>sK>Te=A:Cj@Lmm>0>ivy=ŗdn=΃a_5yBB?wh >.4>AN=13xm>e4e?2ڇ=Tߋd">>=|羧'5><7dx>|DŗAGK ž8"D?r t)7 SUG=?-w/QaJ==vqfaP*>?>EҘ T$h<_ĻžI6>SI>ξ??Z>v??F>"I>jio>b_w[;h=V~o<>ӄ?ʿ dZpqſ}5`|<E?vHF> =?E~aI=tѦ=C1`?.+ȏ!S`ܾ?&]?V?6P`N辏@?,?9?+*>RҾ~1t/yB]A$Dr>?d=TW71Ҿ ?^?q>Oz7=?=u'[ |K>rQ~?n%>ߨ{|O> NaP9lyL>׿IZ5p.cv>Zp/d>??>PVYPLjD>ދ?xw=W>T6B=5fI?U$Jw;=ɴ<j.ӿ){@>:ؿ*uZ\OfA]=g%>?GECeK`.>,?Ց>R;jb >ƬԖUx`cn&?%ԫb0:~Z?>![>p %0eL>ҘgQF Br&o >ӾM(oz>C$?T=ƧiqR@ }k$f?U'k J ;(?6&J:K>>o=1?RfԿK>?2`?/> (h??ib?me?$r ? aܰ <=z?N*=X"g>"?R?l>{]-b> >*?ogϞ8M+E=*>﵍?>?dw5U~9Qv?<غh~ JIf>=rzԾoC?1P<8ǿeN:b3> ʤF &G;b?9kU?EZ>̛ 4gt?G?> y3=$et֡R4e =vd==~о(AIϾxɸP- /?h#>fjOWA9K&uA7wV=X=V;>؈(>7J(.Lq1*? ?j1>?z qcS 8޾;Ѿh._==I syMj><,ÿO%p2h^=GT:f##6>w>7Sr9;==(3|)+g;C߿#5C~}VjQ;鸿,,ܽ&u=(db{p>!?9?X5?1L& $q==x ?)5tO>ne8?x8>>^nz>??>c?"]¶1X<>={c??Z>k}⵽ɿ4P. >L=:ީW O`P=XPYR!T?0Ecm>I_x,+5M=Wժ?dn>Y>MDx#@Y}e:aB$lʽϑSiU"}z=_PN?= >*c>3?D{g>==fZ=a? _#?=|>JZ??3v> ;˞lS +=(?dKM>ϧ> ^Y?8Kn%aſSZḄClT>?T>> y?[?Q? YJb=]=\D9%m>\C-9Z=w;>X>9 ?Ai@-ϧ>=S?]>?EJA ]X!2ʾlMsj?Ng;>"($HY4f?7a;>~[տF4VH-vO#VT/C/ ΢`BV2?` ?"E?dhh.p>C> >Eg?78=0_-;PVž(Կ'^xVIc Y= {n=>+p ==#R + 0 VKA־I@X!x8̕ӶFMBM3>9>??.|8?R>>KXK? ;+)mh-=&HFc澗i_|>bi!?Bп0p8@-k#=O{R<=w=>}s\(->'bʒ`>ײQ罍bE]=;AkϾBL>v{=L>3>I,> ?  =˖Zh羛eÖ=7om2vz :_Y}F KPn~<ɽƹ>psX=b>=վ>GM<.={?H->X>5j8fpF۾l#?%J>?pqPD >={?<Y 37W|F?ƾ.J=ɾA> J9SƆ>>&?A6\ہ;Ӿ=^ {>R1;+9>~>H?E/>xW>mK$ymyk髽t>:?Ho'FW=Lվ=oRR ><ٽ!_F>,@C>e=8>K ᾆ >r>j?.c.%.>;>\?(c?=y?VGxbȽ|L>2=?$Y k;yTʾƕt>9^<~±>"]B 㽴᤾] ؟\-;n{=ٝg?h>9Yn 4+,ԙ>{?eZ?}?1i>a?2Q??HX)μf?Y!?+?lYHH= >r<';t\H'L=?q.?SH?pT$??)p+D_= ??gU?vQ-(108??o~ ?(x2>=?#r"jHs}u >,=lH?)cwL!u J3?6& zͯ>>?ZVӽ ;^M˽H ع0qa~wh<>SV 9½҃EiTʾ7" ?yd>?=hQ3aSHnƾ=ydg{߿?">?9Dzz9*=E \K? yt?}ྯ>y~ ~r#:>Tm}0,s ewna *1N8eC#PWi=e]_+i.Q>>2?(@CpzʽAW?e>?:x)tּ2>U>I;~? zb!Y?'?l?"TL??⑎x>>f>I>}n? 'YD(]^6۾m=zO?Cţ=ꧽ]>>I;7U>=?,^KX;3xʚ>Y>f@!?I?B6$> >?PpY?(k{V`ھ!"|<+~Ys%¿P˾nLp8if^>]BD=ʾG$ CGT?VP "??c#5;[޿&i۽S zl`ͽn$XNxY }>=\3>K?UM?W?Bl2?]nz?iap?u/?cS@2nq>}Y=#b? p>Hr>`~>?:*_>xVW>4>U9>d,=frURvʿ!)U!r=vOЌ?>q>c#{ >prp}qȾy>-tE=VkDedD%9>%/=-Y>G6[=Cz>L=z^vF"V^1ntr8 ĸZP> c |IwEDTUe>tHtxU>k!= ?FgXo=y?&idicQ=1?odl{|lFi>(bF$=$-(?'}t4} _eVG>j%DJ$F<0. >8&J!B2>t>6=w?;c\D=л?+V/ Y;o7? >-4mH23=bF>}$$ M9!dA>HWP).`IH!SzH0[O>#;<4ʾ$>>n]?F.| t@6΍'NV羀>[6 -q5L~ā>6=e=>?{/^=$T޾6{?W2ʿJ6H?Ct?w?Lj?ߥn:.5=7? *:Pڳcӽ}gJ>9ߠ0A>N%DW X1k,lv-#>ײxfo ۿ> ,8Rpҽ<>g`©-侁d~>d$ ;{Sax^>c2ro5)R PcJKK6e=!) xԽM#NJ>]B`I=<얾$?. P qm Jׯ>?a>$(C]S2j>Y f >¾x#=,jgMb?A375,.?үLprGU>ǡ>?N/:uo>Z>8?%1.,>;?3KPB>)>Cz?f5?p>>4ύ?`Msx>|iLk>NJf$>cʾO>*@F=b0х>>o^ >koDKZ?%Wn*Pզf:?`NU |;)yI?KC'{NN%`=y(PN/9h=q(_c;Gǿr2n=v40!>p\;~i'?}!(j>ؾٿ>0ZֽLQV$>0'Bܾy>Pپ,h?@eMoؾ_R=9|?bX ̾>}> p?h?[C&nMR? = Xݾ?7v>\->i>ne9ڭ>=[ei}>T=A}?}X_o x)->>G?|h]b>-<9?s.=t>KWT_>F>204f,#^bXNĬ>Kt=Q?{oxھ%<>[E=+?}i-ξj ?5TO0"p?+aBH ~74]e?A2pp=Kf0v?VMuHR-0vi?,WPQ_DN}1*I?)'dFž6at??'&"0oQC9i4?/Ƚ~k#2/>K#pҾ6?P"qtjl^)Pe>!`۾>} ?l8 Ns)o>SB<~?M05ʾ(=X7. '?Xt8R :B?: e vm=mK?O6EFo=Ua [?R Nf>x!=?&5+-(i$>s=R{-?}IR E)U>`н`Ï?mA?*?hM?-O1؍?G d)7>=e^Az?),)BB>Y1&?aHݵ7ڿ3F>`$?41>8D"sPm3?\?;R>9Ӊ%7E?E'Z^#p ?'Y _e=𪾗 +?2a(TҾl=([>ZhQasVQ>x=iއ?bSe>r=h?bᤠ ;E׌CG6>K{` G>}>]?I]Tl>0%(?wYŻ̚D>㾀PU? rGq>Y׾wd?*ܠ&>.^="⾒?d><=?}`i@->n,g]t?"VcC1Կ+?? s[0GAȴ95¿7u>z#>X!P>+˾YW¹>?ZQ|?=hB{WbA>ʬ=n/?,sw?Id?j > = gx)w?N{8%8ݽ>?@J78>qbE?%t%ڽd>ڔ=f8?yw=+蟿*?؀tb$=BW> &J?&e8?I!Y"\>M9??B%1) p">3>սA9?ZS`>S? ,Z>H,,?l3|H⨾>?JX??۱Q?"u>Ǭ?^IvTtB_??>?ѰĿf~hB܇U?{[>S?L'0> u=W?|?92r7>Bzc>B?I* ?tKz6>.>d?]?z0zݺF2D*>,s?WS?+NEKo? ?|??Fm_`[?DR?G޾ v =>lLG?ML =ٚ X?XP7aUHn0M{'{|W<=8 Z<>6=)?쿮G=br[?w79 !b=p@ ]d?. 6 龚;޾SH>}F뢾L#>$I[{?16t=MRm?>qNV>d D>8a=:?&noH >?žN$W>K>o>jwGPp>R1Η>/plD%>?.4"͉>4 t?΁OK澬<4k0?IZjDy \}>Y=ޜ׬8 >#O!ԦAm=8P+>=p>]8½>&_>Iu? ?;75=m<>6>yA0#ľ>C? +?zaU>_Bxu;l?,-Y`>'1 X?B$ԽOaV?K8?0Ĺ諾~>>|si}(1x VJwv?=M?U;F8=ξ>̡`638D==Io=ۢ<ޱe4EDG]ѿLʾ5y]Ms[s5$t3ǻ?tY3㬾hl>g~0&by [?%[;@ >;?L6Wp>uurBI8eHO%|W?p?Fh>\=?s9E>~> c?h+i(旯Xȉ?v9Ҿ>>A?U`VJv:?&~c? ZK>BR>-6){>E{>͸5=rbM N>=?^a?о.ľǾD?F}-*>?$k>h90ݽ>#?Ls>dʒ4>շ?+<>!-GPcg>~>>..UQܐ=f4?J3;g#Ⱦ>Ɔ=n3oNrM? ?&( ,; ]f?1@ A=ۥ= pa6?`x)=\> q~<N[>|t?'g ܧ=L-5>LsMkv>>8m>>>yJpq>?kU>eP0>Ȫ>fQ =ީeu?Fſ>w="z%xz@X*qr&. ̜=$ af>[A-w>&!*+ >ӮVM>QI@!>MfWٮ=<]B>>vޖ0>d<ʺ8>ܼ9=:]>rq>?6>Vʴ3ѾvRy}>I;YG^>wKJ@>nMܺ>Tc,>k3)>vjQY>?K5ɣW2={}>> 5@_ O< 6_^Al>?>>\?di> ?HWo?S?u?:VE,߽5? "R@0\< 1_>v0Pe|YCu'cLݔ$[ukaؼ̎iZ7io.Ǻ>Nģ=Օ z7ץ>=^?}=hMq7a>7 =?*<$%jm=`6O(+zdSҿ#QGE°Y۾0<\a&;%%$c&>:wZI#ߑ_F> 6 >x4>'&ξvKw\j(`W+>=hѾ8&>rRE ƺ u򛮿 am02pLC-K0>]68>*Vꅾc=*9/<8DxiܫHFpɾ>KBJ`#Qi=b__>7GkyrDD$: >8+0Fz>b=>)L4?= F.OU=}޿+S.``:Ӥ=/4]i>h{ 2= =T[޵:$*傾'ޡ@cz>+=KϿN׿9Zۿ~J>響.X.?r.ޜڵ>i}H|Xf<=!ٿ :)&;޾٩=q:ɣ?t2ǐi=Q|_/n? xh<$D'qQ>6;C>0Cpq>o; 1{>R"q\x>(ǾDV>%1> f>휮xuP>={1;>*c]_+C݂>,'9|lR"KX2ؿ*PP c >MK)Aj #t>xݾl>>D>^?:> fQ>ڲ>Q>hl??p`w>!ĿfRL.O%HH\-> fN٨O"[lϿXPj'#oWIk>j I#*мdoA_>yz=/ja=]>,`sm>8P=#>I%u$a>>d Z?]/οJdB(þ4>G>?c Hp3Q,>>q?i R.y.>Q>5?gF՞mih< p?\-! e>s4=?7쫽.h >%J}A>!}DJ=W&ov2 rIL!~59=Ǘ@5V"6dpھÍ?>McERp=IN]_`薹D,@"d=$=>zS3)kpx_=S~@tcM>I%xi ەվz=i&3pf.˾>P'$>@J;> >DN? &4<.%v.> =>ӐP(>r̿us`Qʾu7o߲)>v ]K2H?!͹PpH>]ᨾE>\ ?0dIO˒>3/*<:q >AzFվ˒Ċz=/Dp~͢/Q0xJh﷿dVqQƿو91JYwL=07>c <U>&_m^_+ܾ(>Bv\.EHj>>_i9G|n>[Pn1-# q?=c0tCԼSznI>I*_誻5>hU>2{p>L&]=y>l>(>&>;p~=".^]r K+Oۼ[ <5o&]Wͯ_|2L޺ ^;rhg'>aU==>@0<H<'»E/%33ݽb ܿHGo7BQ=_ȿ%vr)ذ޾Ծ k{2|:=bG?:H5Ѣ=ԿKG龭P?GD?=Զ*V蟾iM%$W";]* ?S.a=x-I_O@>M.A? -hmPGǰ>_:yZ7Bqں>IT*7<{?vD4:='Y=JVf0q2Q¾nۢ{ [úeֿa'Xgm=㴾뉔 Ԫ=h<ͺԿ2QGKw[F>.^tN {Jo}1۾_#;IDl=3!VK7׾#s\+>8?R,E=r?$l==;CkG(4P?&x}Ac> àa?$?l;?>9P sj= f{> ITn=%ڿr>7m* \w%G `KI L0%Ⱦ=Guh`)X\w dؾ}LZ((Љ9޾(d Rz>>'j/* C ¿~X=\L'M'ό?Gc >X!)I熿kR>Jqi>ʞ1J??֦)9?[׋>ǿ/Ao߿Ŀ>_,0^$Qv5Z>_egǾ (n HYɾa}]aNf?H]q-i.IL>_5 d!>HL7> kQ V)߃d[>|Pĵ>ѻϾ#.8{ڔP~Y{J?Ž'J%x=*,P">0jcq#R?l%ľڴS=60O冿 0j@Q>0=/. >{!=k>kwɵch ߿a>Ҿ@(_}U\>Fd>W.>>>>s׾@7m>?;7.#:>Fc>9ھ+^z]>ǰ2>=,7I>>5:?~Pv>zrϭ>Fg)'-?炿][>Ϛ$YS>4¾Ԣ>!0f!>?a)$=@?9{B>[ޏ>wƿV&CW<%?M$EXm>>0?>Ѿ ? K=aZ>+$<_1!~>|< 5$BF?PU=&?>7&>6X?cRÿ%-j=L>ܗ?E>. >c=J[`? 'Ծ%W=ۮ.>Id=>?AC") CO>ֻ-F?=#-QeϿW>=?_r ڿa=>Zn3?i&WA}|9mC? e#qn>WU>j?Q?a%>Z><&?V_>#>=X:?C;]>mK=CE>8/?ik۽`x;2=pM۽w?& w`_._x >Ol?q_H$>m_=xFLLpF?="˽}ȸ<͖ ?TKc=oN@>dž>' K>\Wx9)=5=>|?]W>M>>E‮K*|WBu<>(Ĺ6=q:ֿY2ח*ia-(?Z9_RD+iI߹?HLy3=3wA,knvZ3;7~XI˿6U`&=|?q~xBp1TqmU=`.?d@WPLT>?=.HO9>%?V> eB0ླݘ>(?d>3(h4aw;A?[4U2C*?#X^zzwO>Ζ>},f:?o^?I6>ܠz<??*?8JA/hٽ<$>vt5/:4BξT>ė?3>sHEk>?=j{ fJý}>E=?=bkm|-^ru`?A?dE?z}~e8a?q?Oj>O@v` ???9>t6c> (>D}?~C5}B6? ?8]dp>=⾎́()>t[m>DA"3\l;Jj>}:8>?;Ӿ>I1]>+c>?z)=l=Ra>>U?|tYhd}H/=¿ s!vmtJ>|WP?BTq(Q{>>b?ɂ>3ϿlȬ>O{?#4?s>o- 1=^ G?T;N@V ; ?*P@W%>E YyV E>xԾ{>E=iQ5>E!޾)d{x|?^.?/?$}P?a?}?>#]=+?Fy?T>b}pPa>s?i%>|SULV =??W= ֮JPX=S;aW!ER=&U *9 ]Q=̋ʿ> x”iJ<Ƅ <E?C/f?>Z =>??,?-2{-0;(?T ?R>e ߍ0>?>2P8sP>nD=>.P$D}p?l'=9 ;8ZO1=!>WCHb);ڡ~qo\A?"?na|=Z1@=9i΅  V?>:K d=D֖_8J8P=3Kxܾ 0sl';< ?t ?z?@*= @0%ҔZ3 |/|#Re>jpnP)? l@oMG23n{r4=渷1bMn4co%x>L"޿S 8 r¡?A:;z>vG>w>M=ɿg'Հ=_GHݿc>=g>KAN?k > #6>?F iŏ>r%=uOՙ7T>yg>?>x>ִPҀ*=?RH>d=k7u>*#:?{7>>r>1V2s;5!v> ?*?>d>? ?/?4a>˼>R2/.>d[=8?in>ꛍ>C }N??4?y"?g?j ?a&A=]> U|b|>\F??~>=>c>ghZ?i>Fo>H(*ツC5?;y?#D?V.G ?? \?lam>P<(*77췾Y>l -72 sCLϽl} ur<@!pXS\P 2&=VӋ&Ԋjs=y@f 5={Pnn> ? *Ww!:>VA\) N?q>[> _gAN?B=:?H? ?"ŜR?R5>&X>پH=r?=I/>Z@J=1S*(Uί9<*Y5rZ:`i1(ep2 >m>'J߽)<`8=3-47M#5FMS>!2↾>1&T)=2ӿLk߽{{@J>0]"d@ K%sn=Z JN+ܾu )=D\J;Mr6W=11|&Wf=ta1ƀp=qV8# Mp])xI#kWdIh$ *ؿJpXy M @1H_+<,2L_*?ۡn?ǰ?Βp@VGN>/ʽt>!YT"=w[})=k`A-H>)tW 7a;*kRn!07;ܱFҿ1\[5 `Xjf%XJ Or".Jo>҃ ???>K52,{RþHRZCw\^ў ?y}5>M۾ п!.>?g4?q?vY+Q>v??c?M俗R)>b?/?}m?_~⾕rE K>#Y˼׿[#^h.%j#P1iA?EPJ>~=9GH+>qC|?])?Y!?utCľd$>s(R㻗gzlSB=TE,iM/(`=ABFik&>h?b?[?$>%?’?o?M%>(֑??*5?K:$=*??}0{?g'4>4??V?ҀԾ0nq>5{079G#C> FW?pUh>9Q>-Q< v>g[)ヌ>";z? (@,7 L>Z-ݰ,=m;m>⃐1i2n7霿=B|X#9 7U5.ȣ6۾>K~ܱ"*?N1?D6;f =6DS9pHtQQ`~h¿8nѿR:Я=ih; lTT.}S= X=|"(??2? ׈"zW?S׀? p`\]<jns:GT=<Ҁ=^X#}_wEM=7h¿Yսg?b?@$``?e?*#?O,? Z}1?f}_?C_Sa?P??>u:Ƥ,/<=z$֑!7b> @xN)V.Rqz>vm2R5dH&?@{ts)/o<ڍ뽵?e| 0i~3B/>{* Oo$>xtFVC=yZ?"L`|'cP$#>B }׽jj>̏24˙"u=ț"/Ev<fQiȯ>{>پM{cJ>Xlz6ֽ<?lm6'tH=L8F?\?ˁl=i$N|򽒄NS?zS8CAGvr>Բt4c8>3t=ކ1z?_h>&=@4?ke>>7Y=fG? ?)Z;@˽!3¾j>;VμakQz?zWܯ\pWoq>>aؾ`>wL.4{=־by>ǂ*Ϡ4|Đ> ##b޽@I>sEJ@ UI= />R{G6 QeG.Fо>ZEgjxݿ Ü>6TP:H4LY>f9V@WdS>*GXO F>(  Bw!=zJG=6r1#^M>en>UJ)Z>Oqw> JÃy>˘DHb}xyӑ>M"hw ;up>:߂Ͼ>33fvdUQ߼>=(?w C[@=4+=W>8+QxFD>sH]2jR?l ,OfG.T>3.@Ov=o~QKZk2ST8*"Q02M?LEX$fD~J;Pn?iEG>]w0=6!%w@>7ٿKL#W 9}>N>lMHV_`s>ʗߨ:Hs U l>[!> (>:ɿ 0>@>dhtꎿN>\tA:!x=#]h-7?Q->C̿,l}%=/0= +o&=yS S򔡽C&[M>K Z>]?OA>:?-\}wIF'9?/[d+R:\>b=?vPx$#F~=`lզ?Pg q<>t=^?Hmr= X/Q>$'!l-;BǾmJ> uƬ?K+@ =q%ݾ>K6>aw+:j&=ljW?DNP垨F+k>?5x]D>=?@$=;yS`ٿ4 >́q?θ=^$&̿Z6 >Z)>Q"M>H =rm@^<2Կ#WM>+g 0!˜3%>'8<I?Nlũ? ؾ( 1")c>þ4᤽?+Y]_-q  B> 1hp6Y!- (6KSu ?1RO Y=ھ?DrmhLT;>)(>%?sA)b?Bde&=ؾ?RE?>f>H8;?sA/?,;O>?Iݯ%S? >(V?6e'a|>hj?rp s=#I?bpj<n>颃>J>>,<n]?I?y>uU=(̾kT\?Zqp ?y?j -?4m EnN=*T?$k'?>%0v>dq?0?p78P[w=Q>?(3/L}A%=((2#Q`>?>n0>L*IJ>膿e>iGxoL><9z>:*Hz+2>܁ v>|N{X >x>rf1p?i=>vAvWu?LN$A>J=J>(tܕS>66m'?u?K)onpv?>sT;? NP76>=ժn?nӕN5^z>!-w<.I>ww\? ;P->q ը߾W?2t-d#:>q\(?8hǼ>-s?- Vo >Pٻ8?Jy^r>Wi_?7?\??W2$?_?Jdh^$?Y@?57?+>wRTV*͊?;,?r?Ww?WWA@'|?3\(PN%>Yz?f>Ye?z=a>'>i?K!>%!f/b?SR<>*}>&?Ø >F>$FxP?rݐ%>dC>:=??<-m?+Aa?ERF5{+P=>ßM9qq\R>k?[>BBBB%cMy̾sP=Q?,Nb?uuJЫ>Ft?UAc?B>-6m?> ;=S$mp?9eM2A;=>T?Un?kG!+DX;z? l?r-Q?C2D>@rp |T;œ+>H@S@ks_? j"d=PPM.?K.\l!|8 /pj}>1q9>-R;շ?#Oұ>~p=ҾN?PR?ƨ>\=l?D$Il\ھ\܇i?|o> y&g>ޓ5:=>LR>?¾F>$w#>ڿ=vGm:?lC>c1>B"\l4't>n<&>kzKD?&=j>D#F?Gܿ"n>LǾ¿+>ۿg>>*>?#?&jB0ʾ1=W.>>>3gEԌu >r>fm/0( >Z?2}5?)80ܿ,|>/?.?' _k0i w>Ff?f0?y5- $RL]y>ZW0E=]>>>9=˜>S?(?*H7wȆ > ȁ1pk>>$>[v2 R/TJb>=\! FC!=ղ(?b+B89TL>8r@ hZտiEgN9xG98XNeg6 -=> ۧ :[V@=Q=&4߽;oL> OC:/?" n܆Ƚ[X>BJ<H/4I/F93[:0?O'M\%A"37>4%s9G<sȃ4;RB=>9>s??MA;,A5>e ؿ'>r_=u=}[G=6 ~m>tm@j">ވ!/>㓾ס>s(C=M=~B=\G?);k> 2;1>2hӽ3ʾ?},z=X=0Mz7>{PT 4<:/o?&ֈ <1@>Ň/l$:8{S;̯jw4G.>Z{ )z?t'@*@Y\g-#I{=Z#>] >ҷ0؈P>oD>/ ?>kBM4>R>0C>1W/{>\:Pʂ>"G=hk;?U>w>WCc>&JE򼽍u>0?>hCKJ(@=θ35?߿<>WQv?Nz>=X=(#>d>R\x"ui}̾|ZSAl?7q>]-H ;?|??kJNg?&?(Y>/- oӻ~^Q Ղ>z>C>y}>O;!?%`>.Pij8>mL5ܾq>e3|o> g;A ?v >eQ>~\?Zcɹ=J=M׾Jk? A9?;<ҿ.89CxQR䰽-=k?bDj]>;Z~#Ke$١7=MYӿL2#r}>juSI&4= AJw˾нTVU(PRVz- VagO04+DN>0f$`۽vh'^tU.'<M$ͯx=~9.Ez-y,>MiMʬ NQФe;=#>bZL[o$>>Ju=ћN>>L[߹ݰ[=uy=#$ \5.Q=PIҿ9z=+f0>ThE+fx>X=H? >0;gQeVǿB>Nk2-3K{w =P8\a= OX=:H0 BvuOe! *F>?,<6Vi>=9rjw=.0'eˠ>jYCKQ>KdѾ}t~>!aM>I=7>~Z>>-B<{P%齔E"YT= C8O^O˽> ?>7CA W>*=}p3mB_];ꍨgĽ?\ɼmzm@>]M?JA >yU#9K.=?4>?a>v&_;F=Ji{>!?+wao90=>C?8 iT<{=Xq08>6Y7&{X >>T?:7_%U3>0>?tk8%ƾcA<Ъ`b ?KyT$jȾB>Q=?2A:0ȑ޾E2ߓ_>/;!x^ >}ِ*>"9*CaKF9fͽfk>Va3=/=<?->n9=u?E>EҾ+Z>ѰE"6mzW>PT,;r=\]<-?”2h!0a>O 2tdǝZW=q=? >c55 'خǏOe=w =z lP>(>>B*?6Ŷ >T>Ƌ?A"dGN;sҼͭ2 H>|)<>U"=ޔ?+~3>,> _?7@`Ba<.ξ6>q+?Q<3.MG"auѿ͊D|3@=d>g>n1>wDG׿y`G!>anz=?4n2b=~z#3DBտsCvQ>3<m3>CNg%>=>Snp>İ># ?~ D8'I?A4z/,;uS'J,1<R1xV"K27ۇ{>x}= _;>Iƿ>s >]sK ^Ս/!\ ќڗ]ϚdZށ>xľ U|>[l=!SX>棜BN=;pYȆ>w6\GV>a>%h?H5d5ѿ{TWB&vwվC8;8<0j>ESi7 [~>dT޽SM?$w=һ>c>:=Ѿ:&^^$,f龕TھĤ >eÿ*;mV>y>? >Rpa4^N? Κ>`?9 N# ̿H磾3o~'Nw2+ Oآfl>G^4Pl#3=Ž={>G6b<כ"HG/4; 5|Ao#FN\ 1$⽢Xx@=D> H?=N+RI)>D=7'̿dĩi2KN| >Ӯh2[>Na~4}Z\h>y-Z佪)x>/{y;mQLU)Ru>ͿgܿC}(^==t-ϼ}=>48 LĽ=.ɾo㽮&տM&1VoȾ!9mH/'N N>񍿠=6iլty =<>&MX^" Kj?>2O$ qdċ:ԆjpZj>Z=n<;>G0j?>>M>I?!9`>qm>#=g >Pe u<ѦPw1W$H=Hk߿Filc>&8;&Hؾ-cE^n5>mef>ut}t>b/'!IQW=fܿEp?]:=٭$"Ot?OI{=>=Z;f@pXw@V>1i¿5~z?X97i{=7'ԿRt|?f>3w6=*|,ᓿUDQU?u7I>~$=;v?Q4z<>!:*NI`J^{!տS9;eTP 5JTX4Wnq5%naq=n)>mظ?N3v%>zqx>po5;LibKj{Rk>̿_y`% V>n9?W1>-M?D˾S?to?>~DrG4<ͧQ0GÿB~&D+e< $غ?%"?)Jc ÿL|cb8  1^=A{y WּڿIՉ' ,y;u (k}sKjo3I!@->@Y!L0x  2ew7T>:*ֿM`ru]r0"2?BKhQUl ӿ*kE~h0>zտY`߱(+? GQT<ރ==fk>oHIV!%a>@}N,=hke>E*]F=#>+Q$"$>y B>./  {5?I.=U\-S #>=_;`Ϳ\t>Š> =Y=޿CL=G3/>5z=U$!=?>R>k=Hj=? >=B(H=Kȿ>W l\}S>]>DUmtqC=MWY>\țˎ0?ވ>Q !>7i@ As?p=?"ܾ@]>Jk(>?D=H=s>>a龗>W= m;?rp?>: ;~>徠5 "S>5?A. $>o> >l?X=̾P_S=Q=J?<盼1>Ȭ>%_?#a 쿀m=ʛо>?fGr=|پYm>.N?^G>>ܾ D|z<̚u>h:*| =YG\=-+ҦH8>=@?R0ׅs=>{?hlP¾s8q$? ( zIl@Ѽ"?3kn@$_. ? z썿y|=w>9>ܽ,Mc>[?hƽLʸ>G>>HϾX/ տ>u<=^>e}>툠>Dcnbt?!^>c>Q7صI~3=ނQ?B\rOf#%<";/E?NݾRsT=ͼ<>⾉h@>i>)] }=Yfdb_>$ >_=d>R>1#q޾ߏ?J]>>8>*8ץ)o?;辛#f; G,=]R{&|?!ڣ} ]_ٽ]13?QK >&>Du [R! +=)߾Sk>4 8ͧX.jkv}>g?>|pD=Tď>H4>>^ 2>7>R>fIhW=ؖ?*3Yv@o=ǾuH$V ~ma =Cj½"}"ȿfd>((>* /~f=>J&3 _Ǘ>k=:(cܝƀc>'="0>>k|{HMlO []>>L^-$wyt짾8|cPAd-E:>P:~66 =?v旽On:%ǂ>5?<1th H?'پz>:_=M>@_>; RZ!?nHp>–>ɾ>J`6>yQ@=G ,b)` g=(cOQ>CEqẂ?!?=ҍs[.>1 =劾j'Xh2+? >%;˷`iu:}F>L>ژ:J?^#`"= !}dnj>(>BC4'G=>V0?";/Y%?M>?H?J4?þFm>_[?W!?ܔ%?'oRK C=@?[mEK `=Q?W CosF;=<6FYLy3 dC4>ⰾK>qiJ>ʨ"7w->o>fꅿ*Կ]? 7e'> W~YJPH=`|>c\j>؍ ,D jY7s/>Uþj?K><4lpOEF34{mD`5>lA~Ae=U r7\RFA4=TmcYuAXA> :iEBIkf>>GCŽ?7P¾hKt>_k=۪?WG@y` m,=>?[~N^.n kn<`=׮X]r`';<ӵKURk>оؿ+ 2YRO= {J?e˫+IZB+>G=?~c=e5DM`>6$>"?>_9خ=j}9Ӿ,E?Cᦼf!}( }Fa=3iYU.1'տe$|>2ST?qgr>MH;>GA-T1e]j=??&?EV~EL=R$%?x 1?0?3qW{j۽3?5?>0J>?Zu> ~Xzc= ?[=uy S<=?Y<=ͦay"<&UFN>Ah?n>7-S>?bZ>U7m0Wa̾0>%B6(]?$j??^/0 &?>'?5D?>6W \AJ>㿃Z{ݿm>ı>r9\B䰿Lr-;K=?j $?$?~'c-C>Z:?kj>w8N`3 V>?~A>z0әf4?drw=)͖aC9>6>DC >(ҽ`>\[ BF_ԛ>Y)*ƾG1MO=hٿ&/#>gԾE?)>f ~>6,<^. >Y6PȂZ=p?5?%t?Yhy=i?? ?^4=l0C޾hr5=E 5iU x @"`=Wg) * 7=(=V<>íQ =PDnGn=ceefa= /Z!\g`Nh6t:{H>eӿalIl>"?s?>ڳ,ʄ>y7>^<0>S<>Vk>"6=O>\F&@ b>> H>\׌CR~'g>>j4P ľSgwh> ?q?Q?8\94pL1#ٿZ]3>d=x )M>hp />Sz>~A>E=t??Q>;?8y>V?}?.?q{'B?G?-D?,͖ ?@R>=g>ma%?]>R? ^N?O4?ti>}>%)h3`a?ۃ?G(?4(N`3!zO۾ vamL=i#^Uq/>ә=C>y$pR-={Tz:z<@=¿Z*_>,N?!nCο*؀Zvr>r!qA0.!FqP#d?p?F"p?&1z@4kJ*NWCi1 0½@C%DYr9w= /#O@=$1xh0fb^=D??>OAg?W6>Z>b 6*=c7Pz>U|03>=GZ.wG`_#>7 C??>OU>y GV(?O{?h,?G:$Q+??hes?>MM<?0?+?JZ=~S"5HUL˾祏>]wND>?!!np.>VBo?:Y?f>$:C CaW-M=N???FO *Kfeb?>PnpʾjfO7I=w?M?f?n-s-Z}A};~? ?L?Jnd@>-IaiXS>y^P=>[?B>Yt; ?Bj<eZ>!b=jA=s[ 2=C 8.3&uȿ+'KmrIA<nY?3?q?26(<`??- ?3Ɋ@xCYuTX3">%h{]𾔃I>}5eP|8m "ݿ<9Qu1}=??**o?:x8ш7HR>RlK %Mrz`l9w@/S9dcW #=ws>E8D,㿍=(Hf$>><>,JHo[ ,!B8`x(eHjOcpJc]XX&="վ_>O;h)FV>Q??x?:byJ%> 8X??܇?G']%>?"?^?B Jޔοݺ j iD>>hBt+V}>ƿN>辍ȿc>>v?%cx>~ >=:>$ S >;B_g#B??H2?op`<}04E!eu5x4k,4¾">K3s>VϾſ>⹽ Ut?j@?_5kؐ?:Ct%o%p?wpP?v?#V?7?/ǟ; J RD>RN[<&py=zfP?(m9?D5t<?y Ͼe>X?>/?]rDbq%𾄏>3 p?[t$!>X?x?aGfǽ cQ>ȗk3 ߾><Ȩb!?P~>#pjeR(>U <ñes1bk?|!MK=ѷ=":?^5Xxr=_P]<4/?KC!"KCz4;UKgR+M+<#mXaX1%о_>6i>iL>uL~>aM>e=G?P܇A;*>=ALf?@'PUھO >g>3?M d>5=MI? 4K}y}0>>Y?j PtfUپGc?c0o43=< Vn?t@M=8ž}>C/<RR> %H$ ٥}>wZM?ںF~׾D]>W?#dEf۾PS촍>8d E4>c[ݾLeؿgZ>P/B3/iD>1Õ=71y>x g>J ;2?!>"#u >M>>P?al./='ULcξz =>Nt8qv)>pq;w'P=@?-1m>L )V6% ;jdؾ3kX!KO=`q=e#f?d'~==н`?84@X=矿.|]~ǟf>&l>Dh'Y曾8H|?go >/=>l>ξڿ=kr?ZjɋP1+>XA DQ?0>v?IPi둴>>x?0R+hZ=Ah2?N!el>=>P]?q6r,PcN>t>=زd?@7>p?*>4?ӑJw>@>o?POs> >ZjD?@=# >,>&?Q`>3NJ? ҍ3>g˴ k{>?>?{N>.W? >ɾ9">om١k>ɃƬ(Ź>G. ==-&pb>VT( =$}>#S<>k=]?uWxBMsK?1YRSaϾE7]>`5> ?%a_ʦLs?'YA>:9v-=]="l=08KMpxu=Ol'>!׿a,>'̀7>$ɾI5>Kh=B1P,,>K G&>ο2+|>U\=[>}l׿\>B>0L$>ؾR>H>G?Y7 W%? 0DFD TaCY?2x)W#[\?$0>۽ͧ>?Ql 4oziK=cx?>wpNþ'>b>?ZNh^*+wNU~?1IpǾD)Um?lvX*P>K1<Ĝ>5_F?q 95@O=L? ɂY{j=YR/?V ḀE?i4@?ABpN5DcX&:뾄,?Emp?rPc>{=?@m?F=q-<Ú3='پUY?PKM6r9v==*?](3B=Q ?c9>aS>%>y~x?T>=Hgg ?|=y>*n>Qna˿8e4=yFrW><}f[r> @,E@=/ ?'i:?A??i|?F\a9ʾS>ٙm?0`_@0<>Z?UX4P;!eE4Y>ʰC)[1;]FB9? Tp >4>O=ЬНkF2>!>)c/->uyƨ g>YH=ZO?d!֖>f˾jw?fp"zh>t/Rm)?Lfg?:>p? :\\5YھxٿG>>?zUFQ<G>aEcUHÿ;">ky3fwS>=?ԑ{=S>> F? D<Ͻu=><^?C .N>=ýDۜ?DI?Mn>P.=Xc*?}kv4<>jœu熿)?! kL>޾渾?6?KO;}>d?.R?vtmHTVsu>>ز?1Bl)|y>UZ?Q?t(]J7ž> ?k?N>j@&4?̴Z.b!B?"xy}Cx6o2"P,֭T1}͚1?PCe0쾝vG >~LԚ#>D79W:&S> 5=>kv=F!l?qܿE]=w?"?n9?6YuE]?>ـ= XCڿBw>mR7=m߿0w>ё=Sp>w?19`Ikʿ7=Khy q_#2';Y=ֳfH ;";Z=}`Aվܿ>M|D>1'cǾ*82?,Y#(@>C>-;eZ?G9,|=KӾʼnHc>a'ǽ:5U,k=T3(d=ΝR3f6؍ @±=ؾ׿9j>7m>M> {>fGR?RS>p:t?$GNDPݽԿ3/~>+>8ľ? d=犾ɫ-> x0<c9_>jM/`4U\4nƛZ>˖Fa=MD>>:?8d Ѿ뼿Iw>>2=,4>$?e?!~C>?B5?^?\2-bxR>j>eǴ2en"+M8=?ՁçT1>i ;DP7$?-!=W&p>]Nl=1XYdgL<*G~1_Vr>Pxr/<]E̿ :>C,j5h/&l!9>H"mCY:&>օ>q?Ϟ#>Q{t>ϼ7@+W=2tL8?YR;>*$=KWsbļHT4}ݾE<6)x]4(Ⱦ0=:io6.v"Ѿ[}yj6 U>eGf,+?4Pjc.cM>/Q4?6r 5H柾wdT7 '&ŏcC__,0"?2>~=|?jU`Ȳ0?>B;e-?`k'Z0G.!>й(>Ø?(;T+3?'c=RH\?C?` >I뎾3 s?!Kvt%H>9u3PL6z>G*'nj>p =n?8;8P@>N@=HE??30~>^x>9I?M0"j=7 ?H-`ƻ=Ơ&?Bre<Ãe#a_r7>U=g=Tھ|c>:U>FU7 >u>,>xl37?`eD3, c=V:w39Y E|ԾP>P>)@1>rpU.^?d>3Ӿʟ?7MV'5~>ߖ?u >@=̾w>L]s>k;>pm*=gTh> F> "pr>iN%11fW>I=svF/ t$w>xo>.ݿ|N=JGXQ">>b=#RR> yum=yJM)>:^*SxޗHĊ"> X¼bqu>pHU>-=:T,(=?=-(>Yk*Pn>LS>>/r.?:(Ӏ=[-Bnοy;5>k\"umH$\>'dI8~[!D­X={&|,hft־8V0h=*~>!㨾c@C)R;zh>AUr<\=!v޿ wSoE U$jYE>eR]]⾞X?.jD)Ibkh?`?:=A>! ?M>`09 dP=ưپAi>DX#EJ>>\KW\μ&WxC"Ky"%$Ы@Ǽ ~9J+ѫ)XMfb%q BTZN3j$dE>1:=% D=9=33:!L4 =5qeSXa3 >J>2-? ">I> \W>? [>hxɂ0=f)ǿiMn@<Z40˾ט1`7S[!{|$$Rɓq>N>ڶ?d=u%E>>B?5VP4Z=S>?X\>C&An7Duc4a%|tc)wdE1~9pB:(V ؿz>ot.dc]P#Pֲ3j(>kͦ!O:8,.Z=;X?+9L>6rI>Px; ގx>v޾$+6ڊqþRμ= .mW=f4b[پ?Ln׿ģڲY}ĔO;+YGlx*u*u>*ߓ>* _bH>LfO4P> mAQ>~=~A?i}y>Y~4k>I;cr>q=4 a>ў%e|5"d/f旯iKiyqѧb>Tbqk@>s<`K=?nw >ScqٿiI=Vel_'g^=6Lȿ{;d:{VO>Mq0$-H>8z@\w>y=x">%>?KUe)=]Wۿ&9`k{]J>6rR|,qMܢ=:|3UXf[/ʹ u&n'iRhM4mxyɿw}&Zv.ڭM}Bݭu 8+> :@=6L+&=n‹>=|N>DҰ=MAW8@ !WU=7޿ 3j׾I. ` q2nC©aΣ-뾀M|/s"%t'YS7vO#X~>&=>P>>s>_>a^Dֲ`>TRX>P5]D{{mۙ*+#2MQ+-k=L<@?IJ'x>ÿ*ͿW ta> NS> ;JT >Sy?<<+/=t!!:")|=v_T3'͚eD>Ur޿ m_4U"X>􄿂H\IE n?C=4_ [>d@MF=h@|$ݎE >廤 _dN>F}0H>]>M >QZ}6UQoXAQË gq=|  u0>KXゾGm 5(Ō =žI;9~龷˾}F]0.|T1YXz> 9Ҿꎾ\B|zg> ^ڿ`_+_"8>n̾ 7ڿJCgE>N׾1-4<쿯p2>z=c:y*a> տ3Cza{>^`(vl=DhTG ]>%ϿžmC<.Nr>RHNP>T%}>N˸羘@#/=ޜ*{>?ZB > @.?z>9N>.M!gGvOYZU}|HW.vq~[ܾ<;O<[ߏݿ>O>_?J=S>ۿĿ" [y<?ADY>*&jLQҿ~՗<.ֿUھ4exS+>pKv?/'߹ڌ`v*B =m>8\>W&%; T\JR] \_ :y !`0OV{$=e^ܱb#QU M}y~9 JQ>LFR|qֽX^e|KꁿU=kIZ ؾ$M&MQ==\>"u>><)=ۼvE =U>'M^> >>y>?>>0?ؚ>x>D?D&Fe%?--(>?B>/L+?D:|=?|[>>y?r>:?B>W??o>e?;ϾϹ>3$B (?1> ,??>,>B ٪7>=?k>έ3D>˽. ?( ? >+>hʂ?e>z(ǂ*2EA>K =PtLY><?#}R>`{=$ݾ{O>.U#^\D9n>{?0?`>gy>??9=?xĠ>8>z_?2v =T\qG?2ؾo}>m+,>s?(IyVu>þ"?2x?>O<?N(av=P _>=>!Y} Y> m%?)"O]+>w<->Gce=r#>þh@ѾCnr< 䌼R|8;6˿߿ >Z1 ?,O@jv>=Ж= p?SK!un>^SA̿rX tLNR? ,k]>>dʽh`8>2>C>V;X3 ?> ؙ? ?be(>/>տ=ھPr` c=bh]y@=Rj8>pfP6ʽI>?B%c"7U?)$=4/r3_p=@B_Հ>=dhqL$a1;f>1?5~.lbg(p5=P?9`D.>k3k& l%>fI75q 'Xyľ+>Ų- B&ε@>$=,H>ZP>u>Ef"}Yc/{>>EG[$ =FR۾7FW_b>qckm:?]rK=4;cI9>Y;}=*~V XrK>V> 2YN05e:*?*Vz a>U?/>$5)9Խr=?&;mv\\:=ýXq?*ž#[:~aB<L>>e?i򈼭QUl ,)?O?=>7HJ2Q==?jwI] ž_i?!XEkhumd7>߸w0[:Z;>?ݾHmھܥ??.?b'JwA>nJZþ/8?>;?s>:\ ߃1;8HH g^=r.w`*ЬKUi> Ѿ:4@V?3Xm|gS)V+wLqs2>z>:>%J{_={WvžDa >#F]h#}<֟IA>ƿ%zN> >cD.,I}˛=?@?'?,2D*?> ?@??NN$ue=GB? ?Iѳ>Zh$,>}|?\>%plam+Z?i?7?>,om-Ǿo*??}RN j2d^>y?N >׮Kp"%⽹ɾD7?B\>E>Or|4 qĠ>u>Ծ*I;p m>{d# x^Dy`;>4?;K?-?yOK>~X?y?{2?3و-}=#i=א, О?KVB|6d }>!(9M;+͇_>, |@1>aIL'4뗻JNF=i?K??TNH8~<]ܥ ؿ=Ia=:zaœYCD?D?a:?\f㏽Ձ?=?1l?wrr;$~?Hl>>(b="d??&(?lVqW*':<6+=ֿFn'oa:>.lUսBW=a0s=D]ȽYQ@<ɰpv>Z R =r~9u}[?fb>s?bO;Qz?>c?)}|մ߽;?JC>>Y}J7A?*;Ly>>˾7yB-Ξ^?D>L>w/便  ? =횿C pW=_y-#fT>;e#<@p=gW^lm>?Q?6OU?E +>=<><:>[y>˕>  v}?#RyE>ȿ.Yё;$o-}<ƀ )>-0=M 8PCѲ>U=8Ne+o]%Xm=ř[USh't>Tm:Тipu>//rcso2#W? x>7}>i.+T TyP6w??U>2J(3ٙU־^0ֻ | ‰&|?]e> >ߕif?zd?2>;'8Y??%6? n^?,?r?Ml,bn?If?I'? Lj\`FZ?7?;ax?5&>7);:1 <@rK {FC+Cؿ({<\^/%#s??Xs?6 @=F8h\Ԁ>y=GYv{?0.>,HK?Ͼ?(t?S?( gB>RXֿ%su]?BD>|ٽ) >U3;t?ZH>b O #EJ E2?g2p~=4<\Oߠ?}i>kDzasaNru>V-??:?6}LkP7KDX"4r,n<ڿ<޿CCRҿ2+|4|-W*O>yEx5>??@>$E8H` C h=l_9~)h-2T07=n)8PI?CCIi>$xKqk=\޿O:ؾ. m>n?}=|B>S'= Ce.>SǾ"L@{c=;m >LҾc҇<>*9C>ItQ]S6*M?Z?;H?UQQEK4#Kܓξi>1;ͅI ;CJDþTxUM'=>B1\<LR>K9::<+p8?sm]g۾nU;3=&6#A!]澨Wyz@ #̾O>$066_j??p?TL3w`@M=|_V X&Mj{g%(>L?7?j@?5\1+ >i#?v??r-xd>=??K?*fma%aRТ? ?_@9pZԉ=ҿT񑿁=!ދ%)U=S?G?nn?[.&ʾ"6~??c?}/${ľ7?v?@b(wp=_^9.>dNko=7PvG%5C(YC==Ϯy 2!ܔ?D~}b>?J@6\<18}=<م'?k՞0[X>\G^̐XŽp .<?+s=ȿ,=t=`<+?IE2=Obt+J>ˀKC>+E;1Ӡ@?Uj8gsF]+(3~=i+69CW>5aI+^=03}>?T7(\l=v!?'|>IJo,=U.b90=!W[C?zT-Q?sw?ߜzOn?'pp#H>d?:u<?$Dþ?36?G?ʞ\[Nb>E=!`?I!_xm> >ھCqn=8ɾƓ>n(?)wO? t?EcB=<<~qoa?yKZ=ذѾ0܈>d(Hz%=a =}t=5v=-? b]秾3G>б}_7?y=Jl8>ޱ^óxj Ko >;`Qk:?,`>|<'ީElvd>0J~w\>?7>s{y"&>>k( /b=XJ}? vt~O>(/,#tr{#A^=EI׺[L8>S¿ 裿9mnԙ|>3'&>YO<3>F̗1l=Ũ>zA~w>{V* >`n18DvuuV>5Df~@>!TTf`8j>OA=ڑK4al>Zhג8=A}|>Jk D]< 7&Z0TiNñ1; T\޿<> G<,A;4PjǾR>NG) =k@8 Ӿ7(>&%RL'_AlB>=RYԕX>M{c?Q~r5>*Z;?~?;w>wv'?u?NxyL><ťA>%-qv|LȾQcy>Nw,*>3=%ʽ|ozNlU>vn?Ałyo]>^Xk>|0t ,[>`bNep;jR]p>1`N<䨿'@pU)E= eEvH辝d6HF̣=p5̰3W"KEO~=p? t$> SiʾbS>4xakG=)= >3R>M [9@u> -I0d|>x >!_>'>zT> = >E]=/(lv +>>B>a 0ӿ<Ũ;#{|u>zX`.(53),|=O-^pV20۾ >"Y%)һEN |> ZPS? _|RY>~U}tk=~=u?\Q3pΎ>IHw3>:N@>-F&>3pG(>rQm?jL!>vԢ1 >mQ4K>6mY?=6Q>rJE;> gk?+Xʾl>8)мg?r.WOؔ> =J\?DZ?pU߀"ǿ>B>yd?GB C ;>Z4?hFJ>U bJB?{N@H>ԣ TS>^# D? Y>?;j=w,s> o>&&-(d>2͢=}XI>5ݾлn>%8>_J>}7>t)Hh= n&vBL8>[>e?ce/`(=$>">|?LsU 9_$>`Z=LU?fB5~=:ŽKz?Ch,p* d,>W=E?p]$]hH>oB=+?qemL˾X+>IA2 k@P`5%A0<K>.j>A-?lҨ?w?)= h#R<̿!s!f> 3?$:?~ ?xCU/L^~?-I+*{A}odT8' kӿ\>X?9>~ lҢ>([>Rv0|1=Z?,Y>]iM}kUŽ0>W>̛ǿ =kG0>F?!5N>:HQn =X?<> "ܷV>CZ&|"ں>/f+=/hU>HW"= }l>%~$?!5>-oT5=9J|>ܾaܔn?(y8BҾܭxʂ ?x@Nve=AվP?RUoo <?N ?E(4g?-\gV>~'Z+pi"ST=rgÐB;] 'k x>wN71%?d=Xu?dMIX-@ѻ?@'85=%>yd=6X?@ShǮ>8s6>L<$O?SPԲ=W=M?WT>!ˊ>*͟3\?s ">Mүhr?T@xnZIhci4[>; iW˾t2c= >MSy?~?xw%?nQRI/>*?-?[ eVmX ` t{9DE> qvl2'5HUC=4`h4b=vD>6zS8JG:Q??s?T -F{=W.>u?VZy?f0˿NG=n>M?/y??*1be<>@}~g׾s#>u%q+뢿;L>y<7aSkm?>rAHߔS)N*'>P ?(Mǿ {S>E,Z^ŏ+P[澭v?. kErȾƌ&->wK;e *> A>Ԡ<@3d? BӨe>'- ߋY?%YoX'>a>!> F?J'|?= t3sL=N >#^籞? ~L>jJ=E=!)?\2iC= N] >)!@9Klzr">BC7= %U>HS>!n?!'5>GoH>??T5#h-F>>j+H~:C>>tH~9?򽶺 ; >>v===m|p>>1rz3zx>->|>~9>c Қ ]>~`@1T>?q7cD>>s>D?`?$y2"[WR>c,1fݾ>6>(Bt Q/׶>~Yo=  <Q>&S ><þفt>c̾.>꾞۾Y6? 7\t>辒?D$M l6oGL ?GΧ- W+0 ǫ?R1@>vj> g"l>> r;ߓyni|?1Z:b#=$>=[Oz?hD @<Me?I=Q~2>>ˌv>^ʬݳF>A?4 r>>S~e>>{=H?u'z53>v`J><=$-2/5 N==MeB G=, p? =pQ>>n>_~=?.>Q̊>kSP>NU> Y}?q0d>Jap?aJK>Qn75Ϣ? 9m S;>%[F=5??S>lx\aF>O5= =7kT‹s6A6:P.=kп/sw=Pu>7b>º| A!=_S{>u>H yW>zn?:VS⠾k>J+)GA=?/l'>ЈE\$·>jtn۾rqO%>+^>,E>nl^7n>JκF?XBx:>A>l?=n>QT=>GU<b7=!TCGƾl<:Ww=}c>4_? j>~F[6=y=پf,>h﻾y\+T}UL=[O _nRSt6ዽ@ݾ6XR>Jb'^ ]Dg (_߹CM2{&lFAi=%5 ȿK8ejݽ_x='F;wirG=̚I&ͷc>>a? /w>Nd-L\>Zq=]ޥ>W=\>9>mx2><,=*K>7~>8 Qx@ 6Sr^"F=Zɰ'^ A } >2.^K>60 >/jF̿ =]?([=%*g~ӿP@t<.;sڿ&$NnuJ==7]jӀ>F2n=5fI'>2AA꾋>~jX>>)?W.>,${>>O?:o!zBP>f>E[?C09²Ͼ*V{w~þxd_/.=VZ 7'Ncy=0Y*>}&F7+=VCq.? YFp]Zl =Ĭm`V"KyW7>5V?m >SUl3Oؽ~%9pr!k8HIlƿ34S]hN!-Z>E?iEj*={ȾAn7> h Q԰YxZX!he-^W,Z& >A |ޜ*cʂW5>3{W+>R) >`$p Qv ؿ=Tn ̟>^"`>>I>:fP=Gr҉^Y>*`dN;AAQLm>Un@%E|@d=@m >>sb^E;Ne|ſʿ mLJg۱>W1!KO,><#tgsw>j>9~>-#d=п: < 2?`C|^;퀡\d>rȿ#v]=\\>Q+N*fޱ!׾k'Ra>_84@ ʾ{ƨA l,gPX佮K J=@A <`=ߏ=bM >D~J!>d/b=9=9 }>tbJ H>qB¯޾+&9-p;#x>2Y=G!;{%>V盾i>ud$>tO ~t?w<6>!ٿg7ſ"?zdt> yqq;_q̧}P`=tL8>~+M_ڡ׾Y=ƥQ?i;>V?8lDl c1d^K6JɊeX~tw=+|Wd?yO 2>!F_M¿x{>W>AW(T߾fGfu>#`޿QP9'ŬzG=>B p=v>OA=Y0ΞGd.? ;XWm=\\߿#3Xë"pG NM^_DHNž::tZYO>곿fֿHVw:m*3!ҿ/K]5321׿6ӌ=YO: Ę_"Ԥ<-: xpr\S>#;[Qid>}=0*>ǀ>羏V޽ھ;`?t OH=G=s޾w_8>.#ֶ[>8HRe>(x/$X#gY:.>2rF>O>  6#}>cŽZ={WsX=%>#W@? aþT&=R:^U >l oֿ6Y]b=]}R9* <\!}%0!Ȃ&YK\C?@J>$˿$D{@Z?>Ȃk> #5?^SH﮼ =Dݾյ12Nd=UɿF<atRm*,=@]M*$@}SAg]=)ԿNl'EJd qҚ=.lxٿ#cNIïѾ#xwY!Da Z>6y!k،1>s;+;!𿆤Dp>"|| ~u> >Ok>}CBP=vDRP8.>SK'>y>ʒ>fsNt>Y>;>iABaRi.>.??M>ÃB6>&=ɿ&TgwV=?0??9W>`>u>>r>.>Ċz> A؄;ѝ?e!+4=%ξܾ| lXO>R>;>5>ʼ?@c>>0?Z=G?6>^>W?>uс?G?=r?HI<3JE?|[?(a<:?5j{6v?A>Z'?.-)?Foe>׊3p s>>?}|>(̾C>IX2?LBG>Z Yu>>p=x?}F?-*G>pt>i87?R>O>Z?V?=bS<@տ=cX>2޿gB`Pv>r 쳾A¼}i)>ӋNuCu[><ײ%7ui{?RPrud㊾U[!?2?]S? ϾD?_[>i.t>Z&r|9ֺ?TjmBiw>^N ˁg=<:?A0R7=^"_?]N+Y=m ?Aq3>?=>p~?>諭g(M>Mb>7~?v>#A> /Q=Y{{>@iÿ|-0?*%9hQb$|?*vKe# >E|=ʺ8?d=aĿ>|=׶?ai=L?X>#t?BI?n?$:>wE=>f>rG?'=F >Q5w=>h?Q> ١kOr%%>?.o>*#}`TIǾ{>󡲾o߾ ׿ud=~?<*V!>Ĩ=?U@FI> ?d?G^*Q]'>v>YR?F>п>Eo={?aŽ)JxNÓ>B:S\?:G^xʂA=mn?߾S=lD>s> E?hs=G?>Ĥ>핚?7T=T;V>,&>)>P >>>@t3>Ai>>Hی>TeKf[w:s3rڿ=.@?#hV>(=!x>AJӾ o:m>Z>??׾*>9>q=?_`Wժ~Ϫ >WD,Z? ɾ'=<O?e.=6^w?<ߜ#G>Q 2{Lj>ݽ{>3ľ%>& پd)Ti>6=>e&ټ=W*{>tFi>؀'>ӵ[)!LO>(~y NH %>|w<K=+NG=w>>jA_>(BlNCȼ3L6`?21?<0+ww>a?><:~> >#>l3q޾o>h#?=na#@> ?8={tý~[C?:Y$M><굀>Y}\1*4)[V|`>ioe>kmD wf? a? =UoFA_=Ƥ-Mw" _A>y>@s޼}P"_ĨC?XȿS>#ֽ$s@ B=؀='=b ۬.ٽN8??n~=Vg""!)(>d?`=hnˡa Z>? *E1p+j]l=R?cv,>xbJ{>O龆볾3H'&=z>lq?=h;Q.}n?B/+ZԔ@>3>S>?Tat2U1>>97 BN>A>ն?Ɏ>TO.3]>.v>[?Dt>j2ǨX(>G>W6?,4_ (<>*B?}4==A `ݽV>$տ aP=/^s"#QIuw=7( >FhI a`RX="?s zi?? 6]NXg8>ۆ >^}>>t_>Dz+}OC>W>!:?&>\&OǓUb>`~="l?fPVxaa=?^56 q>>`>Ԧ쾉}J YatDA>W<5xƾp")ג}W/Ͼ-Vז:Y 4s\N>{=s?jҐ" /ԍ >r}ľXĽ>~g?HI=伮X2j>2;iwM=xrm?MITR3ʼXhZ?+tQWLmH<>k?>[/؟V -Z>u?%>Yy~>$z(P$^o*>cԽ%u/<ֲ=W0`>ھJhc:$-[r-ؼ R?o=o `Fm? lR ?w=U=ٺ=g-`p)>F=e=¿z_>d =d߿+ݺ> G>w u, 1=F>WI>2nv?=g? ^>u>H 9u`=>ل¾gA>`v!x%!>7?{>80'tc@>?;?S>Mv~6 o(uk?d =j&8?$'?M?F/8"r2>?3a>{E)#}>?q>#y)3E?/?M?R&fz=qzF ]) >/Pո(9;3,>>Y=|; &J4G? h#*˾_K>% ?T>% %04ǂs/9>)~bf=(̿QJ'>>r >AjUZ7ZľLp9ヘr9ݵW?bM꿴n=\0|cA!K>D^ >Z;ͯK>+G> >w mBs? = %<<ťZK $O&vG>#F? &VC.?p8>\?1 6g0?P>T> Q?Zn`.晾fTd *`~>)"=2>{?`=L6ž0ި?=I T~a(=ˁs߿I# ܫo>O??QJM?)DgOng>8??Oyd?/B}j>???XukY>Ko?ʹ ??_g!%hq>:?U?XE?' [\z,o> e?0?`)?-C>Q>((&S_=-PYCwp;PG?`=ZVJS>_#>z>DaN㾾`=\ (wc> G?M?4>OYp(MҀ't!-(S&k:lnmh>?+?R,g? ~=Q ?z?*>4OZUx?6Q+> >Tp)PCr ܇2juͿ/!OWY=?m>h<>|g*>ih??f?6#⿹f >I? ?>?Wd(m=F#?n?P?#%p=>p ƿJ%xhv??W?(_)RlD?q?)>+ +a&>徺 <V>Wپ]fj>>Aw?t3>-\>+a5@%[`7 `}="G?"? ?O4a/wL?)?&9>uv3=^?j?b?_i%V?x?T>'5?J`>>$p9=`1۾w%=cGɼ * ?̓:?C?S D&d??k?~S_G?!l?/0?M@8}U={g2U ^9?;ԙJ1m+88[cUNa5v;b̾&F5>@7\>7,.!>SVl>ο \=H2ijQ@Mx&Pp??A@W?"hq0iĨ 5[C&JC7?T >@#GA[6ͣt־ ?JV?a`?1{ |{/l>$# , D3/Y?(H>s ~ o^ ?B}?g^?? )/{(XxPM>=ds;4?e8Ym>\=z6j2=wr?4r?!?2Y:%?ܜ?O?L18fֿ)8X } ۼ691c>X@s>-0)(#y>yr8gR>"Azc=/ '~B[ip[=d 0#юT2">GSa)o-SP>rއ???mEc5E_4=?@-kW}!ʰO=Б4<˾0hֽ(Ծ9),>1ȰV?Oa= L=gf,U>8.,;>s?L??ė9R龁X1P;ز@8Ct=E((5i2Hd|opĿ$501ldrѦԀ>gT`NE=@gsDyhEG@=xl] }=`G>1}<5&l{2'?f>@Q| _쌵XO|ػ,{>3)A)64P >};*TQ>Ix)3Y羖࿷ .P=u?/? ?sUә\ >])(rҾXB>[/! m>g0 '>?`ú>Z8֍#=l~r%>${pdY)=+7Xc~,l`X> pI3 xkH =47>kN۾߿ i>M!v)><3/Eg.>H>AKYq>kƾiMKM>OQi.)=??vB[?5;[$վn־W.r>avվz>hU,#>q]:)1<ݔ?a?`"?$ a&Z 2??m%5?gp&>8m??}j?ܤXV]->>x>'P>ót_^h\>lP'jre^>2fzO kp"`>!5Th=n da>nOZ7>_ Pߞj}z:>:.?>6X? ?h:2?gUs?QB-{>lXоbNv*p>@ =ﬣap9P>; ]v.>HuBz>9~KɊ>H\o5@ >AE=/w? }_ `y=꾾g 5=v8=ńY>dPr%=RݯK.+I<)$<سSB ޤ> I;M &C\?Bxy&>%"]+,>uE?6G>zHPy>u H;PHZeI>ڲ[~\D9PL>?r@B>+~<&vd? (+KA >>,Ub?33f?(|tޱ> оiCu>v($ZAp??u@F *0ܾɎ>Y1' =ξ7X*>>BUu=Zw*1>z|E$ٌ?q.A?J?2r3#<:u>K#TMHkjH=UH)1>zQHfcؾT=h#(V5d=P[E>_8`Ѽ&2jU9"Z%Q_DR <4 >qߏ?s?Lby?Rb$PξGR?Z?_)?΅PξY+;r`k?{5=<? |c̾<"N?$` x)þu^>@g?.{^?Ec`Nw<6~=?6P=#3vpU? ?f<%̫>T}/?fM|(?_{?wCg=ަ'qv> @@9Q"O>*y-Mp}_{ >4 Y4yOe$)>+(}SC+ZnB>>7hh>̾~> >z>Zͽa]Y>n=Cqݾw=s5*E>j8a>^6x_3XFoP6>+׸=M0w[>Y.9[Ct@>L# '=o:JO>?M93>4(L>O R" MU>t*'5m=7?K<(lk>[}f[d?$̾>hHd{g>B5oY4nлf>/:<$e7T*]->|;^p<$:AHk?!4lE}u+>(Z!= HBǾ/:?FT;dG>cA=Qi=𽷓?+! ]v=lu>><+?<< I=yt:t!>o"|#-Ц> 3p*8v=b?/h|l=?'Re5>:־)C=5o~>/pY)L &%"=V"@9%>Kc)yd>@FgྫuC>WNr=t:Ɋ?`jK/8 tQu4 >~ C7/e>>o*?%5O~ =]?VT=&>,=-#?`$ 1辰R >-(>dV.?|b,`?>)|?EW@d_> ?3>R?J8 >?H?X ?@%N<o{?<:ް7Ĵl? å/ü=5kD?9~Dat> O=la?W+o <cлadA?& %Fu?A^3Q aP {?%B['{`(>zeX='Ծɬw?avoj8!t|>fQ=2Q?UVۡ1;_?G_/Duƾ ,?!|ng?/?:?g>yY߿?S\?^>I0Um;\=ASX޻.,?J@{A8@X-> ˾Hi?uv*h;=N4F1/>W?>iG3 P쾚'B>͐ =Uq?-8#>MQU)0?4v}A>ز,;?~=V-? ?CN>[fs?۔r?Yp?[^ k?LI;?v,?ela\K?;z?,A?/z7b0b?um>jI?ny\E1)ڽ+s@Go>Қ&$9=#T?]8&ߘX.=[BZ!?L"F,_H\^jFZݸ?9S=">Tվ?~&@ >& ?Voa I>1? C?Qk>#=Bo羔?e.ɴSF|>Gk>׋?; _?Kf=*VQ= ??p&?jTf>tG?At?Q?hVN.>? v?d%?xȊO/N>6<­?AU?yp?<Sw3z>/?,?Z:;FATͅ> g?y?ZS?{.ߑ>=_?njUe>x>?;mv?FuO??|?mQV3n^>]?&1bܠ OɾOHxd7>AKW( 4Qłm>ͼ U>zN۾ү?>b>7H_J?M[>s'پ(?;<(p=z ?WJ$;{<`˾ ?9ω5TRki"eF=kO-p tO+0\>lJAeTƽ?58+R>kОGCt) 5]f>Ca@ t>Ծ&-r½?8%}߾TɾH?0 ?#*?*(w=)Kܥ ?.i?8`<mL4.ZLwhL?>? zD>'N>)|-?}n4 7`TQڿkUL`=65]pNp< 4`z=ۼ#>bɎ|ڈ=ĚQ?&};?$>8Б(?*7/>h >[q2G>YX=Ax;?WVT >1/^>>QY>^HE?ȽXQ,R=0; -D(NM>C=!>kL>]Ѩ6MA|f>2>gǵ 2X7r>7)? I?oBA>>?zBUe>Ҿ$T==>T_S6>ݾ,=t=:O=z=q$>Y> x8a7a> :=HI2ꚼ` >W&>4jk7)t9˾޾՘?Q+PfaؾXr=!r`?eeV<*wG>4.\>%!W@̿l>ǿM(>| J8>[u>,UR=!ͽfƾiLJ=/f= $=ElHі>Jv=(>Ļ>v;i?W>$%>h?"?g?;ÿ;."=U9P?VƋa= e;zG2D? =$yܽ%W>F=t!?|>=>ルG?ӽJ|>iҿFԾGlHo*࿿~gDC=4܄`}7VCQ =K־}(@Bk&2+j:&>u}o8`Dt2:?-2"F?e4>" Zf,=L컝Q?k^-De&?2G 1{y;e>2?z>U.)>=C=:KUST>#=) 2a4g0>QV>P]zT2>>澌is'>6^<?C7'5G9޾A<6vv@,$<u/5>cT^ݽ$T޾;3ZJ?1?Id>C?n住D?MG?2?]r>fľL8?;ud>, h >!N½l?P5;u5; pzl>',=z% O @gϿn+7,2龘Ѕ>.#hr+>(v܈ >wlF"{!>ƹW4>?l'S6%W>}i`-JE=`>FL=G5~c$꿎 ^7i<=@LBJb>{uku;No/?1${7<ŗN?]]>s><r1>C'=#쌾 g'l>|b8$3<󔸿2cfR;`(𯽧Saj*ND9c-iz)BdꁿFӾ$c@F OL1>Q?]>*Dc:QG#>?Ṛ>maTjiCp=ˉ׽wS:/o jr'78 ,/N>teDIlUɿ!rV3=@}>ګ>E\ٽ4?DW[:Ѿ́>ɖ>a;tѾ=??[}[;Un>ο6qP0x>cYt>&>77>:2wH]p=q>W]?? N)kDL4a=K>Ĩ>YN!>tcd?>"l>B8=1~x>VXO=34Z#=X?B=z)E 5ʾ߾>kjb5\-M8JQt>2rXI16;>zS9ɴ>/#/=ob:7+%Bj=oT>EuXLd>xdPDe,Z U! ޾ٽU>- t\Pa|<žy:vv)=g_<X_)[2>AS -)sTOο :",RIҾ.G=9>WtᅮX>ǂ>Bu~;*>.A> >LMۿhIJ@ C̡>%>A]?>sE;ߤ@\uſ wv&&Gͨ=A.:v!=\9`t@==a>#lH},P>b>0\)>!M:aV5D׾4.R*~վdZ%KQb4eJ=}Cڶ-yH/)) `Y)gw>D!>>X>`w>\ґ>&?*5?{#1{E<;!N>};=^V=yO=H>_>+Yf<B*oHk37=\=`QD?'_ {J"y#Z>=mת?]Ub>4z>)?EPk8J;yҿ,JAT)&$v+7,>lC,Gc^>i?M?e'?B\Eb4yu=bg8? :-X=3D=fM?G&|=;4*S=3:ܘ?)򽍭~V ݗh߽s2"d>K@1]S>-CP݄>J6㿏>7H^6mlL=EDt>Ⱦ";?i>S >-?|”>[Ľ+>43%]=5a=\%>5⋾ M=D/5=\]>L4PHjB.:mýV&>76qO=ȇ#f^><S=fG>xR ,y=2S?6 =M>&)i YF H=微>ٸ̾2 K=G >>1C9G>UCd0XV=W A>u`>߉=c;ՙ?X5_>Hg}+xkV`>nę>4=#R=v >m$x >>=%? ;H]<Â@Ja8& #P.=)%=rͿ:3JD}=տ׿'>/g>B:+#>.tו>Ozw3*>2G+>.ӾG"bF>W|H=0^)e뿝}d?m٥>.ؐ <3YL<=UBʽ2#8tڽhk>侷D;or t.>޿ ܼn x#=/`s>=ZLm<C6X=LS*pž{T|v>UN+=[Y>izhmz<㴿Hnn+=0|ÿW.J^Kv#\,0tQ* xؗU9_WFc*K<'mt`>0/^Y-aW<K1]"I>-ZKUh>[eemDB,>fՁ;4}5>FP?(ѽ T)䨾>U)huը̾E#-3 \4~>TsRV(ӿA>ٺ}ZzJ=mRb=¤U%¾h׾ϭB@pO+w BhIe 3νd>>ͅ wp"S؝I\_$S셡辎/($LdiSi;ʹ1ֲj߿bk:4 {YG=C ղA U>dPʾ!1 \DU>Cd'dB)>)Rҿο+(6"=уb?8869>6|NoT?=6>1,< VA>KQ↿f^+>BF/ǾY~K>]}K>3ffԃEdhɎ}>3㾍V󾧗x?(F3 >Jɿ/ш?U>M>z,S2$AlsG>Aտ,#ٿ;jR*>O>EF+-gӿ8:Ѣ=A%NViӾ@pp> pj¿Eo(?!<u>dGWֿIj'=~Ue,>%쁿fڈO+>}.yF v#C$Ɔ>UE?o*Z. N оz>9>Ԁ>b>N 1>a_8jC`>(>N 6XK}>s rPw6c~:>1Qa > ] X)>5zem=A >/>U>/b>}>mS=R=udJ?7ؾ>\7>?fL>%1)~I=X>õ9?#m{_>n>?|XX>To?Z>Th>Q>=*VW!?BIC>p<(>f?wI>1& k/>mIR?b>N-?,IR>#=?dV=? i>>:?Y>D?-*R>[>j?`>䂿`^-(6e=i?d3@= >04>a>g0?s%> cj>?dAh=oѿP:V>8i> h?icx=9޾3=>Z.`?;2˴-p;.+I}?'pNb|l=r>yH?yB>VT~_>s>)_?xe=58C=~O?Xˎ;> Ϭ?H6/>`$?1jĠ=,E;>x/F~إ>3]?=N]1>fs>2CBc>˖T+/5xJ>% (b>y6*H,˾*??G>ކ?*? ? #]G? kc| ΰ?y?>*g± ./E>?>L @pKO=.F?yGǣ݁[>\qҾ}P0QC< ?%ً/%_ Ⱦ7?M/WX34𾣛E?k*@ ̽i ?K #DZEh>@SтS>ɯ>H?Lb>hI=p>M#?8G=Nv>8V?m_ղo^n=b?P+Hk(֠֡=C?damr|=+^m;% JЁn%=ZP BFU-[a>M/|^91L~q9"T뾂/T7PɽfY-b'-=G )Ծ2?Z<yI+&-C,Rخ>?>%PY>V?v>>WRT={?\ eY4P=B=bo=eMb4][X _p>jТVmze> [> ,UT>=>gW>=|˰4)9?<ƒUj?'@9SJ:þ;,R>ݾ-> e^>}<'hp hA>oH=N/Z?>B>0y a˅q>ǥ, T_ty>ƾ{ݺGx>*%پ( ?OcԾ<_g=Y _%?B՝<'ELT1=?C[Q(\Ӿɔ:?y>>473)c9UM|peC=$vh op5d=﯆ڿT>4}>` ) p?{>$<}f 3E&t8 >e<> RPx:=1侏E9~ Zao<>J>`cVE?>?Joa>$j%GZ4?Rν[w]!y3< ?eHs9`>KP?ՄTv)>1$JW<>[}5 >!#8>E`"P=A@?܊zMPl&>#{F?$XuO@sd:bV!_<=1>6D?b<y!R>#>:?Š>tnҿ6Dg3=8>z>m=ǎt_UEe?00|XS`'YLUV?)`>$&/^ȽfR3?p =5 ^vP,>x<`?F#=s0DE<ѷLS*?H4=tY}u(%FV=3d?>,ޤپHKbXOPw>EоE@˼((>Za[Ou=t5US&>澍p A>rXp?%@ؿ>^ˆ }ᾭȾY@>h8K\wG>>^fU <ܠ*q!N>H`W?>F@)=POn?>F^&#=H??$ ?ì?G!jp#>?e>à `2:>a=30D(g>2~ @[G=N'jOUMe5fˤ@>ŨMzݿ3T5=׿$ӿg2"Ymhc>1b(>%nW=q(%Kҷ?FD(6?*?M?O2X&ؾA>J?`5>sm #a/;*?C=ēs 'il[ ?{FQ)F??]Ə>%ۺPTyKM>-e>od>x5=x>jy'2tٔ?ț>S.e m=?X}>3W-!ھQc=̅6Kmʂ8>?8F>?)8G80W?'`>[>riYI?R>X\>7P1xvԾ6ݥ[>1\fJQ_?!>w򌾰=wк>*߿=?}@ =) IN???@#.xyjJl?l3>*9+;Ƭ!>o?&[>~05<ڏ>Z?.'?!!@E'b\+=n60k*WHgm*`2þ?>Ӎ??/Z?Qj> 83P p83g˾9>_M8?u>>\P(K.B&>9o={FM`! [)R=T7az= e,Lyտeqg> {r x? L:>:#P&x*:Q,k?V>&p>&vM?R>4>ӗ5@>)?y/>c0? \xDо̥ 5ge ? z?:?'?e@yE0 J|6˿Ft:Dm"2k8~>:m=kտ4Bׄ+K>N Am(;?HE>hZJE3¿#-`b>n??a?;;=z: l;.0]>"dQ>Ҭ2EGܾ߾br>_I @澳 >p>5?{?Xhf?%ݢbe>t ?\>?M?Vr5Qп6AN:=>*._[>?Ň@?i?cV!wQex>?,=?)?Re c>cԿ0k=]HFoLO"Rs)> S??"?Ropq>?7>yy>J_?V,>>K^`>$=7=r>iSWם>]?Ɖ?;?qV/L`>??EV?mj$}v_J=h??W?S2>n3>Z??F?c"U"Թ>V բ>7;NF=ƒ@gQ>2"TcM࿫#.>`.4ǀ>UN>B"No>v >lvѿ ؿD(TFF<f?Z>,t2B:PB>iz??]J?tG{G=t'?ֲ?WF?@i}8<@?_?P8? P;?w?6? @BfQ?U?I?(c??N ? PމW?mG?" > o/+"6%zxXe彸Qe0SL=%k`\dPӍgsnvs!N=¿5ؾbAs=DCNg=j p'i=lӿ(ᓿOB?[.>3gn=[>$ k:6.?x ?,4>.}Z?{ ?bEo?4"05X_Umzݾ¿WĿdy^xPc1>D 1]>Lޗ>=j^/j2{?2>U>oU'>[ >(c9qq8nq|BjA c??y7~?m yX>.n뾒>:>Nroړ>}?4=M@>ZP'md; ݤݥ6/8;l@.iAڿw q~y%=Tޏ<AY b$+|xcZ> >o>6U I=H`m\쾳s*PO\짾_H>i6>7\VG}?;>Dؿٿ"WwA3=?dk??/࿟o5=Is?G?e?fϿjh77;Qi?j{?i?#Ŀ./p>-?b??pr`/m=2/'/:+TD<ӾbD5>+c^j>ER>BAH">Pr]Wx=\-;R>]Vl}>J/M>q) (@:Fܺb0Ri=?ׄ?d?ھ8S;X?}?U=?mCx%ݲ>D#@Lξ u=T"8=ngQbԿFg<`Eδ=O{=.d]>x@{C`^_Qa=Q¾;!> ĆU ''>m~~_ >63rq>}> G= /PN=sؿ&d3X!޽ &(7z=\-]8t"F6,Z>&%ƤAտ!e/0Lriؾ#q=JM96=.??/N?c3o7>c???pT.(>>Q?b ?r0?ZPNБ u.I,?O7ԾܔpʟϿ@?8.w,>!b>l.>~b?r?y?_"ۘ)<=N6??&?jS?&Y?}?s?Yu=8>UJ'%D?K? ?t%.?~?Xѷ?Z>]X B z@=ʾk P>f_y&\???;?'`$`"M+=6d ƛJ:/9>;Ɨ`^*l=MYOƕPm D90B<' Q =FYK8`>DRR\`;Z=4ʾL?:i?A=諾1tzF>9hݧM?[ j,T&8q/.::þpÐvHǿ?-^P0½gTR,ܾ>ӪAHula?욾>]%~zMYZVvd>Y /pw--w2=ս"7?-cӘlʽE@TL1ė<@=׭ѾrH? w\7 <,1=@F?_j?p{z? 83~3ɐ>A߼zG>=-gw= Ĝ6L?Ƶb}_?Ƃe?o#?*kҿ#^Z?V>?e&??Bd?H0!8n׾Y|#>$O?$7?0?.,?}g?q"^p;?9v>D?>&>8>J? 047C >-Ę= =gjJ@U>b7>@}}t>nҀ>A*=>=E5&?8z?O?'?/?z?L >j=G0زr=}Ѿr>>|-i:J;h? RYmHꞾ4'f>vvf *OW#%=g&?!z= !ݺ>Vi|R?ڲR# jsϢ>O@~ˣ.z,>k_OuSyBNOY>B@=ܾi/EoK?>O sAi¾>h< ia>k%&=yJo j>oE> >i>z1Մ+?)f}(,<v>D ~AԠ1m>? ۃ-b>;<| +?ccJkF%*t־ƒ,>KA оި3>3ϯɽj/>z3Gz>7lξSؾ+o>oz>E==Ԯ'>Qn?iP+DĀ>>%?eF HU:>JǾd`>Nz>Y*T> (k><4;=]>>"4ﲫ>rq},8>=ܙ?k Vͬ־Ë>R=?XdCt>Q hQ>ѢmB?nv?"PvվAf˂=d>2#)?s>1 g6>:bҳ+=B>hnKz>p㾽 M>?Ոu?|~?J;?^?|'P?t*?Ts?n8??#=??K%B1ZJD> BF#?D?&?a,B7?bDp yޢ N3>y?va?duu?jj5Xt!f3h>bY?!mF?sdyr?tmt~??J ?/z_?9&?2 ?Cq?mm??;K{̯?Z>0Ce\(ؾ?(V@ӹ-þgQ>ss2?]?H55;e>!bߠ?de#?2+Q(??VK?'|?HW?8q>bč>&[?>?*>S(t>b>:?#S =~NEeG?/ 7?;!?r?47]H̾{$>lL>7?ɣ@CULevG>f>R?L.U?3 ??h0y)->Sx=6?tOnap#š<|>a={?w^SD>61>|>9? )1>;?j?9?̰>F9 ;l?'7h >?'}>9???h8q>Q=C?p}b&A;--H?H=i;*? ٝ0]PN> ?eV>ߙ_?t0?.?jj??oG,?B >V `>w I>f1r=tC ?Df>HE徧?$S\KO>W,-IA>jT?73?`m4Tv>V= $?^Y}-tM#=ɸզ@?9wH@&B BW8&>wH)B;M'"H'=lJ=1?*?JW?=ѿ,^P=7M^Z%|>D==p?> X޿9VhwXUo}¿׀> e^¿d'd JO@wƹƺϾnT?/a@N ~Tſ&>?es>&vR">=E2F=a J+>Rp?VI>qqI/?n @''c^KGB?HR8@ f=?]e5 U>S?~Ex6ҽcԾ 7 >/0;? E^?i?W?O<?}?`D! S=n6ÿr?lQn> {K#ݿ ?EoƏ0}>PC: ?^t`d>Gg=4F?V`|0>{,dwL=P7TP>ÿ[#>\Hk-^N]H8[>7>.^7Պv,$=#>ӕ]{N0]uKϽuO>awd(Hx@>iֲ?kְG$=<c5=ye D])[@>\B?? -\撾hlC=߭>HzCO>q?i^˙]nAs>\?,d֙=(r嗾`[?GBA!bxiVႈ?8U|>z? |?S?d4nW>fTP>)0?81?I1D 7CVH>a>I?(O+?AVwVa> &>?eE?B42HwWf>W>u>^2Y/z!o>O?%{We<@$>+>R;~U+<>?(?W}y`Jh3uC?bCž !֤?A1Ac7+#>O=?DҢX >8>tq?7?CTWd%9c>i?Xq1D?>3?*ɟ@&̾)? 9T=iY`??WRv?`SwpSIO}Qb=}w紾's,B>5wόE02>@x=-?/>?y|H>7??`?O?P==׶?:g>w?6=4wE9?DV`>}V@?w@S뾨Ũ><܇?p5NC>'2?{ytͅp>Ȃ%@:?)e ZW&xd>C eB)iL.>!㋿"sc=*xE>H4M{{J!=>V!a9&:VV>Qc G>),.<?Yg b+QvsZBY,!"̴A=\ Wx< &A=ZCx.&d=ſ @t"a>~D02ZR(6R0?1=|Ŀ@*N>]e?>"1@To?%>B]#>-k>*>Ӣ\(<4&ힼ5Z=GND>7l׾a :(>bx9RG~>,9 ku6U=[FG@]>ѫ>#?B)8;UO?7)>ɼ>b.V>A@Ժ>H`5KI;R>`>98w7.="=0+5l=>˹>13 =>($>v:z$=XB?^/H<&B]>'V0v6ַE>|WJ3оWgAOba=!la9l:#Z>.=3^1?v&+<_9V ?PY3H> Br궍 M>E9 ;ē>O>S?qih>=?|8׺t}o?Yy'5=Y2> > 76|@=i=reOVk>j>%?uyA3[>>[B>C ?hO@ѾK/==Js?nSX.<:=žZr1 l b;Ǿ~>=7?LkC>VB=8s<|/$>=[d="=E8զ^>-=P"7}QY>t=3MFoɗ6g¾ư=sZgL8+bQz?1/ӿ9Vj]>A>o"?\=1=u?aοP0^FO>j׾̍\[J>Ggemuo>RzQ>Fm,47Hy: K5+>5> Qv|lK>Im 58m-D>i =!=M'sN; DuY>/>0Y8oIcܾa NHx3G~ >fQjhE)o ^= {)6J\W$-?w`9#<n>>|MmkQN q?4/bPB7-fi>=_3S >2/Ŀ7Xmd*SOXzJ>'?>KA _}tB5#y~>>D^?WpXw>2:N{O>pe\>Va,?b.-,i|>x=g'|&'#-;6?=f cJo0>nQ x,tZ;Or!*=l|?&bg?U;&ĿԮ=?>5f=I/ꣿw䛽c5I>aUP g^W:6=,,۩M%=1O @>6|f?濖X?>^VK tɿaM@Oی> >B?B>C J=m]>Y)?F-?4nTQޏ>`$?L?7ᇿ.Hs=}5>?6?%ͣ J_"⾘ =;?z>?ND.^&쿨Ӯɥ +odtwh" v

~V)wCL^\D=?t>"?EلӍl7=?>Y=~p&ὤu>=Kz ')o<=ˀ(hےqο3U>}>u{#hZ>ʊ,ཁ^9D'g < 큻^Up<=Dྨ=nfEi -=ߋ*A>_sqQ`<U="[o$>Z|H@n7p=u׽?r )S۶<~\>)b>^?kA>U} ]Fh&$r tPP>8plJ#`G ?ͫ8=Gs|YR">;tڤ!%@Q>>kL?E Rl S(>,w>V?f_("X{ƻTG>4PA)c'wI_G'> zD>Nk=aRn?> gG gW%ݐ> qF=p~|(jMmp7>[>Y?{>ۿ>G5;>0?&(?mwJ<*#%뷾]Mʍ>N>~?N?Ҍ>*>F?&>4'z=A=z?IP=tKS&*0YҔ6oISHx轁iq>&gJ %=gbMӾ^W =n2y;m=p/f&$=td>lvܠ@>++Q>׿H>YJo}$ᾥ>[~EZݷJ,ޠ:T>FVǨ۪>I,LE{5;>Uwm Ͽ[>S8q%従:iBS'"W0>&]N)SAF >w?6 > eʖH-۾1R><Ź]9wB?.$v=`@;j]DQ>3ji\>,rm2=JfV?3L¿u!>p})`i0b㿏Ͽ0k/׽8a.8>]\Z>"?8eY>KU6M?Q^P>8l`)5<*RվTxoݘAbܾ>P ^==TX\–O!*rĻסǾ;C>MU>GB=pC>=RCvz>J>\q־}i0≯49X:4㴽K4=Z)Jo33>ؽ=6\ݵ>|WspMtv>3x%*Ri~AVeC栾=;OD=3=.w k%=Ǵ|fSھ'芿]zL> Uq>J9)y)~ca.(0%yAB ^Jsvߢ :OD zj<)AھQT#X+ܽ{ib}ᾅ`ږ ,>iOC̾|Wz>>j@⵾<55Tk>2⹿f_葟<)>((qI3|=߿PP>=ݿH!޿#>ARj/~;ߋʽa˿B۔$<>ҾdӾ"y_Q`(h4N^>GNg֍3=ξQvn>UiH>\ƜK]q]>~jbup>^ pe0<%Jm>5 6XѾH ^Z>nLܱm"ҿ۾:V(5yl.U־9Oj#p9: ^6? $=t>tlFqR;¿Q#pKOƿއX>FKJ;> =4>z>_=m ?,(:ƹ>c)>V?\ ->;%ASz=f?5R]i{>'2*-XBcQ!9['i0)?9M=,1e^>!J5 Wײ}?S )k>3bc5^lk> ?b>rXо 2=#=pw=#>Ai?(y>Ⱦzwsdw?)9F>> t;̿?c>t 5zSL얿p%z>=? /@>C^tC< b=M۾x2ܿ3ۭ|UJLƂ<M; *=ûpAF=g2> LTi/Zֿrf?RE>> ?y>Gti?>>!v?,,fI?b><䨾;t?(3J?\g>h>t?>|?Q=d> >w?'>Č?w>s`.o?1C{?x>6]>?>Z;ۿ`YsKQ>?pX>ZgA>a?p-8=t?m>>~?R>D[]kD=?b1@=xR?X8>VG>T?y_>)rͿ|#Q>`=&?c9=!-O>65aC?9[)>>>b]?=ҿJg>Ξ=?iΎ=Bw=U|c>Y> c>F>44?y=ߕ Q]1f ?>{>Ԍ?<}>2wP>M?)>)gmAȟN=-?{ս_Y&@*.!s%q>]$[.H?-x>yf=A>g#l3>Z >DwW=a篆֪?پ>k s?{> Ⱦ pF q S*>?GE>4 Ahk>hLj?D,= okaW?u>%?B X>t>Jè?Z"^>;Ƽ>ӿbiFc߾,Ͽ%$y>W2>Ȃ?+$;ѿ 8]>N1Q>< ?r*>m=:$=I\$`0==gϿ#'Hq>Կ ?C??@lCa>8U> ?>:VOqM>E *e`cAQ>f# ' ( >\+;/@~9+N?Ti CM¿>#nM@d;_eý7i#*|yԎνh:)_.̱ٽۓM=뷿£\=HboǛ3B+4}V8?AK{|W:}c>7~?e8= ֈ&*>6;[H?sּ?}3U=Ͼ?%=g829&=W6b0?D< M>,oJV1D[>:*=57gdI7O+H??Z><}V;?1d?!?@>i+8JZZ?K'??.?pfվ0Y>fՍ,o]y%>vNZ4:%c?53>=xDJ7d?^>A=>gm;v͚>?@>k3BT>ρ?R>ߒ侂Hs=CF?;߽!Q0˼wO2+>1dǾ?O%>bV$`<|>;%@9=G/qe>Փ>S*p&>}oJ0.&puvb>(W4TOÿxy<h>ad"' t?;>>}wH=q.̽D?(۾JA 4=`5j>0 ;L8=S=ǻ0?)ükX[>>>`?i>fA@s7>b>:>cGVO E?3ヒ^ L>Z=0 ZBh:H>޾pz,m>m+&2rp*?nI-s\")ݾd<?>n cD>?w%>tc>](н< X@:b˾yq%t.!Àؽ,=.=y3]=ޮ\B9m>V;0q?q!yx;$*?XeR>K] aT#6B=q?l>Bg; OBBi@ m/ !#Wv˾&mc J=`dR3O'}>?!p>@?I؄m >,O޽h8Y>? |=i>:Goz<l> ;,>`$J,_5?e=>P :>hW >>u9,>N󑽝C=޿bo>˚?*>?&ck?=>Pg'-fw>!B\!w>6q |X30!?bc?rn>`LF5M#>-?>1ؾ>c?.?>$B>2+ӿ) rܽ=?*X`>RK> [p6!Z0>q?>Ѐ57=K ?x5> |&l`Fܻ=ھjz` bx>$1-!6,KuL@>+""B+;Rx>+Z߽IJk; Ͼ_6?iJ>k7TNl ?gɬ>G 91&q&u\?U >7!>S.?>K.p!W@@Lq=;9\5`ӁR߾3>j'?[æξ`GKaL,?]Yq>>U _/#?Qk>4U>Dຽo#)?-50&K >4m3?%>R>+a7?<[>.0>قݐ?9Fo>>>ǀs/1z8m "W%W(?տMY#p%;|3]6dG@PP8&))8eP%>;z-j*6ksh[>}i ?sm??3 -N>==|ݼ$r;57A6?>!=U;B Xm]]>n!?Ǽ,?Fg?n=e>~F?l?x?kc>۩?b??]L澾L?F0?&?hhE= ~2>462X* =dzt=/=:>p ʀ> *vbc>@=ˎ(&KmeA6H> oW YQ>5Aatc`?b>L׿.*NƾӃ0$l>?Ɣ?f?kOCp02+HU8=?sQz>bD5$AN?yL>J Ӫ8оxKmޜgIpV XQOc.Ս7`Imk?=?>?E WľF?_WO? >(5Gj_vtB[{TQ>| Q>i/0<+>*#&MZ ABN>"g #%AȂ?%?:?$l>j,ؙ%>8ApG>X3@i<S=ܿQ]K;@=͞a(Y*q t[>ȿ=~P?^e:y>l{><Ͼ 5&>|/b?ifn|??mpP?mE1;ו#?\?w7?6=>ҿ%$R]t?<a<B??{g,?dL}t%=Jz>z6 u= tBOa:)q =>]9TV>\&Hpv$@= B*c>f, mJ=оoؾW>Hq np>v' 2nDBޠK%>,{W)3E >c-~F\p/8Lϯ㚿>gnPdx=欿c.۽WmJpOHt>Bf4-U?\Ҿ*QPT:>{FܾkHM:EH>w6-:Yapr%= a>J>>Q5V(>)5+><= -P3U 彺?-|>sIk3>,]ֶ}x>m-6#`!=$ _F!]]>U>p4w=󪽾L>'v> k@>Љ¿'=1<TP W=x9>EAk< BL6?~NgJZGpvȟ;@a[v>p=CVڿai.B1@=`ݿ?eR|Loپ.+Ir}>Z>|>e0U~g>u?à ?>961ϼݱ>crET=JN>)0G>F?$?z?/WaF3Ov>???|2^>䃩?Ց??ѯ|WeBS>=E.?/>?-s?q?dO+="?? ǽ?6%1->' ?K?6`?<H|0>¡?iI??όC2(SLUsd?A>0?'k낡+ =2?gP>p?`= F߅>..=c̿Nzt"5~=+ |q/>0n4D."%>J.?ү??%>K)__;@?w>1?,|"$j?u%?7^?իðUE >fY=$QAls>u=: Ͼ?O xqϽv+ &@=o]nm/G#տ7kJY~.|ASApw$΅4+R;ks)߾ 0;ow>с U.c<`>Z@?Ir+b>?7_Ƹ>> ?tF#?ܾ?99?;!>Ϳ1U># ٿX5_M>!0ྶR =Ih~g?@ 2׾ɻ>Lv*=U:9?y A8v>5?X>ߙ=>ѝ>=?J>"(>$>=ϡ?IwCN?{{1??&0=mHO}3?T1..|ؙ>@ \ݴ=JAg+;L>x>]&D`?Ѥ?.x?=>,7ο!9u=9&؀ۃ=CxB~Fy?S.^?L?R?5h(ľno=Pj?l'? 1J-㾟1>{>;?q1DWm?At?/}?FP1|){>E|?'x=qz?] 4fjŏP>yėm=?abQx)*0BnTa>HVñ֨>\> @?o:>>nU?~‹uj =?:>u?2=r6?GaG">ްuR1ʾ>q>Mpa?t i>Cz=eq?Xu?QaľX*=qa gI?MYs7?n?/EcPӼ ?]? $=U""W?E˼#??o?}?E'Jh'?*]?C}?Y.tM?z,?X??b1?#|?k?N8?`B7=92Q)\>hg'0肗Cx%Ё0E$>STOޘ<AL.=Px?#>.?_?/?Z:A?ѯ@= I6>/ ?k7?54Nb)n? D,A̾. >O=]d?l|?t:dP:=l?L>R?ҴGȾ?>>V?o+H(>APKJ՝?U?npQDv>w>"?q[%r-G>AտAoU-+˯>3߿u5~>6>H= g,A@'||?r>ogȿ;پ}>s+=Mq=g ?K+ )>A>Qv>?_7ǒ=2=_ 5?DSJo=8af>#p/0[>mi Y;y>?Kp?;a?T??n 9?ڼ=l: F?C$Z 9$>9?@>\t>D>?-RDZI>>kY?I \ :x%?n>߿(y> J;743>- >>YOf>ZBl%^lQ=t=S߿,"_=?fw?KA#vmY;u^_j5+A=~ؾ/!>4+?v|>A":>l"? >5 ֡Bg>=\?+#>ped<:Bx?mU?U>_3>;:?/n>*l>L??P?XOuq?;Hu >u?4Ƚ???Q?>c˾:SC>mQx?A?[n???M?0?M#?/h:t]]>?d?szc?;?p?{? ?:Ea?[u?(??d?->? 6??1?@?R/?Oˁ/>)}k1]=0 P>LQWrF6U>xWW/$?|>7H0xwZ=@?!G?`??OZ&tօ>-?dK8XYJ=?qِv|8G꾔Z>'WJw?qj8.:=*Z?^R =JĦ"P?3@_ڻ>2Ta?%N<'( |Կ> pvo쿙9>ɴ'\nz=d>?A>Ȇ 3G[`>h^t0I=>ҡ?3mj@?$-]b=!q}[Vm<=޷>p~"`Y>}?@:?xsi?UX2>OH?T?RF?gqY>>?HD|?z?^X9;/bѥc=q==MM?]בǼg (?<:ҡQV0>}?G?5o?N'9Y%ň½>Xa8ۼX+>+[rҾ>">>}[XZ])  2U>SdbaC(Z;Ͼj?Q`7?)>>F?$\yJ>?[?A^?EX*oY+=>p?7Y?<bM ԽHm-j$*IzP3<:soA[Y?s>(?7o߾<>v=Qi?:`!$? >Ty ?6L0E7Vͣ>' 5>t܃4~п_I)?4B>uFU>a.?Vi:ҵ_>h> >?I""&R?>M'?N_A'h{>>&?V`|YcsP>%)?>J?CUžY? ?R?Z/Yѯ/?%?i[?j..V?Q%?*?=)w$^> )AB>j ݯș\?Ih̯ɼmʾƛ9?"l=X>~?? 3|Ap>(p>\?,ɧ?%hl;i>'>G? ?R7}+>i>O'5?xrB^>[>Q=-M?]PXA=I˿4> \c|j>J?az?m@?rep 7cv0k=QPg {>NP>2Kz ? ). %<;Gd >3(=Т ,> hީR>fo&>yWfR#R=˞Ͼ$ >Af,Ǿqj>g=[^C=芾 (==U)\F$>ľvyQZq؄.41X:{>T>ʤL2ノhj{?rtv,KWi:3?(^#g*qĵ߾4>|#R.]ZK$1?# / -EqZ,.?)_Y9`Ï]5?>p?D߽?'>Ala>*?}?d9?`>>?#S?xS@>>(?3fj-uGy<%FU ؾV:Qn?4ȽЫMfIW=e[9DFQkU>ƨ?V8>jKܾt=?#b?n >w="=?|j>i O> c+R۾ξ?dqsu>}> ?,p)վl!'pE>t2>j&M*>ē&<.0wF'n\_)#!>a?>*>pb>D}}JU\ ̾S,?#uVH %CRx-? 2y])03U/pz>~s(63>==ׂM>F>n/ci;1=}>.>,R>Jb6r>F(?Dn?:e;d+|vG>M>~P?d J=,^\MCcչA>rPj=~/?Pn=8pƿ׮޾f?"fE\F>ѽq&>>'Ay=O>e??w#;ㆾj>E4>3F;9̵/u \t4]Nq]ۻ软?.>=(#S?,; R>lL?$R?Q=z}|=w>V>/RKJOν\zPذTRNOHju9#'2/?پLI>vev&/&ܾmһOn?= 4@I=ѿQ9} G@t=KSGc>3T~= 'F>I>)N?I?:aVCŤ*=h<>>,[)BE>P罿kɽDG>ɽ]s(a$fu>[aNNC;D>7C>A7ۋĽ 4ZpPDŽFy̿*ծfi; m;ş\< ⨇/9>O"l.XO=\Hn!YvrujW>ckО.F(1:PLۿ,9>K9|U,kYU=18 ߖ О>&nV;Ԫ39VO*o0IfHؿ@q@~j8x%l@tt˔Y6ASj]~E޿{YOԀ?oxcK,>7PLjx{FaN㾣??xڲ?bR(=<ʴ>z?T&??9nC=v>+0> X>Oe@=->>">n+J.=(> >,.>vGC={? >?KA;3Rp6 ݧ#½{Uh ݜ2һ>qtżK=7">$ N]E|Ǿz'Ba=_꼝d>7>S:io"=^$Wi=oeJӿMUMD>I@5?%>܀A[Zj9R>??l"4n>l^>lP"BɿW>T>?Cx#^uq=sC?Va ,©P{>a?0n sj"cэ="=TJ?%~cx,7B"xKYs>&p@"C>>6?aJ,dt /`=Jg4> ">XG>7W0>B e_ 8md_3>]>kn ?Q_5:\p/="/?.r}h).b.q>{!־X_>>?@xh ({Pw>o>V?&cmj%$$5 'ZYFvS1mG<*=Nÿh4Σ>☫?33?{l?bB+37> >Oh3>*>m>ȿ\=ɽ|>d _=vd=Z>']}x>:>) `)&=7(nqnzB=ɓ >޹n#r>#3>*l>>?=uC>uD=87=9>t>)?4S?%-z&A=jR? g ;n/>1\d=?c>$@4C>*ʼ>Ho?~E>e~hÿe˾GD̸A&^Pr>]=G33v>O>3 ] 0|=]J 3>p?*E?c?Cꣿu t>C,>n?P>زj"=w1>xĤ>D<(_+I>,:@=(ǣ}> =ξ?&"H =?v6?I7v,T +> 9Žx%v?Gؾ}[>Pv#gX>w/|K>N>4r;=؝?Chjxg>P'蚉F(?T: }>Pk8K"y>eִ-Y{g( AU濈Nf E,j1@!K|W<7:#f ,lb'}ؾk<7a'6JUXd<=8!! ϣ=p'=z1~>>I_e$=e>p1Ͽ d=ۑwu><Q) 5f{ݾYWLe=(;>'TAt# 47'B#ѿJ, qwg-M &Hz=;e>&N=[os>}=AB?X[[q{J>j׿׾>H>{\>ЇB?#j&> N>;+=P:gAֆv=c!3+ƿ!>s> 6޸մa=WG>q.A c9=&Q]-! S=# F^6/'>""˸閿N¿O>V*'[Q׿0 >ͽ{K& =`cbߺ/'Mp);ۆn`WW|>p+cZwE;Rο35coan>W[=t;ozܸ9>b5>e@r!ٿ$R tZ.#*7X,n̸3e&VPX;⾭Ѿ`JvSϝ})R=퉋.4d}pƸ>-&n,#N dRSK^=ژg>?IΓ}yBjс>P*=Ov?h6"v>RL>(xh|k߾CX=U* gJ떼E,."R>T{-=zQ$a>㿔.Q,0">u޿xԾfQWY6Ⱦ8R =!ѿ ʠ#>hӿ 8 r(`>H?O֙WJ6hKƽ G:E1e>R<P$8Ld-bA>C!`qNv"HR T#=%>F?\V>B>ma>+@>84sGI<">qE?] >IM>%V.>2%M߿Vp*"y?֦-d>)>Iba?JB9$>Jv63s^w>^fEQ2@Y*?&>/h{}]I$ċ=ob=>a˿f&>ޕT>AO7A Ո=7_-(>|M hr?0>IRAH%LM?+97+=fFIIRtm?$ =OY$Sҿ!+8?L>/w=451~?@>獵%$?3x >IJ,/d8^>0m=唯+j=}c?g >L}H) )?nd8>WUq־u2>/;>Wv;sC=a>A^>,vѾkpY&?>.=qO?S@=Q?>Eu:>>?z\>>2?L>bT>>?z>X>u=>*?dZ>?i>k5>E?}>S^%l?4ڡ;T[W/;m?Q~x!ÿ^dԻ=?3%T3;~Nu=[CN?9 ">@+~Z>4'>#o?'c>-ӻ? >Ǫ?B8C?J?,[?$!Ѕ?0F?M%?ЀI?2?R8>׽ ?Yܽ c?<`>9=vf?y )=\pC?M~>T7= ?x^ =wʧ>]> sq>'?'>vǂj=d;)?pG $1c( >-?C>z /뒟?E?˼>8Ba?*_?*?Z*A^rJQ1? .Kͼhw?!Y/w*>?d>4X'>aQ^,YG^ >`=>վ>>_ay[L?4 >@ޏ= >15;rX=3)þS>Eһv@B>r>J?z;!'Ks?緄;?>6G4=z-?{B>/8=9?;EakS_+>ߓ "`mF;?dj?$2">Wfb)4$\ Y>J?]C|QnP^Ql(pL+>Qr澼f!?4Ll@ >*.<=?>kru3a@~>\X2>/Wq"=s =f^{z'/W?Ev=g%ͫ>"b?=I#`C>PaA/?f7z>G=3>:qY'>m=>]=?Of9>?`=ן#=©@G8=ds">{ľ8l=<j>Z޾  =na_>g C-=2!=?:@S쾹>7`? b%=0󈾗`=p5Jo)ؾ>L$?=ާ[>N?>`cӾ`=0?c)I>Y=3==G*>s]_=> >|cq+}6%jԯ?Q.0Lf -pN>:` ?=z"=T+0g?$RG$|2Ѧ >߭?y>LS `; о?JVоV hPk{>]w-f=K>W>ٯ\5"JU>=Gh׸Nh?PX_ >=G˾5 o?HY.>Bvr@E5ҿ .4S7>N?>z%=WT=B6k4>5UT=r?Z<9= d>f3?^=oH=DKx>?> TE&Ѧ??Z>"e>=kj?==@!>=j?z=N7=%B>/?k]5>`Js&/>VT ?M?9??; <)>."`>D?ty>h@0 _;<8*mU?SZ1x-.@͖>K쫾U?9Y1.U3=ھ?6, 1> %? MAMMk>?hi> c >qu5˾FR !>=׶=TݽS(ܔ^\E]D>((?1=BЫK;>?Zh?>jH>B>tR`ľְ?Tc?HS?LA%'T?XYd?L?G$1h ݾMVt!?B;RII>\=?:=BSs>>?e>Qפai>a>Ӫ*I>n k$ξ? tL0`ѷ>>>R?s={=͡#>_x?ڟ>9bоoN\d4RWFR>.wr̒!>{>ޘݾ.0|>k#S,$G>8޿0睑4W^>s)?<;JQ>(k=8d>c|?/<>`-&j~>s?OV>dA2h>%,IW< 1_r?+=??kJ k;M]>s1-dK(d?TWv 1y `tc0?.mzz+!+nj>Zi>u2C>0\t\+=v?zS=>"kyT>(>V >W8) <.#=?)!%gDl0W2ͧ>Q?ov>=ApgL;>Aw9/>uտ2QLl1= >}=7#>a*/>=GȾs?9IbJm.F$ ?콬bSt$Ul>ܾs=͓w ?&s>Q>w4GP㽦?eDg>3P? $*@OEۿH=? [BH?3>5>o|HՊ1/?5>9> 7eVOUO?d$>]Ue ?2>qv>^c;E>0?1>V!06 ھx3?Z>iiz ۩(j+$Ov[7\K>KQ=Ȋ=њ> 9=kAP -|bL (֙XA@0odl+5`R3r >E5RH=L>qߋմFO>?Eh>>/<4H!pr>i=ưٻ y K?M%?E>%Y`K2ܾˉ=Cl(z>K$ZGY A7>ӿ<`+&R>Š?F?Z-?6Pk>g?@W?1?ϿHaP>?kf??+3?q?`(?'p4$ѽ4Wm7ZHgp.齑N¾E$ڔH=ľ@!zELi?z>eIjm~4[oG=vP?‘?:?njC7P1] };*pPFUzրENlv=fd4R>pC?p??]@tI> ??F(?qye>77??L? R}7sI=T??g?8H* ciֿuCmp/S==п):QIR"5dG>L?j/?3?U7 R?= m>#>ߏ\ƾ{?st?/?*#8 ?/-^>>~ {;{Bj`">``n >4ŗG7?O?l?Ca~5?^/?L>~x0kU>x3<1Z'W#>]lп>A>qLaؿvWT`!Et9a8F?P1? p>ְ }CK4>B_>Jt=3&F v=-V8@Ǿÿ`N=TJJLvY>N՝xd=d+ _ > D| 4 ui[&=T"' Ͻ`Lz>hFn[J[=Z%˿:=vh\ [=/su (;~20+=C1ҿ\?-j_?D^ ?=?S~?R=ȼ?,?6?Cj>c'g;DIx>8E/GH>mM@ S8ӾG! k>ʹ>,<=\?G0sL>"F|0^_ܱ>>+ꋏ#>cI< %>ɼEߨ>ތI:*'l=$qC=#MHÿ6^ݿ?? Gf>}#Yf8>߱;u>`-;~,=:8.s>䗿g>P^$1P`2Ϳ GR>C@ d=P?:ؽb?>D4MY>?^?Qn?n7>f˖?^B?P-8?mM|>w-G3[;Ÿܾl>ē!!h=  Z>v=>Tn =vڔy+H> ދ1z>?,A?k?Љ+=ޫ64]>{>?ͅ?|6?>]!3U?%r?-?{?-(awѷ>(FB1ܽ6N >},@Y>@r?D>ިa@_'x; `?ĀM==̾H Bh>8G=mϾ׿I#>@1h>µ=??.x?[>[4>w?|?/M?CpttW7bt; c!v$e?Y@5B<*F>p")=J?!6>֑?|B ~)A='V?l>?GA&6)R?S?DP?ҿ]b. >.?X>{)?qP"\8&K? ?/?͚9$l7A%hD½}e.>&{?uN+>??wվ$3>3?ka>Tm?%B&u?-?T?4ph$$W? ?Oe?agOy }qHS>X.|>Gk ?!R69 T>D_)d>'>fgo>pM>¾>-k<?B90bnd-Ta?R>\ݺ -4=彔t:!>_G=iG?Sg"?S?^?.si>HӼɾ\>ye윽ϣw= ?6$;Jk>DYxU* >OiL@*;e?lYEpػD>c[fQ{キ Cf|[>^=Tᄒ!H^??K?P?) =?Xgȟn[.V~=?S/`}K>>h?@=vBf?44][ }X?C'l>>$l?l]h0bz?$?3H?WH5¤U>D,ý5]?H g=X۾=]y=Tȵ=4:=n5ٸ +< ,H5논` =T4Ax= =ԻĖ="xѽ?4 $Σ!.C.+?'į?$뾝f>2>?ˆ7˾gjǾ>T7r5d>PX?A%bd<.b=߾ u!?/]<'" n>q"BY嗽r?pxcx%`U>!2rH?#o|.+*< !>> cd >>#-?|L>_cþ;f>p5ϽƉAa>#}?Dc?Y?Ɏմ~>l?:@&=&;ri},>}C3x=jWk?ԷHCӾ+=@A?WO*֓2 $?65ĽH,5"@>lĬ?dG))+>3mNp˚.I떾jM>!#پ/@[? ND>h?<0H>GBL?B!Hо7>@uբ?M>4KeB>gs=z?tk =4;TeClwZrzOቾ?>$oc-C=ʿNv:nU=y!Ip|wS~ =Jm|-́([!^W>(r@>(?;>&#K5> ɐ>)H8>[5=< ((,=ӝI>(P>ttOʀ>%>? ezD=?@` JE/Kk>~A=><3/膿> q->\fA> >J1 u)>>?23=㽿 ^K;=>cP8G>}NuO?$rO3yIiy >_N(zWih׾>0M $JOs C ?vCmеu1۾ 'RxB?48:&-E?WT?xW>7=Z?_Xܾ&> b=YG?SΖ R$󾴜>6>"6?6M!I">>C?dž| +6> ] i?#E Np~>G2i7?xK]=٧;Z]?Feh>}FR@>]CwE<:܌?/{>wS?h"hZKq+>>2G?q@pO=Rj3>-N ͭ=厾Tm>?և@p =2>&$?[+@yF>fVy?+? )M՟qYy?5i :-tFw-?)EHekʾ(޾?PTTo](>Ye`a W>ɇޏiDxz>^?Zdƨ'XX=7 ?8(齻hDg5Y??){i>&6?ؔ/?Ͽ>5?޵?8Bo\=k'>աE?ΐO}>>-?Ծ/>>?xhE̚N>Sr?`?x E ? ?i,?QFVWȰ?Zf??LTEŏ? ?Y)$?}J?zp>\0>'?x$>a,3/r?>a ԫJ¾ >/>+?穗F؝?U?1+?_lOJN%?R(?X?]lBH?ES?m|_?g? ?}S}<_x>?hۜMCc ?-?bd?aeOؾG=?ۺ?F?M/!V@EN)>q*ӱozXEVm? _<꾨wKp"?%3npcĚpO+mYmn?H4}D4 % <>LT\H>ܵ?/%?paW=潥~>n?=LyIP~?r?y?+8Խq)4z:=C 08\ u,w?,_#>TRa.ͳXv?T>i^*`mu= "V\S-Z?o-،*nb:J?@ ́>l"?hȮOc Կi>`(#`?8=_<&?Ho0 =|UC?aPo?o|= oخYOklkHğA=\8ÿ@>;>${=S/QkA=p?Z>h=SJ?]?L]&, GDN_?$jlbh/j>=?J{r5: >ߒ=9z?/|^@>J>%h[( IFmz=miJ{?Vb̟Wb=dk[=cl>`j(H8V;>c>i A>,?IM#x9n&5?;U< ѽ;;m?E䴾[u>~\?6,?rR?}[=<2D> =q7?F:03& ?\o?=?4S\>(x???7&p[>???R{-?\9ﺌ?>^t>o?`>?I?Ybt޾~Z(>`sBp;ʯ6QG>Lc wܺMu\X=,Ǿ(b ,=>?K?)f8ف>|eLs=ji:d9:HC=`?xh>"pm+(vL aT=}1MP<^?JX>*IB?4YJ]9G9?K>잪?33b*RUi>I?#?#+?ؚ<ԉ58i>~ŰuU6?&?qk?qp–<)KM!#>piQ? o?A?Z~R?i~X`>2t>>Uah>B>>⛍x=[",#tq=bsaJ>kh?>V?<>0>j;$?R =GY3 >DF?#?l?-k?ܣq N_GBWhI <@c6{t@)>@69}*>_PTDӿݾ?$'FξF>go9b===s S>b>6-M`Yݾu0Ͼ>Ҟ(j>2heɾx(g9x ?Pfؿؙ)>gM__=Lx7A=G~6 ,5)B=43 C>,ԿG>a#/PRb̿OIp(Լ s*A^_4 >[Sie'fWENx]>-ѿ-^>}'ׁ2Dɸ>ǖnu6 >}?MR? >"WC>?{͊?e'>PۿGNOn>.=SN>8/QH7t==S?B6~q>龺%:P>>l>?W?K2>Zmy?+>E١U^>>|R%o#,eUqxH!w۾=WIb> K>"]?i??T?5>0#j>+(kY>fyꋱݾSLMY!>ӷJb=hbRN>DBzc>q4(>ƽ> x>P?jesFFtn,Xr*bA&Hmgw>Zy>PյC;35:?>0{>cM8AfV>Q?G?=|N?IMa=Y>e?>TOg>5M>I\lX0u2/ Vs?$*[L@㘦>'?z,>loJ7G>A?>:uL޺>7?o>ƖLྋ"}!?>9@+|J?CRV WJ E??A0o\)x-EP,)>> 1!]NOk>v}= O<3/@=y|#!U?>n J|пq?psw>S'檏LS?>Ԓ6?D?/fJ=/f>O*?^>^5J>υs?<?'9aJsG>Υr?;?$}z?D?wqz"aؿ-;}$wᾴe> 3 $V8悾,>j&0*$u>EھgU9?[e=6&-fN\>!?+D?UÆӾݮg<^=:=>m?+n>;m}}#6M9ҿ&jD1eRr!b'п7YB%k4%D÷l'>%}YlQ,+ؾc>[l<ؖ9$}oRebszH"S۾7>f># ?mya#!Z!><>WI?6|$'2K=gy?zx$zS~S(Z9b!-kL_N>ʊe ܾ*w)>jWI8>X>?>zq!\?4?!X2?Y*$u<^-q ?Q1^ZLϾ>_A=A~Љ> =jzx!d?F0?1z5?KE edž>H\O|j/-@a>u7m,9:Hw= >5n+>EWXUD;ʉݽ>=>ߒ>obǭ>z>5?=?ZIF_?+?8\?OC45>1n>Gk?K >B9?2G`o>׈>-?$?@rWT>|aR>֝s?;?ka=¨=>Ɩ>S=lR)pq莾O/=]wuDS>a>PSq =[.ǾOV>kF~UE^`X޾Q=]|@>'|F=*DA>>V G)>IK)>)׺=;5=в-j?/ -&nlu<HpD2=ۥ j =?]|>-X F=u`LYш >f' Gh>WϢA->ֲ)ӉX|Uj)k1O1k<>k9Ӿ # ]Z$QmbLL7ȼۿg(L#(j{$>i>n>?OeE> >>E=ߟ?AFynYU=ߛܾFu>о$sBF>|>=?Ft`q9>dT=Ǜ= ??TҽBt.=z̑>FTH=8<>*Nq7hj>56J&xi~WX :=_a"dʿguKI= wn>[ET>⵾uC?f>>{?/U5l zPcAX'a0@F`Ŀ@m>fS0BBl=߾!>K#܋=tF?hdD]t㎈Y>^W_>أ^=)Z2^-5

gU0$5=Z޾8ȑ߫=DwFZSJ{?x)i:>qaqo >پYGAq^=P>Z L4?[Yf>F ̾sd\ izT'7 ʥaO2׾ć ױ=;=OoЅT>B'9>(C=^>3W;k!=,g>ƾғ$߻aSb &8\i?j=X4"¾" G'syI8$>ܾ*ꚾBJZfsKzx:ޱ ˛0" пUt)=9*c*Ț>5x^6>ԾN:;}6rT.DN r>J ZЃ4(Cn=$T*>^VzV˽,59e>տJ@8<<:P@cZER>NCh~f'r`-MVj`vW=t6<} =>aXPi'=@=Gf0˿ZrG>M?6g>*”cg>6:O_4ƾ<1ʿ 9?Ma8D> *k*A>-V%q&+<.%B51C$#ϊ+? 꾖DH) 7־rO%v}>dn `=hCjcu>><>@BqPVV'6A[(pYQX>D>׺>)VyJ;>L@>>^Wͳ>lo>ȸ>:if6me1'e^M˾/?[澘ܾsKy2Lnva;Gyh:>U&lP?[l>DC-FZ7DZ<"@1Iܿ)c# [B|г 0FjƋ!_xg/E< |5 EJ0DF6k䓿 ?d1> "hEl Y?Q<}> VֿR@Q#n?'*9Fg> GL+Q/?F?Cz=v^O>\FN=3׾2Ͼt޾?c#j>dVza|j>NST?m=7&I\Zyb?z1 ;>Y%>Lb ?t4>XT>c!?e>la?Zh>`>3'?b>?NNd.E=o~=>K? >c?V=:E?Wa_Q9BtĹ?RAp^ҽGؿ;_>D ?Vu>l=)=Ϊm>?_>0@>>( >?g >+Q7@ &6d>Q\?P.~=Q9Hc=0)?0b ƽ˸>f?>jbPq.R>B@t?^J>|h#"=v>K>!?S>?v؀>$mn?d7c.pjU?MF|X!!ھ?Uʹ ,gm"?=\ *=>a>ig?/w>5"Q~ @J?/@?>>(8G>!TB3??B5V= s:?l~KϿ~M4?ln/GgH?OQ? > g>Cؾqh;"_R e=!Ǿ64U?QHA>U=چ?܌;)goqC e 1<ܩ=/ڃDN@׿a>?Anh c>^xT>!dڽD< o>`>'ti>n>Z=?)(>DݽC ?5<[`@+=Tl3?] ,5<4>; >Lr έbeתŽ? 1C9A,y>>jbC(<ě)0> 0z74]^KRo{>ᾂ?Wu>e > >`=u}?!Yy:>5>j _>V½1/9 nV=d>vf>F (>=?JX>|ex%1>?VZ=X?b|=LE).3=? F?\p>qg$h>%'~_?uHg Tc=x:?۾W`s>-־PL?4侑Ĉeg>#?SQ>d ɬ=:?^)G2ʰ&p>uVҽD?`h˽Eyf˾J>)>+>5vT><ʆ=&;DߞB>&=q=LfV|Hy?OA[ݾ!mk>>>wR$r P'$8bl=+_{ ΅3k!>akt%>"??#͊?c!? C^>e?.E?v`>ȿ^9co>?-?K?kLMm^b?Bٌu3Zq>Y*>fq>VlW98`?sy;]d_ 5HN'?izBDF=6>C! 8a6 >Zd>>@> vFoLJd>ɿľ,LO'!%< ?M>>#`9 ???&fa|lT>T>ME:?=ὒJ_/>ed>,>($>2'1  =+??n?>#rX>-Ž־tl-BGZ>a(|?'>ȅ ]S_>Zl>6U܃=%t.^Ajw>8>h/׼$6d*!>\L?v:>ζc=JW8t޿w,>R>߽'=;>nkrY=[?[w)>?)C`*=,p? g>O>_[a*JB>;vrum0ν}|?gJwj/!n (<W+0<u?G-,>U;>d0-:[:?1X>>Kj ;?4+>>?{5C@L??v{>>O1GȽ*Z\?-x c7w<-Eg?O>l/mȢ fVƾrYV#<^?g?_? R=]=F9+>₥??AJ61, ?=ɴ>QU8Wk> ?Edc>v?4\=C"h?!:>~6Ăo½Q7?IeM>Kx~P4>׾4ei?D\>L&?/p V7*9ϔa"d˜?3>U>]$->D>ev?w? sn>X%=?rM>ڃE`F:d'޾@?9=`_h=QF>?{'>[x=]>h>G?M?5k3ڧ[bMII(DP ]k鋓c<,~=\x|~sz0g "W>>#27MYNBd> N>.$6L:$Zq4?1c$>Z+>[A}ݥ2 = (EN1X?B>eV@x!?` >e*?%J`?H/>ǿ@b0rƣ[!>?!??/͋l? >>^;L><=x\P9M bѯU@2oȬ=lJi+żЫ'fcA` U2=G&\M`LM?G|>f3H6ldF]=>@?s?Ʋ:L[w>@ T??) ~Oxe)$00䑰p$>(@⋽ަae)=@: ȿ_9܍]rR>O@?߲_?4Y?uBN.%0:'>EPDa%u+4ҀD>#9ܾz>5EA -A>^Z6㼐K>p >]RAȿd/O*|bR>y{ƿ?W`@CNHr=1?Ɏ?+?~MP>-zLɧ>mI[P>$bþR!ؽF((>>(DJU>@>!$U?=za[oz(. ~3[>VZɿӮ!">h还J2jfh4eXTXcxt0pD>(6T:BN@=5&5gaIAF&=J???t?Az5V??|?鸾Ž??Nln?' ?gO?+f?50xDwPϿY`M)Ps_i^Uk.hw影U.b9l/Z)G!A6W>QeR.H%>>P*ٝ pv8>Bս9:>*žSa=E4V>N')KVGK% ?\>wCP>þ_ܯ >ſ 7hq¶>Q>s46Z%c%\/`C0>cl5grB;=j??z?*<|ZUYɴ$I:"Kmp=`^pɂNF>%_PĽ2c>O>ÓP9;K=?:)>gKAd9> ?\*ӽ>iDZ>A?Ig,>nD>6oPvA5+??<%)?y[8.Ad ?xT?"?N@mGV>'>>u6!~=߿eVH V yX8;FVKL=Fr'[>0p>6>R>9C%վQ>~>6˧>TT髿>6gxUCQ`5>Fw=TJk(n \6={XK>%; /=j>lk>b\Oһq#!CF]?e>qq?0NQJoUe?(?|?`7 Om?G>]?qTދE 9ֺ?.E?;K?e=a> v?"? {?kA<=!??J|?퍿Ƶ5A=ջ?I>\?-;V>.?h4> }?AC?0& ^=|Np =Pq,^>6xB>˜$Ⱦ$F-*2l¼m0]\^2 MתxR`Fk<6g "27i<dE ;e]ܱ>$J~ϯ>ˠ@%0I>Hv<=]S]SiAzr=O+ڔ,v. t9ݾ+*gȿi2s)=:&p=_xD׉>u?|>G?TFC_ELG;tTPD!=m 'N1f=zy%Fn2=N5>ɐ AaN=Eg#H>Om?Nlr&Z=ƿ=kv=q!> 45W>$?V>0?z@Q* g+㏿5iYCw2)$/d:jRlt( )-I<}f˿Gc&=R^ң`̿ 1W=] 8X*=ɬ.p\0e@;=)sQFvGã"Y\Ӟ~>݁tx@=ˮ>>?7t>$S? 2>ْ?z ~mSڶICUT8vȾ 3Bn"b+9$!.>ž+N=|x>!qI>OcD/8>(x1?u9>w?!W5^>@?s>?qpO$O? ?@F%鴾8?0?X? =;o?jZ>d( rsP讗>]qm):>+V?N=jۡ=kV@SSb>&4>VpV$#lP??Y7?*@do[''Zu >޽)=+?`t>ܽU?TCL@%f3?W?3 ?ʎDi%p?~Ri>lj?o"ܾt?^?n?.sE&=q&Z>4z& ?^?;Ɔ?ʵ{`+Rj'l;XϾx{?Y\g;gz>me#IhByC$r?a,-难i_>s₩D|a=2>Oq"si{T?L>?"ytoĜTz>N<.?ng>>?`h2þ->8U?Ipp.J R>l! [?Rt:Ĝ=]u qGlκ='&)%g0V *[& پu#p>6;^9>ݽYd?Fc1;bUm=FRM?&N8\͟})1Y2m? {L+8<@iw?Tf=JT_>\@ϼg=(o?H2U:A"z-lg>wRf02?'W^IϾg>>>e?g-,?W&p@MvSC=""3?6xp2O黲;x>{"2d![>~k(}=O>OfI 93 ==.BP>Vs;SZ!5=>Dнʾ+=?tu`Js>}@8I?cXg:EF ݾl>]QE=M); Ŀ][P_$&|ځ <>H$2Z%/,>x?R*LQ߿$^?.uDĨ;Ӟ?e€D˾Uy_B1>6 >2i4=m&? >㊾"_ >WQ{>(?.4pL@>6=L?v#n N_t?M>|?aN־<>5>#? PAdAs=kTP;Y`!~u>2@JeL4Z> ^>nkFjςo>VҾ->Y`yR=E->>S'*4@>>@?#v+>,=–>5`?}B>0`؀>O?-T7=>@>JQ?er~'PH?6/]$B>Ǿݦ>_ρ&4m>35;s=<-Ln>-}=>?ʨi'?<?QxB>/J>۽y@ц>Ufۿ0q >3Mˉ>.7>Pr%>O3׿2>@ȿ >aþM T?M쿌b9>"W>n? ,?k4+ >kP>8 ?yvlM=w>G?[<` >6à#-?aw=>X˿Ӿqq?o*R2>= mr?v'J0>/Ոơ<4?l:T=.=K(̿Т?G ?7sQճa?tX8#`G(|F?HH8 >T5*= X@s?q>`6L)V;z.^?@`W-~n>dZGlUH׾=9}??GH[˾̽?Qi?Y @QJrhܾb?HnD}>Ĝ".^>sU'>>,YQ">#Oiu2>2~<>?)>9Tn־O>>}T>͎CYrÛ> & >t62aT\>L>^N{13=p}g>H7{4ޗ^?wK: [x̿J񻡋?Hxb9߾lu;?c6C0Ϳ'Ɨ>L8g(<7׎>xtCw/$8Qn>m5>Nb| (8Ɇ9R>XK>!B=C9R>W :8>dST`'=|2.AMn?%p=ŽB>k?`ٶa4½/Ͼs? ڰf+žE1->!h_$8r=ď=?+@ zb5=6>#: x?>AHB=IJ R?_6g=Dlvw?L%ӽ4Rg+k>;?>S}I>/K5qe<*c >L)?B$,dxe"A4/A:>"|n;%-`t>.Qe $>>-) Ǿ$=e$f?,׌ D%3>UL>c?@t>-^.7? g`E>izh>~z?01`J.?%_?,D?R;/9h¾L  ? ACPg*9>$t N +>wh⾋*I=]SǨ?WQHD"m۾/>bQZ8iQ'RvihQ=y}R,G1 vѾX>1/Du^??6ku>⹿@E>yJlQW޾]>0>z[?]7V>e,?D?c"Xx}=>y?b6rTP=]-x?R%˙Y [[-=ž?P5 cb={-vE?eC.q<\پ-?RX+"Ka>U~$ LD?~ \1U>D??l2]~ܾ>?B!?K̀E[d; h4?J&c2U>VX>k?*8"?iEm;X.μ6>|,?/p Q踼z> >3? XЛ^ :=>g?6ߘ^o~R>O.>W6>>uS>?]_x_&%Gk>9 6?yET3>(?Aoe?p?ۿQ>l?P?y?T'>I?T ?@p?\,=ݩ>\>ߞŹG]u⾙YK;]4>U7?,?u2i/.qv>=?b )¾>=(mr?֌a=Y>*A?;?dm?pA5"sS. =? hb?9?i$d=V>c>ǎ\?U |^t>Vo(G?+X;QA>9?0P?Rx?hLYI`1\>>:u?1?b?i*I>dO.L>Ǿ}&?i$JK;~*>xϾT*?X\W<ݜ?~=4? >D*?a_zh>^u?-G?a??cXi5b8=*?T?O?ouƽdɧ>k˽k?9ch>,?!J,?Q?LfNA]`c>=?X>tfJu>X74?&=0ϖV\>}`”?/Ýp>>q>}>^QnS>&_>eʰ>>*|_dY>>?"?ʖfͿ@L>!=`r~'i$=_z m| TlUFN%տg3=;> %S?l'p'P(>׽?Y+;fLuFeq<_>?F?l3%z>(a >d"(>Uͼ?z?#x=j>s(TXqH&B'ξf$?4`>X%?lIu0?9>ȟ?cs>,>l?j+H1>p??Ka?߁Ʉ==,'>5ؒΙ= (^>U?R-?U~? ?ti?4?u??+@U 1W`y-2(HBh,~ g)̾H:c C ր n@(t !omiPva御Ⱦ&㾇O\:"t x*>Jc \>DUP'ABAX>7:ž&4 g8 5.6S!#4 5NHeT&$#)= &j4=,r\rX+!OX}/ hw;QaR$tTCDN;I!G>0qei<> >? k?>f`J>O> ?? ,(¤PעϿ'CH|\=+a;n/N2K%߃xᑡ7)oI Nw>?*I4)'('1>߰؊ᾩAֻw>oEÄ4亶>=} $FqE2澪y\8]G9ѾK x+0iN)G{B !<)T"t`$?;Ef<9=弈EQ&S>zD>߾>:m>>>} 6??O9*fY)ս[4<8>h%f= :R}={ѐ4<'"Ne3=Y3x=*0U;q>N RY+R>w[-t)= *f.m>B > z>,#1ھ#F?-z?B'|>>¿},k>l,hpar|?2/>FD @?1_@#>JY:=տj=5?r!/>X->B|>2OBp>HlW=z=^>6u)x?sKST]#Y6-fb?= .=(j7>i>H >;iDF? y?%3>4ʹF-#Oh>}Ak>>mL;ھFnD #=[3Bm7>,<%jFƽq?۔G|=\Uo^?<ٽ b?N?H">-z? 6 >?}h́,=/E> _=_?v,> 1>|5;!?B}m׈J0^>"Y=y=*1aDؾ;Ⱦ??@x!=4; >P ܔj=ྃҷ ?VXs{3>>lZ>>?I>Xm./`(>GzƏ5>UžaX? Ȩ>w!8>+,>d'J = >m??8JY>/V!???84HC>J6>h?-?'#I:>ČT>A>4( BP<*O] >O=N^9?j2\;,=iƽmh?chI!lQg;bǾ*jDG0y41, 2f+T뒧j># ?m`6K/׾]_>z?!2? .0L0kfC>#>qpPr>Rgza==BD>T*#%Jsrpmqoſ#M~V>e>- տ6=9q}>%1b(,/@>]Drt4A_>/H>{6>U;ѿAPZ꽓>y>CK>?29?R8>[>Տ?B>뷷F׿ DJ 8=zmYYZl=WHWyٽΙ:|lj=2<14&([,sU=xp&˿CͿuXXD7SF>ltt#\]= eEk>wt!'>l>Ĩ]?Y_FC!%Su>-=rd MCx>Y}>*?O%>`9>~L >S)躾==M>.g,tjI=+==ݾ6F'zw:=%47=>f5lʽ?}ͤ'n'd.EH5iKf4+@ݾDn>O_N0 =!$j쾽V>*h{ؾwp2H5vkA$Wʿ/+v&h>KS<2{7#,agk8MrT)ewʧEAr6t=.*hE>ٺ=>Ny[>R[u'>>­=>2>E F>>U`?g=>Me(\׾3W X\(z-FsT9x"ʜVKxtپ Bk T$7Dڣu"AW閽!.;]? {>$ϳB`N<*1Q~>6TG=$> HLj>n3'=#> M#c'?3=5ؕYq<0.jmp,s;R/j 0=Y 5ٹs>%5pgoV$ =Mnx60EW'N;տ(!UPd0DKT lV^F#{60NEdcn<>52@H{W G>E=(cw5k"MyQEtӷG>o1n\RK1b᜾gF [^|dҾXd377,̽_p" > * ` >rm@H=ЖP>$D~=akC =ʿ6K$b>Cb=?f~1>-52>#am? MRRY/𾎁$=U'K5^̾۫"T.>df +WUz&Tſ$Q#S8$ArX_Ԙu W1?1'>˖( =9 >?J&Ks Gm{(L{q|с>'c,GS>pL;q>=8Kو?&dQ|˂k^{}M=O4ǾMڌc}.Ft =4߾f񽞓{F& Hy̸]J!!xWZLlƻAľ??lQ>A]=A>,׌TC>|)y[7ӳL7g}ڌ>e־ >aיtתƬ`|D=|>.E2 .o9M=kiۿKŜR޽=2q>E>F̻T??;D;ʿ@:Ж-4j^`=Xr~*8f;R2@)7R؀37>ovxo? ''ݿe'?1Knq>eL쾵8kk=O.>T{Ȏܿ'2'W:m22u;ѾDؽhZxR>ɿS}1SZεNK' >1ӼN4xt±\O~|O/xVK>tXKbm9npƾz3b$l}龰rҿpD*leؾtKg-!uӾOr&q(ؙۿ&Y=u>DɿT||v{㬽ů논?w.5{>dɾɾn3?0|߇=g>*>\jS/%uv`==œssy#A7=r?WTp">L<߾F]O>'{|$X+Si >A徧dt[[{ε=q$~܍ȑ=n<:Ua|>{BwWſQ8]Ѣ> c(h#p=_>$d>gֶw>lx֮>C>|_2@F d>s 7S>%)Le7¾ M&tȈsR=ft>SΧ>@>Ϻ? Di=Z޽rj>ھWþVD^>*I<䐣>m8e?t>+>+3<0i"=63 2]=¦ 0#2$yҾ?''d5d@n:뽋Z=ˀ>C0c=E21# )I`Ң:=l~>6. t?Wѿ?&0;=ԕ^{ DCy_H=_ߓy/k;=,μH82F>J`W> 6=VHN>Blqz> =((khhP= 5U7x&$ J}qVǿ J=:)(Q.Ys^>6?Ϳ;c#?f~>j+FJ-bDΎ'Z=>S>Gl_8)=4fok9*Oο@ҳvP>bh0ƿq\EcE 㾨>(>>ۿɝ#۽ L$޿"ٝm)A>/ҿiDG˿? WC.#¤ۿeR&ʝ?9P$>EN` &=V>>>Dȿ,> ΅<0fu*> >KZ6a?X*a>'$tz ?~M>g7?<8 Y}?*>Т*Ͼ5x?U~>_548o?]'_> yL9ꚾ?p>Vɾ?sM=hEhI;Ns6@?~ A>ga?K=+ ;?_>c/BNտc9?a~>0$O9)r?#>s}caNE,65?V?>WI>#?>a?}L_=8>\&?\h> x@@-4>hx?#:タ(@9$c>sR?NϽ2?u}i>[1?r?L0?_@ I>E >7??d>B@,5b>'g ?dն3ʽ {ޱ>>,J,?ALK>v\U?hڽ;?S>=C?Tܰ:@'x1<6>H=&Pa?1=?+t>deb?0#?6?7s 􀿦KI>*?A>*qtu=T=Ŭ?2Q>X~I0=ݱ!?lR=4v)>u8>>?>z%>$~>è>6?B>Q=?L$d>G=4?O@=C=DA>?G>oic= W?{=^(ʉ¾> D?k=Q]$f=3?T>\dVY>?>ʿa󳧾204?Kƹʼÿ辩>cg?N]>\y'8;'?T)gl@=*NC?7T w5=GW(?/sp"~k;=Ȇ?H>پ ]lݿޤ>X?>z$ڶ <?eI ? >BA>-o>Cdᔟ>OD<@h?h?C(>R>?> >ݷ<>?4֡?_>i? W>C?06?Y>>?En~>m>#<`>޾;j >n=S?߻x?6WjA%>q=*(>[d.fb=zpz; ߋ;Uξ=:?hc~>a?WT?x>^# 6Ae@y?l%hU ?+?&>ѳrۘ >?J>ܧ\&?5?S?'c&3ݾ=PH>lj&tɾ]3L?-/o$ \A?^tc=Uο3>뉿ǻ

`|(&>:d>&5=r%ZnKM> >p~?tuO>A)&ې>:?Z?#?L !(a,>Q?-8?F?Y^7XFμ?þ~n>N> U?>rl>x?v۶Ϫ?<>,GÓ>l܇D )`?j>iw=?[=9^ ٗ>P@?;ܓMxo@F?cn>a= nyeuO.N<>{?Wl?O?G0,At,=zѽ1>F3iW:='3lm9<*;NČ;!r9Z* +<O?(CNS`;>)}J}>}unG,>^ [Ku!G8s>+P޾O]z@ _J0?L_3π'ɾ-?V:r<Y_AM?dƽU'Y'[?T+@H>>WC?Ac>CC7OSi?X>9%h=>0푗>C½l?ڻĿhVO{>Bp>O _tJ=<.6q=R> g= 1U zz;9AȾ(_?K=< 6۾1Qrzx)>>'>^( i=0  ؃d=G͊T>{̧?g. #t>Ԏλ4M䨏6>`ٽ1 j*@>/?>1؀z>TCr*ֿP=$r嗿~}>-:`P8>u(27&C=H˿)0 }V& %>Vw- ?3CqfY >'F~?(Xx>=%i7;޾k8=ɿ$.ܿuG 'L쾍=V>?G$>:@<>|LpLL``$@(w< Sv>^wLu*=$Oĵ?"a+' `ҿlI0> rzP!ѿ:6#?Ⱦ >ȿ4a ݾuV5"%=ri g5k-* fԩ(}>Yg ڿ>}p:.m#>7>>@#!>UVvc=ֲ?%>m">ޭ5&FCF=C?z3'>b:ZD;O>>G>3+?𑽨D?4Ĭ>@>JƢw>׮>0Yd=`=bv?Tv?W6?싼C-;\%66~=sW Hw]4WQDܿ1T7ׄ^>9ӿ^oֿJ#}Tԉ<ĿM?rp]?"O?,<R/|kU=?9>>L^>$?3>RO>Gȸ񾦝s#S œ>2a> >/=j?cP>͟^j<1EO?'A>K ?}>+ ܾZzeI$y_0[<+$?>֡> ;3Ѧc?,0>Zx)g;;8=n??N&>ťvO=?a5xf?=u='=g'b>R¿ @>,˿zxgxW wWp.8,6,-_CBig>cH}_nF>XWQ>-OAAϑ>􌿤Ή{ 9='K/'e^M9?c,>\sFc>nTزANh>Xݿ_տ{ߗ->as2"\.??r>$飿HL{r?>tvڿ?:0 =ǿ !5gqV>>U|4<`>Y`=XgE3>X| nF>e׿d\h%߽Aی>d MsXo>@?P?0f*)> K> = ,h @xpm&d,JbQ߂Z>xi@*s ٌXIVU>E??@?oL;P>??C?]K^E>BZ??5?P[^>?ز?n ?Lm(R(c>bJk?w?yO'?fS|j =?T?6D?ag[6>/nƿ$XRdq%V>Wu>FyokV= M?W? )>uy~k^k>k?ِ??z\>O0hF=J?O?f8??H Xk̋ʾT=u[o.L'щ1޽2}iLU|pVER>P@%>qD()>8,!>"_/ĿY`@T9(>Wμ&;>DInzp"N&> ?ܠ?y?[l)LwG=(v?a?e ?btI+&?>G>(uWbN'?Ye?L>^W?v ?:l?X*ͮ>{c Ŀ-ͳ.a`+>&БQ?ѿTPߋf2zeR݋>I\1l% rѾ> s:eg\hj !=wE|}p5>FVWFp_9 ,>yR\{UWAOv>ǔd">>a PvOc(>???#,QnL,?.>>$n s{tfo']0]1B%tOjF=??Dx?SXkc=c̾߾C=>1?& >;{6Gg=BHnm۹V.13:qiEu(5*=37=Ϊ(ul֣l>Jؿ 0Ohg=T-Nq\F}>#x- Ѣ>nku<4˿xa$Z=SjVNwmh^> _=l񲾼q iu=t*ү(=8jMu>)E ݿZ%hf!)z-(=Lx*=4&?>@ЫW L+>nRLG_?b?%?XJhK#O53n?ҳ?SSP??͘t =ɿ./¼}AY=,[ÿYsV'7#m<UHUW\^F=^оZ{PIם_N?a,?H΁?9@@=}XK8 1j<[!@sl`!rO<*?x?f? tORܾϳ?.?U?w€j>_,0|U>GOn[qw>4O"K%pK\>0߿W\S{5R\⾙ZK?@?m?8r>L0#Ƃ>o0OK0mλ^ݿ7PYۧ=Juڿ>/V> ˾=3?=-=k>n/?>ȴ?R>:Dg>p"?і>?mhOad=p߿7=8<>>Q?ٌ?8?zIK=9 Ѧ=I(T#dYw =Pzl/o?#R6 m? ә>?%/ށ&9?>?F$~7_ZddP@}0 wc%0@J9qL߽qh57NCZUuxjXk ;h=kaG>2@(,>8=>>a?smD>D?Uղ>>6>Pb?}+>m?n@7{==`> R= =5>]?1 ]3/>,'&<ξ^z>]9>+Z0i>WGN1Ft>ľ/>j??"a?e>4>r??N:?R&U6ҾYɿ ;>=e>Ѿ cb>h TB,9>K??#y?f)b(< ?@=T?dZg0`$yo>->_=(1>}By`/wsn%_? 3{%uy9jl?%h+='[#Wk>ĸ9 7!<<_\>0wu?ZxSP>{=A3xw~߻Q, o>D٧~>=޾>]>)< ?!k=k>N><%ŀ!.=@)>ؽY ?u],,|=,nྗ?= 9 sw\=‮ JI?=zՊv=R C`A=# `z>7q >(Ň& >6i> Xڿo'3=Nc^>ϾN#n>`?>7H?2'>6?0H>?!>e>=`?MpX=_t ?Ha>J/SD N)t>9ѳG-Wi=z $>VGuu-*?e}rO=A> >l ?N8R->=ӑ?}c5 M2d<%_?1f}05sW>/o)2] M>Bhj.L>2aV>qT'Ǿk%<=?Vgji8n;>E=LXݽ;y?>b>"9">u>&=.4?z>e C>Ԑ>ސ>Ra?U~E!>P >E>?V!P>3>ӗW>.?=lzQ ?dS*Wd=;.a ?9_ϼQg>+:i?G?)7qoX{>xQ>5L)⾔f??>b *G> ,;Rƾ C.>'H:еƧis4@>v A א.A3=x@<5 5Ծ>]'=_>I2;?Dоkf%> ]>?M>*%?(,H;&L<4;B9ėݥ >l?j?P?0>꾌{w>(t`R-q >'{@/Db2>D'I=$=;Cu>.E5=PV (=,I=/T>nmk>!8?r^5݈]獾&IvտO>Z ðTw0h٥>4l-6o0I hD2kIo~> `M>,Կԙ7j>|J> C׿84>cBA=7]>h2)-6`=ξk/av>ޛZ 7;s:6_9cufI~< >^ldؾz27>ܩ/6>'?=Zn0V>:Y}Ul? LbÚƟ;Z:[4`> !;Xڿ>7&?d@p=9/{>&x-( mT= anZ>#l$C8M>7"Z-?d v .Q2̝>yH<8? 8T3>?/٪9D,a>P: 2hn=A[$ɾ>q2^ >x>1<>:6?qqQGmiT>|C4`ҽ얾MwTi>ױLW g=/3?)i4PR;z/_>6LK~B ؾY??8Cw>jٮ+>'?>x}h<>YJ,"V>rU? >b!@D> 5 >n>f>݇?pq[hs|ZHs>^>.P@?f ilv,HCN=4`Ũ?.0kd= ԽЅ?%wh=<>rL>>os6=0$ >? w|=ln?>%<ܥ7V,0>3v?Sz@#`5n=5=Jœ?%D;%< 2=s>~ 'j{;\W=d>C9>r?1TXA5=X=>>k*zRX5>w\bN߼:f ?~ d޺>q]=?W'g?R}=G>`ݾ*> WWI(ؾW?+M/|cb$ ?Z`/I-l@M>4:)ދ~>2ܾn>`W) >n>E= h>Fxl>K;>>Cw>K?tye?|?W=a>D? u2vK$=k@>rѯ>h? Kzl|>|>?CyKG<^r< >!B(`k辂,>,5H6H?p̔%<>8¤>>J6]>/'[d:>R?N??NVQ@:!>v>4>%>RcJf >>K'?PվD~ 8?(z4?Q=X=%0>5ECHr=N?b,Q^=2j _?Kc%F bD[>C&eW8>0kv k=|?]=B?z'[??`?V:?|?{^pr=>k+?,O4V'?v`?92r =>= ]>3BY>3@/o?,<>ZY:U"@?HQ>l*4?wH,J?t>l |?~A YP3*&>d=?f?Cٽ1b>M>lRF?j[!ǟ|;s>˼#S?P=I|W?(rҿ >m=伖(̾'?=<[c(>nD `? ;Xõ|>mg=>9P>}|-<ՙ9JG=MQ8v6?e>eQW?? V>@?8\=;>p[V?2&j=>қ?#p? OcEr-=k=Ⱑ#׾$ 侓þHo'4;.4H \/dм5 ^ɾHjH=8I r:TC H #a 9 .Se" =IV.Y> V5?a>+%v1>uf6"D"E=q*Xu9i¿['Q]!q=+ 6_ȟ=օ3[>>z`L?)j1g "pm=,֭Vb2^Wއ_4/8f#KnPS|k{ CcY(5QSz JJaHϠ<} -ZD>_FCXdؿ.vSU`|[=wiNj>??YH?Sdhm>=?A?ViY?LQZ彦tj=*[S4SdsW|y+ƽ߹ B!G#wn2Uo8.N|UH5&Wu#0hwkv$h(1 4CNz>>M^Ս>*G#=LU=1zмIrٽ Zhh0C&"4BmjػԿ VX2tLSPҳds\4 UɽXAN]8$B>)zpL ck>-w2^u:}ؿ@(Lr9?C>'+>fƽZE$>[o]|dw=4Y??{=ǎACH=EƽjY3>eI>A+>)_Q*>lIp==? лz=rq>T_P|>s>?sTO;FJ W>оMVV(?;a=Y?1R>3PmD侑ɽX?@F=^B=Ҿ>l?A|>w=HླQY=p&?H)(>>91JBs>?>o*肆=D> n=Se?xB8 ~vJAV!?.(@_=bV_+g?;D)ސH>΅>A?SE>>>?vyڋR>mY?yq~?ds?(>^߾q>tG>fwO><=- ?.jK>6>{{)>8Eվ0>>U0? X>-=!=}N3?k=->[>>f>E?ǀڴ>}?U[%?@?efp=2?z5i> G? ?!2½?Zƾ9?ܥ<ä<=n?ah]>n/>5`D6/{9>߼o?o<`>N,>>?c>M?>1? )&?">gP<>H[?xOH=?`_??&|0F œ>b?ti>T;Dм&>P?W(>cE##_ο-տ:7sR#<7Ĩh ~= )k##c<Ɖ>.)0\#XX,=|'c5T0V=>9@?_1JؾҼ`9%~?K@ jwKZ>ސX>eI>NʿhL><|VP=pX=7< ,zw!+$E5!l=uoDb;i>:6?õ>mw$$qdfMʽ#>;l"Z=OњYy>f}$5#L%_u=^{gJ͚>Z8>xk??dKS>8'?>E 5!׈s(l3k<-?Q@G"GD3>u|^+44> oQьٵ\[>Ps#8  >O¾v>v??(RS.<>P>LTMܜk< m>XX>K>߶=g>Q>k>fTPR5/>}T~4>nț7>Pcݷ>!,PzP>ù.39Ce6߮= %V2=9[2v=>6>>m!Ȇ>hMw>,?NE8$HϿG"c=RQ;Z_7.K+?uIeLHR4]|jþq\޲ci="ɾTvِ>!=0]>sWGzh>P$OU8v=a>>:>J=`^{J+>ԹE?=? "xQ\K=#'z;\ݬ1!UI|\|RN=TT<>̒g @~@B>QL>?.45`f) 9$=#M W>0˿6<1!) M¼ (hE=6ó]/0{F> W/N3>=S 很B?JRŽe;"o1f`{,ο]=mlD;< >_aAFnPr ,>p"?\;g%>-џo=Q/> I>s:( J>fT>'F>^*=̾1'?1]? 6?;^\-{(796)=>{h3k?4Q=ŗN,~#>>!?^s>"Ehh#DH>7?]?"n=L([>6D=߾=?;뽕";'j',>x>3? NV&ξ>|??%V_<^:𽍋>X>ɼ>7ʿM>X?Md J>O=>© >3?!6ḱ>zս+|>C6=f2$8ݾATC=e>V>z d0KҾ[zu,=6z-$Dҽ0#/9=PAݿ^A_/Ԅ=X*):;' &G=ɾ>>) SE>=O>Qw?x>b w ]>1AO?J-=;5>KhΎ?0mŽB<؃n2=?Bp>_>u!=[N-kh}1U>eо!I=~`?eP= >uUXO=i>\x">:qEt> %C#a>= .>v>9W<>]\=3?TP7>2G=:Ҿ󽾿o>t6m/=žC T>/bf|̽4)A>je#[ '>?۽8jÜ=wѾV>+>тtl>hsy>*=G0dm=پŽh6ICq4yYma[=^нw~=<>Ybgg侣Ծɡ>(cǾT־r羗>BAd?> ; ]P1oʆ]|`0 N>٩DDN>>.9a󽹖tU[24Ͼ_=%оrK/E 1нEߨՄ+䰟>(Wh=-oۿB_uIKs䒛>S>vE=k=Uʟr3Y+/5+յ"=Z|پkJ>Lg׿/ϒ- q ^ )>>*FE8@M>;Ż>zQ]>XtZ>.^0?2ʾAL>)Oʾ Ik 6 =ܭ =,Z މa"һ>'MӾ[=>Z<] i;m澇k@nH=G5* 7=>+P>H5o>eE.ܿ >>>\̊j۾݄>WGQƆ>:ͿSӽCPO<>}% 9>aݿ|N>ƛ2>c̾CoK>Utq2=e(:eE=0Ͽ M>kJz>֟*;l@Ѿ^jo1&5˔SC?~>50w>P > t!!wv?=O$>&]{3p/:}rn槿ݎ\5>cݿ:\<ίt[p>k3$h؏RFJO)r2b9}맾.g׾gBg:y=i^,Xfo_ѽ`xbiw65m)֝0fIIS>*k=Ia!T\+SWco19=׶3dBv3Q$O~/x'kʾ&$G>Wt4aQ"v)M"4U᷾޾}-۽RV<ʾ:;Xޤ=zO*qZ>hǾPOz\>Eվ8K^nξ5b~>ĿC!'=3+>t>K)5<5>0Z>޿8]=m>׿_q+^U2/h>Q!ڐl;2cB>tf=xy?1)u>O >Pa">gvVGVc>1~GroV.\_!Ѿg_4)MyF[پ$#{-e%ɾb&/(އ_sm3QW3axW>˿YfWܿ4"Ϳ}X'>vտl^cD]?p(o> ck)L쾟V;q?0>[ȾB &渿i$N=BݿT3ʾyݻt%35LA :f=I>>,,,R>oKD $=|8'k>WE.P^$9c>AUL?4.{?[#0>4n] z?#+= 5eǺR?E">:2%Q>G>Jk>Ko?a>C<^͎=PLGv>>R ­=KZ>IBվ̸/^;\>=N?RLD`>V<ϯ8& ?=J[>GM!%?BR>9orh#fZ?&N>tBS")2d,v>L>i̿D龿!=\?kn.>"oa26&@5?Z; >WNտF_ S?yHM>FK+?_}C=ő<8?mgw= @4>,=?=h>@E@$>ӕ*?o),;W#xŏ?UVa<r%;}?#c^1?{W}>Zg? Jk?W*?s@9?${?g>s?N>?@F.>nӕ=D?<\=2kǼ^>.?lD>n? /'>I>}??5>'1r>H~|>R9?>|=*=GK>̕:?J>.A?M #><>-?o~>)c?&(.h>ۘ>?E??*eX;;N~{B@< ?|1= P㾘g=?>+׿A"q>^?>Là@ p`N>(?>|ھ]>e?v>@꾆G\~R=ᄉ3n?݇s.;ݿ}><.=a_? ῒ=3(>? >>bA:>RV>/bt?>*H&BUkS?-D̾o1++|>U?nY= x#x_D?@w>}8>`:2=>ϾxHA>%>>p)?pGW>>a>ף۽*?j}">=+%>-+޿`> = ?=Ib$M'=>j?}>9(Āf2Joo>z??bY>"O>>9?.?|rWd=2 f è7X>2?>l3A>uo?(eЅ[Ta>643>L oO>$/?\}a==>EV`ϟ$ž?\=پĮ4[=w>h?U>??S7[>HGbZ1žԪm& 5?Kh*_ %<ݯʀ?:jw~?5g >Қ=>>߽?ha>)(觾<s> g\B> ʼHEʀ4>*տ$^>OLGL =ۄU>er4+=!>)?#3f?y?taM?6&ٿYBSK? c>>"=E +H>;S>"!?Y> @>q5Sg>[m _wSO+$2<Ɋ"k8_ <=?e?=y?ރh!PQ>A>h >9U,؄X?z0#㰾*>y V>VvdSS.?Q *F>==`;??h=4P7;:/,s޾l]1~ȾQо"ٶ,-_6!,y>ܾ =Ƶ Tkɾ^Hb@]?jŽ<7߽6;Q] lR=!F<:W\V˾mw2!S8?P~ܼI=\/k]̾aJd4j* \d&1ȸ1=\e>?ֽ׀4>.O,V+]N{ξ۩LCTe=o%i>o0Q6T:?yS5>stat>mwu{oAݾyc (1 c>m7i9ȅ^>z &(i/+PZ>Kq>1>?ͿF>.>۽l%=5>;r<(NQZ*1-b‹=UAB=O).z[$( 1],&#OX< ?4w>!g6X ?\= |Ɔʆr>@S?Op>j=d?= >u$2 ハ/>F?fù>>OT Z->$^k#?_>(},!ɴ>>˸=w7(`5>?WM>VA`+Z>(?b<#78&o>ppg?Tk8tQ>zQ? ?^sN x>N ]mPeH>辶ȓ9> *>.Қ=.QjuW-`e=nF|?aF=dK2@E;Χ=?}>dn=ɿܾ5'_ \>V>fx:=ƛZ3Cl? UɼzfP+B7r? n(@='JM?"Zg"4-?%罎e$Ǿ?S =H+XPW;;{>R­ <74co!D-e>6ݭ>ce5D=/ǿ0QH>Us>m;>(c7DWzF>A>y*;!> k7@1Y ̟>VOU޾>-0<ھZKĬ>CuɾK'6YfNϾf\>5s>TX`_E>>c5һ=׮4> CpĽBM/>}县Wk`=>|a$ѿlfG,R]^d>2>D>A>5m}>?tm>O>Y)}7gG?*=oit>L'E||cV0:>&7ֿ"P>m)运Ue`8e>]f%QLܺ)=f>^)?*%>k>5x3=?>!>y:X½c?P7>Wm~!$;dk>~g#13C>xSɼ< 5 tl&>>%>>S>c0er=K>8>> fW!$Y;7>C>R>5N{?!k>>>myt? f=WGj=%/ڽ0ߜ?3>omW@W44?G>K>m =T 'z`N?2x)>vv;tkz@?">%)=NOC̾ccqn?| ?f_=;Qz"2WU҄)=l-F9.6=6n[<$>m'5-fN>Z"6Jn`"= [#( ܾln,|押fR3$6PM =k+" 8K0>4QQyuV[½Ys>> NU=;d_?>>m0`E`9^)ξL=\So@0[ٰ>q7FV0'^<([[=GwÁW>#(5 F@c>]xS~H Q]EaZV>:Ҿˊ8X0Uy>GEpjU[>p@:^Ŀz7 ɽwS>D9}п_4])qːE*>:Nƾm>L< >6\,o]l+ ?x>}ab̿S1D> pG 6?1t`G]4>˽ hI(P? uGJ3@=͘9=?,س w?YO? Q?z+vQL?mQ?3?HxUe~w>EmS`A־T q,>.a>$E>C~JTѼfվAq>M{ ?p?I?*O%??c?A_ҩF!i¿' [FB^;쉿G^I1=-@>!2j {5>u,1>zy ӿ>:I'=1?h?K"?bW&37ڿW=eJpN:>oGOƻ@m={c**3ySS ->&N8GǾ G?02%>LI4:1Ж- LA;\)?#?F;?gpX@, =q?/>J4^>XJe->'Fw: >^?Q('>zpL< =AEY.D>l}_"= <}C=< $> >C>(a龡c a>dFc=6F<=U]k?ٕ>??jg[C<>^ N';>SZ":B>k,A* =Ɗ >S '<3gR[0dQ>T^ӾX>~`e2֝>$)p~I>Uށj= Ah7i>Jo=ő¿*>`!`-Jv=[I?=>ўXA=Հ?@Q> ? t1XYBz?=? ?J,V0h?#?x}?ZV;ޙ?`?n:?^p=+,{x&;k*0=Hb>wT"}{|L<#DW%)?cg>і?,=WdQ;_?XE>j?#F5϶$`ѻf?u?$-?5ڝHxc7,Ros- h5/X-"rÞ }=<]%Pj? >-:*=>Ց?N>E?xPSZ%W=2`p? >K<>gs_L?D>@J?+^fz"?+$1>HpT>JMᆵfb>=eIXgҧ?=F=JB?$_^>=Cfs>DC3F>eоO.ȹ&xWuw;N_R| x8n»/G&Cz srUUi*m!pnվ p8nz;d?ͽqahf0]p1>{F5j*)x <n=}p?( >6+(=Vſb'<mLžo=OM@=#X>!)̾"=>:KBk>x_?&c?3׀?r?>Уr;m>Fo?Q?j?QX<]HECi$'=: F>[K=W!1>I9??2?+>.v>,?T>0/?ʾv!'>?$3>P?. 66%=Ep.>>EV><=k-?Qe>j'R>}5[t>>sM>Մ a>Mw?U4ZEȀR>V {\@-V>RX! <]ko?%c!:>$>bf='(c?9L۷>>B3?"J?48.{>rr?2?D?mj?@Q33Q>3??:?}/RYXfԾf>1Qw@,?,Kv3?(nfH,gཪFᾤ->X-%9eȻ徃aV?5/YР%6>?Wm4(׀_sھk?O @=.۾ =2 0<ͣ=F,4?)T?/>w ?j|>Մ?8% >F?9f'>H(?t=WB& pT.?=J(Y>!>'>?/{Df>Ȥ6fAܹ4; H> :'x?2>B)c$8A >1p >Vƽke>J>\(&W>FD>`=p?*KKқ G(^_>9>R)&>=.>Dt0 ?cC Nh8V>X5*17_7Y$>𼾾 ľS*> (>+8;>݋,Uyg芾Y\Ⱦ1>ʘgV XV[kz_>m>8 ?&:4Y2[u*i8? R OtE}%HI=w)IѽclDRVRqC_>a"!8>^K˾Q>!>]Ud=Ib=h^ [^پ*Qۆ>D+p=bK ?z$#@-1>`(v?#?@'>C>M?Uֺ- 鴿To"d6ߘ#fDi>/AH!y-Ȩ6&E?hQJQ<NY>͟>-Ct>=>%?C+M- 꾅C? NlЭMm(#h|Y>k1pν_?bZt3N󹌿u>BJ͐L۽T]X? !?3S>ؾ鴾M>Ӷ> 5+>s>?[8?s>O+A>8>?2 ?=,>(k̟>?xM4,]>BXV=h??K H=y ܿ *>_>V=Z:?e͎=;QW.E>f0=V뒾I>#y.>>@9&>!?}p2=q=\0+? NZx(,-=<>zt=>j?=}xO{=὿6 Ϳ`W;Ъ~3{/z>~1?!?FB?o1>\m? ?&?aXvJ%>>[?t?Y{wb>n:Ϟ8XJ?A>R?lQ2a4U瘖K?22CC%nL?5`XY;\D>^z=&F5>K~\ͫ |H>!>Kx=>=%?X?x&>->G+GA?eS>>nֽPNbZ?2E=}N>d>?n;%C(>9>4,?h;Hx$W?>f>y8?x1{< g >H5=b?H4+_匾>!"u?1(bqL=ؾu?PW?e>0>vv?vU`Ǵ>K?j1}WC;Y0&? RDxŽP,>!l>$B?\jH"b/II> ,#E&?+>`@| 5)?50،.f> S>s> >HI>Jþu8?>8>Sz???1@j>?KD8c>>?l'>x>ۥ,@ =?^>?I+YH=ڃo޿W1>v>uy=lI>Ŀ^­>s/'t=Gh5Y>^:T>,0MUc>Yh>;%p>t9>) ;Y>=hA*|= Oxw=%A>Q ?`>eIVO>R?.?K`?Z5&U,=?0D?P?Zn>lN>Od>^d>{{~>7;>/M>x>bVG>/俪\y?,^?OcN?S2Ck;zI?H?Yǽ<$B? ?>э?A0Nj(t??׾0(? *?1{>9Ӿ=|?s4rWV;f>ƓKB㿻Aݾ+G> ?rJ4>`ʾ ٿU>kr=p2?A?4>#?i=7G{>=+Pת?6&_>"? )?T>q?EOh)d?~??nf+? p?,g?%^CPvi??5.?)m~(?i5??Ͼӿ<󾩾( ?L>V >]>jM<?'> m>8E4 >ҿ h=LK??3?ؿwOz=>v>8>4nq4m?BD1?l?cjM>Aɴ8k?u!C-iRT>Y^Z?kfM{M>ߓ?7?>`?4 TP>U lMƿdc9>,Q>ٖz>hN3K/>T Zq>zXqx1 Saܿ4\>*h0@}Կ8C~9f?Cl(">dVP5zw>o S>w>>ݰy{, پߘ$CR݋GA12>9c x>c1n<|Hf=xȾK~=`[NlL>)>~g=7Yh>{>]UwW=jem2{q;2r_zN{WWq|ezXK>)=|g,?*mrp ٮ |撾 1>)s)6> &>? ߵuk?s~9=6=Z> >y֮#Yھ޾$߾&󲾙ɿ*>q@A9s=Nxl j>A_>.doWp7|Wz*> ?q"?`t?vBCPj&!Fl5ۿ}|{>f???n?6 5 n[)>F=>>KIwW==5=JCͽP>UG|CH>?w)&Q+>F9I`<XnekAuQ'<wd復׮q0[>{Oۦ><ݾPq>T *2ӿ-=>T= %n p<>j@2>8 >rꖿ,=t\=[6Mv6rfT>I=s>,>-F*d>6>(Z>>ՑUt~g>S=%[>F>9L=X΃>W>5}:=e`BŰ=f<[Y =DG(=H8<5(kԬ=ͳ;>Dk'="ŵ=G1>P=4?@>շJŵ>L^;Ո_z>|<0>B>v8w1)=5'>qC=2<>zy:=pʽXՄ>O>H=OQ>S=-('jB+((ڈ?Q\>pVS]>'JOѾi(k\O4>?>X>t.?V?|=q>,Y2>g;I9aƬ>>m? >3U'nHb=r徫Z^A=ɾ >>had=ڐ>d֗5o~);ʾonW(>8>+fO{%˼q a!!=^ܪiFB ¾Mwu\Ui ghuᓿ րI~>%;/c#29R Vw9󾫯 M7[]>l˾aλ~:;ȊiF S?;C"-oV=c==czĿbW>&˾D>i>y؄b#p ;n4۽'5.W46]x)<y_N{ˇ8ס"7ξ-*,YX1fWR>>?OF?@peF!OK>>G? S?p&Nap3=䴾?hZ3-Afe=E[>>$umyIA.=j66^H۽I4㽪%:uxZl0 }$HBl>eZ?~U>ץ?xGN=6o !F|>u?+Ӏ>RT ?2T}S5>c>q?-?^@A*,b>?b!>g$fFQ=>?F>6+Ǿ ?t ?b82?<'T!}?c+$?M?cpśx6a?8??v(T>[?{W?.^@PHE<=;T?۾?D?!>?Z!?yP??>βѾYC?k> Ĥ>mg>"?#]>*&=GY>5T`1>9>Wܥ?Ȉc>Z>Q >!B?;quI>< 7?]B_? (>>(P¾P/>ۜ0U5OɿC=侯D `{Q<9;U?!P>DV<>JI=?=EC-#:>"e(?>-0>J<>%m>?I>YAS>?P>p-"_,i>&!i3F0=N8Pg;>X>?? H9Ĭ==??}]\n>+Ã>SL>?P݃>1LZ?G&9:JIJW`?0n>z?? 9zl!⾀,9aJQ7=%?#F??.=b>}>v?XCZd>PS>4=?U__=۾MeO?8l4Ĵ>>Hǟ=e|?N< I>>ݘ>?N>=e>=fNg,Ki?A>V?&"`?du[BO8>o>J>ZUU7<>C#>&=W-Tؾl1>~w?0#>">^&>W>܊>E'&A."`%Ĩ, :v`W1>,W1l<>,>)KQdz,RZ%d$H"JHbc))^؅ ? eM)ZY==;ѝ?vm۠8mmI> ?(?fdx >7r$>orqp!=͎Gj]=m iDʧ ㊾~w>N8KE.>4"?+;? -Mz%+=9>D>hVz2~cx%>!5>u`>\$I=ۍ?>Ldx <=g<=L> FQV=)ԿȽeKL2`>|>2?r> V 9iv{>]?P>]7%.d> ?8?*f#ځVĿL}>с:=>sO? ?~>Kaxؿ >[>ܥzS>:NN^?2?;N_(p>+ >cƆ>>?E,\b>Q>t=n~7l+S?st?d4a-((i 5<>G~D knD-S7خ:py3eHl3]H>^09FGc?2ϻbԽ="P5!=+ҷA^'U>n=8?z>0 >ё=?X >yUԥ=b9HG,>TS=P98X>XM> ޾4>i `=(=>\ěe==6*>JE=MXE7W@$L;0=NϽ Xh>&b=}<)|=Dp8=ÛEz[̵x>?0pHVEReM:0ǡ `,*ˆޕ6 >53/ c|>g>/>H>xc|>ATq%_->~'ԙJ>av=">A:~2=ɾmq">Ia>e==9>-H=N~7̒($ ˼=3 꾶F^M=ں="?P{Q`?:ʾOl>?!Y>}>1LR>%*"IRa5>G>i >S01zi;M=J=<>aE l<>_du4 _5_߼6 K>˳/ڈ ;=>W?UT>Yu)5 u\^ >q-w.~ 0j;Zu="= _>D.tmJ>>>u;>\k>[uzX:@u'77vO rǢW=4suw>ԬzK>$;&DR=v]>prk= 7>Yb>}m!-=cw>xx@[»iIԾz]5>^.ڿ.<_?-v>pGMpL=%6Đ2=WXzhન?0h= Tvj>.8?w7⎓==f,8q'j8=B>K>=É~쾳d>?=@ PL8vU?~(>x?,W94> D=l>'WOgD=wJmvϠ[?"[nPSYMpuS帾ϾA޼6Lſ 9Gǝ>ڿ$~ ">n\>oIa ={1XOli#ѿ𾥟,X:Թ[iƿ ;J3X >[A F ͯ>ʿc 6^z=a}=>l+ <{]U'9>d7E ==C\dVT>uV;l>,;=nHaJB@>Hrmپھ3)cv=߭U" U$>%eÿ&MM(5 ; ;`u.>s$l?>\Q[W>\y=q? wp$?TRF?>(-?,I=k3?v2IQ>\>7c??$>jYg=3>Hs!=5~gHӞ1x+o/'=>%Xd˖+GC>y>,t$Z>?107C>9؄j=l@?V=LI1N%soD z 6ΖC.@-0>z:9@ ;L"$>Ӟ()5_$ъ>#N>-[Tgj0%:S>ǿN"GZ&5?0&I^>;5X>cFE><5uV:? غ>L Lf4H?Q4>` kWO]>L@> 3 >#|6lXQ?:C;d>s}?q?5&?-@H> !?'>A`?$>s@Gb>vn?eH?)P> >?>?~8>yy[????M=<c~hib>W~?>l+=?z->GX?$oX>: =q?>> >4L$1>6=q?=욿}`P>m?M>]5 hĽdCjH?; }P=O?>,a"vվTU"?E<>lzh>ryW=(e?c<[~G,X&?4-mjGs=A>+j;:?o%>h cWOF x>޿c!ABҼz?tɾYEB=&">"CkSҾ1?Ẓ? >x?>?j>K> ?^(>Ƶ??/>fȿc܀=b>?>g^?>v?i>.?wX>7>ϧ>u=B?hd=+᤽GRi_=Vi/? z?p=]O{΅!l?ma=\p 6@#>5f>@-$t eǾ? ?P?93Dڸ?YcEB_?f>%92D+ Cx@1g= >ɋ?O>~$_> b>Ͼ?J^>͓ĿƓ>Ki?J~?y>?I>pK=(}>+ǿ:N >>K??_? @R>!> [=+MS  q=&?"??!@yA5>.;ݾdZvs6ċD> |>>UA9VC(>*5>r>+|~ԾnP>r>&|>ey羣!&=(kY-Ҿ|1n퉼l\5=|ԾeD>eg>; 侁'n>B׽v =W?G?T3?JnT/;@־v?'1ǵ\?/5;BWɿ&>V{%yF ?5ߒl?'AqaJ<2?=Pw> %=1*aQ=5eHP=ՍL@'xĿэ>ZJ>ZWD LG\VS{?jTŽ49`O's?dypC@?ɟC>~D Z> >o4={NN;?X񾅇/uSi!ɝJC80(a!7>ԙ3T<"şMy1e=I,($:<5οxO1/>Ĺ+ >֌>j5>U߿9S7W@Y0&S:>ݹǽdg2arP;rFЪ*l2BJyμ{n-UW8)(IqhnGk>r0J2rʮmG\>>$=eb>m}8AS=W%AG;U> d:?Q:aRJIm(X콟v R  z5L۽ff? >>(>rfTV >b3>X)>$&"Na>Fq>ۛ= F>S3~="=}pE1Z6s<_HP0)('Q(y[n(>fE;o6ɽ,7uu0˾SR%zAYS=B0aA2e2O@ G,5=?==)7o&>t0$3U=HG,-'>!ufe|A޿0!l&H>*E.gI 8>]=Ua>Z>ǿ*C>< >y>n/ ݿO@ܯ>sھzɰ%S:N>k9hk^<:VP6oK? w/VhZğQ$?pE>0%((Z=͸>޾1ʠ=܈#>dV2¾V3>Ǭ[ |WCt 9hQIӉ?DL>tM>;t0PaA?B=>4=s羒g>x}=;]V@)>dý$?lQ>lQ&>l^?><fv-I>žN>3>ZڿG 9kYkj>,<¤U^>3Z>>?>>)῰n9>/?5>R?Vu Q[?|?mx65me>#>z1{<1^>@=T?Y'oi=cL{>Pҽ3+i"p,派>+=Ve03[x@>rv=I p6鶾nM>*G=yrG>2JěǿynG>-@hg׿=1<>HzݿSpeqT=7߿5d5ziV!>#߱>Q>Vm>[>^>r? b>>`y2;M>==I<(%v\> ?Q?3I9L'龦% >Utq=ץ=mp#k_;]>>D=988IptCǭ=*<O6,,*g>t94!e>{$>}X9놾2`>v>Um_H==®K-Mٽ¦4>2"}} Ȃ=g;y++49Kb=k & hb̼pB4=짿 L7D?_=\$p "9]*> >ҧ? J9.>|i>OQ>?EH(yin˾q> )@u= 7.9i=y#|Rư'7p=J"Ty}G>MoW+O}> ~4g}j}}?>4>uп Yo>ro?O??\>>m?j?e}k?Q0V0>@???GVՀ?A[?P>sjyb2>%>r>c 9Sh>ݺ???mj(bBc=؆Y?ŏ?s ?Z&pkH+ӽ)=B=:?2"wѰO?3==&a(<{?%2k @G<0>Pa1@>@-I_l?Q>P?dc??4c/=?P?G?.~rk ?S?#?Zl0J@4܃E 2Ji>˧?8ŗ:H,=Nmu:dQ3V<-y=,nɟe9뾇tj4a<_X?]d?7P> zH{a1k?y?Fo?*Bo~ ?T??<1"%@8>j]-/$q" =)'eP={MŢQ>}` 2>=D>_>aI)Bp>DڝXzakA?qy?:?Sbs~_T?YD?"?tz20?RC$?ty?í}ſ?%??Oa3Y'>7IZ"PpeF)4&j>}ֿ;ܿ1J)ˀ"+=IywȠ=D?Dt>S?S`p>dq/|$m&r?M >S@I#ym)>L>Kʧ;>BpM>6?H?uG?y{)(??bJ? *@Ϙ>H"u) n>2r?`3HS) >R.?7 >152IlQ؏C?_>[>CԿuUx-SO6eL>MxȾ>:< z)>םҿ?t:~>MdZ'9t @E'>{9jDb3'?&>(~[-p=L=>5?p?5w?@IOQ{߹9?w?[[?`[|W7???A?b{ ?TPz=P?eN?m?#tY{=*?U>>`? %U7z ??$?WJl??C5?s¦[.˾T~J?b?@?i OY?l??z@L={X-_x%|2-,΁>FBh.t lU>6XQu=.>@x^gv?2?HW?w'=7E2>m7&;Νؾ?kDǩ d_KS?AB>Ή?]u\P?Q>D?L.8=M4!MXkP_Gkf__l ?fk|qv CWWx#hop@,=Y0fN2tb6DU<[?7GA>^u6?LK=U?//=>%L^#6Ko?cG>zB?+?Saf4rH|?N8>6 ?CxBC>C?>߾4?S"kE<>9?o|>8i?>oH<>(?l;>O]?FI,(wxKgI_d7I\8=ƿG= 5>FyD=CNk)=v>}>@+Z q,m`r` _:ɾʈj>6 uҾ~q4t\hCfʂQ> 8޿:Qia}T Vʾ>{Ňi>7=~$? oQb=U BgBԽ{<P L%нz:@5c氾U?>,w"P$)CW'D>TShʍ@Ū."j>]{ u=pS;ރO>t5~h:UҾ]F(>YX>8 ,,>2&?9d>o?m ?\0u.>aA??*?݇2&<>' ?7F9IR*>@?'>?IO~;ɾ1ۿ/#>0SMus Z\T+=k] ~'0ƾk3N>&=:=Қܭ.T>vջA>Yξԭ >2@U sֽT.?!*uiv'>H jfA>69@<L:s.z>>v\[IS?E>إ?eؿJ@?.j#??. @:&E>>AB?GՈ\u>Q?^.[_?>|2?ih2Se-4sG?`>*w6߇T L>߇5 2>%!v?%Ygf@C-=Y><>?]RcAHh? l`P=c R֪?A/ >"KF_>`r*A>r>8>1Qƾ>~Gw2{>}=>@!PQ= -=ݾ$wn?fL1="R>26ϧ=N |=d$?u` ݾ9o>] cmP=cAg?5rְcY7>$/?X*g7.C=I gj+l0 > RPnRI>jsoؽq侟a̾E>Dj)ڪr&⨾N>;%#YeMg2Y?!p}Yw`捹>[22v2X׳t>y=3&(>??26=?;=A>g)>Ta*>(q?H>E(>6{ W? HIcƜ̾6~Y:>9[P^{z8>mTplg7$>mlK1AٽXe?k~?GV̽1䴾U'v>) !=@gΉʿ&>@`K=cqTuͿ>NWUԻ=#>F>y>V /3\>#EjGHm>I_cþ$W>>$<nF?p=ju29 >5=*e>2>=b9>_|?d|>f*T>L=>1?Tc@rÑ>P=28?Uaa+>>G=>?&?]S}(>(=v}>ٙ?Pu|ys?3?t?wp=?0w6??RR'Y6="=H>D?9 mv.}=f???ȿfs'dIcV>V >?=C<|e?v>M?>Gj 1={=zl:?"%u=,0@J/@_>YT"A2?.ٝ? v?E ܽx™?%b 6hQ8?^?>z㽮"rl=h|ow11W>p=?Q}DžAR*?$>(?N_E+>@>dlv?q8i f=U>o=sG?F Zݾgֶ>#> 5e?[Kl:@a(c>uwCYh3k?W8T'׾>=Ϋ?Qin{@#پS.7?y#>|1?~5 3z>Y=>=K>ͻ{-posq>/vfB?-,mp >t>W?T'w=})XSQ>Έ~[ >A=2?@XMx4↽Gپz>qmplWrG=b ?%.iXMF>8=/?IJk>dX5;?{ξ3>4v<={t>#aPb>b<?9:`.ds>s>?} Չ-;=޾B?TةQr޽x`4"DQ>D׾SUG%;??egA'& 9 gݐ?#<a P<熾<>ȜhیLۿ'z>G˰<,H>Z"K>][6Q>|F`>#d὿Qx>I5?>reg> T&3^}=◿.)>EݿLO>uTq>߽X6yE>;"I>nZ2>}=Al>>A'?]}>=Ik?Ն>2j>CFO>J>;? AB?YO [B>?VP}zcK?>˔ݜ(l׿8\>+A!RQٿS>Cۯ(~933,>"?W&bT=`-?V_YhCgf>G0>0*>{#>"P:;r?so~&g?OڟM1,>ڸ>\i>nT>*нt?{v>?y =Sߠ޾8B1`~ÿu3*?FfL˾L';$>3eT׾˾]F-=TsH\J3>Adͧ?%[>1 b>W=_W>wF>MX.d>؈'ٽǾacྜE?~U;=])>Ul>9ې \[O)0>pu}@⾪g=23>'5E>cv >%>y? =%qiym28wJs ƽa<><PLD`{>8{ A.\'d›>|g o|b*ٝ>U@砫>(jӾM>#H>^]+.?On)SFo>$9P[:3?Yd>#j>=JE?$ݭ=Ƥz]4sG6Kx|]Cty'P>.½df?'B= ߜ1>W> P >t ?r=!{ M=co=}򪾢r)"?Z ̾"'5j| d >`ʾ޾CǿE>)<28>Z>4Ɇ*44j>WWZ11iGv>=O쾕B  X$پNY?#,cw@V2r*5?| `F Ũ7ɛLS > =;p=rbӑ/>ܶ>*>>5j>T=c>&"Q(J_ ԝxYC8x+Nz"߇>\X=B3ZuNvK1YOKH6[;GA-:vſP|B`ѽ㾭>R>j>п.$>O<>E><>6?Fz|9>r)޿,w=>ue5=;Z!P ?2awUm=~[~EþFץ>t<W3[eB?6z=@]>Y@>SB>F>Z>X?>@??<,???+m"?ܽ>T>?lЩ.\?I ?4 ?h%3_9>du>,?خ>~?4?0]%bfk>_cx)@il>+?Lh>nw9BqR=\;?*6>rl{]A"?L>$iQ>=ͽKv??nP7[W[[>->W t? `>ߓv<>ٽ3>܃=ԷS]̾۩>=>i>77σMp=l\>=3k@hu=j?=>r2?Ѿ_>7?9u>N·mjO?=Ѣ?,>o=-?y5TG=>oad?ZNlYa>7? 9>Ldm>H? >|1jd;>s>4;foe] >.??,?Q"fI)G` A>(5o" T#,DƒR6q-H İ}? >qa?Ǘ(T߅9>ݔ>j?r?io>\!>~̾`|>0 Q>K=I>\>Tz"U>^=>b>u>DT>NS?&>ژ)ھ<(tS1?f~4#z]F}G>k "NپԾDo~>?"Ey>gD>:?0cʽ0 g>fAp= $@?f)={>`>>?'r3xDUJ>\? \?,0N> {)D??zm3>%-`)f?):PD>>[Vu>P?uP(i>$he0u?$Xxak5N']_6-0 Ve?VCU@hȵF(ʾ ( *A>Z0N=m09< [Q_PӽP-=<2 HZNf={Vz";@>?,cd(=9d>k >XksV> #f$E$;j H3a AWX⾵UcI{>S3YA-=>-μaԾ#>Q3tqQ=sž O>MEqQϿ:`pfrT=Y7D"y">W\{p?"Rg>^6:<|21#J~auLET}tVYFO|-NnRHb+vE9=G-*>i|=4~^>P=s?"h>CWBQ~>f(zl>ī)$x>>?{>%>C_"u>>)*?pu>T79 tW'Np;>F)_a;-: ؽP?1!ͽ$gl z,D>>& s=Mq) >Xg3^-M>qо5>f,">C ء/] >pL#}?/6μ2vJ>FkOaB2>Cc0>VK u>nV?M=*H.>Q?=q\djQu=cw>ϾGd@>c>uX?(>[>X=i>>[T, s=CG=*> |xRʠ꼀nX:d?$ž n=ӽ-t xȑ>E>>˪4׽氾θe=2d< A >a?[q>Jp =UO?Kkd>I^xQ/vH{ڈ>>a?dA>ʿlcV>]>?>wجպ>@ӿ v>͎ŤF>0˿ n>M떿3&0̋>n_>Gc>Q" Ov=rK \ɼҾ h_>m"2 %p?0r a==Q==>"?bK>B0 ѾվVzS%RD%ZJ8;QRn޿߸Vrv>Fÿ4T;vſ0'"( Oݔ>'y=43>W?!r } $e_5H=Z0[w? tka>?EϿ >8R){auCjb?ȬڔvƄ© QTfqfAՕV7=iɸ꯾=tݩľ=(:.`?w;Υ>IbĤZK˾&,7Fx6 * ?)a=տWXG>DH =h)@l >DFJF=ǐkžOoRT=)Uq]p_̿:=Rξ8>d7ο\Q>?Ŀ";?& ?dozn>j@LPz?$5?d>㿘{yc#悾]_>nܮPbrN8^输Y@|#v0\J?p$>ȿ5١%!=v.<~#s\ Fqipg=dW@yĿg0{?HE;!>FT->#a>]>h?)=3J{+=,> BHD+s=srKH>Y0 8 z`ZP= ׼۾5uM> SONGE" >i\w6LO4z=)PQ:G>o&@^?"A>K+<9i?<`7>W>g?M/20>V.h>nZJ^28NU=A۶ ʑE=w':^hᨿ+?(W&=,)Q$8L?U#>5'uutq)?I> 辡<޾-?2u(ۥ>6#{[ Q@(#nP>V E?`7ּJ M>k?>:>?Des=!6/`?Rp;'?yE> 3ms?N7 c?Y(>&kM?iT?l >!e?_P@?mɴ=9 ?};T_ w={{>!?>``x?q-%>k>?a>?G8>FnPr>1!?v>X$ IZ~%B>e?>ؕPV@=X4?>E2w< W%>?F?}'q~>[M?j^($gQ?8Xpb?ˁ >8^?,q7?<>t ?3R{?F>9>`?( E{>s?>ӜVͽI׾=?Kl0z|UTv=?>*|{$X?i, `>әE?ic6ῦE?_v (= >>?|>63>YȆL>*]= A?E==߿ȏY???ο3+cC?&?ɪ?c=cܿa=:>=?8>ԴJJd=?[X\??_x6/mR-?K?C>*쳾?B2??BݜaN=ʾ]B?r>,?.gjyb>A1?CAj P{>،l!?y">ʣ>?_?;j>" ?v>a?~?K>.r`>"d)k?UPHr!>B޾U?2O?1?_P>@!aA ?r??j+S*&>}?t>4"Bc>0i>E?ax>9`[:~}"^?:־ww=r??R72#}]=F)=~?|a>"櫛>o_ ?->wmԽ?*G?ɒ2?07םR=%T[?GϽ:Cg>?O=?ؑ?O?,h R>i>>Ѕ>b[q!=dFlM樗:BL6=W=j=`;M>e;2`±w>o>5v4|)`/qRiZn>>F>F}Ds?*3>2?/ྼ^?E>y0?ܭ0 Tr7v?X^6d<۾L>\%3<[W>:= >d+S &=ŌLS>|W1VR@H'=TOQ>+Y#0v:J>QƿM$Ydvu=dJ&=2AN=|:>˿NrA5>Bܾ#=ѸI6Hmp>x>fμ,lLw&>]ѾAz->A/>B Y>c>8>>"\9=\žIejeQ = &BXU%<#zG¾:{>˾>=]&ſ>?la>lt?U-=?2}V>w`7*zٿӻL0s/>>ߤ!>5;S˅X> ?J>ֿ5Gm=F9>A{=%` *[*k=SP=V;!H >I?^۽E"lPh<>6>U`=/~6vb࠾{?*|5j>=t>L/Iy =i|=ZȦg*&DTe)~ rҾ:yy퀡?,lU*=y?L>w> }>QX׿6#:)FJ{:>;%p;f>A8=R=!_F>Cٽ$c=jG!#/=e3>8# =Y: >x;l_B |G$"[@nоxRH_Jgno徐 17NU/ȘnrEcxSC@ʼnu8?vۿ\h #D!}S"ULO:~DJAl 6\!qGͿB6Evi'7ǣw;G?g ^SӾFibݾfdV`*E= G݃>#b/+==tϾF徾=] Yٹw$IV7{vq}(`nҾv{ZRSw=01eݓvY@/6`(N>X)e.X=p> PL(>{x8kY?0>~<'h4gSrkӿ!w񍾢U:>t>]L+A>&>|O< 52yCt5xپ-M?*>L?Ah>t\i%>h >mqT>2:?>I>˸ѿWmZGBt\Pb>><=>2(qc6A#>6?^>(dn-|4>.3?2f>fp?R!>㹿8]=~TS>'2>`>r!>quqJG>@n>O> >ؐH>U$? @??]=L߭V>пf^˴RC=J>@}}?z9?Ut`0A|R?>S>R7οr(>LPH}G+Կ8(>熿>4i>UC>rh ?P#?(?3e>V>>n?ZQ]?5?=IUx;.2>.?o?_W4Ze<S ;g S?=́(p*De>d>n+?AK??$.:ua~`ļ?#>5 j#>>+I?4???zoW=? 0>>{E6mE u>?>RZ7 ƒj;?G=۰`:9yJo=? MY?bX9y)*= ? >ah2D뚾Ty=l2#xK@0:Aёz> >"` =6㿇}M"O=ƿz&sahE=DY)haf>)?0+??}F=e&> ?rm?Ehs?D ͟iAt>hp?R?%G? n =B> >F>v;@>>o>. =M!>ωYv=F̓>8J.Z޿վU,;p7jC=>N=#=WqZu2]>D>0|egd>B> =cty7ݍ>TC>;.??85j@>d???^6$ =>5> ?6]H65ӽ*>,|>k- ?6+ =meЛ=Y { X2P%п>hB`=cC1}i|{6ξ亶>?ᆘ?P4žv˾ z=.>w5ŷ ==a}? ʗa9c{xF%с*? [4"H0>!G>?nZGQ9 -=tJ= ?'ӳO-9 㹾J.>|kh6߾SH>2X5~? {W~L=?f>>/b:c}>=> ?YY<\ j?\?&? c<{`b =.t=W?'I=(ZRN>??<\?jsjX'>M5e?4?:?,VݢU~>})V??j}?bq^t>?[v?? KKnܼ!{?sP]?8?ZnQg=Y?z???%;`)>&}t=Y- >&.Z=2t\ ƺ>,!#Shw gV:=.Qf >S芿@5"t7d>S?S:6>(/A S>O,T~hʴ=Si>4&?!?8?.RpWF>V??]87?V8z;??O$?0@vܾ9C?[ c?+\K?V?xJ>k?!b忓 "E%>53qDd0+iFe>S61q?#>Uq"}V>?jjOa>g??)E?<}>Y,N>:?(?M?Xg>LQ>X?'?n?x$OL>ѻ48Bp>_ DkB>T-{|,Khos!d?[ې?+z?2]pmSd?-Wi> >ĵ@ H>3e]Y z>sֿ\2n=!w=f:p=}q> P>(?+?j?l6>R??3 ??>QH>??w?L#h>T:&_1p3΀;>X\=SaFXxЗ&)=*ڿ K;9UQ = 4]s2>?>+d )g>m+-S>T,??R;?a_O<0Z> оdu%>6?2!>|H51,3bԴ_=,ϳW>[Ac>KQOw:)XSG!ܝ=kUB|<fD=u6< Rf4?k \rTT?GP >ʴ?dla1>@<>2cjC=+KB)>`ӽ̲- >;Jc7wG?Zu??EccC?y?_ք?Sb": `ݪ>dRpC0+ÿ'E'[=Q4pR܃!9,zl$j<ɭ]e? ?D?wV^?ý#ξ:2\>>a 2;Tijn>-M&=D#w>.tI=D6PBW:;%0="22"!=H7~h%Ⱦ.?8mpiz?m>H?.~ C|r'667LxjHdV.l)+<&a}# :?a7 26~K|ľ8e >*WP3=Ǚ%0j=8~ÿ5*̫> pm,?[C>s*?UoB<SvT(N<^inr%M?u>G?=9vھGx?wܾ??;"Dxr?D?*?WY`|t뾱#?P?DP?]ikȳտ=G:FT>sA?C?A 1?Ukq?e??;4?tx8oZ?{x?%?ZB[N@BP=0dB {n㽰9?e'> ?1Ғ^s?R,E?D?1_?oGA,aTEd$ۿ%=gmQ nF[vA>7ǂO13Uqw>v?W. zE|=ǤI8c-,s2>M =E9ݿr˽ Z>0>Y>Eͻ?*=>AU>78?^>9? ??7>?ޘ?7?4>,ZЕ= |~>53>{$d=Mw?7qCYCF=)2>7 Ã#=g8yբ>_Wq<^=k^OQr>ҮR=駽НP<>?;c4>P???}?M=i8=u>Ľ5:??i<z͛_<^y?ې*}=3;>=?]tµ Ƕ> >k7_>5`ҾS>jw>rRs>5),ﱞ>P-j3U>=go?_hEwd:?>$q?= Lb6d>(9=績hE? th2u<.˄>ldS+>p1pvQdP,#W\i׃Z>v: 7(?#d>{7?wqM4<=>>MW]?Scب-+=0=l\?(KQ 8$=BtV>́?w֒.?[d0-ٽR@t\IqA%< ׾h>: 2cL'=H?]S-t2=<>Ws?O~nZ&c>{=?M5@=3==|1)?8m/u|7nB>P>x;F??aE#gi<>&X AG% =s~:}>O^5y>a1@T`=?^u]Nb>k ؽ#?o|r`1$T)?0½oyae>CA qy _=K>u9=/+:> =V\*4> i8344!2ǰ-t>P=SennKW&G;=Q&LǿV;x=>7 O=俚=.!)E=z>/?J4ݾ؁ÿ>>rOEJ/LT}n>Զ<=>%*ǿVn;k0e=$g?LlDD `iEj>K:lӞsAp=Y<)6>&[F?S?`3]vhip 9?EsPO/U5>Iw4lL>,Ͼ л>>/{>HW>u>ʾ %>d,>f o>ctS ϼ>߈*!):lD=?0<:Hy=k`FF[=e$}o{>]G? ]h}"=Pξҿ |>>w˸>K4G>Հ=/6,>>XsD= B >1@<%=C$J^>P#=ޤ?E> }$?=HzЁ"=`J۫뽷Z>9;pZپ>`Ï=1?Z(n`\C=?Siw(f[yYw? ;C==㾌si >~‹$ &=,˾>3Q'xEN>.>&X?hS `ޭ?G>X?`.=n=$M"? (UߵsmeӢ,?wO=P;.H?1Qw^#껕+=kQ>Rck_l0Ӿ =>KM([:~=u.c 9>VgW)e=;Bh&? r@2M?/ p/;$žIbJ>4>b?;*Km@n;vƽ/#!jH>yp m"bv6=>T9[` D>P?V"ʀxH?+>Ћ? B@Cx?U?/?wqT?i>?H3Q>҅#>?{D?x О=笂_*?Pdm6r.>w >,>Oj>8@*>+=ԙ?S(1Mӽ }= OW?*Ɣ/MWF>pm>?T%{| pM> H>oi=b?F _>;[p?dƓm2ٽGsq&#n>ƨTyz ,E< \- P$>ݽbw?à,Ƚ;=?"ld$E>Ӊ=mY?Nl'!\=\K!> Gk>M=Ј(?;p&Ġ|.w>4H>tU"?FOvbsAJ>oh{? ><m,>AtmKSa>9#>mq>heRd=T=e>dԾ[տ8J0>e}qY=V>Ҫ? i?.I{9>B$? Ë? ?#C?*7zmk>\:6c>CTQ\>??-+^?,RLξr>V>>thqy|o>?P>|y>[D>)>yCoCN>J<>0>qe4DU>x>O>M?&j[l=2߿DZ6u ? f=yR\ZHsG ]ѫYYa3~ >[F3`Ӿ/">X@ [Iz>ʼ%l7,>ɏ?1 fۜ#YF>*ԩa>[)ދ? v;uK=m?!H'>=3_?6B≠ZZLM? ?=|G]%7ę|BS3>yH7C=bؾ\޽F1t`2L@Ac5?/n 7ԽOH>8%Z}?7N>t*=0@bϿp;9 .߾D=R>O= >'5+>M񝾳!G >L>TuPocM#> fLcL%>%8)hs&gWTuj{5-ht2gc/!o?=^tq?6Pr >~:~aBƵB<'>Rq>}+a|c?x>Q=eT+E?]>I9eܵC>+b*>/諿_ /}%h p>,㛾fX>N1Ӊ>>ɟaB=`۫>AZK@꾢rZt/߭*ҿU3$NWm=E%>?1Ppw=h`T>v:{*7LgIz> `>8pT%;X <'U[x&k=;-'EiT`eT=x,,[!7=.~=,F/=Jء+V=`YkvCrh8==!8?>Pw 1%⾠E嬾8N<;ܾ~8mc=؛R|&(=vͿ}m> d=?#}zm>PRTսI%x)' 6n>k/?ٔ>?~>Lj5ނ>.!t: 5cd9[ 4Hh4rm0ܳ7-~>i>];?]qI>@pv=]!y?h;oXZQ?4 )51mؾT>xu`ᨾLz>I raYjK>5r>lԉ>1>b>m&$>y4  *5;5ÿ#Wޙkf_i9>}>>?_c8 ݼ'(?B:>sP>p ݼMFo82>>pݼa | ߜ>'{>qo\̣>? q7=9+YX1=H>r<-`yec9=4>ݵ>4 ?A$D>R>=?@DAԫ? >8Lm.>Q1hB־+>+nRfם`>0䐀ŷXD>8>^??+y=X:ו>q }x뾌 ϙw>>=y g>GѷEоt?*P??؀= >ӂ>oy>;P+>N}x4>F>UE>B1>gw?!z?kn}=(X=?,E>gd!8~HE;B>?E>Tp8:ɢ&g> S?9O>l{g =k1=~}?%>E5xgj>?P23? ˀ9P0>1?Dw?K!* ㏼8F9>8l o[{=kd*e߾A,\7PLo0;ֽq47pD?-=l>>۾ R? BeYҽ>J$=#Zf=fS>^>`Wuvg5ўdhN":*N=3HB]g/ѽ޾d>GϨON #c:뾣>GTКpPjnӷR? *?_}[ ;TNUܱ&?=༪?TS%~l_>#=51Z>iw?U9?24=V>v.? o>&t8!>yaþE<>VW(u֧ ">.y=ۜs?F/q=PHS|=+DA"y=$|V^s,0ſ_>Ӿh>}y!)"/>@8o= Ũ^7>t柽 :)Aü>w)>!_FMB|;vlz>נ>%| L"kA7==.#?[*x" 8W>4?>m@?CnѼ[/\AAx^Y0isž>ADA;kw¾?x/'ڿU>ʿ+XL>?.Ͻs2>k< jnTnP;㣩<>>(q.ɽo> >b4 Z>:) νP6"=n=pam H'uC>Vm}ݾ񽄿P/>>JST;>>>_t?#L ;{̽zp6{oVdӿD)1Odk'>0ۭEҾ}>02`>F*DV>RY!?,|;Β"yy6=Z~ݾ掂;>{B.b/s Z0>F7/>OӼ|; u?3J>נs*?>uG>{?84o= ⫦i h>"Р/ÿ~1>J?x3>?R3䆾%?<6sa龬HI@Y14 Lye0>v V`gE vѾc [>j> b<þ⾽U>>1m=ߤʾsT>z&J5>x<@?cC > 8b>J~1?P+=#C :/5=Ͼz<4g{^R`/ ?$ O>;wp?)UQc>A{gD>j˶>{pʎ>6;*>.?om>9 ˽( V&}չ^>#D!#>=Rv<>x>%{B>ȕ>l~&=? A &InNfA_F 4"@Ul6">ylL<ܾI>7=sdYMa=1C`V>Njb&->>W(=w#U" ¿ſ9X e=rZ=ξP3 > ]|%20DkJE/z >6J=m>Y?z+>:+>\}_&>VQM!YKTL]bv;S8ٕiodۘ;U7о >߼&>> FR>'lܠf>]=r4> ظ~/>7vׄ>|(5鼟5 Ҿ1ֆh;i4e# )ɿut򄾆o$f=~ȓ&w>6k߿{tR> 7>-\澬$>>/ܱ> _> n?>K]}Ec/c쾬\F,qإN]>* aED>mɬs?=<>e`B˸Xgw*9ZzSHj3۽kKc;"<[=KF)4Q >=->>K>LH=O׽-{[yW׽=!312 &W:K>`ZqZ#[`$>xq>P-<ʴ?FXbc>*Z>Yl>tqܾ>7X?A1=M  ?>O:=`V`ne!&q=[ݿI*;`>:q"}=dQM㼲I.b>LaоDpj;>lbUξIhhAj&,=e8d$.@";6>Bٽ ?_;2(*V@;>L==P?1= K@"H>>?>;@w>'>  ?ed&@+@BDN>}?azG?9~+ >=R;~?v|=Y6?O9>K=w?7 >&?t7xh=)0?@D9])>G='xK?Z`ļP>S = =@Ϟ?[=p?L%=g>%?M5?:, 7>V*>G? 0>>pk?̅?v?~?3h=Ǧe?> qy: CZټ%پq??Bi0[оO>q?>c`пIU:` >Z}$?x%>>T$>|#?(0侠?B>6!2>zF?>p?7;]> =Q@?>= =b>5ƾXl?K4>[9>?C#R]?:BNI>?=վeҍZZ($c^?db??hf䏿 X?3?q"?_=?"f>U>H?-+>CZ>$><={j?Dz><>/+c#>>9?P?2?4 p>1?(N?P>,>9cq?P<@>?(><;2a@=LVP?T!WH=޾z?I):>zqi>վ9?Cqe~/NY==>#2M={=_4 >p~!ɾ:>?:/?a?; ]l=b-=L@e$>j>\ ä<\U?;w?@_09X?,=mi>#]twy>h?Rh>C$>吟?(>v/=r&=܃=mXkj?$#jb ˾\K?EȾ֕S *.s^\?ߏ&u L $`x>v nhK>)V5=};*G>;T>}]=!N]:?=RM hAľƾ9*.ǽ| l_J>^̆>agL`܁ľ?(FؾzF,(k>VePO>;ѿ_[ )='WXJE} :zc2'+?D2pl*?%=C @٩;qm?%Ex u>yѾ#0<$Zz*\0/;0s}s>G\K0>]F># ;6y%Y\:C+@,eL?+M6@e+>x'?(l>n?I-QV\>s =&ʟjn>`̾X 2̂͛=ٺ==R~ '>ѵc?!l=4: ~>ڏ=f?>\̊>'><>魧cA2/IAľcg`>ui7?u,InI?`N8`̴ >?<>w#RvSKӾ k'k{1OQ>>MϿ۾O#?>EzW>8'>08tUKjEg(=(KbFoP{IE!*־S*0r>\iW?hn]<]sa>ؑ9.IW`G0@Q>Ҥ3m*?>k_F~5ٛ$А;=bw>1Vv+)w*=WU$= H>&e>!=H>h=d!0>>fE.?.>uHi`&b>?u{?}>%N?%[%о!{پd^^züjyѿ-ȗ9]f±>%n&c=Fkc}1tֿw--[d,k{#N*Z@g뼗oz8JUi!>}|CA)BOݩ?]X=軐sl'BŽp̼?Iv' ɽiI>>$6¾ >>y;A̾'Z=C=Kh~;6QQi6v"d,˾ĢFk&iuN>ۥAa``"t>XSѷ =>$M:Ӗq4Ͽ ;`=N{UqbqGg?J}dndo ᾇժ ~t=TG^'E+C@m{'@ eB9R|ͺa-[PC coss+O@ľQiLAk{|8Oӿ&aJ^d/of%S]Z_1澪,l1Hw* akŜ?+N]K'1a7*;>=`^$By.Qw?5jeؿ&_c?:ܩ@P2R2gy_7Y9I5"?jb> s/{˫>f0BpJL>8MMDVm-ڽ8C=fRh< >K쿤ɸ ki#?R?K|&忩)2=jMZ|F>d>d>N|>\QT#30=6ꅾo򡾕5BT־hXC?.U btʟl @+W%J { 9>X>zl?4v?_[?i>nSk>c(? > >_Q1>PQ>'>fp>wɛr,31{Ľ#1G.: 8Z`n>$?v>>%g|x>o?YZ?-A?'N9+>ì ?28?FٮUnH>\qֿ2 6 =`>Dg=?@ v=kJf)|<+4(?t>~Y;H9&NXc>>6r>k>pS>o*? >>Xh] >XU>>7j> HZ$e9G>Q)?>7>["5OZW=/G?H3^b槽F(>=4>>W\?Mu>/a%z`@>49>{ٰ1O?n.>_t>)9"  <@C$%$}c[HF >1bc7v> ѐ2Qbkǹ>xπ/>o>H0F6 [>>uebt>۬.>t >*N86}EԽi?iY?4?TQ0ȾЭ%>"N>=8G?Eu:R+0/Z&>ǬGM&pVz.Ĥ>XA0'<R,J ;SI+ "- @>俽;TQu=6*KH>4a=MY۔KzY -?O??PvBV?- >>ѿ>I'ݩjdN:> m >/˾U*6>E韽9?G>ꘫ3=?u>иk?>@fmQ3D?R?"?4[>膾T>HB1EH>M!'7g>ͽNFrĕ?_eV?/q?&o'yv6?:Ç? >7Bph?_?E?J->[mL0aK=H_X)/f`)*>'T>I+&4@=Om wM<Ǔ7!>Rc>6Lh=j9P=C>d>Tf)B>VUͼ>y??pH?XV!>??U-?k俽 |F$"\>"ٿ }E;/V?e:2>"tѾz? Q7/?6<EeǾ鳯>@D(+=^j׿x>7߿ml>g4Yg>:?bY? ?$"y,^=?]>j=8>jb$\>7?J >?yHr{p8.E>Q&7g욾-?S>TG?nn5/O? >Ѝ>~ nξ`?">T > Z3y).!+=#QրQ x K >6!?=:q@< m6hx;?=?)b?Xc@TT?>M=C'>xpH"N > `Nrmr??a?PJsJ<+=ֈtCR>!>r Bɾ!\d/#>}>lgpſ+>S&r6?q`R??1bL +y=S_Ŀ\=ER<ka5דN>3HՙO2=ڔ6?@”>B? эw`V??!E?]; WV=?0a>?aݿM3LN(>\??;?xͬV\S=x??;?dy9C{7h?m>?5sC8\d?CP=վƲ`c[oT\N!DDě 0h IqhsCQɾOe>"dY45}[bd^>R+" >n~<0XTf><P'|v6j#}>ǿ>}>ma>R}F> lthl?L> r>PΞu+V1V?wC?N?CI(]qC(z?e>ญ?4PY={ھ?rs.?1?<9"A?j>hs?5Yd`/w~eҿ_ӢKS;2hf WWj5 ;!><k=帿\KCgim=e}Nx=<žxgJ>##??4 ?Y:Gv^~?VB>|?(!)_o¼I8?/\>iU.?r|opA?b?*г?grJ>mP5aXC>޽'2d>3> Ϟ?#?L>ҽj+>`忽a> FAH8>/>߭>>!,?O4>?c꼊,>Bm6ra(cN< =1UPo12?6=at}E>Ou8< ˖ѿ'͚=RL!;4>RAp?\+0/2L\y>u)4J?&>6?]&`~<j߾T(=>Ц6%=g[>˼@ Ծ=Ⱦn>s)Za>G}e<>Ř9 _öt>1e;>tbl]Rf1K >=+q2A ?0'S=(Ã=Ymk*>̌-(T=^ ԃE>$lՅ>JG>}=!^N=~+c/>h> =Nw& >?=<=ʾA̿>czb?s*τ?EN<>?@X(,`%=[FͿ6>+<;^=^+ yB>۾ʊ3?Ƥ>=&?j#R}ؾa*>̼>^?dP[3X?%Ц?0\(fP@ >y;T#B8 >ۑDs=f Hs?K{i=@==3/0?>o`6,> =NM.c ?6 (&WS>:0ۣ*, $̿_Nhb׿c Tcۿ2'>I@f(5;-s>C!eDcҀ\p>}c*b!,dԉH>o8c=ij(^ľ?.^d1צTp*T<.I>rC>B><$>?Ŀ >G'eHǾ0D? /eҾ.IM Hk>̰r7wnn% P>Mt>% >b?U&R>Za>?T7Sוs`>Ct>@!?bh\W;o#?DB|`HF=c{P;E.>"t>x豚? 좿KsD>^>4YZ>-M$H+bǽ N ?[Ǔ#XdMa  >+\ؾZs.=v7?1SZŽ`ٿ>n`Qy:;mƿP>#@4WBn@}> WO$We>mHM 7w@#n >[ܚMf?# 꿯qrɽ*> {=`?I%e$˻)>) ='?QKIiSO)>wҾk߿R>Z8>ҁuk>\ 2>)Z 5r.Ⱦzyy? cV. B->+=U?Ou9$P(F5:oC[?$!:?>>c?|]3ʟ#={ɿ,>HN =_0{x>ץ~> Gy4=i?e> 7 6>P36½$M"s >yCwW=AFg>P^_J=imu>u1B#WmԸWּ/|>[=:m?}T=BBоLp>[pF=> ѽN?Q_<sZ-H C[=Ծ>o(ȽQP y >ϧ`=>*tsS>!>>(?h*3j=3aq>HI3(?<7BB<4ZKx&V=s<>{*8=9;E>8,,Du齸't>H/QA5T?`[mys>5oeO`?\s= <6]?Ԡu>-I>/<$?:W2'x~=>p~>'if=P?Alp>?M=R?"]\0 [?H"s;- 3[[Ľ/&Nns&>c5>@?=Ϛ rU&پ\m?L޾-Ж!>vIM.1m U뾯:>$'ھ>ݩ<6?3p- =k>X>?}N~i081>7`*P(D> 쫽:o>Vݙ0𾙁>a b^8lfh(s=>&儼2Ծi >˕9ڶ+f8>0ATپ^0f>[̾.<7O? f@ Ip">FyFxMފh-{a#>rI0"`J%>M/ |lЉ6>3h'Ï7T>R>'t@cؾQ>Tµ<"?0h.YU(=FE? ;Utp|F> T6?#u^>{8>FGS?I/rJ>B>;#6?^Q~i =ญ)tF>K> b=SG>?m>daMw>8zJ=O?m>abA>-2>wb,=

d> >>_2eIϿ1>h?=^a' '/Ѽ4;LS^O۾zR=t=08&= kR?~pD F>=>@UV>*z n?*pap+M>ć;,?V"H?,D{> eq2{տ O'>nQe龅P :K>yAin;\>q> n@Atfmr0A[_zվ\lL+*tsT}VrK'Ѿrk+^ͫ4 &Yѽn2ۥ' by/򡾕:.q(I*l?-!>&R;뽻?8zx=TzQ#AX+?=<>3>Xz&bƽ-;sLU',.ھ%۔dnPܾ|?r="@TAFSv=!?%>M?^>pF>V%<־zP0M>v$>pT]B?27\>fһ>+CC >  bYt=#'+ C9xi DZĉm?s>L=7 >jLbY&E>үW>]>/?ZFF>\|R/f g#>J#'2> KO20.CE>f9t!gA[>09i`>#wܿZ+;y,p>3+>6i j="s>'>A>1 O=hd$_l=w>k>I> >: } 3=H-8~V="꾳,Ǿ RP=֩Ž䙍jk8 Lcw[da =)ʿ9>C|^wž[y>(Z P8%[Zi=XW2x&>C[`8* 8K>O^B=&P>&ཾ >}.53HԾ[k;CgϾe`[qtw6G=@YսCľ!a彀jEcWC-䴿AQ>/@$dnlMҀ?D`eAPtV?:6[a)Ǿq? \whb?>=4 #>3 <v&`Y-þoƾ5?Q.3q  ɸ>pI־,A7>]dNCn$g> [`H < 2d>svO5DJ&ǨB/?{U0C>jBG9h'.b?#rEgQE>٥W> @m> |-?^u~8vf8C>`.$D?lmP:UU>Cʸ!?nD"usSSM$z)xOc4p^W!O?.a3K P!?qۜWE}9O0>+NemĹ>R8|?&f1kȾ#:#Bx?0xdd.'%;%>dc?HmPh$?ܾ>T:x9Wluni`_?W~RpnоkhF?M̰˾m=}#+V??^#@Qq?<9CO?8 K3?>X = c?d(ٔ=ڌ?H@,`Fp? iEXFm P|]?f8? xV=7zt>/jC M*ƛZ*_B:z>:hEȾ)a*h>= ?"ݾ]\>>z~0Q7ѽb%F? ”tg.#*??̎mڤ)>bc-?XEVm&mxl584L]?cJo0k-9dnL5=HM:g eQkײ=O^/J?93EѾhV`>'?R$<h=~?? aJ޾1>I4?W(ȍP7Vֽ@D? ?V4=A?5w>}>ɸ?m锾cVݾ=gԄvj7?:͖-? (kL-mL{̾zþxd?W%t/g&i?-ʟel.оt%؃>-Ab}t%=*x?XO`ȾcKQ=y I?Eq6i s & þj|>Ay:?G%p|{)%>‡ AtP'Jz>2r4= ÿ\h>g>'y g>q"b$\>v3Za[I/)[>|ݽ?@y_+=ӾXiV?'?!;'>e ~8<"I>PB2>XzѾ0 =>pdnaY"<!0d $D< .]#jT 81;ywn>.?9>MQt 5_ A=?+}1>hfv&%~ic> AzmM,s ۿ)̽{xgbk+mN >q?<ñ>䲷u[.n>`?n+|?*4Ux*9?=? ?Z"Z,Jn?6?x?R*rV龩w꾼^>AV\ml$m*(Xy4Ƚhy^Qf?A?ʾ׾)f ?<(n=KE?o{ 6k.0??p?XYS3'󾟥 ?6?~?T"hD M)LU%>kPZ8@ R> _>^ >xuc>ͣNTV=b[0н檰S;+N>xws=q2>'>9 ]f>!=s>V?+!>{ky&I<?0??O#H1F?@>kP?>n }X!:Uh5i+hU>owl}U¾3.8$n>wiDؾ?%#LӾ\}۬ݙS"޾-paV|j ޿/J'{60tneo#=+ՀJ=%, >>2r=̅ݦh>OX?¾F??`,^>~>4?Jg?XK+-U$}>x!?(f?%դ/.Z?q?x)?W9k'Mܳ$ WoP2>4Ft3"=Q4j=KQsq쀦 FTNf>98'>pEM{Ƽu)8+?St?\} ?]w=1/=1?tNPԽCs=Mg;XLfb0a%>5`= *E2x uEɟ`>=@ >=^>m> MyU>>\n?>>bg׾9zig^? ܽiMȬ>aR"0o,'EPv>F=g{9V4T>*~<>δc>vL|g۾n> yDc ? =:\>d>d>? >Ij >>+?$=>/^ ('bt;+=!"?_=4ǿ ؙ>D6,w㏼,>= jF=ZO2{=R*6LA5I>x[= &ds>;Q7Q>(ϋ>] $3=ln@B=#=T>Y\>Y>8 2> ]2@D>ngHW0b>ܜ3Ef݋a`(2+:T;=s2'<^ɾ+оؽ|X)?4g8>轈>>d\?3?8w>b<?F>C>L>Ntm=z?x E zv;M> oz-Fdڶ>!'8_="FP F>|¢-˾M<>>|n `>nw ,&C?5X>wJ>:s ?Debef(I˾V>btZ<Ŀe4=_Yb-<=_߾ʇ>¦LC8՗=2N>v`cx=NR >_L>&;[V>k:="O=޿=l >."a[d =𿃸Q-eq=w&L=,hnG$>ri/8J =1."=,b(G-=!=``>l>̖+!MtOM'2HInp=t~ "W!);#ݿ7҅ lԗT~R)3ntmn9Y5ÑOB#GD>:YM׾V(:GNB>{m[=se>4xY==SXU ٺ=p{Fz} ;ω ÏJ|(>: ;HN縿5+@X=_$`<*s>"0w_9,8?)_0U=3jY>d ?9>N=}߿zHz.ÿ!n= VPL=ƆپlDtO=*Sٍ֮i=G*>G]̮jd}]?ӷxGT[>=>ECB=lm>Ke;(>TJ>zwL/?3SE~PhYc'ީt;3R=ѿ4Z>ҦH37)>EJHF!,lۿ`C>q>T ԝy>{ih@[ iSX?*[>G[Ŀ!= %?/Ҧ]>j3q|~>8۾@?(΁>-/8=3]di{~T./OBv!>]5kU=QҾbqG.Q|H=na;hп-&H=h#%:/'?ztK=6I;i˿;sb<[STAp>T ?X|͡#݋+ñJebǿ>yݾ<+%qG3=kCNݿS@=/ ONk9"Sr %*v꿉.7>XUb#IF=>-׿͒??H->ⰾꞾϾ?M< >;;N)??C9"Y=)>;=0>:6 3l'Ļ_=>|B S O?3 `>x p߿wվ?+Z=>gPnʛ>s'> Gi4&Xb ?Ao"$F>ؿW)޿TBDC->9"05?ma$Q> 䓿B=ZSB@#\><>ne?{=h@@ 8*>F=k?>%?y2{=y-?-crr旾F!>Y?'>? =n?xh=@W?!>s>i?x>?;~>B$T=ɱ\y?th<)9!f|isL{?tm=m?Z>C_>94?)LY?~U">pT?J?vAA>*AJ?9ľ?$0:,?[VCD(+>n}?A=8#>T*?YA&Ҿ~Ve>Hz*? =&Jf౾T> ?fM>w(>cL>DԾ?CT">F>[$?$=G/ !=~>j>?|>00<{6@?+N?W?y> >y~>'R?&?>? >Yb=w%>uM?Sq=II9Z\>_>Ѿ?*끾0?-k >'g??8 >?ҀjH>KD_=>[@-pҽ$ﵿ> ԍ>"?c`>4އi>핚>=&QA>"f6;Vå>Ǵ$=">.+>OC>sEba :q?H8?"6 7a?[W4t3S =7>j=1>gm>5ҍ?W?>ȵlD>A]<ĺsy>s܌E=ڰtͿE>-B>-Jkiۿn9>LHQývة>UJS^ Q_پswٔ?;SCܦh<]G>ŀ^ o73@ㅚ>Tfbi?r5ƽKƿ^=I??KӸ===k;a3G3 m|O>ƿ)M=۲ys?(RCӋ<~2> ±>g>q..^>0h{Nu^,:Ǿmva[;GV>uW8> ~>Rտ8+j?> 3- B> (?c_=t8=l3?i>+!B>>hFgpʣ=Κ?$>ؾ^yXG>n:ƿ ? n5$>!-w jØc0u%ȾBJؾr׾%u:uhSF3{$ 5 GVL cH!ԝ?%ל`V?H 9 a= &_?iW<86x>99Dݿ j7L$uA`>~V_F9n 8v=n?>y7ِ44: R?s|>+-MB,`#>c z?+>\@P-ϋYc޾4 Otu> 侐Z(D>>4|1> |=_2{=(,3>Y=30Z>kq#u;2 5{|>H4>~c<>lclPʿK:ҿ 18q,Բtj,/ Yp2=h# Sڶr5?j<߾愭oǾU}o>J={ R mù>7뽸=dž> 5+s2>ɗ>H>?蛀;ܽq>۠>/尡Jҕ>©.>^ ޾{t>\>hٓ{ƾʄp?\>O$Gv>>ϳ#/ly =}̾޾*?6;e>W-=nF><&f`5%>V?>>C> g p2:~a>M>'>7*/ӿRH>>4>HN%R>ؼ?3ք>g ǀBiP? > ǏɾP ?q>~w4ξ`ؾj-g}<\%IV&Z=\>IyIu>5T>]S>?>8뿵Z?M=IP>$>>D6%&?d>i?K)N.y>>4>52YSl?bx?G?br`s TɆ>N,QiP'?y>(??M(L&Kk?T*>GA??Lc9P'4@?3^?? PV.\lоY| ȿss yd@E=ˤ?+{|? ?"R(?+~>?8?Rh`e=2S#ߤ ||Q[t+C׾gs?#a?>854쿃OƗG0 v<Wp>1 H+@_t=ȷ pi=oLG!>hM4>.<2R-5~cƙB =',>% Ñk}#+R۾<^?Z>mCoe r47|p'$<䐣';ً9x S~f;.k=]>] ?D??CCJ9n&?kh> PeGeMbq^'} s dw= ==M>?P?<.>?oQ0!-5= =ڋL,_]>y?^>i>_2n+<'v 08=,Mf<>P6.Fo>1\hb=yAvj[p$cBE@'Dp*9r>N7)ߎھ0=>m>v?m, `/8=~?@beҀ>޼?Ĭ?zY`_>M>2>G>Wr+6 5#%D=D}W./Ӿi>E|N!_ dR?!1 u~&>+>B?<(H NbQr=>[>8K>4Go==64>`>P.f>?P"7T==ԩ?-[%xI?y%>c9>=ybIl3>H]50Up7EY n>c-f ξSCȂ>)P =ٽR|Si.=y俑9p о t~M ib>ݳ}+>rd}xn}Wrᠽ?<>g>0K>~3n>k랿ȸg>l ?W>³{ 4>i>:.R??圦?Wq?)7S>K??,? [`Vm>6c?k??Pufp=?mf?6g?*i?=)6l+y [<> hϿT@8(h(c;Ol+0?Q?&,?f#K~x=':z¾h@]jL4ו?$<>z>UGp  />`,{ e>TRJ FxEP߷>e3+?InYÿ;=Pz F>V6=4¤ђ; o=oj>>H[%{aO|>\03(Ԯ >1I#q<>>>-=BdEV -,M2n0{>ٲ[/=O&SƼ'{6Tg>le?!??l$p-=ƞ㟿FY;%ȿY>N??hC?*e,^=>Bh>">" _=+ 7PwW;hs _=w/˿^FQ.y=J[?E=N筈yCxF+?Zտ>ޏ?!Xgf ?P| >7.?;Oq8{W4 dc*/0s=,x-¿U֌j(? #=->`-(>+=y?\e6 iD¾g?J?(U?dSD+>ӿ6L>6$b1={}微B|> V@)1Ƃ>"D` :ھޡ/M>h=->@V*!~>x'F> 2́>9'ԾTRe>lc'I>e￈>. bY)VQ6c=?$>|>j|N0=Lݾ˿>E!-N}V>D]@^=?`k>Ǜ5?@~e?>=[?dJ0>?L[o_ R#>?]?%?+&?pZwzѽ?Zr>z?0kq/?xI? 4?I)}/Po&?fx>A?;ޤ0]?RT>4L?&oj% ?H>:?W CZ?6Y>?rA}(=(?n??Es+2{9>P 5%U[ۿͼ> t>FCO@>:w>r8Qk?.>GZ='$?W |AC[{$?BD>?( <"V>|PZ=C쉾,>  =(!\>$ˡ:P JΤ>V$P>Ǎ>Q=?Y=d>@x">ED3?gm>?=:ءA>ㅥ{h8H.=O??+?P=p??$kH?FБ?q? ?տ/@@=l]?*,9㛻?@S>B)?PY@oK8JeZa־{ A@SA>^ d;v=J?B ><.?ґM<3?tFAs:Wy>1>k(H>=Nb;?Be>u>*=M]?8\R =GNRk/W>4]l|aaƾf@!N>ҘOx]; >S>Q PCM=V]PY?((i5i=S ھHt3>0 v1Ϳtd>zo ν@U}>ݿ&`>C}һ>ݮ>c01O;˟YK X>1 dTu!HMx&[}Du:d5au:={B?ggͳ%11f>#thE=q ء~ >4_/'\.D=Ԍ}=߾>; >P"ľP?$nLR4q:;nֿ)S< 3>nP=6J?AKH>?AANSο͊>sZ\f޾M?,>k_ Ͼ |c^&u%>j"Ug<3?/4 \hԧ=ȣ ?0Z}y>1zYE=^H _Z>m׾O">@缿 >Yѿ>>U_}0>G޾ĺR>">F?tʾ*?4Q*7^LN?7 )˽n>"2=?K1M# Hz>&B>#ɬ?iL,^h=㨾@>ph!=[p.>`s˸IǾ¾x?iԓ=?(_<þr >Cc6=+><n=Ų>Pͼ$X?`>.Lo> M,l%?#%Pi%=d_Jk'?y_b=o򡾾n>\}U<[Ex>'NS;<վqù>#0 ::H" 􏪽T҂b>j_< $ >Č.}w̽>QFk?^ƿo;%7]>ν̞?M8}pal3= 'ɦ-ÿhU$ ܿ0p=z;3:C>uG>Ѝ? O;2ݥ=$L{=P>Kx{=qھ >وnxj$+=ԍU @>E$T>^ ?4>dk5=ksX{%>bW}<9<Ѿ,#? 0s`tm>N=s?)kMtQ>l=%?73G.>q9O?e 2U?QZy?? >aJ?Wi'KbZ>S*> ? +Ϳ\'>+)d6>ɢ :6(=RaHUq>iJ,={P<ؾs=Ji8?Dpk>0>̽w=u?Jlss>es>vW>? |?5CpxkUQ>#n/:dqv`:Y<=䟾i# j>O=$ۭoۿb;&IV5A A=ʖ'e-Ͽ:G4SbEP7VM;iNmžV#`m+< ;Pr0w+>#M޽V^F>;?"*Ԅjc>8\ٔ?%Lfr=w>؀s?GT^Y>; ?"8@eZ~>z1?iA>:X=Xz1b?.Fωԭ \@+R:HdɗpվQ}kA/A=}?ɷ4R}Vu>22sCTb >*WR8+>+6g7_=->g;>҉>^Of:-pi=gb<3y|>p++3=%_>>;h> ե 1E"EȲ󾙚˿<<>,Gxk W&ΝT靾Gx>8L l2ʿ->b?f>B_e#>\ÃP3#˒>wh¾|/=WP8NV;> ?? [?ҽCUOvh>jQ?f?{r?xà&VP'>\?C?ZD?S:>f>[˝Ȏ>_->#>g2Yл^>I1?;?O?DS]]پ[>?C>D+4 ?>qi?W=?AASQZ?:"?T{?=/&>@>>4aS"@/MDV=!Ƚ\1 D>ciA?7E> cZ=ͿKڿ{11@XkSٲ܌>#ܢKBS>j3a?5r0V侵G9<"?\DP۫.nx: >t( *oSY X}>Nu6eR,2&L1V=+?hTX |P<)=Kzý&6DC<>[k/ <`!=)>o=y ;XM-̚缿JW=ֲYHUNb.r>AhQL]LIpĿV>ۜFܠL`,oKj=R>>@ +ԽU#g5ѼϾQظU? Ӛ[==ܾ>Zh>v EM&EGZ'|F3$WЧaU(Ph<&ϴ>Đʽl>Gؾ N=?d=d>#W`EM/>TpF(KLya1 MDR?=rP>K0NR~eMi⾹ˊGؽ21j6?@EA>tpHjyD^8>qܼIG>IcV{Ⱦ\."׶!ay9DBjb]Oy'? "WSal3z$? G)LcX;*o-^?f4aj [9{tUU?=7pDaþeU =q%>/#BȀ_jL >#pa|?3<6`N֪辇V?h1f"Xib94dMɿ>IZһ׾OU?ʧ=E7qY`ܾx&_v =wſ}FoFi=ؾJ @7is=N?B{.K#c = ᠾCc¨ t5Oњ6g7I=*>+3*>b)=ɰi뾏;;=Q }X~\=` FTR=ͦ7X>q& x >ɿڿ'>D(c>}0$l>0 b>.gGd;a5ha˾oi~>*3_EOtۆ?9Y_yľ\lUɿ->vsx{Bs2H*>T0W.v?N~Qݮ%,>0a,| ؾ~1Q?#`3F=xW`?+sTpZ? M *E4<0wM?$~NEݾ]?+919*w=QD, >gs=@W=:пd=6>ĽoX$Sc.<S<.8 JHp=sپP pi,=0~ =R tֿ6$}Q=aA{jްu*D=J>> U3?FtO?"0X¾eo?=_gy[bݾ2m߾JE? TIO=\Ľ?D+#L3cXX= #?;+E!2k=4n% Ua)ޱ> UnX1o4n=vccōzU|O׾./#!O<ě6ܽ}þ &yg꾫cc>q`= Lx1s>VYѿq>>+>i>b_pC>>!z>`q<}JOJ 5?)+ <k+?j֙]@I~A=yS?--kо>o7?Ev= 6ܥ>ڐa8iȆ>޹>]p?=c>2=?[?u=쵻 Q) >IE1uK>ɻac=s*о63B | >s=aX>l2TZ->Hܽ}KJտϬT нi=Jں(kЦ?{y KZJf4%7ɀ=>or,|8νWUb7EX6E>a=v?yڛ>[3UxMwPe>`~>Ϊ>Jk>DA>뒾p~K>W A=Sν>-ba1o|U=Nx^wfhOUtb?#&Rξ>?j>>g}R9wc^J=@>9=濇Ԅm?=5|N> =Fi{V,ƿ6;'q::ھyO>cPU">gi?*?< mzf>70? _>SHoE|>К:=a> ,l>h>rm#"I8; ƒ?:?L?vZwA>=0?0x!>Ѿ>P/>.Y[> wG0>+=;?=)_Qԍ[P;,R>)=UBdݑ?Sqv?) \b=Շ;1$=}A>7]>s] lZn??"?\]pQR}>Eq?<2 $/#=Fÿz>;G >bc"z>3??xd*=>fi'#v>m9*JT>㽌 O>1<0Jd>+X>X#עr&=D=\MA.Z5=0Ͼ [NW>ZhֈܻN׾v;E>! 3=t>E>]K>ȓ=+>?>Loz f ;z?!7M},74?1Hb;Wn" &?J&%E#bK>N>xWBdc>/>;?6E?C>kRi|᤼0{s!=ž,{>տɾ=ܙ(77?XSo'?@R>aA2@>o@]J@S? 9Pɏ(Oٺ6-J>(9>B>Ԯ>^+|l>|8>E޳>#>T?=!>Ty$Ffh徽 |>'W4??=L>S?t>a> e?IM+U>N>>A$eM曾jD"އt859* XeS<2Bv%"4lP`ݿ@)пVUq2rkSmоv?>f=k2H9? (ž{.{lAQ>1@>í}>o>XZ p=R{T>u:{jl<ƾŋ>>>=ad-==<+?VU>Nb=utO6?&IFzL>>t>>` >pHEL %<#f7HhN>?h}>YC<>|>_]>W>goݐ((^ΐݼۘB+pE֖6m۾;>aZ=Z>)/+AĹ6=O<6T>t* EINin^a]VGEDRȾp{v`̲#RKLCJKX=W~VV 76= ޿N p/W=ݺ# D bV/:ruh=: c>rj9s9>>=Y>ȬI|3=iGÓG`cν[=B>l> h8[ɽj>+>$ VR7}=>9*]q7>N>1Z=Eȿ#qv @>tUXf\=uPX!;~vh'~?~Z9>3C B=Oy>__X>Qߵ_?_v=AGO>oMRӾ%04ҾvSI8G/=MB>_I]$(=ꧾ?> 㿚i>>h'rFC0>X>ÿ a>??>k\yLM W+WsrTg^ſ*("y>=_ >?xG冽Lp~ZCg=ZR=ێvV=ܿBϖH40>U>u9u= =>j!d |rW?E}B>'n|7bR?$~g>w#yne|$SĔ dγ w>ɿUU컿Hf>i>C>6FTV;:? c> S4d4>Zɾ34꾘k?ۃ8=2G:Ϳ?zOK=6ؿ]tی?*=Xk#qP?m@F') >!:l1=\S?Z\)>=kJl4 j ->&8-kں(,oҹ .q>]޾Rޘ@@>Ў7>w?>ka@ >>>]? >H @ '>H?V4?M+=mR?kV`?`W> 1)i?UK_YD?>[??HM> žK?Q~{?LI>3/,?]Pt>,>_=>*=?>?|.>\5H!?h?e>'?:?C?@?(MRD>Ӿ0?:D opC7e?Oz?'?Rc࿠-4=Q?> )|"?!= z)?y>Nw;߾TݾJ?3/O4~K򲽃?Op=Bm>g?j>2x~뾺N>&?Q>!dſ.*?ev=|FrӾ-i*A\)@}>YS;OV!3 ?Ey2{Wx[[?pv=,jV ܹ$$M?a޽q2{&BʨӮO ?d <`_7Jÿ3=?2n>W=sͿ<?n<$&>mi -=\O>??>jG"ݾǼ?v$= 9?.;}?L}>PI>If?>yf{=֙>WW2?x>/> >";Mu?j]>I>?d>b=ԍG?5ncZf!>4 >fsB܀gVQ??auYu?[<CԽ o?(] xnVq?dQ`3 e=n`57?Um>i? r?,n+>J >:ɂEH u '>@=>A >/z>ِ=-6/>m<>p=m>?>ȟ=>=R7[=թ>y>=8J=}O=>}=k>>ҕ*IC=֌+t?mkֈ Rl?оn~~=>>Ɏ=<= 8cD踽R>35 H9z\=@!=b$r* ?> >(AȗaI {> (,Aݾ;#AZܾq;>,< o@ὤ$>(>H=[Dᗿ4i>=& %e= >m^þJQa>8a>VQ>ã.S #= =b, l>K?=G6v!?j',w> Wx۩>kp]]YսM* H=)YA?s> (opH @J!`?E\1S=)O. Ydfu>μb+Bt!=o$P&%v=̡ITп$ؿ"r x=Ҟ{OrSˏǾB>1Ӿ| /?L="B\+'<;W%|MJ$(Xd >i_4. vkUv?Nm@>&[!>>5=K?">ߊPm$µ>c,b=[N@td:`W%6d=e=z])>h >2PQD̾Vp[|>%'_O+oF2>0.[>p\;֌E$=?1>sq#)b><2>+ƒ>>Zj>.x2>DH:ʬƋ@ݶafSʾQ;>]=&7!O`XX>L; >03T9=?i?Kz>?fHv,&tK?>Ԥ?.NI&?<>C??@D%"y5>Ѣ?@B>QҀemξ\a9Y'ճ[?)>9?+0Ã*L?>D,mѿSZɿ@r+t<^0߭y?`?1z<>V2:u7r7DJ4?@h???a$;$,pyZ=E5%5uC?ܜUa]^}vQU+o0*T?ۿ &rA`,=\yϽ d=2%3rvP <)4u@ҾNҐv,Tz>y> PLz>Y:>Em]:4'p4*/7>T>' ž>?&?.ݔI>k? '?U%k0z:j>>'Z#56C`#*LL'>#W> X8-^H2=>-%,M|>g>1+>#>>{1 >R>:ɰ>_?>_>Hft_>w>ֿuwf$?)$>`{~C6'?N>ýBjƿ73eao )oq<%eG!`fB=_`J w>E>2U=>m>x?%<(νܿrVV&FNaK<],b}K=V@]DPrX6p!2#>>x?I{[W$]>Ͼb0뽾g(uz>s/`+徠ӽ >ŰP'سp>,>g?GW 4 =Z>A?8 ̿{Nv>?#4?9?LnGN8>PE?H8>Sz>◿F.>-^?F?'?+:P3{9E1>pe?a?zP3 ?5?}?2P/u !?#=QJ >*pk㾩~=›>R >>m9>Y9ߞh8=9~? >э>œk|->נ0`2Ծ"K/ 17컾 B)>Y-qA* >пƿޟk.o)_c>2Y>~>>2m> >ܵ?R`=26y,?,͸?@? RR ¾f>L)9@E{׾Jb>V#@e M?3XٔA>Df$浾Qs>+9$Ue)9>(v^}>~ѫ̬uwk>ݿZH> 8>z-_>ſO|>Rh2cptɽՃAZ2=߇j?uW?:ў?0 ? %_P=Z?r'??y?-cUcRL>7??q?=#p?(V{cZB=!`?~?LW?7oĿ5r?M? ?~ >:!>]˿O*Q?GO&>^'%替X9ҿ?->#;Vz^>FĂ?\A>iz7=o o> 0II=f۾g >\'ȿcO q@>D$a-|adX?).>:>e5 =1=>9=(\3rЖ>ƙ>=˜5'-ja9l`T=?v?s??TO>wA??%?9>4?S~,>ں??w?r0`\=?g?8y?%0Y+G{ V>L5;RBK4>9*K> _>|䬆=Ж|߭>Q'X>2??^??sT;d'\>"D?8ˎ>?d@9Ԫ8ֿU>ͫ .?X?U?"\>"վL> ~1?'?l?0}GG??[?NhB>r*oP?3/8| |>h? >P?*'vB V5kZl3M`>>ɕ>Z??2#)n>?w>ģ?#u7?_ρ>7?&q=>UҼj|?O?0s),d4>:>s=l%?o>%:<q"?f>G?5p.p8 渾>m)`:H(P%=]bjT5> ??w?, Fv&8m8Y6`_0 پ;?>16KfAȾ+>Wz>Sv?&J??}<b=uؕQ$&Ϳ Nk>`?}1??H{>j@??-?}|kj?^-??_!R, ?v)?:_?|M~~{u?s|? ?S $懶?.?>P?| j:?ѯ?( ?c8$K3=M^??z?Q;,o??FJ?3ۏ;L??F?tqx??rq?4T7<_?r&||>Rs{=N#(>cq|<>׈>Dsj?3_忎=>>O>' ?iJ$=1K=i]>4>k=ل?M#==:ŽýM>ƿzpS6e=^?Xq?G?ݬ₩{Qέ?X?)O?""!F'1?k??.:yGueW?xGo?/?zB-Hp7!q?i?%=?Od|sC>+s=b޾#8.?¤>>u>&?g BSJ?-?OkL?xw="h>=\#ʢБ?$@#`5=]IRL8>Ɵ'jFBh?O?&?uMh(=0F1w>(q=J_5">/>dH>hMX;?#Q R>c?k?6?꿥O=C?o?.?hϿ{+aO>HM?B$?0]B?PLqv>u| ??4H?AFmv>V?oײ??(9-Y@=xz>۶_c 2-6>A\M=#>7!վm?#og6tF>^AQxe)~炿%kd=Ԍ.Ž ݾvg >1(|"#:>I%tgcE_4ʒ>8h=P贿(R>G@##T _lpNJX&M*l82=jz'?w> Zʿ%z>$Q׿uu?$>x)5c>9?VPf^98ǿtлTOg<#ֿZ=5nմh?sm>rM7>Ng3/c㛾^&>zCiۼ*TT>ҽ )}N`->g%sɽb0u>[8bބc5Vѿ?Xc I T=ưSPH^x6g>-"h@f4ۿ'>>H뢽ž$>v)0dW~=??:>ʿy>_th>iIL;4(8}K>-6*@3"bJ +3UA1:f=*i? ~ W\L=><Тꊃ"<:> _ 5I>ʣnO>23!>Fk#Z>>dV? U>@!>2>k<{>ې?$P= >7=4>Ms?ڶX4>">Eڿy)>i0T=T>}Ku0?=wuOg5>ߒl?F |Ծ~n T>f(Fj^Χ2>ڢ`Lྌο4>DMT YbgGTo&>rD Lm"=ký^? 'RtO(0?Yz> k&=bM;*> %2U>C,b>~>]Æx<:ラdпE>p۾8\h>%jehr־Ĥ>8v7e4>nAPv{K0>/̀/YǾ>zվl>+g=Y.FGx?9uAP׾f>ee>?nyͿ'>]>1?:Do@ ?P6?Y]_?l+n}>"ͽ^.>0c=M<~嬾5]> RNZl3>Q>pH>G rT??S?H o)%'4/7?D?K8?kf &);潇?H?P?t:a!c4>Y}>mX>d4+>?5 ?^?PtI->?@[?K?qbJX%*v=?@!?JP?sCU-7ѯ(tžM>"AY*NU8k/>0{F\.C{>lj)-߽1?-!?7?T .H=8=,?ˁ? ? Y˙;UGjrKb (>].Q˥?E>biH=kDe>j=ӵ澰>>:(b<ӿSQ%`=Dҽ>Dg=@z]? W> ?e( ,? I>??O0To> WŽ?V`@[_9i>X6z!b??'T*?4;2{[?>?.?,h[ǽЁ > o=;n9.raK4=nC'>W׀fBP>N?a? ?)Z29EȾل?q!?w?~#ѿ7;w?-~?8ؙ?@?W1 =ݝz?4s5/;< J&?Κ_¾+5` eZ>nծpA=f?0c?@U?CcHh>b?kW?zi?y~ ξCg(|R>pbIR>5zbt>gbk;<>)a>?(Ⱦ79>GH'|/r/U$C=>z;tH=3f? Ba 5G{?'>?iDzNy>A)=ʛ?c>fo=rZm/xm=D>CT~=|wFx:s">L0>*,>u|ٽ => Q= 85软>4|>6">=fFV>S>M>i@LG ?>U"?o;#`#U>>B$?tqĨϾb>_i=H7>M#p +X?8?D?xy?տ>Tjn>6?i??[_ .%(y>gK1'-p̬^a>L?lA5>ƽk?RC:w$>H=]?fi}ގa>E?6ZWLY=;j@?d9=7h>ڻi|=WT 2}C<n,u@d7=b4͠w} v }"6ݡf>okkD?2БwC<K#>Ɏ, ?X-'ȿ>~A`<1beнf[<˃Tᾠ^> tK=׹msؐyB-(F -Tm<=Ҿ~>^=?Jdž\9mՄ\B>T`d=r=&̽:G?"8e>d Alý+CY=*5߿Xc+m7"#Y]c体?~1'>:6fǿgh8(?4{ȼ6$? j4Aݾ^վ'|>]|>yJ'>$4n轒 yh9Á# =|=yLDs8þ>`XI_{ |?(@оX='==1FzN'3>^[}AQ>/wB=5>8mr;4{>}QF=`F F޾x %5gKr^^jc>=#?k5]m 1ϾD:?ZȊ=꽅}?LK-=׽3?9PNkK2?xQ\bS=Y?J1J4ѳ<ґ2it?E n) )>+6GN U;BVe>uNXSeݾu?NfB>&'>6L[?IS?I#١7Pe>%<$5acs J`%='Aje) w X>>Gԝ>Mӻ=& g~? >>*߻'?u(>Q8!-`Z`>|==!<3S*T?=췿az}Ⱦ`{=`{V i<=SX<, =U5T,ٻHcӾ uaԾ^?=n>Kb 4>ɿCF>~]}^оr)RPss>ôվ=},Nr?=^S>򌾄2wۂ={gz>f%E{~= xS;o ;A=H8n!Wؾ~ Ծe=>>Um羴3/>tOHKy>Z#Yžq?KK>=M?UdLE=>Y/oؿ> ?\K"p>RD8h{->ZI.p>?}/4H]پԾh#[{I6NϾyD3O1 >;3?WC 8U=ww0@?) 5; W >q?CWB+μWS?oCW(Ѿn' >J Y¾)p'G>6% o{F5+,>?ku=])l+=}_ʾ﻾@18q.6aؽ坙?YH 'Ɋ=L+>7i:+.Y^ 便>~([^dbþC??TNAtP=({F%? |=V 3=gjrRpr龺 X?a ]f>ZeEOnŽЌ?2Ap=>>~N+>VC̾s>{?~yz>F9>\"%NIb(>ia>?>kF><֝5XJ?1 RPվ[B>?9r=>8$ʿ*o=vh" 8&>Ju?W!?nr= =vy>8b,@>8h*s<}G?h ?S>>MP?e8o=&>q=zl?}Si ?ǖ=н#"(?9gwcE=d,>=*K!_8*e?9;E< '!>bb=?{Zh*AWB򶾕Y ?C;! 49X>p>Q#?,` h tU?2IԿTn>>3>pD=1<5>#$t0JMZ>ё=a>,Z3f ɾ,>1,k<“?m|`lヌ9*ƹ=> LaIZ>;{Z?'T*Tt>d=>*8g>_=W=˽o7>2۾V&>>x3>'vooLv:yFxa׾xPt~c0׾3o6vL~b ;$dFE3>>6> }>ƾK>޴c|;>9q 5:"B󀾦}r">νz}N#|n޽nҽc7llrhȦShj,k4Ҿ߽='4K+C0ތ e0>ɾ+n:yǗ=v y4Ӿپ>0 iE>eB>>46+ؽ+0f>z0>(V>?N-<M1>>>sؾ?`I>&Ҫ>j2ވ䓽fYѽ?&Ci4!fƾǾ=& ܾ[䊾>&ȂlMRYK?o͘9#>?%:?wߕ?>$?-yxb&?T?d?.0h*~",?[T*?+?jTFҿֽžDHH>3]C~ xuh_-ÿ#j61= [=v4xRnb=߾ҎD,@(;/쾟W.H>y <"4+3akCwNžapRk;X`*vq=AkۼB?C+>^ =Y>Q4K?=gS_GLLYn4߭\ma>w= WͽD=wX蒾~( +ige2<@)lM ><½>P;xj3>!B?ľ%y?>0q>C>;>gl\b=Cp?jFY =u;ؾH?yoS!=9Ҿ\?Dl =HG=?@=z.},%cjtL^>>M>+>jϼ>d>2Y'\>:>B>ژ>dHjۓO>1Y:>T*=8Gw=H9s"y>л=l=>)cUD#a>ʙ??$4ݽ(q"`̾TTrA=Dzw;.>uc=zŸV??P>-go/>E'^.?$8(ݽ>H=3=\)v>*q;\>U˼8h@>w!==*kD r >M8-:}C;)P?<4esiWak2C?/hqh玾5N?#=}@hh=s t>{>?>gq=?FX?9TIkf}|>>O?8>edG=2P=>T>/ݍ,6`뾆& 2r T=rノ?K¿ `> >o?jR&>|=ɿ KM>ib> _f>L5=>l>P?{T[ې=zxܽ a?IZd>7^=T뽀$?RO>9n>I>>d*?s+QL>th>=?Xm>>^[>e>>۶>">d3fa fk*]> &B7Qs1HP>a[>,/>~DPڡ9ʾfbe) S> 輿+6zF2-r=g>>׌Dt>Be>ޏ7Ϳ1<=%/=,b_C5޿0#6>5M߼\hd>a$ѿ['xdg`VOQ>,dwsoӿw7'ړ? ck>"? rҿ'92>>?¿=ֿ#&>0>DF>ā >;i>yO|'A?K]e>Wv3Zd8!>_>>Dᄐ>%>@l?.8 ^z>e#OYj侔3Wy-m>hK8J`_ UՉ$Oygü`=_I41] &N#>hR[8+Ծ)鼗P>I??(A>lq -}|=2&?1>u,?`W?#< Y>FiTjH?`>.p;[h8>{=~I7\2>9uB>>V!|ᾺH~ƽPD'<6D_J~cUb"8I>?9H˾Ȱ(G>t>,@J36οdͿ,>5z3N>+NFG8a>*QI&ڿF4d3->%tJhӾDC3>F>O)LsG?ij>['FzN_5?nCF,=]bh?t6*=,t>dK|?'*J>1CVu쉿BV>V,>OϿ>M9y@¿#6>Nu=?xd>@#>? ;\??nY?>Xb>?>ڒ?|>*5P>3?n>XL? %=a?7r.<`k3> ⏼p?+=g>>b;Y?#=[?>#N># ?et?Ŀ=er?%"K>3e=þL8?dי>F/=lQ8/?^Ͻ%@"Լk)a?=1: ソ,ґ?:IZJϿ~re2M>0!ɽjZ?| ?>w }=g>E ?Z>?)ÿn=ʾn??E?X*=ni {$>DHp}GϽ1I?t=M&z¿5>G"?%_>[ ?H??(F$CZ8&J?a=7~ԱJ|M?M!ƿ y `?t ?LA=` w?z=2#fKT>ʼ?[=-:7C?B?=t3~=(=ʣ?4>'b]ߜ=9y?Ku&ǿ|(9R?rv<}1As =fز?x>O>v|> >E ?>Lx1h=A>h2?<>pF$<罠K?D<ʼn>?['A1~>-ؾni?zzȽ *>i~=^?>Rl='|>5a=}?Z>:7 >7WO}2SJテ%?eI"wD?dw_F:E'n?SSR]Є^Lf?2(s>S1G+(?=v> Lw=Н> <u ۾&?jWuzB> 5 $HZ>>e ?),?-P> V>+?9?Ѧ?O.??BTA@!?4O>H$O?? g>z>q"lǬ??T{F>\S>R7>5`j6>a?>F7/ཾŒڿ AB?X6=>J >}>Q~xEؕ>yO>Է {= <] jPGq?f9q;{[͜I>"l=>?']>Ѝ>Ӳ>o>J?D_>#Ğk c2>^~,=#?+W>̛?3L. Z >>+>I("HDVSe?bD?)?iUEQD5?+:>?/\>NCweZ>=>>p,Mg"l? O>R? 2 ? ?Wg=G̵Erl>`, =T@}12?BM? +$ξn=t~= 7=P??Ve'ȾTK>>B>.jPƽS'B>݃ҙaOr>$C=>;Aھ16^7𻾚+|AeTZhTEb_W±s"ѿ2e=w40u>!`}=)((@S=8a? lͿNz>>0mJ0Tk>̊GY/ԍuv8*>|?K?}?sxB >fx?Rm?5e?Fb0$%=3??}T"??m&ԥ@I@>;i=&Z'6ϿrʿA+ǿi]DJ>Fvž U_ g=e/q|_7'4cP׾fRۿ jP=uX,w㾱t?Vae<ݭ;TaJ>: e=` @V)ə5>qL=It 8ܘXa`N@D=&k=΢ ^90ġOL>@>\?NL{>H1GA Zz?AK]>H YK)o/#c>@> 9?E?.?=0/ r<Ҧ:T="#@xBƙB>>ڢm] {t>>_R.F>?I?G?MU5!d>&6?Dg?X?.'T"?+?DA?.cW%9`d$>R>Kf>eP*龨?"m?ք?%ۨ&8n?6 ?$?1i k1%?@?1R~?>Ba (=5z <&\^([c>'H=H>P ͽ6|lI%` SڏOLn= ݿ?ޤD0=oq?pe>w>28ʼ7ti?)з?(t?"@]?$? ;?2i.A)V?5 ?'??38ɍR;>E? k>\>ؒG}AM>_?>{>J)̌[I=ۗ?>3ǓG7pBX ">ם:ҿQaD>N?$??m->4>>?+xg@*&>*|[<غA=7i>ߛ`)>3>>?D@ C?>>?!?}c@Z52e^FǐTFIA=Ai_p ,=p׿Ykݽl =,5?RV`O >m>+?n52a?L?2_=kXӾ|bxp~$tF׾=rgǿDVԄ0>D>?{hIbu!!b"=lDGNE0I CbB=$?RL>>>*6dǽJ?(>_[> 7f}>̇3>t>8*Vp ]Ͼ;\I>~k¾>[0,;`A:侅8>!2W,շ?hSmW\>ς>m>/Eb6+q>o;>K>뫀>T-0*?W9>WOk>p ]6=?->QKCv<{mڿ UT?_F??>rP>%|ĿZ?Zb> ݿzR&jo@H[eG?}a?Kq?={e_Ⱦ(?n>>qxj!f?md?? ?,WW8ijJ??g?S#kͼ)Ee>k&}1[>|1owf:S,*u$ھ2>[yN=ʱO?6m 2O<>DtZ߿J⨾Aۇ5p=; ct$$`>DWۿqFўeɼ^=u!!'_})SVy*??E?@LU^;"?a"?5c?%-E`)ᾳ?? _?Dp?Jdž[?,?>?\l=R>>>R'\w%Է?q;?Ev?9Q?UW?9??z])?\?v"?g[.)B??]?x'=q C=Z!SN=۾j66*>h > 5s 0@1њ= o꿎tym2^=Uji/Ӿ/Uo=??Ej?TQi@??M?;!(g8P(<Ѩi?7?aX?q\P!<޻w?J??G1 ˽p־-En>7q 2=R\ )7*{=ъG$ e>k!>'7>X>~,R|>Y{1짿:!=R>>>^ӿ:'=8Ҿ˝^W7>?sU?-I?DD_&>G|?kT??8NG@)Mrщt|> nB } *>i[4mrnKAپͼf>տ^.A6wpv>vKe(jCB!e0=vr3+>?50EO=-9>Ae}>a+侃?eAލ;ѻ>դa9;."9O2g>,I>?f>.x?m??96/+S"i|>?o=\??]">Bvy͸? >{{>0+\{(+?pz?) ?YPQCR7HIvBK˽nPm@@s*so>2a{,pFx8Pdt=F+9 q> TN/?v>+>'JR?\}>d?.MlddR??7!?i{NIY7 ڿ><Ro7H?Y/>楔?)"Sc`7*\Ǩ>{=ԝmH"s>(=$p"?dCXʰ0h+2p8?+UX 0=Q=IR?P&\p 9y㛿B>| pb.'ȾWm><7>ɾu>tUMI?qr?cV?MLu;?Fk?7L?kr. mq04-?j@?=?N r='>tὺS3?E>+OP?={[ګ!y=6 jMOhzW>~?H??Esb1>Ic?I?_?s_>N???ڳxƈ"?,?EF?ex)r??U? FXT??pM?7?qu=s־+eE>> ȿkS派ARn?d>V?~EFgM6v2?7?.?oj=Xڿ iEv=ɂk@:=֌ ,>.́?Y= >*?80B ==>?//E6=>:,>0s6j=nI8?+qW>H=3?GcOG?˧?6?flBie=_Y?*d@_P?=G˴?=+oi;>=He?X7En~n nn>Q+;Ÿ?Lj=Y>M1c3?Bj.W=>M?cL{e_>c(?*>4?(wp>>:վ?d1½Z;Q>?F8C Z~>(:> _>?>M2?XD=/>b}F>B5>Y? |Yv`<[>z hG;7=oa=pxپ56?=oX;x=]MC?V+-\=n"'v>97??p/]~> =g?+<&Ű.5>G>?<9?`Vz:>`>i>{?aA׽G>gp7?2om ,Fg>=2f<>Q<$?0YH@ǽ0i2<7 <歴>7z'>q(<??*0c@Nj5D)xgVq\ ?>z 1T'rA=<H vjs־D7:˾C[E6a.ٝ9Ͽf`vX&@+}#^+@>)x<](vt!>d@IýVБ9/?5$ =9v _?8b>$lv ?!\mY澄? ?& >}?f?5;`"N`\1na>T0YR"¾& ]>kah]Z3SI)x>C(NܖDe*B]PsR9'%hؾ >9T+HaRݨ>\hb<2 ͽlwx>o/Ū%Ax\*>~ Ǖ;׾ĹE>$ SX.-<)ɓ>ZWOZ꾠>6>'?Wl|>ߏ>k>1$ol!?>˝=?1֒!B>5=$> [/<>>l?gp6 (:Y\>Jwh@aAݺ 0g> e2%!<%ӯu>'xo/>|1@EV>oοPu>;o([> |f$c>y?s^cH|J:?Je?&x1+7>V>w?d׾ rZh O ۽v&> pFb|F`?tW>^uF>p>ds>}*3 >ר۾m>'>/z>;m¿m>sTϾܥ<ͱd=M˛>(.6 -E<EF>?1`N>>+>ί.E=B >咸?ҀrR>yABr>*9/ΧH>kw:>->"F =8>R 6>`R =#<amezx>N`;G}ؾ@W<6L?=m!>DnҾ ?,>>^>V? 74hǾ>%>*>.?u9J>a>u>! #@c=Ƚࢇ,>_F Q=< ?d c==tnҼu@?)JMB{4|=Q45 >(/`"3/=Or6;>8?? nw>)7 >>M۴E>6@>U>t,tA>\>=8VYŚtd>5?5'Ӊءċez>`1H=nH@/MI2Q?= G=k?jKU=¾fþ >@?m]>J7!&>]RRRY> >?.KM'5H> g=f|JQEW?  x=t?(3ީnT>u#y?Ov?H?YY^,>>>}A?#e@ra>B*o>z}h#jߵ >R9Ҿz/O=|P:hST q2NxN"d`ɾ}q* >&B{db>X޾?K<.Z-%es_k?-X?2#?MdؿbM=$wѾ|>Ѿ+7/n?!?(?:)GE)ξX?f(?m?Pr@N>W>G?[fxGrb>œpiM#g >=?9~`yyx>_=|XPY> #="+'tZo\lsx{>?Iޠm8=$=Ϩ/?Y~WW;>F? q6eJ ?=vþn> {@T٪2>>;e?UcLY\L=5?eЁcmʾὃHo>Ϩ o?^A-9;=쨠cDA" ym`gd^`B1)=)k3?/g9f=:(U ܿ$@>u;O_ BI<O?x4A]5=ݾ|? l^') = ?5ɞ]nZܐM>j\}b+ؼvhǿV{N< (7Ezq>%?qL? -i㨿)Nxpeq0ǿYwҷkR< ῔VzЮ0qJIj'a|C=P_|ھUƗJS=%g辴gp;L>tphe{>Pզ3?,]]wu<3)t>? ׋_tB %.>Srag">>~E?=0Y1t`8EIk?K?N?U|*(rb.Q>1gb:whTP?xdT- tf>xLאvV=7X\!l<ͽӗW]>S)(`>%5 n] R>ο>)|uh?zυ?kD?:+_?t6"?|n?׾2"fn۾+D_ `얿!8޿`V4/∋$ jN3 <F is=g{xF?ǿQc =k8(6߾yFF?P?]*?\ο@׾?O7?Y?Zs}:?6c> ƙFb1ep Fq6Xſ#>!pa~4=p־2ӿ& >25NL<>b?]?h?A [+P_J=?kCB?w^?pHqe ;⾾>/j9ڹR>=?lA_M2#> 5q?D?)0]޾S2>U>J?@>ƿX>???TѨbm\ީ]:+9t%`Nm1D o _<`{0v>I8ay>J`v.%ɾצ7j={ZҸ4]OPb=2pk=>9>>'ț`|>?[?^?%?m/?__S,=>H$=78"g򦾧 X\>*9}4u._r8Ҟ>va{9ë= ?y3hx2ӽ{z)=\>nP7>C&i~5=վH>cs>:."g>Y!9q<>þœV9}=2{Ͳ@[ܼIIlj4uM辴w޾/́I N=a>>K=r6; >Z k=s?: =}C]ip*EC p@3#ξhEsVʊa.A/=sPο [>X?!`HJA!'=L+Q&>V0Y<<`䨿(m> A/&. ]->>y3ư2h2lvl*o]4e<\Sm=XΜo=k{ȿI{>Y N޻Ƭ!Ew),EyQ=ǾYA>@/EF> Ӊ=ݿ (C֟qG%dI AQ} q>:y8,Z_46JǾX_1jEIDلꎾ,Av6҅* :<i4Gݽ7FӼ[e9݈AȾΖ^݋8P\U@Zq>&4[Ⱦ[>2gA?'Y@_}>DOEVd T>@濅]J>ǂ !%>n^/=Zu辨׾udV=l#_ P_V 1V\h?ko0(;S;LI] *^jP:FFF=<@7{˾:s=2;`CkM=;y\>!>>U>?h(ضG>*ʼ>L>V=^w<>jMn>!x>#N< S[.Q>2=&3=^>HPSd۾PӾ@ |Z?!cо GLg|F?{Fdž6bF J>v֠>9V潲;P>J|b,\ >ժ(8M>V.T?;bL">^JHAs?`Kj>̬=,"?h?EnsLc >\t3׈K'3p??.)KqLl-s>Zu6SC&y_r,||_?b8A(bO51 8>n8cAu>U8>ƹ,=aF>쯿UѢnZi<#/E1w>_@n\o_ԿuK>TX=a#d?~_ Dҳ>(^&MD''i>9= igE~w@[‹ʣ=L'=?t15`\ھ鎽wsFy?F,u9x. y+>-8G\OW|L="pA侩O!.>VۿHV"X<\@$FVG S>sG>6P >oGs ;N>&X\|R@? V Ľo޾!G>cP`ԝt>pBT<Ȇ;6/?%:glNi=76]>I/Z` =89+q4EA;>O پ .s>ߓntΞG HӮHK>~_>Qs>q|=bU*&9>K=ۣ>zPLo>b>T?z>>@KC<#K$?\t?)6t=ý FԿW>]l?>8u/>zپվQ>?Ev=ZG^P>3@G'<ِ*>>^>ĤlĻo>>XO=iz2¾p6?+ٿi={>\t2?/|t>.KE>>:qHC>`>J>>F"U*6:彽fT?H0dB1@!d= eB??i\,rdýiF?60ýej? Z\Dœ dE>v&Mܾcb?QT=5ڼ>>s|)A>@^>+E =ޜ=J=K+V t|RWž޾O>P<>$>7HbV*>ܜg>pԾ ?O$ >H]??ust\>eE>oN? p=y= F>!=xʂu>T18<>3Dm'o>2>N>>db!=:)>sK>>S*I_jK=s~>\c(>Sm>$J h>4Ƥ>>xu=d⾳ݾFp;$2"l O b>|1ُž])`>\ROLY>Pȶ>=ʾQ?8Z`@ Y= =9XO =݃e7">x'<#$A0BcB?7v"Ҿ{V#>B4\y쟶>.=?]F+oP=K>a>-j?l$-5?"վXuw?5eMx ὞6Lh?U_6a3dV6GM?@)>.3L_>Q$^g˾4>+c>>]ky"v G$/ E z>>?ݥ/)6k?v$ w_ԝ>6 !>O+눇>p>u}!!>>vɿ% ~>ӀUIZ.6ҽ07>>=H$񾖪L?8??s4Ӿí>? ?woL鄽7k=1=Lf >A#,V>KEO/K@p2ؕ>ML=|>މD@0> ̾9P;G?<,MIҷ=`=צz>ZG>1qKƽ>n>I>4D~rT󀾦8>>>9?O")wB> JI>Y>?v\Yat^>n}>n>$%s*aRjb?)?n;?dQ[ҼU?\Y=; Tfoah mR1>?9i'?9*?2nʐqJ=J>\>_x( cK,bx! S=s\T;n4[|V=D?`7 &@Љr;-ʿ<̊= Z>>GD> $>!>YH> F=I>K 𑾦ýJ{E Ծھra|Ҧa>S?%Ц?z?Q|Pʝ?%?Wy?^?ga=T?: E?",?^Kqo=zf”=<2>xwȾ> ?5?]?;U&<s~?Bľӎt> Nrwk@>[ Ľ?Jm77rY\=9x>?>6 OUS}6;vY4Z ;3x>Ҿ5ȗ=0 S3=1 XS`z>m_ >~A ҞoYMpL'=-u\ sGR>>} 5@J;_ >>3C> ?r0?%=$=0?Sif׿=6ɾ`>>mpC>ۼ@J)?H>ui9u>3")7b?$?fA>|$\ツK?G}>sg>M?u4Be(0Wo㾂&(^}[%%xk>]h>3>R>Æj>n|f|7=r| `?/ ܭ=<*w?Y2sq>7>_>@>0YcA>w>žgl>y῜+9|>}"BT>ov'a>,JyFcA$, xچUUzҏ;M=p:JI(9k!S=Y>>)MT6 =KS<_*>Jaǥt>Ym(\, [򾅆>)(]LYJ,y>>Q>}Ngaz̽տTEg el#ă3m>;>Գ_?q߾23>?>-(?@v>ct>@տ=a*Ly\F}>BW[wɿzcE@a> h>G>/e^) <^ٿ"Fv r`ɣ=9sڿlD>d I|Zd=܄0tq}%>.Qҿ]h*=)Y㿹 ݿDՕL5:>m> >P߽:>wvž*->F =4>[l,==E>,aT>&/y']@}.#>l>n>½`{T(p5Ϳ*b)5qC>M>/-<=3L^>b֪>ͽ >hbo/=̔-`== >X.=+=<#~> <[}l<=vLξB? @%> kჶf>S>=«& >[S?x>W~6]_.2M???j>1v¾?DKI=⿂yX?o<,*,=G{אM F?}H0=YxmU}P?U.>g\e`?~%=mJ*?|Ax<9Ib@ '>Gs?+Uf@/>||T\6?[o]a@<"{>v?G8U?G=L?z8M? >f?| @y>e)x;Bt?i=p>?lH=s\*H>ȿ!?,g=K#Z?}?!>X1*R?\?~-><>dwh?k$5z>b ?_(ֽ+>\5>Յ8?jjU-C0>1=?QP>MԾ L>Iy!d?P]=5@￿7]5>S-?Y?X.>Mb#>ˏC@ iY2>Wj?**'jFN=r$4>_@?I>r?a_N>役rG?y2F:? ]|>>,?}ͣ<͇rDr`|B>?l?H*,db>;?[h> @X z_?a;6"ᠼKܾ0?_>@> Y?$?y =y`}A{v{>õ[?>%ǐ2(=ټͱd?\=G? ft>^mz:?Wj\l=oC?B' ~;:~orl?@2۾:Lt=].،?m}YG?a?[?nʊJ?& ?Is?f?_:_$>]N>R?[>q?g?y>k >?>d?Pn>(>҅f? 3>?H>w4> `*KA c`?oܜ =3'?cc<gO=0`=[+4?1>1<?>VK?^Em=ٜs:f}z?D~h>>j>0>.@ŀ01?:=uه -?P4KDՈ̟?hԽY2zQ2D?Za/E{>" ]>Ͼ(@?U>bHԽ!?zqq>%ξ=F*ӓ>پO8>3KQ-"rT>L>k>Ӵ ~݋;04<>xP= `>J&=~vɽa>=4Y::蟽CT~)==%[">B>pӾ;>->hIE5>L>鴾pP>A˾?='R 0m׻i?k>%oM~If:myË?pJ >Ee=?>^_,Ir"?;ٷ?Y<jd9?d7?^?)>Uo?/&#>EҾu?lX%ʀׅ}> =E?W`>m7Ib> (_oII>5U?4>7ʧJ1b%nϢY>>e d>ۥAÇ>c>_?>5/Cw~?J> ڗE=C=?q=ES&`?<2?4Wo*=@ >>莼0w>>a8Ā>$>[? ?Hi=v@W> > _>V>@J=C?5I>6??,㗿w`??M)? ?>+$?m???gGA!1>7?1>?`,?ޤsI>x>$D?+C>SvP>(,o{:"MؽU{ ?*wa>p>\?p?6>_=+ 2yh"u=Q7.Z|FYJ% =7j׾}z=ٚdQA Jr1Ѿ+>>,V >9hwR>B=,>UQu>q>:>?ʿ2> >?kr?V?u׿ƨJ>-޾?>֕t? f1KNӸ<9\=K @==miMܽf>?M=\o? G>N{%H<)oٝzg?O>vu/¿4nt:r=z@oG+[n=NZȿ+2;CO\>6 Կ kjW?u JǗ\?qi^=d(#|>O?mx?]@?v+п{)A >?t~?fI? '=;?(?l?3Yz=k?µ>.[pE>>?t>ٝgy>ڿ'c=s~">DR=,ǽeKI o>x:/%]=>Vz>`y=΅Idb$>=1Y?sQ?g S?|`4n Te=)+?R>9=75@q=4B7S:y j(9z=^?P?C?W:aB#;8?|$=$J=V +Kݺ+I|"F(=܈?V?ʀi;O>s>cEFj:C>2Ű>>|>BdT}>->G>`&FWܾ!>sK>>GK %=b'$d{Szs>/>>߉@/>ڥ>>me-A>%>p >?26=_Jv2GtF=h90Zp=Zl/|;DO2?`J?H?Qn6þE<=3<>`?39`s?r-Io>0>>cÿ`$I $ds' =?:O?/O?=TGJ'L?9?? ?l#fh>>"6>mE[ >X=R>R> S@%>7>t>n?1\)p%ez󢜾D26PݾV\, , 9?>6> F>_pB@.~4>>R?7]yvp/ӾJO>viI>[?4r \/ľu>C>ꜟ &wЯ>9`,NkKT;j(>,8>s0(<(G=r >]#>zT+d =sG>n$?: 4hj>>?X64q?G?.a?p(4fϾ?>??xPYan=ʽ =?\-H><?3 R??D>T=>7>H(>ʸ0K=̣>5"?mv3qs=]>+? =c''ǽӾn>T (l۾<E>N@<^OWO4&Ǩ$AȄj>vpn)g>Q݈Z2{`.0m'>Lsoy+Y?y;`>fVmJ>wl8~@kn>˻ǿ),={>ېB]p~'>ֿJ eby<[̚?J>}> 5auu?">F>չ9Zf@ľb?_?47?"Y)ؿ9D'N?"}ؿJu7ZҬ1>Ȯ.>Nƿ?ѿVTcn=缿IA[=Umwײ>D.>h B"=0o[>eZ8Ts(ؽ̀ϾC+N >Ó?>d#9!gIɋ/Y7zx??n?`N=p&&_?)ክ>F>p>/?S"+AZ"RN:$<N ھ >c#Er=pFƿ7gӼ + >;}ȿ$Ⱦ > 0>>;/qX> 5z> ]fB+N=B}M JA. 7=_Y 1Ls。Xu9[>{%?N?A?^-_>j9?maN?!?>5Q-ゥv>D%KO0<"%s?I S>8x~O> =޿'y=6;}L߿HȊ1`=.''>Q=z׾J>y5 A> >'>sfQ?1쿄e->[(?hr??6 Ki>`@:?7?2?RD=y>e>y?޿$='>C>8? + {}e?$z=4˾gU? n 9>Jk?>V?\ >M>a=?hO+Qm=׌C>F?X"⾅B_G?.5׀)(s;:)A?.J!P>e>vu?)NJ=٥z̿l>RN<>z>-?нbU>>]2=Rۥ?nkC(>O?)>>7߿'߱f&>[@p?A>r ?fj|f=6*^>N.o/'r=/@>}=盿vp:>?0H>O? Ru+R<=>H&վYw˽W|?(W]0'g:`.> o?"NfB'ڥ?2?c{y:?8Wg@`&FN*@? Ľoec!?oX.ZbA$?}R/=]% ?XbOaݭy{+{?jNzQ=Žz?OD %P e> p3_?>>N>ٝ"ٿP>Øc?  >pe0^0)MXp?59ԉ ;/m?̼߳ K??> ?qv0@׾??V?B\S?1I>?B-`{ Sʿ=m"ҽƨ2;,<"!M^[ܥ@a PȾ@7 ?A?N/?QD" ?R5> t?.9#wWwl?+O>?ܩUD$R6?l?\:?țzWxJE?}?W?TPb-?>Y?+zpxbY> ?ڴS?4/?ם[i?d?E9?H wᄼT.?>:? gQ4?h?%>?e=õ?/?XӾq\[>z[% >V6 >RZ1=T!K*w$=@:@>us|پ4>`l1 ><}l ْ> vy@=`nZY= N]?h?j?ŧ&{$ >7X??;?!h \=1n>Xa"?R/5u!=qᵿwY>gl~!<<۾|%J>($ϾU K>H=;=>'R%=;mmLx?60MC>F7>>]=_?i_ P*>.>+>/?v ><> nn?TbN Xo>? v>?Mj%pxl >˵=?XK1\[>=Ƭ>+0>eE>B5R\˾L>oP>oa;)޾>?`4_#K(L>Ă@H@#=N7-8>/X>*>>Vz?hA>4p >$n ?G%?>((=S&?@? Rz>f>_W; ?]uvp>aFi2z? a,w>BF<(`N?Z!j#=%DͪN&>_;>{MdB77Uy<`5_wT;-^.y`3VͿ<7>tYYԤY4gܿT?\WLza[3ٺn8X#BEO#FMM迀۾ lW<`o ݿH?>*WlL=tӾUھػ >;CI===ñߎ;?Mr@=+> Pi?X8a5=н.Mq?#C`&(=:=a?7>8#r=v:6? s.罉hG>(FľCV>>y >'D!SJ@1Y$>̪_X>=U*q8⬾a>V>?*T>=r>#])^?T*>]?!leGH贿F >/`(g߾,&>*/+4=}5[MV>O;Ľ;=~jֿuDппN])u`lĉ[o]="w?0M1׀o9Hd>c?=ָs?cR`_sqk,G>j[<a vO"=|9Y?澂*ѿ>M(^Ts??ۃ3R辏? f>E?mXX(ս0 \7=S猿=RP/|x>P s<.Fо= J>/;)1<%>?EZ+ieil]?'>F?.f0=ܬ?:?F?K6i =F⛾>GN> .>ȎR>$ eP>T>wx>kL壿2>nL >ھX\>)=>^ؾ.{;O?D8C>@>o>PG,E >0b??$>هv>Jֈ>ƽ>з,%V==W#:?&h^^_=EXo>m1=%FWm۾:>oir>ٍiI>5Y%>Nyamn>C?$ 9XL=b$1Ӿ? O綽`>d^+=]nr$=yIؿ N@b$?6`=*>+?q/>랾VYd>?x>3Dp|K>ܘS ̿AC= a<, <V>#y>00 =c~K>0s>&×̼i`=IR= t} >>zFD'I6;>su>uRVlrͷ(> >leV |A̾Y/>ɫK>l@? 6a)-?>)>9>]W0| 隄>?t=}wr,h=-Klz!bC(EQ=N6==s^1>i0=5r~+><3x>(><.? .T[~? (?%!?J2m43#f= Std̽Ahx>8To=*z ?$5G꫾q;tO>]޽y꾒>+,q>0=p@?%8l^>J< ??}_V8x=*x`>Ϫ&z b>Y=4뚽?8 +&0~5;2>? 5˾>|d>h=OLEQ>WG1ž;3>}>ޔ> wb?~?!R?A~(h>]HE=3J ?,Z wbB=˾B7Ua>ʽ]nGX$-^q\n"p=s>yd6>ǾVVi>*G0g gvT>;R"c>^~ >eSi>/)Z6+ ?"?'K?;6&s0ݽ'>7C>->Z>9?ⷻ>>2'> `IәV>E >O>_ B>7e>H=-7M>U >, J> q߾?>?<.>?4>G)Z:2??f? $$Pr>sh'>`>Јa/]>(?l<ᬾ)c>;~PD]x >`xq%qLh蹙> m(x<=>E^0ཎD1 Xd>6O`8(m6ʾ8{4>f<>X+ʿg=ݾ <ս3y'2nm!@F>#>A6hZț> |x>7W >}J3FDŽ#>>!S>B#hy{輾=8l>?I@~l6==>,i{];و@q9wkxLe-<0L[U> a@\<3_9>kREh'RǾԝgA'p~qy"L.ܿnmL]5~^6ViHb9=T2`]=DԾϿ!4>S4)xK? >>ˤ/-/𼶾d$? ;>`>> q>-C=\[=֌qW'howɯ0d=] *WӑmCr䏻PT>^3/>U= ;l ]s;wdk=LL;OApd= ʣEЀurn1@ݾ>(umG=dO zepe>?o࿧^q=Av7Ɋ><h' >K}˸%Ѭ9dG=O8?<=b>P57&_鿂8*忥'H>H>>>8=վ-L>o>c>aPr9 >&3h2="@?2>nOf>Gf{0䟽 f3>hKӿ1WT?>=i?#?+?!w3V=ϴ? ?e>bQ_^ >G? K?(?F8L<&>>>ps޽k˾~$?vӿ1#SV!A%o@_E>[D.EkO>;B^S㾝*A>ҕdn<+y5Cƨ)=do}Y>| ?R?^?R1B.>)>R>*p asCR#=}^%f||Cl=Q><]"j6>>F=cҴCudH> VG&0V! 4=\و)Jؾ[I>q3I`"#t?i>.Q~@%a,H> ?A齲E,Dk>`Bxt>]%D7=ᆪj]>ļIf忟߾-d|_*=Ž>m=8 =yx>̯>>_)>j>ǝ,>~K:fZ =={?'@F{&=δ>oHuf>0cJ{: n>b<19zjB@՘!ż_Z;<sݐm9.  |)Q]Q@O5ʾn(r 1EJ^(N_G= !|> j@>$2|> J< >6>H> *>bc>W=x>3쾈?p1>Ns0Cw>b>o\6Y>NH>r'=b08IZ*0ۿp.EO|EĽv)R<~T.Ӫ?וd5۽O[Nu/U-\ B> Կ]jY2 <&W">%I`"TV=`" q޿|fݒ2$ 3kfQ hRɩüG!MgU>p={1@'W?;y^G@X>Źk>Ƚ>gs:i>HR6>w>> >?J:ʊ^>_r>}N> >g>,?E̅?CC1?!^bþYH?N@Tþy#>*'(֘M=\q־>rSY>踾Ҿt>boXI| 4&>#=2?JP./P'GE=ď|A)p< mW(sS#\y=u c>;8? ~?]F>;5=n>E/>K=Qav+%6>4v`1x/\->[X39݄cνK)5<׾?&%̈/B$>|@{%>e@])ZR]J> 徰t%(D4%އ0[>E"dlF>f~.9>uH>]^cs1>9Ib_16#ٿGZi=2fuG'>sKQqo=(п" KEFcW>fuo>1y3=#W{[BXq>@q>D b wxC.A<>8zϾ2/>B=T.$=ag.wj=#':@] [>F+̽>UP*>(y2>l^ >vZ{NZ>P?z/`?!Q>~P@>~=w,YU`iJ?@ > c=>4+'gӾB?(=챉>{̽eәu0*ZbE;>x>? a(=rNLLLkaR۾hI->=ٲ Rwa̾Y>B)@n'ſBjw=bF? w>Ќ?JCi{)> F?= ,~򡾐[: Y(/>\>L?x`S'<>WKǾU*s>Nw`$h 8Y>M]?G0;׿dǠ>&>N佇V旾\”}Hd=߾MY^p>ჶHX>pq:->\ ,B>?+-=2侢? }}=L,IH?{a(>;䬾f>8?;z=Yp>g;ۣx= F><AD㼮6;Ĭm +>J.,GʾN6 f>澃äfNü?CNwQՂV 7D^;V\=f>Mz׻>s%%߿Rӆ'œ,ؿ]׺_ah4*pԿ-nkb4Ʈ0rK=j}tQv?h:>hzᾪQ>׈?1{z>Io>?&q?BCx!>E\S">.NfMZŬOd;Q7H`W(=6fKF#D۾>8C}ә>:XȾ]:q>d<,*ў?o+Tõ GI?njNZ>me}H=>q5 oJ>~znH>ɾh\1{>=7m w>Usa%=ڸcH; eM#mLŷ=8phKs־>!ԉ>bA:Nc< Sz>z]0W7ାK>18r>0jɮ./ϾXy<ńo!z)y; a|< 5.*Ϸ!վ >oY?>d|;>>/jZ>/P]\ֽZ8_g=>j*=(>'}Zlϼ>?>yXT=&>@->Ǩ>sE,R_ ?=G?F?ӳ}L^()оC>b(v@6㴾Fu=16XW0 \?OU'p9+ǿ t>CI{h.ȾGg>X`ԾeO? ]daPezG?Rh=Jӕ{>.&C\Y=-[1>Q]G[=u;Y>٥ ~<}Nz?kϳ>>C햾;>>ͳJ谽+E>v>>;iW1|kW! */92`lʾYX>#.|J>>sUG?L0 >3pq>^gt4>$e ?]>*"/>,l0r&>ȓPHx=>$\6>Y>MoT=KH<=>2'=5-Hg=y8>\W?S>}ˬ.K\ѽ>K>b>BEpT4v?J?9? | ̖P 5r.>mn?+Q>8VC`ki&{K; ӽ'K74J-JV?-ox=z%<s?G Zt&(?B|???BTp`c!XwK=x=\E̼蟾(Z6] 6?GP|(>=ʊR Cn=8u /dž r>;V(>0#>>Bkr>>Hʨ3??}W?k?w=꾓}>n=.QL:Fs=^.Rmkn=-< Ո?[63dS>#T;>ɶ>ۥ?炿!fD}z>!> ?v]H#>GN=8a˯>v,w˾jWO> ?>e?2!2?C3??½?B?SR>,?V%?@g?ʐ.3>?4?ͯ?yt??P=w5(W*ƣGuN#i]Ӱs!MMپU>:6c> m>Y ? 5>0$&7?} ?\?CO?IG0??]??,pVv=~=;S?T׮-X,?9.?M;??3;vqK@*VO> :qQ?FdqC>_>%=߀?qR]^+}J5??ÿU~R">]>GC >Y?yZ}k>J;]?R|j>&ս =$k?/+wxP=ʽ齝)?AP?[; =s;gþ֫X| juSA9>Tl"¾ 徢k/#A?>\>=?V?Q;\A!!}p 3*оyRq7=0+(w7;=~%~߾`Fe;r NKӿ1ւϼ_Snrt@UE`:;֐zp<*ޚp続2E`=( A==>bz> ?w=FExCĽ]N =aL~P;AÝּ21@]^>s>>>g?*P>N8>>>>KU? ?`g?6?uN\U>~>?> ;tſUB8RF f1Q򽒼0>>y8>ܱhh齡z><>\>Ounr=>=Up?>UQ?iK>w)=>2>4_#[>=>>,TKI:8:S.vh>o+X>9=*1U> e<&>2¿ ^<Š}>*H0[VcG S;>*cHѿ4Sی=-v"sJ@!f;>>_>C1|U=í>!-^]=Ήܳľ4QLpoW>&ٿ~o?A5;+pD><iɾqCr*<_qjT=1.?>Gg?* vZJa> R>rD>(N|%>,0Zq~9qM~q^>@Aپ^e*<fZW 钽" @\>*^x>Kr?94@IEL#>C?郶?HD>$z[8?:ҾoD6!>r>ʎ?E>r#>F?P? R@"9s>T7žk? ^ VpA>gq>؆8??=0M\v>>.o= ?>*Wn=zt1?=9#X?UlJ>s>|Q?_>?A >KvqNB?<¾ ?J>8'+?qt<8fg<: >HHW>料S? )t?(5S >3߱|.?=q4Un߾ :?c?dn>?=wK?BnR4 >6>?>?-lˎ>ZTX}?5Ec_ԿuU=EN>ǿ]>t1Q>i=?>B?2@>U?Qi?>?)ߘ?m"1>L? ? ?-1h㤽U??W?=O?[XUpe&[H?GufR C?;K>7>>Q߹? >ĵi@Fǽ>? >?ґ>*>?`&>?/Zm?~.?L >>V?z>/c|Ϟ> > ?>?Ȅ>bl=þF"$B5a{5?d3/?܃Y>R¾|@)~>B>3??Ӿ#c>>j¿Pu3>A?a>5>XF>>)o?D>[?]Y>Y"{?7<唯> ?г?6~p=1Um?Z U"\uA޽1?=dg'X\Ty ya{?p =+ҿv/>0> U?ɛ>>=1Xu>"ʎ.>M,хS=m+x}9=kpo=tY>pa7T>D_H˾vv rol7\q/F=d=>O47l۾f> `x/࿞׌)>0ξ>Rid>&Mp>HV9W=h>+'?>$9n4=3]%:1b7Vҿ?0`>!?L(qc?g=VY?4Goȯ#AU"?CPv9>忑a!%?=>ٙ?Svz=$哾~<1l3e`Bx=>C =Ё=*Y:>t|w>eHΚo/h!2 >O!-?{Q2"D=پq?^ .ɽ> "?sѡM>$¾?Eܽ@ۃ=^u? =xb(:?F>*o?QZΔݽV?;} >?L߽sz>_п c?Wk/t >69P!WGR׾;>X>e߿Ywu˾O.>CD ҿu1>Mr]D녿"A1>Fܿ*/{.=mŠ8?8=t< fm˧?6]>ĪT>l?z?BD != y>~>~O~>7˾pWa&ƽ[?>>?ѿЫj=+>&۔=x>G0Ѭz>frh>{=.l=[~?e>Z>oƿΚ=>>E3]Imv);>>yP__>>r>7e4=|FJ=MNw3V0W>U] ޾]J2a?>6Ir?49:>wI(fh]>8K! ,厾i)>b? ??|Q?(L?%??_0̿~> #>{/> *>L<켄=7>Y=gs>R]+=`?4+>B Ay>XBt%Ͻ.r)-bN>x?~ 5?r;??Iq}J4(= =.EJ vK佗&?G@>!}C``#D>\;OBU`X=8I 9RG˾*_>D3fR=+/[5YN#Al UK›?)<)J:Ҽ"գ¾=b>?Jo>0˿rUSοא?Bg >)q  #?=?2?( ?>x=???'C>)S߾hM=.t /?Nk>k7TXF? F>OӿEVox!Ύ?dz7>"}jh:5LY>>>enk'=n=@=ݜp@ Vq4 |fb5ʟ+ ,>K>b `Z^>ݺ,=]>_`>ʒ<z~>. g>3:`|T?^>Ś? ?=K2  _֕D[lbbt_HSS>!Bm=#kgaMpҳ3<_)?%$?u?SᅬI:m=顺?>R?󿱆(=a>m}>;>IUi'#=w$/k]=T\>Rns >?n?RԶ0U[>4"F>Q?My[H/3d=/>v1{o>x?#?I}=%>?0?;6#Bh? >%>LI6m,:־6>s!=T}׿|%cƟ=#-xBQ{!$> uqz<>Y.ϿHiq[u'?xd>>řEY̽?j?J?K,_Iƾx)?^??i P^>=>࿷bh0لc>cÿ8zzr4W4??6f?W2I="%?x?5}?!c@1~=>? a(.uHS1n>o,w۳L$>a`">bU󿶋va~ZmD$q.?"f>q> fy,> ^ٿS3D[#? .>%>s``+hǾ 4<ԿF&w];[> ]I3p'DԿ1$}8/U87? |0'l=6\i[YV't?4n? y?!N6Kd ?~&?T)J?T}?*>ؙܿ >h.^PI?eo?¢M?tQ+K'k?¹^?g?|8*IC=?e? ?+MOP?}?=?S&,`N=*??G?}ȿkI`=?xS?y}? ]>COƿ"EN>m=oCW?=Xy`b=|,C#T;=Ɩ`AJ>z)]ľR!B?׌jS> _?z?9H?S*(kOe=?)?{-)hә>e^>}V=H(ýɀ,?=Ͼ;>Ov@~?(8*5 w:XV>dR+A=5lE?~9;>% >iݿUx(?Ͽ~NԾe>IOS:4?/qv>?+^YWxW??6?h; 1UF, i>= <@B > Ѽ$1>D;>AB1>@O Q&4f2<\=kgZ־>^>A>m<(>b ?>u'>l l:T?'?m#O?iBJ> ? ?~?~13Mq_-=x%?Yc>?Dq>i?S?.]?ayu?Av{=a(?n>x? 6`?e?#9?[zָiӉ?z$y?5?o?u;?w?-@W?gP $v+??a2@?ؿY\!kY>?3?D?RcT&>{B?e?]? w3?{?,v?eUA\` ?:һJ$#?j>~W?g(>iYAb=迣rɸ=22M?tp3??:bh?ߤ?4?maA2> N9~])bˮnQ<³?W?ܘ?Ðc="> ?H (>.$1>gǿ4(??ew>?r.y?2g rO}?؞#?R7?˒a'??Rln?j/Uh Rl?":?7 t?AKRV;?^o?eR?bR=?>hn?44 eV:?h>`N?1h>~=c>׹9玀=𾄩Hۏ>s!I~\? >fH?G?yRk.>,>ϯ!U?Aղ1\?U?q?_( 1>V~<>kO‚=9L>dS?MŪ p>$_= Ye?!>}Ƭ>sYy=%?@>?>>LA?S/@8=@ >?/ ?J?,lۺ1>8ճ?30s/þ$^>vS=t?X R";=Cb?|L<>DF<n?!)[] V7u D=G=?=u?IeX;=鴚Q?4P /=ǒK|%є[>cNܸ,t=:T?N E{>xc>^>r?[[p/UQ,?<%ȿ-@?%PtfU@pT>o1G@U1D0>}>< ?1Di)V:>o\Z4|?d<j>[ bڽ(̿ y15J>nw ݽe)ziW粽< ^;y>/``?E9eyV>=tѿ ?l]cY x!NB=)?%[)@}J*>}q>RǾ?!>7= /ϾU >W {<֟I@>[6ﮝ?_?4h?`{$Dp#y1 @_=?=3 v&-??ir&]<]>fMYOD?O={x?<#?Xg%>]=9>2n>!c>\>>ժ?hs>G%z>>>P?Ë00]=7X=%> J?DeCaνž=":?a8uоc4??g?tG?KF ='ei>P]OG)> >?Wi?d8Ҿ:-:>>>m"??N`}< t(>3><>I6T>v>H>ʆ>];4*$>4>Ȋi,s*>L>C}U>U>fspy/==D6? !6^(.=>>M4?u*X$=A>׮>[Y?Y9`/2=̼=H=E{?26EpS۾Xξ!>? ڐVJ:=Ϛ$la?%Rͣ>!>^>KGؕLa(??NT[e,uu>=>D,Lr|=$*??=9Gwp=8Q93L0m*o=*5sC?eeVu I=S >"~I bfUB>Xp/=D*Zt%>'fV=6һ_ރ?L YL=xz= e 1`*5>`L̝̐ R= ־!24ErB?$l=B|^@Ⱦ>ʘF8?ʿD4P|~7( G~Q3 _<߾H=uݘ.IAmS>+ =O þq`=p?JFᾐ\3> >c=ж1o>q=_Ƚ>.AI:>r@iӔ =fk=K'>>];d~ؾ<8>G9*>2Κ뻈>_>$h> @{c^>r&>}?V!,e(=Ľݾ8y;!G%/ZZ=DU=)<=J,==D=ij=(& F|>> J>fiϿWt\>(}>7>Sm-h{?->>~5{'>u}> >{0 /=m@>A>n">FLf6>> E3"Xisu* V<>(>!d>H&< >K?!>Gq>VKx(i|>=ͧn;? G&`e=X=ϒ?&)ngI Vυⷻ>O`]Z2=s'!>;j\L]}>=%s]6=So~?}e>l2S1i'=a >a>V>ރ ž4 >E>2=zP` mB~1 Te=c&>.>5>79k?>>/{ й>}=E((u^7̇|p>>>m<;ζ<޽򌾌AxѤ8-.j>F>2!=tC?~Y>=m= -'F|==b?&7oѹ=6v0ӿ,ν~j37 ({|VZs=@/0`w7skcܿRUԾ*˔S>ΞfcAt>vOU@ $>*g??%{|b PY/=S7>q>> Fp3=PL(LuG} ?+b*q>p3'3,P;^Pl:Y;bJ,b Cx&N<d+ѫ)Y?)I'}$/>g2빻;\)eb>ZUi{f#>2bP()X 1MoA!\6ƾu6zN_R>AF?N??w*>[->x?z(?47;fs?Y0%ڽzq >3`X<) >جW?l0˿Hi*j>AQܿߓUC2p=o">>t>Jg>_?4߽?D=?5kEtھү??)y?  Dhl?? |B?z}tx> B>?Mq¸6@γ>s>?_ ; X(<[6&u u>~n?>G뿱b[??(?"}?{H@@!< 鼾>T.>ܓ>vm =18S?Y{E=T;=>1>?:;QP)VݼOHR"%tDY<n>==?9>>>í$(1?\?b?D,,!O ?e-?g^?I9cޖ?VT?AS>H9=e=?;_b=j9Հ€`%?>]TGԿǣ3^C+о} F?f GD\CϦ7n 9>'~EF[D怿=C-jfܾɿH^}<>uSi?;? s>ֻs=UB?j?,>H( &>tHY)>5=$L6?De0DEf?>w[?Kewwp@W=I; >"p8==#]ݿ,J>`cn8'-0CXz[=E!5!@W>2¾MU?$y?=7gH@v3Zߵ@@j<={ /2d2ѻ@3=,J2<ms;=֢2#)=@F?1>p)?l$n PE((NxTn2f>z1Q^:)>[>E8&?uKX'β>> ?H,8$>?>kRD?y1w hId>>\?‡V?!?v?P?Y8UT>i%?=%>U?w)>5>>g |NU=N4[>O۽[6ApAjϿpX>ab(X푾TE7f>n;n4>e7?C_(J=V ?F_>HŜRiH?*} ?Z>F߰ݟ> 5f@5ip=ꪟ>&Bq:=!#?L%k\>:Gٺ d^`_xlH'G[>I9P\;fO=?*<݂&J [oBJ N]eQhy=J h[T^->@ p뾞p[˿ jh6 ½ã#,X=y?YjjO|QF8\KKN$-/+ge_R&?Qr>C~x[?]>dL>=K>f>*?j>==kL?HVֿ#j|q=X73 ;s~+mF_+=c`܌ sw? aԨ<@i辐OӾ?S˫=#"ɾ>ޠU c򄾩0>tPÅ@^>٣+ѫPUz? 徺 G?x0ɾ -'*`?Gx;ct>^ @g=c0F׿2t\BLkccS3>}׽<:V)vH c>fln>̅>Gfb[pL=މ">Ԫ=ծ}~I{t=BhK<]2=;<͎>&{&gb>AC}=:m+6#lbb? ~=>`G|>%>^W>O7Kz1I?4(_=:_>W>O>G>C`>I9>]d>~tY{>O>%i>=& UKZ]_?4?c ?2]o>,?Ƃ>BK+a L>s~>ߨP>7.qžq0;|pw.>YoetܴAپT>hb$ݱ྆վ0?~9RxWX{?>I}>޾>Ƃ?El}W???/9¾>`b>`2?E>| >!\"zt>xuVľ|>غ?>V[Z`>c?k>:/=$GD>\,T(Y>C>Q>.\?R6&`(>=D<2?2%>y+8C>yyӷS;m?:d>$Ϫc5X>EAIOƈ{Q J?<<, <=_U1?뽚(/> ʿ+cF>(O=49ѿ> C 9|>" ܿGc>GwC? ??NQƑv?-D?#c ?)_P[>[4?^Z:EV=!\ؾ f"c ?#5?c?a!]x+>c>J?'E=3=G>Pr>q-|F$r`оic9BYƂɾ(m-˩Ҿ۷׈h(m>UT!ѽ pX,;"Wɿ&nDhm>% 0\F=v:<¸=i4u=)c>MJ PS=aQ>|>aQIzy-@ww".l kK08c>f???tR}AUh0{>uz5>?:?QΠ>&tZ䮾? h? 3?G{?7B,?7݇? l?:)0?Db@բ?Vx)?N?Ť>s8>>4">o?"d;оDVp?Ȩ??m?y-?vcH= qP׍p;>d>>5???\Ed>EH=X>t==HY8>H= >(V>%"MEJ>H8l U19=ӾԾi26O=@&R4xhw<-rGK|=~:N ^>*,۹>`ӾD|& 6xл>2*rC*蟿o>WO>V>{>>?n>x>V(k=ZWR c >()I9Aa> %聾rq?(H>@>D=g;>S>= >d=<.x@=g<8u,U@>4S >󿒐 } 86 >`=5d0C\=XQ s>>dW*款g>qߩߓ>>!L>e%=SϽO<l=3/=@=o>PY{=V˿ܿ`G|l[>;piw67"};-> =3= >2l3j~ k?iaQ>[^hW>>>k]D>>ʖp>g/>zr">M>݋=,L82=&xa 3`.>t<{>5@RARP? fEF>t>"EoL>[Wl=g2wgꣿ/ý$a>e[FV\?pC>1rp.Dxn? _:ZW=Qn2v?8>q翍᏿-wb?Zj=/b>\Aݿ_NSva%?CD4>:LTF ̣U?roD!2>y*j7 o@ 9?=>|c?0M?]e"%p?ھA?|EV>z +?S! @'N3>M{8?Y @+)=>Oݏ?@5>86">U?NeH`>uz?7u~w> Rh>%򾑵 ?8i :wV,E=;$?Yb7=_ٿd>%>|?@?BBȒ='=8?pT&> .iuS=>`Q?f3=ܡI?l>ҋLdk=%*=ܶ?>bo2پyY?8?c?7^ƽU>z??@>Js1>W&d?C=,?wH>?>mZ,<>C.=?>}hT统w>,,?ϖ>Wi+⿐=l<>6a(?rC>^9`qE>;p>%2ƾnv>' >]A>cῑ(ؾmS>lN/?(>5~a|$ G>R?*7>sᅦ =?Wʥ?$=$>]L? 6>NA? "u>k^?<>_a?>z࿏, >A?-q*?DrҾ$%=&8?3>RF09u>^R>>g>Zʼ>Z>@RH@1H?N߼0">ԍ>6$tPQ>~ ׻>BR;t>6FN=dssc?#.>SRD}?ۃa>%>ɽ1=`m?~k??!yʾt?]F?Gʆ?Lw>A=>?:Q>>02_-FD>1vW =^(41=5ř?OQ߾ghZJM<><? >-[ߢ>k.?Ң=[w~ț>%?9$ῨĽ?A$J>?Y>ht>nӿCXdiDi])ǽK?:3??OHP>E?;H?YH??bM=X> ?A>ʠHw =`z)?|>j."|<>k.>3=?.m?-,~ҵ>~>霿><_>pOs>\%>dbX>%b>F>=q>[ֿk=' %?mg{>aycDEa?-n>5 Kqf4n< >|>>Ǽ\h)UP S>`5>&1? |_0 nt5&@*=Gq>5?Qu?+cIb>Jo4_9~Pa ib>?Bj?3\?Na4 (>> '?>]>o[uј"G.so<>\=)P> \ =]ؿ.jIq{;G>8>>spJ>c=?CB7sh=]Ue8vվeWk>JV>d$ϟ+= >3YRLj>=>э>.juGv\[`=.ij%@Li=w ľtud( (j<.F:D4  ZFv24qR>jvk=|1ۀP),z=>e>D>u*"+R? V2?b?@-pJI>ɽ_=vDԢ@d0>O>f)R1ֿ8GgH8U;Q;u!Hi>Q>D=Gp jq=԰aȾ3"0c>4xľ3&C>\ALTT>a58־Ζ=4IV>=>]>j>KY}>>U>l>~"><>>>4e .8Q쾫>52C½=Ѿ;г jC &M5a=c>L{>/W?!i=#ub|=Rl>v`P` >ξ@f*>\bn)wմ>u,D\=;>CpP&ƚ鳍=I8>jMIF=Y>HƤ]CHo?1n.п Nir}@B=A4k3N_\< <$+4 {$=C19;pC"">EiJʂcԾu H>"ܱsK쿔D'CKj=~f?#r?j?|6U?'S?Z ?OE6->?.9?X57p>\>ѯ}?=rK?165侞\>;^ ( =UR<+w= ?;GT%4<0J,k߭>OQ@"&>]5{b/?#[?Mo?#`4W;Ho?s??ݵ2XG^Y?T?0-Z?&l05þ ?U?":? Y\>ƿƴ{3vf2;C9=:.>5d-1۝ =}>ri33}YRL>">S6Iu"!??>R?0}|>ŗݿa{.)XK>vU㿴;TWZBc5=T?Aw?a?B9AC =?$N>?ke9>,$>ƒ>lb>S%PK)? ڝ>M>Mf+Df= ?l?IC?JǨ?**k,*̿F:KC_][-[O< ҉BпC3c=yf 'ߓE=޾N]$=\>I?e?;V?EZ:&TӪ?FO?!6?nP35 ?%۩4N>\>Ƌ?[N3ٰ5ݷVQ=8>q?2Z6e>!O_G3:]>84 pH $ؾ 1e>f?(#~)@QнR>#܌? .ɠ.4=#>?;0fX1 }#S;=>"0-4]Vq H(>-Cv0儾C=9>#-?FG8oH9.\-oJ09ؾg'l=K_uy~9DƲ>]'= 0D=??@?yZI2S???HC[=ѳ? R?\?5۾T->s?U.?mY4W>#? ?y"X5bAL=i>:?6iux2OD<\> ?*$F3žk}c>NĤ?G`/r>? d?q=ڐ]>Z79>QP6v>jy>m?_b6)ϾE k>!?0? K'`!>=:2ql?;???ibB>BB?m ?q?QP7 ?:T?y$:?.IP5a2T? c?G?JV쾁P.>՝̄s>l@`t+wA>m ;>R˾3 W>,g^>,dw#>33H|=&H>?T>jFʢ1n?:?<>6&ܭ :;>+:>/#R=S:HA>GVV6*>À>4::*,=! ">;ﴁ$>Nn>j>[`9%>JW> 5>ˆVnʾƔ>f4>>D.('b=c¨a9P=[185(=B[=9I9=1$Ѿ>/׽Ѿs?B<`>X3@>f>N8cJ7k<\>*~>u>~tU>m+B?>jv6~9q?/'>#qO^~Űa1j>?z=?2?U=R\?4X>??:$ 5n>MD΢ľ=EF ?G 3 >l 'リˎ?qSÒ~5%\?(^vMY 8$S>@jr'u,>?!-?[Xyh><]1q"a!v>r|9IT <~k ?Uڿy-n>?B?q4z?ÿ7 u c>w?L8>ڷ?B^=@Z Zn>Ѿag>bbPh@?K@ 'BW36j>S3n@렾%?ߋOJ\_0W~;6> :jK=;G068O> B4˖?"#N@ gQӧ?O`>V|(nP>*_>4Ͽ>h>LY?V? 1?ιem?'??-E?Mƾj?G???y2GAT?|2?/e4?fpH=Mv:m# ʚÿ^2JV>*' )|a='mH;ZCh8-d>uղ9ml+IW?ƿ #tf^>$d??.G?cN\=r>kC?9`F .;>+?DB@YrϾo>rK>E:h>"vՈ=`<2ʾ=SᾥHC?Gw/aʄZ&r=pb?~UhPshc?+t`C?]c+e;CK?# Yom@-:>G?7lNFTw맘>m.@̝ܾ͂ )? ,ݐɾIY,<\Z?-q ?VguP>˛NPiJ5 =G?A`_;>? l?8J@ˡ =>S.?E ".^ Ѽg?`kV޽@?YM ( =0" >Z?ѱ+>t=@?l!.>b?=P:1>zzp?,E=>F<->#Bvv>4 ?GM{>*(?TM;*}L4>)>c.8>!޾n$>>x:>ynl??KT?R"L=n?RD?rG?EGtC?J>i?_T ~a[?j`? *?~"칾6> >f>g?\xĤ?A??j˾9>v>T?t ^@>š#>AB>: :f!?#h>O?.&@y>MD>>ˆ? ">h?8?"?o !CYhf>N>3? 5 >x<[7?\<`z>k=gQ;T\?(b(#>eȗ=#c?"R07=<>0?CE;;? >?a"QI{-?(_9>ۋ&?9q(>m?c?NY?J?'Y>N#>u1M?3(!@}|>>]B>xdM Xν&.کh<h^:xcrIc]&O <>oOZ=o+B=_龧]> >x?E?7 1?; C3>J>D_>?$ 6CRe.f.>ˎLwJ?A> w?7[1=4>1?Z`n|=y>ZdL{?`$b_>}> Y>_N`2"=RkN>MU1֐#\(>{T<7??3-g!>>XP=*?l4P#4>>ubk?1)Jp>IM>Pr>I?Mp>%>5E=?l .cnzInNC=ǰ-M>Jr ?FA?? t-\ +,>>Q?>J+6U7?s>+>ddbPvIp>E&8d>5=6g0%?8}}A= =ҙ;3_=?EMr+)>-4i#?^x}>|=ʿy?hHk+GIž5l??~? e ?750 ?6$5?0x>+?5YrdCm'" l?%$cVx~aXf&as3G2G_I=J kV =_BCп?=skh?1!u긿G<,ዾJCCt )oʿ+=mmA;Hdܿa " gK9Ll b ^hb>_3 ,$ǿ >t!`q,:զ=|G4?91 ^ 47O?&?J$3_CY?Ŕ?$+?JXb?a=P>_W5~1&$->ȐqO*,龴B |=>*uA# Ӓ =.>d6޾">4pTk=;[z?"D; `;ڽg?%5;'b>!v<<7#]?% , ?2!u?L?#͊-/"e+?w3?F R?o'2Ƚ?.?UP?u+4Cоy?F?[?ibhư;IJE;ɾې>%+u?O>!e=ِ>.\? ?Hm@l1j=t#!q"{z=u8f>?8ҽg?;u?N?:Wd=NWvN(>YAGo<֔;񝾜VP>;Ө6|=:#}&>n+A_ɾP?>>G?Z 0J=챉H Ri>>#>D>>63H>OG=+[,f >]2>x [=&ȾMEzp>ʒ@A?%\B?kv?'iI-B9>_>V> Ku`>V`>dk>ӥ <ϳ1l婨=$>% t=M^>O>6Ԁ>cмӄ%)<~>>(B> U#jM($>x7>~>/Rz{ז>J? ?;D:<2=k=q#Ļx?#Oa3`.R=Re>]F>?uPʌмeKIe*c>6N5i/=k{cؿ d>)?1rY>yK>4@{9>W6>?1b#*ː#'A{>>#Vl we&=$}kHᄇg>o|E*x>iIs0"X>ku=?Fozc%S\ϯS>'p̙e;ݓľAJ=̃f=ڕB34>-?GR?.A鏌y>?#VT?K@OTq/D=->iQ?E6a3aP> ?,$?H:O?ϾHy>y>)X| =ƹ>S&Gྜྷe> }>ֶD&Ӧ>6Dv0폻|O?n~S<.=i/o?;e^5>]<ʾ >JnHFTS&=V<ܐ91=),,=>*>l>u7L=I 5GtUeI C>=rtFl[=U"ЍBiO=K&9OJ}>PXC>v>`Tl>/#+[I*\>;afؾCCgYc;"7c~gTVDq=?`>=>Ͼz0S =i>`@=H/'K>&_Ġ}KE=ʼgӹ>w>'>8{C);=Am:?K>Iw>K/xYSR? %5>>Xz?-w>{>GIj>mv>A>>G[x$Jd=꽉C[ Τ@d=>bE>>‡L=&>5+>6>u7z >>=^P' ?(>ڳ>7(\)?)L>(}QU%>X> ;=|:^d%/?l>nĤ=Qտ7?Qe>8>jLbJ BsC(?0>QM=iQ[-=vN?( c0`(>>l>i'>e^=`[>>+?/??+A!f?5$>Á>$)2᷾ ?D> >/==fw-I? >v=m>2Jv%wټk-,xoF,E5mD5  $ĤC;ћb8-Ⱦ~>'u2>$?! Pr&0-^h3  N/%B.^? 't2s9\m>>?OFzx <9BBĿ[$#p154[T.q~PGc;>s?(?o?&Q7j, >>*2?3r=/6=a?) Hq޽=q1f.?'(p<|+=?,9X3g=tL8Jv>߻XN3>Y+=?DJ \}{>>u6 ?s9=?F?&5?k 9f={>,> 9?S)H.a[> -U?^#5=ѯz^߁)Tfс~Z=7jƿȵs;y='e4>v>g?GAI#$п~lX[t~J?\?Wb?8]tV]^a0<>ץ[lzơܴ>  Y j/+$F5>j x<@BA=TQ??dWX:E`=a[p?rA>*B&H~<AL=`O+@n=o7F=O|`9>^m,󙿾Օ>F\-%'p(c>̿ޭ$D)սauѾX.:>(߽j,QU韾nT>(}{c>!>>E4p*|޽?'F=҂Fk¾bzce(z>l6SҽEL>pm>>CyC>">+>.g{<6$>=>->L-J½b|'$_%U7RCJB=I> l|5 V8C&-<=!= oo>)w<e>[<>=`wF@>cǾkd>hC ?N<>W?#rX=>~=2W>ywOH;%>>+IE@WB>6=t?1`6p>=焩 AdѦ< J?.%3y=ׯd[{=㽾`>|yAQ=rX7bAҠ+xF/<;\Rk_q > >s>L;Un=hdM&t;-?/`ܔ!±>XT*AF*BvKC(߾ _\?/=Ľ N81FT.>- h>^_dKV( <=s?LrP: w`aI?y,N=o_Nk?Z}>9>m'v?"FL ->) )Έ4+Ix ƚX"`_l>8eBэ>?biAо>n> ?>O> Z\<{F yE=FCa`>獹rTo"[JZ͌*p<.,?Y|Ew`>Ծ: ?rŦrj3(Kӽh<)F>Dgo sZ:*?4zŋ> ƾ:!>b;sIk(•i$ PH&[l? b??;>e޿$>6J(>Iٿѻw1 &>Ckh^ab(=K0%wR1> =h7f>L1^=q6a[j ԉ@P=+0j0DהIJ_D=F#ѿ0Rr)V4,*焺/ɿRӽ?~ɰ>hxT<:?Y-ϗV c侽?X1p>&R`й @=qeK'$ Ǿ3 b$=߱I<6y  _>>fw>-?l|>)>wy>`R>xYC?~=K*T>,K>+%о|罝7~Q^dվ'a(9M'*t!la?Xs> >2ʾ_Ոu>[Ay=ᗿ=<6L6e~E=hϾjGm9T ~ޜƀZH@$CSy ?W!ham<.rvy>~ ;>K~:'?4L\u>I AJ2#ap !v ?,!>M `pϾ!أ>z`ꩽڿ%>-uGlٽω3uC5+=n7F>8韾?j}_ >|=>#>8m|?=BAt>^U$Ee־ |2辡>>-ahl)E;m:"/C>=2PG U$>M>0y=#%~ܿL> `x * 1۩S6}x ~K>+;Ls>gpxF@B ?5YKH |c$WѾ]K I/^W d>]yǰ>LP<'f"?)&E=/n"mK'(x1ٮ>Bپ1Ր>v!1`.<z> >^/ ,(>+lz~C.w?" ?6?o5yD>>8?t.*==?࿐@k= >K>h?ῥBw =۽?XPsW>])Ӽmض?iN=~.> dԿ>̗tVX,?f,?8;?>. [k?$?T?T|h{+>ԏh>`} } '>Y kB>9(>D@?[6]bxv>>?&Lӻ+=*]>W6H<[Sg>85_Iz;`KXkfsO>>? s\[౼!v޽y>E:>, ߿޾O%ھFd=w=,y:i Ƚj]l>'c|>Efs\>i>>Ȯu?|=%dQ>TD>Ű>?>>$c9=?%_N?G,a=ϊL>AP>2(V?E h>FV?1o3?q=?[0 =_b0>">G>? n>||==q1f?e>29>3d;9>E<>#7j>ZuS)G?S:>( 9T< hY>(>?S?(֣1B>">1=2>sq>ҿ]>ܱx>|?6t`S>(7>k>jKxD>f7>>wi>B֙o7>ڼ?_9P>O޵Z=U'D ŗ[>PǽE>%}> [P$=nO3 TlQ]=NwkʿRDJ>h7gLrgAſC{]>}2d=4YVerp= C*bP9c=9 JΒLz^,ͼ'KҾR3t_u#`o<}k=>B\3r?<-+>=}_>=T>i4Gz?KZK¾Kg\eM/>H}'1Y]zl=s, %O>dZ`+ؾ|Cc>CL>k8bt@}(oa=IoUi&et>ZykuCY[T\$5=[)̾QB>'r?y#>տ9\?T&>OwXտWB?? 9>j>!!X=u{F_uCk>6U\_6%`Ӵ>w/>#l5CkL.eGBf><0Y>^,/轫п?xU>Qd*gzɾU?XHR>_@;K>VWS>V!mvr>>; >KGо*auw=}"JI!ÿ8>!3>rF9>|] >_>ŵ>yf`I>9J޾1Sl ,>.큿kN ?QV>yO־jt:[%p~\ _==<"+9smTOi=3UII=>У/>}x+^ ==k3>} 1[l?!kAJ>;.ZA'BB>qr>WE<%>Ц>욾4]?`F>(￈ӮDؿj@Di> W??d(Jf? [[>X>a̾ٺ>Æ ;>Ub?H=C?&vT>MݻB?7=k!>>?w>I>]?d?R?3g2< ?6s?$?S9<ȡ?T?,~>qm>Q?|ԙ? ^ܩH=Y>3?*>>,=S>?b>?cBm>)>xI?>x?.[>$u潱w?|= ==|r>O<={?~>/*?3p>+>U??a>vMy">Au>c?Ê>^.L>^0>w6?y>/<'>(F>y ?@:>ˊ~A>?:`t>?Ϣ>w A*=>q&?l>=A>/?]O? ;]\>@>>%?Ƥf=%>u?-j? #ľ*cr&>=?>+3Y<܇U?7=o=S,L>Ց?I!? q '>_?6>am@>?>࿍{Vu4K+>_=s?14>3,1Y>#ɽjj@Ȑ?׼?> GÅ\9m>ȓEA>K; >?S >8lz>=ҏ?:>k>>N=ag#?j>>Z#d>=?!>jĘ?9|Ῐh5?I??h 𿿠g4G??7&9?=0N=sҾex`?y|>> L4>=+oS?}w>s-<ŇI>Ǔy*=5>&F>'M>:6C=KA>b=l> Wb?9X(?=(R?pCt>w WfǾ>?&w̫28W ->J3?BQ/_$=w^?e<޾T\uk>:vپVT?Y!ރAT?`>3 ?qT{ῂR1g> >? su*Y>j 8caQ𿛶D7>TU"12Gz=Vx !]pGX`>5>?g?OT@dY?K?)]?BҪT>>=Y?><`XX>C>h>WIE>oP>>"grc> #->Z>43f>bx>>.>F>L.BǠ׾V&3)>E>>vw>/:6,>Z`>>[u >,>=&+>IZAS? >53-> pv+>ٺ>S?&b> `=ṿ˿L}RiY tq> ?!?[?.\>1>9!=Ñ>_``!>>A>hc=Ԅ׿֌=/>ރ^> 1>4 y#>)hw>> ,u>qˎ>Ŭ<@׊N> <}ȼ½i`=Fy̾=>3b=ZY\%:v!>gA>"/@%'+=p=>1pͿ>>W? |^ >>V?>RH*ྱ>@>>. &߾=07Ё<о/=n'[wBܾ̎>[>>\?si=5L? ,? 2w>Eq>$XG>q Y-y Z =A< =t=GIj FA 9>RNC$>c9=Yk<!IgE>iՀJ>*{? T?!qL?Dc`HM=ı%0="厽߿(}c.\= >,-k=%>%i+O3/:.wz5 g>=[>=@;\2<<4$_=#:=ax=H! ">7/J>>Ra>qs'۱>Q>P'K>y[,>>0bA?>3n>>>47 9%>> >7?> yG>9_9=Y28s|/>6%[pᵿ8>,@ѾU=!E>5ea ^ǗF=_=}^g>!D_S" S7m>ObꟾX AA=:>A/r>5[?(W?2?n&!>7?&?̒?Ruq'*J ,=|>l+3<Ⱦ;=S?js$pξ]@e=>{О"+¾\l޾A>;< u"{p>F Ӭ9"/ J&?>{ӿߨ@$Y<>{FqGěumC|>MLwA#P2xl $/V@Mw>k¾dܾ>,W?X>>> ?L5l6>=NM>`S]?B@ =gA2`Կ́׾ 6>0?e)?J/?Q9Cvy6=g?jv?OY?U/ _!kf1Z2r=̊>JH;ɾPv}>)0*{D>c?#꼞svLbX<]=ib8[B>n>>`)A\? 2>wϿ$ r?4/B (> vѿŧʿKlP;;@?Xb?]M>?IvL "y=!ap=ٺ?y?Yy0IV@?Lߜ?1?97b %?k@?N])?SEd-gGؾ^<- AҾ ? ?@?9-4(O?d?H?,M}ap?&??sGZ?G??f#iI2n =>t4 'g;>- >00>L ?/W.?`?[.4 I=~d?v9`?f?Mt,,q>,> >@)?@m`,F>>?7?tc~)'>t??Ux?eK>X=?/w?P?,t}5;>P'?&J?Q018> {?)`?h?X(:=P?)f?u? {75l2>?>`0lI<R&>H?" - 06? Jb< !iDKkxVk3_=q.ǿ>CV>˿T䤿8%}TX>0mPl~9APp(>S$B$3>,>>QƏ>]|8GR>p?pq?Df?ROt"3:辕3QY=n>ozA0,0= w >,n^m">z?1?10*->|?_ ?>b-IC<^3'Z0).׮>D63>G=F{=KC 2(>n>z> >\4L>?0?RS-NiM'>?:?~ NPΉݾ[ ľ8>P˓վ#{Ⱦi>cc71޾4>ln?$ل?G`5+S l7>.'?Z%f/$=X?gP7|<#>f~4S1˶g>a?#t%P47G>z_>?|i5bE|>M?p??vs >RL>N@V >VzF?$<+`kd^>(,J*=Y6JPhY>%$>X?Xb87o??TA?3GQLu>=6S?;=?s~ͪ>RĠʰY>&kǾF>*lJ>=ԩ?|?_?<hk@>M@?|W?A?t!B=5?НA??4h6>Nj?[?vLQ7ž^?E??r>4&fe鎽5+5n>Q!R~O>;`j>E.B?gUؐ=,?B?v?&J63?%.>4"? Ot~Zi >\Q?l ?(?GMb`>P??H?i \g>}?5?:=O?\ O@ٿ.D3~={mݿimS&Qz;:I"Q03 gl>a?~?8b?\6e$)a>q??R1Q?t'|io>K?e!?"?F?i>eΗ>?>weE>R*sD >@?6>1?LN| =0?(`>ȁ=? uy(3 ?m?"k?V ~7Ϣ?>{>?.趾Q???΅?t; ⮾8 ?0 9V˾\Dj l_PZX._|6;>52%.D>Y<z>@B?WGݒ;>V |?]>-f>Q}^J?ԃa/*k>4'%BFr2۾C?.?AG >N >n?Je|>3'L@^?({`:?|?4-?kc(DJZdMG=W7w8@SH^4>2Z,Q4<, >>*~>+ܿCt=?X1>5ƿ&M =M?-_xu> l>o'>% ??#;?Uɿ 6vN>?,>a?(3#s`(>?->u?+ =W=2>B=>Hz>b<>Ën">}_3e;=?E>? Ut_hw%?s?,}?c(cH%qDп(`N>w&Aqҿ$M>h/zH9?4#k>?I+>Ī&޿/>?u| /w?HO>Yq?;. &̾i1֌?=/ $YS4}C->pã4뚿,>vNHPN,[玾k?%\/U"=A>x'4茂ͧj?&b0'*RԷ>RTJ' OӾ$BoA?$vzp0tae`m?/WXU]Fп=>0j1#I}?0R A8 1?Sb!< >1>?Zֆ)o ?>ڽLQ'PAZ T#?FCsV;?kMξ >oH>Q?{>"?>-?,xٿ =}=.>S=•!>=24 5;׌C>;f->·㼱̖?(>3?*x-;*dR?N? ?\J8;0ƈ>>P?ln&ŀ+==`?}% |@0Wi=u>+?$p %}>>Q?$Nv =ܩ=T?n0&<>>Ï?lؙQ^>w>W0>yʾ>]>q=u?ro Bl?'|?A?C5{ʾ]?>l?Oozs>>O0>)g>\?+X?v?/Ӏp=  ;>տjI>7Կ 9>}>fR)k>V>N>v>X?C߱\>A?<?*?n0@Bȍ=]:(>Qri?8'>><>?z]:zYH3鼺긿8io۽tdC/"L=7x]p8n6a!>;^^:xx>[O _>Be?n\?az? R >\0?@?-?8&k?{ h٥,?$>Wn= \u.?@u?@XI>'>0>̟?w5>^q>2a?w7+>A%>b槽qa?\~ZL ֿ>>Xm>N/Vg>XS~>2t="W?YV~>Dr>k~9??Aɼ>="jf?8Q?UO>'>f,=&?L:>XW~o?M&D[꾔bSNzYkcNHw{Nlpo2p>YT~g\=Yڝ߿Sؽ'7>u>Z>uX?l N">q~>p)~?iW'>>MP?!z>H>,Js?ڭcT>[W> ?˸wY=T?>V> >VucՀ=8>>6 >}Tc'.Zsi>6`NN<ݿ"ٝ*`>9`ٴHV+L#SC?'NU3 t+?jb$M;>N?"2t?#O^> WcD=?-wy0J>D>>]?fw[F=?lHe??%>=ُX>Ľ?^?VL1\=> (?W8?z!TbVum] M> ,bhB޿ v)>N^`pou:$dB=XMo[h&c ;HWjsfþ/?=g]侎U\O}ȿw/]/ 7=.hv\o?2i<=B<?44,;G}??>Mw>- O 2%f>~Xbx4I x F45۱U7>WQ\=҄>H>ڲ>+[C=2b>>1>|K<8>>97>>ޤ*;>.M>? ^?IZ?(>ҹ>p??:>Om0U>>^k>>u.8s?,? $l?$+u>->ׄ<ʾQ?վa}&>=+%V?$俉=%>Ev)>̨;> ? V({=>^ñR>M>z>T>W>511;IW?uR>JG*>2vdOn=Tt<^5RK&о?Z2??$V:>V??Z OY>=#>b+=P&=J4?k/??-?Iw%!/>8>?k.,/<8> $>_>BC_  T>J?I3n_>LZ͟?8wc 2?[>?1I?_1vDA̽=N 29j4t=JB>'E?ٯvU>D]?kH=Ծ2=%?!z>(G8-?E>~>=SC?)鵅&>>s>g~:_>>tBB>Fvi'=ON½ǽe`=.eC>*?\ʒl޾:`?>̟?ho3#>e>?rfɽ>fEb>C>u>Z5b=Re͕~,;JAqн>YCtsG;UrqW=> >2c> T7!@>>͚>oj=F̾'S>=C1>V>S;T>E0>VڈCCNa۾ vtb=)(``.7?& }=E?>z> 5S0>z)=VŻ@S̽^Z%jP=:N{};Ҁkȿ")=RF<= +u %>m?W<~gt>}^(=ZK>9I<OH?^f>=:Y? rWU@?<(i@yr>R:c+kҚ⾰>o@cxݾlH4 9> eox0`neɂcazSa`ʛ.;en뼰3D_ͽKse%{l,> h=gU:+a=smi5=,=>go>g>j>׿;J>N˸? ? 4?:0f.a`R*]⵾&F#u䧵8R?k3Ë'1n d?>>,Jd^1VsKo2xRʾe|P'RX>d G<5S&\m:`ylwCؿmL~m4+8&(ս GE~[x=͸5AzKP`w< @ 3so> MeoJ'x e P?j>jR==3AvѨ> TJ쾲d>m80'依T3>ZW>9C?Q5T,==&=0?EN:npvŽ>'88ֽ:4%D羂tn:=շ(X¾8Ce֡>D>\?>LJ`@=o%&=?o:03_B?:? $?z*> a5?W>4t!K>V&?TI$o(@uKȤI Ⱦ$̾r>x )dʥ@Ӟí>} |! =?m <7Mqd~$>mL>s>k'=>h>`5>w)mk=???[>xS=r=⋱ >#?Ҥ$b[[>/=om?|$e5"n?k'??3j\wH59="> k>?H"P;i}\k @Z%jϾH4>(R=3r©&[!֞Vh%>?5*rIV>Ϸ=?~G4:7_>>yO?2.ZXţ<1̖DTzY4u=很55a>Xeɾu?>?f-Ԩΰ;;nֿq* Pt=@=a=80~y&=#1?qC?>"j}P=k=U|5>OOX0>ዿ 5p.>8H/7~RB4=f K+9wJ{ϾI>>>">b8t=>{>G|>/) P\P@WX>@J5ެɽlH?p~b=m=m&׾A>ofP=>=q"= ?$0uȬ"}[W1&cQ=xi#ӿ꾋ԍqB|=6|оT%t;F忤3h7>q&ıfv4[>B|>=(8PCu>33PϹ|:>=ͬ!P*Z\Qֿ'ݭI)]z뫾^?? L>Ξ6H"c$7? >oT޼T7u%,>~p;8#tIAۿGS=qe};>e>9>{D~/S&?_?4>֝ssnw`>>K>WPaOL6v>l">e=پsU$ɽèoi?^/M,8>9>J`=2M9=$$DG!d>.޼μ3¾3{%7? F=?/b>WxEvR72Ptپ(!!p^N=o+lzCp^1i=oأ/g |Y '>>{>4>?}[?K>;d=e>g>H2߿b=Ay= x@dP>C|l>";"*K?@hB>xbh=Z = ֮#t?7wU>֕+>Z%^ {Pl^1Ӿ#y Vоҿh+C$B>n>B?m"xC%\?HG%mD=j}_о`1?d*(4GL=jre|ۓ>IV-G(==yI^?PǛ{=c#ϖ#6jY-}cO>>vز>U=G?? xZ־>.(O~[1G90>%Ψos2ĔO\abx>ę(>==@< [?bH&Q= ] ?, rW>8? ?8(0:?3؈w", EKA}C>S@u O^>UCt6\=K=H>*sdeOʼei{j#?Ⱦ >o3xɏ3n)t>+Vu>S >f磾i?!尿Wo>ؾL վ@N?)Kmwp281j?A =|>J>ӈd=g#X"P(,=aH),,%SL>1,==H >>f?c-knO9>>)>2>n8ڭ y>1yЍTЩ߾>e͂0V 5{V*? |J֕l$q>TG̀~SֿOnP|cnw'ÛǾ>Ĩ,RHg7ߏh?[>?P@e=)tſ!;\>u>v{<%,#B$>Ln?{h=Kag@>8Ko(M)1>(n~*rDO==la? ҰBi5>d>z?=̲sI=<.w? >zy)=ڿ">+v>>$N.*þi?F޹=>:=KB|FVˆ J?I?9Dg?7o N>x g?-CNw->>*þϥ>Ggڹ0%n> Hw%EƼ]a;G ʿ4.6*>qF.!!B>91ݽnͿ,E>d=9(̾=[a>l#!sVHA==>u7ΫSkMHEq<0`+4>gҿ"{>Oq,>Ħʾ,{>Y'<.*,4;O>|2`iw?|?|?4 a]?ı?.?,@ʾ=oX}>x2v>?M5p*>s>>X%4|,ҽܒX==7a_1=V}x^`uX?@?9?K6]`>ɽK=ڣ=Ǘ?*?BF>Az><>ӟ3~x =P遾xZPu{FҾEq=A>۽=5ؾ_Gn>UkAM Z @TҠƛ0=<ˁsG/>>תHԖ3>s>>"!GPx23w@[)sv>`˻ ̽=؁[=23uV)Խv:=>'J>KZyjjRn >νɟ㫤=B$LXl,z>>M! >9wB> L¿2Q8>f@|=/KlKE=Ka>ğtfk>> U=#?p>>1>Ul>`D>>xg'6ü޽Rٌ=>ƒ>= =.G=)k=EV>STes>eHi4>mZ9"(>lj=B&-V>s=O> >k;-i=#vF`徻J>2+\=,(ܽ߳?ڃ>bӺ#>2(L>j]ebP0 hƠo0eu>~ 0ھ~}V/8o}ž0s޾|R>%=0b;%/'='&UXÏ= iϾоdI={оC J,S=TKg "l~9.>xս<޼E?xl1><>eG=|ο*}~>eRʆ#[h?rgA>^=NN,n ?劾>XxΖs: ?bI=ʀ>*!x >%ni`(>4PdN<)W\9>˿?оRBw>C@ V6>HǿxG=.}]j8 x> ޿s6/J>΃ߏ뾍c$Q5Ԅ=x#?FvBF">߿7a}(9?OT>,8[V@`b?:MwK>:XZ;X=>5T>|'Pu> Q!?|Ao? K=v?)>;?C}R?1;vH?wM8=u?\Rx>\jr?7Z`?ePDi>U־!/ ?Z_h?h0>>c?t>M?ܕ}t >%p=fI?o>?o?BP>2?u?J7>[Ⱦ]?*\^#l?~v9 >Y}&1?QإD~J?}^>'=bE?mY>#?\>y7e?D/.>˼ @?KM?3m>BX F?!?>I >Mm=0Y>Үm>?_>-5>"?EJ?#?9>{g3>X=ő?>i6?j?4?6!S>UX>L?>K~);G >m+?>_a6a>l8>عV>b*8$q=܉n>?>^ _3f=M>z>k]F=)zZ-=Ȯ=?O>Q7mvk@菉N>H?#>@MȂ>h?A>poig==\>}Q>9.~8OkizгfFa5==+k?^S>o 1$]p?E=C?j?az>>>$Li@ >cdU"?~yj>l>hD#>l>`.ϼO{?$N>6=p=h>?.IW>_+?;L⋿|:>%?t5cM>nz觽 SvJ-t?>hCEa?*$Wѿ 6>̿ "?`Nǰ=oZ=6?L??$ cd.M=kyH({>yĿ=h="=>,NpÅ> @y=;g?}>L5z=ZW=Ì=wb>6L?J/1? V*>'?4ɸSc=G>?Ac>4ռː!>8.=>4@~m>>z[>Z>Q !>!V>K>f>>Z>,Ah>ؒ%]>D$>4@p>__>:>D?Ky>Ű|=ﳷ?\{ֶ> Uq=׳=A>Z>M>0b\տr>%_>坻>>B`=??? KyPiD>$>˫? $Bl>>??7~a<=bпy?k6=Ro&?g-> ]Is%\3-g>@S>2H>|3 %>tT>j>$ uFӾ[>?>;!>~~(+ FZy><>ãg#' >̻=>H>|j=R*=z>}YJ]=Q+y=,=G ?4[h=ӪH$?D^G=u,R.^ƨKU>!=y>>GSL q`˽Vs>C ?8\{=q{hC^հi%?L\< t2D?YeU>Jܿmۆ l?j^J>*3j'>}ʎ?]sk>_E&^:?efj>:M+=j/0 Ǿ^=R=><4H>P{>{(>/"}>bf Y>> fӾ{=ÐC>EB ڃ )4j>f>WABb=:{= >AZۼb@="=ޏO߾)ZKm;>(fFkf̿ SEb`= dEdG=>HW;)N>R/-@=[6=>Q*Dw9> . =2{>|.` U>8=T>sv޾ ni5POVb՝\=s>a 5wE*>?kl?Q?[^0M[=ʵ>iwd' ^ҾNa> 0 t!޽6>!ľ2˧MMc(1sMU ľ8ǟW=CFP$p>7 Ek$8<* ?I`1?/:G?;0?\ '<L/4B>Ɛ9π=X6=g>#Ѿ *h=?i8={9?2S>[Z!i{Jc?S>}:zc*">?"?Y?DZ '>-\>ȴ>?Xpf 03+XI;=Rg+XS;G_ڽdp?0?3?K#?4az-=>? ?>>9 />`?w>i>X='16?ć?ij?6*W4_l8?x?XE?`#B[U% >S=>~?(K>?ܾ@>|>~d$c=gt*e=,}ƣ:LGʿ/@> ʮ!hUټw>J~a H|ybY>+>з6^̿(oes>,>⻈=ڿ1<зܞ>XD,>ۙN? >֣>F&3R>E?D?l?*q4t7m?(Y?g?B);>?j?jw? \4(;?;0?xӮ?sS44U>'?4{?Wiz('c>@Y?3s'=,𾒽.ij>W.;_R=~? EDCY>N09+:6v=! =ᒧ2­e=$KI>Ũ p.>G0Bs=N?i?BF?]l7&p?j2!YɊ*͟& v!>U*1$XiDŽcb 9= 5o>BZ{>v7ny#_R8(1=1@??R ?hZ/r3}?(-{>n?;G8Oξͯ?*>"?\d=U ?*?bo/?{c,r6&s9>>b?v\T>.ؿ0\h=¿&">¹h4>>+>L=-0C[,V?ܭ?xr?j?|$>7߽?>i> 6;I>?,?2rngd>A2/?34e3x=߇f>?/{h17>jDA>D5?z.MV=z _>К> ? -b`2K*>"D>hn?l0w_d/>o-zӾ4">}0 }6۾}>`x3z>!j@2HD<b? J5Fj6N>?u-@1U ==j>?ZbP2;=DchG}ɂ >&!u1]v0f>i^>$?!d0Ƒ=>?eʖg@aJ\AINɿ/+:=s#1ԼSj;X^s+ O>' *ѿ-U >0WʵPmſ0]t>=y:=|?cp?!?Kh{:=.?J+? ?5i[8w~?:>O{? 3)Ȉg?p?0?eaNs?ux?02?e ,;iVK`ݾ Fc>6yOd?>S?X{?) .ܳ_?Rn-\<2;u?TG,[p L->ܨ(?&ÿ%զ>{B *Xο'Ŝ >)_K=y>T ,ȾÿҾ&>Yq)=_K?DC@ 6ٽ%X}Կ:h>1E`an;9$>|! qTk^BM?, e>!03rX=Ihnzq?*,?b(+$s|F?D ['=y+Gn>Z 2P󕾓? L[߃!݄oįO?{rz#>`ƒ>8.4;>(Jro3?'s>N?jDj^8?V!??OG^*J?`?$MD?Z/ ;P?*?T*?غ`%Sn~]Q} )oP1B wO>__ܥ$ ?#mj g*g8X6?ܕ׽ʾD >=L?/S>?*>;V(I>U&mNF)R?`U2? ?ZQŨ+"Moz?U.!+D? NspC!_諾䰾?'(q녥? CNTS~(1p>X[\m !?tJ%@==,6ӿ>މD5 <Ծ2aI?8TZY>!>?ʿ >DÿOU\587!>-FcI=(aF=>so4=\5N\˽݇ H?>d?'$>V+&r[(t?:l>*Z?C* 2p<ޘ?5>EZ?KOU>w^>J{>Ȱ??`[-I=?Z? MU?^*=~F?A ? ?F=?b>-?~ btSq?9z?v?A^h{ J?D>ɲ?!J^F;6r?3>?!Y|?$_[!Լ ?)?p?|>ʻ>ƌi??G'v>>Cx"Y\?Qyl>^ W>jQQXg1M?lݼ'?(D>?,(P O=[?k?eK'?(5#fý??? 3?@]PR̷-,?Gǿk4PDSJսqbZMo=2n|K#A* 7Ŝ`_@;)A@ &>'>?b=?l87 ~?"~R|hI=*kH,VA aMIN޿˽n=Dc>?c=Бhr>ں>!?`㰿ڿ7>49M!7?0 >$y? YŎTk>:K@.>jɾ?s˲@ŽRDK]Fcþ̊S`8>S!@ =>3zנ,>BZ.O5/=- ="=>|>6>rԑ=vr,>=5=Ϸ>`P=㾱8ȬJZ>L@J =Y>zJd=57>n$5>[`?x@nIw=,>耶?W?j>,qa>1F=ZT?=q3>1:.ȟtȾAM8>qB>v>l+ړ)?,&P>>D=?Swhj>K>z:2?I[Hķ m>\>z?W+ [9L? #l??2R_þUU?>ˣ>Օ> %P$@=][>0> ?<(Jb>:Wdz>>h?H<>Z>nn> ?`+}?e??pYz _>dž2>ib2y;3ṿ -> Jځ=CMd>^͎ʄX\=7_PƒB>R;6Pľ"Sy)>+sPߋ!lH=yM-=>7ibg> ?VePVyzY=ZOAm8%$<&JX=>f:(ƀ%?=t.<&]?VԠ>/H>g>t?P(#p%=&N1Ͻ+? *=/Jܽ{Rs>|R4=FaD&>.]>|/p=ۘB>z>a>ʼߏGe^>y̽Ì>ݡ>ffy>.&=@l5?3?3wd>/2>5=>h>+?#%8T&>|>/>cZ>ɑ8r<Tž{>z V`G ٔ!=zpX9X] >m%c@lMΉ yJ=c>35=.iِ;Ǿ4&>~ECc+4/Ŀ{lŨv{r>>^i>EWX97YDs=3uCC㽻'EQe}`G==H >90-̾:S3>T~C7<3U=ik`TU=Z[޾0N>rO*XCU=~Aڕ=@2*}E:N>B=T6?kĻ wTi}^?$T>/>Y?3,s?+6?+S3Mr?w>>[ud? q>ܾ>9H> >1:B<=L>SZ I/fYzRoc=a=,R?5Z?)Z? >B>9e=41?;<>E>0q>TtAP AS-U ='f<{(:뽣Dq\_=-0e<5վ7

rȘZj=7&+l>F?+>|>GIQOn(c?z>V >`9CN*~ta@=(1 |#}1x=xu0']h= hf>/~? D?I>1Q$1C>?=MPjw<<>D>q|-/Gr=U\Sdi Mڷ(0 䊿0>2iX#=a\>l=.%>d?Ku kԦ={>> (?j0eH3$_ >b>тE?_א XH= `=K\<_l`-HHj5wt'*^=f%c,ۡz΅>#Nb{BXg>F&h¿0[h*^>>9 ;aO2$j׾ym?Si>>4e@XG2S?K{>cs>pXLXk5>>G=9ዾKאD,>y 4qC g >90o=Z>w=t?Q| z纈z:>q> 3۾>Sο‘}|Y>#>\>l#" ܲ콤w? Ȃ>lF=[ ެ==Ál ?("a)ἒ=2ȷ?72$20?a ?>z!iքj?+8>h>E5N?3+>>*!9ru4?],>P>qSC}?$,=$auV i{[n?!V 3=/? t?!(?>LG!2@>|>۾f?*E?sc U ni;E+*R>P 英%eT>_=A{>i҆ I>F|;`Ǿ,m>׿N 4=`Xx~>D81~->x>a>H$?FD=ӒZڿvlP3*<]"t,q"uھu)?50j?2oP?]tSu-U\>r+>\=»fV8=Շ׾j(>s3o->k (<ʯ?*@911>Lxd/k>r:/>mbԾV={MY;إNÇd9oD ȝ>?~ˈ+֧&DXqb>ܩ>+V=;uH!\￾c z~LG+#j{){1? wwF@pv<{ep?$oC; L?q:^,nY0@5uԙ<Vo,ʵĿP'Rn諽>-[ ]`ODyھ>>:>?JvԿLX=Ź6!:QJt(cz@9h %㾡L_6z<o> xmKBFi'zAQ3?>Ɠ>V>$>wP$k>{_3>[D) U)yF=x zu>c>I-|\j8?!zx?-?{,Ew{=)v>F |< B>.-|*̾C>JD=:h׾5V=@>=>ꖾ#_>%3b_>*̾ 0xB=磿>u>詽> I(>>N2 _-p0{k>K7mʿ?gM>B<4K >zob=>  ݵ r&彵E:\\:>> ]<77*a4 SrD7>DSҿy> P"pRD> _'??F?E?VežVX=#==%cohuoJ4 vG. )zp>'>/mv>@ ɲӻprҾ")k hq\D١j6>/>[?GT@>0? ?d D<?:R>"=?ؽ.o?9@#>Er?b4n7=>r==x>\K>?j?!?X7>Mζ[Wx=ȊH<#>!(M/>}t8;;a><>Ŕ?$-U=Z,ԾSQ?C7>AF?%?enzM>cľu>ut1V,k`:˽+__;# ?I=|:M k=h>+?kx9:y}G/􋨽?:^/V=Gÿz(ݿuuɟ=;~ܱZ b}==q@~W#,=_JkAWi"<<N<(@c^; ɾ +>:g_;KnN[lO|3/E>`Ϟ>|?qK!+/>iU.>wp?cVe1wS> >?ޜ`88?>&5>VT?oq>c>AU%y=,I}-A>$<،=elX@5 j>$%뒽þa~ O~v?l^_ti4? w4,fٛ{1>r=ۆ!퍿G*_s\n=$_Կ4>I\Y0k8YdIV2~m8>tȴ[=rmRh$>0cB''p> ?`I94>%>Bx?a8==@?fw-lE>>?@햾iSXrz?0As=v.U>ɣj޲%:l>u+N? W>v!(mr{?T;>? S7=^J8='?g@-ݔS\SEvh@UuCҽwd"SۃɗE^ @OPRںɾ/"j0v Elս>n+mpz>->?;KVD*&(RtX>k;h;>W>k??G? 2>D&rM>oXQh! 'fϮL` 5,lL6LF1M$[O% Կ80; ?5~y>!j?&?Lm>MFRm?06ŧL=J#lf=%QIS $bmԄ>>~h^?b'Jp Yc5L+>LA Ș>/#xH (&#>42 KG6F\8UdhF $5idI fM=mϩA%QeZﮛ`AEk%bk'+ J8҄>XB;#WOn?''Y˾{<>˿>ƿj -=N<푼?f ܄0m=03|?E&A弟W ľؕ'Xm!:qB=7?X ̴>-<;% F7|\=Cľc^>-r|=u>=\>\>OPT? K!E?b憾=Sb'=NU^þ9?8W!g.<ʊ9>л@r t>l"^Q 2?,?-k?ͫu]_kL=ꕅ>?C^ a>ʹ>Ԭ?Jsy9x=w;3"S[@M<<$>Ӡ5c彤Z!S8>,*ͽAr&jcʂ{-,!3!r 67=>\:>>W3L>VBs>48=![^W2ɻϿ!hQA7],^8:(‹YqD*RĖHn}߻QU[ =`Q=/`jӾ>h|_=#3aS?@>&S7WֿLHj]_D7go+=}۽ޤح>E>?>| VֽMt=>&f ^U>Ye/=9TzwQ k(Q+#;ܿ4*bu5DԾ8b0ʼ(J=8QWX{~?!?*NjM꾍 >>΀9?.5ki+>#Mjn>C*3@_>=y>4=kZ0>:X>Bݾةz(j+$*o>îw8Go'P,*%[US!y` RN+~7upb>=S>XK.>!>-N -7{@u>am$m=5꽍@=W' ?8>(x;վ >,Fa=%оYG=<Ц8\Y]>n,W#Y\B埿ɣ=>b$Q=p>gA%>. >>I>DU"'=zپLf cRr=ak ߨpBj>ab<[WH >K#ڗ]>O==)lК>uKi>k&Ζ澞 h?O/I>VX=LƂ>]At=!?I72r>Cp=Z8Pb =,e=l[?b}t>Q7.8 lz?LXy>|x#B>N?iF*=73Nb?e=q"w`ᾉXc >|B6;Zr>1, 7P-:ſ8q>DÌT<\ھ h>+ >Dkҿ W~o6;>컀O>쾊ژ<#@ A=?0b=?Q>g;C><'>6?,o>> B<C>>?6F|>>fC<=y}?>c?/s=>,0?>[?A@H$>?>8?? -O<c>?H{?+>&>B>}=Cr]뽙q]ȿ>!=,Ž8=r=B' Z9';pAF*=0?A>VL0=>5[?Q ԾRs=TCN>?c?ޜYf>I)>u?b)>g؈?Q>(i@>M>,ǂ>}?`)E>xz?vX >؄K@="B>>ɿ{>/@>Cxs> E>W>*>gJp.$L⏾QOD1@F-L4?? ??Ȱ5_>f>g>9_ڴi4HqF?r?t ?v? z5?/(XW?-??n=`k=O]>Qi??l3>.p?F?aF?%_p;0?ײ??Ĥɀy? ?@t?-ܶO? ? K?B37>+>;?#M?:P 5c>@EнS,u>? >ǢC>)d>~Bu==>گ;j|=͋>m> @_Զ*=:>Y#xBnU;a=c?5E?$p?;9T+Bzc???&Yѿjʿ8G=k???&q,"? j??5Nh4l۽ >֥>R>B$Uܿ龋E>>/?(`tǗ=o>.>Z@ >V>#=˥>?K %L1=MS>O>;A=ÜF=%տ"?#c?B?1Y?^]bR=Lز׽BG>.>H>%p H˾(񑽒RHNW>N  "[> Q_#D=.e }&)Sfk=n=3??Z\ =zcZG*L>m?<ս HMTQ 8>e> hmP>>ρ>0!ݠ>n9q)2=L&>(%[*?y>QX23B>KI߽d?Smefk>߾!j)=vl?p_[>0 v=?>t? T=>#>>>;>Z>C|>`@Ju>Rk>#>k+Aׄӻ^ݿջoT.`E?O==xrd>lƂL#U73 =l2D}f~yp>ck=#A%b쯿GEf>TO?"? ?O>YA?,C??&9.W<L>h=K<п@$<s>&?-?/o?#%r[f>Iw>ɠ>">gL`\v%L=>sd|C!=}=?h5?N?[?B,`\; g>.\ >!aPLS=T>N@ V׾_KH^> y> GQ\=!>:jDs](w?B?)/?2BUI?$z? >?y{vSU~?.S??$TG@ >;6=>/?- 3R*>U`̑?"?m󾧢'>yW~0Qީ{A:a&,<'.j `>cV{p%XO>Nj>{?9?ȟDC>=S>\}?=GS Ҿ%F=mZ%O'F|>T??>G|=Govħ6ꚾ p? ?{?c~?[,=@??M?D`,a=> >8>s>鿦R&(s>f>d>w?>_ Le=M⹾i=AE=ݵ@|R 3=i+㤾M.>t.;-*۾& .>^f $ Ҿ|QmN=d>*^W h=yg>A?&AKEE=t>?95Z>RK>Db?3Qy_H\ĿO8- S3>m?/1Ơ0m2=2>:G?'Mh0n=`=a>?$vA(wB=A7>&FT-c=t%պԾ>>CptӴ!:r">p0mο2? A.=%??ru?Fsq?_CcM/T?)->S??4F8P>?S?7Ŭ?.x +5= x>o?Or`>qwtiNM#Rl >I[yqc|] >y\Q W:uܩ3t _>=>EL<)/~9+>ش>~ >6پ}?M?:?rfh`'=#3=-? Ne?%/>4i"G>"tp,(tC=='k?<[=KhI|5jy5?:v7`pm:>>;@p>u`.^:c(@:?fO$O+A%WQ\hs0J#_Eؾݲվu;/yBÄ$& p-]}ϒK,?ľl"%5 þ>=??9o-$鯾}/0>g*.ݾ@U<}? >Wꚠ;jl+ >2,(>>]-EyM@84$ľ?=0=?T2V=>}d=%'T"7AF=G@;A3r110>30 =ش|h82eU|N>A8>?YG` )~ ԪZ\z>Yuf{*zuu>W?'^$ @>/7ӽs޿ƾ0{Y=Ncyi¿]\`̿?Xz>]?`;?i??!{D彮}?0>?e=I)Լ?|pe?C?^Uf<\>¾Ar&>>%$}>v.\iȶؾI>Mƿ^>&I ?k?*q?Mѳ1/꾧`[=?;ҀƹcC(#V.=` !êؿ#Q>$|,2 A/>akx1yO+??1#?F[#>)?:>k'?!Mr@cB8l 1Y>P$wl7Qɴ] 駽KM1NJ>9;"b ֿ!u>`WBvx&T7=O0:6=V9R=78]P=౿>sq>\`> iΎ5O>.;Z/d>?,>P+?NC>yc]>t?`?!֝?F<#dj>n2?UH?B|?;r> ?9>h?6?<ʂE=޳.ŏO=Б?= -U>Q sC5/?PBt?Ӏ?Fh.홾=,>ݺ?pIa(/e@$$B?!_.5$=z#}?UpH.%t2뾙o"?$-/Clܽѳl>=G=t.(>9/Ά??q?o۴/{??R?`0þD=iG>N?}8*žPʛBq?m@f˿o˿S?SG6Rf 㼊V>WA{`=6 5͠>D 9,ǿ!%>i==5nM>OH-7!>B&>?X.s쾫;Yf?"X.- 2?Ѣ?Kb^$PN<7濃~̿h$>)&>TP>cK4>\aؿ5+>>g=>?>>Ax=q>)U0G>>ӡ=t*>4OyW=kJ+ >1Bp> o> )R=V7zyOd>>>>8aJ??>v?>6z%>c=;%Pt=ӛsW]?|U?F?yL޼ھ'ͱ!t>>.&QC(=G'jsk?~2?F?~p;腐?k?2?r&h;)9e?5܃jvl pɆ?.a=rmE?.@)@ &z=|@CA)`>B=V쿊ҿtBB$0.=#kH?lq+=9xAf>r$2Vɿ@>`"kݾqa?/Mh#vHY>KrP" ⾎X0w!>>dR>(+>\&i&r9`E=!сJ,?q&& 5>>ӻ>(1?#F>ay>S1b,L9&>D=h?C:v?> =N>rT8?f>M=U/<ٴ?< _Ȃ}>dh=&^B?I"~>.y, c?2<^b}T?!(v=>c>(c>5O{>S~>t~(v=$?aZK?,?g$Ⴚjl,?Zff?)9?a,mJ])?Z ?* ?a1f Ȉ\?R?";?XCN}/T?xɗ?J?|#1 xXR?M?r?LkZ>,]6=IR% >xH>$Bv@ 9> ?tCN?j`?D?8Mw>~=qJ ?@o:#Ľ?{z?J`=?rk>K? Կ_xsH.)>Y_;>N'I /6B;њ!'=|N=@TMV>?\C?LQ?}?->/Ѝ(R?!QIV0"<5?w><%i=O|>j9+'b) =RNvm>: @N>$*> >D?*c?z>Xu̾z+??<>A0蟾,?"@^n=d Z>Um>J;MU>Kϒ=$w\?1>>,㽬'y ?=^n5v)*9>wD>-`==Rr?PLld0B>e?:?#?%[jHB?vq?M??5p>XD+>?9??9Xg/@N?,#?C?}6?ף#-Z˄=C>0b>l7>\DӼ4Z? Ҫ ֻ}F1NXz>X' _>IXZ S;OfvSR7XDE=X!y]O?fQnT?>a>˟?W|>T=M?T(/&!=˾k4Sbc>&EU!= ^> *>S!H)bIݽ{? ]='m |?XJ>qz=3N">`>nƽ>:m?`}|DP>>4?)Fz?F>a> ?"0<ދ;RO>h=j=4F;9BN>7He=Cאz ?4@?d20>>4;>>+)<= <=>5>Gy|~O-%=1>O=Һ>U-f"b0i=v>G:B{/H> >$>/pė==o?# V ݾ8==?->>p=08ܘ? >_>>L>\?pKV)w>e>>Q;E͒>>_>~=„=M=5?!:<76 >Sz.ҹ="pm)~>`N6iCuC> >> [~ <^If8{B>{6>Au=派Ԫ7>>f5>P=+Q?> >>jj>X5?|o@/%>3 >>~?5?ɽ.=o>ӳb&0HڧXž]>xW-:- > ZTPEzbċ=1<ѕ?(h>Un =8ɾlis>5>"w> N߿>t0n? qC_c> 2۾GM`?2I?z>T>_[>4CIΟg :ڠ˾짾̒>T>`>o1>=k(yCp=uQPőh>%tf=pw'Sa> 2}A<"킺 >-nxXC^=̅>5 <ؖ?!~ 2vAH4A`>7{end"뻥[Ia=QX5m`->Vy8&>O>oJV>##y> >C>ޕ>NM4v>Vu>͔>>C|}6><>B>4<=>Ѿ龥T>3"0z7<|g¾->gW%_Tzm[.=Ж?^?1^?q>???|"B]$?Y?q?b^"-="#1kLn~r*1=;\WKgO=iۺxs;+8Dq>Ki @"֥ >⼠`IK\׾&μ>wdNl\f:\5~?){L`y=>=? : lB^̡?N?b>nZn=b>z=?5 j>1?0Ź?%QP?OIúq?>h>z`N=Ƶ╣?6=P@0Z=}?> }=KSPe=ʒ>;>,qP?<'!n=ͽ{LG⿧y}gGi^1ι徽"ɿQ=u`jrh哼3BtE>w6NW84ċy>,8???f/_>$V??G?o |J>?V?V~? ~)7; >O>D!< ;w?M+N?,> dMX޽G $4d>>.M=l?H r}x>)>ߵ>y>?e^z>->>$?RX03_:>V>?H C-@,W^9S>Öf`ؾp ɿMQ5w_>`3Bs!Ŵ Tx57?>r=}piWR<?>>%5>1K݅w ? e>|=n+-k FgŠ>!žQwܟs>kP:>>"ý ?/)_(w5}>Ia=:?#dwt>+ u>=̿+?E/^ ae>D0nR զW6p =?)y?!?Kod78C?b#:?kr?;dm8[5?#.?*?i'P;ͱB?s??ϒSdը? ?? qP?~WTp%ĿV͘9PBĿE@Ao .e]Y;:- pv(8? C?<)?GH$EB>=v ~fu_?!PDR~3*>>f?PǰmK}_>I0 ;=١w>?^ֈ>ZB! A'k ?f>Hb0Jӡn>t > Z=~~lvsR~=]>? ?1>Bt Nr+0???"ЄH?DM>>S gQSF? >J>9?E*T&B> 8n?TiP{Rg{:a?lYe]<8 ??4?`j>a־ ?L?& ?O]8L?I?Q?Dm0t->1(= >D]?;p/E>E>y?8?sMY8.?W ?3?$P'?0[(,>5>IE>+(?]o3mlʾmK芻:NM+"u>Z'e>ܽ*>%@~rjǛ5?l? >P>Wq%v>~9>2=H]1X\ǹ>K)xX=)H?]Ps侚 ;.L>c,q;??'k> ?:&h)P>>aƖ_=j:>X=eؾo_>j8>Է>Mk=nM>>=? I <[I4JjS>#,>𑿪]BD> S> #8翾 ^>Mn+>]>P>e>0 pnM>~>z >p">#hp>0n]}?Di>OA==?40c<оR>$=G?;nfH@eহ ˽|? a]8Fͨ3=ˍӻA>dKѼNn?[^TY!Ɨ\$  ?\=̎ 1z@$-p(> Z@8! ⿆ftX>B(k4~>03A >վu~RGNN/>.wpHCƶZ'?}O 6Vg=8>iU7, <J'=eq pib=۩=z-[Oq==VPOagΞțs<7*[%~w;y>MO> #1=sݸByӱ>yְyjV̽bRb|9~?|c? >5F?zQ?1?&E?qv*B86=1&_ >$ap:0<}ݾq¾-> @n+g񿇬n;6y=F<=dA<) c~iD0?1)?(?#+J@>O&owl>WQ!ێly =JV[~˽t }i$)?ū9>AQſ(=jL>Q>.9`2n<-=LZ?V?Q_g?=Azh=߃?ND?F?5:M>G,>r>Dphi%x<< rҼYe/-< v~@B o47v:|6Y#=R>~?jx}ؼ:bJE?"j9i =3Ԫ>Vn>$>T<y*>Op7"?/avPat>r?I?CQ?3Pj'"C A(9Xp>>ԧ?ofО]ڌ=( =## cLH(?^V(>e 0M>ì?' >QrE0Y7g 4;վ_f3j?#\A>UοLꞾeDed=ae@à=ST>( 5G=m?>>.)t=? zx?D >`^:>EQ(Tp2N˿4?"?,i?4>]D>`>q?fx,_8=; =z?LvKk0ǽ,;ڌ?@xs/׈ 5Q?0:F#Ў># q?<Ĭ2=$ܰ?>ӑOC=' #Z!> b E=xV1ArM==_bc"iz >z:= ӳ0|`>h1;˽IkYc?>%+ _a +4B槿F<^W$v?*o>^޿ H>?g[;˔>Ҧn׀# V ߤ>.o+A` 7L¥@>c)Klzva?ʂV>6 ȪC>1H>zS*>ǿ7d=/+@&`>םQT>>>5>(XQN؈ a_ͧv [T%/>e>-%??8[XK'>z>CNܠr$FqgSL.>*>? ?D:em>%Z~1D&5?'>f R> о`tS?ῥXX2M>;C پs`>#<_=aQI<炿6qz!@N _I?ZMt\V"C!Bpծe\+m`6]=6? 躡YmD> $Z6>DV=Z?0#h)h=U < ?#0==)c?+f`jȾ>whQU@pc:0@&.T=;hѢbsDpE?d̹4EA>*nrNj>6??%\>%ھP>~=3<>+Y2>J>&W>^%/N=ɾՌҾ>U> rs=0T&>eKgC|ׯڷܾ^=7;^=6=I=>kH|> <,շ?)zuP0'>z4ҾvM¿>rżlz CZ>@I>>>>ۥ0F>{i;'=PqPJ>þiUGÝ3bl=_>W<>f#>27xľ=잿|>5:?r0K槿Wb?F?,]ܿ6 >y۾*V@Ft:=speOU$m!7?6>O&)>ԾRz)Fþ O/=<&eZ?9an$W QlGR?Dzb=>#>D?GA#EV&=Q~k@P+[~?)> B5rۿ rߴ>'/?!'=ƠV!Ѿ*]wy>]t?? x?Mv]ʗ>3Y>ŏ>?ܥ>]i=ھ~?Guuvq:V>?o߾Hˎ hZ5g> :X  @u4bVּ=>*&EY­>Ċ >fKw >CO¬.>PJ=d4`k>VY žu65T>G˾b=5,͖i =F>8a =w+ 1>AB>("y7O">o9;S/5|'1<޾_ľ k>Yh^Wl]>,˿Cք4׼Ҵ=%jо߃8 ˈ=:ɿb+ +ctep{-=}{a>7GI(J1?. $a<>(|D'!=e>P`>xYUP=H=|R>XQ} N)=74=J߃=<+LIGP=m>>^?nv! >]{[>3? >x?ʒF?<'(& ɬ6> ?'>pX^s>uڭ>>oj^t?,?Y?+쾪gb=7>A=}> o/Z?5>?d?7U*I@?W>G?H?W(%ưk=|ڡm?,)}A>h>M>L>_->~ۭ=_TCkݻ0>:$>>5Oo>վ{Ӿ?">vȴ>M >3>Yؿ:U '?;:>-RH?8M>d&=`/ BU=Ɍ;>!Y=?BY}w>gsLƾC?oFEA>Ih׾M/'?]!>w !=03+ܻGR>%Yq>q&=+>z+|X> >?J>@?Vr>N<>(:>@b?>?2>j<ሱ?KN)>,>Po>Ԝ>>6`z>\v>">>”'|nn= >8?[u>ſl>>)>>>?E.}=ؽe^)?_=m8i=c<>T=p?`UIz=^=?E>F?4f d>@)@?[n} =06̾%D<x>>< o=:g1w>L?CھY?5==ZO=;>=.Y{v]\0+ 4zuG*~>01a?0ۿ#!vU˜?EM?hb?kTQ gmw>2?? b;pg˿?jmH??I`9оL> >vh? jݽu'_>->Bd>XP=wѾ$?Mx,,A> ?urL>r ?l5 L BY\V=9i6cZKj&>Oj><>d4d> ?G?*C˽6; ~R^$AT=~bH˿G^}j<9A $- 3>'?Bh>Fc?5?4N>sts>ν??>~.>u:?\>1>W>ϿQ I>1y&_0G}>TYѾG |?}y*>1(/lUB> >yP9l <>O>Mg=U@_ݾ $_ҞyQ]>콤9>qq_-ǾM?̟? ɧ?!j__c>\>>pǿ۾3n???6?$KIhF1B?,$???1+ŵN=aIǿ侫֌ O/=T<>?9?Ib=lGXMϾè?tw=,=X SP@Є<>$;>x>} >]>o>lLE?=<Љ o7O:?UT`n=@-SξaL6T?eea>]Ar TҾj?k)>jrWr x?lM^\>wc#=Oa>]f+9>O>|>?5 c>g$)곽K{T?[>I??^>?m> iJ>"UVf$y>C~,?:T?#9?4׿R6=}?_>r>l !>>&n>Ā4q<ź@A=xǾS@=>)p gf=נ>3j>ʟ@">0 > _|>$ =#dx-*=  ey}0yi' >پV+>]r>-L֡>*X> F@`I9ew>%>Dà= )k >S>@9&!7>F VW޾=l#>//ldML=z{JྤĿ( /0(̿-=?k>? L( c=VW>ŭ? EAĀ F>(ryeY >=om1>>JW??R 8E >j%>FM> oD㹾%;-> ѿ({k=Ve@>o>BUlj\;\'Q\??s?Dr`KKR>+@>"Y0y˳Ⱦ䆾S>Z (:%=?2>S?/ZSl<S>w>>r > >n?>龐?ɿQ >Z ? >y[>E?2>|Fk˫b!l>A>>L*>DF)_>f.>|<=u.>'>a\!6>\A~6N~0~.`Ľw>>~|,#ܔ/>Ή> o$`'}׼ S;>P8۾ 쫾Jǽ1>93 *> ?1i+?{bOf>4r?axlۯ=\R翙Z\Hp>ޤ]Q+ =>Ͽq2>y\6*%+>:bk3@$=C'>CA``>n/ q>I>n ?[@!Q7ǽ}%1>)>>5>}o`'Q>rx>+;>?3N^ =ziB>xF)DOz8Q"zBD7a#4s61<-=ÿ7>D2`ݖ=^rƂE5(*I>4 ?L?$ ?9~-=??X?o|0x.ջsC? izנ*>C=>1?*'9Z:)sPǽs־s rg)O=Il>Je?63oa˾}=.s\D90`?쵻տs<žala;Aٺ;,Ʌrs=O~.ѿn~>Wx>B/KK"5ν=h>'FoP=Rz)N=,5rv;,}"ľH>k @<0غ $>*- U30bbQ>f'eINһ) =aGnVzM.>oonShDcrڎ>P7C=-ΕU/v >,Ms-=bv.뾃j>^">fE?d2^ >uV>?u%W/#)>? L?|WP'W@ߏ=ڑ?1jWGp&N=MtW~>~ʿ# =܌ YyiZ⽽'Ŀ,~>2gF/=g4ڊ=L[]n<#31dM>.=jΦ/8SG>}=w;>0.h>V>?e¾ w>dZtc@`8ꉾz?F>>/!?8 4ZfȽ悶W?a?>.? !C?Ϸ>Vm?1[ ?W~?-?g,@)pHHY<{`-~վWwI?jϿoF<8&>>>#1Ҿ:??:?!l\y@#<ƿ5ƾ>~KEEP ]UT٥)+/ƾL>\ ,mP;=%15O?F?s?џ)0s)k?)^?V*N?f0/y^>|?+$?p?(g=47, >2{p+:>Ue,N>.F>?<>1)9i>bR># a>daQ? ɓzL( RbEj@֌pb>FYK?5e>?4 K0{k=V~?:>D1?$#1n7E=??]>&?+l1Tg<>3>$>4$? %>dž?#xK+S??7b0[ >?9?:0]\a>1O>?0|-/+ xW m?&l /ɾ{G 0>>?\aC/dA^>#y?[^y0~>g>(?|C'ⰾA :%B?G{(.~q*j?$05>g?80o>ܾa>?ȁռFDRV־߶x>ôɽd#ۿ>>!ZVg)?3{-z/)C$?E</N?u=S?USUw꾩.?(րBd q">J-@>?0P*ꦾ,1YeVa>ߠ>+ M𻾥>ǩ־ԡӑ?OA8c"6¿ϾU>9?Y> _Cؿf!|jZ> =95v=(?uY?8 ?xs'd,=?L?H?J+3%l[DK?KTA$ľ2>? >~Rd,wFK'=}Y?^:?+q?k|F+@?w?`s?YJ#:G?`?q7?_è(/ C>~‹`"^pCGc .>[ƀJ<|f%tA3=p?x$Uͽy|ĿeSο>w=a,Yo@H掿Dw ->үjeo/N,4>GWþ=B %Ra>0``=.N>~R{>=;Lz/ecӿ=ֻ#͚>r[a=N! T>ׅ153=$  >^?O/{>4Da;F(݀go??T??p`CtE=F$bV ĽO>D2#%j>"?@B+ _>r=߾0?=9b-?/j١W=T撾?lA>R{-&sO=T[l?X*>= =k?*C?Ə>0H>-Q>Cǿ 6CJEz2p-ɾ;!c`(ѷ>{TZ=baݽ`?LXGÃA'=ڿ]}>K?M>$O0s;`{>j^нf?Q!45>; " ?YKI@>Ob08nؐ?P˪B>s*'Կ&p~=J?X'? ?$h?ž->tҷ:=" YT?]?o?@D = e=?=E? .6>C>u>h\%?ĵYI>CV8G?/ w>?>^ >.6?B??=$_Ub6'E=- ёE!:G?r>wi辡>+ ??)?^_>\Z>o6 ?( ` |>T=9$?NpbS>Z|[ X?<;nÁM?(??3r$gzpgJr=<~Ⱦٙ>0#>qL)9?  _8 =d۾+(>kT= 7vɿN[@dHAJ7?]>a?kNHAp? ??wt?">]z >c^>.r>O@_?$>PP>?w{1>D?QF?%?'YI><:?0~>73? ;fW.=?DX? ?vLT%;Edg?GYXPӾ C[=ᓴh;>/=4="?Kknh;<ǛU$?b;^m>[>`>?#YNм#>A r]"O~g:\5@ƾ@GWKV>Ĕ?=y{l4;'?Y?#>RXX6>" ǜG=p?z>ac>7Z=N >"<πY>pe;"KES&=?:0>-ֿ b> ;5VE1>؞/.Be;>u>:>hnA ۾s?8?m?ڃXq~Ͷe=bg$I>>ɾILE>1?n>Hyľ|#}U>^۾uo"T>6=5ʾS?N-?v?Q?v:;?j?le?n3{0ף<;8PzľqB>F_l =@ >_̟4*?(?Z?.GPSQItT*>'o򴷽 KG> >>T|m?1X6%>+>f>X[?lD>O>+ 2?'z6s<>w>>$W! ûAᄂu>n@L=Mwd>Lob=?6^˾>V=G>k]=(0.#?ҾJm>l&ྡN>D>{?s8F=ۏ<w =:csH`bo@>l>ۭFN}|>z?#?-dQl @uV2<>z=(?-5Mx=P?>>ˊ?C6߼>rA>8?G\Wj<+5dbþbo*=]"'< g ;=\*RV f)L;-c<>4X,B=,߾_,:>=W Vu/½D?jM>|,x=5ӍC>v)=>`;~~t\#h>={>=N3j={t=@<`u*y=(t9??I?No?h6:-t?>l?2K?\4>}~ܾ/I>Bx? k? ?>PQf>N/,]fB>Q[S>K=f1;[V|0)uHR=(:5uZ=>CNCw=o]TxPU]< Җd羦_=40l$ύO=U-#cs>k4>K:f?'T=yf>\* rp>YھQ>?<G >B>HŇ>>* >r>??"?I M>^?>?"?Gx ^ٺq>;]>;>i+#7f =>m>}_>i%r5O=?D`hOv=dPd>y&P#]^>]=jb?c&C%ym-c&k#>>T?.+ p6.Ø/j>Rm@e_qJ3>=xu/_gʽGҷ?=`;?|lY=񕉽v>Oʾwc+>|? ?Y >cb<+?Z ?=?,R7Wѽ3n??hF?QwJ=Jgb>L;?3?Boy=,yp=UZ?'JD1=w$1j>=> j [)᾿¿fO=NWwfRG??{9?rT>jnzj>'n?K ?5P3?F>6T ?a???/"K$D>?m+?C+?RsH} =%>#K¾'6;>48z2O9-C$&=pj<׀`B7>PXH< =0>ɪBB=D >0Ũ=hQ?N!I|<w>4kw͠8vҠh+BQ.l>f㿝^y>'K@?qX? ?c=?op?W?J,K}޾?o?SL?N+%w=xr?G?W?Ԁm8~m%ҿ5˴V"u?DE? D>ΉYݾZ 6"/W.>%A?q%\ȾiU~s N>@_3uG>$,= M=ZG?(>ǣ3>t_<"?6j>@W>2"e0YcZ:N="`t>ggM>>T?q<)RFkM*iW:Y#J<;^Se>yxMFE`o潻Tw>ᗿ-K?yT>ۿ1ѿLv!<ѽ\0%;W=x+ɿ@YuexS*PF>="SkξOO9f^ >Wzr.>@ rVVw5>!G???iQH|rUC>R?c?V?=gΣ ?0>i>.ѿB,3b?">2}=-sP> x>ٯ~W==:ҚPoW?U\m9;G!?7X?g^?zܱ m<:Kȓ>^d n>ad0>Ҿ_2?5"PPx/̫=1 >2۾ ?:">>? Ca5?4=Bxƒ]?bg?>o7C#}?N5>j>= 3BҦy?6c>ۥi1=bԭɽ?v><>Jj@AË8?>?/?l(E_|?v+|?tT?'-n0IҾc?>?7?mNI I?*?(Q?cIVruڿp>|RMsj׿*h?ˊ??U(zḓX??ML?Fx4Up0c?{o?J >9Pu9y&B>Lp製l8>c@ȾY?#?#?hTK7K>>߃?8B3=~*Yu> Rd :ľIx==!o?{<^H/Խ~|[z>->+,>s=A<>] K< Rrſnީ<ܻÿ+fz^p<  ؾ3ӌ?p?s>?F/qf)d??O?g==4l֝˾a?m>B>hO,=^}sm"oa_=>A>>`8SG??A?Yz6( }7=}V'vO:ʾ#->%#'>xjM{پ=v>Ul?l?" m9u>!{?A!&k>(*=8_ U=nʄ=r b`>޿ A-A>r=<>:K3~o>Sro>Yu>W~_=J12 ,)u= o=8$%&]>Uri> WK K`!0L>;]<Ĥ >|5_<#=0IJxy>(۾>5&>(쿟cl>,> B?߿Ѩ7'Y?6>)/+ƫP>1>nHkV?(>DW>,ov>5>#>= gIn>7ܾ>{>zx)>(>uov> >ge=:?U6j!^%ĿY;(Ⱦg8n.#>l`>{< ^Qp>3,|Ϧ>V+gpT<% X̀>2z UP>ζ|?`n>j>'>l>M` 08>IaoD>Gna=^@P޾zB#滄Sh,࿈C-,=k+J˿fS]<[=ܱI g澅ϫb9=p[}>>u>AW⾟c.KE8n6%>>vd==9<2T6 |ݐ>R6H.$> ܇ P= zA,哿n㓼\#Mq>Lپ.ʾ;@^77y=>lրZHEݾo[ `>B7>A=> XT> ==y[9q e p1&ѾOS>%M>T?N43/P>>IM?((> g>5\?=S$8rl>Rn>?doi7>=$ݾQ}b>/=aN꼾OLȖ@= E;mrΚ=14jpPG@p>M j+U;f@><­de-?+^">(޿D wD,O #eq+/F4Mx(< JL?`/W҅JϾ *:A׼$CA 3 9uk8M ul,9⾊~>T>Y?GH%H.潔= ?7B!y=彎W:r"?JE]H=f=e"ew>AW$2Ͼ={>s(PݘWu>BT>M׿vM@81QNB =SEugF3fx>R<^LQ='<Էgw{>}$1Ӿ!ЪûlNJ-ֶjm[~6ƳTҾ˾Zu}xEg=wh==yUik=EWXs0kjr>i<{4=HRPUt:X>[=ې> ~u1D$ȷ>"vK0_!R^W? ;BYO>Q"Ì>8XqQ7>h' 5hG@?;?4?ZWYAOQi>_վ>> ?;@e$P?1>ގ>k?? $*huO>L>2?4+x63n+%޾>fvd8᾽;%'Q >ߨ Pݾ־F{_>T5w>fh>0?SM, ډ!A?0P]W6>YUr>4 >Vi>TTjSd>#>?.xB 1>ub>c?6G .;>"F>l >orCl(i¾]:\58>>rxI l>ТiG"==|<9[﮿hA̾M"01<)%=޿&>Qx"c)st<.g*$Ŀ> >;_c=pB1λ|; 5w-t؃iWCڔC3t넎ce$߾a+^(|<">-,=c(>\B==k_xd>v5b jC>>V?#J#Rt?޸"hCľ<pހ=pLϾX>Sz=|Xロ`оI|F=#m4z]S>dǾ￾ 1>Kv5\ڌ=X>wFg_0wd2=>j>>l@&7>F,1D̾AF?m/@J==?f+>p]=E# C=b>cp-'R"V-w8=h׿ 9>!GUkSc%2Z>@F1y,c>s;=ä?TPYm.'>^l>@?JY =]`5R?"O zCre3 ?2Ƭ?D8ji>'>z3V>,+>E>彿Wd>ACS&?2bE]:ȮSm>w26 pAFy'N l$6/K5=doV,z:[:>>>5=seVeI?`@}iH>$;ރ? C?e+gY)> ;mǾ?%µ&I+F'#%a?y=->G*9>Ϯyf>K*?66~{=XR>&>|YɗG?j0&1N=B}F Nkrz?xkm=i1<0> Z7.Q:3 :=EZ>~U>?v?M?M{q 5>iR؝?8,?sk>zJ<$?02CZO<(>)!Rg~*,>)=舵>p3[Nƾg-:a k{)G|>":[!][EA F*P>!'-+vqGe>TG>֓:>em̬1׾߮>O?&Y>ib  ={>=l>(Bᾁe @A>u=}YG=KS>/#,0A= *(-=Hʲ> j.f.Vʒ A;T >?(>f>: Ի>&غ=eS{BZ>s;;Y]>!NqeV JKQP3Cھ8X?.P=[>^h>k>Z\F>Sᄚ:i?D >R/4>—wWHI>M?Cw[ľ9AX">íCRa{?=@>]ؾKT㾎^>;r>EG}=A9;E.>cs8q=q?z>~>.+I92'tX?+,# >.orɀNbgE>4F>=?[ c9j?E޽>/>d>b>>6?e>p'>%>>?>>}V>ر>Ț>2Y>TJ<ϼn?=`>'yw=H< $?)_Ue>i>>Ο>n?4Q=Ʈ= #B>Ioe R> > >s]>Qv>e.s>]>KU?޼ď>C?n7>?Q8> AkU=:ܽ2]?oM3=陻=.>#(= 3fپ?hIu> ?wL=^?~̾?Q:i=r槿5#> &?%5GL=*U.˼9XS?Lnm>oI>9?Y}X> ȾYSy`t?hM>]\t?4`̾V?\q>8*EV?>77% a>>K>Nľͤj>>֙>΁t&Fm=t>[>UN [b@=#=I6~:QU)S;Rt?b)^^'o>>ayQH>x>!>V׀{tqQH l Zh>H+>>[́<'>P,>$J.2_wlv!==  >?%>} @iTH>;> ? =J(=ͅ2.<ھZN|^hj=9s|$T{>>)>Ո>p>9C?(Pɓ/{? ?"VX?;oҿKyv=Br*ȿ#E@Z\f>dO>b>AW>%>2>*e:xl?;?4?-lf{?xO]?y?_Y\?C?'om?Ch>-=F>R><>;I:;>uS>$m)?k?m?9Ҝ?$N?A ?Se?=#yI>$6\=5¿8@:ھL?K{>B-TA@ Ǘh{œ=Hb'?TIs>B6~7JQ>bTWML=?>ֈ? 2A]?4?&[?U^lC(ҿO?HG?8R?L;-]?2 t?$?7j>M閷iƾ5ylAN> h<ߤ=}>I=>f ?%iĿ򐛾zeI>>Q>t?%jƠ>0&'Nuj[/a]>YK{)EA5-Э>hm/hS Bo>sXD=C I>=Tw+zxq=6㾚<ց>w((=V?w`>?z }q?Z??t`Ǒ<㊾:>,㗾>=1&a`=Xxzѿ>c?0.??+#%#E>:?5+=?X?0;>jS}>]_?7)?$?2dF䭰>.A>(>Nw@ظ >'4/.'[ W#%l @d(P=\lU͌:apt޾&)M=裾 =g>YɿLqM-E#wFb,o> ]SΒ押meZ B,=>C>>{;󽏻>+I>ˊ)^ 3jA}ALf=,&J佋Y>۞8Uy(bA;U?>M? b Ĕ=Q.0]>ʿ>? ]=׼_|?\K?Lۤ_sI=H}=3>#q"sMϾQ&=œ?XNpp<>?,/ U7<̘_>U>|> 2=@ *=M>T>6 o0=>>T_>SGG>Ҷk?\17^?SǴ?<+?KL?E ?+W?9XA㾀(?t?ZGx?fUSRIF~5Y943%>"p>? 2?DBپ̈R>4=sHN^觾Q!lʿjÉ=b2=q ,i=pʿV>}w=􈿟-'ԿSC/#]2?0+?*?U?(=> UD_=}?)>ZC5QF}gv$o?!?jD?漿qq\0>2?5-??%&>8D?>V>it!>>?Ms?-M?>Ap]=,޼m5 CK>œFQ߾ /,f0.^=a_8ͧ#@ К?B)>??,Al6'T>#>?&9q/(5/:>C'>Q0=/@_Ⱦ5=%_@,b: LF)0 򻲾Ij(̾i<܀ S=d>9O25Id}>݃>|>!>;]}d>~-.A*?j= A+!G%m=R?B?H?2qW({ >F*>˴?ESH '&)>J-CZ8<>q3?&y{)*KZ= Q>z?-m &YNg0(>,#`>SY_%<~$ۘ>o?7>GUqbf)G~ï>J/t0.#=ʆQ"]>L"M*!> >Rt\D[cN2)AΞ^[ Ə:" 1=>gO{_^FAa_ =ʠ>Uܾdw=Y?>xd>ؿAGO0;_?47>^1A=0@ľj=J>ED= пpȾ2H-2$3>X>֝s?i-zA)ɾҼM>@?(5HL#JᾈA̾c>l'c1ݾQ?Y+I<DoPoξ&>si{КoP>ǖ:ҧ,bѨhG>7.`.Lp>7>kH މ>wiH ?:>P4t2=+| <\L*/֙nH?`*1AcjO0:5i!?*>?Sr +_8~N CK&H*>C/<> ?Z><9)Jĵ<'?2?C>`g)ÿ5=Vx-<*Gg=Ȼ>@?j7&n,>G>Vq?!LD?1%0F}&o>h?G?D==*9Ⱦ>:/?{P/>|1=M>Y;~?,>NMd>g>FD[%>E~ >õؠ/ `>>٥?/l#'>h>XP>y?{, >_?L?:0D?|,x#<އ >[>o?s[Y6>U?NG?g?9{1{gp+>X>v>Ӝ?5v>@ڡ?>;?G?+m(>;%?2k>-4? >`=>?;e?!?,.#p8Z=by?*5>k?^CeFԽ 1?>>8? g $ =l.׽z?#O # ¿'z u>:㥫[/\>gQ-?Nq7?`?HhܾDT?U?# ?R"_K=:`%a$>20> ' H~>Ɓ3`?W??kZ=X`?!M>?C+k>w;RD>ʙ1Nb=n>EW0+BlT$?h?BY.fYYg?wpc=> ?.?Ymn?~VJ,0=2>،>Hp> |Wþu?z?R? E`=fCW>j@=,`*o=fÿY >|v@ݸT=ܸZ٥>i/j!j=Ӿ]? ^_;ZcI>q;0G\>N d3>25@>;|J<T~>H=Gbc/he?3?A?;~VHj2$?ٺ V>y_@=[Pd=ɭC 6~>-~F$o>w&I>Ǿ0>'P>Yf8 6ZW>I>s&G=> >V/R=U>S=,K>+|m ޷X-޾gk? ?V? Ӿ?+?3?.M;;b"d$>.C$6=*DȾwl>>P /I>M]1>G*|?&?6>z=|>΋~(>龭&g>4fM>TCy @Ѿ3Ϳ^+>ի=ɾ >[>!)_-լ?;IR¯>Z;;Q @>>> >2>d>T?Κ>?=D>(-?Jl?V?U{pz<;?T?(v?Wbc?z,?OP?x j`N??{l?.^ Y>ھԿI>D:pk>#-s>B>a$>>< a >xK!E=&B9'q%=1 N&3>Zb.>=ض{$G2G?5l>A%S>ZL?L?~u?|pL Kv?v}??iYohGt@2Uhs<H*!U= ^Cg? S?9u>IZvkE >2u=!̿%e=&v 9/+ǒ> 1ne>B?9h?V? >o/>d*?QY>_1>6,V>T?'>Y>~u=(?)h>e? C=>:>M>OsIپ5S, Km=[j2"Q=1.l>Ü3@ x>~s>@(>SL?HOҞ퟼|>3?=r;߾N?3=ZWSTMO29 ~R>&>^>E|>:{ JV|kK#[V?"\xCoZ.w8>{m^8zTL+?(+x@>~v7?8 8s6">Wu B@'x>=d=B?4b`/=޾:>H$&,>N>2=H?=gP3Ͻq';dKj7܊߿=fB=ì?9G>? ~0DGF<r%?? !:c0;=%#pes9u>Ti\==iYW E>4HF<\>&5hG>⌜??GC^ؼM@=])> z?p'H>PRPPP>:!o>2}=nٝe>t==>D1>F ?|,qZ(9==:>EV?kڔA>(uz>:`B/o޽Oξ0xټmD?ia2pk ;r?>o =;gZ>YL*ŋ=W҅Wq>g8V>R3lAcEe>J˾Wi B${ =߿?~??+9M̾׏>0?@Z?0ϽL਽K>$eѢ6#{`(>Aoޘ>DG*cwo"b,M>u 边vR5C>=/>x~P20wp>){?H$N5wB>+G>S?-#)t9E`?#?V??eb(ڽ~uz>:=,>B>BQe?,dE̥_j+yQ><^p񷽬=O=޵?hd^=~ӿX=sE `=~a~>8C1=z[\ oXg$@>89>4> P>I]f˾yB>>px>F>,Ԫ(?#>B>tɾt)<ႾN>9H=x>L@;bLu? G(8.>8m>?m53# =Uc<ݐ<'.`h=;z_wu)>|?ˬ=e#\Sy&>@>Z(=>hIn?>%zo>Pv>QH&? >> }=>\c(= )k?>)C>@ 徆>)>@LFl>[ ]Z9/v>j/@ x0=>+.>ms>֌uV<>y$l=d?S090_=tcId>,$?(kY^#`>"D ¼q9 :Ad,C?UE> $dGxe+\Ս>/#=u퍼 \w=?.O?? g'tU>#?K??JMDp>9qŽ/# i[협>?Y(?R?d/]>X*? ?-8?)j=[u?4>>*sXjp= _>%#<+?=0dO< =?+5+7a=>zAsn> +A>ء8xoI?E=lu_= <,k? }Y\ew<'F<̾E? 6& M>Т:jU?θ޽*o̿&Q >VmxZ=!=o<#Y6? H[UQ0=2}̽>:`!lqHW9%T$f?>?T?,V`?S(>?e? ?yx(TGʒ>Q:#L?w>^PLuHϾ2s>^^h>*yg>)M Ͼj:=7 >= (?;5r>=rq?Wd=ڽh5߾ZUL>YrۀY>;>t2>Th?=#2eĽN!&(?||s?Ҿ>yy>g??O?Zd'C=5>v>،|=>o>@j= /tl'>YJC<> Z[ >-=\o?'`4? >N+?7zt߰Ud9=>>6?ruL8=<6Ŭ<|PH>X1+=H\fӾH>S"!<@Fں=F p{;֕%-ܿdУTϿ >]8Gd|>}[??a?9ƏT{'>u:? ??(\E |?'N??+zFT6!/-?AUa?3H?t`G 5=W>o>nE?6MPC>v>>?Am˂ɾ:i>>dw̗Ӿ>MfW'?&>BW>V3!ȆĦ쾻[?-{W>!V* (J1tr ?G#?=$?"*Lg=ۇF>wqAYg\@l=nehB+8>5.>SѨg:>OJ=>vbQ~: ?"?Z?7 -=JƽGT>} &=I;>pY;>PD"U>az=vGew>|9>fVt trƾʥ???yZ)9?Y=๽@[n?^>r>_3cd`Cؾt?.?(?\ o?N?ރ? ?Q%>麏B=<->ȡ> IVi&>tr͕=[d'Ŀg'[>>} n3n>>6L>4>lmvn>`?,̼?`t>`yr~Y?z+?r?Ua#֦N::?r?1>qz^>?*Enzc>>ST>={=ʧ?5zo>Q >3=GY$!Ơ;A?$?V>ЅMR Hmc??.O>ة/ վ?Io?Zݜ?(3l ogٻ _yh?% ,\eW;Cg_>bȂid=)ϡ<YC>av^!#K׾. ;=ם P=.U X .9&x<ȰgE'>`}=俆pv5? > ?^I@<*o`5 P4̽ G>7H0.yc$"`>>k@* b>*h!߾a S ø]%q( cK<3ӿ@1Wgӹ)<2f4PY==σ{-p|^=uZuGez$ٽ7 nE%=rD :;d6>r߾L O1:;>[Y>7W[ jZƋX? xbO> ,ǿ憾4:ɰ{`=c :e%@{>qn>n>5n>x>>B8@W> L?cRa?QξnruUg>UCۡ=|&?mPIs>QY+k5==^l4 _>O 02߽%Nè=ɪ>##6l%>4@=t׽lHm>>X=] dJܽ>\O>0B>4ވ$>D<`3">+ >06 =0&?>]$aȿSH? m >Z>>=>Dkz?O>#S>u>f,wIEm1>>>=ggo='> >,>k9\=+>Ӏ>r|+-M}==jj?&el3T<_=R?+}ql.z<>d,=-:" >Ht23==BXƾ{O? +[/=¾1=WG[$*qF=ȫ>M]=%= >Td?`M>ݿ#YVOA)&>n?%\B?6?E?!h>j(dd"a?`ր>M?yoL?`~ K>h.ks*v IQ>xu?w_" =Oھ>[_@=<Ũ/=x@>(:re<>&U<=ZJB<[;V0>"}g_W>«T>2Eo!C>`]X!bξzFV_>po0$JH>a?L.]% ,? 9W'7-=C T ?-OH&[c'%Q?0s2T}=>!d?$ݵ3I@[<ݭTz?E=5A̾Ť>Ҁ<{Aj@=6qcN=X/˿,w6=݉O8=I/ej>:6-N<=Қr8ɖ[ ɷ =E}DVBJUBո=tqz=ٿ@j6>H;@rʾUXl=l= F=E(;HN,=>Xi@,=k3=z2Y` >=%~7*s ?:=0G@Mz=HЉ>H>m]>ky>=k)?*E>> puy04?7?e?zOWu (?b ?[J?A=&LEpi[.3AN*Ah&ǴfH3%.5¿G_HѾH_#~~6N x+8?>dh>>h?\Tz{&7Y>G>3f?cVT>aR>?~`|Cx`3N?Z<0,T=Is= 9?=?ՀW>nr2? tiFpbv)X>(#DCb(SQcH>t>fL>6`ѽ#.X<i(7ν䏗o?L\P<־=Q: DD5p~fp= ?Qrz_>?`1#i>?2x} = k&?}O6H?-==#>4ݜĤFH-*= gXԹ==O=?8-ݜ=l>>g#?))),݌~=>Oa>M?THA J Sm$/뾮ͯo<8ܻgF>6>?j7;<0xɂ {2Ng+G:5B 8>OQv>V:m>@]Srd>l=:ɿ}=x/>:@S' =`";*7v ;s P++v"=h(YM>Jܿtӄc>{CWF-0EVAM?!S>޵?Raw=YÈ? ?/^=(|k>cxkݱ!$O9"'- 03" һzş>]h~J3>8H^ K>?Qbc=޾?GIhwu?~?(F?6X[!CN??"R?.#}礐=ž>>b? ځ>sJ>#A>u>GP[IE>÷R>V~?[>\}Б?hs> >?p?)'vI>(;E?6?Mt>r`-?U) =2uhi "+gM~g=pBS¼s,bA@$&DuSEL_w@=>-t>fM(g0<.w>MI>٭> /Ƅ=ÿmYubih=;CC/4(,= =ѣ+uِzIj+?)u?f8>'D>Ck?C|?,vC?7> [>&?э?a2o=>bdmƾ87?*޿-=l]SԄIP ^ޖ*XuKs^-&_8> dѶۡ}>H9GȀ06EmQ+>*JQ0YPjn;vp~g< 2t>޼Q;=0=௣0s\B!> jDWM8q?40^= ɾ·M?ygA=|So?>!!:3"ѿ![ypk ?9HT*>>⾅18vB.^>T(>f <ك$Nsl=.8 '̾hMEk??0>(Uھ/G[?])->Fܾ])?H > =am>(z>u? >/>.<>¾'>ͧ?~>t>۫?#? k?U>k!ZW=}??3=gJ<+|~&q㺁ǿ#n0%BB=!2ذK>Oת>Ig>(ؽb>`RP=Aj>-T>!޿ ?nf?<$?v>?n;?D?yMr:?wc>I? Ԏ&?Kz,> %-x`imd?kt>0IfJV@Y>2+>Ҟ>sq>^.o?큿Z>/ < T>hP=]?2Y!>+%p23=$>vG>3?AnB>:ڼh> s=oU^>? s>7O  *lY6W2>SA>۞k>||;q/w>A~xbA=(v=p=BS>q?pŇ}V=o"KfOU7>%?'O0>/? JM>?dA5>>Ji>>;Ea,hz>}>ґ{An?iQ??2>r<)=y)=@>xV>~:g@I>3>U3t>EB-6ƾ%[= =ʒ>?%? b$+>'>WIJ>eKI Y]#`>B  }%>{$?C"J|6Ðm>&>ӊ]>Wݱ U?<?+'?@PkÖl?a?qe?u6Dx~?@ ?/}?Bq(B>"ǾWK+2>q TӾRۢY?&?z+?^B>h-ЖaA?H>t#S=Pv>ü?!8>6>`(>M>o?:(S{PX?,7?E?-S? u>@/7n>i$> 57 eW~#/EӢN#=@g?CnP?0 ?A;~G޿M>sK?.?w?+f ̼>9CG^kG <l=PA=+kx=ʿf _ʊ;Ca1=m>(>T>0=ҙ=/)HF7zj{>mz^>7?0:?p?+<=R?K?7Z?Iվ"#`=[?B?,??WO8 =Bo3>>k?d>$ɾ*o=!>9`1«>b""k84sK'x=i³o k8K+k<ʽA>.O3?? ?;ρ3=c5Y\t c+ 6EN>".^>|PoyvWC򾼜 @%A 3?/f"p2`*=F>Pb2)e'c]S%"s4셾`=W =Cl-diHpg"{. xD=>>I=1!>>YC>ۢY3/ɾmdV=kY l>>ߤ2>8\>ݭu& >ʾm>bZ>0mI[!?- ??&R?j@?QNT;i>?!|@! >7$>l=>y;`^>!> S>1$>^b>'7>=Ue ?.??"Qϛll7Ӿڧ߾)>&lb^>o߻r5'_VlyBzíR]߾ǹ=㿲~0=F9M 񿽘~vI=g(cDؓ>~i/> Xo3`>(H?#XwG?J?-?;ŏ|?=>w?rg >%3@V$1[Fu0x=ƿSiҪd$G鴚<^>k">V &'Q<:6>q;Y!;Yvd@>K/Q:P>Ua >GEB`-4j=C#6>@*Z=x.&վI?,&P^[6ì>8?.p ھQ`%9>V?>U>;?3B?R?'>'JF >?aN?@:?S;pFþAٿgsC>3T~?,>`>M^Hǿɿ k= 9P>_ER}}k~ l=ÇF=ʗ/`G`>oƼJ>E˼?1>[}>?V~ ?44?Gr7>E?+? ??RKPA=0`>W_d=VVտ23se=g>>>DK ׽t~#p#=’=C>F0>{q&i,>C>&N*);Q{ (ܘ=u⽋X=Zޱ OH=0E;t\)E>7U<= qp&〾(>O>?B;pp&.R=>:8@>7쫾 >J=冿㿓'bȻ.?>S4=2npi(9Ui4>z_od*r>nv=>?V)a`%r>.O?=ۇ?$ip* >>9G??[l %>>)>!?i#<Py>V+Ƹ}ZbZy FÿC|?xCƋ1%SRd>VT"ī>I;ײ>.?1Kɔ@)kP?g;9iS7>Ge4;wn=z3<;^cWetFj=9>om>>9uUGL=PL?2Y>B>}ٰ,QWĕ[^I?:E=M'&=O;x>E! G>caVk>?Ux:5=мiJMn6 ?.=]lΫ>sʽTm>!?-9>P? z*8J] q?-Z|Ra<9?<U`T>Uҽ7 =?T?>> +0>? vD>HX=]d?PBȿKB>(i>k= >5l@DXu>Y>r=c>T-O}IR>_o>7e>9>AٽST>1f?`>dZ>쉏K,W?>w?dw%?+^?Pr?>%뎾o?j9>?> ? ~|dD>(?>!>lL@-*AM??L7=H ԪkU>q5= 5<Џe߁b>"5`>i쾑"S?G?Z0=A>¾\bc>?- >?)'Fg?>^>xx+FϾU??L!+Ὰ%ͽ??u>$#ef>*6>>o>v?r>7=? f >ў0?a\{>?B? M?6 {=%?h?1?] 3fYd??T?C o7??`?n9T?T?"@?RC~X*{fͿ\>L*d|??&bgpè<?D">Yu %Vd?zŏ?NG?}!tO*?@(fý-!aNG=?,8y.'aQ`?ں~T~#{A־5+?ŏ4$x=_ոܾ>tTkäE>1{iHt+ eþX*ܿ}R>ċ">ܽv>:K:z@ >$OC>K~v>=;lT=^miy=ov澔”s? .4 s>Rr0 컾q B V?V?+?YfK?!> ?$`4r?5M? y?9p0྇i?S?U%?ۃ??y?ߵ"=/w`>$O2i=?[?*c?fx)8??"l?@>"7HG\>ۿ}m>$ >?$5ycU>==v> ?!>`|???Uշ>߾U KU?&.^>JĿt%>qK@dc>"l&E>1_F4{Y>"D.H= >bE5v j+?.9fdT?6?j?V/A ?0?gxy?9i?D?5?:}&{?@@??5<e>p ;bǾ >B *=* qL>6>"P)M?!D=ȿ+4P^Yل>h+s=c#;qվMf?\l|>ž1ń >o' ?SԾ˟>qP2Ý^ (>o&& =R |>K?QL>=fk6;w?.>A⋿Oڿ ->Uov?4m>>>, ?>> G=>=`B=isP\Hk?H>>uYG?3?s0b?Nt7MY?p?Dµ?\ȽaT=>v==0>a$;X]!e ?K/FA=&vh?f2డW0xپԀ>qTC1;f>@e? >[>G(!5Lo%=^?'+]>3==7t?$K@<5nV>3|W֣@h{G1?>me8 F cX>#fZ>? 7P>vy>3='>>6r>en&ݽ>s+ ݩ>=8GB>dy/>RZ7=F& ,I=y]6>Ĺ28>FK>?2s?>?iOP9x>FZ5q=U?JG XQqA\7?nS>3a >b_o2ʫ=ʫ?=ǸPɽVK=l=?%.ڡ7f,=}F=?% bE=˧"[->e6T9>2~ܾL? Oq' ^P>GRzkH>K?\V?? *>j ?F?D3/?Xxr_=7;>>f޹>m3P7$Ϳ >?);\?C= 8 ψ>? ?F gK>)>~bUTyd%:_B/d42#?Dv?(&?Gh%dDE>> ->?ڨ6 o=i;>8?u5H>?_?,6m ?'?g?>P$Fn>"=<݅= ةP]e>A߾fg_zt>ÓE.݇1{i K>}؄1 ʽ>o>H? ZlT5R?jD?q? )˟5>Bо$->J">pT l7>GB>v=qs;ļ"3-^|٥,|E>Q8/1ѽf? =q('ͽ4V="A>Ә3a|>,V=R?96P3h,e}>i?W'naf'|?-%F?*D?A%i=\>8V`=P>x@@<?տ%SgMV;MRz=H?7L z#=!=2ti=Ǩ>Jgȯ<j=I>R>uλ>& m>;q?&u6m=0On9<>--=u??R`ƘH:x>lU=.?TКH@3B_w>|< ?; >_]>*?6&?L|c>L?3??h c<3? d>J>RD]!

:=+@?DsˆVh;>B[=s5?K;@x?H=Q>Fq&=A?!+#=jK~g>}(M(I xEdhuY/> o?AjϾ)>J~#KD]BhǾ>Z4ٴ7<%-?](>;>Ωg.ւŠ>e fSUl>IM>rW>Py?9Cwp.dž9ҿq~>yB]@Q`>2>JY}>$<}?+E<|~k{> [y4;FE`!>#??U?˖ŷ>??:?/##N[>F?o)=?Dy ?'=0Q? >P>^43=٠j?X? >BtHt{ VܡϿx>[A?u?7?h?)4޲ݽD?3u>Y='I|3؄>Y\>`aC>z h{>RL)("=\޾Ë>YR `,{ O j>?Y~|>Pɿ6/:\Aս,D2UTAxu~SUV0= ԕ3>Q,>4c<;>185=Rz6LƎa=4L@H>{v>oMu??? $tq=?>B֪v),'?~8>:$SOrmsi???kK5<>n=:*\_p@?L?@?|$+*Q9Ž3L>yC;6ۿt"e<=Nοm}ci =;Z꿙7sɿX ><h"5?>@>\2f?)z(g>>g>Y3?*:]k>޽a>\QP]>#!Hw<>>FopKw=ſ35fs6=#࿝&Ⱦ?7q>j=q=TƽwSMgW? ?>cp\>&V? ?(>ϙo=9?7 ??CnrϧW?~!?g.?HxzpXr-?,E?C?iI =I<=dRnŪ80/Z;i?V>=J4U]J|?Of>3>AW/(%9r?^>f>؝,b)><\2<쾸}N=gOžEZ>6{B5ν"H=ޘT=rQ>ܼ>?]Al>v>\:=?G S>2&>(AG͡4>4y6r>/b0ȕp 9'>zѽξC>ou=`FםoQ9"->l? *ɂX:FZW;5v>q賈+> >?&Z>^LS :u5sL>6>o7>E>>-s%f??4?x+Hh( /|=ak>4r#`>]T>+k>>qti+TXI>ˢ\ab SmB&o>'*>6ߋ>faF==Wj,f>>k>!=fb?4 > gKa>iry-=NU?;p?>?`oW>?$>> >^Q+`ǯɾȸ> ,#=:X\s;ߊ=VX7y<O>>1%ݿ6vyb0?|@?BX?&ffp?tG=Y>I^q"W`~c>81Г<(+<֡K˾;>/45$v"B>P ʆ>9EI9`=>}a,É?1E qC̾d$#>Co>3c?X>Ⱦ>`"N@,p=1y!\hDG>18. ?! k:>S?;>f>S?k!? ? >U\>̊e9><0M> n3=LU |==,dw9?[>*Ƌ> *=Թ˾P7H>`%hBcT=kG=IP ->fێ> >v>>t2}C=n=j=OHRfs=Tw>W>^a>Kv >7=>0=Y)vX- #E=>?:՝@jx#=7!!9_g>j.k5?$?s`>b|> m$>Ȩ >u =e,<6v=tm}|i|X=U/<&j=Z[ߘw>޽N~0;Z ΟAUak&(_[:=b < +5V >=2-MD]P$-[O>u>=C?}}[H$=2Cǂy> m&"&-4o>>= =is>p<5!5Kul|?8# N=ֿr>t6f>Qqk>Aj/U> žk]>z>!Á>,g¿i&5?N6>wQWX?-~TF>-PF=5[;kƾp6>eD[0#="྆h> <382E3Wհ6?*C=qrI^ ԽY?3`x`N<̖={NU?G߿&>hC+Nce+>ِ2 Ϳ _cC $o>c,b; :*!, V?*Q]f>?s&?i><>پs;y? r=|>Ȃ_R>gA.ؘԿq=v?h|>h4Pܾx>ɠ' @? #><ٲ!cN8zk+?i/쵾YQ@*?$3!Q u>%#I"*Ѷ?pݾUszV>*|Q/ݎ>W>bXO?e?283>Կ߾?wx":l%MdH%"2DC\ ]==eR>H1>5]dbbz?:q< n>>7mZiT"9,=920> yC8ۮKR5=+E< 6>>5z>$?|b>~^>cP >k/Г;뾈-@-_~gI?_z=AJmA=>oa_JeID|>ʢ8Ǖ=0=mr(=@1-GH>SFȤ+=뉾Eݾ=Lʘ=ÐɾA5TUZ>K!=#cNB=3Už)#y}Ԁ;\=7X\`nToҿ>6P$Pa1D=`*x>$>FD'99ξD}%ý;&]#uUݎe p˫,ƿ:d>"$"=?aCt ը=9zt tɾ޿&ù=YE>>??$H0N>>k<ёwI>*lAL::m=U?r=~ DpTi>}5г~=URnVT IBېm½HԾΎW{ n=`uh<%|?;xT>i4=3=?c)?kӍ> <-?_$P@>>>=c> QzĚ.1_Bz>J^n<)6ƾ<,>+]>*zȾ`Io_>->|UC$'1+@*KܾQ sub>!K>>{}1Oz>0Ϟ>`>'˾h>G> >\QO<*=>7?<}_>(JؾKbia\<>)i>VY!\>4=_ .n8u==Jb:Ҿo> ⼔{3!tq>G׾rTF?: >PG`|Iꚾp~?z O>v$=Y=kjV`t J>{:ᆰ5(R>Ã=Ծ׎㾮P>y\>B۾]13?,/U> ( YKܾo? >[jbwԨ?J ,>{˽#=:޽z?z߃1R>$ƾݕ6}̾4'g.>Pkt ?3S>]K윑?j;G>n{ľ~zw?ȹN>/y;5?&>z)zݿn$қT f)?{ ,M>>b?>RǾjJ;K Q?Q~J>o=M>:>D8?xS>W-=>>#?j!6>a<])==_{=Zվ=~,l@h] >^;# >tV=p@ +\>C>Nw? x>|?2DyU>ֻاku?@\y>W"?b@Kt'}j3s*] @$>8>Q׿ĂpHfؼ1}*ZASz=S]>X>Hwh1L 5D=:6]>>.Ш ]W=[=/Ϳ >pUz=Ŀ%׿ %*u=3ξtdX>w?>ݺ?\>g>>C??[Sl׀ )<#>>Մ? Fc~>X?> m4<>k>9i>AA=T>{>lf`CX>h(==yW> |n*=>A>J=ȴ?B?_s?S33>俑;>>ϫ>?HZ>$h@/>$R>s? {? +#>c>ا??;ǂ?p(T==&>:>}~mIb; V>>>L>h8p;ft21ՍV?H=_Z=>} >'>iGd龝l > ZLdY>$R Q>j?0?1-?9S7RKW?:?l?s3\W[?T?D6v?W?y>ͳ>|>w?,zѿu6>R>K΅??B?2~{g>>|[?dZ>-G=F,>h9>z.r50?u_x>RljUAS= ۿْ!?U??B ?T[<Vٷ?=?|?-Jzf> Fq $J#?r>6 <>S?Rm>F[!%S =o>my> =W~P/>d9ʂ?D?{?lE?|K?l?~ N33εp??W?H?g7hR>X[[?_/=pe`C>';C݃>'$1>M:PWԿ+ߡ1`R?+v`? ?% 1@na\:þ&ھn=98] SUz;6=\>o?p"ntž5D>'/4?_NmH=>v)>>ݾѿs=.#>>h>:U> JB꾐i5=Q}k&T̾ϼlC>*_Ⱦ48>g>S=~¢>uKln X>]??[B`wQ=@?_>?>d&>mq*]>?nL2?jDî>- >ٿ?Z`%kx=۹>?H;G[m_9 >B>>B?OV2Ar%%r>8PY)΃>)Ȇ㆐>MFo})>ο!> b?>́?%-?8Koנ?$?W?w XX>>9N]>z7i;⾚ 6+=2 >S^>B> ز>0>ҍ> 1) 㽛K0Tػ">7rPA4#jΫoH<<>h p'>UTHk!w@>K|>P]44IOõOj>/>Z>%( )"پczļ>0{x0=R[MϾe=V|>@)Pͽ-Yվ$ 5 =@h.p;[>8=vQ>hҨY)>ޔ?%>n?,o!w *qTi)O׿@] "_M6e }k=ܘ>P> >pa(c Wa=˽μ=Ewٿ a#>:K>u܃>m bG> l]>i{+5>>>VGp8 ž2L=ҩ>43 ?SIM>Vz<.>N\?+w? eg?!m1>HHZ>u<>5>z?s?Ql?fBe=/Ͼb?Y*s>{99\ڈ=#:7> S> h>?V@E!>R!DUL>y!`l"\>T>I?2!??(mi~Ui=W'.>7Ln>*^쿕^@fP =jM=>5=u3? vwh>K?l<}?L?dEg>z1?]zx?<'?S?>#nʾ㻥>3G>ɾ97a>߸Կ}X\>M}9`;O:V$>6OUp%^'m [>J=ʬ>|X+ Pg7H)˫>KǽѼV8>$^e#QXzѾW9m׃>✻P@hv:wO>~BUž^~>f?Su%Oe&,;G>k-@LQƾ]1í>ٸN"_>nP=>sJ?SKsEg`>>F;ܼ[:?&X-ӽg=Y`0=<  ѾǾ?%#H> uAG 8?3QHOꖾX2>ˎm/5H_־e`r@()%>)a==G>~?hmI343>(#?B>G/̿>ZdхM>@?#>h?8i'a?SQIA>ϒ_d&<侯1/>H+؝н=o?@pP+}-9i>H>`>ý0L(>[GA>p{=%@>>.4b0ƿ>4ۿ >GRۿHb[`>jZ?$RP>?^,Z > 5>>.lL>6~?>Jf>mg>Љ=%^N>Ȅ>P>EP/c|?)>#p?*Q\.R+ᗿ>Z 𝌿Tr~?s~>?r;>c#( {x3{E=7??T? ?6d+$T?u^?I?xy&2޾Uʰ>}'hZ9`>U`ΚLj99u][>Oo1/Vx=*@Xqq8-=%>{=oOſ1/> B?=kLlQ"MJ (ڌ*=1Mw1?=KU彡п=ʁB&!>AsmNͯD>V?\=G> eA (>o;w%wJ{ۍ>r$P<öF{?{fU5bZ$=eϿA[<>N+S>otċ?2G>6H˾+?CR-.?Y?}?%,@I=ĽZ .>|{M=]Or.>_=Ӡ &;M$i?}g.jPc"4g!ܵ>\ca>ژ0\/>8dE> >8ֿҿ7o >3:MW>i>ƽ>܃>-?hÏ?8$?r>>Տ?O?Q?P߿ed,?Qx57)J!M(.??}?~ \==?*??A >*Vf#fV?M>:Q㾑㾕}?>1B>e>?،=^R @G<&,T79w<$?a ҫ􁲿#%K=7 ۘ@ p# l;>k>+Q=(=J?TXG @ |>"=mj=?YSH0=ԿS]=#s> T$h% ۩ 4=sjl?1? d?"MS5?Tw?*?B(`9𾄤ӽ̤nJk?6#'μYQ@ӿ3r>4&_ֽ;.?8P+=r‰>*ȣd/#d|>` 4ds>V x==6>>":>PGisN>г>>q>:9bĽ`]4߽T\>=o>Ar+:>$>>mՑ9>OA?&f>)g?4kK>=ĞE= u?pę܃>5 k=,==Zߵ?#kPC=DW1=>&A=MV>|1K!yD>>i?&%>ܢ>$kϒd>x?@? 0? ! 0.>I4?P*$?f4?K.%=۾=M? w=%25F=k>p>( տ п5=& bad>-p? >r> >$?$g>/>ޜ]*=>O=ߕ > ]FgH(>8a?>X\>l9X#>x> ?F=TC[>Hw*>Gy>&g?0*>A>ўk>n;?l?B?E(A3X>,?mv>>r7aY>}>\?ϢUh͟6&S>r^1H? 1r=' >1?e ֽ?D? ?&S4Ѿ|<8*=]?4 e)vཙ9"_N{?o0*ν H>'D?>HbS>DzUl ؝>f=> M>Xɽh*<5"<,>:!?i2Q3$]I>y?Zf#9D3 >=^?V?+\?e,4᯿i'>?L?AΜ2 o߽n>?^N}B-*֖j|A?{,ǦHY|>ି'>=#?س`1>uNΚ۝^>uY> L>WG8>mD3߿u>k0? ?X2<>7?KIu7J1D4Ub>:`=%t/}`žvr>e>3 =Z% ' >@@Ϳo?Sgf=|F;=>̈@ `P='<ñ;=?`=Q@(Gm3v4eB05x;J=P߼[? f78.}== =?8Ҁna׊HIZw޾Ԩ>Dz>U<rD>Zjɸ> 8>?-?JHӴz7<}>>^>78~Z=#>̵> >`[ٛ`> >me? }?MWB;;7>=4?;J`:[ >*T=ͫ?HL<\?>T.UUv>6U>aO?U?A@W?@&iP k>}G>?Zh^^< H߼Jd==;Ba9?>Q?)`y=YR>2ʨ9==~5:>hOར E+8> op ^9Ū>\ȷqIܽ`:=>G}$=ь9i^e>qq5=>Hܘ?U??%z'`*>Süw5w$1<f ?#|s/:2A>q WDyYQV%\_\d!=fv!=%=S?%:?`>x=dc=$'Ռ>xh(=پd>?5>??jm?\l)+->E@E=ӖJޗн]S>ޠO9K > ==? QJ3>P>>_?N1̲u??ܺ? S? ϽY?->>0_>8?6 >i>f$ޒ0)f?FZ>j>%m.vؐ?=d>R0=w!X~iMϿ^$1=}b3NS>5n>>k?vjZN1s>>r>ם?y>`J=1U8;~=u2@= ;+?NgI.>b+9U?}R Kͼ[>w??? P~;af N q>a' 3).>H= E<>8+<>>S>]o?.4t45>U=#(=cQ?meԽڶ!W*>Mf˩q(=>ްN~Yɾ<>`@Y6+>!CDŽ`Ϋ@eb<[]:U#>Pn>ޱ~爽ݽ,5N+>὿|g5?r??γuvɾ?!???}Ubg7?5=RA5x>އ޿`Y7==ZdO+:TJuveF???4-='>'K<? .[jBPBL>ԭ>?Uo#@'i5FR)UMjO%=;dɦ ;:07>O 1#$>}b>l"let;h?M=>-|v;VX8w<ܭ?l??Lޏ?-Ž?w.>?|_>K>'ur4<ð?\=%?A :?#'{>?\Z?5Ĩ?BBS~m0?+?]>3="2鿟žU-fݹU=!.b=u0+B>)<*0>ww>ڼnV*>,?>)&:&K5!꾎?p>>lv|g=߹>E>v?!Tjd^k<>֌H>w?'5i0>#ҝu=S{{>;KTC>=C >| ǿ7==&ݳW*?]?^?/co%2xw"W?p?8!? C|IJ>ۂ^<"od3M>s>i?wB[%x oNb!a(=%&ѿ-->VN K-&8ef0 >X徽=< F=G$=Dt(U>Կ =rz#>>qf1>=ӻ}B> )N>W?v?9Z? zL?S?!s>eL_R۾+]F槾t>D_y>>& ?c8X 彊qq"h0Zq?e>^>u>Yi7k=K>a 1b>r~ؾ:5ic!?m>O> ,?O?o?AMV%xf6kY>~Zdwm=TG?f?/N?+(V?9V>>fQ&-`$J?jD?H?*.M/=G'g? L>|oz>y @>g>K<` !{=Pď۾>;GZ=;>^+X\=Ymewf?C>L>4P-?lj?1?݇< v`ȳ-??CI?&!jp=mG!=ŬN#}=,5ǽ"oJnP>:=qpC>GZ(2?%mE>n?5>ɹ>Qa )| }N.(%IL=h P3ytSHp>z>>o >w?5>>,>Ɏ?OH~?y4OyϼNU-;4V+H=B9$ɾ[C>/j` t$ >v$5>ݜ=:a|¾`j>>h+Y?J<Q Ar&>ȥG?YL.>pw?ZkQ(J=˸!>Ύ=,s>һιP=.:e=Z?<>EgϿp~нЯ?0'jɣ??7k?;>C)~<5#0b5P< #y&nAۺ( >#mϡ^d`ߪ>'wѿV;6fgB.M>aa9 >,=ki?@?-?>[-DVk[>h>@>]>"u r>2>*x2ۻsھ* ]˛$ōz>=R;lNњ!#@ӑ= oq@ T>=.];B~| 7s>͗R`" =A]˰87>%q A \>M)^DƧC?dH>H)p , .сZ>!>a>$iQlo^>a>[>]"B>'! %MEz]|>Ou>cI8?A>pP>(ɥD>AI>#-b>ZdYu>,sO?i?VW>9.z-? TV>lI=2lO<s jnW~<\=?QM}޻5ξdgG>i] cX) `'4Ӿ>4;>L80¿D1ӿс,>$EkE5z̿&>;ke\K o~d>`6&co/(>J8/5ҿ$KTcx@b@ vȀ>o>.=s! >HEc?ii5a ??y?oP@<\ŌLn>n~IK39>!P=>Q?Pc>C>L?e4wdhEV??>rG;׾?U; E>ɸrjL٥?\11HxYP>'%@3>vB+=0D>}J0 gÿڪ@;> X7Ӿn ?j>tCN ƿ#@09pK#.TѤ[NE`Ct=D^վ2½B6;OL&<}$\EAL-ǾU HVT0b&e&Uϳ1l>sx.=7~ZF"(T=d??Zzw<>N4H>fE?@z>*omE>p;?+s;=M0D=⛾ֵ-8X>GPÔ,ÿ$/DzoV7:=1;K")X8;>Y>>~60eÓ>{5>c*I>rC0z; J*k O@g0ڿPV Vٽ,>Gub8Q?>;fD#'/c% >aq0( >]}=)=?Ľj)=^|hEB.lX +>>K>3'3T,>~>lBc>U!{p==+>4J:f쯾 u> q`|pd=Pgkf9'>8\߭\t%&H>q5 5o=4nj=YcsK,02`2 >>v?U'xCZֈ=q=>z [ز<NJ<(1 >o=L=׮=q<>ԯqO=9d lS;>b-X=U3<>{`!>(R=$߻G>EA?@x`=jHVҿ!>C!Σ=h!վQL4&y n>.t3qF=LϾ:: 4lDl5B93-.yҿ9~BF|7^Pf޿D0{-Uml=T3aþ>),J _a>vE_34=M>M8~w>X| !lZq?hbI =諭ap>Y:?\h_=ءE˿=A> w?DHd B=ohԼ M@AF:0<~x֟ϻDnZO<* rdo>Ix=7;XExg4=ÿQ nٕĈf;`,+:IM$&׺>xp> Y=˾ldwD?%T Z=?ľ;wMP#¬=u :cR{;8_HJ A 1?=N<ȠoX 񈾲&B>8>G_ >E6?"L>4>~qS?Dw>i:>1^9wdC?L??c=fοS*C?Wo3>ٿK_08JpL>HνW{r{="ۿ*Y8j =H*ܾF~þ?p7xf=hpk_ x?vVGo>)0;-h=csm?iypǾbc>M>>bk8>"i> >9\^,xG!>>v>ÿ `>R`p*ӷ+, C/q༲)vI?r=\2E?Pܿ߹>34@ +N?6è>ٙ?O7" 7ݾxC7 QDʽ6O^AY([=$BN>hOS3O+>%Y|;y>lӾN{f|>5|N B üAj>5;GǽG2/=N߾Jv{?Br>NyƀѾn?^Bo5> QYvk?'dl>Nh..$vw>> Ďネ{?>!uczѾN? 1_e> qqZ>+ gG>!G;& ?ջ>% Ѿ?? )X>yދO?W=Q>{{վਾŬ?̀^v6>5,Je?́B(>jĿaBly[?5>aGkt%?lOH>>A>l>;?*?}>K> ?>[?M>>gj>& >v?C=>VC.=أ~V;ht:T?b:>6>B>ͼ>p?}s>r=8>>@ V>a> ?ė>+>/0>%)>?">꒿)0{ݾoI|Mf>4D`=23>B>>˧?ӂܿd!>9F=>% >>y?OiQ>0}Aն=> ?P>\19Ϛ n>yum? %>&>ĿLO>%>D>aFeA񾨞>"$>:>?]`<йV=K>U>۱?"b˽:=W>Hs=Ҽ1O#;U>/>&5QS~ԽtJG`>t q=q=h0wVI???>Y}cEr?JP?i?ZM9 !=C>>W1>k>f!dh:>& h>+و>2M>>Ab>6Q;ēB>? s?Ŭ>9n>#W H˾I>=tw>s-4?p >[kn԰Y:8>>>v96>H uK> 9S=T?p~k<ޕ>wj>>>$A-I>Ũ>>>e8>)Z30lh>R:e3>~(>1 U>]CD;:0>q>(|>^=x>x]VʿyBY,|I<4 >s>%>8?gJ#?T=?gi~R>u樂}X(Կcjÿ>.#=>l?$G> >de> N> ſ4?>m>| ?^?OlNM>L<>5?&#?jۥ>w=Y.%2>qM#<2׾ĆIy>XGWu9zur ,>juO <=W=ّ>1bA>Ne>e? c?T60Ƚ=LI?>ݩ?'=0=N'N8mE>1}|-M3#~}>H^>>>y?C[=r>3=ˆ>Ԅ=鿶<ݚFN 0֙Im>!> ![<>=Ir>>r/=XМ^>Kۃh'%l =gmf4>9by>m?F>T?y^p䉃n߱>eN@U1P A>Z-sBѮO QnA1=N>P+=>ƽܥ>?pT9>/Ͼ !!>.><{ \>fjUǼ>d ?,>D>I? >o=6>4@j2=p>l/=7Ts=d?h>8a !=抿.<>Ѯ.>m>e2Zp>l >FR> ?!q=ݤgvT$x 2\`>Ŭ>W>6ɽ?yȾA=E~>d L`tC%= `>BݼP>e?n`<>¾p>>dR>NJ> 6=l~~˿(\FQ֘,这%cTN@cABҿaؕt5u|ʨDX פ>G>>ؕ?8`3>H] tEξPL G>8>T>O> Z>cK?I{>?1Y3F`v>=/ľ'=>`=y1 3k>pNu#->9@=oՈODA> s8 _@v=V#ᗾҋn=AT=}2Wq;_1=<Ĭ[^=|׌>wHz>~*ÿkM4>S>j?k?L?eA7S v>rX =#>8 g? PX<=T@Q|tuߤ@Fz<ߵx I>~Jdk HgE~e= 1Հ=ejl~w{n>)sHoKО<<GI??qH?-h p=&BýQ) >8GC>as]=9;}dPZ-`_g>?L?,}?Dq.mn־j۾VO>d^Nu6νɾr [>չ*a CtG_[>s8>L#;ֿ6B= (]@=$5׺#tT>~ H<ʣ>> '>' t >}sCbg "R~Ks< >G 1*=rK ɶg3}>:Axw_-yu?$ym4=9i諿{NA>ܼ>aؿo] >Xʾ>bt>ʴt?V B2 [¿_wK ƾ/>X?kӾ7 ? eaP%@̾#ĽϢ? cN U"d?? z?p|ȿ#>?AG=GA_N;}1>]>fO=|>K~;.>*=E╧= zx<}]dI>Me"E>k=O?*ѯQp!ؾI>@?0K=/⓾g[>_?3F@F=}Ǿ?(??Vlc>y +΅?1!?;$=UwG[]>R=>m?p@?57=>Q=:?iU> *=s;yt==4?=(*Cg.q=?F=8u<=Ab(Cuh>ad>u=yp.>ZN{8A/Q>& =`t,=kc2Q;>;3>+lj>Ǘ]#1PW:0=<$Ŭ_>DTھg&A>=>Yj='W9=S?[x@(Epq?>g,$磽sMQ+5?"0g: [U>;`3[ `? $Ѱ_N}SQ?:])澨?p ~z>nPlOp%}li ~?>k~ rT=0?>>l>Bj#X>>r>Wa>ʓ)>a`>ξC ȇ<-}|k\RO 1=/S>\AW{dNm-S<t2":> NM>$ pf韡U8"=Y`[@ġeLDFZ;Lg?a1 Ȼ%ϿB#+>6Mm<ն `HA>53` 1=ſa+>w>=G @g=OTξď?RT\> ,{ >B?PFt?qB>?GY?uv`Oq;-??K?)e4P!AK+J\+ԍ=- V=}]a߷>0jſG=;~#=O]9J?3ʗ?">ϖr2>LFm>k5v꾣eE?F<>[0+?:G>Ǿxײ>լx= 8?kzN?DU?l]duA>?s`?L-?pJ=T8?L?]5?,M un2 x?ߘ?x2?;n?|y?Uy?)T_b>st=-sa[q$(?z??҅?@yk>)0Sx? g6 #Ѿ-ʾOh!?*ں)Dxo1ln?7r<$% 1>˸=bp!'W? pjcܿݾt?6&SC}J? [b/?q;?<%?Կf>)t! >e6@Bѷ>%(|t+1>?}?%?{8?(J=] e?"p5>:Ӿ޽>nY>X>2*Y>=@>I|VP>Yq P:.|?#1>?j{;W )徐<%*ǽ+4a?.X`>P*⾝qHE?$Sfp4cs<[1u+?5?p/<>;?C<) 3G=5˿h>>T%)Ɛf>$ ( >+I7ᄎX>S05$޽4¾ۡ>?"%>!$?7J>w?<*,>a>8@p? -ղ=!?B㾟?#=me UڿBC[˾Ɯ?a?M!?eZs?`?4^?I˛Ǖ0S,?d?:;?I7VwK?r>? V*%=;6 N=X`>!A>D|>>?O%Z??P?x O=C>4`>4\Iʾao>Rκz>A?,>>(,&i0;xOAl > W[=>3aUEA<@)=Uo>X$z)A>3XVk:8Bӽ|$it< O{y"?@p޾<7a5?!Ih0p=Pi?(^w1p=Wzp< ?09iW!1)= Ⱦd4>? >Xp'1s=@&>E1x+#6;*$>D.BH>j`NR>l'鿏f>]b z>wh+(_=ўۿ qvզS>|F6/>T>^>rz*^h? ڔlq>?XC? ?fjȗ>XR?f?Z W?l4s5#=a=>j=?d}3| @>> ?G]f0H;36p]?R>Jӽ&Kɴ1}>C;h0>V |N='yTJ48<=3>$?iv<2ja8 47=8?+c P1N\g4r;g?D3nE}C>CPǗٽ6?z?/:?J_$[O>'?:sfT%ս\pQ>p?8YC6nB96 ?>SK`R>|QbN'Iݷ?6?[?.MԔ3 ȴ=s>?Lnl/ZT>CV@О=H8~!>0>W?}=羏Xt!>iU= {>6-`<j=>%>DIs?ڿ~ >\]=iY>l.>[>=USS'^@0hj3=MU?W2Pݽ"G>?e50,i!==?hS! 8^ދtd?p?e}䎊Q۽7?naX#>( <Ք<[l:OT?ڲ_=s>k 2>n?JM_a_N>; Oj>sm-)ZY=n=qk?/9 μ?ν| ?3PD Ÿ$Ӿ#nǖ[>f: >6m>T>*>AK4G>!=6??C4h- > /=q~?Bƨk>??Ǥ?klt> ?k??J?,rQ> s&?o?sR?[ |T%@Ag>L;=Ȃk?RIJ(;QiNDt0u1P9i =]oG<0+|E$> /гpWd ,WX>pr!>ol??a/?@Ri P'v<8=!q?((OX4PG=' Wd"> qИ>l?.?rE?M#gK@Q ]_=j~Sr??mS,=RxzwqC? @(C >>*p>? @>/^Q"烝>(kE>"6XMc>`%P8>I=a=bR?p0(: >&d 5a>N|x4&>0*?ICJx߽?s#h>9> =lRὓ#?@ >G>>c>?7>z>yP>s*?7M/GF[>O?Ă?+?|U(*g>2=JT>Z6xa>)~?!@n$wve>+lroʿ s.=RfITF!>FAi _>>* Mc;.)>>XCĽQ۾*xlnAp>v77=-ؾ12mo(b?df>;>`q cV=j=o/߰@3=3n%ȾM>-U?^R8> Z6;OV~?>>(Tw翯u?I=ȿZ6LĿ%g>h???W΃:=4><[ =͈sm;jV>wE9[ݣ>E'K#>9%!*>7=H=z? Aؤ@XɿDvKA->1?ZZ?0l?N[=T>i>$>LK ?>tE=a$w%>JB>[nپADv$#>>(>4 =::(^+k+?f>>T$#f?NMn>4<Itu=$^'k>D[\=₾9ɾў>Hu T?S]Vt>^PEX=ν{Rqz>֌?ϒ>ƿ:>>t]SGa>_>Xmؾ!Etgb:Y$̾ 6?tcqώ==>~`U>OO>i?ru>U>>:>x??>>} m?6H0vZ?IH>7>Jf>&`_?$cGp3a?d?L>/xCSA<0 ZͿ"h=)`)G(Ӿ7@6G>BTƿ E=>=\`5uy) >`G鿔TĀc?o=>&]40n_>?{??>/} =!>Ba徵`AP ?}>4>'Ӭ\^ܽ-L?kDWs` >>?^fNqX =U?%8edSX>{>W&?i$b:OL>i>?lgf>#>i?[=nL4P>QK #d=QU_h>%,ج>_=L^9>)?jw>[%>6<1])l8??OW?)~Q,㛾 H>xkM>C@d޾_>AQ>¾dZӪ=P?9Pvm>ʧ=-Pl=j>W6 n=|Yھ? txO>9>=/A﷾~(?>=x=6q/ݾ?zl>z>OD# ZK%-?l>>@}>~_>?>]?T !-;~=Հ?$u>|">^9=JB>wzN>#>Z>\>e->f{>>@> !8V>9Y`?=s>_>4=Ͳ?6?%>>sO&>_<Ts?y?WK?4Io;X>RKx]>N>=2(Ah ^?(x?.?i\Mf?d?g?9" + J?X?q>?DM@|K"Z&NQWAcR>jVPVOEz>W<s!|p%>&ݾ±p?V?pj?N/'M꾎T??Gh?%NeI4eZ}?$? _>*Ǣp],?^>>EQYX??ʣ>پ4SpY2?Sr ??H67rͽ?sܜ?(?uC~ل?0?u ?X6 -=n ɼ1>;OaJʣw>4p9T vjS>$㿯[ 6> SP3Dڃwyݠ?t<? ȨGydxw>HM>Ek0>z?>^->>Sl><&?0 >x>h0'䨾*dp׿=&t]=Ύ =hk;4L=.i2e.9Ť>*u:>OGGc>{k:>}>>\̊>%.$Qb<\Ϩ =0X 1`;;^/n(F>{>ھOw5+;Pt]V>0ÿྋA$>ҿ {;Uυ>$.#+,F0$^j>Z?qL><:> l>A>{3=-BĻ%*mfM>>v=׺g=Nw$8 J={=B<4/z*!=HA=vj?zP[>^>1?F/IvP->VP>lz?Yp]h~QZ ;h>9 98R=wȎ@ȟ=?&ki> $bU~ Nrh6r> >?:t@Qt=?ja>~˛m>9e<?&1#pӬ>(=_x??Xʟ>n;GE=?6H/׈>Eؕȸx;`>>n>s2fꁽoP-Ik"?=\ļ`M@s8I]O,>d>%?#_pu׾ϰ>뿔>-?hҢnh%l>Ź>?Lm/i@ 1/{>p>`?%kf>I>wľ22*>ex7> Ld>L5tsfLs˾~.< =Vռ060X<0?dм ? W-d[\Md<=h?fX[\DV= =rϖ>WTUҸ!x&7 )>n[Y >:%=i<eôp?o'?`=?GhO[z;Z]n-\ D;<<Y>~Xt`>dE>^?/L(^FH"V>1>6徝\C=gu6>>u?s*?,ǰ;ؾØ<( =^?>AǂLϾ+$\>䞪u径"u)>XK`=ӿ5?J=>[&]D)rXIC>v<śDL>p膾| -w#Em3>MXjDȾɾ`R䦇K> ΗK/),DJ>i/oNĿ1J;u=X:<_JxR*Ӧh;VM>Ҧ>'I=@]ʬ+ >O>>fIhjwʾ#>{ޏϫ3H,},c> ;PGV96 k Lf=G~_otX*>AB BT> V٥7X?=mL4׿6Y=\^տWGc'a;;#^ĿRV?ao4;>i@p[?9_?(<s>t9Ytv?\9*>dп3}ؿOs*C |>lD{_^na5ȸ>=4R@U>Umi:U3>A-E>7ŵZ10)(/m>/ANV'F޲8MЃ ==d?U}|~>aiL]T ^)~!< 9;=*O=֕S=S>Sn=K+vU>/Օ6ʣh O>h5F*|*ו.c=i?.U$^NM>^>~y`@_y{i}l2+=Hq$e)T=?%5>&>_ľ<T/ *r羗gM= <6.=)+XT>=in>9h Z=ri=k>;2lP=F̣a6 eP >3Q>l &)!>/'4>T%=kH>%>JjTվy*(PY|>YN>x>I"?8g޳g =g=G=+N>h1b=8{ݿPZ쾣h=m3=[Vm As=7@kZKUd%|>DUҽv`9տb?>3GV >{?l|j> ܾ#?Y?yͼ>wy{>5P>Y>.9;;A:3 0" (>|ܔFR>>|iY4%lœ>V͚=,_=HY=ɗ>Wl=pߠ4Aپޘ xIV~D(FYKcmQ8Gk]phHoUx?< ?&Y?/#>@=1=U>h0(?Ai/ ҿI;r';Ҧx ?/4UB;B)_- SF1b4bN =@8fro>>?>YX?𬾋~ >> |>b-6rJ^>a>hk>Կtdﻎ6 Y%%$Ĭoe4@,*uǨwWF̾u?n t=) _ܿ,. S<>:]>ם>$E$(\4wپx>f>>\eA9RaL{=&>Xi>l>v>/L?&1b(Nw` N''dqؾ=S "t*\b_ gAu.?Wi>7>K>2[u>Ӽp>X7* U?Ft=aؿ4o.F|?la=7* 4_?bX>WQ+?k>akj'=)꽨?~1>CM5A=ڌS?ޮ}};>D=H=I _?t:>6> -?/>?Cn>j2>G? >?i¬*>'A=~>t>[}?a=۔>r>:C>_téTV\-w>PA3<@`U>Rr>f=f?.e`=>k?> ?Ap>%<>Mf=Y? |U>+>Hk? >cȈ=m>Q>Ek=̀A>̿M>b?=W=L>O=ŗ!!>\>k/?-0??Ԅ> Y88>$>Ve}u=OKb=>>Mp?Vw<Dþ=w>jY>12r>g<>s=WX;s">k>9O v>Xی>Nf?E >ǫb>*>C>:>랿^<)>y%>C?3?Pċv=L辬ꮰ=1ſu'9?;U?V}?JT69>OĵB&t|>=2{+;F> >Z3٩=Fk=dE$>l{.>s;!>>u?=T;>>+k>>"l=9>0>>y^.>(?>C?+ ܼc>f~?ck>eNJ0+rT>P">E{y'R>$ >O k\%@B=؈r>>zG>K1ӿfuc\>/0"]žkjbuX<]hz[/ҿ=*(=t%8=_l>}BܾߺgҺ%D^>&վi>?K|>W `<>egDA><Rژ>;?x|I x9=@~׺ڔƾ 9I؞`ؐؿ%,>B"O>Ѻ=;RJ#Q>n~QWI=?>bI=@?Es->񄾞=vu?P|9>mm¾@>Whq3씚=>9X>`x>t*F94I,=,sXv>_H >l?;>a5󢾽>$5ik[>QR=ط>u">kI 9j>\]/H=g='=G~>E>0J>AH>VPZ>=>Zoj_=)A]_Al>YwB= hq>;*>?@؎$׾-?=W5s*þ@ꇩ㾠g36T=!r>A>/b>hA!ղN8?8*>8?Ӊn 4 >>+I}4>Ya| t>N6?*=ǿbg1]25aiw>>>ߩz) &>i(=w>Nծ׀=&hÿHsԯf_*Ic˺-Mn\\M6?д%Yz]/<;]>4>i>!ֿ^?#xh? ? $J5?,e?J?#t2NR>>@o&>2녾-E>y[>G>/e~n/Ͽ9NWT&SL-.;4@@!l/A$r=KEH3 þ+=?[Q>G|\ґB,wCp?dww%>;y(Ex x`=? {>gzp rXN#b>s>d>|<" ܘ=% a==Fg>.>t4>T i򻴕Te"13G^f(=0]E=lF=Mѿ.>?zZ>(Fbh^_>0 >D,>ׄ>>$V- <>>s>Kmp(W#h"T"F>~nQ@Y>c悾#h/Z>A>τf%= ?C`9>6ffBľV=Etc=ʾ0fd>Oih޾Hؾk>icf9x Y>mieh QŬiL:>૓~{6>{)S$.WڽBp Q >/???A?8>`c #>=?nUNE1ͅY|X> aA̫ 9>`>\>7>}<==48<Om52##l? O'?lp> hޱ>pFAo=>5>{@ kZ3{+> $_[ܿ!_F >= 0Ӣ$>Yy。裿#k>>>>t=Y_"`78C> 4j= m.>HZ=e>$=Ǿ˒>>>F}OuYC%SYu>y?qZ1Rg>v2.{u꽁8zS :GE< ɿ~=҉BU0|B=]H|p=Ļ!C >qL#?3'M'=ri>ɽU6f=Ij=+:60׻%߽m|i}<j>*t%&?NP ی=wɛ7j{[=D ڿiR>D'uyJ.w>` Wt?t݂ܾ ?ex VgskL>P?ދ=:ͿGM8λ܏>{X~w>5o 3>z?g#.2C#! `? # ><žqAcϜ? 16m>v,ڦ=!??+?B=H >F==Qg5?TG^ ؾ2HRjЁKb/->Y?P> H U>La>J ⇠>pZJ= C>Ϲ?;Ew@=]տv(>aɓq{;>{>&@>fnnH!>fz=r>R/jm8av>G>(>uWi=]>1>}>C2{ʾ9>4>)^>Z!97D>}*` >_5]F&pj?*)} s>6xk/?#S[Sb>hR?,s>j>nAte=Ȋ>>AU>^4>e=#^>WpaB >g(0+>j.u @.⬿~S=oM^>ѿf>E^s\o ?,?>OaȾ?mq t>;$>?>_W> =R ;?jEN_( Ϩb)c>ҶIV1WI(QQ 2,=-Ak`O=[dJAEz=v\iy>ns`r6?* +čV?a?o#? JHYͿ\9>k5t>8qL>!K=q+e=I,#'>dhE(T=۾݈<w>替{u$=;>űd0pP> B?S?->O?Li9=zw`?o?]cV?|_ >N?rØ?Lqa?p4 S>eNn?y?S-?sA]?=Ǥ˿۔>}NM??$? j?D??kHX+?[ӑ?7?Q4S+e?P?+Y?E="CM>6k5>*憿?pE^=9H> 4@J94=I4Q"Z?+ ??Ta<`ըzi>y5=iæj>sL=_FǾ >`>o$=ɒ{{=7!w]XxLQU?X lP/Q"=ھVX>?X:>ʮ>OI>wPċ<|1?i=ĺ-l׿1? R> xF+=gݬ&??]D?k lzIV>>h>:m>k>Vt>~T=ld?'J>̮C>DP s=D-CW>2at=ַER=ʂ(9?#8>8=B>#p>H>IR뽮>[>@>S>=>+@|[6@&˾>ɸf`>.<>W0> ?7`B>*>Qb(>?8H^ >d c?c>>һ?Hy?.I?1BP-Sj`g>MIp0zpa<Ȏ8~?7H ޽wlξ]n>qDL=/on>}=+ >]>>Q>UQ큽vs>$7xwU&žǎ; >N0D>Zt>))COE~>M>=3=Eü,#Y>r5>D=<>aZM>>8v\>=hu=Xv ل=7ޔrP8Z' H0#8 DqF)V> fJ~0c;n|J4qֿ+?OR?o? 1GG<8l?>j]>TPp+ 3==) >fV?L;G0)l=2Ɨ:t:? 2f.嘺n!=P? h-=HЉ{='i=u??IO?d/l/<Zj>n?DοRD<<ſ=L#/q?J?g?} 2)>;q>97?-h1~g>*X>?p2h >? ?mXH-1=$ѾR^?SuHAW >@J?=J?Q 2R(V>?H?K?Uw`H)0н/>Y%5g$$Q%cgCc>HRXڽO,>@GN?>%r֬ϖ?܌??!}) N?`??vq.2c,i>jx0(!c5 P>JM,$V| > _L! =F>.>:yJJl>̼>0i>j2n;ѿ2= >?`>q>y] ~o=y##[???~!Ekf??Z?Ɋ@~==d ʼ~?DfsB@>\<G0>Eē\;->>>Wi>~_W޼eTC^ >̅> <> K/JT.t?$?0QIr\>\0>L4>Q>4 >W >H? > o*X\Ó>љ*p'+ͼ̘_=m= G?=ɂK p0b=҂=j'?=Wr&=s>d= ݾ@J=R2?$?B?#@S%@Dˆ؆ OtFJI+H 轚Y<9=\U?l ? >ōբY⻺K?$? >VwW=vd=+X?4=WmR=K=D9l ?A*0R+h}>Ep'TE>h%]P??%]p?<}ɖco?>?'>0g꾘"SIک?&<_H=Ja9?35]<{>#=+={? s?z+=ӽG.Qݦ>- = ؿU)Jpp?yx>>jj?rk[=T*iXC'?Q"I>p'R=X* ?`>.1d ]>>3Χ?Jb? >=$ټ)?>>onٽd3?>y:>lALx>eн )f>R@8b>CSEȓ>2W=0z;jƾ >4z.f<:Q15/>iIҼQ="{,jxw= 0XΣg׿rV=M/过w> >ڐG>Y=qE>?>m=\md=񑽯hWZ? 7Ġj" *AF>O(<\= >.;?7X4/ͷ=\ա#ecvE|8/= qھY`>l&(=\ђɿ ZWz?&&H>U"EeM0>7~~>?&>ц>I0y(m+?Le>QE=%Xehm= ؽ ">?O6 O=rタ1M"z'p59/[ᓾbоԙ(=_=WdM8V)԰V?o>>?",q>G="">c !W)+4EP^65~=l<*4?.~vQD[p-D=ƻVtR`D=&ߓ=4,?Y?D>|(4]>6Y>ָ0>?*$/ϿZjSC3&.T;^[~U>$,Os>3L>XzST>/>̻>V=m=@>}>B>N<8X<>KR Kw%>?>Jre=.X1>>*1?`ьNzrV>`=o?A`Qᓾ?>v>!d?_|v>J-" >$Ir4M潿Դ"J>\O-k=ꁾ3!`?&wtK^OT> d?Bv\J"<D,!? 0 Ukri>b|p0fxd&࿉M=Gǿd<>Ⱦ=dXj>qB =p,??Q>=úH>{->>!'>@n>N`bu&? %?±?,.GX}?+?T}_?8a:|"F ?'+>R =C߁گ>/l:\J TeTQq?Wd?S?7? ~ ڋL?~n?)?? E =<F.>FZ=FkDd>O> z<7>׋!i,˿5r\=OF?+'>/>82 8/>/f OTb>*J%j|5>}Y?d>y>>=u k>n^?4>>6iͿ{A#%}%,,8 `=6T;;6SҾbޱ_ᨾ   =澭>0M1w[%N>}.ina>K>['F?) j~>u>#@?*)b 4MU:>E>#?* "Tc>V(k( >p=Ē<[$ڐKk+%3˸VD'gMě>=7c>+ϾVTrk_=69 ؃/Y#< A>%3T?>Qe$= {?C% D>F/]? 5W5>>[~>(5?<e@d>i>X>_?ts>q&鿉'd)+ZYzJԬ*>)U=n*j=%i??^5 f>s N|? @_p=@n1>} |Q9= F=(F5qqmZO=?%!v= WFc=ThG;im/Zr>q=HPHPj>>m?$)S@VjF>>L?MV)>xw>& (!=}6? {głI N:v?%B u;Ͻ{e?v k x=b?63!>&ycI>JI}>Lu>vρ? .PYRRDL+>I7[wľT>loߵf[d ؽz?ċtBľX>2x>pT?kxoq"E L?u?&!?{E B:?jU~RS>G>;??$ >>ٿ ˿,߿E:.D!v+ = [>S.T=վ\`RS>u?;wKq>BE"Ͼ_ۨ> A֩žin>BĿ|sR=/0ܿ*P=?mڭ6@>,ߦ7 /-m+?#>Q?8e%|Ŀzd==8;"=05AJXsCB=ў96ɰ=~Rb]ǟfRe>&W2?~d?ĿS>!?wރfn]=52(%>>4^>7?Y>Ð>h>WL=c?V9>NHrj콮޾<GUeߴ`ʾ=a9Z}<$9>W>:6>ژVa_=>"< >y%OpG8=Հs>߿^>? 0\>?==t*;ͦ>͡'z==Ԯ)=>v{>{Mz>G>B>tK ;o>rr>KZ?{_ܳ/h< >f>99"?;F=z1zϿ薾BNcVZ>4#S2=MuDнֽBDDſǿ=q vݾ:Ǘ,sDao=L5TE>WE=*%ľ7v=V|2N>PX-<>tpA_>u>' =]%?M-^>)JL{$S>E?AL>L~(= =uslW&(%0>Jc?%8z}i>9X5l> :.> > K2E=*VіUć$}!aT"pdlf 773xLd-N-ayKyWMu,+WY)o8zIX6=x-^($67_ݺ=Մ?xJgn+wWEJ¾Max-k,A=L4ɾU AL7 =R"> ?~?}ݿ~=̴;֩=Fk?m >:ߵW=:>HI#Mjqx-t%MhW$Ҿ#OÁW[ͽ4¾,^c_=?=(j=\0#װy7aK&! OHiϧ&@o*Jp^BM0jV7Re xJ=t=سpf4>| Ë Oj)X9+K= =țR}sFsǨ7JOnW>i,+E=)@5?,> #<ĬB ľm.Z>U>L>$ֿ7P>f>J>H{H48~ >k >>J@G?L!=F.M>|w>Nn;Hh=Cp?HQg>>*򙼁`R>dX)W=,=[mD>6U= ??{1T> ~U7_}?oC"(=U~9‡+P >B>e>OQ,7<*=<>"=>BdH^>{p=Jʹ&sqx>!!Iyp?$_S=LS˿:/g;?ף >o/ܾEb<P=b:QR*˾_<./>"l=]?[ھ>,#t9O8]?O7>оپ$a?(FD> bB_ ?7T#!>wN*xSa$?ڨh>Z,m?.$>9J:_:X$>Qv\8e>XW*UQ=ľ@= ?S>2>RNtv='K=AVZVz?@cٺ>hɸI]=z@u@ Y(>=&>>MT?ƒU=x*V''?%==͎>ń>T[?T>.U>MA=)ʟ@eV~=Kɢƾa?ƒSN=o>(8~=(3ƿ3YY;*>>q0O+=̮꾋 F=. ݜ~<ם>C>9>NR>j?>=ʠV>v=*>0+>F?Z}Th>96>و>>]t?4WF>>S >>?IT=_=j>>/>~mF=?j?'?>Iya=8/Q>H?k?.>~h>?= >Nr>y#CL=a>ʪ>ti>fϾN>F>=LU/JվU>ZB?&?@1nuh ciNx %|ԾڈHD6$?X񩹼˿z*=K,-j۾&?68*>H1YtjI]A׏ͽ1!@j(1qe=m<g!ʍCs~==T@zS״Py==ngQf!> *Vǥ%Oj׾˖nhq->m>leA?rG>L/>+>$ n>#F??IӦ0վq'=\<'-=̾C=>=-'ο>m?H,?> >U*ϳ#@}3L`P]$=pO ;2ЁɘȾq=7 &$ܼν^8a?>S>o0Gž<>>Mw޽9>@>Ua߿HEl> = aǾ5iÒ>e>( k=>ʠ>RX"9>_a? D>A}>[e? z>E"}_5>?Ou?>F#>%%,'cRY>d l> +OL8?~>gu%'q> 7= S=l<%=S?0y>& ̾mzZJ1#>]+ξdIpX~2>Uҿ#]2P>=3)>TC>KԷPCVG`ƣ!ԌNT*}<Ġ=|s|O]X`y>ZT> }P$}`;=bR:ەdӢ{ؾEgh[;w尼X>a?@U>)o>-S>yzft{?ck>-p͹APa>I?SnD>#D$>Ķc>,k5>" Ľ*>r"!=E[{=55=2> otx>kE.g辨J ƞBkMSFܽ$0l'ܺQfM:k[>)Z q־H="dNH2@=~2>>u>;}o >#)ٹs>c@?Ai=PGcձH˿ >>w>f9}̿˾>>>g$JI!=gW>[>p(=td!@_ō?<Qko]Sžw>"=aTC`z>;ÃZĬGѾ:Tu]_,.%.KgK 9οt,"=.Di?.>⛍?WY=n"n&ԩ$3׾ܠ^t?4{s>h¿R/0a7j5l8?gw>ȗ>ˣ.=j/0mApֿG ?&>@? f^ ֿc[↿-%|>*c ?eYQ!< ?#q> Tk߿^+=,w}?>ϕ>bݾ|?8>^>(޽I>y->7U>>BdeV@>1d뷾y#Ⱦ>v t/>gL>"`-@n=֭ql"=kq3`ǀ>eaþQ?b> _3N~$;]8?iK"">UeWDk۾><:Ks>9 ? ̧>ܱh?W:)l>u"v ?bR꾔<>5?~ 9ByѢNvY8XH=zU+$,H*>9\<󾫚>AǛxj>>\>j+9u>>->2`Ga=z>>yum?;;ʠL 9> 6?$!Y`>F!2 6NQB>X@ im> b6!>NaI=2j8_}߿3F=햾 $ 0=ѿ\˿WIW{|J ~[>%ξ)>uGo`Mž=è>}?,)J1܏> If>?:n-jy>w#>R?'-6&0>T~J1'> :&|t=S3>/<->%->&E?>>(t)J>8&>}$q86K$=ges X!R?FE8NqsERb?:nTp(q>IP> >">s3i>J>O=>:>|[H^_+ڐ>e?S>ز?>2>'>}o=>lb0,>'z-<,P>5D >A֌ 6HH>b gA=ٶվ>qe>Pxm[=FпxwJV>=`!Z=?-><;+?TwI> _Cq Z'>} @>sO齅?% |>HT=HB!t?> =Bپk/>^Jn>D[>$}=V>J'@:=¿ 9m@>bkX=m_J@ ռ3?ނ6ֿX6z˾aۇr1M3>M>r?=( >_VQ^=>6eZ6>.-x!A0>ij>W>w]>>B>ՑLF6=&>h3[`o<;w:>Mo< >@z\p!ܾB_;R-?)*R@@>N1m>&?&=Kyc.!c=cH4 I>X A0}%?U>&?YuE@&7`Y?+} O fDF谽=1?>y0=لw$ ṳ#~z=t?}T?Vd?|.>?T?.?QN48?K\?$#?M>%+1?Lɗ?$?OH= S̅¾K>s)>'p69N> n>|S*,ѿ2G>_nQU>@1T6Jk>}g^?@>>VO>>>b=>W=1 >vy>>>lB>u>u>DA=N> ⿋cھ>>f+= >D]>$?%> ?[ u>BW>W=Fg>?'>i?=w>M[zbt>;C>'na=AG=?'ud? ?bb"=` >J8>^>~w2<=*^>>f>`]t>v?(r*?O7?D< J#>B.z=!Ex#ȟ>gJ4>naY8>*>?,=r>Xu>9>ɽԤ?7?{?qqȌI<?7 ??)9|mo9?DAh?C?9H$ :?cZ:L7?%?i?7q>JӦ?,? ?J?cc>7c?.??IBt=A?D?1?2^hPG"?4?g%>?|> =>Q? >K>܁  D=`v?,>.>!>U辈?,>^? ULؾ* >C>BL>B>N?*L>5?w>p>#>>7>kGm=u> >L>Ytfo?Xv?/?Cgw`|]?>(x>1Q$>6=^1?VJ hP]Oq= x= 1??3 ޼ ؾ8>٩U.>c9>^B>6d;>Ї>\>X |Aݾt`>0 ><>|#;wJ [? >чb>?ֿ8>d?={> E{>? >θ>"Ō]?dc>䁲?Pfυ>A>A5>*0]wj?>>ȽdЋ%?4׮?? 6_/>w E$>0>(}]5=>A)>r>7b*`%!?Jȣ?$?4B?1>K?|(6þĽ> x `=쫾U.>-]C >.Ծ>m>K`>du<>+Iq? #:pՀ=>ro >== _?[z݃>HL=R=^?$?=6n"55?,(=iۿdaھ?Nym=ǿ&̿O=OV=qN'#H?;.{%=5ҿXu3l>M>==tOn+McdAsD敔A'n?%?"z?5#pkc??Y=S?lb(ʻ(?n?9??ONoXwC? ?"??'9@#=U:=Kv=0?<(uK>UT뾲2>$%5 !< {|%>qGZ~"<DP]=98iP?_?b?9l]1> ?/ ?d1!y>S ?0O?P/|eW>j>l@?oa!*?z>`kvM½;Z?W(%>iE"k/8@?:\+h=6_N+=AS?4]1pC"eS>^P+z וX:~=6r ;E?V!!?*?,G"??~?Ts.\nvf>{p+N :>-剾{ %->L|Hh/Ͳ=踾-]? 0 *<[m3>z"Q=j4=8&?#ܾ5@?K^?2? -cv?2? ?>uIƘ57BGK>N?>*Mwf,>fϓq??w?.tǰ[=S_? fEQm44X%>fo`!-&[HP>Ήa"@V?gK>C0@&=>v? @]>=T#W>>A> n>CB= >+Iuy>޾i>""HC?O?0?cc =w ?Y?>혞mai>G1 q?\iQ??)p3;#?=>sT倽i??@?OH:* m3=\zbU~N>Y= { >派II >=܃=F>>z ><_ws>>!>X=(S>G?vQ+?! .L'8M4>@?۽rALR.>mI^ӣJ=4@=r+Re@>I=u=P9iӯa*(>7<=a$o(%&==<=?9>> >;1>eC5+ >M14({=2¾g>2@Ơ=mj<J>.Ҟ K1=V&rsGc>oKY*Z=TY)&=E@*e:ahby< l<5O`>$\=};>[ŽU?;:>=;?dU齯?7>>j ?Tz>k=\1gF( V>6υ=Z?QH$Cd%Xb0w>J]=O@y/o> 0;o V> xY)> ^Ü> ]@s=7b.>DV >l"վ4>IA=+ξʌ7=ժ( >LL˾t=Jty>/>>d=m(>'m?7ˣ?>2C6 =᥇? [>&>TUQv?G?%z>c?? o>nauM{^>^wνʾ>?mrSj G>z_mspP=(=5 ~?B]XE>x`>&>p>M?a]>P!<}=6xQC>qĠb0?X><>Chk=&o־|ϯ>#mVM>j9:> X@>?n,dsd>>!`>]nH=$bpH>ڽ%>sl`Qa>.Z"<][\E>Y=B>|ak=#3Ttjٍ?Î>0e F/:;0d>iݿSa\׮>dIYhݽ|=K۫>f>u=l3Nu6>o=X˰@gI&Y´ +N?mR>v=fb)R==C Nv.>d0>6"R40\`M>>!: >YOMw=HoT~?gL<@a,>$%=L> 2(?>ǥ>UAdIG >+`k>%JTcAs>=c%yP_ >]>Y>7b=d:7&>}[=X2 r/cH>:>a=\;? ~(>[Z=¾n>V:a?pv>w>Lg_s=]Q~|dDZ4@fƾLl>t 0ÝqŽ辛>d~`8>p>?MvX6὞!SDԾ>́>γ>>%,8?y&?S>,Z>+6yOCN?">Ib>ahfϾ)>?!xgiFDHw>g,? N>[A!> I{>l>A꼿 ^?|v}H? >?$v:ȟP7PZoQGo]>~HA=&xf>wGz4>6E">fb=r$M>6D~ݼN^?>Bo=  z=Ո>!0z9{U=\ѽ2>@='ǽK>;`Le@=8|_V< tgo[Lm ##|!JAZ`qXS2@#W>YPv(U)Ծ5"'z>|nf=O̴dqPs=>Kj4j*"F=m}7-fac=eZ"%v!EI3=5=X`i=;<uC_='D~BTa]VmywhWI(gwľ6N_}2߾c =ʺJ@b2n=-?[[l=ĨՑE |9vwpsƆ>C<:  {)YÛ>Oo0)'t׽^>7`) Y0>C_o~qÿO'c6Ak >' >ty ܜ>?8Mf4SR>E>H8?6kWn #پcafD>G<C?ȾJ>f,=7⦆`][>Ǜ0`m=zE 5>F':hv=sqv>Nz^ >/?޾C957;ɎTS?\} KTa@b9N]S9\V>>?.ՍPwh"Ծ:lS(1>bJ9K ===[Fx?z1(Kn ?X= @Yj> Kh = b;JV>n9.> >3@el@">M>Xm>E?Gxa)1~ >?C\)>@"J>EkcYƏ=TE=o?bvBP7>#toҾxǾD:>On~?<A>X1Y?o=XCh(F>g,>3ts>@!TT~?% ޶r̼RἙ>K=jyi>$O]5О&@=&>??.jFl;z>U>?w?$>>_Y>Ax?L\F)?@?&?X(sA@>1>=?YX`Ā?$x?3?:>_IJo >2?(>H(n Ծ,?'=g,/=\(tWuN2[<=U>9Gx=dd{|$n>b!_ar;1@[[ >a:q` 5uGV>[꿖F|ߍ=˾gL>ȗ?t>Gbt9=A'.j==_?w2) ='n=?r*\||R>4J>w5==1.=,|=lHM.n"9QEr>f8637=1r8~(>hDg7>v|SC˰`kOwCpuZ~-fSWq8iRey낀弮"VzLkH>G>9([e`>I?XZd'=$:mf0V"?5kZ=%pmOaxĽ)Zl}g۶<<ٺ;?sh=J>˿1=Τ#drڡ>b#O24'O<9> ?d= >RU< <켲>ؾP=п]fL)>0&䏗 xS>C>{5'>j/<美ѾݾrOgU%>N0>!M?J%R=>,|c>>P8j A־V\<(!=^ؽjp=n뾤B꾰xKBA=i蝌оܿ)P4I&DN\X U,=K?կH>W.22+,0N`n=hspc}[F'wͽeUQ$Jw?p='B?ܿ=R۾ɽǾU PW>  ҀRm7>f1bjW!0> ی?wd,>KDF}ԀT >i{\f{^>rNzCp=Z\">0ϽDt<Z1?ݼ^2>Oa$tG۾??V ]>a5>;n?d>>4 O}$>9>]7 V!u?>0\$ { F??O>Q֒Tڔ?ڔzm>Qq\D9>/~=׭?t(1>)~>mv?P>1@[.8>1+GDp=ݭ>N3=p>iy?I>C@a]>X;j6>=ċ=P>L=0>Z>Q?)>o=e>>澒{o&>>?So?/F?rYڽ`+<:d>P*=T[$` >M>C|?4rK?ᄍ`[>>y?>Pe`6>{N>ؽ?Cc?d龓&g>p*>>>wL U>D>!O?*9? ?\_]dM=A)>}v>&D?sˁb=@W>w>T>g>b>è>7z>>u<@J><>4>x>­?*|_R3>d>N>`J>IA?sCg>,H??,?l;i"=%W>m?}>h[߾g,Aݾ{=sż7b^aP9҉}(5#=%5O"=kPD?T A>CB>?p?>y=cD=βJ>WE|>?k>g>8>x>+؄)_=}p̏_7y6vKmXɿ2Vjݠ߿⽾yXHKvp=9>%ȗ<3W=fg$&,<>S7ߦY>n>^/Bg=uo=Qe>^>@>r> \>N??MϿDPU9e>e?K֦?? ec=>N?>F?2?|=?=M=L-р<ݾ0+?3;?h?vμ .l>d? > c&|I⾹?Ji??7 R*W?)"d?y?oخ~B޾"?W?c܌?ZT `~??e2?Z=>HvX=>T>>$_:=?Y?h?_s>`=azpa߽>0 u>-h@)`>>c9?cA=|R>>s=l>X0[5VG>>}>۔uO= s&?BV??tT?7 =g>a>>΁ݩ6<P<~|a`1хI՗jZ}d/Qif ===`BWgV==},?1Lʗ=>7l|_vB=F># &ՏQud>>D_(|9!(|>>HD4=Ղ־^Tq=_h{<;>>7+>&X>\?p? SI0@:=ҾS==])zm>վl Κ+矾(J*>˿pB_]}U>g< _=>>Tԉž.=sԿ;8W4`fM>}GԿ/p߾Fe =$"=X#B%1>tRwÿ[B?x >]¾^& >I53WeuZ:I4>>?>h3A/>̧@ٲ=8<4;>Idc+=O.ؽ=ŋ?-AֿU=!UP=>f֙m=+ʸeq^FhORL> hZhw?=_j=*,qɿ=_]Qֶ薫%>>>oYlؿ ;z>d(>+>1YX@m>a >KM?Lֿ F>գ]>V>ũ"o3;Znv&=N)q;=.Av/aKZ>h >Lwm>}(JfA9=wپEE=|abeO\?o>DFe=j>!2>;~>T`M{ɐm>>51> @Պ =cZNɨ>?'5 ㆾ>5Qr>4D=‰?2kE4 #bh>r;ծf0>D>1{>@l>֟O}>Y|Ba9?Tzx*>d>>2f>&_(t :*>HF>?>A>T >\k? >(5? ׿=_t>>Æ+>n v]-iL`jpGN>>=>QB-ٻqӿ]Z>>n='ȿl>wu@LvI=fѫk>a YvZW*ل?3k~=X+>8n_=h վ֙>#@l>?>.I?);`Ɠy> rCG罷?ǿ<ҍ _)? SX>? , j;S<^?6B 7>8>?w`ӎǽƿcz>)J%Aq@d¾щ>@{@>iuy? =~$>\}>]kRnŗ>X)z>>>߽>Z6\rٿ '>'͓x*-!Pz?:>3iwnz?(PH=5cݕW?$r=?PŹ./ >ѫ& @p? `6fz=r'>ּ&<4>>>U\>88,>?.>P?3=t>xO?",#>N?%. >Xž = [?Ϊ />f1"? D2M>t4>+E> +>78O>o3>h=> Sq=>WN=r>H!lk A*ؿgA}Jbx&}H="ѿl^&5|d|=œ(><}Iu8LC?%p4̝=˖P 31=Eq=QۿRʣ^>s4F!>0M3Y=YSXZ!DD~>$QP뉿+خ>"zcOQv> 1AD>R^" @V=ؿ\w=#= U?*?3?/G:` =<@gM?43g`i<=;-u?q Z{=!>ż-o=fq"=>=>Ӟ=T?.T ??-5w%? aA uPo`?/?A8bm>53(e>hu>1]8 ?B^ =KhOWG=7C\S>%;(6)'>Mo09>_q3_ήS=VEž<>?c?<+ g0>ԍ><'k>>b=cn/>7Tm c i%2=7?~P2"!0a?a̰>[,7b==ӽј)mѥ?C#>!9> I>}_?t:of?hU"?B#K?WocaFU\?FN?!s?:ܠ ?.T?_?_%?*?3JE? z?!w͚>#>oP>y @GP.>3r=E $>>Gkv(o=??cp,h'8ھ>>#@ d쫽˽? ƂJ"(8-0?,L޾-8?_ ž-5z݄>*_?/8e>5/TV<־D1>89>jKe>\Wi{> ?! ݾ >Pž S>̥J"M? >?uVp SK 2>h"0ٯS>4+pӱ׈#7>Qgk9@ݾ̱F6>/v} >h,>A0?b-o^>:$>*t?X,gϽ' !>12bQ*m#? xhRBFd>=_ >3/E Pc 3HR>`l>7ah{>M=@>֨>">9$>:{@ >f,!>BpXq>ˎ5U>Ǿ >{D>>(rU">?0 <^:X>M` w?C(Ud>*l;,>N]B>47jnv>L>>Usbf> ?)?)=69> W8>x`ŷ>;>:>T?}gAK=>X>aҞ??$S?E>>;2Ͼ՟Ӿ>2:*>Gp>X>R=B;́M y>b_>=ڴ=b "K>6ʾ!h>O3^@Y= , "=1 3>Egb>Dz[`$0>l@ꇽN[B" i>Ϟ%-F> Sl2aLf= t= W> >0VEn>/o >ǽO*> >6?:T.> Å=-¾ J>(ж\>z>>lPH>`[5/Ȧ>?>3>KNj=Ӣ>=`=Xa.M =?Q>>-b=53?/YG>>̐+-d '>;4>ڐ?l('-ei>Hv>B?o}AD-$:<@>? #?',-Tɽ=ѷ?+,|J+>oL>*?]-ov(CJfD>p}=YC߇u>Ib!E=?D>F>wL/>0+>QU?j-Ga[R>>%h?~,+!J:YK>F?>Hl@(JkQHoC>Jp1a@ Lz=轮.[ ?r!z=*x&v!?& ŽߜcOW=Zi(`&a=6@d9`pk8OTPg!!ZB˸hwxP,3x^A.>őD%^=2]<\=?;PD'8=ԼF?8P8 =^)=J=_?5bk;0ٽiD-t?= N,EBϽM^>Zy?3n,&=ݔly>oS%H>+^ cӢ>co=P>Sڿ?VG1]>NC{“>.Ҭ>(ӓ> vP*D@M׾E^>9BT\Ⱦ+T>e& =6Zɽ3>~1=X >oNO`?LW~>M?ˊLj?feZ%K>x::@8&82u>7;4#˒e=aA>ƽ<׽$f>c_]>oX&?Ⱦ.]U,>H>u=t;ڹPYzx>+e?>I+=ri' B > V?%F=>o=sHts=@1H?A>w->)7%??bfp<ik")1> ApG >,>7>%u=Lof飐&>;IOҽV`_w>:A6弴mƾ #K>P49> >(?;w>P>9=#FG>1>hN>e>t=V[XDZz>"x>µJIKNK>>&=1'$?:3e ~>3o=1>5*#R>3ixO+H?,=} mžC#?.p>xaf.9EԱ/ v>ト׌5>@=@F׀V ׺Hnp1=\Ƥҍq>[d? mU>>A.:=-d?d?|>Srw/>c ZrX>[>4>*?ߜ?=?֦m!>V?8>1>CMA1>0?&L>Bjͷ(?I?O>am[.YS"=m O;4 [F> }zX.=^J 5>N#bIQ=ҪPLI?WLa-???O>CNO ?>PJ>š={E_>4r󾮞>&OVg=:A{a>T~qqO-=H5$:?M%>EY([&Ը(u>/侌 ,=0"+=ljıN59vx3U>Gپ=FJP?H>t>bv2@>z]"v6>ID4k=-5Ơ6>j&_֕FtEyY>о8\e?>DB2kU>l>Y=>)>=(Xyx=Z!^M=8DȾ0=㹾}pA'>+п#+w]S?{e> QWXؾ4J=>n>?HSg?P>?a}I8=O01>|#ZE>>5N<^?Խ>Trvn"j#&*>s>MϽO*D-6p]>Q =?2Uj$H*2>8>Q?RTo>"kbA>`-T >C>.  &n'ʿ }>F^hzۙ_cI>qZѿWsHZR>-@ݿ]`)Կ `>>k=} Ih+D>9>v6e8?E >>a ZD=w$>:E?&햚>]ENji{=[?BP =\:4D>$S`M?-8aizϾ3< _=Ϳaxǰh ZB@}?.>ِK>~o/|?e>=?FU= -Y ># 9@?7mUo":=xU>9?T[Eu?I>=l$F$?jnv>m]>8Z< m#>>[f? !S>O>3>hg>(>UL˝>ir>1?9>C>;A}e>Ɏڽl\n>6Q~ſ1<6d7ba'Sҿ4I[%ao>zѿyY>p=ph>_?$>Y>*K?T=VSpPWgo#m=KĿ2&>Nn=7>^rw>==\Pը+PLe#׻O5mw6+<~>L>I?6Ӷ̾GD'@=9Hs&>|U`_W=Na`[y>j'a>{TMyYsGڽb? ?3@G>| >$>Ȃ?,E>m>/>?D>,>>:?u-Y=VG4mԾYۍ?8&Z ?]8'>nӾ~(} ?[:>TmCA[[=d8~>%$M g?"a`s!>>>l?6=vZi=yݽϿƾ< =9> >}Wy=uC6>ľ7&>=ǽk ?(g8>,8>Tغ@rW>BI>F5aΛ 2"7F$>>~?!p=0QǾ>6{<+Z%>TeQ[`=>4U?PN-mx>p>Fh>?m)xO>zX1 >T>k>m]e>]?bHi>.yF0>knmvR]>5 9=d G|X\/^>K==F,ԄQ`!>oY>ԕ=`Lh )C>cC=T=~ne>InI>qp >U?&ʼ?yV6>pm;:?ZK5E2ʾ@:(ZWYNJW޽k) Ծ~Ne!-J"}~L {W>0=qMۻS wٽ˾4Lz0v h^>!> ?Xq۴ Ὂ횾m߾at=a?}v>>ݿ|@p'2ԠE˽R\龂$> &)h1wXqD!=oOοR%h? g>s>?>5;:׽ņ!04,1&0=Ӽ矾6'9[*8]lܣ>*>;Qz=*PDyT"_[ A@K)@=m1> 2#(rHxu }y>3<#O>NQ $)AaR罠Ifg5Ol{xfvKѦ?on>`ͿfUcg?hxi>Uh`ֽ6 PkTMoRhg')JwkDXqnzmHO-P=o=>9>I9>˿!G>WZ?5wiD>VF(Q N1zTнY^nUзֽ }o;C>FH@3>&{=j<>Y(uyOb>PJ?y}f>>>(V=ߒa;Ԉn>sEaa=[<-=X?A ->K+4=G=r?D[5=v1z6i_ C۾F<,==YD zPu+g>Dpvl>-rsVf0> ;aRH>b| )(?A=(i8\B_Ag?1)8¾XRx!nn>䊻G=lL;Ϯ~?U=7A7ٿ4FA,:"G,8^Մ><' UԿ?pH(=q71]SH(>J*')ο XaE>[ DпIdj/=bԽ¼&;2>C >iM.-ÑOT*>?8>x L;m? ==Iؿf⠿zGr> wk>,N>~]y < F?LM=ʾ=hǾL<` d@}>\\վ6Xj5 ںs? o>l?>2B?"+>MLuf;?w >gMu.= ?X u>,H=Bù@ >dd>`=ގa?nK> >ݣ?:? n?R>;>z)= ?f>_3Dj?>y=\?6>F:t24|}$>"P>y?m>wRY>ڃ>?,R?j8=d>z>?;?H8=Se<C>>V.?ڑ]>G=>r@t>u~= gI>]S>>P3a3,>B>S335p~$=gve1;qT =zj1= =>su>O)R=bའ=>&)=ſAM>y=>ή>JI)1>f>qm?%)E?J@ʚԾ_욽C>F<> <ſ6:Pk>`?"f?a8%ܩ6 <4>U>/(I=>\>Ϊ>ԩx>9?)>'Ó>:>d$@"?Fu2=q;VXXcdVun'aj;߾K=#=)ZݽkL>n%B>fUA)co>q6>ST=;\>&>ͮ>>q9>q bS`?[>i3BݾD/>C?6(}>8 cdYQX> ~i傾s5ez<%BR끿^0l>8sK8w9>0Wܿ1Q_>%-7r>_=L?u>$|w`=Of>T1=S쾝XX.E}$L=b|B[[=inWd%bt=h?qgQ>,=S!>6nd*= U>7>+E>?fh>d=F>P?ch-=`-R=\[K?l*> z  >?}l=2˾=?&t>#H,+9>Ҡհ?pnj=eJ˾WMYh“=VRQ0K?6&3(=.% = =>B>>?C  $>eڿ]ok>=>g>K;Iͼ>pLQO>9$pfa>0`Qm>? h&>]Z͎"F3H>0D?V=M2r>g1>*Kwb3)~>? D>%E5eb>,M܁k89c>wmL[>*>$gnȟ<\ 𾌊Y>Rvf)ǿ0FRQ>;`=>ێ>5>iw>7>؀? F>?+>C>?1̧?(?.:(爚>T3>?f>I ޾@>2 "~=çjf?}R -_=͖?8Nƿ.1>p;>^= >b_>is֦>_S~n>2?gE>g'  >ݿ>>1V!???$np\{>?>˰?:d^0kd=>k?S w=k׿JA=Q?`}=b1V/J=}e>^>ƿWb+=wK>|>?O!%@ ^ۥ=>]d?*p E>ie0;lz?/@N=w~U>SfvĠ=߾o>3@ow VQ>L+3n>u>?TIÄ H  >'O/@%Q>&> ^ S[V2>;׾/l>j}(L>;?>{1?& c=>H> >n+ S?m>ӏ? cMSr=u=Zd>X!]po=վ\6>4 ? =ϐ\>ӿrK,4܃F?|u|WJվp?Q]8{͟=;\􊜾>>n'xr>6` vl>Wmr=_`x0? /|>s ~5>"v=?1?)6;4ʿ c~>z gM=^ľ > 2mҾ:>@I'л;>\_>)> ޾fӾTU>.ǝA΀?d>E"H=ژ>< N| Ag=p">ڿI8O=aY?"> 'C+ ߞ=ӋHx`?@T>5쿋\Ծ<.=,r">.K/Pv9;d>JſwE,>~B=>po L(=3Re=맿;澹>%V:A >: ` Ʊ<ӿ7o >HUbj<>q= >z&ˆ?>³%? @,kF?S>۔? P)v.Z#?>?SI~>N>'<%vG> !y=,#?9f{`n>U=Ug?QG`>C !>`!]} >_)W= >2<Ƚ@P=V>Aq1ۿwӀz>9yL>9_=9ɽ,#=Ku> />c :W&>^ċ2<.澾 A?#(T= AMb>r=0 ՜">lw޿AҿG7= >jݿs>TV>,q5>)$(.T=3>??`*ҿC{? ?*v?O>{i>&|>?At>O!>td?2va)_ >/yh ۾}xboj>4}9` %=EB"vvh W0X\x>K&~m 9ξr[>F r_PH>Hpu0 cܾ. >!-w~p [#ȗ؂k=0U\0Vv t>V3jp:eپu==Y(ShRvA8h 9"/<k `5m]ޠw=Mx &>FQk 6E?hd>0oaj`¾Z=fW TY¾}p=.yH "Bp6o| ƾ4>6;it*n`,ڐ[BJ qгž=}U0 Td>DXG`@5˿W~>i?XpIfw2G=~G;0UP#;˿>=HҢOu󥱾P8|F>::6+Я< G=A/ $`㴃 >~9pZ;3QՀ*3klD>LJjUtj[>14@DrF>L?bо;9a&PQnׄ$xB>QWcEE>ÞUླ gZ>2M2f4|@>Rc a6I==K>?1EP敉/X.e=>2KΒ">}>!G;y_ѱu#Ⱦ>W>+̾$S>9S??>-Ti>EMؿ+$ )Fͯ<J4? F f޾Z˫R&>{t <>dWgU >i3M>|_|⡶ף3=3+0^>n9q׾z=^I,Ÿ 7"^=>prý薽Y?`5=>LnDR=>{c||>`Ҩ9>]m>v2<>f?E4ᵀ3w?:.>Cy1=D>>1?,w?S=3>K@j>AmK8>`} 4 ' _ܽA=3?{{=^B)H'!_̯>`>z ?J:;> X.=(>D?+ ׂO,F?>???]EJ?PҢ>ں>`?c{>s*? v%`UH ??=?Mz\'*ͅ=?1 }+q$->Cc>??)*O.>y?+?5нmƾ9`>q2<!?m]>m`G9Vy?)k>ܜ=xU S:uP> >>>:?hŋ>|g>彮䟽Xu˻>ׯ="=*WѾ7?3?+?F})츿'>^>5?q#`+>}>^)? P=|A>s<`}=*ۿdlv=H>, <&3e4>(O31]$?j>>ʤ? |A>?N>?Բw`(+_>Z`?M? { (]*Kq=eZ?'XP'߾qv??"a?BP+L^>? L?$d=AB3zq?yqP埿 #=>0ӄ=r.MT=b!=>N?B"M =F=əV>?9mҾ.I=y+>% #=/?1:`IH =N BNY%:qC"M;>.y%=AA>c7(> 1Q۾H>dTQ<c=p<?1<"ݾmc>BToa|fF>q_==yt?Us>颥> c>./{?Pr>+g>)ȫii >;K?OQH>>m5L!إ?e[>?%T?>R?DYץ@R??n:*?dT=k=?t?I>fy '<6?Z>>kO?Tk>cz>?ȟ'ۅ.?76߾uj>g %_ý-M>9`@"&Jֻ 6T>pOdGM.Q>1?EFzm!SqY?jhW}Z_>m TUap@y&݃C >%>8EF=>M+>Yy>`Ϟ=g=&>ZLMr>kj{ >b?~>Ƚྷe4>[Ȩ*н4߾Hm~@>םӑQ] k?|Z>!Y>$ tR񪾒 U\>{N+ >o=dE=yٽɾh˽à?@?x>xUI4𕾀,M3>n7O"\96?!`P>;#/En?-X _cAc?>Svp7>:]P>9ڽ0e>Oo>3-ܿ$+F>??@? jM0'<ˁ?}?c>qbHѽ难81>@bGG< ??P ;`=&YB9>9\*@ = U->= v='Pe_x?&鷀= ƾ?Z>F%B=>?[B?K? nneF/Z??' >T(S> ==W?6p=> y=M=,?L(PD>ѕhd>}9>O־M>qkRA>m=+?Lхx>ccs [?b^>Kuҿ3?b x>_z1U%0:?#?>Ƨ 厽K?S?bG?1t 7L=,?q?Ң>jX@M/Jf>ML{> Re%> 1HA3? k8?|?%)$>c=$?6?PZO?!yq0L>*|[7 ?K\W C>=nÀhpB=õ(Ϟ1'A0??{9>z"Cƨ?s>?~!!0@ǤV>>N?HM4DA=2w>J=?;6tI`->bxK=H#?R?a`B#>j$Fp57>N<04N>i>I'4m=+Xt#=57=*Rۃ?Wuv8D>Lr=˽p=?{tfKx<~k={ L:>A0?$?5> (IY?? Y>c?b>d> B72/>2qz ?-<n=}>=C?=r|< F;½$>B(4< (>fQ.;? :ͻ>K>MK'D(2 ~Z>M<ρ?@2Mh+=B⧽>P^lW>?N>v>+Xgl>}^J>=CBttB9>{B>6]O7YIXϒ?.oG`2oI>«=Q?O0#wi=nƾntm?u>&i?1?R>֕>X>삿f>O'? > e=*Y: w$>| ?&>!v="Jg1H=-rS? j=* wGR>5ֻ?A=_=n<)пTLQ>Rf>+?uX>uh>)XHsn귙`f8mvu>`1qȾJ}|84L:оY/ T~V85{ȾA$@h=йܻ(澛Keu>~~ >\>,L=FUg>>y;Ƚ.+ c>,t2>£=^><Oi=C>,8*R(-[@8W5KIzya=fiɔ:$Wk1j 8j";=}P=A,>)g(os⾿=VN{FCF>332o` MHqA,3/]H@mU.>2Fce>m{CPe>8/׾ ̾i8uH0>ciɾ}K'aп M͖=3H4 }ԯe;=ZRʰ0f4=7b>I=mVt>AA\*?.h?!+?u =fV̅=ƁA9\> (pf+>%|>VI>??J~>u?9C(*쵻Jb ==r8=^<!?˼΅n=~AϾ>,>_)>2>t?` ?yX>>gb$>\䨿npH>%>4%9>?1njjn?k5&>0ѷ=j1bXA ?U=Ҽ0ME?њ?!)m/>13Vsi>q"lPLcÿ"JP h A\r:ڿj)Hda׾nM$eRq'!!u=h>C?r3>I=-=7?/y >S? F>5Z..!=Q녽_Ӿ8z[b20n<]Xݐj\޾i߾ʂ<>M=>4b#>֌`T.= |`x->"x}o>UJ~.#v>@3U42=K>9=֌[@+<\>dŗ>Ӧ;*V<69>bo>&=<K;k<;>R=f{9&5Ҿ>)>O>4=ojEe=FV&;\>W"';ǼRr[^S-4L[>>=T=e%X=X>kn>a>0ʄ`Ij:UsM'GVem$z9?]5ſ!^eEh"ս>>Cr&>..&$^>*#}> q>ЧΧ>S>h!ex'>Z\>΁g=r\>|>m>)g7h9M>e(>"%>v M遾g;9` ?W|k>y21&T>+4?a===3߇e s=2>]>¿w>n l~82辦o!0s?04޾>6&C? 3>Xf>>g>#*BDVx;2]~~RֽLgY'پd%QܽϞ۾GoxVTo$^}4s^=>D~п:C̾w?I >ti< p 9T*VKDv>$ǿ/N8)J>O{ <־۾?$="xѽ+V=žrb5G)p00},"Ϳ@x>N˿A^>پ ̾cM~1vW>iQAs}j=3+1i2"XQ> @ 77M.r=7A/0{FdAD>7 &ṿ5c t>Fm/=}rv>Xu꾋nNֿ'>0$=ҍ98;Gi,>^hb N ?Wh=MwߋcbDH>lXb|x6^qv>~23kLϾaJ />o73啚ƾ<>e9l/aJi> NEe>P:K?!-=7[ݽe0^V>YQ =uR>C= =`//=c^=?9ҾK¾*2 s> ;:{eg>)> 6h<(}?@>ؾV[!3x?MH\>9 R,D?Ҿ >sŽ=<2_c=?d> Jǿ Bz#=D[i.j>}x^=! лa@wiz>X> b>>k?@vG>j!dw>3UG+?i>`~/(A>x{={bA?S6>^ξs6;WѾ;k?B>O#>oTL=._?ʳ3>{e#i=վ=@Z>]>+>7;׮@V>hsc,=Z:OP>"5>?.!d?Mt'>:~>e,?>K>*'E>Mb>3Q>E>~>`'J>%QE=x0=?h&"2>t>OAl<s|9>~/?4>U ;A>T?=/?諿' M>?>>#]派Dt%^>+=>}>d?I?+K >k?O?43C2>B?"P?}?O)J>fP>^? ?= !C>i>bM?Qr?JC;!>gu? Vz>9C￿w)O=>`>?Ņ P=V2=eȿ I=Uk}1ojvd;ٽ.>b>J?qnT>e">Mv?T>ŵ?Df>3P=>*>G=? >j>??վm+> i>1?2?2ieu=>?*?.~9,><>:?5h?7E<}a>Ks?(?12ѣ!G"Fh=F>OVYCuuj=4o?Ks2HEAίi =+a=}kd4=,@?k=%9>jl]>K R>M׿Y'^$=?>_g'^>9r?>Hྈ1=7>-ዀOgAUF=[6'F'-̾fQ“RQ!n͙ Dg/:=,<ڡ>ZG>0CY==$>XC>;?q=50=3=&fi)-5s lz*-(>C*s`hܾdz<ֿ=>,s?%_ܐ=3>h+>=>.A>=>F>>r>N> WoĽ; zB>SM)掾\uŽ=sa.ŜI=Jֈ>#r>T[=z x=a__",辏*/X:v@\]S-T\<)>>9 4fw<ӗW=b>B`c)4=l>z n޾6)Lw=?@?u>Р!><omgl׽=*>zm)Hs=X:>/^JfѾW>L_|>>>4FrEн>%>y֮ niN߾3vOg?>,P<4>UH>Of6IC=fK# o q~o$wN@>HwAxċLlӽ>;{Ut _F|7> , @vm\+>8&{>R^=WZVq=;bJ 9?5j=ӿ֝>J*D9[> t>>޵N\!W>e=_J>8J>!+z>W2$ ؾ%%=>u_ 32I>*>&h>(\mgȣr? *=8.l=Wd[>J6IpszȾj&彌-S>q9C[AX'u=+ T*Խe= Q!矼]t %}wBs־JϷ0_=\% }lh,>m(|j Fm>>9᱾iC7T>0.#za 5BI>QvsP,KV`>KŽ:>g; yKvҪVHA= kVLj>3'$ff4oƈȠO62=F=bVTCN>w > |=!Ծ>F2v >gk>q`PpV>)=Rud !i;2=p# |VڽtH >@ @w-0=X⾚KwV=~<@#;>.`=}4=Xb>͟vUfAÍ(>-ֿ15UM>Ɣ>{L8>2{?;f0??;'>1>P?O?1%?NK> >m>w>|>ـ $>q>? +V>? "W#{ [>N>_f? ;: ;==G>wuԐu =T>>] Pj>O>?q=2} >Dk")ړ)>TC6r>?oy>oه/R>G?X>}?"!d=.>@!>D>!`v ȿn~=Q87,3/=vfeq$>>r'UX镉>~ K=[W:G=#<`ݿ ;?A?(*?I"?H?S;?&o? s&\-:;=4?$>avj>7kbr 3_=Q w> rj=1X4(z=f,$>J?=~??A~?Hzeb;|'>h.?J=$d%b> y=oBq>=>a>xFR2@>>y=_XƿM]T><؛>A򍨾Z>ۃ,=y_:6>Ra,C=?O>`=3!վYM>g0D~>%a>: >2~>Cٔ[=F>WM>ߧ>>ڗ}ԭ$ >5P5ʧ>_>;;2=\y>B@ >i7(F= MIU=D>UGrҜkUt?>??>v&>b$e?d(?: N?dqf3?>"?" @ O?r?I?y,bt|DePc?v=JukXCp I=_;wu LM=3`J=zSQ=ۃI紿k!0@s=".^Jǿ.AHL~>쿉,x.0=7>DRȰuž/2mX*=j<>>(g'>~h WX!?`?7|?e:>>j+gA>[%p>e>>5v;NyIb?  27X"p=>ЍL,$kqLϾH?P 4,1?/ ,!>4HY|>/ 5:!Yz'?bZ?9.0?hKF _>\<|,@?%K@2>|oӽ?9֩&|T<>WK=d'>gneiU3 Set݃t=UqU%@ _ Д澐{>œ>_ljo>;ݺ?@h>n>hJgA>,X>d>[>=Bg>?l?HS;?dXr?G%c>bjˀ[BJc?+Nw"i)> (B>]Mj:0he/Ž9>nDp0~VK#2!>i` >AJVB>ob(bc=B?hebzN#[H2vln>j#XsPx#¾'i>7^t6 ;k5n?`r!ƾ =7?qnpG7>)#`jim\m9> #g> >?S߽݇/=K8>Q?W-`bۥ=>P? >خ*,>A={>܃>VtBP9*_C/x|0݇f͖>>A?SP RHs-ɾBiPy1,=jS$޽ǽϾR>Kb$> ĜBᾕ)>E>D6Ga5>U뿩.=^cco>nfƶ>tЏe?'P jb Ⱦ Aa]-3MjPTU3J+>K4ߐ2ľ0 &>vy,^R㾏SOg4>-2`ڡ%Ӏ;; !>bAUG|=>P*:b1hK=*2 ݽBC!?&q>J~>JռE3DPC0(U)=eQf_),>Ck UɾDu><;pvp!%$ߧ=nz3GQ`̾v>UtD>R <- :? ?:aAu4> ґz* h"y>A>Užï2z>%lQ H>+U&S1>Z?M>;)GɎ>(H8?J4>I.辵Ͼ>Yp.=ا>xF*%_>8TG³ᨾ->Y=۾lj[8>`?1>iƥ><]U>.{S;4con> OVj:>ׁ`t>!e[?x>$=GW dž>}>%N+b>kL>1>a>Bӄ8P>d >>/+>f3&>!E>L>:@>1,Bz=FZ>Ov>>R7Mо.I?rK>7?Y_!M $e1F=Wh>µtN6?7>g/.ؽRVX& ܝZ>? ?`kv@M^k <.}V?V{R羿'?Xx>G?UM@|e| ?K_>Ik>Zh ʾa-4?q>?%tվ??-Ѕ?t)Uu)!;_Q?ah"E!=}}9wJ>$4L_P# <9)J=NHֶS>Dݸ0!=Ǿ>p1(1/>yľT=Z]ڽh:==CJ> /?9Ԅ t =Pl4[>hs:ھ Yd=*[SMB{u>?jT?lr>hd-Ms >0?> ?OU=9?I%5>>U}[)iI>+?] >>Т}f?L6Di&eYf>D7hD=2=M.F8|<{ľm)R=$@=S~澃Ŝ>,`> 5gٌ? u89o>G>nƾ=;󥾣>Y ߲hn<>1f'F0>?)=3n`Lk?I5v[>gH%ǿD_>5=?x>D>Q0/<Y%L;0lDQ 罫_İ:5O7>V QH#=uO=0a? |=qX O)>td<='r̿vHB=_ԽPw>>-O" JHC?O<Z*=Z>SL?ZL9xwGgf> tt8ٙ>Ov0 %ni Is+D>7Wo>ɾo>Er<3/=?v6*? 4n>>:B>?a$?>(>7I m{SXS?,ma՝\*S4 E1&J<Lƾ>Ұd5=9#h>j>|V>lXͿ=HK5M >۽ݥ5gBq>?,~>gslGnsǾ/t>;!?su?"f>L>1U$H>s_=Pt!]%fQK;u>i=(q?Il̠O^kk?% yY0>a#Lj>p>Sm 0\WTM9ysSk>&JIJ>+ݾȊ=$cg>S?7?8R >Y%v>*B)?Q]?w.?4NhTN??" h>Qe{??H?o6(*<(㛿E> l[ھ/k>a|ݠ/ AF~>^.sc.oOeV?2 = ľ]F,? Əб?T=C?>X#!)>s=޿_ g֭>A?[l??C>s!b?>&p?=uOߜ??!J,>K 8?@?>o?g$j?+?@.?$f&I=v>+s=z4D??V@CZ((dv>NQ:> (EXR /҅2>u91wEƏ*y>d8f??>I=%`7U2idž>w=j>2M=1?":7۾c s0 f>0-(=R#d+>>Ec?u\9P>>b?Q?z>u>L#?4BLBW$?;>ຄ?\E<-L4om? 'ݰ(>Qm@=f ,=?gxٿ(= )>ahϿ8=2NϿf+sy= rֿ=B&> '鿕a0@^Gi>F3dJ ?b>xU(}ҿ W_Nf>msd=efr>;gY@A>T=G}`?"L08>hTnwO;>D_4pGM=\x:qӾ:V>>)"?R Pho=1)D$yǾ7&&l> `tƿRDA\ c="[?tz>ٔ>63.Al*>y?sP?T%?/7Z>A??Bq?X\Η@?k'>[>50IV*AѾ=e[S@(S y5G>AO'!*vþ4A3>>f=U;R7=q b=ri>7+@hq> ;OBU?"ٵ=ǿn 꼿Li>v?'5 >[=Roy>oͫ?;.j>l<>%KV*#;XE=Y6G,ڽB%tх5=0eپ>w>cR^/>Z>\=QOHK>vTo>z?Fj>Y>s9>3P*>7z-?q>@=ۇ0 sT>6/7-$6D=q\"iP,:x);υ ha2rkM>L>ZaA >f>ۃWlۿPI>>=w!xfܾZ@VTz[[9{{t=0b#fqjoX<9{RD7eTm29P]EN_{=h>=s;q&|jz'73>/"3dm>Qˊ4P}=,JrdКjvaHB-ԢUY{T㾨L'=J6׽l@P^e݄=pe; ~vz6*=w㽵1۽ӗ&&=)mR|q>+Y(J{Ƚ>l`Yz37G6^hv莽UqcL=VuXq >dD]{=%#V2>ru䀽4j΂=: XBt`V`־]%Rpv6O>pE_ҳ>UEmNMs>ڈ]&>IbUR]?+NپM>+>>W?@:D7>K>mx>Q?~sq Ce>C>%:lt2X%;R ?f?[?o9=0=?q???1XLP?}q?t(N?$l_<???PN,`ϾW?4?'?nJ$S(=Z*< ;>f5. VM>==g0>>8Ʀ>Dp>w >_9 H?.? ?Rj=!t> LI[}D> =]? 2DDA>Z=>0?KY+An[>$[>#U>oݩ?Y?/炾>>-nH>΀90o,><>C2>"w~*=`3w>/z g>>?? ){svվQ#l &{ccؼ*#b y~LkG@s:R5)*cH=D.8>qx!-eA,=>KL=/j>@@ug7T~=$pi)=xѾ:뾖^h>]"B=6iì.>&xޜV>aҚ=>nCB> n N>(gLiXҞ;_ʌ'`L]9J^>]>ܢ4!(ʿ/> >̧? )9 fýbeAH_Hә'U=?O8zc<徉GQ=l Q=@?n8>̐`>>EP=VC?t7$d>=>t=~廻MIaNAq">4*=V`o;b=ʣr IͽO>a8=ٱ<} Eɾ>>=>տuRvƛ=qX޹Wo/=mz>,x@<>#>aھ?>96W5kʽҍ8B=p=g"8ھw`%m5">>+= d2Ta5 =m>(o?=Kf(푿ɿ1^9T<8F5z`N>(B=F =;>b=K!b M@J1׽0T&>lW?|>t>wP?/aZ}_E5ϾP壾MN>yye ߽7߿ T PҀӁY pCxD"ǿ64@ #^N%)>g5hCC7>u+>ڿ's">UIris=a>v>K=> ~Z>EfI>Z6>>?\>_w>Pe>2>Ex>G>*͟>&>2>Fù[ -=ˊ_@HνTnٝ+w_RPvCr<.0=C6ŷnSr6CJEE ̾p/|t>9S_jSķ ?S=}>YӿN\u\?e>sl??h>@O`#:? :dCpcn"G޾yf{\*r?g>42?O`hܾ >Yݾb}A =P3>|@>Q ;[>t2?>Q޿@>Q>]JBZ6M"u%?bY>P$7>"?aWy>&ز־w=q?G= ۾b 8= A[ݿD0,<*r~Tcu⾅<=l V3濇ml>ν ⾼h{><Ž41|;>XP߾zpLƆ{0>N!=.=G$zƽ\-(tw6D!x'W>cdIѩv.Q}E>a?>yX>o]gIy>6=À><>.3j=v >S>DR>t8>YnY|><=Q=%TC > 6 VX7?`=0SB|X=op>>I*>ڌ>񑾰{rX>?1I== )9Uu>b=7>}>$ ?r>kmʽR;>6X?U>dH=*?Y}>&=>b>V?:Zj{>$>?!' >?1B>p>Y!H> J?C8?>>LM>ѻI?9I?C?Nf>><`?&]>e@T*>t>첖?%? @Y>~ʬ>>>/0<`f==֕>Чa>h¿$+"=}k>x>?1S?qoi#??TG?8~kSC??k>(必4W?W?-?@9?q>S`>>>$?P]z5?=AD,>A=?8Cf>OE=t!6 pP|7a>0?!? &{=ׇa> c>U"x0Lj> +a>g@>o >A?@#?:i@AL>? ??/+<+>$7>N|m=}Žf>)> =X/E>Jf<*>k>`>V`>[Vu?N?]!W?aV< XC?=&>w>ÿ`mZ= m>$??q `<^i:\>=^>yAC#Fa=S>C@FP۾0q;~J8*R-<="`40׮>#>{])kh=M>>¹;r)龜'-cԾ3.m==2vK{<=G˿ޠ=~>%>?*!{=>F9?!?E|>ʺ>HO>޾30>C>¿u.A=Y?g>M\=?xg>y l"أ/>?E>y۾ǒ)>MN~j3!:y#@ 0=b=Zl>NC>$ =R9=3=`>]>~k.=OQk']>b?~|p>1=-,R>҅>:ſf=x>>k >?I-{=_>[>@2|AW3 [=1>e:rW!R=|%J>&>ē Y>.U>q>W??;>0"hܔ>ʧٽWfto[K=?+$>j-0lt":[ VOӽOM{2ox>Eǿ,7y?J5>žղt>g?>,Xxi@=#W>NaP>*>,><`5< >5>ax>Xk~=̫?>1>8sk=9C=?_G>]Ѣ >?RB=]i_>#?dwvz= >c?{d~>$Q=d|? WKR{?:) ݭ=x!-> fo/>マyb>f{>A!þ&wBW7yIw%| >A<:= Ũ>ł>y|2w >YL>(̾pr5? =&>7!F}]2=_ ݾf'>{[08>Czo]>~}v!3-0 >-?Ja̿]>R>H=>^|``:tcz}>y 4nx' mL>f=Iyj侴9޻A 8W!L>!=Pp.W>Aˀ;} vk>JbIkd<*= >?0>S|Ѿw>H>TT>Z> w=W?I>D? MRg սP>w>G>xKD >T>[->Ĝ;?+U??8Vܾԕ>>.? oľԸ|>M>? <2>p>e?pX<=tO)~N=k=8(>잽A>7Q9K\p>r]%>\Kq+>ߏ&qm]>7>>|->3 pe¾垥>A? A?q3@1>r?>?j">08>??nF>'6 4V.>rB/@=ưS3F=PI`=!zGo<4'A88>F=b>qخ Y]>*'(=te>KOH0>-?$k?sK?*CEmv<9^[)>=L?=T(-B>,5>گ7=lzqտMPD=]`cr=tRMg˿-́=LP>:j>6>?$p$/>a?K?,V.?Vl Fc%#}>L>X>i> 5ima=˾޾QfZ>`?~c>m0tu?C>eJG=E> >oww=vdsj>&ݾ}1P>-<>Q=e>_>b(=*>=Tv>5kA/= x>P=!s>MpjOd=9==g;]G?>F?N~>gIϓs~;>e׿M8iྡ:eI?N'Yro)N=ŏ?SU>ܻ} >|?sizq.=]>a=8>VquY>?3 ??5I`>#>ً >>ځ]#^ =R+|>q?>4>`;p3KI>\=]8羬C`L>iMc}w辕熾w2+9>.ZVpr cfdN=Oe?-T JV8v=O? J]<@T J09>) P͸du`=w?$](>?*t$>*>H:>l?j dtPUj¹>Hl\0; _=n>6y?'W[4P ]l>émU>8o=?p>7s?,O>q?(?D?`?͒?!H>g ?C?^I?,〄?q? 1?@/& k>:8vcۿe oEx>hᓿ73tX=ԆjlJ>DcB@A3=.=wK>Pi*j0\=|>=-ܿ(5őY>V>?W.`aM>}?~?W?-1‡=m?6 c?c?D%+>2?TX?;E?f:?;3a>?T ?:?aZ @E J>.jr۶->+z>a?VК,A?\?']?Pvyˠ#1PD?UPR g>A>.'?HfG 51~qGu:iSCŲk>kj!ɀGbZBT=͍?odϱ sR>!>?>9qg>`!$A=k>>D>R^BSG'< !GR`Hǿ ؾj=O>S>6dC-g >F=vrpy<5?y>6B%ٿH5&; >*gp>8\?1y:?c|?C_Б}u}j>h{W0@%K1UCl>tj ߘe8=jj?+R1$O%>=>KfJԽs0Ani^j0H+. =t$>!Fʟ!EA9<Խٽރ?пmm>r.)?((X佉rS|5"㓾+Z3\ս7I]Ľ)ZlL ɽ*5˿giݽ]2T=H^Q'~޿ \>;pzĽ @>0#N: Ǿý׹?_|e=[={5=Qr?Gs~{+x >Q/>VY 6W+~lBR?  b=?# 3)=>c|?\(,[V?ZK< Z.)t? f)``bD>0{l-w2?h>̺%v ZͿ lOn>qv]!V RzZ:;W>v%k>3;5>|>Og >-EGZr>N>?=́(> ??)I>UP>X?O#;=@?>j’澭f>B>.>IMQeI>_fDU?O=ɽJ?9;=Y=p > ?F}h>u>=>J.?]KAv=>V?- >ۡ=TU߾/k> =Pl;G> Ѡg>=M=ҨDƭ+T|>-=zN= el?OR>>K!ڧ?A>>Ϭt ,?>??,>=8ž+$>L> ?`] ?ھ?nn`X>(?> >%f=>= =zhcD/X=}=~X u:*SC><#ד>U>P/?}m@#vb?s??8$¿'E?7?TY!?Pv}"{gnhN>iܹ'wξX=mc؈ b!;=]A=U x1>zBr=߾wz->ܠ=x .P+3n>@ =tg~+>۩!=ߵ= ?on \־Ӿ>UK߈?kB>>? #j?:ne?R}?Vp![t>F>?s p׮>D>?C=ž#)*X.>p$rw??-#?&>v $=u3=ր?!NneX`>8=>Z?ChAsW=|>?">o?Qu^`۽?_?%?F„>=p>D|o=r ?h=-/r=JX澟ɛ>~l > Q=zտkɿha޽!?=B >.>,8?wv>@?_8>u?K"x?&r?> 1?0`zI0˾ >mЁ꽻0s |- >P9b> 㓽?\  y=Y> ~&;G>$?R4e><`>2r'fQ> =6(>|pCb ܾ>-gۍƾ8>◿Be>_<>cR0D>a 6]>aJPP|?~>=3?=>`B4f,/qٌa;L) S<Ϸ3[G>Q+[f=ib@SӾ7-;W>3?K@H{[>V>?pdbHڋ<: R?<@O"O=X$O>'?C0l$ekʾpb>!:Z;C:6MZ>0Qˤ=]Ps޾d=>㈩hۊnQx>n: N>9a= \>~_Js*= $> E7k<T?"Q0>W/w=aFO"}?-Wy[EnEý8Mw? DE90/viO>ZC>q>,?^3R8+Bo#,I)$?f%)jlb>u!9`+g'HPD̿ >: R=XU~>?1=}Fw>u ޚ_:?)M5-=LC-_>¤8 =>=[?WA+.=7ȾI?u><8?P>">CPoT>Z"-?6?S? +J@)>sG??Y{?!|Pf+-=@??V&A=??΁?7>z[9Ǿ8?7?dm?2PJѽ+?T&?'>#{1&=8~~^>D_[=9Klz;?2 =z?л>N=d=!*Rsx>T=?#>FA;8620c1>T;4E>?>E?/j0-ʼ8.>4˾]?a>?rK<ެ<ӈ AtH>㟺86'E䲷>>=?=e~r:G;>;T>$?Fv?4>A+d>T)>/Vܒ60M}  >>N5n'SxӾ,(cW2x>x1qaLsy>Se3;gq)>t柿ܿSe>| |ҽ0^?>]>i{2ɾ4A5y>dc0:| i>ptd=0Z>l}7>DR7~m>R¾ >[|5JX%Pb>ο*3ICȟ bI?b>>B ph40ཫJfϭ󾗘>ygؒ>bAi⿅ _k^9F>5?[w:>x>9, *2͖??Mn>?j+¯>Ovbgӿi>ɝgd5>?>=W%Np)= |[b#=dR'E<þ7If4 R  bb,W==>6yk> S8޾׿=^< rݾ9`ms=̾L$>Y*:N! 9RR߾5=˧> ([_>( /-G>>&Gޘ[Y<=)ͿWI>J Y>r5Nrݾc ue!k3=Sn>!U?\p>e?s>ko>!^ӏpkS~,*'nncNhrľ;=X)U\ x>pn3?wkQ޻4=;/be!WXD> u?9>_=#K_>?E.>>'.8\=s?K>%>s;4a壼t=^1 uG>hw(d{2Q>6%=*/I<)/=զ`^mV ?[4>.fJ~@"̴o*#G8"ЏeY;=TF$UGF.o6*Q1d>%\VPy1{em^ ƨ6)O3Wu KjU.Nwwvžʹ ښ1)PaRa=SimxiTTmJ8L.=ɘJwO? Ѽ`VG'>~JQVܽP+>` Tdr>|N>j>G>90" j(>*`=>߹2f?1??]1Gږپх?YJ?J3?P֏s>D>?!w2=q >Mhz"} s>S yP$>;B@5>Nj=Q>U }?XM?@%8$>ma,>]=Z"xYM>--hj{>o(>!;? ->e@g׾0>7hҽuſgiu!K,3;GlH ŝ(>7==_"mz#/9U^-S=w5L,=ާ7m3E]ph%FD/>^$6K#>>s?)6>=pgx W5J8ݼ{l>pշ=b}I^ Ź (sA_!?6sҾSڶL9ؾs| n <='X6 5^РS9=I7 =>B=ʣ>tB <>+s U_ DP;>1,k=CLrV^ʸH >-;m?>6>`>9\=>M>K>%A8>H:?>>ski⾳)>>y.>-WOf@=e(ˡ>)g势i;Y'Q |&@;㴾kP^)Z\پ%9ƄϾsK]<0bvleRu=}:uB$a =>ePDnf>lO٩WSrIoa-J{hk2;UVu^!%@#16)RxB<|>_>Σcо>Xݱ&&<&cǾ{bA8><o&>ϣUBᾈ>=>:>L1`993]v_N_VQ]᾽p=p<ս5LjӾг9sG>F|վcg4ey>V*TYo? ?G> >xl>!6Ls?"~=|ozdӾІ{^= *zkH3^=ۜS,V @>.*þb)(=]ω?-L _=ِ:о. ?HD= ;_(A?Ƃ1=¾Joƾ+{ޯrp>ZY.cNȾZzj>>Qs2>>c?2#^>ӽ:ޤ>!??_>U }>#g>H=l"h?~$Մ>(nC]!+?p:k>l=ȿ>&p]N?dGw>m(!?=R۾?Kb >8 _ľZ?D>n>8>L=%?6 e>+8rm_^?DGc>yư=S@l|>j\<>R= ?bh>bg=4>>3&?rZ=>n>>`g>e8?wV>*Zq>T(=H?A>Q8Ի>aLb?₿c>>H?-?ԑ?h}>i ?A?}?`?h*>>B_?i?=\>[= >#y?#;?k2;?,?`?B#>R=?Y =??B)¾*O?7?I9?3<@N/%=_>>ʮ>@`>r?V>q"o%}=o>~?n>id=C=u;ac>FA>I==i1>j>wB2@>EP>T>͖>.>[N>?ې?üN 9z>DC>?#?(F>?>>@|>>[?dЖ>> N?q?*?V[>P9X>c1>?`e> >I?oe?$N?{l=8a>>>?s\M=8>^>>?=6=u>;>>?*7I>"}?JL +@$>ee>ֳ?Rr)#sZ>?s*? !>R ~=->?&N?-?,󡾵= >><_-=>v>0D xl?B[?=.?LL,TB?(?^h?pc@J=>OP>?6S)#;"-`??;0]<:d}<=>@1C^͒DG=P>D;6=Ԋ>O?R?*I=?f@qP=Y>L#>j>q]zƹy$2mq=>b>X?D?r=mcE>>>j?k9z=>z>Ur>?@H|=:6>M^>޷? ?J{=F>>o>/E?jaȓ={x>0>>:*>?r @T-ý콘=7;=`>aaKL<0Y>C9>V>q>n >U&dՕ=}(?V?O>J<>?&>}tO=MO>)|=s>2?~~(x=O=!3:?bx=[>gDp>>{8La7);=]2>0w"=ZH龩@}<3ŨNu>$ >u$=/'???Z>csX=Xu? ?zSS>?& ?VP>(p>Js>~m=AQ? >)xh;s?;?e?>xv:D>e4>> Sarpi>! c=X+> b}>Q3hI>[>>L>\>ξ7;.>;m?=v>Z4+N<0?>'io=wI%<,q>X63<>>=c7L> _=zЁ?xS>0?6 @=Tf?$??1>ĿDa>.|?>>? %>$[) B>E|X;h;n(g>ousVP3;B<#7>fA@ᦾb 5}=AgϷnھ۽ulDNC#<'>䆿+:L{> þJb>0>X>?2Ͼ{#U>I#g76?$)a0s>ꔼ>?P ١?*Ԣ??;o (R=>a>2>fSm&?,?*?f [A;V*<%>(@wr>? ?tL>/@?{?lƒ$r> ݿ9aB=|Nt>%C(۾@>@y"=R Uc>¿%i=;o:V.?ݾ=d ?/=:>>Ǹ?QW7">=k?2>fr?%5<>v >׈gׂd?3?%?Hx6r?'u?+?9g A5?(?]?5V~žYɽ=71?RkƼ>_>u?Gy,l2>N0>ڭ?AWA{eg@>Th!嵹6>r>o,?5 пo[=? >?W= ;u7?Ҧop$ľB>a>>Ё^]kx>Q=>~P<xñ>T6=E$?!d7=8Em=C4->_9{>M>S/?&>?gVL>?Ab?%ov?P)';>0baN|徔@v^ >nkm#NAd0d]>4&xk}_ݾ_YyBbe=>]o?U??>#ɿ|A{CٿQ[/f>9>=ܸ>N8>M>W>6>R>aпeyE?)">=|u^JO=Z~?W>!uv?>6<2Yg>JoZ=#2> M#=w-ܾ _9>beG>Ϳ](@ $]iHq=1ԑ=ٜ9<?=AA=CeE=}|3lt@9=<#l/m⾇~V6*?">ZuҿOo y>BdI $0ֈ?Qg#\&?;G> P6p];\=ڮm>L'?#d ?8P?JGi>2@1ニ-A?y콛>ji0?!L笀>*?'\O&3=ԋ>Ed0?%U;Űe9/UՈ<=EJ2Px#%s>>ȾD/7n>I0>ཥ6P=z?KAUm6=G/>K?i@⊉>UY?>u`}>V~92}?,(h=̹g>&#aKcHgZ8>D=>>x"#漷;dk=0IK'텾6R!>>>p?'X\?`_ ?W?iѢ?E? L!@z?|U?? >?[I?>?]ak=4? @?6?c@> ?K?pܺ?oL="ɿ 3> ϩ>BbE%_>p=?V/?3?QK،[˛=?jX??m"? (DpX]1%=Y24ؽ\˿( J)#Ewr,A`1 \hք5= оXS>I?j`>/b{忈qK?RP=(x?FW>f,W]Zh>`5kU >??|S*?V6T>?Z<@9R=dlq:?Bt#cA=hg>ݱYa$6?^??q/=C1>@)?DJ3>\?5UYQ1ZG{"K>\PM ýN=C>\0(= / <9=lſUa2썾*ARv'!b=>䷳K΀yľd׮>`Y! M=\6ؿּ$2)=1oD&ſ@=]DmS>U >V)󽤿ӿ7P ?}wKgʿ þHS(1O_ɾz]e^>ppa9=XF oS&qc=tdKw>jA`4 & ZG=i;s磿BHR fpñ>Bt\?@f1@U"=>xB>|p?loI=s>Ah>9RL?]6*P2)>7D/@HGcC> 1U8xx-^>3!p͋tYyѼ?Q [@"PӾ0{>J @|̾O6i=^>?NI?^=>>]->.83>>p0&=#(1 > mξH2> =効)>HuOl=y?b>B>">f4un>>. ὐ"ݽ>np"===ٽ h]d\? t>r>%;KӘ?L">тE>]=???n?Tb7CJ4Bt?g,?;?_d>((?x>3>|p=Ԟ=iX<>='i=`{UIb?"U\> >TGEǂ]=ra ̉=^zP㾹l>>yhe疿Sd+>9 )>!L>:?24V>1[eT Ƣ>$rw>cz>>><=A?I~>al?9>>V(w\A_%q>{qx־侓D>{d<Ѿ~7e^>:Xj% ng=?)>_=D I4UӍˤ?r>c?Z7=L>PwʀӾK'>a_þW55>וe՟ϒ4eס>z'p"|ß>օw??(xaĦWΚ?l>/ʽ,=d!K~=9?T>>.ܿzAT>!?]'?j>|cgZaR=u?q=>ԩi|_>>c5?X8 h 33?9.?O_?BR=xEV*> =Pu6r?]??tݐcM3?[&)?i?tMC?x?_?{`¾/?.?0?U?;=qpٿz¾t>R=A O Z0>*!!?J>> hwyw>?9M/?F?qs8G{ u??^?Ŀ/+~> +ǽԽ2n?u i=nӆnp3>(lf߃\>U= =\Q?A@O=;sUNkr*,2-=w=?t>+>M~kK ,>v>E?QEAtA(m V?&?? a E=m=&l?({1.R<=pl0A= *[@~=wߋ>23g>cܾ5g? G}%> k3>}kA8&=ߤN=`K~þ?y̧ny >Y?C#]:@lX1$>®Y _=+%˾>%])9xt=(ѿ<>SNw.>#Ⱦzb> |p/a=G?}Q>⁙>t`п >k?8?o龮q&dq}4=Q=w?CqDpnӿ:ؽTzG>"}tXXܽ>vL.þC?<4=5>[d`߾`bBG>Br@* ->BXhG>-?U?gi(!>>3?.B||>N>V*?sT~]>U F> ?jdPQ=??>Th+=>c><? >R;WY!G2=ؼy~ܽ ?(QC-;K`:?>V?7>Aپq>B88Kb>V?̭`?2@>"`>#^R>~?? V>L <# >J AI?Ɲ?"\>L#-3[Gǽm*d >U*qRA}žI=|.%GZiQ >wM=#Ho4>Ը|=hx<>WO/`YM=Kj:o>@$= [=Ky=oqUrG?$i=l??j$?%2|*YX{VҾ0> +`O2>%cgkD>k?@?n>gcws>k?3?9.>Om3L=&3/ͫ>tY0R?:*'O>:2ώ݈qm}a#?x+C[<0Z 3_>K0 F=-0 >iJþ~>ik3pi>]iMr%ʽ1e~t>E3O/쾘jnZ0>43 Yվ\_?8w>*;XSĿq@j>9z㗿&QD1>eds_B &P@>ce2¿F_ЅqT?fI>muf>սD?>>Aνz ?'>>/mzix)x#ؾ0] Gi2~+=]p"}սQ ,ҒL-j>q?+@_>L=2+ lK>8Rr?[>>h8>9i?M?!'>_|W{n>N?f>">^DqG>p??U?0ar/=<ր?ݠ?Ed?ԷǵcbY\??g?>Tr=X}p?>/>Kh 1~Pƾ[=Sp'yv6=\O?{V>`xI x&J?ס?t?_4 ??-?:s9E?t%?dg'?9>(¤NA:>r?&1>N =^X#:~oX9Q 2>!Zl=7݇x>KRD7 o=H$=%`t!,"y x/a t@->SMU?=5(k6>-1Rt>ǿ#=8MAм־i ]vp SbR-Q> XPxSͫI>鿃 k/N%8w9o 2<`6 ="+9 2¼[3 ě ia;T0=Lu8zaof־BE\>˂$4],Ϳ̾/콰T&}>s4VPvE=s>NݿJl!)c=BAԠ>:mfRu6 AnVP=Ë?S,>>f!U> cӲ0l%xR=N?2h>/>@W="Wo=<>m)V@Aˆ${Y>JEulb#-dAD^ Q$@mһ27P=5Oʿ->_4׿*|>\Oe70{_;뒾#󝾨?"9`IAȾ>,oa~O7 =(@ 2v 0t/3A+u>pzAU>E=إ[(p9ӳ>hY>1*CCԿE'>>y>(>֮>b6HF=f=LY SN1gd(>P>jr< !:8C=$Λ fs>>|?Ň܎<^ 5ŠeH1٨Ҿ_?SK=>& 6>^R>=s.d>_>M>~_N}%پg=l[.W>>_?# S`D >_Fg>w>o ј=?1:?Q?E"x=;%?1]? ?K=Oݺ=l=x=>>Bjpۧa=ֽ~u>uWٙ⠾|( KfA/ T_o~r">)Y!h49>R̾Lx> +?͡=LӿRıh=ھ>Np>S ?9? U?Rd5??~w?vH{? >?!W5t={ÿ|]>2pzTm=$)W;ѦP>_=Hs<j,c﻽`U'徵c]qoX<^5~\tpF?\#?FiI?s M"έ> *Qy<|?}Nd^y=WdZ>=k}>%`뽂b=o."=3bv>c ľӴN>`>о^5W2>lX>w = 2{>rd<5獵>p>gy\%E8=>W>i>GO _*¾19C]Xʿ@+kϾM$T~B=9p.@>e0,j=pNv>p뿴su=و>ҿ[41|OMľHn;>:=>|U_<4= ٿ#KQ=6@d>%K)_Qv4>Qv7> >?HҐ>$竾133>E =볾}j>??~yB>uU? ƿ <v?8n~ck>Zk׿*h+棾z>8g>l>3o~>7>/af*&=iDg⾋3 >?=~=$kG>MI>0>?>">L?p>~9KB^>@E>>v>_Q'x<뿐*x󄿃V?$>gO/>pZ>``xiiz=>;k~  =;ɽ0==%>5=;==: >QOξI=^S? :>k=wq= ?A>¼QR>1?=s>-A=Dx=E_>L{?F=ᾮMc?^gR>5yDоQ;?Մa^>'82=?Db>-=o>>>?"p>A5? TL?M ?-i?Fp~zM>9 ?XX?6 ??J8v=$?R3??y?<>8?3C1?#0?΁|\F>bg?%:?[[?F۶p n;>|?nv?C?>=O>>?.?E?@b?8'=>|=?e? ڈ,3n>M>P'?,g?))J>]P>>h??DG?Ik#>2&>(d>z?? ?[B>j{=%>>l?oBND>z >D? k??kOrz>">pp3> ? -?sW>6#=k>>ƙ?¿/=?-'?3?>4?&|>=X-?e?h?td?eg>?#v?5N?!l8>D?"k?a#?pݿ}eT.?!?\NQ?k?0g>"=>S>si? 3?IƧ>>&?0/=> >Ϧ?DFG<2=>9`19@Be,s7 Cf% uڼg=(e>o T?S=Iܾm `B'= >?uy?KlPE=g>ZB?'/?Q;?Pj=>>#+dL=\ 6_<̽]:;C;T=>IIQPl=AW!?=}㛾>BFhq>)t@q=ׂԾPWO9.\huh7P>N|(>>N==*>lq 9LY9J>T6ƽށE>B:{ >.ω>TӨi`ze1U=z=D>ү;lƾL=d4>R>vP >n9qC_R\>Mۘ>k^?x>7z R%?-Ǿreҽ]_`oӳ=¿=>؆mK> Jqˣ>R޾> t>#?+þcKX>3;Й>p]?P2 77>hz\!ƳݾPm⢽ Ŭ;0>[}.H=F.=s>4O*V=< =\1>ޗy߽tC>J߁#. #0r2>+ӿ9>P߱ݐzt>>>hi+>>W?O4 x>/#>g?. @'99??f?y ܵ=Hߏ>#_K=%*ÿ{c:=~tZ=+X=d=?οr>Re`gX?׎츋W6>̺>?pT c0>? ?ؿA=P8>ɸW>35)>;>ʦ >IЦ > @h9>n>Ή?2> 7?FR?)%5?;J>>>b5f3=aw? ?N(>V=K=x .Z=׀?'˜?t?7. ޾vb>'>?CL̠Mv?Bϧ?Iܥ?+ F+>\>Pa?O1F0p&ڡ>  k|eH$ \>( r`/<`>uRF9>>?D?T>Gx;ɿjB ؀B>;>ZL? Օ >>@?nھo>>0U??dI֟#&>8?Wdw~8=?%>- )鿑r޾ȸ?:>859iL'I >p?dAx=Xhn<>.Q@f>G F>>@?K˒~W7T> >C?$'$wj|> ??qVU+>>J?Yޜ(p6L>L>؃4?`;)+ ®Ӿ5x`>rk>F?9?ҠX ڻI(>!0ɃC>_ݩ>Bl?Ap}>ZL~6 aE$ (ڪ8#=13>_>ds>ƫ61ھ^>9&>M?P.X̾ >?l?w-u?7=>A.?(}KdXg5n?,P?h+?12yX0=>Q3?}=ٴ1K72=$>;F :H!l<|><N@,ϼfb .Qp.>7=7n>ԾD|u>fC>~1ua&<> $ W寰>q>տkJ?C>Ly!Z(2talln?e?>n?gK q=E>x'1?oE缡 k+h[?EuY>g> 6׶Y?'\nψ>.۾?ow*>f6[?*Y}=3͠>?ȌQr??q?*8VT6P?Sx?,@?W&Dbb뫾 6y#piSb${$ cS=վMF<>6?hIXKMB>=?T>S;~=v>p?wc?Yxh>>/v>|2SO">Ȏ>|}>{8? ?? ?>m?C(>H;>%>ɟ?zcc9>~. kˌ?&"΍0{|?01?[6&?4y>EͿ#3>^0˿̎W >5l?2??4x!O0뵾 D<@{UB??7@ ͎1 ?f}?]?GVeʊ> x, ÿ >JX4+jl>m?V?i?z>q#p>Mn?P?l?{/w6a:?$:?}?mIXLU??u@?/(VZ^?e?[??@DJU=:3?K4?0?O|QaQ轂$h?]j?@?[mecR =8?F?v? 5]]@>v[ҳN?m?Z?XX3d't>J?э ?w?Ƣ4?Ѷ?d)i=e`JQmn>GDpSk=./ =$ @0f=l*%=!ɽ-: ?%,^@._J>?>q>?/?Nk?Xu?*Ax%> ?4>>a}l><γ?a?h?d[!la>@?1?|?X3`vDc?ԡ?j?ĬBHOPH6?>c?àLX> >ͮ?N1ML?'>m]?*N&g" ?=\?"6~?:b ݝZy>>#Qʐyu=B?4GP|,d-=Я`?  +;>>aԼ~˾>8PуCyǾ}ab>[1?>^^(\i?C 6Ue6 8-{;! ͼZ W+%$Q{Fςu>3>>+oμC=VG8*|>)gYX>Y?DD=C^ZϾ|>@ǼuS?3Y*F<ۿO=̖*E<)7gZA־c5>cu>A>'>*e?[ +>@>9>N+?b ˰+{I=Z?:|PQ<^jM>&LoځQj+>vÂ*9>:v?2@B0f>RYuf๾7žt>!J=3 ?0Yyy]>-o=9Y=;.ȃ?W>ƿ#?_=~k3Gc >5˟p=S>Zu=> lٺl ĽZ[}pT?*5?>ۃ>f~١==Ͼ'k}>if׻b=KC>=JA=JT"jP?*rep̔YF>;EP>>Rm>W=?:ҿ>Ln-<;P?µh& ?SX>C|> 9EH#rӄ>CqD 6'9Pz>ϒ3ӱQi|̞E=tB=`Ϳ;-@y @h=ۿ9uѿ0WK%~$%*>{=S=q?EfC_PKN?:T י_>GB)C?|>׺#ko;fG?-c|3>Hϯ}7R?E>>c>B0tti?(W>o>}t& -(= (Y=>'+n17#x>Qe r䏿:?MEb:>n?X>sX>yX'[> z>^p> ?pNϿ>sKK; ?=ž{>4=r֦¾5>#>PP=EZ"1'Zb=u(>6$?o?W>@mn)I= `=k?YmKI>F9=b>)r?F/ 3=Lwbv>:HK }=޾wCF=AP?*R=T>l>?jF9l

>8) K_J\ؾKM ).L_Կ뽤uY}oi۰=Ӣi$t+U>S)z=m?i?P?+wI8y T>0C>_/>c?pY`>=/'>C*?IsdWO¦>D\很K>;~>z=_AvE,]%;Gץ? ʣqP:D!B>(>?.s[h供ᾜs>,C O8zt>mDt7&;W=?3&(^=)=?6 ?ʾv?Y?~"?K Fm%G;k?5i?+>By Ⱦ:nO/KˣKTwCc> Kxp*Ť=R#;Ti>qhϨ NuKRнtlH(" >`͍<[u=ۥN>ܐ>>ݥ?G]>=h:=~?/ŋi(0cC-Z4 Ӏf>k]zt>ftJ>'\ѿǿ > DѝpV>[V>g>K^?Z񙿁JH>>~>{?q 96Jh=?o?>mk>[g=Ԋ;ZDb8?5nh=LjrMza{Y =Y*/e<~>g}>,;ֿ6=G:2V>-=y?Gh80y;>>$)?x tq=0 U9?]!D>tɾ`*t*>'j>NY_\o|>]W>;g>?̼I?y->Hs-P*K1'|Z$>$%1~-ᤜ>T\=%?S#F >-V*w߾>xٿ>W.js}K'>򐊿)>־1j>rt$v| @=%"dc!SG<տ D3ʆ,%p&v CaL=˞I<>Q:Ifm>X?&?J?'~%=\U?)?bl?&_<]?%?>:t8"_"?oa>>I<Ӿ)? >~>I&5-`c?~t?I?uns~fZ< *(<ћԾ>^)ƥHr;>? ?^f?CrE>:?1?">c|>\ޠ??f|?l5=z?>>DS}7#RnnzBR*1=_GO:8(a(<Կ eI1?+ 8W=l+>m-F˗5>.Tp;q>S?F>lL>eHg|P&/N`ՄySq wʽϞ_E,(Ȏ> <'s>~rR?=[0Hםu̿t&0>6}/qWuKmݹ>J>S"}Co/=ٍ/\jGEi=>RU45οnܾt۠>[׿NL׿[p 5>_ Y\˘.>`w=}mRb[>L&?#>'_=[W?e t>t6ÿ u=3&k%X0D>?C>><(,fz!(7o+gYL=j!&[YFN>@+='JiGG'c`¾G18C>8=("J0惼| ĿV>0T \&=!K<ƽ`t 0=VTX"=]ӻa?ڍ뾊WɿP=Bu_BM;>=hs!>?Gˁp?Mξҿ8j1bc֧cG?F r>ũe޿'&.>5Ex>Y>QݞAPDR=?> T=J~ZGOV=?6\p>*^>?QXy>H(=Wӿ~ϷŹ?[>R:z;%> =O5=o??.v?\prUX$I>XUTT"ͽ.^ʎ#->v>/ =`Qv>>=bd(^=]l$=;/׽<\ߗ>t.? >D|_]V쿱EP=&?b?M?:Zn'>9/;GTfdO&>Z<,dwjW!nfH&>V< v>>S\l忇olȽc_l쾈QY z>,mu:?XiC>B&>t$:r.?JU9>2Y⿍&eD3?0>t~7m"as?`ŽCxrCx4=$d#?AWy$!/=\8ozWf>>DNPq$)C|>S=m>FE<']TQlɾ ˆU !>6h_ݾzvS<)2kVOU1@T,K=FZܾDJߡںRž<͇r>fA|=mo:d>4npo8 P&F>pg:o>3=zJ!hsj'oMb=B>>S>0 έ"(V^9Ga#Nw>-.'hf{> ~>2>F>I<<4Z~,3pRgw?*L??;^ b>=V> Y<5㾫BP4Q>*>/>%=˹ܻi>0>PH>R ȍm "=zC/B=YZ=B(2->?>Gc>P> 5v1>>:2n׽撽J0j==~!:> Ty?-la??0=;>+vǿ 9PQo4C==>O>7<{mʽT_-S>=>ǖ}>v >(-{<>e Gk=8A%a5V=.^>ָ>t>]JR">>>>=׳=Si𾌒 p=ҾV>>?>6ƾ羑P>3?2>ÿ K]] <Ɩ̓A -V<{CXA 0Q=g<>>_b,^(F9d=m;>:g=j*$ ~$>Xd;>Qs7)&OuC$Y>q>W>ÃDc=S8̽2/H?;쾢ۯN@D.,q߱!aPE=Z:06>W>}eC龖>U6@!+>޽ӄkYw2Ac=یl1ÿ z<} =y}=mJ>U\༧xV@g8>DӾ^=U 3Ӿ=ӿ4c<=Ͼb>fOno> %=,=9> [[Uaþ==p=D?>q ع=?@w>Ҿƾү<?ZRi>{o<>06PR[/ʆ=1=!;߹C==FV<@J^h4d&|J~̽o>BJ>Ľ=;>Ltͽ_R>ҽ>m>֎x>i7=R%+ÿ7{h=ׂMa# P? =XnRY <4'=%$+UjO+x<<{= =d=XOu>)1{j.?C > iQDc]F?hW>3' ?C| u> !6=k>=v[?Cl͒>Tҽ#h>cl?^[->~=.H>@5?V^x>lPߪI>=;m=$=r [% b*,>\*>S7{|ؾC[?q>z?G?sX?h׮?B>`?A?q?eC[@~%>o,?c?='?.)?V==*?zƬ?v??E>#>3?$F?꼽?>?M?A?>^>n?+T?jē?mzݾ<>M3?]?Hk?N=8"">>7=?p?IH?Q[?g:>@>)$>S>z=/+?=>Է?6e?'k?J 5>>Ym]>6 Ƃ=NO?'C?d0?o޽Gc=)?r?N\?\=f`>Φ?&p~?1L쾸 2|9={>-> >࿨M b?L?'-?=>,X?MXC?X??IT\=t??ِ?q?!%=B>?p?#?=?C= [>?do??6"(I/>"p?5L?R?)=$ ?u??O?&|< !?h?jAp?xyB =v<f>\>>MR>E=#>;>eϿF==#>>>FJ6;b==g>S>N?Rov<#>=>Z&+#rGz V=6O3:GЯ=>J? ?2} E:Q=W>>{-?+=`>/>>ZB?߿%S=>v<>(>k+{ =q>xu>kj>n>#@"W:>@>{-Qk=AO>G>}>>{<>?RH*=Y<3nV=SAsk=#݄ h>JA{=`J 4 !a~SL>>7i? ~p>;TP>+>1larq> 7&>9>v>kWb<6tu>XFǟgEM.<(B|Ǘ=4*=@th`gi^>8%>p*>>-T]> Q>M>y? >ͭW>E>ОV? ,i@Z>>?!;I8_-ܽ >"`S vǿ \S?)1?(G? b "[>>Q?N~X>*s=D=Ίr> NϾ,???vLpK@>7C>s?`9Aܺ&Zq?p?,?>#2Tբ>$}?E< >~j>\ N>L?4??GΧ{-S> ?.> (?)пx`N=v >)>>tI X>>>f=o>+>f? mBIo"?2{?g?* x2$pd?"[?f?=N H'Ҿ>>0?I=>Sa>?3O>_KEբ=p>A>/LQ"u%=\654ʾ/P½ٹ>S!ľwQ>MϿuF!>=@h?}??,c-S3> xB>@kA =ؚFnL>%>5 Ls>gܜ<\Qb:3wy>?&7?g?0p?ݾyd/1 >p?(Q >JuͿ~BYkDȆ>>MFwS-oa%l=8>kV=5>eѰYi׽p>*1=\/>k=>B>>E?tK 3pIw.W>Ҭu>VS>(b ?\t>y}!^OUq>+>{_EۼIs$=5g! >$ux#t=18>[=ޕ1>Rf传:2? >̜o?:Mu6ͼ^>0{<>Ga P˜=>O?# Ğ\{fs>M迃fgN۾, *;g(>HN >vI0+q=jˆ!xϣ_>>b?E0!@2=EKϿ! K׽-;m >/*T=vy}>/3@>w?W2?BV>RP#6?5ri0@ێ=Ճg0? p=1 #ľo5]>o#`f>?z >Y?-Tνa!={F?O|_ԓ{-ܾn&>޲ls;֪bf= -DD,#':t=$= >90{>,?J5V?>0=h>qf?wW>k13<&>"ZU/>UO??n?`=4p>.y'>p,=NHy>/@?a~??#|u$4?[,?t?ލ~: |s>բ?&J?Hqs?6?`?>~Z>8 je(h +p=uؿle?m= ->z1>?]?f{s: _=G?Rp`T:>:A?#?q=I^b'ePhP8p쯽$;aP>u.NvBL&Ž>U=zt'w};ѕR=@ C=ih;EѾ%@?O~=&(R~?3f%+=24e!=>ZASG>z.>(>>~]Jb!*>s >>$E%>L>C<`>@Bѐ(=/U7%>.R#>7Bݾj>lх >- =A(i=M>I?`f3N,H==9?5YL=dNM>߽GV,G?6c>?"??8+X=G???x!PH?l?(_??Lq->v=2f>ecM˧>>(}>SJ'>Z>j> L.>(x>ʺ?AJ娾R?^??%uމ i8/(=>SlYh =?,gj>H>ZپEX'=Ӟ?5;?R?_7T'0akzRJ`=-wy>Lq ͎=D9A1`;iU=n?,2TU3U/>8Մ>G>_x6?b 04?>?>6~?b񈿂S>CG>9~>[}A?] پ> >C?S;Ǿ$13Ӣ>y?+_:Kif>/?*jI> Ui=nn>|?=Խx f >b= ?9>s>ȤNxci7L>=](>G~J=bxA!;?0^!y=3U>C<4E=rF9kD>ͽj,;T#Wʆ=t` >>cCN>`>x>_?J>S><>>W?_E*k^? 8=>P`elŧ?9/>ra>Qd[07 >m˛>?NMN2J@ ѳ>m*g6$N?)=,P>i2i9?J>eR>Ż{T\{?k>a9?ZCk*оɎd>@=E[ =㮫?;N>f0=1eԿ{b'H=?;1>&b=wB29N ?|=pߜ?)*=| S/՟o o<&3¤ر>˼! Ͻܠ=j? 5")0 q]pEc>8 Ҽ= X=yi?i/sp>ta/Y? 7+E><<=ߤ?>CY >A%tE>3?=jþ>sЦ$>Pc;Ǵ>>,t2$>?'?E]>?.jioh3 >S>\?h}dڨJT>K>ݔ?7LO=Eÿc@=ï"O> ]^<=+>"?qTX[==x=Q? |Gͪ=k=V8=̧?5˫O_FA=Lj<)A>a?&[m&aӑErX>T뽽x#1=;?4? > LfPa=ȸ>H3@?W| ; 4 >+wK~ڴ<ÿ?}xĿ=(He>?7‡=&ɰ(c׽?W>>,I(Na<75ӾĿLyB@K?D?6ܐ@8?e?I=/x@ nP?6?qPb?W??T]1xT[6}]>6e>|л?]6"?z?X?\Z} ˾?1>>K?0hP? ??d| >_>?;€ 3?g??XS|J J >+>??ՙaO=e>>8L?-.pSq>mz>?&1D7\ѽ]}R?re>D=4 I-K#1=oJMi?D7?7?tir^` ?4x?) ?ej&_=ž=.>lL2I>vg>.0D>`@!͚=<>aJ cgqĠ]T]3LMӶفZI/6=II[`H^j?TȽ?N?Yl~(>֪>?\舢 Eg>rM?t|c?>Ý C:+õ?@W?E-?{꿥CVz ?b?>y^ͺb?!??^vQ[p ʾRnn~>{g_? kDE>XѯBf=gÓ=x-?e M 9=iDAWҳ>L?w? m>DJ*N=v?1<>ݜ>EF8 /X6L?,`bھSg*>>@V|e+Nͯ?; >&548 O<+)>b >^-?_?7>ەfG0$u9_]yĄQ=\`(vپUι> O;Lǿ=:dѿ q^}VD>䉏˾p4t:I!5۾mT?~}<* :#X?+ ]Q=ʰ!>kQ'1뫽Gq> N+M0>BFZ?Ra=߀>_ ,=9ξ.ӿr>c܌? ?cg>߫*j?O?R>?2m)?8L?_?,HP=hKG\m!-j=>.UbS>?+k?1>r (+kZo=z{ H˾$| T? G- xվ!->es!d֑>nL??6*>]?X =տGHjl?Qv>B =Μf>Zc`kLq >ע>f뉿9Ҿp l@>j?סvq棿_>??J>>1mSbq5=?>>2f[O=?nH>>Xx4{ዽ+? ?>쨠sE =澅f= Fٮ>:MtO;#>]Rñd4zSd?}?}c?Qڭ=S ?i? >l$ۀ$?J1=m&x_f_?>>H*c4{%>\Db,`<k=Q(טU[=9ΎY^0wa=mSw$>4LL_Yԃ˽e.q>tJ> _6P>97X2+#;{ |s#[k= }]!H9?νȾ{>l8?@-Z>Bm6޹L)gDq\:mRe>9,nT].%>E==k?<~ >:I[xWG0<=LHWu|Jj^q;^ɼ՝G^N?pX> [<kJ>B׿ ؐ,mM]M>/*?<9?oO>-1 WJܾ?}wQY>R?_Jѿ9'>ba>#`4XĽ4P>2 >v=䟺tZE4I> K^ժ~ J$d?-? ?c տ̯?+%? J? Ub9*@  ۾??w{|?~qJpq?by?H|?Nd?8فv?=?$g?0`d 1>ɫ>&>5;+=<>O\#?g>?_a5= vf0 *&5ҢĻ ˿t5hLM!=ӿV@~61>C%=P7g?E>C_>㣩&=/>8Q=>?U<徊 -=II9 %3_swʕ MQ=<>=*^>`zxS>.NN׾P |>O@>q\Z< pId=.Ӿ'믾mg>=I$_G>&YѾdþF$$މA>NžU2!bn8,,b_x4s09O*dʉ̦1>^>JZ>L>Po>hXړhB= h*(=>>a >r \X> >>=\z =ʎ3BW5Wb=$ ۿ vagP={7*$G16N=IؾeK?`/=.= 0ym*92+=؇>Y>z>W7=j?0?>==V@;;3 ['i-MP= m=m^_plv># =s2Y'NlYh6"=Kg#`2Q='ʟJ6=g>>X><>a>/M W>ړ!dP='*V`ca2>9>/b>t=콹0N,!}=}|8YW05%з⾮Z݂3'>|Zt>pT&8բ>Εt?L<PU>rG=>Z0h?@>b<DzF=$<h3a1< (:L׾P#@l>,H݆ؾw>&>&e໿+$!>>> =Pa=\W??*́\1>g>>]?[S?<>:QÞk>3>$)GV>z >[>9"SV~rm$Ey-K??j/?Zl>k׾a?8>GDM⬼ﰒL? >뚾MB'~o?/<9>9X<<9k{ Cu=r$> >9u> >Bq8>!WFN?m >]- {?2wq>A ?֙?AHs,>-g6i?Yx~g>t`0HY?{>h4=7 9>ua?D >7e?8<}0>34@(Ⱦ>1?A><\H4c5? !A>q⛾[*񾵔?!X>M* 7z?=(㊿$ ?#ۭ>W3v8[[ ^?cA>)?L?D?BuX>ԝ>eO?K?UF?VI?x><ʴ?(E?^?_e?|q&>B)?7j?q?x?_>X?1#-?g?l ?>R?5;?V?V=">1Ȩ?I?zG4?? 4v>n?x ???c Ir>4y =&>9>p ?jP>?a?L?^пI n7>?j>Ap >Ln=@_>a>!?p>>g=W><>,N) <= ܇>gQ>=bZS=!>f?r?/g?+>>H>&?{W_8=I 5P<r>u;ql>+O=昻? G{>9q>>>??n~c=E>o>e?V?=ޠ>K>{L>O?^=Mf>Ӟ>$??A;m=C?a>S7?9GkR=a=>f>fO>)!??20?g>)H>c? ?*˸?YMsP>T&F=kSv >-;:+<$=1>$b=>fV> ?}tB*=Z[<@= $>Y>F~G^L>#?L=&~B؀=='<>mzWEi>]>&>J>L5A>27>&>?xS.D/>SޒZ>zo>qe?a=V>>~?9Ͽ<'Q>U>r? "1=Uď=O`[>D=> ~&;%=ɿs,>D@l+)-==X>%>ʜׄþ>W>nD?-X~a>Hw>{t?@ྑXfk= >3>??E CYf{>3>c?\>̖?64`?hJ,<ऽ!>T]cg> 薾y:A=1V>2銾F l>]b.{=&rTH>o?06D=\;=j>)4 쾰R?J?.uG?@|=J>>f4?ew1 >1?9?Og?eN> ]>ߏ?!!?vJJ?K?L?ϵپU2?)?R?B]JGAf6{"K>E?]?_X@A?i> i> p?{ R?H?K?9?:=">? ?C>^>#->?A3)>(Y??TX?,6?B7X?IӪ?l+g9m?F?Le?݇G >Ua>wa?&d=!K뾈%>}_?ފ81>I*Ҿ<Ū./n[[F0+v*E>SM?,?B?=Yc?Hþ< X㷾U>>i{?D)YIW>r>3?3 Y5=>#?!>^WA[G>!эxa=R>im=Gx-ǯ!>3%>/43n >9 )?5&=>@>;m>3 ^@kv>z>?2֪`QQ0=>S?t>տ>sBK?6D? &>ľSž?k?]^?_$Žզ? H(8 X>? !W>E?D9m> #>^>Ą6?P$|?<>wBy TQ&@do"J;=gy#>'?\>A?=Xc% >z>>%bm?9?M?Io{3gi>o =i>4Aū=D$[=5M=>ʱ=Uc [>cIpr?f>eb?&ְ73¾^?R>\t?8%ES??o-^?nlD&>> _?L Pj.>;?%4&?16i#=%$>?u+2P\5>M>;&hP=?) ?x1?/VY= ?o>?":@gĠ?>*? 4v#L??]W?(D|RP/?&[?y?$F־xO?C? ?IS0ޖlJ'!WX vѾZϐ͜o>0TwuӠ9C=|k^fAƾv XH|?%2"6aO`^69^%i|O;国޾%S`>[Q B1=B(34=VQYF.M0f?v>@ >:Y}fɿY:ZKE>N?j?z'?d=@Smӕ#>Xy H <.=- u< Ё=. L>y>\ 9>n ld u!N>^?!??א>=WZOeR}F3>bS gk=Vbx?5C9?;>&Z?S4;Ě(FuH$+c?Ey=D|cu> p" H">t?L?w?xl AV=?B=?*u?Md0 l=~s=O N=7 lfUq<k?&;;@:<6NfϾd>[PS>5l/0)(?>@<>Au?bZ%tr >47`.?(ם> oD >oPI @>3>D>M`&==?E3@Tǽuѽ=>9?l"w#==\;ɆPj=r04?{?W?\It?/n??7HEx%>A>>Q^H谾?G??"F˶?$?O?#AcS@EԹ<ƛZXGQ@?a>>G:=?&??3n@;A>W>45i>zt?V?+>->^%>H== 6L=/0jT޿j䔒;r =›\<եpL:>hrN8*=NJ?9>v.>ɖt[OH=3?EsT?1?#_> ]=~F? P]>in>da=w_ н=j:`ZZ7>1=`AE>MB>c=X6"=X>?> Y>V?2t=@~^b`wTQKs,}>kӾ| >MU9B %T?$\ b'5̧ =?'ʾRLe=b[(c,eZA>jUʘ_e=?l>:>? Qa>>>sFUq>Z?){>&_>!G=-?{=^>>Js>:9@ѽ=?>ʆ?JSv8?Ø4<>?#=p&>x?7>v=XK>?:6_>(l?U?)g?$#Nٮ>N?OY?]~5?h6T'U>>?s?o?w =S{>?IH? ~?0@>>'o>35?1W0aXq?iD>ƿ?ۭZdP>fG>t?NnG2rK*VA>!W>+4>i=3=?DR?wD ;퍾MQI4>7qC2&>*=OiYuo߿d>V)g"=>-M^? 例=uTT1hs?/ ݼZr>}\3 ֒=뾟R>ck6;=f=?>St=?y>>D9h->I4Xd,C->rq=Q_pJW>K)p%Z~x/L=¤'Wb=}<=ɣM?;X}l=^YO5dkF>So_4z"B=NοB,Gc=.1MoL j =ξ{,E>}=xy 6@P(=5;>4!:bs+ Ҿ>3>i?Sԏ޷?:G?:C?4q\]W>|g>R?NuEY>>??]Fh>p =&>J>V? ۃos`*>y{>x?G;o!-?]?>,=O&">YS=-C \= N?>`k>W ~9߾H@?dd?5d\ulۤ?M??;YG,np?\? ?2SB>H>+>ҿ?IAV@ k>[V>D>?O2Yk,þ===L?Kjƈpi*ʾg>w a Ϗ!O?"?=@DV=DXf{qz`??mK?62=: @ N?*?QR;KuXՄ>Y>>Rpe>C\>EQ?X;$'>ƈ>)?Rvk_u=R>>A?f^?x=㊽I#^‹>jO`)[`w6>`ܺ*^>7QH>8U?TH)!b9E???Ypf>Q&оEݾ#/撿XC<ݱ'@?@?Gr.>00{Ŀ ?+??[ .0Lf@)?i?Sz~|;0D*??Lx>,.XCJ>DC ?Ƀ>7>D?Mr=0A[ȣؾWq;b?v@нeLU? NBxo=P4F@D?M!?J'p@R#TB>I_wxG_q!Էv\> yߛM> Lݾm>BT="OS?Ux:( ?N?P;?Pl?M?S?Lr[u?>{C=X#O%=:dJ>] l-:*dþN]>~.r\>7mjnd)H D=cs 52S N >/d8mw >aU=ʗ#&=E[R >5?Ə>>gi#W6?E?.T>Xw>?B?Ϗ?k> f>aQ?=?%j>/n =~??s>x =~ >'^> E_(l>_|(>ʬ6*=Oh>hrmR8Z>U~Y7sF4۾I=-QWH ľ0j6=Px,k>:a;uy4ξfXW>wo*?f>>4׾P/^>W?L>>M[x PI>a9?>&>S)[> ?h+>W>y8X:R>:?1?B!?"H\ghE=?x>m>3h=¤?>D>Y|ʾO??7? b>q>& 4B m׼p>~(3Ѿ#IM8[Z27*˫?ę&c B X-exw2]"囿g ڶ tH a)=K]=nf2/=' ]2׾XjT?4=2 `g'"ǰVӾܰ8U뽾>6T>'R>5"N嬽^NR:>Ȃ?,>ce>e=sV CS3`od=C8% ~ܾv@EN𿿂Jο"B=z?IM>>'IB[W^ƩT׾>@9>m5\M>ɜ9>1g>m X8TX=bLpUK þ _y[+;="IN嬾0w37D[L>ulQ;GK I4>z;70u!>?fP\%t/ tⰾ;>ML=P>rX!I|<弈#D̾e<${B;TnN}b|{G\a!%"x[Z%=璼G=ڗ[?<}[>L9H( m^k85>3>>!=30>.==z ckR_#ξ d?6a|ְi>TT>{>3uc&N풸* 4$O^p!q.j?[Qľ.>N>_>87 gr<[?*=??fSX>qq?9>I>ͬi1@˸=Pk@:t[>'p_>w㾞޹,<֘= o >JV>DD ->A,>8(=18;ξK384>1'>x>(>@`99>k?l?PX?b ,~=E߿Կ+ C4ʨDZ`=Ǿ;Ѿl]}ck=;w<>L:>Q׽qB- Q>eܾ >.^v= x>T۾v| h=CF > 锟S>I%A>->V>>^cߦK>݇<.O=:G^K=΀|eR,kݱ"~_=Vɿ4uտKa̾1=%+~*Nc=X?6&=Cv l3>FU>is>#>,l,k>j>2v>k>&Z>'!8qR~(&>HV; XC>ݜ9X>BH?"c>8C>~w<>,>i=7?$!].#>Z>>B= >>>;=@>f1e=⾾ӾBIZ;=vF='xJC\Oi=*K=b}=.SxK=@SHg<. =T㾢f 5"3<$<V@d#?>b>:I>Ikv=?>־݇Q̼ϿBEٽ^ծ? 5? ?_Nz=`(>*J>>/>>2i;>_6&\2#n7x?@^>0^4@B =C[?>>Akn H=?,=>} ϚW)=?z?t>Ѝ~Tq ?>Nqt?>Ng>Ϻܥ?NЁ|>*ƾ膿$?b+Š>dQ] g?>Z??HGN?r?v3?ĭ[h>E?D!?ga5?k]h?-;>R?'=\?X?X-?X>g?(?V?\T?bK >q?fn?U ??a=l>&? Jb?k?₿l>$ ?G4?f?he?tQ@>;3=!UP>u׈><x V=?#N?ND?a?K?R>u?^!S?T??$]_>mU>y >es?%=X2j>?>8>q>?}H=/ݩ>>M޾>*?b=cq>?Ȇ?Ǭ?a(h>8=L>> o?޾=.?u? z?+b=@1wu%>7=i >K>>Nm`>'[>&>>>>!T>Ո?;?5@=7i>:~?'Z?=!?vsd^>0>;F>X>>H>6Ă?0B1?J?ڿ(==K>*>^quq>, >+>?$h)9y>Mᠽ2?=B#[>{o>F>#ä?? ?[>64>MSH?f.?|?(Rz>nv=Z>N>Ա|I>YW5J>>=93> 1>PY>^?'wy5LW>/P>f^>v߃?UM?D3>ջ>Z>?8'>x>>*??>]'?U?`W?CAB>8>X>D?k_U3=K M>-> 쫽+>V,j=q=Ľ>:k=ƾk>HfU=U~Yߜ?vS>'>o>FWu>>A>#->c=>jvS>M?@> >>Qf>#!`< >>Ԥ >$M?>ek?*Dk>tI?78?$?Fr.ǿd=ӛ? >ᅌ?6z@o`F!>!>f>~`u= =V=>z)с>^IoL›a ?B>$=׌C>'|?wP9>y>>(?MG=[=> 2? {>Ru?6L?;?Eiŏ?*$h?@?G(ZN??6?jmq> >?06y鴾c>>v>}?@/9Gy>>k?+}x >>8?I`_@$>>-Z?.??L ~&???Zh >3?7?=?{c=>!\>>Xy0R>B>?bMn6D/>47C>0=^ >6w-?{>R?'G&8&";W<⌽k[S;>KnFP%%=f#A9>J >JA?"ZQ?ʬ= W>fak?sY߃>CMž_>lf}>Igw=&E?8\?s!?`!Gpr×=7lH>$" ==S>sEA@&x9ͼv?+wپ>R??Ӟ( _JküMB!>>W @m=떾tT>Q_1=|-9g[&>JZL¼H?73̤>i ~>!& ?\c93z/tR?0y?Mb?<@Ӡ񾢑ı%=?DRp>> >?=;Q3 pu\>qaƏ> ?YpAܦP=R@t\B~]Jˆ~=(:L#1pJ'OK=uA];BE9RK?5' >(Ɠ+>,+RirP>̗SAm>SJ->.?Yb|>4X;ة_@>ѯ+@B^BdG;> |>2 ,>>>.>:26$=iҬ>ɾ->I@F=/w`?>'Ǧ> 9QSPf-抇;W9.bw)>%6p =;:%>q.6>!Ge>AɎ 6?L<+=׿/.<=LU@*=K=>(޼_>"u+Y U=bp*=Z46H[%nG>&пD#]n?sc=Xڿ$=h"O=܎WAn9=88zuEʾ7>]>>&2\.=M>?s=VٝV8_LlfǨS>(R.'>2>-_}b=fr:`px= ?v2p=磿j(d̾Dd?ss^=-I-_( =vg3~>TdDi?lJg 7P=5jDG>T>>7Fɓ >I>>"!%=wJ'<{yپQ9Tscsx/>ǟ#7=nIu>@h=@|V~>f&́[<+I#Wq>Y9>Y>@ uFZ>dRi>IV'}VRl]=Z'a{[E() :>\6)ݠ.=$v.٥}?>hM4=Y`o>}YhѼ>^ ˖_㾷Ɨ>#>?P]d_> R<?>/D =|R[h=;us[5Yu>V -;Ρ]H?P/=V>TȽ@P'/#?L?t?:0Z%Wqc?? +?1p8l=B ?'ߠ7=#` >V> ?eJ?l?#E/p <+=UG> EN?%D\ {־F^мݳ9>?2$97<=z?B-/`F,`V>h׹c~9e)9=p[0R=˾rAt=f |c=ң>ZQ]OZ>{>}V?SջUW7]>:>}w??B &_R3<&= ?%%@Y=WSPG^>;(>/>b>D?<I>2״>&Mz> HZ=&x->Ro6$?7s>@>C> )?0a|8?U?ା=9;S9A՝?PV<l>P#hH<$ZLbl>?H@ Y  > 6P۶3AS>?>~|>)GZo? <3<=:&?o!>Ս>οK|=?gS>_C0 4==}=nP?@|=]~>~p =0>Fg?M?>+SnA>?3t>j=Ypz? =J =&|0Ȋ?]=vǨH>Zy5D|xXz=D>4>lƂ?#_Z>4a? P=a>?hfxʂ>4 >h>Q")+>mGq>7> > R?0!p36=QZ>F?>YP>#'={?-?^n$>P'ټub)??> =7v?tMf>ވ>!93sdAPI/n+ȑ?ݾIfA5)o(,c' 8ti>>>d}!4e=n=w>߃M s>yL>H??`JV>^>j?T&;`jre'Y>8PGeIv>'8F$5' ?J?;T?\-p?n?.?\F<;D?-q??>>#=f­?]?U"?,δ9j?Kb?+> @&׾_.2׈?=\`/?? >m pHc@F?b?*pa>TKo>X0$잽@= B<@>T^>@('I>c> A>Un'n&1a+ؾs+Q[Kg{=e@IxۇË>kUC>+3۾ZULd>m+(` >!b‹*K>t辖\p@?pm?-ɿ /Ia ??D>ù=h&1@??;N5#qTocX,Ѱe %s S!l>%eg=#Y6&?C('.1t?l?re?~@$MȽܒ޾3:G>l?:p:'X~(>t2>Բ>?VB,)5Riu>iRZV)?-?+s?J?7z=; w=p?l>!>gXi?{19=#"@??y埾3H7>2)??RU? &<5z5??¥'?;>rj(I2+=%Ͼ z>bbzx=Rƾ >aHؾ/>aa_= >YhѾ]yEu:>kAf4x=M>=R v.PEt_K=`Ws?3(V|??A>jP2$?fy_ ۽ͽn}?r =g%)0C=,v=y;8_?\>4 G&qy, ?`c=򃐽țrg8?f>*>% X]<|gc B>}@:0;u.T?]Iŀ==yȿ>cZ+T=|->_% akQ=9 #I= 7z^>E1?Ò?YC>a?c>޾?"W?>F!ak==p >G#0`>:`==(ھHv> MMؼB) ;Ž@BGC ]%FGɾ5<^r$z">U!uC>g& R#>q>9>n?Ll~=z?%~9n.>A S>T=l[2>_0>.> ;ް?!|>m¾:#}HM>/D;>"J?=2BJ &qYb(?ѯ?$>H/(mPҵ WĻrl0??AA?q7x8mۃe?(? >nE(8̾B(ѿ!ƾ{3 D=XsTj 7K4>UP?A>'>G> |5>@j?(͸>L(=ď 59qNeć5=վ(3r)8rQ=c>#n,>v11>$dտM]>v>H]Ĕտd?2y`>4Pj" V>9 `cZ\.ξ:LX8U}@,L๿&\G^! 2`Ǘ7Tg;P;@ A=q >)߾N#6kw$:="gn,_`=5:3YfӾĭy7i=;>=ru=b7,S>,?(w>k>K'+ Eth'O/;cA=ڝ?*>>1>q?AD>I3g2> t4J<5N+'.bBӽg<>ľO%_Ԣ?>@m%M{%?׾'>d=#"ȟ(tM۾ $u#6 þ~,&Cc~44=,>c>"=bedXb)>?>K>GYR>`V=/2<J>A>7>ʣ<о*,>@:>/>9sr(vDzd/W=~A=̾‡Mw'ƾ2iOOȾN|> o>Ua1v9^08WP r6{IOjB D>BO,=qΔ>R.Ҩ"a@W>Ѿsm>C1_"xֿ Ť5T=I,遾j> *h=:>Ok;7`UDti=>޽z%rv=s(ǶU\B'H>I>0'R=>DJ;/0>y%= <.Go?1==bPQd3B9>dN>5=aؿi> [=V!u.>׈O<N-G9 i>qb,^H[>#9~ܦDu=>L=hoS~Cg&By>Od>>\=>I0=>%-f>K=x= 8a=XT>-=>h>Bj=)\dwフ#S?L<> >[>a>rυ@m=ʗiZmVſWZ=ϾhJQF X>Q8? K>{\}jˆ0ɗCh'}8b===PD>t>M cd=?>$ycg> Խ>!M>‘>5W cU?<E N>F>z>0T(1SX?yzR>MPA <8?B'6>x̽88Ah=e?5H߭>1===]=gZ=fz/ϾZٮ?^>}`>0Nu}4ϾN֔?0~L^>Z^dD=(?=>Ag>$ȽjY#{??O>S<`gƾ0>܇P>:^>H5>/>Obt?,(>4^Blؾ?$I>9̾ޕ|?>A?,=W?_L?f?l >O$S?I?o?wiD?~>U? K?0p?=?`&>lA?2M?^w ?jM?wLw>?V?u?}Y?5>b? ??y?f=ʻ?^u?t?h>edž>>>;>^t? 0p=\=]_>> ? e?S> ?e?%)? S?&>͒=3>> ? ?=>>pe>_> *(\B>#>}%>R>Bf:>.>E=>Ζ>?P@;f'>v>3??5ǽ>ɛ>9GI>R> ?%2$@ ? i? I??P?9>ծ>>?%?)sM"m>?DdzI=m_ꞽ=>X$=p=>>%1 Q>Ȱ>>>G?$"l>.<9,<>p?L>{&?T?`>2?q~>\>e?B?O=:?뿂v}(<~>E>?[+AӽV?ir?]?Z Igp??^?LXS2*dѽ.y%>3y>1x>nV#'?\?R?{d(Gx> Y2=8>/+Abܾ?G}?=Ԧ?i-k"3>s>pP?HT7>.W>>ۨ?g̿Hsb?>}?mU@>>4(>TD[?ƀvu=Xc\[>_7bt>PM>$>]?t\y>$%laV=>>bsP>ΣY@@m;?L\?Jz?qv&ľ>>Z?Yz9j>>*^?=@??Y>b?6)?$?W?\yV>2?n?`W?3?*8O>[?v?]?8ͧjƽ?!?%ɣ?Vbg>#>?\=y73a?NO?Pj? Da9EC,c,>{;cL>v<=Q?1.`.t>-1T(>YS 4S>{t<,> ?4]1=C<`=ހ9>]%?Ж p?%~>{5>7?.ca=R>o>N?&އ>z9;6>v>5=7>Ӟ|=<>7>jI?{=?_c?Kȸ^cuov?d@?Fץ?u5w@sX= e#Hᵿ2J=:lhQ1,R=8`Oj4-:A>x->y?'@¯|:={#W>kU&?bp>+? f,?q.͇1k.5ew>yJ>V?F?J˾B??`+?2@혼wuIQ=>E?V _h+=IC?t?T ?6(,?U?4L?bĵ ԍ:\>?u>r??@x=סF?0bZyb?i#Ǫ>8= ?JQ# >J>M\>G4>>>O??`\m>K^ ? 6iX} >־X(f?*B`5LRTwW>=@e>`=/?N 5[=?$ ? ?5*ٞ=0ھfs>=2ƾ>9[8L?.?DN>{._ !d= o?To>D%!>U\?`_);=&1>Nο.+>4U?N?8M?bHa0o=l>T =L?>>U"orR>84>ؾ37e[UU?p7?"?` =q?0>8n= Ἑ> =>^a C>녃>ȶ? KOY=zt#>~1!a=W %xg>mHA.NQ>o>?;.Zl>>j>r@>E> >0L=j䰾Xu>}?y/=ҠfTQ3GcN?{ah=wR = BY=H?j{?f>? v%"CӍセ Nq>>g%.>=>d=QHV<1=]->Ҿ'>q>Ž!q?B$=*|? 0>T?z>6>=>g;(_>Ȏ>;2?:l߾;?,?? ?*́0`ؽ11fV&>ʸ(s`,?=<>C?"u0&'꒼@T$`ڼ8+(=5?Sҙ?$= |2ʊɽ9=VU'G%ľY~=><&X>uv}y= !Ͼi>! Cȗ{lz>>xC>mU$lǥp}8=Ct>gDp?(m _٧=wʿ:0 6==/k+V =}_ݿ͒>Dk=ƾؾ>)@c=ùkϥ=,_9?I="}ݚ1`@\8|p>d>#X#U=Vſ꼾>sue.= Guھۏz>p c=٪a'">E^>fe?^,?Б?(;?ĂF>\?M?C?@j#G<>wB<-)2^:Klz?>R>LW51>$'=F A>e>l?Cm[%&;>>?#Ȏ#/'Zit=`[?|HL=e? VA9Sھtd>f1.Y=B5? y>v=63 ,0`5=@->@?'&7ꚾi>H:>o?:ў6)Hy!;5낀>ͳ>T˳B>)i> i>=Ɠ;s$D8= G=?&=)?B(V>ICκFؾ?*s>q_mN1M?c5~>>\}$kVEhfJ'CO>? Ľc-j*\= a=>񔟾k{B>kg#,>xHK^=Y?{ھҝ>-? N=Q?J?=>l ?k>2-= KpdS>6"= >!> x>;¼Z? L680 >; >Xr>at?% =݉_l= y)X<BSo='Frᄀl= ]=Li)3],?H =?pr?3k>#$ ^r>Ě=l>4?=.K~=Hb.#>t= yk>U?Ơ?R?m,N0Wg>J>|>r?!`p3>==g9?,3L>=t!=*?-2O=VE>B?%=?!q?)>tǰ﵍?$%?Β?'^"U>$>R>NoҽcؽɤY\hRTнb5^4!AЍ aRad6MW)mμAg׀h,o;Q0i@%򽡘l>>? [?'>j?i࿤G>c齒 K'?y?f>'/w=i?"}1>G> C>(z炾 =S;|=Xb?' |?ŋ?#V= e>(> L>%GwH>km??&?oA* M>?3?<}?z[=# I*?;}a&e=oνj_?"Q[A2>|>7G>V?ar&yJwW>R>4>EX?Z?aq=27>IU}V?#Yh Q=:?gg>NƼ400?Y|?F?T &Нe?f#? ?rMm3#?[?F??P???\⾂L =u?>>h: =MS?h>ѕh>7͂ԾȜ? ??: ҾR>p:>>X 9w)@?Vq?K@ ~v m <ξ^Y?/?.%?F1@@<)6ƿӿ+#HQ@ #!Ӿ̎?0J`=l%HԿ?.=ȿ8bNbHRl <\?/?6}V>.7pڭbEc~>V6>=?Hb,ԝ'%]@'?`8?`>kƷ=簴j~lھT>q>xz^h?"=`v*zllv\+@FX>e+=8R>V :>N熿{ $/:޽"?JI?#>%>8G{=1hL>~TqM? Q*F7hd6/1'?o?9?S%j*S]?\B? >N,An1|?4>Z>JOZn |-?$?3%>07 Y㊽>"?6>44X!ݬ=Os3v?TP>+>)l.me ?ub>VE<@V) tル=#>{ZHTzd:8 'o{N"9Q{bR Jq޿i>!ɿ-Z$Q=o"z>MR>2>>>yq uԾfiN>>?]>=Pn=>l3= O'x>Ih1̑Z= >˼7"&>/veQA[>~ԿB8>%>¾蠐>@tMc@>W?D?>wEՍ>B?>=OCS>67?@!>Y>VS=ީ?%S> R< h>Ľþ> 9&GQ0>-KzW>jZ>s|>5Ӿ%>S>e>=9=HA?98l"׿==>t+aھ*Q=o0>5((]>?&B) =]9=پO>b&X [=ľ˼Ѽ>BlC=2 ¾=~T>2z =aE?($=/#>9R=D?(PZ->6þ֞ =ѥ\> ,=ʿYXh1HQpm=xS?>,w>fK'>O??*5? [hl%}`<|> 8riR ?>"=笂; =6aϿ7$/8\=S5K8GؿSB"=?M>Ѧ> ;H=Y?2i><D[9o<>Q=ٿ."=h?;2>G=daxgT%?~?M>*ajd#?d2f>KBJ> Ol?>$>8ӱ9AtH>A<=0\}AăM=i(Na>ҵ>A5"֪bJB?9>&X%)`g/b?<>ծc!OAKnh|6pn7 Χ|g)?sVޘ0qa[,X`=*Pl52x{-~:Q>Ne '@'?i>ys>Al? Bl>;:Xm-?aǛ<-ž "3nr= V"(qS>fiI=4=g"(%>w`>5i>Ų-5o>>lD>Fo?[}v>X 9qҪ;>l?>>t (']>t=r=be06\p82B,u1'= G4vQ/-f > <r1`^1p=`ܾcu>/==:ݿQ!&jM>v<ֽ>!7vW'<?S>D>AQ?(5>m3)o>]b>oԾo3>I؄?ZA>XI  )V?i >$<1b! Oa ->O>;L=B>> >; 8Gy4>'8a i@=>92/'KR{1Oƽ#C1>=ݱDyA}q?>Qm==A=2I^#/z=i쾘mPvI"\=}nA ņDfG?>k3s_ゾH?@y#Y> =.=߳tQZA>>>0>ЁQ0>EK˿wB\ >B,E ,>2[-b>]$l^?]>bgP/>l%9>&=v׼>?&H>hp>B>=-=XHphL>UY c H>>@BE_k?!'3>h?>.j>DK+>K)??=:>v>> *?|?:>">r뾦-*c>_? bZ>a$>rA̅e=o/˼od=ͻ8 J=W&<,`FB>*=@)r1@=Z? %>f-IQ0> 4Qv0>L1}B>z:0s=7?k>y?]k>B<] =?hT>J'{?}]u>TѾu? A}|k'>Si>=>Z?"@>#l@!?m5->ST,%F31?CE>`~?QC[?q@?~q7?}k>i?KM?v? ?C\>^?JCW?f$?x?]=أ>Zm?ժ?C?T?>,W?(i?D?\X?>g?G?gQ?*?|>7o??ZO?U?re>>?zK???;>a~?f?E?_?20> /?Y47?gE? >,R> ?, ?A~?_W;|_c>d?]?9?8[K?Y=?6? ?,?'+=?>?GX?n /‡>>]>? 3?zM=4+>qm>⬸??@=ʧ>>,(> D 0=l>e>zG>:T?=>,>mI>t?S=~Z>(>_ >ꤺ3Gg>H>Ă>?$V>>F>ib>*>m;?|I=>z >0:>I0aH???P O8>`e>>u?7*k<!:>+??#f?w1]>g>=?_?ij?> 5L>D ?3A?=/?& |PHzJ>0'?^>ܥ>c><>M>?0<@ݿѢW?"H???Q>1acV=R? W!>B><>>N ?= $n>? 9?>K?E?\?'?k~>!'?DM?9 t?_Z9w?n?ec?F2򀿫s???9? rzGO?f?] ?1bzJQ>>MI?=sCxFP<~>i<=>Umx>$=Rq=x>RȣwǤ=?;0?8??"<=jʾG]W>_췼ēB=Ko?p =0;?{c?@?6\e;o? ??2п޽F?l??C;ɺl=-w?4H?)?]Is;>`p?NH? y?:et<>1}=%= ?8V>7n?=oAlչA‹L=R{؀L:u< 2VkVI>3=A>?>L>G}?p >_?#Kb?$>?lb?`o?܌?V^Y>?i!W?Z?a1l=6L}>`>݊?JnvҾl(,?B>?V2?d>Ku!>Y>w?[l">Q}ÿ;<{"?,V?.?g5>N޾(+!>ǭ> oa>O׿ 1춦=h`8J=>F\>L?cM!Q>t>N>:.?'|oo<VzS^>6Lb>Jw)htC? x?L{<>= =>h-{?i>h->mn>?[[?8e~>=$74!:>DU? =>>5?$>?>?.ǖu=Y>i >,? Ud>3vx<?$ $>.j>??{پL^>q>x>Ó%?z qLޏ=A>s> >@>m)o=A= F>0;?` X>>ZE=>=?>?=;C3>잾J2??J'=U?=d? ?QPW8 >B>j?}'4=?9[?i?Gf+?t?Ul?DݿRs U= Y=08> fNw6=>,?qE»I=i<?,I?Eg?>OU#u"ýK?c;2?E?r@ 7w??sJ?e,ǽ*Oʻ/>ȳ RF=j9=e9&ٿ"F)  !3>]=Qz9dPQFcA=kb36ץǧV >rT0(⠼(8+)> G>T>Í? 6"< ; =Alqh>Š=9~&i=>i >_>l' >]y3?"_K>n~>E>U#>]p)A==d?Hb>M>| վ >?/>%ݿ)> TT#0"1Y=(#=b'>CEe []4Q׿>k'Ӿ=}>wl>1ܿʂE(>}Av>ySOw)>]A>i?V=+˾n>ڌ 8?JE??:?6ѿ3Ͻ>xx>QP>@ı=:h=!>n@]QAT=h?#B>'6=m>!)?ZSE=>)l5Fh?TG?8.?0[AV>=L>.g0׺g>B 1>?:?wVB=h[V>X)0*eǽzY<=i 85$O=IŤ 1=֝N+qھR}="/ ɂ=̿X)=n}=>GtG( ݾ\~(!>Gྱf>>5x>d?@t[ٽ->U0 TJnȳ#-Ծ=Ԣ `NpW{=K>g@>W?Ra =!vš>.9ܢ4n>1Np^>gH/0>I> k#cX.C'BS>5Uq.޾V> 3dc>;?%K=\slbQ|xdN! ߺ3'W`??AHe;>ߐW8_>\b?N?!?L xCRk=Y>GY>m(=&x:Ć? +cuHx?r.?"?7z_k#Ի $>? GIA{JN*H>6?h9E>!G?#x6>ϲ6=X!JZ5e|ObR|??=P?l |5> >?F D⾥,< >?G0?>j[(=>k,?/>(`>/!xp I_.I w>la}>.0v=?  >K>?mAA>$lkh8\d?# @>TD9>PU=6?Y/<>A\> ͐nߤ3i>v?Ect~>uKc$>`'@<0Y>`4;>6?=<ɾ+=.`V9=)Ua*<%>,\ݿ ma=!,=L )?^8>GZ?pf?IF>G?4gIs=g?c0b>>d?[X> -?}?q>&Y=~jND=>=!R֙)'>>:m_Lľc>28hPοT]پ9pz>C ȿ| P?"*>=`<?zB>z۫>=ߤ@=S?,%?o;M/=na?4>B=>?J *=F*>}ݱ G->}t V@?@@A=dU׾+<=|57;$o9fր= %XBGI?<})>9>Z>?\-#Z#>@N>/s>>? $`Q>\>ݠvq>=gĭ> >tO?H>?;H-?Q?i>e=?2W>-ZN  Q>.=T>r(/>s=A=Z>1Y>M* [p1>(kӳY=K׾-v?inT>$ľ~<^@>?g"2]=P(?&4>Zl]F cZ?> >i>D=> >!>K =?? [?V@<}TTf+Y<%@#M=p;b>8+>L>>?R64>"; =d=?=r&/Z=M=z?: >")>1|_>r?MEul@ܭ?^qi?H?M΋=Q#C>Ӊ 2B8T?$i@?&?XUAP<>T>OH?En2?.Ă?r?ETŬ}?$(N? (? х%`ݾ>4v>>&>VA`1{#>W?= >(n ܾ]>Gs>h> J3ar>*̒>->?v >5]ZG=]?>9=,TE/ѡܼ`74=TWPJ(p9$>(P2-˽X>w}=#A?GQY?N?W=0~&#"$^!??=:>/>% |=a?u?! >>!b=k?y>=W,'=%?Qi?,>Цv*M&3?3? >>2IHx̯JDB@@;Apz? l>5?9JEz4>X=I>j+#w?uZ]3۠B#]MIRǓM_A?F?6?CFj>9^/ v#2jZ >zf"pmb>W羄n+m>< CX>)ҿ$=7. y@?ͣ?_ *vP@:=1;>mH=a X$"h`3r| kP=gk@ٿIfh =Lcؾæ>$|mu?? >|f1x?q#>M:rs=2BVq>\sknP=s`Ǭ>v%> >>><|=$Y \~,> ?F#=-&҈9I=ȶR},mʾ*; >-Bf`fb76ο =kP>D$>i{='Qt>-0F>wJw*ニ>gaA=Dݿ;Z[1/=lƿ#n?^e|7΁cA>WҢ'% ->/] >oX:Z]W?zO>6~>O_LLvG;!G?11=6.m^BF}?>%>rwj=&?j>,c > ?a9>W> 2w>*+1?G>>o|?E)x>hl?">MV*=Ίrp[p=4 I= ={HӮ?¾z>wl,C=]cq ":>`&T$?/}F>lY!ٙ'8AXx;7c$4Cz*dc^׶)P}=¾<?@>@ݿGTW?WK'UC><?3\>O>SV?O>1j?3AJ>>>Tq?q=q?'?>}9>'h򾇙=rBоMQPEؾ>u !wG>U$?@>W>H>;$b>XB?v?>N]>-I8=YwvcsIB? >>SSrK;>>;=6?q?|l>=HLI3e'e>b>݂"Y25J0>=>8=khοL>>@HZ>JE?y=sK2_Ж b ^ϧ=eDu,u@x6 @KM(_MMϿ}W@`P' ,e=s?E P's=Np>=@Nyp=mO7Ԣ+9V׾0'=2Ⱦx>d`WV&9j{`(x4#U"vEƿ]N`MX\/2Eg(_SܾMB > ?E >&|t*=&w6=7ӾE/6%=M,*ErL2nl>>  M[ω@>>`|n4W\yz Kj?p>"&{禜=7 ?B>E҅h[S(:b?>j>8uˀ$j%ZjX32=\SqP=@|3澸xz`B< :]:sY>)KB$?4/>f,4?>]RuX D=G>0#)=W`>'vq*y>,>/V!g^0OM! i{P˾̾M>Rrtq>;{>}H>-GFj?S>R澧6-.Fa>\AC&#KB=^pP"~cHV>&{徘)(4?nf! W>^>U𳼍psyvl>L> >t>_!~<>\"SBg{sH=OMOl[3>;>_ݽ~z>?$>;~>Ζ?>si>˟>>x?0->$?C>x>Q+?4G%>w>ݦ>Md=<*@>>X=+Z=I"?>Jq=9xIuż h6X>O!{oJq>TL5z?OQ) >>jw@ξ=st>(B]㾕^^'> u)>)˫!!ɽ^2?k|f\>þ5I4?Q4zj>Y콻p8v)?R>@Ӎƾߌ$?I*>X뫿G?@)'>?B֪m v?4>Dh퉾B??^>y[ýC?+q=߷ ?[b?c-??oe>E?Z?^`?">@=%>⥃>X?$}?=>>? ?D>U>V>N>m?>Is>̴>>r?:~ =ڐ>zJ>k)>[?7`>>#>I>ڊa/g=Z<<>(h=2=|=U>]!d= =p=ڞ>mۿÝ'y=!>@>1>׿4P>t4?&>{>ۜ? l >q> ? %?)V?3>6YKT־|=yVnSP>$/쾒<= > m>2>>c?9 J?_t> ν cGc>?}X`>>ܱF<>t?K>"nN2>jD?=>S!>za[?c3>=#Dqb>jM?sq >qƽ>~u?ֻ?L?7]BI_>>?/iӿ]>>iw>K?L]%jIC>ɾZ])Rm>+?s= ;`>[?fSt=Ѿ>GfA?z>?Z0+N>UNn=^L$1>-B> =ܺ>s? ?>>)n>:o?>Q=wOŠa=?/L>1þ_>H?1-a>gdf/>1?*>O$< ap=vl??P'?l'1A-=$dgJ>hVR6<ɗ+!K>ֺ_f>'>$>f? 1Is>ʏ>9?G/?@rb(>,8>?.M> }>^vSMcE>H=>Cn}_>K?v:;>A.A>\>b>?ppe >>+>Ka=7> @Y(>XX>?1M )YS??m?Hs i?5?a?M"6>[C>yh?!O>3;uM>)n?G/?fP@h>=:ܔ>2ރeu{?p7??z8q>UX>ٷ?r>@3> >Fx7Jw?zA-&~ ?ww?Za?,h2>ր㽤M?ދ;>vL>*+>? >b? Vss!0> ?; ?!s?OS8->HJ5=$'>>D?>D?-D>fv!vG>*=kVIoyB^=]x~YyҿzT>#^ ?v. :^>+ ]̾>U"j>׈>>{?ol@=?lre(&@d>s3> =,A>%D% >[=%=U>ae-dEn+>v>m>ķo';KI2QK50O?'G? Ӯ?M+ +ZOH?>?)r>0<Ҧ>? 3m3>HxfϾ ->A>AҞ8q%YyJ/q<>x>X%g>F h3ƾ[t?WZ?O:i?x€0vپ@>߫>i?WZ-=U' K=PqŽ>v-c>^>?PR=K 0>oE?) c>{WѾ>B>Y=r<k&9A;Q=N=/~L>yCfz_?#6> >uaԾ%f>$?H=Je4O>\A=6˼T =d >D @P3=ӿCgϓ=81=hغ2}@/>6 l,\뼰[A=썿Z%<տJ>>#n>u;Nt 1E)>k˾X%>[>ε@>AYžS>Hb=j>=g>0V3;Pp=7{=3Dөvj*JFR%}YD];s>H4/z ASu4E>"{k,ǽҤ>߂{<O,o>A?2^r=ߋ?IZ**>SH>=K=I>@>d$^>:@>U);=Hb>9#z>>|>Yբ>s6;*p>Nr=>~Κjs>>Se?3[G >$>3?6~!!>\|R =Guu=r+V2jQ>r>5>>@r>>f& >f3>=ҫ>F 鿪R>FO,ȿm? k?t\W Q>Z=o>|4`s>"<7>E 9eE>Ç{?8W;Q>?%O?e=κ[ը7=?!?A>[- =>s*f>)?\$??'۱0WC=櫛?]1? ]?"ꅿ9;0#=۫?1>q>PH5?G>{>ޮ"0M;ʏ>m>` ?2- 8&+O?">_>I2>O(S C=Q&?=^>JqoH=p?FD*+Z>6JϾ߮?8P>?0R?c>hlf¹,> ?I0Q5%.>\߿1Etǀ=۹I`*a>\b>Mp7¹$d.ɾRc>%]t_`ŷ>>;$iсS*%N?t4=?8D>=^ݤ=sGvv3H>]4 B=#yzTf>{liXR>zO:'t0>mʽҽ9?$/=?R7=ŰW@>>@r?vvå9>}a+ ?QР8>ǾN#>n"՛>c >>>er8vǝ,>6P@!]>!/)? `>յU>H~:>OOoeLYaZ=!<$e4݀W?:ӷs]\DVpa<"Z>2\>K*>? &ٙ9=>>C^`<=QvIϾv=>> t&>S N5?3M^>,Eki?0Q?.=MD> Ľu>?!` =ÿr?K>x,=ou?} 1=k?+i49?;X=W>RZ 5&f8>s>?>A?/>F5> >E?}ξDx?#j@? b?W߰ IX>?d>K>"1ľd?Z&?7q?6GFQP9?K?.6?.07Ac׈̣=DOǏo*\?C??Zi=檏ÿC=ma,?i?=7?i>">ذ8o?=e?3?|J5<"-pY!.go`ÏOtSy[O>؄  Z?jز?l?ob?L?~k?nX;4,=>= =ŧ ?rC?#?]?zprS5P=㠄mR<%n!fESwR$XG h>?BKhlϿ'8 # mYLn9b t>DR ?>.=a>9>E?7>9RLi^~?yf> 3X9ć;&?Y>wٿ,J1c쾚:>dl ;.=뼿j_ л渾A5͛*>-"B]1>?>E>lwFhN?W8>%?@?/k;>D??}>PF=ri?1> _K#>s?-?h>) Gs>S?WuqX )?{>>79dY?mw>=fϱSO"??;+ܾ@BORI#?:>=)Z/ʽYپHw=&N;Nž, o">9+)>>? X?õ@K!%=)ܐ]R V >1eQL½Ȱ^B$>a>v>aa@t?5/ 8ދ5%̿gAhd>2 t޽A [?!SIZ=0>a_m>TX>u=7(&>/VT40>B?A>Y>Qmw\?9=ň,PKkƾ >sK3RLsۡV? ߠ6T~>d޽YQ>`2so[=Vvlp?-am@>KDԼRd2>=-o_g>8 =M>/>gE>)t @la辠Pk?6t?Pޱ4>/X>]fy>Q/\2s ?LB>ع)>>R C[>氾X=$N"澉.*Fžݵyh=&=%N_+Kǂ`x hOcs=*F=_R?*¾J>LsSvY0v}k>UOc8D<,;>e{뼓O~=Bӣk)6}aA=/]hL򎓾A[>f~t%eLE ^ھo ۾k>A0?z8v=I7?D$>ܠ&ӽ ?)=᾽.Q |9?&>Ip(н1MG{WCu%7վvQ+=,ؽ*L@)5e'>]#=EWOM,>N\=#R>6L$BIɾA?sk gR :KF,Epv X4^VMTO&M^?=>kv>}B7u1/ ;3Ix J,6S7(Hjjο=EؿjZ YqcN=q]v#-o= \6oag2H _(!=$:i}WXXNQJ{+g?Xy>a;Xf=Z?X%G. ?GQ?{>%->"ʾ?3>>%`vz[=}{ j]{C/@i1Ü{Z-ܾl~þxF?^L>UG'XJ >{E=֯&SKI7?~>PrGp=" _H?X\6?L4?Oε$@vǪi\yN>"=Z@|_ΐ?^ ?><8!6t`?`W>G0@=ϭmؾn8O?S=wna&5Џas¾5) 1sCҋ s=+$]?T ><ɾViϾ$M/>5=ܾHnN1>)`J+?c>i=ھ\1mh%g=~Z}>#{=\ֽ7>¿#<=$=ґ.q~E>(oN=)eC1G>&< Zuѿ(3S>‡~…f&fg4>VX=kr?=48L/>1Ӿo=l'{(>! Z>پ"AĻ(b>UE=:}AP&>g:|- پVu?>Iҿd쾟B4?P>c>"ÇqP*b?mMj>K+$.b(>⓾i ,>ݪ 6%>ٯ~Ծ6O>Hn>`Ȧݣ]?S|>,*ҫ&l>_n>h掾F=? "g>alaYィjM?m/>\# M<6?KYy;>\:y43y>oCL'>=) l(p?w-ې>J觾q|oz?2?>Cg ْC?2G>K1|# a|?%-e>(ԾmZ_a"?3S> Rj猨?=J>@"@yF ?H_>)kvݾA?>>?oD?c0?F?}|%>Zd=?sh?rw??w>D?y?wO??|]S=K>>?P? S=a?P?8?7w?Jt>?H?Mx?v?&Z%=H?y??:?9=Οk?ܜ??FY>=˦&>f>_)? #3=cN=ىY=>+Nd`>Kqg>ADXu>0Gִ͆O@?R^@>| ߇<ǰ->]y{&JH?M??%D¸A?{|?r?2G忘:?0?*?\ 1~8\> '?I? ?S%->̯C_>?z>#i>T>E?k|xȽL?F??*?o3D؀(3>>V? /*=>ot>Vu>3[}㤽? M?8?326~?>=>"?>5,>>1>?1iV>W>5?P7orO!C?,,o?'?|T8~">Xm_X>ο{N>z=>? f>l^>D?m??c ?? >9E?f?Y ??@`+>˔>řF?;?I =$ =iX>K$4>Y>z?D?-?,>ƾНH>?V>꾑_>=1>>>=?-Up/@>6J>>Al?3nU=i>Q*>O ?JfBE> yC>T۩=c|=B>.k=>'h>,:? Ya=[ͽk< -> 33@=۾>j$l=gýS*>ZO?)X>=h}ԾM>̴> ]=z[E2>dD?X=}œ>->4lv? x΁ =3UI-E$X?w"ӑ>9->(t><6>c=5> 1\!>9???>'<>b(>>[꾠zFd>>ZS>a 1<8??T>-ƠvA>q> 5>Zomv=4@?.'ge=Q?-?P?D&>*l=ø>>>(Aֽ]SIZNy_<>^Ez=DTUa= c0b >c`O=ξj4g>AF=+4=žu>nοa> } =>y >1 o=;>LR/R>1=뱯=%>g074C=Я\ٿ9( ŕ1/L!,Ͼ}YOρ;bǾ=q>{J SX>{|;q=c`-?.0?)?W (R)?#??N )k+'?MQP?K?| 18a>;[p7 O=ʾj "Z,==7p%si[??T?I; %,a&?8?5?e0 =7d=*I>'?M>N gϾYG>-ܿ<> /#>U><A>o>b>@?5{9>VJL"0+AEae0==t5;;iV?4LX2VXO>`= !ߕ!o>R>2>|?0EP>>h)>?<8;r% =:>:i>|?Hɗݢ!+=ܩ>a>6? =>+R0M3N=Z>d$>J>ľ$=>>SQY?$Wy=qRV+ TK!/>G;y>ӿX> 崿tOu0ӿ}_|>+&T,Խt>:dg>Ns>͸>"@>^n>0>5=M<>Sb7;4j?i>㐆?Xu-:+?;~>9X?Ҁؾ;o> bA? k GN/=r? U+XҖ/^=?J>m=y(*>/?[}>`gyq}>վ8=ۗx2>N>y0y>PY?0><>à7=d> Ѣ'M>++?o>ֿ>0"xX?Z?%6?FFW'.)i?[S> x?C?9GpX<_>Љг1='6wd>@ѿ׀=t>g.j?1rrK˾!=|>Y<?*Fi1?>?-p% Tۭ̾>7Y<+ܽ. >_?)rH=J1>F ??٥>)3)Xu觼ss*د>A->V?T ??p]>N͎O=H?>?U}>NWTz="?~Y>/+㤻q>!̽zW -ОV?6E>q !X z >>?j%?f?>` (JcZ=X_޽p Ž柼R>?M=-l?tF>nY>?"=X?R? =h1eiO>oԪ'>=U>k?+*ZZ>,_ΟV=C+1D֕>վk"_>%Aٿ/1ӾC 7>*jbNP*@q>N,ȾO@> lᄄ>C>P=u?о:>+vp,>)=?>x>:?# 10n<ԙJ%_ uhhd>BbcX*N>X>)> @ h? 4j0Ui>: QE%>]Z8=8<x(PX>>H=Ԫ>>6>(J0>u>o=u3=&?Be=LE>toR>$Ƚ?7?CB?ҷ5=y?`? N?x> =>f8<ک;Ym?2;i@:> k>9>U(/>;|=!~=Yր1Y:Z !Sʎ~>ľy(>W}=hPӿ <k=?c?k9\?1>k u=(g> v.$LW˼*=E$!tht :2]Fs8*0zLy ?b7^]ſ %8('?c ?>?3%\MJ?s?HA?>xpx? n>ź>#`Ϙf?!̖>3'>( \p&h տjJZEz_o (<9zYp"Wj>v]QB=޾"վe|>b@;qdԿ45zr>.fqx> w>ljov>)>OmAyB16߾% ?>n좡ԷC$$>|so:^m42!06Lld=Z<>aeql;J*^($_}?J{p>;??2D>hM?Ou==2?W>g=~5}>I{eg>kApE?2O2w;8οp<־DHz T׀>Lj>j&]=߇?>=Q?Xo=C?>R>Z6>??SM.v*kbԾ(۝=0{?/>/{'0?N>d>Rn]:>UiD??0 >@yڔ{rb5T>$>X>ۡ1t>:ܐ Խ>>>W2Jqׁjt~A<ߛܿ#Z| >P>-GYɾW?hh:CxypF;ھ`?>m=43Kj;LgA<'=>Q?>^>1EDL>3U?;T?'>;<}"<$uA"VYKb&77eczz>.'2ƾ>:HCz>kH#>IK@? ǽp۴N@c?r`]h鹑 >]nCo%0d> ?z?X> N 0=,wc9mkq;?aC>Ž>1/gNU!&BU̸޻ =A:ꚿs}iM?"%P>?}?j>\?MHU>9?Tc(>̭X>LwZw> P7Ơ1>#`?,rC=I?=zW<69 >©>7s1=?ecٖ>z,xR/=E><=>H4:?aŤ@=r>O={~ngfs&=U`-ǬrT?9CictE?D< "pJs=g׿>L/m]5> H˴>'ĂRg>.`ľ(1j=b~xU>@,=`D>P@BBнI>s= %/=Gv>P=3=њA=>xc⏿aUXWԉB\zh=QF(B=7Oz=k/羴6v>(>LG>x4LL>2#?Ki>M%$=ݱ>?Gg>boa>Dwݱ?u?>,ܾh<>8V s=>YJ,'P<K̟e@A |YGJ,e往>}F̾gnl7C=D0Jh)^ÿ 1-?Z=3@eo&:=-$w-Ã>sƽ]5a>om= >4cITmY=<<><&=ZxFb=ɚ齒=;.{JXC\= c46D?X=\A&;X1bp?f{>]>d(#>8L=ȳ>'=#O+x>=:un]=TvTkOk$<<9OjB8hEP~W?=ŃRoh }>p`>=7.[0;3Al==qԾ:C!p>hGξ1M'tia|>qA,񾜊Y= }{} >;:Bܿ 0?EA)>6u= Yv㴾<&R>\>(>u mL>wx>vþ( Jo=֝>k>p8;MX`=>o{*^ٽO>]"=:(T>C=X¤?ъ>{>y-=7=$m?a= >~x>>Eg?=3???Av?Ae4>,?:R?2?[&?OU=$> >?&?kD>.V?':?P?I%F?׀]=π?U>?* ?w>~? is6>J??`=؄?)?f?H<?8=ſ?A?[F?J=AQ =b>O) >TNQ>֍T?=o?3و?1?fJ>Ƃ=d>]>Q>L? Ŀ{=Yq?$??Il?_>"?Qr?J>?t>@&NO?-b?]=-? ?K??=K?+=Cc,9.>1)3>?]?X!?y_7U;*??P?K?8_>?&J b>6*3>eھm= |:A>$h 3>W?hiW>% 0lI>5v?4*5>PsX?Xu>w>>k ":Z>B?s>w}$߼s>?l >TH>/4$ >D.ܾ394;>ҷ}]>+~\ݾZ\>%j8?j>΂=A:\O(>cI>?da|=_1%>.H4?I>5wu>"ȾO !%>ӹ$=p"_a2 >>8?M9IE/>z>P'?ÿ |>i˽s2C$B>?=7>,.?):>dV:+>mxY`vf<4XI;{>|Bc>kN?gÿ=_ >ʆ{w > 侭hn>L}> 61>U2 JT>?S>G+=\ h>*~M[=Վ>=d>%?5DEE=???n{!d#O=ھ>Q P>7Vڽ|>^B?U~9>7Ŭ? #>-?,8?> lD?>ݺ?4W~~4k= A>Lb>=% >`e0CH=X؎>/CBL#Y=^<7ǂ >fkY:~=p^B>Բְ}Ʀ=O _f3BZ=u|*>&}_<.=$A>~D=,[^> =c=ߝ>X?8+)==`B;#IyW=ӏzp_пO/? >㟽=?&?$F>]ȾV>n>)>>zu>+>=bbZJ>Km>;!mZ>%>W޿?KW3AM@>3/>?B_R>&D>;>!薾v>DJ>= m>ΈY,d|۵&̺/ ~1>'M.Y @B=4?==>|=̼Oxy>C1掀zr>'>V?"GA$߾X?,ʴ?+?_q1'L۾'?:?;@?m')L<+[>.[>.e8AhzW>{ƿh,>rz% =PHoY>v =c|~bܽr=j10*.,?X)?V>?h'^Љ?3?4l?h`":x>>?*^F|t< <<=b=:]?=>3@q>pQ | $>=Ϳ/b>W`{8 ̿|z>e;}&SAUF Zxa>yc::GpE02M>\w>>`5>|9$'>'(<ѽ97> 'Qa>><Ӟ=S>wb&>(4>>Bp*><)dw`9?f?c?: P.?6:ȣ>>S?p+qS?4k?1?a6 878kN= )= 3gM) ɾky(彽aV?? ?:x@.,I>>>Y>o"!RxQ=?u?B+=50Ͻb>`#u=]>e? ZD̾%O7}1>gXz> '*đ}d>;" r޾;}R>/{><>t_h>{͸!h@=>*KI={a=<>(U_K6>Bku!Ï2v_?1!?K0?+ޤ?O(*g<>ҵ_>mK>771߾<>b2=n>s}8ҾHP!: M+=l^-Ta<0-A~.=afþ>wU'`=oU?0G>źt>>7><"+Jag例w 6>D=Guɾ_>:Wd` L48 *,)=oT=N"X󽊳Π>8.Mӿsͽ"$[=7?jѿ?7?:=+0/+>8lý>Ҥu&>5[T8>j/')Ҿ??}R?:M?@x)>G( W={?A^-?e >D? ͼ, ư??6?;$i+?5?/?d>">&?Wɾ=>(?wΓ<&뒿d AX>>?\@WO>E?n?X~׮8~|=>M(?$qmQ>u#>T>^?ng~˺mn>Z??n0͇0/>? -?= oeY>]l?Qdvz6>+z_>{?G\2=1=J>VL?2<0)=b9=H>)|?#k=~=4&L==X?23>n>[M=%? ~X }? >I'Ծ7?~>F?%1"E{ݺ?P=>q\W4̾CW=K%-L>[t>ytؕ>j"D/==ʿ[ &>-z>4˱>U>$ >3aݿB7+T;)gʓs> 5PL7>dKo0>!mY̙քP">LU9B,qQ>\ 7V2"-0/̑a>S7>)cܾ5>*C_>S7Í?={_>^:;wͼmb>H R>'K"Ƚ#>L+ӮՓ>(߽[u/Z>Ua#>9dcw6j> tC+>d/b[W>ֻ*5$=Bz"^GV>D>uC=Wժ>>? 50=`Ƶ>+Y>E>Ρb^0̃=>v\>->@>B%1=^=>>{L=#>5Y>?Ѫv>^ȾW/4CY>)ٲ>x%=>>D>eG=>$?LjY'C ==w`=Wu?(?j>(A>u[)> >E>a3>'̾:>6hj>[O>Kg?j; !x+>7>5c?^1>?y>gR>~?pU'>Pi?8?n=獓&׿,Ӟ<ӑ>V>  A>ߞ IY'1>_4=5=4 <=# N413+-k?Kydm$ RۃAF.8L7ƿX*gˆ<䓿:G!`+<#K<큿>X<>zN>63AI?u>[>f iMs?,?pjQ~W?eX?<?)e ??toH?^&dß_x2Y&lݵl>9&p)J LR>jRz>񔟾;>cK׿6_=WEYr-$ԕ=9ii{j>|J똾`?1?P??=EfIXS~? a>>MwO@oe>'<ĽrPnxsk=Kh뾘Q0,5H> > +>)g{>>N0D? 8b[!"oh$t#>SH>x%v=&t=Nm?;2Hþ=QI?q>g)gf/+V=D̐[<1>iNU>ǥ+? M6>U>N?`~mB>%r=;:>q^}?+;>&"ྺ]J>%?[>TQ3~q>Se? %&t>?:>n">sTDTҿ%??:AN? (@(?\> >J2nD0|_?)?z_>jJ (?h?w>o.>y>\L?%00 žpBP"$(;rjE3>  ?h}>Ͻg/7~-?^>[>>jO>?p)?V@=ҷxΠylsȪ"k=ɰ΁ j>]=SK>H X>"J'E?,{%`2/=&>Ĝ>xC?v"k~?j?3? =н! O(Dоv>2c> 秿=7 =Uu<D2;:g,->$?f=g{>Q ےS5>I? >PqjKX.`=j>ᾔϯpe1^5s>?Uӻ:Jÿxu&>!?>Mjm %=؃4>j==>ŹgΙ<y'lrɿ=>_"t!>-8X?w?8??u> tѤ8?y?<,?qjV沾o??h?s]`jWq">V>)>@\`?4H>c??j@'Ax>˧=>4]!S|…:qN-=&=V5c~=4!J n #LL)+>b?r?O>̐`/>(z<9?-_$=C)"9=,?V=&`\.eo?lh5>HU|=WTTо >7rֽS=M)^볾on2">{>R>:F0rR>3=>-~>>aĹ?|kH?Y\>>Οk=?)$J>FjU=?"μѷ=?D1H>>NANS~ѿk?Xq=1,#>%y49@>̯=V?ݾMѢ> L~=NDL޲)=v ;j]>SŽ^F=Y>㰯q3d9ؿ"p+k݈Za(>M(нGN/nt>Ymp7< Ϻ0HGR\ 鴽U)֑qcfE=fOB N<=d?_>k>֗=y `P7BVm콠9YW.#-[*ڀоe=*߿)hQ="ϾYC(Jg#,e˾о'%F::+q2> \yvyy>c# ֲJ[zX9-,!"!Q&J>T>pT>GV:\=SB>wG<ţ=+=U P=,>(:Ç3xd(=OX-Jÿc0 v uȨj?~_ >s>j7S ?+>z>>=n $.KK=/{)C҅C]fN{<=`֨T,`( x>o>>4ݾ$P=b(=iC|? %>|N>L4WY}>nn>CMF':y?S]pz?f?>>a?b9?~?S >>X?ɣq=\?6 ?0n?bx[?}=?X?B?B.?u=ռE>>?.wbC>4>>s?;L>l=#t=m5=>?>S>Ζ>?'>=n=`?2ۃ?- ?a?TQ>7?*?$?Y(n;.>?>p?(΁<>=>/?-s&>9ɽ*ӑ> ?CxƗ=̆>>7?+Q7>3连=vF?0?'?]?]v> =:=|61='>㪛>?6Ro(=@C>>e?7>/w<2?]? ?=nH>2u│{p<%?? :?@翳;=a3>>d(?K|M> ^-q&>,b^>X>E>צ;Ă{&;ԪgL=w;=<#<}a>*Y[>]5>!Y>&i>Ӿ_Ol=ڼAս#>sVT*I'={!vH>GDty=$hn;>_h 0>!?.f? S?C`8`+|]?"^?T\?L>Ft=*?B^W?.?g ?|Bka>r=`>O?4¿8>Y/^I˽KL?b>58:!I1 =W~c=;G12> Y>JhE=檏?'ʗ`ٽv1Ͼ=>U#7>{ u>RS>4?cC>g><>>2Ή>?b;>>e =?2 ? V>5|>>/L>+HW; ҙ>o> {>ZV|r\.>3qmƾz Xkv.> =Xo|>n6ƾ><=P >UvG>1ĵ=Eg哽>w>̾Ӿ>%Sj M'i6ƿ/>~NGʿ ;W?$w>U־v0쾦- Խъ#=rv@7<ԑL_>^ȓ>3>i^xI>tѽBd^E>0L +-!{9X?2?@:?EfPɾx>B>L?/fnBB=O{ґ=k"c|>˾ھ=si!!Hi??/?V7$s*nF4b=>¿I>&5\=z:7?1n>mU=j> S?VV=(ZW`?~bg??=!c=?]}ᠾ >fVA>fFʿ'c]z=|>*f? ͒>>(zEx>:$>ӗ>?>O2>O'? zp>γ>z>}>5w?́>{>Ɠ\%h&o?>j?sP"ñ?I ?jf?B8[Zͽi'<7f>V%_$ݽw )Is$(P>=>?>24տ?.m?-?6h/ Ծ"N>&d =8>XԻ?n==>2CN>Qp9@>xϿwÚ9<=‚+,=9?w=?&>?M>Y>c&?cH?Nw?<?h?>$"?>ck>ߜ?x S>?:?:> ?ힿ[l-??\?PՖ {$at??F*^?r` ~9l@??3ʸ?p1$j@V??*dN?X'BL?$?p?JyV!A ?TX?@?i'xnʾX?%?K?V=M?ҷ?J ?V1ր>c>?Nא>`>@?h;1;9<=|? >\}`ڽvgR\>mE ?:>?KT0~ m?!>?*b?&tj:>u/\>І?.>=><6?/ k8 6Dsl?q=>6?d"B=iM?j>7?E'd Vy?E?B3?!}u4? >{V8R=˰3Q޹?H^=`6wO a4OkY.>$pJνh>Z>Am>lhfļQ>j?+^ =|?|>Gg? Ť>}x2<l>7vah8N>{>]?>O>.ANDԲ8j>]vQ>*=NV>E$?]A=$J?Y'=;>>"^F>(盿ÿU~,>0o\U>@dA>>egUM!Ώ> $\r\%k>O_>|c=̊> >2v!>'@ľ (>j* >]|hef0>(V$=FO'F>Do=/a>ey''$> `A;~ #^Bp7AV= =Ǹ>&>|!wj=a> >5ɣ>wG5ɂ>pr&&Ŀ@HO>1<:gu>?_=V{>5U~Z`(>H*!;}\?.6~tC>>.>k?v4~>>t>R?j> >>?u}k0?#K> >SP* >"F=?T =9q;???>we>B>?ؿv8_?>>3s5? ON?T?%? Rпq?&;<~F(ޏO[ N?=Ԅ>ͽn뽮{? ?^5>1Iys>͜{̽=Dԉ PcȽ!۾s4Ӯ%Y x_=2iǟɡU"<ǗhdIܾM>NU;`I h>d^sC='#%y wV_?e!?&gb?(5Q=>PĒ+p<!;c>*?L<>eKϾmZ>c?EuI>FAT?)R ?/=>?8?@>&>?>T,>?n>$O>8?J='??>9=%?d >7??o>pEP ];׌C'ݾ>+A^aFa zKp06b?>ɎT>85=g>L`?^ >9>>C4ҽ=)׼nr&C̾Zÿ/> } =H&! 2D(<[++}D2Dρ=,`>+H >>%v}>>٘ǽD?n"?5O{?|LQUƿ=1Y':J 6.`=uzR`!a=w8ƿ'~=U8C==rla:jH?J~??ReIM*e?j?0?t xL+s?7y>?EuKMb,ӄ>%}eG񹾆Ԣ?i;K?-?g 'x꫽;>m=4>L' 3=E2끿Tc˪XBXs=ۿ+(L$ c()=yêz=Im@B۶ֽ+>\!J>v?>?&o [=>=F>=K>C(,>RI>y>~=C>٥MF?>5bὦl+PvQ>a>Ir>'^b5><"پFA->7i>Y c`>eoHt}-?>v>&pD↾?v+9>u%>NH`۽>$=JI0P^*?>[>PQpRiY=ak4=5ھ/>.>/B?"e>p= W6 w@x\>=E>S,b0ܾN\ 7E9EJƂǰ=ZqLfQ"npdi RLQ`kp{p=^z; wQ=zݾ&| %xĠ<¾U||7@i(5˼=CоHs>@d` gCL>BWe\i)x B~=jDm?xu><>-p>ּ7B$?Y>hGo?.->nq=y?jt?>h?=ݼR?a>_x? >i1=p1_ V&j۽m{ ̖[Ij'Q5+R\@n_>Ti=]Ѿ/C>x=Ƭ!I4>(*h=ugUR?Pb(=>o*=p>@^JDe>=[> S\U>"+<<4jC=1U9;)Z?.\p>%.>/8=" ?u>" =LDo*pNT /`r:p>G`=Do?Fh!l4"zr==Y>]F3f?ѿA>>\O;\?>D>t3Qzо޿]E 9=,ҾGþh¾>apz=]w&J?'=\(|>hڐ 쾦۶?dO^>\ν&?##S>%eZ.?>>46L;9?ռӿ>;>6(0@"?n >ٛN> t>V= x4>O fC̾žA?]E>$kD=u |??E=D K8 -?[>=5ʾ-Nq?R3=^ .?N?H.4?w?}z=˧>`H>Gv>?¿>xhw>M>ޜ??L|>m?$?X?U~F?Ȱ>G?6&?/m?g:?@>M6/?>-?6>ߨ }>?eN+?Z]}?t?*|@=>܃>A? /?>??׮?N`>|z}>Y3?g%>?`HI?r\>-9>%r>>e?I6z>i>H>ХH?=/?y5=ֽ;d+=6L=@!>d L}3>=>=}Ǭ<%*>œ4>6?AY<>>=h>8悿疾VB>3=kl>?=/T>c>Y=.>>,?YbA[S?>{e>5>e@tc¾٫Ҿ%Z>!\d=Ik=>3@=sӛ>[>Kq;<<>췾S'~>wTU ̽~>M\>MI!G>^>7f:K>({M>/eVi'ԾV:>\p >,і= ?'E?񍽿?>Mo۾ѷFZ?> $=f">("c|=<S>!'3f>SϿV>1žny%\=>1\]D=-(`ƒ> ,?2>྘Fc70l}1x}T"='_->AF=>K8Al>x\%T\I4> r?N@>r! ⾳t#n+@_>=>iM=Ծ=t>E8&ԙ> 쾆!=wo&1U [==j40>Qrݹ&qҾ p?o??T>>> r1ƾ">}\t7ѿ>>%3>S? &D &:?_]?]C?Ё't*?>8> >j3(h-U[=וՄ,T/3p_=݋@uuGb7H>HH8)": p_{>-M@=[mhW>"Y\H=\O4>;V>i6?1x=ﳷA@>ᾒZ.R>}=>ih_F=!q>a#Ph>s8=(>>pz)>5 x=|>[>In#dyB{<3"dJ| G믽uן- =,e4m=. v#=͖&̾=/A "5n>uu4׀k= 4竽A>\~s=64㾡*=W&+Yh>PLNr.J{*n?_䧓>jw? ?.S+>m>b>xW?H 1>>΍?Q`;>?O>v?;~?@3}@[q>`?s?+?'R?BtN=?CN>?E-4 S??L?>щ=?l>I?0]l+ ?.?20?vM6?7?Y?aw7XKzx?/?0?|H>|B>?haw^$>1><6?2LR \?x?3wK?vkPWv?W?Fl?Ы_>PgO['>e|X$ I=Y{վW>wqv;?E>2/?\U4@=}!?>?^mI^D1?7?I ?`->g=}0?>>?$9`@ >\~Ǿ*͟>/t>fǾ~d="> ?>Qʽ5>{<+;>G~AÐ=ո> lX>7 =&<?->+nPJN5Uz+Zj>U"yn=ʑSH >;Ι=^>dL{R.=_?Iۚ=O?1t7>ld?z܌=a?h|Ⱦ[>v?x6=?6Y:#>Q9U "ӡ?2>oX>\Y'H>̽ I<>E ʕ>21s#d|>H[>eھ'ϡ>9~ͦȣ>,TYھ2>聿N>L>݀ >?.@>ѿ}>B>re?=. =X:zȾ:`@?Xlƾ!x?4>S>yl#!<>kvѽ;Y`R J`J]QDuX???{"}9i#?`B??c,o /ԝoc5 tP4neϘ=?ɗ@:2AfIf`{-_>%@nB~ѿD|*9vU=^9CCƗ Ahj߾귙?{??'hKhuwtCMs7xDJL9F}L>A@տ=='j?Vm>6w>ޙZljn@?u?,R? XCB/ )<2\\,8&>{ z~4=S=> _ ɾȃ>}`i>Fv=B<ل?+>LM2=߽ྠ=^x-`컺X͸Z=t,.|=>/">yqf="!IRa>D?ԲA>@G ?k`>zENL"?{-A>?">ܺs>=?W5ޏ>Q0?c>)Il>;PBٽ`X`|=Kv$u ==Q? |N=!?:>}> ? >?d >=0,<e>XfM/ɬ/N߽?V=nxeI= W}=G}qW/?D9>2Z?>/=r>]#i>H?")>map mO?%,>Μ$?&M$HA>=]d>k Lwe? >?U;j>q=HM>FD> N>ǾrJ'$=h>k߿L09k߽˖l> ̾.tž1a|̠KAbNH?bZ>L<6g0ϰVy?,>p?wyymyy>p=Q~@?~?:? 0b=ci^X}3>5 >#?(?'??FUǟ>?hNQ>g>]p2/m?e`B*8;0Z?;r=3Ue?ZO ?Bl?;t?֕z?C>#>A>YK{>nƾpweFL>~=rG>)~Gώ~#vis&KOJw h)=ܵҾIf:\o1=]Lw뫿F%ͿE=n\տ6?'UcǾAP? K>j?>'=s t\ T= h0=R?>k>"}G,j?d>u/>.?r">te?9# >7>zH?{*>U?IՀ>d>AHҾ*>=>&OHuF>(<>X>D=~%` ?)O> ?߿{e4?&q?rֽպ,=vl>x rݵ? ƾ; =J3 ߿qB>`<2큿?h>w|>:8߿Cl?v>$ =`QAH?M>/M>Ȏ]H s"?AS>E>d<2L>@==4 .jO?B>`G>04Dr?>5D=>J ͯ5\>v>=>?o{^8>DI?>8)?8*>Y>jj`pO]>p> >v>L3> B7$tT?>V>ea?>w(?\>l>8pT.j>z="<)K62ns>λ=i=xXGA ?V?l>`VǾ~>>3>hF轎Lcx=5?؄>~i?Tm>Pԙ=O@C%>?'/>6>q! '1@??8?3x @%?;w)>>č\ϕQ))g?O>{>i{7=2<̚x6Ҿ DhwaA>u= <ޤfNp=:=N8P o5M>v=>XV>4F=V;>N?ߜ=jGM8L >UNQJFV>)|=b>>?K)>%u"S?;>z>guu膾?b6>R=helξ~ޭ7R>&$vԿ@V>,>a>VX%T gne>J(h#>>!<񪾎=Yl,6>i@B;?k>t3׽qC¾D?Sz=C>! оE[?Ⴟ>xU??۶?)?EƒV> [>I>?+1]M?J?C#?zz?Zbb=g=ܩi=0>`?1/==qh<>>j=P>Z>?k!> $?u)? ?Ui?]=>v#>V>?Q+>i>/>qY> `?f>H=r==C>r?$D>8?w??oQ7? |m k1<̽)=>)T<dн1!>R{>iF=5>:'>} >Yn[2?A8?5?t3QO?d?w;?c mn??t?Uj>&h@܇>Ab??-= =%5[>+?u;~T=3>@>,>s*};?,>|?9L?W=f"|$4?}J>VbX(sK>`;>RaZKo>g?Η>P 2<=3]$Hx3>RvN3pJ=<2|kԲ3D?q?vμ?([!?_?D?<%?D ?HO?Lw>VBض>joa#y<=ɬ<>k?!>Ȫp)E>ùh9>#j zD>Uqm=5>Ro{> Wj;$9>:Y}?zڈiQ>~C1ֹ">7P_͒)Vt$d6D4>NcQL~>,R>?=>Ȱ>7>?Kj8= :!0."=v^꾬7?ο<=`M{e='?=.0k@!??"S3?W@]?( ?.e?h@@mq*?a ?i4?l\!$v?T? Ϟ?;ġ`"$M?^F? ?= _g>qE> 2`m׾J>{ ?I2=pƟf=`ure=Tn(8~>\i=_ւQ~=0>|;>1sZ>?3!@-_u!<(N?N?!5?H#B0=?>X\=!`>@Zᕾc<*A> X>H V>+v.P=3꾛?Vf=6][1;خ*?(~>g->#?HW>Qx(%T?YzF>*? t>^>f?m=s>O=&t>t^?SaFZ>?V t?q?5?Կ>5?EZ>p8>$娜r{=L>׀` 3mn=q#>dҾ߷>9>X?;D`aDt ZMiM>L nz=K=x jpzD>.l|ξ(>>q>t½mtZ ?"??kNU/Hf?O?W?P E>B>\h?Z8eaֶ+>>?q"پD=BBPr=? U`s2==?±>>2- s޾ ?>@>?YR]싼)>:V>F?;T~^;I>x#>~?K/ڥ>־DJcp>f=#>$/>6.轈??zS?d?r>o?jzQH= ˋi;վ>x.A=+%sU> q]}3=Ilƾ%v߃> 2AF#q]=1U>Ͼ B>l⬾G^>&׾%¿=vl??]B?ic~7NȰ= >J&?e?Cn=a?-V<> W*>."`6;A> )N>R: >T r>H;.> _+R>^,=%?`DCU>*yO4>,d*у= N=d>qC>Wݩ=ie>Y%>M>[1=w=F0>j>8?>[3U>>Zq?3Z[cAb>J>6>?;9!<u>$>Hu>}X>N\վ辢>n/->e ȿu=d(8ӿl>rn:=kW >ǽIQ)#`>VK>Ӿ;H>=?&E:/ =e?+=?A>-?4$?scAS=*^??jJ?H!!=0=mvҝǽVz;==Mm¾B a~<ؾN!5<}:L@=L= $9gSPjz=)?43?~ ?Z%8/XsT ??'[?;ds#uaG?;?P{?-J>jP0Q>MJÙN'>VLsTY\pL0f@ ?nv?ȴi=^ 18;??P?R/<=~X>Ǘ=ư9!Q% t@u?S?"󽾅)=ƾF>J8ɽ3곾=Xi>g+>>M`ԽOμgo=Я—R㙳'=<4`Jg>h>3m?"=Zw>^  t=i쾜o>;r?R^FQ$^ T v?.?~Lb?VfPѸ3rd9G?+o[>ϒS>>\nk@?/L>fM=x6=>]=`Br>G?3Xn twv?fBtc>eE o=Md,E=u*R=“pa1=sDо-l>n x>LǏ$dV36YpW?p|>}(<׿L|g 0B?͒? >:f+$?'c>>th!dw ?3U=w!2T ~}? >q>Q|3ѷ{r?w =>}z=8B1f4D=m h=dg=G{fӿ8辛eEba=:= 蕯gq?~=G?R?$><Մ+>叴>C>4ա=7 >w><@B>J@%"B>@>>17I>Nn*A$,>N')Z>&}>8<>h<&^=n9>ag7Tr>3gR|t >=U/)*>0a>s>'>ːd:=`]Ж=0,>>5Jc:<̖F)>{w}7z|fՀ.N½3?#p>!Y=t?o2һF :DD?>] >)=A3>5?<??\?9?zD1>+ -?P> >5=r?E1w>i\=X`]ڽ 1=Wo5aB-QlзeR>">:=ȓ?~>?Ɋ>dr>;0@̽e=Ծ|)Q = m.q\!k5[;ܿ>łL>kLuſ) >WP+üyX<̧ t.hB:*?rY[=NJSAJoH bD='6ӄ]o~pv&?Wu>9>ӿ¿Xm?0o>"l>e ~} ҷ?NgA>l>r*| ??l>d>|+6>]B;ۋ'?޿w>Ux?e?>XjϽ>N!8MHAvl#6>=˹=A`DaȽŵ2.pvJs=>QaPOcAD?#1>>lsVP>Q>=m>MZB?#㽋@p[ľJ_$țugZ鳍ɋrRD==vL*cJPa8.mx@ ⏿>>P?>{>(@$OW.?G?>>qeoc-=[Ek3v>^'<PҞXdO=ÿ=.~cW6>>+>s\T./Ҿ:y>쒾G` YOE?7>>E5@*A>oi>2RIs?nM<=y(|1 <\w޽ =*=@> g˽O> > >;>S?I~k>4">ʟ=7<6>L =K^=icAzhSG>JCx/9_;,?v>}H, >p=ɽs>>?%?>Li>VνW 3a>0{Ӏ> ΅*^hZ?l"v>B=]Meþj ?,C>Kǽª犾?5)EA>S+ |?K< T>S7aVypOf?>4@>Yvy>:8v>5@ Kf>^ɟ>͊>pl> ?X}ò5>>5s>o>ɳl@ >[>i>[?8?7>8)>Ȭ>?@6?>>>]?3p?B2>??d?>=o:>;?!d?x?0"ɂ>~c???(>]]l=1m׾]=ܽL'YdA9X=Rao~>D=΢ =K^>W>I=ŏu|}=)0?zH3>p"#y>HFc?a8w=|!)D>]?Ƃ-[>ة=z=:Mn>> pqn>ui KY>?5GjdZ>ِ0캖x}>/mQνu>>? rf=Mg=-Qzhn-s=9>(O =ض>S3[w .==l+>; I{1?]??^e?C?2f?z-7p⻈???ZK}Vu!>lоkUb >c=K8 E>!ƿ1Qm?Vυ߇>axڿGg_?rֻ=>\7pKvu=r;úr!Wth>?e=/;Idc>>w>L@xeA >>Ґ?$\ib>t>Z>9??V?Zl=0>Eb>8>]>= =BS=ar>p)oj.= ==T>~D>}<(P=K>{W>A>>/?Z4}r57>(QR=<}rY.>ǽ+- =Ȭ>S?=Eg,h @Q@= =<- =>"M)y=d=$L06G4~F>Gn @=U={`>QS7ςowt=֪>`7j~Eg{,?GG>Ͼ; u>_R?~!>A>[%$>x-Z`89Ikcv>'n=O>ix?\63"6g>b =>s?@壽n@#>->H?n>?;> >K'0V64Hk޿˾o}FA3l³R 6-׭0o i}Lt1 9/y*w5ژ/xdVZ0*x a3R{[Xѿ,G"?z=1.=K=gO 9L\(A]ݾC6<>9LD>ck2@B# HkA>q>RDnD2EK#>w>?X!!A/:7=8rm>n>==?5I'=c> H H,>%?)k?7W?|,=>]˛uxy?C_={?m>? {?$F>w?UXE?/~<=>7~Nf+!3#j>=h>]y>v:?ÿٸ>^B[?˽?e? v=?L>s>¹?=f`?#`>.=ۃ'=lD><>(g>Ȅ@D=$8=ѿ>B>Xrs=y>yC>>vKR=:2=|>ZV>7m@>a>r>EA?.T=^[>D>8?=!?j=<?-& >C=l0`u?c?ip?cjRau0p>)>˧>?)$Y;O:??5?=e?>GjdXh=E?U?Ed?#;ɰk=y?bs?T?7aF́]>۾C뺙>kW-<7PDϖV=E=V&y̽e~=+ ᾔuTx< > '>|BzTn>9$)?#=mH?bd^>I>܇?=ZCx?>ة>T%bU*8e*cH"V>o >kje8>5U̱E,B \nmı%.ޘ;E@\<}ݿ7Xnԑ">M>o ?yξ8>Ch>SHΉ jq&п#Ffr3ܾk>\u<%ؕ??1?Q@aCϾИ-@?w?ֳN`Rƾ`?>>=fKЁ]yNY󾃔̟=@-;OxyPdSPf.p=>d _PT/?.= &?w>H4>hf8?8z<٧&پgC?.NwwSGz=B)>WNu8&>,+з<'=2=W?#>j?>ʁ>6^/b=T>R#Z=M?c>񵦿 ͽ?r~}T>`&̿%',2'=d>=`>y* >PX>!.ǽ>?`[ }> =HϿ2vG=}/>;`qq_pYZ>zL轄t=u?uϯ=XUQr>k_No Ah=N2ZqW6:ĂdE1>t򿿛ͿV~X>[)M!:qZ_;>xeDHG1=KFx#> i>xak 1QBk'>=7p뚿A>|z>{M+=:?,x >>l=VG?"a=e=?QW>>`]9+>ɬy;ecﳅ\f?Cl>:X=d/}?#*w^SL(<׾#?@Bn-?/dv]}>I?K}v>ln)v);>s;<;?;>U?>?>e?S>/>P?y8=ם?*`p>>){1&W>4 ^5yW=yB$n>ڽ[ٽL .EJj߾v.;;=?@-{Q>,tu??&f?؄?^|K>`/s?@>>`?2zP>~>oe;g tC6t x\i>X4exo?8nv*>f'%]=?"p> >ָ=^W?c=Y\>>=W<@@@>„8>yt> =jQ?a_>?~1>RE>A>Q'=J>9@+XیKp=O=s>=<8LL@BŠ>܏6 ~' fu);?+=A=Q~\տθ!?q-E>>2r,p$?U|>~s>[>j=t?Ȼÿŋ>Z?>I =? A>j><_dJb?^=!>>[= żs]\;kV=-E$=ރ>+>9>M?];\>5ɣ݌*<;3?"E>pt>rw=.>[g?*>ی]>IY꽺uG@g>t>V>@?*?Ь2> ;>5H>?6^?\Ŀ>.c>4%>)J>x)@4>h>6^F>>ǥ?('>"P/>]f>89G>߷ ?:G>?F|9?<?X?w>{????,Ǫ=>?I?zǽ> g?v?k??c>>%>~>!2?J=ƻV?? Qr?U?>Z?b?Yx??zy= ?#p??b'[?=> -?-4?%?s? *\t>=?Nt:?n?=t>7z=έ >)|?^=L>?>s>?Wmw>8?|?Κ?El/=8>3 ?/'?(6?zx=?=>>/?? :T?`?s$\=ç?э? ?g>1>3?je?cIk??m3ty=>=@->>a3)==s?b_? ?\%l>x "O<¹q a>;)?&<)=<<@>?#=0=vd9>m\1?T*=>4>U|>? }do>CH,/O>j?Ŀpz>58!>=?Ӑ~2>|c>?x>ipSpξ?¿TP> 徳 u׏ -;1,>$_b߼h>bw>]V> )=y>S>]?Ce?) >~,?|?HAْ>旾˸-E.im)Ǭ?$O8 $c?W?d.#? %Zվ ?4?Cݺ?KiȾG?o?{[?XABB4 ?v?~?բq|>YJoy b >әQP=M^>H5Y>T>iM~ n>P?~x)(>>?l>b?"&Z ==}s=4H>d5d>qھ&$f>vtnDE!>V?`TiC(zS>[V>_1?:l,>'/2]h=,ppG>?ND"ֿd>YK=?K>j~t:>"(`h嘖= ?^>י?E={Wſ8>!?;:>Т? ivb M>^?Mw?^sVXb_њ>=>>?YsTas$>}=SL>ʰ?#&? u=>)=5-D0T?ub=@}Ծ@ܽl>=$qp=v>w?‹tuMk,GX#>6rkduCr> O>>?//U?sك{>%>*(<> ?Uzq">#> >|?"?k͸>'=MK>&x? ڲ? }p*>(SpH>?}1?e=Q>qJ>I?B~>u?b>?,?0C= ɿP7"kK/`;HBܿ Љ);޾ S!DǾS;7>(ۭ>T*=X >oj@.a8!$̊Ea'egƹeY_:Q Ɋo۾bG\ܾ-< `=a.M᥇>k>-I _XJ[]FpAZz==30=,Qr"Θ??P?)<Ø W~,?UB? t?A\s>_\A>?#v?3. ^=^?E?k?f>K*9ǽ=krFl>>5>? =տ Ds>1I=>?1mL=g?I{>>?!=VuX?5O>D >?/¿=2?<=y>c>w`3=¬2>ȗ>?G=ڭ>&>7?Ơ =c>\6>g?wc=>sa>Y!?Dqe)L@;]??v?Ek??Vѷ> ;?L??V??P쉠=Qn?E >>5?A=?`>->\`˩=T>>G>`>=| l=B~>u79>?>e,?g=K?P+>;>Fa ta=M>>>^H;H%=G>?U>|[Y=E=>4p=o^bAO3=¨?k? 9>{gM<'Tmv;i|<Ԫ=C1Ҽ%~<ҽ(/0<`= t>/ bcarA=_~=*=O>=z>ʼ=>> ! =n"Vݐ>>pS`>N &>y:>v=@~=  hiT?==-@!Ŭ(_>gw +4>=>bKi=ē? ?>s?-s>`˾/>2>O>/==F?[S5a<,6ȴ@Jo?_?b8> ??c{)?5'-@Z7=X!??{?kd(0Sv>.???dAiB^>?q-4????&-2{8Z8>K,7=łs= )֨3>@3>I(/0?!s>ɐm?1ӏrG>۱>Bd>wΖQK>71M^I,>a)&a4> =i??>#SD5> >s6>#?/*?lw,>K `\>҅?yx>bU)c>>K>3F>N>'}?)l?Z>PJ0=Ls=\? gZ>e7o=>z>;$ ?)1>"=#??q?:A1p6U@k?~o?4Q/=+BG(p??qB?v:ty>s![ ?t??w?T{ .> A?? > >=??'6Y>:C#:;w%?Q@?L?VvGT[G{>rkf`ˁ=Ud>=gbCg=>Mzl=ӿ, > >n-6=D>"b̿W=3?_>6>8.S=8#6?{>RY?>J>f&L{>Qi˼ 6>Ǯ>*P"X=$?}?> ?7-=q>so=}RDg$Ⱦ?d>> ?@H? 1>*= [|_= =@B:60+K6?>b꾲D.|3=us>N37=#%Mb>ϽzJq!>B#(BȾ `kw-h<_>ڗ1O/jA<>{!}<ՆD/cvB=﷼iVaA|)>,,j.mjpq>cwR]IJ3uw8>o+\F,>yb>Gv"28c>>?S?>ܘ_>>? ?>pW;f>J&)? =?7C>=E?? m>jE?hV>>?++>@?b>B>I{t> aA=ȿ{;?;@>>p~?!C>?#>W=iZ?7|W>>s45]=~4ľh07Y=2>&^} SvQS?CT?=&=뿅 b|>Mz=n{L HH^>fB| r C˾j T> %5fA%D?v߃Ge>fP%9<?S>418Ad~'yd~&=Dl9{?8lDх= 1Gɛ>6C=0疿\6>_5Ȕ>ɛ׾ Q?B|6=սQ)=>,V>7?x:>x_G +?5(S>?`5Aپ) > 0֕>MUl2ջ?ID2==WhF[d:4?N8{=m+޾+?Y׈.=wc??C >k>Խ+d>?e׈+W=֓:?$ ?ć]>`ضKDC"?A>PS5o\Kf??>=:%$dZ> 26>Y;辡CVm@cAY\?Hs????U 5@A%_>?>H?7?]}e=.>T_>- >}x?y>(\h>TA>)=>ت?@1=>Ǧ7>A? Y?^`>%>O/>E??mc=;>>ˢ?0?(|=q>!=柌>W?bN [>?.@?$9?qf?t >6#? C>0?A?a<`=AF>t>?9P?< =>>? ?>:B좽>1`?xW>2<>>s=>n?>+>OJV<Iԕ>a?ƒ+=L>^S>F?-8?> `=1>Q>D?&7?Zje> K(>D?UC<=>:=YM>B?IJ)>vO=m>4V??>b`,a&>`>B7?]?sVL>*<=C>?>>e-#>>X?îj>*3?XI>X<ݳ9=j>!?If*>G˾]>f?1@r.>@ѽu &=*I=|_> =T>HE>>&>pL?#͏ _=>Lb>6E>lӾ W>;?l!t>*=r>Е>μ?3ſy) J _??E?ĿY==B>,8>۩}>U>ۃ?0>Ga.f=U1>+ewK=<=9h>pQܿ̎>0=W+=>OTR>"R> >`>4 d==z=F5>w$k>t=\>>: F ½>vѿ~Z=o>,O>Tի|=*|= 5>H,>??=0>>>7=>]>>zE=4>;~ > >Կ5T>??&W???u9Y= >UgܽN>ZE3A?Y?@ӣ>*>>9>?91>KmD>>Z&>>=p=Xt> c>I>">hQ>#>ė'|hHw=]>>>l ?UXbC>; m6 >g݇=d3<>@'R]F=? >/^>z>>3<>,?>Hk>`<µ>]nH?U}c> >=>JU8>T >V\Z#>'=$:>և?RW=%п:ExRw>e伭:8>?ީ#Dh=C>RT0=ȠM=Y>n\ ??ig4=To1J>p?Iеg>I >i¾)o"=uH">UG>ԝ?$ ?>=ɒ+V>>P{=>>e?L ?~U.> v>H⠾zp=5a `a#Wޑɾ9V<>A>`ɗ=r>F7>O?1H'a oOs~(ǻVX_s齢A??@Օ?Z"x!g*N/? f?3?Q>(>o/|Am>S >?QQ/pKC?>tdrEqνxeؾ=?5=Shk@ee>e=n>=g?  D>(_=پ)>Y?Ƃ#=Vi=r}5;?7?ؑ=q>$G>'2 k> S>??%hw-S?:Z?e\1?x$<rY[4?:qi?cJ?忂GT>~7+ʗ>xSn2>9>Z>sg?({Ƌ=>!K??'Yyk7~7=>Sf>d>sieц>(??@PY=if"= T7>#==>j9>? l% g=󪽽0Ӽ ?> #=gTm>>D>HEw:<;@p>a6h=m"??3p?3&=m>b> >-L*=>ne>{>љ`>G>+?g?mH?\=?ipa?)5>ä/C=v|*=*K?e=˥?i?Y>qI=M>Z<=>ZG6e=3^@-*3@7=MhD?IVeޭ=ёASJυAT< >&{п\^>bt\'a_=?5*=?Z6>X?>^3b>HW݇ ,P ? %9>B9??u>ڊ>kA>#=)?uq;?>(GZ>^p?Y ?C>`cEk>DRK9K>Tď&쾄>c;0'>Lug>%=eX>5jr]?En>E?}s>TrTI>j#>Ob.S?7> o>OtGB&7P=:??D̼? ypI ?e7?">m 3 >N>"=?'$?7ͫ>P@.8k@ ݿF慺]`\;˜d׿GA:3~= vG-Eo? (>??H'? 9?>N?L>聀>RX?{ \>?\?:'>Mp̽Ĺ9=_ !!s<|2eQx=Rn?[׽8e?zס>E7<] cIe?\>=p ټ?"B=f ?>>V>N ?~??>{ t?P?>)? xu' wr鋵{Wg= LM2v 3Ls*ͳd=.T꯾?M}>O( i@NH?՝ >?Id>0P. 2=D> >N`0)龟?Nb>u=8{=m>9=e3+P LN>迡 վb<<>H,SC$<*0{񍾵C4>8?y~> >L=a?/;%7) :>H6"#p>>M4?"?SK@?4Rp)^}>A\Z3یb$Fc4d<>]>J"'I UH0>9>K#aZ?CW'W>t=y(?,A_B>pT<)kxuO?K>j>m&tNQ<645>RMw-C[ .=-#տt Y?Oc>P]Ⱦ;?g1>ƾ%5TIC=> >_%>-+>U<E>0>m==?5=7-= GdAsM?).;Xh34/?L0y=#2ZxMT>n75ƾǾK♷AR#>i[Ϳ*]0N >,+tX>A~x>34ҾA=C̾>(.j>y^< iUE u>>==2Ue@yI>>:ѝc?1*ԼY羧Ha>u1J\^pԦ㟾=;.>v*ÿ`Rfɟ>cuu>vl?"=\pMzݿ3?(>=QM+? Y>"BJL?y?<=?:Jv2ſs?}_x&8.>#.WT5>##6?z#><>¾>.Q?c?`|=P> >b?o?*=>>$?#S?|һ=~A>ʖO>p?#J?y,=o? >M?Ks?Oa>:>ɕ>C??=l >> [>?##%?_|t>>>?h?Z}Vq=i==>4?3=]}>M>G?C?d=0=֌i=>? k=>AO> >z?n>w>>{?9?m>%g>\>y?b?$=t>=V>>ڋ?z^ w=C5>~>Jf??.=<\>) >4>&?/=>,!>a_>ӻ?>#=;"H>X?tڐ> J>N>IP>Ⴊ?Opʫ>m傽U?%>Lb=\s>\?"̠>(:dQ="(?yJY>n>ӑ>p?>?B>CD>4>?,n?KL}>VV>$>'W?+Ɋ=4Nɽ*-0>l>n>#}>>?4\yd?4=j? M?Y?c?*;X>*J>O+>¤???^|>վ3 gӖ>p?7HЖ> {>F>RG?#d>__9>>43/Q&>@۲>:&=N!>ph=?O`_A>Ɇ>YFre=4=!>7z> K=/J?N/?\?f7~t=ɕ> >? ZSu0Z?}l]=j/=P>>c8_t> *>??eۻY-)=7.?kXm??Tۃ8>=l>z>YOWk]>|>$>??>/;L>|=>c:>?$#@=6=> }Kz<>-<0>>GD> c?t??-==>G>NF>ˎ3>ѽi>/>ў?NmW$=d< |= >=>Ɠ-hSǾ;>>O?Y}?Vn>B"O\37kI{1=+ @J=BsDjS`_0??>һE=}\>7 BEh??9 ?p D@[c?E13?f?w4Wd>zQ>P?A心E>t>*>6?LUuN ?>=>b9`?P {:L=PD>vy>?5.AE*>??qG"Kf>Q<8>G?$?~p`>#f'\=j?"{`=Uɾn=$?]hy>V ~|(>uf4/D?6k?VW?b?C|j=QǤ? m?ս@_=>ݱͺ sT?}=>ͧ> nL>>w+> NsF(>U;??`>1?%?,hN>r>? p$${վȂs6$sJg?H>/I{ϒ >>q>@ 5>$m/uL> Yn;)a"ᗾ"GS*#>rü NWSkF.=r e[->=$>{?H½=>G?ĥuq=<à?a>F>\4@n>XH??%tO?)A{h>:">x?Z?&;=tNQ>>⊤?!Su>f=s>&>>?>xJ>8,X+=>>e>PM5=r;?> t=>?X>%W>ꀮ?=?__>7>wߓ=F>a>z[>m=s佾M=C=2>C>>R=m=>|MؽI>k?)g>C?\ ? >Kwɀ_=E=d>->ֲl@Um=c4<:=#==!r$>cz?+?H)?Ht?={8P?SUX><>C`o=4&xL3ƾj[d=v=H p4]x}B=^=)=ŋ=rSsCx=t( 5]qBWnT=ҒŽ/@2]}>N꾁kURu޿r^>I4̮꾕4. {>'BA>8&!H>l"??g*Z?C|0ԝ> ?>?|>?dC1=ܬ?a? ܃> >> f?3"}>L>J?>y>u>?<}>Ain>QB?#? >Ⱦ#d>%>,>>f: >?>Z> _~I4>3<ܢ>i~>:*<[ʗ>:zC=վ>K?t>>O;>cO@8G?y_>/MͳKso~E>k˽4{ e+m=?l'>=l=ABmbKҾL< О}*>w?@(=v?G>>yl>[$ ?|o>;m-{K!>I #g=n?X??bvó =?{?js?-$?cZ>L׌>KH= ?E?z>n0co,8?{3!=.(h1<@)|vj=b/'DNY={ ;H5cNQ+=C{p0!}=cI_==ϾӿnF ?Œ}yG>J!dz ѫ[[?/>=5=d>KϾP|ȾQ=.?%F=޾ ?7> >jm&{f9=T9޾ $wzP GR=D̽5<վH`t|>, Ë8HY?Tx6><$>~˾ȿ!>X U*>u~$>fRLfґOH>/񾚃՟^?OBx>x=x8?(u> pQi_. %z>q㾗:23"*?Y? c><<@J>j ?e,<쉾\p5+>飾gLƪ*UaZ<=@twĬ4?KTq=;l=*Ϸ\ >5\?k/>!>?"W='>{  bR? X?>`kN'ٿI̸=T>5Wۿ^½/!>U?7?;H?+?pV>iRuGX %9=>{̾i-SD=/YQ@9}i*1=sJE=>ھn;L<̒>Ͽ4[zJn>+T󿍃Ͽo҅?]vW!>[~?~Lb? E(> ?> U,:8K?oK>eE:*=yO{0;?~ >8?=\S>t2>_W.? o>v~>v=--RX>@_=8I%n-H?#'>&S=il?-`>8Bm( >? >$==bgrSC~>"=‹*?l-{@x=nۿR߿C[a1?f8 -0mK%?F=o?^ $PRҿD >O=.^ #xl>2>Ц;਽=wp">߾nBx,?b(-=X-j߿b?6 >. V(:?qC$g=~]ݿ,y `?ˑ_>+LO^?kDp>HRTC6?К>&EW޿,R_?><,yTo?==վ0>?>)*zȾy S-k.=5?|>">[B=FZ>*?&| N>G>:6>9?+`?-ZK>d>8>/?F?)>0">`>^?)?P>/J?ׄŝ=>@'d#=,?=/U>s?.9??,=?y?n>Z?? ?g\?[A4> >bW>i? ?\ >OV>y>?"?*p>'>v>? ?4%ߠ>>d|>?D{?e͑`>A>"~=;>?o3=퓁=X=[ >?CG=vF6M?jqӝ>F`=>h$M=[>?H$?J">3>0y*X=+e>۾ =|>\@)c>C?F?]"2? >>?E? J0?6t-s>&>{>?ɰq_P>>٢b?m?]HV o>?/>X>ՙ>.+H >Vn>p;>&>?1?^NϚ>P9]y=_l >7+>N>%>w?ap='\:q>P/0)=Gz>D?[U>d$k=)>W?uf>6ƾSc-M>>?c>W@%}>F L=8?}|Z=G5Ɔ>P?[> 攊<T>V ?b@>jV>"H>p>l? # =R\Nm5a =^~ c1!mn;8N=2?otb$>BO">@>W?*\?jnL>?>Q>?1s ^h?? ?];*?o48{ ξ?;?A>`?P/ HM/>?II?^a#? ?A~x?FkO~V??E?D*V?2lzc> L!8> a䘁>>瓚>3T~Ĝ?W?=P?:UT>j?4?h?2c>;;fSʽKj>ƗNz=~> }>e'?nq=ƾ;=]Ĥ=,z>>>`>lh>j'>DtgƏ=M-E0@}=X#B`d8=>li>E>$rST>W=->.<>W2?>f8ɾVnÏ>y?U2=J?!>a[>F?$@Go=>}_>>?{!=W?J?>>6&?w=??>>&>7OB>>GV?Cu?W}R?2G^>=/b*,\_=õiy𿾢o`>D H܏Hdn~j$=%sUs>^8۾\o`῿zs>T6n=SZo>k=遽μA>.>!Tb=`4E%BYh=) >WM.wpA\c=b=\ݾQ w&>ܽ<67S3=*c>I>ѵ>*J";^~q(|aE=uSߺ˿?ҿ>}F> s>"E$}>{q7>yUG?vpm>eؽsSl>íq?3v>g>> >y=->t!?F0?1? 1w?F|t>\^k=]?w{>exZ>@.<4Y5"Ck&=}H1A)0m/S߱š8p텼¿ BL˾rni޾h+>a>`5?|e>]=[0jk>?g9c><΍>NuE=:&?EV?@?^ >Ó?*Z?[?K۾=??[k? S>.?:>>A)EVPA}>=d>S??za>3ƾƶ=y>;; :=\1??0i>U?zeZ>q} L=m?7&خ>s??k>ʗ>%? >a-????zRkvj=P%c%37o9 >R?]* x_> wj> JɿI?y (>o\?@!>>F~Ao?]V\>0=Q7?)=ƚNڐ@wċ?Zb>>ǿ4a$=>3ij?F%S>?<'l6`T = è>ؕ Ar罒Pc>6I?O">E>ྶ`?3">Gi>_ ݘ|A=2]dDNE1bH=aZ>\$¿EV>[.j@y5¿ >JX漆e7=G=YC=W뾈cR)c=վ=0ʿt?ܵ>C?]?W?:n?A`8>!?3?!?R?}U]>eZPJ򦽬<>Ϳ)(\W?E>O.o^5Vm?N~1>%ȿc$y ?In>nB~$ٿ?S?? A=^ѿ;qjH<9>s'ؾ?EJ5/>:h7Ŀw*?fN7\>>㬾_ݾL>@?6>gR=w ݾ?Q@.Q>4b,9&?&=¤՝`@.?h>sdd~S?I>r"V/I?O?_=O> 2~h/??= 'YKdI?Ɨ*,>< o1<\?BB>ov`aIRIE?zz>/>Ƚ>q6??Z>]>>G>?"~?|e>@=1=>0] [>B>>j?`>FK#>l7>H>ԇU  \=E=v>>ĭ6?F 5>*e=h>EH>> 6T>eE>>*(?>6$!>/T>E??N0"T>4>>>?>CZ>o,>j ?z>(>Na>??\C?p: >:ʼ>`Z>U?l>  ><<\>\>>Vi?i?>9o>Ӯ>>?:?K>뫾M;󽆌>>AF>nr?yή=n=C =,?Uר=!DS2=7?D~5=O=|3=?mD̚>5=)o=ag%-??#͊?rƿh8 D?)?6??VY u>$f=>?T{>@$x=,?t?`>7FE:j=F??i>T>&ʊRc=?`[>f@d>Bw> 8?U6]>=}>>?b_N>s?ǀx.Sͼ>? ?1KR~䨾*?W'?r\?㿗gn%>?*? sk???a?zP/ 8ɺb>'>U>h<^>>cx>F? _=̽6(b>Ds?(Z=P<@)>ň>a>׿z=1?%M?FE?4?\>=poi>08b(F:G*;=YB>>yp~ m=>?* >4} m=>5>>z>$%>[V^‹t¿#>NFh(> a\A==y>V=>ȱ?1} ><-(o.O>@?(uI>뾵HkcN=&ƹ@ =@A=KB>uRD=$RHc>"|9 ~a=6vFk8N)=:K=@bM_X=|&ͽi>h0>>d@6Z>N?|B=>4=>6U??={)>>`>w?C=l?Z>e>↿o.>Z=ni𿩓1=Pμ\=f`k{ }AyO=m=ʉ>d63=>y=e>ٙ>ө>>ck#IOd>A-嵷8"'H>J/t~ɭ-Q.AQm>=7kNؿ~M>' &پԿ Y >LRam04)4[d>A+vq˒ )Ff'=τ̚7Y)?Iz >D?)L>j>i;?>E&RGv q~[e8=d&Q=?yp>Ӿ+-0=8Ξ/m3<˖l>Z׾ 5zmd=?Ki>i >y?vy>,e23"7>@=?u?T? 3s>B?8?C>H>6i??p> LV[>=J8> ?>K> >կr> t=l?g>>_u?:=n>;T~R؄;8>|gP>%?G_N>"h>%>£>ij1=2r >Lp `g6/?~qm>aY1@MwO?r~s >b{ۭ~?X=?yG>N>{2>J;>jA=OGO?>Eo"?|q>>%]-yA=sb=XS߿7w=Ss;#^?n>x >|xBkn>/>zh#ì.T>H?=P6=!`=k@țy4_>׈+" i܃A=m)_5zA}=M"m?aAY>S:?_=>="qz?@9>aC?/l7>>.= ٿ݋~Ni>)؄<(=~$̿LR>( 8vK=I\O0m?R6hZ>-& ?}>a<ǧʾ%\t?">=Jc0IԢUw%>d;ͤ'iQ?63>}8B%=( >ɾCäH"=-3E>ʃ,iPh2Q> +>vy_W8?:?O7-B >[O#>j$>|tPu64?xy(T7>-ӿ_οA?"b>Pjl տP0?H >mbvH?[}>G*xKjL?B>GpU%U;=>>b0?8[>%f~t΁? 9U>0佽Q/=ί?缩>\3>È>? ? >9Ȇ>*>#W>> U>>B>C?;ҷ?s>b?*:~?,?K?_ >R?PS*?A?q?-#=`>>@c>D?@s\>>s>p?^p?A}ǽ>|B>}<w>z>۷ϫ"> >q~x?uh?/I==5">>O&/C=*>>~?L?~®\>[>08=V>.x&RV*?`9&?}?w޽w'Ǽ}?@N?`7??uO֌>㓽a=)>A?h5>X>Z!m3>cY6?3><:>ӄ>G4; >U&>ʼn? n\>v??*)?J?S> (=2B>о?M<=پ?(V>>qv׿gt=3SE?S?r]?ք w<?$V`?F*?eFԿC>!>` _>>r?Yd =\b?JTL=C~>l0>`KaV Cl=/{"lReN>|\A= 1/=Q>?@WK=\>E@F>2kd=Ťjf/.> {|ؙ>;n >Q&,t>U> >>ײF.>h4L&=hi@>`׿G0>C @ɗ+=?W_',>LD"|ڲ>7͊Eg4>l=u+PH>x!)=E>j>=Ѽ13>z9>vY>,? mb=µF|(Q;>EG46= =!yAQu`= <#>F=j? ء=>ynY>>X5k=>s&?,>@?0=>T?$w>4>b?mT p>$??#D>>p? zN>1e ?'^t?GE>1V4> 9>>>T}>g>?ؾ2G<;~>vF?9I?7?,eA8?=dQ}nӄ;ޖ6ƨ= ]~gTڿۡ,œ=}ͩ"=1?k]?GBhP>d X`?Vֈ>h>UJ&g/oE?il>-R*cI<1!!_=>`n οO!z==UIs'M+/>gw<>4Uc83a(>>B"K x>U뽆=>9Ĵ:%pu>d^ս>T7>@ ]\6=NF/h8>3TW>}=~>=j?!Y>mH>LͼK>wῗvXؾ,K+*nmr>$>5|le࿷ӀJ=>*/@_?[?>nRv#> jr>f>ᱽBCݾpK<>8?i> >M>d=ADz!')&Ffqz=w¿ǤcF?i>e]+龲 ;?glj[>Q3VھT_[>?m*>Kn䨾ג?k>fؾq=?k>x w`jw<9R> C=ı> ?lw>Iֽ-0=vG>:k>v#=Y>Ǵ?2؀o>Q'g2: @`~!>3_mn=?`_>NJ>v><"='L X6-=L?X>#>A6) ) y?XF>!>6> i>Q?b>ȽH矿M`?=>g`=9Ϛ86]>?j>vY>8~6cE>g? >Q,>ȷ=B2~?+?lZ??5vM?F?=?j? s 2N>sMnZ eyھ?F> -=<`/>m>ٺe=m׿a=(->ы ocNfE>2Ի>@@>|\p?K.>?f> 5 >#B$ɾ>#>G彝`U|}/=eaE?&y̾a%>Sb+M>1>blb> &?6`>0_lO{>j;̾՞;?o>Jp >zW8*?6>Xtɽ4#T }?/>oh>?֒>]5B$U .?#>m$ 2?C=>.F$;?*V>n#DL?y>=Ծpv?O3>gXN 5?Io>/>hMY?mBt>,Z>!>ɲ? M?$m>u">e>o?߽?0(>[ >;??O?>?x=>?<>0|B貧lW>3?>S>N>&c??|e'>U>B>>+?}|;>3vռ̞tG>J?- >1>"z >w?z? 3r=g)(= >?D| >)J=7>!>ـ?܀>?*?Iw!???p?"[ܱ`=x>>k>ؙ>6=ŋ>eb>5>><>+? O?V>?vO>H><7b>f4>F' C>">4?avx=43<{>>"=">$-?5Y?_4?0M,#=C[/f>:M?g6 |>̾bJ>hD?O"&J>)>@0>??Q* c=c>>u?k>5>xL>!>??~$=s>^x?}ÿɲh>u>Dz>?[0>K >j< >?޸Z=>y~=@>?\F.=+@>?^;&>W t>>/?=t?LE>ϽDzF= M>ΰٿG=IZ>5P??2q>*|@=˨?=iI>Z>F> տ>?\?A}ٸ=P>`0Ez>#?޾,>JV>&>d *>v^>> ??M@< $=g?˽_:X>kw?_?D>Ji{=3?"}0=*>dھ=!>4>P ?t!?/Ek>k>q3=L=>H=>Op-t>%h>L>:=}- V>eс@`j=>E0f>+A>vdJb=x>' H>>Ĩ>>? ?,(=5~>;"n<<>=B>i^'p>O>nH={?A \> >>+>_?獂$=M>ڥ=#(=?\O>>.j>Y>xu?6 ^>A+^?X?t>~?> r>>j>)Y?R>K=>lH>>Q]>]K>Cf>p^_>?= ?Ln>(.=MU> iӽ A(UF?Q?*>xP>ǪہC}??N??&;D>>,ƂN DND?YM?\?ؕ?J>GH> !?>6?8V?x#>-&1=e>=#;7K>CJ>;wN=E>^g>qq\B}=+0?Y>g>ܽe>4'& N>@4IϿ4=n= )_nH>>nx<<%>= ->|>b D=م>·=>^FZ|>"d=O&=z𙾪i?n>WfA>O=N`> B>={mD5>20> P/X}=g>=[L>wjr *]=>&la>%?Ni>/֕>w> ?ķt>za>h[ Um6%>1DF>kuR{?9>(9G>%2{?]>NVG?z> gI?T>E->ֽ=ui+ֶ=-s>< x>AN;<7a?i?>f B>G??O6?%ZK,|?d?p?DYk/C>u>̪=M>f%h>!3G!ASg>&J>.9>`ɟ򔼿&/E?-#?7'?"=Y??j>>b ">)2>Y{F?q*> >X޾Ey="@>3>AxIu.>e= M>q=;SҾ(N?>: > T#+ ͣ]@߿>C>RQҾi?8=Ӿ!5贿G6?b|>BK>'>n>PY?6>%->M =?dyd>ы $F>r?'>VO>$>ij?$E?}^>M>->'?/?yS>/N=R>>>L+?-b>I>a>O?`?xƋ>h>'>l>?>C>&>DJ>ϩ~? ^= i=>g?`kD|=ʕ>K>b?>ڸ?r7Q>C>v??o=x U>,c9=P>R>ɶ (>޹ =_x>~>a=eb?Ŭ? #?q*?.'> SU&=5a?+/={>yF>>w>Yn߽82>-Ɔ>U?=K>f >b?L>X $h=s>>M !F>f];m3> >A?¿F>W>ݾ+b>J; oH>%>Jy5>t\?6?7T>u;VDR;`h?/¿^>/b?x>[P>>s>w?U?r2>7;?U`>>n>^>P>>U`>T\>>EZ:?h *>W>? >6?q>6>>=з?^>>Q>>b>*?rF| s>r<>? #y>*Ծ>Ac?ϫ? >~*>S.>\Uɾv+NrusA^>>7>O>{=߯.w><bH>, H>?J>:2>>BIם>>7=>'>T>p=ɛ4=wX>ޔJ>d4>= T>\վ<%>o+Ta_? t>8 >D\> =? >y˫>~<>y|=t?_>s3]*.?tr>!dc]Dݿ' V>-x>>/JVVp'->e[>*A9N>>P= z>/=j>"z<T?'l>A!h> :2>$Q3?c=Io ݿ=@-(1{>j>s(lf>?m;>3|?:>J=Q>>+2H=uR]BS>l=O?d|B>>!O?f>'X?U>v>YACB??}Հ?J>8?^>77긾p?t7+>,>Nbn6K?>'?>1<4?>%c>7"?|W>Ho> \;}徶&?`>5=๾?&=S0,4 ,?횿2>uc$Wke?Ƙu>EAۿ'?O>ɽi [F?>K>5w:>g??V=Fa=u)>1?䂿>=>">?ڀ`>M~,$,>g?3a>7q=>N>?}A>:,<=p>?>W=@>=13> `?wU>$ >d x>1??O >FX>-k>w>y??>aё> lr>n|>l?J#;> CMj>?p4>S>S>A? |?0>PI=G>-C> 5?9 =FJ>D?bʸ>Vz -?B;(㾤FYY?s9>7(h˾T>͉4(>k>=M_~߽ > $>b<^ݾ[qdA> @.>7>D|>;V>"> >kEgU9>$fKdbÇ>>C>9.?I,"|=>'xA2/=P㽆e?*C l>]=?/ >+=|fўI?$ > y}Houin>ü !/>1A >4> ? Ŀ>ы/?>?<[B?­>m?(~>d;K]>{><8??][>!?=>!>?4>?O>>u>F)?CN>h(?^=>>f?ms>>?jE>A>Z?>TG?Tf >mU>?VH>@'yb'?r ʸ>(IE2mο S ?hz>j:=߾]I?||X>;=7쾆?>[u>i]? =e־G?Ё=!>*y5>>T>?W~@>Mm/_cQ?KK'>dJ=ֆUy?+>v;4ʾXu?'>KDm,F?B+=cR'Kǿ+ m7?g =횾&r ?{ )V>f=㾑־=?v E>8=Ĭᾭ?,+=.&Ep0:C?> |<23K?|>|"|?AG>>Dp;BF>]uI?/>!)?,^>>z4= ?>Q/ ?Ii<>$>LF? Ѕ>-k#=uؾm?u|>#?.=?y} y->2N$p?>3=K52{?Ѧޭ=Y &u[;pC?~,>.>?}po?u&> a=۔Q?ܛA>z=rK?yB>7.͂a?CXO>BD[9@@H^M>pl>=Z`b3?+ܜ>a>b ȾeD?6I>*>=z* ? ÿ>%j7"2?;~>"d彴̣? =Pο!Ϳ^#T?==پ/ESBŠ?a3>Qy>TR󀾬e?}>)=U尾6/ߵ?Ca>%N]Kre?MMU=̾ ,92#?/N{>ki>;la/?`| =5[ ľA?V =Ƈ2 #?06=`݋O:K?;5e=p&F4D?ؐ>G?6>a>?K>1>ȟb:ž /#?=$>݉ξYmL?ɭxF=&9Vۿdm?D>O3> Ǿ5TY?%> ]>!r q@?|X=Vy> )8?>o*>F=I?"(>"z?ρ>ܱqSnY?J=ǰ(=_$?/[>4=6mzK?C=>̫uHV?C>"Šr{-_?>6s;^ݾ?狂N]>`= ̼A[?~6>91mIcaret-5.6.4~dfsg.1.orig/run_qmake_dos.bat0000755000175000017500000000256611572067322020112 0ustar michaelmichaelcd caret %QTDIR%\qmake\qmake "CONFIG += release" "CONFIG -= debug" REM %QTDIR%\qmake\qmake -makefile -t app cd .. cd caret_brain_set %QTDIR%\qmake\qmake "CONFIG += release" "CONFIG -= debug" REM %QTDIR%\qmake\qmake -makefile -t lib cd .. cd caret_common %QTDIR%\qmake\qmake "CONFIG += release" "CONFIG -= debug" REM %QTDIR%\qmake\qmake -makefile -t lib cd .. cd caret_command_operations %QTDIR%\qmake\qmake "CONFIG += release" "CONFIG -= debug" REM %QTDIR%\qmake\qmake -makefile -t lib cd .. cd caret_statistics %QTDIR%\qmake\qmake "CONFIG += release" "CONFIG -= debug" REM %QTDIR%\qmake\qmake -makefile -t lib cd .. cd caret_vtk4_classes %QTDIR%\qmake\qmake "CONFIG += release" "CONFIG -= debug" REM %QTDIR%\qmake\qmake -makefile -t lib cd .. cd caret_uniformize %QTDIR%\qmake\qmake "CONFIG += release" "CONFIG -= debug" REM %QTDIR%\qmake\qmake -makefile -t lib cd .. cd caret_files %QTDIR%\qmake\qmake "CONFIG += release" "CONFIG -= debug" REM %QTDIR%\qmake\qmake -makefile -t lib cd .. cd caret_widgets %QTDIR%\qmake\qmake "CONFIG += release" "CONFIG -= debug" REM %QTDIR%\qmake\qmake -makefile -t lib cd .. cd caret_command %QTDIR%\qmake\qmake "CONFIG += release" "CONFIG -= debug" REM %QTDIR%\qmake\qmake -makefile -t app cd .. cd caret_edit %QTDIR%\qmake\qmake "CONFIG += release" "CONFIG -= debug" REM %QTDIR%\qmake\qmake -makefile -t app cd .. caret-5.6.4~dfsg.1.orig/install_dos.bat0000755000175000017500000000040111572067322017560 0ustar michaelmichaelcopy .\caret\debug\caret5.exe c:\caret_distribution\caret\bin copy .\caret_command\debug\caret_command.exe c:\caret_distribution\caret\bin copy .\caret_edit\debug\caret_edit.exe c:\caret_distribution\caret\bin strip c:\caret_distribution\caret\bin\*.exe caret-5.6.4~dfsg.1.orig/flat_fluid/0000775000175000017500000000000011572067322016672 5ustar michaelmichaelcaret-5.6.4~dfsg.1.orig/flat_fluid/surface_utils.c0000664000175000017500000006302611572067322021715 0ustar michaelmichael#include #include #include "surface.h" #define DEG2RAD 0.0174533 #define RAD2DEG 1.0/DEG2RAD #define X 0 #define Y 1 #define Z 2 void find_surface_extent (); void translate_to_center_of_mass (); void compute_center_of_mass (); void reindex_points (); int find_index (); float distance (); void normal_check (); void find_section_extent (); void copy_point (int snum1, int idx1, int snum2, int idx2); int int_is_in_list (int val, int num, int *list, int *pos) { int i; for (i = 0; i < num; i++){ if (list [i] == val){ *pos = i; return (True); } } return (False); } int find_index (int nbr, int snum) { int k, kmax; kmax = surface [snum].num_points; k = 0; while (k < kmax){ if (nbr == surface [snum].points [k].Index) return (k); else k++; } return (-1); } void reindex_points (snum) { int i, j, k; int Index, num_neigh; int point_to_delete, l, kmax; kmax = surface [snum].num_points; /* Reindex neighbors */ printf ("Reindexing %d neighbors from file...\n", kmax); for (k = 0; k < kmax; k++){ num_neigh = 0; if ((k % 1000) == 0) printf ("\t\treindex point %d\n", k); for (j = 0; j < surface [snum].points [k].num_neighs; j++){ Index = find_index (surface [snum].points [k].neighs [j], snum); if ((Index >= 0) && (Index != k)) surface [snum].points [k].neighs [num_neigh++] = Index; } surface [snum].points [k].num_neighs = num_neigh; if (num_neigh > MAX_NEIGHS){ printf ("ERROR: Exceeded max # of neighbors=%d for point %d (%d)\n", MAX_NEIGHS, kmax, num_neigh); exit (-1); } } k = 0; while (k < kmax){ if (surface [snum].points [k].num_neighs == 0) k++; else if (surface [snum].points [k].num_neighs < 2){ printf ("POINT %d (%d,%d) has %d neighbors -> DELETING\n", k, surface [snum].points [k].section, surface [snum].points [k].point, surface [snum].points [k].num_neighs); surface [snum].points [k].num_neighs = 0; point_to_delete = k; for (j = 0; j < kmax; j++){ for (i = 0; i < surface [snum].points [j].num_neighs; i++){ if (surface [snum].points [j].neighs [i] == point_to_delete){ for (l = i; l < surface [snum].points [j].num_neighs; l++) surface [snum].points [j].neighs [l] = surface [snum].points [j].neighs [l+1]; surface [snum].points [j].num_neighs--; } } } k = 0; } else k++; } surface [snum].num_points = kmax; printf ("%d points after reindexing...\n", surface [snum].num_points); } void find_surface_extent (int snum) { int i; float minx, maxx; float miny, maxy; float minz, maxz; minx = maxx = surface [snum].points [0].pos [0]; miny = maxy = surface [snum].points [0].pos [1]; minz = maxz = surface [snum].points [0].pos [2]; for (i = 0; i < surface [snum].num_points; i++){ if (surface [snum].points [i].pos [0] < minx) minx = surface [snum].points [i].pos [0]; if (surface [snum].points [i].pos [1] < miny) miny = surface [snum].points [i].pos [1]; if (surface [snum].points [i].pos [2] < minz) minz = surface [snum].points [i].pos [2]; if (surface [snum].points [i].pos [0] > maxx) maxx = surface [snum].points [i].pos [0]; if (surface [snum].points [i].pos [1] > maxy) maxy = surface [snum].points [i].pos [1]; if (surface [snum].points [i].pos [2] > maxz) maxz = surface [snum].points [i].pos [2]; } surface [snum].minx = minx; surface [snum].miny = miny; surface [snum].minz = minz; surface [snum].maxx = maxx; surface [snum].maxy = maxy; surface [snum].maxz = maxz; printf ("Surface extent: X %.2f..%.2f, Y %.2f..%.2f, Z %.2f..%.2f\n", surface [snum].minx, surface [snum].maxx, surface [snum].miny, surface [snum].maxy, surface [snum].minz, surface [snum].maxz); } void translate_to_center_of_mass (int snum) { int i; float cx, cy, cz; printf ("Translate to center of mass...\n"); compute_center_of_mass (snum, &cx, &cy, &cz); for (i = 0; i < surface [snum].num_points; i++){ surface [snum].points [i].pos [0] -= cx; surface [snum].points [i].pos [1] -= cy; surface [snum].points [i].pos [2] -= cz; } for (i = 0; i < surface [snum].NumCells; i++){ surface [snum].cells [i].pos [0] -= cx; surface [snum].cells [i].pos [1] -= cy; surface [snum].cells [i].pos [2] -= cz; } } void compute_center_of_mass (int snum, float *CX, float *CY, float *CZ) { float cx, cy, cz; int i, cnt = 0; cx = cy = cz = 0.0; for (i = 0; i < surface [snum].num_points; i++){ cx += surface [snum].points [i].pos [0]; cy += surface [snum].points [i].pos [1]; cz += surface [snum].points [i].pos [2]; cnt++; } *CX = cx/cnt; *CY = cy/cnt; *CZ = cz/cnt; } int DeleteLink (int snum, int n1, int n2) { int i, j, n, found = False; int temp_neighs [MAX_NEIGHS]; /*printf ("\tDelete %d %d\n", n1, n2);*/ i = 0; for (j = 0; j < surface [snum].points [n1].num_neighs; j++){ n = surface [snum].points [n1].neighs [j]; if (n2 == n){ /* found pair to delete, mark it! */ /*printf ("Found pair to delete...\n");*/ found = True; } else surface [snum].points [n1].neighs [i++] = surface [snum].points [n1].neighs [j]; } if (found == True){ surface [snum].points [n1].num_neighs = surface [snum].points [n1].num_neighs-1; return (True); } else{ printf ("\n"); return (False); } } int InsertLink (int snum, int n1, int n2) { int i, j, n; int t1; /*printf ("Insert %d %d\n", n1, n2);*/ if ((surface [snum].points [n1].num_neighs+1) > MAX_NEIGHS){ fprintf (stderr, "ERROR: Can't add link, exceeded MAX_NEIGHS %d\n", MAX_NEIGHS); return (False); } t1 = surface [snum].points [n1].num_neighs; surface [snum].points [n1].neighs [t1] = n2; surface [snum].points [n1].num_neighs++; return (True); } void DeleteAllLinks (int idx) { int n1, n2, t1, t2 [MAX_NEIGHS]; int np; n1 = idx; t1 = surface [0].points [n1].num_neighs; for (np = 0; np < t1; np++) t2 [np] = surface [0].points [n1].neighs [np]; for (np = 0; np < t1; np++){ n2 = t2 [np]; DeleteLink (0, n1, n2); DeleteLink (0, n2, n1); } /*point_hits [n1] = False;*/ } void ResetSurface (snum) { surface [snum].num_points = 0; surface [snum].NumBorders = 0; surface [snum].NumCells = 0; } int isBorder (int snum, int idx) { int i, j; for (i = 0; i < surface [snum].NumBorders; i++){ for (j = 0; j < surface [snum].borders [i].num_links; j++){ if (surface [snum].borders [i].links [j] == idx) return (True); } } return (False); } int find_point (int snum, int section, int point) { int i; for (i = 0; i < surface [snum].num_points; i++){ if (surface [snum].points [i].section == section){ if (surface [snum].points [i].point == point) return (i); } } } int find_point_fast (int snum, int section, int point, int prev) { int i; for (i = prev; i < surface [snum].num_points; i++){ if (surface [snum].points [i].section == section){ if (surface [snum].points [i].point == point) return (i); } } for (i = 0; i < prev; i++){ if (surface [snum].points [i].section == section){ if (surface [snum].points [i].point == point) return (i); } } printf ("\tWARNING: Point (%d,%d) not found in surface\n", section, point); return (-1); } float distance (v1, v2) register float *v1, *v2; { register float x, y, z; x = v1 [0] - v2 [0]; y = v1 [1] - v2 [1]; z = v1 [2] - v2 [2]; return (sqrt(x*x + y*y + z*z)); } int find_closest_point (int snum, float *point, float *dist) { int j, closest_point; float min_distance, length; closest_point = 0; min_distance = distance (point, surface [snum].points [0].pos); for (j = 1; j < surface [snum].num_points; j++){ if (surface [snum].points [j].num_neighs > 0){ length = distance (point, surface [snum].points [j].pos); if (length < min_distance){ min_distance = length; closest_point = j; } } } *dist = min_distance; return (closest_point); } void filter_colors (int snum) { int i, j, k, n; float accum [3]; printf ("Low-pass filter colors...\n"); for (i = 0; i < surface [snum].num_points; i++){ if ((i % 5000) == 0) printf ("\t%4d of %4d\n", i, surface [snum].num_points); for (k = 0; k < 3; k++) accum [k] = surface [snum].points [i].colors [k]; for (j = 0; j < surface [snum].points [i].num_neighs; j++){ n = surface [snum].points [i].neighs [j]; for (k = 0; k < 3; k++) accum [k] += surface [snum].points [n].colors [k]; } for (k = 0; k < 3; k++) surface [snum].points [i].colors [k] = accum [k]/(float)(surface [snum].points [i].num_neighs+1); } } float magnitude (vector) register float *vector; { return (sqrt(vector [X]*vector [X] + vector [Y]*vector [Y] + vector [Z]*vector [Z])); } void subtract_vectors (v1, v2, diff) register float *v1, *v2, *diff; { int i; for (i = 0; i < 3; i++) diff [i] = v1 [i] - v2 [i]; } void unit_normal (float *o, float *n, float * m, float *normal) { int i; float d_o [3], d_m [3], nmag; /* Obtain the unit normal from (o - n) x (m - n) */ subtract_vectors (o, n, d_o); subtract_vectors (m, n, d_m); normal [X] = d_o [Y]*d_m [Z] - d_m [Y]*d_o [Z]; normal [Y] = d_m [X]*d_o [Z] - d_o [X]*d_m [Z]; normal [Z] = d_o [X]*d_m [Y] - d_m [X]*d_o [Y]; nmag = magnitude (normal); if (nmag > 0.0) { for (i = 0; i < 3; i++) normal [i] /= nmag; } else { for (i = 0; i < 3; i++) normal [i] = 0.0; } } void compute_normals (int snum) { int v1, v2, v3; int i, j; float normal [3], nmag; for (i = 0; i < surface [snum].num_points; i++){ for (j = 0; j < 3; j++) surface [snum].points [i].normal [j] = 0.0; surface [snum].points [i].num_tris = 0; } for (i = 0; i < surface [snum].NumPolygons; i++){ v1 = surface [snum].tiles [i].triangle [0]; v2 = surface [snum].tiles [i].triangle [1]; v3 = surface [snum].tiles [i].triangle [2]; unit_normal (surface [snum].points [v1].pos, surface [snum].points [v2].pos, surface [snum].points [v3].pos, normal); for (j = 0; j < 3; j++){ surface [snum].points [v1].normal [j] += normal [j]; surface [snum].points [v1].num_tris++; surface [snum].points [v2].normal [j] += normal [j]; surface [snum].points [v2].num_tris++; surface [snum].points [v3].normal [j] += normal [j]; surface [snum].points [v3].num_tris++; } /*if ((i % 1) == 0) printf ("Normal for triangle %d: %d %d %d is %.2f %.2f %.2f\n", i, v1, v2, v3, normal [0], normal [1], normal [2]);*/ } for (i = 0; i < surface [snum].num_points; i++){ for (j = 0; j < 3; j++) surface [snum].points [i].normal [j] /= surface [snum].points [v3].num_tris; nmag = magnitude (surface [snum].points [i].normal); for (j = 0; j < 3; j++) surface [snum].points [i].normal [j] /= nmag; } } normal_constistency_check (int snum) { int i; for (i = 0; i < surface [snum].NumPolygons; i++) surface [snum].tiles [i].visited = False; normal_check (snum, 0); } int DoTrianglesShareEdge (int snum, int Tidx1, int Tidx2, int *common) { int i; int v1, v2; int found, flag, pos; float val; i = 0; found = False; while (found == False){ flag = int_is_in_list (surface [snum].tiles [Tidx1].triangle [i], 3, surface [snum].tiles [Tidx2].triangle, &pos); if (flag == True){ v1 = surface [snum].tiles [Tidx1].triangle [i]; found = True; } else i++; if (i == 3) return (False); } i = 0; found = False; while (found == False){ if (surface [snum].tiles [Tidx1].triangle [i] == v1) i++; flag = int_is_in_list (surface [snum].tiles [Tidx1].triangle [i], 3, surface [snum].tiles [Tidx2].triangle, &pos); if (flag == True){ v2 = surface [snum].tiles [Tidx1].triangle [i]; found = True; } else i++; if (i >= 3) return (False); } common [0] = v1; common [1] = v2; /*printf ("Triangles share edge %d %d\n", v1, v2); printf ("\t%d: %d %d %d\n", Tidx1, surface [snum].tiles [Tidx1].triangle [0], surface [snum].tiles [Tidx1].triangle [1], surface [snum].tiles [Tidx1].triangle [2]); printf ("\t%d: %d %d %d\n", Tidx2, surface [snum].tiles [Tidx2].triangle [0], surface [snum].tiles [Tidx2].triangle [1], surface [snum].tiles [Tidx2].triangle [2]);*/ return (True); } int findTriangleNeighbors (int snum, int Tidx, int *Tneighs) { int i, flag, num = 0; int commonVertices [2]; for (i = 0; i < surface [snum].NumPolygons; i++){ if (i != Tidx){ flag = DoTrianglesShareEdge (snum, Tidx, i, commonVertices); if (flag == True) Tneighs [num++] = i; } } if (num > 3){ printf ("ERROR: What?\n"); printf ("\tTriangle %d has %d neighboring triangles...\n", Tidx, num); for (i = 0; i < num; i++) printf ("\t\t%d %d\n", i, Tneighs [i]); /*exit (-1);*/ } return (num); } void insertVertex (int snum, int Tidx1, int Tidx2, int *commonVertices, int *tri) { int notshared; int i, flag; int p1, p2; for (i = 0; i < 3; i++){ flag = int_is_in_list (surface [snum].tiles [Tidx2].triangle [i], 2, commonVertices, &p1); if (flag == False) notshared = surface [snum].tiles [Tidx2].triangle [i]; } flag = int_is_in_list (commonVertices [0], 3, surface [snum].tiles [Tidx1].triangle, &p1); flag = int_is_in_list (commonVertices [1], 3, surface [snum].tiles [Tidx1].triangle, &p2); /*printf ("New polygon: %4d %4d, new = %4d\n", commonVertices [0], commonVertices [1], notshared); printf (" : %4d %4d\n", p1, p2);*/ if ((p1 == 0) && (p2 == 1)){ tri [0] = commonVertices [0]; tri [1] = notshared; tri [2] = commonVertices [1]; }else if ((p1 == 0) && (p2 == 2)){ tri [0] = commonVertices [1]; tri [1] = notshared; tri [2] = commonVertices [0]; }else if ((p1 == 1) && (p2 == 2)){ tri [0] = commonVertices [0]; tri [1] = notshared; tri [2] = commonVertices [1]; } else{ printf ("What to do!\n"); exit (-1); } } void normal_check (int snum, int Tidx) { int Tneighs [10]; /* triangles that share common edge (can't be more than 3) */ int newTri [3]; int numTneighs; int i, j; int commonVertices [2], notshared; if (surface [snum].tiles [Tidx].visited == True) return; if ((Tidx % 500) == 0) printf ("Checking triangle %d\n", Tidx); surface [snum].tiles [Tidx].visited = True; numTneighs = findTriangleNeighbors (snum, Tidx, Tneighs); for (i = 0; i < numTneighs; i++){ DoTrianglesShareEdge (snum, Tidx, Tneighs [i], commonVertices); insertVertex (snum, Tidx, Tneighs [i], commonVertices, newTri); for (j = 0; j < 3; j++) surface [snum].tiles [Tneighs [i]].triangle [j] = newTri [j]; normal_check (snum, Tneighs [i]); } } #define sgn(a) ((a) < 0.0 ? -1.0 : 1.0) /* NB 0.0 -> 1.0 */ float compute_angle (float *v1, float *v2, float *v3, float nx, float ny, float nz) { float x1, x2, y1, y2, z1, z2, dx, dy, dz, s, c, phi; x1 = v2 [0] - v1 [0]; y1 = v2 [1] - v1 [1]; z1 = v2 [2] - v1 [2]; x2 = v3 [0] - v1 [0]; y2 = v3 [1] - v1 [1]; z2 = v3 [2] - v1 [2]; dx = y1*z2 - y2*z1; dy = x2*z1 - x1*z2; dz = x1*y2 - x2*y1; s = sgn((dx*nx) + (dy*ny) + (dz*nz)) * sqrt((dx*dx) + (dy*dy) + (dz*dz)); c = x1*x2 + y1*y2 + z1*z2; phi = atan2(s,c); return (phi); } float compute_triangle_area (float *p1, float *p2, float *p3, float *tnormal) { float area, w, h; w = distance (p2, p1); h = distance (p2, p3); if ((w <= 0.0) || (h <= 0.0)) area = 0.0; else area = 0.5*w*h*sin(compute_angle (p2, p3, p1, tnormal [0], tnormal [1], tnormal [2])); return (area); } void find_section_extent (int snum) { int min, max; int i; min = max = surface [snum].points [0].section; for (i = 0; i < surface [snum].num_points; i++){ /*printf ("%d %d\n", i, surface [snum].points [i].section);*/ if (surface [snum].points [i].section > max) max = surface [snum].points [i].section; if (surface [snum].points [i].section < min) min = surface [snum].points [i].section; } printf ("SURFACE: Sections %d..%d\n", min, max); surface [snum].lo_section = min; surface [snum].hi_section = max; } int find_point_using_pos (int snum, float *pos) { int i; float d1, d2, d3; for (i = 0; i < surface [snum].num_points; i++){ d1 = fabs (pos [0] - surface [snum].points [i].pos [0]); if (d1 < 0.01){ d2 = fabs (pos [1] - surface [snum].points [i].pos [1]); if (d2 < 0.01){ d3 = fabs (pos [2] - surface [snum].points [i].pos [2]); if (d3 < 0.1) return (i); } } } printf ("ERROR: Can't find point %f %f %f...\n", pos [0], pos [1], pos [2]); return (-1); } void smoothing (int snum, float init_t_value, int iter) { float F_VALUE; int nsmooth, i, j, neigh; float xa, ya, za; float smoothp [MAX_POINTS][3]; printf ("\tSMOOTH surface %d for %d iters, %f param\n", snum, iter, init_t_value); for (j = 0; j < surface [snum].num_points; j++) for (i = 0; i < 3; i++) smoothp [j][i] = surface [snum].points [j].pos [i]; for (nsmooth = 0; nsmooth < iter; nsmooth++){ /*if ((nsmooth % 10) == 0) printf ("\t%d of %d\n", nsmooth, iter);*/ for (j = 0; j < surface [snum].num_points; j++){ F_VALUE = 1.0 - init_t_value; xa = ya = za = 0.0; for (i = 0; i < surface [snum].points [j].num_neighs; i++){ neigh = surface [snum].points [j].neighs [i]; xa += surface [snum].points [neigh].pos [0]; ya += surface [snum].points [neigh].pos [1]; za += surface [snum].points [neigh].pos [2]; } xa = xa/(float) surface [snum].points [j].num_neighs; ya = ya/(float) surface [snum].points [j].num_neighs; za = za/(float) surface [snum].points [j].num_neighs; if (surface [snum].points [j].num_neighs > 0){ smoothp [j][0] = (1.0 - F_VALUE)*surface [snum].points [j].pos [0] + F_VALUE*xa; smoothp [j][1] = (1.0 - F_VALUE)*surface [snum].points [j].pos [1] + F_VALUE*ya; smoothp [j][2] = (1.0 - F_VALUE)*surface [snum].points [j].pos [2] + F_VALUE*za; } } } for (j = 0; j < surface [snum].num_points; j++) for (i = 0; i < 3; i++) surface [snum].points [j].pos [i] = smoothp [j][i]; } void cross_product (d_o, d_m, product) float *product, *d_o, *d_m; { int i; float nmag; product [X] = d_o [Y]*d_m [Z] - d_m [Y]*d_o [Z]; product [Y] = d_m [X]*d_o [Z] - d_o [X]*d_m [Z]; product [Z] = d_o [X]*d_m [Y] - d_m [X]*d_o [Y]; nmag = magnitude (product); if (nmag > 0.0) { for (i = 0; i < 3; i++) product [i] /= nmag; } else { for (i = 0; i < 3; i++) product [i] = 0.0; } } float dot_product (v, w) float *v, *w; { float result; result = v [0]*w [0] + v [1]*w [1] + v [2]*w [2]; return (result); } void check_triangles (int snum) { int i, v1, v2, v3; float angle1, angle2, angle3, normal [3], temp1, temp2, temp3; int s1, s2, s3; float LOWER = 2.0; printf ("\nChecking triangles for surface %d\n", snum); for (i = 0; i < surface [snum].NumPolygons; i++){ if ((i % 10000) == 0) printf ("\ttriangle %5d of %5d\n", i, surface [snum].NumPolygons); v1 = surface [snum].tiles [i].triangle [0]; v2 = surface [snum].tiles [i].triangle [1]; v3 = surface [snum].tiles [i].triangle [2]; unit_normal (surface [snum].points [v1].pos, surface [snum].points [v2].pos, surface [snum].points [v3].pos, normal); angle1 = compute_angle ( surface [snum].points [v1].pos, surface [snum].points [v2].pos, surface [snum].points [v3].pos, normal [0], normal [1], normal [2]); temp1 = fabsf (angle1)*RAD2DEG; angle2 = compute_angle ( surface [snum].points [v2].pos, surface [snum].points [v3].pos, surface [snum].points [v1].pos, normal [0], normal [1], normal [2]); temp2 = fabsf (angle2)*RAD2DEG; angle3 = compute_angle ( surface [snum].points [v3].pos, surface [snum].points [v1].pos, surface [snum].points [v2].pos, normal [0], normal [1], normal [2]); temp3 = fabsf (angle2)*RAD2DEG; if ((temp1 < LOWER) || (temp2 < LOWER) || (temp3 < LOWER)){ s1 = surface [snum].points [v1].section; s2 = surface [snum].points [v2].section; s3 = surface [snum].points [v3].section; if ((s1 == s2) && (s2 == s3)) printf ("Triangle on one section\n"); else{ printf ("WARNING: Angle for triangle %d too SMALL\n", i); printf ("\tVertices: %d (%d,%d) %d (%d,%d) %d (%d,%d)\n", v1, surface [snum].points [v1].section, surface [snum].points [v1].point, v2, surface [snum].points [v2].section, surface [snum].points [v2].point, v3, surface [snum].points [v3].section, surface [snum].points [v3].point); printf ("\tAngles : %f,%f,%f)\n", temp1, temp2, temp3); } } /*printf ("Triangle %4d: %.2f %.2f %.2f\n", i, angle1*RAD2DEG, angle2*RAD2DEG, angle3*RAD2DEG);*/ } } void compute_distortion (int snum) { int i; int v1, v2, v3; float temp, avg = 0.0; printf ("Compute distortion for surface %d\n", snum); for (i = 0; i < surface [snum].NumPolygons; i++){ temp = surface [snum].tiles [i].area2D/surface [snum].tiles [i].area3D; if ((i % 1000) == 0) printf ("%d %f %f %f %f\n", i, surface [snum].tiles [i].area2D, surface [snum].tiles [i].area3D, temp, avg); avg += fabsf ((temp-1.0)*100.0); surface [snum].tiles [i].distortion = log (temp)/log (2.0); } avg /= surface [snum].NumPolygons; printf ("\tAverage polygon distortion is %f\n", avg); for (i = 0; i < surface [snum].num_points; i++) surface [snum].points [i].distortion = 0.0; for (i = 0; i < surface [snum].NumPolygons; i++){ v1 = surface [snum].tiles [i].triangle [0]; v2 = surface [snum].tiles [i].triangle [1]; v3 = surface [snum].tiles [i].triangle [2]; surface [snum].points [v1].distortion += surface [snum].tiles [i].distortion; surface [snum].points [v2].distortion += surface [snum].tiles [i].distortion; surface [snum].points [v3].distortion += surface [snum].tiles [i].distortion; } for (i = 0; i < surface [snum].num_points; i++){ surface [snum].points [i].distortion /= surface [snum].points [i].num_neighs; /*if ((i % 1000) == 0) printf ("\t\t%d %f\n", i, surface [snum].points [i].distortion);*/ } } /* Copy point idx1 -> idx2 */ void copy_point (int snum1, int idx1, int snum2, int idx2) { int i; for (i = 0; i < 3; i++){ surface [snum2].points [idx2].pos [i] = surface [snum1].points [idx1].pos [i]; surface [snum2].points [idx2].pos3D [i] = surface [snum1].points [idx1].pos3D [i]; surface [snum2].points [idx2].normal [i] = surface [snum1].points [idx1].normal [i]; surface [snum2].points [idx2].colors [i] = surface [snum1].points [idx1].colors [i]; } surface [snum2].points [idx2].num_neighs = surface [snum1].points [idx1].num_neighs; surface [snum2].points [idx2].num_tris = surface [snum1].points [idx1].num_tris; for (i = 0; i < surface [snum1].points [idx1].num_neighs; i++){ surface [snum2].points [idx2].neighs [i] = surface [snum1].points [idx1].neighs [i]; } surface [snum2].points [idx2].section = surface [snum1].points [idx1].section; surface [snum2].points [idx2].point = surface [snum1].points [idx1].point; surface [snum2].points [idx2].class = surface [snum1].points [idx1].class; surface [snum2].points [idx2].Index = surface [snum1].points [idx1].Index; strcpy (surface [snum2].points [idx2].region, surface [snum1].points [idx1].region); surface [snum2].points [idx2].display_flag = True; surface [snum2].points [idx2].curvature = surface [snum1].points [idx1].curvature; surface [snum2].points [idx2].projcells = surface [snum1].points [idx1].projcells; surface [snum2].points [idx2].distortion = surface [snum1].points [idx1].distortion; } caret-5.6.4~dfsg.1.orig/flat_fluid/surface_io.c0000664000175000017500000014157411572067322021171 0ustar michaelmichael#include #include "surface.h" #define NEW #define SKIP 1 extern int num_surfaces; void read_surface_file (); void write_all_surface_file (); void write_coord_file (); void write_3Dcoord_file (); void write_sort_file (); void write_cnt_file (); void read_coord_file (); void read_3Dcoord_file (); void read_sort_file (); void read_aux_file (); void read_border_file (); void read_ascii_border_file (); void read_polygon_file (); void read_off_file (); void convert_off_file (); void convert_off_file_new (); void match_points_to_triangles (); void read_curvature_file (); void read_projcells_file (); void copy_point (); void read_anat_boundaries_file (); void extract_sections (int snum, int num_sections, float *distinct_z); int determine_num_contours (int snum, int sect, int *npoints); int read_2Darea_file (); int read_3Darea_file (); extern void reindex_points (); extern void compute_normals (); extern int find_index (); extern void find_surface_extent (); extern void translate_to_center_of_mass (); extern void compute_center_of_mass (); extern int find_point (); extern int find_closest_point (); extern int find_section_extent (); extern void check_triangles (); #define MAX_PT_TRIS 100 struct{ int num_tris; int tris [MAX_PT_TRIS]; }pt_tris [MAX_POINTS]; int determine_section_num (int snum, float val, int nsections, float *distinct_z) { int i; for (i = 0; i < nsections; i++){ if (distinct_z [i] == val) return (i); } printf ("ERROR: Can't find point with z value of %f\n", val); exit (-1); } void InitStuff (int snum) { int i; for (i = 0; i < MAX_BORDERS; i++) surface [snum].borders [i].num_links = 0; } void read_surface_file (char *filename, int snum) { FILE *fp; int i, j; int i1, i2, i3, i4; float f1, f2, f3; char line [100], s1 [5]; int debug = False; if ((fp = fopen (filename, "r")) == NULL){; printf ("ERROR: (read_surface_file) could not open file %s\n", filename); exit (-1); } fgets (line, MAXLINE, fp); sscanf (line, "%d", &surface [snum].num_points); InitStuff (snum); printf ("%d points to read from raw %s...\n", surface [snum].num_points, filename); if (surface [snum].num_points > MAX_POINTS){ printf ("ERROR: %d Exceeded max # of points %d\n", surface [snum].num_points, MAX_POINTS); exit (-1); } for (i = 0; i < surface [snum].num_points; i++){ fgets (line, MAXLINE, fp); sscanf (line, "%d %f %f %f %d %d %d %s", &i1, &f1, &f2, &f3, &i2, &i3, &i4, s1); /*printf ("%d %f %f %f %d %d %d %s\n", i1, f1, f2, f3, i2, i3, i4, s1);*/ /*surface [snum].points [i].Index = i1;*/ surface [snum].points [i].pos [0] = f1; surface [snum].points [i].pos [1] = f2; surface [snum].points [i].pos [2] = f3; /*printf ("\t%d %f %f %f\n", i, surface [snum].points [i].pos [0], surface [snum].points [i].pos [1], surface [snum].points [i].pos [2]);*/ /*surface [snum].points [i].num_neighs = i2;*/ if (surface [snum].points [i].num_neighs > MAX_NEIGHS){ printf ("ERROR: %d Exceeded max # of neighbors %d > %d\n", i, surface [snum].points [i].num_neighs, MAX_NEIGHS); exit (-1); } /*surface [snum].points [i].section = i3; surface [snum].points [i].point = i4; strcpy (surface [snum].points [i].region, s1);*/ if (debug) printf ("%d %f %f %f %d %d %d %s\n", surface [snum].points [i].Index, surface [snum].points [i].pos [0], surface [snum].points [i].pos [1], surface [snum].points [i].pos [2], surface [snum].points [i].num_neighs, surface [snum].points [i].section, surface [snum].points [i].point, surface [snum].points [i].region); for (j = 0; j < i2; j++){ fgets (line, MAXLINE, fp); sscanf (line, "%d %d", &i1, &i3); /*printf ("\t\t%d %d\n", i1, i3);*/ /*surface [snum].points [i].neighs [j] = i3;*/ if (debug) printf ("\t%d %d\n", j, surface [snum].points [i].neighs [j]); } } fclose (fp); printf ("Read %d points from file\n", i); /*reindex_points (snum); translate_to_center_of_mass (snum); find_surface_extent (snum);*/ } void write_all_3Dsurface_file (char *filename, int snum) { FILE *fp; int i, j; char newfile [100]; sprintf (newfile, "%s.3Dall", filename); if ((fp = fopen (newfile, "w")) == NULL){; printf ("ERROR: (write_surface_file) could not open file %s\n", newfile); exit (-1); } fprintf (fp, "%d\n", surface [snum].num_points); printf ("%d points to write to %s...\n", surface [snum].num_points, newfile); for (i = 0; i < surface [snum].num_points; i++){ fprintf (fp, "%d %f %f %f %d %d %d %s\n", i, surface [snum].points [i].pos3D [0], surface [snum].points [i].pos3D [1], surface [snum].points [i].pos3D [2], surface [snum].points [i].num_neighs, surface [snum].points [i].section, surface [snum].points [i].point, surface [snum].points [i].region); for (j = 0; j < surface [snum].points [i].num_neighs; j++) fprintf (fp, "%d %d\n", j, surface [snum].points [i].neighs [j]); } fclose (fp); } void write_all_surface_file (char *filename, int snum) { FILE *fp; int i, j; char newfile [100]; sprintf (newfile, "%s.all", filename); if ((fp = fopen (newfile, "w")) == NULL){; printf ("ERROR: (write_surface_file) could not open file %s\n", newfile); exit (-1); } fprintf (fp, "%d\n", surface [snum].num_points); printf ("%d points to write to %s...\n", surface [snum].num_points, newfile); for (i = 0; i < surface [snum].num_points; i++){ fprintf (fp, "%d %f %f %f %d %d %d %s\n", i, surface [snum].points [i].pos [0], surface [snum].points [i].pos [1], surface [snum].points [i].pos [2], surface [snum].points [i].num_neighs, surface [snum].points [i].section, surface [snum].points [i].point, surface [snum].points [i].region); for (j = 0; j < surface [snum].points [i].num_neighs; j++) fprintf (fp, "%d %d\n", j, surface [snum].points [i].neighs [j]); } fclose (fp); } void extract_surface_file (char *filename, int snum, char *area) { FILE *fp; int i, j, s1, temp; if ((fp = fopen (filename, "w")) == NULL){; printf ("ERROR: (write_surface_file) could not open file %s\n", filename); exit (-1); } temp = 0; for (i = 0; i < surface [snum].num_points; i++){ s1 = strcmp (surface [snum].points [i].region, area); if (s1 == 0) temp++; } fprintf (fp, "%d\n", temp); printf ("%d points to write to %s for area %s...\n", temp, filename, area); for (i = 0; i < surface [snum].num_points; i++){ s1 = strcmp (surface [snum].points [i].region, area); if (s1 == 0){ fprintf (fp, "%d %f %f %f %d %d %d %s\n", surface [snum].points [i].Index, surface [snum].points [i].pos [0], surface [snum].points [i].pos [1], surface [snum].points [i].pos [2], surface [snum].points [i].num_neighs, surface [snum].points [i].section, surface [snum].points [i].point, surface [snum].points [i].region); for (j = 0; j < surface [snum].points [i].num_neighs; j++) fprintf (fp, "%d %d\n", j, surface [snum].points [i].neighs [j]); } } fclose (fp); } void write_3Dcoord_file (char *filename, int snum) { FILE *fp; int i, j; char newfile [100]; sprintf (newfile, "%s.3Dcoord", filename); if ((fp = fopen (newfile, "w")) == NULL){; printf ("ERROR: (write_3Dcoord_file) could not open file %s\n", newfile); exit (-1); } fprintf (fp, "%d\n", surface [snum].num_points); printf ("%d points to write to %s for snum %d...\n", surface [snum].num_points, newfile, snum); for (i = 0; i < surface [snum].num_points; i++){ fprintf (fp, "%d %f %f %f\n", i, surface [snum].points [i].pos3D [0], surface [snum].points [i].pos3D [1], surface [snum].points [i].pos3D [2]); } fclose (fp); } void write_coord_file (char *filename, int snum) { FILE *fp; int i, j; char newfile [100]; sprintf (newfile, "%s.coord", filename); if ((fp = fopen (newfile, "w")) == NULL){; printf ("ERROR: (write_coord_file) could not open file %s\n", newfile); exit (-1); } fprintf (fp, "%d\n", surface [snum].num_points); printf ("%d points to write to %s for snum %d...\n", surface [snum].num_points, newfile, snum); for (i = 0; i < surface [snum].num_points; i++){ fprintf (fp, "%d %f %f %f\n", i, surface [snum].points [i].pos [0], surface [snum].points [i].pos [1], surface [snum].points [i].pos [2]); if (i < 10) printf ("%d %.2f %.2f\n", i, surface [snum].points [i].pos [0], surface [snum].points [i].pos [1]); } fclose (fp); } void write_cnt_file (char *filename, int snum) { FILE *fp; int i, j, idx; char newfile [100]; int cnt, current_contour, num_contour_points [10], num_contours; sprintf (newfile, "%s.cnt", filename); if ((fp = fopen (newfile, "w")) == NULL){; printf ("ERROR: (write_cnt_file) could not open file %s\n", newfile); exit (-1); } fprintf (fp, "S %d\n", surface [snum].NumSections); printf ("%d points to write to %s...\n", surface [snum].num_points, newfile); for (i = 0; i < surface [snum].NumSections; i++){ num_contours = determine_num_contours (snum, i, num_contour_points); printf ("\tSection %d has %d contours\n", i, num_contours); j = 0; current_contour = 0; idx = surface [snum].sections [i].points [j]; fprintf (fp, "v %d z %f\n", num_contour_points [current_contour], surface [snum].points [idx].pos [2]); fprintf (fp, "{\n"); while (j < surface [snum].sections [i].num_points){ idx = surface [snum].sections [i].points [j]; if (surface [snum].points [idx].contour != current_contour){ fprintf (fp, "}\n"); current_contour++; fprintf (fp, "v %d z %f\n", num_contour_points [current_contour], surface [snum].points [idx].pos [2]); fprintf (fp, "{\n"); } fprintf (fp, "%f %f\n", surface [snum].points [idx].pos [0], surface [snum].points [idx].pos [1]); j++; } fprintf (fp, "}\n"); } fclose (fp); } void write_sort_file (char *filename, int snum) { FILE *fp; int i, j; char newfile [100]; sprintf (newfile, "%s.sort", filename); if ((fp = fopen (newfile, "w")) == NULL){; printf ("ERROR: (write_sort_file) could not open file %s\n", newfile); exit (-1); } fprintf (fp, "%d\n", surface [snum].num_points); printf ("%d points to write to %s...\n", surface [snum].num_points, newfile); for (i = 0; i < surface [snum].num_points; i++){ if (strlen (surface [snum].points [i].region) == 0) strcpy (surface [snum].points [i].region, "???"); #ifdef NEW fprintf (fp, "%d %d %d %d %d %d %s\n", i, surface [snum].points [i].num_neighs, surface [snum].points [i].section, surface [snum].points [i].contour, surface [snum].points [i].point, surface [snum].points [i].class, surface [snum].points [i].region); #else fprintf (fp, "%d %d %d %d %d %s\n", i, surface [snum].points [i].num_neighs, surface [snum].points [i].section, surface [snum].points [i].point, surface [snum].points [i].class, surface [snum].points [i].region); #endif /*printf ("%d %d %d %d %s\n", i, surface [snum].points [i].num_neighs, surface [snum].points [i].section, surface [snum].points [i].point, surface [snum].points [i].region);*/ for (j = 0; j < surface [snum].points [i].num_neighs; j++) fprintf (fp, "%d %d\n", j, surface [snum].points [i].neighs [j]); } fclose (fp); } void read_coord_file (char *filename, int snum) { FILE *fp; int i, j; float f1, f2, f3; int i1, i2, i3, i4, i5, i6; char s1 [5]; int cnt; if ((fp = fopen (filename, "r")) == NULL){; printf ("ERROR: (read_coord_file) could not open file %s\n", filename); exit (-1); } fscanf (fp, "%d", &surface [snum].num_points); printf ("%d points to read from coord %s to snum %d...\n", surface [snum].num_points, filename, snum); if (surface [snum].num_points > MAX_POINTS){ printf ("ERROR: %d Exceeded max # of points %d\n", surface [snum].num_points, MAX_POINTS); exit (-1); } InitStuff (snum); cnt = 0; for (i = 0; i < surface [snum].num_points; i++){ if ((i % 5000) == 0) printf ("\t%5d of %5d\n", i, surface [snum].num_points); #ifdef NEW fscanf (fp, "%d %f %f %f", &i1, &f1, &f2, &f3); /*printf ("%d %f %f %f\n", i1, f1, f2, f3);*/ #else fscanf (fp, "%d %f %f %f %d %d %d %d %s %d %d", &i1, &f1, &f2, &f3, &i1, &i2, &i3, &i4, s1, &i5, &i6); #endif if ((i % SKIP) == 0){ double TransformX2Image (double); double TransformY2Image (double); surface [snum].points [cnt].pos [0] = f1; surface [snum].points [cnt].pos [1] = f2; surface [snum].points [cnt].pos [2] = f3; /*surface [snum].points [cnt].pos [0] = TransformX2Image (f1); surface [snum].points [cnt].pos [1] = TransformY2Image (f2);*/ surface [snum].points [cnt].display_flag = True; cnt++; } } surface [snum].num_points = cnt; printf ("%d points for surface...\n", cnt); fclose (fp); } void read_sort_file (char *filename, int snum) { FILE *fp; int i, j; int i1, i2, i3, i4, i5, i6; char s1 [10]; if ((fp = fopen (filename, "r")) == NULL){; printf ("ERROR: (read_sort_file) could not open file %s\n", filename); exit (-1); } fscanf (fp, "%d", &surface [snum].num_points); printf ("%d points to read from sort %s...\n", surface [snum].num_points, filename); if (surface [snum].num_points > MAX_POINTS){ printf ("ERROR: %d Exceeded max # of points %d\n", surface [snum].num_points, MAX_POINTS); exit (-1); } for (i = 0; i < surface [snum].num_points; i++){ if ((i % 5000) == 0) printf ("\t%5d of %5d\n", i, surface [snum].num_points); #ifdef NEW /*fscanf (fp, "%d %d %d %d %d %d %s", &i1, &i2, &i3, &i6, &i4, &i5, s1);*/ /*printf ("%d %d %d %d %d %d %s\n", i1, i2, i3, i6, i4, i5, s1);*/ fscanf (fp, "%d %d %d %d %d %s", &i1, &i2, &i3, &i4, &i5, s1); /*surface [snum].points [i].contour = i6;*/ #else fscanf (fp, "%d %d %d %d %d %s", &i1, &i2, &i3, &i4, &i5, s1); #endif surface [snum].points [i].num_neighs = i2; if (surface [snum].points [i].num_neighs > MAX_NEIGHS){ printf ("ERROR: %d Exceeded max # of neighbors %d > %d\n", i, surface [snum].points [i].num_neighs, MAX_NEIGHS); exit (-1); } surface [snum].points [i].Index = i1; surface [snum].points [i].section = i3; surface [snum].points [i].point = i4; surface [snum].points [i].class = i5; strcpy (surface [snum].points [i].region, s1); for (j = 0; j < surface [snum].points [i].num_neighs; j++){ fscanf (fp, "%d %d", &i1, &i2); surface [snum].points [i].neighs [j] = i2; } } fclose (fp); } void read_sort_file_old (char *filename, int snum) { FILE *fp; int i, j; int i1, i2, i3, i4, i5, i6; char s1 [10]; if ((fp = fopen (filename, "r")) == NULL){; printf ("ERROR: (read_sort_file) could not open file %s\n", filename); exit (-1); } fscanf (fp, "%d", &surface [snum].num_points); printf ("%d points to read from sort %s...\n", surface [snum].num_points, filename); if (surface [snum].num_points > MAX_POINTS){ printf ("ERROR: %d Exceeded max # of points %d\n", surface [snum].num_points, MAX_POINTS); exit (-1); } for (i = 0; i < surface [snum].num_points; i++){ if ((i % 5000) == 0) printf ("\t%5d of %5d\n", i, surface [snum].num_points); #ifdef NEW fscanf (fp, "%d %d %d %d %d %d %s", &i1, &i2, &i3, &i6, &i4, &i5, s1); printf ("%d %d %d %d %d %d %s\n", i1, i2, i3, i6, i4, i5, i6, s1); surface [snum].points [i].contour = i6; #else fscanf (fp, "%d %d %d %d %d %s", &i1, &i2, &i3, &i4, &i5, s1); #endif surface [snum].points [i].num_neighs = i2; if (surface [snum].points [i].num_neighs > MAX_NEIGHS){ printf ("ERROR: %d Exceeded max # of neighbors %d > %d\n", i, surface [snum].points [i].num_neighs, MAX_NEIGHS); exit (-1); } surface [snum].points [i].Index = i1; surface [snum].points [i].section = i3; surface [snum].points [i].point = i4; surface [snum].points [i].class = i5; /*if (i5 != 0) printf ("EDGE %d %d %d %d %s\n", i, surface [snum].points [i].num_neighs, surface [snum].points [i].section, surface [snum].points [i].point, surface [snum].points [i].region);*/ strcpy (surface [snum].points [i].region, s1); /*printf ("%d %d %d %d %s\n", i, surface [snum].points [i].num_neighs, surface [snum].points [i].section, surface [snum].points [i].point, surface [snum].points [i].region);*/ for (j = 0; j < surface [snum].points [i].num_neighs; j++){ fscanf (fp, "%d %d", &i1, &i2); /*printf ("\t%d %d\n", i1, i2); */ surface [snum].points [i].neighs [j] = i2; } } fclose (fp); } void ReadParamFile (int snum, char *file) { int i, j; FILE *fd_params; char line [MAXLINE], temp_string [MAXLINE]; char aux_file [100]; char curvature_file [100], projcells_file [100], area2D_file [100], area3D_file [100]; char param_string [][80] = { "coord_file", "sort_file", "border_file", "cell_file", "polygon_file", "3Dcoord_file", "off_file", "aux_file", "curvature_file", "2Darea_file", "3Darea_file", "projcells_file" }; float distinct_z [100]; int num_sections; printf ("Open parameter file %s\n", file); if ((fd_params = fopen (file, "r")) == NULL){ printf ("ERROR: Can't read params file %s\n", file); exit (-1); } while (fgets (line, MAXLINE, fd_params) != NULL){ if (line [0] != '#'){ if (strncmp (line, param_string [0], strlen (param_string [0])) == 0){ sscanf (line, "%s %s\n", temp_string, surface [snum].coord_file); printf ("Coord file %s\n", surface [snum].coord_file); } else if (strncmp (line, param_string [1], strlen (param_string [1])) == 0){ sscanf (line, "%s %s\n", temp_string, surface [snum].sort_file); printf ("Sort file %s\n", surface [snum].sort_file); } else if (strncmp (line, param_string [2], strlen (param_string [2])) == 0){ sscanf (line, "%s %s\n", temp_string, surface [snum].border_file); printf ("Border file %s\n", surface [snum].border_file); } else if (strncmp (line, param_string [3], strlen (param_string [3])) == 0){ sscanf (line, "%s %s\n", temp_string, surface [snum].cell_file); printf ("Cell file %s\n", surface [snum].cell_file); } else if (strncmp (line, param_string [4], strlen (param_string [4])) == 0){ sscanf (line, "%s %s\n", temp_string, surface [snum].polygon_file); printf ("Polygon file %s\n", surface [snum].polygon_file); } else if (strncmp (line, param_string [5], strlen (param_string [5])) == 0){ sscanf (line, "%s %s\n", temp_string, surface [snum].coord3D_file); printf ("3D coordinate file %s\n", surface [snum].coord3D_file); } else if (strncmp (line, param_string [6], strlen (param_string [6])) == 0){ sscanf (line, "%s %s\n", temp_string, surface [snum].off_file); printf ("OFF file %s\n", surface [snum].off_file); } else if (strncmp (line, param_string [7], strlen (param_string [7])) == 0){ sscanf (line, "%s %s\n", temp_string, aux_file); printf ("AUX file %s\n", aux_file); } else if (strncmp (line, param_string [8], strlen (param_string [8])) == 0){ sscanf (line, "%s %s\n", temp_string, curvature_file); printf ("Curvature file %s\n", curvature_file); } else if (strncmp (line, param_string [9], strlen (param_string [9])) == 0){ sscanf (line, "%s %s\n", temp_string, area2D_file); printf ("2D Area file %s\n", area2D_file); } else if (strncmp (line, param_string [10], strlen (param_string [10])) == 0){ sscanf (line, "%s %s\n", temp_string, area3D_file); printf ("3D Area file %s\n", area3D_file); } else if (strncmp (line, param_string [11], strlen (param_string [11])) == 0){ sscanf (line, "%s %s\n", temp_string, projcells_file); printf ("Cell Projection file %s\n", projcells_file); } } } if (strlen (surface [snum].off_file) > 0){ read_off_file (surface [snum].off_file, snum); read_cell_file (surface [snum].cell_file, snum); read_border_file (surface [snum].border_file, snum); match_points_to_triangles (snum); convert_off_file_new (snum); /*convert_off_file (snum);*/ num_sections = determine_num_sections (snum, distinct_z); printf ("%d: Number of sections %d, points %d\n", snum, num_sections, surface [snum].num_points); for (i = 0; i < surface [snum].num_points; i++){ surface [snum].points [i].section = determine_section_num (snum, surface [snum].points [i].pos [2], num_sections, distinct_z); /*printf ("\t%d %d\n", i, surface [snum].points [i].section);*/ } /*write_coord_file (surface [snum].off_file, snum); write_sort_file (surface [snum].off_file, snum);*/ } else{ int flag1, flag2; read_coord_file (surface [snum].coord_file, snum); read_curvature_file (curvature_file, snum); read_projcells_file (projcells_file, snum); /*read_surface_file (surface [snum].coord_file, snum);*/ read_3Dcoord_file (surface [snum].coord3D_file, snum); read_sort_file (surface [snum].sort_file, snum); read_aux_file (aux_file, snum); read_border_file (surface [snum].border_file, snum); /*read_anat_boundaries_file (surface [snum].border_file, snum);*/ /*read_ascii_border_file (surface [snum].border_file, snum);*/ read_cell_file (surface [snum].cell_file, snum); read_polygon_file (surface [snum].polygon_file, snum); flag1 = read_2Darea_file (area2D_file, snum); flag2 = read_3Darea_file (area3D_file, snum); if ((flag1 == True) && (flag2 == True)){ compute_distortion (snum); } num_sections = determine_num_sections (snum, distinct_z); printf ("%d: Number of sections %d, points %d\n", snum, num_sections, surface [snum].num_points); extract_sections (snum, num_sections, distinct_z); } find_section_extent (snum); /*translate_to_center_of_mass (snum);*/ find_surface_extent (snum); surface [snum].is_view = True; surface [snum].StateChanged = True; /*surface [snum].Object = glGenLists (1)*/ surface [snum].Object = snum+1; for (i = 0; i < 4; i++) for (j = 0; j < 4; j++) surface [snum].matrix [i][j] = (i == j) ? 1.0 : 0.0; printf ("Surface %d has object %d\n", snum, surface [snum].Object); num_surfaces++; } void write_border_file (char *file, int snum) { FILE *fp; int i, j, n; char newfile [100]; sprintf (newfile, "%s.borders", file); if ((fp = fopen (newfile, "w")) == NULL){; printf ("ERROR: (write_border_file) could not open file %s\n", newfile); return; } fprintf (fp, "%d\n", surface [snum].NumBorders); printf ("%d borders to write to %s...\n", surface [snum].NumBorders, newfile); for (i = 0; i < surface [snum].NumBorders; i++){ fprintf (fp, "%d %d\n", i, surface [snum].borders [i].num_links); for (j = 0; j < surface [snum].borders [i].num_links; j++){ n = surface [snum].borders [i].links [j], fprintf (fp, "%d %d %d %d\n", j, surface [snum].borders [i].links [j], surface [snum].points [n].section, surface [snum].points [n].point); /*fprintf (fp, "%d %d %d %d %f %f %f\n", j, surface [snum].borders [i].links [j], surface [snum].points [n].section, surface [snum].points [n].point, surface [snum].points [n].pos [0], surface [snum].points [n].pos [1], surface [snum].points [n].pos [2]);*/ } } fclose (fp); } void read_ascii_border_file (char *file, int snum) { FILE *fp; int i, j; int t1, t2, t3, t4; int t5, t6; char s1 [5]; if ((fp = fopen (file, "r")) == NULL){; printf ("ERROR: (read_ascii_border_file) could not open file %s\n", file); return; } fscanf (fp, "%d", &surface [snum].NumBorders); if (surface [snum].NumBorders > MAX_BORDERS){ printf ("ERROR: %d Exceeded max # of borders %d\n", surface [snum].NumBorders, MAX_BORDERS); exit (-1); } printf ("%d borders to read from %s...\n", surface [snum].NumBorders, file); for (i = 0; i < surface [snum].NumBorders; i++){ fscanf (fp, "%d %s %d", &t1, s1, &t2); surface [snum].borders [i].num_links = t2; if (surface [snum].borders [i].num_links > MAX_BORDER_LENGTH){ printf ("ERROR: %d Exceeded max # of borders %d\n", t2, MAX_BORDER_LENGTH); exit (-1); } t5 = 0; for (j = 0; j < surface [snum].borders [i].num_links; j++){ fscanf (fp, "%d %d %d", &t1, &t3, &t4); /*if ((t3+1) == 85) t3 = 0;*/ t2 = find_point (snum, t3, t4); if (t2 > 0) surface [snum].borders [i].links [t5++] = t2; } surface [snum].borders [i].num_links = t5; } fclose (fp); } void read_border_file (char *file, int snum) { FILE *fp; int i, j; int t1, t2, t3, t4; int t5, t6; float f [3], dist; if ((fp = fopen (file, "r")) == NULL){; printf ("ERROR: (read_border_file) could not open file %s\n", file); return; } fscanf (fp, "%d", &surface [snum].NumBorders); if (surface [snum].NumBorders > MAX_BORDERS){ printf ("ERROR: %d Exceeded max # of borders %d\n", surface [snum].NumBorders, MAX_BORDERS); exit (-1); } printf ("%d borders to read from %s...\n", surface [snum].NumBorders, file); for (i = 0; i < surface [snum].NumBorders; i++){ fscanf (fp, "%d %d", &t1, &t2); surface [snum].borders [i].num_links = t2; if (surface [snum].borders [i].num_links > MAX_BORDER_LENGTH){ printf ("ERROR: %d Exceeded max # of borders %d\n", t2, MAX_BORDER_LENGTH); exit (-1); } t5 = 0; for (j = 0; j < surface [snum].borders [i].num_links; j++){ fscanf (fp, "%d %d %d %d", &t1, &t2, &t3, &t4); /*fscanf (fp, "%d %d %d %d %f %f %f", &t1, &t2, &t3, &t4, &f [0], &f [1], &f [2]);*/ /*t2 = find_point_using_pos (snum, f);*/ /*t2 = find_closest_point (snum, f, &dist);*/ /*if ((t3+1) == 85) t3 = 0; t2 = find_point (snum, t3+1, t4); if (t2 > 0)*/ surface [snum].borders [i].links [t5++] = t2; } surface [snum].borders [i].num_links = t5; } fclose (fp); } read_cell_file (char *file, int snum) { int i, j; char line [MAXLINE]; int t1, t2, t3; char s1 [5], s2 [5]; float f1, f2, f3; FILE *fp; int num, num_cells; if ((fp = fopen (file, "r")) == NULL){; printf ("ERROR: (read_cell_file) could not open file %s\n", file); return; } fscanf (fp, "%d", &surface [snum].NumCells); if (surface [snum].NumCells > MAX_CELLS){ printf ("ERROR: %d Exceeded max # of cells %d\n", surface [snum].NumCells, MAX_CELLS); exit (-1); } printf ("%d cells to read from %s...\n", surface [snum].NumCells, file); num_cells = 0; for (i = 0; i < surface [snum].NumCells; i++){ fgets (line, MAXLINE, fp); num = sscanf (line, "%d %d %d %s %s %f %f %f", &t1, &t2, &t3, s1, s2, &f1, &f2, &f3); if (num != 8){ /* We don't want to use this info */ printf ("WARNING: Ignore line %d, %d entries\n", i, num); } else{ strcpy (surface [snum].cells [num_cells].area1, s1); strcpy (surface [snum].cells [num_cells].area2, s2); surface [snum].cells [num_cells].display_flag = True; surface [snum].cells [num_cells].section = t2; surface [snum].cells [num_cells].point = t3; surface [snum].cells [num_cells].pos [0] = f1; surface [snum].cells [num_cells].pos [1] = f2; surface [snum].cells [num_cells].pos [2] = f3; if (((strcmp (s1, "E")) != 0) && (strcmp (s2, "PRP")) != 0) num_cells++; } } fclose (fp); surface [snum].NumCells = num_cells; printf ("\n%d CELLS used for Areal Borders...\n", surface [snum].NumCells); /*#define MAP_3D_TO_2D*/ #ifdef MAP_3D_TO_2D /* Now find the points on the surface based on position */ /* SPECIAL CASE FOR FINDING 79-O BORDERS! 1.12.95 */ { int i, j, t1; printf ("79-O: Mapping 3D areal borders onto surface...\n"); for (i = 0; i < surface [snum].NumCells; i++){ if ((i % 50) == 0) printf ("\tCell %d (%d %d) %s %s\n", i, surface [snum].cells [i].section, surface [snum].cells [i].point, surface [snum].cells [i].area1, surface [snum].cells [i].area2); t1 = find_point (snum, surface [snum].cells [i].section, surface [snum].cells [i].point); for (j = 0; j < 3; j++) surface [snum].cells [i].pos [j] = surface [snum].points [t1].pos [j]; } /*write_cell_file ("dve79.cells", 0);*/ } #endif /*#define CREATE_AREAL_NEW*/ #ifdef CREATE_AREAL_NEW /* Now find the points on the surface based on position */ /* SPECIAL CASE FOR FINDING 79-O BORDERS! 1.12.95 */ { int i, j; float dist; int closest; printf ("79-O: Creating areal.new file...\n"); for (i = 0; i < surface [snum].NumCells; i++){ if ((i % 10) == 0) printf ("\tCell %d (%d %d) %s %s\n", i, surface [snum].cells [i].section, surface [snum].cells [i].point, surface [snum].cells [i].area1, surface [snum].cells [i].area2); closest = find_closest_point (snum, surface [snum].cells [i].pos, &dist); /*printf ("\tOLD: %.2f %.2f %.2f\n", surface [snum].cells [i].pos [0], surface [snum].cells [i].pos [1], surface [snum].cells [i].pos [2]); printf ("\tCLS: %4d %.2f %.2f %.2f\n", closest, surface [snum].points [closest].pos [0], surface [snum].points [closest].pos [1], surface [snum].points [closest].pos [2]);*/ surface [snum].cells [i].section = surface [snum].points [closest].section; surface [snum].cells [i].point = surface [snum].points [closest].point; for (j = 0; j < 3; j++) surface [snum].cells [i].pos [j] = surface [snum].points [closest].pos [j]; } write_cell_file ("areal.new", 0); } #endif } write_cell_file (char *file, int snum) { int i; FILE *fp; char newfile [100]; sprintf (newfile, "%s.cells", file); if ((fp = fopen (newfile, "w")) == NULL){; printf ("ERROR: (write_cell_file) could not open file %s\n", newfile); return; } fprintf (fp, "%d\n", surface [snum].NumCells); printf ("%d cells to write to %s...\n", surface [snum].NumCells, newfile); for (i = 0; i < surface [snum].NumCells; i++){ fprintf (fp, "%d %d %d %s %s %f %f %f\n", i, surface [snum].cells [i].section, surface [snum].cells [i].point, surface [snum].cells [i].area1, surface [snum].cells [i].area2, surface [snum].cells [i].pos [0], surface [snum].cells [i].pos [1], surface [snum].cells [i].pos [2]); } fclose (fp); } void write_polygon_file (); void read_polygon_file (char *filename, int snum) { int i, i1, i2, i3; FILE *fp; if ((fp = fopen (filename, "r")) == NULL){; printf ("ERROR: (read_polygon_file) could not open file %s\n", filename); return; } fscanf (fp, "%d", &surface [snum].NumPolygons); printf ("%d polygons to read from polygon file %s...\n", surface [snum].NumPolygons, filename); if (surface [snum].NumPolygons > MAX_POLYS){ printf ("ERROR: %d Exceeded max # of polygons %d\n", surface [snum].NumPolygons, MAX_POLYS); exit (-1); } for (i = 0; i < surface [snum].NumPolygons; i++){ if ((i % 10000) == 0) printf ("\t%5d of %5d\n", i, surface [snum].NumPolygons); fscanf (fp, "%d %d %d", &i1, &i2, &i3); surface [snum].tiles [i].triangle [0] = i1; surface [snum].tiles [i].triangle [1] = i2; surface [snum].tiles [i].triangle [2] = i3; } fclose (fp); /*normal_constistency_check (snum); write_polygon_file ("newpoly", snum);*/ compute_normals (snum); /*check_triangles (snum);*/ } void write_polygon_file (char *filename, int snum) { int i, i1, i2, i3; FILE *fp; char newfile [100]; sprintf (newfile, "%s.polygons", filename); if ((fp = fopen (newfile, "w")) == NULL){; printf ("ERROR: (write_polygon_file) could not open file %s\n", newfile); return; } fprintf (fp, "%d\n", surface [snum].NumPolygons); printf ("%d polygons to write to polygon file %s...\n", surface [snum].NumPolygons, newfile); for (i = 0; i < surface [snum].NumPolygons; i++){ fprintf (fp, "%d %d %d\n", surface [snum].tiles [i].triangle [0], surface [snum].tiles [i].triangle [1], surface [snum].tiles [i].triangle [2]); } fclose (fp); } void read_3Dcoord_file (char *filename, int snum) { FILE *fp; int i, j; float f1, f2, f3; int i1, i2, i3, i4, i5, i6; char s1 [5]; if ((fp = fopen (filename, "r")) == NULL){; printf ("ERROR: (read_3Dcoord_file) could not open file %s\n", filename); return; } fscanf (fp, "%d", &i1); if (i1 != surface [snum].num_points) printf ("WARNING: Number of points in 3D %d file does not correspond %d\n", i1, surface [snum].num_points); printf ("%d points to read from 3D coord %s...\n", i1, filename); if (i1 > MAX_POINTS){ printf ("ERROR: %d Exceeded max # of points %d\n", i1, MAX_POINTS); return; } for (i = 0; i < surface [snum].num_points; i++){ if ((i % 5000) == 0) printf ("\t%5d of %5d\n", i, surface [snum].num_points); /*fscanf (fp, "%d %f %f %f", &i1, &f1, &f2, &f3);*/ fscanf (fp, "%d %f %f %f %d %d %d %d %s %d %d", &i1, &f1, &f2, &f3, &i1, &i2, &i3, &i4, s1, &i5, &i6); surface [snum].points [i].pos3D [0] = f1; surface [snum].points [i].pos3D [1] = f2; surface [snum].points [i].pos3D [2] = f3; } fclose (fp); } void read_off_file (char *file, int snum) { int i; float tf1, tf2, tf3; FILE *fp; char line [100]; int temp; printf ("Reading file %s...\n", file); if ((fp = fopen (file, "r")) == NULL){; printf ("ERROR: (read_file) could not open file %s\n", file); exit (-1); } fgets (line, MAXLINE, fp); fgets (line, MAXLINE, fp); fgets (line, MAXLINE, fp); fgets (line, MAXLINE, fp); fgets (line, MAXLINE, fp); fgets (line, MAXLINE, fp); sscanf (line, "%d %d %d", &surface [snum].num_points, &surface [snum].NumPolygons, &temp); printf ("%d vertices, %d triangles\n", surface [snum].num_points, surface [snum].NumPolygons); if (surface [snum].num_points > MAX_POINTS){ printf ("ERROR: Exceeded MAX_POINTS %d points\n", MAX_POINTS); exit (-1); } if (surface [snum].NumPolygons > MAX_POLYS){ printf ("ERROR: Exceeded max # of triangles %d\n", MAX_POLYS); exit (-1); } for (i = 0; i < surface [snum].num_points; i++){ if ((i % 5000) == 0) printf ("\t%5d of %5d\n", i, surface [snum].num_points); fgets (line, MAXLINE, fp); sscanf (line, "%f %f %f %f %f %f", &surface [snum].points [i].pos [0], &surface [snum].points [i].pos [1], &surface [snum].points [i].pos [2], &surface [snum].points [i].normal [0], &surface [snum].points [i].normal [1], &surface [snum].points [i].normal [2]); } for (i = 0; i < surface [snum].NumPolygons; i++){ if ((i % 10000) == 0) printf ("\t%5d of %5d\n", i, surface [snum].NumPolygons); fgets (line, MAXLINE, fp); sscanf (line, "%d %d %d %d", &temp, &surface [snum].tiles [i].triangle [0], &surface [snum].tiles [i].triangle [1], &surface [snum].tiles [i].triangle [2]); } } void convert_off_file_new (int snum) { int i, j, k; int temp_neighbors [MAX_NEIGHS]; int num, p0, p1, p2; printf ("Converting OFF file...\n"); for (i = 0; i < surface [snum].num_points; i++){ if ((i % 5000) == 0) printf ("\tpoint %5d of %5d\n", i, surface [snum].num_points); surface [snum].points [i].num_neighs = 0; num = 0; for (k = 0; k < pt_tris [i].num_tris; k++){ j = pt_tris [i].tris [k]; p0 = surface [snum].tiles [j].triangle [0]; p1 = surface [snum].tiles [j].triangle [1]; p2 = surface [snum].tiles [j].triangle [2]; /*printf ("\t%d: %d %d %d\n", i, p0, p1, p2);*/ if (p0 == i){ if ((is_neighbor (p1, num, temp_neighbors)) == False){ temp_neighbors [num++] = p1; } if ((is_neighbor (p2, num, temp_neighbors)) == False){ temp_neighbors [num++] = p2; } } if (p1 == i){ if ((is_neighbor (p0, num, temp_neighbors)) == False){ temp_neighbors [num++] = p0; } if ((is_neighbor (p2, num, temp_neighbors)) == False){ temp_neighbors [num++] = p2; } } if (p2 == i){ if ((is_neighbor (p0, num, temp_neighbors)) == False){ temp_neighbors [num++] = p0; } if ((is_neighbor (p1, num, temp_neighbors)) == False){ temp_neighbors [num++] = p1; } } } surface [snum].points [i].num_neighs = num; /*printf ("Point %d has %d neighs\n", i, num);*/ for (j = 0; j < surface [snum].points [i].num_neighs; j++){ surface [snum].points [i].neighs [j] = temp_neighbors [j]; /*printf ("\t%d %d\n", j, temp_neighbors [j]);*/ } } } void convert_off_file (int snum) { int i, j; int temp_neighbors [MAX_NEIGHS]; int num, p0, p1, p2; printf ("Converting OFF file...\n"); for (i = 0; i < surface [snum].num_points; i++){ if ((i % 500) == 0) printf ("\tpoint %5d of %5d\n", i, surface [snum].num_points); surface [snum].points [i].num_neighs = 0; num = 0; for (j = 0; j < surface [snum].NumPolygons; j++){ p0 = surface [snum].tiles [j].triangle [0]; p1 = surface [snum].tiles [j].triangle [1]; p2 = surface [snum].tiles [j].triangle [2]; /*printf ("\t%d: %d %d %d\n", i, p0, p1, p2);*/ if (p0 == i){ if ((is_neighbor (p1, num, temp_neighbors)) == False){ temp_neighbors [num++] = p1; } if ((is_neighbor (p2, num, temp_neighbors)) == False){ temp_neighbors [num++] = p2; } } if (p1 == i){ if ((is_neighbor (p0, num, temp_neighbors)) == False){ temp_neighbors [num++] = p0; } if ((is_neighbor (p2, num, temp_neighbors)) == False){ temp_neighbors [num++] = p2; } } if (p2 == i){ if ((is_neighbor (p0, num, temp_neighbors)) == False){ temp_neighbors [num++] = p0; } if ((is_neighbor (p1, num, temp_neighbors)) == False){ temp_neighbors [num++] = p1; } } } surface [snum].points [i].num_neighs = num; /*printf ("Point %d has %d neighs\n", i, num);*/ for (j = 0; j < surface [snum].points [i].num_neighs; j++){ surface [snum].points [i].neighs [j] = temp_neighbors [j]; /*printf ("\t%d %d\n", j, temp_neighbors [j]);*/ } } } int is_neighbor (idx, num, list) int idx, num; int *list; { int i; for (i = 0; i < num; i++){ if (list [i] == idx) return (True); } return (False); } int is_in_list (idx, num, list) int idx, num, *list; { int i; for (i = 0; i < num; i++){ if (list [i] == idx){ return (True); } } return (False); } int float_is_in_list (float val, int num, float *list) { int i; for (i = 0; i < num; i++){ if (list [i] == val) return (True); } return (False); } int determine_num_sections (int snum, float *distinct_z) { int num_z = 0; int i, pos; distinct_z [0] = surface [snum].points [0].pos [2]; /*printf ("%d %f\n", num_z, distinct_z [num_z]);*/ num_z++; for (i = 0; i < surface [snum].num_points; i++){ if (float_is_in_list (surface [snum].points [i].pos [2], num_z, distinct_z) == False){ distinct_z [num_z] = surface [snum].points [i].pos [2]; /*printf ("%d %f\n", num_z, distinct_z [num_z]);*/ num_z++; } } /*printf ("%d sections\n", num_z);*/ return (num_z); } void match_points_to_triangles (int snum) { int i, j; int v1, v2, v3; int n1, n2, n3; for (i = 0; i < surface [snum].num_points; i++) pt_tris [i].num_tris = 0; printf ("Assigning triangles to points...\n"); for (i = 0; i < surface [snum].NumPolygons; i++){ if ((i % 5000) == 0) printf ("\t%5d of %5d\n", i, surface [snum].NumPolygons); v1 = surface [snum].tiles [i].triangle [0]; v2 = surface [snum].tiles [i].triangle [1]; v3 = surface [snum].tiles [i].triangle [2]; n1 = pt_tris [v1].num_tris; n2 = pt_tris [v2].num_tris; n3 = pt_tris [v3].num_tris; if ((is_in_list (i, n1, pt_tris [v1].tris)) == False) pt_tris [v1].tris [n1] = i; if ((is_in_list (i, n2, pt_tris [v2].tris)) == False) pt_tris [v2].tris [n2] = i; if ((is_in_list (i, n3, pt_tris [v3].tris)) == False) pt_tris [v3].tris [n3] = i; pt_tris [v1].num_tris++; if (pt_tris [v1].num_tris > MAX_PT_TRIS){ printf ("ERROR: Point %d exceeds max # of tris %d\n", v1, MAX_PT_TRIS); for (j = 0; j < pt_tris [v1].num_tris; j++) printf ("\t%d %d\n", j, pt_tris [v1].tris [j]); exit (-1); } pt_tris [v2].num_tris++; if (pt_tris [v2].num_tris > MAX_PT_TRIS){ printf ("ERROR: Point %d exceeds max # of tris %d\n", v2, MAX_PT_TRIS); for (j = 0; j < pt_tris [v2].num_tris; j++) printf ("\t%d %d\n", j, pt_tris [v2].tris [j]); exit (-1); } pt_tris [v3].num_tris++; if (pt_tris [v3].num_tris > MAX_PT_TRIS){ printf ("ERROR: Point %d exceeds max # of tris %d\n", v3, MAX_PT_TRIS); for (j = 0; j < pt_tris [v3].num_tris; j++) printf ("\t%d %d\n", j, pt_tris [v3].tris [j]); exit (-1); } } } void read_aux_file (char *filename, int snum) { FILE *fp; int i, j; int i1, i2, i3, i4, i5, i6, i7, i8, i9, prev; char s1 [5]; if ((fp = fopen (filename, "r")) == NULL){; printf ("ERROR: (read_aux_file) could not open file %s\n", filename); return; } fscanf (fp, "%d", &i6); printf ("%d points to read from sort %s...\n", i6, filename); /*for (i = 0; i < i6; i++) strcpy (surface [snum].points [i].region, "HEM");*/ prev = i7 = 0; for (i = 0; i < i6; i++){ if ((i % 1000) == 0) printf ("\t%5d of %5d\n", i, i6); fscanf (fp, "%d %d %d %d %d %s", &i1, &i2, &i3, &i4, &i5, s1); prev = i7; i7 = find_point (snum, i3, i4, prev); /*printf ("New %d %d (%d,%d) gets %s\n", i, i7, i3, i4, s1);*/ strcpy (surface [snum].points [i7].region, s1); for (j = 0; j < i2; j++){ fscanf (fp, "%d %d", &i8, &i9); } } fclose (fp); } void read_projcells_file (char *filename, int snum) { FILE *fp; int i, i1; float f1; if ((fp = fopen (filename, "r")) == NULL){; printf ("ERROR: (read_projcells_file) could not open file %s\n", filename); return; } for (i = 0; i < surface [snum].num_points; i++){ if ((i % 10000) == 0) printf ("\t%5d of %5d\n", i, surface [snum].num_points); fscanf (fp, "%d %f", &i1, &f1); surface [snum].points [i].projcells = f1; } fclose (fp); } void read_curvature_file (char *filename, int snum) { FILE *fp; int i, i1; float f1; if ((fp = fopen (filename, "r")) == NULL){; printf ("ERROR: (read_curvature_file) could not open file %s\n", filename); return; } for (i = 0; i < surface [snum].num_points; i++){ if ((i % 10000) == 0) printf ("\t%5d of %5d\n", i, surface [snum].num_points); fscanf (fp, "%d %f", &i1, &f1); surface [snum].points [i].curvature = f1; /*printf ("%d %f", i, surface [snum].points [i].curvature); */ } fclose (fp); } int read_2Darea_file (char *filename, int snum) { FILE *fp; int i, i1; float f1; if ((fp = fopen (filename, "r")) == NULL){; printf ("ERROR: (read_2Darea_file) could not open file %s\n", filename); return (False); } printf ("Read 2D areas from %s\n", filename); for (i = 0; i < surface [snum].NumPolygons; i++){ if ((i % 10000) == 0) printf ("\t%5d of %5d\n", i, surface [snum].num_points); fscanf (fp, "%d %f", &i1, &f1); surface [snum].tiles [i].area2D = f1; } fclose (fp); return (True); } int read_3Darea_file (char *filename, int snum) { FILE *fp; int i, i1; float f1; if ((fp = fopen (filename, "r")) == NULL){; printf ("ERROR: (read_3Darea_file) could not open file %s\n", filename); return (False); } printf ("Read 3D areas from %s\n", filename); for (i = 0; i < surface [snum].NumPolygons; i++){ if ((i % 10000) == 0) printf ("\t%5d of %5d\n", i, surface [snum].num_points); fscanf (fp, "%d %f", &i1, &f1); surface [snum].tiles [i].area3D = f1; } fclose (fp); return (True); } void read_anat_boundaries_file (char *file, int snum) { char line [100]; FILE *fp; int t1, t2, t3; int i, j, pt; char name [MAXLINE]; int cur; printf ("Attempting to read ANAT boundaries file: %s\n", file); if ((fp = fopen (file, "r")) == NULL){; printf ("ERROR: (read_anat_boundaries_file) could not open file %s\n", file); return; } cur = surface [snum].NumBorders = 0; while (fgets (line, MAXLINE, fp) != NULL){ sscanf (line, "%d %s %d", &t1, name, &t2); printf ("Border %d %s %d\n", t1, name, t2); surface [snum].borders [cur].num_links = t2; for (i = 0; i < surface [snum].borders [cur].num_links; i++){ fgets (line, MAXLINE, fp); sscanf (line, "%d %d %d", &t1, &t2, &t3); pt = find_point (snum, t2-1, t3); printf ("\t%d %d %d -> %d\n", t1, t2-1, t3, pt); /*pt = find_point (t2-1, t3);*/ if (pt < 0){ printf ("WARNING: Can't find point %d,%d in structure\n", t2, t3); exit (-1); } surface [snum].borders [cur].links [i] = pt; } cur++; if (cur > MAX_BORDERS){ printf ("ERROR: Exceeded MAX_BORDERS %d\n", MAX_BORDERS); exit (-1); } } surface [snum].NumBorders = cur; printf ("\n%d boundaries read...\n", surface [snum].NumBorders); } void extract_sections (int snum, int num_sections, float *distinct_z) { int i, sec, num; surface [snum].NumSections = num_sections; if (surface [snum].NumSections > MAX_SECTIONS){ printf ("ERROR: Exceeded MAX # of sections %d (%d)\n", MAX_SECTIONS, surface [snum].NumSections); exit (-1); } for (i = 0; i < surface [snum].num_points; i++){ sec = surface [snum].points [i].section; num = surface [snum].sections [sec].num_points; surface [snum].sections [sec].points [num] = i; surface [snum].sections [sec].num_points++; } for (i = 0; i < surface [snum].NumSections; i++) printf ("Section %4d: %4d points\n", i, surface [snum].sections [i].num_points); } int determine_num_contours (int snum, int sect, int *npoints) { int i; int idx, prev = -1, num_contours = 0; idx = surface [snum].sections [sect].points [0]; prev = surface [snum].points [idx].contour; npoints [num_contours] = 0; for (i = 0; i < surface [snum].sections [sect].num_points; i++){ idx = surface [snum].sections [sect].points [i]; if (surface [snum].points [prev].contour != surface [snum].points [idx].contour){ prev = idx; num_contours++; npoints [num_contours] = 0; } npoints [num_contours]++; } num_contours++; return (num_contours); } caret-5.6.4~dfsg.1.orig/flat_fluid/surface_defs.h0000664000175000017500000000213011572067322021470 0ustar michaelmichaeltypedef unsigned char GLbyte; typedef unsigned int GLuint; #define MAX_NEIGHS 20 #define MAX_POINTS 60000 #define MAX_SECTIONS 200 #define MAX_SECTION_POINTS 5000 #define MAX_SURFACES 2 #define MAXLINE 200 #define MAX_BORDER_LENGTH 100 #define MAX_BORDERS 100 #define MAX_CELLS 1 #define MAX_POLYS MAX_POINTS*2 #define True 1 #define False 0 #define VIEWING_MODE 0 #define INSERT_MODE 1 #define DELETE_ALL_MODE 2 #define DELETE_LINK_MODE 3 #define BORDER_ADD_MODE 4 #define BORDER_DELETE_MODE 5 #define BORDER_FILL_MODE 6 #define ID_MODE 7 #define BORDER_DELETE_LINK_MODE 8 #define MAXSELECT 100 #define PI 3.141593 #define DISP_POINT 1 #define DISP_LINKS 2 #define DISP_FILLED 4 #define DISP_SPHERE 8 #define DISP_BORDERS 16 #define DISP_CELLS 32 #define DISP_AREAS 64 #define DISP_CURVATURE 128 #define DISP_DISTORTION 256 #define DISP_PROJECT_CELLS 512 #define CELL_POINT 0 #define CELL_SPHERE 1 caret-5.6.4~dfsg.1.orig/flat_fluid/surface.h0000664000175000017500000000251611572067322020477 0ustar michaelmichael #include "surface_defs.h" typedef struct{ float pos3D [3]; float pos [3]; float normal [3]; short num_neighs; short num_tris; int neighs [MAX_NEIGHS]; int section, point, contour, class, Index; char region [5]; GLbyte colors [3]; float curvature, projcells, distortion; GLuint display_flag; }Point2; typedef struct{ int num_links; int links [MAX_BORDER_LENGTH]; }Border; typedef struct{ int section, point; char area1 [5], area2 [5]; float pos [3]; GLbyte colors [3]; short display_flag; }Cell; typedef struct{ int triangle [3]; int visited; float area3D, area2D, distortion; }Poly; typedef struct{ int num_points; int points [MAX_SECTION_POINTS]; int num_contours; }Section; struct Surface{ int StateChanged; GLuint Object; float matrix [4][4]; char coord_file [MAXLINE]; char coord3D_file [MAXLINE]; char sort_file [MAXLINE]; char border_file [MAXLINE]; char cell_file [MAXLINE]; char polygon_file [MAXLINE]; char off_file [MAXLINE]; int is_view; int lo_section, hi_section; float minx, maxx; float miny, maxy; float minz, maxz; int num_points; Point2 points [MAX_POINTS]; int NumBorders; Border borders [MAX_BORDERS]; int NumCells; Cell cells [MAX_CELLS]; int NumPolygons; Poly tiles [MAX_POLYS]; int NumSections; Section sections [MAX_SECTIONS]; }surface [MAX_SURFACES]; caret-5.6.4~dfsg.1.orig/flat_fluid/resamp.c0000664000175000017500000000542011572067322020326 0ustar michaelmichael#include #include double dist (double,double,double,double); void resample_line (double *xorig, double *yorig, int totpoints, double *xout, double *yout, double ddd, int *numpoint, int flag) { int i, j, k, l; double totdist, dj, dj1; double x1, y1, frac; if (flag == 1) { totdist = 0.0; for (i = 1; i < totpoints; i++) totdist += dist (xorig [i], yorig [i], xorig [i-1], yorig [i-1]); ddd = totdist/(*numpoint-1); printf ("\tTotal distance of segment is %.2f, avg distance %.2f, numpoint %d\n", totdist, ddd, *numpoint); printf ("\tCOMPUTE %d points...\n", *numpoint); } else if (flag == 0){ totdist = 0.0; for (i = 1; i < totpoints; i++) totdist += dist (xorig [i], yorig [i], xorig [i-1], yorig [i-1]); *numpoint = totdist/ddd + 1; printf ("Total distance of segment is %.2f, avg distance %.2f, numpoint %d\n", totdist, ddd, *numpoint); printf ("\tCOMPUTE points that are %.2f away...\n", ddd); } /* Now find the next point dist away from the previous point */ xout [0] = xorig [0]; yout [0] = yorig [0]; j = 0; /* index of the points processed */ for (i = 0; i < *numpoint-1; i++){ x1 = xout [i]; y1 = yout [i]; dj1 = 0; dj = dist (x1, y1, xorig [j], yorig [j]); /*printf ("Find next point after %.2f %.2f that is %.2f away...\n", x1, y1, ddd); */ k = j; /* find the distance to the jth point */ while (dj < ddd){ /*printf ("\t\t\tloop: j %d, dj %.2f, dj1 %.2f\n", j, dj, dj1);*/ dj1 = dj; dj = dj+dist (xorig [j], yorig [j], xorig [j+1], yorig [j+1]); j++; } /* The new point lies in the jth segment */ frac = (ddd - dj1)/(dj-dj1); /*printf ("\t\tj is %d, dj1 is %.2f, dj is %.2f, ddd %.2f, frac %.2f\n", j, dj1, dj, ddd, frac);*/ if (k != j) { x1 = xorig [j-1]; y1 = yorig [j-1]; } /*printf ("\t\tCompute location betwen %.2f %.2f and %.2f %.2f\n", x1, y1, xorig [j], yorig [j]);*/ xout [i+1] = (1-frac)*x1 + frac*xorig[j]; yout [i+1] = (1-frac)*y1 + frac*yorig[j]; /*printf ("\t%d %d %d, %.2f %.2f -> %.2f %.2f, dist %.2f\n", i, k, j, xout [i], yout [i], xout [i+1], yout [i+1], dist (xout [i], yout [i], xout [i+1], yout [i+1]));*/ } /**numpoint = i-1;*/ /*printf ("%d points...\n", *numpoint); for (i = 1; i < *numpoint; i++){ printf ("\t\t%d: %.2f %.2f, dist %.2f\n",i, xout [i],yout [i], totdist); totdist = dist (xout [i], yout [i], xout [i-1], yout [i-1]); }*/ } double dist (double x1,double y1,double x2,double y2) { double d; double xdiff, ydiff; xdiff = x2-x1; ydiff = y2-y1; /*d = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));*/ d = sqrt ((xdiff*xdiff)+(ydiff*ydiff)); /*printf ("\tDIST: %.2f %.2f, answer %f\n", xdiff, ydiff, d);*/ return(d); } caret-5.6.4~dfsg.1.orig/flat_fluid/flat_fluid.c0000664000175000017500000020057611572067322021161 0ustar michaelmichael#include #include #include #ifdef MAC_OSX_SYSTEM #include #endif #ifdef HAVE_IRISGL #include #include #endif /* HAVE_IRISGL */ static float SCALE_FACTOR = 1.0; // JWH 14 Mar 2006 #define FLUID_METHOD #define FLUID 1 #define IMAGE_SCALE #ifdef IMAGE_SCALE #define EXTENT 200.0 double left = 0, right = EXTENT, bottom = 0, top = EXTENT, near = 100.0, far = -100.0; float DIM = 0.25; #else #define EXTENT 300.0 double left = -EXTENT, right = EXTENT, bottom = -EXTENT, top = EXTENT, near = 150.0, far = -150.0; float DIM = 0.25; #endif int xsize = 200, ysize = 200; static const float DEFAULT_SAMPLING_DENSITY = 20.0; static const float DEFAULT_VARIANCE = 1.0; #define NUM_POINTS 20 #define LINES #ifdef HAVE_IRISGL #define DISPLAY #endif /* #define MAX_FIDUCIAL_POINTS 5000 */ #define MAX_FIDUCIAL_POINTS 500 /* #define MAX_SULCI 1000 */ #define MAX_SULCI 10000 #define NEW_BORDERS /*#define READ_CELL_FILE */ /* comment out IMAGE_SCALE */ /*#define READ_COORD_FILE*/ #define READ_BORDER_FILE #ifdef READ_CELL_FILE #define MAX_NUM_CELLS 50000 #endif #define MAXLINE 256 #include "surface.h" void DisplaySurface (short new, int snum); void DisplayDeform (short new, int snum, int flag); void DisplayTotalDeform (short new, int snum, int flag); void DisplaySulci (short new, int snum, int flag); void DisplaySulci2 (short new, int snum, int flag); int get_lut_index (int snum, float value, float dmin, float dmax); void read_lut_file (); void determine_min_max (int num, float *array, float *min, float *max); float DetermineVariance (char *name, float var); void DisplayImage (short, int, unsigned char*); void DisplayDeformedImage (short new, unsigned char *image); void LAPACK_stuff (double *mat, double *x1, double *y1, double *iwtx, double *iwty); void ReadCellFile (char *file); void WriteCellFile (char *file); void CreateSurface (int width, int height, int spacing); void ImageInitStuff (char *filename, int xsize, int ysize); void ComputeDeformationFLUID (int step, double x0, double y0, double *defx, double *defy); void ResampleData (); void CreateGridImage (char *image, int xsize, int ysize); void WriteImage (char *file, char *inimage, int xsize, int ysize); void DeformImage (int ixsize, int iysize, int deform_flag); double ImageX2Transform (double val); double ImageY2Transform (double val); int num_surfaces = 1; #define byte unsigned char #define ABS(x) ((x) >= 0 ? (x) : -(x)) #define max(A, B) ((A) > (B) ? (A) : (B)) #define min(A, B) ((A) > (B) ? (B) : (A)) int totpoints; int dim; double origX1 [MAX_FIDUCIAL_POINTS], origY1 [MAX_FIDUCIAL_POINTS]; double origX2 [MAX_FIDUCIAL_POINTS], origY2 [MAX_FIDUCIAL_POINTS]; #ifdef READ_CELL_FILE typedef struct{ int section, point; char area1 [MAXLINE], area2 [MAXLINE]; float pos [3]; }Cells; int NumCells; Cells cells [MAX_NUM_CELLS]; #endif typedef struct{ double x [MAX_FIDUCIAL_POINTS], y [MAX_FIDUCIAL_POINTS]; float ddd; float variance; int np; int hold_np; char name [MAXLINE]; }Sulcus; Sulcus sulci [4][MAX_SULCI]; typedef struct{ char name [MAXLINE]; float var_factor; }SulciVar; #define NUM_SULCI_TYPE 21 SulciVar sulcivar [NUM_SULCI_TYPE] = { {"MORPH.A", 0.01}, {"MORPH.B", 0.01}, {"MORPH.C", 0.01}, {"MORPH.D", 0.01}, {"MORPH.E", 0.01}, {"MORPH.F", 0.01}, {"MORPH.G", 0.01}, {"MORPH.H", 0.01}, {"MORPH.I", 0.01}, {"MORPH.Cis", 0.25}, {"MORPH.Ces", 0.25}, {"MORPH.IPS", 0.25}, {"MORPH.POS", 0.25}, {"MORPH.IOS", 0.25}, {"MORPH.OTS", 0.25}, {"MORPH.SF1", 0.25}, {"MORPH.SF2", 0.25}, {"MORPH.AS", 0.25}, {"MORPH.PS", 0.25}, {"MORPH.STS", 0.25}, {"MORPH.MOS", 0.25} }; double newX1 [MAX_FIDUCIAL_POINTS], newY1 [MAX_FIDUCIAL_POINTS]; char name [MAX_FIDUCIAL_POINTS][MAXLINE]; float displace [2][MAX_POINTS]; float total_displace [2][MAX_POINTS]; char *inimage, *outimage, *def_out; float *image_xdeform; float *image_ydeform; int ixsize, iysize; void ReadPoints (char *file, int *num_sulci, int idx); void WritePoints (char *file, int num_sulci, int idx); int find_sulcus (int num, char *name, int idx); double dist (double x1, double y1, double x2, double y2); #define NUMT 10 #define graphics 0 #ifdef HAVE_IRISGL Matrix Identity = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 }; #endif /* HAVE_IRISGL */ double X1 [MAX_FIDUCIAL_POINTS], Y1 [MAX_FIDUCIAL_POINTS]; double X2 [MAX_FIDUCIAL_POINTS], Y2 [MAX_FIDUCIAL_POINTS], VAR [MAX_FIDUCIAL_POINTS]; double pathx [NUMT][5000]; double pathy [NUMT][5000]; double *deformx; double *deformy; void findpath (double *X1,double *Y1,double *X2,double *Y2, int totpoints); void calculate_weightsFLUID (int totpoints, int dim, double *mat, double *X1, double *Y1, double *X2, double *Y2); double TransformY2Image (double val); double TransformX2Image (double val); /* The weights Of each of the greens functions at the points */ double wtx [MAX_FIDUCIAL_POINTS], wty [MAX_FIDUCIAL_POINTS]; int n1, n2, n3 = 0, n4; double beta; float var_mult; double alpha = 0.001; /*double sigma = 1.0;*/ int numiter; short val; long device, done; FILE *fd_iter; double *mat; /* the matrix of linear equation */ /* Surface stuff. HAD 5.9.95 */ int snum = 0; int main (int argc, char *argv[]) { int iter; double l1,l2,l3,l4; double tmp1, tmp2; int flag,i,ret_val,j,k,l; int doImageWarping = 0; /* JWH 12/05/00 */ /* Now the stuff to do the actual deformation */ double x,y,z; double ux,uy,uz; /* Displacement FIELD */ int tmpux,tmpuy; /* Displacement FIELD */ double xdelta,ydelta,tx,ty; FILE *fp, *fopen(); /* File pointer for the corespondance file */ FILE *fpin,*fpout; char out [100]; FILE *fdx, *fdy, *fdnew; float errorx = 0, errory = 0, t1, t2; int step; float min_ux, max_ux, min_uy, max_uy; float x0, y0; char s1 [10]; char imagefile [256], filename [256], outfile [256]; printf("Size of surface: %d\n", sizeof(surface)); printf("Size of sulci: %d\n", sizeof(sulci)); if (argc != 10){ printf ("USAGE: %s file1 file2 area_file beta var_mult numiter image xsize ysize\n", argv [0]); printf("If xsize or ysize is zero, no image will be displayed.\n"); exit(-1); } beta = atof (argv [4]); var_mult = atof (argv [5]); numiter = atoi (argv [6]); printf ("beta is %f\n", beta); printf ("var_mult is %f\n", var_mult); printf ("numiter is %d\n", numiter); #ifdef READ_COORD_FILE read_coord_file (argv [3], snum); /*read_sort_file (argv [4], snum);*/ #else #ifdef READ_CELL_FILE ReadCellFile (argv [3]); #else ReadPoints (argv [3], &n3, 2); #endif #endif /* n3 is areal borders */ ReadPoints (argv [1], &n1, 0); ReadPoints (argv [2], &n2, 1); ResampleData (); ixsize = atoi (argv [8]); iysize = atoi (argv [9]); if (argc >= 11) { SCALE_FACTOR = atof(argv[10]); } if ((ixsize > 0) && (iysize > 0)) { doImageWarping = 1; } if (doImageWarping) { ImageInitStuff ((char *)argv [7], ixsize, iysize); } /* Add 4 corner points */ /*X1 [totpoints] = 0; Y1 [totpoints] = 0; totpoints++; X1 [totpoints] = EXTENT; Y1 [totpoints] = EXTENT; totpoints++; X1 [totpoints] = EXTENT; Y1 [totpoints] = 0; totpoints++; X1 [totpoints] = 0; Y1 [totpoints] = EXTENT; totpoints++;*/ /* Alocate the memory for the mat */ dim = totpoints+3; mat = (double *)calloc(dim*dim,sizeof(double)); #ifdef DISPLAY read_lut_file (); DisplaySulci (True, snum, 0); DisplaySulci2 (True, snum, 0); if (doImageWarping) { DisplayDeformedImage (True, inimage); } #endif /*for (i = 0; i < totpoints; i++) printf ("DEFORM %.1f %.1f -> %.1f %.1f, variance %f\n", X1 [i], Y1 [i], X2 [i], Y2 [i], VAR [i]);*/ printf ("\n****FLUID Deformation method...\n\n"); deformx = (double *)calloc(totpoints,sizeof(double)); deformy = (double *)calloc(totpoints,sizeof(double)); findpath (X1,Y1,X2,Y2,totpoints); for(j=0;j= 0; step--){ printf ("Step %2d\n", step); calculate_weightsFLUID (totpoints, dim, mat, pathx[step+1], pathy[step+1], pathx[step], pathy[step]); /* Now deform the actual surface */ printf ("\tDeforming Surface %d points...\n", surface [snum].num_points); for (j = 0; j < surface [snum].num_points; j++){ if ((j % 10000) == 0) printf ("\t%5d of %5d\n", j, surface [snum].num_points); x0 = surface [snum].points [j].pos [0]; y0 = surface [snum].points [j].pos [1]; ComputeDeformationFLUID (step, x0, y0, &ux, &uy); surface [snum].points [j].pos [0] = x0 + ux; surface [snum].points [j].pos [1] = y0 + uy; /*printf ("DISPLACE: %d %f %d %f\n", j, ux, j, uy);*/ } #ifdef READ_COORD_FILE { char fname [256]; sprintf (fname, "surface.fluid.%d", step); write_coord_file (fname, snum); } #endif #ifdef READ_CELL_FILE /* Deform the cells */ printf ("\tDeforming %d cells...\n", NumCells); for (j = 0; j < NumCells; j++){ if ((j % 10000) == 0) printf ("\t%d of %d\n", j, NumCells); x0 = cells [j].pos [0]; y0 = cells [j].pos [1]; ComputeDeformationFLUID (step, x0, y0, &ux, &uy); cells [j].pos [0] = x0 + ux; cells [j].pos [1] = y0 + uy; } #else /* Deform the areal borders */ printf ("\tDeforming %d areal borders...\n", n3); for (j = 0; j < n3; j++){ /*printf ("Deforming areal border %d %s\n", j, sulci [2][j].name); */ for (i = 0; i < sulci [2][j].np; i++){ x0 = sulci [2][j].x [i]; y0 = sulci [2][j].y [i]; ComputeDeformationFLUID (step, x0, y0, &ux, &uy); sulci [2][j].x [i] = x0 + ux; sulci [2][j].y [i] = y0 + uy; /*printf ("\tAreal %.2f %.2f -> %.2f %.2f\n", x0, y0, x0 + ux, y0 + uy);*/ } } #endif /* Now test it on known points */ for (j = 0; j < totpoints; j++){ x0 = X2 [j]; y0 = Y2 [j]; ComputeDeformationFLUID (step, x0, y0, &ux, &uy); X2 [j] = x0 + ux; Y2 [j] = y0 + uy; } /* This is stupid, but it works. redundant (these are known points) */ /* HAD 6.13.96 */ for (i = 0; i < n4; i++){ /*printf ("Deform Sulcus %d %s, %d points\n", i, sulci [3][i].name, sulci [3][i].np); */ for (j = 0; j < sulci [3][i].np; j++){ x0 = sulci [3][i].x [j]; y0 = sulci [3][i].y [j]; ComputeDeformationFLUID (step, x0, y0, &ux, &uy); sulci [3][i].x [j] = x0 + ux; sulci [3][i].y [j] = y0 + uy; } } /*&&&*/ #ifdef DISPLAY DisplaySulci (False, snum, 0); DisplaySulci2 (False, snum, 0); sleep (1); #endif } /*printf("PathX PathY \n"); for(i=0;i 0.001) || (fabsf (tot2) > 0.001) || (fabsf (tot3) > 0.001)){ printf ("WARNING: Constraints not met!!\n"); printf("\tSum of weights = %lf\n",tot1); printf("\tSum of X1*weights = %lf\n",tot2); printf("\tSum of X1*wy = %lf\n",tot3); exit (-1); } } #ifdef HAVE_IRISGL Object SURFACE = 1; Object DEFORMX = 2; Object DEFORMY = 3; Object TARGET = 4; Object TEMPLATE = 5; Object TOTAL_DEFORMX = 6; Object TOTAL_DEFORMY = 7; #define max(a,b) ((a) > (b) ? (a) : (b)) #define min(a,b) ((a) < (b) ? (a) : (b)) #define abs(a) ((a) > 0.0 ? (a) : -(a)) #define sgn(a) ((a) < 0.0 ? -1.0 : 1.0) /* NB 0.0 -> 1.0 */ long surface_win, deformx_win, deformy_win, total_deformx_win, total_deformy_win, target_win, template_win, target_win2, winid1, winid2; char lut [256][4]; short white [3] = {200, 200, 200}; short black [3] = {0, 0, 0}; short red [3] = {255, 0, 0}; short green [3] = {0, 255, 0}; short blue [3] = {0, 0, 255}; short gray [3] = {100, 100, 100}; void DisplaySurface (short new, int snum) { int i, j, n; short val; int x_init = 880, y_init = 0; int x_size = xsize*2.0, y_size = ysize*2.0; #ifdef CALC left = bottom = surface [snum].points [0].pos [0]; right = top = surface [snum].points [0].pos [1]; for (i = 0; i < surface [snum].num_points; i++) { left = min(left, surface [snum].points [i].pos [0]); right = max(right, surface [snum].points [i].pos [0]); bottom = min(bottom, surface [snum].points [i].pos [1]); top = max(top, surface [snum].points[i].pos [1]); } /*left = left - left*0.10; right = right + right*0.10; bottom = bottom - bottom*0.10; top = top + top*0.10; */ printf ("Extent: X %.2f %.2f, Y %.2f %.2f\n", left, right, top, bottom); near = 100.0; far = -100.0; #endif if (new){ foreground (); keepaspect ((right-left),(top-bottom)); prefposition (x_init, x_init+x_size, y_init, y_init+y_size); surface_win = winopen ("Sulcal Warping Engine"); /*printf ("surface_win %x\n", surface_win);*/ RGBmode (); doublebuffer(); gconfig(); } /*printf ("set win to surface win %x\n", surface_win);*/ winset (surface_win); ortho (left, right, bottom, top, near, far); setmap (0); /*color (254);*/ c3s (white); clear (); makeobj (SURFACE); for (i = 0; i < surface [snum].num_points; i++){ c3s (black); /*if (i < 10) printf ("DISPLAY %d %.2f %.2f\n", i, surface [snum].points [i].pos [0], surface [snum].points [i].pos [1]);*/ #ifdef LINES for (j = 0; j < surface [snum].points [i].num_neighs; j++){ n = surface [snum].points [i].neighs [j]; if (i > j){ /*printf ("line %d -> %d\n", i, n);*/ bgnline(); v3f (surface [snum].points [i].pos); v3f (surface [snum].points [n].pos); /*printf ("Point %.2f %.2f %.2f to %.2f %.2f %.2f\n", surface [snum].points [i].pos [0], surface [snum].points [i].pos [1], surface [snum].points [i].pos [2], surface [snum].points [n].pos [0], surface [snum].points [n].pos [1], surface [snum].points [n].pos [2]);*/ endline(); } } #else rectf (surface [snum].points [i].pos [0]-DIM, surface [snum].points [i].pos [1]-DIM, surface [snum].points [i].pos [0]+DIM, surface [snum].points [i].pos [1]+DIM); #endif } closeobj (); callobj (SURFACE); swapbuffers (); } void DisplayDeform (short new, int snum, int flag) { int i, j, n; short val; int x_init = 480, y_init = 0; float dmin, dmax; int color_index; short current_color [3]; int x_size = xsize*2.0, y_size = ysize*2.0; if (new){ foreground (); keepaspect ((right-left),(top-bottom)); if (flag == 0) x_init = 480; else x_init = 80; prefposition (x_init, x_init+x_size, y_init, y_init+y_size); if (flag == 0) deformx_win = winopen ("Deformation in X"); else deformy_win = winopen ("Deformation in Y"); doublebuffer(); RGBmode (); gconfig(); } if (flag == 0) winset (deformx_win); else winset (deformy_win); ortho (left, right, bottom, top, near, far); c3s (white); clear (); if (flag == 0) makeobj (DEFORMX); else makeobj (DEFORMY); if (flag == 0) determine_min_max (surface [snum].num_points, displace [0], &dmin, &dmax); else determine_min_max (surface [snum].num_points, displace [1], &dmin, &dmax); printf ("flag %d %f %f\n", flag, dmin, dmax); /*dmin = -0.025; dmax = 0.025;*/ for (i = 0; i < surface [snum].num_points; i++){ if (flag == 0) color_index = get_lut_index (snum, displace [0][i], dmin, dmax); else color_index = get_lut_index (snum, displace [1][i], dmin, dmax); for (j = 0; j < 3; j++) current_color [j] = lut [color_index][j+1]; c3s (current_color); /*if ((flag == 0) && ((i % 1000) == 0)) printf ("color is %d %d %d\n", current_color [0], current_color [1], current_color [2]);*/ #ifdef LINES for (j = 0; j < surface [snum].points [i].num_neighs; j++){ n = surface [snum].points [i].neighs [j]; if (i > j){ bgnline(); v3f (surface [snum].points [i].pos); v3f (surface [snum].points [n].pos); endline(); } } #endif rectf (surface [snum].points [i].pos [0]-DIM, surface [snum].points [i].pos [1]-DIM, surface [snum].points [i].pos [0]+DIM, surface [snum].points [i].pos [1]+DIM); } closeobj (); if (flag == 0) callobj (DEFORMX); else callobj (DEFORMY); swapbuffers (); } void DisplayTotalDeform (short new, int snum, int flag) { int i, j, n; short val; int x_init = 480, y_init = 400; float dmin, dmax; int color_index; short current_color [3]; int x_size = xsize*2.0, y_size = ysize*2.0; if (new){ foreground (); keepaspect ((right-left),(top-bottom)); if (flag == 0) x_init = 480; else x_init = 80; prefposition (x_init, x_init+x_size, y_init, y_init+y_size); if (flag == 0) total_deformx_win = winopen ("Aggregate Deformation in X"); else total_deformy_win = winopen ("Aggregate Deformation in Y"); doublebuffer(); RGBmode (); gconfig(); } if (flag == 0) winset (total_deformx_win); else winset (total_deformy_win); ortho (left, right, bottom, top, near, far); c3s (white); clear (); if (flag == 0) makeobj (TOTAL_DEFORMX); else makeobj (TOTAL_DEFORMY); if (flag == 0) determine_min_max (surface [snum].num_points, total_displace [0], &dmin, &dmax); else determine_min_max (surface [snum].num_points, total_displace [1], &dmin, &dmax); /*dmin = -0.25; dmax = 0.25;*/ for (i = 0; i < surface [snum].num_points; i++){ if (flag == 0) color_index = get_lut_index (snum, total_displace [0][i], dmin, dmax); else color_index = get_lut_index (snum, total_displace [1][i], dmin, dmax); for (j = 0; j < 3; j++) current_color [j] = lut [color_index][j+1]; c3s (current_color); #ifdef LINES for (j = 0; j < surface [snum].points [i].num_neighs; j++){ n = surface [snum].points [i].neighs [j]; if (i > j){ bgnline(); v3f (surface [snum].points [i].pos); v3f (surface [snum].points [n].pos); endline(); } } #else rectf (surface [snum].points [i].pos [0]-DIM, surface [snum].points [i].pos [1]-DIM, surface [snum].points [i].pos [0]+DIM, surface [snum].points [i].pos [1]+DIM); #endif } closeobj (); if (flag == 0) callobj (TOTAL_DEFORMX); else callobj (TOTAL_DEFORMY); swapbuffers (); } void DisplaySulci (short new, int snum, int flag) { int i, j, n; short val; int x_init = 0, y_init = 800; int x_size = xsize*2.0, y_size = ysize*2.0; if (flag == 1){ printf ("DisplaySulci return...\n"); return; } if (new){ foreground (); keepaspect ((right-left),(top-bottom)); prefposition (x_init, x_init+x_size, y_init, y_init+y_size); printf ("prefposition %d %d %d %d\n", x_init, x_init+x_size, y_init, y_init+y_size); if (flag == 0) target_win = winopen ("Target"); else template_win = winopen ("Tempate"); doublebuffer(); RGBmode (); gconfig(); } if (flag == 0) winset (target_win); else winset (template_win); ortho (left, right, bottom, top, near, far); c3s (white); clear (); if (flag == 0) makeobj (TARGET); else makeobj (TEMPLATE); for (i = 0; i < totpoints; i++){ c3s (red); rectf (X1 [i]-DIM*2, Y1 [i]-DIM*2, X1 [i]+DIM*2, Y1 [i]+DIM*2); c3s (blue); rectf (X2 [i]-DIM*2, Y2 [i]-DIM*2, X2 [i]+DIM*2, Y2 [i]+DIM*2); } /*{ float vert1 [2], vert2 [2]; for (i = 1; i < totpoints; i++){ c3s (red); vert1 [0] = X1 [i-1]; vert1 [1] = Y1 [i-1]; vert2 [0] = X1 [i]; vert2 [1] = Y1 [i]; bgnline (); v2f (vert1); v2f (vert2); endline (); } }*/ c3s (gray); /*for (i = 0; i < surface [snum].num_points; i++) rectf (surface [snum].points [i].pos [0]-DIM, surface [snum].points [i].pos [1]-DIM, surface [snum].points [i].pos [0]+DIM, surface [snum].points [i].pos [1]+DIM);*/ closeobj (); if (flag == 0) callobj (TARGET); else callobj (TEMPLATE); swapbuffers (); } void DisplaySulci2 (short new, int snum, int flag) { int i, j, n; short val; int x_init = 700, y_init = 800; int x_size = xsize*2.0, y_size = ysize*2.0; float x0, y0; if (flag == 1) return; if (new){ foreground (); keepaspect ((right-left),(top-bottom)); prefposition (x_init, x_init+x_size, y_init, y_init+y_size); if (flag == 0) target_win2 = winopen ("Target2"); else template_win = winopen ("Tempate"); doublebuffer(); RGBmode (); gconfig(); } if (flag == 0) winset (target_win2); else winset (template_win); ortho (left, right, bottom, top, near, far); c3s (white); clear (); if (flag == 0) makeobj (TARGET); else makeobj (TEMPLATE); for (i = 0; i < totpoints; i++){ c3s (red); rectf (X1 [i]-DIM*2, Y1 [i]-DIM*2, X1 [i]+DIM*2, Y1 [i]+DIM*2); c3s (blue); rectf (X2 [i]-DIM*2, Y2 [i]-DIM*2, X2 [i]+DIM*2, Y2 [i]+DIM*2); } #ifdef READ_CELL_FILE for (i = 0; i < NumCells; i++){ if ((i % 100) == 0){ x0 = cells [i].pos [0]; y0 = cells [i].pos [1]; c3s (black); rectf (x0-DIM*2, y0-DIM*2, x0+DIM*2, y0+DIM*2); } } #endif for (j = 0; j < n3; j++){ for (i = 0; i < sulci [2][j].np; i++){ x0 = sulci [2][j].x [i]; y0 = sulci [2][j].y [i]; c3s (green); rectf (x0-DIM*2, y0-DIM*2, x0+DIM*2, y0+DIM*2); } } closeobj (); if (flag == 0) callobj (TARGET); else callobj (TEMPLATE); swapbuffers (); } void read_lut_file () { FILE *fd; int i; if ((fd = fopen ("/v1d/heather/ANATOMY/CARET2/bb1.lut", "r")) == NULL){; printf ("ERROR: could not open file %s...\n", "/v1d/heather/ANATOMY/CARET2/bb1.lut"); exit (-1); } fread (lut, 1, 256*4, fd); /*for (i = 0; i < 256; i++) printf ("LUT %2d: %d %d %d %d\n", i, lut [0], lut [1], lut [2], lut [3]);*/ printf ("BB lut read in ...\n"); } int get_lut_index (int snum, float value, float dmin, float dmax) { float lut_scale; int color_index; if (value < dmin) color_index = 0; else if (value > dmax) color_index = 255; else{ lut_scale = 255.0/(dmax-dmin); color_index = (int)(lut_scale * (value - dmin)); } return (color_index); } #endif /* HAVE_IRISGL */ void determine_min_max (int num, float *array, float *min, float *max) { int i; *min = *max = array [0]; for (i = 0; i < totpoints; i++){ if (array [i] < *min) *min = array [i]; if (array [i] > *max) *max = array [i]; } /*printf ("Min %.2f, Max %.2f\n", *min, *max);*/ } /* BORDER 2 FILE FORMAT */ void ReadPoints (char *file, int *num_sulci, int idx) { FILE *fp; int i, j; char name [MAXLINE]; int t1, t2, t3; float f1, f2, f3; char lineIn[MAXLINE]; printf ("Opening file %s...\n", file); if ((fp = fopen (file, "r")) == NULL){ printf ("ERROR: Could not open file %s\n", file); return; } /* * (JWH 12/05/00) * skip over header if present. * if a header is present the first line is "BeginHeader". The * header is concluded with "EndHeader". */ if (fgets(lineIn, MAXLINE, fp) == NULL) { printf("ERROR: Unable to read file %s\n", file); return; } if (strncmp(lineIn, "BeginHeader", 11) == 0) { int done = 0; while (done == 0) { if (fgets(lineIn, MAXLINE, fp) == NULL) { printf("ERROR: Error while reading file %s\n", file); return; } if (strncmp(lineIn, "EndHeader", 9) == 0) { done = 1; } } /* read number of borders */ /* fscanf (fp, "%d", &t1); */ fgets(lineIn, MAXLINE, fp); sscanf(lineIn, "%d", &t1); } else { /* no header, 1st line is number of borders */ sscanf(lineIn, "%d", &t1); } /* JWH 12/05/00 fscanf (fp, "%d", &t1); */ *num_sulci = t1; printf ("\t%d sulci to read...\n", *num_sulci); if (t1 > MAX_SULCI) { printf("\n\n MAX_SULCI = %d exceeded\n", MAX_SULCI); printf("Number of borders from file %s is %d\n\n\n", file, t1); exit(-1); } for (j = 0; j < *num_sulci; j++){ float sd, vr, numScanned; /* fscanf (fp, "%d %d %s", &t1, &t2, name); */ fgets(lineIn, MAXLINE, fp); numScanned = sscanf(lineIn, "%d %d %s %f %f", &t1, &t2, name, &sd, &vr); if (numScanned != 5) { sd = DEFAULT_SAMPLING_DENSITY; vr = DEFAULT_VARIANCE; } /*printf ("\tsulcus %d %d %s\n", j, t2, name);*/ /*if (t2 > 0) printf ("\t%d %d %s\n", j, t2, name);*/ /* fscanf (fp, "%f %f %f", &f1, &f2, &f3); */ fgets(lineIn, MAXLINE, fp); sscanf (lineIn, "%f %f %f", &f1, &f2, &f3); strcpy (sulci [idx][j].name, name); sulci[idx][j].ddd = sd; sulci[idx][j].variance = vr; sulci [idx][j].np = t2; if (idx != 2){ #define FILT #ifdef FILT if ( (strncmp(name, "morph.", 6) == 0) || (strncmp(name, "MORPH.", 6) == 0) || (strncmp(name, "LANDMARK", 8) == 0) || (strncmp(name, "landmark", 8) == 0)){ printf ("\t***USING %s; %d\n", name, t2); sulci [idx][j].np = t2; } else { printf ("\tNOT USING %s\n", name); sulci [idx][j].np = 0; } #endif } else{ /*sulci [idx][j].np = t2; printf ("\t%d %d %s\n", j, t2, name);*/ } if (t1 > MAX_SULCI){ printf ("ERROR: Exceeded max # of sulci %d, max %d\n", t2, MAX_SULCI); exit (-1); } if (t2 > MAX_FIDUCIAL_POINTS) { printf("\n\n MAX_FIDUCIAL_POINTS = %d exceeded\n", MAX_SULCI); printf("Number of border links in bordr %s is %d\n\n\n", name, t2); exit(-1); } for (i = 0; i < t2; i++){ #ifdef NEW_BORDERS /* fscanf (fp, "%d %d %f %f %f", &t1, &t3, &f1, &f2, &f3); */ fgets(lineIn, MAXLINE, fp); sscanf (lineIn, "%d %d %f %f %f", &t1, &t3, &f1, &f2, &f3); #else /*if (idx == 2) fscanf (fp, "%d %d %f %f %f", &t1, &t3, &f1, &f2, &f3); else fscanf (fp, "%d %f %f %f", &t1, &f1, &f2, &f3);*/ /* fscanf (fp, "%d %f %f %f", &t1, &f1, &f2, &f3); */ fgets(lineIn, MAXLINE, fp); sscanf (lineIn, "%d %f %f %f", &t1, &f1, &f2, &f3); #endif /*printf ("\t\t%d %f %f\n", i, f1, f2);*/ #ifdef IMAGE_SCALE /*if ((idx == 0) || (idx == 1) || (idx == 2)){ f1 *= 0.3; f2 *= 0.3; }*/ #endif /*if (idx == 1){ f1 *= 3; f2 *= 3; }*/ /*if (idx == 1){ f1 += 80; f2 += 80; }*/ /*f1 *= 2; f2 *= 2;*/ sulci [idx][j].x [i] = f1 * SCALE_FACTOR; sulci [idx][j].y [i] = f2 * SCALE_FACTOR; } } fclose (fp); } int find_sulcus (int num, char *name, int idx) { int i, n; for (i = 0; i < num; i++){ if (sulci [idx][i].np > 0){ n = strcmp (sulci [idx][i].name, name); /*printf ("\t %s %s\n", sulci [idx][i].name, name);*/ if (n == 0){ return (i); } } } printf ("ERROR: Corresponding sulcus for %s not found!\n", name); /*exit (-1); */ return (-1); } /* BORDER 2 FILE FORMAT */ void WritePoints (char *file, int num_sulci, int idx) { FILE *fp; int i, j; char name [MAXLINE]; int t1, t2; float f1, f2, f3; printf ("Opening file %s...\n", file); if ((fp = fopen (file, "w")) == NULL){ printf ("ERROR: Could not open file %s\n", file); return; } fprintf (fp, "%d\n", num_sulci); for (j = 0; j < num_sulci; j++){ fprintf (fp, "%d %d %s\n", j, sulci [idx][j].np, sulci [idx][j].name); /*printf ("WRITE %d %d %s\n", j, sulci [idx][j].np, sulci [idx][j].name); */ fprintf (fp, "%f %f %f\n", 0.0, 0.0, 0.0); for (i = 0; i < sulci [idx][j].np; i++){ #ifdef IMAGE_SCALE f1 = ImageX2Transform (sulci [idx][j].x [i]); f2 = ImageX2Transform (sulci [idx][j].y [i]); #else f1 = sulci [idx][j].x [i]; f2 = sulci [idx][j].y [i]; #endif f1 = f1 / SCALE_FACTOR; f2 = f2 / SCALE_FACTOR; fprintf (fp, "%d %d %f %f %f\n", i, -1, f1, f2, 0.0); } } fclose (fp); } float DetermineVariance (char *name, float var) { int i, tst; float varout; for (i = 0; i < NUM_SULCI_TYPE; i++){ tst = strncmp (name, sulcivar [i].name, strlen (sulcivar [i].name)); if (tst == 0){ /*printf ("var is %f times %f = %f\n", var, sulcivar [i].var_factor, varout);*/ varout = var * sulcivar [i].var_factor; return (varout); } } printf ("Error: Can't find variance for sulci type %s\n", name); return (1.0); return (0.01); varout = var * 1.0; exit (-1); return (varout); } #ifdef HAVE_IRISGL void DisplayImage (short new, int snum, unsigned char *image) { int i, j, n; short val; int x_init = 0, y_init = 0; unsigned long *parray; parray = (unsigned long *)malloc (ixsize*iysize*sizeof (unsigned long)); for (j = 0; j < iysize; j++) for (i = 0; i < ixsize; i++) parray [(j*ixsize)+i] = image [(j*ixsize)+i]; if (new){ foreground (); keepaspect ((right-left),(top-bottom)); prefposition (x_init, x_init+ixsize, y_init, y_init+iysize); printf ("prefposition %d %d %d %d\n", x_init, x_init+ixsize, y_init, y_init+iysize); winid1 = winopen ("Original Image"); RGBmode (); doublebuffer(); gconfig(); } winset (winid1); RGBcolor (0, 0, 0); clear (); /*ortho (left, right, bottom, top, near, far);*/ ortho (0, ixsize, 0, iysize, -10000, 10000); /*rectzoom (2.0, 2.0);*/ lrectwrite (0, 0, ixsize-1, iysize-1, parray); for (i = 0; i < totpoints; i++){ c3s (white); /*printf ("OrigImage: %d %.2f %.2f\n", i, X1 [i], Y1 [i]); */ rectf (X1 [i]-DIM*2, Y1 [i]-DIM*2, X1 [i]+DIM*2, Y1 [i]+DIM*2); } swapbuffers (); } void DisplayDeformedImage (short new, unsigned char *image) { int i, j, n; short val; int x_init = 400, y_init = 0; unsigned long *larray; float zfactor = 3.0; if ((ixsize > 0) && (iysize > 0)){ printf ("Display deformed image %d %d...\n", ixsize, iysize); larray = (unsigned long *)malloc (ixsize*iysize*sizeof (unsigned long)); for (j = 0; j < iysize; j++){ for (i = 0; i < ixsize; i++){ larray [(j*ixsize)+i] = (image [(j*ixsize)+i] | (image [(j*ixsize)+i] << 8) | (image [(j*ixsize)+i] << 16)); /*larray [(j*ixsize)+i] = (image [(j*ixsize)+i]); */ } } if (new){ foreground (); keepaspect ((right-left),(top-bottom)); prefposition (x_init, x_init+ixsize*zfactor, y_init, y_init+iysize*zfactor); winid2 = winopen ("Image"); RGBmode (); doublebuffer(); gconfig(); } winset (winid2); clear (); ortho (left, right, bottom, top, -10000, 10000); rectzoom (zfactor, zfactor); lrectwrite (0, 0, ixsize-1, iysize-1, larray); for (i = 0; i < totpoints; i++){ c3s (red); rectf (X1 [i]-DIM*2, Y1 [i]-DIM*2, X1 [i]+DIM*2, Y1 [i]+DIM*2); /*c3s (blue); rectf (X2 [i]-DIM*2, Y2 [i]-DIM*2, X2 [i]+DIM*2, Y2 [i]+DIM*2);*/ } swapbuffers (); } } void cmodeDisplayDeformedImage (short new, unsigned char *image) { int i, j, n; short val; int x_init = 400, y_init = 0; unsigned short *sarray; printf ("Display deformed image %d %d...\n", ixsize, iysize); sarray = (unsigned short *)malloc (ixsize*iysize*sizeof (unsigned short)); for (j = 0; j < iysize; j++){ for (i = 0; i < ixsize; i++){ /*larray [(j*ixsize)+i] = i % 255;*/ sarray [(j*ixsize)+i] = image [(j*ixsize)+i]; } } if (new){ foreground (); keepaspect ((right-left),(top-bottom)); prefposition (x_init, x_init+ixsize, y_init, y_init+iysize); winid2 = winopen ("Image"); cmode (); doublebuffer(); gconfig(); } winset (winid2); for (i = 0; i < 256; i++) mapcolor (i, i, i, i); clear (); ortho (left, right, bottom, top, -10000, 10000); rectwrite (0, 0, ixsize-1, iysize-1, sarray); for (i = 0; i < totpoints; i++){ color (255); rectf (X1 [i]-DIM*2, Y1 [i]-DIM*2, X1 [i]+DIM*2, Y1 [i]+DIM*2); } swapbuffers (); } #endif /* HAVE_IRISGL */ #ifdef READ_CELL_FILE void ReadCellFile (char *file) { int i, j; char line [MAXLINE]; int t1, t2, t3; char s1 [MAXLINE], s2 [MAXLINE]; float f1, f2, f3; FILE *fp; int num; if ((fp = fopen (file, "r")) == NULL){; printf ("ERROR: (ReadCellFile) could not open file %s\n", file); return; } fscanf (fp, "%d", &NumCells); printf ("%d cells to read from %s...\n", NumCells, file); if (NumCells > MAX_NUM_CELLS){ printf ("ERROR: %d > MAX_NUM_CELLS %d...\n", NumCells, MAX_NUM_CELLS); exit (-1); } for (i = 0; i < NumCells; i++){ fgets (line, MAXLINE, fp); num = sscanf (line, "%d %d %d %s %s %f %f %f", &t1, &t2, &t3, s1, s2, &f1, &f2, &f3); if ((i % 10000) == 0) printf ("\t%5d of %5d\n", i, NumCells); strcpy (cells [i].area1, s1); strcpy (cells [i].area2, s2); cells [i].section = t2; cells [i].point = t3; cells [i].pos [0] = f1; cells [i].pos [1] = f2; cells [i].pos [2] = f3; } fclose (fp); } void WriteCellFile (char *file) { int i, j; char line [MAXLINE]; int t1, t2, t3; char s1 [MAXLINE], s2 [MAXLINE]; float f1, f2, f3; FILE *fp; int num; if ((fp = fopen (file, "w")) == NULL){; printf ("ERROR: (WriteCellFile) could not open file %s\n", file); return; } fprintf (fp, "%d\n", NumCells); printf ("%d cells to write to %s...\n", NumCells, file); for (i = 0; i < NumCells; i++){ if ((i % 10000) == 0) printf ("\t%5d of %5d\n", i, NumCells); fprintf (fp, "%d %d %d %s %s %f %f %f\n", i, cells [i].section, cells [i].point, cells [i].area1, cells [i].area2, cells [i].pos [0], cells [i].pos [1], cells [i].pos [2]); } fclose (fp); } #endif /* READ_CELL_FILE */ void calculate_weightsFLUID (int totpoints, int dim, double *mat, double *X1, double *Y1, double *X2, double *Y2) { int INFO,LDA,LDB,LWORK,N,NRHS; char UPLO; int IPIV[MAX_FIDUCIAL_POINTS]; double work[MAX_FIDUCIAL_POINTS]; int i, j; float t1; /* Now calculate the weights */ /* This is done by solving a liner equation */ /* First fill the part of the covariance function */ /*for(j=0;j -width/2){ n = surface [snum].points [npoints].num_neighs; surface [snum].points [npoints].neighs [n] = npoints-1; surface [snum].points [npoints].num_neighs++; } if (i < width/2-spacing){ n = surface [snum].points [npoints].num_neighs; surface [snum].points [npoints].neighs [n] = npoints+1; surface [snum].points [npoints].num_neighs++; } if (j > -height/2){ n = surface [snum].points [npoints].num_neighs; surface [snum].points [npoints].neighs [n] = npoints-w; surface [snum].points [npoints].num_neighs++; /*printf ("point %d %d %d, neigh %d gets %d\n", npoints, i, j, n, npoints-w);*/ } if (j < height/2-spacing){ n = surface [snum].points [npoints].num_neighs; surface [snum].points [npoints].neighs [n] = npoints+w; surface [snum].points [npoints].num_neighs++; /*printf ("point %d %d %d, neigh %d gets %d\n\n", npoints, i, j, n, npoints+w);*/ } npoints++; } } surface [snum].num_points = npoints; printf ("Created surface with %d points...\n", npoints); #endif } void ImageInitStuff (char *filename, int xsize, int ysize) { int i; FILE *fpin; int answer; /*left = 0; right = xsize; bottom = 0; top = ysize;*/ printf ("Deforming image %s also %d %d...\n", filename, xsize, ysize); /* alocate the memory */ inimage = (char *)calloc (xsize*ysize,1); outimage = (char *)calloc (xsize*ysize,1); def_out = (char *)calloc (xsize*ysize,1); image_xdeform = (float *)malloc (xsize*ysize*sizeof(float)); image_ydeform = (float *)malloc (xsize*ysize*sizeof(float)); for (i = 0; i < xsize*ysize; i++){ outimage [i] = 0; image_xdeform [i] = 0.0; image_ydeform [i] = 0.0; } if ((fpin = fopen (filename, "r")) == NULL){ printf ("Could not open file %s\n", filename); for (i = 0; i < xsize*ysize; i++) inimage [i] = 128; CreateGridImage (inimage, xsize, ysize); /*DisplayDeformedImage (True, inimage); while (done == False){ if (qtest ()){ device = qread (&val); if (device == ESCKEY) done = TRUE; } }*/ } else{ answer = fread (inimage, 1, xsize*ysize, fpin); printf ("after %d...\n", answer); } } void ComputeDeformationFLUID (int step, double x0, double y0, double *defx, double *defy) { int tmpux,tmpuy; /* Displacement FIELD */ int k; double tmp1, tmp2; double ux, uy; /*Do the sumation of the Greens Functions */ tmpux = ux = 0; tmpuy = uy = 0; for (k=0;k 0){ /* Find the corresponding sulcus in the other list */ idx = find_sulcus (n2, sulci [0][i].name, 1); if (idx >= 0){ char name [256]; strcpy (name, sulci [1][idx].name); if ( (strncmp(name, "morph.", 6) == 0) || (strncmp(name, "MORPH.", 6) == 0) || (strncmp(name, "LANDMARK", 8) == 0) || (strncmp(name, "landmark", 8) == 0) ) { ddd = 5.00; } else { ddd = 10.00; } printf ("Sulcus %3d: target %10s %4d, template %d %10s %4d, %.2f %s\n", i, sulci [0][i].name, sulci [0][i].np, idx, sulci [1][idx].name, sulci [1][idx].np, ddd, name); flag = 0; resample_line (sulci [0][i].x, sulci [0][i].y, sulci [0][i].np, newx, newy, ddd, &new, flag); for (j = 1; j < new; j++){ X1 [totpoints+j-1] = newx [j]; Y1 [totpoints+j-1] = newy [j]; VAR [totpoints+j-1] = DetermineVariance (sulci [0][i].name, var_mult); sulci [0][sulcus_count].x [j-1] = X1 [totpoints+j-1]; sulci [0][sulcus_count].y [j-1] = Y1 [totpoints+j-1]; } flag = 1; resample_line (sulci [1][idx].x, sulci [1][idx].y, sulci [1][idx].np, newx, newy, ddd, &new, flag); for (j = 1; j < new; j++){ X2 [totpoints+j-1] = newx [j]; Y2 [totpoints+j-1] = newy [j]; #ifdef PIN_VISIBLE_MAN_EDGES if ((strncmp (name, "93I.MORPH.P", 7)) == 0){ X2 [totpoints+j-1] = X1 [totpoints+j-1]; Y2 [totpoints+j-1] = Y1 [totpoints+j-1]; } #endif /*printf ("\t%s: %d %.2f %.2f -> %.2f %.2f\n", name, totpoints+j-1, X1 [totpoints+j-1], Y1 [totpoints+j-1], X2 [totpoints+j-1], Y2 [totpoints+j-1]);*/ sulci [3][sulcus_count].x [j-1] = X2 [totpoints+j-1]; sulci [3][sulcus_count].y [j-1] = Y2 [totpoints+j-1]; } /*totpoints += (new-2); sulci [0][sulcus_count].np = sulci [0][i].hold_np = (new-2); sulci [3][sulcus_count].np = sulci [1][idx].hold_np = (new-2);*/ totpoints += (new-1); sulci [0][sulcus_count].np = sulci [0][i].hold_np = new-1; sulci [3][sulcus_count].np = sulci [1][idx].hold_np = new-1; strcpy (sulci [0][sulcus_count].name, sulci [0][i].name); strcpy (sulci [3][sulcus_count].name, sulci [0][i].name); printf ("Sulcus %d, %d points, name %s\n", sulcus_count, sulci [0][sulcus_count].np, sulci [0][sulcus_count].name); sulcus_count++; } else{ printf ("Sulcus %3d NOT FOUND: target %10s %4d\n", i, sulci [0][i].name, sulci [0][i].np); sulci [0][i].hold_np = 0; } } } { int temp = 0;; n1 = sulcus_count; for (i = 0; i < n1; i++){ printf ("Sulcus %d %s, %d points\n", i, sulci [0][i].name, sulci [0][i].np); temp += sulci [0][i].np; } printf ("%d total points...\n\n", temp); n4 = sulcus_count; temp = 0; for (i = 0; i < n4; i++){ printf ("Sulcus %d %s, %d points\n", i, sulci [3][i].name, sulci [3][i].np); temp += sulci [3][i].np; } printf ("%d total points...\n", temp); } #ifdef IMAGE_SCALE /* Rescale the input points so they are back in image coordinate system */ for (i = 0; i < totpoints; i++){ X1 [i] = TransformX2Image (X1 [i]); Y1 [i] = TransformY2Image (Y1 [i]); #define JUNK #ifdef JUNK X2 [i] = TransformX2Image (X2 [i]); Y2 [i] = TransformY2Image (Y2 [i]); #endif /* X1,Y1 is the TARGET */ /*X1 [i] = ((X1 [i] - 392/2.0)*0.70)+392/2.0 - 50*0; Y1 [i] = ((Y1 [i] - 364/2.0)*0.70)+364/2.0 - 50*0; */ /* X2,Y2 is the SOURCE */ /*X2 [i] = ((X2 [i] - 392/2.0)*0.9)+392/2.0 - 50*0; Y2 [i] = ((Y2 [i] - 364/2.0)*0.9)+364/2.0 - 50*0;*/ } #ifdef JUNK for (i = 0; i < n3; i++){ /*printf ("\tAreal %d %d\n", i, sulci [2][i].np);*/ for (j = 0; j < sulci [2][i].np; j++){ sulci [2][i].x [j] = TransformX2Image (sulci [2][i].x [j]); sulci [2][i].y [j] = TransformY2Image (sulci [2][i].y [j]); /* FVE map */ /*sulci [2][i].x [j] = ((sulci [2][i].x [j] - 392/2.0)*0.7)+392/2.0 - 50*0; sulci [2][i].y [j] = ((sulci [2][i].y [j] - 364/2.0)*0.7)+364/2.0 - 50*0; */ /* Brodmann map */ /*sulci [2][i].x [j] = ((sulci [2][i].x [j] - 392/2.0)*0.9)+392/2.0 - 50*0; sulci [2][i].y [j] = ((sulci [2][i].y [j] - 364/2.0)*0.9)+364/2.0 - 50*0; */ } } #endif #endif printf("Total number of corespondance points = %d\n",totpoints); for (i = 0; i < totpoints; i++){ origX1 [i] = X1 [i]; origY1 [i] = Y1 [i]; origX2 [i] = X2 [i]; origY2 [i] = Y2 [i]; /*printf ("%d: %.2f %.2f -> %.2f %.2f\n", i, X1 [i], Y1 [i], X2 [i], Y2 [i]);*/ } /*{ int cnt = 0; printf ("n1 is %d, n2 is %d, n3 is %d\n", n1, n2, n3); for (i = 0; i < n1; i++){ sulci [0][i].np = sulci [0][i].hold_np; sulci [1][i].np = sulci [0][i].hold_np; strcpy (sulci [1][i].name, sulci [0][i].name); for (j = 0; j < sulci [0][i].np; j++){ sulci [0][i].x [j] = X1 [cnt]; sulci [0][i].y [j] = Y1 [cnt]; sulci [1][i].x [j] = X2 [cnt]; sulci [1][i].y [j] = Y2 [cnt]; cnt++; } } }*/ WritePoints ("target.orig.dat", n1, 0); WritePoints ("source.orig.dat", n4, 3); #ifndef READ_CELL_FILE WritePoints ("arch.orig.dat", n3, 2); #endif { FILE *fd1, *fd2; fd1 = fopen ("source.dat", "w"); fd2 = fopen ("target.dat", "w"); for (i = 0; i < totpoints; i++){ fprintf (fd1, "%.2f %.2f %.2f\n", X1 [i], Y1 [i], VAR [i]); fprintf (fd2, "%.2f %.2f %.2f\n", X2 [i], Y2 [i], VAR [i]); } fclose (fd1); fclose (fd2); } } void CreateGridImage (char *inimage, int xsize, int ysize) { /*unsigned char *inimage;*/ int i, j, k; int ii, jj; /*inimage = (unsigned char *)calloc (xsize*ysize, sizeof(unsigned char));*/ for (j = 0; j < ysize; j++) for (i = 0; i < xsize; i++) inimage [(j*ixsize)+i] = 255; for (j = 0; j < ysize; j++){ for (i = 0; i < xsize; i++){ if ((i % 10) == 0) inimage [(j*ixsize)+i] = 0; if ((j % 10) == 0) inimage [(j*ixsize)+i] = 0; for (k = 0; k < totpoints; k++){ if ((i == (int)X2 [k]) && (j == (int)Y2 [k])){ for (jj = j-1; jj < j+1; jj++){ for (ii = i-1; ii < i+1; ii++){ inimage [(jj*ixsize)+ii] = 0; } } } } } } } void WriteImage (char *file, char *inimage, int xsize, int ysize) { FILE *fd; int answer; if ((fd = fopen (file, "w")) == NULL){; printf ("ERROR: could not open file %s...\n", file); return; } answer = fwrite (inimage, 1, xsize*ysize, fd); printf ("write %d bytes, %d %d...\n", answer, xsize, ysize); fclose (fd); } void DeformImage (int ixsize, int iysize, int deform_flag) { int i, j, k, step; float x0, y0; int tmpux,tmpuy; double xdelta,ydelta,tx,ty; double l1,l2,l3,l4; double ux, uy; double tmp1, tmp2; double new_pathx [NUMT][5000]; double new_pathy [NUMT][5000]; /*printf ("Deform image %d %d...\n", ixsize, iysize);*/ if ((deform_flag == FLUID) && (ixsize > 0) && (iysize > 0)){ for(j=0;j= 0; step--){ calculate_weightsFLUID (totpoints, dim, mat, pathx[step+1], pathy[step+1], pathx[step], pathy[step]); printf ("Deform the image, step %d of %d...\n", step, NUMT-1); for (j = 0; j < iysize; j++){ if ((j % 100) == 0) printf ("\t%d of %d\n", j, iysize); for (i = 0; i < ixsize; i++){ x0 = i; y0 = j; ComputeDeformationFLUID (step, x0, y0, &ux, &uy); tmpux = (int)floor(ux); tmpuy = (int)floor(uy); xdelta = ux-(double)tmpux; ydelta = uy-(double)tmpuy; tx = 1.0-xdelta; ty = 1.0-ydelta; /* Now do the bi-linear interpolation * 1--2 * | | * 4--3 Only I and Gary Know what this is!! */ l1=l2=l3=l4=0.0; k = ((j+tmpuy)*ixsize)+(i+tmpux); if (((j+tmpuy)>=0)&((i+tmpux)>=0)&((i+tmpux)=0)&((i+tmpux+1)>=0)&((i+tmpux+1)=0)&((i+tmpux+1)>=0)&((i+tmpux+1)=0)&((i+tmpux+1)>=0)&((i+tmpux+1) %3d %3d (%lf %lf) \n", k, i, j, i+tmpux, j+tmpuy,pathx[step+1][k],pathy[step+1][k]); } }*/ } } /* Transfer the outimage into inimage */ for(j=0;jtar.gz # # Usage: # repack.sh # set -e ORIGSRC=$1 if [ -z "$ORIGSRC" ]; then echo "No upstream sources given." exit 1 fi CURDIR=$(pwd) WDIR=$(mktemp -d) SUBDIR=caret5_source # put upstream sources into working dir ORIGSRC_PATH=$(readlink -f ${ORIGSRC}) cd $WDIR unzip -q $ORIGSRC_PATH UPSTREAM_VERSION_STRING=$(cat $WDIR/$SUBDIR/caret_common/CaretVersion.h | grep getCaretVersionAsString | cut -d '"' -f 2,2) UPSTREAM_VERSION=$(python -c "import re; a=str($UPSTREAM_VERSION_STRING); print re.sub(r'([0-9])', r'\1.', a.replace('.',''))[:-1]") ORIG_VERSION="$UPSTREAM_VERSION~dfsg.1" echo "Determined version: $UPSTREAM_VERSION" echo "Debian orig version: $ORIG_VERSION" # remove non-free pieces rm -rf $SUBDIR/caret_vtk4_classes mv $SUBDIR caret-$ORIG_VERSION.orig tar czf caret_$ORIG_VERSION.orig.tar.gz caret-$ORIG_VERSION.orig mv caret_$ORIG_VERSION.orig.tar.gz $CURDIR # clean working dir rm -rf $WDIR echo "Tarball is at: $CURDIR/caret_$ORIG_VERSION.orig.tar.gz" caret-5.6.4~dfsg.1.orig/debian/dirs0000664000175000017500000000007411572067322016670 0ustar michaelmichaelusr/bin usr/lib/caret/bin usr/lib/caret/lib usr/share/caret caret-5.6.4~dfsg.1.orig/debian/copyright0000664000175000017500000000636711572067322017752 0ustar michaelmichaelFormat-Specification: http://wiki.debian.org/Proposals/CopyrightFormat Upstream-Name: Caret Upstream-Source: http://brainmap.wustl.edu/pub/caret Files: * Copyright: Copyright 1995-2008, John Harwell Heather Drury Donna Hanlon David Van Essen Copyright: Copyright 1995-2002, Washington University School of Medicine License: GPL-2+ On Debian systems the full text of the GNU General Public License can be found in the `/usr/share/common-licenses/GPL' file. Files: caret_common/MathUtilities.cxx Copyright: Copyright 1993-2002, Ken Martin Will Schroeder Bill Lorensen License: other Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither name of Ken Martin, Will Schroeder, or Bill Lorensen nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. * Modified source versions must be plainly marked as such, and must not be misrepresented as being the original software. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Files: caret_brain_set/BrainModelVolumeBiasCorrection.cxx Copyright: Copyright (c) 2002 Insight Consortium. All rights reserved. License: BSD This code adapted from the ITK Application "BiasCorrector.cxx" On Debian systems the full text of the BSD License can be found in the `/usr/share/common-licenses/BSD' file. Files: caret_uniformize/* Copyright: Copyright 1994-2000, Medical College of Wisconsin License: GPL-2+ This source code has been derived from parts of the AFNI package (http://afni.nimh.nih.gov). While AFNI's source code is (partially) covered by several different copyrights and licenses, the pieces included in the Caret sources are exclusively covered by the GNU General Public License. On Debian systems the full text of the GNU General Public License can be found in the `/usr/share/common-licenses/GPL' file. Files: debian/* Copyright: Copyright 2007-2008, Michael Hanke License: GPL-2+ On Debian systems the full text of the GNU General Public License can be found in the `/usr/share/common-licenses/GPL' file. caret-5.6.4~dfsg.1.orig/debian/control0000664000175000017500000000270411572067322017411 0ustar michaelmichaelSource: caret Section: science Priority: optional Maintainer: Michael Hanke Uploaders: Yaroslav Halchenko Build-Depends: debhelper (>= 5), libqt4-dev (>= 4.3), libqt4-opengl-dev | libqt4-dev (<< 4.4.0), libqwt5-qt4-dev, libvtk5-dev, libminc-dev Standards-Version: 3.8.4 Homepage: http://brainvis.wustl.edu/wiki/index.php/Caret:About Vcs-Browser: http://git.debian.org/?p=pkg-exppsy/caret.git Vcs-Git: git://git.debian.org/git/pkg-exppsy/caret.git DM-Upload-Allowed: yes Package: caret Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Suggests: caret-data (>= 5.6~dfsg.1) Description: Computerized Anatomical Reconstruction and Editing Toolkit This software allows for creating, viewing and manipulating surface reconstructions of the cerebral and cerebellar cortex, viewing volumes and for displaying experimental data on the surfaces and volumes. While Caret is primarily a GUI application with 'caret_command' there is also a versatile command line tool, that allows access to a substantial proportion of Caret's functionality. . Caret can download and use stereotaxic atlases (human, monkey, mouse and rat) from an open online database. . Reference: . Van Essen, D.C., Dickson, J., Harwell, J., Hanlon, D., Anderson, C.H. and Drury, H.A. 2001. An Integrated Software System for Surface-based Analyses of Cerebral Cortex. Journal of American Medical Informatics Association, 8(5), 443-459. caret-5.6.4~dfsg.1.orig/debian/compat0000664000175000017500000000000211572067322017201 0ustar michaelmichael5 caret-5.6.4~dfsg.1.orig/debian/changelog0000664000175000017500000001345711572067322017667 0ustar michaelmichaelcaret (5.6.1.3~dfsg.1-3) UNRELEASED; urgency=low * Switch the source package format 3.0 (quilt). Moved all patches into separate series. -- Michael Hanke Thu, 08 Apr 2010 11:03:18 -0400 caret (5.6.1.3~dfsg.1-2) unstable; urgency=low * Add slightly modified patch to address FTBFS on kFreeBSD originally provided by Cyril Brulebois -- Thanks (Closes: #575235). -- Michael Hanke Thu, 25 Mar 2010 09:08:10 -0400 caret (5.6.1.3~dfsg.1-1) unstable; urgency=low * New upstream release. Still no upstream support for VTK 5.2 (or later). * Applied patch for compatibility with GCC 4.4 (Closes: #525789). Thanks to Martin Michlmayr. * Add fixes for compatibility with VTK 5.2 (Closes: #520701, #520867). * Bumped Standards-Version to 3.8.4 -- no changes necessary. -- Michael Hanke Mon, 22 Mar 2010 20:46:27 -0400 caret (5.6.1~dfsg.1-4) unstable; urgency=low * Clarify copyright statement of the pieces of the Caret sources that have been derived from AFNI, after checking with ftp-masters (Closes: #518688). -- Michael Hanke Sat, 21 Mar 2009 19:02:39 +0100 caret (5.6.1~dfsg.1-3) unstable; urgency=low * Reverse the order of the build-dependency alternatives on libqt4 and libqt4-opengl-dev. The reason is that sbuild currently only considers the first alternative (see #403246), and hence the package FTBFS on the buildds. The alternative on libqt4-dev 4.3 is kept in the package as it allows to easily build backports on etch systems. (Closes: #519270). -- Michael Hanke Wed, 11 Mar 2009 18:42:13 +0100 caret (5.6.1~dfsg.1-2) unstable; urgency=low * Patched to build with VTK 5.2 (Closes: #518640). * Updated the upstream homepage field. Thanks to Francesco Poli for pointing this out. * Updated package description and added a reference to it. -- Michael Hanke Tue, 10 Mar 2009 15:20:06 +0100 caret (5.6.1~dfsg.1-1) unstable; urgency=low * New Upstream Version. * Added 'DM-Upload-Allowed: yes' to debian/control. * Minimized GCC compatibility-related Debian diff. Upstream applied slightly modified patch. * Fixed LD_LIBRARY_PATH setting in dh_shlibdeps call in debian/rules. -- Michael Hanke Mon, 12 Jan 2009 14:26:01 +0100 caret (5.6~dfsg.1-1) UNRELEASED; urgency=low * New upstream version. * Do not install link for caret_edit manpage, since the binary is not installed by the Debian package. * Use minc version 2 instead of old libminc0. * Bumped Standards-Version to 3.8.0 -- no changes necessary. * Several bugfixes (missing headers) for GCC 4.3 compatibility. * Adjust build-dependencies to account for the new libqt4-opengl-dev package, built by qt4-x11 (from 4.4.0-1 on). Done in a backport-friendly way, i.e. alternatively depend on libqt4-dev (>= 4.3) and (<< 4.4.0). * Added Yaroslav Halchenko to Uploaders. * caret-data is not recommended, but suggested dependency as the package is not yet in the Debian archive. Added relevant notes to README.Debian. * Converted debian/copyright into a machine readable format. * Include the AFNI licensing terms in debian/copyright as pieces of caret_uniformize were derived from AFNI. -- Michael Hanke Thu, 21 Aug 2008 09:40:25 +0200 caret (5.5.2~dfsg.1-1) UNRELEASED; urgency=low * New Upstream Version. Build-depends on Qt >= 4.3. Merged most commandline tools into 'caret_command'. * Package now honours DEB_BUILD_OPTIONS setting 'noopt'. * Build with debug symbols by default. * Debian packaging does not use upstream Makefile wrapper to qmake anymore, as it might hide build-failures. Calling qmake from debian/rules directly instead. * Simplified Debian diff to minimize conflicts between upstream changes and Debian packaging. * Set linker flags -Wl,--as-needed and --no-undefined to reduce the number of package dependencies and ensure proper internal shared libraries. * Do not build 'caret_edit' anymore as it caused problems with the internal shared libraries. This should be no problem, as it is a very simple editor and all of the 1000 editors in Debian should be able to do what 'caret_edit' does/did. -- Michael Hanke Mon, 30 Jun 2008 19:40:29 +0200 caret (5.5.1~dfsg.1-2) UNRELEASED; urgency=low * Added a manpage. * Fixed desktop and menu files to comply to the latest menu policy. -- Michael Hanke Tue, 11 Sep 2007 21:59:09 +0200 caret (5.5.1~dfsg.1-1) UNRELEASED; urgency=low * New Upstream Version. * Abandoned dpatch in favor of Git. -- Michael Hanke Sun, 8 Jul 2007 13:17:27 +0200 caret (5.5~dfsg.1-1) UNRELEASED; urgency=low [ Michael Hanke ] * Initial release. (Closes: #421703) * MPEG support is disabled as VTK in Debian does not provide the necessary library for patent reasons (see #408552). * The package builds internal libraries as shared libs instead of static linking to reduce the size of the distributed binaries. * A desktop and menu file for Caret5 was added. * Caret binaries are called via a wrapper script that sets an appropriate LD_LIBRARY_PATH for the necessary caret-internal libs and some Qt image format plugins. * Caret depends on the caret-data package that provides tutorials, online help and atlas datasets. While these files are part of the binary distribution of Caret they are not part of the sources. The Debian maintainer packaged them in a separate source package using the binary distribution as source (caret-data). [ Yaroslav Halchenko ] * Uses dh_wraporig to make source tarball DFSG-free -- Michael Hanke Tue, 22 May 2007 12:43:33 +0200 caret-5.6.4~dfsg.1.orig/debian/caret_app_wrapper0000755000175000017500000000205411572067322021426 0ustar michaelmichael#! /bin/sh -e # Copyright (C) 2007 by # Michael Hanke michael.hanke@gmail.com # # This script is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. if [ "${0##*/}" = "caret_app_wrapper" ]; then echo 'caret_app_wrapper: This script should not be run like this, see caret(1) for details' 1>&2 exit 1 fi # setup library search path for carets internal libs and Qt4 plugins LD_LIBRARY_PATH=/usr/lib/caret/lib/:/usr/lib/qt4/plugins/imageformats \ CARET5_HOME=/usr/share/caret \ CARET_WEB_BROWSER=/etc/alternatives/x-www-browser \ CARET_ATLAS_DIRECTORIES=/usr/share/caret/data_files/fmri_mapping_files \ /usr/lib/caret/bin/${0##*/} "$@" caret-5.6.4~dfsg.1.orig/debian/caret.menu0000664000175000017500000000033511572067322017770 0ustar michaelmichael?package(caret): \ needs="X11" \ section="Applications/Science/Medicine" \ title="Caret" \ longtitle="Computerized Anatomical Reconstruction and Editing Toolkit" \ command="/usr/bin/caret5" \ hints="MRI,fMRI" caret-5.6.4~dfsg.1.orig/debian/caret.manpages0000664000175000017500000000001711572067322020614 0ustar michaelmichaeldebian/caret.1 caret-5.6.4~dfsg.1.orig/debian/caret.links0000664000175000017500000000043611572067322020146 0ustar michaelmichael/usr/lib/caret/bin/caret_app_wrapper /usr/bin/caret5 /usr/lib/caret/bin/caret_app_wrapper /usr/bin/caret_command /usr/lib/caret/bin /usr/share/caret/bin /usr/share/man/man1/caret.1.gz /usr/share/man/man1/caret5.1.gz /usr/share/man/man1/caret.1.gz /usr/share/man/man1/caret_command.1.gz caret-5.6.4~dfsg.1.orig/debian/caret.install0000664000175000017500000000012711572067322020471 0ustar michaelmichaeldebian/caret_app_wrapper usr/lib/caret/bin debian/caret.desktop usr/share/applications caret-5.6.4~dfsg.1.orig/debian/caret.desktop0000664000175000017500000000032011572067322020467 0ustar michaelmichael[Desktop Entry] Encoding=UTF-8 GenericName=Cortical Surface Reconstruction and Visualization Name=Caret Exec=caret5 TryExec=caret5 Type=Application Terminal=false Categories=Utility;Science;MedicalSoftware; caret-5.6.4~dfsg.1.orig/debian/caret.10000664000175000017500000000253511572067322017170 0ustar michaelmichael.TH "CARET" "1" "December 2007" "Michael Hanke" "" .SH "NAME" caret \- interactive viewing, manipulation and analysis of surface reconstructions of the cerebral and cerebellar cortex .SH "DESCRIPTION" Caret is a software application for viewing and manipulating surface reconstructions of the cerebral and cerebellar cortex, viewing volumes, for displaying experimental data on the surfaces and volumes and performing functional and structural analysis of the cerebral cortex. .PP Besides the main GUI application, the Caret software package provides a command line interface \fBcaret_command\fR that significantly improves the efficiency when analyzing a large number of datasets. .PP \fBcaret_command\fR provides an extensive help output when called with the \fI-help\fR option. .PP Questions regarding the usage of \fBCaret\fR or related theory can be posted on the \fBCaret mailing list\fR (see \fIhttp://brainvis.wustl.edu/caret/#Help\fR). .SH "SEE ALSO" The Caret homepage at .I http://brainvis.wustl.edu/caret which provides extensive documentation, including tutorials and demo datasets. .SH "AUTHOR" \fBCaret\fR was written by John Harwell, Heather Drury, Donna Hanlon and David Van Essen; Washington University School of Medicine .PP This manual page was written by Michael Hanke , for the Debian project (but may be used by others). caret-5.6.4~dfsg.1.orig/debian/TODO0000664000175000017500000000005711572067322016475 0ustar michaelmichael* introduce main config in /etc/caret/caret.sh caret-5.6.4~dfsg.1.orig/debian/README.Debian-source0000664000175000017500000000110611572067322021340 0ustar michaelmichaelREADME on source packaging of caret: -------------------------------------------------------------- The source tarball of the package was generated by dh_wraporig v.0.1.363 script which can be obtained from alioth's exppsy project repository: http://svn.debian.org/wsvn/pkg-exppsy/tools/dh_wraporig For this package dh_wraporig performed following actions: * Extracted files from md5:94ea24cced57512b0b5ac04d86298f7c ../caret_source.v5.61.zip * Removed following files/directories: caret_vtk4_classes * Additional parameters for tar on tarball creation were: --exclude *~ caret-5.6.4~dfsg.1.orig/debian/README.Debian0000664000175000017500000000245511572067322020052 0ustar michaelmichaelCaret for Debian ================ This document describes the differences between the Debian package of Caret and original Caret releases. User interface -------------- The Caret package provides desktop integration via desktop files for the main Caret GUI application. Additionally, the package includes a manpage. Caret binaries are called via a simple wrapper script that configures an appropriate environment (browser selection and path settings) for using Caret on Debian systems. Missing Functionality --------------------- Due to patent issues Debian VTK comes without MPEG2 support. Therefore the MPEG support in CARET is disabled as well. CARET is build with MINC support, but at the moment without ITK support. The Debian maintainer has to figure out what kind of advantages ITK support really has. Unlike the source distribution, the binary distribution of Caret comes with a set of additional documentation and data files, e.g. for fMRI mapping data into several stereotaxic spaces. This package does not include them. Currently, they are available from unofficial Debian repositories (e.g. http://apsy.gse.uni-magdeburg.de/debian). However, the Debian maintainer is working on integrating this package in Debian as well. -- Michael Hanke Tue, 15 Jul 2008 08:23:34 +0200 caret-5.6.4~dfsg.1.orig/caret_widgets/0000775000175000017500000000000011572067322017405 5ustar michaelmichaelcaret-5.6.4~dfsg.1.orig/caret_widgets/caret_widgets.pro0000664000175000017500000000275111572067322022760 0ustar michaelmichael###################################################################### # Automatically generated by qmake (1.04a) Tue Mar 18 09:10:35 2003 ###################################################################### TARGET = CaretWidgets CONFIG += staticlib INCLUDEPATH += . \ ../caret_common include(../caret_qmake_include.pro) win32:vs { TEMPLATE = vclib } !vs { TEMPLATE = lib } dll { CONFIG -= staticlib CONFIG += plugin } # Input HEADERS += \ QtDialogWizard.h \ QtListBoxSelectionDialog.h \ QtMultipleInputDialog.h \ QtRadioButtonSelectionDialog.h \ QtScriptInputDialog.h \ QtTableDialog.h \ QtTextEditDialog.h \ QtTextFileEditorDialog.h \ QtUtilities.h \ WuQDataEntryDialog.h \ WuQDialog.h \ WuQFileDialog.h \ WuQMessageBox.h \ WuQMultiPageDialog.h \ WuQSaveWidgetAsImagePushButton.h \ WuQSeparatorLine.h \ WuQWidgetGroup.h \ WuQWizard.h SOURCES += \ QtDialogWizard.cxx \ QtListBoxSelectionDialog.cxx \ QtMultipleInputDialog.cxx \ QtRadioButtonSelectionDialog.cxx \ QtScriptInputDialog.cxx \ QtTableDialog.cxx \ QtTextEditDialog.cxx \ QtTextFileEditorDialog.cxx \ QtUtilities.cxx \ WuQDataEntryDialog.cxx \ WuQDialog.cxx \ WuQFileDialog.cxx \ WuQMessageBox.cxx \ WuQMultiPageDialog.cxx \ WuQSaveWidgetAsImagePushButton.cxx \ WuQSeparatorLine.cxx \ WuQWidgetGroup.cxx \ WuQWizard.cxx caret-5.6.4~dfsg.1.orig/caret_widgets/WuQWizard.h0000664000175000017500000000411711572067322021456 0ustar michaelmichael#ifndef __WU_QWIZARD_H__ #define __WU_QWIZARD_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include class QKeyEvent; class QMenu; /// QWizard with a few additions including copy of dialog as image to clipboard class WuQWizard : public QWizard { Q_OBJECT public: // constructor WuQWizard(QWidget* parent = 0, Qt::WindowFlags f = 0); // destructor virtual ~WuQWizard(); // ring the bell static void beep(); // show the wait cursor static void showWaitCursor(); // normal cursor static void showNormalCursor(); public slots: // called to close bool close(); protected slots: // called to capture image of window and place it on the clipboard void slotMenuCaptureImageOfWindowToClipboard(); // called to capture image after timeout so nothing obscures window void slotCaptureImageAfterTimeOut(); protected: // add a capture image of window menu item to the menu void addImageCaptureToMenu(QMenu* menu); // called by parent when context menu event occurs virtual void contextMenuEvent(QContextMenuEvent*); }; #endif // __WU_QWIZARD_H__ caret-5.6.4~dfsg.1.orig/caret_widgets/WuQWizard.cxx0000664000175000017500000000623611572067322022035 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include "WuQWizard.h" /** * constructor. */ WuQWizard::WuQWizard(QWidget* parent, Qt::WindowFlags f) : QWizard(parent, f) { setFocusPolicy(Qt::ClickFocus); } /** * destructor. */ WuQWizard::~WuQWizard() { } /** * called to capture image after timeout so nothing obscures window. */ void WuQWizard::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 WuQWizard::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 WuQWizard::addImageCaptureToMenu(QMenu* menu) { menu->addAction("Capture Image to Clipboard", this, SLOT(slotMenuCaptureImageOfWindowToClipboard())); } /** * called by parent when context menu event occurs. */ void WuQWizard::contextMenuEvent(QContextMenuEvent* cme) { // // Popup menu for selection of pages // QMenu menu(this); // // Add menu item for image capture // addImageCaptureToMenu(&menu); // // Popup the menu // menu.exec(cme->globalPos()); } /** * ring the bell. */ void WuQWizard::beep() { QApplication::beep(); } /** * show the watch cursor. */ void WuQWizard::showWaitCursor() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); } /** * normal cursor. */ void WuQWizard::showNormalCursor() { QApplication::restoreOverrideCursor(); } /** * called to close. */ bool WuQWizard::close() { return QDialog::close(); } caret-5.6.4~dfsg.1.orig/caret_widgets/WuQWidgetGroup.h0000664000175000017500000000410611572067322022454 0ustar michaelmichael #ifndef __QT_WIDGET_GROUP_H__ #define __QT_WIDGET_GROUP_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include class QWidget; /// class for grouping widgets for ease of disabling and hiding class WuQWidgetGroup : public QObject { Q_OBJECT public: // constructor WuQWidgetGroup(QWidget* parent); // destructor ~WuQWidgetGroup(); // add a widget to the group void addWidget(QWidget* w); public slots: // block signals void blockSignals(bool blockTheSignals); // enable the group's widgets void setEnabled(bool enable); // disable the group's widgets void setDisabled(bool disable); // make the group's widgets visible void setVisible(bool makeVisible); // make the group's widgets hidden void setHidden(bool hidden); // make all of the widgets in the group the same size as size hint // of largest widget void resizeAllToLargestSizeHint(); // set status of all checkboxes void setAllCheckBoxesChecked(const bool b); protected: /// keeps track of the widgets QVector widgets; }; #endif // __QT_WIDGET_GROUP_H__ caret-5.6.4~dfsg.1.orig/caret_widgets/WuQWidgetGroup.cxx0000664000175000017500000000623011572067322023027 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "WuQWidgetGroup.h" /** * constructor. */ WuQWidgetGroup::WuQWidgetGroup(QWidget* parent) : QObject(parent) { } /** * destructor. */ WuQWidgetGroup::~WuQWidgetGroup() { // // Note: Do not "delete" the widgets !!!! // widgets.clear(); } /** * add a widget to the group. */ void WuQWidgetGroup::addWidget(QWidget* w) { widgets.push_back(w); } /** * enable the group's widgets. */ void WuQWidgetGroup::setEnabled(bool enable) { for (int i = 0; i < widgets.size(); i++) { widgets.at(i)->setEnabled(enable); } } /** * disable the group's widgets. */ void WuQWidgetGroup::setDisabled(bool disable) { for (int i = 0; i < widgets.size(); i++) { widgets.at(i)->setDisabled(disable); } } /** * make the group's widgets visible. */ void WuQWidgetGroup::setVisible(bool makeVisible) { for (int i = 0; i < widgets.size(); i++) { QWidget* w = widgets.at(i); w->setVisible(makeVisible); } } /** * make the group's widgets hidden. */ void WuQWidgetGroup::setHidden(bool hidden) { setVisible(! hidden); } /** * block signals. */ void WuQWidgetGroup::blockSignals(bool blockTheSignals) { for (int i = 0; i < widgets.size(); i++) { widgets.at(i)->blockSignals(blockTheSignals); } } /** * set status of all checkboxes. */ void WuQWidgetGroup::setAllCheckBoxesChecked(const bool b) { for (int i = 0; i < widgets.size(); i++) { QCheckBox* cb = dynamic_cast(widgets.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 WuQWidgetGroup::resizeAllToLargestSizeHint() { int largestWidth = -1; int largestHeight = -1; for (int i = 0; i < widgets.size(); i++) { const QSize size = widgets.at(i)->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 < widgets.size(); i++) { widgets.at(i)->setFixedSize(newSize); } } } caret-5.6.4~dfsg.1.orig/caret_widgets/WuQSeparatorLine.h0000664000175000017500000000256011572067322022766 0ustar michaelmichael #ifndef __WU_QSEPARATOR_H__ #define __WU_QSEPARATOR_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include /// a separator widget like Motif's Separator (line) class WuQSeparatorLine : public QFrame { Q_OBJECT public: // constructor WuQSeparatorLine(const Qt::Orientation orientation, const int lineWidthOrHeight = 10, QWidget* parent = 0); // destructor ~WuQSeparatorLine(); protected: }; #endif // __WU_QSEPARATOR_H__ caret-5.6.4~dfsg.1.orig/caret_widgets/WuQSeparatorLine.cxx0000664000175000017500000000275211572067322023344 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "WuQSeparatorLine.h" /** * constructor. */ WuQSeparatorLine::WuQSeparatorLine(const Qt::Orientation orientation, const int lineWidthOrHeight, QWidget* parent) : QFrame(parent) { switch (orientation) { case Qt::Horizontal: setFrameStyle(QFrame::HLine | QFrame::Raised); break; case Qt::Vertical: setFrameStyle(QFrame::VLine | QFrame::Raised); break; } setLineWidth(0); setMidLineWidth(lineWidthOrHeight); } /** * destructor. */ WuQSeparatorLine::~WuQSeparatorLine() { } caret-5.6.4~dfsg.1.orig/caret_widgets/WuQSaveWidgetAsImagePushButton.h0000664000175000017500000000323311572067322025541 0ustar michaelmichael #ifndef __WU_QSAVE_WIDGET_AS_IMAGE_H___ #define __WU_QSAVE_WIDGET_AS_IMAGE_H___ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include /// class for saving the contents of a widget as an image class WuQSaveWidgetAsImagePushButton : public QPushButton { Q_OBJECT public: /// Constructor WuQSaveWidgetAsImagePushButton(const QString& text, QWidget* widgetToSaveImageOfIn, QWidget* parent = 0); /// Destructor ~WuQSaveWidgetAsImagePushButton(); protected slots: /// called when button pressed to save the image void slotClicked(); protected: /// widget that is to be saved QWidget* widgetToSaveImageOf; }; #endif // __WU_QSAVE_WIDGET_AS_IMAGE_H___ caret-5.6.4~dfsg.1.orig/caret_widgets/WuQSaveWidgetAsImagePushButton.cxx0000664000175000017500000001200111572067322026105 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include "FileUtilities.h" #include "WuQSaveWidgetAsImagePushButton.h" #include "StringUtilities.h" #include "WuQFileDialog.h" /** * Constructor. */ WuQSaveWidgetAsImagePushButton::WuQSaveWidgetAsImagePushButton(const QString& text, QWidget* widgetToSaveImageOfIn, QWidget* parent) : QPushButton(text, parent) { setAutoDefault(false); widgetToSaveImageOf = widgetToSaveImageOfIn; QObject::connect(this, SIGNAL(clicked()), this, SLOT(slotClicked())); } /** * Destructor. */ WuQSaveWidgetAsImagePushButton::~WuQSaveWidgetAsImagePushButton() { } /** * called when button pressed to save the image. */ void WuQSaveWidgetAsImagePushButton::slotClicked() { static QString previousFileFilter; // // Create the file filters and file extensions and find the jpeg and ppm filters // QStringList fileFilterList; std::vector fileFilters; std::vector fileExtensions; std::vector fileFormats; QString jpegFileFilter; QString ppmFileFilter; for (int i = 0; i < QImageWriter::supportedImageFormats().size(); i++) { QString str = QString(QImageWriter::supportedImageFormats().at(i)); QString filter = QString("%1 Image File (*.%2)").arg(str).arg( StringUtilities::makeLowerCase(str)); fileExtensions.push_back(StringUtilities::makeLowerCase(str)); if (str == "ppm") { ppmFileFilter = filter; } else if (str == "jpg") { jpegFileFilter = filter; } fileFilterList << filter; fileFilters.push_back(filter); fileFormats.push_back(str); } // // Create the file dialog // WuQFileDialog saveImageDialog(this); saveImageDialog.setModal(true); saveImageDialog.setWindowTitle("Save Image File"); saveImageDialog.setFileMode(WuQFileDialog::AnyFile); saveImageDialog.setDirectory("."); saveImageDialog.setAcceptMode(WuQFileDialog::AcceptSave); // // Set the file filters // saveImageDialog.setFilters(fileFilterList); if (previousFileFilter.isEmpty() == false) { saveImageDialog.selectFilter(previousFileFilter); } else if (jpegFileFilter.isEmpty() == false) { saveImageDialog.selectFilter(jpegFileFilter); } else if (ppmFileFilter.isEmpty() == false) { saveImageDialog.selectFilter(ppmFileFilter); } // // Execute the dialog // if (saveImageDialog.exec() == WuQFileDialog::Accepted) { QString name(saveImageDialog.selectedFiles().at(0)); // // Get the selected file filter // previousFileFilter = saveImageDialog.selectedFilter(); // // Find the file filter // int fileFilterIndex = -1; for (unsigned int i = 0; i < fileFilters.size(); i++) { if (fileFilters[i] == previousFileFilter) { fileFilterIndex = i; break; } } // // See if invalid filter index // if (fileFilterIndex < 0) { QString msg("Program Error: invalid file filter index when saving image file."); QApplication::beep(); QMessageBox::critical(this, "PROGRAM ERROR", msg, "OK"); return; } if (FileUtilities::filenameExtension(name) != fileExtensions[fileFilterIndex]) { name.append("."); name.append(fileExtensions[fileFilterIndex]); } QImage image = QPixmap::grabWidget(widgetToSaveImageOf).toImage(); /* if (image.save(name, fileFormats[fileFilterIndex].toAscii().constData(), 100) == false) { QApplication::beep(); QMessageBox::critical(this, "ERROR", "Unable to save image.", "OK"); } */ QImageWriter imageWriter(name, fileFormats[fileFilterIndex].toAscii()); if (imageWriter.write(image) == false) { QApplication::beep(); QMessageBox::critical(this, "ERROR", imageWriter.errorString()); } } } caret-5.6.4~dfsg.1.orig/caret_widgets/WuQMultiPageDialog.h0000664000175000017500000001422111572067322023222 0ustar michaelmichael #ifndef __WU_QMULTI_PAGE_DIALOG_H__ #define __WU_QMULTI_PAGE_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "WuQDialog.h" class QComboBox; class QDialogButtonBox; class QFrame; class QHBoxLayout; class QStackedWidget; class QToolBar; class QToolButton; /// page for generic multipage dialog class WuQMultiPageDialogPage : public QWidget { Q_OBJECT public: // constructor WuQMultiPageDialogPage(); // destructor virtual ~WuQMultiPageDialogPage(); // apply the pages settings virtual void applyPage() = 0; // create the page virtual QWidget* createPage() = 0; // update the page virtual void updatePage() = 0; // see if the page is valid virtual bool getPageValid() const = 0; protected: }; /// generic multi-page dialog class WuQMultiPageDialog : public WuQDialog { Q_OBJECT public: /// page creation time enum PAGE_CREATION { /// create when first displayed PAGE_CREATION_WHEN_DISPLAYED, /// create immediately PAGE_CREATION_IMMEDIATELY }; // constructor WuQMultiPageDialog(const PAGE_CREATION pageCreationIn, const int numberOfToolBarsIn, QWidget* parent = 0, Qt::WindowFlags flags = 0); // destructor virtual ~WuQMultiPageDialog(); // update the dialog void updateDialog(); // add a page void addPage(const QString& pageName, WuQMultiPageDialogPage* page); // create and add a tool button to the dialog QToolButton* addToolButton(const int toolBarNumber, const QString& buttonText, const QString& toolTipText, const QObject* receiver, const char* member); // create a tool button QToolButton* createToolButton(const QString& buttonText, const QString& toolTipText, const QObject* receiver, const char* member); // add a widget to a toolbar void addWidgetToToolBar(const int toolBarNumber, QWidget* widget); // show a page void showPage(WuQMultiPageDialogPage* page); // show the dialog virtual void show(); public slots: /// called to close dialog virtual bool close(); protected slots: /// called when page back tool button clicked void slotPageBackToolButtonClicked(); /// called when page forward tool button clicked void slotPageFwdToolButtonClicked(); /// called when page selection combo box selection is made void slotPageSelectionComboBox(int); /// called when apply button is clicked void slotApplyButtonClicked(); protected: /// class for data on each page class PageInfo { public: /// constructor PageInfo(const QString& nameIn, WuQMultiPageDialogPage* dataPageIn) { name = nameIn; dataPage = dataPageIn; pageComboBoxIndex = -1; pageWidget = NULL; } /// destructor ~PageInfo() { } /// name of page QString name; /// index of page in combo box int pageComboBoxIndex; /// the page WuQMultiPageDialogPage* dataPage; /// the page's widget QWidget* pageWidget; }; // set the default page void setDefaultPage(WuQMultiPageDialogPage* defaultPageIn); /// get currently displayed page PageInfo* getDisplayedPage(); /// update the page selection combo box void updatePageSelectionComboBox(); /// show a page void showPage(PageInfo* p, const bool updatePagesVisited); /// when to create pages const PAGE_CREATION pageCreation; /// the pages QVector pagesVector; /// pages that have been visited QVector pagesVisited; /// index into pages visited int pagesVisitedIndex; /// the toolbar layout QVector toolBarLayouts; /// page selection combo box QComboBox* pageSelectionComboBox; /// page back tool button QToolButton* pageBackToolButton; /// page fwd tool button QToolButton* pageForwardToolButton; /// frame for operations pages QFrame* pagesFrameWidget; /// stacked widget containing pages QStackedWidget* pagesStackedWidget; /// dialog's button box QDialogButtonBox* dialogButtonBox; /// first time dialog shown bool firstTimeDialogShown; /// the default page WuQMultiPageDialogPage* defaultPage; }; #endif // __WU_QMULTI_PAGE_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret_widgets/WuQMultiPageDialog.cxx0000664000175000017500000003406511572067322023605 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include "WuQMultiPageDialog.h" #include "WuQSeparatorLine.h" /** * constructor. */ WuQMultiPageDialog::WuQMultiPageDialog(const PAGE_CREATION pageCreationIn, const int numberOfToolBarsIn, QWidget* parent, Qt::WindowFlags flags) : WuQDialog(parent, flags), pageCreation(pageCreationIn) { defaultPage = NULL; firstTimeDialogShown = true; // // Page Selection label // QLabel* pageSelectionLabel = new QLabel("Page Selection"); // // Page Selection Backward tool button // pageBackToolButton = new QToolButton; pageBackToolButton->setToolTip("Go back to the \n" "previous page."); pageBackToolButton->setArrowType(Qt::LeftArrow); QObject::connect(pageBackToolButton, SIGNAL(clicked(bool)), this, SLOT(slotPageBackToolButtonClicked())); // // Page Selection Forward tool button // pageForwardToolButton = new QToolButton; pageForwardToolButton->setToolTip("Go forward to the \n" "next page as a \n" "result of using \n" "the back arrow."); pageForwardToolButton->setArrowType(Qt::RightArrow); QObject::connect(pageForwardToolButton, SIGNAL(clicked(bool)), this, SLOT(slotPageFwdToolButtonClicked())); // // Page Selection combo box // pageSelectionComboBox = new QComboBox; QObject::connect(pageSelectionComboBox, SIGNAL(activated(int)), this, SLOT(slotPageSelectionComboBox(int))); // // Layout for page selection controls // QHBoxLayout* pageSelectionLayout = new QHBoxLayout; pageSelectionLayout->addWidget(pageSelectionLabel); pageSelectionLayout->addWidget(pageBackToolButton); pageSelectionLayout->addWidget(pageForwardToolButton); pageSelectionLayout->addWidget(pageSelectionComboBox); pageSelectionLayout->setStretchFactor(pageSelectionLabel, 0); pageSelectionLayout->setStretchFactor(pageBackToolButton, 0); pageSelectionLayout->setStretchFactor(pageForwardToolButton, 0); pageSelectionLayout->setStretchFactor(pageSelectionComboBox, 100); // // The ToolBar // for (int i = 0; i < numberOfToolBarsIn; i++) { toolBarLayouts.push_back(new QHBoxLayout); } // // Stacked widget for pages // pagesStackedWidget = new QStackedWidget; // // Dialog button box // dialogButtonBox = new QDialogButtonBox(QDialogButtonBox::Apply | QDialogButtonBox::Close); QObject::connect(dialogButtonBox->button(QDialogButtonBox::Apply), SIGNAL(clicked()), this, SLOT(slotApplyButtonClicked())); QObject::connect(dialogButtonBox, SIGNAL(rejected()), this, SLOT(close())); // // Layout for page controls and widgets // WuQSeparatorLine* sepLine = new WuQSeparatorLine(Qt::Horizontal, 3); pagesFrameWidget = new QFrame; pagesFrameWidget->setFrameStyle(QFrame::Box | QFrame::Plain); pagesFrameWidget->setLineWidth(1); QVBoxLayout* operationsLayout = new QVBoxLayout(pagesFrameWidget); operationsLayout->addLayout(pageSelectionLayout); operationsLayout->addWidget(sepLine); operationsLayout->addWidget(pagesStackedWidget); operationsLayout->setStretchFactor(pageSelectionLayout, 0); operationsLayout->setStretchFactor(sepLine, 0); operationsLayout->setStretchFactor(pagesStackedWidget, 100); // // Layout for dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); for (int i = 0; i < numberOfToolBarsIn; i++) { dialogLayout->addLayout(toolBarLayouts[i]); } dialogLayout->addWidget(pagesFrameWidget); dialogLayout->addWidget(dialogButtonBox); for (int i = 0; i < numberOfToolBarsIn; i++) { dialogLayout->setStretchFactor(toolBarLayouts[i], 0); } dialogLayout->setStretchFactor(pagesFrameWidget, 100); dialogLayout->setStretchFactor(dialogButtonBox, 0); pagesVisitedIndex = -1; } /** * destructor. */ WuQMultiPageDialog::~WuQMultiPageDialog() { for (int i = 0; i < pagesVector.size(); i++) { delete pagesVector[i]; pagesVector[i] = NULL; } pagesVector.clear(); } /** * called when apply button is clicked. */ void WuQMultiPageDialog::slotApplyButtonClicked() { PageInfo* p = getDisplayedPage(); p->dataPage->applyPage(); } /** * called to close dialog. */ bool WuQMultiPageDialog::close() { return WuQDialog::close(); } /** * get currently displayed page. */ WuQMultiPageDialog::PageInfo* WuQMultiPageDialog::getDisplayedPage() { const QWidget* w = pagesStackedWidget->currentWidget(); PageInfo* p = NULL; for (int i = 0; i < pagesVector.count(); i++) { if (pagesVector[i]->pageWidget == w) { p = pagesVector[i]; break; } } return p; } /** * update the dialog. */ void WuQMultiPageDialog::updateDialog() { /* const int num = pagesVector.size(); for (int i = 0; i < num; i++) { pagesVector[i]->dataPage->updatePage(); } */ PageInfo* currentPage = getDisplayedPage(); if (currentPage != NULL) { currentPage->dataPage->updatePage(); } updatePageSelectionComboBox(); } /** * update the page selection combo box. */ void WuQMultiPageDialog::updatePageSelectionComboBox() { PageInfo* currentPage = getDisplayedPage(); pageSelectionComboBox->blockSignals(true); pageSelectionComboBox->clear(); PageInfo* firstValidPage = NULL; for (int i = 0; i < pagesVector.size(); i++) { PageInfo* p = pagesVector[i]; if (p->dataPage->getPageValid()) { p->pageComboBoxIndex = i; pageSelectionComboBox->addItem(p->name); if (firstValidPage == NULL) { firstValidPage = p; } } else if (p == currentPage) { currentPage = NULL; } } pageSelectionComboBox->blockSignals(false); if (currentPage == NULL) { currentPage = firstValidPage; } showPage(currentPage, true); } /** * called when page back tool button clicked. */ void WuQMultiPageDialog::slotPageBackToolButtonClicked() { pagesVisitedIndex--; if ((pagesVisitedIndex >= 0) && (pagesVisitedIndex < pagesVisited.size())) { showPage(pagesVisited[pagesVisitedIndex], false); } } /** * called when page forward tool button clicked. */ void WuQMultiPageDialog::slotPageFwdToolButtonClicked() { pagesVisitedIndex++; if ((pagesVisitedIndex >= 0) && (pagesVisitedIndex < pagesVisited.size())) { showPage(pagesVisited[pagesVisitedIndex], false); } } /** * called when page selection combo box selection is made. */ void WuQMultiPageDialog::slotPageSelectionComboBox(int item) { if (item >= 0) { for (int i = 0; i < pagesVector.count(); i++) { if (item == pagesVector[i]->pageComboBoxIndex) { showPage(pagesVector[i], true); } } } } /** * create and add a tool button to the dialog. */ QToolButton* WuQMultiPageDialog::addToolButton(const int toolBarNumber, const QString& buttonText, const QString& toolTipText, const QObject* receiver, const char* member) { if ((toolBarNumber < 0) || (toolBarNumber >= toolBarLayouts.size())) { std::cout << "ERROR WuQMultiPageDialog::addToolButton: " << "ToolBar number invalid." << std::endl; return NULL; } /* QToolButton* button = new QToolButton; button->setText(buttonText); button->setToolTip(toolTipText); QObject::connect(button, SIGNAL(clicked()), receiver, member); */ QToolButton* button = createToolButton(buttonText, toolTipText, receiver, member); addWidgetToToolBar(toolBarNumber, button); return button; } /** * Create a tool button. */ QToolButton* WuQMultiPageDialog::createToolButton(const QString& buttonText, const QString& toolTipText, const QObject* receiver, const char* member) { QToolButton* button = new QToolButton; button->setText(buttonText); button->setToolTip(toolTipText); QObject::connect(button, SIGNAL(clicked()), receiver, member); return button; } /** * add a widget to a toolbar. */ void WuQMultiPageDialog::addWidgetToToolBar(const int toolBarNumber, QWidget* widget) { if ((toolBarNumber < 0) || (toolBarNumber >= toolBarLayouts.size())) { std::cout << "ERROR WuQMultiPageDialog::addWidgetToToolBar: " << "ToolBar number invalid." << std::endl; return; } toolBarLayouts[toolBarNumber]->addWidget(widget); } /** * add a page. */ void WuQMultiPageDialog::addPage(const QString& pageName, WuQMultiPageDialogPage* page) { PageInfo* p = new PageInfo(pageName, page); switch (pageCreation) { case PAGE_CREATION_WHEN_DISPLAYED: break; case PAGE_CREATION_IMMEDIATELY: p->pageWidget = page->createPage(); pagesStackedWidget->addWidget(p->pageWidget); break; } pagesVector.push_back(p); } /** * show a page. */ void WuQMultiPageDialog::showPage(WuQMultiPageDialogPage* page) { const int num = pagesVector.size(); for (int i = 0; i < num; i++) { if (pagesVector[i]->dataPage == page) { showPage(pagesVector[i], true); break; } } } /** * show a page. */ void WuQMultiPageDialog::showPage(PageInfo* p, const bool updatePagesVisited) { if (p != NULL) { // // Create the page, if needed // if (p->pageWidget == NULL) { p->pageWidget = p->dataPage->createPage(); pagesStackedWidget->addWidget(p->pageWidget); } // // Update the page // p->dataPage->updatePage(); // // Show the page // pagesStackedWidget->setCurrentWidget(p->pageWidget); // // Set the page selection combo box to the current page // pageSelectionComboBox->blockSignals(true); pageSelectionComboBox->setCurrentIndex(p->pageComboBoxIndex); pageSelectionComboBox->blockSignals(false); if (updatePagesVisited) { // // Remove any pages "forward" of the current page index // const int numPages = static_cast(pagesVisited.size()); if ((pagesVisitedIndex >= 0) && (pagesVisitedIndex < (numPages - 1))) { pagesVisited.erase(pagesVisited.begin() + pagesVisitedIndex + 1, pagesVisited.end()); } // // Add new page // pagesVisited.push_back(p); pagesVisitedIndex = static_cast(pagesVisited.size() - 1); } // // Make dialog its minimum size so that no space is empty // pagesStackedWidget->setFixedSize(p->pageWidget->sizeHint()); pagesFrameWidget->setFixedSize(pagesFrameWidget->sizeHint()); setFixedSize(sizeHint()); } else { std::cout << "PROGRAM ERROR: No page to show in WuQMultiPageDialog::showPage" << std::endl; } // // Enable/Disable back and forward buttons // pageBackToolButton->setEnabled(pagesVisitedIndex > 0); pageForwardToolButton->setEnabled(pagesVisitedIndex < static_cast((pagesVisited.size() - 1))); } /** * show the dialog. */ void WuQMultiPageDialog::show() { if (firstTimeDialogShown) { firstTimeDialogShown = false; for (int i = 0; i < toolBarLayouts.size(); i++) { toolBarLayouts[i]->addStretch(); } if (defaultPage != NULL) { showPage(defaultPage); } } WuQDialog::show(); updateDialog(); } /** * set the default page. */ void WuQMultiPageDialog::setDefaultPage(WuQMultiPageDialogPage* defaultPageIn) { defaultPage = defaultPageIn; } //============================================================================= //============================================================================= //============================================================================= //============================================================================= //============================================================================= /** * constructor. */ WuQMultiPageDialogPage::WuQMultiPageDialogPage() { } /** * destructor. */ WuQMultiPageDialogPage::~WuQMultiPageDialogPage() { } caret-5.6.4~dfsg.1.orig/caret_widgets/WuQMessageBox.h0000664000175000017500000000754611572067322022264 0ustar michaelmichael #ifndef __GUI_MESSAGE_BOX_H__ #define __GUI_MESSAGE_BOX_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include /// class that extends QMessageBox to add enhancements class WuQMessageBox : public QMessageBox { Q_OBJECT public: // constructor WuQMessageBox(QWidget* parent = 0); // constructor WuQMessageBox(Icon icon, const QString& title, const QString& text, StandardButtons buttons = NoButton, QWidget* parent = 0, Qt::WindowFlags f = Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint); // destructor ~WuQMessageBox(); // set the window title void setTheWindowTitle(const QString& title); // information dialog static QMessageBox::StandardButton information(QWidget *parent, const QString &title, const QString &text, QMessageBox::StandardButtons buttons = Ok, QMessageBox::StandardButton defaultButton = QMessageBox::NoButton); // question dialog static QMessageBox::StandardButton question(QWidget *parent, const QString &title, const QString &text, QMessageBox::StandardButtons buttons = Ok, QMessageBox::StandardButton defaultButton = QMessageBox::NoButton); // warning dialog static QMessageBox::StandardButton warning(QWidget *parent, const QString &title, const QString &text, QMessageBox::StandardButtons buttons = Ok, QMessageBox::StandardButton defaultButton = QMessageBox::NoButton); // critical dialog static QMessageBox::StandardButton critical(QWidget *parent, const QString &title, const QString &text, QMessageBox::StandardButtons buttons = Ok, QMessageBox::StandardButton defaultButton = QMessageBox::NoButton); protected slots: // called to capture image of window and place it on the clipboard void slotMenuCaptureImageOfWindowToClipboard(); // called to capture image after timeout so nothing obscures window void slotCaptureImageAfterTimeOut(); protected: // called by parent when context menu event occurs virtual void contextMenuEvent(QContextMenuEvent*); // used by other static methods to create the dialog static QMessageBox::StandardButton showNewMessageBox(QWidget *parent, QMessageBox::Icon icon, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton); // Show the old message box static int showOldMessageBox(QWidget *parent, QMessageBox::Icon icon, const QString &title, const QString &text, int button0, int button1, int button2); }; #endif // __GUI_MESSAGE_BOX_H__ caret-5.6.4~dfsg.1.orig/caret_widgets/WuQMessageBox.cxx0000664000175000017500000001657711572067322022643 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include "WuQMessageBox.h" /** * constructor. */ WuQMessageBox::WuQMessageBox(QWidget* parent) : QMessageBox(parent) { } /** * constructor. */ WuQMessageBox::WuQMessageBox(Icon icon, const QString& title, const QString& text, StandardButtons buttons, QWidget* parent, Qt::WindowFlags f) : QMessageBox(icon, title, text, buttons, parent, f) { setTheWindowTitle(title); } /** * destructor. */ WuQMessageBox::~WuQMessageBox() { } /** * Set the window title. * Mac Guidelines say that a pop-up should not have a title so Qt's * implementation of QMessageBox has its own setWindowTitle() method * that overrides QDialog::setWindowTitle() to prevent the title * from showing up on a Mac. But, we want the title on Macs, and * this method does it! */ void WuQMessageBox::setTheWindowTitle(const QString& title) { QDialog::setWindowTitle(title); } /** * called to capture image after timeout so nothing obscures window. */ void WuQMessageBox::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 WuQMessageBox::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())); } /** * called by parent when context menu event occurs. */ void WuQMessageBox::contextMenuEvent(QContextMenuEvent* cme) { // // Popup menu for selection of pages // QMenu menu(this); // // Add menu item for image capture // menu.addAction("Capture Image to Clipboard", this, SLOT(slotMenuCaptureImageOfWindowToClipboard())); // // Popup the menu // menu.exec(cme->globalPos()); } QMessageBox::StandardButton WuQMessageBox::information(QWidget *parent, const QString &title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { return showNewMessageBox(parent, Information, title, text, buttons, defaultButton); } QMessageBox::StandardButton WuQMessageBox::question(QWidget *parent, const QString &title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { return showNewMessageBox(parent, Question, title, text, buttons, defaultButton); } QMessageBox::StandardButton WuQMessageBox::warning(QWidget *parent, const QString &title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { return showNewMessageBox(parent, Warning, title, text, buttons, defaultButton); } QMessageBox::StandardButton WuQMessageBox::critical(QWidget *parent, const QString &title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { return showNewMessageBox(parent, Critical, title, text, buttons, defaultButton); } /** * used by other static methods to create the dialog. */ QMessageBox::StandardButton WuQMessageBox::showNewMessageBox(QWidget *parent, QMessageBox::Icon icon, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { // necessary for source compatibility with Qt 4.0 and 4.1 // handles (Yes, No) and (Yes|Default, No) if (defaultButton && !(buttons & defaultButton)) { return (QMessageBox::StandardButton) showOldMessageBox(parent, icon, title, text, int(buttons), int(defaultButton), 0); } WuQMessageBox msgBox(icon, title, text, QMessageBox::NoButton, parent); msgBox.setTheWindowTitle(title); QDialogButtonBox *buttonBox = qFindChild(&msgBox); Q_ASSERT(buttonBox != 0); uint mask = QMessageBox::FirstButton; while (mask <= QMessageBox::LastButton) { uint sb = buttons & mask; mask <<= 1; if (!sb) continue; QPushButton *button = msgBox.addButton((QMessageBox::StandardButton)sb); // Choose the first accept role as the default if (msgBox.defaultButton()) continue; if ((defaultButton == QMessageBox::NoButton && buttonBox->buttonRole(button) == QDialogButtonBox::AcceptRole) || (defaultButton != QMessageBox::NoButton && sb == uint(defaultButton))) msgBox.setDefaultButton(button); } if (msgBox.exec() == -1) return QMessageBox::Cancel; return msgBox.standardButton(msgBox.clickedButton()); } /** * Show the old message box */ int WuQMessageBox::showOldMessageBox(QWidget *parent, QMessageBox::Icon icon, const QString &title, const QString &text, int button0, int button1, int button2) { int butts[3] = { button0, button1, button2 }; QMessageBox::StandardButtons buttons; for (int i = 0; i < 3; i++) { switch (butts[i]) { case QMessageBox::YesAll: buttons |= QMessageBox::YesToAll; break; case QMessageBox::NoAll: buttons |= QMessageBox::NoToAll; break; default: buttons |= static_cast(butts[i]); break; } } WuQMessageBox messageBox(icon, title, text, buttons, parent); return messageBox.exec(); } caret-5.6.4~dfsg.1.orig/caret_widgets/WuQFileDialogIcons.h0000664000175000017500000002111211572067322023203 0ustar michaelmichael #ifndef __CARET_FILE_DIALOG_ICONS_H__ #define __CARET_FILE_DIALOG_ICONS_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ /**************************************************************************** ** ** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved. ** ** This file is part of the Qt3Support module of the Qt Toolkit. ** ** This file may be used under the terms of the GNU General Public ** License version 2.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 GNU ** General Public Licensing requirements will be met: ** http://www.trolltech.com/products/qt/opensource.html ** ** If you are unsure which license is appropriate for your use, please ** review the following information: ** http://www.trolltech.com/products/qt/licensing.html or contact the ** sales department at sales@trolltech.com. ** ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ** ****************************************************************************/ static const char * const goto_xpm [] = { "17 17 3 1", "a c #00FF00", "# c #000000", ". c None", ".................", ".......aaa.......", "......aaaaa......", "....aaaaaaaaa....", "...aaaaaaaaaaa...", "..aaaaaaaaaaaaa..", "..aaaaaaaaaaaaa..", ".aaaaaaaaaaaaaaa.", ".aaaaaaaaaaaaaaa.", "..aaaaaaaaaaaaa..", "..aaaaaaaaaaaaa..", "...aaaaaaaaaaa...", "....aaaaaaaaa....", "......aaaaa......", ".......aaa.......", ".................", "................." }; /* XPM */ static const char * const back_xpm [] = { "13 11 3 1", "a c #ffff99", "# c #000000", ". c None", ".....#.......", "....##.......", "...#a#.......", "..#aa########", ".#aaaaaaaaaa#", "#aaaaaaaaaaa#", ".#aaaaaaaaaa#", "..#aa########", "...#a#.......", "....##.......", ".....#......." }; /* XPM */ static const char * const forward_xpm [] = { "13 11 3 1", "a c #ffff99", "# c #000000", ". c None", ".......#.....", ".......##....", ".......#a#...", "########aa#..", "#aaaaaaaaaa#.", "#aaaaaaaaaaa#", "#aaaaaaaaaa#.", "########aa#..", ".......#a#...", ".......##....", ".......#....." }; static const char * const up_xpm[] = { "13 11 3 1", "a c #ffff99", "# c #000000", ". c None", "......#......", ".....#a#.....", "....#aaa#....", "...#aaaaa#...", "..#aaaaaaa#..", ".###aaaaa###.", "....#aaa#....", "....#aaa#....", "....#aaa#....", "....#aaa#....", "....#####...." }; static const char * const trash_xpm[] = { "14 15 3 1", "a c #ffff99", "# c #000000", ". c None", ".....####.....", ".....####.....", "##############", "##############", "..##########..", "..#aa#aa#aa#..", "..#aa#aa#aa#..", "..#aa#aa#aa#..", "..#aa#aa#aa#..", "..#aa#aa#aa#..", "..#aa#aa#aa#..", "..#aa#aa#aa#..", "..#aa#aa#aa#..", ".,##########..", ".............." }; static const char * const rename_xpm[] = { "29 11 2 1", "# c #000000", ". c None", ".......#........###########..", ".......##.......###......###.", ".......#a#......###.......###", "########aa#.....###.......###", "#aaaaaaaaaa#....###......###.", "#aaaaaaaaaaa#...############.", "#aaaaaaaaaa#....###......###.", "########aa#.....###.......###", ".......#a#......###.......###", ".......##.......###......###.", ".......#........###########.." }; /* XPM */ static const char * const refresh_xpm [] = { "25 19 3 1", "a c #ffff99", "# c #000000", ". c None", "..####################...", "..##aaaaaaaaaaaaaaaa##...", "..##aaaaaaaaaaaaaaaa##...", "..###############aaa##...", "...............##aaa##...", "...............##aaa##...", "............##aaaaaaaaa##", "......#......##aaaaaaa##.", "....##a##.....##aaaaa##..", "...##aaa##.....##aaa##...", "..##aaaaa##.....##a##....", ".##aaaaaaa##......#......", "##aaaaaaaaa##............", "...##aaa##...............", "...##aaa##...............", "...##aaa###############..", "...##aaaaaaaaaaaaaaaa##..", "...##aaaaaaaaaaaaaaaa##..", "...####################.." /* "..........##aaa##........", "...........##aaa##.......", "............##aaa##......", ".............##aaa##.....", "..............##aaa##....", "...............##aaa##...", "............##aaaaaaaaa##", "......#......##aaaaaaa##.", "....##a##.....##aaaaa##..", "...##aaa##.....##aaa##...", "..##aaaaa##.....##a##....", ".##aaaaaaa##......#......", "##aaaaaaaaa##............", "...##aaa##...............", "....##aaa##..............", ".....##aaa##.............", "......##aaa##............", ".......##aaa##...........", "........##aaa##.........." */ }; /* XPM */ static const char* const cdtoparent_xpm[]={ "15 13 3 1", ". c None", "* c #000000", "a c #ffff99", "..*****........", ".*aaaaa*.......", "***************", "*aaaaaaaaaaaaa*", "*aaaa*aaaaaaaa*", "*aaa***aaaaaaa*", "*aa*****aaaaaa*", "*aaaa*aaaaaaaa*", "*aaaa*aaaaaaaa*", "*aaaa******aaa*", "*aaaaaaaaaaaaa*", "*aaaaaaaaaaaaa*", "***************" }; /* XPM */ static const char* const newfolder_xpm[] = { "15 14 4 1", " c None", ". c #000000", "+ c #FFFF00", "@ c #FFFFFF", " . ", " ", " . ", " . . ", " .... . . . ", " .+@+@. . . ", ".......... . .", ".@+@+@+@+@.. ", ".+@+@+@+@+. . ", ".@+@+@+@+@. . ", ".+@+@+@+@+. ", ".@+@+@+@+@. ", ".+@+@+@+@+. ", "........... " }; /* XPM */ static const char* const mclistview_xpm[]={ "15 11 4 1", "* c None", "b c #000000", ". c #000099", "a c #ffffff", "...*****...****", ".a.*bbb*.a.*bbb", "...*****...****", "***************", "...*****...****", ".a.*bbb*.a.*bbb", "...*****...****", "***************", "...*****...****", ".a.*bbb*.a.*bbb", "...*****...****" }; /* XPM */ static const char* const detailedview_xpm[]={ "14 11 3 1", ". c None", "* c #000000", "a c #000099", ".****.***.***.", "..............", "aaaaaaaaaaaaaa", "..............", ".****.***.***.", "..............", ".****.***.***.", "..............", ".****.***.***.", "..............", ".****.***.***." }; /* XPM */ static const char* const file_xpm[]={ "16 16 5 1", ". c #7f7f7f", "# c None", "c c #000000", "b c #bfbfbf", "a c #ffffff", "################", "..........######", ".aaaaaaaab.#####", ".aaaaaaaaba.####", ".aaaaaaaacccc###", ".aaaaaaaaaabc###", ".aaaaaaaaaabc###", ".aaaaaaaaaabc###", ".aaaaaaaaaabc###", ".aaaaaaaaaabc###", ".aaaaaaaaaabc###", ".aaaaaaaaaabc###", ".aaaaaaaaaabc###", ".aaaaaaaaaabc###", ".bbbbbbbbbbbc###", "ccccccccccccc###" }; static const char * const folder_xpm[]={ "16 16 6 1", ". c None", "b c #ffff00", "d c #000000", "* c #999999", "a c #cccccc", "c c #ffffff", "................", "................", "..*****.........", ".*ababa*........", "*abababa******..", "*cccccccccccc*d.", "*cbababababab*d.", "*cabababababa*d.", "*cbababababab*d.", "*cabababababa*d.", "*cbababababab*d.", "*cabababababa*d.", "*cbababababab*d.", "**************d.", ".dddddddddddddd.", "................" }; #endif // __CARET_FILE_DIALOG_ICONS_H__ caret-5.6.4~dfsg.1.orig/caret_widgets/WuQFileDialog.h0000664000175000017500000004243111572067322022216 0ustar michaelmichael #ifndef __WU_Q_FILE_DIALOG_H__ #define __WU_Q_FILE_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ /**************************************************************************** ** ** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved. ** ** This file is part of the Qt3Support module of the Qt Toolkit. ** ** This file may be used under the terms of the GNU General Public ** License version 2.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 GNU ** General Public Licensing requirements will be met: ** http://www.trolltech.com/products/qt/opensource.html ** ** If you are unsure which license is appropriate for your use, please ** review the following information: ** http://www.trolltech.com/products/qt/licensing.html or contact the ** sales department at sales@trolltech.com. ** ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ** ****************************************************************************/ #include #include #include #include "WuQDialog.h" class QAbstractButton; class QAction; class QByteArray; class QComboBox; class QFileSystemWatcher; class QGridLayout; class QHBoxLayout; class QLabel; class QLayout; class QLineEdit; class QListWidget; class QListWidgetItem; class QPushButton; class QSplitter; class QStackedWidget; class QTreeWidget; class QTreeWidgetItem; class QVBoxLayout; /// class for a useful, extendable file selection dialog class WuQFileDialog : public WuQDialog { Q_OBJECT public: /// type used for mapping file extensions to file type names typedef QMap TypeExtensionToTypeNameMap; /// opening or closing a file enum AcceptMode { AcceptOpen, AcceptSave }; /// enum used to set dialog button or label texts enum DialogLabel { LookIn, FileName, FileType, Accept, Reject }; /// determines what user may select and what dialog returns if accepted enum FileMode { /// name of file, whether it exists or not AnyFile, /// name of a single existing file ExistingFile, /// name of a directory and both files and directories are displayed Directory, /// names of zero or more existing files ExistingFiles, /// name of a directory and only directories are displayed DirectoryOnly }; enum Option { ShowDirsOnly = 0x01, DontResolveSymlinks = 0x02, DontConfirmOverwrite = 0x04, DontUseSheet = 0x08, DontUseNativeDialog = 0x10 }; typedef unsigned int Options; enum ViewMode { Detail, List }; // constructor WuQFileDialog(QWidget* parent, Qt::WindowFlags f); // constructor WuQFileDialog(QWidget* parent = 0, const QString& caption = QString(), const QString& directory = QString(), const QString& filter = QString()); // destructor ~WuQFileDialog(); /// get the accept mode AcceptMode acceptMode() const { return theAcceptMode; } /// get confirm overwrite bool confirmOverwrite() const { return confirmOverwriteFlag; } /// get the default suffix QString defaultSuffix() const { return theDefaultSuffix; } /// get the directory QDir directory() const; /// get the file mode FileMode fileMode() const { return theFileMode; } /// get the file filters QStringList filters() const; /// get the history (previous directories) QStringList history() const; /// get read only status bool isReadOnly() const { return readOnlyFlag; } /// get label text QString labelText(const DialogLabel label) const; // returns file filters that match the name virtual QStringList matchingFilters(const QString& name); // restores the dialog's layout, history and current directory to the state specified // returns false if there are errors bool restoreState(const QByteArray& state); // saves the state of the dialog's layout, history, current directory QByteArray saveState() const; /// select a file void selectFile(const QString& name); /// select the file filter void selectFilter(const QString& filter); // get the selected files QStringList selectedFiles() const; // get the selected file filter QString selectedFilter() const; // set the accept mode void setAcceptMode(const AcceptMode mode); /// set confirm overwrite void setConfirmOverwrite(const bool enabled) { confirmOverwriteFlag = enabled; } /// set the default suffix void setDefaultSuffix(const QString& suffix) { theDefaultSuffix = suffix; } // set the directory void setDirectory(const QString& dir); // set the directory void setDirectory(const QDir& dir); // set the file mode void setFileMode(const FileMode mode); // sets file filters void setFilter(const QString& filterName); // set the file filters void setFilters(const QStringList& filters); // set the history (previous paths) void setHistory(const QStringList& paths); // set the label text void setLabelText(const DialogLabel label, const QString& text); // set read only void setReadOnly(const bool enabled); // set the sidebar URLS void setSidebarUrls(const QList& urls); // set the view mode void setViewMode(const ViewMode viewMode); // get sidebar Urls QList sidebarUrls() const; // get the view mode ViewMode viewMode() const; // modal method to get open file name static QString getOpenFileName(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 getSaveFileName(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 directory name static QString getExistingDirectory(QWidget *parent = 0, const QString &caption = QString(), const QString &dir = QString(), Options options = ShowDirsOnly); // modal method to get open file names static QStringList getOpenFileNames(QWidget *parent = 0, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = 0, Options options = 0); // initialize the default file extension to type name map static void initializeFileExtensionToTypeNameMap(); /// get the file extension to type name map static TypeExtensionToTypeNameMap getFileExtensionToTypeNameMap() { return fileExtensionToTypeNameMap; } /// set the file extension to type name map static void setFileExtensionToTypeNameMap(const TypeExtensionToTypeNameMap& typeMap) { fileExtensionToTypeNameMap = typeMap; } signals: // When the current file changes, this signal is emitted with the new file // as the path paramter void currentChanged(const QString&); // This signal is emitted when the user enters a directory void directoryEntered(const QString&); // When the selection changes, this signal is emitted with the (possibly // empty) list of selected files void filesSelected(const QStringList&); // This signal is emitted when the user selects a filter void filterSelected(const QString&); public slots: // Rereads the current directory shown in the file dialog void rereadDir(); protected: // add a widgets to the dialog void addWidgets(QWidget* leftColumn, QWidget* centerColumn, QWidget* rightColumn); // add a toolbutton to the dialog void addToolButton(QAbstractButton* b, const bool separator = false); private slots: // called when navigation back tool button clicked void slotNavigationBackAction(); // called when navigation forward tool button clicked void slotNavigationForwardAction(); // called when navigation up tool button clicked void slotNavigationUpAction(); // called when navigation go to directory tool button clicked void slotNavigationGoToDirectoryAction(); // called when navigation refresh tool button clicked void slotNavigationRefreshAction(); // called when case sensitive tool button clicked void slotNavigationCaseSensitiveAction(); // called when show hidden files tool button clicked void slotNavigationShowHiddenFilesAction(); // called when navigation new directory tool button clicked void slotNavigationNewDirectoryAction(); // called when navigation delete file tool button clicked void slotNavigationDeleteFileAction(); // called when navigation rename file tool button clicked void slotNavigationRenameFileAction(); // called when navigation view tool button clicked void slotNavigationViewActionTriggered(QAction*); // called when a common directory item selected void slotCommonDirectoryListWidget(QListWidgetItem*); // called when a file selection list widget item clicked void slotFileSelectionListWidgetItemClicked(QListWidgetItem*); // called when a file selection list widget item double clicked void slotFileSelectionListWidgetItemDoubleClicked(QListWidgetItem*); // called when a file selection tree widget item clicked void slotFileSelectionTreeWidgetItemClicked(QTreeWidgetItem*, int); // called when a file selection tree widget item double clicked void slotFileSelectionTreeWidgetItemDoubleClicked(QTreeWidgetItem*, int); // called when a navigation history selection is made void slotNavigationHistoryComboBox(const QString&); // called when accept button is pressed void slotAcceptPushButton(); // called when reject button is pressed void slotRejectPushButton(); // called when file type combo box selection is made void slotFileTypeComboBox(const QString&); // called when file name line edit is changed void slotFileNameLineEditChanged(const QString&); private: // add to common directory void addToCommonDirectory(const QString& directoryPath, const QString& labelName); // initialize the dialog void initializeDialog(); // update the title, labels, and buttons void updateTitleLabelsButtons(); // update selected file line edit void updateSelectedFileLineEdit(const QString& s); // create the navigation section of the dialog QLayout* createNavigationSection(); // create the common directory section of the dialog QWidget* createCommonDirectorySection(); // create the file selection section of the dialog QWidget* createFileSelectionSection(); // load the common directory section void loadCommonDirectorySection(); // set the directory void setDirectory(const QString& dirPath, const bool selectionFromHistoryFlag); /// file name line edit QLineEdit* fileNameLineEdit; /// file type combo box QComboBox* fileTypeComboBox; /// accept push button QPushButton* acceptPushButton; /// reject push button QPushButton* rejectPushButton; /// look in label QLabel* lookInLabel; /// file name label QLabel* fileNameLabel; /// file type label; QLabel* fileTypeLabel; /// navigation history combo box QComboBox* navigationHistoryComboBox; /// list widget for common directories QListWidget* commonDirectoryListWidget; /// layout for labels, combo boxes, and push buttons QGridLayout* nameFilterButtonsGridLayout; /// index of first sidebar URL in "commonDirectoryListWidget" int firstSideBarUrlIndex; /// stacked widget for file name list and detail views QStackedWidget* fileListAndDetailStackedWidget; /// file selection list widget QListWidget* fileSelectionListWidget; /// file selection tree widget QTreeWidget* fileSelectionTreeWidget; /// width has already been set for name in tree bool fileSelectionTreeNameWidthAdjustedFlag; /// navigation toolbutton layout QHBoxLayout* navigationToolButtonLayout; /// navigation back action QAction* navigationBackAction; /// navigation forward action QAction* navigationForwardAction; /// navigation up action QAction* navigationUpAction; /// navigation go to directory action QAction* navigationGoToDirectoryAction; /// navigation refresh action QAction* navigationRefreshAction; /// navigation case sensitive action QAction* navigationCaseSensitiveFileAction; /// navigation show hidden files action QAction* navigationShowHiddensFilesAction; /// navigation new directory action QAction* navigationNewDirectoryAction; /// delete file action QAction* navigationDeleteFileAction; /// rename the file action QAction* navigationRenameFileAction; /// navigation list view action QAction* navigationListViewAction; /// navigation detail view tool button QAction* navigationDetailViewAction; /// the directory being navigated QDir theDirectory; /// the accept mode AcceptMode theAcceptMode; /// confirm overwrite flag bool confirmOverwriteFlag; /// the default suffix QString theDefaultSuffix; /// the file mode FileMode theFileMode; /// user set label for "look in" bool userSetLookInLabel; /// user set label for "file name" bool userSetFileNameLabel; /// user set label for "file type" bool userSetFileTypeLabel; /// user set label for "accept" bool userSetAcceptLabel; /// user set label for "reject" bool userSetRejectLabel; /// read only flag bool readOnlyFlag; /// the file system watcher QFileSystemWatcher* fileSystemWatcher; /// splits between side bar and files QSplitter* dirFileSplitter; /// the debugging flag bool debugFlag; /// the map that maps file extensions to type names static TypeExtensionToTypeNameMap fileExtensionToTypeNameMap; }; #ifdef _WU_Q_FILE_DIALOG_MAIN_H_ WuQFileDialog::TypeExtensionToTypeNameMap WuQFileDialog::fileExtensionToTypeNameMap; #endif // _WU_Q_FILE_DIALOG_MAIN_H_ #endif // __WU_Q_FILE_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret_widgets/WuQFileDialog.cxx0000664000175000017500000021132311572067322022567 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ /**************************************************************************** ** ** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved. ** ** This file is part of the Qt3Support module of the Qt Toolkit. ** ** This file may be used under the terms of the GNU General Public ** License version 2.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 GNU ** General Public Licensing requirements will be met: ** http://www.trolltech.com/products/qt/opensource.html ** ** If you are unsure which license is appropriate for your use, please ** review the following information: ** http://www.trolltech.com/products/qt/licensing.html or contact the ** sales department at sales@trolltech.com. ** ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ** ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "DateAndTime.h" #define _WU_Q_FILE_DIALOG_MAIN_H_ #include "WuQFileDialog.h" #include "WuQFileDialogIcons.h" #undef _WU_Q_FILE_DIALOG_MAIN_H_ static const qint32 WUQFileDialogMagic = 0x57554644; //'WUFD'; static const qint32 WUQFileDialogVersion = 1; /** * constructor. */ WuQFileDialog::WuQFileDialog(QWidget* parent, Qt::WindowFlags f) : WuQDialog(parent, f) { initializeDialog(); } /** * constructor. */ WuQFileDialog::WuQFileDialog(QWidget* parent, const QString& caption, const QString& directoryName, const QString& filter) : WuQDialog(parent, 0) { initializeDialog(); if (caption.isEmpty() == false) { setWindowTitle(caption); } if (directoryName.isEmpty() == false) { setDirectory(directoryName); } if (filter.isEmpty() == false) { setFilter(filter); } } /** * initialize the dialog. */ void WuQFileDialog::initializeDialog() { debugFlag = false; confirmOverwriteFlag = true; theFileMode = AnyFile; theDefaultSuffix = ""; firstSideBarUrlIndex = 500000; readOnlyFlag = false; userSetLookInLabel = false; userSetFileNameLabel = false; userSetFileTypeLabel = false; userSetAcceptLabel = false; userSetRejectLabel = false; fileSelectionTreeNameWidthAdjustedFlag = false; // // Create the file system watcher // fileSystemWatcher = new QFileSystemWatcher(this); QObject::connect(fileSystemWatcher, SIGNAL(directoryChanged(const QString&)), this, SLOT(rereadDir())); // // Initialize the directory // theDirectory.setPath(QDir::currentPath()); // // file name line edit and file type combo box // fileNameLineEdit = new QLineEdit; QObject::connect(fileNameLineEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotFileNameLineEditChanged(const QString&))); fileTypeComboBox = new QComboBox; QObject::connect(fileTypeComboBox, SIGNAL(activated(const QString&)), this, SLOT(slotFileTypeComboBox(const QString&))); QObject::connect(fileTypeComboBox, SIGNAL(activated(const QString&)), this, SIGNAL(filterSelected(const QString&))); // // Labels // fileNameLabel = new QLabel(""); fileTypeLabel = new QLabel(""); // // push buttons // acceptPushButton = new QPushButton(""); acceptPushButton->setAutoDefault(true); QObject::connect(acceptPushButton, SIGNAL(clicked()), this, SLOT(slotAcceptPushButton())); rejectPushButton = new QPushButton(""); QObject::connect(rejectPushButton, SIGNAL(clicked()), this, SLOT(slotRejectPushButton())); // // Splitter for common directory and file lists // dirFileSplitter = new QSplitter; dirFileSplitter->addWidget(createCommonDirectorySection()); dirFileSplitter->addWidget(createFileSelectionSection()); dirFileSplitter->setStretchFactor(0, 1); dirFileSplitter->setStretchFactor(1, 1000); // // Layout file name, filter, buttons, additional widgets // nameFilterButtonsGridLayout = new QGridLayout; nameFilterButtonsGridLayout->addWidget(fileNameLabel, 0, 0, Qt::AlignLeft); nameFilterButtonsGridLayout->addWidget(fileNameLineEdit, 0, 1); nameFilterButtonsGridLayout->addWidget(acceptPushButton, 0, 2); nameFilterButtonsGridLayout->addWidget(fileTypeLabel, 1, 0, Qt::AlignLeft); nameFilterButtonsGridLayout->addWidget(fileTypeComboBox, 1, 1); nameFilterButtonsGridLayout->addWidget(rejectPushButton, 1, 2); // // Layout the dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->addLayout(createNavigationSection()); dialogLayout->addWidget(dirFileSplitter); dialogLayout->addLayout(nameFilterButtonsGridLayout); setAcceptMode(AcceptOpen); // // Initialize the dialog // loadCommonDirectorySection(); QStringList filterList; filterList << "*"; setFilters(filterList); setDirectory(theDirectory.absolutePath(), false); slotFileNameLineEditChanged(""); updateTitleLabelsButtons(); // // Initialize file extension to type map // static bool firstTime = true; if (firstTime) { initializeFileExtensionToTypeNameMap(); firstTime = false; } // // Place into current directory // setDirectory(QDir::currentPath()); } /** * destructor. */ WuQFileDialog::~WuQFileDialog() { } /** * modal method to get open file name. */ QString WuQFileDialog::getOpenFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, Options /*options*/) { QString name; WuQFileDialog cfd(parent); cfd.setWindowTitle(caption); cfd.setDirectory(dir); cfd.setFilters(filter.split(";;", QString::SkipEmptyParts)); cfd.setFileMode(ExistingFile); cfd.setAcceptMode(AcceptOpen); cfd.rereadDir(); if (cfd.exec() == Accepted) { if (cfd.selectedFiles().count() > 0) { name = cfd.selectedFiles().at(0); if (selectedFilter != NULL) { (*selectedFilter) = cfd.selectedFilter(); } } } return name; } /** * modal method to get save file name. */ QString WuQFileDialog::getSaveFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, Options options) { QString name; WuQFileDialog cfd(parent); cfd.setWindowTitle(caption); cfd.setDirectory(dir); cfd.setFilters(filter.split(";;", QString::SkipEmptyParts)); cfd.setFileMode(AnyFile); cfd.setAcceptMode(AcceptSave); if (options & DontConfirmOverwrite) { cfd.setConfirmOverwrite(false); } cfd.rereadDir(); if (cfd.exec() == Accepted) { if (cfd.selectedFiles().count() > 0) { name = cfd.selectedFiles().at(0); if (selectedFilter != NULL) { (*selectedFilter) = cfd.selectedFilter(); } } } return name; } /** * modal method to get directory name. */ QString WuQFileDialog::getExistingDirectory(QWidget *parent, const QString &caption, const QString &dir, Options options) { QString name; WuQFileDialog cfd(parent); cfd.setWindowTitle(caption); cfd.setDirectory(dir); if (options & ShowDirsOnly) { cfd.setFileMode(DirectoryOnly); } else { cfd.setFileMode(Directory); } cfd.rereadDir(); if (cfd.exec() == Accepted) { name = cfd.directory().absolutePath(); } return name; } /** * modal method to get open file names. */ QStringList WuQFileDialog::getOpenFileNames(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, Options /*options*/) { QStringList names; WuQFileDialog cfd(parent); cfd.setWindowTitle(caption); cfd.setDirectory(dir); cfd.setFilters(filter.split(";;", QString::SkipEmptyParts)); cfd.setFileMode(ExistingFile); cfd.setAcceptMode(AcceptOpen); cfd.rereadDir(); if (cfd.exec() == Accepted) { if (cfd.selectedFiles().count() > 0) { names = cfd.selectedFiles(); if (selectedFilter != NULL) { (*selectedFilter) = cfd.selectedFilter(); } } } return names; } /** * called when accept button is pressed. */ void WuQFileDialog::slotAcceptPushButton() { if (debugFlag) { std::cout << "Selected Directory: {" << directory().absolutePath().toAscii().constData() << "}" << std::endl; } bool fileFlag = false; switch (fileMode()) { case AnyFile: fileFlag = true; break; case ExistingFile: fileFlag = true; break; case Directory: break; case ExistingFiles: fileFlag = true; break; case DirectoryOnly: break; } if (fileFlag) { if (selectedFiles().count() <= 0) { QMessageBox::critical(this, tr("Error"), tr("No file selected"), QMessageBox::Ok); return; } switch (acceptMode()) { case AcceptOpen: break; case AcceptSave: if (confirmOverwrite()) { QFileInfo fi(selectedFiles().at(0)); if (fi.exists()) { QString fileName = fi.fileName(); const QString message(fileName + tr(" already exists.\n") + tr("Do you want to replace it?")); const QMessageBox::StandardButton buttonPressed = QMessageBox::warning(this, tr("Overwrite File"), message, QMessageBox::Yes | QMessageBox::No); if (buttonPressed == QMessageBox::No) { return; } } } break; } } accept(); /* if (isModal()) { accept(); } else { close(); } */ } /** * called when reject button is pressed. */ void WuQFileDialog::slotRejectPushButton() { reject(); /* if (isModal()) { reject(); } else { close(); } */ } /** * called when file name line edit is changed. */ void WuQFileDialog::slotFileNameLineEditChanged(const QString& text) { bool dirFlag = false; bool fileFlag = false; bool renameFlag = false; switch (fileMode()) { case AnyFile: case ExistingFile: case ExistingFiles: if (text.isEmpty() == false) { fileFlag = true; } renameFlag = (selectedFiles().count() == 1); break; case Directory: case DirectoryOnly: dirFlag = true; break; } acceptPushButton->setEnabled(dirFlag || fileFlag); navigationDeleteFileAction->setEnabled(fileFlag && (readOnlyFlag == false)); navigationRenameFileAction->setEnabled(fileFlag && renameFlag && (readOnlyFlag == false)); } /** * get the directory. */ QDir WuQFileDialog::directory() const { QDir dirOut = theDirectory; switch (fileMode()) { case AnyFile: case ExistingFile: case ExistingFiles: break; case Directory: case DirectoryOnly: { if (fileListAndDetailStackedWidget->currentWidget() == fileSelectionListWidget) { const QList selItems = fileSelectionListWidget->selectedItems(); if (selItems.count() > 0) { const QListWidgetItem* item = selItems.at(0); const QString name(item->data(Qt::UserRole).toString()); QFileInfo fi(theDirectory, name); if (fi.isDir()) { dirOut = QDir(fi.absoluteFilePath()); } } } else if (fileListAndDetailStackedWidget->currentWidget() == fileSelectionTreeWidget) { const QList selItems = fileSelectionTreeWidget->selectedItems(); if (selItems.count() > 0) { const QTreeWidgetItem* item = selItems.at(0); const QString name(item->data(0, Qt::UserRole).toString()); QFileInfo fi(theDirectory, name); if (fi.isDir()) { dirOut = QDir(fi.absoluteFilePath()); } } } } } return dirOut; } /** * get the selected files. */ QStringList WuQFileDialog::selectedFiles() const { QStringList fileList; const QString s = fileNameLineEdit->text().trimmed(); if (s.isEmpty() == false) { int firstQuoteIndex = s.indexOf('"'); if (firstQuoteIndex >= 0) { const QStringList sl = s.split('"'); for (int i = 0; i < sl.count(); i++) { const QString s = sl.at(i).trimmed(); if (s.isEmpty() == false) { if (s != "\"") { fileList << s; } } } } else { fileList << s; } } // // Insert directory into each file name // for (int i = 0; i < fileList.count(); i++) { QFileInfo fi(theDirectory, fileList.at(i)); fileList[i] = fi.absoluteFilePath(); } // // May need to add default suffix if saving // if (theDefaultSuffix.isEmpty() == false) { switch (acceptMode()) { case AcceptOpen: break; case AcceptSave: for (int i = 0; i < fileList.count(); i++) { if (fileList[i].endsWith(theDefaultSuffix) == false) { fileList[i] += theDefaultSuffix; } } break; } } return fileList; } /** * update selected file line edit. */ void WuQFileDialog::updateSelectedFileLineEdit(const QString& s) { fileNameLineEdit->setText(s); emit filesSelected(selectedFiles()); if (selectedFiles().count() > 0) { emit currentChanged(selectedFiles().at(0)); } else { emit currentChanged(""); } } /** * update the title, labels, and buttons. */ void WuQFileDialog::updateTitleLabelsButtons() { // // Set any buttons and labels that have not been set by the user // if (userSetLookInLabel == false) { lookInLabel->setText(tr("Look In")); } if (userSetFileNameLabel == false) { fileNameLabel->setText(tr("File Name")); } if (userSetFileTypeLabel == false) { fileTypeLabel->setText(tr("File Type")); } if (userSetRejectLabel == false) { rejectPushButton->setText(tr("Cancel")); } if (userSetAcceptLabel == false) { switch (fileMode()) { case AnyFile: case ExistingFile: case ExistingFiles: switch (acceptMode()) { case AcceptOpen: acceptPushButton->setText(tr("Open")); break; case AcceptSave: acceptPushButton->setText(tr("Save")); break; } break; case Directory: case DirectoryOnly: acceptPushButton->setText(tr("Choose")); break; } } const QString openModeTitle(tr("Open")); const QString saveModeTitle(tr("Save")); const QString directoryModeTitle(tr("Find Directory")); if (windowTitle().isEmpty() || (windowTitle() == openModeTitle) || (windowTitle() == saveModeTitle) || (windowTitle() == directoryModeTitle)) { switch (fileMode()) { case AnyFile: case ExistingFile: case ExistingFiles: switch (theAcceptMode) { case AcceptOpen: setWindowTitle(openModeTitle); break; case AcceptSave: setWindowTitle(saveModeTitle); break; } break; case Directory: case DirectoryOnly: setWindowTitle(directoryModeTitle); break; } } } /** * set the accept mode. */ void WuQFileDialog::setAcceptMode(const AcceptMode mode) { theAcceptMode = mode; updateTitleLabelsButtons(); } /** * get label text. */ QString WuQFileDialog::labelText(const DialogLabel label) const { QString text; switch (label) { case LookIn: text = lookInLabel->text(); break; case FileName: text = fileNameLabel->text(); break; case FileType: text = fileTypeLabel->text(); break; case Accept: text = acceptPushButton->text(); break; case Reject: text = rejectPushButton->text(); break; } return text; } /** * set the label text. */ void WuQFileDialog::setLabelText(const DialogLabel label, const QString& text) { switch (label) { case LookIn: lookInLabel->setText(text); userSetLookInLabel = true; break; case FileName: fileNameLabel->setText(text); userSetFileNameLabel = true; break; case FileType: fileTypeLabel->setText(text); userSetFileTypeLabel = true; break; case Accept: acceptPushButton->setText(text); userSetAcceptLabel = true; break; case Reject: rejectPushButton->setText(text); userSetRejectLabel = true; break; } updateTitleLabelsButtons(); } /** * create the navigation section of the dialog. */ QLayout* WuQFileDialog::createNavigationSection() { // // combo box for navigation history // navigationHistoryComboBox = new QComboBox; navigationHistoryComboBox->setInsertPolicy(QComboBox::InsertAtTop); QObject::connect(navigationHistoryComboBox, SIGNAL(activated(const QString&)), this, SLOT(slotNavigationHistoryComboBox(const QString&))); // // back tool button // navigationBackAction = new QAction(this); navigationBackAction->setToolTip(tr("Go Back To\n" "Previous\n" "Directory")); navigationBackAction->setIcon(QPixmap(back_xpm)); QObject::connect(navigationBackAction, SIGNAL(triggered(bool)), this, SLOT(slotNavigationBackAction())); QToolButton* navigationBackToolButton = new QToolButton; navigationBackToolButton->setDefaultAction(navigationBackAction); // // forward tool button // navigationForwardAction = new QAction(this); navigationForwardAction->setToolTip(tr("Go Forward\n" "To Directory")); navigationForwardAction->setIcon(QPixmap(forward_xpm)); QObject::connect(navigationForwardAction, SIGNAL(triggered(bool)), this, SLOT(slotNavigationForwardAction())); QToolButton* navigationForwardToolButton = new QToolButton; navigationForwardToolButton->setDefaultAction(navigationForwardAction); // // up tool button // navigationUpAction = new QAction(this); navigationUpAction->setToolTip(tr("Go Up To Parent\n" "Directory")); navigationUpAction->setIcon(QPixmap(up_xpm)); QObject::connect(navigationUpAction, SIGNAL(triggered(bool)), this, SLOT(slotNavigationUpAction())); QToolButton* navigationUpToolButton = new QToolButton; navigationUpToolButton->setDefaultAction(navigationUpAction); // // go to directory tool button // navigationGoToDirectoryAction = new QAction(this); navigationGoToDirectoryAction->setText("Dir"); navigationGoToDirectoryAction->setToolTip(tr("Enter") + "\n" + tr("Directory") + "\n" + tr("Name")); //navigationGoToDirectoryAction->setIcon(QPixmap(goto_xpm)); QObject::connect(navigationGoToDirectoryAction, SIGNAL(triggered(bool)), this, SLOT(slotNavigationGoToDirectoryAction())); QToolButton* navigationGoToDirectoryToolButton = new QToolButton; navigationGoToDirectoryToolButton->setDefaultAction(navigationGoToDirectoryAction); // // refresh tool button // navigationRefreshAction = new QAction(this); navigationRefreshAction->setToolTip(tr("Refresh the\n" "File Listing")); navigationRefreshAction->setIcon(QPixmap(refresh_xpm)); QObject::connect(navigationRefreshAction, SIGNAL(triggered(bool)), this, SLOT(slotNavigationRefreshAction())); QToolButton* navigationRefreshToolButton = new QToolButton; navigationRefreshToolButton->setDefaultAction(navigationRefreshAction); // // new directory tool button // navigationNewDirectoryAction = new QAction(this); navigationNewDirectoryAction->setToolTip(tr("Create New\n" "Directory")); navigationNewDirectoryAction->setIcon(QPixmap(newfolder_xpm)); QObject::connect(navigationNewDirectoryAction, SIGNAL(triggered(bool)), this, SLOT(slotNavigationNewDirectoryAction())); QToolButton* navigationNewDirectoryToolButton = new QToolButton; navigationNewDirectoryToolButton->setDefaultAction(navigationNewDirectoryAction); // // Delete file action and tool button // navigationDeleteFileAction = new QAction(this); navigationDeleteFileAction->setIcon(QPixmap(trash_xpm)); navigationDeleteFileAction->setToolTip(tr("Delete\n" "Selected\n" "Files")); QObject::connect(navigationDeleteFileAction, SIGNAL(triggered(bool)), this, SLOT(slotNavigationDeleteFileAction())); QToolButton* navigationDeleteFileToolButton = new QToolButton; navigationDeleteFileToolButton->setDefaultAction(navigationDeleteFileAction); navigationRenameFileAction = new QAction(this); navigationRenameFileAction->setText(tr("A2B")); //navigationRenameFileAction->setIcon(QPixmap(rename_xpm)); navigationRenameFileAction->setToolTip(tr("Rename\n" "Selected\n" "File")); QObject::connect(navigationRenameFileAction, SIGNAL(triggered(bool)), this, SLOT(slotNavigationRenameFileAction())); QToolButton* navigationRenameFileToolButton = new QToolButton; navigationRenameFileToolButton->setDefaultAction(navigationRenameFileAction); // // Case sensitive action and tool button // navigationCaseSensitiveFileAction = new QAction(this); navigationCaseSensitiveFileAction->setText(tr("Aa")); navigationCaseSensitiveFileAction->setToolTip(tr("Case Sensitive") + "\n" + tr("(List View Only)")); navigationCaseSensitiveFileAction->setCheckable(true); navigationCaseSensitiveFileAction->setChecked(true); QObject::connect(navigationCaseSensitiveFileAction, SIGNAL(triggered(bool)), this, SLOT(slotNavigationCaseSensitiveAction())); QToolButton* navigationCaseSensitiveToolButton = new QToolButton; navigationCaseSensitiveToolButton->setDefaultAction(navigationCaseSensitiveFileAction); // // Show hidden files action and tool button // navigationShowHiddensFilesAction = new QAction(this); navigationShowHiddensFilesAction->setText(tr(".")); navigationShowHiddensFilesAction->setToolTip(tr("Show Hidden Files")); navigationShowHiddensFilesAction->setCheckable(true); navigationShowHiddensFilesAction->setChecked(false); QObject::connect(navigationShowHiddensFilesAction, SIGNAL(triggered(bool)), this, SLOT(slotNavigationShowHiddenFilesAction())); QToolButton* navigationShowHiddenFilesToolButton = new QToolButton; navigationShowHiddenFilesToolButton->setDefaultAction(navigationShowHiddensFilesAction); // // list view tool button // navigationListViewAction = new QAction(this); navigationListViewAction->setCheckable(true); navigationListViewAction->setToolTip(tr("List View")); navigationListViewAction->setIcon(QPixmap(mclistview_xpm)); QToolButton* navigationListViewToolButton = new QToolButton; navigationListViewToolButton->setDefaultAction(navigationListViewAction); // // detail view tool button // navigationDetailViewAction = new QAction(this); navigationDetailViewAction->setCheckable(true); navigationDetailViewAction->setToolTip(tr("Detail View")); navigationDetailViewAction->setIcon(QPixmap(detailedview_xpm)); QToolButton* navigationDetailViewToolButton = new QToolButton; navigationDetailViewToolButton->setDefaultAction(navigationDetailViewAction); // // Action group for list/detail views // QActionGroup* navigationViewActionGroup = new QActionGroup(this); navigationViewActionGroup->addAction(navigationListViewAction); navigationViewActionGroup->addAction(navigationDetailViewAction); QObject::connect(navigationViewActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(slotNavigationViewActionTriggered(QAction*))); // // Look in Label // lookInLabel = new QLabel(""); // // History row // QHBoxLayout* navigationHistoryLayout = new QHBoxLayout; navigationHistoryLayout->addWidget(lookInLabel, 0); navigationHistoryLayout->addWidget(navigationHistoryComboBox, 1000); // // Toolbutton row // navigationToolButtonLayout = new QHBoxLayout; navigationToolButtonLayout->addWidget(navigationBackToolButton, 0); navigationToolButtonLayout->addWidget(navigationForwardToolButton, 0); navigationToolButtonLayout->addWidget(navigationUpToolButton, 0); navigationToolButtonLayout->addWidget(navigationGoToDirectoryToolButton, 0); navigationToolButtonLayout->addWidget(navigationRefreshToolButton, 0); navigationToolButtonLayout->addWidget(new QLabel(" ")); navigationToolButtonLayout->addWidget(navigationCaseSensitiveToolButton, 0); navigationToolButtonLayout->addWidget(navigationShowHiddenFilesToolButton, 0); navigationToolButtonLayout->addWidget(new QLabel(" ")); navigationToolButtonLayout->addWidget(navigationNewDirectoryToolButton, 0); navigationToolButtonLayout->addWidget(navigationRenameFileToolButton, 0); navigationToolButtonLayout->addWidget(navigationDeleteFileToolButton, 0); navigationToolButtonLayout->addWidget(new QLabel(" ")); navigationToolButtonLayout->addWidget(navigationListViewToolButton, 0); navigationToolButtonLayout->addWidget(navigationDetailViewToolButton, 0); // // Layout for the two rows // QVBoxLayout* navigationLayout = new QVBoxLayout; navigationLayout->addLayout(navigationToolButtonLayout); navigationLayout->addLayout(navigationHistoryLayout); navigationLayout->setAlignment(navigationToolButtonLayout, Qt::AlignLeft); return navigationLayout; } /** * create the common directory section of the dialog. */ QWidget* WuQFileDialog::createCommonDirectorySection() { // // List widget for directories // commonDirectoryListWidget = new QListWidget; commonDirectoryListWidget->setSelectionMode(QListWidget::NoSelection); commonDirectoryListWidget->setMinimumWidth(120); QObject::connect(commonDirectoryListWidget, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(slotCommonDirectoryListWidget(QListWidgetItem*))); return commonDirectoryListWidget; } /** * called when a common directory item selected. */ void WuQFileDialog::slotCommonDirectoryListWidget(QListWidgetItem* item) { const QString directoryName = item->data(Qt::UserRole).toString(); if (debugFlag) { std::cout << "Directory: " << directoryName.toAscii().constData() << std::endl; } setDirectory(directoryName, false); } /** * set the sidebar URLS. */ void WuQFileDialog::setSidebarUrls(const QList& urls) { loadCommonDirectorySection(); for (int i = 0; i < urls.count(); i++) { const QString dirName(urls.at(i).toLocalFile()); addToCommonDirectory(dirName, dirName); } } /** * get sidebar Urls. */ QList WuQFileDialog::sidebarUrls() const { QList urls; for (int i = firstSideBarUrlIndex; i < commonDirectoryListWidget->count(); i++) { urls << QUrl::fromLocalFile(commonDirectoryListWidget->item(i)->text()); } return urls; } /** * load the common directory section. */ void WuQFileDialog::loadCommonDirectorySection() { // // clear the current items // commonDirectoryListWidget->clear(); // // Add the Computer // addToCommonDirectory(QDir::rootPath(), tr("Computer")); // // Add the user's home directory // const QString homeDir(QDir::homePath()); addToCommonDirectory(homeDir, "Home"); #ifdef Q_OS_MACX // // Add Desktop // const QString desktopPath(homeDir + QDir::separator() + "Desktop"); addToCommonDirectory(desktopPath, tr("Desktop")); // // Add Documents // const QString documentsPath(homeDir + QDir::separator() + "Documents"); addToCommonDirectory(documentsPath, tr("Documents")); // // Add Downloads // const QString downloadsPath(homeDir + QDir::separator() + "Downloads"); addToCommonDirectory(downloadsPath, tr("Downloads")); // // Add Volumes // const QString volumesPath("/Volumes"); addToCommonDirectory(volumesPath, tr("Volumes")); #endif // Q_OS_MACX #ifdef Q_OS_WIN32 // // Add Desktop // const QString desktopPath(homeDir + QDir::separator() + "Desktop"); addToCommonDirectory(desktopPath, tr("Desktop")); // // Add Document // const QString documentsPath(homeDir + QDir::separator() + "My Documents"); addToCommonDirectory(documentsPath, tr("My Documents")); #endif // Q_OS_WIN32 // // Add drives // QFileInfoList drivesList = QDir::drives(); for (int i = 0; i < drivesList.count(); i++) { const QFileInfo fi = drivesList.at(i); const QString driveName = fi.absoluteFilePath(); #ifdef Q_OS_MACX if (driveName == "/") { continue; } #endif // Q_OS_MACX addToCommonDirectory(driveName, driveName); } // // Anything else will be sidebar URLS // firstSideBarUrlIndex = commonDirectoryListWidget->count(); } /** * add to common directory. */ void WuQFileDialog::addToCommonDirectory(const QString& directoryPath, const QString& labelName) { if (QFile::exists(directoryPath)) { QListWidgetItem* item = new QListWidgetItem(QPixmap(folder_xpm), labelName); item->setData(Qt::UserRole, directoryPath); commonDirectoryListWidget->addItem(item); } } /** * create the file selection section of the dialog. */ QWidget* WuQFileDialog::createFileSelectionSection() { const int minHeight = 150; // // list widget for list view file selection // fileSelectionListWidget = new QListWidget; fileSelectionListWidget->setMinimumHeight(minHeight); fileSelectionListWidget->setFlow(QListWidget::TopToBottom); fileSelectionListWidget->setWrapping(true); fileSelectionListWidget->setSortingEnabled(false); QObject::connect(fileSelectionListWidget, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(slotFileSelectionListWidgetItemClicked(QListWidgetItem*))); QObject::connect(fileSelectionListWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(slotFileSelectionListWidgetItemDoubleClicked(QListWidgetItem*))); // // tree widget detail view file selection // fileSelectionTreeWidget = new QTreeWidget; fileSelectionTreeWidget->setMinimumHeight(minHeight); fileSelectionTreeWidget->setSortingEnabled(true); fileSelectionTreeWidget->sortItems(0, Qt::AscendingOrder); QObject::connect(fileSelectionTreeWidget, SIGNAL(itemClicked(QTreeWidgetItem*,int)), this, SLOT(slotFileSelectionTreeWidgetItemClicked(QTreeWidgetItem*,int))); QObject::connect(fileSelectionTreeWidget, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), this, SLOT(slotFileSelectionTreeWidgetItemDoubleClicked(QTreeWidgetItem*,int))); // // stacked widget for list and detail views // fileListAndDetailStackedWidget = new QStackedWidget; fileListAndDetailStackedWidget->addWidget(fileSelectionListWidget); fileListAndDetailStackedWidget->addWidget(fileSelectionTreeWidget); return fileListAndDetailStackedWidget; } /** * called when a file selection tree widget item clicked. */ void WuQFileDialog::slotFileSelectionTreeWidgetItemClicked(QTreeWidgetItem* /*item*/, int) { // // Get all selected files and put in set so names unique // QSet fileNamesSorted; const QList selItems = fileSelectionTreeWidget->selectedItems(); for (int i = 0; i < selItems.count(); i++) { const QTreeWidgetItem* item = selItems.at(i); const QString name(item->data(0, Qt::UserRole).toString()); if (debugFlag) { std::cout << "Item Clicked: " << name.toAscii().constData() << std::endl; } QFileInfo fi(name); if (fi.isFile()) { fileNamesSorted << fi.fileName(); } } // // Load files into file name line edit // If more than one selected file, put them in double quotes // QStringList fileNameList = QStringList::fromSet(fileNamesSorted); QString fileNames; const int numFiles = fileNameList.count(); if (numFiles == 1) { fileNames = fileNameList.at(0); } else { for (int i = 0; i < numFiles; i++) { const QString quotedName = "\"" + fileNameList.at(i) + "\""; if (fileNames.isEmpty() == false) { fileNames += " "; } fileNames.append(quotedName); } } updateSelectedFileLineEdit(fileNames); } /** * called when a file selection tree widget item double clicked. */ void WuQFileDialog::slotFileSelectionTreeWidgetItemDoubleClicked(QTreeWidgetItem* item, int column) { // // Get name // const QString name(item->data(0, Qt::UserRole).toString()); // // If directory, go into it // QFileInfo fi(name); if (fi.isDir()) { setDirectory(QDir(QFileInfo(theDirectory, name).absoluteFilePath())); return; } // // if file, select it and close dialog // if (fi.isFile()) { slotFileSelectionTreeWidgetItemClicked(item, column); if (selectedFiles().count() > 0) { slotAcceptPushButton(); } } } /** * called when a file selection widget item clicked. */ void WuQFileDialog::slotFileSelectionListWidgetItemClicked(QListWidgetItem* /*item*/) { // // Get all selected files // QStringList fileNameList; const QList selItems = fileSelectionListWidget->selectedItems(); for (int i = 0; i < selItems.count(); i++) { const QListWidgetItem* item = selItems.at(i); const QString name(item->data(Qt::UserRole).toString()); if (debugFlag) { std::cout << "Item Clicked: " << name.toAscii().constData() << std::endl; } QFileInfo fi(name); if (fi.isFile()) { fileNameList << fi.fileName(); } } // // Load files into file name line edit // If more than one selected file, put them in double quotes // QString fileNames; const int numFiles = fileNameList.count(); if (numFiles == 1) { fileNames = fileNameList.at(0); } else { for (int i = 0; i < numFiles; i++) { const QString quotedName = "\"" + fileNameList.at(i) + "\""; if (fileNames.isEmpty() == false) { fileNames += " "; } fileNames.append(quotedName); } } updateSelectedFileLineEdit(fileNames); } /** * called when a file selection widget item double clicked. */ void WuQFileDialog::slotFileSelectionListWidgetItemDoubleClicked(QListWidgetItem* item) { // // Get name // const QString name(item->data(Qt::UserRole).toString()); // // If directory, go into it // QFileInfo fi(name); if (fi.isDir()) { setDirectory(QDir(QFileInfo(theDirectory, name).absoluteFilePath())); return; } // // if file, select it and close dialog // if (fi.isFile()) { slotFileSelectionListWidgetItemClicked(item); if (selectedFiles().count() > 0) { slotAcceptPushButton(); } } } /** * called when file type combo box selection is made. */ void WuQFileDialog::slotFileTypeComboBox(const QString& s) { selectFilter(s); } /** * select a file filter. */ void WuQFileDialog::selectFilter(const QString& filterName) { fileTypeComboBox->blockSignals(true); for (int i = 0; i < fileTypeComboBox->count(); i++) { if (filterName == fileTypeComboBox->itemText(i)) { fileTypeComboBox->setCurrentIndex(i); break; } } fileTypeComboBox->blockSignals(false); rereadDir(); } /** * get the file filters. */ QStringList WuQFileDialog::filters() const { QStringList sl; for (int i = 0; i < fileTypeComboBox->count(); i++) { sl << fileTypeComboBox->itemText(i); } return sl; } /** * sets file filters. */ void WuQFileDialog::setFilter(const QString& filterName) { setFilters(QStringList(filterName)); } /** * set the file filters. */ void WuQFileDialog::setFilters(const QStringList& filters) { fileTypeComboBox->clear(); for (int i = 0; i < filters.count(); i++) { fileTypeComboBox->addItem(filters.at(i)); } if (fileTypeComboBox->count() <= 0) { fileTypeComboBox->addItem(tr("Any File (*)")); } rereadDir(); } /** * get the selected file filter. */ QString WuQFileDialog::selectedFilter() const { QString s; if (fileTypeComboBox->count() > 0) { s = fileTypeComboBox->currentText(); } return s; } /** * select a file. */ void WuQFileDialog::selectFile(const QString& name) { bool validFilesOnly = false; switch (fileMode()) { case AnyFile: break; case ExistingFile: validFilesOnly = true; break; case Directory: break; case ExistingFiles: validFilesOnly = true; break; case DirectoryOnly: break; } QFileInfo fi(name); const QString fileName = fi.fileName(); const QString path = fi.absolutePath(); if (path.isEmpty()) { setDirectory(path, false); rereadDir(); } QList lwItems = fileSelectionListWidget->findItems(fileName, (Qt::MatchFixedString | Qt::MatchCaseSensitive)); if (lwItems.count() > 0) { fileSelectionListWidget->setCurrentItem(lwItems.at(0)); updateSelectedFileLineEdit(fileName); } for (int i = 0; i < fileSelectionTreeWidget->topLevelItemCount(); i++) { QTreeWidgetItem* item = fileSelectionTreeWidget->topLevelItem(i); if (item->text(0) == fileName) { item->setSelected(true); } else { item->setSelected(false); } } if (validFilesOnly) { QFileInfo fullFilePath(theDirectory, fileName); if (fullFilePath.exists()) { updateSelectedFileLineEdit(fileName); } } else { updateSelectedFileLineEdit(fileName); } } /** * called when a navigation history selection is made. */ void WuQFileDialog::slotNavigationHistoryComboBox(const QString& name) { setDirectory(name, true); } /** * set the directory. */ void WuQFileDialog::setDirectory(const QString& dir) { setDirectory(dir, false); } /** * set the directory. */ void WuQFileDialog::setDirectory(const QDir& dir) { setDirectory(dir.absolutePath(), false); } /** * set the file mode. */ void WuQFileDialog::setFileMode(const FileMode mode) { theFileMode = mode; QListWidget::SelectionMode listSelMode = QListWidget::SingleSelection; QTreeWidget::SelectionMode treeSelMode = QTreeWidget::SingleSelection; switch (fileMode()) { case AnyFile: break; case ExistingFile: break; case Directory: break; case ExistingFiles: listSelMode = QListWidget::ExtendedSelection; treeSelMode = QTreeWidget::ExtendedSelection; break; case DirectoryOnly: break; } fileSelectionListWidget->setSelectionMode(listSelMode); fileSelectionTreeWidget->setSelectionMode(treeSelMode); slotFileNameLineEditChanged(fileNameLineEdit->text()); updateTitleLabelsButtons(); } /** * get the history (previous directories). */ QStringList WuQFileDialog::history() const { QStringList sl; for (int i = 0; i < navigationHistoryComboBox->count(); i++) { sl << navigationHistoryComboBox->itemText(i); } return sl; } /** * set the history (previous paths). */ void WuQFileDialog::setHistory(const QStringList& paths) { navigationHistoryComboBox->clear(); for (int i = 0; i < paths.count(); i++) { navigationHistoryComboBox->addItem(paths.at(i)); } } /** * set read only. */ void WuQFileDialog::setReadOnly(const bool enabled) { readOnlyFlag = enabled; slotFileNameLineEditChanged(fileNameLineEdit->text()); } /** * set the directory path. */ void WuQFileDialog::setDirectory(const QString& dirPathIn, const bool selectionFromHistoryFlag) { // // Convert from ".", if needed // QString dirPath = dirPathIn; if (dirPath == ".") { dirPath = QDir::currentPath(); } // // Set the directory // theDirectory.setPath(dirPath); // // Update navigation history combo box // if (selectionFromHistoryFlag == false) { navigationHistoryComboBox->blockSignals(true); // // If directory is first item in combo box, do not add it // const int dirIndex = navigationHistoryComboBox->findText(dirPath); if (dirIndex != 0) { // // Add to history // navigationHistoryComboBox->insertItem(0, dirPath); navigationHistoryComboBox->setCurrentIndex(0); } else if (dirIndex == 0) { navigationHistoryComboBox->setCurrentIndex(0); } navigationHistoryComboBox->blockSignals(false); } // // Remove previous directories from file system watcher // and add new directory // QStringList currentPaths(fileSystemWatcher->directories()); if (currentPaths.count() > 0) { fileSystemWatcher->removePaths(currentPaths); } fileSystemWatcher->addPath(theDirectory.absolutePath()); // // Update listing of files in dialog // rereadDir(); // // Enable forward and back buttons // const int historyIndex = navigationHistoryComboBox->currentIndex(); navigationBackAction->setEnabled(navigationHistoryComboBox->count() > (historyIndex + 1)); navigationForwardAction->setEnabled(historyIndex > 0); emit directoryEntered(theDirectory.absolutePath()); } /** * Rereads the current directory shown in the file dialog. */ void WuQFileDialog::rereadDir() { // // Get the current file filter // QString filterText = selectedFilter(); if (filterText.isEmpty()) { filterText = "*"; } else { const int openParenIndex = filterText.indexOf("("); const int closeParenIndex = filterText.indexOf(")"); if (openParenIndex >= 0) { if (closeParenIndex >=openParenIndex) { const int num = closeParenIndex - openParenIndex - 1; filterText = filterText.mid(openParenIndex + 1, num); } else { filterText = filterText.mid(openParenIndex + 1); } } } // // Get filters into a QStringList separate by white space and semicolons // QStringList filterStringList = filterText.split(QRegExp("[\\s;]"), QString::SkipEmptyParts); if (debugFlag) { std::cout << "Filter: |" << filterText.toAscii().constData() << "|" << std::endl; std::cout << "Filters: "; for (int i = 0; i < filterStringList.count(); i++) { std::cout << "|" << filterStringList.at(i).toAscii().constData() << "| "; } std::cout << std::endl; } // // Choose types of files to filter // bool showFiles = true; QDir::Filters filterFlags = QDir::NoDotAndDotDot | QDir::CaseSensitive; switch (fileMode()) { case AnyFile: filterFlags |= (QDir::AllDirs | QDir::Files); break; case ExistingFile: filterFlags |= (QDir::AllDirs | QDir::Files); break; case Directory: filterFlags |= (QDir::AllDirs | QDir::Files); break; case ExistingFiles: filterFlags |= (QDir::AllDirs | QDir::Files); break; case DirectoryOnly: filterFlags |= (QDir::AllDirs); showFiles = false; break; } if (navigationShowHiddensFilesAction->isChecked()) { filterFlags |= QDir::Hidden; } // // Sorting // QDir::SortFlags sortFlags = QDir::Name | QDir::DirsFirst; if (navigationCaseSensitiveFileAction->isChecked() == false) { sortFlags |= QDir::IgnoreCase; } // // Get list of directories and files // QFileInfoList dirList = theDirectory.entryInfoList(filterStringList, filterFlags, sortFlags); // // Remove all items in list widget // fileSelectionListWidget->clear(); // // Add items to list widget // for (int i = 0; i < dirList.count(); i++) { const QFileInfo& fi = dirList.at(i); // // Skip files ? // if (showFiles == false) { if (fi.isFile()) { continue; } } const QString name = fi.fileName(); QListWidgetItem* item = NULL; if (fi.isDir()) { item = new QListWidgetItem(QPixmap(folder_xpm), name); } else { item = new QListWidgetItem(QPixmap(file_xpm), name); } item->setData(Qt::UserRole, fi.absoluteFilePath()); fileSelectionListWidget->addItem(item); } // // Remove all items in tree widget // fileSelectionTreeWidget->clear(); // // Columns for different types of data // int columnCount = 0; const int nameColumn = columnCount++; const int typeColumn = columnCount++; const int dateColumn = columnCount++; const int sizeColumn = columnCount++; // // number of rows // const int rowCount = dirList.count(); if (rowCount > 0) { // // set column size of tree // fileSelectionTreeWidget->setColumnCount(columnCount); if (fileSelectionTreeNameWidthAdjustedFlag == false) { fileSelectionTreeWidget->setColumnWidth(nameColumn, 300); fileSelectionTreeNameWidthAdjustedFlag = true; } // // Set column titles // QStringList columnTitles; columnTitles << tr("Name"); columnTitles << tr("Type"); columnTitles << tr("Date"); columnTitles << tr("Size"); fileSelectionTreeWidget->setHeaderLabels(columnTitles); // // Add items to list widget // for (int i = 0; i < rowCount; i++) { const QFileInfo& fi = dirList.at(i); // // Skip files ? // if (showFiles == false) { if (fi.isFile()) { continue; } } // // Create the tree widget item // QTreeWidgetItem* treeItem = new QTreeWidgetItem(fileSelectionTreeWidget); // // Name // const QString name = fi.fileName(); treeItem->setText(nameColumn, name); if (fi.isDir()) { treeItem->setIcon(nameColumn, QPixmap(folder_xpm)); } else { treeItem->setIcon(nameColumn, QPixmap(file_xpm)); } treeItem->setData(nameColumn, Qt::UserRole, fi.absoluteFilePath()); // // Type (file extension) // QString typeName = fi.suffix(); if (fi.isDir()) { typeName = "Directory"; } else { QString extensionTypeName = "." + typeName.toLower(); if (fileExtensionToTypeNameMap.contains(extensionTypeName)) { typeName = fileExtensionToTypeNameMap.value(extensionTypeName); } } treeItem->setText(typeColumn, typeName); treeItem->setData(typeColumn, Qt::UserRole, fi.absolutePath()); // // Date // const QString dateString = fi.lastModified().toString("yyyy/MM/dd hh:mm:ss"); treeItem->setText(dateColumn, dateString); // // size // QString sizeString; if (fi.isFile()) { const qint64 fileSize = fi.size(); if (fileSize < 1024) { sizeString = (QString::number(fileSize) + " bytes"); } else if (fileSize < (1024 * 1024)) { sizeString = (QString::number(fileSize / 1024) + " KB"); } else { sizeString = (QString::number(fileSize / (1024*1024)) + " MB"); } } treeItem->setText(sizeColumn, sizeString); // // Add to the tree // fileSelectionTreeWidget->addTopLevelItem(treeItem); } } } /** * returns file filters that match the name. */ QStringList WuQFileDialog::matchingFilters(const QString& name) { QStringList matchingFilters; // // Loop through the filters // QStringList theFilters = filters(); for (int i = 0; i < theFilters.size(); i++) { const QString filterText = theFilters.at(i); // // Loop for the part within the parenthesis (if any) // Example "Word Files (*.doc *.rtf)" ===>> "*.doc *.rtf" // const int openParenIndex = filterText.indexOf("("); const int closeParenIndex = filterText.indexOf(")"); QString patternsText; if (openParenIndex >= 0) { if (closeParenIndex >=openParenIndex) { const int num = closeParenIndex - openParenIndex - 1; patternsText = filterText.mid(openParenIndex + 1, num); } else { patternsText = filterText.mid(openParenIndex + 1); } } // // Get patterns into a QStringList separate by white space and semicolons // QStringList patternsStringList = patternsText.split(QRegExp("[\\s;]"), QString::SkipEmptyParts); for (int i = 0; i < patternsStringList.count(); i++) { const QString pattern = patternsStringList.at(i); QRegExp regExp(pattern, Qt::CaseSensitive, QRegExp::Wildcard); if (regExp.exactMatch(name)) { matchingFilters += filterText; } } } return matchingFilters; } /** * add a toolbutton to the dialog. */ void WuQFileDialog::addToolButton(QAbstractButton* b, const bool separator) { if (b != NULL) { if (separator) { navigationToolButtonLayout->addWidget(new QLabel(" ")); navigationToolButtonLayout->addWidget(b); } } } /** * Add a widgets to the dialog. * The widgets are placed in a new row at the bottom of the dialog. * Widgets that are NULL are ignored. * A widget may be specified more than once. For example, specifying the * "leftColumn" and the "centerColumn" with the same widget results in the * widget occupying both the left and center column. */ void WuQFileDialog::addWidgets(QWidget* leftColumn, QWidget* centerColumn, QWidget* rightColumn) { if ((leftColumn != NULL) || (centerColumn != NULL) || (rightColumn != NULL)) { const int numRows = nameFilterButtonsGridLayout->rowCount(); if (leftColumn != NULL) { int leftColumnSpan = 1; if (centerColumn == leftColumn) { leftColumnSpan++; centerColumn = NULL; if (rightColumn == leftColumn) { leftColumnSpan++; rightColumn = NULL; } } Qt::Alignment alignment = Qt::AlignTop; if (leftColumnSpan == 1) { alignment |= Qt::AlignRight; } nameFilterButtonsGridLayout->addWidget(leftColumn, numRows, 0, 1, leftColumnSpan, alignment); } if (centerColumn != NULL) { int centerColumnSpan = 1; if (rightColumn == centerColumn) { centerColumnSpan++; rightColumn = NULL; } nameFilterButtonsGridLayout->addWidget(centerColumn, numRows, 1, 1, centerColumnSpan, Qt::AlignTop); } if (rightColumn != NULL) { nameFilterButtonsGridLayout->addWidget(rightColumn, numRows, 2, (Qt::AlignLeft | Qt::AlignTop)); } updateGeometry(); } } /** * called when navigation back tool button clicked. */ void WuQFileDialog::slotNavigationBackAction() { const int backIndex = navigationHistoryComboBox->currentIndex() + 1; if (navigationHistoryComboBox->count() > backIndex) { navigationHistoryComboBox->blockSignals(true); navigationHistoryComboBox->setCurrentIndex(backIndex); navigationHistoryComboBox->blockSignals(false); setDirectory(navigationHistoryComboBox->currentText(), true); } } /** * called when navigation forward tool button clicked. */ void WuQFileDialog::slotNavigationForwardAction() { const int forwardIndex = navigationHistoryComboBox->currentIndex() - 1; if (forwardIndex >= 0) { navigationHistoryComboBox->blockSignals(true); navigationHistoryComboBox->setCurrentIndex(forwardIndex); navigationHistoryComboBox->blockSignals(false); setDirectory(navigationHistoryComboBox->currentText(), true); } } /** * called when navigation go to directory tool button clicked. */ void WuQFileDialog::slotNavigationGoToDirectoryAction() { QString dirName; bool doLoopFlag = true; while (doLoopFlag) { doLoopFlag = false; bool ok = false; dirName = QInputDialog::getText(this, tr("Go To Directory"), tr("Directory Name"), QLineEdit::Normal, dirName, &ok); if (ok) { // // Substitute home directory for ~ // if (dirName.startsWith("~")) { dirName = QDir::homePath() + dirName.mid(1); } QFileInfo fi(dirName); if (fi.exists()) { setDirectory(dirName); } else { QFileInfo fi(theDirectory, dirName); if (fi.exists()) { setDirectory(theDirectory.absolutePath() + "/" + dirName); } else { doLoopFlag = true; QMessageBox::critical(this, tr("Error"), tr("Invalid Directory Name"), QMessageBox::Ok); } } } } } /** * called when navigation up tool button clicked. */ void WuQFileDialog::slotNavigationUpAction() { theDirectory.cdUp(); setDirectory(theDirectory.absolutePath(), false); } /** * called when navigation refresh tool button clicked. */ void WuQFileDialog::slotNavigationRefreshAction() { rereadDir(); } /** * called when navigation new directory tool button clicked. */ void WuQFileDialog::slotNavigationNewDirectoryAction() { // // Get name for new directory // bool ok = false; const QString name = QInputDialog::getText(this, tr("New Directory"), tr("Enter name for new directory."), QLineEdit::Normal, "", &ok).trimmed(); if (ok) { if (name.isEmpty() == false) { theDirectory.mkdir(name); rereadDir(); } } } /** * set the view mode. */ void WuQFileDialog::setViewMode(const ViewMode viewMode) { navigationListViewAction->blockSignals(true); navigationDetailViewAction->blockSignals(true); navigationListViewAction->setChecked(false); navigationDetailViewAction->setChecked(false); switch (viewMode) { case Detail: fileListAndDetailStackedWidget->setCurrentWidget(fileSelectionTreeWidget); navigationDetailViewAction->setChecked(true); break; case List: fileListAndDetailStackedWidget->setCurrentWidget(fileSelectionListWidget); navigationListViewAction->setChecked(true); break; } navigationListViewAction->blockSignals(false); navigationDetailViewAction->blockSignals(false); } /** * get the view mode. */ WuQFileDialog::ViewMode WuQFileDialog::viewMode() const { if (fileListAndDetailStackedWidget->currentWidget() == fileSelectionListWidget) { return List; } return Detail; } /** * called when navigation rename file tool button clicked. */ void WuQFileDialog::slotNavigationRenameFileAction() { const QStringList nameList = selectedFiles(); if (nameList.count() == 1) { const QString oldFileName = nameList.at(0); bool ok = false; const QString newFileName = QInputDialog::getText(this, tr("Rename File"), tr("Enter new file name."), QLineEdit::Normal, oldFileName, &ok); if (ok) { if (newFileName != oldFileName) { // // Rename the file // QFileInfo newInfo(theDirectory, newFileName); if (QFile::rename(oldFileName, newInfo.filePath()) == false) { QMessageBox::critical(this, tr("ERROR"), tr("Unable to rename file"), QMessageBox::Ok); return; } // // Refresh file listing // rereadDir(); } } } } /** * called when navigation delete file tool button clicked. */ void WuQFileDialog::slotNavigationDeleteFileAction() { const QStringList nameList = selectedFiles(); if (nameList.count() > 0) { QString confirmNames; // // Look for selected items that are not files // QStringList namesNoPath; for (int i = 0; i < nameList.count(); i++) { const QString fileName = nameList.at(i); QFileInfo fi(fileName); const QString fileNameNoPath(fi.fileName()); namesNoPath << fileNameNoPath; if (fi.isFile() == false) { QMessageBox::critical(this, tr("ERROR"), fileName + tr(" is not a file. Unable to delete."), QMessageBox::Ok); return; } if (fi.exists() == false) { QMessageBox::critical(this, tr("ERROR"), fileNameNoPath + tr(" does not exist. Unable to delete."), QMessageBox::Ok); return; } } // // CONFIRM // const QString msg = (tr("Are you sure you want to delete these files? \n") + namesNoPath.join("\n")); if (QMessageBox::question(this, tr("CONFIRM"), msg, QMessageBox::Ok, QMessageBox::Cancel) == QMessageBox::Cancel) { return; } // // Delete the files // for (int i = 0; i < nameList.count(); i++) { const QString fileName = nameList.at(i); QFile::remove(fileName); } // // Refresh file listing // rereadDir(); } } /** * called when navigation view tool button clicked. */ void WuQFileDialog::slotNavigationViewActionTriggered(QAction* action) { if (action == navigationListViewAction) { setViewMode(List); } else { setViewMode(Detail); } } /** * called when case sensitive tool button clicked. */ void WuQFileDialog::slotNavigationCaseSensitiveAction() { rereadDir(); } /** * called when show hidden files tool button clicked. */ void WuQFileDialog::slotNavigationShowHiddenFilesAction() { rereadDir(); } /** * restores the dialog's layout, history and current directory to the state specified * returns false if there are errors. */ bool WuQFileDialog::restoreState(const QByteArray& state) { QByteArray sd = state; QDataStream stream(&sd, QIODevice::ReadOnly); stream.setVersion(QDataStream::Qt_4_3); if (stream.atEnd()) { return false; } qint32 marker, version; stream >> marker; stream >> version; if ((marker != WUQFileDialogMagic) || (version != WUQFileDialogVersion)) { return false; } QByteArray splitterState; QByteArray headerState; QStringList historyState; QString directoryState; qint32 viewModeState; qint32 caseSensitiveState; qint32 showHiddenState; stream >> splitterState >> historyState >> directoryState >> headerState >> viewModeState >> caseSensitiveState >> showHiddenState; if (dirFileSplitter->restoreState(splitterState) == false) { return false; } setHistory(historyState); setDirectory(directoryState); if (fileSelectionTreeWidget->header()->restoreState(headerState) == false) { return false; } setViewMode(ViewMode(viewModeState)); navigationCaseSensitiveFileAction->setChecked(caseSensitiveState != 0); navigationShowHiddensFilesAction->setChecked(showHiddenState != 0); return true; } /** * saves the state of the dialog's layout, history, current directory. */ QByteArray WuQFileDialog::saveState() const { QByteArray data; QDataStream stream(&data, QIODevice::WriteOnly); stream.setVersion(QDataStream::Qt_4_3); stream << qint32(WUQFileDialogMagic); stream << qint32(WUQFileDialogVersion); stream << dirFileSplitter->saveState(); stream << history(); stream << directory().absolutePath(); stream << fileSelectionTreeWidget->header()->saveState(); stream << qint32(viewMode()); stream << qint32(navigationCaseSensitiveFileAction->isChecked()); stream << qint32(navigationShowHiddensFilesAction->isChecked()); return data; } void WuQFileDialog::initializeFileExtensionToTypeNameMap() { fileExtensionToTypeNameMap[".doc"] = "Word"; fileExtensionToTypeNameMap[".xls"] = "Excel"; fileExtensionToTypeNameMap[".ppt"] = "PowerPoint"; fileExtensionToTypeNameMap[".jpg"] = "Image - JPEG"; fileExtensionToTypeNameMap[".tif"] = "Image - TIFF"; fileExtensionToTypeNameMap[".tiff"] = "Image - TIFF"; fileExtensionToTypeNameMap[".png"] = "Image - PNG"; fileExtensionToTypeNameMap[".ppm"] = "Image - PPM"; fileExtensionToTypeNameMap[".gif"] = "Image - GIF"; fileExtensionToTypeNameMap[".sh"] = "Bourne Shell"; fileExtensionToTypeNameMap[".csh"] = "C Shell"; fileExtensionToTypeNameMap[".pl"] = "Perl"; fileExtensionToTypeNameMap[".py"] = "Python"; fileExtensionToTypeNameMap[".wrl"] = "VRML"; fileExtensionToTypeNameMap[".bat"] = "MSDOS Batch"; fileExtensionToTypeNameMap[".cpp"] = "C++"; fileExtensionToTypeNameMap[".cxx"] = "C++"; fileExtensionToTypeNameMap[".c"] = "C"; fileExtensionToTypeNameMap[".o"] = "Header"; fileExtensionToTypeNameMap[".obj"] = "Object"; fileExtensionToTypeNameMap[".exe"] = "Executable"; fileExtensionToTypeNameMap[".pdf"] = "PDF"; fileExtensionToTypeNameMap[".zip"] = "Compressed"; fileExtensionToTypeNameMap[".gz"] = "Compressed"; fileExtensionToTypeNameMap[".pro"] = "QT Project"; fileExtensionToTypeNameMap[".wav"] = "Audio Wave"; fileExtensionToTypeNameMap[".mpg"] = "Audio MP3"; fileExtensionToTypeNameMap[".mov"] = "Movie Quicktime"; fileExtensionToTypeNameMap[".wmv"] = "Movie Windows Media"; fileExtensionToTypeNameMap[".mpg"] = "Movie MPEG"; fileExtensionToTypeNameMap[".mpeg"] = "Movie MPEG"; fileExtensionToTypeNameMap[".avi"] = "Movie AVI"; fileExtensionToTypeNameMap[".rar"] = "Archive"; fileExtensionToTypeNameMap[".psd"] = "Photoshop"; fileExtensionToTypeNameMap[".wma"] = "Audio Windows Media"; fileExtensionToTypeNameMap[".sitx"] = "Stuffit X"; fileExtensionToTypeNameMap[".sit"] = "Stuffit"; fileExtensionToTypeNameMap[".eps"] = "Postscript"; fileExtensionToTypeNameMap[".ps"] = "Postscript"; fileExtensionToTypeNameMap[".rgb"] = "Rich Text"; fileExtensionToTypeNameMap[".html"] = "HTML"; fileExtensionToTypeNameMap[".tgz"] = "Archive Tar/Gzip"; } caret-5.6.4~dfsg.1.orig/caret_widgets/WuQDialog.h0000664000175000017500000000411711572067322021415 0ustar michaelmichael#ifndef __WU_QDIALOG_H__ #define __WU_QDIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include class QKeyEvent; class QMenu; /// QDialog with a few additions including copy of dialog as image to clipboard class WuQDialog : public QDialog { Q_OBJECT public: // constructor WuQDialog(QWidget* parent = 0, Qt::WindowFlags f = 0); // destructor virtual ~WuQDialog(); // ring the bell static void beep(); // show the wait cursor static void showWaitCursor(); // normal cursor static void showNormalCursor(); public slots: // called to close bool close(); protected slots: // called to capture image of window and place it on the clipboard void slotMenuCaptureImageOfWindowToClipboard(); // called to capture image after timeout so nothing obscures window void slotCaptureImageAfterTimeOut(); protected: // add a capture image of window menu item to the menu void addImageCaptureToMenu(QMenu* menu); // called by parent when context menu event occurs virtual void contextMenuEvent(QContextMenuEvent*); }; #endif // __WU_QDIALOG_H__ caret-5.6.4~dfsg.1.orig/caret_widgets/WuQDialog.cxx0000664000175000017500000000623611572067322021774 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include "WuQDialog.h" /** * constructor. */ WuQDialog::WuQDialog(QWidget* parent, Qt::WindowFlags f) : QDialog(parent, f) { setFocusPolicy(Qt::ClickFocus); } /** * destructor. */ WuQDialog::~WuQDialog() { } /** * 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) { // // Popup menu for selection of pages // QMenu menu(this); // // Add menu item for image capture // addImageCaptureToMenu(&menu); // // Popup the menu // menu.exec(cme->globalPos()); } /** * 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(); } caret-5.6.4~dfsg.1.orig/caret_widgets/WuQDataEntryDialog.h0000664000175000017500000001204211572067322023225 0ustar michaelmichael #ifndef __WU_Q_DATA_ENTRY_DIALOG_H__ #define __WU_Q_DATA_ENTRY_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "WuQDialog.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; /// class for a modal data entry dialog class WuQDataEntryDialog : public WuQDialog { Q_OBJECT public: // constructor WuQDataEntryDialog(QWidget* parent = 0, const bool addScrollBarsFlag = false, Qt::WindowFlags f = 0); // destructor ~WuQDataEntryDialog(); // add widget to next available row in the dialog QWidget* addWidget(const QString& labelText, 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); // set the OK button text void setOkButtonText(const QString& s); // set the Cancel button text void setCancelButtonText(const QString& s); // hide the cancel button void hideCancelButton(); // set text at top of dialog void setTextAtTop(const QString& s, const bool wrapTheText); protected: // override to verify data after OK button pressed if subclassing this dialog virtual bool dataEnteredIsValid(); private slots: // called when OK button pressed void slotOKButtonPressed(); private: /// widgets in dialog QVector widgets; /// layout for widgets in dialog QGridLayout* widgetGridLayout; /// the dialog's ok/cancel buttons QDialogButtonBox* buttonBox; /// label for text at dialog top QLabel* textAtTopLabel; /// button group for radio buttons QButtonGroup* radioButtonGroup; }; #endif // __WU_Q_DATA_ENTRY_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret_widgets/WuQDataEntryDialog.cxx0000664000175000017500000002370311572067322023606 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "WuQDataEntryDialog.h" /** * constructor. */ WuQDataEntryDialog::WuQDataEntryDialog(QWidget* parent, const bool addScrollBarsFlag, Qt::WindowFlags f) : WuQDialog(parent, f) { // // 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); // // Button box for dialog's buttons // buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); QObject::connect(buttonBox, SIGNAL(accepted()), this, SLOT(slotOKButtonPressed())); QObject::connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); // // May use scrolling // QScrollArea* scrollArea = NULL; if (addScrollBarsFlag) { scrollArea = new QScrollArea; scrollArea->setWidget(widgetForGridLayout); scrollArea->setWidgetResizable(true); } // // Layout for dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->addWidget(textAtTopLabel); if (scrollArea != NULL) { dialogLayout->addWidget(scrollArea); } else { dialogLayout->addWidget(widgetForGridLayout); } dialogLayout->addWidget(buttonBox); } /** * destructor. */ WuQDataEntryDialog::~WuQDataEntryDialog() { } /** * called when OK button pressed. */ void WuQDataEntryDialog::slotOKButtonPressed() { if (dataEnteredIsValid()) { accept(); } } /** * hide the cancel button. */ void WuQDataEntryDialog::hideCancelButton() { QPushButton* cancelButton = buttonBox->button(QDialogButtonBox::Cancel); if (cancelButton != NULL) { buttonBox->removeButton(cancelButton); delete cancelButton; } } /** * 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 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 = new QComboBox; 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 = new QSpinBox; 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 = new QDoubleSpinBox; 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; } /** * set the OK button text. */ void WuQDataEntryDialog::setOkButtonText(const QString& s) { buttonBox->button(QDialogButtonBox::Ok)->setText(s); } /** * set the Cancel button text. */ void WuQDataEntryDialog::setCancelButtonText(const QString& s) { buttonBox->button(QDialogButtonBox::Cancel)->setText(s); } caret-5.6.4~dfsg.1.orig/caret_widgets/QtUtilities.h0000664000175000017500000000651011572067322022040 0ustar michaelmichael #ifndef __QT_UTILITIES_H__ #define __QT_UTILITIES_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include // // Avoid include files. // class QDialog; class QImage; class QKeyEvent; class QPushButton; class QSizePolicy; /// This class contains methods that help simplify Gui Programming with QT. class QtUtilities { public: // Set the sizes of a vector of buttons to the size of // the button with the largest width. static void makeButtonsSameSize(std::vector& buttons); // Set the sizes of buttons to the size of the button with the largest width. static void makeButtonsSameSize(QPushButton* b1, QPushButton* b2, QPushButton* b3 = NULL, QPushButton* b4 = NULL, QPushButton* b5 = NULL, QPushButton* b6 = NULL); // position a dialog to that it is off of a window static void positionWindowOffOtherWindow(const QWidget* otherWindow, QWidget* window); // position and set the size of a dialog so that it is over the main window static void positionAndSetDialogSize(QWidget* mainWindow, QDialog* dialog, const QSize& desiredSize); static QSizePolicy& fixedSizePolicy(); // save an image of the widget static void saveWidgetAsImage(QWidget* widget); /// get the image capture key selected static bool getImageCaptureKeySelected(QKeyEvent* ke); // get the maximum height for a dialog or window static int getMaximumWindowHeight(); /// print the size hint of the widget static void printWidgetSizeHint(QWidget* w, const QString& widgetName); /// set the maximum height for a widget (gets around bug in QT if minimum size greater than maximum) static void setMaximumHeightToNinetyPercentOfScreenHeight(QWidget* w); protected: // copy an image of the widget to the clipboard static void saveWidgetAsImageToClipboard(QImage& image); // print an image of the widget static void saveWidgetAsImageToPrinter(QWidget* widget, QImage& image); // save an image of the widget to file static void saveWidgetAsImageToFile(QWidget* widget, QImage& image); }; #endif caret-5.6.4~dfsg.1.orig/caret_widgets/QtUtilities.cxx0000664000175000017500000002726711572067322022427 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "FileUtilities.h" #include "QtRadioButtonSelectionDialog.h" #include "QtUtilities.h" #include "StringUtilities.h" #include "WuQFileDialog.h" /** * Set the sizes of a vector of buttons to the size of the button with * the largest width. */ void QtUtilities::makeButtonsSameSize(std::vector& buttons) { int maxWidth = -1; QSize size; for (unsigned int i = 0; i < buttons.size(); i++) { if (buttons[i] != NULL) { if (buttons[i]->sizeHint().width() > maxWidth) { size = buttons[i]->sizeHint(); maxWidth = size.width(); } } } if (maxWidth > 0) { for (unsigned int i = 0; i < buttons.size(); i++) { if (buttons[i] != NULL) { buttons[i]->setFixedSize(size); } } } } /** * Set the sizes of buttons to the size of the button with the largest width. */ void QtUtilities::makeButtonsSameSize(QPushButton* b1, QPushButton* b2, QPushButton* b3, QPushButton* b4, QPushButton* b5, QPushButton* b6) { std::vector buttons; buttons.push_back(b1); buttons.push_back(b2); buttons.push_back(b3); buttons.push_back(b4); buttons.push_back(b5); buttons.push_back(b6); if (buttons.size() > 0) { makeButtonsSameSize(buttons); } } /** * position a dialog to that it is off of a window. */ void QtUtilities::positionWindowOffOtherWindow(const QWidget* otherWindow, QWidget* window) { QDesktopWidget* dt = QApplication::desktop(); const int dtWidth = dt->width(); const int dtHeight = dt->height(); const int otherX = otherWindow->x(); const int otherY = otherWindow->y(); const int otherWidth = otherWindow->width(); const int otherHeight = otherWindow->height(); const int spaceOnSide[4] = { otherX, // left dtWidth - otherX + otherWidth, // right dtHeight - (otherY + otherHeight), // bottom (0 is top) otherY // top }; int maxIndx = 0; int maxSpace = spaceOnSide[0]; for (int i = 1; i < 4; i++) { if (spaceOnSide[i] > maxSpace) { maxIndx = i; maxSpace = spaceOnSide[i]; } } int newX = 0; int newY = 0; switch(maxIndx) { case 0: newX = otherX - window->width(); newY = otherY; break; case 1: newX = otherX + otherWidth; newY = otherY; break; case 2: newX = otherX; newY = otherY + otherHeight; break; case 3: newX = otherX; newY = otherY - window->height(); break; } newX = std::max(newX, 100); newX = std::min(newX, (dtWidth - 100)); newY = std::max(newY, 100); newY = std::min(newY, (dtHeight - 100)); window->move(newX, newY); } /** * Position and set the size of a dialog so that it is over the main window. */ void QtUtilities::positionAndSetDialogSize(QWidget* mainWindow, QDialog* dialog, const QSize& desiredSize) { QDesktopWidget desktop; QRect desktopRect = desktop.screenGeometry(); QRect mainWindowRect = mainWindow->geometry(); const int x = mainWindowRect.left(); const int y = mainWindowRect.top() + 25; const int width = mainWindowRect.width(); // std::cout << "Main window: " int xsize = desiredSize.width(); if ((x +xsize) > desktopRect.right()) { xsize = desktopRect.right() - x - 20; } if (xsize < width) { xsize = width; if (xsize > 600) { xsize = 600; } } const int windowHeight = (desktopRect.bottom() - 50); int ysize = desiredSize.height(); if ((y + ysize) > windowHeight) { ysize = windowHeight - y - 20; } if (ysize < 300) { ysize = 300; } dialog->setGeometry(x, y, xsize, ysize); } QSizePolicy& QtUtilities::fixedSizePolicy() { static QSizePolicy sizePolicyFixed(QSizePolicy::Fixed, QSizePolicy::Fixed); return sizePolicyFixed; } /** * save the dialog into an image. */ void QtUtilities::saveWidgetAsImage(QWidget* widget) { std::vector itemChoices; itemChoices.push_back("Copy to Clipboard"); itemChoices.push_back("Print"); itemChoices.push_back("Save to File"); static int defaultItem = 2; QtRadioButtonSelectionDialog choiceDialog(widget, "Capture Image", "What would you like to do\n" "with the captured image?", itemChoices, defaultItem); if (choiceDialog.exec() != QDialog::Accepted) { return; } QImage image = QPixmap::grabWidget(widget).toImage(); defaultItem = choiceDialog.getSelectedItemIndex(); switch (choiceDialog.getSelectedItemIndex()) { case 0: saveWidgetAsImageToClipboard(image); break; case 1: saveWidgetAsImageToPrinter(widget, image); break; case 2: saveWidgetAsImageToFile(widget, image); break; } } /** * copy an image of the widget to the clipboard. */ void QtUtilities::saveWidgetAsImageToClipboard(QImage& image) { QApplication::clipboard()->setImage(image, QClipboard::Clipboard); } /** * print an image of the widget. */ void QtUtilities::saveWidgetAsImageToPrinter(QWidget* widget, QImage& image) { QPrinter printer; QPrintDialog dialog(&printer, widget); if (dialog.exec() == QDialog::Accepted) { QPainter painter(&printer); painter.drawImage(0, 0, image); } } /** * save an image of the widget to file. */ void QtUtilities::saveWidgetAsImageToFile(QWidget* widget, QImage& image) { static QString previousFileFilter; // // Create the file filters and file extensions and find the jpeg and ppm filters // QStringList fileFilterList; std::vector fileFilters; std::vector fileExtensions; std::vector fileFormats; QString jpegFileFilter; QString ppmFileFilter; for (int i = 0; i < QImageWriter::supportedImageFormats().count(); i++) { QString str = QString(QImageWriter::supportedImageFormats().at(i)); QString filter; if ((str == "JPEG") || (str == "jpeg")) { filter = QString("%1 Image File (*.jpg *.jpeg)").arg(str); fileExtensions.push_back("jpg"); jpegFileFilter = filter; } else if ((str == "JPEG") || (str == "JPG")) { filter = QString("%1 Image File (*.jpg *.jpeg)").arg(str); fileExtensions.push_back("jpg"); jpegFileFilter = filter; } else { filter = QString("%1 Image File (*.%2)").arg(str).arg( StringUtilities::makeLowerCase(str)); fileExtensions.push_back(StringUtilities::makeLowerCase(str)); if (filter == "PPM") { ppmFileFilter = filter; } } fileFilterList << filter; fileFilters.push_back(filter); fileFormats.push_back(str); } // // Create the file dialog // WuQFileDialog saveImageDialog(widget); saveImageDialog.setModal(true); saveImageDialog.setWindowTitle(QString("Save Image of ") + widget->objectName()); saveImageDialog.setFileMode(WuQFileDialog::AnyFile); saveImageDialog.setAcceptMode(WuQFileDialog::AcceptSave); saveImageDialog.setDirectory(QDir::currentPath()); // // Set the file filters // saveImageDialog.setFilters(fileFilterList); if (previousFileFilter.isEmpty() == false) { saveImageDialog.selectFilter(previousFileFilter); } else if (jpegFileFilter.isEmpty() == false) { saveImageDialog.selectFilter(jpegFileFilter); } else if (ppmFileFilter.isEmpty() == false) { saveImageDialog.selectFilter(ppmFileFilter); } // // Execute the dialog // if (saveImageDialog.exec() == WuQFileDialog::Accepted) { QString name(saveImageDialog.selectedFiles().at(0)); // // Get the selected file filter // previousFileFilter = saveImageDialog.selectedFilter(); // // Find the file filter // int fileFilterIndex = -1; for (unsigned int i = 0; i < fileFilters.size(); i++) { if (fileFilters[i] == previousFileFilter) { fileFilterIndex = i; break; } } // // See if invalid filter index // if (fileFilterIndex < 0) { QString msg("Program Error: invalid file filter index when saving image file."); QApplication::beep(); QMessageBox::critical(widget, "PROGRAM ERROR", msg, "OK"); return; } if (FileUtilities::filenameExtension(name) != fileExtensions[fileFilterIndex]) { name.append("."); name.append(fileExtensions[fileFilterIndex]); } if (image.save(name, fileFormats[fileFilterIndex].toAscii().constData(), 100) == false) { QApplication::beep(); QMessageBox::critical(widget, "ERROR", "Unable to save image.", "OK"); } } } /** * get the image capture key. */ bool QtUtilities::getImageCaptureKeySelected(QKeyEvent* ke) { if ((ke->key() == Qt::Key_F1) && (ke->modifiers() & Qt::ControlModifier) && (ke->modifiers() & Qt::ShiftModifier)) { return true; } return false; } /** * get the maximum height for a dialog or window. */ int QtUtilities::getMaximumWindowHeight() { const int mh = QApplication::desktop()->height() - 100; return mh; } /** * print the size of the widget. */ void QtUtilities::printWidgetSizeHint(QWidget* w, const QString& widgetName) { const QSize sz = w->sizeHint(); std::cout << "Size of widget " << widgetName.toAscii().constData() << " (" << sz.width() << ", " << sz.height() << ")" << std::endl; } /** * set the maximum height for a widget (gets around bug in QT if minimum size greater than maximum). */ void QtUtilities::setMaximumHeightToNinetyPercentOfScreenHeight(QWidget* w) { //std::cout << "Min Height: " << minimumHeight() << std::endl; const float mh = QtUtilities::getMaximumWindowHeight(); const int maxHeight = static_cast(mh * 0.90); //std::cout << "Max Height: " << mh << std::endl; w->setMinimumHeight(maxHeight / 2); w->setMaximumHeight(maxHeight); w->updateGeometry(); } caret-5.6.4~dfsg.1.orig/caret_widgets/QtTextFileEditorDialog.h0000664000175000017500000001250611572067322024102 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __QT_TEXT_FILE_EDITOR_DIALOG_H__ #define __QT_TEXT_FILE_EDITOR_DIALOG_H__ #include #include #include "WuQDialog.h" class QCheckBox; class QKeyEvent; class QLineEdit; class QPushButton; class QToolButton; class QtTextFileEditor; class QtTextFileEditorSearchDialog; class PreferencesFile; /// Dialog for editing text files class QtTextFileEditorDialog : public WuQDialog { Q_OBJECT public: /// Constructor QtTextFileEditorDialog(QWidget* parent); /// Destructor ~QtTextFileEditorDialog(); /// add additional file filters void addAdditionalFileFilters(QStringList& aff) { additionalFileFilters = aff; } /// load a file void loadFile(const QString& fileName, const bool richTextFlag = false); /// set the preferences file void setPreferencesFile(PreferencesFile* pf); private slots: /// called when open button is pressed void slotFileOpen(); /// called when as save as button is pressed void slotFileSaveAs(); /// called when save button is pressed void slotFileSave(); /// called when print button is pressed void slotPrint(); /// called to close the text file editor void slotClose(); /// called enable save button void slotEnableSaveButton(); /// called when find button pressed void slotFind(); /// called when font button pressed void slotFont(); /// called when go to button pressed void slotGoTo(); /// called to turn on/off text wrapping void slotWrap(); protected: // save a file void saveFile(const QString& name); /// the find/replace dialog QtTextFileEditorSearchDialog* findReplaceDialog; /// the text display QtTextFileEditor* textEditor; /// the wrap tool button QToolButton* wrapToolButton; /// save button QToolButton* saveToolButton; /// name of file being edited QString filename; /// additional file filters QStringList additionalFileFilters; /// current file filter QString currentFileFilter; /// previously search text QString previousSearchText; /// previously replace text QString previousReplaceText; /// paragraph of last search int paragraphNum; /// letter index in paragraph of last search int paragraphChar; /// previous Go To Line Number int previousLineNumber; /// the preferences file PreferencesFile* preferencesFile; }; /// text editor class QtTextFileEditor : public QTextEdit { Q_OBJECT public: // constructor QtTextFileEditor(QWidget* parent = 0); // destructor ~QtTextFileEditor(); signals: // find command requested void signalFindCommand(); protected: // called when keys pressed void keyPressEvent(QKeyEvent* event); }; /// search dialog class QtTextFileEditorSearchDialog : public QDialog { Q_OBJECT public: // constructor QtTextFileEditorSearchDialog(QTextEdit* editorIn, QWidget* parent = 0); // destructor ~QtTextFileEditorSearchDialog(); protected slots: // called when next button pressed void slotNextPushButton(); // called when previous button pressed void slotPreviousPushButton(); // called when replace button pressed void slotReplacePushButton(); // called when replace & find button pressed void slotReplaceAndFindPushButton(); // called when replace all button pressed void slotReplaceAllPushButton(); protected: // called to replace text (returns true if text was found and replaced) bool replaceText(); // called to search for text void searchForText(const bool searchBackwards); /// the text editor QTextEdit* editor; /// the find line edit QLineEdit* findLineEdit; /// the replace line edit QLineEdit* replaceLineEdit; /// case sensitive check box QCheckBox* caseSensitiveCheckBox; /// text previously searched for QString previousSearchText; }; #endif // __QT_TEXT_FILE_EDITOR_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret_widgets/QtTextFileEditorDialog.cxx0000664000175000017500000005507611572067322024466 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "FileUtilities.h" #include "QtMultipleInputDialog.h" #include "QtTextFileEditorDialog.h" #include "QtUtilities.h" #include "PreferencesFile.h" #include "TextFile.h" #include "WuQFileDialog.h" /** * The constructor. */ QtTextFileEditorDialog::QtTextFileEditorDialog(QWidget* parent) : WuQDialog(parent) { preferencesFile = NULL; findReplaceDialog = NULL; setAttribute(Qt::WA_DeleteOnClose); resize(400, 200); setWindowTitle("Text File Editor"); QVBoxLayout* rows = new QVBoxLayout(this); rows->setMargin(5); // // Create the toolbar // QHBoxLayout* toolbar = new QHBoxLayout; rows->addLayout(toolbar); // // Create the text editor // textEditor = new QtTextFileEditor; rows->addWidget(textEditor); textEditor->setWordWrapMode(QTextOption::NoWrap); // // Open toolbar button // QToolButton* openToolButton = new QToolButton; toolbar->addWidget(openToolButton); openToolButton->setText("Open"); openToolButton->setToolTip( "Open a file and load\n" "it into the editor."); QObject::connect(openToolButton, SIGNAL(clicked()), this, SLOT(slotFileOpen())); // // Save toolbar button // saveToolButton = new QToolButton; toolbar->addWidget(saveToolButton); saveToolButton->setText("Save"); saveToolButton->setToolTip( "Save the text in the\n" "editor to a file."); QObject::connect(saveToolButton, SIGNAL(clicked()), this, SLOT(slotFileSave())); // // Save As toolbar button // QToolButton* saveAsToolButton = new QToolButton; toolbar->addWidget(saveAsToolButton); saveAsToolButton->setText("Save As"); saveAsToolButton->setToolTip( "Save the text in the\n" "editor to a file."); QObject::connect(saveAsToolButton, SIGNAL(clicked()), this, SLOT(slotFileSaveAs())); // // Print toolbar button // QToolButton* printToolButton = new QToolButton; toolbar->addWidget(printToolButton); printToolButton->setText("Print"); printToolButton->setToolTip( "Print the text."); QObject::connect(printToolButton, SIGNAL(clicked()), this, SLOT(slotPrint())); // // Space after save // QLabel* spaceAfterSave = new QLabel(" "); spaceAfterSave->setFixedSize(spaceAfterSave->sizeHint()); toolbar->addWidget(spaceAfterSave); // // Copy toolbar button // QToolButton* copyToolButton = new QToolButton; toolbar->addWidget(copyToolButton); copyToolButton->setText("Copy"); copyToolButton->setToolTip( "Copy Selected Text."); QObject::connect(copyToolButton, SIGNAL(clicked()), textEditor, SLOT(copy())); // // Cut toolbar button // QToolButton* cutToolButton = new QToolButton; toolbar->addWidget(cutToolButton); cutToolButton->setText("Cut"); cutToolButton->setToolTip( "Cut Selected Text."); QObject::connect(cutToolButton, SIGNAL(clicked()), textEditor, SLOT(cut())); // // Paste toolbar button // QToolButton* pasteToolButton = new QToolButton; toolbar->addWidget(pasteToolButton); pasteToolButton->setText("Paste"); pasteToolButton->setToolTip( "Paste Text From Clipboard."); QObject::connect(pasteToolButton, SIGNAL(clicked()), textEditor, SLOT(paste())); // // Space after paste // QLabel* spaceAfterPaste = new QLabel(" "); spaceAfterPaste->setFixedSize(spaceAfterPaste->sizeHint()); toolbar->addWidget(spaceAfterPaste); // // Font toolbar button // QToolButton* fontToolButton = new QToolButton; toolbar->addWidget(fontToolButton); fontToolButton->setText("Font"); fontToolButton->setToolTip( "Set the font."); QObject::connect(fontToolButton, SIGNAL(clicked()), this, SLOT(slotFont())); // // Space after fond // QLabel* spaceAfterFont = new QLabel(" "); spaceAfterFont->setFixedSize(spaceAfterFont->sizeHint()); toolbar->addWidget(spaceAfterFont); // // Find toolbar button // QToolButton* findToolButton = new QToolButton; toolbar->addWidget(findToolButton); findToolButton->setText("Find"); findToolButton->setToolTip( "Find in Text."); QObject::connect(findToolButton, SIGNAL(clicked()), this, SLOT(slotFind())); QObject::connect(textEditor, SIGNAL(signalFindCommand()), this, SLOT(slotFind())); // // Goto toolbar button // QToolButton* gotoToolButton = new QToolButton; toolbar->addWidget(gotoToolButton); gotoToolButton->setText("GoTo"); gotoToolButton->setToolTip( "Go to a line."); QObject::connect(gotoToolButton, SIGNAL(clicked()), this, SLOT(slotGoTo())); // // Space after paste // QLabel* spaceAfterGoTo = new QLabel(" "); spaceAfterGoTo->setFixedSize(spaceAfterGoTo->sizeHint()); toolbar->addWidget(spaceAfterGoTo); // // Wrap toolbar button // wrapToolButton = new QToolButton; wrapToolButton->setText("Wrap"); wrapToolButton->setCheckable(true); wrapToolButton->setToolTip( "Toggles text wrapping."); QObject::connect(wrapToolButton, SIGNAL(clicked()), this, SLOT(slotWrap())); toolbar->addWidget(wrapToolButton); // // Pack toolbar items // toolbar->setStretchFactor(openToolButton, 0); toolbar->setStretchFactor(saveToolButton, 0); toolbar->setStretchFactor(spaceAfterSave, 0); toolbar->setStretchFactor(copyToolButton, 0); toolbar->setStretchFactor(cutToolButton, 0); toolbar->setStretchFactor(pasteToolButton, 0); toolbar->setStretchFactor(spaceAfterPaste, 0); toolbar->setStretchFactor(findToolButton, 0); toolbar->setStretchFactor(gotoToolButton, 0); toolbar->setStretchFactor(spaceAfterGoTo, 0); toolbar->setStretchFactor(wrapToolButton, 0); toolbar->addStretch(); // QLabel* spaceLabel = new QLabel(" "); // toolbar->setStretchFactor(spaceLabel, 1000); // // Close Buttons // QHBoxLayout* buttonsLayout2 = new QHBoxLayout; rows->addLayout(buttonsLayout2); buttonsLayout2->setSpacing(3); // // Close Button // QPushButton* closeButton = new QPushButton("Close"); buttonsLayout2->addWidget(closeButton); closeButton->setAutoDefault(false); closeButton->setFixedSize(closeButton->sizeHint()); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(slotClose())); resize(500, 300); currentFileFilter = "Any File (*)"; paragraphNum = 0; paragraphChar = 0; previousLineNumber = 0; QObject::connect(textEditor, SIGNAL(textChanged()), this, SLOT(slotEnableSaveButton())); slotEnableSaveButton(); wrapToolButton->setChecked(false); slotWrap(); } /** * The destructor. */ QtTextFileEditorDialog::~QtTextFileEditorDialog() { } /** * set the preferences file. */ void QtTextFileEditorDialog::setPreferencesFile(PreferencesFile* pf) { preferencesFile = pf; } /** * called when print button is pressed. */ void QtTextFileEditorDialog::slotPrint() { QPrinter printer; QPrintDialog* printDialog = new QPrintDialog(&printer, this); if (printDialog->exec() == QPrintDialog::Accepted) { textEditor->document()->print(&printer); } } /** * called when font button pressed. */ void QtTextFileEditorDialog::slotFont() { bool ok; QFont font = QFontDialog::getFont(&ok, textEditor->font(), this); if (ok) { textEditor->setFont(font); } } /** * called to turn on/off text wrapping. */ void QtTextFileEditorDialog::slotWrap() { if (wrapToolButton->isChecked()) { textEditor->setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); } else { textEditor->setWordWrapMode(QTextOption::NoWrap); } } /** * called when find button pressed. */ void QtTextFileEditorDialog::slotFind() { if (findReplaceDialog == NULL) { findReplaceDialog = new QtTextFileEditorSearchDialog(textEditor, this); } findReplaceDialog->show(); findReplaceDialog->activateWindow(); } /** * called when go to button pressed. */ void QtTextFileEditorDialog::slotGoTo() { bool ok = false; const int lineNum = QInputDialog::getInteger(this, "Go To Line Number", "Go To Line Number", previousLineNumber, 0, 1000000000, 1, &ok); if (ok) { previousLineNumber = lineNum; QTextCursor tc = textEditor->textCursor(); tc.movePosition(QTextCursor::Start); textEditor->setTextCursor(tc); tc.movePosition(QTextCursor::Down, QTextCursor::MoveAnchor, lineNum - 1); textEditor->setTextCursor(tc); //textEditor->setCursorPosition(previousLineNumber - 1, 0); } } /** * called enable save button. */ void QtTextFileEditorDialog::slotEnableSaveButton() { saveToolButton->setEnabled(false); if (filename.isEmpty() == false) { if (textEditor->document()->isModified()) { saveToolButton->setEnabled(true); } } } /** * called when open button is pressed. */ void QtTextFileEditorDialog::slotFileOpen() { WuQFileDialog fd(this); fd.setModal(true); fd.setDirectory(QDir::currentPath()); fd.setWindowTitle("Choose File"); fd.setFileMode(WuQFileDialog::ExistingFile); fd.setAcceptMode(WuQFileDialog::AcceptOpen); QStringList filters; filters << "Any File (*)"; filters << "Comma Separated Value File (*.csv)"; filters << "Text File (*.txt)"; const QString richTextFilter("Rich Text (*.rtf)"); // RTF does not work //fd.addFilter(richTextFilter); if (additionalFileFilters.empty() == false) { for (QStringList::Iterator it = additionalFileFilters.begin(); it != additionalFileFilters.end(); ++it) { filters << *it; } } fd.setFilters(filters); fd.selectFilter(currentFileFilter); if (preferencesFile != NULL) { fd.setHistory(preferencesFile->getRecentDataFileDirectories()); } if (fd.exec() == QDialog::Accepted) { currentFileFilter = fd.selectedFilter(); loadFile(fd.selectedFiles().at(0), (currentFileFilter == richTextFilter)); if (preferencesFile != NULL) { preferencesFile->addToRecentDataFileDirectories( FileUtilities::dirname(fd.selectedFiles().at(0)), true); } } } /** * load a file (returns true if an error occurs) */ void QtTextFileEditorDialog::loadFile(const QString& fileNameIn, const bool richTextFlag) { TextFile textFile; try { textFile.readFile(fileNameIn); } catch (FileException& e) { QMessageBox::critical(this, "ERROR", e.whatQString()); return; } textEditor->clear(); if (richTextFlag) { textEditor->setHtml(textFile.getText()); } else { textEditor->setPlainText(textFile.getText()); } textEditor->document()->setModified(false); filename = fileNameIn; QString caption("Text File Editor - "); caption.append(FileUtilities::basename(filename)); setWindowTitle(caption); paragraphNum = 0; paragraphChar = 0; previousLineNumber = 0; } /** * called when save button is pressed. */ void QtTextFileEditorDialog::slotFileSaveAs() { WuQFileDialog fd(this); fd.setModal(true); fd.setAcceptMode(WuQFileDialog::AcceptSave); fd.setWindowTitle("Choose File"); fd.setFileMode(WuQFileDialog::AnyFile); QStringList filters; filters << "Any File (*)"; filters << "Comma Separated Value File (*.csv)"; filters << "Text File (*.txt)"; if (additionalFileFilters.empty() == false) { for (QStringList::Iterator it = additionalFileFilters.begin(); it != additionalFileFilters.end(); ++it) { filters << *it; } } if (preferencesFile != NULL) { fd.setHistory(preferencesFile->getRecentDataFileDirectories()); } fd.setFilters(filters); fd.selectFilter(currentFileFilter); fd.setDirectory(FileUtilities::dirname(filename)); fd.selectFile(FileUtilities::basename(filename)); if (fd.exec() == QDialog::Accepted) { if (fd.selectedFiles().count() > 0) { filename = fd.selectedFiles().at(0); saveFile(filename); if (preferencesFile != NULL) { preferencesFile->addToRecentDataFileDirectories( FileUtilities::dirname(fd.selectedFiles().at(0)), true); } } } } /** * save a file. */ void QtTextFileEditorDialog::saveFile(const QString& name) { TextFile textFile; textFile.setText(textEditor->toPlainText()); try { textFile.writeFile(name); } catch (FileException& e) { QMessageBox::critical(this, "ERROR", e.whatQString()); return; } textEditor->document()->setModified(false); } /** * save a file. */ void QtTextFileEditorDialog::slotFileSave() { if (filename.isEmpty()) { QMessageBox::critical(this, "ERROR", "File name is empty, use \"Save As\".", "OK"); return; } if (QFile::exists(filename)) { QString msg(FileUtilities::basename(filename)); msg += " already exists.\n" "Do you want to replace it?"; if (QMessageBox::warning(this, "Confirm", msg, "Yes", "No") != 0) { return; } } saveFile(filename); } /** * called to close the text file editor. */ void QtTextFileEditorDialog::slotClose() { if (textEditor->document()->isModified()) { QApplication::beep(); if (QMessageBox::question(this, "File Changed Warning", "File in editor has been modified but not saved.\n" "Are you sure you want to close the text editor?", "Yes, Close Editor", "Cancel") == 1) { return; } } QDialog::close(); } //===================================================================================== // Text Editor Widget //===================================================================================== /** * constructor. */ QtTextFileEditor::QtTextFileEditor(QWidget* parent) : QTextEdit(parent) { } /** * destructor. */ QtTextFileEditor::~QtTextFileEditor() { } /** * called when keys pressed. */ void QtTextFileEditor::keyPressEvent(QKeyEvent* event) { if (event->matches(QKeySequence::Find)) { emit signalFindCommand(); } else { QTextEdit::keyPressEvent(event); } } //===================================================================================== // FIND DIALOG //===================================================================================== /** * constructor. */ QtTextFileEditorSearchDialog::QtTextFileEditorSearchDialog(QTextEdit* editorIn, QWidget* parent) : QDialog(parent) { editor = editorIn; // // Minimum width for line edit // const int minLineEditWidth = 300; // // Find and replace line edits and labels // QLabel* findLabel = new QLabel("Find"); findLineEdit = new QLineEdit; findLineEdit->setMinimumWidth(minLineEditWidth); QLabel* replaceLabel = new QLabel("Replace"); replaceLineEdit = new QLineEdit; replaceLineEdit->setMinimumWidth(minLineEditWidth); // // next push button // QPushButton* nextPushButton = new QPushButton("Next"); nextPushButton->setAutoDefault(true); QObject::connect(nextPushButton, SIGNAL(clicked()), this, SLOT(slotNextPushButton())); // // previous push button // QPushButton* previousPushButton = new QPushButton("Previous"); previousPushButton->setAutoDefault(false); QObject::connect(previousPushButton, SIGNAL(clicked()), this, SLOT(slotPreviousPushButton())); // // replace push button // QPushButton* replacePushButton = new QPushButton("Replace"); replacePushButton->setAutoDefault(false); QObject::connect(replacePushButton, SIGNAL(clicked()), this, SLOT(slotReplacePushButton())); // // replace and find push button // QPushButton* replaceAndFindPushButton = new QPushButton("Replace and Find"); replaceAndFindPushButton->setAutoDefault(false); QObject::connect(replaceAndFindPushButton, SIGNAL(clicked()), this, SLOT(slotReplaceAndFindPushButton())); // // replace push button // QPushButton* replaceAllPushButton = new QPushButton("Replace All"); replaceAllPushButton->setAutoDefault(false); QObject::connect(replaceAllPushButton, SIGNAL(clicked()), this, SLOT(slotReplaceAllPushButton())); // // Make all of the buttons the same size // QtUtilities::makeButtonsSameSize(nextPushButton, previousPushButton, replacePushButton, replaceAndFindPushButton, replaceAllPushButton); // // case sensitive check box // caseSensitiveCheckBox = new QCheckBox("Case Sensitive"); // // Grid layout for search controls // QGridLayout* gridLayout = new QGridLayout; gridLayout->addWidget(findLabel, 0, 0); gridLayout->addWidget(findLineEdit, 0, 1); gridLayout->addWidget(replaceLabel, 1, 0); gridLayout->addWidget(replaceLineEdit, 1, 1); gridLayout->addWidget(nextPushButton, 0, 2); gridLayout->addWidget(previousPushButton, 1, 2); gridLayout->addWidget(replacePushButton, 2, 2); gridLayout->addWidget(replaceAndFindPushButton, 3, 2); gridLayout->addWidget(replaceAllPushButton, 4, 2); gridLayout->addWidget(caseSensitiveCheckBox, 2, 0, 1, 2, Qt::AlignLeft); // // Close button // QPushButton* closePushButton = new QPushButton("Close"); closePushButton->setAutoDefault(false); closePushButton->setFixedSize(closePushButton->sizeHint()); QObject::connect(closePushButton, SIGNAL(clicked()), this, SLOT(close())); QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->addWidget(closePushButton); // // Layout for dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->addLayout(gridLayout); dialogLayout->addLayout(buttonsLayout); } /** * destructor. */ QtTextFileEditorSearchDialog::~QtTextFileEditorSearchDialog() { } /** * called to search for text. */ void QtTextFileEditorSearchDialog::searchForText(const bool searchBackwards) { QTextDocument::FindFlags findFlags; if (caseSensitiveCheckBox->isChecked()) { findFlags |= QTextDocument::FindCaseSensitively; } if (searchBackwards) { findFlags |= QTextDocument::FindBackward; } previousSearchText = findLineEdit->text(); if (previousSearchText.isEmpty() == false) { const bool textFound = editor->find(previousSearchText, findFlags); if (textFound == false) { QString msg("Text not found, search from beginning of file ?"); if (searchBackwards) { msg = "Text not found, search from end of file ?"; } if (QMessageBox::question(this, "Question", msg, "Yes", "No") == 0) { QTextCursor tc = editor->textCursor(); tc.movePosition(QTextCursor::Start); if (searchBackwards) { tc.movePosition(QTextCursor::End); } editor->setTextCursor(tc); editor->find(previousSearchText, findFlags); } } } } /** * called when next button pressed. */ void QtTextFileEditorSearchDialog::slotNextPushButton() { searchForText(false); } // called when previous button pressed void QtTextFileEditorSearchDialog::slotPreviousPushButton() { searchForText(true); } /** * called to replace text (returns true if text was found and replaced). */ bool QtTextFileEditorSearchDialog::replaceText() { QTextCursor tc = editor->textCursor(); if (tc.hasSelection()) { tc.removeSelectedText(); tc.insertText(replaceLineEdit->text()); return true; } return false; } /** * called when replace button pressed. */ void QtTextFileEditorSearchDialog::slotReplacePushButton() { replaceText(); } /** * called when replace & find button pressed. */ void QtTextFileEditorSearchDialog::slotReplaceAndFindPushButton() { if (replaceText()) { slotNextPushButton(); } } /** * called when replace all button pressed. */ void QtTextFileEditorSearchDialog::slotReplaceAllPushButton() { previousSearchText = findLineEdit->text(); if (previousSearchText.isEmpty() == false) { QTextDocument::FindFlags findFlags; if (caseSensitiveCheckBox->isChecked()) { findFlags |= QTextDocument::FindCaseSensitively; } // // Move to start of file // QTextCursor tc = editor->textCursor(); tc.movePosition(QTextCursor::Start); editor->setTextCursor(tc); while (editor->find(previousSearchText, findFlags)) { editor->cut(); editor->insertPlainText(replaceLineEdit->text()); } } } caret-5.6.4~dfsg.1.orig/caret_widgets/QtTextEditDialog.h0000664000175000017500000000311511572067322022735 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_QT_TEXT_EDIT_DIALOG_H__ #define __VE_QT_TEXT_EDIT_DIALOG_H__ #include #include "WuQDialog.h" class QTextEdit; /// Dialog that displays a scrolling text widget class QtTextEditDialog : public WuQDialog { Q_OBJECT public: /// Constructor QtTextEditDialog(QWidget* parent, const bool readOnly = false, const bool modalFlag = true); /// Destructor ~QtTextEditDialog(); /// set the text display void setText(const QString& s); /// get the text display QString getText() const; private: /// the text display QTextEdit* textEditor; }; #endif // __VE_QT_TEXT_EDIT_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret_widgets/QtTextEditDialog.cxx0000664000175000017500000000521711572067322023315 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include "QtTextEditDialog.h" #include "QtUtilities.h" /** * The constructor. */ QtTextEditDialog::QtTextEditDialog(QWidget* parent, const bool readOnly, const bool modalFlag) : WuQDialog(parent) { setModal(modalFlag); if (modalFlag == false) { // // Destroy the dialog when it is closed // setAttribute(Qt::WA_DeleteOnClose); } resize(400, 200); setWindowTitle("Text Editor"); QVBoxLayout* rows = new QVBoxLayout(this); rows->setSpacing(5); textEditor = new QTextEdit; textEditor->setReadOnly(readOnly); rows->addWidget(textEditor); // // OK and Cancel Buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; rows->addLayout(buttonsLayout); QPushButton* okButton = NULL; if (readOnly == false) { okButton = new QPushButton("OK"); QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); buttonsLayout->addWidget(okButton); } QPushButton* cancelButton = new QPushButton("Cancel"); buttonsLayout->addWidget(cancelButton); QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); if (readOnly) { cancelButton->setText("Close"); cancelButton->setFixedSize(cancelButton->sizeHint()); } else { QtUtilities::makeButtonsSameSize(okButton, cancelButton); } } /** * The destructor. */ QtTextEditDialog::~QtTextEditDialog() { } /** * Set the text in the text editor. */ void QtTextEditDialog::setText(const QString& s) { textEditor->setPlainText(s); } /** * Get the text in the editor */ QString QtTextEditDialog::getText() const { return textEditor->toPlainText(); } caret-5.6.4~dfsg.1.orig/caret_widgets/QtTableDialog.h0000664000175000017500000000360411572067322022235 0ustar michaelmichael#ifndef __QT_TABLE_DIALOG_H__ #define __QT_TABLE_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "WuQDialog.h" class QContextMenuEvent; class StringTable; class QTableWidget; /// dialog for displaying data in a Qt Table class QtTableDialog : public WuQDialog { Q_OBJECT public: // constructor QtTableDialog(QWidget* parent, const QString& title, const StringTable& dataTable, const bool deleteMeWhenClosed); // destructor ~QtTableDialog(); protected slots: /// called when context menu requested //void slotContextMenu(QContextMenuEvent* e); /// called when sort button is pressed void slotSortButton(); /// called when save as text button is pressed void slotSaveAsTextButton(); protected: /// the table QTableWidget* table; /// names of columns QStringList columnNames; }; #endif // __QT_TABLE_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret_widgets/QtTableDialog.cxx0000664000175000017500000002163611572067322022615 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more detailsx. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Softwarexx * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include "StringTable.h" #include "QtListBoxSelectionDialog.h" #include "QtRadioButtonSelectionDialog.h" #include "QtTableDialog.h" #include "QtUtilities.h" #include "WuQFileDialog.h" /** * constructor. */ QtTableDialog::QtTableDialog(QWidget* parentWidget, const QString& title, const StringTable& dataTable, const bool deleteMeWhenClosed) : WuQDialog(parentWidget) { if (deleteMeWhenClosed) { setAttribute(Qt::WA_DeleteOnClose); } setWindowTitle(title); // // Layout for dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(5); // // Add the table and load it with data // const int nr = dataTable.getNumberOfRows(); const int nc = dataTable.getNumberOfColumns(); table = new QTableWidget(nr, nc); for (int i = 0; i < nr; i++) { for (int j = 0; j < nc; j++) { table->setItem(i, j, new QTableWidgetItem(dataTable.getElement(i, j))); } } if (nc == 1) { table->setColumnWidth(0, 500); } dialogLayout->addWidget(table); // // Set the table's left margin // //const int numChars = static_cast(std::log10(static_cast(nr))) + 3; //table->setLeftMargin(table->fontMetrics().width(QString().fill('X', numChars))); // // Set the column titles for the table // columnNames.clear(); for (int j = 0; j < nc; j++) { columnNames << dataTable.getColumnTitle(j); } table->setHorizontalHeaderLabels(columnNames); // // connect signals from QTable // //QObject::connect(table, SIGNAL(contextMenuEvent(QContextMenuEvent*)), // this, SLOT(slotContextMenu(QContextMenuEvent*))); // // Layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; dialogLayout->addLayout(buttonsLayout); buttonsLayout->setSpacing(5); // // Save as Text button // QPushButton* saveAsTextButton = new QPushButton("Save As Text..."); buttonsLayout->addWidget(saveAsTextButton); saveAsTextButton->setAutoDefault(false); QObject::connect(saveAsTextButton, SIGNAL(clicked()), this, SLOT(slotSaveAsTextButton())); // // Sort button // QPushButton* sortButton = new QPushButton("Sort..."); buttonsLayout->addWidget(sortButton); sortButton->setAutoDefault(false); QObject::connect(sortButton, SIGNAL(clicked()), this, SLOT(slotSortButton())); // // Close button // QPushButton* closeButton = new QPushButton("Close"); buttonsLayout->addWidget(closeButton); closeButton->setAutoDefault(false); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); QtUtilities::makeButtonsSameSize(saveAsTextButton, closeButton, sortButton); } /** * destructor. */ QtTableDialog::~QtTableDialog() { } /** * called when save as text button is pressed. */ void QtTableDialog::slotSaveAsTextButton() { // // Use file dialog to get name of file // WuQFileDialog fd(this); fd.setModal(true); fd.setWindowTitle("Choose File for Export"); fd.setFileMode(WuQFileDialog::AnyFile); fd.setDirectory("."); fd.setAcceptMode(WuQFileDialog::AcceptSave); const QString textFilter("Text Files (*.txt *.text)"); QStringList filters; filters << textFilter << "All Files (*)"; fd.selectFilter(textFilter); if (fd.exec() == QDialog::Accepted) { QString filename = fd.selectedFiles().at(0); if (filename.isEmpty() == false) { // // Add extension if needed // if (fd.selectedFilter() == textFilter) { if ((filename.endsWith(".txt", Qt::CaseInsensitive) == false) && (filename.endsWith(".text", Qt::CaseInsensitive) == false)) { filename += ".txt"; } } // // Get separator to place between elements in file // const QString colonString("colon"); const QString commaString("comma"); const QString semicolonString("semicolon"); const QString spaceString("space"); const QString tabString("tab"); static QString selectedSeparator(semicolonString); std::vector separators; separators.push_back(colonString); separators.push_back(commaString); separators.push_back(semicolonString); separators.push_back(spaceString); separators.push_back(tabString); int defaultItem = 0; for (unsigned int i = 0; i < separators.size(); i++) { if (selectedSeparator == separators[i]) { defaultItem = i; } } // // Allow user to choose separator // QApplication::beep(); QtRadioButtonSelectionDialog rbd(this, "Choose Separator", "Choose separator that is placed\n" "between each element in the file.", separators, defaultItem); if (rbd.exec() == QDialog::Accepted) { selectedSeparator = separators[rbd.getSelectedItemIndex()]; QString separator(";"); if (selectedSeparator == colonString) { separator = ":"; } else if (selectedSeparator == commaString) { separator = ","; } else if (selectedSeparator == semicolonString) { separator = ";"; } else if (selectedSeparator == spaceString) { separator = " "; } else if (selectedSeparator == tabString) { separator = "\t"; } // // Write the data to the file // QFile file(filename); if (file.open(QIODevice::WriteOnly)) { QTextStream stream(&file); for (int j = 0; j < table->columnCount(); j++) { if (j > 0) { stream << separator; } stream << table->horizontalHeaderItem(j)->text(); } stream << "\n"; for (int i = 0; i < table->rowCount(); i++) { for (int j = 0; j < table->columnCount(); j++) { if (j > 0) { stream << separator; } stream << table->item(i, j)->text(); } stream << "\n"; } } else { QApplication::beep(); QString msg("Unable to open " + filename + " for writing."); QMessageBox::critical(this, "ERROR", msg, "OK"); return; } } } } } /** * called when sort button is pressed. */ void QtTableDialog::slotSortButton() { QtListBoxSelectionDialog lbsd(this, "Choose Column for Sorting", "Select the column for sorting", columnNames, -1); if (lbsd.exec() == QDialog::Accepted) { const int column = lbsd.getSelectedItemIndex(); if (column >= 0) { table->sortByColumn(column); } } } /** * called when context menu requested. * void QtTableDialog::slotContextMenu(QContextMenuEvent* e) { //std::cout << "Context Menu: " << row << ", " << col << std::endl; } */ caret-5.6.4~dfsg.1.orig/caret_widgets/QtScriptInputDialog.h0000664000175000017500000000325611572067322023475 0ustar michaelmichael #ifndef __QT_INPUT_DIALOG_H__ #define __QT_INPUT_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include class QLineEdit; /// dialog for input data with optional file selection button class QtScriptInputDialog : public QDialog { Q_OBJECT public: // constructor QtScriptInputDialog(QWidget* parent, const QString& messageText, const bool showFileSelectionPushButtonFlag = false, Qt::WindowFlags f = 0); // constructor ~QtScriptInputDialog(); // get text entered by user QString getInputText() const; protected slots: // called when file push button is selected void slotFilePushButton(); protected: // the line edit QLineEdit* lineEdit; }; #endif // __QT_INPUT_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret_widgets/QtScriptInputDialog.cxx0000664000175000017500000000632011572067322024043 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "FileFilters.h" #include "QtScriptInputDialog.h" #include "WuQFileDialog.h" /** * constructor. */ QtScriptInputDialog::QtScriptInputDialog(QWidget* parent, const QString& messageText, const bool showFileSelectionPushButtonFlag, Qt::WindowFlags f) : QDialog(parent, f) { QLabel* label = new QLabel(messageText); lineEdit = new QLineEdit; QPushButton* filePushButton = NULL; if (showFileSelectionPushButtonFlag) { filePushButton = new QPushButton("Select File..."); filePushButton->setAutoDefault(false); filePushButton->setFixedSize(filePushButton->sizeHint()); QObject::connect(filePushButton, SIGNAL(clicked()), this, SLOT(slotFilePushButton())); } QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(label); layout->addWidget(lineEdit); if (filePushButton != NULL) { layout->addWidget(filePushButton); } // // Dialog buttons // QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); layout->addWidget(buttonBox); QObject::connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); QObject::connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); } /** * constructor. */ QtScriptInputDialog::~QtScriptInputDialog() { } /** * called when file push button is selected. */ void QtScriptInputDialog::slotFilePushButton() { QStringList allFileFilters; FileFilters::getAllFileFilters(allFileFilters); WuQFileDialog fd(this); fd.setModal(true); fd.setAcceptMode(WuQFileDialog::AcceptOpen); fd.setDirectory("."); fd.setFileMode(WuQFileDialog::ExistingFile); fd.setFilters(allFileFilters); fd.selectFilter(FileFilters::getAnyFileFilter()); if (fd.exec() == WuQFileDialog::Accepted) { QStringList selectedFiles = fd.selectedFiles(); if (selectedFiles.count() > 0) { lineEdit->setText(selectedFiles.at(0)); } } } /** * get text entered by user. */ QString QtScriptInputDialog::getInputText() const { return lineEdit->text().trimmed(); } caret-5.6.4~dfsg.1.orig/caret_widgets/QtRadioButtonSelectionDialog.h0000664000175000017500000000347611572067322025315 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __QT_RADIO_BUTTON_SELELCTION_DIALOG_H__ #define __QT_RADIO_BUTTON_SELELCTION_DIALOG_H__ #include "WuQDialog.h" #include #include class QButtonGroup; /// class that creates a dialog for choosing mutually exlusive items class QtRadioButtonSelectionDialog : public WuQDialog { Q_OBJECT public: /// constructor QtRadioButtonSelectionDialog(QWidget* parent, const QString& title, const QString& message, const std::vector& itemLabels, const int defaultItem = -1); /// destructor ~QtRadioButtonSelectionDialog(); /// get the selected item index int getSelectedItemIndex() const; private: /// button group for the radio buttons QButtonGroup* radioButtonGroup; }; #endif // __QT_RADIO_BUTTON_SELELCTION_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret_widgets/QtRadioButtonSelectionDialog.cxx0000664000175000017500000000705611572067322025666 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "QtRadioButtonSelectionDialog.h" #include "QtUtilities.h" /** * Constructor. */ QtRadioButtonSelectionDialog::QtRadioButtonSelectionDialog(QWidget* parent, const QString& title, const QString& message, const std::vector& itemLabels, const int defaultItem) : WuQDialog(parent) { setModal(true); setWindowTitle(title); // // layout for dialog // QVBoxLayout* layout = new QVBoxLayout; layout->setMargin(5); layout->setSpacing(5); setLayout(layout); // // display message // if (message.isEmpty() == false) { layout->addWidget(new QLabel(message)); } // // radio button group for radio buttons // radioButtonGroup = new QButtonGroup(this); // // vertical box for radio buttons // QVBoxLayout* buttonBox = new QVBoxLayout; layout->addLayout(buttonBox); // // create the radio buttons // for (int i = 0; i < static_cast(itemLabels.size()); i++) { QRadioButton* rb = new QRadioButton(itemLabels[i]); buttonBox->addWidget(rb); radioButtonGroup->addButton(rb, i); } // // set the default radio button // if ((defaultItem >= 0) && (defaultItem < radioButtonGroup->buttons().count())) { QRadioButton* rb = dynamic_cast(radioButtonGroup->button(defaultItem)); if (rb != NULL) { rb->setChecked(true); } } // // Add the OK button and connect to accept slot // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(5); layout->addLayout(buttonsLayout); QPushButton* okButton = new QPushButton("OK"); buttonsLayout->addWidget(okButton); QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); QPushButton* cancelButton = new QPushButton("Cancel"); buttonsLayout->addWidget(cancelButton); QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); QtUtilities::makeButtonsSameSize(okButton, cancelButton); } /** * Destructor. */ QtRadioButtonSelectionDialog::~QtRadioButtonSelectionDialog() { } /** * Get the selected item index. */ int QtRadioButtonSelectionDialog::getSelectedItemIndex() const { const int itemNum = radioButtonGroup->checkedId(); return itemNum; /* QButton* selectedButton = radioButtonGroup->selected(); if (selectedButton != NULL) { return radioButtonGroup->id(selectedButton); } return -1; */ } caret-5.6.4~dfsg.1.orig/caret_widgets/QtMultipleInputDialog.h0000664000175000017500000000516511572067322024025 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __QT_MULTIPLE_INPUT_DIALOG_H__ #define __QT_MULTIPLE_INPUT_DIALOG_H__ #include #include #include "WuQDialog.h" class QLineEdit; /// class that creates a modal dialog for input of multiple items class QtMultipleInputDialog : public WuQDialog { Q_OBJECT public: /// constructor QtMultipleInputDialog(QWidget* parent, const QString& title, const QString& instructions, const std::vector& rowLabels, const std::vector& rowValues, const bool enableCancelButton = true, const bool modalIn = true, Qt::WindowFlags f = 0); /// destructor ~QtMultipleInputDialog(); /// get values as strings void getValues(std::vector& values) const; /// get values as integers void getValues(int values[]) const; /// get values as floats void getValues(float values[]) const; /// get values as doubles void getValues(double values[]) const; /// get values as integers in a vector void getValues(std::vector& values) const; /// get values as floats in a vector void getValues(std::vector& values) const; /// get values as doubles in a vector void getValues(std::vector& values) const; signals: /// emitted when apply button pressed (non-modal only) void signalApplyPressed(); private: /// value line edits std::vector valueLineEdits; }; #endif // __QT_MULTIPLE_INPUT_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret_widgets/QtMultipleInputDialog.cxx0000664000175000017500000001421711572067322024376 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "QtMultipleInputDialog.h" #include "QtUtilities.h" /** * Constructor. * Instructions (if any) are placed at the top of the dialog. * The dialog may be modal or non-modal. If non-model, Qt::WDestructiveClose may be * passed for the WFlags to automatically destroy the dialog when the Close button * is pressed. * enableCancelButton is valid only for a modal dialog. */ QtMultipleInputDialog::QtMultipleInputDialog(QWidget* parent, const QString& title, const QString& instructions, const std::vector& rowLabels, const std::vector& rowValues, const bool enableCancelButton, const bool modalIn, Qt::WindowFlags f) : WuQDialog(parent, f) { setModal(modalIn); setWindowTitle(title); QVBoxLayout* layout = new QVBoxLayout; layout->setSpacing(3); layout->setMargin(3); setLayout(layout); if (instructions.isEmpty() == false) { layout->addWidget(new QLabel(instructions, this)); } // // Grid for labels and line edits // QGridLayout* grid = new QGridLayout; layout->addLayout(grid); grid->setSpacing(5); // // create the labels and line edits // for (unsigned int i = 0; i < rowLabels.size(); i++) { grid->addWidget(new QLabel(rowLabels[i]), i, 0); QLineEdit* le = new QLineEdit; valueLineEdits.push_back(le); if (i < rowValues.size()) { le->setText(rowValues[i]); } grid->addWidget(le, i, 1); } // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; layout->setSpacing(2); layout->addLayout(buttonsLayout); // // is this dialog modal // if (isModal()) { // // OK button // QPushButton* okButton = new QPushButton("OK"); buttonsLayout->addWidget(okButton); QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); // // Cancel button connects to QDialogs close() slot. // if (enableCancelButton) { QPushButton* cancelButton = new QPushButton("Cancel"); buttonsLayout->addWidget(cancelButton); QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); QtUtilities::makeButtonsSameSize(okButton, cancelButton); } else { okButton->setFixedSize(okButton->sizeHint()); } } else { // // Apply button // QPushButton* applyButton = new QPushButton("Apply"); buttonsLayout->addWidget(applyButton); applyButton->setAutoDefault(false); QObject::connect(applyButton, SIGNAL(clicked()), this, SIGNAL(signalApplyPressed())); // // Close button connects to QDialogs close() slot. // QPushButton* closeButton = new QPushButton("Close"); buttonsLayout->addWidget(closeButton); closeButton->setAutoDefault(false); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); QtUtilities::makeButtonsSameSize(applyButton, closeButton); } } /** * destructor. */ QtMultipleInputDialog::~QtMultipleInputDialog() { } /** * get values as strings. */ void QtMultipleInputDialog::getValues(std::vector& values) const { values.clear(); for (unsigned int i = 0; i < valueLineEdits.size(); i++) { values.push_back(valueLineEdits[i]->text()); } } /** * get values as integers in a vector. */ void QtMultipleInputDialog::getValues(std::vector& values) const { values.clear(); for (unsigned int i = 0; i < valueLineEdits.size(); i++) { values.push_back(valueLineEdits[i]->text().toInt()); } } /** * get values as floats in a vector. */ void QtMultipleInputDialog::getValues(std::vector& values) const { values.clear(); for (unsigned int i = 0; i < valueLineEdits.size(); i++) { values.push_back(valueLineEdits[i]->text().toFloat()); } } /** * get values as doubles in a vector. */ void QtMultipleInputDialog::getValues(std::vector& values) const { values.clear(); for (unsigned int i = 0; i < valueLineEdits.size(); i++) { values.push_back(valueLineEdits[i]->text().toDouble()); } } /** * get values as integers. */ void QtMultipleInputDialog::getValues(int values[3]) const { for (unsigned int i = 0; i < valueLineEdits.size(); i++) { values[i] = valueLineEdits[i]->text().toInt(); } } /** * get values as floats. */ void QtMultipleInputDialog::getValues(float values[3]) const { for (unsigned int i = 0; i < valueLineEdits.size(); i++) { values[i] = valueLineEdits[i]->text().toFloat(); } } /** * get values as doubles. */ void QtMultipleInputDialog::getValues(double values[3]) const { for (unsigned int i = 0; i < valueLineEdits.size(); i++) { values[i] = valueLineEdits[i]->text().toDouble(); } } caret-5.6.4~dfsg.1.orig/caret_widgets/QtListBoxSelectionDialog.h0000664000175000017500000000735611572067322024450 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_QT_LIST_BOX_SELECTION_DIALOG_H__ #define __GUI_QT_LIST_BOX_SELECTION_DIALOG_H__ #include "WuQDialog.h" #include #include class QListWidget; class QListWidgetItem; /// Dialog for selecting items in a list box class QtListBoxSelectionDialog : public WuQDialog { Q_OBJECT public: /// Constructor that adds select all button QtListBoxSelectionDialog(QWidget* parent, const QString& title, const QString& instructions, const std::vector& items, const QString& selectAllButtonLabel, const int defaultItem); /// Constructor QtListBoxSelectionDialog(QWidget* parent, const QString& title, const QString& instructions, const std::vector& items, const int defaultItem = -1); /// Constructor QtListBoxSelectionDialog(QWidget* parent, const QString& title, const QString& instructions, const QStringList& items, const int defaultItem = -1); /// Constructor QtListBoxSelectionDialog(QWidget* parent, const QString& title); /// Destructor ~QtListBoxSelectionDialog(); /// allow multiple item selection void setAllowMultipleItemSelection(const bool allowIt); /// set the contents of the list box void setListBoxContents(const std::vector& contents, const int defaultIndex = -1); /// get the selected item int getSelectedItemIndex() const; /// get the selected item text QString getSelectedText() const; /// get multiple selected items void getSelectedItemsIndices(std::vector& selectedItemIndices) const; /// get multiple selected items void getSelectedItems(std::vector& selectedItems) const; protected slots: /// called when select all pushbutton is pressed void slotSelectAllPushButton(); protected: /// the list box QListWidget* listWidget; /// items in list widget std::vector items; /// create the dialog void createDialog(const QString& title, const QString& selectAllButtonLabel, const QString& instructions); /// items input by the user std::vector inputItems; }; #endif // __GUI_QT_LIST_BOX_SELECTION_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret_widgets/QtListBoxSelectionDialog.cxx0000664000175000017500000001545511572067322025022 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "QtListBoxSelectionDialog.h" #include "QtUtilities.h" /** * Constructor that adds select all button */ QtListBoxSelectionDialog::QtListBoxSelectionDialog(QWidget* parent, const QString& title, const QString& instructions, const std::vector& items, const QString& selectAllButtonLabel, const int defaultItem) : WuQDialog(parent) { createDialog(title, selectAllButtonLabel, instructions); setListBoxContents(items, defaultItem); } /** * Constructor */ QtListBoxSelectionDialog::QtListBoxSelectionDialog(QWidget* parent, const QString& title, const QString& instructions, const std::vector& items, const int defaultItem) : WuQDialog(parent) { createDialog(title, "", instructions); setListBoxContents(items, defaultItem); } /** * Constructor */ QtListBoxSelectionDialog::QtListBoxSelectionDialog(QWidget* parent, const QString& title, const QString& instructions, const QStringList& itemList, const int defaultItem) : WuQDialog(parent) { std::vector items; for (int i = 0; i < itemList.count(); i++) { items.push_back(itemList[i]); } createDialog(title, "", instructions); setListBoxContents(items, defaultItem); } QtListBoxSelectionDialog::QtListBoxSelectionDialog(QWidget* parent, const QString& title) : WuQDialog(parent) { createDialog(title, "", ""); } /** * Destructor */ QtListBoxSelectionDialog::~QtListBoxSelectionDialog() { } /** * */ void QtListBoxSelectionDialog::setAllowMultipleItemSelection(const bool allowIt) { if (allowIt) { listWidget->setSelectionMode(QListWidget::ExtendedSelection); } else { listWidget->setSelectionMode(QListWidget::SingleSelection); } } /** * Create the dialog. */ void QtListBoxSelectionDialog::createDialog(const QString& title, const QString& selectAllButtonLabel, const QString& instructions) { setWindowTitle(title); QVBoxLayout* layout = new QVBoxLayout; layout->setMargin(3); layout->setSpacing(3); setLayout(layout); if (instructions.isEmpty() == false) { layout->addWidget(new QLabel(instructions, this)); } listWidget = new QListWidget; layout->addWidget(listWidget); if (selectAllButtonLabel.isEmpty() == false) { listWidget->setSelectionMode(QListWidget::ExtendedSelection); QPushButton* selectAllPushButton = new QPushButton(selectAllButtonLabel); selectAllPushButton->setAutoDefault(false); selectAllPushButton->setFixedSize(selectAllPushButton->sizeHint()); QObject::connect(selectAllPushButton, SIGNAL(clicked()), this, SLOT(slotSelectAllPushButton())); layout->addWidget(selectAllPushButton); } // // Dialog buttons // QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); layout->addWidget(buttonBox); QObject::connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); QObject::connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); } /** * called when select all pushbutton is pressed. */ void QtListBoxSelectionDialog::slotSelectAllPushButton() { for (unsigned int i = 0; i < items.size(); i++) { listWidget->setItemSelected(items[i], true); } } /** * Load the list box */ void QtListBoxSelectionDialog::setListBoxContents(const std::vector& contents, const int defaultIndex) { inputItems = contents; listWidget->clear(); items.clear(); for (unsigned int i = 0; i < contents.size(); i++) { QListWidgetItem* it = new QListWidgetItem(contents[i]); listWidget->addItem(it); items.push_back(it); } if (defaultIndex >= 0) { listWidget->setItemSelected(items[defaultIndex], true); } } /* * Get the selected item */ int QtListBoxSelectionDialog::getSelectedItemIndex() const { const int num = listWidget->count(); for (int i = 0; i < num; i++) { if (listWidget->isItemSelected(items[i])) { return i; } } return -1; } /** * Get the text of the selected item */ QString QtListBoxSelectionDialog::getSelectedText() const { QString txt; const int indx = getSelectedItemIndex(); if (indx >= 0) { txt = items[indx]->text(); } return txt; } /** * get multiple selected items. */ void QtListBoxSelectionDialog::getSelectedItems(std::vector& selectedItems) const { selectedItems.clear(); const int num = listWidget->count(); for (int i = 0; i < num; i++) { if (listWidget->isItemSelected(items[i])) { selectedItems.push_back(inputItems[i]); } } } /** * get multiple selected items. On return vector contain selected item indices. */ void QtListBoxSelectionDialog::getSelectedItemsIndices(std::vector& selectedItemIndices) const { selectedItemIndices.clear(); const int num = listWidget->count(); for (int i = 0; i < num; i++) { if (listWidget->isItemSelected(items[i])) { selectedItemIndices.push_back(i); } } } caret-5.6.4~dfsg.1.orig/caret_widgets/QtDialogWizard.h0000664000175000017500000000773411572067322022456 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include class QPushButton; class QStackedWidget; class QTextBrowser; /// a wizard dialog created since the A**holes at Trolltech got rid of QWizard in QT4 class QtDialogWizard : public QDialog { Q_OBJECT public: // constructor QtDialogWizard(QWidget* parent = 0, const bool enableHelpSection = false, Qt::WFlags f = 0); // destructor ~QtDialogWizard(); // update the dialog virtual void updateDialog(); signals: // emitted when finish button is pressed void signalFinishButtonPressed(); protected slots: // user should connect this to widgets that affect page and button validity void slotUpdatePageAndButtonValidity(); protected: // Initialize the dialog (call from derived classes constructor). void initializeDialog(); // add a page to the dialog void addPage(QWidget* pageWidget, const QString& helpText = ""); // see if a page is valid bool getPageValid(QWidget* pageWidget); // set a page's validity user should call this from setValidPagesAndButtons() void setPageValid(QWidget* pageWidget, const bool pageValidFlag); // called when a page is about to show user should override this virtual void pageAboutToShow(QWidget* pageWidget); // read from a page before going to next page user should override this virtual void pageAboutToChange(QWidget* pageWidget); // set the pages that are valid and buttons that are valid (all invalid when this called) virtual void setValidPagesAndButtons(QWidget* currentWidget) = 0; // set the finish button enabled user should call this from setValidPagesAndButtons() void setFinishButtonEnabled(const bool enableIt, const QString& finishButtonText = "Finish"); protected slots: // called when next button pressed void slotNextPushButton(); // called when prev button pressed void slotPrevPushButton(); // called when close button pressed void slotClosePushButton(); private: // set the next button enabled user should call this from setValidPagesAndButtons() virtual void setNextButtonEnabled(const bool enableIt); // show a page in the dialog void showPage(QWidget* pageWidget); /// stacked widget containing the pages /// the page widgets QStackedWidget* pageStackedWidget; /// help text for a page std::map pageHelpText; /// the page widget validity flags std::map pageValidityFlags; /// the help section QTextBrowser* helpBrowser; /// the prev push button QPushButton* prevPushButton; /// the next pushbutton QPushButton* nextPushButton; /// the finish push button QPushButton* finishPushButton; }; caret-5.6.4~dfsg.1.orig/caret_widgets/QtDialogWizard.cxx0000664000175000017500000002076511572067322023030 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "QtDialogWizard.h" #include "QtUtilities.h" /** * constructor. */ QtDialogWizard::QtDialogWizard(QWidget* parent, const bool enableHelpSection, Qt::WFlags f) : QDialog(parent, f) { // // Widget stack for page widgets // pageStackedWidget = new QStackedWidget; // // Help browser // helpBrowser = NULL; if (enableHelpSection) { helpBrowser = new QTextBrowser; } // // prev push button // prevPushButton = new QPushButton("Prev"); prevPushButton->setAutoDefault(false); QObject::connect(prevPushButton, SIGNAL(clicked()), this, SLOT(slotPrevPushButton())); // // next push button // nextPushButton = new QPushButton("Next"); nextPushButton->setAutoDefault(false); QObject::connect(nextPushButton, SIGNAL(clicked()), this, SLOT(slotNextPushButton())); // // finish push button // finishPushButton = new QPushButton("Finish"); finishPushButton->setAutoDefault(false); QObject::connect(finishPushButton, SIGNAL(clicked()), this, SIGNAL(signalFinishButtonPressed())); // // close push button // QPushButton* closePushButton = new QPushButton("Close"); closePushButton->setAutoDefault(false); QObject::connect(closePushButton, SIGNAL(clicked()), this, SLOT(slotClosePushButton())); // // Make buttons same size // QtUtilities::makeButtonsSameSize(prevPushButton, nextPushButton, finishPushButton, closePushButton); // // Layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->addWidget(prevPushButton); buttonsLayout->addWidget(nextPushButton); buttonsLayout->addWidget(finishPushButton); buttonsLayout->addWidget(closePushButton); // // Layout for dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->addWidget(pageStackedWidget); if (helpBrowser != NULL) { dialogLayout->addWidget(helpBrowser); } dialogLayout->addLayout(buttonsLayout); } /** * destructor. */ QtDialogWizard::~QtDialogWizard() { } /** * Initialize the dialog (call from derived classes constructor). */ void QtDialogWizard::initializeDialog() { // // Initialize the dialog // QWidget* firstWidget = pageStackedWidget->widget(0); if (firstWidget != NULL) { pageAboutToShow(firstWidget); pageStackedWidget->setCurrentWidget(firstWidget); } slotUpdatePageAndButtonValidity(); } /** * update the dialog. */ void QtDialogWizard::updateDialog() { slotUpdatePageAndButtonValidity(); } /** * user should connect this to widgets that affect page and button validity. */ void QtDialogWizard::slotUpdatePageAndButtonValidity() { // // Disable all buttons and pages // prevPushButton->setEnabled(false); setNextButtonEnabled(false); setFinishButtonEnabled(false, finishPushButton->text()); for (int i = 0; i < pageStackedWidget->count(); i++) { pageValidityFlags[pageStackedWidget->widget(i)] = false; } // // Let user update page and button validities // setValidPagesAndButtons(pageStackedWidget->currentWidget()); // // Get index of current page // const int currentPageIndex = pageStackedWidget->currentIndex(); // // Enable prev button if a page before the current is enabled // If finish button is NOT enabled, // enable next button if a page after the current is enabled // for (int i = 0; i < pageStackedWidget->count(); i++) { QWidget* w = pageStackedWidget->widget(i); if (i < currentPageIndex) { if (getPageValid(w)) { prevPushButton->setEnabled(true); } } else if (i > currentPageIndex) { if (finishPushButton->isEnabled() == false) { if (getPageValid(w)) { nextPushButton->setEnabled(true); } } } } } /** * add a page to the dialog. */ void QtDialogWizard::addPage(QWidget* pageWidget, const QString& helpText) { pageStackedWidget->addWidget(pageWidget); pageHelpText[pageWidget] = helpText; pageValidityFlags[pageWidget] = false; } /** * see if a page is valid. */ bool QtDialogWizard::getPageValid(QWidget* pageWidget) { return pageValidityFlags[pageWidget]; } /** * set a page's validity user should call this from setValidPagesAndButtons() */ void QtDialogWizard::setPageValid(QWidget* pageWidget, const bool pageValidFlag) { pageValidityFlags[pageWidget] = pageValidFlag; } /** * show a page in the dialog. */ void QtDialogWizard::showPage(QWidget* pageWidget) { // // Notify that page is about to be removed // pageAboutToChange(pageStackedWidget->currentWidget()); // // Notify that page is about to show // pageAboutToShow(pageWidget); // // Show the widget // pageStackedWidget->setCurrentWidget(pageWidget); // // Update help // if (helpBrowser != NULL) { helpBrowser->setHtml(pageHelpText[pageWidget]); } // // Set page and button validity // slotUpdatePageAndButtonValidity(); } /** * called when a page is about to show. user should override this */ void QtDialogWizard::pageAboutToShow(QWidget* /*pageWidget*/) { // // Let user override this // } /** * read from a page before going to next page. user should override this */ void QtDialogWizard::pageAboutToChange(QWidget* /*pageWidget*/) { // // Let user override this // } /** * set the next button enabled. user should call this from setValidPagesAndButtons() */ void QtDialogWizard::setNextButtonEnabled(const bool enableIt) { nextPushButton->setEnabled(enableIt); } /** * set the finish button enabled. user should call this from setValidPagesAndButtons() */ void QtDialogWizard::setFinishButtonEnabled(const bool enableIt, const QString& finishButtonText) { finishPushButton->setEnabled(enableIt); if (finishButtonText.isEmpty() == false) { finishPushButton->setText(finishButtonText); } } /** * called when next button pressed. */ void QtDialogWizard::slotNextPushButton() { // // index of next page // int indx = pageStackedWidget->currentIndex() + 1; // // Search for a valid page // while (indx < pageStackedWidget->count()) { // // If next page valid, switch to it // QWidget* nextPage = pageStackedWidget->widget(indx); if (nextPage != NULL) { if (pageValidityFlags[nextPage]) { showPage(nextPage); break; } } // // Try next page // indx++; } } /** * called when prev button pressed. */ void QtDialogWizard::slotPrevPushButton() { // // index of previous page // int indx = pageStackedWidget->currentIndex() - 1; // // Search for a valid page // while (indx >= 0) { // // If next page valid, switch to it // QWidget* prevPage = pageStackedWidget->widget(indx); if (prevPage != NULL) { if (pageValidityFlags[prevPage]) { showPage(prevPage); break; } } // // Try prev page // indx--; } } /** * called when close button pressed. */ void QtDialogWizard::slotClosePushButton() { QDialog::close(); } caret-5.6.4~dfsg.1.orig/caret_widgets/.project0000664000175000017500000000437211572067322021062 0ustar michaelmichael caret_widgets org.eclipse.cdt.managedbuilder.core.genmakebuilder clean,full,incremental, ?name? org.eclipse.cdt.make.core.append_environment true org.eclipse.cdt.make.core.autoBuildTarget all org.eclipse.cdt.make.core.buildArguments org.eclipse.cdt.make.core.buildCommand make org.eclipse.cdt.make.core.cleanBuildTarget clean org.eclipse.cdt.make.core.contents org.eclipse.cdt.make.core.activeConfigSettings org.eclipse.cdt.make.core.enableAutoBuild false org.eclipse.cdt.make.core.enableCleanBuild true org.eclipse.cdt.make.core.enableFullBuild true org.eclipse.cdt.make.core.fullBuildTarget all org.eclipse.cdt.make.core.stopOnError true org.eclipse.cdt.make.core.useDefaultBuildCmd true org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder org.eclipse.cdt.core.cnature org.eclipse.cdt.core.ccnature org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature caret-5.6.4~dfsg.1.orig/caret_widgets/.cproject0000664000175000017500000002073111572067322021222 0ustar michaelmichael make all true true true caret-5.6.4~dfsg.1.orig/caret_uniformize/0000775000175000017500000000000011572067322020126 5ustar michaelmichaelcaret-5.6.4~dfsg.1.orig/caret_uniformize/randgen.c0000664000175000017500000000457711572067322021725 0ustar michaelmichael/***************************************************************************** Major portions of this software are copyrighted by the Medical College of Wisconsin, 1994-2000, and are released under the Gnu General Public License, Version 2. See the file README.Copyright for details. ******************************************************************************/ /*---------------------------------------------------------------------------*/ /* Some utility routines for generating random numbers. File: randgen.c Author: B. Douglas Ward Date: 15 February 1999 Mod: Correction to rand_normal Date: 15 September 1999 Mod: Added routine rand_initialize. Date: 28 January 2000 */ #include #include "StatisticRandomNumber.h" const double PI = M_PI; /*---------------------------------------------------------------------------*/ /* Initialize the random number generator. */ void rand_initialize (long int seedval) { //CARET initialize seed, srand48 (seedval); StatisticRandomNumber::setRandomSeed(static_cast(seedval)); } /*---------------------------------------------------------------------------*/ /* Routine to generate a uniform U(a,b) random variate. */ float rand_uniform (float a, float b) { const float f = StatisticRandomNumber::randomFloat(a, b); return f; //CARET return (a + (float)drand48() * (b-a) ); } /*---------------------------------------------------------------------------*/ /* Routine to generate a normal N(mu,var) random variate. */ float rand_normal (float mu, float var) { float u1, u2; float r, n; u1 = 0.0; while (u1 <= 0.0) { u1 = rand_uniform (0.0, 1.0); } u2 = rand_uniform (0.0, 1.0); r = sqrt(-2.0*log(u1)); n = r * cos(2.0*PI*u2); return (mu + n * sqrt(var)); } /*---------------------------------------------------------------------------*/ /* Routine to generate two independent normal N(mu,var) random variates. */ void rand_binormal (float mu, float var, float * n1, float * n2) { float u1, u2; float r, sigma; u1 = 0.0; while (u1 <= 0.0) { u1 = rand_uniform (0.0, 1.0); } u2 = rand_uniform (0.0, 1.0); r = sqrt(-2.0*log(u1)); sigma = sqrt (var); *n1 = mu + r * cos(2.0*PI*u2) * sigma; *n2 = mu + r * sin(2.0*PI*u2) * sigma; } /*---------------------------------------------------------------------------*/ caret-5.6.4~dfsg.1.orig/caret_uniformize/pdf.h0000664000175000017500000001170111572067322021050 0ustar michaelmichael/***************************************************************************** Major portions of this software are copyrighted by the Medical College of Wisconsin, 1994-2000, and are released under the Gnu General Public License, Version 2. See the file README.Copyright for details. ******************************************************************************/ /*---------------------------------------------------------------------------*/ /* Header file of general purpose routines for input, manipulation, and output of probability density functions. File: pdf.h Author: B. Douglas Ward Date: 28 January 2000 */ /*---------------------------------------------------------------------------*/ /* Define pdf data structure. */ typedef struct pdf { int nbin; float * prob; float lower_bnd; float upper_bnd; float width; } pdf; /*---------------------------------------------------------------------------*/ /* Routine to print an error message and stop. */ void PDF_error (char * message); /*---------------------------------------------------------------------------*/ /* macro to test a malloc-ed pointer for validity */ #define PDF_MTEST(ptr) \ if((ptr)==NULL) \ ( PDF_error ("Cannot allocate memory") ) /*---------------------------------------------------------------------------*/ /* Initialize pdf data structure. */ void PDF_initialize (pdf * p); /*---------------------------------------------------------------------------*/ /* Destroy pdf data structure by deallocating memory. */ void PDF_destroy (pdf * p); /*---------------------------------------------------------------------------*/ /* Normalize pdf to have unity area. */ void PDF_normalize (pdf * p); /*---------------------------------------------------------------------------*/ /* Create pdf data structure by allocating memory and initializing values. */ void PDF_create (int nbin, float * prob, float lower_bnd, float upper_bnd, pdf * p); /*---------------------------------------------------------------------------*/ /* Copy pdf data structure from p to pc. */ void PDF_copy (pdf p, pdf * pc); /*---------------------------------------------------------------------------*/ /* Convert bin number to value of independent variable at center of the bin. */ float PDF_ibin_to_xvalue (pdf p, int ibin); /*---------------------------------------------------------------------------*/ /* Convert value of independent variable to bin number. */ int PDF_xvalue_to_ibin (pdf p, float xvalue); /*---------------------------------------------------------------------------*/ /* Convert value of independent variable to probability. */ float PDF_xvalue_to_pvalue (pdf p, float xvalue); /*---------------------------------------------------------------------------*/ /* Print contents of pdf p to screen. */ void PDF_print (pdf p); /*---------------------------------------------------------------------------*/ /* Print contents of string str and pdf p to screen. */ void PDF_sprint (char * str, pdf p); /*---------------------------------------------------------------------------*/ /* Write contents of pdf p to specified file. */ void PDF_write_file (char * filename, pdf p); /*---------------------------------------------------------------------------*/ /* Simple smoothing of the pdf estimate. */ void PDF_smooth (pdf * p); /*---------------------------------------------------------------------------*/ /* Trim the pdf by removing the extreme lower and extreme upper values. */ void PDF_trim (float lower_per, float upper_per, pdf * p); /*---------------------------------------------------------------------------*/ /* Determine the range of values in the input short array. */ void PDF_short_range (int npts, short * sarray, short * min_val, short * max_val); /*---------------------------------------------------------------------------*/ /* Determine the range of values in the input float array. */ void PDF_float_range (int npts, float * farray, float * min_val, float * max_val); /*---------------------------------------------------------------------------*/ /* Estimate the pdf corresponding to the input short array. */ void PDF_short_to_pdf (int npts, short * sarray, pdf * p); /*---------------------------------------------------------------------------*/ /* Estimate the pdf corresponding to the input float array. */ void PDF_float_to_pdf (int npts, float * farray, int num_bins, pdf * p); /*---------------------------------------------------------------------------*/ /* Find extrema of pdf function. */ void PDF_find_extrema (pdf p, int * num_min, int * pdf_min, int * num_max, int * pdf_max); /*---------------------------------------------------------------------------*/ /* Find bimodality of pdf function (if possible). */ int PDF_find_bimodal (pdf p, int * gmax, int * wmax); /*---------------------------------------------------------------------------*/ caret-5.6.4~dfsg.1.orig/caret_uniformize/pdf.c0000664000175000017500000003177311572067322021056 0ustar michaelmichael/***************************************************************************** Major portions of this software are copyrighted by the Medical College of Wisconsin, 1994-2000, and are released under the Gnu General Public License, Version 2. See the file README.Copyright for details. ******************************************************************************/ /*---------------------------------------------------------------------------*/ /* This file contains general purpose routines for input, manipulation, and output of probability density functions. File: pdf.c Author: B. Douglas Ward Date: 28 January 2000 */ #ifndef USE_QUIET # define quiet 0 #endif /*---------------------------------------------------------------------------*/ /* Routine to print an error message and stop. */ void PDF_error (char * message) { printf ("PDF error: %s \n", message); exit (1); } /*---------------------------------------------------------------------------*/ /* Initialize pdf data structure. */ void PDF_initialize (pdf * p) { p->nbin = 0; p->prob = NULL; p->lower_bnd = 0.0; p->upper_bnd = 0.0; p->width = 0.0; return; } /*---------------------------------------------------------------------------*/ /* Destroy pdf data structure by deallocating memory. */ void PDF_destroy (pdf * p) { if (p->prob != NULL) free (p->prob); PDF_initialize (p); return; } /*---------------------------------------------------------------------------*/ /* Normalize pdf to have unity area. */ void PDF_normalize (pdf * p) { int ibin; double sum; sum = 0.0; for (ibin = 0; ibin < p->nbin; ibin++) sum += p->prob[ibin]; for (ibin = 0; ibin < p->nbin; ibin++) p->prob[ibin] /= sum; return; } /*---------------------------------------------------------------------------*/ /* Create pdf data structure by allocating memory and initializing values. */ void PDF_create (int nbin, float * prob, float lower_bnd, float upper_bnd, pdf * p) { int ibin; PDF_destroy (p); p->nbin = nbin; p->prob = (float *) malloc (sizeof(float) * nbin); PDF_MTEST (p->prob); for (ibin = 0; ibin < nbin; ibin++) p->prob[ibin] = prob[ibin]; p->lower_bnd = lower_bnd; p->upper_bnd = upper_bnd; p->width = (upper_bnd - lower_bnd) / (nbin-1); PDF_normalize (p); return; } /*---------------------------------------------------------------------------*/ /* Copy pdf data structure from p to pc. */ void PDF_copy (pdf p, pdf * pc) { PDF_create (p.nbin, p.prob, p.lower_bnd, p.upper_bnd, pc); return; } /*---------------------------------------------------------------------------*/ /* Convert bin number to value of independent variable at center of the bin. */ float PDF_ibin_to_xvalue (pdf p, int ibin) { float xvalue; xvalue = p.lower_bnd + ibin*p.width; return (xvalue); } /*---------------------------------------------------------------------------*/ /* Convert value of independent variable to bin number. */ int PDF_xvalue_to_ibin (pdf p, float xvalue) { int ibin; ibin = (int)floor ( (xvalue - p.lower_bnd) / p.width + 0.5); return (ibin); } /*---------------------------------------------------------------------------*/ /* Convert value of independent variable to probability. */ float PDF_xvalue_to_pvalue (pdf p, float xvalue) { int ibin; float pvalue; ibin = PDF_xvalue_to_ibin (p, xvalue); if ((ibin < 0) || (ibin >= p.nbin)) pvalue = 0.0; else pvalue = p.prob[ibin]; return (pvalue); } /*---------------------------------------------------------------------------*/ /* Print contents of pdf p to screen. */ void PDF_print (pdf p) { /*int ibin;*/ if( !quiet ){ printf ("Number of bins = %d \n", p.nbin); printf ("Lower bound = %f \n", p.lower_bnd); printf ("Upper bound = %f \n", p.upper_bnd); printf ("Bin width = %f \n", p.width); /* printf ("%3s %10.6s %10.6s \n", "i", "x[i]", "p[i]"); for (ibin = 0; ibin < p.nbin; ibin++) printf ("%3d %10.6f %10.6f \n", ibin, PDF_ibin_to_xvalue(p, ibin), p.prob[ibin]); */ } return; } /*---------------------------------------------------------------------------*/ /* Print contents of string str and pdf p to screen. */ void PDF_sprint (char * str, pdf p) { if( quiet ) return ; printf ("%s \n", str); PDF_print (p); return; } /*---------------------------------------------------------------------------*/ /* Write contents of pdf p to specified file. */ void PDF_write_file (char * filename, pdf p) { int ibin; FILE * outfile = NULL; outfile = fopen (filename, "w"); if (!outfile) { fprintf (stderr, "\n" "*****************************\n" "Error:\n" "Failed to open %s for output.\n" "Check for write permissions.\n" "*****************************\n" "\n", filename); return; } for (ibin = 0; ibin < p.nbin; ibin++) fprintf (outfile, "%d %f %f \n", ibin, PDF_ibin_to_xvalue(p, ibin), p.prob[ibin]); fclose (outfile); return; } /*---------------------------------------------------------------------------*/ /* Simple smoothing of the pdf estimate. */ void PDF_smooth (pdf * p) { float * sprob; int ibin; sprob = (float *) malloc (sizeof(float) * p->nbin); sprob[0] = 0.5*(p->prob[0] + p->prob[1]); sprob[p->nbin-1] = 0.5*(p->prob[p->nbin-2] + p->prob[p->nbin-1]); for (ibin = 1; ibin < p->nbin-1; ibin++) sprob[ibin] = 0.25 * (p->prob[ibin-1] + 2*p->prob[ibin] + p->prob[ibin+1]); free (p->prob); p->prob = sprob; PDF_normalize (p); return; } /*---------------------------------------------------------------------------*/ /* Trim the pdf by removing the extreme lower and extreme upper values. */ void PDF_trim (float lower_per, float upper_per, pdf * p) { int ibin; float * fbin = NULL; float cum_prob; float lower_bnd, upper_bnd; int lo_bin = 0, hi_bin = 0; /*----- Trim lower values -----*/ cum_prob = 0.0; for (ibin = 0; ibin < p->nbin; ibin++) { cum_prob += p->prob[ibin]; p->prob[ibin] = 0.0; if (cum_prob > lower_per) { lo_bin = ibin + 1; break; } } /*----- Trim upper values -----*/ cum_prob = 0.0; for (ibin = p->nbin-1; ibin >= 0; ibin--) { cum_prob += p->prob[ibin]; p->prob[ibin] = 0.0; if (cum_prob > 1.0 - upper_per) { hi_bin = ibin - 1; break; } } /*----- Reset lower and upper bounds -----*/ lower_bnd = PDF_ibin_to_xvalue (*p, lo_bin); upper_bnd = PDF_ibin_to_xvalue (*p, hi_bin); p->lower_bnd = lower_bnd; p->upper_bnd = upper_bnd; p->nbin = hi_bin - lo_bin + 1; /*----- Copy data -----*/ fbin = (float *) malloc (sizeof(float) * p->nbin); for (ibin = 0; ibin < p->nbin; ibin++) fbin[ibin] = p->prob[ibin+lo_bin]; /*----- Reset pointer to data -----*/ free (p->prob); p->prob = fbin; /*----- Normalize to unity area -----*/ PDF_normalize (p); return; } /*---------------------------------------------------------------------------*/ /* Determine the range of values in the input short array. */ void PDF_short_range (int npts, short * sarray, short * min_val, short * max_val) { int ipt; *min_val = sarray[0]; *max_val = sarray[0]; for (ipt = 1; ipt < npts; ipt++) { if (sarray[ipt] < *min_val) *min_val = sarray[ipt]; if (sarray[ipt] > *max_val) *max_val = sarray[ipt]; } return; } /*---------------------------------------------------------------------------*/ /* Determine the range of values in the input float array. */ void PDF_float_range (int npts, float * farray, float * min_val, float * max_val) { int ipt; *min_val = farray[0]; *max_val = farray[0]; for (ipt = 1; ipt < npts; ipt++) { if (farray[ipt] < *min_val) *min_val = farray[ipt]; if (farray[ipt] > *max_val) *max_val = farray[ipt]; } return; } /*---------------------------------------------------------------------------*/ /* Estimate the pdf corresponding to the input short array. */ void PDF_short_to_pdf (int npts, short * sarray, pdf * p) { const int MIN_COUNT = 5; const int MIN_BINS = 5; int ipt, ibin, count; float * fbin = NULL; int num_bins; short lower_lim, upper_lim; char message[80]; /*----- Make histogram of input short array -----*/ PDF_short_range (npts, sarray, &lower_lim, &upper_lim); num_bins = upper_lim - lower_lim + 1; if (num_bins < MIN_BINS) { sprintf (message, "histogram contains only %d bins", num_bins); PDF_error (message); } fbin = (float *) malloc (sizeof(float) * num_bins); PDF_MTEST (fbin); for (ibin = 0; ibin < num_bins; ibin++) fbin[ibin] = 0.0; count = 0; for (ipt = 0; ipt < npts; ipt++) { ibin = sarray[ipt] - lower_lim; if ((ibin >= 0) && (ibin < num_bins)) { fbin[ibin] += 1.0; count++; } } /*----- Check for too few points -----*/ if (count < MIN_COUNT) { sprintf (message, "histogram contains only %d points", count); PDF_error (message); } /*----- Create PDF -----*/ PDF_create (num_bins, fbin, (float) lower_lim, (float) upper_lim, p); /*----- Release memory -----*/ free (fbin); fbin = NULL; return; } /*---------------------------------------------------------------------------*/ /* Estimate the pdf corresponding to the input float array. */ void PDF_float_to_pdf (int npts, float * farray, int num_bins, pdf * p) { const int MIN_COUNT = 5; const int MIN_BINS = 5; int ipt, ibin, count; float * fbin = NULL; float width; float min_val, max_val; char message[80]; /*----- Make histogram of input float array -----*/ if (num_bins < MIN_BINS) { sprintf (message, "histogram contains only %d bins", num_bins); PDF_error (message); } fbin = (float *) malloc (sizeof(float) * num_bins); PDF_MTEST (fbin); for (ibin = 0; ibin < num_bins; ibin++) fbin[ibin] = 0.0; PDF_float_range (npts, farray, &min_val, &max_val); width = (max_val - min_val) / num_bins; count = 0; for (ipt = 0; ipt < npts; ipt++) { ibin = (int) ((farray[ipt] - min_val) / width); if ((ibin >= 0) && (ibin < num_bins)) { fbin[ibin] += 1.0; count++; } } /*----- Check for too few points -----*/ if (count < MIN_COUNT) { sprintf (message, "histogram contains only %d points", count); PDF_error (message); } /*----- Create PDF -----*/ PDF_create (num_bins, fbin, min_val, max_val, p); /*----- Release memory -----*/ free (fbin); fbin = NULL; return; } /*---------------------------------------------------------------------------*/ /* Find extrema of pdf function. */ void PDF_find_extrema (pdf p, int * num_min, int * pdf_min, int * num_max, int * pdf_max) { int ibin; int i; *num_min = 0; *num_max = 0; for (ibin = 1; ibin < p.nbin-1; ibin++) { if ((p.prob[ibin] < p.prob[ibin-1]) && (p.prob[ibin] < p.prob[ibin+1])) { pdf_min[*num_min] = ibin; (*num_min)++; } if ((p.prob[ibin] > p.prob[ibin-1]) && (p.prob[ibin] > p.prob[ibin+1])) { pdf_max[*num_max] = ibin; (*num_max)++; } } if( !quiet ){ printf ("\nExtrema of PDF: \n"); printf ("\nNum Local Min = %d \n", *num_min); for (i = 0; i < *num_min; i++) { ibin = pdf_min[i]; printf ("x[%3d] = %8.3f p[%3d] = %12.6f \n", ibin, PDF_ibin_to_xvalue(p, ibin), ibin, p.prob[ibin]); } printf ("\nNum Local Max = %d \n", *num_max); for (i = 0; i < *num_max; i++) { ibin = pdf_max[i]; printf ("x[%3d] = %8.3f p[%3d] = %12.6f \n", ibin, PDF_ibin_to_xvalue(p, ibin), ibin, p.prob[ibin]); } } } /*---------------------------------------------------------------------------*/ /* Find bimodality of pdf function (if possible). */ int PDF_find_bimodal (pdf p, int * gmax, int * wmax) { //const int NPTS = 12; int * pdf_min = NULL, * pdf_max = NULL; int num_min, num_max; int imax, temp; pdf_min = (int *) malloc (sizeof(int) * p.nbin); pdf_max = (int *) malloc (sizeof(int) * p.nbin); PDF_find_extrema (p, &num_min, pdf_min, &num_max, pdf_max); if (num_max >= 2) { if (p.prob[pdf_max[1]] >= p.prob[pdf_max[0]]) { *wmax = pdf_max[1]; *gmax = pdf_max[0]; } else { *wmax = pdf_max[0]; *gmax = pdf_max[1]; } if (num_max > 2) { for (imax = 2; imax < num_max; imax++) { if (p.prob[pdf_max[imax]] >= p.prob[*wmax]) { *gmax = *wmax; *wmax = pdf_max[imax]; } else if (p.prob[pdf_max[imax]] >= p.prob[*gmax]) { *gmax = pdf_max[imax]; } } } if (*gmax > *wmax) { temp = *gmax; *gmax = *wmax; *wmax = temp; } } /* end if (num_max >= 2) */ free (pdf_min); pdf_min = NULL; free (pdf_max); pdf_max = NULL; if (num_max < 2) return (0); else return (1); } /*---------------------------------------------------------------------------*/ caret-5.6.4~dfsg.1.orig/caret_uniformize/matrix.h0000664000175000017500000002175111572067322021611 0ustar michaelmichael#ifndef MATRIX_INCLUDED #define MATRIX_INCLUDED /***************************************************************************** Major portions of this software are copyrighted by the Medical College of Wisconsin, 1994-2000, and are released under the Gnu General Public License, Version 2. See the file README.Copyright for details. ******************************************************************************/ /* This is the header file for matrix.c. File: matrix.h Author: B. Douglas Ward Date: 23 April 1997 Mod: Added routines matrix_file_write and matrix_file_read. Date: 02 July 1999 Mod: Added routine for calculating square root of matrix. Date: 30 September 1999 Mod: Added routines matrix_sprint and vector_sprint. Date: 04 October 1999 Mod: Modified matrix_file_read to use mri_read_ascii routine. Date: 12 January 2000 Mod: Changed return type of vector_dot from float to double. Date: 13 April 2000 Mod: Added functions column_to_vector and matrix_extract_rows. Date: 21 April 2000 Mod: Added functions vector_dotself() and vector_multiply_subtract() -- RWCox. Date: 28 Dec 2002 Mod: Use one array instead of array of arrays for matrix -- RWCox. Date: 04 Mar 2005 */ /*---------------------------------------------------------------------------*/ /* Define matrix and vector data structures. */ typedef struct matrix { int rows; int cols; double ** elts; #ifndef DONT_USE_MATRIX_MAT double * mat ; /* 04 Mar 2005 */ #endif } matrix; typedef struct vector { int dim; double * elts; } vector; /*---------------------------------------------------------------------------*/ /* Routine to print an error message and stop. */ void matrix_error (char * message); /*---------------------------------------------------------------------------*/ /* Initialize matrix data structure. */ void matrix_initialize (matrix * m); /*---------------------------------------------------------------------------*/ /* Destroy matrix data structure by deallocating memory. */ void matrix_destroy (matrix * m); /*---------------------------------------------------------------------------*/ /* Create matrix data structure by allocating memory and initializing values. */ void matrix_create (int rows, int cols, matrix * m); /*---------------------------------------------------------------------------*/ /* Print contents of matrix m. */ void matrix_print (matrix m); /*---------------------------------------------------------------------------*/ /* Print label and contents of matrix m. */ void matrix_sprint (char * s, matrix m); /*---------------------------------------------------------------------------*/ /* Print contents of matrix m to specified file. */ void matrix_file_write (char * filename, matrix m); /*---------------------------------------------------------------------------*/ /* Manual entry of matrix data. */ void matrix_enter (matrix * m); /*---------------------------------------------------------------------------*/ /* Read contents of matrix m from specified file. If unable to read matrix from file, or matrix has wrong dimensions: If error_exit flag is set, then print error message and exit. Otherwise, return null matrix. */ void matrix_file_read (char * filename, int rows, int cols, matrix * m, int error_exit); /*---------------------------------------------------------------------------*/ /* Convert simple array to matrix structure. */ void array_to_matrix (int rows, int cols, float ** f, matrix * m); /*---------------------------------------------------------------------------*/ /* Make a copy of the first matrix, return copy as the second matrix. */ void matrix_equate (matrix a, matrix * b); /*---------------------------------------------------------------------------*/ /* Extract p columns (specified by list) from matrix a. Result is matrix b. */ void matrix_extract (matrix a, int p, int * list, matrix * b); /*---------------------------------------------------------------------------*/ /* Extract p rows (specified by list) from matrix a. Result is matrix b. */ void matrix_extract_rows (matrix a, int p, int * list, matrix * b); /*---------------------------------------------------------------------------*/ /* Create n x n identity matrix. */ void matrix_identity (int n, matrix * m); /*---------------------------------------------------------------------------*/ /* Add matrix a to matrix b. Result is matrix c. */ void matrix_add (matrix a, matrix b, matrix * c); /*---------------------------------------------------------------------------*/ /* Subtract matrix b from matrix a. Result is matrix c. */ void matrix_subtract (matrix a, matrix b, matrix * c); /*---------------------------------------------------------------------------*/ /* Multiply matrix a by matrix b. Result is matrix c. */ void matrix_multiply (matrix a, matrix b, matrix * c); /*---------------------------------------------------------------------------*/ /* Multiply matrix a by scalar constant k. Result is matrix c. */ void matrix_scale (double k, matrix a, matrix * c); /*---------------------------------------------------------------------------*/ /* Take transpose of matrix a. Result is matrix t. */ void matrix_transpose (matrix a, matrix * t); /*---------------------------------------------------------------------------*/ /* Use Gaussian elimination to calculate inverse of matrix a. Result is matrix ainv. */ int matrix_inverse (matrix a, matrix * ainv); int matrix_inverse_dsc (matrix a, matrix * ainv); /* 15 Jul 2004 */ /*---------------------------------------------------------------------------*/ /* Calculate square root of symmetric positive definite matrix a. Result is matrix s. */ int matrix_sqrt (matrix a, matrix * s); /*---------------------------------------------------------------------------*/ /* Initialize vector data structure. */ void vector_initialize (vector * v); /*---------------------------------------------------------------------------*/ /* Destroy vector data structure by deallocating memory. */ void vector_destroy (vector * v); /*---------------------------------------------------------------------------*/ /* Create vector v by allocating memory and initializing values. */ void vector_create (int dim, vector * v); /*---------------------------------------------------------------------------*/ /* Print contents of vector v. */ void vector_print (vector v); /*---------------------------------------------------------------------------*/ /* Print label and contents of vector v. */ void vector_sprint (char * s, vector v); /*---------------------------------------------------------------------------*/ /* Copy vector a. Result is vector b. */ void vector_equate (vector a, vector * b); /*---------------------------------------------------------------------------*/ /* Convert simple array f into vector v. */ void array_to_vector (int dim, float * f, vector * v); /*---------------------------------------------------------------------------*/ /* Convert column c of matrix m into vector v. */ void column_to_vector (matrix m, int c, vector * v); /*---------------------------------------------------------------------------*/ /* Convert vector v into array f. */ void vector_to_array (vector v, float * f); /*---------------------------------------------------------------------------*/ /* Add vector a to vector b. Result is vector c. */ void vector_add (vector a, vector b, vector * c); /*---------------------------------------------------------------------------*/ /* Subtract vector b from vector a. Result is vector c. */ void vector_subtract (vector a, vector b, vector * c); /*---------------------------------------------------------------------------*/ /* Right multiply matrix a by vector b. Result is vector c. */ void vector_multiply (matrix a, vector b, vector * c); /*---------------------------------------------------------------------------*/ /* Right multiply matrix a by vector b, then subtract c. Result is vector d. Also returns sum of squares of elements of d. */ double vector_multiply_subtract (matrix a, vector b, vector c, vector * d) ; /*---------------------------------------------------------------------------*/ /* Calculate dot product of vector a with vector b. */ double vector_dot (vector a, vector b); double vector_dotself (vector a); /* 28 Dec 2002: RWCox */ /*---------------------------------------------------------------------------*/ double matrix_norm( matrix a ) ; /* 03 Mar 2003: RWCox */ int * matrix_check_columns( matrix a , double eps ) ; /* 14 Jul 2004: RWCox */ double * matrix_singvals( matrix X ) ; /* 14 Jul 2004 */ void matrix_psinv( matrix X , matrix *XtXinv , matrix *XtXinvXt ) ; /* 19 Jul 2004 */ extern void matrix_psinv_seteps( double eps ) ; /* 02 Mar 2007 - MoJM */ double get_matrix_flops(void) ; double get_matrix_dotlen(void) ; #endif caret-5.6.4~dfsg.1.orig/caret_uniformize/matrix.cxx0000664000175000017500000010115411572067322022160 0ustar michaelmichael/***************************************************************************** Major portions of this software are copyrighted by the Medical College of Wisconsin, 1994-2000, and are released under the Gnu General Public License, Version 2. See the file README.Copyright for details. ******************************************************************************/ /*! This file contains matrix and vector arithmetic routines. File: matrix.c Author: B. Douglas Ward Date: 23 April 1997 Mod: Changed print format for functions matrix_print and vector_print. Date: 05 August 1997 Mod: Changed initialization in function vector_create. Date: 04 November 1997 Mod: Added routines matrix_file_write and matrix_file_read. Date: 02 July 1999 Mod: Added routine for calculating square root of matrix. Date: 30 September 1999 Mod: Added routines matrix_sprint and vector_sprint. Date: 04 October 1999 Mod: Modified matrix_file_read to use mri_read_ascii routine. Date: 12 January 2000 Mod: Changed return type of vector_dot from float to double. Date: 13 April 2000 Mod: Added functions column_to_vector and matrix_extract_rows. Date: 21 April 2000 Mod: Added test for missing matrix file name. Date: 08 May 2000 Mod: Added "register" declarations and a few other things to speed up calculations (including vector_create_noinit) -- RWCox. Date: 28 Dec 2001 Mod: Allow matrices and vectors with zero rows and columns. Date: 26 February 2002 Mod: Corrected errors in vector_multiply and vector_multiply_subtract routines that would produce segmentation fault for certain input matrices. Date: 18 March 2003 Mod: UNROLL_VECMUL defined to allow unrolling by 2 of vector-multiply dot product loops. Mod: 'ipr' added to matrix_print() function. Date: 03 Aug 2004 - RWCox Mod: Added USE_SCSLBLAS stuff for SGI Altix, and USE_SUNPERF for Solaris. Date: 01 Mar 2005 */ /*---------------------------------------------------------------------*/ /** Vectorization macros: - DOTP(n,x,y,z) computes the n-long dot product of vectors x and y and puts the result into the place pointed to by z. - VSUB(n,x,y,z) computes vector x-y into vector z. - These are intended to be the fast method for doing these things. **/ /*---------------------------------------------------------------------*/ #include #include // CARET #include // CARET #include // CARET #include "matrix.h" // CARET #undef SETUP_BLAS1 /* define this to use BLAS-1 functions */ #undef SETUP_BLAS2 /* define this to use BLAS-2 functions */ #undef DOTP #undef VSUB #undef MATVEC #undef SUBMATVEC #if defined(USE_SCSLBLAS) /** SGI Altix **/ # include # define SETUP_BLAS1 # undef SETUP_BLAS2 /* don't use this */ # define TRANSA "T" #elif defined(USE_SUNPERF) /** Sun Solaris **/ # include # define SETUP_BLAS1 # undef SETUP_BLAS2 # define TRANSA 'T' #elif defined(USE_ACML) # ifndef _ACML_COMPLEX # define _ACML_COMPLEX /* typedef struct { float real, imag; } complex; */ /* typedef struct { double real, imag; } doublecomplex; */ # endif # include # define SETUP_BLAS1 #endif /* double precision BLAS-1 functions */ #ifdef SETUP_BLAS1 # define DOTP(n,x,y,z) *(z)=ddot(n,x,1,y,1) # define VSUB(n,x,y,z) (memcpy(z,x,sizeof(double)*n),daxpy(n,-1.0,y,1,z,1)) #endif /*....................................................................... BLAS-2 function operate on matrix-vector structs defined in matrix.h: MATVEC(m,v,z): [z] = [m][v] where m=matrix, z,v = matrices SUBMATVEC(m,v,z): [z] = [z] - [m][v] .........................................................................*/ #ifdef DONT_USE_MATRIX_MAT # undef SETUP_BLAS2 #endif #ifdef SETUP_BLAS2 /* doesn't seem to help much */ # define MATVEC(m,v,z) dgemv( TRANSA , (m).cols , (m).rows , \ 1.0 , (m).mat , (m).cols , \ (v).elts , 1 , 0.0 , (z).elts , 1 ) # define SUBMATVEC(m,v,z) dgemv( TRANSA , (m).cols , (m).rows , \ -1.0 , (m).mat , (m).cols , \ (v).elts , 1 , 1.0 , (z).elts , 1 ) #endif /*---------------------------------------------------------------------------*/ static double flops=0.0 ; double get_matrix_flops(void){ return flops; } static double dotnum=0.0 , dotsum=0.0 ; double get_matrix_dotlen(void){ return (dotnum > 0.0) ? dotsum/dotnum : 0.0 ; } #define ENABLE_FLOPS /*---------------------------------------------------------------------------*/ /*! Routine to print and error message and stop. */ void matrix_error (char * message) { printf ("Matrix error: %s \n", message); exit (1); } /*---------------------------------------------------------------------------*/ /*! Initialize matrix data structure. */ void matrix_initialize (matrix * m) { m->rows = 0; m->cols = 0; m->elts = NULL; #ifndef DONT_USE_MATRIX_MAT m->mat = NULL ; /* 04 Mar 2005 */ #endif } /*---------------------------------------------------------------------------*/ /*! Destroy matrix data structure by deallocating memory. */ void matrix_destroy (matrix * m) { if (m->elts != NULL){ #ifdef DONT_USE_MATRIX_MAT int i ; for( i=0 ; i < m->rows ; i++ ) if( m->elts[i] != NULL ) free(m->elts[i]) ; #endif free(m->elts) ; } #ifndef DONT_USE_MATRIX_MAT if( m->mat != NULL) free (m->mat ) ; #endif matrix_initialize (m); } /*---------------------------------------------------------------------------*/ /*! Create matrix data structure by allocating memory and initializing values. */ void matrix_create (int rows, int cols, matrix * m) { register int i ; matrix_destroy (m); if ((rows < 0) || (cols < 0)) matrix_error ("Illegal dimensions for new matrix"); m->rows = rows; m->cols = cols; if ((rows < 1) || (cols < 1)) return; m->elts = (double **) malloc (sizeof(double *) * rows); if (m->elts == NULL) matrix_error ("Memory allocation error"); #ifdef DONT_USE_MATRIX_MAT for (i = 0; i < rows; i++){ m->elts[i] = (double *) calloc (sizeof(double) , cols); if (m->elts[i] == NULL) matrix_error ("Memory allocation error"); } #else m->mat = (double *) calloc( sizeof(double) , rows*cols ) ; if( m->mat == NULL ) matrix_error ("Memory allocation error"); for (i = 0; i < rows; i++) m->elts[i] = m->mat + (i*cols) ; /* 04 Mar 2005: offsets into mat */ #endif } /*---------------------------------------------------------------------------*/ /*! Print contents of matrix m. */ void matrix_print (matrix m) { int i=0, j=0; int rows, cols; double val ; int ipr ; rows = m.rows; cols = m.cols; for( i=0 ; i < rows ; i++ ){ for( j=0 ; j < cols ; j++ ){ val = (int)m.elts[i][j] ; if( val != m.elts[i][j] || fabs(val) > 9.0 ) goto zork ; } } zork: ipr = (i==rows && j==cols) ; for (i = 0; i < rows; i++) { for (j = 0; j < cols; j++) if( ipr ) printf (" %2d" , (int)m.elts[i][j]); else printf (" %10.4g", m.elts[i][j]); printf (" \n"); } printf (" \n"); fflush(stdout) ; } /*---------------------------------------------------------------------------*/ /*! Print label and contents of matrix m. */ void matrix_sprint (char * s, matrix m) { printf ("%s \n", s); matrix_print (m); } /*---------------------------------------------------------------------------*/ /*! Print contents of matrix m to specified file. */ void matrix_file_write (char * filename, matrix m) { int i, j; int rows, cols; FILE * outfile = NULL; /*----- First, check for empty file name -----*/ if (filename == NULL) matrix_error ("Missing matrix file name"); outfile = fopen (filename, "w"); rows = m.rows; cols = m.cols; for (i = 0; i < rows; i++) { for (j = 0; j < cols; j++) fprintf (outfile, " %g", m.elts[i][j]); fprintf (outfile, " \n"); } fprintf (outfile, " \n"); fclose (outfile); } /*---------------------------------------------------------------------------*/ /*! Manual entry of matrix data. */ void matrix_enter (matrix * m) { int rows, cols; int i, j; float fval; printf ("Enter number of rows: "); fflush(stdout) ; scanf ("%d", &rows); printf ("Enter number of cols: "); fflush(stdout) ; scanf ("%d", &cols); matrix_create (rows, cols, m); for (i = 0; i < rows; i++) for (j = 0; j < cols; j++) { printf ("elts[%d][%d] = ", i, j); fflush(stdout); scanf ("%f", &fval); m->elts[i][j] = fval; } } /*---------------------------------------------------------------------------*/ /*! Read contents of matrix m from specified file. If unable to read matrix from file, or matrix has wrong dimensions: If error_exit flag is set, then print error message and exit. Otherwise, return null matrix. */ // matrix_file_read REMOVED CARET /*---------------------------------------------------------------------------*/ /*! Convert simple array to matrix structure. */ void array_to_matrix (int rows, int cols, float ** f, matrix * m) { register int i, j; matrix_create (rows, cols, m); for (i = 0; i < rows; i++) for (j = 0; j < cols; j++) m->elts[i][j] = f[i][j]; } /*---------------------------------------------------------------------------*/ /*! Make a copy of the first matrix, return copy as the second matrix. */ void matrix_equate (matrix a, matrix * b) { register int i; //, j; register int rows, cols; rows = a.rows; cols = a.cols; matrix_create (rows, cols, b); for (i = 0; i < rows; i++){ #if 0 for (j = 0; j < cols; j++) b->elts[i][j] = a.elts[i][j]; #else if( cols > 0 ) memcpy( b->elts[i] , a.elts[i] , sizeof(double)*cols ) ; /* RWCox */ #endif } } /*---------------------------------------------------------------------------*/ /*! Extract p columns (specified by list) from matrix a. Result is matrix b. */ void matrix_extract (matrix a, int p, int *list, matrix * b) { register int i, j; register int rows, cols; rows = a.rows; cols = p; matrix_create (rows, cols, b); for (i = 0; i < rows; i++) for (j = 0; j < cols; j++) b->elts[i][j] = a.elts[i][list[j]]; } /*---------------------------------------------------------------------------*/ /*! Extract p rows (specified by list) from matrix a. Result is matrix b. */ void matrix_extract_rows (matrix a, int p, int * list, matrix * b) { register int i, j; register int rows, cols; rows = p; cols = a.cols; matrix_create (rows, cols, b); for (i = 0; i < rows; i++) for (j = 0; j < cols; j++) b->elts[i][j] = a.elts[list[i]][j]; } /*---------------------------------------------------------------------------*/ /*! Create n x n identity matrix. */ void matrix_identity (int n, matrix * m) { register int i, j; if (n < 0) matrix_error ("Illegal dimensions for identity matrix"); matrix_create (n, n, m); for (i = 0; i < n; i++) for (j = 0; j < n; j++) if (i == j) m->elts[i][j] = 1.0; else m->elts[i][j] = 0.0; } /*---------------------------------------------------------------------------*/ /*! Add matrix a to matrix b. Result is matrix c. */ void matrix_add (matrix a, matrix b, matrix * c) { register int rows, cols; register int i, j; if ((a.rows != b.rows) || (a.cols != b.cols)) matrix_error ("Incompatible dimensions for matrix addition"); rows = a.rows; cols = a.cols; matrix_create (rows, cols, c); for (i = 0; i < rows; i++) for (j = 0; j < cols; j++) c->elts[i][j] = a.elts[i][j] + b.elts[i][j]; #ifdef ENABLE_FLOPS flops += rows*cols ; #endif } /*---------------------------------------------------------------------------*/ /*! Subtract matrix b from matrix a. Result is matrix c. */ void matrix_subtract (matrix a, matrix b, matrix * c) { register int rows, cols; register int i, j; if ((a.rows != b.rows) || (a.cols != b.cols)) matrix_error ("Incompatible dimensions for matrix subtraction"); rows = a.rows; cols = a.cols; matrix_create (rows, cols, c); for (i = 0; i < rows; i++) for (j = 0; j < cols; j++) c->elts[i][j] = a.elts[i][j] - b.elts[i][j]; #ifdef ENABLE_FLOPS flops += rows*cols ; #endif } /*---------------------------------------------------------------------------*/ /*! Multiply matrix a by matrix b. Result is matrix c. */ void matrix_multiply (matrix a, matrix b, matrix * c) { int rows, cols; register int i, j, k; register double sum ; if (a.cols != b.rows) matrix_error ("Incompatible dimensions for matrix multiplication"); rows = a.rows; cols = b.cols; matrix_create (rows, cols, c); for (i = 0; i < rows; i++) for (j = 0; j < cols; j++) { sum = 0.0 ; for (k = 0; k < a.cols; k++) sum += a.elts[i][k] * b.elts[k][j]; c->elts[i][j] = sum; } #ifdef ENABLE_FLOPS flops += 2.0*rows*cols*cols ; #endif } /*---------------------------------------------------------------------------*/ /*! Multiply matrix a by scalar constant k. Result is matrix c. */ void matrix_scale (double k, matrix a, matrix * c) { register int rows, cols; register int i, j; rows = a.rows; cols = a.cols; matrix_create (rows, cols, c); for (i = 0; i < rows; i++) for (j = 0; j < cols; j++) c->elts[i][j] = k * a.elts[i][j]; #ifdef ENABLE_FLOPS flops += rows*cols ; #endif } /*---------------------------------------------------------------------------*/ /*! Take transpose of matrix a. Result is matrix t. */ void matrix_transpose (matrix a, matrix * t) { register int rows, cols; register int i, j; rows = a.cols; cols = a.rows; matrix_create (rows, cols, t); for (i = 0; i < rows; i++) for (j = 0; j < cols; j++) t->elts[i][j] = a.elts[j][i]; } /*---------------------------------------------------------------------------*/ /*! Use Gaussian elimination to calculate inverse of matrix a. Result is matrix ainv. */ int matrix_inverse (matrix a, matrix * ainv) { const double epsilon = 1.0e-10; matrix tmp; register int i, j, ii, n; register double fval; register double fmax; register double * p; matrix_initialize (&tmp); if (a.rows != a.cols) matrix_error ("Illegal dimensions for matrix inversion"); #if 0 matrix_sprint("matrix_inverse:",a) ; #endif n = a.rows; matrix_identity (n, ainv); matrix_equate (a, &tmp); for (i = 0; i < n; i++) { fmax = fabs(tmp.elts[i][i]); for (j = i+1; j < n; j++) if (fabs(tmp.elts[j][i]) > fmax) { fmax = fabs(tmp.elts[j][i]); p = tmp.elts[i]; tmp.elts[i] = tmp.elts[j]; tmp.elts[j] = p; p = ainv->elts[i]; ainv->elts[i] = ainv->elts[j]; ainv->elts[j] = p; } if (fmax < epsilon) { matrix_destroy (&tmp); return (0); } fval = 1.0 / tmp.elts[i][i]; /* RWCox: change division by this to */ for (j = 0; j < n; j++) /* multiplication by 1.0/this */ { tmp.elts[i][j] *= fval; ainv->elts[i][j] *= fval; } for (ii = 0; ii < n; ii++) if (ii != i) { fval = tmp.elts[ii][i]; for (j = 0; j < n; j++) { tmp.elts[ii][j] -= fval*tmp.elts[i][j]; ainv->elts[ii][j] -= fval*ainv->elts[i][j]; } } } matrix_destroy (&tmp); #ifdef ENABLE_FLOPS flops += 3.0*n*n*n ; #endif return (1); } /*---------------------------------------------------------------------------*/ /*! Use Gaussian elimination to calculate inverse of matrix a, with diagonal scaling applied for stability. Result is matrix ainv. */ int matrix_inverse_dsc (matrix a, matrix * ainv) /* 15 Jul 2004 - RWCox */ { matrix atmp; register int i, j, n; register double *diag ; int mir ; if (a.rows != a.cols) matrix_error ("Illegal dimensions for matrix inversion"); matrix_initialize (&atmp); n = a.rows; matrix_equate (a, &atmp); diag = (double *)malloc( sizeof(double)*n ) ; for( i=0 ; i < n ; i++ ){ diag[i] = fabs(atmp.elts[i][i]) ; if( diag[i] == 0.0 ) diag[i] = 1.0 ; /* shouldn't happen? */ diag[i] = 1.0 / sqrt(diag[i]) ; } for( i=0 ; i < n ; i++ ) /* scale a */ for( j=0 ; j < n ; j++ ) atmp.elts[i][j] *= diag[i]*diag[j] ; mir = matrix_inverse( atmp , ainv ) ; /* invert */ for( i=0 ; i < n ; i++ ) /* scale inverse */ for( j=0 ; j < n ; j++ ) ainv->elts[i][j] *= diag[i]*diag[j] ; matrix_destroy (&atmp); free((void *)diag) ; #ifdef ENABLE_FLOPS flops += 4.0*n*n + 4.0*n ; #endif return (mir); } /*---------------------------------------------------------------------------*/ /*! Calculate square root of symmetric positive definite matrix a. Result is matrix s. */ int matrix_sqrt (matrix a, matrix * s) { const int MAX_ITER = 100; int n; int ok; int iter; register float sse, psse; register int i, j; matrix x, xinv, axinv, xtemp, error; matrix_initialize (&x); matrix_initialize (&xinv); matrix_initialize (&axinv); matrix_initialize (&xtemp); matrix_initialize (&error); if (a.rows != a.cols) matrix_error ("Illegal dimensions for matrix square root"); n = a.rows; matrix_identity (n, &x); psse = 1.0e+30; for (iter = 0; iter < MAX_ITER; iter++) { ok = matrix_inverse (x, &xinv); if (! ok) return (0); matrix_multiply (a, xinv, &axinv); matrix_add (x, axinv, &xtemp); matrix_scale (0.5, xtemp, &x); matrix_multiply (x, x, &xtemp); matrix_subtract (a, xtemp, &error); sse = 0.0; for (i = 0; i < n; i++) for (j = 0; j < n; j++) sse += error.elts[i][j] * error.elts[i][j] ; if (sse >= psse) break; psse = sse; } if (iter == MAX_ITER) return (0); matrix_equate (x, s); matrix_destroy (&x); matrix_destroy (&xinv); matrix_destroy (&axinv); matrix_destroy (&xtemp); return (1); } /*---------------------------------------------------------------------------*/ /*! Initialize vector data structure. */ void vector_initialize (vector * v) { v->dim = 0; v->elts = NULL; } /*---------------------------------------------------------------------------*/ /*! Destroy vector data structure by deallocating memory. */ void vector_destroy (vector * v) { if (v->elts != NULL) free (v->elts); vector_initialize (v); } /*---------------------------------------------------------------------------*/ /*! Create vector v by allocating memory and initializing values. */ void vector_create (int dim, vector * v) { //register int i; vector_destroy (v); if (dim < 0) matrix_error ("Illegal dimensions for new vector"); v->dim = dim; if (dim < 1) return; v->elts = (double *) calloc (sizeof(double) , dim); if (v->elts == NULL) matrix_error ("Memory allocation error"); } /*---------------------------------------------------------------------------*/ static void vector_create_noinit(int dim, vector * v) /* 28 Dec 2001: RWCox */ { //register int i; vector_destroy (v); if (dim < 0) matrix_error ("Illegal dimensions for new vector"); v->dim = dim; if (dim < 1) return; v->elts = (double *) malloc (sizeof(double) * dim); if (v->elts == NULL) matrix_error ("Memory allocation error"); } /*---------------------------------------------------------------------------*/ /*! Print contents of vector v. */ void vector_print (vector v) { int i; for (i = 0; i < v.dim; i++) printf (" %10.4g \n", v.elts[i]); printf (" \n"); fflush(stdout); } /*---------------------------------------------------------------------------*/ /*! Print label and contents of vector v. */ void vector_sprint (char * s, vector v) { printf ("%s \n", s); vector_print (v); } /*---------------------------------------------------------------------------*/ /*! Copy vector a. Result is vector b. */ void vector_equate (vector a, vector * b) { //register int i, register int dim; dim = a.dim; vector_create_noinit (dim, b); #if 0 for (i = 0; i < dim; i++) b->elts[i] = a.elts[i]; #else if( dim > 0 ) memcpy( b->elts , a.elts , sizeof(double)*dim ) ; /* RWCox */ #endif } /*---------------------------------------------------------------------------*/ /*! Convert simple array f into vector v. */ void array_to_vector (int dim, float * f, vector * v) { register int i; vector_create_noinit (dim, v); for (i = 0; i < dim; i++) v->elts[i] = f[i]; } /*---------------------------------------------------------------------------*/ /*! Convert column c of matrix m into vector v. */ void column_to_vector (matrix m, int c, vector * v) { register int i; register int dim; dim = m.rows; vector_create_noinit (dim, v); for (i = 0; i < dim; i++) v->elts[i] = m.elts[i][c]; } /*---------------------------------------------------------------------------*/ /*! Convert vector v into array f. */ void vector_to_array (vector v, float * f) { register int i; for (i = 0; i < v.dim; i++) f[i] = v.elts[i]; } /*---------------------------------------------------------------------------*/ /*! Add vector a to vector b. Result is vector c. */ void vector_add (vector a, vector b, vector * c) { register int i, dim; if (a.dim != b.dim) matrix_error ("Incompatible dimensions for vector addition"); dim = a.dim; vector_create_noinit (dim, c); for (i = 0; i < dim; i++) c->elts[i] = a.elts[i] + b.elts[i]; #ifdef ENABLE_FLOPS flops += dim ; #endif } /*---------------------------------------------------------------------------*/ /*! Subtract vector b from vector a. Result is vector c. */ void vector_subtract (vector a, vector b, vector * c) { register int i, dim; register double *aa,*bb,*cc ; if (a.dim != b.dim) matrix_error ("Incompatible dimensions for vector subtraction"); dim = a.dim; vector_create_noinit (dim, c); aa = a.elts ; bb = b.elts ; cc = c->elts ; for (i = 0; i < dim; i++) #if 0 c->elts[i] = a.elts[i] - b.elts[i]; #else cc[i] = aa[i] - bb[i] ; #endif #ifdef ENABLE_FLOPS flops += dim ; #endif } /*** for vector-matrix multiply routines below ***/ #define UNROLL_VECMUL /* RWCox */ /*---------------------------------------------------------------------------*/ /*! Right multiply matrix a by vector b. Result is vector c. */ void vector_multiply (matrix a, vector b, vector * c) { register int rows, cols; register int i, j; register double *bb ; register double sum ; #ifdef DOTP register double **aa , *cc ; #else register double *aa ; #endif if (a.cols != b.dim){ char str[444] ; sprintf(str, "Incompatible dimensions for vector multiplication: %dx%d X %d", a.rows,a.cols,b.dim ) ; matrix_error(str) ; } rows = a.rows; cols = a.cols; vector_create_noinit (rows, c); if( cols <= 0 ){ for( i=0 ; i < rows ; i++ ) c->elts[i] = 0.0 ; return ; } bb = b.elts ; #ifdef MATVEC MATVEC( a , b , *c ) ; /* 04 Mar 2005 */ #elif defined(DOTP) /* vectorized */ aa = a.elts ; cc = c->elts ; i = rows%2 ; if( i == 1 ) DOTP(cols,aa[0],bb,cc) ; for( ; i < rows ; i+=2 ){ DOTP(cols,aa[i] ,bb,cc+i ) ; DOTP(cols,aa[i+1],bb,cc+(i+1)) ; } #else #ifdef UNROLL_VECMUL switch( cols%4 ){ case 0: for (i = 0; i < rows; i++){ sum = 0.0 ; aa = a.elts[i] ; for (j = 0; j < cols; j+=4 ) sum += aa[j]*bb[j]+aa[j+1]*bb[j+1]+aa[j+2]*bb[j+2]+aa[j+3]*bb[j+3]; c->elts[i] = sum ; } break ; case 1: for (i = 0; i < rows; i++){ aa = a.elts[i] ; sum = aa[0]*bb[0] ; for (j = 1; j < cols; j+=4 ) sum += aa[j]*bb[j]+aa[j+1]*bb[j+1]+aa[j+2]*bb[j+2]+aa[j+3]*bb[j+3]; c->elts[i] = sum ; } break ; case 2: for (i = 0; i < rows; i++){ aa = a.elts[i] ; sum = aa[0]*bb[0]+aa[1]*bb[1] ; for (j = 2; j < cols; j+=4 ) sum += aa[j]*bb[j]+aa[j+1]*bb[j+1]+aa[j+2]*bb[j+2]+aa[j+3]*bb[j+3]; c->elts[i] = sum ; } break ; case 3: for (i = 0; i < rows; i++){ aa = a.elts[i] ; sum = aa[0]*bb[0]+aa[1]*bb[1]+aa[2]*bb[2] ; for (j = 3; j < cols; j+=4 ) sum += aa[j]*bb[j]+aa[j+1]*bb[j+1]+aa[j+2]*bb[j+2]+aa[j+3]*bb[j+3]; c->elts[i] = sum ; } break ; } #else for (i = 0; i < rows; i++){ sum = 0.0 ; aa = a.elts[i] ; for (j = 0; j < cols; j++ ) sum += aa[j]*bb[j] ; c->elts[i] = sum ; } #endif /* UNROLL_VECMUL */ #endif /* MATVEC, DOTP */ #ifdef ENABLE_FLOPS flops += 2.0*rows*cols ; dotsum += rows*cols ; dotnum += rows ; #endif return ; } /*---------------------------------------------------------------------------*/ /*! Compute d = c-a*b: a is a matrix; b,c,d are vectors -- RWCox 26 Feb 2002: return value is sum of squares of d vector */ double vector_multiply_subtract (matrix a, vector b, vector c, vector * d) { register int rows, cols; register int i, j; register double *bb ; #ifdef DOTP double qsum,sum , **aa , *dd,*cc,*ee ; #else register double qsum,sum, *aa ; #endif if (a.cols != b.dim || a.rows != c.dim ) matrix_error ("Incompatible dimensions for vector multiplication-subtraction"); rows = a.rows; cols = a.cols; vector_create_noinit (rows, d); if( cols <= 0 ){ qsum = 0.0 ; for( i=0 ; i < rows ; i++ ){ d->elts[i] = c.elts[i] ; qsum += d->elts[i] * d->elts[i] ; } return qsum ; } qsum = 0.0 ; bb = b.elts ; #ifdef DOTP /* vectorized */ aa = a.elts ; dd = d->elts ; cc = c.elts ; ee = (double *)malloc(sizeof(double)*rows) ; i = rows%2 ; if( i == 1 ) DOTP(cols,aa[0],bb,ee) ; for( ; i < rows ; i+=2 ){ DOTP(cols,aa[i] ,bb,ee+i ) ; DOTP(cols,aa[i+1],bb,ee+(i+1)) ; } VSUB(rows,cc,ee,dd) ; DOTP(rows,dd,dd,&qsum) ; free((void *)ee) ; #else #ifdef UNROLL_VECMUL switch( cols%4 ){ case 0: for (i = 0; i < rows; i++){ aa = a.elts[i] ; sum = c.elts[i] ; for (j = 0; j < cols; j+=4 ) sum -= aa[j]*bb[j]+aa[j+1]*bb[j+1]+aa[j+2]*bb[j+2]+aa[j+3]*bb[j+3]; d->elts[i] = sum ; qsum += sum*sum ; } break ; case 1: for (i = 0; i < rows; i++){ aa = a.elts[i] ; sum = c.elts[i]-aa[0]*bb[0] ; for (j = 1; j < cols; j+=4 ) sum -= aa[j]*bb[j]+aa[j+1]*bb[j+1]+aa[j+2]*bb[j+2]+aa[j+3]*bb[j+3]; d->elts[i] = sum ; qsum += sum*sum ; } break ; case 2: for (i = 0; i < rows; i++){ aa = a.elts[i] ; sum = c.elts[i]-aa[0]*bb[0]-aa[1]*bb[1] ; for (j = 2; j < cols; j+=4 ) sum -= aa[j]*bb[j]+aa[j+1]*bb[j+1]+aa[j+2]*bb[j+2]+aa[j+3]*bb[j+3]; d->elts[i] = sum ; qsum += sum*sum ; } break ; case 3: for (i = 0; i < rows; i++){ aa = a.elts[i] ; sum = c.elts[i]-aa[0]*bb[0]-aa[1]*bb[1]-aa[2]*bb[2] ; for (j = 3; j < cols; j+=4 ) sum -= aa[j]*bb[j]+aa[j+1]*bb[j+1]+aa[j+2]*bb[j+2]+aa[j+3]*bb[j+3]; d->elts[i] = sum ; qsum += sum*sum ; } break ; } #else for (i = 0; i < rows; i++){ aa = a.elts[i] ; sum = c.elts[i] ; for (j = 0; j < cols; j++) sum -= aa[j] * bb[j] ; d->elts[i] = sum ; qsum += sum*sum ; } #endif /* UNROLL_VECMUL */ #endif /* DOTP */ #ifdef ENABLE_FLOPS flops += 2.0*rows*(cols+1) ; dotsum += rows*cols ; dotnum += rows ; #endif return qsum ; /* 26 Feb 2003 */ } /*---------------------------------------------------------------------------*/ /*! Calculate dot product of vector a with vector b. */ double vector_dot (vector a, vector b) { register int i, dim; register double sum; register double *aa , *bb ; if (a.dim != b.dim) matrix_error ("Incompatible dimensions for vector dot product"); dim = a.dim; sum = 0.0; aa = a.elts ; bb = b.elts ; for (i = 0; i < dim; i++) #if 0 sum += a.elts[i] * b.elts[i]; #else sum += aa[i] * bb[i] ; #endif #ifdef ENABLE_FLOPS flops += 2.0*dim ; #endif return (sum); } /*--------------------------------------------------------------------------*/ /*! Calculate dot product of vector a with itself -- 28 Dec 2001, RWCox. */ double vector_dotself( vector a ) { register int i, dim; register double sum; register double *aa ; dim = a.dim; sum = 0.0; aa = a.elts ; for (i = 0; i < dim; i++) #if 0 sum += a.elts[i] * a.elts[i]; #else sum += aa[i] * aa[i] ; #endif #ifdef ENABLE_FLOPS flops += 2.0*dim ; #endif return (sum); } /*---------------------------------------------------------------------------*/ /*! Compute the L_infinity norm of a matrix: the max absolute row sum. */ double matrix_norm( matrix a ) { int i,j , rows=a.rows, cols=a.cols ; double sum , smax=0.0 ; for (i = 0; i < rows; i++){ sum = 0.0 ; for (j = 0; j < cols; j++) sum += fabs(a.elts[i][j]) ; if( sum > smax ) smax = sum ; } #ifdef ENABLE_FLOPS flops += 2.0*rows*cols ; #endif return smax ; } /*---------------------------------------------------------------------------*/ /*! Search a matrix for nearly identical column pairs, where "nearly identical" means they are correlated closer than 1-eps. Return is a pointer to an int array of the form [ i1 j1 i2 j2 ... -1 -1 ] where columns (i1,j1) are nearly the same, (i2,j2) also, etc. In addition: - A pair (i,-1) indicates that column #i is all zeros. - The array is terminated with the pair (-1,-1). - If there are no bad column pairs or all-zero columns, NULL is returned. - Pairs of all-zero columns are NOT reported. - The array should be free()-ed when you are done with it. -----------------------------------------------------------------------------*/ int * matrix_check_columns( matrix a , double eps ) /* 14 Jul 2004 */ { int i,j,k , rows=a.rows , cols=a.cols ; int *iar=NULL , nar=0 ; double sumi,sumj,sumd ; if( eps <= 0.0 ) eps = 1.e-5 ; for( i=0 ; i < cols ; i++ ){ sumi = 0.0 ; for( k=0 ; k < rows ; k++ ) sumi += a.elts[k][i] * a.elts[k][i] ; if( sumi <= 0.0 ){ iar = (int *)realloc( (void *)iar , sizeof(int)*2*(nar+1) ) ; iar[2*nar] = i ; iar[2*nar+1] = -1 ; nar++ ; continue ; /* skip to next column i */ } for( j=i+1 ; j < cols ; j++ ){ sumj = sumd = 0.0 ; for( k=0 ; k < rows ; k++ ){ sumj += a.elts[k][j] * a.elts[k][j] ; sumd += a.elts[k][j] * a.elts[k][i] ; } if( sumj > 0.0 ){ sumd = fabs(sumd) / sqrt(sumi*sumj) ; if( sumd >= 1.0-eps ){ iar = (int *)realloc( (void *)iar , sizeof(int)*2*(nar+1) ) ; iar[2*nar] = i ; iar[2*nar+1] = j ; nar++ ; } } } } if( iar != NULL ){ iar = (int *)realloc( (void *)iar , sizeof(int)*2*(nar+1) ) ; iar[2*nar] = iar[2*nar+1] = -1 ; } return iar ; } /*---------------------------------------------------------------------------*/ /*! Return the eigenvalues of matrix X-transpose X, scaled to diagonal 1. The output points to a vector of doubles, of length X.cols. This should be free()-ed when you are done with it. -----------------------------------------------------------------------------*/ /* CARET double * matrix_singvals( matrix X ) { int i,j,k , M=X.rows , N=X.cols ; double *a , *e , sum ; a = (double *) malloc( sizeof(double)*N*N ) ; e = (double *) malloc( sizeof(double)*N ) ; for( i=0 ; i < N ; i++ ){ for( j=0 ; j <= i ; j++ ){ sum = 0.0 ; for( k=0 ; k < M ; k++ ) sum += X.elts[k][i] * X.elts[k][j] ; a[j+N*i] = sum ; if( j < i ) a[i+N*j] = sum ; } } for( i=0 ; i < N ; i++ ){ if( a[i+N*i] > 0.0 ) e[i] = 1.0 / sqrt(a[i+N*i]) ; else e[i] = 1.0 ; } for( i=0 ; i < N ; i++ ){ for( j=0 ; j < N ; j++ ) a[j+N*i] *= e[i]*e[j] ; } symeigval_double( N , a , e ) ; free( (void *)a ) ; #ifdef ENABLE_FLOPS flops += (M+N+2.0)*N*N ; #endif return e ; } CARET */ /*---------------------------------------------------------------------------*/ //CARETextern void svd_double( int, int, double *, double *, double *, double * ) ; static double pseps = 1.e-16 ; void matrix_psinv_seteps( double eps ) { pseps = (eps > 0.0) ? eps : 1.e-16 ; } /*---------------------------------------------------------------------------*/ /*! Given MxN matrix X, return the NxN matrix [ T ]-1 [ T ]-1 T [ X X ] and the NxM matrix [ X X ] X -----------------------------------------------------------------------------*/ // CARET REMOVEDvoid matrix_psinvXX( matrix X , matrix *XtXinv , matrix *XtXinvXt ) caret-5.6.4~dfsg.1.orig/caret_uniformize/estpdf3.c0000664000175000017500000003153111572067322021645 0ustar michaelmichael/***************************************************************************** Major portions of this software are copyrighted by the Medical College of Wisconsin, 1994-2000, and are released under the Gnu General Public License, Version 2. See the file README.Copyright for details. ******************************************************************************/ /*---------------------------------------------------------------------------*/ /* These routines estimate the probability density function (PDF) corresponding to the distribution of gray-matter and white-matter voxel intensities. The estimate is formed as the sum of three normal distributions, using the Simplex algorithm for non-linear optimization to estimate the unknown parameters. File: estpdf.c Author: B. Douglas Ward Date: 27 May 1999 Mod: Extensive restructuring of the code. Date: 28 January 2000 Mod: USE_QUIET (RWCox) Date: 16 Apr 2003 */ #ifndef USE_QUIET /* 16 Apr 2003 */ # define quiet 0 #endif /*---------------------------------------------------------------------------*/ /* Include header files and forward declarations. */ #include "pdf.h" float calc_error (float * vertex); /*---------------------------------------------------------------------------*/ /* Global variables and constants. */ #define DIMENSION 9 /* number of parameters to be estimated */ pdf p; /* empirical pdf */ /*---------------------------------------------------------------------------*/ /* Include source code files. */ #include "randgen.c" #include "pdf.c" #include "Simplexx.c" /*---------------------------------------------------------------------------*/ /* Perform initialization for estimation of PDF from short array. */ void estpdf_short_initialize ( int nxyz, short * sfim, float * gpeak, /* estimated peak of gray-matter distribution */ float * wpeak /* estimated peak of white-matter distribution */ ) { pdf ps; int gmax, wmax; //int kk; int ok = 1; /*---- Initialize pdf's -----*/ PDF_initialize (&p); PDF_initialize (&ps); /*----- Convert short array to pdf estimate -----*/ PDF_short_to_pdf (nxyz, sfim, &p); PDF_sprint ("\nOriginal PDF:", p); /*----- Trim extreme values from pdf estimate -----*/ PDF_trim (0.01, 0.99, &p); PDF_sprint ("\nTrimmed PDF:", p); /*----- Smooth the pdf estimate -----*/ PDF_copy (p, &ps); PDF_smooth (&ps); PDF_sprint ("\nSmoothed PDF:", ps); /*----- Try to locate bimodality of the pdf -----*/ ok = PDF_find_bimodal (ps, &gmax, &wmax); if (ok) { *gpeak = PDF_ibin_to_xvalue (ps, gmax); *wpeak = PDF_ibin_to_xvalue (ps, wmax); } else { printf ("Unable to find bimodal distribution \n"); *gpeak = (2.0/3.0)*p.lower_bnd + (1.0/3.0)*p.upper_bnd; *wpeak = (1.0/3.0)*p.lower_bnd + (2.0/3.0)*p.upper_bnd; } if( !quiet ){ printf ("\nInitial PDF estimates: \n"); printf ("Lower Bnd = %8.3f Upper Bnd = %8.3f \n", p.lower_bnd, p.upper_bnd); printf ("Gray Peak = %8.3f White Peak = %8.3f \n", *gpeak, *wpeak); } PDF_destroy (&ps); } /*---------------------------------------------------------------------------*/ /* Perform initialization for estimation of PDF from float array. */ void estpdf_float_initialize ( int nxyz, float * ffim, int nbin, float * gpeak, /* estimated peak of gray-matter distribution */ float * wpeak /* estimated peak of white-matter distribution */ ) { pdf ps; int gmax, wmax; //int kk; int ok = 1; /*---- Initialize pdf's -----*/ PDF_initialize (&p); PDF_initialize (&ps); /*----- Convert float array to pdf estimate -----*/ PDF_float_to_pdf (nxyz, ffim, nbin, &p); PDF_sprint ("\nOriginal PDF:", p); /*----- Trim extreme values from pdf estimate -----*/ PDF_trim (0.01, 0.99, &p); PDF_sprint ("\nTrimmed PDF:", p); /*----- Smooth the pdf estimate -----*/ PDF_copy (p, &ps); PDF_smooth (&ps); PDF_sprint ("\nSmoothed PDF:", ps); /*----- Try to locate bimodality of the pdf -----*/ ok = PDF_find_bimodal (ps, &gmax, &wmax); if (ok) { *gpeak = PDF_ibin_to_xvalue (ps, gmax); *wpeak = PDF_ibin_to_xvalue (ps, wmax); } else { printf ("Unable to find bimodal distribution \n"); *gpeak = (2.0/3.0)*p.lower_bnd + (1.0/3.0)*p.upper_bnd; *wpeak = (1.0/3.0)*p.lower_bnd + (2.0/3.0)*p.upper_bnd; } if( !quiet ){ printf ("\nInitial PDF estimates: \n"); printf ("Lower Bnd = %8.3f Upper Bnd = %8.3f \n", p.lower_bnd, p.upper_bnd); printf ("Gray Peak = %8.3f White Peak = %8.3f \n", *gpeak, *wpeak); } PDF_destroy (&ps); } /*---------------------------------------------------------------------------*/ /* Generate the initial guess for the parameter vector. */ void generate_initial_guess (float gpeak, float wpeak, float * parameters) { float b; /* coefficient for background distribution */ float bmean; /* mean for background distribution */ float bsigma; /* std. dev. for background distribution */ float g; /* coefficient for gray-matter distribution */ float gmean; /* mean for gray-matter distribution */ float gsigma; /* std. dev. for gray-matter distribution */ float w; /* coefficient for white-matter distribution */ float wmean; /* mean for white-matter distribution */ float wsigma; /* std. dev. for white-matter distribution */ /*----- Initialize distribution coefficients -----*/ b = 0.75; g = 0.25; w = 0.25; /*----- Initialize distribution means -----*/ bmean = p.lower_bnd; if ((gpeak > p.lower_bnd) && (gpeak < p.upper_bnd) && (gpeak < wpeak)) gmean = gpeak; else gmean = p.lower_bnd; if ((wpeak > p.lower_bnd) && (wpeak < p.upper_bnd) && (wpeak > gpeak)) wmean = wpeak; else wmean = p.upper_bnd; if ((gmean-bmean) < 0.25*(wmean-bmean)) gmean = bmean + 0.25*(wmean-bmean); if ((wmean-gmean) < 0.25*(wmean-bmean)) gmean = wmean - 0.25*(wmean-bmean); /*----- Initialize distribution standard deviations -----*/ bsigma = 0.25 * (p.upper_bnd - p.lower_bnd); gsigma = 0.25 * (wmean - gmean); wsigma = 0.25 * (wmean - gmean); /*----- Set parameter vector -----*/ parameters[0] = b; parameters[1] = bmean; parameters[2] = bsigma; parameters[3] = g; parameters[4] = gmean; parameters[5] = gsigma; parameters[6] = w; parameters[7] = wmean; parameters[8] = wsigma; } /*---------------------------------------------------------------------------*/ /* Write parameter vector. */ void write_parameter_vector (float * parameters) { int i; printf ("Dimension = %d \n", DIMENSION); for (i = 0; i < DIMENSION; i++) printf ("parameter[%d] = %f \n", i, parameters[i]); } /*---------------------------------------------------------------------------*/ /* Normal probability density function. */ float normal (float x, float mean, float sigma) { float z; z = (x - mean) / sigma; return ( (1.0/(sqrt(2.0*PI)*sigma)) * exp (-0.5 * z * z) ); } /*---------------------------------------------------------------------------*/ /* Estimate the voxel intensity distribution as the sum of three normal PDF's. */ float estimate (float * parameters, float x) { float b, bmean, bsigma, g, gmean, gsigma, w, wmean, wsigma; //float z, float fval; /*----- Initialize local variables -----*/ b = parameters[0]; bmean = parameters[1]; bsigma = parameters[2]; g = parameters[3]; gmean = parameters[4]; gsigma = parameters[5]; w = parameters[6]; wmean = parameters[7]; wsigma = parameters[8]; /*----- Calculate the sum of three normal PDF's -----*/ fval = b * normal (x, bmean, bsigma); fval += g * normal (x, gmean, gsigma); fval += w * normal (x, wmean, wsigma); return (fval); } /*---------------------------------------------------------------------------*/ /* Calculate the error sum of squares for the PDF estimate. */ float calc_error (float * vertex) { const float BIG_NUMBER = 1.0e+10; /* return when constraints are violated */ float b, bmean, bsigma, g, gmean, gsigma, w, wmean, wsigma; /* parameters */ float deltah, deltam; /* rough estimate of spread of distribution */ int i; float t; float diff, sse; count += 1; /*----- Assign local variables -----*/ b = vertex[0]; bmean = vertex[1]; bsigma = vertex[2]; g = vertex[3]; gmean = vertex[4]; gsigma = vertex[5]; w = vertex[6]; wmean = vertex[7]; wsigma = vertex[8]; deltah = p.upper_bnd - p.lower_bnd; deltam = wmean - gmean; /*----- Apply constraints? -----*/ if ((b < 0.05) || (b > 1.5)) return (BIG_NUMBER); if ((g < 0.05) || (g > 1.0)) return (BIG_NUMBER); if ((w < 0.05) || (w > 1.0)) return (BIG_NUMBER); if ((b+g+w < 1.0) || (b+g+w > 2.0)) return (BIG_NUMBER); if ((bmean < p.lower_bnd) || (bmean > p.upper_bnd)) return (BIG_NUMBER); if ((gmean < p.lower_bnd) || (gmean > p.upper_bnd)) return (BIG_NUMBER); if ((wmean < p.lower_bnd) || (wmean > p.upper_bnd)) return (BIG_NUMBER); if ((gmean < bmean) || (gmean > wmean)) return (BIG_NUMBER); if ((gmean-bmean) < 0.10*(wmean-bmean)) return (BIG_NUMBER); if ((wmean-gmean) < 0.10*(wmean-bmean)) return (BIG_NUMBER); if ((bsigma < 0.01*deltah) || (bsigma > 0.5*deltah)) return (BIG_NUMBER); if ((gsigma < 0.01*deltam) || (gsigma > 0.5*deltam)) return (BIG_NUMBER); if ((wsigma < 0.01*deltam) || (wsigma > 0.5*deltam)) return (BIG_NUMBER); /*----- Not constrained, so calculate actual error sum of squares -----*/ sse = 0.0; for (i = 0; i < p.nbin; i++) { t = PDF_ibin_to_xvalue (p, i); diff = p.prob[i] - estimate (vertex, t)*p.width; sse += diff * diff; } return (sse); } /*---------------------------------------------------------------------------*/ /* Write the parameter estimates. */ void output_pdf_results (float * vertex, float sse) { float b, bmean, bsigma, g, gmean, gsigma, w, wmean, wsigma; /*----- Assign variables -----*/ b = vertex[0]; bmean = vertex[1]; bsigma = vertex[2]; g = vertex[3]; gmean = vertex[4]; gsigma = vertex[5]; w = vertex[6]; wmean = vertex[7]; wsigma = vertex[8]; if( !quiet ){ printf ("\nProbability Density Function Estimates: \n"); printf ("Background Coef = %f \n", b); printf ("Background Mean = %f \n", bmean); printf ("Background Std Dev = %f \n", bsigma); printf ("Gray Matter Coef = %f \n", g); printf ("Gray Matter Mean = %f \n", gmean); printf ("Gray Matter Std Dev = %f \n", gsigma); printf ("White Matter Coef = %f \n", w); printf ("White Matter Mean = %f \n", wmean); printf ("White Matter Std Dev = %f \n", wsigma); printf ("\nrmse = %f \n", sqrt (sse / p.nbin )); } } /*---------------------------------------------------------------------------*/ /* Estimate the PDF of the voxel intensities. */ void estpdf_short (int nxyz, short * sfim, float * parameters) { float gpeak; /* estimated peak of gray-matter distribution */ float wpeak; /* estimated peak of white-matter distribution */ float sse; /*----- Progress report -----*/ if( !quiet ) printf ("\nEstimating PDF of voxel intensities \n"); /*----- Initialization for PDF estimation -----*/ estpdf_short_initialize (nxyz, sfim, &gpeak, &wpeak); generate_initial_guess (gpeak, wpeak, parameters); /*----- Get least squares estimate for PDF parameters -----*/ simplex_optimization (parameters, &sse); /*----- Report PDF parameters -----*/ output_pdf_results (parameters, sse); /*----- Free memory -----*/ /* PDF_destroy (&p); */ return; } /*---------------------------------------------------------------------------*/ /* Estimate the PDF of the voxel intensities. */ void estpdf_float (int nxyz, float * ffim, int nbin, float * parameters) { float gpeak; /* estimated peak of gray-matter distribution */ float wpeak; /* estimated peak of white-matter distribution */ float sse; /*----- Progress report -----*/ if( !quiet ) printf ("\nEstimating PDF of voxel intensities \n"); /*----- Initialization for PDF estimation -----*/ estpdf_float_initialize (nxyz, ffim, nbin, &gpeak, &wpeak); /*----- Make initial estimate of the parameters from previous results -----*/ generate_initial_guess (gpeak, wpeak, parameters); /*----- Get least squares estimate for PDF parameters -----*/ simplex_optimization (parameters, &sse); /*----- Report PDF parameters -----*/ output_pdf_results (parameters, sse); /*----- Free memory -----*/ /* PDF_destroy (&p); */ return ; } /*---------------------------------------------------------------------------*/ caret-5.6.4~dfsg.1.orig/caret_uniformize/caret_uniformize.pro0000664000175000017500000000100611572067322024212 0ustar michaelmichael###################################################################### # Automatically generated by qmake (1.04a) Tue Jan 14 11:58:13 2003 ###################################################################### TARGET = CaretUniformize CONFIG += staticlib INCLUDEPATH += . dll { CONFIG -= staticlib CONFIG += plugin } include(../caret_qmake_include.pro) !vs:TEMPLATE = lib vs:TEMPLATE=vclib # Input HEADERS += \ caret_uniformize.h \ matrix.h SOURCES += \ matrix.cxx \ caret_uniformize.cxx caret-5.6.4~dfsg.1.orig/caret_uniformize/caret_uniformize.h0000664000175000017500000000230011572067322023637 0ustar michaelmichael #ifndef __CARET_UNIFORMIZE_H__ #define __CARET_UNIFORMIZE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ class VolumeFile; void biasCorrectVolume(VolumeFile* volumeFile, const int lowLimitIn, const int highLimitIn, const int numberOfIterations); #endif // __CARET_UNIFORMIZE_H__ caret-5.6.4~dfsg.1.orig/caret_uniformize/caret_uniformize.cxx0000664000175000017500000005553611572067322024235 0ustar michaelmichael/***************************************************************************** Major portions of this software are copyrighted by the Medical College of Wisconsin, 1994-2001, and are released under the Gnu General Public License, Version 2. See the file README.Copyright for details. ******************************************************************************/ /*---------------------------------------------------------------------------*/ /* Program to correct for image intensity non-uniformity. File: 3dUniformize.c Author: B. Douglas Ward Date: 28 January 2000 Mod: Added call to AFNI_logger. Date: 15 August 2001 */ /*---------------------------------------------------------------------------*/ #define PROGRAM_NAME "3dUniformize" /* name of this program */ #define PROGRAM_AUTHOR "B. D. Ward" /* program author */ #define PROGRAM_INITIAL "28 January 2000" /* date of initial program release */ #define PROGRAM_LATEST "26 September 2005 [rickr, zss]" /* date of latest program revision */ /*---------------------------------------------------------------------------*/ /* Include header files. */ #include // CARET #include // CARET #include // CARET #include // CARET #include #include "caret_uniformize.h" #include "DebugControl.h" #include "VolumeFile.h" // CARET //CARET #include "mrilib.h" #include "matrix.h" #define IJK_TO_THREE(ijk,i,j,k,nx,nxy) \ ( (k) = (ijk)/(nxy) , (j)=((ijk)%(nxy))/(nx) , (i)=(ijk)%(nx) ) /*---------------------------------------------------------------------------*/ /* Global variables, constants, and data structures. */ #define MAX_STRING_LENGTH 80 static short* inputData = NULL; // CARET static VolumeFile* inputVolume; // CARET static THD_3dim_dataset * anat_dset = NULL; /* input anatomical dataset */ //CARET char * commandline = NULL ; /* command line for history notes */ // CARET int input_datum = MRI_short ; /* 16 Apr 2003 - RWCox */ static int quiet = 0 ; /* ditto */ #define USE_QUIET typedef bool Boolean; // CARET typedef struct UN_options { char * anat_filename; /* file name for input anat dataset */ char * prefix_filename; /* prefix name for output dataset */ Boolean quiet; /* flag for suppress screen output */ int lower_limit; /* lower limit for voxel intensity */ int upper_limit; /* upper limit for voxel intensity 0 for ignoring this parameter*/ int rpts; /* #voxels in sub-sampled image (for pdf) */ int spts; /* #voxels in subsub-sampled image (for field poly.) */ int nbin; /* #bins for pdf estimation */ int npar; /* #parameters for field polynomial */ int niter; /* #number of iterations */ // CARET THD_3dim_dataset * new_dset; /* output afni data set pointer */ } UN_options; /*---------------------------------------------------------------------------*/ /* Include source code files. */ //CARET #include "matrix.c" #include "estpdf3.c" /*---------------------------------------------------------------------------*/ /* Print error message and stop. */ static void UN_error (char * message) { fprintf (stderr, "%s Error: %s \n", PROGRAM_NAME, message); //CARET exit(1); } /*---------------------------------------------------------------------------*/ /** macro to test a malloc-ed pointer for validity **/ #define MTEST(ptr) \ if((ptr)==NULL) \ ( UN_error ("Cannot allocate memory") ) /*---------------------------------------------------------------------------*/ /* Routine to initialize the input options. */ static void initialize_options ( UN_options * option_data /* uniformization program options */ ) { /*----- initialize default values -----*/ option_data->anat_filename = NULL; /* file name for input anat dataset */ option_data->prefix_filename = NULL; /* prefix name for output dataset */ option_data->quiet = FALSE; /* flag for suppress screen output */ option_data->lower_limit = 0; /* voxel intensity lower limit, used to be 25 always ZSS Sept. 36 05 */ option_data->upper_limit = 0; option_data->rpts = 200000; /* #voxels in sub-sampled image (for pdf) */ option_data->spts = 10000; /* #voxels in subsub-sampled image (for field polynomial estimation) */ option_data->nbin = 250; /* #bins for pdf estimation */ option_data->npar = 35; /* #parameters for field polynomial */ option_data->niter = 5; /* #number of iterations */ //CARET option_data->new_dset = NULL; } /*---------------------------------------------------------------------------*/ /* Program initialization. */ static void initialize_program ( UN_options ** option_data, /* uniformization program options */ short ** sfim /* output image volume */ ) { int nxyz; /* #voxels in input dataset */ /*----- Save command line for history notes -----*/ //CARET commandline = tross_commandline( PROGRAM_NAME , argc,argv ) ; /*----- Allocate memory for input options -----*/ *option_data = (UN_options *) malloc (sizeof(UN_options)); MTEST (*option_data); /*----- Initialize the input options -----*/ initialize_options (*option_data); /*----- Get operator inputs -----*/ //CARET get_options (argc, argv, *option_data); /*----- Verify that inputs are acceptable -----*/ //CARET verify_inputs (*option_data); /*----- Initialize random number generator -----*/ rand_initialize (1234567); /*----- Allocate memory for output volume -----*/ //CARET nxyz = DSET_NX(anat_dset) * DSET_NY(anat_dset) * DSET_NZ(anat_dset); int dim[3]; //CARET inputVolume->getDimensions(dim); //CARET nxyz = dim[0] * dim[1] * dim[2]; //CARET *sfim = (short *) malloc (sizeof(short) * nxyz); MTEST (*sfim); } /*---------------------------------------------------------------------------*/ /* Write time series data to specified file. */ static void ts_write (char * filename, int ts_length, float * data) { int it; FILE * outfile = NULL; outfile = fopen (filename, "w"); for (it = 0; it < ts_length; it++) { fprintf (outfile, "%f ", data[it]); fprintf (outfile, " \n"); } fclose (outfile); } /*---------------------------------------------------------------------------*/ /* Resample the original image at randomly selected voxels (whose intensity value is greater than the specified lower limit, to exclude voxels outside the brain). Take the logarithm of the intensity values for the selected voxels. */ static void resample ( UN_options * option_data, int * ir, /* voxel indices for resampled image */ float * vr /* resampled image data (logarithms) */ ) { short * anat_data = NULL; int nxyz; int rpts; int lower_limit; int it, k; /*----- Initialize local variables -----*/ //CARET nxyz = DSET_NX(anat_dset) * DSET_NY(anat_dset) * DSET_NZ(anat_dset); int dim[3]; //CARET inputVolume->getDimensions(dim); //CARET nxyz = dim[0] * dim[1] * dim[2]; //CARET //CARET anat_data = (short *) DSET_BRICK_ARRAY(anat_dset,0); anat_data = inputData; //CARET lower_limit = option_data->lower_limit; rpts = option_data->rpts; it = 0; while (it < rpts) { k = (int)rand_uniform (0, nxyz); /* okay if no upper_limit, or data < upper_limit 16 Dec 2005 [rickr] */ if ( (k >= 0) && (k < nxyz) && (anat_data[k] > lower_limit) && ( ! option_data->upper_limit || (anat_data[k] < option_data->upper_limit) ) ) { ir[it] = k; vr[it] = log (anat_data[k] + rand_uniform (0.0,1.0)); it++; } } return; } /*---------------------------------------------------------------------------*/ /* Create intensity map that will tend to concentrate values around the means of the gray and white matter distributions. */ static void create_map (pdf vpdf, float * pars, float * vtou) { int ibin; float v; for (ibin = 0; ibin < vpdf.nbin; ibin++) { v = PDF_ibin_to_xvalue (vpdf, ibin); if ((v > pars[4]-2.0*pars[5]) && (v < 0.5*(pars[4]+pars[7]))) vtou[ibin] = pars[4]; else if ((v > 0.5*(pars[4]+pars[7])) && (v < pars[7]+2.0*pars[8])) vtou[ibin] = pars[7]; else vtou[ibin] = v; } } /*---------------------------------------------------------------------------*/ /* Use the intensity map to transform values of voxel intensities. */ static void map_vtou (pdf vpdf, int rpts, float * vr, float * vtou, float * ur) { int i, ibin; float v; for (i = 0; i < rpts; i++) { v = vr[i]; ibin = PDF_xvalue_to_ibin (vpdf, v); if ((ibin >= 0) && (ibin < vpdf.nbin)) ur[i] = vtou[ibin]; else ur[i] = v; } } /*---------------------------------------------------------------------------*/ static void subtract (int rpts, float * a, float * b, float * c) { int i; for (i = 0; i < rpts; i++) { c[i] = a[i] - b[i]; } } /*---------------------------------------------------------------------------*/ /* Create one row of the X matrix. */ static void create_row (int ixyz, int nx, int ny, int nz, float * xrow) { int ix, jy, kz; float x, y, z, x2, y2, z2, x3, y3, z3, x4, y4, z4; IJK_TO_THREE (ixyz, ix, jy, kz, nx, nx*ny); x = (float) ix / (float) nx - 0.5; y = (float) jy / (float) ny - 0.5; z = (float) kz / (float) nz - 0.5; x2 = x*x; x3 = x*x2; x4 = x2*x2; y2 = y*y; y3 = y*y2; y4 = y2*y2; z2 = z*z; z3 = z*z2; z4 = z2*z2; xrow[0] = 1.0; xrow[1] = x; xrow[2] = y; xrow[3] = z; xrow[4] = x*y; xrow[5] = x*z; xrow[6] = y*z; xrow[7] = x2; xrow[8] = y2; xrow[9] = z2; xrow[10] = x*y*z; xrow[11] = x2*y; xrow[12] = x2*z; xrow[13] = y2*x; xrow[14] = y2*z; xrow[15] = z2*x; xrow[16] = z2*y; xrow[17] = x3; xrow[18] = y3; xrow[19] = z3; xrow[20] = x2*y*z; xrow[21] = x*y2*z; xrow[22] = x*y*z2; xrow[23] = x2*y2; xrow[24] = x2*z2; xrow[25] = y2*z2; xrow[26] = x3*y; xrow[27] = x3*z; xrow[28] = x*y3; xrow[29] = y3*z; xrow[30] = x*z3; xrow[31] = y*z3; xrow[32] = x4; xrow[33] = y4; xrow[34] = z4; return; } /*---------------------------------------------------------------------------*/ /* Approximate the distortion field with a polynomial function in 3 dimensions. */ static void poly_field (int nx, int ny, int nz, int rpts, int * ir, float * fr, int spts, int npar, float * fpar) { int p; /* number of parameters in the full model */ int i, j, k; matrix x; /* independent variable matrix */ matrix xtxinv; /* matrix: 1/(X'X) */ matrix xtxinvxt; /* matrix: (1/(X'X))X' */ vector y; vector coef; float * xrow = NULL; int ip; //int iter; //float f; p = npar; /*----- Initialize matrices and vectors -----*/ matrix_initialize (&x); matrix_initialize (&xtxinv); matrix_initialize (&xtxinvxt); vector_initialize (&y); vector_initialize (&coef); /*----- Allocate memory -----*/ matrix_create (spts, p, &x); vector_create (spts, &y); xrow = (float *) malloc (sizeof(float) * p); /*----- Set up the X matrix and Y vector -----*/ for (i = 0; i < spts; i++) { k = (int)rand_uniform (0, rpts); create_row (ir[k], nx, ny, nz, xrow); for (j = 0; j < p; j++) x.elts[i][j] = xrow[j]; y.elts[i] = fr[k]; } /* matrix_sprint ("X matrix = ", x); vector_sprint ("Y vector = ", y); */ { /*----- calculate various matrices which will be needed later -----*/ matrix xt, xtx; /* temporary matrix calculation results */ int ok; /* flag for successful matrix inversion */ /*----- initialize matrices -----*/ matrix_initialize (&xt); matrix_initialize (&xtx); matrix_transpose (x, &xt); matrix_multiply (xt, x, &xtx); ok = matrix_inverse (xtx, &xtxinv); if (ok) matrix_multiply (xtxinv, xt, &xtxinvxt); else { matrix_sprint ("X matrix = ", x); matrix_sprint ("X'X matrix = ", xtx); UN_error ("Improper X matrix (cannot invert X'X) "); } /*----- dispose of matrices -----*/ matrix_destroy (&xtx); matrix_destroy (&xt); } /* matrix_sprint ("1/(X'X) = ", xtxinv); matrix_sprint ("(1/(X'X))X' = ", xtxinvxt); vector_sprint ("Y data = ", y); */ vector_multiply (xtxinvxt, y, &coef); /* vector_sprint ("Coef = ", coef); */ for (ip = 0; ip < p; ip++) { fpar[ip] = coef.elts[ip]; } /*----- Dispose of matrices and vectors -----*/ matrix_destroy (&x); matrix_destroy (&xtxinv); matrix_destroy (&xtxinvxt); vector_destroy (&y); vector_destroy (&coef); free(xrow); } /*---------------------------------------------------------------------------*/ /* Use the 3-dimensional polynomial function to estimate the distortion field at each point. */ static float warp_image (int npar, float * fpar, int nx, int ny, int nz, int rpts, int * ir, float * fs) { int i, j; //float x; float * xrow; float max_warp; xrow = (float *) malloc (sizeof(float) * npar); max_warp = 0.0; for (i = 0; i < rpts; i++) { create_row (ir[i], nx, ny, nz, xrow); fs[i] = 0.0; for (j = 1; j < npar; j++) fs[i] += fpar[j] * xrow[j]; if (fabs(fs[i]) > max_warp) max_warp = fabs(fs[i]); } free (xrow); xrow = NULL; return (max_warp); } /*---------------------------------------------------------------------------*/ /* Find polynomial approximation to the distortion field. */ static void estimate_field (UN_options * option_data, int * ir, float * vr, float * fpar) { float * ur = NULL, * us = NULL, * fr = NULL, * fs = NULL, * wr = NULL; float * vtou = NULL; float * gpar; int iter = 0, itermax=5; int ip; //int it; int nx, ny, nz, nxy, nxyz; int rpts, spts, nbin, npar; float parameters [DIMENSION]; /* parameters for PDF estimation */ //Boolean ok = TRUE; /* flag for successful PDF estimation */ char filename[MAX_STRING_LENGTH]; /*----- Initialize local variables -----*/ //CARET nx = DSET_NX(anat_dset); ny = DSET_NY(anat_dset); nz = DSET_NZ(anat_dset); int dim[3]; //CARET inputVolume->getDimensions(dim); //CARET nx = dim[0]; ny = dim[1]; nz = dim[2]; //CARET nxy = nx*ny; nxyz = nxy*nz; rpts = option_data->rpts; spts = option_data->spts; nbin = option_data->nbin; npar = option_data->npar; itermax = option_data->niter; /*----- Allocate memory -----*/ ur = (float *) malloc (sizeof(float) * rpts); MTEST (ur); us = (float *) malloc (sizeof(float) * rpts); MTEST (us); fr = (float *) malloc (sizeof(float) * rpts); MTEST (fr); fs = (float *) malloc (sizeof(float) * rpts); MTEST (fs); wr = (float *) malloc (sizeof(float) * rpts); MTEST (wr); gpar = (float *) malloc (sizeof(float) * npar); MTEST (gpar); vtou = (float *) malloc (sizeof(float) * nbin); MTEST (vtou); /*----- Initialize polynomial coefficients -----*/ for (ip = 0; ip < npar; ip++) { fpar[ip] = 0.0; gpar[ip] = 0.0; } /*----- Estimate pdf for resampled data -----*/ if( 0 && !quiet ){ fprintf (stderr," PDF_Initializing... \n"); } PDF_initialize (&p); if( 0 && !quiet ){ fprintf (stderr," float to pdf... \n"); } PDF_float_to_pdf (rpts, vr, nbin, &p); if( !quiet ){ sprintf (filename, "p%d.1D", iter); fprintf (stderr," Writing pdf output to %s... \n", filename); PDF_write_file (filename, p); } /*----- Estimate gross field distortion -----*/ if( 0 && !quiet ){ fprintf (stderr," Estimating gross distortions... \n"); } poly_field (nx, ny, nz, rpts, ir, vr, spts, npar, fpar); warp_image (npar, fpar, nx, ny, nz, rpts, ir, fs); subtract (rpts, vr, fs, ur); for (ip = 0; ip < rpts; ip++) vr[ip] = ur[ip]; /*----- Iterate over field distortion for concentrating the PDF -----*/ for (iter = 1; iter <= itermax; iter++) { /*----- Estimate pdf for perturbed image ur -----*/ estpdf_float (rpts, ur, nbin, parameters); PDF_sprint ("p", p); if( !quiet ){ sprintf (filename, "p%d.1D", iter); PDF_write_file (filename, p); } /*----- Sharpen the pdf and produce modified image wr -----*/ create_map (p, parameters, vtou); if( !quiet ){ sprintf (filename, "vtou%d.1D", iter); ts_write (filename, p.nbin, vtou); } map_vtou (p, rpts, ur, vtou, wr); /*----- Estimate smooth distortion field fs -----*/ subtract (rpts, vr, wr, fr); poly_field (nx, ny, nz, rpts, ir, fr, spts, npar, gpar); warp_image (npar, gpar, nx, ny, nz, rpts, ir, fs); /*----- Create perturbed image ur -----*/ subtract (rpts, vr, fs, ur); } /*----- Accumulate distortion field polynomial coefficients -----*/ for (ip = 0; ip < npar; ip++) fpar[ip] += gpar[ip]; /*----- Deallocate memory -----*/ free (ur); ur = NULL; free (us); us = NULL; free (fr); fr = NULL; free (fs); fs = NULL; free (wr); wr = NULL; free (gpar); gpar = NULL; free (vtou); vtou = NULL; return; } /*---------------------------------------------------------------------------*/ /* Remove the nonuniformity field. */ static void remove_field (UN_options * option_data, float * fpar, short * sfim) { short * anat_data = NULL; int rpts; int npar; int lower_limit; int nx, ny, nz, nxyz; int ixyz, jpar; //float x; float * xrow; float f; double d, dmax = 0.0; int tcount = 0; /*----- Initialize local variables -----*/ //CARET nx = DSET_NX(anat_dset); ny = DSET_NY(anat_dset); nz = DSET_NZ(anat_dset); int dim[3]; //CARET inputVolume->getDimensions(dim); //CARET nx = dim[0]; ny = dim[1]; nz = dim[2]; //CARET nxyz = nx*ny*nz; //CARET anat_data = (short *) DSET_BRICK_ARRAY(anat_dset,0); anat_data = inputData; rpts = option_data->rpts; npar = option_data->npar; lower_limit = option_data->lower_limit; xrow = (float *) malloc (sizeof(float) * npar); for (ixyz = 0; ixyz < nxyz; ixyz++) { if (anat_data[ixyz] > lower_limit) { create_row (ixyz, nx, ny, nz, xrow); f = 0.0; for (jpar = 1; jpar < npar; jpar++) f += fpar[jpar] * xrow[jpar]; /* monitor the results for short range (rickr) */ { d = exp( log((float)(anat_data[ixyz]) - f)); if ( d > 32767.0 ) { if ( d > dmax ) dmax = d; sfim[ixyz] = 32767; tcount++; } else sfim[ixyz] = (short)d; } } else sfim[ixyz] = anat_data[ixyz]; } if ( dmax > 32767.0 && !option_data->quiet ) /* then report an overflow */ fprintf(stderr, "\n" "** warning: %d values exceeded the maximum dataset value of %d\n" " (max overflow value of %.1f)\n" "** such values were set to the maximum %d\n" "** check your results!\n", tcount, 32767, dmax, 32767); free(xrow); return; } /*---------------------------------------------------------------------------*/ /* Correct for image intensity nonuniformity. */ static void uniformize (UN_options * option_data, short * sfim) { int * ir = NULL; float * vr = NULL; float * fpar = NULL; int rpts, npar; /*----- Initialize local variables -----*/ rpts = option_data->rpts; npar = option_data->npar; /*----- Allocate memory -----*/ ir = (int *) malloc (sizeof(int) * rpts); MTEST(ir); vr = (float *) malloc (sizeof(float) * rpts); MTEST(vr); fpar = (float *) malloc (sizeof(float) * npar); MTEST(fpar); /*----- Resample the data -----*/ if( 0 && !quiet ){ fprintf (stderr," resampling... \n"); } resample (option_data, ir, vr); /*----- Estimate the nonuniformity field -----*/ if( 0 && !quiet ){ fprintf (stderr," estimating field... \n"); } estimate_field (option_data, ir, vr, fpar); /*----- Remove the nonuniformity field -----*/ if( 0 && !quiet ){ fprintf (stderr," removing field... \n"); } remove_field (option_data, fpar, sfim); /*----- Deallocate memory -----*/ free (ir); ir = NULL; free (vr); vr = NULL; free (fpar); fpar = NULL; } /*---------------------------------------------------------------------------*/ /* Do the bias correction */ void biasCorrectVolume(VolumeFile* inputVolumeIn, const int lowLimitIn, const int highLimitIn, const int numberOfIterations) { UN_options * option_data = NULL; /* uniformization program options */ short * sfim = NULL; /* output uniformized image */ inputVolume = inputVolumeIn; int dim[3]; inputVolume->getDimensions(dim); const int numVoxels = dim[0] * dim[1] * dim[2]; inputData = new short[numVoxels]; for (int i = 0; i < numVoxels; i++) { inputData[i] = static_cast(inputVolume->getVoxelWithFlatIndex(i)); } quiet = (DebugControl::getDebugOn() == false); /*----- Program initialization -----*/ if( !quiet ){ fprintf (stderr," Initializing... \n"); } initialize_program (&option_data, &sfim); option_data->lower_limit = lowLimitIn; option_data->upper_limit = highLimitIn; option_data->niter = numberOfIterations; /*----- Perform uniformization -----*/ if( !quiet ){ fprintf (stderr," Uniformizing... \n"); } uniformize (option_data, sfim); /*----- Write out the results -----*/ if( !quiet ){ fprintf (stderr," Writing results... \n"); } for (int i = 0; i < numVoxels; i++) { inputVolume->setVoxelWithFlatIndex(i, 0, sfim[i]); } //write_afni_data (option_data, sfim); delete[] inputData; if (sfim != NULL) free(sfim); if (option_data != NULL) free(option_data); } /*---------------------------------------------------------------------------*/ /* This is the main routine for program 3dUniformize. */ /* int main ( int argc, char ** argv ) { QApplication app(argc, argv, false); VolumeFile volume; try { volume.readFile("anat_needs_correction.nii"); //volume.readFile("Human.colin.LR.TLRC-711-2B.111+orig.HEAD"); } catch (FileException& e) { std::cout << "ERROR reading input volume: " << e.whatQString().toAscii().constData() << std::endl; std::exit(-1); } biasCorrectVolume(&volume, 14, 132, 5); try { inputVolume->writeFile("anat_corrected.nii"); //inputVolume->writeFile("colin_corrected.nii"); } catch (FileException& e) { std::cout << "ERROR writing output volume: " << e.whatQString().toAscii().constData() << std::endl; std::exit(-1); } return 0; } */ /*---------------------------------------------------------------------------*/ caret-5.6.4~dfsg.1.orig/caret_uniformize/Simplexx.c0000664000175000017500000002542511572067322022113 0ustar michaelmichael/***************************************************************************** Major portions of this software are copyrighted by the Medical College of Wisconsin, 1994-2000, and are released under the Gnu General Public License, Version 2. See the file README.Copyright for details. ******************************************************************************/ /*---------------------------------------------------------------------------*/ /* This file contains routines for implementing the Simplex algorithm for non-linear optimization to estimate the unknown parameters. The Simplex algorithm is adapted from: A Jump Start Course in C++ Programming File: Simplex.c Author: B. Douglas Ward Date: 28 January 2000 Note: The calling program should include the following statements prior to "#include "Simplex.c" #define DIMENSION p where p = number of parameters to be estimated #include "randgen.c" float calc_error (float * vertex); */ /*---------------------------------------------------------------------------*/ /* Global variables and constants. */ int count = 0; /* count of error evaluations */ int number_restarts = 0; /* count of simplex algorithm restarts */ /*---------------------------------------------------------------------------*/ void allocate_arrays (float *** simplex, float ** centroid, float ** response, float ** step_size, float ** test1, float ** test2) { int i; *centroid = (float *) malloc (sizeof(float) * DIMENSION); *response = (float *) malloc (sizeof(float) * (DIMENSION+1)); *step_size = (float *) malloc (sizeof(float) * DIMENSION); *test1 = (float *) malloc (sizeof(float) * DIMENSION); *test2 = (float *) malloc (sizeof(float) * DIMENSION); *simplex = (float **) malloc (sizeof(float *) * (DIMENSION+1)); for (i = 0; i < DIMENSION+1; i++) (*simplex)[i] = (float *) malloc (sizeof(float) * DIMENSION); } /*---------------------------------------------------------------------------*/ void deallocate_arrays (float *** simplex, float ** centroid, float ** response, float ** step_size, float ** test1, float ** test2) { int i; free (*centroid); *centroid = NULL; free (*response); *response = NULL; free (*step_size); *step_size = NULL; free (*test1); *test1 = NULL; free (*test2); *test2 = NULL; for (i = 0; i < DIMENSION+1; i++) { free ((*simplex)[i]); (*simplex)[i] = NULL; } free (*simplex); *simplex = NULL; } /*---------------------------------------------------------------------------*/ void eval_vertices (float * response, int * worst, int * next, int * best) { int i; /* initialize values */ *worst = 0; *best = 0; /* find the best and worst */ for (i = 1; i < DIMENSION+1; i++) { if (response[i] > response[*worst]) *worst = i; if (response[i] < response[*best]) *best = i; } /* find the next worst index */ if (*worst == 0) *next = 1; else *next = 0; for (i = 0; i < DIMENSION+1; i++) if ((i != *worst) && (response[i] > response[*next])) *next = i; } /*---------------------------------------------------------------------------*/ void restart (float ** simplex, float * response, float * step_size) { const float STEP_FACTOR = 0.9; int i, j; int worst, next, best; float minval, maxval; /* find the current best vertex */ eval_vertices (response, &worst, &next, &best); /* set the first vertex to the current best */ for (i = 0; i < DIMENSION; i++) simplex[0][i] = simplex[best][i]; /* decrease step size */ for (i = 0; i < DIMENSION; i++) step_size[i] *= STEP_FACTOR; /* set up remaining vertices of simplex using new step size */ for (i = 1; i < DIMENSION+1; i++) for (j = 0; j < DIMENSION; j++) { minval = simplex[0][j] - step_size[j]; maxval = simplex[0][j] + step_size[j]; simplex[i][j] = rand_uniform (minval, maxval); } /* initialize response for each vector */ for (i = 0; i < DIMENSION+1; i++) response[i] = calc_error (simplex[i]); } /*---------------------------------------------------------------------------*/ /* Calculate the centroid of the simplex, ignoring the worst vertex. */ void calc_centroid (float ** simplex, int worst, float * centroid) { int i, j; for (i = 0; i < DIMENSION; i++) { centroid[i] = 0.0; /* add each vertex, except the worst */ for (j = 0; j < DIMENSION+1; j++) if (j != worst) centroid[i] += simplex[j][i]; } /* divide by the number of vertices */ for (i = 0; i < DIMENSION; i++) centroid[i] /= DIMENSION; } /*---------------------------------------------------------------------------*/ /* Calculate the reflection of the worst vertex about the centroid. */ void calc_reflection (float ** simplex, float * centroid, int worst, float coef, float * vertex) { int i; for (i = 0; i < DIMENSION; i++) vertex[i] = centroid[i] + coef*(centroid[i] - simplex[worst][i]); } /*---------------------------------------------------------------------------*/ /* Replace a vertex of the simplex. */ void replace (float ** simplex, float * response, int index, float * vertex, float resp) { int i; for (i = 0; i < DIMENSION; i++) simplex[index][i] = vertex[i]; response[index] = resp; } /*---------------------------------------------------------------------------*/ /* Calculate goodness of fit. */ float calc_good_fit (float * response) { int i; float avg, sd, tmp; /* average the response values */ avg = 0.0; for (i = 0; i < DIMENSION+1; i++) avg += response[i]; avg /= DIMENSION+1; /* compute standard deviation of response */ sd = 0.0; for (i = 0; i < DIMENSION+1; i++) { tmp = response[i] - avg; sd += tmp*tmp; } sd /= DIMENSION; return (sqrt(sd)); } /*---------------------------------------------------------------------------*/ /* Perform initialization for the Simplex algorithm. */ void simplex_initialize (float * parameters, float ** simplex, float * response, float * step_size) { int i, j; int worst, next, best; float resp; float minval, maxval; for (j = 0; j < DIMENSION; j++) { simplex[0][j] = parameters[j]; step_size[j] = 0.5 * parameters[j]; } for (i = 1; i < DIMENSION+1; i++) for (j = 0; j < DIMENSION; j++) { minval = simplex[0][j] - step_size[j]; maxval = simplex[0][j] + step_size[j]; simplex[i][j] = rand_uniform (minval, maxval); } for (i = 0; i < DIMENSION+1; i++) response[i] = calc_error (simplex[i]); for (i = 1; i < 500; i++) { for (j = 0; j < DIMENSION; j++) { minval = simplex[0][j] - step_size[j]; maxval = simplex[0][j] + step_size[j]; parameters[j] = rand_uniform (minval, maxval); } resp = calc_error (parameters); eval_vertices (response, &worst, &next, &best); if (resp < response[worst]) replace (simplex, response, worst, parameters, resp); } } /*---------------------------------------------------------------------------*/ /* Use Simplex algorithm to estimate the voxel intensity distribution. The Simplex algorithm is adapted from: A Jump Start Course in C++ Programming */ void simplex_optimization (float * parameters, float * sse) { const int MAX_ITERATIONS = 100; const int MAX_RESTARTS = 25; const float EXPANSION_COEF = 2.0; const float REFLECTION_COEF = 1.0; const float CONTRACTION_COEF = 0.5; const float TOLERANCE = 1.0e-10; float ** simplex = NULL; float * centroid = NULL; float * response = NULL; float * step_size = NULL; float * test1 = NULL; float * test2 = NULL; float resp1, resp2; int i, worst, best, next; int num_iter, num_restarts; int done; float fit; allocate_arrays (&simplex, ¢roid, &response, &step_size, &test1, &test2); simplex_initialize (parameters, simplex, response, step_size); /* start loop to do simplex optimization */ num_iter = 0; num_restarts = 0; done = 0; while (!done) { /* find the worst vertex and compute centroid of remaining simplex, discarding the worst vertex */ eval_vertices (response, &worst, &next, &best); calc_centroid (simplex, worst, centroid); /* reflect the worst point through the centroid */ calc_reflection (simplex, centroid, worst, REFLECTION_COEF, test1); resp1 = calc_error (test1); /* test the reflection against the best vertex and expand it if the reflection is better. if not, keep the reflection */ if (resp1 < response[best]) { /* try expanding */ calc_reflection (simplex, centroid, worst, EXPANSION_COEF, test2); resp2 = calc_error (test2); if (resp2 <= resp1) /* keep expansion */ replace (simplex, response, worst, test2, resp2); else /* keep reflection */ replace (simplex, response, worst, test1, resp1); } else if (resp1 < response[next]) { /* new response is between the best and next worst so keep reflection */ replace (simplex, response, worst, test1, resp1); } else { /* try contraction */ if (resp1 >= response[worst]) calc_reflection (simplex, centroid, worst, -CONTRACTION_COEF, test2); else calc_reflection (simplex, centroid, worst, CONTRACTION_COEF, test2); resp2 = calc_error (test2); /* test the contracted response against the worst response */ if (resp2 > response[worst]) { /* new contracted response is worse, so decrease step size and restart */ num_iter = 0; num_restarts += 1; restart (simplex, response, step_size); } else /* keep contraction */ replace (simplex, response, worst, test2, resp2); } /* test to determine when to stop. first, check the number of iterations */ num_iter += 1; /* increment iteration counter */ if (num_iter >= MAX_ITERATIONS) { /* restart with smaller steps */ num_iter = 0; num_restarts += 1; restart (simplex, response, step_size); } /* limit the number of restarts */ if (num_restarts == MAX_RESTARTS) done = 1; /* compare relative standard deviation of vertex responses against a defined tolerance limit */ fit = calc_good_fit (response); if (fit <= TOLERANCE) done = 1; /* if done, copy the best solution to the output array */ if (done) { eval_vertices (response, &worst, &next, &best); for (i = 0; i < DIMENSION; i++) parameters[i] = simplex[best][i]; *sse = response[best]; } } /* while (!done) */ number_restarts = num_restarts; deallocate_arrays (&simplex, ¢roid, &response, &step_size, &test1, &test2); } /*---------------------------------------------------------------------------*/ caret-5.6.4~dfsg.1.orig/caret_uniformize/Simplex.c0000664000175000017500000007513211572067322021723 0ustar michaelmichael/***************************************************************************** Major portions of this software are copyrighted by the Medical College of Wisconsin, 1994-2000, and are released under the Gnu General Public License, Version 2. See the file README.Copyright for details. ******************************************************************************/ /* This file implements the Simplex algorithm for non-linear optimization. Some routines are adapted from: A Jump Start Course in C++ Programming File: simplex.c Author: B. Douglas Ward Date: 23 May 1997 Mod: Changed random number generator function from rand to drand48. 29 August 1997 */ /*---------------------------------------------------------------------------*/ /* This software is Copyright 1997 by Medical College of Wisconsin 8701 Watertown Plank Road Milwaukee, WI 53226 License is granted to use this program for nonprofit research purposes only. It is specifically against the license to use this program for any clinical application. The Medical College of Wisconsin makes no warranty of usefulness of this program for any particular purpose. The redistribution of this program for a fee, or the derivation of for-profit works from this program is not allowed. */ /*---------------------------------------------------------------------------*/ /* Routine to generate a uniform U(0,1) random variate. */ float uniform () { return ( (float)drand48() ); } /*---------------------------------------------------------------------------*/ /* Routine to generate a normal N(0,1) random variate. */ void normal (float * n1, float * n2) { float u1, u2; float r; u1 = 0.0; while (u1 <= 0.0) { u1 = uniform(); } u2 = uniform(); r = sqrt(-2.0*log(u1)); *n1 = r * cos(2.0*PI*u2); *n2 = r * sin(2.0*PI*u2); } /*---------------------------------------------------------------------------*/ /* Routine to generate a U(a,b) random variate. */ float get_random_value(float a, float b) { float fval; fval = a + uniform() * (b-a); return (fval); } /*---------------------------------------------------------------------------*/ /* Allocate memory for simplex algorithm. */ void allocate_arrays ( int dimension, /* dimension of parameter space */ float *** simplex, /* the simplex itself */ float ** centroid, /* center of mass of the simplex */ float ** response, /* error sum of squares at each vertex */ float ** step_size, /* controls random placement of new vertex */ float ** test1, /* test vertex */ float ** test2 /* test vertex */ ) { int i; *centroid = (float *) malloc (sizeof(float) * dimension); *step_size = (float *) malloc (sizeof(float) * dimension); *test1 = (float *) malloc (sizeof(float) * dimension); *test2 = (float *) malloc (sizeof(float) * dimension); *response = (float *) malloc (sizeof(float) * (dimension+1)); *simplex = (float **) malloc (sizeof(float *) * (dimension+1)); for (i = 0; i < dimension+1; i++) (*simplex)[i] = (float *) malloc (sizeof(float) * dimension); } /*---------------------------------------------------------------------------*/ /* Set up initial values for the simplex vertices. */ void initialize_simplex ( int dimension, /* dimension of the full model */ vfp nmodel, /* pointer to noise model */ vfp smodel, /* pointer to signal model */ int r, /* number of parameters in the noise model */ int p, /* number of parameters in the signal model */ int nabs, /* use absolute constraints for noise parameters */ float * min_nconstr, /* minimum parameter constraints for noise model */ float * max_nconstr, /* maximum parameter constraints for noise model */ float * min_sconstr, /* minimum parameter constraints for signal model */ float * max_sconstr, /* maximum parameter constraints for signal model */ float * par_rdcd, /* estimated parameters for the reduced model */ float * parameters, /* starting point */ float ** simplex, /* the simplex itself */ float * response, /* sse at each vertex of the simplex */ float * step_size, /* amount of allowed variation at each parameter */ int ts_length, /* length of time series array */ float ** x_array, /* independent variable matrix */ float * ts_array /* observed time series */ ) { int i, j; float minval, maxval; /*----- copy parameter vector into first vertex of simplex -----*/ for (i = 0; i < dimension; i++) simplex[0][i] = parameters[i]; /*----- set up initial step sizes -----*/ for (i = 0; i < r; i++) step_size[i] = 0.1 * (max_nconstr[i] - min_nconstr[i]); for (i = r; i < dimension; i++) step_size[i] = 0.1 * (max_sconstr[i-r] - min_sconstr[i-r]); /*----- choose random vectors for remaining vertices -----*/ for (i = 1; i < dimension+1; i++) { /*----- choose noise model parameters -----*/ for (j = 0; j < r; j++) { minval = simplex[0][j] - step_size[j]; if (nabs) /*--- absolute noise parameter constraints ---*/ { if (minval < min_nconstr[j]) minval = min_nconstr[j]; } else /*--- relative noise parameter constraints ---*/ { if (minval < min_nconstr[j] + par_rdcd[j]) minval = min_nconstr[j] + par_rdcd[j]; } maxval = simplex[0][j] + step_size[j]; if (nabs) /*--- absolute noise parameter constraints ---*/ { if (maxval > max_nconstr[j]) maxval = max_nconstr[j]; } else /*--- relative noise parameter constraints ---*/ { if (maxval > max_nconstr[j] + par_rdcd[j]) maxval = max_nconstr[j] + par_rdcd[j]; } simplex[i][j] = get_random_value (minval, maxval); } /*----- choose signal model parameters -----*/ for (j = r; j < dimension; j++) { minval = simplex[0][j] - step_size[j]; if (minval < min_sconstr[j-r]) minval = min_sconstr[j-r]; maxval = simplex[0][j] + step_size[j]; if (maxval > max_sconstr[j-r]) maxval = max_sconstr[j-r]; simplex[i][j] = get_random_value (minval, maxval); } } /*----- calculate and save sse for each vertex of simplex -----*/ for (i = 0; i < dimension+1; i++) response[i] = calc_sse(nmodel, smodel, r, p, nabs, min_nconstr, max_nconstr, min_sconstr, max_sconstr, par_rdcd, simplex[i], ts_length, x_array, ts_array); } /*---------------------------------------------------------------------------*/ /* Evaluate the vertices of the simplex. Find indices of the best, worst, and next-to-worst vertices. */ void eval_vertices ( int dimension, /* dimension of parameter space */ float * response, /* error sum of squares at each vertex */ int * worst, /* index of worst vertex in simplex */ int * next, /* index of next-to-worst vertex in simplex */ int * best /* index of best vertex in simplex */ ) { int i; /* initialize values */ *worst = 0; *best = 0; /* find the best and worst */ for (i = 1; i < dimension+1; i++) { if (response[i] > response[*worst]) *worst = i; if (response[i] < response[*best]) *best = i; } /* find the next worst index */ if (*worst == 0) *next = 1; else *next = 0; for (i = 0; i < dimension+1; i++) if ((i != *worst) && (response[i] > response[*next])) *next = i; } /*---------------------------------------------------------------------------*/ /* Routine to restart the simplex algorithm by putting random vectors into the simplex (and keeping the best previous vertex). */ void restart ( int dimension, /* dimension of the full model */ vfp nmodel, /* pointer to noise model */ vfp smodel, /* pointer to signal model */ int r, /* number of parameters in the noise model */ int p, /* number of parameters in the signal model */ int nabs, /* use absolute constraints for noise parameters */ float * min_nconstr, /* minimum parameter constraints for noise model */ float * max_nconstr, /* maximum parameter constraints for noise model */ float * min_sconstr, /* minimum parameter constraints for signal model */ float * max_sconstr, /* maximum parameter constraints for signal model */ float * par_rdcd, /* estimated parameters for the reduced model */ float ** simplex, /* the simplex itself */ float * response, /* sse at each vertex of the simplex */ float * step_size, /* amount of allowed variation at each parameter */ int ts_length, /* length of time series array */ float ** x_array, /* independent variable matrix */ float * ts_array /* observed time series */ ) { const float STEP_FACTOR = 0.9; int i, j; int worst, next, best; float minval, maxval; /* find the current best vertex */ eval_vertices (dimension, response, &worst, &next, &best); /* set the first vertex to the current best */ for (i = 0; i < dimension; i++) simplex[0][i] = simplex[best][i]; /* decrease step size */ for (i = 0; i < dimension; i++) step_size[i] *= STEP_FACTOR; /* set up remaining vertices of simplex using new step size */ for (i = 1; i < dimension+1; i++) { /*----- choose noise model parameters -----*/ for (j = 0; j < r; j++) { minval = simplex[0][j] - step_size[j]; if (nabs) /*--- absolute noise parameter constraints ---*/ { if (minval < min_nconstr[j]) minval = min_nconstr[j]; } else /*--- relative noise parameter constraints ---*/ { if (minval < min_nconstr[j] + par_rdcd[j]) minval = min_nconstr[j] + par_rdcd[j]; } maxval = simplex[0][j] + step_size[j]; if (nabs) { if (maxval > max_nconstr[j]) maxval = max_nconstr[j]; } else { if (maxval > max_nconstr[j] + par_rdcd[j]) maxval = max_nconstr[j] + par_rdcd[j]; } simplex[i][j] = get_random_value (minval, maxval); } /*----- choose signal model parameters -----*/ for (j = r; j < dimension; j++) { minval = simplex[0][j] - step_size[j]; if (minval < min_sconstr[j-r]) minval = min_sconstr[j-r]; maxval = simplex[0][j] + step_size[j]; if (maxval > max_sconstr[j-r]) maxval = max_sconstr[j-r]; simplex[i][j] = get_random_value (minval, maxval); } } /* initialize response for each vector */ for (i = 0; i < dimension+1; i++) response[i] = calc_sse (nmodel, smodel, r, p, nabs, min_nconstr, max_nconstr, min_sconstr, max_sconstr, par_rdcd, simplex[i], ts_length, x_array, ts_array); } /*---------------------------------------------------------------------------*/ /* Calculate the centroid of the simplex, ignoring the worst vertex. */ void calc_centroid ( int dimension, /* dimension of parameter space */ float ** simplex, /* the simplex itself */ int worst, /* index of worst vertex in simplex */ float * centroid /* center of mass of the simplex minus worst vertex */ ) { int i, j; for (i = 0; i < dimension; i++) { centroid[i] = 0.0; /* add each vertex, except the worst */ for (j = 0; j < dimension+1; j++) if (j != worst) centroid[i] += simplex[j][i]; } /* divide by the number of vertices */ for (i = 0; i < dimension; i++) centroid[i] /= dimension; } /*---------------------------------------------------------------------------*/ /* Calculate the reflection of the worst vertex about the centroid. */ void calc_reflection ( int dimension, /* dimension of parameter space */ float ** simplex, /* the simplex itself */ float * centroid, /* center of mass of the simplex */ int worst, /* index of worst vertex in simplex */ float coef, /* expansion or contraction factor */ float * vertex /* new vertex */ ) { int i; for (i = 0; i < dimension; i++) vertex[i] = centroid[i] + coef*(centroid[i] - simplex[worst][i]); } /*---------------------------------------------------------------------------*/ /* Replace a vertex of the simplex. */ void replace ( int dimension, /* dimension of parameter space */ float ** simplex, /* the simplex itself */ float * response, /* error sum of squares at each vertex */ int index, /* index of vertex to be replaced */ float * vertex, /* new vertex */ float resp /* error sum of squares at new vertex */ ) { int i; for (i = 0; i < dimension; i++) simplex[index][i] = vertex[i]; response[index] = resp; } /*---------------------------------------------------------------------------*/ /* Calculate the goodness of fit. This is measured by the variation in responses at the different vertices relative to the average response. */ float calc_good_fit ( int dimension, /* dimension of parameter space */ float * response /* error sum of squares at each vertex */ ) { int i; float avg, sd, tmp; /*----- average the response values -----*/ avg = 0.0; for (i = 0; i < dimension+1; i++) avg += response[i]; avg /= dimension+1; /*----- compute standard deviation of response -----*/ sd = 0.0; for (i = 0; i < dimension+1; i++) { tmp = response[i] - avg; sd += tmp*tmp; } sd /= dimension; return (sqrt(sd) / avg); } /*---------------------------------------------------------------------------*/ /* Release memory required for simplex optimization. */ void deallocate_arrays ( int dimension, /* dimension of parameter space */ float *** simplex, /* the simplex itself */ float ** centroid, /* center of mass of the simplex */ float ** response, /* error sum of squares at each vertex */ float ** step_size, /* controls random placement of new vertex */ float ** test1, /* test vertex */ float ** test2 /* test vertex */ ) { int iv; /* vertex index */ free (*centroid); *centroid = NULL; free (*response); *response = NULL; free (*step_size); *step_size = NULL; free (*test1); *test1 = NULL; free (*test2); *test2 = NULL; for (iv = 0; iv < dimension+1; iv++) { free ((*simplex)[iv]); (*simplex)[iv] = NULL; } free (*simplex); *simplex = NULL; } /*---------------------------------------------------------------------------*/ /* Implementation of the (non-linear) simplex optimization algorithm. */ void simplex_optimization ( vfp nmodel, /* pointer to noise model */ vfp smodel, /* pointer to signal model */ int r, /* number of parameters in the noise model */ int p, /* number of parameters in the signal model */ float * min_nconstr, /* minimum parameter constraints for noise model */ float * max_nconstr, /* maximum parameter constraints for noise model */ float * min_sconstr, /* minimum parameter constraints for signal model */ float * max_sconstr, /* maximum parameter constraints for signal model */ int nabs, /* use absolute constraints for noise parameters */ int ts_length, /* length of time series array */ float ** x_array, /* independent variable matrix */ float * ts_array, /* observed time series */ float * par_rdcd, /* estimated parameters for the reduced model */ float * parameters, /* estimated parameters */ float * sse /* error sum of squares */ ) { const int MAX_ITERATIONS = 50; /* maximum number of iterations */ const int MAX_RESTARTS = 5; /* maximum number of restarts */ const float EXPANSION_COEF = 2.0; /* expansion coefficient */ const float REFLECTION_COEF = 1.0; /* reflection coefficient */ const float CONTRACTION_COEF = 0.5; /* contraction coefficient */ const float TOLERANCE = 1.0e-4; /* solution convergence tolerance */ float ** simplex = NULL; /* the simplex itself */ float * centroid = NULL; /* center of mass of the simplex */ float * response = NULL; /* error sum of squares at each vertex */ float * step_size = NULL; /* controls random placement of new vertex */ float * test1 = NULL; /* test vertex */ float * test2 = NULL; /* test vertex */ float resp1, resp2; /* error sum of squares for test vertex */ int i; /* vertex index */ int worst; /* index of worst vertex in simplex */ int best; /* index of best vertex in simplex */ int next; /* index of next-to-worst vertex in simplex */ int num_iter; /* number of simplex algorithm iterations */ int num_restarts; /* number of restarts of simplex algorithm */ int done; /* boolean for search finished */ float fit; /* array of fitted time series values */ int dimension; /* dimension of parameter space */ /*----- dimension of parameter space -----*/ dimension = r + p; /*----- allocate memory -----*/ allocate_arrays (dimension, &simplex, ¢roid, &response, &step_size, &test1, &test2); /*----- initialization for simplex algorithm -----*/ initialize_simplex (dimension, nmodel, smodel, r, p, nabs, min_nconstr, max_nconstr, min_sconstr, max_sconstr, par_rdcd, parameters, simplex, response, step_size, ts_length, x_array, ts_array); /* start loop to do simplex optimization */ num_iter = 0; num_restarts = 0; done = 0; while (!done) { /*----- find the worst vertex and compute centroid of remaining simplex, discarding the worst vertex -----*/ eval_vertices (dimension, response, &worst, &next, &best); calc_centroid (dimension, simplex, worst, centroid); /*----- reflect the worst point through the centroid -----*/ calc_reflection (dimension, simplex, centroid, worst, REFLECTION_COEF, test1); resp1 = calc_sse (nmodel, smodel, r, p, nabs, min_nconstr, max_nconstr, min_sconstr, max_sconstr, par_rdcd, test1, ts_length, x_array, ts_array); /*----- test the reflection against the best vertex and expand it if the reflection is better. if not, keep the reflection -----*/ if (resp1 < response[best]) { /*----- try expanding -----*/ calc_reflection (dimension, simplex, centroid, worst, EXPANSION_COEF, test2); resp2 = calc_sse (nmodel, smodel, r, p, nabs, min_nconstr, max_nconstr, min_sconstr, max_sconstr, par_rdcd, test2, ts_length, x_array, ts_array); if (resp2 <= resp1) /* keep expansion */ replace (dimension, simplex, response, worst, test2, resp2); else /* keep reflection */ replace (dimension, simplex, response, worst, test1, resp1); } else if (resp1 < response[next]) { /*----- new response is between the best and next worst so keep reflection -----*/ replace (dimension, simplex, response, worst, test1, resp1); } else { /*----- try contraction -----*/ if (resp1 >= response[worst]) calc_reflection (dimension, simplex, centroid, worst, -CONTRACTION_COEF, test2); else calc_reflection (dimension, simplex, centroid, worst, CONTRACTION_COEF, test2); resp2 = calc_sse (nmodel, smodel, r, p, nabs, min_nconstr, max_nconstr, min_sconstr, max_sconstr, par_rdcd, test2, ts_length, x_array, ts_array); /*---- test the contracted response against the worst response ----*/ if (resp2 > response[worst]) { /*----- new contracted response is worse, so decrease step size and restart -----*/ num_iter = 0; num_restarts += 1; restart (dimension, nmodel, smodel, r, p, nabs, min_nconstr, max_nconstr, min_sconstr, max_sconstr, par_rdcd, simplex, response, step_size, ts_length, x_array, ts_array); } else /*----- keep contraction -----*/ replace (dimension, simplex, response, worst, test2, resp2); } /*----- test to determine when to stop. first, check the number of iterations -----*/ num_iter += 1; /*----- increment iteration counter -----*/ if (num_iter >= MAX_ITERATIONS) { /*----- restart with smaller steps -----*/ num_iter = 0; num_restarts += 1; restart (dimension, nmodel, smodel, r, p, nabs, min_nconstr, max_nconstr, min_sconstr, max_sconstr, par_rdcd, simplex, response, step_size, ts_length, x_array, ts_array); } /*----- limit the number of restarts -----*/ if (num_restarts == MAX_RESTARTS) done = 1; /*----- compare relative standard deviation of vertex responses against a defined tolerance limit -----*/ fit = calc_good_fit (dimension, response); if (fit <= TOLERANCE) done = 1; /*----- if done, copy the best solution to the output array -----*/ if (done) { eval_vertices (dimension, response, &worst, &next, &best); for (i = 0; i < dimension; i++) parameters[i] = simplex[best][i]; *sse = response[best]; } } /*----- while (!done) -----*/ deallocate_arrays (dimension, &simplex, ¢roid, &response, &step_size, &test1, &test2); } /*----------------------------------------------------------------------------*/ /******************************************************************************/ /***** Powell's NEWUOA Method (instead of Nelder-Mead) - cf. powell_int.c *****/ /******************************************************************************/ /*----------------------------------------------------------------------------*/ static int N_newuoa = 0 ; /* indicates if NEWUOA method is to be used */ static vfp N_nmodel , N_smodel ; static int N_r , N_p , N_nabs, N_ts_length ; static float *N_min_nconstr , *N_max_nconstr ; static float *N_min_sconstr , *N_max_sconstr ; static float **N_x_array ; static float *N_ts_array , *N_par_rdcd ; static float *N_pbot , *N_psiz ; static float *N_pv ; #ifdef SOLARIS #define floorf floor /* is Solaris lame, or what? */ #endif /* Macro to periodically reduce a float variable into the range 0..1: for example: PRED01(1.2) == 0.8, PRED01(1.8) == 0.2, et cetera; graphically PRED01(x)| | /\ /\ /\ /\ /\ |/ \ / \ / \ / \ / | \ / \ / \ / \ / | \/ \/ \/ \/ +------------------------------------> x -3 -2 -1 0 +1 +2 +3 +4 +5 */ #undef PRED01 #define PRED01(x) fabsf( (x) - 2.0f*floorf(0.5f*((x)+1.0f)) ) /* double precision version of the above */ #undef DRED01 #define DRED01(x) fabs ( (x) - 2.0 *floor (0.5 *((x)+1.0 )) ) /*----------------------------------------------------------------------------*/ double newfunc( int np , double *pv ) /* parameters are scaled to [0,1] */ { double val ; int ii ; float x,y ; for( ii=0 ; ii < np ; ii++ ){ x = (float)pv[ii] ; if( x < 0.0f || x > 1.0f ) x = PRED01(x); /* reduce to [0,1] range */ N_pv[ii] = N_pbot[ii] + N_psiz[ii] * x ; /* scale to true value */ } /* compute sum of squares between model fit and data */ val = (double) calc_sse( N_nmodel, N_smodel, N_r, N_p, N_nabs, N_min_nconstr, N_max_nconstr, N_min_sconstr, N_max_sconstr, N_par_rdcd, N_pv , N_ts_length, N_x_array, N_ts_array ) ; return val ; } /*----------------------------------------------------------------------------*/ static double N_rstart=0.04 ; static double N_rend =0.0005 ; static int N_maxit =9999 ; static void set_newuoa_parm( double rs , double re , int mm ) { if( rs > re && re > 0.0 && mm > 9 ){ N_rstart = rs ; N_rend = re ; N_maxit = mm ; } else { N_rstart = 0.04 ; N_rend = 0.0005 ; N_maxit = 9999 ; } } /*----------------------------------------------------------------------------*/ /*! Supposed to be a dropin replacement for simplex_optimization(). ------------------------------------------------------------------------------*/ void newuoa_optimization ( vfp nmodel, /* pointer to noise model */ vfp smodel, /* pointer to signal model */ int r, /* number of parameters in the noise model */ int p, /* number of parameters in the signal model */ float * min_nconstr, /* minimum parameter constraints for noise model */ float * max_nconstr, /* maximum parameter constraints for noise model */ float * min_sconstr, /* minimum parameter constraints for signal model */ float * max_sconstr, /* maximum parameter constraints for signal model */ int nabs, /* use absolute constraints for noise parameters */ int ts_length, /* length of time series array */ float ** x_array, /* independent variable matrix */ float * ts_array, /* observed time series */ float * par_rdcd, /* estimated parameters for the reduced model */ float * parameters, /* estimated parameters */ float * sse /* error sum of squares */ ) { double *dv ; int ii ; N_nmodel = nmodel ; N_smodel = smodel ; N_r = r ; N_p = p ; N_min_nconstr = min_nconstr ; N_max_nconstr = max_nconstr ; N_min_sconstr = min_sconstr ; N_max_sconstr = max_sconstr ; N_nabs = nabs ; N_ts_length = ts_length ; N_x_array = x_array ; N_ts_array = ts_array ; N_par_rdcd = par_rdcd ; N_pv = (float *) malloc(sizeof(float) *(r+p)) ; N_pbot = (float *) malloc(sizeof(float) *(r+p)) ; N_psiz = (float *) malloc(sizeof(float) *(r+p)) ; dv = (double *)malloc(sizeof(double)*(r+p)) ; /* set N_pbot = min allowed values N_psiz = max-min = size of allowed values range */ if( nabs ){ for( ii=0 ; ii < r ; ii++ ){ N_pbot[ii] = min_nconstr[ii] ; N_psiz[ii] = max_nconstr[ii] - min_nconstr[ii] ; } } else { for( ii=0 ; ii < r ; ii++ ){ N_pbot[ii] = min_nconstr[ii] + par_rdcd[ii] ; N_psiz[ii] = max_nconstr[ii] - min_nconstr[ii] ; } } for( ii=0 ; ii < p ; ii++ ){ N_pbot[ii+r] = min_sconstr[ii] ; N_psiz[ii+r] = max_sconstr[ii] - min_sconstr[ii] ; } /* scale all parameters into the range [0,1]; NEWUOA will operate on these, since it is scale-free */ for( ii=0 ; ii < r+p ; ii++ ){ dv[ii] = (double) ((parameters[ii]-N_pbot[ii])/N_psiz[ii]); if( dv[ii] < 0.0 || dv[ii] > 0.0 ) dv[ii] = DRED01(dv[ii]); /* 03 Nov 2006 */ } powell_newuoa( r+p , dv , N_rstart , N_rend , N_maxit , newfunc ) ; *sse = (float)newfunc( r+p , dv ) ; for( ii=0 ; ii < r+p ; ii++ ){ if( dv[ii] < 0.0 || dv[ii] > 0.0 ) dv[ii] = DRED01(dv[ii]); /* 03 Nov 2006 */ parameters[ii] = (float)( N_pbot[ii] + N_psiz[ii]*dv[ii] ); } free((void *)dv) ; free((void *)N_pbot) ; free((void *)N_psiz) ; free((void *)N_pv) ; return ; } /*----------------------------------------------------------------------------*/ #define WIN_SIM 1 #define WIN_POW 2 #define WIN_STP 3 static int opt_winner ; /*----------------------------------------------------------------------------*/ /*! Chooses which optimization function(s) to call. ------------------------------------------------------------------------------*/ void generic_optimization ( vfp nmodel, /* pointer to noise model */ vfp smodel, /* pointer to signal model */ int r, /* number of parameters in the noise model */ int p, /* number of parameters in the signal model */ float * min_nconstr, /* minimum parameter constraints for noise model */ float * max_nconstr, /* maximum parameter constraints for noise model */ float * min_sconstr, /* minimum parameter constraints for signal model */ float * max_sconstr, /* maximum parameter constraints for signal model */ int nabs, /* use absolute constraints for noise parameters */ int ts_length, /* length of time series array */ float ** x_array, /* independent variable matrix */ float * ts_array, /* observed time series */ float * par_rdcd, /* estimated parameters for the reduced model */ float * parameters, /* estimated parameters */ float * sse /* error sum of squares */ ) { float *powv , *simv , spow=1.e+33 , ssim=1.e+33 ; int dopow = (N_newuoa > 0) ; int dosim = (N_newuoa == 2 || N_newuoa == 0) ; int stp=0 ; if( dopow && dosim ){ powv = (float *)malloc(sizeof(float)*(r+p)) ; simv = (float *)malloc(sizeof(float)*(r+p)) ; memcpy(powv,parameters,sizeof(float)*(r+p)) ; memcpy(simv,parameters,sizeof(float)*(r+p)) ; } else { powv = simv = parameters ; } if( dosim ){ /* Simplex from same start pt */ simplex_optimization(nmodel, smodel, r, p, min_nconstr, max_nconstr, min_sconstr, max_sconstr, nabs, ts_length, x_array, ts_array, par_rdcd, simv, &ssim ); if( dopow ){ float *qv = (float *)malloc(sizeof(float)*(r+p)) , qs=1.e+33 ; memcpy(qv,simv,sizeof(float)*(r+p)) ; set_newuoa_parm( 0.01 , 0.0009 , 666 ) ; /* touchup with NEWUOA */ newuoa_optimization(nmodel, smodel, r, p, min_nconstr, max_nconstr, min_sconstr, max_sconstr, nabs, ts_length, x_array, ts_array, par_rdcd, qv, &qs ); if( qs < ssim ){ memcpy(simv,qv,sizeof(float)*(r+p)) ; ssim = qs ; stp = 1 ; } free((void*)qv) ; } } if( dopow ){ /* NEWUOA from same start pt */ set_newuoa_parm( 0.0 , 0.0 , 0 ) ; /* default settings for NEWUOA */ newuoa_optimization (nmodel, smodel, r, p, min_nconstr, max_nconstr, min_sconstr, max_sconstr, nabs, ts_length, x_array, ts_array, par_rdcd, powv , &spow ); } opt_winner = 0 ; if( dopow && dosim ){ if( spow < ssim ) memcpy(parameters,powv,sizeof(float)*(r+p)) ; else memcpy(parameters,simv,sizeof(float)*(r+p)) ; free((void *)simv); free((void *)powv); opt_winner = (spow < ssim) ? WIN_POW : (stp) ? WIN_STP : WIN_SIM ; } *sse = (spow < ssim) ? spow : ssim ; } caret-5.6.4~dfsg.1.orig/caret_uniformize/.project0000664000175000017500000000437511572067322021606 0ustar michaelmichael caret_uniformize org.eclipse.cdt.managedbuilder.core.genmakebuilder clean,full,incremental, ?name? org.eclipse.cdt.make.core.append_environment true org.eclipse.cdt.make.core.autoBuildTarget all org.eclipse.cdt.make.core.buildArguments org.eclipse.cdt.make.core.buildCommand make org.eclipse.cdt.make.core.cleanBuildTarget clean org.eclipse.cdt.make.core.contents org.eclipse.cdt.make.core.activeConfigSettings org.eclipse.cdt.make.core.enableAutoBuild false org.eclipse.cdt.make.core.enableCleanBuild true org.eclipse.cdt.make.core.enableFullBuild true org.eclipse.cdt.make.core.fullBuildTarget all org.eclipse.cdt.make.core.stopOnError true org.eclipse.cdt.make.core.useDefaultBuildCmd true org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder org.eclipse.cdt.core.cnature org.eclipse.cdt.core.ccnature org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature caret-5.6.4~dfsg.1.orig/caret_uniformize/.cproject0000664000175000017500000002074211572067322021745 0ustar michaelmichael make all true true true caret-5.6.4~dfsg.1.orig/caret_statistics/0000775000175000017500000000000011572067322020131 5ustar michaelmichaelcaret-5.6.4~dfsg.1.orig/caret_statistics/caret_statistics.pro0000664000175000017500000000522011572067322024222 0ustar michaelmichael###################################################################### # Automatically generated by qmake (1.04a) Wed Jan 15 08:28:52 2003 ###################################################################### TARGET = CaretStatistics CONFIG += staticlib INCLUDEPATH += . include(../caret_qmake_include.pro) !vs:TEMPLATE = lib vs:TEMPLATE=vclib dll { CONFIG -= staticlib CONFIG += plugin } # turn off unicode for displaying windows web browser win32 { DEFINES -= UNICODE } # Input HEADERS += \ StatisticAlgorithm.h \ StatisticAnovaOneWay.h \ StatisticAnovaTwoWay.h \ StatisticConvertToZScore.h \ StatisticCorrelationCoefficient.h \ StatisticDataGroup.h \ StatisticDcdflib.h \ StatisticDescriptiveStatistics.h \ StatisticException.h \ StatisticFalseDiscoveryRate.h \ StatisticGeneratePValue.h \ StatisticHistogram.h \ StatisticKruskalWallis.h \ StatisticLeveneVarianceEquality.h \ StatisticLinearRegression.h \ StatisticMatrix.h \ StatisticMeanAndDeviation.h \ StatisticMultipleRegression.h \ StatisticNormalizeDistribution.h \ StatisticNumericalRecipes.h \ StatisticPermutation.h \ StatisticRandomNumber.h \ StatisticRandomNumberOperator.h \ StatisticRankTransformation.h \ StatisticTestNames.h \ StatisticTtestOneSample.h \ StatisticTtestPaired.h \ StatisticTtestTwoSample.h \ StatisticUnitTesting.h \ StatisticValueIndexSort.h \ StatisticVtkMath.h SOURCES += \ StatisticAlgorithm.cxx \ StatisticAnovaOneWay.cxx \ StatisticAnovaTwoWay.cxx \ StatisticConvertToZScore.cxx \ StatisticCorrelationCoefficient.cxx \ StatisticDataGroup.cxx \ StatisticDcdflib.cxx \ StatisticDcdflibIpmpar.cxx \ StatisticDescriptiveStatistics.cxx \ StatisticException.cxx \ StatisticFalseDiscoveryRate.cxx \ StatisticGeneratePValue.cxx \ StatisticHistogram.cxx \ StatisticKruskalWallis.cxx \ StatisticLeveneVarianceEquality.cxx \ StatisticLinearRegression.cxx \ StatisticMatrix.cxx \ StatisticMeanAndDeviation.cxx \ StatisticMultipleRegression.cxx \ StatisticNormalizeDistribution.cxx \ StatisticNumericalRecipes.cxx \ StatisticPermutation.cxx \ StatisticRandomNumber.cxx \ StatisticRandomNumberOperator.cxx \ StatisticRankTransformation.cxx \ StatisticTestNames.cxx \ StatisticTtestOneSample.cxx \ StatisticTtestPaired.cxx \ StatisticTtestTwoSample.cxx \ StatisticUnitTesting.cxx \ StatisticValueIndexSort.cxx \ StatisticVtkMath.cxx caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticVtkMath.h0000664000175000017500000000532011572067322023550 0ustar michaelmichael #ifndef __STATISTIC_VTK_MATH_H__ #define __STATISTIC_VTK_MATH_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ /*========================================================================= Program: Visualization Toolkit Module: $RCSfile: StatisticVtkMath.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. =========================================================================*/ /// stuff taken from vtkMath class StatisticVtkMath { public: // Description: // Thread safe version of InvertMatrix method. // Working memory arrays tmp1SIze and tmp2Size // of length size must be passed in. static int InvertMatrix(double **A, double **AI, int size, int *tmp1Size, double *tmp2Size); // Description: // Thread safe version of LUFactorLinearSystem method. // Working memory array tmpSize of length size // must be passed in. static int LUFactorLinearSystem(double **A, int *index, int size, double *tmpSize); // Description: // Solve linear equations Ax = b using LU decomposition A = LU where L is // lower triangular matrix and U is upper triangular matrix. Input is // factored matrix A=LU, integer array of pivot indices index[0->n-1], // load vector x[0->n-1], and size of square matrix n. Note that A=LU and // index[] are generated from method LUFactorLinearSystem). Also, solution // vector is written directly over input load vector. static void LUSolveLinearSystem(double **A, int *index, double *x, int size); }; #endif // __STATISTIC_VTK_MATH_H__ caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticVtkMath.cxx0000664000175000017500000001437211572067322024132 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ /*========================================================================= Program: Visualization Toolkit Module: $RCSfile: StatisticVtkMath.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 "StatisticVtkMath.h" #define VTK_SMALL_NUMBER 1.0e-12 // Invert input square matrix A into matrix AI. Note that A is modified during // the inversion. The size variable is the dimension of the matrix. Returns 0 // if inverse not computed. // ----------------------- // For thread safe behavior, temporary arrays tmp1SIze and tmp2Size // of length size must be passsed in. int StatisticVtkMath::InvertMatrix(double **A, double **AI, int size, int *tmp1Size, double *tmp2Size) { int i, j; // // Factor matrix; then begin solving for inverse one column at a time. // Note: tmp1Size returned value is used later, tmp2Size is just working // memory whose values are not used in LUSolveLinearSystem // if ( StatisticVtkMath::LUFactorLinearSystem(A, tmp1Size, size, tmp2Size) == 0 ) { return 0; } for ( j=0; j < size; j++ ) { for ( i=0; i < size; i++ ) { tmp2Size[i] = 0.0; } tmp2Size[j] = 1.0; StatisticVtkMath::LUSolveLinearSystem(A,tmp1Size,tmp2Size,size); for ( i=0; i < size; i++ ) { AI[i][j] = tmp2Size[i]; } } return 1; } // Factor linear equations Ax = b using LU decompostion A = LU where L is // lower triangular matrix and U is upper triangular matrix. Input is // square matrix A, integer array of pivot indices index[0->n-1], and size // of square matrix n. Output factorization LU is in matrix A. If error is // found, method returns 0. //------------------------------------------------------------------ // For thread safe, temporary memory array tmpSize of length size // must be passed in. int StatisticVtkMath::LUFactorLinearSystem(double **A, int *index, int size, double *tmpSize) { int i, j, k; int maxI = 0; double largest, temp1, temp2, sum; // // Loop over rows to get implicit scaling information // for ( i = 0; i < size; i++ ) { for ( largest = 0.0, j = 0; j < size; j++ ) { if ( (temp2 = fabs(A[i][j])) > largest ) { largest = temp2; } } if ( largest == 0.0 ) { //vtkGenericWarningMacro(<<"Unable to factor linear system"); return 0; } tmpSize[i] = 1.0 / largest; } // // Loop over all columns using Crout's method // for ( j = 0; j < size; j++ ) { for (i = 0; i < j; i++) { sum = A[i][j]; for ( k = 0; k < i; k++ ) { sum -= A[i][k] * A[k][j]; } A[i][j] = sum; } // // Begin search for largest pivot element // for ( largest = 0.0, i = j; i < size; i++ ) { sum = A[i][j]; for ( k = 0; k < j; k++ ) { sum -= A[i][k] * A[k][j]; } A[i][j] = sum; if ( (temp1 = tmpSize[i]*fabs(sum)) >= largest ) { largest = temp1; maxI = i; } } // // Check for row interchange // if ( j != maxI ) { for ( k = 0; k < size; k++ ) { temp1 = A[maxI][k]; A[maxI][k] = A[j][k]; A[j][k] = temp1; } tmpSize[maxI] = tmpSize[j]; } // // Divide by pivot element and perform elimination // index[j] = maxI; if ( fabs(A[j][j]) <= VTK_SMALL_NUMBER ) { //vtkGenericWarningMacro(<<"Unable to factor linear system"); return 0; } if ( j != (size-1) ) { temp1 = 1.0 / A[j][j]; for ( i = j + 1; i < size; i++ ) { A[i][j] *= temp1; } } } return 1; } //---------------------------------------------------------------------------- // Solve linear equations Ax = b using LU decompostion A = LU where L is // lower triangular matrix and U is upper triangular matrix. Input is // factored matrix A=LU, integer array of pivot indices index[0->n-1], // load vector x[0->n-1], and size of square matrix n. Note that A=LU and // index[] are generated from method LUFactorLinearSystem). Also, solution // vector is written directly over input load vector. void StatisticVtkMath::LUSolveLinearSystem(double **A, int *index, double *x, int size) { int i, j, ii, idx; double sum; // // Proceed with forward and backsubstitution for L and U // matrices. First, forward substitution. // for ( ii = -1, i = 0; i < size; i++ ) { idx = index[i]; sum = x[idx]; x[idx] = x[i]; if ( ii >= 0 ) { for ( j = ii; j <= (i-1); j++ ) { sum -= A[i][j]*x[j]; } } else if (sum) { ii = i; } x[i] = sum; } // // Now, back substitution // for ( i = size-1; i >= 0; i-- ) { sum = x[i]; for ( j = i + 1; j < size; j++ ) { sum -= A[i][j]*x[j]; } x[i] = sum / A[i][i]; } } #undef VTK_SMALL_NUMBER caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticValueIndexSort.h0000664000175000017500000000437411572067322025116 0ustar michaelmichael #ifndef __STATISTIC_VALUE_INDEX_SORT_H__ #define __STATISTIC_VALUE_INDEX_SORT_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "StatisticAlgorithm.h" /// sort one array of values but also provided original index for each sorted value class StatisticValueIndexSort : public StatisticAlgorithm { public: // Constructor StatisticValueIndexSort(); // Destructor ~StatisticValueIndexSort(); // execute the algorithm void execute() throw (StatisticException); // get number of value index pairs int getNumberOfItems() const; // get value and original index for an item void getValueAndOriginalIndex(const int itemNum, int& indexOut, float& valueOut) const; protected: /// class for storing names and indices class ValueIndexPair { public: /// constructor ValueIndexPair(const int indexIn, const float valueIn); /// the value float value; /// the index int indx; /// less than operator bool operator<(const ValueIndexPair& vip) const; }; /// the value and indices std::vector values; }; #endif // __STATISTIC_VALUE_INDEX_SORT_H__ caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticValueIndexSort.cxx0000664000175000017500000000523411572067322025465 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "StatisticDataGroup.h" #include "StatisticValueIndexSort.h" /** * Constructor. */ StatisticValueIndexSort::StatisticValueIndexSort() : StatisticAlgorithm("Value-Index Sort") { } /** * Constructor. */ StatisticValueIndexSort::~StatisticValueIndexSort() { } /** * execute the algorithm. */ void StatisticValueIndexSort::execute() throw (StatisticException) { // // Verify the input data group // if (getNumberOfDataGroups() != 1) { throw StatisticException("Value/Indx Sort only allows one data group."); } const StatisticDataGroup* sdg = getDataGroup(0); const int numValues = sdg->getNumberOfData(); if (numValues <= 0) { throw StatisticException("Value/Indx Sort data group has no values"); } // // Get the data and sort it // values.clear(); for (int i = 0; i < numValues; i++) { values.push_back(ValueIndexPair(i, sdg->getData(i))); } std::sort(values.begin(), values.end()); } /** * get number of value indice pairs. */ int StatisticValueIndexSort::getNumberOfItems() const { return values.size(); } /** * get value and index for an item. */ void StatisticValueIndexSort::getValueAndOriginalIndex(const int itemNum, int& indexOut, float& valueOut) const { indexOut = values[itemNum].indx; valueOut = values[itemNum].value; } /** * constructor. */ StatisticValueIndexSort::ValueIndexPair::ValueIndexPair(const int indexIn, const float valueIn) { indx = indexIn; value = valueIn; } /** * less than operator. */ bool StatisticValueIndexSort::ValueIndexPair::operator<(const ValueIndexPair& nip) const { return (value < nip.value); } caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticUnitTesting.h0000664000175000017500000001155711572067322024460 0ustar michaelmichael #ifndef __STATISTIC_UNIT_TESTING_H__ #define __STATISTIC_UNIT_TESTING_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "StatisticAlgorithm.h" class StatisticMatrix; /// class that performs unit testing of the statistical routines class StatisticUnitTesting : public StatisticAlgorithm { public: // constructor StatisticUnitTesting(const bool printTestValuesFlagIn); // destructor ~StatisticUnitTesting(); // run the tests void execute() throw (StatisticException); /// get problems occurred during testing bool getProblemsOccurredDuringTesting() const { return problemFlag; } protected: // verify that two floating point numbers are nearly identical (false if ok) bool verify(const std::string& testName, const float computedValue, const float correctValue, const float acceptableDifference = 0.001); // verify that two matrices numbers are nearly identical (false if ok) bool verify(const std::string& testName, const StatisticMatrix& computedMatrix, const StatisticMatrix& correctMatrix, const float acceptableDifference = 0.001); // verify that a group of coefficients are nearly identical (false if ok) bool verifyCoefficients(const std::string& testName, const std::vector& computedCoefficients, const std::vector& correctCoefficients, const float acceptableDifference = 0.001); // test mean, variance, deviation bool testStatisticMeanAndDeviation(); /// test descriptive statistics bool testStatisticDescriptive(); // test one-sample T-Test bool testStatisticTtestOneSample(); // test Paired T-Test. bool testStatisticTtestPaired(); // test two-sample T-Test with pooled variance bool testStatisticTtestTwoSamplePooledVariance(); // test two-sample T-Test with unpooled variance bool testStatisticTtestTwoSampleUnpooledVariance(); // test one-way ANOVA bool testStatisticAnovaOneWay(); // test two-way fixed-effect ANOVA bool testStatisticAnovaTwoWayFixedEffectCase1(); // test two-way fixed-effect ANOVA bool testStatisticAnovaTwoWayFixedEffectCase2(); // test two-way random-effect ANOVA bool testStatisticAnovaTwoWayRandomEffect(); // test two-way mixed-effect ANOVA bool testStatisticAnovaTwoWayMixedEffect(); // test convert to z-score bool testConvertToZScore(); // test correlation coefficient bool testCorrelationCoefficient(); // test false discovery rate bool testFalseDiscoveryRate(); // test histogram bool testHistogram(); // test kruskal-wallis non-parameteric anova bool testKruskalWallis(); // test levene's test bool testLevenesTest(); // test linear regression bool testLinearRegression(); // test matrix operations bool testMatrixOperations(); // test multiple linear regression bool testMultipleLinearRegression(); // test normalization of a distribution of sorted values bool testNormalizeDistributionSorted(); // test normalization of a distribution of unsorted values bool testNormalizeDistributionUnsorted(); // test rank transformation bool testRankTransformation(); // test permutation random shuffle bool testPermutationRandomShuffle(); // test permutation sign flipping bool testPermutationSignFlipping(); // test value/index sorting bool testValueIndexSort(); // problems encountered in testing bool problemFlag; // print test values even if correct bool printTestValuesFlag; }; #endif // __STATISTIC_UNIT_TESTING_H__ caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticUnitTesting.cxx0000664000175000017500000026405711572067322025040 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include "StatisticAnovaOneWay.h" #include "StatisticAnovaTwoWay.h" #include "StatisticConvertToZScore.h" #include "StatisticCorrelationCoefficient.h" #include "StatisticDataGroup.h" #include "StatisticDescriptiveStatistics.h" #include "StatisticException.h" #include "StatisticFalseDiscoveryRate.h" #include "StatisticHistogram.h" #include "StatisticKruskalWallis.h" #include "StatisticLeveneVarianceEquality.h" #include "StatisticLinearRegression.h" #include "StatisticMatrix.h" #include "StatisticMeanAndDeviation.h" #include "StatisticMultipleRegression.h" #include "StatisticNormalizeDistribution.h" #include "StatisticPermutation.h" #include "StatisticRankTransformation.h" #include "StatisticRandomNumber.h" #include "StatisticTtestOneSample.h" #include "StatisticTtestPaired.h" #include "StatisticTtestTwoSample.h" #include "StatisticUnitTesting.h" #include "StatisticValueIndexSort.h" /** * constructor. */ StatisticUnitTesting::StatisticUnitTesting(const bool printTestValuesFlagIn) : StatisticAlgorithm("Unit Testing") { printTestValuesFlag = printTestValuesFlagIn; } /** * destructor. */ StatisticUnitTesting::~StatisticUnitTesting() { } /** * run the tests. */ void StatisticUnitTesting::execute() throw (StatisticException) { problemFlag = false; std::cout << std::endl; problemFlag |= testStatisticAnovaOneWay(); std::cout << std::endl; problemFlag |= testStatisticAnovaTwoWayFixedEffectCase1(); std::cout << std::endl; problemFlag |= testStatisticAnovaTwoWayFixedEffectCase2(); std::cout << std::endl; problemFlag |= testStatisticAnovaTwoWayRandomEffect(); std::cout << std::endl; problemFlag |= testStatisticAnovaTwoWayMixedEffect(); std::cout << std::endl; problemFlag |= testConvertToZScore(); std::cout << std::endl; problemFlag |= testCorrelationCoefficient(); std::cout << std::endl; problemFlag |= testStatisticDescriptive(); std::cout << std::endl; problemFlag |= testFalseDiscoveryRate(); std::cout << std::endl; problemFlag |= testHistogram(); std::cout << std::endl; problemFlag |= testKruskalWallis(); std::cout << std::endl; problemFlag |= testLevenesTest(); std::cout << std::endl; problemFlag |= testLinearRegression(); std::cout << std::endl; problemFlag |= testMatrixOperations(); std::cout << std::endl; problemFlag |= testMultipleLinearRegression(); std::cout << std::endl; problemFlag |= testNormalizeDistributionSorted(); std::cout << std::endl; problemFlag |= testNormalizeDistributionUnsorted(); std::cout << std::endl; problemFlag |= testStatisticMeanAndDeviation(); std::cout << std::endl; problemFlag |= testPermutationRandomShuffle(); std::cout << std::endl; problemFlag |= testPermutationSignFlipping(); std::cout << std::endl; problemFlag |= testRankTransformation(); std::cout << std::endl; problemFlag |= testStatisticTtestOneSample(); std::cout << std::endl; problemFlag |= testStatisticTtestPaired(); std::cout << std::endl; problemFlag |= testStatisticTtestTwoSamplePooledVariance(); std::cout << std::endl; problemFlag |= testStatisticTtestTwoSampleUnpooledVariance(); std::cout << std::endl; problemFlag |= testValueIndexSort(); std::cout << std::endl; if (problemFlag == false) { std::cout << "SUCCESSFUL Statistic Unit Test." << std::endl; } else { std::cout << "FAILURES in Statistic Unit Test." << std::endl; } std::cout << std::endl; } /** * test value/index sorting. */ bool StatisticUnitTesting::testValueIndexSort() { const int numData = 10; const float data[numData] = { 3, 5, 7, 2, 4, 9, 1, 13, 12, 6 }; const float dataSorted[numData] = { 1, 2, 3, 4, 5, 6, 7, 9, 12, 13 }; const float indicesSorted[numData] = { 6, 3, 0, 4, 1, 9, 2, 5, 8, 7 }; StatisticValueIndexSort vis; vis.addDataArray(data, numData); try { vis.execute(); } catch (StatisticException& e) { std::cout << "FAILED StatisticValueIndexSort threw exception: " << e.whatStdString() << std::endl; return true; } if (vis.getNumberOfItems() != numData) { std::cout << "FAILED StatisticValueIndexSort number of output items should be " << numData << " but is " << vis.getNumberOfItems() << std::endl; return true; } bool problem = false; for (int i = 0; i < numData; i++) { int indx; float value; vis.getValueAndOriginalIndex(i, indx, value); problem |= verify("StatisticValueIndexSort value " + StatisticAlgorithm::numberToString(i), value, dataSorted[i]); problem |= verify("StatisticValueIndexSort original index " + StatisticAlgorithm::numberToString(i), indx, indicesSorted[i]); } if (problem == false) { std::cout << "PASSED StatisticValueIndexSort" << std::endl; } return problem; } /** * test descriptive statistics. */ bool StatisticUnitTesting::testStatisticDescriptive() { // // Data from page 43, table 2-2, Statistics For Psychology, 2nd, Aron & Aron // const int numData = 10; const float data[numData] = { 7.0, 8.0, 8.0, 7.0, 3.0, 1.0, 6.0, 9.0, 3.0, 8.0 }; StatisticDescriptiveStatistics sds; sds.addDataArray(data, numData); try { sds.execute(); } catch (StatisticException& e) { std::cout << "FAILED StatisticDescriptiveStatistics threw exception: " << e.whatStdString() << std::endl; return true; } bool problem = false; problem |= verify("StatisticDescriptiveStatistics SumOfSquares", sds.getSumOfSquares(), 66.0); problem |= verify("StatisticDescriptiveStatistics Mean", sds.getMean(), 6.0); problem |= verify("StatisticDescriptiveStatistics Variance", sds.getVariance(), 6.6); problem |= verify("StatisticDescriptiveStatistics Population Sample Variance", sds.getPopulationSampleVariance(), 7.333333); problem |= verify("StatisticDescriptiveStatistics Standard Deviation", sds.getStandardDeviation(), 2.57); problem |= verify("StatisticDescriptiveStatistics Population Sample Standard Deviation", sds.getPopulationSampleStandardDeviation(), 2.708); problem |= verify("StatisticDescriptiveStatistics Root Mean Square", sds.getRootMeanSquare(), 6.52687); problem |= verify("StatisticDescriptiveStatistics Standard Error of the Mean", sds.getStandardErrorOfTheMean(), 0.856349); float minValue, maxValue; sds.getMinimumAndMaximum(minValue, maxValue); problem |= verify("StatisticDescriptiveStatistics Minimum Value", minValue, 1.0); problem |= verify("StatisticDescriptiveStatistics Maximum Value", maxValue, 9.0); problem |= verify("StatisticDescriptiveStatistics Median", sds.getMedian(), 7.0); problem |= verify("StatisticDescriptiveStatistics Skewness", sds.getSkewness(), -0.784397); problem |= verify("StatisticDescriptiveStatistics Kurtosis", sds.getKurtosis(), 3.80165); if (problem == false) { std::cout << "PASSED StatisticDescriptiveStatistics" << std::endl; } return problem; } /** * test mean, variance, deviation. */ bool StatisticUnitTesting::testStatisticMeanAndDeviation() { // // Data from page 43, table 2-2, Statistics For Psychology, 2nd, Aron & Aron // const int numData = 10; float data[numData] = { 7.0, 8.0, 8.0, 7.0, 3.0, 1.0, 6.0, 9.0, 3.0, 8.0 }; StatisticMeanAndDeviation smad; smad.addDataArray(data, numData); try { smad.execute(); } catch (StatisticException& e) { std::cout << "FAILED StatisticMeanAndDeviation threw exception: " << e.whatStdString() << std::endl; return true; } bool problem = false; problem |= verify("StatisticMeanAndDeviation SumOfSquares", smad.getSumOfSquares(), 66.0); problem |= verify("StatisticMeanAndDeviation Mean", smad.getMean(), 6.0); problem |= verify("StatisticMeanAndDeviation Variance", smad.getVariance(), 6.6); problem |= verify("StatisticMeanAndDeviation Population Sample Variance", smad.getPopulationSampleVariance(), 7.333333); problem |= verify("StatisticMeanAndDeviation Standard Deviation", smad.getStandardDeviation(), 2.57); problem |= verify("StatisticMeanAndDeviation Population Sample Standard Deviation", smad.getPopulationSampleStandardDeviation(), 2.708); if (problem == false) { std::cout << "PASSED StatisticMeanAndDeviation" << std::endl; } return problem; } /** * test one-sample T-Test. */ bool StatisticUnitTesting::testStatisticTtestOneSample() { // // Data from page 264, table 9-3, Statistics For Psychology, 2nd, Aron & Aron // const int numData = 10; float data[numData] = { 5.0, 3.0, 6.0, 2.0, 7.0, 6.0, 7.0, 4.0, 2.0, 5.0 }; const float knownMeanMu = 4.0; StatisticTtestOneSample tTest(knownMeanMu); tTest.addDataArray(data, numData); try { tTest.execute(); } catch (StatisticException& e) { std::cout << "FAILED StatisticTtestOneSample threw exception: " << e.whatStdString() << std::endl; return true; } bool problem = false; problem |= verify("StatisticTtestOneSample T-Value", tTest.getTValue(), 1.17211); problem |= verify("StatisticTtestOneSample Degrees Of Freedom", tTest.getDegreesOfFreedom(), 9.0); problem |= verify("StatisticTtestOneSample P-Value", tTest.getPValue(), 0.135623); if (problem == false) { std::cout << "PASSED StatisticTtestOneSample" << std::endl; } return problem; } /** * test Paired T-Test. */ bool StatisticUnitTesting::testStatisticTtestPaired() { // // Data from page 269, table 9-5, Statistics For Psychology, 2nd, Aron & Aron // const int numData = 19; float dataBefore[numData] = { 126, 133, 126, 115, 108, 109, 124, 98, 95, 120, 118, 126, 121, 116, 94, 105, 123, 125, 128, }; float dataAfter[numData] = { 115, 125, 96, 115, 119, 82, 93, 109, 72, 104, 107, 118, 102, 115, 83, 87, 121, 100, 118, }; StatisticTtestPaired tTest; tTest.addDataArray(dataAfter, numData); tTest.addDataArray(dataBefore, numData); try { tTest.execute(); } catch (StatisticException& e) { std::cout << "FAILED StatisticTtestPaired threw exception: " << e.whatStdString() << std::endl; return true; } bool problem = false; problem |= verify("StatisticTtestPaired T-Value", tTest.getTValue(), -4.24042); problem |= verify("StatisticTtestPaired Degrees Of Freedom", tTest.getDegreesOfFreedom(), 18.0); problem |= verify("StatisticTtestPaired P-Value", tTest.getPValue(), 0.000246008); if (problem == false) { std::cout << "PASSED StatisticTtestPaired" << std::endl; } return problem; } /** * test Paired T-Test. */ bool StatisticUnitTesting::testStatisticTtestTwoSamplePooledVariance() { // // Data from http://www.statsdirect.com/help/parametric_methods/utt.htm // const int numDataA = 12; float dataA[numDataA] = { 134, 146, 104, 119, 124, 161, 107, 83, 113, 129, 97, 123 }; const int numDataB = 7; float dataB[numDataB] = { 70, 118, 101, 85, 107, 132, 94 }; StatisticTtestTwoSample tTest(StatisticTtestTwoSample::VARIANCE_TYPE_POOLED); tTest.addDataArray(dataA, numDataA); tTest.addDataArray(dataB, numDataB); try { tTest.execute(); } catch (StatisticException& e) { std::cout << "FAILED StatisticTtestTwoSample PooledVariance threw exception: " << e.whatStdString() << std::endl; return true; } bool problem = false; problem |= verify("StatisticTtestTwoSample PooledVariance T-Value", tTest.getTValue(), 1.891436); problem |= verify("StatisticTtestTwoSample PooledVariance Degrees Of Freedom", tTest.getDegreesOfFreedom(), 17.0); problem |= verify("StatisticTtestTwoSample PooledVariance P-Value", tTest.getPValue(), 0.0379); if (problem == false) { std::cout << "PASSED StatisticTtestTwoSample PooledVariance" << std::endl; } return problem; } /** * test Paired T-Test. */ bool StatisticUnitTesting::testStatisticTtestTwoSampleUnpooledVariance() { // // Data from http://www.statsdirect.com/help/parametric_methods/utt.htm // const int numDataA = 12; float dataA[numDataA] = { 134, 146, 104, 119, 124, 161, 107, 83, 113, 129, 97, 123 }; const int numDataB = 7; float dataB[numDataB] = { 70, 118, 101, 85, 107, 132, 94 }; StatisticTtestTwoSample tTest(StatisticTtestTwoSample::VARIANCE_TYPE_UNPOOLED); tTest.addDataArray(dataA, numDataA); tTest.addDataArray(dataB, numDataB); try { tTest.execute(); } catch (StatisticException& e) { std::cout << "FAILED StatisticTtestTwoSample UnpooledVariance threw exception: " << e.whatStdString() << std::endl; return true; } bool problem = false; problem |= verify("StatisticTtestTwoSample UnpooledVariance T-Value", tTest.getTValue(), 1.9107); problem |= verify("StatisticTtestTwoSample UnpooledVariance Degrees Of Freedom", tTest.getDegreesOfFreedom(), 13.081702); problem |= verify("StatisticTtestTwoSample UnpooledVariance P-Value", tTest.getPValue(), 0.0391); if (problem == false) { std::cout << "PASSED StatisticTtestTwoSample UnpooledVariance " << std::endl; } return problem; } /** * test two-way fixed-effect ANOVA. */ bool StatisticUnitTesting::testStatisticAnovaTwoWayFixedEffectCase1() { // // Data from Statistics for Psychology // Arthur Aron & Elaine Aron // 2nd Edition, 1999 // Table 17-3, page 397 // const int numData = 10; const float boysLowAffiliation[numData] = { 12.1, 11.4, 11.2, 10.9, 10.3, 9.8, 9.7, 9.5, 9.3, 8.8 }; const float boysHighAffiliation[numData] = { 11.1, 10.4, 10.2, 9.8, 9.2, 9.1, 8.9, 8.7, 8.2, 6.6 }; const float girlsLowAffiliation[numData] = { 17.4, 17.1, 16.8, 16.7, 15.5, 15.3, 15.0, 15.4, 14.3, 14.0 }; const float girlsHighAffiliation[numData] = { 22.0, 20.5, 19.9, 19.1, 18.5, 17.4, 17.0, 17.1, 17.1, 16.5 }; // Affiliation //Gender Low High //Boys //Girls StatisticAnovaTwoWay anova; anova.setAnovaModelType(StatisticAnovaTwoWay::ANOVA_MODEL_TYPE_FIXED_EFFECT); anova.setNumberOfFactorLevels(2, 2); anova.setDataArray(0, 0, boysLowAffiliation, numData); anova.setDataArray(0, 1, boysHighAffiliation, numData); anova.setDataArray(1, 0, girlsLowAffiliation, numData); anova.setDataArray(1, 1, girlsHighAffiliation, numData); try { anova.execute(); } catch (StatisticException& e) { std::cout << "FAILED StatisticAnovaTwoWay Fixed Case 1 threw exception: " << e.whatStdString() << std::endl; return true; } bool problem = false; problem |= verify("StatisticAnovaTwoWay Fixed Case 1 SSTR", anova.getSumOfSquaresTreatmentSSTR(), 587.089); problem |= verify("StatisticAnovaTwoWay Fixed Case 1 SSE", anova.getSumOfSquaresErrorSSE(), 67.25); problem |= verify("StatisticAnovaTwoWay Fixed Case 1 SSTO", anova.getSumOfSquaresTotalSSTO(), 654.339); problem |= verify("StatisticAnovaTwoWay Fixed Case 1 SSA", anova.getSumOfSquaresSSA(), 543.169); problem |= verify("StatisticAnovaTwoWay Fixed Case 1 SSB", anova.getSumOfSquaresSSB(), 7.056); problem |= verify("StatisticAnovaTwoWay Fixed Case 1 SSAB", anova.getSumOfSquaresSSAB(), 36.864); problem |= verify("StatisticAnovaTwoWay Fixed Case 1 Mean of All", anova.getMeanOfAllValues(), 13.445); const float cellMeans[4] = { 10.3, 9.22, 15.75, 18.51 }; for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { const std::string text("StatisticAnovaTwoWay Fixed Case 1 Cell " + StatisticAlgorithm::numberToString(i) + ", " + StatisticAlgorithm::numberToString(j) + " Mean"); problem |= verify(text, anova.getCellMean(i, j), cellMeans[i*2 + j]); } } const float meansA[2] = { 9.76, 17.13 }; for (int i = 0; i < 2; i++) { const std::string text("StatisticAnovaTwoWay Fixed Case 1 Factor Level A " + StatisticAlgorithm::numberToString(i) + " Mean"); problem |= verify(text, anova.getMeanFactorLevelA(i), meansA[i]); } const float meansB[2] = { 13.025, 13.865 }; for (int j = 0; j < 2; j++) { const std::string text("StatisticAnovaTwoWay Fixed Case 1 Factor Level B " + StatisticAlgorithm::numberToString(j) + " Mean"); problem |= verify(text, anova.getMeanFactorLevelB(j), meansB[j]); } problem |= verify("StatisticAnovaTwoWay Fixed Case 1 Degrees of Freedom Factor A", anova.getDegreesOfFreedomFactorA(), 1.0); problem |= verify("StatisticAnovaTwoWay Fixed Case 1 Degrees of Freedom Factor B", anova.getDegreesOfFreedomFactorB(), 1.0); problem |= verify("StatisticAnovaTwoWay Fixed Case 1 Degrees of Freedom Interactions", anova.getDegreesOfFreedomInteractions(), 1.0); problem |= verify("StatisticAnovaTwoWay Fixed Case 1 Degrees of Freedom Between Treatments", anova.getDegreesOfFreedomBetweenTreatments(), 3.0); problem |= verify("StatisticAnovaTwoWay Fixed Case 1 Degrees of Freedom Error", anova.getDegreesOfFreedomError(), 36.0); problem |= verify("StatisticAnovaTwoWay Fixed Case 1 Degrees of Freedom Total", anova.getDegreesOfFreedomTotal(), 39.0); problem |= verify("StatisticAnovaTwoWay Fixed Case 1 Mean Square Factor A", anova.getMeanSquareFactorA_MSA(), 543.169); problem |= verify("StatisticAnovaTwoWay Fixed Case 1 Mean Square Factor B", anova.getMeanSquareFactorB_MSB(), 7.056); problem |= verify("StatisticAnovaTwoWay Fixed Case 1 Mean Square Interaction", anova.getMeanSquareInteractionMSAB(), 36.864); problem |= verify("StatisticAnovaTwoWay Fixed Case 1 Mean Square Between Treatments", anova.getMeanSquareBetweenTreatmentsMSTR(), 195.696); problem |= verify("StatisticAnovaTwoWay Fixed Case 1 Mean Square Error", anova.getMeanSquareErrorMSE(), 1.868); problem |= verify("StatisticAnovaTwoWay Fixed Case 1 F-Statistic Factor A", anova.getFStatisticFactorA(), 290.767); problem |= verify("StatisticAnovaTwoWay Fixed Case 1 F-Statistic Factor B", anova.getfStatisticFactorB(), 3.77719); problem |= verify("StatisticAnovaTwoWay Fixed Case 1 F-Statistic Interaction", anova.getfStatisticInteraction(), 19.7339); problem |= verify("StatisticAnovaTwoWay Fixed Case 1 P-Value Factor A", anova.getPValueFactorA(), 0.0); problem |= verify("StatisticAnovaTwoWay Fixed Case 1 P-Value Factor B", anova.getPValueFactorB(), 0.0598056); problem |= verify("StatisticAnovaTwoWay Fixed Case 1 P-Value Interaction", anova.getPValueInteraction(), 0.0000814); if (problem) { std::cout << "StatisticAnovaTwoWay Fixed Case 1 Factor A: Gender" << std::endl; std::cout << "StatisticAnovaTwoWay Fixed Case 1 Factor B: Affiliation" << std::endl; } if (problem == false) { std::cout << "PASSED StatisticAnovaTwoWay Fixed Case 1 " << std::endl; } return problem; } /** * test two-way fixed-effect ANOVA. */ bool StatisticUnitTesting::testStatisticAnovaTwoWayFixedEffectCase2() { // // Data from Applied Linear Statistical Models // John Neter, William Wasserman, and Michael H. Kutner // Third Edition, 1990 // Data from Table 18.7, page 695 Castle Bakery Example // Table 18.10, page 705 // Figure 18.7, page 711 // const int numData = 2; const float bottomRegular[numData] = { 47.0, 43.0 }; const float middleRegular[numData] = { 62.0, 68.0}; const float topRegular[numData] = { 41.0, 39.0}; const float bottomWide[numData] = { 46.0, 40.0 }; const float middleWide[numData] = { 67.0, 71.0 }; const float topWide[numData] = { 42.0, 46.0 }; // Display Width //Height Regular Wide //Bottom //Middle //Top StatisticAnovaTwoWay anova; anova.setAnovaModelType(StatisticAnovaTwoWay::ANOVA_MODEL_TYPE_FIXED_EFFECT); anova.setNumberOfFactorLevels(3, 2); anova.setDataArray(0, 0, bottomRegular, numData); anova.setDataArray(1, 0, middleRegular, numData); anova.setDataArray(2, 0, topRegular, numData); anova.setDataArray(0, 1, bottomWide, numData); anova.setDataArray(1, 1, middleWide, numData); anova.setDataArray(2, 1, topWide, numData); try { anova.execute(); } catch (StatisticException& e) { std::cout << "FAILED StatisticAnovaTwoWay Fixed Case 2 threw exception: " << e.whatStdString() << std::endl; return true; } bool problem = false; problem |= verify("StatisticAnovaTwoWay Fixed Case 2 SSTR", anova.getSumOfSquaresTreatmentSSTR(), 1580.0); problem |= verify("StatisticAnovaTwoWay Fixed Case 2 SSE", anova.getSumOfSquaresErrorSSE(), 62.0); problem |= verify("StatisticAnovaTwoWay Fixed Case 2 SSTO", anova.getSumOfSquaresTotalSSTO(), 1642.0); problem |= verify("StatisticAnovaTwoWay Fixed Case 2 SSA", anova.getSumOfSquaresSSA(), 1544.0); problem |= verify("StatisticAnovaTwoWay Fixed Case 2 SSB", anova.getSumOfSquaresSSB(), 12.0); problem |= verify("StatisticAnovaTwoWay Fixed Case 2 SSAB", anova.getSumOfSquaresSSAB(), 24.0); problem |= verify("StatisticAnovaTwoWay Fixed Case 2 Mean of All", anova.getMeanOfAllValues(), 51.0); const float cellMeans[6] = { 45.0, 43.0, 65.0, 69.0, 40.0, 44.0 }; for (int i = 0; i < 3; i++) { for (int j = 0; j < 2; j++) { const std::string text("StatisticAnovaTwoWay Fixed Case 2 Cell " + StatisticAlgorithm::numberToString(i) + ", " + StatisticAlgorithm::numberToString(j) + " Mean"); problem |= verify(text, anova.getCellMean(i, j), cellMeans[i*2 + j]); } } const float meansA[3] = { 44.0, 67.0, 42.0 }; for (int i = 0; i < 3; i++) { const std::string text("StatisticAnovaTwoWay Fixed Case 2 Factor Level A " + StatisticAlgorithm::numberToString(i) + " Mean"); problem |= verify(text, anova.getMeanFactorLevelA(i), meansA[i]); } const float meansB[2] = { 50.0, 52.0 }; for (int j = 0; j < 2; j++) { const std::string text("StatisticAnovaTwoWay Fixed Case 2 Factor Level B " + StatisticAlgorithm::numberToString(j) + " Mean"); problem |= verify(text, anova.getMeanFactorLevelB(j), meansB[j]); } problem |= verify("StatisticAnovaTwoWay Fixed Case 2 Degrees of Freedom Factor A", anova.getDegreesOfFreedomFactorA(), 2.0); problem |= verify("StatisticAnovaTwoWay Fixed Case 2 Degrees of Freedom Factor B", anova.getDegreesOfFreedomFactorB(), 1.0); problem |= verify("StatisticAnovaTwoWay Fixed Case 2 Degrees of Freedom Interactions", anova.getDegreesOfFreedomInteractions(), 2.0); problem |= verify("StatisticAnovaTwoWay Fixed Case 2 Degrees of Freedom Between Treatments", anova.getDegreesOfFreedomBetweenTreatments(), 5.0); problem |= verify("StatisticAnovaTwoWay Fixed Case 2 Degrees of Freedom Error", anova.getDegreesOfFreedomError(), 6.0); problem |= verify("StatisticAnovaTwoWay Fixed Case 2 Degrees of Freedom Total", anova.getDegreesOfFreedomTotal(), 11.0); problem |= verify("StatisticAnovaTwoWay Fixed Case 2 Mean Square Factor A", anova.getMeanSquareFactorA_MSA(), 772.0); problem |= verify("StatisticAnovaTwoWay Fixed Case 2 Mean Square Factor B", anova.getMeanSquareFactorB_MSB(), 12.0); problem |= verify("StatisticAnovaTwoWay Fixed Case 2 Mean Square Interaction", anova.getMeanSquareInteractionMSAB(), 12.0); problem |= verify("StatisticAnovaTwoWay Fixed Case 2 Mean Square Between Treatments", anova.getMeanSquareBetweenTreatmentsMSTR(), 316.0); problem |= verify("StatisticAnovaTwoWay Fixed Case 2 Mean Square Error", anova.getMeanSquareErrorMSE(), 10.33333); problem |= verify("StatisticAnovaTwoWay Fixed Case 2 F-Statistic Factor A", anova.getFStatisticFactorA(), 74.71); problem |= verify("StatisticAnovaTwoWay Fixed Case 2 F-Statistic Factor B", anova.getfStatisticFactorB(), 1.16129); problem |= verify("StatisticAnovaTwoWay Fixed Case 2 F-Statistic Interaction", anova.getfStatisticInteraction(), 1.16129); problem |= verify("StatisticAnovaTwoWay Fixed Case 2 P-Value Factor A", anova.getPValueFactorA(), 0.0001); problem |= verify("StatisticAnovaTwoWay Fixed Case 2 P-Value Factor B", anova.getPValueFactorB(), 0.3226); problem |= verify("StatisticAnovaTwoWay Fixed Case 2 P-Value Interaction", anova.getPValueInteraction(), 0.3747); if (problem) { std::cout << "StatisticAnovaTwoWay Fixed Case 2 Factor A: Display Height" << std::endl; std::cout << "StatisticAnovaTwoWay Fixed Case 2 Factor B: Width" << std::endl; } if (problem == false) { std::cout << "PASSED StatisticAnovaTwoWay Fixed Case 2 " << std::endl; } return problem; } /** * test two-way random-effect ANOVA. */ bool StatisticUnitTesting::testStatisticAnovaTwoWayRandomEffect() { // // Data from Statistics for Psychology // Arthur Aron & Elaine Aron // 2nd Edition, 1999 // Table 17-3, page 397 // const int numData = 10; const float boysLowAffiliation[numData] = { 12.1, 11.4, 11.2, 10.9, 10.3, 9.8, 9.7, 9.5, 9.3, 8.8 }; const float boysHighAffiliation[numData] = { 11.1, 10.4, 10.2, 9.8, 9.2, 9.1, 8.9, 8.7, 8.2, 6.6 }; const float girlsLowAffiliation[numData] = { 17.4, 17.1, 16.8, 16.7, 15.5, 15.3, 15.0, 15.4, 14.3, 14.0 }; const float girlsHighAffiliation[numData] = { 22.0, 20.5, 19.9, 19.1, 18.5, 17.4, 17.0, 17.1, 17.1, 16.5 }; // Affiliation //Gender Low High //Boys //Girls StatisticAnovaTwoWay anova; anova.setAnovaModelType(StatisticAnovaTwoWay::ANOVA_MODEL_TYPE_RANDOM_EFFECT); anova.setNumberOfFactorLevels(2, 2); anova.setDataArray(0, 0, boysLowAffiliation, numData); anova.setDataArray(0, 1, boysHighAffiliation, numData); anova.setDataArray(1, 0, girlsLowAffiliation, numData); anova.setDataArray(1, 1, girlsHighAffiliation, numData); try { anova.execute(); } catch (StatisticException& e) { std::cout << "FAILED StatisticAnovaTwoWay Random threw exception: " << e.whatStdString() << std::endl; return true; } bool problem = false; problem |= verify("StatisticAnovaTwoWay Random SSTR", anova.getSumOfSquaresTreatmentSSTR(), 587.089); problem |= verify("StatisticAnovaTwoWay Random SSE", anova.getSumOfSquaresErrorSSE(), 67.25); problem |= verify("StatisticAnovaTwoWay Random SSTO", anova.getSumOfSquaresTotalSSTO(), 654.339); problem |= verify("StatisticAnovaTwoWay Random SSA", anova.getSumOfSquaresSSA(), 543.169); problem |= verify("StatisticAnovaTwoWay Random SSB", anova.getSumOfSquaresSSB(), 7.056); problem |= verify("StatisticAnovaTwoWay Random SSAB", anova.getSumOfSquaresSSAB(), 36.864); problem |= verify("StatisticAnovaTwoWay Random Mean of All", anova.getMeanOfAllValues(), 13.445); const float cellMeans[4] = { 10.3, 9.22, 15.75, 18.51 }; for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { const std::string text("StatisticAnovaTwoWay Random Cell " + StatisticAlgorithm::numberToString(i) + ", " + StatisticAlgorithm::numberToString(j) + " Mean"); problem |= verify(text, anova.getCellMean(i, j), cellMeans[i*2 + j]); } } const float meansA[2] = { 9.76, 17.13 }; for (int i = 0; i < 2; i++) { const std::string text("StatisticAnovaTwoWay Random Factor Level A " + StatisticAlgorithm::numberToString(i) + " Mean"); problem |= verify(text, anova.getMeanFactorLevelA(i), meansA[i]); } const float meansB[2] = { 13.025, 13.865 }; for (int j = 0; j < 2; j++) { const std::string text("StatisticAnovaTwoWay Random Factor Level B " + StatisticAlgorithm::numberToString(j) + " Mean"); problem |= verify(text, anova.getMeanFactorLevelB(j), meansB[j]); } problem |= verify("StatisticAnovaTwoWay Random Degrees of Freedom Factor A", anova.getDegreesOfFreedomFactorA(), 1.0); problem |= verify("StatisticAnovaTwoWay Random Degrees of Freedom Factor B", anova.getDegreesOfFreedomFactorB(), 1.0); problem |= verify("StatisticAnovaTwoWay Random Degrees of Freedom Interactions", anova.getDegreesOfFreedomInteractions(), 1.0); problem |= verify("StatisticAnovaTwoWay Random Degrees of Freedom Between Treatments", anova.getDegreesOfFreedomBetweenTreatments(), 3.0); problem |= verify("StatisticAnovaTwoWay Random Degrees of Freedom Error", anova.getDegreesOfFreedomError(), 36.0); problem |= verify("StatisticAnovaTwoWay Random Degrees of Freedom Total", anova.getDegreesOfFreedomTotal(), 39.0); problem |= verify("StatisticAnovaTwoWay Random Mean Square Factor A", anova.getMeanSquareFactorA_MSA(), 543.169); problem |= verify("StatisticAnovaTwoWay Random Mean Square Factor B", anova.getMeanSquareFactorB_MSB(), 7.056); problem |= verify("StatisticAnovaTwoWay Random Mean Square Interaction", anova.getMeanSquareInteractionMSAB(), 36.864); problem |= verify("StatisticAnovaTwoWay Random Mean Square Between Treatments", anova.getMeanSquareBetweenTreatmentsMSTR(), 195.696); problem |= verify("StatisticAnovaTwoWay Random Mean Square Error", anova.getMeanSquareErrorMSE(), 1.868); problem |= verify("StatisticAnovaTwoWay Random F-Statistic Factor A", anova.getFStatisticFactorA(), 14.7344); problem |= verify("StatisticAnovaTwoWay Random F-Statistic Factor B", anova.getfStatisticFactorB(), 0.191406); problem |= verify("StatisticAnovaTwoWay Random F-Statistic Interaction", anova.getfStatisticInteraction(), 19.7339); problem |= verify("StatisticAnovaTwoWay Random P-Value Factor A", anova.getPValueFactorA(), 0.000481591); problem |= verify("StatisticAnovaTwoWay Random P-Value Factor B", anova.getPValueFactorB(), 0.664362); problem |= verify("StatisticAnovaTwoWay Random P-Value Interaction", anova.getPValueInteraction(), 0.0000814022); if (problem) { std::cout << "StatisticAnovaTwoWay Random Factor A: Gender" << std::endl; std::cout << "StatisticAnovaTwoWay Random Factor B: Affiliation" << std::endl; } if (problem == false) { std::cout << "PASSED StatisticAnovaTwoWay Random " << std::endl; } return problem; } /** * test two-way mixed-effect ANOVA. */ bool StatisticUnitTesting::testStatisticAnovaTwoWayMixedEffect() { // // Data from Statistics for Psychology // Arthur Aron & Elaine Aron // 2nd Edition, 1999 // Table 17-3, page 397 // const int numData = 10; const float boysLowAffiliation[numData] = { 12.1, 11.4, 11.2, 10.9, 10.3, 9.8, 9.7, 9.5, 9.3, 8.8 }; const float boysHighAffiliation[numData] = { 11.1, 10.4, 10.2, 9.8, 9.2, 9.1, 8.9, 8.7, 8.2, 6.6 }; const float girlsLowAffiliation[numData] = { 17.4, 17.1, 16.8, 16.7, 15.5, 15.3, 15.0, 15.4, 14.3, 14.0 }; const float girlsHighAffiliation[numData] = { 22.0, 20.5, 19.9, 19.1, 18.5, 17.4, 17.0, 17.1, 17.1, 16.5 }; // Affiliation //Gender Low High //Boys //Girls StatisticAnovaTwoWay anova; anova.setAnovaModelType(StatisticAnovaTwoWay::ANOVA_MODEL_TYPE_MIXED_EFFECT); anova.setNumberOfFactorLevels(2, 2); anova.setDataArray(0, 0, boysLowAffiliation, numData); anova.setDataArray(0, 1, boysHighAffiliation, numData); anova.setDataArray(1, 0, girlsLowAffiliation, numData); anova.setDataArray(1, 1, girlsHighAffiliation, numData); try { anova.execute(); } catch (StatisticException& e) { std::cout << "FAILED StatisticAnovaTwoWay Mixed threw exception: " << e.whatStdString() << std::endl; return true; } bool problem = false; problem |= verify("StatisticAnovaTwoWay Mixed SSTR", anova.getSumOfSquaresTreatmentSSTR(), 587.089); problem |= verify("StatisticAnovaTwoWay Mixed SSE", anova.getSumOfSquaresErrorSSE(), 67.25); problem |= verify("StatisticAnovaTwoWay Mixed SSTO", anova.getSumOfSquaresTotalSSTO(), 654.339); problem |= verify("StatisticAnovaTwoWay Mixed SSA", anova.getSumOfSquaresSSA(), 543.169); problem |= verify("StatisticAnovaTwoWay Mixed SSB", anova.getSumOfSquaresSSB(), 7.056); problem |= verify("StatisticAnovaTwoWay Mixed SSAB", anova.getSumOfSquaresSSAB(), 36.864); problem |= verify("StatisticAnovaTwoWay Mixed Mean of All", anova.getMeanOfAllValues(), 13.445); const float cellMeans[4] = { 10.3, 9.22, 15.75, 18.51 }; for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { const std::string text("StatisticAnovaTwoWay Mixed Cell " + StatisticAlgorithm::numberToString(i) + ", " + StatisticAlgorithm::numberToString(j) + " Mean"); problem |= verify(text, anova.getCellMean(i, j), cellMeans[i*2 + j]); } } const float meansA[2] = { 9.76, 17.13 }; for (int i = 0; i < 2; i++) { const std::string text("StatisticAnovaTwoWay Mixed Factor Level A " + StatisticAlgorithm::numberToString(i) + " Mean"); problem |= verify(text, anova.getMeanFactorLevelA(i), meansA[i]); } const float meansB[2] = { 13.025, 13.865 }; for (int j = 0; j < 2; j++) { const std::string text("StatisticAnovaTwoWay Mixed Factor Level B " + StatisticAlgorithm::numberToString(j) + " Mean"); problem |= verify(text, anova.getMeanFactorLevelB(j), meansB[j]); } problem |= verify("StatisticAnovaTwoWay Mixed Degrees of Freedom Factor A", anova.getDegreesOfFreedomFactorA(), 1.0); problem |= verify("StatisticAnovaTwoWay Mixed Degrees of Freedom Factor B", anova.getDegreesOfFreedomFactorB(), 1.0); problem |= verify("StatisticAnovaTwoWay Mixed Degrees of Freedom Interactions", anova.getDegreesOfFreedomInteractions(), 1.0); problem |= verify("StatisticAnovaTwoWay Mixed Degrees of Freedom Between Treatments", anova.getDegreesOfFreedomBetweenTreatments(), 3.0); problem |= verify("StatisticAnovaTwoWay Mixed Degrees of Freedom Error", anova.getDegreesOfFreedomError(), 36.0); problem |= verify("StatisticAnovaTwoWay Mixed Degrees of Freedom Total", anova.getDegreesOfFreedomTotal(), 39.0); problem |= verify("StatisticAnovaTwoWay Mixed Mean Square Factor A", anova.getMeanSquareFactorA_MSA(), 543.169); problem |= verify("StatisticAnovaTwoWay Mixed Mean Square Factor B", anova.getMeanSquareFactorB_MSB(), 7.056); problem |= verify("StatisticAnovaTwoWay Mixed Mean Square Interaction", anova.getMeanSquareInteractionMSAB(), 36.864); problem |= verify("StatisticAnovaTwoWay Mixed Mean Square Between Treatments", anova.getMeanSquareBetweenTreatmentsMSTR(), 195.696); problem |= verify("StatisticAnovaTwoWay Mixed Mean Square Error", anova.getMeanSquareErrorMSE(), 1.868); problem |= verify("StatisticAnovaTwoWay Mixed F-Statistic Factor A", anova.getFStatisticFactorA(), 14.7344); problem |= verify("StatisticAnovaTwoWay Mixed F-Statistic Factor B", anova.getfStatisticFactorB(), 3.77719); problem |= verify("StatisticAnovaTwoWay Mixed F-Statistic Interaction", anova.getfStatisticInteraction(), 19.7339); problem |= verify("StatisticAnovaTwoWay Mixed P-Value Factor A", anova.getPValueFactorA(), 0.000481591); problem |= verify("StatisticAnovaTwoWay Mixed P-Value Factor B", anova.getPValueFactorB(), 0.0598056); problem |= verify("StatisticAnovaTwoWay Mixed P-Value Interaction", anova.getPValueInteraction(), 0.0000814022); if (problem) { std::cout << "StatisticAnovaTwoWay Mixed Factor A: Gender" << std::endl; std::cout << "StatisticAnovaTwoWay Mixed Factor B: Affiliation" << std::endl; } if (problem == false) { std::cout << "PASSED StatisticAnovaTwoWay Mixed " << std::endl; } return problem; } /** * test one-way ANOVA. * Data from http://www.statsdirect.com/help/analysis_of_variance/oneway.htm */ bool StatisticUnitTesting::testStatisticAnovaOneWay() { float data1[] = { 279, 338, 334, 198, 303 }; const int numData1 = sizeof(data1) / sizeof(float); float data2[] = { 378, 275, 412, 265, 286 }; const int numData2 = sizeof(data2) / sizeof(float); float data3[] = { 172, 335, 335, 282, 250 }; const int numData3 = sizeof(data3) / sizeof(float); float data4[] = { 381, 346, 340, 471, 318 }; const int numData4 = sizeof(data4) / sizeof(float); StatisticAnovaOneWay anova; anova.addDataArray(data1, numData1); anova.addDataArray(data2, numData2); anova.addDataArray(data3, numData3); anova.addDataArray(data4, numData4); try { anova.execute(); } catch (StatisticException& e) { std::cout << "FAILED StatisticAnovaOneWay threw exception: " << e.whatStdString() << std::endl; return true; } bool problem = false; problem |= verify("StatisticAnovaOneWay SSTR", anova.getSumOfSquaresTreatmentSSTR(), 27234.2); problem |= verify("StatisticAnovaOneWay SSE", anova.getSumOfSquaresErrorSSE(), 63953.6); problem |= verify("StatisticAnovaOneWay SSTO", anova.getSumOfSquaresTotalSSTO(), 91187.8); problem |= verify("StatisticAnovaOneWay MSTR", anova.getMeanSumOfSquaresTreatmentMSTR(), 9078.066667); problem |= verify("StatisticAnovaOneWay MSE", anova.getMeanSumOfSquaresErrorMSE(), 3997.1); problem |= verify("StatisticAnovaOneWay DOF Between", anova.getDegreesOfFreedomBetweenTreatments(), 3.0); problem |= verify("StatisticAnovaOneWay DOF Within", anova.getDegreesOfFreedomWithinTreatments(), 16.0); problem |= verify("StatisticAnovaOneWay DOF Total", anova.getDegreesOfFreedomTotal(), 19.0); problem |= verify("StatisticAnovaOneWay F-Statistic", anova.getFStatistic(), 2.271163); problem |= verify("StatisticAnovaOneWay P-Value", anova.getPValue(), .1195); if (problem == false) { std::cout << "PASSED StatisticAnovaOneWay " << std::endl; } return problem; } /** * test Kruskal-Wallis. * Data from Applied Linear Statistical Models * John Neter, William Wasserman, Michael H. Kutner * 3rd Edition * Page 644 */ bool StatisticUnitTesting::testKruskalWallis() { float dataA[] = { 105, 3, 90, 217, 22 }; const int numDataA = sizeof(dataA) / sizeof(float); float dataB[] = { 56, 43, 1, 37, 14 }; const int numDataB = sizeof(dataB) / sizeof(float); float dataC[] = { 183, 144, 219, 86, 39 }; const int numDataC = sizeof(dataC) / sizeof(float); StatisticKruskalWallis kw; kw.addDataArray(dataA, numDataA); kw.addDataArray(dataB, numDataB); kw.addDataArray(dataC, numDataC); try { kw.execute(); } catch (StatisticException& e) { std::cout << "FAILED StatisticKruskalWallis threw exception: " << e.whatStdString() << std::endl; return true; } bool problem = false; problem |= verify("StatisticKruskalWallis SSTR", kw.getSumOfSquaresTreatmentSSTR(), 96.4); problem |= verify("StatisticKruskalWallis SSE", kw.getSumOfSquaresErrorSSE(), 183.6); problem |= verify("StatisticKruskalWallis MSTR", kw.getMeanSumOfSquaresTreatmentMSTR(), 48.2); problem |= verify("StatisticKruskalWallis MSE", kw.getMeanSumOfSquaresErrorMSE(), 15.3); problem |= verify("StatisticKruskalWallis DOF Between", kw.getDegreesOfFreedomBetweenTreatments(), 2.0); problem |= verify("StatisticKruskalWallis DOF Within", kw.getDegreesOfFreedomWithinTreatments(), 12.0); problem |= verify("StatisticKruskalWallis DOF Total", kw.getDegreesOfFreedomTotal(), 14.0); problem |= verify("StatisticKruskalWallis F-Statistic", kw.getFStatistic(), 3.15); problem |= verify("StatisticKruskalWallis P-Value", kw.getPValue(), 0.08); if (problem == false) { std::cout << "PASSED StatisticKruskalWallis " << std::endl; } return problem; } /* * verify that two matrices numbers are nearly identical (false if ok). */ bool StatisticUnitTesting::verify(const std::string& testName, const StatisticMatrix& computedMatrix, const StatisticMatrix& correctMatrix, const float acceptableDifference) { bool printThem = false; bool errorFlag = false; std::string printWord; const int numRows = computedMatrix.getNumberOfRows(); const int numCols = computedMatrix.getNumberOfColumns(); if ((numRows == correctMatrix.getNumberOfRows()) && (numCols == correctMatrix.getNumberOfColumns())) { for (int i = 0; i < numRows; i++) { for (int j = 0; j < numCols; j++) { const float diff = std::fabs(computedMatrix.getElement(i, j) - correctMatrix.getElement(i, j)); if (diff > acceptableDifference) { printWord = "FAILED"; printThem = true; errorFlag = true; } else if (printTestValuesFlag) { printThem = true; } } } } else { printWord = "FAILED"; printThem = true; errorFlag = true; } if (printThem) { std::cout << printWord << " " << testName << std::endl; computedMatrix.print(std::cout, " ", " Computed Matrix: "); if (errorFlag) { correctMatrix.print(std::cout, " ", " Correct Matrix: "); } } return errorFlag; } /** * verify that two floating point numbers are nearly identical (false if ok). */ bool StatisticUnitTesting::verify(const std::string& testName, const float computedValue, const float correctValue, const float acceptableDifference) { bool printThem = false; bool errorFlag = false; std::string printWord; const float diff = std::fabs(computedValue - correctValue); if (diff > acceptableDifference) { printWord = "FAILED"; printThem = true; errorFlag = true; } else if (printTestValuesFlag) { printThem = true; } if (printThem) { std::cout << printWord << " " << testName << std::endl; std::cout << " Computed Value = " << computedValue << std::endl; if (errorFlag) { std::cout << " Correct Value = " << correctValue << std::endl; } } return errorFlag; } /** * verify that a group of coefficients are nearly identical (false if ok). */ bool StatisticUnitTesting::verifyCoefficients(const std::string& testName, const std::vector& computedCoefficients, const std::vector& correctCoefficients, const float acceptableDifference) { bool errorFlag = false; for (int i = 0; i < static_cast(correctCoefficients.size()); i++) { if (i < static_cast(computedCoefficients.size())) { std::ostringstream str; str << testName << " coefficient[" << i << "]"; errorFlag |= verify(str.str(), computedCoefficients[i], correctCoefficients[i], acceptableDifference); } else { std::cout << testName << " computed coefficient " << i << " is missing." << std::endl; errorFlag |= true; } } return errorFlag; } /** * test convert to z-score. */ bool StatisticUnitTesting::testConvertToZScore() { // // Data from Statistics for Psychology // Arthur Aron & Elaine Aron // 2nd Edition, 1999 // Table 2-2, page 43 // Table 2-5, page 53 // Mean = 6 // SD = 2.57 // bool problem = false; const int numData = 10; const float data[numData] = { 7, 8, 8, 7, 3, 1, 6, 9, 3, 8 }; StatisticConvertToZScore convertToZ; convertToZ.addDataArray(data, numData); try { convertToZ.execute(); } catch (StatisticException& e) { std::cout << "FAILED StatisticConvertToZScore threw exception: " << e.whatStdString() << std::endl; return true; } float value = 7.0; convertToZ.convertToZScore(value); problem |= verify("StatisticConvertToZScore ", value, 0.38910); // 0.39 in example if (problem == false) { std::cout << "PASSED StatisticConvertToZScore " << std::endl; } return problem; } /** * test correlation coefficient. */ bool StatisticUnitTesting::testCorrelationCoefficient() { bool problem = false; // // Data from Statistics for Psychology // Arthur Aron & Elaine Aron // 2nd Edition, 1999 // Table 3-2, page 78 // T-stats page 99 const int numData = 5; const float numEmployees[numData] = { 6, 8, 3, 10, 8 }; const float stressLevel[numData] = { 7, 8, 1, 8, 6 }; StatisticCorrelationCoefficient correlate; correlate.addDataArray(numEmployees, numData); correlate.addDataArray(stressLevel, numData); try { correlate.execute(); } catch (StatisticException& e) { std::cout << "FAILED StatisticCorrelationCoefficient threw exception: " << e.whatStdString() << std::endl; return true; } problem |= verify("StatisticCorrelationCoefficient Correlation Coefficient R2", correlate.getCorrelationCoefficientR2(), 0.765756); problem |= verify("StatisticCorrelationCoefficient Correlation Coefficient R", correlate.getCorrelationCoefficientR(), 0.875075); problem |= verify("StatisticCorrelationCoefficient T-Value", correlate.getTValue(), 3.13164); // 3.17 in book problem |= verify("StatisticCorrelationCoefficient Degrees of Freedom", correlate.getDegreesOfFreedom(), 3.0); problem |= verify("StatisticCorrelationCoefficient P-Value", correlate.getPValue(), 0.02599); if (problem == false) { std::cout << "PASSED StatisticCorrelationCoefficient " << std::endl; } return problem; } /** * test false discovery rate. */ bool StatisticUnitTesting::testFalseDiscoveryRate() { // // This data is made up and not known to be valid. // const int numData = 12; const float data[numData] = { 0.8, 0.01, 0.07, 0.12, 0.15, 0.0015, 0.3, 0.02, 0.03, 0.03, 0.34, 0.0375 }; const float q = 0.05; StatisticFalseDiscoveryRate fdr(q, StatisticFalseDiscoveryRate::C_CONSTANT_1); fdr.addDataArray(data, numData); try { fdr.execute(); } catch (StatisticException& e) { std::cout << "FAILED StatisticFalseDiscoveryRate threw exception: " << e.whatStdString() << std::endl; return true; } bool problem = false; problem |= verify("StatisticFalseDiscoveryRate P-Cutoff", fdr.getPCutoff(), 0.0015); if (problem == false) { std::cout << "PASSED StatisticFalseDiscoveryRate " << std::endl; } return problem; } /** * test histogram. */ bool StatisticUnitTesting::testHistogram() { const int numData = 15; const float data[numData] = { 1, 2, 9, 4, 3, 7, 5, 4, 5, 8, 2, 5, 3, 4, 4}; const int numBuckets = 5; StatisticHistogram hist(numBuckets); hist.addDataArray(data, numData); try { hist.execute(); } catch (StatisticException& e) { std::cout << "FAILED StatisticHistogram threw exception: " << e.whatStdString() << std::endl; return true; } if (numBuckets != hist.getNumberOfBuckets()) { std::cout << "FAILED StatisticHistogram should have produced " << numBuckets << " buckets but produced " << hist.getNumberOfBuckets(); return true; } const float bucketValues[numBuckets] = { 1.0, 2.6, 4.2, 5.8, 7.4 }; const float bucketCounts[numBuckets] = { 3.0, 6.0, 3.0, 1.0, 2.0 }; bool problem = false; for (int i = 0; i < numBuckets; i++) { float buckVal = 1.0; float buckCnt = 1.0; hist.getDataForBucket(i, buckVal, buckCnt); const std::string msg1("StatisticHistogram bucket data value " + StatisticAlgorithm::numberToString(i)); problem |= verify(msg1, buckVal, bucketValues[i]); const std::string msg2("StatisticHistogram bucket count value " + StatisticAlgorithm::numberToString(i)); problem |= verify(msg2, buckCnt, bucketCounts[i]); } if (problem == false) { std::cout << "PASSED StatisticHistogram " << std::endl; } return problem; } /** * test levene's test. */ bool StatisticUnitTesting::testLevenesTest() { // // Data is made upt // const int numData = 5; const float dataA[numData] = { 1.4, 2.6, 0.8, 1.3, 1.9 }; const float dataB[numData] = { 2.4, 1.8, 2.7, 2.3, 1.6 }; StatisticLeveneVarianceEquality levene; levene.addDataArray(dataA, numData); levene.addDataArray(dataB, numData); try { levene.execute(); } catch (StatisticException& e) { std::cout << "FAILED StatisticLeveneVarianceEquality threw exception: " << e.whatStdString() << std::endl; return true; } bool problem = false; problem |= verify("StatisticLeveneVarianceEquality F-Statistic", levene.getLeveneF(), 0.0982914); problem |= verify("StatisticLeveneVarianceEquality DOF 1", levene.getDegreesOfFreedom1(), 1.0); problem |= verify("StatisticLeveneVarianceEquality DOF 2", levene.getDegreesOfFreedom2(), 8.0); problem |= verify("StatisticLeveneVarianceEquality P-Value", levene.getPValue(), 0.761908); if (problem == false) { std::cout << "PASSED StatisticLeveneVarianceEquality " << std::endl; } return problem; } /** * test linear regression. */ bool StatisticUnitTesting::testLinearRegression() { // // Example from Applied Linear Regression Models // John Neter, William Wasserman, and Michael H. Kutner // Second Edition // Page 44 // const int numData = 10; const float xi[numData] = { 30, 20, 60, 80, 40, 50, 60, 30, 70, 60 }; const float yi[numData] = { 73, 50, 128, 170, 87, 108, 135, 69, 148, 132 }; StatisticDataGroup dependentDataGroup(yi, numData, StatisticDataGroup::DATA_STORAGE_MODE_POINT); StatisticDataGroup independentDataGroup(xi, numData, StatisticDataGroup::DATA_STORAGE_MODE_POINT); StatisticLinearRegression regression; regression.setDependentDataArray(yi, numData); regression.setIndependentDataArray(xi, numData); try { regression.execute(); } catch (StatisticException& e) { std::cout << "FAILED StatisticLinearRegression threw exception: " << e.whatStdString() << std::endl; return true; } bool problem = false; float b0, b1; regression.getRegressionCoefficients(b0, b1); problem |= verify("StatisticLinearRegression b0 (intercept)", b0, 10.0); problem |= verify("StatisticLinearRegression b1 (slope)", b1, 2.0); if (problem == false) { std::cout << "PASSED StatisticLinearRegression " << std::endl; } return problem; } /** * test rank transformation. */ bool StatisticUnitTesting::testRankTransformation() { const int numData = 7; const float groupA[numData] = { 3, 9, 1, 7, 5, 1, 10 }; const float groupB[numData] = { 8, 10, 2, 7, 3, 10, 15 }; const float resultA[numData] = { 4.5, 10, 1.5, 7.5, 6, 1.5, 12 }; const float resultB[numData] = { 9, 12, 3, 7.5, 4.5, 12, 14 }; StatisticRankTransformation srt; srt.addDataArray(groupA, numData); srt.addDataArray(groupB, numData); try { srt.execute(); } catch (StatisticException& e) { std::cout << "FAILED StatisticRankTransformation threw exception: " << e.whatStdString() << std::endl; return true; } bool problem = false; if (srt.getNumberOfOutputDataGroups() != 2) { std::cout << "FAILED StatisticRankTransformation number of output data groups is " << srt.getNumberOfOutputDataGroups() << " but should be 2." << std::endl; return problem; } const StatisticDataGroup* aOut = srt.getOutputDataGroupContainingRankValues(0); for (int i = 0; i < numData; i++) { if (resultA[i] != aOut->getData(i)) { std::cout << "FAILED StatisticRankTransformation groupe A element " << groupA[i] << " should have rank " << resultA[i] << " but is ranked " << aOut->getData(i) << std::endl; problem = true; } } const StatisticDataGroup* bOut = srt.getOutputDataGroupContainingRankValues(1); for (int i = 0; i < numData; i++) { if (resultB[i] != bOut->getData(i)) { std::cout << "FAILED StatisticRankTransformation groupe B element " << groupB[i] << " should have rank " << resultB[i] << " but is ranked " << bOut->getData(i) << std::endl; problem = true; } } if (problem == false) { std::cout << "PASSED StatisticRankTransformation " << std::endl; } return problem; } /** * test matrix operations. */ bool StatisticUnitTesting::testMatrixOperations() { bool problem = false; // // Test matrix inverse 2x2 // { const float m1Data[4] = { 2, 4, 3, 1 }; const float m1InverseData[4] = { -0.1, 0.4, 0.3, -0.2 }; StatisticMatrix m1(2, 2); m1.setMatrixFromOneDimensionalArray(m1Data); StatisticMatrix m1Inverse; StatisticMatrix m1CorrectInverse(2,2); m1CorrectInverse.setMatrixFromOneDimensionalArray(m1InverseData); try { m1Inverse = m1.inverse(); problem |= verify("Matrix Inverse (m1)", m1Inverse, m1CorrectInverse); } catch (StatisticException& e) { std::cout << "FAILED: Matrix m1 inverse failed " << e.whatStdString() << std::endl; problem = true; } } // // Test matrix inverse (4x4) // { const float m2Data[16] = { 2, 0, 1, -1, 1, -1, 0, 2, 0, -1, 2, 1, -2, 1, 3, 0 }; const float m2InverseData[16] = { 7, 6, -5, 1, // divide all by 18 after 5, 12, -19, 11, // in StatisticMatrix 3, 0, 3, 3, -1, 12, -7, 5 }; StatisticMatrix m2(4, 4); m2.setMatrixFromOneDimensionalArray(m2Data); StatisticMatrix m2Inverse; StatisticMatrix m2CorrectInverse(4, 4); m2CorrectInverse.setMatrixFromOneDimensionalArray(m2InverseData); m2CorrectInverse = m2CorrectInverse.multiplyByScalar(1.0 / 18.0); //std::cout << "Input matrix: " << std::endl; //m2.print(std::cout, " "); try { m2Inverse = m2.inverse(); problem |= verify("Matrix Inverse (m2)", m2Inverse, m2CorrectInverse); } catch (StatisticException& e) { std::cout << "FAILED: Matrix m2 inverse failed " << e.whatStdString() << std::endl; problem = true; } } // // Test pseudo inverse matrix inverse 2x2 // { const float m1Data[4] = { 3.0, -13.0, -2.0, 9.0 }; const float m1InverseData[4] = { 9.0, 13.0, 2.0, 3 }; StatisticMatrix m1(2, 2); m1.setMatrixFromOneDimensionalArray(m1Data); StatisticMatrix m1Inverse; StatisticMatrix m1CorrectInverse(2,2); m1CorrectInverse.setMatrixFromOneDimensionalArray(m1InverseData); try { m1Inverse = m1.inversePseudo(); problem |= verify("Matrix Pseudo Inverse (m3)", m1Inverse, m1CorrectInverse); } catch (StatisticException& e) { std::cout << "FAILED: Matrix m3 inverse failed " << e.whatStdString() << std::endl; problem = true; } } // // Test matrix pseudo inverse 2x2 of with linear dependent matrix // Inverse values are taken from using Matlab's pinv() on the input matrix // { const float m1Data[4] = { 2, 1, 4, 2 }; const float m1InverseData[4] = { 0.08, 0.16, 0.04, 0.08 }; StatisticMatrix m1(2, 2); m1.setMatrixFromOneDimensionalArray(m1Data); StatisticMatrix m1Inverse; StatisticMatrix m1CorrectInverse(2,2); m1CorrectInverse.setMatrixFromOneDimensionalArray(m1InverseData); try { m1Inverse = m1.inversePseudo(); problem |= verify("Matrix Pseudo Inverse (m4)", m1Inverse, m1CorrectInverse); } catch (StatisticException& e) { std::cout << "FAILED: Matrix m4 pseudo inverse failed " << e.whatStdString() << std::endl; problem = true; } } // // Test matrix pseudo inverse 3x3 of with linear dependent matrix // Inverse values are taken from using Matlab's pinv() on the input matrix // { const float m1Data[9] = { 1, 2, 3, 7, 4, 7, 2, 4, 6 }; const float m1InverseData[9] = { -0.0920, 0.2067, -0.1840, 0.0560, -0.0533, 0.1120, 0.0600, -0.0333, 0.1200 }; StatisticMatrix m1(3, 3); m1.setMatrixFromOneDimensionalArray(m1Data); StatisticMatrix m1Inverse; StatisticMatrix m1CorrectInverse(3,3); m1CorrectInverse.setMatrixFromOneDimensionalArray(m1InverseData); try { m1Inverse = m1.inversePseudo(); problem |= verify("Matrix Pseudo Inverse (m5)", m1Inverse, m1CorrectInverse); } catch (StatisticException& e) { std::cout << "FAILED: Matrix m5 pseudo inverse failed " << e.whatStdString() << std::endl; problem = true; } } // // Test Multiply // { const float dataA[4] = { 9, 13, 2, 3 }; StatisticMatrix ma(2, 2); ma.setMatrixFromOneDimensionalArray(dataA); const float dataB[4] = { 7, 5, -3, -2 }; StatisticMatrix mb(2, 2); mb.setMatrixFromOneDimensionalArray(dataB); const float dataC[4] = { 24, 19, 5, 4 }; StatisticMatrix mc(2, 2); mc.setMatrixFromOneDimensionalArray(dataC); try { const StatisticMatrix product = ma.multiply(mb); problem |= verify("Matrix Multiply (A*B)", product, mc); } catch (StatisticException& e) { std::cout << "FAILED: Matrix multiply A*B failed " << e.whatStdString() << std::endl; problem = true; } } // // Test Multiply // { const float dataA[6] = { 3, -1, 0, 2, 1, -1 }; StatisticMatrix ma(3, 2); ma.setMatrixFromOneDimensionalArray(dataA); const float dataB[8] = { 2, -1, 0, 1, 3, 0, 1, 2 }; StatisticMatrix mb(2, 4); mb.setMatrixFromOneDimensionalArray(dataB); const float dataC[12] = { 3, -3, -1, 1, 6, 0, 2, 4, -1, -1, -1, -1 }; StatisticMatrix mc(3, 4); mc.setMatrixFromOneDimensionalArray(dataC); try { const StatisticMatrix product = ma.multiply(mb); problem |= verify("Matrix Multiply (A*B)", product, mc); } catch (StatisticException& e) { std::cout << "FAILED: Matrix multiply A*B failed " << e.whatStdString() << std::endl; problem = true; } } // // Test Transpose // { const float data[3] = { 1, 2, 3 }; StatisticMatrix ma(1, 3); ma.setMatrixFromOneDimensionalArray(data); StatisticMatrix mb(3, 1); mb.setMatrixFromOneDimensionalArray(data); const StatisticMatrix trans = ma.transpose(); problem |= verify("Matrix Transpose One-Dimensional", trans, mb); } // // Test Transpose // { const float dataA[6] = { 2, 1, -3, 4, -1, 5 }; StatisticMatrix ma(2, 3); ma.setMatrixFromOneDimensionalArray(dataA); const float dataB[6] = { 2, 4, 1, -1, -3, 5 }; StatisticMatrix mb(3, 2); mb.setMatrixFromOneDimensionalArray(dataB); const StatisticMatrix trans = ma.transpose(); problem |= verify("Matrix Transpose 3x2", trans, mb); } if (problem == false) { std::cout << "PASSED StatisticMatrix " << std::endl; } return problem; } /** * test multiple linear regression. */ bool StatisticUnitTesting::testMultipleLinearRegression() { bool problem = false; { // // Example from Applied Linear Regression Models // John Neter, William Wasserman, and Michael H. Kutner // Second Edition // Page 44 // // b = Inverse(Xt * X) * Xt * Y // const int numData = 10; const float xi[numData] = { 30, 20, 60, 80, 40, 50, 60, 30, 70, 60 }; const float yi[numData] = { 73, 50, 128, 170, 87, 108, 135, 69, 148, 132 }; StatisticMultipleRegression regression; regression.setNumberOfIndependentDataGroups(1); regression.setDependentDataArray(yi, numData); regression.setIndependentDataArray(0, xi, numData); try { regression.execute(); } catch (StatisticException& e) { std::cout << "FAILED StatisticMultipleRegression 1-X threw exception: " << e.whatStdString() << std::endl; return true; } std::vector computedCoefficients, correctCoefficients; correctCoefficients.push_back(10.0); correctCoefficients.push_back(2.0); regression.getRegressionCoefficients(computedCoefficients); problem |= verifyCoefficients("Multiple Regression Test 1-X", computedCoefficients, correctCoefficients); } { // // Example from Applied Linear Regression Models // John Neter, William Wasserman, and Michael H. Kutner // Second Edition // Page 207, 249-252 // const int numData = 15; const float y[numData] = { 162, 120, 223, 131, 67, 169, 81, 192, 116, 55, 252, 232, 144, 103, 212 }; const float x1[numData] = { 274, 180, 375, 205, 86, 265, 98, 330, 195, 53, 430, 372, 236, 157, 370 }; const float x2[numData] = { 2450, 3254, 3802, 2838, 2347, 3782, 3008, 2450, 2137, 2560, 4020, 4427, 2660, 2088, 2605 }; StatisticMultipleRegression regression; regression.setNumberOfIndependentDataGroups(2); regression.setDependentDataArray(y, numData); regression.setIndependentDataArray(0, x1, numData); regression.setIndependentDataArray(1, x2, numData); float SSTO, SSE, SSR, MSR, MSE, F, pValue, R2; int regressionDOF, errorDOF, totalDOF; try { regression.execute(); regression.getAnovaParameters(SSTO, SSE, SSR, MSR, MSE, F, pValue, R2, regressionDOF, errorDOF, totalDOF); } catch (StatisticException& e) { std::cout << "FAILED StatisticMultipleRegression 2-X threw exception: " << e.whatStdString() << std::endl; return true; } std::vector computedCoefficients, correctCoefficients; correctCoefficients.push_back(3.452613); correctCoefficients.push_back(0.496005); correctCoefficients.push_back(0.009199); regression.getRegressionCoefficients(computedCoefficients); problem |= verifyCoefficients("Multiple Regression Test 2-X", computedCoefficients, correctCoefficients); problem |= verify("Multiple Regression Test 2-X SSTO", SSTO, 53901.6); problem |= verify("Multiple Regression Test 2-X SSE", SSE, 56.884); problem |= verify("Multiple Regression Test 2-X SSR", SSR, 53844.716, 0.01); problem |= verify("Multiple Regression Test 2-X MSR", MSR, 26922.358, 0.01); problem |= verify("Multiple Regression Test 2-X MSE", MSE, 4.740); problem |= verify("Multiple Regression Test 2-X F", F, 5679.47, //5680.0); 0.01); problem |= verify("Multiple Regression Test 2-X P-Value", pValue, 0.0); problem |= verify("Multiple Regression Test 2-X R2", R2, .9989); problem |= verify("Multiple Regression Test 2-X Regression DOF", regressionDOF, 2.0); problem |= verify("Multiple Regression Test 2-X Error DOF", errorDOF, 12.0); problem |= verify("Multiple Regression Test 2-X Total DOF", totalDOF, 14.0); } { // // Example from Applied Linear Regression Models // John Neter, William Wasserman, and Michael H. Kutner // Second Edition // Page 272 // const int numData = 20; const float y[numData] = { 11.9, 22.8, 18.7, 20.1, 12.9, 21.7, 27.1, 25.4, 21.3, 19.3, 25.4, 27.2, 11.7, 17.8, 12.8, 23.9, 22.6, 25.4, 14.8, 21.1 }; const float x1[numData] = { 19.5, 24.7, 30.7, 29.8, 19.1, 25.6, 31.4, 27.9, 22.1, 25.5, 31.1, 30.4, 18.7, 19.7, 14.6, 29.5, 27.7, 30.2, 22.7, 25.2 }; const float x2[numData] = { 43.1, 49.8, 51.9, 54.3, 42.2, 53.9, 58.5, 52.1, 49.9, 53.5, 56.6, 56.7, 46.5, 44.2, 42.7, 54.4, 55.3, 58.6, 48.2, 51.0 }; const float x3[numData] = { 29.1, 28.2, 37.0, 31.1, 30.9, 23.7, 27.6, 30.6, 23.2, 24.8, 30.0, 28.3, 23.0, 28.6, 21.3, 30.1, 25.7, 24.6, 27.1, 27.5 }; StatisticMultipleRegression regression; regression.setNumberOfIndependentDataGroups(3); regression.setDependentDataArray(y, numData); regression.setIndependentDataArray(0, x1, numData); regression.setIndependentDataArray(1, x2, numData); regression.setIndependentDataArray(2, x3, numData); try { regression.execute(); } catch (StatisticException& e) { std::cout << "FAILED StatisticMultipleRegression 3-X threw exception: " << e.whatStdString() << std::endl; return true; } std::vector computedCoefficients, correctCoefficients; correctCoefficients.push_back(117.084); correctCoefficients.push_back(4.334); correctCoefficients.push_back(-2.857); correctCoefficients.push_back(-2.186); regression.getRegressionCoefficients(computedCoefficients); problem |= verifyCoefficients("Multiple Regression Test 3-X", computedCoefficients, correctCoefficients); } { // // Data from Statistics for Psychology // Arthur Aron & Elaine Aron // 2nd Edition, 1999 // Table 3-2, page 78 // Regression, page 105, 112 // T-stats page 99 const int numData = 5; const float numEmployees[numData] = { 6, 8, 3, 10, 8 }; const float stressLevel[numData] = { 7, 8, 1, 8, 6 }; StatisticDataGroup dependentDataGroup(stressLevel, numData, StatisticDataGroup::DATA_STORAGE_MODE_POINT); StatisticDataGroup independentDataGroup1(numEmployees, numData, StatisticDataGroup::DATA_STORAGE_MODE_POINT); StatisticMultipleRegression regression; regression.setNumberOfIndependentDataGroups(1); regression.setDependentDataArray(stressLevel, numData); regression.setIndependentDataArray(0, numEmployees, numData); float SSTO, SSE, SSR, MSR, MSE, F, pValue, R2; int regressionDOF, errorDOF, totalDOF; try { regression.execute(); regression.getAnovaParameters(SSTO, SSE, SSR, MSR, MSE, F, pValue, R2, regressionDOF, errorDOF, totalDOF); } catch (StatisticException& e) { std::cout << "FAILED StatisticMultipleRegression 4-X threw exception: " << e.whatStdString() << std::endl; return true; } std::vector computedCoefficients, correctCoefficients; correctCoefficients.push_back(-0.75); correctCoefficients.push_back(0.964286); regression.getRegressionCoefficients(computedCoefficients); problem |= verifyCoefficients("Multiple Regression Test 4-X", computedCoefficients, correctCoefficients); problem |= verify("Multiple Regression Test 4-X SSTO", SSTO, 34); problem |= verify("Multiple Regression Test 4-X SSE", SSE, 7.96429); problem |= verify("Multiple Regression Test 4-X SSR", SSR, 26.0357, 0.01); problem |= verify("Multiple Regression Test 4-X MSR", MSR, 26.04, 0.01); problem |= verify("Multiple Regression Test 4-X MSE", MSE, 2.65476); problem |= verify("Multiple Regression Test 4-X F", F, 9.80717, // T=sqrt(9.81) = 3.132 ~= 3.17 0.01); problem |= verify("Multiple Regression Test 4-X P-Value", pValue, 0.052); problem |= verify("Multiple Regression Test 4-X R2", R2, 0.765756); problem |= verify("Multiple Regression Test 4-X Regression DOF", regressionDOF, 1.0); problem |= verify("Multiple Regression Test 4-X Error DOF", errorDOF, 3.0); problem |= verify("Multiple Regression Test 4-X Total DOF", totalDOF, 4.0); } if (problem == false) { std::cout << "PASSED StatisticMultipleRegression " << std::endl; } return problem; } /** * test normalization of a distribution. */ bool StatisticUnitTesting::testNormalizeDistributionSorted() { // // Data is made upt // const int numData = 15; const float data[numData] = { 1, 3, 3, 3, 4, 4, 5, 7, 7, 8, 9, 10, 12, 14, 16 }; const float normValues[numData] = { -5.7, -1.2, -0.85, -0.55, -0.3, -0.1, 0.0, 0.1, 0.3, 0.5, 0.75, 1.05, 1.45, 1.7, 10.0 }; //const float normValues[numData] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; StatisticNormalizeDistribution normal(0.0, 1.0); normal.addDataArray(data, numData); try { normal.execute(); } catch (StatisticException& e) { std::cout << "FAILED StatisticNormalizeDistribution Sorted Data threw exception: " << e.whatStdString() << std::endl; return true; } const StatisticDataGroup* sdgOut = normal.getOutputDataGroupContainingNormalizeValues(); if (sdgOut->getNumberOfData() != numData) { std::cout << "FAILED StatisticNormalizeDistribution Sorted Data output has wrong number of values." << std::endl; return true; } bool problem = false; for (int i = 0; i < numData; i++) { const std::string msg("StatisticNormalizeDistribution Sorted Data output value[" + StatisticAlgorithm::numberToString(i) + "]"); problem |= verify(msg, sdgOut->getData(i), normValues[i]); } if (problem == false) { std::cout << "PASSED StatisticNormalizeDistribution Sorted Data " << std::endl; } return problem; } /** * test normalization of a distribution. */ bool StatisticUnitTesting::testNormalizeDistributionUnsorted() { // // Data is made upt // const int numData = 15; const float data[numData] = { 1, 3, 7, 4, 12, 8, 5, 4, 9, 10, 3, 14, 3, 7, 16 }; const float normValues[numData] = { -5.7, -1.2, 0.1, -0.3, 1.45, 0.5, 0.0, -0.1, 0.75, 1.05, -0.85, 1.7, -0.55, 0.3, 10 }; StatisticNormalizeDistribution normal(0.0, 1.0); normal.addDataArray(data, numData); try { normal.execute(); } catch (StatisticException& e) { std::cout << "FAILED StatisticNormalizeDistribution Unsorted Data threw exception: " << e.whatStdString() << std::endl; return true; } const StatisticDataGroup* sdgOut = normal.getOutputDataGroupContainingNormalizeValues(); if (sdgOut->getNumberOfData() != numData) { std::cout << "FAILED StatisticNormalizeDistribution Unsorted Data output has wrong number of values." << std::endl; return true; } bool problem = false; for (int i = 0; i < numData; i++) { const std::string msg("StatisticNormalizeDistribution Unsorted Data output value[" + StatisticAlgorithm::numberToString(i) + "]"); problem |= verify(msg, sdgOut->getData(i), normValues[i]); } if (problem == false) { std::cout << "PASSED StatisticNormalizeDistribution Unsorted Data" << std::endl; } return problem; } /** * test permutation random shuffle. */ bool StatisticUnitTesting::testPermutationRandomShuffle() { // // Setting the seed results in the same set of random numbers being generated // and the same order each time this test is run // StatisticRandomNumber::setRandomSeed(1234567); // // Data is made up // const int numData = 10; const float data[numData] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; const float shuffledData[numData] = { 3, 5, 2, 1, 7, 8, 6, 9, 10, 4 }; StatisticPermutation perm(StatisticPermutation::PERMUTATION_METHOD_RANDOM_ORDER); perm.addDataArray(data, numData); // // Run the algorithm // try { perm.execute(); } catch (StatisticException& e) { std::cout << "FAILED StatisticPermutation Random Shuffle threw exception: " << e.whatStdString() << std::endl; return true; } const StatisticDataGroup* sdgOut = perm.getOutputData(); if (sdgOut->getNumberOfData() != numData) { std::cout << "FAILED StatisticPermutation Random Shuffle output has wrong number of values." << std::endl; return true; } bool problem = false; for (int i = 0; i < numData; i++) { const std::string msg("StatisticPermutation Random Shuffle output value[" + StatisticAlgorithm::numberToString(i) + "]"); problem |= verify(msg, sdgOut->getData(i), shuffledData[i]); } if (problem == false) { std::cout << "PASSED StatisticPermutation Random Shuffle" << std::endl; } return problem; } /** * test permutation sign flipping. */ bool StatisticUnitTesting::testPermutationSignFlipping() { // // Setting the seed results in the same set of random numbers being generated // and the same order each time this test is run // StatisticRandomNumber::setRandomSeed(1234567); // // Data is made up // const int numData = 10; const float data[numData] = { -1, 2, -3, 4, -5, 6, -7, 8, -9, 10 }; const float signFlippedData[numData] = { -1, -2, 3, -4, -5, 6, -7, 8, -9, -10 }; StatisticPermutation perm(StatisticPermutation::PERMUTATION_METHOD_RANDOM_SIGN_FLIP); perm.addDataArray(data, numData); // // Run the algorithm // try { perm.execute(); } catch (StatisticException& e) { std::cout << "FAILED StatisticPermutation Sign Flip threw exception: " << e.whatStdString() << std::endl; return true; } const StatisticDataGroup* sdgOut = perm.getOutputData(); if (sdgOut->getNumberOfData() != numData) { std::cout << "FAILED StatisticPermutation Sign Flip output has wrong number of values." << std::endl; return true; } bool problem = false; for (int i = 0; i < numData; i++) { const std::string msg("StatisticPermutation Sign Flip output value[" + StatisticAlgorithm::numberToString(i) + "]"); problem |= verify(msg, sdgOut->getData(i), signFlippedData[i]); } if (problem == false) { std::cout << "PASSED StatisticPermutation Sign Flip" << std::endl; } return problem; } caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticTtestTwoSample.h0000664000175000017500000000506411572067322025136 0ustar michaelmichael#ifndef __STATISTIC_T_TEST_TWO_SAMPLE_H__ #define __STATISTIC_T_TEST_TWO_SAMPLE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "StatisticAlgorithm.h" /// algorithm for performing a two-sample T Test class StatisticTtestTwoSample : public StatisticAlgorithm { public: /// variance type enum VARIANCE_TYPE { /// pooled variance (the variances of the sample are the same) VARIANCE_TYPE_POOLED, /// unpooled variance (the variances of the samples are not the same) VARIANCE_TYPE_UNPOOLED }; // constructor StatisticTtestTwoSample(const VARIANCE_TYPE varianceTypeIn); // destructor ~StatisticTtestTwoSample(); // execute the algorithm void execute() throw (StatisticException); // get the t-Value float getTValue() const { return tValue; } /// get the degrees of freedom float getDegreesOfFreedom() const { return degreesOfFreedom; } /// get the p-value float getPValue() const { return pValue; } /// use this value for the variance override void setVarianceOverride(const int groupIndex, const float varianceOverrideIn[2], const bool varianceOverrideFlagIn[2]); protected: /// the variance type VARIANCE_TYPE varianceType; /// the t-value float tValue; /// the degrees of freedom float degreesOfFreedom; /// the p-value float pValue; /// variance override value float varianceOverride[2]; /// use man and deviation override values bool varianceOverrideFlag[2]; }; #endif // __STATISTIC_T_TEST_TWO_SAMPLE_H__ caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticTtestTwoSample.cxx0000664000175000017500000001541511572067322025512 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "StatisticDataGroup.h" #include "StatisticGeneratePValue.h" #include "StatisticMeanAndDeviation.h" #include "StatisticTtestTwoSample.h" /** * constructor. */ StatisticTtestTwoSample::StatisticTtestTwoSample(const VARIANCE_TYPE varianceTypeIn) : StatisticAlgorithm("T-Test Two-Sample") { varianceType = varianceTypeIn; varianceOverride[0] = 0.0; varianceOverride[1] = 0.0; varianceOverrideFlag[0] = false; varianceOverrideFlag[1] = false; } /** * destructor. */ StatisticTtestTwoSample::~StatisticTtestTwoSample() { } /** * use this value for the variance override. */ void StatisticTtestTwoSample::setVarianceOverride(const int groupIndex, const float varianceOverrideIn[2], const bool varianceOverrideFlagIn[2]) { varianceOverride[groupIndex] = varianceOverrideIn[groupIndex]; varianceOverrideFlag[groupIndex] = varianceOverrideFlagIn[groupIndex]; } /** * execute the algorithm. * Formulas are from or equivalent to: * http://www.statsdirect.com/help/parametric_methods/utt.htm */ void StatisticTtestTwoSample::execute() throw (StatisticException) { tValue = 0.0; degreesOfFreedom = 0.0; pValue = 0.0; // // Verify that there are groups // const int numGroups = getNumberOfDataGroups(); if (numGroups != 2) { throw StatisticException("Two-Sample T-Test requires exactly two data groups."); } // // Get the data group // StatisticDataGroup* dataGroup1 = getDataGroup(0); StatisticDataGroup* dataGroup2 = getDataGroup(1); // // Get the number of items in the data groups // const int numData1 = dataGroup1->getNumberOfData(); const int numData2 = dataGroup2->getNumberOfData(); if (numData1 <= 0) { throw StatisticException("First data group sent to Two-Sample T-Test has less than two elements."); } if (numData2 <= 0) { throw StatisticException("Second data group sent to Two-Sample T-Test has less than two elements."); } // // Compute mean, mean, dof, sum-squared, and // variance of dist or diff of means values for first group // StatisticMeanAndDeviation smad1; smad1.addDataGroup(dataGroup1); try { smad1.execute(); } catch (StatisticException& e) { std::string msg("StatisticTtestTwoSample mean/dev failed: " + e.whatStdString()); throw StatisticException(msg); } const float mean1 = smad1.getMean(); const float df1 = numData1 - 1; float populationVariance1 = smad1.getPopulationSampleVariance(); if (varianceOverrideFlag[0]) { populationVariance1 = varianceOverride[0]; } // // Compute mean, mean, dof, sum-squared, and // variance of dist or diff of means values for second group // StatisticMeanAndDeviation smad2; smad2.addDataGroup(dataGroup2); try { smad2.execute(); } catch (StatisticException& e) { std::string msg("StatisticTtestTwoSample mean/dev failed: " + e.whatStdString()); throw StatisticException(msg); } const float mean2 = smad2.getMean(); const float df2 = numData2 - 1; float populationVariance2 = smad2.getPopulationSampleVariance(); if (varianceOverrideFlag[1]) { populationVariance2 = varianceOverride[1]; } // // Denominator for T-Value computation // float denominator = 1.0; // // Compute variance based upon type of variance // switch (varianceType) { case VARIANCE_TYPE_POOLED: { // // degrees of freedom total for pooled variance // degreesOfFreedom = df1 + df2; // // Pooled population variance // const float pooledPopulationVariance = ((df1 * populationVariance1) + (df2 * populationVariance2)) / degreesOfFreedom; // // Denominator for T-Value computation // denominator = std::sqrt(pooledPopulationVariance) * std::sqrt((1.0 / static_cast(numData1)) + (1.0 / static_cast(numData2))); } break; case VARIANCE_TYPE_UNPOOLED: { // // denominator for unpooled variance T-Value // denominator = std::sqrt((populationVariance1 / static_cast(numData1)) + (populationVariance2 / static_cast(numData2))); // // Degrees of freedom for unpooled variance // From http://www.itl.nist.gov/div898/handbook/eda/section3/eda353.htm // const float num1 = numData1; const float num2 = numData2; float numerator = populationVariance1/num1 + populationVariance2/num2; numerator = numerator * numerator; float denom = (1.0 / df1) * (populationVariance1/num1) * (populationVariance1/num1) + (1.0 / df2) * (populationVariance2/num2) * (populationVariance2/num2); degreesOfFreedom = 0.0; if (denom != 0.0) { degreesOfFreedom = numerator / denom; } } } // // Compute the T-Score // tValue = (mean1 - mean2) / denominator; // // Generate the p-value // pValue = StatisticGeneratePValue::getOneTailTTestPValue(degreesOfFreedom, tValue); /* int which = 1; // generate P and Q double p = 0.0; double q = 0.0; double t = std::fabs(tValue); double df = degreesOfFreedom; int status = 0; double bound = 0.0; cdft(&which, &p, &q, &t, &df, &status, &bound); pValue = q; // p is close to one so want q = 1 - p */ } caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticTtestPaired.h0000664000175000017500000000427611572067322024433 0ustar michaelmichael #ifndef __STATISTIC_T_TEST_PAIRED_H__ #define __STATISTIC_T_TEST_PAIRED_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "StatisticAlgorithm.h" /// algorithm for performing a paired (dependent means) T Test /// Use two data groups where first is "after" and the second is "before" class StatisticTtestPaired : public StatisticAlgorithm { public: // constructor StatisticTtestPaired(); // destructor ~StatisticTtestPaired(); // execute the algorithm void execute() throw (StatisticException); // get the t-Value float getTValue() const { return tValue; } /// get the degrees of freedom int getDegreesOfFreedom() const { return degreesOfFreedom; } /// get the p-value float getPValue() const { return pValue; } /// use this value for the variance override void setVarianceOverride(const float varianceOverrideIn, const bool varianceOverrideFlagIn); protected: /// the t-value float tValue; /// the degrees of freedom int degreesOfFreedom; /// the p-value float pValue; /// variance override value float varianceOverride; /// use man and deviation override values bool varianceOverrideFlag; }; #endif // __STATISTIC_T_TEST_PAIRED_H__ caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticTtestPaired.cxx0000664000175000017500000000612711572067322025003 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "StatisticDataGroup.h" #include "StatisticTtestOneSample.h" #include "StatisticTtestPaired.h" /** * constructor. */ StatisticTtestPaired::StatisticTtestPaired() : StatisticAlgorithm("T-Test Paired") { varianceOverride = 0.0; varianceOverrideFlag = false; } /** * destructor. */ StatisticTtestPaired::~StatisticTtestPaired() { } /** * use this value for the variance override. */ void StatisticTtestPaired::setVarianceOverride(const float varianceOverrideIn, const bool varianceOverrideFlagIn) { varianceOverride = varianceOverrideIn; varianceOverrideFlag = varianceOverrideFlagIn; } /** * execute the algorithm. */ void StatisticTtestPaired::execute() throw (StatisticException) { tValue = 0.0; degreesOfFreedom = 0; pValue = 0.0; // // Verify that there are groups // const int numGroups = getNumberOfDataGroups(); if (numGroups != 2) { throw StatisticException("Paired T-Test requires exactly two data groups."); } // // Get the data group // StatisticDataGroup* dataGroupA = getDataGroup(0); StatisticDataGroup* dataGroupB = getDataGroup(1); // // Get the number of items in the data groups // const int numDataA = dataGroupA->getNumberOfData(); const int numDataB = dataGroupB->getNumberOfData(); if (numDataA != numDataB) { throw StatisticException("Data groups sent to Paired T-Test contains a different number of values."); } if (numDataA <= 0) { throw StatisticException("Data groups sent to Paired T-Test contains no data."); } StatisticDataGroup diffDataGroup = *dataGroupA - *dataGroupB; StatisticTtestOneSample tTestOneSample(0.0); tTestOneSample.setVarianceOverride(varianceOverride, varianceOverrideFlag); tTestOneSample.addDataGroup(&diffDataGroup); try { tTestOneSample.execute(); } catch (StatisticException& e) { std::string msg("Failure while using one-sample T-Test: " + e.whatStdString()); throw StatisticException(msg); } tValue = tTestOneSample.getTValue(); degreesOfFreedom = tTestOneSample.getDegreesOfFreedom(); pValue = tTestOneSample.getPValue(); } caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticTtestOneSample.h0000664000175000017500000000444311572067322025106 0ustar michaelmichael #ifndef __STATISTIC_T_TEST_ONE_SAMPLE_H__ #define __STATISTIC_T_TEST_ONE_SAMPLE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "StatisticAlgorithm.h" /// algorithm for performing a one-sample T Test class StatisticTtestOneSample : public StatisticAlgorithm { public: // constructor StatisticTtestOneSample(const float testMeanValueIn = 0); // destructor ~StatisticTtestOneSample(); // execute the algorithm void execute() throw (StatisticException); // get the t-Value float getTValue() const { return tValue; } /// get the degrees of freedom int getDegreesOfFreedom() const { return degreesOfFreedom; } /// get the p-value float getPValue() const { return pValue; } /// use this value for the variance override void setVarianceOverride(const float varianceOverrideIn, const bool varianceOverrideFlagIn); protected: /// test to see if mean of data group is different than this value float testMeanValue; /// the t-value float tValue; /// the degrees of freedom int degreesOfFreedom; /// the p-value float pValue; /// variance override value float varianceOverride; /// use man and deviation override values bool varianceOverrideFlag; }; #endif // __STATISTIC_T_TEST_ONE_SAMPLE_H__ caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticTtestOneSample.cxx0000664000175000017500000001025011572067322025452 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "StatisticDataGroup.h" #include "StatisticGeneratePValue.h" #include "StatisticMeanAndDeviation.h" #include "StatisticTtestOneSample.h" /** * constructor. */ StatisticTtestOneSample::StatisticTtestOneSample(const float testMeanValueIn) : StatisticAlgorithm("T-Test One-Sample") { varianceOverride = 0.0; varianceOverrideFlag = false; testMeanValue = testMeanValueIn; } /** * destructor. */ StatisticTtestOneSample::~StatisticTtestOneSample() { } /** * use this value for the variance override. */ void StatisticTtestOneSample::setVarianceOverride(const float varianceOverrideIn, const bool varianceOverrideFlagIn) { varianceOverride = varianceOverrideIn; varianceOverrideFlag = varianceOverrideFlagIn; } /** * execute the algorithm. * Formulas are from: * A Aron and E Aron * Statistics for Psychology (2nd Edition) * Upper Saddle River, NJ * Prentice Hall * 1999 */ void StatisticTtestOneSample::execute() throw (StatisticException) { tValue = 0.0; degreesOfFreedom = 0; pValue = 0.0; // // Verify that there is only one group // const int numGroups = getNumberOfDataGroups(); if (numGroups != 1) { throw StatisticException("One Sample T-Test requires one and only one data array."); } // // Get the data group // StatisticDataGroup* dataGroup = getDataGroup(0); // // Get the number of items in the data group // const int numData = dataGroup->getNumberOfData(); if (numData <= 0) { throw StatisticException("Data group sent to One Sample T-Test contains no data."); } float mean = 0.0; float estimatedPopulationVarianceSS = 0.0; if (numData == 1) { mean = dataGroup->getData(0); } else { // // Generate the mean and deviation // StatisticMeanAndDeviation smad; smad.addDataGroup(dataGroup); try { smad.execute(); } catch (StatisticException& e) { } mean = smad.getMean(); estimatedPopulationVarianceSS = smad.getPopulationSampleVariance(); } // // Check for variance override // if (varianceOverrideFlag) { estimatedPopulationVarianceSS = varianceOverride; } // // Standard deviation of the distribution of means // const float standardDeviationDistributionOfMeansSM = std::sqrt(estimatedPopulationVarianceSS / static_cast(numData)); // // Generate the T-value // tValue = mean - testMeanValue; if (standardDeviationDistributionOfMeansSM != 0.0) { tValue /= standardDeviationDistributionOfMeansSM; } degreesOfFreedom = numData - 1; // // Generate the p-value // pValue = StatisticGeneratePValue::getOneTailTTestPValue(degreesOfFreedom, tValue); /* int which = 1; // generate P and Q double p = 0.0; double q = 0.0; double t = std::fabs(tValue); double df = degreesOfFreedom; int status = 0; double bound = 0.0; cdft(&which, &p, &q, &t, &df, &status, &bound); pValue = q; // p is close to one so want q = 1 - p */ } caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticTestNames.h0000664000175000017500000000230111572067322024071 0ustar michaelmichael #ifndef __STATISTIC_TEST_NAMES_H__ #define __STATISTIC_TEST_NAMES_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include /// class with names of statistic tests class StatisticTestNames { public: // get the names of the tests static void getTestNames(std::vector& testNames); }; #endif // __STATISTIC_TEST_NAMES_H__ caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticTestNames.cxx0000664000175000017500000000416111572067322024452 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "StatisticTestNames.h" /** * get the names of the tests. */ void StatisticTestNames::getTestNames(std::vector& testNames) { testNames.clear(); testNames.push_back("Correlation statistic"); testNames.push_back("T-statistic"); testNames.push_back("F-statistic"); testNames.push_back("Z-score"); testNames.push_back("Chi-squared distribution"); testNames.push_back("Beta distribution"); testNames.push_back("Binomial distribution"); testNames.push_back("Gamma distribution"); testNames.push_back("Poisson distribution"); testNames.push_back("Normal distribution"); testNames.push_back("F-statistic noncentral"); testNames.push_back("Chi-squared noncentral"); testNames.push_back("Logistic distribution"); testNames.push_back("Laplace distribution"); testNames.push_back("Uniform distribition"); testNames.push_back("T-statistic noncentral"); testNames.push_back("Weibull distribution"); testNames.push_back("Chi distribution"); testNames.push_back("Inverse Gaussian distribution"); testNames.push_back("Extreme Value distribution"); testNames.push_back("P-value"); testNames.push_back("Log P-value"); testNames.push_back("Log10 P-value"); testNames.push_back("Estimate"); } caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticRankTransformation.h0000664000175000017500000000561611572067322026024 0ustar michaelmichael #ifndef __RANK_TRANSFORMATION_H__ #define __RANK_TRANSFORMATION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "StatisticAlgorithm.h" /// class for rank transforming values used with non-parametric statistical procedures class StatisticRankTransformation : public StatisticAlgorithm { public: // constructor StatisticRankTransformation(); // destructor ~StatisticRankTransformation(); // convert the input arrays to ranks void execute() throw (StatisticException); /// get the number of output data groups int getNumberOfOutputDataGroups() const { return outputDataGroupContainingRankValues.size(); } /// get the output data group that contains the ranked values const StatisticDataGroup* getOutputDataGroupContainingRankValues(const int inputArrayNum) const { return outputDataGroupContainingRankValues[inputArrayNum]; } protected: // class used for rank ordering items class RankOrder { public: // Constructor RankOrder(const int arrayNumberIn, const float valueIn, const int valuesArrayIndexIn); // Destructor ~RankOrder() { } // comparison operator for sorting bool operator<(const RankOrder& r) const { return this->value < r.value; } /// value from array float value; /// array value belongs to int arrayNumber; /// index into array int valuesArrayIndex; /// the rank float rank; }; /// process any duplicates in the arrays void processDuplicates(std::vector& ranks); /// used for assigning ranks std::vector ranks; // the output data group containing the ranks std::vector outputDataGroupContainingRankValues; }; #endif // __RANK_TRANSFORMATION_H__ caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticRankTransformation.cxx0000664000175000017500000001410611572067322026371 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "StatisticDataGroup.h" #include "StatisticRankTransformation.h" /** * constructor. * * IMPORTANT: The output data replaces the input data so be sure to create * the input StatisticDataGroup with DATA_STORAGE_MODE_POINT. */ StatisticRankTransformation::StatisticRankTransformation() : StatisticAlgorithm("Rank Transformation") { } /** * destructor. */ StatisticRankTransformation::~StatisticRankTransformation() { for (unsigned int i = 0; i < outputDataGroupContainingRankValues.size(); i++) { if (outputDataGroupContainingRankValues[i] != NULL) { delete outputDataGroupContainingRankValues[i]; outputDataGroupContainingRankValues[i] = NULL; } } } /** * convert the input arrays to ranks. */ void StatisticRankTransformation::execute() throw (StatisticException) { const int numDataGroups = getNumberOfDataGroups(); if (numDataGroups <= 0) { throw StatisticException("StatisticRankTransformation requires at least one data group."); } // // Loop through data groups // for (int i = 0; i < numDataGroups; i++) { // // Get array and count // const StatisticDataGroup* sdg = getDataGroup(i); const float* ptr = sdg->getPointerToData(); const int numElements = sdg->getNumberOfData(); // // load array values into rank sum structure // for (int j = 0; j < numElements; j++) { ranks.push_back(RankOrder(i, ptr[j], j)); } } // // Make sure there is data // if (ranks.empty()) { throw StatisticException("No data supplied to RankTransformation."); } // // Sort by the array values // std::sort(ranks.begin(), ranks.end()); // // set the ranks which start at a value of 1.0 // const int numRanks = static_cast(ranks.size()); for (int i = 0; i < numRanks; i++) { ranks[i].rank = i + 1.0; } // // Adjust ranks for duplicates // processDuplicates(ranks); // // Create output data groups // for (int dataArrayNumber = 0; dataArrayNumber < numDataGroups; dataArrayNumber++) { // // Create an array for input data group // const int numElements = getDataGroup(dataArrayNumber)->getNumberOfData(); float* rankValues = new float[numElements]; // // load the output array // for (int j = 0; j < numRanks; j++) { const RankOrder& rank = ranks[j]; if (rank.arrayNumber == dataArrayNumber) { rankValues[rank.valuesArrayIndex] = rank.rank; } } StatisticDataGroup* sdg = new StatisticDataGroup(rankValues, numElements, StatisticDataGroup::DATA_STORAGE_MODE_TAKE_OWNERSHIP); outputDataGroupContainingRankValues.push_back(sdg); } } /** * Constructor. */ StatisticRankTransformation::RankOrder::RankOrder(const int arrayNumberIn, const float valueIn, const int valuesArrayIndexIn) { value = valueIn; arrayNumber = arrayNumberIn; valuesArrayIndex = valuesArrayIndexIn; rank = 0; } // // All duplicate ranks receive the same ranking // void StatisticRankTransformation::processDuplicates(std::vector& ranks) { const int num = static_cast(ranks.size()); if (num <= 1) { return; } // // Keep track of starting and ending indices of ranks with same value // float currentValue = ranks[0].value; int currentValueStart = 0; int currentValueEnd = 0; // // loop through remaining items // for (int i = 1; i < num; i++) { // // Is this value same as previous values // if (ranks[i].value == currentValue) { // // Update ending index // currentValueEnd = i; } else { // // new value different than last? // if (currentValueStart != currentValueEnd) { // // Determine the average rank and assign it // to all ranks with same value // float sum = 0; for (int j = currentValueStart; j <= currentValueEnd; j++) { sum += ranks[j].rank; } const float numRanks = currentValueEnd - currentValueStart + 1; const float averageRank = sum / numRanks; for (int j = currentValueStart; j <= currentValueEnd; j++) { ranks[j].rank = averageRank; } } // // New value encountered // currentValue = ranks[i].value; currentValueStart = i; currentValueEnd = i; } } // // Handle instance when the last few values are the same // if (currentValueStart != currentValueEnd) { float sum = 0; for (int j = currentValueStart; j <= currentValueEnd; j++) { sum += ranks[j].rank; } const float numRanks = currentValueEnd - currentValueStart + 1; const float averageRank = sum / numRanks; for (int j = currentValueStart; j <= currentValueEnd; j++) { ranks[j].rank = averageRank; } } } caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticRandomNumberOperator.h0000664000175000017500000000237311572067322026304 0ustar michaelmichael #ifndef __STATISTIC_RANDOM_NUMBER_OPERATOR_H__ #define __STATISTIC_RANDOM_NUMBER_OPERATOR_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include /// class for a random number generator object used with standard library algorithms class StatisticRandomNumberOperator { public: // // "()" operator // ptrdiff_t operator() (ptrdiff_t maxNum); }; #endif // __STATISTIC_RANDOM_NUMBER_OPERATOR_H__ caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticRandomNumberOperator.cxx0000664000175000017500000000240211572067322026650 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "StatisticRandomNumber.h" #include "StatisticRandomNumberOperator.h" /** * "()" operator */ ptrdiff_t StatisticRandomNumberOperator::operator() (ptrdiff_t maxNum) { const unsigned int minVal = 0; const unsigned int maxVal = static_cast(maxNum - 1); const ptrdiff_t p = static_cast(StatisticRandomNumber::randomInteger(minVal, maxVal)); return p; } caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticRandomNumber.h0000664000175000017500000000347311572067322024572 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __STATISTIC_RANDOM_NUMBER_H__ #define __STATISTIC_RANDOM_NUMBER_H__ /// class for random number generation class StatisticRandomNumber { public: // generate a random integer within the specified range static float randomFloat(const float minRandomValue, const float maxRandomValue); // generate a random integer within the specified range static int randomInteger(const int minRandomValue, const int maxRandomValue); // generate a random unsigned integer within the specified range static int randomInteger(const unsigned int minRandomValue, const unsigned int maxRandomValue); // set the seed for the random number generator static void setRandomSeed(const int i); }; #endif // __STATISTIC_RANDOM_NUMBER_H__ caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticRandomNumber.cxx0000664000175000017500000000441011572067322025135 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "StatisticRandomNumber.h" /** * generate a random integer within the specified range. */ int StatisticRandomNumber::randomInteger(const int minRandomValue, const int maxRandomValue) { const double dm = maxRandomValue - minRandomValue; int v = minRandomValue + static_cast((dm * std::rand()/(RAND_MAX + 1.0))); return v; } /** * generate a random unsigned integer within the specified range. */ int StatisticRandomNumber::randomInteger(const unsigned int minRandomValue, const unsigned int maxRandomValue) { const double dm = maxRandomValue - minRandomValue; unsigned int v = minRandomValue + static_cast((dm * std::rand()/(RAND_MAX + 1.0))); return v; } /** * generate a random integer within the specified range. */ float StatisticRandomNumber::randomFloat(const float minRandomValue, const float maxRandomValue) { const double dm = maxRandomValue - minRandomValue; float v = minRandomValue + ((dm * std::rand()/(RAND_MAX + 1.0))); v = std::max(minRandomValue, v); v = std::min(maxRandomValue, v); return v; } /** * set the seed for the random number generator. */ void StatisticRandomNumber::setRandomSeed(const int i) { std::srand(i); } caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticPermutation.h0000664000175000017500000000412111572067322024477 0ustar michaelmichael #ifndef __STATISTIC_PERMUTATION_H__ #define __STATISTIC_PERMUTATION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "StatisticAlgorithm.h" class StatisticDataGroup; /// class for permuting a group of values class StatisticPermutation : public StatisticAlgorithm { public: /// permutation method enum PERMUTATION_METHOD { /// randomly flip the signs PERMUTATION_METHOD_RANDOM_SIGN_FLIP, /// randomly reorder the values PERMUTATION_METHOD_RANDOM_ORDER }; // constructor StatisticPermutation(const PERMUTATION_METHOD permutationMethodIn); // destructor ~StatisticPermutation(); // execute the algorithm void execute() throw (StatisticException); /// get the output const StatisticDataGroup* getOutputData() const { return outputDataGroup; } /// generate a random integer static int randomInteger(const int minRandomValue, const int maxRandomValue); protected: /// the output data group StatisticDataGroup* outputDataGroup; /// the permutation method PERMUTATION_METHOD permutationMethod; }; #endif // __STATISTIC_PERMUTATION_H__ caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticPermutation.cxx0000664000175000017500000000615311572067322025061 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "StatisticDataGroup.h" #include "StatisticPermutation.h" #include "StatisticRandomNumber.h" #include "StatisticRandomNumberOperator.h" /** * constructor. */ StatisticPermutation::StatisticPermutation(const PERMUTATION_METHOD permutationMethodIn) : StatisticAlgorithm("Permutation") { permutationMethod = permutationMethodIn; outputDataGroup = NULL; } /** * destructor. */ StatisticPermutation::~StatisticPermutation() { if (outputDataGroup != NULL) { delete outputDataGroup; outputDataGroup = NULL; } } /** * execute the algorithm. */ void StatisticPermutation::execute() throw (StatisticException) { // // Verify the input data group // if (getNumberOfDataGroups() != 1) { throw StatisticException("Normalization only allows one data group."); } StatisticDataGroup* sdg = getDataGroup(0); const int numValues = sdg->getNumberOfData(); if (numValues <= 0) { throw StatisticException("Normalization data group has no values"); } // // Copy the data // std::vector* outputVector = new std::vector; for (int i = 0; i < numValues; i++) { outputVector->push_back(sdg->getData(i)); } // // Apply the appropriate algorithm to the values // switch (permutationMethod) { case PERMUTATION_METHOD_RANDOM_SIGN_FLIP: { // // randomly flip signs of values // for (int i = 0; i < numValues; i++) { if (StatisticRandomNumber::randomInteger(-1000, 1000) < 0) { (*outputVector)[i] = -(*outputVector)[i]; } } } break; case PERMUTATION_METHOD_RANDOM_ORDER: { // // Randomly shuffle the values // StatisticRandomNumberOperator randOp; std::random_shuffle(outputVector->begin(), outputVector->end(), randOp); } break; } // // Create the output data group // outputDataGroup = new StatisticDataGroup(outputVector, StatisticDataGroup::DATA_STORAGE_MODE_TAKE_OWNERSHIP); } caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticNumericalRecipes.h0000664000175000017500000000163011572067322025424 0ustar michaelmichael #ifndef __STATISTIC_NUMERICAL_RECIPES_H__ #define __STATISTIC_NUMERICAL_RECIPES_H__ #include "StatisticException.h" /// code from numerical recipes book class StatisticNumericalRecipes { public: static float SIGN(const float a, const float b); static float FMAX(const float a, const float b); static int IMIN(const int a, const int b); static float SQR(const float a); static float *vector(long nl, long nh) throw (StatisticException); static void free_vector(float *v, long nl, long nh); static float pythag(float a, float b); static float **matrix(long nrl, long nrh, long ncl, long nch) throw (StatisticException); static void free_matrix(float **m, long nrl, long nrh, long ncl, long nch); static void svdcmp(float **a, int m, int n, float w[], float **v) throw (StatisticException); protected: }; #endif // __STATISTIC_NUMERICAL_RECIPES_H__ caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticNumericalRecipes.cxx0000664000175000017500000001550511572067322026005 0ustar michaelmichael #include #include #include #include "StatisticNumericalRecipes.h" static const int NR_END = 1; float StatisticNumericalRecipes::SIGN(const float a, const float b) { return ((b) >= 0.0 ? std::fabs(a) : -std::fabs(a)); } float StatisticNumericalRecipes::FMAX(const float a, const float b) { return std::max(a, b); float maxarg1,maxarg2; return (maxarg1=(a),maxarg2=(b),(maxarg1) > (maxarg2) ?\ (maxarg1) : (maxarg2)); } int StatisticNumericalRecipes::IMIN(const int a, const int b) { return std::min(a, b); int iminarg1,iminarg2; return (iminarg1=(a),iminarg2=(b),(iminarg1) < (iminarg2) ?\ (iminarg1) : (iminarg2)); } float StatisticNumericalRecipes::SQR(const float a) { float sqrarg; return ((sqrarg=(a)) == 0.0 ? 0.0 : sqrarg*sqrarg); } float* StatisticNumericalRecipes::vector(long nl, long nh) throw (StatisticException) /* allocate a float vector with subscript range v[nl..nh] */ { float *v; v=(float *)std::malloc((size_t) ((nh-nl+1+NR_END)*sizeof(float))); if (!v) throw StatisticException("allocation failure in vector()"); return v-nl+NR_END; } void StatisticNumericalRecipes::free_vector(float *v, long nl, long /*nh*/) /* free a float vector allocated with vector() */ { std::free((char*) (v+nl-NR_END)); } float StatisticNumericalRecipes::pythag(float a, float b) { float absa,absb; absa=std::fabs(a); absb=std::fabs(b); if (absa > absb) return absa*sqrt(1.0+SQR(absb/absa)); else return (absb == 0.0 ? 0.0 : absb*sqrt(1.0+SQR(absa/absb))); } float ** StatisticNumericalRecipes::matrix(long nrl, long nrh, long ncl, long nch) throw (StatisticException) /* allocate a float matrix with subscript range m[nrl..nrh][ncl..nch] */ { long i, nrow=nrh-nrl+1,ncol=nch-ncl+1; float **m; /* allocate pointers to rows */ m=(float **) std::malloc((size_t)((nrow+NR_END)*sizeof(float*))); if (!m) throw StatisticException("allocation failure 1 in matrix()"); m += NR_END; m -= nrl; /* allocate rows and set pointers to them */ m[nrl]=(float *) std::malloc((size_t)((nrow*ncol+NR_END)*sizeof(float))); if (!m[nrl]) throw StatisticException("allocation failure 2 in matrix()"); m[nrl] += NR_END; m[nrl] -= ncl; for(i=nrl+1;i<=nrh;i++) m[i]=m[i-1]+ncol; /* return pointer to array of pointers to rows */ return m; } void StatisticNumericalRecipes::free_matrix(float **m, long nrl, long /*nrh*/, long ncl, long /*nch*/) /* free a float matrix allocated by matrix() */ { std::free((char*) (m[nrl]+ncl-NR_END)); std::free((char*) (m+nrl-NR_END)); } void StatisticNumericalRecipes::svdcmp(float **a, int m, int n, float w[], float **v) throw (StatisticException) { int flag,i,its,j,jj,k,l,nm; float anorm,c,f,g,h,s,scale,x,y,z,*rv1; rv1=vector(1,n); g=scale=anorm=0.0; for (i=1;i<=n;i++) { l=i+1; rv1[i]=scale*g; g=s=scale=0.0; if (i <= m) { for (k=i;k<=m;k++) scale += std::fabs(a[k][i]); if (scale) { for (k=i;k<=m;k++) { a[k][i] /= scale; s += a[k][i]*a[k][i]; } f=a[i][i]; g = -SIGN(sqrt(s),f); h=f*g-s; a[i][i]=f-g; for (j=l;j<=n;j++) { for (s=0.0,k=i;k<=m;k++) s += a[k][i]*a[k][j]; f=s/h; for (k=i;k<=m;k++) a[k][j] += f*a[k][i]; } for (k=i;k<=m;k++) a[k][i] *= scale; } } w[i]=scale *g; g=s=scale=0.0; if (i <= m && i != n) { for (k=l;k<=n;k++) scale += std::fabs(a[i][k]); if (scale) { for (k=l;k<=n;k++) { a[i][k] /= scale; s += a[i][k]*a[i][k]; } f=a[i][l]; g = -SIGN(sqrt(s),f); h=f*g-s; a[i][l]=f-g; for (k=l;k<=n;k++) rv1[k]=a[i][k]/h; for (j=l;j<=m;j++) { for (s=0.0,k=l;k<=n;k++) s += a[j][k]*a[i][k]; for (k=l;k<=n;k++) a[j][k] += s*rv1[k]; } for (k=l;k<=n;k++) a[i][k] *= scale; } } anorm=FMAX(anorm,(std::fabs(w[i])+std::fabs(rv1[i]))); } for (i=n;i>=1;i--) { if (i < n) { if (g) { for (j=l;j<=n;j++) v[j][i]=(a[i][j]/a[i][l])/g; for (j=l;j<=n;j++) { for (s=0.0,k=l;k<=n;k++) s += a[i][k]*v[k][j]; for (k=l;k<=n;k++) v[k][j] += s*v[k][i]; } } for (j=l;j<=n;j++) v[i][j]=v[j][i]=0.0; } v[i][i]=1.0; g=rv1[i]; l=i; } for (i=IMIN(m,n);i>=1;i--) { l=i+1; g=w[i]; for (j=l;j<=n;j++) a[i][j]=0.0; if (g) { g=1.0/g; for (j=l;j<=n;j++) { for (s=0.0,k=l;k<=m;k++) s += a[k][i]*a[k][j]; f=(s/a[i][i])*g; for (k=i;k<=m;k++) a[k][j] += f*a[k][i]; } for (j=i;j<=m;j++) a[j][i] *= g; } else for (j=i;j<=m;j++) a[j][i]=0.0; ++a[i][i]; } for (k=n;k>=1;k--) { for (its=1;its<=30;its++) { flag=1; for (l=k;l>=1;l--) { nm=l-1; if ((float)(std::fabs(rv1[l])+anorm) == anorm) { flag=0; break; } if ((float)(std::fabs(w[nm])+anorm) == anorm) break; } if (flag) { c=0.0; s=1.0; for (i=l;i<=k;i++) { f=s*rv1[i]; rv1[i]=c*rv1[i]; if ((float)(std::fabs(f)+anorm) == anorm) break; g=w[i]; h=pythag(f,g); w[i]=h; h=1.0/h; c=g*h; s = -f*h; for (j=1;j<=m;j++) { y=a[j][nm]; z=a[j][i]; a[j][nm]=y*c+z*s; a[j][i]=z*c-y*s; } } } z=w[k]; if (l == k) { if (z < 0.0) { w[k] = -z; for (j=1;j<=n;j++) v[j][k] = -v[j][k]; } break; } if (its == 30) throw StatisticException("no convergence in 30 svdcmp iterations"); x=w[l]; nm=k-1; y=w[nm]; g=rv1[nm]; h=rv1[k]; f=((y-z)*(y+z)+(g-h)*(g+h))/(2.0*h*y); g=pythag(f,1.0); f=((x-z)*(x+z)+h*((y/(f+SIGN(g,f)))-h))/x; c=s=1.0; for (j=l;j<=nm;j++) { i=j+1; g=rv1[i]; y=w[i]; h=s*g; g=c*g; z=pythag(f,h); rv1[j]=z; c=f/z; s=h/z; f=x*c+g*s; g = g*c-x*s; h=y*s; y *= c; for (jj=1;jj<=n;jj++) { x=v[jj][j]; z=v[jj][i]; v[jj][j]=x*c+z*s; v[jj][i]=z*c-x*s; } z=pythag(f,h); w[j]=z; if (z) { z=1.0/z; c=f*z; s=h*z; } f=c*g+s*y; x=c*y-s*g; for (jj=1;jj<=m;jj++) { y=a[jj][j]; z=a[jj][i]; a[jj][j]=y*c+z*s; a[jj][i]=z*c-y*s; } } rv1[l]=0.0; rv1[k]=f; w[k]=x; } } free_vector(rv1,1,n); } /* int main(int argc, char* argv[]) { float** a = matrix(1, 2, 1, 2); float* w = vector(1, 4); float** v = matrix(1, 2, 1, 2); int i, j; a[1][1] = 3.0; a[1][2] = -13.0; a[2][1] = -2.0; a[2][2] = 9.0; svdcmp(a, 2, 2, w, v); std::printf("A\n"); for (i = 1; i <= 2; i++) { for (j = 1; j <= 2; j++) { printf(" %d, %d: %f\n", i, j, a[i][j]); } } std::printf("V\n"); for (i = 1; i <= 2; i++) { for (j = 1; j <= 2; j++) { std::printf(" %d, %d: %f\n", i, j, v[i][j]); } } std::printf("W\n"); for (i = 1; i <= 2; i++) { std::printf(" %d: %f\n", i, w[i]); } } */ caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticNormalizeDistribution.h0000664000175000017500000000576411572067322026546 0ustar michaelmichael#ifndef __STATISTIC_NORMALIZE_DISTRIBUTION_H__ #define __STATISTIC_NORMALIZE_DISTRIBUTION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "StatisticAlgorithm.h" // remap a set of values so that they fit a normal distribution class StatisticNormalizeDistribution : public StatisticAlgorithm { public: // constructor StatisticNormalizeDistribution(const float meanIn = 0.0, const float deviationIn = 0.0); // destructor ~StatisticNormalizeDistribution(); // execute the normalization void execute() throw (StatisticException); // get the output data group that contains the normalized values const StatisticDataGroup* getOutputDataGroupContainingNormalizeValues() const { return outputDataGroupContainingNormalizeValues; } protected: /// normalization method enum NORMALIZE_METHOD { /// normalize so that values are mapped ONLY to the left of the mean NORMALIZE_METHOD_BELOW_MEAN, /// normalize so that values are mapped ONLY to the right of the mean NORMALIZE_METHOD_ABOVE_MEAN, /// normalize using all of curve NORMALIZE_METHOD_ALL }; // normalize so median is at mean void normalizeHelper(float* valuesInOut, const int numValues, const NORMALIZE_METHOD normMethod, const float mean, const float deviation) throw (StatisticException); // Rescale a sorted set of values to a new range. void rescaleSortedValues(float* values, const int numValues, const float outputMinimum, const float outputMaximum); /// mean value for normal distribution float mean; /// deviation for normal distribution float deviation; // the output data group StatisticDataGroup* outputDataGroupContainingNormalizeValues; }; #endif // __STATISTIC_NORMALIZE_DISTRIBUTION_H__ caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticNormalizeDistribution.cxx0000664000175000017500000002427411572067322027116 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "StatisticDataGroup.h" #include "StatisticNormalizeDistribution.h" #include "StatisticValueIndexSort.h" /** * constructor. This algorithm functions on one and only one StatisticDataGroup. * * IMPORTANT: The output data replaces the input data so be sure to create * the input StatisticDataGroup with DATA_STORAGE_MODE_POINT. */ StatisticNormalizeDistribution::StatisticNormalizeDistribution(const float meanIn, const float deviationIn) : StatisticAlgorithm("Normalize Distribution") { outputDataGroupContainingNormalizeValues = NULL; mean = meanIn; deviation = deviationIn; } /** * destructor. */ StatisticNormalizeDistribution::~StatisticNormalizeDistribution() { if (outputDataGroupContainingNormalizeValues != NULL) { delete outputDataGroupContainingNormalizeValues; outputDataGroupContainingNormalizeValues = NULL; } } /** * execute the normalization. */ void StatisticNormalizeDistribution::execute() throw (StatisticException) { // // Verify the input data group // if (getNumberOfDataGroups() != 1) { throw StatisticException("Normalization only allows one data group."); } StatisticDataGroup* sdg = getDataGroup(0); const int numValues = sdg->getNumberOfData(); if (numValues <= 0) { throw StatisticException("Normalization data group has no values"); } float* outputNormalizedValues = new float[numValues]; if (numValues == 1) { outputNormalizedValues[0] = mean; } else { StatisticValueIndexSort svis; svis.addDataGroup(sdg); svis.execute(); if (svis.getNumberOfItems() != numValues) { throw StatisticException("StatisticValueIndexSort failed (has wrong number of values)."); } // // Sort the values (need indices for output so data remains in origin "temporal" order) // std::vector indices(numValues); std::vector values(numValues); for (int i = 0; i < numValues; i++) { svis.getValueAndOriginalIndex(i, indices[i], values[i]); } // // Get the index of the median value // const int medianIndex = numValues / 2; // // Do the half below the median // normalizeHelper(&values[0], medianIndex, NORMALIZE_METHOD_BELOW_MEAN, mean, deviation); // // Do the half below the median // normalizeHelper(&values[medianIndex], (numValues - medianIndex), NORMALIZE_METHOD_ABOVE_MEAN, mean, deviation); // // Put values back in "temporal" location // for (int i = 0; i < numValues; i++) { outputNormalizedValues[indices[i]] = values[i]; } } outputDataGroupContainingNormalizeValues = new StatisticDataGroup(outputNormalizedValues, numValues, StatisticDataGroup::DATA_STORAGE_MODE_TAKE_OWNERSHIP); } /** * normalize so median is at mean. */ void StatisticNormalizeDistribution::normalizeHelper(float* valuesInOut, const int numValues, const NORMALIZE_METHOD normMethod, const float mean, const float deviation) throw (StatisticException) { if (numValues <= 0) { return; } if (numValues == 1) { valuesInOut[0] = mean; return; } // // Sort the values (need indices for output so data remains in origin "temporal" order) // StatisticDataGroup sdg(valuesInOut, numValues, StatisticDataGroup::DATA_STORAGE_MODE_POINT); StatisticValueIndexSort svis; svis.addDataGroup(&sdg); svis.execute(); if (svis.getNumberOfItems() != numValues) { throw StatisticException("StatisticValueIndexSort failed (has wrong number of values)."); } std::vector indices(numValues); std::vector values(numValues); for (int i = 0; i < numValues; i++) { svis.getValueAndOriginalIndex(i, indices[i], values[i]); } // // number of values remapped // int numRemapped = 0; const double oneOverSigmaSqrt2Pi = 1.0 / (deviation * std::sqrt(2.0 * M_PI)); const double deltaX = 0.1; double cumulativeAreaUnderCurve = 0.0; const double tailSize = deviation * 10.0; double maxX = mean + tailSize; double minX = mean - tailSize; double totalArea = 1.0; // // Limit depending upon part of curve that is being used // switch (normMethod) { case NORMALIZE_METHOD_BELOW_MEAN: totalArea = 0.5; maxX = mean; break; case NORMALIZE_METHOD_ABOVE_MEAN: totalArea = 0.5; minX = mean; break; case NORMALIZE_METHOD_ALL: break; } float prevVal = 0.0; bool prevValValid = false; // // For values that do not get mapped due to numerical error // double lastMappedValueX = minX; double prevAreaUnderCurve = 0.0; for (double x = minX; x <= maxX; x += deltaX) { // // Determine the gaussian value for this scalar // const double numeratorE = (x - mean) * (x - mean); const double denominatorE = 2.0 * deviation * deviation; const double t = std::exp(-(numeratorE / denominatorE)); const double val = t * oneOverSigmaSqrt2Pi; if (prevValValid) { // // Determine the area under the curve between previous and current scalar // const double areaUnderCurveDelta = (((val + prevVal) * 0.5) * deltaX); cumulativeAreaUnderCurve += areaUnderCurveDelta; if (getDebugOn()) { std::cout << "f(" << x << ") = " << val << " F(" << x << ") = " << cumulativeAreaUnderCurve << std::endl; } // // Percentage under curve // const double percentUnderCurve = (areaUnderCurveDelta + prevAreaUnderCurve) / totalArea; // // number of values for this part under the curve // int numValuesUnderCurve = static_cast(percentUnderCurve * numValues); // // Remap the nodes // if (numValuesUnderCurve > 0) { // // Limit so that total number of nodes is not exceeded // if ((numValuesUnderCurve + numRemapped) > numValues) { numValuesUnderCurve = numValues - numRemapped; } // // Remap the values // //rescaleSortedValues(&values[numRemapped], numValuesUnderCurve, x - deltaX, x); rescaleSortedValues(&values[numRemapped], numValuesUnderCurve, lastMappedValueX, x); // // Update number of nodes remapped // numRemapped += numValuesUnderCurve; if (numRemapped >= numValues) { break; } // // Save last mapped values // lastMappedValueX = x; // // start new accumulation of area // prevAreaUnderCurve = 0.0; } else { // // Accumulate area under curve needed if number of values is small // prevAreaUnderCurve += areaUnderCurveDelta; } } prevVal = val; prevValValid = true; } // // Process any remaining values // if (numRemapped < numValues) { rescaleSortedValues(&values[numRemapped], (numValues - numRemapped), lastMappedValueX, maxX); //for (int i = numRemapped; i < numValues; i++) { // values[i] = (lastMappedValueX + maxX) / 2.0; //} } // // Put values back in "temporal" location // for (int i = 0; i < numValues; i++) { valuesInOut[indices[i]] = values[i]; } if (getDebugOn()) { std::cout << "Area under curve: " << cumulativeAreaUnderCurve << std::endl; } } /** * Rescale a sorted set of values to a new range. */ void StatisticNormalizeDistribution::rescaleSortedValues(float* values, const int numValues, const float outputMinimum, const float outputMaximum) { if (numValues <= 0) { return; } const float inputMinimum = values[0]; const float inputMaximum = values[numValues - 1]; float inputDiff = inputMaximum - inputMinimum; if (inputDiff == 0.0) { for (int i = 0; i < numValues; i++) { values[i] = (outputMinimum + outputMaximum) / 2.0; } return; } const float outputDiff = outputMaximum - outputMinimum; for (int i = 0; i < numValues; i++) { float f = values[i]; const float normalized = (f - inputMinimum) / inputDiff; f = normalized * outputDiff + outputMinimum; values[i] = f; } } caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticMultipleRegression.h0000664000175000017500000001013011572067322026021 0ustar michaelmichael #ifndef __STATISTIC_MULTIPLE_LINEAR_REGRESSION_H__ #define __STATISTIC_MULTIPLE_LINEAR_REGRESSION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "StatisticAlgorithm.h" #include "StatisticMatrix.h" /// class for computing multiple linear regression class StatisticMultipleRegression : public StatisticAlgorithm { public: // constructor StatisticMultipleRegression(); // destructor ~StatisticMultipleRegression(); // execute the algorithm void execute() throw (StatisticException); // get the regression coefficients void getRegressionCoefficients(std::vector& coefficientsOut) const; // set the number of independent data groups void setNumberOfIndependentDataGroups(const int numGroups); // get the number of independent data groups int getNumberOfIndependentDataGroups() const { return independentDataGroups.size(); } // set the independent data group (must call setNumberOfIndependentDataGroups() before this) void setIndependentDataGroup(const int groupNumber, StatisticDataGroup* dataGroup, const bool takeOwnershipOfTheData = false); // set the independent data (must call setNumberOfIndependentDataGroups() before this) void setIndependentDataArray(const int groupNumber, const float* array, const int numItemsInArray, const bool takeOwnershipOfThisData = false); // set the dependent data group void setDependentDataGroup(StatisticDataGroup* dataGroup, const bool takeOwnershipOfTheData = false); // set the dependent data void setDependentDataArray(const float* array, const int numItemsInArray, const bool takeOwnershipOfThisData = false); // get the ANOVA parameters (must be called AFTER execute()) void getAnovaParameters(float& SSTO, float& SSE, float& SSR, float& MSR, float& MSE, float& F, float& pValue, float& R2, int& regressionDOF, int& errorDOF, int& totalDOF) throw (StatisticException); protected: // coefficients std::vector coefficients; // the independent data groups (X) (do not delete elements in StatisticAlgorithm will) std::vector independentDataGroups; // the dependent data group (Y) StatisticDataGroup* dependentDataGroup; // X - The indepenent variables matrix StatisticMatrix X; // Y - the Dependent variables matrix StatisticMatrix Y; // Transpose of X StatisticMatrix Xt; // the coefficients StatisticMatrix b; }; #endif // __STATISTIC_MULTIPLE_LINEAR_REGRESSION_H__ caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticMultipleRegression.cxx0000664000175000017500000002546611572067322026416 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include "StatisticDataGroup.h" #include "StatisticGeneratePValue.h" #include "StatisticMatrix.h" #include "StatisticMultipleRegression.h" /** * constructor. */ StatisticMultipleRegression::StatisticMultipleRegression() : StatisticAlgorithm("Multiple Linear Regression") { dependentDataGroup = NULL; } /** * destructor. */ StatisticMultipleRegression::~StatisticMultipleRegression() { independentDataGroups.clear(); // do not delete elements !! dependentDataGroup = NULL; } /** * execute the algorithm. * * This algorithm is from Applied Linear Regression Models * John Neter, William Wasserman, and Michael H. Kutner * Second Edition * Page 252 */ void StatisticMultipleRegression::execute() throw (StatisticException) { // // Check inputs // if (dependentDataGroup == NULL) { throw StatisticException("Dependent data group is invalid (NULL)"); } const int numIndependentDataGroups = static_cast(independentDataGroups.size()); if (numIndependentDataGroups <= 0) { throw StatisticException("No Independent data groups "); } for (int i = 0; i < numIndependentDataGroups; i++) { if (independentDataGroups[i] == NULL) { std::ostringstream str; str << "Independent data group " << i << " is invalid (NULL)"; throw StatisticException(str.str()); } } const int numData = dependentDataGroup->getNumberOfData(); if (numData <= 0) { throw StatisticException("Dependent data group contains no elements."); } for (int i = 0; i < numIndependentDataGroups; i++) { if (independentDataGroups[i]->getNumberOfData() != numData) { std::ostringstream str; str << "Independent data group " << i << " has a different number of elements than dependent data group."; throw StatisticException(str.str()); } } // // Y - the Dependent variables matrix // Y.setDimensions(numData, 1); // // X - The indepenent variables matrix // X.setDimensions(numData, numIndependentDataGroups + 1); // // Load the matrices // for (int i = 0; i < numData; i++) { Y.setElement(i, 0, dependentDataGroup->getData(i)); X.setElement(i, 0, 1.0); for (int j = 0; j < numIndependentDataGroups; j++) { X.setElement(i, (j + 1), independentDataGroups[j]->getData(i)); } } if (getDebugOn()) { X.print(std::cout, " ", "X"); Y.print(std::cout, " ", "Y"); } // // Transpose of X // Xt = X.transpose(); if (getDebugOn()) { Xt.print(std::cout, " ", "Xt"); } // // X-transpose times X // const StatisticMatrix XtX = Xt.multiply(X); if (getDebugOn()) { XtX.print(std::cout, " ", "XtX"); } // // Inverse of X-transpose times X // const StatisticMatrix IXtX = XtX.inverse(); if (getDebugOn()) { IXtX.print(std::cout, " ", "IXtX"); } // // X-transpose times Y // const StatisticMatrix XtY = Xt.multiply(Y); if (getDebugOn()) { XtY.print(std::cout, " ", "XtY"); } // // Calculate the coefficients // b = IXtX.multiply(XtY); if (getDebugOn()) { b.print(std::cout, " ", "b"); } // // Make coefficients avaialble to the user // coefficients.clear(); for (int i = 0; i < b.getNumberOfRows(); i++) { coefficients.push_back(b.getElement(i, 0)); } } /** * get the ANOVA parameters (must be called AFTER execute()). * This algorithm is from Applied Linear Regression Models * John Neter, William Wasserman, and Michael H. Kutner * Second Edition * Page 256 */ void StatisticMultipleRegression::getAnovaParameters(float& SSTO, float& SSE, float& SSR, float& MSR, float& MSE, float& F, float& pValue, float& R2, int& regressionDOF, int& errorDOF, int& totalDOF) throw (StatisticException) { const int numData = dependentDataGroup->getNumberOfData(); // // transpose of Y // const StatisticMatrix Yt = Y.transpose(); // // Y-transpose times Y // const StatisticMatrix YtY = Yt.multiply(Y); if ((YtY.getNumberOfRows() != 1) && (YtY.getNumberOfColumns() != 1)) { std::ostringstream str; str << "YtY Matrix should be a 1x1 matrix but is " << YtY.getNumberOfRows() << "x" << YtY.getNumberOfColumns() << "."; throw StatisticException(str.str()); } const double YtYValue = YtY.getElement(0, 0); // // J is matrix of all ones // StatisticMatrix J(numData, numData); J.setAllElements(1.0); // // (1/N)Y'JY // const StatisticMatrix YtJY = Yt.multiply(J).multiply(Y); if ((YtJY.getNumberOfRows() != 1) && (YtJY.getNumberOfColumns() != 1)) { std::ostringstream str; str << "Y'JY Matrix should be a 1x1 matrix but is " << YtJY.getNumberOfRows() << "x" << YtJY.getNumberOfColumns() << "."; throw StatisticException(str.str()); } const double YtJYValue = YtJY.getElement(0, 0) / static_cast(numData); // // SSTO = Y'Y - (1/n)Y'JY; // SSTO = YtYValue - YtJYValue; // // Transpose of b // const StatisticMatrix bt = b.transpose(); // // b'X'Y // const StatisticMatrix btXtY = bt.multiply(Xt).multiply(Y); if ((btXtY.getNumberOfRows() != 1) && (btXtY.getNumberOfColumns() != 1)) { std::ostringstream str; str << "b'X'Y Matrix should be a 1x1 matrix but is " << btXtY.getNumberOfRows() << "x" << btXtY.getNumberOfColumns() << "."; throw StatisticException(str.str()); } const double btXtYValue = btXtY.getElement(0, 0);; // // SSE = Y'Y - b'X'Y from p 256 // SSE = YtYValue - btXtYValue; // // SSR = SSTO - SSE // SSR = SSTO - SSE; // // Degrees of Freedom // regressionDOF = getNumberOfIndependentDataGroups(); errorDOF = numData - (getNumberOfIndependentDataGroups() + 1); totalDOF = regressionDOF + errorDOF; // // MSR // MSR = SSR / static_cast(regressionDOF); // // MSE // MSE = SSE / static_cast(errorDOF); // // F // F = MSR / MSE; // // P-Value for F // pValue = StatisticGeneratePValue::getFStatisticPValue(regressionDOF, errorDOF, F); // // Coefficient of Multiple Determination // R2 = SSR / SSTO; } /** * get the regression coefficients. */ void StatisticMultipleRegression::getRegressionCoefficients(std::vector& coefficientsOut) const { coefficientsOut = coefficients; } /** * set the number of independent data groups. */ void StatisticMultipleRegression::setNumberOfIndependentDataGroups(const int numGroups) { independentDataGroups.resize(numGroups, NULL); } /** * set the independent data group. */ void StatisticMultipleRegression::setIndependentDataGroup(const int groupNumber, StatisticDataGroup* dataGroup, const bool takeOwnershipOfThisDataGroup) { const int indx = addDataGroup(dataGroup, takeOwnershipOfThisDataGroup); independentDataGroups[groupNumber] = getDataGroup(indx); } /** * set the independent data (must call setNumberOfIndependentDataGroups() before this). */ void StatisticMultipleRegression::setIndependentDataArray(const int groupNumber, const float* array, const int numItemsInArray, const bool takeOwnershipOfTheData) { StatisticDataGroup::DATA_STORAGE_MODE storageMode = StatisticDataGroup::DATA_STORAGE_MODE_POINT; if (takeOwnershipOfTheData) { storageMode = StatisticDataGroup::DATA_STORAGE_MODE_TAKE_OWNERSHIP; } StatisticDataGroup* sdg = new StatisticDataGroup(array, numItemsInArray, storageMode); setIndependentDataGroup(groupNumber, sdg, true); } /** * set the dependent data group. */ void StatisticMultipleRegression::setDependentDataGroup(StatisticDataGroup* dataGroup, const bool takeOwnershipOfThisDataGroup) { const int indx = addDataGroup(dataGroup, takeOwnershipOfThisDataGroup); dependentDataGroup = getDataGroup(indx); } /** * set the dependent data. */ void StatisticMultipleRegression::setDependentDataArray(const float* array, const int numItemsInArray, const bool takeOwnershipOfTheData) { StatisticDataGroup::DATA_STORAGE_MODE storageMode = StatisticDataGroup::DATA_STORAGE_MODE_POINT; if (takeOwnershipOfTheData) { storageMode = StatisticDataGroup::DATA_STORAGE_MODE_TAKE_OWNERSHIP; } StatisticDataGroup* sdg = new StatisticDataGroup(array, numItemsInArray, storageMode); setDependentDataGroup(sdg, true); } caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticMeanAndDeviation.h0000664000175000017500000000531111572067322025340 0ustar michaelmichael #ifndef __STATISTIC_MEAN_AND_DEVIATION_H__ #define __STATISTIC_MEAN_AND_DEVIATION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "StatisticAlgorithm.h" /// class for computation of mean and deviations /// Use sample deviation if data is a sample from a population /// Use deviation if data is the ENTIRE population class StatisticMeanAndDeviation : public StatisticAlgorithm { public: // constructor StatisticMeanAndDeviation(); // destructor ~StatisticMeanAndDeviation(); // generate the mean and deviation void execute() throw (StatisticException); /// get the mean float getMean() const { return mean; } /// get the sample of population standard deviation (divide by N - 1) float getPopulationSampleStandardDeviation() const { return populationSampleDeviation; } /// get the sample of population variance (divied by N - 1) float getPopulationSampleVariance() const { return populationSampleVariance; } /// get the standard deviation float getStandardDeviation() const { return deviation; } /// get the variance float getVariance() const { return variance; } /// get the sum of squares double getSumOfSquares() const { return sumOfSquares; } protected: // the mean of the data float mean; // the sample from population deviation of the data (divide by N - 1) float populationSampleDeviation; // the sample from population variance of the data (divide by N - 1) float populationSampleVariance; // the population deviation of the data (divide by N) float deviation; // the population variance of the data (divide by N) float variance; // sum of squares double sumOfSquares; }; #endif // __STATISTIC_MEAN_AND_DEVIATION_H__ caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticMeanAndDeviation.cxx0000664000175000017500000000560411572067322025720 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "StatisticDataGroup.h" #include "StatisticMeanAndDeviation.h" /** * constructor. */ StatisticMeanAndDeviation::StatisticMeanAndDeviation() : StatisticAlgorithm("Mean and Deviation") { mean = 0.0; populationSampleDeviation = 0.0; populationSampleVariance = 0.0; deviation = 0.0; variance = 0.0; sumOfSquares = 0.0; } /** * destructor. */ StatisticMeanAndDeviation::~StatisticMeanAndDeviation() { } /** * generate the mean and deviation. * Formulas are from: * A Aron and E Aron * Statistics for Psychology (2nd Edition) * Upper Saddle River, NJ * Prentice Hall * 1999 */ void StatisticMeanAndDeviation::execute() throw (StatisticException) { mean = 0.0; populationSampleDeviation = 0.0; populationSampleVariance = 0.0; deviation = 0.0; variance = 0.0; sumOfSquares = 0.0; int totalNumberOfData = 0; // // Determine mean // double meanSum = 0.0; for (int i = 0; i < getNumberOfDataGroups(); i++) { const StatisticDataGroup* sdg = getDataGroup(i); const float* data = sdg->getPointerToData(); const int numData = sdg->getNumberOfData(); for (int j = 0; j < numData; j++) { meanSum += data[j]; totalNumberOfData++; } } mean = meanSum / static_cast(totalNumberOfData); // // Determine deviation // for (int i = 0; i < getNumberOfDataGroups(); i++) { const StatisticDataGroup* sdg = getDataGroup(i); const float* data = sdg->getPointerToData(); const int numData = sdg->getNumberOfData(); for (int j = 0; j < numData; j++) { const double diff = data[j] - mean; sumOfSquares += (diff * diff); } } if (totalNumberOfData > 1) { variance = sumOfSquares / static_cast(totalNumberOfData); deviation = std::sqrt(variance); populationSampleVariance = sumOfSquares / static_cast(totalNumberOfData - 1); populationSampleDeviation = std::sqrt(populationSampleVariance); } } caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticMatrix.h0000664000175000017500000001040011572067322023431 0ustar michaelmichael #ifndef __STATISTIC_MATRIX_H__ #define __STATISTIC_MATRIX_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "StatisticException.h" /// class for matrix operations /// element [0,0] is in the top left corner, i increases down, j increases right class StatisticMatrix { public: // constructor StatisticMatrix(); // constructor StatisticMatrix(const int numRows, const int numColumns); // copy constructor StatisticMatrix(const StatisticMatrix& sm); // destructor ~StatisticMatrix(); // Assignment operator. StatisticMatrix& operator=(const StatisticMatrix& sm); // Equality operator bool operator==(const StatisticMatrix& sm); // print a matrix void print(std::ostream& stream, const std::string& offset, const std::string& matrixName) const; /// get the number of rows int getNumberOfRows() const { return numberOfRows; } /// get the number of columns int getNumberOfColumns() const { return numberOfColumns; } // set the dimensions of a matrix void setDimensions(const int numRows, const int numColumns); // get an element from the matrix double getElement(const int rowNumber, const int columnNumber) const; // set the matrix from a one-dimensional array starting with "top row" of elements // matrix must already be set to a number of rows and columns void setMatrixFromOneDimensionalArray(const float dataIn[]); // set the matrix from a one-dimensional array starting with "top row" of elements // matrix must already be set to a number of rows and columns void setMatrixFromOneDimensionalArray(const double dataIn[]); // set an element from the matrix void setElement(const int rowNumber, const int columnNumber, const float value); // set an element from the matrix void setElement(const int rowNumber, const int columnNumber, const double value); // set all elements to value void setAllElements(const float value); /// get the inverse of a matrix StatisticMatrix inverse() const throw (StatisticException); /// get the psueo inverse of a matrix StatisticMatrix inversePseudo() const throw (StatisticException); /// multiply by a matrix (this * matrixIn) StatisticMatrix multiply(const StatisticMatrix& sm) const throw (StatisticException); /// multiply by a scalar StatisticMatrix multiplyByScalar(const double value) const; /// transpose a matrix StatisticMatrix transpose() const; protected: /// copy data for assignment operator and copy constructor void copyHelper(const StatisticMatrix& sm); /// get the location of an element in the matrix int getElementIndex(const int rowNumber, const int columnNumber) const; /// the matrix data double* data; /// number of rows in the matrix int numberOfRows; /// number of columns in the matrix int numberOfColumns; }; #endif // __STATISTIC_MATRIX_H__ caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticMatrix.cxx0000664000175000017500000003373711572067322024026 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include "StatisticAlgorithm.h" #include "StatisticMatrix.h" #include "StatisticNumericalRecipes.h" #include "StatisticVtkMath.h" #define MATRIX_DEBUG_FLAG 1 /** * constructor. */ StatisticMatrix::StatisticMatrix() { data = NULL; setDimensions(0, 0); } /** * constructor. */ StatisticMatrix::StatisticMatrix(const int numRows, const int numColumns) { data = NULL; setDimensions(numRows, numColumns); } /** * copy constructor. */ StatisticMatrix::StatisticMatrix(const StatisticMatrix& sm) { data = NULL; copyHelper(sm); } /** * destructor. */ StatisticMatrix::~StatisticMatrix() { setDimensions(0, 0); } /** * Assignment operator. */ StatisticMatrix& StatisticMatrix::operator=(const StatisticMatrix& sm) { if (this != &sm) { copyHelper(sm); } return *this; } /** * copy data for assignment operator and copy constructor. */ void StatisticMatrix::copyHelper(const StatisticMatrix& sm) { // // setDimensions will allocate memory and set number of rows/cols // setDimensions(sm.getNumberOfRows(), sm.getNumberOfColumns()); const int numData = numberOfRows * numberOfColumns; for (int i = 0; i < numData; i++) { data[i] = sm.data[i]; } } /** * Equality operator. */ bool StatisticMatrix::operator==(const StatisticMatrix& sm) { if ((numberOfRows != sm.numberOfRows) || (numberOfColumns != sm.numberOfColumns)) { return false; } const int numData = numberOfRows * numberOfColumns; for (int i = 0; i < numData; i++) { if (data[i] != sm.data[i]) { return false; } } return true; } /** * print a matrix. */ void StatisticMatrix::print(std::ostream& stream, const std::string& offset, const std::string& matrixName) const { if (matrixName.empty() == false) { stream << matrixName << std::endl; } for (int i = 0; i < numberOfRows; i++) { stream << offset; for (int j = 0; j < numberOfColumns; j++) { stream << getElement(i, j) << " "; } stream << std::endl; } } /** * set the dimensions of a matrix. */ void StatisticMatrix::setDimensions(const int numRows, const int numColumns) { if (data != NULL) { delete[] data; data = NULL; } numberOfRows = numRows; numberOfColumns = numColumns; if ((numberOfRows > 0) && (numberOfColumns > 0)) { data = new double[numberOfRows * numberOfColumns]; } } /** * get an element from the matrix. */ double StatisticMatrix::getElement(const int rowNumber, const int columnNumber) const { const int indx = getElementIndex(rowNumber, columnNumber); return data[indx]; } /** * set an element from the matrix. */ void StatisticMatrix::setElement(const int rowNumber, const int columnNumber, const float value) { setElement(rowNumber, columnNumber, static_cast(value)); } /** * set an element from the matrix. */ void StatisticMatrix::setElement(const int rowNumber, const int columnNumber, const double value) { const int indx = getElementIndex(rowNumber, columnNumber); data[indx] = value; } // set all elements to value void StatisticMatrix::setAllElements(const float value) { const int num = numberOfRows * numberOfColumns; for (int i = 0; i < num; i++) { data[i] = value; } } /** * set the matrix from a one dimensional array starting with "top row" of elements * matrix must already be set to a number of rows and columns */ void StatisticMatrix::setMatrixFromOneDimensionalArray(const float dataIn[]) { #ifdef MATRIX_DEBUG_FLAG if (numberOfRows <= 0) { std::cout << "StatisticMatrix::setMatrixFromOneDimensionalArray: invalid number of rows " << numberOfRows << std::endl; std::abort(); } if (numberOfColumns <= 0) { std::cout << "StatisticMatrix::setMatrixFromOneDimensionalArray: invalid number of columns " << numberOfColumns << std::endl; std::abort(); } #endif // MATRIX_DEBUG_FLAG int ctr = 0; for (int i = 0; i < numberOfRows; i++) { for (int j = 0; j < numberOfColumns; j++) { setElement(i, j, dataIn[ctr]); ctr++; } } } /** * set the matrix from a one dimensional array starting with "top row" of elements * matrix must already be set to a number of rows and columns */ void StatisticMatrix::setMatrixFromOneDimensionalArray(const double dataIn[]) { #ifdef MATRIX_DEBUG_FLAG if (numberOfRows <= 0) { std::cout << "StatisticMatrix::setMatrixFromOneDimensionalArray: invalid number of rows " << numberOfRows << std::endl; std::abort(); } if (numberOfColumns <= 0) { std::cout << "StatisticMatrix::setMatrixFromOneDimensionalArray: invalid number of columns " << numberOfColumns << std::endl; std::abort(); } #endif // MATRIX_DEBUG_FLAG int ctr = 0; for (int i = 0; i < numberOfRows; i++) { for (int j = 0; j < numberOfColumns; j++) { setElement(i, j, dataIn[ctr]); ctr++; } } } /** * get the location of an element in the matrix. */ int StatisticMatrix::getElementIndex(const int rowNumber, const int columnNumber) const { #ifdef MATRIX_DEBUG_FLAG if (numberOfRows <= 0) { std::cout << "StatisticMatrix::getElementIndex: invalid number of rows " << numberOfRows << std::endl; std::abort(); } if (numberOfColumns <= 0) { std::cout << "StatisticMatrix::getElementIndex: invalid number of columns " << numberOfColumns << std::endl; std::abort(); } if ((rowNumber < 0) || (rowNumber >= numberOfRows)) { std::cout << "StatisticMatrix::getElementIndex: invalid row number " << rowNumber << std::endl << " number of rows " << numberOfRows << std::endl; std::abort(); } if ((columnNumber < 0) || (columnNumber >= numberOfColumns)) { std::cout << "StatisticMatrix::getElementIndex: invalid row number " << columnNumber << std::endl << " number of rows " << numberOfColumns << std::endl; std::abort(); } #endif // MATRIX_DEBUG_FLAG const int indx = (rowNumber * numberOfColumns) + columnNumber; return indx; } /** * get the inverse of a matrix. * Taken from VTK. */ StatisticMatrix StatisticMatrix::inverse() const throw (StatisticException) { StatisticMatrix inverseMatrixOut; if ((numberOfRows != numberOfColumns)) { throw StatisticException("ERROR: Matrix must be square for inverse operation."); } inverseMatrixOut.setDimensions(getNumberOfRows(), getNumberOfColumns()); const int size = numberOfRows; int *index=new int[size]; double *column=new double[size]; const int sizeSQ = size* size; double* matrixIn = new double[sizeSQ]; double* matrixOut = new double [sizeSQ]; for (int i = 0; i < sizeSQ; i++) { matrixIn[i] = data[i]; } const int MAX_DIM = 100; if (size > MAX_DIM) { throw StatisticException("ERROR StatisticMatrix::inverse: MAX_DIM exceeded."); } double *A[MAX_DIM]; double *AI[MAX_DIM]; for (int i = 0; i < size; i++) { A[i] = &matrixIn[i * size]; AI[i] = &matrixOut[i * size]; //AI[(size - 1 - i)] = &matrixOut[i * size]; } const int retVal = StatisticVtkMath::InvertMatrix(A, AI, size, index, column); if (retVal != 0) { /* for (int i = 0; i < size; i++) { double* temp = AI[i]; for (int j = 0; j < size; j++) { matrixOut[getElementIndex(i, j)] = temp[j]; } } */ for (int i = 0; i < sizeSQ; i++) { inverseMatrixOut.data[i] = matrixOut[i]; } } else { throw StatisticException("ERROR: Matrix inverse failed."); } delete [] index; delete [] column; return inverseMatrixOut; } /** * get the pseudo inverse of a matrix. */ StatisticMatrix StatisticMatrix::inversePseudo() const throw (StatisticException) { if ((numberOfRows != numberOfColumns)) { throw StatisticException("ERROR: Matrix must be square for pseudo inverse operation."); } const int n = numberOfRows; if (n <= 0) { throw StatisticException("ERROR: Matrix is empty for pseudo inverse operation."); } // // Allocate for numerical recipes // float** au = StatisticNumericalRecipes::matrix(1, n, 1, n); float* w = StatisticNumericalRecipes::vector(1, n); float** v = StatisticNumericalRecipes::matrix(1, n, 1, n); // // Load the input for numerical recipes // //for (int i = 0; i < n; i++) { for (int i = (n - 1); i >= 0; i--) { for (int j = 0; j < n; j++) { au[i+1][j+1] = getElement(i, j); } } // // Do singular value decomposition // StatisticNumericalRecipes::svdcmp(au, n, n, w, v); // // Make the W+ matrix // const float VERY_SMALL_NUMBER = 0.001; StatisticMatrix wplus(n, n); wplus.setAllElements(0.0); for (int i = 0; i < n; i++) { const float wi = w[i+1]; if (std::fabs(wi) < VERY_SMALL_NUMBER) { wplus.setElement(i, i, 0.0); } else { wplus.setElement(i, i, (1.0 / wi)); } } if (StatisticAlgorithm::getDebugOn()) { std::cout << "W-vector: "; for (int i = 1; i <= n; i++) { std::cout << w[i] << ", "; } std::cout << std::endl; wplus.print(std::cout, "", "W-Plus"); } // // Create the U-Transpose matrix // StatisticMatrix umatrix(n, n); for (int i = (n - 1); i >= 0; i--) { for (int j = 0; j < n; j++) { umatrix.setElement(i, j, au[i+1][j+1]); } } if (StatisticAlgorithm::getDebugOn()) { umatrix.print(std::cout, "", "U"); } const StatisticMatrix uTranspose = umatrix.transpose(); // // Create the V-Matrix // StatisticMatrix vmatrix(n, n); for (int i = (n - 1); i >= 0; i--) { for (int j = 0; j < n; j++) { vmatrix.setElement(i, j, v[i+1][j+1]); } } if (StatisticAlgorithm::getDebugOn()) { vmatrix.print(std::cout, "", "V"); } // // Pseudo inverse is [V][W+][UT] // const StatisticMatrix inverseMatrixOut = vmatrix.multiply(wplus).multiply(uTranspose); if ((inverseMatrixOut.getNumberOfRows() != n) || (inverseMatrixOut.getNumberOfColumns() != n)) { throw StatisticException("Pseudo inverse matrix is not same size as input matrix."); } // // Free numerical recipes memory // StatisticNumericalRecipes::free_matrix(au, 1, n, 1, n); StatisticNumericalRecipes::free_matrix(v, 1, n, 1, n); StatisticNumericalRecipes::free_vector(w, 1, n); return inverseMatrixOut; } /** * multiply by a scalar. */ StatisticMatrix StatisticMatrix::multiplyByScalar(const double value) const { StatisticMatrix matrixOut = *this; const int num = numberOfRows * numberOfColumns; for (int i = 0; i < num; i++) { matrixOut.data[i] *= value; } return matrixOut; } /** * multiply by a matrix (this * matrixIn). */ StatisticMatrix StatisticMatrix::multiply(const StatisticMatrix& otherMatrix) const throw (StatisticException) { StatisticMatrix matrixOut; if (numberOfColumns != otherMatrix.numberOfRows) { throw StatisticException( "StatisticMatrix::multiply: Number of column in this matrix is " "different than the number of rows in the other matrix."); } // // Output matrix has same number of rows as "this" matrix // Output matrix has same number of columns as "other" matrix // matrixOut.setDimensions(numberOfRows, otherMatrix.numberOfColumns); for (int i = 0; i < numberOfRows; i++) { for (int j = 0; j < otherMatrix.numberOfColumns; j++) { double value = 0.0; if (StatisticAlgorithm::getDebugOn()) { std::cout << "(" << i << "," << j << ") = "; } for (int k = 0; k < numberOfColumns; k++) { value += getElement(i, k) * otherMatrix.getElement(k, j); if (StatisticAlgorithm::getDebugOn()) { std::cout << "A(" << i << "," << k << ")*"; std::cout << "B(" << k << "," << j << ") "; std::cout << "IJK=(" << i << "," << j << "," << k << ") "; } } if (StatisticAlgorithm::getDebugOn()) { std::cout << std::endl; } matrixOut.setElement(i, j, value); //std::cout << std::endl; } } return matrixOut; } /** * transpose a matrix. */ StatisticMatrix StatisticMatrix::transpose() const { StatisticMatrix matrixOut; if ((numberOfRows > 0) && (numberOfColumns > 0)) { matrixOut.setDimensions(numberOfColumns, numberOfRows); for (int i = 0; i < numberOfRows; i++) { for (int j = 0; j < numberOfColumns; j++) { matrixOut.setElement(j, i, getElement(i, j)); } } } return matrixOut; } caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticLinearRegression.h0000664000175000017500000000537411572067322025456 0ustar michaelmichael #ifndef __STATISTIC_LINEAR_REGRESSION_H__ #define __STATISTIC_LINEAR_REGRESSION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "StatisticAlgorithm.h" /// class for computing linear regression class StatisticLinearRegression : public StatisticAlgorithm { public: // constructor StatisticLinearRegression(); // destructor ~StatisticLinearRegression(); // execute the algorithm void execute() throw (StatisticException); // get the regression coefficients (b0 = intercept, b1 = slope) void getRegressionCoefficients(float& b0out, float& b1out) const; // set the independent data group void setIndependentDataGroup(StatisticDataGroup* dataGroup, const bool takeOwnershipOfThisDataGroup = false); // set the independent data array void setIndependentDataArray(const float* array, const int numItemsInArray, const bool takeOwnershipOfThisDataArray = false); // set the dependent data group void setDependentDataGroup(StatisticDataGroup* dataGroup, const bool takeOwnershipOfThisDataGroup = false); // set the dependent data array void setDependentDataArray(const float* array, const int numItemsInArray, const bool takeOwnershipOfThisDataArray = false); protected: // b0, the intercept float b0; // Beta 1, the slope float b1; // the independent data group (X) StatisticDataGroup* independentDataGroup; // the dependent data group (Y) StatisticDataGroup* dependentDataGroup; }; #endif // __STATISTIC_LINEAR_REGRESSION_H__ caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticLinearRegression.cxx0000664000175000017500000001301111572067322026014 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "StatisticDataGroup.h" #include "StatisticLinearRegression.h" /** * constructor. */ StatisticLinearRegression::StatisticLinearRegression() : StatisticAlgorithm("Linear Regression") { dependentDataGroup = NULL; independentDataGroup = NULL; b0 = 0.0; b1 = 0.0; } /** * destructor. */ StatisticLinearRegression::~StatisticLinearRegression() { } /** * execute the algorithm. * * This algorithm is from Applied Linear Regression Models * John Neter, William Wasserman, and Michael H. Kutner * Second Edition * Page 42 */ void StatisticLinearRegression::execute() throw (StatisticException) { // // Check inputs // if (dependentDataGroup == NULL) { throw StatisticException("Dependent data group is invalid (NULL)"); } if (independentDataGroup == NULL) { throw StatisticException("Independent data group is invalid (NULL)"); } if (independentDataGroup->getNumberOfData() <= 0) { throw StatisticException("Independent data group contains zero elements"); } const int numData = dependentDataGroup->getNumberOfData(); if (numData != independentDataGroup->getNumberOfData()) { throw StatisticException("Independent and dependent data groups have a different number of elements"); } // // Get pointers to data // const float* xi = independentDataGroup->getPointerToData(); const float* yi = dependentDataGroup->getPointerToData(); // // Means of data // const float meanXBar = independentDataGroup->getMeanOfData(); const float meanYBar = dependentDataGroup->getMeanOfData(); // // Calculate b1, the slope // double denomenator = 0.0; double numerator = 0.0; for (int i = 0; i < numData; i++) { const float xdev = xi[i] - meanXBar; const float ydev = yi[i] - meanYBar; denomenator += xdev * xdev; numerator += xdev * ydev; } if (denomenator != 0.0) { b1 = numerator / denomenator; } else { // // Must be a vertical line since all Xi are the same // b1 = std::numeric_limits::max(); } // // Calculate b0, the intercept // b0 = meanYBar - b1 * meanXBar; } /** * get the regression coefficients (B0 = intercept, B1 = slope). */ void StatisticLinearRegression::getRegressionCoefficients(float& b0out, float& b1out) const { b0out = b0; b1out = b1; } /** * set the independent data group. */ void StatisticLinearRegression::setIndependentDataGroup(StatisticDataGroup* dataGroup, const bool takeOwnershipOfThisDataGroup) { const int indx = addDataGroup(dataGroup, takeOwnershipOfThisDataGroup); independentDataGroup = getDataGroup(indx); } /** * set the independent data array. */ void StatisticLinearRegression::setIndependentDataArray(const float* array, const int numItemsInArray, const bool takeOwnershipOfThisDataArray) { StatisticDataGroup::DATA_STORAGE_MODE storageMode = StatisticDataGroup::DATA_STORAGE_MODE_POINT; if (takeOwnershipOfThisDataArray) { storageMode = StatisticDataGroup::DATA_STORAGE_MODE_TAKE_OWNERSHIP; } StatisticDataGroup* sdg = new StatisticDataGroup(array, numItemsInArray, storageMode); setIndependentDataGroup(sdg, true); } /** * set the dependent data group. */ void StatisticLinearRegression::setDependentDataGroup(StatisticDataGroup* dataGroup, const bool takeOwnershipOfThisDataGroup) { const int indx = addDataGroup(dataGroup, takeOwnershipOfThisDataGroup); dependentDataGroup = getDataGroup(indx); } /** * set the dependent data array. */ void StatisticLinearRegression::setDependentDataArray(const float* array, const int numItemsInArray, const bool takeOwnershipOfThisDataArray) { StatisticDataGroup::DATA_STORAGE_MODE storageMode = StatisticDataGroup::DATA_STORAGE_MODE_POINT; if (takeOwnershipOfThisDataArray) { storageMode = StatisticDataGroup::DATA_STORAGE_MODE_TAKE_OWNERSHIP; } StatisticDataGroup* sdg = new StatisticDataGroup(array, numItemsInArray, storageMode); setDependentDataGroup(sdg, true); } caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticLeveneVarianceEquality.h0000664000175000017500000000417611572067322026607 0ustar michaelmichael #ifndef __STATISTIC_LEVENE_VARIANCE_EQUALITY_H__ #define __STATISTIC_LEVENE_VARIANCE_EQUALITY_H__ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "StatisticAlgorithm.h" /// class for Levene's Test for Equality of Variances /// http://www.itl.nist.gov/div898/handbook/eda/section3/eda35a.htm /// http://www.people.vcu.edu/~wsstreet/courses/314_20033/Handout.Levene.pdf class StatisticLeveneVarianceEquality : public StatisticAlgorithm { public: // constructor StatisticLeveneVarianceEquality(); // destructor ~StatisticLeveneVarianceEquality(); // execute the algorithm void execute() throw (StatisticException); /// get the levene F-statistic float getLeveneF() const { return leveneF; } /// get degrees of freedom 1 float getDegreesOfFreedom1() const { return dof1; } /// get degrees of freedom 2 float getDegreesOfFreedom2() const { return dof2; } /// get the P-value float getPValue() { return pValue; } protected: /// the levene's F statistic float leveneF; /// the first degree of freedom float dof1; /// the second degree of freedom float dof2; /// the p-value float pValue; }; #endif // __STATISTIC_LEVENE_VARIANCE_EQUALITY_H__ caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticLeveneVarianceEquality.cxx0000664000175000017500000001352711572067322027162 0ustar michaelmichael/* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "StatisticDataGroup.h" #include "StatisticGeneratePValue.h" #include "StatisticLeveneVarianceEquality.h" #include "StatisticMeanAndDeviation.h" /** * constructor. */ StatisticLeveneVarianceEquality::StatisticLeveneVarianceEquality() : StatisticAlgorithm("Levene Variance Equality") { leveneF = 0.0; dof1 = 0.0; dof2 = 0.0; pValue = 1; } /** * destructor. */ StatisticLeveneVarianceEquality::~StatisticLeveneVarianceEquality() { } /** * execute the algorithm. */ void StatisticLeveneVarianceEquality::execute() throw (StatisticException) { leveneF = 0.0; dof1 = 0.0; dof2 = 0.0; pValue = 1; // // This algorithm is from Step 4 of // http://www.people.vcu.edu/~wsstreet/courses/314_20033/Handout.Levene.pdf // // Note: variables are named as follows // A descriptive name followed by an underscore followed by the name // from the above web site PDF file // // Check number of groups (t) // const int numGroups_t = getNumberOfDataGroups(); if (numGroups_t < 2) { throw StatisticException("There must be at least two groups for Levene's Test."); } // // Get the data groups // std::vector groups(numGroups_t); for (int i = 0; i < numGroups_t; i++) { groups[i] = getDataGroup(i); } // // Get the size of each group and the total number of data // int numberInAllGroups_N = 0; std::vector numberInGroup_ni(numGroups_t); for (int i = 0; i < numGroups_t; i++) { numberInGroup_ni[i] = groups[i]->getNumberOfData(); numberInAllGroups_N += numberInGroup_ni[i]; } // // Get the mean for each group // std::vector meanForGroup_yi(numGroups_t); for (int i = 0; i < numGroups_t; i++) { StatisticMeanAndDeviation smad; smad.addDataGroup(groups[i]); try { smad.execute(); } catch (StatisticException&) { } meanForGroup_yi[i] = smad.getMean(); } // // Get the average absolute deviation within each group // float allAverageAbsoluteDeviation_D = 0.0; std::vector withinGroupAverageAbsoluteDeviation_Di(numGroups_t, 0.0); for (int i = 0; i < numGroups_t; i++) { for (int j = 0; j < numberInGroup_ni[i]; j++) { const float yij = groups[i]->getData(j); withinGroupAverageAbsoluteDeviation_Di[i] += (std::fabs(yij - meanForGroup_yi[i])); } // // Sum up for all groups // allAverageAbsoluteDeviation_D += withinGroupAverageAbsoluteDeviation_Di[i]; // // average absolute deviation for group // if (numberInGroup_ni[i] > 0) { withinGroupAverageAbsoluteDeviation_Di[i] /= static_cast(numberInGroup_ni[i]); } } if (numberInAllGroups_N > 0) { allAverageAbsoluteDeviation_D /= static_cast(numberInAllGroups_N); } // // Determine the numerator // float numerator = 0.0; for (int i = 0; i < numGroups_t; i++) { const float d = withinGroupAverageAbsoluteDeviation_Di[i] - allAverageAbsoluteDeviation_D; numerator += numberInGroup_ni[i] * (d * d); } numerator /= static_cast(numGroups_t - 1); // // Determine the denominator // float sum = 0.0; for (int i = 0; i < numGroups_t; i++) { for (int j = 0; j < numberInGroup_ni[i]; j++) { const float Dij = groups[i]->getData(j) - meanForGroup_yi[i]; const float d = std::fabs(Dij - withinGroupAverageAbsoluteDeviation_Di[i]); sum += (d * d); } } float denominator = sum / static_cast(numberInAllGroups_N - numGroups_t); if (denominator == 0.0) { denominator = 1.0; } // // Determine Levene's F // leveneF = numerator / denominator; dof1 = numGroups_t - 1; dof2 = numberInAllGroups_N - numGroups_t; // // Determine the P-Value // Note this->pValue is passed to the output group so it will get set by the p-value algorithm // StatisticDataGroup fGroup(&leveneF, 1, StatisticDataGroup::DATA_STORAGE_MODE_POINT); StatisticDataGroup numeratorGroup(&dof1, 1, StatisticDataGroup::DATA_STORAGE_MODE_POINT); StatisticDataGroup denominatorGroup(&dof2, 1, StatisticDataGroup::DATA_STORAGE_MODE_POINT); StatisticGeneratePValue genP(StatisticGeneratePValue::INPUT_STATISTIC_F); genP.addDataGroup(&fGroup); genP.addDataGroup(&numeratorGroup); genP.addDataGroup(&denominatorGroup); try { genP.execute(); const StatisticDataGroup* pValuesDataGroup = genP.getOutputDataGroupContainingPValues(); if (pValuesDataGroup->getNumberOfData() > 0) { pValue = pValuesDataGroup->getData(0); } else { throw StatisticException("StatisticGeneratePValue did not produce any output."); } } catch (StatisticException& e) { std::cout << "Generation of P-Value failed for Levene statistic: " << std::endl << " " << e.whatStdString() << std::endl; } } caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticKruskalWallis.h0000664000175000017500000000624711572067322024773 0ustar michaelmichael #ifndef __STATISTIC_KRUSKAL_WALLIS_H__ #define __STATISTIC_KRUSKAL_WALLIS_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "StatisticAlgorithm.h" /// algorithm for Kruskal-Wallis Test essentially a non-parametric one-way ANOVA class StatisticKruskalWallis : public StatisticAlgorithm { public: // constructor StatisticKruskalWallis(); // destructor ~StatisticKruskalWallis(); // execute the algorithm void execute() throw (StatisticException); /// F statistic double getFStatistic() const { return fStatistic; } /// P-Value double getPValue() const { return pValue; } /// get treatment sum of squares double getSumOfSquaresTreatmentSSTR() const { return sumOfSquaresTreatmentSSTR; } /// get error sum of squares double getSumOfSquaresErrorSSE() const { return sumOfSquaresErrorSSE; } /// mean treatment sum of squares double getMeanSumOfSquaresTreatmentMSTR() const { return meanSumOfSquaresTreatmentMSTR; } /// mean error sum of squares double getMeanSumOfSquaresErrorMSE() const { return meanSumOfSquaresErrorMSE; } /// between treatment degrees of freedom double getDegreesOfFreedomBetweenTreatments() const { return degreesOfFreedomBetweenTreatments; } /// within treatment degrees of freedom double getDegreesOfFreedomWithinTreatments() const { return degreesOfFreedomWithinTreatments; } /// degrees of freedom total double getDegreesOfFreedomTotal() const { return degreesOfFreedomTotal; } protected: /// F statistic double fStatistic; /// P-Value double pValue; /// treatment sum of squares double sumOfSquaresTreatmentSSTR; /// error sum of squares double sumOfSquaresErrorSSE; /// mean treatment sum of squares double meanSumOfSquaresTreatmentMSTR; /// mean error sum of squares double meanSumOfSquaresErrorMSE; /// between treatment degrees of freedom double degreesOfFreedomBetweenTreatments; /// within treatment degrees of freedom double degreesOfFreedomWithinTreatments; /// degrees of freedom total double degreesOfFreedomTotal; }; #endif // __STATISTIC_KRUSKAL_WALLIS_H__ caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticKruskalWallis.cxx0000664000175000017500000001214111572067322025334 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "StatisticDataGroup.h" #include "StatisticGeneratePValue.h" #include "StatisticKruskalWallis.h" #include "StatisticMeanAndDeviation.h" #include "StatisticRankTransformation.h" /** * constructor. */ StatisticKruskalWallis::StatisticKruskalWallis() : StatisticAlgorithm("Kruskal-Wallis") { } /** * destructor. */ StatisticKruskalWallis::~StatisticKruskalWallis() { } /** * execute the algorithm. * Formulas are from Applied Linear Statistical Models by John Neter, * William Wasserman, and Michael H. Kutner, 3rd ed. */ void StatisticKruskalWallis::execute() throw (StatisticException) { fStatistic = 0.0; pValue = 0.0; sumOfSquaresTreatmentSSTR = 0.0; sumOfSquaresErrorSSE = 0.0; meanSumOfSquaresTreatmentMSTR = 0.0; meanSumOfSquaresErrorMSE = 0.0; degreesOfFreedomBetweenTreatments = 0.0; degreesOfFreedomWithinTreatments = 0.0; degreesOfFreedomTotal = 0.0; // // Verify that there are groups. Each group is a factor level. // const int numberOfDataGroupsR = getNumberOfDataGroups(); if (numberOfDataGroupsR < 2) { throw StatisticException("Kruskal-Wallis requires at least two data groups."); } // // Transform the data into ranks // StatisticRankTransformation rankTransform; for (int i = 0; i < numberOfDataGroupsR; i++) { rankTransform.addDataGroup(getDataGroup(i)); } rankTransform.execute(); // // Get the transformed data // std::vector dataGroupRanks(numberOfDataGroupsR); std::vector numberOfRanksNi(numberOfDataGroupsR); std::vector meanOfRanksRi(numberOfDataGroupsR); int totalNumberOfRanksNT = 0; for (int i = 0; i < numberOfDataGroupsR; i++) { dataGroupRanks[i] = rankTransform.getOutputDataGroupContainingRankValues(i); numberOfRanksNi[i] = dataGroupRanks[i]->getNumberOfData(); meanOfRanksRi[i] = dataGroupRanks[i]->getMeanOfData(); totalNumberOfRanksNT += numberOfRanksNi[i]; } if (totalNumberOfRanksNT <= 0) { throw StatisticException("All data groups are empty."); } // // since ranks are 1..NT, overall mean is one-half of total number of ranks // const float overallMeanRBar = static_cast(totalNumberOfRanksNT + 1) / 2.0; // // Compute Sum Squares of Treatment // sumOfSquaresTreatmentSSTR = 0.0; for (int i = 0; i < numberOfDataGroupsR; i++) { const float value = (meanOfRanksRi[i] - overallMeanRBar); sumOfSquaresTreatmentSSTR += numberOfRanksNi[i] * (value * value); } // // Compute error sum of squares // sumOfSquaresErrorSSE = 0.0; for (int i = 0; i < numberOfDataGroupsR; i++) { for (int j = 0; j < numberOfRanksNi[i]; j++) { const float value = dataGroupRanks[i]->getData(j) - meanOfRanksRi[i]; sumOfSquaresErrorSSE += value * value; } } // // Between treatments degrees of freedom // degreesOfFreedomBetweenTreatments = numberOfDataGroupsR - 1; // // Within treatments degrees of freedom // degreesOfFreedomWithinTreatments = totalNumberOfRanksNT - numberOfDataGroupsR; // // Total degrees of freedom // degreesOfFreedomTotal = degreesOfFreedomBetweenTreatments + degreesOfFreedomWithinTreatments; // // mean treatment sum of squares // meanSumOfSquaresTreatmentMSTR = sumOfSquaresTreatmentSSTR / degreesOfFreedomBetweenTreatments; // // mean error sum of squares // meanSumOfSquaresErrorMSE = sumOfSquaresErrorSSE / degreesOfFreedomWithinTreatments; // // Calculate F-Statistic // if (meanSumOfSquaresErrorMSE == 0.0) { throw StatisticException("Unable to compute F-Statistic since Mean Sums of Squares Error (MSE) is zero."); } fStatistic = meanSumOfSquaresTreatmentMSTR / meanSumOfSquaresErrorMSE; // // Compute P-Value // pValue = StatisticGeneratePValue::getFStatisticPValue(degreesOfFreedomBetweenTreatments, degreesOfFreedomWithinTreatments, fStatistic); } caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticHistogram.h0000664000175000017500000001133711572067322024134 0ustar michaelmichael #ifndef __HISTOGRAM_H__ #define __HISTOGRAM_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "StatisticAlgorithm.h" /// class for creating a histogram from a set of values class StatisticHistogram : public StatisticAlgorithm { public: // constructor StatisticHistogram(const int numberOfBucketsIn = 256, const float excludeLeftPercent = 0.0, const float excludeRightPercent = 0.0); // destructor ~StatisticHistogram(); // execute the algorithm void execute() throw (StatisticException); /// get the number of buckets int getNumberOfBuckets() const { return buckets.size(); } // get the data for a bucket void getDataForBucket(const int bucketNumber, float& bucketDataValueOut, float& bucketCountOut) const; /// get the data value for a bucket float getDataValueForBucket(const int bucketNumber, bool* validBucketOut = NULL) const; /// get statistics on the data void getDataStatistics(float& minValue, float& maxValue, float& range, float& mean, float& sampleDeviation) const; /// get the estimate of gray and white matter peaks (value of -1 means valid is invalid) void getGrayWhitePeakEstimates(int& grayPeakBucketNumber, int& whitePeakBucketNumber, int& grayMinimumBucketNumber, int& whiteMaximumBucketNumber, int& grayWhiteBoundaryBucketNumber, int& csfPeakBucketNumber) const; /// smooth the histogram (MUST be called after execute) void smoothHistogram(const float strengthZeroToOne = 0.5, const int iterations = 5, const int neighborDepth = 2) throw (StatisticException); /// print the histogram peaks void printHistogramPeaks(std::ostream& stream) const; protected: /// used to sort items for the histogram class HistoPts { public: HistoPts(const int xin, const int yin) { x = xin; y = yin; } int x, y; bool operator<(const HistoPts& p) const { return (x < p.x); } }; /// get the largest bucket that is near the specified bucket int getLargestBucketNearby(const int bucketIndex, const int numberOfNeighbors) const; /// distance of a point to an infinite line in 3D static float distancePointToLine3D(const float pt[3], const float v1[3], const float v2[3]); /// subtract vectors (3d) static void subtractVectors(const float v1[3], const float v2[3], float result[3]); /// cross product static void crossProduct(const float v1[3], const float v2[3], float crossedVector[3]); /// get length of a vector static float vectorLength(const float v[3]); /// the buckets of the histogram std::vector buckets; /// width of the buckets float bucketWidth; /// the minimum value of the data float dataMinimumValue; /// the maximum value of the data float dataMaximumValue; /// data mean float dataMean; /// data sample deviation float dataSampleDeviation; /// number of buckets int numberOfBuckets; /// percentage to exclude low float excludeLeftPercent; /// percentage to exclude high float excludeRightPercent; }; #endif // __HISTOGRAM_H__ caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticHistogram.cxx0000664000175000017500000006603011572067322024507 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include "StatisticDataGroup.h" #include "StatisticHistogram.h" #include "StatisticMeanAndDeviation.h" /** * constructor. Exclude percentages should range 0 to 100. * * Note: Input data is not modified. */ StatisticHistogram::StatisticHistogram(const int numberOfBucketsIn, const float excludeLeftPercentIn, const float excludeRightPercentIn) : StatisticAlgorithm("Histogram") { numberOfBuckets = std::max(numberOfBucketsIn, 1); excludeLeftPercent = excludeLeftPercentIn; excludeRightPercent = excludeRightPercentIn; } /** * execute the algorithm. */ void StatisticHistogram::execute() throw (StatisticException) { // // Get all the data values and have them sorted (2nd arg == true) // std::vector values; getAllDataValues(values, true); if (values.empty()) { throw StatisticException("No data supplied for histogram computation"); } if (values.size() == 1) { buckets.resize(numberOfBuckets, 0); buckets[numberOfBuckets / 2] = 1; dataMinimumValue = values[0]; dataMaximumValue = values[0]; dataMean = values[0]; dataSampleDeviation = 0.0; return; } // // Exclude data on left // int startIndex = 0; if (excludeLeftPercent > 0.0) { if (excludeLeftPercent >= 100.0) { std::cout << "ERROR: Left exclusion percentage for histgram is >= 100.0" << std::endl; return; } else { startIndex = static_cast((excludeLeftPercent / 100.0) * values.size()); } } // // Exclude data on right // int endIndex = static_cast(values.size()); if (excludeRightPercent > 0.0) { if (excludeRightPercent >= 100.0) { std::cout << "ERROR: Right exclusion percentage for histgram is >= 100.0" << std::endl; return; } else { const int numOnRight = static_cast((excludeRightPercent / 100.0) * values.size()); endIndex -= numOnRight; } } if (endIndex <= startIndex) { std::cout << "ERROR: Exclusions for histogram are too large." << std::endl; return; } // // Determine min and max buckets values // dataMinimumValue = values[startIndex]; dataMaximumValue = values[endIndex - 1]; // // Determine stats on data // StatisticMeanAndDeviation meanAndDev; StatisticDataGroup sdg(&values[startIndex], (endIndex - startIndex), StatisticDataGroup::DATA_STORAGE_MODE_POINT); meanAndDev.addDataGroup(&sdg); try { meanAndDev.execute(); } catch (StatisticException&) { } dataMean = meanAndDev.getMean(); dataSampleDeviation = meanAndDev.getPopulationSampleStandardDeviation(); // // Determine width of bucket // bucketWidth = (dataMaximumValue - dataMinimumValue) / static_cast(numberOfBuckets); // // Create the histogram // buckets.resize(numberOfBuckets, 0); for (int i = startIndex; i < endIndex; i++) { int index = static_cast((values[i] - dataMinimumValue) / bucketWidth); index = std::max(index, 0); index = std::min(index, numberOfBuckets - 1); buckets[index]++; } } /** * destructor. */ StatisticHistogram::~StatisticHistogram() { } /** * get the data value for a bucket. */ float StatisticHistogram::getDataValueForBucket(const int bucketNumber, bool* validBucketOut) const { if (validBucketOut != NULL) { *validBucketOut = false; } if ((bucketNumber >= 0) && (bucketNumber < getNumberOfBuckets())) { const float value = dataMinimumValue + bucketWidth * bucketNumber; if (validBucketOut != NULL) { *validBucketOut = true; } return value; } return -1.0; } /** * get the data for a bucket. */ void StatisticHistogram::getDataForBucket(const int bucketNumber, float& bucketDataValueOut, float& bucketCountOut) const { bucketDataValueOut = 0.0; bucketCountOut = 0.0; if ((bucketNumber >= 0) && (bucketNumber < getNumberOfBuckets())) { bucketDataValueOut = dataMinimumValue + bucketWidth * bucketNumber; bucketCountOut = buckets[bucketNumber]; } } /** * smooth the histogram (MUST be called after execute). */ void StatisticHistogram::smoothHistogram(const float strengthZeroToOne, const int iterations, const int neighborDepth) throw (StatisticException) { if ((strengthZeroToOne < 0.0) || (strengthZeroToOne > 1.0)) { throw StatisticException("Strength outside range [0.0, 1.0]"); } if (neighborDepth < 1) { throw StatisticException("Neighbor depth must be 1 or greater."); } if (iterations < 1) { throw StatisticException("Number of iterations must be 1 or greater"); } const int numBuckets = getNumberOfBuckets(); if (numBuckets <= 0) { return; } // // Do as float because of rounding errors // std::vector bucketsFloat(numBuckets); for (int m = 0; m < numBuckets; m++) { bucketsFloat[m] = buckets[m]; } const float oneMinusStrength = 1.0 - strengthZeroToOne; // // Loop for the specified number of iterations // for (int iter = 0; iter < iterations; iter++) { // // Go through all buckets // for (int i = 0; i < numBuckets; i++) { // // Determine weight of neighbors // float neighborCounter = 0.0; float neighborSum = 0.0; const int iStart = std::max((i - neighborDepth), 0); const int iEnd = std::min((i + neighborDepth), (numBuckets - 1)); for (int j = iStart; j <= iEnd; j++) { if (j != i) { neighborSum += bucketsFloat[j]; neighborCounter += 1.0; } } // // Smooth bucket "i" // if (neighborCounter >= 1.0) { const float neighborAverage = neighborSum / neighborCounter; const float myValue = bucketsFloat[i]; bucketsFloat[i] = static_cast((myValue * oneMinusStrength) + (neighborAverage * strengthZeroToOne)); } } } // // Put back to int and round by adding (0.5) // const int bucketNumber = -1; for (int m = 0; m < numBuckets; m++) { if (m == bucketNumber) { std::cout << "Bucket[" << bucketNumber << "] = " << buckets[bucketNumber] << " "; } buckets[m] = static_cast(bucketsFloat[m] + 0.5); if (m == bucketNumber) { std::cout << buckets[bucketNumber] << std::endl; } } } /** * get the largest bucket that is near the specified bucket. */ int StatisticHistogram::getLargestBucketNearby(const int bucketIndex, const int numberOfNeighbors) const { const int numberOfBuckets = static_cast(buckets.size()); const int startIndex = std::max(bucketIndex - numberOfNeighbors, 0); const int endIndex = std::min(bucketIndex + numberOfNeighbors + 1, numberOfBuckets); int biggestBucketIndex = -1; int biggestBucketValue = -1; for (int i = startIndex; i < endIndex; i++) { if (buckets[i] > biggestBucketValue) { biggestBucketValue = buckets[i]; biggestBucketIndex = i; } } return biggestBucketIndex; } /** * get the estimate of gray and white matter peaks (value of -1 means value is invalid). * * grayMinimumBucketNumber is the estimate of the minimum gray value * grayPeakBucketNumber is the estimate of the gray matter peak * grayWhiteBoundaryBucketNumber is the estimate of the boundary between gray and white values * whitePeakBucketNumber is the estimate of the white matter peak * whiteMaximumBucketNumber is the estimate of the maximum white matter value * * Be sure to call getDatForBucket() with the above parameters to get * the actual data values. */ void StatisticHistogram::getGrayWhitePeakEstimates(int& grayPeakBucketNumber, int& whitePeakBucketNumber, int& grayMinimumBucketNumber, int& whiteMaximumBucketNumber, int& grayWhiteBoundaryBucketNumber, int& csfPeakBucketNumber) const { // // Reset buckets // grayPeakBucketNumber = -1; whitePeakBucketNumber = -1; grayMinimumBucketNumber = -1; whiteMaximumBucketNumber = -1; grayWhiteBoundaryBucketNumber = -1; csfPeakBucketNumber = -1; // // Copy the histogram since it will be smoothed in order to find peaks // StatisticHistogram smoothedHistogram = *this; // // Start and ending buckets // const int numBuckets = smoothedHistogram.getNumberOfBuckets(); const int ninetyPercentBucket = static_cast(numBuckets * 0.90); const int startBucket = 0; //25; const int endBucket = numBuckets - 1; if (endBucket <= startBucket) { return; } // // Storage for finding peaks and valleys // std::vector histVector; std::vector histPeaks, histValleys; // // Loop for smoothing histogram // bool continueSmoothing = true; int totalSmoothingIterations = 0; while(continueSmoothing) { totalSmoothingIterations++; // // Smooth the histogram // const float smoothingStrength = 0.5; const int smoothingIterations = 1; const int smoothingNeighborDepth = 3; smoothedHistogram.smoothHistogram(smoothingStrength, smoothingIterations, smoothingNeighborDepth); // // Store line segment points in a vector that is sorted by X-coordinate // std::set pts; pts.insert(HistoPts(startBucket, 0)); //buckets[startBucket])); pts.insert(HistoPts(endBucket, 0)); // buckets[endBucket])); // // Use a "Douglas Puecker" curve simplification to find the peaks and valleys // in the histogram by approximating the curve with a set of line segments // It starts with just the endpoints of the curve and finds the point in the // curve that is furthest from the line connecting the two endpoints. This // process iterates by finding the point that is furthes from its line segment // and inserting it. // const unsigned int maxSegments = 20; while (pts.size() < maxSegments) { std::vector ptsVector(pts.begin(), pts.end()); const int numSegments = static_cast(ptsVector.size() - 1); int furthestX = -1; float furthestDist = -1.0; // // Examine each line segment // for (int m = 0; m < numSegments; m++) { const int xStart = static_cast(ptsVector[m].x); const int yStart = static_cast(ptsVector[m].y); const int xEnd = static_cast(ptsVector[m+1].x); const int yEnd = static_cast(ptsVector[m+1].y); const float p1[3] = { xStart, yStart, 0.0 }; const float p2[3] = { xEnd, yEnd, 0.0 }; // // Test all points to find distance to line segment // for (int i = xStart + 1; i < xEnd - 1; i++) { const float pt[3] = { i, smoothedHistogram.buckets[i], 0.0 }; const float dist = distancePointToLine3D(pt, p1, p2); if (dist > furthestDist) { furthestX = i; furthestDist = dist; } } } if (furthestX >= 0) { pts.insert(HistoPts(furthestX, smoothedHistogram.buckets[furthestX])); } else { break; } } // // Place the points of the line segment into a vector // histVector.clear(); histVector.insert(histVector.end(), pts.begin(), pts.end()); histPeaks.clear(); histValleys.clear(); if (getDebugOn()) { std::cout << "Peak finding:" << std::endl; } const int lastIndex = histVector.size() - 1; for (int i = 0; i <= lastIndex; i++) { const HistoPts& pt = histVector[i]; if (getDebugOn()) { std::cout << " " << pt.x << ", " << pt.y << std::endl; } // // Ignore endpoints // if ((i > 0) && (i < lastIndex)) { // // Is this a peak (peak is greater than its left and right neighbors)? // if ((pt.y > histVector[i-1].y) && (pt.y > histVector[i+1].y)) { histPeaks.push_back(pt); } // // Is this a valley (peak is less than its left and right neighbors)? // if ((pt.y < histVector[i-1].y) && (pt.y < histVector[i+1].y)) { histValleys.push_back(pt); } } } const int peakCount = histPeaks.size(); if (getDebugOn()) { std::cout << "Peaks: " << std::endl; for (int i = 0; i < peakCount; i++) { const HistoPts& pt = histPeaks[i]; std::cout << " " << pt.x << ", " << pt.y << std::endl; } std::cout << std::endl; std::cout << "Valleys: " << std::endl; for (unsigned int i = 0; i < histValleys.size(); i++) { const HistoPts& pt = histValleys[i]; std::cout << " " << pt.x << ", " << pt.y << std::endl; } } // // Have the necessary peaks been found? // if (peakCount <= 3) { // // The peaks should be CSF, Gray, White // continueSmoothing = false; } else if (peakCount >= 4) { bool allPeaks90Plus = true; for (int i = 3; i < peakCount; i++) { if (histPeaks[i].x < ninetyPercentBucket) { allPeaks90Plus = false; } } if (allPeaks90Plus) { // // Fourth and greater buckets is/are skull, blood, etc // continueSmoothing = false; } } } if (getDebugOn()) { std::cout << totalSmoothingIterations << " iterations of smoothing needed to find peaks." << std::endl; } // // The first peak is the CSF // The second peak is the Gray Matter // The third peak is the White Matter // The fourth peak is Skull or Arteries // if (histPeaks.size() > 0) { csfPeakBucketNumber = histPeaks[0].x; if (histPeaks.size() > 1) { grayPeakBucketNumber = histPeaks[0].x; whitePeakBucketNumber = histPeaks[1].x; if (histPeaks.size() > 2) { grayPeakBucketNumber = histPeaks[1].x; whitePeakBucketNumber = histPeaks[2].x; } } } // // First valley BEFORE gray peaks is gray minimum // First valley AFTER white peak is white maximum // for (unsigned int i = 0; i < histValleys.size(); i++) { const HistoPts& pt = histValleys[i]; if (grayPeakBucketNumber >= 0) { if (pt.x < grayPeakBucketNumber) { grayMinimumBucketNumber = pt.x; } } //if (whitePeakBucketNumber >= 0) { // if (pt.x > whitePeakBucketNumber) { // if (whiteMaximumBucketNumber < 0) { // whiteMaximumBucketNumber = pt.x; // } // } //} if ((grayPeakBucketNumber >= 0) && (whitePeakBucketNumber >= 0)) { if ((grayPeakBucketNumber < pt.x) && (whitePeakBucketNumber > pt.x)) { grayWhiteBoundaryBucketNumber = pt.x; } } } // // Since histogram was smoothed, may not be at the peak so use max of it or neighbors // if (grayPeakBucketNumber > 0) { grayPeakBucketNumber = getLargestBucketNearby(grayPeakBucketNumber, 3); } if (whitePeakBucketNumber > 0) { whitePeakBucketNumber = getLargestBucketNearby(whitePeakBucketNumber, 3); } // // Estimate white maximum value. Assume distribution of white voxels is symmetric // but push white max a little to the right // if (whiteMaximumBucketNumber < 0) { if ((whitePeakBucketNumber > 0) && (grayWhiteBoundaryBucketNumber > 0) && (grayWhiteBoundaryBucketNumber < whitePeakBucketNumber)) { const int diff = static_cast( static_cast(whitePeakBucketNumber - grayWhiteBoundaryBucketNumber) * 1.15); whiteMaximumBucketNumber = std::min((whitePeakBucketNumber + diff), endBucket); } } if (getDebugOn()) { std::cout << "CSF Peak: " << getDataValueForBucket(csfPeakBucketNumber) << std::endl; std::cout << "Gray Minimum: " << getDataValueForBucket(grayMinimumBucketNumber) << std::endl; std::cout << "Gray Peak: " << getDataValueForBucket(grayPeakBucketNumber) << std::endl; std::cout << "Gray/White Boundary: " << getDataValueForBucket(grayWhiteBoundaryBucketNumber) << std::endl; std::cout << "White Peak: " << getDataValueForBucket(whitePeakBucketNumber) << std::endl; std::cout << "White Maximum: " << getDataValueForBucket(whiteMaximumBucketNumber) << std::endl; } } /* // // Create a smoothed version of this histogram to remove noise // StatisticHistogram smoothedHistogram = *this; smoothedHistogram.smoothHistogram(0.5, 5, 5); grayPeakBucketNumber = -1; whitePeakBucketNumber = -1; grayMinimumBucketNumber = -1; whiteMaximumBucketNumber = -1; grayWhiteBoundaryBucketNumber = -1; // // Start and ending buckets // const int numBuckets = smoothedHistogram.getNumberOfBuckets(); const int startBucket = 0; //25; const int endBucket = numBuckets - 1; if (endBucket <= startBucket) { return; } std::set pts; pts.insert(HistoPts(startBucket, 0)); //buckets[startBucket])); pts.insert(HistoPts(endBucket, 0)); // buckets[endBucket])); // // Use a "Douglas Puecker" curve simplification // const unsigned int maxSegments = 20; while (pts.size() < maxSegments) { std::vector ptsVector(pts.begin(), pts.end()); const int numSegments = static_cast(ptsVector.size() - 1); int furthestX = -1; float furthestDist = -1.0; for (int m = 0; m < numSegments; m++) { const int xStart = static_cast(ptsVector[m].x); const int yStart = static_cast(ptsVector[m].y); const int xEnd = static_cast(ptsVector[m+1].x); const int yEnd = static_cast(ptsVector[m+1].y); const float p1[3] = { xStart, yStart, 0.0 }; const float p2[3] = { xEnd, yEnd, 0.0 }; for (int i = xStart + 1; i < xEnd - 1; i++) { const float pt[3] = { i, smoothedHistogram.buckets[i], 0.0 }; const float dist = distancePointToLine3D(pt, p1, p2); if (dist > furthestDist) { furthestX = i; furthestDist = dist; } } } if (furthestX >= 0) { pts.insert(HistoPts(furthestX, smoothedHistogram.buckets[furthestX])); } else { break; } } std::vector histVector(pts.begin(), pts.end()); std::vector histPeaks, histValleys; if (getDebugOn()) { std::cout << "Peak finding:" << std::endl; } const int lastIndex = histVector.size() - 1; for (int i = 0; i <= lastIndex; i++) { const HistoPts& pt = histVector[i]; if (getDebugOn()) { std::cout << " " << pt.x << ", " << pt.y << std::endl; } // // Ignore endpoints // if ((i > 0) && (i < lastIndex)) { // // Is this a peak? // if ((pt.y > histVector[i-1].y) && (pt.y > histVector[i+1].y)) { histPeaks.push_back(pt); } // // Is this a valley? // if ((pt.y < histVector[i-1].y) && (pt.y < histVector[i+1].y)) { histValleys.push_back(pt); } } } if (getDebugOn()) { std::cout << "Peaks: " << std::endl; for (unsigned int i = 0; i < histPeaks.size(); i++) { const HistoPts& pt = histPeaks[i]; std::cout << " " << pt.x << ", " << pt.y << std::endl; } std::cout << std::endl; std::cout << "Valleys: " << std::endl; for (unsigned int i = 0; i < histValleys.size(); i++) { const HistoPts& pt = histValleys[i]; std::cout << " " << pt.x << ", " << pt.y << std::endl; } } // // The first peak is the CSF // The second peak is the Gray Matter // The third peak is the White Matter // The fourth peak is Skull or Arteries // if (histPeaks.size() > 1) { grayPeakBucketNumber = histPeaks[1].x; whitePeakBucketNumber = histPeaks[1].x; if (histPeaks.size() > 2) { whitePeakBucketNumber = histPeaks[2].x; } } // // First valley BEFORE gray peaks is gray minimum // First valley AFTER white peak is white maximum // for (unsigned int i = 0; i < histValleys.size(); i++) { const HistoPts& pt = histValleys[i]; if (grayPeakBucketNumber >= 0) { if (pt.x < grayPeakBucketNumber) { grayMinimumBucketNumber = pt.x; } } if (whitePeakBucketNumber >= 0) { if (pt.x > whitePeakBucketNumber) { if (whiteMaximumBucketNumber < 0) { whiteMaximumBucketNumber = pt.x; } } } if ((grayPeakBucketNumber >= 0) && (whitePeakBucketNumber >= 0)) { if ((grayPeakBucketNumber < pt.x) && (whitePeakBucketNumber > pt.x)) { grayWhiteBoundaryBucketNumber = pt.x; } } } // // If white max not found, estimate at midpoint of white peak and last bucket // if (whiteMaximumBucketNumber < 0) { if (whitePeakBucketNumber > 0) { whiteMaximumBucketNumber = (whitePeakBucketNumber + histVector[lastIndex].x) / 2; //std::cout << "White max guessed." << std::endl; } } if (getDebugOn()) { std::cout << "Gray Minimum: " << getDataValueForBucket(grayMinimumBucketNumber) << std::endl; std::cout << "Gray Peak: " << getDataValueForBucket(grayPeakBucketNumber) << std::endl; std::cout << "Gray/White Boundary: " << getDataValueForBucket(grayWhiteBoundaryBucketNumber) << std::endl; std::cout << "White Peak: " << getDataValueForBucket(whitePeakBucketNumber) << std::endl; std::cout << "White Maximum: " << getDataValueForBucket(whiteMaximumBucketNumber) << std::endl; } } */ /** * get statistics on the data. */ void StatisticHistogram::getDataStatistics(float& minValue, float& maxValue, float& range, float& mean, float& sampleDeviation) const { minValue = dataMinimumValue; maxValue = dataMaximumValue; range = maxValue - minValue; mean = dataMean; sampleDeviation = dataSampleDeviation; } /** * distance of a point to an infinite line in 3D. * "pt" is the point. "v1" and "v2" are points on the line. * Formula is from "http://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html". */ float StatisticHistogram::distancePointToLine3D(const float pt[3], const float v1[3], const float v2[3]){ float dv2v1[3]; subtractVectors(v2, v1, dv2v1); float dv1pt[3]; subtractVectors(v1, pt, dv1pt); float crossed[3]; crossProduct(dv2v1, dv1pt, crossed); float numerator = vectorLength(crossed); float denomenator = vectorLength(dv2v1); float dist = numerator / denomenator; return dist; } /** * subtract vectors (3d) result = v1 - v2. */ void StatisticHistogram::subtractVectors(const float v1[3], const float v2[3], float result[3]) { result[0] = v1[0] - v2[0]; result[1] = v1[1] - v2[1]; result[2] = v1[2] - v2[2]; } /** * cross product. */ void StatisticHistogram::crossProduct(const float v1[3], const float v2[3], float crossedVector[3]) { crossedVector[0] = (v1[1] * v2[2]) - (v1[2] * v2[1]); crossedVector[1] = (v1[2] * v2[0]) - (v1[0] * v2[2]); crossedVector[2] = (v1[0] * v2[1]) - (v1[1] * v2[0]); } /** * get length of a vector. */ float StatisticHistogram::vectorLength(const float v[3]) { const float len = std::sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]); return len; } /** * print the histogram peaks. */ void StatisticHistogram::printHistogramPeaks(std::ostream& stream) const { int grayPeakBucketNumber; int whitePeakBucketNumber; int grayMinimumBucketNumber; int whiteMaximumBucketNumber; int grayWhiteBoundaryBucketNumber; int csfPeakBucketNumber; getGrayWhitePeakEstimates(grayPeakBucketNumber, whitePeakBucketNumber, grayMinimumBucketNumber, whiteMaximumBucketNumber, grayWhiteBoundaryBucketNumber, csfPeakBucketNumber); // // Print results // stream << std::endl; stream << "CSF Peak: " << getDataValueForBucket(csfPeakBucketNumber) << std::endl; stream << "Gray Minimum: " << getDataValueForBucket(grayMinimumBucketNumber) << std::endl; stream << "Gray Peak: " << getDataValueForBucket(grayPeakBucketNumber) << std::endl; stream << "Gray/White Boundary: " << getDataValueForBucket(grayWhiteBoundaryBucketNumber) << std::endl; stream << "White Peak: " << getDataValueForBucket(whitePeakBucketNumber) << std::endl; stream << "White Maximum: " << getDataValueForBucket(whiteMaximumBucketNumber) << std::endl; stream << std::endl; } caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticGeneratePValue.h0000664000175000017500000000700411572067322025042 0ustar michaelmichael #ifndef __STATISTIC_GENERATE_P_VALUE_H__ #define __STATISTIC_GENERATE_P_VALUE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "StatisticAlgorithm.h" /// generate P-Values from a statistic and degrees-of-freedom class StatisticGeneratePValue : public StatisticAlgorithm { public: // generate P-Value for an F-Statistic static float getFStatisticPValue(const float numeratorDegreesOfFreedom, const float denominatorDegreesOfFreedom, const float F); // generate P-Value for One-Tailed T-Test static float getOneTailTTestPValue(const float degreesOfFreedom, const float T); // generate P-Value for Two-Tailed T-Test static float getTwoTailTTestPValue(const float degreesOfFreedom, const float T); /// type of statistic enum INPUT_STATISTIC { /// input statistic if F-Statistic INPUT_STATISTIC_F, /// input statistic is T-statistic with one tale distribution INPUT_STATISTIC_T_ONE_TALE, /// input statistic is T-statistic with two tale distribution INPUT_STATISTIC_T_TWO_TALE }; // constructor StatisticGeneratePValue(const INPUT_STATISTIC inputStatisticTypeIn); // destructor ~StatisticGeneratePValue(); // generate the P-Values void execute() throw (StatisticException); // get the output data group that contains the P-values const StatisticDataGroup* getOutputDataGroupContainingPValues() const { return outputDataGroupContainingPValues; } protected: /// type of input statistic INPUT_STATISTIC inputStatisticType; // from AFNI and used by tStatisticToPValue static double incbeta( double x , double p , double q , double beta ); // from AFNI and used by tStatisticToPValue static double lnbeta( double p , double q ); // from AFNI and used by tStatisticToPValue static double gamma( double x ); // from AFNI and used by tStatisticToPValue static double gamma_asympt(double x); // from AFNI and used by tStatisticToPValue static double gamma_12( double y ); // the output data group StatisticDataGroup* outputDataGroupContainingPValues; }; #endif // __STATISTIC_GENERATE_P_VALUE_H__ caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticGeneratePValue.cxx0000664000175000017500000003767511572067322025436 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include "StatisticDataGroup.h" #include "StatisticDcdflib.h" #include "StatisticGeneratePValue.h" /** * constructor. * @param 1st data group must be the statistic for T-Distribution * @param 2nd data group must be the degrees of freedom for T-Distribution * @param 1st data group must be the statistic for F-Distribution * @param 2nd data group must be the numerator degrees of freedom for F-Distribution * @param 2nd data group must be the deonominator degrees of freedom for F-Distribution */ StatisticGeneratePValue::StatisticGeneratePValue(const INPUT_STATISTIC inputStatisticTypeIn) : StatisticAlgorithm("Generate P-Value") { inputStatisticType = inputStatisticTypeIn; outputDataGroupContainingPValues = NULL; } /** * destructor. */ StatisticGeneratePValue::~StatisticGeneratePValue() { if (outputDataGroupContainingPValues != NULL) { delete outputDataGroupContainingPValues; outputDataGroupContainingPValues = NULL; } } /** * generate P-Value for One-Tailed T-Test. */ float StatisticGeneratePValue::getOneTailTTestPValue(const float degreesOfFreedom, const float T) { StatisticDataGroup tSDG(&T, 1, StatisticDataGroup::DATA_STORAGE_MODE_POINT); StatisticDataGroup dofSDG(°reesOfFreedom, 1, StatisticDataGroup::DATA_STORAGE_MODE_POINT); StatisticGeneratePValue genP(INPUT_STATISTIC_T_ONE_TALE); genP.addDataGroup(&tSDG); genP.addDataGroup(&dofSDG); float pValue = -100000.0; try { genP.execute(); const StatisticDataGroup* sdg = genP.getOutputDataGroupContainingPValues(); if (sdg->getNumberOfData() > 0) { pValue = sdg->getData(0); } } catch (StatisticException&) { } return pValue; } /** * generate P-Value for Two-Tailed T-Test. */ float StatisticGeneratePValue::getTwoTailTTestPValue(const float degreesOfFreedom, const float T) { StatisticDataGroup tSDG(&T, 1, StatisticDataGroup::DATA_STORAGE_MODE_POINT); StatisticDataGroup dofSDG(°reesOfFreedom, 1, StatisticDataGroup::DATA_STORAGE_MODE_POINT); StatisticGeneratePValue genP(INPUT_STATISTIC_T_TWO_TALE); genP.addDataGroup(&tSDG); genP.addDataGroup(&dofSDG); float pValue = -100000.0; try { genP.execute(); const StatisticDataGroup* sdg = genP.getOutputDataGroupContainingPValues(); if (sdg->getNumberOfData() > 0) { pValue = sdg->getData(0); } } catch (StatisticException&) { } return pValue; } /** * generate P-Value for an F-Statistic. */ float StatisticGeneratePValue::getFStatisticPValue(const float numeratorDegreesOfFreedom, const float denominatorDegreesOfFreedom, const float F) { StatisticDataGroup fSDG(&F, 1, StatisticDataGroup::DATA_STORAGE_MODE_POINT); StatisticDataGroup numSDG(&numeratorDegreesOfFreedom, 1, StatisticDataGroup::DATA_STORAGE_MODE_POINT); StatisticDataGroup denSDG(&denominatorDegreesOfFreedom, 1, StatisticDataGroup::DATA_STORAGE_MODE_POINT); StatisticGeneratePValue genP(INPUT_STATISTIC_F); genP.addDataGroup(&fSDG); genP.addDataGroup(&numSDG); genP.addDataGroup(&denSDG); float pValue = -100000.0; try { genP.execute(); const StatisticDataGroup* sdg = genP.getOutputDataGroupContainingPValues(); if (sdg->getNumberOfData() > 0) { pValue = sdg->getData(0); } } catch (StatisticException&) { } return pValue; } /** * generate the P-Values. */ void StatisticGeneratePValue::execute() throw (StatisticException) { StatisticDataGroup* statisticDataGroup = NULL; StatisticDataGroup* degreesOfFreedomOneDataGroup = NULL; StatisticDataGroup* degreesOfFreedomTwoDataGroup = NULL; switch (inputStatisticType) { case INPUT_STATISTIC_F: if (getNumberOfDataGroups() != 3) { throw StatisticException("Number of data groups for StatisticGeneratePValue must be 3.\n" "1st group contains the statistics\n" "2nd group contains the numerator degrees-of-freedom\n" "3rd group contains the denominator degrees-of-freedom"); } statisticDataGroup = getDataGroup(0); degreesOfFreedomOneDataGroup = getDataGroup(1); degreesOfFreedomTwoDataGroup = getDataGroup(2); break; case INPUT_STATISTIC_T_ONE_TALE: case INPUT_STATISTIC_T_TWO_TALE: if (getNumberOfDataGroups() != 2) { throw StatisticException("Number of data groups for StatisticGeneratePValue must be 2.\n" "1st group contains the statistics\n" "2nd group contains the degrees-of-freedom"); } statisticDataGroup = getDataGroup(0); degreesOfFreedomOneDataGroup = getDataGroup(1); break; } const int numValues = statisticDataGroup->getNumberOfData(); if (numValues <= 0) { throw StatisticException("Data group passed to StatisticGeneratePValue is empty."); } if (numValues != degreesOfFreedomOneDataGroup->getNumberOfData()) { throw StatisticException("Degrees of Freedom Data Group one must have same number of values as the Statistic Data Group."); } if (degreesOfFreedomTwoDataGroup != NULL) { if (numValues != degreesOfFreedomTwoDataGroup->getNumberOfData()) { throw StatisticException("Degrees of Freedom Data Group two must have same number of values as the Statistic Data Group."); } } float* outputPValues = new float[numValues]; for (int i = 0; i < numValues; i++) { double statistic = statisticDataGroup->getData(i); const double dof1 = degreesOfFreedomOneDataGroup->getData(i); double dof2 = 0.0; if (degreesOfFreedomTwoDataGroup != NULL) { dof2 = degreesOfFreedomTwoDataGroup->getData(i); } double pValue = 0.0; switch (inputStatisticType) { case INPUT_STATISTIC_F: { // // Use symmetry // if (statistic < 0.0) { statistic = -statistic; } //if( statistic <= 0.0 || dof1 < 1.0 ) { // pValue = 1.0; //} //else { // // Use dcdflib routine to calculate P // Note they report close to one (ie P = 0.95) and Q = 1 - P // so just use Q. // int which = 1; double p = 0.0; double q = 0.0; double f = statistic; double dfn = dof1; double dfd = dof2; int status = 0; double bound = 0; cdff(&which, &p, &q, &f, &dfn, &dfd, &status, &bound); if (status != 0) { //pValue = p; std::cout << "WARNING: F-Statistic to P-Value function (cdft) failed, code=" << status << "." << std::endl; std::cout << " F: " << f << ", " << "DOF-N: " << dfn << ", " << "DOF-D: " << dfd << std::endl; } pValue = q; //} } break; case INPUT_STATISTIC_T_ONE_TALE: { // // Use symmetry // if (statistic < 0.0) { statistic = -statistic; } if( statistic <= 0.0 || dof1 < 1.0 ) { pValue = 1.0; } else { // // Use dcdflib routine to calculate P // Note they report close to one (ie P = 0.95) and Q = 1 - P // The result is also a one tail test so we really one Q * 2 // int which = 1; double p = 0.0; double q = 0.0; double t = statistic; double df = dof1; int status = 0; double bound = 0; cdft(&which, &p, &q, &t, &df, &status, &bound); if (status != 0) { //pValue = p; std::cout << "WARNING: T-Statistic to P-Value function (cdft) failed, code=" << status << "." << std::endl; } pValue = q; } } break; case INPUT_STATISTIC_T_TWO_TALE: { // // Use symmetry // if (statistic < 0.0) { statistic = -statistic; } if( statistic <= 0.0 || dof1 < 1.0 ) { pValue = 1.0; } else { // // Use dcdflib routine to calculate P // Note they report close to one (ie P = 0.95) and Q = 1 - P // The result is also a one tail test so we really one Q * 2 // int which = 1; double p = 0.0; double q = 0.0; double t = statistic; double df = dof1; int status = 0; double bound = 0; cdft(&which, &p, &q, &t, &df, &status, &bound); if (status != 0) { //pValue = p; std::cout << "WARNING: T-Statistic to P-Value function (cdft) failed, code=" << status << "." << std::endl; } pValue = q * 2.0; } } break; } outputPValues[i] = pValue; } outputDataGroupContainingPValues = new StatisticDataGroup(outputPValues, numValues, StatisticDataGroup::DATA_STORAGE_MODE_TAKE_OWNERSHIP); } /***********************************************************************/ /**** Taken from AFNI's mri_stats.c ****/ /**** Provide a ln(gamma(x)) function for stupid math libraries. ****/ /**** This routine is not very efficient! Don't use elsewhere. ****/ /**** (cf. Abramowitz and Stegun, Eq. 6.1.36.) ****/ /***********************************************************************/ /** * Taken from AFNI's mri_stats.c * log of gamma, for argument between 1 and 2 */ double StatisticGeneratePValue::gamma_12( double y ) { double x , g ; x = y - 1.0 ; g = ((((((( 0.035868343 * x - 0.193527818 ) * x + 0.482199394 ) * x - 0.756704078 ) * x + 0.918206857 ) * x - 0.897056937 ) * x + 0.988205891 ) * x - 0.577191652 ) * x + 1.0 ; return std::log(g) ; } /** * Taken from AFNI's mri_stats.c * asymptotic expansion of ln(gamma(x)) for large positive x */ double StatisticGeneratePValue::gamma_asympt(double x) { const double LNSQRT2PI = 0.918938533204672; /* ln(sqrt(2*PI)) */ double sum ; sum = (x-0.5)*std::log(x) - x + LNSQRT2PI + 1.0/(12.0*x) - 1./(360.0*x*x*x) ; return sum ; } /** * Taken from AFNI's mri_stats.c * log of gamma, argument positive (not very efficient!) */ double StatisticGeneratePValue::gamma( double x ) { double w , g ; if( x <= 0.0 ){ fprintf(stderr,"Internal gamma: argument %g <= 0\a\n",x) ; return 0.0 ; } if( x < 1.0 ) return gamma_12( x+1.0 ) - log(x) ; if( x <= 2.0 ) return gamma_12( x ) ; if( x >= 6.0 ) return gamma_asympt(x) ; g = 0 ; w = x ; while( w > 2.0 ){ w -= 1.0 ; g += std::log(w) ; } return ( gamma_12(w) + g ) ; } /** * Taken from AFNI's mri_stats.c * compute log of complete beta function, using the * Unix math library's log gamma function. If this is * not available, see the end of this file. */ double StatisticGeneratePValue::lnbeta( double p , double q ) { return (gamma(p) + gamma(q) - gamma(p+q)) ; } /** * Taken from AFNI's mri_stats.c * TRANSLATED FROM THE ORIGINAL FORTRAN: *algorithm as 63 appl. statist. (1973), vol.22, no.3 * * computes incomplete beta function ratio for arguments * x between zero and one, p and q positive. * log of complete beta function, beta, is assumed to be known */ double StatisticGeneratePValue::incbeta( double x , double p , double q , double beta ) { const double ZERO = 0.0; const double ONE = 1.0; const double ACU = 1.0e-15; double betain , psq , cx , xx,pp,qq , term,ai , temp , rx ; int indx , ns ; if( p <= ZERO || q <= ZERO ) return -1.0 ; /* error! */ if( x <= ZERO ) return ZERO ; if( x >= ONE ) return ONE ; /** change tail if necessary and determine s **/ psq = p+q ; cx = ONE-x ; if( p < psq*x ){ xx = cx ; cx = x ; pp = q ; qq = p ; indx = 1 ; } else { xx = x ; pp = p ; qq = q ; indx = 0 ; } term = ONE ; ai = ONE ; betain = ONE ; ns = static_cast(qq + cx*psq) ; /** use soper's reduction formulae **/ rx = xx/cx ; lab3: temp = qq-ai ; if(ns == 0) rx = xx ; lab4: term = term*temp*rx/(pp+ai) ; betain = betain+term ; temp = std::fabs(term) ; if(temp <= ACU && temp <= ACU*betain) goto lab5 ; ai = ai+ONE ; ns = ns-1 ; if(ns >= 0) goto lab3 ; temp = psq ; psq = psq+ONE ; goto lab4 ; lab5: betain = betain*std::exp(pp*std::log(xx)+(qq-ONE)*std::log(cx)-beta)/pp ; if(indx) betain=ONE-betain ; return betain ; } caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticFalseDiscoveryRate.h0000664000175000017500000000427711572067322025742 0ustar michaelmichael #ifndef __FALSE_DISCOVERY_RATE_H__ #define __FALSE_DISCOVERY_RATE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "StatisticAlgorithm.h" /// given an array of P-Values, determine the false discovery rate /// "Thresholding of Statistical Maps in Functional Neuroimaging Using the False /// Discovery Rate" by Christopher R. Genovese, Nicole A. Lazar, and Thomas Nichols /// in NeuroImage 15, 870-878 (2002). class StatisticFalseDiscoveryRate : public StatisticAlgorithm { public: /// determination of "C" constant enum C_CONSTANT { /// use "C" equal to 1 C_CONSTANT_1, /// use "C" equal to summation of 1/i for i = [1, numValues] C_CONSTANT_SUMMATION }; // constructor StatisticFalseDiscoveryRate(const float qIn, const C_CONSTANT cConstantIn); // destructor ~StatisticFalseDiscoveryRate(); // execute the algorthm void execute() throw (StatisticException); // get the "p-cutoff" that was found when execute() ran float getPCutoff() const { return pCutoff; } protected: /// the user entered q-value float q; /// the "C" constant C_CONSTANT cConstant; /// p-cutoff found when executed float pCutoff; }; #endif // __FALSE_DISCOVERY_RATE_H__ caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticFalseDiscoveryRate.cxx0000664000175000017500000000571611572067322026314 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "StatisticDataGroup.h" #include "StatisticFalseDiscoveryRate.h" /** * constructor The input data * is expected to be group(s) of P-Values. */ StatisticFalseDiscoveryRate::StatisticFalseDiscoveryRate(const float qIn, const C_CONSTANT cConstantIn) : StatisticAlgorithm("False Discovery Rate") { pCutoff = 0.0; q = qIn; cConstant = cConstantIn; } /** * destructor. */ StatisticFalseDiscoveryRate::~StatisticFalseDiscoveryRate() { } /** * execute the algorthm (throws exception if an error occurs). */ void StatisticFalseDiscoveryRate::execute() throw (StatisticException) { if (getNumberOfDataGroups() < 1) { throw StatisticException("StatisticFalseDiscoveryRate requires at least one data group."); } pCutoff = 0.0; if ((q < 0.0) || (q > 1.0)) { throw StatisticException("\"q\" must be between 0.0 and 1.0 inclusively"); } // // copy P-Values and sort them // std::vector pValuesSorted; getAllDataValues(pValuesSorted, true); const int numPValues = static_cast(pValuesSorted.size()); if (numPValues <= 0) { throw StatisticException("Number of values is less than or equal to zero."); } // // Determine the constant "C" // float c = 0.0; switch (cConstant) { case C_CONSTANT_1: c = 1.0; break; case C_CONSTANT_SUMMATION: { c = 0.0; for (int i = 1; i <= numPValues; i++) { c += (1.0 / static_cast(i)); } } break; } // // Pre-compute part of the significance cutoff (item 3, page 872) // const float partOfSig = q / (static_cast(numPValues) * c); // // Determine the significance cutoff // int pCutoffIndex = 0; for (int i = 0; i < numPValues; i++) { const float pr = static_cast(i+1) * partOfSig; if (pValuesSorted[i] <= pr) { pCutoffIndex = i; } } pCutoff = pValuesSorted[pCutoffIndex]; } caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticException.h0000664000175000017500000000334611572067322024136 0ustar michaelmichael #ifndef __STATISTIC_EXCEPTION_H__ #define __STATISTIC_EXCEPTION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include /// a simple exception class for statistic exceptions class StatisticException : public std::exception { public: /// constructor StatisticException(const std::string& msg) { description = msg; } /// destructor virtual ~StatisticException() throw () { } /// get description of exception //virtual const char* what() const throw(); /// get description of exception virtual std::string whatStdString() const throw(); protected: /// Description of the exception std::string description; private: /// get description of exception (private to prevent its use) virtual const char* what() const throw() { return ""; } }; #endif // __STATISTIC_EXCEPTION_H__ caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticException.cxx0000664000175000017500000000230011572067322024476 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "StatisticException.h" /** * get description of exception. */ /* const char* StatisticException::what() const throw() { return description.toAscii().constData(); } */ /** * get description of exception. */ std::string StatisticException::whatStdString() const throw() { return description; } caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticDescriptiveStatistics.h0000664000175000017500000000573311572067322026536 0ustar michaelmichael #ifndef __STATISTIC_DESCRIPTIVE_STATISTICS_H__ #define __STATISTIC_DESCRIPTIVE_STATISTICS_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "StatisticAlgorithm.h" /// class for descriptive statistics calculations class StatisticDescriptiveStatistics : public StatisticAlgorithm { public: // constructor StatisticDescriptiveStatistics(); // destructor ~StatisticDescriptiveStatistics(); // generate the mean and deviation void execute() throw (StatisticException); /// get the mean float getMean() const { return mean; } // get the sample of population standard deviation (divide by N - 1) float getPopulationSampleStandardDeviation() const; // get the sample of population variance (divide by N - 1) float getPopulationSampleVariance() const; // get the standard deviation float getStandardDeviation() const; // get the variance float getVariance() const; /// get the sum of squares double getSumOfSquares() const { return sumOfSquares; } // get root mean square float getRootMeanSquare() const; // get the standard error of the mean (standard deviation of distribution of means) float getStandardErrorOfTheMean() const; // get the minimum and maximum void getMinimumAndMaximum(float& minimumOut, float& maximumOut) const; // get the median value float getMedian() const; // get the skewness float getSkewness() const; // get the kurtosis float getKurtosis() const; protected: /// the mean of the data float mean; /// number of data elements int numberOfDataElements; /// sum of data squared double dataSumSquared; /// sum of squares (sum of (xi - mean)^2) double sumOfSquares; /// sum of cubes (sum of (xi - mean)^3) double sumOfCubes; /// sum of quads (sum of (xi - mean)^4) double sumOfQuads; }; #endif // __STATISTIC_DESCRIPTIVE_STATISTICS_H__ caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticDescriptiveStatistics.cxx0000664000175000017500000001631511572067322027107 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include "StatisticDataGroup.h" #include "StatisticDescriptiveStatistics.h" /** * constructor. */ StatisticDescriptiveStatistics::StatisticDescriptiveStatistics() : StatisticAlgorithm("Descriptive Statistics") { mean = 0.0; dataSumSquared = 0.0; sumOfSquares = 0.0; sumOfCubes = 0.0; sumOfQuads = 0.0; numberOfDataElements = 0; } /** * destructor. */ StatisticDescriptiveStatistics::~StatisticDescriptiveStatistics() { } /** * generate the mean and deviation. * Formulas are from: * A Aron and E Aron * Statistics for Psychology (2nd Edition) * Upper Saddle River, NJ * Prentice Hall * 1999 */ void StatisticDescriptiveStatistics::execute() throw (StatisticException) { // // Determine mean // double dataSum = 0.0; for (int i = 0; i < getNumberOfDataGroups(); i++) { const StatisticDataGroup* sdg = getDataGroup(i); const float* data = sdg->getPointerToData(); const int numData = sdg->getNumberOfData(); for (int j = 0; j < numData; j++) { const float d = data[j]; dataSum += d; dataSumSquared += (d * d); numberOfDataElements++; } } if (numberOfDataElements <= 0) { return; } mean = dataSum / static_cast(numberOfDataElements); // // Determine sum of squares // for (int i = 0; i < getNumberOfDataGroups(); i++) { const StatisticDataGroup* sdg = getDataGroup(i); const float* data = sdg->getPointerToData(); const int numData = sdg->getNumberOfData(); for (int j = 0; j < numData; j++) { const double diff = data[j] - mean; sumOfSquares += (diff * diff); sumOfCubes += (sumOfSquares * diff); sumOfQuads += (sumOfCubes * diff); } } } /** * get the skewness. * http://www.statsdirect.com/help/basic_descriptive_statistics/desc.htm */ float StatisticDescriptiveStatistics::getSkewness() const { float s = 0.0; if (numberOfDataElements > 0) { const float numerator = sumOfCubes / static_cast(numberOfDataElements); const double variance = getVariance(); const float denominator = std::pow(variance, 1.5); if (denominator > 0.0) { s = numerator / denominator; } } return s; } /** * get the kurtosis. * http://www.statsdirect.com/help/basic_descriptive_statistics/desc.htm */ float StatisticDescriptiveStatistics::getKurtosis() const { float k = 0; if (numberOfDataElements > 0) { const float numerator = sumOfQuads / static_cast(numberOfDataElements); const float variance = getVariance(); const float denominator = variance * variance; if (denominator > 0.0) { k = numerator / denominator; } } return k; } /** * get the median value. */ float StatisticDescriptiveStatistics::getMedian() const { if (numberOfDataElements < 1) { return 0.0; } std::vector dataSorted; for (int i = 0; i < getNumberOfDataGroups(); i++) { const StatisticDataGroup* sdg = getDataGroup(i); const float* data = sdg->getPointerToData(); const int numData = sdg->getNumberOfData(); for (int j = 0; j < numData; j++) { dataSorted.push_back(data[j]); } } std::sort(dataSorted.begin(), dataSorted.end()); int middleIndex = numberOfDataElements / 2; const float median = dataSorted[middleIndex]; return median; } /** * get the minimum and maximum. */ void StatisticDescriptiveStatistics::getMinimumAndMaximum(float& minimumOut, float& maximumOut) const { if (numberOfDataElements < 1) { minimumOut = 0.0; maximumOut = 0.0; } minimumOut = std::numeric_limits::max(); maximumOut = -std::numeric_limits::max(); for (int i = 0; i < getNumberOfDataGroups(); i++) { const StatisticDataGroup* sdg = getDataGroup(i); const float* data = sdg->getPointerToData(); const int numData = sdg->getNumberOfData(); for (int j = 0; j < numData; j++) { const float d = data[j]; minimumOut = std::min(minimumOut, d); maximumOut = std::max(maximumOut, d); } } } /** * get the sample of population standard deviation (divide by N - 1). * http://www.statsdirect.com/help/basic_descriptive_statistics/standard_deviation.htm */ float StatisticDescriptiveStatistics::getPopulationSampleStandardDeviation() const { const float sd = std::sqrt(getPopulationSampleVariance()); return sd; } /** * get the sample of population variance (divied by N - 1). * http://www.statsdirect.com/help/basic_descriptive_statistics/standard_deviation.htm */ float StatisticDescriptiveStatistics::getPopulationSampleVariance() const { if (numberOfDataElements <= 1) { return 0.0; } const float pv = sumOfSquares / static_cast(numberOfDataElements - 1); return pv; } /** * get the standard deviation. * http://www.statsdirect.com/help/basic_descriptive_statistics/standard_deviation.htm */ float StatisticDescriptiveStatistics::getStandardDeviation() const { const float d = std::sqrt(getVariance()); return d; } /** * get the variance. * http://www.statsdirect.com/help/basic_descriptive_statistics/standard_deviation.htm */ float StatisticDescriptiveStatistics::getVariance() const { if (numberOfDataElements <= 1) { return 0.0; } const float v= sumOfSquares / static_cast(numberOfDataElements); return v; } /** * get the standard error (standard deviation of distribution of means). * http://www.statsdirect.com/help/basic_descriptive_statistics/standard_deviation.htm */ float StatisticDescriptiveStatistics::getStandardErrorOfTheMean() const { if (numberOfDataElements <= 1) { return 0.0; } const double sn = std::sqrt(static_cast(numberOfDataElements)); const float se = getPopulationSampleStandardDeviation() / sn; return se; } /** * get root mean square. * http://mathworld.wolfram.com/Root-Mean-Square.html */ float StatisticDescriptiveStatistics::getRootMeanSquare() const { if (numberOfDataElements <= 0) { return 0.0; } const float rms = std::sqrt(dataSumSquared / static_cast(numberOfDataElements)); return rms; } caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticDcdflibIpmpar.cxx0000664000175000017500000002232111572067322025245 0ustar michaelmichaelint ipmpar(int*); /* ----------------------------------------------------------------------- IPMPAR PROVIDES THE INTEGER MACHINE CONSTANTS FOR THE COMPUTER THAT IS USED. IT IS ASSUMED THAT THE ARGUMENT I IS AN INTEGER HAVING ONE OF THE VALUES 1-10. IPMPAR(I) HAS THE VALUE ... INTEGERS. ASSUME INTEGERS ARE REPRESENTED IN THE N-DIGIT, BASE-A FORM SIGN ( X(N-1)*A**(N-1) + ... + X(1)*A + X(0) ) WHERE 0 .LE. X(I) .LT. A FOR I=0,...,N-1. IPMPAR(1) = A, THE BASE. IPMPAR(2) = N, THE NUMBER OF BASE-A DIGITS. IPMPAR(3) = A**N - 1, THE LARGEST MAGNITUDE. FLOATING-POINT NUMBERS. IT IS ASSUMED THAT THE SINGLE AND DOUBLE PRECISION FLOATING POINT ARITHMETICS HAVE THE SAME BASE, SAY B, AND THAT THE NONZERO NUMBERS ARE REPRESENTED IN THE FORM SIGN (B**E) * (X(1)/B + ... + X(M)/B**M) WHERE X(I) = 0,1,...,B-1 FOR I=1,...,M, X(1) .GE. 1, AND EMIN .LE. E .LE. EMAX. IPMPAR(4) = B, THE BASE. SINGLE-PRECISION IPMPAR(5) = M, THE NUMBER OF BASE-B DIGITS. IPMPAR(6) = EMIN, THE SMALLEST EXPONENT E. IPMPAR(7) = EMAX, THE LARGEST EXPONENT E. DOUBLE-PRECISION IPMPAR(8) = M, THE NUMBER OF BASE-B DIGITS. IPMPAR(9) = EMIN, THE SMALLEST EXPONENT E. IPMPAR(10) = EMAX, THE LARGEST EXPONENT E. ----------------------------------------------------------------------- TO DEFINE THIS FUNCTION FOR THE COMPUTER BEING USED REMOVE THE COMMENT DELIMITORS FROM THE DEFINITIONS DIRECTLY BELOW THE NAME OF THE MACHINE ----------------------------------------------------------------------- IPMPAR IS AN ADAPTATION OF THE FUNCTION I1MACH, WRITTEN BY P.A. FOX, A.D. HALL, AND N.L. SCHRYER (BELL LABORATORIES). IPMPAR WAS FORMED BY A.H. MORRIS (NSWC). THE CONSTANTS ARE FROM BELL LABORATORIES, NSWC, AND OTHER SOURCES. ----------------------------------------------------------------------- .. Scalar Arguments .. */ int ipmpar(int *i) { static int imach[11]; static int ipmpar; /* MACHINE CONSTANTS FOR AMDAHL MACHINES. */ /* imach[1] = 2; imach[2] = 31; imach[3] = 2147483647; imach[4] = 16; imach[5] = 6; imach[6] = -64; imach[7] = 63; imach[8] = 14; imach[9] = -64; imach[10] = 63; */ /* MACHINE CONSTANTS FOR THE AT&T 3B SERIES, AT&T PC 7300, AND AT&T 6300. */ /* imach[1] = 2; imach[2] = 31; imach[3] = 2147483647; imach[4] = 2; imach[5] = 24; imach[6] = -125; imach[7] = 128; imach[8] = 53; imach[9] = -1021; imach[10] = 1024; */ /* MACHINE CONSTANTS FOR THE BURROUGHS 1700 SYSTEM. */ /* imach[1] = 2; imach[2] = 33; imach[3] = 8589934591; imach[4] = 2; imach[5] = 24; imach[6] = -256; imach[7] = 255; imach[8] = 60; imach[9] = -256; imach[10] = 255; */ /* MACHINE CONSTANTS FOR THE BURROUGHS 5700 SYSTEM. */ /* imach[1] = 2; imach[2] = 39; imach[3] = 549755813887; imach[4] = 8; imach[5] = 13; imach[6] = -50; imach[7] = 76; imach[8] = 26; imach[9] = -50; imach[10] = 76; */ /* MACHINE CONSTANTS FOR THE BURROUGHS 6700/7700 SYSTEMS. */ /* imach[1] = 2; imach[2] = 39; imach[3] = 549755813887; imach[4] = 8; imach[5] = 13; imach[6] = -50; imach[7] = 76; imach[8] = 26; imach[9] = -32754; imach[10] = 32780; */ /* MACHINE CONSTANTS FOR THE CDC 6000/7000 SERIES 60 BIT ARITHMETIC, AND THE CDC CYBER 995 64 BIT ARITHMETIC (NOS OPERATING SYSTEM). */ /* imach[1] = 2; imach[2] = 48; imach[3] = 281474976710655; imach[4] = 2; imach[5] = 48; imach[6] = -974; imach[7] = 1070; imach[8] = 95; imach[9] = -926; imach[10] = 1070; */ /* MACHINE CONSTANTS FOR THE CDC CYBER 995 64 BIT ARITHMETIC (NOS/VE OPERATING SYSTEM). */ /* imach[1] = 2; imach[2] = 63; imach[3] = 9223372036854775807; imach[4] = 2; imach[5] = 48; imach[6] = -4096; imach[7] = 4095; imach[8] = 96; imach[9] = -4096; imach[10] = 4095; */ /* MACHINE CONSTANTS FOR THE CRAY 1, XMP, 2, AND 3. */ /* imach[1] = 2; imach[2] = 63; imach[3] = 9223372036854775807; imach[4] = 2; imach[5] = 47; imach[6] = -8189; imach[7] = 8190; imach[8] = 94; imach[9] = -8099; imach[10] = 8190; */ /* MACHINE CONSTANTS FOR THE DATA GENERAL ECLIPSE S/200. */ /* imach[1] = 2; imach[2] = 15; imach[3] = 32767; imach[4] = 16; imach[5] = 6; imach[6] = -64; imach[7] = 63; imach[8] = 14; imach[9] = -64; imach[10] = 63; */ /* MACHINE CONSTANTS FOR THE HARRIS 220. */ /* imach[1] = 2; imach[2] = 23; imach[3] = 8388607; imach[4] = 2; imach[5] = 23; imach[6] = -127; imach[7] = 127; imach[8] = 38; imach[9] = -127; imach[10] = 127; */ /* MACHINE CONSTANTS FOR THE HONEYWELL 600/6000 AND DPS 8/70 SERIES. */ /* imach[1] = 2; imach[2] = 35; imach[3] = 34359738367; imach[4] = 2; imach[5] = 27; imach[6] = -127; imach[7] = 127; imach[8] = 63; imach[9] = -127; imach[10] = 127; */ /* MACHINE CONSTANTS FOR THE HP 2100 3 WORD DOUBLE PRECISION OPTION WITH FTN4 */ /* imach[1] = 2; imach[2] = 15; imach[3] = 32767; imach[4] = 2; imach[5] = 23; imach[6] = -128; imach[7] = 127; imach[8] = 39; imach[9] = -128; imach[10] = 127; */ /* MACHINE CONSTANTS FOR THE HP 2100 4 WORD DOUBLE PRECISION OPTION WITH FTN4 */ /* imach[1] = 2; imach[2] = 15; imach[3] = 32767; imach[4] = 2; imach[5] = 23; imach[6] = -128; imach[7] = 127; imach[8] = 55; imach[9] = -128; imach[10] = 127; */ /* MACHINE CONSTANTS FOR THE HP 9000. */ /* imach[1] = 2; imach[2] = 31; imach[3] = 2147483647; imach[4] = 2; imach[5] = 24; imach[6] = -126; imach[7] = 128; imach[8] = 53; imach[9] = -1021; imach[10] = 1024; */ /* MACHINE CONSTANTS FOR THE IBM 360/370 SERIES, THE ICL 2900, THE ITEL AS/6, THE XEROX SIGMA 5/7/9 AND THE SEL SYSTEMS 85/86. */ /* imach[1] = 2; imach[2] = 31; imach[3] = 2147483647; imach[4] = 16; imach[5] = 6; imach[6] = -64; imach[7] = 63; imach[8] = 14; imach[9] = -64; imach[10] = 63; */ /* MACHINE CONSTANTS FOR THE IBM PC. */ /* imach[1] = 2; imach[2] = 31; imach[3] = 2147483647; imach[4] = 2; imach[5] = 24; imach[6] = -125; imach[7] = 128; imach[8] = 53; imach[9] = -1021; imach[10] = 1024; */ /* MACHINE CONSTANTS FOR THE MACINTOSH II - ABSOFT MACFORTRAN II. */ /* imach[1] = 2; imach[2] = 31; imach[3] = 2147483647; imach[4] = 2; imach[5] = 24; imach[6] = -125; imach[7] = 128; imach[8] = 53; imach[9] = -1021; imach[10] = 1024; */ /* MACHINE CONSTANTS FOR THE MICROVAX - VMS FORTRAN. */ /* imach[1] = 2; imach[2] = 31; imach[3] = 2147483647; imach[4] = 2; imach[5] = 24; imach[6] = -127; imach[7] = 127; imach[8] = 56; imach[9] = -127; imach[10] = 127; */ /* MACHINE CONSTANTS FOR THE PDP-10 (KA PROCESSOR). */ /* imach[1] = 2; imach[2] = 35; imach[3] = 34359738367; imach[4] = 2; imach[5] = 27; imach[6] = -128; imach[7] = 127; imach[8] = 54; imach[9] = -101; imach[10] = 127; */ /* MACHINE CONSTANTS FOR THE PDP-10 (KI PROCESSOR). */ /* imach[1] = 2; imach[2] = 35; imach[3] = 34359738367; imach[4] = 2; imach[5] = 27; imach[6] = -128; imach[7] = 127; imach[8] = 62; imach[9] = -128; imach[10] = 127; */ /* MACHINE CONSTANTS FOR THE PDP-11 FORTRAN SUPPORTING 32-BIT INTEGER ARITHMETIC. */ /* imach[1] = 2; imach[2] = 31; imach[3] = 2147483647; imach[4] = 2; imach[5] = 24; imach[6] = -127; imach[7] = 127; imach[8] = 56; imach[9] = -127; imach[10] = 127; */ /* MACHINE CONSTANTS FOR THE SEQUENT BALANCE 8000. */ /* imach[1] = 2; imach[2] = 31; imach[3] = 2147483647; imach[4] = 2; imach[5] = 24; imach[6] = -125; imach[7] = 128; imach[8] = 53; imach[9] = -1021; imach[10] = 1024; */ /* MACHINE CONSTANTS FOR THE SILICON GRAPHICS IRIS-4D SERIES (MIPS R3000 PROCESSOR). */ /* imach[1] = 2; imach[2] = 31; imach[3] = 2147483647; imach[4] = 2; imach[5] = 24; imach[6] = -125; imach[7] = 128; imach[8] = 53; imach[9] = -1021; imach[10] = 1024; */ /* MACHINE CONSTANTS FOR IEEE ARITHMETIC MACHINES, SUCH AS THE AT&T 3B SERIES, MOTOROLA 68000 BASED MACHINES (E.G. SUN 3 AND AT&T PC 7300), AND 8087 BASED MICROS (E.G. IBM PC AND AT&T 6300). */ imach[1] = 2; imach[2] = 31; imach[3] = 2147483647; imach[4] = 2; imach[5] = 24; imach[6] = -125; imach[7] = 128; imach[8] = 53; imach[9] = -1021; imach[10] = 1024; /* MACHINE CONSTANTS FOR THE UNIVAC 1100 SERIES. */ /* imach[1] = 2; imach[2] = 35; imach[3] = 34359738367; imach[4] = 2; imach[5] = 27; imach[6] = -128; imach[7] = 127; imach[8] = 60; imach[9] = -1024; imach[10] = 1023; */ /* MACHINE CONSTANTS FOR THE VAX 11/780. */ /* imach[1] = 2; imach[2] = 31; imach[3] = 2147483647; imach[4] = 2; imach[5] = 24; imach[6] = -127; imach[7] = 127; imach[8] = 56; imach[9] = -127; imach[10] = 127; */ ipmpar = imach[*i]; return ipmpar; } caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticDcdflib.h0000664000175000017500000000752711572067322023534 0ustar michaelmichael#ifndef __STATISTIC_DCDFLIB_H__ #define __STATISTIC_DCDFLIB_H__ /* * See corresponding cxx file for documentation. */ double algdiv(double*,double*); double alngam(double*); double alnrel(double*); double apser(double*,double*,double*,double*); double basym(double*,double*,double*,double*); double bcorr(double*,double*); double betaln(double*,double*); double bfrac(double*,double*,double*,double*,double*,double*); void bgrat(double*,double*,double*,double*,double*,double*,int*i); double bpser(double*,double*,double*,double*); void bratio(double*,double*,double*,double*,double*,double*,int*); double brcmp1(int*,double*,double*,double*,double*); double brcomp(double*,double*,double*,double*); double bup(double*,double*,double*,double*,int*,double*); void cdfbet(int*,double*,double*,double*,double*,double*,double*, int*,double*); void cdfbin(int*,double*,double*,double*,double*,double*,double*, int*,double*); void cdfchi(int*,double*,double*,double*,double*,int*,double*); void cdfchn(int*,double*,double*,double*,double*,double*,int*,double*); void cdff(int*,double*,double*,double*,double*,double*,int*,double*); void cdffnc(int*,double*,double*,double*,double*,double*,double*, int*s,double*); void cdfgam(int*,double*,double*,double*,double*,double*,int*,double*); void cdfnbn(int*,double*,double*,double*,double*,double*,double*, int*,double*); void cdfnor(int*,double*,double*,double*,double*,double*,int*,double*); void cdfpoi(int*,double*,double*,double*,double*,int*,double*); void cdft(int*,double*,double*,double*,double*,int*,double*); void cdftnc(int*,double*,double*,double*,double*,double*,int*,double*); void cumbet(double*,double*,double*,double*,double*,double*); void cumbin(double*,double*,double*,double*,double*,double*); void cumchi(double*,double*,double*,double*); void cumchn(double*,double*,double*,double*,double*); void cumf(double*,double*,double*,double*,double*); void cumfnc(double*,double*,double*,double*,double*,double*); void cumgam(double*,double*,double*,double*); void cumnbn(double*,double*,double*,double*,double*,double*); void cumnor(double*,double*,double*); void cumpoi(double*,double*,double*,double*); void cumt(double*,double*,double*,double*); void cumtnc(double*,double*,double*,double*,double*); double devlpl(double [],int*,double*); double dinvnr(double *p,double *q); /*static*/ void E0000(int,int*,double*,double*,unsigned long*, unsigned long*,double*,double*,double*, double*,double*,double*,double*); void dinvr(int*,double*,double*,unsigned long*,unsigned long*); void dstinv(double*,double*,double*,double*,double*,double*, double*); double dt1(double*,double*,double*); /*static*/ void E0001(int,int*,double*,double*,double*,double*, unsigned long*,unsigned long*,double*,double*, double*,double*); void dzror(int*,double*,double*,double*,double *, unsigned long*,unsigned long*); void dstzr(double *zxlo,double *zxhi,double *zabstl,double *zreltl); double erf1(double*); double erfc1(int*,double*); double esum(int*,double*); double exparg(int*); double fpser(double*,double*,double*,double*); double gam1(double*); void gaminv(double*,double*,double*,double*,double*,int*); double gamln(double*); double gamln1(double*); double Xgamm(double*); void grat1(double*,double*,double*,double*,double*,double*); void gratio(double*,double*,double*,double*,int*); double gsumln(double*,double*); double psi(double*); double rcomp(double*,double*); double rexp(double*); double rlog(double*); double rlog1(double*); double spmpar(int*); double stvaln(double*); double fifdint(double); double fifdmax1(double,double); double fifdmin1(double,double); double fifdsign(double,double); long fifidint(double); long fifmod(long,long); void ftnstop(const char*); extern int ipmpar(int*); #endif //__STATISTIC_DCDFLIB_H__ caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticDcdflib.cxx0000664000175000017500000072676611572067322024124 0ustar michaelmichael /* * http://biostatistics.mdanderson.org/SoftwareDownload/SingleSoftware.aspx?Software_Id=21 DCDFLIB Library of C Routines for Cumulative Distribution Functions, Inverses, and Other Parameters Version 1.1 (November, 1997) Summary Documentation of Each Routine Compiled and Written by: Barry W. Brown James Lovato Kathy Russell Department of Biomathematics, Box 237 The University of Texas, M.D. Anderson Cancer Center 1515 Holcombe Boulevard Houston, TX 77030 This work was supported by grant CA-16672 from the National Cancer Institute. SUMMARY OF DCDFLIB This library contains routines to compute cumulative distribution functions, inverses, and parameters of the distribution for the following set of statistical distributions: (1) Beta (2) Binomial (3) Chi-square (4) Noncentral Chi-square (5) F (6) Noncentral F (7) Gamma (8) Negative Binomial (9) Normal (10) Poisson (11) Student's t (12) Noncentral t Given values of all but one parameter of a distribution, the other is computed. These calculations are done with C pointers to Doubles. -------------------- WARNINGS -------------------- The F and Noncentral F distribution are not necessarily monotone in either degree of freedom argument. Consequently, there may be two degree of freedom arguments that satisfy the specified condition. An arbitrary one of these will be found by the cdf routines. The amount of computation required for the noncentral chisquare and noncentral F distribution is proportional to the value of the noncentrality parameter. Very large values of this parameter can require immense numbers of computation. Consequently, when the noncentrality parameter is to be calculated, the upper limit searched is 10,000. For the noncentral t, the computation time is proportional to the noncentrality parameter so the upper limit searched is 10000. -------------------- END WARNINGS -------------------- COMMENTS ON THE C VERSION OF DCDFLIB The C version was obtained by converting the original Fortran DCDFLIB to C using PROMULA.FORTRAN and performing some hand crafting of the result. Information on PROMULA.FORTRAN can be obtained from PROMULA Development Corporation 3620 N. High Street, Suite 301 Columbus, Ohio 43214 (614) 263-5454 DCDFLIB.C was tested using the xlc compiler under AIX 3.1 on an IBM RS/6000. The code was also examined with lint on the same system. DCDFLIB was also successfully tested run using the gcc compiler (see below) on a Solbourne. DCDFLIB.C can be obtained by anonymous ftp to odin.mda.uth.tmc.edu (129.106.3.17) where it is available as /pub/unix/dcdflib.c.tar.Z The Fortran version of DCDFLIB is available as /pub/unix/dcdflib.f.tar.Z on the same machine. ^L CAVEAT DCDFLIB.C is written in ANSI C and makes heavy use of prototypes. It will not compile under old style (KR) C compilers (such as the default Sun cc compiler). I don't recommend conversion to an obsolete C dialect. Instead, get the Free Software Foundation's excellent ANSI C compiler, gcc. It compiles KR C as well as ANSI C. A version of gcc that runs on many varieties of Unix is available by anonymous ftp as /pub/gnu/gcc-1.40.tar.Z at prep.ai.mit.edu (18.71.0.38). A Vax version is also present on /pub/gnu. The compilers are also available on tape. Write the Free Software Foundation at: Free Software Foundation, Inc. 675 Massachusetts Avenue Cambridge, MA 02139 Phone: (617) 876-3296 A MSDOS port of gcc, performed by DJ Delorie is also available by ftp. File location: host: grape.ecs.clarkson.edu login: ftp password: send your e-mail address directory: ~ftp/pub/msdos/djgcc File in .ZIP format - djgpp.zip - one 2.2M file, contains everything. A version of DCDFLIB which compiles under old style C can be obtained by anonymous ftp to odin.mda.uth.tmc.edu (129.106.3.17) where it is available as /pub/unix/dcdflib.kr.c.tar.Z DOCUMENTATION This file contains an overview of the library and is the primary documentation. Other documentation is in directory 'doc' on the distribution as character (ASCII) files. A summary of all of the available routines is contained in dcdflib.chs (chs is an abbreviation of 'cheat sheet'). The 'chs' file will probably be the primary reference. The file, dcdflib.fdoc, contains the comments for each routine intended for direct use. The file, dcdflib.h, contains prototypes for each routine intended for direct use. INSTALLATION Directory src contains the C source. The files ipmpar.c and dcdflib.c constitute DCDFLIB. The file cdflib.h is included in dcdflib.c. A few routines use machine dependent constants. Lists of such constants for different machines are found in ipmpar.c. Uncomment the ones appropriate to your machine. The distributed version uses the IEEE arithmetic that is used by the IBM PC, Macintosh, and most Unix workstations. If you need to change the distribution version you must comment out the definitions for IEEE arithmetic as well as uncomment the ones appropriate to your machine. NOTE: dcdflib should be linked to the C math library. NOTE: Ignore compiler warnings of the type "statement not reached". SOURCES The following routines, written by others, are incorporated into DCDFLIB. Beta Distribution DiDinato, A. R. and Morris, A. H. Algorithm 708: Significant Digit Computation of the Incomplete Beta Function Ratios. ACM Trans. Math. Softw. 18 (1993), 360-373. Gamma Distribution and It's Inverse DiDinato, A. R. and Morris, A. H. Computation of the Incomplete Gamma Function Ratios and their Inverse. ACM Trans. Math. Softw. 12 (1986), 377-393. Normal Distribution Kennedy and Gentle, Statistical Computing, Marcel Dekker, NY, 1980. The rational function approximations from pages 90-95 are used during the calculation of the inverse normal. Cody, W.D. (1993). "ALGORITHM 715: SPECFUN - A Portabel FORTRAN Package of Special Function Routines and Test Drivers", acm Transactions on Mathematical Software. 19, 22-32. A slightly modified version of Cody's function anorm is used for the cumultive normal. Zero Finder J. C. P. Bus and T. J. Dekker. Two Efficient Algorithms with Guaranteed Convergence for Finding a Zero of a Function. ACM Trans. Math. Softw. 4 (1975), 330. We transliterated Algoritm R of this paper from Algol to Fortran. General Reference Abramowitz, M. and Stegun, I. A. Handbook of Mathematical Functions With Formulas, Graphs, and Mathematical Tables. (1964) National Bureau of Standards. This book has been reprinted by Dover and others. LEGALITIES Code that appeared in an ACM publication is subject to their algorithms policy: Submittal of an algorithm for publication in one of the ACM Transactions implies that unrestricted use of the algorithm within a computer is permissible. General permission to copy and distribute the algorithm without fee is granted provided that the copies are not made or distributed for direct commercial advantage. The ACM copyright notice and the title of the publication and its date appear, and notice is given that copying is by permission of the Association for Computing Machinery. To copy otherwise, or to republish, requires a fee and/or specific permission. Krogh, F. Algorithms Policy. ACM Tran. Math. Softw. 13(1987), 183-186. We place the DCDFLIB code that we have written in the public domain. NO WARRANTY WE PROVIDE ABSOLUTELY NO 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 THIS PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. IN NO EVENT SHALL THE UNIVERSITY OF TEXAS OR ANY OF ITS COMPONENT INSTITUTIONS INCLUDING M. D. ANDERSON HOSPITAL BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA OR ITS ANALYSIS BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES) THE PROGRAM. (Above NO WARRANTY modified from the GNU NO WARRANTY statement.) HOW TO USE THE ROUTINES The calling sequence for each routine is of the form: void cdf(int *which,double *p,double *q,double *x, double *,int *status,double *bound) WHICH and STATUS are pointers to int , all other arguments are pointers to double. is a one to three character name identifying the distribution. which is an input integer value that identifies what parameter value is to be calculated from the values of the other parameters. P is always the cdf evaluated at X, Q is always the compliment of the cdf evaluated at X, i.e. 1-P, and X is always the value at which the cdf is evaluated. The auxiliary parameters, , of the distribution differ by distribution. If WHICH is 1, P and Q are to be calculated, i.e., the cdf; if WHICH is 2, X is to be calculated, i.e., the inverse cdf. The value of one auxiliary parameter in can also be the value calculated. STATUS returns 0 if the calculation completes correctly. --------------------WARNING-------------------- If STATUS is not 0, no meaningful answer is returned. -------------------- END WARNING -------------------- STATUS returns -I if the I'th input parameter was not in the legal range (see below). Parameters are counted with which being the first in these return values. A STATUS value of 1 indicates that the desired answer was apparently lower than the lower bound on the search interval. A return code of 2 indicates that the answer was apparently higher than the upper bound on the search interval. A return code of 3 indicates that P and Q did not sum to 1. Other positive codes are routine specific. BOUND is not set if status is returned as 0. If STATUS is -I then BOUND is the bound illegally exceeded by input parameter I, where WHICH is counted as 1, P as 2, Q as 3, X as 4, etc. If STATUS is returned as 1 or 2 then bound is returned as the lower or upper bound on the search interval respectively. BOUNDS Below are the rules that we used in determining bounds on quantities to be calculated. Those who don't care can find a summary of the bounds in dcdflib.chs. Input bounds are checked for legality of input. The search range is the range of values searched for an answer. Input Bounds Bounds on input parameters are checked by the cdf* routines. These bounds were set according to the following rules. P: If the domain of the cdf (X) extends to -infinity then P must be greater than 0 otherwise P must be greater than or equal to 0. P must always be less than or equal to 1. Q: If the domain of the cdf (X) extends to +infinity then Q must be greater than 0 otherwise Q must be greater than or equal to 0. Q must always be less than or equal to 1. Further, P and Q must sum to 1. The smaller of the two P and Q will be used in calculations to increase accuracy X: If the domain is infinite in either the positive or negative direction, no check is performed in that direction. If the left end of the domain is 0, then X is checked to assure non-negativity. DF, SD, etc.: Some auxiliary parameters must be positive. The lowest input values accepted for these parameters is 1E-100. Search Bounds These are the ranges searched for an answer. If the domain of the parameter in the cdf is closed at some finite value, e.g., 0, then this value is the same endpoint of the search range. If the domain is open at some finite endpoint (which only occurs for 0 -- some parameters must be strictly positive) then the endpoint is 1E-100. If the domain is infinite in either direction then +/- 1E100 is used as the endpoint of the search range. HOW THE ROUTINES WORK The cumulative distribution functions are computed directly. The normal, gamma, and beta functions use the code from the references cited. Other cdfs are calculated by relating them to one of these distributions. For example, the binomial and negative binomial cdfs can be converted to a beta cdf. This is how fractional observations are handled. The formula from Abramowitz and Stegun for converting the cdfs is cited in the fdoc file. (We think the formula for the negative binomial in A&S is wrong, but there is a correct one which we used.) The inverse normal and gamma are also taken from the references. For all other parameters, a search is made for the value that provides the desired P. Initial values are chosen crudely for the search (e.g., 5). If the domain of the cdf for the parameter being calculated is infinite, a step doubling strategy is used to bound the desired value then the zero finder is employed to refine the answer. The zero finder attempts to obtain the answer accurately to about eight decimal places. */ #include #include #include #include "StatisticDcdflib.h" /* * A comment about ints and longs - whether ints or longs are used should * make no difference, but where double r-values are assigned to ints the * r-value is cast converted to a long, which is then assigned to the int * to be compatible with the operation of fifidint. */ /* ----------------------------------------------------------------------- COMPUTATION OF LN(GAMMA(B)/GAMMA(A+B)) WHEN B .GE. 8 -------- IN THIS ALGORITHM, DEL(X) IS THE FUNCTION DEFINED BY LN(GAMMA(X)) = (X - 0.5)*LN(X) - X + 0.5*LN(2*PI) + DEL(X). ----------------------------------------------------------------------- */ double algdiv(double *a,double *b) { static double c0 = .833333333333333e-01; static double c1 = -.277777777760991e-02; static double c2 = .793650666825390e-03; static double c3 = -.595202931351870e-03; static double c4 = .837308034031215e-03; static double c5 = -.165322962780713e-02; static double algdiv,c,d,h,s11,s3,s5,s7,s9,t,u,v,w,x,x2,T1; /* .. .. Executable Statements .. */ if(*a <= *b) goto S10; h = *b/ *a; c = 1.0e0/(1.0e0+h); x = h/(1.0e0+h); d = *a+(*b-0.5e0); goto S20; S10: h = *a/ *b; c = h/(1.0e0+h); x = 1.0e0/(1.0e0+h); d = *b+(*a-0.5e0); S20: /* SET SN = (1 - X**N)/(1 - X) */ x2 = x*x; s3 = 1.0e0+(x+x2); s5 = 1.0e0+(x+x2*s3); s7 = 1.0e0+(x+x2*s5); s9 = 1.0e0+(x+x2*s7); s11 = 1.0e0+(x+x2*s9); /* SET W = DEL(B) - DEL(A + B) */ t = pow(1.0e0/ *b,2.0); w = ((((c5*s11*t+c4*s9)*t+c3*s7)*t+c2*s5)*t+c1*s3)*t+c0; w *= (c/ *b); /* COMBINE THE RESULTS */ T1 = *a/ *b; u = d*alnrel(&T1); v = *a*(log(*b)-1.0e0); if(u <= v) goto S30; algdiv = w-v-u; return algdiv; S30: algdiv = w-u-v; return algdiv; } double alngam(double *x) /* ********************************************************************** double alngam(double *x) double precision LN of the GAMma function Function Returns the natural logarithm of GAMMA(X). Arguments X --> value at which scaled log gamma is to be returned X is DOUBLE PRECISION Method If X .le. 6.0, then use recursion to get X below 3 then apply rational approximation number 5236 of Hart et al, Computer Approximations, John Wiley and Sons, NY, 1968. If X .gt. 6.0, then use recursion to get X to at least 12 and then use formula 5423 of the same source. ********************************************************************** */ { #define hln2pi 0.91893853320467274178e0 static double coef[5] = { 0.83333333333333023564e-1,-0.27777777768818808e-2,0.79365006754279e-3, -0.594997310889e-3,0.8065880899e-3 }; static double scoefd[4] = { 0.62003838007126989331e2,0.9822521104713994894e1,-0.8906016659497461257e1, 0.1000000000000000000e1 }; static double scoefn[9] = { 0.62003838007127258804e2,0.36036772530024836321e2,0.20782472531792126786e2, 0.6338067999387272343e1,0.215994312846059073e1,0.3980671310203570498e0, 0.1093115956710439502e0,0.92381945590275995e-2,0.29737866448101651e-2 }; static int K1 = 9; static int K3 = 4; static int K5 = 5; static double alngam,offset,prod,xx; static int i,n; static double T2,T4,T6; /* .. .. Executable Statements .. */ if(!(*x <= 6.0e0)) goto S70; prod = 1.0e0; xx = *x; if(!(*x > 3.0e0)) goto S30; S10: if(!(xx > 3.0e0)) goto S20; xx -= 1.0e0; prod *= xx; goto S10; S30: S20: if(!(*x < 2.0e0)) goto S60; S40: if(!(xx < 2.0e0)) goto S50; prod /= xx; xx += 1.0e0; goto S40; S60: S50: T2 = xx-2.0e0; T4 = xx-2.0e0; alngam = devlpl(scoefn,&K1,&T2)/devlpl(scoefd,&K3,&T4); /* COMPUTE RATIONAL APPROXIMATION TO GAMMA(X) */ alngam *= prod; alngam = log(alngam); goto S110; S70: offset = hln2pi; /* IF NECESSARY MAKE X AT LEAST 12 AND CARRY CORRECTION IN OFFSET */ n = fifidint(12.0e0-*x); if(!(n > 0)) goto S90; prod = 1.0e0; for(i=1; i<=n; i++) prod *= (*x+(double)(i-1)); offset -= log(prod); xx = *x+(double)n; goto S100; S90: xx = *x; S100: /* COMPUTE POWER SERIES */ T6 = 1.0e0/pow(xx,2.0); alngam = devlpl(coef,&K5,&T6)/xx; alngam += (offset+(xx-0.5e0)*log(xx)-xx); S110: return alngam; #undef hln2pi } double alnrel(double *a) /* ----------------------------------------------------------------------- EVALUATION OF THE FUNCTION LN(1 + A) ----------------------------------------------------------------------- */ { static double p1 = -.129418923021993e+01; static double p2 = .405303492862024e+00; static double p3 = -.178874546012214e-01; static double q1 = -.162752256355323e+01; static double q2 = .747811014037616e+00; static double q3 = -.845104217945565e-01; static double alnrel,t,t2,w,x; /* .. .. Executable Statements .. */ if(fabs(*a) > 0.375e0) goto S10; t = *a/(*a+2.0e0); t2 = t*t; w = (((p3*t2+p2)*t2+p1)*t2+1.0e0)/(((q3*t2+q2)*t2+q1)*t2+1.0e0); alnrel = 2.0e0*t*w; return alnrel; S10: x = 1.e0+*a; alnrel = log(x); return alnrel; } double apser(double *a,double *b,double *x,double *eps) /* ----------------------------------------------------------------------- APSER YIELDS THE INCOMPLETE BETA RATIO I(SUB(1-X))(B,A) FOR A .LE. MIN(EPS,EPS*B), B*X .LE. 1, AND X .LE. 0.5. USED WHEN A IS VERY SMALL. USE ONLY IF ABOVE INEQUALITIES ARE SATISFIED. ----------------------------------------------------------------------- */ { static double g = .577215664901533e0; static double apser,aj,bx,c,j,s,t,tol; /* .. .. Executable Statements .. */ bx = *b**x; t = *x-bx; if(*b**eps > 2.e-2) goto S10; c = log(*x)+psi(b)+g+t; goto S20; S10: c = log(bx)+g+t; S20: tol = 5.0e0**eps*fabs(c); j = 1.0e0; s = 0.0e0; S30: j += 1.0e0; t *= (*x-bx/j); aj = t/j; s += aj; if(fabs(aj) > tol) goto S30; apser = -(*a*(c+s)); return apser; } double basym(double *a,double *b,double *lambda,double *eps) /* ----------------------------------------------------------------------- ASYMPTOTIC EXPANSION FOR IX(A,B) FOR LARGE A AND B. LAMBDA = (A + B)*Y - B AND EPS IS THE TOLERANCE USED. IT IS ASSUMED THAT LAMBDA IS NONNEGATIVE AND THAT A AND B ARE GREATER THAN OR EQUAL TO 15. ----------------------------------------------------------------------- */ { static double e0 = 1.12837916709551e0; static double e1 = .353553390593274e0; static int num = 20; /* ------------------------ ****** NUM IS THE MAXIMUM VALUE THAT N CAN TAKE IN THE DO LOOP ENDING AT STATEMENT 50. IT IS REQUIRED THAT NUM BE EVEN. THE ARRAYS A0, B0, C, D HAVE DIMENSION NUM + 1. ------------------------ E0 = 2/SQRT(PI) E1 = 2**(-3/2) ------------------------ */ static int K3 = 1; static double basym,bsum,dsum,f,h,h2,hn,j0,j1,r,r0,r1,s,sum,t,t0,t1,u,w,w0,z,z0, z2,zn,znm1; static int i,im1,imj,j,m,mm1,mmj,n,np1; static double a0[21],b0[21],c[21],d[21],T1,T2; /* .. .. Executable Statements .. */ basym = 0.0e0; if(*a >= *b) goto S10; h = *a/ *b; r0 = 1.0e0/(1.0e0+h); r1 = (*b-*a)/ *b; w0 = 1.0e0/sqrt(*a*(1.0e0+h)); goto S20; S10: h = *b/ *a; r0 = 1.0e0/(1.0e0+h); r1 = (*b-*a)/ *a; w0 = 1.0e0/sqrt(*b*(1.0e0+h)); S20: T1 = -(*lambda/ *a); T2 = *lambda/ *b; f = *a*rlog1(&T1)+*b*rlog1(&T2); t = exp(-f); if(t == 0.0e0) return basym; z0 = sqrt(f); z = 0.5e0*(z0/e1); z2 = f+f; a0[0] = 2.0e0/3.0e0*r1; c[0] = -(0.5e0*a0[0]); d[0] = -c[0]; j0 = 0.5e0/e0*erfc1(&K3,&z0); j1 = e1; sum = j0+d[0]*w0*j1; s = 1.0e0; h2 = h*h; hn = 1.0e0; w = w0; znm1 = z; zn = z2; for(n=2; n<=num; n+=2) { hn = h2*hn; a0[n-1] = 2.0e0*r0*(1.0e0+h*hn)/((double)n+2.0e0); np1 = n+1; s += hn; a0[np1-1] = 2.0e0*r1*s/((double)n+3.0e0); for(i=n; i<=np1; i++) { r = -(0.5e0*((double)i+1.0e0)); b0[0] = r*a0[0]; for(m=2; m<=i; m++) { bsum = 0.0e0; mm1 = m-1; for(j=1; j<=mm1; j++) { mmj = m-j; bsum += (((double)j*r-(double)mmj)*a0[j-1]*b0[mmj-1]); } b0[m-1] = r*a0[m-1]+bsum/(double)m; } c[i-1] = b0[i-1]/((double)i+1.0e0); dsum = 0.0e0; im1 = i-1; for(j=1; j<=im1; j++) { imj = i-j; dsum += (d[imj-1]*c[j-1]); } d[i-1] = -(dsum+c[i-1]); } j0 = e1*znm1+((double)n-1.0e0)*j0; j1 = e1*zn+(double)n*j1; znm1 = z2*znm1; zn = z2*zn; w = w0*w; t0 = d[n-1]*w*j0; w = w0*w; t1 = d[np1-1]*w*j1; sum += (t0+t1); if(fabs(t0)+fabs(t1) <= *eps*sum) goto S80; } S80: u = exp(-bcorr(a,b)); basym = e0*t*u*sum; return basym; } double bcorr(double *a0,double *b0) /* ----------------------------------------------------------------------- EVALUATION OF DEL(A0) + DEL(B0) - DEL(A0 + B0) WHERE LN(GAMMA(A)) = (A - 0.5)*LN(A) - A + 0.5*LN(2*PI) + DEL(A). IT IS ASSUMED THAT A0 .GE. 8 AND B0 .GE. 8. ----------------------------------------------------------------------- */ { static double c0 = .833333333333333e-01; static double c1 = -.277777777760991e-02; static double c2 = .793650666825390e-03; static double c3 = -.595202931351870e-03; static double c4 = .837308034031215e-03; static double c5 = -.165322962780713e-02; static double bcorr,a,b,c,h,s11,s3,s5,s7,s9,t,w,x,x2; /* .. .. Executable Statements .. */ a = fifdmin1(*a0,*b0); b = fifdmax1(*a0,*b0); h = a/b; c = h/(1.0e0+h); x = 1.0e0/(1.0e0+h); x2 = x*x; /* SET SN = (1 - X**N)/(1 - X) */ s3 = 1.0e0+(x+x2); s5 = 1.0e0+(x+x2*s3); s7 = 1.0e0+(x+x2*s5); s9 = 1.0e0+(x+x2*s7); s11 = 1.0e0+(x+x2*s9); /* SET W = DEL(B) - DEL(A + B) */ t = pow(1.0e0/b,2.0); w = ((((c5*s11*t+c4*s9)*t+c3*s7)*t+c2*s5)*t+c1*s3)*t+c0; w *= (c/b); /* COMPUTE DEL(A) + W */ t = pow(1.0e0/a,2.0); bcorr = (((((c5*t+c4)*t+c3)*t+c2)*t+c1)*t+c0)/a+w; return bcorr; } double betaln(double *a0,double *b0) /* ----------------------------------------------------------------------- EVALUATION OF THE LOGARITHM OF THE BETA FUNCTION ----------------------------------------------------------------------- E = 0.5*LN(2*PI) -------------------------- */ { static double e = .918938533204673e0; static double betaln,a,b,c,h,u,v,w,z; static int i,n; static double T1; /* .. .. Executable Statements .. */ a = fifdmin1(*a0,*b0); b = fifdmax1(*a0,*b0); if(a >= 8.0e0) goto S100; if(a >= 1.0e0) goto S20; /* ----------------------------------------------------------------------- PROCEDURE WHEN A .LT. 1 ----------------------------------------------------------------------- */ if(b >= 8.0e0) goto S10; T1 = a+b; betaln = gamln(&a)+(gamln(&b)-gamln(&T1)); return betaln; S10: betaln = gamln(&a)+algdiv(&a,&b); return betaln; S20: /* ----------------------------------------------------------------------- PROCEDURE WHEN 1 .LE. A .LT. 8 ----------------------------------------------------------------------- */ if(a > 2.0e0) goto S40; if(b > 2.0e0) goto S30; betaln = gamln(&a)+gamln(&b)-gsumln(&a,&b); return betaln; S30: w = 0.0e0; if(b < 8.0e0) goto S60; betaln = gamln(&a)+algdiv(&a,&b); return betaln; S40: /* REDUCTION OF A WHEN B .LE. 1000 */ if(b > 1000.0e0) goto S80; n = (long)(a - 1.0e0); w = 1.0e0; for(i=1; i<=n; i++) { a -= 1.0e0; h = a/b; w *= (h/(1.0e0+h)); } w = log(w); if(b < 8.0e0) goto S60; betaln = w+gamln(&a)+algdiv(&a,&b); return betaln; S60: /* REDUCTION OF B WHEN B .LT. 8 */ n = (long)(b - 1.0e0); z = 1.0e0; for(i=1; i<=n; i++) { b -= 1.0e0; z *= (b/(a+b)); } betaln = w+log(z)+(gamln(&a)+(gamln(&b)-gsumln(&a,&b))); return betaln; S80: /* REDUCTION OF A WHEN B .GT. 1000 */ n = (long)(a - 1.0e0); w = 1.0e0; for(i=1; i<=n; i++) { a -= 1.0e0; w *= (a/(1.0e0+a/b)); } betaln = log(w)-(double)n*log(b)+(gamln(&a)+algdiv(&a,&b)); return betaln; S100: /* ----------------------------------------------------------------------- PROCEDURE WHEN A .GE. 8 ----------------------------------------------------------------------- */ w = bcorr(&a,&b); h = a/b; c = h/(1.0e0+h); u = -((a-0.5e0)*log(c)); v = b*alnrel(&h); if(u <= v) goto S110; betaln = -(0.5e0*log(b))+e+w-v-u; return betaln; S110: betaln = -(0.5e0*log(b))+e+w-u-v; return betaln; } double bfrac(double *a,double *b,double *x,double *y,double *lambda, double *eps) /* ----------------------------------------------------------------------- CONTINUED FRACTION EXPANSION FOR IX(A,B) WHEN A,B .GT. 1. IT IS ASSUMED THAT LAMBDA = (A + B)*Y - B. ----------------------------------------------------------------------- */ { static double bfrac,alpha,an,anp1,beta,bn,bnp1,c,c0,c1,e,n,p,r,r0,s,t,w,yp1; /* .. .. Executable Statements .. */ bfrac = brcomp(a,b,x,y); if(bfrac == 0.0e0) return bfrac; c = 1.0e0+*lambda; c0 = *b/ *a; c1 = 1.0e0+1.0e0/ *a; yp1 = *y+1.0e0; n = 0.0e0; p = 1.0e0; s = *a+1.0e0; an = 0.0e0; bn = anp1 = 1.0e0; bnp1 = c/c1; r = c1/c; S10: /* CONTINUED FRACTION CALCULATION */ n += 1.0e0; t = n/ *a; w = n*(*b-n)**x; e = *a/s; alpha = p*(p+c0)*e*e*(w**x); e = (1.0e0+t)/(c1+t+t); beta = n+w/s+e*(c+n*yp1); p = 1.0e0+t; s += 2.0e0; /* UPDATE AN, BN, ANP1, AND BNP1 */ t = alpha*an+beta*anp1; an = anp1; anp1 = t; t = alpha*bn+beta*bnp1; bn = bnp1; bnp1 = t; r0 = r; r = anp1/bnp1; if(fabs(r-r0) <= *eps*r) goto S20; /* RESCALE AN, BN, ANP1, AND BNP1 */ an /= bnp1; bn /= bnp1; anp1 = r; bnp1 = 1.0e0; goto S10; S20: /* TERMINATION */ bfrac *= r; return bfrac; } void bgrat(double *a,double *b,double *x,double *y,double *w, double *eps,int *ierr) /* ----------------------------------------------------------------------- ASYMPTOTIC EXPANSION FOR IX(A,B) WHEN A IS LARGER THAN B. THE RESULT OF THE EXPANSION IS ADDED TO W. IT IS ASSUMED THAT A .GE. 15 AND B .LE. 1. EPS IS THE TOLERANCE USED. IERR IS A VARIABLE THAT REPORTS THE STATUS OF THE RESULTS. ----------------------------------------------------------------------- */ { static double bm1,bp2n,cn,coef,dj,j,l,lnx,n2,nu,p,q,r,s,sum,t,t2,u,v,z; static int i,n,nm1; static double c[30],d[30],T1; /* .. .. Executable Statements .. */ bm1 = *b-0.5e0-0.5e0; nu = *a+0.5e0*bm1; if(*y > 0.375e0) goto S10; T1 = -*y; lnx = alnrel(&T1); goto S20; S10: lnx = log(*x); S20: z = -(nu*lnx); if(*b*z == 0.0e0) goto S70; /* COMPUTATION OF THE EXPANSION SET R = EXP(-Z)*Z**B/GAMMA(B) */ r = *b*(1.0e0+gam1(b))*exp(*b*log(z)); r *= (exp(*a*lnx)*exp(0.5e0*bm1*lnx)); u = algdiv(b,a)+*b*log(nu); u = r*exp(-u); if(u == 0.0e0) goto S70; grat1(b,&z,&r,&p,&q,eps); v = 0.25e0*pow(1.0e0/nu,2.0); t2 = 0.25e0*lnx*lnx; l = *w/u; j = q/r; sum = j; t = cn = 1.0e0; n2 = 0.0e0; for(n=1; n<=30; n++) { bp2n = *b+n2; j = (bp2n*(bp2n+1.0e0)*j+(z+bp2n+1.0e0)*t)*v; n2 += 2.0e0; t *= t2; cn /= (n2*(n2+1.0e0)); c[n-1] = cn; s = 0.0e0; if(n == 1) goto S40; nm1 = n-1; coef = *b-(double)n; for(i=1; i<=nm1; i++) { s += (coef*c[i-1]*d[n-i-1]); coef += *b; } S40: d[n-1] = bm1*cn+s/(double)n; dj = d[n-1]*j; sum += dj; if(sum <= 0.0e0) goto S70; if(fabs(dj) <= *eps*(sum+l)) goto S60; } S60: /* ADD THE RESULTS TO W */ *ierr = 0; *w += (u*sum); return; S70: /* THE EXPANSION CANNOT BE COMPUTED */ *ierr = 1; return; } double bpser(double *a,double *b,double *x,double *eps) /* ----------------------------------------------------------------------- POWER SERIES EXPANSION FOR EVALUATING IX(A,B) WHEN B .LE. 1 OR B*X .LE. 0.7. EPS IS THE TOLERANCE USED. ----------------------------------------------------------------------- */ { static double bpser,a0,apb,b0,c,n,sum,t,tol,u,w,z; static int i,m; /* .. .. Executable Statements .. */ bpser = 0.0e0; if(*x == 0.0e0) return bpser; /* ----------------------------------------------------------------------- COMPUTE THE FACTOR X**A/(A*BETA(A,B)) ----------------------------------------------------------------------- */ a0 = fifdmin1(*a,*b); if(a0 < 1.0e0) goto S10; z = *a*log(*x)-betaln(a,b); bpser = exp(z)/ *a; goto S100; S10: b0 = fifdmax1(*a,*b); if(b0 >= 8.0e0) goto S90; if(b0 > 1.0e0) goto S40; /* PROCEDURE FOR A0 .LT. 1 AND B0 .LE. 1 */ bpser = pow(*x,*a); if(bpser == 0.0e0) return bpser; apb = *a+*b; if(apb > 1.0e0) goto S20; z = 1.0e0+gam1(&apb); goto S30; S20: u = *a+*b-1.e0; z = (1.0e0+gam1(&u))/apb; S30: c = (1.0e0+gam1(a))*(1.0e0+gam1(b))/z; bpser *= (c*(*b/apb)); goto S100; S40: /* PROCEDURE FOR A0 .LT. 1 AND 1 .LT. B0 .LT. 8 */ u = gamln1(&a0); m = (long)(b0 - 1.0e0); if(m < 1) goto S60; c = 1.0e0; for(i=1; i<=m; i++) { b0 -= 1.0e0; c *= (b0/(a0+b0)); } u = log(c)+u; S60: z = *a*log(*x)-u; b0 -= 1.0e0; apb = a0+b0; if(apb > 1.0e0) goto S70; t = 1.0e0+gam1(&apb); goto S80; S70: u = a0+b0-1.e0; t = (1.0e0+gam1(&u))/apb; S80: bpser = exp(z)*(a0/ *a)*(1.0e0+gam1(&b0))/t; goto S100; S90: /* PROCEDURE FOR A0 .LT. 1 AND B0 .GE. 8 */ u = gamln1(&a0)+algdiv(&a0,&b0); z = *a*log(*x)-u; bpser = a0/ *a*exp(z); S100: if(bpser == 0.0e0 || *a <= 0.1e0**eps) return bpser; /* ----------------------------------------------------------------------- COMPUTE THE SERIES ----------------------------------------------------------------------- */ sum = n = 0.0e0; c = 1.0e0; tol = *eps/ *a; S110: n += 1.0e0; c *= ((0.5e0+(0.5e0-*b/n))**x); w = c/(*a+n); sum += w; if(fabs(w) > tol) goto S110; bpser *= (1.0e0+*a*sum); return bpser; } void bratio(double *a,double *b,double *x,double *y,double *w, double *w1,int *ierr) /* ----------------------------------------------------------------------- EVALUATION OF THE INCOMPLETE BETA FUNCTION IX(A,B) -------------------- IT IS ASSUMED THAT A AND B ARE NONNEGATIVE, AND THAT X .LE. 1 AND Y = 1 - X. BRATIO ASSIGNS W AND W1 THE VALUES W = IX(A,B) W1 = 1 - IX(A,B) IERR IS A VARIABLE THAT REPORTS THE STATUS OF THE RESULTS. IF NO INPUT ERRORS ARE DETECTED THEN IERR IS SET TO 0 AND W AND W1 ARE COMPUTED. OTHERWISE, IF AN ERROR IS DETECTED, THEN W AND W1 ARE ASSIGNED THE VALUE 0 AND IERR IS SET TO ONE OF THE FOLLOWING VALUES ... IERR = 1 IF A OR B IS NEGATIVE IERR = 2 IF A = B = 0 IERR = 3 IF X .LT. 0 OR X .GT. 1 IERR = 4 IF Y .LT. 0 OR Y .GT. 1 IERR = 5 IF X + Y .NE. 1 IERR = 6 IF X = A = 0 IERR = 7 IF Y = B = 0 -------------------- WRITTEN BY ALFRED H. MORRIS, JR. NAVAL SURFACE WARFARE CENTER DAHLGREN, VIRGINIA REVISED ... NOV 1991 ----------------------------------------------------------------------- */ { static int K1 = 1; static double a0,b0,eps,lambda,t,x0,y0,z; static int ierr1,ind,n; static double T2,T3,T4,T5; /* .. .. Executable Statements .. */ /* ****** EPS IS A MACHINE DEPENDENT CONSTANT. EPS IS THE SMALLEST FLOATING POINT NUMBER FOR WHICH 1.0 + EPS .GT. 1.0 */ eps = spmpar(&K1); *w = *w1 = 0.0e0; if(*a < 0.0e0 || *b < 0.0e0) goto S270; if(*a == 0.0e0 && *b == 0.0e0) goto S280; if(*x < 0.0e0 || *x > 1.0e0) goto S290; if(*y < 0.0e0 || *y > 1.0e0) goto S300; z = *x+*y-0.5e0-0.5e0; if(fabs(z) > 3.0e0*eps) goto S310; *ierr = 0; if(*x == 0.0e0) goto S210; if(*y == 0.0e0) goto S230; if(*a == 0.0e0) goto S240; if(*b == 0.0e0) goto S220; eps = fifdmax1(eps,1.e-15); if(fifdmax1(*a,*b) < 1.e-3*eps) goto S260; ind = 0; a0 = *a; b0 = *b; x0 = *x; y0 = *y; if(fifdmin1(a0,b0) > 1.0e0) goto S40; /* PROCEDURE FOR A0 .LE. 1 OR B0 .LE. 1 */ if(*x <= 0.5e0) goto S10; ind = 1; a0 = *b; b0 = *a; x0 = *y; y0 = *x; S10: if(b0 < fifdmin1(eps,eps*a0)) goto S90; if(a0 < fifdmin1(eps,eps*b0) && b0*x0 <= 1.0e0) goto S100; if(fifdmax1(a0,b0) > 1.0e0) goto S20; if(a0 >= fifdmin1(0.2e0,b0)) goto S110; if(pow(x0,a0) <= 0.9e0) goto S110; if(x0 >= 0.3e0) goto S120; n = 20; goto S140; S20: if(b0 <= 1.0e0) goto S110; if(x0 >= 0.3e0) goto S120; if(x0 >= 0.1e0) goto S30; if(pow(x0*b0,a0) <= 0.7e0) goto S110; S30: if(b0 > 15.0e0) goto S150; n = 20; goto S140; S40: /* PROCEDURE FOR A0 .GT. 1 AND B0 .GT. 1 */ if(*a > *b) goto S50; lambda = *a-(*a+*b)**x; goto S60; S50: lambda = (*a+*b)**y-*b; S60: if(lambda >= 0.0e0) goto S70; ind = 1; a0 = *b; b0 = *a; x0 = *y; y0 = *x; lambda = fabs(lambda); S70: if(b0 < 40.0e0 && b0*x0 <= 0.7e0) goto S110; if(b0 < 40.0e0) goto S160; if(a0 > b0) goto S80; if(a0 <= 100.0e0) goto S130; if(lambda > 0.03e0*a0) goto S130; goto S200; S80: if(b0 <= 100.0e0) goto S130; if(lambda > 0.03e0*b0) goto S130; goto S200; S90: /* EVALUATION OF THE APPROPRIATE ALGORITHM */ *w = fpser(&a0,&b0,&x0,&eps); *w1 = 0.5e0+(0.5e0-*w); goto S250; S100: *w1 = apser(&a0,&b0,&x0,&eps); *w = 0.5e0+(0.5e0-*w1); goto S250; S110: *w = bpser(&a0,&b0,&x0,&eps); *w1 = 0.5e0+(0.5e0-*w); goto S250; S120: *w1 = bpser(&b0,&a0,&y0,&eps); *w = 0.5e0+(0.5e0-*w1); goto S250; S130: T2 = 15.0e0*eps; *w = bfrac(&a0,&b0,&x0,&y0,&lambda,&T2); *w1 = 0.5e0+(0.5e0-*w); goto S250; S140: *w1 = bup(&b0,&a0,&y0,&x0,&n,&eps); b0 += (double)n; S150: T3 = 15.0e0*eps; bgrat(&b0,&a0,&y0,&x0,w1,&T3,&ierr1); *w = 0.5e0+(0.5e0-*w1); goto S250; S160: n = (long)(b0); b0 -= (double)n; if(b0 != 0.0e0) goto S170; n -= 1; b0 = 1.0e0; S170: *w = bup(&b0,&a0,&y0,&x0,&n,&eps); if(x0 > 0.7e0) goto S180; *w += bpser(&a0,&b0,&x0,&eps); *w1 = 0.5e0+(0.5e0-*w); goto S250; S180: if(a0 > 15.0e0) goto S190; n = 20; *w += bup(&a0,&b0,&x0,&y0,&n,&eps); a0 += (double)n; S190: T4 = 15.0e0*eps; bgrat(&a0,&b0,&x0,&y0,w,&T4,&ierr1); *w1 = 0.5e0+(0.5e0-*w); goto S250; S200: T5 = 100.0e0*eps; *w = basym(&a0,&b0,&lambda,&T5); *w1 = 0.5e0+(0.5e0-*w); goto S250; S210: /* TERMINATION OF THE PROCEDURE */ if(*a == 0.0e0) goto S320; S220: *w = 0.0e0; *w1 = 1.0e0; return; S230: if(*b == 0.0e0) goto S330; S240: *w = 1.0e0; *w1 = 0.0e0; return; S250: if(ind == 0) return; t = *w; *w = *w1; *w1 = t; return; S260: /* PROCEDURE FOR A AND B .LT. 1.E-3*EPS */ *w = *b/(*a+*b); *w1 = *a/(*a+*b); return; S270: /* ERROR RETURN */ *ierr = 1; return; S280: *ierr = 2; return; S290: *ierr = 3; return; S300: *ierr = 4; return; S310: *ierr = 5; return; S320: *ierr = 6; return; S330: *ierr = 7; return; } double brcmp1(int *mu,double *a,double *b,double *x,double *y) /* ----------------------------------------------------------------------- EVALUATION OF EXP(MU) * (X**A*Y**B/BETA(A,B)) ----------------------------------------------------------------------- */ { static double Const = .398942280401433e0; static double brcmp1,a0,apb,b0,c,e,h,lambda,lnx,lny,t,u,v,x0,y0,z; static int i,n; /* ----------------- CONST = 1/SQRT(2*PI) ----------------- */ static double T1,T2,T3,T4; /* .. .. Executable Statements .. */ a0 = fifdmin1(*a,*b); if(a0 >= 8.0e0) goto S130; if(*x > 0.375e0) goto S10; lnx = log(*x); T1 = -*x; lny = alnrel(&T1); goto S30; S10: if(*y > 0.375e0) goto S20; T2 = -*y; lnx = alnrel(&T2); lny = log(*y); goto S30; S20: lnx = log(*x); lny = log(*y); S30: z = *a*lnx+*b*lny; if(a0 < 1.0e0) goto S40; z -= betaln(a,b); brcmp1 = esum(mu,&z); return brcmp1; S40: /* ----------------------------------------------------------------------- PROCEDURE FOR A .LT. 1 OR B .LT. 1 ----------------------------------------------------------------------- */ b0 = fifdmax1(*a,*b); if(b0 >= 8.0e0) goto S120; if(b0 > 1.0e0) goto S70; /* ALGORITHM FOR B0 .LE. 1 */ brcmp1 = esum(mu,&z); if(brcmp1 == 0.0e0) return brcmp1; apb = *a+*b; if(apb > 1.0e0) goto S50; z = 1.0e0+gam1(&apb); goto S60; S50: u = *a+*b-1.e0; z = (1.0e0+gam1(&u))/apb; S60: c = (1.0e0+gam1(a))*(1.0e0+gam1(b))/z; brcmp1 = brcmp1*(a0*c)/(1.0e0+a0/b0); return brcmp1; S70: /* ALGORITHM FOR 1 .LT. B0 .LT. 8 */ u = gamln1(&a0); n = (long)(b0 - 1.0e0); if(n < 1) goto S90; c = 1.0e0; for(i=1; i<=n; i++) { b0 -= 1.0e0; c *= (b0/(a0+b0)); } u = log(c)+u; S90: z -= u; b0 -= 1.0e0; apb = a0+b0; if(apb > 1.0e0) goto S100; t = 1.0e0+gam1(&apb); goto S110; S100: u = a0+b0-1.e0; t = (1.0e0+gam1(&u))/apb; S110: brcmp1 = a0*esum(mu,&z)*(1.0e0+gam1(&b0))/t; return brcmp1; S120: /* ALGORITHM FOR B0 .GE. 8 */ u = gamln1(&a0)+algdiv(&a0,&b0); T3 = z-u; brcmp1 = a0*esum(mu,&T3); return brcmp1; S130: /* ----------------------------------------------------------------------- PROCEDURE FOR A .GE. 8 AND B .GE. 8 ----------------------------------------------------------------------- */ if(*a > *b) goto S140; h = *a/ *b; x0 = h/(1.0e0+h); y0 = 1.0e0/(1.0e0+h); lambda = *a-(*a+*b)**x; goto S150; S140: h = *b/ *a; x0 = 1.0e0/(1.0e0+h); y0 = h/(1.0e0+h); lambda = (*a+*b)**y-*b; S150: e = -(lambda/ *a); if(fabs(e) > 0.6e0) goto S160; u = rlog1(&e); goto S170; S160: u = e-log(*x/x0); S170: e = lambda/ *b; if(fabs(e) > 0.6e0) goto S180; v = rlog1(&e); goto S190; S180: v = e-log(*y/y0); S190: T4 = -(*a*u+*b*v); z = esum(mu,&T4); brcmp1 = Const*sqrt(*b*x0)*z*exp(-bcorr(a,b)); return brcmp1; } double brcomp(double *a,double *b,double *x,double *y) /* ----------------------------------------------------------------------- EVALUATION OF X**A*Y**B/BETA(A,B) ----------------------------------------------------------------------- */ { static double Const = .398942280401433e0; static double brcomp,a0,apb,b0,c,e,h,lambda,lnx,lny,t,u,v,x0,y0,z; static int i,n; /* ----------------- CONST = 1/SQRT(2*PI) ----------------- */ static double T1,T2; /* .. .. Executable Statements .. */ brcomp = 0.0e0; if(*x == 0.0e0 || *y == 0.0e0) return brcomp; a0 = fifdmin1(*a,*b); if(a0 >= 8.0e0) goto S130; if(*x > 0.375e0) goto S10; lnx = log(*x); T1 = -*x; lny = alnrel(&T1); goto S30; S10: if(*y > 0.375e0) goto S20; T2 = -*y; lnx = alnrel(&T2); lny = log(*y); goto S30; S20: lnx = log(*x); lny = log(*y); S30: z = *a*lnx+*b*lny; if(a0 < 1.0e0) goto S40; z -= betaln(a,b); brcomp = exp(z); return brcomp; S40: /* ----------------------------------------------------------------------- PROCEDURE FOR A .LT. 1 OR B .LT. 1 ----------------------------------------------------------------------- */ b0 = fifdmax1(*a,*b); if(b0 >= 8.0e0) goto S120; if(b0 > 1.0e0) goto S70; /* ALGORITHM FOR B0 .LE. 1 */ brcomp = exp(z); if(brcomp == 0.0e0) return brcomp; apb = *a+*b; if(apb > 1.0e0) goto S50; z = 1.0e0+gam1(&apb); goto S60; S50: u = *a+*b-1.e0; z = (1.0e0+gam1(&u))/apb; S60: c = (1.0e0+gam1(a))*(1.0e0+gam1(b))/z; brcomp = brcomp*(a0*c)/(1.0e0+a0/b0); return brcomp; S70: /* ALGORITHM FOR 1 .LT. B0 .LT. 8 */ u = gamln1(&a0); n = (long)(b0 - 1.0e0); if(n < 1) goto S90; c = 1.0e0; for(i=1; i<=n; i++) { b0 -= 1.0e0; c *= (b0/(a0+b0)); } u = log(c)+u; S90: z -= u; b0 -= 1.0e0; apb = a0+b0; if(apb > 1.0e0) goto S100; t = 1.0e0+gam1(&apb); goto S110; S100: u = a0+b0-1.e0; t = (1.0e0+gam1(&u))/apb; S110: brcomp = a0*exp(z)*(1.0e0+gam1(&b0))/t; return brcomp; S120: /* ALGORITHM FOR B0 .GE. 8 */ u = gamln1(&a0)+algdiv(&a0,&b0); brcomp = a0*exp(z-u); return brcomp; S130: /* ----------------------------------------------------------------------- PROCEDURE FOR A .GE. 8 AND B .GE. 8 ----------------------------------------------------------------------- */ if(*a > *b) goto S140; h = *a/ *b; x0 = h/(1.0e0+h); y0 = 1.0e0/(1.0e0+h); lambda = *a-(*a+*b)**x; goto S150; S140: h = *b/ *a; x0 = 1.0e0/(1.0e0+h); y0 = h/(1.0e0+h); lambda = (*a+*b)**y-*b; S150: e = -(lambda/ *a); if(fabs(e) > 0.6e0) goto S160; u = rlog1(&e); goto S170; S160: u = e-log(*x/x0); S170: e = lambda/ *b; if(fabs(e) > 0.6e0) goto S180; v = rlog1(&e); goto S190; S180: v = e-log(*y/y0); S190: z = exp(-(*a*u+*b*v)); brcomp = Const*sqrt(*b*x0)*z*exp(-bcorr(a,b)); return brcomp; } double bup(double *a,double *b,double *x,double *y,int *n,double *eps) /* ----------------------------------------------------------------------- EVALUATION OF IX(A,B) - IX(A+N,B) WHERE N IS A POSITIVE INTEGER. EPS IS THE TOLERANCE USED. ----------------------------------------------------------------------- */ { static int K1 = 1; static int K2 = 0; static double bup,ap1,apb,d,l,r,t,w; static int i,k,kp1,mu,nm1; /* .. .. Executable Statements .. */ /* OBTAIN THE SCALING FACTOR EXP(-MU) AND EXP(MU)*(X**A*Y**B/BETA(A,B))/A */ apb = *a+*b; ap1 = *a+1.0e0; mu = 0; d = 1.0e0; if(*n == 1 || *a < 1.0e0) goto S10; if(apb < 1.1e0*ap1) goto S10; mu = (long)(fabs(exparg(&K1))); k = (long)(exparg(&K2)); if(k < mu) mu = k; t = mu; d = exp(-t); S10: bup = brcmp1(&mu,a,b,x,y)/ *a; if(*n == 1 || bup == 0.0e0) return bup; nm1 = *n-1; w = d; /* LET K BE THE INDEX OF THE MAXIMUM TERM */ k = 0; if(*b <= 1.0e0) goto S50; if(*y > 1.e-4) goto S20; k = nm1; goto S30; S20: r = (*b-1.0e0)**x/ *y-*a; if(r < 1.0e0) goto S50; t = nm1; k = (long)(t); if(r < t) k = (long)(r); S30: /* ADD THE INCREASING TERMS OF THE SERIES */ for(i=1; i<=k; i++) { l = i-1; d = (apb+l)/(ap1+l)**x*d; w += d; } if(k == nm1) goto S70; S50: /* ADD THE REMAINING TERMS OF THE SERIES */ kp1 = k+1; for(i=kp1; i<=nm1; i++) { l = i-1; d = (apb+l)/(ap1+l)**x*d; w += d; if(d <= *eps*w) goto S70; } S70: /* TERMINATE THE PROCEDURE */ bup *= w; return bup; } void cdfbet(int *which,double *p,double *q,double *x,double *y, double *a,double *b,int *status,double *bound) /********************************************************************** void cdfbet(int *which,double *p,double *q,double *x,double *y, double *a,double *b,int *status,double *bound) Cumulative Distribution Function BETa Distribution Function Calculates any one parameter of the beta distribution given values for the others. Arguments WHICH --> Integer indicating which of the next four argument values is to be calculated from the others. Legal range: 1..4 iwhich = 1 : Calculate P and Q from X,Y,A and B iwhich = 2 : Calculate X and Y from P,Q,A and B iwhich = 3 : Calculate A from P,Q,X,Y and B iwhich = 4 : Calculate B from P,Q,X,Y and A P <--> The integral from 0 to X of the chi-square distribution. Input range: [0, 1]. Q <--> 1-P. Input range: [0, 1]. P + Q = 1.0. X <--> Upper limit of integration of beta density. Input range: [0,1]. Search range: [0,1] Y <--> 1-X. Input range: [0,1]. Search range: [0,1] X + Y = 1.0. A <--> The first parameter of the beta density. Input range: (0, +infinity). Search range: [1D-100,1D100] B <--> The second parameter of the beta density. Input range: (0, +infinity). Search range: [1D-100,1D100] STATUS <-- 0 if calculation completed correctly -I if input parameter number I is out of range 1 if answer appears to be lower than lowest search bound 2 if answer appears to be higher than greatest search bound 3 if P + Q .ne. 1 4 if X + Y .ne. 1 BOUND <-- Undefined if STATUS is 0 Bound exceeded by parameter number I if STATUS is negative. Lower search bound if STATUS is 1. Upper search bound if STATUS is 2. Method Cumulative distribution function (P) is calculated directly by code associated with the following reference. DiDinato, A. R. and Morris, A. H. Algorithm 708: Significant Digit Computation of the Incomplete Beta Function Ratios. ACM Trans. Math. Softw. 18 (1993), 360-373. Computation of other parameters involve a seach for a value that produces the desired value of P. The search relies on the monotinicity of P with the other parameter. Note The beta density is proportional to t^(A-1) * (1-t)^(B-1) **********************************************************************/ { #define tol 1.0e-8 #define atol 1.0e-50 #define zero 1.0e-100 #define inf 1.0e100 #define one 1.0e0 static int K1 = 1; static double K2 = 0.0e0; static double K3 = 1.0e0; static double K8 = 0.5e0; static double K9 = 5.0e0; static double fx,xhi,xlo,cum,ccum,xy,pq; static unsigned long qhi,qleft,qporq; static double T4,T5,T6,T7,T10,T11,T12,T13,T14,T15; /* .. .. Executable Statements .. */ /* Check arguments */ if(!(*which < 1 || *which > 4)) goto S30; if(!(*which < 1)) goto S10; *bound = 1.0e0; goto S20; S10: *bound = 4.0e0; S20: *status = -1; return; S30: if(*which == 1) goto S70; /* P */ if(!(*p < 0.0e0 || *p > 1.0e0)) goto S60; if(!(*p < 0.0e0)) goto S40; *bound = 0.0e0; goto S50; S40: *bound = 1.0e0; S50: *status = -2; return; S70: S60: if(*which == 1) goto S110; /* Q */ if(!(*q < 0.0e0 || *q > 1.0e0)) goto S100; if(!(*q < 0.0e0)) goto S80; *bound = 0.0e0; goto S90; S80: *bound = 1.0e0; S90: *status = -3; return; S110: S100: if(*which == 2) goto S150; /* X */ if(!(*x < 0.0e0 || *x > 1.0e0)) goto S140; if(!(*x < 0.0e0)) goto S120; *bound = 0.0e0; goto S130; S120: *bound = 1.0e0; S130: *status = -4; return; S150: S140: if(*which == 2) goto S190; /* Y */ if(!(*y < 0.0e0 || *y > 1.0e0)) goto S180; if(!(*y < 0.0e0)) goto S160; *bound = 0.0e0; goto S170; S160: *bound = 1.0e0; S170: *status = -5; return; S190: S180: if(*which == 3) goto S210; /* A */ if(!(*a <= 0.0e0)) goto S200; *bound = 0.0e0; *status = -6; return; S210: S200: if(*which == 4) goto S230; /* B */ if(!(*b <= 0.0e0)) goto S220; *bound = 0.0e0; *status = -7; return; S230: S220: if(*which == 1) goto S270; /* P + Q */ pq = *p+*q; if(!(fabs(pq-0.5e0-0.5e0) > 3.0e0*spmpar(&K1))) goto S260; if(!(pq < 0.0e0)) goto S240; *bound = 0.0e0; goto S250; S240: *bound = 1.0e0; S250: *status = 3; return; S270: S260: if(*which == 2) goto S310; /* X + Y */ xy = *x+*y; if(!(fabs(xy-0.5e0-0.5e0) > 3.0e0*spmpar(&K1))) goto S300; if(!(xy < 0.0e0)) goto S280; *bound = 0.0e0; goto S290; S280: *bound = 1.0e0; S290: *status = 4; return; S310: S300: if(!(*which == 1)) qporq = *p <= *q; /* Select the minimum of P or Q Calculate ANSWERS */ if(1 == *which) { /* Calculating P and Q */ cumbet(x,y,a,b,p,q); *status = 0; } else if(2 == *which) { /* Calculating X and Y */ T4 = atol; T5 = tol; dstzr(&K2,&K3,&T4,&T5); if(!qporq) goto S340; *status = 0; dzror(status,x,&fx,&xlo,&xhi,&qleft,&qhi); *y = one-*x; S320: if(!(*status == 1)) goto S330; cumbet(x,y,a,b,&cum,&ccum); fx = cum-*p; dzror(status,x,&fx,&xlo,&xhi,&qleft,&qhi); *y = one-*x; goto S320; S330: goto S370; S340: *status = 0; dzror(status,y,&fx,&xlo,&xhi,&qleft,&qhi); *x = one-*y; S350: if(!(*status == 1)) goto S360; cumbet(x,y,a,b,&cum,&ccum); fx = ccum-*q; dzror(status,y,&fx,&xlo,&xhi,&qleft,&qhi); *x = one-*y; goto S350; S370: S360: if(!(*status == -1)) goto S400; if(!qleft) goto S380; *status = 1; *bound = 0.0e0; goto S390; S380: *status = 2; *bound = 1.0e0; S400: S390: ; } else if(3 == *which) { /* Computing A */ *a = 5.0e0; T6 = zero; T7 = inf; T10 = atol; T11 = tol; dstinv(&T6,&T7,&K8,&K8,&K9,&T10,&T11); *status = 0; dinvr(status,a,&fx,&qleft,&qhi); S410: if(!(*status == 1)) goto S440; cumbet(x,y,a,b,&cum,&ccum); if(!qporq) goto S420; fx = cum-*p; goto S430; S420: fx = ccum-*q; S430: dinvr(status,a,&fx,&qleft,&qhi); goto S410; S440: if(!(*status == -1)) goto S470; if(!qleft) goto S450; *status = 1; *bound = zero; goto S460; S450: *status = 2; *bound = inf; S470: S460: ; } else if(4 == *which) { /* Computing B */ *b = 5.0e0; T12 = zero; T13 = inf; T14 = atol; T15 = tol; dstinv(&T12,&T13,&K8,&K8,&K9,&T14,&T15); *status = 0; dinvr(status,b,&fx,&qleft,&qhi); S480: if(!(*status == 1)) goto S510; cumbet(x,y,a,b,&cum,&ccum); if(!qporq) goto S490; fx = cum-*p; goto S500; S490: fx = ccum-*q; S500: dinvr(status,b,&fx,&qleft,&qhi); goto S480; S510: if(!(*status == -1)) goto S540; if(!qleft) goto S520; *status = 1; *bound = zero; goto S530; S520: *status = 2; *bound = inf; S530: ; } S540: return; #undef tol #undef atol #undef zero #undef inf #undef one } void cdfbin(int *which,double *p,double *q,double *s,double *xn, double *pr,double *ompr,int *status,double *bound) /********************************************************************** void cdfbin(int *which,double *p,double *q,double *s,double *xn, double *pr,double *ompr,int *status,double *bound) Cumulative Distribution Function BINomial distribution Function Calculates any one parameter of the binomial distribution given values for the others. Arguments WHICH --> Integer indicating which of the next four argument values is to be calculated from the others. Legal range: 1..4 iwhich = 1 : Calculate P and Q from S,XN,PR and OMPR iwhich = 2 : Calculate S from P,Q,XN,PR and OMPR iwhich = 3 : Calculate XN from P,Q,S,PR and OMPR iwhich = 4 : Calculate PR and OMPR from P,Q,S and XN P <--> The cumulation from 0 to S of the binomial distribution. (Probablility of S or fewer successes in XN trials each with probability of success PR.) Input range: [0,1]. Q <--> 1-P. Input range: [0, 1]. P + Q = 1.0. S <--> The number of successes observed. Input range: [0, XN] Search range: [0, XN] XN <--> The number of binomial trials. Input range: (0, +infinity). Search range: [1E-100, 1E100] PR <--> The probability of success in each binomial trial. Input range: [0,1]. Search range: [0,1] OMPR <--> 1-PR Input range: [0,1]. Search range: [0,1] PR + OMPR = 1.0 STATUS <-- 0 if calculation completed correctly -I if input parameter number I is out of range 1 if answer appears to be lower than lowest search bound 2 if answer appears to be higher than greatest search bound 3 if P + Q .ne. 1 4 if PR + OMPR .ne. 1 BOUND <-- Undefined if STATUS is 0 Bound exceeded by parameter number I if STATUS is negative. Lower search bound if STATUS is 1. Upper search bound if STATUS is 2. Method Formula 26.5.24 of Abramowitz and Stegun, Handbook of Mathematical Functions (1966) is used to reduce the binomial distribution to the cumulative incomplete beta distribution. Computation of other parameters involve a seach for a value that produces the desired value of P. The search relies on the monotinicity of P with the other parameter. **********************************************************************/ { #define atol 1.0e-50 #define tol 1.0e-8 #define zero 1.0e-100 #define inf 1.0e100 #define one 1.0e0 static int K1 = 1; static double K2 = 0.0e0; static double K3 = 0.5e0; static double K4 = 5.0e0; static double K11 = 1.0e0; static double fx,xhi,xlo,cum,ccum,pq,prompr; static unsigned long qhi,qleft,qporq; static double T5,T6,T7,T8,T9,T10,T12,T13; /* .. .. Executable Statements .. */ /* Check arguments */ if(!(*which < 1 && *which > 4)) goto S30; if(!(*which < 1)) goto S10; *bound = 1.0e0; goto S20; S10: *bound = 4.0e0; S20: *status = -1; return; S30: if(*which == 1) goto S70; /* P */ if(!(*p < 0.0e0 || *p > 1.0e0)) goto S60; if(!(*p < 0.0e0)) goto S40; *bound = 0.0e0; goto S50; S40: *bound = 1.0e0; S50: *status = -2; return; S70: S60: if(*which == 1) goto S110; /* Q */ if(!(*q < 0.0e0 || *q > 1.0e0)) goto S100; if(!(*q < 0.0e0)) goto S80; *bound = 0.0e0; goto S90; S80: *bound = 1.0e0; S90: *status = -3; return; S110: S100: if(*which == 3) goto S130; /* XN */ if(!(*xn <= 0.0e0)) goto S120; *bound = 0.0e0; *status = -5; return; S130: S120: if(*which == 2) goto S170; /* S */ if(!((*s < 0.0e0) || ((*which != 3) && (*s > *xn)))) goto S160; if(!(*s < 0.0e0)) goto S140; *bound = 0.0e0; goto S150; S140: *bound = *xn; S150: *status = -4; return; S170: S160: if(*which == 4) goto S210; /* PR */ if(!(*pr < 0.0e0 || *pr > 1.0e0)) goto S200; if(!(*pr < 0.0e0)) goto S180; *bound = 0.0e0; goto S190; S180: *bound = 1.0e0; S190: *status = -6; return; S210: S200: if(*which == 4) goto S250; /* OMPR */ if(!(*ompr < 0.0e0 || *ompr > 1.0e0)) goto S240; if(!(*ompr < 0.0e0)) goto S220; *bound = 0.0e0; goto S230; S220: *bound = 1.0e0; S230: *status = -7; return; S250: S240: if(*which == 1) goto S290; /* P + Q */ pq = *p+*q; if(!(fabs(pq-0.5e0-0.5e0) > 3.0e0*spmpar(&K1))) goto S280; if(!(pq < 0.0e0)) goto S260; *bound = 0.0e0; goto S270; S260: *bound = 1.0e0; S270: *status = 3; return; S290: S280: if(*which == 4) goto S330; /* PR + OMPR */ prompr = *pr+*ompr; if(!(fabs(prompr-0.5e0-0.5e0) > 3.0e0*spmpar(&K1))) goto S320; if(!(prompr < 0.0e0)) goto S300; *bound = 0.0e0; goto S310; S300: *bound = 1.0e0; S310: *status = 4; return; S330: S320: if(!(*which == 1)) qporq = *p <= *q; /* Select the minimum of P or Q Calculate ANSWERS */ if(1 == *which) { /* Calculating P */ cumbin(s,xn,pr,ompr,p,q); *status = 0; } else if(2 == *which) { /* Calculating S */ *s = 5.0e0; T5 = atol; T6 = tol; dstinv(&K2,xn,&K3,&K3,&K4,&T5,&T6); *status = 0; dinvr(status,s,&fx,&qleft,&qhi); S340: if(!(*status == 1)) goto S370; cumbin(s,xn,pr,ompr,&cum,&ccum); if(!qporq) goto S350; fx = cum-*p; goto S360; S350: fx = ccum-*q; S360: dinvr(status,s,&fx,&qleft,&qhi); goto S340; S370: if(!(*status == -1)) goto S400; if(!qleft) goto S380; *status = 1; *bound = 0.0e0; goto S390; S380: *status = 2; *bound = *xn; S400: S390: ; } else if(3 == *which) { /* Calculating XN */ *xn = 5.0e0; T7 = zero; T8 = inf; T9 = atol; T10 = tol; dstinv(&T7,&T8,&K3,&K3,&K4,&T9,&T10); *status = 0; dinvr(status,xn,&fx,&qleft,&qhi); S410: if(!(*status == 1)) goto S440; cumbin(s,xn,pr,ompr,&cum,&ccum); if(!qporq) goto S420; fx = cum-*p; goto S430; S420: fx = ccum-*q; S430: dinvr(status,xn,&fx,&qleft,&qhi); goto S410; S440: if(!(*status == -1)) goto S470; if(!qleft) goto S450; *status = 1; *bound = zero; goto S460; S450: *status = 2; *bound = inf; S470: S460: ; } else if(4 == *which) { /* Calculating PR and OMPR */ T12 = atol; T13 = tol; dstzr(&K2,&K11,&T12,&T13); if(!qporq) goto S500; *status = 0; dzror(status,pr,&fx,&xlo,&xhi,&qleft,&qhi); *ompr = one-*pr; S480: if(!(*status == 1)) goto S490; cumbin(s,xn,pr,ompr,&cum,&ccum); fx = cum-*p; dzror(status,pr,&fx,&xlo,&xhi,&qleft,&qhi); *ompr = one-*pr; goto S480; S490: goto S530; S500: *status = 0; dzror(status,ompr,&fx,&xlo,&xhi,&qleft,&qhi); *pr = one-*ompr; S510: if(!(*status == 1)) goto S520; cumbin(s,xn,pr,ompr,&cum,&ccum); fx = ccum-*q; dzror(status,ompr,&fx,&xlo,&xhi,&qleft,&qhi); *pr = one-*ompr; goto S510; S530: S520: if(!(*status == -1)) goto S560; if(!qleft) goto S540; *status = 1; *bound = 0.0e0; goto S550; S540: *status = 2; *bound = 1.0e0; S550: ; } S560: return; #undef atol #undef tol #undef zero #undef inf #undef one } void cdfchi(int *which,double *p,double *q,double *x,double *df, int *status,double *bound) /********************************************************************** void cdfchi(int *which,double *p,double *q,double *x,double *df, int *status,double *bound) Cumulative Distribution Function CHI-Square distribution Function Calculates any one parameter of the chi-square distribution given values for the others. Arguments WHICH --> Integer indicating which of the next three argument values is to be calculated from the others. Legal range: 1..3 iwhich = 1 : Calculate P and Q from X and DF iwhich = 2 : Calculate X from P,Q and DF iwhich = 3 : Calculate DF from P,Q and X P <--> The integral from 0 to X of the chi-square distribution. Input range: [0, 1]. Q <--> 1-P. Input range: (0, 1]. P + Q = 1.0. X <--> Upper limit of integration of the non-central chi-square distribution. Input range: [0, +infinity). Search range: [0,1E100] DF <--> Degrees of freedom of the chi-square distribution. Input range: (0, +infinity). Search range: [ 1E-100, 1E100] STATUS <-- 0 if calculation completed correctly -I if input parameter number I is out of range 1 if answer appears to be lower than lowest search bound 2 if answer appears to be higher than greatest search bound 3 if P + Q .ne. 1 10 indicates error returned from cumgam. See references in cdfgam BOUND <-- Undefined if STATUS is 0 Bound exceeded by parameter number I if STATUS is negative. Lower search bound if STATUS is 1. Upper search bound if STATUS is 2. Method Formula 26.4.19 of Abramowitz and Stegun, Handbook of Mathematical Functions (1966) is used to reduce the chisqure distribution to the incomplete distribution. Computation of other parameters involve a seach for a value that produces the desired value of P. The search relies on the monotinicity of P with the other parameter. **********************************************************************/ { #define tol 1.0e-8 #define atol 1.0e-50 #define zero 1.0e-100 #define inf 1.0e100 static int K1 = 1; static double K2 = 0.0e0; static double K4 = 0.5e0; static double K5 = 5.0e0; static double fx,cum,ccum,pq,porq; static unsigned long qhi,qleft,qporq; static double T3,T6,T7,T8,T9,T10,T11; /* .. .. Executable Statements .. */ /* Check arguments */ if(!(*which < 1 || *which > 3)) goto S30; if(!(*which < 1)) goto S10; *bound = 1.0e0; goto S20; S10: *bound = 3.0e0; S20: *status = -1; return; S30: if(*which == 1) goto S70; /* P */ if(!(*p < 0.0e0 || *p > 1.0e0)) goto S60; if(!(*p < 0.0e0)) goto S40; *bound = 0.0e0; goto S50; S40: *bound = 1.0e0; S50: *status = -2; return; S70: S60: if(*which == 1) goto S110; /* Q */ if(!(*q <= 0.0e0 || *q > 1.0e0)) goto S100; if(!(*q <= 0.0e0)) goto S80; *bound = 0.0e0; goto S90; S80: *bound = 1.0e0; S90: *status = -3; return; S110: S100: if(*which == 2) goto S130; /* X */ if(!(*x < 0.0e0)) goto S120; *bound = 0.0e0; *status = -4; return; S130: S120: if(*which == 3) goto S150; /* DF */ if(!(*df <= 0.0e0)) goto S140; *bound = 0.0e0; *status = -5; return; S150: S140: if(*which == 1) goto S190; /* P + Q */ pq = *p+*q; if(!(fabs(pq-0.5e0-0.5e0) > 3.0e0*spmpar(&K1))) goto S180; if(!(pq < 0.0e0)) goto S160; *bound = 0.0e0; goto S170; S160: *bound = 1.0e0; S170: *status = 3; return; S190: S180: if(*which == 1) goto S220; /* Select the minimum of P or Q */ qporq = *p <= *q; if(!qporq) goto S200; porq = *p; goto S210; S200: porq = *q; S220: S210: /* Calculate ANSWERS */ if(1 == *which) { /* Calculating P and Q */ *status = 0; cumchi(x,df,p,q); if(porq > 1.5e0) { *status = 10; return; } } else if(2 == *which) { /* Calculating X */ *x = 5.0e0; T3 = inf; T6 = atol; T7 = tol; dstinv(&K2,&T3,&K4,&K4,&K5,&T6,&T7); *status = 0; dinvr(status,x,&fx,&qleft,&qhi); S230: if(!(*status == 1)) goto S270; cumchi(x,df,&cum,&ccum); if(!qporq) goto S240; fx = cum-*p; goto S250; S240: fx = ccum-*q; S250: if(!(fx+porq > 1.5e0)) goto S260; *status = 10; return; S260: dinvr(status,x,&fx,&qleft,&qhi); goto S230; S270: if(!(*status == -1)) goto S300; if(!qleft) goto S280; *status = 1; *bound = 0.0e0; goto S290; S280: *status = 2; *bound = inf; S300: S290: ; } else if(3 == *which) { /* Calculating DF */ *df = 5.0e0; T8 = zero; T9 = inf; T10 = atol; T11 = tol; dstinv(&T8,&T9,&K4,&K4,&K5,&T10,&T11); *status = 0; dinvr(status,df,&fx,&qleft,&qhi); S310: if(!(*status == 1)) goto S350; cumchi(x,df,&cum,&ccum); if(!qporq) goto S320; fx = cum-*p; goto S330; S320: fx = ccum-*q; S330: if(!(fx+porq > 1.5e0)) goto S340; *status = 10; return; S340: dinvr(status,df,&fx,&qleft,&qhi); goto S310; S350: if(!(*status == -1)) goto S380; if(!qleft) goto S360; *status = 1; *bound = zero; goto S370; S360: *status = 2; *bound = inf; S370: ; } S380: return; #undef tol #undef atol #undef zero #undef inf } void cdfchn(int *which,double *p,double *q,double *x,double *df, double *pnonc,int *status,double *bound) /********************************************************************** void cdfchn(int *which,double *p,double *q,double *x,double *df, double *pnonc,int *status,double *bound) Cumulative Distribution Function Non-central Chi-Square Function Calculates any one parameter of the non-central chi-square distribution given values for the others. Arguments WHICH --> Integer indicating which of the next three argument values is to be calculated from the others. Input range: 1..4 iwhich = 1 : Calculate P and Q from X and DF iwhich = 2 : Calculate X from P,DF and PNONC iwhich = 3 : Calculate DF from P,X and PNONC iwhich = 3 : Calculate PNONC from P,X and DF P <--> The integral from 0 to X of the non-central chi-square distribution. Input range: [0, 1-1E-16). Q <--> 1-P. Q is not used by this subroutine and is only included for similarity with other cdf* routines. X <--> Upper limit of integration of the non-central chi-square distribution. Input range: [0, +infinity). Search range: [0,1E100] DF <--> Degrees of freedom of the non-central chi-square distribution. Input range: (0, +infinity). Search range: [ 1E-100, 1E100] PNONC <--> Non-centrality parameter of the non-central chi-square distribution. Input range: [0, +infinity). Search range: [0,1E4] STATUS <-- 0 if calculation completed correctly -I if input parameter number I is out of range 1 if answer appears to be lower than lowest search bound 2 if answer appears to be higher than greatest search bound BOUND <-- Undefined if STATUS is 0 Bound exceeded by parameter number I if STATUS is negative. Lower search bound if STATUS is 1. Upper search bound if STATUS is 2. Method Formula 26.4.25 of Abramowitz and Stegun, Handbook of Mathematical Functions (1966) is used to compute the cumulative distribution function. Computation of other parameters involve a seach for a value that produces the desired value of P. The search relies on the monotinicity of P with the other parameter. WARNING The computation time required for this routine is proportional to the noncentrality parameter (PNONC). Very large values of this parameter can consume immense computer resources. This is why the search range is bounded by 10,000. **********************************************************************/ { #define tent4 1.0e4 #define tol 1.0e-8 #define atol 1.0e-50 #define zero 1.0e-100 #define one ( 1.0e0 - 1.0e-16 ) #define inf 1.0e100 static double K1 = 0.0e0; static double K3 = 0.5e0; static double K4 = 5.0e0; static double fx,cum,ccum; static unsigned long qhi,qleft; static double T2,T5,T6,T7,T8,T9,T10,T11,T12,T13; /* .. .. Executable Statements .. */ /* Check arguments */ if(!(*which < 1 || *which > 4)) goto S30; if(!(*which < 1)) goto S10; *bound = 1.0e0; goto S20; S10: *bound = 4.0e0; S20: *status = -1; return; S30: if(*which == 1) goto S70; /* P */ if(!(*p < 0.0e0 || *p > one)) goto S60; if(!(*p < 0.0e0)) goto S40; *bound = 0.0e0; goto S50; S40: *bound = one; S50: *status = -2; return; S70: S60: if(*which == 2) goto S90; /* X */ if(!(*x < 0.0e0)) goto S80; *bound = 0.0e0; *status = -4; return; S90: S80: if(*which == 3) goto S110; /* DF */ if(!(*df <= 0.0e0)) goto S100; *bound = 0.0e0; *status = -5; return; S110: S100: if(*which == 4) goto S130; /* PNONC */ if(!(*pnonc < 0.0e0)) goto S120; *bound = 0.0e0; *status = -6; return; S130: S120: /* Calculate ANSWERS */ if(1 == *which) { /* Calculating P and Q */ cumchn(x,df,pnonc,p,q); *status = 0; } else if(2 == *which) { /* Calculating X */ *x = 5.0e0; T2 = inf; T5 = atol; T6 = tol; dstinv(&K1,&T2,&K3,&K3,&K4,&T5,&T6); *status = 0; dinvr(status,x,&fx,&qleft,&qhi); S140: if(!(*status == 1)) goto S150; cumchn(x,df,pnonc,&cum,&ccum); fx = cum-*p; dinvr(status,x,&fx,&qleft,&qhi); goto S140; S150: if(!(*status == -1)) goto S180; if(!qleft) goto S160; *status = 1; *bound = 0.0e0; goto S170; S160: *status = 2; *bound = inf; S180: S170: ; } else if(3 == *which) { /* Calculating DF */ *df = 5.0e0; T7 = zero; T8 = inf; T9 = atol; T10 = tol; dstinv(&T7,&T8,&K3,&K3,&K4,&T9,&T10); *status = 0; dinvr(status,df,&fx,&qleft,&qhi); S190: if(!(*status == 1)) goto S200; cumchn(x,df,pnonc,&cum,&ccum); fx = cum-*p; dinvr(status,df,&fx,&qleft,&qhi); goto S190; S200: if(!(*status == -1)) goto S230; if(!qleft) goto S210; *status = 1; *bound = zero; goto S220; S210: *status = 2; *bound = inf; S230: S220: ; } else if(4 == *which) { /* Calculating PNONC */ *pnonc = 5.0e0; T11 = tent4; T12 = atol; T13 = tol; dstinv(&K1,&T11,&K3,&K3,&K4,&T12,&T13); *status = 0; dinvr(status,pnonc,&fx,&qleft,&qhi); S240: if(!(*status == 1)) goto S250; cumchn(x,df,pnonc,&cum,&ccum); fx = cum-*p; dinvr(status,pnonc,&fx,&qleft,&qhi); goto S240; S250: if(!(*status == -1)) goto S280; if(!qleft) goto S260; *status = 1; *bound = zero; goto S270; S260: *status = 2; *bound = tent4; S270: ; } S280: return; #undef tent4 #undef tol #undef atol #undef zero #undef one #undef inf } void cdff(int *which,double *p,double *q,double *f,double *dfn, double *dfd,int *status,double *bound) /********************************************************************** void cdff(int *which,double *p,double *q,double *f,double *dfn, double *dfd,int *status,double *bound) Cumulative Distribution Function F distribution Function Calculates any one parameter of the F distribution given values for the others. Arguments WHICH --> Integer indicating which of the next four argument values is to be calculated from the others. Legal range: 1..4 iwhich = 1 : Calculate P and Q from F,DFN and DFD iwhich = 2 : Calculate F from P,Q,DFN and DFD iwhich = 3 : Calculate DFN from P,Q,F and DFD iwhich = 4 : Calculate DFD from P,Q,F and DFN P <--> The integral from 0 to F of the f-density. Input range: [0,1]. Q <--> 1-P. Input range: (0, 1]. P + Q = 1.0. F <--> Upper limit of integration of the f-density. Input range: [0, +infinity). Search range: [0,1E100] DFN < --> Degrees of freedom of the numerator sum of squares. Input range: (0, +infinity). Search range: [ 1E-100, 1E100] DFD < --> Degrees of freedom of the denominator sum of squares. Input range: (0, +infinity). Search range: [ 1E-100, 1E100] STATUS <-- 0 if calculation completed correctly -I if input parameter number I is out of range 1 if answer appears to be lower than lowest search bound 2 if answer appears to be higher than greatest search bound 3 if P + Q .ne. 1 BOUND <-- Undefined if STATUS is 0 Bound exceeded by parameter number I if STATUS is negative. Lower search bound if STATUS is 1. Upper search bound if STATUS is 2. Method Formula 26.6.2 of Abramowitz and Stegun, Handbook of Mathematical Functions (1966) is used to reduce the computation of the cumulative distribution function for the F variate to that of an incomplete beta. Computation of other parameters involve a seach for a value that produces the desired value of P. The search relies on the monotinicity of P with the other parameter. WARNING The value of the cumulative F distribution is not necessarily monotone in either degrees of freedom. There thus may be two values that provide a given CDF value. This routine assumes monotonicity and will find an arbitrary one of the two values. **********************************************************************/ { #define tol 1.0e-8 #define atol 1.0e-50 #define zero 1.0e-100 #define inf 1.0e100 static int K1 = 1; static double K2 = 0.0e0; static double K4 = 0.5e0; static double K5 = 5.0e0; static double pq,fx,cum,ccum; static unsigned long qhi,qleft,qporq; static double T3,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15; /* .. .. Executable Statements .. */ /* Check arguments */ if(!(*which < 1 || *which > 4)) goto S30; if(!(*which < 1)) goto S10; *bound = 1.0e0; goto S20; S10: *bound = 4.0e0; S20: *status = -1; return; S30: if(*which == 1) goto S70; /* P */ if(!(*p < 0.0e0 || *p > 1.0e0)) goto S60; if(!(*p < 0.0e0)) goto S40; *bound = 0.0e0; goto S50; S40: *bound = 1.0e0; S50: *status = -2; return; S70: S60: if(*which == 1) goto S110; /* Q */ if(!(*q <= 0.0e0 || *q > 1.0e0)) goto S100; if(!(*q <= 0.0e0)) goto S80; *bound = 0.0e0; goto S90; S80: *bound = 1.0e0; S90: *status = -3; return; S110: S100: if(*which == 2) goto S130; /* F */ if(!(*f < 0.0e0)) goto S120; *bound = 0.0e0; *status = -4; return; S130: S120: if(*which == 3) goto S150; /* DFN */ if(!(*dfn <= 0.0e0)) goto S140; *bound = 0.0e0; *status = -5; return; S150: S140: if(*which == 4) goto S170; /* DFD */ if(!(*dfd <= 0.0e0)) goto S160; *bound = 0.0e0; *status = -6; return; S170: S160: if(*which == 1) goto S210; /* P + Q */ pq = *p+*q; if(!(fabs(pq-0.5e0-0.5e0) > 3.0e0*spmpar(&K1))) goto S200; if(!(pq < 0.0e0)) goto S180; *bound = 0.0e0; goto S190; S180: *bound = 1.0e0; S190: *status = 3; return; S210: S200: if(!(*which == 1)) qporq = *p <= *q; /* Select the minimum of P or Q Calculate ANSWERS */ if(1 == *which) { /* Calculating P */ cumf(f,dfn,dfd,p,q); *status = 0; } else if(2 == *which) { /* Calculating F */ *f = 5.0e0; T3 = inf; T6 = atol; T7 = tol; dstinv(&K2,&T3,&K4,&K4,&K5,&T6,&T7); *status = 0; dinvr(status,f,&fx,&qleft,&qhi); S220: if(!(*status == 1)) goto S250; cumf(f,dfn,dfd,&cum,&ccum); if(!qporq) goto S230; fx = cum-*p; goto S240; S230: fx = ccum-*q; S240: dinvr(status,f,&fx,&qleft,&qhi); goto S220; S250: if(!(*status == -1)) goto S280; if(!qleft) goto S260; *status = 1; *bound = 0.0e0; goto S270; S260: *status = 2; *bound = inf; S280: S270: ; } else if(3 == *which) { /* Calculating DFN */ *dfn = 5.0e0; T8 = zero; T9 = inf; T10 = atol; T11 = tol; dstinv(&T8,&T9,&K4,&K4,&K5,&T10,&T11); *status = 0; dinvr(status,dfn,&fx,&qleft,&qhi); S290: if(!(*status == 1)) goto S320; cumf(f,dfn,dfd,&cum,&ccum); if(!qporq) goto S300; fx = cum-*p; goto S310; S300: fx = ccum-*q; S310: dinvr(status,dfn,&fx,&qleft,&qhi); goto S290; S320: if(!(*status == -1)) goto S350; if(!qleft) goto S330; *status = 1; *bound = zero; goto S340; S330: *status = 2; *bound = inf; S350: S340: ; } else if(4 == *which) { /* Calculating DFD */ *dfd = 5.0e0; T12 = zero; T13 = inf; T14 = atol; T15 = tol; dstinv(&T12,&T13,&K4,&K4,&K5,&T14,&T15); *status = 0; dinvr(status,dfd,&fx,&qleft,&qhi); S360: if(!(*status == 1)) goto S390; cumf(f,dfn,dfd,&cum,&ccum); if(!qporq) goto S370; fx = cum-*p; goto S380; S370: fx = ccum-*q; S380: dinvr(status,dfd,&fx,&qleft,&qhi); goto S360; S390: if(!(*status == -1)) goto S420; if(!qleft) goto S400; *status = 1; *bound = zero; goto S410; S400: *status = 2; *bound = inf; S410: ; } S420: return; #undef tol #undef atol #undef zero #undef inf } void cdffnc(int *which,double *p,double *q,double *f,double *dfn, double *dfd,double *phonc,int *status,double *bound) /********************************************************************** void cdffnc(int *which,double *p,double *q,double *f,double *dfn, double *dfd,double *phonc,int *status,double *bound) Cumulative Distribution Function Non-central F distribution Function Calculates any one parameter of the Non-central F distribution given values for the others. Arguments WHICH --> Integer indicating which of the next five argument values is to be calculated from the others. Legal range: 1..5 iwhich = 1 : Calculate P and Q from F,DFN,DFD and PNONC iwhich = 2 : Calculate F from P,Q,DFN,DFD and PNONC iwhich = 3 : Calculate DFN from P,Q,F,DFD and PNONC iwhich = 4 : Calculate DFD from P,Q,F,DFN and PNONC iwhich = 5 : Calculate PNONC from P,Q,F,DFN and DFD P <--> The integral from 0 to F of the non-central f-density. Input range: [0,1-1E-16). Q <--> 1-P. Q is not used by this subroutine and is only included for similarity with other cdf* routines. F <--> Upper limit of integration of the non-central f-density. Input range: [0, +infinity). Search range: [0,1E100] DFN < --> Degrees of freedom of the numerator sum of squares. Input range: (0, +infinity). Search range: [ 1E-100, 1E100] DFD < --> Degrees of freedom of the denominator sum of squares. Must be in range: (0, +infinity). Input range: (0, +infinity). Search range: [ 1E-100, 1E100] PNONC <-> The non-centrality parameter Input range: [0,infinity) Search range: [0,1E4] STATUS <-- 0 if calculation completed correctly -I if input parameter number I is out of range 1 if answer appears to be lower than lowest search bound 2 if answer appears to be higher than greatest search bound 3 if P + Q .ne. 1 BOUND <-- Undefined if STATUS is 0 Bound exceeded by parameter number I if STATUS is negative. Lower search bound if STATUS is 1. Upper search bound if STATUS is 2. Method Formula 26.6.20 of Abramowitz and Stegun, Handbook of Mathematical Functions (1966) is used to compute the cumulative distribution function. Computation of other parameters involve a seach for a value that produces the desired value of P. The search relies on the monotinicity of P with the other parameter. WARNING The computation time required for this routine is proportional to the noncentrality parameter (PNONC). Very large values of this parameter can consume immense computer resources. This is why the search range is bounded by 10,000. WARNING The value of the cumulative noncentral F distribution is not necessarily monotone in either degrees of freedom. There thus may be two values that provide a given CDF value. This routine assumes monotonicity and will find an arbitrary one of the two values. **********************************************************************/ { #define tent4 1.0e4 #define tol 1.0e-8 #define atol 1.0e-50 #define zero 1.0e-100 #define one ( 1.0e0 - 1.0e-16 ) #define inf 1.0e100 static double K1 = 0.0e0; static double K3 = 0.5e0; static double K4 = 5.0e0; static double fx,cum,ccum; static unsigned long qhi,qleft; static double T2,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17; /* .. .. Executable Statements .. */ /* Check arguments */ if(!(*which < 1 || *which > 5)) goto S30; if(!(*which < 1)) goto S10; *bound = 1.0e0; goto S20; S10: *bound = 5.0e0; S20: *status = -1; return; S30: if(*which == 1) goto S70; /* P */ if(!(*p < 0.0e0 || *p > one)) goto S60; if(!(*p < 0.0e0)) goto S40; *bound = 0.0e0; goto S50; S40: *bound = one; S50: *status = -2; return; S70: S60: if(*which == 2) goto S90; /* F */ if(!(*f < 0.0e0)) goto S80; *bound = 0.0e0; *status = -4; return; S90: S80: if(*which == 3) goto S110; /* DFN */ if(!(*dfn <= 0.0e0)) goto S100; *bound = 0.0e0; *status = -5; return; S110: S100: if(*which == 4) goto S130; /* DFD */ if(!(*dfd <= 0.0e0)) goto S120; *bound = 0.0e0; *status = -6; return; S130: S120: if(*which == 5) goto S150; /* PHONC */ if(!(*phonc < 0.0e0)) goto S140; *bound = 0.0e0; *status = -7; return; S150: S140: /* Calculate ANSWERS */ if(1 == *which) { /* Calculating P */ cumfnc(f,dfn,dfd,phonc,p,q); *status = 0; } else if(2 == *which) { /* Calculating F */ *f = 5.0e0; T2 = inf; T5 = atol; T6 = tol; dstinv(&K1,&T2,&K3,&K3,&K4,&T5,&T6); *status = 0; dinvr(status,f,&fx,&qleft,&qhi); S160: if(!(*status == 1)) goto S170; cumfnc(f,dfn,dfd,phonc,&cum,&ccum); fx = cum-*p; dinvr(status,f,&fx,&qleft,&qhi); goto S160; S170: if(!(*status == -1)) goto S200; if(!qleft) goto S180; *status = 1; *bound = 0.0e0; goto S190; S180: *status = 2; *bound = inf; S200: S190: ; } else if(3 == *which) { /* Calculating DFN */ *dfn = 5.0e0; T7 = zero; T8 = inf; T9 = atol; T10 = tol; dstinv(&T7,&T8,&K3,&K3,&K4,&T9,&T10); *status = 0; dinvr(status,dfn,&fx,&qleft,&qhi); S210: if(!(*status == 1)) goto S220; cumfnc(f,dfn,dfd,phonc,&cum,&ccum); fx = cum-*p; dinvr(status,dfn,&fx,&qleft,&qhi); goto S210; S220: if(!(*status == -1)) goto S250; if(!qleft) goto S230; *status = 1; *bound = zero; goto S240; S230: *status = 2; *bound = inf; S250: S240: ; } else if(4 == *which) { /* Calculating DFD */ *dfd = 5.0e0; T11 = zero; T12 = inf; T13 = atol; T14 = tol; dstinv(&T11,&T12,&K3,&K3,&K4,&T13,&T14); *status = 0; dinvr(status,dfd,&fx,&qleft,&qhi); S260: if(!(*status == 1)) goto S270; cumfnc(f,dfn,dfd,phonc,&cum,&ccum); fx = cum-*p; dinvr(status,dfd,&fx,&qleft,&qhi); goto S260; S270: if(!(*status == -1)) goto S300; if(!qleft) goto S280; *status = 1; *bound = zero; goto S290; S280: *status = 2; *bound = inf; S300: S290: ; } else if(5 == *which) { /* Calculating PHONC */ *phonc = 5.0e0; T15 = tent4; T16 = atol; T17 = tol; dstinv(&K1,&T15,&K3,&K3,&K4,&T16,&T17); *status = 0; dinvr(status,phonc,&fx,&qleft,&qhi); S310: if(!(*status == 1)) goto S320; cumfnc(f,dfn,dfd,phonc,&cum,&ccum); fx = cum-*p; dinvr(status,phonc,&fx,&qleft,&qhi); goto S310; S320: if(!(*status == -1)) goto S350; if(!qleft) goto S330; *status = 1; *bound = 0.0e0; goto S340; S330: *status = 2; *bound = tent4; S340: ; } S350: return; #undef tent4 #undef tol #undef atol #undef zero #undef one #undef inf } void cdfgam(int *which,double *p,double *q,double *x,double *shape, double *scale,int *status,double *bound) /********************************************************************** void cdfgam(int *which,double *p,double *q,double *x,double *shape, double *scale,int *status,double *bound) Cumulative Distribution Function GAMma Distribution Function Calculates any one parameter of the gamma distribution given values for the others. Arguments WHICH --> Integer indicating which of the next four argument values is to be calculated from the others. Legal range: 1..4 iwhich = 1 : Calculate P and Q from X,SHAPE and SCALE iwhich = 2 : Calculate X from P,Q,SHAPE and SCALE iwhich = 3 : Calculate SHAPE from P,Q,X and SCALE iwhich = 4 : Calculate SCALE from P,Q,X and SHAPE P <--> The integral from 0 to X of the gamma density. Input range: [0,1]. Q <--> 1-P. Input range: (0, 1]. P + Q = 1.0. X <--> The upper limit of integration of the gamma density. Input range: [0, +infinity). Search range: [0,1E100] SHAPE <--> The shape parameter of the gamma density. Input range: (0, +infinity). Search range: [1E-100,1E100] SCALE <--> The scale parameter of the gamma density. Input range: (0, +infinity). Search range: (1E-100,1E100] STATUS <-- 0 if calculation completed correctly -I if input parameter number I is out of range 1 if answer appears to be lower than lowest search bound 2 if answer appears to be higher than greatest search bound 3 if P + Q .ne. 1 10 if the gamma or inverse gamma routine cannot compute the answer. Usually happens only for X and SHAPE very large (gt 1E10 or more) BOUND <-- Undefined if STATUS is 0 Bound exceeded by parameter number I if STATUS is negative. Lower search bound if STATUS is 1. Upper search bound if STATUS is 2. Method Cumulative distribution function (P) is calculated directly by the code associated with: DiDinato, A. R. and Morris, A. H. Computation of the incomplete gamma function ratios and their inverse. ACM Trans. Math. Softw. 12 (1986), 377-393. Computation of other parameters involve a seach for a value that produces the desired value of P. The search relies on the monotinicity of P with the other parameter. Note The gamma density is proportional to T**(SHAPE - 1) * EXP(- SCALE * T) **********************************************************************/ { #define tol 1.0e-8 #define atol 1.0e-50 #define zero 1.0e-100 #define inf 1.0e100 static int K1 = 1; static double K5 = 0.5e0; static double K6 = 5.0e0; static double xx,fx,xscale,cum,ccum,pq,porq; static int ierr; static unsigned long qhi,qleft,qporq; static double T2,T3,T4,T7,T8,T9; /* .. .. Executable Statements .. */ /* Check arguments */ if(!(*which < 1 || *which > 4)) goto S30; if(!(*which < 1)) goto S10; *bound = 1.0e0; goto S20; S10: *bound = 4.0e0; S20: *status = -1; return; S30: if(*which == 1) goto S70; /* P */ if(!(*p < 0.0e0 || *p > 1.0e0)) goto S60; if(!(*p < 0.0e0)) goto S40; *bound = 0.0e0; goto S50; S40: *bound = 1.0e0; S50: *status = -2; return; S70: S60: if(*which == 1) goto S110; /* Q */ if(!(*q <= 0.0e0 || *q > 1.0e0)) goto S100; if(!(*q <= 0.0e0)) goto S80; *bound = 0.0e0; goto S90; S80: *bound = 1.0e0; S90: *status = -3; return; S110: S100: if(*which == 2) goto S130; /* X */ if(!(*x < 0.0e0)) goto S120; *bound = 0.0e0; *status = -4; return; S130: S120: if(*which == 3) goto S150; /* SHAPE */ if(!(*shape <= 0.0e0)) goto S140; *bound = 0.0e0; *status = -5; return; S150: S140: if(*which == 4) goto S170; /* SCALE */ if(!(*scale <= 0.0e0)) goto S160; *bound = 0.0e0; *status = -6; return; S170: S160: if(*which == 1) goto S210; /* P + Q */ pq = *p+*q; if(!(fabs(pq-0.5e0-0.5e0) > 3.0e0*spmpar(&K1))) goto S200; if(!(pq < 0.0e0)) goto S180; *bound = 0.0e0; goto S190; S180: *bound = 1.0e0; S190: *status = 3; return; S210: S200: if(*which == 1) goto S240; /* Select the minimum of P or Q */ qporq = *p <= *q; if(!qporq) goto S220; porq = *p; goto S230; S220: porq = *q; S240: S230: /* Calculate ANSWERS */ if(1 == *which) { /* Calculating P */ *status = 0; xscale = *x**scale; cumgam(&xscale,shape,p,q); if(porq > 1.5e0) *status = 10; } else if(2 == *which) { /* Computing X */ T2 = -1.0e0; gaminv(shape,&xx,&T2,p,q,&ierr); if(ierr < 0.0e0) { *status = 10; return; } else { *x = xx/ *scale; *status = 0; } } else if(3 == *which) { /* Computing SHAPE */ *shape = 5.0e0; xscale = *x**scale; T3 = zero; T4 = inf; T7 = atol; T8 = tol; dstinv(&T3,&T4,&K5,&K5,&K6,&T7,&T8); *status = 0; dinvr(status,shape,&fx,&qleft,&qhi); S250: if(!(*status == 1)) goto S290; cumgam(&xscale,shape,&cum,&ccum); if(!qporq) goto S260; fx = cum-*p; goto S270; S260: fx = ccum-*q; S270: if((!(qporq && (cum > 1.5e0)) || (!qporq && (ccum > 1.5e0)))) goto S280; *status = 10; return; S280: dinvr(status,shape,&fx,&qleft,&qhi); goto S250; S290: if(!(*status == -1)) goto S320; if(!qleft) goto S300; *status = 1; *bound = zero; goto S310; S300: *status = 2; *bound = inf; S320: S310: ; } else if(4 == *which) { /* Computing SCALE */ T9 = -1.0e0; gaminv(shape,&xx,&T9,p,q,&ierr); if(ierr < 0.0e0) { *status = 10; return; } else { *scale = xx/ *x; *status = 0; } } return; #undef tol #undef atol #undef zero #undef inf } void cdfnbn(int *which,double *p,double *q,double *s,double *xn, double *pr,double *ompr,int *status,double *bound) /********************************************************************** void cdfnbn(int *which,double *p,double *q,double *s,double *xn, double *pr,double *ompr,int *status,double *bound) Cumulative Distribution Function Negative BiNomial distribution Function Calculates any one parameter of the negative binomial distribution given values for the others. The cumulative negative binomial distribution returns the probability that there will be F or fewer failures before the XNth success in binomial trials each of which has probability of success PR. The individual term of the negative binomial is the probability of S failures before XN successes and is Choose( S, XN+S-1 ) * PR^(XN) * (1-PR)^S Arguments WHICH --> Integer indicating which of the next four argument values is to be calculated from the others. Legal range: 1..4 iwhich = 1 : Calculate P and Q from S,XN,PR and OMPR iwhich = 2 : Calculate S from P,Q,XN,PR and OMPR iwhich = 3 : Calculate XN from P,Q,S,PR and OMPR iwhich = 4 : Calculate PR and OMPR from P,Q,S and XN P <--> The cumulation from 0 to S of the negative binomial distribution. Input range: [0,1]. Q <--> 1-P. Input range: (0, 1]. P + Q = 1.0. S <--> The upper limit of cumulation of the binomial distribution. There are F or fewer failures before the XNth success. Input range: [0, +infinity). Search range: [0, 1E100] XN <--> The number of successes. Input range: [0, +infinity). Search range: [0, 1E100] PR <--> The probability of success in each binomial trial. Input range: [0,1]. Search range: [0,1]. OMPR <--> 1-PR Input range: [0,1]. Search range: [0,1] PR + OMPR = 1.0 STATUS <-- 0 if calculation completed correctly -I if input parameter number I is out of range 1 if answer appears to be lower than lowest search bound 2 if answer appears to be higher than greatest search bound 3 if P + Q .ne. 1 4 if PR + OMPR .ne. 1 BOUND <-- Undefined if STATUS is 0 Bound exceeded by parameter number I if STATUS is negative. Lower search bound if STATUS is 1. Upper search bound if STATUS is 2. Method Formula 26.5.26 of Abramowitz and Stegun, Handbook of Mathematical Functions (1966) is used to reduce calculation of the cumulative distribution function to that of an incomplete beta. Computation of other parameters involve a seach for a value that produces the desired value of P. The search relies on the monotinicity of P with the other parameter. **********************************************************************/ { #define tol 1.0e-8 #define atol 1.0e-50 #define inf 1.0e100 #define one 1.0e0 static int K1 = 1; static double K2 = 0.0e0; static double K4 = 0.5e0; static double K5 = 5.0e0; static double K11 = 1.0e0; static double fx,xhi,xlo,pq,prompr,cum,ccum; static unsigned long qhi,qleft,qporq; static double T3,T6,T7,T8,T9,T10,T12,T13; /* .. .. Executable Statements .. */ /* Check arguments */ if(!(*which < 1 || *which > 4)) goto S30; if(!(*which < 1)) goto S10; *bound = 1.0e0; goto S20; S10: *bound = 4.0e0; S20: *status = -1; return; S30: if(*which == 1) goto S70; /* P */ if(!(*p < 0.0e0 || *p > 1.0e0)) goto S60; if(!(*p < 0.0e0)) goto S40; *bound = 0.0e0; goto S50; S40: *bound = 1.0e0; S50: *status = -2; return; S70: S60: if(*which == 1) goto S110; /* Q */ if(!(*q <= 0.0e0 || *q > 1.0e0)) goto S100; if(!(*q <= 0.0e0)) goto S80; *bound = 0.0e0; goto S90; S80: *bound = 1.0e0; S90: *status = -3; return; S110: S100: if(*which == 2) goto S130; /* S */ if(!(*s < 0.0e0)) goto S120; *bound = 0.0e0; *status = -4; return; S130: S120: if(*which == 3) goto S150; /* XN */ if(!(*xn < 0.0e0)) goto S140; *bound = 0.0e0; *status = -5; return; S150: S140: if(*which == 4) goto S190; /* PR */ if(!(*pr < 0.0e0 || *pr > 1.0e0)) goto S180; if(!(*pr < 0.0e0)) goto S160; *bound = 0.0e0; goto S170; S160: *bound = 1.0e0; S170: *status = -6; return; S190: S180: if(*which == 4) goto S230; /* OMPR */ if(!(*ompr < 0.0e0 || *ompr > 1.0e0)) goto S220; if(!(*ompr < 0.0e0)) goto S200; *bound = 0.0e0; goto S210; S200: *bound = 1.0e0; S210: *status = -7; return; S230: S220: if(*which == 1) goto S270; /* P + Q */ pq = *p+*q; if(!(fabs(pq-0.5e0-0.5e0) > 3.0e0*spmpar(&K1))) goto S260; if(!(pq < 0.0e0)) goto S240; *bound = 0.0e0; goto S250; S240: *bound = 1.0e0; S250: *status = 3; return; S270: S260: if(*which == 4) goto S310; /* PR + OMPR */ prompr = *pr+*ompr; if(!(fabs(prompr-0.5e0-0.5e0) > 3.0e0*spmpar(&K1))) goto S300; if(!(prompr < 0.0e0)) goto S280; *bound = 0.0e0; goto S290; S280: *bound = 1.0e0; S290: *status = 4; return; S310: S300: if(!(*which == 1)) qporq = *p <= *q; /* Select the minimum of P or Q Calculate ANSWERS */ if(1 == *which) { /* Calculating P */ cumnbn(s,xn,pr,ompr,p,q); *status = 0; } else if(2 == *which) { /* Calculating S */ *s = 5.0e0; T3 = inf; T6 = atol; T7 = tol; dstinv(&K2,&T3,&K4,&K4,&K5,&T6,&T7); *status = 0; dinvr(status,s,&fx,&qleft,&qhi); S320: if(!(*status == 1)) goto S350; cumnbn(s,xn,pr,ompr,&cum,&ccum); if(!qporq) goto S330; fx = cum-*p; goto S340; S330: fx = ccum-*q; S340: dinvr(status,s,&fx,&qleft,&qhi); goto S320; S350: if(!(*status == -1)) goto S380; if(!qleft) goto S360; *status = 1; *bound = 0.0e0; goto S370; S360: *status = 2; *bound = inf; S380: S370: ; } else if(3 == *which) { /* Calculating XN */ *xn = 5.0e0; T8 = inf; T9 = atol; T10 = tol; dstinv(&K2,&T8,&K4,&K4,&K5,&T9,&T10); *status = 0; dinvr(status,xn,&fx,&qleft,&qhi); S390: if(!(*status == 1)) goto S420; cumnbn(s,xn,pr,ompr,&cum,&ccum); if(!qporq) goto S400; fx = cum-*p; goto S410; S400: fx = ccum-*q; S410: dinvr(status,xn,&fx,&qleft,&qhi); goto S390; S420: if(!(*status == -1)) goto S450; if(!qleft) goto S430; *status = 1; *bound = 0.0e0; goto S440; S430: *status = 2; *bound = inf; S450: S440: ; } else if(4 == *which) { /* Calculating PR and OMPR */ T12 = atol; T13 = tol; dstzr(&K2,&K11,&T12,&T13); if(!qporq) goto S480; *status = 0; dzror(status,pr,&fx,&xlo,&xhi,&qleft,&qhi); *ompr = one-*pr; S460: if(!(*status == 1)) goto S470; cumnbn(s,xn,pr,ompr,&cum,&ccum); fx = cum-*p; dzror(status,pr,&fx,&xlo,&xhi,&qleft,&qhi); *ompr = one-*pr; goto S460; S470: goto S510; S480: *status = 0; dzror(status,ompr,&fx,&xlo,&xhi,&qleft,&qhi); *pr = one-*ompr; S490: if(!(*status == 1)) goto S500; cumnbn(s,xn,pr,ompr,&cum,&ccum); fx = ccum-*q; dzror(status,ompr,&fx,&xlo,&xhi,&qleft,&qhi); *pr = one-*ompr; goto S490; S510: S500: if(!(*status == -1)) goto S540; if(!qleft) goto S520; *status = 1; *bound = 0.0e0; goto S530; S520: *status = 2; *bound = 1.0e0; S530: ; } S540: return; #undef tol #undef atol #undef inf #undef one } void cdfnor(int *which,double *p,double *q,double *x,double *mean, double *sd,int *status,double *bound) /********************************************************************** void cdfnor(int *which,double *p,double *q,double *x,double *mean, double *sd,int *status,double *bound) Cumulative Distribution Function NORmal distribution Function Calculates any one parameter of the normal distribution given values for the others. Arguments WHICH --> Integer indicating which of the next parameter values is to be calculated using values of the others. Legal range: 1..4 iwhich = 1 : Calculate P and Q from X,MEAN and SD iwhich = 2 : Calculate X from P,Q,MEAN and SD iwhich = 3 : Calculate MEAN from P,Q,X and SD iwhich = 4 : Calculate SD from P,Q,X and MEAN P <--> The integral from -infinity to X of the normal density. Input range: (0,1]. Q <--> 1-P. Input range: (0, 1]. P + Q = 1.0. X < --> Upper limit of integration of the normal-density. Input range: ( -infinity, +infinity) MEAN <--> The mean of the normal density. Input range: (-infinity, +infinity) SD <--> Standard Deviation of the normal density. Input range: (0, +infinity). STATUS <-- 0 if calculation completed correctly -I if input parameter number I is out of range 1 if answer appears to be lower than lowest search bound 2 if answer appears to be higher than greatest search bound 3 if P + Q .ne. 1 BOUND <-- Undefined if STATUS is 0 Bound exceeded by parameter number I if STATUS is negative. Lower search bound if STATUS is 1. Upper search bound if STATUS is 2. Method A slightly modified version of ANORM from Cody, W.D. (1993). "ALGORITHM 715: SPECFUN - A Portabel FORTRAN Package of Special Function Routines and Test Drivers" acm Transactions on Mathematical Software. 19, 22-32. is used to calulate the cumulative standard normal distribution. The rational functions from pages 90-95 of Kennedy and Gentle, Statistical Computing, Marcel Dekker, NY, 1980 are used as starting values to Newton's Iterations which compute the inverse standard normal. Therefore no searches are necessary for any parameter. For X < -15, the asymptotic expansion for the normal is used as the starting value in finding the inverse standard normal. This is formula 26.2.12 of Abramowitz and Stegun. Note The normal density is proportional to exp( - 0.5 * (( X - MEAN)/SD)**2) **********************************************************************/ { static int K1 = 1; static double z,pq; /* .. .. Executable Statements .. */ /* Check arguments */ *status = 0; if(!(*which < 1 || *which > 4)) goto S30; if(!(*which < 1)) goto S10; *bound = 1.0e0; goto S20; S10: *bound = 4.0e0; S20: *status = -1; return; S30: if(*which == 1) goto S70; /* P */ if(!(*p <= 0.0e0 || *p > 1.0e0)) goto S60; if(!(*p <= 0.0e0)) goto S40; *bound = 0.0e0; goto S50; S40: *bound = 1.0e0; S50: *status = -2; return; S70: S60: if(*which == 1) goto S110; /* Q */ if(!(*q <= 0.0e0 || *q > 1.0e0)) goto S100; if(!(*q <= 0.0e0)) goto S80; *bound = 0.0e0; goto S90; S80: *bound = 1.0e0; S90: *status = -3; return; S110: S100: if(*which == 1) goto S150; /* P + Q */ pq = *p+*q; if(!(fabs(pq-0.5e0-0.5e0) > 3.0e0*spmpar(&K1))) goto S140; if(!(pq < 0.0e0)) goto S120; *bound = 0.0e0; goto S130; S120: *bound = 1.0e0; S130: *status = 3; return; S150: S140: if(*which == 4) goto S170; /* SD */ if(!(*sd <= 0.0e0)) goto S160; *bound = 0.0e0; *status = -6; return; S170: S160: /* Calculate ANSWERS */ if(1 == *which) { /* Computing P */ z = (*x-*mean)/ *sd; cumnor(&z,p,q); } else if(2 == *which) { /* Computing X */ z = dinvnr(p,q); *x = *sd*z+*mean; } else if(3 == *which) { /* Computing the MEAN */ z = dinvnr(p,q); *mean = *x-*sd*z; } else if(4 == *which) { /* Computing SD */ z = dinvnr(p,q); *sd = (*x-*mean)/z; } return; } void cdfpoi(int *which,double *p,double *q,double *s,double *xlam, int *status,double *bound) /********************************************************************** void cdfpoi(int *which,double *p,double *q,double *s,double *xlam, int *status,double *bound) Cumulative Distribution Function POIsson distribution Function Calculates any one parameter of the Poisson distribution given values for the others. Arguments WHICH --> Integer indicating which argument value is to be calculated from the others. Legal range: 1..3 iwhich = 1 : Calculate P and Q from S and XLAM iwhich = 2 : Calculate A from P,Q and XLAM iwhich = 3 : Calculate XLAM from P,Q and S P <--> The cumulation from 0 to S of the poisson density. Input range: [0,1]. Q <--> 1-P. Input range: (0, 1]. P + Q = 1.0. S <--> Upper limit of cumulation of the Poisson. Input range: [0, +infinity). Search range: [0,1E100] XLAM <--> Mean of the Poisson distribution. Input range: [0, +infinity). Search range: [0,1E100] STATUS <-- 0 if calculation completed correctly -I if input parameter number I is out of range 1 if answer appears to be lower than lowest search bound 2 if answer appears to be higher than greatest search bound 3 if P + Q .ne. 1 BOUND <-- Undefined if STATUS is 0 Bound exceeded by parameter number I if STATUS is negative. Lower search bound if STATUS is 1. Upper search bound if STATUS is 2. Method Formula 26.4.21 of Abramowitz and Stegun, Handbook of Mathematical Functions (1966) is used to reduce the computation of the cumulative distribution function to that of computing a chi-square, hence an incomplete gamma function. Cumulative distribution function (P) is calculated directly. Computation of other parameters involve a seach for a value that produces the desired value of P. The search relies on the monotinicity of P with the other parameter. **********************************************************************/ { #define tol 1.0e-8 #define atol 1.0e-50 #define inf 1.0e100 static int K1 = 1; static double K2 = 0.0e0; static double K4 = 0.5e0; static double K5 = 5.0e0; static double fx,cum,ccum,pq; static unsigned long qhi,qleft,qporq; static double T3,T6,T7,T8,T9,T10; /* .. .. Executable Statements .. */ /* Check arguments */ if(!(*which < 1 || *which > 3)) goto S30; if(!(*which < 1)) goto S10; *bound = 1.0e0; goto S20; S10: *bound = 3.0e0; S20: *status = -1; return; S30: if(*which == 1) goto S70; /* P */ if(!(*p < 0.0e0 || *p > 1.0e0)) goto S60; if(!(*p < 0.0e0)) goto S40; *bound = 0.0e0; goto S50; S40: *bound = 1.0e0; S50: *status = -2; return; S70: S60: if(*which == 1) goto S110; /* Q */ if(!(*q <= 0.0e0 || *q > 1.0e0)) goto S100; if(!(*q <= 0.0e0)) goto S80; *bound = 0.0e0; goto S90; S80: *bound = 1.0e0; S90: *status = -3; return; S110: S100: if(*which == 2) goto S130; /* S */ if(!(*s < 0.0e0)) goto S120; *bound = 0.0e0; *status = -4; return; S130: S120: if(*which == 3) goto S150; /* XLAM */ if(!(*xlam < 0.0e0)) goto S140; *bound = 0.0e0; *status = -5; return; S150: S140: if(*which == 1) goto S190; /* P + Q */ pq = *p+*q; if(!(fabs(pq-0.5e0-0.5e0) > 3.0e0*spmpar(&K1))) goto S180; if(!(pq < 0.0e0)) goto S160; *bound = 0.0e0; goto S170; S160: *bound = 1.0e0; S170: *status = 3; return; S190: S180: if(!(*which == 1)) qporq = *p <= *q; /* Select the minimum of P or Q Calculate ANSWERS */ if(1 == *which) { /* Calculating P */ cumpoi(s,xlam,p,q); *status = 0; } else if(2 == *which) { /* Calculating S */ *s = 5.0e0; T3 = inf; T6 = atol; T7 = tol; dstinv(&K2,&T3,&K4,&K4,&K5,&T6,&T7); *status = 0; dinvr(status,s,&fx,&qleft,&qhi); S200: if(!(*status == 1)) goto S230; cumpoi(s,xlam,&cum,&ccum); if(!qporq) goto S210; fx = cum-*p; goto S220; S210: fx = ccum-*q; S220: dinvr(status,s,&fx,&qleft,&qhi); goto S200; S230: if(!(*status == -1)) goto S260; if(!qleft) goto S240; *status = 1; *bound = 0.0e0; goto S250; S240: *status = 2; *bound = inf; S260: S250: ; } else if(3 == *which) { /* Calculating XLAM */ *xlam = 5.0e0; T8 = inf; T9 = atol; T10 = tol; dstinv(&K2,&T8,&K4,&K4,&K5,&T9,&T10); *status = 0; dinvr(status,xlam,&fx,&qleft,&qhi); S270: if(!(*status == 1)) goto S300; cumpoi(s,xlam,&cum,&ccum); if(!qporq) goto S280; fx = cum-*p; goto S290; S280: fx = ccum-*q; S290: dinvr(status,xlam,&fx,&qleft,&qhi); goto S270; S300: if(!(*status == -1)) goto S330; if(!qleft) goto S310; *status = 1; *bound = 0.0e0; goto S320; S310: *status = 2; *bound = inf; S320: ; } S330: return; #undef tol #undef atol #undef inf } void cdft(int *which,double *p,double *q,double *t,double *df, int *status,double *bound) /********************************************************************** void cdft(int *which,double *p,double *q,double *t,double *df, int *status,double *bound) Cumulative Distribution Function T distribution Function Calculates any one parameter of the t distribution given values for the others. Arguments WHICH --> Integer indicating which argument values is to be calculated from the others. Legal range: 1..3 iwhich = 1 : Calculate P and Q from T and DF iwhich = 2 : Calculate T from P,Q and DF iwhich = 3 : Calculate DF from P,Q and T P <--> The integral from -infinity to t of the t-density. Input range: (0,1]. Q <--> 1-P. Input range: (0, 1]. P + Q = 1.0. T <--> Upper limit of integration of the t-density. Input range: ( -infinity, +infinity). Search range: [ -1E100, 1E100 ] DF <--> Degrees of freedom of the t-distribution. Input range: (0 , +infinity). Search range: [1e-100, 1E10] STATUS <-- 0 if calculation completed correctly -I if input parameter number I is out of range 1 if answer appears to be lower than lowest search bound 2 if answer appears to be higher than greatest search bound 3 if P + Q .ne. 1 BOUND <-- Undefined if STATUS is 0 Bound exceeded by parameter number I if STATUS is negative. Lower search bound if STATUS is 1. Upper search bound if STATUS is 2. Method Formula 26.5.27 of Abramowitz and Stegun, Handbook of Mathematical Functions (1966) is used to reduce the computation of the cumulative distribution function to that of an incomplete beta. Computation of other parameters involve a seach for a value that produces the desired value of P. The search relies on the monotinicity of P with the other parameter. **********************************************************************/ { #define tol 1.0e-8 #define atol 1.0e-50 #define zero 1.0e-100 #define inf 1.0e100 #define rtinf 1.0e100 #define maxdf 1.0e10 static int K1 = 1; static double K4 = 0.5e0; static double K5 = 5.0e0; static double fx,cum,ccum,pq; static unsigned long qhi,qleft,qporq; static double T2,T3,T6,T7,T8,T9,T10,T11; /* .. .. Executable Statements .. */ /* Check arguments */ if(!(*which < 1 || *which > 3)) goto S30; if(!(*which < 1)) goto S10; *bound = 1.0e0; goto S20; S10: *bound = 3.0e0; S20: *status = -1; return; S30: if(*which == 1) goto S70; /* P */ if(!(*p <= 0.0e0 || *p > 1.0e0)) goto S60; if(!(*p <= 0.0e0)) goto S40; *bound = 0.0e0; goto S50; S40: *bound = 1.0e0; S50: *status = -2; return; S70: S60: if(*which == 1) goto S110; /* Q */ if(!(*q <= 0.0e0 || *q > 1.0e0)) goto S100; if(!(*q <= 0.0e0)) goto S80; *bound = 0.0e0; goto S90; S80: *bound = 1.0e0; S90: *status = -3; return; S110: S100: if(*which == 3) goto S130; /* DF */ if(!(*df <= 0.0e0)) goto S120; *bound = 0.0e0; *status = -5; return; S130: S120: if(*which == 1) goto S170; /* P + Q */ pq = *p+*q; if(!(fabs(pq-0.5e0-0.5e0) > 3.0e0*spmpar(&K1))) goto S160; if(!(pq < 0.0e0)) goto S140; *bound = 0.0e0; goto S150; S140: *bound = 1.0e0; S150: *status = 3; return; S170: S160: if(!(*which == 1)) qporq = *p <= *q; /* Select the minimum of P or Q Calculate ANSWERS */ if(1 == *which) { /* Computing P and Q */ cumt(t,df,p,q); *status = 0; } else if(2 == *which) { /* Computing T .. Get initial approximation for T */ *t = dt1(p,q,df); T2 = -rtinf; T3 = rtinf; T6 = atol; T7 = tol; dstinv(&T2,&T3,&K4,&K4,&K5,&T6,&T7); *status = 0; dinvr(status,t,&fx,&qleft,&qhi); S180: if(!(*status == 1)) goto S210; cumt(t,df,&cum,&ccum); if(!qporq) goto S190; fx = cum-*p; goto S200; S190: fx = ccum-*q; S200: dinvr(status,t,&fx,&qleft,&qhi); goto S180; S210: if(!(*status == -1)) goto S240; if(!qleft) goto S220; *status = 1; *bound = -rtinf; goto S230; S220: *status = 2; *bound = rtinf; S240: S230: ; } else if(3 == *which) { /* Computing DF */ *df = 5.0e0; T8 = zero; T9 = maxdf; T10 = atol; T11 = tol; dstinv(&T8,&T9,&K4,&K4,&K5,&T10,&T11); *status = 0; dinvr(status,df,&fx,&qleft,&qhi); S250: if(!(*status == 1)) goto S280; cumt(t,df,&cum,&ccum); if(!qporq) goto S260; fx = cum-*p; goto S270; S260: fx = ccum-*q; S270: dinvr(status,df,&fx,&qleft,&qhi); goto S250; S280: if(!(*status == -1)) goto S310; if(!qleft) goto S290; *status = 1; *bound = zero; goto S300; S290: *status = 2; *bound = maxdf; S300: ; } S310: return; #undef tol #undef atol #undef zero #undef inf #undef rtinf #undef maxdf } void cdftnc(int *which,double *p,double *q,double *t,double *df, double *pnonc,int *status,double *bound) /********************************************************************** void cdftnc(int *which,double *p,double *q,double *t,double *df, double *pnonc,int *status,double *bound) Cumulative Distribution Function Non-Central T distribution Function Calculates any one parameter of the noncentral t distribution give values for the others. Arguments WHICH --> Integer indicating which argument values is to be calculated from the others. Legal range: 1..3 iwhich = 1 : Calculate P and Q from T,DF,PNONC iwhich = 2 : Calculate T from P,Q,DF,PNONC iwhich = 3 : Calculate DF from P,Q,T iwhich = 4 : Calculate PNONC from P,Q,DF,T P <--> The integral from -infinity to t of the noncentral t-den Input range: (0,1]. Q <--> 1-P. Input range: (0, 1]. P + Q = 1.0. T <--> Upper limit of integration of the noncentral t-density. Input range: ( -infinity, +infinity). Search range: [ -1E100, 1E100 ] DF <--> Degrees of freedom of the noncentral t-distribution. Input range: (0 , +infinity). Search range: [1e-100, 1E10] PNONC <--> Noncentrality parameter of the noncentral t-distributio Input range: [-infinity , +infinity). Search range: [-1e4, 1E4] STATUS <-- 0 if calculation completed correctly -I if input parameter number I is out of range 1 if answer appears to be lower than lowest search bound 2 if answer appears to be higher than greatest search bound 3 if P + Q .ne. 1 BOUND <-- Undefined if STATUS is 0 Bound exceeded by parameter number I if STATUS is negative. Lower search bound if STATUS is 1. Upper search bound if STATUS is 2. Method Upper tail of the cumulative noncentral t is calculated usin formulae from page 532 of Johnson, Kotz, Balakrishnan, Coninuou Univariate Distributions, Vol 2, 2nd Edition. Wiley (1995) Computation of other parameters involve a seach for a value that produces the desired value of P. The search relies on the monotinicity of P with the other parameter. **********************************************************************/ { #define tent4 1.0e4 #define tol 1.0e-8 #define atol 1.0e-50 #define zero 1.0e-100 #define one ( 1.0e0 - 1.0e-16 ) #define inf 1.0e100 static double K3 = 0.5e0; static double K4 = 5.0e0; static double ccum,cum,fx; static unsigned long qhi,qleft; static double T1,T2,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14; /* .. .. Executable Statements .. */ if(!(*which < 1 || *which > 4)) goto S30; if(!(*which < 1)) goto S10; *bound = 1.0e0; goto S20; S10: *bound = 5.0e0; S20: *status = -1; return; S30: if(*which == 1) goto S70; if(!(*p < 0.0e0 || *p > one)) goto S60; if(!(*p < 0.0e0)) goto S40; *bound = 0.0e0; goto S50; S40: *bound = one; S50: *status = -2; return; S70: S60: if(*which == 3) goto S90; if(!(*df <= 0.0e0)) goto S80; *bound = 0.0e0; *status = -5; return; S90: S80: if(*which == 4) goto S100; S100: if(1 == *which) { cumtnc(t,df,pnonc,p,q); *status = 0; } else if(2 == *which) { *t = 5.0e0; T1 = -inf; T2 = inf; T5 = atol; T6 = tol; dstinv(&T1,&T2,&K3,&K3,&K4,&T5,&T6); *status = 0; dinvr(status,t,&fx,&qleft,&qhi); S110: if(!(*status == 1)) goto S120; cumtnc(t,df,pnonc,&cum,&ccum); fx = cum - *p; dinvr(status,t,&fx,&qleft,&qhi); goto S110; S120: if(!(*status == -1)) goto S150; if(!qleft) goto S130; *status = 1; *bound = -inf; goto S140; S130: *status = 2; *bound = inf; S150: S140: ; } else if(3 == *which) { *df = 5.0e0; T7 = zero; T8 = tent4; T9 = atol; T10 = tol; dstinv(&T7,&T8,&K3,&K3,&K4,&T9,&T10); *status = 0; dinvr(status,df,&fx,&qleft,&qhi); S160: if(!(*status == 1)) goto S170; cumtnc(t,df,pnonc,&cum,&ccum); fx = cum - *p; dinvr(status,df,&fx,&qleft,&qhi); goto S160; S170: if(!(*status == -1)) goto S200; if(!qleft) goto S180; *status = 1; *bound = zero; goto S190; S180: *status = 2; *bound = inf; S200: S190: ; } else if(4 == *which) { *pnonc = 5.0e0; T11 = -tent4; T12 = tent4; T13 = atol; T14 = tol; dstinv(&T11,&T12,&K3,&K3,&K4,&T13,&T14); *status = 0; dinvr(status,pnonc,&fx,&qleft,&qhi); S210: if(!(*status == 1)) goto S220; cumtnc(t,df,pnonc,&cum,&ccum); fx = cum - *p; dinvr(status,pnonc,&fx,&qleft,&qhi); goto S210; S220: if(!(*status == -1)) goto S250; if(!qleft) goto S230; *status = 1; *bound = 0.0e0; goto S240; S230: *status = 2; *bound = tent4; S240: ; } S250: return; #undef tent4 #undef tol #undef atol #undef zero #undef one #undef inf } void cumbet(double *x,double *y,double *a,double *b,double *cum, double *ccum) /* ********************************************************************** void cumbet(double *x,double *y,double *a,double *b,double *cum, double *ccum) Double precision cUMulative incomplete BETa distribution Function Calculates the cdf to X of the incomplete beta distribution with parameters a and b. This is the integral from 0 to x of (1/B(a,b))*f(t)) where f(t) = t**(a-1) * (1-t)**(b-1) Arguments X --> Upper limit of integration. X is DOUBLE PRECISION Y --> 1 - X. Y is DOUBLE PRECISION A --> First parameter of the beta distribution. A is DOUBLE PRECISION B --> Second parameter of the beta distribution. B is DOUBLE PRECISION CUM <-- Cumulative incomplete beta distribution. CUM is DOUBLE PRECISION CCUM <-- Compliment of Cumulative incomplete beta distribution. CCUM is DOUBLE PRECISION Method Calls the routine BRATIO. References Didonato, Armido R. and Morris, Alfred H. Jr. (1992) Algorithim 708 Significant Digit Computation of the Incomplete Beta Function Ratios. ACM ToMS, Vol.18, No. 3, Sept. 1992, 360-373. ********************************************************************** */ { static int ierr; /* .. .. Executable Statements .. */ if(!(*x <= 0.0e0)) goto S10; *cum = 0.0e0; *ccum = 1.0e0; return; S10: if(!(*y <= 0.0e0)) goto S20; *cum = 1.0e0; *ccum = 0.0e0; return; S20: bratio(a,b,x,y,cum,ccum,&ierr); /* Call bratio routine */ return; } void cumbin(double *s,double *xn,double *pr,double *ompr, double *cum,double *ccum) /* ********************************************************************** void cumbin(double *s,double *xn,double *pr,double *ompr, double *cum,double *ccum) CUmulative BINomial distribution Function Returns the probability of 0 to S successes in XN binomial trials, each of which has a probability of success, PBIN. Arguments S --> The upper limit of cumulation of the binomial distribution. S is DOUBLE PRECISION XN --> The number of binomial trials. XN is DOUBLE PRECISIO PBIN --> The probability of success in each binomial trial. PBIN is DOUBLE PRECIS OMPR --> 1 - PBIN OMPR is DOUBLE PRECIS CUM <-- Cumulative binomial distribution. CUM is DOUBLE PRECISI CCUM <-- Compliment of Cumulative binomial distribution. CCUM is DOUBLE PRECIS Method Formula 26.5.24 of Abramowitz and Stegun, Handbook of Mathematical Functions (1966) is used to reduce the binomial distribution to the cumulative beta distribution. ********************************************************************** */ { static double T1,T2; /* .. .. Executable Statements .. */ if(!(*s < *xn)) goto S10; T1 = *s+1.0e0; T2 = *xn-*s; cumbet(pr,ompr,&T1,&T2,ccum,cum); goto S20; S10: *cum = 1.0e0; *ccum = 0.0e0; S20: return; } void cumchi(double *x,double *df,double *cum,double *ccum) /* ********************************************************************** void cumchi(double *x,double *df,double *cum,double *ccum) CUMulative of the CHi-square distribution Function Calculates the cumulative chi-square distribution. Arguments X --> Upper limit of integration of the chi-square distribution. X is DOUBLE PRECISION DF --> Degrees of freedom of the chi-square distribution. DF is DOUBLE PRECISION CUM <-- Cumulative chi-square distribution. CUM is DOUBLE PRECISIO CCUM <-- Compliment of Cumulative chi-square distribution. CCUM is DOUBLE PRECISI Method Calls incomplete gamma function (CUMGAM) ********************************************************************** */ { static double a,xx; /* .. .. Executable Statements .. */ a = *df*0.5e0; xx = *x*0.5e0; cumgam(&xx,&a,cum,ccum); return; } void cumchn(double *x,double *df,double *pnonc,double *cum, double *ccum) /********************************************************************** void cumchn(double *x,double *df,double *pnonc,double *cum, double *ccum) CUMulative of the Non-central CHi-square distribution Function Calculates the cumulative non-central chi-square distribution, i.e., the probability that a random variable which follows the non-central chi-square distribution, with non-centrality parameter PNONC and continuous degrees of freedom DF, is less than or equal to X. Arguments X --> Upper limit of integration of the non-central chi-square distribution. DF --> Degrees of freedom of the non-central chi-square distribution. PNONC --> Non-centrality parameter of the non-central chi-square distribution. CUM <-- Cumulative non-central chi-square distribution. CCUM <-- Compliment of Cumulative non-central chi-square distribut Method Uses formula 26.4.25 of Abramowitz and Stegun, Handbook of Mathematical Functions, US NBS (1966) to calculate the non-central chi-square. Variables EPS --- Convergence criterion. The sum stops when a term is less than EPS*SUM. CCUM <-- Compliment of Cumulative non-central chi-square distribution. **********************************************************************/ { #define dg(i) (*df + 2.0e0 * (double)(i)) #define qsmall(xx) (int)(sum < 1.0e-20 || (xx) < eps * sum) static double eps = 1.0e-5; static double adj,centaj,centwt,chid2,dfd2,lcntaj,lcntwt,lfact,pcent,pterm,sum, sumadj,term,wt,xnonc; static int i,icent; static double T1,T2,T3; /* .. .. Executable Statements .. */ if(!(*x <= 0.0e0)) goto S10; *cum = 0.0e0; *ccum = 1.0e0; return; S10: if(!(*pnonc <= 1.0e-10 )) goto S20; /* When non-centrality parameter is (essentially) zero, use cumulative chi-square distribution */ cumchi(x,df,cum,ccum); return; S20: xnonc = *pnonc / 2.0e0; /* *********************************************************************** The following code calcualtes the weight, chi-square, and adjustment term for the central term in the infinite series. The central term is the one in which the poisson weight is greatest. The adjustment term is the amount that must be subtracted from the chi-square to move up two degrees of freedom. *********************************************************************** */ icent = fifidint(xnonc); if(icent == 0) icent = 1; chid2 = *x / 2.0e0; /* Calculate central weight term */ T1 = (double)(icent + 1); lfact = alngam(&T1); lcntwt = -xnonc + (double)icent * log(xnonc) - lfact; centwt = exp(lcntwt); /* Calculate central chi-square */ T2 = dg(icent); cumchi(x,&T2,&pcent,ccum); /* Calculate central adjustment term */ dfd2 = dg(icent) / 2.0e0; T3 = 1.0e0 + dfd2; lfact = alngam(&T3); lcntaj = dfd2 * log(chid2) - chid2 - lfact; centaj = exp(lcntaj); sum = centwt * pcent; /* *********************************************************************** Sum backwards from the central term towards zero. Quit whenever either (1) the zero term is reached, or (2) the term gets small relative to the sum *********************************************************************** */ sumadj = 0.0e0; adj = centaj; wt = centwt; i = icent; goto S40; S30: if(qsmall(term) || i == 0) goto S50; S40: dfd2 = dg(i) / 2.0e0; /* Adjust chi-square for two fewer degrees of freedom. The adjusted value ends up in PTERM. */ adj = adj * dfd2 / chid2; sumadj += adj; pterm = pcent + sumadj; /* Adjust poisson weight for J decreased by one */ wt *= ((double)i / xnonc); term = wt * pterm; sum += term; i -= 1; goto S30; S50: /* *********************************************************************** Now sum forward from the central term towards infinity. Quit when either (1) the term gets small relative to the sum, or *********************************************************************** */ sumadj = adj = centaj; wt = centwt; i = icent; goto S70; S60: if(qsmall(term)) goto S80; S70: /* Update weights for next higher J */ wt *= (xnonc / (double)(i + 1)); /* Calculate PTERM and add term to sum */ pterm = pcent - sumadj; term = wt * pterm; sum += term; /* Update adjustment term for DF for next iteration */ i += 1; dfd2 = dg(i) / 2.0e0; adj = adj * chid2 / dfd2; sumadj += adj; goto S60; S80: *cum = sum; *ccum = 0.5e0 + (0.5e0 - *cum); return; #undef dg #undef qsmall } void cumf(double *f,double *dfn,double *dfd,double *cum,double *ccum) /* ********************************************************************** void cumf(double *f,double *dfn,double *dfd,double *cum,double *ccum) CUMulative F distribution Function Computes the integral from 0 to F of the f-density with DFN and DFD degrees of freedom. Arguments F --> Upper limit of integration of the f-density. F is DOUBLE PRECISION DFN --> Degrees of freedom of the numerator sum of squares. DFN is DOUBLE PRECISI DFD --> Degrees of freedom of the denominator sum of squares. DFD is DOUBLE PRECISI CUM <-- Cumulative f distribution. CUM is DOUBLE PRECISI CCUM <-- Compliment of Cumulative f distribution. CCUM is DOUBLE PRECIS Method Formula 26.5.28 of Abramowitz and Stegun is used to reduce the cumulative F to a cumulative beta distribution. Note If F is less than or equal to 0, 0 is returned. ********************************************************************** */ { #define half 0.5e0 #define done 1.0e0 static double dsum,prod,xx,yy; static int ierr; static double T1,T2; /* .. .. Executable Statements .. */ if(!(*f <= 0.0e0)) goto S10; *cum = 0.0e0; *ccum = 1.0e0; return; S10: prod = *dfn**f; /* XX is such that the incomplete beta with parameters DFD/2 and DFN/2 evaluated at XX is 1 - CUM or CCUM YY is 1 - XX Calculate the smaller of XX and YY accurately */ dsum = *dfd+prod; xx = *dfd/dsum; if(xx > half) { yy = prod/dsum; xx = done-yy; } else yy = done-xx; T1 = *dfd*half; T2 = *dfn*half; bratio(&T1,&T2,&xx,&yy,ccum,cum,&ierr); return; #undef half #undef done } void cumfnc(double *f,double *dfn,double *dfd,double *pnonc, double *cum,double *ccum) /* ********************************************************************** F -NON- -C-ENTRAL F DISTRIBUTION Function COMPUTES NONCENTRAL F DISTRIBUTION WITH DFN AND DFD DEGREES OF FREEDOM AND NONCENTRALITY PARAMETER PNONC Arguments X --> UPPER LIMIT OF INTEGRATION OF NONCENTRAL F IN EQUATION DFN --> DEGREES OF FREEDOM OF NUMERATOR DFD --> DEGREES OF FREEDOM OF DENOMINATOR PNONC --> NONCENTRALITY PARAMETER. CUM <-- CUMULATIVE NONCENTRAL F DISTRIBUTION CCUM <-- COMPLIMENT OF CUMMULATIVE Method USES FORMULA 26.6.20 OF REFERENCE FOR INFINITE SERIES. SERIES IS CALCULATED BACKWARD AND FORWARD FROM J = LAMBDA/2 (THIS IS THE TERM WITH THE LARGEST POISSON WEIGHT) UNTIL THE CONVERGENCE CRITERION IS MET. FOR SPEED, THE INCOMPLETE BETA FUNCTIONS ARE EVALUATED BY FORMULA 26.5.16. REFERENCE HANDBOOD OF MATHEMATICAL FUNCTIONS EDITED BY MILTON ABRAMOWITZ AND IRENE A. STEGUN NATIONAL BUREAU OF STANDARDS APPLIED MATEMATICS SERIES - 55 MARCH 1965 P 947, EQUATIONS 26.6.17, 26.6.18 Note THE SUM CONTINUES UNTIL A SUCCEEDING TERM IS LESS THAN EPS TIMES THE SUM (OR THE SUM IS LESS THAN 1.0E-20). EPS IS SET TO 1.0E-4 IN A DATA STATEMENT WHICH CAN BE CHANGED. ********************************************************************** */ { #define qsmall(x) (int)(sum < 1.0e-20 || (x) < eps*sum) #define half 0.5e0 #define done 1.0e0 static double eps = 1.0e-4; static double dsum,dummy,prod,xx,yy,adn,aup,b,betdn,betup,centwt,dnterm,sum, upterm,xmult,xnonc; static int i,icent,ierr; static double T1,T2,T3,T4,T5,T6; /* .. .. Executable Statements .. */ if(!(*f <= 0.0e0)) goto S10; *cum = 0.0e0; *ccum = 1.0e0; return; S10: if(!(*pnonc < 1.0e-10)) goto S20; /* Handle case in which the non-centrality parameter is (essentially) zero. */ cumf(f,dfn,dfd,cum,ccum); return; S20: xnonc = *pnonc/2.0e0; /* Calculate the central term of the poisson weighting factor. */ icent = (long)(xnonc); if(icent == 0) icent = 1; /* Compute central weight term */ T1 = (double)(icent+1); centwt = exp(-xnonc+(double)icent*log(xnonc)-alngam(&T1)); /* Compute central incomplete beta term Assure that minimum of arg to beta and 1 - arg is computed accurately. */ prod = *dfn**f; dsum = *dfd+prod; yy = *dfd/dsum; if(yy > half) { xx = prod/dsum; yy = done-xx; } else xx = done-yy; T2 = *dfn*half+(double)icent; T3 = *dfd*half; bratio(&T2,&T3,&xx,&yy,&betdn,&dummy,&ierr); adn = *dfn/2.0e0+(double)icent; aup = adn; b = *dfd/2.0e0; betup = betdn; sum = centwt*betdn; /* Now sum terms backward from icent until convergence or all done */ xmult = centwt; i = icent; T4 = adn+b; T5 = adn+1.0e0; dnterm = exp(alngam(&T4)-alngam(&T5)-alngam(&b)+adn*log(xx)+b*log(yy)); S30: if(qsmall(xmult*betdn) || i <= 0) goto S40; xmult *= ((double)i/xnonc); i -= 1; adn -= 1.0; dnterm = (adn+1.0)/((adn+b)*xx)*dnterm; betdn += dnterm; sum += (xmult*betdn); goto S30; S40: i = icent+1; /* Now sum forwards until convergence */ xmult = centwt; if(aup-1.0+b == 0) upterm = exp(-alngam(&aup)-alngam(&b)+(aup-1.0)*log(xx)+ b*log(yy)); else { T6 = aup-1.0+b; upterm = exp(alngam(&T6)-alngam(&aup)-alngam(&b)+(aup-1.0)*log(xx)+b* log(yy)); } goto S60; S50: if(qsmall(xmult*betup)) goto S70; S60: xmult *= (xnonc/(double)i); i += 1; aup += 1.0; upterm = (aup+b-2.0e0)*xx/(aup-1.0)*upterm; betup -= upterm; sum += (xmult*betup); goto S50; S70: *cum = sum; *ccum = 0.5e0+(0.5e0-*cum); return; #undef qsmall #undef half #undef done } void cumgam(double *x,double *a,double *cum,double *ccum) /* ********************************************************************** void cumgam(double *x,double *a,double *cum,double *ccum) Double precision cUMulative incomplete GAMma distribution Function Computes the cumulative of the incomplete gamma distribution, i.e., the integral from 0 to X of (1/GAM(A))*EXP(-T)*T**(A-1) DT where GAM(A) is the complete gamma function of A, i.e., GAM(A) = integral from 0 to infinity of EXP(-T)*T**(A-1) DT Arguments X --> The upper limit of integration of the incomplete gamma. X is DOUBLE PRECISION A --> The shape parameter of the incomplete gamma. A is DOUBLE PRECISION CUM <-- Cumulative incomplete gamma distribution. CUM is DOUBLE PRECISION CCUM <-- Compliment of Cumulative incomplete gamma distribution. CCUM is DOUBLE PRECISIO Method Calls the routine GRATIO. ********************************************************************** */ { static int K1 = 0; /* .. .. Executable Statements .. */ if(!(*x <= 0.0e0)) goto S10; *cum = 0.0e0; *ccum = 1.0e0; return; S10: gratio(a,x,cum,ccum,&K1); /* Call gratio routine */ return; } void cumnbn(double *s,double *xn,double *pr,double *ompr, double *cum,double *ccum) /* ********************************************************************** void cumnbn(double *s,double *xn,double *pr,double *ompr, double *cum,double *ccum) CUmulative Negative BINomial distribution Function Returns the probability that it there will be S or fewer failures before there are XN successes, with each binomial trial having a probability of success PR. Prob(# failures = S | XN successes, PR) = ( XN + S - 1 ) ( ) * PR^XN * (1-PR)^S ( S ) Arguments S --> The number of failures S is DOUBLE PRECISION XN --> The number of successes XN is DOUBLE PRECISIO PR --> The probability of success in each binomial trial. PR is DOUBLE PRECISIO OMPR --> 1 - PR OMPR is DOUBLE PRECIS CUM <-- Cumulative negative binomial distribution. CUM is DOUBLE PRECISI CCUM <-- Compliment of Cumulative negative binomial distribution. CCUM is DOUBLE PRECIS Method Formula 26.5.26 of Abramowitz and Stegun, Handbook of Mathematical Functions (1966) is used to reduce the negative binomial distribution to the cumulative beta distribution. ********************************************************************** */ { static double T1; /* .. .. Executable Statements .. */ T1 = *s+1.e0; cumbet(pr,ompr,xn,&T1,cum,ccum); return; } void cumnor(double *arg,double *result,double *ccum) /* ********************************************************************** void cumnor(double *arg,double *result,double *ccum) Function Computes the cumulative of the normal distribution, i.e., the integral from -infinity to x of (1/sqrt(2*pi)) exp(-u*u/2) du X --> Upper limit of integration. X is DOUBLE PRECISION RESULT <-- Cumulative normal distribution. RESULT is DOUBLE PRECISION CCUM <-- Compliment of Cumulative normal distribution. CCUM is DOUBLE PRECISION Renaming of function ANORM from: Cody, W.D. (1993). "ALGORITHM 715: SPECFUN - A Portabel FORTRAN Package of Special Function Routines and Test Drivers" acm Transactions on Mathematical Software. 19, 22-32. with slight modifications to return ccum and to deal with machine constants. ********************************************************************** Original Comments: ------------------------------------------------------------------ This function evaluates the normal distribution function: / x 1 | -t*t/2 P(x) = ----------- | e dt sqrt(2 pi) | /-oo The main computation evaluates near-minimax approximations derived from those in "Rational Chebyshev approximations for the error function" by W. J. Cody, Math. Comp., 1969, 631-637. This transportable program uses rational functions that theoretically approximate the normal distribution function to at least 18 significant decimal digits. The accuracy achieved depends on the arithmetic system, the compiler, the intrinsic functions, and proper selection of the machine-dependent constants. ******************************************************************* ******************************************************************* Explanation of machine-dependent constants. MIN = smallest machine representable number. EPS = argument below which anorm(x) may be represented by 0.5 and above which x*x will not underflow. A conservative value is the largest machine number X such that 1.0 + X = 1.0 to machine precision. ******************************************************************* ******************************************************************* Error returns The program returns ANORM = 0 for ARG .LE. XLOW. Intrinsic functions required are: ABS, AINT, EXP Author: W. J. Cody Mathematics and Computer Science Division Argonne National Laboratory Argonne, IL 60439 Latest modification: March 15, 1992 ------------------------------------------------------------------ */ { static double a[5] = { 2.2352520354606839287e00,1.6102823106855587881e02,1.0676894854603709582e03, 1.8154981253343561249e04,6.5682337918207449113e-2 }; static double b[4] = { 4.7202581904688241870e01,9.7609855173777669322e02,1.0260932208618978205e04, 4.5507789335026729956e04 }; static double c[9] = { 3.9894151208813466764e-1,8.8831497943883759412e00,9.3506656132177855979e01, 5.9727027639480026226e02,2.4945375852903726711e03,6.8481904505362823326e03, 1.1602651437647350124e04,9.8427148383839780218e03,1.0765576773720192317e-8 }; static double d[8] = { 2.2266688044328115691e01,2.3538790178262499861e02,1.5193775994075548050e03, 6.4855582982667607550e03,1.8615571640885098091e04,3.4900952721145977266e04, 3.8912003286093271411e04,1.9685429676859990727e04 }; static double half = 0.5e0; static double p[6] = { 2.1589853405795699e-1,1.274011611602473639e-1,2.2235277870649807e-2, 1.421619193227893466e-3,2.9112874951168792e-5,2.307344176494017303e-2 }; static double one = 1.0e0; static double q[5] = { 1.28426009614491121e00,4.68238212480865118e-1,6.59881378689285515e-2, 3.78239633202758244e-3,7.29751555083966205e-5 }; static double sixten = 1.60e0; static double sqrpi = 3.9894228040143267794e-1; static double thrsh = 0.66291e0; static double root32 = 5.656854248e0; static double zero = 0.0e0; static int K1 = 1; static int K2 = 2; static int i; static double del,eps,temp,x,xden,xnum,y,xsq,min; /* ------------------------------------------------------------------ Machine dependent constants ------------------------------------------------------------------ */ eps = spmpar(&K1)*0.5e0; min = spmpar(&K2); x = *arg; y = fabs(x); if(y <= thrsh) { /* ------------------------------------------------------------------ Evaluate anorm for |X| <= 0.66291 ------------------------------------------------------------------ */ xsq = zero; if(y > eps) xsq = x*x; xnum = a[4]*xsq; xden = xsq; for(i=0; i<3; i++) { xnum = (xnum+a[i])*xsq; xden = (xden+b[i])*xsq; } *result = x*(xnum+a[3])/(xden+b[3]); temp = *result; *result = half+temp; *ccum = half-temp; } /* ------------------------------------------------------------------ Evaluate anorm for 0.66291 <= |X| <= sqrt(32) ------------------------------------------------------------------ */ else if(y <= root32) { xnum = c[8]*y; xden = y; for(i=0; i<7; i++) { xnum = (xnum+c[i])*y; xden = (xden+d[i])*y; } *result = (xnum+c[7])/(xden+d[7]); xsq = fifdint(y*sixten)/sixten; del = (y-xsq)*(y+xsq); *result = exp(-(xsq*xsq*half))*exp(-(del*half))**result; *ccum = one-*result; if(x > zero) { temp = *result; *result = *ccum; *ccum = temp; } } /* ------------------------------------------------------------------ Evaluate anorm for |X| > sqrt(32) ------------------------------------------------------------------ */ else { *result = zero; xsq = one/(x*x); xnum = p[5]*xsq; xden = xsq; for(i=0; i<4; i++) { xnum = (xnum+p[i])*xsq; xden = (xden+q[i])*xsq; } *result = xsq*(xnum+p[4])/(xden+q[4]); *result = (sqrpi-*result)/y; xsq = fifdint(x*sixten)/sixten; del = (x-xsq)*(x+xsq); *result = exp(-(xsq*xsq*half))*exp(-(del*half))**result; *ccum = one-*result; if(x > zero) { temp = *result; *result = *ccum; *ccum = temp; } } if(*result < min) *result = 0.0e0; /* ------------------------------------------------------------------ Fix up for negative argument, erf, etc. ------------------------------------------------------------------ ----------Last card of ANORM ---------- */ if(*ccum < min) *ccum = 0.0e0; } void cumpoi(double *s,double *xlam,double *cum,double *ccum) /* ********************************************************************** void cumpoi(double *s,double *xlam,double *cum,double *ccum) CUMulative POIsson distribution Function Returns the probability of S or fewer events in a Poisson distribution with mean XLAM. Arguments S --> Upper limit of cumulation of the Poisson. S is DOUBLE PRECISION XLAM --> Mean of the Poisson distribution. XLAM is DOUBLE PRECIS CUM <-- Cumulative poisson distribution. CUM is DOUBLE PRECISION CCUM <-- Compliment of Cumulative poisson distribution. CCUM is DOUBLE PRECIS Method Uses formula 26.4.21 of Abramowitz and Stegun, Handbook of Mathematical Functions to reduce the cumulative Poisson to the cumulative chi-square distribution. ********************************************************************** */ { static double chi,df; /* .. .. Executable Statements .. */ df = 2.0e0*(*s+1.0e0); chi = 2.0e0**xlam; cumchi(&chi,&df,ccum,cum); return; } void cumt(double *t,double *df,double *cum,double *ccum) /* ********************************************************************** void cumt(double *t,double *df,double *cum,double *ccum) CUMulative T-distribution Function Computes the integral from -infinity to T of the t-density. Arguments T --> Upper limit of integration of the t-density. T is DOUBLE PRECISION DF --> Degrees of freedom of the t-distribution. DF is DOUBLE PRECISIO CUM <-- Cumulative t-distribution. CCUM is DOUBLE PRECIS CCUM <-- Compliment of Cumulative t-distribution. CCUM is DOUBLE PRECIS Method Formula 26.5.27 of Abramowitz and Stegun, Handbook of Mathematical Functions is used to reduce the t-distribution to an incomplete beta. ********************************************************************** */ { static double K2 = 0.5e0; static double xx,a,oma,tt,yy,dfptt,T1; /* .. .. Executable Statements .. */ tt = *t**t; dfptt = *df+tt; xx = *df/dfptt; yy = tt/dfptt; T1 = 0.5e0**df; cumbet(&xx,&yy,&T1,&K2,&a,&oma); if(!(*t <= 0.0e0)) goto S10; *cum = 0.5e0*a; *ccum = oma+*cum; goto S20; S10: *ccum = 0.5e0*a; *cum = oma+*ccum; S20: return; } void cumtnc(double *t,double *df,double *pnonc,double *cum, double *ccum) /********************************************************************** void cumtnc(double *t,double *df,double *pnonc,double *cum, double *ccum) CUMulative Non-Central T-distribution Function Computes the integral from -infinity to T of the non-central t-density. Arguments T --> Upper limit of integration of the non-central t-density. DF --> Degrees of freedom of the non-central t-distribution. PNONC --> Non-centrality parameter of the non-central t distibutio CUM <-- Cumulative t-distribution. CCUM <-- Compliment of Cumulative t-distribution. Method Upper tail of the cumulative noncentral t using formulae from page 532 of Johnson, Kotz, Balakrishnan, Coninuous Univariate Distributions, Vol 2, 2nd Edition. Wiley (1995) This implementation starts the calculation at i = lambda, which is near the largest Di. It then sums forward and backward. **********************************************************************/ { #define one 1.0e0 #define zero 0.0e0 #define half 0.5e0 #define two 2.0e0 #define onep5 1.5e0 #define conv 1.0e-7 #define tiny 1.0e-10 static double alghdf,b,bb,bbcent,bcent,cent,d,dcent,dpnonc,dum1,dum2,e,ecent, halfdf,lambda,lnomx,lnx,omx,pnonc2,s,scent,ss,sscent,t2,term,tt,twoi,x,xi, xlnd,xlne; static int ierr; static unsigned long qrevs; static double T1,T2,T3,T4,T5,T6,T7,T8,T9,T10; /* .. .. Executable Statements .. */ /* Case pnonc essentially zero */ if(fabs(*pnonc) <= tiny) { cumt(t,df,cum,ccum); return; } qrevs = *t < zero; if(qrevs) { tt = -*t; dpnonc = -*pnonc; } else { tt = *t; dpnonc = *pnonc; } pnonc2 = dpnonc * dpnonc; t2 = tt * tt; if(fabs(tt) <= tiny) { T1 = -*pnonc; cumnor(&T1,cum,ccum); return; } lambda = half * pnonc2; x = *df / (*df + t2); omx = one - x; lnx = log(x); lnomx = log(omx); halfdf = half * *df; alghdf = gamln(&halfdf); /* ******************** Case i = lambda */ cent = fifidint(lambda); if(cent < one) cent = one; /* Compute d=T(2i) in log space and offset by exp(-lambda) */ T2 = cent + one; xlnd = cent * log(lambda) - gamln(&T2) - lambda; dcent = exp(xlnd); /* Compute e=t(2i+1) in log space offset by exp(-lambda) */ T3 = cent + onep5; xlne = (cent + half) * log(lambda) - gamln(&T3) - lambda; ecent = exp(xlne); if(dpnonc < zero) ecent = -ecent; /* Compute bcent=B(2*cent) */ T4 = cent + half; bratio(&halfdf,&T4,&x,&omx,&bcent,&dum1,&ierr); /* compute bbcent=B(2*cent+1) */ T5 = cent + one; bratio(&halfdf,&T5,&x,&omx,&bbcent,&dum2,&ierr); /* Case bcent and bbcent are essentially zero Thus t is effectively infinite */ if(bcent + bbcent < tiny) { if(qrevs) { *cum = zero; *ccum = one; } else { *cum = one; *ccum = zero; } return; } /* Case bcent and bbcent are essentially one Thus t is effectively zero */ if(dum1 + dum2 < tiny) { T6 = -*pnonc; cumnor(&T6,cum,ccum); return; } /* First term in ccum is D*B + E*BB */ *ccum = dcent * bcent + ecent * bbcent; /* compute s(cent) = B(2*(cent+1)) - B(2*cent)) */ T7 = halfdf + cent + half; T8 = cent + onep5; scent = gamln(&T7) - gamln(&T8) - alghdf + halfdf * lnx + (cent + half) * lnomx; scent = exp(scent); /* compute ss(cent) = B(2*cent+3) - B(2*cent+1) */ T9 = halfdf + cent + one; T10 = cent + two; sscent = gamln(&T9) - gamln(&T10) - alghdf + halfdf * lnx + (cent + one) * lnomx; sscent = exp(sscent); /* ******************** Sum Forward */ xi = cent + one; twoi = two * xi; d = dcent; e = ecent; b = bcent; bb = bbcent; s = scent; ss = sscent; S10: b += s; bb += ss; d = lambda / xi * d; e = lambda / (xi + half) * e; term = d * b + e * bb; *ccum += term; s = s * omx * (*df + twoi - one) / (twoi + one); ss = ss * omx * (*df + twoi) / (twoi + two); xi += one; twoi = two * xi; if(fabs(term) > conv * *ccum) goto S10; /* ******************** Sum Backward */ xi = cent; twoi = two * xi; d = dcent; e = ecent; b = bcent; bb = bbcent; s = scent * (one + twoi) / ((*df + twoi - one) * omx); ss = sscent * (two + twoi) / ((*df + twoi) * omx); S20: b -= s; bb -= ss; d *= (xi / lambda); e *= ((xi + half) / lambda); term = d * b + e * bb; *ccum += term; xi -= one; if(xi < half) goto S30; twoi = two * xi; s = s * (one + twoi) / ((*df + twoi - one) * omx); ss = ss * (two + twoi) / ((*df + twoi) * omx); if(fabs(term) > conv * *ccum) goto S20; S30: if(qrevs) { *cum = half * *ccum; *ccum = one - *cum; } else { *ccum = half * *ccum; *cum = one - *ccum; } /* Due to roundoff error the answer may not lie between zero and one Force it to do so */ *cum = fifdmax1(fifdmin1(*cum,one),zero); *ccum = fifdmax1(fifdmin1(*ccum,one),zero); return; #undef one #undef zero #undef half #undef two #undef onep5 #undef conv #undef tiny } double devlpl(double a[],int *n,double *x) /* ********************************************************************** double devlpl(double a[],int *n,double *x) Double precision EVALuate a PoLynomial at X Function returns A(1) + A(2)*X + ... + A(N)*X**(N-1) Arguments A --> Array of coefficients of the polynomial. A is DOUBLE PRECISION(N) N --> Length of A, also degree of polynomial - 1. N is INTEGER X --> Point at which the polynomial is to be evaluated. X is DOUBLE PRECISION ********************************************************************** */ { static double devlpl,term; static int i; /* .. .. Executable Statements .. */ term = a[*n-1]; for(i= *n-1-1; i>=0; i--) term = a[i]+term**x; devlpl = term; return devlpl; } double dinvnr(double *p,double *q) /* ********************************************************************** double dinvnr(double *p,double *q) Double precision NoRmal distribution INVerse Function Returns X such that CUMNOR(X) = P, i.e., the integral from - infinity to X of (1/SQRT(2*PI)) EXP(-U*U/2) dU is P Arguments P --> The probability whose normal deviate is sought. P is DOUBLE PRECISION Q --> 1-P P is DOUBLE PRECISION Method The rational function on page 95 of Kennedy and Gentle, Statistical Computing, Marcel Dekker, NY , 1980 is used as a start value for the Newton method of finding roots. Note If P or Q .lt. machine EPS returns +/- DINVNR(EPS) ********************************************************************** */ { #define maxit 100 #define eps 1.0e-13 #define r2pi 0.3989422804014326e0 #define nhalf -0.5e0 #define dennor(x) (r2pi*exp(nhalf*(x)*(x))) static double dinvnr,strtx,xcur,cum,ccum,pp,dx; static int i; static unsigned long qporq; /* .. .. Executable Statements .. */ /* FIND MINIMUM OF P AND Q */ qporq = *p <= *q; if(!qporq) goto S10; pp = *p; goto S20; S10: pp = *q; S20: /* INITIALIZATION STEP */ strtx = stvaln(&pp); xcur = strtx; /* NEWTON INTERATIONS */ for(i=1; i<=maxit; i++) { cumnor(&xcur,&cum,&ccum); dx = (cum-pp)/dennor(xcur); xcur -= dx; if(fabs(dx/xcur) < eps) goto S40; } dinvnr = strtx; /* IF WE GET HERE, NEWTON HAS FAILED */ if(!qporq) dinvnr = -dinvnr; return dinvnr; S40: /* IF WE GET HERE, NEWTON HAS SUCCEDED */ dinvnr = xcur; if(!qporq) dinvnr = -dinvnr; return dinvnr; #undef maxit #undef eps #undef r2pi #undef nhalf #undef dennor } /* DEFINE DINVR */ /*static*/ void E0000(int IENTRY,int *status,double *x,double *fx, unsigned long *qleft,unsigned long *qhi,double *zabsst, double *zabsto,double *zbig,double *zrelst, double *zrelto,double *zsmall,double *zstpmu) { #define qxmon(zx,zy,zz) (int)((zx) <= (zy) && (zy) <= (zz)) static double absstp,abstol,big,fbig,fsmall,relstp,reltol,small,step,stpmul,xhi, xlb,xlo,xsave,xub,yy; static int i99999; static unsigned long qbdd,qcond,qdum1,qdum2,qincr,qlim,qok,qup; switch(IENTRY){case 0: goto DINVR; case 1: goto DSTINV;} DINVR: if(*status > 0) goto S310; qcond = !qxmon(small,*x,big); if(qcond) ftnstop(" SMALL, X, BIG not monotone in INVR"); xsave = *x; /* See that SMALL and BIG bound the zero and set QINCR */ *x = small; /* GET-FUNCTION-VALUE */ i99999 = 1; goto S300; S10: fsmall = *fx; *x = big; /* GET-FUNCTION-VALUE */ i99999 = 2; goto S300; S20: fbig = *fx; qincr = fbig > fsmall; if(!qincr) goto S50; if(fsmall <= 0.0e0) goto S30; *status = -1; *qleft = *qhi = 1; return; S30: if(fbig >= 0.0e0) goto S40; *status = -1; *qleft = *qhi = 0; return; S40: goto S80; S50: if(fsmall >= 0.0e0) goto S60; *status = -1; *qleft = 1; *qhi = 0; return; S60: if(fbig <= 0.0e0) goto S70; *status = -1; *qleft = 0; *qhi = 1; return; S80: S70: *x = xsave; step = fifdmax1(absstp,relstp*fabs(*x)); /* YY = F(X) - Y GET-FUNCTION-VALUE */ i99999 = 3; goto S300; S90: yy = *fx; if(!(yy == 0.0e0)) goto S100; *status = 0; qok = 1; return; S100: qup = (qincr && (yy < 0.0e0)) || (!qincr && (yy > 0.0e0)); /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ HANDLE CASE IN WHICH WE MUST STEP HIGHER ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ if(!qup) goto S170; xlb = xsave; xub = fifdmin1(xlb+step,big); goto S120; S110: if(qcond) goto S150; S120: /* YY = F(XUB) - Y */ *x = xub; /* GET-FUNCTION-VALUE */ i99999 = 4; goto S300; S130: yy = *fx; qbdd = (qincr && (yy >= 0.0e0)) || (!qincr && (yy <= 0.0e0)); qlim = xub >= big; qcond = qbdd || qlim; if(qcond) goto S140; step = stpmul*step; xlb = xub; xub = fifdmin1(xlb+step,big); S140: goto S110; S150: if(!(qlim && !qbdd)) goto S160; *status = -1; *qleft = 0; *qhi = !qincr; *x = big; return; S160: goto S240; S170: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ HANDLE CASE IN WHICH WE MUST STEP LOWER ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ xub = xsave; xlb = fifdmax1(xub-step,small); goto S190; S180: if(qcond) goto S220; S190: /* YY = F(XLB) - Y */ *x = xlb; /* GET-FUNCTION-VALUE */ i99999 = 5; goto S300; S200: yy = *fx; qbdd = (qincr && (yy <= 0.0e0)) || (!qincr && (yy >= 0.0e0)); qlim = xlb <= small; qcond = qbdd || qlim; if(qcond) goto S210; step = stpmul*step; xub = xlb; xlb = fifdmax1(xub-step,small); S210: goto S180; S220: if(!(qlim && !qbdd)) goto S230; *status = -1; *qleft = 1; *qhi = qincr; *x = small; return; S240: S230: dstzr(&xlb,&xub,&abstol,&reltol); /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ IF WE REACH HERE, XLB AND XUB BOUND THE ZERO OF F. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ *status = 0; goto S260; S250: if(!(*status == 1)) goto S290; S260: dzror(status,x,fx,&xlo,&xhi,&qdum1,&qdum2); if(!(*status == 1)) goto S280; /* GET-FUNCTION-VALUE */ i99999 = 6; goto S300; S280: S270: goto S250; S290: *x = xlo; *status = 0; return; DSTINV: small = *zsmall; big = *zbig; absstp = *zabsst; relstp = *zrelst; stpmul = *zstpmu; abstol = *zabsto; reltol = *zrelto; return; S300: /* TO GET-FUNCTION-VALUE */ *status = 1; return; S310: switch((int)i99999){case 1: goto S10;case 2: goto S20;case 3: goto S90;case 4: goto S130;case 5: goto S200;case 6: goto S270;default: break;} #undef qxmon } void dinvr(int *status,double *x,double *fx, unsigned long *qleft,unsigned long *qhi) /* ********************************************************************** void dinvr(int *status,double *x,double *fx, unsigned long *qleft,unsigned long *qhi) Double precision bounds the zero of the function and invokes zror Reverse Communication Function Bounds the function and invokes ZROR to perform the zero finding. STINVR must have been called before this routine in order to set its parameters. Arguments STATUS <--> At the beginning of a zero finding problem, STATUS should be set to 0 and INVR invoked. (The value of parameters other than X will be ignored on this cal When INVR needs the function evaluated, it will set STATUS to 1 and return. The value of the function should be set in FX and INVR again called without changing any of its other parameters. When INVR has finished without error, it will return with STATUS 0. In that case X is approximately a root of F(X). If INVR cannot bound the function, it returns status -1 and sets QLEFT and QHI. INTEGER STATUS X <-- The value of X at which F(X) is to be evaluated. DOUBLE PRECISION X FX --> The value of F(X) calculated when INVR returns with STATUS = 1. DOUBLE PRECISION FX QLEFT <-- Defined only if QMFINV returns .FALSE. In that case it is .TRUE. If the stepping search terminated unsucessfully at SMALL. If it is .FALSE. the search terminated unsucessfully at BIG. QLEFT is LOGICAL QHI <-- Defined only if QMFINV returns .FALSE. In that case it is .TRUE. if F(X) .GT. Y at the termination of the search and .FALSE. if F(X) .LT. Y at the termination of the search. QHI is LOGICAL ********************************************************************** */ { E0000(0,status,x,fx,qleft,qhi,NULL,NULL,NULL,NULL,NULL,NULL,NULL); } void dstinv(double *zsmall,double *zbig,double *zabsst, double *zrelst,double *zstpmu,double *zabsto, double *zrelto) /* ********************************************************************** void dstinv(double *zsmall,double *zbig,double *zabsst, double *zrelst,double *zstpmu,double *zabsto, double *zrelto) Double Precision - SeT INverse finder - Reverse Communication Function Concise Description - Given a monotone function F finds X such that F(X) = Y. Uses Reverse communication -- see invr. This routine sets quantities needed by INVR. More Precise Description of INVR - F must be a monotone function, the results of QMFINV are otherwise undefined. QINCR must be .TRUE. if F is non- decreasing and .FALSE. if F is non-increasing. QMFINV will return .TRUE. if and only if F(SMALL) and F(BIG) bracket Y, i. e., QINCR is .TRUE. and F(SMALL).LE.Y.LE.F(BIG) or QINCR is .FALSE. and F(BIG).LE.Y.LE.F(SMALL) if QMFINV returns .TRUE., then the X returned satisfies the following condition. let TOL(X) = MAX(ABSTOL,RELTOL*ABS(X)) then if QINCR is .TRUE., F(X-TOL(X)) .LE. Y .LE. F(X+TOL(X)) and if QINCR is .FALSE. F(X-TOL(X)) .GE. Y .GE. F(X+TOL(X)) Arguments SMALL --> The left endpoint of the interval to be searched for a solution. SMALL is DOUBLE PRECISION BIG --> The right endpoint of the interval to be searched for a solution. BIG is DOUBLE PRECISION ABSSTP, RELSTP --> The initial step size in the search is MAX(ABSSTP,RELSTP*ABS(X)). See algorithm. ABSSTP is DOUBLE PRECISION RELSTP is DOUBLE PRECISION STPMUL --> When a step doesn't bound the zero, the step size is multiplied by STPMUL and another step taken. A popular value is 2.0 DOUBLE PRECISION STPMUL ABSTOL, RELTOL --> Two numbers that determine the accuracy of the solution. See function for a precise definition. ABSTOL is DOUBLE PRECISION RELTOL is DOUBLE PRECISION Method Compares F(X) with Y for the input value of X then uses QINCR to determine whether to step left or right to bound the desired x. the initial step size is MAX(ABSSTP,RELSTP*ABS(S)) for the input value of X. Iteratively steps right or left until it bounds X. At each step which doesn't bound X, the step size is doubled. The routine is careful never to step beyond SMALL or BIG. If it hasn't bounded X at SMALL or BIG, QMFINV returns .FALSE. after setting QLEFT and QHI. If X is successfully bounded then Algorithm R of the paper 'Two Efficient Algorithms with Guaranteed Convergence for Finding a Zero of a Function' by J. C. P. Bus and T. J. Dekker in ACM Transactions on Mathematical Software, Volume 1, No. 4 page 330 (DEC. '75) is employed to find the zero of the function F(X)-Y. This is routine QRZERO. ********************************************************************** */ { E0000(1,NULL,NULL,NULL,NULL,NULL,zabsst,zabsto,zbig,zrelst,zrelto,zsmall, zstpmu); } double dt1(double *p,double *q,double *df) /* ********************************************************************** double dt1(double *p,double *q,double *df) Double precision Initalize Approximation to INVerse of the cumulative T distribution Function Returns the inverse of the T distribution function, i.e., the integral from 0 to INVT of the T density is P. This is an initial approximation Arguments P --> The p-value whose inverse from the T distribution is desired. P is DOUBLE PRECISION Q --> 1-P. Q is DOUBLE PRECISION DF --> Degrees of freedom of the T distribution. DF is DOUBLE PRECISION ********************************************************************** */ { static double coef[4][5] = { {1.0e0,1.0e0,0.0e0,0.0e0,0.0e0}, {3.0e0,16.0e0,5.0e0,0.0e0,0.0e0}, {-15.0e0,17.0e0,19.0e0,3.0e0,0.0e0}, {-945.0e0,-1920.0e0,1482.0e0,776.0e0,79.0e0} }; static double denom[4] = { 4.0e0,96.0e0,384.0e0,92160.0e0 }; static int ideg[4] = { 2,3,4,5 }; static double dt1,denpow,sum,term,x,xp,xx; static int i; /* .. .. Executable Statements .. */ x = fabs(dinvnr(p,q)); xx = x*x; sum = x; denpow = 1.0e0; for(i=0; i<4; i++) { term = devlpl(&coef[i][0],&ideg[i],&xx)*x; denpow *= *df; sum += (term/(denpow*denom[i])); } if(!(*p >= 0.5e0)) goto S20; xp = sum; goto S30; S20: xp = -sum; S30: dt1 = xp; return dt1; } /* DEFINE DZROR */ /*static*/ void E0001(int IENTRY,int *status,double *x,double *fx, double *xlo,double *xhi,unsigned long *qleft, unsigned long *qhi,double *zabstl,double *zreltl, double *zxhi,double *zxlo) { #define ftol(zx) (0.5e0*fifdmax1(abstol,reltol*fabs((zx)))) static double a,abstol,b,c,d,fa,fb,fc,fd,fda,fdb,m,mb,p,q,reltol,tol,w,xxhi,xxlo; static int ext,i99999; static unsigned long first,qrzero; switch(IENTRY){case 0: goto DZROR; case 1: goto DSTZR;} DZROR: if(*status > 0) goto S280; *xlo = xxlo; *xhi = xxhi; b = *x = *xlo; /* GET-FUNCTION-VALUE */ i99999 = 1; goto S270; S10: fb = *fx; *xlo = *xhi; a = *x = *xlo; /* GET-FUNCTION-VALUE */ i99999 = 2; goto S270; S20: /* Check that F(ZXLO) < 0 < F(ZXHI) or F(ZXLO) > 0 > F(ZXHI) */ if(!(fb < 0.0e0)) goto S40; if(!(*fx < 0.0e0)) goto S30; *status = -1; *qleft = *fx < fb; *qhi = 0; return; S40: S30: if(!(fb > 0.0e0)) goto S60; if(!(*fx > 0.0e0)) goto S50; *status = -1; *qleft = *fx > fb; *qhi = 1; return; S60: S50: fa = *fx; first = 1; S70: c = a; fc = fa; ext = 0; S80: if(!(fabs(fc) < fabs(fb))) goto S100; if(!(c != a)) goto S90; d = a; fd = fa; S90: a = b; fa = fb; *xlo = c; b = *xlo; fb = fc; c = a; fc = fa; S100: tol = ftol(*xlo); m = (c+b)*.5e0; mb = m-b; if(!(fabs(mb) > tol)) goto S240; if(!(ext > 3)) goto S110; w = mb; goto S190; S110: tol = fifdsign(tol,mb); p = (b-a)*fb; if(!first) goto S120; q = fa-fb; first = 0; goto S130; S120: fdb = (fd-fb)/(d-b); fda = (fd-fa)/(d-a); p = fda*p; q = fdb*fa-fda*fb; S130: if(!(p < 0.0e0)) goto S140; p = -p; q = -q; S140: if(ext == 3) p *= 2.0e0; if(!(p*1.0e0 == 0.0e0 || p <= q*tol)) goto S150; w = tol; goto S180; S150: if(!(p < mb*q)) goto S160; w = p/q; goto S170; S160: w = mb; S190: S180: S170: d = a; fd = fa; a = b; fa = fb; b += w; *xlo = b; *x = *xlo; /* GET-FUNCTION-VALUE */ i99999 = 3; goto S270; S200: fb = *fx; if(!(fc*fb >= 0.0e0)) goto S210; goto S70; S210: if(!(w == mb)) goto S220; ext = 0; goto S230; S220: ext += 1; S230: goto S80; S240: *xhi = c; qrzero = ((fc >= 0.0e0) && (fb <= 0.0e0)) || ((fc < 0.0e0) && (fb >= 0.0e0)); if(!qrzero) goto S250; *status = 0; goto S260; S250: *status = -1; S260: return; DSTZR: xxlo = *zxlo; xxhi = *zxhi; abstol = *zabstl; reltol = *zreltl; return; S270: /* TO GET-FUNCTION-VALUE */ *status = 1; return; S280: switch((int)i99999){case 1: goto S10;case 2: goto S20;case 3: goto S200; default: break;} #undef ftol } void dzror(int *status,double *x,double *fx,double *xlo, double *xhi,unsigned long *qleft,unsigned long *qhi) /* ********************************************************************** void dzror(int *status,double *x,double *fx,double *xlo, double *xhi,unsigned long *qleft,unsigned long *qhi) Double precision ZeRo of a function -- Reverse Communication Function Performs the zero finding. STZROR must have been called before this routine in order to set its parameters. Arguments STATUS <--> At the beginning of a zero finding problem, STATUS should be set to 0 and ZROR invoked. (The value of other parameters will be ignored on this call.) When ZROR needs the function evaluated, it will set STATUS to 1 and return. The value of the function should be set in FX and ZROR again called without changing any of its other parameters. When ZROR has finished without error, it will return with STATUS 0. In that case (XLO,XHI) bound the answe If ZROR finds an error (which implies that F(XLO)-Y an F(XHI)-Y have the same sign, it returns STATUS -1. In this case, XLO and XHI are undefined. INTEGER STATUS X <-- The value of X at which F(X) is to be evaluated. DOUBLE PRECISION X FX --> The value of F(X) calculated when ZROR returns with STATUS = 1. DOUBLE PRECISION FX XLO <-- When ZROR returns with STATUS = 0, XLO bounds the inverval in X containing the solution below. DOUBLE PRECISION XLO XHI <-- When ZROR returns with STATUS = 0, XHI bounds the inverval in X containing the solution above. DOUBLE PRECISION XHI QLEFT <-- .TRUE. if the stepping search terminated unsucessfully at XLO. If it is .FALSE. the search terminated unsucessfully at XHI. QLEFT is LOGICAL QHI <-- .TRUE. if F(X) .GT. Y at the termination of the search and .FALSE. if F(X) .LT. Y at the termination of the search. QHI is LOGICAL ********************************************************************** */ { E0001(0,status,x,fx,xlo,xhi,qleft,qhi,NULL,NULL,NULL,NULL); } void dstzr(double *zxlo,double *zxhi,double *zabstl,double *zreltl) /* ********************************************************************** void dstzr(double *zxlo,double *zxhi,double *zabstl,double *zreltl) Double precision SeT ZeRo finder - Reverse communication version Function Sets quantities needed by ZROR. The function of ZROR and the quantities set is given here. Concise Description - Given a function F find XLO such that F(XLO) = 0. More Precise Description - Input condition. F is a double precision function of a single double precision argument and XLO and XHI are such that F(XLO)*F(XHI) .LE. 0.0 If the input condition is met, QRZERO returns .TRUE. and output values of XLO and XHI satisfy the following F(XLO)*F(XHI) .LE. 0. ABS(F(XLO) .LE. ABS(F(XHI) ABS(XLO-XHI) .LE. TOL(X) where TOL(X) = MAX(ABSTOL,RELTOL*ABS(X)) If this algorithm does not find XLO and XHI satisfying these conditions then QRZERO returns .FALSE. This implies that the input condition was not met. Arguments XLO --> The left endpoint of the interval to be searched for a solution. XLO is DOUBLE PRECISION XHI --> The right endpoint of the interval to be for a solution. XHI is DOUBLE PRECISION ABSTOL, RELTOL --> Two numbers that determine the accuracy of the solution. See function for a precise definition. ABSTOL is DOUBLE PRECISION RELTOL is DOUBLE PRECISION Method Algorithm R of the paper 'Two Efficient Algorithms with Guaranteed Convergence for Finding a Zero of a Function' by J. C. P. Bus and T. J. Dekker in ACM Transactions on Mathematical Software, Volume 1, no. 4 page 330 (Dec. '75) is employed to find the zero of F(X)-Y. ********************************************************************** */ { E0001(1,NULL,NULL,NULL,NULL,NULL,NULL,NULL,zabstl,zreltl,zxhi,zxlo); } double erf1(double *x) /* ----------------------------------------------------------------------- EVALUATION OF THE REAL ERROR FUNCTION ----------------------------------------------------------------------- */ { static double c = .564189583547756e0; static double a[5] = { .771058495001320e-04,-.133733772997339e-02,.323076579225834e-01, .479137145607681e-01,.128379167095513e+00 }; static double b[3] = { .301048631703895e-02,.538971687740286e-01,.375795757275549e+00 }; static double p[8] = { -1.36864857382717e-07,5.64195517478974e-01,7.21175825088309e+00, 4.31622272220567e+01,1.52989285046940e+02,3.39320816734344e+02, 4.51918953711873e+02,3.00459261020162e+02 }; static double q[8] = { 1.00000000000000e+00,1.27827273196294e+01,7.70001529352295e+01, 2.77585444743988e+02,6.38980264465631e+02,9.31354094850610e+02, 7.90950925327898e+02,3.00459260956983e+02 }; static double r[5] = { 2.10144126479064e+00,2.62370141675169e+01,2.13688200555087e+01, 4.65807828718470e+00,2.82094791773523e-01 }; static double s[4] = { 9.41537750555460e+01,1.87114811799590e+02,9.90191814623914e+01, 1.80124575948747e+01 }; static double erf1,ax,bot,t,top,x2; /* .. .. Executable Statements .. */ ax = fabs(*x); if(ax > 0.5e0) goto S10; t = *x**x; top = (((a[0]*t+a[1])*t+a[2])*t+a[3])*t+a[4]+1.0e0; bot = ((b[0]*t+b[1])*t+b[2])*t+1.0e0; erf1 = *x*(top/bot); return erf1; S10: if(ax > 4.0e0) goto S20; top = ((((((p[0]*ax+p[1])*ax+p[2])*ax+p[3])*ax+p[4])*ax+p[5])*ax+p[6])*ax+p[ 7]; bot = ((((((q[0]*ax+q[1])*ax+q[2])*ax+q[3])*ax+q[4])*ax+q[5])*ax+q[6])*ax+q[ 7]; erf1 = 0.5e0+(0.5e0-exp(-(*x**x))*top/bot); if(*x < 0.0e0) erf1 = -erf1; return erf1; S20: if(ax >= 5.8e0) goto S30; x2 = *x**x; t = 1.0e0/x2; top = (((r[0]*t+r[1])*t+r[2])*t+r[3])*t+r[4]; bot = (((s[0]*t+s[1])*t+s[2])*t+s[3])*t+1.0e0; erf1 = (c-top/(x2*bot))/ax; erf1 = 0.5e0+(0.5e0-exp(-x2)*erf1); if(*x < 0.0e0) erf1 = -erf1; return erf1; S30: erf1 = fifdsign(1.0e0,*x); return erf1; } double erfc1(int *ind,double *x) /* ----------------------------------------------------------------------- EVALUATION OF THE COMPLEMENTARY ERROR FUNCTION ERFC1(IND,X) = ERFC(X) IF IND = 0 ERFC1(IND,X) = EXP(X*X)*ERFC(X) OTHERWISE ----------------------------------------------------------------------- */ { static double c = .564189583547756e0; static double a[5] = { .771058495001320e-04,-.133733772997339e-02,.323076579225834e-01, .479137145607681e-01,.128379167095513e+00 }; static double b[3] = { .301048631703895e-02,.538971687740286e-01,.375795757275549e+00 }; static double p[8] = { -1.36864857382717e-07,5.64195517478974e-01,7.21175825088309e+00, 4.31622272220567e+01,1.52989285046940e+02,3.39320816734344e+02, 4.51918953711873e+02,3.00459261020162e+02 }; static double q[8] = { 1.00000000000000e+00,1.27827273196294e+01,7.70001529352295e+01, 2.77585444743988e+02,6.38980264465631e+02,9.31354094850610e+02, 7.90950925327898e+02,3.00459260956983e+02 }; static double r[5] = { 2.10144126479064e+00,2.62370141675169e+01,2.13688200555087e+01, 4.65807828718470e+00,2.82094791773523e-01 }; static double s[4] = { 9.41537750555460e+01,1.87114811799590e+02,9.90191814623914e+01, 1.80124575948747e+01 }; static int K1 = 1; static double erfc1,ax,bot,e,t,top,w; /* .. .. Executable Statements .. */ /* ABS(X) .LE. 0.5 */ ax = fabs(*x); if(ax > 0.5e0) goto S10; t = *x**x; top = (((a[0]*t+a[1])*t+a[2])*t+a[3])*t+a[4]+1.0e0; bot = ((b[0]*t+b[1])*t+b[2])*t+1.0e0; erfc1 = 0.5e0+(0.5e0-*x*(top/bot)); if(*ind != 0) erfc1 = exp(t)*erfc1; return erfc1; S10: /* 0.5 .LT. ABS(X) .LE. 4 */ if(ax > 4.0e0) goto S20; top = ((((((p[0]*ax+p[1])*ax+p[2])*ax+p[3])*ax+p[4])*ax+p[5])*ax+p[6])*ax+p[ 7]; bot = ((((((q[0]*ax+q[1])*ax+q[2])*ax+q[3])*ax+q[4])*ax+q[5])*ax+q[6])*ax+q[ 7]; erfc1 = top/bot; goto S40; S20: /* ABS(X) .GT. 4 */ if(*x <= -5.6e0) goto S60; if(*ind != 0) goto S30; if(*x > 100.0e0) goto S70; if(*x**x > -exparg(&K1)) goto S70; S30: t = pow(1.0e0/ *x,2.0); top = (((r[0]*t+r[1])*t+r[2])*t+r[3])*t+r[4]; bot = (((s[0]*t+s[1])*t+s[2])*t+s[3])*t+1.0e0; erfc1 = (c-t*top/bot)/ax; S40: /* FINAL ASSEMBLY */ if(*ind == 0) goto S50; if(*x < 0.0e0) erfc1 = 2.0e0*exp(*x**x)-erfc1; return erfc1; S50: w = *x**x; t = w; e = w-t; erfc1 = (0.5e0+(0.5e0-e))*exp(-t)*erfc1; if(*x < 0.0e0) erfc1 = 2.0e0-erfc1; return erfc1; S60: /* LIMIT VALUE FOR LARGE NEGATIVE X */ erfc1 = 2.0e0; if(*ind != 0) erfc1 = 2.0e0*exp(*x**x); return erfc1; S70: /* LIMIT VALUE FOR LARGE POSITIVE X WHEN IND = 0 */ erfc1 = 0.0e0; return erfc1; } double esum(int *mu,double *x) /* ----------------------------------------------------------------------- EVALUATION OF EXP(MU + X) ----------------------------------------------------------------------- */ { static double esum,w; /* .. .. Executable Statements .. */ if(*x > 0.0e0) goto S10; if(*mu < 0) goto S20; w = (double)*mu+*x; if(w > 0.0e0) goto S20; esum = exp(w); return esum; S10: if(*mu > 0) goto S20; w = (double)*mu+*x; if(w < 0.0e0) goto S20; esum = exp(w); return esum; S20: w = *mu; esum = exp(w)*exp(*x); return esum; } double exparg(int *l) /* -------------------------------------------------------------------- IF L = 0 THEN EXPARG(L) = THE LARGEST POSITIVE W FOR WHICH EXP(W) CAN BE COMPUTED. IF L IS NONZERO THEN EXPARG(L) = THE LARGEST NEGATIVE W FOR WHICH THE COMPUTED VALUE OF EXP(W) IS NONZERO. NOTE... ONLY AN APPROXIMATE VALUE FOR EXPARG(L) IS NEEDED. -------------------------------------------------------------------- */ { static int K1 = 4; static int K2 = 9; static int K3 = 10; static double exparg,lnb; static int b,m; /* .. .. Executable Statements .. */ b = ipmpar(&K1); if(b != 2) goto S10; lnb = .69314718055995e0; goto S40; S10: if(b != 8) goto S20; lnb = 2.0794415416798e0; goto S40; S20: if(b != 16) goto S30; lnb = 2.7725887222398e0; goto S40; S30: lnb = log((double)b); S40: if(*l == 0) goto S50; m = ipmpar(&K2)-1; exparg = 0.99999e0*((double)m*lnb); return exparg; S50: m = ipmpar(&K3); exparg = 0.99999e0*((double)m*lnb); return exparg; } double fpser(double *a,double *b,double *x,double *eps) /* ----------------------------------------------------------------------- EVALUATION OF I (A,B) X FOR B .LT. MIN(EPS,EPS*A) AND X .LE. 0.5. ----------------------------------------------------------------------- SET FPSER = X**A */ { static int K1 = 1; static double fpser,an,c,s,t,tol; /* .. .. Executable Statements .. */ fpser = 1.0e0; if(*a <= 1.e-3**eps) goto S10; fpser = 0.0e0; t = *a*log(*x); if(t < exparg(&K1)) return fpser; fpser = exp(t); S10: /* NOTE THAT 1/B(A,B) = B */ fpser = *b/ *a*fpser; tol = *eps/ *a; an = *a+1.0e0; t = *x; s = t/an; S20: an += 1.0e0; t = *x*t; c = t/an; s += c; if(fabs(c) > tol) goto S20; fpser *= (1.0e0+*a*s); return fpser; } double gam1(double *a) /* ------------------------------------------------------------------ COMPUTATION OF 1/GAMMA(A+1) - 1 FOR -0.5 .LE. A .LE. 1.5 ------------------------------------------------------------------ */ { static double s1 = .273076135303957e+00; static double s2 = .559398236957378e-01; static double p[7] = { .577215664901533e+00,-.409078193005776e+00,-.230975380857675e+00, .597275330452234e-01,.766968181649490e-02,-.514889771323592e-02, .589597428611429e-03 }; static double q[5] = { .100000000000000e+01,.427569613095214e+00,.158451672430138e+00, .261132021441447e-01,.423244297896961e-02 }; static double r[9] = { -.422784335098468e+00,-.771330383816272e+00,-.244757765222226e+00, .118378989872749e+00,.930357293360349e-03,-.118290993445146e-01, .223047661158249e-02,.266505979058923e-03,-.132674909766242e-03 }; static double gam1,bot,d,t,top,w,T1; /* .. .. Executable Statements .. */ t = *a; d = *a-0.5e0; if(d > 0.0e0) t = d-0.5e0; T1 = t; if(T1 < 0) goto S40; else if(T1 == 0) goto S10; else goto S20; S10: gam1 = 0.0e0; return gam1; S20: top = (((((p[6]*t+p[5])*t+p[4])*t+p[3])*t+p[2])*t+p[1])*t+p[0]; bot = (((q[4]*t+q[3])*t+q[2])*t+q[1])*t+1.0e0; w = top/bot; if(d > 0.0e0) goto S30; gam1 = *a*w; return gam1; S30: gam1 = t/ *a*(w-0.5e0-0.5e0); return gam1; S40: top = (((((((r[8]*t+r[7])*t+r[6])*t+r[5])*t+r[4])*t+r[3])*t+r[2])*t+r[1])*t+ r[0]; bot = (s2*t+s1)*t+1.0e0; w = top/bot; if(d > 0.0e0) goto S50; gam1 = *a*(w+0.5e0+0.5e0); return gam1; S50: gam1 = t*w/ *a; return gam1; } void gaminv(double *a,double *x,double *x0,double *p,double *q, int *ierr) /* ---------------------------------------------------------------------- INVERSE INCOMPLETE GAMMA RATIO FUNCTION GIVEN POSITIVE A, AND NONEGATIVE P AND Q WHERE P + Q = 1. THEN X IS COMPUTED WHERE P(A,X) = P AND Q(A,X) = Q. SCHRODER ITERATION IS EMPLOYED. THE ROUTINE ATTEMPTS TO COMPUTE X TO 10 SIGNIFICANT DIGITS IF THIS IS POSSIBLE FOR THE PARTICULAR COMPUTER ARITHMETIC BEING USED. ------------ X IS A VARIABLE. IF P = 0 THEN X IS ASSIGNED THE VALUE 0, AND IF Q = 0 THEN X IS SET TO THE LARGEST FLOATING POINT NUMBER AVAILABLE. OTHERWISE, GAMINV ATTEMPTS TO OBTAIN A SOLUTION FOR P(A,X) = P AND Q(A,X) = Q. IF THE ROUTINE IS SUCCESSFUL THEN THE SOLUTION IS STORED IN X. X0 IS AN OPTIONAL INITIAL APPROXIMATION FOR X. IF THE USER DOES NOT WISH TO SUPPLY AN INITIAL APPROXIMATION, THEN SET X0 .LE. 0. IERR IS A VARIABLE THAT REPORTS THE STATUS OF THE RESULTS. WHEN THE ROUTINE TERMINATES, IERR HAS ONE OF THE FOLLOWING VALUES ... IERR = 0 THE SOLUTION WAS OBTAINED. ITERATION WAS NOT USED. IERR.GT.0 THE SOLUTION WAS OBTAINED. IERR ITERATIONS WERE PERFORMED. IERR = -2 (INPUT ERROR) A .LE. 0 IERR = -3 NO SOLUTION WAS OBTAINED. THE RATIO Q/A IS TOO LARGE. IERR = -4 (INPUT ERROR) P + Q .NE. 1 IERR = -6 20 ITERATIONS WERE PERFORMED. THE MOST RECENT VALUE OBTAINED FOR X IS GIVEN. THIS CANNOT OCCUR IF X0 .LE. 0. IERR = -7 ITERATION FAILED. NO VALUE IS GIVEN FOR X. THIS MAY OCCUR WHEN X IS APPROXIMATELY 0. IERR = -8 A VALUE FOR X HAS BEEN OBTAINED, BUT THE ROUTINE IS NOT CERTAIN OF ITS ACCURACY. ITERATION CANNOT BE PERFORMED IN THIS CASE. IF X0 .LE. 0, THIS CAN OCCUR ONLY WHEN P OR Q IS APPROXIMATELY 0. IF X0 IS POSITIVE THEN THIS CAN OCCUR WHEN A IS EXCEEDINGLY CLOSE TO X AND A IS EXTREMELY LARGE (SAY A .GE. 1.E20). ---------------------------------------------------------------------- WRITTEN BY ALFRED H. MORRIS, JR. NAVAL SURFACE WEAPONS CENTER DAHLGREN, VIRGINIA ------------------- */ { static double a0 = 3.31125922108741e0; static double a1 = 11.6616720288968e0; static double a2 = 4.28342155967104e0; static double a3 = .213623493715853e0; static double b1 = 6.61053765625462e0; static double b2 = 6.40691597760039e0; static double b3 = 1.27364489782223e0; static double b4 = .036117081018842e0; static double c = .577215664901533e0; static double ln10 = 2.302585e0; static double tol = 1.e-5; static double amin[2] = { 500.0e0,100.0e0 }; static double bmin[2] = { 1.e-28,1.e-13 }; static double dmin[2] = { 1.e-06,1.e-04 }; static double emin[2] = { 2.e-03,6.e-03 }; static double eps0[2] = { 1.e-10,1.e-08 }; static int K1 = 1; static int K2 = 2; static int K3 = 3; static int K8 = 0; static double am1,amax,ap1,ap2,ap3,apn,b,c1,c2,c3,c4,c5,d,e,e2,eps,g,h,pn,qg,qn, r,rta,s,s2,sum,t,u,w,xmax,xmin,xn,y,z; static int iop; static double T4,T5,T6,T7,T9; /* .. .. Executable Statements .. */ /* ****** E, XMIN, AND XMAX ARE MACHINE DEPENDENT CONSTANTS. E IS THE SMALLEST NUMBER FOR WHICH 1.0 + E .GT. 1.0. XMIN IS THE SMALLEST POSITIVE NUMBER AND XMAX IS THE LARGEST POSITIVE NUMBER. */ e = spmpar(&K1); xmin = spmpar(&K2); xmax = spmpar(&K3); *x = 0.0e0; if(*a <= 0.0e0) goto S300; t = *p+*q-1.e0; if(fabs(t) > e) goto S320; *ierr = 0; if(*p == 0.0e0) return; if(*q == 0.0e0) goto S270; if(*a == 1.0e0) goto S280; e2 = 2.0e0*e; amax = 0.4e-10/(e*e); iop = 1; if(e > 1.e-10) iop = 2; eps = eps0[iop-1]; xn = *x0; if(*x0 > 0.0e0) goto S160; /* SELECTION OF THE INITIAL APPROXIMATION XN OF X WHEN A .LT. 1 */ if(*a > 1.0e0) goto S80; T4 = *a+1.0e0; g = Xgamm(&T4); qg = *q*g; if(qg == 0.0e0) goto S360; b = qg/ *a; if(qg > 0.6e0**a) goto S40; if(*a >= 0.30e0 || b < 0.35e0) goto S10; t = exp(-(b+c)); u = t*exp(t); xn = t*exp(u); goto S160; S10: if(b >= 0.45e0) goto S40; if(b == 0.0e0) goto S360; y = -log(b); s = 0.5e0+(0.5e0-*a); z = log(y); t = y-s*z; if(b < 0.15e0) goto S20; xn = y-s*log(t)-log(1.0e0+s/(t+1.0e0)); goto S220; S20: if(b <= 0.01e0) goto S30; u = ((t+2.0e0*(3.0e0-*a))*t+(2.0e0-*a)*(3.0e0-*a))/((t+(5.0e0-*a))*t+2.0e0); xn = y-s*log(t)-log(u); goto S220; S30: c1 = -(s*z); c2 = -(s*(1.0e0+c1)); c3 = s*((0.5e0*c1+(2.0e0-*a))*c1+(2.5e0-1.5e0**a)); c4 = -(s*(((c1/3.0e0+(2.5e0-1.5e0**a))*c1+((*a-6.0e0)**a+7.0e0))*c1+( (11.0e0**a-46.0)**a+47.0e0)/6.0e0)); c5 = -(s*((((-(c1/4.0e0)+(11.0e0**a-17.0e0)/6.0e0)*c1+((-(3.0e0**a)+13.0e0)* *a-13.0e0))*c1+0.5e0*(((2.0e0**a-25.0e0)**a+72.0e0)**a-61.0e0))*c1+(( (25.0e0**a-195.0e0)**a+477.0e0)**a-379.0e0)/12.0e0)); xn = (((c5/y+c4)/y+c3)/y+c2)/y+c1+y; if(*a > 1.0e0) goto S220; if(b > bmin[iop-1]) goto S220; *x = xn; return; S40: if(b**q > 1.e-8) goto S50; xn = exp(-(*q/ *a+c)); goto S70; S50: if(*p <= 0.9e0) goto S60; T5 = -*q; xn = exp((alnrel(&T5)+gamln1(a))/ *a); goto S70; S60: xn = exp(log(*p*g)/ *a); S70: if(xn == 0.0e0) goto S310; t = 0.5e0+(0.5e0-xn/(*a+1.0e0)); xn /= t; goto S160; S80: /* SELECTION OF THE INITIAL APPROXIMATION XN OF X WHEN A .GT. 1 */ if(*q <= 0.5e0) goto S90; w = log(*p); goto S100; S90: w = log(*q); S100: t = sqrt(-(2.0e0*w)); s = t-(((a3*t+a2)*t+a1)*t+a0)/((((b4*t+b3)*t+b2)*t+b1)*t+1.0e0); if(*q > 0.5e0) s = -s; rta = sqrt(*a); s2 = s*s; xn = *a+s*rta+(s2-1.0e0)/3.0e0+s*(s2-7.0e0)/(36.0e0*rta)-((3.0e0*s2+7.0e0)* s2-16.0e0)/(810.0e0**a)+s*((9.0e0*s2+256.0e0)*s2-433.0e0)/(38880.0e0**a* rta); xn = fifdmax1(xn,0.0e0); if(*a < amin[iop-1]) goto S110; *x = xn; d = 0.5e0+(0.5e0-*x/ *a); if(fabs(d) <= dmin[iop-1]) return; S110: if(*p <= 0.5e0) goto S130; if(xn < 3.0e0**a) goto S220; y = -(w+gamln(a)); d = fifdmax1(2.0e0,*a*(*a-1.0e0)); if(y < ln10*d) goto S120; s = 1.0e0-*a; z = log(y); goto S30; S120: t = *a-1.0e0; T6 = -(t/(xn+1.0e0)); xn = y+t*log(xn)-alnrel(&T6); T7 = -(t/(xn+1.0e0)); xn = y+t*log(xn)-alnrel(&T7); goto S220; S130: ap1 = *a+1.0e0; if(xn > 0.70e0*ap1) goto S170; w += gamln(&ap1); if(xn > 0.15e0*ap1) goto S140; ap2 = *a+2.0e0; ap3 = *a+3.0e0; *x = exp((w+*x)/ *a); *x = exp((w+*x-log(1.0e0+*x/ap1*(1.0e0+*x/ap2)))/ *a); *x = exp((w+*x-log(1.0e0+*x/ap1*(1.0e0+*x/ap2)))/ *a); *x = exp((w+*x-log(1.0e0+*x/ap1*(1.0e0+*x/ap2*(1.0e0+*x/ap3))))/ *a); xn = *x; if(xn > 1.e-2*ap1) goto S140; if(xn <= emin[iop-1]*ap1) return; goto S170; S140: apn = ap1; t = xn/apn; sum = 1.0e0+t; S150: apn += 1.0e0; t *= (xn/apn); sum += t; if(t > 1.e-4) goto S150; t = w-log(sum); xn = exp((xn+t)/ *a); xn *= (1.0e0-(*a*log(xn)-xn-t)/(*a-xn)); goto S170; S160: /* SCHRODER ITERATION USING P */ if(*p > 0.5e0) goto S220; S170: if(*p <= 1.e10*xmin) goto S350; am1 = *a-0.5e0-0.5e0; S180: if(*a <= amax) goto S190; d = 0.5e0+(0.5e0-xn/ *a); if(fabs(d) <= e2) goto S350; S190: if(*ierr >= 20) goto S330; *ierr += 1; gratio(a,&xn,&pn,&qn,&K8); if(pn == 0.0e0 || qn == 0.0e0) goto S350; r = rcomp(a,&xn); if(r == 0.0e0) goto S350; t = (pn-*p)/r; w = 0.5e0*(am1-xn); if(fabs(t) <= 0.1e0 && fabs(w*t) <= 0.1e0) goto S200; *x = xn*(1.0e0-t); if(*x <= 0.0e0) goto S340; d = fabs(t); goto S210; S200: h = t*(1.0e0+w*t); *x = xn*(1.0e0-h); if(*x <= 0.0e0) goto S340; if(fabs(w) >= 1.0e0 && fabs(w)*t*t <= eps) return; d = fabs(h); S210: xn = *x; if(d > tol) goto S180; if(d <= eps) return; if(fabs(*p-pn) <= tol**p) return; goto S180; S220: /* SCHRODER ITERATION USING Q */ if(*q <= 1.e10*xmin) goto S350; am1 = *a-0.5e0-0.5e0; S230: if(*a <= amax) goto S240; d = 0.5e0+(0.5e0-xn/ *a); if(fabs(d) <= e2) goto S350; S240: if(*ierr >= 20) goto S330; *ierr += 1; gratio(a,&xn,&pn,&qn,&K8); if(pn == 0.0e0 || qn == 0.0e0) goto S350; r = rcomp(a,&xn); if(r == 0.0e0) goto S350; t = (*q-qn)/r; w = 0.5e0*(am1-xn); if(fabs(t) <= 0.1e0 && fabs(w*t) <= 0.1e0) goto S250; *x = xn*(1.0e0-t); if(*x <= 0.0e0) goto S340; d = fabs(t); goto S260; S250: h = t*(1.0e0+w*t); *x = xn*(1.0e0-h); if(*x <= 0.0e0) goto S340; if(fabs(w) >= 1.0e0 && fabs(w)*t*t <= eps) return; d = fabs(h); S260: xn = *x; if(d > tol) goto S230; if(d <= eps) return; if(fabs(*q-qn) <= tol**q) return; goto S230; S270: /* SPECIAL CASES */ *x = xmax; return; S280: if(*q < 0.9e0) goto S290; T9 = -*p; *x = -alnrel(&T9); return; S290: *x = -log(*q); return; S300: /* ERROR RETURN */ *ierr = -2; return; S310: *ierr = -3; return; S320: *ierr = -4; return; S330: *ierr = -6; return; S340: *ierr = -7; return; S350: *x = xn; *ierr = -8; return; S360: *x = xmax; *ierr = -8; return; } double gamln(double *a) /* ----------------------------------------------------------------------- EVALUATION OF LN(GAMMA(A)) FOR POSITIVE A ----------------------------------------------------------------------- WRITTEN BY ALFRED H. MORRIS NAVAL SURFACE WARFARE CENTER DAHLGREN, VIRGINIA -------------------------- D = 0.5*(LN(2*PI) - 1) -------------------------- */ { static double c0 = .833333333333333e-01; static double c1 = -.277777777760991e-02; static double c2 = .793650666825390e-03; static double c3 = -.595202931351870e-03; static double c4 = .837308034031215e-03; static double c5 = -.165322962780713e-02; static double d = .418938533204673e0; static double gamln,t,w; static int i,n; static double T1; /* .. .. Executable Statements .. */ if(*a > 0.8e0) goto S10; gamln = gamln1(a)-log(*a); return gamln; S10: if(*a > 2.25e0) goto S20; t = *a-0.5e0-0.5e0; gamln = gamln1(&t); return gamln; S20: if(*a >= 10.0e0) goto S40; n = (long)(*a - 1.25e0); t = *a; w = 1.0e0; for(i=1; i<=n; i++) { t -= 1.0e0; w = t*w; } T1 = t-1.0e0; gamln = gamln1(&T1)+log(w); return gamln; S40: t = pow(1.0e0/ *a,2.0); w = (((((c5*t+c4)*t+c3)*t+c2)*t+c1)*t+c0)/ *a; gamln = d+w+(*a-0.5e0)*(log(*a)-1.0e0); return gamln; } double gamln1(double *a) /* ----------------------------------------------------------------------- EVALUATION OF LN(GAMMA(1 + A)) FOR -0.2 .LE. A .LE. 1.25 ----------------------------------------------------------------------- */ { static double p0 = .577215664901533e+00; static double p1 = .844203922187225e+00; static double p2 = -.168860593646662e+00; static double p3 = -.780427615533591e+00; static double p4 = -.402055799310489e+00; static double p5 = -.673562214325671e-01; static double p6 = -.271935708322958e-02; static double q1 = .288743195473681e+01; static double q2 = .312755088914843e+01; static double q3 = .156875193295039e+01; static double q4 = .361951990101499e+00; static double q5 = .325038868253937e-01; static double q6 = .667465618796164e-03; static double r0 = .422784335098467e+00; static double r1 = .848044614534529e+00; static double r2 = .565221050691933e+00; static double r3 = .156513060486551e+00; static double r4 = .170502484022650e-01; static double r5 = .497958207639485e-03; static double s1 = .124313399877507e+01; static double s2 = .548042109832463e+00; static double s3 = .101552187439830e+00; static double s4 = .713309612391000e-02; static double s5 = .116165475989616e-03; static double gamln1,w,x; /* .. .. Executable Statements .. */ if(*a >= 0.6e0) goto S10; w = ((((((p6**a+p5)**a+p4)**a+p3)**a+p2)**a+p1)**a+p0)/((((((q6**a+q5)**a+ q4)**a+q3)**a+q2)**a+q1)**a+1.0e0); gamln1 = -(*a*w); return gamln1; S10: x = *a-0.5e0-0.5e0; w = (((((r5*x+r4)*x+r3)*x+r2)*x+r1)*x+r0)/(((((s5*x+s4)*x+s3)*x+s2)*x+s1)*x +1.0e0); gamln1 = x*w; return gamln1; } double Xgamm(double *a) /* ----------------------------------------------------------------------- EVALUATION OF THE GAMMA FUNCTION FOR REAL ARGUMENTS ----------- GAMMA(A) IS ASSIGNED THE VALUE 0 WHEN THE GAMMA FUNCTION CANNOT BE COMPUTED. ----------------------------------------------------------------------- WRITTEN BY ALFRED H. MORRIS, JR. NAVAL SURFACE WEAPONS CENTER DAHLGREN, VIRGINIA ----------------------------------------------------------------------- */ { static double d = .41893853320467274178e0; static double pi = 3.1415926535898e0; static double r1 = .820756370353826e-03; static double r2 = -.595156336428591e-03; static double r3 = .793650663183693e-03; static double r4 = -.277777777770481e-02; static double r5 = .833333333333333e-01; static double p[7] = { .539637273585445e-03,.261939260042690e-02,.204493667594920e-01, .730981088720487e-01,.279648642639792e+00,.553413866010467e+00,1.0e0 }; static double q[7] = { -.832979206704073e-03,.470059485860584e-02,.225211131035340e-01, -.170458969313360e+00,-.567902761974940e-01,.113062953091122e+01,1.0e0 }; static int K2 = 3; static int K3 = 0; static double Xgamm,bot,g,lnx,s,t,top,w,x,z; static int i,j,m,n,T1; /* .. .. Executable Statements .. */ Xgamm = 0.0e0; x = *a; if(fabs(*a) >= 15.0e0) goto S110; /* ----------------------------------------------------------------------- EVALUATION OF GAMMA(A) FOR ABS(A) .LT. 15 ----------------------------------------------------------------------- */ t = 1.0e0; m = fifidint(*a)-1; /* LET T BE THE PRODUCT OF A-J WHEN A .GE. 2 */ T1 = m; if(T1 < 0) goto S40; else if(T1 == 0) goto S30; else goto S10; S10: for(j=1; j<=m; j++) { x -= 1.0e0; t = x*t; } S30: x -= 1.0e0; goto S80; S40: /* LET T BE THE PRODUCT OF A+J WHEN A .LT. 1 */ t = *a; if(*a > 0.0e0) goto S70; m = -m-1; if(m == 0) goto S60; for(j=1; j<=m; j++) { x += 1.0e0; t = x*t; } S60: x += (0.5e0+0.5e0); t = x*t; if(t == 0.0e0) return Xgamm; S70: /* THE FOLLOWING CODE CHECKS IF 1/T CAN OVERFLOW. THIS CODE MAY BE OMITTED IF DESIRED. */ if(fabs(t) >= 1.e-30) goto S80; if(fabs(t)*spmpar(&K2) <= 1.0001e0) return Xgamm; Xgamm = 1.0e0/t; return Xgamm; S80: /* COMPUTE GAMMA(1 + X) FOR 0 .LE. X .LT. 1 */ top = p[0]; bot = q[0]; for(i=1; i<7; i++) { top = p[i]+x*top; bot = q[i]+x*bot; } Xgamm = top/bot; /* TERMINATION */ if(*a < 1.0e0) goto S100; Xgamm *= t; return Xgamm; S100: Xgamm /= t; return Xgamm; S110: /* ----------------------------------------------------------------------- EVALUATION OF GAMMA(A) FOR ABS(A) .GE. 15 ----------------------------------------------------------------------- */ if(fabs(*a) >= 1.e3) return Xgamm; if(*a > 0.0e0) goto S120; x = -*a; n = (long)(x); t = x-(double)n; if(t > 0.9e0) t = 1.0e0-t; s = sin(pi*t)/pi; if(fifmod(n,2) == 0) s = -s; if(s == 0.0e0) return Xgamm; S120: /* COMPUTE THE MODIFIED ASYMPTOTIC SUM */ t = 1.0e0/(x*x); g = ((((r1*t+r2)*t+r3)*t+r4)*t+r5)/x; /* ONE MAY REPLACE THE NEXT STATEMENT WITH LNX = ALOG(X) BUT LESS ACCURACY WILL NORMALLY BE OBTAINED. */ lnx = log(x); /* FINAL ASSEMBLY */ z = x; g = d+g+(z-0.5e0)*(lnx-1.e0); w = g; t = g-w; if(w > 0.99999e0*exparg(&K3)) return Xgamm; Xgamm = exp(w)*(1.0e0+t); if(*a < 0.0e0) Xgamm = 1.0e0/(Xgamm*s)/x; return Xgamm; } void grat1(double *a,double *x,double *r,double *p,double *q, double *eps) { static int K2 = 0; static double a2n,a2nm1,am0,an,an0,b2n,b2nm1,c,cma,g,h,j,l,sum,t,tol,w,z,T1,T3; /* .. .. Executable Statements .. */ /* ----------------------------------------------------------------------- EVALUATION OF THE INCOMPLETE GAMMA RATIO FUNCTIONS P(A,X) AND Q(A,X) IT IS ASSUMED THAT A .LE. 1. EPS IS THE TOLERANCE TO BE USED. THE INPUT ARGUMENT R HAS THE VALUE E**(-X)*X**A/GAMMA(A). ----------------------------------------------------------------------- */ if(*a**x == 0.0e0) goto S120; if(*a == 0.5e0) goto S100; if(*x < 1.1e0) goto S10; goto S60; S10: /* TAYLOR SERIES FOR P(A,X)/X**A */ an = 3.0e0; c = *x; sum = *x/(*a+3.0e0); tol = 0.1e0**eps/(*a+1.0e0); S20: an += 1.0e0; c = -(c*(*x/an)); t = c/(*a+an); sum += t; if(fabs(t) > tol) goto S20; j = *a**x*((sum/6.0e0-0.5e0/(*a+2.0e0))**x+1.0e0/(*a+1.0e0)); z = *a*log(*x); h = gam1(a); g = 1.0e0+h; if(*x < 0.25e0) goto S30; if(*a < *x/2.59e0) goto S50; goto S40; S30: if(z > -.13394e0) goto S50; S40: w = exp(z); *p = w*g*(0.5e0+(0.5e0-j)); *q = 0.5e0+(0.5e0-*p); return; S50: l = rexp(&z); w = 0.5e0+(0.5e0+l); *q = (w*j-l)*g-h; if(*q < 0.0e0) goto S90; *p = 0.5e0+(0.5e0-*q); return; S60: /* CONTINUED FRACTION EXPANSION */ a2nm1 = a2n = 1.0e0; b2nm1 = *x; b2n = *x+(1.0e0-*a); c = 1.0e0; S70: a2nm1 = *x*a2n+c*a2nm1; b2nm1 = *x*b2n+c*b2nm1; am0 = a2nm1/b2nm1; c += 1.0e0; cma = c-*a; a2n = a2nm1+cma*a2n; b2n = b2nm1+cma*b2n; an0 = a2n/b2n; if(fabs(an0-am0) >= *eps*an0) goto S70; *q = *r*an0; *p = 0.5e0+(0.5e0-*q); return; S80: /* SPECIAL CASES */ *p = 0.0e0; *q = 1.0e0; return; S90: *p = 1.0e0; *q = 0.0e0; return; S100: if(*x >= 0.25e0) goto S110; T1 = sqrt(*x); *p = erf1(&T1); *q = 0.5e0+(0.5e0-*p); return; S110: T3 = sqrt(*x); *q = erfc1(&K2,&T3); *p = 0.5e0+(0.5e0-*q); return; S120: if(*x <= *a) goto S80; goto S90; } void gratio(double *a,double *x,double *ans,double *qans,int *ind) /* ---------------------------------------------------------------------- EVALUATION OF THE INCOMPLETE GAMMA RATIO FUNCTIONS P(A,X) AND Q(A,X) ---------- IT IS ASSUMED THAT A AND X ARE NONNEGATIVE, WHERE A AND X ARE NOT BOTH 0. ANS AND QANS ARE VARIABLES. GRATIO ASSIGNS ANS THE VALUE P(A,X) AND QANS THE VALUE Q(A,X). IND MAY BE ANY INTEGER. IF IND = 0 THEN THE USER IS REQUESTING AS MUCH ACCURACY AS POSSIBLE (UP TO 14 SIGNIFICANT DIGITS). OTHERWISE, IF IND = 1 THEN ACCURACY IS REQUESTED TO WITHIN 1 UNIT OF THE 6-TH SIGNIFICANT DIGIT, AND IF IND .NE. 0,1 THEN ACCURACY IS REQUESTED TO WITHIN 1 UNIT OF THE 3RD SIGNIFICANT DIGIT. ERROR RETURN ... ANS IS ASSIGNED THE VALUE 2 WHEN A OR X IS NEGATIVE, WHEN A*X = 0, OR WHEN P(A,X) AND Q(A,X) ARE INDETERMINANT. P(A,X) AND Q(A,X) ARE COMPUTATIONALLY INDETERMINANT WHEN X IS EXCEEDINGLY CLOSE TO A AND A IS EXTREMELY LARGE. ---------------------------------------------------------------------- WRITTEN BY ALFRED H. MORRIS, JR. NAVAL SURFACE WEAPONS CENTER DAHLGREN, VIRGINIA -------------------- */ { static double alog10 = 2.30258509299405e0; static double d10 = -.185185185185185e-02; static double d20 = .413359788359788e-02; static double d30 = .649434156378601e-03; static double d40 = -.861888290916712e-03; static double d50 = -.336798553366358e-03; static double d60 = .531307936463992e-03; static double d70 = .344367606892378e-03; static double rt2pin = .398942280401433e0; static double rtpi = 1.77245385090552e0; static double third = .333333333333333e0; static double acc0[3] = { 5.e-15,5.e-7,5.e-4 }; static double big[3] = { 20.0e0,14.0e0,10.0e0 }; static double d0[13] = { .833333333333333e-01,-.148148148148148e-01,.115740740740741e-02, .352733686067019e-03,-.178755144032922e-03,.391926317852244e-04, -.218544851067999e-05,-.185406221071516e-05,.829671134095309e-06, -.176659527368261e-06,.670785354340150e-08,.102618097842403e-07, -.438203601845335e-08 }; static double d1[12] = { -.347222222222222e-02,.264550264550265e-02,-.990226337448560e-03, .205761316872428e-03,-.401877572016461e-06,-.180985503344900e-04, .764916091608111e-05,-.161209008945634e-05,.464712780280743e-08, .137863344691572e-06,-.575254560351770e-07,.119516285997781e-07 }; static double d2[10] = { -.268132716049383e-02,.771604938271605e-03,.200938786008230e-05, -.107366532263652e-03,.529234488291201e-04,-.127606351886187e-04, .342357873409614e-07,.137219573090629e-05,-.629899213838006e-06, .142806142060642e-06 }; static double d3[8] = { .229472093621399e-03,-.469189494395256e-03,.267720632062839e-03, -.756180167188398e-04,-.239650511386730e-06,.110826541153473e-04, -.567495282699160e-05,.142309007324359e-05 }; static double d4[6] = { .784039221720067e-03,-.299072480303190e-03,-.146384525788434e-05, .664149821546512e-04,-.396836504717943e-04,.113757269706784e-04 }; static double d5[4] = { -.697281375836586e-04,.277275324495939e-03,-.199325705161888e-03, .679778047793721e-04 }; static double d6[2] = { -.592166437353694e-03,.270878209671804e-03 }; static double e00[3] = { .25e-3,.25e-1,.14e0 }; static double x00[3] = { 31.0e0,17.0e0,9.7e0 }; static int K1 = 1; static int K2 = 0; static double a2n,a2nm1,acc,am0,amn,an,an0,apn,b2n,b2nm1,c,c0,c1,c2,c3,c4,c5,c6, cma,e,e0,g,h,j,l,r,rta,rtx,s,sum,t,t1,tol,twoa,u,w,x0,y,z; static int i,iop,m,max,n; static double wk[20],T3; static int T4,T5; static double T6,T7; /* .. .. Executable Statements .. */ /* -------------------- ****** E IS A MACHINE DEPENDENT CONSTANT. E IS THE SMALLEST FLOATING POINT NUMBER FOR WHICH 1.0 + E .GT. 1.0 . */ e = spmpar(&K1); if(*a < 0.0e0 || *x < 0.0e0) goto S430; if(*a == 0.0e0 && *x == 0.0e0) goto S430; if(*a**x == 0.0e0) goto S420; iop = *ind+1; if(iop != 1 && iop != 2) iop = 3; acc = fifdmax1(acc0[iop-1],e); e0 = e00[iop-1]; x0 = x00[iop-1]; /* SELECT THE APPROPRIATE ALGORITHM */ if(*a >= 1.0e0) goto S10; if(*a == 0.5e0) goto S390; if(*x < 1.1e0) goto S160; t1 = *a*log(*x)-*x; u = *a*exp(t1); if(u == 0.0e0) goto S380; r = u*(1.0e0+gam1(a)); goto S250; S10: if(*a >= big[iop-1]) goto S30; if(*a > *x || *x >= x0) goto S20; twoa = *a+*a; m = fifidint(twoa); if(twoa != (double)m) goto S20; i = m/2; if(*a == (double)i) goto S210; goto S220; S20: t1 = *a*log(*x)-*x; r = exp(t1)/Xgamm(a); goto S40; S30: l = *x/ *a; if(l == 0.0e0) goto S370; s = 0.5e0+(0.5e0-l); z = rlog(&l); if(z >= 700.0e0/ *a) goto S410; y = *a*z; rta = sqrt(*a); if(fabs(s) <= e0/rta) goto S330; if(fabs(s) <= 0.4e0) goto S270; t = pow(1.0e0/ *a,2.0); t1 = (((0.75e0*t-1.0e0)*t+3.5e0)*t-105.0e0)/(*a*1260.0e0); t1 -= y; r = rt2pin*rta*exp(t1); S40: if(r == 0.0e0) goto S420; if(*x <= fifdmax1(*a,alog10)) goto S50; if(*x < x0) goto S250; goto S100; S50: /* TAYLOR SERIES FOR P/R */ apn = *a+1.0e0; t = *x/apn; wk[0] = t; for(n=2; n<=20; n++) { apn += 1.0e0; t *= (*x/apn); if(t <= 1.e-3) goto S70; wk[n-1] = t; } n = 20; S70: sum = t; tol = 0.5e0*acc; S80: apn += 1.0e0; t *= (*x/apn); sum += t; if(t > tol) goto S80; max = n-1; for(m=1; m<=max; m++) { n -= 1; sum += wk[n-1]; } *ans = r/ *a*(1.0e0+sum); *qans = 0.5e0+(0.5e0-*ans); return; S100: /* ASYMPTOTIC EXPANSION */ amn = *a-1.0e0; t = amn/ *x; wk[0] = t; for(n=2; n<=20; n++) { amn -= 1.0e0; t *= (amn/ *x); if(fabs(t) <= 1.e-3) goto S120; wk[n-1] = t; } n = 20; S120: sum = t; S130: if(fabs(t) <= acc) goto S140; amn -= 1.0e0; t *= (amn/ *x); sum += t; goto S130; S140: max = n-1; for(m=1; m<=max; m++) { n -= 1; sum += wk[n-1]; } *qans = r/ *x*(1.0e0+sum); *ans = 0.5e0+(0.5e0-*qans); return; S160: /* TAYLOR SERIES FOR P(A,X)/X**A */ an = 3.0e0; c = *x; sum = *x/(*a+3.0e0); tol = 3.0e0*acc/(*a+1.0e0); S170: an += 1.0e0; c = -(c*(*x/an)); t = c/(*a+an); sum += t; if(fabs(t) > tol) goto S170; j = *a**x*((sum/6.0e0-0.5e0/(*a+2.0e0))**x+1.0e0/(*a+1.0e0)); z = *a*log(*x); h = gam1(a); g = 1.0e0+h; if(*x < 0.25e0) goto S180; if(*a < *x/2.59e0) goto S200; goto S190; S180: if(z > -.13394e0) goto S200; S190: w = exp(z); *ans = w*g*(0.5e0+(0.5e0-j)); *qans = 0.5e0+(0.5e0-*ans); return; S200: l = rexp(&z); w = 0.5e0+(0.5e0+l); *qans = (w*j-l)*g-h; if(*qans < 0.0e0) goto S380; *ans = 0.5e0+(0.5e0-*qans); return; S210: /* FINITE SUMS FOR Q WHEN A .GE. 1 AND 2*A IS AN INTEGER */ sum = exp(-*x); t = sum; n = 1; c = 0.0e0; goto S230; S220: rtx = sqrt(*x); sum = erfc1(&K2,&rtx); t = exp(-*x)/(rtpi*rtx); n = 0; c = -0.5e0; S230: if(n == i) goto S240; n += 1; c += 1.0e0; t = *x*t/c; sum += t; goto S230; S240: *qans = sum; *ans = 0.5e0+(0.5e0-*qans); return; S250: /* CONTINUED FRACTION EXPANSION */ tol = fifdmax1(5.0e0*e,acc); a2nm1 = a2n = 1.0e0; b2nm1 = *x; b2n = *x+(1.0e0-*a); c = 1.0e0; S260: a2nm1 = *x*a2n+c*a2nm1; b2nm1 = *x*b2n+c*b2nm1; am0 = a2nm1/b2nm1; c += 1.0e0; cma = c-*a; a2n = a2nm1+cma*a2n; b2n = b2nm1+cma*b2n; an0 = a2n/b2n; if(fabs(an0-am0) >= tol*an0) goto S260; *qans = r*an0; *ans = 0.5e0+(0.5e0-*qans); return; S270: /* GENERAL TEMME EXPANSION */ if(fabs(s) <= 2.0e0*e && *a*e*e > 3.28e-3) goto S430; c = exp(-y); T3 = sqrt(y); w = 0.5e0*erfc1(&K1,&T3); u = 1.0e0/ *a; z = sqrt(z+z); if(l < 1.0e0) z = -z; T4 = iop-2; if(T4 < 0) goto S280; else if(T4 == 0) goto S290; else goto S300; S280: if(fabs(s) <= 1.e-3) goto S340; c0 = ((((((((((((d0[12]*z+d0[11])*z+d0[10])*z+d0[9])*z+d0[8])*z+d0[7])*z+d0[ 6])*z+d0[5])*z+d0[4])*z+d0[3])*z+d0[2])*z+d0[1])*z+d0[0])*z-third; c1 = (((((((((((d1[11]*z+d1[10])*z+d1[9])*z+d1[8])*z+d1[7])*z+d1[6])*z+d1[5] )*z+d1[4])*z+d1[3])*z+d1[2])*z+d1[1])*z+d1[0])*z+d10; c2 = (((((((((d2[9]*z+d2[8])*z+d2[7])*z+d2[6])*z+d2[5])*z+d2[4])*z+d2[3])*z+ d2[2])*z+d2[1])*z+d2[0])*z+d20; c3 = (((((((d3[7]*z+d3[6])*z+d3[5])*z+d3[4])*z+d3[3])*z+d3[2])*z+d3[1])*z+ d3[0])*z+d30; c4 = (((((d4[5]*z+d4[4])*z+d4[3])*z+d4[2])*z+d4[1])*z+d4[0])*z+d40; c5 = (((d5[3]*z+d5[2])*z+d5[1])*z+d5[0])*z+d50; c6 = (d6[1]*z+d6[0])*z+d60; t = ((((((d70*u+c6)*u+c5)*u+c4)*u+c3)*u+c2)*u+c1)*u+c0; goto S310; S290: c0 = (((((d0[5]*z+d0[4])*z+d0[3])*z+d0[2])*z+d0[1])*z+d0[0])*z-third; c1 = (((d1[3]*z+d1[2])*z+d1[1])*z+d1[0])*z+d10; c2 = d2[0]*z+d20; t = (c2*u+c1)*u+c0; goto S310; S300: t = ((d0[2]*z+d0[1])*z+d0[0])*z-third; S310: if(l < 1.0e0) goto S320; *qans = c*(w+rt2pin*t/rta); *ans = 0.5e0+(0.5e0-*qans); return; S320: *ans = c*(w-rt2pin*t/rta); *qans = 0.5e0+(0.5e0-*ans); return; S330: /* TEMME EXPANSION FOR L = 1 */ if(*a*e*e > 3.28e-3) goto S430; c = 0.5e0+(0.5e0-y); w = (0.5e0-sqrt(y)*(0.5e0+(0.5e0-y/3.0e0))/rtpi)/c; u = 1.0e0/ *a; z = sqrt(z+z); if(l < 1.0e0) z = -z; T5 = iop-2; if(T5 < 0) goto S340; else if(T5 == 0) goto S350; else goto S360; S340: c0 = ((((((d0[6]*z+d0[5])*z+d0[4])*z+d0[3])*z+d0[2])*z+d0[1])*z+d0[0])*z- third; c1 = (((((d1[5]*z+d1[4])*z+d1[3])*z+d1[2])*z+d1[1])*z+d1[0])*z+d10; c2 = ((((d2[4]*z+d2[3])*z+d2[2])*z+d2[1])*z+d2[0])*z+d20; c3 = (((d3[3]*z+d3[2])*z+d3[1])*z+d3[0])*z+d30; c4 = (d4[1]*z+d4[0])*z+d40; c5 = (d5[1]*z+d5[0])*z+d50; c6 = d6[0]*z+d60; t = ((((((d70*u+c6)*u+c5)*u+c4)*u+c3)*u+c2)*u+c1)*u+c0; goto S310; S350: c0 = (d0[1]*z+d0[0])*z-third; c1 = d1[0]*z+d10; t = (d20*u+c1)*u+c0; goto S310; S360: t = d0[0]*z-third; goto S310; S370: /* SPECIAL CASES */ *ans = 0.0e0; *qans = 1.0e0; return; S380: *ans = 1.0e0; *qans = 0.0e0; return; S390: if(*x >= 0.25e0) goto S400; T6 = sqrt(*x); *ans = erf1(&T6); *qans = 0.5e0+(0.5e0-*ans); return; S400: T7 = sqrt(*x); *qans = erfc1(&K2,&T7); *ans = 0.5e0+(0.5e0-*qans); return; S410: if(fabs(s) <= 2.0e0*e) goto S430; S420: if(*x <= *a) goto S370; goto S380; S430: /* ERROR RETURN */ *ans = 2.0e0; return; } double gsumln(double *a,double *b) /* ----------------------------------------------------------------------- EVALUATION OF THE FUNCTION LN(GAMMA(A + B)) FOR 1 .LE. A .LE. 2 AND 1 .LE. B .LE. 2 ----------------------------------------------------------------------- */ { static double gsumln,x,T1,T2; /* .. .. Executable Statements .. */ x = *a+*b-2.e0; if(x > 0.25e0) goto S10; T1 = 1.0e0+x; gsumln = gamln1(&T1); return gsumln; S10: if(x > 1.25e0) goto S20; gsumln = gamln1(&x)+alnrel(&x); return gsumln; S20: T2 = x-1.0e0; gsumln = gamln1(&T2)+log(x*(1.0e0+x)); return gsumln; } double psi(double *xx) /* --------------------------------------------------------------------- EVALUATION OF THE DIGAMMA FUNCTION ----------- PSI(XX) IS ASSIGNED THE VALUE 0 WHEN THE DIGAMMA FUNCTION CANNOT BE COMPUTED. THE MAIN COMPUTATION INVOLVES EVALUATION OF RATIONAL CHEBYSHEV APPROXIMATIONS PUBLISHED IN MATH. COMP. 27, 123-127(1973) BY CODY, STRECOK AND THACHER. --------------------------------------------------------------------- PSI WAS WRITTEN AT ARGONNE NATIONAL LABORATORY FOR THE FUNPACK PACKAGE OF SPECIAL FUNCTION SUBROUTINES. PSI WAS MODIFIED BY A.H. MORRIS (NSWC). --------------------------------------------------------------------- */ { static double dx0 = 1.461632144968362341262659542325721325e0; static double piov4 = .785398163397448e0; static double p1[7] = { .895385022981970e-02,.477762828042627e+01,.142441585084029e+03, .118645200713425e+04,.363351846806499e+04,.413810161269013e+04, .130560269827897e+04 }; static double p2[4] = { -.212940445131011e+01,-.701677227766759e+01,-.448616543918019e+01, -.648157123766197e+00 }; static double q1[6] = { .448452573429826e+02,.520752771467162e+03,.221000799247830e+04, .364127349079381e+04,.190831076596300e+04,.691091682714533e-05 }; static double q2[4] = { .322703493791143e+02,.892920700481861e+02,.546117738103215e+02, .777788548522962e+01 }; static int K1 = 3; static int K2 = 1; static double psi,aug,den,sgn,upper,w,x,xmax1,xmx0,xsmall,z; static int i,m,n,nq; /* .. .. Executable Statements .. */ /* --------------------------------------------------------------------- MACHINE DEPENDENT CONSTANTS ... XMAX1 = THE SMALLEST POSITIVE FLOATING POINT CONSTANT WITH ENTIRELY INTEGER REPRESENTATION. ALSO USED AS NEGATIVE OF LOWER BOUND ON ACCEPTABLE NEGATIVE ARGUMENTS AND AS THE POSITIVE ARGUMENT BEYOND WHICH PSI MAY BE REPRESENTED AS ALOG(X). XSMALL = ABSOLUTE ARGUMENT BELOW WHICH PI*COTAN(PI*X) MAY BE REPRESENTED BY 1/X. --------------------------------------------------------------------- */ xmax1 = ipmpar(&K1); xmax1 = fifdmin1(xmax1,1.0e0/spmpar(&K2)); xsmall = 1.e-9; x = *xx; aug = 0.0e0; if(x >= 0.5e0) goto S50; /* --------------------------------------------------------------------- X .LT. 0.5, USE REFLECTION FORMULA PSI(1-X) = PSI(X) + PI * COTAN(PI*X) --------------------------------------------------------------------- */ if(fabs(x) > xsmall) goto S10; if(x == 0.0e0) goto S100; /* --------------------------------------------------------------------- 0 .LT. ABS(X) .LE. XSMALL. USE 1/X AS A SUBSTITUTE FOR PI*COTAN(PI*X) --------------------------------------------------------------------- */ aug = -(1.0e0/x); goto S40; S10: /* --------------------------------------------------------------------- REDUCTION OF ARGUMENT FOR COTAN --------------------------------------------------------------------- */ w = -x; sgn = piov4; if(w > 0.0e0) goto S20; w = -w; sgn = -sgn; S20: /* --------------------------------------------------------------------- MAKE AN ERROR EXIT IF X .LE. -XMAX1 --------------------------------------------------------------------- */ if(w >= xmax1) goto S100; nq = fifidint(w); w -= (double)nq; nq = fifidint(w*4.0e0); w = 4.0e0*(w-(double)nq*.25e0); /* --------------------------------------------------------------------- W IS NOW RELATED TO THE FRACTIONAL PART OF 4.0 * X. ADJUST ARGUMENT TO CORRESPOND TO VALUES IN FIRST QUADRANT AND DETERMINE SIGN --------------------------------------------------------------------- */ n = nq/2; if(n+n != nq) w = 1.0e0-w; z = piov4*w; m = n/2; if(m+m != n) sgn = -sgn; /* --------------------------------------------------------------------- DETERMINE FINAL VALUE FOR -PI*COTAN(PI*X) --------------------------------------------------------------------- */ n = (nq+1)/2; m = n/2; m += m; if(m != n) goto S30; /* --------------------------------------------------------------------- CHECK FOR SINGULARITY --------------------------------------------------------------------- */ if(z == 0.0e0) goto S100; /* --------------------------------------------------------------------- USE COS/SIN AS A SUBSTITUTE FOR COTAN, AND SIN/COS AS A SUBSTITUTE FOR TAN --------------------------------------------------------------------- */ aug = sgn*(cos(z)/sin(z)*4.0e0); goto S40; S30: aug = sgn*(sin(z)/cos(z)*4.0e0); S40: x = 1.0e0-x; S50: if(x > 3.0e0) goto S70; /* --------------------------------------------------------------------- 0.5 .LE. X .LE. 3.0 --------------------------------------------------------------------- */ den = x; upper = p1[0]*x; for(i=1; i<=5; i++) { den = (den+q1[i-1])*x; upper = (upper+p1[i+1-1])*x; } den = (upper+p1[6])/(den+q1[5]); xmx0 = x-dx0; psi = den*xmx0+aug; return psi; S70: /* --------------------------------------------------------------------- IF X .GE. XMAX1, PSI = LN(X) --------------------------------------------------------------------- */ if(x >= xmax1) goto S90; /* --------------------------------------------------------------------- 3.0 .LT. X .LT. XMAX1 --------------------------------------------------------------------- */ w = 1.0e0/(x*x); den = w; upper = p2[0]*w; for(i=1; i<=3; i++) { den = (den+q2[i-1])*w; upper = (upper+p2[i+1-1])*w; } aug = upper/(den+q2[3])-0.5e0/x+aug; S90: psi = aug+log(x); return psi; S100: /* --------------------------------------------------------------------- ERROR RETURN --------------------------------------------------------------------- */ psi = 0.0e0; return psi; } double rcomp(double *a,double *x) /* ------------------- EVALUATION OF EXP(-X)*X**A/GAMMA(A) ------------------- RT2PIN = 1/SQRT(2*PI) ------------------- */ { static double rt2pin = .398942280401433e0; static double rcomp,t,t1,u; /* .. .. Executable Statements .. */ rcomp = 0.0e0; if(*a >= 20.0e0) goto S20; t = *a*log(*x)-*x; if(*a >= 1.0e0) goto S10; rcomp = *a*exp(t)*(1.0e0+gam1(a)); return rcomp; S10: rcomp = exp(t)/Xgamm(a); return rcomp; S20: u = *x/ *a; if(u == 0.0e0) return rcomp; t = pow(1.0e0/ *a,2.0); t1 = (((0.75e0*t-1.0e0)*t+3.5e0)*t-105.0e0)/(*a*1260.0e0); t1 -= (*a*rlog(&u)); rcomp = rt2pin*sqrt(*a)*exp(t1); return rcomp; } double rexp(double *x) /* ----------------------------------------------------------------------- EVALUATION OF THE FUNCTION EXP(X) - 1 ----------------------------------------------------------------------- */ { static double p1 = .914041914819518e-09; static double p2 = .238082361044469e-01; static double q1 = -.499999999085958e+00; static double q2 = .107141568980644e+00; static double q3 = -.119041179760821e-01; static double q4 = .595130811860248e-03; static double rexp,w; /* .. .. Executable Statements .. */ if(fabs(*x) > 0.15e0) goto S10; rexp = *x*(((p2**x+p1)**x+1.0e0)/((((q4**x+q3)**x+q2)**x+q1)**x+1.0e0)); return rexp; S10: w = exp(*x); if(*x > 0.0e0) goto S20; rexp = w-0.5e0-0.5e0; return rexp; S20: rexp = w*(0.5e0+(0.5e0-1.0e0/w)); return rexp; } double rlog(double *x) /* ------------------- COMPUTATION OF X - 1 - LN(X) ------------------- */ { static double a = .566749439387324e-01; static double b = .456512608815524e-01; static double p0 = .333333333333333e+00; static double p1 = -.224696413112536e+00; static double p2 = .620886815375787e-02; static double q1 = -.127408923933623e+01; static double q2 = .354508718369557e+00; static double rlog,r,t,u,w,w1; /* .. .. Executable Statements .. */ if(*x < 0.61e0 || *x > 1.57e0) goto S40; if(*x < 0.82e0) goto S10; if(*x > 1.18e0) goto S20; /* ARGUMENT REDUCTION */ u = *x-0.5e0-0.5e0; w1 = 0.0e0; goto S30; S10: u = *x-0.7e0; u /= 0.7e0; w1 = a-u*0.3e0; goto S30; S20: u = 0.75e0**x-1.e0; w1 = b+u/3.0e0; S30: /* SERIES EXPANSION */ r = u/(u+2.0e0); t = r*r; w = ((p2*t+p1)*t+p0)/((q2*t+q1)*t+1.0e0); rlog = 2.0e0*t*(1.0e0/(1.0e0-r)-r*w)+w1; return rlog; S40: r = *x-0.5e0-0.5e0; rlog = r-log(*x); return rlog; } double rlog1(double *x) /* ----------------------------------------------------------------------- EVALUATION OF THE FUNCTION X - LN(1 + X) ----------------------------------------------------------------------- */ { static double a = .566749439387324e-01; static double b = .456512608815524e-01; static double p0 = .333333333333333e+00; static double p1 = -.224696413112536e+00; static double p2 = .620886815375787e-02; static double q1 = -.127408923933623e+01; static double q2 = .354508718369557e+00; static double rlog1,h,r,t,w,w1; /* .. .. Executable Statements .. */ if(*x < -0.39e0 || *x > 0.57e0) goto S40; if(*x < -0.18e0) goto S10; if(*x > 0.18e0) goto S20; /* ARGUMENT REDUCTION */ h = *x; w1 = 0.0e0; goto S30; S10: h = *x+0.3e0; h /= 0.7e0; w1 = a-h*0.3e0; goto S30; S20: h = 0.75e0**x-0.25e0; w1 = b+h/3.0e0; S30: /* SERIES EXPANSION */ r = h/(h+2.0e0); t = r*r; w = ((p2*t+p1)*t+p0)/((q2*t+q1)*t+1.0e0); rlog1 = 2.0e0*t*(1.0e0/(1.0e0-r)-r*w)+w1; return rlog1; S40: w = *x+0.5e0+0.5e0; rlog1 = *x-log(w); return rlog1; } double spmpar(int *i) /* ----------------------------------------------------------------------- SPMPAR PROVIDES THE SINGLE PRECISION MACHINE CONSTANTS FOR THE COMPUTER BEING USED. IT IS ASSUMED THAT THE ARGUMENT I IS AN INTEGER HAVING ONE OF THE VALUES 1, 2, OR 3. IF THE SINGLE PRECISION ARITHMETIC BEING USED HAS M BASE B DIGITS AND ITS SMALLEST AND LARGEST EXPONENTS ARE EMIN AND EMAX, THEN SPMPAR(1) = B**(1 - M), THE MACHINE PRECISION, SPMPAR(2) = B**(EMIN - 1), THE SMALLEST MAGNITUDE, SPMPAR(3) = B**EMAX*(1 - B**(-M)), THE LARGEST MAGNITUDE. ----------------------------------------------------------------------- WRITTEN BY ALFRED H. MORRIS, JR. NAVAL SURFACE WARFARE CENTER DAHLGREN VIRGINIA ----------------------------------------------------------------------- ----------------------------------------------------------------------- MODIFIED BY BARRY W. BROWN TO RETURN DOUBLE PRECISION MACHINE CONSTANTS FOR THE COMPUTER BEING USED. THIS MODIFICATION WAS MADE AS PART OF CONVERTING BRATIO TO DOUBLE PRECISION ----------------------------------------------------------------------- */ { static int K1 = 4; static int K2 = 8; static int K3 = 9; static int K4 = 10; static double spmpar,b,binv,bm1,one,w,z; static int emax,emin,ibeta,m; /* .. .. Executable Statements .. */ if(*i > 1) goto S10; b = ipmpar(&K1); m = ipmpar(&K2); spmpar = pow(b,(double)(1-m)); return spmpar; S10: if(*i > 2) goto S20; b = ipmpar(&K1); emin = ipmpar(&K3); one = 1.0; binv = one/b; w = pow(b,(double)(emin+2)); spmpar = w*binv*binv*binv; return spmpar; S20: ibeta = ipmpar(&K1); m = ipmpar(&K2); emax = ipmpar(&K4); b = ibeta; bm1 = ibeta-1; one = 1.0; z = pow(b,(double)(m-1)); w = ((z-one)*b+bm1)/(b*z); z = pow(b,(double)(emax-2)); spmpar = w*z*b*b; return spmpar; } double stvaln(double *p) /* ********************************************************************** double stvaln(double *p) STarting VALue for Neton-Raphon calculation of Normal distribution Inverse Function Returns X such that CUMNOR(X) = P, i.e., the integral from - infinity to X of (1/SQRT(2*PI)) EXP(-U*U/2) dU is P Arguments P --> The probability whose normal deviate is sought. P is DOUBLE PRECISION Method The rational function on page 95 of Kennedy and Gentle, Statistical Computing, Marcel Dekker, NY , 1980. ********************************************************************** */ { static double xden[5] = { 0.993484626060e-1,0.588581570495e0,0.531103462366e0,0.103537752850e0, 0.38560700634e-2 }; static double xnum[5] = { -0.322232431088e0,-1.000000000000e0,-0.342242088547e0,-0.204231210245e-1, -0.453642210148e-4 }; static int K1 = 5; static double stvaln,sign,y,z; /* .. .. Executable Statements .. */ if(!(*p <= 0.5e0)) goto S10; sign = -1.0e0; z = *p; goto S20; S10: sign = 1.0e0; z = 1.0e0-*p; S20: y = sqrt(-(2.0e0*log(z))); stvaln = y+devlpl(xnum,&K1,&y)/devlpl(xden,&K1,&y); stvaln = sign*stvaln; return stvaln; } /************************************************************************ FIFDINT: Truncates a double precision number to an integer and returns the value in a double. ************************************************************************/ double fifdint(double a) /* a - number to be truncated */ { long temp; temp = (long)(a); return (double)(temp); } /************************************************************************ FIFDMAX1: returns the maximum of two numbers a and b ************************************************************************/ double fifdmax1(double a,double b) /* a - first number */ /* b - second number */ { if (a < b) return b; else return a; } /************************************************************************ FIFDMIN1: returns the minimum of two numbers a and b ************************************************************************/ double fifdmin1(double a,double b) /* a - first number */ /* b - second number */ { if (a < b) return a; else return b; } /************************************************************************ FIFDSIGN: transfers the sign of the variable "sign" to the variable "mag" ************************************************************************/ double fifdsign(double mag,double sign) /* mag - magnitude */ /* sign - sign to be transfered */ { if (mag < 0) mag = -mag; if (sign < 0) mag = -mag; return mag; } /************************************************************************ FIFIDINT: Truncates a double precision number to a long integer ************************************************************************/ long fifidint(double a) /* a - number to be truncated */ { return (long)(a); } /************************************************************************ FIFMOD: returns the modulo of a and b ************************************************************************/ long fifmod(long a,long b) /* a - numerator */ /* b - denominator */ { return a % b; } /************************************************************************ FTNSTOP: Prints msg to standard error and then exits ************************************************************************/ void ftnstop(const char* msg) /* msg - error message */ { if (msg != NULL) fprintf(stderr,"%s\n",msg); exit(EXIT_FAILURE); /* EXIT_FAILURE from stdlib.h, or use an int */ } caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticDataGroup.h0000664000175000017500000000741711572067322024071 0ustar michaelmichael #ifndef __STATISTIC_DATA_GROUP_H__ #define __STATISTIC_DATA_GROUP_H__ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include /// class for pointing/storing a data group for statistical processing /// NOTE the data passed to the StatisticDataGroup is NEVER modified class StatisticDataGroup { public: /// data storage mode - how to store data enum DATA_STORAGE_MODE { /// maintain a pointer to data (data must NOT be deallocated by user until statistical /// algorithm that uses data has executed). DATA_STORAGE_MODE_POINT, /// maintain pointer to data and delete the data in destructor /// data MUST have been allocated with new[]. DATA_STORAGE_MODE_TAKE_OWNERSHIP }; // constructor (if taking ownership, data must have been allocated with new[]) StatisticDataGroup(const float* dataIn, const int numDataIn, const DATA_STORAGE_MODE dataStorageModeIn); // constructor from vector StatisticDataGroup(const std::vector* dataIn, const DATA_STORAGE_MODE dataStorageModeIn); // copy constructor StatisticDataGroup(const StatisticDataGroup& dataGroup); // destructor ~StatisticDataGroup(); // assignment operator StatisticDataGroup& operator=(const StatisticDataGroup& dataGroup); /// get the number of data items inline int getNumberOfData() const { return numData; } /// get a data item inline float getData(const int indx) const { return data[indx]; } /// set a data item //inline void setData(const int indx, const float d) { data[indx] = d; } /// get a pointer to data (const method) const float* getPointerToData() const { return data; } // get the sum of all of the data double getSumOfData() const; // get mean of data float getMeanOfData() const; protected: // copy helper for copy constructor and operator= void copyHelper(const StatisticDataGroup& dataGroup); // delete the data in this data group void deleteData(); // constructor helper (if NOT copying data, data must have been allocated with new[]) void constructorHelper(const float* dataIn, const std::vector* dataVectorIn, const int numDataIn, const DATA_STORAGE_MODE dataStorageModeIn); /// the data float* data; /// vector for data std::vector* dataVector; /// number of data items int numData; /// how data is stored and deleted DATA_STORAGE_MODE dataStorageMode; friend class StatisticAlgorithm; }; /// subraction operator StatisticDataGroup operator-(const StatisticDataGroup& a, const StatisticDataGroup& b); #endif // __STATISTIC_DATA_GROUP_H__ caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticDataGroup.cxx0000664000175000017500000001321611572067322024436 0ustar michaelmichael/* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "StatisticDataGroup.h" /** * constructor (if taking ownership, data must have been allocated with new[]). */ StatisticDataGroup::StatisticDataGroup(const float* dataIn, const int numDataIn, const DATA_STORAGE_MODE dataStorageModeIn) { constructorHelper(dataIn, NULL, numDataIn, dataStorageModeIn); } /** * constructor. */ StatisticDataGroup::StatisticDataGroup(const std::vector* dataVectorIn, const DATA_STORAGE_MODE dataStorageModeIn) { constructorHelper(NULL, dataVectorIn, dataVectorIn->size(), dataStorageModeIn); } /** * destructor. */ StatisticDataGroup::~StatisticDataGroup() { deleteData(); } /** * delete the data in this data group. */ void StatisticDataGroup::deleteData() { switch (dataStorageMode) { case DATA_STORAGE_MODE_POINT: break; case DATA_STORAGE_MODE_TAKE_OWNERSHIP: if (dataVector != NULL) { dataVector->clear(); delete dataVector; } else { if (data != NULL) { delete[] data; } } break; } data = NULL; dataVector = NULL; numData = 0; } /** * copy constructor. */ StatisticDataGroup::StatisticDataGroup(const StatisticDataGroup& dataGroup) { copyHelper(dataGroup); } /** * copy helper for copy constructor and operator=. */ void StatisticDataGroup::copyHelper(const StatisticDataGroup& dataGroup) { // // Get rid of existing data // deleteData(); // // copy data // float* ptr = NULL; if (dataGroup.numData > 0) { ptr = new float[dataGroup.numData]; for (int i = 0; i < dataGroup.numData; i++) { ptr[i] = dataGroup.data[i]; } constructorHelper(ptr, NULL, dataGroup.numData, DATA_STORAGE_MODE_TAKE_OWNERSHIP); } } /** * get the sum of all of the data. */ double StatisticDataGroup::getSumOfData() const { double sum = 0.0; for (int i = 0; i < numData; i++) { sum += data[i]; } return sum; } /** * get the mean of all of the data. */ float StatisticDataGroup::getMeanOfData() const { double sum = 0.0; for (int i = 0; i < numData; i++) { sum += data[i]; } float mean = 0.0; if (numData > 0.0) { mean = sum / static_cast(numData); } return mean; } /** * assignment operator. */ StatisticDataGroup& StatisticDataGroup::operator=(const StatisticDataGroup& dataGroup) { if (this != &dataGroup) { copyHelper(dataGroup); } return *this; } /** * constructor helper (if NOT copying data, data must have been allocated with new[]). * One of dataIn and dataVectorIn MUST BE NULL so that memory is processed properly. * * @param dataIn - this should used if the data was allocated with new[] * @param dataVectorIn - this should be used if the data is stored in a float vector */ void StatisticDataGroup::constructorHelper(const float* dataIn, const std::vector* dataVectorIn, const int numDataIn, const DATA_STORAGE_MODE dataStorageModeIn) { // // Verify that there is data // data = NULL; dataVector = NULL; dataStorageMode = DATA_STORAGE_MODE_POINT; if (numData < 0) { numData = 0; } data = (float*)dataIn; dataVector = (std::vector*)dataVectorIn; dataStorageMode = dataStorageModeIn; numData = numDataIn; // // Process input parameters // switch (dataStorageMode) { case DATA_STORAGE_MODE_POINT: // // Just point to data // if (dataVector != NULL) { data = (float*)&((*dataVector)[0]); // address of first element dataVector = NULL; // prevents deletion of vector } break; case DATA_STORAGE_MODE_TAKE_OWNERSHIP: if (dataVector != NULL) { data = (float*)&((*dataVector)[0]); // address of first element } break; } } /** * subraction operator. */ StatisticDataGroup operator-(const StatisticDataGroup& a, const StatisticDataGroup& b) { float* data = NULL; int numData = 0; const int numA = a.getNumberOfData(); const int numB = b.getNumberOfData(); if (numA == numB) { if (numA > 0) { numData = numA; data = new float[numData]; for (int i = 0; i < numData; i++) { data[i] = a.getData(i) - b.getData(i); } } } else { std::cout << "PROGRAM ERROR operator-(StatisticDataGroup): different sized data groups." << std::endl; } StatisticDataGroup result(data, numData, StatisticDataGroup::DATA_STORAGE_MODE_TAKE_OWNERSHIP); return result; } caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticCorrelationCoefficient.h0000664000175000017500000000445011572067322026615 0ustar michaelmichael #ifndef __STATISTIC_CORRELATION_COEFFICIENT_H__ #define __STATISTIC_CORRELATION_COEFFICIENT_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "StatisticAlgorithm.h" /// class for computing a correlation coefficent class StatisticCorrelationCoefficient : public StatisticAlgorithm { public: // constructor StatisticCorrelationCoefficient(); // destructor ~StatisticCorrelationCoefficient(); // execute the algorithm void execute() throw (StatisticException); // get the correlation coefficient (r2 or r-squared) float getCorrelationCoefficientR2() const { return correlationCoefficientR2; } // get the correlation coefficient (r NOT r-squared) float getCorrelationCoefficientR() const { return correlationCoefficientR; } /// get the t-value float getTValue() const { return tValue; } /// get the degrees of freedom float getDegreesOfFreedom() const { return tDegreesOfFreedom; } /// get the p-value float getPValue() const { return pValue; } protected: /// the correlation coefficient R-Squared float correlationCoefficientR2; /// the correlation coefficient R float correlationCoefficientR; /// t-value float tValue; /// degrees of freedom float tDegreesOfFreedom; /// p-value float pValue; }; #endif // __STATISTIC_CORRELATION_COEFFICIENT_H__ caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticCorrelationCoefficient.cxx0000664000175000017500000000715411572067322027174 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "StatisticCorrelationCoefficient.h" #include "StatisticDataGroup.h" #include "StatisticGeneratePValue.h" /** * constructor. */ StatisticCorrelationCoefficient::StatisticCorrelationCoefficient() : StatisticAlgorithm("Correlation Coefficient") { correlationCoefficientR = 0.0; correlationCoefficientR2 = 0.0; pValue = 0.0; tValue = -1000000.0; tDegreesOfFreedom = 0.0; } /** * destructor. */ StatisticCorrelationCoefficient::~StatisticCorrelationCoefficient() { } /** * execute the algorithm. */ void StatisticCorrelationCoefficient::execute() throw (StatisticException) { correlationCoefficientR2 = 0.0; correlationCoefficientR = 0.0; pValue = 0.0; tValue = -1000000.0; tDegreesOfFreedom = 0.0; // // Check the data groups // if (getNumberOfDataGroups() != 2) { throw StatisticException("Correlation coefficient requires two and only two data groups."); } StatisticDataGroup* xGroup = getDataGroup(0); const int numData = xGroup->getNumberOfData(); StatisticDataGroup* yGroup = getDataGroup(1); if (numData != yGroup->getNumberOfData()) { throw StatisticException("Groups sent to correlation coefficient must have same number of elements."); } const float* x = xGroup->getPointerToData(); const float* y = yGroup->getPointerToData(); const double numFloat = numData; double xSum = 0.0; double x2Sum = 0.0; double ySum = 0.0; double y2Sum = 0.0; double xySum = 0.0; for (int i = 0; i < numData; i++) { xSum += x[i]; x2Sum += x[i] * x[i]; ySum += y[i]; y2Sum += y[i] * y[i]; xySum += x[i] * y[i]; } const double xMean = xSum / numFloat; const double yMean = ySum / numFloat; const double ssxx = x2Sum - (numFloat * xMean * xMean); const double ssyy = y2Sum - (numFloat * yMean * yMean); const double ssxy = xySum - (numFloat * xMean * yMean); const double denom = ssxx * ssyy; if (denom != 0.0) { correlationCoefficientR2 = static_cast((ssxy * ssxy) / denom); } if (correlationCoefficientR2 >= 0.0) { correlationCoefficientR = std::sqrt(correlationCoefficientR2); } // // T-Value calculation from: // Statistics for Psychology // Arthur Aron & Elaine Aron // 2nd Edition, 1999 // page 98-99 // float tDenom = 1.0 - correlationCoefficientR2; if (tDenom <= 1.0) { tDegreesOfFreedom = numFloat - 2.0; if (tDegreesOfFreedom >= 0.0) { const float tNum = correlationCoefficientR * std::sqrt(tDegreesOfFreedom); tValue = tNum / std::sqrt(tDenom); pValue = StatisticGeneratePValue::getOneTailTTestPValue(tDegreesOfFreedom, tValue); } } } caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticConvertToZScore.h0000664000175000017500000000320311572067322025241 0ustar michaelmichael #ifndef __STATISTIC_CONVERT_TO_Z_SCORE_H__ #define __STATISTIC_CONVERT_TO_Z_SCORE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "StatisticAlgorithm.h" /// convert the data to Z-scores Z = (x - mean) / deviation class StatisticConvertToZScore : public StatisticAlgorithm { public: // constructor StatisticConvertToZScore(); // destructor ~StatisticConvertToZScore(); // execute the algorithm call convertToZScore() to convert values to Z-scores void execute() throw (StatisticException); // call after execute to convert value to z-score void convertToZScore(float& value) const; protected: // the mean float mean; // the deviation float deviation; }; #endif // __STATISTIC_CONVERT_TO_Z_SCORE_H__ caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticConvertToZScore.cxx0000664000175000017500000000363511572067322025625 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "StatisticConvertToZScore.h" #include "StatisticDataGroup.h" #include "StatisticMeanAndDeviation.h" /** * constructor. */ StatisticConvertToZScore::StatisticConvertToZScore() : StatisticAlgorithm("Convert to Z-Score") { mean = 0.0; deviation = 1.0; } /** * destructor. */ StatisticConvertToZScore::~StatisticConvertToZScore() { } /** * execute the algorithm. */ void StatisticConvertToZScore::execute() throw (StatisticException) { // // Compute mean and deviation // StatisticMeanAndDeviation meanAndDev; for (int i = 0; i < getNumberOfDataGroups(); i++) { meanAndDev.addDataGroup(getDataGroup(i)); } meanAndDev.execute(); mean = meanAndDev.getMean(); deviation = meanAndDev.getStandardDeviation(); if (deviation == 0.0) { deviation = 1.0; } } /** * call after execute to convert value to z-score. */ void StatisticConvertToZScore::convertToZScore(float& value) const { // // Convert to Z-Scores // const float zScore = (value - mean) / deviation; value = zScore; } caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticAnovaTwoWay.h0000664000175000017500000002053311572067322024414 0ustar michaelmichael #ifndef __STATISTIC_ANOVA_TWO_WAY_H__ #define __STATISTIC_ANOVA_TWO_WAY_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "StatisticAlgorithm.h" /// this class performs a two way analysis of variance class StatisticAnovaTwoWay : public StatisticAlgorithm { public: /// ANOVA model type enum ANOVA_MODEL_TYPE { /// invalid type ANOVA_MODEL_TYPE_INVALID, /// fixed effect ANOVA_MODEL_TYPE_FIXED_EFFECT, /// random effect ANOVA_MODEL_TYPE_RANDOM_EFFECT, /// mixed effect (A=fixed, B=random) ANOVA_MODEL_TYPE_MIXED_EFFECT }; // constructor StatisticAnovaTwoWay(); // destructor ~StatisticAnovaTwoWay(); // execute the algorithm void execute() throw (StatisticException); // set the ANOVA model type void setAnovaModelType(const ANOVA_MODEL_TYPE amt); // set the number of factor levels void setNumberOfFactorLevels(const int factorLevelsInGroupA, const int factorLevelsInGroupB); // set a data group (call after "setNumberOfFactorLevels()") void setDataGroup(const int factorLevelA, const int factorLevelB, StatisticDataGroup* dataGroup, const bool takeOwnershipOfThisDataGroup = false); // set a data array (call after "setNumberOfFactorLevels()") void setDataArray(const int factorLevelA, const int factorLevelB, const float* array, const int numItemsInArray, const bool takeOwnershipOfThisDataGroup = false); /// get treatment sum of squares double getSumOfSquaresTreatmentSSTR() const { return sumOfSquaresTreatmentSSTR; } /// get error sum of squares double getSumOfSquaresErrorSSE() const { return sumOfSquaresErrorSSE; } /// get total sum of squares double getSumOfSquaresTotalSSTO() const { return sumOfSquaresTotalSSTO; } /// get sum of squares for factor A double getSumOfSquaresSSA() const { return sumOfSquaresSSA; } /// get sum of squares for factor B double getSumOfSquaresSSB() const { return sumOfSquaresSSB; } /// get sum of squares for interaction of factors A & B double getSumOfSquaresSSAB() const { return sumOfSquaresSSAB; } /// get the mean of all data values double getMeanOfAllValues() const { return meanOfAllY; } /// get a cell mean double getCellMean(const int factorLevelA, const int factorLevelB) const; /// get a factor level A mean double getMeanFactorLevelA(const int factorLevelA) const; /// get a factor level B mean double getMeanFactorLevelB(const int factorLevelB) const; /// degrees of freedom factor A double getDegreesOfFreedomFactorA() const { return degreesOfFreedomFactorA; } /// degrees of freedom factor B double getDegreesOfFreedomFactorB() const { return degreesOfFreedomFactorB; } /// degrees of freedom interactions double getDegreesOfFreedomInteractions() const { return degreesOfFreedomInteractions; } /// degrees of freedom between treatments double getDegreesOfFreedomBetweenTreatments() const { return degreesOfFreedomBetweenTreatments; } /// degrees of freedom error double getDegreesOfFreedomError() const { return degreesOfFreedomError; } /// degrees of freedom total double getDegreesOfFreedomTotal() const { return degreesOfFreedomTotal; } /// mean square factor A double getMeanSquareFactorA_MSA() const { return meanSquareFactorA_MSA; } /// mean square factor B double getMeanSquareFactorB_MSB() const { return meanSquareFactorB_MSB; } /// mean square interaction double getMeanSquareInteractionMSAB() const { return meanSquareInteractionMSAB; } /// mean square between treatments double getMeanSquareBetweenTreatmentsMSTR() const { return meanSquareBetweenTreatmentsMSTR; } /// mean square error double getMeanSquareErrorMSE() const { return meanSquareErrorMSE; } /// F-Statistic Factor A double getFStatisticFactorA() const { return fStatisticFactorA; } /// F-Statistic Factor B double getfStatisticFactorB() const { return fStatisticFactorB; } /// F-Statistic Interation double getfStatisticInteraction() const { return fStatisticInteraction; } /// P-Value for Factor A double getPValueFactorA() const { return pValueFactorA; } /// P-Value for Factor B double getPValueFactorB() const { return pValueFactorB; } /// P-Value for Interaction double getPValueInteraction() const { return pValueInteraction; } protected: // get a data group StatisticDataGroup* getDataGroup(const int factorLevelA, const int factorLevelB); // get single data group index int getDataGroupIndex(const int factorLevelA, const int factorLevelB) const; /// number of factor levels in group A int numberOfFactorLevelsGroupA; /// number of factor levels in group B int numberOfFactorLevelsGroupB; /// ANOVA model type ANOVA_MODEL_TYPE anovaModelType; /// treatment sum of squares double sumOfSquaresTreatmentSSTR; /// error sum of squares double sumOfSquaresErrorSSE; /// total sum of squares double sumOfSquaresTotalSSTO; /// sum of squares for factor A double sumOfSquaresSSA; /// sum of squares for factor B double sumOfSquaresSSB; /// sum of squares for interaction of factors A & B double sumOfSquaresSSAB; /// means of the cells double* cellMeans_Yij; /// mean of all values double meanOfAllY; /// mean of each row (group A factor level) double* meanOfFactorLevelsGroupA_Yi; /// mean of each column (group B factor level) double* meanOfFactorLevelsGroupB_Yj; /// degrees of freedom factor A double degreesOfFreedomFactorA; /// degrees of freedom factor B double degreesOfFreedomFactorB; /// degrees of freedom interactions double degreesOfFreedomInteractions; /// degrees of freedom between treatments double degreesOfFreedomBetweenTreatments; /// degrees of freedom error double degreesOfFreedomError; /// degrees of freedom total double degreesOfFreedomTotal; /// mean square factor A double meanSquareFactorA_MSA; /// mean square factor B double meanSquareFactorB_MSB; /// mean square interaction double meanSquareInteractionMSAB; /// mean square between treatments double meanSquareBetweenTreatmentsMSTR; /// mean square error double meanSquareErrorMSE; /// F-Statistic Factor A double fStatisticFactorA; /// F-Statistic Factor B double fStatisticFactorB; /// F-Statistic Interation double fStatisticInteraction; /// P-Value for Factor A double pValueFactorA; /// P-Value for Factor B double pValueFactorB; /// P-Value for Interaction double pValueInteraction; }; #endif // __STATISTIC_ANOVA_TWO_WAY_H__ caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticAnovaTwoWay.cxx0000664000175000017500000003755611572067322025004 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "StatisticAnovaTwoWay.h" #include "StatisticDataGroup.h" #include "StatisticGeneratePValue.h" /** * constructor. * Note: Factor A is in the rows, Factor B is in the columns */ StatisticAnovaTwoWay::StatisticAnovaTwoWay() : StatisticAlgorithm("ANOVA Two-Way") { cellMeans_Yij = NULL; meanOfFactorLevelsGroupA_Yi = NULL; meanOfFactorLevelsGroupB_Yj = NULL; meanOfAllY = 0.0; numberOfFactorLevelsGroupA = 0; numberOfFactorLevelsGroupB = 0; } /** * destructor. */ StatisticAnovaTwoWay::~StatisticAnovaTwoWay() { if (meanOfFactorLevelsGroupA_Yi != NULL) { delete[] meanOfFactorLevelsGroupA_Yi; meanOfFactorLevelsGroupA_Yi = NULL; } if (meanOfFactorLevelsGroupB_Yj != NULL) { delete[] meanOfFactorLevelsGroupB_Yj; meanOfFactorLevelsGroupB_Yj = NULL; } if (cellMeans_Yij != NULL) { delete[] cellMeans_Yij; cellMeans_Yij = NULL; } } /** * execute the algorithm. * Formulas are from Analysis of Variance for FMRI Data * By Douglas Ward (with modifications by Gang Chen) * January 10, 2006 * http://afni.nimh.nih.gov/afni/doc/manual/ANOVA */ void StatisticAnovaTwoWay::execute() throw (StatisticException) { sumOfSquaresTreatmentSSTR = 0.0; sumOfSquaresErrorSSE = 0.0; sumOfSquaresTotalSSTO = 0.0; sumOfSquaresSSA = 0.0; sumOfSquaresSSB = 0.0; sumOfSquaresSSAB = 0.0; switch (anovaModelType) { case ANOVA_MODEL_TYPE_INVALID: throw StatisticException("ANOVA model type is invalid."); break; case ANOVA_MODEL_TYPE_FIXED_EFFECT: break; case ANOVA_MODEL_TYPE_RANDOM_EFFECT: break; case ANOVA_MODEL_TYPE_MIXED_EFFECT: break; } // // verify that there are factor levels // if ((numberOfFactorLevelsGroupA < 2) || (numberOfFactorLevelsGroupB < 2)) { throw StatisticException("Both groups must have at least two factor levels."); } // // Verify that all arrays exist // for (int i = 0; i < numberOfFactorLevelsGroupA; i++) { for (int j = 0; j < numberOfFactorLevelsGroupB; j++) { if (getDataGroup(i, j) == NULL) { std::string msg("Factor level (" + numberToString(i) + ", " + numberToString(j) + ") is invalid (NULL)."); throw StatisticException(msg); } } } // // Verify that sample sizes are the same for all factor level combinations // const int sampleSize = getDataGroup(0, 0)->getNumberOfData(); for (int i = 0; i < numberOfFactorLevelsGroupA; i++) { for (int j = 0; j < numberOfFactorLevelsGroupB; j++) { if (getDataGroup(i, j)->getNumberOfData() != sampleSize) { std::string msg("Factor level (" + numberToString(i) + ", " + numberToString(j) + ") has a different sample size than (1, 1)."); throw StatisticException(msg); } } } if (numberOfFactorLevelsGroupA <= 0) { throw StatisticException("Number of factor levels in Group A is invalid."); } if (numberOfFactorLevelsGroupB <= 0) { throw StatisticException("Number of factor levels in Group B is invalid."); } // // Number of cells (interactions) // const int numberOfCells = getNumberOfDataGroups(); const double numberOfCellsFloat = numberOfCells; // // Determine sums and means for all cells // double allCellsSum = 0.0; double* cellSums = new double[numberOfCells]; cellMeans_Yij = new double[numberOfCells]; for (int i = 0; i < numberOfFactorLevelsGroupA; i++) { for (int j = 0; j < numberOfFactorLevelsGroupB; j++) { const int indx = getDataGroupIndex(i, j); cellSums[indx] = getDataGroup(i, j)->getSumOfData(); cellMeans_Yij[indx] = cellSums[indx] / static_cast(sampleSize); allCellsSum += cellSums[indx]; } } // // Mean for all group A's factor levels // meanOfFactorLevelsGroupA_Yi = new double[numberOfFactorLevelsGroupA]; for (int i = 0; i < numberOfFactorLevelsGroupA; i++) { double sum = 0.0; for (int j = 0; j < numberOfFactorLevelsGroupB; j++) { const int indx = getDataGroupIndex(i, j); sum += cellSums[indx]; } const double numData = numberOfFactorLevelsGroupB * sampleSize; meanOfFactorLevelsGroupA_Yi[i] = sum / numData; } // // Mean for all group B's factor levels // meanOfFactorLevelsGroupB_Yj = new double[numberOfFactorLevelsGroupB]; for (int j = 0; j < numberOfFactorLevelsGroupB; j++) { double sum = 0.0; for (int i = 0; i < numberOfFactorLevelsGroupA; i++) { const int indx = getDataGroupIndex(i, j); sum += cellSums[indx]; } const double numData = numberOfFactorLevelsGroupA * sampleSize; meanOfFactorLevelsGroupB_Yj[j] = sum / numData; } // // Overall Mean // meanOfAllY = allCellsSum / static_cast(numberOfCellsFloat * sampleSize); // // Sum of Squares Total, Treatement, Error // for (int i = 0; i < numberOfFactorLevelsGroupA; i++) { for (int j = 0; j < numberOfFactorLevelsGroupB; j++) { const int indx = getDataGroupIndex(i, j); const StatisticDataGroup* sdg = getDataGroup(i, j); for (int k = 0; k < sampleSize; k++) { // // Get the data element // const float dataValue = sdg->getData(k); // // Add into total sum of squares // const double dto = dataValue - meanOfAllY; sumOfSquaresTotalSSTO += (dto * dto); // // Add into error sum of squares // const double de = dataValue - cellMeans_Yij[indx]; sumOfSquaresErrorSSE += (de * de); } // // Add into treatment sum of squares // const double d = cellMeans_Yij[indx] - meanOfAllY; sumOfSquaresTreatmentSSTR += (d * d); } } // // Lastly, multiply by sample size (number of elements in each cell) // sumOfSquaresTreatmentSSTR *= sampleSize; // // Sum of squares for factor level A // for (int i = 0; i < numberOfFactorLevelsGroupA; i++) { const double d = meanOfFactorLevelsGroupA_Yi[i] - meanOfAllY; sumOfSquaresSSA += (d * d); } sumOfSquaresSSA *= (sampleSize * numberOfFactorLevelsGroupB); // // Sum of squares for factor level B // for (int j = 0; j < numberOfFactorLevelsGroupB; j++) { const double d = meanOfFactorLevelsGroupB_Yj[j] - meanOfAllY; sumOfSquaresSSB += (d * d); } sumOfSquaresSSB *= (sampleSize * numberOfFactorLevelsGroupA); // // Sum of squares for interaction of factors A & B // for (int i = 0; i < numberOfFactorLevelsGroupA; i++) { for (int j = 0; j < numberOfFactorLevelsGroupB; j++) { const float d = (getCellMean(i, j) - getMeanFactorLevelA(i) - getMeanFactorLevelB(j) + meanOfAllY); sumOfSquaresSSAB += (d * d); } } sumOfSquaresSSAB *= sampleSize; // // Set degrees of freedom // degreesOfFreedomFactorA = numberOfFactorLevelsGroupA - 1; degreesOfFreedomFactorB = numberOfFactorLevelsGroupB - 1; degreesOfFreedomInteractions = degreesOfFreedomFactorA * degreesOfFreedomFactorB; degreesOfFreedomBetweenTreatments = (numberOfFactorLevelsGroupA * numberOfFactorLevelsGroupB) - 1.0; degreesOfFreedomError = (numberOfFactorLevelsGroupA * numberOfFactorLevelsGroupB) * (sampleSize - 1); degreesOfFreedomTotal = (sampleSize * numberOfFactorLevelsGroupA * numberOfFactorLevelsGroupB) - 1.0; // // Mean Squares // meanSquareFactorA_MSA = sumOfSquaresSSA / degreesOfFreedomFactorA; meanSquareFactorB_MSB = sumOfSquaresSSB / degreesOfFreedomFactorB; meanSquareInteractionMSAB = sumOfSquaresSSAB / degreesOfFreedomInteractions; meanSquareBetweenTreatmentsMSTR = sumOfSquaresTreatmentSSTR / degreesOfFreedomBetweenTreatments; meanSquareErrorMSE = sumOfSquaresErrorSSE / degreesOfFreedomError; // // F-Statistics // The only difference between the models is the F-Statistic calculation // switch (anovaModelType) { case ANOVA_MODEL_TYPE_INVALID: break; case ANOVA_MODEL_TYPE_FIXED_EFFECT: fStatisticFactorA = meanSquareFactorA_MSA / meanSquareErrorMSE; fStatisticFactorB = meanSquareFactorB_MSB / meanSquareErrorMSE; fStatisticInteraction = meanSquareInteractionMSAB / meanSquareErrorMSE; break; case ANOVA_MODEL_TYPE_RANDOM_EFFECT: fStatisticFactorA = meanSquareFactorA_MSA / meanSquareInteractionMSAB; fStatisticFactorB = meanSquareFactorB_MSB / meanSquareInteractionMSAB; fStatisticInteraction = meanSquareInteractionMSAB / meanSquareErrorMSE; break; case ANOVA_MODEL_TYPE_MIXED_EFFECT: fStatisticFactorA = meanSquareFactorA_MSA / meanSquareInteractionMSAB; fStatisticFactorB = meanSquareFactorB_MSB / meanSquareErrorMSE; fStatisticInteraction = meanSquareInteractionMSAB / meanSquareErrorMSE; break; } // // Determine P-Values // pValueFactorA = StatisticGeneratePValue::getFStatisticPValue(degreesOfFreedomFactorA, degreesOfFreedomError, fStatisticFactorA); pValueFactorB = StatisticGeneratePValue::getFStatisticPValue(degreesOfFreedomFactorB, degreesOfFreedomError, fStatisticFactorB); pValueInteraction = StatisticGeneratePValue::getFStatisticPValue(degreesOfFreedomInteractions, degreesOfFreedomError, fStatisticInteraction); /* // // Determine P-Values // int which = 1; double p = 0.0; double q = 0.0; double f = fStatisticFactorA; double dfn = degreesOfFreedomFactorA; double dfd = degreesOfFreedomError; int status = 0; double bound = 0; cdff(&which, &p, &q, &f, &dfn, &dfd, &status, &bound); pValueFactorA = q; which = 1; p = 0.0; q = 0.0; f = fStatisticFactorB; dfn = degreesOfFreedomFactorB; dfd = degreesOfFreedomError; status = 0; bound = 0; cdff(&which, &p, &q, &f, &dfn, &dfd, &status, &bound); pValueFactorB = q; which = 1; p = 0.0; q = 0.0; f = fStatisticInteraction; dfn = degreesOfFreedomInteractions; dfd = degreesOfFreedomError; status = 0; bound = 0; cdff(&which, &p, &q, &f, &dfn, &dfd, &status, &bound); pValueInteraction = q; */ delete[] cellSums; } /** * set the ANOVA model type. */ void StatisticAnovaTwoWay::setAnovaModelType(const ANOVA_MODEL_TYPE amt) { anovaModelType = amt; } /** * set the number of factor levels. */ void StatisticAnovaTwoWay::setNumberOfFactorLevels(const int factorLevelsInGroupA, const int factorLevelsInGroupB) { numberOfFactorLevelsGroupA = factorLevelsInGroupA; numberOfFactorLevelsGroupB = factorLevelsInGroupB; const int numberOfDataGroups = numberOfFactorLevelsGroupA * numberOfFactorLevelsGroupB; setNumberOfDataGroups(numberOfDataGroups); } /** * set a data group (call after "setNumberOfFactorLevels()"). */ void StatisticAnovaTwoWay::setDataGroup(const int factorLevelA, const int factorLevelB, StatisticDataGroup* dataGroup, const bool takeOwnershipOfThisDataGroup) { const int indx = getDataGroupIndex(factorLevelA, factorLevelB); if (indx >= 0) { StatisticAlgorithm::setDataGroup(indx, dataGroup, takeOwnershipOfThisDataGroup); } } /** * set a data array (call after "setNumberOfFactorLevels()"). */ void StatisticAnovaTwoWay::setDataArray(const int factorLevelA, const int factorLevelB, const float* array, const int numItemsInArray, const bool takeOwnershipOfThisDataArray) { const int indx = getDataGroupIndex(factorLevelA, factorLevelB); if (indx >= 0) { StatisticDataGroup::DATA_STORAGE_MODE storageMode = StatisticDataGroup::DATA_STORAGE_MODE_POINT; if (takeOwnershipOfThisDataArray) { storageMode = StatisticDataGroup::DATA_STORAGE_MODE_TAKE_OWNERSHIP; } StatisticDataGroup* sdg = new StatisticDataGroup(array, numItemsInArray, storageMode); StatisticAlgorithm::setDataGroup(indx, sdg, true); } } /** * get a data group. */ StatisticDataGroup* StatisticAnovaTwoWay::getDataGroup(const int factorLevelA, const int factorLevelB) { const int indx = getDataGroupIndex(factorLevelA, factorLevelB); if (indx >= 0) { return StatisticAlgorithm::getDataGroup(indx); } return NULL; } /** * get single data group index. */ int StatisticAnovaTwoWay::getDataGroupIndex(const int factorLevelA, const int factorLevelB) const { const int indx = (factorLevelA * numberOfFactorLevelsGroupB) + factorLevelB; if ((indx < 0) || (indx >= getNumberOfDataGroups())) { return -1; } return indx; } /** * get a cell mean. */ double StatisticAnovaTwoWay::getCellMean(const int factorLevelA, const int factorLevelB) const { const int indx = (factorLevelA * numberOfFactorLevelsGroupB) + factorLevelB; if ((indx < 0) || (indx >= getNumberOfDataGroups())) { return 0.0; } return cellMeans_Yij[indx]; } /** * get a factor level A mean. */ double StatisticAnovaTwoWay::getMeanFactorLevelA(const int factorLevelA) const { return meanOfFactorLevelsGroupA_Yi[factorLevelA]; } /** * get a factor level B mean. */ double StatisticAnovaTwoWay::getMeanFactorLevelB(const int factorLevelB) const { return meanOfFactorLevelsGroupB_Yj[factorLevelB]; } caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticAnovaOneWay.h0000664000175000017500000000651411572067322024367 0ustar michaelmichael #ifndef __STATISTIC_ANOVA_ONE_WAY_H__ #define __STATISTIC_ANOVA_ONE_WAY_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "StatisticAlgorithm.h" /// class that performs a one way analysis of variance class StatisticAnovaOneWay : public StatisticAlgorithm { public: // constructor StatisticAnovaOneWay(); // destructor ~StatisticAnovaOneWay(); // execute the algorithm void execute() throw (StatisticException); /// get treatment sum of squares double getSumOfSquaresTreatmentSSTR() const { return sumOfSquaresTreatmentSSTR; } /// get error sum of squares double getSumOfSquaresErrorSSE() const { return sumOfSquaresErrorSSE; } /// total sum of squares double getSumOfSquaresTotalSSTO() const { return sumOfSquaresTotalSSTO; } /// mean treatment sum of squares double getMeanSumOfSquaresTreatmentMSTR() const { return meanSumOfSquaresTreatmentMSTR; } /// mean error sum of squares double getMeanSumOfSquaresErrorMSE() const { return meanSumOfSquaresErrorMSE; } /// between treatment degrees of freedom double getDegreesOfFreedomBetweenTreatments() const { return degreesOfFreedomBetweenTreatments; } /// within treatment degrees of freedom double getDegreesOfFreedomWithinTreatments() const { return degreesOfFreedomWithinTreatments; } /// degrees of freedom total double getDegreesOfFreedomTotal() const { return degreesOfFreedomTotal; } /// F statistic double getFStatistic() const { return fStatistic; } /// P-Value double getPValue() const { return pValue; } protected: /// treatment sum of squares double sumOfSquaresTreatmentSSTR; /// error sum of squares double sumOfSquaresErrorSSE; /// total sum of squares double sumOfSquaresTotalSSTO; /// mean treatment sum of squares double meanSumOfSquaresTreatmentMSTR; /// mean error sum of squares double meanSumOfSquaresErrorMSE; /// between treatment degrees of freedom double degreesOfFreedomBetweenTreatments; /// within treatment degrees of freedom double degreesOfFreedomWithinTreatments; /// degrees of freedom total double degreesOfFreedomTotal; /// F statistic double fStatistic; /// P-Value double pValue; }; #endif // __STATISTIC_ANOVA_ONE_WAY_H__ caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticAnovaOneWay.cxx0000664000175000017500000001330411572067322024735 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "StatisticAnovaOneWay.h" #include "StatisticDataGroup.h" #include "StatisticGeneratePValue.h" #include "StatisticMeanAndDeviation.h" /** * constructor. */ StatisticAnovaOneWay::StatisticAnovaOneWay() : StatisticAlgorithm("ANOVA One-Way") { } /** * destructor. */ StatisticAnovaOneWay::~StatisticAnovaOneWay() { } /** * execute the algorithm. * Formulas are from Analysis of Variance for FMRI Data * By Douglas Ward (with modifications by Gang Chen) * January 10, 2006 * http://afni.nimh.nih.gov/afni/doc/manual/ANOVA */ void StatisticAnovaOneWay::execute() throw (StatisticException) { sumOfSquaresTreatmentSSTR = 0.0; sumOfSquaresErrorSSE = 0.0; sumOfSquaresTotalSSTO = 0.0; meanSumOfSquaresTreatmentMSTR = 0.0; meanSumOfSquaresErrorMSE = 0.0; degreesOfFreedomBetweenTreatments = 0.0; degreesOfFreedomWithinTreatments = 0.0; degreesOfFreedomTotal = 0.0; fStatistic = 0.0; pValue = 0.0; // // Verify that there are groups. Each group is a factor level. // const int numberOfFactorLevelsR = getNumberOfDataGroups(); if (numberOfFactorLevelsR < 2) { throw StatisticException("One-way ANOVA requires at least two data groups."); } // // Data Groups and Number of observations in each factor level // std::vector dataGroupObservations(numberOfFactorLevelsR); std::vector numberOfObservationsN(numberOfFactorLevelsR); for (int i = 0; i < numberOfFactorLevelsR; i++) { dataGroupObservations[i] = getDataGroup(i); numberOfObservationsN[i] = dataGroupObservations[i]->getNumberOfData(); } // // Compute mean at each factor and overall mean // double overallMeanYBar = 0.0; int totalOfObservationsY = 0; std::vector factorMeanYiBar(numberOfFactorLevelsR, 0.0); for (int i = 0; i < numberOfFactorLevelsR; i++) { const int ni = numberOfObservationsN[i]; for (int j = 0; j < ni; j++) { factorMeanYiBar[i] += dataGroupObservations[i]->getData(j); } totalOfObservationsY += ni; overallMeanYBar += factorMeanYiBar[i]; factorMeanYiBar[i] /= static_cast(ni); } overallMeanYBar /= static_cast(totalOfObservationsY); // // Compute the various Sums Of Squares // for (int i = 0; i < numberOfFactorLevelsR; i++) { // // Treatment Sum Of Squares // const double tr = (factorMeanYiBar[i] - overallMeanYBar); sumOfSquaresTreatmentSSTR += (numberOfObservationsN[i] * tr * tr); const int numObsI = numberOfObservationsN[i]; for (int j = 0; j < numObsI; j++) { // // Data element "j" of the i'th factor // const float Yij = dataGroupObservations[i]->getData(j); // // error sum of squares // const double te = (Yij - factorMeanYiBar[i]); sumOfSquaresErrorSSE += (te * te); // // total sum of squares // const double ts = (Yij - overallMeanYBar); sumOfSquaresTotalSSTO += (ts * ts); } } // // Between treatments degrees of freedom // degreesOfFreedomBetweenTreatments = numberOfFactorLevelsR - 1; // // Within treatments degrees of freedom // for (int i = 0; i < numberOfFactorLevelsR; i++) { degreesOfFreedomWithinTreatments += numberOfObservationsN[i]; } degreesOfFreedomWithinTreatments -= numberOfFactorLevelsR; // // Total degrees of freedom // for (int i = 0; i < numberOfFactorLevelsR; i++) { degreesOfFreedomTotal += numberOfObservationsN[i]; } degreesOfFreedomTotal -= 1.0; // // Mean treatment sum of squares // meanSumOfSquaresTreatmentMSTR = sumOfSquaresTreatmentSSTR / degreesOfFreedomBetweenTreatments; // // mean error sum of squares // meanSumOfSquaresErrorMSE = sumOfSquaresErrorSSE / degreesOfFreedomWithinTreatments; // // F-statistic // if (meanSumOfSquaresErrorMSE == 0) { throw StatisticException("Unable to compute F-statistic because mean sum of squares (MSE) is zero."); } fStatistic = meanSumOfSquaresTreatmentMSTR / meanSumOfSquaresErrorMSE; pValue = StatisticGeneratePValue::getFStatisticPValue(degreesOfFreedomBetweenTreatments, degreesOfFreedomWithinTreatments, fStatistic); /* // // Determine P-Value // int which = 1; double p = 0.0; double q = 0.0; double f = fStatistic; double dfn = degreesOfFreedomBetweenTreatments; double dfd = degreesOfFreedomWithinTreatments; int status = 0; double bound = 0; cdff(&which, &p, &q, &f, &dfn, &dfd, &status, &bound); pValue = q; */ } caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticAlgorithm.h0000664000175000017500000000736211572067322024130 0ustar michaelmichael #ifndef __STATISTIC_ALGORITHM_H__ #define __STATISTIC_ALGORITHM_H__ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "StatisticException.h" class StatisticDataGroup; /// abstract class for a statistical operation class StatisticAlgorithm { public: // constructor StatisticAlgorithm(const std::string& algorithmNameIn); // destructor virtual ~StatisticAlgorithm(); // add a data array group to this algorithm int addDataArray(const float array[], const int numItemsInArray, const bool takeOwnershipOfThisDataGroup = false); // add a data group to this algorithm int addDataGroup(StatisticDataGroup* dataGroup, const bool takeOwnershipOfThisDataGroup = false); // execute the algorithm virtual void execute() throw (StatisticException) = 0; // get the number of data groups inline int getNumberOfDataGroups() const { return dataGroups.size(); } // get a data group StatisticDataGroup* getDataGroup(const int indx) { return dataGroups[indx]; } // get a data group (const method) const StatisticDataGroup* getDataGroup(const int indx) const { return dataGroups[indx]; } /// turn on/off debugging of ALL algorithms static void setDebugOn(const bool onOff) { debugOnFlag = onOff; } /// see if debugging is on static bool getDebugOn() { return debugOnFlag; } /// get the name of the algorithm std::string getAlgorithmName() const { return algorithmName; } protected: // get all of the data values in a vector void getAllDataValues(std::vector& values, const bool sortTheValues) const; // set the number of data groups (note: "dataGroups" is resized but still contains NULL pointers) void setNumberOfDataGroups(const int numDataGroups); // set a data group void setDataGroup(const int indx, StatisticDataGroup* dataGroup, const bool takeOwnershipOfThisDataGroup = false); // convert an integer to a standard string static std::string numberToString(const int i); // convert a double to a standard string static std::string numberToString(const double d, const int digitsRightOfDecimal = 3); /// the data groups std::vector dataGroups; /// own the data group std::vector ownDataGroup; /// name of the algorithm std::string algorithmName; /// debug flag for all algorithms static bool debugOnFlag; }; #ifdef __STATISTIC_ALGORITHM_MAIN__ bool StatisticAlgorithm::debugOnFlag = false; #endif // __STATISTIC_ALGORITHM_MAIN__ #endif // __STATISTIC_ALGORITHM_H__ caret-5.6.4~dfsg.1.orig/caret_statistics/StatisticAlgorithm.cxx0000664000175000017500000001057011572067322024476 0ustar michaelmichael/* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #define __STATISTIC_ALGORITHM_MAIN__ #include "StatisticAlgorithm.h" #undef __STATISTIC_ALGORITHM_MAIN__ #include "StatisticDataGroup.h" /** * constructor. */ StatisticAlgorithm::StatisticAlgorithm(const std::string& algorithmNameIn) { algorithmName = algorithmNameIn; } /** * destructor. */ StatisticAlgorithm::~StatisticAlgorithm() { for (int i = 0; i < getNumberOfDataGroups(); i++) { if (ownDataGroup[i]) { if (dataGroups[i] != NULL) { delete dataGroups[i]; } } dataGroups[i] = NULL; } dataGroups.clear(); ownDataGroup.clear(); } /** * add a data array group to this algorithm. * If "takeOwnershipOfTheData" is set, the array must have been allocated with new[]. */ int StatisticAlgorithm::addDataArray(const float* array, const int numItemsInArray, const bool takeOwnershipOfTheData) { StatisticDataGroup::DATA_STORAGE_MODE storageMode = StatisticDataGroup::DATA_STORAGE_MODE_POINT; if (takeOwnershipOfTheData) { storageMode = StatisticDataGroup::DATA_STORAGE_MODE_TAKE_OWNERSHIP; } StatisticDataGroup* sdg = new StatisticDataGroup(array, numItemsInArray, storageMode); dataGroups.push_back(sdg); ownDataGroup.push_back(true); // created data group here so it must be deleted return (getNumberOfDataGroups() - 1); } /** * add a data group to this algorithm. */ int StatisticAlgorithm::addDataGroup(StatisticDataGroup* dataGroup, const bool takeOwnershipOfThisDataGroup) { dataGroups.push_back(dataGroup); ownDataGroup.push_back(takeOwnershipOfThisDataGroup); return (getNumberOfDataGroups() - 1); } /** * set a data group. */ void StatisticAlgorithm::setDataGroup(const int indx, StatisticDataGroup* dataGroup, const bool takeOwnershipOfThisDataGroup) { dataGroups[indx] = dataGroup; ownDataGroup[indx] = takeOwnershipOfThisDataGroup; } /** * set the number of data groups (note: "dataGroups" is resized but still contains NULL pointers). */ void StatisticAlgorithm::setNumberOfDataGroups(const int numDataGroups) { if (numDataGroups > 0) { dataGroups.resize(numDataGroups, NULL); ownDataGroup.resize(numDataGroups, false); } } /** * get all of the data values in a vector. */ void StatisticAlgorithm::getAllDataValues(std::vector& values, const bool sortTheValues) const { values.clear(); for (int i = 0; i < getNumberOfDataGroups(); i++) { const int num = dataGroups[i]->numData; const float* d = dataGroups[i]->data; for (int j = 0; j < num; j++) { values.push_back(d[j]); } } if (sortTheValues) { std::sort(values.begin(), values.end()); } } /** * convert an integer to a standard string. */ std::string StatisticAlgorithm::numberToString(const int i) { std::ostringstream str; str << i; const std::string s = str.str(); return s; } /** * convert a double to a standard string. */ std::string StatisticAlgorithm::numberToString(const double d, const int digitsRightOfDecimal) { std::ostringstream str; str.precision(digitsRightOfDecimal); str << std::fixed << d; const std::string s = str.str(); return s; } caret-5.6.4~dfsg.1.orig/caret_statistics/.project0000664000175000017500000000437511572067322021611 0ustar michaelmichael caret_statistics org.eclipse.cdt.managedbuilder.core.genmakebuilder clean,full,incremental, ?name? org.eclipse.cdt.make.core.append_environment true org.eclipse.cdt.make.core.autoBuildTarget all org.eclipse.cdt.make.core.buildArguments org.eclipse.cdt.make.core.buildCommand make org.eclipse.cdt.make.core.cleanBuildTarget clean org.eclipse.cdt.make.core.contents org.eclipse.cdt.make.core.activeConfigSettings org.eclipse.cdt.make.core.enableAutoBuild false org.eclipse.cdt.make.core.enableCleanBuild true org.eclipse.cdt.make.core.enableFullBuild true org.eclipse.cdt.make.core.fullBuildTarget all org.eclipse.cdt.make.core.stopOnError true org.eclipse.cdt.make.core.useDefaultBuildCmd true org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder org.eclipse.cdt.core.cnature org.eclipse.cdt.core.ccnature org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature caret-5.6.4~dfsg.1.orig/caret_statistics/.cproject0000664000175000017500000002073311572067322021750 0ustar michaelmichael make all true true true caret-5.6.4~dfsg.1.orig/caret_scripts/0000775000175000017500000000000011572067322017426 5ustar michaelmichaelcaret-5.6.4~dfsg.1.orig/caret_scripts/smooth_medial_wall.py0000755000175000017500000001047411572067322023652 0ustar michaelmichael#!/usr/bin/python # # Imports # import os import sys # # Global Variables # progName = "/Users/john/caret5_osx/caret_source/caret_command/caret_command" #progName = "caret_command" areaColorFileName = "Geography.areacolor" separateBorderProjectionFileName = "MedialWall_Separate.borderproj" mergedBorderProjectionFileName = "MedialWall_Merged.borderproj" borderColorFileName = "LANDMARK.bordercolor" medialWallBorderName = "LANDMARK.MEDIAL.WALL" fiducialCoordFileName = "Human.colin.Cerebral.R.FIDUCIAL.TLRC.711-2B.71723.coord" smoothedFiducialCoordFileName = "Human.colin.Cerebral.R.FIDUCIAL_SMOOTHED.TLRC.711-2B.71723.coord" inflatedCoordFileName = "Human.colin.Cerebral.R.INFLATED.71723.coord" paintFileName = "MedialWall.paint" paintName = "MEDIAL.WALL" roiFileName = "medial_wall.roi" surfaceShapeFileName = "Curvature.surface_shape" topologyFileName = "Human.colin.Cerebral.R.CLOSED.71723.topo" ##----------------------------------------------------------------------------- # # Run a command # def runCommand(cmdList) : cmd = " ".join(cmdList) # join cmdList into a string separated by blanks print "\nExecuting: %s\n" % cmd result = os.system(cmd) if (result != 0) : print "COMMAND FAILED: " print " ", cmd os._exit(-1) ##----------------------------------------------------------------------------- # # Main # # # Merge the two medial wall borders into a single border # cmdList = (progName, "-surface-border-merge", separateBorderProjectionFileName, mergedBorderProjectionFileName, medialWallBorderName, "LANDMARK.MedWall.DORSAL", "LANDMARK.MedWall.VENTRAL", "-delete-input-border-projections", "-close-border") runCommand(cmdList) # # Resample the border # cmdList = (progName, "-surface-border-resample", fiducialCoordFileName, topologyFileName, mergedBorderProjectionFileName, mergedBorderProjectionFileName, str(2.0), "-all") runCommand(cmdList) # # Create a region of interest that contains nodes within # the medial wall border projection # cmdList = (progName, "-surface-region-of-interest-selection", inflatedCoordFileName, topologyFileName, roiFileName, roiFileName, "-border-projection", mergedBorderProjectionFileName, medialWallBorderName, "M", "3D", 0, "NORMAL") runCommand(cmdList) # # Create the color for the medial wall paint # cmdList = (progName, "-color-file-add-color", areaColorFileName, areaColorFileName, paintName, str(255), str(0), str(0)) runCommand(cmdList) # # Create the color for the medial wall border # cmdList = (progName, "-color-file-add-color", borderColorFileName, borderColorFileName, medialWallBorderName, str(255), str(0), str(0)) runCommand(cmdList) # # Create a NEW paint file with one column named "Geography" # cmdList = (progName, "-paint-file-create", paintFileName, str(1), "-coordinate-file", inflatedCoordFileName, "-set-column-name 1 Geography") runCommand(cmdList) # # Assign nodes in ROI to paint # cmdList = (progName, "-paint-assign-to-nodes", paintFileName, paintFileName, str(1), paintName, "-assign-from-roi-file", roiFileName) runCommand(cmdList) # # Smooth the medial wall # cmdList = (progName, "-surface-smoothing", fiducialCoordFileName, smoothedFiducialCoordFileName, topologyFileName, str(1.0), str(50), str(-1), "-roi-file ", roiFileName) runCommand(cmdList) # # Generate curvature # cmdList = (progName, "-surface-curvature", smoothedFiducialCoordFileName, topologyFileName, surfaceShapeFileName, surfaceShapeFileName, "-generate-mean-curvature", "-mean-column-name \"Folding (Mean Curvature) MWS\"") runCommand(cmdList) caret-5.6.4~dfsg.1.orig/caret_scripts/run_sulcal_id_threads.py0000755000175000017500000007742411572067322024354 0ustar michaelmichael#!/usr/bin/python # # Run sulcal identification on buckner case 01-12 left and right # caretCommand = "C:/caret/bin/caret_command" caretCommand = "/Users/john/caret5_development/caret5_cpp/caret_source/caret_command/caret_command" import os import re import time import subprocess import sys from threading import Thread ##----------------------------------------------------------------------------- # # Run a command # def runCommand(cmd) : print "\nExecuting: %s\n" % cmd result = os.system(cmd) if (result != 0) : print "ERROR COMMAND FAILED: " print " ", cmd ##----------------------------------------------------------------------------- # # Add file to spec file # def addToSpecFile(specFileName, specFileTag, fileName) : cmdList = ( caretCommand, "-spec-file-add", specFileName, specFileTag, fileName) runCommand(cmdList) ##----------------------------------------------------------------------------- # # Class that runs a command in a thread. # If the command sent to the constructor is a list, each item in the list # is executed as a command sequentially # class RunCommandInThread(Thread): # # Constructor # "commandIn" may be either a command or a list containing commands # def __init__ (self, commandIn): Thread.__init__(self) # # If input is a string, place it into a list # If input is a list, it's ok # if isinstance(commandIn, str): self.commandList = [commandIn] elif isinstance(commandIn, list): self.commandList = commandIn else: self.commandList = [] #print "RunCommandInThread commandList:", self.commandList #print "RunCommandInThread commandIn:", commandIn #print "RunCommandInThread type(commandIn):", type(commandIn) def run(self): if len(self.commandList) == 0: print "ERROR COMMAND LIST EMPTY" return for cmd in self.commandList: p = subprocess.Popen(cmd, shell=True) result = p.wait() #result = os.waitpid(p.pid, 0) if (result != 0) : print "ERROR COMMAND FAILED: " print " ", cmd ##----------------------------------------------------------------------------- # # Run a a list of commands in multiple threads # class RunCommandsInMultipleThreads(Thread): def __init__(self, commandList, numberOfThreads): Thread.__init__(self) self.commandList = commandList self.maximumNumberOfThreads = numberOfThreads def run(self): if len(self.commandList) == 0: print "ERROR: List of commands is empty" return numberOfCommandsToRun = len(self.commandList) i = 0 while i < numberOfCommandsToRun: # # Determine how many threads to create # numThreadsToCreate = self.maximumNumberOfThreads numCommandsLeft = numberOfCommandsToRun - i if (numCommandsLeft < numThreadsToCreate) : numThreadsToCreate = numCommandsLeft # # Get directories that are to be executed # commandsToRunList = [] j = 0 while j < numThreadsToCreate: commandsToRunList.append(self.commandList[i]) i = i + 1 j = j + 1 # # Execute the directories # threadList = [] for commandToRun in commandsToRunList : print "STARTING: ", commandToRun cmdThread = RunCommandInThread(commandToRun) threadList.append(cmdThread) cmdThread.start() for thread in threadList: thread.join() ##----------------------------------------------------------------------------- # # Build add file to spec file command # def buildAddToSpecFileCommand(directoryName, specFileName, specFileTag, fileName) : #if (os.path.exists(fileName)) : cmdList = ( caretCommand, "-spec-file-add", "-CHDIR", directoryName, specFileName, specFileTag, fileName) commandText = " ".join(cmdList) return commandText ##----------------------------------------------------------------------------- # # Create an image of the first scene # def buildCreateSceneImageCommand(directoryName, sceneNumberInString) : # # Get files in directory # files = os.listdir(directoryName) # # Find the fiducial coord file to get case, hemisphere nodes # case = "" hem = "" nodes = "" # for filename in files: # if (filename.find("Fiducial") >= 0) : # #print "Fiducial", filename # m = re.match(r"Human\.Buckner(Case\d\d)\.([L|R])\.Fiducial\.(\d+)\.coord", # filename) # # case = m.group(1) # hem = m.group(2) # nodes = m.group(3) # # break # # Find the fiducial coord file to get case, hemisphere nodes # case = "" hem = "" nodes = "" for filename in files: if (filename.find("Human.BucknerCase") >= 0) : if (filename.find(".spec") >= 0) : #print "SpecFile", filename m = re.match("Human.Buckner(Case\d\d)\.([L|R])\.spec", filename) case = m.group(1) hem = m.group(2) break #print "case ", case #print "hem ", hem #print "nodes ", nodes # # Put together the data file names # sceneFileName = "Human.BUCKNER" + case + "." + hem + ".Landmarks.scene" specFileName = "Human.Buckner" + case + "." + hem + ".spec" imageFileName = "Landmarks." + case + "." + hem + ".jpg" # # Scene # idCmdList = ( caretCommand, "-show-scene", "-CHDIR", directoryName, "-CHMOD", "UR,UW,GR,GW,AR,AW", specFileName, sceneFileName, sceneNumberInString, "-image-file", imageFileName, "3" ) commandList = [" ".join(idCmdList)] # # Add text to image # idCmdList = ( caretCommand, "-image-insert-text", "-CHDIR", directoryName, "-CHMOD", "UR,UW,GR,GW,AR,AW", imageFileName, imageFileName, "20", "20", "255", "0", "0", case) commandList.append(" ".join(idCmdList)) return commandList ##----------------------------------------------------------------------------- # # Assemble images command. # def buildAssembleImagesCommand(compositeImageFileName, allDirectoryNames) : # # Command # idCmdList = ( caretCommand, "-image-combine", "-CHMOD", "UR,UW,GR,GW,AR,AW", "1", compositeImageFileName) for directoryName in allDirectoryNames: # # Get files in directory # files = os.listdir(directoryName) # # Find the fiducial coord file to get case, hemisphere nodes # case = "" hem = "" nodes = "" # # Find the fiducial coord file to get case, hemisphere nodes # case = "" hem = "" nodes = "" for filename in files: if (filename.find("Human.BucknerCase") >= 0) : if (filename.find(".spec") >= 0) : #print "Fiducial", filename m = re.match("Human.Buckner(Case\d\d)\.([L|R])\.spec", filename) case = m.group(1) hem = m.group(2) break # for filename in files: # if (filename.find("Fiducial") >= 0) : # #print "Fiducial", filename # m = re.match(r"Human\.Buckner(Case\d\d)\.([L|R])\.Fiducial\.(\d+)\.coord", # filename) # # case = m.group(1) # hem = m.group(2) # nodes = m.group(3) # # break # # Put together the data file names # imageFileName = directoryName + "/Landmarks." + case + "." + hem + ".jpg" # # If image file exists # if os.path.exists(imageFileName) : # # Add to command # Semicolon near end of line is needed to make it a tuple # idCmdList = idCmdList + (imageFileName,) # # Final command # command = " ".join(idCmdList) return command ##----------------------------------------------------------------------------- # # Clean spec file commands # def buildCleanSpecFileCommand(directoryName) : # # Get files in directory # files = os.listdir(directoryName) # # Find the fiducial coord file to get case, hemisphere nodes # case = "" hem = "" nodes = "" for filename in files: if (filename.find("Fiducial") >= 0) : #print "Fiducial", filename m = re.match(r"Human\.Buckner(Case\d\d)\.([L|R])\.Fiducial\.(\d+)\.coord", filename) case = m.group(1) hem = m.group(2) nodes = m.group(3) break #print "case ", case #print "hem ", hem #print "nodes ", nodes # # Put together the data file names # specFileName = "Human.Buckner" + case + "." + hem + ".spec" # # Scene # idCmdList = ( caretCommand, "-spec-file-clean", "-CHDIR", directoryName, "-CHMOD", "UR,UW,GR,GW,AR,AW", specFileName ) commandList = [" ".join(idCmdList)] return commandList ##----------------------------------------------------------------------------- # # Build create medial wall scene command list and return it # def buildCreateMedialWallSceneCommand(directoryName) : # # Get files in directory # files = os.listdir(directoryName) # # Find the fiducial coord file to get case, hemisphere nodes # case = "" hem = "" nodes = "" for filename in files: if (filename.find("Fiducial") >= 0) : #print "Fiducial", filename m = re.match(r"Human\.Buckner(Case\d\d)\.([L|R])\.Fiducial\.(\d+)\.coord", filename) case = m.group(1) hem = m.group(2) nodes = m.group(3) break #print "case ", case #print "hem ", hem #print "nodes ", nodes # # Put together the data file names # sceneFileName = "Human.BUCKNER" + case + "." + hem + ".Landmarks.scene" specFileName = "Human.Buckner" + case + "." + hem + ".spec" # # Corpus Callosum Slice # idCmdList = ( caretCommand, "-scene-create", "-CHDIR", directoryName, "-CHMOD", "UR,UW,GR,GW,AR,AW", specFileName, sceneFileName, sceneFileName, "Corpus_Callosum", "-window-volume-coord", "WINDOW_MAIN", "512", "512", "PARASAGITTAL", "0.0", "0.0", "0.0", "-volume-overlay", "PRIMARY", "SEGMENTATION", "-volume-overlay", "UNDERLAY", "ANATOMY", "-volume-overlay-segmentation", "CorpusCallosum.nii.gz", "1", "-show-borders", "-show-foci", "-window-surface-types", "WINDOW_2", "512", "512", "FIDUCIAL", "CLOSED", "MEDIAL", "-window-surface-types", "WINDOW_3", "512", "512", "INFLATED", "CLOSED", "MEDIAL", "-surface-overlay", "PRIMARY", "PAINT", "\"Sulcal Identification\"", "0", "-show-borders", "-show-foci" ) commandList = [" ".join(idCmdList)] # # Fiducial Medial # idCmdList = ( caretCommand, "-scene-create", "-CHDIR", directoryName, "-CHMOD", "UR,UW,GR,GW,AR,AW", specFileName, sceneFileName, sceneFileName, "Fiducial_Medial", "-window-surface-types", "WINDOW_MAIN", "512", "512", "FIDUCIAL", "CLOSED", "MEDIAL", "-show-borders", "-show-foci" ) #commandList.append(" ".join(idCmdList)) # # Update the spec file # commandList.append(buildAddToSpecFileCommand(directoryName, specFileName, "scene_file", sceneFileName)) return commandList ##----------------------------------------------------------------------------- # # Build create border scene command list and return it # def buildEkrBorderSceneCommand(directoryName) : # # Get files in directory # files = os.listdir(directoryName) # # Find the fiducial coord file to get case, hemisphere nodes # case = "" hem = "" nodes = "" for filename in files: if (filename.find("Human.BucknerCase") >= 0) : #print "Fiducial", filename m = re.match("Human.Buckner(Case\d\d)\.([L|R])\.spec", filename) case = m.group(1) hem = m.group(2) break #print "case ", case #print "hem ", hem #print "nodes ", nodes # # Put together the data file names # sceneFileName = "Human.BUCKNER" + case + "." + hem + ".Landmarks.scene" specFileName = "Human.Buckner" + case + "." + hem + ".spec" # # Corpus Callosum Slice # idCmdList = ( caretCommand, "-scene-create", "-CHDIR", directoryName, "-CHMOD", "UR,UW,GR,GW,AR,AW", specFileName, "\"\"", sceneFileName, "Landmarks", "-window-surface-types", "WINDOW_MAIN", "512", "512", "FIDUCIAL", "CLOSED", "MEDIAL", "-window-surface-types", "WINDOW_2", "512", "512", "VERY_INFLATED", "CLOSED", "LATERAL", "-window-surface-types", "WINDOW_3", "512", "512", "INFLATED", "CLOSED", "MEDIAL", "-surface-overlay", "UNDERLAY", "SURFACE_SHAPE", "\"Folding (Mean Curvature)\"", "0", "-show-borders" ) commandList = [" ".join(idCmdList)] # # Fiducial Medial # idCmdList = ( caretCommand, "-scene-create", "-CHDIR", directoryName, "-CHMOD", "UR,UW,GR,GW,AR,AW", specFileName, sceneFileName, sceneFileName, "Fiducial_Medial", "-window-surface-types", "WINDOW_MAIN", "512", "512", "FIDUCIAL", "CLOSED", "MEDIAL", "-show-borders", "-show-foci" ) #commandList.append(" ".join(idCmdList)) # # Update the spec file # commandList.append(buildAddToSpecFileCommand(directoryName, specFileName, "scene_file", sceneFileName)) return commandList ##----------------------------------------------------------------------------- # # Build create border scene command list and return it # def buildCreateBorderSceneCommand(directoryName) : # # Get files in directory # files = os.listdir(directoryName) # # Find the fiducial coord file to get case, hemisphere nodes # case = "" hem = "" nodes = "" for filename in files: if (filename.find("Fiducial") >= 0) : #print "Fiducial", filename m = re.match(r"Human\.Buckner(Case\d\d)\.([L|R])\.Fiducial\.(\d+)\.coord", filename) case = m.group(1) hem = m.group(2) nodes = m.group(3) break #print "case ", case #print "hem ", hem #print "nodes ", nodes # # Put together the data file names # sceneFileName = "Human.BUCKNER" + case + "." + hem + ".Landmarks.scene" specFileName = "Human.Buckner" + case + "." + hem + ".spec" # # Corpus Callosum Slice # idCmdList = ( caretCommand, "-scene-create", "-CHDIR", directoryName, "-CHMOD", "UR,UW,GR,GW,AR,AW", specFileName, "\"\"", sceneFileName, "Landmarks", "-window-surface-types", "WINDOW_MAIN", "512", "512", "FIDUCIAL", "CLOSED", "MEDIAL", "-window-surface-types", "WINDOW_2", "512", "512", "VERY_INFLATED", "CLOSED", "LATERAL", "-window-surface-types", "WINDOW_3", "512", "512", "INFLATED", "CLOSED", "MEDIAL", "-surface-overlay", "UNDERLAY", "SURFACE_SHAPE", "\"Folding (Mean Curvature)\"", "0", "-show-borders" ) commandList = [" ".join(idCmdList)] # # Fiducial Medial # idCmdList = ( caretCommand, "-scene-create", "-CHDIR", directoryName, "-CHMOD", "UR,UW,GR,GW,AR,AW", specFileName, sceneFileName, sceneFileName, "Fiducial_Medial", "-window-surface-types", "WINDOW_MAIN", "512", "512", "FIDUCIAL", "CLOSED", "MEDIAL", "-show-borders", "-show-foci" ) #commandList.append(" ".join(idCmdList)) # # Update the spec file # commandList.append(buildAddToSpecFileCommand(directoryName, specFileName, "scene_file", sceneFileName)) return commandList ##----------------------------------------------------------------------------- # # Build a sulcal id command list and return it # def buildSulcalIdCommand(directoryName) : # # Get files in directory # files = os.listdir(directoryName) # # Find the fiducial coord file to get case, hemisphere nodes # case = "" hem = "" nodes = "" for filename in files: if (filename.find("Fiducial") >= 0) : #print "Fiducial", filename m = re.match(r"Human\.Buckner(Case\d\d)\.([L|R])\.Fiducial\.(\d+)\.coord", filename) case = m.group(1) hem = m.group(2) nodes = m.group(3) break #print "case ", case #print "hem ", hem #print "nodes ", nodes # # Put together the data file names # anatomyVolumeFileName = "Human.Buckner." + hem + "." + case + "_ANATOMY+orig.nii.gz" closedTopologyFileName = "Human.Buckner" + case + "." + hem + ".CLOSED." + nodes + ".topo" corpusCallosumVolumeFileName = "LANDMARK_BORDER_DEBUG_FILES/CorpusCallosum.nii.gz" ellipsoidCoordinateFileName = "Human.Buckner" + case + "." + hem + ".Ellipsoidal." + nodes + ".coord" fiducialCoordinateFileName = "Human.Buckner" + case + "." + hem + ".Fiducial." + nodes + ".coord" inflatedCoordinateFileName = "Human.Buckner" + case + "." + hem + ".Inflated." + nodes + ".coord" inputAreaColorFileName = "Human.BUCKNER" + case + "." + hem + ".Initial.areacolor" inputBorderColorFileName = "\"\"" inputBorderProjectionFileName = "\"\"" inputPaintFileName = "Human.Buckner" + case + "." + hem + ".Initial." + nodes + ".paint" inputPaintFileGeographyColumnName = "Geography" inputSurfaceShapeFileName = "Human.Buckner" + case + "." + hem + ".Initial." + nodes + ".surface_shape" inputSurfaceShapeFileDepthColumnName = "Depth" inputVocabularyFileName = "\"\"" outputAreaColorFileName = "Human.BUCKNER" + case + "." + hem + ".SulcalIdentification.areacolor" outputBorderColorFileName = "Human.BUCKNER" + case + "." + hem + ".LandmarkColors.bordercolor" outputBorderProjectionFileName = "Human.BUCKNER" + case + "." + hem + ".Landmarks.borderproj" outputFociColorFileName = "LANDMARK_BORDER_DEBUG_FILES/Human.Buckner" + case + "." + hem + ".DebugFoci.focicolor" outputFociProjectionFileName = "LANDMARK_BORDER_DEBUG_FILES/Human.Buckner" + case + "." + hem + ".DebugFoci.fociproj" outputPaintFileName = "Human.BUCKNER" + case + "." + hem + ".SulcalIdentification.paint" outputVocabularyFileName = "Human.BUCKNER" + case + "." + hem + ".vocabulary" specFileName = "Human.Buckner" + case + "." + hem + ".spec" veryInflatedCoordFileName = "Human.Buckner" + case + "." + hem + ".VeryInflated." + nodes + ".coord" # # Stereotaxic space # stereotaxicSpace = "711-2C" # # Run sulcal identification # idCmdList = ( caretCommand, "-surface-border-landmark-identification", "-CHDIR", directoryName, "-CHMOD", "UR,UW,GR,GW,AR,AW", stereotaxicSpace, anatomyVolumeFileName, fiducialCoordinateFileName, inflatedCoordinateFileName, veryInflatedCoordFileName, ellipsoidCoordinateFileName, closedTopologyFileName, inputPaintFileName, outputPaintFileName, inputPaintFileGeographyColumnName, inputSurfaceShapeFileName, inputSurfaceShapeFileDepthColumnName, inputAreaColorFileName, outputAreaColorFileName, inputVocabularyFileName, outputVocabularyFileName, inputBorderProjectionFileName, outputBorderProjectionFileName, inputBorderColorFileName, outputBorderColorFileName, #outputFociProjectionFileName, #outputFociColorFileName, "-no-flatten" ) commandList = [" ".join(idCmdList)] # # Update the spec file # commandList.append(buildAddToSpecFileCommand(directoryName, specFileName, "area_color_file", outputAreaColorFileName)) commandList.append(buildAddToSpecFileCommand(directoryName, specFileName, "border_color_file", outputBorderColorFileName)) commandList.append(buildAddToSpecFileCommand(directoryName, specFileName, "borderproj_file", outputBorderProjectionFileName)) commandList.append(buildAddToSpecFileCommand(directoryName, specFileName, "foci_color_file", outputFociColorFileName)) commandList.append(buildAddToSpecFileCommand(directoryName, specFileName, "fociproj_file", outputFociProjectionFileName)) commandList.append(buildAddToSpecFileCommand(directoryName, specFileName, "paint_file", outputPaintFileName)) commandList.append(buildAddToSpecFileCommand(directoryName, specFileName, "vocabulary_file", outputVocabularyFileName)) commandList.append(buildAddToSpecFileCommand(directoryName, specFileName, "volume_segmentation_file", corpusCallosumVolumeFileName)) return commandList ##----------------------------------------------------------------------------- # # Test # def buildTestCommand(directoryName) : commandList = [] commandList.append(" ".join(("echo", directoryName))) return commandList ##----------------------------------------------------------------------------- # # Print help information # def printHelp() : print "Caret Landmark Testing" print "" print "Options" print " -clean Delete all foci/border proj/color files, jpg files" print " -clean-specs Remove non-existing files from spec files" print " -landmarks Generate landmarks" print " -scene-create Create scenes" print " -scene-create-ekr Create scenes" print " -scene-images Create Images of Scenes" print " -scene-images-mw Create Images of Medial Wall Scenes" print " -scene-composite Create a composite of the images that were" print " created with \"-scene-images\"" print " " ##----------------------------------------------------------------------------- # # MAIN # # # Flags for running different command # doCleanFlag = False doCleanSpecsFlag = False doEkrScenesFlag = False doLandmarksFlag = False doScenesFlag = False doSceneImagesFlag = False doSceneMedialWallImagesFlag = False doSceneImagesCompositeFlag = False doTestFlag = False # # Process arguments # numArgs = len(sys.argv) if (numArgs <= 1) : printHelp() os._exit(0) for i in range(1, numArgs) : arg = sys.argv[i] if arg == "-clean" : doCleanFlag = True elif arg == "-clean-specs" : doCleanSpecsFlag = True elif arg == "-landmarks" : doLandmarksFlag = True elif arg == "-scene-create" : doScenesFlag = True elif arg == "-scene-create-ekr" : doEkrScenesFlag = True elif arg == "-scene-images" : doSceneImagesFlag = True elif arg == "-scene-images-mw" : doSceneMedialWallImagesFlag = True elif arg == "-scene-composite" : doSceneImagesCompositeFlag = True; elif arg == "-test" : doTestFlag = True else : print "ERROR: Unrecognized parameter: ", arg os._exit(0) # # Run sulcal identification on the specified cases # subDirListEkr = [ "Human_Buckner_Case01/BUCKNER_Case01.L", "Human_Buckner_Case02/BUCKNER_Case02.L", "Human_Buckner_Case03/BUCKNER_Case03.L", "Human_Buckner_Case01/BUCKNER_Case01.R", "Human_Buckner_Case02/BUCKNER_Case02.R", "Human_Buckner_Case03/BUCKNER_Case03.R" ] #subDirListEkr = [ "Human_Buckner_Case01/BUCKNER_Case01.L" ] subDirListLeft = [ "Human_Buckner_Case01/BUCKNER_Case01.L", "Human_Buckner_Case02/BUCKNER_Case02.L", "Human_Buckner_Case03/BUCKNER_Case03.L", "Human_Buckner_Case04/BUCKNER_Case04.L", "Human_Buckner_Case05/BUCKNER_Case05.L", "Human_Buckner_Case06/BUCKNER_Case06.L", "Human_Buckner_Case07/BUCKNER_Case07.L", "Human_Buckner_Case08/BUCKNER_Case08.L", "Human_Buckner_Case09/BUCKNER_Case09.L", "Human_Buckner_Case10/BUCKNER_Case10.L", "Human_Buckner_Case11/BUCKNER_Case11.L", "Human_Buckner_Case12/BUCKNER_Case12.L", "Human_Buckner_Case13/BUCKNER_Case13.L", "Human_Buckner_Case14/BUCKNER_Case14.L", "Human_Buckner_Case15/BUCKNER_Case15.L", "Human_Buckner_Case16/BUCKNER_Case16.L", "Human_Buckner_Case17/BUCKNER_Case17.L", "Human_Buckner_Case18/BUCKNER_Case18.L", "Human_Buckner_Case19/BUCKNER_Case19.L", "Human_Buckner_Case20/BUCKNER_Case20.L", "Human_Buckner_Case21/BUCKNER_Case21.L", "Human_Buckner_Case22/BUCKNER_Case22.L", "Human_Buckner_Case23/BUCKNER_Case23.L", "Human_Buckner_Case24/BUCKNER_Case24.L" ] subDirListRight = [ "Human_Buckner_Case01/BUCKNER_Case01.R", "Human_Buckner_Case02/BUCKNER_Case02.R", "Human_Buckner_Case03/BUCKNER_Case03.R", "Human_Buckner_Case04/BUCKNER_Case04.R", "Human_Buckner_Case05/BUCKNER_Case05.R", "Human_Buckner_Case06/BUCKNER_Case06.R", "Human_Buckner_Case07/BUCKNER_Case07.R", "Human_Buckner_Case08/BUCKNER_Case08.R", "Human_Buckner_Case09/BUCKNER_Case09.R", "Human_Buckner_Case10/BUCKNER_Case10.R", "Human_Buckner_Case11/BUCKNER_Case11.R", "Human_Buckner_Case12/BUCKNER_Case12.R", "Human_Buckner_Case13/BUCKNER_Case13.R", "Human_Buckner_Case14/BUCKNER_Case14.R", "Human_Buckner_Case15/BUCKNER_Case15.R", "Human_Buckner_Case16/BUCKNER_Case16.R", "Human_Buckner_Case17/BUCKNER_Case17.R", "Human_Buckner_Case18/BUCKNER_Case18.R", "Human_Buckner_Case19/BUCKNER_Case19.R", "Human_Buckner_Case20/BUCKNER_Case20.R", "Human_Buckner_Case21/BUCKNER_Case21.R", "Human_Buckner_Case22/BUCKNER_Case22.R", "Human_Buckner_Case23/BUCKNER_Case23.R", "Human_Buckner_Case24/BUCKNER_Case24.R" ] # # All Cases # subDirListAll = subDirListLeft + subDirListRight # # ERIN - Put the case you would like to run here!! # subDirListSingle = ["Human_Buckner_Case01/BUCKNER_Case01.R"] # # Name of directory containing subjects # topDir = os.getcwd() #"/backup/sulcal_id/sulcal_id_john"; # # Choose directory list for execution # subDirList = subDirListEkr #subDirList = subDirListAll #subDirList = subDirListLeft #subDirList = subDirListRight #subDirList = subDirListSingle # # Maximum number of threads # maxThreads = 4 singleThread = 1 # # Doing Landmarks ? # if doLandmarksFlag : # # Get all commands # allCommands = [] for dirName in subDirList: subjectDirectory = topDir + "/" + dirName allCommands.append(buildSulcalIdCommand(subjectDirectory)) # # Run the commands in threads # runThreads = RunCommandsInMultipleThreads(allCommands, maxThreads) runThreads.start() # # Doing EKR Scenes ? # if doEkrScenesFlag : # # Get all commands # allCommands = [] for dirName in subDirListEkr: subjectDirectory = topDir + "/" + dirName allCommands.append(buildEkrBorderSceneCommand(subjectDirectory)) # # Run the commands in ONE thread since multiple scenes # runThreads = RunCommandsInMultipleThreads(allCommands, singleThread) runThreads.start() # # Doing Scenes ? # if doScenesFlag : # # Get all commands # allCommands = [] for dirName in subDirList: subjectDirectory = topDir + "/" + dirName allCommands.append(buildCreateBorderSceneCommand(subjectDirectory)) allCommands.append(buildCreateMedialWallSceneCommand(subjectDirectory)) # # Run the commands in ONE thread since multiple scenes # runThreads = RunCommandsInMultipleThreads(allCommands, singleThread) runThreads.start() if doSceneImagesFlag : # # Get all commands # allCommands = [] for dirName in subDirList: subjectDirectory = topDir + "/" + dirName allCommands.append(buildCreateSceneImageCommand(subjectDirectory, "1")) # # Run the commands in ONE thread since multiple scenes # runThreads = RunCommandsInMultipleThreads(allCommands, singleThread) runThreads.start() if doSceneMedialWallImagesFlag : # # Get all commands # allCommands = [] for dirName in subDirList: subjectDirectory = topDir + "/" + dirName allCommands.append(buildCreateSceneImageCommand(subjectDirectory, "2")) # # Run the commands in ONE thread since multiple scenes # runThreads = RunCommandsInMultipleThreads(allCommands, singleThread) runThreads.start() if doSceneImagesCompositeFlag : # # Create the composite image # allImagesCommand = buildAssembleImagesCommand("LandmarksAll.jpg", subDirList) runCommand(allImagesCommand) if doTestFlag : allCommands = [] for dirName in subDirList: subjectDirectory = topDir + "/" + dirName allCommands.append(buildTestCommand(subjectDirectory)) runThreads = RunCommandsInMultipleThreads(allCommands, maxThreads) runThreads.start() if doCleanSpecsFlag : allCommands = [] for dirName in subDirList: subjectDirectory = topDir + "/" + dirName allCommands.append(buildCleanSpecFileCommand(subjectDirectory)) runThreads = RunCommandsInMultipleThreads(allCommands, singleThread) runThreads.start() if doCleanFlag : runCommand("rm `find . -name '*borderproj' -print`") runCommand("rm `find . -name '*bordercolor' -print`") runCommand("rm `find . -name '*fociproj' -print`") runCommand("rm `find . -name '*focicolor' -print`") runCommand("rm `find . -name '*.jpg' -print`") caret-5.6.4~dfsg.1.orig/caret_scripts/run_sulcal_id_buckner_13_38.py0000755000175000017500000021006011572067322025151 0ustar michaelmichael#!/usr/bin/python # # Imports # import os import sys # # Global Variables # progName = "/Users/john/caret5_osx/caret_source/caret_command_new/caret_command_new" #progName = "caret_command_new" # # Hemisphere # rightHemFlag = 1 # # Cluster ratio and output file name # clusterRatio = 0.5 outputCompositePaintFileName = "Human.Case13-18.R.TestSulcalID_Composite.73730.paint" # # Post Central Sulcus parameters # postCentralSulcusOffset = 25.0 postCentralSulcusStdDevSquared = 100.0 postCentralSulcusSplit = 5.0 # # Names of input data files # borderColorFileName = "ForSphericalRegistration_Automated.bordercolor" borderProjectionFilePrefix = "Case" borderProjectionFileSuffix = ".LANDMARKS.73730.borderproj" fiducialCoordFilePrefix = "Human.Buck_Case" fiducialCoordFileSuffix = ".R.F.RegToPALS_B12.LR.FIDUCIAL.align.73730.coord" fociColorFileName = "Landmark-related.focicolor" fociProjectionFilePrefix = "LANDMARK-RELATED.Case" fociProjectionFileSuffix = ".73730.fociproj" inflatedCoordFilePrefix = "Human.Buck_Case" inflatedCoordFileSuffix = ".R.F.RegToPALS_B12.LR.INFLATED.align.73730.coord" veryInflatedCoordFilePrefix = "Human.Buck_Case" veryInflatedCoordFileSuffix = ".R.F.RegToPALS_B12.LR.VERY_INFLATED.align.73730.coord" inflatedShapeCurvatureFilePrefix = "Human.Buckner_INFLATED_Case" shapeCurvatureFilePrefix = "Human.Buckner_Case" shapeCurvatureFileSuffix = ".R.curvature.73730.surface_shape" paintFilePrefix = "Human.Case" paintFileSuffix = ".R.TestSulcalID.73730.paint" veryInflatedCoordFile = "Human.PALS_B12.RIGHT_AVG_B1-12.VERY_INFLATED.clean.73730.coord" outputPaintFiles = [ "Human.Case13.R.TestSulcalID.73730.paint", "Human.Case14.R.TestSulcalID.73730.paint", "Human.Case15.R.TestSulcalID.73730.paint", "Human.Case16.R.TestSulcalID.73730.paint", "Human.Case17.R.TestSulcalID.73730.paint", "Human.Case18.R.TestSulcalID.73730.paint" ] anatomyVolumeFilePrefix = "Human_Buckner_Case" anatomyVolumeFileSuffix = "+orig.HEAD" inputTopoFile = "Human.sphere_6.RIGHT_HEM.73730.topo" inputPaintFile = "Human.PALS_B12.LR.B13-18_RIGHT_WOMEN.COMPOSITE.73730.paint" inputShapeFile = "Human.PALS_B12.B13-18.RIGHT-DEPTH_INDIVIDUAL.73730.surface_shape" probabilisticSulcusVolumeListFileName = "probabilistic-depth-volume.csv" startCaseNumber = 13 # 13 endCaseNumber = 19 # 19 ##----------------------------------------------------------------------------- # # Run a command # def runCommand(cmdList) : cmd = " ".join(cmdList) # join cmdList into a string separated by blanks print "\nExecuting: %s\n" % cmd result = os.system(cmd) if (result != 0) : print "COMMAND FAILED: " print " ", cmd os._exit(-1) ##----------------------------------------------------------------------------- ## ## Delete border and foci projection files ## def removeSulcalIdentficationBorderAndFociProjectionFiles() : for caseID in range(startCaseNumber, endCaseNumber) : caseNumberString = str(caseID) borderProjectionFileName = borderProjectionFilePrefix \ + caseNumberString \ + borderProjectionFileSuffix if (os.path.exists(borderProjectionFileName)) : os.remove(borderProjectionFileName) fociProjectionFileName = fociProjectionFilePrefix \ + caseNumberString \ + fociProjectionFileSuffix if (os.path.exists(fociProjectionFileName)) : os.remove(fociProjectionFileName) if (os.path.exists(borderColorFileName)) : os.remove(borderColorFileName) if (os.path.exists(fociColorFileName)) : os.remove(fociColorFileName) ##----------------------------------------------------------------------------- ## ## Identify the Medial Wall ## def identifyMedialWall(caseNumberString) : # # Global variables # # # Assemble file names # borderProjectionFileName = borderProjectionFilePrefix \ + caseNumberString \ + borderProjectionFileSuffix fiducialCoordFileName = fiducialCoordFilePrefix \ + caseNumberString \ + fiducialCoordFileSuffix fociProjectionFileName = fociProjectionFilePrefix \ + caseNumberString \ + fociProjectionFileSuffix inflatedCoordFileName = inflatedCoordFilePrefix \ + caseNumberString \ + inflatedCoordFileSuffix veryInflatedCoordFileName = veryInflatedCoordFilePrefix \ + caseNumberString \ + veryInflatedCoordFileSuffix paintFileName = paintFilePrefix \ + caseNumberString \ + paintFileSuffix paintColumnName = "\"Sulcus ID.Buck_Case" \ + caseNumberString \ + ".R\"" roiFileName = "Human.case" \ + caseNumberString \ + "." \ + "MedialWall" \ + ".roi" shapeCurvatureFileName = shapeCurvatureFilePrefix \ + caseNumberString \ + shapeCurvatureFileSuffix anatomyVolumeFileName = anatomyVolumeFilePrefix \ + caseNumberString \ + anatomyVolumeFileSuffix # # Names of foci created when creating medial wall landmark # ccPosteriorFocusName = "CC-post.Case" + caseNumberString ccAnteriorFocusName = "CC-ant.Case" + caseNumberString ccCogFocusName = "CC-cog.Case" + caseNumberString genuLimitFocusName = "CC-genu-limit.Case" + caseNumberString spleniumLimitFocusName = "CC-splenium-limit.Case" + caseNumberString ccGenuBeginningFocusName = "CC-genu-beginning.Case" + caseNumberString olfSulcusPosteriorFocusName = "OlfSuclus-Posterior.Case" + caseNumberString olfSulcusMedialFocusName = "OlfSulcus-Medial.Case" + caseNumberString medialWallStartFocusName = "MedialWallStart.Case" + caseNumberString # # Remove any existing foci that identify corpus callosum locations # cmdList = (progName, "-surface-foci-delete", fociProjectionFileName, fociProjectionFileName, ccPosteriorFocusName, ccAnteriorFocusName, ccCogFocusName, genuLimitFocusName, spleniumLimitFocusName, ccGenuBeginningFocusName, olfSulcusPosteriorFocusName, olfSulcusMedialFocusName) runCommand(cmdList) # # Remove any previous corpus callosum borders # corpusCallosumLandmarkBorderName = "LANDMARK.CorpusCallosum.Case" + caseNumberString corpusCallosumOlfactoryBorderName = "LANDMARK.CorpusCallosumOflactory" cmdList = (progName, "-surface-border-delete", borderProjectionFileName, borderProjectionFileName, corpusCallosumLandmarkBorderName, corpusCallosumOlfactoryBorderName) runCommand(cmdList) # # Create the corpus callosum slice # cmdList = (progName, "-volume-create-corpus-callosum-slice", anatomyVolumeFileName, "CorpusCallosumSlice+orig.nii", "right") runCommand(cmdList) # # Smear along X axis # cmdList = (progName, "-volume-smear-axis", "CorpusCallosumSlice+orig.nii", "CorpusCallosumSlice_Smear10+orig.nii", "X", str(5), str(-1), str(1)) runCommand(cmdList) # # Dilate # cmdList = (progName, "-volume-dilate", "CorpusCallosumSlice_Smear10+orig.nii", "CorpusCallosumSlice_Smear10_Dilate5+orig.nii", str(5)) runCommand(cmdList) # # Smear along Y axis # corpusCallosumVolumeFileName = "CorpusCallosumSlice_Smear10+Dilate5_SmearPost_Case" \ + caseNumberString \ + "+orig.nii" cmdList = (progName, "-volume-smear-axis", "CorpusCallosumSlice_Smear10_Dilate5+orig.nii", corpusCallosumVolumeFileName, "Y", str(5), str(-1), str(1)) runCommand(cmdList) # # Map the non-zero voxels to a surface ROI file # corpusCallosumFringeRoiFileName = "corpus_callosum_fringe.Case" + caseNumberString + ".roi" cmdList = (progName, "-volume-map-to-surface-roi-file", corpusCallosumVolumeFileName, fiducialCoordFileName, inputTopoFile, corpusCallosumFringeRoiFileName) runCommand(cmdList) # # Modify the ROI to exclude help exlude stuff in the cingulate sulcus # cmdList = (progName, "-surface-region-of-interest-selection", fiducialCoordFileName, inputTopoFile, corpusCallosumFringeRoiFileName, corpusCallosumFringeRoiFileName, "-erode 1", "-dilate 1") runCommand(cmdList) # # Modify the ROI to that nodes have a curvature range (-100.0, -0.10) # corpusCallosumFringeCurveRoiFileName = "corpus_callosum_fringe_curve.Case" + caseNumberString + ".roi" cmdList = (progName, "-surface-region-of-interest-selection", fiducialCoordFileName, inputTopoFile, corpusCallosumFringeRoiFileName, corpusCallosumFringeCurveRoiFileName, "-shape", shapeCurvatureFileName, str(1), str(-100.0), str(-0.10), "AND") runCommand(cmdList) # # Place foci at anterior and posterior of corpus callosum # cmdList = (progName, "-surface-place-foci-at-limits", fiducialCoordFileName, fiducialCoordFileName, inputTopoFile, corpusCallosumFringeCurveRoiFileName, fociProjectionFileName, fociProjectionFileName, "-y-min", ccPosteriorFocusName, "-y-max", ccAnteriorFocusName, "-cog", ccCogFocusName) runCommand(cmdList) # # Deselect nodes above and posterior to CC-center leaving # just a ventral anterior group selected # corpusCallosumFringeCurveVentAntRoiFileName = "corpus_callosum_fringe_curve_vent_ant.Case" + caseNumberString + ".roi" cmdList = (progName, "-surface-region-of-interest-selection", fiducialCoordFileName, inputTopoFile, corpusCallosumFringeCurveRoiFileName, corpusCallosumFringeCurveVentAntRoiFileName, "-limit-z-max-focus", fociProjectionFileName, ccCogFocusName, "-limit-y-min-focus", fociProjectionFileName, ccCogFocusName) runCommand(cmdList) # # Place a focus at "Genu" -Y-Max limit # cmdList = (progName, "-surface-place-foci-at-limits", fiducialCoordFileName, fiducialCoordFileName, inputTopoFile, corpusCallosumFringeCurveVentAntRoiFileName, fociProjectionFileName, fociProjectionFileName, "-y-max", genuLimitFocusName) runCommand(cmdList) # # Deselect nodes above and posterior to CC-center leaving # just a ventral anterior group selected # corpusCallosumFringeCurveVentPostRoiFileName = "corpus_callosum_fringe_curve_vent_post.Case" + caseNumberString + ".roi" cmdList = (progName, "-surface-region-of-interest-selection", fiducialCoordFileName, inputTopoFile, corpusCallosumFringeCurveRoiFileName, corpusCallosumFringeCurveVentPostRoiFileName, "-limit-z-max-focus", fociProjectionFileName, ccCogFocusName, "-limit-y-max-focus", fociProjectionFileName, ccCogFocusName) runCommand(cmdList) # # Place a focus at "Splenium" -Y-Max limit # cmdList = (progName, "-surface-place-foci-at-limits", fiducialCoordFileName, fiducialCoordFileName, inputTopoFile, corpusCallosumFringeCurveVentPostRoiFileName, fociProjectionFileName, fociProjectionFileName, "-z-min", spleniumLimitFocusName) runCommand(cmdList) # # Draw a callosal border # cmdList = (progName, "-surface-border-draw-geodesic", fiducialCoordFileName, inputTopoFile, fociProjectionFileName, genuLimitFocusName, spleniumLimitFocusName, corpusCallosumFringeCurveRoiFileName, borderProjectionFileName, borderProjectionFileName, corpusCallosumLandmarkBorderName, str(1.0)) runCommand(cmdList) # # Create a focus at start of LANDMARK.CorpusCallosum Border # cmdList = (progName, "-surface-border-link-to-focus", fiducialCoordFileName, inputTopoFile, borderProjectionFileName, corpusCallosumLandmarkBorderName, fociProjectionFileName, fociProjectionFileName, "-first-link", ccGenuBeginningFocusName) runCommand(cmdList) # # Create an ROI containing Olfactory Sulcus # olfactorySulcusRoiFileName = "OlfactorySulcus.Case" + caseNumberString + ".roi" cmdList = (progName, "-surface-region-of-interest-selection", fiducialCoordFileName, inputTopoFile, olfactorySulcusRoiFileName, olfactorySulcusRoiFileName, "-paint", paintFileName, str(1), # use initial ID paintColumnName, "SUL.OlfS", "NORMAL") runCommand(cmdList) # # Find geographic limits of Olfactory Sulcus # cmdList = (progName, "-surface-place-foci-at-limits", fiducialCoordFileName, fiducialCoordFileName, inputTopoFile, olfactorySulcusRoiFileName, fociProjectionFileName, fociProjectionFileName, "-y-min", olfSulcusPosteriorFocusName, "-x-most-medial", olfSulcusMedialFocusName) runCommand(cmdList) # # Create a new focus with X at Olfactory medial # with Y at Olfactory posterior # with Z at Olfactory posterior # cmdList = (progName, "-surface-foci-create", fiducialCoordFileName, inputTopoFile, fociProjectionFileName, fociProjectionFileName, "-focus-offset-xyz", medialWallStartFocusName, olfSulcusMedialFocusName, "0.0", olfSulcusPosteriorFocusName, "-5.0", olfSulcusPosteriorFocusName, "10.0") runCommand(cmdList) # # Create an ROI of all nodes # allNodesRoiFileName = "Olfactory-AllNodes.roi" cmdList = (progName, "-surface-region-of-interest-selection", fiducialCoordFileName, inputTopoFile, allNodesRoiFileName, allNodesRoiFileName, "-all-nodes") runCommand(cmdList) # # Draw border connecting genu beginning to dorsal start # cmdList = (progName, "-surface-border-draw-geodesic", veryInflatedCoordFileName, inputTopoFile, fociProjectionFileName, medialWallStartFocusName, ccGenuBeginningFocusName, allNodesRoiFileName, borderProjectionFileName, borderProjectionFileName, corpusCallosumOlfactoryBorderName, str(1.0)) runCommand(cmdList) ##----------------------------------------------------------------------------- ## ## Identify all medial walls def identifyAllMedialWalls() : # # Add Colors to Foci File # cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "CC", str(0), str(0), str(255), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "Olf", str(0), str(0), str(255), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "MedialWall", str(0), str(0), str(255), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) # # Add paint colors # #cmdList = (progName, # "-color-file-add-color", # areaColorFileName, # areaColorFileName, # "GYRAL.STG", # str(100), # str(255), # str(150), # "-point-size 1", # "-symbol SPHERE"); runCommand(cmdList) # # Add border colors # cmdList = (progName, "-color-file-add-color", borderColorFileName, borderColorFileName, "LANDMARK.CorpusCallosum", str(255), str(255), str(0), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) # # ID the central sulcus on the specified cases # for caseID in range(startCaseNumber, endCaseNumber) : identifyMedialWall(str(caseID)) ##----------------------------------------------------------------------------- ## ## Identify the Sylvian fissure ## def identifySylvianFissure(caseNumberString) : # # Global variables # # # Assemble file names # borderProjectionFileName = borderProjectionFilePrefix \ + caseNumberString \ + borderProjectionFileSuffix fiducialCoordFileName = fiducialCoordFilePrefix \ + caseNumberString \ + fiducialCoordFileSuffix fociProjectionFileName = fociProjectionFilePrefix \ + caseNumberString \ + fociProjectionFileSuffix inflatedCoordFileName = inflatedCoordFilePrefix \ + caseNumberString \ + inflatedCoordFileSuffix veryInflatedCoordFileName = veryInflatedCoordFilePrefix \ + caseNumberString \ + veryInflatedCoordFileSuffix paintFileName = paintFilePrefix \ + caseNumberString \ + paintFileSuffix paintColumnName = "\"Sulcus ID.Buck_Case" \ + caseNumberString \ + ".R\"" roiFileName = "Human.case" \ + caseNumberString \ + "." \ + "SF" \ + ".roi" roiErodedFileName = "Human.case" \ + caseNumberString \ + "." \ + "SF_Eroded" \ + ".roi" roiStringentFileName = "Human.case" \ + caseNumberString \ + "." \ + "SF_Stringent" \ + ".roi" inflatedShapeCurvatureFileName = inflatedShapeCurvatureFilePrefix \ + caseNumberString \ + shapeCurvatureFileSuffix inflatedCurvatureColumnName = "\"Folding (Mean Curvature) Inflated\"" shapeCurvatureFileName = shapeCurvatureFilePrefix \ + caseNumberString \ + shapeCurvatureFileSuffix # # Generate curvature on the INFLATED surface # cmdList = (progName, "-surface-curvature", inflatedCoordFileName, inputTopoFile, inflatedShapeCurvatureFileName, inflatedShapeCurvatureFileName, "-generate-mean-curvature", "-mean-column-name", inflatedCurvatureColumnName); runCommand(cmdList); # # Create an ROI that identifies the sylvian fissure # with paint name SUL.SF # cmdList = (progName, "-surface-region-of-interest-selection", inflatedCoordFileName, inputTopoFile, roiFileName, roiFileName, "-paint", paintFileName, paintColumnName, # column name "SUL.SF", # paint name "NORMAL") # normal selection runCommand(cmdList) # # Erode the ROI since SF paint tends to be too big # cmdList = (progName, "-surface-region-of-interest-selection", inflatedCoordFileName, inputTopoFile, roiFileName, roiErodedFileName, "-erode 5") runCommand(cmdList) # # Create foci at some limits of ROI at eroded ROI # sfAnteriorFocusName = "SF_Anterior.Case" + caseNumberString sfPosteriorFocusName = "SF_Posterior.Case" + caseNumberString sfDorsalFocusName = "SF_Dorsal.Case" + caseNumberString cmdList = (progName, "-surface-place-foci-at-limits", fiducialCoordFileName, inflatedCoordFileName, inputTopoFile, roiErodedFileName, fociProjectionFileName, fociProjectionFileName, "-y-max " + sfAnteriorFocusName, "-y-min " + sfPosteriorFocusName, "-z-max " + sfDorsalFocusName) runCommand(cmdList) # # Limit original ROI to apply curvature limits # cmdList = (progName, "-surface-region-of-interest-selection", inflatedCoordFileName, inputTopoFile, roiFileName, roiStringentFileName, "-shape", inflatedShapeCurvatureFileName, inflatedCurvatureColumnName, str(-100.0), str(-0.07), # use -0.7 since inflated "AND") runCommand(cmdList) # # Draw border from posterior to anterior of SF # USES GEODESIC METHOD # borderSampling = 1.0 cmdList = (progName, "-surface-border-draw-geodesic", inflatedCoordFileName, inputTopoFile, fociProjectionFileName, sfPosteriorFocusName, sfAnteriorFocusName, roiStringentFileName, borderProjectionFileName, borderProjectionFileName, "LANDMARK.SF1", str(borderSampling)) runCommand(cmdList) # # USES CURVATURE METHOD # cmdList = (progName, "-surface-border-draw-metric", inflatedCoordFileName, inputTopoFile, inflatedShapeCurvatureFileName, inflatedCurvatureColumnName, "NEGATIVE", fociProjectionFileName, sfPosteriorFocusName, sfAnteriorFocusName, borderProjectionFileName, borderProjectionFileName, "LANDMARK.SF1", str(borderSampling)); ## DO NOT RUN runCommand(cmdList) # # Create a focus near ventral limit of frontal pole, # on lateral bank of the olfactory sulcus on the fiducial surface # ventralFrontalX = -14 if (rightHemFlag) : ventralFrontalX = 14 ventralFrontalFocusName = "SF_VentralFrontal.Case" + caseNumberString cmdList = (progName, "-surface-foci-create", fiducialCoordFileName, inputTopoFile, fociProjectionFileName, fociProjectionFileName, "-focus", ventralFrontalFocusName, str(ventralFrontalX), str(5), str(-12)) runCommand(cmdList); # # Identify the ventral limit of frontal lobe, on the lateral bank of the # olfactory sulcus on the fiducial surface # ventralFrontalExtremeFocusName = "SF_VentralFrontalExtreme.Case" + caseNumberString cmdList = (progName, "-surface-place-focus-at-extremum", fiducialCoordFileName, fiducialCoordFileName, inputTopoFile, fociProjectionFileName, ventralFrontalFocusName, fociProjectionFileName, ventralFrontalExtremeFocusName, "Z-NEG", str(100000.0), str(100000.0), str(100000.0)) runCommand(cmdList) # # Draw border from most anterior SF node to ventral tip of frontal lobe # borderSampling = 1.0 cmdList = (progName, "-surface-border-draw-geodesic", inflatedCoordFileName, inputTopoFile, fociProjectionFileName, sfAnteriorFocusName, ventralFrontalExtremeFocusName, roiStringentFileName, borderProjectionFileName, borderProjectionFileName, "LANDMARK.SF2", str(borderSampling)) runCommand(cmdList) # # Merge the SF1 and SF2 borders into SF # sylvianFissureBorderName = "LANDMARK.SF" + caseNumberString cmdList = (progName, "-surface-border-merge", borderProjectionFileName, borderProjectionFileName, sylvianFissureBorderName, "LANDMARK.SF1", "LANDMARK.SF2", "-delete-input-border-projections") runCommand(cmdList) # # Create a focus posterior and dorsal to Temporal Pole, close to # secondary fundus of SF # sfVentralFocusName = "SF_VentralNearSecondary_SF.Case" + caseNumberString temporalPoleFocusName = "TemporalPole.Case" + caseNumberString ventralSecondaryX = -7 if (rightHemFlag) : ventralSecondaryX = 7 cmdList = (progName, "-surface-foci-create", inflatedCoordFileName, inputTopoFile, fociProjectionFileName, fociProjectionFileName, "-focus-offset", sfVentralFocusName, temporalPoleFocusName, str(ventralSecondaryX), str(-45), str(40)) runCommand(cmdList); # # Draw border along secondary fundus from anterior to posterior in SF # secondarySylvianFissureBorderName = "LANDMARK.SF-secondary" cmdList = (progName, "-surface-border-draw-metric", inflatedCoordFileName, inputTopoFile, inflatedShapeCurvatureFileName, inflatedCurvatureColumnName, "NEGATIVE", fociProjectionFileName, sfVentralFocusName, sfPosteriorFocusName, borderProjectionFileName, borderProjectionFileName, secondarySylvianFissureBorderName, str(borderSampling)) runCommand(cmdList) # # Find intersection of Sylvian fissue and secondary Sylvian fissure # sylvianIntersectionFocusName = "SF_Intersect_Superior_Inferior" + caseNumberString borderIntersectionTolerance = 3.0 cmdList = (progName, "-surface-border-intersection", inflatedCoordFileName, inputTopoFile, borderProjectionFileName, fociProjectionFileName, fociProjectionFileName, secondarySylvianFissureBorderName, sylvianFissureBorderName, sylvianIntersectionFocusName, str(borderIntersectionTolerance)) runCommand(cmdList) # # Trim beyond 12mm posterior to intersection of superior and inferior circular sulci # ##dorsalPostSylvianFissureBorderName = "LANDMARK.SF_DorsalPost" + caseNumberString cmdList = (progName, "-surface-border-nibbler", inflatedCoordFileName, inputTopoFile, borderProjectionFileName, borderProjectionFileName, sylvianFissureBorderName, sylvianFissureBorderName, fociProjectionFileName, sylvianIntersectionFocusName, "-less-than-y -12") runCommand(cmdList) # # Nibble anything within 15mm Z of ventral-frontal extreme # #finishedSylvianBorderName = "LANDMARK.SylvianFissure.Case" + caseNumberString ventralFrontalExtremeFocusName = "SF_VentralFrontalExtreme.Case" + caseNumberString cmdList = (progName, "-surface-border-nibbler", inflatedCoordFileName, inputTopoFile, borderProjectionFileName, borderProjectionFileName, sylvianFissureBorderName, sylvianFissureBorderName, fociProjectionFileName, ventralFrontalExtremeFocusName, "-within-z-distance 15") runCommand(cmdList) ##----------------------------------------------------------------------------- ## ## Identify all sylvian fissures def identifyAllSylvianFissure() : # # Add Colors to Foci File # cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "SF", str(50), str(255), str(255), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) ventralFrontalExtremeFocusName = "SF_VentralFrontalExtreme.Case" cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "SF", str(0), str(255), str(0), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) ventralFrontalFocusName = "SF_VentralFrontal.Case" cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "SF", str(0), str(0), str(255), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) # # Add paint colors # #cmdList = (progName, # "-color-file-add-color", # areaColorFileName, # areaColorFileName, # "GYRAL.STG", # str(100), # str(255), # str(150), # "-point-size 1", # "-symbol SPHERE"); runCommand(cmdList) # # Add border colors # cmdList = (progName, "-color-file-add-color", borderColorFileName, borderColorFileName, "LANDMARK.SF", str(0), str(255), str(255), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) # # ID the central sulcus on the specified cases # for caseID in range(startCaseNumber, endCaseNumber) : identifySylvianFissure(str(caseID)) ##----------------------------------------------------------------------------- ## ## Identify the superior temporal gyrus ## def identifySuperiorTemporalGyrus(caseNumberString) : # # Global variables # # # Assemble file names # borderProjectionFileName = borderProjectionFilePrefix \ + caseNumberString \ + borderProjectionFileSuffix fiducialCoordFileName = fiducialCoordFilePrefix \ + caseNumberString \ + fiducialCoordFileSuffix fociProjectionFileName = fociProjectionFilePrefix \ + caseNumberString \ + fociProjectionFileSuffix inflatedCoordFileName = inflatedCoordFilePrefix \ + caseNumberString \ + inflatedCoordFileSuffix tempRotateY45InflatedCoordFileName = "Temp_Rotated_Y45_Inflated_Case" \ + caseNumberString \ + ".coord" veryInflatedCoordFileName = veryInflatedCoordFilePrefix \ + caseNumberString \ + veryInflatedCoordFileSuffix paintFileName = paintFilePrefix \ + caseNumberString \ + paintFileSuffix paintFileGyralSTGName = paintFilePrefix \ + caseNumberString \ + ".GyralSTG" \ + paintFileSuffix paintColumnName = "\"Sulcus ID.Buck_Case" \ + caseNumberString \ + ".R\"" roiFileName = "Human.case" \ + caseNumberString \ + "." \ + "STG" \ + ".roi" roiStringentFileName = "Human.case" \ + caseNumberString \ + "." \ + "STG_Stringent" \ + ".roi" shapeCurvatureFileName = shapeCurvatureFilePrefix \ + caseNumberString \ + shapeCurvatureFileSuffix # # Create an ROI that identifies the superior temporal sulcus # with paint name SUL.STS # cmdList = (progName, "-surface-region-of-interest-selection", inflatedCoordFileName, inputTopoFile, roiFileName, roiFileName, "-paint", paintFileName, paintColumnName, # column name "SUL.STS", # paint name "NORMAL") # AND with previous selection runCommand(cmdList) # # Create foci at some limits of ROI # stsVentralFocusName = "STS_Inflated_Ventral.Case" + caseNumberString stsDorsalFocusName = "STS_Inflated_Dorsal.Case" + caseNumberString cmdList = (progName, "-surface-place-foci-at-limits", fiducialCoordFileName, inflatedCoordFileName, inputTopoFile, roiFileName, fociProjectionFileName, fociProjectionFileName, "-z-min " + stsVentralFocusName, "-z-max " + stsDorsalFocusName) runCommand(cmdList) # # Find extremum point for temporal pole # temporalPoleFocusName = "TemporalPole.Case" + caseNumberString cmdList = (progName, "-surface-place-focus-at-extremum", fiducialCoordFileName, inflatedCoordFileName, inputTopoFile, fociProjectionFileName, stsVentralFocusName, fociProjectionFileName, temporalPoleFocusName, "Y-POS", str(100000.0), str(100000.0), str(100000.0)) runCommand(cmdList) # # Create a transformation matrix rotated Y=-45 # rotateString = "-rotate 0.0 45.0 0.0" if (rightHemFlag) : rotateString = "-rotate 0.0 -45.0 0.0" transformationMatrixFileName = "TempRotateYMinus45.matrix" transformationMatrixName = "RotateYMinus45" cmdList = (progName, "-transformation-matrix-create", transformationMatrixFileName, transformationMatrixFileName, transformationMatrixName, "-delete-all-matrices-from-file", "-matrix-comment \"rotate minus 45 degrees about Y-axis\"", rotateString) runCommand(cmdList) # # Create a temporary surface rotated Y-45 # cmdList = (progName, "-surface-apply-transformation-matrix", inflatedCoordFileName, inputTopoFile, tempRotateY45InflatedCoordFileName, "-matrix-file ", transformationMatrixFileName, transformationMatrixName) #"-matrix", # "0.707107 0.000000 -0.707107 0.000000", # "0.000000 1.000000 0.000000 0.000000", # "0.707107 0.000000 0.707107 0.000000", # "0.000000 0.000000 0.000000 1.000000") #"-matrix-file STG.matrix Y45Down"); runCommand(cmdList) # # Find extremum point starting at temporal pole # moving in a posterior/superior direction along the STG # stgPathFocusName = "STG-posterior.Case" + caseNumberString stgRoiFileName = "Case" + caseNumberString + ".STG.roi" cmdList = (progName, "-surface-place-focus-at-extremum", fiducialCoordFileName, tempRotateY45InflatedCoordFileName, inputTopoFile, fociProjectionFileName, temporalPoleFocusName, fociProjectionFileName, stgPathFocusName, "Z-POS", str(100000.0), str(100000.0), str(100000.0), "-create-roi-from-path", stgRoiFileName) #"-start-offset 3.0 0.0 0.0") runCommand(cmdList) # # Limit the ROI so it does not go beyond temporal pole # or beyond the Y position of the ventral tip of the # central sulcus # cesVentralFocusName = "CeS-ventral.Case" + caseNumberString cmdList = (progName, "-surface-region-of-interest-selection", inflatedCoordFileName, inputTopoFile, stgRoiFileName, stgRoiFileName, "-limit-y-min-focus", fociProjectionFileName, cesVentralFocusName, "-limit-y-max-focus", fociProjectionFileName, temporalPoleFocusName, "-limit-z-min-focus", fociProjectionFileName, temporalPoleFocusName) runCommand(cmdList) # # Create limits at posterior and ventral ends of GYRAL.STG # stgCesLimitFocusName = "STG-CES-limit.Case" + caseNumberString #stgPosteriorFocusName = "STG-posterior.Case" + caseNumberString #stgVentralFocusName = "STG-ventral.Case" + caseNumberString cmdList = (progName, "-surface-place-foci-at-limits", fiducialCoordFileName, inflatedCoordFileName, inputTopoFile, stgRoiFileName, fociProjectionFileName, fociProjectionFileName, "-y-min " + stgCesLimitFocusName) #"-z-min " + stgVentralFocusName) runCommand(cmdList) # # Create the draw border comand to draw the LANDMARK.SF_STSant border # borderSampling = 1.0 cmdList = (progName, "-surface-border-draw-geodesic", inflatedCoordFileName, inputTopoFile, fociProjectionFileName, stgCesLimitFocusName, temporalPoleFocusName, stgRoiFileName, borderProjectionFileName, borderProjectionFileName, "LANDMARK.SF_STSant", str(borderSampling)) runCommand(cmdList) ###################################################### # The following steps are not necessary but assign paint # for the STG # # # Dilate the STG ROI but only nodes identified as GYRAL # and limit the extent of the ROI so that it does not # go posterior to ventral tip of central sulcus or # beyond the temporal pole. # dilateIterations = 5 cesVentralFocusName = "CeS-ventral.Case" + caseNumberString cmdList = (progName, "-surface-region-of-interest-selection", inflatedCoordFileName, inputTopoFile, stgRoiFileName, stgRoiFileName, "-dilate-paint", paintFileName, paintColumnName, "SUL.SF", # SF may be too big str(dilateIterations), "-dilate-paint", paintFileName, paintColumnName, "GYRAL", str(dilateIterations), "-limit-y-min-focus", fociProjectionFileName, cesVentralFocusName, "-limit-y-max-focus", fociProjectionFileName, temporalPoleFocusName, "-limit-z-min-focus", fociProjectionFileName, temporalPoleFocusName, ) runCommand(cmdList) # # Assign the STG paint # cmdList = (progName, "-paint-assign-to-nodes", paintFileName, paintFileGyralSTGName, paintColumnName, "GYRAL.STG", "-assign-from-roi-file", stgRoiFileName); runCommand(cmdList) ############################################### # # STOP STOP STOP # return # # Create an ROI that identifies the central sulcus nodes # with paint name GYRAL.STG and Shape folding ranging 0.10 to 100 # cmdList = (progName, "-surface-region-of-interest-selection", inflatedCoordFileName, inputTopoFile, roiFileName, roiFileName, "-paint", paintFileGyralSTGName, paintColumnName, # column name "GYRAL.STG", # paint name "NORMAL", # normal selection "-shape", shapeCurvatureFileName, "1", # column number "0.1 100.0", # value range "AND") # AND with previous selection runCommand(cmdList) # # Create limits at posterior and ventral ends of GYRAL.STG # stgPosteriorFocusName = "STG-posterior.Case" + caseNumberString stgVentralFocusName = "STG-ventral.Case" + caseNumberString cmdList = (progName, "-surface-place-foci-at-limits", fiducialCoordFileName, inflatedCoordFileName, inputTopoFile, roiFileName, fociProjectionFileName, fociProjectionFileName, "-y-min " + stgPosteriorFocusName, "-z-min " + stgVentralFocusName) runCommand(cmdList) # # Create an ROI that identifies the superior temporal gyrus nodes # with paint name GYRAL.STG and Shape folding ranging 0.16 to 100 # cmdList = (progName, "-surface-region-of-interest-selection", inflatedCoordFileName, inputTopoFile, roiStringentFileName, roiStringentFileName, "-paint", paintFileGyralSTGName, paintColumnName, # column name "GYRAL.STG", # paint name "NORMAL", # normal selection "-shape", shapeCurvatureFileName, "1", # column number "0.16 100.0", # value range "AND") # AND with previous selection runCommand(cmdList) # # Create the draw border comand to draw the LANDMARK.SF_STSant border # borderSampling = 1.0 cmdList = (progName, "-surface-border-draw-geodesic", inflatedCoordFileName, inputTopoFile, fociProjectionFileName, stgPosteriorFocusName, stgVentralFocusName, roiStringentFileName, borderProjectionFileName, borderProjectionFileName, "LANDMARK.SF_STSant", str(borderSampling)) runCommand(cmdList) ##----------------------------------------------------------------------------- ## ## Identify all superior temporal gyri def identifyAllSuperiorTemporalGyri() : # # Add Colors to Foci File # cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "STS_Inflated_Ventral", str(0), str(150), str(255), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "STS_Inflated_Dorsal", str(0), str(150), str(255), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "TemporalPole", str(100), str(0), str(200), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "STG-posterior", str(0), str(150), str(255), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "STG-ventral", str(0), str(150), str(255), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "STG", str(100), str(255), str(150), "-point-size 1", "-symbol SPHERE"); runCommand(cmdList) # # Add paint colors # #cmdList = (progName, # "-color-file-add-color", # areaColorFileName, # areaColorFileName, # "GYRAL.STG", # str(100), # str(255), # str(150), # "-point-size 1", # "-symbol SPHERE"); runCommand(cmdList) # # Add border colors # cmdList = (progName, "-color-file-add-color", borderColorFileName, borderColorFileName, "LANDMARK.SF_STSant", str(255), str(0), str(187), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) # # ID the central sulcus on the specified cases # for caseID in range(startCaseNumber, endCaseNumber) : identifySuperiorTemporalGyrus(str(caseID)) ##----------------------------------------------------------------------------- ## ## Identify the calcarine sulcus ## def identifyCalcarineSulcus(caseNumberString) : # # Global variables # # # Assemble file names # borderProjectionFileName = borderProjectionFilePrefix \ + caseNumberString \ + borderProjectionFileSuffix fiducialCoordFileName = fiducialCoordFilePrefix \ + caseNumberString \ + fiducialCoordFileSuffix fociProjectionFileName = fociProjectionFilePrefix \ + caseNumberString \ + fociProjectionFileSuffix inflatedCoordFileName = inflatedCoordFilePrefix \ + caseNumberString \ + inflatedCoordFileSuffix paintFileName = paintFilePrefix \ + caseNumberString \ + paintFileSuffix paintColumnName = "\"Sulcus ID.Buck_Case" \ + caseNumberString \ + ".R\"" roiFileName = "Human.case" \ + caseNumberString \ + "." \ + "CaS" \ + ".roi" roiStringentFileName = "Human.case" \ + caseNumberString \ + "." \ + "CaS_Stringent" \ + ".roi" shapeCurvatureFileName = shapeCurvatureFilePrefix \ + caseNumberString \ + shapeCurvatureFileSuffix # # Create an ROI that identifies the central sulcus nodes # with paint name SUL.CaS and Shape folding ranging -100 to -0.10 # cmdList = (progName, "-surface-region-of-interest-selection", inflatedCoordFileName, inputTopoFile, roiFileName, roiFileName, "-paint", paintFileName, paintColumnName, # column name "SUL.CaS", # paint name "NORMAL", # normal selection "-shape", shapeCurvatureFileName, "1", # column number "-100.0 -0.10", # value range "AND") # AND with previous selection runCommand(cmdList) # # Create foci at some limits of ROI # casAnteriorFocusName = "CaS-anterior.Case" + caseNumberString casPosteriorFocusName = "CaS-posterior.Case" + caseNumberString cmdList = (progName, "-surface-place-foci-at-limits", fiducialCoordFileName, inflatedCoordFileName, inputTopoFile, roiFileName, fociProjectionFileName, fociProjectionFileName, "-y-max " + casAnteriorFocusName, "-y-min " + casPosteriorFocusName) runCommand(cmdList) # # Create an ROI that identifies the central sulcus nodes # with paint name SUL.CaS and Shape folding ranging -100 to -0.16 # cmdList = (progName, "-surface-region-of-interest-selection", inflatedCoordFileName, inputTopoFile, roiStringentFileName, roiStringentFileName, "-paint", paintFileName, paintColumnName, # column name "SUL.CaS", # paint name "NORMAL", # normal selection "-shape", shapeCurvatureFileName, "1", # column number "-100.0 -0.16", # value range "AND") # AND with previous selection runCommand(cmdList) # # Create the draw border comand to draw the LANDMARK.CalcarineSulcus border # borderSampling = 1.0 cmdList = (progName, "-surface-border-draw-geodesic", inflatedCoordFileName, inputTopoFile, fociProjectionFileName, casPosteriorFocusName, casAnteriorFocusName, roiStringentFileName, borderProjectionFileName, borderProjectionFileName, "LANDMARK.CalcarineSulcus", str(borderSampling)) runCommand(cmdList) # # Find extremum point for lateral side # casPosteriorExtremeFocusName = "CaS-PosteriorExtreme.Case" + caseNumberString cmdList = (progName, "-surface-place-focus-at-extremum", fiducialCoordFileName, inflatedCoordFileName, inputTopoFile, fociProjectionFileName, casPosteriorFocusName, fociProjectionFileName, casPosteriorExtremeFocusName, "Y-NEG", str(100000.0), str(100000.0), str(100000.0)) runCommand(cmdList) # # Trim border 24mm from posterior extreme # cmdList = (progName, "-surface-border-nibbler", inflatedCoordFileName, inputTopoFile, borderProjectionFileName, borderProjectionFileName, "LANDMARK.CalcarineSulcus", "LANDMARK.CalcarineSulcus", fociProjectionFileName, casPosteriorExtremeFocusName, "-within-y-distance 24") runCommand(cmdList) ##----------------------------------------------------------------------------- ## ## Identify all calcarine sulci def identifyAllCalcarineSulci() : # # Add Colors to Foci File # cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "CaS-posterior", str(0), str(150), str(255), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "CaS-anterior", str(0), str(150), str(255), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "CaS-PosteriorExtreme", str(0), str(255), str(0), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", borderColorFileName, borderColorFileName, "LANDMARK.CalcarineSulcus", str(246), str(114), str(0)); runCommand(cmdList) # # ID the central sulcus on the specified cases # for caseID in range(startCaseNumber, endCaseNumber) : identifyCalcarineSulcus(str(caseID)) ##----------------------------------------------------------------------------- ## ## Identify the central sulcus ## def identifyCentralSulcus(caseNumberString) : # # Global variables # # # Assemble file names # borderProjectionFileName = borderProjectionFilePrefix \ + caseNumberString \ + borderProjectionFileSuffix fiducialCoordFileName = fiducialCoordFilePrefix \ + caseNumberString \ + fiducialCoordFileSuffix fociProjectionFileName = fociProjectionFilePrefix \ + caseNumberString \ + fociProjectionFileSuffix inflatedCoordFileName = inflatedCoordFilePrefix \ + caseNumberString \ + inflatedCoordFileSuffix paintFileName = paintFilePrefix \ + caseNumberString \ + paintFileSuffix paintColumnName = "\"Sulcus ID.Buck_Case" \ + caseNumberString \ + ".R\"" roiFileName = "Human.case" \ + caseNumberString \ + "." \ + "CeS" \ + ".roi" roiStringentFileName = "Human.case" \ + caseNumberString \ + "." \ + "CeS_Stringent" \ + ".roi" shapeCurvatureFileName = shapeCurvatureFilePrefix \ + caseNumberString \ + shapeCurvatureFileSuffix # # Create an ROI that identifies the central sulcus nodes # with paint name SUL.CeS and Shape folding ranging -100 to -0.10 # cmdList = (progName, "-surface-region-of-interest-selection", inflatedCoordFileName, inputTopoFile, roiFileName, roiFileName, "-paint", paintFileName, paintColumnName, # column name "SUL.CeS", # paint name "NORMAL", # normal selection "-shape", shapeCurvatureFileName, "1", # column number "-100.0 -0.10", # value range "AND") # AND with previous selection runCommand(cmdList) # # Create foci at some limits of ROI # cesMedialFocusName = "CeS-medial.Case" + caseNumberString cesVentralFocusName = "CeS-ventral.Case" + caseNumberString cmdList = (progName, "-surface-place-foci-at-limits", fiducialCoordFileName, inflatedCoordFileName, inputTopoFile, roiFileName, fociProjectionFileName, fociProjectionFileName, "-z-min " + cesVentralFocusName, "-x-most-medial " + cesMedialFocusName) runCommand(cmdList) # # Create an ROI that identifies the central sulcus nodes # with paint name SUL.CeS and Shape folding ranging -100 to -0.16 # cmdList = (progName, "-surface-region-of-interest-selection", inflatedCoordFileName, inputTopoFile, roiStringentFileName, roiStringentFileName, "-paint", paintFileName, paintColumnName, # column name "SUL.CeS", # paint name "NORMAL", # normal selection "-shape", shapeCurvatureFileName, "1", # column number "-100.0 -0.16", # value range "AND") # AND with previous selection runCommand(cmdList) # # Create the draw border comand to draw the LANDMARK.CentralSulcus border # borderSampling = 1.0 cmdList = (progName, "-surface-border-draw-geodesic", inflatedCoordFileName, inputTopoFile, fociProjectionFileName, cesVentralFocusName, cesMedialFocusName, roiStringentFileName, borderProjectionFileName, borderProjectionFileName, "LANDMARK.CentralSulcus", str(borderSampling)) runCommand(cmdList) # # Find extremum point for lateral side # cesVentralExtremeFocusName = "CeS-VentralExtreme.Case" + caseNumberString cmdList = (progName, "-surface-place-focus-at-extremum", fiducialCoordFileName, inflatedCoordFileName, inputTopoFile, fociProjectionFileName, cesVentralFocusName, fociProjectionFileName, cesVentralExtremeFocusName, "Z-NEG", str(100000.0), str(3.0), str(100000.0)) runCommand(cmdList) # # Find extremum point for medial side # cesMedialExtremeFocusName = "CeS-MedialExtreme.Case" + caseNumberString cmdList = (progName, "-surface-place-focus-at-extremum", fiducialCoordFileName, inflatedCoordFileName, inputTopoFile, fociProjectionFileName, cesMedialFocusName, fociProjectionFileName, cesMedialExtremeFocusName, "X-MEDIAL", str(100000.0), str(5.0), str(100000.0)) runCommand(cmdList) # # Trim border 19mm above ventral extreme # cmdList = (progName, "-surface-border-nibbler", inflatedCoordFileName, inputTopoFile, borderProjectionFileName, borderProjectionFileName, "LANDMARK.CentralSulcus", "LANDMARK.CentralSulcus", fociProjectionFileName, cesVentralExtremeFocusName, "-within-z-distance 19") runCommand(cmdList) # # Trim border 18mm lateral to midline # trimValue = -18 if (rightHemFlag) : trimValue = 18 cmdList = (progName, "-surface-border-nibbler", inflatedCoordFileName, inputTopoFile, borderProjectionFileName, borderProjectionFileName, "LANDMARK.CentralSulcus", "LANDMARK.CentralSulcus", fociProjectionFileName, cesMedialExtremeFocusName, "-within-x-distance ", str(trimValue)) runCommand(cmdList) ##----------------------------------------------------------------------------- ## ## Identify all central sulci def identifyAllCentralSulci() : # # Add Colors to Foci File # cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "CeS-medial", str(255), str(0), str(0), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "CeS-ventral", str(0), str(255), str(0), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "CeS-MedialExtreme", str(255), str(0), str(0), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "CeS-VentralExtreme", str(0), str(255), str(0), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", borderColorFileName, borderColorFileName, "LANDMARK.CentralSulcus", str(255), str(255), str(0)); runCommand(cmdList) # # ID the central sulcus on the specified cases # for caseID in range(startCaseNumber, endCaseNumber) : identifyCentralSulcus(str(caseID)) ##----------------------------------------------------------------------------- ## ## Combine paint files ## def combinePaintFiles() : # # Global variables # global outputCompositePaintFileName global outputPaintFiles global progName # # Create the command # cmd = progName \ + " -paint-composite " \ + outputCompositePaintFileName \ + " " \ + " ".join(outputPaintFiles) print "\nExecuting: %s\n" % cmd result = os.system(cmd) if (result != 0) : print "COMMAND FAILED: " print " ", cmd os._exit(-1) ##----------------------------------------------------------------------------- ## ## Run sulcal identification ## def runSulcalIdentificationSome() : # # Global variables # global clusterRatio global fiducialCoordFiles global inputPaintFile global inputShapeFile global inputTopoFile global outputPaintFiles global progName # # loop through the coord files # paintShapeColumnNumber = 0 for coordFile in fiducialCoordFiles : # # Create the command string # paintShapeColumnNumber = paintShapeColumnNumber + 1 cmdList = (progName, "-surface-sulcal-named-identification", coordFile, inputTopoFile, inputPaintFile, str(paintShapeColumnNumber), inputShapeFile, str(paintShapeColumnNumber), str(clusterRatio), outputPaintFiles[paintShapeColumnNumber-1]) cmd = " ".join(cmdList) print "\nExecuting: %s\n" % cmd result = os.system(cmd) if (result != 0) : print "COMMAND FAILED: " print " ", cmd os._exit(-1) ##----------------------------------------------------------------------------- ## ## Run ALL sulcal identification ## def runSulcalIdentificationAll() : # # Global variables # global clusterRatio global fiducialCoordFiles global inputPaintFile global inputShapeFile global inputTopoFile global outputPaintFiles global postCentralSulcusOffset global postCentralSulcusStdDevSquared global postCentralSulcusSplit global probabilisticSulcusVolumeListFileName global progName global veryInflatedCoordFile # # loop through the coord files # paintShapeColumnNumber = 0 for coordFile in fiducialCoordFiles : # # Create the command string # paintShapeColumnNumber = paintShapeColumnNumber + 1 cmdList = (progName, "-surface-sulcal-named-all-identification", coordFile, veryInflatedCoordFile, inputTopoFile, inputPaintFile, str(paintShapeColumnNumber), inputShapeFile, str(paintShapeColumnNumber), probabilisticSulcusVolumeListFileName, str(postCentralSulcusOffset), str(postCentralSulcusStdDevSquared), str(postCentralSulcusSplit), outputPaintFiles[paintShapeColumnNumber-1]) cmd = " ".join(cmdList) print "\nExecuting: %s\n" % cmd result = os.system(cmd) if (result != 0) : print "COMMAND FAILED: " print " ", cmd os._exit(-1) ##----------------------------------------------------------------------------- ## ## Print help information ## def printHelp() : print "Options" #print "-cas Identify calcarine sulcus landmark." #print "-ces Identify central sulcus landmark." print "-cpf Combine the output paint files into a composite file." print "-landmarks Identify Calcarine, Central, Sylvian, Superior Temporal" print "-mw Identify medial wall landmark." #print "-sf Identify sylvian fissure landmark." #print "-stg Identify superior temporal gyrus landmark." print "-run-all Run the sulcal (Paint) identification of ALL sulci." print "-run-some Run the sulcal (Paint)identification of CeSi and SF." ##----------------------------------------------------------------------------- ## ## "Main" code ## # # Get number of arguments # numArgs = len(sys.argv) if (numArgs <= 1) : printHelp() os._exit(0) # # Flags for different operations # doCalcarineSulcus = False doCentralSulcus = False doCombinePaint = False doMedialWall = False doRemoveFiles = False doRunSome = False doRunAll = False doSuperiorTemporalGyrus = False doSylvianFissure = False # # Process arguments # for i in range (1, numArgs) : arg = sys.argv[i] if (arg == "-cas") : doCalcarineSulcus = True elif (arg == "-ces") : doCentralSulcus = True elif (arg == "-cpf") : doCombinePaint = True elif (arg == "-landmarks") : doCalcarineSulcus = True doCentralSulcus = True doSylvianFissure = True doSuperiorTemporalGyrus = True elif (arg == "-mw") : doMedialWall = True elif (arg == "-run-all") : doRunAll = True elif (arg == "-run-some") : doRunSome = True elif (arg == "-sf") : doSylvianFissure = True elif (arg == "-stg") : doSuperiorTemporalGyrus = True else: print "ERROR Invalid option: ", arg os._exit(-1) if (doRunAll) : runSulcalIdentificationAll() if (doRunSome) : runSulcalIdentificationSome() if (doCombinePaint) : combinePaintFiles() if (doCentralSulcus or \ doCalcarineSulcus or \ doSylvianFissure or \ doSuperiorTemporalGyrus) : removeSulcalIdentficationBorderAndFociProjectionFiles() if (doCentralSulcus) : identifyAllCentralSulci() if (doCalcarineSulcus) : identifyAllCalcarineSulci() if (doSuperiorTemporalGyrus) : identifyAllSuperiorTemporalGyri() if (doSylvianFissure) : identifyAllSylvianFissure() if (doMedialWall) : identifyAllMedialWalls() caret-5.6.4~dfsg.1.orig/caret_scripts/run_sulcal_id_K05.py0000755000175000017500000015153711572067322023257 0ustar michaelmichael#!/usr/bin/python # # Imports # import os import sys # # Global Variables # progName = "/Users/john/caret5_osx/caret_source/caret_command_new/caret_command_new" #progName = "caret_command_new" # # Post Central Sulcus parameters # postCentralSulcusOffset = 25.0 postCentralSulcusStdDevSquared = 100.0 postCentralSulcusSplit = 5.0 probabilisticSulcusVolumeListFileName = "probabilistic-depth-volume.csv" ##----------------------------------------------------------------------------- # # Run a command # def runCommand(cmdList) : cmd = " ".join(cmdList) # join cmdList into a string separated by blanks print "\nExecuting: %s\n" % cmd result = os.system(cmd) if (result != 0) : print "COMMAND FAILED: " print " ", cmd os._exit(-1) ##----------------------------------------------------------------------------- ## ## Generate Sulcal Paint Identification File ## def createSulcalIdentificationPaintFile() : cmdList = (progName, "-system-file-delete", paintFileName) runCommand(cmdList) cmdList = (progName, "-surface-sulcal-named-all-identification", fiducialCoordFileName, veryInflatedCoordFileName, closedTopoFileName, geographyPaintFileName, paintFileName, geographyPaintColumnName, shapeFileName, shapeFileDepthColumnName, probabilisticSulcusVolumeListFileName, str(postCentralSulcusOffset), str(postCentralSulcusStdDevSquared), str(postCentralSulcusSplit)) runCommand(cmdList) ##----------------------------------------------------------------------------- ## ## Identify central sulcus def identifyCentralSulcus() : # # Add Colors to Foci File # cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "CeS-medial", str(255), str(0), str(0), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "CeS-ventral", str(0), str(255), str(0), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "CeS-MedialExtreme", str(255), str(0), str(0), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "CeS-VentralExtreme", str(0), str(255), str(0), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", borderColorFileName, borderColorFileName, "LANDMARK.CentralSulcus", str(255), str(255), str(0)); runCommand(cmdList) # # Delete any existing foci with these names # cesMedialFocusName = "CeS-medial" cesVentralFocusName = "CeS-ventral" cesVentralExtremeFocusName = "CeS-VentralExtreme" cesMedialExtremeFocusName = "CeS-MedialExtreme" cmdList = (progName, "-surface-foci-delete", fociProjectionFileName, fociProjectionFileName, cesMedialFocusName, cesVentralFocusName, cesVentralExtremeFocusName, cesMedialExtremeFocusName) runCommand(cmdList) # # Delete any existing border with these names # landmarkCentralSulcusBorderName = "LANDMARK.CentralSulcus" cmdList = (progName, "-surface-border-delete", borderProjectionFileName, borderProjectionFileName, landmarkCentralSulcusBorderName) runCommand(cmdList) # # Create an ROI that identifies the central sulcus nodes # with paint name SUL.CeS and Shape folding ranging -100 to -0.10 # cmdList = (progName, "-surface-region-of-interest-selection", inflatedCoordFileName, closedTopoFileName, roiCeSFileName, roiCeSFileName, "-paint", paintFileName, sulcusIdPaintColumnName, # column name "SUL.CeS", # paint name "NORMAL", # normal selection "-shape", shapeFileName, shapeFileCurvatureColumnName, # column number "-100.0 -0.10", # value range "AND") # AND with previous selection runCommand(cmdList) # # Create foci at some limits of ROI # cmdList = (progName, "-surface-place-foci-at-limits", fiducialCoordFileName, inflatedCoordFileName, closedTopoFileName, roiCeSFileName, fociProjectionFileName, fociProjectionFileName, "-z-min " + cesVentralFocusName, "-x-most-medial " + cesMedialFocusName) runCommand(cmdList) # # Create an ROI that identifies the central sulcus nodes # with paint name SUL.CeS and Shape folding ranging -100 to -0.16 # cmdList = (progName, "-surface-region-of-interest-selection", inflatedCoordFileName, closedTopoFileName, roiStringentCeSFileName, roiStringentCeSFileName, "-paint", paintFileName, sulcusIdPaintColumnName, # column name "SUL.CeS", # paint name "NORMAL", # normal selection "-shape", shapeFileName, shapeFileCurvatureColumnName, # column number "-100.0 -0.16", # value range "AND") # AND with previous selection runCommand(cmdList) # # Create the draw border comand to draw the LANDMARK.CentralSulcus border # borderSampling = 1.0 cmdList = (progName, "-surface-border-draw-geodesic", inflatedCoordFileName, closedTopoFileName, fociProjectionFileName, cesVentralFocusName, cesMedialFocusName, roiStringentCeSFileName, borderProjectionFileName, borderProjectionFileName, landmarkCentralSulcusBorderName, str(borderSampling)) runCommand(cmdList) # # Find extremum point for lateral side # cmdList = (progName, "-surface-place-focus-at-extremum", fiducialCoordFileName, inflatedCoordFileName, closedTopoFileName, fociProjectionFileName, cesVentralFocusName, fociProjectionFileName, cesVentralExtremeFocusName, "Z-NEG", str(100000.0), str(3.0), str(100000.0)) runCommand(cmdList) # # Find extremum point for medial side # cmdList = (progName, "-surface-place-focus-at-extremum", fiducialCoordFileName, inflatedCoordFileName, closedTopoFileName, fociProjectionFileName, cesMedialFocusName, fociProjectionFileName, cesMedialExtremeFocusName, "X-MEDIAL", str(100000.0), str(5.0), str(100000.0)) runCommand(cmdList) # # Trim border 19mm above ventral extreme # cmdList = (progName, "-surface-border-nibbler", inflatedCoordFileName, closedTopoFileName, borderProjectionFileName, borderProjectionFileName, landmarkCentralSulcusBorderName, landmarkCentralSulcusBorderName, fociProjectionFileName, cesVentralExtremeFocusName, "-within-z-distance 19") runCommand(cmdList) # # Trim border 18mm lateral to midline # trimValue = -18 if (rightHemFlag) : trimValue = 18 cmdList = (progName, "-surface-border-nibbler", inflatedCoordFileName, closedTopoFileName, borderProjectionFileName, borderProjectionFileName, landmarkCentralSulcusBorderName, landmarkCentralSulcusBorderName, fociProjectionFileName, cesMedialExtremeFocusName, "-within-x-distance ", str(trimValue)) runCommand(cmdList) ##----------------------------------------------------------------------------- ## ## Identify calcarine sulci def identifyCalcarineSulcus() : # # Add Colors to Foci File # cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "CaS-posterior", str(0), str(150), str(255), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "CaS-anterior", str(0), str(150), str(255), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "CaS-PosteriorExtreme", str(0), str(255), str(0), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", borderColorFileName, borderColorFileName, "LANDMARK.CalcarineSulcus", str(246), str(114), str(0)); runCommand(cmdList) # # Delete any existing foci with these names # casAnteriorFocusName = "CaS-anterior" casPosteriorFocusName = "CaS-posterior" casPosteriorExtremeFocusName = "CaS-PosteriorExtreme" cmdList = (progName, "-surface-foci-delete", fociProjectionFileName, fociProjectionFileName, casAnteriorFocusName, casPosteriorFocusName, casPosteriorExtremeFocusName) runCommand(cmdList) # # Delete any existing border with these names # landmarkCalcarineSulcusBorderName = "LANDMARK.CalcarineSulcus" cmdList = (progName, "-surface-border-delete", borderProjectionFileName, borderProjectionFileName, landmarkCalcarineSulcusBorderName) runCommand(cmdList) # # Create an ROI that identifies the central sulcus nodes # with paint name SUL.CaS and Shape folding ranging -100 to -0.10 # cmdList = (progName, "-surface-region-of-interest-selection", inflatedCoordFileName, closedTopoFileName, roiCaSFileName, roiCaSFileName, "-paint", paintFileName, sulcusIdPaintColumnName, # column name "SUL.CaS", # paint name "NORMAL", # normal selection "-shape", shapeFileName, shapeFileCurvatureColumnName, # column number "-100.0 -0.10", # value range "AND") # AND with previous selection runCommand(cmdList) # # Create foci at some limits of ROI # cmdList = (progName, "-surface-place-foci-at-limits", fiducialCoordFileName, inflatedCoordFileName, closedTopoFileName, roiCaSFileName, fociProjectionFileName, fociProjectionFileName, "-y-max " + casAnteriorFocusName, "-y-min " + casPosteriorFocusName) runCommand(cmdList) # # Create an ROI that identifies the central sulcus nodes # with paint name SUL.CaS and Shape folding ranging -100 to -0.16 # cmdList = (progName, "-surface-region-of-interest-selection", inflatedCoordFileName, closedTopoFileName, roiStringentCaSFileName, roiStringentCaSFileName, "-paint", paintFileName, sulcusIdPaintColumnName, # column name "SUL.CaS", # paint name "NORMAL", # normal selection "-shape", shapeFileName, shapeFileCurvatureColumnName, # column number "-100.0 -0.16", # value range "AND") # AND with previous selection runCommand(cmdList) # # Create the draw border comand to draw the LANDMARK.CalcarineSulcus border # borderSampling = 1.0 cmdList = (progName, "-surface-border-draw-geodesic", inflatedCoordFileName, closedTopoFileName, fociProjectionFileName, casPosteriorFocusName, casAnteriorFocusName, roiStringentCaSFileName, borderProjectionFileName, borderProjectionFileName, landmarkCalcarineSulcusBorderName, str(borderSampling)) runCommand(cmdList) # # Find extremum point for lateral side # cmdList = (progName, "-surface-place-focus-at-extremum", fiducialCoordFileName, inflatedCoordFileName, closedTopoFileName, fociProjectionFileName, casPosteriorFocusName, fociProjectionFileName, casPosteriorExtremeFocusName, "Y-NEG", str(100000.0), str(100000.0), str(100000.0)) runCommand(cmdList) # # Trim border 24mm from posterior extreme # cmdList = (progName, "-surface-border-nibbler", inflatedCoordFileName, closedTopoFileName, borderProjectionFileName, borderProjectionFileName, landmarkCalcarineSulcusBorderName, landmarkCalcarineSulcusBorderName, fociProjectionFileName, casPosteriorExtremeFocusName, "-within-y-distance 24") runCommand(cmdList) ##----------------------------------------------------------------------------- ## ## Identify superior temporal gyrus def identifySuperiorTemporalGyrus() : # # Add Colors to Foci File # cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "STS_Inflated_Ventral", str(0), str(150), str(255), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "STS_Inflated_Dorsal", str(0), str(150), str(255), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "TemporalPole", str(100), str(0), str(200), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "STG-posterior", str(0), str(150), str(255), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "STG-ventral", str(0), str(150), str(255), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "STG", str(100), str(255), str(150), "-point-size 1", "-symbol SPHERE"); runCommand(cmdList) # # Delete any existing foci with these names # stsVentralFocusName = "STS_Inflated_Ventral" stsDorsalFocusName = "STS_Inflated_Dorsal" temporalPoleFocusName = "TemporalPole" stgPathFocusName = "STG-posterior" stgCesLimitFocusName = "STG-CES-limit" cmdList = (progName, "-surface-foci-delete", fociProjectionFileName, fociProjectionFileName, stsVentralFocusName, stsDorsalFocusName, temporalPoleFocusName, stgPathFocusName, stgCesLimitFocusName) runCommand(cmdList) # # Delete any existing border with these names # stgBorderName = "LANDMARK.SF_STSant" cmdList = (progName, "-surface-border-delete", borderProjectionFileName, borderProjectionFileName, stgBorderName) runCommand(cmdList) # # Add border colors # cmdList = (progName, "-color-file-add-color", borderColorFileName, borderColorFileName, "LANDMARK.SF_STSant", str(255), str(0), str(187), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) # # Create an ROI that identifies the superior temporal sulcus # with paint name SUL.STS # cmdList = (progName, "-surface-region-of-interest-selection", inflatedCoordFileName, closedTopoFileName, roiSTGFileName, roiSTGFileName, "-paint", paintFileName, sulcusIdPaintColumnName, # column name "SUL.STS", # paint name "NORMAL") # AND with previous selection runCommand(cmdList) # # Create foci at some limits of ROI # cmdList = (progName, "-surface-place-foci-at-limits", fiducialCoordFileName, inflatedCoordFileName, closedTopoFileName, roiSTGFileName, fociProjectionFileName, fociProjectionFileName, "-z-min " + stsVentralFocusName, "-z-max " + stsDorsalFocusName) runCommand(cmdList) # # Find extremum point for temporal pole # cmdList = (progName, "-surface-place-focus-at-extremum", fiducialCoordFileName, inflatedCoordFileName, closedTopoFileName, fociProjectionFileName, stsVentralFocusName, fociProjectionFileName, temporalPoleFocusName, "Y-POS", str(100000.0), str(100000.0), str(100000.0)) runCommand(cmdList) # # Create a transformation matrix rotated Y=-45 # rotateString = "-rotate 0.0 45.0 0.0" if (rightHemFlag) : rotateString = "-rotate 0.0 -45.0 0.0" transformationMatrixFileName = "TempRotateYMinus45.matrix" transformationMatrixName = "RotateYMinus45" cmdList = (progName, "-transformation-matrix-create", transformationMatrixFileName, transformationMatrixFileName, transformationMatrixName, "-delete-all-matrices-from-file", "-matrix-comment \"rotate minus 45 degrees about Y-axis\"", rotateString) runCommand(cmdList) # # Create a temporary surface rotated Y-45 # tempRotateY45InflatedCoordFileName = "temp.rotatedY45.coord" cmdList = (progName, "-surface-apply-transformation-matrix", inflatedCoordFileName, closedTopoFileName, tempRotateY45InflatedCoordFileName, "-matrix-file ", transformationMatrixFileName, transformationMatrixName) #"-matrix", # "0.707107 0.000000 -0.707107 0.000000", # "0.000000 1.000000 0.000000 0.000000", # "0.707107 0.000000 0.707107 0.000000", # "0.000000 0.000000 0.000000 1.000000") #"-matrix-file STG.matrix Y45Down"); runCommand(cmdList) # # Find extremum point starting at temporal pole # moving in a posterior/superior direction along the STG # cmdList = (progName, "-surface-place-focus-at-extremum", fiducialCoordFileName, tempRotateY45InflatedCoordFileName, closedTopoFileName, fociProjectionFileName, temporalPoleFocusName, fociProjectionFileName, stgPathFocusName, "Z-POS", str(100000.0), str(100000.0), str(100000.0), "-create-roi-from-path", roiSTGFileName) #"-start-offset 3.0 0.0 0.0") runCommand(cmdList) # # Limit the ROI so it does not go beyond temporal pole # or beyond the Y position of the ventral tip of the # central sulcus # cesVentralFocusName = "CeS-ventral" cmdList = (progName, "-surface-region-of-interest-selection", inflatedCoordFileName, closedTopoFileName, roiSTGFileName, roiSTGFileName, "-limit-y-min-focus", fociProjectionFileName, cesVentralFocusName, "-limit-y-max-focus", fociProjectionFileName, temporalPoleFocusName, "-limit-z-min-focus", fociProjectionFileName, temporalPoleFocusName) runCommand(cmdList) # # Create limits at posterior and ventral ends of GYRAL.STG # cmdList = (progName, "-surface-place-foci-at-limits", fiducialCoordFileName, inflatedCoordFileName, closedTopoFileName, roiSTGFileName, fociProjectionFileName, fociProjectionFileName, "-y-min " + stgCesLimitFocusName) runCommand(cmdList) # # Create the draw border comand to draw the LANDMARK.SF_STSant border # borderSampling = 1.0 cmdList = (progName, "-surface-border-draw-geodesic", inflatedCoordFileName, closedTopoFileName, fociProjectionFileName, stgCesLimitFocusName, temporalPoleFocusName, roiSTGFileName, borderProjectionFileName, borderProjectionFileName, stgBorderName, str(borderSampling)) runCommand(cmdList) ###################################################### # The following steps are not necessary but assign paint # for the STG # # # Dilate the STG ROI but only nodes identified as GYRAL # and limit the extent of the ROI so that it does not # go posterior to ventral tip of central sulcus or # beyond the temporal pole. # dilateIterations = 5 cmdList = (progName, "-surface-region-of-interest-selection", inflatedCoordFileName, closedTopoFileName, roiSTGFileName, roiSTGFileName, "-dilate-paint", paintFileName, sulcusIdPaintColumnName, "SUL.SF", # SF may be too big str(dilateIterations), "-dilate-paint", paintFileName, sulcusIdPaintColumnName, "GYRAL", str(dilateIterations), "-limit-y-min-focus", fociProjectionFileName, cesVentralFocusName, "-limit-y-max-focus", fociProjectionFileName, temporalPoleFocusName, "-limit-z-min-focus", fociProjectionFileName, temporalPoleFocusName, ) runCommand(cmdList) # # Assign the STG paint # cmdList = (progName, "-paint-assign-to-nodes", paintFileName, paintFileGyralSTGName, sulcusIdPaintColumnName, "GYRAL.STG", "-assign-from-roi-file", roiSTGFileName); runCommand(cmdList) ##----------------------------------------------------------------------------- ## ## Identify sylvian fissure ## def identifySylvianFissure() : # # Add Colors to Foci File # cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "SF", str(50), str(255), str(255), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) ventralFrontalExtremeFocusName = "SF_VentralFrontalExtreme" cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "SF", str(0), str(255), str(0), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) ventralFrontalFocusName = "SF_VentralFrontal" cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "SF", str(0), str(0), str(255), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) # # Add border colors # cmdList = (progName, "-color-file-add-color", borderColorFileName, borderColorFileName, "LANDMARK.SF", str(0), str(255), str(255), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) # # Delete any existing foci with these names # sfAnteriorFocusName = "SF_Anterior" sfPosteriorFocusName = "SF_Posterior" sfDorsalFocusName = "SF_Dorsal" ventralFrontalFocusName = "SF_VentralFrontal" ventralFrontalExtremeFocusName = "SF_VentralFrontalExtreme" sfVentralFocusName = "SF_VentralNearSecondary_SF" sylvianIntersectionFocusName = "SF_Intersect_Superior_Inferior" ventralFrontalExtremeFocusName = "SF_VentralFrontalExtreme" cmdList = (progName, "-surface-foci-delete", fociProjectionFileName, fociProjectionFileName, sfAnteriorFocusName, sfPosteriorFocusName, sfDorsalFocusName, ventralFrontalFocusName, ventralFrontalExtremeFocusName, sfVentralFocusName, sylvianIntersectionFocusName, ventralFrontalExtremeFocusName) runCommand(cmdList) # # Delete any existing border with these names # sylvianFissureBorderName = "LANDMARK.SF" secondarySylvianFissureBorderName = "LANDMARK.SF-secondary" cmdList = (progName, "-surface-border-delete", borderProjectionFileName, borderProjectionFileName, sylvianFissureBorderName, secondarySylvianFissureBorderName) runCommand(cmdList) # # Generate curvature on the INFLATED surface # cmdList = (progName, "-surface-curvature", inflatedCoordFileName, closedTopoFileName, inflatedShapeCurvatureFileName, inflatedShapeCurvatureFileName, "-generate-mean-curvature", "-mean-column-name", inflatedCurvatureColumnName); runCommand(cmdList); # # Create an ROI that identifies the sylvian fissure # with paint name SUL.SF # cmdList = (progName, "-surface-region-of-interest-selection", inflatedCoordFileName, closedTopoFileName, roiSFFileName, roiSFFileName, "-paint", paintFileName, sulcusIdPaintColumnName, # column name "SUL.SF", # paint name "NORMAL") # normal selection runCommand(cmdList) # # Erode the ROI since SF paint tends to be too big # cmdList = (progName, "-surface-region-of-interest-selection", inflatedCoordFileName, closedTopoFileName, roiSFFileName, roiSFErodedFileName, "-erode 5") runCommand(cmdList) # # Create foci at some limits of ROI at eroded ROI # cmdList = (progName, "-surface-place-foci-at-limits", fiducialCoordFileName, inflatedCoordFileName, closedTopoFileName, roiSFErodedFileName, fociProjectionFileName, fociProjectionFileName, "-y-max " + sfAnteriorFocusName, "-y-min " + sfPosteriorFocusName, "-z-max " + sfDorsalFocusName) runCommand(cmdList) # # Limit original ROI to apply curvature limits # cmdList = (progName, "-surface-region-of-interest-selection", inflatedCoordFileName, closedTopoFileName, roiSFFileName, roiStringentSFFileName, "-shape", inflatedShapeCurvatureFileName, inflatedCurvatureColumnName, str(-100.0), str(-0.07), # use -0.7 since inflated "AND") runCommand(cmdList) # # Draw border from posterior to anterior of SF # USES GEODESIC METHOD # borderSampling = 1.0 cmdList = (progName, "-surface-border-draw-geodesic", inflatedCoordFileName, closedTopoFileName, fociProjectionFileName, sfPosteriorFocusName, sfAnteriorFocusName, roiStringentSFFileName, borderProjectionFileName, borderProjectionFileName, "LANDMARK.SF1", str(borderSampling)) runCommand(cmdList) # # USES CURVATURE METHOD # cmdList = (progName, "-surface-border-draw-metric", inflatedCoordFileName, closedTopoFileName, inflatedShapeCurvatureFileName, inflatedCurvatureColumnName, "NEGATIVE", fociProjectionFileName, sfPosteriorFocusName, sfAnteriorFocusName, borderProjectionFileName, borderProjectionFileName, "LANDMARK.SF1", str(borderSampling)); ## DO NOT RUN runCommand(cmdList) # # Create a focus near ventral limit of frontal pole, # on lateral bank of the olfactory sulcus on the fiducial surface # ventralFrontalX = -14 if (rightHemFlag) : ventralFrontalX = 14 cmdList = (progName, "-surface-foci-create", fiducialCoordFileName, closedTopoFileName, fociProjectionFileName, fociProjectionFileName, "-focus", ventralFrontalFocusName, str(ventralFrontalX), str(5), str(-12)) runCommand(cmdList); # # Identify the ventral limit of frontal lobe, on the lateral bank of the # olfactory sulcus on the fiducial surface # cmdList = (progName, "-surface-place-focus-at-extremum", fiducialCoordFileName, fiducialCoordFileName, closedTopoFileName, fociProjectionFileName, ventralFrontalFocusName, fociProjectionFileName, ventralFrontalExtremeFocusName, "Z-NEG", str(100000.0), str(100000.0), str(100000.0)) runCommand(cmdList) # # Draw border from most anterior SF node to ventral tip of frontal lobe # borderSampling = 1.0 cmdList = (progName, "-surface-border-draw-geodesic", inflatedCoordFileName, closedTopoFileName, fociProjectionFileName, sfAnteriorFocusName, ventralFrontalExtremeFocusName, roiStringentSFFileName, borderProjectionFileName, borderProjectionFileName, "LANDMARK.SF2", str(borderSampling)) runCommand(cmdList) # # Merge the SF1 and SF2 borders into SF # cmdList = (progName, "-surface-border-merge", borderProjectionFileName, borderProjectionFileName, sylvianFissureBorderName, "LANDMARK.SF1", "LANDMARK.SF2", "-delete-input-border-projections") runCommand(cmdList) # # Create a focus posterior and dorsal to Temporal Pole, close to # secondary fundus of SF # temporalPoleFocusName = "TemporalPole" ventralSecondaryX = -7 if (rightHemFlag) : ventralSecondaryX = 7 cmdList = (progName, "-surface-foci-create", inflatedCoordFileName, closedTopoFileName, fociProjectionFileName, fociProjectionFileName, "-focus-offset", sfVentralFocusName, temporalPoleFocusName, str(ventralSecondaryX), str(-45), str(40)) runCommand(cmdList); # # Draw border along secondary fundus from anterior to posterior in SF # cmdList = (progName, "-surface-border-draw-metric", inflatedCoordFileName, closedTopoFileName, inflatedShapeCurvatureFileName, inflatedCurvatureColumnName, "NEGATIVE", fociProjectionFileName, sfVentralFocusName, sfPosteriorFocusName, borderProjectionFileName, borderProjectionFileName, secondarySylvianFissureBorderName, str(borderSampling)) runCommand(cmdList) # # Find intersection of Sylvian fissue and secondary Sylvian fissure # borderIntersectionTolerance = 3.0 cmdList = (progName, "-surface-border-intersection", inflatedCoordFileName, closedTopoFileName, borderProjectionFileName, fociProjectionFileName, fociProjectionFileName, secondarySylvianFissureBorderName, sylvianFissureBorderName, sylvianIntersectionFocusName, str(borderIntersectionTolerance)) runCommand(cmdList) # # Trim beyond 12mm posterior to intersection of superior and inferior circular sulci # cmdList = (progName, "-surface-border-nibbler", inflatedCoordFileName, closedTopoFileName, borderProjectionFileName, borderProjectionFileName, sylvianFissureBorderName, sylvianFissureBorderName, fociProjectionFileName, sylvianIntersectionFocusName, "-less-than-y -12") runCommand(cmdList) # # Nibble anything within 15mm Z of ventral-frontal extreme # cmdList = (progName, "-surface-border-nibbler", inflatedCoordFileName, closedTopoFileName, borderProjectionFileName, borderProjectionFileName, sylvianFissureBorderName, sylvianFissureBorderName, fociProjectionFileName, ventralFrontalExtremeFocusName, "-within-z-distance 15") runCommand(cmdList) ##----------------------------------------------------------------------------- ## ## Identify medial wall ## def identifyMedialWall() : # # Add Colors to Foci File # cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "CC", str(0), str(0), str(255), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "Olf", str(0), str(0), str(255), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "MedialWall", str(0), str(0), str(255), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) # # Add border colors # cmdList = (progName, "-color-file-add-color", borderColorFileName, borderColorFileName, "LANDMARK.CorpusCallosum", str(255), str(255), str(0), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) # # Names of foci created when creating medial wall landmark # ccPosteriorFocusName = "CC-post" ccAnteriorFocusName = "CC-ant" ccCogFocusName = "CC-cog" genuLimitFocusName = "CC-genu-limit" spleniumLimitFocusName = "CC-splenium-limit" ccGenuBeginningFocusName = "CC-genu-beginning" olfSulcusPosteriorFocusName = "OlfSuclus-Posterior" olfSulcusMedialFocusName = "OlfSulcus-Medial" medialWallStartFocusName = "MedialWallStart" nearGenuBeginningFocusName = "CC-near-genu-beginning" nearSpleniumEndFocusName = "CC-near-splenium-end" # # Remove any existing foci that identify corpus callosum locations # cmdList = (progName, "-surface-foci-delete", fociProjectionFileName, fociProjectionFileName, ccPosteriorFocusName, ccAnteriorFocusName, ccCogFocusName, genuLimitFocusName, spleniumLimitFocusName, ccGenuBeginningFocusName, olfSulcusPosteriorFocusName, olfSulcusMedialFocusName, nearGenuBeginningFocusName, nearSpleniumEndFocusName) runCommand(cmdList) # # Remove any previous corpus callosum borders # corpusCallosumLandmarkBorderName = "LANDMARK.CorpusCallosum" corpusCallosumOlfactoryBorderName = "LANDMARK.CorpusCallosumOflactory" cmdList = (progName, "-surface-border-delete", borderProjectionFileName, borderProjectionFileName, corpusCallosumLandmarkBorderName, corpusCallosumOlfactoryBorderName) runCommand(cmdList) # # Create the corpus callosum slice # cmdList = (progName, "-volume-create-corpus-callosum-slice", anatomyVolumeFileName, "CorpusCallosumSlice+orig.nii.gz", "right") runCommand(cmdList) # # Smear along X axis # cmdList = (progName, "-volume-smear-axis", "CorpusCallosumSlice+orig.nii.gz", "CorpusCallosumSlice_Smear10+orig.nii.gz", "X", str(5), str(-1), str(1)) runCommand(cmdList) # # Dilate # cmdList = (progName, "-volume-dilate", "CorpusCallosumSlice_Smear10+orig.nii.gz", "CorpusCallosumSlice_Smear10_Dilate5+orig.nii.gz", str(5)) runCommand(cmdList) # # Smear along Y axis # cmdList = (progName, "-volume-smear-axis", "CorpusCallosumSlice_Smear10_Dilate5+orig.nii.gz", corpusCallosumVolumeFileName, "Y", str(2), str(-1), str(1)) runCommand(cmdList) # # Map the non-zero voxels to a surface ROI file # cmdList = (progName, "-volume-map-to-surface-roi-file", corpusCallosumVolumeFileName, fiducialCoordFileName, closedTopoFileName, roiCorpusCallosumFileName) runCommand(cmdList) # # Place foci at anterior and posterior of corpus callosum - CHANGE FILE NAME # cmdList = (progName, "-surface-place-foci-at-limits", fiducialCoordFileName, fiducialCoordFileName, closedTopoFileName, roiCorpusCallosumFileName, fociProjectionFileName, fociProjectionFileName, "-y-min", ccPosteriorFocusName, "-y-max", ccAnteriorFocusName, "-cog", ccCogFocusName) runCommand(cmdList) # # Create a focus 20 mm posterior and 10 mm ventral to ccAnt # cmdList = (progName, "-surface-foci-create", fiducialCoordFileName, closedTopoFileName, fociProjectionFileName, fociProjectionFileName, "-focus-offset-xyz", nearGenuBeginningFocusName, ccAnteriorFocusName, "0.0", ccAnteriorFocusName, "-20.0", ccAnteriorFocusName, "-10.0") runCommand(cmdList) # # Create a focus with 6 mm anterior and 5 mm ventral to ccPost # cmdList = (progName, "-surface-foci-create", fiducialCoordFileName, closedTopoFileName, fociProjectionFileName, fociProjectionFileName, "-focus-offset-xyz", nearSpleniumEndFocusName, ccPosteriorFocusName, "0.0", ccPosteriorFocusName, "6.0", ccPosteriorFocusName, "-5.0") runCommand(cmdList) # # Create border around ROI # cmdList = (progName, "-surface-border-draw-around-roi", fiducialCoordFileName, closedTopoFileName, roiCorpusCallosumFileName, borderProjectionFileName, borderProjectionFileName, corpusCallosumLandmarkBorderName, "-start-near-focus", fociProjectionFileName, nearGenuBeginningFocusName) runCommand(cmdList) # # Resample the border # cmdList = (progName, "-surface-border-resample", fiducialCoordFileName, closedTopoFileName, borderProjectionFileName, borderProjectionFileName, str(1.0), "-border-name", corpusCallosumLandmarkBorderName) runCommand(cmdList) # # Remove links from border after near splenium # cmdList = (progName, "-surface-border-nibbler", fiducialCoordFileName, closedTopoFileName, borderProjectionFileName, borderProjectionFileName, corpusCallosumLandmarkBorderName, corpusCallosumLandmarkBorderName, fociProjectionFileName, nearSpleniumEndFocusName, "-remove-after"); runCommand(cmdList) # # Create a focus at start of LANDMARK.CorpusCallosum Border # cmdList = (progName, "-surface-border-link-to-focus", fiducialCoordFileName, closedTopoFileName, borderProjectionFileName, corpusCallosumLandmarkBorderName, fociProjectionFileName, fociProjectionFileName, "-first-link", ccGenuBeginningFocusName) runCommand(cmdList) # # Create an ROI containing Olfactory Sulcus # cmdList = (progName, "-surface-region-of-interest-selection", fiducialCoordFileName, closedTopoFileName, roiOlfactorySulcusFileName, roiOlfactorySulcusFileName, "-paint", paintFileName, sulcusIdPaintColumnName, "SUL.OlfS", "NORMAL") runCommand(cmdList) # # Find geographic limits of Olfactory Sulcus # cmdList = (progName, "-surface-place-foci-at-limits", fiducialCoordFileName, fiducialCoordFileName, closedTopoFileName, roiOlfactorySulcusFileName, fociProjectionFileName, fociProjectionFileName, "-y-min", olfSulcusPosteriorFocusName, "-x-most-medial", olfSulcusMedialFocusName) runCommand(cmdList) # # Create a new focus with X at Olfactory medial # with Y at Olfactory posterior # with Z at Olfactory posterior # cmdList = (progName, "-surface-foci-create", fiducialCoordFileName, closedTopoFileName, fociProjectionFileName, fociProjectionFileName, "-focus-offset-xyz", medialWallStartFocusName, olfSulcusMedialFocusName, "0.0", olfSulcusPosteriorFocusName, "-5.0", olfSulcusPosteriorFocusName, "10.0") runCommand(cmdList) # # Create an ROI of all nodes # allNodesRoiFileName = "Olfactory-AllNodes.roi" cmdList = (progName, "-system-file-delete", allNodesRoiFileName) runCommand(cmdList) cmdList = (progName, "-surface-region-of-interest-selection", fiducialCoordFileName, closedTopoFileName, allNodesRoiFileName, allNodesRoiFileName, "-all-nodes") runCommand(cmdList) # # Draw border connecting genu beginning to dorsal start # cmdList = (progName, "-surface-border-draw-geodesic", veryInflatedCoordFileName, closedTopoFileName, fociProjectionFileName, medialWallStartFocusName, ccGenuBeginningFocusName, allNodesRoiFileName, borderProjectionFileName, borderProjectionFileName, corpusCallosumOlfactoryBorderName, str(1.0)) runCommand(cmdList) ##----------------------------------------------------------------------------- # # Files created by this script # def createFileNames() : global rightHemFlag global borderColorFileName, borderProjectionFileName, corpusCallosumVolumeFileName global fociColorFileName, fociProjectionFileName global inflatedShapeCurvatureFileName, inflatedCurvatureColumnName global sulcusIdPaintColumnName global paintFileGyralSTGName, paintFileName global roiCaSFileName, roiStringentCaSFileName global roiCeSFileName, roiStringentCeSFileName global roiSTGFileName, roiStringentSTGFileName global roiSFFileName, roiStringentSFFileName, roiSFErodedFileName global roiCorpusCallosumFileName global roiOlfactorySulcusFileName rightHemFlag = False if (hemisphere == "R") : rightHemFlag = True filePrefix = species + "." + subject + "." + hemisphere + "." borderColorFileName = filePrefix + "Landmark.bordercolor" borderProjectionFileName = filePrefix + "Landmark.borderproj" corpusCallosumVolumeFileName = filePrefix + "CorpusCallosumSlice_Smear10+Dilate3_SmearPost+orig.nii.gz" fociColorFileName = filePrefix + "Landmark.focicolor" fociProjectionFileName = filePrefix + "Landmark.fociproj" inflatedShapeCurvatureFileName = filePrefix + "InflatedCurvature.shape" inflatedCurvatureColumnName = "\"Folding (Curvature) INFLATED\"" sulcusIdPaintColumnName = "\"Sulcus ID\"" paintFileGyralSTGName = filePrefix + "SulcalID_withSTG.paint" paintFileName = filePrefix + "SulcalID.paint" roiCaSFileName = filePrefix + "CaS.roi" roiStringentCaSFileName = filePrefix + "CaS_Stringent.roi" roiCeSFileName = filePrefix + "CeS.roi" roiStringentCeSFileName = filePrefix + "CeS_Stringent.roi" roiSTGFileName = filePrefix + "STG.roi" roiStringentSTGFileName = filePrefix + "STG_Stringent.roi" roiSFFileName = filePrefix + "SF.roi" roiStringentSFFileName = filePrefix + "SF_Stringent.roi" roiSFErodedFileName = filePrefix + "SF_Eroded.roi" roiCorpusCallosumFileName = filePrefix + "CorpusCallosum.roi" roiOlfactorySulcusFileName = filePrefix + "OlfactorySulcus.roi" ##----------------------------------------------------------------------------- ## ## Do the sulcal ID ## def doSulcalID() : createFileNames() if (doMapProbabilisticVolumes) : createSulcalIdentificationPaintFile() if (doCentralSulcus) : identifyCentralSulcus() if (doCalcarineSulcus) : identifyCalcarineSulcus() if (doSuperiorTemporalGyrus) : identifySuperiorTemporalGyrus() if (doSylvianFissure) : identifySylvianFissure() if (doMedialWall) : identifyMedialWall() ##----------------------------------------------------------------------------- ## ## Print help information ## def printHelp() : print "Options" print "-cas Identify calcarine sulcus." print "-ces Identify central sulcus." print "-mpv Map probabilistic volumes to create Sulcal ID Paint File." print "-mw Identify medial wall." print "-sf Identify sylvian fissure." print "-stg Identify Superior Temporal Gyrus." print "" print "-case04 Identify landmarks on Case 04" print "-case05 Identify landmarks on Case 05" ##----------------------------------------------------------------------------- ## ## "Main" code ## # # Get number of arguments # numArgs = len(sys.argv) if (numArgs <= 1) : printHelp() os._exit(0) # # Flags for different operations # doCalcarineSulcus = False doCentralSulcus = False doMapProbabilisticVolumes = False doMedialWall = False doSuperiorTemporalGyrus = False doSylvianFissure = False # # Flags for cases # doCase04 = False doCase05 = False # # Process arguments # for i in range (1, numArgs) : arg = sys.argv[i] if (arg == "-cas") : doCalcarineSulcus = True elif (arg == "-ces") : doCentralSulcus = True elif (arg == "-mpv") : doMapProbabilisticVolumes = True elif (arg == "-mw") : doMedialWall = True elif (arg == "-sf") : doSylvianFissure = True elif (arg == "-stg") : doSuperiorTemporalGyrus = True elif (arg == "-case04") : doCase04 = True elif (arg == "-case05") : doCase05 = True else: print "ERROR Invalid option: ", arg os._exit(-1) # # Case04 # if (doCase04) : anatomyVolumeFileName = "K04_mpr_on_711_2L_111_t88.4dfp.ifh" closedTopoFileName = "Human.K04.R.CLOSED.71612.topo" fiducialCoordFileName = "Human.K04.R.FIDUCIAL.71612.coord" inflatedCoordFileName = "Human.K04.R.Inflated.71612.coord" veryInflatedCoordFileName = "Human.K04.R.VeryInflated.71612.coord" geographyPaintFileName = "K04_mpr_on_711_2L_111_t88.R.full.segment_vent_corr4.geography.71612.paint" geographyPaintColumnName = "Geography" shapeFileName = "K04_mpr_on_711_2L_111_t88.R.full.segment_vent_corr4.71612.surface_shape" shapeFileDepthColumnName = "Depth" shapeFileCurvatureColumnName = "\"Folding (Mean Curvature)\"" species = "Human" subject = "K04" hemisphere = "R" # # ID the sulci # doSulcalID() # # Case05 # if (doCase05) : anatomyVolumeFileName = "K05_mpr_on_711_2L_111_t88.4dfp.ifh" closedTopoFileName = "Human.K05.R.CLOSED.78049.topo" fiducialCoordFileName = "Human.K05.R.FIDUCIAL.78049.coord" inflatedCoordFileName = "Human.K05.R.Inflated.78049.coord" veryInflatedCoordFileName = "Human.K05.R.VeryInflated.78049.coord" geographyPaintFileName = "K05_mpr_on_711_2L_111_t88.R.full.segment_vent_corr5.geography.78049.paint" geographyPaintColumnName = "Geography" shapeFileName = "K05_mpr_on_711_2L_111_t88.R.full.segment_vent_corr5.78049.surface_shape" shapeFileDepthColumnName = "Depth" shapeFileCurvatureColumnName = "\"Folding (Mean Curvature)\"" species = "Human" subject = "K05" hemisphere = "R" # # ID the sulci # doSulcalID() caret-5.6.4~dfsg.1.orig/caret_scripts/run_sulcal_id_DVE.py0000755000175000017500000022275411572067322023336 0ustar michaelmichael#!/usr/bin/python # version uploaded to SumsDB by DVE 13 aug; used by Donna for testing: # http://sumsdb.wustl.edu/sums/archivelist.do?archive_id=6632924&archive_name=run_sulcal_id.py # downloaded by DVE 23 aug 07. Medial wall changes 23 Aug # # Imports # import getpass import os import sys # # Global Variables # #progName = "/Users/john/caret5_osx/caret_source/caret_command_new/caret_command_new" progName = "caret_command" if (getpass.getuser() == "john") : progName = "/Users/john/caret5_osx/caret_source/caret_command/caret_command" # # Post Central Sulcus parameters # postCentralSulcusOffset = 25.0 postCentralSulcusStdDevSquared = 100.0 postCentralSulcusSplit = 5.0 probabilisticSulcusVolumeListFileName = "probabilistic-depth-volume.csv" ##----------------------------------------------------------------------------- # # Run a command # def runCommand(cmdList) : cmd = " ".join(cmdList) # join cmdList into a string separated by blanks print "\nExecuting: %s\n" % cmd result = os.system(cmd) if (result != 0) : print "COMMAND FAILED: " print " ", cmd os._exit(-1) ##----------------------------------------------------------------------------- ## ## Generate Sulcal Paint Identification File ## def createSulcalIdentificationPaintFile() : cmdList = (progName, "-system-file-delete", paintFileName) runCommand(cmdList) cmdList = (progName, "-surface-sulcal-named-all-identification", fiducialCoordFileName, veryInflatedCoordFileName, closedTopoFileName, geographyPaintFileName, paintFileName, geographyPaintColumnName, shapeFileName, shapeFileDepthColumnName, probabilisticSulcusVolumeListFileName, str(postCentralSulcusOffset), str(postCentralSulcusStdDevSquared), str(postCentralSulcusSplit)) runCommand(cmdList) ##----------------------------------------------------------------------------- ## ## Identify central sulcus def identifyCentralSulcus() : # # Add Colors to Foci File # cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "CeS-medial", str(255), str(0), str(0), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "CeS-ventral", str(0), str(255), str(0), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "CeS-MedialExtreme", str(255), str(0), str(0), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "CeS-VentralExtreme", str(0), str(255), str(0), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", borderColorFileName, borderColorFileName, "LANDMARK.CentralSulcus", str(255), str(255), str(0)); runCommand(cmdList) # # Delete any existing foci with these names # cesMedialFocusName = "CeS-medial" cesVentralFocusName = "CeS-ventral" cesVentralExtremeFocusName = "CeS-VentralExtreme" cesMedialExtremeFocusName = "CeS-MedialExtreme" landmarkCentralMedialFocusName = "CeS-medial-Landmark" landmarkCentralVentralFocusName = "CeS-ventral-Landmark" cmdList = (progName, "-surface-foci-delete", fociProjectionFileName, fociProjectionFileName, cesMedialFocusName, cesVentralFocusName, landmarkCentralMedialFocusName, landmarkCentralVentralFocusName, cesVentralExtremeFocusName, cesMedialExtremeFocusName) runCommand(cmdList) # # Delete any existing border with these names # landmarkCentralSulcusBorderName = "LANDMARK.CentralSulcus" cmdList = (progName, "-surface-border-delete", borderProjectionFileName, borderProjectionFileName, landmarkCentralSulcusBorderName) runCommand(cmdList) # # Create an ROI that identifies the central sulcus nodes # with paint name SUL.CeS and Shape folding ranging -100 to -0.10 # cmdList = (progName, "-surface-region-of-interest-selection", inflatedCoordFileName, closedTopoFileName, roiCeSFileName, roiCeSFileName, "-paint", paintFileName, sulcusIdPaintColumnName, # column name "SUL.CeS", # paint name "NORMAL", # normal selection "-shape", shapeFileName, shapeFileCurvatureColumnName, # column number "-100.0 -0.10", # value range "AND") # AND with previous selection runCommand(cmdList) # # Create foci at some limits of ROI # cmdList = (progName, "-surface-place-foci-at-limits", fiducialCoordFileName, inflatedCoordFileName, closedTopoFileName, roiCeSFileName, fociProjectionFileName, fociProjectionFileName, "-z-min " + cesVentralFocusName, "-x-most-medial " + cesMedialFocusName) runCommand(cmdList) # # Create an ROI that identifies the central sulcus nodes # with paint name SUL.CeS and Shape folding ranging -100 to -0.16 # cmdList = (progName, "-surface-region-of-interest-selection", inflatedCoordFileName, closedTopoFileName, roiStringentCeSFileName, roiStringentCeSFileName, "-paint", paintFileName, sulcusIdPaintColumnName, # column name "SUL.CeS", # paint name "NORMAL", # normal selection "-shape", shapeFileName, shapeFileCurvatureColumnName, # column number "-100.0 -0.16", # value range "AND") # AND with previous selection runCommand(cmdList) # # Draw the LANDMARK.CentralSulcus border # borderSampling = 1.0 cmdList = (progName, "-surface-border-draw-geodesic", inflatedCoordFileName, closedTopoFileName, fociProjectionFileName, cesVentralFocusName, cesMedialFocusName, roiStringentCeSFileName, borderProjectionFileName, borderProjectionFileName, landmarkCentralSulcusBorderName, str(borderSampling)) runCommand(cmdList) # # Find extremum point for lateral side # cmdList = (progName, "-surface-place-focus-at-extremum", fiducialCoordFileName, inflatedCoordFileName, closedTopoFileName, fociProjectionFileName, cesVentralFocusName, fociProjectionFileName, cesVentralExtremeFocusName, "Z-NEG", str(100000.0), str(3.0), str(100000.0)) runCommand(cmdList) # # Find extremum point for medial side # cmdList = (progName, "-surface-place-focus-at-extremum", fiducialCoordFileName, inflatedCoordFileName, closedTopoFileName, fociProjectionFileName, cesMedialFocusName, fociProjectionFileName, cesMedialExtremeFocusName, "X-MEDIAL", str(100000.0), str(5.0), str(100000.0)) runCommand(cmdList) # # Trim border 19mm above ventral extreme # cmdList = (progName, "-surface-border-nibbler", inflatedCoordFileName, closedTopoFileName, borderProjectionFileName, borderProjectionFileName, landmarkCentralSulcusBorderName, landmarkCentralSulcusBorderName, fociProjectionFileName, cesVentralExtremeFocusName, "-within-z-distance 19") runCommand(cmdList) # # Trim border 18mm lateral to midline # trimValue = -18 if (rightHemFlag) : trimValue = 18 cmdList = (progName, "-surface-border-nibbler", inflatedCoordFileName, closedTopoFileName, borderProjectionFileName, borderProjectionFileName, landmarkCentralSulcusBorderName, landmarkCentralSulcusBorderName, fociProjectionFileName, cesMedialExtremeFocusName, "-within-x-distance ", str(trimValue)) runCommand(cmdList) # # Generate foci for final CeS landmark extrema cmdList = (progName, "-surface-border-link-to-focus", fiducialCoordFileName, closedTopoFileName, borderProjectionFileName, landmarkCentralSulcusBorderName, fociProjLDMKextremaFileName, fociProjLDMKextremaFileName, "-first-link", landmarkCentralMedialFocusName) runCommand(cmdList) cmdList = (progName, "-surface-border-link-to-focus", fiducialCoordFileName, closedTopoFileName, borderProjectionFileName, landmarkCentralSulcusBorderName, fociProjLDMKextremaFileName, fociProjLDMKextremaFileName, "-last-link", landmarkCentralVentralFocusName) runCommand(cmdList) ##----------------------------------------------------------------------------- ## ## Identify calcarine sulci def identifyCalcarineSulcus() : # # Add Colors to Foci File # cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "CaS-posterior", str(0), str(150), str(255), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "CaS-anterior", str(0), str(150), str(255), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "CaS-PosteriorExtreme", str(0), str(255), str(0), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", borderColorFileName, borderColorFileName, "LANDMARK.CalcarineSulcus", str(246), str(114), str(0)); runCommand(cmdList) # # Delete any existing foci with these names # casAnteriorFocusName = "CaS-anterior" casPosteriorFocusName = "CaS-posterior" casPosteriorExtremeFocusName = "CaS-PosteriorExtreme" landmarkCalcarinePosteriorFocusName = "CaS-anterior-Landmark" landmarkCalcarineAnteriorFocusName = "CaS-posterior-Landmaark" cmdList = (progName, "-surface-foci-delete", fociProjectionFileName, fociProjectionFileName, casAnteriorFocusName, casPosteriorFocusName, casPosteriorExtremeFocusName, landmarkCalcarinePosteriorFocusName, landmarkCalcarineAnteriorFocusName) runCommand(cmdList) # # Delete any existing border with these names # landmarkCalcarineSulcusBorderName = "LANDMARK.CalcarineSulcus" cmdList = (progName, "-surface-border-delete", borderProjectionFileName, borderProjectionFileName, landmarkCalcarineSulcusBorderName) runCommand(cmdList) # # Create an ROI that identifies the central sulcus nodes # with paint name SUL.CaS and Shape folding ranging -100 to -0.10 # cmdList = (progName, "-surface-region-of-interest-selection", inflatedCoordFileName, closedTopoFileName, roiCaSFileName, roiCaSFileName, "-paint", paintFileName, sulcusIdPaintColumnName, # column name "SUL.CaS", # paint name "NORMAL", # normal selection "-shape", inflatedShapeCurvatureFileName, inflatedCurvatureColumnName, str(-100.0), str(-0.07), # use -0.07 since inflated "AND") # AND with previous selection runCommand(cmdList) # # Create foci at some limits of ROI # cmdList = (progName, "-surface-place-foci-at-limits", fiducialCoordFileName, inflatedCoordFileName, closedTopoFileName, roiCaSFileName, fociProjectionFileName, fociProjectionFileName, "-y-max " + casAnteriorFocusName, "-y-min " + casPosteriorFocusName) runCommand(cmdList) # # Create an ROI that identifies the calcarine sulcus nodes # with paint name SUL.CaS and Shape folding ranging -100 to -0.16 # cmdList = (progName, "-surface-region-of-interest-selection", inflatedCoordFileName, closedTopoFileName, roiStringentCaSFileName, roiStringentCaSFileName, "-paint", paintFileName, sulcusIdPaintColumnName, # column name "SUL.CaS", # paint name "NORMAL", # normal selection "-shape", shapeFileName, shapeFileCurvatureColumnName, # column number "-100.0 -0.16", # value range "AND") # AND with previous selection runCommand(cmdList) # # Create the draw border comand to draw the LANDMARK.CalcarineSulcus border using metric-curvature # borderSampling = 2.0 # cmdList = (progName, "-surface-border-draw-geodesic", inflatedCoordFileName, closedTopoFileName, fociProjectionFileName, casPosteriorFocusName, casAnteriorFocusName, roiStringentCaSFileName, borderProjectionFileName, borderProjectionFileName, landmarkCalcarineSulcusBorderName, str(borderSampling)) ## DO NOT RUN runCommand(cmdList) # USES CURVATURE METHOD # cmdList = (progName, "-surface-border-draw-metric", inflatedCoordFileName, closedTopoFileName, inflatedShapeCurvatureFileName, inflatedCurvatureColumnName, "NEGATIVE", fociProjectionFileName, casPosteriorFocusName, casAnteriorFocusName, borderProjectionFileName, borderProjectionFileName, landmarkCalcarineSulcusBorderName, str(borderSampling)) runCommand(cmdList) # # Find extremum point for occipital pole # cmdList = (progName, "-surface-place-focus-at-extremum", fiducialCoordFileName, inflatedCoordFileName, closedTopoFileName, fociProjectionFileName, casPosteriorFocusName, fociProjectionFileName, casPosteriorExtremeFocusName, "Y-NEG", str(100000.0), str(100000.0), str(100000.0)) runCommand(cmdList) # # Trim border 24mm from posterior extreme # cmdList = (progName, "-surface-border-nibbler", inflatedCoordFileName, closedTopoFileName, borderProjectionFileName, borderProjectionFileName, landmarkCalcarineSulcusBorderName, landmarkCalcarineSulcusBorderName, fociProjectionFileName, casPosteriorExtremeFocusName, "-within-y-distance 24") runCommand(cmdList) # Generate foci for final CaS landmark extrema cmdList = (progName, "-surface-border-link-to-focus", fiducialCoordFileName, closedTopoFileName, borderProjectionFileName, landmarkCalcarineSulcusBorderName, fociProjLDMKextremaFileName, fociProjLDMKextremaFileName, "-first-link", landmarkCalcarinePosteriorFocusName) runCommand(cmdList) cmdList = (progName, "-surface-border-link-to-focus", fiducialCoordFileName, closedTopoFileName, borderProjectionFileName, landmarkCalcarineSulcusBorderName, fociProjLDMKextremaFileName, fociProjLDMKextremaFileName, "-last-link", landmarkCalcarineAnteriorFocusName) runCommand(cmdList) ##----------------------------------------------------------------------------- ## ## Identify superior temporal gyrus def identifySuperiorTemporalGyrus() : # # Add Colors to Foci File # cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "STS_Inflated_Ventral", str(0), str(150), str(255), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "STS_Inflated_Dorsal", str(0), str(150), str(255), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "TemporalPole", str(100), str(0), str(200), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "STG-posterior", str(0), str(150), str(255), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "STG-ventral", str(0), str(150), str(255), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "STG", str(100), str(255), str(150), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) # # Delete any existing foci with these names # stsVentralFocusName = "STS_Inflated_Ventral" stsDorsalFocusName = "STS_Inflated_Dorsal" temporalPoleFocusName = "TemporalPole" stgPathFocusName = "STG-posterior" stgCesLimitFocusName = "STG-CES-limit" landmarkSTGdorsalFocusName = "STG-dorsal-Landmark" landmarkSTGventralFocusName = "STG-ventral-Landmark" cmdList = (progName, "-surface-foci-delete", fociProjectionFileName, fociProjectionFileName, stsVentralFocusName, stsDorsalFocusName, temporalPoleFocusName, stgPathFocusName, stgCesLimitFocusName, landmarkSTGdorsalFocusName, landmarkSTGventralFocusName) runCommand(cmdList) # # Delete any existing border with these names # stgBorderName = "LANDMARK.SF_STSant" cmdList = (progName, "-surface-border-delete", borderProjectionFileName, borderProjectionFileName, stgBorderName) runCommand(cmdList) # # Add border colors # cmdList = (progName, "-color-file-add-color", borderColorFileName, borderColorFileName, "LANDMARK.SF_STSant", str(255), str(0), str(187), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) # # Create an ROI that identifies the superior temporal sulcus # with paint name SUL.STS # cmdList = (progName, "-surface-region-of-interest-selection", inflatedCoordFileName, closedTopoFileName, roiSTGFileName, roiSTGFileName, "-paint", paintFileName, sulcusIdPaintColumnName, # column name "SUL.STS", # paint name "NORMAL") # AND with previous selection runCommand(cmdList) # # Create foci at some limits of ROI # cmdList = (progName, "-surface-place-foci-at-limits", fiducialCoordFileName, inflatedCoordFileName, closedTopoFileName, roiSTGFileName, fociProjectionFileName, fociProjectionFileName, "-z-min " + stsVentralFocusName, "-z-max " + stsDorsalFocusName) runCommand(cmdList) # # Find extremum point for temporal pole # cmdList = (progName, "-surface-place-focus-at-extremum", fiducialCoordFileName, inflatedCoordFileName, closedTopoFileName, fociProjectionFileName, stsVentralFocusName, fociProjectionFileName, temporalPoleFocusName, "Y-POS", str(100000.0), str(100000.0), str(100000.0)) runCommand(cmdList) # # Create a transformation matrix rotated Y=-45 # rotateString = "-rotate 0.0 45.0 0.0" if (rightHemFlag) : rotateString = "-rotate 0.0 -45.0 0.0" transformationMatrixFileName = "TempRotateYMinus45.matrix" transformationMatrixName = "RotateYMinus45" cmdList = (progName, "-transformation-matrix-create", transformationMatrixFileName, transformationMatrixFileName, transformationMatrixName, "-delete-all-matrices-from-file", "-matrix-comment \"rotate minus 45 degrees about Y-axis\"", rotateString) runCommand(cmdList) # # Create a temporary surface rotated Y-45 # tempRotateY45InflatedCoordFileName = "temp.rotatedY45.coord" cmdList = (progName, "-surface-apply-transformation-matrix", inflatedCoordFileName, closedTopoFileName, tempRotateY45InflatedCoordFileName, "-matrix-file ", transformationMatrixFileName, transformationMatrixName) #"-matrix", # "0.707107 0.000000 -0.707107 0.000000", # "0.000000 1.000000 0.000000 0.000000", # "0.707107 0.000000 0.707107 0.000000", # "0.000000 0.000000 0.000000 1.000000") #"-matrix-file STG.matrix Y45Down"); runCommand(cmdList) # # Find extremum point starting at temporal pole # moving in a posterior/superior direction along the STG # cmdList = (progName, "-surface-place-focus-at-extremum", fiducialCoordFileName, tempRotateY45InflatedCoordFileName, closedTopoFileName, fociProjectionFileName, temporalPoleFocusName, fociProjectionFileName, stgPathFocusName, "Z-POS", str(100000.0), str(100000.0), str(100000.0), "-create-roi-from-path", roiSTGFileName) #"-start-offset 3.0 0.0 0.0") runCommand(cmdList) # # Limit the ROI so it does not go beyond temporal pole # or beyond the Y position of the ventral tip of the # central sulcus # cesVentralFocusName = "CeS-ventral" cmdList = (progName, "-surface-region-of-interest-selection", inflatedCoordFileName, closedTopoFileName, roiSTGFileName, roiSTGFileName, "-limit-y-min-focus", fociProjectionFileName, cesVentralFocusName, "-limit-y-max-focus", fociProjectionFileName, temporalPoleFocusName, "-limit-z-min-focus", fociProjectionFileName, temporalPoleFocusName) runCommand(cmdList) # # Create limits at posterior and ventral ends of GYRAL.STG # cmdList = (progName, "-surface-place-foci-at-limits", fiducialCoordFileName, inflatedCoordFileName, closedTopoFileName, roiSTGFileName, fociProjectionFileName, fociProjectionFileName, "-y-min " + stgCesLimitFocusName) runCommand(cmdList) # # Create the draw border comand to draw the LANDMARK.SF_STSant border # borderSampling = 1.0 cmdList = (progName, "-surface-border-draw-geodesic", inflatedCoordFileName, closedTopoFileName, fociProjectionFileName, stgCesLimitFocusName, temporalPoleFocusName, roiSTGFileName, borderProjectionFileName, borderProjectionFileName, stgBorderName, str(borderSampling)) runCommand(cmdList) # Generate foci for final STG landmark extrema cmdList = (progName, "-surface-border-link-to-focus", fiducialCoordFileName, closedTopoFileName, borderProjectionFileName, stgBorderName, fociProjLDMKextremaFileName, fociProjLDMKextremaFileName, "-first-link", landmarkSTGdorsalFocusName) runCommand(cmdList) cmdList = (progName, "-surface-border-link-to-focus", fiducialCoordFileName, closedTopoFileName, borderProjectionFileName, stgBorderName, fociProjLDMKextremaFileName, fociProjLDMKextremaFileName, "-last-link", landmarkSTGventralFocusName) runCommand(cmdList) ###################################################### # The following steps are not necessary but assign paint # for the STG # # # Dilate the STG ROI but only nodes identified as GYRAL # and limit the extent of the ROI so that it does not # go posterior to ventral tip of central sulcus or # beyond the temporal pole. # dilateIterations = 5 cmdList = (progName, "-surface-region-of-interest-selection", inflatedCoordFileName, closedTopoFileName, roiSTGFileName, roiSTGFileName, "-dilate-paint", paintFileName, sulcusIdPaintColumnName, "SUL.SF", # SF may be too big str(dilateIterations), "-dilate-paint", paintFileName, sulcusIdPaintColumnName, "GYRAL", str(dilateIterations), "-limit-y-min-focus", fociProjectionFileName, cesVentralFocusName, "-limit-y-max-focus", fociProjectionFileName, temporalPoleFocusName, "-limit-z-min-focus", fociProjectionFileName, temporalPoleFocusName, ) runCommand(cmdList) # # Assign the STG paint # cmdList = (progName, "-paint-assign-to-nodes", paintFileName, paintFileGyralSTGName, sulcusIdPaintColumnName, "GYRAL.STG", "-assign-from-roi-file", roiSTGFileName); runCommand(cmdList) ##----------------------------------------------------------------------------- ## ## Identify sylvian fissure ## def identifySylvianFissure() : # # Add Colors to Foci File # cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "SF", str(50), str(255), str(255), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) ventralFrontalExtremeFocusName = "SF_VentralFrontalExtreme" cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "SF", str(0), str(255), str(0), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) ventralFrontalFocusName = "SF_VentralFrontal" cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "SF", str(0), str(0), str(255), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) # # Add border colors # cmdList = (progName, "-color-file-add-color", borderColorFileName, borderColorFileName, "LANDMARK.SF", str(0), str(255), str(255), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) # # Delete any existing foci with these names # sfAnteriorFocusName = "SF_Anterior" sfPosteriorFocusName = "SF_Posterior" sfDorsalFocusName = "SF_Dorsal" ventralFrontalFocusName = "SF_VentralFrontal" ventralFrontalExtremeFocusName = "SF_VentralFrontalExtreme" sfVentralFocusName = "SF_VentralNearSecondary_SF" sylvianIntersectionFocusName = "SF_Intersect_Superior_Inferior" sfSaddleAntLimitFocusName = "SFsaddleAnteriorLimit" postToSfSaddleFocusName = "postToSfSaddle" landmarkSFposteriorFocusName = "SF_Posterior-Landmark" landmarkSFanteriorFocusName = "SF_Anterior-Landmark" cmdList = (progName, "-surface-foci-delete", fociProjectionFileName, fociProjectionFileName, sfAnteriorFocusName, sfPosteriorFocusName, landmarkSFposteriorFocusName, landmarkSFanteriorFocusName, sfDorsalFocusName, ventralFrontalFocusName, ventralFrontalExtremeFocusName, sfVentralFocusName, sylvianIntersectionFocusName, sfSaddleAntLimitFocusName) runCommand(cmdList) # # Delete any existing border with these names # sylvianFissureDorsBorderName = "LANDMARK.SFdorsal" sylvianFissureAntBorderName = "LANDMARK.SFant" sylvianFissureBorderName = "LANDMARK.SF" secondarySylvianFissureBorderName = "LANDMARK.SF-secondary" cmdList = (progName, "-surface-border-delete", borderProjectionFileName, borderProjectionFileName, sylvianFissureBorderName, sylvianFissureDorsBorderName, sylvianFissureAntBorderName, secondarySylvianFissureBorderName) runCommand(cmdList) # # Generate folding and gaussian curvature on the INFLATED surface # cmdList = (progName, "-surface-curvature", inflatedCoordFileName, closedTopoFileName, inflatedShapeCurvatureFileName, inflatedShapeCurvatureFileName, "-generate-mean-curvature", "-generate-gaussian-curvature", "-mean-column-name", inflatedCurvatureColumnName, "-gaussian-column-name", inflatedGaussianColumnName); ## NOW DONE BEFORE ANY SULCAL ID runCommand(cmdList); # # Create an ROI that identifies the sylvian fissure # with paint name SUL.SF # cmdList = (progName, "-surface-region-of-interest-selection", inflatedCoordFileName, closedTopoFileName, roiSFFileName, roiSFFileName, "-paint", paintFileName, sulcusIdPaintColumnName, # column name "SUL.SF", # paint name "NORMAL") # normal selection runCommand(cmdList) # # Erode the ROI since SF paint tends to be too big # cmdList = (progName, "-surface-region-of-interest-selection", inflatedCoordFileName, closedTopoFileName, roiSFFileName, roiSFErodedFileName, "-erode 5") runCommand(cmdList) # # Create foci at some limits of ROI at eroded ROI # cmdList = (progName, "-surface-place-foci-at-limits", fiducialCoordFileName, inflatedCoordFileName, closedTopoFileName, roiSFErodedFileName, fociProjectionFileName, fociProjectionFileName, "-y-max " + sfAnteriorFocusName, "-y-min " + sfPosteriorFocusName, "-z-max " + sfDorsalFocusName) runCommand(cmdList) # # Limit original ROI to apply curvature limits # cmdList = (progName, "-surface-region-of-interest-selection", inflatedCoordFileName, closedTopoFileName, roiSFFileName, roiStringentSFFileName, "-shape", inflatedShapeCurvatureFileName, inflatedCurvatureColumnName, str(-100.0), str(-0.07), # use -0.7 since inflated "AND") runCommand(cmdList) # # Draw border from posterior to anterior of SF # USES GEODESIC METHOD # borderSampling = 1.0 cmdList = (progName, "-surface-border-draw-geodesic", inflatedCoordFileName, closedTopoFileName, fociProjectionFileName, sfPosteriorFocusName, sfAnteriorFocusName, roiStringentSFFileName, borderProjectionFileName, borderProjectionFileName, sylvianFissureDorsBorderName, str(borderSampling)) runCommand(cmdList) # # USES CURVATURE METHOD # cmdList = (progName, "-surface-border-draw-metric", inflatedCoordFileName, closedTopoFileName, inflatedShapeCurvatureFileName, inflatedCurvatureColumnName, "NEGATIVE", fociProjectionFileName, sfPosteriorFocusName, sfAnteriorFocusName, borderProjectionFileName, borderProjectionFileName, sylvianFissureDorsBorderName, str(borderSampling)); ## DO NOT RUN runCommand(cmdList) # # Create a focus near ventral limit of frontal pole, # on lateral bank of the olfactory sulcus on the fiducial surface # ventralFrontalX = -16 if (rightHemFlag) : ventralFrontalX = 16 cmdList = (progName, "-surface-foci-create", fiducialCoordFileName, closedTopoFileName, fociProjectionFileName, fociProjectionFileName, "-focus", ventralFrontalFocusName, str(ventralFrontalX), str(12), str(-19)) runCommand(cmdList); # # Identify the ventral limit of frontal lobe, on the lateral bank of the # olfactory sulcus on the fiducial surface # cmdList = (progName, "-surface-place-focus-at-extremum", fiducialCoordFileName, fiducialCoordFileName, closedTopoFileName, fociProjectionFileName, ventralFrontalFocusName, fociProjectionFileName, ventralFrontalExtremeFocusName, "Z-NEG", str(100000.0), str(100000.0), str(100000.0)) runCommand(cmdList) # # Draw border from most anterior SF node to ventral tip of frontal lobe # borderSampling = 1.0 cmdList = (progName, "-surface-border-draw-geodesic", inflatedCoordFileName, closedTopoFileName, fociProjectionFileName, sfAnteriorFocusName, ventralFrontalExtremeFocusName, roiStringentSFFileName, borderProjectionFileName, borderProjectionFileName, sylvianFissureAntBorderName, str(borderSampling)) runCommand(cmdList) # # Merge the SF1 and SF2 borders into SF # cmdList = (progName, "-surface-border-merge", borderProjectionFileName, borderProjectionFileName, sylvianFissureBorderName, sylvianFissureDorsBorderName, sylvianFissureAntBorderName, "-delete-input-border-projections") runCommand(cmdList) # # Create a focus posterior and dorsal to Temporal Pole, close to # secondary fundus of SF # temporalPoleFocusName = "TemporalPole" ventralSecondaryX = -7 if (rightHemFlag) : ventralSecondaryX = 7 cmdList = (progName, "-surface-foci-create", inflatedCoordFileName, closedTopoFileName, fociProjectionFileName, fociProjectionFileName, "-focus-offset", sfVentralFocusName, temporalPoleFocusName, str(ventralSecondaryX), str(-45), str(40)) runCommand(cmdList); # # Draw border along secondary fundus from anterior to posterior in SF # cmdList = (progName, "-surface-border-draw-metric", inflatedCoordFileName, closedTopoFileName, inflatedShapeCurvatureFileName, inflatedCurvatureColumnName, "NEGATIVE", fociProjectionFileName, sfVentralFocusName, sfPosteriorFocusName, borderProjectionFileName, borderProjectionFileName, secondarySylvianFissureBorderName, str(borderSampling)) runCommand(cmdList) # # Find intersection of Sylvian fissue and secondary Sylvian fissure # borderIntersectionTolerance = 3.0 cmdList = (progName, "-surface-border-intersection", inflatedCoordFileName, closedTopoFileName, borderProjectionFileName, fociProjectionFileName, fociProjectionFileName, secondarySylvianFissureBorderName, sylvianFissureBorderName, sylvianIntersectionFocusName, str(borderIntersectionTolerance)) runCommand(cmdList) cmdList = (progName, "-surface-border-delete", borderProjectionFileName, borderProjectionFileName, secondarySylvianFissureBorderName) runCommand(cmdList) # # Trim beyond 12mm posterior to intersection of superior and inferior circular sulci # cmdList = (progName, "-surface-border-nibbler", ellipsoidalCoordFileName, closedTopoFileName, borderProjectionFileName, borderProjectionFileName, sylvianFissureBorderName, sylvianFissureBorderName, fociProjectionFileName, sylvianIntersectionFocusName, "-less-than-y -12") runCommand(cmdList) # # Nibble anything within 15mm Z of ventral-frontal extreme # cmdList = (progName, "-surface-border-nibbler", inflatedCoordFileName, closedTopoFileName, borderProjectionFileName, borderProjectionFileName, sylvianFissureBorderName, sylvianFissureBorderName, fociProjectionFileName, ventralFrontalExtremeFocusName, "-within-z-distance 15") runCommand(cmdList) # Generate foci for final SF landmark extrema cmdList = (progName, "-surface-border-link-to-focus", fiducialCoordFileName, closedTopoFileName, borderProjectionFileName, sylvianFissureBorderName, fociProjLDMKextremaFileName, fociProjLDMKextremaFileName, "-first-link", landmarkSFposteriorFocusName) runCommand(cmdList) cmdList = (progName, "-surface-border-link-to-focus", fiducialCoordFileName, closedTopoFileName, borderProjectionFileName, sylvianFissureBorderName, fociProjLDMKextremaFileName, fociProjLDMKextremaFileName, "-last-link", landmarkSFanteriorFocusName) runCommand(cmdList) # determine where the saddle of sylvian thumb lies cmdList = (progName, "-surface-region-of-interest-selection", inflatedCoordFileName, closedTopoFileName, roiSFFileName, roiSFinflatedGaussianFileName, "-limit-z-max-focus", fociProjectionFileName, ventralFrontalExtremeFocusName, "-shape", inflatedShapeCurvatureFileName, inflatedGaussianColumnName, str(-100), str(-.01), # to capture saddle of Sylvian thumb "AND") runCommand(cmdList) #find anterior limit of sylvian saddle. cmdList = (progName, "-surface-place-foci-at-limits", fiducialCoordFileName, inflatedCoordFileName, closedTopoFileName, roiSFinflatedGaussianFileName, fociProjectionFileName, fociProjectionFileName, "-y-max " + sfSaddleAntLimitFocusName) runCommand(cmdList) ##----------------------------------------------------------------------------- ## ## Identify medial wall ## def identifyMedialWall() : # # Add Colors to Foci File # cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "CC", str(0), str(0), str(255), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "MedialWall", str(0), str(0), str(255), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "PHG", str(0), str(150), str(255), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "HF", str(0), str(0), str(255), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", fociColorFileName, fociColorFileName, "MW", str(0), str(0), str(255), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) # # Add border colors # cmdList = (progName, "-color-file-add-color", borderColorFileName, borderColorFileName, "LANDMARK.CorpusCallosum", str(255), str(255), str(0), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", borderColorFileName, borderColorFileName, "PHG", str(255), str(255), str(0), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", borderColorFileName, borderColorFileName, "MW", str(255), str(255), str(0), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", borderColorFileName, borderColorFileName, "HF", str(255), str(0), str(100), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", borderColorFileName, borderColorFileName, "LANDMARK.MedWall.DORSAL", str(150), str(0), str(100), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) cmdList = (progName, "-color-file-add-color", borderColorFileName, borderColorFileName, "LANDMARK.MedWall.VENTRAL", str(100), str(0), str(150), "-point-size 3", "-symbol SPHERE"); runCommand(cmdList) # # Names of foci created when creating medial wall landmark # ccPosteriorFocusName = "CC-post" ccAnteriorFocusName = "CC-ant" ccCogFocusName = "CC-cog" genuLimitFocusName = "CC-genu-limit" ccGenuBeginningFocusName = "CC-genu-beginning" medialWallStartFocusName = "MedialWallStart" nearGenuBeginningFocusName = "CC-near-genu-beginning" nearSpleniumEndFocusName = "CC-near-splenium-end" ccSpleniumEndFocusName = "CC-splenium-limit" casAnteriorFocusName = "CaS-anterior" temporalPoleFocusName = "TemporalPole" PHGpostFocusName = "PHG-post" PHGantFocusName = "PHG-ant" HFfundusPostFocusName = "HF-fundus-post" HFfundusAntFocusName = "HF-fundus-ant" medialWallVentralEndFocusName = "MW-ventEnd" HFlandmarkPostFocusName = "HF-LANDMARK-post" HFlandmarkAntFocusName = "HF-LANDMARK-ant" # # Remove any existing foci that identify corpus callosum locations # cmdList = (progName, "-surface-foci-delete", fociProjectionFileName, fociProjectionFileName, ccPosteriorFocusName, ccAnteriorFocusName, ccCogFocusName, genuLimitFocusName, ccSpleniumEndFocusName, ccGenuBeginningFocusName, medialWallStartFocusName, nearGenuBeginningFocusName, nearSpleniumEndFocusName, PHGpostFocusName, PHGantFocusName, HFfundusPostFocusName, HFfundusAntFocusName, HFlandmarkPostFocusName, HFlandmarkAntFocusName, medialWallVentralEndFocusName) runCommand(cmdList) # # Remove any previous corpus callosum borders # corpusCallosumLandmarkBorderName = "LANDMARK.CorpusCallosum" corpusCallosumOlfactoryBorderName = "LANDMARK.CorpusCallosumOflactory" PHgyrusBorderName = "PHG" HFlandmarkBorderName = "LANDMARK.HippocampalFissure" HFfundusBorderName = "HF-fundus" HFfundusToMWendBorderName = "HF-fundus-ant-to-MW-start" HFlandmarkToHFfundusBorderName = "HF-landmark-to-HF-fundus" HFlandmarkToMWendBorderName = "HF-landmark-to-MW-end" landmarkMedWallDorsalBorderName = "LANDMARK.MedWall.DORSAL" landmarkMedWallVentralBorderName = "LANDMARK.MedWall.VENTRAL" MedialWallBorderName = "MEDIAL.WALL" cmdList = (progName, "-surface-border-delete", borderProjectionFileName, borderProjectionFileName, corpusCallosumLandmarkBorderName, corpusCallosumOlfactoryBorderName, HFlandmarkBorderName, PHgyrusBorderName, HFfundusBorderName, HFfundusToMWendBorderName, HFlandmarkToHFfundusBorderName, HFlandmarkToMWendBorderName, landmarkMedWallDorsalBorderName, landmarkMedWallVentralBorderName, MedialWallBorderName) runCommand(cmdList) # # BORDER SAMPLING for MEDIAL WALL borderSampling = 3.0 # # Create the corpus callosum slice # cmdList = (progName, "-volume-create-corpus-callosum-slice", anatomyVolumeFileName, "CorpusCallosumSlice+orig.nii.gz", "right") runCommand(cmdList) # # Smear along X axis # cmdList = (progName, "-volume-smear-axis", "CorpusCallosumSlice+orig.nii.gz", "CorpusCallosumSlice_Smear6+orig.nii.gz", "X", str(6), str(-1), str(1)) runCommand(cmdList) cmdList = (progName, "-volume-smear-axis", "CorpusCallosumSlice_Smear6+orig.nii.gz", "CorpusCallosumSlice_Smear12+orig.nii.gz", "X", str(6), str(1), str(1)) runCommand(cmdList) # Smear more cmdList = (progName, "-volume-smear-axis", "CorpusCallosumSlice_Smear12+orig.nii.gz", "CorpusCallosumSlice_Smearx12_z3+orig.nii.gz", "Z", str(3), str(1), str(1)) runCommand(cmdList) # # Dilate # cmdList = (progName, "-volume-dilate", "CorpusCallosumSlice_Smearx12_z3+orig.nii.gz", corpusCallosumVolumeFileName, str(2)) runCommand(cmdList) # # Smear along Y axis # cmdList = (progName, "-volume-smear-axis", "CorpusCallosumSlice_SmearXZ_Dilate2+orig.nii.gz", corpusCallosumVolumeFileName, "Y", str(0), str(-1), str(1)) # DO NOT runCommand(cmdList) # # Map the non-zero voxels to a surface ROI file # cmdList = (progName, "-volume-map-to-surface-roi-file", corpusCallosumVolumeFileName, fiducialCoordFileName, closedTopoFileName, roiCorpusCallosumFileName) runCommand(cmdList) # # Place foci at anterior and posterior of corpus callosum # cmdList = (progName, "-surface-place-foci-at-limits", fiducialCoordFileName, fiducialCoordFileName, closedTopoFileName, roiCorpusCallosumFileName, fociProjectionFileName, fociProjectionFileName, "-y-min", ccPosteriorFocusName, "-y-max", ccAnteriorFocusName, "-cog", ccCogFocusName) runCommand(cmdList) # # Create a focus 20 mm posterior to ccAnt and and 10 mm ventral to cc-cog # nearGenuX = -2 if (rightHemFlag) : nearGenuX = 2 cmdList = (progName, "-surface-foci-create", fiducialCoordFileName, closedTopoFileName, fociProjectionFileName, fociProjectionFileName, "-focus", nearGenuBeginningFocusName, str(nearGenuX), str(15), str(-2)) runCommand(cmdList) # # Create a focus ~8 mm anterior to CaS-Ant and ~5 mm above for end of cc border # Xoffset = 5 if (rightHemFlag) : Xoffset = -5 cmdList = (progName, "-surface-foci-create", inflatedCoordFileName, closedTopoFileName, fociProjectionFileName, fociProjectionFileName, "-focus-offset-xyz", nearSpleniumEndFocusName, casAnteriorFocusName, str(Xoffset), casAnteriorFocusName, str(-3), casAnteriorFocusName, str(5)) runCommand(cmdList) # # Create border around ROI # cmdList = (progName, "-surface-border-draw-around-roi", fiducialCoordFileName, closedTopoFileName, roiCorpusCallosumFileName, borderProjectionFileName, borderProjectionFileName, corpusCallosumLandmarkBorderName, "-start-near-focus", fociProjectionFileName, nearGenuBeginningFocusName) runCommand(cmdList) # # Resample the border # cmdList = (progName, "-surface-border-resample", fiducialCoordFileName, closedTopoFileName, borderProjectionFileName, borderProjectionFileName, str(3.0), "-border-name", corpusCallosumLandmarkBorderName) runCommand(cmdList) # # Create a focus at start of LANDMARK.CorpusCallosum Border # cmdList = (progName, "-surface-border-link-to-focus", fiducialCoordFileName, closedTopoFileName, borderProjectionFileName, corpusCallosumLandmarkBorderName, fociProjectionFileName, fociProjectionFileName, "-first-link", ccGenuBeginningFocusName) runCommand(cmdList) # # Remove border points in front of on LANDMARK.CorpusCallosum Border # cmdList = (progName, "-surface-border-nibbler", fiducialCoordFileName, closedTopoFileName, borderProjectionFileName, borderProjectionFileName, corpusCallosumLandmarkBorderName, corpusCallosumLandmarkBorderName, fociProjectionFileName, nearSpleniumEndFocusName, "-remove-after") runCommand(cmdList) # # Create a focus at end of LANDMARK.CorpusCallosum Border # cmdList = (progName, "-surface-border-link-to-focus", fiducialCoordFileName, closedTopoFileName, borderProjectionFileName, corpusCallosumLandmarkBorderName, fociProjectionFileName, fociProjectionFileName, "-last-link", ccSpleniumEndFocusName) runCommand(cmdList) # # Create a new focus with X at coordinates relative to origin (AC) # cmdList = (progName, "-surface-foci-create", fiducialCoordFileName, closedTopoFileName, fociProjectionFileName, fociProjectionFileName, "-focus MedialWallStart 7 4 -10") runCommand(cmdList) # # Create an ROI of all nodes # allNodesRoiFileName = "AllNodes.roi" cmdList = (progName, "-system-file-delete", allNodesRoiFileName) runCommand(cmdList) cmdList = (progName, "-surface-region-of-interest-selection", fiducialCoordFileName, closedTopoFileName, allNodesRoiFileName, allNodesRoiFileName, "-all-nodes") runCommand(cmdList) # # Draw border connecting genu beginning to dorsal start # cmdList = (progName, "-surface-border-draw-geodesic", veryInflatedCoordFileName, closedTopoFileName, fociProjectionFileName, "MedialWallStart", ccGenuBeginningFocusName, allNodesRoiFileName, borderProjectionFileName, borderProjectionFileName, corpusCallosumOlfactoryBorderName, str(3.0)) runCommand(cmdList) # # Merge the borders into LANDMARK.MedWall.DORSAL # cmdList = (progName, "-surface-border-merge", borderProjectionFileName, borderProjectionFileName, landmarkMedWallDorsalBorderName, corpusCallosumOlfactoryBorderName, corpusCallosumLandmarkBorderName, "-delete-input-border-projections") runCommand(cmdList) # # Create a focus ~6 mm anterior to CaS-ant and 6 mm below for beginning of PHG # HFstartX = 3 if (rightHemFlag) : HFstartX = -3 cmdList = (progName, "-surface-foci-create", inflatedCoordFileName, closedTopoFileName, fociProjectionFileName, fociProjectionFileName, "-focus-offset-xyz", PHGpostFocusName, casAnteriorFocusName, str(HFstartX), casAnteriorFocusName, str(6), casAnteriorFocusName, str(-6)) runCommand(cmdList) # # Create an ROI of shape range using inflated curvature # cmdList = (progName, "-surface-region-of-interest-selection", inflatedCoordFileName, closedTopoFileName, roiPosInflatedFoldingFileName, roiPosInflatedFoldingFileName, "-shape", inflatedShapeCurvatureFileName, inflatedCurvatureColumnName, str(.1), str(100), "NORMAL") runCommand(cmdList) # # Create a focus ~11 mm above and 8 mm ant to CaS-ant on inflated for beginning of HF # HFstartX = 3 if (rightHemFlag) : HFstartX = -3 cmdList = (progName, "-surface-foci-create", inflatedCoordFileName, closedTopoFileName, fociProjectionFileName, fociProjectionFileName, "-focus-offset-xyz", HFfundusPostFocusName, casAnteriorFocusName, str(HFstartX), casAnteriorFocusName, str(8), casAnteriorFocusName, str(11)) runCommand(cmdList) # # Generate amygdala to olfactory stretch. sylvianSaddleX = 8 if (rightHemFlag) : sylvianSaddleX = -8 cmdList = (progName, "-surface-foci-create", inflatedCoordFileName, closedTopoFileName, fociProjectionFileName, fociProjectionFileName, "-focus-offset-xyz", HFfundusAntFocusName, "SFsaddleAnteriorLimit", str(sylvianSaddleX), "SFsaddleAnteriorLimit", str(-10), "SFsaddleAnteriorLimit", str(-7)) runCommand(cmdList); # # Create focus near HF # hfAntToPHGantX = 8 if (rightHemFlag) : hfAntToPHGantX = -8 cmdList = (progName, "-surface-foci-create", inflatedCoordFileName, closedTopoFileName, fociProjectionFileName, fociProjectionFileName, "-focus-offset-xyz", PHGantFocusName, HFfundusAntFocusName, str(hfAntToPHGantX), HFfundusAntFocusName, str(0), HFfundusAntFocusName, str(-7)) runCommand(cmdList) # # Draw the border # cmdList = (progName, "-surface-border-draw-metric", inflatedCoordFileName, closedTopoFileName, inflatedShapeCurvatureFileName, inflatedCurvatureColumnName, "NEGATIVE", fociProjectionFileName, HFfundusPostFocusName, HFfundusAntFocusName, borderProjectionFileName, borderProjectionFileName, HFfundusBorderName, str(borderSampling)); runCommand(cmdList) # # Resample the border SEEMS TO BE NECESSARY STILL # cmdList = (progName, "-surface-border-resample", fiducialCoordFileName, closedTopoFileName, borderProjectionFileName, borderProjectionFileName, str(3.0), "-border-name", HFfundusBorderName) runCommand(cmdList) # # Draw border from posterior to anterior of PHG # USES CURVATURE METHOD # cmdList = (progName, "-surface-border-draw-metric", inflatedCoordFileName, closedTopoFileName, inflatedShapeCurvatureFileName, inflatedCurvatureColumnName, "POSITIVE", fociProjectionFileName, PHGpostFocusName, PHGantFocusName, borderProjectionFileName, borderProjectionFileName, PHgyrusBorderName, str(borderSampling)); runCommand(cmdList) # # Resample the border SEEMS TO BE NECESSARY STILL # cmdList = (progName, "-surface-border-resample", fiducialCoordFileName, closedTopoFileName, borderProjectionFileName, borderProjectionFileName, str(3.0), "-border-name", PHgyrusBorderName) runCommand(cmdList) cmdList = (progName, "-surface-border-create-parallel-border", inflatedCoordFileName, closedTopoFileName, borderProjectionFileName, borderProjectionFileName, PHgyrusBorderName, HFlandmarkBorderName, "-separation-axis LATERAL 10", "-separation-axis Z -5") runCommand(cmdList) # # Create a focus at start of HFlandmark Border # cmdList = (progName, "-surface-border-link-to-focus", fiducialCoordFileName, closedTopoFileName, borderProjectionFileName, HFlandmarkBorderName, fociProjectionFileName, fociProjectionFileName, "-first-link", HFlandmarkPostFocusName) runCommand(cmdList) # # Create a focus at end of HFlandmark Border # cmdList = (progName, "-surface-border-link-to-focus", fiducialCoordFileName, closedTopoFileName, borderProjectionFileName, HFlandmarkBorderName, fociProjectionFileName, fociProjectionFileName, "-last-link", HFlandmarkAntFocusName) runCommand(cmdList) # # draw border segment # cmdList = (progName, "-surface-border-draw-geodesic", inflatedCoordFileName, closedTopoFileName, fociProjectionFileName, HFlandmarkAntFocusName, HFfundusAntFocusName, allNodesRoiFileName, borderProjectionFileName, borderProjectionFileName, HFlandmarkToHFfundusBorderName, str(borderSampling)) runCommand(cmdList) # # create medial wall ventral end # MWstartX = -19 if (rightHemFlag) : MWstartX = 19 cmdList = (progName, "-surface-foci-create", inflatedCoordFileName, closedTopoFileName, fociProjectionFileName, fociProjectionFileName, "-focus-offset-xyz", medialWallVentralEndFocusName, medialWallStartFocusName, str(MWstartX), medialWallStartFocusName, str(0), medialWallStartFocusName, str(0)) runCommand(cmdList) # # draw border segment # cmdList = (progName, "-surface-border-draw-geodesic", inflatedCoordFileName, closedTopoFileName, fociProjectionFileName, HFfundusAntFocusName, medialWallVentralEndFocusName, allNodesRoiFileName, borderProjectionFileName, borderProjectionFileName, HFfundusToMWendBorderName, str(borderSampling)) runCommand(cmdList) # ### Merge borders, create medial wall ventral landmark # cmdList = (progName, "-surface-border-merge", borderProjectionFileName, borderProjectionFileName, landmarkMedWallVentralBorderName, HFlandmarkBorderName, HFlandmarkToHFfundusBorderName, "-border-proj", HFfundusToMWendBorderName) runCommand(cmdList) # ### Merge borders, create medial wall, running along HF fundus # cmdList = (progName, "-surface-border-merge", borderProjectionFileName, borderProjectionFileName, MedialWallBorderName, HFfundusBorderName, HFfundusToMWendBorderName, "-border-proj", landmarkMedWallDorsalBorderName) runCommand(cmdList) # # Create an ROI that identifies nodes inside the medial wall border # cmdList = (progName, "-surface-region-of-interest-selection", ellipsoidalCoordFileName, closedTopoFileName, roiMedWallFileName, roiMedWallFileName, "-border-projection", borderProjectionFileName, MedialWallBorderName, "M", "3D", "0", "NORMAL") runCommand(cmdList) # # Assign the MEDIAL.WALL paint # cmdList = (progName, "-paint-assign-to-nodes", paintFileName, paintFileName, MedialWallPaintColumnName, "MEDIAL.WALL", "-assign-from-roi-file", roiMedWallFileName) runCommand(cmdList) ##----------------------------------------------------------------------------- # # Files created by this script # def createFileNames() : global rightHemFlag global borderColorFileName, borderProjectionFileName, corpusCallosumVolumeFileName global fociColorFileName, fociProjectionFileName global fociProjLDMKextremaFileName global inflatedShapeCurvatureFileName, inflatedCurvatureColumnName global inflatedGaussianColumnName global sulcusIdPaintColumnName global paintFileGyralSTGName, paintFileName global roiCaSFileName, roiStringentCaSFileName global roiCeSFileName, roiStringentCeSFileName global roiSTGFileName, roiStringentSTGFileName global roiSFFileName, roiStringentSFFileName, roiSFErodedFileName global roiCorpusCallosumFileName, roiOlfactorySulcusFileName global roiPosInflatedFoldingFileName, roiSFinflatedGaussianFileName global roiMedWallFileName global paintFileMedialWallName, MedialWallPaintColumnName rightHemFlag = False if (hemisphere == "R") : rightHemFlag = True filePrefix = species + "." + subject + "." + hemisphere + "." borderColorFileName = filePrefix + "Landmark.bordercolor" borderProjectionFileName = filePrefix + "Landmark.borderproj" corpusCallosumVolumeFileName = filePrefix + "CorpusCallosumSlice_SmearXZ_Dilate+orig.nii.gz" fociColorFileName = filePrefix + "Landmark.focicolor" fociProjectionFileName = filePrefix + "LandmarkGeneration.fociproj" fociProjLDMKextremaFileName = filePrefix + "LandmarkExtrema.fociproj" inflatedShapeCurvatureFileName = filePrefix + "InflatedCurvature.surface_shape" inflatedCurvatureColumnName = "\"Folding (Curvature) INFLATED\"" inflatedGaussianColumnName = "\"Gaussian Curvature INFLATED\"" sulcusIdPaintColumnName = "\"Sulcus ID\"" paintFileGyralSTGName = filePrefix + "SulcalID_withSTG.paint" MedialWallPaintColumnName = "\"Medial Wall\"" paintFileMedialWallName = "MEDIAL.WALL" paintFileName = filePrefix + "SulcalID.paint" roiCaSFileName = filePrefix + "CaS.roi" roiStringentCaSFileName = filePrefix + "CaS_Stringent.roi" roiCeSFileName = filePrefix + "CeS.roi" roiStringentCeSFileName = filePrefix + "CeS_Stringent.roi" roiSTGFileName = filePrefix + "STG.roi" roiStringentSTGFileName = filePrefix + "STG_Stringent.roi" roiSFFileName = filePrefix + "SF.roi" roiStringentSFFileName = filePrefix + "SF_Stringent.roi" roiSFErodedFileName = filePrefix + "SF_Eroded.roi" roiCorpusCallosumFileName = filePrefix + "CorpusCallosum.roi" roiOlfactorySulcusFileName = filePrefix + "OlfactorySulcus.roi" roiPosInflatedFoldingFileName = filePrefix + "PositiveInflatedFolding.roi" roiSFinflatedGaussianFileName = filePrefix + "SFinflatedGaussian.roi" roiMedWallFileName = filePrefix + "MedialWall.roi" ##----------------------------------------------------------------------------- ## ## Do the sulcal ID ## def doSulcalID() : createFileNames() if (doMapProbabilisticVolumes) : createSulcalIdentificationPaintFile() if (doCentralSulcus) : identifyCentralSulcus() if (doCalcarineSulcus) : identifyCalcarineSulcus() if (doSuperiorTemporalGyrus) : identifySuperiorTemporalGyrus() if (doSylvianFissure) : identifySylvianFissure() if (doMedialWall) : identifyMedialWall() ##----------------------------------------------------------------------------- ## ## Print help information ## def printHelp() : print "Options" print "-cas Identify calcarine sulcus." print "-ces Identify central sulcus." print "-mpv Map probabilistic volumes to create Sulcal ID Paint File." print "-mw Identify medial wall." print "-sf Identify sylvian fissure." print "-stg Identify Superior Temporal Gyrus." print "" print "-case04 Identify landmarks on Case 04" print "-case05 Identify landmarks on Case 05" ##----------------------------------------------------------------------------- ## ## "Main" code ## # # Get number of arguments # numArgs = len(sys.argv) if (numArgs <= 1) : printHelp() os._exit(0) # # Flags for different operations # doCalcarineSulcus = False doCentralSulcus = False doMapProbabilisticVolumes = False doMedialWall = False doSuperiorTemporalGyrus = False doSylvianFissure = False # # Flags for cases # doCase04 = False doCase05 = False # # Process arguments # for i in range (1, numArgs) : arg = sys.argv[i] if (arg == "-cas") : doCalcarineSulcus = True elif (arg == "-ces") : doCentralSulcus = True elif (arg == "-mpv") : doMapProbabilisticVolumes = True elif (arg == "-mw") : doMedialWall = True elif (arg == "-sf") : doSylvianFissure = True elif (arg == "-stg") : doSuperiorTemporalGyrus = True elif (arg == "-case04") : doCase04 = True elif (arg == "-case05") : doCase05 = True else: print "ERROR Invalid option: ", arg os._exit(-1) # # Case04 # if (doCase04) : anatomyVolumeFileName = "K04_mpr_on_711_2L_111_t88.4dfp.ifh" closedTopoFileName = "Human.K04.R.CLOSED.71612.topo" fiducialCoordFileName = "Human.K04.R.FIDUCIAL.71612.coord" inflatedCoordFileName = "Human.K04.R.Inflated.71612.coord" veryInflatedCoordFileName = "Human.K04.R.VeryInflated.71612.coord" ellipsoidalCoordFileName = "Human.K04.R.Ellipsoidal.71612.coord" geographyPaintFileName = "K04_mpr_on_711_2L_111_t88.R.full.segment_vent_corr4.geography.71612.paint" geographyPaintColumnName = "Geography" MedialWallPaintColumnName = "MEDIAL.WALL" shapeFileName = "K04_mpr_on_711_2L_111_t88.R.full.segment_vent_corr4.71612.surface_shape" shapeFileDepthColumnName = "Depth" shapeFileCurvatureColumnName = "\"Folding (Mean Curvature)\"" species = "Human" subject = "K04" hemisphere = "R" # # ID the sulci # doSulcalID() # # Case05 # if (doCase05) : anatomyVolumeFileName = "K05_mpr_on_711_2L_111_t88.4dfp.ifh" closedTopoFileName = "Human.K05.R.CLOSED.78049.topo" fiducialCoordFileName = "Human.K05.R.FIDUCIAL.78049.coord" inflatedCoordFileName = "Human.K05.R.Inflated.78049.coord" veryInflatedCoordFileName = "Human.K05.R.VeryInflated.78049.coord" ellipsoidalCoordFileName = "Human.K05.R.Ellipsoidal.78049.coord" geographyPaintFileName = "K05_mpr_on_711_2L_111_t88.R.full.segment_vent_corr5.geography.78049.paint" geographyPaintColumnName = "Geography" MedialWallPaintColumnName = "MEDIAL.WALL" shapeFileName = "K05_mpr_on_711_2L_111_t88.R.full.segment_vent_corr5.78049.surface_shape" shapeFileDepthColumnName = "Depth" shapeFileCurvatureColumnName = "\"Folding (Mean Curvature)\"" species = "Human" subject = "K05" hemisphere = "R" # # ID the sulci # doSulcalID() caret-5.6.4~dfsg.1.orig/caret_scripts/run_sulcal_id.py0000755000175000017500000001417311572067322022632 0ustar michaelmichael#!/usr/bin/python # # Run sulcal identification on buckner case 01-12 left and right # import re import os import sys caretCommand = "/Users/john/caret5_development/caret5_cpp/caret_source/caret_command/caret_command" ##----------------------------------------------------------------------------- # # Run a command # def runCommand(cmdList) : cmd = " ".join(cmdList) # join cmdList into a string separated by blanks print "\nExecuting: %s\n" % cmd result = os.system(cmd) if (result != 0) : print "ERROR COMMAND FAILED: " print " ", cmd ##os._exit(-1) ##----------------------------------------------------------------------------- # # Add file to spec file # def addToSpecFile(specFileName, specFileTag, fileName) : cmdList = ( caretCommand, "-spec-file-add", specFileName, specFileTag, fileName) runCommand(cmdList) ##----------------------------------------------------------------------------- # # Run sulcal identification # def runSulcalID(case, hem, nodes) : # # Some file names # areaColorFileName = "Human.BUCKNER_" + case + "." + hem + ".SulcalIdentification.areacolor" borderColorFileName = "Human.BUCKNER_" + case + "." + hem + ".LandmarkColors.bordercolor" borderProjectionFileName = "Human.BUCKNER_" + case + "." + hem + ".Landmarks.borderproj" fociColorFileName = "Human.BUCKNER_" + case + "." + hem + ".Debug.focicolor" fociProjectionFileName = "Human.BUCKNER_" + case + "." + hem + ".Debug.fociproj" paintFileName = "Human.BUCKNER_" + case + "." + hem + ".SulcalIdentification.paint" specFileName = "Human.Buckner" + case + "." + hem + ".spec" # # Run sulcal identification # cmdList = ( caretCommand, "-surface-border-landmark-identification", "Human.Buckner." + hem + "." + case + "_ANATOMY+orig.nii.gz", "Human.Buckner" + case + "." + hem + ".Fiducial." + nodes + ".coord", "Human.Buckner" + case + "." + hem + ".Inflated." + nodes + ".coord", "Human.Buckner" + case + "." + hem + ".VeryInflated." + nodes + ".coord", "Human.Buckner" + case + "." + hem + ".Ellipsoidal." + nodes + ".coord", "Human.Buckner" + case + "." + hem + ".CLOSED." + nodes + ".topo", "Human.Buckner" + case + "." + hem + ".paint_file_80." + nodes + ".paint", paintFileName, "Geography", "Human.Buckner" + case + "." + hem + ".surface_shape_file_87." + nodes + ".surface_shape", "Depth", "Human.BUCKNER_" + case + "." + hem + ".SulcalID.areacolor", areaColorFileName, "\"\"", borderProjectionFileName, "\"\"", borderColorFileName, fociProjectionFileName, fociColorFileName ) runCommand(cmdList) # # Update spec file # addToSpecFile(specFileName, "area_color_file", areaColorFileName) addToSpecFile(specFileName, "border_color_file", borderColorFileName) addToSpecFile(specFileName, "borderproj_file", borderProjectionFileName) addToSpecFile(specFileName, "foci_color_file", fociColorFileName) addToSpecFile(specFileName, "fociproj_file", fociProjectionFileName) addToSpecFile(specFileName, "paint_file", paintFileName) ##----------------------------------------------------------------------------- # # Find Fiducial surface and run Sulcal Identification # def runSulcalIdentificationInDirectory() : # # Get files in directory # files = os.listdir(".") # # Find the fiducial coord file # for filename in files: if (filename.find("Fiducial") >= 0) : print "Fiducial", filename m = re.match(r"Human\.Buckner(Case\d\d)\.([L|R])\.Fiducial\.(\d+)\.coord", filename) #print "m " m print "case ", m.group(1) print "hem ", m.group(2) print "nodes ", m.group(3) runSulcalID(m.group(1), m.group(2), m.group(3)) break ##----------------------------------------------------------------------------- # # Run sulcal identification on the specified cases # subDirListAll = ( "Human_Buckner_Case01/BUCKNER_Case01.L", "Human_Buckner_Case02/BUCKNER_Case02.L", "Human_Buckner_Case03/BUCKNER_Case03.L", "Human_Buckner_Case04/BUCKNER_Case04.L", "Human_Buckner_Case05/BUCKNER_Case05.L", "Human_Buckner_Case06/BUCKNER_Case06.L", "Human_Buckner_Case07/BUCKNER_Case07.L", "Human_Buckner_Case08/BUCKNER_Case08.L", "Human_Buckner_Case09/BUCKNER_Case09.L", "Human_Buckner_Case10/BUCKNER_Case10.L", "Human_Buckner_Case11/BUCKNER_Case11.L", "Human_Buckner_Case12/BUCKNER_Case12.L", "Human_Buckner_Case01/BUCKNER_Case01.R", "Human_Buckner_Case02/BUCKNER_Case02.R", "Human_Buckner_Case03/BUCKNER_Case03.R", "Human_Buckner_Case04/BUCKNER_Case04.R", "Human_Buckner_Case05/BUCKNER_Case05.R", "Human_Buckner_Case06/BUCKNER_Case06.R", "Human_Buckner_Case07/BUCKNER_Case07.R", "Human_Buckner_Case08/BUCKNER_Case08.R", "Human_Buckner_Case09/BUCKNER_Case09.R", "Human_Buckner_Case10/BUCKNER_Case10.R", "Human_Buckner_Case11/BUCKNER_Case11.R", "Human_Buckner_Case12/BUCKNER_Case12.R" ) subDirListSingle = ( "Human_Buckner_Case01/BUCKNER_Case01.L", "Human_Buckner_Case01/BUCKNER_Case01.R", "Human_Buckner_Case02/BUCKNER_Case02.L", "Human_Buckner_Case02/BUCKNER_Case02.R", ) # # Choose directory list for execution # subDirList = subDirListAll subDirList = subDirListSingle for subDirName in subDirList : print "*******************************************************************" print " ", subDirName print "*******************************************************************" os.chdir(subDirName) runSulcalIdentificationInDirectory() os.chdir("../..") #m = re.match(r"Human\.Buckner(Case\d\d)\.([L|R])\.Fiducial\.(\d+)\.coord", # "Human.BucknerCase01.L.Fiducial.60417.coord") #print "case ", m.group(1) #print "hem ", m.group(2) #print "nodes ", m.group(3) #runSulcalID(m.group(1), m.group(2), m.group(3)) caret-5.6.4~dfsg.1.orig/caret_scripts/run_flatten_threads.py0000755000175000017500000002744511572067322024050 0ustar michaelmichael#!/usr/bin/python # # Run sulcal identification on buckner case 01-12 left and right # caretCommand = "C:/caret/bin/caret_command" caretCommand = "/Users/john/caret5_osx/caret_source/caret_command/caret_command" import os import re import time import subprocess import sys from threading import Thread ##----------------------------------------------------------------------------- # # Add file to spec file # def addToSpecFile(specFileName, specFileTag, fileName) : cmdList = ( caretCommand, "-spec-file-add", specFileName, specFileTag, fileName) runCommand(cmdList) ##----------------------------------------------------------------------------- # # Class that runs a command in a thread. # If the command sent to the constructor is a list, each item in the list # is executed as a command sequentially # class RunCommandInThread(Thread): # # Constructor # "commandIn" may be either a command or a list containing commands # def __init__ (self, commandIn): Thread.__init__(self) # # If input is a string, place it into a list # If input is a list, it's ok # if isinstance(commandIn, str): self.commandList = [commandIn] elif isinstance(commandIn, list): self.commandList = commandIn else: self.commandList = [] #print "RunCommandInThread commandList:", self.commandList #print "RunCommandInThread commandIn:", commandIn #print "RunCommandInThread type(commandIn):", type(commandIn) def run(self): if len(self.commandList) == 0: print "ERROR COMMAND LIST EMPTY" return for cmd in self.commandList: p = subprocess.Popen(cmd, shell=True) result = p.wait() #result = os.waitpid(p.pid, 0) if (result != 0) : print "ERROR COMMAND FAILED: " print " ", cmd ##----------------------------------------------------------------------------- # # Run a a list of commands in multiple threads # class RunCommandsInMultipleThreads(Thread): def __init__(self, commandList, numberOfThreads): Thread.__init__(self) self.commandList = commandList self.maximumNumberOfThreads = numberOfThreads def run(self): if len(self.commandList) == 0: print "ERROR: List of commands is empty" return numberOfCommandsToRun = len(self.commandList) i = 0 while i < numberOfCommandsToRun: # # Determine how many threads to create # numThreadsToCreate = self.maximumNumberOfThreads numCommandsLeft = numberOfCommandsToRun - i if (numCommandsLeft < numThreadsToCreate) : numThreadsToCreate = numCommandsLeft # # Get directories that are to be executed # commandsToRunList = [] j = 0 while j < numThreadsToCreate: commandsToRunList.append(self.commandList[i]) i = i + 1 j = j + 1 # # Execute the directories # threadList = [] for commandToRun in commandsToRunList : print "STARTING: ", commandToRun cmdThread = RunCommandInThread(commandToRun) threadList.append(cmdThread) cmdThread.start() for thread in threadList: thread.join() ##----------------------------------------------------------------------------- # # Build add file to spec file command # def buildAddToSpecFileCommand(directoryName, specFileName, specFileTag, fileName) : cmdList = ( caretCommand, "-CHDIR", directoryName, "-spec-file-add", specFileName, specFileTag, fileName) commandText = " ".join(cmdList) return commandText ##----------------------------------------------------------------------------- # # Build a sulcal id command list and return it # def buildFlattenCommand(directoryName) : # # Get files in directory # files = os.listdir(directoryName) # # Find the fiducial coord file to get case, hemisphere nodes # case = "" hem = "" nodes = "" for filename in files: if (filename.find("Fiducial") >= 0) : #print "Fiducial", filename m = re.match(r"Human\.Buckner(Case\d\d)\.([L|R])\.Fiducial\.(\d+)\.coord", filename) case = m.group(1) hem = m.group(2) nodes = m.group(3) break #print "case ", case #print "hem ", hem #print "nodes ", nodes # # Put together the data file names # inputClosedTopologyFileName = "Human.Buckner" + case + "." + hem + ".CLOSED." + nodes + ".topo" inputEllipsoidCoordinateFileName = "Human.Buckner" + case + "." + hem + ".Ellipsoidal." + nodes + ".coord" inputFiducialCoordinateFileName = "Human.Buckner" + case + "." + hem + ".Fiducial." + nodes + ".coord" outputFiducialSmoothMedialWallCoordinateFileName = "Human.Buckner" + case + "." + hem + ".FIDUCIAL_SMOOTH_MW." + nodes + ".coord" outputSphericalCoordinateFileName = "Human.Buckner" + case + "." + hem + ".Sphere." + nodes + ".coord" outputInitialFlatCoordinateFileName = "Human.Buckner" + case + "." + hem + ".InitialFlat." + nodes + ".coord" inputAreaColorFileName = "Human.BUCKNER" + case + "." + hem + ".SulcalIdentification.areacolor" inputBorderProjectionFileName = "Human.BUCKNER" + case + "." + hem + ".Landmarks.borderproj" inputPaintFileName = "Human.BUCKNER" + case + "." + hem + ".SulcalIdentification.paint" outputCutTopologyFileName = "Human.Buckner" + case + "." + hem + ".CUT." + nodes + ".topo" outputOpenTopologyFileName = "Human.Buckner" + case + "." + hem + ".OPEN." + nodes + ".topo" outputAreaColorFileName = "Human.BUCKNER" + case + "." + hem + ".SulcalIdentification.areacolor" outputPaintFileName = "Human.BUCKNER" + case + "." + hem + ".SulcalIdentification.paint" specFileName = "Human.Buckner" + case + "." + hem + ".spec" # # Stereotaxic space # stereotaxicSpace = "711-2C" # # Run flatten hemisphere command # flattenCmdList = ( caretCommand, "-surface-flatten", "-CHDIR", directoryName, "-CHMOD", "UR,UW,GR,GW,AR,AW", inputFiducialCoordinateFileName, inputEllipsoidCoordinateFileName, inputClosedTopologyFileName, inputBorderProjectionFileName, outputFiducialSmoothMedialWallCoordinateFileName, outputSphericalCoordinateFileName, outputInitialFlatCoordinateFileName, outputOpenTopologyFileName, outputCutTopologyFileName, inputPaintFileName, outputPaintFileName, inputAreaColorFileName, outputAreaColorFileName, ) commandList = [" ".join(flattenCmdList)] # # Update the spec file # commandList.append(buildAddToSpecFileCommand(directoryName, specFileName, "FIDUCIALcoord_file", outputFiducialSmoothMedialWallCoordinateFileName)) commandList.append(buildAddToSpecFileCommand(directoryName, specFileName, "SPHERICALcoord_file", outputSphericalCoordinateFileName)) commandList.append(buildAddToSpecFileCommand(directoryName, specFileName, "FLATcoord_file", outputInitialFlatCoordinateFileName)) commandList.append(buildAddToSpecFileCommand(directoryName, specFileName, "OPENtopo_file", outputOpenTopologyFileName)) commandList.append(buildAddToSpecFileCommand(directoryName, specFileName, "CUTtopo_file", outputCutTopologyFileName)) # # Run flat multi-resolution morphing command # morphCmdList = ( caretCommand, "-surface-flat-multi-morph", "-CHDIR", directoryName, "-CHMOD", "UR,UW,GR,GW,AR,AW", specFileName, inputFiducialCoordinateFileName, outputInitialFlatCoordinateFileName, outputCutTopologyFileName, "-ces-borderprojection-file", inputBorderProjectionFileName, "LANDMARK.CentralSulcus" ) commandList.append(" ".join(morphCmdList)) return commandList ##----------------------------------------------------------------------------- # # Run sulcal identification on the specified cases # subDirListAll = [ "Human_Buckner_Case01/BUCKNER_Case01.L", "Human_Buckner_Case02/BUCKNER_Case02.L", "Human_Buckner_Case03/BUCKNER_Case03.L", "Human_Buckner_Case04/BUCKNER_Case04.L", "Human_Buckner_Case05/BUCKNER_Case05.L", "Human_Buckner_Case06/BUCKNER_Case06.L", "Human_Buckner_Case07/BUCKNER_Case07.L", "Human_Buckner_Case08/BUCKNER_Case08.L", "Human_Buckner_Case09/BUCKNER_Case09.L", "Human_Buckner_Case10/BUCKNER_Case10.L", "Human_Buckner_Case11/BUCKNER_Case11.L", "Human_Buckner_Case12/BUCKNER_Case12.L", "Human_Buckner_Case01/BUCKNER_Case01.R", "Human_Buckner_Case02/BUCKNER_Case02.R", "Human_Buckner_Case03/BUCKNER_Case03.R", "Human_Buckner_Case04/BUCKNER_Case04.R", "Human_Buckner_Case05/BUCKNER_Case05.R", "Human_Buckner_Case06/BUCKNER_Case06.R", "Human_Buckner_Case07/BUCKNER_Case07.R", "Human_Buckner_Case08/BUCKNER_Case08.R", "Human_Buckner_Case09/BUCKNER_Case09.R", "Human_Buckner_Case10/BUCKNER_Case10.R", "Human_Buckner_Case11/BUCKNER_Case11.R", "Human_Buckner_Case12/BUCKNER_Case12.R" ] subDirListSome = [ "Human_Buckner_Case01/BUCKNER_Case01.R", "Human_Buckner_Case10/BUCKNER_Case10.R", "Human_Buckner_Case11/BUCKNER_Case11.R" ] # # ERIN - Put the case you would like to run here!! # subDirListSingle = ["TEST_CASE01/BUCKNER_Case01.L"] # # Name of directory containing subjects # topDir = "/backup/sulcal_id/sulcal_id_john"; # # Choose directory list for execution # #subDirList = subDirListAll #subDirList = subDirListSome subDirList = subDirListSingle # # Number of subdirectories for processing # numSubDirs = len(subDirList) # # Maximum number of threads # maxThreads = 4 # # Get all commands # allCommands = [] for dirName in subDirList: subjectDirectory = topDir + "/" + dirName allCommands.append(buildFlattenCommand(subjectDirectory)) # # Run the commands in threads # runThreads = RunCommandsInMultipleThreads(allCommands, maxThreads) runThreads.start() # # Loop until all subdirectories are executed # ##i = 0 ##while i < numSubDirs: ## # ## # Determine how many threads to create ## # ## numThreadsToCreate = maxThreads ## numDirsLeft = numSubDirs - i ## if (numDirsLeft < numThreadsToCreate) : ## numThreadsToCreate = numDirsLeft ## ## # ## # Get directories that are to be executed ## # ## subDirsToRunList = [] ## j = 0 ## while j < numThreadsToCreate: ## subDirsToRunList.append(subDirList[i]) ## i = i + 1 ## j = j + 1 ## ## # ## # Execute the directories ## # ## threadList = [] ## for subDirName in subDirsToRunList : ## subjectDirectory = topDir + "/" + subDirName ## print "*******************************************************************" ## print subjectDirectory ## print "*******************************************************************" ## sidThread = SulcalID(subjectDirectory) ## threadList.append(sidThread) ## sidThread.start() ## ## for thread in threadList: ## thread.join() caret-5.6.4~dfsg.1.orig/caret_scripts/rgb_random.py0000755000175000017500000000140411572067322022112 0ustar michaelmichael#!/usr/bin/python # # Create an RGB paint file with random colors # import os import random import sys # # Name of RGB Paint file and number of nodes in the file # rgbPaintFileName = "random.RGB_paint" numberOfNodes = 71723 # # Create an RGB paint file with random colors # file = open(rgbPaintFileName, 'w') file.write("tag-version " + str(2) + "\n") file.write("tag-number-of-nodes " + str(numberOfNodes) + "\n") file.write("tag-number-of-columns " + str(1) + "\n") file.write("tag-BEGIN-DATA\n"); for i in range(numberOfNodes): node = str(i) red = str(random.random() * 255.0) green = str(random.random() * 255.0) blue = str(random.random() * 255.0) line = node + " " + red + " " + green + " " + blue + "\n" file.write(line) file.close() caret-5.6.4~dfsg.1.orig/caret_scripts/create_prob_atlas_volume.py0000755000175000017500000001157311572067322025050 0ustar michaelmichael#!/usr/bin/python # # Create the probabilistic atlas volume # # # Imports # import getpass import os import sys caretCommand = "/Users/john/caret5_osx/caret_source/caret_command/caret_command" ##----------------------------------------------------------------------------- # # Run a command # def runCommand(cmdList) : cmd = " ".join(cmdList) # join cmdList into a string separated by blanks print "\nExecuting: %s\n" % cmd result = os.system(cmd) if (result != 0) : print "COMMAND FAILED: " print " ", cmd os._exit(-1) ##----------------------------------------------------------------------------- # # Data file names # leftCoordFileNameList = [ "Human_Buck_Case01.L.F.RegToPALS_B12.LR.FIDUCIAL_711-2C.align.73730.coord", "Human_Buck_Case02.L.F.RegToPALS_B12.LR.FIDUCIAL_711-2C.align.73730.coord", "Human_Buck_Case03.L.F.RegToPALS_B12.LR.FIDUCIAL_711-2C.align.73730.coord", "Human_Buck_Case04.L.F.RegToPALS_B12.LR.FIDUCIAL_711-2C.align.73730.coord", "Human_Buck_Case05.L.F.RegToPALS_B12.LR.FIDUCIAL_711-2C.clean.align.73730.coord", "Human_Buck_Case06.L.F.RegToPALS_B12.LR.FIDUCIAL_711-2C.clean.align.73730.coord", "Human_Buck_Case07.L.M.RegToPALS_B12.LR.FIDUCIAL_711-2C.align.73730.coord", "Human_Buck_Case08.L.M.RegToPALS_B12.LR.FIDUCIAL_711-2C.align.73730.coord", "Human_Buck_Case09.L.M.RegToPALS_B12.LR.FIDUCIAL_711-2C.align.73730.coord", "Human_Buck_Case10.L.M.RegToPALS_B12.LR.FIDUCIAL_711-2C.align.73730.coord", "Human_Buck_Case11.L.M.RegToPALS_B12.LR.FIDUCIAL_711-2C.align.73730.coord", "Human_Buck_Case12.L.M.RegToPALS_B12.LR.FIDUCIAL_711-2C.align.73730.coord" ] leftPaintFileName = "Human.PALS_B12.IDsulci_B1-12_LEFT.clean3.73730.atlas.paint" leftTopoFileName = "Human.sphere_6.LEFT_HEM.73730.topo" leftOutputVolumeFileName = "PALS_B12.B1-12.LEFT.PROB-ATLAS_IDsulci.paint.clean.align+orig.nii.gz" rightCoordFileNameList = [ "Human_Buck_Case01.R.F.RegToPALS_B12.LR.FIDUCIAL_711-2C.align.73730.coord", "Human_Buck_Case02.R.F.RegToPALS_B12.LR.FIDUCIAL_711-2C.align.73730.coord", "Human_Buck_Case03.R.F.RegToPALS_B12.LR.FIDUCIAL_711-2C.align.73730.coord", "Human_Buck_Case04.R.F.RegToPALS_B12.LR.FIDUCIAL_711-2C.clean.align.73730.coord", "Human_Buck_Case05.R.F.RegToPALS_B12.LR.FIDUCIAL_711-2C.align.73730.coord", "Human_Buck_Case06.R.F.RegToPALS_B12.LR.FIDUCIAL_711-2C.clean.align.73730.coord", "Human_Buck_Case07.R.M.RegToPALS_B12.LR.FIDUCIAL_711-2C.align.73730.coord", "Human_Buck_Case08.R.M.RegToPALS_B12.LR.FIDUCIAL_711-2C.align.73730.coord", "Human_Buck_Case09.R.M.RegToPALS_B12.LR.FIDUCIAL_711-2C.align.73730.coord", "Human_Buck_Case10.R.M.RegToPALS_B12.LR.FIDUCIAL_711-2C.align.73730.coord", "Human_Buck_Case11.R.M.RegToPALS_B12.LR.FIDUCIAL_711-2C.align.73730.coord", "Human_Buck_Case12.R.M.RegToPALS_B12.LR.FIDUCIAL_711-2C.align.73730.coord" ] rightPaintFileName = "Human.PALS_B12.IDsulci_B1-12_RIGHT.clean4.73730.atlas.paint" rightTopoFileName = "Human.sphere_6.RIGHT_HEM.73730.topo" rightOutputVolumeFileName = "PALS_B12.B1-12.LEFT.PROB-ATLAS_IDsulci.paint.clean.align+orig.nii.gz" coordFileNameList = rightCoordFileNameList paintFileName = rightPaintFileName topoFileName = rightTopoFileName outputVolumeFileName = rightOutputVolumeFileName ##----------------------------------------------------------------------------- # # Create the paint volumes # paintVolumeFileNamesList = [] columnCounter = 1 for coordFileName in coordFileNameList : paintFileColumn = str(columnCounter) if (columnCounter < 10) : paintFileColumn = "0" + str(columnCounter) columnCounter = columnCounter + 1 paintVolumeFileName = "Human_Buck_Case" \ + paintFileColumn \ + ".R111_SulcalID+orig.nii.gz" paintVolumeFileNamesList.append(paintVolumeFileName) cmdList = (caretCommand, "-volume-create-in-stereotaxic-space", "711-2C-111", paintVolumeFileName) runCommand(cmdList) cmdList = (caretCommand, "-surface-to-volume", coordFileName, topoFileName, paintFileName, paintFileColumn, paintVolumeFileName, "-inner -1.5 -outer 1.5 -step 0.5") runCommand(cmdList) ##----------------------------------------------------------------------------- # # Combine the paint volumes into a single, multi-brick volume file # cmdList = (caretCommand, "-volume-file-combine", outputVolumeFileName, " ".join(paintVolumeFileNamesList), "-paint") runCommand(cmdList) ##----------------------------------------------------------------------------- # # Create the functional volumes, one for each paint name # cmdList = (caretCommand, "-volume-prob-atlas-to-functional", outputVolumeFileName, "PALS_B12.RIGHT.PROBABILISTIC-", ".align+orig.nii.gz") runCommand(cmdList) caret-5.6.4~dfsg.1.orig/caret_scripts/caret_unit_test.py0000755000175000017500000010160211572067322023175 0ustar michaelmichael#!/usr/bin/python # # Imports # import os import re import sys import time # # Globals # cleanupOutputFilesFlag = False correctImageDirectory = "correct_images" progName = "/Users/john/caret5_development/caret5_cpp/caret_source/caret_command/caret_command" progName = "/usr/local/caret/bin_macosx/caret_command" problemCount = 0 problemMessage = "" ##----------------------------------------------------------------------------- ## ## Delete any files matching the "glob regular expression" ## def deleteFiles(regularExpression) : print "Removing files matching %s" % regularExpression for fileName in os.listdir(".") : if (os.path.isfile(fileName)) : if (re.compile(regularExpression).search(fileName)) : #print "file: %s" % fileName os.remove(fileName) ##----------------------------------------------------------------------------- ## ## Set the random seed def setRandomSeed() : # # Global variables # global problemCount global problemMessage cmd = progName + " -statistic-set-random-seed 1001" result = os.system(cmd) if (result != 0) : problemCount += 1 problemMessage += ("Setting statistic random seed failed.\n") return result; ##----------------------------------------------------------------------------- ## ## Test statistics library ## def testStatistics() : # # Global variables # global cleanupOutputFilesFlag global problemCount global problemMessage global progName # # If only cleaning up output files we are done # if (cleanupOutputFilesFlag) : return # # Test the statistical algrorithms # cmd = progName \ + " -statistic-unit-test false " print "cmd: %s" % (cmd) # # Run the command # result = os.system(cmd) if (result != 0) : problemCount += 1 problemMessage += ("Statistics library testing failed.\n") return result ##----------------------------------------------------------------------------- ## ## Test graphics rendering of surfaces and volumes ## def testRendering() : # # globals # global cleanupOutputFilesFlag global problemCount global problemMessage deleteFiles(".*\.jpg") # # If only cleaning up output files we are done # if (cleanupOutputFilesFlag) : return specFileName = "rendering_unit_test_files.spec" sceneFileName = "Human.colin.R.RENDERING_TEST.scene" #renderSceneToImage($specFileName, $sceneFileName, "1", "render1.jpg"); #renderSceneToImage($specFileName, $sceneFileName, "2", "render2.jpg"); #renderSceneToImage($specFileName, $sceneFileName, "3", "render3.jpg"); #renderSceneToImage($specFileName, $sceneFileName, "4", "render4.jpg"); #renderSceneToImage($specFileName, $sceneFileName, "5", "render5.jpg"); #renderSceneToImage($specFileName, $sceneFileName, "6", "render6.jpg"); #renderSceneToImage($specFileName, $sceneFileName, "7", "render7.jpg"); fileList = [ "render1.jpg", "render2.jpg", "render3.jpg", "render4.jpg", "render5.jpg", "render6.jpg", "render7.jpg" ] counter = 1 for imageFile in fileList : if (renderSceneToImage(specFileName, sceneFileName, counter, imageFile) != 0) : problemCount += 1 problemMessage += ("Rendering test %d failed\n" % counter) counter += 1 ##----------------------------------------------------------------------------- ## ## Test scenes ## def testScenes1() : # # globals # global cleanupOutputFilesFlag global problemCount global problemMessage deleteFiles(".*\.jpg") # # If only cleaning up output files we are done # if (cleanupOutputFilesFlag) : return specFileName = "PALS_B12.RIGHT.STANDARD-SCENES.73730.spec" sceneFileName = "PALS_B12.RIGHT.STANDARD-for-Starting-ANALYSES.scene" fileList = [ "render1.jpg", "render2.jpg", "render3.jpg", "render4.jpg", "render5.jpg", "render6.jpg", "render7.jpg", "render8.jpg", "render9.jpg", "render10.jpg", "render11.jpg", "render12.jpg", "render13.jpg" ] counter = 1 for imageFile in fileList : if (renderSceneToImage(specFileName, sceneFileName, counter, imageFile) != 0) : problemCount += 1 problemMessage += ("Scenes 1 test %d failed\n" % counter) counter += 1 ##----------------------------------------------------------------------------- ## ## Test scenes ## def testScenes2() : # # globals # global cleanupOutputFilesFlag global problemCount global problemMessage deleteFiles(".*\.jpg") # # If only cleaning up output files we are done # if (cleanupOutputFilesFlag) : return specFileName = "PALS_B12.RIGHT.DEMO.73730.spec" sceneFileName = "PALS_B12.RIGHT.DEMO.scene" fileList = [ "render1.jpg", "render2.jpg", "render3.jpg", "render4.jpg", "render5.jpg", "render6.jpg", "render7.jpg", "render8.jpg", "render9.jpg", "render10.jpg", "render11.jpg", "render12.jpg", "render13.jpg", "render14.jpg" ] counter = 1 for imageFile in fileList : if (renderSceneToImage(specFileName, sceneFileName, counter, imageFile) != 0) : problemCount += 1 problemMessage += ("Scenes 2 test %d failed\n" % counter) counter += 1 ##----------------------------------------------------------------------------- ## ## Render a scene to an image file ## def renderSceneToImage(specFileName, sceneFileName, sceneNumber, imageName) : # # Global variables # global cleanupOutputFilesFlag global correctImageDirectory global progName # # Create the image # cmd = progName \ + " -show-scene " \ + specFileName \ + " " \ + sceneFileName \ + " " \ + str(sceneNumber) \ + " -image-file " \ + imageName \ + " 1" print "cmd: %s" % (cmd) # # Run the command # result = os.system(cmd) # # Successful # if (result == 0) : # # Compare with previously created valid image # cmd = progName \ + " -image-compare " \ + imageName \ + " " \ + correctImageDirectory + "/" + imageName result = os.system(cmd) return result ##----------------------------------------------------------------------------- ## ## Test metric mathematics ## def testMetricMathematics() : # # Global variables # global cleanupOutputFilesFlag global correctImageDirectory global problemCount global problemMessage global progName # # Metric file names # inputMetricFileName = "input.metric" infixOutputMetricFileName = "infixOutput.metric" postfixOutputMetricFileName = "postfixOutput.metric" # # Remove output metric # deleteFiles(infixOutputMetricFileName) deleteFiles(postfixOutputMetricFileName) # # If only cleaning up output files we are done # if (cleanupOutputFilesFlag) : return # # Test postfix # cmd = "%s %s %s %s %s %s" % (progName, "-metric-math-postfix", inputMetricFileName, postfixOutputMetricFileName, "postfix1", "\"@one@ @two@ * @three@ @four@ * -\"") print "Executing: %s" % cmd result = os.system(cmd) if (result == 0) : correctFile = "./results/" + postfixOutputMetricFileName tol = 1.0 cmd = "%s -caret-data-file-compare %s %s %f" % (progName, postfixOutputMetricFileName, correctFile, tol) result = os.system(cmd) if (result != 0) : problemCount += 1 problemMessage = problemMessage + "Metric math postfix failed.\n" # # Test infix 1 (normal) # cmd = "%s %s %s %s %s %s" % (progName, "-metric-math", inputMetricFileName, infixOutputMetricFileName, "math1", "\"max2[@one@ * @two@, @three@ * @four@]\"") print "Executing: %s" % cmd result1 = os.system(cmd) # # Test infix 2 (normal) # cmd = "%s %s %s %s %s %s" % (progName, "-metric-math", infixOutputMetricFileName, infixOutputMetricFileName, "math2", "\"@one@ - @two@ * @three@ + @four@\"") print "Executing: %s" % cmd result2 = os.system(cmd) # # Test infix 3 (normal) # cmd = "%s %s %s %s %s %s" % (progName, "-metric-math", infixOutputMetricFileName, infixOutputMetricFileName, "math3", "\"sqrt[@three@] + log10[nodeavg]\"") print "Executing: %s" % cmd result3 = os.system(cmd) allResults = result1 \ + result2 \ + result3 if (allResults == 0) : correctFile = "./results/" + infixOutputMetricFileName tol = 1.0 cmd = "%s -caret-data-file-compare %s %s %f" % (progName, infixOutputMetricFileName, correctFile, tol) allResults = os.system(cmd) if (allResults != 0) : problemCount += 1 problemMessage = problemMessage + "Metric math infix failed.\n" ##----------------------------------------------------------------------------- ## ## Test map volume to surface metric ## def testMapVolumeToSurfaceMetric() : # # Global variables # global cleanupOutputFilesFlag global correctImageDirectory global problemCount global problemMessage global progName # # Remove image and CYCLE coord files deleteFiles(".*\.metric") # # If only cleaning up output files we are done # if (cleanupOutputFilesFlag) : return option = "-volume-map-to-surface" topo = "Human.colin.Cerebral.R.CLOSED.71723.topo" fiducial = "Human.colin.Cerebral.R.FIDUCIAL.TLRC.711-2B.71723.coord" metric = "Human.colin.results.metric" volume = "CORBETTA_EtAl98.AttentionShift.PopAvg+orig.HEAD" cmd = "%s %s %s %s %s %s %s %s %s" % (progName, \ option, \ fiducial, \ topo, \ metric, \ metric, \ "METRIC_STRONGEST_VOXEL", \ volume, \ "-sv 3.0") print "Executing: %s" % cmd result = os.system(cmd) if (result == 0) : file = metric correctFile = "./results/" + file tol = 1.0 cmd = "%s -caret-data-file-compare %s %s %f" % (progName, file, correctFile, tol) result = os.system(cmd) if (result != 0) : problemCount += 1 problemMessage = problemMessage + "Map Volume to Surface Metric test failed.\n" ##----------------------------------------------------------------------------- ## ## Test map volume to surface paint ## def testMapVolumeToSurfacePaint() : # # Global variables # global cleanupOutputFilesFlag global correctImageDirectory global problemCount global problemMessage global progName # # Remove image and CYCLE coord files deleteFiles(".*\.paint") # # If only cleaning up output files we are done # if (cleanupOutputFilesFlag) : return option = "-volume-map-to-surface" topo = "Human.colin.Cerebral.R.CLOSED.71723.topo" fiducial = "Human.colin.Cerebral.R.FIDUCIAL.TLRC.711-2B.71723.coord" paint = "Human.colin.results.paint" volume = "brodmann.nii.gz" cmd = "%s %s %s %s %s %s %s %s" % (progName, \ option, \ fiducial, \ topo, \ paint, \ paint, \ "PAINT_ENCLOSING_VOXEL", \ volume) print "Executing: %s" % cmd result = os.system(cmd) if (result == 0) : file = paint correctFile = "./results/" + file tol = 1.0 cmd = "%s -caret-data-file-compare %s %s %f" % (progName, file, correctFile, tol) result = os.system(cmd) if (result != 0) : problemCount += 1 problemMessage = problemMessage + "Map Volume to Surface Paint test failed.\n" ##----------------------------------------------------------------------------- ## ## Test flat multiresolution morphing ## def testFlatMorphing() : # # Global variables # global cleanupOutputFilesFlag global correctImageDirectory global problemCount global problemMessage global progName # # Remove image and CYCLE coord files deleteFiles(".*\.jpg") deleteFiles(".*CYCLE.*\.coord") # # If only cleaning up output files we are done # if (cleanupOutputFilesFlag) : return option = "-surface-flat-multi-morph" spec = "Human.1582.L.FULL.spec" topo = "Human.1582.L.Full.CUT.65950.topo" fiducial = "Human.1582.L.Full.FIDUCIAL.65950.coord" flat = "Human.1582.L.Full.InitialFlat.65950.coord" cmd = "%s %s %s %s %s %s" % (progName, option, spec, fiducial, flat, topo) print "Executing: %s" % cmd result = os.system(cmd) if (result == 0) : file = "Human.1582.L.Full.FLAT_CYCLE5_OVERLAP_SMOOTH.65950.coord" correctFile = "./results/" + file tol = 1.0 cmd = "%s -caret-data-file-compare %s %s %f" % (progName, file, correctFile, tol) result = os.system(cmd) if (result != 0) : problemCount += 1 problemMessage = problemMessage + "Flat Multi-Resolution Morphing test failed.\n" ##----------------------------------------------------------------------------- ## ## Test spherical multiresolution morphing ## def testSphericalMorphing() : # # Global variables # global cleanupOutputFilesFlag global correctImageDirectory global problemCount global problemMessage global progName # # Delete image and CYCLE coord files # deleteFiles(".*\.jpg") deleteFiles(".*CYCLE.*\.coord") # # If only cleaning up output files we are done # if (cleanupOutputFilesFlag) : return option = "-surface-sphere-multi-morph" spec = "Human.1582.L.FULL.spec" topo = "Human.1582.L.Full.CLOSED.65950.topo" fiducial = "Human.1582.L.Full.FIDUCIAL.65950.coord" sphere = "Human.1582.L.Full.SPHERE.65950.coord" cmd = "%s %s %s %s %s %s" % (progName, option, spec, fiducial, sphere, topo) print "Executing: %s" % cmd result = os.system(cmd) if (result == 0) : file = "Human.1582.L.Full.SPHERE_CYCLE4.65950.coord" correctFile = "./results/" + file tol = 1.0 cmd = "%s -caret-data-file-compare %s %s %f" % (progName, file, correctFile, tol) result = os.system(cmd) if (result != 0) : problemCount += 1 problemMessage = problemMessage + "Spherical Multi-Resolution Morphing test failed.\n" ##----------------------------------------------------------------------------- ## ## Test spherical registration ## def testSphericalRegistration() : # # Global variables # global cleanupOutputFilesFlag global correctImageDirectory global problemCount global problemMessage global progName # # Delete image and deformed coord files # os.chdir("INDIVIDUAL.1582.L") deleteFiles("deformed.*") os.chdir("..") os.chdir("ATLAS_LEFT_HEM") deleteFiles("deformed.*") os.chdir("..") # # If only cleaning up output files we are done # if (cleanupOutputFilesFlag) : return command = "-surface-register-sphere-spec-only" options = "N" defMapFile = "\"\"" indivSpec = "INDIVIDUAL.1582.L/Human.1582.L.REGISTER-with-ATLAS.03-05.65950.spec" atlasSpec = "ATLAS_LEFT_HEM/Human.colin.L.REGISTER-to-INDIVIDUAL.03-05.71785.spec" cmd = "%s %s %s %s %s %s" % (progName, command, options, defMapFile, indivSpec, atlasSpec) print "Executing: cmd %s" % cmd result = os.system(cmd) if (result == 0) : os.chdir("ATLAS_LEFT_HEM") fileList = ("deformed_Human.1582.L.*.deform_map", "deformed_Human.1582.L.Eye-movements_attention.71785.metric", "deformed_Human.1582.L.FIDUCIAL.smMW.AC-orig.LPI.71785.coord", "deformed_two.71785.foci", "deformed_Human.1582.L.Full.FLAT.CartStd.71785.topo", "deformed_Human.1582.L.Full.LANDMARKS.ForSphericalRegistration.71785.borderproj") for file in fileList : correctFile = "./results/" + file tol = 1.0 cmd = "%s -caret-data-file-compare %s %s %f" % (progName, file, correctFile, tol) result += os.system(cmd) os.chdir("..") if (result != 0) : problemCount += 1 problemMessage = problemMessage + "Spherical registration test failed.\n" ##----------------------------------------------------------------------------- ## ## Test segmentation and generation of volume, surface, paint, and shape files ## def testSegmentation() : # # Global variables # global cleanupOutputFilesFlag global correctImageDirectory global problemCount global problemMessage global progName # # Delete image and deformed coord files # deleteFiles(".*\.jpg") deleteFiles("Human\.case9\.R.*") deleteFiles("RadialPositionMap.*") deleteFiles("params_file.*") # # If only cleaning up output files we are done # if (cleanupOutputFilesFlag) : return # 1111111111 # 1234567890123456789 op = "YYYYYYYYNYYYYYYYY" command = "-volume-segment" gray = "57" white = "106" pad = "NNNNNN" structure = "RIGHT" specName = "Human.TestSegmentation.R.spec" anatVolName = "Human.AnatomyVolume.R+orig.nii" segVolName = "\"\"" errorCorrection = "GRAPH" volType = "NIFTI_GZIP"; cmd = "%s %s %s %s %s %s %s %s %s %s %s %s" % \ (progName, command, anatVolName, segVolName, specName, op, gray, white, pad, structure, errorCorrection, volType) print "Executing: %s" % cmd result = os.system(cmd) if (result == 0) : fileList = ("Human.case9.R.Segmentation.nii.gz", "Human.case9.R.Segmentation_vent.nii.gz", "RadialPositionMap+orig.nii.gz", "Human.case9.R.Segment_GraphErrorCorrected.nii.gz", "Human.case9.R.CerebralHull.nii.gz", "Human.case9.R.Fiducial.*.coord", "Human.case9.R.Inflated.*.coord", "Human.case9.R.*.paint", "Human.case9.R.*.surface_shape") for file in fileList : correctFile = "./results/" + file tol = 1.0; cmd = "%s -caret-data-file-compare %s %s %f" % (progName, file, correctFile, tol) print cmd, "\n" result += os.system(cmd); if (result != 0) : problemMessage += "Segmentation test failed.\n"; problemCount += 1; ##----------------------------------------------------------------------------- ## ## Test one sample T-Test ## def testOneSampleTTest() : # # Global variables # global cleanupOutputFilesFlag global correctImageDirectory global problemCount global problemMessage global progName # # Names of output files # fileNamePrefix = "output-one-sample" outputTMap = fileNamePrefix + "_TMap.surface_shape" outputShuffledTMap = fileNamePrefix + "_ShuffledTMap.surface_shape" outputClustersPaint = fileNamePrefix + "_TMapClusters.paint" outputClustersMetric = fileNamePrefix + "_TMapClusters.metric" outputReport = fileNamePrefix + "_TMap_Significant_Clusters.txt" # # Delete previous output files # deleteFiles(outputTMap) deleteFiles(outputShuffledTMap) deleteFiles(outputClustersPaint) deleteFiles(outputClustersMetric) deleteFiles(outputReport) # # If only cleaning up output files we are done # if (cleanupOutputFilesFlag) : return # # arguments for command # argList = ("-metric-statistics-one-sample-t-test", "Composite_CON_young_left.surface_shape", "Human.PALS_B12.LEFT_AVG_B1-12.FIDUCIAL.clean.73730.coord", "Human.sphere_6.LEFT_HEM_OPEN.73730.topo", "Human.PALS_B12.B1-12_LEFT_DISTORTION-vs-AVG-FIDUCIAL_ONLY.73730.surface_shape", "1", # dist column number fileNamePrefix, "-3.0", # negative threshold "3.0", # positive threshold, "0.25", # p-value, "0", # variance smoothing iterations "0.0", # variance smoothing strength "250", # iterations "0.0", # T-Test known mean "1") # number of threads # # Assemble the command # cmd = progName for arg in argList : cmd = cmd + " " + arg # # Execute the command # print "Executing: %s" % cmd result = os.system(cmd) print "One-sample-result-code: %d", result if (result == 0) : fileList = (outputTMap, outputShuffledTMap, outputClustersPaint) for file in fileList : print "comparing: %s" % (file) correctFile = "./results/" + file tol = 1.0; cmd = "%s -caret-data-file-compare %s %s %f" % (progName, file, correctFile, tol) result += os.system(cmd) if (result != 0) : problemMessage += "One-Sample T-Test failed.\n" problemCount += 1 ##----------------------------------------------------------------------------- ## ## Test two sample T-Test with unpooled variance ## def testTwoSampleTTestUnpooled() : # # Global variables # global cleanupOutputFilesFlag global correctImageDirectory global problemCount global problemMessage global progName # # Names of output files # fileNamePrefix = "output-two-sample-unpooled" outputTMap = fileNamePrefix + "_TMap.surface_shape" outputShuffledTMap = fileNamePrefix + "_ShuffledTMap.surface_shape" outputClustersPaint = fileNamePrefix + "_TMapClusters.paint" outputClustersMetric = fileNamePrefix + "_TMapClusters.metric" outputReport = fileNamePrefix + "_TMap_Significant_Clusters.txt" # # Delete previous output files # deleteFiles(outputTMap) deleteFiles(outputShuffledTMap) deleteFiles(outputClustersPaint) deleteFiles(outputClustersMetric) deleteFiles(outputReport) # # If only cleaning up output files we are done # if (cleanupOutputFilesFlag) : return # # arguments for command # argList = ("-metric-statistics-two-sample-t-test", "NO_TRANSFORM", "UNPOOLED", "Composite_CON_young_left.surface_shape", "Composite_LFA_young_left.surface_shape", "Human.PALS_B12.LEFT_AVG_B1-12.FIDUCIAL.clean.73730.coord", "Human.sphere_6.LEFT_HEM_OPEN.73730.topo", "Human.PALS_B12.B1-12_LEFT_DISTORTION-vs-AVG-FIDUCIAL_ONLY.73730.surface_shape", "1", # dist column number fileNamePrefix, "250", # iterations "-3.0", # negative threshold "3.0", # positive threshold, "0.25", # p-value, "25", # variance smoothing iterations "0.5", # variance smoothing strength "true", # do Degrees-of-Freedom "true", # do p-value "1") # number of threads # # Assemble the command # cmd = progName for arg in argList : cmd = cmd + " " + arg # # Execute the command # print "Executing: %s" % cmd result = os.system(cmd) if (result == 0) : fileList = (outputTMap, outputShuffledTMap, outputClustersPaint) for file in fileList : correctFile = "./results/" + file tol = 1.0; cmd = "%s -caret-data-file-compare %s %s %f" % (progName, file, correctFile, tol) result += os.system(cmd) if (result != 0) : problemMessage += "Two-Sample T-Test Unpooled failed.\n" problemCount += 1 ##----------------------------------------------------------------------------- ## ## Test two sample T-Test with pooled variance ## def testTwoSampleTTestPooled() : # # Global variables # global cleanupOutputFilesFlag global correctImageDirectory global problemCount global problemMessage global progName # # Names of output files # fileNamePrefix = "output-two-sample-pooled" outputTMap = fileNamePrefix + "_TMap.surface_shape" outputShuffledTMap = fileNamePrefix + "_ShuffledTMap.surface_shape" outputClustersPaint = fileNamePrefix + "_TMapClusters.paint" outputClustersMetric = fileNamePrefix + "_TMapClusters.metric" outputReport = fileNamePrefix + "_TMap_Significant_Clusters.txt" # # Delete previous output files # deleteFiles(outputTMap) deleteFiles(outputShuffledTMap) deleteFiles(outputClustersPaint) deleteFiles(outputClustersMetric) deleteFiles(outputReport) # # If only cleaning up output files we are done # if (cleanupOutputFilesFlag) : return # # arguments for command # argList = ("-metric-statistics-two-sample-t-test", "NO_TRANSFORM", "POOLED", "Composite_CON_young_left.surface_shape", "Composite_LFA_young_left.surface_shape", "Human.PALS_B12.LEFT_AVG_B1-12.FIDUCIAL.clean.73730.coord", "Human.sphere_6.LEFT_HEM_OPEN.73730.topo", "Human.PALS_B12.B1-12_LEFT_DISTORTION-vs-AVG-FIDUCIAL_ONLY.73730.surface_shape", "1", # dist column number fileNamePrefix, "250", # iterations "-3.0", # negative threshold "3.0", # positive threshold, "0.25", # p-value, "25", # variance smoothing iterations "0.5", # variance smoothing strength "true", # do Degrees-of-Freedom "true", # do p-value "1") # number of threads # # Assemble the command # cmd = progName for arg in argList : cmd = cmd + " " + arg # # Execute the command # print "Executing: %s" % cmd result = os.system(cmd) if (result == 0) : fileList = (outputTMap, outputShuffledTMap, outputClustersPaint) for file in fileList : correctFile = "./results/" + file tol = 1.0; cmd = "%s -caret-data-file-compare %s %s %f" % (progName, file, correctFile, tol) result += os.system(cmd) if (result != 0) : problemMessage += "Two-Sample T-Test Pooled failed.\n" problemCount += 1 ##----------------------------------------------------------------------------- ## ## Initialize preferences file ## def initializePreferencesFile() : # # Set background and foreground color # argList = ("-preferences-file-settings", "-background-color", "0", "0", "0", "-foreground-color", "255", "255", "255", "-debug", "false"); # # Assemble the command # cmd = progName for arg in argList : cmd = cmd + " " + arg # # Execute the command # print "Executing: %s" % cmd result = os.system(cmd) if (result != 0) : problemMessage += "Updating preferences file failed.\n" problemCount += 1 ##----------------------------------------------------------------------------- ## def printHelp() : print "Caret Unit Testing" print "" print "Options" print " -all Peform all tests" print " -clean Cleanup test files generated by this program" print " -help Print this help information" print " -map-vol Test map volumes to surface" print " -metric-math Test metric mathematics" print " -morph Test morphing" print " -register Test registration" print " -render Test rending" print " -scenes Test scenes" print " -segment Test segmentation" print " -stat-lib Test statistical library" print " -surf-stat Test surface statistics" print " " print "More than one option may be specified." ##----------------------------------------------------------------------------- ## ## "Main" code ## # # Get number of arguments # numArgs = len(sys.argv) if (numArgs <= 1) : printHelp() os._exit(0) # # Flags to run the different tests # testMetricMathematicsFlag = False testMapVolumeToSurfaceFlag = False testMorphingFlag = False testRegistrationFlag = False testRenderingFlag = False testSegmentationFlag = False testScenesFlag = False testStatsLibraryFlag = False testSurfaceStatisticsFlag = False doAllFlag = False # # Process arguments # for i in range (1, numArgs) : arg = sys.argv[i] if arg == "-all" : doAllFlag = True elif arg == "-clean" : doAllFlag = True cleanupOutputFilesFlag = True elif arg == "-help" : printHelp() os._exit(0) elif arg == "-map-vol" : testMapVolumeToSurfaceFlag = True elif arg == "-metric-math" : testMetricMathematicsFlag = True elif arg == "-morph" : testMorphingFlag = True elif arg == "-register" : testRegistrationFlag = True elif arg == "-render" : testRenderingFlag = True elif arg == "-scenes" : testScenesFlag = True elif arg == "-segment" : testSegmentationFlag = True elif arg == "-stat-lib" : testStatsLibraryFlag = True elif arg == "-surf-stat" : testSurfaceStatisticsFlag = True else: print "ERROR Invalid option: ", arg os._exit(-1) if doAllFlag : testMapVolumeToSurfaceFlag = True testMetricMathematicsFlag = True testMorphingFlag = True testRegistrationFlag = True testRenderingFlag = True testScenesFlag = True testSegmentationFlag = True testStatsLibraryFlag = True testSurfaceStatisticsFlag = True print "Unit testing started" startTime = time.clock() # # Update preferences file # initializePreferencesFile() # # Set the random seed so statistical results consistent # setRandomSeed() # # Test statistical algorithms # if testStatsLibraryFlag : testStatistics() # # Test Statistical One-Sample T-Test # if testSurfaceStatisticsFlag : os.chdir("statistics") testOneSampleTTest() os.chdir("..") # # Test Statistical Two-Sample T-Test with Unpooled Variance # if testSurfaceStatisticsFlag : os.chdir("statistics") testTwoSampleTTestUnpooled() os.chdir("..") # # Test Statistical Two-Sample T-Test with Pooled Variance # if testSurfaceStatisticsFlag : os.chdir("statistics") testTwoSampleTTestPooled() os.chdir("..") # # Test Map Volume to Surface # if testMapVolumeToSurfaceFlag : os.chdir("map_volume_to_surface_metric") testMapVolumeToSurfaceMetric() os.chdir("..") os.chdir("map_volume_to_surface_paint") testMapVolumeToSurfacePaint() os.chdir("..") # # Test Metric Math # if testMetricMathematicsFlag : os.chdir("metric_math") testMetricMathematics() os.chdir("..") # # Test rendering code # if testRenderingFlag : os.chdir("rendering") testRendering() os.chdir("..") # # Test scene code # if testScenesFlag : os.chdir("scenes1") testScenes1() os.chdir("..") os.chdir("scenes2") testScenes2() os.chdir("..") # # Test flat multi-resolution morphing # if testMorphingFlag : os.chdir("flat_morphing") testFlatMorphing() os.chdir("..") # # Test spherical multi-resolution morphing # if testMorphingFlag : os.chdir("spherical_morphing") testSphericalMorphing() os.chdir("..") # # Test spherical registration # if testRegistrationFlag : os.chdir("spherical_registration") testSphericalRegistration() os.chdir("..") # # Test segmentation # if testSegmentationFlag : os.chdir("segmentation") testSegmentation() os.chdir("..") print "" print "There were %s errors. **************************************\n" % problemCount print "Unit Testing Completed." print "" if (problemCount > 0) : print "PROBLEMS: " print "%s" % problemMessage print "" endTime = time.clock() totalTime = endTime - startTime print "Total time (in seconds): %f" % totalTime os._exit(problemCount) caret-5.6.4~dfsg.1.orig/caret_scripts/RunCommandsInMultipleThreads.py0000755000175000017500000001050511572067322025546 0ustar michaelmichaelimport os import subprocess from threading import Thread ##----------------------------------------------------------------------------- # # Class that runs a command in a thread. # If the command sent to the constructor is a list, each item in the list # is executed as a command sequentially # class RunCommandInThread(Thread): # # Constructor # "commandIn" may be either a command or a list containing commands # def __init__ (self, commandIn): Thread.__init__(self) # # If input is a string, place it into a list # If input is a list, it's ok # if isinstance(commandIn, str): self.commandList = [commandIn] elif isinstance(commandIn, list): self.commandList = commandIn else: self.commandList = [] #print "RunCommandInThread commandList:", self.commandList #print "RunCommandInThread commandIn:", commandIn #print "RunCommandInThread type(commandIn):", type(commandIn) def run(self): if len(self.commandList) == 0: print "ERROR COMMAND LIST EMPTY" return for cmd in self.commandList: p = subprocess.Popen(cmd, shell=True) result = os.waitpid(p.pid, 0) if (result <= 0) : print "ERROR COMMAND FAILED: " print " ", cmd ###XX ##----------------------------------------------------------------------------- ###XX # ###XX # Run a a list of commands in multiple threads ###XX # ###XX class RunCommandsInMultipleThreads(Thread): ###XX def __init__(self, commandList, numberOfThreads): ###XX Thread.__init__(self) ###XX self.commandList = commandList ###XX self.maximumNumberOfThreads = numberOfThreads ###XX ###XX def run(self): ###XX if len(self.commandList) == 0: ###XX print "ERROR: List of commands is empty" ###XX return ###XX ###XX numberOfCommandsToRun = len(self.commandList) ###XX ###XX i = 0 ###XX while i < numberOfCommandsToRun: ###XX # ###XX # Determine how many threads to create ###XX # ###XX numThreadsToCreate = self.maximumNumberOfThreads ###XX numCommandsLeft = numberOfCommandsToRun - i ###XX if (numCommandsLeft < numThreadsToCreate) : ###XX numThreadsToCreate = numCommandsLeft ###XX ###XX # ###XX # Get directories that are to be executed ###XX # ###XX commandsToRunList = [] ###XX j = 0 ###XX while j < numThreadsToCreate: ###XX commandsToRunList.append(self.commandList[i]) ###XX i = i + 1 ###XX j = j + 1 ###XX ###XX # ###XX # Execute the directories ###XX # ###XX threadList = [] ###XX for commandToRun in commandsToRunList : ###XX #print "STARTING: ", commandToRun ###XX cmdThread = RunCommandInThread(commandToRun) ###XX threadList.append(cmdThread) ###XX cmdThread.start() ###XX ###XX for thread in threadList: ###XX thread.join() ##----------------------------------------------------------------------------- # # Run a a list of commands in multiple threads # def runCommands(commandList, maximumNumberOfThreads): if len(commandList) == 0: print "ERROR: List of commands is empty" return numberOfCommandsToRun = len(commandList) i = 0 while i < numberOfCommandsToRun: # # Determine how many threads to create # numThreadsToCreate = maximumNumberOfThreads numCommandsLeft = numberOfCommandsToRun - i if (numCommandsLeft < numThreadsToCreate) : numThreadsToCreate = numCommandsLeft # # Get directories that are to be executed # commandsToRunList = [] j = 0 while j < numThreadsToCreate: commandsToRunList.append(commandList[i]) i = i + 1 j = j + 1 # # Execute the directories # threadList = [] for commandToRun in commandsToRunList : #print "STARTING: ", commandToRun cmdThread = RunCommandInThread(commandToRun) threadList.append(cmdThread) cmdThread.start() for thread in threadList: thread.join() caret-5.6.4~dfsg.1.orig/caret_qmake_include.pro.john0000664000175000017500000002264211572067322022225 0ustar michaelmichael # # Compile debug on mac since that is where development is done # Compile optimized on Linux and Windows # macx { # # Uncomment for Debug # #CONFIG -= release #CONFIG += warn_on debug # # Uncomment for Release # CONFIG += release CONFIG -= debug # # Suppress "has different visibility" and ALL warnings # QMAKE_LFLAGS_APP += -w } !macx { CONFIG += release CONFIG -= debug } CONFIG += qt thread QT += network opengl xml #QT += qt3support QT -= qt3support # # when missing, it must be the GIFTI API library # DEFINES += CARET_FLAG #================================================================================= # # Check for needed environment variables # !exists( $(VTK_INC_DIR)/vtkConfigure.h ) { error("The environment variable for VTK includes \"VTK_INC_DIR\" not defined.") } !exists( $(QWT_INC_DIR)/qwt.h ) { error("The environment variable for QWT includes \"QWT_INC_DIR\" not defined.") } !exists( $(QTDIR)/include/qt.h ) { !exists( $(QTDIR)/include/Qt ) { !exists( $(QTDIR)/include/qt4/qt.h ) { !exists( $(QTDIR)/include/qt4/Qt ) { error("The environment variable for QT \"QTDIR\" not defined.") } } } } #================================================================================= # # if this file exists then QT4 is being used # exists( $(QTDIR)/include/Qt/qicon.h ) { DEFINES += CARET_QT4 QT += network opengl xml } #================================================================================= # # enable for profile (performance) measurement # #QMAKE_CXXFLAGS_DEBUG += -pg #QMAKE_LFLAGS_DEBUG += -pg #QMAKE_CXXFLAGS_RELEASE += -pg #QMAKE_LFLAGS_RELEASE += -pg #================================================================================= # # OpenMP (www.openmp.org) # !win32 { QMAKE_CXXFLAGS_DEBUG += -fopenmp QMAKE_LFLAGS_DEBUG += -fopenmp QMAKE_CXXFLAGS_RELEASE += -fopenmp QMAKE_LFLAGS_RELEASE += -fopenmp } #================================================================================= # # Update include paths # INCLUDEPATH += $$(QWT_INC_DIR) INCLUDEPATH += \ ../caret_brain_set \ ../caret_command_operations \ ../caret_common \ ../caret_statistics \ ../caret_files \ ../caret_uniformize \ ../caret_widgets DEPENDPATH += \ ../caret_brain_set \ ../caret_command_operations \ ../caret_common \ ../caret_statistics \ ../caret_files \ ../caret_uniformize \ ../caret_widgets #================================================================================= # # Is NetCDF/Minc available ? # exists( $(NETCDF_INC_DIR)/minc.h ) { DEFINES += HAVE_MINC INCLUDEPATH += $$(NETCDF_INC_DIR) NETCDF_LIBS = -L$$(NETCDF_LIB_DIR) \ -lminc \ -lnetcdf exists( $(NETCDF_LIB_DIR)/libminc2.a ) { NETCDF_LIBS += -lminc2 } exists( $(NETCDF_LIB_DIR)/libminc2.so ) { NETCDF_LIBS += -lminc2 } message( "Building with MINC support" ) } # # Is NetCDF/Minc NOT available # !exists( $(NETCDF_INC_DIR)/minc.h ) { message( "Building WITHOUT MINC support" ) } #============================================================================== # # VTK settings # INCLUDEPATH += $$(VTK_INC_DIR) # # have VTK compiler defines (primarily for GIFTI API) # DEFINES += HAVE_VTK # # VTK 5.x flag # DEFINES += HAVE_VTK5 message( "Building WITH VTK5 support" ) # # # INCLUDEPATH += ../caret_vtk4_classes # # need by caret_vtk4_classes # INCLUDEPATH += $$(VTK_INC_DIR)/vtkmpeg2encode # # VTK Libraries for VTK 5.x # win32 { #VTK_LIBS = ../caret_vtk4_classes/debug/libCaretVtk4Classes.a } !win32 { VTK_LIBS = ../caret_vtk4_classes/libCaretVtk4Classes.a } VTK_LIBS += \ -L$$(VTK_LIB_DIR) \ -lvtkFiltering \ -lvtkGenericFiltering \ -lvtkImaging \ -lvtkGraphics \ -lvtkIO \ -lvtkFiltering \ -lvtkCommon \ -lvtksys \ -lvtkjpeg \ -lvtkpng \ -lvtkexpat \ -lvtkzlib exists( $(VTK_INC_DIR)/vtkMPEG2Writer.h ) { message( "Building WITH MPEG support" ) DEFINES += HAVE_MPEG VTK_LIBS += -lvtkMPEG2Encode } # # Check for VTK 4.x (does not have vtkMPEG2Writer.h) # #!exists( $(VTK_INC_DIR)/vtkMPEG2Writer.h ) { # # # # VTK Libraries for VTK 4.x # # # VTK_LIBS = -L$$(VTK_LIB_DIR) \ # -lvtkGraphics \ # -lvtkFiltering \ # -lvtkIO \ # -lvtkPatented \ # -lvtkImaging \ # -lvtkCommon \ # -lvtkGraphics \ # -lvtkFiltering \ # -lvtkIO \ # -lvtkPatented \ # -lvtkImaging \ # -lvtkCommon \ # -lvtkFiltering \ # -lvtkCommon \ # -lvtkjpeg \ # -lvtkpng \ # -lvtkexpat \ # -lvtkDICOMParser \ # -lvtksys # !macx { # VTK_LIBS += \ # -lvtkzlib # } #} #============================================================================== # # Is Mesa Offscreen Rendering Available? # #exists ( $(OSMESA_INC_DIR)/GL/osmesa.h ) { # DEFINES += HAVE_OSMESA # # OSMESA_INCLUDE_PATH = $$(OSMESA_INC_DIR) # OSMESA_LIBS = -L$$(OSMESA_LIB_DIR) \ # -lOSMesa \ # -lGL \ # -lGLU \ # -lOSMesa # # message( "Offscreen Mesa Available" ) #} #============================================================================== # # Is ITK available # #exists( $(ITK_INC_DIR)/itkConfigure.h ) { # message( "Building with ITK support" ) exists( $(ITK_INC_DIR)/INTENTIONALLY_NO_VTK ) { DEFINES += HAVE_ITK INCLUDEPATH += \ $$(ITK_INC_DIR) \ $$(ITK_INC_DIR)/Algorithms \ $$(ITK_INC_DIR)/BasicFilters \ $$(ITK_INC_DIR)/Common \ $$(ITK_INC_DIR)/IO \ $$(ITK_INC_DIR)/Numerics \ $$(ITK_INC_DIR)/Numerics/Statistics \ $$(ITK_INC_DIR)/Patented \ $$(ITK_INC_DIR)/SpatialObject \ $$(ITK_INC_DIR)/Utilities/vxl/core \ $$(ITK_INC_DIR)/Utilities/vxl/vcl ITK_LIBS = -L$$(ITK_LIB_DIR) \ -lITKBasicFilters \ -lITKStatistics \ -lITKNumerics \ -lITKCommon \ -litkvnl_inst \ -litkvnl_algo \ -litkvnl \ -litkvcl \ -litknetlib \ -litksys } # # is ITK NOT available # !exists( $(ITK_INC_DIR)/itkConfigure.h ) { message( "Building WITHOUT ITK support" ) } #================================================================================= # # Windows unique stuff # win32 { !exists( $(ZLIB_INC_DIR)/zlib.h ) { error( "You must define ZLIB_INC_DIR to the ZLIB include files directory.") } CONFIG += rtti exceptions console INCLUDEPATH += $$(ZLIB_INC_DIR) ## LIBS += -L$$(ZLIB_LIB_DIR) -lzlib QMAKE_CXXFLAGS_RELEASE += -Wno-deprecated QMAKE_CXXFLAGS_DEBUG += -Wno-deprecated # # QWT libraries # QWT_LIBS = -L$$(QWT_LIB_DIR) \ -lqwt } #================================================================================= # # Windows Speech API # #win32 { # exists( $(SAPI_DIR)\Include\sapi.h ) { # DEFINES += HAVE_MS_SPEECH # INCLUDEPATH += $(SAPI_DIR)\Include # LIBS += $(SAPI_DIR)\Lib\i386\sapi.lib # } #} #================================================================================= # # Macintosh unique stuff # macx { # # Build objects for Universal binaries # #CONFIG += ppc x86 #QMAKE_CXXFLAGS_RELEASE += -Wno-deprecated \ # -isysroot /Developer/SDKs/MacOSX10.4u.sdk -arch i386 -arch ppc #QMAKE_CXXFLAGS_DEBUG += -Wno-deprecated \ # -isysroot /Developer/SDKs/MacOSX10.4u.sdk -arch i386 -arch ppc QMAKE_CXXFLAGS_RELEASE += -Wno-deprecated \ -isysroot /Developer/SDKs/MacOSX10.5.sdk QMAKE_CXXFLAGS_DEBUG += -Wno-deprecated \ -isysroot /Developer/SDKs/MacOSX10.5.sdk QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.4 # # Link for OSX 10.4 # #QMAKE_LFLAGS_DEBUG += -Wl,-syslibroot,/Developer/SDKs/MacOSX10.4u.sdk QMAKE_LFLAGS_RELEASE += -Wl,-syslibroot,/Developer/SDKs/MacOSX10.5.sdk #QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.4 # Link for Intel #QMAKE_LFLAGS_DEBUG += -arch i386 #QMAKE_LFLAGS_RELEASE += -arch i386 # # Add Link PPC for universal binaries # #QMAKE_LFLAGS_DEBUG += -arch ppc #QMAKE_LFLAGS_RELEASE += -arch ppc # # Universal binaries # Note: universal binaries are very slow to link, # so disable except when needed. # #QMAKE_LFLAGS_DEBUG += -arch i386 -arch ppc #QMAKE_LFLAGS_RELEASE += -arch i386 -arch ppc # # 64 bit support # Note that these flags are not sufficient to link # May need to recompile VTK, QT, etc # #QMAKE_CXXFLAGS_RELEASE += -m64 #QMAKE_CXXFLAGS_DEBUG += -m64 #QMAKE_LFLAGS_DEBUG += -m64 #QMAKE_LFLAGS_RELEASE += -m64 # CONFIG -= release # CONFIG += warn_on debug # # QWT libraries # QWT_LIBS = -L$$(QWT_LIB_DIR) \ -lqwt } #================================================================================= # # Unix (but not Mac) unique stuff # unix:!macx { # # QWT libraries # QWT_LIBS = -L$$(QWT_LIB_DIR) \ -lqwt LIBS += \ -ltiff \ -ljpeg QMAKE_CXXFLAGS_RELEASE += -Wno-deprecated QMAKE_CXXFLAGS_DEBUG += -Wno-deprecated #profiling #QMAKE_CXXFLAGS_RELEASE += -pg #QMAKE_CXXFLAGS_DEBUG += -pg #QMAKE_LFLAGS_DEBUG += -pg #QMAKE_LFLAGS_RELEASE += -pg } caret-5.6.4~dfsg.1.orig/caret_qmake_include.pro0000755000175000017500000002315711572067322021273 0ustar michaelmichaelCONFIG += qt thread QT += network opengl xml QT -= qt3support # # when missing, it must be the GIFTI API library # DEFINES += CARET_FLAG #================================================================================= # # Check for needed environment variables # !exists( $(VTK_INC_DIR)/vtkConfigure.h ) { error("The environment variable for VTK includes \"VTK_INC_DIR\" not defined.") } !exists( $(QTDIR)/include/qt.h ) { !exists( $(QTDIR)/include/Qt ) { !exists( $(QTDIR)/include/qt4/qt.h ) { !exists( $(QTDIR)/include/qt4/Qt ) { error("The environment variable for QT \"QTDIR\" not defined.") } } } } #================================================================================= # # if this file exists then QT4 is being used # exists( $(QTDIR)/include/Qt/qicon.h ) { DEFINES += CARET_QT4 QT += network opengl xml } #================================================================================= # # Update include paths # INCLUDEPATH += \ ../caret_brain_set \ ../caret_command_operations \ ../caret_common \ ../caret_statistics \ ../caret_files \ ../caret_uniformize \ ../caret_widgets \ ../caret_cifti DEPENDPATH += \ ../caret_brain_set \ ../caret_command_operations \ ../caret_common \ ../caret_statistics \ ../caret_files \ ../caret_uniformize \ ../caret_widgets \ ../caret_cifti #================================================================================= # # Is NetCDF/Minc available ? # exists( $(NETCDF_INC_DIR)/minc.h ) { DEFINES += HAVE_MINC INCLUDEPATH += $$(NETCDF_INC_DIR) NETCDF_LIBS = -L$$(NETCDF_LIB_DIR) \ -lminc \ -lnetcdf exists( $(NETCDF_LIB_DIR)/libminc2.a ) { NETCDF_LIBS += -lminc2 # # Apparently, if libminc2 exists, libminc # may not and is not necessary # !exists( $(NETCDF_LIB_DIR)/libminc.a ) { NETCDF_LIBS -= -lminc } } exists( $(NETCDF_LIB_DIR)/libminc2.so ) { NETCDF_LIBS += -lminc2 } message( "Building with MINC support" ) } # # Is NetCDF/Minc NOT available # !exists( $(NETCDF_INC_DIR)/minc.h ) { message( "Building WITHOUT MINC support" ) } #============================================================================== # # QWT settings # exists( $(QWT_INC_DIR)/qwt.h ) { message("Building with QWT support") DEFINES += HAVE_QWT INCLUDEPATH += $$(QWT_INC_DIR) } !exists( $(QWT_INC_DIR)/qwt.h ) { message("Building WITHOUT QWT support") } #============================================================================== # # VTK settings # !vs:!nmake:INCLUDEPATH += $$(VTK_INC_DIR) #visual studio has separate include dirs for debug and release # # have VTK compiler defines (primarily for GIFTI API) # DEFINES += HAVE_VTK # # VTK 5.x flag # DEFINES += HAVE_VTK5 message( "Building with VTK5 support" ) # # # VTK_LIBS_TEMP = -lvtkFiltering \ -lvtkGenericFiltering \ -lvtkImaging \ -lvtkGraphics \ -lvtkIO \ -lvtkFiltering \ -lvtkCommon \ -lvtksys \ -lvtkjpeg \ -lvtkpng \ -lvtkexpat \ -lvtkzlib #============================================================================== #============================================================================== # # There are five major target platforms, Unix, OSX, Windows/Msys, Windows/VisualStudio, Debian/Ubuntu. # # # Windows/Msys Specific # # qmake doesn't have an OR operator when checking conditionals, so I check for win32, then if it's not vs AND not nmake, assume msys, # otherwise it's either vs or nmake. win32 { !vs:!nmake { INCLUDEPATH += ../caret_vtk4_classes INCLUDEPATH += $$(VTK_INC_DIR)/vtkmpeg2encode VTK_LIBS = -L$$(VTK_LIB_DIR) $$VTK_LIBS_TEMP exists( $(VTK_INC_DIR)/vtkMPEG2Writer.h ) { message( "Building WITH MPEG support" ) DEFINES += HAVE_MPEG VTK_LIBS += -lvtkMPEG2Encode } # # We need to include zlib on windows # !exists( $(ZLIB_INC_DIR)/zlib.h ) { error( "You must define ZLIB_INC_DIR to the ZLIB include files directory.") } CONFIG += rtti exceptions console INCLUDEPATH += $$(ZLIB_INC_DIR) LIBS += -L$$(ZLIB_LIB_DIR) -lz contains (DEFINES, HAVE_QWT) { QWT_LIBS = -L$$(QWT_LIB_DIR) -lqwt } } # # Windows/Visual Studio Specific # else { CONFIG(debug,release|debug):INCLUDEPATH += $$(VTK_INC_DIR) CONFIG(release,release|debug):INCLUDEPATH += $$(VTK_RELEASE_INC_DIR) INCLUDEPATH += ../caret_vtk4_classes CONFIG(debug,release|debug):INCLUDEPATH += $$(VTK_INC_DIR)/vtkmpeg2encode CONFIG(release,release|debug):INCLUDEPATH += $$(VTK_RELEASE_INC_DIR)/vtkmpeg2encode VTK_LIBS = -L$$(VTK_LIB_DIR) $$VTK_LIBS_TEMP VTK_RELEASE_LIBS = -L$$(VTK_RELEASE_LIB_DIR) $$VTK_LIBS_TEMP exists( $(VTK_INC_DIR)/vtkMPEG2Writer.h ) { message( "Building WITH MPEG support" ) DEFINES += HAVE_MPEG VTK_LIBS += -lvtkMPEG2Encode VTK_REELEASE_LIBS += -lvtkMPEG2Encode } # # We need to include zlib on windows # !exists( $(ZLIB_INC_DIR)/zlib.h ) { error( "You must define ZLIB_INC_DIR to the ZLIB include files directory.") } CONFIG += rtti exceptions console INCLUDEPATH += $$(ZLIB_INC_DIR) LIBS += -L$$(ZLIB_LIB_DIR) -lzlib contains (DEFINES, HAVE_QWT) { CONFIG(release,release|debug):QWT_LIBS = -L$$(QWT_LIB_DIR) -lqwt CONFIG(debug,release|debug):QWT_LIBS = -L$$(QWT_LIB_DIR) -lqwtd } } } # # OsX Specific # macx { QMAKE_CXXFLAGS += -fopenmp QMAKE_LFLAGS += -fopenmp INCLUDEPATH += ../caret_vtk4_classes INCLUDEPATH += $$(VTK_INC_DIR)/vtkmpeg2encode !dll:VTK_LIBS = ../caret_vtk4_classes/libCaretVtk4Classes.a VTK_LIBS += -L$$(VTK_LIB_DIR) $$VTK_LIBS_TEMP exists( $(VTK_INC_DIR)/vtkMPEG2Writer.h ):!ubuntu { message( "Building WITH MPEG support" ) DEFINES += HAVE_MPEG VTK_LIBS += -lvtkMPEG2Encode } contains (DEFINES, HAVE_QWT) { QWT_LIBS = -L$$(QWT_LIB_DIR) -lqwt } # # Target 10.5 if it is available, else 10.6 # exists( /Developer/SDKs/MacOSX10.5.sdk ) { QMAKE_CXXFLAGS += -isysroot /Developer/SDKs/MacOSX10.5.sdk QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.5 QMAKE_LFLAGS_RELEASE += -Wl,-syslibroot,/Developer/SDKs/MacOSX10.5.sdk } !exists( /Developer/SDKs/MacOSX10.5.sdk ) { exists( /Developer/SDKs/MacOSX10.6.sdk ) { QMAKE_CXXFLAGS += -isysroot /Developer/SDKs/MacOSX10.6.sdk QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.6 QMAKE_LFLAGS_RELEASE += -Wl,-syslibroot,/Developer/SDKs/MacOSX10.5.sdk } } QMAKE_LFLAGS_APP += -w } # # Debian/Ubuntu Specific # ubuntu { message ("Building for Ubuntu") QMAKE_CXXFLAGS += -fopenmp -DUBUNTU QMAKE_LFLAGS += -fopenmp VTK_LIBS += -L$$(VTK_LIB_DIR) -lvtkFiltering \ -lvtkGenericFiltering \ -lvtkImaging \ -lvtkGraphics \ -lvtkIO \ -lvtkFiltering \ -lvtkCommon \ -lvtksys LIBS += -lpng contains (DEFINES, HAVE_QWT) { QWT_LIBS = -L$$(QWT_LIB_DIR) -lqwt-qt4 } DEFINES -= HAVE_MPEG VTK_LIBS -= -lvtkMPEG2Encode exists( $(NETCDF_INC_DIR)/minc.h ) { DEFINES += HAVE_MINC INCLUDEPATH += $$(NETCDF_INC_DIR) NETCDF_LIBS = -L$$(NETCDF_LIB_DIR) \ -lminc2 \ -lnetcdf NETCDF_LIBS -= -lminc } } # # All other Unix variants # unix:!macx:!ubuntu { contains(QMAKE_CXX, icpc) { #QMAKE_CXXFLAGS += -openmp -ipo #QMAKE_LFLAGS += -openmp -openmp-link static -ipo QMAKE_CXXFLAGS += -openmp QMAKE_LFLAGS += -openmp -openmp-link static } !contains(QMAKE_CXX, icpc) { QMAKE_CXXFLAGS += -fopenmp QMAKE_LFLAGS += -fopenmp } INCLUDEPATH += ../caret_vtk4_classes INCLUDEPATH += $$(VTK_INC_DIR)/vtkmpeg2encode !dll:VTK_LIBS = ../caret_vtk4_classes/libCaretVtk4Classes.a VTK_LIBS += -L$$(VTK_LIB_DIR) $$VTK_LIBS_TEMP exists( $(VTK_INC_DIR)/vtkMPEG2Writer.h ) { message( "Building WITH MPEG support" ) DEFINES += HAVE_MPEG VTK_LIBS += -lvtkMPEG2Encode } contains (DEFINES, HAVE_QWT) { QWT_LIBS = -L$$(QWT_LIB_DIR) -lqwt } } #============================================================================== #============================================================================== # # For build flags, there are two major platforms, Unix and Visual Studio # # # Unix (including msys win32) Build Flags # !vs:!nmake { release { QMAKE_CXXFLAGS -= -g -O1 -Wl,-O1 QMAKE_LFLAGS -= -g -O1 -Wl,-O1 QMAKE_CXXFLAGS += -O2 -Wno-deprecated QMAKE_LFLAGS += -O2 !debug:!profile:QMAKE_POST_LINK=strip -S $(TARGET) } debug { QMAKE_CXXFLAGS += -g -Wno-deprecated QMAKE_LFLAGS += -g QMAKE_CXXFLAGS -= -O2 QMAKE_LFLAGS -= -O2 } profile { QMAKE_CXXFLAGS += -pg -O2 QMAKE_LFLAGS += -pg } } # # Visual Studio specific build flags # else:win32 { CONFIG(release,release|debug) { QMAKE_CXXFLAGS_RELEASE -= -O1 -Wl,-O2 QMAKE_LFLAGS_RELEASE -= -O1 -Wl,-O2 QMAKE_CXXFLAGS_RELEASE += -O2 -D_USE_MATH_DEFINES -wd"4290" -wd"4244" -wd"4267" -wd"4305" -wd"4100" -wd"4005" -MP -DNOMINMAX -D_CRT_SECURE_NO_WARNINGS QMAKE_LFLAGS_RELEASE += -O2 -D_USE_MATH_DEFINES -STACK:10000000 } CONFIG(debug,release|debug) { QMAKE_CXXFLAGS_DEBUG -= -O2 QMAKE_LFLAGS_DEBUG -= -O2 QMAKE_CXXFLAGS_DEBUG += -D_DEBUG -D_USE_MATH_DEFINES -wd"4290" -wd"4244" -wd"4267" -wd"4305" -wd"4100" -wd"4005" -MP -DNOMINMAX -D_CRT_SECURE_NO_WARNINGS QMAKE_LFLAGS_DEBUG += -DEBUG -STACK:10000000 } } caret-5.6.4~dfsg.1.orig/caret_files/0000775000175000017500000000000011572067322017041 5ustar michaelmichaelcaret-5.6.4~dfsg.1.orig/caret_files/nifti1.h0000664000175000017500000020424011572067322020406 0ustar michaelmichael/** \file nifti1.h \brief Official definition of the nifti1 header. Written by Bob Cox, SSCC, NIMH. */ #ifndef _NIFTI_HEADER_ #define _NIFTI_HEADER_ /***************************************************************************** ** 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 /*=================*/ /*! \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; */ char data_type[10]; /*!< ++UNUSED++ */ /* char data_type[10]; */ char db_name[18]; /*!< ++UNUSED++ */ /* char db_name[18]; */ int extents; /*!< ++UNUSED++ */ /* int extents; */ short session_error; /*!< ++UNUSED++ */ /* short session_error; */ char regular; /*!< ++UNUSED++ */ /* char regular; */ char dim_info; /*!< MRI slice ordering. */ /* char hkey_un0; */ /*--- was image_dimension substruct ---*/ short dim[8]; /*!< Data array dimensions.*/ /* short dim[8]; */ float intent_p1 ; /*!< 1st intent parameter. */ /* short unused8; */ /* short unused9; */ float intent_p2 ; /*!< 2nd intent parameter. */ /* short unused10; */ /* short unused11; */ float intent_p3 ; /*!< 3rd intent parameter. */ /* short unused12; */ /* short unused13; */ short intent_code ; /*!< NIFTI_INTENT_* code. */ /* short unused14; */ short datatype; /*!< Defines data type! */ /* short datatype; */ short bitpix; /*!< Number bits/voxel. */ /* short bitpix; */ short slice_start; /*!< First slice index. */ /* short dim_un0; */ float pixdim[8]; /*!< Grid spacings. */ /* float pixdim[8]; */ float vox_offset; /*!< Offset into .nii file */ /* float vox_offset; */ float scl_slope ; /*!< Data scaling: slope. */ /* float funused1; */ float scl_inter ; /*!< Data scaling: offset. */ /* float funused2; */ short slice_end; /*!< Last slice index. */ /* float funused3; */ char slice_code ; /*!< Slice timing order. */ char xyzt_units ; /*!< Units of pixdim[1..4] */ float cal_max; /*!< Max display intensity */ /* float cal_max; */ float cal_min; /*!< Min display intensity */ /* float cal_min; */ float slice_duration;/*!< Time for 1 slice. */ /* float compressed; */ float toffset; /*!< Time axis shift. */ /* float verified; */ int glmax; /*!< ++UNUSED++ */ /* int glmax; */ int glmin; /*!< ++UNUSED++ */ /* int glmin; */ /*--- was data_history substruct ---*/ char descrip[80]; /*!< any text you like. */ /* char descrip[80]; */ char aux_file[24]; /*!< auxiliary filename. */ /* char aux_file[24]; */ short qform_code ; /*!< NIFTI_XFORM_* code. */ /*-- all ANALYZE 7.5 ---*/ short sform_code ; /*!< NIFTI_XFORM_* code. */ /* fields below here */ /* are replaced */ float quatern_b ; /*!< Quaternion b param. */ float quatern_c ; /*!< Quaternion c param. */ float quatern_d ; /*!< Quaternion d param. */ float qoffset_x ; /*!< Quaternion x shift. */ float qoffset_y ; /*!< Quaternion y shift. */ float qoffset_z ; /*!< Quaternion z shift. */ float srow_x[4] ; /*!< 1st row affine transform. */ float srow_y[4] ; /*!< 2nd row affine transform. */ float srow_z[4] ; /*!< 3rd row affine transform. */ char intent_name[16];/*!< 'name' or meaning of data. */ char magic[4] ; /*!< MUST be "ni1\0" or "n+1\0". */ } ; /**** 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 ; /*---------------------------------------------------------------------------*/ /* 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 */ /*! \defgroup NIFTI1_DATATYPES \brief nifti1 datatype codes @{ */ /*--- the original ANALYZE 7.5 type codes ---*/ #define DT_NONE 0 #define DT_UNKNOWN 0 /* what it says, dude */ #define DT_BINARY 1 /* binary (1 bit/voxel) */ #define DT_UNSIGNED_CHAR 2 /* unsigned char (8 bits/voxel) */ #define DT_SIGNED_SHORT 4 /* signed short (16 bits/voxel) */ #define DT_SIGNED_INT 8 /* signed int (32 bits/voxel) */ #define DT_FLOAT 16 /* float (32 bits/voxel) */ #define DT_COMPLEX 32 /* complex (64 bits/voxel) */ #define DT_DOUBLE 64 /* double (64 bits/voxel) */ #define DT_RGB 128 /* RGB triple (24 bits/voxel) */ #define DT_ALL 255 /* not very useful (?) */ /*----- another set of names for the same ---*/ #define DT_UINT8 2 #define DT_INT16 4 #define DT_INT32 8 #define DT_FLOAT32 16 #define DT_COMPLEX64 32 #define DT_FLOAT64 64 #define DT_RGB24 128 /*------------------- new codes for NIFTI ---*/ #define DT_INT8 256 /* signed char (8 bits) */ #define DT_UINT16 512 /* unsigned short (16 bits) */ #define DT_UINT32 768 /* unsigned int (32 bits) */ #define DT_INT64 1024 /* long long (64 bits) */ #define DT_UINT64 1280 /* unsigned long long (64 bits) */ #define DT_FLOAT128 1536 /* long double (128 bits) */ #define DT_COMPLEX128 1792 /* double pair (128 bits) */ #define 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. */ #define NIFTI_TYPE_UINT8 2 /*! signed short. */ #define NIFTI_TYPE_INT16 4 /*! signed int. */ #define NIFTI_TYPE_INT32 8 /*! 32 bit float. */ #define NIFTI_TYPE_FLOAT32 16 /*! 64 bit complex = 2 32 bit floats. */ #define NIFTI_TYPE_COMPLEX64 32 /*! 64 bit float = double. */ #define NIFTI_TYPE_FLOAT64 64 /*! 3 8 bit bytes. */ #define NIFTI_TYPE_RGB24 128 /*! signed char. */ #define NIFTI_TYPE_INT8 256 /*! unsigned short. */ #define NIFTI_TYPE_UINT16 512 /*! unsigned int. */ #define NIFTI_TYPE_UINT32 768 /*! signed long long. */ #define NIFTI_TYPE_INT64 1024 /*! unsigned long long. */ #define NIFTI_TYPE_UINT64 1280 /*! 128 bit float = long double. */ #define NIFTI_TYPE_FLOAT128 1536 /*! 128 bit complex = 2 64 bit floats. */ #define NIFTI_TYPE_COMPLEX128 1792 /*! 256 bit complex = 2 128 bit floats */ #define 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. */ #define 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 @{ */ #define NIFTI_INTENT_CORREL 2 /*! [C2, chap 28] Student t statistic (1 param): p1 = DOF. */ #define NIFTI_INTENT_TTEST 3 /*! [C2, chap 27] Fisher F statistic (2 params): p1 = numerator DOF, p2 = denominator DOF. */ #define NIFTI_INTENT_FTEST 4 /*! [C1, chap 13] Standard normal (0 params): Density = N(0,1). */ #define NIFTI_INTENT_ZSCORE 5 /*! [C1, chap 18] Chi-squared (1 param): p1 = DOF. Density(x) proportional to exp(-x/2) * x^(p1/2-1). */ #define 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). */ #define 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. */ #define 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). */ #define 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,.... */ #define NIFTI_INTENT_POISSON 10 /*! [C1, chap 13] Normal distribution (2 params): p1 = mean, p2 = standard deviation. */ #define NIFTI_INTENT_NORMAL 11 /*! [C2, chap 30] Noncentral F statistic (3 params): p1 = numerator DOF, p2 = denominator DOF, p3 = numerator noncentrality parameter. */ #define NIFTI_INTENT_FTEST_NONC 12 /*! [C2, chap 29] Noncentral chi-squared statistic (2 params): p1 = DOF, p2 = noncentrality parameter. */ #define 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)). */ #define NIFTI_INTENT_LOGISTIC 14 /*! [C2, chap 24] Laplace distribution (2 params): p1 = location, p2 = scale. Density(x) proportional to exp(-abs(x-p1)/p2). */ #define NIFTI_INTENT_LAPLACE 15 /*! [C2, chap 26] Uniform distribution: p1 = lower end, p2 = upper end. */ #define NIFTI_INTENT_UNIFORM 16 /*! [C2, chap 31] Noncentral t statistic (2 params): p1 = DOF, p2 = noncentrality parameter. */ #define 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. */ #define 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. */ #define 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. */ #define NIFTI_INTENT_INVGAUSS 20 /*! [C2, chap 22] Extreme value type I (2 params): p1 = location, p2 = scale cdf(x) = exp(-exp(-(x-p1)/p2)). */ #define NIFTI_INTENT_EXTVAL 21 /*! Data is a 'p-value' (no params). */ #define 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). */ #define 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). */ #define NIFTI_INTENT_LOG10PVAL 24 /*! Smallest intent_code that indicates a statistic. */ #define NIFTI_FIRST_STATCODE 2 /*! Largest intent_code that indicates a statistic. */ #define 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. */ #define 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. */ #define 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. */ #define 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] */ #define 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 */ #define 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) */ #define NIFTI_INTENT_DISPVECT 1006 /* specifically for displacements */ #define 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"). */ #define 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. */ #define 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 */ #define NIFTI_INTENT_QUATERNION 1010 /*! Dimensionless value - no params - although, as in _ESTIMATE the name of the parameter may be stored in intent_name. */ #define 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). */ #define NIFTI_XFORM_UNKNOWN 0 /*! Scanner-based anatomical coordinates */ #define NIFTI_XFORM_SCANNER_ANAT 1 /*! Coordinates aligned to another file's, or to anatomical "truth". */ #define NIFTI_XFORM_ALIGNED_ANAT 2 /*! Coordinates aligned to Talairach- Tournoux Atlas; (0,0,0)=AC, etc. */ #define NIFTI_XFORM_TALAIRACH 3 /*! MNI 152 normalized coordinates. */ #define 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. */ #define NIFTI_UNITS_UNKNOWN 0 /** Space codes are multiples of 1. **/ /*! NIFTI code for meters. */ #define NIFTI_UNITS_METER 1 /*! NIFTI code for millimeters. */ #define NIFTI_UNITS_MM 2 /*! NIFTI code for micrometers. */ #define NIFTI_UNITS_MICRON 3 /** Time codes are multiples of 8. **/ /*! NIFTI code for seconds. */ #define NIFTI_UNITS_SEC 8 /*! NIFTI code for milliseconds. */ #define NIFTI_UNITS_MSEC 16 /*! NIFTI code for microseconds. */ #define NIFTI_UNITS_USEC 24 /*** These units are for spectral data: ***/ /*! NIFTI code for Hertz. */ #define NIFTI_UNITS_HZ 32 /*! NIFTI code for ppm. */ #define NIFTI_UNITS_PPM 40 /*! NIFTI code for radians per second. */ #define 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 @{ */ #define NIFTI_SLICE_UNKNOWN 0 #define NIFTI_SLICE_SEQ_INC 1 #define NIFTI_SLICE_SEQ_DEC 2 #define NIFTI_SLICE_ALT_INC 3 #define NIFTI_SLICE_ALT_DEC 4 #define NIFTI_SLICE_ALT_INC2 5 /* 05 May 2005: RWCox */ #define 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_ */ caret-5.6.4~dfsg.1.orig/caret_files/minc_cpp.h0000664000175000017500000000223511572067322021004 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ /* * This header file is used for enclosing the MNC header file within * an extern "C" block since minc.h does not have this. */ #ifndef __MINC_CPP_H__ #define __MINC_CPP_H__ #ifdef __cplusplus extern "C" { #endif #include "minc.h" #ifdef __cplusplus } #endif #endif /* __MINC_CPP_H__ */ caret-5.6.4~dfsg.1.orig/caret_files/mayo_analyze.h0000664000175000017500000002370711572067322021713 0ustar michaelmichael#ifndef _RWC_ANALYZE_HEADER_ /*************************************************************************** From http://www.mayo.edu/bir/Analyze_Pages/AnalyzeFileInfo.html Describes the ANALYZE 7.5 file format (.img/.hdr pairs). ---------------------------------------------------------------- The image database is the system of files that the ANALYZE package uses to organize and access image data on the disk. Facilities are provided for converting data from a number of sources for use with the package. A description of the database format is provided to aid developers in porting images from other sources for use with the ANALYZE TM system. An ANALYZE image database consists of at least two files: * an image file * a header file The files have the same name being distinguished by the extensions .img for the image file and .hdr for the header file. Thus, for the image database heart, there are the UNIX files heart.img and heart.hdr. The ANALYZE programs all refer to this pair of files as a single entity named heart. Image File The format of the image file is very simple containing usually uncompressed pixel data for the images in one of several possible pixel formats: * 1 bit packed binary (slices must begin on byte boundaries) * 8 bit 8 bits per pixel (unsigned char) * 16 bit 16 bits per pixel (signed short) * 32 bit 32 bits per pixel signed integers, or floating point * 64 bit 64 bits per pixel; double precision, floating point, or complex. * 24 bit RGB , 8-bits per channel Red, Green, Blue. Header File The header file is represented here as a `C' structure which describes the dimensions and history of the pixel data. The header structure consists of three substructures: header_key describes the header image_dimension describes image sizes data_history optional ****************************************************************************/ /// analyze volume struct struct header_key /* header key */ { /* off + size */ int sizeof_hdr; /* 0 + 4 */ char data_type[10]; /* 4 + 10 */ char db_name[18]; /* 14 + 18 */ int extents; /* 32 + 4 */ short int session_error; /* 36 + 2 */ char regular; /* 38 + 1 */ char hkey_un0; /* 39 + 1 */ }; /* total=40 bytes */ /// analyze volume struct struct image_dimension { /* off + size */ short int dim[8]; /* 0 + 16 */ short int unused8; /* 16 + 2 */ short int unused9; /* 18 + 2 */ short int unused10; /* 20 + 2 */ short int unused11; /* 22 + 2 */ short int unused12; /* 24 + 2 */ short int unused13; /* 26 + 2 */ short int unused14; /* 28 + 2 */ short int datatype; /* 30 + 2 */ short int bitpix; /* 32 + 2 */ short int dim_un0; /* 34 + 2 */ float pixdim[8]; /* 36 + 32 */ /* pixdim[] specifies the voxel dimensitons: pixdim[1] - voxel width pixdim[2] - voxel height pixdim[3] - interslice distance ...etc */ float vox_offset; /* 68 + 4 */ float funused1; /* 72 + 4 */ float funused2; /* 76 + 4 */ float funused3; /* 80 + 4 */ float cal_max; /* 84 + 4 */ float cal_min; /* 88 + 4 */ float compressed; /* 92 + 4 */ float verified; /* 96 + 4 */ int glmax,glmin; /* 100 + 8 */ }; /* total=108 bytes */ /// analyze volume struct struct data_history { /* off + size */ char descrip[80]; /* 0 + 80 */ char aux_file[24]; /* 80 + 24 */ char orient; /* 104 + 1 */ char originator[10]; /* 105 + 10 */ char generated[10]; /* 115 + 10 */ char scannum[10]; /* 125 + 10 */ char patient_id[10]; /* 135 + 10 */ char exp_date[10]; /* 145 + 10 */ char exp_time[10]; /* 155 + 10 */ char hist_un0[3]; /* 165 + 3 */ int views; /* 168 + 4 */ int vols_added; /* 172 + 4 */ int start_field; /* 176 + 4 */ int field_skip; /* 180 + 4 */ int omax, omin; /* 184 + 8 */ int smax, smin; /* 192 + 8 */ }; /// analyze volume struct struct dsr { struct header_key hk; /* 0 + 40 */ struct image_dimension dime; /* 40 + 108 */ struct data_history hist; /* 148 + 200 */ }; /* total= 348 bytes*/ /* Acceptable values for datatype */ #define ANDT_NONE 0 #define ANDT_UNKNOWN 0 /* what it says, dude */ #define ANDT_BINARY 1 /* binary (1 bit/voxel) */ #define ANDT_UNSIGNED_CHAR 2 /* unsigned char (8 bits/voxel) */ #define ANDT_SIGNED_SHORT 4 /* signed short (16 bits/voxel) */ #define ANDT_SIGNED_INT 8 /* signed int (32 bits/voxel) */ #define ANDT_FLOAT 16 /* float (32 bits/voxel) */ #define ANDT_COMPLEX 32 /* complex (64 bits/voxel) */ #define ANDT_DOUBLE 64 /* double (64 bits/voxel) */ #define ANDT_RGB 128 /* RGB triple (24 bits/voxel) */ #define ANDT_ALL 255 #define ANDT_string(aa) \ ((aa)==ANDT_BINARY ? "binary" \ :(aa)==ANDT_UNSIGNED_CHAR ? "byte" \ :(aa)==ANDT_SIGNED_SHORT ? "short" \ :(aa)==ANDT_SIGNED_INT ? "int" \ :(aa)==ANDT_FLOAT ? "float" \ :(aa)==ANDT_COMPLEX ? "complex" \ :(aa)==ANDT_DOUBLE ? "double" \ :(aa)==ANDT_RGB ? "RGB" \ : "unknown" ) /*************************************************************************** The header format is flexible and can be extended for new user-defined data types. The essential structures of the header are the header_key and the image_dimension. The required elements in the header_key substructure are: int sizeof_header Must indicate the byte size of the header file. int extents Should be 16384, the image file is created as contiguous with a minimum extent size. char regular Must be `r' to indicate that all images and volumes are the same size. The image_dimension substructure describes the organization and size of the images. These elements enable the database to reference images by volume and slice number. Explanation of each element follows: short int dim[]; = array of the image dimensions dim[0] = Number of dimensions in database; usually 4 dim[1] = Image X dimension; number of pixels in an image row dim[2] = Image Y dimension; number of pixel rows in slice dim[3] = Volume Z dimension; number of slices in a volume dim[4] = Time points, number of volumes in database. char vox_units[4] = specifies the spatial units of measure for a voxel char cal_units[4] = specifies the name of the calibration unit short int datatype = datatype for this image set Acceptable values for datatype are one of the ANDT_* defines above short int bitpix = number of bits per pixel; 1, 8, 16, 32, 64 short int dim_un0 = unused float pixdim[] = Parallel array to dim[], giving real world measurements in mm and ms. pixdim[1] = voxel width in mm pixdim[2] = voxel height in mm pixdim[3] = slice thickness in mm float vox_offset = byte offset in the .img file at which voxels start. This value can be negative to specify that the absolute value is applied for every image in the file float cal_max, = specify the range of calibration values cal_min int glmax, glmin = The maximum and minimum pixel values for the entire database The data_history substructure is not required, but the orient field is used to indicate individual slice orientation and determines whether the Movie program will attempt to flip the images before displaying a movie sequence. orient = slice orientation for this dataset. 0 = transverse unflipped 1 = coronal unflipped 2 = sagittal unflipped 3 = transverse flipped 4 = coronal flipped 5 = sagittal flipped ****************************************************************************/ #endif /* _RWC_ANALYZE_HEADER_ */ caret-5.6.4~dfsg.1.orig/caret_files/caret_files.pro0000664000175000017500000001320511572067322022044 0ustar michaelmichael###################################################################### # Automatically generated by qmake (1.04a) Wed Jan 15 08:39:18 2003 ###################################################################### TARGET = CaretFiles !vs:TEMPLATE = lib vs:TEMPLATE=vclib CONFIG += staticlib INCLUDEPATH += . dll { CONFIG -= staticlib CONFIG += plugin } include(../caret_qmake_include.pro) # Input HEADERS += AbstractFile.h \ AfniHeader.h \ AreaColorFile.h \ ArealEstimationFile.h \ AtlasSpaceFile.h \ AtlasSurfaceDirectoryFile.h \ BorderColorFile.h \ BorderFile.h \ BorderProjectionFile.h \ BrainVoyagerFile.h \ ByteSwapping.h \ Caret6ProjectedItem.h \ CaretScriptFile.h \ CellClass.h \ CellColorFile.h \ CellFile.h \ CellProjectionFile.h \ CellStudyInfo.h \ CocomacConnectivityFile.h \ CommaSeparatedValueFile.h \ ContourCellColorFile.h \ ContourCellFile.h \ ContourFile.h \ ColorFile.h \ CoordinateFile.h \ CutsFile.h \ DeformationFieldFile.h \ DeformationMapFile.h \ FileException.h \ FileFilters.h \ FociColorFile.h \ FociFile.h \ FociProjectionFile.h \ FociSearchFile.h \ FreeSurferCurvatureFile.h \ FreeSurferFunctionalFile.h \ FreeSurferLabelFile.h \ FreeSurferSurfaceFile.h \ GenericXmlFile.h \ GeodesicDistanceFile.h \ GeodesicHelper.h \ GiftiCommon.h \ GiftiDataArray.h \ GiftiDataArrayFile.h \ GiftiDataArrayFileSaxReader.h \ GiftiDataArrayFileStreamReader.h \ GiftiLabelTable.h \ GiftiMatrix.h \ GiftiMetaData.h \ GiftiNodeDataFile.h \ ImageFile.h \ LatLonFile.h \ MDPlotFile.h \ MetricFile.h \ MniObjSurfaceFile.h \ MultiResMorphFile.h \ NeurolucidaFile.h \ NiftiCaretExtension.h \ NiftiFileHeader.h \ NodeAttributeFile.h \ NodeRegionOfInterestFile.h \ PaintFile.h \ PaletteFile.h \ ParamsFile.h \ PreferencesFile.h \ ProbabilisticAtlasFile.h \ PubMedArticleFile.h \ RgbPaintFile.h \ SceneFile.h \ SectionFile.h \ SegmentationMaskListFile.h \ SpecFile.h \ SpecFileUtilities.h \ StudyCollectionFile.h \ StudyMetaDataFile.h \ StudyMetaDataLink.h \ StudyMetaDataLinkSet.h \ StudyNamePubMedID.h \ SumsFileListFile.h \ SureFitVectorFile.h \ SurfaceFile.h \ SurfaceShapeFile.h \ TextFile.h \ TopographyFile.h \ TopologyFile.h \ TopologyHelper.h \ TopologyNode.h \ TransformationMatrixFile.h \ VectorFile.h \ VocabularyFile.h \ VolumeFile.h \ VolumeITKImage.h \ VolumeModification.h \ VtkModelFile.h \ WuNilHeader.h \ WustlRegionFile.h \ XhtmlTableExtractorFile.h \ XmlGenericWriter.h \ XmlGenericWriterAttributes.h \ minc_cpp.h \ GiftiDataArrayReadListener.h \ nifti1.h \ mayo_analyze.h SOURCES += AbstractFile.cxx \ AfniHeader.cxx \ AreaColorFile.cxx \ ArealEstimationFile.cxx \ AtlasSpaceFile.cxx \ AtlasSurfaceDirectoryFile.cxx \ BorderColorFile.cxx \ BorderFile.cxx \ BorderProjectionFile.cxx \ BrainVoyagerFile.cxx \ ByteSwapping.cxx \ Caret6ProjectedItem.cxx \ CaretScriptFile.cxx \ CellBase.cxx \ CellColorFile.cxx \ CellFile.cxx \ CellProjectionFile.cxx \ CellStudyInfo.cxx \ CocomacConnectivityFile.cxx \ ColorFile.cxx \ CommaSeparatedValueFile.cxx \ ContourCellColorFile.cxx \ ContourCellFile.cxx \ ContourFile.cxx \ CoordinateFile.cxx \ CutsFile.cxx \ DeformationFieldFile.cxx \ DeformationMapFile.cxx \ FileException.cxx \ FileFilters.cxx \ FociColorFile.cxx \ FociFile.cxx \ FociProjectionFile.cxx \ FociSearchFile.cxx \ FreeSurferCurvatureFile.cxx \ FreeSurferFunctionalFile.cxx \ FreeSurferLabelFile.cxx \ FreeSurferSurfaceFile.cxx \ GenericXmlFile.cxx \ GeodesicDistanceFile.cxx \ GeodesicHelper.cxx \ GiftiCommon.cxx \ GiftiDataArray.cxx \ GiftiDataArrayFile.cxx \ GiftiDataArrayFileSaxReader.cxx \ GiftiDataArrayFileStreamReader.cxx \ GiftiLabelTable.cxx \ GiftiMatrix.cxx \ GiftiMetaData.cxx \ GiftiNodeDataFile.cxx \ ImageFile.cxx \ LatLonFile.cxx \ MDPlotFile.cxx \ MetricFile.cxx \ MniObjSurfaceFile.cxx \ MultiResMorphFile.cxx \ NeurolucidaFile.cxx \ NiftiCaretExtension.cxx \ NiftiFileHeader.cxx \ NodeAttributeFile.cxx \ NodeRegionOfInterestFile.cxx \ PaintFile.cxx \ PaletteFile.cxx \ ParamsFile.cxx \ PreferencesFile.cxx \ ProbabilisticAtlasFile.cxx \ PubMedArticleFile.cxx \ RgbPaintFile.cxx \ SceneFile.cxx \ SectionFile.cxx \ SegmentationMaskListFile.cxx \ SpecFile.cxx \ SpecFileUtilities.cxx \ StudyCollectionFile.cxx \ StudyMetaDataFile.cxx \ StudyMetaDataLink.cxx \ StudyMetaDataLinkSet.cxx \ StudyNamePubMedID.cxx \ SumsFileListFile.cxx \ SureFitVectorFile.cxx \ SurfaceFile.cxx \ SurfaceShapeFile.cxx \ TextFile.cxx \ TopographyFile.cxx \ TopologyFile.cxx \ TopologyHelper.cxx \ TransformationMatrixFile.cxx \ VectorFile.cxx \ VocabularyFile.cxx \ VolumeFile.cxx \ VolumeITKImage.cxx \ VolumeModification.cxx \ VtkModelFile.cxx \ WuNilHeader.cxx \ WustlRegionFile.cxx \ XhtmlTableExtractorFile.cxx \ XmlGenericWriter.cxx caret-5.6.4~dfsg.1.orig/caret_files/XmlGenericWriterAttributes.h0000664000175000017500000000603311572067322024515 0ustar michaelmichael/* * File: XmlGenericWriterAttributes.h * Author: john * * Created on November 6, 2009, 10:48 AM */ #ifndef __XML_GENERIC_WRITER_ATTRIBUTES_H__ #define __XML_GENERIC_WRITER_ATTRIBUTES_H__ #include #include /** * Maintains attribute for XML Generic Writer. */ class XmlGenericWriterAttributes { public: /** * Constructor. */ XmlGenericWriterAttributes() { this->clear(); } /** * Clear the attributes. */ void clear() { this->names.clear(); this->values.clear(); } /** * Add an attribute. * * @param name - Name of attribute. * @param value - Value of attribute. */ void addAttribute(QString name, QString value) { names.append(name); values.append(value); } /** * Add an attribute. * * @param name - Name of attribute. * @param value - Value of attribute. */ void addAttribute(QString name, char value) { names.append(name); values.append(QString::number(value)); } /** * Add an attribute. * * @param name - Name of attribute. * @param value - Value of attribute. */ void addAttribute(QString name, short value) { names.append(name); values.append(QString::number(value)); } /** * Add an attribute. * * @param name - Name of attribute. * @param value - Value of attribute. */ void addAttribute(QString name, int value) { names.append(name); values.append(QString::number(value)); } /** * Add an attribute. * * @param name - Name of attribute. * @param value - Value of attribute. */ void addAttribute(QString name, long value) { names.append(name); values.append(QString::number(value)); } /** * Add an attribute. * * @param name - Name of attribute. * @param value - Value of attribute. */ void addAttribute(QString name, float value) { names.append(name); values.append(QString::number(value, 'f')); } /** * Add an attribute. * * @param name - Name of attribute. * @param value - Value of attribute. */ void addAttribute(QString name, double value) { names.append(name); values.append(QString::number(value, 'f')); } /** * Get the number of attributes. * * @return Number of attributes. */ int getNumberOfAttributes() { return this->names.size(); } /** * Get the name of an attribute. * * @param index - index of attribute. * * @return Name of attribute at index. */ QString getAttributeName(int index) { return this->names.at(index); } /** * Get the value of an attribute. * * @param index - index of attribute. * * @return Value of attribute at index. */ QString getAttributeValue(int index) { return this->values.at(index); } private: /** attribute names. */ QVector names; /** attribute values. */ QVector values; }; #endif /* __XML_GENERIC_WRITER_ATTRIBUTES_H__ */ caret-5.6.4~dfsg.1.orig/caret_files/XmlGenericWriter.h0000664000175000017500000001743111572067322022452 0ustar michaelmichael/* * File: XmlGenericWriter.h * Author: john * * Created on November 6, 2009, 10:22 AM */ #ifndef __XML_GENERIC_WRITER_H__ #define __XML_GENERIC_WRITER_H__ #include #include #include "FileException.h" #include "XmlGenericWriterAttributes.h" class QTextStream; class XmlGenericWriterAttributes; /** * Writes XML to a writer with indentation (pretty printing). * Similar to StAX. */ class XmlGenericWriter { public: /** * Constructor. * * @param writer - Writer to which XML is written. */ XmlGenericWriter(QTextStream& writerIn); /** * Write the XML Start Document. * * @param xmlVersion - Version number, eg: "1.0". * @throws IOException if an I/O error occurs. */ void writeStartDocument(QString xmlVersion) throw (FileException); /** * Writes a start tag to the output. * * @param localName - local name of tag to write. * @throws IOException if an I/O error occurs. */ //void writeStartDocument(const char* localName) throw(FileException) { // QString ln = localName; // this->writeStartDocument(ln); //} /** * Write the XML Start document. * * @throws IOException if an I/O error occurs. */ void writeStartDocument() throw (FileException); /** * Write a DTD section. * * @param rootTag - the root tag of the XML document. * @param dtdURL - URL of DTD. * @throws IOException if an I/O error occurs. */ void writeDTD(QString rootTag, QString dtdURL) throw(FileException); /** * Closes any start tags and writes corresponding end tags. * @throws IOException if an I/O error occurs. */ void writeEndDocument() throw(FileException); /** * Write an element on one line. * * @param localName - local name of tag to write. * @param text - text to write. * @throws IOException if an I/O error occurs. */ void writeElementCharacters(const QString localName, const float f); /** * Write an element on one line. * * @param localName - local name of tag to write. * @param text - text to write. * @throws IOException if an I/O error occurs. */ void writeElementCharacters(const QString localName, const float* values, const int num); /** * Write an element on one line. * * @param localName - local name of tag to write. * @param text - text to write. * @throws IOException if an I/O error occurs. */ void writeElementCharacters(const QString localName, const int value); /** * Write an element on one line. * * @param localName - local name of tag to write. * @param text - text to write. * @throws IOException if an I/O error occurs. */ void writeElementCharacters(const QString localName, const int* values, const int num); /** * Write an element on one line. * * @param localName - local name of tag to write. * @param text - text to write. * @throws IOException if an I/O error occurs. */ //void writeElementCharacters(const char* localName, const char* text) { // this->writeElementCharacters(localName, text); //} /** * Write an element on one line. * * @param localName - local name of tag to write. * @param text - text to write. * @throws IOException if an I/O error occurs. */ void writeElementCharacters(QString localName, QString text) throw(FileException); /** * Write an element on one line. * * @param localName - local name of tag to write. * @param text - text to write. * @throws IOException if an I/O error occurs. */ //void writeElementCharacters(const char* localName, QString text) // throw(FileException) { // QString ln = localName; // this->writeElementCharacters(ln, text); //} /** * Write an element on one line. * * @param localName - local name of tag to write. * @param text - text to write. * @throws IOException if an I/O error occurs. */ //void writeElementCData(const char* localName, const char* text) { // this->writeElementCData(localName, text); //} /** * Write an element on one line. * * @param localName - local name of tag to write. * @param text - text to write. * @throws IOException if an I/O error occurs. */ //void writeElementCData(const char* localName, QString text) { // this->writeElementCData(localName, text); //} /** * Write a CData section on one line. * * @param localName - local name of tag to write. * @param text - text to write. * @throws IOException if an I/O error occurs. */ void writeElementCData(QString localName, QString text) throw(FileException); /** * Write a CData section on one line with attributes. * * @param localName - local name of tag to write. * @param attributes - attribute for element. * @param text - text to write. * @throws IOException if an I/O error occurs. */ void writeElementCData(QString localName, XmlGenericWriterAttributes& attributes, QString text) throw(FileException); /** * Write an element with no spacing between start and end tags. * * @param localName - local name of tag to write. * @param text - text to write. * @throws IOException if an I/O error occurs. */ void writeElementNoSpace(QString localName, QString text) throw(FileException); /** * Writes a start tag to the output. * * @param localName - local name of tag to write. * @throws IOException if an I/O error occurs. */ //void writeStartElement(const char* localName) throw(FileException) { // QString ln = localName; // this->writeStartElement(ln); //} /** * Writes a start tag to the output. * * @param localName - local name of tag to write. * @throws IOException if an I/O error occurs. */ void writeStartElement(QString localName) throw(FileException); /** * Writes a start tag to the output. * * @param localName - local name of tag to write. * @param attributes - attributes for start tag * @throws IOException if an I/O error occurs. */ void writeStartElement(QString localName, XmlGenericWriterAttributes& attributes) throw(FileException); /** * Writes an end tag to the output. * * @throws IOException if an I/O error occurs */ void writeEndElement() throw(FileException); /** * Writes a CData section. * * @param data - data to write. * @throws IOException if an I/O error occurs. */ void writeCData(QString data) throw(FileException); /** * Writes text to the output. * * @param text - text to write. * @throws IOException if an I/O error occurs. */ void writeCharacters(QString text) throw(FileException); /** * Writes text with indentation to the output. * * @param text - text to write. * @throws IOException if an I/O error occurs. */ void writeCharactersWithIndent(QString text) throw(FileException); void setNumberOfDecimalPlaces(int decimals); private: /** * Write indentation spaces. * * @throws IOException if an I/O error occurs. */ void writeIndentation() throw(FileException); /** The writer to which XML is written */ QTextStream& writer; /** The indentation amount for new element tags. */ int indentationSpaces; /** The element stack used for closing elements. */ QStack elementStack; int numberOfDecimalPlaces; }; #endif /* __XML_GENERIC_WRITER_H__ */ caret-5.6.4~dfsg.1.orig/caret_files/XmlGenericWriter.cxx0000664000175000017500000002566411572067322023034 0ustar michaelmichael#include #include #include #include "StringUtilities.h" #include "XmlGenericWriter.h" /** * Constructor. * * @param writer - Writer to which XML is written. */ XmlGenericWriter::XmlGenericWriter(QTextStream& writerIn) : writer(writerIn) { indentationSpaces = 0; this->numberOfDecimalPlaces = 6; StringUtilities::setFloatDigitsRightOfDecimal(this->numberOfDecimalPlaces); } /** * Write the XML Start Document. * * @param xmlVersion - Version number, eg: "1.0". * @throws IOException if an I/O error occurs. */ void XmlGenericWriter::writeStartDocument(QString xmlVersion) throw (FileException) { writer << ("\n" ""); } /** * Writes a start tag to the output. * * @param localName - local name of tag to write. * @throws IOException if an I/O error occurs. */ //void writeStartDocument(const char* localName) throw(FileException) { // QString ln = localName; // this->writeStartDocument(ln); //} /** * Write the XML Start document. * * @throws IOException if an I/O error occurs. */ void XmlGenericWriter::writeStartDocument() throw (FileException) { this->writeStartDocument("1.0"); } /** * Write a DTD section. * * @param rootTag - the root tag of the XML document. * @param dtdURL - URL of DTD. * @throws IOException if an I/O error occurs. */ void XmlGenericWriter::writeDTD(QString rootTag, QString dtdURL) throw(FileException) { writer << ("\n"); } /** * Closes any start tags and writes corresponding end tags. * @throws IOException if an I/O error occurs. */ void XmlGenericWriter::writeEndDocument() throw(FileException) { while (this->elementStack.empty() == false) { writeEndElement(); } writer.flush(); } /** * Write an element on one line. * * @param localName - local name of tag to write. * @param text - text to write. * @throws IOException if an I/O error occurs. */ void XmlGenericWriter::writeElementCharacters(const QString localName, const float f) { QString text = StringUtilities::fromNumber(f); //QString::number(f, 'f', this->numberOfDecimalPlaces); this->writeElementCharacters(localName, text); } /** * Write an element on one line. * * @param localName - local name of tag to write. * @param text - text to write. * @throws IOException if an I/O error occurs. */ void XmlGenericWriter::writeElementCharacters(const QString localName, const float* values, const int num) { QStringList sl; for (int i = 0; i < num; i++) { sl << StringUtilities::fromNumber(values[i]); //QString::number(values[i], 'f', this->numberOfDecimalPlaces); } this->writeElementCharacters(localName, sl.join(" ")); } /** * Write an element on one line. * * @param localName - local name of tag to write. * @param text - text to write. * @throws IOException if an I/O error occurs. */ void XmlGenericWriter::writeElementCharacters(const QString localName, const int value) { QString text = QString::number(value); this->writeElementCharacters(localName, text); } /** * Write an element on one line. * * @param localName - local name of tag to write. * @param text - text to write. * @throws IOException if an I/O error occurs. */ void XmlGenericWriter::writeElementCharacters(const QString localName, const int* values, const int num) { QStringList sl; for (int i = 0; i < num; i++) { sl << QString::number(values[i]); } this->writeElementCharacters(localName, sl.join(" ")); } /** * Write an element on one line. * * @param localName - local name of tag to write. * @param text - text to write. * @throws IOException if an I/O error occurs. */ //void writeElementCharacters(const char* localName, const char* text) { // this->writeElementCharacters(localName, text); //} /** * Write an element on one line. * * @param localName - local name of tag to write. * @param text - text to write. * @throws IOException if an I/O error occurs. */ void XmlGenericWriter::writeElementCharacters(QString localName, QString text) throw(FileException) { this->writeIndentation(); writer << ("<" + localName + ">"); this->writeCharacters(text); writer << ("\n"); } /** * Write an element on one line. * * @param localName - local name of tag to write. * @param text - text to write. * @throws IOException if an I/O error occurs. */ //void writeElementCharacters(const char* localName, QString text) // throw(FileException) { // QString ln = localName; // this->writeElementCharacters(ln, text); //} /** * Write an element on one line. * * @param localName - local name of tag to write. * @param text - text to write. * @throws IOException if an I/O error occurs. */ //void writeElementCData(const char* localName, const char* text) { // this->writeElementCData(localName, text); //} /** * Write an element on one line. * * @param localName - local name of tag to write. * @param text - text to write. * @throws IOException if an I/O error occurs. */ //void writeElementCData(const char* localName, QString text) { // this->writeElementCData(localName, text); //} /** * Write a CData section on one line. * * @param localName - local name of tag to write. * @param text - text to write. * @throws IOException if an I/O error occurs. */ void XmlGenericWriter::writeElementCData(QString localName, QString text) throw(FileException) { this->writeIndentation(); writer << ("<" + localName + ">"); this->writeCData(text); writer << ("\n"); } /** * Write a CData section on one line with attributes. * * @param localName - local name of tag to write. * @param attributes - attribute for element. * @param text - text to write. * @throws IOException if an I/O error occurs. */ void XmlGenericWriter::writeElementCData(QString localName, XmlGenericWriterAttributes& attributes, QString text) throw(FileException) { this->writeIndentation(); writer << ("<" + localName); int numAtts = attributes.getNumberOfAttributes(); for (int i = 0; i < numAtts; i++) { writer << (" " + attributes.getAttributeName(i) + "=\"" + attributes.getAttributeValue(i) + "\""); } writer << (">"); this->writeCData(text); writer << ("\n"); } /** * Write an element with no spacing between start and end tags. * * @param localName - local name of tag to write. * @param text - text to write. * @throws IOException if an I/O error occurs. */ void XmlGenericWriter::writeElementNoSpace(QString localName, QString text) throw(FileException) { this->writeIndentation(); writer << ("<" + localName + ">"); writer << (text); writer << ("\n"); } /** * Writes a start tag to the output. * * @param localName - local name of tag to write. * @throws IOException if an I/O error occurs. */ //void writeStartElement(const char* localName) throw(FileException) { // QString ln = localName; // this->writeStartElement(ln); //} /** * Writes a start tag to the output. * * @param localName - local name of tag to write. * @throws IOException if an I/O error occurs. */ void XmlGenericWriter::writeStartElement(QString localName) throw(FileException) { this->writeIndentation(); writer << ("<" + localName + ">\n"); this->indentationSpaces++; this->elementStack.push(localName); } /** * Writes a start tag to the output. * * @param localName - local name of tag to write. * @param attributes - attributes for start tag * @throws IOException if an I/O error occurs. */ void XmlGenericWriter::writeStartElement(QString localName, XmlGenericWriterAttributes& attributes) throw(FileException) { this->writeIndentation(); writer << ("<" + localName + " "); int attIndentSpaces = localName.length() + 2; QString attIndentString(attIndentSpaces, ' '); int numAtts = attributes.getNumberOfAttributes(); for (int i = 0; i < numAtts; i++) { if (i > 0) { this->writeIndentation(); writer << (attIndentString); } writer << (attributes.getAttributeName(i) + "=\"" + attributes.getAttributeValue(i) + "\""); if (i < (numAtts - 1)) { writer << ("\n"); } } writer << (">\n"); this->indentationSpaces++; this->elementStack.push(localName); } /** * Writes an end tag to the output. * * @throws IOException if an I/O error occurs */ void XmlGenericWriter::writeEndElement() throw(FileException) { if (this->elementStack.empty()) { throw FileException("Unbalanced start/end element calls."); } QString localName = this->elementStack.pop(); this->indentationSpaces--; this->writeIndentation(); writer << ("\n"); } /** * Writes a CData section. * * @param data - data to write. * @throws IOException if an I/O error occurs. */ void XmlGenericWriter::writeCData(QString data) throw(FileException) { writer << "writeCharacters(data); writer << "]]>"; } /** * Writes text to the output. Avoids unprintable characters which cause * problems with some XML parsers. * * @param text - text to write. * @throws IOException if an I/O error occurs. */ void XmlGenericWriter::writeCharacters(QString text) throw(FileException) { const ushort CARRIAGE_RETURN = 13; const ushort LINE_FEED = 10; const ushort TAB = 9; int num = text.length(); for (int i = 0; i < num; i++) { QChar c = text[i]; ushort u = c.unicode(); bool printIt = true; //c.isPrint(); if (u < 32) { printIt = false; if ((u == CARRIAGE_RETURN) || (u == LINE_FEED) || (u == TAB)) { printIt = true; } } if (printIt) { writer << c; } else { std::cout << "Unicode value of character not written: " << u << std::endl; } } //writer << (text); } /** * Writes text with indentation to the output. * * @param text - text to write. * @throws IOException if an I/O error occurs. */ void XmlGenericWriter::writeCharactersWithIndent(QString text) throw(FileException) { this->writeIndentation(); writer << (text); } void XmlGenericWriter::setNumberOfDecimalPlaces(int decimals) { this->numberOfDecimalPlaces = decimals; } /** * Write indentation spaces. * * @throws IOException if an I/O error occurs. */ void XmlGenericWriter::writeIndentation() throw(FileException) { if (this->indentationSpaces > 0) { QString sb(indentationSpaces * 3, ' '); writer << (sb); } } caret-5.6.4~dfsg.1.orig/caret_files/XhtmlTableExtractorFile.h0000664000175000017500000001421411572067322023754 0ustar michaelmichael#ifndef __XHTML_TABLE_EXTRACTOR_FILE_H__ #define __XHTML_TABLE_EXTRACTOR_FILE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "AbstractFile.h" /// file for extracting tables from XHTML files class XhtmlTableExtractorFile : public AbstractFile { public: // stores a row from a table class TableRow { public: // constructor TableRow(); // destructor ~TableRow(); // add an element to the row void addElement(const QString& s, const int colSpan = 1); // insert an element void insertElement(const int position, const QString& value); // get the number of elements int getNumberOfElements() const; // get an element QString getElement(const int indx) const; protected: /// the elements std::vector elements; }; // class for handling row span class TableRowSpan { public: // constructor TableRowSpan(const int rowStartIn, const int numRowsIn, const int colStartIn, const int numColsIn); // destructor ~TableRowSpan(); /// starting row for rowspan int rowStart; /// last row for rowspan int rowEnd; /// starting column for rowspan int colStart; /// ending column for rowspan int colEnd; }; // stores a group of TableRows class Table { public: // constructor Table(); // destructor ~Table(); // add a row to the table void addRow(TableRow* tableRow); // add a row span to the table void addRowSpan(const TableRowSpan& rowSpan); // finish the table (handle row spans) void finishTable(); // get the dimensions of the table void getTableDimensions(int& numRows, int& numCols) const; // get the number of rows in the table int getNumberOfRows() const; // get a row from the table TableRow* getRow(const int indx); // get a row from the table (const method) const TableRow* getRow(const int indx) const; // get the newest row TableRow* getNewestRow(); protected: /// the rows std::vector rows; /// row span storage std::vector rowSpans; }; // constructor XhtmlTableExtractorFile(); // destructor ~XhtmlTableExtractorFile(); // call AbstractFile::clearAbstractFile() from its clear method. void clear(); // returns true if the file is isEmpty (contains no data) bool empty() const; // get the number of tables int getNumberOfTables() const; // get a table Table* getTable(const int indx); // get a table const Table* getTable(const int indx) const; // find out if comma separated file conversion supported void getCommaSeparatedFileSupport(bool& readFromCSV, bool& writeToCSV) const; // write the file's data into a comma separated values file (throws exception if not supported) void writeDataIntoCommaSeparatedValueFile(CommaSeparatedValueFile& csv) throw (FileException); protected: // Read the contents of the file (header has already been read) void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& rootElement) throw (FileException); // Write the file's data (header has already been written) void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& xmlDoc, QDomElement& rootElement) throw (FileException); // read an XHTML format file void readXHTML(QDomElement& elementIn) throw (FileException); // read an Html Table void readHtmlTable(QDomElement& elementIn) throw (FileException); // read an Html Table Row void readHtmlTableRow(QDomElement& elementIn) throw (FileException); // read an Html Table Data void readHtmlTableData(QDomElement& elementIn) throw (FileException); // Recursively get the contents of a table data node void tableDataToText(QDomNode node, const bool doSiblingsFlag, QString& text); // clear the tables read void clearTables(); /// tables std::vector tables; /// active table stack used to assist with file reading std::stack activeTableStack; /// active table used to assist with file reading Table* activeTable; }; #endif // __XHTML_TABLE_EXTRACTOR_FILE_H__ caret-5.6.4~dfsg.1.orig/caret_files/XhtmlTableExtractorFile.cxx0000664000175000017500000004306311572067322024333 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include "CommaSeparatedValueFile.h" #include "DebugControl.h" #include "SpecFile.h" #include "StringTable.h" #include "XhtmlTableExtractorFile.h" /** * constructor. */ XhtmlTableExtractorFile::XhtmlTableExtractorFile() : AbstractFile("XHTML Table Extractor File", // description SpecFile::getXmlFileExtension(), // default extension true, // has header FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE, // default write type FILE_IO_NONE, // ascii support FILE_IO_NONE, // binary support FILE_IO_READ_ONLY, // XML support FILE_IO_NONE, // XML Base64 support FILE_IO_NONE, // XML GZip Base64 support FILE_IO_NONE, // other support FILE_IO_WRITE_ONLY) // CSV support { // // XHTML table file root is always "html" // rootXmlElementTagName = "html"; } /** * destructor. */ XhtmlTableExtractorFile::~XhtmlTableExtractorFile() { } /** * call AbstractFile::clearAbstractFile() from its clear method. */ void XhtmlTableExtractorFile::clear() { clearAbstractFile(); clearTables(); } /** * returns true if the file is isEmpty (contains no data). */ bool XhtmlTableExtractorFile::empty() const { return true; } /** * find out if comma separated file conversion supported. */ void XhtmlTableExtractorFile::getCommaSeparatedFileSupport(bool& readFromCSV, bool& writeToCSV) const { readFromCSV = false; writeToCSV = true; } /** * write the file's data into a comma separated values file (throws exception if not supported). */ void XhtmlTableExtractorFile::writeDataIntoCommaSeparatedValueFile(CommaSeparatedValueFile& csv) throw (FileException) { csv.clear(); const int numTables = getNumberOfTables(); for (int i = 0; i < numTables; i++) { const Table* table = getTable(i); int numRows, numCols; table->getTableDimensions(numRows, numCols); if ((numRows > 0) && (numCols > 0)) { StringTable* st = new StringTable(numRows, numCols); for (int j = 0; j < numRows; j++) { const TableRow* tr = table->getRow(j); const int numElem = tr->getNumberOfElements(); for (int k = 0; k < numElem; k++) { st->setElement(j, k, tr->getElement(k).trimmed()); } } csv.addDataSection(st); } } } /** * read an Html Table element ("table") */ void XhtmlTableExtractorFile::readHtmlTable(QDomElement& elementIn) throw (FileException) { // // Create a new table and make it the active table // activeTable = new Table; activeTableStack.push(activeTable); // // Process children // QDomNode node = elementIn.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { readXHTML(elem); } node = node.nextSibling(); } // // Done with table // activeTable = NULL; if (activeTableStack.empty() == false) { activeTable = activeTableStack.top(); activeTableStack.pop(); tables.push_back(activeTable); } } /** * read an Html Table Row element ("tr") */ void XhtmlTableExtractorFile::readHtmlTableRow(QDomElement& elementIn) throw (FileException) { if (activeTable == NULL) { throw FileException("XhtmlTableExtractorFile read error: have a table row but there is not an active table."); } // // Create a new row in the table // TableRow* row = new TableRow; activeTable->addRow(row); // // Process children // QDomNode node = elementIn.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { readXHTML(elem); } node = node.nextSibling(); } } /** * Recursively get the contents of an HTML "td" element by creating a * string from the "leaves" of this element's children */ void XhtmlTableExtractorFile::tableDataToText(QDomNode node, const bool doSiblingsFlag, QString& text) { while (node.isNull() == false) { // // Does this element have children?? // if (node.hasChildNodes()) { // // process its children // tableDataToText(node.firstChild(), true, text); } else { // // Since this elemenet does not have children, it is a leaf // Get its text // bool addNodeValue = true; QDomElement elem = node.toElement(); if (elem.isNull() == false) { // // Journal of Neuroscience uses an image for minus signs // If found, convert it to a minus sign // if (DebugControl::getDebugOn()) { std::cout << "ELEM TAGNAME: " << elem.tagName().toAscii().constData() << std::endl; } if (elem.tagName().toLower() == "img") { if (elem.attribute("src").contains("minus.gif")) { text += "-"; addNodeValue = false; } } } if (addNodeValue) { // // add on to the text string // text += node.nodeValue(); } } // // Process siblings // if (doSiblingsFlag) { node = node.nextSibling(); } else { return; } } } /** * read an Html Table Data (an HTML "td" element) */ void XhtmlTableExtractorFile::readHtmlTableData(QDomElement& elementIn) throw (FileException) { if (activeTable == NULL) { throw FileException("XhtmlTableExtractorFile read error: have a table data but there is not an active table."); } TableRow* tableRow = activeTable->getNewestRow(); if (tableRow == NULL) { throw FileException("XhtmlTableExtractorFile read error: have table data but no newest row"); } // // See if any children are a table // bool haveTableChild = false; QDomNode node = elementIn.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (elem.tagName().toLower() == "table") { haveTableChild = true; break; } } node = node.nextSibling(); } // // Nested tables ? // if (haveTableChild) { QDomNode node = elementIn.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { readXHTML(elem); } node = node.nextSibling(); } } else { // // Look for rowspan and colspan // const int rowspan = elementIn.attribute("rowspan", "0").toInt(); const int colspan = elementIn.attribute("colspan", "1").toInt(); if (rowspan > 1) { TableRowSpan trs(activeTable->getNumberOfRows(), rowspan - 1, tableRow->getNumberOfElements(), colspan); activeTable->addRowSpan(trs); } // // Create a string from all of this table data's "leaves" // QString s; tableDataToText(elementIn, false, s); if (DebugControl::getDebugOn()) { std::cout << "NodeTraversed: " << s.toAscii().constData() << std::endl; } // // Replace newlines and line feeds with a blank // s = s.replace('\n', " "); s = s.replace('\r', " "); // // Add to the table // tableRow->addElement(s, colspan); } } /** * read an XHTML format file. */ void XhtmlTableExtractorFile::readXHTML(QDomElement& elementIn) throw (FileException) { const QString tagName = elementIn.tagName().toLower(); if (tagName == "table") { readHtmlTable(elementIn); } else if (tagName == "tr") { readHtmlTableRow(elementIn); } else if ((tagName == "td") || (tagName == "th")) { readHtmlTableData(elementIn); } else { QDomNode node = elementIn.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { readXHTML(elem); } node = node.nextSibling(); } } } /** * clear the tables read. */ void XhtmlTableExtractorFile::clearTables() { const int numTables = getNumberOfTables(); for (int i = 0; i < numTables; i++) { delete tables[i]; tables[i] = NULL; } tables.clear(); } /** * get the number of tables. */ int XhtmlTableExtractorFile::getNumberOfTables() const { return tables.size(); } /** * get a table. */ XhtmlTableExtractorFile::Table* XhtmlTableExtractorFile::getTable(const int indx) { return tables[indx]; } /** * get a table. */ const XhtmlTableExtractorFile::Table* XhtmlTableExtractorFile::getTable(const int indx) const { return tables[indx]; } /** * Read the contents of the file (header has already been read). */ void XhtmlTableExtractorFile::readFileData(QFile& /*file*/, QTextStream& /*stream*/, QDataStream& /*binStream*/, QDomElement& rootElement) throw (FileException) { activeTable = NULL; clearTables(); switch (getFileReadType()) { case FILE_FORMAT_ASCII: throw FileException(filename, "Reading in Ascii format not supported."); break; case FILE_FORMAT_BINARY: throw FileException(filename, "Reading in Binary format not supported."); break; case FILE_FORMAT_XML: readXHTML(rootElement); for (int i = 0; i < static_cast(tables.size()); i++) { tables[i]->finishTable(); } break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "Reading XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "Reading XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Reading XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Reading in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Reading in Comma Separated Value File format not supported."); break; } if (activeTableStack.empty() == false) { std::cout << "Program Error: Active table stack is not empty after reading XhtmlTableExtractorFile" << std::endl; } } /** * Write the file's data (header has already been written). */ void XhtmlTableExtractorFile::writeFileData(QTextStream& stream, QDataStream& /*binStream*/, QDomDocument& /*xmlDoc*/, QDomElement& /*rootElement*/) throw (FileException) { switch (getFileWriteType()) { case FILE_FORMAT_ASCII: throw FileException(filename, "Writing in Ascii format not supported."); break; case FILE_FORMAT_BINARY: throw FileException(filename, "Writing in Binary format not supported."); break; case FILE_FORMAT_XML: throw FileException(filename, "Writing XML not supported."); break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "Writing XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "Writing XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Writing XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Writing in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: { CommaSeparatedValueFile csvf; writeDataIntoCommaSeparatedValueFile(csvf); csvf.writeToTextStream(stream); } break; } } //==================================================================================== // TableRow Class //==================================================================================== /** * constructor. */ XhtmlTableExtractorFile::Table::Table() { } /** * destructor. */ XhtmlTableExtractorFile::Table::~Table() { const int num = getNumberOfRows(); for (int i = 0; i < num; i++) { delete rows[i]; rows[i] = NULL; } rows.clear(); } /** * add a row to the table. */ void XhtmlTableExtractorFile::Table::addRow(TableRow* tableRow) { rows.push_back(tableRow); } /** * add a row span to the table. */ void XhtmlTableExtractorFile::Table::addRowSpan(const TableRowSpan& rowSpan) { rowSpans.push_back(rowSpan); } /** * finish the table (handle row spans). */ void XhtmlTableExtractorFile::Table::finishTable() { const int num = static_cast(rowSpans.size()); for (int k = 0; k < num; k++) { const TableRowSpan& trs = rowSpans[k]; for (int j = trs.rowStart; j <= trs.rowEnd; j++) { for (int i = trs.colStart; i <= trs.colEnd; i++) { //if (DebugControl::getDebugOn()) { TableRow* tr = getRow(j); tr->insertElement(i, ""); std::cout << "Insert empty element at table" << " row " << j << " col " << i << std::endl; //} } } } } /** * get the dimensions of the table. */ void XhtmlTableExtractorFile::Table::getTableDimensions(int& numRows, int& numCols) const { numRows = getNumberOfRows(); numCols = 0; for (int i = 0; i < numRows; i++) { const TableRow* tr = getRow(i); numCols = std::max(numCols, tr->getNumberOfElements()); } } /** * get the number of rows in the table. */ int XhtmlTableExtractorFile::Table::getNumberOfRows() const { return rows.size(); } /** * get a row from the table. */ XhtmlTableExtractorFile::TableRow* XhtmlTableExtractorFile::Table::getRow(const int indx) { return rows[indx]; } /** * get a row from the table (const method). */ const XhtmlTableExtractorFile::TableRow* XhtmlTableExtractorFile::Table::getRow(const int indx) const { return rows[indx]; } /** * get the newest row. */ XhtmlTableExtractorFile::TableRow* XhtmlTableExtractorFile::Table::getNewestRow() { const int num = getNumberOfRows(); if (num > 0) { return rows[num - 1]; } return NULL; } //==================================================================================== // TableRow Class //==================================================================================== /** * constructor. */ XhtmlTableExtractorFile::TableRow::TableRow() { } /** * destructor. */ XhtmlTableExtractorFile::TableRow::~TableRow() { elements.clear(); } /** * add an element to the row. */ void XhtmlTableExtractorFile::TableRow::addElement(const QString& s, const int colSpan) { elements.push_back(s); for (int i = 1; i < colSpan; i++) { elements.push_back(""); } } /** * get the number of elements. */ int XhtmlTableExtractorFile::TableRow::getNumberOfElements() const { return elements.size(); } /** * get an element. */ QString XhtmlTableExtractorFile::TableRow::getElement(const int indx) const { return elements[indx]; } /** * insert an element. */ void XhtmlTableExtractorFile::TableRow::insertElement(const int position, const QString& value) { elements.insert(elements.begin() + position, value); } //==================================================================================== // TableRowSpan Class //==================================================================================== /** * constructor. */ XhtmlTableExtractorFile::TableRowSpan::TableRowSpan(const int rowStartIn, const int numRowsIn, const int colStartIn, const int numColsIn) { rowStart = rowStartIn; rowEnd = rowStart + numRowsIn - 1; colStart = colStartIn; colEnd = colStart + numColsIn - 1; } /** * destructor. */ XhtmlTableExtractorFile::TableRowSpan::~TableRowSpan() { } caret-5.6.4~dfsg.1.orig/caret_files/WustlRegionFile.h0000664000175000017500000001711011572067322022274 0ustar michaelmichael #ifndef __WUSTL_REGION_FILE_H__ #define __WUSTL_REGION_FILE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "AbstractFile.h" /// This class is used for the Washington University NeuroImaging Lab's ROI file class WustlRegionFile : public AbstractFile { public: /// Class contains a Case for a Region class RegionCase { public: /// Constructor RegionCase(); /// Constructor ~RegionCase(); /// get the name of the case QString getName() const { return name; } /// set the name of the case void setName(const QString& n) { name = n; } /// get the number of timepoints in the case int getNumberOfTimePoints() const { return timePoints.size(); } /// add a timepoint void addTimePoint(const float val) { timePoints.push_back(val); } /// get the timepoints void getTimePoints(std::vector& tp) const { tp = timePoints; } /// get the timepoints std::vector getTimePoints() const { return timePoints; } /// set the timepoints void setTimePoints(const std::vector& tp) { timePoints = tp; } protected: /// name of the case QString name; /// the time points std::vector timePoints; }; /// Class contains a Region class Region { public: /// Constructor Region(); /// Constructor ~Region(); /// get the region number int getNumber() const { return regionNumber; } /// set the region number void setNumber(const int num) { regionNumber = num; } /// get the name of the region QString getName() const { return name; } /// set the name of the region void setName(const QString& n) { name = n; } /// get the number of voxels in the ROI int getNumberOfVoxels() const { return numberOfVoxels; } /// set the number of voxels in the ROI void setNumberOfVoxels(const int num) { numberOfVoxels = num; } /// get the number of region cases int getNumberOfRegionCases() const { return regionCases.size(); } /// add a region case void addRegionCase(const RegionCase& rc) { regionCases.push_back(rc); } /// get a region case const RegionCase* getRegionCase(const int indx) const { return ®ionCases[indx]; } /// get a region case (const method) RegionCase* getRegionCase(const int indx) { return ®ionCases[indx]; } /// get a region case by name (returns NULL if not found) const RegionCase* getRegionCaseByName(const QString& name) const; /// get a region case by name (returns NULL if not found - const method) RegionCase* getRegionCaseByName(const QString& name); protected: /// region number int regionNumber; /// region name QString name; /// number of voxels in the ROI int numberOfVoxels; /// cases in this region std::vector regionCases; }; /// Class contains a Timecourse class TimeCourse { public: /// constructor TimeCourse(); /// constructor ~TimeCourse(); /// get the name of the timecourse QString getName() const { return name; } /// set the name of the timecourse void setName(const QString& n) { name = n; } /// get the number of regions in the timecourse int getNumberOfRegions() const { return regions.size(); } /// get a region by its index Region* getRegionByIndex(const int indx) { return ®ions[indx]; } /// get a region by its index (const method) const Region* getRegionByIndex(const int indx) const { return ®ions[indx]; } /// get a region by its name (returns NULL if not found) Region* getRegionByName(const QString name); /// get a region (const method) const Region* getRegion(const int indx) const { return ®ions[indx]; } /// add a region void addRegion(const Region& r) { regions.push_back(r); } /// get all of the case names in a time course void getAllRegionCaseNames(std::vector& names) const; protected: /// name of timecourse QString name; /// regions in the timecourse std::vector regions; }; /// Constructor WustlRegionFile(); /// Destructor ~WustlRegionFile(); /// clear the file. virtual void clear(); /// returns true if the file is isEmpty (contains no data) virtual bool empty() const; /// get the number of timecourses int getNumberOfTimeCourses() const { return timeCourses.size(); } /// get a time course TimeCourse* getTimeCourse(const int indx) { return &timeCourses[indx]; } /// get a time course const TimeCourse* getTimeCourse(const int indx) const { return &timeCourses[indx]; } /// add a time course void addTimeCourse(const TimeCourse tc); /// append a region file to this file void append(const WustlRegionFile wrf); protected: /// Read the contents of the file (header has already been read) virtual void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException); /// Write the file's data (header has already been written) virtual void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException); /// the time courses std::vector timeCourses; }; #endif // __WUSTL_REGION_FILE_H__ caret-5.6.4~dfsg.1.orig/caret_files/WustlRegionFile.cxx0000664000175000017500000002120411572067322022646 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "DebugControl.h" #include "SpecFile.h" #include "StringUtilities.h" #include "WustlRegionFile.h" /** * Constructor. */ WustlRegionFile::WustlRegionFile() : AbstractFile("Wustl Region File", SpecFile::getWustlRegionFileExtension(), false, AbstractFile::FILE_FORMAT_ASCII, FILE_IO_READ_AND_WRITE, FILE_IO_NONE, FILE_IO_NONE, FILE_IO_NONE) { clear(); } /** * Destructor. */ WustlRegionFile::~WustlRegionFile() { clear(); } /** * add a time course. */ void WustlRegionFile::addTimeCourse(const TimeCourse tc) { timeCourses.push_back(tc); setModified(); } /** * append a region file to this file. */ void WustlRegionFile::append(const WustlRegionFile wrf) { appendToFileComment(wrf.getFileComment()); timeCourses.insert(timeCourses.end(), wrf.timeCourses.begin(), wrf.timeCourses.end()); } /** * clear the file. */ void WustlRegionFile::clear() { clearAbstractFile(); timeCourses.clear(); } /** * returns true if the file is isEmpty (contains no data). */ bool WustlRegionFile::empty() const { return (timeCourses.empty()); } /** * Read the contents of the file (header has already been read). */ void WustlRegionFile::readFileData(QFile& /*file*/, QTextStream& stream, QDataStream&, QDomElement& /* rootElement */ ) throw (FileException) { // // Should reading data be skipped ? // if (getReadMetaDataOnlyFlag()) { return; } bool readingRegionData = false; TimeCourse* timeCourseBeingRead = NULL; Region* regionBeingRead = NULL; QString line; readLine(stream, line); while (stream.atEnd() == false) { if (readingRegionData == false) { if (StringUtilities::startsWith(line, "TIMECOURSE")) { std::vector tokens; StringUtilities::token(line, " ", tokens); TimeCourse timeCourse; if (tokens.size() >= 3) { timeCourse.setName(tokens[2]); addTimeCourse(timeCourse); const int num = getNumberOfTimeCourses(); timeCourseBeingRead = getTimeCourse(num - 1); } } else if (StringUtilities::startsWith(line, "REGION")) { std::vector tokens; StringUtilities::token(line, " ", tokens); Region region; if (tokens.size() >= 5) { region.setNumber(StringUtilities::toInt(tokens[2])); region.setName(tokens[3]); region.setNumberOfVoxels(StringUtilities::toInt(tokens[4])); if (timeCourseBeingRead == NULL) { QString msg("Error reading file. Have region named "); msg.append(region.getName()); msg.append(" but no timecourse."); throw FileException(filename, msg); } timeCourseBeingRead->addRegion(region); const int num = timeCourseBeingRead->getNumberOfRegions(); regionBeingRead = timeCourseBeingRead->getRegionByIndex(num - 1); readingRegionData = true; } else { QString msg("REGION line has fewer than 5 items: "); msg.append(line); throw FileException(filename, msg); } } } else { std::vector tokens; StringUtilities::token(line, " ", tokens); if (tokens.size() >= 2) { RegionCase rc; rc.setName(tokens[0]); for (unsigned int i = 1; i < tokens.size(); i++) { rc.addTimePoint(StringUtilities::toFloat(tokens[i])); } if (regionBeingRead == NULL) { QString msg("Have RegionCase but no current region for line: "); msg.append(line); throw FileException(filename, msg); } regionBeingRead->addRegionCase(rc); } else { readingRegionData = false; regionBeingRead = NULL; } } readLine(stream, line); } if (DebugControl::getDebugOn()) { std::cout << "WustlRegionFile" << std::endl; std::cout << " Number of timecourses: " << getNumberOfTimeCourses() << std::endl; for (int i = 0; i < getNumberOfTimeCourses(); i++) { std::cout << " Timecourse " << i << " has "; const TimeCourse* tc = getTimeCourse(i); std::cout << tc->getNumberOfRegions() << " regions." << std::endl; } } } /** * Write the file's data (header has already been written). */ void WustlRegionFile::writeFileData(QTextStream&, QDataStream&, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException) { throw FileException(filename, "Writing of Wu NIL Region of Interest Files not supported."); } // //--------------------------------------------------------------------------------------- // /** * constructor. */ WustlRegionFile::TimeCourse::TimeCourse() { name = ""; } /** * constructor. */ WustlRegionFile::TimeCourse::~TimeCourse() { } /** * get a region by its name (returns NULL if not found). */ WustlRegionFile::Region* WustlRegionFile::TimeCourse::getRegionByName(const QString name) { const int num = getNumberOfRegions(); for (int i = 0; i < num; i++) { Region* reg = getRegionByIndex(i); if (reg->getName() == name) { return reg; } } return NULL; } /** * get all of the case names in a time course. */ void WustlRegionFile::TimeCourse::getAllRegionCaseNames(std::vector& names) const { std::set uniqueNames; const int num = getNumberOfRegions(); for (int i = 0; i < num; i++) { const Region* reg = getRegionByIndex(i); const int numCase = reg->getNumberOfRegionCases(); for (int j = 0; j < numCase; j++) { const RegionCase* rc = reg->getRegionCase(j); uniqueNames.insert(rc->getName()); } } names.clear(); names.insert(names.end(), uniqueNames.begin(), uniqueNames.end()); } // //--------------------------------------------------------------------------------------- // /** * Constructor. */ WustlRegionFile::Region::Region() { regionNumber = -1; name = ""; numberOfVoxels = 0; } /** * Constructor. */ WustlRegionFile::Region::~Region() { } /** * get a region case by name. */ const WustlRegionFile::RegionCase* WustlRegionFile::Region::getRegionCaseByName(const QString& name) const { const int numCases = getNumberOfRegionCases(); for (int i = 0; i < numCases; i++) { const RegionCase* rc = getRegionCase(i); if (rc->getName() == name) { return rc; } } return NULL; } /** * get a region case by name (const method). */ WustlRegionFile::RegionCase* WustlRegionFile::Region::getRegionCaseByName(const QString& name) { const int numCases = getNumberOfRegionCases(); for (int i = 0; i < numCases; i++) { RegionCase* rc = getRegionCase(i); if (rc->getName() == name) { return rc; } } return NULL; } // //--------------------------------------------------------------------------------------- // /** * Constructor. */ WustlRegionFile::RegionCase::RegionCase() { name = ""; timePoints.clear(); } /** * Constructor. */ WustlRegionFile::RegionCase::~RegionCase() { } // //--------------------------------------------------------------------------------------- // caret-5.6.4~dfsg.1.orig/caret_files/WuNilHeader.h0000664000175000017500000001635111572067322021367 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_WUNIL_HEADER_H__ #define __VE_WUNIL_HEADER_H__ #include #include #include "FileException.h" /// class for storing a Washingtion University Neuro Imaging Laboratory attribute class WuNilAttribute { public: /// constructor for single double WuNilAttribute(const QString& name, const double value); /// constructor for single float WuNilAttribute(const QString& name, const float value); /// constructor for single int WuNilAttribute(const QString& name, const int value); /// constructor for array of floats WuNilAttribute(const QString& name, const float values[], const int numValues); /// constructor for array of ints WuNilAttribute(const QString& name, const int values[], const int numValues); /// constructor for vector of floats WuNilAttribute(const QString& name, const std::vector& values); /// constructor for vector of ints WuNilAttribute(const QString& name, const std::vector& values); /// constructor WuNilAttribute(const QString& name, const QString& value); /// get the values for an int attribute void getValue(std::vector& valueOut) const; /// get the values for a float void getValue(std::vector& valueOut) const; /// get the value for a string QString getValue() const { return value; } /// name of the attribute QString attributeName; /// storage for a string attribute QString value; static const QString NAME_CARET_METADATA; static const QString NAME_NUMBER_FORMAT; static const QString NAME_NUMBER_OF_BYTES_PER_PIXEL; static const QString NAME_ORIENTATION; static const QString NAME_NUMBER_OF_DIMENSIONS; static const QString NAME_SCALING_FACTOR_1; static const QString NAME_SCALING_FACTOR_2; static const QString NAME_SCALING_FACTOR_3; static const QString NAME_MATRIX_SIZE_1; static const QString NAME_MATRIX_SIZE_2; static const QString NAME_MATRIX_SIZE_3; static const QString NAME_MATRIX_SIZE_4; static const QString NAME_DATE; static const QString NAME_CENTER; static const QString NAME_MMPPIX; static const QString NAME_CONVERSION_PROGRAM; static const QString NAME_REGION_NAME; static const QString NAME_IMAGEDATA_BYTE_ORDER; }; /// class for storing a Washingtion University Neuro Imaging Laboratory Header File class WuNilHeader { public: /// Constructor WuNilHeader(); /// Destructor ~WuNilHeader(); /// add an attribute void addAttribute(WuNilAttribute& attr); /// clear the header void clear(); /// Get the number of attributes int getNumberOfAttributes() const { return attributes.size(); } /// Get an attribute by its index WuNilAttribute* getAttribute(const int index); /// Get an attribute by its name (returns NULL if not found) WuNilAttribute* getAttribute(const QString& name); /// Get an attributes index from its name (returns -1 if not found) int getAttributeIndexFromName(const QString& name) const; /// get the region names void getRegionNames(std::vector& names) const; /// set the region names void setRegionNames(const std::vector& names); /// read a header file void readHeader(QFile& file, QTextStream& stream) throw (FileException); /// Write to a header file void writeHeader(QTextStream& stream) throw (FileException); /// convert a voxel indices into stereotaxic coordinates static void voxelIndicesToStereotaxicCoordinates(const int dim[3], const float center[3], const float mmpix[3], const int voxelIndices[3], float coordsOut[3]); private: /// write an attribute with the specified name void writeAttribute(QTextStream& stream, const QString& attributeName, std::vector& attributeWrittenFlags); /// write an attribute with the specified index void writeAttribute(QTextStream& stream, const int index); /// used for flipping coordinate stuff static void vrtflip(const int imgdim[3], const float centeri[3], const float mmppixi[3], float centert[3], float mmppixt[3]); /// storage for the attributes std::vector attributes; /// the region names std::vector nilRegionNames; }; #endif // __VE_WUNIL_HEADER_H__ #ifdef __WUNIL_HEADER_DEFINE__ const QString WuNilAttribute::NAME_CARET_METADATA = "caret_metadata"; const QString WuNilAttribute::NAME_NUMBER_FORMAT = "number format"; const QString WuNilAttribute::NAME_NUMBER_OF_BYTES_PER_PIXEL = "number of bytes per pixel"; const QString WuNilAttribute::NAME_ORIENTATION = "orientation"; const QString WuNilAttribute::NAME_NUMBER_OF_DIMENSIONS = "number of dimensions"; const QString WuNilAttribute::NAME_SCALING_FACTOR_1 = "scaling factor (mm/pixel) [1]"; const QString WuNilAttribute::NAME_SCALING_FACTOR_2 = "scaling factor (mm/pixel) [2]"; const QString WuNilAttribute::NAME_SCALING_FACTOR_3 = "scaling factor (mm/pixel) [3]"; const QString WuNilAttribute::NAME_MATRIX_SIZE_1 = "matrix size [1]"; const QString WuNilAttribute::NAME_MATRIX_SIZE_2 = "matrix size [2]"; const QString WuNilAttribute::NAME_MATRIX_SIZE_3 = "matrix size [3]"; const QString WuNilAttribute::NAME_MATRIX_SIZE_4 = "matrix size [4]"; const QString WuNilAttribute::NAME_DATE = "date"; const QString WuNilAttribute::NAME_CENTER = "center"; const QString WuNilAttribute::NAME_MMPPIX = "mmppix"; const QString WuNilAttribute::NAME_CONVERSION_PROGRAM = "conversion program"; const QString WuNilAttribute::NAME_REGION_NAME = "region names"; const QString WuNilAttribute::NAME_IMAGEDATA_BYTE_ORDER = "imagedata byte order"; #endif // __WUNIL_HEADER_DEFINE__ caret-5.6.4~dfsg.1.orig/caret_files/WuNilHeader.cxx0000664000175000017500000003271711572067322021746 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #define __WUNIL_HEADER_DEFINE__ #include "WuNilHeader.h" #undef __WUNIL_HEADER_DEFINE__ #include "DateAndTime.h" #include "DebugControl.h" #include "FileUtilities.h" #include "StringUtilities.h" /** * Constructor. */ WuNilHeader::WuNilHeader() { clear(); } /** * Destructor. */ WuNilHeader::~WuNilHeader() { } /** * Clear the afni header and set to default values */ void WuNilHeader::clear() { // // Create the required default attributes assuming a single subvolume // attributes.clear(); WuNilAttribute format(WuNilAttribute::NAME_NUMBER_FORMAT, "float"); addAttribute(format); WuNilAttribute bpp(WuNilAttribute::NAME_NUMBER_OF_BYTES_PER_PIXEL, 4); addAttribute(bpp); WuNilAttribute orient(WuNilAttribute::NAME_ORIENTATION, 2); addAttribute(orient); WuNilAttribute numdim(WuNilAttribute::NAME_NUMBER_OF_DIMENSIONS, 4); addAttribute(numdim); WuNilAttribute s1(WuNilAttribute::NAME_SCALING_FACTOR_1, 1.0); addAttribute(s1); WuNilAttribute s2(WuNilAttribute::NAME_SCALING_FACTOR_2, 1.0); addAttribute(s2); WuNilAttribute s3(WuNilAttribute::NAME_SCALING_FACTOR_3, 1.0); addAttribute(s3); WuNilAttribute m1(WuNilAttribute::NAME_MATRIX_SIZE_1, 0); addAttribute(m1); WuNilAttribute m2(WuNilAttribute::NAME_MATRIX_SIZE_2, 0); addAttribute(m2); WuNilAttribute m3(WuNilAttribute::NAME_MATRIX_SIZE_3, 0); addAttribute(m3); WuNilAttribute m4(WuNilAttribute::NAME_MATRIX_SIZE_4, 0); addAttribute(m4); WuNilAttribute nd(WuNilAttribute::NAME_DATE, DateAndTime::getDateAndTimeAsString()); //QDateTime::currentDateTime().toString("ddd MMM d hh:mm::ss yyyy")); addAttribute(nd); //WuNilAttribute nc(WuNilAttribute::NAME_CENTER, "0.0 0.0 0.0"); //addAttribute(nc); WuNilAttribute nm(WuNilAttribute::NAME_MMPPIX, "1.0 -1.0 -1.0"); addAttribute(nm); WuNilAttribute prog(WuNilAttribute::NAME_CONVERSION_PROGRAM, "caret"); addAttribute(prog); nilRegionNames.clear(); } /** * add an attribute (replaces it if it exists) */ void WuNilHeader::addAttribute(WuNilAttribute& attr) { WuNilAttribute* a = getAttribute(attr.attributeName); if (a != NULL) { *a = attr; } else { attributes.push_back(attr); } } /** * Get an attribute by its index */ WuNilAttribute* WuNilHeader::getAttribute(const int index) { if (index < getNumberOfAttributes()) { return &attributes[index]; } return NULL; } /** * get an attribute for the specified name (returns NULL if not found) */ WuNilAttribute* WuNilHeader::getAttribute(const QString& name) { const int numAttrs = getNumberOfAttributes(); for (int i = 0; i < numAttrs; i++) { if (attributes[i].attributeName == name) { return &attributes[i]; } } return NULL; } /** * Get an attributes index from its name (returns -1 if not found) */ int WuNilHeader::getAttributeIndexFromName(const QString& name) const { const int numAttrs = getNumberOfAttributes(); for (int i = 0; i < numAttrs; i++) { if (attributes[i].attributeName == name) { return i; } } return -1; } /** * get the region names. */ void WuNilHeader::getRegionNames(std::vector& names) const { names = nilRegionNames; } /** * set the region names. */ void WuNilHeader::setRegionNames(const std::vector& names) { nilRegionNames = names; } /** * Read an WuNil header. */ void WuNilHeader::readHeader(QFile& /*file*/, QTextStream& stream) throw (FileException) { // // Read until end of file // while(stream.atEnd() == false) { const QString line(stream.readLine()); if (line.isEmpty() == false) { std::vector tokens; StringUtilities::tokenSingleSeparator(line, ":=", tokens); if (tokens.size() == 2) { const QString key(StringUtilities::trimWhitespace(tokens[0])); if (key == WuNilAttribute::NAME_REGION_NAME) { const QString label(tokens[1]); StringUtilities::tokenSingleSeparator(label, " ", tokens); if (tokens.size() >= 2) { nilRegionNames.push_back(tokens[1]); } } else { const QString value(StringUtilities::trimWhitespace(tokens[1])); if (DebugControl::getDebugOn()) { std::cout << "key '" << key.toAscii().constData() << "'" << std::endl; std::cout << "value '" << value.toAscii().constData() << "'" << std::endl; std::cout << std::endl; } WuNilAttribute attr(key, value); addAttribute(attr); } } } } } /** * Write an AFNI header. */ void WuNilHeader::writeHeader(QTextStream& stream) throw (FileException) { // // Set the byte ordering // //int wordSize; bool bigEndian = (QSysInfo::ByteOrder == QSysInfo::BigEndian); //qSysInfo(&wordSize, &bigEndian); if (bigEndian == false) { // need to swap bytes when writing volume file since 4dfp always MSB } // // Set the date // WuNilAttribute dat(WuNilAttribute::NAME_DATE, DateAndTime::getDateAndTimeAsString()); //QDateTime::currentDateTime().toString("ddd MMM d hh:mm::ss yyyy")); addAttribute(dat); // // Write all of the attributes // const int numAttr = getNumberOfAttributes(); std::vector attributeWritten(numAttr, false); writeAttribute(stream, WuNilAttribute::NAME_NUMBER_FORMAT, attributeWritten); writeAttribute(stream, WuNilAttribute::NAME_NUMBER_OF_BYTES_PER_PIXEL, attributeWritten); writeAttribute(stream, WuNilAttribute::NAME_ORIENTATION, attributeWritten); writeAttribute(stream, WuNilAttribute::NAME_NUMBER_OF_DIMENSIONS, attributeWritten); writeAttribute(stream, WuNilAttribute::NAME_SCALING_FACTOR_1, attributeWritten); writeAttribute(stream, WuNilAttribute::NAME_SCALING_FACTOR_2, attributeWritten); writeAttribute(stream, WuNilAttribute::NAME_SCALING_FACTOR_3, attributeWritten); writeAttribute(stream, WuNilAttribute::NAME_MATRIX_SIZE_1, attributeWritten); writeAttribute(stream, WuNilAttribute::NAME_MATRIX_SIZE_2, attributeWritten); writeAttribute(stream, WuNilAttribute::NAME_MATRIX_SIZE_3, attributeWritten); writeAttribute(stream, WuNilAttribute::NAME_MATRIX_SIZE_4, attributeWritten); writeAttribute(stream, WuNilAttribute::NAME_CENTER, attributeWritten); writeAttribute(stream, WuNilAttribute::NAME_MMPPIX, attributeWritten); writeAttribute(stream, WuNilAttribute::NAME_DATE, attributeWritten); // // Write all attributes that have not already been written // for (int i = 0; i < numAttr; i++) { if (attributeWritten[i] == false) { writeAttribute(stream, i); } } // // Write the region names (start at one to skip "???" // const int numRegions = static_cast(nilRegionNames.size()); for (int i = 0; i < numRegions; i++) { QString s(WuNilAttribute::NAME_REGION_NAME); if (s.length() < 34) { //s.setLength(34); //s.fill(' ', 34); s = s.leftJustified(34, ' '); } stream << s << " := " << i << " " << nilRegionNames[i] << "\n"; } } /** * Write the specified attribute */ void WuNilHeader::writeAttribute(QTextStream& stream, const QString& attributeName, std::vector& attributeWrittenFlags) { const int index = getAttributeIndexFromName(attributeName); if (index >= 0) { writeAttribute(stream, index); attributeWrittenFlags[index] = true; } } /** * Write attribute at specified index. */ void WuNilHeader::writeAttribute(QTextStream& stream, const int index) { if (index >= 0) { const WuNilAttribute* attr = getAttribute(index); QString s(attr->attributeName); if (s.length() < 34) { //s.setLength(34); //s.fill(34, ' '); s = s.leftJustified(34, ' '); } stream << s << " := " << attr->value << "\n"; } } /** * convert a voxel indices into stereotaxic coordinates. * From Avi Snyder's index2at.c and ft4imgo.f. */ void WuNilHeader::voxelIndicesToStereotaxicCoordinates(const int dim[3], const float center[3], const float mmpix[3], const int voxelIndicesIn[3], float coordsOut[3]) { float centerr[3], mmppixr[3]; vrtflip(dim, center, mmpix, centerr, mmppixr); const int voxelIndex[3] = { voxelIndicesIn[0] + 1, voxelIndicesIn[1] + 1, voxelIndicesIn[2] + 1 }; for (int i = 0; i < 3; i++) { coordsOut[i] = voxelIndex[i] * mmppixr[i] - centerr[i]; } } /** * used for flipping coordinate stuff. * From Avi Snyder's index2at.c and ft4imgo.f. */ void WuNilHeader::vrtflip(const int imgdim[3], const float centeri[3], const float mmppixi[3], float centert[3], float mmppixt[3]) { float flips[3] = { -1, 1, -1 }; for (int i = 0; i < 3; i++) { mmppixt[i] = mmppixi[i] * flips[i]; centert[i] = centeri[i] * flips[i]; if (flips[i] < 0) { centert[i] = mmppixt[i] * static_cast(imgdim[i] + 1) - centert[i]; } } } //================================================================================ // // WuNilAttribute methods // /** * constructor for single double but stored as float. The compiler treats a * floating point number (e.g. 4.5) as a double so this contructor is required. */ WuNilAttribute::WuNilAttribute(const QString& name, const double valueIn) { attributeName = name; value = QString::number(valueIn, 'f', 6); } /** * constructor for single float */ WuNilAttribute::WuNilAttribute(const QString& name, const float valueIn) { attributeName = name; value = QString::number(valueIn, 'f', 6); } /** * constructor for single int */ WuNilAttribute::WuNilAttribute(const QString& name, const int valueIn) { attributeName = name; value = QString::number(valueIn); } /** * constructor for float array */ WuNilAttribute::WuNilAttribute(const QString& name, const float values[], const int numValues) { attributeName = name; std::vector sv; for (int i = 0; i < numValues; i++) { sv.push_back(QString::number(values[i], 'f', 6)); } value = StringUtilities::combine(sv, " "); } /** * constructor for int array */ WuNilAttribute::WuNilAttribute(const QString& name, const int values[], const int numValues) { attributeName = name; std::vector sv; for (int i = 0; i < numValues; i++) { sv.push_back(QString::number(values[i])); } value = StringUtilities::combine(sv, " "); } /** * constructor for vector of floats */ WuNilAttribute::WuNilAttribute(const QString& name, const std::vector& values) { attributeName = name; std::vector sv; for (int i = 0; i < static_cast(values.size()); i++) { sv.push_back(QString::number(values[i], 'f', 6)); } value = StringUtilities::combine(sv, " "); } /** * constructor for vector of ints */ WuNilAttribute::WuNilAttribute(const QString& name, const std::vector& values) { attributeName = name; std::vector sv; for (int i = 0; i < static_cast(values.size()); i++) { sv.push_back(QString::number(values[i])); } value = StringUtilities::combine(sv, " "); } /** * constructor for string */ WuNilAttribute::WuNilAttribute(const QString& name, const QString& valueIn) { attributeName = name; value = valueIn; } /** * Get an attribute value. */ void WuNilAttribute::getValue(std::vector& valueOut) const { valueOut.clear(); std::vector tokens; StringUtilities::token(value, " ", tokens); for (int i = 0; i < static_cast(tokens.size()); i++) { valueOut.push_back(QString(tokens[i]).toInt()); } } /** * Get an attribute value. */ void WuNilAttribute::getValue(std::vector& valueOut) const { valueOut.clear(); std::vector tokens; StringUtilities::token(value, " ", tokens); for (int i = 0; i < static_cast(tokens.size()); i++) { valueOut.push_back(QString(tokens[i]).toFloat()); } } caret-5.6.4~dfsg.1.orig/caret_files/VtkModelFile.h0000664000175000017500000001451011572067322021540 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "AbstractFile.h" #ifndef __VTK_MODEL_FILE_H__ #define __VTK_MODEL_FILE_H__ #include "AbstractFile.h" #include "CoordinateFile.h" class BorderColorFile; class BorderFile; class CellColorFile; class CellFile; class FociColorFile; class FociFile; class TransformationMatrix; /// class for reading/writing accessing VTK polydata files (including XML) class VtkModelFile : public AbstractFile { public: /// class for storing a line or polygon class VtkModelObject { public: /// Constructor VtkModelObject(const int* ptsIn, const int numPtsIn) { for (int i = 0; i < numPtsIn; i++) { pts.push_back(ptsIn[i]); } } /// get number of items in object int getNumberOfItems() const { return pts.size(); } /// get a pointer to a point number in the item const int* getPointIndex(const int indx) const { return &pts[indx]; } protected: std::vector pts; }; /// Constructor VtkModelFile(); /// Constructor - converts borders to VTK lines VtkModelFile(const BorderFile* bf, const BorderColorFile* colors); /// Constructor - converts cells to VTK vertices VtkModelFile(const CellFile* cells, const CellColorFile* colors); /// Constructor - converts foci to VTK vertices VtkModelFile(const FociFile* foci, const FociColorFile* colors); /// Constructor (construct from polydata) VtkModelFile(vtkPolyData* polyData); /// Destructor ~VtkModelFile(); /// add a coordinate void addCoordinate(const float xyz[3], const unsigned char* rgbaColorIn = NULL, const float* normalIn = NULL); /// Clears current file data in memory. void clear(); /// returns true if the file is isEmpty bool empty() const; /// apply a transformation matrix to the vtk model coordinates void applyTransformationMatrix(const TransformationMatrix& matrix); /// get the display flag bool getDisplayFlag() const { return displayFlag; } /// set the display flag void setDisplayFlag(const bool df) { displayFlag = df; }; /// get the coordinates const CoordinateFile* getCoordinateFile() const { return &coordinates; } /// get the number of points int getNumberOfPoints() const { return coordinates.getNumberOfCoordinates(); } /// get the RGBA colors for a point (pointer to the RGBA components) const unsigned char* getPointColor(const int indx) const; /// set the RGBA colors for a point void setPointColor(const int indx, const unsigned char[4]); /// get the normal for a point const float* getPointNormal(const int indx) const; /// get the number of vertices int getNumberOfVertices() const { return vertices.size(); } /// get a vertex (pointer to its "point" indices) const int* getVertex(const int indx) const; /// get the number of triangles int getNumberOfTriangles() const { return (triangles.size() / 3); } /// get a vertex (pointer to its 3 "point" indices) const int* getTriangle(const int indx) const; /// get a triangles 3D position (average of its coordinates) void getTriangleCoordinate(const int indx, float coord[3]) const; /// get the number of lines int getNumberOfLines() const { return lines.size(); } /// get a line const VtkModelObject* getLine(const int indx) const; /// get the number of polygons int getNumberOfPolygons() const { return polygons.size(); } /// set the entire model to a specific color void setToSolidColor(const unsigned char rgba[4]); /// get a polygon const VtkModelObject* getPolygon(const int index) const; /// read the file header and its volume data void readFile(const QString& fileNameIn) throw (FileException); /// write the volume file void writeFile(const QString& filenameIn) throw (FileException); protected: /// Read the spec file data (should never be called) void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException); /// Write the spec file data (should never be called) void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException); /// read in the model from vtk poly data void readPolyData(vtkPolyData* polyData); /// Coordinates of all points CoordinateFile coordinates; /// storage for point colors std::vector pointColors; /// the triangles (3 per triangle) std::vector triangles; /// the vertices std::vector vertices; /// lines std::vector lines; /// polygons std::vector polygons; /// display this model flag bool displayFlag; /// point normals std::vector pointNormals; }; #endif // __VTK_MODEL_FILE_H__ caret-5.6.4~dfsg.1.orig/caret_files/VtkModelFile.cxx0000664000175000017500000006332711572067322022125 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "vtkCellArray.h" #include "vtkFloatArray.h" #include "vtkLookupTable.h" #include "vtkPointData.h" #include "vtkPoints.h" #include "vtkPolyData.h" #include "vtkPolyDataNormals.h" #include "vtkPolyDataReader.h" #include "vtkPolyDataWriter.h" #include "vtkTriangleFilter.h" #include "vtkXMLPolyDataReader.h" #include "vtkXMLPolyDataWriter.h" #include "BorderColorFile.h" #include "BorderFile.h" #include "CellColorFile.h" #include "CellFile.h" #include "DebugControl.h" #include "FileUtilities.h" #include "FociColorFile.h" #include "FociFile.h" #include "SpecFile.h" #include "VtkModelFile.h" /** * Constructor. */ VtkModelFile::VtkModelFile() : AbstractFile("VTK Model File", SpecFile::getVtkModelFileExtension(), false, AbstractFile::FILE_FORMAT_ASCII, FILE_IO_READ_AND_WRITE, FILE_IO_NONE, FILE_IO_READ_AND_WRITE, FILE_IO_NONE) // be sure to update all constructors { clear(); } /** * Constructor. (construct from polydata) */ VtkModelFile::VtkModelFile(vtkPolyData* polyData) : AbstractFile("VTK Model File", SpecFile::getVtkModelFileExtension(), false, AbstractFile::FILE_FORMAT_ASCII, FILE_IO_READ_AND_WRITE, FILE_IO_NONE, FILE_IO_READ_AND_WRITE, FILE_IO_NONE) { clear(); readPolyData(polyData); } /** * Constructor - converts borders to VTK lines. */ VtkModelFile::VtkModelFile(const BorderFile* bf, const BorderColorFile* colors) : AbstractFile("VTK Model File", SpecFile::getVtkModelFileExtension(), false, AbstractFile::FILE_FORMAT_ASCII, FILE_IO_READ_AND_WRITE, FILE_IO_NONE, FILE_IO_READ_AND_WRITE, FILE_IO_NONE) { clear(); if (bf == NULL) { return; } const int numBorders = bf->getNumberOfBorders(); for (int i = 0; i < numBorders; i++) { const Border* border = bf->getBorder(i); const int numLinks = border->getNumberOfLinks(); if (numLinks > 0) { std::vector pts; for (int j = 0; j < numLinks; j++) { unsigned char rgbaColor[4] = { 170, 170, 170, 255 }; const int colorIndex = border->getBorderColorIndex(); if ((colorIndex >= 0) && (colorIndex < colors->getNumberOfColors())) { colors->getColorByIndex(colorIndex, rgbaColor[0], rgbaColor[1], rgbaColor[2], rgbaColor[3]); } const float normal[3] = { 0.0, 0.0, 1.0 }; const float* xyz = border->getLinkXYZ(j); pts.push_back(coordinates.getNumberOfCoordinates()); addCoordinate(xyz, rgbaColor, normal); /* pointColors.push_back(rgbaColor[0]); pointColors.push_back(rgbaColor[1]); pointColors.push_back(rgbaColor[2]); pointColors.push_back(rgbaColor[3]); pointNormals.push_back(0.0); pointNormals.push_back(0.0); pointNormals.push_back(1.0); */ } lines.push_back(VtkModelObject(&pts[0], pts.size())); } } } /** * Constructor - converts cells to VTK vertices. */ VtkModelFile::VtkModelFile(const CellFile* cells, const CellColorFile* colors) : AbstractFile("VTK Model File", SpecFile::getVtkModelFileExtension(), false, AbstractFile::FILE_FORMAT_ASCII, FILE_IO_READ_AND_WRITE, FILE_IO_NONE, FILE_IO_READ_AND_WRITE, FILE_IO_NONE) { clear(); if (cells == NULL) { return; } const int numCells = cells->getNumberOfCells(); for (int i = 0; i < numCells; i++) { const CellData* cd = cells->getCell(i); unsigned char rgbaColor[4] = { 170, 170, 170, 255 }; const int colorIndex = cd->getColorIndex(); if ((colorIndex >= 0) && (colorIndex < colors->getNumberOfColors())) { colors->getColorByIndex(colorIndex, rgbaColor[0], rgbaColor[1], rgbaColor[2], rgbaColor[3]); } const float normal[3] = { 0.0, 0.0, 1.0 }; const float* xyz = cd->getXYZ(); vertices.push_back(coordinates.getNumberOfCoordinates()); addCoordinate(xyz, rgbaColor, normal); /* pointColors.push_back(rgbaColor[0]); pointColors.push_back(rgbaColor[1]); pointColors.push_back(rgbaColor[2]); pointColors.push_back(rgbaColor[3]); pointNormals.push_back(0.0); pointNormals.push_back(0.0); pointNormals.push_back(1.0); */ } } /** * Constructor - converts foci to VTK vertices. */ VtkModelFile::VtkModelFile(const FociFile* foci, const FociColorFile* colors) : AbstractFile("VTK Model File", SpecFile::getVtkModelFileExtension(), false, AbstractFile::FILE_FORMAT_ASCII, FILE_IO_READ_AND_WRITE, FILE_IO_NONE, FILE_IO_READ_AND_WRITE, FILE_IO_NONE) { clear(); if (foci == NULL) { return; } const int numFoci = foci->getNumberOfCells(); for (int i = 0; i < numFoci; i++) { const CellData* cd = foci->getCell(i); unsigned char rgbaColor[4] = { 170, 170, 170, 255 }; const int colorIndex = cd->getColorIndex(); if ((colorIndex >= 0) && (colorIndex < colors->getNumberOfColors())) { colors->getColorByIndex(colorIndex, rgbaColor[0], rgbaColor[1], rgbaColor[2], rgbaColor[3]); } const float normal[3] = { 0.0, 0.0, 0.0 }; const float* xyz = cd->getXYZ(); vertices.push_back(coordinates.getNumberOfCoordinates()); addCoordinate(xyz, rgbaColor, normal); /* pointColors.push_back(rgbaColor[0]); pointColors.push_back(rgbaColor[1]); pointColors.push_back(rgbaColor[2]); pointColors.push_back(rgbaColor[3]); pointNormals.push_back(0.0); pointNormals.push_back(0.0); pointNormals.push_back(1.0); */ } } /** * Destructor. */ VtkModelFile::~VtkModelFile() { clear(); } /** * add a coordinate. */ void VtkModelFile::addCoordinate(const float xyz[3], const unsigned char* rgbaColorIn, const float* normalIn) { vertices.push_back(coordinates.getNumberOfCoordinates()); coordinates.addCoordinate(xyz); unsigned char rgbaColor[4] = { 170, 170, 170, 255 }; if (rgbaColorIn != NULL) { rgbaColor[0] = rgbaColorIn[0]; rgbaColor[1] = rgbaColorIn[1]; rgbaColor[2] = rgbaColorIn[2]; rgbaColor[3] = rgbaColorIn[3]; } pointColors.push_back(rgbaColor[0]); pointColors.push_back(rgbaColor[1]); pointColors.push_back(rgbaColor[2]); pointColors.push_back(rgbaColor[3]); float normal[3] = { 0.0, 0.0, 1.0 }; if (normalIn != NULL) { normal[0] = normalIn[0]; normal[1] = normalIn[1]; normal[2] = normalIn[2]; } pointNormals.push_back(normal[0]); pointNormals.push_back(normal[1]); pointNormals.push_back(normal[2]); } /** * Clears current file data in memory. */ void VtkModelFile::clear() { clearAbstractFile(); coordinates.clear(); triangles.clear(); vertices.clear(); lines.clear(); polygons.clear(); pointNormals.clear(); pointColors.clear(); displayFlag = true; } /** * returns true if the file is isEmpty. */ bool VtkModelFile::empty() const { return coordinates.empty(); } /** * apply a transformation matrix to the vtk model coordinates. */ void VtkModelFile::applyTransformationMatrix(const TransformationMatrix& matrix) { coordinates.applyTransformationMatrix(matrix); setModified(); } /** * read the file (overridden since file has no header). */ void VtkModelFile::readFile(const QString& fileNameIn) throw (FileException) { clear(); if (fileNameIn.isEmpty()) { throw FileException(fileNameIn, "Filename for reading is isEmpty"); } filename = fileNameIn; QTime timer; timer.start(); vtkPolyData* polyData = NULL; // // See which type of VTK file to read // vtkPolyDataReader* vtkReader = NULL; vtkXMLPolyDataReader* xmlReader = NULL; if (FileUtilities::filenameExtension(filename) == "vtk") { // // Read normal VTK file // vtkReader = vtkPolyDataReader::New(); vtkReader->SetFileName((char*)filename.toAscii().constData()); vtkReader->Update(); polyData = vtkReader->GetOutput(); } else if (FileUtilities::filenameExtension(filename) == "vtp") { // // Read XML VTK file // xmlReader = vtkXMLPolyDataReader::New(); xmlReader->SetFileName((char*)filename.toAscii().constData()); xmlReader->Update(); polyData = xmlReader->GetOutput(); } else { QString msg("Unrecognized extension neither of \"vtk\" nor \"vtp\"."); throw FileException(filename, msg); } if (polyData != NULL) { readPolyData(polyData); //polyData->Delete(); } timeToReadFileInSeconds = static_cast(timer.elapsed()) / 1000.0; QFileInfo fi(filename); const float fileSize = fi.size() / 1048576.0; if (DebugControl::getDebugOn() || DebugControl::getFileReadTimingFlag()) { std::cout << "Time to read " << FileUtilities::basename(getFileName()).toAscii().constData() << " (" << fileSize << " MB) was " << timeToReadFileInSeconds << " seconds." << std::endl; } // // Free up memory // if (vtkReader != NULL) { vtkReader->Delete(); } if (xmlReader != NULL) { xmlReader->Delete(); } } /** * read in the model from vtk poly data. */ void VtkModelFile::readPolyData(vtkPolyData* polyData) { const int numPoints = polyData->GetNumberOfPoints(); if (numPoints <= 0) { throw FileException(filename, "contains no points."); } // // Convert any triangle strips to triangles // vtkTriangleFilter* triangleFilter = NULL; if (polyData->GetNumberOfStrips() > 0) { triangleFilter = vtkTriangleFilter::New(); triangleFilter->SetInput(polyData); triangleFilter->Update(); polyData = triangleFilter->GetOutput(); } // // Compute normals // vtkPolyDataNormals* polyNormals = vtkPolyDataNormals::New(); polyNormals->SetInput(polyData); polyNormals->SplittingOff(); polyNormals->ConsistencyOn(); polyNormals->ComputePointNormalsOn(); polyNormals->NonManifoldTraversalOn(); polyNormals->Update(); polyData = polyNormals->GetOutput(); // // Read in the points // coordinates.setNumberOfCoordinates(numPoints); vtkPoints* points = polyData->GetPoints(); for (int i = 0; i < numPoints; i++) { #ifdef HAVE_VTK5 double xyz[3]; #else // HAVE_VTK5 float xyz[3]; #endif // HAVE_VTK5 points->GetPoint(i, xyz); coordinates.setCoordinate(i, xyz); } coordinates.clearModified(); // // Get the point normals // pointNormals.resize(numPoints * 3); vtkPointData* pointData = polyData->GetPointData(); vtkDataArray* normals = pointData->GetNormals(); if ((normals->GetNumberOfTuples() == numPoints) && (normals->GetNumberOfComponents() == 3)) { for (int i = 0; i < numPoints; i++) { #ifdef HAVE_VTK5 const double* xyz = normals->GetTuple3(i); #else // HAVE_VTK5 const float* xyz = normals->GetTuple3(i); #endif // HAVE_VTK5 pointNormals[i * 3] = xyz[0]; pointNormals[i * 3 + 1] = xyz[1]; pointNormals[i * 3 + 2] = xyz[2]; } } else { std::cout << "Normals failed for VTK model: " << filename.toAscii().constData() << std::endl; for (int i = 0; i < numPoints; i++) { pointNormals[i * 3] = 0.0; pointNormals[i * 3 + 1] = 0.0; pointNormals[i * 3 + 2] = 1.0; } } // // Read in the vertices // const int numVertices = polyData->GetNumberOfVerts(); if (numVertices > 0) { vtkCellArray* verts = polyData->GetVerts(); vtkIdType npts; vtkIdType* pts; for (verts->InitTraversal(); verts->GetNextCell(npts, pts); ) { for (int i = 0; i < npts; i++) { vertices.push_back(pts[i]); } } } // // Read in the lines // const int numLines = polyData->GetNumberOfLines(); if (numLines > 0) { vtkCellArray* cellLines = polyData->GetLines(); vtkIdType npts; vtkIdType* pts; for (cellLines->InitTraversal(); cellLines->GetNextCell(npts, pts); ) { if (npts > 0) { int npts2 = npts; int* pts2 = new int[npts2]; for (int k = 0; k < npts2; k++) { pts2[k] = pts[k]; } delete[] pts2; lines.push_back(VtkModelObject(pts2, npts2)); } } } // // Read in the polygons (convert triangle strips to triangles if needed) // vtkCellArray* polys = polyData->GetPolys(); const int numPolys = polyData->GetNumberOfPolys(); if (numPolys > 0) { vtkIdType npts; vtkIdType* pts; for (polys->InitTraversal(); polys->GetNextCell(npts,pts); ) { if (npts == 3) { triangles.push_back(pts[0]); triangles.push_back(pts[1]); triangles.push_back(pts[2]); } else if (npts > 3) { int* pp = new int[npts*3]; for (int k = 0; k < npts*3; k++) { pp[k] = pts[k]; } polygons.push_back(VtkModelObject(pp, static_cast(npts))); delete[] pp; } } } // // Allocate and Read in the colors // pointColors.resize(numPoints * 4, 170); for (int i = 0; i < numPoints; i++) { pointColors[i*4] = 255; } vtkDataArray* scalars = pointData->GetScalars(); if (scalars != NULL) { if ( (scalars->GetDataType() == VTK_UNSIGNED_CHAR) && (scalars->GetNumberOfComponents() == 3) ) { vtkUnsignedCharArray* colors = (vtkUnsignedCharArray*)scalars; for (int i = 0; i < numPoints; i++) { #ifdef HAVE_VTK5 double rgb[3]; #else // HAVE_VTK5 float rgb[3]; #endif // HAVE_VTK5 colors->GetTuple(i, rgb); const unsigned char rgbaChar[4] = { static_cast(rgb[0]), static_cast(rgb[1]), static_cast(rgb[2]), 255 }; setPointColor(i, rgbaChar); } } if ( (scalars->GetDataType() == VTK_UNSIGNED_CHAR) && (scalars->GetNumberOfComponents() == 4) ) { vtkUnsignedCharArray* colors = (vtkUnsignedCharArray*)scalars; for (int i = 0; i < numPoints; i++) { #ifdef HAVE_VTK5 double rgba[4] = { 170, 170, 170, 255 }; #else // HAVE_VTK5 float rgba[4] = { 170, 170, 170, 255 }; #endif // HAVE_VTK5 colors->GetTuple(i, rgba); const unsigned char rgbaChar[4] = { static_cast(rgba[0]), static_cast(rgba[1]), static_cast(rgba[2]), static_cast(rgba[3]) }; setPointColor(i, rgbaChar); } } else if ( (scalars->GetDataType() == VTK_FLOAT) && (scalars->GetNumberOfComponents() == 1) ) { float maxValue = -100000.0; for (int j = 0; j < numPoints; j++) { if (scalars->GetComponent(j, 0) > maxValue) { maxValue = scalars->GetComponent(j, 0); } } vtkLookupTable* lookupTable = scalars->GetLookupTable(); for (int i = 0; i < numPoints; i++) { const float value = scalars->GetComponent(i, 0); if (lookupTable == NULL) { const unsigned char rgbaChar[4] = { static_cast(value), static_cast(value), static_cast(value), 255 }; setPointColor(i, rgbaChar); } else { #ifdef HAVE_VTK5 double rgb[3] = { 0.0, 0.0, 0.0 }; lookupTable->GetColor((double)value, rgb); #else // HAVE_VTK5 float rgb[3] = { 0.0, 0.0, 0.0 }; lookupTable->GetColor((float)value, rgb); #endif // HAVE_VTK5 const unsigned char rgbaChar[4] = { static_cast(rgb[0]), static_cast(rgb[1]), static_cast(rgb[2]), 255 }; setPointColor(i, rgbaChar); } } } } polyNormals->Delete(); clearModified(); if (triangleFilter != NULL) { triangleFilter->Delete(); } } /** * get the RGB colors for a point. */ const unsigned char* VtkModelFile::getPointColor(const int indx) const { if ((indx >= 0) && (indx < getNumberOfPoints())) { return &pointColors[indx * 4]; } static unsigned char dummy[4] = { 170, 170, 170, 255 }; return dummy; } /** * get the normal vector for a point. */ const float* VtkModelFile::getPointNormal(const int indx) const { if ((indx >= 0) && (indx < getNumberOfPoints())) { return &pointNormals[indx * 3]; } static float dummy[3] = { 0.0, 0.0, 1.0 }; return dummy; } /** * set the RGB colors for a point. */ void VtkModelFile::setPointColor(const int indx, const unsigned char rgba[4]) { if ((indx >= 0) && (indx < getNumberOfPoints())) { pointColors[indx * 4] = rgba[0]; pointColors[indx * 4 + 1] = rgba[1]; pointColors[indx * 4 + 2] = rgba[2]; pointColors[indx * 4 + 3] = rgba[3]; setModified(); } } /** * set the entire model to a specific color. */ void VtkModelFile::setToSolidColor(const unsigned char rgba[4]) { const int num = getNumberOfPoints(); for (int i = 0; i < num; i++) { setPointColor(i, rgba); } } /** * get a vertex (pointer to its "point" indices). */ const int* VtkModelFile::getVertex(const int indx) const { return &vertices[indx]; } /** * get a vertex (pointer to its 3 "point" indices). */ const int* VtkModelFile::getTriangle(const int indx) const { return &triangles[indx*3]; } /** * get a triangles 3D position (average of its coordinates). */ void VtkModelFile::getTriangleCoordinate(const int indx, float coord[3]) const { if ((indx >= 0) && (indx < getNumberOfTriangles())) { const int* tri = getTriangle(indx); const CoordinateFile* cf = getCoordinateFile(); const float* v1 = cf->getCoordinate(tri[0]); const float* v2 = cf->getCoordinate(tri[1]); const float* v3 = cf->getCoordinate(tri[2]); coord[0] = (v1[0] + v2[0] + v3[0]) / 3.0; coord[1] = (v1[1] + v2[1] + v3[1]) / 3.0; coord[2] = (v1[2] + v2[2] + v3[2]) / 3.0; } else { coord[0] = 0.0; coord[1] = 0.0; coord[2] = 0.0; } } /** * get a line. */ const VtkModelFile::VtkModelObject* VtkModelFile::getLine(const int indx) const { return &lines[indx]; } /** * get a polygon. */ const VtkModelFile::VtkModelObject* VtkModelFile::getPolygon(const int indx) const { return &polygons[indx]; } /** * write the file. */ void VtkModelFile::writeFile(const QString& fileNameIn) throw (FileException) { if (fileNameIn.isEmpty()) { throw FileException(fileNameIn, "Filename for reading is isEmpty"); } filename = fileNameIn; // // Write points // vtkPoints* pointData = vtkPoints::New(); const int numCoords = coordinates.getNumberOfCoordinates(); for (int i = 0; i < numCoords; i++) { pointData->InsertPoint(i, coordinates.getCoordinate(i)); } // // Write normals // vtkFloatArray* normalsVTK = vtkFloatArray::New(); normalsVTK->SetNumberOfTuples(numCoords); normalsVTK->SetNumberOfComponents(3); for (int i = 0; i < numCoords; i++) { normalsVTK->InsertTuple(i, getPointNormal(i)); } // // Write triangles & polygons // vtkCellArray* polysVTK = NULL; const int numTriangles = getNumberOfTriangles(); if (numTriangles > 0) { if (polysVTK == NULL) { polysVTK = vtkCellArray::New(); } //int size = trianglesVTK->EstimateSize(numTriangles, 3); //polysVTK->Allocate(size, 25); for (int j = 0; j < numTriangles; j++) { const int* v = getTriangle(j); vtkIdType v2[3] = { v[0], v[1], v[2] }; polysVTK->InsertNextCell(static_cast(3), v2); } } const int numPolys = getNumberOfPolygons(); if (numPolys > 0) { if (polysVTK == NULL) { polysVTK = vtkCellArray::New(); } for (int j = 0; j < numPolys; j++) { const VtkModelObject* vmo = getPolygon(j); vtkIdType num = vmo->getNumberOfItems(); if (num > 0) { vtkIdType* pts = new vtkIdType[num*3]; for (int k = 0; k < num; k++) { const int* pp = vmo->getPointIndex(0); for (int m = 0; m < 3; m++) { pts[k*3+m] = pp[m]; } } polysVTK->InsertNextCell(num, pts); delete[] pts; } } } // // Write lines // const int numLines = getNumberOfLines(); vtkCellArray* linesVTK = NULL; if (numLines > 0) { linesVTK = vtkCellArray::New(); //int size = linesVTK->EstimateSize(numLines, 2); for (int j = 0; j < numLines; j++) { const VtkModelObject* vmo = getLine(j); vtkIdType num = vmo->getNumberOfItems(); if (num > 0) { vtkIdType* pts = new vtkIdType[num*3]; for (int k = 0; k < num; k++) { const int* pp = vmo->getPointIndex(0); for (int m = 0; m < 3; m++) { pts[k*3+m] = pp[m]; } } linesVTK->InsertNextCell(num, pts); } } } // // Write the vertices // const int numVerts = getNumberOfVertices(); vtkCellArray* vertsVTK = NULL; if (numVerts > 0) { vertsVTK = vtkCellArray::New(); for (int j = 0; j < numVerts; j++) { const int* v = getVertex(j); vtkIdType v2[3] = { v[0], v[1], v[2] }; vertsVTK->InsertNextCell(static_cast(1), v2); } } // // Write colors // vtkUnsignedCharArray* colorsVTK = vtkUnsignedCharArray::New(); colorsVTK->SetNumberOfComponents(4); colorsVTK->SetNumberOfTuples(numCoords); for (int i = 0; i < numCoords; i++) { const unsigned char* rgba = getPointColor(i); float floatRGBA[4] = { rgba[0], rgba[1], rgba[2], rgba[3] }; colorsVTK->InsertTuple(i, floatRGBA); } // // Create the polydata // vtkPolyData* polyData = vtkPolyData::New(); polyData->SetPoints(pointData); pointData->Delete(); polyData->GetPointData()->SetScalars(colorsVTK); colorsVTK->Delete(); polyData->GetPointData()->SetNormals(normalsVTK); normalsVTK->Delete(); if (vertsVTK != NULL) { polyData->SetVerts(vertsVTK); vertsVTK->Delete(); } if (linesVTK != NULL) { polyData->SetLines(linesVTK); linesVTK->Delete(); } if (polysVTK != NULL) { polyData->SetPolys(polysVTK); polysVTK->Delete(); } if (FileUtilities::filenameExtension(filename) == "vtp") { vtkXMLPolyDataWriter *writer = vtkXMLPolyDataWriter::New(); writer->SetInput(polyData); //writer->SetHeader("Written by Caret"); writer->SetFileName((char*)filename.toAscii().constData()); writer->Write(); writer->Delete(); } else { vtkPolyDataWriter *writer = vtkPolyDataWriter::New(); writer->SetInput(polyData); writer->SetHeader("Written by Caret"); writer->SetFileName((char*)filename.toAscii().constData()); writer->Write(); writer->Delete(); } polyData->Delete(); clearModified(); } /** * Read the vtk model file data (should never be called). */ void VtkModelFile::readFileData(QFile& /*file*/, QTextStream& /*stream*/, QDataStream&, QDomElement& /* rootElement */) throw (FileException) { throw FileException(filename, "Program Error: VtkModelFile::readFileData should never be called."); } /** * Write the vtk model file data (should never be called). */ void VtkModelFile::writeFileData(QTextStream& /*stream*/, QDataStream&, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException) { throw FileException(filename, "Program Error: VtkModelFile::writeFileData should never be called."); } caret-5.6.4~dfsg.1.orig/caret_files/VoxelIJK.h0000664000175000017500000000500611572067322020646 0ustar michaelmichael #ifndef __VOXEL_IJK_H__ #define __VOXEL_IJK_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ /// Class for storing voxel indices class VoxelIJK { public: /// Constructor VoxelIJK() { ijkv[0] = -1; ijkv[1] = -1; ijkv[2] = -1; } /// Constructor VoxelIJK(const int i, const int j, const int k) { ijkv[0] = i; ijkv[1] = j; ijkv[2] = k; } /// Constructor VoxelIJK(const int ijkIn[3]) { ijkv[0] = ijkIn[0]; ijkv[1] = ijkIn[1]; ijkv[2] = ijkIn[2]; } /// get the voxel indices const int* getIJK() const { return &ijkv[0]; } /// get the I component int getI() const { return ijkv[0]; } /// get the J component int getJ() const { return ijkv[1]; } /// get the K component int getK() const { return ijkv[2]; } /// get the voxel indices void getIJK(int& i, int& j, int& k) const { i = ijkv[0]; j = ijkv[1]; k = ijkv[2]; } /// get the voxel indices void getIJK(int ijkOut[3]) const { ijkOut[0] = ijkv[0]; ijkOut[1] = ijkv[1]; ijkOut[2] = ijkv[2]; } /// set the voxel indices void setIJK(const int ijkIn[3]) { ijkv[0] = ijkIn[0]; ijkv[1] = ijkIn[1]; ijkv[2] = ijkIn[2]; } /// get the voxel indices void setIJK(const int i, const int j, const int k) { ijkv[0] = i; ijkv[1] = j; ijkv[2] = k; } protected: /// the voxel indices int ijkv[3]; friend class VolumeFile; }; #endif // __VOXEL_IJK_H__ caret-5.6.4~dfsg.1.orig/caret_files/VolumeModification.h0000664000175000017500000000656011572067322023016 0ustar michaelmichael#ifndef __VOLUME_MODIFICATION_H__ #define __VOLUME_MODIFICATION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include class VolumeFile; /// This class tracks the change to a single voxel class VoxelModified { public: /// constructor VoxelModified(const int ijkIn[3], const float valueIn, const unsigned char colorIn[4]) { ijk[0] = ijkIn[0]; ijk[1] = ijkIn[1]; ijk[2] = ijkIn[2]; value = valueIn; color[0] = colorIn[0]; color[1] = colorIn[1]; color[2] = colorIn[2]; color[3] = colorIn[3]; } /// destructor ~VoxelModified() { } /// get the voxel's IJK index const int* getIJK() const { return ijk; } /// get the voxels value float getVoxelValue() const { return value; } /// get the voxel's coloring const unsigned char* getVoxelColor() const { return color; } protected: /// voxel indices int ijk[3]; /// value of voxel float value; /// color of voxel unsigned char color[4]; friend class VolumeModification; }; /// This class tracks voxels changed when a volume is modified class VolumeModification { public: /// Constructor VolumeModification(); /// Destructor ~VolumeModification(); /// add a voxel (use colorVolumeIn if you want the voxels and color take from another volume) void addVoxel(VolumeFile* vf, const int ijk[3], VolumeFile* colorVolumeIn = NULL); /// add a voxel (use colorVolumeIn if you want the voxels and color take from another volume) void addVoxel(VolumeFile* vf, const int i, const int j, const int k, VolumeFile* colorVolumeIn = NULL); /// add a voxel void addVoxel(const VoxelModified& vm); /// get the number of voxels in this change int getNumberOfVoxels() const { return voxels.size(); } /// get modified voxels const VoxelModified* getModifiedVoxel(const int indx) const; /// get the memory required to store the modification int getMemorySize() const; protected: /// voxels involved in this change std::vector voxels; }; #endif // __VOLUME_MODIFICATION_H__ caret-5.6.4~dfsg.1.orig/caret_files/VolumeModification.cxx0000664000175000017500000000442411572067322023366 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "VolumeFile.h" #include "VolumeModification.h" /** * Constructor. */ VolumeModification::VolumeModification() { } /** * Destructor. */ VolumeModification::~VolumeModification() { voxels.clear(); } /** * add a voxel. */ void VolumeModification::addVoxel(VolumeFile* vf, const int ijk[3], VolumeFile* colorVolumeIn) { if (vf->getVoxelIndexValid(ijk)) { VolumeFile* colorVolume = vf; if (colorVolumeIn != NULL) { colorVolume = colorVolumeIn; } float value = colorVolume->getVoxel(ijk); unsigned char color[4]; colorVolume->getVoxelColor(ijk, color); addVoxel(VoxelModified(ijk, value, color)); } } /** * add a voxel. */ void VolumeModification::addVoxel(VolumeFile* vf, const int i, const int j, const int k, VolumeFile* colorVolume) { const int ijk[3] = { i, j, k }; addVoxel(vf, ijk, colorVolume); } /** * add a voxel. */ void VolumeModification::addVoxel(const VoxelModified& vm) { voxels.push_back(vm); } /** * get modified voxels. */ const VoxelModified* VolumeModification::getModifiedVoxel(const int indx) const { return &voxels[indx]; } /** * get the memory required to store the modification. */ int VolumeModification::getMemorySize() const { const int memSize = getNumberOfVoxels() * sizeof(VoxelModified) + sizeof(std::vector); return memSize; } caret-5.6.4~dfsg.1.orig/caret_files/VolumeITKImage.h0000664000175000017500000000336411572067322022002 0ustar michaelmichael #ifndef __VOLUME_ITK_IMAGE_H__ #define __VOLUME_ITK_IMAGE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifdef HAVE_ITK #include "itkImage.h" #endif // HAVE_ITK // class for holding an ITK Image in memory class VolumeITKImage { public: // constructor VolumeITKImage(); // destructor ~VolumeITKImage(); #ifdef HAVE_ITK /// determine if ITK is supported static bool itkSupported() { return true; } /// A 3 dimensional floating point volume type typedef itk::Image ImageTypeFloat3; /// Smart pointer to a 3 dimensional floating point volume type typedef ImageTypeFloat3::Pointer ImagePointer; /// the image storage ImagePointer image; #else // HAVE_ITK /// determine if ITK is supported static bool itkSupported() { return false; } #endif // HAVE_ITK }; #endif // __VOLUME_ITK_IMAGE_H__ caret-5.6.4~dfsg.1.orig/caret_files/VolumeITKImage.cxx0000664000175000017500000000211511572067322022346 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "VolumeITKImage.h" /** * constructor. */ VolumeITKImage::VolumeITKImage() { #ifdef HAVE_ITK image = ImageTypeFloat3::New(); #endif } /** * destructor. */ VolumeITKImage::~VolumeITKImage() { } caret-5.6.4~dfsg.1.orig/caret_files/VolumeFile.h0000664000175000017500000020357411572067322021274 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VOLUME_FILE_NEW_H__ #define __VOLUME_FILE_NEW_H__ #include #include #include #include #include #include "AbstractFile.h" #include "AfniHeader.h" #include "FileException.h" #include "VoxelIJK.h" #include "StudyMetaDataLinkSet.h" #include "TransformationMatrixFile.h" #include "WuNilHeader.h" #include "zlib.h" class Border; class ParamsFile; class StatisticHistogram; class TransformationMatrix; class SureFitVectorFile; class VolumeModification; class VolumeITKImage; class vtkImageData; class vtkStructuredPoints; class vtkTransform; /// This class is used to store a volume and its attributes class VolumeFile : public AbstractFile { private: /// Volume data read mode enum VOLUME_DATA_READ_MODE { VOLUME_DATA_READ_WITH_STDLIB, // read with C++ Standard Library VOLUME_DATA_READ_WITH_ZLIB // read with ZLIB }; public: /// group of voxels class VoxelGroup { public: /// constructor VoxelGroup() { } /// destructor ~VoxelGroup() { clear(); } /// add a voxel void addVoxel(const VoxelIJK& v) { voxels.push_back(v); } /// clear the voxel group void clear() { voxels.clear(); } /// get the number of voxels in the group int getNumberOfVoxels() const { return voxels.size(); } /// get a voxel in the group VoxelIJK getVoxel(const int indx) const { return voxels[indx]; } protected: /// the voxels std::vector voxels; }; /// type of volume enum VOLUME_TYPE { /// anatomical volume VOLUME_TYPE_ANATOMY, /// functional volume VOLUME_TYPE_FUNCTIONAL, /// paint volume VOLUME_TYPE_PAINT, /// probabilistic atals volume VOLUME_TYPE_PROB_ATLAS, /// Red-Green-Blue volume VOLUME_TYPE_RGB, /// segmentation volume VOLUME_TYPE_SEGMENTATION, /// vector volume file VOLUME_TYPE_VECTOR, /// region of interest selected voxel VOLUME_TYPE_ROI, /// unknown volume VOLUME_TYPE_UNKNOWN }; /// Type of volume space enum VOLUME_SPACE { /// volume is read and manipulated to be LPI VOLUME_SPACE_COORD_LPI, /// volume is read and left in "voxel native space" VOLUME_SPACE_VOXEL_NATIVE }; /// Volume file type enum FILE_READ_WRITE_TYPE { /// raw FILE_READ_WRITE_TYPE_RAW, /// AFNI FILE_READ_WRITE_TYPE_AFNI, /// Analyze FILE_READ_WRITE_TYPE_ANALYZE, /// NIFTI FILE_READ_WRITE_TYPE_NIFTI, /// NIFTI GZIPped FILE_READ_WRITE_TYPE_NIFTI_GZIP, /// SPM/MEDx FILE_READ_WRITE_TYPE_SPM_OR_MEDX, /// WU IFH FILE_READ_WRITE_TYPE_WUNIL, /// UNKNOWN FILE_READ_WRITE_TYPE_UNKNOWN }; /// axis enum VOLUME_AXIS { /// X-axis VOLUME_AXIS_X, /// Y-axis VOLUME_AXIS_Y, /// Z-axis VOLUME_AXIS_Z, /// all axes VOLUME_AXIS_ALL, /// oblique axis VOLUME_AXIS_OBLIQUE, /// oblique axis X VOLUME_AXIS_OBLIQUE_X, /// oblique axis Y VOLUME_AXIS_OBLIQUE_Y, /// oblique axis Z VOLUME_AXIS_OBLIQUE_Z, /// oblique all axes VOLUME_AXIS_OBLIQUE_ALL, /// Unknown-axis VOLUME_AXIS_UNKNOWN }; /// voxel data type enum VOXEL_DATA_TYPE { /// data type unknown VOXEL_DATA_TYPE_UNKNOWN, /// data type char VOXEL_DATA_TYPE_CHAR, /// data type unsigned char VOXEL_DATA_TYPE_CHAR_UNSIGNED, /// data type short VOXEL_DATA_TYPE_SHORT, /// data type unsigned short VOXEL_DATA_TYPE_SHORT_UNSIGNED, /// data type int VOXEL_DATA_TYPE_INT, /// data type unsigned int VOXEL_DATA_TYPE_INT_UNSIGNED, /// data type long VOXEL_DATA_TYPE_LONG, /// data type unsigned long VOXEL_DATA_TYPE_LONG_UNSIGNED, /// data type float VOXEL_DATA_TYPE_FLOAT, /// data type double VOXEL_DATA_TYPE_DOUBLE, /// data type RGB voxel interleaved VOXEL_DATA_TYPE_RGB_VOXEL_INTERLEAVED, /// data type RGB slice interleaved VOXEL_DATA_TYPE_RGB_SLICE_INTERLEAVED, /// data type vector VOXEL_DATA_TYPE_VECTOR }; /// volume file orientation enum ORIENTATION { /// orientation - unknown ORIENTATION_UNKNOWN, /// orientation - right to left ORIENTATION_RIGHT_TO_LEFT, /// orientation - left to right ORIENTATION_LEFT_TO_RIGHT, /// orientation - posterior to anterior ORIENTATION_POSTERIOR_TO_ANTERIOR, /// orientation - anterior to posterior ORIENTATION_ANTERIOR_TO_POSTERIOR, /// orientation - inferior to superior ORIENTATION_INFERIOR_TO_SUPERIOR, /// orientation - superior to inferior ORIENTATION_SUPERIOR_TO_INFERIOR }; /* /// standard volume spaces (DO NOT REARRANGE, add new spaces before "LAST") enum STANDARD_VOLUME_SPACE { /// non-standard volume space STANDARD_VOLUME_SPACE_NON_STANDARD, /// AFNI-TLRC volume space STANDARD_VOLUME_SPACE_AFNI_TALAIRACH, /// WU 111 volume space STANDARD_VOLUME_SPACE_WU_7112B_111, /// WU 222 volume space STANDARD_VOLUME_SPACE_WU_7112B_222, /// WU 333 volume space STANDARD_VOLUME_SPACE_WU_7112B_333, /// SPM Default volume space STANDARD_VOLUME_SPACE_SPM_DEFAULT, /// SPM Template volume space STANDARD_VOLUME_SPACE_SPM_TEMPLATE, /// number of volume space STANDARD_SPACE_LAST }; */ /// mathematical operations on volumes enum VOLUME_MATH_OPERATION { /// math operation ADD VOLUME_MATH_OPERATION_ADD, /// math operation AND VOLUME_MATH_OPERATION_AND, /// math operation SUBTRACT VOLUME_MATH_OPERATION_SUBTRACT, /// math operation MULTIPLY VOLUME_MATH_OPERATION_MULTIPLY, /// math operation DIVIDE VOLUME_MATH_OPERATION_DIVIDE, /// math operation OR VOLUME_MATH_OPERATION_OR, /// math operation SUBTRACT POSITIVE (if (result < 0) result = 0) VOLUME_MATH_OPERATION_SUBTRACT_POSITIVE, /// math operation MAX VOLUME_MATH_OPERATION_MAX, /// math operation DIFF_RATIO VOLUME_MATH_OPERATION_DIFFRATIO, /// math operation SQRT VOLUME_MATH_OPERATION_SQRT, /// math operation combine paint volumes VOLUME_MATH_OPERATION_COMBINE_PAINT, /// math operation NOR VOLUME_MATH_OPERATION_NOR, /// math operation NAND VOLUME_MATH_OPERATION_NAND, /// math operation AVERAGE VOLUME_MATH_OPERATION_AVERAGE, /// math operation EXCLUSIVE OR VOLUME_MATH_EXCLUSIVE_OR }; /// operations on segmentation volumes enum SEGMENTATION_OPERATION { /// segmenation operation dilate SEGMENTATION_OPERATION_DILATE, /// segmenation operation erode SEGMENTATION_OPERATION_ERODE, /// segmenation operation flood fill 2D SEGMENTATION_OPERATION_FLOOD_FILL_2D, /// segmenation operation flood fill 3D SEGMENTATION_OPERATION_FLOOD_FILL_3D, /// segmenation operation remove connected piece in 2D SEGMENTATION_OPERATION_REMOVE_CONNECTED_2D, /// segmenation operation remove connected piece in 3D SEGMENTATION_OPERATION_REMOVE_CONNECTED_3D, /// segmenation operation turn voxels on SEGMENTATION_OPERATION_TOGGLE_ON, /// segmenation operation turn voxels off SEGMENTATION_OPERATION_TOGGLE_OFF }; /// sculpt mode enum SCULPT_MODE { /// sculpt mode AND SCULPT_MODE_AND, /// sculpt mode SEED AND SCULPT_MODE_SEED_AND, /// sculpt mode AND NOT SCULPT_MODE_AND_NOT, /// sculpt mode SEED AND NOT SCULPT_MODE_SEED_AND_NOT }; /// voxel search flags enum VOXEL_SEARCH_STATUS { /// voxel not searched VOXEL_NOT_SEARCHED = 0, /// voxel has been searched VOXEL_SEARCHED = 1 }; /// voxel coloring status enum VOXEL_COLOR_STATUS { /// voxel color invalid VOXEL_COLOR_STATUS_INVALID, /// voxel color valid and voxel should be displayed VOXEL_COLOR_STATUS_VALID, /// voxel color valid but voxel should not be displayed VOXEL_COLOR_STATUS_VALID_DO_NOT_SHOW_VOXEL }; /// volume reading selections enum VOLUME_READING_SELECTION { /// read all sub volumes VOLUME_READ_SELECTION_ALL = -1, /// read header only VOLUME_READ_HEADER_ONLY = -2 }; /// data order in slices enum SLICE_DATA_ORDER { /// increment column fastest SLICE_DATA_ORDER_COLUMN, /// increment row fastest SLICE_DATA_ORDER_ROW }; /// interpolation type enum INTERPOLATION_TYPE { /// interpolation type cubic INTERPOLATION_TYPE_CUBIC, /// interpolation type linear INTERPOLATION_TYPE_LINEAR, /// interpolation type nearest neighbor (use for paint and atlas volumes) INTERPOLATION_TYPE_NEAREST_NEIGHBOR }; /// get the name of the file (description only used if file name is isEmpty) virtual QString getFileName(const QString& description = "") const; /// get type of volume space used when volume files are read static VOLUME_SPACE getVolumeSpace() { return volumeSpace; } /// set type of volume space used when volume files are read static void setVolumeSpace(const VOLUME_SPACE vs) { volumeSpace = vs; } /* /// get name, dimensions, origin, and voxel spacing for standard volumes static void getStandardSpaceParameters(const STANDARD_VOLUME_SPACE svs, QString& nameOut, int dimensionOut[3], float originOut[3], float voxelSpacingOut[3]); */ /// constructor VolumeFile(); /// construct a volume consisting of a single slice /// copy constructor VolumeFile(const VolumeFile& vf); /// constructor creates volume from a vector file VolumeFile(const SureFitVectorFile& vf); /// destructor ~VolumeFile(); /// Assignment operator. VolumeFile& operator=(const VolumeFile& vf); /// initialize (allocates memory for a volume of specified type and dimensions) void initialize(const VOXEL_DATA_TYPE vdt, const int dim[3], const ORIENTATION orient[3], const float org[3], const float space[3], const bool doClear = false, const bool allocateVoxelData = true); /// compare a file for unit testing (returns true if "within tolerance") bool compareFileForUnitTesting(const AbstractFile* af, const float tolerance, QString& messageOut) const; /// get axis from string static VOLUME_AXIS getAxisFromString(const QString& s); /// Get the label of an axis enumerated type. static QString getAxisLabel(const VOLUME_AXIS axis); /// get the label of an orientations static QString getOrientationLabel(const ORIENTATION orient); /// see if a file is a NIFTI volume file static bool isFileNifti(const QString& name); /// get NIFTI intention and tr void getNiftiInfo(QString& intentCodeAndParamStringOut, QString& intentNameOut, int& intentCodeOut, float& intentParameter1Out, float& intentParameter2Out, float& intentParameter3Out, float &trOut) const; /// get the string describing the type of volume (anatomy, functional, etc) QString getVolumeTypeDescription() const; /// get the minimum and maximum values for a data type static void getDataTypeMinMaxValues(const VOXEL_DATA_TYPE vdt, double& minValueForDataType, double& maxValueForDataType); /// get all volume types and names (anatomy, functional, etc) static void getAllVolumeTypesAndNames(std::vector& typesOut, std::vector& namesOut, const bool addUnknown = false, const bool addROI = false); /// get all voxel data types and names (float, int, etc) static void getAllVoxelDataTypesAndNames(std::vector& typesOut, std::vector& namesOut, const bool addUnknown = false); /// Clears current file data in memory. void clear(); /// resize the volume; if provided, update params with cropping void resize(const int dimExtent[6], ParamsFile* paramsFile = NULL); /// pad segmentation volume void padSegmentation(const int padding[6], const bool erodePaddingFlag); /// copy a subvolume to "this" volume void copySubVolume(const VolumeFile* sourceVolume, const int extent[6], const unsigned char offRgbValue[4], const unsigned char onRgbValue[4], VolumeModification* modifiedVoxels = NULL) throw (FileException); /// copy a slice to "this" volume void copySlice(const VolumeFile* sourceVolume, const int sourceSliceNumber, const VOLUME_AXIS axis, const int destinationSliceNumber); /// get the volume type VOLUME_TYPE getVolumeType() const { return volumeType; } /// set the volume type void setVolumeType(const VOLUME_TYPE vt) { volumeType = vt; }; /// returns true if the file is isEmpty bool empty() const { return (voxels == NULL); } /// get the afni header AfniHeader* getAfniHeader() { return &afniHeader; } /// get the wu-nil header WuNilHeader* getWuNilHeader() { return &wunilHeader; } /// get the volume data (const method) const float* getVoxelData() const { return voxels; } /// get the coordinate at the center of the voxel void getVoxelCoordinate(const int ijk[3], float coord[3]) const; /// get the coordinate at the center of the voxel void getVoxelCoordinate(const int i, const int j, const int k, float coord[3]) const; /// get the coordinate at the center of the voxel void getVoxelCoordinate(const VoxelIJK& v, float coord[3]) const; /// get the volume data float* getVoxelData() { return voxels; } /// get a voxel with a flat index float getVoxelWithFlatIndex(const int indx, const int component = 0) const; /// set a voxel with a flat index void setVoxelWithFlatIndex(const int indx, const int component, const float value); /// get a voxel float getVoxel(const int i, const int j, const int k, const int component = 0) const; /// get a voxel float getVoxel(const int ijk[3], const int component = 0) const; /// get a voxel float getVoxel(const VoxelIJK& v, const int component = 0) const; /// see if a voxel index is valid bool getVoxelIndexValid(const int ijk[3]) const; /// see if a voxel index is valid bool getVoxelIndexValid(const int i, const int j, const int k) const; /// see if a voxel index is valid bool getVoxelIndexValid(const VoxelIJK& v) const; /// get a voxel at the specified index bool getVoxelAllComponents(const int ijk[3], float* voxelValue) const; /// get a voxel at the specified index bool getVoxelAllComponents(const int i, const int j, const int k, float* voxelValue) const; /// set a voxel at the specified index void setVoxelAllComponents(const int ijk[3], const float* voxelValue); /// set a voxel at the specified index void setVoxelAllComponents(const int i, const int j, const int k, const float* voxelValue); /// set a voxel at the specified index void setVoxel(const int ijk[3], const int component, const float voxelValue); /// set a voxel at the specified index void setVoxel(const VoxelIJK& v, const int component, const float voxelValue); /// set a voxel at the specified index void setVoxel(const int i, const int j, const int k, const int component, const float voxelValue); /// set a bunch of voxels using one dimensional index void setVoxel(const std::vector indicies, const float voxelValue); /// set all of the voxels to a value void setAllVoxels(const float value); /// set all voxels within a rectangle void setAllVoxelsInRectangle(const int extent[6], const float value); /// set all of the voxels in a slice void setAllVoxelsInSlice(const VOLUME_AXIS axis, const int sliceNumber, const float value); /// get the size of a slice (number of voxels and components) int getSizeOfSlice(const VOLUME_AXIS axis) const; /// get a slice from a volume (sliceVoxelsOut should be size getSizeOfSlice()) void getSlice(const VOLUME_AXIS axis, const int sliceNumber, const SLICE_DATA_ORDER dataOrder, float* sliceVoxelsOut) const; /// set a slice from a volume (sliceVoxelsIn should be size getSizeOfSlice()) void setSlice(const VOLUME_AXIS axis, const int sliceNumber, const SLICE_DATA_ORDER dataOrder, const float* sliceVoxelsIn); /// get the number of non-zero voxels int getNumberOfNonZeroVoxels() const; /// set voxel coloring valid void setVoxelColoringInvalid() { voxelColoringValid = false; } /// set the colors for a voxel (4th byte is VOXEL_COLOR_STATUS) void setVoxelColor(const int ijk[3], const unsigned char rgb[4]); /// set the colors for a voxel (4th byte is VOXEL_COLOR_STATUS) void setVoxelColor(const int i, const int j, const int k, const unsigned char rgb[4]); /// get the colors at a voxel (returns true if a valid voxel index) bool getVoxelColor(const int ijk[3], unsigned char rgb[4]); /// get the colors at a voxel (returns true if a valid voxel index) bool getVoxelColor(const int i, const int j, const int k, unsigned char rgb[4]); /// Get an "interpolate" voxel at the specified coordinate bool getInterpolatedVoxel(const float xyz[3], float& voxelValue); /// get the voxel to surface distances (used by surface and volume rendering) float* getVoxelToSurfaceDistances(); /// get the voxel to surface distances valid bool getVoxelToSurfaceDistancesValid() const { return voxelToSurfaceDistancesValid; } /// set the voxel to surface distances valid void setVoxelToSurfaceDistancesValid(const bool valid) { voxelToSurfaceDistancesValid = valid; } /// get the data type VOXEL_DATA_TYPE getVoxelDataType() const { return voxelDataType; } /// set the data type void setVoxelDataType(const VOXEL_DATA_TYPE vdt); /// get the SPM ac position void getSpmAcPosition(float ac[3]) const; /// set the ac position void setSpmAcPosition(const float ac[3]); /// get the number of components per voxel int getNumberOfComponentsPerVoxel() const { return numberOfComponentsPerVoxel; } /// get the dimensions of the volume (const method) void getDimensions(int& dimX, int& dimY, int& dimZ) const; /// get the dimensions of the volume (const method) void getDimensions(int dim[3]) const; /// get the dimensions of the volume void getDimensions(int dim[3]); /// set the dimensions of the volume void setDimensions(const int dim[3]); /// get the origin at the corner of the first voxel void getOriginAtCornerOfVoxel(float originCornerOfVoxelOut[3]) const; /// set the origin at the corner of the first voxel void setOriginAtCornerOfVoxel(const float originCornerOfVoxelIn[3], const float voxelSizesIn[3]); /// get the origin (at the center of the first voxel) void getOrigin(float originOut[3]) const; /// set the origin (at the center of the first voxel) void setOrigin(const float originIn[3]); /// get the voxel spacing for the volume void getSpacing(float spacingOut[3]) const; /// set the voxel spacing for for the volume void setSpacing(const float spacingIn[3]); /// get the orientation void getOrientation(VolumeFile::ORIENTATION orient[3]) const; /// set the orientation void setOrientation(const VolumeFile::ORIENTATION orient[3]); /// Returns true if the orientation is valid, else false. static bool isValidOrientation(const VolumeFile::ORIENTATION orient[3]); /// Get the inverse orientation for an orientation (ie "left" is /// opposite of "right") static VolumeFile::ORIENTATION getInverseOrientation(const VolumeFile::ORIENTATION orient); /// Permute (reorient) the volume to the specified orientation. void permuteToOrientation(const VolumeFile::ORIENTATION newOrientation[3]) throw (FileException); /// Get the volume extent of non-zero voxels. Return voxel index range of non-zero voxels. void getNonZeroVoxelExtent(int extentVoxelIndices[6], float extentCoordinates[6]) const; /// get the volume's data file name QString getDataFileName() const { return dataFileName; } /// set the volume's data file name void setDataFileName(const QString& name) { dataFileName = name; } /// get the volume's descriptive label QString getDescriptiveLabel() const; /// set the volume's descriptive label void setDescriptiveLabel(const QString& s) { descriptiveLabel = s; } /// get the number of sub volumes int getNumberOfSubVolumes() const { return numberOfSubVolumes; } /// get the sub volume names void getSubVolumeNames(std::vector& names) const; /// get the volume file's type for reading FILE_READ_WRITE_TYPE getFileReadType() const { return fileReadType; } // /// set the volume file's type for reading (also defaults write type) //void setFileReadType(const FILE_READ_WRITE_TYPE ft) { fileReadType = ft; // fileWriteType = ft; } /// get the volume file's type for writing FILE_READ_WRITE_TYPE getFileWriteType() const { return fileWriteType; } /// set the volume file's type for writing void setFileWriteType(const FILE_READ_WRITE_TYPE ft); /// flip volume about an axis void flip(const VOLUME_AXIS axis, const bool updateOrientation = true); /// rotate volume about an axis void rotate(const VOLUME_AXIS axis); /// rescale voxel values (input min/max mapped to output min/max) void rescaleVoxelValues(const float inputMinimum, const float inputMaximum, const float outputMinimum, const float outputMaximum); /// Scale the voxel values. void scaleVoxelValues(const float scale, const float minimumValueAllowed, const float maximumValueAllowed); /// Scale Anatomy and Segmentation Volumes to be 0 to 255 /// BUT ONLY if the maximum value is 1.0 or less. void scaleAnatomyAndSegmentationVolumesTo255(); /// assign voxels within border for paint volumes void assignVoxelsWithinBorder(const VOLUME_AXIS axis, const QString& paintName, const Border* border, const int slicesAboveAndBelowPlane); /// set highlight a region name void setHighlightRegionName(const QString& name, const bool highlightItFlag); /// get a region is highlighted bool getHighlightRegionNameByIndex(const int indx) const; /// clear region highlighting void clearRegionHighlighting(); /// get the number of region names int getNumberOfRegionNames() const { return regionNames.size(); } /// get a region name by its index QString getRegionNameFromIndex(const int index) const; /// get the index of a region name int getRegionIndexFromName(const QString& name) const; /// delete all region names void deleteAllRegionNames(); /// add a region name (returns its index) int addRegionName(const QString& name); /// set a region name void setRegionName(int index, QString& name); /// create region names for voxels that do not index into a region void createRegionNamesForVoxelsThatDoNotIndexIntoRegionNames(); /// synchronize the region names in the volumes (index X is always region Y) static void synchronizeRegionNames(std::vector& volumeFiles); /// Get the ranges of the voxel values for a specific column. void getMinMaxVoxelValues(float& minVoxelValue, float& maxVoxelValue); /// Get the value of the 2% and 98% voxels. void getTwoToNinetyEightPercentMinMaxVoxelValues(float& minVoxelValue, float& maxVoxelValue); /// get a histogram of the voxels (assumes one component per voxel) /// user must delete returned histogram StatisticHistogram* getHistogram(const int numBuckets = 256, const float excludeLeftPercent = 0.0, const float excludeRightPercent = 0.0) const; /// get a histogram of the voxels void getHistogram(const int numBuckets, std::vector& histogram, float& minHistoVoxelValue, float& maxHistoVoxelValue); /// import an analyze volume void importAnalyzeVolume(const QString& fileName) throw (FileException); /// import a minc volume void importMincVolume(const QString& fileName) throw (FileException); /// import a vtk structured points volume void importVtkStructuredPointsVolume(const QString& fileName) throw (FileException); /// export a vtk structured points volume void exportVtkStructuredPointsVolume(const QString& fileName) throw (FileException); /// export an analyze volume void exportAnalyzeVolume(const QString& fileName) throw (FileException); /// export an minc volume void exportMincVolume(const QString& fileName) throw (FileException); /// read the file header and its first subvolume data void readFile(const QString& fileNameIn) throw (FileException); /// read the file header and the specified subvolume data void readFile(const QString& fileNameIn, const int subVolumeNumber, const bool spmRightIsOnLeft = false) throw (FileException); /// read the specified sub-volumes in a volume file static void readFile(const QString& fileNameIn, const int subVolumeNumber, std::vector& volumesReadOut, const bool spmRightIsOnLeft = false) throw (FileException); /// read the names of the volume's sub-volumes static void readSubVolumeNames(const QString& fileNameIn, std::vector& subVolumeNamesOut) throw (FileException); /// write the specified sub-volumes static void writeFile(const QString& fileNameIn, const VOLUME_TYPE volumeType, const VOXEL_DATA_TYPE writeVoxelDataType, std::vector& volumesToWrite, const bool zipAfniBrikFile = false, const ColorFile* labelColorsForCaret6 = NULL) throw (FileException); /// read a raw volume file that has no header void readFileVolumeRaw(const QString& name, const int subVolumeNumber, const VOXEL_DATA_TYPE vdt, const int dim[3], const ORIENTATION orient[3], const float org[3], const float space[3], const bool byteSwap) throw (FileException); /// write the volume file void writeFile(const QString& filenameIn) throw (FileException); /// write a volume in the specified type and add the correct file extension /// (assumes no file extension) static void writeVolumeFile(VolumeFile* vf, const FILE_READ_WRITE_TYPE fileType, const QString filenameWithoutExtension, const bool compressVolumeFileFlag, QString& fileNameOut, QString& dataFileNameOut) throw (FileException); /// change a range of values to zero static void setRangeOfValuesToZero(const VolumeFile* inputVolume, VolumeFile* outputVolume, const float minValue, const float maxValue, const bool inclusiveRangeFlag) throw (FileException); /// create a segmentation volume mask static void createSegmentationMask(const QString& outputFileName, const std::vector& inputFileNames, const int numberOfDilationIterations) throw (FileException); /// perform unary operations on a volume static void performUnaryOperation(const UNARY_OPERATION operation, const VolumeFile* inputVolume, VolumeFile* outputVolume, const float scalar) throw (FileException); /// perform binary operations on a volume static void performMathematicalOperation(const VOLUME_MATH_OPERATION operation, const VolumeFile* inputVolumeA, const VolumeFile* inputVolumeB, const VolumeFile* inputVolumeC, VolumeFile* outputVolume) throw (FileException); /// perform segmentation operation void performSegmentationOperation(const SEGMENTATION_OPERATION operation, const VOLUME_AXIS axis, const bool threeDimensionalFlag, const int ijkMin[3], const int ijkMax[3], const float newVoxelValue, const unsigned char newRgbValue[4], VolumeModification* modifiedVoxel = NULL); /// assing paint volume voxels void assignPaintVolumeVoxels(const QString& paintName, const int ijkMin[3], const int ijkMax[3], VolumeModification* modifiedVoxel = NULL); /// get the types of volumes and names available for writing static void getVolumeFileTypesAndNames(std::vector& fileTypes, std::vector& fileTypeNames); /// Undo a volume modification void undoModification(const VolumeModification* modifiedVoxel); /// resample the image to the specified spacing void resampleToSpacing(const float newSpacing[3], const INTERPOLATION_TYPE interpolationType); /// apply a transformation matrix to a volume void applyTransformationMatrix(vtkTransform* transform); /// apply a transformation matrix to a volume void applyTransformationMatrix(const TransformationMatrix& tm); /// get number of voxel elements (dims * components per voxel) int getTotalNumberOfVoxelElements() const; /// get number of voxel elements (dims only, does not include components per voxel) int getTotalNumberOfVoxels() const; /// compute a voxel index. inline int getVoxelDataIndex(const VoxelIJK& v, const int component = 0) const { const int indx = v.ijkv[0] + v.ijkv[1] * dimensions[0] + v.ijkv[2] * dimensions[0] * dimensions[1]; const int compIndex = indx * numberOfComponentsPerVoxel + component; return compIndex; } /// compute a voxel data index inline int getVoxelDataIndex(const int ijk[3], const int component = 0) const { const int indx = ijk[0] + ijk[1] * dimensions[0] + ijk[2] * dimensions[0] * dimensions[1]; const int compIndex = indx * numberOfComponentsPerVoxel + component; return compIndex; } /// compute a voxel data index inline int getVoxelDataIndex(const int i, const int j, const int k, const int component = 0) const { const int indx = i + j * dimensions[0] + k * dimensions[0] * dimensions[1]; const int compIndex = indx * numberOfComponentsPerVoxel + component; return compIndex; } /// compute a voxel color index. int getVoxelColorIndex(const VoxelIJK& v) const; /// compute a voxel color data index int getVoxelColorIndex(const int ijk[3]) const; /// compute a voxel color data index int getVoxelColorIndex(const int i, const int j, const int k) const; /// get the index of this voxel ignoring the components) int getVoxelNumber(const int i, const int j, const int k) const; /// get the index of this voxel ignoring the components) int getVoxelNumber(const VoxelIJK& v) const; /// get the index of this voxel ignoring the components) int getVoxelNumber(const int ijk[3]) const; /// convert coordinates into a voxel index (returns true if inside volume) bool convertCoordinatesToVoxelIJK(const float* xyz, int ikjOut[3], float offset[3]) const; /// convert coordinates into a voxel index (returns true if inside volume) bool convertCoordinatesToVoxelIJK(const float* xyz, int ikjOut[3]) const; /// convert to VTK structured points vtkStructuredPoints* convertToVtkStructuredPoints(const bool makeUnsignedCharType = false) const; /// convert from VTK structured points void convertFromVtkStructuredPoints(vtkStructuredPoints* sp); /// convert from VTK image data void convertFromVtkImageData(vtkImageData* sp); /// convert to VTK image data vtkImageData* convertToVtkImageData(const bool makeUnsignedCharType = false) const; /// bias correction using AFNI's 3dUniformize code void biasCorrectionWithAFNI(const int grayMinimum, const int whiteMaximum, const int numberOfIterations) throw (FileException); /// Dual hreshold volume (voxels between thresholds become 255, all other voxels 0). void dualThresholdVolume(const float thresholdLow, const float thresholdHigh); /// threshold volume (voxels above become 255, voxels below 0) void thresholdVolume(const float thresholdValue); /// threshold volume (voxels below become 255, voxels above 0) void inverseThresholdVolume(const float thresholdValue); /// Find each of the disconnect objects (islands) within the volume. void findObjectsWithinSegmentationVolume(std::vector& objectsOut) const; /// Fill the largest connect set of voxels within the specified bounds bool fillBiggestObjectWithinMask(const int iminIn, const int imaxIn, const int jminIn, const int jmaxIn, const int kminIn, const int kmaxIn, const float minValue, const float maxValue); /// Fill the largest connect set of voxels within the specified bounds bool fillBiggestObjectWithinMask(const int extent[6], const float minValue, const float maxValue); /// Find the largest connect set of voxels within the specified bounds int findBiggestObjectWithinMask(const int iminIn, const int imaxIn, const int jminIn, const int jmaxIn, const int kminIn, const int kmaxIn, const float minValue, const float maxValue, VoxelIJK& bigseed) const; /// Find the largest connect set of voxels within the specified bounds int findBiggestObjectWithinMask(const int extent[6], const float minValue, const float maxValue, VoxelIJK& bigseed) const; /// Find the largest connect set of voxels within the specified bounds int findBiggestObjectWithinMask(const int extent[6], const float minValue, const float maxValue, int bigseed[3]) const; /// Find the largest connect set of voxels in the volume int findBiggestObject(const float minValue, const float maxValue, VoxelIJK& bigseed) const; /// find voxel with "value" that has not been searched bool findUnsearchedVoxel(const float minValue, const float maxValue, VOXEL_SEARCH_STATUS searchFlags[], VoxelIJK& seedOut) const; /// clamp a voxel index to within valid values (0 to dim-1) void clampVoxelIndex(const VOLUME_AXIS axis, int& voxelIndex) const; /// clamp a voxel index to within valid values (0 to dim-1) void clampVoxelIndex(int voxelIJK[3]) const; /// clamp a voxel dimensions to within valid values (0 to dim) void clampVoxelDimension(const VOLUME_AXIS axis, int& voxelIndex) const; /// clamp a voxel dimensions to within valid values (0 to dim) void clampVoxelDimension(int voxelIJK[3]) const; /// get 6 connected neighbors for a voxel void getNeighbors(const VoxelIJK& voxel, std::vector& neighbors) const; /// flood fill slice with VTK void floodFillSliceWithVTK(const VolumeFile::VOLUME_AXIS axis, const int seed[3], const int connectedValueIn, const int connectedValueOut, const int unconnectedValueOut, VolumeModification* modifiedVoxels = NULL); /// flood fill with VTK void floodFillWithVTK(const VoxelIJK& seedVoxel, const int connectedValueIn, const int connectedValueOut, const int unconnectedValueOut, VolumeModification* modifiedVoxels = NULL); /// flood fill with VTK void floodFillWithVTK(const int seed[3], const int connectedValueIn, const int connectedValueOut, const int unconnectedValueOut, VolumeModification* modifiedVoxels = NULL); /// remove islands (all but the largest connected piece of surface, true if islands removed) bool removeIslandsFromSegmentation(); /// Find non-zero voxel extent and write limits file if filename is not isEmpty void findLimits(const QString& limitfileName, int extent[6]); /// Shift the volume "offset" voxels in the specified axis void shiftAxis(const VOLUME_AXIS axis, const int offset); /// Smear voxel data along a specified axis void smearAxis(const VOLUME_AXIS axis, const int mag, const int sign, const int core) throw (FileException); /// Stretch the voxels in the volume to range 0 to 255. void stretchVoxelValues(); /// Stretch the voxel values and exlucde top and bottom percentage (0 to 100) void stretchVoxelValuesExcludePercentage(const float bottomPercentToExclude, const float topPercentToExclude); /// Copy a volume but only copy voxels within a specified region. void maskVolume(const int limitsIn[6]); /// apply a volume mask to "this" volume using STEREOTAXIC coordinates void maskWithVolume(const VolumeFile* maskVolume) throw (FileException); /// voxels in "this" volume are set to "newVoxelValue" if the corresponding voxel /// value in "maskVolume" is within the min and max values void maskWithVolumeThreshold(const VolumeFile* maskVolume, const float maskMinimumVoxelValue, const float maskMaximumVoxelValue, const float newVoxelValue) throw (FileException); /// Generate a Cerebral Hull volume from "this" segmentation volume void createCerebralHullVolume(VolumeFile& cerebralHullOut) const; /// ??? void sculptVolume(const int sculptMode, const VolumeFile* vol2, const int numsteps, int seed[3], int limits[6]); /// ??? void imposeLimits(const int limits[6]); /// Get the neighbors for a node given one-dimensional offsets. int computeNeighbors(const int idx, const int neighborOffsets[], const int numNeighs, int neighsOut[]) const; /// dilation and erosion void doVolMorphOps(const int nDilation, const int nErosion); /// dilation and erosion within mask void doVolMorphOpsWithinMask(const int extent[6], const int nDilation, const int nErosion); /// ?? int stripBorderVoxels(const int neighborOffsets[], int numNeighs, VolumeFile *vol2); /// ?? int stripBorderVoxels(const int neighborOffsets[], const int numNeighs); /// ?? void makeShellVolume(const int Ndilation, const int Nerosion); /// ??? void makePlane(const float xslope, const float xoffset, const float yslope, const float yoffset, const float zslope, const float zoffset, const float offset, const float thickness); /// ??? void classifyIntensities(const float mean, const float low, const float high, const float signum); /// blue a volume void blur(); /// static void seperableConvolve(int ncol, int nrow, int nslices, float *volume, float *filter); /// static void oneDimConvolve(float *voxel, float *tempResult, float *filter, const int dim, const int inc, const int ncol, const int nrow, const int nslices); /// voxel 6 connected to seed are found in "this" volume /// and set to "markValue" in the "mark" volume void breadthFirstFloodFill(const VoxelIJK& seed, const float valueToFind, VolumeFile *markVolume, const float markValue, const bool onlyDoUnmarkedVoxels = false) const; /// Fill internal cavities in a segmentation volume. void fillSegmentationCavities(const VolumeFile* maskVolumeIn = NULL); /// Fill internal cavities in a segmentation volume but only one slice. void fillSegmentationCavitiesInSingleSlice(const VOLUME_AXIS axis, const int sliceNumber); /// invert the voxels in a segmentation volume void invertSegmentationVoxels(); /// get the number of objects in a segmentation volume int getNumberOfSegmentationObjects() const; /// get the number of objects in a segmentation volume int getNumberOfSegmentationObjectsSubVolume(const int extent[6]) const; /// get the number of cavities in a segmentation volume int getNumberOfSegmentationCavities() const; /// get the number of cavities in a segmentation volume int getNumberOfSegmentationCavitiesSubVolume(const int extent[6]) const; /// get topology information by generating a surface void getSegmentationTopologyInformation(int& numberOfObjects, int& numberOfCavities, int& numberOfHoles, int& eulerCount) const throw (FileException); /// get the euler data for this volume void getEulerCountsForSegmentationVolume(int& numberOfObjects, int& numberOfCavities, int& numberOfHoles, int& eulerCount) const; /// get the euler data for this volume void getEulerCountsForSegmentationSubVolume(int& numberOfObjects, int& numberOfCavities, int& numberOfHoles, int& eulerCount, const int extent[6]) const; /// determine the euler number of a segmentation volume int getEulerNumberForSegmentationVolume() const; /// determine the euler number of a subvolume of segmentation volume int getEulerNumberForSegmentationSubVolume(const int extent[6]) const; /// make all voxels in a segmentation volume 0 or 255 void makeSegmentationZeroTwoFiftyFive(); /// make a sphere within the volume void makeSphere(const int center[3], const float radius); /// AC-PC align a volume void acPcAlign(const int superiorAcVoxel[3], const int inferiorPcVoxel[3], const int superiorLateralFissureVoxel[3]) throw (FileException); /// see if the data file was zipped (compressed) bool getDataFileWasZipped() const { return dataFileWasZippedFlag; } /// perform uniformity correction with AFNI 3duniformize void afniUniformityCorrection(const int grayMin = 70, const int whiteMax = 210, const int iterations = 5) throw (FileException); /// NIFTI SForm TransformationMatrix TransformationMatrix getNiftiSFormTransformationMatrix() const { return niftiSFormTransformationMatrix; } /// NIFTI QForm TransformationMatrix TransformationMatrix getNiftiQFormTransformationMatrix() const { return niftiQFormTransformationMatrix; } /// write the file's memory in caret6 format to the specified name virtual QString writeFileInCaret6Format(const QString& filenameIn, Structure structure,const ColorFile* colorFileIn, const bool useCaret6ExtensionFlag) throw (FileException); /// get study meta data link //StudyMetaDataLinkSet getStudyMetaDataLinkSet() const { return studyMetaDataLinkSet; } // set study meta data link //void setStudyMetaDataLinkSet(const StudyMetaDataLinkSet& smdls); //************************************************************************ // // The following methods require ITK // They will throw an exception if ITK was not available. // //************************************************************************ /// convert from ITK Image void convertFromITKImage(VolumeITKImage& itkImageIn) throw (FileException); /// convert to ITK Image void convertToITKImage(VolumeITKImage& itkImageOut) throw (FileException); //************************************************************************ // // The previous methods require ITK // They will throw an exception if ITK was not available. // //************************************************************************ protected: /// read the specified sub-volumes in a volume file static void readFileAfni(const QString& fileNameIn, const int readSelection, std::vector& volumesReadOut) throw (FileException); /// read the specified sub-volumes in a volume file static void readFileAnalyze(const QString& fileNameIn, const int readSelection, std::vector& volumesReadOut, const bool spmFlag = false) throw (FileException); /// read the specified sub-volumes in a volume file static void readFileNifti(const QString& fileNameIn, const int readSelection, std::vector& volumesReadOut) throw (FileException); /// read the specified sub-volumes in an SPM volume file static void readFileSpm(const QString& fileNameIn, const int readSelection, std::vector& volumesReadOut, const bool rightIsOnLeft = false) throw (FileException); /// read the specified sub-volumes in a Wash U. volume file static void readFileWuNil(const QString& fileNameIn, const int readSelection, std::vector& volumesReadOut) throw (FileException); /// write the specified AFNI sub-volumes static void writeFileAfni(const QString& fileNameIn, const VOXEL_DATA_TYPE writeVoxelDataType, std::vector& volumesToWrite, const bool zipAfniBrikFile = false) throw (FileException); /// write the specified Analyze sub-volumes static void writeFileAnalyze(const QString& fileNameIn, const VOXEL_DATA_TYPE writeVoxelDataType, std::vector& volumesToWrite) throw (FileException); /// write the specified NIFTI sub-volumes static void writeFileNifti(const QString& fileNameIn, const VOXEL_DATA_TYPE writeVoxelDataType, std::vector& volumesToWrite, const ColorFile* labelColorsForCaret6 = NULL) throw (FileException); /// write the specified SPM sub-volumes static void writeFileSPM(const QString& fileNameIn, const VOXEL_DATA_TYPE writeVoxelDataType, std::vector& volumesToWrite, const bool analyzeFlag = false) throw (FileException); /// write the specified WU NIL sub-volumes static void writeFileWuNil(const QString& fileNameIn, const VOXEL_DATA_TYPE writeVoxelDataType, std::vector& volumesToWrite) throw (FileException); /// read the volume data void readVolumeFileData(const bool byteSwapNeeded, const float scaleFact, const float offsetFact, gzFile dataFile) throw (FileException); /// read the volume data void readVolumeFileDataSubVolume(const bool byteSwapNeeded, const float scaleFact, const float offsetFact, const long dataOffset, const int subVolumeNumber, gzFile dataFile) throw (FileException); /// write the volume data void writeVolumeFileData(const VOXEL_DATA_TYPE voxelDataTypeForWriting, const bool byteSwapNeeded, const bool compressDataWithZlib, gzFile zipStream, std::ofstream* cppStream, const float divideByThisValue) throw (FileException); /// copy volume data (used by copy contructor and assignment operator) void copyVolumeData(const VolumeFile& vf, const bool copyVoxelData = true); /// Flood fill starting at a voxel or remove a connected set of voxels. void floodFillAndRemoveConnected(const SEGMENTATION_OPERATION operation, const VOLUME_AXIS axis, const int ijkStart[3], const float voxelValue, const unsigned char rgbValue[4], VolumeModification* modifiedVoxels = NULL); /// Allocate the voxel coloring void allocateVoxelColoring(); /// Set all voxels' colors invalid if the global coloring invalid flag is set void checkForInvalidVoxelColors(); /// initialize the sub volume information void initializeSubVolumes(const int num); /// get data file name for read error (if data file name empty, return file name) QString getDataFileNameForReadError() const; /// Read the spec file data (should never be called) void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException); /// Write the spec file data (should never be called) void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException); /// Read voxels from the data file void readCharData(gzFile dataFile) throw (FileException); /// Read voxels from the data file void readUnsignedCharData(gzFile dataFile) throw (FileException); /// Read voxels from the data file void readShortData(gzFile dataFile, const bool byteSwapData) throw (FileException); /// Read voxels from the data file void readUnsignedShortData(gzFile dataFile, const bool byteSwapData) throw (FileException); /// Read voxels from the data file void readIntData(gzFile dataFile, const bool byteSwapData) throw (FileException); /// Read voxels from the data file void readUnsignedIntData(gzFile dataFile, const bool byteSwapData) throw (FileException); /// Read voxels from the data file void readLongLongData(gzFile dataFile, const bool byteSwapData) throw (FileException); /// Read voxels from the data file void readUnsignedLongLongData(gzFile dataFile, const bool byteSwapData) throw (FileException); /// Read voxels from the data file void readFloatData(gzFile dataFile, const bool byteSwapData) throw (FileException); /// Read voxels from the data file void readDoubleData(gzFile dataFile, const bool byteSwapData) throw (FileException); /// Read voxels from the data file void readRgbDataVoxelInterleaved(gzFile dataFile) throw (FileException); /// Read voxels from the data file void readRgbDataSliceInterleaved(gzFile dataFile) throw (FileException); /// Get a double attribute from a minc file. void get_minc_attribute(int mincid, char *varname, char *attname, int maxvals, double vals[]); /// create the euler table static void createEulerTable(); /// compute the euler value for a voxel. int computeEulerOctant(const int i, const int j, const int k, const int D[3]) const; /// volume space for reading of volumes static VOLUME_SPACE volumeSpace; /// the type of volume VOLUME_TYPE volumeType; /// type of volume file for reading FILE_READ_WRITE_TYPE fileReadType; /// type of volume file for writing FILE_READ_WRITE_TYPE fileWriteType; /// the data file's name QString dataFileName; /// voxel data type VOXEL_DATA_TYPE voxelDataType; /// SPM AC position float spmAcPosition[3]; /// scale slope used when reading (voxels multiplied by this) std::vector scaleSlope; /// scale offset used when reading (added to voxels) std::vector scaleOffset; /// orientation of volume ORIENTATION orientation[3]; /// names of sub volumes std::vector subVolumeNames; /// number of sub volumes int numberOfSubVolumes; /// mode read reading volume data VOLUME_DATA_READ_MODE volumeDataReadMode; /// the afni header AfniHeader afniHeader; /// the wunil header WuNilHeader wunilHeader; /// the region names std::vector regionNames; /// indices of highlighted region names std::vector regionNameHighlighted; /// the voxel colors (3 components (RGB) per voxel) unsigned char* voxelColoring; /// voxel coloring valid bool voxelColoringValid; /// voxel distances float* voxelToSurfaceDistances; /// voxel distances valid bool voxelToSurfaceDistancesValid; /// dimensions of volume int dimensions[3]; /// voxel sizes float spacing[3]; /// coordinates for origin (located at the center of the first voxel) float origin[3]; /// number of components per voxel int numberOfComponentsPerVoxel; /// the voxels float* voxels; /// minimum voxel value float minimumVoxelValue; /// maximum voxel value float maximumVoxelValue; /// min/max voxel values valid bool minMaxVoxelValuesValid; /// 2% minimum voxel value float minMaxTwoPercentVoxelValue; /// 98% maximum voxel value float minMaxNinetyEightPercentVoxelValue; /// min/max 2% and 98% voxel values valid bool minMaxTwoToNinetyEightPercentVoxelValuesValid; /// data file was zipped flag bool dataFileWasZippedFlag; /// the volume's descriptive label QString descriptiveLabel; /// NIFTI read data offset unsigned long niftiReadDataOffset; /// NIFTI intention code and parameters QString niftiIntentCodeAndParamString; /// NIFTI intent name QString niftiIntentName; /// NIFTI intent code int niftiIntentCode; /// NIFTI intention parameter 1 float niftiIntentParameter1; /// NIFTI intention parameter 2 float niftiIntentParameter2; /// NIFTI intention parameter 3 float niftiIntentParameter3; /// NIFTI TR float niftiTR; /// NIFTI SForm TransformationMatrix TransformationMatrix niftiSFormTransformationMatrix; /// NIFTI QForm TransformationMatrix TransformationMatrix niftiQFormTransformationMatrix; /// study meta data link //StudyMetaDataLinkSet studyMetaDataLinkSet; // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // IF NEW VARIABLES ADDED UPDATE copyVolumeData() !!!!!!!!!!!!!!!!!! // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! /// local neighbor indices (26 connected) static int localNeighbors[26][3]; /// the euler table static float eulerTable[256]; /// the euler table is valid static bool eulerTableValid; }; #endif // __VE_VOLUME_FILE_NEW_H__ #ifdef __VOLUME_FILE_MAIN_H__ bool VolumeFile::eulerTableValid = false; float VolumeFile::eulerTable[256]; VolumeFile::VOLUME_SPACE VolumeFile::volumeSpace = VolumeFile::VOLUME_SPACE_COORD_LPI; int VolumeFile::localNeighbors[26][3] = { {0, 0, 1}, {0, 1, 0}, {1, 0, 0}, {-1, 0, 0}, {0, -1, 0}, {0, 0, -1}, {1, 1, 1}, {0, 1, 1}, {-1, 1, 1}, {1, 0, 1}, {-1, 0, 1}, {1, -1, 1}, {0, -1, 1}, {-1, -1, 1}, {1, 1, 0}, {-1, 1, 0}, {1, -1, 0}, {-1, -1, 0}, {1, 1, -1}, {0, 1, -1}, {-1, 1, -1}, {1, 0, -1}, {-1, 0, -1}, {1, -1, -1}, {0, -1, -1}, {-1, -1, -1} }; #endif // __VOLUME_FILE_MAIN_H__ caret-5.6.4~dfsg.1.orig/caret_files/VolumeFile.cxx0000664000175000017500000157526111572067322021655 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ /*****===================================================================*****/ /***** Sample functions to deal with NIFTI-1 and ANALYZE files *****/ /*****...................................................................*****/ /***** This code is released to the public domain. *****/ /*****...................................................................*****/ /***** Author: Robert W Cox, SSCC/DIRP/NIMH/NIH/DHHS/USA/EARTH *****/ /***** Date: August 2003 *****/ /*****...................................................................*****/ /***** Neither the National Institutes of Health (NIH), nor any of its *****/ /***** employees imply any warranty of usefulness of this software for *****/ /***** any purpose, and do not assume any liability for damages, *****/ /***** incidental or otherwise, caused by any use of this document. *****/ /*****===================================================================*****/ #include // needed for Q_OS_WIN32 #ifdef Q_OS_WIN32 // required for M_PI in #define _USE_MATH_DEFINES #define NOMINMAX #endif #include #include #include #include #include #include #include #include #include #include #define __VOLUME_FILE_MAIN_H__ #include "VolumeFile.h" #undef __VOLUME_FILE_MAIN_H__ #include "BorderFile.h" #include "ByteSwapping.h" #include "DebugControl.h" #include "FileUtilities.h" #include "MathUtilities.h" #include "NiftiFileHeader.h" #include "ParamsFile.h" #include "SpecFile.h" #include "StatisticDataGroup.h" #include "StatisticHistogram.h" #include "StringUtilities.h" #include "TopologyFile.h" #include "TransformationMatrixFile.h" #include "SystemUtilities.h" #include "SureFitVectorFile.h" #include "VolumeITKImage.h" #include "VolumeModification.h" #ifdef HAVE_MINC #include "minc_cpp.h" #endif #include "caret_uniformize.h" #include "mayo_analyze.h" #include "nifti1.h" #include "vtkCleanPolyData.h" #include "vtkFloatArray.h" #include "vtkImageCast.h" #include "vtkImageFlip.h" #include "vtkImageGaussianSmooth.h" #include "vtkImageResample.h" #include "vtkImageReslice.h" #include "vtkImageSeedConnectivity.h" #include "vtkImageShrink3D.h" #include "vtkMarchingCubes.h" #include "vtkMath.h" #include "vtkPointData.h" #include "vtkPolyDataNormals.h" #include "vtkPolyDataWriter.h" #include "vtkStructuredPoints.h" #include "vtkStructuredPointsReader.h" #include "vtkStructuredPointsWriter.h" #include "vtkTransform.h" #include "vtkTriangle.h" #include "vtkTriangleFilter.h" #include "vtkUnsignedCharArray.h" #include "NiftiCaretExtension.h" /** * Constructor. */ VolumeFile::VolumeFile() : AbstractFile("Volume File", SpecFile::getNiftiGzipVolumeFileExtension(), false, FILE_FORMAT_OTHER, FILE_IO_NONE, FILE_IO_NONE, FILE_IO_NONE, FILE_IO_NONE, FILE_IO_NONE, FILE_IO_READ_AND_WRITE) { voxels = NULL; voxelColoring = NULL; voxelToSurfaceDistances = NULL; clear(); } /** * Copy Constructor. */ VolumeFile::VolumeFile(const VolumeFile& vf) : AbstractFile("Volume File", vf.getDefaultFileNameExtension(), false, FILE_FORMAT_OTHER, FILE_IO_NONE, FILE_IO_NONE, FILE_IO_NONE, FILE_IO_READ_AND_WRITE) { voxels = NULL; voxelColoring = NULL; voxelToSurfaceDistances = NULL; copyVolumeData(vf); } /** * Assignment operator. */ VolumeFile& VolumeFile::operator=(const VolumeFile& vf) { if (this != &vf) { // do not do this since this volume already has data in it: voxels = NULL; // do not do this since this volume already has data in it: voxelColoring = NULL; // do not do this since this volume already has data in it: voxelToSurfaceDistances = NULL; copyVolumeData(vf); } return *this; } /** * constructor creates volume from a vector file. */ VolumeFile::VolumeFile(const SureFitVectorFile& vf) : AbstractFile("Volume File", vf.getDefaultFileNameExtension(), false, FILE_FORMAT_OTHER, FILE_IO_NONE, FILE_IO_NONE, FILE_IO_NONE, FILE_IO_READ_AND_WRITE) { voxels = NULL; voxelColoring = NULL; voxelToSurfaceDistances = NULL; int dim[3]; vf.getDimensions(dim); const ORIENTATION orient[3] = { ORIENTATION_LEFT_TO_RIGHT, ORIENTATION_POSTERIOR_TO_ANTERIOR, ORIENTATION_INFERIOR_TO_SUPERIOR }; const float org[3] = { 0.0, 0.0, 0.0 }; const float space[3] = { 1.0, 1.0, 1.0 }; initialize(VOXEL_DATA_TYPE_VECTOR, dim, orient, org, space, true, true); for (int i = 0; i < dim[0]; i++) { for (int j = 0; j < dim[1]; j++) { for (int k = 0; k < dim[2]; k++) { float xyz[3]; vf.getVector(i, j, k, xyz); setVoxel(i, j, k, 0, xyz[0]); setVoxel(i, j, k, 1, xyz[1]); setVoxel(i, j, k, 2, xyz[2]); setVoxel(i, j, k, 3, vf.getMagnitude(i, j, k)); } } } } /** * copy volume data (used by copy contructor and assignment operator). */ void VolumeFile::copyVolumeData(const VolumeFile& vf, const bool copyVoxelData) { clear(); // // Copy parent's data // copyHelperAbstractFile(vf); // // Copy member variables // volumeType = vf.volumeType; fileReadType = vf.fileReadType; setFileWriteType(vf.fileWriteType); dataFileName = ""; voxelDataType = vf.voxelDataType; niftiReadDataOffset = vf.niftiReadDataOffset; spmAcPosition[0] = vf.spmAcPosition[0]; spmAcPosition[1] = vf.spmAcPosition[1]; spmAcPosition[2] = vf.spmAcPosition[2]; scaleSlope = vf.scaleSlope; scaleOffset = vf.scaleOffset; orientation[0] = vf.orientation[0]; orientation[1] = vf.orientation[1]; orientation[2] = vf.orientation[2]; subVolumeNames = vf.subVolumeNames; numberOfSubVolumes = vf.numberOfSubVolumes; volumeDataReadMode = vf.volumeDataReadMode; afniHeader = vf.afniHeader; wunilHeader = vf.wunilHeader; regionNames = vf.regionNames; dataFileWasZippedFlag = vf.dataFileWasZippedFlag; // // Setup volume data // int dim[3]; vf.getDimensions(dim); ORIENTATION orient[3]; vf.getOrientation(orient); float org[3]; vf.getOrigin(org); float space[3]; vf.getSpacing(space); initialize(voxelDataType, dim, orient, org, space, false); // // Copy the voxels // if (copyVoxelData) { const int num = getTotalNumberOfVoxelElements(); for (int i = 0; i < num; i++) { voxels[i] = vf.voxels[i]; } } minimumVoxelValue = vf.minimumVoxelValue; maximumVoxelValue = vf.maximumVoxelValue; minMaxVoxelValuesValid = vf.minMaxVoxelValuesValid; minMaxTwoPercentVoxelValue = vf.minMaxTwoPercentVoxelValue; minMaxNinetyEightPercentVoxelValue = vf.minMaxNinetyEightPercentVoxelValue; minMaxTwoToNinetyEightPercentVoxelValuesValid = vf.minMaxTwoToNinetyEightPercentVoxelValuesValid; descriptiveLabel = vf.descriptiveLabel; niftiIntentCodeAndParamString = vf.niftiIntentCodeAndParamString; niftiIntentCode = vf.niftiIntentCode; niftiIntentName = vf.niftiIntentName; niftiIntentParameter1 = vf.niftiIntentParameter1; niftiIntentParameter2 = vf.niftiIntentParameter2; niftiIntentParameter3 = vf.niftiIntentParameter3; niftiTR = vf.niftiTR; niftiSFormTransformationMatrix = vf.niftiSFormTransformationMatrix; niftiQFormTransformationMatrix = vf.niftiQFormTransformationMatrix; regionNameHighlighted = vf.regionNameHighlighted; //studyMetaDataLinkSet = vf.studyMetaDataLinkSet; allocateVoxelColoring(); std::ostringstream defaultName; defaultName << "copy_of" << vf.getFileName().toAscii().constData(); filename = defaultName.str().c_str(); setModified(); } /** * set the volume file's type for writing. */ void VolumeFile::setFileWriteType(const FILE_READ_WRITE_TYPE ft) { fileWriteType = ft; switch (fileWriteType) { case FILE_READ_WRITE_TYPE_RAW: setDefaultFileNameExtension(".vol"); break; case FILE_READ_WRITE_TYPE_AFNI: setDefaultFileNameExtension(SpecFile::getAfniVolumeFileExtension()); break; case FILE_READ_WRITE_TYPE_ANALYZE: setDefaultFileNameExtension(SpecFile::getAnalyzeVolumeFileExtension()); break; case FILE_READ_WRITE_TYPE_NIFTI: setDefaultFileNameExtension(SpecFile::getNiftiVolumeFileExtension()); break; case FILE_READ_WRITE_TYPE_NIFTI_GZIP: setDefaultFileNameExtension(SpecFile::getNiftiGzipVolumeFileExtension()); break; case FILE_READ_WRITE_TYPE_WUNIL: setDefaultFileNameExtension(SpecFile::getWustlVolumeFileExtension()); break; case FILE_READ_WRITE_TYPE_SPM_OR_MEDX: setDefaultFileNameExtension(SpecFile::getAnalyzeVolumeFileExtension()); break; case FILE_READ_WRITE_TYPE_UNKNOWN: setDefaultFileNameExtension(".vol"); break; } } /** * get the name of the file. */ QString VolumeFile::getFileName(const QString& description) const { QString name = AbstractFile::getFileName(description); if (description.isEmpty() == false) { QString ext("."); ext.append(FileUtilities::filenameExtension(name)); if (ext == ".vol") { switch (fileWriteType) { case FILE_READ_WRITE_TYPE_RAW: ext = ".vol"; break; case FILE_READ_WRITE_TYPE_AFNI: ext = SpecFile::getAfniVolumeFileExtension(); break; case FILE_READ_WRITE_TYPE_ANALYZE: ext = SpecFile::getAnalyzeVolumeFileExtension(); break; case FILE_READ_WRITE_TYPE_NIFTI: ext = SpecFile::getNiftiVolumeFileExtension(); break; case FILE_READ_WRITE_TYPE_NIFTI_GZIP: ext = SpecFile::getNiftiGzipVolumeFileExtension(); break; case FILE_READ_WRITE_TYPE_WUNIL: ext = SpecFile::getWustlVolumeFileExtension(); break; case FILE_READ_WRITE_TYPE_SPM_OR_MEDX: ext = SpecFile::getAnalyzeVolumeFileExtension(); break; case FILE_READ_WRITE_TYPE_UNKNOWN: ext = ".vol"; break; } } QString newName; // // Add directory, if needed, to new file name // QString bn(FileUtilities::dirname(name)); if ((bn.isEmpty() == false) && (bn != ".")) { newName = bn; newName.append("/"); } // // Assemble file name // const QString nameNoExt(FileUtilities::filenameWithoutExtension(name)); newName.append(nameNoExt); if (fileWriteType == FILE_READ_WRITE_TYPE_AFNI) { // // Afni likes "+orig" in name // if (nameNoExt.indexOf('+') == -1) { newName.append("+orig"); } } newName.append(ext); name = newName; } return name; } /** * get number of voxel elements (dims * components per voxel). */ int VolumeFile::getTotalNumberOfVoxelElements() const { const int num = getTotalNumberOfVoxels() * numberOfComponentsPerVoxel; return num; } /** * get number of voxel elements (dims only, does not include components per voxel) */ int VolumeFile::getTotalNumberOfVoxels() const { const int num = dimensions[0] * dimensions[1] * dimensions[2]; return num; } /** * set the data type. */ void VolumeFile::setVoxelDataType(const VOXEL_DATA_TYPE vdt) { voxelDataType = vdt; switch (voxelDataType) { case VOXEL_DATA_TYPE_UNKNOWN: case VOXEL_DATA_TYPE_CHAR: case VOXEL_DATA_TYPE_CHAR_UNSIGNED: case VOXEL_DATA_TYPE_SHORT: case VOXEL_DATA_TYPE_SHORT_UNSIGNED: case VOXEL_DATA_TYPE_INT: case VOXEL_DATA_TYPE_INT_UNSIGNED: case VOXEL_DATA_TYPE_LONG: case VOXEL_DATA_TYPE_LONG_UNSIGNED: case VOXEL_DATA_TYPE_FLOAT: case VOXEL_DATA_TYPE_DOUBLE: numberOfComponentsPerVoxel = 1; break; case VOXEL_DATA_TYPE_RGB_VOXEL_INTERLEAVED: case VOXEL_DATA_TYPE_RGB_SLICE_INTERLEAVED: numberOfComponentsPerVoxel = 3; break; case VOXEL_DATA_TYPE_VECTOR: numberOfComponentsPerVoxel = 4; break; } } /** * get the sub volume names. */ void VolumeFile::getSubVolumeNames(std::vector& names) const { names = subVolumeNames; if (names.empty()) { names.resize(std::max(1, numberOfSubVolumes), FileUtilities::basename(getFileName())); } } /** * Initialize - creates a volume and allocates memory for the specified dimensions. */ void VolumeFile::initialize(const VOXEL_DATA_TYPE vdt, const int dim[3], const ORIENTATION orient[3], const float org[3], const float space[3], const bool doClear, const bool allocateVoxelData) { if (doClear) { clear(); } if (voxels != NULL) { delete[] voxels; voxels = NULL; } minimumVoxelValue = 0.0; maximumVoxelValue = 0.0; minMaxVoxelValuesValid = false; minMaxTwoPercentVoxelValue = 0.0; minMaxNinetyEightPercentVoxelValue = 0.0; minMaxTwoToNinetyEightPercentVoxelValuesValid = false; setVoxelDataType(vdt); setDimensions(dim); setOrientation(orient); setOrigin(org); setSpacing(space); if (allocateVoxelData) { const int num = getTotalNumberOfVoxelElements(); voxels = new float[num]; for (int i = 0; i < num; i++) { voxels[i] = 0.0; } allocateVoxelColoring(); } filename = getFileName(""); /* static int nameCounter = 0; std::ostringstream defaultName; defaultName << "volume_" << nameCounter; nameCounter++; filename = defaultName.str().c_str(); */ setModified(); } /** * Destructor. */ VolumeFile::~VolumeFile() { clear(); } /** * get all volume types and names (anatomy, functional, etc). */ void VolumeFile::getAllVolumeTypesAndNames(std::vector& typesOut, std::vector& namesOut, const bool addUnknown, const bool addROI) { typesOut.clear(); namesOut.clear(); typesOut.push_back(VOLUME_TYPE_ANATOMY); namesOut.push_back("Anatomy"); typesOut.push_back(VOLUME_TYPE_FUNCTIONAL); namesOut.push_back("Functional"); typesOut.push_back(VOLUME_TYPE_PAINT); namesOut.push_back("Paint"); typesOut.push_back(VOLUME_TYPE_PROB_ATLAS); namesOut.push_back("Probabilistic Atlas"); typesOut.push_back(VOLUME_TYPE_RGB); namesOut.push_back("RGB"); if (addROI) { typesOut.push_back(VOLUME_TYPE_ROI); namesOut.push_back("ROI"); } typesOut.push_back(VOLUME_TYPE_SEGMENTATION); namesOut.push_back("Segmentation"); typesOut.push_back(VOLUME_TYPE_VECTOR); namesOut.push_back("Vector"); if (addUnknown) { typesOut.push_back(VOLUME_TYPE_UNKNOWN); namesOut.push_back("Unknown"); } // // This switch statement is here so that it will cause a compilation warning // if a new volume type is added but not update above and below!!!! // VOLUME_TYPE vt = VOLUME_TYPE_ANATOMY; switch (vt) { case VOLUME_TYPE_ANATOMY: case VOLUME_TYPE_FUNCTIONAL: case VOLUME_TYPE_PAINT: case VOLUME_TYPE_PROB_ATLAS: case VOLUME_TYPE_RGB: case VOLUME_TYPE_ROI: case VOLUME_TYPE_SEGMENTATION: case VOLUME_TYPE_VECTOR: case VOLUME_TYPE_UNKNOWN: break; } } /* * assemble type name with number of bits for type */ static QString voxelDataTypeHelper(const QString& nameIn, const int numBytes) { QString name(nameIn); const int numBits = numBytes * 8; name += " ("; name += QString::number(numBits); name += " bits)"; return name; } /** * get all voxel data types and names (float, int, etc). */ void VolumeFile::getAllVoxelDataTypesAndNames(std::vector& typesOut, std::vector& namesOut, const bool addUnknown) { typesOut.clear(); namesOut.clear(); typesOut.push_back(VOXEL_DATA_TYPE_CHAR); namesOut.push_back(voxelDataTypeHelper("Char", sizeof(char))); typesOut.push_back(VOXEL_DATA_TYPE_CHAR_UNSIGNED); namesOut.push_back(voxelDataTypeHelper("Unsigned Char", sizeof(unsigned char))); typesOut.push_back(VOXEL_DATA_TYPE_SHORT); namesOut.push_back(voxelDataTypeHelper("Short", sizeof(short))); typesOut.push_back(VOXEL_DATA_TYPE_SHORT_UNSIGNED); namesOut.push_back(voxelDataTypeHelper("Unsigned Short", sizeof(unsigned short))); typesOut.push_back(VOXEL_DATA_TYPE_INT); namesOut.push_back(voxelDataTypeHelper("int", sizeof(int))); typesOut.push_back(VOXEL_DATA_TYPE_INT_UNSIGNED); namesOut.push_back(voxelDataTypeHelper("Unsigned Int", sizeof(unsigned int))); if (sizeof(long long) == 8) { typesOut.push_back(VOXEL_DATA_TYPE_LONG); namesOut.push_back(voxelDataTypeHelper("Long", sizeof(long long))); typesOut.push_back(VOXEL_DATA_TYPE_LONG_UNSIGNED); namesOut.push_back(voxelDataTypeHelper("Unsigned Long", sizeof(unsigned long long))); } typesOut.push_back(VOXEL_DATA_TYPE_FLOAT); namesOut.push_back(voxelDataTypeHelper("Float", sizeof(float))); typesOut.push_back(VOXEL_DATA_TYPE_DOUBLE); namesOut.push_back(voxelDataTypeHelper("Double", sizeof(double))); typesOut.push_back(VOXEL_DATA_TYPE_RGB_VOXEL_INTERLEAVED); namesOut.push_back(voxelDataTypeHelper("RGB Voxel Interleaved", sizeof(unsigned char))); typesOut.push_back(VOXEL_DATA_TYPE_RGB_SLICE_INTERLEAVED); namesOut.push_back(voxelDataTypeHelper("RGB Slice Interleaved", sizeof(unsigned char))); typesOut.push_back(VOXEL_DATA_TYPE_VECTOR); namesOut.push_back(voxelDataTypeHelper("Vector", sizeof(float))); if (addUnknown) { typesOut.push_back(VOXEL_DATA_TYPE_UNKNOWN); namesOut.push_back("Unknown"); } // // This code is just here so that the compiler will complain // if a new voxel data type is added // VOXEL_DATA_TYPE vdt = VOXEL_DATA_TYPE_UNKNOWN; switch (vdt) { case VOXEL_DATA_TYPE_UNKNOWN: case VOXEL_DATA_TYPE_CHAR: case VOXEL_DATA_TYPE_CHAR_UNSIGNED: case VOXEL_DATA_TYPE_SHORT: case VOXEL_DATA_TYPE_SHORT_UNSIGNED: case VOXEL_DATA_TYPE_INT: case VOXEL_DATA_TYPE_INT_UNSIGNED: case VOXEL_DATA_TYPE_LONG: case VOXEL_DATA_TYPE_LONG_UNSIGNED: case VOXEL_DATA_TYPE_FLOAT: case VOXEL_DATA_TYPE_DOUBLE: case VOXEL_DATA_TYPE_RGB_VOXEL_INTERLEAVED: case VOXEL_DATA_TYPE_RGB_SLICE_INTERLEAVED: case VOXEL_DATA_TYPE_VECTOR: break; } } /** * get the volume's descriptive label. */ QString VolumeFile::getDescriptiveLabel() const { if (descriptiveLabel.isEmpty()) { return FileUtilities::basename(getFileName()); } return descriptiveLabel; } /** * get the minimum and maximum values for a data type. */ void VolumeFile::getDataTypeMinMaxValues(const VOXEL_DATA_TYPE vdt, double& minValueForDataType, double& maxValueForDataType) { minValueForDataType = 0.0; maxValueForDataType = 0.0; switch (vdt) { case VOXEL_DATA_TYPE_UNKNOWN: minValueForDataType = 0.0; maxValueForDataType = 0.0; break; case VOXEL_DATA_TYPE_CHAR: minValueForDataType = std::numeric_limits::min(); maxValueForDataType = std::numeric_limits::max(); break; case VOXEL_DATA_TYPE_CHAR_UNSIGNED: minValueForDataType = std::numeric_limits::min(); maxValueForDataType = std::numeric_limits::max(); break; case VOXEL_DATA_TYPE_SHORT: minValueForDataType = std::numeric_limits::min(); maxValueForDataType = std::numeric_limits::max(); break; case VOXEL_DATA_TYPE_SHORT_UNSIGNED: minValueForDataType = std::numeric_limits::min(); maxValueForDataType = std::numeric_limits::max(); break; case VOXEL_DATA_TYPE_INT: minValueForDataType = std::numeric_limits::min(); maxValueForDataType = std::numeric_limits::max(); break; case VOXEL_DATA_TYPE_INT_UNSIGNED: minValueForDataType = std::numeric_limits::min(); maxValueForDataType = std::numeric_limits::max(); break; case VOXEL_DATA_TYPE_LONG: minValueForDataType = std::numeric_limits::min(); maxValueForDataType = std::numeric_limits::max(); break; case VOXEL_DATA_TYPE_LONG_UNSIGNED: minValueForDataType = std::numeric_limits::min(); maxValueForDataType = std::numeric_limits::max(); break; case VOXEL_DATA_TYPE_FLOAT: minValueForDataType = -std::numeric_limits::max(); maxValueForDataType = std::numeric_limits::max(); break; case VOXEL_DATA_TYPE_DOUBLE: minValueForDataType = -std::numeric_limits::max(); maxValueForDataType = std::numeric_limits::max(); break; case VOXEL_DATA_TYPE_RGB_VOXEL_INTERLEAVED: minValueForDataType = std::numeric_limits::min(); maxValueForDataType = std::numeric_limits::max(); break; case VOXEL_DATA_TYPE_RGB_SLICE_INTERLEAVED: minValueForDataType = std::numeric_limits::min(); maxValueForDataType = std::numeric_limits::max(); break; case VOXEL_DATA_TYPE_VECTOR: minValueForDataType = -std::numeric_limits::max(); maxValueForDataType = std::numeric_limits::max(); break; } } /** * rescale voxel values (input min/max mapped to output min/max). */ void VolumeFile::rescaleVoxelValues(const float inputMinimum, const float inputMaximum, const float outputMinimum, const float outputMaximum) { float inputDiff = inputMaximum - inputMinimum; if (inputDiff == 0.0) { inputDiff = 1.0; } const float outputDiff = outputMaximum - outputMinimum; const int num = getTotalNumberOfVoxelElements(); for (int i = 0; i < num; i++) { float value = voxels[i]; if (value <= inputMinimum) { value = outputMinimum; } else if (value >= inputMaximum) { value = outputMaximum; } else { const float normalized = (value - inputMinimum) / inputDiff; value = normalized * outputDiff + outputMinimum; } voxels[i] = value; } setModified(); minMaxVoxelValuesValid = false; minMaxTwoToNinetyEightPercentVoxelValuesValid = false; } /** * Scale the voxel values. */ void VolumeFile::scaleVoxelValues(const float scale, const float minimumValueAllowed, const float maximumValueAllowed) { const int num = getTotalNumberOfVoxelElements(); for (int i = 0; i < num; i++) { float value = voxels[i]; value *= scale; value = std::min(value, maximumValueAllowed); value = std::max(value, minimumValueAllowed); voxels[i] = value; } setModified(); minMaxVoxelValuesValid = false; minMaxTwoToNinetyEightPercentVoxelValuesValid = false; } /** * Get the ranges of the voxel values for a specific component. */ void VolumeFile::getMinMaxVoxelValues(float& minVoxelValue, float& maxVoxelValue) { if (minMaxVoxelValuesValid == false) { const int numVoxelElements = getTotalNumberOfVoxelElements(); if (numVoxelElements <= 0) { minimumVoxelValue = 0.0; maximumVoxelValue = 0.0; } else { minimumVoxelValue = std::numeric_limits::max(); maximumVoxelValue = -std::numeric_limits::max(); for (int i = 0; i < numVoxelElements; i++) { const float value = voxels[i]; minimumVoxelValue = std::min(minimumVoxelValue, value); maximumVoxelValue = std::max(maximumVoxelValue, value); } } minMaxVoxelValuesValid = true; } minVoxelValue = minimumVoxelValue; maxVoxelValue = maximumVoxelValue; } /** * Get the value of the 2% and 98% voxels. */ void VolumeFile::getTwoToNinetyEightPercentMinMaxVoxelValues(float& minVoxelValue, float& maxVoxelValue) { if (minMaxTwoToNinetyEightPercentVoxelValuesValid == false) { float minVoxel = 0.0; float maxVoxel = 255.0; std::vector histogram; const int histoSize = 256; getHistogram(histoSize, histogram, minVoxel, maxVoxel); const float range = maxVoxel - minVoxel; minMaxTwoPercentVoxelValue = 0.0; minMaxNinetyEightPercentVoxelValue = 255.0; if (range != 0.0) { const float percent = 0.02; // // Skip the first percent of voxels // int sum = 0; const int numVoxels = getTotalNumberOfVoxels(); int percentage = static_cast(numVoxels * percent); for (int i = 0; i < histoSize; i++) { sum += histogram[i]; if (sum >= percentage) { minMaxTwoPercentVoxelValue = (static_cast(i) / static_cast(histoSize)) * range + minVoxel; break; } } // // Skip the first percent of voxels // sum = 0; for (int i = histoSize - 1; i >= 0; i--) { sum += histogram[i]; if (sum >= percentage) { minMaxNinetyEightPercentVoxelValue = (static_cast(i) / static_cast(histoSize)) * range + minVoxel; break; } } } minMaxTwoToNinetyEightPercentVoxelValuesValid = true; } minVoxelValue = minMaxTwoPercentVoxelValue; maxVoxelValue = minMaxNinetyEightPercentVoxelValue; } /** * get a histogram of the voxels (assumes one component per voxel). * User must delete the returned Histogram. */ StatisticHistogram* VolumeFile::getHistogram(const int numBuckets, const float excludeLeftPercent, const float excludeRightPercent) const { std::vector values; const int numVoxels = getTotalNumberOfVoxels(); for (int i = 0; i < numVoxels; i++) { values.push_back(getVoxelWithFlatIndex(i)); } StatisticHistogram* hist = new StatisticHistogram(numBuckets, excludeLeftPercent, excludeRightPercent); StatisticDataGroup sdg(&values, StatisticDataGroup::DATA_STORAGE_MODE_POINT); hist->addDataGroup(&sdg); try { hist->execute(); } catch (StatisticException&) { } return hist; } /** * get a histogram of the voxels. * "minVoxelValue" is the minimum voxel value found * "maxVoxelValue" is the maximum voxel value found */ void VolumeFile::getHistogram(const int numBuckets, std::vector& histogram, float& minVoxelValue, float& maxVoxelValue) { getMinMaxVoxelValues(minVoxelValue, maxVoxelValue); const int numVoxels = getTotalNumberOfVoxels(); const int numComponents = getNumberOfComponentsPerVoxel(); histogram.resize(numBuckets); std::fill(histogram.begin(), histogram.end(), 0); const float range = maxVoxelValue - minVoxelValue; if (range == 0.0) { return; } const int bucketMax = numBuckets - 1; for (int i = 0; i < numVoxels; i++) { const int indx = i * numComponents; float f = ((voxels[indx] - minVoxelValue) / range) * numBuckets; int intValue = static_cast(f + 0.5); // round into an int intValue = std::min(intValue, bucketMax); intValue = std::max(intValue, 0); histogram[intValue]++; } } /** * Allocate voxel coloring. */ void VolumeFile::allocateVoxelColoring() { if (voxelColoring != NULL) { delete[] voxelColoring; voxelColoring = NULL; } if (voxels != NULL) { const int num = getTotalNumberOfVoxels(); if (num > 0) { voxelColoring = new unsigned char[num * 4]; } } setVoxelColoringInvalid(); } /** * get the label of an orientation */ QString VolumeFile::getOrientationLabel(const ORIENTATION orient) { QString s; switch(orient) { case ORIENTATION_UNKNOWN: s = "Unknown"; break; case ORIENTATION_RIGHT_TO_LEFT: s = "Right to Left"; break; case ORIENTATION_LEFT_TO_RIGHT: s = "Left to Right"; break; case ORIENTATION_POSTERIOR_TO_ANTERIOR: s = "Posterior to Anterior"; break; case ORIENTATION_ANTERIOR_TO_POSTERIOR: s = "Anterior to Posterior"; break; case ORIENTATION_INFERIOR_TO_SUPERIOR: s = "Inferior to Superior"; break; case ORIENTATION_SUPERIOR_TO_INFERIOR: s = "Superior to Inferior"; break; default: s = "Invalid Value"; break; } return s; } /** * Clear the file's contents. */ void VolumeFile::clear() { clearAbstractFile(); if (voxels != NULL) { delete[] voxels; voxels = NULL; } if (voxelColoring != NULL) { delete[] voxelColoring; voxelColoring = NULL; } voxelColoringValid = false; dimensions[0] = 0; dimensions[1] = 0; dimensions[2] = 0; origin[0] = 0.0; origin[1] = 0.0; origin[2] = 0.0; spacing[0] = 0.0; spacing[1] = 0.0; spacing[2] = 0.0; numberOfComponentsPerVoxel = 0; dataFileWasZippedFlag = false; volumeType = VOLUME_TYPE_ANATOMY; //VOLUME_TYPE_UNKNOWN; dataFileName = ""; fileReadType = FILE_READ_WRITE_TYPE_NIFTI_GZIP; setFileWriteType(FILE_READ_WRITE_TYPE_NIFTI_GZIP); numberOfSubVolumes = 0; orientation[0] = ORIENTATION_UNKNOWN; orientation[1] = ORIENTATION_UNKNOWN; orientation[2] = ORIENTATION_UNKNOWN; spmAcPosition[0] = 0.0; spmAcPosition[1] = 0.0; spmAcPosition[2] = 0.0; niftiReadDataOffset = 0; voxelDataType = VOXEL_DATA_TYPE_UNKNOWN; scaleSlope.clear(); scaleOffset.clear(); subVolumeNames.clear(); afniHeader.clear(); wunilHeader.clear(); regionNames.clear(); if (voxelToSurfaceDistances != NULL) { delete[] voxelToSurfaceDistances; voxelToSurfaceDistances = NULL; } voxelToSurfaceDistancesValid = false; minimumVoxelValue = 0.0; maximumVoxelValue = 0.0; minMaxVoxelValuesValid = false; minMaxTwoPercentVoxelValue = 0.0; minMaxNinetyEightPercentVoxelValue = 0.0; minMaxTwoToNinetyEightPercentVoxelValuesValid = false; descriptiveLabel = ""; niftiIntentCodeAndParamString = ""; niftiIntentName = ""; niftiIntentCode = 0; niftiIntentParameter1 = 0.0; niftiIntentParameter2 = 0.0; niftiIntentParameter3 = 0.0; niftiTR = 0.0; niftiSFormTransformationMatrix.identity(); niftiQFormTransformationMatrix.identity(); setVoxelDataType(VOXEL_DATA_TYPE_FLOAT); clearRegionHighlighting(); //studyMetaDataLinkSet.clear(); } /** * get the string describing the type of volume (anatomy, functional, etc). */ QString VolumeFile::getVolumeTypeDescription() const { QString s; switch (volumeType) { case VOLUME_TYPE_ANATOMY: s = "Anatomy"; break; case VOLUME_TYPE_FUNCTIONAL: s = "Functional"; break; case VOLUME_TYPE_PAINT: s = "Paint"; break; case VOLUME_TYPE_PROB_ATLAS: s = "Prob Atlas"; break; case VOLUME_TYPE_RGB: s = "RGB"; break; case VOLUME_TYPE_ROI: s = "ROI"; break; case VOLUME_TYPE_SEGMENTATION: s = "Segmentation"; break; case VOLUME_TYPE_VECTOR: s = "Vector"; break; case VOLUME_TYPE_UNKNOWN: s = "Unknown"; break; } return s; } /** * get a region name by its index. */ QString VolumeFile::getRegionNameFromIndex(const int index) const { if ((index >= 0) && (index < getNumberOfRegionNames())) { return regionNames[index]; } return ""; } /** * get the index of a region name (returns -1 if not found) */ int VolumeFile::getRegionIndexFromName(const QString& name) const { const int numNames = getNumberOfRegionNames(); for (int i = 0; i < numNames; i++) { if (name == regionNames[i]) { return i; } } return -1; } /** * Set a region name. */ void VolumeFile::setRegionName(int index, QString& name) { if (index >= static_cast(this->regionNames.size())) { this->regionNames.resize(index + 1, ""); } this->regionNames[index] = name; this->setModified(); } /** * remove all region names. */ void VolumeFile::deleteAllRegionNames() { regionNames.clear(); } /** * Create region names for voxels that do not index into a region. */ void VolumeFile::createRegionNamesForVoxelsThatDoNotIndexIntoRegionNames() { int numVoxels = this->getTotalNumberOfVoxels(); for (int iv = 0; iv < numVoxels; iv++) { int voxel = static_cast(this->voxels[iv]); if (voxel >= 0) { QString name = this->getRegionNameFromIndex(voxel); if (name.isEmpty()) { if (voxel > 0) { name = "Region_" + QString::number(voxel); } else { name = "???"; } this->setRegionName(voxel, name); } } } } /** * add a region name (returns its index) */ int VolumeFile::addRegionName(const QString& name) { const int index = getRegionIndexFromName(name); if (index >= 0) { return index; } // // WU NIL volume file cannot have a voxel value of 1. So, the // zero index is "not in a region", and index one is unused. // if (regionNames.size() == 0) { regionNames.push_back("???"); regionNames.push_back("???_not_used"); } else if (regionNames.size() == 1) { if (regionNames[0] == "???_not_used") { regionNames.push_back("???_not_used1"); } else { regionNames.push_back("???_not_used"); } } // // Name could be one of the ??? names // const int index2 = getRegionIndexFromName(name); if (index2 >= 0) { return index2; } regionNames.push_back(name); return (regionNames.size() - 1); } /** * set highlight a region name. */ void VolumeFile::setHighlightRegionName(const QString& name, const bool highlightItFlag) { const int indx = getRegionIndexFromName(name); if (indx >= 0) { std::vector::iterator iter = std::find(regionNameHighlighted.begin(), regionNameHighlighted.end(), indx); if (highlightItFlag) { if (iter == regionNameHighlighted.end()) { regionNameHighlighted.push_back(indx); } } else { if (iter != regionNameHighlighted.end()) { regionNameHighlighted.erase(iter); } } setVoxelColoringInvalid(); } } /** * get a region is highlighted. */ bool VolumeFile::getHighlightRegionNameByIndex(const int indx) const { const bool exists = (std::find(regionNameHighlighted.begin(), regionNameHighlighted.end(), indx) != regionNameHighlighted.end()); return exists; } /** * clear region highlighting. */ void VolumeFile::clearRegionHighlighting() { regionNameHighlighted.clear(); setVoxelColoringInvalid(); } /** * synchronize the region names in the volumes (index X is always region Y). */ void VolumeFile::synchronizeRegionNames(std::vector& volumeFiles) { const int numVolumes = static_cast(volumeFiles.size()); if (numVolumes <= 1) { return; } VolumeFile* firstVolume = volumeFiles[0]; firstVolume->clearRegionHighlighting(); // // Use region table from first volume file // for (int i = 1; i < numVolumes; i++) { // // Add region names for volume "i" to the first volume and build // translation from volume "i" to first volume region names // VolumeFile* vf = volumeFiles[i]; const int numRegionNames = vf->getNumberOfRegionNames(); std::vector regionIndexUpdater(numRegionNames, 0); for (int j = 0; j < numRegionNames; j++) { regionIndexUpdater[j] = firstVolume->addRegionName(vf->getRegionNameFromIndex(j)); } // // Update volume "i" voxels with new region indices // const int numVoxels = vf->getTotalNumberOfVoxels(); for (int k = 0; k < numVoxels; k++) { vf->voxels[k] = regionIndexUpdater[static_cast(vf->voxels[k])]; } vf->clearRegionHighlighting(); } // // replace the region names and invalidate coloring // for (int i = 1; i < numVolumes; i++) { volumeFiles[i]->regionNames = firstVolume->regionNames; volumeFiles[i]->setVoxelColoringInvalid(); } } /** * get the voxel distance (used by surface and volume rendering). */ float* VolumeFile::getVoxelToSurfaceDistances() { if (voxelToSurfaceDistances == NULL) { if (voxels != NULL) { int dim[3]; getDimensions(dim); const int num = dim[0] * dim[1] * dim[2]; if (num > 0) { voxelToSurfaceDistances = new float[num]; for (int i = 0; i < num; i++) { voxelToSurfaceDistances[i] = 0.0; } } } } return voxelToSurfaceDistances; } /** * get axis from string. */ VolumeFile::VOLUME_AXIS VolumeFile::getAxisFromString(const QString& sIn) { const QString& s = sIn.toUpper(); if (s == "X") { return VOLUME_AXIS_X; } else if (s == "Y") { return VOLUME_AXIS_Y; } else if (s == "Z") { return VOLUME_AXIS_Z; } else if (s == "ALL") { return VOLUME_AXIS_ALL; } else if (s == "OBLIQUE") { return VOLUME_AXIS_OBLIQUE; } else if (s == "X-OBLIQUE") { return VOLUME_AXIS_OBLIQUE_X; } else if (s == "Y-OBLIQUE") { return VOLUME_AXIS_OBLIQUE_Y; } else if (s == "Z-OBLIQUE") { return VOLUME_AXIS_OBLIQUE_Z; } else if (s == "ALL-OBLIQUE") { return VOLUME_AXIS_OBLIQUE_ALL; } else { return VOLUME_AXIS_UNKNOWN; } } /** * Get the label of an axis enumerated type. */ QString VolumeFile::getAxisLabel(const VOLUME_AXIS axis) { switch (axis) { case VOLUME_AXIS_X: return "X"; break; case VOLUME_AXIS_Y: return "Y"; break; case VOLUME_AXIS_Z: return "Z"; break; case VOLUME_AXIS_ALL: return "ALL"; break; case VOLUME_AXIS_OBLIQUE: return "OBLIQUE"; break; case VOLUME_AXIS_OBLIQUE_X: return "X-OBLIQUE"; break; case VOLUME_AXIS_OBLIQUE_Y: return "Y-OBLIQUE"; break; case VOLUME_AXIS_OBLIQUE_Z: return "Z-OBLIQUE"; break; case VOLUME_AXIS_OBLIQUE_ALL: return "ALL-OBLIQUE"; break; case VOLUME_AXIS_UNKNOWN: return "UNKNOWN"; break; } return "UNKNOWN"; } /** * get the size of a slice (number of voxels and components). */ int VolumeFile::getSizeOfSlice(const VOLUME_AXIS axis) const { int sliceSize = 0; switch (axis) { case VOLUME_AXIS_X: sliceSize = dimensions[1] * dimensions[2] * getNumberOfComponentsPerVoxel(); break; case VOLUME_AXIS_Y: sliceSize = dimensions[0] * dimensions[2] * getNumberOfComponentsPerVoxel(); break; case VOLUME_AXIS_Z: sliceSize = dimensions[0] * dimensions[1] * getNumberOfComponentsPerVoxel(); break; case VOLUME_AXIS_ALL: break; case VOLUME_AXIS_OBLIQUE: break; case VOLUME_AXIS_OBLIQUE_X: break; case VOLUME_AXIS_OBLIQUE_Y: break; case VOLUME_AXIS_OBLIQUE_Z: break; case VOLUME_AXIS_OBLIQUE_ALL: break; case VOLUME_AXIS_UNKNOWN: break; } return sliceSize; } /** * get a slice from a volume (sliceVoxelsOut should be size getSizeOfSlice()). */ void VolumeFile::getSlice(const VOLUME_AXIS axis, const int sliceNumber, const SLICE_DATA_ORDER dataOrder, float* sliceVoxelsOut) const { const int dimI = dimensions[0]; const int dimJ = dimensions[1]; const int dimK = dimensions[2]; const int numComp = getNumberOfComponentsPerVoxel(); switch (axis) { case VOLUME_AXIS_X: if (dataOrder == SLICE_DATA_ORDER_COLUMN) { int ctr = 0; for (int j = 0; j < dimJ; j++) { for (int k = 0; k < dimK; k++) { for (int m = 0; m < numComp; m++) { sliceVoxelsOut[ctr] = getVoxel(sliceNumber, j, k, m); ctr++; } } } } else { int ctr = 0; for (int k = 0; k < dimK; k++) { for (int j = 0; j < dimJ; j++) { for (int m = 0; m < numComp; m++) { sliceVoxelsOut[ctr] = getVoxel(sliceNumber, j, k, m); ctr++; } } } } break; case VOLUME_AXIS_Y: if (dataOrder == SLICE_DATA_ORDER_COLUMN) { int ctr = 0; for (int i = 0; i < dimI; i++) { for (int k = 0; k < dimK; k++) { for (int m = 0; m < numComp; m++) { sliceVoxelsOut[ctr] = getVoxel(i, sliceNumber, k, m); ctr++; } } } } else { int ctr = 0; for (int k = 0; k < dimK; k++) { for (int i = 0; i < dimI; i++) { for (int m = 0; m < numComp; m++) { sliceVoxelsOut[ctr] = getVoxel(i, sliceNumber, k, m); ctr++; } } } } break; case VOLUME_AXIS_Z: if (dataOrder == SLICE_DATA_ORDER_COLUMN) { int ctr = 0; for (int i = 0; i < dimI; i++) { for (int j = 0; j < dimJ; j++) { for (int m = 0; m < numComp; m++) { sliceVoxelsOut[ctr] = getVoxel(i, j, sliceNumber, m); ctr++; } } } } else { int ctr = 0; for (int j = 0; j < dimJ; j++) { for (int i = 0; i < dimI; i++) { for (int m = 0; m < numComp; m++) { sliceVoxelsOut[ctr] = getVoxel(i, j, sliceNumber, m); ctr++; } } } } break; case VOLUME_AXIS_ALL: break; case VOLUME_AXIS_OBLIQUE: break; case VOLUME_AXIS_OBLIQUE_X: break; case VOLUME_AXIS_OBLIQUE_Y: break; case VOLUME_AXIS_OBLIQUE_Z: break; case VOLUME_AXIS_OBLIQUE_ALL: break; case VOLUME_AXIS_UNKNOWN: break; } } /** * set a slice from a volume (sliceVoxelsIn should be size getSizeOfSlice()). */ void VolumeFile::setSlice(const VOLUME_AXIS axis, const int sliceNumber, const SLICE_DATA_ORDER dataOrder, const float* sliceVoxelsIn) { const int dimI = dimensions[0]; const int dimJ = dimensions[1]; const int dimK = dimensions[2]; const int numComp = getNumberOfComponentsPerVoxel(); switch (axis) { case VOLUME_AXIS_X: if (dataOrder == SLICE_DATA_ORDER_COLUMN) { int ctr = 0; for (int j = 0; j < dimJ; j++) { for (int k = 0; k < dimK; k++) { for (int m = 0; m < numComp; m++) { setVoxel(sliceNumber, j, k, m, sliceVoxelsIn[ctr]); ctr++; } } } } else { int ctr = 0; for (int k = 0; k < dimK; k++) { for (int j = 0; j < dimJ; j++) { for (int m = 0; m < numComp; m++) { setVoxel(sliceNumber, j, k, m, sliceVoxelsIn[ctr]); ctr++; } } } } break; case VOLUME_AXIS_Y: if (dataOrder == SLICE_DATA_ORDER_COLUMN) { int ctr = 0; for (int i = 0; i < dimI; i++) { for (int k = 0; k < dimK; k++) { for (int m = 0; m < numComp; m++) { setVoxel(i, sliceNumber, k, m, sliceVoxelsIn[ctr]); ctr++; } } } } else { int ctr = 0; for (int k = 0; k < dimK; k++) { for (int i = 0; i < dimI; i++) { for (int m = 0; m < numComp; m++) { setVoxel(i, sliceNumber, k, m, sliceVoxelsIn[ctr]); ctr++; } } } } break; case VOLUME_AXIS_Z: if (dataOrder == SLICE_DATA_ORDER_COLUMN) { int ctr = 0; for (int i = 0; i < dimI; i++) { for (int j = 0; j < dimJ; j++) { for (int m = 0; m < numComp; m++) { setVoxel(i, j, sliceNumber, m, sliceVoxelsIn[ctr]); ctr++; } } } } else { int ctr = 0; for (int j = 0; j < dimJ; j++) { for (int i = 0; i < dimI; i++) { for (int m = 0; m < numComp; m++) { setVoxel(i, j, sliceNumber, m, sliceVoxelsIn[ctr]); ctr++; } } } } break; case VOLUME_AXIS_ALL: break; case VOLUME_AXIS_OBLIQUE: break; case VOLUME_AXIS_OBLIQUE_X: break; case VOLUME_AXIS_OBLIQUE_Y: break; case VOLUME_AXIS_OBLIQUE_Z: break; case VOLUME_AXIS_OBLIQUE_ALL: break; case VOLUME_AXIS_UNKNOWN: break; } } /** * Rotate the volume clockwise about an axis while loooking down the axis * from the positive end of the axis to the negative end of the axis. */ void VolumeFile::rotate(const VOLUME_AXIS axis) { if (DebugControl::getDebugOn()) { std::cout << "VolumeFile rotating about axis: " << getAxisLabel(axis).toAscii().constData() << std::endl; } // // Copy current volume into the "old" volume // VolumeFile oldVolume = *this; // // Get information on current volume // int oldDim[3]; oldVolume.getDimensions(oldDim); float oldSpacing[3]; oldVolume.getSpacing(oldSpacing); float oldOrigin[3]; oldVolume.getOrigin(oldOrigin); ORIENTATION oldOrientation[3]; oldVolume.getOrientation(oldOrientation); // // Does this volume have a valid orientation. If not do not adjust spacing and origin. // bool validOrientation = false; switch (volumeSpace) { case VOLUME_SPACE_COORD_LPI: validOrientation = isValidOrientation(orientation); break; case VOLUME_SPACE_VOXEL_NATIVE: break; } // // Setup new dimensions and let spacing follow // // NOTE: IF THE VOLUME IS ROTATED USING EDIT VOLUME ATTRIBUTES, THE VOLUME MAY // APPEAR "UPSIDE DOWN". THIS MAY BE CORRECTED BY FLIPPING THE SIGNS OF THE // ORIGIN AND SPACING FOR ONE OF THE AXIS. // int newDim[3] = { dimensions[0], dimensions[1], dimensions[2] }; float newSpacing[3] = { oldSpacing[0], oldSpacing[1], oldSpacing[2] }; float newOrigin[3] = { oldOrigin[0], oldOrigin[1], oldOrigin[2] }; ORIENTATION newOrientation[3] = { oldOrientation[0], oldOrientation[1], oldOrientation[2] }; switch (axis) { case VOLUME_AXIS_X: newDim[0] = oldDim[0]; newDim[1] = oldDim[2]; newDim[2] = oldDim[1]; newSpacing[0] = oldSpacing[0]; newSpacing[1] = oldSpacing[2]; newSpacing[2] = oldSpacing[1]; if (validOrientation) { newSpacing[2] = -oldSpacing[1]; newOrigin[0] = oldOrigin[0]; newOrigin[1] = oldOrigin[2]; newOrigin[2] = (oldDim[1] * oldSpacing[1] + oldOrigin[1]); newOrientation[VOLUME_AXIS_X] = oldOrientation[VOLUME_AXIS_X]; newOrientation[VOLUME_AXIS_Y] = oldOrientation[VOLUME_AXIS_Z]; newOrientation[VOLUME_AXIS_Z] = getInverseOrientation(oldOrientation[VOLUME_AXIS_Y]); } break; case VOLUME_AXIS_Y: newDim[0] = oldDim[2]; newDim[1] = oldDim[1]; newDim[2] = oldDim[0]; newSpacing[0] = oldSpacing[2]; newSpacing[1] = oldSpacing[1]; newSpacing[2] = oldSpacing[0]; if (validOrientation) { newSpacing[2] = -oldSpacing[0]; newOrigin[0] = oldOrigin[2]; newOrigin[1] = oldOrigin[1]; newOrigin[2] = (oldDim[0] * oldSpacing[0] + oldOrigin[0]); newOrientation[VOLUME_AXIS_X] = oldOrientation[VOLUME_AXIS_Z]; newOrientation[VOLUME_AXIS_Y] = oldOrientation[VOLUME_AXIS_Y]; newOrientation[VOLUME_AXIS_Z] = getInverseOrientation(oldOrientation[VOLUME_AXIS_X]); } break; case VOLUME_AXIS_Z: newDim[0] = oldDim[1]; newDim[1] = oldDim[0]; newDim[2] = oldDim[2]; newSpacing[0] = oldSpacing[1]; newSpacing[1] = oldSpacing[0]; newSpacing[2] = oldSpacing[2]; if (validOrientation) { newSpacing[1] = -oldSpacing[0]; newOrigin[0] = oldOrigin[1]; newOrigin[1] = (oldDim[0] * oldSpacing[0] + oldOrigin[0]); newOrigin[2] = oldOrigin[2]; newOrientation[VOLUME_AXIS_X] = oldOrientation[VOLUME_AXIS_Y]; newOrientation[VOLUME_AXIS_Y] = getInverseOrientation(oldOrientation[VOLUME_AXIS_X]); newOrientation[VOLUME_AXIS_Z] = oldOrientation[VOLUME_AXIS_Z]; } break; case VOLUME_AXIS_ALL: std::cout << "ALL axis not supported for rotate() in VolumeFile." << std::endl; return; break; case VOLUME_AXIS_OBLIQUE: std::cout << "OBLIQUE axis not supported for rotate() in VolumeFile." << std::endl; return; break; case VOLUME_AXIS_OBLIQUE_X: std::cout << "X OBLIQUE axis not supported for rotate() in VolumeFile." << std::endl; return; break; case VOLUME_AXIS_OBLIQUE_Y: std::cout << "Y OBLIQUE axis not supported for rotate() in VolumeFile." << std::endl; return; break; case VOLUME_AXIS_OBLIQUE_Z: std::cout << "Z OBLIQUE axis not supported for rotate() in VolumeFile." << std::endl; return; break; case VOLUME_AXIS_OBLIQUE_ALL: std::cout << "ALL OBLIQUE axis not supported for rotate() in VolumeFile." << std::endl; return; break; case VOLUME_AXIS_UNKNOWN: std::cout << "UNKNOWN axis not supported for rotate() in VolumeFile." << std::endl; return; break; } // // Create a new structured points and initialize it // setDimensions(newDim); setOrigin(newOrigin); setSpacing(newSpacing); setOrientation(newOrientation); if (voxels != NULL) { // // Rotate the voxels into the new volume // switch (axis) { case VOLUME_AXIS_X: { // // Size of slice and memory for slice // const int sliceSize = getSizeOfSlice(VOLUME_AXIS_Z); float* sliceVoxels = new float[sliceSize]; // // Fill slices into new volume along K-axis going min to max // for (int k = 0; k < newDim[2]; k++) { // // Slice from old volume along J-axis going max to min // const int oldSliceNum = oldDim[1] - k - 1; // // Get the slice from the old volume // oldVolume.getSlice(VOLUME_AXIS_Y, oldSliceNum, SLICE_DATA_ORDER_ROW, sliceVoxels); // // Put slice in new volume // setSlice(VOLUME_AXIS_Z, k, SLICE_DATA_ORDER_ROW, sliceVoxels); } delete[] sliceVoxels; } break; case VOLUME_AXIS_Y: { // // Size of slice and memory for slice // const int sliceSize = getSizeOfSlice(VOLUME_AXIS_Z); float* sliceVoxels = new float[sliceSize]; // // Fill slices into new volume along K-axis going min to max // for (int k = 0; k < newDim[2]; k++) { // // Slice from old volume along I-axis going max to min // const int oldSliceNum = oldDim[0] - k - 1; // // Get the slice from the old volume // oldVolume.getSlice(VOLUME_AXIS_X, oldSliceNum, SLICE_DATA_ORDER_COLUMN, sliceVoxels); // // Put slice in new volume // setSlice(VOLUME_AXIS_Z, k, SLICE_DATA_ORDER_ROW, sliceVoxels); } delete[] sliceVoxels; } break; case VOLUME_AXIS_Z: { // // Size of slice and memory for slice // const int sliceSize = getSizeOfSlice(VOLUME_AXIS_Y); float* sliceVoxels = new float[sliceSize]; // // Fill slices into new volume along J-axis going min to max // for (int j = 0; j < newDim[1]; j++) { // // Slice from old volume along I-axis going max to min // const int oldSliceNum = oldDim[0] - j - 1; //j; // // Get the slice from the old volume // oldVolume.getSlice(VOLUME_AXIS_X, oldSliceNum, SLICE_DATA_ORDER_ROW, sliceVoxels); // // Put slice in new volume // setSlice(VOLUME_AXIS_Y, j, SLICE_DATA_ORDER_ROW, sliceVoxels); } delete[] sliceVoxels; } /* for (int k = 0; k < newDim[2]; k++) { for (int j = 0; j < newDim[1]; j++) { for (int i = 0; i < newDim[0]; i++) { int newIndx = i + j * newDim[0] + k * newDim[0] * newDim[1]; const int oi = (oldDim[0] - 1) - j; const int oj = i; const int ok = k; int oldIndx = oi + oj * oldDim[0] + ok * oldDim[0] * oldDim[1]; for (int m = 0; m < numComponents; m++) { voxels[newIndx + m] = oldVoxels[oldIndx + m]; } } } } */ break; case VOLUME_AXIS_ALL: std::cout << "ALL axis not supported for rotate() in VolumeFile." << std::endl; return; break; case VOLUME_AXIS_OBLIQUE: std::cout << "OBLIQUE axis not supported for rotate() in VolumeFile." << std::endl; return; break; case VOLUME_AXIS_OBLIQUE_X: std::cout << "X OBLIQUE axis not supported for rotate() in VolumeFile." << std::endl; return; break; case VOLUME_AXIS_OBLIQUE_Y: std::cout << "Y OBLIQUE axis not supported for rotate() in VolumeFile." << std::endl; return; break; case VOLUME_AXIS_OBLIQUE_Z: std::cout << "Z OBLIQUE axis not supported for rotate() in VolumeFile." << std::endl; return; break; case VOLUME_AXIS_OBLIQUE_ALL: std::cout << "ALL OBLIQUE axis not supported for rotate() in VolumeFile." << std::endl; return; break; case VOLUME_AXIS_UNKNOWN: std::cout << "UNKNOWN axis not supported for rotate() in VolumeFile." << std::endl; return; break; } } allocateVoxelColoring(); setModified(); minMaxVoxelValuesValid = false; minMaxTwoToNinetyEightPercentVoxelValuesValid = false; } /** * Determine if a voxel index is valid. */ bool VolumeFile::getVoxelIndexValid(const VoxelIJK& v) const { return getVoxelIndexValid(v.getIJK()); } /** * Determine if a voxel index is valid. */ bool VolumeFile::getVoxelIndexValid(const int ijk[3]) const { if (ijk[0] < 0) return false; if (ijk[0] >= dimensions[0]) return false; if (ijk[1] < 0) return false; if (ijk[1] >= dimensions[1]) return false; if (ijk[2] < 0) return false; if (ijk[2] >= dimensions[2]) return false; return true; } /** * Determine if a voxel index is valid. */ bool VolumeFile::getVoxelIndexValid(const int i, const int j, const int k) const { if (i < 0) return false; if (i >= dimensions[0]) return false; if (j < 0) return false; if (j >= dimensions[1]) return false; if (k < 0) return false; if (k >= dimensions[2]) return false; return true; } /** * get a voxel with a flat index. */ float VolumeFile::getVoxelWithFlatIndex(const int indx, const int component) const { return voxels[indx*numberOfComponentsPerVoxel + component]; } /** * set a voxel with a flat index. */ void VolumeFile::setVoxelWithFlatIndex(const int indx, const int component, const float value) { voxels[indx*numberOfComponentsPerVoxel + component] = value; setModified(); minMaxVoxelValuesValid = false; minMaxTwoToNinetyEightPercentVoxelValuesValid = false; } /** * get the coordinate of a voxel. */ void VolumeFile::getVoxelCoordinate(const int ijk[3], float coord[3]) const { getVoxelCoordinate(ijk[0], ijk[1], ijk[2], coord); } /** * get the coordinate at the center of the voxel. */ void VolumeFile::getVoxelCoordinate(const int i, const int j, const int k, float coord[3]) const { coord[0] = origin[0] + spacing[0] * i; coord[1] = origin[1] + spacing[1] * j; coord[2] = origin[2] + spacing[2] * k; /* if (centerOfVoxelFlag) { coord[0] += spacing[0] * 0.5; coord[1] += spacing[1] * 0.5; coord[2] += spacing[2] * 0.5; } */ } /// get the coordinate at the center of the voxel void VolumeFile::getVoxelCoordinate(const VoxelIJK& v, float coord[3]) const { getVoxelCoordinate(v.ijkv[0], v.ijkv[1], v.ijkv[2], coord); } /** * get a voxel. */ float VolumeFile::getVoxel(const int i, const int j, const int k, const int component) const { const int indx = getVoxelDataIndex(i, j, k, component); return voxels[indx]; } /** * get a voxel. */ float VolumeFile::getVoxel(const int ijk[3], const int component) const { const int indx = getVoxelDataIndex(ijk, component); return voxels[indx]; } /** * get a voxel. */ float VolumeFile::getVoxel(const VoxelIJK& v, const int component) const { const int indx = getVoxelDataIndex(v.getIJK(), component); return voxels[indx]; } /** * Get the value at a voxel. Returns true if a valid voxel index. * "voxelValue" should be allocated by the user and have * "getNumberOfComponentsPerVoxel" number of voxels. */ bool VolumeFile::getVoxelAllComponents(const int ijk[3], float* voxelValue) const { if (getVoxelIndexValid(ijk)) { if (voxels != NULL) { const int indx = getVoxelDataIndex(ijk); for (int i = 0; i < numberOfComponentsPerVoxel; i++) { voxelValue[i] = voxels[indx + i]; } return true; } } return false; } /** * get the index of this voxel ignoring the components). */ int VolumeFile::getVoxelNumber(const int i, const int j, const int k) const { const int indx = i + j * dimensions[0] + k * dimensions[0] * dimensions[1]; return indx; } /** * get the index of this voxel ignoring the components). */ int VolumeFile::getVoxelNumber(const VoxelIJK& v) const { return getVoxelNumber(v.ijkv[0], v.ijkv[1], v.ijkv[2]); } /** * get the index of this voxel ignoring the components). */ int VolumeFile::getVoxelNumber(const int ijk[3]) const { return getVoxelNumber(ijk[0], ijk[1], ijk[2]); } /** * Get the value at a voxel. Returns true if a valid voxel index. * "voxelValue" should be allocated by the user and have * "getNumberOfComponentsPerVoxel" number of voxels. */ bool VolumeFile::getVoxelAllComponents(const int i, const int j, const int k, float* voxelValue) const { int ijk[3] = { i, j, k }; return getVoxelAllComponents(ijk, voxelValue); } /** * Set the value at a voxel. * "voxelValue" should have "getNumberOfComponentsPerVoxel" number of voxels. */ void VolumeFile::setVoxelAllComponents(const int ijk[3], const float* voxelValue) { if (getVoxelIndexValid(ijk)) { if (voxels != NULL) { const int indx = getVoxelDataIndex(ijk); for (int i = 0; i < numberOfComponentsPerVoxel; i++) { voxels[indx + i] = voxelValue[i]; } setModified(); minMaxVoxelValuesValid = false; minMaxTwoToNinetyEightPercentVoxelValuesValid = false; // // Set color invalid for this voxel // if (voxelColoring != NULL) { const int indx = getVoxelColorIndex(ijk); voxelColoring[indx+3] = VOXEL_COLOR_STATUS_INVALID; } } } } /** * set all of the voxels in a slice. */ void VolumeFile::setAllVoxelsInSlice(const VOLUME_AXIS axis, const int sliceNumber, const float value) { if (sliceNumber < 0) { return; } int iMin = 0; int iMax = dimensions[0] - 1; int jMin = 0; int jMax = dimensions[1] - 1; int kMin = 0; int kMax = dimensions[2] - 1; switch (axis) { case VOLUME_AXIS_X: if (sliceNumber > iMax) { return; } iMin = sliceNumber; iMax = sliceNumber; break; case VOLUME_AXIS_Y: if (sliceNumber > jMax) { return; } jMin = sliceNumber; jMax = sliceNumber; break; case VOLUME_AXIS_Z: if (sliceNumber > kMax) { return; } kMin = sliceNumber; kMax = sliceNumber; break; case VOLUME_AXIS_ALL: case VOLUME_AXIS_OBLIQUE: case VOLUME_AXIS_OBLIQUE_X: case VOLUME_AXIS_OBLIQUE_Y: case VOLUME_AXIS_OBLIQUE_Z: case VOLUME_AXIS_OBLIQUE_ALL: case VOLUME_AXIS_UNKNOWN: return; break; } const int numComp = getNumberOfComponentsPerVoxel(); for (int i = iMin; i <= iMax; i++) { for (int j = jMin; j <= jMax; j++) { for (int k = kMin; k <= kMax; k++) { for (int m = 0; m < numComp; m++) { setVoxel(i, j, k, m, value); } } } } } /** * Set the value at a voxel. */ void VolumeFile::setVoxel(const int ijk[3], const int component, const float voxelValue) { if (getVoxelIndexValid(ijk)) { if (voxels != NULL) { const int indx = getVoxelDataIndex(ijk); voxels[indx + component] = voxelValue; setModified(); minMaxVoxelValuesValid = false; minMaxTwoToNinetyEightPercentVoxelValuesValid = false; // // Set color invalid for this voxel // if (voxelColoring != NULL) { const int indx = getVoxelColorIndex(ijk); voxelColoring[indx+3] = VOXEL_COLOR_STATUS_INVALID; } } } } /** * set a voxel at the specified index. */ void VolumeFile::setVoxel(const VoxelIJK& v, const int component, const float voxelValue) { const int ijk[3] = { v.getI(), v.getJ(), v.getK() }; setVoxel(ijk, component, voxelValue); } /** * set the value at a voxel. * "voxelValue" should be have "getNumberOfComponentsPerVoxel" number of voxels. */ void VolumeFile::setVoxelAllComponents(const int i, const int j, const int k, const float* voxelValue) { int ijk[3] = { i, j, k }; setVoxelAllComponents(ijk, voxelValue); } /** * set the value at a voxel. */ void VolumeFile::setVoxel(const int i, const int j, const int k, const int component, const float voxelValue) { int ijk[3] = { i, j, k }; setVoxel(ijk, component, voxelValue); } /** * set a bunch of voxels using one dimensional index. */ void VolumeFile::setVoxel(const std::vector indicies, const float voxelValue) { const int num = static_cast(indicies.size()); if (voxels != NULL) { if (numberOfComponentsPerVoxel > 0) { for (int i = 0; i < num; i++) { const int id = indicies[i]; for (int j = 0; j < numberOfComponentsPerVoxel; j++) { voxels[id+j] = voxelValue; } // // Set color invalid for this voxel // if (voxelColoring != NULL) { const int id4 = id * 4; voxelColoring[id4+3] = VOXEL_COLOR_STATUS_INVALID; } } setModified(); minMaxVoxelValuesValid = false; minMaxTwoToNinetyEightPercentVoxelValuesValid = false; } } } /** * set all voxels within a rectangle. */ void VolumeFile::setAllVoxelsInRectangle(const int extentIn[6], const float value) { int extent[6] = { extentIn[0], extentIn[1], extentIn[2], extentIn[3], extentIn[4], extentIn[5] }; clampVoxelDimension(VOLUME_AXIS_X, extent[0]); clampVoxelDimension(VOLUME_AXIS_X, extent[1]); clampVoxelDimension(VOLUME_AXIS_Y, extent[2]); clampVoxelDimension(VOLUME_AXIS_Y, extent[3]); clampVoxelDimension(VOLUME_AXIS_Z, extent[4]); clampVoxelDimension(VOLUME_AXIS_Z, extent[5]); for (int i = extent[0]; i < extent[1]; i++) { for (int j = extent[2]; j < extent[3]; j++) { for (int k = extent[4]; k < extent[5]; k++) { for (int m = 0; m < numberOfComponentsPerVoxel; m++) { setVoxel(i, j, k, m, value); } } } } } /** * set all of the voxels to a value. */ void VolumeFile::setAllVoxels(const float value) { const int num = getTotalNumberOfVoxelElements(); for (int i = 0; i < num; i++) { voxels[i] = value; } setModified(); minMaxVoxelValuesValid = false; minMaxTwoToNinetyEightPercentVoxelValuesValid = false; setVoxelColoringInvalid(); } /** * Set the colors for a voxel. This should only be used for editing the volume so * the colors match the voxel value. Note the 4th byte denotes whether or not * the voxel should be displayed and if the coloring is valid. */ void VolumeFile::setVoxelColor(const int ijk[3], const unsigned char rgb[4]) { if (getVoxelIndexValid(ijk)) { if (voxelColoring != NULL) { const int indx = getVoxelColorIndex(ijk); voxelColoring[indx] = rgb[0]; voxelColoring[indx+1] = rgb[1]; voxelColoring[indx+2] = rgb[2]; voxelColoring[indx+3] = rgb[3]; } } } /** * Set the colors for a voxel. This should only be used for editing the volume so * the colors match the voxel value. Note the 4th byte denotes whether or not * the voxel should be displayed and if the coloring is valid. */ void VolumeFile::setVoxelColor(const int i, const int j, const int k, const unsigned char rgb[4]) { if (getVoxelIndexValid(i, j, k)) { if (voxelColoring != NULL) { const int indx = getVoxelColorIndex(i, j, k); voxelColoring[indx] = rgb[0]; voxelColoring[indx+1] = rgb[1]; voxelColoring[indx+2] = rgb[2]; voxelColoring[indx+3] = rgb[3]; } } } /** * Set all voxels' colors invalid if the global coloring invalid flag is set */ void VolumeFile::checkForInvalidVoxelColors() { if (voxelColoringValid == false) { if (voxelColoring != NULL) { voxelColoringValid = true; const int numVoxels = getTotalNumberOfVoxels(); for (int i = 0; i < numVoxels; i++) { voxelColoring[i*4+3] = VOXEL_COLOR_STATUS_INVALID; } } } } /** * Get the color for a voxel. Note the 4th byte denotes whether or not * the voxel should be displayed. Returns true if a valid voxel index. */ bool VolumeFile::getVoxelColor(const int ijk[3], unsigned char rgb[4]) { if (getVoxelIndexValid(ijk)) { if (voxelColoring != NULL) { const int indx = getVoxelColorIndex(ijk); checkForInvalidVoxelColors(); rgb[0] = voxelColoring[indx]; rgb[1] = voxelColoring[indx+1]; rgb[2] = voxelColoring[indx+2]; rgb[3] = voxelColoring[indx+3]; return true; } } return false; } /** * compute a voxel color index. */ int VolumeFile::getVoxelColorIndex(const VoxelIJK& v) const { return getVoxelColorIndex(v.getI(), v.getJ(), v.getK()); } /** * compute a voxel color data index. */ int VolumeFile::getVoxelColorIndex(const int ijk[3]) const { return getVoxelColorIndex(ijk[0], ijk[1], ijk[2]); } /** * compute a voxel color data index. */ int VolumeFile::getVoxelColorIndex(const int i, const int j, const int k) const { const int indx = (i + j * dimensions[0] + k * dimensions[0] * dimensions[1]) * 4; return indx; } /** * Get the color for a voxel. Note the 4th byte denotes whether or not * the voxel should be displayed. Returns true if a valid voxel index. */ bool VolumeFile::getVoxelColor(const int i, const int j, const int k, unsigned char rgb[4]) { const int ijk[3] = { i, j, k }; return getVoxelColor(ijk, rgb); } /** * flip volume about an axis. * Cannot use vtkImageFlip because it crashes if more than one component per voxel (ie: rgb) */ void VolumeFile::flip(const VOLUME_AXIS axis, const bool updateOrientation) { int dim[3]; getDimensions(dim); float spacing[3]; getSpacing(spacing); float origin[3]; getOrigin(origin); float* data1 = NULL; float* data2 = NULL; if (voxels != NULL) { data1 = new float[numberOfComponentsPerVoxel]; data2 = new float[numberOfComponentsPerVoxel]; } if (DebugControl::getDebugOn()) { std::cout << "VolumeFile flipping about axis: " << getAxisLabel(axis).toAscii().constData() << std::endl; } switch(axis) { case VOLUME_AXIS_X: if (voxels != NULL) { for (int iz = 0; iz < dim[2]; iz++) { for (int iy = 0; iy < dim[1]; iy++) { const int halfDimX = dim[0] / 2; for (int ix = 0; ix < halfDimX; ix++) { const int ijk1[3] = { ix, iy, iz }; const int ijk2[3] = { dim[0] - ix - 1, iy, iz }; getVoxelAllComponents(ijk1, data1); getVoxelAllComponents(ijk2, data2); setVoxelAllComponents(ijk1, data2); setVoxelAllComponents(ijk2, data1); } } } } origin[0] = (dim[0] - 1)* spacing[0] + origin[0]; spacing[0] = -spacing[0]; break; case VOLUME_AXIS_Y: if (voxels != NULL) { for (int iz = 0; iz < dim[2]; iz++) { for (int ix = 0; ix < dim[0]; ix++) { const int halfDimY = dim[1] / 2; for (int iy = 0; iy < halfDimY; iy++) { const int ijk1[3] = { ix, iy, iz }; const int ijk2[3] = { ix, dim[1] - iy - 1, iz }; getVoxelAllComponents(ijk1, data1); getVoxelAllComponents(ijk2, data2); setVoxelAllComponents(ijk1, data2); setVoxelAllComponents(ijk2, data1); } } } } origin[1] = (dim[1] - 1) * spacing[1] + origin[1]; spacing[1] = -spacing[1]; break; case VOLUME_AXIS_Z: if (voxels != NULL) { for (int ix = 0; ix < dim[0]; ix++) { for (int iy = 0; iy < dim[1]; iy++) { const int halfDimZ = dim[2] / 2; for (int iz = 0; iz < halfDimZ; iz++) { const int ijk1[3] = { ix, iy, iz }; const int ijk2[3] = { ix, iy, dim[2] - iz - 1 }; getVoxelAllComponents(ijk1, data1); getVoxelAllComponents(ijk2, data2); setVoxelAllComponents(ijk1, data2); setVoxelAllComponents(ijk2, data1); } } } } origin[2] = (dim[2] - 1) * spacing[2] + origin[2]; spacing[2] = -spacing[2]; break; case VOLUME_AXIS_ALL: std::cout << "ALL axis not supported for flip() in VolumeFile." << std::endl; return; break; case VOLUME_AXIS_OBLIQUE: std::cout << "OBLIQUE axis not supported for flip() in VolumeFile." << std::endl; return; break; case VOLUME_AXIS_OBLIQUE_X: std::cout << "X OBLIQUE axis not supported for flip() in VolumeFile." << std::endl; return; break; case VOLUME_AXIS_OBLIQUE_Y: std::cout << "Y OBLIQUE axis not supported for flip() in VolumeFile." << std::endl; return; break; case VOLUME_AXIS_OBLIQUE_Z: std::cout << "Z OBLIQUE axis not supported for flip() in VolumeFile." << std::endl; return; break; case VOLUME_AXIS_OBLIQUE_ALL: std::cout << "ALL OBLIQUE axis not supported for flip() in VolumeFile." << std::endl; return; break; case VOLUME_AXIS_UNKNOWN: std::cout << "UNKNOWN axis not supported for flip() in VolumeFile." << std::endl; return; break; } // // Only update spacing and origin if the orientation is valid // if (isValidOrientation(orientation) && updateOrientation) { switch (volumeSpace) { case VOLUME_SPACE_COORD_LPI: setSpacing(spacing); setOrigin(origin); break; case VOLUME_SPACE_VOXEL_NATIVE: break; } } if (data1 != NULL) { delete[] data1; } if (data2 != NULL) { delete[] data2; } if (updateOrientation) { orientation[axis] = getInverseOrientation(orientation[axis]); } setModified(); minMaxVoxelValuesValid = false; minMaxTwoToNinetyEightPercentVoxelValuesValid = false; setVoxelColoringInvalid(); } /** * Get the volume extent of non-zero voxels. Return voxel index range of non-zero voxels. */ void VolumeFile::getNonZeroVoxelExtent(int extentVoxelIndices[6], float extentCoordinates[6]) const { bool voxelsFound = false; if (voxels != NULL) { extentVoxelIndices[0] = dimensions[0] + 1; extentVoxelIndices[1] = -1; extentVoxelIndices[2] = dimensions[1] + 1; extentVoxelIndices[3] = -1; extentVoxelIndices[4] = dimensions[2] + 1; extentVoxelIndices[5] = -1; for (int i = 0; i < dimensions[0]; i++) { for (int j = 0; j < dimensions[1]; j++) { for (int k = 0; k < dimensions[2]; k++) { for (int m = 0; m < numberOfComponentsPerVoxel; m++) { if (getVoxel(i, j, k, m) != 0.0) { voxelsFound = true; extentVoxelIndices[0] = std::min(extentVoxelIndices[0], i); extentVoxelIndices[1] = std::max(extentVoxelIndices[1], i); extentVoxelIndices[2] = std::min(extentVoxelIndices[2], j); extentVoxelIndices[3] = std::max(extentVoxelIndices[3], j); extentVoxelIndices[4] = std::min(extentVoxelIndices[4], k); extentVoxelIndices[5] = std::max(extentVoxelIndices[5], k); } } } } } } // // Nothing found // if (voxelsFound) { float xyz[3]; getVoxelCoordinate(extentVoxelIndices[0], extentVoxelIndices[2], extentVoxelIndices[4], xyz); extentCoordinates[0] = xyz[0]; extentCoordinates[2] = xyz[1]; extentCoordinates[4] = xyz[2]; getVoxelCoordinate(extentVoxelIndices[1], extentVoxelIndices[3], extentVoxelIndices[5], xyz); extentCoordinates[1] = xyz[0]; extentCoordinates[3] = xyz[1]; extentCoordinates[5] = xyz[2]; } else { extentVoxelIndices[0] = -1; extentVoxelIndices[1] = -1; extentVoxelIndices[2] = -1; extentVoxelIndices[3] = -1; extentVoxelIndices[4] = -1; extentVoxelIndices[5] = -1; } } /** * Get orientation */ void VolumeFile::getOrientation(VolumeFile::ORIENTATION orient[3]) const { orient[0] = orientation[0]; orient[1] = orientation[1]; orient[2] = orientation[2]; } /** * set orientation. */ void VolumeFile::setOrientation(const VolumeFile::ORIENTATION orient[3]) { orientation[0] = orient[0]; orientation[1] = orient[1]; orientation[2] = orient[2]; setModified(); } /** * Returns true if the orientation is valid. A valid orientation is one in which * one axis is left or right, one axis is posterior or anterior, and one axis is * inferior or superior. */ bool VolumeFile::isValidOrientation(const VolumeFile::ORIENTATION orient[3]) { int lrCount = 0; int paCount = 0; int isCount = 0; for (int i = 0; i < 3; i++) { switch (orient[i]) { case ORIENTATION_RIGHT_TO_LEFT: case ORIENTATION_LEFT_TO_RIGHT: lrCount++; break; case ORIENTATION_POSTERIOR_TO_ANTERIOR: case ORIENTATION_ANTERIOR_TO_POSTERIOR: paCount++; break; case ORIENTATION_INFERIOR_TO_SUPERIOR: case ORIENTATION_SUPERIOR_TO_INFERIOR: isCount++; break; case ORIENTATION_UNKNOWN: break; } } if ((lrCount == 1) && (paCount == 1) && (isCount == 1)) { return true; } return false; } /** * Get the inverse orientation for an orientation (ie "left" is inverse of "right") */ VolumeFile::ORIENTATION VolumeFile::getInverseOrientation(const VolumeFile::ORIENTATION orient) { switch (orient) { case ORIENTATION_UNKNOWN: return ORIENTATION_UNKNOWN; break; case ORIENTATION_RIGHT_TO_LEFT: return ORIENTATION_LEFT_TO_RIGHT; break; case ORIENTATION_LEFT_TO_RIGHT: return ORIENTATION_RIGHT_TO_LEFT; break; case ORIENTATION_POSTERIOR_TO_ANTERIOR: return ORIENTATION_ANTERIOR_TO_POSTERIOR; break; case ORIENTATION_ANTERIOR_TO_POSTERIOR: return ORIENTATION_POSTERIOR_TO_ANTERIOR; break; case ORIENTATION_INFERIOR_TO_SUPERIOR: return ORIENTATION_SUPERIOR_TO_INFERIOR; break; case ORIENTATION_SUPERIOR_TO_INFERIOR: return ORIENTATION_INFERIOR_TO_SUPERIOR; break; } return ORIENTATION_UNKNOWN; } /** * Get the ac position */ void VolumeFile::getSpmAcPosition(float ac[3]) const { ac[0] = spmAcPosition[0]; ac[1] = spmAcPosition[1]; ac[2] = spmAcPosition[2]; } /** * Set the ac position */ void VolumeFile::setSpmAcPosition(const float ac[3]) { spmAcPosition[0] = ac[0]; spmAcPosition[1] = ac[1]; spmAcPosition[2] = ac[2]; setModified(); } /** * get the dimensions of the volume (const method). */ void VolumeFile::getDimensions(int& dimX, int& dimY, int& dimZ) const { dimX = dimensions[0]; dimY = dimensions[1]; dimZ = dimensions[2]; } /** * Get the dimensions (const method) */ void VolumeFile::getDimensions(int dim[3]) const { dim[0] = dimensions[0]; dim[1] = dimensions[1]; dim[2] = dimensions[2]; } /** * Get the dimensions */ void VolumeFile::getDimensions(int dim[3]) { dim[0] = dimensions[0]; dim[1] = dimensions[1]; dim[2] = dimensions[2]; } /** * Set the dimensions */ void VolumeFile::setDimensions(const int dim[3]) { dimensions[0] = dim[0]; dimensions[1] = dim[1]; dimensions[2] = dim[2]; setModified(); } /** * Get the origin (at the center of the first voxel) */ void VolumeFile::getOrigin(float originOut[3]) const { originOut[0] = origin[0]; originOut[1] = origin[1]; originOut[2] = origin[2]; } /** * Set the origin (at the center of the first voxel) */ void VolumeFile::setOrigin(const float originIn[3]) { origin[0] = originIn[0]; origin[1] = originIn[1]; origin[2] = originIn[2]; setModified(); } /** * get the origin at the corner of the first voxel. */ void VolumeFile::getOriginAtCornerOfVoxel(float originCornerOfVoxelOut[3]) const { originCornerOfVoxelOut[0] = origin[0] - (spacing[0] * 0.5); originCornerOfVoxelOut[1] = origin[1] - (spacing[1] * 0.5); originCornerOfVoxelOut[2] = origin[2] - (spacing[2] * 0.5); } /** * set the origin at the corner of the first voxel. */ void VolumeFile::setOriginAtCornerOfVoxel(const float originCornerOfVoxelIn[3], const float voxelSizesIn[3]) { origin[0] = originCornerOfVoxelIn[0] + (voxelSizesIn[0] * 0.5); origin[1] = originCornerOfVoxelIn[1] + (voxelSizesIn[1] * 0.5); origin[2] = originCornerOfVoxelIn[2] + (voxelSizesIn[2] * 0.5); setModified(); } /** * Get the spacing */ void VolumeFile::getSpacing(float spacingOut[3]) const { spacingOut[0] = spacing[0]; spacingOut[1] = spacing[1]; spacingOut[2] = spacing[2]; } /** * Set the spacing */ void VolumeFile::setSpacing(const float spacingIn[3]) { spacing[0] = spacingIn[0]; spacing[1] = spacingIn[1]; spacing[2] = spacingIn[2]; setModified(); } /** * Resize the volume; if provided, update params with cropping. */ void VolumeFile::resize(const int cropping[6], ParamsFile* paramsFile) { if (voxels != NULL) { // // Get the new dimensions // int dimNew[3] = { cropping[1] - cropping[0] + 1, cropping[3] - cropping[2] + 1, cropping[5] - cropping[4] + 1 }; if ((dimNew[0] < 1) || (dimNew[1] < 1) || (dimNew[2] < 1)) { return; } // // if expanding an axis // for (int i = 0; i < 3; i++) { if (dimNew[i] > dimensions[i]) { // // Take one voxel off // dimNew[i]--; } } // // Keep the old volume data so that it can be copied // float* oldVoxels = voxels; float space[3]; getSpacing(space); int dimOld[3]; getDimensions(dimOld); float originOld[3]; getOrigin(originOld); // // Create new volume data // setDimensions(dimNew); setSpacing(spacing); voxels = new float[getTotalNumberOfVoxelElements()]; // // Set the new origin // float originNew[3] = { cropping[0] * spacing[0] + originOld[0], cropping[2] * spacing[1] + originOld[1], cropping[4] * spacing[2] + originOld[2] }; setOrigin(originNew); // // Load the cropped volumes voxels // for (int k = 0; k < dimNew[2]; k++) { for (int j = 0; j < dimNew[1]; j++) { for (int i = 0; i < dimNew[0]; i++) { // // Index to voxel that is to be set // int ijk[3] = { i, j, k }; const int pointID = getVoxelDataIndex(ijk); // // IJK index of voxel in "old" volume (prior to resizing) // int oldIJK[3] = { i + cropping[0], j + cropping[2], k + cropping[4] }; // // Is location valid in volume before resizing // if ((oldIJK[0] >= 0) && (oldIJK[0] < dimOld[0]) && (oldIJK[1] >= 0) && (oldIJK[1] < dimOld[1]) && (oldIJK[2] >= 0) && (oldIJK[2] < dimOld[2])) { const int oldPointID = (oldIJK[0] + oldIJK[1]* dimOld[0] + oldIJK[2] * dimOld[0] * dimOld[1]) * numberOfComponentsPerVoxel; for (int m = 0; m < numberOfComponentsPerVoxel; m++) { voxels[pointID + m] = oldVoxels[oldPointID + m]; } } else { for (int m = 0; m < numberOfComponentsPerVoxel; m++) { voxels[pointID + m] = 0.0; } } } } } // // Update the voxel coloring allocation // allocateVoxelColoring(); // // delete old voxels // delete[] oldVoxels; // // Update parameters file // if (paramsFile != NULL) { paramsFile->setParameter(ParamsFile::keyCropped, ParamsFile::keyValueYes); paramsFile->setParameter(ParamsFile::keyCropMinX, cropping[0]); paramsFile->setParameter(ParamsFile::keyCropMaxX, cropping[1]); paramsFile->setParameter(ParamsFile::keyCropMinY, cropping[2]); paramsFile->setParameter(ParamsFile::keyCropMaxY, cropping[3]); paramsFile->setParameter(ParamsFile::keyCropMinZ, cropping[4]); paramsFile->setParameter(ParamsFile::keyCropMaxZ, cropping[5]); } setModified(); minMaxVoxelValuesValid = false; minMaxTwoToNinetyEightPercentVoxelValuesValid = false; } } /** * pad segmentation volume (second/second to last slice along axis is extended). * In output volume first and last slices are all zeros. */ void VolumeFile::padSegmentation(const int padding[6], const bool erodePaddingFlag) { // // used for padding erosion // const int dilateIterations = 0; const int erodeIterations = 1; const int sliceStep = 5; // // Enlarge "this" volume // const int dimMod[6] = { -padding[0], dimensions[0] + padding[1], -padding[2], dimensions[1] + padding[3], -padding[4], dimensions[2] + padding[5], }; resize(dimMod); // // Copy "this" volume // VolumeFile origVolume(*this); // // Do left X padding // if (padding[0] > 0) { origVolume.fillSegmentationCavitiesInSingleSlice(VOLUME_AXIS_X, padding[0]); for (int i = 1; i <= padding[0]; i++) { copySlice(&origVolume, padding[0] + 1, VOLUME_AXIS_X, i); } if (erodePaddingFlag) { for (int iSlice = padding[0] - 1; iSlice > 0; iSlice -= sliceStep) { const int erodeExtent[6] = { 0, iSlice, 0, dimensions[1] - 1, 0, dimensions[2] - 1, }; doVolMorphOpsWithinMask(erodeExtent, dilateIterations, erodeIterations); } } } // // Do right X padding // if (padding[1] > 0) { const int iStart = dimensions[0] - padding[1]; origVolume.fillSegmentationCavitiesInSingleSlice(VOLUME_AXIS_X, iStart - 1); for (int i = iStart - 1; i < (dimensions[0] - 1); i++) { copySlice(&origVolume, iStart - 2, VOLUME_AXIS_X, i); } if (erodePaddingFlag) { for (int iSlice = iStart + 1; iSlice < dimensions[0]; iSlice += sliceStep) { const int erodeExtent[6] = { iSlice, dimensions[0] - 1, 0, dimensions[1] - 1, 0, dimensions[2] - 1, }; doVolMorphOpsWithinMask(erodeExtent, dilateIterations, erodeIterations); } } } // // Do posterior Y padding // if (padding[2] > 0) { origVolume.fillSegmentationCavitiesInSingleSlice(VOLUME_AXIS_Y, padding[2]); for (int j = 1; j <= padding[2]; j++) { copySlice(&origVolume, padding[2] + 1, VOLUME_AXIS_Y, j); } if (erodePaddingFlag) { for (int iSlice = padding[2] - 1; iSlice > 0; iSlice -= sliceStep) { const int erodeExtent[6] = { 0, dimensions[0] - 1, 0, iSlice, 0, dimensions[2] - 1, }; doVolMorphOpsWithinMask(erodeExtent, dilateIterations, erodeIterations); } } } // // Do anterior Y padding // if (padding[3] > 0) { const int jStart = dimensions[1] - padding[3]; origVolume.fillSegmentationCavitiesInSingleSlice(VOLUME_AXIS_Y, jStart - 1); for (int j = jStart - 1; j < (dimensions[1] - 1); j++) { copySlice(&origVolume, jStart - 2, VOLUME_AXIS_Y, j); } if (erodePaddingFlag) { for (int iSlice = jStart + 1; iSlice < dimensions[1]; iSlice += sliceStep) { const int erodeExtent[6] = { 0, dimensions[0] - 1, iSlice, dimensions[1] - 1, 0, dimensions[2] - 1, }; doVolMorphOpsWithinMask(erodeExtent, dilateIterations, erodeIterations); } } } // // Do inferior Z padding // if (padding[4] > 0) { origVolume.fillSegmentationCavitiesInSingleSlice(VOLUME_AXIS_Z, padding[4]); for (int k = 1; k <= padding[4]; k++) { copySlice(&origVolume, padding[4] + 1, VOLUME_AXIS_Z, k); } if (erodePaddingFlag) { for (int iSlice = padding[4] - 1; iSlice > 0; iSlice -= sliceStep) { const int erodeExtent[6] = { 0, dimensions[0] - 1, 0, dimensions[1] - 1, 0, iSlice, }; doVolMorphOpsWithinMask(erodeExtent, dilateIterations, erodeIterations); } } } // // Do superior Z padding // if (padding[5] > 0) { const int kStart = dimensions[2] - padding[5]; origVolume.fillSegmentationCavitiesInSingleSlice(VOLUME_AXIS_Z, kStart - 1); for (int k = kStart - 1; k < (dimensions[2] - 1); k++) { copySlice(&origVolume, kStart - 2, VOLUME_AXIS_Z, k); } if (erodePaddingFlag) { for (int iSlice = kStart + 1; iSlice < dimensions[2]; iSlice += sliceStep) { const int erodeExtent[6] = { 0, dimensions[0] - 1, 0, dimensions[1] - 1, iSlice, dimensions[2] - 1, }; doVolMorphOpsWithinMask(erodeExtent, dilateIterations, erodeIterations); } } } } /** * copy a subvolume to "this" volume. */ void VolumeFile::copySubVolume(const VolumeFile* sourceVolume, const int extentIn[6], const unsigned char offRgbValue[4], const unsigned char onRgbValue[4], VolumeModification* modifiedVoxels) throw (FileException) { if (sourceVolume == NULL) { throw FileException("Source Volume is invalid in VolumeFile::copySubVolume()"); } int sourceDim[3]; sourceVolume->getDimensions(sourceDim); if ((dimensions[0] != sourceDim[0]) || (dimensions[1] != sourceDim[1]) || (dimensions[2] != sourceDim[2])) { throw FileException("Source Volume has different dimensions in VolumeFile::copySubVolume()"); } if (numberOfComponentsPerVoxel != sourceVolume->getNumberOfComponentsPerVoxel()) { throw FileException("Source Volume has different number of components in VolumeFile::copySubVolume()"); } int extent[6] = { extent[0] = extentIn[0], extent[1] = extentIn[1], extent[2] = extentIn[2], extent[3] = extentIn[3], extent[4] = extentIn[4], extent[5] = extentIn[5], }; clampVoxelIndex(VOLUME_AXIS_X, extent[0]); clampVoxelIndex(VOLUME_AXIS_X, extent[1]); clampVoxelIndex(VOLUME_AXIS_Y, extent[2]); clampVoxelIndex(VOLUME_AXIS_Y, extent[3]); clampVoxelIndex(VOLUME_AXIS_Z, extent[4]); clampVoxelIndex(VOLUME_AXIS_Z, extent[5]); for (int i = extent[0]; i <= extent[1]; i++) { for (int j = extent[2]; j <= extent[3]; j++) { for (int k = extent[4]; k <= extent[5]; k++) { for (int m = 0; m < numberOfComponentsPerVoxel; m++) { const float v = sourceVolume->getVoxel(i, j, k, m); setVoxel(i, j, k, m, v); if (m == 0) { if (modifiedVoxels != NULL) { modifiedVoxels->addVoxel(this, i, j, k); } if (v != 0.0) { setVoxelColor(i, j, k, onRgbValue); } else { setVoxelColor(i, j, k, offRgbValue); } } } } } } } /** * copy a slice to "this" volume. Dimensions orthogonal to axis must match. */ void VolumeFile::copySlice(const VolumeFile* sourceVolume, const int sourceSliceNumber, const VOLUME_AXIS axis, const int destinationSliceNumber) { int sourceDim[3]; sourceVolume->getDimensions(sourceDim); const int numComp = getNumberOfComponentsPerVoxel(); if (sourceVolume->getNumberOfComponentsPerVoxel() != numComp) { return; } switch (axis) { case VOLUME_AXIS_X: if ((dimensions[1] != sourceDim[1]) || (dimensions[2] != sourceDim[2])) { return; } if ((sourceSliceNumber < 0) || (sourceSliceNumber >= sourceDim[0])) { return; } if ((destinationSliceNumber < 0) || (destinationSliceNumber >= dimensions[0])) { return; } for (int j = 0; j < dimensions[1]; j++) { for (int k = 0; k < dimensions[2]; k++) { for (int m = 0; m < numComp; m++) { setVoxel(destinationSliceNumber, j, k, m, sourceVolume->getVoxel(sourceSliceNumber, j, k, m)); } } } break; case VOLUME_AXIS_Y: if ((dimensions[0] != sourceDim[0]) || (dimensions[2] != sourceDim[2])) { return; } if ((sourceSliceNumber < 0) || (sourceSliceNumber >= sourceDim[1])) { return; } if ((destinationSliceNumber < 0) || (destinationSliceNumber >= dimensions[1])) { return; } for (int i = 0; i < dimensions[0]; i++) { for (int k = 0; k < dimensions[2]; k++) { for (int m = 0; m < numComp; m++) { setVoxel(i, destinationSliceNumber, k, m, sourceVolume->getVoxel(i, sourceSliceNumber, k, m)); } } } break; case VOLUME_AXIS_Z: if ((dimensions[0] != sourceDim[0]) || (dimensions[1] != sourceDim[1])) { return; } if ((sourceSliceNumber < 0) || (sourceSliceNumber >= sourceDim[2])) { return; } if ((destinationSliceNumber < 0) || (destinationSliceNumber >= dimensions[2])) { return; } for (int i = 0; i < dimensions[0]; i++) { for (int j = 0; j < dimensions[1]; j++) { for (int m = 0; m < numComp; m++) { setVoxel(i, j, destinationSliceNumber, m, sourceVolume->getVoxel(i, j, sourceSliceNumber, m)); } } } break; case VOLUME_AXIS_ALL: std::cout << "ERROR: ALL axis not supported for copySlice()." << std::endl; return; break; case VOLUME_AXIS_OBLIQUE: std::cout << "ERROR: OBLIQUE axis not supported for copySlice()." << std::endl; return; break; case VOLUME_AXIS_OBLIQUE_X: std::cout << "ERROR: X OBLIQUE axis not supported for copySlice()." << std::endl; return; break; case VOLUME_AXIS_OBLIQUE_Y: std::cout << "ERROR: Y OBLIQUE axis not supported for copySlice()." << std::endl; return; break; case VOLUME_AXIS_OBLIQUE_Z: std::cout << "ERROR: Z OBLIQUE axis not supported for copySlice()." << std::endl; return; break; case VOLUME_AXIS_OBLIQUE_ALL: std::cout << "ERROR: ALL OBLIQUE axis not supported for copySlice()." << std::endl; return; break; case VOLUME_AXIS_UNKNOWN: std::cout << "ERROR: UNKNOWN axis not supported for copySlice()." << std::endl; return; break; } } /** * convert coordinates into a voxel index (returns true if inside volume). * NOTE: copied from VTK's * Copyright (c) 1993-2002 Ken Martin, Will Schroeder, Bill Lorensen */ bool VolumeFile::convertCoordinatesToVoxelIJK(const float* xyz, int ijk[3]) const { float offset[3]; return convertCoordinatesToVoxelIJK(xyz, ijk, offset); } /** * convert coordinates into a voxel index (returns true if inside volume). * NOTE: copied from VTK's * Copyright (c) 1993-2002 Ken Martin, Will Schroeder, Bill Lorensen */ bool VolumeFile::convertCoordinatesToVoxelIJK(const float* xyz, int ijk[3], float offset[3]) const { bool insideVolume = true; // // NOTE: Origin is at center of voxel but we need to know the coordinate // at the corner of the voxel // float originCorner[3]; getOriginAtCornerOfVoxel(originCorner); // // Compute the ijk location // for (int i=0; i<3; i++) { const float d = xyz[i] - originCorner[i]; const float floatLoc = d / spacing[i]; // Floor for negtive indexes. ijk[i] = (int) (floor(floatLoc)); if ( ijk[i] >= 0 && ijk[i] < dimensions[i] ) { offset[i] = floatLoc - (float)ijk[i]; } else if ( ijk[i] < 0 || ijk[i] > dimensions[i] ) { offset[i] = floatLoc - (float)ijk[i]; insideVolume = false; } else { //if ( ijk[i] == dimensions[i] ) if (dimensions[i] == 1) { offset[i] = 0.0; } else { ijk[i] -= 1; offset[i] = 1.0; } } } return insideVolume; } /** * Get an "interpolated" voxel at a coordinate. * The coordinate is the center of the interpolated voxel. * Returns true if the coordinate is in the volume, else false. */ bool VolumeFile::getInterpolatedVoxel(const float xyzIn[3], float& voxelValue) { // // Because of the weighting system used, we need to offset // by half a voxel. This since voxels interpolated are always // to the larger indices. Without this, if the xyz was near the // left edge of a voxel, the voxel on the to the left would not // get used. // const float xyz[3] = { xyzIn[0] - (spacing[0] * 0.5), xyzIn[1] - (spacing[1] * 0.5), xyzIn[2] - (spacing[2] * 0.5) }; voxelValue = 0.0; // // Get the voxel coordinates // int ijk[3]; float pcoords[3]; const int insideVolume = convertCoordinatesToVoxelIJK((float*)xyz, ijk, pcoords); if (insideVolume == false) { return false; } // // Is this voxel along the edge of the volume // if ((ijk[0] == 0) || (ijk[0] == (dimensions[0] - 1)) || (ijk[1] == 0) || (ijk[1] == (dimensions[1] - 1)) || (ijk[2] == 0) || (ijk[2] == (dimensions[2] - 1))) { voxelValue = getVoxel(ijk); } else { convertCoordinatesToVoxelIJK(xyz, ijk, pcoords); const float r = pcoords[0]; const float s = pcoords[1]; const float t = pcoords[2]; // // Weighting from book Visualization Toolkit, 2nd Ed, page 316 // for (int j = 0; j < 8; j++) { int dijk[3] = { 0, 0, 0 }; float weight = 0.0; switch(j) { case 0: weight = (1.0 - r) * (1.0 - s) * (1.0 - t); break; case 1: weight = r * (1.0 - s) * (1.0 - t); dijk[0] = 1; break; case 2: weight = (1.0 - r) * s * (1.0 - t); dijk[1] = 1; break; case 3: weight = r * s * (1.0 - t); dijk[0] = 1; dijk[1] = 1; break; case 4: weight = (1.0 - r) * (1.0 - s) * t; dijk[2] = 1; break; case 5: weight = r * (1.0 - s) * t; dijk[0] = 1; dijk[2] = 1; break; case 6: weight = (1.0 - r) * s * t; dijk[1] = 1; dijk[2] = 1; break; case 7: weight = r * s * t; dijk[0] = 1; dijk[1] = 1; dijk[2] = 1; break; } // // adjust the voxel indices // int vijk[3] = { ijk[0] + dijk[0], ijk[1] + dijk[1], ijk[2] + dijk[2] }; // // Add into the voxel // const float vv = getVoxel(vijk, 0); voxelValue += vv * weight; } } return true; } /** * convert to VTK structured points. */ vtkStructuredPoints* VolumeFile::convertToVtkStructuredPoints(const bool makeUnsignedCharType) const { vtkStructuredPoints* sp = vtkStructuredPoints::New(); sp->SetDimensions((int*)dimensions); #ifdef HAVE_VTK5 { double ds[3] = { spacing[0], spacing[1], spacing[2] }; double dorg[3] = { origin[0], origin[1], origin[2] }; sp->SetSpacing(ds); sp->SetOrigin(dorg); } #else // HAVE_VTK5 sp->SetSpacing((float*)spacing); sp->SetOrigin((float*)origin); #endif // HAVE_VTK5 const int numVoxels = getTotalNumberOfVoxels(); vtkDataArray* scalars = NULL; if (makeUnsignedCharType) { scalars = vtkUnsignedCharArray::New(); sp->SetScalarTypeToUnsignedChar(); } else { scalars = vtkFloatArray::New(); sp->SetScalarTypeToFloat(); } scalars->SetNumberOfComponents(numberOfComponentsPerVoxel); scalars->SetNumberOfTuples(numVoxels); float* temp = new float[numberOfComponentsPerVoxel]; for (int i = 0; i < numVoxels; i++) { for (int m = 0; m < numberOfComponentsPerVoxel; m++) { float f = voxels[i*numberOfComponentsPerVoxel+m]; if (makeUnsignedCharType) { f = std::min(255.0f, f); f = std::max(0.0f, f); } temp[m] = f; } scalars->InsertTuple(i, temp); } delete[] temp; sp->GetPointData()->SetScalars(scalars); scalars->Delete(); return sp; } /** * convert from VTK structured points. */ void VolumeFile::convertFromVtkStructuredPoints(vtkStructuredPoints* sp) { if (voxels != NULL) { delete[] voxels; voxels = NULL; } sp->GetDimensions(dimensions); #ifdef HAVE_VTK5 { double ds[3]; double dorg[3]; sp->GetSpacing(ds); sp->GetOrigin(dorg); spacing[0] = ds[0]; spacing[1] = ds[1]; spacing[2] = ds[2]; const float forg[3] = { dorg[0], dorg[1], dorg[2] }; setOrigin(forg); } #else // HAVE_VTK5 sp->GetSpacing(spacing); sp->GetOrigin(origin); #endif // HAVE_VTK5 vtkDataArray* scalars = sp->GetPointData()->GetScalars(); numberOfComponentsPerVoxel = scalars->GetNumberOfComponents(); const int num = getTotalNumberOfVoxels(); voxels = new float[num]; for (int i = 0; i < num; i++) { for (int j = 0; j < numberOfComponentsPerVoxel; j++) { const int indx = i * numberOfComponentsPerVoxel + j; voxels[indx] = scalars->GetComponent(i, j); } } allocateVoxelColoring(); setModified(); minMaxVoxelValuesValid = false; minMaxTwoToNinetyEightPercentVoxelValuesValid = false; } /** * convert from VTK image data. */ void VolumeFile::convertFromVtkImageData(vtkImageData* sp) { if (voxels != NULL) { delete[] voxels; voxels = NULL; } sp->GetDimensions(dimensions); #ifdef HAVE_VTK5 { double ds[3]; double dorg[3]; sp->GetSpacing(ds); sp->GetOrigin(dorg); spacing[0] = ds[0]; spacing[1] = ds[1]; spacing[2] = ds[2]; const float forg[3] = { dorg[0], dorg[1], dorg[2] }; setOrigin(forg); } #else // HAVE_VTK5 sp->GetSpacing(spacing); sp->GetOrigin(origin); #endif // HAVE_VTK5 vtkDataArray* scalars = sp->GetPointData()->GetScalars(); numberOfComponentsPerVoxel = scalars->GetNumberOfComponents(); const int num = getTotalNumberOfVoxels(); voxels = new float[num]; for (int i = 0; i < num; i++) { for (int j = 0; j < numberOfComponentsPerVoxel; j++) { const int indx = i * numberOfComponentsPerVoxel + j; voxels[indx] = scalars->GetComponent(i, j); } } allocateVoxelColoring(); setModified(); } /** * convert to VTK image data. */ vtkImageData* VolumeFile::convertToVtkImageData(const bool makeUnsignedCharType) const { vtkImageData* id = vtkImageData::New(); id->SetDimensions((int*)dimensions); #ifdef HAVE_VTK5 { double ds[3] = { spacing[0], spacing[1], spacing[2] }; float forg[3]; getOriginAtCornerOfVoxel(forg); double dorg[3] = { forg[0], forg[1], forg[2] }; id->SetSpacing(ds); id->SetOrigin(dorg); } #else // HAVE_VTK5 id->SetSpacing((float*)spacing); id->SetOrigin((float*)origin); #endif // HAVE_VTK5 const int numVoxels = getTotalNumberOfVoxels(); vtkDataArray* scalars = NULL; if (makeUnsignedCharType) { scalars = vtkUnsignedCharArray::New(); id->SetScalarTypeToUnsignedChar(); } else { scalars = vtkFloatArray::New(); id->SetScalarTypeToFloat(); } scalars->SetNumberOfComponents(numberOfComponentsPerVoxel); scalars->SetNumberOfTuples(numVoxels); float* temp = new float[numberOfComponentsPerVoxel]; for (int i = 0; i < numVoxels; i++) { for (int m = 0; m < numberOfComponentsPerVoxel; m++) { float f = voxels[i*numberOfComponentsPerVoxel+m]; if (makeUnsignedCharType) { f = std::min(255.0f, f); f = std::max(0.0f, f); } temp[m] = f; } scalars->InsertTuple(i, temp); } delete[] temp; id->GetPointData()->SetScalars(scalars); scalars->Delete(); return id; } /** * Apply transformation matrix to a volume. */ void VolumeFile::applyTransformationMatrix(const TransformationMatrix& tmIn) { // // This makes the transfomations function correctly // TransformationMatrix tm(tmIn); float trans[3]; tm.getTranslation(trans[0], trans[1], trans[2]); tm.translate(0.0, 0.0, 0.0); tm.transpose(); tm.translate(trans[0], trans[1], trans[2]); vtkTransform* transform = vtkTransform::New(); tm.getMatrix(transform); applyTransformationMatrix(transform); transform->Delete(); } /** * Apply transformation matrix to a volume. */ void VolumeFile::applyTransformationMatrix(vtkTransform* transform) { vtkStructuredPoints* spInput = convertToVtkStructuredPoints(); vtkImageReslice* reslice = vtkImageReslice::New(); reslice->SetNumberOfThreads(1); reslice->SetInput(spInput); reslice->SetInformationInput(spInput); reslice->SetResliceTransform(transform); reslice->SetAutoCropOutput(1); switch (volumeType) { case VOLUME_TYPE_ANATOMY: reslice->SetInterpolationModeToCubic(); break; case VOLUME_TYPE_FUNCTIONAL: reslice->SetInterpolationModeToCubic(); break; case VOLUME_TYPE_PAINT: reslice->SetInterpolationModeToNearestNeighbor(); break; case VOLUME_TYPE_PROB_ATLAS: reslice->SetInterpolationModeToNearestNeighbor(); break; case VOLUME_TYPE_RGB: reslice->SetInterpolationModeToNearestNeighbor(); break; case VOLUME_TYPE_ROI: reslice->SetInterpolationModeToNearestNeighbor(); break; case VOLUME_TYPE_SEGMENTATION: reslice->SetInterpolationModeToNearestNeighbor(); break; case VOLUME_TYPE_VECTOR: reslice->SetInterpolationModeToNearestNeighbor(); break; case VOLUME_TYPE_UNKNOWN: reslice->SetInterpolationModeToCubic(); break; } reslice->Update(); convertFromVtkImageData(reslice->GetOutput()); reslice->Delete(); spInput->Delete(); allocateVoxelColoring(); setModified(); minMaxVoxelValuesValid = false; minMaxTwoToNinetyEightPercentVoxelValuesValid = false; } /** * resample the image to the specified spacing. */ void VolumeFile::resampleToSpacing(const float newSpacing[3], const INTERPOLATION_TYPE interpolationType) { vtkStructuredPoints* spInput = convertToVtkStructuredPoints(); vtkImageResample* resample = vtkImageResample::New(); resample->SetNumberOfThreads(1); resample->SetInput(spInput); resample->SetAxisOutputSpacing(0, newSpacing[0]); resample->SetAxisOutputSpacing(1, newSpacing[1]); resample->SetAxisOutputSpacing(2, newSpacing[2]); resample->SetDimensionality(3); resample->SetInterpolationModeToCubic(); switch (interpolationType) { case INTERPOLATION_TYPE_CUBIC: resample->SetInterpolationModeToCubic(); break; case INTERPOLATION_TYPE_LINEAR: resample->SetInterpolationModeToLinear(); break; case INTERPOLATION_TYPE_NEAREST_NEIGHBOR: resample->SetInterpolationModeToNearestNeighbor(); break; } resample->Update(); convertFromVtkImageData(resample->GetOutput()); resample->Delete(); spInput->Delete(); allocateVoxelColoring(); setModified(); minMaxVoxelValuesValid = false; minMaxTwoToNinetyEightPercentVoxelValuesValid = false; } /** * make all voxels in a segmentation volume 0 or 255. */ void VolumeFile::makeSegmentationZeroTwoFiftyFive() { const int num = getTotalNumberOfVoxelElements(); for (int i = 0; i < num; i++) { if (voxels[i] != 0.0) { voxels[i] = 255.0; } } setModified(); minMaxVoxelValuesValid = false; minMaxTwoToNinetyEightPercentVoxelValuesValid = false; } /** * Import an analyze volume. */ void VolumeFile::importAnalyzeVolume(const QString& fileNameIn) throw (FileException) { readFile(fileNameIn); } /** * Import a minc volume. */ void VolumeFile::importMincVolume(const QString& fileName) throw (FileException) { #ifdef HAVE_MINC filename = fileName; int output_signed, is_signed, mincid, imgid, icvid; double valid_range[2] = {0.0,0.0}; nc_type datatype, output_datatype=NC_FLOAT; int ndims, dims[MAX_VAR_DIMS], idim, jdim, dataSizeInBytes, i, slice_offset; long start[MAX_VAR_DIMS], count[MAX_VAR_DIMS], end[MAX_VAR_DIMS]; long size; double temp; /* Open the file */ mincid = miopen((char*)fileName.toAscii().constData(), NC_NOWRITE); /* Inquire about the image variable */ imgid = ncvarid(mincid, MIimage); ncvarinq(mincid, imgid, NULL, NULL, &ndims, dims, NULL); miget_datatype(mincid, imgid, &datatype, &is_signed); /* Output is NC_FLOAT type -> signed. */ output_signed = TRUE; /* Get output range */ if (output_datatype == datatype) { miget_valid_range(mincid, imgid, valid_range); } else { miget_default_range(output_datatype, output_signed, valid_range); if ((datatype == NC_CHAR) || (datatype == NC_BYTE)) { valid_range[0] = 0.0; valid_range[1] = 255.0; } } if (valid_range[0] > valid_range[1]) { temp = valid_range[0]; valid_range[0] = valid_range[1]; valid_range[1] = temp; } ORIENTATION orient[3] = { ORIENTATION_UNKNOWN, ORIENTATION_UNKNOWN, ORIENTATION_UNKNOWN }; /* --------------- MNI's mincstats.c --------------- */ /* Get start, step, and dircos attributes */ const int WORLD_NDIMS = 3; double dircos[WORLD_NDIMS]; double voxdim, origin; // called step and start in minc, but start means something else here const char *dimensions[] = {MIxspace, MIyspace, MIzspace}; QString dimensionNames[3] = { "zspace", "yspace", "xspace" }; float mincOrigin[3] = { 0.0, 0.0, 0.0 }; float mincVoxDim[3] = { 1.0, 1.0, 1.0 }; for (jdim=0; jdim < WORLD_NDIMS; jdim++) { /* Set default values */ voxdim = 1.0; origin = 0.0; for (idim=0; idim < WORLD_NDIMS; idim++) dircos[idim] = 0.0; dircos[jdim] = 1.0; /* Get the attributes */ get_minc_attribute(mincid, (char*)dimensions[jdim], MIstart, 1, &origin); get_minc_attribute(mincid, (char*)dimensions[jdim], MIstep, 1, &voxdim); get_minc_attribute(mincid, (char*)dimensions[jdim], MIdirection_cosines, WORLD_NDIMS, dircos); mincOrigin[jdim] = origin; mincVoxDim[jdim] = voxdim; char dimName[MAX_NC_NAME]; ncdiminq(mincid, dims[jdim], dimName, NULL); dimensionNames[jdim] = StringUtilities::makeLowerCase(dimName); /* if (mivar_exists(mincid, MIalignment)) { const int MAX_LEN_STR = 256; char alignChars[MAX_LEN_STR]; int varid = ncvarid(mincid, MIalignment); char* alignmentStr = miattgetstr(mincid, varid, MIalignment, MAX_LEN_STR, alignChars); if (alignmentStr != NULL) { std::cout << "MINC alignment: " << alignmentStr << std::endl; } } */ if (DebugControl::getDebugOn()) { std::cout << "----dim=" << jdim << "----" << std::endl; std::cout << "origin=" << (float)origin << std::endl; std::cout << "voxdim=" << (float)voxdim << std::endl; std::cout << "dircos=" << (float)dircos[0] << "," << (float)dircos[1] << ", " << (float)dircos[2] << std::endl; std::cout << "name =" << dimName << std::endl; } orient[jdim] = ORIENTATION_UNKNOWN; if (dircos[0] == 1.0) { orient[jdim] = ORIENTATION_LEFT_TO_RIGHT; } else if (dircos[0] == -1.0) { orient[jdim] = ORIENTATION_RIGHT_TO_LEFT; } else if (dircos[1] == 1.0) { orient[jdim] = ORIENTATION_POSTERIOR_TO_ANTERIOR; } else if (dircos[1] == -1.0) { orient[jdim] = ORIENTATION_ANTERIOR_TO_POSTERIOR; } else if (dircos[2] == 1.0) { orient[jdim] = ORIENTATION_INFERIOR_TO_SUPERIOR; } else if (dircos[2] == -1.0) { orient[jdim] = ORIENTATION_SUPERIOR_TO_INFERIOR; } } /* ----------- back to MNI's minctoraw.c ------------ */ /* Set up image conversion */ icvid = miicv_create(); miicv_setint(icvid, MI_ICV_TYPE, output_datatype); miicv_setstr(icvid, MI_ICV_SIGN, (char*)(output_signed ? MI_SIGNED : MI_UNSIGNED)); miicv_setdbl(icvid, MI_ICV_VALID_MIN, valid_range[0]); miicv_setdbl(icvid, MI_ICV_VALID_MAX, valid_range[1]); miicv_setint(icvid, MI_ICV_DO_NORM, TRUE); //miicv_setint(icvid, MI_ICV_USER_NORM, TRUE); miicv_attach(icvid, mincid, imgid); /* Set input file start, count and end vectors for reading a slice at a time */ for (idim=0; idim < ndims; idim++) { ncdiminq(mincid, dims[idim], NULL, &end[idim]); } /* DLH Note: end[2]=xdim; end[1]=ydim; end[0]=zdim */ miset_coords(ndims, (long) 0, start); miset_coords(ndims, (long) 1, count); dataSizeInBytes = size = nctypelen(output_datatype); int pixels = 1; for (idim=ndims-2; idim < ndims; idim++) { count[idim] = end[idim]; size *= count[idim]; pixels *= count[idim]; } int num_voxels = pixels*end[0]; if (DebugControl::getDebugOn()) { std::cout << "valid range: " << valid_range[0] << " - " << valid_range[1] << std::endl; std::cout << "dims: " << dims[0] << " " << dims[1] << " " << dims[2] << std::endl; std::cout << "dataSizeInBytes: " << dataSizeInBytes << std::endl; std::cout << "size: " << (int)size << " pixels " << pixels << " voxels " << num_voxels << std::endl; std::cout << "start: " << (int)start[0] << " " << (int)start[1] << " " << (int)start[2] << std::endl; std::cout << "count: " << (int)count[0] << " " << (int)count[1] << " " << (int)count[2] << std::endl; std::cout << "end: " << (int)end[0] << " " << (int)end[1] << " " << (int)end[2] << std::endl; } /* Allocate space */ float* slicedata = new float [pixels]; float* voxdataflat = new float [num_voxels]; /* Loop over input slices */ while (start[0] < end[0]) { /* Read in the slice */ miicv_get(icvid, start, count, (void*)slicedata); /* Copy slice to volume */ slice_offset = start[0]*pixels; for ( i=0 ; i < pixels ; i++ ) voxdataflat[i+slice_offset] = slicedata[i]; /* Increment start counter */ idim = ndims-1; start[idim] += count[idim]; while ( (idim>0) && (start[idim] >= end[idim])) { start[idim] = 0; idim--; start[idim] += count[idim]; } } /* End loop over slices */ // float org[3] = { 0.0, 0.0, 0.0 }; // float space[3] = { 1.0, 1.0, 1.0 }; int dimen[3] = { end[2], end[1], end[0] }; // // In most cases the data is stored z, y, x which is LPI. // The following code handles all storage orientations // ORIENTATION initOrient[3] = { orient[0], orient[1], orient[2] }; float initOrigin[3] = { mincOrigin[0], mincOrigin[1], mincOrigin[2] }; float initVoxDim[3] = { mincVoxDim[0], mincVoxDim[1], mincVoxDim[2] }; for (int i = 0; i < 3; i++) { const int ii = 2 - i; int indx = -1; if (dimensionNames[i] == "zspace") { indx = 2; } else if (dimensionNames[i] == "yspace") { indx = 1; } else if (dimensionNames[i] == "xspace") { indx = 0; } initOrient[ii] = orient[indx]; initOrigin[ii] = mincOrigin[indx]; initVoxDim[ii] = mincVoxDim[indx]; } initOrigin[0] += (initVoxDim[0] * 0.5); initOrigin[1] += (initVoxDim[1] * 0.5); initOrigin[2] += (initVoxDim[2] * 0.5); initialize(VOXEL_DATA_TYPE_FLOAT, dimen, initOrient, //orient, initOrigin, //mincOrigin, initVoxDim, //mincVoxDim, true, true); filename = fileName; // // Set the voxels // for (int i = 0; i < num_voxels; i++) { voxels[i] = voxdataflat[i]; } /* Clean up */ miclose(mincid); miicv_free(icvid); delete [] slicedata; delete [] voxdataflat; // // Is the orientation valid? If so, the volume may still need to be made LPI // if (isValidOrientation(initOrient)) { const VolumeFile::ORIENTATION lpiOrientation[3] = { VolumeFile::ORIENTATION_LEFT_TO_RIGHT, VolumeFile::ORIENTATION_POSTERIOR_TO_ANTERIOR, VolumeFile::ORIENTATION_INFERIOR_TO_SUPERIOR }; bool makeItLPI = false; for (int i = 0; i < 3; i++) { if (initOrient[i] != lpiOrientation[i]) { makeItLPI = true; break; } } if (makeItLPI) { // // Make the volume LPI // try { permuteToOrientation(lpiOrientation); } catch (FileException& e) { clearModified(); QString msg("Volume was read but had problems placing it in an LPI orientation.\n"); msg.append(e.whatQString()); throw FileException(fileName, msg); } } } clearModified(); #else // HAVE_MINC throw FileException(fileName, "Unable to read. MINC volume file support not compiled."); #endif } /** * Get a double attribute from a minc file. */ void VolumeFile::get_minc_attribute(int mincid, char *varname, char *attname, int maxvals, double vals[]) { #ifdef HAVE_MINC int varid; int old_ncopts; int att_length; if (!mivar_exists(mincid, varname)) return; varid = ncvarid(mincid, varname); old_ncopts = ncopts; ncopts = 0; (void) miattget(mincid, varid, attname, NC_DOUBLE, maxvals, vals, &att_length); ncopts = old_ncopts; #endif } /** * Import a vtk structured points volume. */ void VolumeFile::importVtkStructuredPointsVolume(const QString& fileName) throw (FileException) { vtkStructuredPointsReader* reader = vtkStructuredPointsReader::New(); reader->SetFileName((char*)fileName.toAscii().constData()); reader->Update(); vtkStructuredPoints* data = reader->GetOutput(); int dim[3]; data->GetDimensions(dim); if ((dim[0] < 1) || (dim[1] < 1) || (dim[2] < 1)) { reader->Delete(); throw FileException(fileName, "Error reading volume"); } float org[3]; float space[3]; #ifdef HAVE_VTK5 { double ds[3]; double dorg[3]; data->GetSpacing(ds); data->GetOrigin(dorg); space[0] = ds[0]; space[1] = ds[1]; space[2] = ds[2]; org[0] = dorg[0] + (space[0] * 0.5); org[1] = dorg[1] + (space[1] * 0.5); org[2] = dorg[2] + (space[2] * 0.5); } #else // HAVE_VTK5 data->GetOrigin(org); data->GetSpacing(space); #endif // HAVE_VTK5 ORIENTATION orient[3] = { ORIENTATION_LEFT_TO_RIGHT, ORIENTATION_POSTERIOR_TO_ANTERIOR, ORIENTATION_INFERIOR_TO_SUPERIOR }; initialize(VOXEL_DATA_TYPE_FLOAT, dim, orient, org, space); filename = fileName; convertFromVtkStructuredPoints(data); reader->Delete(); clearModified(); } /** * Export a vtk structured points volume. */ void VolumeFile::exportVtkStructuredPointsVolume(const QString& fileName) throw (FileException) { if (voxels != NULL) { vtkStructuredPoints* sp = convertToVtkStructuredPoints(); vtkStructuredPointsWriter* writer = vtkStructuredPointsWriter::New(); writer->SetFileName((char*)fileName.toAscii().constData()); writer->SetInput(sp); writer->Write(); writer->Delete(); sp->Delete(); } } /** * Export an analyze volume. */ void VolumeFile::exportAnalyzeVolume(const QString& fileName) throw (FileException) { const QString savedFileName(getFileName()); const unsigned long isModified = getModified(); const FILE_READ_WRITE_TYPE ft = getFileReadType(); setFileWriteType(FILE_READ_WRITE_TYPE_ANALYZE); writeFile(fileName); setFileWriteType(ft); setFileName(savedFileName); setModifiedCounter(isModified); } /** * Export an minc volume. */ void VolumeFile::exportMincVolume(const QString& fileName) throw (FileException) { #ifdef HAVE_MINC // // create an image conversion variable // int icv = miicv_create(); if (icv == MI_ERROR) { throw FileException(fileName, "ERROR: Unable to create mnc file image conversion variable."); return; } // // Min/max voxels // float minVoxel, maxVoxel; getMinMaxVoxelValues(minVoxel, maxVoxel); // // set source data to float // miicv_setint(icv, MI_ICV_TYPE, NC_FLOAT); miicv_setint(icv, MI_ICV_DO_NORM, 1); miicv_setdbl(icv, MI_ICV_VALID_MIN, 0); miicv_setdbl(icv, MI_ICV_VALID_MAX, maxVoxel); //255); int cdf = nccreate(fileName.toAscii().constData(), NC_CLOBBER); // // set output dimensions of file // int dim[3]; dim[0] = ncdimdef(cdf, MIzspace, dimensions[2]); dim[1] = ncdimdef(cdf, MIyspace, dimensions[1]); dim[2] = ncdimdef(cdf, MIxspace, dimensions[0]); //int img = micreate_std_variable(cdf, MIimage, NC_BYTE, 3, dim); const int img = micreate_std_variable(cdf, MIimage, NC_FLOAT, 3, dim); // // set output type to unsigned // miattputstr(cdf, img, MIsigntype, MI_UNSIGNED); // // set output range // float range[2] = { 0.0, maxVoxel }; //255.0 }; ncattput(cdf, img, MIvalid_range, NC_FLOAT, 2, range); miattputstr(cdf, img, MIsigntype, MI_SIGNED); // // create variables for image min/max // int max = micreate_std_variable(cdf, MIimagemax, NC_FLOAT, 0, NULL); int min = micreate_std_variable(cdf, MIimagemin, NC_FLOAT, 0, NULL); float originCorner[3]; getOriginAtCornerOfVoxel(originCorner); // // spacing origin and direction cosines for z-axis // int varid = micreate_std_variable(cdf, MIzspace, NC_INT, 0, NULL); (void) miattputdbl(cdf, varid, MIstep, spacing[2]); (void) miattputdbl(cdf, varid, MIstart, originCorner[2]); const double zdircos[3] = { 0.0, 0.0, 1.0 }; (void) ncattput(cdf, varid, MIdirection_cosines, NC_DOUBLE, 3, zdircos); // // spacing origin and direction cosines for y-axis // varid = micreate_std_variable(cdf, MIyspace, NC_INT, 0, NULL); (void) miattputdbl(cdf, varid, MIstep, spacing[1]); (void) miattputdbl(cdf, varid, MIstart, originCorner[1]); const double ydircos[3] = { 0.0, 1.0, 0.0 }; (void) ncattput(cdf, varid, MIdirection_cosines, NC_DOUBLE, 3, ydircos); // // spacing origin and direction cosines for x-axis // varid = micreate_std_variable(cdf, MIxspace, NC_INT, 0, NULL); (void) miattputdbl(cdf, varid, MIstep, spacing[0]); (void) miattputdbl(cdf, varid, MIstart, originCorner[0]); const double xdircos[3] = { 1.0, 0.0, 0.0 }; (void) ncattput(cdf, varid, MIdirection_cosines, NC_DOUBLE, 3, xdircos); // // end definition mode // ncendef(cdf); // // attach image variable // miicv_attach(icv, cdf, img); // // write the image max and min // double image_maximum = maxVoxel; double image_minimum = minVoxel; ncvarput1(cdf, max, NULL, &image_maximum); ncvarput1(cdf, min, NULL, &image_minimum); // // write the image // long start[3] = { 0, 0, 0 }; long count[3] = { dimensions[2], dimensions[1], dimensions[0] }; miicv_put(icv, start, count, voxels); // // close file and free icv // ncclose(cdf); miicv_free(icv); #else // HAVE_MINC throw FileException(fileName, "Unable to read. MINC volume file support not compiled."); #endif } /** * Initialize the sub volumes. */ void VolumeFile::initializeSubVolumes(const int num) { numberOfSubVolumes = num; scaleSlope.resize(numberOfSubVolumes); scaleOffset.resize(numberOfSubVolumes); subVolumeNames.resize(numberOfSubVolumes); for (int i = 0; i < numberOfSubVolumes; i++) { scaleSlope[i] = 1.0; scaleOffset[i] = 0.0; std::ostringstream str; if (filename.isEmpty() == false) { str << FileUtilities::basename(filename).toAscii().constData(); // << " "; } //str << "Sub Volume "; //str << i; subVolumeNames[i] = str.str().c_str(); } } /// see if a file is a NIFTI volume file bool VolumeFile::isFileNifti(const QString& name) { bool valid = StringUtilities::endsWith(name, SpecFile::getNiftiVolumeFileExtension()) || StringUtilities::endsWith(name, SpecFile::getNiftiGzipVolumeFileExtension()); return valid; } /** * read a raw volume file that has no header. */ void VolumeFile::readFileVolumeRaw(const QString& name, const int subVolumeNumber, const VOXEL_DATA_TYPE vdt, const int dim[3], const ORIENTATION orient[3], const float org[3], const float space[3], const bool byteSwapIn) throw (FileException) { initialize(vdt, dim, orient, org, space, true, false); filename = name; dataFileName = name; gzFile dataFile = gzopen(name.toAscii().constData(), "rb"); if (dataFile == NULL) { throw FileException(name, "Unable to open."); } readVolumeFileDataSubVolume(byteSwapIn, 1.0, 0.0, 0, subVolumeNumber, dataFile); gzclose(dataFile); } /** * Scale Anatomy and Segmentation Volumes to be 0 to 255 * BUT ONLY if the maximum value is 1.0 or less. */ void VolumeFile::scaleAnatomyAndSegmentationVolumesTo255() { switch (volumeType) { case VOLUME_TYPE_FUNCTIONAL: case VOLUME_TYPE_PAINT: case VOLUME_TYPE_PROB_ATLAS: case VOLUME_TYPE_RGB: case VOLUME_TYPE_ROI: break; case VOLUME_TYPE_SEGMENTATION: case VOLUME_TYPE_ANATOMY: { float minValues, maxValues; getMinMaxVoxelValues(minValues, maxValues); if (maxValues <= 1.0) { scaleVoxelValues(255.0, 0.0, 255.0); } } break; case VOLUME_TYPE_VECTOR: break; case VOLUME_TYPE_UNKNOWN: break; } } /** * Permute (reorient) the volume to the specified orientation. */ void VolumeFile::permuteToOrientation(const ORIENTATION newOrientation[3]) throw (FileException) { if (isValidOrientation(orientation) == false) { throw FileException("Input volume has invalid orientation."); } if (isValidOrientation(newOrientation) == false) { throw FileException("New orientation is invalid."); } VOLUME_AXIS axis = VOLUME_AXIS_X; while(axis != VOLUME_AXIS_ALL) { // // Is the orientation correct for this axis // if (orientation[axis] == newOrientation[axis]) { // // Move on to next axis // switch (axis) { case VOLUME_AXIS_X: axis = VOLUME_AXIS_Y; break; case VOLUME_AXIS_Y: axis = VOLUME_AXIS_Z; break; case VOLUME_AXIS_Z: axis = VOLUME_AXIS_ALL; break; case VOLUME_AXIS_ALL: case VOLUME_AXIS_OBLIQUE: case VOLUME_AXIS_OBLIQUE_X: case VOLUME_AXIS_OBLIQUE_Y: case VOLUME_AXIS_OBLIQUE_Z: case VOLUME_AXIS_OBLIQUE_ALL: case VOLUME_AXIS_UNKNOWN: throw FileException("PROGRAM ERROR: Invalid axis for incrementing."); break; } } // // Is the orientation opposite for this axis (ie: "left" and need "right") // else if (orientation[axis] == getInverseOrientation(newOrientation[axis])) { // // flip about the axis // flip(axis); } else { // // Find the axis that contains the desired orientation or its opposite // VOLUME_AXIS foundInAxis = VOLUME_AXIS_ALL; for (int i = (axis + 1); i < 3; i++) { if ((orientation[i] == newOrientation[axis]) || (orientation[i] == getInverseOrientation(newOrientation[axis]))) { foundInAxis = static_cast(i); break; } } if (foundInAxis == VOLUME_AXIS_ALL) { throw FileException("PROGRAM ERROR: Unable to find axis for rotating."); } // // Determine which axis to rotate about // VOLUME_AXIS rotateAxis = VOLUME_AXIS_ALL; if (axis == VOLUME_AXIS_X) { if (foundInAxis == VOLUME_AXIS_Y) { rotateAxis = VOLUME_AXIS_Z; } else if (foundInAxis == VOLUME_AXIS_Z) { rotateAxis = VOLUME_AXIS_Y; } } else if (axis == VOLUME_AXIS_Y) { if (foundInAxis == VOLUME_AXIS_Z) { rotateAxis = VOLUME_AXIS_X; } } switch (rotateAxis) { case VOLUME_AXIS_X: case VOLUME_AXIS_Y: case VOLUME_AXIS_Z: rotate(rotateAxis); break; case VOLUME_AXIS_ALL: case VOLUME_AXIS_OBLIQUE: case VOLUME_AXIS_OBLIQUE_X: case VOLUME_AXIS_OBLIQUE_Y: case VOLUME_AXIS_OBLIQUE_Z: case VOLUME_AXIS_OBLIQUE_ALL: case VOLUME_AXIS_UNKNOWN: throw FileException("PROGRAM ERROR: Invalid axis for rotating."); break; } } } setModified(); minMaxVoxelValuesValid = false; minMaxTwoToNinetyEightPercentVoxelValuesValid = false; } /** * Flood fill starting at a voxel or remove a connected set of voxels. */ void VolumeFile::floodFillAndRemoveConnected(const SEGMENTATION_OPERATION operation, const VOLUME_AXIS axis, const int ijkStart[3], const float newVoxelValue, const unsigned char newRgbValue[4], VolumeModification* modifiedVoxels) { // // Dimensions of volume // int dim[3]; getDimensions(dim); // // Flag for operation being performed // bool fillingFlag = false; bool threeDimensionalFlag = false; switch (operation) { case SEGMENTATION_OPERATION_DILATE: break; case SEGMENTATION_OPERATION_ERODE: break; case SEGMENTATION_OPERATION_FLOOD_FILL_2D: fillingFlag = true; break; case SEGMENTATION_OPERATION_FLOOD_FILL_3D: fillingFlag = true; threeDimensionalFlag = true; break; case SEGMENTATION_OPERATION_REMOVE_CONNECTED_2D: break; case SEGMENTATION_OPERATION_REMOVE_CONNECTED_3D: threeDimensionalFlag = true; break; case SEGMENTATION_OPERATION_TOGGLE_ON: break; case SEGMENTATION_OPERATION_TOGGLE_OFF: break; } // // Initialize to the staring voxel // std::stack st; st.push(VoxelIJK(ijkStart)); // // While there are voxels to process // while (st.empty() == false) { // // Get the next voxel to process // const VoxelIJK v = st.top(); st.pop(); int i, j, k; v.getIJK(i, j, k); // // If the voxel has valid indices // if ((i >= 0) && (i < dim[0]) && (j >= 0) && (j < dim[1]) && (k >= 0) && (k < dim[2])) { const int ijk[3] = { i, j, k }; float currentValue = getVoxel(ijk); // // See if voxel has proper value for operation // bool matchingVoxel = false; if (fillingFlag) { matchingVoxel = (currentValue == 0.0); } else { matchingVoxel = (currentValue != 0.0); } // // If the voxel should be modified // if (matchingVoxel) { // // Update the voxels value // if (modifiedVoxels != NULL) { modifiedVoxels->addVoxel(this, ijk); } setVoxel(ijk, 0, newVoxelValue); setVoxelColor(ijk, newRgbValue); // // Determine neighboring voxels // int iDelta = 0; int jDelta = 0; int kDelta = 0; switch (axis) { case VOLUME_AXIS_X: if (threeDimensionalFlag) { iDelta = 1; } else { iDelta = 0; } jDelta = 1; kDelta = 1; break; case VOLUME_AXIS_Y: iDelta = 1; if (threeDimensionalFlag) { jDelta = 1; } else { jDelta = 0; } kDelta = 1; break; case VOLUME_AXIS_Z: iDelta = 1; jDelta = 1; if (threeDimensionalFlag) { kDelta = 1; } else { kDelta = 0; } break; case VOLUME_AXIS_ALL: case VOLUME_AXIS_OBLIQUE: case VOLUME_AXIS_OBLIQUE_X: case VOLUME_AXIS_OBLIQUE_Y: case VOLUME_AXIS_OBLIQUE_Z: case VOLUME_AXIS_OBLIQUE_ALL: case VOLUME_AXIS_UNKNOWN: 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)); } } } } } /** * perform operation on segmentation volume. */ void VolumeFile::performSegmentationOperation(const SEGMENTATION_OPERATION operation, const VOLUME_AXIS axis, const bool threeDimensionalFlag, const int ijkMinIn[3], const int ijkMaxIn[3], const float voxelValue, const unsigned char rgbValue[4], VolumeModification* modifiedVoxels) { // // Limit to valid indices // int ijkMin[3] = { ijkMinIn[0], ijkMinIn[1], ijkMinIn[2] }; clampVoxelIndex(VOLUME_AXIS_X, ijkMin[0]); clampVoxelIndex(VOLUME_AXIS_Y, ijkMin[1]); clampVoxelIndex(VOLUME_AXIS_Z, ijkMin[2]); int ijkMax[3] = { ijkMaxIn[0], ijkMaxIn[1], ijkMaxIn[2] }; clampVoxelIndex(VOLUME_AXIS_X, ijkMax[0]); clampVoxelIndex(VOLUME_AXIS_Y, ijkMax[1]); clampVoxelIndex(VOLUME_AXIS_Z, ijkMax[2]); bool allocatedModifiedVoxelsInHere = false; const int STRUCTURE_ELEMENT_SIZE = 1; // 1 => 3 x 3 switch (operation) { case SEGMENTATION_OPERATION_DILATE: case SEGMENTATION_OPERATION_ERODE: { // // Need to use modified voxels since we need to check voxels before setting them // if (modifiedVoxels == NULL) { modifiedVoxels = new VolumeModification; allocatedModifiedVoxelsInHere = true; } // // Check each voxel in the desired region // for (int i = ijkMin[0]; i <= ijkMax[0]; i++) { for (int j = ijkMin[1]; j <= ijkMax[1]; j++) { for (int k = ijkMin[2]; k <= ijkMax[2]; k++) { // // Make sure the voxel is in the volume since we // may be near the edge of the volume // const int ijk[3] = { i, j, k }; if (getVoxelIndexValid(ijk)) { // // Get the value of the voxel // float value = getVoxel(ijk); bool voxelMatches = false; // // If eroding, look for "ON" voxels // if (operation == SEGMENTATION_OPERATION_ERODE) { if (value != 0.0) { voxelMatches = true; } } // // If dilating, look for "OFF" boxels // if (operation == SEGMENTATION_OPERATION_DILATE) { if (value == 0.0) { voxelMatches = true; } } // // Should we continue processing this voxel // if (voxelMatches) { // // Create Structuring Element based upon the axis // int iMin = ijk[0]; int iMax = ijk[0]; int jMin = ijk[1]; int jMax = ijk[1]; int kMin = ijk[2]; int kMax = ijk[2]; switch (axis) { case VOLUME_AXIS_X: if (threeDimensionalFlag) { iMin -= STRUCTURE_ELEMENT_SIZE; iMax += STRUCTURE_ELEMENT_SIZE; } jMin -= STRUCTURE_ELEMENT_SIZE; jMax += STRUCTURE_ELEMENT_SIZE; kMin -= STRUCTURE_ELEMENT_SIZE; kMax += STRUCTURE_ELEMENT_SIZE; break; case VOLUME_AXIS_Y: iMin -= STRUCTURE_ELEMENT_SIZE; iMax += STRUCTURE_ELEMENT_SIZE; if (threeDimensionalFlag) { jMin -= STRUCTURE_ELEMENT_SIZE; jMax += STRUCTURE_ELEMENT_SIZE; } kMin -= STRUCTURE_ELEMENT_SIZE; kMax += STRUCTURE_ELEMENT_SIZE; break; case VOLUME_AXIS_Z: iMin -= STRUCTURE_ELEMENT_SIZE; iMax += STRUCTURE_ELEMENT_SIZE; jMin -= STRUCTURE_ELEMENT_SIZE; jMax += STRUCTURE_ELEMENT_SIZE; if (threeDimensionalFlag) { kMin -= STRUCTURE_ELEMENT_SIZE; kMax += STRUCTURE_ELEMENT_SIZE; } break; case VOLUME_AXIS_ALL: case VOLUME_AXIS_OBLIQUE: case VOLUME_AXIS_OBLIQUE_X: case VOLUME_AXIS_OBLIQUE_Y: case VOLUME_AXIS_OBLIQUE_Z: case VOLUME_AXIS_OBLIQUE_ALL: case VOLUME_AXIS_UNKNOWN: break; } // // Check all voxels "under" the structuring element // bool setVoxelFlag = false; for (int ii = iMin; ii <= iMax; ii++) { for (int jj = jMin; jj <= jMax; jj++) { for (int 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 int iijjkk[3] = { ii, jj, kk }; if (getVoxelIndexValid(iijjkk)) { float value = getVoxel(iijjkk); // // If dilating, look for voxels that are "ON" // under the structuring element // if (operation == SEGMENTATION_OPERATION_DILATE) { if (value != 0.0) { setVoxelFlag = true; break; } } // // If eroding look for voxels that are "OFF" // under the structuring element // if (operation == SEGMENTATION_OPERATION_ERODE) { if (value == 0.0) { setVoxelFlag = true; break; } } } } } if (setVoxelFlag) { break; } } if (setVoxelFlag) { break; } } if (setVoxelFlag) { // // 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. // modifiedVoxels->addVoxel(this, ijk); } } } } } } // // Now that all of the voxels have been examined // set the voxels that need to be changed. // const int num = modifiedVoxels->getNumberOfVoxels(); for (int m = 0; m < num; m++) { const VoxelModified* vm = modifiedVoxels->getModifiedVoxel(m); const int* ijk = vm->getIJK(); setVoxel(ijk, 0, voxelValue); setVoxelColor(ijk, rgbValue); } } break; case SEGMENTATION_OPERATION_FLOOD_FILL_2D: case SEGMENTATION_OPERATION_FLOOD_FILL_3D: case SEGMENTATION_OPERATION_REMOVE_CONNECTED_2D: case SEGMENTATION_OPERATION_REMOVE_CONNECTED_3D: floodFillAndRemoveConnected(operation, axis, ijkMin, voxelValue, rgbValue, modifiedVoxels); break; case SEGMENTATION_OPERATION_TOGGLE_ON: case SEGMENTATION_OPERATION_TOGGLE_OFF: for (int i = ijkMin[0]; i <= ijkMax[0]; i++) { for (int j = ijkMin[1]; j <= ijkMax[1]; j++) { for (int k = ijkMin[2]; k <= ijkMax[2]; k++) { const int ijk[3] = { i, j, k }; if (getVoxelIndexValid(ijk)) { if (modifiedVoxels != NULL) { modifiedVoxels->addVoxel(this, ijk); } setVoxel(ijk, 0, voxelValue); setVoxelColor(ijk, rgbValue); } } } } break; } if (allocatedModifiedVoxelsInHere) { delete modifiedVoxels; } } /** * Undo a volume modification */ void VolumeFile::undoModification(const VolumeModification* modifiedVoxels) { const int num = modifiedVoxels->getNumberOfVoxels(); for (int i = 0; i < num; i++) { const VoxelModified* vm = modifiedVoxels->getModifiedVoxel(i); const int* ijk = vm->getIJK(); if (getVoxelIndexValid(ijk)) { setVoxel(ijk, 0, vm->getVoxelValue()); setVoxelColor(ijk, vm->getVoxelColor()); } } } /** * change a range of values to zero. */ void VolumeFile::setRangeOfValuesToZero(const VolumeFile* inputVolume, VolumeFile* outputVolume, const float minValue, const float maxValue, const bool inclusiveRangeFlag) throw (FileException) { int dimA[3], dimOut[3]; inputVolume->getDimensions(dimA); outputVolume->getDimensions(dimOut); for (int d = 0; d < 3; d++) { if (dimA[d] != dimOut[d]) { throw FileException("Input and Output Volumes have different dimensions."); } } const int num = inputVolume->getTotalNumberOfVoxels(); for (int i = 0; i < num; i++) { float value = inputVolume->voxels[i]; if (inclusiveRangeFlag) { if ((value >= minValue) && (value <= maxValue)) { value = 0.0; } } else { if ((value > minValue) && (value < maxValue)) { value = 0.0; } } outputVolume->voxels[i] = value; } } /** * create a segmentation volume mask. Output volume must exist. */ void VolumeFile::createSegmentationMask(const QString& outputFileName, const std::vector& inputFileNames, const int numberOfDilationIterations) throw (FileException) { // // Verify inputs // if (outputFileName.isEmpty()) { throw FileException("Output file name is empty."); } const int numInputVolumes = static_cast(inputFileNames.size()); if (numInputVolumes <= 0) { throw FileException("There are no input volume file names."); } if (numberOfDilationIterations < 0) { throw FileException("Number of dilation iterations is less than zero."); } // // Comment for mask volume // QString comment("Mask volume with " + QString::number(numberOfDilationIterations) + " dilation iterations created from: \n"); // // The mask volume // VolumeFile maskVolume; try { maskVolume.readFile(outputFileName); } catch (FileException& e) { const QString msg("ERROR: unable to open output volume file which should already exist,\n " + e.whatQString()); throw FileException(msg); } maskVolume.setAllVoxels(0.0); // // Read the volumes // for (int inputIndex = 0; inputIndex < numInputVolumes; inputIndex++) { QString errorMessage; std::vector volumesRead; try { // // Read all sub volumes in the volume file // readFile(inputFileNames[inputIndex], VolumeFile::VOLUME_READ_SELECTION_ALL, volumesRead, false); // // Add file name to mask file comment // comment += (FileUtilities::basename(inputFileNames[inputIndex]) + "\n"); // // Process all subvolumes that were read // const int numVolumesRead = static_cast(volumesRead.size()); for (int subVolIndex = 0; subVolIndex < numVolumesRead; subVolIndex++) { // // Test each voxel in the mask volume to see if it is inside an input volume voxel // const VolumeFile* inputVolume = volumesRead[subVolIndex]; int maskDim[3]; maskVolume.getDimensions(maskDim); for (int i = 0; i < maskDim[0]; i++) { for (int j = 0; j < maskDim[1]; j++) { for (int k = 0; k < maskDim[2]; k++) { // // Get coordinate of mask volume voxel // float xyz[3]; maskVolume.getVoxelCoordinate(i, j, k, xyz); // // Is coordinate in an input volume voxel // int ijk[3]; if (inputVolume->convertCoordinatesToVoxelIJK(xyz, ijk)) { // // If voxel in input volume is on, turn on corresponding mask voxel // const float voxelValue = inputVolume->getVoxel(ijk, 0); if (voxelValue != 0) { maskVolume.setVoxel(i, j, k, 0, voxelValue); } } } } } } } catch (FileException& e) { // // Save the exception message so that volumes read can be deleted before throwing // errorMessage = e.whatQString(); } // // Delete volumes that were read // for (unsigned int i = 0; i < volumesRead.size(); i++) { if (volumesRead[i] != NULL) { delete volumesRead[i]; volumesRead[i] = NULL; } volumesRead.clear(); } // // If there was an error, abort // if (errorMessage.isEmpty() == false) { throw FileException(errorMessage); } } // // Make all non-zero voxels 255 // maskVolume.makeSegmentationZeroTwoFiftyFive(); // // Dilate the mask volume // if (numberOfDilationIterations > 0) { maskVolume.doVolMorphOps(numberOfDilationIterations, 0); } // // Write the mask volume // maskVolume.setFileComment(comment); maskVolume.setDescriptiveLabel("Mask"); maskVolume.writeFile(outputFileName); } /** * perform unary operations on a volume. */ void VolumeFile::performUnaryOperation(const UNARY_OPERATION operation, const VolumeFile* inputVolume, VolumeFile* outputVolume, const float scalar) throw (FileException) { int dimA[3], dimOut[3]; inputVolume->getDimensions(dimA); outputVolume->getDimensions(dimOut); for (int d = 0; d < 3; d++) { if (dimA[d] != dimOut[d]) { throw FileException("Input and Output Volumes have different dimensions."); } } for (int i = 0; i < dimA[0]; i++) { for (int j = 0; j < dimA[1]; j++) { for (int k = 0; k < dimA[2]; k++) { float value = 0.0; if (inputVolume->getVoxelAllComponents(i, j, k, &value)) { switch (operation) { case UNARY_OPERATION_ADD: value += scalar; break; case UNARY_OPERATION_ABS_VALUE: if (value < 0.0) { value = -value; } break; case UNARY_OPERATION_CEILING: value = std::min(value, scalar); break; case UNARY_OPERATION_FLOOR: value = std::max(value, scalar); break; case UNARY_OPERATION_MULTIPLY: value *= scalar; break; case UNARY_OPERATION_FIX_NOT_A_NUMBER: if (MathUtilities::isNaN(value)) { value = 0.0; } break; case UNARY_OPERATION_SQUARE_ROOT: if (value > 0.0) { value = std::sqrt(value); } break; case UNARY_OPERATION_SUBTRACT_FROM_ONE: value = 1.0 - value; break; case UNARY_OPERATION_LOG2: // use scalar as base value = MathUtilities::log(scalar, value); break; } outputVolume->setVoxel(i, j, k, 0, value); } } } } } /** * perform binary operations on a volume. */ void VolumeFile::performMathematicalOperation(const VOLUME_MATH_OPERATION operation, const VolumeFile* inputVolumeA, const VolumeFile* inputVolumeB, const VolumeFile* inputVolumeC, VolumeFile* outputVolume) throw (FileException) { int dimA[3], dimB[3], dimOut[3]; inputVolumeA->getDimensions(dimA); inputVolumeB->getDimensions(dimB); outputVolume->getDimensions(dimOut); for (int d = 0; d < 3; d++) { if ((dimA[d] != dimB[d]) || (dimA[d] != dimOut[d]) || (dimB[d] != dimOut[d])) { throw FileException("Input and Output Volumes have different dimensions."); } } // // For paint volume, handle paint names // const int paintVolumeBQuestionIndex = inputVolumeB->getRegionIndexFromName("???"); std::vector paintNamesVolumeA; std::vector paintNamesVolumeB; if (operation == VOLUME_MATH_OPERATION_COMBINE_PAINT) { const int numA = inputVolumeA->getNumberOfRegionNames(); if (numA <= 0) { throw FileException("There are no paint regions in the first volume."); } paintNamesVolumeA.resize(numA, -1); const int numB = inputVolumeB->getNumberOfRegionNames(); if (numB <= 0) { throw FileException("There are no paint regions in the second volume."); } paintNamesVolumeB.resize(numB, -1); //outputVolume->regionNames.clear(); } // // Special volume for paint name of output volume since the output volume may be // the same as one of the input volumes. // VolumeFile paintNameVolume; for (int i = 0; i < dimA[0]; i++) { for (int j = 0; j < dimA[1]; j++) { for (int k = 0; k < dimA[2]; k++) { float valueA = 0.0, valueB = 0.0, valueC = 0.0; if (inputVolumeA->getVoxelAllComponents(i, j, k, &valueA)) { if (inputVolumeB->getVoxelAllComponents(i, j, k, &valueB)) { if (inputVolumeC != NULL) { inputVolumeC->getVoxelAllComponents(i, j, k, &valueC); } float result = 0.0; switch (operation) { case VOLUME_MATH_OPERATION_ADD: result = valueA + valueB; break; case VOLUME_MATH_OPERATION_AND: if ((valueA > 0.0) && (valueB > 0.0)) { result = 255.0; } break; case VOLUME_MATH_OPERATION_NAND: if (! ((valueA > 0.0) && (valueB > 0.0))) { result = 255.0; } break; case VOLUME_MATH_OPERATION_SUBTRACT: result = valueA - valueB; break; case VOLUME_MATH_OPERATION_MULTIPLY: result = valueA * valueB; break; case VOLUME_MATH_OPERATION_DIVIDE: if (valueB != 0.0) { result = valueA / valueB; } else { result = valueA; } break; case VOLUME_MATH_OPERATION_OR: if ((valueA > 0.0) || (valueB > 0.0)) { result = 255.0; } break; case VOLUME_MATH_OPERATION_NOR: if ((valueA == 0.0) && (valueB == 0.0)) { result = 255.0; } break; case VOLUME_MATH_OPERATION_SUBTRACT_POSITIVE: result = valueA - valueB; result = std::max(result, 0.0f); break; case VOLUME_MATH_OPERATION_MAX: result = std::max(valueA, valueB); break; case VOLUME_MATH_OPERATION_DIFFRATIO: { const float denom = valueA + valueB; if (valueC == 255.0) { result = 1.0; } else if (denom == 0.0) { result = -1.0; } else { result = (valueA - valueB) / denom; } } break; case VOLUME_MATH_OPERATION_SQRT: result = valueA * valueB; if (result > 0.0) { result = sqrt(result); } break; case VOLUME_MATH_OPERATION_COMBINE_PAINT: { const int valueBInt = static_cast(valueB); if (valueBInt != paintVolumeBQuestionIndex) { if (paintNamesVolumeB[valueBInt] < 0) { paintNamesVolumeB[valueBInt] = paintNameVolume.addRegionName(inputVolumeB->getRegionNameFromIndex(valueBInt)); } result = paintNamesVolumeB[valueBInt]; } else { const int valueAInt = static_cast(valueA); if (paintNamesVolumeA[valueAInt] < 0) { paintNamesVolumeA[valueAInt] = paintNameVolume.addRegionName(inputVolumeA->getRegionNameFromIndex(valueAInt)); } result = paintNamesVolumeA[valueAInt]; } } break; case VOLUME_MATH_OPERATION_AVERAGE: result = (valueA + valueB) * 0.5; break; case VOLUME_MATH_EXCLUSIVE_OR: if ((valueA != 0.0) && (valueB == 0.0)) { result = valueA; } else if ((valueA == 0.0) && (valueB != 0.0)) { result = valueB; } else { result = 0.0; } break; } outputVolume->setVoxel(i, j, k, 0, result); } } } } } // // Set the paint names for the output volume // if (operation == VOLUME_MATH_OPERATION_COMBINE_PAINT) { outputVolume->regionNames = paintNameVolume.regionNames; } } /** * Read data of the specified type. */ void VolumeFile::readRgbDataVoxelInterleaved(gzFile dataFile) throw (FileException) { const int numVoxels = getTotalNumberOfVoxels(); const int length = numVoxels * sizeof(unsigned char) * 3; unsigned char* data = new unsigned char[length]; const int numRead = gzread(dataFile, (char*)data, (unsigned)length); if (numRead != length) { std::ostringstream str; str << "Premature EOF reading zipped file. Tried to read\n" << length << "bytes. Actually read " << numRead << ".\n"; throw FileException(getDataFileNameForReadError(), str.str().c_str()); } for (int i = 0; i < numVoxels; i++) { const int indx = i * 3; voxels[indx] = data[indx]; voxels[indx+1] = data[indx+1]; voxels[indx+2] = data[indx+2]; } delete[] data; } /** * Read data of the specified type. */ void VolumeFile::readRgbDataSliceInterleaved(gzFile dataFile) throw (FileException) { const int numVoxels = getTotalNumberOfVoxels(); const int length = numVoxels * sizeof(unsigned char) * 3; unsigned char* data = new unsigned char[length]; const int numRead = gzread(dataFile, (char*)data, (unsigned)length); if (numRead != length) { std::ostringstream str; str << "Premature EOF reading zipped file. Tried to read\n" << length << "bytes. Actually read " << numRead << ".\n"; throw FileException(getDataFileNameForReadError(), str.str().c_str()); } int dim[3]; getDimensions(dim); const int sliceOffset = dim[0] * dim[1]; const int componentOffset = sliceOffset * 3; for (int k = 0; k < dim[2]; k++) { for (int j = 0; j < dim[1]; j++) { for (int i = 0; i < dim[0]; i++) { int ijk[3] = { i, j, k }; const int pointID = getVoxelDataIndex(ijk); const int dataID = componentOffset * k + (j * dim[0]) + i; voxels[pointID] = data[dataID]; voxels[pointID+1] = data[dataID + sliceOffset]; voxels[pointID+2] = data[dataID + (sliceOffset * 2)]; } } } delete[] data; } /** * Read data of the specified type. */ void VolumeFile::readCharData(gzFile dataFile) throw (FileException) { const int numVoxels = getTotalNumberOfVoxels(); const int length = numVoxels * sizeof(char); char* data = new char[length]; const int numRead = gzread(dataFile, (char*)data, (unsigned)length); if (numRead != length) { std::ostringstream str; str << "Premature EOF reading zipped file. Tried to read\n" << length << "bytes. Actually read " << numRead << ".\n"; throw FileException(getDataFileNameForReadError(), str.str().c_str()); } for (int i = 0; i < numVoxels; i++) { voxels[i] = data[i]; } delete[] data; } /** * Read data of the specified type. */ void VolumeFile::readUnsignedCharData(gzFile dataFile) throw (FileException) { const int numVoxels = getTotalNumberOfVoxels(); const int length = numVoxels * sizeof(unsigned char); unsigned char* data = new unsigned char[length]; const int numRead = gzread(dataFile, (char*)data, (unsigned)length); if (numRead != length) { std::ostringstream str; str << "Premature EOF reading zipped file. Tried to read\n" << length << "bytes. Actually read " << numRead << ".\n"; throw FileException(getDataFileNameForReadError(), str.str().c_str()); } for (int i = 0; i < numVoxels; i++) { voxels[i] = data[i]; } delete[] data; } /** * Read data of the specified type. */ void VolumeFile::readShortData(gzFile dataFile, const bool byteSwapData) throw (FileException) { const int numVoxels = getTotalNumberOfVoxels(); const int length = numVoxels * sizeof(short); short* data = new short[length]; const int numRead = gzread(dataFile, (char*)data, (unsigned)length); if (numRead != length) { std::ostringstream str; str << "Premature EOF reading zipped file. Tried to read\n" << length << "bytes. Actually read " << numRead << ".\n"; throw FileException(getDataFileNameForReadError(), str.str().c_str()); } if (byteSwapData) { ByteSwapping::swapBytes(data, numVoxels); } for (int i = 0; i < numVoxels; i++) { voxels[i] = data[i]; } delete[] data; } /** * Read data of the specified type. */ void VolumeFile::readUnsignedShortData(gzFile dataFile, const bool byteSwapData) throw (FileException) { const int numVoxels = getTotalNumberOfVoxels(); const int length = numVoxels * sizeof(unsigned short); unsigned short* data = new unsigned short[length]; const int numRead = gzread(dataFile, (char*)data, (unsigned)length); if (numRead != length) { std::ostringstream str; str << "Premature EOF reading zipped file. Tried to read\n" << length << "bytes. Actually read " << numRead << ".\n"; throw FileException(getDataFileNameForReadError(), str.str().c_str()); } if (byteSwapData) { ByteSwapping::swapBytes(data, numVoxels); } for (int i = 0; i < numVoxels; i++) { voxels[i] = data[i]; } delete[] data; } /** * Read data of the specified type. */ void VolumeFile::readIntData(gzFile dataFile, const bool byteSwapData) throw (FileException) { const int numVoxels = getTotalNumberOfVoxels(); const int length = numVoxels * sizeof(int); int* data = new int[length]; const int numRead = gzread(dataFile, (char*)data, (unsigned)length); if (numRead != length) { std::ostringstream str; str << "Premature EOF reading zipped file. Tried to read\n" << length << "bytes. Actually read " << numRead << ".\n"; throw FileException(getDataFileNameForReadError(), str.str().c_str()); } if (byteSwapData) { ByteSwapping::swapBytes(data, numVoxels); } for (int i = 0; i < numVoxels; i++) { voxels[i] = data[i]; } delete[] data; } /** * Read data of the specified type. */ void VolumeFile::readUnsignedIntData(gzFile dataFile, const bool byteSwapData) throw (FileException) { const int numVoxels = getTotalNumberOfVoxels(); const int length = numVoxels * sizeof(unsigned int); unsigned int* data = new unsigned int[length]; const int numRead = gzread(dataFile, (char*)data, (unsigned)length); if (numRead != length) { std::ostringstream str; str << "Premature EOF reading zipped file. Tried to read\n" << length << "bytes. Actually read " << numRead << ".\n"; throw FileException(getDataFileNameForReadError(), str.str().c_str()); } if (byteSwapData) { ByteSwapping::swapBytes(data, numVoxels); } for (int i = 0; i < numVoxels; i++) { voxels[i] = data[i]; } delete[] data; } /** * Read data of the specified type. */ void VolumeFile::readLongLongData(gzFile dataFile, const bool byteSwapData) throw (FileException) { const int numVoxels = getTotalNumberOfVoxels(); const int length = numVoxels * sizeof(long long); long long* data = new long long[length]; const int numRead = gzread(dataFile, (char*)data, (unsigned)length); if (numRead != length) { std::ostringstream str; str << "Premature EOF reading zipped file. Tried to read\n" << length << "bytes. Actually read " << numRead << ".\n"; throw FileException(getDataFileNameForReadError(), str.str().c_str()); } if (byteSwapData) { ByteSwapping::swapBytes(data, numVoxels); } for (int i = 0; i < numVoxels; i++) { voxels[i] = data[i]; } delete[] data; } /** * Read data of the specified type. */ void VolumeFile::readUnsignedLongLongData(gzFile dataFile, const bool byteSwapData) throw (FileException) { const int numVoxels = getTotalNumberOfVoxels(); const int length = numVoxels * sizeof(unsigned long long); unsigned long long* data = new unsigned long long[length]; const int numRead = gzread(dataFile, (char*)data, (unsigned)length); if (numRead != length) { std::ostringstream str; str << "Premature EOF reading zipped file. Tried to read\n" << length << "bytes. Actually read " << numRead << ".\n"; throw FileException(getDataFileNameForReadError(), str.str().c_str()); } if (byteSwapData) { ByteSwapping::swapBytes(data, numVoxels); } for (int i = 0; i < numVoxels; i++) { voxels[i] = data[i]; } delete[] data; } /** * Read data of the specified type. */ void VolumeFile::readFloatData(gzFile dataFile, const bool byteSwapData) throw (FileException) { const int numVoxels = getTotalNumberOfVoxels(); const int length = numVoxels * sizeof(float); float* data = new float[length]; const int numRead = gzread(dataFile, (char*)data, (unsigned)length); if (numRead != length) { std::ostringstream str; str << "Premature EOF reading zipped file. Tried to read\n" << length << "bytes. Actually read " << numRead << ".\n"; throw FileException(getDataFileNameForReadError(), str.str().c_str()); } if (byteSwapData) { ByteSwapping::swapBytes(data, numVoxels); } for (int i = 0; i < numVoxels; i++) { voxels[i] = data[i]; } delete[] data; } /** * Read data of the specified type. */ void VolumeFile::readDoubleData(gzFile dataFile, const bool byteSwapData) throw (FileException) { const int numVoxels = getTotalNumberOfVoxels(); const int length = numVoxels * sizeof(double); double* data = new double[length]; const int numRead = gzread(dataFile, (char*)data, (unsigned)length); if (numRead != length) { std::ostringstream str; str << "Premature EOF reading zipped file. Tried to read\n" << length << "bytes. Actually read " << numRead << ".\n"; throw FileException(getDataFileNameForReadError(), str.str().c_str()); } if (byteSwapData) { ByteSwapping::swapBytes(data, numVoxels); } for (int i = 0; i < numVoxels; i++) { voxels[i] = data[i]; } delete[] data; } /** * Read both header and volume. */ void VolumeFile::readFile(const QString& fileNameIn) throw (FileException) { readFile(fileNameIn, 0, false); } /** * Write the volume to a file (header and data). */ void VolumeFile::writeFile(const QString& filenameIn) throw (FileException) { std::vector volumes; volumes.push_back(this); writeFile(filenameIn, getVolumeType(), getVoxelDataType(), volumes, false); } /** * Read the spec file data (should never be called). */ void VolumeFile::readFileData(QFile& /*file*/, QTextStream& /*stream*/, QDataStream&, QDomElement& /* rootElement */) throw (FileException) { throw FileException(filename, "VolumeFile::readFileData was called and should never be called." "This is a programming error."); } /** write a volume in the specified type and add the correct file extension * (assumes no file extension). */ void VolumeFile::writeVolumeFile(VolumeFile* vf, const FILE_READ_WRITE_TYPE fileType, const QString filenameWithoutExtensionIn, const bool compressVolumeFileFlagIn, QString& fileNameOut, QString& dataFileNameOut) throw (FileException) { bool compressVolumeFileFlag = compressVolumeFileFlagIn; if (vf == NULL) { throw FileException("VolumeFile::writeVolumeFile was passed a NULL volume pointer."); } if (filenameWithoutExtensionIn.isEmpty()) { throw FileException("Filename is empty"); } QString filenameWithoutExtension = filenameWithoutExtensionIn; if (filenameWithoutExtension.endsWith("+orig") == false) { filenameWithoutExtension += "+orig"; } fileNameOut = ""; dataFileNameOut = ""; QString ext; bool zipAfniFlag = false; switch(fileType) { case FILE_READ_WRITE_TYPE_RAW: throw FileException("RAW volume type not supported for writing."); break; case FILE_READ_WRITE_TYPE_AFNI: fileNameOut = filenameWithoutExtension + SpecFile::getAfniVolumeFileExtension(); dataFileNameOut = filenameWithoutExtension + ".BRIK"; if (compressVolumeFileFlag) { dataFileNameOut += ".gz"; zipAfniFlag = true; } break; case FILE_READ_WRITE_TYPE_ANALYZE: fileNameOut = filenameWithoutExtension + SpecFile::getAnalyzeVolumeFileExtension(); dataFileNameOut = filenameWithoutExtension + ".img"; break; case FILE_READ_WRITE_TYPE_NIFTI: fileNameOut = filenameWithoutExtension + SpecFile::getNiftiVolumeFileExtension(); if (compressVolumeFileFlag) { fileNameOut += ".gz"; } break; case FILE_READ_WRITE_TYPE_NIFTI_GZIP: fileNameOut = filenameWithoutExtension + SpecFile::getNiftiGzipVolumeFileExtension(); compressVolumeFileFlag = true; break; case FILE_READ_WRITE_TYPE_SPM_OR_MEDX: fileNameOut = filenameWithoutExtension + SpecFile::getAnalyzeVolumeFileExtension(); dataFileNameOut = filenameWithoutExtension + ".img"; break; case FILE_READ_WRITE_TYPE_WUNIL: fileNameOut = filenameWithoutExtension + SpecFile::getWustlVolumeFileExtension(); dataFileNameOut = filenameWithoutExtension + ".img"; break; case FILE_READ_WRITE_TYPE_UNKNOWN: throw FileException("Undefined file type not supported for writing volume."); break; } std::vector theFiles; theFiles.push_back(vf); vf->writeFile(fileNameOut, vf->getVolumeType(), vf->getVoxelDataType(), theFiles, zipAfniFlag); } /** * Write the spec file data (should never be called). */ void VolumeFile::writeFileData(QTextStream& /*stream*/, QDataStream&, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException) { throw FileException(filename, "VolumeFile::writeFileData was called and should never be called." "This is a programming error."); } /** * Dual hreshold volume (voxels between thresholds become 255, all other voxels 0). */ void VolumeFile::dualThresholdVolume(const float thresholdLow, const float thresholdHigh) { int cnt = 0; const int num = getTotalNumberOfVoxelElements(); for (int i = 0; i < num; i++){ if ((voxels[i] > thresholdLow) && (voxels[i] < thresholdHigh)) { voxels[i] = 255; cnt++; } else { voxels[i] = 0; } } if (DebugControl::getDebugOn()) { std::cout << "\tDual Threshold " << thresholdLow << ", " << thresholdHigh << std::endl; std::cout << "\tThresholded " << cnt << " voxels " << (cnt/(float)(num)*100.0) << "%" << std::endl; } setModified(); minMaxVoxelValuesValid = false; minMaxTwoToNinetyEightPercentVoxelValuesValid = false; } /** * threshold volume (voxels above become 255, voxels below 0). */ void VolumeFile::thresholdVolume(const float thresholdValue) { int cnt = 0; const int num = getTotalNumberOfVoxelElements(); for (int i = 0; i < num; i++){ if (voxels[i] > thresholdValue) { voxels[i] = 255; cnt++; } else { voxels[i] = 0; } } if (DebugControl::getDebugOn()) { std::cout << "\tThreshold " << thresholdValue << std::endl; std::cout << "\tThresholded " << cnt << " voxels " << (cnt/(float)(num)*100.0) << "%" << std::endl; } setModified(); minMaxVoxelValuesValid = false; minMaxTwoToNinetyEightPercentVoxelValuesValid = false; } /** * threshold volume (voxels below become 255, voxels above 0). */ void VolumeFile::inverseThresholdVolume(const float thresholdValue) { int cnt = 0; const int num = getTotalNumberOfVoxelElements(); for (int i = 0; i < num; i++){ if (voxels[i] < thresholdValue){ voxels[i] = 255; cnt++; } else { voxels[i] = 0; } } if (DebugControl::getDebugOn()) { std::cout << "\tInverse Threshold " << thresholdValue << std::endl; std::cout << "\tInverse Thresholded " << cnt << " voxels " << (cnt/(float)(num)*100.0) << std::endl; } setModified(); minMaxVoxelValuesValid = false; minMaxTwoToNinetyEightPercentVoxelValuesValid = false; } /** * clamp a voxel dimensions to within valid values (0 to dim). */ void VolumeFile::clampVoxelDimension(int voxelIJK[3]) const { clampVoxelDimension(VOLUME_AXIS_X, voxelIJK[0]); clampVoxelDimension(VOLUME_AXIS_Y, voxelIJK[1]); clampVoxelDimension(VOLUME_AXIS_Z, voxelIJK[2]); } /** * clamp a voxel dimension to within valid values (0 to dim). */ void VolumeFile::clampVoxelDimension(const VOLUME_AXIS axis, int& voxelIndex) const { int maxIndex = 0; switch (axis) { case VOLUME_AXIS_X: maxIndex = dimensions[0]; break; case VOLUME_AXIS_Y: maxIndex = dimensions[1]; break; case VOLUME_AXIS_Z: maxIndex = dimensions[2]; break; case VOLUME_AXIS_ALL: case VOLUME_AXIS_OBLIQUE: case VOLUME_AXIS_OBLIQUE_X: case VOLUME_AXIS_OBLIQUE_Y: case VOLUME_AXIS_OBLIQUE_Z: case VOLUME_AXIS_OBLIQUE_ALL: case VOLUME_AXIS_UNKNOWN: break; } voxelIndex = std::max(voxelIndex, 0); voxelIndex = std::min(voxelIndex, maxIndex); } /** * clamp a voxel index to within valid values (0 to dim-1). */ void VolumeFile::clampVoxelIndex(int voxelIJK[3]) const { clampVoxelIndex(VOLUME_AXIS_X, voxelIJK[0]); clampVoxelIndex(VOLUME_AXIS_Y, voxelIJK[1]); clampVoxelIndex(VOLUME_AXIS_Z, voxelIJK[2]); } /** * clamp a voxel index to within valid values (0 to dim-1). */ void VolumeFile::clampVoxelIndex(const VOLUME_AXIS axis, int& voxelIndex) const { int maxIndex = 0; switch (axis) { case VOLUME_AXIS_X: maxIndex = dimensions[0]; break; case VOLUME_AXIS_Y: maxIndex = dimensions[1]; break; case VOLUME_AXIS_Z: maxIndex = dimensions[2]; break; case VOLUME_AXIS_ALL: case VOLUME_AXIS_OBLIQUE: case VOLUME_AXIS_OBLIQUE_X: case VOLUME_AXIS_OBLIQUE_Y: case VOLUME_AXIS_OBLIQUE_Z: case VOLUME_AXIS_OBLIQUE_ALL: case VOLUME_AXIS_UNKNOWN: break; } voxelIndex = std::max(voxelIndex, 0); voxelIndex = std::min(voxelIndex, maxIndex - 1); } /** * get 6 connected neighbors for a voxel. */ void VolumeFile::getNeighbors(const VoxelIJK& voxel, std::vector& neighbors) const { int ijk[3]; voxel.getIJK(ijk); int n[3]; n[0] = ijk[0] - 1; n[1] = ijk[1]; n[2] = ijk[2]; if (getVoxelIndexValid(n)) { neighbors.push_back(VoxelIJK(n)); } n[0] = ijk[0] + 1; n[1] = ijk[1]; n[2] = ijk[2]; if (getVoxelIndexValid(n)) { neighbors.push_back(VoxelIJK(n)); } n[0] = ijk[0]; n[1] = ijk[1] - 1; n[2] = ijk[2]; if (getVoxelIndexValid(n)) { neighbors.push_back(VoxelIJK(n)); } n[0] = ijk[0]; n[1] = ijk[1] + 1; n[2] = ijk[2]; if (getVoxelIndexValid(n)) { neighbors.push_back(VoxelIJK(n)); } n[0] = ijk[0]; n[1] = ijk[1]; n[2] = ijk[2] - 1; if (getVoxelIndexValid(n)) { neighbors.push_back(VoxelIJK(n)); } n[0] = ijk[0]; n[1] = ijk[1]; n[2] = ijk[2] + 1; if (getVoxelIndexValid(n)) { neighbors.push_back(VoxelIJK(n)); } } /** * Fill the largest connect set of voxels within the specified bounds. */ bool VolumeFile::fillBiggestObjectWithinMask(const int imin, const int imax, const int jmin, const int jmax, const int kmin, const int kmax, const float minValue, const float maxValue) { const int extent[6] = { imin, imax, jmin, jmax, kmin, kmax }; return fillBiggestObjectWithinMask(extent, minValue, maxValue); } /** * Fill the largest connect set of voxels within the specified bounds. */ bool VolumeFile::fillBiggestObjectWithinMask(const int extent[6], const float minValue, const float maxValue) { VoxelIJK bigSeed(-1, -1, -1); const int numObjects = findBiggestObjectWithinMask(extent, minValue, maxValue, bigSeed); if ((numObjects > 0) && (bigSeed.getI() >= 0)) { floodFillWithVTK(bigSeed, 255, 255, 0); return true; } return false; } /** * Find the largest connect set of voxels in the volume. * Returns the number of objects found. */ int VolumeFile::findBiggestObject(const float minValue, const float maxValue, VoxelIJK& bigSeed) const { const int extent[6] = { 0, dimensions[0], 0, dimensions[1], 0, dimensions[2] }; return findBiggestObjectWithinMask(extent, minValue, maxValue, bigSeed); } /** * Find the largest connect set of voxels within the specified bounds. */ int VolumeFile::findBiggestObjectWithinMask(const int extent[6], const float minValue, const float maxValue, int bigSeed[3]) const { VoxelIJK ijkSeed(bigSeed); const int val = findBiggestObjectWithinMask(extent, minValue, maxValue, ijkSeed); bigSeed[0] = ijkSeed.getI(); bigSeed[1] = ijkSeed.getJ(); bigSeed[2] = ijkSeed.getK(); return val; } /** * Find the largest connect set of voxels within the specified bounds. * Returns the number of objects found. */ int VolumeFile::findBiggestObjectWithinMask(const int extent[6], const float minValue, const float maxValue, VoxelIJK& bigSeed) const { return findBiggestObjectWithinMask(extent[0], extent[1], extent[2], extent[3], extent[4], extent[5], minValue, maxValue, bigSeed); } /** * Find the largest connect set of voxels within the specified bounds. * Returns the number of objects found. */ int VolumeFile::findBiggestObjectWithinMask(const int iminIn, const int imaxIn, const int jminIn, const int jmaxIn, const int kminIn, const int kmaxIn, const float minValue, const float maxValue, VoxelIJK& bigSeed) const { bigSeed.setIJK(-1, -1, -1); int imin = iminIn; int imax = imaxIn; int jmin = jminIn; int jmax = jmaxIn; int kmin = kminIn; int kmax = kmaxIn; // // largest object count // int largestObjectCount = 0; // // Number of objects found // int numberOfObjectsFound = 0; // // Make sure search region is within the volume // clampVoxelDimension(VOLUME_AXIS_X, imin); clampVoxelDimension(VOLUME_AXIS_X, imax); clampVoxelDimension(VOLUME_AXIS_Y, jmin); clampVoxelDimension(VOLUME_AXIS_Y, jmax); clampVoxelDimension(VOLUME_AXIS_Z, kmin); clampVoxelDimension(VOLUME_AXIS_Z, kmax); if (DebugControl::getDebugOn()) { std::cout << "FindBiggestObjectWithinMask " << imin << " " << imax << " " << jmin << " " << jmax << " " << kmin << " " << kmax << " " << std::endl; } const int numVoxels = getTotalNumberOfVoxels(); // // single slice ? // if ((imin == imax) || (jmin == jmax) || (kmin == kmax)) { if (DebugControl::getDebugOn()) { std::cout << "For x, y or z, min = max" << std::endl; } } else { // // Create a flag for noting which voxels have been searched. // Mark those within region and within min and max values NOT SEARCHED // and all others SEARCHED. // VOXEL_SEARCH_STATUS* voxelSearched = new VOXEL_SEARCH_STATUS[numVoxels]; for (int k = 0; k < dimensions[2]; k++) { for (int j = 0; j < dimensions[1]; j++) { for (int i = 0; i < dimensions[0]; i++) { const int idx = getVoxelDataIndex(i, j, k); voxelSearched[idx] = VOXEL_SEARCHED; if ((i >= imin) && (i < imax) && (j >= jmin) && (j < jmax) && (k >= kmin) && (k < kmax)) { if ((voxels[idx] >= minValue) && (voxels[idx] <= maxValue)) { voxelSearched[idx] = VOXEL_NOT_SEARCHED; } } } } } // // Find a voxel within value range that has not been searched // VoxelIJK seedVoxel; bool voxelFound = findUnsearchedVoxel(minValue, maxValue, voxelSearched, seedVoxel); if (voxelFound == false) { if (DebugControl::getDebugOn()) { std::cout << "FindBiggestObjectWithinMask no initial voxel found with values: " << minValue << " " << maxValue << std::endl; } } // // Loop through all objects // while (voxelFound) { // // Create a stack // std::stack stack; stack.push(seedVoxel); // // Number of voxels in this connected piece // int numConnectedVoxels = 0; // // While there are voxels to search // while (stack.empty() == false) { // // Get the next voxel to search // const VoxelIJK v = stack.top(); stack.pop(); const int idx = getVoxelDataIndex(v.getIJK()); if (voxelSearched[idx] == VOXEL_NOT_SEARCHED) { voxelSearched[idx] = VOXEL_SEARCHED; // // Increase connected count // numConnectedVoxels++; // // Get the neighboring voxels // std::vector neighbors; getNeighbors(v, neighbors); // // Add neighbors to stack // for (unsigned int i = 0; i < neighbors.size(); i++) { VoxelIJK& v = neighbors[i]; const int idx = getVoxelDataIndex(v.getIJK()); if (voxelSearched[idx] == VOXEL_NOT_SEARCHED) { stack.push(v); } } } } // while (stack.isEmpty() == false) // // Was an object found // if (numConnectedVoxels > 0) { numberOfObjectsFound++; if (DebugControl::getDebugOn()) { int i, j, k; seedVoxel.getIJK(i, j, k); std::cout << "\t" << "seed : " << i << ", " << j << ", " << k << ": size " << numConnectedVoxels << std::endl; } } // // Is this bigger than previous object // if (numConnectedVoxels > largestObjectCount) { largestObjectCount = numConnectedVoxels; bigSeed = seedVoxel; } // // Find another voxel to search // voxelFound = findUnsearchedVoxel(minValue, maxValue, voxelSearched, seedVoxel); } // while (voxelFound) if (largestObjectCount > 0) { if (DebugControl::getDebugOn()) { int i, j, k; bigSeed.getIJK(i, j, k); std::cout << "\t" << "MAX seed : " << i << ", " << j << ", " << k << ": size " << largestObjectCount << std::endl; } } delete[] voxelSearched; } if (largestObjectCount == 0) { if (DebugControl::getDebugOn()) { std::cout << "\tNo voxels found, clearing volume." << std::endl; } for (int i = 0; i < numVoxels; i++) { voxels[i] = 0.0; } } return numberOfObjectsFound; } /** * Find voxel within value range that has not been searched. * Returns true if found else false. */ bool VolumeFile::findUnsearchedVoxel(const float minValue, const float maxValue, VOXEL_SEARCH_STATUS searchStatus[], VoxelIJK& seedOut) const { // // Loop through region // for (int k = 0; k < dimensions[2]; k++) { for (int j = 0; j < dimensions[1]; j++) { for (int i = 0; i < dimensions[0]; i++) { const int idx = getVoxelDataIndex(i, j, k); if (searchStatus[idx] == VOXEL_NOT_SEARCHED) { if ((voxels[idx] >= minValue) && (voxels[idx] <= maxValue)) { seedOut.setIJK(i, j, k); return true; } } } } } return false; } /** * remove islands (all but the largest connected piece of surface). * returns true if islands were removed */ bool VolumeFile::removeIslandsFromSegmentation() { // // Find the biggest piece of surface // VoxelIJK biggestPiece; if (findBiggestObject(255.0, 255.0, biggestPiece) > 1) { // // Keep only the biggest piece of surface // floodFillWithVTK(biggestPiece, 255, 255, 0); return true; } return false; } /** * flood fill slice with VTK. */ void VolumeFile::floodFillSliceWithVTK(const VolumeFile::VOLUME_AXIS axis, const int seed[3], const int connectedValueIn, const int connectedValueOut, const int unconnectedValueOut, VolumeModification* modifiedVoxels) { int sliceNum = 0; switch (axis) { case VOLUME_AXIS_X: sliceNum = seed[0]; break; case VOLUME_AXIS_Y: sliceNum = seed[1]; break; case VOLUME_AXIS_Z: sliceNum = seed[2]; break; case VOLUME_AXIS_ALL: case VOLUME_AXIS_OBLIQUE: case VOLUME_AXIS_OBLIQUE_X: case VOLUME_AXIS_OBLIQUE_Y: case VOLUME_AXIS_OBLIQUE_Z: case VOLUME_AXIS_OBLIQUE_ALL: case VOLUME_AXIS_UNKNOWN: return; break; } VolumeFile vf(*this); vf.setAllVoxels(0.0); vf.copySlice(this, sliceNum, axis, sliceNum); vf.floodFillWithVTK(seed, connectedValueIn, connectedValueOut, unconnectedValueOut, modifiedVoxels); copySlice(&vf, sliceNum, axis, sliceNum); } /** * flood fill with VTK. */ void VolumeFile::floodFillWithVTK(const int seed[3], const int connectedValueIn, const int connectedValueOut, const int unconnectedValueOut, VolumeModification* modifiedVoxels) { VoxelIJK seedIJK(seed); floodFillWithVTK(seedIJK, connectedValueIn, connectedValueOut, unconnectedValueOut, modifiedVoxels); } /** * flood fill with VTK. */ void VolumeFile::floodFillWithVTK(const VoxelIJK& seedVoxel, const int connectedValueIn, const int connectedValueOut, const int unconnectedValueOut, VolumeModification* modifiedVoxels) { if ((seedVoxel.getI() < 0) || (seedVoxel.getJ() < 0) || (seedVoxel.getK() < 0)) { std::cout << "ERROR: VolumeFile::floodFillWithVTK() called with invalid seed." << std::endl; std::cout << "ERROR: Seed = (" << seedVoxel.getI() << ", " << seedVoxel.getJ() << ", " << seedVoxel.getK() << ")" << std::endl; return; } VolumeFile* copyOfVolume = NULL; if (modifiedVoxels != NULL) { copyOfVolume = new VolumeFile(*this); } vtkStructuredPoints* sp = convertToVtkStructuredPoints(true); vtkImageSeedConnectivity* connect = vtkImageSeedConnectivity::New(); connect->SetInput(sp); connect->SetInputConnectValue(connectedValueIn); connect->SetOutputConnectedValue(connectedValueOut); connect->SetOutputUnconnectedValue(unconnectedValueOut); int i, j, k; seedVoxel.getIJK(i, j, k); connect->AddSeed(i, j, k); connect->Update(); convertFromVtkImageData(connect->GetOutput()); connect->Delete(); sp->Delete(); setModified(); minMaxVoxelValuesValid = false; minMaxTwoToNinetyEightPercentVoxelValuesValid = false; if (modifiedVoxels != NULL) { for (int i = 0; i < dimensions[0]; i++) { for (int j = 0; j < dimensions[1]; j++) { for (int k = 0; k < dimensions[2]; k++) { if (getVoxel(i, j, k) != copyOfVolume->getVoxel(i, j, k)) { modifiedVoxels->addVoxel(this, i, j, k, copyOfVolume); } } } } } if (copyOfVolume != NULL) { delete copyOfVolume; copyOfVolume = NULL; } } // // Find non-zero voxel extent and write limits file if filename is not isEmpty // void VolumeFile::findLimits(const QString& limitFileName, int extent[6]) { // // Find non-zero voxels // float coordExtent[6]; getNonZeroVoxelExtent(extent, coordExtent); if (DebugControl::getDebugOn()) { std::cout << "\textent: X " << extent[0] << " " << extent[1] << "; Y " << extent[2] << " " << extent[3] << "; Z " << extent[4] << " " << extent[5] << std::endl; } // // Should limits file be written // if (limitFileName.isEmpty() == false) { QFile file(limitFileName); if (file.open(QIODevice::WriteOnly)) { QTextStream stream(&file); stream.setRealNumberNotation(QTextStream::FixedNotation); stream.setRealNumberPrecision(6); stream << "LimitXmin=" << extent[0] << "\n"; stream << "LimitXmax=" << extent[1] << "\n"; stream << "LimitYmin=" << extent[2] << "\n"; stream << "LimitYmax=" << extent[3] << "\n"; stream << "LimitZmin=" << extent[4] << "\n"; stream << "LimitZmax=" << extent[5] << "\n"; file.close(); } else { std::cout << "Unable to open limits file: " << limitFileName.toAscii().constData() << std::endl; } } } /** * Shift the volume "offset" voxels in the specified axis */ void VolumeFile::shiftAxis(const VOLUME_AXIS axis, const int offset) { int i, j, k, idx1, idx2; float *voltemp; if (DebugControl::getDebugOn()) { std::cout << "ShiftAxis axis=" << axis << " offset=" << offset << std::endl; } const int numVoxels = getTotalNumberOfVoxels(); voltemp = new float [numVoxels]; for (i = 0; i < numVoxels; i++) { voltemp [i] = 0; } const int nslices = dimensions[2]; const int nrow = dimensions[1]; const int ncol = dimensions[0]; switch (axis){ case VOLUME_AXIS_X: for (k = 0; k < nslices; k++){ for (j = 0; j < nrow; j++){ for (i = 0; i < ncol; i++){ if (((i+offset) > 0) && ((i+offset) < ncol)){ idx1 = getVoxelDataIndex(i, j, k); idx2 = getVoxelDataIndex((i+offset), j, k); voltemp[idx2] = voxels[idx1]; } } } } break; case VOLUME_AXIS_Y: for (k = 0; k < nslices; k++){ for (j = 0; j < nrow; j++){ for (i = 0; i < ncol; i++){ if (((j+offset) > 0) && ((j+offset) < nrow)){ idx1 = getVoxelDataIndex(i, j, k); idx2 = getVoxelDataIndex(i, (j+offset), k); voltemp[idx2] = voxels[idx1]; } } } } break; case VOLUME_AXIS_Z: for (k = 0; k < nslices; k++){ for (j = 0; j < nrow; j++){ for (i = 0; i < ncol; i++){ if (((k+offset) > 0) && ((k+offset) < nslices)){ idx1 = getVoxelDataIndex(i, j, k); idx2 = getVoxelDataIndex(i, j, (k+offset)); voltemp[idx2] = voxels[idx1]; } } } } break; case VOLUME_AXIS_OBLIQUE: case VOLUME_AXIS_OBLIQUE_X: case VOLUME_AXIS_OBLIQUE_Y: case VOLUME_AXIS_OBLIQUE_Z: case VOLUME_AXIS_OBLIQUE_ALL: case VOLUME_AXIS_ALL: case VOLUME_AXIS_UNKNOWN: break; } for (i = 0; i < numVoxels; i++) { voxels[i] = voltemp[i]; } delete[] voltemp; setModified(); minMaxVoxelValuesValid = false; minMaxTwoToNinetyEightPercentVoxelValuesValid = false; } /** * Smear voxel data along a specified axis. During smearing, a voxel is set * to the maximum of its value and the corresponding voxel in an adjacent * slice. * * "mag" Number of iterations of smearing * * "sign" offset of slice to smear with the current slice * "-1" uses slice above * "1" uses slice below * * "core" * "0" If a voxel's value decreased as a result of smearing, set the * voxel to zero * "1" Output smearing regardless of voxel value changes. */ void VolumeFile::smearAxis(const VOLUME_AXIS axis, const int mag, const int sign, const int core) throw (FileException) { const int fliphem = 1; // for 1582 const int numVoxels = getTotalNumberOfVoxels(); float* vol1 = new float[numVoxels]; float* vol2 = new float[numVoxels]; for (int i = 0; i < numVoxels; i++){ vol1[i] = 0; vol2[i] = 0; } for (int i = 0; i < numVoxels; i++) { vol1[i] = voxels[i]; } const int nslices = dimensions[2]; const int nrow = dimensions[1]; const int ncol = dimensions[0]; for (int count = 0; count < mag; count++){ switch (axis){ case VOLUME_AXIS_X: if (DebugControl::getDebugOn()) { std::cout << "\tSmearXaxis " << count << " of " << mag << " smears" << std::endl; } for (int k = 0; k < nslices; k++){ for (int j = 0; j < nrow; j++){ for (int i = 0; i < ncol; i++){ if (fliphem == 0){ if (((i-sign) > 0) && ((i-sign) < ncol)){ int idx1 = getVoxelDataIndex(i, j, k); int idx2 = getVoxelDataIndex((i-sign), j, k); vol2[idx1] = std::max(vol1[idx2], vol1[idx1]); } }else{ //special case for 1582 HAD 5.28.99 if (((i+sign) > 0) && ((i+sign) < ncol)){ int idx1 = getVoxelDataIndex(i, j, k); int idx2 = getVoxelDataIndex((i+sign), j, k); vol2[idx1] = std::max(vol1[idx2], vol1[idx1]); } } } } } break; case VOLUME_AXIS_Y: if (DebugControl::getDebugOn()) { std::cout << "\tSmearYaxis " << count << " of " << mag << " smears" << std::endl; } for (int k = 0; k < nslices; k++){ for (int j = 0; j < nrow; j++){ for (int i = 0; i < ncol; i++){ if (((j-sign) > 0) && ((j-sign) < nrow)){ int idx1 = getVoxelDataIndex(i, j, k); int idx2 = getVoxelDataIndex(i, (j-sign), k); vol2[idx1] = std::max(vol1[idx2], vol1[idx1]); } } } } break; case VOLUME_AXIS_Z: if (DebugControl::getDebugOn()) { std::cout << "\tSmearZaxis " << count << " of " << mag << " smears" << std::endl; } for (int k = 0; k < nslices; k++){ for (int j = 0; j < nrow; j++){ for (int i = 0; i < ncol; i++){ if (((k-sign) > 0) && ((k-sign) < nslices)){ int idx1 = getVoxelDataIndex(i, j, k); int idx2 = getVoxelDataIndex(i, j, (k-sign)); vol2[idx1] = std::max(vol1[idx2], vol1[idx1]); } } } } break; case VOLUME_AXIS_ALL: case VOLUME_AXIS_OBLIQUE: case VOLUME_AXIS_OBLIQUE_X: case VOLUME_AXIS_OBLIQUE_Y: case VOLUME_AXIS_OBLIQUE_Z: case VOLUME_AXIS_OBLIQUE_ALL: case VOLUME_AXIS_UNKNOWN: throw FileException("VOLUME SMEAR: AXIS must be X, Y, or Z"); break; } for (int i = 0; i < ncol*nrow*nslices; i++) { vol1[i] = vol2[i]; } } if (core == 0) { for (int i = 0; i < numVoxels; i++){ voxels[i] = vol2[i] - voxels[i]; if (voxels[i] < 0) { voxels[i] = 0; } } } else { for (int i = 0; i < numVoxels; i++){ voxels[i] = vol2[i]; } } delete[] vol1; delete[] vol2; setModified(); minMaxVoxelValuesValid = false; minMaxTwoToNinetyEightPercentVoxelValuesValid = false; } /** * Stretch the voxel values and exlucde top and bottom percentage (0 to 100) */ void VolumeFile::stretchVoxelValuesExcludePercentage(const float bottomPercentToExclude, const float topPercentToExclude) { const StatisticHistogram* histogram = getHistogram(256, bottomPercentToExclude, topPercentToExclude); float minValue, maxValue, range, mean, sampleDeviation; histogram->getDataStatistics(minValue, maxValue, range, mean, sampleDeviation); rescaleVoxelValues(minValue, maxValue, 0.0, 255.0); delete histogram; histogram = NULL; } /** * Stretch the voxels in the volume to range 0 to 255. */ void VolumeFile::stretchVoxelValues() { const int numVoxels = getTotalNumberOfVoxels(); float minVoxel, maxVoxel; getMinMaxVoxelValues(minVoxel, maxVoxel); if (maxVoxel > minVoxel) { const float scale = 255.0/(maxVoxel-minVoxel); if (DebugControl::getDebugOn()) { std::cout << "stretchVoxelValues scale " << scale << std::endl; } for (int i = 0; i < numVoxels; i++){ float value = std::min(scale * (voxels[i] - minVoxel), 255.0f); voxels[i] = static_cast(value); } /* .000001 instead of 0 because of weird case where max=0 evaluated to 0.000000000000000000000000000036 ??? */ } else if ( maxVoxel > 0.000001 ) { //all voxels same positive value for (int i = 0; i < numVoxels; i++){ voxels[i]=255; } if (DebugControl::getDebugOn()) { std::cout << "0convertCoordinatesToVoxelIJK(xyz, ijk)) { voxelInMask = (maskVolume->getVoxel(ijk, 0) != 0.0); } // // If is not in mask // if (voxelInMask == false) { // // Turn off // setVoxel(i, j, k, 0, 0.0); } } } } } /** * voxels in "this" volume are set to "newVoxelValue" if the corresponding voxel * value in "maskVolume" is within the min and max values */ void VolumeFile::maskWithVolumeThreshold(const VolumeFile* maskVolume, const float maskMinimumVoxelValue, const float maskMaximumVoxelValue, const float newVoxelValue) throw (FileException) { if (maskVolume == NULL) { throw FileException("VolumeFile::maskWithVolumeThreshold: Mask volume is invalid."); } // // Verify dimensions match // int myDim[3], maskDim[3]; getDimensions(myDim); maskVolume->getDimensions(maskDim); for (int i = 0; i < 3; i++) { if (myDim[i] != maskDim[i]) { throw FileException("VolumeFile::maskWithVolumeThreshold: Mask volume dimensions to not match."); } } // // apply the mask // const int numComponents = getNumberOfComponentsPerVoxel(); for (int i = 0; i < myDim[0]; i++) { for (int j = 0; j < myDim[1]; j++) { for (int k = 0; k < myDim[2]; k++) { const float maskVoxelValue = maskVolume->getVoxel(i, j, k); if ((maskVoxelValue >= maskMinimumVoxelValue) && (maskVoxelValue <= maskMaximumVoxelValue)) { for (int m = 0; m < numComponents; m++) { setVoxel(i, j, k, m, newVoxelValue); } } } } } } /** * Clear all of the voxels outside the specified extent. */ void VolumeFile::maskVolume(const int limitsIn[6]) { if (DebugControl::getDebugOn()) { std::cout << "Extent (maskVolume): " << limitsIn[0] << " to " << limitsIn[1] << ", " << limitsIn[2] << " to " << limitsIn[3] << ", " << limitsIn[4] << " to " << limitsIn[5] << std::endl; } const int numVoxels = getTotalNumberOfVoxels(); float* out = new float[numVoxels]; for (int i = 0; i < numVoxels; i++){ out[i] = 0; } int limits[6]; for (int i = 0; i < 6; i++) { limits[i] = limitsIn[i]; } clampVoxelDimension(VOLUME_AXIS_X, limits[0]); clampVoxelDimension(VOLUME_AXIS_X, limits[1]); clampVoxelDimension(VOLUME_AXIS_Y, limits[2]); clampVoxelDimension(VOLUME_AXIS_Y, limits[3]); clampVoxelDimension(VOLUME_AXIS_Z, limits[4]); clampVoxelDimension(VOLUME_AXIS_Z, limits[5]); int cnt = 0; for (int k = limits [4]; k < limits [5]; k++){ for (int j = limits [2]; j < limits [3]; j++){ for (int i = limits [0]; i < limits [1]; i++){ const int idx = getVoxelDataIndex(i, j, k); cnt++; out[idx] = voxels[idx]; } } } for (int i = 0; i < numVoxels; i++){ voxels[i] = out[i]; } if (DebugControl::getDebugOn()) { std::cout << "COPIED " << cnt << " of " << numVoxels << " voxels: " << 100.0*((float)cnt/(float)(numVoxels)) << " percent." << std::endl; } delete[] out; setModified(); minMaxVoxelValuesValid = false; minMaxTwoToNinetyEightPercentVoxelValuesValid = false; } /** * */ void VolumeFile::sculptVolume(const int option, const VolumeFile* vol2, const int numsteps, int seed[3], int limits[6]) { clampVoxelDimension(VOLUME_AXIS_X, limits[0]); clampVoxelDimension(VOLUME_AXIS_X, limits[1]); clampVoxelDimension(VOLUME_AXIS_Y, limits[2]); clampVoxelDimension(VOLUME_AXIS_Y, limits[3]); clampVoxelDimension(VOLUME_AXIS_Z, limits[4]); clampVoxelDimension(VOLUME_AXIS_Z, limits[5]); clampVoxelIndex(VOLUME_AXIS_X, seed[0]); clampVoxelIndex(VOLUME_AXIS_Y, seed[1]); clampVoxelIndex(VOLUME_AXIS_Z, seed[2]); QString msg; if (option == 0) msg = "Sculpt And option"; else if (option == 1) msg = "Sculpt SeedAnd option"; else if (option == 2) msg = "Sculpt AndNot option"; else if (option == 3) msg = "Sculpt SeedAndNot option"; else exit (-1); if (DebugControl::getDebugOn()) { std::cout << msg.toAscii().constData() << std::endl; std::cout << "Sculpt Seed: " << seed[0] << ", " << seed[1] << ", " << seed[2] << std::endl; } const int numVoxels = getTotalNumberOfVoxels(); VolumeFile sculpttemp(*this); VolumeFile voltemp(*this); VolumeFile voltemp2(*this); VolumeFile shelltemp(*this); for (int i = 0; i < numVoxels; i++) { sculpttemp.voxels[i] = 0.0; voltemp.voxels[i] = 0.0; voltemp2.voxels[i] = 0.0; shelltemp.voxels[i] = 0.0; } if ((option == 1) || (option == 3)){ const int idx = getVoxelDataIndex(seed[0], seed[1], seed[2]); voltemp.voxels[idx] = voxels[idx]; } else{ for (int i = 0; i < numVoxels; i++) voltemp.voxels[i] = voxels[i]; } for (int step = 0; step < numsteps; step++) { if (DebugControl::getDebugOn()) { std::cout << "\tStep " << step << " of " << numsteps << std::endl; } for (int i = 0; i < numVoxels; i++) { voltemp2.voxels[i] = voltemp.voxels[i]; } //11/8voltemp2.makeShellVolume(&shelltemp, 1, 0); shelltemp = voltemp2; shelltemp.makeShellVolume(1, 0); if ((option == 0) || (option == 1)) { //And for (int i = 0; i < numVoxels; i++) { sculpttemp.voxels[i] = shelltemp.voxels[i] * vol2->voxels[i]; } for (int i = 0; i < numVoxels; i++) { if ((voltemp.voxels[i] > 0) || (sculpttemp.voxels[i] > 0)) { voltemp.voxels[i] = 255; } else { voltemp.voxels[i] = 0; } } } else { //AndNot for (int i = 0; i < numVoxels; i++) { sculpttemp.voxels[i] = shelltemp.voxels[i] * (255-vol2->voxels[i]); } for (int i = 0; i < numVoxels; i++) { if ((voltemp.voxels[i] > 0) || (sculpttemp.voxels[i] > 0)) { voltemp.voxels[i] = 255; } else { voltemp.voxels[i] = 0; } } } voltemp.imposeLimits(limits); } for (int i = 0; i < numVoxels; i++) { voxels[i] = voltemp.voxels[i]; } setModified(); minMaxVoxelValuesValid = false; minMaxTwoToNinetyEightPercentVoxelValuesValid = false; } /** * */ void VolumeFile::imposeLimits(const int limits[6]) { const int numVoxels = getTotalNumberOfVoxels(); float *out = new float[numVoxels]; for (int i = 0; i < numVoxels; i++) { out[i] = 0; } for (int k = limits[4]; k < limits[5]; k++){ for (int j = limits[2]; j < limits[3]; j++){ for (int i = limits[0]; i < limits[1]; i++){ const int idx = getVoxelDataIndex(i, j, k); out[idx] = voxels[idx]; } } } for (int i = 0; i < numVoxels; i++) { voxels[i] = out[i]; } delete[] out; setModified(); minMaxVoxelValuesValid = false; minMaxTwoToNinetyEightPercentVoxelValuesValid = false; } /** * */ void VolumeFile::makeShellVolume(const int Ndilation, const int Nerosion) { const int numVoxels = getTotalNumberOfVoxels(); VolumeFile vol2(*this); VolumeFile vol3(*this); for (int i = 0; i < numVoxels; i++) { vol2.voxels[i] = 0; } int localNeighsOffset[26]; for (int i = 0; i < 26; i++){ const int ii = localNeighbors[i][0]; const int jj = localNeighbors[i][1]; const int kk = localNeighbors[i][2]; localNeighsOffset[i] = ii + (jj * dimensions[0]) + (kk * dimensions[0] * dimensions[1]); } for (int i = 0; i < numVoxels; i++) { vol3.voxels[i] = voxels[i]; } if (Nerosion > 0) { for (int j = 0; j < Nerosion; j++) { if ((j % 2) == 0) { const int cnt = stripBorderVoxels(localNeighsOffset, 6, &vol2); if (DebugControl::getDebugOn()) { std::cout << "\tErode 6 neighs " << j << "; " << cnt << " voxels..." << std::endl; } } else { const int cnt = stripBorderVoxels(localNeighsOffset, 26, &vol2); if (DebugControl::getDebugOn()) { std::cout << "\tErode 26 neighs " << j << "; " << cnt << " voxels..." << std::endl; } } } } for (int i = 0; i < numVoxels; i++) { voxels[i] = vol3.voxels[i]; } int cnt = 0; if (Ndilation > 0){ for (int i = 0; i < numVoxels; i++) voxels[i] = 255 - voxels[i]; for (int i = 0; i < Ndilation; i++){ if ((i % 2) == 0){ cnt = stripBorderVoxels(localNeighsOffset, 6, &vol2); if (DebugControl::getDebugOn()) { std::cout << "\tDilate 6 neighs " << i << "; " << cnt << " voxels..." << std::endl; } } else { cnt = stripBorderVoxels(localNeighsOffset, 26, &vol2); if (DebugControl::getDebugOn()) { std::cout << "\tDilate 26 neighs " << i << "; " << cnt << " voxels..." << std::endl; } } } for (int i = 0; i < numVoxels; i++) { voxels[i] = 255 - voxels[i]; } } for (int i = 0; i < numVoxels; i++) { voxels[i] = vol2.voxels[i]; } setModified(); minMaxVoxelValuesValid = false; minMaxTwoToNinetyEightPercentVoxelValuesValid = false; } /** * */ int VolumeFile::stripBorderVoxels(const int neighborOffsets[], int numNeighs, VolumeFile *vol2) { const int numVoxels = getTotalNumberOfVoxels(); int cnt = 0; const int slices = dimensions[2] - 1; const int rows = dimensions[1] - 1; const int columns = dimensions[0] - 1; for (int k = 1; k < slices; k++) { if ((k % 50) == 0) { if (DebugControl::getDebugOn()) { std::cout << "\tslice " << k << std::endl; } } for (int j = 1; j < rows; j++) { for (int i = 1; i < columns; i++) { int idx = getVoxelDataIndex(i, j, k); if (voxels[idx] == 255) { int neighs[26]; computeNeighbors(idx, neighborOffsets, numNeighs, neighs); int n = 0; bool done = false; while ((n < numNeighs) && (done == false)) { if (voxels[neighs[n]] == 0) { done = true; // Found border voxel voxels[idx] = 127; cnt++; } n++; } } } } } for (int idx = 0; idx < numVoxels; idx++){ if (voxels[idx] == 127){ vol2->voxels[idx] = 255; voxels[idx] = 0; } } setModified(); minMaxVoxelValuesValid = false; minMaxTwoToNinetyEightPercentVoxelValuesValid = false; return(cnt); } /** * Get the neighbors for a node given one-dimensional offsets. */ int VolumeFile::computeNeighbors(const int idx, const int neighborOffsets[], const int numNeighs, int neighsOut[]) const { const int numVoxels = getTotalNumberOfVoxels(); int cnt = 0; for (int nn = 0; nn < numNeighs; nn++) { const int idx2 = idx + neighborOffsets[nn]; if ((idx2 >= 0) && (idx2 < numVoxels)) { neighsOut[cnt] = idx2; } else { neighsOut[cnt] = 0; } cnt++; } return (cnt); } /** * ??? */ void VolumeFile::makePlane(const float xslope, const float xoffset, const float yslope, const float yoffset, const float zslope, const float zoffset, const float offset, const float thickness) { if (DebugControl::getDebugOn()) { std::cout << "MakePlane " << xslope << "x + " << yslope << "y + " << zslope << "z - " << offset << " < " << thickness << std::endl; } for (int k = 0; k < dimensions[2]; k++){ for (int j = 0; j < dimensions[1]; j++){ for (int i = 0; i < dimensions[0]; i++){ float result = (xslope * (i - xoffset)) + (yslope * (j - yoffset)) + (zslope * (k - zoffset)); result = result - offset; if (result < 0) { result = -result; } if (result < thickness) { const int idx = getVoxelDataIndex(i, j, k); voxels[idx] = 255.0; } } } } setModified(); minMaxVoxelValuesValid = false; minMaxTwoToNinetyEightPercentVoxelValuesValid = false; } /** * dilation and erosion. */ void VolumeFile::doVolMorphOpsWithinMask(const int extent[6], const int nDilation, const int nErosion) { VolumeFile vf(*this); //vf.maskVolume(extent); vf.doVolMorphOps(nDilation, nErosion); unsigned char rgb[4]; copySubVolume(&vf, extent, rgb, rgb); setModified(); minMaxVoxelValuesValid = false; minMaxTwoToNinetyEightPercentVoxelValuesValid = false; } /** * dilation and erosion. */ void VolumeFile::doVolMorphOps(const int nDilation, const int nErosion) { if (DebugControl::getDebugOn()) { std::cout << nDilation << " dilation iters, " << nErosion << " erosion iters" << std::endl; } int localNeighsOffset[26]; for (int i = 0; i < 26; i++) { const int ii = localNeighbors[i][0]; const int jj = localNeighbors[i][1]; const int kk = localNeighbors[i][2]; localNeighsOffset[i] = ii + (jj * dimensions[0]) + (kk * dimensions[0] * dimensions[1]); } const int numVoxels = getTotalNumberOfVoxels(); int cnt = 0; if (nDilation > 0){ for (int i = 0; i < numVoxels; i++) { voxels[i] = 255.0 - voxels[i]; } for (int i = 0; i < nDilation; i++){ if ((i % 2) == 0){ cnt = stripBorderVoxels(localNeighsOffset, 6); if (DebugControl::getDebugOn()) { std::cout << "\tDilate 6 neighs " << i << "; " << cnt << " voxels...\n" << std::endl; } } else{ cnt = stripBorderVoxels(localNeighsOffset, 26); if (DebugControl::getDebugOn()) { std::cout << "\tDilate 26 neighs " << i << "; " << cnt << " voxels...\n" << std::endl; } } } for (int i = 0; i < numVoxels; i++) voxels[i] = 255.0 - voxels[i]; } cnt = 0; if (nErosion > 0){ for (int j = 0; j < nErosion; j++) { if ((j % 2) == 0) { cnt = stripBorderVoxels(localNeighsOffset, 6); if (DebugControl::getDebugOn()) { std::cout << "\tErode 6 neighs " << j << "; " << cnt << " voxels...\n" << std::endl; } } else { cnt = stripBorderVoxels(localNeighsOffset, 26); if (DebugControl::getDebugOn()) { std::cout << "\tErode 26 neighs " << j << "; " << cnt << " voxels...\n" << std::endl; } } } } setModified(); minMaxVoxelValuesValid = false; minMaxTwoToNinetyEightPercentVoxelValuesValid = false; } /** * ?? */ int VolumeFile::stripBorderVoxels(const int neighborOffsets[], const int numNeighs) { /* Mark border voxels */ if (DebugControl::getDebugOn()) { std::cout << "StripBorderVoxels ..." << std::endl; } const int nslices = dimensions[2]; const int nrow = dimensions[1]; const int ncol = dimensions[0]; int cnt = 0; for (int k = 1; k < nslices-1; k++){ if ((k % 20) == 0) { if (DebugControl::getDebugOn()) { std::cout << "\tslice " << k << std::endl; } } for (int j = 1; j < nrow-1; j++) { for (int i = 1; i < ncol-1; i++) { const int idx = getVoxelDataIndex(i, j, k); if (voxels[idx] == 255.0) { int neighs[26]; computeNeighbors(idx, neighborOffsets, numNeighs, neighs); int n = 0; bool done = false; while ((n < numNeighs) && (done == false)) { if (voxels[neighs[n]] == 0){ done = true; // Found border voxel voxels[idx] = 127.0; cnt++; } n++; } } } } } const int numVoxels = getTotalNumberOfVoxels(); for (int idx = 0; idx < numVoxels; idx++) { if (voxels[idx] == 127.0) { voxels[idx] = 0.0; } } setModified(); minMaxVoxelValuesValid = false; minMaxTwoToNinetyEightPercentVoxelValuesValid = false; return (cnt); } /** * Classify intensities */ void VolumeFile::classifyIntensities(const float mean, const float low, const float high, const float signum) { //%printf ("ClassifyIntensities: mean %f, low %f, high %f, signum %f\n", //% mean, low, high, signum); if (DebugControl::getDebugOn()) { std::cout << "ClassifyIntensities: mean " << mean << ", low " << low << ", high " << high << ", signum " << signum << std::endl; } const int numVoxels = getTotalNumberOfVoxels(); for (int i = 0; i < numVoxels; i++){ float sigma = 0.0; if (voxels[i] <= mean) { sigma = (mean-low) / signum; } else { sigma = (high-mean) / signum; } const float t1 = -((voxels[i] - mean) * (voxels[i] - mean)); voxels[i] = exp(t1 / (2.0 * sigma * sigma)); } setModified(); minMaxVoxelValuesValid = false; minMaxTwoToNinetyEightPercentVoxelValuesValid = false; if (DebugControl::getDebugOn()) { for (float f = 0.0; f <= 255.0; f += 1.0) { float sigma = 0.0; if (f <= mean) { sigma = (mean-low) / signum; } else { sigma = (high-mean) / signum; } const float t1 = -((f - mean) * (f - mean)); const float f2 = exp(t1 / (2.0 * sigma * sigma)); std::cout << " " << f << " => " << f2 << std::endl; } } } /** * get the number of non-zero voxels. */ int VolumeFile::getNumberOfNonZeroVoxels() const { int cnt = 0; const int num = getTotalNumberOfVoxels(); const int ncomp = getNumberOfComponentsPerVoxel(); for (int i = 0; i < num; i++) { for (int j = 0; j < ncomp; j++) { const int offset = i * ncomp + j; if (voxels[offset] != 0.0) { cnt++; break; } } } return cnt; } /** * */ void VolumeFile::blur() { float lpf_filter [5]; lpf_filter [0] = 1.0/16.0; lpf_filter [1] = 1.0/4.0; lpf_filter [2] = 3.0/8.0; lpf_filter [3] = 1.0/4.0; lpf_filter [4] = 1.0/16.0; seperableConvolve(dimensions[0], dimensions[1], dimensions[2], voxels, lpf_filter); setModified(); minMaxVoxelValuesValid = false; minMaxTwoToNinetyEightPercentVoxelValuesValid = false; } /** * */ void VolumeFile::seperableConvolve(int ncol, int nrow, int nslices, float *volume, float *filter) { int isize = ncol*nrow; //printf ("\tSeperableConvolve filtersize=%d\n", FSIZE); float* Result = new float[ncol*nrow*nslices]; float* TempSpace = new float[ncol*nrow*nslices]; float* voxel = volume; float* tempResult = Result; oneDimConvolve (voxel, tempResult, filter, 0, 1, ncol, nrow, nslices); //printf ("%d %f %f\n", idx, voxel[idx], tempResult[idx]); voxel = Result; tempResult = TempSpace; oneDimConvolve (voxel, tempResult, filter, 1, ncol, ncol, nrow, nslices); //printf ("%d %f %f\n", idx, voxel[idx], tempResult[idx]); voxel = TempSpace; tempResult = volume; oneDimConvolve (voxel, tempResult, filter, 2, isize, ncol, nrow, nslices); //printf ("%d %f %f\n", idx, voxel[idx], tempResult[idx]); delete[] Result; delete[] TempSpace; return; } /** * */ void VolumeFile::oneDimConvolve (float *voxel, float *tempResult, float *filter, const int dim, const int inc, const int ncol, const int nrow, const int nslices) { const int FILTSIZE = 5; float p[FILTSIZE]; int cnt = 0; for (int k = 0; k < nslices; k++){ for (int j = 0; j < nrow; j++){ for (int i = 0; i < ncol; i++){ float* ip = voxel; if (dim == 0){ if (i == 0){ p[0] = *ip; p[1] = *ip; p[2] = *ip; p[3] = *(ip+inc); p[4] = *(ip+inc+inc); } else if (i == 1) { p[0] = *(ip-inc); p[1] = *(ip-inc); p[2] = *ip; p[3] = *(ip+inc); p[4] = *(ip+inc+inc); } else if (i == ncol-2) { p[0] = *(ip-inc-inc); p[1] = *(ip-inc); p[2] = *ip; p[3] = *(ip+inc); p[4] = *(ip+inc); } else if (i == ncol-1) { p[0] = *(ip-inc-inc); p[1] = *(ip-inc); p[2] = *ip; p[3] = *ip; p[4] = *ip; } else { p[0] = *(ip-inc-inc); p[1] = *(ip-inc); p[2] = *ip; p[3] = *(ip+inc); p[4] = *(ip+inc+inc); } } else if (dim == 1) { if (j == 0){ p[0] = *ip; p[1] = *ip; p[2] = *ip; p[3] = *(ip+inc); p[4] = *(ip+inc+inc); } else if (j == 1) { p[0] = *(ip-inc); p[1] = *(ip-inc); p[2] = *ip; p[3] = *(ip+inc); p[4] = *(ip+inc+inc); } else if (j == nrow-2) { p[0] = *(ip-inc-inc); p[1] = *(ip-inc); p[2] = *ip; p[3] = *(ip+inc); p[4] = *(ip+inc); } else if (j == nrow-1) { p[0] = *(ip-inc-inc); p[1] = *(ip-inc); p[2] = *ip; p[3] = *ip; p[4] = *ip; } else { p[0] = *(ip-inc-inc); p[1] = *(ip-inc); p[2] = *ip; p[3] = *(ip+inc); p[4] = *(ip+inc+inc); } } else if (dim == 2) { if (k == 0){ p[0] = *ip; p[1] = *ip; p[2] = *ip; p[3] = *(ip+inc); p[4] = *(ip+inc+inc); } else if (k == 1) { p[0] = *(ip-inc); p[1] = *(ip-inc); p[2] = *ip; p[3] = *(ip+inc); p[4] = *(ip+inc+inc); } else if (k == nslices-2) { p[0] = *(ip-inc-inc); p[1] = *(ip-inc); p[2] = *ip; p[3] = *(ip+inc); p[4] = *(ip+inc); } else if (k == nslices-1) { p[0] = *(ip-inc-inc); p[1] = *(ip-inc); p[2] = *ip; p[3] = *ip; p[4] = *ip; } else { p[0] = *(ip-inc-inc); p[1] = *(ip-inc); p[2] = *ip; p[3] = *(ip+inc); p[4] = *(ip+inc+inc); } } *tempResult = 0; for (int n = 0; n < FILTSIZE; n++){ *tempResult += filter[n]*p[n]; } tempResult++; voxel++; cnt++; } } } } void VolumeFile::breadthFirstFloodFill(const VoxelIJK& seed, const float valueToFind, VolumeFile *markVolume, const float markValue, const bool onlyDoUnmarkedVoxels) const { // // See if this voxel has already been searched // if (onlyDoUnmarkedVoxels) { if (markVolume->getVoxel(seed) == markValue) { return; } } // // Initialize to the staring voxel // std::stack st; st.push(VoxelIJK(seed)); // // Keep track of voxels that have been searched // const int numVoxels = getTotalNumberOfVoxels(); if (numVoxels <= 0) { return; } int* voxelSearched = new int[numVoxels]; for (int i = 0; i < numVoxels; i++) { if (getVoxelWithFlatIndex(i) == valueToFind) { voxelSearched[i] = false; } else { voxelSearched[i] = true; } if (onlyDoUnmarkedVoxels) { if (markVolume->getVoxelWithFlatIndex(i) == markValue) { voxelSearched[i] = true; } } } // // While there are voxels to process // while (st.empty() == false) { // // Get the next voxel to process // const VoxelIJK v = st.top(); st.pop(); int i, j, k; v.getIJK(i, j, k); // // If the voxel has valid indices // if ((i >= 0) && (i < dimensions[0]) && (j >= 0) && (j < dimensions[1]) && (k >= 0) && (k < dimensions[2])) { const int ijk[3] = { i, j, k }; const float currentValue = getVoxel(ijk); // // See if voxel has been searched // const int flatIndex = getVoxelDataIndex(ijk); if (voxelSearched[flatIndex] == false) { voxelSearched[flatIndex] = true; // // See if voxel has proper value for operation // if (currentValue == valueToFind) { // // Update the voxels value // markVolume->setVoxel(ijk, 0, markValue); // // Add neighboring voxels for search // std::vector newVoxels; newVoxels.reserve(6); newVoxels.push_back(VoxelIJK(i - 1, j, k)); newVoxels.push_back(VoxelIJK(i + 1, j, k)); newVoxels.push_back(VoxelIJK(i, j - 1, k)); newVoxels.push_back(VoxelIJK(i, j + 1, k)); newVoxels.push_back(VoxelIJK(i, j, k - 1)); newVoxels.push_back(VoxelIJK(i, j, k + 1)); for (unsigned int i = 0; i < 6; i++) { const VoxelIJK& v= newVoxels[i]; if (getVoxelIndexValid(v)) { const int flatIndex = getVoxelDataIndex(v); if (voxelSearched[flatIndex] == false) { st.push(v); } } } } } } } delete[] voxelSearched; } /** * Fill internal cavities in a segmentation volume. */ void VolumeFile::fillSegmentationCavities(const VolumeFile* markVolumeIn) { // // Volume to keep track of unset voxels // VolumeFile* markVolume = NULL; if (markVolumeIn != NULL) { markVolume = new VolumeFile(*markVolumeIn); } else { markVolume = new VolumeFile(*this); markVolume->setAllVoxels(0.0); } // // Find voxels along edges that are not set // const int imax = dimensions[0] - 1; const int jmax = dimensions[1] - 1; const int kmax = dimensions[2] - 1; for (int k = 0; k <= kmax; k++) { for (int j = 0; j <= jmax; j++) { for (int i = 0; i <= imax; i++) { // // is this an edge voxel // if ((i == 0) || (i == imax) || (j == 0) || (j == jmax) || (k == 0) || (k == kmax)) { if (markVolume->getVoxel(i, j, k) == 0.0) { if (getVoxel(i, j, k) == 0.0) { VoxelIJK seed(i, j, k); breadthFirstFloodFill(seed, 0.0, markVolume, 1.0, true); } } } } } } // // If there are any other voxels not marked and not 255 set them because // they must be cavities in the segmentation // const int numVoxels = getTotalNumberOfVoxels(); for (int i = 0; i < numVoxels; i++) { if ((voxels[i] == 0.0) && (markVolume->voxels[i] == 0.0)) { voxels[i] = 255.0; } } setModified(); minMaxVoxelValuesValid = false; minMaxTwoToNinetyEightPercentVoxelValuesValid = false; setVoxelColoringInvalid(); delete markVolume; } /** * Fill internal cavities in a segmentation volume but only one slice. */ void VolumeFile::fillSegmentationCavitiesInSingleSlice(const VOLUME_AXIS axis, const int sliceNumber) { // // Create a mask volume with all voxels masked // VolumeFile maskVolume(*this); maskVolume.setAllVoxels(1.0); // // Determine voxels that should be unmasked // int iMin = 0; int iMax = dimensions[0] - 1; int jMin = 0; int jMax = dimensions[1] - 1; int kMin = 0; int kMax = dimensions[2] - 1; switch (axis) { case VOLUME_AXIS_X: iMin = sliceNumber; iMax = sliceNumber; break; case VOLUME_AXIS_Y: jMin = sliceNumber; jMax = sliceNumber; break; case VOLUME_AXIS_Z: kMin = sliceNumber; kMax = sliceNumber; break; case VOLUME_AXIS_ALL: case VOLUME_AXIS_OBLIQUE: case VOLUME_AXIS_OBLIQUE_X: case VOLUME_AXIS_OBLIQUE_Y: case VOLUME_AXIS_OBLIQUE_Z: case VOLUME_AXIS_OBLIQUE_ALL: case VOLUME_AXIS_UNKNOWN: break; } for (int i = iMin; i <= iMax; i++) { for (int j = jMin; j <= jMax; j++) { for (int k = kMin; k <= kMax; k++) { maskVolume.setVoxel(i, j, k, 0, 0); } } } // // cavites in the slice that is not masked // fillSegmentationCavities(&maskVolume); } /** * invert the voxels in a segmentation volume. */ void VolumeFile::invertSegmentationVoxels() { // // Voxels below 0.001 become 255, above 0.001 become 0 // inverseThresholdVolume(0.001); } /** * get the number of objects in a segmentation volume. */ int VolumeFile::getNumberOfSegmentationObjects() const { VoxelIJK seed; return findBiggestObject(255.0, 255.0, seed); } /** * get the number of objects in a segmentation volume. */ int VolumeFile::getNumberOfSegmentationObjectsSubVolume(const int extent[6]) const { VolumeFile volumeCopy(*this); volumeCopy.maskVolume(extent); return volumeCopy.getNumberOfSegmentationObjects(); } /** * get the number of cavities in a segmentation volume. */ int VolumeFile::getNumberOfSegmentationCavitiesSubVolume(const int extent[6]) const { VolumeFile volumeCopy(*this); volumeCopy.maskVolume(extent); return volumeCopy.getNumberOfSegmentationCavities(); } /** * get the number of cavities in a segmentation volume. */ int VolumeFile::getNumberOfSegmentationCavities() const { // // Make a copy of "this" volume // VolumeFile volumeCopy(*this); // // Flood fill around using all exterior voxels // const int maxDimX = dimensions[0] - 1; const int maxDimY = dimensions[1] - 1; const int maxDimZ = dimensions[2] - 1; const unsigned char rgb4[4] = { 255, 0, 0, 0 }; for (int i = 0; i <= maxDimX; i++) { for (int j = 0; j <= maxDimY; j++) { for (int k = 0; k <= maxDimZ; k++) { if ((i == 0) || (i == maxDimX) || (j == 0) || (j == maxDimY) || (k == 0) || (k == maxDimZ)) { if (getVoxel(i, j, k, 0) == 0.0) { const int ijk[3] = { i, j, k }; volumeCopy.floodFillAndRemoveConnected(SEGMENTATION_OPERATION_FLOOD_FILL_3D, VOLUME_AXIS_Z, ijk, 255.0, rgb4); } } } } } // // Invert the voxels // volumeCopy.invertSegmentationVoxels(); // // Count the objects // return volumeCopy.getNumberOfSegmentationObjects(); } /** * Generate a Cerebral Hull volume from "this" segmentation volume. */ void VolumeFile::createCerebralHullVolume(VolumeFile& cerebralHullOut) const { // // Copy "this" volume to the cerebral hull volume // cerebralHullOut = *this; // // Change file's name and description // cerebralHullOut.setFileWriteType(getFileWriteType()); cerebralHullOut.makeDefaultFileName("CerebralHull"); cerebralHullOut.setDescriptiveLabel("CerebralHull"); // // dialate and erode to fill in sulci // //cerebralHullOut.doVolMorphOps(6, 6); // // dilate six iterations // cerebralHullOut.doVolMorphOps(6, 0); // // fill cavities that may occur in deep sulci such as around insula // cerebralHullOut.fillSegmentationCavities(); // // erode six iterations // cerebralHullOut.doVolMorphOps(0, 6); // // OR cerebral hull together with "this" segmentation // performMathematicalOperation(VOLUME_MATH_OPERATION_OR, this, &cerebralHullOut, NULL, &cerebralHullOut); } /** * get the euler data for this volume but limit to a subvolume. */ void VolumeFile::getEulerCountsForSegmentationSubVolume(int& numberOfObjects, int& numberOfCavities, int& numberOfHoles, int& eulerCount, const int extent[6]) const { numberOfObjects = getNumberOfSegmentationObjectsSubVolume(extent); numberOfCavities = getNumberOfSegmentationCavitiesSubVolume(extent); eulerCount = getEulerNumberForSegmentationSubVolume(extent); numberOfHoles = numberOfObjects + numberOfCavities - eulerCount; } /** * get the euler data for this volume. */ void VolumeFile::getEulerCountsForSegmentationVolume(int& numberOfObjects, int& numberOfCavities, int& numberOfHoles, int& eulerCount) const { numberOfObjects = getNumberOfSegmentationObjects(); numberOfCavities = getNumberOfSegmentationCavities(); eulerCount = getEulerNumberForSegmentationVolume(); numberOfHoles = numberOfObjects + numberOfCavities - eulerCount; } /** * determine the euler number of a subvolume of segmentation volume. */ int VolumeFile::getEulerNumberForSegmentationSubVolume(const int extentIn[6]) const { /* int extent[6] = { extentIn[0], extentIn[1], extentIn[2], extentIn[3], extentIn[4], extentIn[5] }; // // Limit extent // clampVoxelIndex(VOLUME_AXIS_X, extent[0]); clampVoxelIndex(VOLUME_AXIS_X, extent[1]); clampVoxelIndex(VOLUME_AXIS_Y, extent[2]); clampVoxelIndex(VOLUME_AXIS_Y, extent[3]); clampVoxelIndex(VOLUME_AXIS_Z, extent[4]); clampVoxelIndex(VOLUME_AXIS_Z, extent[5]); // // add padding around the volume // extent[0]--; extent[1]++; extent[2]--; extent[3]++; extent[4]--; extent[5]++; // // Copy the volume // VolumeFile volumeCopy(*this); // // Resize the volume // volumeCopy.resize(extent); // // Zero out the voxels along the edges // int dim[3]; volumeCopy.getDimensions(dim); volumeCopy.setAllVoxelsInSlice(VOLUME_AXIS_X, 0, 0.0); volumeCopy.setAllVoxelsInSlice(VOLUME_AXIS_X, dim[0] - 1, 0.0); volumeCopy.setAllVoxelsInSlice(VOLUME_AXIS_Y, 0, 0.0); volumeCopy.setAllVoxelsInSlice(VOLUME_AXIS_Y, dim[1] - 1, 0.0); volumeCopy.setAllVoxelsInSlice(VOLUME_AXIS_Z, 0, 0.0); volumeCopy.setAllVoxelsInSlice(VOLUME_AXIS_Z, dim[2] - 1, 0.0); */ // // Get the euler number for the volume // VolumeFile volumeCopy(*this); volumeCopy.maskVolume(extentIn); return volumeCopy.getEulerNumberForSegmentationVolume(); } /** * determine the euler number of a segmentation volume. */ int VolumeFile::getEulerNumberForSegmentationVolume() const { if (eulerTableValid == false) { eulerTableValid = true; createEulerTable(); } float eulerSum = 0; const int d[3] = { 1, 1, 1 }; for (int k = 0; k < dimensions[2]; k++) { for (int j = 0; j < dimensions[1]; j++) { for (int i = 0; i < dimensions[0]; i++) { const int val = computeEulerOctant(i, j, k, d); eulerSum += eulerTable[val]; } } } return static_cast(eulerSum); } /** * create the euler table. */ void VolumeFile::createEulerTable() { for (int n = 0; n < 256; n++) { int corners[8]; for (int i = 0; i < 8; i++) { const int t1 = n >> (i + 1 - 1); const int t2 = t1 & 1; corners[7 - i] = t2; } float vertices = 0.0; for (int k = 0; k < 8; k++) { if (corners[k] == 1) { vertices += 1.0; } } float edges = 0.0; if ((corners[0] == 1) && (corners[1] == 1)) { edges += 1.0; } if ((corners[0] == 1) && (corners[2] == 1)) { edges += 1.0; } if ((corners[0] == 1) && (corners[4] == 1)) { edges += 1.0; } if ((corners[2] == 1) && (corners[3] == 1)) { edges += 1.0; } if ((corners[3] == 1) && (corners[7] == 1)) { edges += 1.0; } if ((corners[6] == 1) && (corners[7] == 1)) { edges += 1.0; } if ((corners[2] == 1) && (corners[6] == 1)) { edges += 1.0; } if ((corners[1] == 1) && (corners[5] == 1)) { edges += 1.0; } if ((corners[5] == 1) && (corners[7] == 1)) { edges += 1.0; } if ((corners[4] == 1) && (corners[5] == 1)) { edges += 1.0; } if ((corners[4] == 1) && (corners[6] == 1)) { edges += 1.0; } if ((corners[1] == 1) && (corners[3] == 1)) { edges += 1.0; } float faces = 0.0; if ((corners[0] == 1) && (corners[2] == 1) && (corners[4] == 1) && (corners[6] == 1)) { faces += 1.0; } if ((corners[0] == 1) && (corners[1] == 1) && (corners[2] == 1) && (corners[3] == 1)) { faces += 1.0; } if ((corners[1] == 1) && (corners[5] == 1) && (corners[3] == 1) && (corners[7] == 1)) { faces += 1.0; } if ((corners[4] == 1) && (corners[5] == 1) && (corners[6] == 1) && (corners[7] == 1)) { faces += 1.0; } if ((corners[2] == 1) && (corners[6] == 1) && (corners[7] == 1) && (corners[3] == 1)) { faces += 1.0; } if ((corners[0] == 1) && (corners[1] == 1) && (corners[4] == 1) && (corners[5] == 1)) { faces += 1.0; } float oct = 0.0; if (vertices == 8.0) { oct = 1.0; } eulerTable[n] = (vertices / 8.0) - (edges / 4.0) + (faces / 2.0) - oct; } } /** * Compute the euler value for a voxel. */ int VolumeFile::computeEulerOctant(const int i, const int j, const int k, const int D[3]) const { if ((i+D[0] >= 0) && (i+D[0] < dimensions[0]) && (j+D[1] >= 0) && (j+D[1] < dimensions[1]) && (k+D[2] >= 0) && (k+D[2] < dimensions[2])) { int vals[8]; vals[7] = getVoxelDataIndex(i, j, k); //ComputeIndex (i, j, k, ncol, nrow); const int offsetI = D[0]; const int offsetJ = D[1] * dimensions[0]; const int offsetK = D[2] * dimensions[0] * dimensions[1]; int newvals[8]; newvals[7] = vals[7]; newvals[6] = vals[7] + offsetI; newvals[5] = vals[7] + offsetJ; newvals[4] = vals[7] + offsetI + offsetJ; newvals[3] = vals[7] + offsetK; newvals[2] = vals[7] + offsetI + offsetK; newvals[1] = vals[7] + offsetJ + offsetK; newvals[0] = vals[7] + offsetI + offsetJ + offsetK; int octant[8]; octant[7] = static_cast(voxels[newvals[7]]); octant[6] = static_cast(voxels[newvals[6]]); octant[5] = static_cast(voxels[newvals[5]]); octant[4] = static_cast(voxels[newvals[4]]); octant[3] = static_cast(voxels[newvals[3]]); octant[2] = static_cast(voxels[newvals[2]]); octant[1] = static_cast(voxels[newvals[1]]); octant[0] = static_cast(voxels[newvals[0]]); int ans2 = 0; for (int i = 0; i < 8; i++){ if (octant[i] != 0.0){ if (i == 0) { ans2 += 1; } else { ans2 += 2 << (i-1); } } } return ans2; } return 0; } /** * get topology information by generating a surface. * Cavities are filled prior to euler count. */ void VolumeFile::getSegmentationTopologyInformation(int& numberOfObjects, int& numberOfCavities, int& numberOfHoles, int& eulerCount) const throw (FileException) { // // Copy this volume // VolumeFile volumeCopy(*this); // // Remove islands and fill cavities // volumeCopy.fillSegmentationCavities(); // // Convert to structured points // vtkStructuredPoints* sp = volumeCopy.convertToVtkStructuredPoints(); // // Shrinker - does this actually do anything ? // vtkImageShrink3D* shrinker = vtkImageShrink3D::New(); shrinker->SetInput(sp); shrinker->SetShrinkFactors(1, 1, 1); shrinker->AveragingOn(); // // Gaussian smooth the volume // vtkImageGaussianSmooth* gaussian = vtkImageGaussianSmooth::New(); gaussian->SetDimensionality(3); gaussian->SetStandardDeviation(0); gaussian->SetInput(shrinker->GetOutput()); // // Marching cubes converts volume to a surface // vtkMarchingCubes* mc = vtkMarchingCubes::New(); mc->SetInput(gaussian->GetOutput()); mc->SetValue(0, 127.5); mc->ComputeScalarsOff(); mc->ComputeGradientsOff(); mc->ComputeNormalsOff(); // // Clean up surface created by marching cubes // vtkCleanPolyData* clean = vtkCleanPolyData::New(); clean->SetInput(mc->GetOutput()); // // Make sure mesh is only triangles // vtkTriangleFilter *triangleFilter = vtkTriangleFilter::New(); triangleFilter->SetInput(clean->GetOutput()); // // Compute normals on the surface to fix polygon orientations // vtkPolyDataNormals* rawNormals = vtkPolyDataNormals::New(); rawNormals->SetInput(triangleFilter->GetOutput()); rawNormals->SplittingOff(); rawNormals->ConsistencyOn(); rawNormals->ComputePointNormalsOn(); rawNormals->NonManifoldTraversalOn(); rawNormals->Update(); // // Get topology // TopologyFile topologyFile; topologyFile.importFromVtkFile(rawNormals->GetOutput()); // // Remove any islands // //topologyFile.disconnectIslands(); int faces, edges, vertices; topologyFile.getEulerCount(false, faces, vertices, edges, eulerCount, numberOfHoles, numberOfObjects); numberOfCavities = getNumberOfSegmentationCavities(); rawNormals->Delete(); triangleFilter->Delete(); clean->Delete(); mc->Delete(); gaussian->Delete(); shrinker->Delete(); } /** * make a sphere within the volume. */ void VolumeFile::makeSphere(const int center[3], const float radius) { if (DebugControl::getDebugOn()) { std::cout << "MakeSphere of " << radius << " radius at " << center[0] << ", " << center[1] << ", " << center[2] << std::endl; } const float radiusSquared = radius * radius; int xDim, yDim, zDim; getDimensions(xDim, yDim, zDim); for (int k = 0; k < zDim; k++) { for (int j = 0; j < yDim; j++) { for (int i = 0; i < xDim; i++) { const float dx = i - center[0]; const float dy = j - center[1]; const float dz = k - center[2]; const float result = dx*dx + dy*dy + dz*dz; float value = 0; if (result <= radiusSquared) { value = 255; } setVoxel(i, j, k, 0, value); } } } } /** * assign voxels within border for paint volumes. */ void VolumeFile::assignVoxelsWithinBorder(const VOLUME_AXIS axis, const QString& paintName, const Border* border, const int slicesAboveAndBelowPlane) { const float voxelValue = addRegionName(paintName); const unsigned char voxelColor[4] = { 0, 0, 0, VOXEL_COLOR_STATUS_INVALID }; const float scaleFactor = 1000.0; const int numLinks = border->getNumberOfLinks(); float sliceZ = 0; std::vector polygon; int numToSkip = 1; int numInPolygon = 0; for (int i = 0; i < (numLinks - 1); i++) { const float* pos = border->getLinkXYZ(i); switch (axis) { case VOLUME_AXIS_X: polygon.push_back(pos[1] * scaleFactor); polygon.push_back(pos[2] * scaleFactor); if (i == 0) { sliceZ = pos[0]; } break; case VOLUME_AXIS_Y: polygon.push_back(pos[0] * scaleFactor); polygon.push_back(pos[2] * scaleFactor); if (i == 0) { sliceZ = pos[1]; } break; case VOLUME_AXIS_Z: polygon.push_back(pos[0] * scaleFactor); polygon.push_back(pos[1] * scaleFactor); if (i == 0) { sliceZ = pos[2]; } break; case VOLUME_AXIS_ALL: case VOLUME_AXIS_OBLIQUE: case VOLUME_AXIS_OBLIQUE_X: case VOLUME_AXIS_OBLIQUE_Y: case VOLUME_AXIS_OBLIQUE_Z: case VOLUME_AXIS_OBLIQUE_ALL: case VOLUME_AXIS_UNKNOWN: return; break; } polygon.push_back(0.0); numInPolygon++; i += numToSkip; } if (numInPolygon < 3) { return; } int sliceNumber = 0; float sliceDistance = std::numeric_limits::max(); switch(axis) { case VolumeFile::VOLUME_AXIS_X: // PARASAGITTAL for (int i = 0; i < dimensions[0]; i++) { const float val = i * spacing[0] + origin[0]; const float dist = fabs(sliceZ - val); if (dist < sliceDistance) { sliceNumber = i; sliceDistance = dist; } } break; case VolumeFile::VOLUME_AXIS_Y: // CORONAL for (int i = 0; i < dimensions[1]; i++) { const float val = i * spacing[1] + origin[1]; const float dist = fabs(sliceZ - val); if (dist < sliceDistance) { sliceNumber = i; sliceDistance = dist; } } break; case VolumeFile::VOLUME_AXIS_Z: // HORIZONTAL for (int i = 0; i < dimensions[2]; i++) { const float val = i * spacing[2] + origin[2]; const float dist = fabs(sliceZ - val); if (dist < sliceDistance) { sliceNumber = i; sliceDistance = dist; } } break; case VOLUME_AXIS_ALL: case VOLUME_AXIS_OBLIQUE: case VOLUME_AXIS_OBLIQUE_X: case VOLUME_AXIS_OBLIQUE_Y: case VOLUME_AXIS_OBLIQUE_Z: case VOLUME_AXIS_OBLIQUE_ALL: case VOLUME_AXIS_UNKNOWN: return; break; } // // Get the bounds but adjust it based upon the axis // float bounds[6], boundsTemp[6]; border->getBounds(boundsTemp); switch (axis) { case VOLUME_AXIS_X: bounds[0] = boundsTemp[2] * scaleFactor; bounds[1] = boundsTemp[3] * scaleFactor; bounds[2] = boundsTemp[4] * scaleFactor; bounds[3] = boundsTemp[5] * scaleFactor; break; case VOLUME_AXIS_Y: bounds[0] = boundsTemp[0] * scaleFactor; bounds[1] = boundsTemp[1] * scaleFactor; bounds[2] = boundsTemp[4] * scaleFactor; bounds[3] = boundsTemp[5] * scaleFactor; break; case VOLUME_AXIS_Z: bounds[0] = boundsTemp[0] * scaleFactor; bounds[1] = boundsTemp[1] * scaleFactor; bounds[2] = boundsTemp[2] * scaleFactor; bounds[3] = boundsTemp[3] * scaleFactor; break; case VOLUME_AXIS_ALL: case VOLUME_AXIS_OBLIQUE: case VOLUME_AXIS_OBLIQUE_X: case VOLUME_AXIS_OBLIQUE_Y: case VOLUME_AXIS_OBLIQUE_Z: case VOLUME_AXIS_OBLIQUE_ALL: case VOLUME_AXIS_UNKNOWN: return; break; } bounds[4] = -1.0; bounds[5] = 1.0; float normal[3] = { 0.0, 0.0, 1.0 }; int maxI = 0; int maxJ = 0; switch (axis) { case VOLUME_AXIS_X: maxI = dimensions[1]; maxJ = dimensions[2]; break; case VOLUME_AXIS_Y: maxI = dimensions[0]; maxJ = dimensions[2]; break; case VOLUME_AXIS_Z: maxI = dimensions[0]; maxJ = dimensions[1]; break; case VOLUME_AXIS_ALL: case VOLUME_AXIS_OBLIQUE: case VOLUME_AXIS_OBLIQUE_X: case VOLUME_AXIS_OBLIQUE_Y: case VOLUME_AXIS_OBLIQUE_Z: case VOLUME_AXIS_OBLIQUE_ALL: case VOLUME_AXIS_UNKNOWN: return; break; } for (int i = 0; i < maxI; i++) { for (int j = 0; j < maxJ; j++) { // // Get voxel indices // int ijk[3]; switch (axis) { case VOLUME_AXIS_X: ijk[0] = sliceNumber; ijk[1] = i; ijk[2] = j; break; case VOLUME_AXIS_Y: ijk[0] = i; ijk[1] = sliceNumber; ijk[2] = j; break; case VOLUME_AXIS_Z: ijk[0] = i; ijk[1] = j; ijk[2] = sliceNumber; break; case VOLUME_AXIS_ALL: case VOLUME_AXIS_OBLIQUE: case VOLUME_AXIS_OBLIQUE_X: case VOLUME_AXIS_OBLIQUE_Y: case VOLUME_AXIS_OBLIQUE_Z: case VOLUME_AXIS_OBLIQUE_ALL: case VOLUME_AXIS_UNKNOWN: return; break; } if (getVoxelIndexValid(ijk)) { float coord[3]; getVoxelCoordinate(ijk, coord); coord[0] *= scaleFactor; coord[1] *= scaleFactor; coord[2] *= scaleFactor; float xyz[3] = { 0.0, 0.0, 0.0 }; switch (axis) { case VOLUME_AXIS_X: xyz[0] = coord[1]; xyz[1] = coord[2]; break; case VOLUME_AXIS_Y: xyz[0] = coord[0]; xyz[1] = coord[2]; break; case VOLUME_AXIS_Z: xyz[0] = coord[0]; xyz[1] = coord[1]; break; case VOLUME_AXIS_ALL: case VOLUME_AXIS_OBLIQUE: case VOLUME_AXIS_OBLIQUE_X: case VOLUME_AXIS_OBLIQUE_Y: case VOLUME_AXIS_OBLIQUE_Z: case VOLUME_AXIS_OBLIQUE_ALL: case VOLUME_AXIS_UNKNOWN: return; break; } if (MathUtilities::pointInPolygon(xyz, numInPolygon, (float*)&polygon[0], bounds, normal)) { setVoxel(ijk, 0, voxelValue); setVoxelColor(ijk, voxelColor); // // Is more than the current slice being filled // if (slicesAboveAndBelowPlane > 0) { int iStart = ijk[0]; int iEnd = ijk[0]; int jStart = ijk[1]; int jEnd = ijk[1]; int kStart = ijk[2]; int kEnd = ijk[2]; switch (axis) { case VOLUME_AXIS_X: iStart -= slicesAboveAndBelowPlane; iEnd += slicesAboveAndBelowPlane; break; case VOLUME_AXIS_Y: jStart -= slicesAboveAndBelowPlane; jEnd += slicesAboveAndBelowPlane; break; case VOLUME_AXIS_Z: kStart -= slicesAboveAndBelowPlane; kEnd += slicesAboveAndBelowPlane; break; case VOLUME_AXIS_ALL: case VOLUME_AXIS_OBLIQUE: case VOLUME_AXIS_OBLIQUE_X: case VOLUME_AXIS_OBLIQUE_Y: case VOLUME_AXIS_OBLIQUE_Z: case VOLUME_AXIS_OBLIQUE_ALL: case VOLUME_AXIS_UNKNOWN: return; break; } for (int ii = iStart; ii <= iEnd; ii++) { for (int jj = jStart; jj <= jEnd; jj++) { for (int kk = kStart; kk <= kEnd; kk++) { if (getVoxelIndexValid(ii, jj, kk)) { setVoxel(ii, jj, kk, 0, voxelValue); setVoxelColor(ii, jj, kk, voxelColor); } } } } } } } } } setModified(); minMaxVoxelValuesValid = false; minMaxTwoToNinetyEightPercentVoxelValuesValid = false; } /** * assing paint volume voxels. */ void VolumeFile::assignPaintVolumeVoxels(const QString& paintName, const int ijkMin[3], const int ijkMax[3], VolumeModification* modifiedVoxels) { const float voxelValue = addRegionName(paintName); const unsigned char voxelColor[4] = { 0, 0, 0, VOXEL_COLOR_STATUS_INVALID }; for (int i = ijkMin[0]; i <= ijkMax[0]; i++) { for (int j = ijkMin[1]; j <= ijkMax[1]; j++) { for (int k = ijkMin[2]; k <= ijkMax[2]; k++) { if (getVoxelIndexValid(i, j, k)) { if (modifiedVoxels != NULL) { modifiedVoxels->addVoxel(this, i, j, k); } setVoxel(i, j, k, 0, voxelValue); setVoxelColor(i, j, k, voxelColor); } } } } setModified(); minMaxVoxelValuesValid = false; minMaxTwoToNinetyEightPercentVoxelValuesValid = false; } /** * AC-PC align a volume. */ void VolumeFile::acPcAlign(const int superiorAcVoxel[3], const int inferiorPcVoxel[3], const int superiorLateralFissureVoxel[3]) throw (FileException) { // // force origin's negative, spacing negative, and make orientation LPI // origin[0] = -fabs(origin[0]); origin[1] = -fabs(origin[1]); origin[2] = -fabs(origin[2]); spacing[0] = fabs(spacing[0]); spacing[1] = fabs(spacing[1]); spacing[2] = fabs(spacing[2]); orientation[0] = ORIENTATION_LEFT_TO_RIGHT; orientation[1] = ORIENTATION_POSTERIOR_TO_ANTERIOR; orientation[2] = ORIENTATION_INFERIOR_TO_SUPERIOR; // // old AC voxel // const float zeros[3] = { 0.0, 0.0, 0.0 }; int oldAcVoxel[3]; convertCoordinatesToVoxelIJK(zeros, oldAcVoxel); // // Translate (set origin) so AC becomes the origin // const float newOrigin[3] = { -(superiorAcVoxel[0] * spacing[0]), -(superiorAcVoxel[1] * spacing[1]), -(superiorAcVoxel[2] * spacing[2]) }; setOrigin(newOrigin); // // Get stereotaxic coordinates of PC and CC // float superiorAcXYZ[3] = { 0.0, 0.0, 0.0 }; //convertCoordinatesToVoxelIJK(superiorAcXYZ, superiorAcVoxel); getVoxelCoordinate(superiorAcVoxel, superiorAcXYZ); float inferiorPcXYZ[3]; getVoxelCoordinate(inferiorPcVoxel, inferiorPcXYZ); float superiorLfXYZ[3]; getVoxelCoordinate(superiorLateralFissureVoxel, superiorLfXYZ); // // Vector from PC to AC // float acToPc[3] = { inferiorPcXYZ[0] - superiorAcXYZ[0], inferiorPcXYZ[1] - superiorAcXYZ[1], inferiorPcXYZ[2] - superiorAcXYZ[2] }; // // Normalize the vector // vtkMath::Normalize(acToPc); // assume a vector goes from the AC in the // negative Y direction so it would be something like (0, -1, 0). // Use the dot product to determine the angle between a vector running // down the negative Y axis and the AC to PC unit vector. const float negYVector[3] = { 0.0, -1.0, 0.0 }; const float negYDot = vtkMath::Dot(negYVector, acToPc); const float angle = std::acos(negYDot) * MathUtilities::radiansToDegrees(); // // Normal vector formed by PC, AC, and point on negative Y Axis // const double floatAC[3] = { superiorAcXYZ[0], superiorAcXYZ[1], superiorAcXYZ[2] }; const double floatPC[3] = { inferiorPcXYZ[0], inferiorPcXYZ[1], inferiorPcXYZ[2] }; const double negY[3] = { 0.0, -25.0, 0.0 }; double pcAcNegYNormal[3]; vtkTriangle::ComputeNormal((double*)floatPC, (double*)floatAC, (double*)negY, pcAcNegYNormal); // // Create a transformation matrix for the rotation and apply it to the volume // TransformationMatrix tm; tm.rotate(angle, pcAcNegYNormal); tm.transpose(); applyTransformationMatrix(tm); // ************************************************* // At this point in time the AC is at the origin and // the PC is on the negative Y axis. // ************************************************* // // Distance of lateral fissure voxel from XZ plane // const float lfDist = sqrt(superiorLfXYZ[0] * superiorLfXYZ[0] + superiorLfXYZ[2] * superiorLfXYZ[2]); // // Vector from Y axis to LF point in the XZ plane // float lfVect[3] = { superiorLfXYZ[0], 0.0, superiorLfXYZ[2] }; vtkMath::Normalize(lfVect); // // Vector pointing up in Z // float ccZ[3] = { 0.0, 0.0, lfDist }; vtkMath::Normalize(ccZ); // // Angle that volume shold be rotated about Y axis so that // the lateral fissure point is directly above the Y-axis. // const float yDot = vtkMath::Dot(lfVect, ccZ); const float yAngle = std::acos(yDot) * MathUtilities::radiansToDegrees(); const float yAngle2 = std::atan2(superiorLfXYZ[0], superiorLfXYZ[2]) * MathUtilities::radiansToDegrees(); if (DebugControl::getDebugOn()) { std::cout << "AC-PC align along Y Axis:" << std::endl; std::cout << " " << yAngle << " " << yAngle2 << std::endl; } // // Create transformation matrix and apply it to the volume // const double posYVec[3] = { 0.0, 1.0, 0.0 }; TransformationMatrix tm2; tm2.rotate(yAngle2, posYVec); //tm2.rotateY(yAngle); tm2.transpose(); applyTransformationMatrix(tm2); } /** * convert from ITK Image. */ void VolumeFile::convertFromITKImage(VolumeITKImage& itkImageIn) throw (FileException) { #ifndef HAVE_ITK throw FileException("ITK support not compiled into this version of Caret"); #endif // HAVE_ITK #ifdef HAVE_ITK // // // VolumeITKImage::ImageTypeFloat3::RegionType region = itkImageIn.image->GetLargestPossibleRegion(); // // // VolumeITKImage::ImageTypeFloat3::SizeType size = region.GetSize(); //std::cout << "Size: " << size[0] << ", " << size[1] << ", " << size[2] << std::endl; const int dim[3] = { size[0], size[1], size[2] }; // // Get origin // VolumeITKImage::ImageTypeFloat3::PointType org = itkImageIn.image->GetOrigin(); //std::cout << "Origin: " << org[0] << ", " << org[1] << ", " << org[2] << std::endl; float org2[3] = { org[0], org[1], org[2] }; // // Get Spacing // VolumeITKImage::ImageTypeFloat3::SpacingType space = itkImageIn.image->GetSpacing(); //std::cout << "Spacing: " << space[0] << ", " << space[1] << ", " << space[2] << std::endl; float space2[3] = { space[0], space[1], space[2] }; org[0] += (space2[0] * 0.5); org[1] += (space2[1] * 0.5); org[2] += (space2[2] * 0.5); // // Do voxels need to be reallocated ? // if ((dimensions[0] != dim[0]) || (dimensions[1] != dim[1]) || (dimensions[2] != dim[2])) { initialize(VOXEL_DATA_TYPE_FLOAT, dim, orientation, org2, space2, false, true); } setSpacing(space2); setOrigin(org2); // // Load the pixels // VolumeITKImage::ImageTypeFloat3::IndexType voxelIndex; for (int i = 0; i < dimensions[0]; i++) { for (int j = 0; j < dimensions[1]; j++) { for (int k = 0; k < dimensions[2]; k++) { voxelIndex[0] = i; voxelIndex[1] = j; voxelIndex[2] = k; VolumeITKImage::ImageTypeFloat3::PixelType pixelValue = itkImageIn.image->GetPixel(voxelIndex); setVoxel(i, j, k, 0, pixelValue); } } } #endif } /** * convert to ITK Image. */ void VolumeFile::convertToITKImage(VolumeITKImage& itkImageOut) throw (FileException) { #ifndef HAVE_ITK throw FileException("ITK support not compiled into this version of Caret"); #endif // HAVE_ITK #ifdef HAVE_ITK // // Size (dimensions) of image // VolumeITKImage::ImageTypeFloat3::SizeType size; size[0] = dimensions[0]; size[1] = dimensions[1]; size[2] = dimensions[2]; // // First index in each direction // VolumeITKImage::ImageTypeFloat3::IndexType start; start[0] = 0; start[1] = 0; start[2] = 0; // // Set voxel start and dimensions // VolumeITKImage::ImageTypeFloat3::RegionType region; region.SetIndex(start); region.SetSize(size); itkImageOut.image->SetRegions(region); // // Set origin // VolumeITKImage::ImageTypeFloat3::PointType org; float forg[3]; getOriginAtCornerOfVoxel(forg); org[0] = forg[0]; org[1] = forg[1]; org[2] = forg[2]; itkImageOut.image->SetOrigin(org); // // Set Spacing // VolumeITKImage::ImageTypeFloat3::SpacingType space; space[0] = spacing[0]; space[1] = spacing[1]; space[2] = spacing[2]; itkImageOut.image->SetSpacing(space); // // Allocate the image data // itkImageOut.image->Allocate(); // // Load the pixels // VolumeITKImage::ImageTypeFloat3::IndexType voxelIndex; for (int i = 0; i < dimensions[0]; i++) { for (int j = 0; j < dimensions[1]; j++) { for (int k = 0; k < dimensions[2]; k++) { voxelIndex[0] = i; voxelIndex[1] = j; voxelIndex[2] = k; itkImageOut.image->SetPixel(voxelIndex, getVoxel(i, j, k)); } } } #endif } /** * get the types of volumes and names available for writing. */ void VolumeFile::getVolumeFileTypesAndNames(std::vector& fileTypes, std::vector& fileTypeNames) { fileTypes.clear(); fileTypeNames.clear(); fileTypes.push_back(FILE_READ_WRITE_TYPE_AFNI); fileTypeNames.push_back("AFNI"); fileTypes.push_back(FILE_READ_WRITE_TYPE_ANALYZE); fileTypeNames.push_back("Analyze"); fileTypes.push_back(FILE_READ_WRITE_TYPE_NIFTI); fileTypeNames.push_back("NIFTI"); fileTypes.push_back(FILE_READ_WRITE_TYPE_NIFTI_GZIP); fileTypeNames.push_back("NIFTI_GZIP"); fileTypes.push_back(FILE_READ_WRITE_TYPE_SPM_OR_MEDX); fileTypeNames.push_back("SPM/MEDx"); fileTypes.push_back(FILE_READ_WRITE_TYPE_WUNIL); fileTypeNames.push_back("WU-NIL"); // // Cause compilation warning if types updated // FILE_READ_WRITE_TYPE frwt = FILE_READ_WRITE_TYPE_RAW; switch (frwt) { case FILE_READ_WRITE_TYPE_RAW: break; case FILE_READ_WRITE_TYPE_AFNI: break; case FILE_READ_WRITE_TYPE_ANALYZE: break; case FILE_READ_WRITE_TYPE_NIFTI: break; case FILE_READ_WRITE_TYPE_NIFTI_GZIP: break; case FILE_READ_WRITE_TYPE_SPM_OR_MEDX: break; case FILE_READ_WRITE_TYPE_WUNIL: break; case FILE_READ_WRITE_TYPE_UNKNOWN: break; } } /** * read the file header and the specified subvolume data. * subVolumeNumber may also be on of VOLUME_READING_SELECTION */ void VolumeFile::readFile(const QString& fileNameIn, const int subVolumeNumber, const bool spmRightIsOnLeft) throw (FileException) { QTime timer; timer.start(); // // Read the sub-volume // std::vector volumes; readFile(fileNameIn, subVolumeNumber, volumes, spmRightIsOnLeft); // // Was anything read? // if (volumes.empty() == false) { // // Copy the volume // *this = *(volumes[0]); this->filename = volumes[0]->filename; this->dataFileName = volumes[0]->dataFileName; } // // Free the volumes // for (unsigned int i = 0; i < volumes.size(); i++) { delete volumes[i]; } timeToReadFileInSeconds = (static_cast(timer.elapsed()) / 1000.0); if (DebugControl::getDebugOn()) { std::cout << "Time to read " << FileUtilities::basename(filename).toAscii().constData() << " was " << timeToReadFileInSeconds << " seconds." << std::endl; } } /** * read the names of the volume's sub-volumes. */ void VolumeFile::readSubVolumeNames(const QString& fileNameIn, std::vector& subVolumeNamesOut) throw (FileException) { // // Read the sub-volume // std::vector volumes; readFile(fileNameIn, VOLUME_READ_HEADER_ONLY, volumes); // // Was anything read? // if (volumes.empty() == false) { subVolumeNamesOut = volumes[0]->subVolumeNames; } // // Free the volumes // for (unsigned int i = 0; i < volumes.size(); i++) { delete volumes[i]; } } /** * read the specified sub-volumes in a volume file. * subVolumeNumber may also be on of VOLUME_READING_SELECTION */ void VolumeFile::readFile(const QString& fileNameIn, const int readSelection, std::vector& volumesReadOut, const bool spmRightIsOnLeft) throw (FileException) { // // clear the output // volumesReadOut.clear(); // // hdr/image pair may be NIFTI // bool niftiFlag = false; if (StringUtilities::endsWith(fileNameIn, SpecFile::getAnalyzeVolumeFileExtension())) { niftiFlag = NiftiFileHeader::hdrIsNiftiFile(fileNameIn); if (DebugControl::getDebugOn()) { std::cout << "HDR file is a NIFTI header file." << std::endl; } } FILE_READ_WRITE_TYPE fileTypeToWrite = FILE_READ_WRITE_TYPE_NIFTI; // // Note that SPM and Analyze are the same file type // if (StringUtilities::endsWith(fileNameIn, SpecFile::getAnalyzeVolumeFileExtension()) && (niftiFlag == false)) { readFileSpm(fileNameIn, readSelection, volumesReadOut, spmRightIsOnLeft); fileTypeToWrite = FILE_READ_WRITE_TYPE_SPM_OR_MEDX; } else if (StringUtilities::endsWith(fileNameIn, SpecFile::getAfniVolumeFileExtension())) { readFileAfni(fileNameIn, readSelection, volumesReadOut); fileTypeToWrite = FILE_READ_WRITE_TYPE_AFNI; } else if (StringUtilities::endsWith(fileNameIn, SpecFile::getMincVolumeFileExtension())) { VolumeFile* vf = new VolumeFile; try { vf->importMincVolume(fileNameIn); volumesReadOut.push_back(vf); } catch (FileException& e) { delete vf; vf = NULL; throw e; } fileTypeToWrite = FILE_READ_WRITE_TYPE_NIFTI; } else if (StringUtilities::endsWith(fileNameIn, SpecFile::getNiftiVolumeFileExtension()) || StringUtilities::endsWith(fileNameIn, SpecFile::getNiftiGzipVolumeFileExtension()) || niftiFlag) { readFileNifti(fileNameIn, readSelection, volumesReadOut); fileTypeToWrite = FILE_READ_WRITE_TYPE_NIFTI; } else if (StringUtilities::endsWith(fileNameIn, SpecFile::getWustlVolumeFileExtension())) { readFileWuNil(fileNameIn, readSelection, volumesReadOut); fileTypeToWrite = FILE_READ_WRITE_TYPE_WUNIL; } else if (StringUtilities::endsWith(fileNameIn, ".vtk")) { VolumeFile* vf = new VolumeFile; try { vf->importVtkStructuredPointsVolume(fileNameIn); volumesReadOut.push_back(vf); } catch (FileException& e) { delete vf; vf = NULL; throw e; } fileTypeToWrite = FILE_READ_WRITE_TYPE_NIFTI; } else { throw FileException(fileNameIn, "File extension not recognized as a volume\n" "file type supported by Caret."); } for (unsigned int i = 0; i < volumesReadOut.size(); i++) { switch (volumeSpace) { case VOLUME_SPACE_COORD_LPI: break; case VOLUME_SPACE_VOXEL_NATIVE: break; } volumesReadOut[i]->clearModified(); volumesReadOut[i]->setFileWriteType(fileTypeToWrite); } } /** * write the specified sub-volumes. */ void VolumeFile::writeFile(const QString& fileNameIn, const VOLUME_TYPE volumeType, const VOXEL_DATA_TYPE writeVoxelDataType, std::vector& volumesToWrite, const bool zipAfniBrikFile, const ColorFile* labelColorsForCaret6) throw (FileException) { QFile file(fileNameIn); if (AbstractFile::getOverwriteExistingFilesAllowed() == false) { if (file.exists()) { throw FileException("file exists and overwrite is prohibited."); } } if (volumesToWrite.size() == 0) { throw FileException(fileNameIn, "No volume data to write."); } switch (volumeType) { case VOLUME_TYPE_ANATOMY: break; case VOLUME_TYPE_FUNCTIONAL: break; case VOLUME_TYPE_PAINT: if (volumesToWrite.size() > 1) { synchronizeRegionNames(volumesToWrite); } break; case VOLUME_TYPE_PROB_ATLAS: break; case VOLUME_TYPE_RGB: break; case VOLUME_TYPE_SEGMENTATION: break; case VOLUME_TYPE_VECTOR: break; case VOLUME_TYPE_ROI: break; case VOLUME_TYPE_UNKNOWN: break; } // // Verify that the volumes have the same dimensions // int dim1[3]; volumesToWrite[0]->getDimensions(dim1); for (unsigned int i = 1; i < volumesToWrite.size(); i++) { int dim2[3]; volumesToWrite[i]->getDimensions(dim2); if ((dim1[0] != dim2[0]) || (dim1[1] != dim2[1]) || (dim1[2] != dim2[2])) { QString msg("All volumes written to a file must have the same dimensions.\n" "These volumes have different dimensions: "); msg += FileUtilities::basename(volumesToWrite[0]->getFileName()); msg += " and "; msg += FileUtilities::basename(volumesToWrite[i]->getFileName()); throw FileException(msg); } } // // Note that SPM and Analyze are the same file type // if (StringUtilities::endsWith(fileNameIn, SpecFile::getAnalyzeVolumeFileExtension())) { writeFileSPM(fileNameIn, writeVoxelDataType, volumesToWrite); } else if (StringUtilities::endsWith(fileNameIn, SpecFile::getAfniVolumeFileExtension())) { writeFileAfni(fileNameIn, writeVoxelDataType, volumesToWrite, zipAfniBrikFile); } else if (StringUtilities::endsWith(fileNameIn, SpecFile::getMincVolumeFileExtension())) { if (volumesToWrite.size() != 1) { throw FileException(fileNameIn, "Multi-volume MINC files not supported."); } VolumeFile* vf = volumesToWrite[0]; try { vf->exportMincVolume(fileNameIn); } catch (FileException& e) { delete vf; vf = NULL; throw e; } } else if (StringUtilities::endsWith(fileNameIn, SpecFile::getNiftiVolumeFileExtension()) || StringUtilities::endsWith(fileNameIn, SpecFile::getNiftiGzipVolumeFileExtension())) { writeFileNifti(fileNameIn, writeVoxelDataType, volumesToWrite, labelColorsForCaret6); } else if (StringUtilities::endsWith(fileNameIn, SpecFile::getWustlVolumeFileExtension())) { writeFileWuNil(fileNameIn, writeVoxelDataType, volumesToWrite); } else if (StringUtilities::endsWith(fileNameIn, ".vtk")) { if (volumesToWrite.size() != 1) { throw FileException(fileNameIn, "Multi-volume VTK files not supported."); } VolumeFile* vf = volumesToWrite[0]; try { vf->exportVtkStructuredPointsVolume(fileNameIn); } catch (FileException& e) { delete vf; vf = NULL; throw e; } } else { throw FileException(fileNameIn, "File extension not recognized as a volume\n" "file type supported by Caret."); } for (unsigned int i = 0; i < volumesToWrite.size(); i++) { volumesToWrite[i]->clearModified(); } } /** * read the specified sub-volumes in a volume file. */ void VolumeFile::readFileAfni(const QString& fileNameIn, const int readSelection, std::vector& volumesReadOut) throw (FileException) { QFile file(fileNameIn); if (file.open(QIODevice::ReadOnly) == false) { throw FileException(fileNameIn, file.errorString()); } QTextStream stream(&file); VolumeFile volumeRead; volumeRead.filename = fileNameIn; volumeRead.voxelDataType = VOXEL_DATA_TYPE_SHORT; AfniHeader* afniHeader = &(volumeRead.afniHeader); afniHeader->clear(); afniHeader->readHeader(volumeRead.filename, file, stream); // // Close the file // file.close(); QString errorMessage; // // Get Dataset rank first since it tells the number of subvolumes in 2nd value // const AfniAttribute* rankAttr = afniHeader->getAttribute(AfniAttribute::NAME_DATASET_RANK); if (rankAttr != NULL) { std::vector values; rankAttr->getValue(values); if (values.size() < 2) { errorMessage.append("Required attribute DATASET_RANK has fewer than 2 elements\n"); } else { volumeRead.initializeSubVolumes(values[1]); } } else { errorMessage.append("Required attribute DATASET_RANK not found\n"); } // // Get the dimensions of the volume // const AfniAttribute* dimAttr = afniHeader->getAttribute(AfniAttribute::NAME_DATASET_DIMENSIONS); if (dimAttr != NULL) { std::vector values; dimAttr->getValue(values); if (values.size() < 3) { errorMessage.append("Required attribute DATASET_DIMENSIONS has fewer than 3 elements\n"); } else { volumeRead.setDimensions(&values[0]); } } else { errorMessage.append("Required attribute DATASET_DIMENSIONS not found\n"); } // // Get the spacing of the volume // const AfniAttribute* spaceAttr = afniHeader->getAttribute(AfniAttribute::NAME_DELTA); if (spaceAttr != NULL) { std::vector values; spaceAttr->getValue(values); if (values.size() < 3) { errorMessage.append("Required attribute DELTA has fewer than 3 elements\n"); } else { volumeRead.setSpacing(&values[0]); } } else { errorMessage.append("Required attribute DELTA not found\n"); } // // Get the orientation of the volume // const AfniAttribute* orientAttr = afniHeader->getAttribute(AfniAttribute::NAME_ORIENT_SPECIFIC); if (orientAttr != NULL) { std::vector values; orientAttr->getValue(values); if (values.size() < 3) { errorMessage.append("Required attribute ORIENT_SPECIFIC has fewer than 3 elements\n"); } else { ORIENTATION orientation[3] = { ORIENTATION_UNKNOWN, ORIENTATION_UNKNOWN, ORIENTATION_UNKNOWN }; for (int j = 0; j < 3; j++) { switch(values[j]) { case 0: orientation[j] = ORIENTATION_RIGHT_TO_LEFT; break; case 1: orientation[j] = ORIENTATION_LEFT_TO_RIGHT; break; case 2: orientation[j] = ORIENTATION_POSTERIOR_TO_ANTERIOR; break; case 3: orientation[j] = ORIENTATION_ANTERIOR_TO_POSTERIOR; break; case 4: orientation[j] = ORIENTATION_INFERIOR_TO_SUPERIOR; break; case 5: orientation[j] = ORIENTATION_SUPERIOR_TO_INFERIOR; break; default: { std::ostringstream str; str << "Unrecognized orientation value: " << values[j]; errorMessage.append(str.str().c_str()); errorMessage.append("\n"); } } } volumeRead.setOrientation(orientation); } } else { errorMessage.append("Required attribute ORIENT_SPECIFIC not found\n"); } // // Get the origin of the volume // const AfniAttribute* originAttr = afniHeader->getAttribute(AfniAttribute::NAME_ORIGIN); if (originAttr != NULL) { std::vector values; originAttr->getValue(values); if (values.size() < 3) { errorMessage.append("Required attribute ORIGIN has fewer than 3 elements\n"); } else { float origin[3] = { 0.0, 0.0, 0.0 }; int dimensions[3]; volumeRead.getDimensions(dimensions); float spacing[3]; volumeRead.getSpacing(spacing); // // NOTE: AFNI uses DICOM style where right, anterior, and inferior are negative. // In addition, AFNI's specifies the origin using the center of the voxel. // // ORIENTATION ORIGIN DELTA // R->L (0) - + // L->R (1) + - // P->A (2) + - // A->P (3) - + // I->S (4) - + // S->I (5) + - // for (int i = 0; i < 3; i++) { switch(volumeRead.orientation[i]) { case ORIENTATION_UNKNOWN: break; case ORIENTATION_RIGHT_TO_LEFT: spacing[i] = -fabs(spacing[i]); origin[i] = fabs(values[i]); // + (fabs(spacing[i]) * 0.5); break; case ORIENTATION_LEFT_TO_RIGHT: spacing[i] = fabs(spacing[i]); origin[i] = -fabs(values[i]); // - (fabs(spacing[i]) * 0.5); break; case ORIENTATION_POSTERIOR_TO_ANTERIOR: spacing[i] = fabs(spacing[i]); origin[i] = -fabs(values[i]); // - (fabs(spacing[i]) * 0.5); break; case ORIENTATION_ANTERIOR_TO_POSTERIOR: spacing[i] = -fabs(spacing[i]); origin[i] = fabs(values[i]); // + (fabs(spacing[i]) * 0.5); break; case ORIENTATION_INFERIOR_TO_SUPERIOR: spacing[i] = fabs(spacing[i]); origin[i] = -fabs(values[i]); // - (fabs(spacing[i]) * 0.5); break; case ORIENTATION_SUPERIOR_TO_INFERIOR: spacing[i] = -fabs(spacing[i]); origin[i] = fabs(values[i]); // + (fabs(spacing[i]) * 0.5); break; } } volumeRead.setOrigin(origin); volumeRead.setSpacing(spacing); } } else { errorMessage.append("Required attribute ORIGIN not found\n"); } // // AFNI data type is optional and the default is short // volumeRead.voxelDataType = VOXEL_DATA_TYPE_SHORT; // // Get the data type of the volume's voxels // const AfniAttribute* typesAttr = afniHeader->getAttribute(AfniAttribute::NAME_BRICK_TYPES); if (typesAttr != NULL) { std::vector values; typesAttr->getValue(values); if (values.size() < 1) { errorMessage.append("Required attribute BRICK_TYPES has fewer than 1 elements\n"); } else { switch(values[0]) { case 0: volumeRead.voxelDataType = VOXEL_DATA_TYPE_CHAR_UNSIGNED; break; case 1: volumeRead.voxelDataType = VOXEL_DATA_TYPE_SHORT; break; case 2: volumeRead.voxelDataType = VOXEL_DATA_TYPE_INT; break; case 3: volumeRead.voxelDataType = VOXEL_DATA_TYPE_FLOAT; break; case 4: volumeRead.voxelDataType = VOXEL_DATA_TYPE_DOUBLE; break; case 5: errorMessage.append("Complex AFNI data type not supported\n"); break; case 6: volumeRead.voxelDataType = VOXEL_DATA_TYPE_RGB_VOXEL_INTERLEAVED; break; case 7: errorMessage.append("RGBA AFNI data type not supported\n"); break; default: { std::ostringstream str; str << "Unrecognized AFNI data type: " << values[0]; errorMessage.append(str.str().c_str()); errorMessage.append("\n"); } break; } } } else { errorMessage.append("Required attribute BRICK_TYPES not found\n"); } // // If error message is not isEmpty something required is missing from the volume // if (errorMessage.isEmpty() == false) { throw FileException(FileUtilities::basename(volumeRead.filename), errorMessage); } // // Get the sccale factors of the volume // const AfniAttribute* scaleAttr = afniHeader->getAttribute(AfniAttribute::NAME_BRICK_FLOAT_FACS); if (scaleAttr != NULL) { std::vector values; scaleAttr->getValue(values); for (int i = 0; i < volumeRead.numberOfSubVolumes; i++) { if (i < static_cast(values.size())) { volumeRead.scaleSlope[i] = values[i]; if (volumeRead.scaleSlope[i] == 0.0) { volumeRead.scaleSlope[i] = 1.0; } } else { volumeRead.scaleSlope[i] = 1.0; } } } // // QT will tell us if the "endian" for this computer // //int wordSize; bool bigEndian = (QSysInfo::ByteOrder == QSysInfo::BigEndian); //qSysInfo(&wordSize, &bigEndian); // // Get the byte order // const AfniAttribute* byteAttr = afniHeader->getAttribute(AfniAttribute::NAME_BYTEORDER_STRING); bool byteSwapFlag = false; if (byteAttr != NULL) { if (byteAttr->getValue() == "MSB_FIRST") { if (bigEndian == false) { byteSwapFlag = true; } } else { if (bigEndian) { byteSwapFlag = true; } } } // // Get the subvolume names // const AfniAttribute* nameAttr = afniHeader->getAttribute(AfniAttribute::NAME_BRICK_LABS); if (nameAttr != NULL) { std::vector names; StringUtilities::token(nameAttr->getValue(), "~", names); const unsigned int minNames = std::min(names.size(), volumeRead.subVolumeNames.size()); for (unsigned int i = 0; i < minNames; i++) { volumeRead.subVolumeNames[i] = names[i]; } } // // Get the HISTORY_NOTE and use it as a comment // const AfniAttribute* commentAttr = afniHeader->getAttribute(AfniAttribute::NAME_HISTORY_NOTE); if (commentAttr != NULL) { volumeRead.setHeaderTag(headerTagComment, commentAttr->getValue()); } // // Get the region names (for paint volume) // const AfniAttribute* regionAttr = afniHeader->getAttribute(AfniAttribute::NAME_LUT_NAMES); if (regionAttr != NULL) { volumeRead.regionNames.clear(); StringUtilities::token(regionAttr->getValue(), "~", volumeRead.regionNames); } // // Get the study meta data // std::vector studyMetaDataLinkSets; const AfniAttribute* studyMetaDataAttr = afniHeader->getAttribute(AfniAttribute::NAME_CARET_METADATA_LINK); if (studyMetaDataAttr != NULL) { std::vector md; StringUtilities::token(studyMetaDataAttr->getValue(), "~", md); for (unsigned int i = 0; i < md.size(); i++) { StudyMetaDataLinkSet smdls; smdls.setLinkSetFromCodedText(md[i]); studyMetaDataLinkSets.push_back(smdls); } } // // Set the PubMed ID // const AfniAttribute* pubMedIDAttr = afniHeader->getAttribute(AfniAttribute::NAME_CARET_PUBMED_ID); if (pubMedIDAttr != NULL) { volumeRead.setFilePubMedID(pubMedIDAttr->getValue()); } // // Default data file name // volumeRead.dataFileName = FileUtilities::filenameWithoutExtension(volumeRead.filename); volumeRead.dataFileName.append(".BRIK"); // // When an Analyze volume is converted to an AFNI volume with "to3d", just // the AFNI header is created with the attribute VOLUME_FILENAMES containing // the name of the Analyze volume data. // const AfniAttribute* volumeFileName = afniHeader->getAttribute(AfniAttribute::NAME_VOLUME_FILENAMES); if (volumeFileName != NULL) { volumeRead.dataFileName = FileUtilities::dirname(volumeRead.filename); volumeRead.dataFileName.append("/"); volumeRead.dataFileName.append(volumeFileName->getValue()); } // // Data file might be gzipped // if (QFile::exists(volumeRead.dataFileName) == false) { QString zipName(volumeRead.dataFileName); zipName.append(".gz"); if (QFile::exists(zipName)) { volumeRead.dataFileName = zipName; } } // // Keep track of data files zipped status // volumeRead.dataFileWasZippedFlag = (volumeRead.dataFileName.right(3) == ".gz"); // // If only reading header // if (readSelection == -2) { VolumeFile* vf = new VolumeFile; vf->copyVolumeData(volumeRead, false); vf->filename = volumeRead.filename; vf->dataFileName = volumeRead.dataFileName; if (studyMetaDataLinkSets.empty() == false) { vf->setStudyMetaDataLinkSet(studyMetaDataLinkSets[0]); } volumesReadOut.push_back(vf); return; } // // Open the data file // gzFile dataFile = gzopen(volumeRead.dataFileName.toAscii().constData(), "rb"); if (dataFile == NULL) { QString msg("Unable to open data file: "); msg.append(volumeRead.dataFileName); throw FileException(fileNameIn, msg); } try { // // loop through and read the volume files // const int numSubs = volumeRead.subVolumeNames.size(); for (int i = 0; i < numSubs; i++) { // // Determine if this sub volume should be read // bool readingSingleSubVolume = false; bool readIt = false; if (readSelection == VOLUME_READ_SELECTION_ALL) { readIt = true; } else if (readSelection == i) { readIt = true; readingSingleSubVolume = true; } if (readIt) { // // copy everything but voxel data from the first volume // VolumeFile* vf = NULL; vf = new VolumeFile; vf->copyVolumeData(volumeRead, false); vf->filename = volumeRead.filename; vf->dataFileName = volumeRead.dataFileName; // // Set the descriptive label // vf->descriptiveLabel = volumeRead.subVolumeNames[i]; // // If only reading a single sub-volume // if (readingSingleSubVolume) { // // Read just the sub-volume // vf->readVolumeFileDataSubVolume(byteSwapFlag, vf->scaleSlope[i], vf->scaleOffset[i], 0, i, dataFile); } else { // // Read just the sub-volume // vf->readVolumeFileData(byteSwapFlag, vf->scaleSlope[i], vf->scaleOffset[i], dataFile); } if (i < static_cast(studyMetaDataLinkSets.size())) { vf->setStudyMetaDataLinkSet(studyMetaDataLinkSets[i]); } // // return the volume to the user // volumesReadOut.push_back(vf); // // If only reading a single sub-volume // if (readingSingleSubVolume) { break; } } } } catch (FileException& e) { gzclose(dataFile); throw e; } // // Close the file // gzclose(dataFile); } /** * read the specified sub-volumes in a volume file. */ void VolumeFile::readFileAnalyze(const QString& fileNameIn, const int readSelection, std::vector& volumesReadOut, const bool spmFlag) throw (FileException) { // // Open the data file // QFile file(fileNameIn); if (file.open(QIODevice::ReadOnly) == false) { throw FileException(fileNameIn, file.errorString()); } // // Read the header file // struct dsr hdr; const unsigned long headerSize = sizeof(hdr); const unsigned long numBytesRead = file.read((char*)&hdr, headerSize); if (numBytesRead != headerSize) { std::ostringstream str; str << "Tried to read " << headerSize << " bytes from header.\n" << "Only read " << numBytesRead << "."; throw FileException(fileNameIn, str.str().c_str()); } // // Close the file // file.close(); short spmAcShort[5] = { 0, 0, 0, 0, 0 }; if (spmFlag) { // // Need to use memcpy since "hdr.hist.originator" is on odd byte boundary // memcpy(spmAcShort, hdr.hist.originator, 10); } // // Volume file for reading header // VolumeFile volumeRead; volumeRead.filename = fileNameIn; // // See if data needs to be byteswapped // bool byteSwapFlag= false; if ((hdr.dime.dim[0] < 0) || (hdr.dime.dim[0] > 15)) { byteSwapFlag = true; ByteSwapping::swapBytes(&hdr.hk.sizeof_hdr, 1); ByteSwapping::swapBytes(&hdr.hk.extents, 1); ByteSwapping::swapBytes(&hdr.hk.session_error, 1); ByteSwapping::swapBytes(hdr.dime.dim, 8); ByteSwapping::swapBytes(&hdr.dime.unused8, 1); ByteSwapping::swapBytes(&hdr.dime.unused9, 1); ByteSwapping::swapBytes(&hdr.dime.unused10, 1); ByteSwapping::swapBytes(&hdr.dime.unused11, 1); ByteSwapping::swapBytes(&hdr.dime.unused12, 1); ByteSwapping::swapBytes(&hdr.dime.unused13, 1); ByteSwapping::swapBytes(&hdr.dime.unused14, 1); ByteSwapping::swapBytes(&hdr.dime.datatype, 1); ByteSwapping::swapBytes(&hdr.dime.bitpix, 1); ByteSwapping::swapBytes(&hdr.dime.dim_un0, 1); ByteSwapping::swapBytes(hdr.dime.pixdim, 8); ByteSwapping::swapBytes(&hdr.dime.vox_offset, 1); ByteSwapping::swapBytes(&hdr.dime.funused1, 1); ByteSwapping::swapBytes(&hdr.dime.funused2, 1); ByteSwapping::swapBytes(&hdr.dime.funused3, 1); ByteSwapping::swapBytes(&hdr.dime.cal_max, 1); ByteSwapping::swapBytes(&hdr.dime.cal_min, 1); ByteSwapping::swapBytes(&hdr.dime.compressed, 1); ByteSwapping::swapBytes(&hdr.dime.verified, 1); ByteSwapping::swapBytes(&hdr.dime.glmax, 1); ByteSwapping::swapBytes(&hdr.dime.glmin, 1); ByteSwapping::swapBytes(&hdr.hist.views, 1); ByteSwapping::swapBytes(&hdr.hist.vols_added, 1); ByteSwapping::swapBytes(&hdr.hist.start_field, 1); ByteSwapping::swapBytes(&hdr.hist.field_skip, 1); ByteSwapping::swapBytes(&hdr.hist.omax, 1); ByteSwapping::swapBytes(&hdr.hist.omin, 1); ByteSwapping::swapBytes(&hdr.hist.smax, 1); ByteSwapping::swapBytes(&hdr.hist.smin, 1); ByteSwapping::swapBytes(spmAcShort, 5); } // // Create the volume data file name // volumeRead.dataFileName = FileUtilities::filenameWithoutExtension(volumeRead.filename); volumeRead.dataFileName.append(".img"); if ((hdr.dime.dim[0] > 0) && (hdr.dime.dim[1] > 0) && (hdr.dime.dim[2] > 0) && (hdr.dime.dim[3] > 0)) { int dimensions[3]; dimensions[0] = hdr.dime.dim[1]; dimensions[1] = hdr.dime.dim[2]; dimensions[2] = hdr.dime.dim[3]; volumeRead.setDimensions(dimensions); } int numSubVols = 1; if (hdr.dime.dim[0] >= 4) { numSubVols = hdr.dime.dim[4]; } volumeRead.initializeSubVolumes(numSubVols); switch(hdr.dime.datatype) { case ANDT_UNKNOWN: throw FileException(FileUtilities::basename(volumeRead.filename), "Analyze unknown data type not supported."); break; case ANDT_BINARY: throw FileException(FileUtilities::basename(volumeRead.filename), "Analyze binary data type not supported."); break; case ANDT_UNSIGNED_CHAR: volumeRead.voxelDataType = VOXEL_DATA_TYPE_CHAR_UNSIGNED; break; case ANDT_SIGNED_SHORT: volumeRead.voxelDataType = VOXEL_DATA_TYPE_SHORT; break; case ANDT_SIGNED_INT: volumeRead.voxelDataType = VOXEL_DATA_TYPE_INT; break; case ANDT_FLOAT: volumeRead.voxelDataType = VOXEL_DATA_TYPE_FLOAT; break; case ANDT_COMPLEX: throw FileException(FileUtilities::basename(volumeRead.filename), "Analyze complex data type not supported."); break; case ANDT_DOUBLE: volumeRead.voxelDataType = VOXEL_DATA_TYPE_DOUBLE; break; case ANDT_RGB: volumeRead.voxelDataType = VOXEL_DATA_TYPE_RGB_SLICE_INTERLEAVED; break; default: throw FileException(FileUtilities::basename(volumeRead.filename), "Analyze data type is unknown value."); break; } // // Comment info // char comm[80]; for (int m = 0; m < 79; m++) { comm[m] = hdr.hist.descrip[m]; } comm[79] = '\0'; volumeRead.setHeaderTag(headerTagComment, comm); float spacing[3]; spacing[0] = hdr.dime.pixdim[1]; spacing[1] = hdr.dime.pixdim[2]; spacing[2] = hdr.dime.pixdim[3]; volumeRead.setSpacing(spacing); if (spmFlag) { volumeRead.spmAcPosition[0] = spmAcShort[0] - 1; volumeRead.spmAcPosition[1] = spmAcShort[1] - 1; volumeRead.spmAcPosition[2] = spmAcShort[2] - 1; if (hdr.dime.funused1 > 0.0) { for (int i = 0; i < volumeRead.numberOfSubVolumes; i++) { if (i < static_cast(volumeRead.scaleSlope.size())) { volumeRead.scaleSlope[i] = hdr.dime.funused1; if (volumeRead.scaleSlope[i] == 0.0) { volumeRead.scaleSlope[i] = 1.0; } } } } float origin[3]; origin[0] = -volumeRead.spmAcPosition[0] * spacing[0]; origin[1] = -volumeRead.spmAcPosition[1] * spacing[1]; origin[2] = -volumeRead.spmAcPosition[2] * spacing[2]; volumeRead.setOrigin(origin); // // SPM or MEDx always LPI orientation // volumeRead.orientation[0] = ORIENTATION_LEFT_TO_RIGHT; volumeRead.orientation[1] = ORIENTATION_POSTERIOR_TO_ANTERIOR; volumeRead.orientation[2] = ORIENTATION_INFERIOR_TO_SUPERIOR; if (DebugControl::getDebugOn()) { cout << "Spm Voxel Size: " << volumeRead.spacing[0] << " " << volumeRead.spacing[1] << " " << volumeRead.spacing[2] << endl; cout << "Spm AC Position: " << volumeRead.spmAcPosition[0] << " " << volumeRead.spmAcPosition[1] << " " << volumeRead.spmAcPosition[2] << endl; cout << "Spm Scaling: " << volumeRead.scaleSlope[0] << endl; } } // // Data file might be gzipped // if (QFile::exists(volumeRead.dataFileName) == false) { QString zipName(volumeRead.dataFileName); zipName.append(".gz"); if (QFile::exists(zipName)) { volumeRead.dataFileName = zipName; } } // // If only reading header // if (readSelection == -2) { VolumeFile* vf = new VolumeFile; vf->copyVolumeData(volumeRead, false); vf->filename = volumeRead.filename; vf->dataFileName = volumeRead.dataFileName; volumesReadOut.push_back(vf); return; } // // Open the data file // gzFile dataFile = gzopen(volumeRead.dataFileName.toAscii().constData(), "rb"); if (dataFile == NULL) { QString msg("Unable to open data file: "); msg.append(volumeRead.dataFileName); throw FileException(fileNameIn, msg); } try { // // loop through and read the volume files // const int numSubs = volumeRead.subVolumeNames.size(); for (int i = 0; i < numSubs; i++) { // // Determine if this sub volume should be read // bool readingSingleSubVolume = false; bool readIt = false; if (readSelection == VOLUME_READ_SELECTION_ALL) { readIt = true; } else if (readSelection == i) { readIt = true; readingSingleSubVolume = true; } if (readIt) { // // copy everything but voxel data from the first volume // VolumeFile* vf = NULL; vf = new VolumeFile; vf->copyVolumeData(volumeRead, false); vf->filename = volumeRead.filename; vf->dataFileName = volumeRead.dataFileName; // // Set the descriptive label // vf->descriptiveLabel = volumeRead.subVolumeNames[i]; // // If only reading a single sub-volume // if (readingSingleSubVolume) { // // Read just the sub-volume // vf->readVolumeFileDataSubVolume(byteSwapFlag, vf->scaleSlope[i], vf->scaleOffset[i], 0, i, dataFile); } else { // // Read just the sub-volume // vf->readVolumeFileData(byteSwapFlag, vf->scaleSlope[i], vf->scaleOffset[i], dataFile); } // // return the volume to the user // volumesReadOut.push_back(vf); // // If only reading a single sub-volume // if (readingSingleSubVolume) { break; } } } } catch (FileException& e) { gzclose(dataFile); throw e; } // // Close the file // gzclose(dataFile); } /** * read the specified sub-volumes in a volume file. */ void VolumeFile::readFileNifti(const QString& fileNameIn, const int readSelection, std::vector& volumesReadOut) throw (FileException) { // // Open the file // VolumeFile volumeRead; volumeRead.filename = fileNameIn; gzFile dataFile = gzopen(fileNameIn.toAscii().constData(), "rb"); if (dataFile == NULL) { throw FileException(fileNameIn, "Unable to open with ZLIB for reading."); } // // The NIFTI header // NiftiFileHeader niftiFileHeader; niftiFileHeader.readHeader(dataFile, volumeRead.filename); nifti_1_header hdr = niftiFileHeader.getNiftiHeaderStruct(); volumeRead.niftiSFormTransformationMatrix = niftiFileHeader.getSFormTransformationMatrix(); volumeRead.niftiQFormTransformationMatrix = niftiFileHeader.getQFormTransformationMatrix(); // // Do bytes need to be swapped ? // bool byteSwapFlag = niftiFileHeader.doesDataNeedByteSwapping(); // // Offset of data // const long niftiReadDataOffset = static_cast(hdr.vox_offset); // // Get volume dimensions // if (hdr.dim[0] < 3) { gzclose(dataFile); throw FileException(volumeRead.filename, "has less than 3 dimensions."); } volumeRead.dimensions[0] = hdr.dim[1]; volumeRead.dimensions[1] = hdr.dim[2]; volumeRead.dimensions[2] = hdr.dim[3]; // // Multiple volumes in file ? // int numSubVols = 1; if (hdr.dim[0] > 3) { // // 4 dim volume is time series // if (hdr.dim[0] == 4) { numSubVols = hdr.dim[4]; } else if (hdr.dim[0] == 5) { // // IF 5 dimensions and dim[4] = 1, then multiple values (subvolumes) per voxel // if (hdr.dim[4] == 1) { // // We'll consider RGB's to be a single volume // if ((hdr.dim[5] == 3) && (hdr.datatype == NIFTI_TYPE_RGB24)) { hdr.dim[5] = 1; } if ((hdr.dim[5] == 3) && (hdr.intent_code == NIFTI_INTENT_VECTOR)) { volumeRead.volumeType = VOLUME_TYPE_VECTOR; } numSubVols = hdr.dim[5]; } else if (hdr.dim[4] > 1) { if (hdr.dim[5] > 1) { throw FileException(volumeRead.filename, "Multiple values per timepoint not supported."); } numSubVols = hdr.dim[4]; } } else { throw FileException(volumeRead.filename, "Dimensions greater than 5 not supported."); } } volumeRead.initializeSubVolumes(numSubVols); // // Set the data type // switch (hdr.datatype) { case NIFTI_TYPE_UINT8: volumeRead.voxelDataType = VOXEL_DATA_TYPE_CHAR_UNSIGNED; break; case NIFTI_TYPE_INT8: volumeRead.voxelDataType = VOXEL_DATA_TYPE_CHAR; break; case NIFTI_TYPE_INT16: volumeRead.voxelDataType = VOXEL_DATA_TYPE_SHORT; break; case NIFTI_TYPE_UINT16: volumeRead.voxelDataType = VOXEL_DATA_TYPE_SHORT_UNSIGNED; break; case NIFTI_TYPE_INT32: volumeRead.voxelDataType = VOXEL_DATA_TYPE_INT; break; case NIFTI_TYPE_UINT32: volumeRead.voxelDataType = VOXEL_DATA_TYPE_INT_UNSIGNED; break; case NIFTI_TYPE_INT64: if (sizeof(long long) == 8) { volumeRead.voxelDataType = VOXEL_DATA_TYPE_LONG; } else { throw FileException("Volume contains 64-bit long long data type which " "this computer does not support."); } break; case NIFTI_TYPE_UINT64: if (sizeof(unsigned long long) == 8) { volumeRead.voxelDataType = VOXEL_DATA_TYPE_LONG_UNSIGNED; } else { throw FileException("Volume contains 64-bit unsigned long long data type which " "this computer does not support."); } break; case NIFTI_TYPE_FLOAT32: volumeRead.voxelDataType = VOXEL_DATA_TYPE_FLOAT; break; case NIFTI_TYPE_FLOAT64: volumeRead.voxelDataType = VOXEL_DATA_TYPE_DOUBLE; break; case NIFTI_TYPE_FLOAT128: gzclose(dataFile); throw FileException(volumeRead.filename, "FLOAT 128 type not supported."); break; case NIFTI_TYPE_RGB24: volumeRead.voxelDataType = VOXEL_DATA_TYPE_RGB_SLICE_INTERLEAVED; break; case NIFTI_TYPE_COMPLEX64: gzclose(dataFile); throw FileException(volumeRead.filename, "COMPLEX 64 type not supported."); break; case NIFTI_TYPE_COMPLEX128: gzclose(dataFile); throw FileException(volumeRead.filename, "COMPLEX 128 type not supported."); break; case NIFTI_TYPE_COMPLEX256: gzclose(dataFile); throw FileException(volumeRead.filename, "COMPLEX 256 type not supported."); break; default: { gzclose(dataFile); std::ostringstream str; str << "datatype number " << hdr.datatype << " is unknown."; throw FileException(volumeRead.filename, str.str().c_str()); } break; } // // Comment info // char comm[80]; for (int m = 0; m < 79; m++) { comm[m] = hdr.descrip[m]; } comm[79] = '\0'; volumeRead.setHeaderTag(headerTagComment, comm); // // Spacing // volumeRead.spacing[0] = hdr.pixdim[1]; volumeRead.spacing[1] = hdr.pixdim[2]; volumeRead.spacing[2] = hdr.pixdim[3]; // // default origin // volumeRead.origin[0] = 0.0; volumeRead.origin[1] = 0.0; volumeRead.origin[2] = 0.0; // // Default orientation // volumeRead.orientation[0] = ORIENTATION_UNKNOWN; volumeRead.orientation[1] = ORIENTATION_UNKNOWN; volumeRead.orientation[2] = ORIENTATION_UNKNOWN; for (int i = 0; i < numSubVols; i++) { volumeRead.scaleOffset[i] = hdr.scl_inter; volumeRead.scaleSlope[i] = hdr.scl_slope; } /* TransformationMatrix qformTM; bool qformTMValid = false; ORIENTATION qformOrientation[3] = { ORIENTATION_UNKNOWN, ORIENTATION_UNKNOWN, ORIENTATION_UNKNOWN }; */ // // Convert units to MilliMeters // float spacingScale = 1.0; switch (hdr.xyzt_units) { case NIFTI_UNITS_METER: spacingScale = 1000.0; break; case NIFTI_UNITS_MM: spacingScale = 1.0; break; case NIFTI_UNITS_MICRON: spacingScale = 0.001; break; } hdr.qoffset_x *= spacingScale; hdr.qoffset_y *= spacingScale; hdr.qoffset_z *= spacingScale; hdr.pixdim[1] *= spacingScale; hdr.pixdim[2] *= spacingScale; hdr.pixdim[3] *= spacingScale; // // sform_code take priority over qform_code // if (hdr.sform_code > 0) { // // Get coordinates of voxels // int ijk0[3] = { 0, 0, 0 }; int ijk1[3] = { 1, 1, 1 }; float xyz0[3], xyz1[3]; niftiFileHeader.getVoxelCoordinate(ijk0, NiftiFileHeader::STEREOTAXIC_TYPE_SFORM, xyz0); niftiFileHeader.getVoxelCoordinate(ijk1, NiftiFileHeader::STEREOTAXIC_TYPE_SFORM, xyz1); volumeRead.origin[0] = xyz0[0] * spacingScale; volumeRead.origin[1] = xyz0[1] * spacingScale; volumeRead.origin[2] = xyz0[2] * spacingScale; volumeRead.spacing[0] = (xyz1[0] - xyz0[0]) * spacingScale; volumeRead.spacing[1] = (xyz1[1] - xyz0[1]) * spacingScale; volumeRead.spacing[2] = (xyz1[2] - xyz0[2]) * spacingScale; niftiFileHeader.getSFormOrientation(volumeRead.orientation); } else if (hdr.qform_code > 0) { // // Get coordinates of voxels // int ijk0[3] = { 0, 0, 0 }; int ijk1[3] = { 1, 1, 1 }; float xyz0[3], xyz1[3]; niftiFileHeader.getVoxelCoordinate(ijk0, NiftiFileHeader::STEREOTAXIC_TYPE_QFORM, xyz0); niftiFileHeader.getVoxelCoordinate(ijk1, NiftiFileHeader::STEREOTAXIC_TYPE_QFORM, xyz1); volumeRead.origin[0] = xyz0[0] * spacingScale; volumeRead.origin[1] = xyz0[1] * spacingScale; volumeRead.origin[2] = xyz0[2] * spacingScale; volumeRead.spacing[0] = (xyz1[0] - xyz0[0]) * spacingScale; volumeRead.spacing[1] = (xyz1[1] - xyz0[1]) * spacingScale; volumeRead.spacing[2] = (xyz1[2] - xyz0[2]) * spacingScale; niftiFileHeader.getQFormOrientation(volumeRead.orientation); } else { // // Get coordinates of voxels // int ijk0[3] = { 0, 0, 0 }; int ijk1[3] = { 1, 1, 1 }; float xyz0[3], xyz1[3]; niftiFileHeader.getVoxelCoordinate(ijk0, NiftiFileHeader::STEREOTAXIC_TYPE_NONE, xyz0); niftiFileHeader.getVoxelCoordinate(ijk1, NiftiFileHeader::STEREOTAXIC_TYPE_NONE, xyz1); volumeRead.origin[0] = xyz0[0] * spacingScale; volumeRead.origin[1] = xyz0[1] * spacingScale; volumeRead.origin[2] = xyz0[2] * spacingScale; volumeRead.spacing[0] = (xyz1[0] - xyz0[0]) * spacingScale; volumeRead.spacing[1] = (xyz1[1] - xyz0[1]) * spacingScale; volumeRead.spacing[2] = (xyz1[2] - xyz0[2]) * spacingScale; niftiFileHeader.getQFormOrientation(volumeRead.orientation); } /* // // The origin and spacing are always ordered L/R, P/A, I/S in NIFTI even if // the data is in a different order such as AIL. So, swap some values to // that they are correct for Caret. // float originTemp[3] = { volumeRead.origin[0], volumeRead.origin[1], volumeRead.origin[2] }; float spacingTemp[3] = { volumeRead.spacing[0], volumeRead.spacing[1], volumeRead.spacing[2] }; for (int i = 0; i < 3; i++) { int orientIndex = i; switch (volumeRead.orientation[i]) { case ORIENTATION_UNKNOWN: break; case ORIENTATION_RIGHT_TO_LEFT: case ORIENTATION_LEFT_TO_RIGHT: orientIndex = 0; break; case ORIENTATION_POSTERIOR_TO_ANTERIOR: case ORIENTATION_ANTERIOR_TO_POSTERIOR: orientIndex = 1; break; case ORIENTATION_INFERIOR_TO_SUPERIOR: case ORIENTATION_SUPERIOR_TO_INFERIOR: orientIndex = 2; break; } volumeRead.origin[i] = originTemp[orientIndex]; volumeRead.spacing[i] = spacingTemp[orientIndex]; } */ // // Check the intent code // volumeRead.volumeType = VOLUME_TYPE_UNKNOWN; switch (hdr.intent_code) { case NIFTI_INTENT_LABEL: volumeRead.volumeType = VOLUME_TYPE_PAINT; break; case NIFTI_INTENT_VECTOR: if (hdr.dim[5] == 3) { volumeRead.volumeType = VOLUME_TYPE_VECTOR; } break; } // // Storage for study meta data links // std::vector studyMetaDataLinkSets; // // Intention string and TR // niftiFileHeader.getNiftiIntentionInformation(volumeRead.niftiIntentCodeAndParamString, volumeRead.niftiIntentName); volumeRead.niftiIntentCode = hdr.intent_code; volumeRead.niftiIntentParameter1 = hdr.intent_p1; volumeRead.niftiIntentParameter2 = hdr.intent_p2; volumeRead.niftiIntentParameter3 = hdr.intent_p3; volumeRead.niftiTR = hdr.slice_duration; QString caretExtensionString = ""; // // Read the extender // if (hdr.vox_offset >= 352) { nifti1_extender extender; const unsigned long extLength = sizeof(extender); const unsigned long numBytesRead = gzread(dataFile, (voidp)&extender, extLength); if (extLength == numBytesRead) { if (DebugControl::getDebugOn()) { std::cout << "NIFTI extension[0] " << static_cast(extender.extension[0]) << std::endl; } } int extCount = 1; z_off_t pos = gztell(dataFile); while (pos < hdr.vox_offset) { // // Read in the extension size and code // int extensionSize, extensionCode; if ((gzread(dataFile, (voidp)&extensionSize, sizeof(extensionSize)) != 4) || (gzread(dataFile, (voidp)&extensionCode, sizeof(extensionCode)) != 4)) { std::cout << "WARNING: " << volumeRead.filename.toAscii().constData() << std::endl << "Problem reading extension " << extCount << ". This and all other extensions ignored." << std::endl; break; } else { if (byteSwapFlag) { ByteSwapping::swapBytes(&extensionSize, 1); ByteSwapping::swapBytes(&extensionCode, 1); } if (DebugControl::getDebugOn()) { std::cout << "Extension Size: " << extensionSize << std::endl; std::cout << "Extension Code: " << extensionCode << std::endl; } // // Check the code // const int evenNum = (extensionCode / 2) * 2; if ((evenNum < 0) || (evenNum > 100)) { std::cout << "WARNING: " << volumeRead.filename.toAscii().constData() << std::endl << "Invalid extension code " << extensionCode << " for extension " << extCount << ". This and all other extensions ignored." << std::endl; break; } // // Check extension size // if ((extensionSize % 16) != 0) { std::cout << "WARNING: NIFTI extension (code " << extensionCode << ") has size that is not a multiple of 16." << std::endl; } // // The 8-byte extension size/code is included in extensionSize // const int dataSize = extensionSize - 8; if (dataSize > 0) { char* data = new char[dataSize + 1]; if (gzread(dataFile, (voidp)data, dataSize) != dataSize) { std::cout << "WARNING: " << volumeRead.filename.toAscii().constData() << std::endl << "Problem reading extension " << extCount << " data. This and all other extensions ignored." << std::endl; break; } data[dataSize] = '\0'; // // Is this the AFNI extension // if (extensionCode == 4) { // NIFTI_ECODE_AFNI) { if (DebugControl::getDebugOn()) { std::cout << "AFNI extension: " << data << std::endl; } // // Process the NIFTI extension // try { volumeRead.afniHeader.readFromNiftiExtension(QString(data)); } catch (FileException& e) { throw FileException(volumeRead.filename, e.whatQString()); } // // Get the subvolume names // const AfniAttribute* nameAttr = volumeRead.afniHeader.getAttribute(AfniAttribute::NAME_BRICK_LABS); if (nameAttr != NULL) { std::vector names; StringUtilities::token(nameAttr->getValue(), "~", names); const unsigned int minNames = std::min(names.size(), volumeRead.subVolumeNames.size()); for (unsigned int i = 0; i < minNames; i++) { volumeRead.subVolumeNames[i] = names[i]; } } // // Get the HISTORY_NOTE and use it as a comment // const AfniAttribute* commentAttr = volumeRead.afniHeader.getAttribute(AfniAttribute::NAME_HISTORY_NOTE); if (commentAttr != NULL) { volumeRead.setHeaderTag(headerTagComment, commentAttr->getValue()); volumeRead.setFileComment(commentAttr->getValue()); } // // Get the region names (for paint volume) // const AfniAttribute* regionAttr = volumeRead.afniHeader.getAttribute(AfniAttribute::NAME_LUT_NAMES); if (regionAttr != NULL) { volumeRead.regionNames.clear(); StringUtilities::token(regionAttr->getValue(), "~", volumeRead.regionNames); } // // Get the study metadata links // const AfniAttribute* mdAttr = volumeRead.afniHeader.getAttribute(AfniAttribute::NAME_CARET_METADATA_LINK); if (mdAttr != NULL) { StudyMetaDataLinkSet smdls; std::vector md; StringUtilities::token(mdAttr->getValue(), "~", md); for (unsigned int m = 0; m < md.size(); m++) { smdls.setLinkSetFromCodedText(md[m]); studyMetaDataLinkSets.push_back(smdls); } } // // Get the PubMed ID // const AfniAttribute* pmidAttr = volumeRead.afniHeader.getAttribute(AfniAttribute::NAME_CARET_PUBMED_ID); if (pmidAttr != NULL) { volumeRead.setFilePubMedID(pmidAttr->getValue()); } } else if ((extensionCode == 30) || (extensionCode == 64)) { caretExtensionString = QString(data); } delete[] data; } } extCount++; pos = gztell(dataFile); } } // // Keep track of data files zipped status // volumeRead.dataFileWasZippedFlag = (volumeRead.filename.right(3) == ".gz"); // // If only reading header // if (readSelection == -2) { VolumeFile* vf = new VolumeFile; vf->copyVolumeData(volumeRead, false); vf->filename = volumeRead.filename; vf->dataFileName = volumeRead.dataFileName; volumesReadOut.push_back(vf); return; } // // Is this a NIFTI hdr/img volume file pair // if ((hdr.magic[0] == 'n') && (hdr.magic[1] == 'i') && (hdr.magic[2] == '1')) { gzclose(dataFile); // // Create the volume data file name // volumeRead.dataFileName = FileUtilities::filenameWithoutExtension(volumeRead.filename); volumeRead.dataFileName.append(".img"); // // Data file might be gzipped // if (QFile::exists(volumeRead.dataFileName) == false) { QString zipName(volumeRead.dataFileName); zipName.append(".gz"); if (QFile::exists(zipName)) { volumeRead.dataFileName = zipName; } } dataFile = gzopen(volumeRead.dataFileName.toAscii().constData(), "rb"); if (dataFile == NULL) { throw FileException(fileNameIn, "Unable to open with ZLIB for reading."); } } try { // // loop through and read the volume files // const int numSubs = volumeRead.subVolumeNames.size(); for (int i = 0; i < numSubs; i++) { // // Determine if this sub volume should be read // bool readingSingleSubVolume = false; bool readIt = false; if (readSelection == VOLUME_READ_SELECTION_ALL) { readIt = true; } else if (readSelection == i) { readIt = true; readingSingleSubVolume = true; } if (readIt) { // // copy everything but voxel data from the first volume // VolumeFile* vf = NULL; vf = new VolumeFile; vf->copyVolumeData(volumeRead, false); vf->filename = volumeRead.filename; vf->dataFileName = volumeRead.dataFileName; // // Set the descriptive label // vf->descriptiveLabel = volumeRead.subVolumeNames[i]; // // If only reading a single sub-volume // if (readingSingleSubVolume) { // // Read just the sub-volume // vf->readVolumeFileDataSubVolume(byteSwapFlag, vf->scaleSlope[i], vf->scaleOffset[i], niftiReadDataOffset, i, dataFile); } else { // // Read just the sub-volume // vf->readVolumeFileData(byteSwapFlag, vf->scaleSlope[i], vf->scaleOffset[i], dataFile); } if (i < static_cast(studyMetaDataLinkSets.size())) { vf->setStudyMetaDataLinkSet(studyMetaDataLinkSets[i]); } // // Apply qform transformation // /* if (qformTMValid) { vf->applyTransformationMatrix(qformTM); } */ // // return the volume to the user // volumesReadOut.push_back(vf); // // If only reading a single sub-volume // if (readingSingleSubVolume) { break; } } } if (caretExtensionString.isEmpty() == false) { NiftiCaretExtension caretExtension(volumesReadOut, NULL); QString filesComment = ""; caretExtension.readAndApplyExtensionToVolumes(caretExtensionString, filesComment); } } catch (FileException& e) { gzclose(dataFile); throw e; } // // Close the file // gzclose(dataFile); } /*=== 27 July 2009 ** * read the specified sub-volumes in a volume file. * void VolumeFile::readFileNifti(const QString& fileNameIn, const int readSelection, std::vector& volumesReadOut) throw (FileException) { // // Open the file // VolumeFile volumeRead; volumeRead.filename = fileNameIn; gzFile dataFile = gzopen(fileNameIn.toAscii().constData(), "rb"); if (dataFile == NULL) { throw FileException(fileNameIn, "Unable to open with ZLIB for reading."); } // // The NIFTI header // nifti_1_header hdr; // // Read the NIFTI header and close file after reading header // const unsigned long headerSize = sizeof(hdr); const unsigned long numBytesRead = gzread(dataFile, (voidp)&hdr, headerSize); if (numBytesRead != headerSize) { gzclose(dataFile); std::ostringstream str; str << "Tried to read " << headerSize << " bytes from header.\n" << "Only read " << numBytesRead << "."; throw FileException(volumeRead.filename, str.str().c_str()); } // // Make sure it is a NIFTI file // const int version = NIFTI_VERSION(hdr); switch (version) { case 0: gzclose(dataFile); throw FileException(volumeRead.filename, "Is not a NIFTI volume file."); break; case 1: break; default: { gzclose(dataFile); std::ostringstream str; str << "Is an invalid NIFTI version: " << version << "."; throw FileException(volumeRead.filename, str.str().c_str()); } break; } // // Do bytes need to be swapped ? // bool byteSwapFlag = false; if (NIFTI_NEEDS_SWAP(hdr)) { byteSwapFlag = true; ByteSwapping::swapBytes(&hdr.sizeof_hdr, 1); ByteSwapping::swapBytes(&hdr.extents, 1); ByteSwapping::swapBytes(&hdr.session_error, 1); ByteSwapping::swapBytes(hdr.dim, 8); ByteSwapping::swapBytes(&hdr.intent_p1, 1); ByteSwapping::swapBytes(&hdr.intent_p2, 1); ByteSwapping::swapBytes(&hdr.intent_p3, 1); ByteSwapping::swapBytes(&hdr.intent_code, 1); ByteSwapping::swapBytes(&hdr.datatype, 1); ByteSwapping::swapBytes(&hdr.bitpix, 1); ByteSwapping::swapBytes(&hdr.slice_start, 1); ByteSwapping::swapBytes(hdr.pixdim, 8); ByteSwapping::swapBytes(&hdr.vox_offset, 1); ByteSwapping::swapBytes(&hdr.scl_slope, 1); ByteSwapping::swapBytes(&hdr.scl_inter, 1); ByteSwapping::swapBytes(&hdr.slice_end, 1); ByteSwapping::swapBytes(&hdr.cal_max, 1); ByteSwapping::swapBytes(&hdr.cal_min, 1); ByteSwapping::swapBytes(&hdr.slice_duration, 1); ByteSwapping::swapBytes(&hdr.toffset, 1); ByteSwapping::swapBytes(&hdr.glmax, 1); ByteSwapping::swapBytes(&hdr.glmin, 1); ByteSwapping::swapBytes(&hdr.qform_code, 1); ByteSwapping::swapBytes(&hdr.sform_code, 1); ByteSwapping::swapBytes(&hdr.quatern_b, 1); ByteSwapping::swapBytes(&hdr.quatern_c, 1); ByteSwapping::swapBytes(&hdr.quatern_d, 1); ByteSwapping::swapBytes(&hdr.qoffset_x, 1); ByteSwapping::swapBytes(&hdr.qoffset_y, 1); ByteSwapping::swapBytes(&hdr.qoffset_z, 1); ByteSwapping::swapBytes(hdr.srow_x, 4); ByteSwapping::swapBytes(hdr.srow_y, 4); ByteSwapping::swapBytes(hdr.srow_z, 4); } // // Offset of data // const long niftiReadDataOffset = static_cast(hdr.vox_offset); // // Get volume dimensions // if (hdr.dim[0] < 3) { gzclose(dataFile); throw FileException(volumeRead.filename, "has less than 3 dimensions."); } volumeRead.dimensions[0] = hdr.dim[1]; volumeRead.dimensions[1] = hdr.dim[2]; volumeRead.dimensions[2] = hdr.dim[3]; // // Multiple volumes in file ? // int numSubVols = 1; if (hdr.dim[0] > 3) { // // 4 dim volume is time series // if (hdr.dim[0] == 4) { numSubVols = hdr.dim[4]; } else if (hdr.dim[0] == 5) { // // IF 5 dimensions and dim[4] = 1, then multiple values (subvolumes) per voxel // if (hdr.dim[4] == 1) { // // We'll consider RGB's to be a single volume // if ((hdr.dim[5] == 3) && (hdr.datatype == NIFTI_TYPE_RGB24)) { hdr.dim[5] = 1; } if ((hdr.dim[5] == 3) && (hdr.intent_code == NIFTI_INTENT_VECTOR)) { volumeRead.volumeType = VOLUME_TYPE_VECTOR; } numSubVols = hdr.dim[5]; } else if (hdr.dim[4] > 1) { if (hdr.dim[5] > 1) { throw FileException(volumeRead.filename, "Multiple values per timepoint not supported."); } numSubVols = hdr.dim[4]; } } else { throw FileException(volumeRead.filename, "Dimensions greater than 5 not supported."); } } volumeRead.initializeSubVolumes(numSubVols); // // Set the data type // switch (hdr.datatype) { case NIFTI_TYPE_UINT8: volumeRead.voxelDataType = VOXEL_DATA_TYPE_CHAR_UNSIGNED; break; case NIFTI_TYPE_INT8: volumeRead.voxelDataType = VOXEL_DATA_TYPE_CHAR; break; case NIFTI_TYPE_INT16: volumeRead.voxelDataType = VOXEL_DATA_TYPE_SHORT; break; case NIFTI_TYPE_UINT16: volumeRead.voxelDataType = VOXEL_DATA_TYPE_SHORT_UNSIGNED; break; case NIFTI_TYPE_INT32: volumeRead.voxelDataType = VOXEL_DATA_TYPE_INT; break; case NIFTI_TYPE_UINT32: volumeRead.voxelDataType = VOXEL_DATA_TYPE_INT_UNSIGNED; break; case NIFTI_TYPE_INT64: if (sizeof(long long) == 8) { volumeRead.voxelDataType = VOXEL_DATA_TYPE_LONG; } else { throw FileException("Volume contains 64-bit long long data type which " "this computer does not support."); } break; case NIFTI_TYPE_UINT64: if (sizeof(unsigned long long) == 8) { volumeRead.voxelDataType = VOXEL_DATA_TYPE_LONG_UNSIGNED; } else { throw FileException("Volume contains 64-bit unsigned long long data type which " "this computer does not support."); } break; case NIFTI_TYPE_FLOAT32: volumeRead.voxelDataType = VOXEL_DATA_TYPE_FLOAT; break; case NIFTI_TYPE_FLOAT64: volumeRead.voxelDataType = VOXEL_DATA_TYPE_DOUBLE; break; case NIFTI_TYPE_FLOAT128: gzclose(dataFile); throw FileException(volumeRead.filename, "FLOAT 128 type not supported."); break; case NIFTI_TYPE_RGB24: volumeRead.voxelDataType = VOXEL_DATA_TYPE_RGB_SLICE_INTERLEAVED; break; case NIFTI_TYPE_COMPLEX64: gzclose(dataFile); throw FileException(volumeRead.filename, "COMPLEX 64 type not supported."); break; case NIFTI_TYPE_COMPLEX128: gzclose(dataFile); throw FileException(volumeRead.filename, "COMPLEX 128 type not supported."); break; case NIFTI_TYPE_COMPLEX256: gzclose(dataFile); throw FileException(volumeRead.filename, "COMPLEX 256 type not supported."); break; default: { gzclose(dataFile); std::ostringstream str; str << "datatype number " << hdr.datatype << " is unknown."; throw FileException(volumeRead.filename, str.str().c_str()); } break; } // // Comment info // char comm[80]; for (int m = 0; m < 79; m++) { comm[m] = hdr.descrip[m]; } comm[79] = '\0'; volumeRead.setHeaderTag(headerTagComment, comm); // // Convert units to MilliMeters // float spacingScale = 1.0; switch (hdr.xyzt_units) { case NIFTI_UNITS_METER: spacingScale = 1000.0; break; case NIFTI_UNITS_MM: spacingScale = 1.0; break; case NIFTI_UNITS_MICRON: spacingScale = 0.001; break; } hdr.qoffset_x *= spacingScale; hdr.qoffset_y *= spacingScale; hdr.qoffset_z *= spacingScale; hdr.pixdim[1] *= spacingScale; hdr.pixdim[2] *= spacingScale; hdr.pixdim[3] *= spacingScale; // // Spacing // volumeRead.spacing[0] = hdr.pixdim[1]; volumeRead.spacing[1] = hdr.pixdim[2]; volumeRead.spacing[2] = hdr.pixdim[3]; // // default origin // volumeRead.origin[0] = 0.0; volumeRead.origin[1] = 0.0; volumeRead.origin[2] = 0.0; // // Default orientation // volumeRead.orientation[0] = ORIENTATION_UNKNOWN; volumeRead.orientation[1] = ORIENTATION_UNKNOWN; volumeRead.orientation[2] = ORIENTATION_UNKNOWN; for (int i = 0; i < numSubVols; i++) { volumeRead.scaleOffset[i] = hdr.scl_inter; volumeRead.scaleSlope[i] = hdr.scl_slope; } TransformationMatrix qformTM; bool qformTMValid = false; ORIENTATION qformOrientation[3] = { ORIENTATION_UNKNOWN, ORIENTATION_UNKNOWN, ORIENTATION_UNKNOWN }; // // sform_code take priority over qform_code // if (hdr.sform_code > 0) { qformTMValid = false; float x[2], y[2], z[2]; for (int i = 0; i < 2; i++) { const int j = i; const int k = i; x[i] = hdr.srow_x[0] * i + hdr.srow_x[1] * j + hdr.srow_x[2] * k + hdr.srow_x[3]; y[i] = hdr.srow_y[0] * i + hdr.srow_y[1] * j + hdr.srow_y[2] * k + hdr.srow_y[3]; z[i] = hdr.srow_z[0] * i + hdr.srow_z[1] * j + hdr.srow_z[2] * k + hdr.srow_z[3]; } // // Convert units to MilliMeters // float spacingScale = 1.0; switch (hdr.xyzt_units) { case NIFTI_UNITS_METER: spacingScale = 1000.0; break; case NIFTI_UNITS_MM: spacingScale = 1.0; break; case NIFTI_UNITS_MICRON: spacingScale = 0.001; break; } volumeRead.origin[0] = x[0] * spacingScale; volumeRead.origin[1] = y[0] * spacingScale; volumeRead.origin[2] = z[0] * spacingScale; volumeRead.spacing[0] = (x[1] - x[0]) * spacingScale; volumeRead.spacing[1] = (y[1] - y[0]) * spacingScale; volumeRead.spacing[2] = (z[1] - z[0]) * spacingScale; // // NIFTI origin is in the center of the voxel // so move the origin to the corner of voxel // //volumeRead.origin[0] -= volumeRead.spacing[0] * 0.5; //volumeRead.origin[1] -= volumeRead.spacing[1] * 0.5; //volumeRead.origin[2] -= volumeRead.spacing[2] * 0.5; NiftiHelper::mat44 m; m.m[0][0] = hdr.srow_x[0]; m.m[0][1] = hdr.srow_x[1]; m.m[0][2] = hdr.srow_x[2]; m.m[0][3] = hdr.srow_x[3]; m.m[1][0] = hdr.srow_y[0]; m.m[1][1] = hdr.srow_y[1]; m.m[1][2] = hdr.srow_y[2]; m.m[1][3] = hdr.srow_y[3]; m.m[2][0] = hdr.srow_z[0]; m.m[2][1] = hdr.srow_z[1]; m.m[2][2] = hdr.srow_z[2]; m.m[2][3] = hdr.srow_z[3]; m.m[3][0] = 0.0; m.m[3][1] = 0.0; m.m[3][2] = 0.0; m.m[3][3] = 1.0; NiftiHelper::mat44ToCaretOrientation(m, volumeRead.orientation[0], volumeRead.orientation[1], volumeRead.orientation[2]); } else if (hdr.qform_code > 0) { volumeRead.origin[0] = hdr.qoffset_x; volumeRead.origin[1] = hdr.qoffset_y; volumeRead.origin[2] = hdr.qoffset_z; float qfac = (hdr.pixdim[0] < 0.0) ? -1.0 : 1.0 ; // left-handedness? NiftiHelper::mat44 m = NiftiHelper::nifti_quatern_to_mat44(hdr.quatern_b, hdr.quatern_c, hdr.quatern_c, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, qfac); qformTMValid = true; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { qformTM.setMatrixElement(i, j, m.m[i][j]); } } for (int j = 0; j < 3; j++) { float f = qformTM.getMatrixElement(j, 3); f = -f; qformTM.setMatrixElement(j, 3, f); } qformTM.transpose(); // // Force correct sign for spacing // for (int i = 0; i < 3; i++) { if (volumeRead.origin[i] < 0.0) { volumeRead.spacing[i] = std::fabs(volumeRead.spacing[i]); } else { volumeRead.spacing[i] = -std::fabs(volumeRead.spacing[i]); } } // // Set orientation // volumeRead.orientation[0] = ORIENTATION_LEFT_TO_RIGHT; volumeRead.orientation[1] = ORIENTATION_POSTERIOR_TO_ANTERIOR; volumeRead.orientation[2] = ORIENTATION_INFERIOR_TO_SUPERIOR; NiftiHelper::mat44ToCaretOrientation(m, qformOrientation[0], qformOrientation[1], qformOrientation[2]); } // // The origin and spacing are always ordered L/R, P/A, I/S in NIFTI even if // the data is in a different order such as AIL. So, swap some values to // that they are correct for Caret. // float originTemp[3] = { volumeRead.origin[0], volumeRead.origin[1], volumeRead.origin[2] }; float spacingTemp[3] = { volumeRead.spacing[0], volumeRead.spacing[1], volumeRead.spacing[2] }; for (int i = 0; i < 3; i++) { int orientIndex = i; switch (volumeRead.orientation[i]) { case ORIENTATION_UNKNOWN: break; case ORIENTATION_RIGHT_TO_LEFT: case ORIENTATION_LEFT_TO_RIGHT: orientIndex = 0; break; case ORIENTATION_POSTERIOR_TO_ANTERIOR: case ORIENTATION_ANTERIOR_TO_POSTERIOR: orientIndex = 1; break; case ORIENTATION_INFERIOR_TO_SUPERIOR: case ORIENTATION_SUPERIOR_TO_INFERIOR: orientIndex = 2; break; } volumeRead.origin[i] = originTemp[orientIndex]; volumeRead.spacing[i] = spacingTemp[orientIndex]; } // // Check the intent code // volumeRead.volumeType = VOLUME_TYPE_UNKNOWN; switch (hdr.intent_code) { case NIFTI_INTENT_LABEL: volumeRead.volumeType = VOLUME_TYPE_PAINT; break; case NIFTI_INTENT_VECTOR: if (hdr.dim[5] == 3) { volumeRead.volumeType = VOLUME_TYPE_VECTOR; } break; } // // Storage for study meta data links // std::vector studyMetaDataLinkSets; // // Intention string and TR // NiftiHelper::getNiftiIntentionInformation(hdr, volumeRead.niftiIntentCodeAndParamString, volumeRead.niftiIntentName); volumeRead.niftiIntentCode = hdr.intent_code; volumeRead.niftiIntentParameter1 = hdr.intent_p1; volumeRead.niftiIntentParameter2 = hdr.intent_p2; volumeRead.niftiIntentParameter3 = hdr.intent_p3; volumeRead.niftiTR = hdr.slice_duration; // // Read the extender // if (hdr.vox_offset >= 352) { nifti1_extender extender; const unsigned long extLength = sizeof(extender); const unsigned long numBytesRead = gzread(dataFile, (voidp)&extender, extLength); if (extLength == numBytesRead) { if (DebugControl::getDebugOn()) { std::cout << "NIFTI extension[0] " << static_cast(extender.extension[0]) << std::endl; } } int extCount = 1; z_off_t pos = gztell(dataFile); while (pos < hdr.vox_offset) { // // Read in the extension size and code // int extensionSize, extensionCode; if ((gzread(dataFile, (voidp)&extensionSize, sizeof(extensionSize)) != 4) || (gzread(dataFile, (voidp)&extensionCode, sizeof(extensionCode)) != 4)) { std::cout << "WARNING: " << volumeRead.filename.toAscii().constData() << std::endl << "Problem reading extension " << extCount << ". This and all other extensions ignored." << std::endl; break; } else { if (byteSwapFlag) { ByteSwapping::swapBytes(&extensionSize, 1); ByteSwapping::swapBytes(&extensionCode, 1); } if (DebugControl::getDebugOn()) { std::cout << "Extension Size: " << extensionSize << std::endl; std::cout << "Extension Code: " << extensionCode << std::endl; } // // Check the code // const int evenNum = (extensionCode / 2) * 2; if ((evenNum < 0) || (evenNum > 100)) { std::cout << "WARNING: " << volumeRead.filename.toAscii().constData() << std::endl << "Invalid extension code " << extensionCode << " for extension " << extCount << ". This and all other extensions ignored." << std::endl; break; } // // Check extension size // if ((extensionSize % 16) != 0) { std::cout << "WARNING: NIFTI extension (code " << extensionCode << ") has size that is not a multiple of 16." << std::endl; } // // The 8-byte extension size/code is included in extensionSize // const int dataSize = extensionSize - 8; if (dataSize > 0) { char* data = new char[dataSize + 1]; if (gzread(dataFile, (voidp)data, dataSize) != dataSize) { std::cout << "WARNING: " << volumeRead.filename.toAscii().constData() << std::endl << "Problem reading extension " << extCount << " data. This and all other extensions ignored." << std::endl; break; } data[dataSize] = '\0'; // // Is this the AFNI extension // if (extensionCode == 4) { // NIFTI_ECODE_AFNI) { if (DebugControl::getDebugOn()) { std::cout << "AFNI extension: " << data << std::endl; } // // Process the NIFTI extension // try { volumeRead.afniHeader.readFromNiftiExtension(QString(data)); } catch (FileException& e) { throw FileException(volumeRead.filename, e.whatQString()); } // // Get the subvolume names // const AfniAttribute* nameAttr = volumeRead.afniHeader.getAttribute(AfniAttribute::NAME_BRICK_LABS); if (nameAttr != NULL) { std::vector names; StringUtilities::token(nameAttr->getValue(), "~", names); const unsigned int minNames = std::min(names.size(), volumeRead.subVolumeNames.size()); for (unsigned int i = 0; i < minNames; i++) { volumeRead.subVolumeNames[i] = names[i]; } } // // Get the HISTORY_NOTE and use it as a comment // const AfniAttribute* commentAttr = volumeRead.afniHeader.getAttribute(AfniAttribute::NAME_HISTORY_NOTE); if (commentAttr != NULL) { volumeRead.setHeaderTag(headerTagComment, commentAttr->getValue()); volumeRead.setFileComment(commentAttr->getValue()); } // // Get the region names (for paint volume) // const AfniAttribute* regionAttr = volumeRead.afniHeader.getAttribute(AfniAttribute::NAME_LUT_NAMES); if (regionAttr != NULL) { volumeRead.regionNames.clear(); StringUtilities::token(regionAttr->getValue(), "~", volumeRead.regionNames); } // // Get the study metadata links // const AfniAttribute* mdAttr = volumeRead.afniHeader.getAttribute(AfniAttribute::NAME_CARET_METADATA_LINK); if (mdAttr != NULL) { StudyMetaDataLinkSet smdls; std::vector md; StringUtilities::token(mdAttr->getValue(), "~", md); for (unsigned int m = 0; m < md.size(); m++) { smdls.setLinkSetFromCodedText(md[m]); studyMetaDataLinkSets.push_back(smdls); } } // // Get the PubMed ID // const AfniAttribute* pmidAttr = volumeRead.afniHeader.getAttribute(AfniAttribute::NAME_CARET_PUBMED_ID); if (pmidAttr != NULL) { volumeRead.setFilePubMedID(pmidAttr->getValue()); } } delete[] data; } } extCount++; pos = gztell(dataFile); } } // // Keep track of data files zipped status // volumeRead.dataFileWasZippedFlag = (volumeRead.filename.right(3) == ".gz"); // // If only reading header // if (readSelection == -2) { VolumeFile* vf = new VolumeFile; vf->copyVolumeData(volumeRead, false); vf->filename = volumeRead.filename; vf->dataFileName = volumeRead.dataFileName; volumesReadOut.push_back(vf); return; } // // Is this a NIFTI hdr/img volume file pair // if ((hdr.magic[0] == 'n') && (hdr.magic[1] == 'i') && (hdr.magic[2] == '1')) { gzclose(dataFile); // // Create the volume data file name // volumeRead.dataFileName = FileUtilities::filenameWithoutExtension(volumeRead.filename); volumeRead.dataFileName.append(".img"); // // Data file might be gzipped // if (QFile::exists(volumeRead.dataFileName) == false) { QString zipName(volumeRead.dataFileName); zipName.append(".gz"); if (QFile::exists(zipName)) { volumeRead.dataFileName = zipName; } } dataFile = gzopen(volumeRead.dataFileName.toAscii().constData(), "rb"); if (dataFile == NULL) { throw FileException(fileNameIn, "Unable to open with ZLIB for reading."); } } try { // // loop through and read the volume files // const int numSubs = volumeRead.subVolumeNames.size(); for (int i = 0; i < numSubs; i++) { // // Determine if this sub volume should be read // bool readingSingleSubVolume = false; bool readIt = false; if (readSelection == VOLUME_READ_SELECTION_ALL) { readIt = true; } else if (readSelection == i) { readIt = true; readingSingleSubVolume = true; } if (readIt) { // // copy everything but voxel data from the first volume // VolumeFile* vf = NULL; vf = new VolumeFile; vf->copyVolumeData(volumeRead, false); vf->filename = volumeRead.filename; vf->dataFileName = volumeRead.dataFileName; // // Set the descriptive label // vf->descriptiveLabel = volumeRead.subVolumeNames[i]; // // If only reading a single sub-volume // if (readingSingleSubVolume) { // // Read just the sub-volume // vf->readVolumeFileDataSubVolume(byteSwapFlag, vf->scaleSlope[i], vf->scaleOffset[i], niftiReadDataOffset, i, dataFile); } else { // // Read just the sub-volume // vf->readVolumeFileData(byteSwapFlag, vf->scaleSlope[i], vf->scaleOffset[i], dataFile); } if (i < static_cast(studyMetaDataLinkSets.size())) { vf->setStudyMetaDataLinkSet(studyMetaDataLinkSets[i]); } // // Apply qform transformation // if (qformTMValid) { vf->applyTransformationMatrix(qformTM); } // // return the volume to the user // volumesReadOut.push_back(vf); // // If only reading a single sub-volume // if (readingSingleSubVolume) { break; } } } } catch (FileException& e) { gzclose(dataFile); throw e; } // // Close the file // gzclose(dataFile); } ===*/ /** * read the specified sub-volumes in an SPM volume file. */ void VolumeFile::readFileSpm(const QString& fileNameIn, const int readSelection, std::vector& volumesReadOut, const bool rightIsOnLeft) throw (FileException) { readFileAnalyze(fileNameIn, readSelection, volumesReadOut, true); if (rightIsOnLeft) { for (unsigned int i = 0; i < volumesReadOut.size(); i++) { volumesReadOut[i]->flip(VOLUME_AXIS_X); } } } /** * read the specified sub-volumes in a Wash U. volume file. */ void VolumeFile::readFileWuNil(const QString& fileNameIn, const int readSelection, std::vector& volumesReadOut) throw (FileException) { VolumeFile volumeRead; volumeRead.filename = fileNameIn; QFile file(fileNameIn); if (file.open(QIODevice::ReadOnly) == false) { throw FileException(fileNameIn, file.errorString()); } QTextStream stream(&file); volumeRead.wunilHeader.clear(); volumeRead.wunilHeader.readHeader(file, stream); QString errorMessage; // // Only support float in RAI orientation // volumeRead.voxelDataType = VOXEL_DATA_TYPE_FLOAT; volumeRead.orientation[0] = ORIENTATION_RIGHT_TO_LEFT; volumeRead.orientation[1] = ORIENTATION_ANTERIOR_TO_POSTERIOR; volumeRead.orientation[2] = ORIENTATION_INFERIOR_TO_SUPERIOR; // // Data type of voxels // WuNilAttribute* dataType = volumeRead.wunilHeader.getAttribute(WuNilAttribute::NAME_NUMBER_FORMAT); if (dataType != NULL) { if (dataType->getValue() != "float") { errorMessage.append("Only \"number format\" of float supported.\n"); } } else { errorMessage.append("required attribute \"number format\" not found.\n"); } // // orientation // int ifhOrientation = 2; WuNilAttribute* orientAttr = volumeRead.wunilHeader.getAttribute(WuNilAttribute::NAME_ORIENTATION); if (orientAttr != NULL) { std::vector orient; orientAttr->getValue(orient); if (orient.size() < 1) { errorMessage.append("Required attribute \"orientation\" does not have a value.\n"); } else { if ((orient[0] != 2) && (orient[0] != 3) && (orient[0] != 4) && (orient[0] != 100)) { std::ostringstream str; str << "\"orientation\" of " << orient[0] << " not supported"; errorMessage.append(str.str().c_str()); errorMessage.append("\n"); } ifhOrientation = orient[0]; } } else { errorMessage.append("Required attribute \"orientation\" not found.\n"); } // // X dimension // int dimensions[3] = { 0, 0, 0 }; WuNilAttribute* xattr= volumeRead.wunilHeader.getAttribute(WuNilAttribute::NAME_MATRIX_SIZE_1); if (xattr != NULL) { std::vector dim; xattr->getValue(dim); if (dim.size() == 0) { errorMessage.append("Required attribute \"matrix size [1]\" does not have a value.\n"); } else { dimensions[0] = dim[0]; } } else { errorMessage.append("Required attribute \"matrix size [1]\" not found.\n"); } // // Y dimension // WuNilAttribute* yattr= volumeRead.wunilHeader.getAttribute(WuNilAttribute::NAME_MATRIX_SIZE_2); if (yattr != NULL) { std::vector dim; yattr->getValue(dim); if (dim.size() == 0) { errorMessage.append("Required attribute \"matrix size [2]\" does not have a value.\n"); } else { dimensions[1] = dim[0]; } } else { errorMessage.append("Required attribute \"matrix size [2]\" not found.\n"); } // // Z dimension // WuNilAttribute* zattr= volumeRead.wunilHeader.getAttribute(WuNilAttribute::NAME_MATRIX_SIZE_3); if (zattr != NULL) { std::vector dim; zattr->getValue(dim); if (dim.size() == 0) { errorMessage.append("Required attribute \"matrix size [2]\" does not have a value.\n"); } else { dimensions[2] = dim[0]; } } else { errorMessage.append("Required attribute \"matrix size [2]\" not found.\n"); } volumeRead.setDimensions(dimensions); // // Number of subvolumes // WuNilAttribute* numsubattr= volumeRead.wunilHeader.getAttribute(WuNilAttribute::NAME_MATRIX_SIZE_4); if (numsubattr != NULL) { std::vector dim; numsubattr->getValue(dim); if (dim.size() == 0) { errorMessage.append("Required attribute \"matrix size [4]\" does not have a value.\n"); } else { volumeRead.initializeSubVolumes(dim[0]); } } else { errorMessage.append("Required attribute \"matrix size [4]\" not found.\n"); } float mmppix[3]; WuNilAttribute* mmppixAttr = volumeRead.wunilHeader.getAttribute(WuNilAttribute::NAME_MMPPIX); if (mmppixAttr != NULL) { std::vector mmppixVector; mmppixAttr->getValue(mmppixVector); if (mmppixVector.size() < 3) { errorMessage.append("Required attribute \"mmppix\" does not have 3 elements\n"); } else { mmppix[0] = mmppixVector[0]; mmppix[1] = mmppixVector[1]; mmppix[2] = mmppixVector[2]; } } else { float scale0 = 1.0; WuNilAttribute* scale0Att = volumeRead.wunilHeader.getAttribute(WuNilAttribute::NAME_SCALING_FACTOR_1); if (scale0Att != NULL) { std::vector scaleVector; scale0Att->getValue(scaleVector); if (scaleVector.empty() == false) { scale0 = scaleVector[0]; } } float scale1 = 1.0; WuNilAttribute* scale1Att = volumeRead.wunilHeader.getAttribute(WuNilAttribute::NAME_SCALING_FACTOR_2); if (scale1Att != NULL) { std::vector scaleVector; scale1Att->getValue(scaleVector); if (scaleVector.empty() == false) { scale1 = scaleVector[0]; } } float scale2 = 1.0; WuNilAttribute* scale2Att = volumeRead.wunilHeader.getAttribute(WuNilAttribute::NAME_SCALING_FACTOR_3); if (scale2Att != NULL) { std::vector scaleVector; scale2Att->getValue(scaleVector); if (scaleVector.empty() == false) { scale2 = scaleVector[0]; } } if ((scale0Att != NULL) && (scale1Att != NULL) && (scale2Att != NULL)) { // // From Avi Snyder // mmppix[0] = scale0; mmppix[1] = -scale1; mmppix[2] = -scale2; } else { errorMessage.append("Required attribute \"mmppix\" or \"scaling factor\" not found.\n"); } } // // Get center // float center[3] = { 0.0, 0.0, 0.0 }; WuNilAttribute* centerAttr = volumeRead.wunilHeader.getAttribute(WuNilAttribute::NAME_CENTER); if (centerAttr != NULL) { std::vector centerVector; centerAttr->getValue(centerVector); if (centerVector.size() < 3) { errorMessage.append("Required attribute \"center\" does not have 3 elements\n"); } else { center[0] = centerVector[0]; center[1] = centerVector[1]; center[2] = centerVector[2]; } } else { // // From Avi Snyder // center[0] = mmppix[0] * static_cast(dimensions[0] - dimensions[0]/2); center[1] = mmppix[1] * static_cast(1 + dimensions[1]/2); center[2] = mmppix[2] * static_cast(1 + dimensions[2]/2); //errorMessage.append("Required attribute \"center\" not found.\n"); } const int firstVoxelIndex[3] = { 0, 0, 0 }; // // Determine stereotaxic coordinates of first voxel // float org[3]; WuNilHeader::voxelIndicesToStereotaxicCoordinates(volumeRead.dimensions, center, mmppix, firstVoxelIndex, org); // // default to transverse orientation // volumeRead.orientation[0] = ORIENTATION_RIGHT_TO_LEFT; volumeRead.orientation[1] = ORIENTATION_ANTERIOR_TO_POSTERIOR; volumeRead.orientation[2] = ORIENTATION_INFERIOR_TO_SUPERIOR; // // Set spacing based upon volume's orientation code // float space[3] = { 0.0, 0.0, 0.0 }; switch (ifhOrientation) { case 2: // transverse space[0] = -mmppix[0]; space[1] = mmppix[1]; space[2] = -mmppix[2]; //volumeRead.setOriginAtCornerOfVoxel(org, space); volumeRead.setOrigin(org);//Tim C: corner of voxel convention discarded by 4dfp, due to interpolation method volumeRead.orientation[0] = ORIENTATION_RIGHT_TO_LEFT; volumeRead.orientation[1] = ORIENTATION_ANTERIOR_TO_POSTERIOR; volumeRead.orientation[2] = ORIENTATION_INFERIOR_TO_SUPERIOR; break; case 3: // coronal space[0] = -mmppix[0]; space[1] = mmppix[1]; space[2] = mmppix[2]; volumeRead.orientation[0] = ORIENTATION_RIGHT_TO_LEFT; volumeRead.orientation[1] = ORIENTATION_SUPERIOR_TO_INFERIOR; volumeRead.orientation[2] = ORIENTATION_ANTERIOR_TO_POSTERIOR; org[0] = fabs(org[0]); org[1] = fabs(org[1]); org[2] = fabs(org[2]); volumeRead.setOriginAtCornerOfVoxel(org, space); break; case 4: // sagittal space[0] = -mmppix[0]; space[1] = mmppix[1];//Tim C: ground truth from S2T says x and y flip, that is, i and k voxel indices space[2] = -mmppix[2]; volumeRead.orientation[0] = ORIENTATION_ANTERIOR_TO_POSTERIOR; volumeRead.orientation[1] = ORIENTATION_SUPERIOR_TO_INFERIOR; volumeRead.orientation[2] = ORIENTATION_LEFT_TO_RIGHT; org[0] = fabs(org[0]); org[1] = fabs(org[1]); org[2] = -fabs(org[2]); volumeRead.setOriginAtCornerOfVoxel(org, space); break; case 100: space[0] = fabs(mmppix[0]); space[1] = fabs(mmppix[1]); space[2] = fabs(mmppix[2]); volumeRead.orientation[0] = ORIENTATION_UNKNOWN; volumeRead.orientation[1] = ORIENTATION_UNKNOWN; volumeRead.orientation[2] = ORIENTATION_UNKNOWN; float org[3] = { 0, 0, 0 }; volumeRead.setOriginAtCornerOfVoxel(org, space); break; } volumeRead.setSpacing(space); // // Get the study metadata link // WuNilAttribute* metaAttr = volumeRead.wunilHeader.getAttribute(WuNilAttribute::NAME_CARET_METADATA); if (metaAttr != NULL) { StudyMetaDataLinkSet smdls; smdls.setLinkSetFromCodedText(metaAttr->getValue().trimmed()); volumeRead.setStudyMetaDataLinkSet(smdls); } // // get the region names // std::vector wuRegionNames; volumeRead.wunilHeader.getRegionNames(wuRegionNames); const int numWuRegionNames = static_cast(wuRegionNames.size()); for (int i = 0; i < numWuRegionNames; i++) { volumeRead.addRegionName(wuRegionNames[i]); } // // If error message is not isEmpty something required is missing from the volume // if (errorMessage.isEmpty() == false) { throw FileException(FileUtilities::basename(volumeRead.filename), errorMessage); } // // WU NIL files are big endian by default // bool bigEndianDataFlag = true; WuNilAttribute* endianAttr = volumeRead.wunilHeader.getAttribute(WuNilAttribute::NAME_IMAGEDATA_BYTE_ORDER); if (endianAttr != NULL) { if (endianAttr->getValue().trimmed() == "littleendian") { bigEndianDataFlag = false; } } // // WU NIL files normally created on sun workstations which are big endian // bool bigEndianComputerFlag = (QSysInfo::ByteOrder == QSysInfo::BigEndian); //const bool byteSwapFlag = (bigEndianComputerFlag == false); const bool byteSwapFlag = (bigEndianComputerFlag != bigEndianDataFlag); // // Create the volume data file name // volumeRead.dataFileName = FileUtilities::filenameWithoutExtension(volumeRead.filename); volumeRead.dataFileName.append(".img"); // // Data file might be gzipped // if (QFile::exists(volumeRead.dataFileName) == false) { QString zipName(volumeRead.dataFileName); zipName.append(".gz"); if (QFile::exists(zipName)) { volumeRead.dataFileName = zipName; } } // // If only reading header // if (readSelection == -2) { VolumeFile* vf = new VolumeFile; vf->copyVolumeData(volumeRead, false); vf->filename = volumeRead.filename; vf->dataFileName = volumeRead.dataFileName; volumesReadOut.push_back(vf); return; } // // Open the data file // gzFile dataFile = gzopen(volumeRead.dataFileName.toAscii().constData(), "rb"); if (dataFile == NULL) { QString msg("Unable to open data file: "); msg.append(volumeRead.dataFileName); throw FileException(fileNameIn, msg); } try { // // loop through and read the volume files // const int numSubs = volumeRead.subVolumeNames.size(); for (int i = 0; i < numSubs; i++) { // // Determine if this sub volume should be read // bool readingSingleSubVolume = false; bool readIt = false; if (readSelection == VOLUME_READ_SELECTION_ALL) { readIt = true; } else if (readSelection == i) { readIt = true; readingSingleSubVolume = true; } if (readIt) { // // copy everything but voxel data from the first volume // VolumeFile* vf = NULL; vf = new VolumeFile; vf->copyVolumeData(volumeRead, false); vf->filename = volumeRead.filename; vf->dataFileName = volumeRead.dataFileName; // // Set the descriptive label // vf->descriptiveLabel = volumeRead.subVolumeNames[i]; // // If only reading a single sub-volume // if (readingSingleSubVolume) { // // Read just the sub-volume // vf->readVolumeFileDataSubVolume(byteSwapFlag, vf->scaleSlope[i], vf->scaleOffset[i], 0, i, dataFile); } else { // // Read just the sub-volume // vf->readVolumeFileData(byteSwapFlag, vf->scaleSlope[i], vf->scaleOffset[i], dataFile); } // // return the volume to the user // volumesReadOut.push_back(vf); // // If only reading a single sub-volume // if (readingSingleSubVolume) { break; } } } } catch (FileException& e) { gzclose(dataFile); throw e; } // // Close the file // gzclose(dataFile); } /** * write the specified AFNI sub-volumes. */ void VolumeFile::writeFileAfni(const QString& fileNameIn, const VOXEL_DATA_TYPE writeVoxelDataTypeIn, std::vector& volumesToWrite, const bool zipAfniBrikFile) throw (FileException) { if (volumesToWrite.empty()) { throw FileException(fileNameIn, "No volume data to write."); } VolumeFile* firstVolume = volumesToWrite[0]; firstVolume->filename = fileNameIn; firstVolume->voxelDataType = writeVoxelDataTypeIn; const int numSubVolumes = static_cast(volumesToWrite.size()); switch(firstVolume->volumeType) { case VOLUME_TYPE_ANATOMY: break; case VOLUME_TYPE_FUNCTIONAL: break; case VOLUME_TYPE_PAINT: break; case VOLUME_TYPE_PROB_ATLAS: break; case VOLUME_TYPE_RGB: firstVolume->voxelDataType = VOXEL_DATA_TYPE_RGB_VOXEL_INTERLEAVED; break; case VOLUME_TYPE_ROI: break; case VOLUME_TYPE_SEGMENTATION: break; case VOLUME_TYPE_VECTOR: break; case VOLUME_TYPE_UNKNOWN: //throw FileException(fileNameIn, "Unknown type of volume."); break; } // // Check for invalid voxel data types in AFNI files // switch(firstVolume->voxelDataType) { case VOXEL_DATA_TYPE_UNKNOWN: throw FileException(firstVolume->filename, "Unknown data type"); break; case VOXEL_DATA_TYPE_CHAR: throw FileException(firstVolume->filename, "AFNI does not support byte-signed data type."); break; case VOXEL_DATA_TYPE_CHAR_UNSIGNED: break; case VOXEL_DATA_TYPE_SHORT: break; case VOXEL_DATA_TYPE_SHORT_UNSIGNED: throw FileException(firstVolume->filename, "AFNI does not support short-unsigned data type."); break; case VOXEL_DATA_TYPE_INT: break; case VOXEL_DATA_TYPE_INT_UNSIGNED: throw FileException(firstVolume->filename, "AFNI does not support int-unsigned data type."); break; case VOXEL_DATA_TYPE_LONG: throw FileException(firstVolume->filename, "AFNI does not support long-signed data type."); break; case VOXEL_DATA_TYPE_LONG_UNSIGNED: throw FileException(firstVolume->filename, "AFNI does not support long-unsigned data type."); break; case VOXEL_DATA_TYPE_FLOAT: break; case VOXEL_DATA_TYPE_DOUBLE: break; case VOXEL_DATA_TYPE_RGB_VOXEL_INTERLEAVED: break; case VOXEL_DATA_TYPE_RGB_SLICE_INTERLEAVED: break; case VOXEL_DATA_TYPE_VECTOR: break; } // // Setup the AFNI header // firstVolume->afniHeader.setupFromVolumeFiles(volumesToWrite, NULL); // // Open file and create a text stream // QFile file(firstVolume->filename); if (file.open(QIODevice::WriteOnly) == false) { throw FileException(firstVolume->filename, file.errorString()); } QTextStream stream(&file); // // Write the header file // firstVolume->afniHeader.writeHeader(stream); // // Close the header file // file.close(); // // Update file permissions ? // if (getFileWritePermissions() != 0) { QFile::setPermissions(firstVolume->filename, getFileWritePermissions()); } // // Create the name of the data file // firstVolume->dataFileName = FileUtilities::filenameWithoutExtension(firstVolume->filename); firstVolume->dataFileName.append(".BRIK"); if (zipAfniBrikFile) { firstVolume->dataFileName.append(".gz"); } firstVolume->dataFileWasZippedFlag = zipAfniBrikFile; // // Open the data file // gzFile zipFile = NULL; std::ofstream* cppFile = NULL; if (zipAfniBrikFile) { zipFile = gzopen(firstVolume->dataFileName.toAscii().constData(), "wb"); if (zipFile == NULL) { throw FileException(firstVolume->dataFileName, "Unable to open for writing"); } } else { cppFile = new std::ofstream(firstVolume->dataFileName.toAscii().constData(), std::ios::out | std::ios::binary); if (cppFile == NULL) { throw FileException(firstVolume->dataFileName, "Unable to open for writing"); } } // // Write the volume data // QString writeErrorMessage; for (int i = 0; i < numSubVolumes; i++) { try { volumesToWrite[i]->writeVolumeFileData(firstVolume->voxelDataType, false, zipAfniBrikFile, zipFile, cppFile, 1.0); } catch (FileException& e) { writeErrorMessage = e.whatQString(); } } // // Close the data file // if (zipAfniBrikFile) { gzclose(zipFile); } else { cppFile->close(); delete cppFile; } if (writeErrorMessage.isEmpty() == false) { throw FileException(firstVolume->dataFileName, writeErrorMessage); } // // Update file permissions ? // if (getFileWritePermissions() != 0) { QFile::setPermissions(firstVolume->dataFileName, getFileWritePermissions()); } } /** * write the specified Analyze sub-volumes. */ void VolumeFile::writeFileAnalyze(const QString& fileNameIn, const VOXEL_DATA_TYPE writeVoxelDataType, std::vector& volumesToWrite) throw (FileException) { writeFileSPM(fileNameIn, writeVoxelDataType, volumesToWrite, true); } /** * write the specified NIFTI sub-volumes. */ void VolumeFile::writeFileNifti(const QString& fileNameIn, const VOXEL_DATA_TYPE writeVoxelDataTypeIn, std::vector& volumesToWrite, const ColorFile* labelColorsForCaret6) throw (FileException) { const int numSubVolumes = static_cast(volumesToWrite.size()); if (numSubVolumes <= 0) { throw FileException(fileNameIn, "No volume data to write."); } // // Get the maximum absolute value of all voxels // float maxAbsVoxelValue = 0.0; for (int i = 0; i < numSubVolumes; i++) { float minValue, maxValue; volumesToWrite[i]->getMinMaxVoxelValues(minValue, maxValue); maxAbsVoxelValue = std::max(std::fabs(minValue), maxAbsVoxelValue); maxAbsVoxelValue = std::max(std::fabs(maxValue), maxAbsVoxelValue); } // // Get the first volume // VolumeFile* firstVolume = volumesToWrite[0]; firstVolume->filename = fileNameIn; firstVolume->voxelDataType = writeVoxelDataTypeIn; switch(firstVolume->volumeType) { case VOLUME_TYPE_ANATOMY: break; case VOLUME_TYPE_FUNCTIONAL: break; case VOLUME_TYPE_PAINT: break; case VOLUME_TYPE_PROB_ATLAS: break; case VOLUME_TYPE_RGB: firstVolume->voxelDataType = VOXEL_DATA_TYPE_RGB_SLICE_INTERLEAVED; break; case VOLUME_TYPE_ROI: break; case VOLUME_TYPE_SEGMENTATION: break; case VOLUME_TYPE_VECTOR: break; case VOLUME_TYPE_UNKNOWN: //throw FileException(firstVolume->filename, "Unknown type of volume."); break; } // // Create a NIFTI header and zero it out // nifti_1_header hdr; memset(&hdr, 0, sizeof(hdr)); // // Set the size of the header // hdr.sizeof_hdr = sizeof(struct dsr); hdr.regular = 'r'; // // Set the dimensions // hdr.dim[0] = 3; //set at 3 to start hdr.dim[1] = firstVolume->dimensions[0]; hdr.dim[2] = firstVolume->dimensions[1]; hdr.dim[3] = firstVolume->dimensions[2]; hdr.dim[4] = 1; hdr.dim[5] = 1; if (numSubVolumes > 1) { hdr.dim[0]++; hdr.dim[hdr.dim[0]] = numSubVolumes; } // // Set the datatype // float maxDataTypeValue = std::numeric_limits::max(); switch (firstVolume->voxelDataType) { case VOXEL_DATA_TYPE_UNKNOWN: throw FileException(firstVolume->filename, "Unknown data type.");; break; case VOXEL_DATA_TYPE_CHAR: hdr.datatype = NIFTI_TYPE_INT8; maxDataTypeValue = std::numeric_limits::max(); break; case VOXEL_DATA_TYPE_CHAR_UNSIGNED: hdr.datatype = NIFTI_TYPE_UINT8; maxDataTypeValue = std::numeric_limits::max(); break; case VOXEL_DATA_TYPE_SHORT: hdr.datatype = NIFTI_TYPE_INT16; maxDataTypeValue = std::numeric_limits::max(); break; case VOXEL_DATA_TYPE_SHORT_UNSIGNED: hdr.datatype = NIFTI_TYPE_UINT16; maxDataTypeValue = std::numeric_limits::max(); break; case VOXEL_DATA_TYPE_INT: hdr.datatype = NIFTI_TYPE_INT32; maxDataTypeValue = std::numeric_limits::max(); break; case VOXEL_DATA_TYPE_INT_UNSIGNED: hdr.datatype = NIFTI_TYPE_UINT32; maxDataTypeValue = std::numeric_limits::max(); break; case VOXEL_DATA_TYPE_LONG: hdr.datatype = NIFTI_TYPE_INT64; maxDataTypeValue = std::numeric_limits::max(); break; case VOXEL_DATA_TYPE_LONG_UNSIGNED: hdr.datatype = NIFTI_TYPE_UINT64; maxDataTypeValue = std::numeric_limits::max(); break; case VOXEL_DATA_TYPE_FLOAT: hdr.datatype = NIFTI_TYPE_FLOAT32; maxDataTypeValue = std::numeric_limits::max(); break; case VOXEL_DATA_TYPE_DOUBLE: hdr.datatype = NIFTI_TYPE_FLOAT64; maxDataTypeValue = std::numeric_limits::max();// FLOAT since date stored in FLOAT which is smaller than double break; case VOXEL_DATA_TYPE_RGB_VOXEL_INTERLEAVED: hdr.datatype = NIFTI_TYPE_RGB24; hdr.dim[0]++; hdr.dim[hdr.dim[0]] = 3; // 3 values per voxel break; case VOXEL_DATA_TYPE_RGB_SLICE_INTERLEAVED: hdr.datatype = NIFTI_TYPE_RGB24; hdr.dim[0]++; hdr.dim[hdr.dim[0]] = 3; // 3 values per voxel break; case VOXEL_DATA_TYPE_VECTOR: hdr.datatype = NIFTI_TYPE_FLOAT32; hdr.dim[0]++; hdr.dim[hdr.dim[0]] = 3; // 3 values per voxel break; } hdr.intent_code = NIFTI_INTENT_NONE; switch(firstVolume->volumeType) { case VOLUME_TYPE_ANATOMY: break; case VOLUME_TYPE_FUNCTIONAL: break; case VOLUME_TYPE_PAINT: hdr.intent_code = NIFTI_INTENT_LABEL; break; case VOLUME_TYPE_PROB_ATLAS: hdr.intent_code = NIFTI_INTENT_LABEL; break; case VOLUME_TYPE_RGB: break; case VOLUME_TYPE_ROI: break; case VOLUME_TYPE_SEGMENTATION: break; case VOLUME_TYPE_VECTOR: hdr.intent_code = NIFTI_INTENT_VECTOR; break; case VOLUME_TYPE_UNKNOWN: break; } // // Data offset and slope // hdr.scl_slope = 1.0; hdr.scl_inter = 0.0; // // Set scaling only if needed. Data will be divided by this value // as it is written. // Scaling is applied after data is read. // When data is written, it will be multiplied by this value to restore // the original values. // if (maxAbsVoxelValue > maxDataTypeValue) { if (maxDataTypeValue > 0.0) { hdr.scl_slope = maxAbsVoxelValue / maxDataTypeValue; if (hdr.scl_slope <= 0.0) { hdr.scl_slope = 1.0; } } } // // voxel sizes // hdr.pixdim[0] = 1; // is actually "qfac" in NIFTI not 3 as in analyze; hdr.pixdim[1] = firstVolume->spacing[0]; hdr.pixdim[2] = firstVolume->spacing[1]; hdr.pixdim[3] = firstVolume->spacing[2]; // // Comment // const QString comm(firstVolume->getHeaderTag(headerTagComment)); if (comm.isEmpty() == false) { int len = comm.length(); if (len > 79) { len = 79; } for (int i = 0; i < len; i++) { hdr.descrip[i] = comm[i].toAscii(); } hdr.descrip[len] = '\0'; } /* // // origin in NIFTI file is in center of voxel, caret origin is at corner of voxel // const float halfVoxelOffset[3] = { firstVolume->spacing[0] * 0.5, firstVolume->spacing[1] * 0.5, firstVolume->spacing[2] * 0.5 }; */ // // Set origin info // // QFORM is always UNKNOWN // This should be fixed so that QFORM produces the same coordinates as SFORM // hdr.qform_code = NIFTI_XFORM_UNKNOWN; if ((firstVolume->orientation[0] == ORIENTATION_LEFT_TO_RIGHT) && (firstVolume->orientation[1] == ORIENTATION_POSTERIOR_TO_ANTERIOR) && (firstVolume->orientation[2] == ORIENTATION_INFERIOR_TO_SUPERIOR)) { hdr.qform_code = NIFTI_XFORM_TALAIRACH; hdr.sform_code = NIFTI_XFORM_TALAIRACH; } else { hdr.qform_code = NIFTI_XFORM_SCANNER_ANAT; hdr.sform_code = NIFTI_XFORM_SCANNER_ANAT; } hdr.quatern_b = 0.0; hdr.quatern_c = 0.0; hdr.quatern_d = 0.0; hdr.qoffset_x = firstVolume->origin[0]; // + halfVoxelOffset[0]; hdr.qoffset_y = firstVolume->origin[1]; // + halfVoxelOffset[1]; hdr.qoffset_z = firstVolume->origin[2]; // + halfVoxelOffset[2]; hdr.srow_x[0] = firstVolume->spacing[0]; hdr.srow_x[1] = 0.0; hdr.srow_x[2] = 0.0; hdr.srow_x[3] = firstVolume->origin[0]; // + halfVoxelOffset[0]; hdr.srow_y[0] = 0.0; hdr.srow_y[1] = firstVolume->spacing[1]; hdr.srow_y[2] = 0.0; hdr.srow_y[3] = firstVolume->origin[1]; // + halfVoxelOffset[1]; hdr.srow_z[0] = 0.0; hdr.srow_z[1] = 0.0; hdr.srow_z[2] = firstVolume->spacing[2]; hdr.srow_z[3] = firstVolume->origin[2]; // + halfVoxelOffset[2]; // // set the magic number info // hdr.magic[0] = 'n'; hdr.magic[1] = '+'; hdr.magic[2] = '1'; hdr.magic[3] = '\0'; // // Setup the AFNI header placed into a NIFTI extension and then // create the extension // firstVolume->afniHeader.setupFromVolumeFiles(volumesToWrite, labelColorsForCaret6); QString afniExtensionString; firstVolume->afniHeader.writeToNiftiExtension(afniExtensionString, &hdr); // Make sure niftiExtension length is a multiple of 16 bytes !!!!! // and that includes the "esize" and "ecode". // fill with blanks const int len = afniExtensionString.length() + 8; const int fillNeeded = 16 - (len % 16); if (fillNeeded > 0) { afniExtensionString += QString(fillNeeded, QChar(' ')); } const int afniExtensionSize = afniExtensionString.length(); // // Create the NIFTI extender and immediately follows the header // nifti1_extender extender; nifti1_extension afniExtension; afniExtension.esize = 8 + afniExtensionSize; // include size of esize/ecode afniExtension.ecode = 4; //NIFTI_ECODE_AFNI; afniExtension.edata = NULL; extender.extension[0] = 0; extender.extension[1] = 0; extender.extension[2] = 0; extender.extension[3] = 0; if (afniExtension.esize > 0) { extender.extension[0] = 1; } if (DebugControl::getDebugOn()) { std::cout << "AFNI extension len/added/after: " << len << ", " << fillNeeded << ", " << afniExtensionSize << std::endl; } // // Create the Caret extension // NiftiCaretExtension caretExtensionCreator(volumesToWrite, labelColorsForCaret6); QString caretExtensionString = caretExtensionCreator.getExtensionAsString(); // Make sure niftiExtension length is a multiple of 16 bytes !!!!! // and that includes the "esize" and "ecode". // fill with blanks const int caretExtlen = caretExtensionString.length() + 8; const int caretExtFillNeeded = 16 - (caretExtlen % 16); if (caretExtFillNeeded > 0) { caretExtensionString += QString(caretExtFillNeeded, QChar(' ')); } const int caretExtensionSize = caretExtensionString.length(); nifti1_extension caretExtension; caretExtension.esize = 8 + caretExtensionSize; caretExtension.ecode = 30; caretExtension.edata = NULL; // // Data offset is size of header // hdr.vox_offset = hdr.sizeof_hdr + sizeof(nifti1_extender); if (afniExtension.esize > 0) { hdr.vox_offset += sizeof(afniExtension.esize) + sizeof(afniExtension.ecode) + afniExtensionSize; } if (caretExtension.esize > 0) { hdr.vox_offset += sizeof(caretExtension.esize) + sizeof(caretExtension.ecode) + caretExtensionSize; } // // Is file being written compressed // const bool zipDataFileFlag = (firstVolume->filename.right(3) == ".gz"); // // NIFTI stored in one file // firstVolume->dataFileName = firstVolume->filename; // // Open the data file // gzFile zipFile = NULL; std::ofstream* cppFile = NULL; if (zipDataFileFlag) { zipFile = gzopen(firstVolume->filename.toAscii().constData(), "wb"); if (zipFile == NULL) { throw FileException(firstVolume->filename, "Unable to open for writing"); } } else { cppFile = new std::ofstream(firstVolume->filename.toAscii().constData(), std::ios::out | std::ios::binary); if (cppFile == NULL) { throw FileException(firstVolume->filename, "Unable to open for writing"); } } firstVolume->dataFileWasZippedFlag = zipDataFileFlag; if (DebugControl::getDebugOn()) { std::cout << "AFNI Extension Length: " << afniExtensionString.length() << ", Size: " << afniExtensionSize; std::cout << "Caret Extension Length: " << caretExtensionString.length() << ", Size: " << caretExtensionSize; } // // Write the header // const unsigned long headerSize = sizeof(hdr); if (zipDataFileFlag) { // // Write the header // gzwrite(zipFile, (voidp)&hdr, headerSize); // // Write the extender that tells whether or not there are extensions // gzwrite(zipFile, (voidp)&extender, sizeof(extender)); // // write the afni extension // if (afniExtension.esize > 0) { gzwrite(zipFile, (voidp)&afniExtension.esize, sizeof(afniExtension.esize)); gzwrite(zipFile, (voidp)&afniExtension.ecode, sizeof(afniExtension.ecode)); gzwrite(zipFile, (voidp)afniExtensionString.toAscii().constData(), afniExtensionSize); } if (caretExtension.esize > 0) { gzwrite(zipFile, (voidp)&caretExtension.esize, sizeof(caretExtension.esize)); gzwrite(zipFile, (voidp)&caretExtension.ecode, sizeof(caretExtension.ecode)); gzwrite(zipFile, (voidp)caretExtensionString.toAscii().constData(), caretExtensionSize); } } else { // // Write the header // cppFile->write((const char*)&hdr, headerSize); // // Write the extender that tells whether or not there are extensions // cppFile->write((const char*)&extender, sizeof(extender)); // // write the afni extension // if (afniExtension.esize > 0) { cppFile->write((const char*)&afniExtension.esize, sizeof(afniExtension.esize)); cppFile->write((const char*)&afniExtension.ecode, sizeof(afniExtension.ecode)); cppFile->write((const char*)afniExtensionString.toAscii().constData(), afniExtensionSize); } if (caretExtension.esize > 0) { cppFile->write((const char*)&caretExtension.esize, sizeof(caretExtension.esize)); cppFile->write((const char*)&caretExtension.ecode, sizeof(caretExtension.ecode)); cppFile->write((const char*)caretExtensionString.toAscii().constData(), caretExtensionSize); } } // // Write the volume data // QString writeErrorMessage; for (int i = 0; i < numSubVolumes; i++) { try { volumesToWrite[i]->writeVolumeFileData(firstVolume->voxelDataType, false, zipDataFileFlag, zipFile, cppFile, hdr.scl_slope); } catch (FileException& e) { writeErrorMessage = e.whatQString(); break; } } // // Close the data file // if (zipDataFileFlag) { gzclose(zipFile); } else { cppFile->close(); delete cppFile; } if (writeErrorMessage.isEmpty() == false) { throw FileException(firstVolume->filename, writeErrorMessage); } } /** * write the specified SPM sub-volumes. */ void VolumeFile::writeFileSPM(const QString& fileNameIn, const VOXEL_DATA_TYPE writeVoxelDataTypeIn, std::vector& volumesToWrite, const bool analyzeFlag) throw (FileException) { const int numSubVolumes = static_cast(volumesToWrite.size()); if (numSubVolumes <= 0) { throw FileException(fileNameIn, "No volume data to write."); } // // Get the first volume // VolumeFile* firstVolume = volumesToWrite[0]; firstVolume->filename = fileNameIn; firstVolume->voxelDataType = writeVoxelDataTypeIn; // // check volume type for compaibility // switch(firstVolume->volumeType) { case VOLUME_TYPE_ANATOMY: break; case VOLUME_TYPE_FUNCTIONAL: break; case VOLUME_TYPE_PAINT: throw FileException(firstVolume->filename, "Paint Volume cannot be written to an SPM/MEDx file."); break; case VOLUME_TYPE_PROB_ATLAS: throw FileException(firstVolume->filename, "Prob Atlas Volume cannot be written to an Analyze file."); break; case VOLUME_TYPE_RGB: firstVolume->voxelDataType = VOXEL_DATA_TYPE_RGB_SLICE_INTERLEAVED; break; case VOLUME_TYPE_ROI: break; case VOLUME_TYPE_SEGMENTATION: break; case VOLUME_TYPE_VECTOR: break; case VOLUME_TYPE_UNKNOWN: //throw FileException(firstVolume->filename, "Unknown type of volume."); break; } // // Analyze header structure // struct dsr hdr; memset((void*)&hdr, 0, sizeof(struct dsr)); // // Set the size of the header // hdr.hk.sizeof_hdr = sizeof(struct dsr); hdr.hk.regular = 'r'; // // dimensions // hdr.dime.dim[0] = 3; hdr.dime.dim[1] = firstVolume->dimensions[0]; hdr.dime.dim[2] = firstVolume->dimensions[1]; hdr.dime.dim[3] = firstVolume->dimensions[2]; hdr.dime.dim[4] = 1; if (numSubVolumes > 1) { hdr.dime.dim[0]++; hdr.dime.dim[hdr.dime.dim[0]] = numSubVolumes; } // // Minimum and Maximum voxel // float mins, maxs; firstVolume->getMinMaxVoxelValues(mins, maxs); hdr.dime.glmax = static_cast(mins); hdr.dime.glmin = static_cast(maxs); // // Verify data type is supported // switch (firstVolume->voxelDataType) { case VOXEL_DATA_TYPE_CHAR_UNSIGNED: hdr.dime.datatype = 2; hdr.dime.bitpix = 8; break; case VOXEL_DATA_TYPE_SHORT: hdr.dime.datatype = 4; hdr.dime.bitpix = 16; break; case VOXEL_DATA_TYPE_INT: hdr.dime.datatype = 8; hdr.dime.bitpix = 32; break; case VOXEL_DATA_TYPE_FLOAT: hdr.dime.datatype = 16; hdr.dime.bitpix = 32; break; case VOXEL_DATA_TYPE_DOUBLE: hdr.dime.datatype = 64; hdr.dime.bitpix = 64; break; case VOXEL_DATA_TYPE_RGB_VOXEL_INTERLEAVED: hdr.dime.datatype = 128; hdr.dime.bitpix = 24; hdr.dime.glmax = 255; hdr.dime.glmin = 0; break; case VOXEL_DATA_TYPE_RGB_SLICE_INTERLEAVED: hdr.dime.datatype = 128; hdr.dime.bitpix = 24; hdr.dime.glmax = 255; hdr.dime.glmin = 0; break; case VOXEL_DATA_TYPE_UNKNOWN: throw FileException(firstVolume->filename, "Data Type is Unknown"); break; case VOXEL_DATA_TYPE_CHAR: throw FileException(firstVolume->filename, "Data Type CHAR is not supported by Analyze"); break; case VOXEL_DATA_TYPE_SHORT_UNSIGNED: throw FileException(firstVolume->filename, "Data Type SHORT UNSIGNED is not supported by Analyze"); break; case VOXEL_DATA_TYPE_INT_UNSIGNED: throw FileException(firstVolume->filename, "Data Type INT UNSIGNED is not supported by Analyze"); break; case VOXEL_DATA_TYPE_LONG: throw FileException(firstVolume->filename, "Data Type LONG is not supported by Analyze"); break; case VOXEL_DATA_TYPE_LONG_UNSIGNED: throw FileException(firstVolume->filename, "Data Type LONG UNSIGNED is not supported by Analyze"); break; case VOXEL_DATA_TYPE_VECTOR: hdr.dime.datatype = 16; hdr.dime.bitpix = 32; break; } // // voxel sizes // hdr.dime.pixdim[0] = 3; hdr.dime.pixdim[1] = firstVolume->spacing[0]; hdr.dime.pixdim[2] = firstVolume->spacing[1]; hdr.dime.pixdim[3] = firstVolume->spacing[2]; if (analyzeFlag == false) { // // Is the volume being made LPI with true coordinates // if ((firstVolume->spacing[0] != 0.0) && (firstVolume->spacing[1] != 0.0) && (firstVolume->spacing[2] != 0.0)) { short spmAcShort[5] = { 0, 0, 0, 0, 0 }; spmAcShort[0] = static_cast(-(firstVolume->origin[0] / firstVolume->spacing[0])) + 1; spmAcShort[1] = static_cast(-(firstVolume->origin[1] / firstVolume->spacing[1])) + 1; spmAcShort[2] = static_cast(-(firstVolume->origin[2] / firstVolume->spacing[2])) + 1; // // Need to use memcpy since "hdr.hist.originator" is on odd byte boundary // memcpy(hdr.hist.originator, spmAcShort, 10); } //} // // voxel scaling // hdr.dime.funused1 = 1.0; //scaleSlope[0]; } // // Offset of image data // hdr.dime.vox_offset = 0.0; // // Planar orientation // hdr.hist.orient = 0; // // Voxel units // //strcpy(hdr.dime.vox_units, "mm"); // // Comment // const QString comm(firstVolume->getHeaderTag(headerTagComment)); if (comm.isEmpty() == false) { int len = comm.length(); if (len > 79) { len = 79; } for (int i = 0; i < len; i++) { hdr.hist.descrip[i] = comm[i].toAscii(); } hdr.hist.descrip[len] = '\0'; } // // Write the header // std::ofstream headerFile(firstVolume->filename.toAscii().constData(), std::ios::out | std::ios::binary); if (!headerFile) { throw FileException(firstVolume->filename, "Unable to open for writing."); } const unsigned long headerSize = sizeof(hdr); headerFile.write((const char*)&hdr, headerSize); headerFile.close(); // // Update file permissions ? // if (getFileWritePermissions() != 0) { QFile::setPermissions(firstVolume->filename, getFileWritePermissions()); } // // Create the name of the data file // firstVolume->dataFileName = FileUtilities::filenameWithoutExtension(firstVolume->filename); firstVolume->dataFileName.append(".img"); // // Open the data file // std::ofstream* cppFile = new std::ofstream(firstVolume->dataFileName.toAscii().constData(), std::ios::out | std::ios::binary); if (cppFile == NULL) { throw FileException(firstVolume->dataFileName, "Unable to open for writing"); } // // Write the volume data // QString writeErrorMessage; for (int i = 0; i < numSubVolumes; i++) { try { volumesToWrite[i]->writeVolumeFileData(firstVolume->voxelDataType, false, false, NULL, cppFile, 1.0); } catch (FileException& e) { writeErrorMessage = e.whatQString(); break; } } // // Close the data file // cppFile->close(); delete cppFile; if (writeErrorMessage.isEmpty() == false) { throw FileException(firstVolume->dataFileName, writeErrorMessage); } // // Update file permissions ? // if (getFileWritePermissions() != 0) { QFile::setPermissions(firstVolume->dataFileName, getFileWritePermissions()); } } /** * write the specified WU NIL sub-volumes. */ void VolumeFile::writeFileWuNil(const QString& fileNameIn, const VOXEL_DATA_TYPE writeVoxelDataTypeIn, std::vector& volumesToWrite) throw (FileException) { const int numSubVolumes = static_cast(volumesToWrite.size()); if (numSubVolumes <= 0) { throw FileException(fileNameIn, "No volume data to write."); } if (numSubVolumes > 1) { throw FileException(fileNameIn, "Multiple subvolumes not supported for WU NIL volume files."); } // // Get the first volume // VolumeFile* firstVolume = volumesToWrite[0]; firstVolume->filename = fileNameIn; firstVolume->voxelDataType = writeVoxelDataTypeIn; switch(firstVolume->volumeType) { case VOLUME_TYPE_ANATOMY: break; case VOLUME_TYPE_FUNCTIONAL: break; case VOLUME_TYPE_PAINT: break; case VOLUME_TYPE_PROB_ATLAS: break; case VOLUME_TYPE_RGB: throw FileException(firstVolume->filename, "RGB Volume cannot be written to a WU-NIL file."); break; case VOLUME_TYPE_ROI: break; case VOLUME_TYPE_SEGMENTATION: break; case VOLUME_TYPE_VECTOR: break; case VOLUME_TYPE_UNKNOWN: //throw FileException(firstVolume->filename, "Unknown type of volume."); break; } // // WU-NIL files are always float // WuNilHeader wunilHeader; firstVolume->voxelDataType = VOXEL_DATA_TYPE_FLOAT; WuNilAttribute format(WuNilAttribute::NAME_NUMBER_FORMAT, "float"); wunilHeader.addAttribute(format); WuNilAttribute bpp(WuNilAttribute::NAME_NUMBER_OF_BYTES_PER_PIXEL, 4); wunilHeader.addAttribute(bpp); WuNilAttribute orient(WuNilAttribute::NAME_ORIENTATION, 2); wunilHeader.addAttribute(orient); WuNilAttribute numdim(WuNilAttribute::NAME_NUMBER_OF_DIMENSIONS, 4); wunilHeader.addAttribute(numdim); WuNilAttribute s1(WuNilAttribute::NAME_SCALING_FACTOR_1, fabs(firstVolume->spacing[0])); wunilHeader.addAttribute(s1); WuNilAttribute s2(WuNilAttribute::NAME_SCALING_FACTOR_2, fabs(firstVolume->spacing[1])); wunilHeader.addAttribute(s2); WuNilAttribute s3(WuNilAttribute::NAME_SCALING_FACTOR_3, fabs(firstVolume->spacing[2])); wunilHeader.addAttribute(s3); WuNilAttribute m1(WuNilAttribute::NAME_MATRIX_SIZE_1, firstVolume->dimensions[0]); wunilHeader.addAttribute(m1); WuNilAttribute m2(WuNilAttribute::NAME_MATRIX_SIZE_2, firstVolume->dimensions[1]); wunilHeader.addAttribute(m2); WuNilAttribute m3(WuNilAttribute::NAME_MATRIX_SIZE_3, firstVolume->dimensions[2]); wunilHeader.addAttribute(m3); WuNilAttribute m4(WuNilAttribute::NAME_MATRIX_SIZE_4, 1); wunilHeader.addAttribute(m4); const bool bigEndianFlag = (QSysInfo::ByteOrder == QSysInfo::BigEndian); if (bigEndianFlag) { WuNilAttribute byteOrder(WuNilAttribute::NAME_IMAGEDATA_BYTE_ORDER, "bigendian"); wunilHeader.addAttribute(byteOrder); } else { WuNilAttribute byteOrder(WuNilAttribute::NAME_IMAGEDATA_BYTE_ORDER, "littleendian"); wunilHeader.addAttribute(byteOrder); } float lpiorigin[3]; //firstVolume->getOriginAtCornerOfVoxel(originCorner); firstVolume->getOrigin(lpiorigin);//Tim C: corner of voxel convention discarded due to interpolation method, see read wunil float org[3], rai[3]; //find rai origin rai[0] = firstVolume->spacing[0] * (firstVolume->dimensions[0] - 1) + lpiorigin[0]; rai[1] = firstVolume->spacing[1] * (firstVolume->dimensions[1] - 1) + lpiorigin[1]; rai[2] = lpiorigin[2]; org[0] = -rai[0] + firstVolume->spacing[0] * firstVolume->dimensions[0];//this spacing gets flipped due to RAI origin org[1] = -firstVolume->spacing[1] - rai[1];//ditto org[2] = -rai[2] - firstVolume->spacing[2] * firstVolume->dimensions[2]; WuNilAttribute nc(WuNilAttribute::NAME_CENTER, org, 3); wunilHeader.addAttribute(nc); const float mmpix[3] = { fabs(firstVolume->spacing[0]), -fabs(firstVolume->spacing[1]), -fabs(firstVolume->spacing[2]) }; WuNilAttribute nm(WuNilAttribute::NAME_MMPPIX, mmpix, 3); wunilHeader.addAttribute(nm); // // Set the study metadata // WuNilAttribute md(WuNilAttribute::NAME_CARET_METADATA, firstVolume->getStudyMetaDataLinkSet().getLinkSetAsCodedText()); wunilHeader.addAttribute(md); // // set the region names (note: names zero and one are skipped since // a voxel value of one is not allowed in a WU volume). // std::vector wuRegionNames; const int numRegionNames = firstVolume->getNumberOfRegionNames(); for (int i = 2; i < numRegionNames; i++) { wuRegionNames.push_back(firstVolume->regionNames[i]); } wunilHeader.setRegionNames(wuRegionNames); // // write the header // QFile file(firstVolume->filename); if (file.open(QIODevice::WriteOnly) == false) { throw FileException(firstVolume->filename, file.errorString()); } QTextStream stream(&file); wunilHeader.writeHeader(stream); file.close(); // // Update file permissions ? // if (getFileWritePermissions() != 0) { QFile::setPermissions(firstVolume->filename, getFileWritePermissions()); } // // Create the name of the data file // firstVolume->dataFileName = FileUtilities::filenameWithoutExtension(firstVolume->filename); firstVolume->dataFileName.append(".img"); // // Open the data file // std::ofstream* cppFile = new std::ofstream(firstVolume->dataFileName.toAscii().constData(), std::ios::out | std::ios::binary); if (cppFile == NULL) { throw FileException(firstVolume->dataFileName, "Unable to open for writing"); } // // WU NIL files normally created on sun workstations which are big endian // //bool bigEndian = (QSysInfo::ByteOrder == QSysInfo::BigEndian); //const bool byteSwapFlag = (bigEndian == false); // // WU NIL volumes now support both big and little endian // const bool byteSwapFlag = false; // // Write the volume data // QString writeErrorMessage; for (int i = 0; i < numSubVolumes; i++) { try { // // Need to flip to RAI as WU volumes are always RAI // VolumeFile copyOfVolume(*volumesToWrite[i]); copyOfVolume.flip(VOLUME_AXIS_X); copyOfVolume.flip(VOLUME_AXIS_Y); copyOfVolume.writeVolumeFileData(firstVolume->voxelDataType, byteSwapFlag, false, NULL, cppFile, 1.0); } catch (FileException& e) { writeErrorMessage = e.whatQString(); break; } } // // Close the data file // cppFile->close(); delete cppFile; if (writeErrorMessage.isEmpty() == false) { throw FileException(firstVolume->dataFileName, writeErrorMessage); } // // Update file permissions ? // if (getFileWritePermissions() != 0) { QFile::setPermissions(firstVolume->dataFileName, getFileWritePermissions()); } } /** * read the volume data. */ void VolumeFile::readVolumeFileData(const bool byteSwapNeeded, const float scaleFact, const float offsetFact, gzFile dataFile) throw (FileException) { QString errorMessage; int dataSizeInBytes = 0; numberOfComponentsPerVoxel = 1; switch(voxelDataType) { case VOXEL_DATA_TYPE_CHAR: case VOXEL_DATA_TYPE_CHAR_UNSIGNED: dataSizeInBytes = 1; break; case VOXEL_DATA_TYPE_SHORT: case VOXEL_DATA_TYPE_SHORT_UNSIGNED: dataSizeInBytes = 2; break; case VOXEL_DATA_TYPE_INT: case VOXEL_DATA_TYPE_INT_UNSIGNED: dataSizeInBytes = 4; break; case VOXEL_DATA_TYPE_LONG: case VOXEL_DATA_TYPE_LONG_UNSIGNED: dataSizeInBytes = 8; break; case VOXEL_DATA_TYPE_FLOAT: dataSizeInBytes = 4; break; case VOXEL_DATA_TYPE_DOUBLE: dataSizeInBytes = 8; break; case VOXEL_DATA_TYPE_RGB_VOXEL_INTERLEAVED: dataSizeInBytes = 1; numberOfComponentsPerVoxel = 3; break; case VOXEL_DATA_TYPE_RGB_SLICE_INTERLEAVED: dataSizeInBytes = 1; numberOfComponentsPerVoxel = 3; break; case VOXEL_DATA_TYPE_VECTOR: dataSizeInBytes = 4; numberOfComponentsPerVoxel = 4; break; case VOXEL_DATA_TYPE_UNKNOWN: dataSizeInBytes = 0; break; } if (dataSizeInBytes <= 0) { errorMessage.append("Invalid data type to data type not set."); } int dimensions[3]; getDimensions(dimensions); if ((dimensions[0] <= 0) || (dimensions[1] <= 0) || (dimensions[2] <= 0)) { errorMessage.append("Dimensions must be greater than zero."); } if (errorMessage.isEmpty() == false) { throw FileException(FileUtilities::basename(dataFileName), errorMessage); } if (voxels != NULL) { delete[] voxels; voxels = NULL; } voxels = new float[getTotalNumberOfVoxelElements()]; allocateVoxelColoring(); try { switch(voxelDataType) { case VOXEL_DATA_TYPE_CHAR: readCharData(dataFile); break; case VOXEL_DATA_TYPE_CHAR_UNSIGNED: readUnsignedCharData(dataFile); break; case VOXEL_DATA_TYPE_SHORT: readShortData(dataFile, byteSwapNeeded); break; case VOXEL_DATA_TYPE_SHORT_UNSIGNED: readUnsignedShortData(dataFile, byteSwapNeeded); break; case VOXEL_DATA_TYPE_INT: readIntData(dataFile, byteSwapNeeded); break; case VOXEL_DATA_TYPE_INT_UNSIGNED: readUnsignedIntData(dataFile, byteSwapNeeded); break; case VOXEL_DATA_TYPE_LONG: readLongLongData(dataFile, byteSwapNeeded); break; case VOXEL_DATA_TYPE_LONG_UNSIGNED: readUnsignedLongLongData(dataFile, byteSwapNeeded); break; case VOXEL_DATA_TYPE_FLOAT: readFloatData(dataFile, byteSwapNeeded); break; case VOXEL_DATA_TYPE_DOUBLE: readDoubleData(dataFile, byteSwapNeeded); break; case VOXEL_DATA_TYPE_RGB_VOXEL_INTERLEAVED: readRgbDataVoxelInterleaved(dataFile); break; case VOXEL_DATA_TYPE_RGB_SLICE_INTERLEAVED: readRgbDataSliceInterleaved(dataFile); break; case VOXEL_DATA_TYPE_VECTOR: readFloatData(dataFile, byteSwapNeeded); break; case VOXEL_DATA_TYPE_UNKNOWN: throw FileException(FileUtilities::basename(dataFileName), "Unknown data type."); break; } } catch (FileException& e) { throw e; } if ((voxelDataType != VOXEL_DATA_TYPE_RGB_VOXEL_INTERLEAVED) && (voxelDataType != VOXEL_DATA_TYPE_RGB_SLICE_INTERLEAVED)) { // // Note: Raw volumes do not have scale factors // float scaledMin = voxels[0] * scaleFact + offsetFact; float scaledMax = voxels[0] * scaleFact + offsetFact; float unscaledMin = voxels[0]; float unscaledMax = voxels[0]; const int totalNum = getTotalNumberOfVoxelElements(); for (int i = 0; i < totalNum; i++) { float s = voxels[i]; if (s < unscaledMin) unscaledMin = s; if (s > unscaledMax) unscaledMax = s; if (scaleFact != 0.0) { s *= scaleFact; } s += offsetFact; if (s < scaledMin) scaledMin = s; if (s > scaledMax) scaledMax = s; voxels[i] = s; } if (DebugControl::getDebugOn()) { std::cout << "Unscaled range: " << unscaledMin << " " << unscaledMax << std::endl; std::cout << "Scaled range: " << scaledMin << " " << scaledMax << std::endl; } } // // WuNil volume data for paint file starts at 2 // if ((fileReadType == FILE_READ_WRITE_TYPE_WUNIL) && ((volumeType == VOLUME_TYPE_PAINT) || (volumeType == VOLUME_TYPE_PROB_ATLAS))) { const int totalNum = getTotalNumberOfVoxelElements(); for (int i = 0; i < totalNum; i++) { float val = voxels[i]; if (val > 0.0) { val += 1.0; voxels[i] = val; } } } // // Should the volume be made LPI // switch (volumeSpace) { case VOLUME_SPACE_COORD_LPI: if (isValidOrientation(orientation)) { ORIENTATION newOrient[3] = { ORIENTATION_LEFT_TO_RIGHT, ORIENTATION_POSTERIOR_TO_ANTERIOR, ORIENTATION_INFERIOR_TO_SUPERIOR }; try { permuteToOrientation(newOrient); } catch (FileException& e) { } // // Adjustment made for WU's IFH (28 April 2005) // //if (fileReadType == FILE_READ_WRITE_TYPE_WUNIL) { // origin[0] += 1.0; // origin[1] += 1.0; // origin[2] += 1.0; //} } break; case VOLUME_SPACE_VOXEL_NATIVE: //{ // const float zeros[3] = { 0.0, 0.0, 0.0 }; // setOrigin(zeros); // if (fileReadType != FILE_READ_WRITE_TYPE_SPM_OR_MEDX) { // const float ones[3] = { 1.0, 1.0, 1.0 }; // setSpacing(ones); // } //} break; } clearModified(); } /** * read the volume data. */ void VolumeFile::readVolumeFileDataSubVolume(const bool byteSwapNeeded, const float scaleFact, const float offsetFact, const long dataOffset, const int subVolumeNumber, gzFile dataFile) throw (FileException) { int dataSizeInBytes = 0; numberOfComponentsPerVoxel = 1; switch(voxelDataType) { case VOXEL_DATA_TYPE_CHAR: case VOXEL_DATA_TYPE_CHAR_UNSIGNED: dataSizeInBytes = 1; break; case VOXEL_DATA_TYPE_SHORT: case VOXEL_DATA_TYPE_SHORT_UNSIGNED: dataSizeInBytes = 2; break; case VOXEL_DATA_TYPE_INT: case VOXEL_DATA_TYPE_INT_UNSIGNED: dataSizeInBytes = 4; break; case VOXEL_DATA_TYPE_LONG: case VOXEL_DATA_TYPE_LONG_UNSIGNED: dataSizeInBytes = 8; break; case VOXEL_DATA_TYPE_FLOAT: dataSizeInBytes = 4; break; case VOXEL_DATA_TYPE_DOUBLE: dataSizeInBytes = 8; break; case VOXEL_DATA_TYPE_RGB_VOXEL_INTERLEAVED: dataSizeInBytes = 1; numberOfComponentsPerVoxel = 3; break; case VOXEL_DATA_TYPE_RGB_SLICE_INTERLEAVED: dataSizeInBytes = 1; numberOfComponentsPerVoxel = 3; break; case VOXEL_DATA_TYPE_VECTOR: dataSizeInBytes = 4; numberOfComponentsPerVoxel = 4; break; case VOXEL_DATA_TYPE_UNKNOWN: dataSizeInBytes = 0; break; } // // Determine the offset // const z_off_t offset = (subVolumeNumber * dataSizeInBytes * numberOfComponentsPerVoxel * dimensions[0] * dimensions[1] * dimensions[2]) + dataOffset; if (DebugControl::getDebugOn()) { std::cout << "Data offset: " << offset << std::endl; } // // read the data // gzseek(dataFile, offset, SEEK_SET); readVolumeFileData(byteSwapNeeded, scaleFact, offsetFact, dataFile); } /** * write the volume data. */ void VolumeFile::writeVolumeFileData(const VOXEL_DATA_TYPE voxelDataTypeForWriting, const bool byteSwapNeeded, const bool compressDataWithZlib, gzFile zipStream, std::ofstream* cppStream, const float divideByThisValue) throw (FileException) { if (voxelDataType == VOXEL_DATA_TYPE_UNKNOWN) { throw FileException("Unknown data type for writing."); } // // Write the data // const int numVoxels = getTotalNumberOfVoxels(); switch(voxelDataTypeForWriting) { case VOXEL_DATA_TYPE_CHAR: { char* data = new char[numVoxels]; for (int i = 0; i < numVoxels; i++) { data[i] = static_cast(voxels[i] / divideByThisValue); } if (compressDataWithZlib) { gzwrite(zipStream, (void*)data, numVoxels * sizeof(char)); } else { cppStream->write((const char*)data, numVoxels * sizeof(char)); } delete[] data; } break; case VOXEL_DATA_TYPE_CHAR_UNSIGNED: { unsigned char* data = new unsigned char[numVoxels]; for (int i = 0; i < numVoxels; i++) { data[i] = static_cast(voxels[i] / divideByThisValue); } if (compressDataWithZlib) { gzwrite(zipStream, (void*)data, numVoxels * sizeof(unsigned char)); } else { cppStream->write((const char*)data, numVoxels * sizeof(unsigned char)); } delete[] data; } break; case VOXEL_DATA_TYPE_SHORT: { short* data = new short[numVoxels]; for (int i = 0; i < numVoxels; i++) { data[i] = static_cast(voxels[i] / divideByThisValue); } if (byteSwapNeeded) { ByteSwapping::swapBytes(data, numVoxels); } if (compressDataWithZlib) { gzwrite(zipStream, (void*)data, numVoxels * sizeof(short)); } else { cppStream->write((const char*)data, numVoxels * sizeof(short)); } delete[] data; } break; case VOXEL_DATA_TYPE_SHORT_UNSIGNED: { unsigned short* data = new unsigned short[numVoxels]; for (int i = 0; i < numVoxels; i++) { data[i] = static_cast(voxels[i] / divideByThisValue); } if (byteSwapNeeded) { ByteSwapping::swapBytes(data, numVoxels); } if (compressDataWithZlib) { gzwrite(zipStream, (void*)data, numVoxels * sizeof(unsigned short)); } else { cppStream->write((const char*)data, numVoxels * sizeof(unsigned short)); } delete[] data; } break; case VOXEL_DATA_TYPE_INT: { int* data = new int[numVoxels]; for (int i = 0; i < numVoxels; i++) { data[i] = static_cast(voxels[i] / divideByThisValue); } if (byteSwapNeeded) { ByteSwapping::swapBytes(data, numVoxels); } if (compressDataWithZlib) { gzwrite(zipStream, (void*)data, numVoxels * sizeof(int)); } else { cppStream->write((const char*)data, numVoxels * sizeof(int)); } delete[] data; } break; case VOXEL_DATA_TYPE_INT_UNSIGNED: { unsigned int* data = new unsigned int[numVoxels]; for (int i = 0; i < numVoxels; i++) { data[i] = static_cast(voxels[i] / divideByThisValue); } if (byteSwapNeeded) { ByteSwapping::swapBytes(data, numVoxels); } if (compressDataWithZlib) { gzwrite(zipStream, (void*)data, numVoxels * sizeof(unsigned int)); } else { cppStream->write((const char*)data, numVoxels * sizeof(unsigned int)); } delete[] data; } break; case VOXEL_DATA_TYPE_LONG: { long long* data = new long long[numVoxels]; for (int i = 0; i < numVoxels; i++) { data[i] = static_cast(voxels[i] / divideByThisValue); } if (byteSwapNeeded) { ByteSwapping::swapBytes(data, numVoxels); } if (compressDataWithZlib) { gzwrite(zipStream, (void*)data, numVoxels * sizeof(long long)); } else { cppStream->write((const char*)data, numVoxels * sizeof(long long)); } delete[] data; } break; case VOXEL_DATA_TYPE_LONG_UNSIGNED: { unsigned long long* data = new unsigned long long[numVoxels]; for (int i = 0; i < numVoxels; i++) { data[i] = static_cast(voxels[i] / divideByThisValue); } if (byteSwapNeeded) { ByteSwapping::swapBytes(data, numVoxels); } if (compressDataWithZlib) { gzwrite(zipStream, (void*)data, numVoxels * sizeof(unsigned long long)); } else { cppStream->write((const char*)data, numVoxels * sizeof(unsigned long long)); } delete[] data; } break; case VOXEL_DATA_TYPE_FLOAT: { float* data = new float[numVoxels]; for (int i = 0; i < numVoxels; i++) { data[i] = static_cast(voxels[i] / divideByThisValue); } if (byteSwapNeeded) { ByteSwapping::swapBytes(data, numVoxels); } if (compressDataWithZlib) { gzwrite(zipStream, (void*)data, numVoxels * sizeof(float)); } else { cppStream->write((const char*)data, numVoxels * sizeof(float)); } delete[] data; } break; case VOXEL_DATA_TYPE_DOUBLE: { double* data = new double[numVoxels]; for (int i = 0; i < numVoxels; i++) { data[i] = static_cast(voxels[i] / divideByThisValue); } if (byteSwapNeeded) { ByteSwapping::swapBytes(data, numVoxels); } if (compressDataWithZlib) { gzwrite(zipStream, (void*)data, numVoxels * sizeof(double)); } else { cppStream->write((const char*)data, numVoxels * sizeof(double)); } delete[] data; } break; case VOXEL_DATA_TYPE_RGB_VOXEL_INTERLEAVED: { unsigned char* data = new unsigned char[numVoxels * 3]; for (int i = 0; i < numVoxels; i++) { data[i*3] = static_cast(voxels[i*3]); data[i*3+1] = static_cast(voxels[i*3+1]); data[i*3+2] = static_cast(voxels[i*3+2]); } if (compressDataWithZlib) { gzwrite(zipStream, (void*)data, numVoxels * 3 * sizeof(unsigned char)); } else { cppStream->write((const char*)data, numVoxels * 3 * sizeof(unsigned char)); } delete[] data; } break; case VOXEL_DATA_TYPE_RGB_SLICE_INTERLEAVED: { unsigned char* data = new unsigned char[numVoxels * 3]; int ctr = 0; for (int k = 0; k < dimensions[2]; k++) { for (int n = 0; n < 3; n++) { for (int j = 0; j < dimensions[1]; j++) { for (int i = 0; i < dimensions[0]; i++) { int ijk[3] = { i, j, k }; const int id = getVoxelDataIndex(ijk, n); data[ctr] = static_cast(voxels[id]); ctr++; } } } } if (compressDataWithZlib) { gzwrite(zipStream, (void*)data, numVoxels * 3 * sizeof(unsigned char)); } else { cppStream->write((const char*)data, numVoxels * 3 * sizeof(unsigned char)); } delete[] data; } break; case VOXEL_DATA_TYPE_VECTOR: { float* data = new float[numVoxels]; for (int i = 0; i < numVoxels; i++) { data[i] = static_cast(voxels[i] / divideByThisValue); } if (byteSwapNeeded) { ByteSwapping::swapBytes(data, numVoxels); } if (compressDataWithZlib) { gzwrite(zipStream, (void*)data, numVoxels * sizeof(float)); } else { cppStream->write((const char*)data, numVoxels * sizeof(float)); } delete[] data; } break; case VOXEL_DATA_TYPE_UNKNOWN: throw FileException("Unknown data type for writing."); break; } } /** * perform uniformity correction with AFNI 3duniformize. */ void VolumeFile::afniUniformityCorrection(const int grayMin, const int whiteMax, const int iterations) throw (FileException) { throw FileException("PROGRAMMER: use biasCorrectionWithAFNI() instead of afniUniformityCorrection"); // // Make sure program exists // const QString programName("3duniformize"); if (SystemUtilities::externalProgramExists(programName) == false) { throw FileException("AFNI program \"" + programName + "\" not found in PATH."); } // // Copy "this" volume // VolumeFile volumeCopy(*this); // // Create temporary names for input and output // QString inputName("caret-3d-uniform-input+orig.HEAD"); QString inputNameData("caret-3d-uniform-input+orig.BRIK"); QString outputPrefix("caret-3d-uniform-output"); QString outputName(outputPrefix + "+orig.HEAD"); QString outputNameData(outputPrefix + "+orig.BRIK"); // // Make sure output files do not exist // QFile::remove(outputName); QFile::remove(outputNameData); // // Write out volume with temporary name and short data type // std::vector volumes; volumes.push_back(&volumeCopy); VolumeFile::writeFile(inputName, getVolumeType(), VolumeFile::VOXEL_DATA_TYPE_SHORT, volumes); // // Arguments to run program // QStringList args; args << "-clip_low" << QString::number(grayMin) << "-clip_high" << QString::number(whiteMax) << "-niter" << QString::number(iterations) << "-prefix" << outputPrefix << "-anat" << inputName; // // Create and run the QProcess to execute the program // QProcess uniform; uniform.start(programName, args); uniform.waitForStarted(); uniform.waitForFinished(); // // See if program was successful // if ((uniform.exitStatus() == QProcess::NormalExit) && (uniform.error() == QProcess::UnknownError)) { if (DebugControl::getDebugOn()) { std::cout << "3duniformize output:" << std::endl; std::cout << " stdout: " << QString(uniform.readAllStandardOutput()).toAscii().constData() << std::endl; std::cout << " stderr: " << QString(uniform.readAllStandardError()).toAscii().constData() << std::endl; } // // Read the output of the program // volumeCopy.readFile(outputName); // // Copy the voxels // const int num = volumeCopy.getTotalNumberOfVoxels(); for (int i = 0; i < num; i++) { setVoxelWithFlatIndex(i, 0, volumeCopy.getVoxelWithFlatIndex(i)); } stretchVoxelValues(); setVoxelColoringInvalid(); // // Clean up // QFile::remove(inputName); QFile::remove(inputNameData); QFile::remove(outputName); QFile::remove(outputNameData); } else { QString msg(uniform.readAllStandardError() + "\n\n" + uniform.readAllStandardOutput()); throw FileException(msg); } } /** * set study meta data link. */ /* void VolumeFile::setStudyMetaDataLinkSet(const StudyMetaDataLinkSet& smdls) { studyMetaDataLinkSet = smdls; setModified(); } */ /** * get NIFTI intention and tr. */ void VolumeFile::getNiftiInfo(QString& intentCodeAndParamStringOut, QString& intentNameOut, int& intentCodeOut, float& intentParameter1Out, float& intentParameter2Out, float& intentParameter3Out, float &trOut) const { intentCodeAndParamStringOut = niftiIntentCodeAndParamString; intentNameOut = niftiIntentName; intentCodeOut = niftiIntentCode; intentParameter1Out = niftiIntentParameter1; intentParameter2Out = niftiIntentParameter2; intentParameter3Out = niftiIntentParameter3; trOut = niftiTR; } /** * compare a file for unit testing (returns true if "within tolerance"). */ bool VolumeFile::compareFileForUnitTesting(const AbstractFile* af, const float tolerance, QString& messageOut) const { messageOut = ""; const VolumeFile* vf = dynamic_cast(af); if (vf == NULL) { messageOut += "ERROR: File for comparison is not a Volume File.\n"; return false; } bool compareVoxelsFlag = true; if ((dimensions[0] != vf->dimensions[0]) || (dimensions[1] != vf->dimensions[1]) || (dimensions[2] != vf->dimensions[2])) { messageOut += "ERROR: The volumes have a different number dimensions.\n"; compareVoxelsFlag = false; } if ((orientation[0] != vf->orientation[0]) || (orientation[1] != vf->orientation[1]) || (orientation[2] != vf->orientation[2])) { messageOut += "ERROR: The volumes have different orientations.\n"; } if ((origin[0] != vf->origin[0]) || (origin[1] != vf->origin[1]) || (origin[2] != vf->origin[2])) { messageOut += "ERROR: The volumes have different origins.\n"; } if ((spacing[0] != vf->spacing[0]) || (spacing[1] != vf->spacing[1]) || (spacing[2] != vf->spacing[2])) { messageOut += "ERROR: The volumes have different voxel sizes.\n"; } if (compareVoxelsFlag) { const int numVoxels = getTotalNumberOfVoxelElements(); if (numVoxels == vf->getTotalNumberOfVoxelElements()) { int diffCount = 0; for (int i = 0; i < numVoxels; i++) { float diff = (getVoxelWithFlatIndex(i) - vf->getVoxelWithFlatIndex(i)); if (diff < 0) diff = -diff; if (diff > tolerance) { diffCount++; } } if (diffCount > 0) { messageOut += "ERROR: There are " + QString::number(diffCount) + " voxels with a difference that are greater than " + QString::number(tolerance, 'f', 3) + "\n"; } } else { messageOut += "ERROR: The volumes have a different number of voxels.\n"; } } return messageOut.isEmpty(); } /** * Find each of the disconnect objects (islands) within the volume. * A voxel is considered part of the segmentation if its value is greater than or equal to one. */ void VolumeFile::findObjectsWithinSegmentationVolume(std::vector& objectsOut) const { objectsOut.clear(); VoxelIJK bigSeed(-1, -1, -1); int imin = 0; int imax = 0; int jmin = 0; int jmax = 0; int kmin = 0; int kmax = 0; getDimensions(imax, jmax, kmax); // // Make sure search region is within the volume // clampVoxelDimension(VOLUME_AXIS_X, imin); clampVoxelDimension(VOLUME_AXIS_X, imax); clampVoxelDimension(VOLUME_AXIS_Y, jmin); clampVoxelDimension(VOLUME_AXIS_Y, jmax); clampVoxelDimension(VOLUME_AXIS_Z, kmin); clampVoxelDimension(VOLUME_AXIS_Z, kmax); const int numVoxels = getTotalNumberOfVoxels(); const float minValue = 1.0; const float maxValue = std::numeric_limits::max(); // // single slice ? // if ((imin == imax) || (jmin == jmax) || (kmin == kmax)) { if (DebugControl::getDebugOn()) { std::cout << "For x, y or z, min = max" << std::endl; } } else { // // Create a flag for noting which voxels have been searched. // Mark those within region and within min and max values NOT SEARCHED // and all others SEARCHED. // VOXEL_SEARCH_STATUS* voxelSearched = new VOXEL_SEARCH_STATUS[numVoxels]; for (int k = 0; k < dimensions[2]; k++) { for (int j = 0; j < dimensions[1]; j++) { for (int i = 0; i < dimensions[0]; i++) { const int idx = getVoxelDataIndex(i, j, k); voxelSearched[idx] = VOXEL_SEARCHED; if ((i >= imin) && (i < imax) && (j >= jmin) && (j < jmax) && (k >= kmin) && (k < kmax)) { if ((voxels[idx] >= minValue) && (voxels[idx] <= maxValue)) { voxelSearched[idx] = VOXEL_NOT_SEARCHED; } } } } } // // Find a voxel within value range that has not been searched // VoxelIJK seedVoxel; bool voxelFound = findUnsearchedVoxel(minValue, maxValue, voxelSearched, seedVoxel); if (voxelFound == false) { if (DebugControl::getDebugOn()) { std::cout << "FindBiggestObjectWithinMask no initial voxel found with values: " << minValue << " " << maxValue << std::endl; } } // // Loop through all objects // while (voxelFound) { // // Create a stack // std::stack stack; stack.push(seedVoxel); // // Stores voxels in the object // VoxelGroup voxelGroupObject; // // While there are voxels to search // while (stack.empty() == false) { // // Get the next voxel to search // const VoxelIJK v = stack.top(); stack.pop(); const int idx = getVoxelDataIndex(v.getIJK()); if (voxelSearched[idx] == VOXEL_NOT_SEARCHED) { voxelSearched[idx] = VOXEL_SEARCHED; // // Add voxel to group // voxelGroupObject.addVoxel(v); // // Get the neighboring voxels // std::vector neighbors; getNeighbors(v, neighbors); // // Add neighbors to stack // for (unsigned int i = 0; i < neighbors.size(); i++) { VoxelIJK& v = neighbors[i]; const int idx = getVoxelDataIndex(v.getIJK()); if (voxelSearched[idx] == VOXEL_NOT_SEARCHED) { stack.push(v); } } } } // while (stack.isEmpty() == false) // // Was an object found // if (voxelGroupObject.getNumberOfVoxels()) { objectsOut.push_back(voxelGroupObject); } // // Find another voxel to search // voxelFound = findUnsearchedVoxel(minValue, maxValue, voxelSearched, seedVoxel); } // while (voxelFound) delete[] voxelSearched; } } /** * bias correction using AFNI's 3dUniformize code. */ void VolumeFile::biasCorrectionWithAFNI(const int grayMinimumIn, const int whiteMaximumIn, const int numberOfIterations) throw (FileException) { int grayMinimum = grayMinimumIn; int whiteMaximum = whiteMaximumIn; // // Get range of input voxels // float minVoxel, maxVoxel; getMinMaxVoxelValues(minVoxel, maxVoxel); // // Get value of gray and white relative to minimum value // const float diff = maxVoxel - minVoxel; const float grayRelative = (static_cast(grayMinimum) - minVoxel) / diff; const float whiteRelative = (static_cast(whiteMaximum) - minVoxel) / diff; // // stretch out the voxels // const float maxStretchValue = 255.0; rescaleVoxelValues(minVoxel, maxVoxel, 0.0, maxStretchValue); //stretchVoxelValues(); // // Remap gray and white values // grayMinimum = static_cast(grayRelative * maxStretchValue); whiteMaximum = static_cast(whiteRelative * maxStretchValue); // // Use AFNI's bias correction algorithm // biasCorrectVolume(this, grayMinimum, whiteMaximum, numberOfIterations); // // Stretch the voxels values excluding 1% at each extreme // stretchVoxelValuesExcludePercentage(1.0, 1.0); // // Invalidate coloring since voxel values changed // setVoxelColoringInvalid(); } /** * get data file name for read error (if data file name empty, return file name). */ QString VolumeFile::getDataFileNameForReadError() const { QString name = dataFileName; if (name.isEmpty()) { name = getFileName(); } name = FileUtilities::basename(name); return name; } /** * Write the file's memory in caret6 format to the specified name. */ QString VolumeFile::writeFileInCaret6Format(const QString& filenameIn, Structure structure,const ColorFile* colorFileIn, const bool useCaret6ExtensionFlag) throw (FileException) { // // The generic method to read a volume file only reads the first volume // so read again to get all volumes // QString nameToRead = this->getFileName(); std::vector volumes; VolumeFile::readFile(nameToRead, VOLUME_READ_SELECTION_ALL, volumes, false); if (volumes.size() > 0) { QString name = filenameIn; if (useCaret6ExtensionFlag) { if (name.endsWith(SpecFile::getNiftiGzipVolumeFileExtension()) == false) { if (name.endsWith(SpecFile::getAfniVolumeFileExtension())) { name = FileUtilities::replaceExtension(filenameIn, SpecFile::getAfniVolumeFileExtension(), SpecFile::getNiftiGzipVolumeFileExtension()); } else if (name.endsWith(SpecFile::getAnalyzeVolumeFileExtension())) { name = FileUtilities::replaceExtension(filenameIn, SpecFile::getAnalyzeVolumeFileExtension(), SpecFile::getNiftiGzipVolumeFileExtension()); } else if (name.endsWith(SpecFile::getNiftiVolumeFileExtension())) { name = FileUtilities::replaceExtension(filenameIn, SpecFile::getNiftiVolumeFileExtension(), SpecFile::getNiftiGzipVolumeFileExtension()); } else if (name.endsWith(SpecFile::getWustlVolumeFileExtension())) { name = FileUtilities::replaceExtension(filenameIn, SpecFile::getWustlVolumeFileExtension(), SpecFile::getNiftiGzipVolumeFileExtension()); } else { name = FileUtilities::replaceExtension(filenameIn, "XXXXXXXXXXXXXXXXXXXXXXXXXXXX", SpecFile::getNiftiGzipVolumeFileExtension()); } } } VOLUME_TYPE volumeType = volumes[0]->getVolumeType(); VOXEL_DATA_TYPE voxelDataType = volumes[0]->getVoxelDataType(); VolumeFile::writeFile(name, volumeType, voxelDataType, volumes, true, colorFileIn); return name; } return ""; } caret-5.6.4~dfsg.1.orig/caret_files/VocabularyFile.h0000664000175000017500000002647511572067322022137 0ustar michaelmichael #ifndef __VOCABULARY_FILE_H__ #define __VOCABULARY_FILE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "AbstractFile.h" #include "CellStudyInfo.h" #include "StudyMetaDataLinkSet.h" class QDomNode; class XmlGenericWriter; /// class for storing vocabulary information class VocabularyFile : public AbstractFile { public: /// stores vocabulary data entry class VocabularyEntry { public: // constructor VocabularyEntry(); // constructor VocabularyEntry(const QString& abbreviationIn, const QString& fullNameIn = "", const QString& classNameIn = "", const QString& vocabularyIDIn = "", const QString& descriptionIn = "", const QString& ontologySourceIn = "", const QString& termIDIn = "", const int studyNumberIn = -1); // copy constructor VocabularyEntry(const VocabularyEntry& ve); // assignment operator VocabularyEntry& operator=(const VocabularyEntry& ve); // destructor ~VocabularyEntry(); // get full description of all fields for display to user //QString getFullDescriptionForDisplayToUser(const bool useHTML) const; /// get the abbreviation QString getAbbreviation() const { return abbreviation; } // set the abbreviation void setAbbreviation(const QString& a); /// get the full name QString getFullName() const { return fullName; } // set the full name void setFullName(const QString& n); /// get the description QString getDescription() const { return description; } // set the description void setDescription(const QString& d); /// get the class name QString getClassName() const { return className; } // set the class name void setClassName(const QString& s); /// get the ontology source QString getOntologySource() const { return ontologySource; } /// set the ontology source void setOntologySource(const QString& s); // get ontology source values static void getOntologySourceValues(std::vector& ontologySourceValues); /// get the term id QString getTermID() const { return termID; } /// set the term id void setTermID(const QString& s); /// get the vocabulary ID QString getVocabularyID() const { return vocabularyID; } // set the vocabulary ID void setVocabularyID(const QString& s); /// get the study number int getStudyNumber() const { return studyNumber; } // set the study number void setStudyNumber(const int sn); /// get the study metadata link set StudyMetaDataLinkSet getStudyMetaDataLinkSet() const { return studyMetaDataLinkSet; } /// set the study metadata link set void setStudyMetaDataLinkSet(const StudyMetaDataLinkSet smdls); /// write the data into a StringTable static void writeDataIntoStringTable(const std::vector& data, StringTable& table); /// read the data from a StringTable static void readDataFromStringTable(std::vector& data, const StringTable& table) throw (FileException); protected: // copy helper void copyHelper(const VocabularyEntry& ve); // clear this item void clear(); // set this item modified void setModified(); // called to read from an XML structure. void readXML(QDomNode& nodeIn) throw (FileException); // called to write to an XML structure. void writeXML(QDomDocument& xmlDoc, QDomElement& parentElement) const; // called to write XML void writeXML(XmlGenericWriter& xmlWriter) const throw (FileException); /// VocabularyFile entry with which this is association VocabularyFile* vocabularyFile; /// the abbreviated name QString abbreviation; /// the full name QString fullName; /// the class name QString className; /// ontology source QString ontologySource; /// term id QString termID; /// the vocabulary ID QString vocabularyID; /// the description QString description; /// the study number int studyNumber; /// the study metadata link StudyMetaDataLinkSet studyMetaDataLinkSet; // ***** IF ADDITIONAL MEMBERS ADDED, UPDATE copyHelper() ********** friend class VocabularyFile; }; // constructor VocabularyFile(); // destructor ~VocabularyFile(); // add a vocabulary entry (returns its index) int addVocabularyEntry(const VocabularyEntry& ve); // delete a vocabulary entry void deleteVocabularyEntry(const int indx); // append a vocabulary file to "this" vocabulary file void append(const VocabularyFile& vf); // Clears current file data in memory. Deriving classes must override this method and // call AbstractFile::clearAbstractFile() from its clear method. void clear(); // returns true if the file is isEmpty (contains no data) bool empty() const; /// get the number of vocabulary entries int getNumberOfVocabularyEntries() const { return vocabularyEntries.size(); } // a vocabulary entry using its index VocabularyEntry* getVocabularyEntry(const int indx); // a vocabulary entry using its index (const method) const VocabularyEntry* getVocabularyEntry(const int indx) const; // get the index of a vocabulary entry from its abbreviation (-1 if not found) int getVocabularyEntryIndexFromName(const QString& abbreviationIn) const; // get a vocabulary entry from its abbreviation (NULL if not found) VocabularyEntry* getVocabularyEntryByName(const QString& abbreviationIn); // get a vocabulary entry from its abbreviation (const method) const VocabularyEntry* getVocabularyEntryByName(const QString& abbreviationIn) const; // get the best matching vocabulary entry (abbreviationIn begins with entry name) VocabularyEntry* getBestMatchingVocabularyEntry(const QString abbreviationIn, const bool caseSensitive = true); // get the best matching vocabulary entry (abbreviationIn begins with entry name) const VocabularyEntry* getBestMatchingVocabularyEntry(const QString abbreviationIn, const bool caseSensitive = true) const; /// find out if comma separated file conversion supported void getCommaSeparatedFileSupport(bool& readFromCSV, bool& writeToCSV) const; /// write the file's data into a comma separated values file (throws exception if not supported) void writeDataIntoCommaSeparatedValueFile(CommaSeparatedValueFile& csv) throw (FileException); /// read the file's data from a comma separated values file (throws exception if not supported) void readDataFromCommaSeparatedValuesTable(const CommaSeparatedValueFile& csv) throw (FileException); /// get a pointer to the study info std::vector* getPointerToStudyInfo() { return &studyInfo; } /// get number of study info int getNumberOfStudyInfo() const { return studyInfo.size(); } /// get the study info index from the study info's value int getStudyInfoFromValue(const CellStudyInfo& studyInfo) const; /// get a study info (const method) const CellStudyInfo* getStudyInfo(const int index) const; /// get a study info CellStudyInfo* getStudyInfo(const int index); /// add a study info int addStudyInfo(const CellStudyInfo& studyInfo); /// delete all study info void deleteAllStudyInfo(); /// delete study info void deleteStudyInfo(const int indx); /// set a study info void setStudyInfo(const int index, const CellStudyInfo& csi); /// get PubMedID's of all linked studies void getPubMedIDsOfAllLinkedStudyMetaData(std::vector& studyPMIDs) const; /// write the file's memory in caret6 format to the specified name virtual QString writeFileInCaret6Format(const QString& filenameIn, Structure structure,const ColorFile* colorFileIn, const bool useCaret6ExtensionFlag) throw (FileException); protected: // Read the contents of the file (header has already been read) void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& rootElement) throw (FileException); // Write the file's data (header has already been written) void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& xmlDoc, QDomElement& rootElement) throw (FileException); /// the vocabulary entries std::vector vocabularyEntries; /// the study info std::vector studyInfo; }; #endif // __VOCABULARY_FILE_H__ caret-5.6.4~dfsg.1.orig/caret_files/VocabularyFile.cxx0000664000175000017500000010275711572067322022510 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include "CommaSeparatedValueFile.h" #include "SpecFile.h" #include "StringTable.h" #include "VocabularyFile.h" #include "XmlGenericWriter.h" /** * constructor. */ VocabularyFile::VocabularyFile() : AbstractFile("Vocabulary File", SpecFile::getVocabularyFileExtension(), true, FILE_FORMAT_XML, // default format FILE_IO_NONE, // ascii format FILE_IO_NONE, // binary format FILE_IO_READ_AND_WRITE, // XML format FILE_IO_NONE, // XML base64 FILE_IO_NONE, // XML gzip base64 FILE_IO_NONE, // other format FILE_IO_READ_AND_WRITE) // csvf { } /** * destructor. */ VocabularyFile::~VocabularyFile() { } /** * add a vocabulary entry (returns its index). */ int VocabularyFile::addVocabularyEntry(const VocabularyEntry& ve) { int indx = getVocabularyEntryIndexFromName(ve.getAbbreviation()); if (indx >= 0) { VocabularyEntry* vocabExistsNow = getVocabularyEntry(indx); *vocabExistsNow = ve; } else { vocabularyEntries.push_back(ve); indx = getNumberOfVocabularyEntries() - 1; } vocabularyEntries[indx].vocabularyFile = this; setModified(); return indx; } /** * delete a vocabulary entry. */ void VocabularyFile::deleteVocabularyEntry(const int indx) { if ((indx >= 0) && (indx < getNumberOfVocabularyEntries())) { vocabularyEntries.erase(vocabularyEntries.begin() + indx); } setModified(); } /** * append a vocabulary file to "this" vocabulary file. */ void VocabularyFile::append(const VocabularyFile& vf) { const int origNumberOfStudyInfo = getNumberOfStudyInfo(); const int num = vf.getNumberOfVocabularyEntries(); for (int i = 0; i < num; i++) { VocabularyEntry ve = *(vf.getVocabularyEntry(i)); int studyNum = ve.getStudyNumber(); if (studyNum >= 0) { studyNum += origNumberOfStudyInfo; } ve.setStudyNumber(studyNum); addVocabularyEntry(ve); } // // Transfer the study info // for (int j = 0; j < vf.getNumberOfStudyInfo(); j++) { addStudyInfo((*vf.getStudyInfo(j))); } // // transfer the file's comment // appendToFileComment(vf.getFileComment()); } /** * Clears current file data in memory. Deriving classes must override this method and * call AbstractFile::clearAbstractFile() from its clear method. */ void VocabularyFile::clear() { clearAbstractFile(); vocabularyEntries.clear(); studyInfo.clear(); } /** * returns true if the file is isEmpty (contains no data). */ bool VocabularyFile::empty() const { return vocabularyEntries.empty(); } /** * Read the contents of the file (header has already been read). */ void VocabularyFile::readFileData(QFile& file, QTextStream& stream, QDataStream& /*binStream*/, QDomElement& rootElement) throw (FileException) { // // Should reading data be skipped ? // if (getReadMetaDataOnlyFlag()) { return; } switch (getFileReadType()) { case FILE_FORMAT_ASCII: throw FileException(filename, "Reading in ASCII format not supported."); break; case FILE_FORMAT_BINARY: throw FileException(filename, "Reading in Binary format not supported."); break; case FILE_FORMAT_XML: { QDomNode node = rootElement.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { // // Is this a "VocabularyEntry" element // if (elem.tagName() == "VocabularyEntry") { VocabularyEntry ve; ve.readXML(node); addVocabularyEntry(ve); } else if (elem.tagName() == CellStudyInfo::tagCellStudyInfo) { CellStudyInfo csi; csi.readXML(node); addStudyInfo(csi); } else if ((elem.tagName() == xmlHeaderOldTagName) || (elem.tagName() == xmlHeaderTagName)) { // ignore, read by AbstractFile::readFile() } else { std::cout << "WARNING: unrecognized Vocabulary File element: " << elem.tagName().toAscii().constData() << std::endl; } } node = node.nextSibling(); } } break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "Reading XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "Reading XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Reading XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Reading in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: { CommaSeparatedValueFile csvf; csvf.readFromTextStream(file, stream); readDataFromCommaSeparatedValuesTable(csvf); } break; } } /** * Write the file's data (header has already been written). */ void VocabularyFile::writeFileData(QTextStream& stream, QDataStream& /*binStream*/, QDomDocument& xmlDoc, QDomElement& rootElement) throw (FileException) { const int num = getNumberOfVocabularyEntries(); switch (getFileWriteType()) { case FILE_FORMAT_ASCII: throw FileException(filename, "Writing in Ascii format not supported."); break; case FILE_FORMAT_BINARY: throw FileException(filename, "Writing in Binary format not supported."); break; case FILE_FORMAT_XML: { // // Write the vocabulary entries // for (int i = 0; i < num; i++) { const VocabularyEntry* ve = getVocabularyEntry(i); ve->writeXML(xmlDoc, rootElement); } // // Write the study info // const int numStudyInfo = getNumberOfStudyInfo(); for (int i = 0; i < numStudyInfo; i++) { studyInfo[i].writeXML(xmlDoc, rootElement, i); } } break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "Writing in XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "Writing in XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Writing XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Writing in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: { CommaSeparatedValueFile csvf; writeDataIntoCommaSeparatedValueFile(csvf); csvf.writeToTextStream(stream); } break; } } /** * get indices to all linked studies. */ void VocabularyFile::getPubMedIDsOfAllLinkedStudyMetaData(std::vector& studyPMIDs) const { std::set pmidSet; const int numVocab = getNumberOfVocabularyEntries(); for (int i = 0; i < numVocab; i++) { const VocabularyEntry* ve = getVocabularyEntry(i); const StudyMetaDataLinkSet smdl = ve->getStudyMetaDataLinkSet(); std::vector pmids; smdl.getAllLinkedPubMedIDs(pmids); pmidSet.insert(pmids.begin(), pmids.end()); } studyPMIDs.clear(); studyPMIDs.insert(studyPMIDs.end(), pmidSet.begin(), pmidSet.end()); } /** * a vocabulary entry using its index. */ VocabularyFile::VocabularyEntry* VocabularyFile::getVocabularyEntry(const int indx) { if ((indx >= 0) && (indx < getNumberOfVocabularyEntries())) { return &vocabularyEntries[indx]; } return NULL; } /** * a vocabulary entry using its index (const method). */ const VocabularyFile::VocabularyEntry* VocabularyFile::getVocabularyEntry(const int indx) const { if ((indx >= 0) && (indx < getNumberOfVocabularyEntries())) { return &vocabularyEntries[indx]; } return NULL; } /** * get the index of a vocabulary entry from its abbreviation (-1 if not found). */ int VocabularyFile::getVocabularyEntryIndexFromName(const QString& abbreviationIn) const { const int num = getNumberOfVocabularyEntries(); for (int i = 0; i < num; i++) { const VocabularyEntry* ve = getVocabularyEntry(i); if (ve->getAbbreviation() == abbreviationIn) { return i; } } return -1; } /** * get a vocabulary entry from its abbreviation (NULL if not found). */ VocabularyFile::VocabularyEntry* VocabularyFile::getVocabularyEntryByName(const QString& abbreviationIn) { const int indx = getVocabularyEntryIndexFromName(abbreviationIn); VocabularyEntry* ve = getVocabularyEntry(indx); return ve; } /** * get a vocabulary entry from its abbreviation (const method). */ const VocabularyFile::VocabularyEntry* VocabularyFile::getVocabularyEntryByName(const QString& abbreviationIn) const { const int indx = getVocabularyEntryIndexFromName(abbreviationIn); const VocabularyEntry* ve = getVocabularyEntry(indx); return ve; } /** * get the best matching vocabulary entry (abbreviationIn begins with entry name). */ VocabularyFile::VocabularyEntry* VocabularyFile::getBestMatchingVocabularyEntry(const QString abbreviationIn, const bool caseSensitive) { int bestMatchIndex = -1; int bestMatchLength = 0; Qt::CaseSensitivity cs = Qt::CaseInsensitive; if (caseSensitive) { cs = Qt::CaseSensitive; } const int num = getNumberOfVocabularyEntries(); for (int i = 0; i < num; i++) { const VocabularyEntry* ve = getVocabularyEntry(i); const QString name(ve->getAbbreviation()); if (abbreviationIn.startsWith(name, cs)) { const int len = name.length(); if (len > bestMatchLength) { bestMatchIndex = i; bestMatchLength = len; } } } if (bestMatchIndex >= 0) { return getVocabularyEntry(bestMatchIndex); } return NULL; } /** * get the best matching vocabulary entry (abbreviationIn begins with entry name). */ const VocabularyFile::VocabularyEntry* VocabularyFile::getBestMatchingVocabularyEntry(const QString abbreviationIn, const bool caseSensitive) const { int bestMatchIndex = -1; int bestMatchLength = 0; Qt::CaseSensitivity cs = Qt::CaseInsensitive; if (caseSensitive) { cs = Qt::CaseSensitive; } const int num = getNumberOfVocabularyEntries(); for (int i = 0; i < num; i++) { const VocabularyEntry* ve = getVocabularyEntry(i); const QString name(ve->getAbbreviation()); if (abbreviationIn.startsWith(name, cs)) { const int len = name.length(); if (len > bestMatchLength) { bestMatchIndex = i; bestMatchLength = len; } } } if (bestMatchIndex >= 0) { return getVocabularyEntry(bestMatchIndex); } return NULL; } /** * find out if comma separated file conversion supported. */ void VocabularyFile::getCommaSeparatedFileSupport(bool& readFromCSV, bool& writeToCSV) const { readFromCSV = true; writeToCSV = true; } /** * write the file's data into a comma separated values file (throws exception if not supported). */ void VocabularyFile::writeDataIntoCommaSeparatedValueFile(CommaSeparatedValueFile& csv) throw (FileException) { csv.clear(); const int numCells = getNumberOfVocabularyEntries(); if (numCells <= 0) { return; } StringTable* headerTable = new StringTable(0, 0); writeHeaderDataIntoStringTable(*headerTable); csv.addDataSection(headerTable); StringTable* entryTable = new StringTable(0, 0); VocabularyEntry::writeDataIntoStringTable(vocabularyEntries, *entryTable); csv.addDataSection(entryTable); StringTable* studyInfoTable = new StringTable(0, 0); CellStudyInfo::writeDataIntoStringTable(studyInfo, *studyInfoTable); csv.addDataSection(studyInfoTable); } /** * read the file's data from a comma separated values file (throws exception if not supported). */ void VocabularyFile::readDataFromCommaSeparatedValuesTable(const CommaSeparatedValueFile& csv) throw (FileException) { clear(); // // Do header // const StringTable* head = csv.getDataSectionByName("header"); if (head != NULL) { readHeaderDataFromStringTable(*head); } // // Do vocabulary entries // const StringTable* stve = csv.getDataSectionByName("Vocabulary Entries"); if (stve != NULL) { VocabularyEntry::readDataFromStringTable(vocabularyEntries, *stve); } const int num = static_cast(vocabularyEntries.size()); for (int i = 0; i < num; i++) { vocabularyEntries[i].vocabularyFile = this; } // // Do study info // const StringTable* stcsi = csv.getDataSectionByName("Cell Study Info"); if (stcsi != NULL) { CellStudyInfo::readDataFromStringTable(studyInfo, *stcsi); } } /** * Get the study info index based upon the study info's value. */ int VocabularyFile::getStudyInfoFromValue(const CellStudyInfo& csi) const { const int num = getNumberOfStudyInfo(); for (int i = 0; i < num; i++) { if ((*getStudyInfo(i)) == csi) { return i; } } return -1; } /** * Get a study info (const method). */ const CellStudyInfo* VocabularyFile::getStudyInfo(const int indx) const { if ((indx >= 0) && (indx < getNumberOfStudyInfo())) { return &studyInfo[indx]; } return NULL; } /** * Get a study info. */ CellStudyInfo* VocabularyFile::getStudyInfo(const int indx) { if ((indx >= 0) && (indx < getNumberOfStudyInfo())) { return &studyInfo[indx]; } return NULL; } /** * Add a study info. */ int VocabularyFile::addStudyInfo(const CellStudyInfo& csi) { studyInfo.push_back(csi); const int index = studyInfo.size() - 1; return index; } /** * delete all study info and clear links to study info */ void VocabularyFile::deleteAllStudyInfo() { const int num = getNumberOfVocabularyEntries(); for (int i = 0; i < num; i++) { VocabularyEntry* ve = getVocabularyEntry(i); ve->setStudyNumber(-1); } studyInfo.clear(); } /** * delete study info. */ void VocabularyFile::deleteStudyInfo(const int indx) { if ((indx >= 0) && (indx < getNumberOfStudyInfo())) { for (int i = 0; i < getNumberOfVocabularyEntries(); i++) { const int studyNum = vocabularyEntries[i].getStudyNumber(); if (studyNum == indx) { vocabularyEntries[i].setStudyNumber(-1); } else if (studyNum > indx) { vocabularyEntries[i].setStudyNumber(studyNum - 1); } } studyInfo.erase(studyInfo.begin() + indx); } } /** * Set a study info. */ void VocabularyFile::setStudyInfo(const int index, const CellStudyInfo& csi) { studyInfo[index] = csi; } //******************************************************************************** /** * constructor. */ VocabularyFile::VocabularyEntry::VocabularyEntry() { clear(); } /** * constructor. */ VocabularyFile::VocabularyEntry::VocabularyEntry(const QString& abbreviationIn, const QString& fullNameIn, const QString& classNameIn, const QString& vocabularyIDIn, const QString& descriptionIn, const QString& ontologySourceIn, const QString& termIDIn, const int studyNumberIn) { clear(); setAbbreviation(abbreviationIn); setFullName(fullNameIn); setClassName(classNameIn); setVocabularyID(vocabularyIDIn); setDescription(descriptionIn); setOntologySource(ontologySourceIn); setTermID(termIDIn); setStudyNumber(studyNumberIn); } /** * copy constructor. */ VocabularyFile::VocabularyEntry::VocabularyEntry(const VocabularyEntry& ve) { clear(); copyHelper(ve); } /** * assignment operator. */ VocabularyFile::VocabularyEntry& VocabularyFile::VocabularyEntry::operator=(const VocabularyEntry& ve) { if (this != &ve) { copyHelper(ve); } return *this; } /** * destructor. */ VocabularyFile::VocabularyEntry::~VocabularyEntry() { } /** * copy helper. */ void VocabularyFile::VocabularyEntry::copyHelper(const VocabularyEntry& ve) { abbreviation = ve.abbreviation; fullName = ve.fullName; className = ve.className; ontologySource = ve.ontologySource; termID = ve.termID; vocabularyID = ve.vocabularyID; description = ve.description; studyNumber = ve.studyNumber; studyMetaDataLinkSet = ve.studyMetaDataLinkSet; } /** * clear this item. */ void VocabularyFile::VocabularyEntry::clear() { vocabularyFile = NULL; studyNumber = -1; studyMetaDataLinkSet.clear(); } /** * set the abbreviation. */ void VocabularyFile::VocabularyEntry::setAbbreviation(const QString& a) { abbreviation = a; setModified(); } /** * set the description. */ void VocabularyFile::VocabularyEntry::setDescription(const QString& d) { description = d; setModified(); } /** * set the full name. */ void VocabularyFile::VocabularyEntry::setFullName(const QString& n) { fullName = n; setModified(); } /** * set the class name. */ void VocabularyFile::VocabularyEntry::setClassName(const QString& s) { className = s; setModified(); } /** * get ontology source values. */ void VocabularyFile::VocabularyEntry::getOntologySourceValues(std::vector& ontologySourceValues) { ontologySourceValues.clear(); ontologySourceValues.push_back("BIRNLex"); ontologySourceValues.push_back("NIFSTD"); ontologySourceValues.push_back("NeuroNames"); } /** * set the ontology source. */ void VocabularyFile::VocabularyEntry::setOntologySource(const QString& s) { ontologySource = s; setModified(); } /** * set the term id. */ void VocabularyFile::VocabularyEntry::setTermID(const QString& s) { termID = s; setModified(); } /** * set the vocabulary ID. */ void VocabularyFile::VocabularyEntry::setVocabularyID(const QString& s) { vocabularyID = s; setModified(); } /** * set the study number. */ void VocabularyFile::VocabularyEntry::setStudyNumber(const int sn) { studyNumber = sn; setModified(); } /** * set the study metadata link. */ void VocabularyFile::VocabularyEntry::setStudyMetaDataLinkSet(const StudyMetaDataLinkSet smdls) { studyMetaDataLinkSet = smdls; setModified(); } /** * set this item modified. */ void VocabularyFile::VocabularyEntry::setModified() { if (vocabularyFile != NULL) { vocabularyFile->setModified(); } } /** * called to read from an XML structure. */ void VocabularyFile::VocabularyEntry::readXML(QDomNode& nodeIn) throw (FileException) { if (nodeIn.isNull()) { return; } QDomElement elem = nodeIn.toElement(); if (elem.isNull()) { return; } if (elem.tagName() != "VocabularyEntry") { QString msg("Incorrect element type passed to VocabularyFile::VocabularyEntry::readXML(): \""); msg.append(elem.tagName()); msg.append("\""); throw FileException("", msg); } QDomNode node = nodeIn.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (elem.tagName() == "abbreviation") { abbreviation = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "fullName") { fullName = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "className") { className = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "vocabularyID") { vocabularyID = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "description") { description = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "ontologySource") { ontologySource = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "termID") { termID = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "studyNumber") { studyNumber = AbstractFile::getXmlElementFirstChildAsInt(elem); } else if (elem.tagName() == "StudyMetaDataLink") { StudyMetaDataLink smdl; smdl.readXML(node); studyMetaDataLinkSet.addStudyMetaDataLink(smdl); } else if (elem.tagName() == "StudyMetaDataLinkSet") { studyMetaDataLinkSet.readXML(node); } else { std::cout << "WARNING: unrecognized VocabularyEntry element: " << elem.tagName().toAscii().constData() << std::endl; } } node = node.nextSibling(); } } /** * called to write to an XML structure. */ void VocabularyFile::VocabularyEntry::writeXML(QDomDocument& xmlDoc, QDomElement& parentElement) const { // // Create the element for this class instance's data // QDomElement vocabularyDataElement = xmlDoc.createElement("VocabularyEntry"); // // color elements // AbstractFile::addXmlCdataElement(xmlDoc, vocabularyDataElement, "abbreviation", abbreviation); AbstractFile::addXmlCdataElement(xmlDoc, vocabularyDataElement, "fullName", fullName); AbstractFile::addXmlCdataElement(xmlDoc, vocabularyDataElement, "className", className); AbstractFile::addXmlCdataElement(xmlDoc, vocabularyDataElement, "vocabularyID", vocabularyID); AbstractFile::addXmlCdataElement(xmlDoc, vocabularyDataElement, "description", description); AbstractFile::addXmlCdataElement(xmlDoc, vocabularyDataElement, "ontologySource", ontologySource); AbstractFile::addXmlCdataElement(xmlDoc, vocabularyDataElement, "termID", termID); AbstractFile::addXmlCdataElement(xmlDoc, vocabularyDataElement, "studyNumber", QString::number(studyNumber)); studyMetaDataLinkSet.writeXML(xmlDoc, vocabularyDataElement); // // Add class instance's data to the parent // parentElement.appendChild(vocabularyDataElement); } /** * called to write XML. */ void VocabularyFile::VocabularyEntry::writeXML(XmlGenericWriter& xmlWriter) const throw (FileException) { xmlWriter.writeStartElement("VocabularyEntry"); xmlWriter.writeElementCData("abbreviation", abbreviation); xmlWriter.writeElementCData("fullName", fullName); xmlWriter.writeElementCData("className", className); xmlWriter.writeElementCData("vocabularyID", vocabularyID); xmlWriter.writeElementCData("description", description); xmlWriter.writeElementCData("ontologySource", ontologySource); xmlWriter.writeElementCData("termID", termID); studyMetaDataLinkSet.writeXML(xmlWriter); xmlWriter.writeEndElement(); } /** * write the data into a StringTable. */ void VocabularyFile::VocabularyEntry::writeDataIntoStringTable(const std::vector& data, StringTable& table) { table.clear(); const int num = static_cast(data.size()); // // Column numbers for data // int numCols = 0; const int abbreviationCol = numCols++; const int fullNameCol = numCols++; const int classNameCol = numCols++; const int vocabularyIDCol = numCols++; const int descriptionCol = numCols++; const int ontologySourceCol = numCols++; const int termIDCol = numCols++; const int studyPubMedIDCol = numCols++; const int studyNumberCol = numCols++; // // Table column names // table.setNumberOfRowsAndColumns(num, numCols, "Vocabulary Entries"); table.setColumnTitle(abbreviationCol, "Abbreviation"); table.setColumnTitle(fullNameCol, "Full Name"); table.setColumnTitle(classNameCol, "Class Name"); table.setColumnTitle(vocabularyIDCol, "Vocabulary ID"); table.setColumnTitle(descriptionCol, "Description"); table.setColumnTitle(ontologySourceCol, "Ontology Source"); table.setColumnTitle(termIDCol, "Term ID"); table.setColumnTitle(studyNumberCol, "Study Number"); table.setColumnTitle(studyPubMedIDCol, "StudyMetaDataLink"); for (int i = 0; i < num; i++) { const VocabularyEntry& ve = data[i]; table.setElement(i, abbreviationCol, ve.getAbbreviation()); table.setElement(i, fullNameCol, ve.getFullName()); table.setElement(i, classNameCol, ve.getClassName()); table.setElement(i, vocabularyIDCol, ve.getVocabularyID()); table.setElement(i, descriptionCol, ve.getDescription()); table.setElement(i, studyNumberCol, ve.getStudyNumber()); table.setElement(i, ontologySourceCol, ve.getOntologySource()); table.setElement(i, termIDCol, ve.getTermID()); const int numLinks = ve.getStudyMetaDataLinkSet().getNumberOfStudyMetaDataLinks(); if (numLinks > 1) { throw FileException("Vocabulary Entry \"" + ve.getFullName() + "\" has more than one Study Metadata Link. " "Cannot write to Table"); } else if (numLinks == 1) { table.setElement(i, studyPubMedIDCol, ve.getStudyMetaDataLinkSet().getStudyMetaDataLink(0).getLinkAsCodedText()); } } } /** * read the data from a StringTable. */ void VocabularyFile::VocabularyEntry::readDataFromStringTable(std::vector& data, const StringTable& table) throw (FileException) { if (table.getTableTitle() != "Vocabulary Entries") { throw FileException("String table for Vocabulary does not have the name Vocabulary"); } data.clear(); int abbreviationCol = -1; int fullNameCol = -1; int classNameCol = -1; int vocabularyIDCol = -1; int descriptionCol = -1; int ontologySourceCol = -1; int termIDCol = -1; int studyNumberCol = -1; int studyPubMedIDCol = -1; const int numCols = table.getNumberOfColumns(); for (int i = 0; i < numCols; i++) { const QString name = table.getColumnTitle(i).toLower(); if (name == "abbreviation") { abbreviationCol = i; } else if (name == "full name") { fullNameCol = i; } else if (name == "class name") { classNameCol = i; } else if (name == "vocabulary id") { vocabularyIDCol = i; } else if (name == "description") { descriptionCol = i; } else if (name == "ontology source") { ontologySourceCol = i; } else if (name == "term id") { termIDCol = i; } else if (name == "study number") { studyNumberCol = i; } else if ((name == "study pubmed id") || (name == "studymetadatalink")) { studyPubMedIDCol = i; } } const int numItems = table.getNumberOfRows(); for (int i = 0; i < numItems; i++) { VocabularyEntry ve; if (abbreviationCol >= 0) { ve.setAbbreviation(table.getElement(i, abbreviationCol)); } if (fullNameCol >= 0) { ve.setFullName(table.getElement(i, fullNameCol)); } if (classNameCol >= 0) { ve.setClassName(table.getElement(i, classNameCol)); } if (vocabularyIDCol >= 0) { ve.setVocabularyID(table.getElement(i, vocabularyIDCol)); } if (descriptionCol >= 0) { ve.setDescription(table.getElement(i, descriptionCol)); } if (ontologySourceCol >= 0) { ve.setOntologySource(table.getElement(i, ontologySourceCol)); } if (termIDCol >= 0) { ve.setTermID(table.getElement(i, termIDCol)); } if (studyPubMedIDCol >= 0) { StudyMetaDataLink smdl; smdl.setLinkFromCodedText(table.getElement(i, studyPubMedIDCol)); if (smdl.getPubMedID().isEmpty() == false) { StudyMetaDataLinkSet smdls; smdls.addStudyMetaDataLink(smdl); ve.setStudyMetaDataLinkSet(smdls); } } if (studyNumberCol >= 0) { ve.setStudyNumber(table.getElementAsInt(i, studyNumberCol)); } data.push_back(ve); } } /** * Write the file's memory in caret6 format to the specified name. */ QString VocabularyFile::writeFileInCaret6Format(const QString& filenameIn, Structure structure,const ColorFile* colorFileIn, const bool useCaret6ExtensionFlag) throw (FileException) { int numVocab = this->getNumberOfVocabularyEntries(); if (numVocab <= 0) { throw FileException("Contains no vocabulary"); } QFile file(filenameIn); if (file.open(QFile::WriteOnly) == false) { throw FileException("Unable to open for writing"); } QTextStream stream(&file); XmlGenericWriter xmlWriter(stream); xmlWriter.writeStartDocument(); XmlGenericWriterAttributes attributes; attributes.addAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); attributes.addAttribute("xsi:noNamespaceSchemaLocation", "http://brainvis.wustl.edu/caret6/xml_schemas/VocabularyFileSchema.xsd"); attributes.addAttribute("CaretFileType", "Vocabulary"); attributes.addAttribute("Version", "6.0"); xmlWriter.writeStartElement("CaretDataFile", attributes); this->writeHeaderXMLWriter(xmlWriter); for (int i = 0; i < numVocab; i++) { const VocabularyEntry* v = getVocabularyEntry(i); v->writeXML(xmlWriter); } xmlWriter.writeEndElement(); xmlWriter.writeEndDocument(); file.close(); return filenameIn; } /** * get full description of all fields for display to user. */ /* QString VocabularyFile::VocabularyEntry::getFullDescriptionForDisplayToUser(const bool useHTML) const { const QString boldStart(""); const QString boldEnd(""); const QString newLine("\n"); QString s; if (useHTML) s += boldStart; s += "Abbreviation"; if (useHTML) s += boldEnd; s += ": "; s += abbreviation; s += newLine; if (fullName.isEmpty() == false) { if (useHTML) s += boldStart; s += "Full Name"; if (useHTML) s += boldEnd; s += ": "; s += fullName; s += newLine; } if (className.isEmpty() == false) { if (useHTML) s += boldStart; s += "Class Name"; if (useHTML) s += boldEnd; s += ": "; s += className; s += newLine; } if (vocabularyID.isEmpty() == false) { if (useHTML) s += boldStart; s += "Vocabulary ID"; if (useHTML) s += boldEnd; s += ": "; s += vocabularyID; s += newLine; } if (description.isEmpty() == false) { if (useHTML) s += boldStart; s += "Description"; if (useHTML) s += boldEnd; s += ": "; s += description; s += newLine; } if (ontologySource.isEmpty() == false) { if (useHTML) s += boldStart; s += "Ontology Source"; if (useHTML) s += boldEnd; s += ": "; s += ontologySource; s += newLine; } if (termID.isEmpty() == false) { if (useHTML) s += boldStart; s += "Term ID"; if (useHTML) s += boldEnd; s += ": "; s += termID; s += newLine; } if (vocabularyFile != NULL) { if ((studyNumber >= 0) && (studyNumber < vocabularyFile->getNumberOfStudyInfo())) { const CellStudyInfo* csi = vocabularyFile->getStudyInfo(studyNumber); const QString s2 = csi->getFullDescriptionForDisplayToUser(true); if (s2.isEmpty() == false) { s += s2; } } } return s; } */ caret-5.6.4~dfsg.1.orig/caret_files/VectorFile.h0000664000175000017500000001570711572067322021266 0ustar michaelmichael#ifndef __VECTOR_FILE_H__ #define __VECTOR_FILE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "GiftiDataArrayFile.h" class TransformationMatrix; class VolumeFile; /// class for storing vectors class VectorFile : public GiftiDataArrayFile { public: // constructor VectorFile(); // copy constructor VectorFile(const VectorFile& nndf); // create vectors from FSL volume files contains x/y/z/magnitude static VectorFile* createVectorFileFromFSLVectorVolumes( const VolumeFile& xVectorVolume, const VolumeFile& yVectorVolume, const VolumeFile& zVectorVolume, const VolumeFile& magnitudeVolume, const VolumeFile& destinationSpaceVolume, const TransformationMatrix& fslMatrix, TransformationMatrix& inputToOutputSpaceTransformationMatrixOut, const float defaultColorRGB[3] = NULL) throw (FileException); // assignment operator VectorFile& operator=(const VectorFile& nndf); // destructor ~VectorFile(); // append a data array file to this one virtual void append(const VectorFile& naf) throw (FileException); // Clear the node data file. virtual void clear(); // add a vector (color and radius are optional) void addVector(const float xyzOriginIn[3], const float xyzComponentsIn[3], const float magnitudeIn, const int nodeNumberIn = -1, const float rgbaColorsIn[4] = NULL, const float radiusIn = 1.0); // get number of vector int getNumberOfVectors() const; // get the vector's data void getVectorData(const int vectorIndex, float xyzOriginOut[3], float xyzComponentsOut[3], float& magnitudeOut, int& nodeNumberOut, float rgbaColorsOut[4], float& radiusOut) const; // set the number of vectors (clears any existing data) void setNumberOfVectors(int numberOfVectors); // get the vector's origin void getVectorOrigin(const int vectorIndex, float xyzOriginOut[3]) const; // set the vector's origin void setVectorOrigin(const int vectorIndex, const float xyzOriginIn[3]); // get the unit vector's XYZ components void getVectorUnitComponents(const int vectorIndex, float xyzVectorOut[3]) const; // set the unit vector's XYZ components void setVectorUnitComponents(const int vectorIndex, const float xyzVectorIn[3]); // get the vector's magnitude float getVectorMagnitude(const int vectorIndex) const; // set the vector's magnitude void setVectorMagnitude(const int vectorIndex, const float magnitudeIn); // get the vectors radius float getVectorRadius(const int vectorIndex) const; // set the vector's radius void setVectorRadius(const int vectorIndex, const float radiusIn); // get the vector's rgba colors void getVectorColorRGBA(const int vectorIndex, float rgbaOut[4]) const; // set the vector's rgba colors void setVectorColorRGBA(const int vectorIndex, const float rgbaIn[4]); // get the vector's node number int getVectorNodeNumber(const int vectorIndex) const; // set the vector's node number void setVectorNodeNumber(const int vectorIndex, const int nodeNumberIn); // set the vector's data void setVectorData(const int vectorIndex, const float xyzOriginIn[3], const float xyzComponentsIn[3], const float magnitudeIn, const int nodeNumberIn = -1, const float rgbaColorsIn[4] = NULL, const float radiusIn = 1.0); // get PubMedID's of all linked studies void getPubMedIDsOfAllLinkedStudyMetaData(std::vector& studyPMIDs) const; // Apply transformation matrix to vector file. void applyTransformationMatrix(const TransformationMatrix& tmIn); /// get the default color static void getDefaultColorRGBA(float rgba[4]); /// write the file's memory in caret6 format to the specified name virtual QString writeFileInCaret6Format(const QString& filenameIn, Structure structure,const ColorFile* colorFileIn, const bool useCaret6ExtensionFlag) throw (FileException); protected: /// indices of vector data enum DATA_INDEX { INDEX_NODE_NUMBER = 0, INDEX_X_COORDINATE = 1, INDEX_Y_COORDINATE = 2, INDEX_Z_COORDINATE = 3, INDEX_X_COMPONENT = 4, INDEX_Y_COMPONENT = 5, INDEX_Z_COMPONENT = 6, INDEX_MAGNITUDE = 7, INDEX_RADIUS = 8, INDEX_COLOR_RED = 9, INDEX_COLOR_GREEN = 10, INDEX_COLOR_BLUE = 11, INDEX_COLOR_ALPHA = 12, NUMBER_OF_ARRAYS = 13 }; // get the data array description static QString getDataArrayDescription(const DATA_INDEX dataIndex); // copy helper void copyHelperVectorFile(const VectorFile& nndf); /// set a data array value void setDataValue(const int arrayIndex, const int vectorIndex, const float value); /// get a data array value float getDataValue(const int arrayIndex, const int vectorIndex) const; // validate the data arrays (optional for subclasses) virtual void validateDataArrays() throw (FileException); /// the default color static const float defaultColor[4]; }; #ifdef __VECTOR_FILE_MAIN__ const float VectorFile::defaultColor[4] = { 1.0, 0.5, 0.5, 1.0 }; #endif // __VECTOR_FILE_MAIN__ #endif /* __VECTOR_FILE_H__ */ caret-5.6.4~dfsg.1.orig/caret_files/VectorFile.cxx0000664000175000017500000006130711572067322021636 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "FileUtilities.h" #include "GiftiCommon.h" #include "GiftiMetaData.h" #include "MathUtilities.h" #include "SpecFile.h" #include "TransformationMatrixFile.h" #define __VECTOR_FILE_MAIN__ #include "VectorFile.h" #undef __VECTOR_FILE_MAIN__ #include "VolumeFile.h" /** * constructor. */ VectorFile::VectorFile() : GiftiDataArrayFile("Vector File", GiftiCommon::intentVectors, GiftiDataArray::DATA_TYPE_FLOAT32, SpecFile::getGiftiVectorFileExtension(), AbstractFile::FILE_FORMAT_XML, AbstractFile::FILE_IO_NONE, AbstractFile::FILE_IO_NONE, AbstractFile::FILE_IO_NONE, AbstractFile::FILE_IO_NONE, false) { } /** * destructor. */ VectorFile::~VectorFile() { /* nothing to do at this time. */ } /** * copy constructor. */ VectorFile::VectorFile(const VectorFile& vf) : GiftiDataArrayFile(vf) { copyHelperVectorFile(vf); } /** * assignment operator. */ VectorFile& VectorFile::operator=(const VectorFile& vf) { if (this != &vf) { GiftiDataArrayFile::operator=(vf); copyHelperVectorFile(vf); } return *this; } /** * create vectors from FSL volume files contains x/y/z/magnitude. */ VectorFile* VectorFile::createVectorFileFromFSLVectorVolumes( const VolumeFile& xVectorVolume, const VolumeFile& yVectorVolume, const VolumeFile& zVectorVolume, const VolumeFile& magnitudeVolume, const VolumeFile& destinationSpaceVolume, const TransformationMatrix& fslMatrixIn, TransformationMatrix& inputToOutputSpaceTransformationMatrixOut, const float defaultColorRGB[3]) throw (FileException) { // // Get info from X-Vector volume // int dim[3]; float origin[3]; float spacing[3]; magnitudeVolume.getDimensions(dim); magnitudeVolume.getOrigin(origin); magnitudeVolume.getSpacing(spacing); // // Verify that Y, Z, and magnitude volumes are of same dimensions as X // int xDim[3]; xVectorVolume.getDimensions(xDim); if ((dim[0] != xDim[0]) || (dim[1] != xDim[1]) || (dim[2] != xDim[2])) { throw FileException("X and Magnitude volumes have different dimensions."); } int yDim[3]; yVectorVolume.getDimensions(yDim); if ((dim[0] != yDim[0]) || (dim[1] != yDim[1]) || (dim[2] != yDim[2])) { throw FileException("Y and Magnitude volumes have different dimensions."); } int zDim[3]; zVectorVolume.getDimensions(zDim); if ((dim[0] != zDim[0]) || (dim[1] != zDim[1]) || (dim[2] != zDim[2])) { throw FileException("Z and Magnitude volumes have different dimensions."); } // // Get the Ref SFORM matrix from the destination space volume // and remove scaling // TransformationMatrix refSformMatrix = destinationSpaceVolume.getNiftiSFormTransformationMatrix(); refSformMatrix.setMatrixElement(0, 0, 1.0); refSformMatrix.setMatrixElement(1, 1, 1.0); refSformMatrix.setMatrixElement(2, 2, 1.0); // // Matrix to flip about X-Axis // float destVolumeSpacing[3]; destinationSpaceVolume.getSpacing(destVolumeSpacing); TransformationMatrix xFlipMatrix; xFlipMatrix.identity(); if (destVolumeSpacing[0] > 0) { xFlipMatrix.setMatrixElement(0, 0, -1.0); } // // Create a "swap" matrix that flips from radiological to // neurological orientation (Wref) // // NOTE: This does not work for flipping which needs to be done after SFORM // See XFLIP matrix below // TransformationMatrix referenceSwapMatrix; referenceSwapMatrix.identity(); //referenceSwapMatrix.setMatrixElement(0, 0, -1.0); //referenceSwapMatrix.setMatrixElement(0, 3, dim[0] - 1); // // Create a matrix for reference volume scaling (which in caret land is 1mm) // so it is just the identify matrix, at least for now. (Sref) // TransformationMatrix refScalingMatrix; refScalingMatrix.identity(); refScalingMatrix.inverse(); // // The matrix from FSL // TransformationMatrix fslMatrix = fslMatrixIn; //fslMatrix.inverse(); // // Create a matrix for input volume scaling which is the absolute values of // the voxels sizes. (Sin) // TransformationMatrix inputScalingMatrix; inputScalingMatrix.identity(); inputScalingMatrix.setMatrixElement(0, 0, std::fabs(spacing[0])); inputScalingMatrix.setMatrixElement(1, 1, std::fabs(spacing[1])); inputScalingMatrix.setMatrixElement(2, 2, std::fabs(spacing[2])); // // Create the swap matrix for the input volume which transforms it into // radiological orientation. Since the input volumes are always in // radiological orientation, this is just the identity matrix // TransformationMatrix inputSwapMatrix; inputSwapMatrix.identity(); // // Source SFORM matrix // // // Get the SFORM matrix // TransformationMatrix sourceSformMatrix = magnitudeVolume.getNiftiSFormTransformationMatrix(); sourceSformMatrix.inverse(); // // Construct the transformation matrix for placing the vectors // into reference (caret) space // TransformationMatrix matrix; matrix.identity(); matrix.postMultiply(xFlipMatrix); matrix.postMultiply(refSformMatrix); matrix.postMultiply(referenceSwapMatrix); matrix.postMultiply(refScalingMatrix); matrix.postMultiply(fslMatrix); matrix.postMultiply(inputScalingMatrix); matrix.postMultiply(inputSwapMatrix); matrix.postMultiply(sourceSformMatrix); // // Determine if any flipping is need of the vector components that might // be caused by storing the vectors in orientation other than // LPI (X=Left-to-Right, Y=Posterior-to-Anterior, Z=Inferior-to-Superior). // float xFlip = ((spacing[0] < 0) ? -1.0 : 1.0); float yFlip = ((spacing[1] < 0) ? -1.0 : 1.0); float zFlip = ((spacing[2] < 0) ? -1.0 : 1.0); // // Get the origin and the vector components // std::vector x, y, z, vx, vy, vz, magnitude; for (int i = 0; i < dim[0]; i++) { for (int j = 0; j < dim[1]; j++) { for (int k = 0; k < dim[2]; k++) { const float mag = magnitudeVolume.getVoxel(i, j, k); if (mag > 0.0) { float xyz[3]; xVectorVolume.getVoxelCoordinate(i, j, k, xyz); x.push_back(xyz[0]); y.push_back(xyz[1]); z.push_back(xyz[2]); vx.push_back(xVectorVolume.getVoxel(i, j, k) * xFlip); vy.push_back(yVectorVolume.getVoxel(i, j, k) * yFlip); vz.push_back(zVectorVolume.getVoxel(i, j, k) * zFlip); magnitude.push_back(mag); } } } } // // Verify that there are vectors // int numVectors = static_cast(vx.size()); if (numVectors <= 0) { throw FileException("No vectors with a positive magnitude were found."); } // // Set the default coloring and use user provided coloring // float rgba[4]; VectorFile::getDefaultColorRGBA(rgba); if (defaultColorRGB != NULL) { rgba[0] = defaultColorRGB[0]; rgba[1] = defaultColorRGB[1]; rgba[2] = defaultColorRGB[2]; } // // Create and fill the vector file // VectorFile* vectorFile = new VectorFile(); vectorFile->setNumberOfVectors(numVectors); for (int i = 0; i < numVectors; i++) { const float xyz[3] = { x[i], y[i], z[i] }; const float vector[3] = { vx[i], vy[i], vz[i] }; const float mag = magnitude[i]; vectorFile->setVectorData(i, xyz, vector, mag, -1, rgba, 1.0); } // // Apply the matrix to the vector file // vectorFile->applyTransformationMatrix(matrix); inputToOutputSpaceTransformationMatrixOut = matrix; return vectorFile; } /** * copy helper. */ void VectorFile::copyHelperVectorFile(const VectorFile& /*vf*/) { /* nothing to do at this time. */ } /** * */ void VectorFile::clear() { GiftiDataArrayFile::clear(); } /** * append a data array file to this one. */ void VectorFile::append(const VectorFile& vf) throw (FileException) { if (this->getNumberOfVectors() <= 0) { *this = vf; } else { int num = vf.getNumberOfVectors(); for (int i = 0; i < num; i++) { float origin[3], vector[3], mag, rgba[4], radius; int nodeNumber; vf.getVectorData(i, origin, vector, mag, nodeNumber, rgba, radius); this->addVector(origin, vector, mag, nodeNumber, rgba, radius); } } } /** * add a vector (color and radius are optional). */ void VectorFile::addVector(const float xyzOriginIn[3], const float xyzComponentsIn[3], const float magnitude, const int nodeNumberIn, const float rgbaColorsIn[4], const float radiusIn) { int numDataArrays = this->getNumberOfDataArrays(); if (numDataArrays <= 0) { this->setNumberOfVectors(1); } else { for (int i = 0; i < numDataArrays; i++) { GiftiDataArray* gda = this->getDataArray(i); gda->addRows(1); } } const int vectorIndex = this->getNumberOfVectors() - 1; this->setVectorData(vectorIndex, xyzOriginIn, xyzComponentsIn, magnitude, nodeNumberIn, rgbaColorsIn, radiusIn); this->setModified(); } /** * get number of vector. */ int VectorFile::getNumberOfVectors() const { if (this->getNumberOfDataArrays() > 0) { return this->dataArrays[0]->getDimension(0); } return 0; } /** * get the vector's data (pass NULL for undesired items). */ void VectorFile::getVectorData(const int vectorIndex, float xyzOriginOut[3], float xyzComponentsOut[3], float& magnitudeOut, int& nodeNumberOut, float rgbaColorsOut[4], float& radiusOut) const { this->getVectorOrigin(vectorIndex, xyzOriginOut); this->getVectorUnitComponents(vectorIndex, xyzComponentsOut); magnitudeOut = this->getVectorMagnitude(vectorIndex); nodeNumberOut = this->getVectorNodeNumber(vectorIndex); this->getVectorColorRGBA(vectorIndex, rgbaColorsOut); radiusOut = this->getVectorRadius(vectorIndex); } /** * Get a data array value. */ float VectorFile::getDataValue(const int arrayIndex, const int vectorIndex) const { float* data = this->dataArrays[arrayIndex]->getDataPointerFloat(); float value = data[vectorIndex]; return value; } /** * set the number of vectors (clears any existing data). */ void VectorFile::setNumberOfVectors(int numberOfVectors) { const int nda = getNumberOfDataArrays(); for (int i = 0; i < nda; i++) { delete dataArrays[i]; } dataArrays.clear(); if (numberOfVectors > 0){ std::vector dim; dim.push_back(numberOfVectors); for (int i = 0; i < NUMBER_OF_ARRAYS; i++) { GiftiDataArray* gda = new GiftiDataArray(this, getDefaultDataArrayIntent(), defaultDataType, dim); gda->getMetaData()->set(GiftiCommon::tagName, VectorFile::getDataArrayDescription( static_cast(i))); this->addDataArray(gda); } } setModified(); } /** * get the vector's origin. */ void VectorFile::getVectorOrigin(const int vectorIndex, float xyzOriginOut[3]) const { xyzOriginOut[0] = this->getDataValue(VectorFile::INDEX_X_COORDINATE, vectorIndex); xyzOriginOut[1] = this->getDataValue(VectorFile::INDEX_Y_COORDINATE, vectorIndex); xyzOriginOut[2] = this->getDataValue(VectorFile::INDEX_Z_COORDINATE, vectorIndex); } /** * set the vector's origin. */ void VectorFile::setVectorOrigin(const int vectorIndex, const float xyzOriginIn[3]) { this->setDataValue(INDEX_X_COORDINATE, vectorIndex, xyzOriginIn[0]); this->setDataValue(INDEX_Y_COORDINATE, vectorIndex, xyzOriginIn[1]); this->setDataValue(INDEX_Z_COORDINATE, vectorIndex, xyzOriginIn[2]); } /** * get the vector's XYZ components. */ void VectorFile::getVectorUnitComponents(const int vectorIndex, float xyzVectorOut[3]) const { xyzVectorOut[0] = this->getDataValue(VectorFile::INDEX_X_COMPONENT, vectorIndex); xyzVectorOut[1] = this->getDataValue(VectorFile::INDEX_Y_COMPONENT, vectorIndex); xyzVectorOut[2] = this->getDataValue(VectorFile::INDEX_Z_COMPONENT, vectorIndex); } /** * set the vector's XYZ components. */ void VectorFile::setVectorUnitComponents(const int vectorIndex, const float xyzVectorIn[3]) { this->setDataValue(INDEX_X_COMPONENT, vectorIndex, xyzVectorIn[0]); this->setDataValue(INDEX_Y_COMPONENT, vectorIndex, xyzVectorIn[1]); this->setDataValue(INDEX_Z_COMPONENT, vectorIndex, xyzVectorIn[2]); } /** * get the vectors radius. */ float VectorFile::getVectorRadius(const int vectorIndex) const { return this->getDataValue(VectorFile::INDEX_RADIUS, vectorIndex); } /** * set the vector's radius. */ void VectorFile::setVectorRadius(const int vectorIndex, const float radiusIn) { this->setDataValue(INDEX_RADIUS, vectorIndex, radiusIn); } /** * get the vector's rgba colors. */ void VectorFile::getVectorColorRGBA(const int vectorIndex, float rgbaOut[4]) const { rgbaOut[0] = this->getDataValue(VectorFile::INDEX_COLOR_RED, vectorIndex); rgbaOut[1] = this->getDataValue(VectorFile::INDEX_COLOR_GREEN, vectorIndex); rgbaOut[2] = this->getDataValue(VectorFile::INDEX_COLOR_BLUE, vectorIndex); rgbaOut[3] = this->getDataValue(VectorFile::INDEX_COLOR_ALPHA, vectorIndex); } /** * set the vector's rgba colors. */ void VectorFile::setVectorColorRGBA(const int vectorIndex, const float rgbaIn[4]) { this->setDataValue(INDEX_COLOR_RED, vectorIndex, rgbaIn[0]); this->setDataValue(INDEX_COLOR_GREEN, vectorIndex, rgbaIn[1]); this->setDataValue(INDEX_COLOR_BLUE, vectorIndex, rgbaIn[2]); this->setDataValue(INDEX_COLOR_ALPHA, vectorIndex, rgbaIn[3]); } /** * get the vector's node number. */ int VectorFile::getVectorNodeNumber(const int vectorIndex) const { return static_cast( this->getDataValue(VectorFile::INDEX_NODE_NUMBER, vectorIndex)); } /** * set the vector's node number. */ void VectorFile::setVectorNodeNumber(const int vectorIndex, const int nodeNumberIn) { this->setDataValue(INDEX_NODE_NUMBER, vectorIndex, nodeNumberIn); } /** * get the vector's magnitude. */ float VectorFile::getVectorMagnitude(const int vectorIndex) const { return this->getDataValue(INDEX_MAGNITUDE, vectorIndex); } /** * set the vector's magnitude. */ void VectorFile::setVectorMagnitude(const int vectorIndex, const float magnitudeIn) { this->setDataValue(INDEX_MAGNITUDE, vectorIndex, magnitudeIn); } /** * set the vector's data (pass NULL for undesired items). */ void VectorFile::setVectorData(const int vectorIndex, const float xyzOriginIn[3], const float xyzComponentsIn[3], const float magnitudeIn, const int nodeNumberIn, const float rgbaColorsIn[4], const float radiusIn) { bool setColorFlag = true; float rgba[4]; VectorFile::getDefaultColorRGBA(rgba); if (rgbaColorsIn != NULL) { rgba[0] = rgbaColorsIn[0]; rgba[1] = rgbaColorsIn[1]; rgba[2] = rgbaColorsIn[2]; rgba[3] = rgbaColorsIn[3]; } else if (this->getDataValue(INDEX_COLOR_ALPHA, vectorIndex) != 0.0) { setColorFlag = false; } this->setVectorOrigin(vectorIndex, xyzOriginIn); this->setVectorUnitComponents(vectorIndex, xyzComponentsIn); this->setVectorMagnitude(vectorIndex, magnitudeIn); this->setVectorNodeNumber(vectorIndex, nodeNumberIn); if (setColorFlag) { this->setVectorColorRGBA(vectorIndex, rgba); } this->setVectorRadius(vectorIndex, radiusIn); } /** * set a data array value. */ void VectorFile::setDataValue(const int arrayIndex, const int vectorIndex, const float value) { float* data = this->dataArrays[arrayIndex]->getDataPointerFloat(); data[vectorIndex] = value; setModified(); } /** * } * get PubMedID's of all linked studies. */ void VectorFile::getPubMedIDsOfAllLinkedStudyMetaData(std::vector& studyPMIDs) const { } /** * get the default color. */ void VectorFile::getDefaultColorRGBA(float rgba[4]) { rgba[0] = VectorFile::defaultColor[0]; rgba[1] = VectorFile::defaultColor[1]; rgba[2] = VectorFile::defaultColor[2]; rgba[3] = VectorFile::defaultColor[3]; } /** * Apply transformation matrix to vector file. */ void VectorFile::applyTransformationMatrix(const TransformationMatrix& tmIn) { // // Get the transformation matrix and create a second transformation // matrix without rotation. // TransformationMatrix& tm = const_cast(tmIn); TransformationMatrix tmNoTranslate = tm; tmNoTranslate.setTranslation(0.0, 0.0, 0.0); const int num = this->getNumberOfVectors(); for (int i = 0; i < num; i++) { // // Get the origin and the vector components // float origin[3]; float vector[3]; this->getVectorOrigin(i, origin); this->getVectorUnitComponents(i, vector); // // Create a point at the end of the vector // float mag = this->getVectorMagnitude(i); float endPoint[3] = { origin[0] + (vector[0] * mag), origin[1] + (vector[1] * mag), origin[2] + (vector[2] * mag), }; // // Transform the origin // tm.multiplyPoint(origin); // // Transform the vector using the without rotation matrix // Also normalize the vector // tmNoTranslate.multiplyPoint(vector); MathUtilities::normalize(vector); // // Store the results // this->setVectorOrigin(i, origin); this->setVectorUnitComponents(i, vector); // // Transform the endpoint and compare it to the new endpoint // tm.multiplyPoint(endPoint); float endVector[3]; MathUtilities::subtractVectors(endPoint, origin, endVector); MathUtilities::normalize(endVector); const float endPointTest[3] = { origin[0] + (endVector[0] * mag), origin[1] + (endVector[1] * mag), origin[2] + (endVector[2] * mag) }; const float endTest[3] = { origin[0] + (vector[0] * mag), origin[1] + (vector[1] * mag), origin[2] + (vector[2] * mag), }; const float diff = MathUtilities::distance3D(endTest, endPointTest); if (diff > 0.001) { std::cout << "Vector Transform: vector rotation difference: " << diff << std::endl; } } setModified(); } /** * get the data array description. */ QString VectorFile::getDataArrayDescription(const DATA_INDEX dataIndex) { QString s("Unknown"); switch (dataIndex) { case INDEX_NODE_NUMBER: s = "Node Number"; break; case INDEX_X_COORDINATE: s = "Origin-X"; break; case INDEX_Y_COORDINATE: s = "Origin-Y"; break; case INDEX_Z_COORDINATE: s = "Origin-Z"; break; case INDEX_X_COMPONENT: s = "Unit Vector-X"; break; case INDEX_Y_COMPONENT: s = "Unit Vector-Y"; break; case INDEX_Z_COMPONENT: s = "Unit Vector-Z"; break; case INDEX_MAGNITUDE: s = "Magnitude"; break; case INDEX_RADIUS: s = "Radius"; break; case INDEX_COLOR_RED: s = "Red"; break; case INDEX_COLOR_GREEN: s = "Green"; break; case INDEX_COLOR_BLUE: s = "Blue"; break; case INDEX_COLOR_ALPHA: s = "Alpha"; break; case NUMBER_OF_ARRAYS: s = "Number of Arrays"; break; } return s; } /** * validate the data arrays (optional for subclasses). */ void VectorFile::validateDataArrays() throw (FileException) { if (this->getNumberOfDataArrays() != VectorFile::NUMBER_OF_ARRAYS) { throw FileException("The number of data arrays is invalid. Is the file " "an obsolete version?"); } } /** * Write the file's memory in caret6 format to the specified name. */ QString VectorFile::writeFileInCaret6Format(const QString& filenameIn, Structure structure,const ColorFile* colorFileIn, const bool useCaret6ExtensionFlag) throw (FileException) { int numVectors = this->getNumberOfVectors(); if (numVectors <= 0) { return ""; } QString description; for (int i = 0; i < NUMBER_OF_ARRAYS; i++) { description += (QString("(") + QString::number(i) + ") " + getDataArrayDescription((DATA_INDEX)i) + ", "); } QString name = filenameIn; if (useCaret6ExtensionFlag) { name = FileUtilities::replaceExtension(filenameIn, SpecFile::getGiftiVectorFileExtension(), SpecFile::getGiftiVectorFileExtension()); } std::vector dims; dims.push_back(numVectors); dims.push_back(NUMBER_OF_ARRAYS); GiftiDataArrayFile gdaf; GiftiDataArray* gda = new GiftiDataArray(&gdaf, "CARET_VECTOR", GiftiDataArray::DATA_TYPE_FLOAT32, dims); gda->getMetaData()->set("Array Columns", description); gdaf.addDataArray(gda); int varIndex[2]; for (int i = 0; i < numVectors; i++) { varIndex[0] = i; varIndex[1] = INDEX_NODE_NUMBER; gda->setDataFloat32(varIndex, this->getDataValue(varIndex[1], i)); varIndex[1] = INDEX_X_COORDINATE; gda->setDataFloat32(varIndex, this->getDataValue(varIndex[1], i)); varIndex[1] = INDEX_Y_COORDINATE; gda->setDataFloat32(varIndex, this->getDataValue(varIndex[1], i)); varIndex[1] = INDEX_Z_COORDINATE; gda->setDataFloat32(varIndex, this->getDataValue(varIndex[1], i)); varIndex[1] = INDEX_X_COMPONENT; gda->setDataFloat32(varIndex, this->getDataValue(varIndex[1], i)); varIndex[1] = INDEX_Y_COMPONENT; gda->setDataFloat32(varIndex, this->getDataValue(varIndex[1], i)); varIndex[1] = INDEX_Z_COMPONENT; gda->setDataFloat32(varIndex, this->getDataValue(varIndex[1], i)); varIndex[1] = INDEX_MAGNITUDE; gda->setDataFloat32(varIndex, this->getDataValue(varIndex[1], i)); varIndex[1] = INDEX_RADIUS; gda->setDataFloat32(varIndex, this->getDataValue(varIndex[1], i)); varIndex[1] = INDEX_COLOR_RED; gda->setDataFloat32(varIndex, this->getDataValue(varIndex[1], i)); varIndex[1] = INDEX_COLOR_GREEN; gda->setDataFloat32(varIndex, this->getDataValue(varIndex[1], i)); varIndex[1] = INDEX_COLOR_BLUE; gda->setDataFloat32(varIndex, this->getDataValue(varIndex[1], i)); varIndex[1] = INDEX_COLOR_ALPHA; gda->setDataFloat32(varIndex, this->getDataValue(varIndex[1], i)); } gdaf.setFileWriteType(AbstractFile::FILE_FORMAT_XML_GZIP_BASE64); gdaf.writeFile(name); return name; } caret-5.6.4~dfsg.1.orig/caret_files/TransformationMatrixFile.h0000664000175000017500000004062511572067322024214 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __TRANSFORMATION_MATRIX_FILE_H__ #define __TRANSFORMATION_MATRIX_FILE_H__ #include "AbstractFile.h" #include "SceneFile.h" class TransformationMatrixFile; class vtkMatrix4x4; class vtkTransform; /// This class contains a transformation matrix. This matrix is Post Multiply /// to be compatible with OpenGL. class TransformationMatrix { public: /// Rotation axes enum ROTATE_AXIS { ROTATE_X_AXIS, ROTATE_Y_AXIS, ROTATE_Z_AXIS }; private: /// set the matrix file that contains this matrix as modified void setMatrixFileModified(); /// the transformation matrix double matrix[4][4]; /// anterior commissure coordinates int acCoords[3]; /// dimension of the volume int volumeDimensions[3]; /// name of this matrix QString name; /// comment associated with this matrix QString comment; /// fiducial coordinate file associated with this matrix QString targetFiducialCoordFileName; /// volume associated with this matrix QString targetVolumeFileName; /// transformation matrix file this matrix is associated with TransformationMatrixFile* matrixFile; /// show the transform's axes bool showAxes; /// axes length float axesLength; static const QString tagMatrixName; static const QString tagMatrixComment; static const QString tagMatrixTargetVolumeFileName; static const QString tagMatrixTargetVolumeDimensions; static const QString tagMatrixTargetACCoords; static const QString tagMatrixFiducialCoordFileName; static const QString tagMatrixBegin; /// matrix number counter static int matrixNumberCounter; /// copy data to this from another TransformationMatrix void copyData(const TransformationMatrix& tm); public: /// constructor TransformationMatrix(); /// copy constructor TransformationMatrix(const TransformationMatrix& tm); /// destructor ~TransformationMatrix(); /// assignment operator TransformationMatrix& operator=(const TransformationMatrix& tm); /// clear the matrix void clear(); /// get the matrix number counter static int getMatrixNumberCounter() { return matrixNumberCounter; } /// get show the transform matrix's axes bool getShowAxes() const { return showAxes; } /// set show the transform matrix's axes void setShowAxes(const bool sa) { showAxes = sa; } /// get the axes length float getAxesLength() const { return axesLength; } /// set the axes length void setAxesLength(const float len) { axesLength = len; } /// get the translation from the matrix void getTranslation(double& tx, double& ty, double& tz) const; /// get the translation from the matrix void getTranslation(float& tx, float& ty, float& tz) const; /// sets (overrides) the translation in the matrix void setTranslation(const double tx, const double ty, const double tz); /// sets (overrides) the translation in the matrix void setTranslation(const float tx, const float ty, const float tz); /// get the rotation angles from the matrix void getRotationAngles(double& rx, double& ry, double& rz) const; /// get the rotation angles from the matrix void getRotationAngles(float& rx, float& ry, float& rz) const; /// get the scaling from the matrix (incorrect in some circumstances) void getScaling(double& sx, double& sy, double& sz) const; /// get the scaling from the matrix (incorrect in some circumstances) void getScaling(float& sx, float& sy, float& sz) const; /// get the matrix as a VTK 4x4 matrix void getMatrix(vtkMatrix4x4* m) const; /// set the matrix from a VTK 4x4 matrix void setMatrix(const vtkMatrix4x4* m); /// get the matrix as a VTK transform matrix void getMatrix(vtkTransform* m) const; /// set the matrix from a VTK transform matrix void setMatrix(const vtkTransform* m); /// set the matrix void setMatrix(const double translate[3], const double rotate[3], const double scale[3]); /// get the entire matrix void getMatrix(double m[4][4]) const; /// get the entire matrix void getMatrix(float m[4][4]) const; /// get the entire matrix void getMatrix(float m[16]) const; /// get the entire matrix void getMatrix(double m[16]) const; /// get the AC coords void getMatrixTargetACCoords(int& x, int& y, int& z) const; /// get an element from the matrix double getMatrixElement(const int row, const int column) const; /// get the comment QString getMatrixComment() const { return comment; } /// get the matrix name QString getMatrixName() const { return name; } /// get the target volume file name QString getMatrixTargetVolumeFileName() const { return targetVolumeFileName; } /// get the volume dimeensions void getMatrixTargetVolumeDimensions(int& x, int& y, int& z) const; /// get the target fiducial file name QString getMatrixFiducialCoordFileName() const { return targetFiducialCoordFileName; } // read the matrix name, comment, and 4x4 matrix void readMatrix(QTextStream& stream, const QString& filename) throw (FileException); /// read the 4x4 matrix void readMatrixData(QTextStream& stream, const QString& firstLine, const QString& filename) throw (FileException); /// set the entire matrix void setMatrix(const double m[4][4]); /// set the entire matrix void setMatrix(const float m[4][4]); /// set the entire matrix void setMatrix(const double m[16]); /// set the entire matrix void setMatrix(const float m[16]); /// set the AC coords void setMatrixTargetACCoords(const int x, const int y, const int z); /// set an element of the matrix void setMatrixElement(const int row, const int column, const double value); /// set the comment void setMatrixComment(const QString& s) { comment = s; } /// set the name void setMatrixName(const QString& s) { name = s; } /// set the name of the target volume void setMatrixTargetVolumeFileName(const QString& s) { targetVolumeFileName = s; } /// set the name of the target volume void setMatrixFiducialCoordFileName(const QString& s) { targetFiducialCoordFileName = s; } /// set the volume dimeensions void setMatrixTargetVolumeDimensions(const int x, const int y, const int z); /// write the matrix void writeMatrix(QTextStream& stream); /// see if the matrix is the identity matrix bool isIdentity() const; //-------------------------------------------------------- // Operations on the matrix //-------------------------------------------------------- /// set the matrix to the identity matrix void identity(); /// set the matrix to the inverse of itself void inverse(); // // Multiply by the matrix in the specified file // int multiply(const string& matrixFilename); /// Pre Multiply by the TransformationMatrix void preMultiply(const TransformationMatrix& tmf); /// Pre Multiply by the TransformationMatrix void postMultiply(const TransformationMatrix& tmf); /// Apply the transformation matrix to a point void multiplyPoint(double p[3]) const; /// Apply the transformation matrix to a point void multiplyPoint(float p[3]) const; /// Apply the transformation matrix to a point void inverseMultiplyPoint(float p[3]) const; /// Apply the inverse of the transformation matrix to a point void inverseMultiplyPoint(double p[3]) const; /// Multiply by the matrix containing the specified rotation void rotate(const TransformationMatrix::ROTATE_AXIS rotationAxis, const double rotateDegrees); /// Multiply by the matrix containing the specified rotation /// about the specified axis void rotate(const double rotateDegrees, const double axis[3]); /// rotate about the X axis void rotateX(const double rotateDegrees); /// rotate about the Y axis void rotateY(const double rotateDegrees); /// rotate about the Z axis void rotateZ(const double rotateDegrees); /// rotate using the three angles relative to "relativeMatrix" void rotate(const double angles[3], vtkTransform* relativeMatrix); /// Multiply by the matrix with the specified scaling void scale(const double scaleX, const double scaleY, const double scaleZ); /// Multiply by the matrix with the specified scaling void scale(const double scaleXYZ[3]); /// Multiply by the matrix with the specified scaling void scale(const float scaleX, const float scaleY, const float scaleZ); /// Multiply by the matrix with the specified scaling void scale(const float scaleXYZ[3]); /// Multiply by the matrix with the specified translation relative to "relativeMatrix" void translate(const double translateXYZ[3], vtkTransform* relativeMatrix); /// Multiply by the matrix with the specified translation void translate(const double translateX, const double translateY, const double translateZ); /// Multiply by the matrix with the specified translation void translate(const float translateX, const float translateY, const float translateZ); /// Multiply by the matrix with the specified translation void translate(const double translateXYZ[3]); /// Multiply by the matrix with the specified translation void translate(const float translateXYZ[3]); /// set the matrix to the transpose of itself void transpose(); friend class TransformationMatrixFile; }; #ifdef _TRANSFORMATION_FILE_MAIN_ const QString TransformationMatrix::tagMatrixName = "tag-matrix-name"; const QString TransformationMatrix::tagMatrixComment = "tag-matrix-comment"; const QString TransformationMatrix::tagMatrixTargetVolumeFileName = "tag-matrix-target-volume-name"; const QString TransformationMatrix::tagMatrixTargetVolumeDimensions = "tag-matrix-target-volume-dimensions"; const QString TransformationMatrix::tagMatrixTargetACCoords = "tag-matrix-target-AC-coords"; const QString TransformationMatrix::tagMatrixFiducialCoordFileName = "tag-matrix-fiducial-coord-name"; const QString TransformationMatrix::tagMatrixBegin = "tag-matrix-begin"; int TransformationMatrix::matrixNumberCounter = 1; #endif // _TRANSFORMATION_FILE_MAIN_ /// File that contains one or more TransoformationMatrix class TransformationMatrixFile : public AbstractFile { private: /// The transformation matrices std::vector matrices; /// index of selected tranformation matrix axes int selectedAxesIndex; static const QString tagMatrixFileVersion; static const QString tagNumberOfMatrices; static const QString tagEndOfTags; /// read the transformation matrix file void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException); /// read a version 1 file void readFileVersion_1(QTextStream& stream) throw (FileException); /// read a version 2 file void readFileVersion_2(QTextStream& stream) throw (FileException); /// write the transformation matrix file void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException); public: /// constructor TransformationMatrixFile(); /// destructor ~TransformationMatrixFile(); /// Append a transformation matrix file to this one void append(TransformationMatrixFile& tmf); /// clear the matrix file void clear(); /// add a transformation matrix void addTransformationMatrix(const TransformationMatrix& tm); /// delete a matrix void deleteMatrix(const int matrixNumber); /// find out if file is isEmpty bool empty() const; /// get a transformation matrix for modifying TransformationMatrix* getTransformationMatrix(const int i); /// get a transformation matrix const TransformationMatrix* getTransformationMatrix(const int i) const; /// get a transformation matrix by int name for modifying TransformationMatrix* getTransformationMatrixWithName(const QString& name); /// get a transformation matrix by its name const TransformationMatrix* getTransformationMatrixWithName(const QString& name) const; /// get the number of matrices int getNumberOfMatrices() const { return (int)matrices.size(); } /// get the selected transformation axes int getSelectedTransformationAxesIndex() const { return selectedAxesIndex; } /// set the selected transformation axes void setSelectedTransformationAxesIndex(const int indx) { selectedAxesIndex = indx; } /// get the index of a matrix (-1 if matrix invalid) int getMatrixIndex(const TransformationMatrix* tm) const; /// see if matrix is still valid (could have been deleted) bool getMatrixValid(const TransformationMatrix* tm) const; /// read the spec file from a scene void showScene(const SceneFile::Scene& scene, QString& errorMessage); /// write the spec file to a scene void saveScene(SceneFile::Scene& scene, const bool selectedFilesOnlyFlag); friend class TransformationMatrix; }; #endif // __TRANSFORMATION_MATRIX_FILE_H__ #ifdef _TRANSFORMATION_FILE_MAIN_ const QString TransformationMatrixFile::tagMatrixFileVersion = "tag-transformation-matrix-file-version"; const QString TransformationMatrixFile::tagNumberOfMatrices = "tag-number-of-matrices"; const QString TransformationMatrixFile::tagEndOfTags = "tag-end-of-tags"; #endif // _TRANSFORMATION_FILE_MAIN_ caret-5.6.4~dfsg.1.orig/caret_files/TransformationMatrixFile.cxx0000664000175000017500000010460511572067322024566 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #define _TRANSFORMATION_FILE_MAIN_ #include "TransformationMatrixFile.h" #undef _TRANSFORMATION_FILE_MAIN_ #include "MathUtilities.h" #include "SpecFile.h" #include "StringUtilities.h" #include "vtkMatrix4x4.h" #include "vtkTransform.h" //-------------------------------------------------------------------------- /* * Constructor */ TransformationMatrix::TransformationMatrix() { matrixFile = NULL; clear(); } /* * Copy Constructor */ TransformationMatrix::TransformationMatrix(const TransformationMatrix& tm) { copyData(tm); } /* * assignment operator */ TransformationMatrix& TransformationMatrix::operator=(const TransformationMatrix& tm) { copyData(tm); return *this; } /* * copy all data from another object to this object */ void TransformationMatrix::copyData(const TransformationMatrix& tm) { matrixFile = NULL; clear(); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { matrix[i][j] = tm.matrix[i][j]; } } matrixFile = NULL; //will get set when added to file tm.matrixFile; setMatrixName(tm.getMatrixName()); setMatrixComment(tm.getMatrixComment()); int x, y, z; tm.getMatrixTargetACCoords(x, y, z); setMatrixTargetACCoords(x, y, z); tm.getMatrixTargetVolumeDimensions(x, y, z); setMatrixTargetVolumeDimensions(x, y, z); setMatrixTargetVolumeFileName(tm.getMatrixTargetVolumeFileName()); setMatrixFiducialCoordFileName(tm.getMatrixFiducialCoordFileName()); showAxes = tm.showAxes; axesLength = tm.axesLength; } /* * Destructor */ TransformationMatrix::~TransformationMatrix() { } /** * Set the matrix file that contains this matrix as modified. */ void TransformationMatrix::setMatrixFileModified() { if (matrixFile != NULL) { matrixFile->setModified(); } } /* * clear the matrix file */ void TransformationMatrix::clear() { identity(); std::ostringstream str; str << "Matrix " << matrixNumberCounter; matrixNumberCounter++; name = str.str().c_str(); comment = ""; targetFiducialCoordFileName = ""; targetVolumeFileName = ""; acCoords[0] = -1; acCoords[1] = -1; acCoords[2] = -1; volumeDimensions[0] = -1; volumeDimensions[1] = -1; volumeDimensions[2] = -1; setMatrixFileModified(); showAxes = false; axesLength = 100.0; } /** * get the translation from the matrix. */ void TransformationMatrix::getTranslation(double& tx, double& ty, double& tz) const { vtkTransform* tm = vtkTransform::New(); getMatrix(tm); double pos[3]; tm->GetPosition(pos); tx = pos[0]; ty = pos[1]; tz = pos[2]; tm->Delete(); } /** * get the translation from the matrix. */ void TransformationMatrix::getTranslation(float& tx, float& ty, float& tz) const { double txd, tyd, tzd; getTranslation(txd, tyd, tzd); tx = txd; ty = tyd; tz = tzd; } /** * sets (overrides) the translation in the matrix. */ void TransformationMatrix::setTranslation(const double tx, const double ty, const double tz) { matrix[0][3] = tx; matrix[1][3] = ty; matrix[2][3] = tz; } /** * sets (overrides) the translation in the matrix. */ void TransformationMatrix::setTranslation(const float tx, const float ty, const float tz) { matrix[0][3] = tx; matrix[1][3] = ty; matrix[2][3] = tz; } /** * get the rotation angles from the matrix. */ void TransformationMatrix::getRotationAngles(double& rx, double& ry, double& rz) const { vtkTransform* tm = vtkTransform::New(); getMatrix(tm); double angles[3]; tm->GetOrientation(angles); rx = angles[0]; ry = angles[1]; rz = angles[2]; tm->Delete(); } /** * get the rotation angles from the matrix. */ void TransformationMatrix::getRotationAngles(float& rx, float& ry, float& rz) const { double rxd, ryd, rzd; getRotationAngles(rxd, ryd, rzd); rx = rxd; ry = ryd; rz = rzd; } /** * get the scaling from the matrix (incorrect in some circumstances). */ void TransformationMatrix::getScaling(double& sx, double& sy, double& sz) const { vtkTransform* tm = vtkTransform::New(); getMatrix(tm); double scale[3]; tm->GetScale(scale); MathUtilities::sign(scale[0], matrix[0][0]); MathUtilities::sign(scale[1], matrix[1][1]); MathUtilities::sign(scale[2], matrix[2][2]); sx = scale[0]; sy = scale[1]; sz = scale[2]; tm->Delete(); } /** * get the scaling from the matrix (incorrect in some circumstances). */ void TransformationMatrix::getScaling(float& sx, float& sy, float& sz) const { double sxd, syd, szd; getScaling(sxd, syd, szd); sx = sxd; sy = syd; sz = szd; } /* * get the entire matrix */ void TransformationMatrix::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]; } } } /** * get the entire matrix. */ void TransformationMatrix::getMatrix(float m[4][4]) const { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { m[i][j] = static_cast(matrix[i][j]); } } TransformationMatrix tm = *this; } /** * set the matrix. */ void TransformationMatrix::setMatrix(const double translateV[3], const double rotateV[3], const double scaleV[3]) { vtkTransform* transform = vtkTransform::New(); transform->PreMultiply(); transform->Translate(translateV); transform->RotateZ(rotateV[2]); transform->RotateX(rotateV[0]); transform->RotateY(rotateV[1]); transform->Scale(scaleV); setMatrix(transform); transform->Delete(); } /** * set the entire matrix. */ void TransformationMatrix::setMatrix(const float m[16]) { matrix[0][0] = m[0]; matrix[1][0] = m[1]; matrix[2][0] = m[2]; matrix[3][0] = m[3]; matrix[0][1] = m[4]; matrix[1][1] = m[5]; matrix[2][1] = m[6]; matrix[3][1] = m[7]; matrix[0][2] = m[8]; matrix[1][2] = m[9]; matrix[2][2] = m[10]; matrix[3][2] = m[11]; matrix[0][3] = m[12]; matrix[1][3] = m[13]; matrix[2][3] = m[14]; matrix[3][3] = m[15]; setMatrixFileModified(); } /** * set the entire matrix. */ void TransformationMatrix::setMatrix(const double m[16]) { matrix[0][0] = m[0]; matrix[1][0] = m[1]; matrix[2][0] = m[2]; matrix[3][0] = m[3]; matrix[0][1] = m[4]; matrix[1][1] = m[5]; matrix[2][1] = m[6]; matrix[3][1] = m[7]; matrix[0][2] = m[8]; matrix[1][2] = m[9]; matrix[2][2] = m[10]; matrix[3][2] = m[11]; matrix[0][3] = m[12]; matrix[1][3] = m[13]; matrix[2][3] = m[14]; matrix[3][3] = m[15]; setMatrixFileModified(); } /** * get the entire matrix. */ void TransformationMatrix::getMatrix(float m[16]) const { m[0] = matrix[0][0]; m[1] = matrix[1][0]; m[2] = matrix[2][0]; m[3] = matrix[3][0]; m[4] = matrix[0][1]; m[5] = matrix[1][1]; m[6] = matrix[2][1]; m[7] = matrix[3][1]; m[8] = matrix[0][2]; m[9] = matrix[1][2]; m[10] = matrix[2][2]; m[11] = matrix[3][2]; m[12] = matrix[0][3]; m[13] = matrix[1][3]; m[14] = matrix[2][3]; m[15] = matrix[3][3]; } /** * get the entire matrix. */ void TransformationMatrix::getMatrix(double m[16]) const { m[0] = matrix[0][0]; m[1] = matrix[1][0]; m[2] = matrix[2][0]; m[3] = matrix[3][0]; m[4] = matrix[0][1]; m[5] = matrix[1][1]; m[6] = matrix[2][1]; m[7] = matrix[3][1]; m[8] = matrix[0][2]; m[9] = matrix[1][2]; m[10] = matrix[2][2]; m[11] = matrix[3][2]; m[12] = matrix[0][3]; m[13] = matrix[1][3]; m[14] = matrix[2][3]; m[15] = matrix[3][3]; } /* * get an element from the matrix */ double TransformationMatrix::getMatrixElement(const int row, const int column) const { return matrix[row][column]; } /* * set the entire matrix */ void TransformationMatrix::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]; } } setMatrixFileModified(); } /* * set the entire matrix */ void TransformationMatrix::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]; } } setMatrixFileModified(); } /* * set an element of the matrix */ void TransformationMatrix::setMatrixElement(const int row, const int column, const double value) { matrix[row][column] = value; setMatrixFileModified(); } /* * get the volume dimeensions */ void TransformationMatrix::getMatrixTargetVolumeDimensions(int& x, int& y, int& z) const { x = volumeDimensions[0]; y = volumeDimensions[1]; z = volumeDimensions[2]; } /* * set the AC coords */ void TransformationMatrix::setMatrixTargetACCoords(const int x, const int y, const int z) { acCoords[0] = x; acCoords[1] = y; acCoords[2] = z; setMatrixFileModified(); } /* * get the AC coords */ void TransformationMatrix::getMatrixTargetACCoords(int& x, int& y, int& z) const { x = acCoords[0]; y = acCoords[1]; z = acCoords[2]; } /* * set the volume dimeensions */ void TransformationMatrix::setMatrixTargetVolumeDimensions(const int x, const int y, const int z) { volumeDimensions[0] = x; volumeDimensions[1] = y; volumeDimensions[2] = z; setMatrixFileModified(); } /* * read the 4x4 matrix */ void TransformationMatrix::readMatrixData(QTextStream& stream, const QString& firstLine, const QString& filename) throw (FileException) { for (int i = 0; i < 4; i++) { QString line; std::vector tokens; if ((i == 0) && (firstLine.isEmpty() == false)) { line = firstLine; StringUtilities::token(line, " \t", tokens); } else { AbstractFile::readLineIntoTokens(filename, stream, line, tokens); } if (tokens.size() < 4) { QString msg("Matrix line missing data: "); msg.append(line); throw FileException(filename, msg); } else { setMatrixElement(i, 0, tokens[0].toFloat()); setMatrixElement(i, 1, tokens[1].toFloat()); setMatrixElement(i, 2, tokens[2].toFloat()); setMatrixElement(i, 3, tokens[3].toFloat()); } } } /* * read a transformation matrix */ void TransformationMatrix::readMatrix(QTextStream& stream, const QString& filename) throw (FileException) { bool readingTags = true; while (readingTags) { QString tag, value; AbstractFile::readTagLine(filename, stream, tag, value); if (tag == tagMatrixName) { name = value; } else if (tag == tagMatrixComment) { comment = value; } else if (tag == tagMatrixTargetVolumeFileName) { targetVolumeFileName = value; } else if (tag == tagMatrixFiducialCoordFileName) { targetFiducialCoordFileName = value; } else if (tag == tagMatrixTargetVolumeDimensions) { std::vector tokens; StringUtilities::token(value, " ", tokens); if (tokens.size() < 3) { QString msg("Error reading line with volume dimensions "); msg.append(value); throw FileException(filename, msg); } volumeDimensions[0] = tokens[0].toInt(); volumeDimensions[1] = tokens[1].toInt(); volumeDimensions[2] = tokens[2].toInt(); } else if (tag == tagMatrixTargetACCoords) { std::vector tokens; StringUtilities::token(value, " ", tokens); if (tokens.size() < 3) { QString msg("Error reading line with ac coords "); msg.append(value); throw FileException(filename, msg); } acCoords[0] = tokens[0].toInt(); acCoords[1] = tokens[1].toInt(); acCoords[2] = tokens[2].toInt(); } else if (tag == tagMatrixBegin) { readingTags = false; } } return readMatrixData(stream, "", filename); } /* * write a transformation matrix */ void TransformationMatrix::writeMatrix(QTextStream& stream) { stream << tagMatrixName << " " << name << "\n"; stream << tagMatrixComment << " " << comment << "\n"; stream << tagMatrixTargetVolumeFileName << " " << targetVolumeFileName << "\n"; stream << tagMatrixTargetVolumeDimensions << " " << volumeDimensions[0] << " " << volumeDimensions[1] << " " << volumeDimensions[2] << "\n"; stream << tagMatrixFiducialCoordFileName << " " << targetFiducialCoordFileName << "\n"; stream << tagMatrixTargetACCoords << " " << acCoords[0] << " " << acCoords[1] << " " << acCoords[2] << "\n"; stream << tagMatrixBegin << "\n"; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { stream << getMatrixElement(i, j) << " "; } stream << "\n"; } } /* * set the matrix to the identity matrix */ void TransformationMatrix::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; setMatrixFileModified(); } /** * get the matrix as a VTK 4x4 matrix. */ void TransformationMatrix::getMatrix(vtkMatrix4x4* m) const { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { m->SetElement(i, j, matrix[i][j]); } } } /** * set the matrix from a VTK 4x4 matrix. */ void TransformationMatrix::setMatrix(const vtkMatrix4x4* m) { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { matrix[i][j] = m->GetElement(i, j); } } setMatrixFileModified(); } /** * get the matrix as a VTK transform matrix. */ void TransformationMatrix::getMatrix(vtkTransform* m) const { vtkMatrix4x4* m44 = vtkMatrix4x4::New(); getMatrix(m44); m->SetMatrix(m44); m44->Delete(); } /** * set the matrix from a VTK transform matrix. */ void TransformationMatrix::setMatrix(const vtkTransform* m) { vtkMatrix4x4* m44 = vtkMatrix4x4::New(); ((vtkTransform*)m)->GetMatrix(m44); setMatrix(m44); setMatrixFileModified(); m44->Delete(); } /* * invert the matrix */ void TransformationMatrix::inverse() { vtkTransform* m = vtkTransform::New(); getMatrix(m); m->Inverse(); setMatrix(m); setMatrixFileModified(); m->Delete(); } /* * transpose the matrix */ void TransformationMatrix::transpose() { std::swap(matrix[1][0], matrix[0][1]); std::swap(matrix[2][0], matrix[0][2]); std::swap(matrix[2][1], matrix[1][2]); std::swap(matrix[3][0], matrix[0][3]); std::swap(matrix[3][1], matrix[1][3]); std::swap(matrix[3][2], matrix[2][3]); setMatrixFileModified(); } // // Multiply by the matrix in the specified file // // int // TransformationMatrix::multiply(const string& matrixFilename) // { // TransformationMatrixFile tmf(matrixFilename); // if (tmf.isBad()) { // return -1; // } // multiply(tmf); // return 0; // } /* * Multiply by the TransformationMatrix */ void TransformationMatrix::preMultiply(const TransformationMatrix& 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); setMatrixFileModified(); } /* * Post-Multiply by the TransformationMatrix */ void TransformationMatrix::postMultiply(const TransformationMatrix& 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); setMatrixFileModified(); } /* * Apply the transformation matrix to a point */ void TransformationMatrix::multiplyPoint(double p[3]) const { double pout[3]; for (int row = 0; row < 3; row++) { pout[row] = matrix[row][0] * p[0] + matrix[row][1] * p[1] + matrix[row][2] * p[2] + matrix[row][3]; } p[0] = pout[0]; p[1] = pout[1]; p[2] = pout[2]; } /** * Apply the transformation matrix to a point. */ void TransformationMatrix::multiplyPoint(float p[3]) const { double d[3] = { p[0], p[1], p[2] }; multiplyPoint(d); p[0] = d[0]; p[1] = d[1]; p[2] = d[2]; } /** * Apply the inverse of a transformation matrix to a point. */ void TransformationMatrix::inverseMultiplyPoint(float p[3]) const { double d[3] = { p[0], p[1], p[2] }; inverseMultiplyPoint(d); p[0] = d[0]; p[1] = d[1]; p[2] = d[2]; } /* * Apply the inverse of the transformation matrix to a point */ void TransformationMatrix::inverseMultiplyPoint(double p[3]) const { TransformationMatrix inverseMatrix = *this; inverseMatrix.inverse(); inverseMatrix.multiplyPoint(p); } /** * rotate using the three angles relative to "relativeMatrix". */ void TransformationMatrix::rotate(const double angles[3], vtkTransform* relativeMatrix) { /* double rotX = angles[0]; double rotY = angles[1]; double rotZ = angles[2]; if (relativeMatrix != NULL) { float dt[4] = { rotX, rotY, rotZ, 1.0 }; float dt2[4]; relativeMatrix->MultiplyPoint(dt, dt2); rotX = dt2[0]; rotY = dt2[1]; rotZ = dt2[2]; } vtkTransform* m = vtkTransform::New(); m->PostMultiply(); const double t[3] = { matrix[0][3], matrix[1][3], matrix[2][3] }; matrix[0][3] = 0.0; matrix[1][3] = 0.0; matrix[2][3] = 0.0; getMatrix(m); if (rotZ != 0.0) { m->RotateZ(rotZ); } if (rotX != 0.0) { m->RotateX(rotX); } if (rotY != 0.0) { m->RotateY(rotY); } setMatrix(m); matrix[0][3] = t[0]; matrix[1][3] = t[1]; matrix[2][3] = t[2]; setMatrixFileModified(); m->Delete(); */ /* if (rotX != 0.0) { rotateX(rotX); } if (rotY != 0.0) { rotateY(rotY); } if (rotZ != 0.0) { rotateZ(rotZ); } */ double rx = angles[0]; double ry = angles[1]; double rz = angles[2]; if (relativeMatrix != NULL) { double dt[4] = { rx, ry, rz, 1.0 }; double dt2[4]; relativeMatrix->MultiplyPoint(dt, dt2); /* vtkMatrix4x4* m = vtkMatrix4x4::New(); relativeMatrix->GetInverse(m); m->MultiplyPoint(dt, dt2); m->Delete(); */ rx = dt2[0]; ry = dt2[1]; rz = dt2[2]; } rotateZ(rz); rotateX(rx); rotateY(ry); } /** * Multiply by the matrix with the specified translation relative to "relativeMatrix". */ void TransformationMatrix::translate(const double translateXYZ[3], vtkTransform* relativeMatrix) { double tx = translateXYZ[0]; double ty = translateXYZ[1]; double tz = translateXYZ[2]; if (relativeMatrix != NULL) { double dt[4] = { tx, ty, tz, 1.0 }; double dt2[4]; relativeMatrix->MultiplyPoint(dt, dt2); /* vtkMatrix4x4* m = vtkMatrix4x4::New(); relativeMatrix->GetInverse(m); m->MultiplyPoint(dt, dt2); m->Delete(); */ tx = dt2[0]; ty = dt2[1]; tz = dt2[2]; } translate(tx, ty, tz); } /** * rotate about the X axis. */ void TransformationMatrix::rotateX(const double rotateDegrees) { rotate(ROTATE_X_AXIS, rotateDegrees); } /** * rotate about the Y axis. */ void TransformationMatrix::rotateY(const double rotateDegrees) { rotate(ROTATE_Y_AXIS, rotateDegrees); } /** * rotate about the Z axis. */ void TransformationMatrix::rotateZ(const double rotateDegrees) { rotate(ROTATE_Z_AXIS, rotateDegrees); } /* * Multiply by the matrix containing the specified rotation */ void TransformationMatrix::rotate(const TransformationMatrix::ROTATE_AXIS rotationAxis, const double rotateDegrees) { double axis[3] = { 0.0, 0.0, 0.0 }; switch(rotationAxis) { case ROTATE_X_AXIS: axis[0] = 1.0; break; case ROTATE_Y_AXIS: axis[1] = 1.0; break; case ROTATE_Z_AXIS: axis[2] = 1.0; break; } rotate(rotateDegrees, axis); setMatrixFileModified(); } /** * Multiply by the matrix containing the specified rotation. * about the specified axis. */ void TransformationMatrix::rotate(const double rotateDegrees, const double axis[3]) { vtkTransform* m = vtkTransform::New(); getMatrix(m); m->RotateWXYZ(rotateDegrees, axis); setMatrix(m); setMatrixFileModified(); m->Delete(); } /* * Multiply by the matrix with the specified scaling */ void TransformationMatrix::scale(const double scaleX, const double scaleY, const double scaleZ) { TransformationMatrix m; m.matrix[0][0] = scaleX; m.matrix[1][1] = scaleY; m.matrix[2][2] = scaleZ; preMultiply(m); setMatrixFileModified(); } /* * Multiply by the matrix with the specified scaling */ void TransformationMatrix::scale(const double scaleXYZ[3]) { scale(scaleXYZ[0], scaleXYZ[1], scaleXYZ[2]); setMatrixFileModified(); } /* * Multiply by the matrix with the specified scaling */ void TransformationMatrix::scale(const float scaleX, const float scaleY, const float scaleZ) { scale(static_cast(scaleX), static_cast(scaleY), static_cast(scaleZ)); setMatrixFileModified(); } /* * Multiply by the matrix with the specified scaling */ void TransformationMatrix::scale(const float scaleXYZ[3]) { scale(scaleXYZ[0], scaleXYZ[1], scaleXYZ[2]); setMatrixFileModified(); } /* * Multiply by the matrix with the specified translation */ void TransformationMatrix::translate(const double translateX, const double translateY, const double translateZ) { TransformationMatrix m; m.matrix[0][3] = translateX; m.matrix[1][3] = translateY; m.matrix[2][3] = translateZ; preMultiply(m); setMatrixFileModified(); } /* * Multiply by the matrix with the specified translation */ void TransformationMatrix::translate(const float translateX, const float translateY, const float translateZ) { translate(static_cast(translateX), static_cast(translateY), static_cast(translateZ)); setMatrixFileModified(); } /* * Multiply by the matrix with the specified translation */ void TransformationMatrix::translate(const double translateXYZ[3]) { translate(translateXYZ[0], translateXYZ[1], translateXYZ[2]); setMatrixFileModified(); } /* * Multiply by the matrix with the specified translation */ void TransformationMatrix::translate(const float translateXYZ[3]) { translate(translateXYZ[0], translateXYZ[1], translateXYZ[2]); setMatrixFileModified(); } /** * see if the matrix is the identity matrix. */ bool TransformationMatrix::isIdentity() const { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { if (i == j) { if (matrix[i][j] != 1.0) { return false; } } else { if (matrix[i][j] != 0.0) { return false; } } } } return true; } //-------------------------------------------------------------------------- /* * Constructors */ TransformationMatrixFile::TransformationMatrixFile() : AbstractFile("Transformation Matrix File", SpecFile::getTransformationMatrixFileExtension()) { clear(); } /* * destructor */ TransformationMatrixFile::~TransformationMatrixFile() { } /* * Find out if file is emtpy */ bool TransformationMatrixFile::empty() const { return (getNumberOfMatrices() == 0); } /* * add a transformation matrix */ void TransformationMatrixFile::addTransformationMatrix( const TransformationMatrix& tm) { matrices.push_back(tm); TransformationMatrix* theMatrix = getTransformationMatrix(getNumberOfMatrices() - 1); theMatrix->matrixFile = this; setModified(); } /* * append a transformation matrix file */ void TransformationMatrixFile::append(TransformationMatrixFile& tmf) { for (int i = 0; i < tmf.getNumberOfMatrices(); i++) { TransformationMatrix* tm = tmf.getTransformationMatrix(i); addTransformationMatrix(*tm); } // // transfer the file's comment // appendFileComment(tmf); } /* * clear the matrix file */ void TransformationMatrixFile::clear() { clearAbstractFile(); matrices.clear(); selectedAxesIndex = -1; //TransformationMatrix tm; //addTransformationMatrix(tm); clearModified(); } /* * delete a matrix */ void TransformationMatrixFile::deleteMatrix(const int matrixNumber) { for (int i = matrixNumber; i < ((int)matrices.size() - 1); i++) { matrices[i] = matrices[i + 1]; } matrices.pop_back(); setModified(); } /* * get a transformation matrix for modifying */ TransformationMatrix* TransformationMatrixFile::getTransformationMatrix(const int i) { if (i < static_cast(matrices.size())) { return &matrices[i]; } return NULL; } /* * get a transformation matrix for modifying */ const TransformationMatrix* TransformationMatrixFile::getTransformationMatrix(const int i) const { if (i < static_cast(matrices.size())) { return &matrices[i]; } return NULL; } /// get a transformation matrix by int name for modifying TransformationMatrix* TransformationMatrixFile::getTransformationMatrixWithName(const QString& name) { for (int i = 0; i < getNumberOfMatrices(); i++) { TransformationMatrix* tm = getTransformationMatrix(i); if (tm->getMatrixName() == name) { return tm; } } return NULL; } /// get a transformation matrix by its name const TransformationMatrix* TransformationMatrixFile::getTransformationMatrixWithName(const QString& name) const { for (int i = 0; i < getNumberOfMatrices(); i++) { const TransformationMatrix* tm = getTransformationMatrix(i); if (tm->getMatrixName() == name) { return tm; } } return NULL; } /* * read matrix file version 2 */ void TransformationMatrixFile::readFileVersion_2(QTextStream& stream) throw (FileException) { int numMatrices = -1; bool readingTags = true; while (readingTags) { QString tag, value; readTagLine(stream, tag, value); if (tag == tagNumberOfMatrices) { numMatrices = value.toInt(); } else if (tag == tagEndOfTags) { readingTags = false; } } if (numMatrices > 0) { matrices.clear(); } for (int i = 0; i < numMatrices; i++) { TransformationMatrix tm; tm.readMatrix(stream, getFileName()); addTransformationMatrix(tm); } } /* * read matrix file version 1 */ void TransformationMatrixFile::readFileVersion_1(QTextStream& stream) throw (FileException) { TransformationMatrix tm; tm.readMatrix(stream, getFileName()); addTransformationMatrix(tm); } /* * Read the matrix file's contents */ void TransformationMatrixFile::readFileData(QFile& /*file*/, QTextStream& stream, QDataStream&, QDomElement& /* rootElement */) throw (FileException) { // // Should reading data be skipped ? // if (getReadMetaDataOnlyFlag()) { return; } // get starting position of data //const QIODevice::Offset startOfMatrixData = file.at(); int version = 0; QString line, tag, value; readTagLine(stream, line, tag, value); if (tag == tagMatrixFileVersion) { switch(value.toInt()) { case 1: version = 1; break; case 2: version = 2; break; default: { QString msg("Unknown version of matrix file "); msg.append(value); throw FileException(getFileName(), msg); } } } else { version = 0; } switch(version) { case 2: readFileVersion_2(stream); break; case 1: readFileVersion_1(stream); break; default: { // set file position as data will now be read //file.at(startOfMatrixData); TransformationMatrix tm; tm.readMatrixData(stream, line, getFileName()); addTransformationMatrix(tm); } break; } } /* * write matrix file */ void TransformationMatrixFile::writeFileData(QTextStream& stream, QDataStream&, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException) { stream << tagMatrixFileVersion << " 2" << "\n"; stream << tagNumberOfMatrices << " " << getNumberOfMatrices() << "\n"; stream << tagEndOfTags << "\n"; for (int i = 0; i < getNumberOfMatrices(); i++) { matrices[i].writeMatrix(stream); } } /** * see if this matrix is valid. */ int TransformationMatrixFile::getMatrixIndex(const TransformationMatrix* tm) const { if (tm == NULL) { return -1; } for (int i = 0; i < getNumberOfMatrices(); i++) { if (getTransformationMatrix(i) == tm) { return i; } } return -1; } /** * see if matrix is still valid (could have been deleted). */ bool TransformationMatrixFile::getMatrixValid(const TransformationMatrix* tm) const { for (int i = 0; i < getNumberOfMatrices(); i++) { if (getTransformationMatrix(i) == tm) { return true; } } return false; } /** * read the spec file from a scene. */ void TransformationMatrixFile::showScene(const SceneFile::Scene& scene, QString& errorMessage) { const int numClasses = scene.getNumberOfSceneClasses(); for (int nc = 0; nc < numClasses; nc++) { const SceneFile::SceneClass* sc = scene.getSceneClass(nc); if (sc->getName() == "TransformationMatrixFile") { const int num = sc->getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc->getSceneInfo(i); const QString infoName = si->getName(); const QString matrixName = si->getModelName(); TransformationMatrix* tm = getTransformationMatrixWithName(matrixName); if (tm != NULL) { if (infoName == "showAxes") { si->getValue(tm->showAxes); } else if (infoName == "axesLength") { si->getValue(tm->axesLength); } } else { errorMessage.append("Unable to find matrix with name "); errorMessage.append(matrixName); errorMessage.append("\n"); } } } } } /** * write the spec file to a scene. */ void TransformationMatrixFile::saveScene(SceneFile::Scene& scene, const bool /*selectedFilesOnlyFlag*/) { const int num = getNumberOfMatrices(); if (num <= 0) { return; } SceneFile::SceneClass sc("TransformationMatrixFile"); for (int i = 0; i < num; i++) { const TransformationMatrix* tm = getTransformationMatrix(i); sc.addSceneInfo(SceneFile::SceneInfo("showAxes", tm->getMatrixName(), tm->showAxes)); sc.addSceneInfo(SceneFile::SceneInfo("axesLength", tm->getMatrixName(), tm->axesLength)); } if (sc.getNumberOfSceneInfo() > 0) { scene.addSceneClass(sc); } } caret-5.6.4~dfsg.1.orig/caret_files/TopologyNode.h0000664000175000017500000000372011572067322021636 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_TOPOLOGY_NODE_H__ #define __VE_TOPOLOGY_NODE_H__ /// Store topology related data /** * Stores topology related data (section, category) for nodes */ class TopologyNode { public: /// Node categories enum CATEGORIES { INTERIOR = 0, EDGE = 1, CORNER = 2, STRUCTURAL = 3 }; private: /// node's section number int section; /// Nodes category CATEGORIES category; public: /// Constructor TopologyNode(const int sectionIn, const CATEGORIES categoryIn) { setData(sectionIn, categoryIn); } /// get topology related data void getData(int& sectionOut, CATEGORIES& categoryOut) const { sectionOut = section; categoryOut = category; } /// set topology related data void setData(const int sectionIn, const CATEGORIES categoryIn) { section = sectionIn; category = categoryIn; } /// get the section number int getSectionNumber() const { return section; } }; #endif caret-5.6.4~dfsg.1.orig/caret_files/TopologyHelper.h0000664000175000017500000002566211572067322022201 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_TOPOLOGY_HELPER_H__ #define __VE_TOPOLOGY_HELPER_H__ #include #include #include #include #include #include "DebugControl.h" class TopologyFile; class vtkPolyData; /// Stores the two nodes and two tiles for an edge (link) in the surface. class TopologyEdgeInfo { public: /// nodes in the edge int node1, node2; /// tiles used by the edge int tile1, tile2; /// flat to indicate if edge is used by more than two triangles bool edgeHasMoreThanTwoTriangles; /// constructor TopologyEdgeInfo(const int tileIn, const int node1In, const int node2In) { edgeHasMoreThanTwoTriangles = false; tile1 = tileIn; tile2 = -1; node1 = node1In; node2 = node2In; if (node2 > node1) { std::swap(node1, node2); } } /// equals operator bool operator==(const TopologyEdgeInfo& e) { return ((node1 = e.node1) && (node2 == e.node2)); } /// add a tile to the edge void addTile(const int tileIn) { if (tile2 < 0) { tile2 = tileIn; } else { edgeHasMoreThanTwoTriangles = true; if (DebugControl::getDebugOn()) { std::cout << "INFO: Edge (" << node1 << ", " << node2 << ") is used by more than two tiles" << std::endl; std::cout << " Triangles: " << tile1 << " " << tile2 << " " << tileIn << std::endl; } } } /// get the more than two triangles flag bool getEdgeUsedByMoreThanTwoTriangles() const { return edgeHasMoreThanTwoTriangles; } /// get the nodes void getNodes(int& n1, int& n2) const { n1 = node1; n2 = node2; } /// get the tiles void getTiles(int& t1, int& t2) const { t1 = tile1; t2 = tile2; } /// return positive if the edge is oriented the same as the triangle in int getEdgeOrientation(const int nodes[3]) const { for (int i = 0; i < 3; i++) { if (nodes[i] == node1) { int iNext = i + 1; if (iNext >= 3) iNext = 0; if (nodes[iNext] == node2) { return 1; } else { return -1; } } } return 0; } }; /// This class is used to determine the node neighbors and edges for a Topology File. class TopologyHelper { public: /// Constructor for use with a Caret Topology File TopologyHelper(const TopologyFile* tfIn, const bool buildEdgeInfo, const bool buildNodeInfo, const bool sortNodeInfo); /// Constructor for use with a VTK PolyData file TopologyHelper(vtkPolyData* vtkIn, const bool buildEdgeInfo, const bool buildNodeInfo, const bool sortNodeInfo); /// Destructor ~TopologyHelper(); /// Get the number of nodes int getNumberOfNodes() const { return nodes.size(); } /// See if a node has neighbors bool getNodeHasNeighbors(const int nodeNum) const; /// Get the number of neighbors for a node int getNodeNumberOfNeighbors(const int nodeNum) const; /// Get the neighbors of a node void getNodeNeighbors(const int nodeNum, std::vector& neighborsOut) const; /// Get the node neighbors, restricted by roi void getNodeNeighborsInROI(const int nodeNum, std::vector& neighborsOut, const float *roiValues) const; /// Get the neighbors of a node to a specified depth the old way void getNodeNeighborsToDepthOld(const int nodeNum, const int depth, std::vector& neighborsOut) const; /// Get the neighbors to a specified depth as fast as possible, order unimportant (this is the new code) void getNodeNeighborsToDepth(const int nodeNum, const int depth, std::vector& neighborsOut) const; /// Get the neighbors to a specified depth preserving the kind of ordering of the old code void getNodeNeighborsToDepthIter(const int nodeNum, const int depth, std::vector& neighborsOut) const; private: void depthNeighHelper(int root, int remdepth, std::vector& neighborsOut) const; mutable std::vector markNodes, nodelist[2];//persistent, never cleared, only initialized once, saving bazillions of nanoseconds //could be templated over bool, which stores bitwise, but we already have three times that many floats and six times the ints in memory mutable QMutex usingMarkNodes;//do not let threads clobber markNodes public: /// Get the neighboring nodes for a node. Returns a pointer to an array /// containing the neighbors. const int* getNodeNeighbors(const int nodeNum, int& numNeighborsOut) const; /// Get the number of boundary edges used by node void getNumberOfBoundaryEdgesForAllNodes(std::vector& numBoundaryEdges) const; /// Get the maximum number of neighbors of all nodes int getMaximumNumberOfNeighbors() const; /// Get the tiles used by a node void getNodeTiles(const int nodeNum, std::vector& tilesOut) const; /// get edge info validity bool getEdgeInfoValid() const { return edgeInfoBuilt; } /// get node info validity bool getNodeInfoValid() const { return nodeInfoBuilt; } /// get node sorted info validity bool getNodeSortedInfoValid() const { return nodeSortedInfoBuilt; } /// Get the edge information const std::set& getEdgeInfo() const { return topologyEdges; } /// Get the number of edges int getNumberOfEdges() const { return topologyEdges.size(); } private: /// Stores tiles and vertices of an edge (link) for use when sorting nodes by NodeInfo. /// These edges are those opposite of a NodeInfo node, this is, given a tile with /// nodes A, B, and C, the nodes B and C would be stored in an NodeEdgeInfo for node A. class NodeEdgeInfo { public: /// nodes in the edge int node1, node2; /// tile used by this edge int tileNumber; /// constructor NodeEdgeInfo(const int tileNum, const int node1In, const int node2In) { tileNumber = tileNum; node1 = node1In; node2 = node2In; } /// get the other node in the edge int getOtherNode(const int node) const { if (node1 == node) return node2; else return node1; } /// see if a node is in the edge bool containsNode(const int node) const { return ((node1 == node) || (node2 == node)); } }; /// Stores information about a node for sorting class NodeInfo { public: /// this node's number int nodeNumber; /// tile's used by this node std::vector tiles; /// the neighboring nodes of this edge std::vector neighbors; /// the edges used to form tiles with this node std::vector edges; /// allow sorting flag bool sortMe; /// constructor NodeInfo(const int nodeNumberIn) { nodeNumber = nodeNumberIn; sortMe = true; } /// add a neighbor to this node without edge information void addNeighbor(const int newNeighbor1) { for (unsigned int i = 0; i < neighbors.size(); i++) { if (neighbors[i] == newNeighbor1) { return; } } neighbors.push_back(newNeighbor1); sortMe = false; } /// add two neighbors that form a tile using this node void addNeighbors(const int tileNum, const int newNeighbor1, const int newNeighbor2) { edges.push_back(NodeEdgeInfo(tileNum, newNeighbor1, newNeighbor2)); } /// add a tile to the node void addTile(const int tileNum) { tiles.push_back(tileNum); } /// find an edge that has one endpoint equal to "seekingNode" but /// does not contain the node "notNode". const NodeEdgeInfo* findEdgeWithPoint(const int seekingNode, const int notNode) { for (unsigned int i = 0; i < edges.size(); i++) { if ( ((edges[i].node1 == seekingNode) && (edges[i].node2 != notNode)) || ((edges[i].node2 == seekingNode) && (edges[i].node1 != notNode)) ) { return &edges[i]; } } return NULL; } /// sort the neighbors for this node void sortNeighbors(); }; /// Node storage std::vector nodes; /// edge storage std::set topologyEdges; /// add information about an edge void addEdgeInfo(const int tileNum, const int node1, const int node2); /// edge info was built bool edgeInfoBuilt; /// node info was built bool nodeInfoBuilt; /// node sorted info built bool nodeSortedInfoBuilt; }; bool operator<(const TopologyEdgeInfo& e1, const TopologyEdgeInfo& e2); #endif // __VE_TOPOLOGY_HELPER_H__ caret-5.6.4~dfsg.1.orig/caret_files/TopologyHelper.cxx0000664000175000017500000006375511572067322022561 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #ifdef Q_OS_WIN32 #define NOMINMAX #endif #include "TopologyFile.h" #include "TopologyHelper.h" #include "vtkCellArray.h" #include "vtkPolyData.h" #include "vtkTriangleFilter.h" #include #include /** * Comparison operator for EdgeInfo */ bool operator<(const TopologyEdgeInfo& e1, const TopologyEdgeInfo& e2) { if (e1.node1 == e2.node1) { return (e1.node2 < e2.node2); } return (e1.node1 < e2.node1); } /** * Constructor. This will contruct the topological information for the TopologyFile. * "buildEdgeInfo" will allow queries to be made about which tiles are used by an edge. * "buildNodeInfo" will allow queries to be made about the tiles and node neighbors of * nodes. If "sortNodeInfo" is also set the tiles and node neighbors will be sorted * around each node. */ TopologyHelper::TopologyHelper(const TopologyFile* tf, const bool buildEdgeInfo, const bool buildNodeInfo, const bool sortNodeInfo) { nodeSortedInfoBuilt = false; nodeInfoBuilt = false; edgeInfoBuilt = false; const int numTiles = tf->getNumberOfTiles(); if (numTiles <= 0) { return; } if (buildNodeInfo) { int maxNodeNum = -1; // // Get the number of nodes // for (int j = 0; j < numTiles; j++) { int n1, n2, n3; tf->getTile(j, n1, n2, n3); if (n1 > maxNodeNum) maxNodeNum = n1; if (n2 > maxNodeNum) maxNodeNum = n2; if (n3 > maxNodeNum) maxNodeNum = n3; } // // Node indices start at zero so need to increment // maxNodeNum++; // // There may be nodes that have been disconnected and not associated with any tiles // maxNodeNum = std::max(maxNodeNum, tf->getNumberOfNodes()); // // Initialize the node structures // nodes.reserve(maxNodeNum); for (int i = 0; i < maxNodeNum; i++) { nodes.push_back(NodeInfo(i)); } } // // Keep track of the tiles // for (int j = 0; j < numTiles; j++) { int n1, n2, n3; tf->getTile(j, n1, n2, n3); if (buildNodeInfo) { if (sortNodeInfo) { nodes[n1].addNeighbors(j, n2, n3); nodes[n2].addNeighbors(j, n3, n1); nodes[n3].addNeighbors(j, n1, n2); } else { nodes[n1].addNeighbor(n2); nodes[n1].addNeighbor(n3); nodes[n2].addNeighbor(n1); nodes[n2].addNeighbor(n3); nodes[n3].addNeighbor(n1); nodes[n3].addNeighbor(n2); nodes[n1].addTile(j); nodes[n2].addTile(j); nodes[n3].addTile(j); } } if (buildEdgeInfo) { addEdgeInfo(j, n1, n2); addEdgeInfo(j, n2, n3); addEdgeInfo(j, n3, n1); } } if (buildEdgeInfo) { edgeInfoBuilt = true; } if (buildNodeInfo) { nodeInfoBuilt = true; if (sortNodeInfo) { nodeSortedInfoBuilt = true; for (unsigned int k = 0; k < nodes.size(); k++) { nodes[k].sortNeighbors(); } } } } /** * Constructor. This will contruct the topological information for the TopologyFile. * "buildEdgeInfo" will allow queries to be made about which tiles are used by an edge. * "buildNodeInfo" will allow queries to be made about the tiles and node neighbors of * nodes. If "sortNodeInfo" is also set the tiles and node neighbors will be sorted * around each node. */ TopologyHelper::TopologyHelper(vtkPolyData* vtkIn, const bool buildEdgeInfo, const bool buildNodeInfo, const bool sortNodeInfo) { vtkPolyData* vtk = vtkIn; // // convert triangle strips to triangles if necessary // vtkTriangleFilter *triangleFilter = NULL; if (vtk->GetNumberOfStrips() > 0) { triangleFilter = vtkTriangleFilter::New(); triangleFilter->SetInput(vtk); triangleFilter->Update(); vtk = triangleFilter->GetOutput(); } nodeSortedInfoBuilt = false; nodeInfoBuilt = false; edgeInfoBuilt = false; //const int numTiles = tf->getNumberOfTiles(); //if (numTiles <= 0) { // return; // } if (buildNodeInfo) { vtkCellArray* polys = vtk->GetPolys(); vtkIdType npts; vtkIdType* pts; const int maxNodeNum = vtk->GetNumberOfPoints(); //-1; for (polys->InitTraversal(); polys->GetNextCell(npts,pts); ) { if (npts != 3) { std::cerr << " Polygon is not a triangle in TopologyHelper, ignored" << std::endl; } //maxNodeNum = std::max(pts[0], maxNodeNum); //maxNodeNum = std::max(pts[1], maxNodeNum); //maxNodeNum = std::max(pts[2], maxNodeNum); } // // Node indices start at zero so need to increment // //maxNodeNum++; // // Initialize the node structures // for (int i = 0; i < maxNodeNum; i++) { nodes.push_back(NodeInfo(i)); } } // // Keep track of the tiles // vtkCellArray* polys = vtk->GetPolys(); int cellId = 0; vtkIdType npts; vtkIdType* pts; for (polys->InitTraversal(); polys->GetNextCell(npts,pts); cellId++) { if (npts != 3) { std::cerr << " Polygon is not a triangle in TopologyHelper" << std::endl; return; } int n1 = pts[0]; int n2 = pts[1]; int n3 = pts[2]; if (buildNodeInfo) { if (sortNodeInfo) { nodes[n1].addNeighbors(cellId, n2, n3); nodes[n2].addNeighbors(cellId, n3, n1); nodes[n3].addNeighbors(cellId, n1, n2); } else { nodes[n1].addNeighbor(n2); nodes[n1].addNeighbor(n3); nodes[n2].addNeighbor(n1); nodes[n2].addNeighbor(n3); nodes[n3].addNeighbor(n1); nodes[n3].addNeighbor(n2); nodes[n1].addTile(cellId); nodes[n2].addTile(cellId); nodes[n3].addTile(cellId); } } if (buildEdgeInfo) { addEdgeInfo(cellId, n1, n2); addEdgeInfo(cellId, n2, n3); addEdgeInfo(cellId, n3, n1); } } if (buildEdgeInfo) { edgeInfoBuilt = true; } if (buildNodeInfo) { nodeInfoBuilt = true; if (sortNodeInfo) { nodeSortedInfoBuilt = true; for (unsigned int k = 0; k < nodes.size(); k++) { nodes[k].sortNeighbors(); } } } } /** * Destructor. */ TopologyHelper::~TopologyHelper() { nodes.clear(); topologyEdges.clear(); } /** * Keep track of edges */ void TopologyHelper::addEdgeInfo(const int tileNum, const int node1, const int node2) { TopologyEdgeInfo edge(tileNum, node1, node2); std::set::iterator iter = topologyEdges.find(edge); if (iter == topologyEdges.end()) { topologyEdges.insert(edge); } else { TopologyEdgeInfo& e = (TopologyEdgeInfo&)(*iter); e.addTile(tileNum); //iter->addTile(tileNum); } } /** * Sort a nodes neighbors */ void TopologyHelper::NodeInfo::sortNeighbors() { if ((edges.size() > 0) && sortMe) { // // Nodes that are on the edge (boundary) of a cut surface must be treated specially when sorting. // In this case the sorting needs to start with the link whose first node is not used // in any other link. This is true if all tiles are consistently oriented (and they // must be). // int startEdge = -1; for (unsigned int k = 0; k < edges.size(); k++) { const int nodeNum = edges[k].node1; bool foundNode = false; // // See if nodeNum is used in any other edges // for (unsigned int m = 0; m < edges.size(); m++) { if (m != k) { if (edges[m].containsNode(nodeNum) == true) { foundNode = true; break; } } } if (foundNode == false) { if (startEdge >= 0) { //std::cerr << "INFO: multiple starting edges for node " << nodeNumber << std::endl; } else { startEdge = k; } } } bool flag = false; if ((nodeNumber >= 44508) && (nodeNumber <= 44507)) { // modify for debugging std::cerr << "Start Edge for node " << nodeNumber << " is " << startEdge << std::endl; for (unsigned int k = 0; k < edges.size(); k++) { std::cerr << " " << edges[k].node1 << " " << edges[k].node2 << std::endl; } flag = true; } // startEdge is less than zero if the node's links are all interior links if (startEdge < 0) { startEdge = 0; } int currentNode = edges[startEdge].node1; int nextNeighbor = edges[startEdge].node2; neighbors.push_back(currentNode); tiles.push_back(edges[startEdge].tileNumber); const int firstNode = currentNode; for (unsigned int i = 1; i < edges.size(); i++) { neighbors.push_back(nextNeighbor); // find edge with node "nextNeighbor" but without node "currentNode" const NodeEdgeInfo* e = findEdgeWithPoint(nextNeighbor, currentNode); if (e != NULL) { tiles.push_back(e->tileNumber); currentNode = nextNeighbor; nextNeighbor = e->getOtherNode(nextNeighbor); if (nextNeighbor < 0) { //std::cerr << "INFO: Unable to find neighbor of" // << nextNeighbor << std::endl; } } else { nextNeighbor = -1; //std::cerr << "INFO: Unable to find edge for for node " // << nodeNumber << std::endl; break; } } if ((nextNeighbor != firstNode) && (nextNeighbor >= 0)) { neighbors.push_back(nextNeighbor); } if (flag) { std::cerr << "Node " << nodeNumber << " neighbors: "; for (unsigned int n = 0; n < neighbors.size(); n++) { std::cerr << " " << neighbors[n]; } std::cerr << std::endl; std::cerr << "Node " << nodeNumber << " tiles: "; for (unsigned int n = 0; n < tiles.size(); n++) { std::cerr << " " << tiles[n]; } std::cerr << std::endl; } } edges.clear(); } /** * See if a node has any neighbors */ bool TopologyHelper::getNodeHasNeighbors(const int nodeNum) const { if ((nodeNum >= 0) && (nodeNum < static_cast(nodes.size()))) { return (nodes[nodeNum].neighbors.empty() == false); } return false; } /** * Get the number of neighbors for a node. */ int TopologyHelper::getNodeNumberOfNeighbors(const int nodeNum) const { if ((nodeNum >= 0) && (nodeNum < static_cast(nodes.size()))) { return nodes[nodeNum].neighbors.size(); } return 0; } /** * Get the number of boundary edges used by node. */ void TopologyHelper::getNumberOfBoundaryEdgesForAllNodes(std::vector& numBoundaryEdgesPerNode) const { // // should already be allocated // const int numNodes = getNumberOfNodes(); if (static_cast(numBoundaryEdgesPerNode.size()) < numNodes) { numBoundaryEdgesPerNode.resize(numNodes); } std::fill(numBoundaryEdgesPerNode.begin(), numBoundaryEdgesPerNode.end(), 0); // // Loop through all edges // for (std::set::const_iterator iter = topologyEdges.begin(); iter != topologyEdges.end(); iter++) { // // Get the tiles // int tile1, tile2; iter->getTiles(tile1, tile2); // // If edges has only one tile // if ((tile1 >= 0) && (tile2 < 0)) { // // Increment the count for the node // int node1, node2; iter->getNodes(node1, node2); numBoundaryEdgesPerNode[node1]++; numBoundaryEdgesPerNode[node2]++; } } } /** * Get the maximum number of neighbors of all nodes. */ int TopologyHelper::getMaximumNumberOfNeighbors() const { unsigned int maxNeighbors = 0; int numNodes = getNumberOfNodes(); for (int i = 0; i < numNodes; i++) { const unsigned int num = nodes[i].neighbors.size(); if (num > maxNeighbors) { maxNeighbors = num; } } return maxNeighbors; } /** * Get the neighboring nodes for a node */ void TopologyHelper::getNodeNeighbors(const int nodeNum, std::vector& neighborsOut) const { if ((nodeNum >= 0) && (nodeNum < static_cast(nodes.size()))) { neighborsOut = nodes[nodeNum].neighbors; } else { neighborsOut.clear(); } } /** * Get the neighboring nodes for a node, within a given ROI */ void TopologyHelper::getNodeNeighborsInROI(const int nodeNum, std::vector& neighborsOut, const float *roiValues) const { if ((nodeNum >= 0) && (nodeNum < static_cast(nodes.size()))) { //Since we are restricting to an roi, we need to make sure that the neighbors are within the ROI, and //if not, build a new neighbor list std::vector neighbors = nodes[nodeNum].neighbors; //optimization, first, loop through and see any neighbors are outside the roi bool neighborOutsideOfRoi = false; for(int i = 0;i& neighborsOut) const { if (depth < 2)//could make this function private, and remove this test {//gracefully handle nonpositives, and do 1 the easy way getNodeNeighbors(rootNode, neighborsOut); return; } QMutexLocker locked(&usingMarkNodes);//lock after choosing which version to use, because they are both public int i, j, k; neighborsOut.clear(); int numNodes = getNumberOfNodes(); int expected = (7 * (depth + 1) * depth) >> 1;//uses bitshift for cheap divide, equals 7 * depth * (depth + 1) / 2 if (expected > numNodes) expected = numNodes; neighborsOut.reserve(expected);//reserve means make space, but don't change size() if ((int)markNodes.size() != numNodes) { markNodes.resize(numNodes); for (i = 0; i < numNodes; ++i) { markNodes[i] = 0; } } if ((int)nodelist[0].size() != numNodes) {//WAY overkill in basically all cases, but no way to know max needed for sure, and branching or clear() would be slow nodelist[0].resize(numNodes); nodelist[1].resize(numNodes); } int newind = 1, oldind = 0, whichneigh; int oldused, newused = 1, numNeigh; std::vector* oldlist, *newlist; markNodes[rootNode] = 1; nodelist[0][0] = rootNode; for (i = 0; i < depth; ++i) { oldused = newused; newused = 0; oldlist = nodelist + oldind;//pointer math should be fast newlist = nodelist + newind; for (j = 0; j < oldused; ++j) { const std::vector& neighbors = nodes[(*oldlist)[j]].neighbors; numNeigh = neighbors.size(); for (k = 0; k < numNeigh; ++k) { whichneigh = neighbors[k]; if (!markNodes[whichneigh]) { markNodes[whichneigh] = 1; neighborsOut.push_back(whichneigh); (*newlist)[newused++] = whichneigh; } } } oldind = newind;//swap the lists newind = 1 ^ oldind;//bitwise xor is probably faster than minus }//done, now clean up markNodes numNeigh = neighborsOut.size(); for (i = 0; i < numNeigh; ++i) markNodes[neighborsOut[i]] = 0; markNodes[rootNode] = 0;//only zero the nodes that were marked: after completion of call, array will be entirely zeroed } /** * Get the neighbors of a node to a specified depth. */ void TopologyHelper::getNodeNeighborsToDepth(const int rootNode, const int depth, std::vector& neighborsOut) const { if (depth < 2) {//gracefully handle nonpositives, and do 1 the easy way getNodeNeighbors(rootNode, neighborsOut); return; } if (depth > 4) {//iterative version is faster for large depths, cutoff found on 64bit machine, but running 32bit executable getNodeNeighborsToDepthIter(rootNode, depth, neighborsOut); return; } QMutexLocker locked(&usingMarkNodes);//lock after choosing which version to use, because they are both public int i;//otherwise, a quick recursive method neighborsOut.clear(); int numNodes = getNumberOfNodes(); int expected = (7 * (depth + 1) * depth) >> 1;//uses bitshift for cheap divide, equals 7 * depth * (depth + 1) / 2 if (expected > numNodes) expected = numNodes; neighborsOut.reserve(expected);//reserve means make space, but don't change size() if ((int)markNodes.size() != numNodes) { markNodes.resize(numNodes); for (i = 0; i < numNodes; ++i) { markNodes[i] = 0; } } markNodes[rootNode] = depth + 1; depthNeighHelper(rootNode, depth, neighborsOut);//uses depth first graph search: fast, but very unordered, if sorted is desired, sort afterwards int numNeigh = neighborsOut.size();//NOTE: depth first technically "wastes" some effort by searching nodes to a lesser depth then required for (i = 0; i < numNeigh; ++i) markNodes[neighborsOut[i]] = 0; markNodes[rootNode] = 0;//only zero the nodes that were marked: after completion of call, array will be entirely zeroed } void TopologyHelper::depthNeighHelper(int node, int depthrem, std::vector& neighborsOut) const { const std::vector& neighbors = nodes[node].neighbors; int i, nextdepth = depthrem - 1, numNeigh = neighbors.size(), thisNeigh, mark; if (nextdepth) {//splitting here removes a large number of recursive calls and compares for (i = 0; i < numNeigh; ++i) { thisNeigh = neighbors[i]; mark = markNodes[thisNeigh]; if (depthrem > mark) { if (!mark) { neighborsOut.push_back(thisNeigh); } markNodes[thisNeigh] = depthrem; depthNeighHelper(thisNeigh, nextdepth, neighborsOut); } } } else {//same, but don't recurse for (i = 0; i < numNeigh; ++i) { thisNeigh = neighbors[i]; if (!markNodes[thisNeigh]) { markNodes[thisNeigh] = 1; neighborsOut.push_back(thisNeigh); } } } } /** * Get the neighbors of a node to a specified depth. */ void TopologyHelper::getNodeNeighborsToDepthOld(const int rootNode, const int depth, std::vector& neighborsOut) const { neighborsOut.clear(); const int numNodes = getNumberOfNodes(); std::vector nodeVisited(numNodes, 0); std::set nodesMarked; nodesMarked.insert(rootNode); for (int dp = 0; dp < depth; dp++) { std::set newNodes; for (std::set::iterator it = nodesMarked.begin(); it != nodesMarked.end(); it++) { const int node = *it; if (nodeVisited[node] == 0) { nodeVisited[node] = 1; // // Get all of the nodes neighbors // const std::vector& neighbors = nodes[node].neighbors; const unsigned int numNeighs = neighbors.size(); for (unsigned int j = 0; j < numNeighs; j++) { const int n = neighbors[j]; if (nodeVisited[n] == 0) { newNodes.insert(n); } } } } nodesMarked.insert(newNodes.begin(), newNodes.end()); } for (std::set::iterator it = nodesMarked.begin(); it != nodesMarked.end(); it++) { const int node = *it; if (node != rootNode) { neighborsOut.push_back(node); } } /* const int numNodes = getNumberOfNodes(); // // Neighbors found to depth // std::vector neighborsFound(numNodes, 0); // // Mark root node as found // neighborsFound[rootNode] = 1; // // Find nodes to the specified depth // for (int dp = 0; dp <= depth; dp++) { for (int i = 0; i < numNodes; i++) { // // If this node is not marked yet // if (neighborsFound[i] == 0) { // // Get all of the nodes neighbors // int numNeighs = 0; const int* nodeNeighbors = getNodeNeighbors(i, numNeighs); // // Add nodes neighbors for next iteration // for (int k = 0; k < numNeighs; k++) { // // If a neighbor is marked // const int n = nodeNeighbors[k]; if (neighborsFound[n]) { // // Mark me // neighborsFound[i] = 1; break; } } } } } for (int i = 0; i < numNodes; i++) { if (i != rootNode) { if (neighborsFound[i]) { neighborsOut.push_back(i); } } } */ /* // // Neighbors found to depth // std::set neighborsFound; // // Keep track of nodes visited so far // std::vector visited(numNodes, false); // // List of nodes to search at each depth iteration // std::vector nodesToSearch; nodesToSearch.push_back(rootNode); // // Find nodes to the specified depth // for (int dp = 0; dp <= depth; dp++) { // // Nodes for next depth iteration (use set so list is unique) // std::set nodesForNextIteration; // // For nodes that are to be searched // const int numToSearch = static_cast(nodesToSearch.size()); for (int i = 0; i < numToSearch; i++) { // // Node that is to be searched // const int node = nodesToSearch[i]; // // If this node has not already been visited // if (visited[node] == false) { // // Mark this node visited // visited[node] = true; // // Add it to the list of neighbors // neighborsFound.insert(node); // // Get all of the nodes neighbors // int numNeighs = 0; const int* nodeNeighbors = getNodeNeighbors(node, numNeighs); // // Add nodes neighbors for next iteration // for (int k = 0; k < numNeighs; k++) { const int n = nodeNeighbors[k]; if (visited[n] == false) { nodesForNextIteration.insert(n); } } } } // // Update list of neighbors to search for next iteration // nodesToSearch.clear(); nodesToSearch.insert(nodesToSearch.end(), nodesForNextIteration.begin(), nodesForNextIteration.end()); } // // Set the output neighbors exluding the input node // for (std::set::iterator iter = neighborsFound.begin(); iter != neighborsFound.end(); iter++) { const int n = *iter; if (n != rootNode) { neighborsOut.push_back(n); } } */ } /** * Get the neighboring nodes for a node. Returns a pointer to an array * containing the neighbors. */ const int* TopologyHelper::getNodeNeighbors(const int nodeNum, int& numNeighborsOut) const { if ((nodeNum >= 0) && (nodeNum < static_cast(nodes.size()))) { numNeighborsOut = static_cast(nodes[nodeNum].neighbors.size()); if (numNeighborsOut <= 0) { return NULL; } return &nodes[nodeNum].neighbors[0]; } numNeighborsOut = 0; return NULL; } /** * Get the tiles that use this node. */ void TopologyHelper::getNodeTiles(const int nodeNum, std::vector& tilesOut) const { if ((nodeNum >= 0) && (nodeNum < static_cast(nodes.size()))) { tilesOut = nodes[nodeNum].tiles; } else { tilesOut.clear(); } } caret-5.6.4~dfsg.1.orig/caret_files/TopologyFile.h0000664000175000017500000002312611572067322021632 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __TOPOLOGY_FILE__H__ #define __TOPOLOGY_FILE__H__ #include "BrainVoyagerFile.h" #include "FreeSurferSurfaceFile.h" #include "GiftiDataArrayFile.h" #include "MniObjSurfaceFile.h" #include class PaintFile; class NodeRegionOfInterestFile; class TopologyHelper; class vtkPolyData; /// Topology File /** * Caret Topology File stores section and category for each node and the * surfaces tiles. */ class TopologyFile : public GiftiDataArrayFile { public: /// Types of Topology Files enum TOPOLOGY_TYPES { TOPOLOGY_TYPE_CLOSED, TOPOLOGY_TYPE_OPEN, TOPOLOGY_TYPE_CUT, TOPOLOGY_TYPE_LOBAR_CUT, TOPOLOGY_TYPE_UNKNOWN, TOPOLOGY_TYPE_UNSPECIFIED }; // constructor TopologyFile(); // copy constructor TopologyFile(const TopologyFile& tf); /// destructor ~TopologyFile(); // assignment operator TopologyFile& operator=(const TopologyFile& tf); // add a tile void addTile(const int v1, const int v2, const int v3); // add a tile void addTile(const int v[3]); // clear the file void clear(); // delete tiles that use any of the marked nodes void deleteTilesWithMarkedNodes(const std::vector& markedNodes); // delete tiles with the specified indices void deleteTiles(const std::vector& tilesToDelete); // delete tiles that use both of these nodes void deleteTilesWithEdge(const int node1, const int node2); // get non-manifold nodes (nodes whose triangles do not share and edge) void getNonManifoldNodes(std::vector& nodes) const; // get number of disjoint objects int getNumberOfDisjointObjects() const; // find the number of disjoint pieces of surface int findIslands(std::vector& islandRootNode, std::vector& islandNumNodes, std::vector& nodeRootNeighbor) const; // disconnect islands (retain largest number of connected nodes; disconnect others) int disconnectIslands(); // disconnect nodes that are in the region of interest void disconnectNodesInRegionOfInterest(const NodeRegionOfInterestFile& roiFile) throw (FileException); // disconnect nodes that are labeled with the specified name and in the specified column void disconnectNodesUsingPaint(const PaintFile& paintFile, const int paintColumn, const QString& paintName) throw (FileException); // Find corner tiles (corners are tiles that have one or more nodes that are only in one tile). void findCornerTiles(const int numCornerNodes, std::vector& cornerTiles) const; // remove corners (returns number of tiles deleted) int removeCornerTiles(const int numCornerNodes); // Get the section numbers for the nodes. Returns true if the sections are valid else false. bool getNodeSections(std::vector& nodeSectionsOut) const; // export topology to a free surfer surface file void exportToFreeSurferSurfaceFile(FreeSurferSurfaceFile& fssf); // import topology from a free surfer surface file void importFromFreeSurferSurfaceFile(const FreeSurferSurfaceFile& fssf, const TopologyFile* tf); // get the topology from a brain voyager file void importFromBrainVoyagerFile(const BrainVoyagerFile& bvf); /// get the topology from a MNI OBJ surface file void importFromMniObjSurfaceFile(const MniObjSurfaceFile& mni) throw (FileException); // import from a VTK surface file void importFromVtkFile(vtkPolyData* polyData); // get the topology helper const TopologyHelper* getTopologyHelper(const bool needEdgeInfo, const bool needNodeInfo, const bool needNodeInfoSorted) const; // Get spec file tag from topology type static QString getSpecFileTagFromTopologyType(const TOPOLOGY_TYPES tt); // get the perimeter ID from a topology type static QString getPerimeterIDFromTopologyType(TOPOLOGY_TYPES tt); // get the topology type from a perimeter ID static TOPOLOGY_TYPES getTopologyTypeFromPerimeterID(const QString pid); // get the topology type TOPOLOGY_TYPES getTopologyType() const; // get a descriptive name of the topology file QString getDescriptiveName() const; // get the name of the topology type QString getTopologyTypeName() const; // set the topology type void setTopologyType(const TOPOLOGY_TYPES tt); // flip the orientation of the tiles void flipTileOrientation(); // get a Tile const int* getTile(const int indx) const; // get a Tile void getTile(const int tileNumber, int& v1, int& v2, int& v3) const; // get a Tile void getTile(const int tileNumber, int vertices[3]) const; // set a tile void setTile(const int tileNumber, const int v1, const int v2, const int v3); // set a tile void setTile(const int tileNumber, const int v[3]); // find the tile with the two vertices int getTileWithVertices(const int v1, const int v2, const int notTileNum) const; // get the number of tiles int getNumberOfTiles() const; // set the number of tiles void setNumberOfTiles(const int numTiles); // set the number of nodes in coordinate files using this topology file void setNumberOfNodes(const int num); // get the number of nodes in coordinate files using this topology file int getNumberOfNodes() const { return numberOfNodes; } // get the euler count (V - E + F = 2 for closed surface) void getEulerCount(const bool twoDimFlag, int& faces, int& vertices, int& edges, int& eulerCount, int& numberOfHoles, int& numObjects) const; // Get Edges with 3 or more tiles assigned to them. void getDegenerateEdges(int& numDegenerateEdges, std::vector& nodesUsedByDegenerateEdges) const; // see if the topology file is equivalent to this one (contains exact same tiles) bool equivalent(const TopologyFile& tf) const; /// Update the file's metadata for Caret6 virtual void updateMetaDataForCaret6(); /// write the file's memory in caret6 format to the specified name virtual QString writeFileInCaret6Format(const QString& filenameIn, Structure structure,const ColorFile* colorFileIn, const bool useCaret6ExtensionFlag) throw (FileException); protected: // copy helper used by copy constructor and assignment operator void copyHelperTopology(const TopologyFile& tf); // read in tiles from ascii file void readTilesAscii(QTextStream& stream, const bool clockwiseOrientation) throw (FileException); // read in tiles from binary file void readTilesBinary(QDataStream& stream) throw (FileException); // read topology file version 0 void readFileDataVersion0(QTextStream& stream, const QString& firstLineRead) throw (FileException); // read topology file version 1 void readFileDataVersion1(QFile& file, QTextStream& stream, QDataStream& binStream) throw (FileException); // read file void readLegacyFileData(QFile& file, QTextStream& stream, QDataStream& binStream) throw (FileException); // write file void writeLegacyFileData(QTextStream& stream, QDataStream& binStream) throw (FileException); /// topology helper needs to be rebuilt (topology was modified) mutable bool topologyHelperNeedsRebuild; /// topology helper for node/edge info mutable TopologyHelper* topologyHelper; /// number of nodes in coordinate files that use this topology file int numberOfNodes; /// node section number std::vector nodeSections; mutable QMutex gettingTopoHelper; // // NOTE: IF ANY NEW VARIABLES ARE ADDED BE SURE TO UPDATE THE COPY CONSTRUCTOR // }; #endif //__TOPOLOGY_FILE__H__ caret-5.6.4~dfsg.1.orig/caret_files/TopologyFile.cxx0000664000175000017500000014506011572067322022207 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #ifdef Q_OS_WIN32 #define NOMINMAX #endif #include #include #include #include #include "DebugControl.h" #include "FileUtilities.h" #include "GiftiCommon.h" #include "MniObjSurfaceFile.h" #include "NodeRegionOfInterestFile.h" #include "PaintFile.h" #include "SpecFile.h" #include "TopologyFile.h" #include "TopologyHelper.h" #include "vtkCellArray.h" #include "vtkPolyData.h" #include "vtkTriangleFilter.h" /** * The constructor. */ TopologyFile::TopologyFile() : GiftiDataArrayFile("Topology File", GiftiCommon::intentTopologyTriangles, GiftiDataArray::DATA_TYPE_INT32, SpecFile::getTopoFileExtension(), FILE_FORMAT_ASCII, FILE_IO_READ_AND_WRITE, FILE_IO_READ_AND_WRITE, FILE_IO_NONE, FILE_IO_NONE, false) { topologyHelper = NULL; clear(); } /** * The copy constructor. */ TopologyFile::TopologyFile(const TopologyFile& tf) : GiftiDataArrayFile(tf) { copyHelperTopology(tf); } /** * The destructor. */ TopologyFile::~TopologyFile() { clear(); } /** * copy helper used by copy constructor and assignment operator. */ void TopologyFile::copyHelperTopology(const TopologyFile& tf) { topologyHelper = NULL; topologyHelperNeedsRebuild = false; nodeSections = tf.nodeSections; numberOfNodes = tf.numberOfNodes; setFileName(""); setModified(); } /** * get the number of tiles. */ int TopologyFile::getNumberOfTiles() const { if (dataArrays.empty()) { return 0; } return dataArrays[0]->getNumberOfRows(); } /** * assignment operator. */ TopologyFile& TopologyFile::operator=(const TopologyFile& tf) { if (&tf != this) { GiftiDataArrayFile::operator=(tf); copyHelperTopology(tf); } return *this; } /** * Add a tile. */ void TopologyFile::addTile(const int v1, const int v2, const int v3) { if (getNumberOfDataArrays() == 0) { std::vector dim; dim.push_back(1); dim.push_back(3); GiftiDataArray* nda = new GiftiDataArray(this, GiftiCommon::intentTopologyTriangles, GiftiDataArray::DATA_TYPE_INT32, dim); addDataArray(nda); int32_t* tiles = nda->getDataPointerInt(); tiles[0] = v1; tiles[1] = v2; tiles[2] = v3; } else { const int numRows = dataArrays[0]->getNumberOfRows(); dataArrays[0]->addRows(1); int32_t* tiles = dataArrays[0]->getDataPointerInt(); const int indx = numRows * 3; tiles[indx] = v1; tiles[indx+1] = v2; tiles[indx+2] = v3; } topologyHelperNeedsRebuild = true; setModified(); // add one to node since node number range is [0..N-1] numberOfNodes = std::max(v1+1, numberOfNodes); numberOfNodes = std::max(v2+1, numberOfNodes); numberOfNodes = std::max(v3+1, numberOfNodes); } /** * Add a tile. */ void TopologyFile::addTile(const int v[3]) { addTile(v[0], v[1], v[2]); } /** * Clear the Topology File. */ void TopologyFile::clear() { GiftiDataArrayFile::clear(); numberOfNodes = 0; //nodes.clear(); nodeSections.clear(); setHeaderTag(AbstractFile::headerTagPerimeterID, "UNKNOWN"); if (topologyHelper != NULL) { delete topologyHelper; topologyHelper = NULL; } topologyHelperNeedsRebuild = true; } /** * Set the number of nodes in coordinate files using this topology file. */ void TopologyFile::setNumberOfNodes(const int num) { // Note: this "set method" does not modify the topology file so do not call setModified() numberOfNodes = std::max(num, numberOfNodes); topologyHelperNeedsRebuild = true; } /** * Get the perimeter ID from a topology type */ QString TopologyFile::getPerimeterIDFromTopologyType(TOPOLOGY_TYPES tt) { QString pid("UNKNOWN"); switch(tt) { case TOPOLOGY_TYPE_CLOSED: pid = "CLOSED"; break; case TOPOLOGY_TYPE_OPEN: pid = "OPEN"; break; case TOPOLOGY_TYPE_CUT: pid = "CUT"; break; case TOPOLOGY_TYPE_LOBAR_CUT: pid = "LOBAR_CUT"; break; case TOPOLOGY_TYPE_UNKNOWN: case TOPOLOGY_TYPE_UNSPECIFIED: pid = "UNKNOWN"; break; } return pid; } /** * Get spec file tag from topology type */ QString TopologyFile::getSpecFileTagFromTopologyType(const TOPOLOGY_TYPES tt) { QString tag(SpecFile::getUnknownTopoFileMatchTag()); switch(tt) { case TOPOLOGY_TYPE_CLOSED: tag = SpecFile::getClosedTopoFileTag(); break; case TOPOLOGY_TYPE_OPEN: tag = SpecFile::getOpenTopoFileTag(); break; case TOPOLOGY_TYPE_CUT: tag = SpecFile::getCutTopoFileTag(); break; case TOPOLOGY_TYPE_LOBAR_CUT: tag = SpecFile::getLobarCutTopoFileTag(); break; case TOPOLOGY_TYPE_UNKNOWN: case TOPOLOGY_TYPE_UNSPECIFIED: tag = SpecFile::getUnknownTopoFileMatchTag(); break; } return tag; } /** * get the topology type from a perimeter ID */ TopologyFile::TOPOLOGY_TYPES TopologyFile::getTopologyTypeFromPerimeterID(const QString pid) { TOPOLOGY_TYPES tt = TOPOLOGY_TYPE_UNKNOWN; if (pid == "CLOSED") { tt = TOPOLOGY_TYPE_CLOSED; } else if (pid == "OPEN") { tt = TOPOLOGY_TYPE_OPEN; } else if (pid == "CUT") { tt = TOPOLOGY_TYPE_CUT; } else if (pid == "LOBAR_CUT") { tt = TOPOLOGY_TYPE_LOBAR_CUT; } return tt; } /** * Set the topology type. */ void TopologyFile::setTopologyType(const TOPOLOGY_TYPES tt) { setModified(); QString topoTypeName; switch(tt) { case TOPOLOGY_TYPE_CLOSED: topoTypeName = "CLOSED"; break; case TOPOLOGY_TYPE_OPEN: topoTypeName = "OPEN"; break; case TOPOLOGY_TYPE_CUT: topoTypeName = "CUT"; break; case TOPOLOGY_TYPE_LOBAR_CUT: topoTypeName = "LOBAR_CUT"; break; case TOPOLOGY_TYPE_UNKNOWN: topoTypeName = "UNKNOWN"; break; case TOPOLOGY_TYPE_UNSPECIFIED: default: topoTypeName = "UNSPECIFIED"; break; } setHeaderTag(AbstractFile::headerTagPerimeterID, topoTypeName); } /** * Get a descriptive name of a file (type followed by basename) */ QString TopologyFile::getDescriptiveName() const { QString name(getTopologyTypeName()); const QString fn(getFileName()); if (fn.isEmpty() == false) { name.append(" "); name.append(FileUtilities::basename(fn)); } return name; } /** * Get the name of the type of this topology file. */ QString TopologyFile::getTopologyTypeName() const { const QString topoTypeName = getHeaderTag(AbstractFile::headerTagPerimeterID); if (topoTypeName.isEmpty()) { return "UNKNOWN"; } return topoTypeName; } /** * Get the topology type */ TopologyFile::TOPOLOGY_TYPES TopologyFile::getTopologyType() const { const QString topoTypeName = getHeaderTag(AbstractFile::headerTagPerimeterID); if (topoTypeName == "CLOSED") { return TOPOLOGY_TYPE_CLOSED; } else if (topoTypeName == "OPEN") { return TOPOLOGY_TYPE_OPEN; } else if (topoTypeName == "CUT") { return TOPOLOGY_TYPE_CUT; } else if (topoTypeName == "LOBAR_CUT") { return TOPOLOGY_TYPE_LOBAR_CUT; } else if (topoTypeName == "UNKNOWN") { return TOPOLOGY_TYPE_UNKNOWN; } else { return TOPOLOGY_TYPE_UNSPECIFIED; } } /** * delete tiles that use both of these nodes. */ void TopologyFile::deleteTilesWithEdge(const int node1, const int node2) { const int numTiles = getNumberOfTiles(); if (numTiles <= 0) { return; } std::vector rowsToDelete; for (int i = 0; i < numTiles; i++) { int v1, v2, v3; getTile(i, v1, v2, v3); bool keepTile = true; if ((v1 == node1) && (v2 == node2)) { keepTile = false; } else if ((v2 == node1) && (v1 == node2)) { keepTile = false; } else if ((v2 == node1) && (v3 == node2)) { keepTile = false; } else if ((v3 == node1) && (v2 == node2)) { keepTile = false; } else if ((v1 == node1) && (v3 == node2)) { keepTile = false; } else if ((v3 == node1) && (v1 == node2)) { keepTile = false; } if (keepTile == false) { rowsToDelete.push_back(i); } } if (rowsToDelete.empty() == false) { dataArrays[0]->deleteRows(rowsToDelete); topologyHelperNeedsRebuild = true; } } /* ** Delete tiles that use any of the marked nodes */ void TopologyFile::deleteTilesWithMarkedNodes(const std::vector& markedNodes) { const int numNodes = static_cast(markedNodes.size()); const int numTiles = getNumberOfTiles(); if (numTiles <= 0) { return; } std::vector rowsToDelete; for (int i = 0; i < numTiles; i++) { int v1, v2, v3; getTile(i, v1, v2, v3); bool deleteTile = false; if (v1 < numNodes) { if (markedNodes[v1]) { deleteTile = true; } } if (v2 < numNodes) { if (markedNodes[v2]) { deleteTile = true; } } if (v3 < numNodes) { if (markedNodes[v3]) { deleteTile = true; } } if (deleteTile) { rowsToDelete.push_back(i); } } if (rowsToDelete.empty() == false) { dataArrays[0]->deleteRows(rowsToDelete); topologyHelperNeedsRebuild = true; } } /** * Delete tiles with the specified indices. */ void TopologyFile::deleteTiles(const std::vector& tilesToDelete) { if (tilesToDelete.empty() == false) { dataArrays[0]->deleteRows(tilesToDelete); topologyHelperNeedsRebuild = true; } } /** * Get Edges with 3 or more tiles assigned to them. */ void TopologyFile::getDegenerateEdges(int& numDegenerateEdges, std::vector& nodesUsedByDegenerateEdges) const { numDegenerateEdges = 0; nodesUsedByDegenerateEdges.clear(); std::set degenNodes; const TopologyHelper* th = getTopologyHelper(true, true, true); std::set edges = th->getEdgeInfo(); for (std::set::iterator iter = edges.begin(); iter != edges.end(); iter++) { if (iter->getEdgeUsedByMoreThanTwoTriangles()) { numDegenerateEdges++; int n1, n2; iter->getNodes(n1, n2); degenNodes.insert(n1); degenNodes.insert(n2); } } nodesUsedByDegenerateEdges.insert(nodesUsedByDegenerateEdges.end(), degenNodes.begin(), degenNodes.end()); } /** * Get the euler count (V - E + F = 2 for closed surface). * For more info: http://mathworld.wolfram.com/PoincareFormula.html * http://mathworld.wolfram.com/EulerCharacteristic.html */ void TopologyFile::getEulerCount(const bool twoDimFlag, int& numFaces, int& numVertices, int& numEdges, int& eulerCount, int& numHoles, int& numObjects) const { numFaces = getNumberOfTiles(); const TopologyHelper* th = getTopologyHelper(true, true, false); numVertices = 0; const int numNodes = th->getNumberOfNodes(); for (int i = 0; i < numNodes; i++) { const int numNeighbors = th->getNodeNumberOfNeighbors(i); if (numNeighbors > 0) { numVertices++; } } numObjects = getNumberOfDisjointObjects(); numEdges = th->getNumberOfEdges(); eulerCount = numVertices - numEdges + numFaces; if (twoDimFlag) { numHoles = 1 - eulerCount; } else { numHoles = 1 - (eulerCount / 2); //(eulerCount - 2) / (-2); } } /** * get non-manifold nodes (nodes whose triangles do not share and edge). */ void TopologyFile::getNonManifoldNodes(std::vector& nodesOut) const { nodesOut.clear(); // // Get this topology file's topology helper (DO NOT DELETE IT) // const TopologyHelper* topologyHelper = getTopologyHelper(true, true, true); const int numNodes = getNumberOfNodes(); std::vector edgesPerNode(numNodes); topologyHelper->getNumberOfBoundaryEdgesForAllNodes(edgesPerNode); // // Loop through nodes // for (int i = 0; i < numNodes; i++) { // // Non-manifold nodes have 4 or more boundary edges // if (edgesPerNode[i] >= 4) { nodesOut.push_back(i); } } } /** * get number of disjoint objects. */ int TopologyFile::getNumberOfDisjointObjects() const { std::vector islandRoot, islandNumNodes, islandRootNeighbor; const int numSurfaceObjects = findIslands(islandRoot, islandNumNodes, islandRootNeighbor); return numSurfaceObjects; } /** * Find islands (number of disjoint groups of nodes). * Returns number disjoint connected pieces of surface. * Return value of 1 indicates no islands (one connected piece of surface). * Return value of 0 indicates no topology. * Return value greater than 1 indicates islands. * * islandRootNode - contains a node in the piece of surface and the number of * elements is the number returned by this method. * islandNumNodes - is the number of nodes in the piece of surface and the * number of elements is the number returned by this method. * nodeRootNeighbor - is the "islandRootNode" for the node "i" and the number * of elements is the number of nodes in the surface. */ int TopologyFile::findIslands(std::vector& islandRootNode, std::vector& islandNumNodes, std::vector& nodeRootNeighbor) const { islandRootNode.clear(); islandNumNodes.clear(); // // Get this topology file's topology helper (DO NOT DELETE IT) // const TopologyHelper* topologyHelper = getTopologyHelper(false, true, false); const int numNodes = topologyHelper->getNumberOfNodes(); if (numNodes == 0) { return 0; } if (numNodes == 1) { for (int i = 0; i < numNodes; i++) { if (topologyHelper->getNodeHasNeighbors(i)) { islandRootNode.push_back(i); islandNumNodes.push_back(1); nodeRootNeighbor.push_back(i); break; } } return static_cast(islandRootNode.size()); } nodeRootNeighbor.resize(numNodes); std::fill(nodeRootNeighbor.begin(), nodeRootNeighbor.end(), -1); std::vector numConnectedNeighbors(numNodes, 0); std::vector visited(numNodes, 0); // // Mark all nodes without neighbors as visited // for (int i = 0; i < numNodes; i++) { if (topologyHelper->getNodeHasNeighbors(i) == false) { visited[i] = 1; } } // // Search the surface marking all connected nodes. // for (int n = 0; n < numNodes; n++) { if (visited[n] == 0) { const int nodeNumberIn = n; const int origNeighbor = n; std::stack st; st.push(nodeNumberIn); while(!st.empty()) { const int nodeNumber = st.top(); st.pop(); if (visited[nodeNumber] == 0) { visited[nodeNumber] = 1; nodeRootNeighbor[nodeNumber] = origNeighbor; numConnectedNeighbors[origNeighbor]++; std::vector neighbors; topologyHelper->getNodeNeighbors(nodeNumber, neighbors); for (int i = 0; i < static_cast(neighbors.size()); i++) { const int node = neighbors[i]; if (visited[node] == 0) { st.push(node); } } } } } } // // set the islands // for (int j = 0; j < numNodes; j++) { if (numConnectedNeighbors[j] > 0) { islandRootNode.push_back(j); islandNumNodes.push_back(numConnectedNeighbors[j]); if (DebugControl::getDebugOn()) { std::cout << j << " is connected to " << numConnectedNeighbors[j] << " nodes." << std::endl; } } } return static_cast(islandRootNode.size()); } /** * disconnect nodes that are in the region of interest. */ void TopologyFile::disconnectNodesInRegionOfInterest(const NodeRegionOfInterestFile& roiFile) throw (FileException) { // // Determine nodes that should be disconnected // const int numNodes = roiFile.getNumberOfNodes(); std::vector disconnectNodeFlags(numNodes, false); for (int i = 0; i < numNodes; i++) { if (roiFile.getNodeSelected(i)) { disconnectNodeFlags[i] = true; } } // // Disonnect the nodes by removing tiles // deleteTilesWithMarkedNodes(disconnectNodeFlags); } /** * disconnect nodes that are labeled with the specified name and in the specified column. */ void TopologyFile::disconnectNodesUsingPaint(const PaintFile& paintFile, const int paintColumn, const QString& paintName) throw (FileException) { // // Check inputs // if ((paintColumn < 0) || (paintColumn >= paintFile.getNumberOfColumns())) { throw FileException("Invalid paint column number"); } if (paintName.isEmpty()) { throw FileException("Paint name is empty."); } const int paintIndex = paintFile.getPaintIndexFromName(paintName); if (paintIndex < 0) { throw FileException("Paint name not found in paint file."); } // // Determine nodes that should be disconnected // const int numNodes = paintFile.getNumberOfNodes(); std::vector disconnectNodeFlags(numNodes, false); for (int i = 0; i < numNodes; i++) { if (paintFile.getPaint(i, paintColumn) == paintIndex) { disconnectNodeFlags[i] = true; } } // // Disonnect the nodes by removing tiles // deleteTilesWithMarkedNodes(disconnectNodeFlags); } /** * Disconnect islands (retain largest number of connected nodes; disconnect others). * Returns the number of islands that were disconnected. */ int TopologyFile::disconnectIslands() { // // Find the islands // std::vector islandRootNode; std::vector islandNumNodes; std::vector nodeRootNeighbor; const int numPieces = findIslands(islandRootNode, islandNumNodes, nodeRootNeighbor); // // See if there are any islands // if (numPieces <= 1) { return 0; } const int numNodes = static_cast(nodeRootNeighbor.size()); // // find node with most connected neighbors // int mostNeighborsNode = -1; int mostNeighbors = 0; for (int j = 0; j < numPieces; j++) { if (islandNumNodes[j] > 0) { if (DebugControl::getDebugOn()) { std::cout << islandRootNode[j] << " is connected to " << islandNumNodes[j] << " nodes." << std::endl; } } if (islandNumNodes[j] > mostNeighbors) { mostNeighborsNode = islandRootNode[j]; mostNeighbors = islandNumNodes[j]; } } if (DebugControl::getDebugOn()) { std::cout << mostNeighborsNode << " has the most neighbors = " << mostNeighbors << std::endl; } // // Disconnect all nodes that are not // connected to the node with the most connected neighbors // std::vector markedNodes(numNodes, false); if (mostNeighborsNode >= 0) { for (int i = 0; i < numNodes; i++) { if (nodeRootNeighbor[i] != mostNeighborsNode) { markedNodes[i] = true; } } } deleteTilesWithMarkedNodes(markedNodes); topologyHelperNeedsRebuild = true; setModified(); return numPieces - 1; } /** * Find corner tiles (corners are tiles that have one or more nodes that are only in one tile). */ void TopologyFile::findCornerTiles(const int numCornerNodes, std::vector& cornerTiles) const { cornerTiles.clear(); // // Topology helper needs to be updated each cycle since tiles get deleted // const TopologyHelper* th = getTopologyHelper(false, true, false); // // Check all nodes // const int numTiles = getNumberOfTiles(); for (int i = 0; i < numTiles; i++) { // // Get the nodes in the tile // int nodes[3]; getTile(i, nodes); // // count the number of corner nodes in the tile // int numCornerNodesInTile = 0; for (int j = 0; j < 3; j++) { if (th->getNodeNumberOfNeighbors(nodes[j]) == 2) { numCornerNodesInTile++; } } // // If only one tile is used by the node then it must be a corner node // if (numCornerNodesInTile > 0) { if (numCornerNodesInTile >= numCornerNodes) { cornerTiles.push_back(i); } } } } /** * Remove corners (corners are tiles that have one or more nodes that are only in one tile). */ int TopologyFile::removeCornerTiles(const int numCornerNodes) { int tilesDeletedCount = 0; // // May need multiple iterations due to corners revealing additional corners // bool cornersFound = true; while (cornersFound) { cornersFound = false; // // Topology helper needs to be updated each cycle since tiles get deleted // const TopologyHelper* th = getTopologyHelper(false, true, false); // // Keep track of tiles that need to be deleted // std::vector tilesToDelete; // // Check all nodes // const int numTiles = getNumberOfTiles(); for (int i = 0; i < numTiles; i++) { // // Get the nodes in the tile // int nodes[3]; getTile(i, nodes); // // count the number of corner nodes in the tile // int numCornerNodesInTile = 0; for (int j = 0; j < 3; j++) { if (th->getNodeNumberOfNeighbors(nodes[j]) == 2) { numCornerNodesInTile++; } } // // If only one tile is used by the node then it must be a corner node // if (numCornerNodesInTile > 0) { if (numCornerNodesInTile >= numCornerNodes) { tilesToDelete.push_back(i); } } } // // If corner tiles are found // if (tilesToDelete.empty() == false) { deleteTiles(tilesToDelete); cornersFound = true; tilesDeletedCount += tilesToDelete.size(); } } if (DebugControl::getDebugOn()) { std::cout << tilesDeletedCount << " corner tiles were deleted." << std::endl; } return tilesDeletedCount; } /* int TopologyFile::removeCornerTiles(const int numCornerNodes) { int tilesDeletedCount = 0; // // May need multiple iterations due to corners revealing additional corners // bool cornersFound = true; while (cornersFound) { cornersFound = false; // // Topology helper needs to be updated each cycle since tiles get deleted // const TopologyHelper* th = getTopologyHelper(false, true, false); // // Keep track of tiles that need to be deleted // std::vector tilesToDelete; // // Check all nodes // const int numNodes = th->getNumberOfNodes(); for (int i = 0; i < numNodes; i++) { // // Get the tiles used by the node // std::vector tilesUsedByNode; th->getNodeTiles(i, tilesUsedByNode); // // If only one tile is used by the node then it must be a corner node // if (tilesUsedByNode.size() == 1) { tilesToDelete.push_back(tilesUsedByNode[0]); } } // // If corner tiles are found // if (tilesToDelete.isEmpty() == false) { deleteTiles(tilesToDelete); cornersFound = true; tilesDeletedCount += tilesToDelete.size(); } } if (DebugControl::getDebugOn()) { std::cout << tilesDeletedCount << " corner tiles were deleted." << std::endl; } topologyHelperNeedsRebuild = true; setModified(); return tilesDeletedCount; } */ /* int TopologyFile::disconnectIslands() { // // Get this topology file's topology helper (DO NOT DELETE IT) // const TopologyHelper* topologyHelper = getTopologyHelper(false, true, false); const int numNodes = topologyHelper->getNumberOfNodes(); if (numNodes < 2) { return 0; } std::vector baseNeighbor(numNodes, -1); std::vector numConnectedNeighbors(numNodes, 0); std::vector visited(numNodes, 0); // // Mark all nodes without neighbors as visited // for (int i = 0; i < numNodes; i++) { if (topologyHelper->getNodeHasNeighbors(i) == false) { visited[i] = 1; } } // // Search the surface marking all connected nodes. // for (int n = 0; n < numNodes; n++) { if (visited[n] == 0) { const int nodeNumberIn = n; const int origNeighbor = n; std::stack st; st.push(nodeNumberIn); while(!st.isEmpty()) { const int nodeNumber = st.top(); st.pop(); if (visited[nodeNumber] == 0) { visited[nodeNumber] = 1; baseNeighbor[nodeNumber] = origNeighbor; numConnectedNeighbors[origNeighbor]++; std::vector neighbors; topologyHelper->getNodeNeighbors(nodeNumber, neighbors); for (int i = 0; i < static_cast(neighbors.size()); i++) { const int node = neighbors[i]; if (visited[node] == 0) { st.push(node); } } } } } } // // find node with most connected neighbors // int mostNeighborsNode = -1; int mostNeighbors = 0; for (int j = 0; j < numNodes; j++) { if (numConnectedNeighbors[j] > 0) { if (DebugControl::getDebugOn()) { std::cout << j << " is connected to " << numConnectedNeighbors[j] << " nodes." << std::endl; } } if (numConnectedNeighbors[j] > mostNeighbors) { mostNeighborsNode = j; mostNeighbors = numConnectedNeighbors[j]; } } if (DebugControl::getDebugOn()) { std::cout << mostNeighborsNode << " has the most neighbors = " << mostNeighbors << std::endl; } // // Disconnect all nodes that are not // connected to the node with the most connected neighbors // std::vector markedNodes(numNodes, false); if (mostNeighborsNode >= 0) { for (int i = 0; i < numNodes; i++) { if (baseNeighbor[i] != mostNeighborsNode) { markedNodes[i] = true; } } } deleteTilesWithMarkedNodes(markedNodes); topologyHelperNeedsRebuild = true; setModified(); } */ /** * Flip the orientation of all tiles */ void TopologyFile::flipTileOrientation() { const int numTiles = getNumberOfTiles(); int v1, v2, v3; for (int i = 0; i < numTiles; i++) { getTile(i, v1, v2, v3); setTile(i, v3, v2, v1); } setModified(); topologyHelperNeedsRebuild = true; } /** * Set the number of Topology Nodes (all zeros for data) */ /* void TopologyFile::setNumberOfTopologyNodes(const int numNodes) { TopologyNode tp(0, TopologyNode::INTERIOR); nodes.resize(numNodes, tp); setModified(); topologyHelperNeedsRebuild = true; } */ /** * Get the topology information for a node. */ /* const TopologyNode* TopologyFile::getTopologyNode(const int nodeNumber) const { return &nodes[nodeNumber]; } */ /** * get a Tile. */ const int* TopologyFile::getTile(const int indx) const { const int* tiles = dataArrays[0]->getDataPointerInt(); return &tiles[indx * 3]; } /** * Get a tiles vertices. */ void TopologyFile::getTile(const int tileNumber, int& v1, int& v2, int& v3) const { int32_t* tiles = dataArrays[0]->getDataPointerInt(); v1 = tiles[tileNumber * 3]; v2 = tiles[tileNumber * 3 + 1]; v3 = tiles[tileNumber * 3 + 2]; } /** * Get a tiles vertices. */ void TopologyFile::getTile(const int tileNumber, int vertices[3]) const { int32_t* tiles = dataArrays[0]->getDataPointerInt(); vertices[0] = tiles[tileNumber * 3]; vertices[1] = tiles[tileNumber * 3 + 1]; vertices[2] = tiles[tileNumber * 3 + 2]; } /** * Find the tile (that is not notTileNum) with the two specified vertices. */ int TopologyFile::getTileWithVertices(const int v1, const int v2, const int notTileNum) const { const int num = getNumberOfTiles(); for (int i = 0; i < num; i++) { if (i != notTileNum) { int p1, p2, p3; getTile(i, p1, p2, p3); if (((v1 == p1) && (v2 == p2)) || ((v1 == p2) && (v2 == p1))) { return i; } if (((v1 == p2) && (v2 == p3)) || ((v1 == p3) && (v2 == p2))) { return i; } if (((v1 == p1) && (v2 == p3)) || ((v1 == p3) && (v2 == p1))) { return i; } } } return -1; } /** * Get the topology helper. Users should not store the pointer to the topology * helper since it may be modified at any time. Call this method to get the * pointer and then use it immediately. */ const TopologyHelper* TopologyFile::getTopologyHelper(const bool needEdgeInfo, const bool needNodeInfo, const bool needNodeInfoSorted) const { QMutexLocker locked(&gettingTopoHelper);//lock BEFORE testing whether rebuild is needed if (topologyHelper == NULL) { topologyHelperNeedsRebuild = true; } if (topologyHelperNeedsRebuild == false) { if (needEdgeInfo) { if (topologyHelper->getEdgeInfoValid() == false) { topologyHelperNeedsRebuild = true; } } if (needNodeInfo) { if (topologyHelper->getNodeInfoValid() == false) { topologyHelperNeedsRebuild = true; } } if (needNodeInfoSorted) { if (topologyHelper->getNodeSortedInfoValid() == false) { topologyHelperNeedsRebuild = true; } } } if (topologyHelperNeedsRebuild) { if (topologyHelper != NULL) { delete topologyHelper; } topologyHelper = new TopologyHelper(this, needEdgeInfo, needNodeInfo, needNodeInfoSorted); topologyHelperNeedsRebuild = false; } return topologyHelper; } /** * Get the section numbers for the nodes. Returns true if the sections are valid else false. */ bool TopologyFile::getNodeSections(std::vector& nodeSectionsOut) const { nodeSectionsOut = nodeSections; if (nodeSectionsOut.empty()) { return false; } return true; } /** * set a tiles vertices. */ void TopologyFile::setTile(const int tileNumber, const int v1, const int v2, const int v3) { int32_t* tiles = dataArrays[0]->getDataPointerInt(); tiles[tileNumber * 3] = v1; tiles[tileNumber * 3 + 1] = v2; tiles[tileNumber * 3 + 2] = v3; setModified(); topologyHelperNeedsRebuild = true; // add one to node since node number range is [0..N-1] numberOfNodes = std::max(v1+1, numberOfNodes); numberOfNodes = std::max(v2+1, numberOfNodes); numberOfNodes = std::max(v3+1, numberOfNodes); } /** * set a tiles vertices. */ void TopologyFile::setTile(const int tileNumber, const int v[3]) { setTile(tileNumber, v[0], v[1], v[2]); } /** * Set the number of tiles (all vertices are zero) */ void TopologyFile::setNumberOfTiles(const int numTiles) { std::vector dim; dim.push_back(numTiles); dim.push_back(3); if (dataArrays.empty()) { GiftiDataArray* nda = new GiftiDataArray(this, GiftiCommon::intentTopologyTriangles, GiftiDataArray::DATA_TYPE_INT32, dim); addDataArray(nda); } else { dataArrays[0]->setDimensions(dim); } setModified(); topologyHelperNeedsRebuild = true; } /** * see if the topology file is equivalent to this one (contains exact same tiles). */ bool TopologyFile::equivalent(const TopologyFile& tf) const { // // Compare type of topology // if (getTopologyType() != tf.getTopologyType()) { return false; } // // Check number of tiles // const int numTiles = getNumberOfTiles(); if (numTiles != tf.getNumberOfTiles()) { return false; } // // Get pointers to the tiles // const int32_t* myTiles = dataArrays[0]->getDataPointerInt(); const int32_t* otherTiles = tf.dataArrays[0]->getDataPointerInt(); // // Compare all tile vertices // const int numVertices = numTiles * 3; for (int i = 0; i < numVertices; i++) { if (myTiles[i] != otherTiles[i]) { return false; } } // // Files must be the same // return true; } /** * get the topology from a vtk poly data file */ void TopologyFile::importFromVtkFile(vtkPolyData* polyDataIn) { clear(); vtkPolyData* polyData = polyDataIn; if (DebugControl::getDebugOn()) { std::cout << "Before Triangle Filter:\n" << " Topology Import Polydata Strips: " << polyData->GetNumberOfStrips() << "\n" << " Topology Import Polydata Polygons: " << polyData->GetNumberOfPolys() << "\n"; } // // Convert triangle strips to triangles (if necessary) // vtkTriangleFilter* triangleFilter = NULL; if (polyData->GetNumberOfStrips() > 0) { triangleFilter = vtkTriangleFilter::New(); triangleFilter->SetInput(polyDataIn); triangleFilter->Update(); polyData = triangleFilter->GetOutput(); } if (DebugControl::getDebugOn()) { std::cout << "After Triangle Filter:\n" << " Topology Import Polydata Strips: " << polyData->GetNumberOfStrips() << "\n" << " Topology Import Polydata Polygons: " << polyData->GetNumberOfPolys() << "\n"; } std::vector triangles; vtkCellArray* polys = polyData->GetPolys(); vtkIdType npts; vtkIdType* pts; for (polys->InitTraversal(); polys->GetNextCell(npts,pts); ) { if (npts == 3) { triangles.push_back(static_cast(pts[0])); triangles.push_back(static_cast(pts[1])); triangles.push_back(static_cast(pts[2])); } else { std::cout << "ERROR: VTK surface contains polygon with " << npts << " vertices." << std::endl; } } const int numTrianglesRead = static_cast(triangles.size()) / 3; setNumberOfTiles(numTrianglesRead); for (int i = 0; i < numTrianglesRead; i++) { setTile(i, &triangles[i*3]); } if (DebugControl::getDebugOn()) { std::cout << "Topology contains " << numTrianglesRead << " triangles." << std::endl; } setModified(); topologyHelperNeedsRebuild = true; if (triangleFilter != NULL) { triangleFilter->Delete(); } } /** * get the topology from a MNI OBJ surface file. */ void TopologyFile::importFromMniObjSurfaceFile(const MniObjSurfaceFile& mni) throw (FileException) { clear(); const int numberOfTriangles = mni.getNumberOfTriangles(); if (numberOfTriangles > 0) { setNumberOfTiles(numberOfTriangles); for (int i = 0; i < numberOfTriangles; i++) { const int* triangle = mni.getTriangle(i); setTile(i, triangle[0], triangle[1], triangle[2]); } } appendToFileComment(" Imported from "); appendToFileComment(FileUtilities::basename(mni.getFileName())); setModified(); topologyHelperNeedsRebuild = true; } /** * get the topology from a brain voyager file */ void TopologyFile::importFromBrainVoyagerFile(const BrainVoyagerFile& bvf) { clear(); const int numberOfTriangles = bvf.getNumberOfTriangles(); if (numberOfTriangles > 0) { setNumberOfTiles(numberOfTriangles); for (int i = 0; i < numberOfTriangles; i++) { int triangle[3]; bvf.getTriangle(i, triangle); setTile(i, triangle[0], triangle[1], triangle[2]); } } appendToFileComment(" Imported from "); appendToFileComment(FileUtilities::basename(bvf.getFileName())); setModified(); topologyHelperNeedsRebuild = true; } /** * get the topology from a free surfer surface file */ void TopologyFile::importFromFreeSurferSurfaceFile(const FreeSurferSurfaceFile& fssf, const TopologyFile* closedTopologyFile) { clear(); const int numberOfTriangles = fssf.getNumberOfTriangles(); // // Binary patch surfaces have no triangles so obtain topology from the closed // topology file which should have been read from the "orig" free surfer surface. // if (numberOfTriangles <= 0) { if (closedTopologyFile == NULL) { throw FileException(filename, "This surface has no topology (triangles) and there \n" "is no closed topology previously loaded. Try loading\n" "the \"orig\" surface prior to loading this surface."); } else if (closedTopologyFile->getNumberOfTiles() <= 0) { throw FileException(filename, "This surface has no topology (triangles) and there \n" "is no closed topology previously loaded. Try loading\n" "the \"orig\" surface prior to loading this surface."); } else { // // Copy from closed topology any tiles that have its three nodes // in the patch // const int maxNodes = std::max(closedTopologyFile->getNumberOfNodes(), fssf.getNumberOfVertices()); std::vector nodeUsed(maxNodes, false); for (int i = 0; i < fssf.getNumberOfVertices(); i++) { nodeUsed[fssf.getVertexNumber(i)] = true; } for (int i = 0; i < closedTopologyFile->getNumberOfTiles(); i++) { int v1, v2, v3; closedTopologyFile->getTile(i, v1, v2, v3); if (nodeUsed[v1] && nodeUsed[v2] && nodeUsed[v3]) { addTile(v1, v2, v3); } } } } else { setNumberOfTiles(numberOfTriangles); for (int i = 0; i < numberOfTriangles; i++) { int triangle[3]; fssf.getTriangle(i, triangle); setTile(i, triangle[0], triangle[1], triangle[2]); } } appendToFileComment(" Imported from "); appendToFileComment(FileUtilities::basename(fssf.getFileName())); setModified(); topologyHelperNeedsRebuild = true; } /** * export topology to a free surfer surface file */ void TopologyFile::exportToFreeSurferSurfaceFile(FreeSurferSurfaceFile& fssf) { const int numberOfTriangles = getNumberOfTiles(); for (int i = 0; i < numberOfTriangles; i++) { int v[3]; getTile(i, v); fssf.setTriangle(i, v); } } /** * Read topology file version 0. */ void TopologyFile::readFileDataVersion0(QTextStream& stream, const QString& firstLineRead) throw (FileException) { QString line = firstLineRead; //readLine(stream, line); numberOfNodes = line.toInt(); //setNumberOfTopologyNodes(numberOfNodes); nodeSections.resize(numberOfNodes, 0); for (int i = 0; i < numberOfNodes; i++) { readLine(stream, line); int nodeNumber; int numNeighbors; int sectionNumber; int contourNumber; int pointNumber; int categoryInt; sscanf(line.toAscii().constData(), "%d %d %d %d %d %d", &nodeNumber, &numNeighbors, §ionNumber, &contourNumber, &pointNumber, &categoryInt); nodeSections[i] = sectionNumber; /* using sscanf is faster QTextIStream(&line) >> nodeNumber >> numNeighbors >> sectionNumber >> contourNumber >> pointNumber >> categoryInt; */ // TopologyNode::CATEGORIES category = (TopologyNode::CATEGORIES)categoryInt; // nodes[i].setData(sectionNumber, category); // // Neighbor data no longer used so read and ignore it // for (int j = 0; j < numNeighbors; j++) { readLine(stream, line); } } readTilesAscii(stream, true); } /** * Read the tiles */ void TopologyFile::readTilesAscii(QTextStream& stream, const bool clockwiseOrientation) throw (FileException) { QString line; readLine(stream, line); const int numTiles = line.toInt(); if (numTiles < 0) { throw FileException(filename, "Number of tiles is less than zero"); } setNumberOfTiles(numTiles); if (numTiles > 0) { int* tilePtr = dataArrays[0]->getDataPointerInt(); // // Read tiles (Note that version 0 stores tiles with Clockwise orientation so switch tile order) // int t1, t2, t3; for (int j = 0; j < numTiles; j++) { // readLine & sscanf is faster than "stream >> t1 >> t2 >> t3;" readLine(stream, line); sscanf(line.toAscii().constData(), "%d %d %d", &t1, &t2, &t3); const int j3 = j * 3; if (clockwiseOrientation) { tilePtr[j3] = t3; tilePtr[j3 + 1] = t2; tilePtr[j3 + 2] = t1; } else { tilePtr[j3] = t1; tilePtr[j3 + 1] = t2; tilePtr[j3 + 2] = t3; } // add one to node since node number range is [0..N-1] numberOfNodes = std::max(numberOfNodes, t1+1); numberOfNodes = std::max(numberOfNodes, t2+1); numberOfNodes = std::max(numberOfNodes, t3+1); } } setModified(); topologyHelperNeedsRebuild = true; } /** * Read the tiles */ void TopologyFile::readTilesBinary(QDataStream& binStream) throw (FileException) { int numTiles = 0; binStream >> numTiles; if (numTiles < 0) { throw FileException(filename, "Number of tiles is less than zero"); } setNumberOfTiles(numTiles); if (numTiles > 0) { int* tilePtr = dataArrays[0]->getDataPointerInt(); // // Read tiles // int t1, t2, t3; for (int j = 0; j < numTiles; j++) { binStream >> t1 >> t2 >> t3; const int j3 = j * 3; tilePtr[j3] = t1; tilePtr[j3 + 1] = t2; tilePtr[j3 + 2] = t3; // add one to node since node number range is [0..N-1] numberOfNodes = std::max(numberOfNodes, t1+1); numberOfNodes = std::max(numberOfNodes, t2+1); numberOfNodes = std::max(numberOfNodes, t3+1); } } setModified(); topologyHelperNeedsRebuild = true; } /** * Read topology file version 1. */ void TopologyFile::readFileDataVersion1(QFile& /*file*/, QTextStream& stream, QDataStream& binStream) throw (FileException) { switch (getFileReadType()) { case FILE_FORMAT_ASCII: readTilesAscii(stream, false); break; case FILE_FORMAT_BINARY: #ifdef QT4_FILE_POS_BUG { qint64 offset = findBinaryDataOffsetQT4Bug(file, "tag-version 1"); if (offset > 0) { offset++; file.seek(offset); } } #endif readTilesBinary(binStream); break; case FILE_FORMAT_XML: throw FileException(filename, "Reading in XML format not supported."); break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Reading in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Comma Separated Value File Format not supported."); break; } } /** * Read Topology File's data. May throw FileException. */ void TopologyFile::readLegacyFileData(QFile& file, QTextStream& stream, QDataStream& binStream) throw (FileException) { // // Should reading data be skipped ? // if (getReadMetaDataOnlyFlag()) { return; } // get starting position of data //const QIODevice::Offset startOfData = file.at(); int version = 0; // read first line to see if it is version 1 or later QString line, versionStr, versionNumberStr; readTagLine(stream, line, versionStr, versionNumberStr); if (versionStr == tagFileVersion) { switch(versionNumberStr.toInt()) { case 1: version = 1; break; default: throw FileException(filename, "Unknown version of topology file"); } } switch(version) { case 1: { //file.seek(stream.pos()); const qint64 pos = this->getQTextStreamPosition(stream); file.seek(pos); readFileDataVersion1(file, stream, binStream); } break; default: /* throw FileException(getFileName(), "Due to a bug in QT4, Caret is unable to read version 0 topology.\n" "files at this time. To get around this problem use caret_file_convert." " caret_file_convert -binary file.topo\n" " caret_file_convert -text file.topo"); */ //file.at(startOfData); readFileDataVersion0(stream, line); break; } topologyHelperNeedsRebuild = true; } void TopologyFile::writeLegacyFileData(QTextStream& stream, QDataStream& binStream) throw (FileException) { stream << tagFileVersion << " 1" << "\n"; const int numTiles = getNumberOfTiles(); switch (getFileWriteType()) { case FILE_FORMAT_ASCII: { stream << numTiles << "\n"; for (int j = 0; j < numTiles; j++) { int t1, t2, t3; getTile(j, t1, t2, t3); stream << t1 << " " << t2 << " " << t3 << "\n"; } } break; case FILE_FORMAT_BINARY: #ifdef QT4_FILE_POS_BUG setBinaryFilePosQT4Bug(); #else // QT4_FILE_POS_BUG // // still a bug in QT 4.2.2 // setBinaryFilePosQT4Bug(); #endif // QT4_FILE_POS_BUG { binStream << numTiles; for (int j = 0; j < numTiles; j++) { int t1, t2, t3; getTile(j, t1, t2, t3); binStream << t1 << t2 << t3; } } break; case FILE_FORMAT_XML: throw FileException(filename, "Writing in XML format not supported."); break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Writing in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Comma Separated Value File Format not supported."); break; } } /** * Update the file's metadata for Caret6. */ void TopologyFile::updateMetaDataForCaret6() { AbstractFile::updateMetaDataForCaret6(); switch (this->getTopologyType()) { case TOPOLOGY_TYPE_CLOSED: this->setHeaderTag(GiftiCommon::metaDataNameTopologicalType, "Closed"); break; case TOPOLOGY_TYPE_OPEN: this->setHeaderTag(GiftiCommon::metaDataNameTopologicalType, "Open"); break; case TOPOLOGY_TYPE_CUT: this->setHeaderTag(GiftiCommon::metaDataNameTopologicalType, "Cut"); break; case TOPOLOGY_TYPE_LOBAR_CUT: this->setHeaderTag(GiftiCommon::metaDataNameTopologicalType, "Cut"); break; case TOPOLOGY_TYPE_UNKNOWN: case TOPOLOGY_TYPE_UNSPECIFIED: this->setHeaderTag(GiftiCommon::metaDataNameTopologicalType, "Closed"); break; } this->removeHeaderTag("perimeter_id"); } /** * Write the file's memory in caret6 format to the specified name. */ QString TopologyFile::writeFileInCaret6Format(const QString& filenameIn, Structure structure,const ColorFile* colorFileIn, const bool useCaret6ExtensionFlag) throw (FileException) { QString name = filenameIn; if (useCaret6ExtensionFlag) { name = FileUtilities::replaceExtension(filenameIn, ".topo", SpecFile::getGiftiTopologyFileExtension()); } this->setFileWriteType(AbstractFile::FILE_FORMAT_XML_GZIP_BASE64); this->writeFile(name); return name; } caret-5.6.4~dfsg.1.orig/caret_files/TopographyFile.h0000664000175000017500000001425011572067322022150 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_TOPOGRAPHY_FILE_H__ #define __VE_TOPOGRAPHY_FILE_H__ #include "NodeAttributeFile.h" class DeformationMapFile; class TopographyFile; //#include "DeformationMapFile.h" /// Class for storing topography data associated with each node. class NodeTopography { private: /// topography file this Node Topography belongs to TopographyFile* topographyFile; /// name of topographic area QString name; /// mean of eccentricity float eMean; /// low of eccentricity float eLow; /// high of eccentricity float eHigh; /// mean of polar angle float pMean; /// low of polar angle float pLow; /// high of polar angle float pHigh; public: /// constructor NodeTopography(); /// constructor NodeTopography(const float eccentricityMean, const float eccentricityLow, const float eccentricityHigh, const float polarMean, const float polarLow, const float polarHigh, const QString& areaName); /// get topography data void getData(float& eccentricityMean, float& eccentricityLow, float& eccentricityHigh, float& polarMean, float& polarLow, float& polarHigh, QString& areaName) const; /// set topography data void setData(const float eccentricityMean, const float eccentricityLow, const float eccentricityHigh, const float polarMean, const float polarLow, const float polarHigh, const QString& areaName); friend class TopographyFile; }; /// class for reading/writing/storing a Topography File class TopographyFile : public NodeAttributeFile { private: /// Store the topography data here std::vector topography; /// number of nodes for reading a version 0 file int numberOfNodesVersion0; /// get an offset into topography //int getOffset(const int nodeNumber, const int columnNumber) const; /// read a version 0 file void readFileDataVersion0(QTextStream& stream) throw (FileException); /// read a version 1 file void readFileDataVersion1(QTextStream& stream) throw (FileException); /// read a Topography File void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException); /// write a Topography File void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException); public: /// constructor for TopographyFile TopographyFile(); /// destructor for TopographyFile ~TopographyFile(); /// append a node attribute file to this one void append(NodeAttributeFile& naf) throw (FileException); /// append a node attribute file to this one but selectively load/overwrite columns /// columnDestination is where naf's columns should be (-1=new, -2=do not load) void append(NodeAttributeFile& naf, std::vector columnDestination, const FILE_COMMENT_MODE fcm) throw (FileException); /// add columns to this topography file void addColumns(const int numberOfNewColumns); /// Add nodes to the file void addNodes(const int numberOfNodesToAdd); /// add topography for a node void setNodeTopography(const int nodeNumber, const int columnNumber, const NodeTopography& nt); /// clear the current data void clear(); /// deform "this" node attribute file placing the output in "deformedFile". void deformFile(const DeformationMapFile& dmf, NodeAttributeFile& deformedFile, const DEFORM_TYPE dt) const throw (FileException); /// reset a column of data void resetColumn(const int columnNumber); /// remove a column of data void removeColumn(const int columnNumber); /// get the minimum and maximum values for each category void getMinMaxTopography(const int columnNumber, float eccentricityMean[2], float eccentricityLow[2], float eccentricityHigh[2], float polarMean[2], float polarLow[2], float polarHigh[2]) const; /// set the number of nodes and columns void setNumberOfNodesAndColumns(const int numNodes, const int numColumns); /// set the number of nodes for reading a version 0 topography file void setNumberOfNodesVersion0File(const int numNodes) { numberOfNodesVersion0 = numNodes; } /// get topography for a specified node and column NodeTopography getNodeTopography(const int nodeNumber, const int columnNumber) const; friend class NodeTopography; }; #ifdef _TOPOGRAPHY_FILE_MAIN_ #endif // _TOPOGRAPHY_FILE_MAIN_ #endif // __VE_TOPOGRAPHY_FILE_H__ caret-5.6.4~dfsg.1.orig/caret_files/TopographyFile.cxx0000664000175000017500000004322011572067322022522 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #define _TOPOGRAPHY_FILE_MAIN_ #include "TopographyFile.h" #undef _TOPOGRAPHY_FILE_MAIN_ #include "DeformationMapFile.h" #include "FileUtilities.h" #include "SpecFile.h" #include "StringUtilities.h" /** * Constructor */ NodeTopography::NodeTopography() { topographyFile = NULL; setData(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ""); } /** * Constructor */ NodeTopography::NodeTopography(const float eccentricityMean, const float eccentricityLow, const float eccentricityHigh, const float polarMean, const float polarLow, const float polarHigh, const QString& areaName) { topographyFile = NULL; setData(eccentricityMean, eccentricityLow, eccentricityHigh, polarMean, polarLow, polarHigh, areaName); } /** * Get data for a node */ void NodeTopography::getData(float& eccentricityMean, float& eccentricityLow, float& eccentricityHigh, float& polarMean, float& polarLow, float& polarHigh, QString& areaName) const { eccentricityMean = eMean; eccentricityLow = eLow; eccentricityHigh = eHigh; polarMean = pMean; polarLow = pLow; polarHigh = pHigh; areaName = name; } /** * Set the data for a node. */ void NodeTopography::setData(const float eccentricityMean, const float eccentricityLow, const float eccentricityHigh, const float polarMean, const float polarLow, const float polarHigh, const QString& areaName) { eMean = eccentricityMean; eLow = eccentricityLow; eHigh = eccentricityHigh; pMean = polarMean; pLow = polarLow; pHigh = polarHigh; name = areaName; if (topographyFile != NULL) { topographyFile->setModified(); } } /** * The constructor. */ TopographyFile::TopographyFile() : NodeAttributeFile("Topography File", SpecFile::getTopographyFileExtension()) { numberOfNodesVersion0 = -1; clear(); } /** * The destructor. */ TopographyFile::~TopographyFile() { clear(); } /** * Clear the topography file. */ void TopographyFile::clear() { clearNodeAttributeFile(); setNumberOfNodesAndColumns(0, 0); } /** * Add topography for a node. */ void TopographyFile::setNodeTopography(const int nodeNumber, const int columnNumber, const NodeTopography& nt) { const int indx = getOffset(nodeNumber, columnNumber); topography[indx] = nt; topography[indx].topographyFile = this; setModified(); } /** * append a node attribute file to this one but selectively load/overwrite columns * columnDestination is where naf's columns should be (-1=new, -2=do not load). */ void TopographyFile::append(NodeAttributeFile& /*naf*/, std::vector /*columnDestination*/, const FILE_COMMENT_MODE /*fcm*/) throw (FileException) { throw FileException("Not implemented yet."); } /** * append an topography file to this one */ void TopographyFile::append(NodeAttributeFile &naf) throw (FileException) { TopographyFile& tf = dynamic_cast(naf); if (getNumberOfNodes() != tf.getNumberOfNodes()) { throw FileException("Cannot append Topography, number of columns does not match."); } const int oldNumCols = getNumberOfColumns(); const int appendNumCols = tf.getNumberOfColumns(); // // Add the additional columns to the file // addColumns(appendNumCols); // // Transfer topography data // for (int i = 0; i < numberOfNodes; i++) { for (int j = 0; j < appendNumCols; j++) { const NodeTopography nt = tf.getNodeTopography(i, j); setNodeTopography(i, oldNumCols + j, nt); } } for (int j = 0; j < appendNumCols; j++) { setColumnName(oldNumCols + j, getColumnName(j)); setColumnComment(oldNumCols + j, getColumnComment(j)); } setModified(); // // transfer the file's comment // appendFileComment(tf); } /** * add columns to this topography file */ void TopographyFile::addColumns(const int numberOfNewColumns) { const int oldNumberOfColumns = numberOfColumns; const int totalColumns = numberOfColumns + numberOfNewColumns; // // Save existing topography data // const std::vector data = topography; // // Setup file for new number of columns (will expand space for column naming) // setNumberOfNodesAndColumns(numberOfNodes, totalColumns); // // transfer existing topography data // for (int i = 0; i < numberOfNodes; i++) { for (int j = 0; j < numberOfColumns; j++) { if (j < oldNumberOfColumns) { const int oldIndex = (oldNumberOfColumns * i) + j; setNodeTopography(i, j, data[oldIndex]); } } } setModified(); } /** * Add nodes to the file. */ void TopographyFile::addNodes(const int numberOfNodesToAdd) { setNumberOfNodesAndColumns(numberOfNodes + numberOfNodesToAdd, numberOfColumns); setModified(); } /** * Deform topography file. */ void TopographyFile::deformFile(const DeformationMapFile& dmf, NodeAttributeFile& deformedFile, const DEFORM_TYPE /*dt*/) const throw (FileException) { TopographyFile& deformedTopographyFile = dynamic_cast(deformedFile); const int numNodes = dmf.getNumberOfNodes(); const int numColumns = getNumberOfColumns(); deformedTopographyFile.setNumberOfNodesAndColumns(numNodes, numColumns); // // Transfer stuff in AbstractFile and NodeAttributeFile // transferFileDataForDeformation(dmf, deformedTopographyFile); int tileNodes[3]; float tileAreas[3]; for (int i = 0; i < numNodes; i++) { dmf.getDeformDataForNode(i, tileNodes, tileAreas); for (int j = 0; j < getNumberOfColumns(); j++) { NodeTopography nt; if (tileNodes[0] > -1) { nt = getNodeTopography(tileNodes[0], j); } else if (tileNodes[1] > -1) { nt = getNodeTopography(tileNodes[1], j); } else if (tileNodes[2] > -1) { nt = getNodeTopography(tileNodes[2], j); } nt.topographyFile = &deformedTopographyFile; deformedTopographyFile.setNodeTopography(i, j, nt); } } } /** * reset a column of data. */ void TopographyFile::resetColumn(const int columnNumber) { const NodeTopography nt(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ""); for (int i = 0; i < numberOfNodes; i++) { setNodeTopography(i, columnNumber, nt); } setColumnName(columnNumber, ""); setColumnComment(columnNumber, ""); setModified(); } /** * remove a column of data. */ void TopographyFile::removeColumn(const int columnNumber) { if (numberOfColumns <= 1) { clear(); return; } TopographyFile tf; tf.setNumberOfNodesAndColumns(numberOfNodes, numberOfColumns - 1); for (int i = 0; i < numberOfNodes; i++) { int ctr = 0; for (int j = 0; j < numberOfColumns; j++) { if (j != columnNumber) { const NodeTopography nt = getNodeTopography(i, j); tf.setNodeTopography(i, ctr, nt); ctr++; } } } int ctr = 0; for (int j = 0; j < numberOfNodes; j++) { if (j != columnNumber) { setColumnName(ctr, getColumnName(j)); setColumnComment(ctr, getColumnComment(j)); ctr++; } } setNumberOfNodesAndColumns(numberOfNodes, numberOfColumns - 1); topography = tf.topography; setModified(); } /** * Get the topography by index. */ /* const NodeTopography* TopographyFile::getNodeTopographyByIndex(const int topoIndex) const { return &topography[topoIndex]; } */ /** * Set the number of nodes and columns. */ void TopographyFile::setNumberOfNodesAndColumns(const int numNodes, const int numColumns) { numberOfNodes = numNodes; numberOfColumns = numColumns; const int num = numberOfNodes * numberOfColumns * numberOfItemsPerColumn; if (num <= 0) { topography.clear(); } else { topography.resize(num); } numberOfNodesColumnsChanged(); setModified(); } /** * Get the topography by node number. */ NodeTopography TopographyFile::getNodeTopography(const int nodeNumber, const int columnNumber) const { const int indx = getOffset(nodeNumber, columnNumber); return topography[indx]; } /** * Get the min/max topography. */ void TopographyFile::getMinMaxTopography(const int columnNumber, float eccentricityMean[2], float eccentricityLow[2], float eccentricityHigh[2], float polarMean[2], float polarLow[2], float polarHigh[2]) const { eccentricityMean[0] = std::numeric_limits::max(); eccentricityMean[1] = -std::numeric_limits::max(); eccentricityLow[0] = std::numeric_limits::max(); eccentricityLow[1] = -std::numeric_limits::max(); eccentricityHigh[0] = std::numeric_limits::max(); eccentricityHigh[1] = -std::numeric_limits::max(); polarMean[0] = std::numeric_limits::max(); polarMean[1] = -std::numeric_limits::max(); polarLow[0] = std::numeric_limits::max(); polarLow[1] = -std::numeric_limits::max(); polarHigh[0] = std::numeric_limits::max(); polarHigh[1] = -std::numeric_limits::max(); for (int i = 0; i < getNumberOfNodes(); i++) { const NodeTopography nt = getNodeTopography(i, columnNumber); float emean, elow, ehigh, pmean, plow, phigh; QString areaName; nt.getData(emean, elow, ehigh, pmean, plow, phigh, areaName); if (areaName.isEmpty()) { continue; } if (emean < eccentricityMean[0]) { eccentricityMean[0] = emean; } if (emean > eccentricityMean[1]) { eccentricityMean[1] = emean; } if (elow < eccentricityLow[0]) { eccentricityLow[0] = elow; } if (elow > eccentricityLow[1]) { eccentricityLow[1] = elow; } if (ehigh < eccentricityHigh[0]) { eccentricityHigh[0] = ehigh; } if (ehigh > eccentricityHigh[1]) { eccentricityHigh[1] = ehigh; } if (pmean < polarMean[0]) { polarMean[0] = pmean; } if (pmean > polarMean[1]) { polarMean[1] = pmean; } if (plow < polarLow[0]) { polarLow[0] = plow; } if (plow > polarLow[1]) { polarLow[1] = plow; } if (phigh < polarHigh[0]) { polarHigh[0] = phigh; } if (phigh > polarHigh[1]) { polarHigh[1] = phigh; } } } /** * Read the version 0 file. */ void TopographyFile::readFileDataVersion0(QTextStream& stream) throw (FileException) { if (numberOfNodesVersion0 <= 0) { QString msg("The number of nodes for reading a version 0 topography file " "have not been set."); throw FileException(filename, msg); } setNumberOfNodesAndColumns(numberOfNodesVersion0, 1); QString line; int numNodesInFile = -1; readLine(stream, line); QTextStream(&line, QIODevice::ReadOnly) >> numNodesInFile; // // Should reading data be skipped ? // if (getReadMetaDataOnlyFlag()) { return; } if (numNodesInFile <= 0) { throw FileException(filename, "No data in topography file"); } for (int i = 0; i < numNodesInFile; i++) { readLine(stream, line); int node; QString an; float em, el, eh, pm, pl, ph; QTextStream(&line, QIODevice::ReadOnly) >> node >> an >> em >> el >> eh >> pm >> pl >> ph; NodeTopography nt(em, el, eh, pm, pl, ph, an); setNodeTopography(node, 0, nt); } } /** * Read the version 1 file. */ void TopographyFile::readFileDataVersion1(QTextStream& stream) throw (FileException) { int numNodes = -1; int numCols = -1; bool readingTags = true; while(readingTags) { QString tag, tagValue; readTagLine(stream, tag, tagValue); if (tag == tagBeginData) { readingTags = false; } else if (tag == tagNumberOfNodes) { numNodes = tagValue.toInt(); if ((numNodes > 0) && (numCols > 0)) { setNumberOfNodesAndColumns(numNodes, numCols); } } else if (tag == tagNumberOfColumns) { numCols = tagValue.toInt(); if ((numNodes > 0) && (numCols > 0)) { setNumberOfNodesAndColumns(numNodes, numCols); } } else if (tag == tagColumnName) { QString name; const int indx = splitTagIntoColumnAndValue(tagValue, name); columnNames[indx] = name; } else if (tag == tagColumnComment) { QString name; const int indx = splitTagIntoColumnAndValue(tagValue, name); columnComments[indx] = StringUtilities::setupCommentForDisplay(name); } else if (tag == tagFileTitle) { fileTitle = tagValue; } else { std::cerr << "WARNING: Unknown Topography File Tag: " << tag.toAscii().constData() << std::endl; } } // // Should reading data be skipped ? // if (getReadMetaDataOnlyFlag()) { return; } if (numNodes <= 0) { throw FileException(filename, "No data in Topography file"); } std::vector tokens; QString line; for (int i = 0; i < numberOfNodes; i++) { readLineIntoTokens(stream, line, tokens); if (static_cast(tokens.size()) == (numberOfColumns * 7 + 1)) { for (int j = 0; j < numberOfColumns; j++) { QString name(tokens[j * 7 + 1]); if (name == "*") { name = ""; } const float em = tokens[j * 7 + 2].toFloat(); const float el = tokens[j * 7 + 3].toFloat(); const float eh = tokens[j * 7 + 4].toFloat(); const float pm = tokens[j * 7 + 5].toFloat(); const float pl = tokens[j * 7 + 6].toFloat(); const float ph = tokens[j * 7 + 7].toFloat(); NodeTopography nt; nt.setData(em, el, eh, pm, pl, ph, name); setNodeTopography(i, j, nt); } } else { QString msg("Reading Topography file line: "); msg.append(line); throw FileException(filename, msg); } } } /** * Read the topography file. */ void TopographyFile::readFileData(QFile& file, QTextStream& stream, QDataStream&, QDomElement& /* rootElement */) throw (FileException) { // // save file position since version 0 has no tags // qint64 oldFilePosition = stream.pos(); //file.pos(); QString line; QString versionStr, versionNumberStr; readTagLine(stream, versionStr, versionNumberStr); int fileVersion = 0; if (versionStr == tagFileVersion) { fileVersion = versionNumberStr.toInt(); } switch(fileVersion) { case 0: file.seek(oldFilePosition); stream.seek(oldFilePosition); readFileDataVersion0(stream); break; case 1: readFileDataVersion1(stream); break; default: throw FileException(filename, "Invalid Topography file version"); break; } } /** * Write the topography file. */ void TopographyFile::writeFileData(QTextStream& stream, QDataStream&, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException) { stream << tagFileVersion << " 1" << "\n"; stream << tagNumberOfNodes << " " << numberOfNodes << "\n"; stream << tagNumberOfColumns << " " << numberOfColumns << "\n"; stream << tagFileTitle << " " << fileTitle << "\n"; for (int j = 0; j < numberOfColumns; j++) { stream << tagColumnName << " " << j << " " << columnNames[j] << "\n"; stream << tagColumnComment << " " << j << " " << StringUtilities::setupCommentForStorage(columnComments[j]) << "\n"; } stream << tagBeginData << "\n"; for (int i = 0; i < numberOfNodes; i++) { stream << i; for (int j = 0; j < numberOfColumns; j++) { const NodeTopography nt = getNodeTopography(i, j); QString name = nt.name; if (name.isEmpty()) { name = "*"; } stream << " " << name << " " << nt.eMean << " " << nt.eLow << " " << nt.eHigh << " " << nt.pMean << " " << nt.pLow << " " << nt.pHigh; } stream << "\n"; } } caret-5.6.4~dfsg.1.orig/caret_files/TextFile.h0000664000175000017500000000537411572067322020747 0ustar michaelmichael #ifndef __TEXT_FILE_H__ #define __TEXT_FILE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "AbstractFile.h" /// a simple text file class TextFile : public AbstractFile { public: // constructor TextFile(); // destructor ~TextFile(); // copy constructor TextFile(const TextFile& tf); // assignment operator TextFile& operator=(const TextFile& tf); // get the text QString getText() const; // set the text void setText(const QString& s); // append a line to the text (new line is also added) void appendLine(const QString& s); // append text to the file (no newline is added) void appendText(const QString& s); // clear the contents void clear(); // returns true if the file is isEmpty (contains no data) bool empty() const; // compare a file for unit testing (returns true if "within tolerance") bool compareFileForUnitTesting(const AbstractFile* af, const float tolerance, QString& messageOut) const; protected: // copy helper used by copy constructor and assignment operator void copyHelperText(const TextFile& tf); // Read the contents of the file (header has already been read) void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& rootElement) throw (FileException); // Write the file's data (header has already been written) void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& xmlDoc, QDomElement& rootElement) throw (FileException); // the text QString text; }; #endif // __TEXT_FILE_H__ caret-5.6.4~dfsg.1.orig/caret_files/TextFile.cxx0000664000175000017500000000743211572067322021317 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "SpecFile.h" #include "TextFile.h" /** * constructor. */ TextFile::TextFile() : AbstractFile("Text File", SpecFile::getTextFileExtension(), false, FILE_FORMAT_ASCII, FILE_IO_READ_AND_WRITE, FILE_IO_READ_ONLY, FILE_IO_READ_ONLY, FILE_IO_READ_ONLY, FILE_IO_READ_ONLY, FILE_IO_READ_ONLY, FILE_IO_READ_ONLY) { clear(); } /** * copy constructor. */ TextFile::TextFile(const TextFile& tf) : AbstractFile(tf) { copyHelperText(tf); } /** * assignment operator. */ TextFile& TextFile::operator=(const TextFile& tf) { if (&tf != this) { AbstractFile::operator=(tf); copyHelperText(tf); } return *this; } /** * copy helper used by copy constructor and assignment operator. */ void TextFile::copyHelperText(const TextFile& tf) { setFileName(""); text = tf.text; setModified(); } /** * destructor. */ TextFile::~TextFile() { clear(); } /** * set the text. */ void TextFile::setText(const QString& s) { text = s; setModified(); } /** * append a line to the text (new line is also added). */ void TextFile::appendLine(const QString& s) { text += s; text += "\n"; setModified(); } /** * append text to the file (no newline is added). */ void TextFile::appendText(const QString& s) { text += s; setModified(); } /** * get the text. */ QString TextFile::getText() const { return text; } /** * clear the contents. */ void TextFile::clear() { AbstractFile::clearAbstractFile(); text = ""; } /** * returns true if the file is isEmpty (contains no data). */ bool TextFile::empty() const { return (text.isEmpty()); } /** * compare a file for unit testing (returns true if "within tolerance"). */ bool TextFile::compareFileForUnitTesting(const AbstractFile* af, const float /*tolerance*/, QString& messageOut) const { const TextFile* tf = dynamic_cast(af); if (tf == NULL) { messageOut = "File for comparison is not a text file."; return false; } const bool theSame = (text == tf->text); return theSame; } /** * Read the contents of the file (header has already been read). */ void TextFile::readFileData(QFile& /*file*/, QTextStream& stream, QDataStream& /*binStream*/, QDomElement& /*rootElement*/) throw (FileException) { text = stream.readAll(); } /** * Write the file's data (header has already been written). */ void TextFile::writeFileData(QTextStream& stream, QDataStream& /*binStream*/, QDomDocument& /*xmlDoc*/, QDomElement& /*rootElement*/) throw (FileException) { stream << text; } caret-5.6.4~dfsg.1.orig/caret_files/SurfaceShapeFile.h0000664000175000017500000000761211572067322022371 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_SURFACE_SHAPE_FILE_H__ #define __VE_SURFACE_SHAPE_FILE_H__ #include "MetricFile.h" class CoordinateFile; /// Class extends metric for storing surface shape class SurfaceShapeFile : public MetricFile { public: static const QString arealDistortionColumnName; static const QString gaussianCurvatureColumnName; static const QString linearDistortionColumnName; static const QString meanCurvatureColumnName; static const QString sulcalDepthColumnName; static const QString sulcalDepthSmoothedColumnName; /// constructor SurfaceShapeFile(); /// destructor ~SurfaceShapeFile(); /// find column containing areal distortion int getArealDistortionColumnNumber() const; /// find column containing gaussian curvature int getGaussianCurvatureColumnNumber() const; /// find column containing linear distortion int getLinearDistortionColumnNumber() const; /// find column containing mean curvature int getMeanCurvatureColumnNumber() const; /// find column containing sulcal depth int getSulcalDepthColumnNumber() const; /// find column containing smoothed sulcal depth int getSulcalDepthSmoothedColumnNumber() const; /// Export free surfer ascii curvature file. void exportFreeSurferAsciiCurvatureFile(const int columnNumber, const CoordinateFile* cf, const QString& filename) throw (FileException); /// Import free surfer curvature file. void importFreeSurferCurvatureFile(const int numNodes, const QString& filename, const FILE_FORMAT fileFormat = AbstractFile::FILE_FORMAT_ASCII) throw (FileException); /// write the file's memory in caret6 format to the specified name virtual QString writeFileInCaret6Format(const QString& filenameIn, Structure structure,const ColorFile* colorFileIn, const bool useCaret6ExtensionFlag) throw (FileException); }; #endif // __VE_SURFACE_SHAPE_FILE_H__ #ifdef _SURFACE_SHAPE_MAIN_ const QString SurfaceShapeFile::arealDistortionColumnName = "Areal Distortion"; const QString SurfaceShapeFile::gaussianCurvatureColumnName = "Gaussian Curvature"; const QString SurfaceShapeFile::linearDistortionColumnName = "Linear Distortion"; const QString SurfaceShapeFile::meanCurvatureColumnName = "Folding (Mean Curvature)"; const QString SurfaceShapeFile::sulcalDepthColumnName = "Depth"; const QString SurfaceShapeFile::sulcalDepthSmoothedColumnName = "Depth Smoothed"; #endif // _SURFACE_SHAPE_MAIN_ caret-5.6.4~dfsg.1.orig/caret_files/SurfaceShapeFile.cxx0000664000175000017500000001332711572067322022744 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #define _SURFACE_SHAPE_MAIN_ #include "SurfaceShapeFile.h" #undef _SURFACE_SHAPE_MAIN_ #include "CoordinateFile.h" #include "FileUtilities.h" #include "FreeSurferCurvatureFile.h" #include "GiftiCommon.h" #include "SpecFile.h" /** * Constructor */ SurfaceShapeFile::SurfaceShapeFile() : MetricFile("Surface Shape File", GiftiCommon::intentShape, SpecFile::getSurfaceShapeFileExtension()) { } /** * Destructor */ SurfaceShapeFile::~SurfaceShapeFile() { } /** * Find column containing areal distortion */ int SurfaceShapeFile::getArealDistortionColumnNumber() const { return getNamedColumnNumber(arealDistortionColumnName); } /** * Find column containing gaussian curvature */ int SurfaceShapeFile::getGaussianCurvatureColumnNumber() const { return getNamedColumnNumber(gaussianCurvatureColumnName); } /** * Find column containing linear distortion */ int SurfaceShapeFile::getLinearDistortionColumnNumber() const { return getNamedColumnNumber(linearDistortionColumnName); } /** * Find column containing mean curvature */ int SurfaceShapeFile::getMeanCurvatureColumnNumber() const { return getNamedColumnNumber(meanCurvatureColumnName); } /** * Find column containing sulcal depth */ int SurfaceShapeFile::getSulcalDepthColumnNumber() const { return getNamedColumnNumber(sulcalDepthColumnName); } /** * Find column containing smoothed sulcal depth */ int SurfaceShapeFile::getSulcalDepthSmoothedColumnNumber() const { return getNamedColumnNumber(sulcalDepthSmoothedColumnName); } /** * Export free surfer ascii curvature file. */ void SurfaceShapeFile::exportFreeSurferAsciiCurvatureFile(const int columnNumber, const CoordinateFile* cf, const QString& filename) throw (FileException) { if ((columnNumber >= 0) && (columnNumber < getNumberOfColumns())) { const int numNodes = getNumberOfNodes(); FreeSurferCurvatureFile fscl; fscl.setNumberOfVertices(numNodes); for (int i = 0; i < numNodes; i++) { float xyz[3]; cf->getCoordinate(i, xyz); fscl.setCurvature(i, xyz, -getValue(i, columnNumber)); } fscl.writeFile(filename); } else { throw FileException(filename, "Invalid surface shape column selected for export."); } } /** * Import free surfer curvature file. */ void SurfaceShapeFile::importFreeSurferCurvatureFile(const int numNodes, const QString& filename, const FILE_FORMAT fileFormat) throw (FileException) { if (numNodes == 0) { throw FileException(filename, "Number of nodes must be set prior to importing a \n" "FreeSurfer curvature file. This is usually\n" "accomplished by importing an \"orig\" surface prior\n" "to importing curvature data."); } // // Add a column to this surface shape file // if (getNumberOfColumns() == 0) { setNumberOfNodesAndColumns(numNodes, 1); } else { addColumns(1); } const int columnNumber = getNumberOfColumns() - 1; // // Set the name of the column to the name of the curvature file // setColumnName(columnNumber, FileUtilities::basename(filename)); setModified(); // // Read the curvature file // FreeSurferCurvatureFile fscf; fscf.setFileReadType(fileFormat); fscf.readFile(filename); // // File must have same number of nodes as surface // const int numItems = fscf.getNumberOfVertices(); if (numItems != numNodes) { throw FileException(filename, "Has different number of nodes than currently loaded surface."); } // // Read until end of file // float xyz[3], curve; for (int i = 0; i < numItems; i++) { fscf.getCurvature(i, xyz, curve); setValue(i, columnNumber, -curve); } // // Set the minimum and maximum for color mapping // float minValue, maxValue; getDataColumnMinMax(columnNumber, minValue, maxValue); setColumnColorMappingMinMax(columnNumber, minValue, maxValue); appendToFileComment(" Imported from "); appendToFileComment(FileUtilities::basename(filename)); } /** * Write the file's memory in caret6 format to the specified name. */ QString SurfaceShapeFile::writeFileInCaret6Format(const QString& filenameIn, Structure structure,const ColorFile* colorFileIn, const bool useCaret6ExtensionFlag) throw (FileException) { QString name = filenameIn; if (useCaret6ExtensionFlag) { name = FileUtilities::replaceExtension(filenameIn, ".surface_shape", SpecFile::getGiftiShapeFileExtension()); } this->setFileWriteType(AbstractFile::FILE_FORMAT_XML_GZIP_BASE64); this->writeFile(name); return name; } caret-5.6.4~dfsg.1.orig/caret_files/SurfaceFile.h0000664000175000017500000000705611572067322021412 0ustar michaelmichael #ifndef __SURFACE_FILE_H__ #define __SURFACE_FILE_H__ #include "GiftiDataArrayFile.h" /// class for storing a surface of coordinates, normals, and triangles class SurfaceFile : public GiftiDataArrayFile { public: // constructor SurfaceFile(); // constructor SurfaceFile(const int numberOfCoordinates, const int numberOfTriangles); // copy constructor SurfaceFile(const SurfaceFile& sf); // destructor virtual ~SurfaceFile(); // assignment operator SurfaceFile& operator=(const SurfaceFile& sf); // clear the file void clear(); // get the number of coordinates int getNumberOfCoordinates() const; // set the number of coordinates void setNumberOfCoordinates(const int num); // get the number of triangles int getNumberOfTriangles() const; // set the number of triangles void setNumberOfTriangles(const int num); // get a coordinate (pointer to coordinates x/y/z) const float* getCoordinate(const int indx) const; // set a coordinate void setCoordinate(const int indx, const float xyz[3]); // set a coordinate void setCoordinate(const int indx, const float x, const float y, const float z); // get a triangles coordinate indices (3) const int32_t* getTriangle(const int indx) const; // set a triangle void setTriangle(const int indx, const int vertices[3]); // set a triangle void setTriangle(const int indx, const int v1, const int v2, const int v3); /// get the type of coordinates QString getCoordinateType() const; // set the type of coordinates void setCoordinateType(const QString& t); /// get the type of topology QString getTopologyType() const; // set the type of topology void setTopologyType(const QString& t); // get the coordinate metadata (NULL If invalid) const method const GiftiMetaData* getCoordinateMetaData() const; // get the topology metadata (NULL If invalid) const method const GiftiMetaData* getTopologyMetaData() const; // get the coordinate metadata (NULL If invalid) GiftiMetaData* getCoordinateMetaData(); // get the topology metadata (NULL If invalid) GiftiMetaData* getTopologyMetaData(); // convert configuration ID to spec file tag static QString convertConfigurationIDToSpecFileTag(const QString& configID); /// Update the file's metadata for Caret6 virtual void updateMetaDataForCaret6(); /// write the file's memory in caret6 format to the specified name virtual QString writeFileInCaret6Format(const QString& filenameIn, Structure structure,const ColorFile* colorFileIn, const bool useCaret6ExtensionFlag) throw (FileException); protected: // the copy helper used by copy constructor and assignement operator void copyHelperSurface(const SurfaceFile& sf); // read file void readLegacyFileData(QFile& file, QTextStream& stream, QDataStream& binStream) throw (FileException); // write file void writeLegacyFileData(QTextStream& stream, QDataStream& binStream) throw (FileException); // // IF ANY MORE MEMBERS ADDED UPDATE CopyHelperSurface // }; #endif // __SURFACE_FILE_H__ caret-5.6.4~dfsg.1.orig/caret_files/SurfaceFile.cxx0000664000175000017500000003357111572067322021766 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "FileUtilities.h" #include "GiftiCommon.h" #include "GiftiDataArray.h" #include "SpecFile.h" #include "StringUtilities.h" #include "SurfaceFile.h" /** * constructor */ SurfaceFile::SurfaceFile() : GiftiDataArrayFile("Surface File", GiftiCommon::intentCoordinates, GiftiDataArray::DATA_TYPE_FLOAT32, SpecFile::getGiftiSurfaceFileExtension(), FILE_FORMAT_XML, FILE_IO_NONE, FILE_IO_NONE, FILE_IO_NONE, FILE_IO_NONE, false) { clear(); } /** * constructor */ SurfaceFile::SurfaceFile(const int numberOfCoordinates, const int numberOfTriangles) { clear(); setNumberOfCoordinates(numberOfCoordinates); setNumberOfTriangles(numberOfTriangles); setModified(); } /** * copy constructor */ SurfaceFile::SurfaceFile(const SurfaceFile& sf) : GiftiDataArrayFile(sf) { copyHelperSurface(sf); } /** * destructor */ SurfaceFile::~SurfaceFile() { clear(); } /** * assignment operator */ SurfaceFile& SurfaceFile::operator=(const SurfaceFile& sf) { if (&sf != this) { GiftiDataArrayFile::operator=(sf); copyHelperSurface(sf); } return *this; } /** * the copy helper used by copy constructor and assignement operator. */ void SurfaceFile::copyHelperSurface(const SurfaceFile& /*sf*/) { setFileName(""); setModified(); } /** * clear the file */ void SurfaceFile::clear() { GiftiDataArrayFile::clear(); } /** * get the number of coordinates */ int SurfaceFile::getNumberOfCoordinates() const { const GiftiDataArray* gda = getDataArrayWithIntent(GiftiCommon::intentCoordinates); if (gda != NULL) { if (gda->getNumberOfDimensions() > 0) { return gda->getDimension(0); } } return 0; } /** * set the number of coordinates */ void SurfaceFile::setNumberOfCoordinates(const int num) { // // Dimensions of coordinates // std::vector dim; dim.push_back(num); dim.push_back(3); // // Find the coordinates category // GiftiDataArray* coordsArray = getDataArrayWithIntent(GiftiCommon::intentCoordinates); if (coordsArray != NULL) { coordsArray->setDimensions(dim); } else { // // Create coordinates category // coordsArray = new GiftiDataArray(this, GiftiCommon::intentCoordinates, GiftiDataArray::DATA_TYPE_FLOAT32, dim); addDataArray(coordsArray); } setModified(); } /** * get the number of triangles */ int SurfaceFile::getNumberOfTriangles() const { const GiftiDataArray* gda = getDataArrayWithIntent(GiftiCommon::intentTopologyTriangles); if (gda != NULL) { if (gda->getNumberOfDimensions() > 0) { return gda->getDimension(0); } } return 0; } /** * set the number of triangles */ void SurfaceFile::setNumberOfTriangles(const int num) { // // Dimensions of triangles // std::vector dim; dim.push_back(num); dim.push_back(3); // // Find the triangles category // GiftiDataArray* trianglesArray =getDataArrayWithIntent(GiftiCommon::intentTopologyTriangles); if (trianglesArray != NULL) { trianglesArray->setDimensions(dim); } else { // // Create coordinates category // trianglesArray = new GiftiDataArray(this, GiftiCommon::intentTopologyTriangles, GiftiDataArray::DATA_TYPE_INT32, dim); addDataArray(trianglesArray); } setModified(); } /** * get a coordinate (pointer to coordinates x/y/z) */ const float* SurfaceFile::getCoordinate(const int indx) const { const GiftiDataArray* coordsArray = getDataArrayWithIntent(GiftiCommon::intentCoordinates); if (coordsArray != NULL) { const int indices[2] = { indx, 0 }; return coordsArray->getDataFloat32Pointer(indices); } return NULL; } /** * set a coordinate */ void SurfaceFile::setCoordinate(const int indx, const float xyz[3]) { const GiftiDataArray* coordsArray = getDataArrayWithIntent(GiftiCommon::intentCoordinates); if (coordsArray != NULL) { for (int i = 0; i < 3; i++) { const int indices[2] = { indx, i }; coordsArray->setDataFloat32(indices, xyz[i]); } setModified(); } } /** * set a coordinate */ void SurfaceFile::setCoordinate(const int indx, const float x, const float y, const float z) { const float xyz[3] = { x, y, z }; setCoordinate(indx, xyz); } /** * get a triangles coordinate indices (3) */ const int32_t* SurfaceFile::getTriangle(const int indx) const { const GiftiDataArray* coordsArray = getDataArrayWithIntent(GiftiCommon::intentTopologyTriangles); if (coordsArray != NULL) { const int indices[2] = { indx, 0 }; return coordsArray->getDataInt32Pointer(indices); } return NULL; } /** * set a triangle */ void SurfaceFile::setTriangle(const int indx, const int vertices[3]) { const GiftiDataArray* topoArray = getDataArrayWithIntent(GiftiCommon::intentTopologyTriangles); if (topoArray != NULL) { for (int i = 0; i < 3; i++) { const int32_t indices[2] = { indx, i }; topoArray->setDataInt32(indices, vertices[i]); } setModified(); } } /** * set a triangle */ void SurfaceFile::setTriangle(const int indx, const int v1, const int v2, const int v3) { const int v[3] = { v1, v2, v3 }; setTriangle(indx, v); } /** * get the type of topology. */ QString SurfaceFile::getTopologyType() const { const GiftiDataArray* topoArray = getDataArrayWithIntent(GiftiCommon::intentTopologyTriangles); if (topoArray != NULL) { const GiftiMetaData* md = topoArray->getMetaData(); QString topoTypeString; if (md->get(AbstractFile::headerTagPerimeterID, topoTypeString)) { return topoTypeString; } } return "UNKNOWN"; } /** * set the type of topology. */ void SurfaceFile::setTopologyType(const QString& t) { GiftiDataArray* topoArray = getDataArrayWithIntent(GiftiCommon::intentTopologyTriangles); if (topoArray != NULL) { GiftiMetaData* md = topoArray->getMetaData(); QString topoTypeString; md->set(AbstractFile::headerTagPerimeterID, t); setModified(); } } /** * get the type of coordinates. */ QString SurfaceFile::getCoordinateType() const { const GiftiDataArray* coordsArray = getDataArrayWithIntent(GiftiCommon::intentCoordinates); if (coordsArray != NULL) { const GiftiMetaData* md = coordsArray->getMetaData(); QString coordTypeString; if (md->get(AbstractFile::headerTagConfigurationID, coordTypeString)) { coordTypeString = StringUtilities::makeUpperCase(coordTypeString); return coordTypeString; } } return "UNKNOWN"; } /** * set the type of coordinates. */ void SurfaceFile::setCoordinateType(const QString& t) { GiftiDataArray* coordsArray = getDataArrayWithIntent(GiftiCommon::intentCoordinates); if (coordsArray != NULL) { GiftiMetaData* md = coordsArray->getMetaData(); md->set(AbstractFile::headerTagConfigurationID, t); setModified(); } } /** * read file. */ void SurfaceFile::readLegacyFileData(QFile& /*file*/, QTextStream& /*stream*/, QDataStream& /*binStream*/) throw (FileException) { throw FileException("Legacy files not supported for SurfaceFile."); } /** * write file. */ void SurfaceFile::writeLegacyFileData(QTextStream& /*stream*/, QDataStream& /*binStream*/) throw (FileException) { throw FileException("Legacy files not supported for SurfaceFile."); } /** * get the coordinate metadata (NULL If invalid) const method. */ const GiftiMetaData* SurfaceFile::getCoordinateMetaData() const { const GiftiDataArray* coordsArray = getDataArrayWithIntent(GiftiCommon::intentCoordinates); if (coordsArray != NULL) { return coordsArray->getMetaData(); } return NULL; } /** * get the topology metadata (NULL If invalid) const method. */ const GiftiMetaData* SurfaceFile::getTopologyMetaData() const { const GiftiDataArray* topoArray = getDataArrayWithIntent(GiftiCommon::intentTopologyTriangles); if (topoArray != NULL) { return topoArray->getMetaData(); } return NULL; } /** * get the coordinate metadata (NULL If invalid). */ GiftiMetaData* SurfaceFile::getCoordinateMetaData() { GiftiDataArray* coordsArray = getDataArrayWithIntent(GiftiCommon::intentCoordinates); if (coordsArray != NULL) { return coordsArray->getMetaData(); } return NULL; } /** * get the topology metadata (NULL If invalid). */ GiftiMetaData* SurfaceFile::getTopologyMetaData() { GiftiDataArray* topoArray = getDataArrayWithIntent(GiftiCommon::intentTopologyTriangles); if (topoArray != NULL) { return topoArray->getMetaData(); } return NULL; } /** * convert configuration ID to spec file tag. */ QString SurfaceFile::convertConfigurationIDToSpecFileTag(const QString& nameIn) { const QString name(nameIn.toUpper()); if (name == "RAW") return SpecFile::getRawSurfaceFileTag(); else if (name == "FIDUCIAL") return SpecFile::getFiducialSurfaceFileTag(); else if (name == "INFLATED") return SpecFile::getInflatedSurfaceFileTag(); else if (name == "VERY_INFLATED") return SpecFile::getVeryInflatedSurfaceFileTag(); else if (name == "SPHERICAL") return SpecFile::getSphericalSurfaceFileTag(); else if (name == "ELLIPSOIDAL") return SpecFile::getEllipsoidSurfaceFileTag(); else if (name == "CMW") return SpecFile::getCompressedSurfaceFileTag(); else if (name == "FLAT") return SpecFile::getFlatSurfaceFileTag(); else if (name == "FLAT_LOBAR") return SpecFile::getLobarFlatSurfaceFileTag(); else if (name == "HULL") return SpecFile::getHullSurfaceFileTag(); else return SpecFile::getUnknownSurfaceFileMatchTag(); } /** * Update the file's metadata for Caret6. */ void SurfaceFile::updateMetaDataForCaret6() { AbstractFile::updateMetaDataForCaret6(); //this->removeHeaderTag("topo_file"); /* switch (this->getTopologyType()) { case TOPOLOGY_TYPE_CLOSED: this->setHeaderTag(GiftiCommon::metaDataNameTopologicalType, "Closed"); break; case TOPOLOGY_TYPE_OPEN: this->setHeaderTag(GiftiCommon::metaDataNameTopologicalType, "Open"); break; case TOPOLOGY_TYPE_CUT: this->setHeaderTag(GiftiCommon::metaDataNameTopologicalType, "Cut"); break; case TOPOLOGY_TYPE_LOBAR_CUT: this->setHeaderTag(GiftiCommon::metaDataNameTopologicalType, "Cut"); break; case TOPOLOGY_TYPE_UNKNOWN: case TOPOLOGY_TYPE_UNSPECIFIED: this->setHeaderTag(GiftiCommon::metaDataNameTopologicalType, "Closed"); break; } this->removeHeaderTag("perimeter_id"); */ } /** * Write the file's memory in caret6 format to the specified name. */ QString SurfaceFile::writeFileInCaret6Format(const QString& filenameIn, Structure structure,const ColorFile* colorFileIn, const bool useCaret6ExtensionFlag) throw (FileException) { /* GiftiDataArray* coordsArray = getDataArrayWithIntent(GiftiCommon::intentCoordinates); if (coordsArray != NULL) { GiftiMetaData* coordMetaData = coordsArray->getMetaData(); Structure myStructure; QString myStructureName; if (coordMetaData->get(AbstractFile::headerTagStructure, myStructureName)) { myStructure.setTypeFromString(myStructureName); }; if (structure != Structure::STRUCTURE_TYPE_INVALID) { myStructure = structure; } myStructureName = "Unknown"; switch (myStructure.getType()) { case Structure::STRUCTURE_TYPE_CORTEX_LEFT: myStructureName = "CortexLeft"; break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT: myStructureName = "CortexRight"; break; case Structure::STRUCTURE_TYPE_CEREBELLUM: myStructureName = "Cerebellum"; break; } coordMetaData->set("AnatomicalStructurePrimary", myStructureName); coordMetaData->set("AnatomicalStructureSecondary", "MidLayer"); coordMetaData->remove("Caret-Version"); coordMetaData->remove("Date"); coordMetaData->remove("UserName"); } GiftiDataArray* topoArray = getDataArrayWithIntent(GiftiCommon::intentTopologyTriangles); if (topoArray != NULL) { } */ QString name = filenameIn; if (useCaret6ExtensionFlag) { name = FileUtilities::replaceExtension(filenameIn, ".surface", SpecFile::getGiftiSurfaceFileExtension()); } this->setFileWriteType(AbstractFile::FILE_FORMAT_XML_GZIP_BASE64); this->writeFile(name); return name; } caret-5.6.4~dfsg.1.orig/caret_files/SureFitVectorFile.h0000664000175000017500000001271111572067322022560 0ustar michaelmichael #ifndef __SUREFIT_VECTOR_FILE_H__ #define __SUREFIT_VECTOR_FILE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "AbstractFile.h" #include "FileException.h" class VolumeFile; /// class for storing vectors class SureFitVectorFile : public AbstractFile { public: /// Combine with volume operations enum COMBINE_VOLUME_OPERATION { COMBINE_VOLUME_REPLACE_MAGNITUDE_WITH_VOLUME, COMBINE_VOLUME_MULTIPLY_MAGNITUDE_WITH_VOLUME }; /// combine operations enum COMBINE_OPERATION { COMBINE_OPERATION_DOT_SQRT_RECT_MINUS, // was 1 COMBINE_OPERATION_2_VEC_NORMAL, // was 2 COMBINE_OPERATION_2_VEC // was 3 }; /// Constructor SureFitVectorFile(const int xdim, const int ydim, const int zdim); /// Constructor SureFitVectorFile(); /// Destructor ~SureFitVectorFile(); /// clear the file void clear(); /// Initialize the file to specified size with all zero values. void initialize(const int xdim, const int ydim, const int zdim); /// returns true if the file is isEmpty (contains no data) bool empty() const; /// get the dimensions void getDimensions(int dim[3]) const; /// get the dimensions void getDimensions(int& dimX, int& dimY, int& dimZ) const; /// get a vector void getVector(const int i, const int j, const int k, float vector[3]) const; /// get magnitude float getMagnitude(const int i, const int j, const int k) const; /// get a vector void getVectorWithFlatIndex(const int indx, float& xOut, float& yOut, float& zOut) const; /// get a vector void getVectorWithFlatIndex(const int indx, float xyzOut[3]) const; /// get a magnitude float getMagnitudeWithFlatIndex(const int indx) const { return magnitude[indx]; } /// set a vector void setVectorWithFlatIndex(const int indx, const float xIn, const float yIn, const float zIn); /// set a vector void setVectorWithFlatIndex(const int indx, float xyzIn[3]); /// set a magnitude void setMagnitudeWithFlatIndex(const int indx, const float mag) { magnitude[indx] = mag; } /// get a pointer to the X data float* getWithFlatIndexValueX(const int indx); /// get a pointer to the Y data float* getWithFlatIndexValueY(const int indx); /// get a pointer to the Z data float* getWithFlatIndexValueZ(const int indx); /// combine a volume with this file's magnitude void combineWithVolumeOperation(const COMBINE_VOLUME_OPERATION operation, const VolumeFile* vf) throw (FileException); /// copy magnitude to a volume's voxels (assumes volume properly allocated) void copyMagnitudeToVolume(VolumeFile* vf) const throw (FileException); /// Combine vector files static void combineVectorFiles (const bool maskingFlag, const COMBINE_OPERATION operation, SureFitVectorFile* vec1, const SureFitVectorFile* vec2, const VolumeFile* maskVolume, SureFitVectorFile* out) throw (FileException); /// multiply x,y,z by magnitude void multiplyXYZByMagnitude(); protected: /// read the file's data (header has already been read) void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException); /// Write the file's data (header has already been written) void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException); /// get data index int getDataIndex(const int ijk[3]) const; /// get flat data int getDataIndex(const int i, const int j, const int k) const; /// dimensions of vector file int dimensions[3]; /// x-vector component std::vector x; /// y-vector component std::vector y; /// z-vector component std::vector z; /// magnitude std::vector magnitude; /// number of elements int numElements; }; #endif // __SUREFIT_VECTOR_FILE_H__ caret-5.6.4~dfsg.1.orig/caret_files/SureFitVectorFile.cxx0000664000175000017500000004360311572067322023137 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "DebugControl.h" #include "SpecFile.h" #include "SureFitVectorFile.h" #include "VolumeFile.h" #include "vtkMath.h" /** * Constructor. */ SureFitVectorFile::SureFitVectorFile(const int xdim, const int ydim, const int zdim) : AbstractFile("Vector File", SpecFile::getSureFitVectorFileExtension(), true, AbstractFile::FILE_FORMAT_BINARY, FILE_IO_READ_AND_WRITE, FILE_IO_READ_AND_WRITE, FILE_IO_NONE, FILE_IO_NONE) { initialize(xdim, ydim, zdim); } /** * Constructor. */ SureFitVectorFile::SureFitVectorFile() : AbstractFile("Vector File", SpecFile::getSureFitVectorFileExtension(), true, AbstractFile::FILE_FORMAT_BINARY, FILE_IO_READ_AND_WRITE, FILE_IO_READ_AND_WRITE, FILE_IO_NONE, FILE_IO_NONE) { initialize(0, 0, 0); } /** * Destructor. */ SureFitVectorFile::~SureFitVectorFile() { clear(); } /** * Initialize the file to specified size with all zero values. */ void SureFitVectorFile::initialize(const int xdim, const int ydim, const int zdim) { dimensions[0] = xdim; dimensions[1] = ydim; dimensions[2] = zdim; x.clear(); y.clear(); z.clear(); magnitude.clear(); numElements = xdim * ydim * zdim; if (numElements > 0) { x.resize(numElements, 0.0); y.resize(numElements, 0.0); z.resize(numElements, 0.0); magnitude.resize(numElements, 0.0); } } /** * clear the file. */ void SureFitVectorFile::clear() { clearAbstractFile(); x.clear(); y.clear(); z.clear(); magnitude.clear(); } /** * returns true if the file is isEmpty (contains no data). */ bool SureFitVectorFile::empty() const { return x.empty(); } /** * get the dimensions. */ void SureFitVectorFile::getDimensions(int dim[3]) const { dim[0] = dimensions[0]; dim[1] = dimensions[1]; dim[2] = dimensions[2]; } /** * get the dimensions. */ void SureFitVectorFile::getDimensions(int& dimX, int& dimY, int& dimZ) const { dimX = dimensions[0]; dimY = dimensions[1]; dimZ = dimensions[2]; } /** * get a vector. */ void SureFitVectorFile::getVectorWithFlatIndex(const int indx, float& xOut, float& yOut, float& zOut) const { xOut = x[indx]; yOut = y[indx]; zOut = z[indx]; } /** * get a vector. */ void SureFitVectorFile::getVectorWithFlatIndex(const int indx, float xyzOut[3]) const { xyzOut[0] = x[indx]; xyzOut[1] = y[indx]; xyzOut[2] = z[indx]; } /** * set a vector. */ void SureFitVectorFile::setVectorWithFlatIndex(const int indx, const float xIn, const float yIn, const float zIn) { x[indx] = xIn; y[indx] = yIn; z[indx] = zIn; } /** * set a vector. */ void SureFitVectorFile::setVectorWithFlatIndex(const int indx, float xyzIn[3]) { x[indx] = xyzIn[0]; y[indx] = xyzIn[1]; z[indx] = xyzIn[2]; } /** * combine a volume with this file's magnitude. */ void SureFitVectorFile::combineWithVolumeOperation(const COMBINE_VOLUME_OPERATION operation, const VolumeFile* vf) throw (FileException) { int volDim[3]; vf->getDimensions(volDim); for (int i = 0; i < 3; i++) { if (volDim[i] != dimensions[i]) { throw FileException( "Volume and Vector File dimensions do not match in VectorFile::combineWithVolumeOperation"); } } const int num = dimensions[0] * dimensions[1] * dimensions[2]; for (int i = 0; i < num; i++) { float value = 0.0; const float voxel = vf->getVoxelWithFlatIndex(i); switch (operation) { case COMBINE_VOLUME_REPLACE_MAGNITUDE_WITH_VOLUME: value = voxel; break; case COMBINE_VOLUME_MULTIPLY_MAGNITUDE_WITH_VOLUME: value = voxel * magnitude[i]; break; } magnitude[i] = value; } } /** * copy magnitude to a volume's voxels (assumes volume properly allocated). */ void SureFitVectorFile::copyMagnitudeToVolume(VolumeFile* vf) const throw (FileException) { int volDim[3]; vf->getDimensions(volDim); for (int i = 0; i < 3; i++) { if (volDim[i] != dimensions[i]) { throw FileException( "Volume and Vector File dimensions do not match in VectorFile::copyMagnitudeToVolume"); } } const int num = dimensions[0] * dimensions[1] * dimensions[2]; for (int i = 0; i < num; i++) { vf->setVoxelWithFlatIndex(i, 0, magnitude[i]); } } /** * Combine vector files */ void SureFitVectorFile::combineVectorFiles (const bool maskingFlag, const COMBINE_OPERATION operation, SureFitVectorFile* vec1, const SureFitVectorFile* vec2, const VolumeFile* maskVolume, SureFitVectorFile* out) throw (FileException) { int dim2[3]; vec2->getDimensions(dim2); int dim[3]; vec1->getDimensions(dim); int outDim[3]; out->getDimensions(outDim); for (int i = 0; i < 3; i++) { if ((dim2[i] != dim[i]) || (dim2[i] != outDim[i])) { throw FileException( "Vector File dimensions do not match in VectorFile::combineVectorFiles"); } } const int num = dim[0] * dim[1] * dim[2]; out->initialize(dim[0], dim[1], dim[2]); switch (operation) { case COMBINE_OPERATION_DOT_SQRT_RECT_MINUS: // dotsqrtrectminus_secondnormal for (int i = 0; i < num; i++) { vec1->magnitude[i] *= -1; } for (int i = 0; i < num; i++) { if (DebugControl::getDebugOn()) { if ((i % 1000000) == 0) { std::cout << "\t" << i << " of " << num << ": " << 100.0*((float)i/(float)(num)) << std::endl; } } if (((maskingFlag) && (maskVolume->getVoxelWithFlatIndex(i) != 0)) || (maskingFlag == false)){ float vector1[3], vector2[3]; vector1[0] = vec1->x[i] * vec1->magnitude[i]; vector1[1] = vec1->y[i] * vec1->magnitude[i]; vector1[2] = vec1->z[i] * vec1->magnitude[i]; vector2[0] = vec2->x[i] * vec2->magnitude[i]; vector2[1] = vec2->y[i] * vec2->magnitude[i]; vector2[2] = vec2->z[i] * vec2->magnitude[i]; out->magnitude[i] = vtkMath::Dot(vector1, vector2); out->magnitude[i] = std::max(out->magnitude[i], 0.0f); out->magnitude[i] = sqrt(out->magnitude[i]); } else { out->magnitude[i] = 0.0; } } for (int i = 0; i < num; i++) { if (DebugControl::getDebugOn()) { if ((i % 1000000) == 0) { std::cout << "\t" << i << " of " << num << ": " << 100.0*((float)i/(float)(num)) << std::endl; } } if (((maskingFlag) && (maskVolume->getVoxelWithFlatIndex(i) != 0)) || (maskingFlag == false)){ // HAD 7.14.99 Changed via DVE instructions out->x[i] = vec2->x[i]; out->y[i] = vec2->y[i]; out->z[i] = vec2->z[i]; }else{ out->x[i] = 0.0; out->y[i] = 0.0; out->z[i] = 0.0; } } break; case COMBINE_OPERATION_2_VEC_NORMAL: // 2vec_secondnormal for (int i = 0; i < num; i++){ if (DebugControl::getDebugOn()) { if ((i % 1000000) == 0) { std::cout << "\t" << i << " of " << num << ": " << 100.0*((float)i/(float)(num)) << std::endl; } } if (((maskingFlag) && (maskVolume->getVoxelWithFlatIndex(i) != 0)) || (maskingFlag == false)){ float vector1[3], vector2[3]; vector1[0] = vec1->x[i]; vector1[1] = vec1->y[i]; vector1[2] = vec1->z[i]; vector2[0] = vec2->x[i]; vector2[1] = vec2->y[i]; vector2[2] = vec2->z[i]; // HAD 7.14.99 Changed via DVE instructions if (vec1->magnitude[i] > vec2->magnitude[i]) out->magnitude[i] = vec1->magnitude[i]; else out->magnitude[i] = vec2->magnitude[i]; out->x[i] = vec2->x[i]; out->y[i] = vec2->y[i]; out->z[i] = vec2->z[i]; } } break; case COMBINE_OPERATION_2_VEC: // 2vec for (int i = 0; i < num; i++) { if (DebugControl::getDebugOn()) { if ((i % 1000000) == 0) { std::cout << "\t" << i << " of " << num << ": " << 100.0*((float)i/(float)(num)) << std::endl; } } if (((maskingFlag) && (maskVolume->getVoxelWithFlatIndex(i) != 0)) || (maskingFlag == false)){ float vector1[3], vector2[3]; vector1[0] = vec1->x[i]; vector1[1] = vec1->y[i]; vector1[2] = vec1->z[i]; vector2[0] = vec2->x[i]; vector2[1] = vec2->y[i]; vector2[2] = vec2->z[i]; const float mag1 = vtkMath::Norm(vector1); const float mag2 = vtkMath::Norm(vector2); if (vec1->magnitude[i] > vec2->magnitude[i]) { out->magnitude[i] = vec1->magnitude[i]; out->x[i] = vec1->x[i]; out->y[i] = vec1->y[i]; out->z[i] = vec1->z[i]; } else { out->magnitude[i] = vec2->magnitude[i]; out->x[i] = vec2->x[i]; out->y[i] = vec2->y[i]; out->z[i] = vec2->z[i]; const float temp = vtkMath::Dot(vector1, vector2); float tempAbs = temp; if (tempAbs < 0.0) { tempAbs = -tempAbs; } const float temp2 = temp / tempAbs; out->x[i] *= temp2; out->y[i] *= temp2; out->z[i] *= temp2; } if (mag1 == 0.0){ out->x[i] = vec2->x[i]; out->y[i] = vec2->y[i]; out->z[i] = vec2->z[i]; } if (mag2 == 0.0){ out->x[i] = vec1->x[i]; out->y[i] = vec1->y[i]; out->z[i] = vec1->z[i]; } } } break; } } /** * multiply x,y,z by magnitude. */ void SureFitVectorFile::multiplyXYZByMagnitude() { const int num = dimensions[0] * dimensions[1] * dimensions[2]; for (int i = 0; i < num; i++) { x[i] *= magnitude[i]; y[i] *= magnitude[i]; z[i] *= magnitude[i]; } } /** * get a pointer to the X data. */ float* SureFitVectorFile::getWithFlatIndexValueX(const int indx) { return &x[indx]; } /** * get a pointer to the Y data. */ float* SureFitVectorFile::getWithFlatIndexValueY(const int indx) { return &y[indx]; } /** * get a pointer to the Z data. */ float* SureFitVectorFile::getWithFlatIndexValueZ(const int indx) { return &z[indx]; } /** * get a vector. */ void SureFitVectorFile::getVector(const int i, const int j, const int k, float vector[3]) const { const int indx = getDataIndex(i, j, k); vector[0] = x[indx]; vector[1] = y[indx]; vector[2] = z[indx]; } /** * get magnitude. */ float SureFitVectorFile::getMagnitude(const int i, const int j, const int k) const { const int indx = getDataIndex(i, j, k); return magnitude[indx]; } /** * get data index. */ int SureFitVectorFile::getDataIndex(const int ijk[3]) const { return getDataIndex(ijk[0], ijk[1], ijk[2]); } /** * get flat data. */ int SureFitVectorFile::getDataIndex(const int i, const int j, const int k) const { const int indx = i + j * dimensions[0] + k * dimensions[0] * dimensions[1]; return indx; } /** * read the file's data (header has already been read). */ void SureFitVectorFile::readFileData(QFile&, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException) { // // Should reading data be skipped ? // if (getReadMetaDataOnlyFlag()) { return; } switch (getFileReadType()) { case FILE_FORMAT_ASCII: { int dim[3]; stream >> dim[0] >> dim[1] >> dim[2]; initialize(dim[0], dim[1], dim[2]); for (int i = 0; i < numElements; i++) { stream >> x[i]; stream >> y[i]; stream >> z[i]; stream >> magnitude[i]; } } break; case FILE_FORMAT_BINARY: { int dim[3]; binStream >> dim[0] >> dim[1] >> dim[2]; initialize(dim[0], dim[1], dim[2]); for (int i = 0; i < numElements; i++) { binStream >> x[i]; } for (int i = 0; i < numElements; i++) { binStream >> y[i]; } for (int i = 0; i < numElements; i++) { binStream >> z[i]; } for (int i = 0; i < numElements; i++) { binStream >> magnitude[i]; } } break; case FILE_FORMAT_XML: throw FileException(filename, "Vector File does not support XML for reading."); break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Vector File does not support \"Other\" for reading."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Comma Separated Value File Format not supported."); break; } } /** * Write the file's data (header has already been written). */ void SureFitVectorFile::writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException) { switch (getFileWriteType()) { case FILE_FORMAT_ASCII: { stream << dimensions[0] << " " << dimensions[1] << " " << dimensions[2] << " " << "\n"; for (int i = 0; i < numElements; i++) { stream << x[i] << " " << y[i] << " " << z[i] << " " << magnitude[i] << "\n"; } } break; case FILE_FORMAT_BINARY: #ifdef QT4_FILE_POS_BUG setBinaryFilePosQT4Bug(); #else // QT4_FILE_POS_BUG // // still a bug in QT 4.2.2 // setBinaryFilePosQT4Bug(); #endif // QT4_FILE_POS_BUG { binStream << dimensions[0] << dimensions[1] << dimensions[2]; for (int i = 0; i < numElements; i++) { binStream << x[i]; } for (int i = 0; i < numElements; i++) { binStream << y[i]; } for (int i = 0; i < numElements; i++) { binStream << z[i]; } for (int i = 0; i < numElements; i++) { binStream << magnitude[i]; } } break; case FILE_FORMAT_XML: throw FileException(filename, "Vector File does not support XML for writing."); break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Vector File does not support \"Other\" for writing."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Comma Separated Value File Format not supported."); break; } } caret-5.6.4~dfsg.1.orig/caret_files/SumsFileListFile.h0000664000175000017500000001603011572067322022375 0ustar michaelmichael #ifndef __SUMS_FILE_LIST_FILE_H__ #define __SUMS_FILE_LIST_FILE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ class QDomElement; class QDomNode; #include "AbstractFile.h" /// Class for storing download info for a file class SumsFileInfo { public: /// file sorting enum SORTING_KEY { SORTING_KEY_DATE, SORTING_KEY_NAME, SORTING_KEY_TYPE }; /// Constructor SumsFileInfo(); /// Constructor ~SumsFileInfo(); /// get the file's name without a path QString getNameWithoutPath() const { return fileNameWithoutPath; } /// set the file's name without a path void setNameWithoutPath(const QString& s); /// get the file's long name QString getNameWithPath() const { return fileNameWithPath; } /// set the file's long name void setNameWithPath(const QString& s) { fileNameWithPath = s; } /// get the file's URL QString getURL() const { return fileURL; } /// set the file's URL void setURL(const QString& s) { fileURL = s; } /// get the file's date QString getDate() const { return fileDate; } /// set the file's date void setDate(const QString& s) { fileDate = s; } /// get the file's comment QString getComment() const { return fileComment; } /// set the file's comment void setComment(const QString& s) { fileComment = s; } /// get validity bool isValid() const; /// get the file's size int getSize() const { return fileSize; } /// set the file's size void setSize(const int s) { fileSize = s; } /// get the file's state QString getState() const { return fileState; } /// set the file's state void setState(const QString& s) { fileState = s; } /// get the file's type name QString getTypeName() const { return fileTypeName; } /// set the file's type name void setTypeName(const QString& s) { fileTypeName = s; } /// get the file's selection status bool getSelected() const { return fileSelected; } /// set the file's selection status void setSelected(const bool s) { fileSelected = s; } /// get the ID QString getID() const { return fileID; } /// set the ID void setID(const QString& idin) { fileID = idin; } /// set the sorting key static void setSortingKey(const SORTING_KEY sk) { sortingKey = sk; } /// Comparison for sorting bool operator<(const SumsFileInfo& sfi) const; protected: /// name of file with path QString fileNameWithPath; /// name of file QString fileNameWithoutPath; /// URL of file QString fileURL; /// date of file QString fileDate; /// comment of file QString fileComment; /// size of the file int fileSize; /// state of the file QString fileState; /// type name of the file QString fileTypeName; /// the SuMS ID QString fileID; /// file selected bool fileSelected; /// sorting key static SORTING_KEY sortingKey; }; /// Class for stroring file listings produced by the SuMS database class SumsFileListFile : public AbstractFile { public: /// file sorting enum SORT_ORDER { SORT_ORDER_DATE, SORT_ORDER_NAME, SORT_ORDER_TYPE }; /// Constructor SumsFileListFile(); /// Destructor ~SumsFileListFile(); /// clear the file void clear(); /// returns true if the file is isEmpty (contains no data) bool empty() const { return sumsFileInfo.empty(); } /// Add a file info to this file. void addSumsFile(const SumsFileInfo& sfi); /// get number of file info's int getNumberOfSumsFiles() const { return sumsFileInfo.size(); } /// get a sums file const SumsFileInfo* getSumsFileInfo(const int index) const; /// get a sums file SumsFileInfo* getSumsFileInfo(const int index); /// See if there is a common subdirectory prefix for all of the files QString getCommonSubdirectoryPrefix() const; /// read the file from a string //void readFileFromString(const QString& s) throw (FileException); /// sort the files void sort(const SORT_ORDER so); /// set the selection status of all files. void setAllFileSelectionStatus(const bool status); /// Remove subdirectory prefix from all files void removeSubdirectoryPrefix(); /// get exclude spec file flag bool getExcludeSpecFileFlag() const { return excludeSpecFileFlag; } /// set exclude spec file flag void setExcludeSpecFileFlag(const bool flag) { excludeSpecFileFlag = flag; } /// Remove paths from all files. void removePathsFromAllFiles(); protected: /// read the file void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException); /// write the file void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException); /// Process the file version. void processFileVersion(QDomElement& elem) throw (FileException); /// Process a file element void processFile(QDomElement& elem) throw (FileException); /// Process a files element void processFiles(QDomElement& elem) throw (FileException); /// info about each file std::vector sumsFileInfo; /// file's version int fileVersion; /// exclude spec file flag bool excludeSpecFileFlag; }; #endif // __SUMS_FILE_LIST_FILE_H__ #ifdef __SUMS_FILE_LIST_FILE_MAIN__ SumsFileInfo::SORTING_KEY SumsFileInfo::sortingKey = SumsFileInfo::SORTING_KEY_TYPE; #endif // __SUMS_FILE_LIST_FILE_MAIN__ caret-5.6.4~dfsg.1.orig/caret_files/SumsFileListFile.cxx0000664000175000017500000003354011572067322022755 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include "DebugControl.h" #include "FileUtilities.h" #include "StringUtilities.h" #define __SUMS_FILE_LIST_FILE_MAIN__ #include "SumsFileListFile.h" #undef __SUMS_FILE_LIST_FILE_MAIN__ /** * Constructor. */ SumsFileListFile::SumsFileListFile() : AbstractFile("Sums File List File", ".sums", true, FILE_FORMAT_XML, FILE_IO_NONE, FILE_IO_NONE, FILE_IO_READ_ONLY, FILE_IO_NONE) { clear(); setRootXmlElementTagName("sums"); } /** * Destructor. */ SumsFileListFile::~SumsFileListFile() { clear(); } /** * clear the file. */ void SumsFileListFile::clear() { clearAbstractFile(); sumsFileInfo.clear(); fileVersion = 1; excludeSpecFileFlag = false; } /** * read the file from a string. */ /* void SumsFileListFile::readFileFromString(const QString& s) throw (FileException) { sumsFileInfo.clear(); // // Place the file contents into a QDomDocument which will parse file. // QString errorMessage; int errorLine = 0, errorColumn = 0; QDomDocument doc("atlas-space-file-document"); if (doc.setContent(s, &errorMessage, &errorLine, &errorColumn) == false) { std::ostringstream str; str << "Error parsing at line " << errorLine << " column " << errorColumn << ". "; str << errorMessage << std::ends; throw FileException("", str.str().c_str()); } // // Traverse the direct children // QDomElement docElem = doc.documentElement(); const QString rootElementNameFound(docElem.tagName()); if (rootElementNameFound != "sums") { QString msg("\nNot an SumsFileListFile. Root element is: "); msg.append(rootElementNameFound); msg.append(".\nRoot element should be: "); msg.append("sums"); throw FileException(filename, msg); } QDomNode node = docElem.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (DebugControl::getDebugOn()) { std::cout << "Tag Name: " << elem.tagName() << std::endl; } if (elem.tagName() == "header") { readHeaderXML(elem); } else if (elem.tagName() == "version") { processFileVersion(elem); } else if (elem.tagName() == "files") { processFiles(elem); } else if (elem.tagName() == "directories") { } else { std::cerr << "SumsFileListFile xml node not recognized \"" << elem.tagName() << "\"" << std::endl; } } node = node.nextSibling(); } // // sort by type // sort(SORT_ORDER_TYPE); } */ /** * Process files tag. */ void SumsFileListFile::processFiles(QDomElement& filesElem) throw (FileException) { QDomNode node = filesElem.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (DebugControl::getDebugOn()) { std::cout << "Tag Name: " << elem.tagName().toAscii().constData() << std::endl; } if ((elem.tagName() == xmlHeaderTagName) || (elem.tagName() == xmlHeaderOldTagName)) { readHeaderXML(elem); } else if (elem.tagName() == "file-version") { processFileVersion(elem); } else if (elem.tagName() == "file") { processFile(elem); } else { std::cerr << "Atlas Space node not recognized in root " << elem.tagName().toAscii().constData() << std::endl; } } node = node.nextSibling(); } } /** * Process the file version. */ void SumsFileListFile::processFileVersion(QDomElement& elem) throw (FileException) { QDomNode vNode = elem.firstChild(); if (vNode.isNull() == false) { QDomText textNode = vNode.toText(); if (textNode.isNull() == false) { fileVersion = StringUtilities::toInt(textNode.data()); } } } /** * Process an atlas space. */ void SumsFileListFile::processFile(QDomElement& elem) throw (FileException) { SumsFileInfo sfi; QDomNode node = elem.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { const QString tagName(elem.tagName()); if (tagName == "comment") { sfi.setComment(getXmlElementFirstChildAsString(elem)); } else if (tagName == "date") { sfi.setDate(getXmlElementFirstChildAsString(elem)); } else if (tagName == "dir_id") { } else if (tagName == "id") { sfi.setID(getXmlElementFirstChildAsString(elem)); } else if (tagName == "location") { sfi.setURL(getXmlElementFirstChildAsString(elem)); } else if (tagName == "name") { sfi.setNameWithPath(getXmlElementFirstChildAsString(elem)); } else if (tagName == "parent_id") { } else if (tagName == "short_name") { sfi.setNameWithoutPath(getXmlElementFirstChildAsString(elem)); } else if (tagName == "size") { sfi.setSize(StringUtilities::toInt(getXmlElementFirstChildAsString(elem))); } else if (tagName == "state") { } else if (tagName == "state_string") { sfi.setState(getXmlElementFirstChildAsString(elem)); } else if (tagName == "status") { } else if (tagName == "user_id") { } else { std::cout << "Unrecognized \"file\" tag (" << tagName.toAscii().constData() << ") for SumsFileListFile " << std::endl; } } node = node.nextSibling(); } if (sfi.isValid()) { if (DebugControl::getDebugOn()) { std::cout << "Have valid file named " << sfi.getNameWithoutPath().toAscii().constData() << "." << std::endl; } // // Exclude spec files if requested // bool addIt = true; if (FileUtilities::filenameExtension(sfi.getNameWithoutPath()) == "spec") { if (excludeSpecFileFlag) { addIt = false; } } if (addIt) { addSumsFile(sfi); } } } /** * Add a file info to this file. */ void SumsFileListFile::addSumsFile(const SumsFileInfo& sfi) { sumsFileInfo.push_back(sfi); } /** * get a sums file (const method) */ const SumsFileInfo* SumsFileListFile::getSumsFileInfo(const int index) const { if ((index >= 0) && (index < getNumberOfSumsFiles())) { return &sumsFileInfo[index]; } return NULL; } /** * get a sums file */ SumsFileInfo* SumsFileListFile::getSumsFileInfo(const int index) { if ((index >= 0) && (index < getNumberOfSumsFiles())) { return &sumsFileInfo[index]; } return NULL; } /** * sort the files. */ void SumsFileListFile::sort(const SORT_ORDER so) { switch (so) { case SORT_ORDER_DATE: SumsFileInfo::setSortingKey(SumsFileInfo::SORTING_KEY_DATE); break; case SORT_ORDER_NAME: SumsFileInfo::setSortingKey(SumsFileInfo::SORTING_KEY_NAME); break; case SORT_ORDER_TYPE: SumsFileInfo::setSortingKey(SumsFileInfo::SORTING_KEY_TYPE); break; } std::sort(sumsFileInfo.begin(), sumsFileInfo.end()); } /** * set the selection status of all files. */ void SumsFileListFile::setAllFileSelectionStatus(const bool status) { const int num = getNumberOfSumsFiles(); for (int i = 0; i < num; i++) { SumsFileInfo* sfi = getSumsFileInfo(i); sfi->setSelected(status); } } /** * See if there is a common subdirectory prefix for all of the files */ QString SumsFileListFile::getCommonSubdirectoryPrefix() const { const int num = getNumberOfSumsFiles(); if (num > 0) { const SumsFileInfo* sfi = getSumsFileInfo(0); const QString prefix(FileUtilities::getSubdirectoryPrefix(sfi->getNameWithPath())); if (prefix.isEmpty() == false) { for (int i = 1; i < num; i++) { const SumsFileInfo* sfi = getSumsFileInfo(i); const QString pf(FileUtilities::getSubdirectoryPrefix(sfi->getNameWithPath())); if (pf != prefix) { return ""; } } return prefix; } } return ""; } /** * Remove paths from all files. */ void SumsFileListFile::removePathsFromAllFiles() { for (int i = 0; i < getNumberOfSumsFiles(); i++) { SumsFileInfo* sfi = getSumsFileInfo(i); sfi->setNameWithPath(sfi->getNameWithoutPath()); } } /** * Remove subdirectory prefix from all files */ void SumsFileListFile::removeSubdirectoryPrefix() { const int num = getNumberOfSumsFiles(); for (int i = 0; i < num; i++) { SumsFileInfo* sfi = getSumsFileInfo(i); QString name(sfi->getNameWithPath()); const int pos = StringUtilities::findFirstOf(name, "/\\"); if (pos != -1) { name = name.mid(pos + 1); sfi->setNameWithPath(name); } } } /** * read the file. */ void SumsFileListFile::readFileData(QFile&, QTextStream& /* stream */, QDataStream&, QDomElement& rootElement) throw (FileException) { sumsFileInfo.clear(); // // Traverse the direct children // const QString rootElementNameFound(rootElement.tagName()); if (rootElementNameFound != "sums") { QString msg("\nNot an SumsFileListFile. Root element is: "); msg.append(rootElementNameFound); msg.append(".\nRoot element should be: "); msg.append("sums"); throw FileException(filename, msg); } QDomNode node = rootElement.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (DebugControl::getDebugOn()) { std::cout << "Tag Name: " << elem.tagName().toAscii().constData() << std::endl; } if ((elem.tagName() == xmlHeaderOldTagName) || (elem.tagName() == xmlHeaderTagName)) { readHeaderXML(elem); } else if (elem.tagName() == "version") { processFileVersion(elem); } else if (elem.tagName() == "files") { processFiles(elem); } else if (elem.tagName() == "directories") { } else { std::cerr << "SumsFileListFile xml node not recognized \"" << elem.tagName().toAscii().constData() << "\"" << std::endl; } } node = node.nextSibling(); } // // sort by type // sort(SORT_ORDER_DATE); /* try { readFileFromString(stream.read()); } catch (FileException& e) { throw FileException(filename, e.what()); } */ } /** * write the file. */ void SumsFileListFile::writeFileData(QTextStream&, QDataStream&, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException) { throw FileException(filename, "Writing SumsFileListFile not supported."); } //--------------------------------------------------------------------------------- /** * Constructor. */ SumsFileInfo::SumsFileInfo() { fileNameWithPath = ""; fileNameWithoutPath = ""; fileURL = ""; fileDate = ""; fileComment = ""; fileID = ""; fileSelected = true; fileSize = 0; fileState = ""; fileTypeName = ""; } /** * Constructor. */ SumsFileInfo::~SumsFileInfo() { } /** * Get valid. */ bool SumsFileInfo::isValid() const { if ((fileNameWithoutPath.isEmpty() == false) && (fileNameWithPath.isEmpty() == false) && (fileURL.isEmpty() == false)) { return true; } return false; } /** * set the file's name. */ void SumsFileInfo::setNameWithoutPath(const QString& s) { fileNameWithoutPath = s; fileTypeName = AbstractFile::getFileTypeNameFromFileName(s); } /** * Comparison for sorting */ bool SumsFileInfo::operator<(const SumsFileInfo& sfi) const { bool result = false; switch (sortingKey) { case SORTING_KEY_DATE: if (fileDate == sfi.fileDate) { if (fileTypeName == sfi.fileTypeName) { result = (fileNameWithoutPath < sfi.fileNameWithoutPath); } else { result = (fileTypeName < sfi.fileTypeName); } } else { result = (fileDate > sfi.fileDate); } break; case SORTING_KEY_NAME: result = (fileNameWithoutPath < sfi.fileNameWithoutPath); break; case SORTING_KEY_TYPE: if (fileTypeName == sfi.fileTypeName) { result = (fileNameWithoutPath < sfi.fileNameWithoutPath); } else { result = (fileTypeName < sfi.fileTypeName); } break; } return result; } caret-5.6.4~dfsg.1.orig/caret_files/StudyNamePubMedID.h0000664000175000017500000000711511572067322022441 0ustar michaelmichael #ifndef __STUDY_NAME_PUBMED_ID_H__ #define __STUDY_NAME_PUBMED_ID_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include class QDomDocument; class QDomElement; class QDomNode; class StudyCollection; class StudyMetaData; /// Study Name and PubMed ID class StudyNamePubMedID { public: // constructor StudyNamePubMedID(); // constructor StudyNamePubMedID(const QString& nameIn, const QString& pubMedIDIn, const QString& mslIDIn); // destructor ~StudyNamePubMedID(); // copy constructor StudyNamePubMedID(const StudyNamePubMedID& as); // assignment operator StudyNamePubMedID& operator=(const StudyNamePubMedID& as); // clear the studies void clear(); /// get the name QString getName() const { return name; } // set the name void setName(const QString& s); /// get the PubMed ID QString getPubMedID() const { return pubMedID; } // set the PubMed ID void setPubMedID(const QString& s); /// get the MSL ID QString getMslID() const { return mslID; } // set the MSL ID void setMslID(const QString& s); // set parent for study metadata void setParent(StudyMetaData* parentIn); // set parent for study collection void setParent(StudyCollection* parentIn); protected: // called to read from an XML structure void readXML(QDomNode& node) throw (FileException); // called to write to an XML structure void writeXML(QDomDocument& xmlDoc, QDomElement& parentElement) const throw (FileException); // called to write XML void writeXML(XmlGenericWriter& xmlWriter) const throw (FileException); /// the study name QString name; /// the PubMed ID QString pubMedID; /// MSL ID QString mslID; // copy helper used by copy constructor and assignment operator void copyHelper(const StudyNamePubMedID& as); // set modified status void setModified(); /// study metadata that is parent of this pubmed ID list (DO NOT COPY) StudyMetaData* parentStudyMetaData; /// study collection that is parent of this pubmed ID list StudyCollection* parentStudyCollection; // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // If additional members are added be sure to update copyHelper() method. // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! friend class StudyCollection; }; #endif // __STUDY_NAME_PUBMED_ID_H__ caret-5.6.4~dfsg.1.orig/caret_files/StudyNamePubMedID.cxx0000664000175000017500000002107011572067322023010 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include "StringTable.h" #include "StudyCollectionFile.h" #include "StudyMetaDataFile.h" #include "StudyNamePubMedID.h" /** * constructor. */ StudyNamePubMedID::StudyNamePubMedID() { clear(); } /** * constructor. */ StudyNamePubMedID::StudyNamePubMedID(const QString& nameIn, const QString& pubMedIDIn, const QString& mslIDIn) { clear(); setName(nameIn); setPubMedID(pubMedIDIn); setMslID(mslIDIn); } /** * destructor. */ StudyNamePubMedID::~StudyNamePubMedID() { clear(); } /** * copy constructor. */ StudyNamePubMedID::StudyNamePubMedID(const StudyNamePubMedID& as) { parentStudyMetaData = NULL; parentStudyCollection = NULL; copyHelper(as); } /** * assignment operator. */ StudyNamePubMedID& StudyNamePubMedID::operator=(const StudyNamePubMedID& as) { if (this != &as) { copyHelper(as); } return *this; } /** * clear the studies. */ void StudyNamePubMedID::clear() { parentStudyMetaData = NULL; parentStudyCollection = NULL; name = ""; pubMedID = ""; mslID = ""; setModified(); } /** * set the name. */ void StudyNamePubMedID::setName(const QString& s) { if (name != s) { name = s; setModified(); } } /** * set the PubMed ID. */ void StudyNamePubMedID::setPubMedID(const QString& s) { if (pubMedID != s) { pubMedID = s; setModified(); } } /** * set the MSL ID. */ void StudyNamePubMedID::setMslID(const QString& s) { if (mslID != s) { mslID = s; setModified(); } } /** * set parent. */ void StudyNamePubMedID::setParent(StudyMetaData* parentIn) { parentStudyMetaData = parentIn; } /** * set parent for study collection. */ void StudyNamePubMedID::setParent(StudyCollection* parentIn) { parentStudyCollection = parentIn; } /** * copy helper used by copy constructor and assignment operator. */ void StudyNamePubMedID::copyHelper(const StudyNamePubMedID& s) { StudyMetaData* savedParentStudyMetaData = parentStudyMetaData; StudyCollection* savedParentStudyCollection = parentStudyCollection; clear(); name = s.name; pubMedID = s.pubMedID; mslID = s.mslID; parentStudyMetaData = savedParentStudyMetaData; parentStudyCollection = savedParentStudyCollection; setModified(); } /** * set modified status. */ void StudyNamePubMedID::setModified() { if (parentStudyMetaData != NULL) { parentStudyMetaData->setModified(); } if (parentStudyCollection != NULL) { parentStudyCollection->setModified(); } } /** * write the data to a string table. * void StudyNamePubMedID::writeDataToStringTable(StringTable& table, const QString& stringTableName) throw (FileException) { table.clear(); const int num = getNumberOfStudies(); if (num <= 0) { return; } int numCols = 0; const int nameColumn = numCols++; const int pmidColumn = numCols++; const int mslidColumn = numCols++; table.setNumberOfRowsAndColumns(num, numCols, stringTableName); table.setColumnTitle(nameColumn, "Name"); table.setColumnTitle(pmidColumn, "Study PubMed ID"); table.setColumnTitle(mslidColumn, "msl_id"); for (int i = 0; i < num; i++) { QString name, pubMedID, mslID; getStudyNameAndPubMedID(i, name, pubMedID, mslID); table.setElement(i, nameColumn, name); table.setElement(i, pmidColumn, pubMedID); table.setElement(i, mslidColumn, mslID); } } */ /** * read the data from a StringTable. * void StudyNamePubMedID::readDataFromStringTable(const StringTable& st) throw (FileException) { if (st.getTableTitle() != "Name_PMID") { throw FileException("String table for StudyMetaData does not have name Study Metadata"); } StudyMetaData* savedParentStudyMetaData = parentStudyMetaData; StudyCollectionFile* savedParentStudyCollectionFile = parentStudyCollectionFile; clear(); int nameColumn = -1; int pmidColumn = -1; int mslidColumn = -1; const int numCols = st.getNumberOfColumns(); for (int i = 0; i < numCols; i++) { const QString name = st.getColumnTitle(i).toLower(); if (name == "name") { nameColumn = i; } else if (name == "study pubmed id") { pmidColumn = i; } else if (name == "msl_id") { mslidColumn = i; } } const int numItems = st.getNumberOfRows(); for (int i = 0; i < numItems; i++) { QString name, pmid, msl; if (nameColumn >= 0) { name = st.getElement(i, nameColumn); } if (pmidColumn >= 0) { pmid = st.getElement(i, pmidColumn); } if (mslidColumn >= 0) { msl = st.getElement(i, mslidColumn); } if (name.isEmpty() == false) { addStudyNameAndPubMedID(name, pmid, msl); } } parentStudyMetaData = savedParentStudyMetaData; parentStudyCollectionFile = savedParentStudyCollectionFile; setModified(); } */ /** * called to read from an XML structure. */ void StudyNamePubMedID::readXML(QDomNode& nodeIn) throw (FileException) { if (nodeIn.isNull()) { return; } QDomElement elem = nodeIn.toElement(); if (elem.isNull()) { return; } if (elem.tagName() != "StudyNamePubMedID") { QString msg("Incorrect element type passed to StudyNamePubMedID::readXML() "); msg.append(elem.tagName()); throw FileException("", msg); } QDomNode node = nodeIn.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (elem.tagName() == "name") { name = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "pubMedID") { pubMedID = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "mslID") { mslID = AbstractFile::getXmlElementFirstChildAsString(elem); } else { std::cout << "WARNING: unrecognized StudyNamePubMedID element: " << elem.tagName().toAscii().constData() << std::endl; } } node = node.nextSibling(); } } /** * called to write to an XML structure. */ void StudyNamePubMedID::writeXML(QDomDocument& xmlDoc, QDomElement& parentElement) const throw (FileException) { // // Create element for this instance's data // QDomElement element = xmlDoc.createElement("StudyNamePubMedID"); // // Set data elements // AbstractFile::addXmlCdataElement(xmlDoc, element, "name", name); AbstractFile::addXmlCdataElement(xmlDoc, element, "pubMedID", pubMedID); AbstractFile::addXmlCdataElement(xmlDoc, element, "mslID", mslID); // // Add class instance's data to the parent // parentElement.appendChild(element); } /** * Called to write XML. */ void StudyNamePubMedID::writeXML(XmlGenericWriter& xmlWriter) const throw (FileException) { xmlWriter.writeStartElement("StudyNamePubMedID"); xmlWriter.writeElementCData("name", name); xmlWriter.writeElementCData("pubMedID", pubMedID); xmlWriter.writeElementCData("mslID", mslID); xmlWriter.writeEndElement(); } caret-5.6.4~dfsg.1.orig/caret_files/StudyMetaDataLinkSet.h0000664000175000017500000000666011572067322023225 0ustar michaelmichael #ifndef __STUDY_META_DATA_LINK_SET_H__ #define __STUDY_META_DATA_LINK_SET_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "StudyMetaDataLink.h" class QDomDocument; class QDomElement; class QDomNode; class XmlGenericWriter; /// class for accessing and storing a group of StudyMetaDataLink class StudyMetaDataLinkSet { 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 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 QString getLinkSetAsCodedText() const; /// set the link set from "coded" text form void setLinkSetFromCodedText(const QString& txt); // called to read from an XML structure void readXML(QDomNode& node) throw (FileException); // called to write to an XML structure void writeXML(QDomDocument& xmlDoc, QDomElement& parentElement) const throw (FileException); // called to write XML void writeXML(XmlGenericWriter& xmlWriter) const throw (FileException); protected: /// the StudyMetaDataLink std::vector links; // //----- tags for reading and writing // /// tag for reading and writing study metadata static const QString tagStudyMetaDataLinkSet; /// get the link separator for when stored as a string static const QString encodedTextLinkSeparator; friend class CellBase; }; #endif // __STUDY_META_DATA_LINK_SET_H__ #ifdef __STUDY_META_DATA_LINK_SET_MAIN__ const QString StudyMetaDataLinkSet::tagStudyMetaDataLinkSet = "StudyMetaDataLinkSet"; const QString StudyMetaDataLinkSet::encodedTextLinkSeparator = ":::::"; #endif // __STUDY_META_DATA_LINK_SET_MAIN__ caret-5.6.4~dfsg.1.orig/caret_files/StudyMetaDataLinkSet.cxx0000664000175000017500000001342611572067322023576 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #define __STUDY_META_DATA_LINK_SET_MAIN__ #include "StudyMetaDataLinkSet.h" #undef __STUDY_META_DATA_LINK_SET_MAIN__ #include "XmlGenericWriter.h" /** * constructor. */ StudyMetaDataLinkSet::StudyMetaDataLinkSet() { clear(); } /** * destructor. */ StudyMetaDataLinkSet::~StudyMetaDataLinkSet() { clear(); } /** * add a StudyMetaDataLink. */ void StudyMetaDataLinkSet::addStudyMetaDataLink(const StudyMetaDataLink& smdl) { links.push_back(smdl); } /** * remove all links. */ void StudyMetaDataLinkSet::clear() { links.clear(); } /** * get a StudyMetaDataLink. */ StudyMetaDataLink StudyMetaDataLinkSet::getStudyMetaDataLink(const int indx) const { return links[indx]; } /** * get a pointer to a StudyMetaDataLink. */ StudyMetaDataLink* StudyMetaDataLinkSet::getStudyMetaDataLinkPointer(const int indx) { if ((indx >= 0) && (indx < getNumberOfStudyMetaDataLinks())) { return &links[indx]; } return NULL; } /** * set a study meta data link. */ void StudyMetaDataLinkSet::setStudyMetaDataLink(const int indx, const StudyMetaDataLink& smdl) { 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 QString 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) { links.erase(links.begin() + indx); } /** * get the entire link set in an "coded" text form. */ QString StudyMetaDataLinkSet::getLinkSetAsCodedText() const { QStringList sl; const int num = getNumberOfStudyMetaDataLinks(); for (int i = 0; i < num; i++) { sl << getStudyMetaDataLink(i).getLinkAsCodedText(); } const QString s = sl.join(encodedTextLinkSeparator); return s; } /** * set the link set from "coded" text form. */ void StudyMetaDataLinkSet::setLinkSetFromCodedText(const QString& txt) { clear(); const QStringList sl = txt.split(encodedTextLinkSeparator, QString::SkipEmptyParts); for (int i = 0; i < sl.count(); i++) { StudyMetaDataLink smdl; smdl.setLinkFromCodedText(sl.at(i)); links.push_back(smdl); } } /** * called to read from an XML structure. */ void StudyMetaDataLinkSet::readXML(QDomNode& nodeIn) throw (FileException) { clear(); if (nodeIn.isNull()) { return; } QDomElement elem = nodeIn.toElement(); if (elem.isNull()) { return; } if (elem.tagName() == tagStudyMetaDataLinkSet) { QDomNode node = nodeIn.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (elem.tagName() == StudyMetaDataLink::tagStudyMetaDataLink) { StudyMetaDataLink smdl; smdl.readXML(elem); links.push_back(smdl); } else { std::cout << "WARNING: unrecognized StudyMetaDataLinkSet element ignored: " << elem.tagName().toAscii().constData() << std::endl; } } node = node.nextSibling(); } } else if (elem.tagName() == StudyMetaDataLink::tagStudyMetaDataLink) { StudyMetaDataLink smdl; smdl.readXML(elem); links.push_back(smdl); } else { QString msg("Incorrect element type passed to StudyMetaDataLinkSet::readXML() "); msg.append(elem.tagName()); throw FileException("", msg); } } /** * called to write to an XML structure. */ void StudyMetaDataLinkSet::writeXML(QDomDocument& xmlDoc, QDomElement& parentElement) const throw (FileException) { // // Create the element for this class instance's data // QDomElement linkSetElement = xmlDoc.createElement(tagStudyMetaDataLinkSet); // // Write the links // const int num = getNumberOfStudyMetaDataLinks(); for (int i = 0; i < num; i++) { StudyMetaDataLink smdl = getStudyMetaDataLink(i); smdl.writeXML(xmlDoc, linkSetElement); } // // Add to parent // parentElement.appendChild(linkSetElement); } /** * called to write XML. */ void StudyMetaDataLinkSet::writeXML(XmlGenericWriter& xmlWriter) const throw (FileException) { xmlWriter.writeStartElement(tagStudyMetaDataLinkSet); const int num = getNumberOfStudyMetaDataLinks(); for (int i = 0; i < num; i++) { StudyMetaDataLink smdl = getStudyMetaDataLink(i); smdl.writeXML(xmlWriter); } xmlWriter.writeEndElement(); } caret-5.6.4~dfsg.1.orig/caret_files/StudyMetaDataLink.h0000664000175000017500000001651711572067322022553 0ustar michaelmichael #ifndef __STUDY_META_DATA_LINK_H__ #define __STUDY_META_DATA_LINK_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "FileException.h" class QDomDocument; class QDomElement; class QDomNode; class XmlGenericWriter; //======================================================================================== // /// the Study Meta Data Link (connects data to a study metadata by study number or PubMed ID class StudyMetaDataLink { 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) QString getPubMedID() const { return pubMedID; } /// set the PubMed ID (negative if project ID) void setPubMedID(const QString& pmid) { pubMedID = pmid; } /// get the table number (blank if invalid) QString getTableNumber() const { return tableNumber; } /// set the table number (blank if invalid) void setTableNumber(const QString& tn); /// get the table sub header number (blank if invalid) QString getTableSubHeaderNumber() const { return tableSubHeaderNumber; } /// set the table sub header number (blank if invalid) void setTableSubHeaderNumber(const QString& tshn); /// get the figure number (blank if invalid) QString getFigureNumber() const { return figureNumber; } /// set the figure number (blank if invalid) void setFigureNumber(const QString& fn); /// get the panel letter/number (blank if invalid) QString getFigurePanelNumberOrLetter() const { return panelNumberOrLetter; } /// set the panel letter/number (blank if invalid) void setFigurePanelNumberOrLetter(const QString& pnl); /// get the page reference page number (blank if invalid) QString getPageReferencePageNumber() const { return pageReferencePageNumber; } /// set the page reference page number (blank if invalid) void setPageReferencePageNumber(const QString& prpn); /// get the page reference sub header number (blank if invalid) QString getPageReferenceSubHeaderNumber() const { return pageReferenceSubHeaderNumber; } /// set the page reference sub header number (blank if invalid) void setPageReferenceSubHeaderNumber(const QString& tshn); /// get the page number (negative if invalid) //QString getPageNumber() const { return pageNumber; } /// set the page number (negative if invalid) //void setPageNumber(const QString& pn); /// get the entire link in an "coded" text form QString getLinkAsCodedText() const; /// set the link from "coded" text form void setLinkFromCodedText(const QString& txt); // called to read from an XML structure void readXML(QDomNode& node) throw (FileException); // called to write to an XML structure void writeXML(QDomDocument& xmlDoc, QDomElement& parentElement) const throw (FileException); // called to write XML void writeXML(XmlGenericWriter& xmlWriter) const throw (FileException); /// set element from text (used by SAX XML parser) void setElementFromText(const QString& elementName, const QString& textValue); protected: /// copy helper void copyHelper(const StudyMetaDataLink& smdl); /// the PubMed ID (negative if project ID, 0 if invalid) QString pubMedID; /// the table number (blank if invalid) QString tableNumber; /// the table sub header number (blank if invalid) QString tableSubHeaderNumber; /// the figure number (blank if invalid) QString figureNumber; /// the panel letter/number (blank if invalid) QString panelNumberOrLetter; /// the page number (blank if invalid) //QString pageNumber; /// page reference page number (blank if invalid) QString pageReferencePageNumber; /// page reference sub header number (blank if invalid) QString pageReferenceSubHeaderNumber; // NOTE: IF MEMBERS ADDED UPDATE THE COPY HELPER // //----- tags for reading and writing // /// tag for reading and writing study metadata static const QString tagStudyMetaDataLink; /// tag for reading and writing study metadata static const QString tagPubMedID; /// tag for reading and writing study metadata static const QString tagTableNumber; /// tag for reading and writing study metadata static const QString tagTableSubHeaderNumber; /// tag for reading and writing study metadata static const QString tagFigureNumber; /// tag for reading and writing study metadata static const QString tagPanelNumberOrLetter; /// tag for reading and writing study metadata //static const QString tagPageNumber; /// tag for reading and writing study metadata static const QString tagPageReferencePageNumber; /// tag for reading and writing study metadata static const QString tagPageReferenceSubHeaderNumber; friend class CellBase; friend class StudyMetaDataLinkSet; }; #endif // __STUDY_META_DATA_LINK_H__ #ifdef __STUDY_META_DATA_LINK_MAIN__ const QString StudyMetaDataLink::tagStudyMetaDataLink = "StudyMetaDataLink"; const QString StudyMetaDataLink::tagPubMedID = "pubMedID"; const QString StudyMetaDataLink::tagTableNumber = "tableNumber"; const QString StudyMetaDataLink::tagTableSubHeaderNumber = "tableSubHeaderNumber"; const QString StudyMetaDataLink::tagFigureNumber = "figureNumber"; const QString StudyMetaDataLink::tagPanelNumberOrLetter = "panelNumberOrLetter"; //const QString StudyMetaDataLink::tagPageNumber = "pageNumber"; const QString StudyMetaDataLink::tagPageReferencePageNumber = "pageReferencePageNumber"; const QString StudyMetaDataLink::tagPageReferenceSubHeaderNumber = "pageReferenceSubHeaderNumber"; #endif // __STUDY_META_DATA_LINK_MAIN__ caret-5.6.4~dfsg.1.orig/caret_files/StudyMetaDataLink.cxx0000664000175000017500000003124211572067322023116 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #define __STUDY_META_DATA_LINK_MAIN__ #include "StudyMetaDataLink.h" #undef __STUDY_META_DATA_LINK_MAIN__ #include "AbstractFile.h" #include "XmlGenericWriter.h" //==================================================================================== // // StudyMetaData Link class // //==================================================================================== /** * constructor. */ StudyMetaDataLink::StudyMetaDataLink() { clear(); } /** * destructor. */ StudyMetaDataLink::~StudyMetaDataLink() { } /** * copy constructor. */ StudyMetaDataLink::StudyMetaDataLink(const StudyMetaDataLink& smdl) { copyHelper(smdl); } /** * assignment opertator. */ StudyMetaDataLink& StudyMetaDataLink::operator=(const StudyMetaDataLink& smdl) { if (this != &smdl) { copyHelper(smdl); } return *this; } /** * copy helper. */ void StudyMetaDataLink::copyHelper(const StudyMetaDataLink& smdl) { pubMedID = smdl.pubMedID; tableNumber = smdl.tableNumber; tableSubHeaderNumber = smdl.tableSubHeaderNumber; figureNumber = smdl.figureNumber; panelNumberOrLetter = smdl.panelNumberOrLetter; //pageNumber = smdl.pageNumber; pageReferencePageNumber = smdl.pageReferencePageNumber; pageReferenceSubHeaderNumber = smdl.pageReferenceSubHeaderNumber; } /** * equality operator. */ bool StudyMetaDataLink::operator==(const StudyMetaDataLink& smdl) const { const bool theSame = ((pubMedID == smdl.pubMedID) && (tableNumber == smdl.tableNumber) && (tableSubHeaderNumber == smdl.tableSubHeaderNumber) && (figureNumber == smdl.figureNumber) && (panelNumberOrLetter == smdl.panelNumberOrLetter) && //(pageNumber == smdl.pageNumber) && (pageReferencePageNumber == smdl.pageReferencePageNumber) && (pageReferenceSubHeaderNumber == smdl.pageReferenceSubHeaderNumber)); return theSame; } /** * clear the link. */ void StudyMetaDataLink::clear() { pubMedID = "0"; tableNumber = ""; tableSubHeaderNumber = ""; figureNumber = ""; panelNumberOrLetter = ""; //pageNumber = ""; pageReferencePageNumber = ""; pageReferenceSubHeaderNumber = ""; } /** * set the table number (blank if invalid). */ void StudyMetaDataLink::setTableNumber(const QString& tn) { if (tn == "-1") { tableNumber = ""; } else { tableNumber = tn; } } /** * set the table sub header number (blank if invalid). */ void StudyMetaDataLink::setTableSubHeaderNumber(const QString& tshn) { if (tshn == "-1") { tableSubHeaderNumber = ""; } else { tableSubHeaderNumber = tshn; } } /** * set the panel letter/number (blank if invalid). */ void StudyMetaDataLink::setFigurePanelNumberOrLetter(const QString& pnl) { if (pnl == "-1") { panelNumberOrLetter = ""; } else { panelNumberOrLetter = pnl; } } /** * set the figure number (blank if invalid). */ void StudyMetaDataLink::setFigureNumber(const QString& fn) { if (fn == "-1") { figureNumber = ""; } else { figureNumber = fn; } } /** * set the page reference page number (blank if invalid). */ void StudyMetaDataLink::setPageReferencePageNumber(const QString& prpn) { if (prpn == "-1") { pageReferencePageNumber = ""; } else { pageReferencePageNumber = prpn; } } /** * set the page reference sub header number (blank if invalid). */ void StudyMetaDataLink::setPageReferenceSubHeaderNumber(const QString& tshn) { if (tshn == "-1") { pageReferenceSubHeaderNumber = ""; } else { pageReferenceSubHeaderNumber = tshn; } } /** * set the page number (negative if invalid). */ /* void StudyMetaDataLink::setPageNumber(const QString& pn) { if (pn == "-1") { pageNumber = ""; } else { pageNumber = pn; } } */ /** * set element from text (used by SAX XML parser). */ void StudyMetaDataLink::setElementFromText(const QString& elementName, const QString& textValue) { if (elementName == tagPubMedID) { setPubMedID(textValue); } else if (elementName == tagTableNumber) { setTableNumber(textValue); } else if (elementName == tagTableSubHeaderNumber) { setTableSubHeaderNumber(textValue); } else if (elementName == tagFigureNumber) { setFigureNumber(textValue); } else if (elementName == tagPanelNumberOrLetter) { setFigurePanelNumberOrLetter(textValue); } //else if (elementName == tagPageNumber) { // setPageNumber(textValue); //} else if (elementName == tagPageReferencePageNumber) { setPageReferencePageNumber(textValue); } else if (elementName == tagPageReferenceSubHeaderNumber) { setPageReferenceSubHeaderNumber(textValue); } else { std::cout << "WARNING: unrecognized StudyMetaDataLink element ignored: " << elementName.toAscii().constData() << std::endl; } } /** * called to read from an XML structure. */ void StudyMetaDataLink::readXML(QDomNode& nodeIn) throw (FileException) { if (nodeIn.isNull()) { return; } QDomElement elem = nodeIn.toElement(); if (elem.isNull()) { return; } if (elem.tagName() != tagStudyMetaDataLink) { QString msg("Incorrect element type passed to StudyMetaDataLink::readXML() "); msg.append(elem.tagName()); throw FileException("", msg); } QString oldPageNumber; QDomNode node = nodeIn.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (elem.tagName() == tagPubMedID) { setPubMedID(AbstractFile::getXmlElementFirstChildAsString(elem)); } else if (elem.tagName() == tagTableNumber) { setTableNumber(AbstractFile::getXmlElementFirstChildAsString(elem)); } else if (elem.tagName() == tagTableSubHeaderNumber) { setTableSubHeaderNumber(AbstractFile::getXmlElementFirstChildAsString(elem)); } else if (elem.tagName() == tagFigureNumber) { setFigureNumber(AbstractFile::getXmlElementFirstChildAsString(elem)); } else if (elem.tagName() == tagPanelNumberOrLetter) { setFigurePanelNumberOrLetter(AbstractFile::getXmlElementFirstChildAsString(elem)); } //else if (elem.tagName() == tagPageNumber) { // setPageNumber(AbstractFile::getXmlElementFirstChildAsString(elem)); //} else if (elem.tagName() == "pageNumber") { oldPageNumber = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == tagPageReferencePageNumber) { setPageReferencePageNumber(AbstractFile::getXmlElementFirstChildAsString(elem)); } else if (elem.tagName() == tagPageReferenceSubHeaderNumber) { setPageReferenceSubHeaderNumber(AbstractFile::getXmlElementFirstChildAsString(elem)); } else { std::cout << "WARNING: unrecognized StudyMetaDataLink element ignored: " << elem.tagName().toAscii().constData() << std::endl; } } node = node.nextSibling(); } if (getPageReferencePageNumber().isEmpty()) { setPageReferencePageNumber(oldPageNumber); } } /** * called to write to an XML structure. */ void StudyMetaDataLink::writeXML(QDomDocument& xmlDoc, QDomElement& parentElement) const throw (FileException) { // // Create the element for this class instance's data // QDomElement linkElement = xmlDoc.createElement(tagStudyMetaDataLink); // // Add the study metadata // AbstractFile::addXmlCdataElement(xmlDoc, linkElement, tagPubMedID, pubMedID); AbstractFile::addXmlCdataElement(xmlDoc, linkElement, tagTableNumber, tableNumber); AbstractFile::addXmlCdataElement(xmlDoc, linkElement, tagTableSubHeaderNumber, tableSubHeaderNumber); AbstractFile::addXmlCdataElement(xmlDoc, linkElement, tagFigureNumber, figureNumber); AbstractFile::addXmlCdataElement(xmlDoc, linkElement, tagPanelNumberOrLetter, panelNumberOrLetter); //AbstractFile::addXmlCdataElement(xmlDoc, linkElement, tagPageNumber, pageNumber); AbstractFile::addXmlCdataElement(xmlDoc, linkElement, tagPageReferencePageNumber, pageReferencePageNumber); AbstractFile::addXmlCdataElement(xmlDoc, linkElement, tagPageReferenceSubHeaderNumber, pageReferenceSubHeaderNumber); // // Add to parent // parentElement.appendChild(linkElement); } /** * called to write XML. */ void StudyMetaDataLink::writeXML(XmlGenericWriter& xmlWriter) const throw (FileException) { xmlWriter.writeStartElement(tagStudyMetaDataLink); xmlWriter.writeElementCData(tagPubMedID, pubMedID); xmlWriter.writeElementCData(tagTableNumber, tableNumber); xmlWriter.writeElementCData(tagTableSubHeaderNumber, tableSubHeaderNumber); xmlWriter.writeElementCData(tagFigureNumber, figureNumber); xmlWriter.writeElementCData(tagPanelNumberOrLetter, panelNumberOrLetter); xmlWriter.writeElementCData(tagPageReferencePageNumber, pageReferencePageNumber); xmlWriter.writeElementCData(tagPageReferenceSubHeaderNumber, pageReferenceSubHeaderNumber); xmlWriter.writeEndElement(); } /** * get the entire link in an "coded" text form. */ QString StudyMetaDataLink::getLinkAsCodedText() const { // // Assemble into one string containing key/value pairs separated by a semi-colon // QStringList sl; sl << ("pubMedID=" + pubMedID) << ("tableNumber=" + tableNumber) << ("tableSubHeaderNumber=" + tableSubHeaderNumber) << ("figureNumber=" + figureNumber) << ("panelNumberOrLetter=" + panelNumberOrLetter) //<< ("pageNumber=" + pageNumber) << ("pageReferencePageNumber=" + pageReferencePageNumber) << ("pageReferenceSubHeaderNumber=" + pageReferenceSubHeaderNumber); const QString s = sl.join(";"); return s; } /** * set the link from "coded" text form. */ void StudyMetaDataLink::setLinkFromCodedText(const QString& txt) { // // Clear this link // clear(); QString oldPageNumber; // // Extract the key/value pairs that are separated by a semi-colon // const QStringList sl = txt.split(";", QString::SkipEmptyParts); for (int i = 0; i < sl.size(); i++) { const QString keyValueString = sl.at(i); // // Split with "=" into key/value pairs // const QStringList keyValueList = keyValueString.split("=", QString::SkipEmptyParts); if (keyValueList.size() == 2) { const QString key = keyValueList.at(0); const QString 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 == "pageNumber") { oldPageNumber = value; //ignore as obsolete setPageNumber(value); } else if (key == "pageReferencePageNumber") { setPageReferencePageNumber(value); } else if (key == "pageReferenceSubHeaderNumber") { setPageReferenceSubHeaderNumber(value); } else { std::cout << "Unrecognized StudyMetaDataLink key: " << key.toAscii().constData() << std::endl; } } } if (getPageReferencePageNumber().isEmpty()) { setPageReferencePageNumber(oldPageNumber); } } caret-5.6.4~dfsg.1.orig/caret_files/StudyMetaDataFile.h0000664000175000017500000012615711572067322022537 0ustar michaelmichael #ifndef __STUDY_META_DATA_FILE_H__ #define __STUDY_META_DATA_FILE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "AbstractFile.h" #include "StudyNamePubMedID.h" class CellFile; class CellProjectionFile; class CellStudyInfo; class QDomDocument; class QDomElement; class QDomNode; class FociProjectionFile; class StudyMetaDataFile; class StudyMetaDataLink; class StudyMetaDataTextDisplayFilter; class VocabularyFile; class XmlGenericWriter; /// Class for storing study meta data class StudyMetaData { public: /// Figure Class class Figure { public: /// figure panel class class Panel { public: // constructor Panel(); // destructor ~Panel(); // copy constructor Panel(const Panel& p); // assignment operator Panel& operator=(const Panel& p); // clear the panel's data void clear(); /// get the panel number/letter QString getPanelNumberOrLetter() const { return panelNumberOrLetter; } // set the panel number/letter void setPanelNumberOrLetter(const QString& s); /// get the description QString getDescription() const { return description; } // set the description void setDescription(const QString& s); /// get task description QString getTaskDescription() const { return taskDescription; } // set Task Description void setTaskDescription(const QString& s); /// get TaskBaseline QString getTaskBaseline() const { return taskBaseline; } // set TaskBaseline void setTaskBaseline(const QString& s); /// get test attributes QString getTestAttributes() const { return testAttributes; } // set TestAttributes void setTestAttributes(const QString& s); // called to read from an XML structure void readXML(QDomNode& node) throw (FileException); // called to write to an XML structure void writeXML(QDomDocument& xmlDoc, QDomElement& parentElement) const throw (FileException); // called to write XML void writeXML(XmlGenericWriter& xmlWriter) const throw (FileException); /// set parent void setParent(Figure* parentFigureIn); protected: // copy helper used by copy constructor and assignment operator void copyHelper(const Panel& p); // set modified status void setModified(); /// figure that is parent of instance (DO NOT COPY) Figure* parentFigure; /// description QString description; /// the panel number/letter QString panelNumberOrLetter; // task description QString taskDescription; // task baseline QString taskBaseline; // test attributes QString testAttributes; // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // If additional members are added be sure to update copyHelper() method. // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! }; // end of panel class // constructor Figure(); // destructor ~Figure(); // copy constructor Figure(const Figure& f); // assignment operator Figure& operator=(const Figure& f); // clear the figure information void clear(); // add a panel void addPanel(Panel* p); // delete a panel void deletePanel(const int indx); // delete a panel void deletePanel(const Panel* panel); /// get the number of panels int getNumberOfPanels() const { return panels.size(); } /// get a panel Panel* getPanel(const int indx) { return panels[indx]; } /// get a panel (const method) const Panel* getPanel(const int indx) const { return panels[indx]; } /// get a panel by its panel number/letter Panel* getPanelByPanelNumberOrLetter(const QString& panelNumberOrLetter); /// get a panel by its panel number/letter (const method) const Panel* getPanelByPanelNumberOrLetter(const QString& panelNumberOrLetter) const; /// get the legend QString getLegend() const { return legend; } // set the legend void setLegend(const QString& s); /// get the figure number QString getNumber() const { return number; } // set the figure number void setNumber(const QString& n); // called to read from an XML structure void readXML(QDomNode& nodeIn) throw (FileException); // called to write to an XML structure void writeXML(QDomDocument& xmlDoc, QDomElement& parentElement) const throw (FileException); // called to write XML void writeXML(XmlGenericWriter& xmlWriter) const throw (FileException); /// set parent void setParent(StudyMetaData* parentStudyMetaDataIn); protected: // copy helper used by copy constructor and assignment operator void copyHelper(const Figure& f); // set modified status void setModified(); /// study metadata that is parent of this figure (DO NOT COPY) StudyMetaData* parentStudyMetaData; /// legend QString legend; /// figure number QString number; /// the panels std::vector panels; // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // If additional members are added be sure to update copyHelper() method. // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! }; // end of Figure class class Table; class PageReference; // Table Subheader class SubHeader { public: // constructor SubHeader(); // destructor ~SubHeader(); // copy constructor SubHeader(const SubHeader& sh); // assignment operator SubHeader& operator=(const SubHeader& sh); // clear the sub header void clear(); /// get name QString getName() const { return name; } // set name void setName(const QString& s); /// get number QString getNumber() const { return number; } // set number void setNumber(const QString& n); /// get short name QString getShortName() const { return shortName; } // set short name void setShortName(const QString& s); /// get task description QString getTaskDescription() const { return taskDescription; } // set Task Description void setTaskDescription(const QString& s); /// get TaskBaseline QString getTaskBaseline() const { return taskBaseline; } // set TaskBaseline void setTaskBaseline(const QString& s); /// get test attributes QString getTestAttributes() const { return testAttributes; } // set TestAttributes void setTestAttributes(const QString& s); // called to read from an XML structure void readXML(QDomNode& node) throw (FileException); // called to write to an XML structure void writeXML(QDomDocument& xmlDoc, QDomElement& parentElement) const throw (FileException); // called to write XML void writeXML(XmlGenericWriter& xmlWriter) const throw (FileException); // set parent void setParent(Table* parentTableIn); // set parent void setParent(PageReference* parentPageReferenceIn); /// get the selected flag bool getSelected() const { return selectedFlag; } /// set the selected flag (does not modify this object) void setSelected(const bool s) { selectedFlag = s; } protected: // copy helper used by copy constructor and assignment operator void copyHelper(const SubHeader& sh); // set instance modified void setModified(); /// parent of this instance (DO NOT COPY) Table* parentTable; /// parent of this instance (DO NOT COPY) PageReference* parentPageReference; /// name QString name; /// subheader number QString number; /// short name QString shortName; /// task description QString taskDescription; /// task baseline QString taskBaseline; /// test attributes QString testAttributes; /// selected flag bool selectedFlag; // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // If additional members are added be sure to update copyHelper() method. // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! }; // end of class SubHeader /// Table Class class Table { public: // constructor Table(); // destructor ~Table(); // copy constructor Table(const Table& t); // assignment operator Table& operator=(const Table& t); // clear the table void clear(); // add a sub header void addSubHeader(SubHeader* sh); // delete a sub header void deleteSubHeader(const int indx); // delete a sub header void deleteSubHeader(const SubHeader* subHeader); /// get the number of sub headers int getNumberOfSubHeaders() const { return subHeaders.size(); } /// get a sub header SubHeader* getSubHeader(const int indx) { return subHeaders[indx]; } /// get a sub header const SubHeader* getSubHeader(const int indx) const { return subHeaders[indx]; } // get a sub header by sub header number SubHeader* getSubHeaderBySubHeaderNumber(const QString& subHeaderNumber); // get a sub header by sub header number (const method) const SubHeader* getSubHeaderBySubHeaderNumber(const QString& subHeaderNumber) const; /// get footer QString getFooter() const { return footer; } // set footer void setFooter(const QString& s); /// get header QString getHeader() const { return header; } // set header void setHeader(const QString& s); /// get number QString getNumber() const { return number; } // set number void setNumber(const QString& n); /// get size units QString getSizeUnits() const { return sizeUnits; } // set size units void setSizeUnits(const QString& s); /// get statistic type QString getStatisticType() const { return statisticType; } // set tatistic type void setStatisticType(const QString& s); /// get statistic description QString getStatisticDescription() const { return statisticDescription; } // set statistic description void setStatisticDescription(const QString& s); /// get voxel dimensions QString getVoxelDimensions() const { return voxelDimensions; } // set voxelDimensions void setVoxelDimensions(const QString& s); // called to read from an XML structure void readXML(QDomNode& node) throw (FileException); // called to write to an XML structure void writeXML(QDomDocument& xmlDoc, QDomElement& parentElement) const throw (FileException); // called to write XML void writeXML(XmlGenericWriter& xmlWriter) const throw (FileException); /// set parent void setParent(StudyMetaData* parentStudyMetaDataIn); // set modified void setModified(); protected: // copy helper used by copy constructor and assignment operator void copyHelper(const Table& t); /// study metadata that is parent of this table (DO NOT COPY) StudyMetaData* parentStudyMetaData; /// the table footer QString footer; /// the table header QString header; /// the table number in the paper QString number; /// size units QString sizeUnits; /// statistic type QString statisticType; /// statistic description QString statisticDescription; /// voxel dimensions QString voxelDimensions; /// the sub headers std::vector subHeaders; // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // If additional members are added be sure to update copyHelper() method. // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! }; // end of class Table /// page reference class PageReference { public: // constructor PageReference(); // destructor ~PageReference(); // copy constructor PageReference(const PageReference& pr); // assignment operator PageReference& operator=(const PageReference& pr); // clear the page link void clear(); // add a sub header void addSubHeader(SubHeader* sh); // delete a sub header void deleteSubHeader(const int indx); // delete a sub header void deleteSubHeader(const SubHeader* subHeader); /// get the number of sub headers int getNumberOfSubHeaders() const { return subHeaders.size(); } /// get a sub header SubHeader* getSubHeader(const int indx) { return subHeaders[indx]; } /// get a sub header const SubHeader* getSubHeader(const int indx) const { return subHeaders[indx]; } // get a sub header by sub header number SubHeader* getSubHeaderBySubHeaderNumber(const QString& subHeaderNumber); // get a sub header by sub header number (const method) const SubHeader* getSubHeaderBySubHeaderNumber(const QString& subHeaderNumber) const; /// get the page number QString getPageNumber() const { return pageNumber; } // set the void setPageNumber(const QString& pn); /// get the header QString getHeader() const { return header; } // set the header void setHeader(const QString& s); /// get the comment QString getComment() const { return comment; } // set the comment void setComment(const QString& s); /// get the size units QString getSizeUnits() const { return sizeUnits; } // set the size units void setSizeUnits(const QString& s); /// get the voxel dimensions QString getVoxelDimensions() const { return voxelDimensions; } // set the voxel dimensions void setVoxelDimensions(const QString& s); /// get the statistic type QString getStatisticType() const { return statisticType; } // set the statistic type void setStatisticType(const QString& s); /// get the statistic description QString getStatisticDescription() const { return statisticDescription; } // set the statistic description void setStatisticDescription(const QString& s); // called to read from an XML structure void readXML(QDomNode& node) throw (FileException); // called to write to an XML structure void writeXML(QDomDocument& xmlDoc, QDomElement& parentElement) const throw (FileException); // called to write XML void writeXML(XmlGenericWriter& xmlWriter) const throw (FileException); // set parent void setParent(StudyMetaData* parentStudyMetaDataIn); // set modified void setModified(); protected: // copy helper void copyHelper(const PageReference& pr); /// study metadata that is parent of this table (DO NOT COPY) StudyMetaData* parentStudyMetaData; /// the page number QString pageNumber; /// the header QString header; /// the comment QString comment; /// the size units QString sizeUnits; /// the voxel dimensions QString voxelDimensions; /// the statistic type QString statisticType; /// the statistic description QString statisticDescription; /// the sub headers std::vector subHeaders; // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // If additional members are added be sure to update copyHelper() method. // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! }; // end of class PageReference /// provenance class Provenance { public: // constructor Provenance(); // destructor ~Provenance(); // copy constructor Provenance(const Provenance& p); // assignment operator Provenance& operator=(const Provenance& p); // clear the page link void clear(); /// get the name QString getName() const { return name; } // set the name void setName(const QString& s); /// get the date QString getDate() const { return date; } // set the date void setDate(const QString& s); /// get the command QString getComment() const { return comment; } // set the comment void setComment(const QString& s); // called to read from XML void readXML(QDomNode& node) throw (FileException); // called to write to an XML structure void writeXML(QDomDocument& xmlDoc, QDomElement& parentElement) const throw (FileException); // called to write XML void writeXML(XmlGenericWriter& xmlWriter) const throw (FileException); // set parent void setParent(StudyMetaData* parentStudyMetaDataIn); // set modified void setModified(); protected: // copy helper void copyHelper(const Provenance& p); /// study metadata that is parent of this table (DO NOT COPY) StudyMetaData* parentStudyMetaData; /// the name QString name; /// the date QString date; /// the comment QString comment; // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // If additional members are added be sure to update copyHelper() method. // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! }; // end of class Provenance // constructor StudyMetaData(); // constructor (from old CellStudyInfo) StudyMetaData(const CellStudyInfo& csi); // destructor ~StudyMetaData(); // copy constructor StudyMetaData(const StudyMetaData& smd); // assignment operator StudyMetaData& operator=(const StudyMetaData& smd); // clear the meta data void clear(); // equality operator bool operator==(const StudyMetaData& cci) const; // called to read from an XML structure void readXML(QDomNode& node) throw (FileException); // called to write to an XML structure void writeXML(QDomDocument& xmlDoc, QDomElement& parentElement) const throw (FileException); // called to write XML void writeXML(XmlGenericWriter& xmlWriter, int indx) const throw (FileException); // get the study data format entries static void getStudyDataFormatEntries(std::vector& entries); // get the study data type entries static void getStudyDataTypeEntries(std::vector& entries); // retrieve data from PubMed using PubMed ID void updateDataFromPubMedDotComUsingPubMedID() throw (FileException); // add a figure void addFigure(Figure* f); // delete a figure void deleteFigure(const int indx); // delete a figure void deleteFigure(const Figure* figure); /// get the number of figures int getNumberOfFigures() const { return figures.size(); } /// get a figure Figure* getFigure(const int indx) { return figures[indx]; } /// get a figure (const method) const Figure* getFigure(const int indx) const { return figures[indx]; } /// get a figure by its figure number Figure* getFigureByFigureNumber(const QString& figureNumber); /// get a figure by its figure number (const method) const Figure* getFigureByFigureNumber(const QString& figureNumber) const; // add a table void addTable(Table* t); // delete a table void deleteTable(const int indx); // delete a table void deleteTable(const Table* table); /// get number of tables int getNumberOfTables() const { return tables.size(); } /// get a table Table* getTable(const int indx) { return tables[indx]; } /// get a table (const method) const Table* getTable(const int indx) const { return tables[indx]; } /// get a table by its table number Table* getTableByTableNumber(const QString& tableNumber); /// get a table by its table number (const method) const Table* getTableByTableNumber(const QString& tableNumber) const; // add a provenance void addProvenance(Provenance* p); // delete a provenance void deleteProvenance(const int indx); // delete a provenance void deleteProvenance(const Provenance* p); /// get number of provenances int getNumberOfProvenances() const { return provenances.size(); } /// get a provenance Provenance* getProvenance(const int indx) { return provenances[indx]; } /// get a provenance (const method) const Provenance* getProvenance(const int indx) const { return provenances[indx]; } // add a page reference void addPageReference(PageReference* pr); // delete a page reference void deletePageReference(const int indx); // delete a page reference void deletePageReference(const PageReference* pr); // get number of page references int getNumberOfPageReferences() const { return pageReferences.size(); } // get a page reference PageReference* getPageReference(const int indx) { return pageReferences[indx]; } // get a page reference (const method) const PageReference* getPageReference(const int indx) const { return pageReferences[indx]; } // get a page reference by its page number PageReference* getPageReferenceByPageNumber(const QString& pageNumber); // get a page reference by its page number (const method) const PageReference* getPageReferenceByPageNumber(const QString& pageNumber) const; /// get authors QString getAuthors() const { return authors; } // set authors void setAuthors(const QString& s); /// get citation QString getCitation() const { return citation; } /// set citation void setCitation(const QString& s); /// get comment QString getComment() const { return comment; } // set comment void setComment(const QString& s); /// get the document object identifier QString getDocumentObjectIdentifier() const { return documentObjectIdentifier; } // set the document object identifier void setDocumentObjectIdentifier(const QString& doi); /// get keywords QString getKeywords() const { return keywords; } // get the keywords void getKeywords(std::vector& keywordsOut) const; // see if study contains a keyword bool containsKeyword(const QString& kw) const; // get all table headers void getAllTableHeaders(std::vector& namesOut) const; // get all table sub header short names in this study void getAllTableSubHeaderShortNames(std::vector& tableSubHeaderShortNamesOut) const; // see if study contains a sub header short names. bool containsSubHeaderShortName(const QString& shsn) const; // set keywords void setKeywords(const QString& s); /// get medical subject headings QString getMedicalSubjectHeadings() const { return medicalSubjectHeadings; } /// get medical subject headings void getMedicalSubjectHeadings(std::vector& meshOut) const; /// set medical subject headings void setMedicalSubjectHeadings(const QString& s); /// get name QString getName() const { return name; } /// set name void setName(const QString& s); /// get partitioning scheme abbreviation QString getPartitioningSchemeAbbreviation() const { return partitioningSchemeAbbreviation; } // set partitioning scheme abbreviation void setPartitioningSchemeAbbreviation(const QString& s); /// get partitioning scheme full name QString getPartitioningSchemeFullName() const { return partitioningSchemeFullName; } // set partitioning scheme full name void setPartitioningSchemeFullName(const QString& s); /// get the PubMed ID (if negative it is project ID) QString getPubMedID() const { return pubMedID; } // set the PubMed ID void setPubMedID(const QString& pmid); // see if the PubMed ID is actually a Project ID bool getPubMedIDIsAProjectID() const; /// get species QString getSpecies() const { return species; } // set species void setSpecies(const QString& s); /// get stereotaxic space QString getStereotaxicSpace() const { return stereotaxicSpace; } // set stereotaxic space void setStereotaxicSpace(const QString& s); /// get stereotaxic space details QString getStereotaxicSpaceDetails() const { return stereotaxicSpaceDetails; } // set stereotaxic space details void setStereotaxicSpaceDetails(const QString& s); /// get the project ID QString getProjectID() const { return projectID; } // set the project ID void setProjectID(const QString& num); /// get the Project ID prefix when used as a static QString getProjectIDInPubMedIDPrefix() { return "ProjID"; } /// get the most recent save date QString getMostRecentDateAndTimeStamp() const; /// get the data and time stamps QString getDateAndTimeStamps() const { return dateAndTimeStamps; } /// get the quality QString getQuality() const { return quality; } /// set the quality void setQuality(const QString& s); /// get the study data format QString getStudyDataFormat() const { return studyDataFormat; } /// set the study data format void setStudyDataFormat(const QString& s); /// get the study data type QString getStudyDataType() const { return studyDataType; } /// set the study data type void setStudyDataType(const QString& s); /// get title QString getTitle() const { return title; } // set title void setTitle(const QString& s); // get parent StudyMetaDataFile* getParent() { return parentStudyMetaDataFile; } // get parent (const method) const StudyMetaDataFile* getParent() const { return parentStudyMetaDataFile; } // set parent void setParent(StudyMetaDataFile* parentStudyMetaDataFile); /// get MSL ID QString getMslID() const { return mslID; } /// set MSL ID void setMslID(const QString& s); /// get parent ID QString getParentID() const { return parentID; } /// set parent ID void setParentID(const QString& s); /// get core data completed QString getCoreDataCompleted() const { return coreDataCompleted; } /// set core data completed void setCoreDataCompleted(const QString& s); /// get completed QString getCompleted() const { return completed; } /// set completed void setCompleted(const QString& s); /// get public access QString getPublicAccess() const { return publicAccess; } /// set public access void setPublicAccess(const QString& s); // set this study info is modified void setModified(); // clear this study info is modified void clearModified(); protected: // copy helper used by copy constructor and assignment operator void copyHelper(const StudyMetaData& smd); // set the date and time stamps void setDateAndTimeStamps(const QString& p); /// study metadata file that is a parent of this instance (do not copy) StudyMetaDataFile* parentStudyMetaDataFile; /// study authors QString authors; /// study citation (journal) QString citation; /// comment QString comment; /// the document object identifier QString documentObjectIdentifier; /// study key words QString keywords; /// medical subject headings QString medicalSubjectHeadings; /// name QString name; /// partitioning scheme abbreviation QString partitioningSchemeAbbreviation; /// partitioning scheme full name QString partitioningSchemeFullName; /// the project ID QString projectID; /// the PubMed ID QString pubMedID; /// quality of data QString quality; /// study data format QString studyDataFormat; /// study data type QString studyDataType; /// the species QString species; /// stereotaxic space QString stereotaxicSpace; /// stereotaxic space details QString stereotaxicSpaceDetails; /// study title QString title; /// MSL ID QString mslID; /// parent ID QString parentID; /// core data completed QString coreDataCompleted; /// completed QString completed; /// public access QString publicAccess; /// tables in the study std::vector tables; /// figures in the study std::vector figures; /// provenances std::vector provenances; /// page references std::vector pageReferences; /// the date and time stamps (DO NOT COPY) mutable QString dateAndTimeStamps; /// the modified flag, cleared when file is written (DO NOT COPY) mutable bool studyDataModifiedFlag; // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // If additional members are added be sure to update copyHelper() method. // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! }; //======================================================================================== // /// the Study Meta Data File class StudyMetaDataFile : public AbstractFile { public: // constructor StudyMetaDataFile(); // destructor ~StudyMetaDataFile(); // copy constructor StudyMetaDataFile(const StudyMetaDataFile& smdf); // assignment operator StudyMetaDataFile& operator=(const StudyMetaDataFile& smdf); // append a study metadata file to "this" study metadata file void append(const StudyMetaDataFile& smdf); // append metadata from a cell file to this file void append(CellFile& cf); // append metadata from a cell projection file to this file void append(CellProjectionFile& cpf); // append metadata from a vocabulary file to this file void append(VocabularyFile& vf); // Clears current file data in memory. Deriving classes must override this method and // call AbstractFile::clearAbstractFile() from its clear method. virtual void clear(); // returns true if the file is isEmpty (contains no data) virtual bool empty() const; // add study meta data void addStudyMetaData(StudyMetaData* smd); // delete study meta data void deleteStudyMetaData(const int indx); // delete studies with the given names void deleteStudiesWithNames(const std::vector& namesOfStudiesToDelete); // get the index of a study metadata item int getStudyMetaDataIndex(const StudyMetaData* smdToFind) const; // get the index of study meta data matching the study metadata link (-1 if no match found) int getStudyIndexFromLink(const StudyMetaDataLink& smdl) const; // get study from a PubMed ID (may match PubMed ID or Project ID) int getStudyIndexFromPubMedID(const QString& pubMedID) const; // get study from its name int getStudyIndexFromName(const QString& name) const; /// get study meta data StudyMetaData* getStudyMetaData(const int indx) { return studyMetaData[indx]; } /// get study meta data (const method) const StudyMetaData* getStudyMetaData(const int indx) const { return studyMetaData[indx]; } /// get the number of study metadata int getNumberOfStudyMetaData() const { return studyMetaData.size(); } // find out if comma separated file conversion supported virtual void getCommaSeparatedFileSupport(bool& readFromCSV, bool& writeToCSV) const; // clear study meta data modified (prevents date and time stamp updates) void clearAllStudyMetaDataElementsModified(); // get all medical subject headings void getAllMedicalSubjectHeadings(std::vector& meshOut) const; // get all keywords void getAllKeywords(std::vector& allKeywords) const; // get all citations void getAllCitations(std::vector& allCitations) const; // get all data formats void getAllDataFormats(std::vector& allDataFormats) const; // get all data types void getAllDataTypes(std::vector& allDataTypes) const; // get all keywords used by displayed foci void getAllKeywordsUsedByDisplayedFoci(const FociProjectionFile* fpf, std::vector& keywordsOut) const; // get studies that are linked by displayed foci. Output is sized by number // of studies and true if study is linked by a focus void getStudiesLinkedByDisplayedFoci(const FociProjectionFile* fpf, std::vector& studyLinkedByFocusOut) const; // get all table headers void getAllTableHeaders(std::vector& namesOut) const; // get all table subheader short names void getAllTableSubHeaderShortNames(std::vector& allShortNames) const; // get all table subheader short names used by displayed foci void getAllTableSubHeaderShortNamesUsedByDisplayedFoci(const FociProjectionFile* fpf, std::vector& allShortNamesOut) const; // retrieve data from PubMed using PubMed ID for all studies void updateAllStudiesWithDataFromPubMedDotCom() throw (FileException); // count the number of studies without at least one provenance entry int getNumberOfStudyMetaDatWithoutProvenceEntries() const; // update all studies without a provenance entry void addProvenanceToStudiesWithoutProvenanceEntries(const QString& name, const QString& date, const QString& comment); // find duplicate studies (map key is PubMedID, value is filename) static void findDuplicateStudies(const std::vector& studyFileNames, std::multimap& duplicatesStudiesOut) throw (FileException); // validate the study metadata file (missing table numbers, duplicate studies, etc) QStringList validStudyMetaDataFile() const; /// write the file's memory in caret6 format to the specified name virtual QString writeFileInCaret6Format(const QString& filenameIn, Structure structure,const ColorFile* colorFileIn, const bool useCaret6ExtensionFlag) throw (FileException); protected: // copy helper used by copy constructor and assignment operator void copyHelper(const StudyMetaDataFile& smdf); // Read the contents of the file (header has already been read) virtual void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& rootElement) throw (FileException) ; // Write the file's data (header has already been written) virtual void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& xmlDoc, QDomElement& rootElement) throw (FileException) ; /// the study metadata std::vector studyMetaData; // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // If additional members are added be sure to update copyHelper() method. // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! }; #endif // __STUDY_META_DATA_FILE_H__ caret-5.6.4~dfsg.1.orig/caret_files/StudyMetaDataFile.cxx0000664000175000017500000032230611572067322023104 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ /* * Hierarchy of classes ("has a" classes are indented) * StudyMetaData * Figure * Panel * Table * SubHeader * Page Reference * SubHeader */ #include #include #include #include #include #include #include #include #include #include "AbstractFile.h" #include "CellFile.h" #include "CellProjectionFile.h" #include "CellStudyInfo.h" #include "CommaSeparatedValueFile.h" #include "FileUtilities.h" #include "FociProjectionFile.h" #include "PubMedArticleFile.h" #include "SpecFile.h" #include "StudyMetaDataFile.h" #include "SystemUtilities.h" #include "VocabularyFile.h" #include "XmlGenericWriter.h" #include "XmlGenericWriterAttributes.h" static const QString boldStart(""); static const QString boldEnd(""); static const QString newLine("\n"); /** * Constructor */ StudyMetaData::StudyMetaData() { clear(); } /** * constructor (from old CellStudyInfo). */ StudyMetaData::StudyMetaData(const CellStudyInfo& csi) { clear(); setAuthors(csi.getAuthors()); setTitle(csi.getTitle()); setCitation(csi.getCitation()); setComment(csi.getComment()); setKeywords(csi.getKeywords()); setPartitioningSchemeAbbreviation(csi.getPartitioningSchemeAbbreviation()); setPartitioningSchemeFullName(csi.getPartitioningSchemeFullName()); setStereotaxicSpace(csi.getStereotaxicSpace()); setDocumentObjectIdentifier(csi.getURL()); } /** * Destructor */ StudyMetaData::~StudyMetaData() { clear(); } /** * copy constructor. */ StudyMetaData::StudyMetaData(const StudyMetaData& smd) { parentStudyMetaDataFile = NULL; copyHelper(smd); } /** * assignment operator. */ StudyMetaData& StudyMetaData::operator=(const StudyMetaData& smd) { if (this != &smd) { copyHelper(smd); } return *this; } /** * copy helper used by copy constructor and assignment operator. */ void StudyMetaData::copyHelper(const StudyMetaData& smd) { StudyMetaDataFile* savedParentStudyMetaDataFile = parentStudyMetaDataFile; clear(); authors = smd.authors; citation = smd.citation; comment = smd.comment; documentObjectIdentifier = smd.documentObjectIdentifier; keywords = smd.keywords; medicalSubjectHeadings = smd.medicalSubjectHeadings; name = smd.name; partitioningSchemeAbbreviation = smd.partitioningSchemeAbbreviation; partitioningSchemeFullName = smd.partitioningSchemeFullName; projectID = smd.projectID; pubMedID = smd.pubMedID; quality = smd.quality; species = smd.species; stereotaxicSpace = smd.stereotaxicSpace; stereotaxicSpaceDetails = smd.stereotaxicSpaceDetails; studyDataFormat = smd.studyDataFormat; studyDataType = smd.studyDataType; title = smd.title; // // DO NOT COPY THESE MEMBERS !!! // // dateAndTimeStamps = ""; studyDataModifiedFlag = false; // // Copy children // const int numTables = smd.getNumberOfTables(); for (int i = 0; i < numTables; i++) { addTable(new Table(*(smd.getTable(i)))); } const int numFigures = smd.getNumberOfFigures(); for (int i = 0; i < numFigures; i++) { addFigure(new Figure(*(smd.getFigure(i)))); } const int numPageRefs = smd.getNumberOfPageReferences(); for (int i = 0; i < numPageRefs; i++) { addPageReference(new PageReference(*(smd.getPageReference(i)))); } const int numProv = smd.getNumberOfProvenances(); for (int i = 0; i < numProv; i++) { addProvenance(new Provenance(*(smd.getProvenance(i)))); } parentStudyMetaDataFile = savedParentStudyMetaDataFile; setModified(); } /** * Clear the metadata */ void StudyMetaData::clear() { parentStudyMetaDataFile = NULL; authors = ""; citation = ""; comment = ""; documentObjectIdentifier = ""; keywords = ""; medicalSubjectHeadings = ""; name = ""; partitioningSchemeAbbreviation = ""; partitioningSchemeFullName = ""; projectID = getProjectIDInPubMedIDPrefix() + AbstractFile::generateUniqueNumericTimeStampAsString(); dateAndTimeStamps = ""; pubMedID = projectID; // user can override later quality = ""; species = ""; stereotaxicSpace = ""; stereotaxicSpaceDetails = ""; studyDataFormat = ""; studyDataType = ""; studyDataModifiedFlag = false; title = ""; for (unsigned int i = 0; i < tables.size(); i++) { delete tables[i]; } tables.clear(); for (unsigned int i = 0; i < figures.size(); i++) { delete figures[i]; } figures.clear(); for (unsigned int i = 0; i < pageReferences.size(); i++) { delete pageReferences[i]; } pageReferences.clear(); for (unsigned int i = 0; i < provenances.size(); i++) { delete provenances[i]; } provenances.clear(); } /** * add a figure. */ void StudyMetaData::addFigure(Figure* f) { f->setParent(this); figures.push_back(f); setModified(); } /** * delete a figure. */ void StudyMetaData::deleteFigure(const int indx) { delete figures[indx]; figures.erase(figures.begin() + indx); setModified(); } /** * delete a figure. */ void StudyMetaData::deleteFigure(const Figure* figure) { for (int i = 0; i < getNumberOfFigures(); i++) { if (getFigure(i) == figure) { deleteFigure(i); break; } } } /** * get a figure by its figure number. */ StudyMetaData::Figure* StudyMetaData::getFigureByFigureNumber(const QString& figureNumber) { for (int i = 0; i < getNumberOfFigures(); i++) { Figure* f = getFigure(i); if (f->getNumber() == figureNumber) { return f; } } return NULL; } /** * get a figure by its figure number (const method). */ const StudyMetaData::Figure* StudyMetaData::getFigureByFigureNumber(const QString& figureNumber) const { for (int i = 0; i < getNumberOfFigures(); i++) { const Figure* f = getFigure(i); if (f->getNumber() == figureNumber) { return f; } } return NULL; } /** * add a table. */ void StudyMetaData::addTable(Table* t) { t->setParent(this); tables.push_back(t); setModified(); } /** * delete a table. */ void StudyMetaData::deleteTable(const int indx) { delete tables[indx]; tables.erase(tables.begin() + indx); setModified(); } /** * delete a table. */ void StudyMetaData::deleteTable(const Table* table) { for (int i = 0; i < getNumberOfTables(); i++) { if (getTable(i) == table) { deleteTable(i); break; } } } /** * get a table by its table number. */ StudyMetaData::Table* StudyMetaData::getTableByTableNumber(const QString& tableNumber) { for (int i = 0; i < getNumberOfTables(); i++) { Table* t = getTable(i); if (t->getNumber() == tableNumber) { return t; } } return NULL; } /** * get a table by its table number (const method). */ const StudyMetaData::Table* StudyMetaData::getTableByTableNumber(const QString& tableNumber) const { for (int i = 0; i < getNumberOfTables(); i++) { const Table* t = getTable(i); if (t->getNumber() == tableNumber) { return t; } } return NULL; } /** * get the most recent save date. */ QString StudyMetaData::getMostRecentDateAndTimeStamp() const { QString s; const QStringList sl = dateAndTimeStamps.split(";", QString::SkipEmptyParts); if (sl.count() > 0) { s = sl.at(0); } return s; } /** * add a provenance. */ void StudyMetaData::addProvenance(Provenance* p) { p->setParent(this); provenances.push_back(p); setModified(); } /** * delete a provenance. */ void StudyMetaData::deleteProvenance(const int indx) { delete provenances[indx]; provenances.erase(provenances.begin() + indx); setModified(); } /** * delete a provenance. */ void StudyMetaData::deleteProvenance(const Provenance* p) { for (int i = 0; i < getNumberOfProvenances(); i++) { if (getProvenance(i) == p) { deleteProvenance(i); break; } } } /** * add a page reference. */ void StudyMetaData::addPageReference(PageReference* pr) { pr->setParent(this); pageReferences.push_back(pr); setModified(); } /** * delete a page reference. */ void StudyMetaData::deletePageReference(const int indx) { delete pageReferences[indx]; pageReferences.erase(pageReferences.begin() + indx); setModified(); } /** * delete a page reference. */ void StudyMetaData::deletePageReference(const PageReference* pr) { for (int i = 0; i < getNumberOfPageReferences(); i++) { if (getPageReference(i) == pr) { deletePageReference(i); break; } } } /** * get a page reference by its page number. */ StudyMetaData::PageReference* StudyMetaData::getPageReferenceByPageNumber(const QString& pageNumber) { for (int i = 0; i < getNumberOfPageReferences(); i++) { PageReference* pr = getPageReference(i); if (pr->getPageNumber() == pageNumber) { return pr; } } return NULL; } /** * get a page reference by its page number (const method). */ const StudyMetaData::PageReference* StudyMetaData::getPageReferenceByPageNumber(const QString& pageNumber) const { for (int i = 0; i < getNumberOfPageReferences(); i++) { const PageReference* pr = getPageReference(i); if (pr->getPageNumber() == pageNumber) { return pr; } } return NULL; } /** * equality operator. */ bool StudyMetaData::operator==(const StudyMetaData& cci) const { // // Note: do not compare pubMedID or projectID // const bool theSame = ((authors == cci.authors) && (citation == cci.citation) && (comment == cci.comment) && (documentObjectIdentifier == cci.documentObjectIdentifier) && (keywords == cci.keywords) && (medicalSubjectHeadings == cci.medicalSubjectHeadings) && (name == cci.name) && (partitioningSchemeAbbreviation == cci.partitioningSchemeAbbreviation) && (partitioningSchemeFullName == cci.partitioningSchemeFullName) && (quality == cci.quality) && (species == cci.species) && (stereotaxicSpace == cci.stereotaxicSpace) && (stereotaxicSpaceDetails == cci.stereotaxicSpaceDetails) && (studyDataFormat == cci.studyDataFormat) && (studyDataType == cci.studyDataType) && (title == cci.title)); return theSame; } /** * called to read from an XML structure. */ void StudyMetaData::readXML(QDomNode& nodeIn) throw (FileException) { if (nodeIn.isNull()) { return; } QDomElement elem = nodeIn.toElement(); if (elem.isNull()) { return; } if (elem.tagName() != "StudyMetaData") { QString msg("Incorrect element type passed to StudyMetaData::readXML() "); msg.append(elem.tagName()); throw FileException("", msg); } QString oldURL; QDomNode node = nodeIn.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (elem.tagName() == "authors") { authors = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "citation") { citation = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "comment") { comment = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "documentObjectIdentifier") { documentObjectIdentifier = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "keywords") { keywords = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "mesh") { medicalSubjectHeadings = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "name") { name = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "partitioningSchemeAbbreviation") { partitioningSchemeAbbreviation = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "partitioningSchemeFullName") { partitioningSchemeFullName = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "projectID") { projectID = AbstractFile::getXmlElementFirstChildAsString(elem); } else if ((elem.tagName() == "provenanceDateAndTimeStamps") || (elem.tagName() == "dateAndTimeStamps")) { dateAndTimeStamps = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "pubMedID") { pubMedID = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "quality") { quality = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "species") { species = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "stereotaxicSpace") { stereotaxicSpace = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "stereotaxicSpaceDetails") { stereotaxicSpaceDetails = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "studyDataFormat") { studyDataFormat = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "studyDataType") { studyDataType = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "title") { title = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "mslID") { mslID = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "parentID") { parentID = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "coreDataCompleted") { coreDataCompleted = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "completed") { completed = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "publicAccess") { publicAccess = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "url") { // obsolete oldURL = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "provenance") { // // Obsolete element, ignore it // } else if (elem.tagName() == "StudyMetaDataTable") { Table* t = new Table; t->readXML(node); addTable(t); } else if (elem.tagName() == "StudyMetaDataFigure") { Figure* f = new Figure; f->readXML(node); addFigure(f); } else if (elem.tagName() == "StudyMetaDataPageReference") { PageReference* pr = new PageReference; pr->readXML(node); addPageReference(pr); } else if (elem.tagName() == "StudyMetaDataProvenance") { Provenance* p = new Provenance; p->readXML(node); addProvenance(p); } else { std::cout << "WARNING: unrecognized StudyMetaData element ignored: " << elem.tagName().toAscii().constData() << std::endl; } } node = node.nextSibling(); } // // Older versions of file have both DOI and URL but DOI takes precedence // if (documentObjectIdentifier.isEmpty()) { documentObjectIdentifier = oldURL; } } /** * called to write to an XML structure. */ void StudyMetaData::writeXML(QDomDocument& xmlDoc, QDomElement& parentElement) const throw (FileException) { // // Update data and time stamp if modified flag is set // if (studyDataModifiedFlag) { dateAndTimeStamps = AbstractFile::generateDateAndTimeStamp() + ";" + dateAndTimeStamps; studyDataModifiedFlag = false; } // // Create the element for this class instance's data // QDomElement studyElement = xmlDoc.createElement("StudyMetaData"); // // Add the study metadata // AbstractFile::addXmlCdataElement(xmlDoc, studyElement, "authors", authors); AbstractFile::addXmlCdataElement(xmlDoc, studyElement, "citation", citation); AbstractFile::addXmlCdataElement(xmlDoc, studyElement, "comment", comment); AbstractFile::addXmlCdataElement( xmlDoc, studyElement, "dateAndTimeStamps", dateAndTimeStamps); AbstractFile::addXmlCdataElement(xmlDoc, studyElement, "documentObjectIdentifier", documentObjectIdentifier); AbstractFile::addXmlCdataElement(xmlDoc, studyElement, "keywords", keywords); AbstractFile::addXmlCdataElement(xmlDoc, studyElement, "mesh", medicalSubjectHeadings); AbstractFile::addXmlCdataElement(xmlDoc, studyElement, "name", name); AbstractFile::addXmlCdataElement(xmlDoc, studyElement, "partitioningSchemeAbbreviation", partitioningSchemeAbbreviation); AbstractFile::addXmlCdataElement(xmlDoc, studyElement, "partitioningSchemeFullName", partitioningSchemeFullName); AbstractFile::addXmlCdataElement(xmlDoc, studyElement, "projectID", projectID); AbstractFile::addXmlCdataElement(xmlDoc, studyElement, "pubMedID", pubMedID); AbstractFile::addXmlCdataElement(xmlDoc, studyElement, "quality", quality); AbstractFile::addXmlCdataElement(xmlDoc, studyElement, "species", species); AbstractFile::addXmlCdataElement(xmlDoc, studyElement, "stereotaxicSpace", stereotaxicSpace); AbstractFile::addXmlCdataElement(xmlDoc, studyElement, "stereotaxicSpaceDetails", stereotaxicSpaceDetails); AbstractFile::addXmlCdataElement(xmlDoc, studyElement, "studyDataFormat", studyDataFormat); AbstractFile::addXmlCdataElement(xmlDoc, studyElement, "studyDataType", studyDataType); AbstractFile::addXmlCdataElement(xmlDoc, studyElement, "title", title); AbstractFile::addXmlCdataElement(xmlDoc, studyElement, "mslID", mslID); AbstractFile::addXmlCdataElement(xmlDoc, studyElement, "parentID", parentID); AbstractFile::addXmlCdataElement(xmlDoc, studyElement, "coreDataCompleted", coreDataCompleted); AbstractFile::addXmlCdataElement(xmlDoc, studyElement, "completed", completed); AbstractFile::addXmlCdataElement(xmlDoc, studyElement, "publicAccess", publicAccess); // // Add tables // for (int i = 0; i < getNumberOfTables(); i++) { tables[i]->writeXML(xmlDoc, studyElement); } // // Add figures // for (int i = 0; i < getNumberOfFigures(); i++) { figures[i]->writeXML(xmlDoc, studyElement); } // // Add page references // for (int i = 0; i < getNumberOfPageReferences(); i++) { pageReferences[i]->writeXML(xmlDoc, studyElement); } // // Add provenances // for (int i = 0; i < getNumberOfProvenances(); i++) { provenances[i]->writeXML(xmlDoc, studyElement); } // // Add to parent // parentElement.appendChild(studyElement); } /** * called to write XML. */ void StudyMetaData::writeXML(XmlGenericWriter& xmlWriter, int indx) const throw (FileException) { // // Update data and time stamp if modified flag is set // if (studyDataModifiedFlag) { dateAndTimeStamps = AbstractFile::generateDateAndTimeStamp() + ";" + dateAndTimeStamps; studyDataModifiedFlag = false; } // // Create the element for this class instance's data // XmlGenericWriterAttributes atts; atts.addAttribute("Index", indx); xmlWriter.writeStartElement("StudyMetaData", atts); // // Add the study metadata // xmlWriter.writeElementCData("authors", authors); xmlWriter.writeElementCData("citation", citation); xmlWriter.writeElementCData("comment", comment); xmlWriter.writeElementCData("dateAndTimeStamps", dateAndTimeStamps); xmlWriter.writeElementCData("documentObjectIdentifier", documentObjectIdentifier); xmlWriter.writeElementCData("keywords", keywords); xmlWriter.writeElementCData("mesh", medicalSubjectHeadings); xmlWriter.writeElementCData("name", name); xmlWriter.writeElementCData("partitioningSchemeAbbreviation", partitioningSchemeAbbreviation); xmlWriter.writeElementCData("partitioningSchemeFullName", partitioningSchemeFullName); xmlWriter.writeElementCData("projectID", projectID); xmlWriter.writeElementCData("pubMedID", pubMedID); xmlWriter.writeElementCData("quality", quality); xmlWriter.writeElementCData("species", species); xmlWriter.writeElementCData("stereotaxicSpace", stereotaxicSpace); xmlWriter.writeElementCData("stereotaxicSpaceDetails", stereotaxicSpaceDetails); xmlWriter.writeElementCData("studyDataFormat", studyDataFormat); xmlWriter.writeElementCData("studyDataType", studyDataType); xmlWriter.writeElementCData("title", title); xmlWriter.writeElementCData("mslID", mslID); xmlWriter.writeElementCData("parentID", parentID); xmlWriter.writeElementCData("coreDataCompleted", coreDataCompleted); xmlWriter.writeElementCData("completed", completed); xmlWriter.writeElementCData("publicAccess", publicAccess); // // Add tables // for (int i = 0; i < getNumberOfTables(); i++) { tables[i]->writeXML(xmlWriter); } // // Add figures // for (int i = 0; i < getNumberOfFigures(); i++) { figures[i]->writeXML(xmlWriter); } // // Add page references // for (int i = 0; i < getNumberOfPageReferences(); i++) { pageReferences[i]->writeXML(xmlWriter); } // // Add provenances // for (int i = 0; i < getNumberOfProvenances(); i++) { provenances[i]->writeXML(xmlWriter); } xmlWriter.writeEndElement(); } /** * get the study data format entries. */ void StudyMetaData::getStudyDataFormatEntries(std::vector& entries) { entries.clear(); entries.push_back("Stereotaxic Foci"); entries.push_back("Metric"); entries.push_back("Surface Shape"); entries.push_back("Paint"); entries.push_back("Volume"); entries.push_back("Surface"); std::sort(entries.begin(), entries.end()); } /** * get the study data type entries. */ void StudyMetaData::getStudyDataTypeEntries(std::vector& entries) { entries.clear(); entries.push_back("fMRI"); entries.push_back("PET"); entries.push_back("Morphometry"); entries.push_back("Connectivity"); entries.push_back("Partitioning Scheme"); entries.push_back("ERP"); entries.push_back("VEP"); entries.push_back("Lesion"); entries.push_back("EEG"); entries.push_back("TMS"); entries.push_back("DTI"); entries.push_back("MEG"); entries.push_back("Single Unit Neurophysiology"); entries.push_back("Multi-Unit Neurophysiology"); std::sort(entries.begin(), entries.end()); entries.push_back("Other"); } /** * retrieve data from PubMed using PubMed ID. */ void StudyMetaData::updateDataFromPubMedDotComUsingPubMedID() throw (FileException) { // // Make sure a PubMed ID was entered // if (pubMedID.isEmpty()) { throw FileException("The PubMed ID has not been entered."); return; } // // Get the article // PubMedArticleFile pubMedFile; pubMedFile.retrieveArticleWithPubMedID(pubMedID); // may throw FileException if (pubMedFile.getArticleTitle().isEmpty() == false) { setTitle(pubMedFile.getArticleTitle()); } if (pubMedFile.getAuthors().isEmpty() == false) { setAuthors(pubMedFile.getAuthors()); } if (pubMedFile.getJournalTitle().isEmpty() == false) { setCitation(pubMedFile.getJournalTitle()); } if (pubMedFile.getDocumentObjectIdentifier().isEmpty() == false) { setDocumentObjectIdentifier(pubMedFile.getDocumentObjectIdentifier()); } if (pubMedFile.getAbstractText().isEmpty() == false) { setComment(pubMedFile.getAbstractText()); } if (pubMedFile.getMedicalSubjectHeadings().isEmpty() == false) { setMedicalSubjectHeadings(pubMedFile.getMedicalSubjectHeadings()); } } /** * see if the PubMed ID is actually a Project ID. */ bool StudyMetaData::getPubMedIDIsAProjectID() const { return (pubMedID.startsWith(getProjectIDInPubMedIDPrefix())); } /** * set the PubMed ID. */ void StudyMetaData::setPubMedID(const QString& pmid) { if (pubMedID != pmid) { pubMedID = pmid; setModified(); } } /** * set the project id. */ void StudyMetaData::setProjectID(const QString& pid) { if (projectID != pid) { projectID = pid; setModified(); } } /** * set keywords. */ void StudyMetaData::setKeywords(const QString& s) { if (keywords != s) { keywords = s; setModified(); } } /** * set medical subject headings. */ void StudyMetaData::setMedicalSubjectHeadings(const QString& s) { if (medicalSubjectHeadings != s) { medicalSubjectHeadings = s; setModified(); } } /** * set name. */ void StudyMetaData::setName(const QString& s) { if (name != s) { name = s; setModified(); } } /** * set the quality. */ void StudyMetaData::setQuality(const QString& s) { if (quality != s) { quality = s; setModified(); } } /** * set the study data format. */ void StudyMetaData::setStudyDataFormat(const QString& s) { if (studyDataFormat != s) { studyDataFormat = s; setModified(); } } /** * set the study data type. */ void StudyMetaData::setStudyDataType(const QString& s) { if (studyDataType != s) { studyDataType = s; setModified(); } } /** * set title. */ void StudyMetaData::setTitle(const QString& s) { if (title != s) { title = s; setModified(); } } /** * set MSL ID. */ void StudyMetaData::setMslID(const QString& s) { if (mslID != s) { mslID = s; setModified(); } } /** * set parent ID. */ void StudyMetaData::setParentID(const QString& s) { if (parentID != s) { parentID = s; setModified(); } } /** * set core metadata. */ void StudyMetaData::setCoreDataCompleted(const QString& s) { if (coreDataCompleted != s) { coreDataCompleted = s; setModified(); } } /** * set completed. */ void StudyMetaData::setCompleted(const QString& s) { if (completed != s) { completed = s; setModified(); } } /** * set public access. */ void StudyMetaData::setPublicAccess(const QString& s) { if (publicAccess != s) { publicAccess = s; setModified(); } } /** * set authors. */ void StudyMetaData::setAuthors(const QString& s) { if (authors != s) { authors = s; setModified(); } } /** * set citation. */ void StudyMetaData::setCitation(const QString& s) { if (citation != s) { citation = s; setModified(); } } /** * set species. */ void StudyMetaData::setSpecies(const QString& s) { if (species != s) { species = s; setModified(); } } /** * set stereotaxic space. */ void StudyMetaData::setStereotaxicSpace(const QString& s) { if (stereotaxicSpace != s) { stereotaxicSpace = s; setModified(); } } /** * set stereotaxic space details. */ void StudyMetaData::setStereotaxicSpaceDetails(const QString& s) { if (stereotaxicSpaceDetails != s) { stereotaxicSpaceDetails = s; setModified(); } } /** * set comment. */ void StudyMetaData::setComment(const QString& s) { if (comment != s) { comment = s; setModified(); } } /** * set partitioning scheme abbreviation. */ void StudyMetaData::setPartitioningSchemeAbbreviation(const QString& s) { if (partitioningSchemeAbbreviation != s) { partitioningSchemeAbbreviation = s; setModified(); } } /** * set the date and time stamps. */ void StudyMetaData::setDateAndTimeStamps(const QString& p) { dateAndTimeStamps = p; // // NOTE: DO NOT SET MODIFIED STATUS // } /** * set partitioning scheme full name. */ void StudyMetaData::setPartitioningSchemeFullName(const QString& s) { if (partitioningSchemeFullName != s) { partitioningSchemeFullName = s; setModified(); } } /** * set the document object identifier. */ void StudyMetaData::setDocumentObjectIdentifier(const QString& doi) { if (documentObjectIdentifier != doi) { documentObjectIdentifier = doi; setModified(); } } /** * set parent. */ void StudyMetaData::setParent(StudyMetaDataFile* parentStudyMetaDataFileIn) { parentStudyMetaDataFile = parentStudyMetaDataFileIn; } /** * clear this study info is modified. */ void StudyMetaData::clearModified() { studyDataModifiedFlag = false; } /** * set this study info is modified. */ void StudyMetaData::setModified() { studyDataModifiedFlag = true; if (parentStudyMetaDataFile != NULL) { parentStudyMetaDataFile->setModified(); } } /** * get medical subject headings. */ void StudyMetaData::getMedicalSubjectHeadings(std::vector& meshOut) const { meshOut.clear(); const QStringList sl = getMedicalSubjectHeadings().split(';', QString::SkipEmptyParts); for (int k = 0; k < sl.size(); k++) { const QString m = sl.at(k).trimmed(); if (m.isEmpty() == false) { meshOut.push_back(m); } } } /** * get the keywords. */ void StudyMetaData::getKeywords(std::vector& keywordsOut) const { static QRegExp regEx(";|\\*|\\|"); keywordsOut.clear(); const QStringList sl = getKeywords().split(regEx, QString::SkipEmptyParts); for (int k = 0; k < sl.size(); k++) { const QString kw = sl.at(k).trimmed(); if (kw.isEmpty() == false) { keywordsOut.push_back(kw); } } } /** * see if study contains a keyword. */ bool StudyMetaData::containsKeyword(const QString& kw) const { std::vector words; getKeywords(words); if (std::find(words.begin(), words.end(), kw) != words.end()) { return true; } return false; } /** * see if study contains a sub header short names. */ bool StudyMetaData::containsSubHeaderShortName(const QString& shsn) const { std::vector shortNames; getAllTableSubHeaderShortNames(shortNames); if (std::find(shortNames.begin(), shortNames.end(), shsn) != shortNames.end()) { return true; } return false; } /** * get all table sub header short names in this study. */ void StudyMetaData::getAllTableSubHeaderShortNames(std::vector& tableSubHeaderShortNamesOut) const { tableSubHeaderShortNamesOut.clear(); const int numTables = getNumberOfTables(); for (int i = 0; i < numTables; i++) { const Table* table = getTable(i); const int numSubHeaders = table->getNumberOfSubHeaders(); for (int j = 0; j < numSubHeaders; j++) { const SubHeader* sh = table->getSubHeader(j); const QString shortName = sh->getShortName(); if (shortName.isEmpty() == false) { tableSubHeaderShortNamesOut.push_back(shortName); } } } } /** * get all table headers. */ void StudyMetaData::getAllTableHeaders(std::vector& headersOut) const { headersOut.clear(); const int numTables = getNumberOfTables(); for (int i = 0; i < numTables; i++) { const Table* table = getTable(i); const QString h = table->getHeader().trimmed(); if (h.isEmpty() == false) { headersOut.push_back(h); } } } //==================================================================================== // // Figure class // //==================================================================================== /** * constructor. */ StudyMetaData::Figure::Figure() { clear(); } /** * destructor. */ StudyMetaData::Figure::~Figure() { clear(); } /** * copy constructor. */ StudyMetaData::Figure::Figure(const Figure& f) { parentStudyMetaData = NULL; copyHelper(f); } /** * assignment operator. */ StudyMetaData::Figure& StudyMetaData::Figure::operator=(const Figure& f) { if (this != &f) { copyHelper(f); } return *this; } /** * copy helper used by copy constructor and assignment operator. */ void StudyMetaData::Figure::copyHelper(const Figure& f) { StudyMetaData* savedParentStudyMetaData = parentStudyMetaData; clear(); legend = f.legend; number = f.number; const int numPanels = f.getNumberOfPanels(); for (int i = 0; i < numPanels; i++) { addPanel(new Panel(*(f.getPanel(i)))); } parentStudyMetaData = savedParentStudyMetaData; setModified(); } /** * clear the figure information. */ void StudyMetaData::Figure::clear() { parentStudyMetaData = NULL; legend = ""; number = "1"; for (unsigned int i = 0; i < panels.size(); i++) { delete panels[i]; } panels.clear(); } /** * add a panel. */ void StudyMetaData::Figure::addPanel(Panel* p) { p->setParent(this); panels.push_back(p); setModified(); } /** * delete a panel. */ void StudyMetaData::Figure::deletePanel(const int indx) { delete panels[indx]; panels.erase(panels.begin() + indx); setModified(); } /** * delete a panel. */ void StudyMetaData::Figure::deletePanel(const Panel* panel) { for (int i = 0; i < getNumberOfPanels(); i++) { if (getPanel(i) == panel) { deletePanel(i); break; } } } /** * get a panel by its panel number/letter. */ StudyMetaData::Figure::Panel* StudyMetaData::Figure::getPanelByPanelNumberOrLetter(const QString& panelNumberOrLetter) { for (int i = 0; i < getNumberOfPanels(); i++) { Panel* p = getPanel(i); if (p->getPanelNumberOrLetter() == panelNumberOrLetter) { return p; } } return NULL; } /** * get a panel by its panel number/letter (const method). */ const StudyMetaData::Figure::Panel* StudyMetaData::Figure::getPanelByPanelNumberOrLetter(const QString& panelNumberOrLetter) const { for (int i = 0; i < getNumberOfPanels(); i++) { const Panel* p = getPanel(i); if (p->getPanelNumberOrLetter() == panelNumberOrLetter) { return p; } } return NULL; } /** * set the legend. */ void StudyMetaData::Figure::setLegend(const QString& s) { if (legend != s) { legend = s; setModified(); } } /** * set the figure number. */ void StudyMetaData::Figure::setNumber(const QString& n) { if (number != n) { number = n; setModified(); } } /** * set modified status. */ void StudyMetaData::Figure::setModified() { if (parentStudyMetaData != NULL) { parentStudyMetaData->setModified(); } } /** * set parent. */ void StudyMetaData::Figure::setParent(StudyMetaData* parentStudyMetaDataIn) { parentStudyMetaData = parentStudyMetaDataIn; } /** * called to read from an XML structure. */ void StudyMetaData::Figure::readXML(QDomNode& nodeIn) throw (FileException) { if (nodeIn.isNull()) { return; } QDomElement elem = nodeIn.toElement(); if (elem.isNull()) { return; } if (elem.tagName() != "StudyMetaDataFigure") { QString msg("Incorrect element type passed to StudyMetaData::Figure::readXML() "); msg.append(elem.tagName()); throw FileException("", msg); } QDomNode node = nodeIn.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (elem.tagName() == "legend") { legend = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "number") { number = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "StudyMetaDataFigurePanel") { Panel* p = new Panel; p->readXML(node); addPanel(p); } else { std::cout << "WARNING: unrecognized StudyMetaData::Figure element ignored: " << elem.tagName().toAscii().constData() << std::endl; } } node = node.nextSibling(); } } /** * called to write to an XML structure. */ void StudyMetaData::Figure::writeXML(QDomDocument& xmlDoc, QDomElement& parentElement) const throw (FileException) { // // Create the element for this class instance's data // QDomElement element = xmlDoc.createElement("StudyMetaDataFigure"); // // write data // AbstractFile::addXmlCdataElement(xmlDoc, element, "legend", legend); AbstractFile::addXmlCdataElement(xmlDoc, element, "number", number); // // write panels // for (int i = 0; i < getNumberOfPanels(); i++) { panels[i]->writeXML(xmlDoc, element); } // // Add to parent // parentElement.appendChild(element); } /** * called to write XML. */ void StudyMetaData::Figure::writeXML(XmlGenericWriter& xmlWriter) const throw (FileException) { xmlWriter.writeStartElement("StudyMetaDataFigure"); xmlWriter.writeElementCData("legend", legend); xmlWriter.writeElementCData("number", number); for (int i = 0; i < getNumberOfPanels(); i++) { panels[i]->writeXML(xmlWriter); } xmlWriter.writeEndElement(); } //==================================================================================== // // Figure Panel class // //==================================================================================== /** * constructor. */ StudyMetaData::Figure::Panel::Panel() { clear(); } /** * destructor. */ StudyMetaData::Figure::Panel::~Panel() { clear(); } /** * copy constructor. */ StudyMetaData::Figure::Panel::Panel(const Panel& p) { parentFigure = NULL; copyHelper(p); } /** * assignment operator. */ StudyMetaData::Figure::Panel& StudyMetaData::Figure::Panel::operator=(const Panel& p) { if (this != &p) { copyHelper(p); } return *this; } /** * copy helper used by copy constructor and assignment operator. */ void StudyMetaData::Figure::Panel::copyHelper(const Panel& p) { Figure* savedParentFigure = parentFigure; clear(); description = p.description; panelNumberOrLetter = p.panelNumberOrLetter; taskDescription = p.taskDescription; taskBaseline = p.taskBaseline; testAttributes = p.testAttributes; parentFigure = savedParentFigure; setModified(); } /** * clear the panel's data. */ void StudyMetaData::Figure::Panel::clear() { parentFigure = NULL; panelNumberOrLetter = ""; description = ""; taskDescription = ""; taskBaseline = ""; testAttributes = ""; } /** * set the panel number/letter. */ void StudyMetaData::Figure::Panel::setPanelNumberOrLetter(const QString& s) { if (panelNumberOrLetter != s) { panelNumberOrLetter = s; setModified(); } } /** * set the description. */ void StudyMetaData::Figure::Panel::setDescription(const QString& s) { if (description != s) { description = s; setModified(); } } /** * set Task Description. */ void StudyMetaData::Figure::Panel::setTaskDescription(const QString& s) { if (taskDescription != s) { taskDescription = s; setModified(); } } /** * set TaskBaseline. */ void StudyMetaData::Figure::Panel::setTaskBaseline(const QString& s) { if (taskBaseline != s) { taskBaseline = s; setModified(); } } /** * set TestAttributes. */ void StudyMetaData::Figure::Panel::setTestAttributes(const QString& s) { if (testAttributes != s) { testAttributes = s; setModified(); } } /** * set modified status. */ void StudyMetaData::Figure::Panel::setModified() { if (parentFigure != NULL) { parentFigure->setModified(); } } /** * set parent. */ void StudyMetaData::Figure::Panel::setParent(Figure* parentFigureIn) { parentFigure = parentFigureIn; } /** * called to read from an XML structure. */ void StudyMetaData::Figure::Panel::readXML(QDomNode& nodeIn) throw (FileException) { if (nodeIn.isNull()) { return; } QDomElement elem = nodeIn.toElement(); if (elem.isNull()) { return; } if (elem.tagName() != "StudyMetaDataFigurePanel") { QString msg("Incorrect element type passed to StudyMetaData::Figure::Panel::readXML() "); msg.append(elem.tagName()); throw FileException("", msg); } QDomNode node = nodeIn.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (elem.tagName() == "description") { description = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "panelNumberOrLetter") { panelNumberOrLetter = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "taskDescription") { taskDescription = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "taskBaseline") { taskBaseline = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "testAttributes") { testAttributes = AbstractFile::getXmlElementFirstChildAsString(elem); } else { std::cout << "WARNING: unrecognized StudyMetaData::Figure::Panel element ignored: " << elem.tagName().toAscii().constData() << std::endl; } } node = node.nextSibling(); } } /** * called to write to an XML structure. */ void StudyMetaData::Figure::Panel::writeXML(QDomDocument& xmlDoc, QDomElement& parentElement) const throw (FileException) { // // Create the element for this class instance's data // QDomElement element = xmlDoc.createElement("StudyMetaDataFigurePanel"); // // write data // AbstractFile::addXmlCdataElement(xmlDoc, element, "description", description); AbstractFile::addXmlCdataElement(xmlDoc, element, "panelNumberOrLetter", panelNumberOrLetter); AbstractFile::addXmlCdataElement(xmlDoc, element, "taskDescription", taskDescription); AbstractFile::addXmlCdataElement(xmlDoc, element, "taskBaseline", taskBaseline); AbstractFile::addXmlCdataElement(xmlDoc, element, "testAttributes", testAttributes); // // Add to parent // parentElement.appendChild(element); } /** * called to write XML. */ void StudyMetaData::Figure::Panel::writeXML(XmlGenericWriter& xmlWriter) const throw (FileException) { xmlWriter.writeStartElement("StudyMetaDataFigurePanel"); xmlWriter.writeElementCData("description", description); xmlWriter.writeElementCData("panelNumberOrLetter", panelNumberOrLetter); xmlWriter.writeElementCData("taskDescription", taskDescription); xmlWriter.writeElementCData("taskBaseline", taskBaseline); xmlWriter.writeElementCData("testAttributes", testAttributes); xmlWriter.writeEndElement(); } //==================================================================================== // // Table class // //==================================================================================== /** * constructor. */ StudyMetaData::Table::Table() { clear(); } /** * destructor. */ StudyMetaData::Table::~Table() { clear(); } /** * copy constructor. */ StudyMetaData::Table::Table(const Table& t) { parentStudyMetaData = NULL; copyHelper(t); } /** * assignment operator. */ StudyMetaData::Table& StudyMetaData::Table::operator=(const Table& t) { if (this != &t) { copyHelper(t); } return *this; } /** * copy helper used by copy constructor and assignment operator. */ void StudyMetaData::Table::copyHelper(const Table& t) { StudyMetaData* savedParentStudyMetaData = parentStudyMetaData; clear(); footer = t.footer; header = t.header; number = t.number; sizeUnits = t.sizeUnits; statisticType = t.statisticType; statisticDescription = t.statisticDescription; voxelDimensions = t.voxelDimensions; const int numSubHeaders = t.getNumberOfSubHeaders(); for (int i = 0; i < numSubHeaders; i++) { addSubHeader(new SubHeader(*(t.getSubHeader(i)))); } parentStudyMetaData = savedParentStudyMetaData; setModified(); } /** * clear the table. */ void StudyMetaData::Table::clear() { parentStudyMetaData = NULL; footer = ""; header = ""; number = "1"; sizeUnits = ""; statisticType = ""; statisticDescription = ""; voxelDimensions = ""; for (unsigned int i = 0; i < subHeaders.size(); i++) { delete subHeaders[i]; subHeaders[i] = NULL; } subHeaders.clear(); } /** * add a sub header. */ void StudyMetaData::Table::addSubHeader(SubHeader* sh) { sh->setParent(this); subHeaders.push_back(sh); setModified(); } /** * delete a sub header. */ void StudyMetaData::Table::deleteSubHeader(const int indx) { delete subHeaders[indx]; subHeaders.erase(subHeaders.begin() + indx); setModified(); } /** * delete a sub header. */ void StudyMetaData::Table::deleteSubHeader(const SubHeader* subHeader) { for (int i = 0; i < getNumberOfSubHeaders(); i++) { if (getSubHeader(i) == subHeader) { deleteSubHeader(i); break; } } } /** * get a sub header by sub header number. */ StudyMetaData::SubHeader* StudyMetaData::Table::getSubHeaderBySubHeaderNumber(const QString& subHeaderNumber) { for (int i = 0; i < getNumberOfSubHeaders(); i++) { SubHeader* sh = getSubHeader(i); if (sh->getNumber() == subHeaderNumber) { return sh; } } return NULL; } /** * get a sub header by sub header number (const method). */ const StudyMetaData::SubHeader* StudyMetaData::Table::getSubHeaderBySubHeaderNumber(const QString& subHeaderNumber) const { for (int i = 0; i < getNumberOfSubHeaders(); i++) { const SubHeader* sh = getSubHeader(i); if (sh->getNumber() == subHeaderNumber) { return sh; } } return NULL; } /** * set footer. */ void StudyMetaData::Table::setFooter(const QString& s) { if (footer != s) { footer = s; setModified(); } } /** * set header. */ void StudyMetaData::Table::setHeader(const QString& s) { if (header != s) { header = s; setModified(); } } /** * set number. */ void StudyMetaData::Table::setNumber(const QString& n) { if (number != n) { number = n; setModified(); } } /** * set size units. */ void StudyMetaData::Table::setSizeUnits(const QString& s) { if (sizeUnits != s) { sizeUnits = s; setModified(); } } /** * set tatistic type. */ void StudyMetaData::Table::setStatisticType(const QString& s) { if (statisticType != s) { statisticType = s; setModified(); } } /** * set statistic description. */ void StudyMetaData::Table::setStatisticDescription(const QString& s) { if (statisticDescription != s) { statisticDescription = s; setModified(); } } /** * set voxelDimensions. */ void StudyMetaData::Table::setVoxelDimensions(const QString& s) { if (voxelDimensions != s) { voxelDimensions = s; setModified(); } } /** * set modified. */ void StudyMetaData::Table::setModified() { if (parentStudyMetaData != NULL) { parentStudyMetaData->setModified(); } } /** * set parent. */ void StudyMetaData::Table::setParent(StudyMetaData* parentStudyMetaDataIn) { parentStudyMetaData = parentStudyMetaDataIn; } /** * called to read from an XML structure. */ void StudyMetaData::Table::readXML(QDomNode& nodeIn) throw (FileException) { if (nodeIn.isNull()) { return; } QDomElement elem = nodeIn.toElement(); if (elem.isNull()) { return; } if (elem.tagName() != "StudyMetaDataTable") { QString msg("Incorrect element type passed to StudyMetaData::Table::readXML() "); msg.append(elem.tagName()); throw FileException("", msg); } QDomNode node = nodeIn.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (elem.tagName() == "footer") { footer = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "header") { header = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "number") { number = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "sizeUnits") { sizeUnits = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "statisticType") { statisticType = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "statisticDescription") { statisticDescription = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "voxelDimensions") { voxelDimensions = AbstractFile::getXmlElementFirstChildAsString(elem); } else if ((elem.tagName() == "StudyMetaDataSubHeader") || (elem.tagName() == "StudyMetaDataTableSubHeader")) { SubHeader* sh = new SubHeader; sh->readXML(node); addSubHeader(sh); } else { std::cout << "WARNING: unrecognized StudyMetaData::Table element ignored: " << elem.tagName().toAscii().constData() << std::endl; } } node = node.nextSibling(); } } /** * called to write to an XML structure. */ void StudyMetaData::Table::writeXML(QDomDocument& xmlDoc, QDomElement& parentElement) const throw (FileException) { // // Create the element for this class instance's data // QDomElement element = xmlDoc.createElement("StudyMetaDataTable"); // // write data // AbstractFile::addXmlCdataElement(xmlDoc, element, "footer", footer); AbstractFile::addXmlCdataElement(xmlDoc, element, "header", header); AbstractFile::addXmlCdataElement(xmlDoc, element, "number", number); AbstractFile::addXmlCdataElement(xmlDoc, element, "sizeUnits", sizeUnits); AbstractFile::addXmlCdataElement(xmlDoc, element, "statisticType", statisticType); AbstractFile::addXmlCdataElement(xmlDoc, element, "statisticDescription", statisticDescription); AbstractFile::addXmlCdataElement( xmlDoc, element, "voxelDimensions", voxelDimensions); // // write sub headers // for (int i = 0; i < getNumberOfSubHeaders(); i++) { subHeaders[i]->writeXML(xmlDoc, element); } // // Add to parent // parentElement.appendChild(element); } /** * called to write XML. */ void StudyMetaData::Table::writeXML(XmlGenericWriter& xmlWriter) const throw (FileException) { xmlWriter.writeStartElement("StudyMetaDataTable"); xmlWriter.writeElementCData("footer", footer); xmlWriter.writeElementCData("header", header); xmlWriter.writeElementCData("number", number); xmlWriter.writeElementCData("sizeUnits", sizeUnits); xmlWriter.writeElementCData("statisticType", statisticType); xmlWriter.writeElementCData("statisticDescription", statisticDescription); xmlWriter.writeElementCData("voxelDimensions", voxelDimensions); for (int i = 0; i < getNumberOfSubHeaders(); i++) { subHeaders[i]->writeXML(xmlWriter); } xmlWriter.writeEndElement(); } //==================================================================================== // // SubHeader class // //==================================================================================== /** * constructor */ StudyMetaData::SubHeader::SubHeader() { clear(); } /** * destructor */ StudyMetaData::SubHeader::~SubHeader() { clear(); } /** * copy constructor. */ StudyMetaData::SubHeader::SubHeader(const SubHeader& sh) { parentPageReference = NULL; parentTable = NULL; copyHelper(sh); } /** * assignment operator. */ StudyMetaData::SubHeader& StudyMetaData::SubHeader::operator=(const SubHeader& sh) { if (this != &sh) { copyHelper(sh); } return *this; } /** * copy helper used by copy constructor and assignment operator. */ void StudyMetaData::SubHeader::copyHelper(const SubHeader& sh) { PageReference* savedParentPageReference = parentPageReference; Table* savedParentTable = parentTable; clear(); name = sh.name; number = sh.number; shortName = sh.shortName; taskDescription = sh.taskDescription; taskBaseline = sh.taskBaseline; testAttributes = sh.testAttributes; selectedFlag = sh.selectedFlag; parentPageReference = savedParentPageReference; parentTable = savedParentTable; setModified(); } /** * clear the sub header. */ void StudyMetaData::SubHeader::clear() { parentPageReference = NULL; parentTable = NULL; name = ""; number = "1"; shortName = ""; taskDescription = ""; taskBaseline = ""; testAttributes = ""; selectedFlag = true; } /** * set name. */ void StudyMetaData::SubHeader::setName(const QString& s) { if (name != s) { name = s; setModified(); } } /** * set number. */ void StudyMetaData::SubHeader::setNumber(const QString& n) { if (number != n) { number = n; setModified(); } } /** * set short name. */ void StudyMetaData::SubHeader::setShortName(const QString& s) { if (shortName != s) { shortName = s.trimmed(); setModified(); } } /** * set Task Description. */ void StudyMetaData::SubHeader::setTaskDescription(const QString& s) { if (taskDescription != s) { taskDescription = s; setModified(); } } /** * set TaskBaseline. */ void StudyMetaData::SubHeader::setTaskBaseline(const QString& s) { if (taskBaseline != s) { taskBaseline = s; setModified(); } } /** * set TestAttributes. */ void StudyMetaData::SubHeader::setTestAttributes(const QString& s) { if (testAttributes != s) { testAttributes = s; setModified(); } } /** * set instance modified. */ void StudyMetaData::SubHeader::setModified() { if (parentPageReference != NULL) { parentPageReference->setModified(); } if (parentTable != NULL) { parentTable->setModified(); } } /** * set parent. */ void StudyMetaData::SubHeader::setParent(Table* parentTableIn) { parentTable = parentTableIn; } /** * set parent. */ void StudyMetaData::SubHeader::setParent(PageReference* parentPageReferenceIn) { parentPageReference= parentPageReferenceIn; } /** * called to read from an XML structure. */ void StudyMetaData::SubHeader::readXML(QDomNode& nodeIn) throw (FileException) { if (nodeIn.isNull()) { return; } QDomElement elem = nodeIn.toElement(); if (elem.isNull()) { return; } if ((elem.tagName() != "StudyMetaDataTableSubHeader") && (elem.tagName() != "StudyMetaDataSubHeader")) { QString msg("Incorrect element type passed to StudyMetaData::SubHeader::readXML() "); msg.append(elem.tagName()); throw FileException("", msg); } QDomNode node = nodeIn.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (elem.tagName() == "name") { name = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "number") { number = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "shortName") { shortName = AbstractFile::getXmlElementFirstChildAsString(elem).trimmed(); } else if (elem.tagName() == "taskDescription") { taskDescription = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "taskBaseline") { taskBaseline = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "testAttributes") { testAttributes = AbstractFile::getXmlElementFirstChildAsString(elem); } else { std::cout << "WARNING: unrecognized StudyMetaData::SubHeader element ignored: " << elem.tagName().toAscii().constData() << std::endl; } } node = node.nextSibling(); } } /** * called to write to an XML structure. */ void StudyMetaData::SubHeader::writeXML(QDomDocument& xmlDoc, QDomElement& parentElement) const throw (FileException) { // // Create the element for this class instance's data // QDomElement element = xmlDoc.createElement("StudyMetaDataSubHeader"); // // write data // AbstractFile::addXmlCdataElement(xmlDoc, element, "name", name); AbstractFile::addXmlCdataElement(xmlDoc, element, "number", number); AbstractFile::addXmlCdataElement(xmlDoc, element, "shortName", shortName); AbstractFile::addXmlCdataElement(xmlDoc, element, "taskDescription", taskDescription); AbstractFile::addXmlCdataElement(xmlDoc, element, "taskBaseline", taskBaseline); AbstractFile::addXmlCdataElement(xmlDoc, element, "testAttributes", testAttributes); // // Add to parent // parentElement.appendChild(element); } /** * called to write XML. */ void StudyMetaData::SubHeader::writeXML(XmlGenericWriter& xmlWriter) const throw (FileException) { xmlWriter.writeStartElement("StudyMetaDataSubHeader"); xmlWriter.writeElementCData("name", name); xmlWriter.writeElementCData("number", number); xmlWriter.writeElementCData("shortName", shortName); xmlWriter.writeElementCData("taskDescription", taskDescription); xmlWriter.writeElementCData("taskBaseline", taskBaseline); xmlWriter.writeElementCData("testAttributes", testAttributes); xmlWriter.writeEndElement(); } //==================================================================================== // // Page Reference class // //==================================================================================== /** * constructor. */ StudyMetaData::PageReference::PageReference() { parentStudyMetaData = NULL; clear(); } /** * destructor. */ StudyMetaData::PageReference::~PageReference() { clear(); } /** * copy constructor. */ StudyMetaData::PageReference::PageReference(const PageReference& pr) { parentStudyMetaData = NULL; copyHelper(pr); } /** * assignment operator. */ StudyMetaData::PageReference& StudyMetaData::PageReference::operator=(const PageReference& pr) { if (this != &pr) { copyHelper(pr); } return *this; } /** * clear the page link. */ void StudyMetaData::PageReference::clear() { pageNumber = "1"; header = ""; comment = ""; sizeUnits = ""; voxelDimensions = ""; statisticType = ""; statisticDescription = ""; for (int i = 0; i < getNumberOfSubHeaders(); i++) { delete subHeaders[i]; subHeaders[i] = NULL; } subHeaders.clear(); } /** * add a sub header. */ void StudyMetaData::PageReference::addSubHeader(SubHeader* sh) { sh->setParent(this); subHeaders.push_back(sh); setModified(); } /** * delete a sub header. */ void StudyMetaData::PageReference::deleteSubHeader(const int indx) { delete subHeaders[indx]; subHeaders.erase(subHeaders.begin() + indx); setModified(); } /** * delete a sub header. */ void StudyMetaData::PageReference::deleteSubHeader(const SubHeader* subHeader) { for (int i = 0; i < getNumberOfSubHeaders(); i++) { if (getSubHeader(i) == subHeader) { deleteSubHeader(i); break; } } } /** * get a sub header by sub header number. */ StudyMetaData::SubHeader* StudyMetaData::PageReference::getSubHeaderBySubHeaderNumber(const QString& subHeaderNumber) { for (int i = 0; i < getNumberOfSubHeaders(); i++) { SubHeader* sh = getSubHeader(i); if (sh->getNumber() == subHeaderNumber) { return sh; } } return NULL; } /** * get a sub header by sub header number (const method). */ const StudyMetaData::SubHeader* StudyMetaData::PageReference::getSubHeaderBySubHeaderNumber(const QString& subHeaderNumber) const { for (int i = 0; i < getNumberOfSubHeaders(); i++) { const SubHeader* sh = getSubHeader(i); if (sh->getNumber() == subHeaderNumber) { return sh; } } return NULL; } /** * copy helper. */ void StudyMetaData::PageReference::copyHelper(const PageReference& pr) { StudyMetaData* savedParentStudyMetaData = parentStudyMetaData; clear(); pageNumber = pr.pageNumber; header = pr.header; comment = pr.comment; sizeUnits = pr.sizeUnits; voxelDimensions = pr.voxelDimensions; statisticType = pr.statisticType; statisticDescription = pr.statisticDescription; const int numSubHeaders = pr.getNumberOfSubHeaders(); for (int i = 0; i < numSubHeaders; i++) { addSubHeader(new SubHeader(*(pr.getSubHeader(i)))); } parentStudyMetaData = savedParentStudyMetaData; setModified(); } /** * set the page number. */ void StudyMetaData::PageReference::setPageNumber(const QString& pn) { if (pageNumber != pn) { pageNumber = pn; setModified(); } } /** * set the header. */ void StudyMetaData::PageReference::setHeader(const QString& s) { if (header != s) { header = s; setModified(); } } /** * set the comment. */ void StudyMetaData::PageReference::setComment(const QString& s) { if(comment != s) { comment = s; setModified(); } } /** * set the size units. */ void StudyMetaData::PageReference::setSizeUnits(const QString& s) { if (sizeUnits != s) { sizeUnits = s; setModified(); } } /** * set the voxel size. */ void StudyMetaData::PageReference::setVoxelDimensions(const QString& s) { if (voxelDimensions != s) { voxelDimensions = s; setModified(); } } /** * set the statistic. */ void StudyMetaData::PageReference::setStatisticType(const QString& s) { if (statisticType != s) { statisticType = s; setModified(); } } /** * set the statistic description. */ void StudyMetaData::PageReference::setStatisticDescription(const QString& s) { if (statisticDescription != s) { statisticDescription = s; setModified(); } } /** * called to read from an XML structure. */ void StudyMetaData::PageReference::readXML(QDomNode& nodeIn) throw (FileException) { if (nodeIn.isNull()) { return; } QDomElement elem = nodeIn.toElement(); if (elem.isNull()) { return; } if (elem.tagName() != "StudyMetaDataPageReference") { QString msg("Incorrect element type passed to StudyMetaData::PageReference::readXML() "); msg.append(elem.tagName()); throw FileException("", msg); } QDomNode node = nodeIn.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (elem.tagName() == "pageNumber") { pageNumber = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "header") { header = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "comment") { comment = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "sizeUnits") { sizeUnits = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "voxelDimensions") { voxelDimensions = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "statisticType") { statisticType = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "statisticDescription") { statisticDescription = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "StudyMetaDataSubHeader") { SubHeader* sh = new SubHeader; sh->readXML(node); addSubHeader(sh); } else { std::cout << "WARNING: unrecognized StudyMetaData::PageReference element ignored: " << elem.tagName().toAscii().constData() << std::endl; } } node = node.nextSibling(); } } /** * called to write to an XML structure. */ void StudyMetaData::PageReference::writeXML(QDomDocument& xmlDoc, QDomElement& parentElement) const throw (FileException) { // // Create the element for this class instance's data // QDomElement element = xmlDoc.createElement("StudyMetaDataPageReference"); // // write data // AbstractFile::addXmlCdataElement(xmlDoc, element, "pageNumber", pageNumber); AbstractFile::addXmlCdataElement(xmlDoc, element, "header", header); AbstractFile::addXmlCdataElement(xmlDoc, element, "comment", comment); AbstractFile::addXmlCdataElement(xmlDoc, element, "sizeUnits", sizeUnits); AbstractFile::addXmlCdataElement(xmlDoc, element, "voxelDimensions", voxelDimensions); AbstractFile::addXmlCdataElement(xmlDoc, element, "statisticType", statisticType); AbstractFile::addXmlCdataElement(xmlDoc, element, "statisticDescription", statisticDescription); // // write sub headers // for (int i = 0; i < getNumberOfSubHeaders(); i++) { subHeaders[i]->writeXML(xmlDoc, element); } // // Add to parent // parentElement.appendChild(element); } /** * called to write XML. */ void StudyMetaData::PageReference::writeXML(XmlGenericWriter& xmlWriter) const throw (FileException) { xmlWriter.writeStartElement("StudyMetaDataPageReference"); xmlWriter.writeElementCData("pageNumber", pageNumber); xmlWriter.writeElementCData("header", header); xmlWriter.writeElementCData("comment", comment); xmlWriter.writeElementCData("sizeUnits", sizeUnits); xmlWriter.writeElementCData("voxelDimensions", voxelDimensions); xmlWriter.writeElementCData("statisticType", statisticType); xmlWriter.writeElementCData("statisticDescription", statisticDescription); for (int i = 0; i < getNumberOfSubHeaders(); i++) { subHeaders[i]->writeXML(xmlWriter); } xmlWriter.writeEndElement(); } /** * set parent. */ void StudyMetaData::PageReference::setParent(StudyMetaData* parentStudyMetaDataIn) { parentStudyMetaData = parentStudyMetaDataIn; } /** * set modified. */ void StudyMetaData::PageReference::setModified() { if (parentStudyMetaData != NULL) { parentStudyMetaData->setModified(); } } //==================================================================================== // // Provenance class // //==================================================================================== /** * constructor. */ StudyMetaData::Provenance::Provenance() { parentStudyMetaData = NULL; clear(); } /** * destructor. */ StudyMetaData::Provenance::~Provenance() { clear(); } /** * copy constructor. */ StudyMetaData::Provenance::Provenance(const Provenance& p) { parentStudyMetaData = NULL; copyHelper(p); } /** * assignment operator. */ StudyMetaData::Provenance& StudyMetaData::Provenance::operator=(const Provenance& p) { if (this != &p) { copyHelper(p); } return *this; } /** * clear the page link. */ void StudyMetaData::Provenance::clear() { name = SystemUtilities::getUserName(); date = QDate::currentDate().toString("dd MMM yyyy"); comment = ""; } /** * set the name. */ void StudyMetaData::Provenance::setName(const QString& s) { if (name != s) { name = s; setModified(); } } /** * set the date. */ void StudyMetaData::Provenance::setDate(const QString& s) { if (date != s) { date = s; setModified(); } } /** * set the comment. */ void StudyMetaData::Provenance::setComment(const QString& s) { if (comment != s) { comment = s; setModified(); } } /** * called to read from XML. */ void StudyMetaData::Provenance::readXML(QDomNode& nodeIn) throw (FileException) { name = ""; date = ""; comment = ""; if (nodeIn.isNull()) { return; } QDomElement elem = nodeIn.toElement(); if (elem.isNull()) { return; } if (elem.tagName() != "StudyMetaDataProvenance") { QString msg("Incorrect element type passed to StudyMetaData::Provenance::readXML() "); msg.append(elem.tagName()); throw FileException(msg); } QDomNode node = nodeIn.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (elem.tagName() == "name") { name = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "date") { date = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "comment") { comment = AbstractFile::getXmlElementFirstChildAsString(elem); } else { std::cout << "WARNING: unrecognized StudyMetaData::Provenance element ignored: " << elem.tagName().toAscii().constData() << std::endl; } } node = node.nextSibling(); } } /** * called to write to an XML structure. */ void StudyMetaData::Provenance::writeXML(QDomDocument& xmlDoc, QDomElement& parentElement) const throw (FileException) { // // Create the element for this class instance's data // QDomElement element = xmlDoc.createElement("StudyMetaDataProvenance"); // // write data // AbstractFile::addXmlCdataElement(xmlDoc, element, "name", name); AbstractFile::addXmlCdataElement(xmlDoc, element, "date", date); AbstractFile::addXmlCdataElement(xmlDoc, element, "comment", comment); // // Add to parent // parentElement.appendChild(element); } /** * called to write XML. */ void StudyMetaData::Provenance::writeXML(XmlGenericWriter& xmlWriter) const throw (FileException) { xmlWriter.writeStartElement("StudyMetaDataProvenance"); xmlWriter.writeElementCData("name", name); xmlWriter.writeElementCData("date", date); xmlWriter.writeElementCData("comment", comment); xmlWriter.writeEndElement(); } /** * set parent. */ void StudyMetaData::Provenance::setParent(StudyMetaData* parentStudyMetaDataIn) { parentStudyMetaData = parentStudyMetaDataIn; } /** * set modified. */ void StudyMetaData::Provenance::setModified() { if (parentStudyMetaData != NULL) { parentStudyMetaData->setModified(); } } /** * copy helper. */ void StudyMetaData::Provenance::copyHelper(const Provenance& p) { StudyMetaData* savedParentStudyMetaData = parentStudyMetaData; clear(); name = p.name; date = p.date; comment = p.comment; parentStudyMetaData = savedParentStudyMetaData; setModified(); } //==================================================================================== // // StudyMetaData File class // //==================================================================================== /** * constructor. */ StudyMetaDataFile::StudyMetaDataFile() : AbstractFile("StudyMetaData File", SpecFile::getStudyMetaDataFileExtension(), true, FILE_FORMAT_XML, // default format FILE_IO_NONE, // ascii format FILE_IO_NONE, // binary format FILE_IO_READ_AND_WRITE, // XML format FILE_IO_NONE, // XML base64 FILE_IO_NONE, // XML gzip base64 FILE_IO_NONE, // other format FILE_IO_READ_AND_WRITE) // csvf { clear(); } /** * destructor. */ StudyMetaDataFile::~StudyMetaDataFile() { clear(); } /** * copy constructor. */ StudyMetaDataFile::StudyMetaDataFile(const StudyMetaDataFile& smdf) : AbstractFile("StudyMetaData File", SpecFile::getStudyMetaDataFileExtension(), true, FILE_FORMAT_XML, // default format FILE_IO_NONE, // ascii format FILE_IO_NONE, // binary format FILE_IO_READ_AND_WRITE, // XML format FILE_IO_NONE, // XML base64 FILE_IO_NONE, // XML gzip base64 FILE_IO_NONE, // other format FILE_IO_NONE) // csvf { copyHelper(smdf); } /** * assignment operator. */ StudyMetaDataFile& StudyMetaDataFile::operator=(const StudyMetaDataFile& smdf) { if (this != &smdf) { copyHelper(smdf); } return *this; } /** * copy helper used by copy constructor and assignment operator. */ void StudyMetaDataFile::copyHelper(const StudyMetaDataFile& smdf) { clear(); // // Copy parent's data // copyHelperAbstractFile(smdf); const int numStudies = smdf.getNumberOfStudyMetaData(); for (int i = 0; i < numStudies; i++) { addStudyMetaData(new StudyMetaData(*(smdf.getStudyMetaData(i)))); } setModified(); } /** * append a study metadata file to "this" study metadata file. */ void StudyMetaDataFile::append(const StudyMetaDataFile& smdf) { const int num = smdf.getNumberOfStudyMetaData(); for (int i = 0; i < num; i++) { StudyMetaData* smf = new StudyMetaData(*(smdf.getStudyMetaData(i))); addStudyMetaData(smf); } setModified(); } /** * append metadata from a cell file to this file. */ void StudyMetaDataFile::append(CellFile& cf) { const int num = cf.getNumberOfStudyInfo(); for (int i = 0; i < num; i++) { // // Convert study info to study metadata and add to study meta data file // CellStudyInfo* csi = cf.getStudyInfo(i); StudyMetaData* smd = new StudyMetaData(*csi); addStudyMetaData(smd); // // Convert links from study info to study metadata in all cells // StudyMetaDataLink smdl; smdl.setPubMedID(smd->getPubMedID()); StudyMetaDataLinkSet smdls; smdls.addStudyMetaDataLink(smdl); const int numCells = cf.getNumberOfCells(); for (int j = 0; j < numCells; j++) { CellData* cd = cf.getCell(j); if (cd->getStudyNumber() == i) { cd->setStudyMetaDataLinkSet(smdls); } } } // // Remove study info from cell file // cf.deleteAllStudyInfo(); } /** * append metadata from a cell projection file to this file. */ void StudyMetaDataFile::append(CellProjectionFile& cpf) { const int num = cpf.getNumberOfStudyInfo(); for (int i = 0; i < num; i++) { // // Convert study info to study metadata and add to study meta data file // const CellStudyInfo* csi = cpf.getStudyInfo(i); StudyMetaData* smd = new StudyMetaData(*csi); addStudyMetaData(smd); // // Convert links from study info to study metadata in all cell projections // StudyMetaDataLink smdl; smdl.setPubMedID(smd->getPubMedID()); StudyMetaDataLinkSet smdls; smdls.addStudyMetaDataLink(smdl); const int numCellProjections = cpf.getNumberOfCellProjections(); for (int j = 0; j < numCellProjections; j++) { CellProjection* cp = cpf.getCellProjection(j); if (cp->getStudyNumber() == i) { cp->setStudyMetaDataLinkSet(smdls); } } } // // Remove study info from cell projection file // cpf.deleteAllStudyInfo(); } /** * append metadata from a cell projection file to this file. */ void StudyMetaDataFile::append(VocabularyFile& vf) { const int num = vf.getNumberOfStudyInfo(); for (int i = 0; i < num; i++) { // // Convert study info to study metadata and add to study meta data file // const CellStudyInfo* csi = vf.getStudyInfo(i); StudyMetaData* smd = new StudyMetaData(*csi); addStudyMetaData(smd); // // Convert links from study info to study metadata in all vocabulary entries // StudyMetaDataLink smdl; smdl.setPubMedID(smd->getPubMedID()); StudyMetaDataLinkSet smdls; smdls.addStudyMetaDataLink(smdl); const int numVocabularyEntries = vf.getNumberOfVocabularyEntries(); for (int j = 0; j < numVocabularyEntries; j++) { VocabularyFile::VocabularyEntry* ve = vf.getVocabularyEntry(j); if (ve->getStudyNumber() == i) { ve->setStudyMetaDataLinkSet(smdls); } } } // // Remove study info from vocabulary file // vf.deleteAllStudyInfo(); } /** * Clears current file data in memory. Deriving classes must override this method and * call AbstractFile::clearAbstractFile() from its clear method. */ void StudyMetaDataFile::clear() { clearAbstractFile(); for (unsigned int i = 0; i < studyMetaData.size(); i++) { delete studyMetaData[i]; } studyMetaData.clear(); } /** * delete studies with the given names. */ void StudyMetaDataFile::deleteStudiesWithNames(const std::vector& namesOfStudiesToDelete) { // // Find the indices of the studies that are to be deleted // std::vector studiesToDelete; const int num = getNumberOfStudyMetaData(); for (int i = 0; i < num; i++) { const StudyMetaData* smd = getStudyMetaData(i); if (std::find(namesOfStudiesToDelete.begin(), namesOfStudiesToDelete.end(), smd->getName()) != namesOfStudiesToDelete.end()) { studiesToDelete.push_back(i); } } // // Delete the studies and start at highest index // since studies will get shifted as removed // const int iStart = static_cast(studiesToDelete.size()) - 1; for (int i = iStart; i >= 0; i--) { deleteStudyMetaData(studiesToDelete[i]); } } /** * get the index of a study metadata item. */ int StudyMetaDataFile::getStudyMetaDataIndex(const StudyMetaData* smdToFind) const { const int num = getNumberOfStudyMetaData(); for (int i = 0; i < num; i++) { const StudyMetaData* smd = getStudyMetaData(i); if (smdToFind == smd) { return i; } } return -1; } /** * get study from its name. */ int StudyMetaDataFile::getStudyIndexFromName(const QString& name) const { if (name.isEmpty()) { return -1; } const int num = getNumberOfStudyMetaData(); for (int i = 0; i < num; i++) { const StudyMetaData* smd = getStudyMetaData(i); if (name == smd->getName()) { return i; } } return -1; } /** * get study from a PubMed ID (may match PubMed ID or Project ID). */ int StudyMetaDataFile::getStudyIndexFromPubMedID(const QString& pubMedID) const { const int num = getNumberOfStudyMetaData(); for (int i = 0; i < num; i++) { const StudyMetaData* smd = getStudyMetaData(i); if (pubMedID == smd->getPubMedID()) { return i; } else if (pubMedID == smd->getProjectID()) { // check for ProjectID match return i; } } return -1; } /** * get the index of study meta data matching the study metadata link (-1 if no match found) */ int StudyMetaDataFile::getStudyIndexFromLink(const StudyMetaDataLink& smdl) const { const int num = getNumberOfStudyMetaData(); for (int i = 0; i < num; i++) { const StudyMetaData* smd = getStudyMetaData(i); if (smdl.getPubMedID() == smd->getPubMedID()) { return i; } else if (smdl.getPubMedID() == smd->getProjectID()) { // check for ProjectID match return i; } } return -1; } /** * add study meta data. */ void StudyMetaDataFile::addStudyMetaData(StudyMetaData* smd) { smd->setParent(this); studyMetaData.push_back(smd); setModified(); } /** * delete study meta data. */ void StudyMetaDataFile::deleteStudyMetaData(const int indx) { delete studyMetaData[indx]; studyMetaData.erase(studyMetaData.begin() + indx); setModified(); } /** * returns true if the file is isEmpty (contains no data). */ bool StudyMetaDataFile::empty() const { return studyMetaData.empty(); } /** * find out if comma separated file conversion supported. */ void StudyMetaDataFile::getCommaSeparatedFileSupport(bool& readFromCSV, bool& writeToCSV) const { readFromCSV = false; // true; writeToCSV = false; // true; } /** * get all medical subject headings. */ void StudyMetaDataFile::getAllMedicalSubjectHeadings(std::vector& meshOut) const { meshOut.clear(); std::set meshSet; const int numStudies = getNumberOfStudyMetaData(); for (int i = 0; i < numStudies; i++) { const StudyMetaData* smd = getStudyMetaData(i); std::vector mesh; smd->getMedicalSubjectHeadings(mesh); meshSet.insert(mesh.begin(), mesh.end()); } meshOut.insert(meshOut.end(), meshSet.begin(), meshSet.end()); } /** * get all keywords. */ void StudyMetaDataFile::getAllKeywords(std::vector& allKeywords) const { allKeywords.clear(); std::set keywordSet; const int numStudies = getNumberOfStudyMetaData(); for (int i = 0; i < numStudies; i++) { const StudyMetaData* smd = getStudyMetaData(i); std::vector studyKeywords; smd->getKeywords(studyKeywords); keywordSet.insert(studyKeywords.begin(), studyKeywords.end()); } allKeywords.insert(allKeywords.end(), keywordSet.begin(), keywordSet.end()); } /** * get all citations. */ void StudyMetaDataFile::getAllCitations(std::vector& allCitations) const { allCitations.clear(); // // Get keywords from studies used by displayed foci // const int numStudies = getNumberOfStudyMetaData(); std::set citationSet; for (int i = 0; i < numStudies; i++) { const StudyMetaData* smd = getStudyMetaData(i); const QString citation = smd->getCitation(); if (citation.isEmpty() == false) { citationSet.insert(citation); } } allCitations.insert(allCitations.end(), citationSet.begin(), citationSet.end()); } /** * get all data formats. */ void StudyMetaDataFile::getAllDataFormats(std::vector& allDataFormats) const { allDataFormats.clear(); const int numStudies = getNumberOfStudyMetaData(); std::set dataFormatSet; for (int i = 0; i < numStudies; i++) { const StudyMetaData* smd = getStudyMetaData(i); const QString dataFormat = smd->getStudyDataFormat(); if (dataFormat.isEmpty() == false) { dataFormatSet.insert(dataFormat); } } allDataFormats.insert(allDataFormats.end(), dataFormatSet.begin(), dataFormatSet.end()); } /** * get all data types. */ void StudyMetaDataFile::getAllDataTypes(std::vector& allDataTypes) const { allDataTypes.clear(); const int numStudies = getNumberOfStudyMetaData(); std::set dataTypeSet; for (int i = 0; i < numStudies; i++) { const StudyMetaData* smd = getStudyMetaData(i); const QString dataType = smd->getStudyDataType(); if (dataType.isEmpty() == false) { dataTypeSet.insert(dataType); } } allDataTypes.insert(allDataTypes.end(), dataTypeSet.begin(), dataTypeSet.end()); } /** * get all keywords used by displayed foci. */ void StudyMetaDataFile::getAllKeywordsUsedByDisplayedFoci(const FociProjectionFile* fpf, std::vector& keywordsOut) const { keywordsOut.clear(); // // Get studies used by foci // std::vector studyIsUsedByFocus; getStudiesLinkedByDisplayedFoci(fpf, studyIsUsedByFocus); const int numStudies = static_cast(studyIsUsedByFocus.size()); // // Get keywords from studies used by displayed foci // std::set keywordSet; for (int i = 0; i < numStudies; i++) { if (studyIsUsedByFocus[i]) { const StudyMetaData* smd = getStudyMetaData(i); std::vector studyKeywords; smd->getKeywords(studyKeywords); keywordSet.insert(studyKeywords.begin(), studyKeywords.end()); } } keywordsOut.insert(keywordsOut.end(), keywordSet.begin(), keywordSet.end()); /* const int numStudies = getNumberOfStudyMetaData(); std::vector studyIsUsedByFocus(numStudies, false); // // Find studies used by displayed foci // const int numFoci = fpf->getNumberOfCellProjections(); for (int i = 0; i < numFoci; i++) { const CellProjection* focus = fpf->getCellProjection(i); if (focus->getDisplayFlag()) { // // Loop through studies used by focus // const StudyMetaDataLinkSet smdls = focus->getStudyMetaDataLinkSet(); const int numLinks = smdls.getNumberOfStudyMetaDataLinks(); for (int j = 0; j < numLinks; j++) { const StudyMetaDataLink smdl = smdls.getStudyMetaDataLink(j); const int studyIndex = getStudyIndexFromLink(smdl); if ((studyIndex >= 0) && (studyIndex < numStudies)) { studyIsUsedByFocus[studyIndex] = true; } } } } // // Get keywords from studies used by displayed foci // std::set keywordSet; for (int i = 0; i < numStudies; i++) { if (studyIsUsedByFocus[i]) { const StudyMetaData* smd = getStudyMetaData(i); std::vector studyKeywords; smd->getKeywords(studyKeywords); keywordSet.insert(studyKeywords.begin(), studyKeywords.end()); } } keywordsOut.insert(keywordsOut.end(), keywordSet.begin(), keywordSet.end()); */ } /** * get studies that are linked by displayed foci. */ void StudyMetaDataFile::getStudiesLinkedByDisplayedFoci(const FociProjectionFile* fpf, std::vector& studyLinkedByFocusOut) const { const int numStudies = getNumberOfStudyMetaData(); studyLinkedByFocusOut.resize(numStudies); std::fill(studyLinkedByFocusOut.begin(), studyLinkedByFocusOut.end(), false); // // Find studies used by displayed foci // const int numFoci = fpf->getNumberOfCellProjections(); for (int i = 0; i < numFoci; i++) { const CellProjection* focus = fpf->getCellProjection(i); if (focus->getDisplayFlag()) { // // Loop through studies used by focus // const StudyMetaDataLinkSet smdls = focus->getStudyMetaDataLinkSet(); const int numLinks = smdls.getNumberOfStudyMetaDataLinks(); for (int j = 0; j < numLinks; j++) { const StudyMetaDataLink smdl = smdls.getStudyMetaDataLink(j); const int studyIndex = getStudyIndexFromLink(smdl); if ((studyIndex >= 0) && (studyIndex < numStudies)) { studyLinkedByFocusOut[studyIndex] = true; } } } } } /** * get all table headers. */ void StudyMetaDataFile::getAllTableHeaders(std::vector& headersOut) const { headersOut.clear(); std::set headerSet; const int numStudies = getNumberOfStudyMetaData(); for (int i = 0; i < numStudies; i++) { const StudyMetaData* smd = getStudyMetaData(i); std::vector tableHeaders; smd->getAllTableHeaders(tableHeaders); headerSet.insert(tableHeaders.begin(), tableHeaders.end()); } headersOut.insert(headersOut.end(), headerSet.begin(), headerSet.end()); } /** * get all table subheader short names. */ void StudyMetaDataFile::getAllTableSubHeaderShortNames(std::vector& allShortNames) const { allShortNames.clear(); std::set shortNameSet; const int numStudies = getNumberOfStudyMetaData(); for (int i = 0; i < numStudies; i++) { const StudyMetaData* smd = getStudyMetaData(i); std::vector studyTableSubHeaderShortNames; smd->getAllTableSubHeaderShortNames(studyTableSubHeaderShortNames); shortNameSet.insert(studyTableSubHeaderShortNames.begin(), studyTableSubHeaderShortNames.end()); } allShortNames.insert(allShortNames.end(), shortNameSet.begin(), shortNameSet.end()); } /** * get all table subheader short names used by displayed foci. */ void StudyMetaDataFile::getAllTableSubHeaderShortNamesUsedByDisplayedFoci( const FociProjectionFile* fpf, std::vector& allShortNamesOut) const { allShortNamesOut.clear(); // // Get studies used by foci // std::vector studyIsUsedByFocus; getStudiesLinkedByDisplayedFoci(fpf, studyIsUsedByFocus); const int numStudies = static_cast(studyIsUsedByFocus.size()); std::set shortNameSet; // // Get names used by displayed foci // for (int i = 0; i < numStudies; i++) { if (studyIsUsedByFocus[i]) { const StudyMetaData* smd = getStudyMetaData(i); std::vector studyTableSubHeaderShortNames; smd->getAllTableSubHeaderShortNames(studyTableSubHeaderShortNames); shortNameSet.insert(studyTableSubHeaderShortNames.begin(), studyTableSubHeaderShortNames.end()); } } allShortNamesOut.insert(allShortNamesOut.end(), shortNameSet.begin(), shortNameSet.end()); } /** * clear study meta data modified (prevents date and time stamp updates). */ void StudyMetaDataFile::clearAllStudyMetaDataElementsModified() { const int num = getNumberOfStudyMetaData(); for (int i = 0; i < num; i++) { StudyMetaData* smd = getStudyMetaData(i); smd->clearModified(); } } /** * retrieve data from PubMed using PubMed ID for all studies. */ void StudyMetaDataFile::updateAllStudiesWithDataFromPubMedDotCom() throw (FileException) { QString errorMessage; const int num = getNumberOfStudyMetaData(); for (int i = 0; i < num; i++) { StudyMetaData* smd = getStudyMetaData(i); try { if (smd->getPubMedIDIsAProjectID() == false) { smd->updateDataFromPubMedDotComUsingPubMedID(); } } catch (FileException& e) { errorMessage += e.whatQString(); } } if (errorMessage.isEmpty() == false) { throw FileException(errorMessage); } } /** * count the number of studies without at least one provenance entry. */ int StudyMetaDataFile::getNumberOfStudyMetaDatWithoutProvenceEntries() const { int count = 0; const int num = getNumberOfStudyMetaData(); for (int i = 0; i < num; i++) { const StudyMetaData* smd = getStudyMetaData(i); if (smd->getNumberOfProvenances() <= 0) { count++; } } return count; } /** * update all studies without a provenance entry. */ void StudyMetaDataFile::addProvenanceToStudiesWithoutProvenanceEntries(const QString& name, const QString& date, const QString& comment) { const int num = getNumberOfStudyMetaData(); for (int i = 0; i < num; i++) { StudyMetaData* smd = getStudyMetaData(i); if (smd->getNumberOfProvenances() <= 0) { StudyMetaData::Provenance* p = new StudyMetaData::Provenance; p->setName(name); p->setDate(date); p->setComment(comment); smd->addProvenance(p); } } } /** * Read the contents of the file (header has already been read). */ void StudyMetaDataFile::readFileData(QFile& /*file*/, QTextStream& /*stream*/, QDataStream& /*binStream*/, QDomElement& rootElement) throw (FileException) { // // Should reading data be skipped ? // if (getReadMetaDataOnlyFlag()) { return; } switch (getFileReadType()) { case FILE_FORMAT_ASCII: throw FileException(filename, "Reading in ASCII format not supported."); break; case FILE_FORMAT_BINARY: throw FileException(filename, "Reading in Binary format not supported."); break; case FILE_FORMAT_XML: { QDomNode node = rootElement.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { // // Is this a "StudyMetaData" element // if (elem.tagName() == "StudyMetaData") { StudyMetaData* smd = new StudyMetaData; smd->readXML(node); addStudyMetaData(smd); } else if ((elem.tagName() == xmlHeaderOldTagName) || (elem.tagName() == xmlHeaderTagName)) { // ignore, read by AbstractFile::readFile() } else { std::cout << "WARNING: unrecognized Vocabulary File element: " << elem.tagName().toAscii().constData() << std::endl; } } node = node.nextSibling(); } } break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "Reading XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "Reading XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Reading XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Reading in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Reading in Comma Separated File format not supported."); break; } // // Prevent data and time stamp updates if file is saved // clearAllStudyMetaDataElementsModified(); } /** * Write the file's data (header has already been written). */ void StudyMetaDataFile::writeFileData(QTextStream& /*stream*/, QDataStream& /*binStream*/, QDomDocument& xmlDoc, QDomElement& rootElement) throw (FileException) { const int num = getNumberOfStudyMetaData(); switch (getFileWriteType()) { case FILE_FORMAT_ASCII: throw FileException(filename, "Writing in Ascii format not supported."); break; case FILE_FORMAT_BINARY: throw FileException(filename, "Writing in Binary format not supported."); break; case FILE_FORMAT_XML: { // // Write the study meta data entries // for (int i = 0; i < num; i++) { const StudyMetaData* smd = getStudyMetaData(i); smd->writeXML(xmlDoc, rootElement); } } break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Writing XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Writing in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Writing in Comma Separated File format not supported."); break; } } /** * find duplicate studies (map key is PubMedID, value is filename). */ void StudyMetaDataFile::findDuplicateStudies(const std::vector& studyFileNames, std::multimap& duplicatesStudiesOut) throw (FileException) { duplicatesStudiesOut.clear(); const int numFiles = static_cast(studyFileNames.size()); if (numFiles <= 0) { throw FileException("No filenames provided."); } // // keep track of PubMedIDs and files // std::set pubMedIDs; std::multimap pubMedIDsAndFiles; // // Loop through the study files // for (int i = 0; i < numFiles; i++) { // // Read the study file // StudyMetaDataFile studyFile; studyFile.readFile(studyFileNames[i]); const QString fileNameNoPath(FileUtilities::basename(studyFileNames[i])); // // loop through the studies // const int numStudies = studyFile.getNumberOfStudyMetaData(); for (int j = 0; j < numStudies; j++) { // // Get the studies PubMedID // const StudyMetaData* smd = studyFile.getStudyMetaData(j); const QString pubMedID = smd->getPubMedID(); pubMedIDs.insert(pubMedID); // // file name and study name // QString name = (fileNameNoPath + " " + smd->getName()); // // Insert into map // pubMedIDsAndFiles.insert(std::make_pair(pubMedID, name)); } } // // Look for Duplicates // for (std::set::iterator iter = pubMedIDs.begin(); iter != pubMedIDs.end(); iter++) { // // Is PubMedID used more than once // const QString pubMedID = *iter; if (pubMedIDsAndFiles.count(pubMedID) > 1) { for (std::multimap::iterator pos = pubMedIDsAndFiles.lower_bound(pubMedID); pos != pubMedIDsAndFiles.upper_bound(pubMedID); pos++) { // // Add to output // duplicatesStudiesOut.insert(std::make_pair(pubMedID, pos->second)); } } } } /** * Validate the study metadata file (missing table numbers, duplicate studies, etc). */ QStringList StudyMetaDataFile::validStudyMetaDataFile() const { QStringList sl; const int num = getNumberOfStudyMetaData(); for (int i = 0; i < num; i++) { const QString studyNumberText = "Study Number " + QString::number(i + 1) + " "; const StudyMetaData* smd = getStudyMetaData(i); // // Check figures // const int numFigures = smd->getNumberOfFigures(); for (int j = 0; j < numFigures; j++) { const StudyMetaData::Figure* figure = smd->getFigure(j); if (figure->getNumber().isEmpty()) { sl += studyNumberText + "has figure missing its number"; } const int numPanels = figure->getNumberOfPanels(); for (int k = 0; k < numPanels; k++) { const StudyMetaData::Figure::Panel* panel = figure->getPanel(k); if (panel->getPanelNumberOrLetter().isEmpty()) { sl += studyNumberText + "has figure panel missing its identifier"; } } } // // Check page references // const int numPageRefs = smd->getNumberOfPageReferences(); for (int j = 0; j < numPageRefs; j++) { const StudyMetaData::PageReference* pageRef= smd->getPageReference(j); if (pageRef->getPageNumber().isEmpty()) { sl += studyNumberText + "has table missing its page number"; } const int numSubHeaders = pageRef->getNumberOfSubHeaders(); for (int k = 0; k < numSubHeaders; k++) { const StudyMetaData::SubHeader* sh = pageRef->getSubHeader(k); if (sh->getNumber().isEmpty()) { sl += studyNumberText + "has page-ref subheader missing its number"; } if (sh->getShortName().isEmpty()) { sl += studyNumberText + "has page-ref subheader missing its short name"; } } } // // Check tables // const int numTables = smd->getNumberOfTables(); for (int j = 0; j < numTables; j++) { const StudyMetaData::Table* table = smd->getTable(j); if (table->getNumber().isEmpty()) { sl += studyNumberText + "has table missing its number"; } const int numSubHeaders = table->getNumberOfSubHeaders(); for (int k = 0; k < numSubHeaders; k++) { const StudyMetaData::SubHeader* sh = table->getSubHeader(k); if (sh->getNumber().isEmpty()) { sl += studyNumberText + "has table subheader missing its number"; } if (sh->getShortName().isEmpty()) { sl += studyNumberText + "has table subheader missing its short name"; } } } } // // Look for duplicate studies names or pubmed id's // for (int i = 0; i < (num - 1); i++) { const StudyMetaData* smd = getStudyMetaData(i); const QString studyName = smd->getName(); if (studyName.isEmpty()) { sl += "Study " + QString::number(i + 1) + " has no name"; } else { bool found = false; QString msg; for (int j = i + 1; j < num; j++) { const StudyMetaData* smd2 = getStudyMetaData(j); if (smd2->getName() == studyName) { if (found == false) { msg += "Multiple studies with name " + studyName + ":"; msg += " " + QString::number(i + 1); found = true; } msg += " " + QString::number(j + 1); } } if (msg.isEmpty() == false) { sl += msg; } } const QString pubMedID = smd->getPubMedID(); if (pubMedID.isEmpty()) { sl += "Study " + QString::number(i + 1) + " has no PubMed ID"; } else { QString msg; bool found = false; for (int j = i + 1; j < num; j++) { const StudyMetaData* smd2 = getStudyMetaData(j); if (smd2->getPubMedID() == pubMedID) { if (found == false) { msg += "Multiple studies with PubMed ID " + pubMedID + ":"; msg += " " + QString::number(i + 1); found = true; } msg += " " + QString::number(j + 1); } } if (msg.isEmpty() == false) { sl += msg; } } } return sl; } /** * Write the file's memory in caret6 format to the specified name. */ QString StudyMetaDataFile::writeFileInCaret6Format(const QString& filenameIn, Structure structure,const ColorFile* colorFileIn, const bool useCaret6ExtensionFlag) throw (FileException) { int numStudies = this->getNumberOfStudyMetaData(); if (numStudies <= 0) { throw FileException("Contains no studies"); } QFile file(filenameIn); if (AbstractFile::getOverwriteExistingFilesAllowed() == false) { if (file.exists()) { throw FileException("file exists and overwrite is prohibited."); } } if (file.open(QFile::WriteOnly) == false) { throw FileException("Unable to open for writing"); } QTextStream stream(&file); XmlGenericWriter xmlWriter(stream); xmlWriter.writeStartDocument(); XmlGenericWriterAttributes attributes; attributes.addAttribute("CaretFileType", "StudyMetaData"); attributes.addAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); attributes.addAttribute("xsi:noNamespaceSchemaLocation", "http://brainvis.wustl.edu/caret6/xml_schemas/StudyMetaDataFileSchema.xsd"); attributes.addAttribute("Version", "6.0"); xmlWriter.writeStartElement("CaretDataFile", attributes); this->writeHeaderXMLWriter(xmlWriter); for (int i = 0; i < numStudies; i++) { const StudyMetaData* smd = getStudyMetaData(i); smd->writeXML(xmlWriter, i); } xmlWriter.writeEndElement(); xmlWriter.writeEndDocument(); file.close(); return filenameIn; } caret-5.6.4~dfsg.1.orig/caret_files/StudyCollectionFile.h0000664000175000017500000002162011572067322023137 0ustar michaelmichael #ifndef __STUDY_COLLECTION_FILE_H__ #define __STUDY_COLLECTION_FILE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "AbstractFile.h" #include "StudyNamePubMedID.h" class StudyCollectionFile; // // Class for storing a study collection // class StudyCollection { public: // constructor StudyCollection(); // copy constructor StudyCollection(const StudyCollection& sc); // destructor ~StudyCollection(); // assignment operator StudyCollection& operator=(const StudyCollection& sc); /// clear the collection void clear(); /// get number of PMIDs int getNumberOfStudyPMIDs() const { return studyPMIDs.size(); } // add a study PMID void addStudyPMID(StudyNamePubMedID* s); // get a study PMID StudyNamePubMedID* getStudyPMID(const int indx); // get a study PMID const StudyNamePubMedID* getStudyPMID(const int indx) const; // remove a study PMID void removeStudyPMID(const int indx); /// get study collection name QString getStudyCollectionName() const { return studyCollectionName; } // set study collection name void setStudyCollectionName(const QString& s); /// get study collection creator QString getStudyCollectionCreator() const { return studyCollectionCreator; } // set study collection creator void setStudyCollectionCreator(const QString& s); // get study type QString getStudyType() const { return studyType; } // set study type void setStudyType(const QString& s); /// get comment QString getComment() const { return comment; } // set comment void setComment(const QString& s); /// get study name QString getStudyName() const { return studyName; } // set study name void setStudyName(const QString& s); /// get PMID QString getPMID() const { return pmid; } // set PMID void setPMID(const QString& s); /// get search ID QString getSearchID() const { return searchID; } // set search ID void setSearchID(const QString& s); /// get foci list ID QString getFociListID() const { return fociListID; } /// set foci list ID void setFociListID(const QString& s); /// get foci color list ID QString getFociColorListID() const { return fociColorListID; } /// set foci color list ID void setFociColorListID(const QString& s); /// get study collection ID QString getStudyCollectionID() const { return sclID; } /// set study collection ID void setStudyCollectionID(const QString& s); /// get topic QString getTopic() const { return topic; } // set topic void setTopic(const QString& s); /// get category ID QString getCategoryID() const { return categoryID; } // set category ID void setCategoryID(const QString& s); // set parent study collection file void setParentStudyCollectionFile(StudyCollectionFile* parent); protected: // copy helper used by copy constructor and assignment operator void copyHelper(const StudyCollection& sc); // set modified void setModified(); // read from XML void readXML(QDomNode& nodeIn) throw (FileException); // write to XML void writeXML(QDomDocument& xmlDoc, QDomElement& parentElement); // called to write XML void writeXML(XmlGenericWriter& xmlWriter, int indx) const throw (FileException); /// study collection name QString studyCollectionName; /// study collection creator QString studyCollectionCreator; /// study type QString studyType; /// comment QString comment; /// study name QString studyName; /// study pmid QString pmid; /// search id QString searchID; /// topic QString topic; /// category ID QString categoryID; /// foci list ID QString fociListID; /// foci color list ID QString fociColorListID; /// study collection ID QString sclID; /// collection of studies std::vector studyPMIDs; /// parent study collection file StudyCollectionFile* parentStudyCollectionFile; // // !!!! UPDATE copyHelper() is any members added !!!! // friend class StudyCollectionFile; friend class StudyNamePubMedID; }; /// class for a study meta-analysis file class StudyCollectionFile : public AbstractFile { public: // constructor StudyCollectionFile(); // copy constructor StudyCollectionFile(const StudyCollectionFile& scf); // destructor ~StudyCollectionFile(); // copy constructor StudyCollectionFile& operator=(const StudyCollectionFile& scf); // append a study collection file to "this" study collection file void append(const StudyCollectionFile& smdf); // add a study collection void addStudyCollection(StudyCollection* sc); /// get the number of study collections int getNumberOfStudyCollections() const { return studyCollections.size(); } // get a study collection StudyCollection* getStudyCollection(const int indx); // get a study collection (const method) const StudyCollection* getStudyCollection(const int indx) const; // delete a study collection void deleteStudyCollection(const int indx); // Clears current file data in memory. Deriving classes must override this method and // call AbstractFile::clearAbstractFile() from its clear method. virtual void clear(); // returns true if the file is isEmpty (contains no data) virtual bool empty() const; // find out if comma separated file conversion supported virtual void getCommaSeparatedFileSupport(bool& readFromCSV, bool& writeToCSV) const; /// write the file's memory in caret6 format to the specified name virtual QString writeFileInCaret6Format(const QString& filenameIn, Structure structure,const ColorFile* colorFileIn, const bool useCaret6ExtensionFlag) throw (FileException); protected: // the copy helper void copyHelper(const StudyCollectionFile& scf); /// read the file's data from a comma separated values file (throws exception if not supported) virtual void readDataFromCommaSeparatedValuesTable(const CommaSeparatedValueFile& csv) throw (FileException); // Read the contents of the file (header has already been read) virtual void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& rootElement) throw (FileException); // Write the file's data (header has already been written) virtual void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& xmlDoc, QDomElement& rootElement) throw (FileException); // read from XML void readXML(QDomNode& nodeIn) throw (FileException); // write to XML void writeXML(QDomDocument& xmlDoc, QDomElement& parentElement); // the study collections std::vector studyCollections; // // !!!! UPDATE copyHelper() is any members added !!!! // }; #endif // __STUDY_COLLECTION_FILE_H__ caret-5.6.4~dfsg.1.orig/caret_files/StudyCollectionFile.cxx0000664000175000017500000006704211572067322023522 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include "CommaSeparatedValueFile.h" #include "SpecFile.h" #include "StringTable.h" #include "StudyCollectionFile.h" /** * constructor. */ StudyCollectionFile::StudyCollectionFile() : AbstractFile("Study Collection File", SpecFile::getStudyCollectionFileExtension(), true, // has header FILE_FORMAT_XML, // default file format FILE_IO_NONE, // ascii FILE_IO_NONE, // binary FILE_IO_READ_AND_WRITE, // xml FILE_IO_NONE, // xml base64 FILE_IO_NONE, // xml base64 gzip FILE_IO_NONE, // other FILE_IO_READ_ONLY) // CSV { clear(); } /** * copy constructor. */ StudyCollectionFile::StudyCollectionFile(const StudyCollectionFile& scf) : AbstractFile(scf) { copyHelper(scf); } /** * destructor. */ StudyCollectionFile::~StudyCollectionFile() { clear(); } /** * copy constructor. */ StudyCollectionFile& StudyCollectionFile::operator=(const StudyCollectionFile& scf) { if (this != &scf) { copyHelper(scf); } setModified(); return *this; } /** * the copy helper. */ void StudyCollectionFile::copyHelper(const StudyCollectionFile& scf) { clear(); const int num = static_cast(studyCollections.size()); for (int i = 0; i < num; i++) { StudyCollection* sc = new StudyCollection(*scf.getStudyCollection(i)); addStudyCollection(sc); } setModified(); } /** * append a study collection file to "this" study collection file. */ void StudyCollectionFile::append(const StudyCollectionFile& scf) { const int num = scf.getNumberOfStudyCollections(); for (int i = 0; i < num; i++) { addStudyCollection(new StudyCollection(*scf.getStudyCollection(i))); } } /** * add a study collection. */ void StudyCollectionFile::addStudyCollection(StudyCollection* sc) { studyCollections.push_back(sc); studyCollections[studyCollections.size() - 1]->setParentStudyCollectionFile(this); } /** * get a study collection. */ StudyCollection* StudyCollectionFile::getStudyCollection(const int indx) { if ((indx >= 0) && (indx < getNumberOfStudyCollections())) { return studyCollections[indx]; } return NULL; } /** * get a study collection (const method). */ const StudyCollection* StudyCollectionFile::getStudyCollection(const int indx) const { if ((indx >= 0) && (indx < getNumberOfStudyCollections())) { return studyCollections[indx]; } return NULL; } /** * delete a study collection. */ void StudyCollectionFile::deleteStudyCollection(const int indx) { if ((indx >= 0) && (indx < getNumberOfStudyCollections())) { delete studyCollections[indx]; studyCollections[indx] = NULL;; studyCollections.erase(studyCollections.begin() + indx); } } /** * call AbstractFile::clearAbstractFile() from its clear method. */ void StudyCollectionFile::clear() { clearAbstractFile(); const int num = getNumberOfStudyCollections(); for (int i = 0; i < num; i++) { delete studyCollections[i]; studyCollections[i] = NULL; } studyCollections.clear(); } /** * returns true if the file is isEmpty (contains no data). */ bool StudyCollectionFile::empty() const { return studyCollections.empty(); } /** * find out if comma separated file conversion supported. */ void StudyCollectionFile::getCommaSeparatedFileSupport(bool& readFromCSV, bool& writeToCSV) const { readFromCSV = true; writeToCSV = false; } /** * read the file's data from a comma separated values file (throws exception if not supported). */ void StudyCollectionFile::readDataFromCommaSeparatedValuesTable(const CommaSeparatedValueFile& csv) throw (FileException) { const QString filenameSaved(filename); clear(); filename = filenameSaved; // // Do header // const StringTable* stHeader = csv.getDataSectionByName("header"); if (stHeader != NULL) { readHeaderDataFromStringTable(*stHeader); } const StringTable* st = csv.getDataSectionByName("StudyCollectionMetadata"); if (st == NULL) { throw FileException("No section titled \"StudyCollectionMetadata\" was found."); } const int numRows = st->getNumberOfRows(); if (numRows != 1) { throw FileException("StudyCollectionMetadata section must contain one and only one row of data."); } int numCols = st->getNumberOfColumns(); int studyCollectionNameCol = -1; int studyCollectionCreatorCol = -1; int typeCol = -1; int commentCol = -1; int studyNameCol = -1; int pmidCol = -1; int searchIDCol = -1; int fociListIDCol = -1; int fociColorListIDCol = -1; int sclIDCol = -1; int topicCol = -1; int categoryIDCol = -1; for (int i = 0; i < numCols; i++) { const QString columnTitle = st->getColumnTitle(i).toLower(); if (columnTitle == "study collection name") { studyCollectionNameCol = i; } else if (columnTitle == "study collection creator") { studyCollectionCreatorCol = i; } else if (columnTitle == "type") { typeCol = i; } else if (columnTitle == "comment") { commentCol = i; } else if (columnTitle == "study name") { studyNameCol = i; } else if (columnTitle == "pmid") { pmidCol = i; } else if (columnTitle == "focilist_id") { fociListIDCol = i; } else if (columnTitle == "focicolorlist_id") { fociColorListIDCol = i; } else if (columnTitle == "scl_id") { sclIDCol = i; } else if (columnTitle == "search_id") { searchIDCol = i; } else if (columnTitle == "topic") { topicCol = i; } else if (columnTitle == "category_id") { categoryIDCol = i; } } StudyCollection* sc = new StudyCollection;; for (int i = 0; i < numRows; i++) { if (studyCollectionNameCol >= 0) { sc->setStudyCollectionName(st->getElement(i, studyCollectionNameCol)); } if (studyCollectionCreatorCol >= 0) { sc->setStudyCollectionCreator(st->getElement(i, studyCollectionCreatorCol)); } if (typeCol >= 0) { sc->setStudyType(st->getElement(i, typeCol)); } if (commentCol >= 0) { sc->setComment(st->getElement(i, commentCol)); } if (studyNameCol >= 0) { sc->setStudyName(st->getElement(i, studyNameCol)); } if (pmidCol >= 0) { sc->setPMID(st->getElement(i, pmidCol)); } if (fociListIDCol >= 0) { sc->setFociListID(st->getElement(i, fociListIDCol)); } if (fociColorListIDCol >= 0) { sc->setFociColorListID(st->getElement(i, fociColorListIDCol)); } if (sclIDCol >= 0) { sc->setStudyCollectionID(st->getElement(i, sclIDCol)); } if (searchIDCol >= 0) { sc->setSearchID(st->getElement(i, searchIDCol)); } if (topicCol >= 0) { sc->setTopic(st->getElement(i, topicCol)); } if (categoryIDCol >= 0) { sc->setCategoryID(st->getElement(i, categoryIDCol)); } } // // Read Study PMIDs // const StringTable* pmidTable = csv.getDataSectionByName("Name_PMID"); int nameColumn = -1; int pmidColumn = -1; int mslidColumn = -1; const int numPMIDCols = pmidTable->getNumberOfColumns(); for (int i = 0; i < numPMIDCols; i++) { const QString name = pmidTable->getColumnTitle(i).toLower(); if (name == "name") { nameColumn = i; } else if (name == "study pubmed id") { pmidColumn = i; } else if (name == "msl_id") { mslidColumn = i; } } const int numItems = pmidTable->getNumberOfRows(); for (int i = 0; i < numItems; i++) { QString name, pmid, msl; if (nameColumn >= 0) { name = pmidTable->getElement(i, nameColumn); } if (pmidColumn >= 0) { pmid = pmidTable->getElement(i, pmidColumn); } if (mslidColumn >= 0) { msl = pmidTable->getElement(i, mslidColumn); } if (name.isEmpty() == false) { sc->addStudyPMID(new StudyNamePubMedID(name, pmid, msl)); } } addStudyCollection(sc); } /** * read from XML. */ void StudyCollectionFile::readXML(QDomNode& nodeIn) throw (FileException) { QDomNode node = nodeIn.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { // // Is this a header element // if ((elem.tagName() == xmlHeaderOldTagName) || (elem.tagName() == xmlHeaderTagName)) { // ignore, read by AbstractFile::readFile() } else if (elem.tagName() == "StudyCollection") { StudyCollection* sc = new StudyCollection; sc->readXML(node); addStudyCollection(sc); } else { std::cout << "WARNING: unrecognized Study Collection File Element: " << elem.tagName().toAscii().constData() << std::endl; } } node = node.nextSibling(); } } /** * Read the contents of the file (header has already been read). */ void StudyCollectionFile::readFileData(QFile& file, QTextStream& stream, QDataStream& /*binStream*/, QDomElement& rootElement) throw (FileException) { // // Should reading data be skipped ? // if (getReadMetaDataOnlyFlag()) { return; } switch (getFileReadType()) { case FILE_FORMAT_ASCII: throw FileException(filename, "Reading in ASCII format not supported."); break; case FILE_FORMAT_BINARY: throw FileException(filename, "Reading in Binary format not supported."); break; case FILE_FORMAT_XML: readXML(rootElement); break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "Reading XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "Reading XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Reading XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Reading in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: { CommaSeparatedValueFile csvf; csvf.readFromTextStream(file, stream); readDataFromCommaSeparatedValuesTable(csvf); } break; } } /** * write to XML. */ void StudyCollectionFile::writeXML(QDomDocument& xmlDoc, QDomElement& parentElement) { const int num = getNumberOfStudyCollections(); for (int i = 0; i < num; i++) { studyCollections[i]->writeXML(xmlDoc, parentElement); } } /** * write the file's memory in caret6 format to the specified name */ QString StudyCollectionFile::writeFileInCaret6Format(const QString& filenameIn, Structure structure, const ColorFile* colorFileIn, const bool useCaret6ExtensionFlag) throw (FileException) { int numCollections = this->getNumberOfStudyCollections(); if (numCollections <= 0) { throw FileException("Contains no study collections."); } QFile file(filenameIn); if (AbstractFile::getOverwriteExistingFilesAllowed() == false) { if (file.exists()) { throw FileException("file exists and overwrite is prohibited."); } } if (file.open(QFile::WriteOnly) == false) { throw FileException("Unable to open for writing"); } QTextStream stream(&file); XmlGenericWriter xmlWriter(stream); xmlWriter.writeStartDocument(); XmlGenericWriterAttributes attributes; attributes.addAttribute("CaretFileType", "StudyCollection"); attributes.addAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); attributes.addAttribute("xsi:noNamespaceSchemaLocation", "http://brainvis.wustl.edu/caret6/xml_schemas/StudyCollectionFileSchema.xsd"); attributes.addAttribute("Version", "6.0"); xmlWriter.writeStartElement("CaretDataFile", attributes); this->writeHeaderXMLWriter(xmlWriter); for (int i = 0; i < numCollections; i++) { const StudyCollection* sc = this->getStudyCollection(i); sc->writeXML(xmlWriter, i); } xmlWriter.writeEndElement(); xmlWriter.writeEndDocument(); file.close(); return filenameIn; } /** * Write the file's data (header has already been written). */ void StudyCollectionFile::writeFileData(QTextStream& /*stream*/, QDataStream& /*binStream*/, QDomDocument& xmlDoc, QDomElement& rootElement) throw (FileException) { switch (getFileWriteType()) { case FILE_FORMAT_ASCII: throw FileException(filename, "Writing in ASCII format not supported."); break; case FILE_FORMAT_BINARY: throw FileException(filename, "Writing in Binary format not supported."); break; case FILE_FORMAT_XML: writeXML(xmlDoc, rootElement); break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "Writing XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "Writing XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Writing XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Writing in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Writing in CSVF format not supported."); break; } } // //============================================================================== // /** * constructor. */ StudyCollection::StudyCollection() { clear(); } /** * destructor. */ StudyCollection::~StudyCollection() { clear(); } /** * copy constructor. */ StudyCollection::StudyCollection(const StudyCollection& sc) { parentStudyCollectionFile = NULL; copyHelper(sc); } /** * copy helper used by copy constructor and assignment operator. */ void StudyCollection::copyHelper(const StudyCollection& sc) { StudyCollectionFile* savedParentStudyCollectionFile = parentStudyCollectionFile; clear(); studyCollectionName = sc.studyCollectionName; studyCollectionCreator = sc.studyCollectionCreator; studyType = sc.studyType; comment = sc.comment; studyName = sc.studyName; pmid = sc.pmid; searchID = sc.searchID; fociListID = sc.fociListID; fociColorListID = sc.fociColorListID; sclID = sc.sclID; topic = sc.topic; categoryID = sc.categoryID; const int num = sc.getNumberOfStudyPMIDs(); for (int i = 0; i < num; i++) { StudyNamePubMedID* sid = new StudyNamePubMedID(*sc.getStudyPMID(i)); addStudyPMID(sid); } parentStudyCollectionFile = savedParentStudyCollectionFile; setModified(); } /** * assignment operator. */ StudyCollection& StudyCollection::operator=(const StudyCollection& sc) { if (this != &sc) { copyHelper(sc); } return *this; } /** * clear the collection. */ void StudyCollection::clear() { parentStudyCollectionFile = NULL; studyCollectionName = ""; studyCollectionCreator = ""; studyType = ""; comment = ""; studyName = ""; pmid = ""; searchID = ""; topic = ""; categoryID = ""; fociListID = ""; fociColorListID = ""; sclID = ""; const unsigned int num = studyPMIDs.size(); for (unsigned int i = 0; i < num; i++) { delete studyPMIDs[i]; studyPMIDs[i] = NULL; } studyPMIDs.clear(); setModified(); } /** * add a study PMID. */ void StudyCollection::addStudyPMID(StudyNamePubMedID* s) { studyPMIDs.push_back(s); const int indx = getNumberOfStudyPMIDs() - 1; studyPMIDs[indx]->setParent(this); setModified(); } /** * get a study PMID. */ StudyNamePubMedID* StudyCollection::getStudyPMID(const int indx) { if ((indx >= 0) && (indx < getNumberOfStudyPMIDs())) { return studyPMIDs[indx]; } return NULL; } /** * get a study PMID. */ const StudyNamePubMedID* StudyCollection::getStudyPMID(const int indx) const { if ((indx >= 0) && (indx < getNumberOfStudyPMIDs())) { return studyPMIDs[indx]; } return NULL; } /** * remove a study PMID. */ void StudyCollection::removeStudyPMID(const int indx) { if ((indx >= 0) && (indx < getNumberOfStudyPMIDs())) { delete studyPMIDs[indx]; studyPMIDs[indx] = NULL; studyPMIDs.erase(studyPMIDs.begin() + indx); } setModified(); } /** * set study collection name. */ void StudyCollection::setStudyCollectionName(const QString& s) { if (studyCollectionName != s) { studyCollectionName = s; setModified(); } } /** * set study collection creator. */ void StudyCollection::setStudyCollectionCreator(const QString& s) { if (studyCollectionCreator != s) { studyCollectionCreator = s; setModified(); } } /** * set study type. */ void StudyCollection::setStudyType(const QString& s) { if (studyType != s) { studyType = s; setModified(); } } /** * set comment. */ void StudyCollection::setComment(const QString& s) { if (comment != s) { comment = s; setModified(); } } /** * set study name. */ void StudyCollection::setStudyName(const QString& s) { if (studyName != s) { studyName = s; setModified(); } } /** * set PMID. */ void StudyCollection::setPMID(const QString& s) { if (pmid != s) { pmid = s; setModified(); } } /** * set search ID. */ void StudyCollection::setSearchID(const QString& s) { if (searchID != s) { searchID = s; setModified(); } } /** * set topic. */ void StudyCollection::setTopic(const QString& s) { if (topic != s) { topic = s; setModified(); } } /** * set category id. */ void StudyCollection::setCategoryID(const QString& s) { if (categoryID != s) { categoryID = s; setModified(); } } /** * set foci list ID. */ void StudyCollection::setFociListID(const QString& s) { if (fociListID != s) { fociListID = s; setModified(); } } /** * set foci color list ID. */ void StudyCollection::setFociColorListID(const QString& s) { if (fociColorListID != s) { fociColorListID = s; setModified(); } } /** * set study collection ID. */ void StudyCollection::setStudyCollectionID(const QString& s) { if (sclID != s) { sclID = s; setModified(); } } /** * set parent study collection file. */ void StudyCollection::setParentStudyCollectionFile(StudyCollectionFile* parent) { parentStudyCollectionFile = parent; const int num = getNumberOfStudyPMIDs(); for (int i = 0; i < num; i++) { getStudyPMID(i)->setParent(this); } } /** * set modified. */ void StudyCollection::setModified() { if (parentStudyCollectionFile != NULL) { parentStudyCollectionFile->setModified(); } } /** * read from XML. */ void StudyCollection::readXML(QDomNode& nodeIn) throw (FileException) { QDomNode node = nodeIn.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (elem.tagName() == "studyCollectionName") { studyCollectionName = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "studyCollectionCreator") { studyCollectionCreator = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "studyType") { studyType = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "comment") { comment = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "studyName") { studyName = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "pmid") { pmid = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "searchID") { searchID = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "fociListID") { fociListID = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "fociColorListID") { fociColorListID = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "sclID") { sclID = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "topic") { topic = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "categoryID") { categoryID = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "Studies") { QDomNode studyChildNode = node.firstChild(); while (studyChildNode.isNull() == false) { QDomElement studyChildElement = studyChildNode.toElement(); if (studyChildElement.isNull() == false) { if (studyChildElement.tagName() == "StudyNamePubMedID") { StudyNamePubMedID* s = new StudyNamePubMedID; s->readXML(studyChildNode); addStudyPMID(s); } } studyChildNode = studyChildNode.nextSibling(); } } else { std::cout << "WARNING: unrecognized Study Collection File Element: " << elem.tagName().toAscii().constData() << std::endl; } } node = node.nextSibling(); } } /** * write to XML. */ void StudyCollection::writeXML(QDomDocument& xmlDoc, QDomElement& parentElement) { // // Element for study collection // QDomElement studyCollectionElement = xmlDoc.createElement("StudyCollection"); parentElement.appendChild(studyCollectionElement); AbstractFile::addXmlCdataElement(xmlDoc, studyCollectionElement, "studyCollectionName", studyCollectionName); AbstractFile::addXmlCdataElement(xmlDoc, studyCollectionElement, "studyCollectionCreator", studyCollectionCreator); AbstractFile::addXmlCdataElement(xmlDoc, studyCollectionElement, "studyType", studyType); AbstractFile::addXmlCdataElement(xmlDoc, studyCollectionElement, "comment", comment); AbstractFile::addXmlCdataElement(xmlDoc, studyCollectionElement, "studyName", studyName); AbstractFile::addXmlCdataElement(xmlDoc, studyCollectionElement, "pmid", pmid); AbstractFile::addXmlCdataElement(xmlDoc, studyCollectionElement, "fociListID", fociListID); AbstractFile::addXmlCdataElement(xmlDoc, studyCollectionElement, "fociColorListID", fociColorListID); AbstractFile::addXmlCdataElement(xmlDoc, studyCollectionElement, "sclID", sclID); AbstractFile::addXmlCdataElement(xmlDoc, studyCollectionElement, "searchID", searchID); AbstractFile::addXmlCdataElement(xmlDoc, studyCollectionElement, "topic", topic); AbstractFile::addXmlCdataElement(xmlDoc, studyCollectionElement, "categoryID", categoryID); // // Create element for studies // QDomElement studyElement = xmlDoc.createElement("Studies"); studyCollectionElement.appendChild(studyElement); const int num = getNumberOfStudyPMIDs(); for (int i = 0; i < num; i++) { studyPMIDs[i]->writeXML(xmlDoc, studyElement); } } /** * Called to write XML */ void StudyCollection::writeXML(XmlGenericWriter& xmlWriter, int indx) const throw (FileException) { XmlGenericWriterAttributes attributes; attributes.addAttribute("Index", QString::number(indx)); xmlWriter.writeStartElement("StudyCollection", attributes); xmlWriter.writeElementCData("studyCollectionName", studyCollectionName); xmlWriter.writeElementCData("studyCollectionCreator", studyCollectionCreator); xmlWriter.writeElementCData("studyType", studyType); xmlWriter.writeElementCData("comment", comment); xmlWriter.writeElementCData("studyName", studyName); xmlWriter.writeElementCData("pmid", pmid); xmlWriter.writeElementCData("fociListID", fociListID); xmlWriter.writeElementCData("fociColorListID", fociColorListID); xmlWriter.writeElementCData("sclID", sclID); xmlWriter.writeElementCData("searchID", searchID); xmlWriter.writeElementCData("topic", topic); xmlWriter.writeElementCData("categoryID", categoryID); const int num = getNumberOfStudyPMIDs(); for (int i = 0; i < num; i++) { const StudyNamePubMedID* spmid = this->getStudyPMID(i); spmid->writeXML(xmlWriter); } xmlWriter.writeEndElement(); } caret-5.6.4~dfsg.1.orig/caret_files/SpecFileUtilities.h0000664000175000017500000000751511572067322022610 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __SPEC_FILE_UTILITIES_H__ #define __SPEC_FILE_UTILITIES_H__ #include #include #include "SpecFile.h" /// This class contains methods for assistance with spec files class SpecFileUtilities { public: enum MODE_COPY_SPEC_FILE { MODE_COPY_SPEC_FILE_NONE, MODE_COPY_SPEC_FILE_COPY_ALL, MODE_COPY_SPEC_FILE_MOVE_ALL, MODE_COPY_SPEC_FILE_POINT_TO_DATA_FILES }; /// copy a spec file (returns true if an error occurred) static bool copySpecFile(const QString& sourceSpecFileIn, const QString& targetSpecFileIn, const MODE_COPY_SPEC_FILE copySpecFileModeIn, QString& errorMessage, const bool oneMustBeCurrentDirectory = false, const bool verboseMode = true); /// zip a spec file (returns true if an error occurred) static bool zipSpecFile(const QString& specFileToZip, const QString& zipFileName, const QString& unzipDirName, QString& errorMessage, const QString& zipCommand = "", const QString& temporaryDirectory = ""); /// find spec files in specified directory static void findSpecFilesInDirectory(const QString& directory, std::vector& files); /// set the volume data file name if it is not already set static void setVolumeDataFileName(const QString& directoryName, const QString& headerFileName, QString& dataFileName); private: /// copy a group of data files static void copySpecFileDataFiles(SpecFile::Entry& fileEntry, const bool verboseMode, QString& errorMessageOut); /// copy a spec file data file static void copySpecFileCopyDataFile(QString& fileName, const QString& dataFileNameIn, const SpecFile::Entry::FILE_TYPE ft, const bool verboseMode, QString& errorMessageOut); /// copy spec file mode static MODE_COPY_SPEC_FILE copySpecFileMode; /// copy spec file mode source path static QString copySpecSourcePath; /// copy spec file mode target path static QString copySpecTargetPath; }; #endif // __SPEC_FILE_UTILITIES_H__ #ifdef __SPEC_FILE_UTILITIES_MAIN__ SpecFileUtilities::MODE_COPY_SPEC_FILE SpecFileUtilities::copySpecFileMode; QString SpecFileUtilities::copySpecSourcePath; QString SpecFileUtilities::copySpecTargetPath; #endif // __SPEC_FILE_UTILITIES_MAIN__ caret-5.6.4~dfsg.1.orig/caret_files/SpecFileUtilities.cxx0000664000175000017500000005226011572067322023160 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include "DebugControl.h" #include "FileUtilities.h" #include "SceneFile.h" #include "SpecFile.h" #include "StringUtilities.h" #include "VolumeFile.h" #define __SPEC_FILE_UTILITIES_MAIN__ #include "SpecFileUtilities.h" #undef __SPEC_FILE_UTILITIES_MAIN__ /** * Copy a spec file. Return false if no errors occur. */ bool SpecFileUtilities::copySpecFile(const QString& sourceSpecFileIn, const QString& targetSpecFileIn, const MODE_COPY_SPEC_FILE copySpecFileModeIn, QString& errorMessage, const bool oneMustBeCurrentDirectory, const bool verboseMode) { errorMessage = ""; copySpecFileMode = copySpecFileModeIn; if (copySpecFileMode == MODE_COPY_SPEC_FILE_NONE) { errorMessage = "ERROR: Invalid copy mode"; return true; } QString sourceSpecFile(sourceSpecFileIn); QString targetSpecFile(targetSpecFileIn); const QString sourceName(FileUtilities::basename(sourceSpecFile)); copySpecSourcePath = FileUtilities::dirname(sourceSpecFile); bool sourceIsCurrentDirectory = false; if (copySpecSourcePath.compare(".") == 0) { sourceIsCurrentDirectory = true; copySpecSourcePath = QDir::currentPath(); } QString targetName(FileUtilities::basename(targetSpecFile)); copySpecTargetPath = FileUtilities::dirname(targetSpecFile); QFileInfo targetInfo(targetSpecFile); if (targetInfo.isDir()) { targetName = ""; copySpecTargetPath = targetSpecFile; } if (targetName.length() == 0) { targetName = sourceName; } // // Can both be relative path, NOT // if (oneMustBeCurrentDirectory) { if ((sourceIsCurrentDirectory == false) && (copySpecTargetPath.compare(".") != 0)) { errorMessage = "ERROR: Either the source or target spec file must be in the " "current directory."; return true; } } //cout << "source-spec-file: " << sourceSpecFile << endl; //cout << "source path: " << sourcePath << endl; //cout << "source name: " << sourceName << endl; //cout << "target-spec-file: " << targetSpecFile << endl; //cout << "target path: " << targetPath << endl; //cout << "target name: " << targetName << endl; SpecFile sf; try { sf.readFile(sourceSpecFile); } catch (FileException& e) { errorMessage.append("ERROR reading: "); errorMessage.append(sourceSpecFile); errorMessage.append(" "); errorMessage.append(e.whatQString()); errorMessage.append("\n"); return true; } // // process all files except scene // for (unsigned int i = 0; i < sf.allEntries.size(); i++) { if (sf.allEntries[i] != &sf.sceneFile) { copySpecFileDataFiles(*(sf.allEntries[i]), verboseMode, errorMessage); } } // // Because the scene file contains paths, it MUST ALWAYS be copied // const MODE_COPY_SPEC_FILE savedCopyMode = copySpecFileMode; copySpecFileMode = MODE_COPY_SPEC_FILE_COPY_ALL; copySpecFileDataFiles(sf.sceneFile, verboseMode, errorMessage); copySpecFileMode = savedCopyMode; // // May need to alter paths in scene files // if (sf.sceneFile.files.empty() == false) { QString savedPath = QDir::currentPath(); QDir::setCurrent(copySpecTargetPath); try { switch (copySpecFileMode) { case MODE_COPY_SPEC_FILE_NONE: break; case MODE_COPY_SPEC_FILE_COPY_ALL: case MODE_COPY_SPEC_FILE_MOVE_ALL: for (unsigned int i = 0; i < sf.sceneFile.files.size(); i++) { SceneFile::removePathsFromAllSpecFileDataFileNames(sf.sceneFile.files[i].filename); } break; case MODE_COPY_SPEC_FILE_POINT_TO_DATA_FILES: for (unsigned int i = 0; i < sf.sceneFile.files.size(); i++) { SceneFile::addPathToAllSpecFileDataFileNames(sf.sceneFile.files[i].filename, copySpecSourcePath); } break; } } catch (FileException& e) { std::cout << "ERROR updating scene file " << e.whatQString().toAscii().constData() << std::endl; } if (savedPath.isEmpty() == false) { QDir::setCurrent(savedPath); } } QString outputName(copySpecTargetPath); if (outputName[outputName.length() - 1] != '/') { outputName.append("/"); } outputName.append(targetName); if (DebugControl::getDebugOn()) { std::cout << "INFO: Writing Spec File: " << outputName.toAscii().constData() << std::endl; } try { sf.writeFile(outputName); } catch (FileException& e) { errorMessage.append("ERROR: writing spec file named: "); errorMessage.append(targetName); errorMessage.append(" "); errorMessage.append(e.whatQString()); return true; } if (copySpecFileMode == MODE_COPY_SPEC_FILE_MOVE_ALL) { QFile file(sourceSpecFile); file.remove(); } if (errorMessage.isEmpty() == false) { return true; } return false; } /** * Copy a group os spec file data files */ void SpecFileUtilities::copySpecFileDataFiles(SpecFile::Entry& fileEntry, const bool verboseMode, QString& errorMessageOut) { for (unsigned int i = 0; i < fileEntry.files.size(); i++) { copySpecFileCopyDataFile(fileEntry.files[i].filename, fileEntry.files[i].dataFileName, fileEntry.fileType, verboseMode, errorMessageOut); } } /** * Copy a spec file's data file. */ void SpecFileUtilities::copySpecFileCopyDataFile(QString& fileName, const QString& dataFileNameIn, const SpecFile::Entry::FILE_TYPE ft, const bool verboseMode, QString& errorMessageOut) { QString dataFileName = dataFileNameIn; if (fileName.isEmpty() == false) { QFileInfo fileInfo(fileName); // // See if file is NOT an absolute path and if not prepend source directory // QString inputName; if (fileInfo.isRelative()) { inputName = copySpecSourcePath; if (inputName.isEmpty() == false) { if (fileName[inputName.length() - 1] != '/') { inputName.append("/"); } } } inputName.append(fileName); //cout << "Input File: " << inputName << endl; if (copySpecFileMode == MODE_COPY_SPEC_FILE_POINT_TO_DATA_FILES) { fileName = inputName; return; } QString outputName(copySpecTargetPath); if (outputName.isEmpty() == false) { if (outputName[outputName.length() - 1] != '/') { outputName.append("/"); } } outputName.append(FileUtilities::basename(fileName)); const bool moveFileFlag = (copySpecFileMode == MODE_COPY_SPEC_FILE_MOVE_ALL); if (FileUtilities::copyFile(inputName, outputName, moveFileFlag, verboseMode)) { errorMessageOut.append("ERROR processing: "); errorMessageOut.append(FileUtilities::basename(inputName)); errorMessageOut.append("\n"); return; } switch (ft) { case SpecFile::Entry::FILE_TYPE_SURFACE: break; case SpecFile::Entry::FILE_TYPE_VOLUME: { // // Skip single file volume files // if ((inputName.right(4) == SpecFile::getNiftiVolumeFileExtension()) || (inputName.right(7) == SpecFile::getNiftiGzipVolumeFileExtension()) || (inputName.right(5) == SpecFile::getMincVolumeFileExtension())) { // do nothing } else { try { if (dataFileName.isEmpty()) { // // Read in the volume' header // VolumeFile vf; vf.readFile(fileName, VolumeFile::VOLUME_READ_HEADER_ONLY); dataFileName = vf.getDataFileName(); } // // Determine output file. // QString outputVolumeName(copySpecTargetPath); if (outputVolumeName.isEmpty() == false) { if (outputVolumeName[outputVolumeName.length() - 1] != '/') { outputVolumeName.append("/"); } } outputVolumeName.append(FileUtilities::basename(dataFileName)); // // Determine input file // QString inputVolumeName(FileUtilities::dirname(inputName)); if (inputVolumeName.isEmpty() == false) { if (inputVolumeName[inputVolumeName.length() - 1] != '/') { inputVolumeName.append("/"); } } inputVolumeName.append(FileUtilities::basename(dataFileName)); // // See if the data does not file exist // if (QFile::exists(inputVolumeName) == false) { // // See if the gzipped version exists // QString temp(inputVolumeName); temp.append(".gz"); if (QFile::exists(temp)) { inputVolumeName.append(".gz"); outputVolumeName.append(".gz"); } } // // Process the volume's data file. // if (FileUtilities::copyFile(inputVolumeName, outputVolumeName, moveFileFlag, verboseMode)) { //std::cout << "ERROR processing: " << inputVolumeName // << " with and without \".gz\" extension." << std::endl; return; } } catch (FileException& e) { errorMessageOut.append("ERROR: Reading "); errorMessageOut.append(FileUtilities::basename(inputName)); errorMessageOut.append(" to determine the volume's data file name."); errorMessageOut.append("\n"); } } } break; case SpecFile::Entry::FILE_TYPE_OTHER: break; } // // Chop any path off the data file since it is copied to the same directory // as the new spec file. // fileName = FileUtilities::basename(fileName); } } //---------------------------------------------------------------------------------------- /** * set the volume data file name if it is not already set. */ void SpecFileUtilities::setVolumeDataFileName(const QString& directoryName, const QString& headerFileName, QString& dataFileName) { if (dataFileName.isEmpty()) { const QString savedDirectory = QDir::currentPath(); if (directoryName.isEmpty() == false) { QDir::setCurrent(directoryName); } // // Read in the volume' header // VolumeFile vf; try { vf.readFile(headerFileName, VolumeFile::VOLUME_READ_HEADER_ONLY); } catch (FileException&) { if (DebugControl::getDebugOn()) { std::cout << "INFO: Unable to read " << headerFileName.toAscii().constData() << " while trying to determine data file name." << std::endl; } QDir::setCurrent(savedDirectory); return; } // // Determine the name of volume's data file. // QString outputVolumeName(FileUtilities::dirname(headerFileName)); if (outputVolumeName.isEmpty() == false) { if (outputVolumeName == ".") { outputVolumeName = ""; } else { outputVolumeName.append("/"); } } QString inputVolumeName(vf.getDataFileName()); outputVolumeName.append(FileUtilities::basename(inputVolumeName)); // // See if the data does not file exist // if (QFile::exists(inputVolumeName) == false) { // // See if the gzipped version exists // QString temp(inputVolumeName); temp.append(".gz"); if (QFile::exists(temp)) { outputVolumeName.append(".gz"); } } // // Only add the volume data file name if it exists // if (QFile::exists(outputVolumeName)) { dataFileName = outputVolumeName; } QDir::setCurrent(savedDirectory); } } /** * find spec files in specified directory. */ void SpecFileUtilities::findSpecFilesInDirectory(const QString& directory, std::vector& files) { FileUtilities::findFilesInDirectory(directory, QStringList("*.spec"), files); } /** * zip a spec file (returns true if an error occurred). */ bool SpecFileUtilities::zipSpecFile(const QString& specFileToZipIn, const QString& zipFileNameIn, const QString& unzipDirName, QString& errorMessage, const QString& zipCommandIn, const QString& temporaryDirectoryIn) { errorMessage = ""; try { SpecFile sf; sf.readFile(specFileToZipIn); QString msg1; if (sf.validate(msg1) == false) { QString msg("Missing data files so unable to zip "); msg.append(FileUtilities::basename(specFileToZipIn)); msg.append(":\n"); msg.append(msg1); errorMessage = msg; return true; } } catch (FileException&) { QString msg("Unable to read: "); msg.append(FileUtilities::basename(specFileToZipIn)); errorMessage = msg; return true; } QString specFileToZip(specFileToZipIn); if (specFileToZip.isEmpty()) { errorMessage = "spec file name is isEmpty."; return true; } QString zipFileName(zipFileNameIn); if (zipFileName.isEmpty()) { errorMessage = "zip file name is isEmpty."; return true; } if (unzipDirName.isEmpty()) { errorMessage = "unzip directory name is isEmpty."; return true; } // // Prepend path to spec file (if needed) // if (QDir::isRelativePath(specFileToZip)) { QString s(QDir::currentPath()); s.append("/"); s.append(specFileToZip); specFileToZip = s; } // // Add zip file extension // if (StringUtilities::endsWith(StringUtilities::makeLowerCase(zipFileName), ".zip") == false) { zipFileName.append(".zip"); } // // Prepend path to zip file (if needed) // if (QDir::isRelativePath(zipFileName)) { QString s(QDir::currentPath()); s.append("/"); s.append(zipFileName); zipFileName = s; } // // Create zip command (if needed) // QString zipCommand(zipCommandIn); if (zipCommand.isEmpty()) { #ifdef Q_OS_WIN32 zipCommand = "caret_zip -r"; #else // Q_OS_WIN32 zipCommand = "zip -r"; #endif // Q_OS_WIN32 } // // Create temporary directory name (if needed) // QString temporaryDirectory(temporaryDirectoryIn); if (temporaryDirectory.isEmpty()) { temporaryDirectory = FileUtilities::temporaryDirectory(); if (temporaryDirectory.isEmpty()) { errorMessage = "Do not know name of temorary directory."; return true; } } // // Save the current directory // const QString savedDirectory(QDir::currentPath()); // // Change to the temporary directory // if (DebugControl::getDebugOn()) { std::cout << "ZIP-SPEC: Changing to the temporary directory named: " << temporaryDirectory.toAscii().constData() << std::endl; } QDir::setCurrent(temporaryDirectory); if (DebugControl::getDebugOn()) { std::cout << "ZIP-SPEC: current directory is: " << QDir::currentPath().toAscii().constData() << std::endl; } // // Create the unzip subdirectory specified by user // if (FileUtilities::createDirectory(unzipDirName) == false) { errorMessage = "ERROR: Unable to create the unzip directory: "; errorMessage.append(unzipDirName); errorMessage.append(" You may need to delete the directory \""); errorMessage.append(unzipDirName); errorMessage.append("\" in "); errorMessage.append(QDir::currentPath()); errorMessage.append("\n"); QDir::setCurrent(savedDirectory); return true; } if (DebugControl::getDebugOn()) { std::cout << "ZIP-SPEC: Creating unzip directory: " << unzipDirName.toAscii().constData() << std::endl; } // // Change to subdirectory specified by user // QDir::setCurrent(unzipDirName); if (DebugControl::getDebugOn()) { std::cout << "ZIP-SPEC: current directory is: " << QDir::currentPath().toAscii().constData() << std::endl; } // // Copy the spec file and its data files // if (DebugControl::getDebugOn()) { std::cout << "ZIP-SPEC: Copying the spec file " << specFileToZip.toAscii().constData() << std::endl; } if (SpecFileUtilities::copySpecFile(specFileToZip, FileUtilities::basename(specFileToZip), SpecFileUtilities::MODE_COPY_SPEC_FILE_COPY_ALL, errorMessage, false, true)) { QDir::setCurrent(savedDirectory); return true; } // // Go up one directory // QDir::setCurrent(".."); // // Zip the subdirectory into the zip file // if (DebugControl::getDebugOn()) { std::cout << "ZIP-SPEC: creating zip file " << FileUtilities::basename(zipFileName).toAscii().constData() << std::endl; } QString command(zipCommand); command.append(" "); command.append(FileUtilities::basename(zipFileName)); command.append(" "); command.append(unzipDirName); command.append("/*"); const int result1 = std::system(command.toAscii().constData()); const int result = ((result1 >> 8) & 0xff); if ((result != 0) || (result1 != 0)) { std::ostringstream str; str << "Execution of command " << command.toAscii().constData() << " failed with status: " << result << " and " << result1; errorMessage = str.str().c_str(); return true; } // // Move the zip file to the desired location // FileUtilities::copyFile(FileUtilities::basename(zipFileName), zipFileName, true, true); // // Remove the directory that was created and the files within it // QDir::setCurrent(unzipDirName); QDir unzipDir; for (unsigned int i = 0; i < unzipDir.count(); i++) { QFile::remove(unzipDir[i]); } QDir::setCurrent(".."); QDir d1; d1.rmdir(unzipDirName); // // Return to the original directory // QDir::setCurrent(savedDirectory); return false; } caret-5.6.4~dfsg.1.orig/caret_files/SpecFile.h0000664000175000017500000011045111572067322020706 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __SPEC_FILE_H__ #define __SPEC_FILE_H__ #include "AbstractFile.h" #include "Category.h" #include "SceneFile.h" #include "Species.h" #include "StereotaxicSpace.h" #include "Structure.h" /// SpecFile - This class is used to read, write, and manipulate a specification file. class SpecFile : public AbstractFile { public: /// True and False for SpecFile. We would prefer to use "bool" but /// std::vector is treated specially by the compiler to pack the /// bools into as little space as possible. This prevents taking the /// address of an element so we have to define our own type. /// See page 158 of "The C++ Standard Library" by Josuttis. enum SPEC_FILE_BOOL { SPEC_FALSE = false, SPEC_TRUE = true }; /// Sorting methods enum SORT { SORT_NONE, SORT_DATE, SORT_NAME }; /// brain structure types /// class for storing info about a file type class Entry { public: // type of file enum FILE_TYPE { FILE_TYPE_SURFACE, FILE_TYPE_VOLUME, FILE_TYPE_OTHER }; /// the files in the entry class Files { public: // constructor Files(const QString& filenameIn, const QString& dataFileNameIn, const Structure& structureIn, const SPEC_FILE_BOOL selectionStatus = SPEC_TRUE); // destructor ~Files(); // comparison operator bool operator<(const Files& e) const; // sort the files static void setSortMethod(const SpecFile::SORT sortMethodIn); /// name of file QString filename; /// name of data file (used by volumes with separate header and data files) QString dataFileName; /// file is selected SPEC_FILE_BOOL selected; /// structure with which file is associated Structure structure; /// how to sort static SpecFile::SORT sortMethod; }; // constructor Entry(); // destructor ~Entry(); // comparison operator bool operator<(const Entry& e) const { return descriptiveName < e.descriptiveName; } // initialize void initialize(const QString& descriptiveNameIn, const QString& specFileTagIn, const FILE_TYPE fileTypeIn, const bool specFilePatternMatchFlagIn = false); // add if tag matches (returns true if tag matched) bool addFile(const QString& tagReadIn, const QString& filenameIn, const QString& dataFileNameIn, const Structure& structureIn); // clear selection status for a file void clearSelectionStatus(const QString& filenameIn); // deselect files from other spec . void deselectFilesOtherSpec(const SpecFile& otherSpecFile); // add path to files void prependPath(const QString& path, const bool ignoreFilesWithAbsPaths); // get all files (including data files) to input vector void getAllFiles(std::vector& allFiles); // get all files (excluding data files) to input vector void getAllFilesNoDataFile(std::vector& allFiles); // clear all members except type and tag void clear(const bool removeFilesFromDiskToo); /// get number or files int getNumberOfFiles() const { return files.size(); } // get number of files selected int getNumberOfFilesSelected() const; /// get name of file QString getFileName(const int indx) const { return files[indx].filename; } /// set name of file void setFileName(const int indx, const QString& name) { files[indx].filename = name; } /// get name of data file (used by volumes with separate header and data files) QString getDataFileName(const int indx) const { return files[indx].dataFileName; } /// get file is selected SPEC_FILE_BOOL getSelected(const int indx) const { return files[indx].selected; } /// get structure with which file is associated Structure getStructure(const int indx) { return files[indx].structure; } /// get structure with which file is associated const Structure getStructure(const int indx) const { return files[indx].structure; } /// set the structure void setStructure(const int indx, const Structure& s) { files[indx].structure = s; } // Returns true if all of myFiles are in otherFiles. bool isSubset(const SpecFile& otherSpecFile, QString& errorMessage) const; // set selection based upon file name (returns true if selected) bool setSelected(const QString& name, const bool addIfNotFound, const Structure& structureIn); // make sure all files exist and are readable void validate(QString& errorMessage) const; // clean up this entry (remove entries for files that do not exist) bool cleanup(); // set all file selections void setAllSelections(const SPEC_FILE_BOOL selStatus); // remove paths from all files void removePaths(); // save scene void saveScene(SceneFile::SceneClass& sc, const bool selectedFilesOnlyFlag); // sort the files void sort(const SORT sortMethod); // write the files void writeFiles(QTextStream& stream, QDomDocument& xmlDoc, QDomElement& rootElement, const FILE_FORMAT fileFormat, const int fileVersionNumber, const bool writeOnlySelectedFiles) throw (FileException); /// get the descriptive name QString getDescriptiveName() const { return descriptiveName; } /// get the spec file tag QString getSpecFileTag() const { return specFileTag; } /// descriptive name QString descriptiveName; /// type of file FILE_TYPE fileType; /// spec file tag QString specFileTag; /// the files std::vector files; /// pattern match (this tag is subset of that found in spec file) bool specFilePatternMatchFlag; }; // Constructor SpecFile(); // Copy constructor SpecFile(const SpecFile& sf); // Destructor ~SpecFile(); // assignment operator SpecFile& operator=(const SpecFile& sf); // append a spec file to this one (files only) void append(const SpecFile& sf); // Clear the spec file void clear(); /// get the version of the spec file int getFileVersion() const { return fileVersion; } // clean the spec file (remove entries for files that do not exist) bool cleanSpecFile(); // remove files from the spec file and possibly the files themselves on the disk void clearFiles(const bool clearVolumeFiles, const bool clearSurfaceFiles, const bool clearOtherFiles, const bool removeFilesFromDiskToo); /// returns true if the file is isEmpty (contains no data) bool empty() const { return getFileName().isEmpty(); } /// set sorting performed when a spec file is read void setSorting(const SORT sort) { sorting = sort; } // Get the number of selected files int getNumberOfSelectedFiles() const; // see if only scene files are selected bool onlySceneFilesSelected() const; // get the number of entries int getNumberOfEntries() const; // get the entry at the specified index Entry* getEntry(int indx); // get all entries void getAllEntries(std::vector& allEntriesOut); // convert all data files to the specified data type void convertAllDataFilesToType(const std::vector ft, const bool printInfoToStdout); // get all of the data files in the spec file void getAllDataFilesInSpecFile(std::vector& allFiles, const bool includeVolumeDataFiles = true) const; // validate a spec file - all files exist and are readable (true if valid) bool validate(QString& errorMessage) const; // add a file to the spec file basing spec file tag off of file extension // returns true if added bool addUnknownTypeOfFileToSpecFile(const QString& fileName); // add a file to the spec file (returns true if file was written) bool addToSpecFile(const QString& tag, const QString& value1, const QString& value2, const bool writeSpecFileIfChanged); // select or deselect all files void setAllFileSelections(const SPEC_FILE_BOOL status); // set just fiducial and flat coord/topo selected void setDefaultFilesFiducialAndFlat(); // set the specified files for metric mapping // returns an error message (isEmpty if no error) QString setFilesForMetricMapping(const QString& topoFileName, const QString& coordFileName, const QString& metricFileName, const Structure structureIn); // Set the specified topology and coordinate files as selected. void setTopoAndCoordSelected(const QString& topoName, const QString& coordName, const Structure structureIn); // Set the specified topology and coordinate files as selected. void setTopoAndCoordSelected(const QString& topoName, const std::vector& coordNames, const Structure structureIn); /// set to write only files that are selected to the spec file void setWriteOnlySelectedFiles(const bool selOnly) { writeOnlySelectedFiles = selOnly; } // get the species Species getSpecies() const; // set the species void setSpecies(const Species& speciesIn); // get the subject QString getSubject() const; // set the subject void setSubject(const QString& subjectIn); // get the space StereotaxicSpace getSpace() const; // set the space void setSpace(const StereotaxicSpace& spaceIn); // get the structure Structure getStructure() const; // set the structure void setStructure(const Structure& st); // get the category Category getCategory() const; // set the category void setCategory(const Category& cat); // set current directory to path of spec file void setCurrentDirectoryToSpecFileDirectory(); // set the files selected for use by deformation void setDeformationSelectedFiles(const QString& closedTopoName, const QString& cutTopoName, const QString& fiducialCoordName, const QString& sphericalCoordName, const QString& flatCoordName, const QString& borderOrBorderProjName, const bool addIfNotFound, const Structure& structureIn); // set the files selected for multi-resolution morphing void setMultiresolutionMorphingFiles(const QString& topoFileName, const QString& fiducialFileName, const QString& flatOrSphereFileName, const Structure& structureIn); // Remove paths from all files. void removePathsFromAllFiles(); // Prepend paths to a vector of file names void prependPathsToAllFiles(const QString& path, const bool ignoreFilesWithAbsPaths); // sort all of the different files types by name void sortAllFilesByName(); // Sort all of the different files types by date void sortAllFilesByDate(); // Select files for use by WebCaret. void setWebFileSelections(); // read the spec file tags that are children of the element void readTagsFromXML(QDomElement& topElement) throw (FileException); // write the spec file tags as children of the element void writeTagsToXML(QDomDocument& xmlDoc, QDomElement& rootElement) throw (FileException); // read the spec file from a scene void showScene(const SceneFile::Scene& scene, QString& errorMessage); // write the spec file to a scene void saveScene(SceneFile::Scene& scene, const bool selectedFilesOnlyFlag); // deselect any of "my files" if they are selected in the "other spec" void deselectFilesSelectedInOtherSpecFile(SpecFile& otherSpecFile); // Returns true if "this" spec file is a subset of the "other" spec file. // In other words, all of the files listed in this spec file are in // the other spec file. bool isSubsetOfOtherSpecFile(const SpecFile& otherSpecFile, QString& errorMessage) const; // clear selection status for file name/selection pair void clearSelectionStatus(const std::vector& specNames, std::vector& selectionStatus, const QString fileName); /// write the file's memory in caret6 format to the specified name virtual QString writeFileInCaret6Format(const QString& filenameIn, Structure structure,const ColorFile* colorFileIn, const bool useCaret6ExtensionFlag) throw (FileException); // convert to caret6 spec file tag, returns empty string if tag invalid for Caret6 static QString convertToCaret6SpecFileTag(const QString& tagCaret5); // IMPORTANT if new extensions added, update the method // addUnknownTypeOfFileToSpecFile() static QString getTopoFileExtension() { return ".topo"; } static QString getCoordinateFileExtension() { return ".coord"; } static QString getTransformationMatrixFileExtension() { return ".matrix"; } static QString getLatLonFileExtension() { return ".latlon"; } static QString getSectionFileExtension() { return ".section"; } static QString getPaintFileExtension() { return ".paint"; } static QString getRegionOfInterestFileExtension() { return ".roi"; } static QString getProbabilisticAtlasFileExtension() { return ".atlas"; } static QString getAreaColorFileExtension() { return ".areacolor"; } static QString getRgbPaintFileExtension() { return ".RGB_paint"; } static QString getBorderFileExtension() { return ".border"; } static QString getBorderColorFileExtension() { return ".bordercolor"; } static QString getBorderProjectionFileExtension() { return ".borderproj"; } static QString getPaletteFileExtension() { return ".palette"; } static QString getTopographyFileExtension() { return ".topography"; } static QString getCellFileExtension() { return ".cell"; } static QString getCellColorFileExtension() { return ".cell_color"; } static QString getCellProjectionFileExtension() { return ".cellproj"; } static QString getContourFileExtension() { return ".contours"; } static QString getContourCellColorFileExtension() { return ".contour_cell_color"; } static QString getContourCellFileExtension() { return ".contour_cells"; } static QString getMetricFileExtension() { return ".metric"; } static QString getSurfaceShapeFileExtension() { return ".surface_shape"; } static QString getCocomacConnectivityFileExtension() { return ".cocomac.xml"; } static QString getArealEstimationFileExtension() { return ".areal_estimation"; } static QString getCutsFileExtension() { return ".cuts"; } static QString getFociFileExtension() { return ".foci"; } static QString getFociColorFileExtension() { return ".focicolor"; } static QString getFociProjectionFileExtension() { return ".fociproj"; } static QString getFociSearchFileExtension() { return ".focisearch"; } static QString getParamsFileExtension() { return ".params"; } static QString getDeformationMapFileExtension() { return ".deform_map"; } static QString getDeformationFieldFileExtension() { return ".deform_field"; } static QString getVtkModelFileExtension() { return ".vtk"; } static QString getGeodesicDistanceFileExtension() { return ".geodesic"; } static QString getAtlasSurfaceDirectoryFileExtension() { return ".directory"; } static QString getBrainVoyagerFileExtension() { return ".srf"; } static QString getAtlasSpaceFileExtension() { return ".atlas_space.xml"; } static QString getFreeSurferAsciiCurvatureFileExtension() { return ".curv.asc"; } static QString getFreeSurferBinaryCurvatureFileExtension() { return ".curv"; } static QString getFreeSurferAsciiFunctionalFileExtension() { return ".w.asc"; } static QString getFreeSurferBinaryFunctionalFileExtension() { return ".w"; } static QString getFreeSurferLabelFileExtension() { return ".label"; } static QString getFreeSurferAsciiSurfaceFileExtension() { return ".asc"; } static QString getFreeSurferBinarySurfaceFileExtension() { return ""; } // no extension static QString getSumaRgbFileExtension() { return ".col"; } static QString getPreferencesFileExtension() { return "caret5_preferences"; } static QString getSpecFileExtension() { return ".spec"; } static QString getAnalyzeVolumeFileExtension() { return ".hdr"; } static QString getAfniVolumeFileExtension() { return ".HEAD"; } static QString getWustlVolumeFileExtension() { return ".ifh"; } static QString getMincVolumeFileExtension() { return ".mnc"; } static QString getNiftiVolumeFileExtension() { return ".nii"; } static QString getNiftiGzipVolumeFileExtension() { return ".nii.gz"; } static QString getSceneFileExtension() { return ".scene"; } static QString getSureFitVectorFileExtension() { return ".vec"; } static QString getWustlRegionFileExtension() { return ".wustl_txt"; } static QString getLimitsFileExtension() { return ".limits"; } static QString getMDPlotFileExtension() { return ".mdo"; } static QString getGiftiGenericFileExtension() { return ".gii"; } static QString getGiftiCoordinateFileExtension() { return ".coord.gii"; } static QString getGiftiFunctionalFileExtension() { return ".func.gii"; } static QString getGiftiLabelFileExtension() { return ".label.gii"; } static QString getGiftiRgbaFileExtension() { return ".rgba.gii"; } static QString getGiftiShapeFileExtension() { return ".shape.gii"; } static QString getGiftiSurfaceFileExtension() { return ".surf.gii"; } static QString getGiftiTensorFileExtension() { return ".tensor.gii"; } static QString getGiftiTimeSeriesFileExtension() { return ".time.gii"; } static QString getGiftiTopologyFileExtension() { return ".topo.gii"; } static QString getGiftiVectorFileExtension() { return ".vector.gii"; } static QString getCommaSeparatedValueFileExtension() { return ".csv"; } static QString getVocabularyFileExtension() { return ".vocabulary"; } static QString getStudyCollectionFileExtension() { return ".study_collection"; } static QString getStudyMetaDataFileExtension() { return ".study"; } static QString getXmlFileExtension() { return ".xml"; } static QString getTextFileExtension() { return ".txt"; } static QString getNeurolucidaFileExtension() { return ".xml"; } static QString getCaretScriptFileExtension() { return ".script"; } static QString getMniObjeSurfaceFileExtension() { return ".obj"; } static QString getZipFileExtension() { return ".zip"; } static QString getMultiResMorphFileExtension() { return ".morph"; } // IMPORTANT if new extensions added, update the method // addUnknownTypeOfFileToSpecFile() /// all spec file "Entry" DO NOT CLEAR std::vector allEntries; // volume files have both header and data file Entry volumeFunctionalFile; Entry volumePaintFile; Entry volumeProbAtlasFile; Entry volumeRgbFile; Entry volumeSegmentationFile; Entry volumeAnatomyFile; Entry volumeVectorFile; Entry closedTopoFile; Entry openTopoFile; Entry cutTopoFile; Entry lobarCutTopoFile; Entry unknownTopoFile; Entry rawCoordFile; Entry fiducialCoordFile; Entry inflatedCoordFile; Entry veryInflatedCoordFile; Entry sphericalCoordFile; Entry ellipsoidCoordFile; Entry compressedCoordFile; Entry flatCoordFile; Entry lobarFlatCoordFile; Entry hullCoordFile; Entry unknownCoordFile; Entry rawSurfaceFile; Entry fiducialSurfaceFile; Entry inflatedSurfaceFile; Entry veryInflatedSurfaceFile; Entry sphericalSurfaceFile; Entry ellipsoidSurfaceFile; Entry compressedSurfaceFile; Entry flatSurfaceFile; Entry lobarFlatSurfaceFile; Entry hullSurfaceFile; Entry unknownSurfaceFile; Entry averageFiducialCoordFile; Entry latLonFile; Entry sectionFile; Entry sceneFile; Entry imageFile; Entry transformationMatrixFile; Entry paintFile; Entry areaColorFile; Entry rgbPaintFile; Entry vectorFile; Entry rawBorderFile; Entry fiducialBorderFile; Entry inflatedBorderFile; Entry veryInflatedBorderFile; Entry sphericalBorderFile; Entry ellipsoidBorderFile; Entry compressedBorderFile; Entry flatBorderFile; Entry lobarFlatBorderFile; Entry hullBorderFile; Entry unknownBorderFile; Entry volumeBorderFile; Entry borderColorFile; Entry borderProjectionFile; Entry momcTemplateFile; Entry momcTemplateMatchFile; Entry paletteFile; Entry topographyFile; Entry cellFile; Entry cellColorFile; Entry cellProjectionFile; Entry volumeCellFile; Entry contourFile; Entry contourCellFile; Entry contourCellColorFile; Entry atlasFile; Entry metricFile; Entry surfaceShapeFile; Entry cocomacConnectivityFile; Entry arealEstimationFile; Entry cutsFile; Entry fociFile; Entry fociColorFile; Entry fociProjectionFile; Entry fociSearchFile; Entry paramsFile; Entry deformationMapFile; Entry deformationFieldFile; Entry cerebralHullFile; Entry vtkModelFile; Entry geodesicDistanceFile; Entry wustlRegionFile; Entry transformationDataFile; Entry studyMetaDataFile; Entry studyCollectionFile; Entry vocabularyFile; Entry documentFile; Entry scriptFile; static QString getVolumeFunctionalFileTag() { return "volume_functional_file"; } static QString getVolumePaintFileTag() { return "volume_paint_file"; } static QString getVolumeProbAtlasFileTag() { return "volume_prob_atlas_file"; } static QString getVolumeRgbFileTag() { return "volume_rgb_file"; } static QString getVolumeSegmentationFileTag() { return "volume_segmentation_file"; } static QString getVolumeAnatomyFileTag() { return "volume_anatomy_file"; } static QString getVolumeVectorFileTag() { return "volume_vector_file"; } static QString getClosedTopoFileTag() { return "CLOSEDtopo_file"; } static QString getOpenTopoFileTag() { return "OPENtopo_file"; } static QString getCutTopoFileTag() { return "CUTtopo_file"; } static QString getLobarCutTopoFileTag() { return "LOBAR_CUTtopo_file"; } static QString getUnknownTopoFileMatchTag() { return "topo_file"; } static QString getTopoFlagTag() { return "topo_flag"; } static QString getRawCoordFileTag() { return "RAWcoord_file"; } static QString getFiducialCoordFileTag() { return "FIDUCIALcoord_file"; } static QString getInflatedCoordFileTag() { return "INFLATEDcoord_file"; } static QString getVeryInflatedCoordFileTag() { return "VERY_INFLATEDcoord_file"; } static QString getSphericalCoordFileTag() { return "SPHERICALcoord_file"; } static QString getEllipsoidCoordFileTag() { return "ELLIPSOIDcoord_file"; } static QString getCompressedCoordFileTag() { return "COMPRESSED_MEDIAL_WALLcoord_file"; } static QString getFlatCoordFileTag() { return "FLATcoord_file"; } static QString getLobarFlatCoordFileTag() { return "LOBAR_FLATcoord_file"; } static QString getHullCoordFileTag() { return "HULLcoord_file"; } static QString getUnknownCoordFileMatchTag() { return "coord_file"; } static QString getAverageFiducialCoordFileTag() { return "AVERAGE_FIDUCIALcoord_file"; } static QString getRawSurfaceFileTag() { return "RAWsurface_file"; } static QString getFiducialSurfaceFileTag() { return "FIDUCIALsurface_file"; } static QString getInflatedSurfaceFileTag() { return "INFLATEDsurface_file"; } static QString getVeryInflatedSurfaceFileTag() { return "VERY_INFLATEDsurface_file"; } static QString getSphericalSurfaceFileTag() { return "SPHERICALsurface_file"; } static QString getEllipsoidSurfaceFileTag() { return "ELLIPSOIDsurface_file"; } static QString getCompressedSurfaceFileTag() { return "COMPRESSED_MEDIAL_WALLsurface_file"; } static QString getFlatSurfaceFileTag() { return "FLATsurface_file"; } static QString getLobarFlatSurfaceFileTag() { return "LOBAR_FLATsurface_file"; } static QString getHullSurfaceFileTag() { return "HULLsurface_file"; } static QString getUnknownSurfaceFileMatchTag() { return "surface_file"; } static QString getLatLonFileTag() { return "lat_lon_file"; } static QString getSectionFileTag() { return "section_file"; } static QString getTransformationMatrixFileTag() { return "transformation_matrix_file"; } static QString getTransformationDataFileTag() { return "transformation_data_file"; } static QString getPaintFileTag() { return "paint_file"; } static QString getAreaColorFileTag() { return "area_color_file"; } static QString getRgbPaintFileTag() { return "RGBpaint_file"; } static QString getVectorFileTag() { return "vector_file"; } static QString getRawBorderFileTag() { return "RAWborder_file"; } static QString getFiducialBorderFileTag() { return "FIDUCIALborder_file"; } static QString getInflatedBorderFileTag() { return "INFLATEDborder_file"; } static QString getVeryInflatedBorderFileTag() { return "VERY_INFLATEDborder_file"; } static QString getSphericalBorderFileTag() { return "SPHERICALborder_file"; } static QString getEllipsoidBorderFileTag() { return "ELLIPSOIDborder_file"; } static QString getCompressedBorderFileTag() { return "COMPRESSED_MEDIAL_WALLborder_file"; } static QString getFlatBorderFileTag() { return "FLATborder_file"; } static QString getLobarFlatBorderFileTag() { return "LOBAR_FLATborder_file"; } static QString getHullBorderFileTag() { return "HULLborder_file"; } static QString getUnknownBorderFileMatchTag() { return "border_file"; } static QString getVolumeBorderFileTag() { return "VOLUMEborder_file"; } static QString getBorderColorFileTag() { return "border_color_file"; } static QString getBorderProjectionFileTag() { return "borderproj_file"; } static QString getPaletteFileTag() { return "palette_file"; } static QString getTopographyFileTag() { return "topography_file"; } static QString getCellFileTag() { return "cell_file"; } static QString getCellColorFileTag() { return "cell_color_file"; } static QString getCellProjectionFileTag() { return "cellproj_file"; } static QString getVolumeCellFileTag() { return "volume_cell_file"; } static QString getContourFileTag() { return "contour_file"; } static QString getContourCellFileTag() { return "contour_cell_file"; } static QString getContourCellColorFileTag() { return "contour_cell_color_file"; } static QString getFociFilterFlagTag() { return "foci_filter_flag"; } static QString getFociFileTag() { return "foci_file"; } static QString getFociColorFileTag() { return "foci_color_file"; } static QString getFociProjectionFileTag() { return "fociproj_file"; } static QString getFociSearchFileTag() { return "foci_search_file"; } static QString getAtlasFileTag() { return "atlas_file"; } static QString getMetricFileTag() { return "metric_file"; } static QString getSurfaceShapeFileTag() { return "surface_shape_file"; } static QString getCocomacConnectivityFileTag() { return "cocomac_connect_file"; } static QString getArealEstimationFileTag() { return "areal_estimation_file"; } static QString getCutsFileTag() { return "cuts_file"; } static QString getParamsFileTag() { return "params_file"; } static QString getDeformationMapFileTag() { return "deform_map_file"; } static QString getDeformationFieldFileTag() { return "deform_field_file"; } static QString getCerebralHullFileTag() { return "CEREBRAL_HULLvtk_file"; } static QString getVtkModelFileTag() { return "vtk_model_file"; } static QString getGeodesicDistanceFileTag() { return "geodesic_distance_file"; } static QString getImageFileTag() { return "image_file"; } static QString getSceneFileTag() { return "scene_file"; } static QString getScriptFileTag() { return "script_file"; } static QString getStudyCollectionFileTag() { return "study_collection_file"; } static QString getStudyMetaDataFileTag() { return "study_metadata_file"; } static QString getVocabularyFileTag() { return "vocabulary_file"; } static QString getWustlRegionFileTag() { return "wustl_region_file"; } static QString getDocumentFileTag() { return "document_file"; } static QString getFlatBorderFileTagName() { return "FLAT"; } static QString getSphericalBorderFileTagName() { return "SPHERICAL"; } protected: // copy helper used by copy constructor and operator= void copyHelperSpecFile(const SpecFile& sf); // Read the spec file data void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException); // Write the spec file data void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException); // process a tag/value pair while reading spec file bool processTag(const std::vector& tokens); /// version of the spec file int fileVersion; /// sorting performed when a spec file is read SORT sorting; // Write a set of files associated with a tag void writeFiles(QTextStream& stream, QDomDocument& xmlDoc, QDomElement& rootElement, const QString& tagName, const std::vector& names, const std::vector& selected) const; // Write a set of files (two names) associated with a tag void writeFiles(QTextStream& stream, QDomDocument& xmlDoc, QDomElement& rootElement, const QString& tagName, const std::vector& names, const std::vector& names2, const std::vector& selected) const; // Write a set of tags with files void writeFiles(QTextStream& stream, QDomDocument& xmlDoc, QDomElement& rootElement, const std::vector& tagName, const std::vector& names, const std::vector& selected) const; // Write a file associated with a tag void writeFiles(QTextStream& stream, QDomDocument& xmlDoc, QDomElement& rootElement, const QString& tagName, const QString& name, const SPEC_FILE_BOOL selected) const; // update the allEntries vector void updateAllEntries(); static QString getXmlFileTagName1() { return "file1"; } static QString getXmlFileTagName2() { return "file2"; } static QString getXmlFileTagStructure() { return "structure"; } /// only write selected files flag bool writeOnlySelectedFiles; std::vector otherTags; std::vector otherTagsValues; // NOTE: BE SURE TO UPDATE copyHelperSpecFile() if new ******************* // variables are added !!!!*********************************************** }; // class #endif // __SPEC_FILE_H__ #ifdef __SPEC_FILE_DEFINE__ SpecFile::SORT SpecFile::Entry::Files::sortMethod; // = SpecFile::SORT_DATE; #endif // __SPEC_FILE_DEFINE__ caret-5.6.4~dfsg.1.orig/caret_files/SpecFile.cxx0000664000175000017500000030460411572067322021266 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include "BorderFile.h" #include "CoordinateFile.h" #include "FileUtilities.h" #define __SPEC_FILE_DEFINE__ #include "SpecFile.h" #undef __SPEC_FILE_DEFINE__ #include "SpecFileUtilities.h" #include "SurfaceFile.h" #include "StringUtilities.h" #include "TopologyFile.h" #include "VolumeFile.h" //SpecFile::SORT SpecFile::Entry::Files::sortMethod; // = SpecFile::SORT_DATE; /** * The Constructor. */ SpecFile::SpecFile() : AbstractFile("Spec File", SpecFile::getSpecFileExtension(), true, AbstractFile::FILE_FORMAT_ASCII, //FILE_READ_WRITE_TYPE_XML, FILE_IO_READ_AND_WRITE, FILE_IO_NONE, FILE_IO_READ_AND_WRITE, FILE_IO_NONE) { sorting = SORT_DATE; clear(); volumeFunctionalFile.initialize("Volume - Functional", getVolumeFunctionalFileTag(), Entry::FILE_TYPE_VOLUME); volumePaintFile.initialize("Volume - Paint", getVolumePaintFileTag(), Entry::FILE_TYPE_VOLUME); volumeProbAtlasFile.initialize("Volume - Probabilistic Atlas", getVolumeProbAtlasFileTag(), Entry::FILE_TYPE_VOLUME); volumeRgbFile.initialize("Volume - RGB", getVolumeRgbFileTag(), Entry::FILE_TYPE_VOLUME); volumeSegmentationFile.initialize("Volume - Segmentation", getVolumeSegmentationFileTag(), Entry::FILE_TYPE_VOLUME); volumeAnatomyFile.initialize("Volume - Anatomy", getVolumeAnatomyFileTag(), Entry::FILE_TYPE_VOLUME); volumeVectorFile.initialize("Volume - Vector", getVolumeVectorFileTag(), Entry::FILE_TYPE_VOLUME); closedTopoFile.initialize("Topology - Closed", getClosedTopoFileTag(), Entry::FILE_TYPE_SURFACE); openTopoFile.initialize("Topology - Open", getOpenTopoFileTag(), Entry::FILE_TYPE_SURFACE); cutTopoFile.initialize("Topology - Cut", getCutTopoFileTag(), Entry::FILE_TYPE_SURFACE); lobarCutTopoFile.initialize("Topology - Lobar Cut", getLobarCutTopoFileTag(), Entry::FILE_TYPE_SURFACE); unknownTopoFile.initialize("Topology - Unknown", getUnknownTopoFileMatchTag(), Entry::FILE_TYPE_SURFACE, true); rawCoordFile.initialize("Coordinate - Raw", getRawCoordFileTag(), Entry::FILE_TYPE_SURFACE); fiducialCoordFile.initialize("Coordinate - Fiducial", getFiducialCoordFileTag(), Entry::FILE_TYPE_SURFACE); inflatedCoordFile.initialize("Coordinate - Inflated", getInflatedCoordFileTag(), Entry::FILE_TYPE_SURFACE); veryInflatedCoordFile.initialize("Coordinate - Very Inflated", getVeryInflatedCoordFileTag(), Entry::FILE_TYPE_SURFACE); sphericalCoordFile.initialize("Coordinate - Spherical", getSphericalCoordFileTag(), Entry::FILE_TYPE_SURFACE); ellipsoidCoordFile.initialize("Coordinate - Ellipsoid", getEllipsoidCoordFileTag(), Entry::FILE_TYPE_SURFACE); compressedCoordFile.initialize("Coordinate - Compressed Medial Wall", getCompressedCoordFileTag(), Entry::FILE_TYPE_SURFACE); flatCoordFile.initialize("Coordinate - Flat", getFlatCoordFileTag(), Entry::FILE_TYPE_SURFACE); lobarFlatCoordFile.initialize("Coordinate - Lobar Flat", getLobarFlatCoordFileTag(), Entry::FILE_TYPE_SURFACE); hullCoordFile.initialize("Coordinate - Hull", getHullCoordFileTag(), Entry::FILE_TYPE_SURFACE); averageFiducialCoordFile.initialize("Coordinate - Average Fiducial", getAverageFiducialCoordFileTag(), Entry::FILE_TYPE_SURFACE); unknownCoordFile.initialize("Coordinate - Unknown", getUnknownCoordFileMatchTag(), Entry::FILE_TYPE_SURFACE, true); rawSurfaceFile.initialize("Surface - Raw", getRawSurfaceFileTag(), Entry::FILE_TYPE_SURFACE); fiducialSurfaceFile.initialize("Surface - Fiducial", getFiducialSurfaceFileTag(), Entry::FILE_TYPE_SURFACE); inflatedSurfaceFile.initialize("Surface - Inflated", getInflatedSurfaceFileTag(), Entry::FILE_TYPE_SURFACE); veryInflatedSurfaceFile.initialize("Surface - Very Inflated", getVeryInflatedSurfaceFileTag(), Entry::FILE_TYPE_SURFACE); sphericalSurfaceFile.initialize("Surface - Spherical", getSphericalSurfaceFileTag(), Entry::FILE_TYPE_SURFACE); ellipsoidSurfaceFile.initialize("Surface - Ellipsoid", getEllipsoidSurfaceFileTag(), Entry::FILE_TYPE_SURFACE); compressedSurfaceFile.initialize("Surface - Compressed Medial Wall", getCompressedSurfaceFileTag(), Entry::FILE_TYPE_SURFACE); flatSurfaceFile.initialize("Surface - Flat", getFlatSurfaceFileTag(), Entry::FILE_TYPE_SURFACE); lobarFlatSurfaceFile.initialize("Surface - Lobar Flat", getLobarFlatSurfaceFileTag(), Entry::FILE_TYPE_SURFACE); hullSurfaceFile.initialize("Surface - Hull", getHullSurfaceFileTag(), Entry::FILE_TYPE_SURFACE); unknownSurfaceFile.initialize("Surface - Unknown", getUnknownSurfaceFileMatchTag(), Entry::FILE_TYPE_SURFACE, true); latLonFile.initialize("Latitude/Longitude File", getLatLonFileTag(), Entry::FILE_TYPE_SURFACE); sectionFile.initialize("Section File", getSectionFileTag(), Entry::FILE_TYPE_SURFACE); sceneFile.initialize("Scene File", getSceneFileTag(), Entry::FILE_TYPE_OTHER); imageFile.initialize("Image File", getImageFileTag(), Entry::FILE_TYPE_OTHER); scriptFile.initialize("Script File", getScriptFileTag(), Entry::FILE_TYPE_OTHER); transformationMatrixFile.initialize("Transformation Matrix File", getTransformationMatrixFileTag(), Entry::FILE_TYPE_SURFACE); paintFile.initialize("Paint File", getPaintFileTag(), Entry::FILE_TYPE_SURFACE); areaColorFile.initialize("Area Color File", getAreaColorFileTag(), Entry::FILE_TYPE_SURFACE); rgbPaintFile.initialize("RGB Paint File", getRgbPaintFileTag(), Entry::FILE_TYPE_SURFACE); vectorFile.initialize("Vector File", getVectorFileTag(), Entry::FILE_TYPE_OTHER); rawBorderFile.initialize("Border File - Raw", getRawBorderFileTag(), Entry::FILE_TYPE_SURFACE); fiducialBorderFile.initialize("Border File - Fiducial", getFiducialBorderFileTag(), Entry::FILE_TYPE_SURFACE); inflatedBorderFile.initialize("Border File - Inflated", getInflatedBorderFileTag(), Entry::FILE_TYPE_SURFACE); veryInflatedBorderFile.initialize("Border File - Very Inflated", getVeryInflatedBorderFileTag(), Entry::FILE_TYPE_SURFACE); sphericalBorderFile.initialize("Border File - Spherical", getSphericalBorderFileTag(), Entry::FILE_TYPE_SURFACE); ellipsoidBorderFile.initialize("Border File - Ellipsoid", getEllipsoidBorderFileTag(), Entry::FILE_TYPE_SURFACE); compressedBorderFile.initialize("Border File - Comp Med Wall", getCompressedBorderFileTag(), Entry::FILE_TYPE_SURFACE); flatBorderFile.initialize("Border File - Flat", getFlatBorderFileTag(), Entry::FILE_TYPE_SURFACE); lobarFlatBorderFile.initialize("Border File - Lobar Flat", getLobarFlatBorderFileTag(), Entry::FILE_TYPE_SURFACE); hullBorderFile.initialize("Border File - Hull", getHullBorderFileTag(), Entry::FILE_TYPE_SURFACE); unknownBorderFile.initialize("Border File - Unknown", getUnknownBorderFileMatchTag(), Entry::FILE_TYPE_SURFACE, true); volumeBorderFile.initialize("Border File - Volume", getVolumeBorderFileTag(), Entry::FILE_TYPE_SURFACE); borderColorFile.initialize("Border Color File", getBorderColorFileTag(), Entry::FILE_TYPE_SURFACE); borderProjectionFile.initialize("Border Projection File", getBorderProjectionFileTag(), Entry::FILE_TYPE_SURFACE); paletteFile.initialize("Palette File", getPaletteFileTag(), Entry::FILE_TYPE_SURFACE); topographyFile.initialize("Topography File", getTopographyFileTag(), Entry::FILE_TYPE_SURFACE); cellFile.initialize("Cell File", getCellFileTag(), Entry::FILE_TYPE_OTHER); cellColorFile.initialize("Cell Color File", getCellColorFileTag(), Entry::FILE_TYPE_OTHER); cellProjectionFile.initialize("Cell Projection File", getCellProjectionFileTag(), Entry::FILE_TYPE_OTHER); volumeCellFile.initialize("Volume Cell File", getVolumeCellFileTag(), Entry::FILE_TYPE_OTHER); contourFile.initialize("Contour File", getContourFileTag(), Entry::FILE_TYPE_OTHER); contourCellFile.initialize("Contour Cell File", getContourCellFileTag(), Entry::FILE_TYPE_OTHER); contourCellColorFile.initialize("Contour Cell Color File", getContourCellColorFileTag(), Entry::FILE_TYPE_OTHER); atlasFile.initialize("Prog Atlas File", getAtlasFileTag(), Entry::FILE_TYPE_SURFACE); metricFile.initialize("Metric File", getMetricFileTag(), Entry::FILE_TYPE_SURFACE); surfaceShapeFile.initialize("Surface Shape File", getSurfaceShapeFileTag(), Entry::FILE_TYPE_SURFACE); cocomacConnectivityFile.initialize("CoCoMac File", getCocomacConnectivityFileTag(), Entry::FILE_TYPE_SURFACE); arealEstimationFile.initialize("Areal Estimation File", getArealEstimationFileTag(), Entry::FILE_TYPE_SURFACE); cutsFile.initialize("Cuts File", getCutsFileTag(), Entry::FILE_TYPE_SURFACE); fociFile.initialize("Foci File", getFociFileTag(), Entry::FILE_TYPE_OTHER); fociColorFile.initialize("Foci Color File", getFociColorFileTag(), Entry::FILE_TYPE_OTHER); fociProjectionFile.initialize("Foci Projection File", getFociProjectionFileTag(), Entry::FILE_TYPE_OTHER); fociSearchFile.initialize("Foci Search File", getFociSearchFileTag(), Entry::FILE_TYPE_OTHER); paramsFile.initialize("Params File", getParamsFileTag(), Entry::FILE_TYPE_OTHER); deformationMapFile.initialize("Deformation Map File", getDeformationMapFileTag(), Entry::FILE_TYPE_SURFACE); deformationFieldFile.initialize("Deformation Field File", getDeformationFieldFileTag(), Entry::FILE_TYPE_SURFACE); cerebralHullFile.initialize("Cerebral Hull File", getCerebralHullFileTag(), Entry::FILE_TYPE_OTHER); vtkModelFile.initialize("VTK Model File", getVtkModelFileTag(), Entry::FILE_TYPE_SURFACE); geodesicDistanceFile.initialize("Geodesic Distance File", getGeodesicDistanceFileTag(), Entry::FILE_TYPE_SURFACE); wustlRegionFile.initialize("WUSTL Region File", getWustlRegionFileTag(), Entry::FILE_TYPE_OTHER); studyCollectionFile.initialize("Study Collection File", getStudyCollectionFileTag(), Entry::FILE_TYPE_OTHER); studyMetaDataFile.initialize("Study Metadata File", getStudyMetaDataFileTag(), Entry::FILE_TYPE_OTHER); transformationDataFile.initialize("Transformation Data File", getTransformationDataFileTag(), Entry::FILE_TYPE_SURFACE); vocabularyFile.initialize("Vocabulary File", getVocabularyFileTag(), Entry::FILE_TYPE_OTHER); documentFile.initialize("Document File", getDocumentFileTag(), Entry::FILE_TYPE_OTHER); updateAllEntries(); } /** * The Destructor. */ SpecFile::~SpecFile() { clear(); } /** * update the allEntries vector. */ void SpecFile::updateAllEntries() { allEntries.clear(); allEntries.push_back(&volumeFunctionalFile); allEntries.push_back(&volumePaintFile); allEntries.push_back(&volumeProbAtlasFile); allEntries.push_back(&volumeRgbFile); allEntries.push_back(&volumeSegmentationFile); allEntries.push_back(&volumeAnatomyFile); allEntries.push_back(&volumeVectorFile); allEntries.push_back(&closedTopoFile); allEntries.push_back(&openTopoFile); allEntries.push_back(&cutTopoFile); allEntries.push_back(&lobarCutTopoFile); // // unknownTopoFile File MUST BE AFTER ALL OTHER TOPO FILES // allEntries.push_back(&unknownTopoFile); allEntries.push_back(&rawCoordFile); allEntries.push_back(&fiducialCoordFile); allEntries.push_back(&inflatedCoordFile); allEntries.push_back(&veryInflatedCoordFile); allEntries.push_back(&sphericalCoordFile); allEntries.push_back(&ellipsoidCoordFile); allEntries.push_back(&compressedCoordFile); allEntries.push_back(&flatCoordFile); allEntries.push_back(&lobarFlatCoordFile); allEntries.push_back(&hullCoordFile); allEntries.push_back(&averageFiducialCoordFile); // // unknownCoordFile MUST BE AFTER ALL OTHER COORD FILES // allEntries.push_back(&unknownCoordFile); allEntries.push_back(&rawSurfaceFile); allEntries.push_back(&fiducialSurfaceFile); allEntries.push_back(&inflatedSurfaceFile); allEntries.push_back(&veryInflatedSurfaceFile); allEntries.push_back(&sphericalSurfaceFile); allEntries.push_back(&ellipsoidSurfaceFile); allEntries.push_back(&compressedSurfaceFile); allEntries.push_back(&flatSurfaceFile); allEntries.push_back(&lobarFlatSurfaceFile); allEntries.push_back(&hullSurfaceFile); // // unknownSurfaceFile File MUST BE AFTER ALL OTHER SURFACES // allEntries.push_back(&unknownSurfaceFile); allEntries.push_back(&latLonFile); allEntries.push_back(§ionFile); allEntries.push_back(&sceneFile); allEntries.push_back(&imageFile); allEntries.push_back(&scriptFile); allEntries.push_back(&transformationMatrixFile); allEntries.push_back(&paintFile); allEntries.push_back(&areaColorFile); allEntries.push_back(&rgbPaintFile); allEntries.push_back(&vectorFile); allEntries.push_back(&rawBorderFile); allEntries.push_back(&fiducialBorderFile); allEntries.push_back(&inflatedBorderFile); allEntries.push_back(&veryInflatedBorderFile); allEntries.push_back(&sphericalBorderFile); allEntries.push_back(&ellipsoidBorderFile); allEntries.push_back(&compressedBorderFile); allEntries.push_back(&flatBorderFile); allEntries.push_back(&lobarFlatBorderFile); allEntries.push_back(&hullBorderFile); allEntries.push_back(&volumeBorderFile); // // unknownBorderFile File MUST BE AFTER ALL OTHER BORDERS // allEntries.push_back(&unknownBorderFile); allEntries.push_back(&borderColorFile); allEntries.push_back(&borderProjectionFile); allEntries.push_back(&momcTemplateFile); allEntries.push_back(&momcTemplateMatchFile); allEntries.push_back(&paletteFile); allEntries.push_back(&topographyFile); allEntries.push_back(&cellFile); allEntries.push_back(&cellColorFile); allEntries.push_back(&cellProjectionFile); allEntries.push_back(&volumeCellFile); allEntries.push_back(&contourFile); allEntries.push_back(&contourCellFile); allEntries.push_back(&contourCellColorFile); allEntries.push_back(&atlasFile); allEntries.push_back(&metricFile); allEntries.push_back(&surfaceShapeFile); allEntries.push_back(&cocomacConnectivityFile); allEntries.push_back(&arealEstimationFile); allEntries.push_back(&cutsFile); allEntries.push_back(&fociFile); allEntries.push_back(&fociColorFile); allEntries.push_back(&fociProjectionFile); allEntries.push_back(&fociSearchFile); allEntries.push_back(¶msFile); allEntries.push_back(&deformationMapFile); allEntries.push_back(&deformationFieldFile); allEntries.push_back(&cerebralHullFile); allEntries.push_back(&vtkModelFile); allEntries.push_back(&geodesicDistanceFile); allEntries.push_back(&wustlRegionFile); allEntries.push_back(&transformationDataFile); allEntries.push_back(&studyCollectionFile); allEntries.push_back(&studyMetaDataFile); allEntries.push_back(&vocabularyFile); allEntries.push_back(&documentFile); } /** * Copy constructor. */ SpecFile::SpecFile(const SpecFile& sf) : AbstractFile(sf) { copyHelperSpecFile(sf); } /** * assignment operator. */ SpecFile& SpecFile::operator=(const SpecFile& sf) { if (this != &sf) { AbstractFile::operator=(sf); copyHelperSpecFile(sf); } return *this; } /** * copy helper used by copy constructor and operator= */ void SpecFile::copyHelperSpecFile(const SpecFile& sf) { volumeFunctionalFile = sf.volumeFunctionalFile; volumePaintFile = sf.volumePaintFile; volumeProbAtlasFile = sf.volumeProbAtlasFile; volumeRgbFile = sf.volumeRgbFile; volumeSegmentationFile = sf.volumeSegmentationFile; volumeAnatomyFile = sf.volumeAnatomyFile; volumeVectorFile = sf.volumeVectorFile; closedTopoFile = sf.closedTopoFile; openTopoFile = sf.openTopoFile; cutTopoFile = sf.cutTopoFile; lobarCutTopoFile = sf.lobarCutTopoFile; unknownTopoFile = sf.unknownTopoFile; rawCoordFile = sf.rawCoordFile; fiducialCoordFile = sf.fiducialCoordFile; inflatedCoordFile = sf.inflatedCoordFile; veryInflatedCoordFile = sf.veryInflatedCoordFile; sphericalCoordFile = sf.sphericalCoordFile; ellipsoidCoordFile = sf.ellipsoidCoordFile; compressedCoordFile = sf.compressedCoordFile; flatCoordFile = sf.flatCoordFile; lobarFlatCoordFile = sf.lobarFlatCoordFile; hullCoordFile = sf.hullCoordFile; unknownCoordFile = sf.unknownCoordFile; averageFiducialCoordFile = sf.averageFiducialCoordFile; rawSurfaceFile = sf.rawSurfaceFile; fiducialSurfaceFile = sf.fiducialSurfaceFile; inflatedSurfaceFile = sf.inflatedSurfaceFile; veryInflatedSurfaceFile = sf.veryInflatedSurfaceFile; sphericalSurfaceFile = sf.sphericalSurfaceFile; ellipsoidSurfaceFile = sf.ellipsoidSurfaceFile; compressedSurfaceFile = sf.compressedSurfaceFile; flatSurfaceFile = sf.flatSurfaceFile; lobarFlatSurfaceFile = sf.lobarFlatSurfaceFile; hullSurfaceFile = sf.hullSurfaceFile; unknownSurfaceFile = sf.unknownSurfaceFile; latLonFile = sf.latLonFile; sectionFile = sf.sectionFile; sceneFile = sf.sceneFile; imageFile = sf.imageFile; scriptFile = sf.scriptFile; transformationMatrixFile = sf.transformationMatrixFile; paintFile = sf.paintFile; areaColorFile = sf.areaColorFile; rgbPaintFile = sf.rgbPaintFile; vectorFile = sf.vectorFile; rawBorderFile = sf.rawBorderFile; fiducialBorderFile = sf.fiducialBorderFile; inflatedBorderFile = sf.inflatedBorderFile; veryInflatedBorderFile = sf.veryInflatedBorderFile; sphericalBorderFile = sf.sphericalBorderFile; ellipsoidBorderFile = sf.ellipsoidBorderFile; compressedBorderFile = sf.compressedBorderFile; flatBorderFile = sf.flatBorderFile; lobarFlatBorderFile = sf.lobarFlatBorderFile; hullBorderFile = sf.hullBorderFile; unknownBorderFile = sf.unknownBorderFile; volumeBorderFile = sf.volumeBorderFile; borderColorFile = sf.borderColorFile; borderProjectionFile = sf.borderProjectionFile; momcTemplateFile = sf.momcTemplateFile; momcTemplateMatchFile = sf.momcTemplateMatchFile; paletteFile = sf.paletteFile; topographyFile = sf.topographyFile; cellFile = sf.cellFile; cellColorFile = sf.cellColorFile; cellProjectionFile = sf.cellProjectionFile; volumeCellFile = sf.volumeCellFile; contourFile = sf.contourFile; contourCellFile = sf.contourCellFile; contourCellColorFile = sf.contourCellColorFile; atlasFile = sf.atlasFile; metricFile = sf.metricFile; surfaceShapeFile = sf.surfaceShapeFile; cocomacConnectivityFile = sf.cocomacConnectivityFile; arealEstimationFile = sf.arealEstimationFile; cutsFile = sf.cutsFile; fociFile = sf.fociFile; fociColorFile = sf.fociColorFile; fociProjectionFile = sf.fociProjectionFile; fociSearchFile = sf.fociSearchFile; paramsFile = sf.paramsFile; deformationMapFile = sf.deformationMapFile; deformationFieldFile = sf.deformationFieldFile; cerebralHullFile = sf.cerebralHullFile; vtkModelFile = sf.vtkModelFile; geodesicDistanceFile = sf.geodesicDistanceFile; studyCollectionFile = sf.studyCollectionFile; studyMetaDataFile = sf.studyMetaDataFile; vocabularyFile = sf.vocabularyFile; wustlRegionFile = sf.wustlRegionFile; documentFile = sf.documentFile; transformationDataFile = sf.transformationDataFile; fileVersion = sf.fileVersion; sorting = sf.sorting; writeOnlySelectedFiles = sf.writeOnlySelectedFiles; otherTags = sf.otherTags; otherTagsValues = sf.otherTagsValues; updateAllEntries(); } /** * Remove paths from all files. */ void SpecFile::removePathsFromAllFiles() { for (unsigned int i = 0; i < allEntries.size(); i++) { allEntries[i]->removePaths(); } } /** * Prepend paths to a vector of file names. */ void SpecFile::prependPathsToAllFiles(const QString& path, const bool ignoreFilesWithAbsPaths) { for (unsigned int i = 0; i < allEntries.size(); i++) { allEntries[i]->prependPath(path, ignoreFilesWithAbsPaths); } } /** * Clear the contents of the spec file. */ void SpecFile::clear() { fileVersion = 0; writeOnlySelectedFiles = false; setStructure(Structure()); setSpecies(Species(Species::TYPE_HUMAN)); setCategory(Category(Category::TYPE_INDIVIDUAL)); setSpace(StereotaxicSpace(StereotaxicSpace::SPACE_UNKNOWN)); clearFiles(true, true, true, false); // DO NOT CLEAR THESE // allEntries } /** * clean the spec file (remove entries for files that do not exist). */ bool SpecFile::cleanSpecFile() { // // Save the current directory // const QString savedDirectory(QDir::currentPath()); // // Set to spec file's directory // const QString fn(getFileName()); if (fn.isEmpty() == false) { QDir::setCurrent(FileUtilities::dirname(fn)); } // // Loop through entries // bool fileRemovedFlag = false; for (unsigned int j = 0; j < allEntries.size(); j++) { fileRemovedFlag |= allEntries[j]->cleanup(); } // // Restore the current directory // QDir::setCurrent(savedDirectory); return fileRemovedFlag; } /** * Remove files from the spec file and possibly the files themselves on the disk. */ void SpecFile::clearFiles(const bool clearVolumeFiles, const bool clearSurfaceFiles, const bool clearOtherFiles, const bool removeFilesFromDiskToo) { for (unsigned int i = 0; i < allEntries.size(); i++) { switch(allEntries[i]->fileType) { case Entry::FILE_TYPE_SURFACE: if (clearSurfaceFiles) { allEntries[i]->clear(removeFilesFromDiskToo); } break; case Entry::FILE_TYPE_VOLUME: if (clearVolumeFiles) { allEntries[i]->clear(removeFilesFromDiskToo); } break; case Entry::FILE_TYPE_OTHER: if (clearOtherFiles) { allEntries[i]->clear(removeFilesFromDiskToo); } break; } } } /** * get the species. */ Species SpecFile::getSpecies() const { return Species(getHeaderTag(AbstractFile::headerTagSpecies)); } /** * set the species. */ void SpecFile::setSpecies(const Species& speciesIn) { setHeaderTag(AbstractFile::headerTagSpecies, speciesIn.getName()); } /** * get the subject. */ QString SpecFile::getSubject() const { return getHeaderTag(AbstractFile::headerTagSubject); } /** * set the subject. */ void SpecFile::setSubject(const QString& subjectIn) { setHeaderTag(AbstractFile::headerTagSubject, subjectIn); } /** * get the space. */ StereotaxicSpace SpecFile::getSpace() const { return StereotaxicSpace(getHeaderTag(AbstractFile::headerTagSpace)); } /** * set the space. */ void SpecFile::setSpace(const StereotaxicSpace& spaceIn) { setHeaderTag(AbstractFile::headerTagSpace, spaceIn.getName()); } /** * get the structure. */ Structure SpecFile::getStructure() const { QString s = getHeaderTag(AbstractFile::headerTagStructure); if (s.isEmpty()) { s = getHeaderTag("hem_flag"); } return Structure(s); } /** * set the structure. */ void SpecFile::setStructure(const Structure& st) { setHeaderTag(AbstractFile::headerTagStructure, st.getTypeAsString()); } /** * get the category. */ Category SpecFile::getCategory() const { return Category(getHeaderTag(AbstractFile::headerTagCategory)); } /** * set the category. */ void SpecFile::setCategory(const Category& cat) { setHeaderTag(AbstractFile::headerTagCategory, cat.getName()); } /** * convert all data files to the specified data type. */ void SpecFile::convertAllDataFilesToType(const std::vector requestedFormats, const bool printInfoToStdout) { // // Get names of all data files // std::vector dataFiles; getAllDataFilesInSpecFile(dataFiles); // // Set to spec file's directory // const QString savedDirectory(QDir::currentPath()); setCurrentDirectoryToSpecFileDirectory(); // // Convert all files // const int num = static_cast(dataFiles.size()); for (int i = 0; i < num; i++) { const QString filename(dataFiles[i]); // // Read the header of the file // QString errorMessage; AbstractFile* af = AbstractFile::readAnySubClassDataFile(filename, true, errorMessage); if (printInfoToStdout) { std::cout << FileUtilities::basename(filename).toAscii().constData() << ": "; } if (af == NULL) { if (printInfoToStdout) { std::cout << "unable to read file or not a caret data file.\n" << "error: " << errorMessage.toAscii().constData(); } } else if (af->getFileHasHeader() == false) { if (printInfoToStdout) { std::cout << "file does not have header."; } } else { // // Get files current encoding // const QString formatString(af->getHeaderTag(AbstractFile::headerTagEncoding)); bool validFormatNameFlag = false; const AbstractFile::FILE_FORMAT currentFormat = convertFormatNameToType(formatString, &validFormatNameFlag); if (validFormatNameFlag) { bool doneFlag = false; for (unsigned int j = 0; j < requestedFormats.size(); j++) { const AbstractFile::FILE_FORMAT newFormat = requestedFormats[j]; const QString newFormatName(AbstractFile::convertFormatTypeToName(newFormat)); if (currentFormat == newFormat) { if (printInfoToStdout) { std::cout << "already in " << newFormatName.toAscii().constData() << " file format."; } doneFlag = true; } else if (af->getCanWrite(newFormat)) { try { af->readFile(filename); af->setFileWriteType(newFormat); af->writeFile(filename); if (printInfoToStdout) { std::cout << "converted to " << newFormatName.toAscii().constData() << "."; } } catch (FileException& e) { if (printInfoToStdout) { std::cout << "error converting or writing."; } } doneFlag = true; } if (doneFlag) { break; } } if (doneFlag == false) { if (printInfoToStdout) { std::cout << "does not support the requested format(s)."; } } } else { if (printInfoToStdout) { std::cout << "unrecognized format: " << formatString.toAscii().constData(); } } if (printInfoToStdout) { std::cout << std::endl; } } if (af != NULL) { delete af; // can't delete ?? compiler bug ?? //af->clear(); // so at least free up memory } } // // Restore directory // QDir::setCurrent(savedDirectory); } /** * validate a spec file - all files exist and are readable (true if valid). */ bool SpecFile::validate(QString& errorMessage) const { errorMessage = ""; // // get a list of the data files in the spec file. // exclude the volume data files. // std::vector dataFiles; getAllDataFilesInSpecFile(dataFiles, false); // // Save the current directory // const QString savedDirectory(QDir::currentPath()); // // Set to spec file's directory // const QString fn(getFileName()); if (fn.isEmpty() == false) { QDir::setCurrent(FileUtilities::dirname(fn)); } // // Check each file // for (unsigned int i = 0; i < dataFiles.size(); i++) { if (dataFiles[i].isEmpty() == false) { QFile f(dataFiles[i]); if (f.exists() == false) { errorMessage.append("DATA FILE NOT FOUND: "); errorMessage.append(dataFiles[i]); errorMessage.append("\n"); } } } // // Restore the current directory // QDir::setCurrent(savedDirectory); return errorMessage.isEmpty(); } /** * get all of the data files in the spec file. */ void SpecFile::getAllDataFilesInSpecFile(std::vector& allFiles, const bool includeVolumeDataFiles) const { allFiles.clear(); for (unsigned int i = 0; i < allEntries.size(); i++) { for (unsigned int j = 0; j < allEntries[i]->files.size(); j++) { allFiles.push_back(allEntries[i]->files[j].filename); if (includeVolumeDataFiles) { if (allEntries[i]->fileType == Entry::FILE_TYPE_VOLUME) { allFiles.push_back(allEntries[i]->files[j].dataFileName); } } } } } /** * Get the number of selected files */ int SpecFile::getNumberOfSelectedFiles() const { int numFilesSelected = 0; for (unsigned int i = 0; i < allEntries.size(); i++) { numFilesSelected += allEntries[i]->getNumberOfFilesSelected(); } return numFilesSelected; } /** * see if only scene files are selected. */ bool SpecFile::onlySceneFilesSelected() const { return (getNumberOfSelectedFiles() == sceneFile.getNumberOfFilesSelected()); } /** * Deselect all files */ void SpecFile::setAllFileSelections(const SPEC_FILE_BOOL status) { for (unsigned int i = 0; i < allEntries.size(); i++) { allEntries[i]->setAllSelections(status); } } /** * Set the specified topology and coordinate files as selected. */ void SpecFile::setTopoAndCoordSelected(const QString& topoName, const QString& coordName, const Structure structureIn) { unknownTopoFile.setSelected(topoName, true, structureIn); unknownCoordFile.setSelected(coordName, true, structureIn); } /** * Set the specified topology and coordinate files as selected. */ void SpecFile::setTopoAndCoordSelected(const QString& topoName, const std::vector& coordNames, const Structure structureIn) { unknownTopoFile.setSelected(topoName, true, structureIn); for (unsigned int i = 0; i < coordNames.size(); i++) { if (coordNames[i].isEmpty() == false) { unknownCoordFile.setSelected(coordNames[i], true, structureIn); } } } /** * set the specified files for metric mapping. Return error message which * is isEmpty if there is no error. */ QString SpecFile::setFilesForMetricMapping(const QString& topoFileName, const QString& coordFileName, const QString& metricFileName, const Structure structureIn) { const bool topoSelected = closedTopoFile.setSelected(topoFileName, false, structureIn) || openTopoFile.setSelected(topoFileName, false, structureIn) || cutTopoFile.setSelected(topoFileName, false, structureIn) || lobarCutTopoFile.setSelected(topoFileName, false, structureIn) || unknownTopoFile.setSelected(topoFileName, false, structureIn); const bool coordSelected = fiducialCoordFile.setSelected(coordFileName, false, structureIn) || rawCoordFile.setSelected(coordFileName, false, structureIn) || inflatedCoordFile.setSelected(coordFileName, false, structureIn) || veryInflatedCoordFile.setSelected(coordFileName, false, structureIn) || sphericalCoordFile.setSelected(coordFileName, false, structureIn) || ellipsoidCoordFile.setSelected(coordFileName, false, structureIn) || compressedCoordFile.setSelected(coordFileName, false, structureIn) || flatCoordFile.setSelected(coordFileName, false, structureIn) || lobarFlatCoordFile.setSelected(coordFileName, false, structureIn) || hullCoordFile.setSelected(coordFileName, false, structureIn) || unknownCoordFile.setSelected(coordFileName, false, structureIn) || averageFiducialCoordFile.setSelected(coordFileName, false, structureIn); // // Note: not a failure if metric not found // metricFile.setSelected(metricFileName, false, structureIn); QString msg; if (topoSelected == false) { msg.append("ERROR: "); msg.append(topoFileName); msg.append(" is not a topo file in the spec file."); } if (coordSelected == false) { if (msg.isEmpty() == false) { msg.append("\n"); } msg.append("ERROR: "); msg.append(coordFileName); msg.append(" is not a coord file in the spec file."); } return msg; } /** * Set default files (just Fiducial and Flat) */ void SpecFile::setDefaultFilesFiducialAndFlat() { setAllFileSelections(SPEC_FALSE); if (fiducialSurfaceFile.files.size() > 0) { fiducialSurfaceFile.files[0].selected = SPEC_TRUE; } else { if (closedTopoFile.files.size() > 0) { closedTopoFile.files[0].selected = SPEC_TRUE; } if (fiducialCoordFile.files.size() > 0) { fiducialCoordFile.files[0].selected = SPEC_TRUE; } } if (flatSurfaceFile.files.size() > 0) { flatSurfaceFile.files[0].selected = SPEC_TRUE; } else { if (cutTopoFile.files.size() > 0) { cutTopoFile.files[0].selected = SPEC_TRUE; } if (flatCoordFile.files.size() > 0) { flatCoordFile.files[0].selected = SPEC_TRUE; } } if (surfaceShapeFile.files.size() > 0) { surfaceShapeFile.files[0].selected = SPEC_TRUE; } if (paramsFile.files.size() > 0) { paramsFile.files[0].selected = SPEC_TRUE; } if (cerebralHullFile.files.size() > 0) { cerebralHullFile.files[0].selected = SPEC_TRUE; } } /** * Set the selected files or use by a deformation. */ void SpecFile::setDeformationSelectedFiles(const QString& closedTopoName, const QString& cutTopoName, const QString& fiducialCoordName, const QString& sphericalCoordName, const QString& flatCoordName, const QString& borderOrBorderProjName, const bool addIfNotFound, const Structure& structureIn) { // // Deselect all files // setAllFileSelections(SPEC_FALSE); // // Select the topo files // closedTopoFile.setSelected(closedTopoName, addIfNotFound, structureIn); closedTopoFile.setSelected(cutTopoName, addIfNotFound, structureIn); cutTopoFile.setSelected(closedTopoName, addIfNotFound, structureIn); cutTopoFile.setSelected(cutTopoName, addIfNotFound, structureIn); lobarCutTopoFile.setSelected(closedTopoName, addIfNotFound, structureIn); lobarCutTopoFile.setSelected(cutTopoName, addIfNotFound, structureIn); // // Select the coordinate files // fiducialCoordFile.setSelected(fiducialCoordName, addIfNotFound, structureIn); sphericalCoordFile.setSelected(sphericalCoordName, addIfNotFound, structureIn); flatCoordFile.setSelected(flatCoordName, addIfNotFound, structureIn); lobarFlatCoordFile.setSelected(flatCoordName, addIfNotFound, structureIn); // // Select the border file // sphericalBorderFile.setSelected(borderOrBorderProjName, addIfNotFound, structureIn); flatBorderFile.setSelected(borderOrBorderProjName, addIfNotFound, structureIn); lobarFlatBorderFile.setSelected(borderOrBorderProjName, addIfNotFound, structureIn); borderProjectionFile.setSelected(borderOrBorderProjName, addIfNotFound, structureIn); } /** * set the files selected for multi-resolution morphing. */ void SpecFile::setMultiresolutionMorphingFiles(const QString& topoFileName, const QString& fiducialFileName, const QString& flatOrSphereFileName, const Structure& structureIn) { closedTopoFile.setSelected(topoFileName, false, structureIn); openTopoFile.setSelected(topoFileName, false, structureIn); cutTopoFile.setSelected(topoFileName, false, structureIn); lobarCutTopoFile.setSelected(topoFileName, false, structureIn); unknownTopoFile.setSelected(topoFileName, false, structureIn); fiducialCoordFile.setSelected(fiducialFileName, false, structureIn); sphericalCoordFile.setSelected(flatOrSphereFileName, false, structureIn); flatCoordFile.setSelected(flatOrSphereFileName, false, structureIn); lobarFlatCoordFile.setSelected(flatOrSphereFileName, false, structureIn); } /** * append a spec file to this one (files only). */ void SpecFile::append(const SpecFile& sf) { for (unsigned int i = 0; i < sf.allEntries.size(); i++) { const Entry* e = sf.allEntries[i]; const QString tag = e->getSpecFileTag(); for (int j = 0; j < e->getNumberOfFiles(); j++) { const QString fileName = e->getFileName(j); const QString dataName = e->getDataFileName(j); addToSpecFile(tag, fileName, dataName, false); } } } /** * add a file to the spec file basing spec file tag off of file extension * returns true if added. */ bool SpecFile::addUnknownTypeOfFileToSpecFile(const QString& fileName) { const QString noTagForFile(""); QString tag; if (fileName.endsWith(getTopoFileExtension())) { try { TopologyFile tf; tf.readFile(fileName); tag = TopologyFile::getSpecFileTagFromTopologyType(tf.getTopologyType()); } catch (FileException&) { } } else if (fileName.endsWith(getCoordinateFileExtension())) { try { CoordinateFile cf; cf.readFile(fileName); tag = cf.getSpecFileTagUsingConfigurationID(); } catch (FileException&) { } } else if (fileName.endsWith(getTransformationMatrixFileExtension())) { tag = SpecFile::getTransformationMatrixFileTag(); } else if (fileName.endsWith(getLatLonFileExtension())) { tag = getLatLonFileTag(); } else if (fileName.endsWith(getSectionFileExtension())) { tag = getSectionFileTag(); } else if (fileName.endsWith(getPaintFileExtension())) { tag = getPaintFileTag(); } else if (fileName.endsWith(getRegionOfInterestFileExtension())) { tag = noTagForFile; } else if (fileName.endsWith(getProbabilisticAtlasFileExtension())) { tag = getAtlasFileTag(); } else if (fileName.endsWith(getAreaColorFileExtension())) { tag = getAreaColorFileTag(); } else if (fileName.endsWith(getRgbPaintFileExtension())) { tag = getRgbPaintFileTag(); } else if (fileName.endsWith(getBorderFileExtension())) { BorderFile bf; bf.readFileMetaDataOnly(fileName); const QString typeTag = bf.getHeaderTag(AbstractFile::headerTagConfigurationID); tag = BorderFile::convertConfigurationIDToSpecFileTag(typeTag); } else if (fileName.endsWith(getBorderColorFileExtension())) { tag = getBorderColorFileTag(); } else if (fileName.endsWith(getBorderProjectionFileExtension())) { tag = getBorderProjectionFileTag(); } else if (fileName.endsWith(getPaletteFileExtension())) { tag = getPaletteFileTag(); } else if (fileName.endsWith(getTopographyFileExtension())) { tag = getTopographyFileTag(); } else if (fileName.endsWith(getCellFileExtension())) { tag = getCellFileTag(); } else if (fileName.endsWith(getCellColorFileExtension())) { tag = getCellColorFileTag(); } else if (fileName.endsWith(getCellProjectionFileExtension())) { tag = getCellProjectionFileTag(); } else if (fileName.endsWith(getContourFileExtension())) { tag = getContourFileTag(); } else if (fileName.endsWith(getContourCellColorFileExtension())) { tag = getContourCellColorFileTag(); } else if (fileName.endsWith(getContourCellFileExtension())) { tag = getContourCellFileTag(); } else if (fileName.endsWith(getMetricFileExtension())) { tag = getMetricFileTag(); } else if (fileName.endsWith(getSurfaceShapeFileExtension())) { tag = getSurfaceShapeFileTag(); } else if (fileName.endsWith(getCocomacConnectivityFileExtension())) { tag = getCocomacConnectivityFileTag(); } else if (fileName.endsWith(getArealEstimationFileExtension())) { tag = getArealEstimationFileTag(); } else if (fileName.endsWith(getCutsFileExtension())) { tag = getCutsFileTag(); } else if (fileName.endsWith(getFociFileExtension())) { tag = getFociFileTag(); } else if (fileName.endsWith(getFociColorFileExtension())) { tag = getFociColorFileTag(); } else if (fileName.endsWith(getFociProjectionFileExtension())) { tag = getFociProjectionFileTag(); } else if (fileName.endsWith(getFociSearchFileExtension())) { tag = getFociSearchFileTag(); } else if (fileName.endsWith(getParamsFileExtension())) { tag = getParamsFileTag(); } else if (fileName.endsWith(getDeformationMapFileExtension())) { tag = getDeformationMapFileTag(); } else if (fileName.endsWith(getDeformationFieldFileExtension())) { tag = getDeformationFieldFileTag(); } else if (fileName.endsWith(getVtkModelFileExtension())) { tag = noTagForFile; } else if (fileName.endsWith(getGeodesicDistanceFileExtension())) { tag = getGeodesicDistanceFileTag(); } else if (fileName.endsWith(getAtlasSurfaceDirectoryFileExtension())) { tag = noTagForFile; } else if (fileName.endsWith(getBrainVoyagerFileExtension())) { tag = noTagForFile; } else if (fileName.endsWith(getAtlasSpaceFileExtension())) { tag = noTagForFile; } else if (fileName.endsWith(getFreeSurferAsciiCurvatureFileExtension())) { tag = noTagForFile; } else if (fileName.endsWith(getFreeSurferBinaryCurvatureFileExtension())) { tag = noTagForFile; } else if (fileName.endsWith(getFreeSurferAsciiFunctionalFileExtension())) { tag = noTagForFile; } else if (fileName.endsWith(getFreeSurferBinaryFunctionalFileExtension())) { tag = noTagForFile; } else if (fileName.endsWith(getFreeSurferLabelFileExtension())) { tag = noTagForFile; } else if (fileName.endsWith(getFreeSurferAsciiSurfaceFileExtension())) { tag = noTagForFile; } //else if (fileName.endsWith(getFreeSurferBinarySurfaceFileExtension())) { // tag = noTagForFile; // FS Binary Surface has no extension //} else if (fileName.endsWith(getSumaRgbFileExtension())) { tag = noTagForFile; } else if (fileName.endsWith(getPreferencesFileExtension())) { tag = noTagForFile; } else if (fileName.endsWith(getSpecFileExtension())) { tag = noTagForFile; } else if ((fileName.endsWith(getAnalyzeVolumeFileExtension())) || (fileName.endsWith(getAfniVolumeFileExtension())) || (fileName.endsWith(getWustlVolumeFileExtension())) || (fileName.endsWith(getMincVolumeFileExtension())) || (fileName.endsWith(getNiftiVolumeFileExtension())) || (fileName.endsWith(getNiftiGzipVolumeFileExtension()))) { try { VolumeFile vf; vf.readFile(fileName); switch (vf.getVolumeType()) { case VolumeFile::VOLUME_TYPE_ANATOMY: tag = getVolumeAnatomyFileTag(); break; case VolumeFile::VOLUME_TYPE_FUNCTIONAL: tag = getVolumeFunctionalFileTag(); break; case VolumeFile::VOLUME_TYPE_PAINT: tag = getVolumePaintFileTag(); break; case VolumeFile::VOLUME_TYPE_PROB_ATLAS: tag = getVolumeProbAtlasFileTag(); break; case VolumeFile::VOLUME_TYPE_RGB: tag = getVolumeRgbFileTag(); break; case VolumeFile::VOLUME_TYPE_SEGMENTATION: tag = getVolumeSegmentationFileTag(); break; case VolumeFile::VOLUME_TYPE_VECTOR: tag = getVolumeVectorFileTag(); break; case VolumeFile::VOLUME_TYPE_ROI: break; case VolumeFile::VOLUME_TYPE_UNKNOWN: tag = getVolumeAnatomyFileTag(); break; } } catch (FileException&) { } } else if (fileName.endsWith(getSceneFileExtension())) { tag = getSceneFileTag(); } else if (fileName.endsWith(getSureFitVectorFileExtension())) { tag = noTagForFile; } else if (fileName.endsWith(getWustlRegionFileExtension())) { tag = getWustlRegionFileTag(); } else if (fileName.endsWith(getLimitsFileExtension())) { tag = noTagForFile; } else if (fileName.endsWith(getMDPlotFileExtension())) { tag = noTagForFile; } //else if (fileName.endsWith(getGiftiGenericFileExtension())) { // tag = noTagForFile; DO NOT TEST FOR GENERIC EXTENSION OTHERWISE // THE REMAINING GIFTI EXTENSIONS WILL FAIL //} else if (fileName.endsWith(getGiftiCoordinateFileExtension())) { try { CoordinateFile cf; cf.readFile(fileName); tag = cf.getSpecFileTagUsingConfigurationID(); } catch (FileException&) { } } else if (fileName.endsWith(getGiftiFunctionalFileExtension())) { tag = getMetricFileTag(); } else if (fileName.endsWith(getGiftiLabelFileExtension())) { tag = getPaintFileTag(); } else if (fileName.endsWith(getGiftiRgbaFileExtension())) { tag = getRgbPaintFileTag(); } else if (fileName.endsWith(getGiftiShapeFileExtension())) { tag = getSurfaceShapeFileTag(); } else if (fileName.endsWith(getGiftiSurfaceFileExtension())) { try { SurfaceFile sf; sf.readFile(fileName); const QString configID = sf.getCoordinateType(); tag = SurfaceFile::convertConfigurationIDToSpecFileTag(configID); } catch (FileException&) { } } else if (fileName.endsWith(getGiftiTensorFileExtension())) { tag = noTagForFile; } else if (fileName.endsWith(getGiftiTimeSeriesFileExtension())) { tag = getMetricFileTag(); } else if (fileName.endsWith(getGiftiTopologyFileExtension())) { try { TopologyFile tf; tf.readFile(fileName); tag = TopologyFile::getSpecFileTagFromTopologyType(tf.getTopologyType()); } catch (FileException&) { } } else if (fileName.endsWith(getGiftiVectorFileExtension())) { tag = getVectorFileTag(); } else if (fileName.endsWith(getCommaSeparatedValueFileExtension())) { tag = noTagForFile; } else if (fileName.endsWith(getVocabularyFileExtension())) { tag = getVocabularyFileTag(); } else if (fileName.endsWith(getStudyCollectionFileExtension())) { tag = getStudyCollectionFileTag(); } else if (fileName.endsWith(getStudyMetaDataFileExtension())) { tag = getStudyMetaDataFileTag(); } else if (fileName.endsWith(getXmlFileExtension())) { tag = noTagForFile; } else if (fileName.endsWith(getTextFileExtension())) { tag = noTagForFile; } else if (fileName.endsWith(getNeurolucidaFileExtension())) { tag = noTagForFile; } else if (fileName.endsWith(getCaretScriptFileExtension())) { tag = getScriptFileTag(); } else if (fileName.endsWith(getMniObjeSurfaceFileExtension())) { tag = noTagForFile; } if (tag.isEmpty() == false) { addToSpecFile(tag, fileName, "", false); return true; } return false; } /** * Add a tag/file to the spec file. Make the file's path relative * to the spec file and then write the spec file if the spec file has * a name. Returns true if the file was written. */ bool SpecFile::addToSpecFile(const QString& tag, const QString& value1In, const QString& value2In, const bool writeSpecFileIfChanged) { bool fileWasWrittenFlag = false; QString value(value1In); if (getFileName().isEmpty() == false) { FileUtilities::relativePath(value1In, getFileNamePath(), value); } else { value = FileUtilities::basename(value1In); } std::vector tokens; tokens.push_back(tag); tokens.push_back(value); if (value2In.isEmpty() == false) { tokens.push_back(FileUtilities::basename(value2In)); } const bool newFileFlag = processTag(tokens); if (newFileFlag) { setModified(); if (writeSpecFileIfChanged) { if (getFileName().isEmpty() == false) { try { writeFile(getFileName()); fileWasWrittenFlag = true; } catch (FileException& e) { } } } } return fileWasWrittenFlag; } /** * Process tags as they are read from the spec file anfd automatically selecte them. * Returns true if the file was not already part of the spec file. */ bool SpecFile::processTag(const std::vector& tokens) { if (tokens.size() < 2) { return false; } Structure st; QString filename; QString dataFileName; const int num = static_cast(tokens.size()); int indx = 0; const QString tag(tokens[indx]); indx++; QString stString; if (fileVersion >= 1) { stString = tokens[indx]; st.setTypeFromString(tokens[indx]); indx++; } if (indx < num) { filename = tokens[indx]; indx++; } else { return false; } if (indx < num) { dataFileName = tokens[indx]; const QString directory(FileUtilities::dirname(filename)); SpecFileUtilities::setVolumeDataFileName(directory, filename, dataFileName); } for (unsigned int i = 0; i < allEntries.size(); i++) { if (allEntries[i]->addFile(tag, filename, dataFileName, st)) { return true; } } //std::cout << "Unknown Spec File tag moved to header: " << tag.toAscii().constData() << std::endl; std::ostringstream str; str << stString.toAscii().constData() << " " << filename.toAscii().constData() << " " << dataFileName.toAscii().constData(); setHeaderTag(tag, filename); return false; } /** * Read the spec file's data. */ void SpecFile::readFileData(QFile& /*file*/, QTextStream& stream, QDataStream&, QDomElement& rootElement) throw (FileException) { fileVersion = 0; // // 7112B changed to 711-2B // if (getHeaderTag(AbstractFile::headerTagSpace) == "7112B") { setHeaderTag(AbstractFile::headerTagSpace, "711-2B"); } switch (getFileReadType()) { case FILE_FORMAT_ASCII: { while(stream.atEnd() == false) { std::vector tokens; QString line; readLineIntoTokens(stream, line, tokens); if (line.isEmpty() == false) { if (line[0] != '#') { if (tokens.empty() == false) { processTag(tokens); } } } } } break; case FILE_FORMAT_BINARY: throw FileException(filename, "Reading in Binary format not supported."); break; case FILE_FORMAT_XML: { QDomNode node = rootElement.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { std::vector tokens; tokens.push_back(elem.tagName()); QString val1, val2; QDomNode childNode = elem.firstChild(); while (childNode.isNull() == false) { QDomElement elemChild = childNode.toElement(); if (elemChild.isNull() == false) { if (elemChild.tagName() == getXmlFileTagName1()) { val1 = getXmlElementFirstChildAsString(elemChild); } else if (elemChild.tagName() == getXmlFileTagName2()) { val2 = getXmlElementFirstChildAsString(elemChild); } } childNode = childNode.nextSibling(); } if (val1.isEmpty() == false) { tokens.push_back(val1); if (val2.isEmpty() == false) { tokens.push_back(val2); } } if (tokens.empty() == false) { processTag(tokens); } } node = node.nextSibling(); } } break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Reading XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Reading in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Comma Separated Value File Format not supported."); break; } switch (sorting) { case SORT_NONE: break; case SORT_DATE: sortAllFilesByDate(); break; case SORT_NAME: sortAllFilesByName(); break; } // // For version 0 files, all files are for one structure // if (fileVersion == 0) { Structure st(getStructure()); for (unsigned int i = 0; i < allEntries.size(); i++) { for (int j = 0; j < allEntries[i]->getNumberOfFiles(); j++) { allEntries[i]->files[j].structure = st; } } } } /** * read the spec file tags that are children of the element. */ void SpecFile::readTagsFromXML(QDomElement& topElement) throw (FileException) { const bool modFlag = getModified(); FILE_FORMAT savedReadType = getFileReadType(); setFileReadType(FILE_FORMAT_XML); QFile file; QTextStream textStream; QDataStream dataStream; dataStream.setVersion(QDataStream::Qt_4_3); readFileData(file, textStream, dataStream, topElement); setFileReadType(savedReadType); if (modFlag == false) { clearModified(); } } /** * Write the spec file's data. */ void SpecFile::writeFileData(QTextStream& stream, QDataStream&, QDomDocument& xmlDoc, QDomElement& rootElement) throw (FileException) { bool streamValid = false; switch (getFileWriteType()) { case FILE_FORMAT_ASCII: streamValid = true; break; case FILE_FORMAT_BINARY: throw FileException(filename, "Writing in Binary format not supported."); break; case FILE_FORMAT_XML: break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Writing XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Writing in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Comma Separated Value File Format not supported."); break; } if (streamValid) stream << "\n"; for (unsigned int i = 0; i < allEntries.size(); i++) { allEntries[i]->writeFiles(stream, xmlDoc, rootElement, getFileWriteType(), fileVersion, writeOnlySelectedFiles); } if (streamValid) stream << "\n"; writeOnlySelectedFiles = false; } /** * write the spec file tags as children of the element. */ void SpecFile::writeTagsToXML(QDomDocument& xmlDoc, QDomElement& topElement) throw (FileException) { const bool modFlag = getModified(); FILE_FORMAT savedWriteType = getFileWriteType(); setFileWriteType(FILE_FORMAT_XML); QTextStream textStream; QDataStream dataStream; dataStream.setVersion(QDataStream::Qt_4_3); writeFileData(textStream, dataStream, xmlDoc, topElement); setFileWriteType(savedWriteType); if (modFlag == false) { clearModified(); } } /// This class is used to sort files by the last modified time (used by spec file) class SortedString { public: enum SORTING { SORTING_BY_DATE, SORTING_BY_NAME }; static SORTING sortMethod; QString s1; QString s2; long time; static void setSortMethod(const SORTING s) { sortMethod = s; } static SORTING getSortMethod() { return sortMethod; } SortedString(const QString& filename, const QString filename2 = "") { s1 = filename; s2 = filename2; QFileInfo fi(s1); time = static_cast(fi.lastModified().toTime_t()); } }; SortedString::SORTING SortedString::sortMethod = SortedString::SORTING_BY_DATE; bool operator<(const SortedString& s1, const SortedString& s2) { switch (SortedString::getSortMethod()) { case SortedString::SORTING_BY_DATE: return (s1.time < s2.time); break; case SortedString::SORTING_BY_NAME: break; return (s1.s1 < s2.s1); } return false; } //bool operator>(const SortedString& s1, const SortedString& s2) { // return (s1.time > s2.time); //} bool sortSortedString(const SortedString& s1, const SortedString& s2) { switch (SortedString::getSortMethod()) { case SortedString::SORTING_BY_DATE: return (s1.time > s2.time); break; case SortedString::SORTING_BY_NAME: return (s1.s1 < s2.s1); break; } return false; } /** * */ void SpecFile::setCurrentDirectoryToSpecFileDirectory() { if (QDir::setCurrent(getFileNamePath()) == false) { std::cerr << "Unable to set path of current spec file, cannot sort by time" << std::endl; return; } } /** * Sort the different file types by date. Note this only sorts the * "files" and not their "selected" status. */ void SpecFile::sortAllFilesByDate() { const QString savedCurrentDirectory(QDir::currentPath()); if (QDir::setCurrent(getFileNamePath()) == false) { std::cerr << "Unable to set path of current spec file, cannot sort by time" << std::endl; return; } for (unsigned int i = 0; i < allEntries.size(); i++) { allEntries[i]->sort(SORT_DATE); } QDir::setCurrent(savedCurrentDirectory); } /** * Sort the different file types by name. Note this only sorts the * "files" and not their "selected" status. */ void SpecFile::sortAllFilesByName() { for (unsigned int i = 0; i < allEntries.size(); i++) { allEntries[i]->sort(SORT_NAME); } } /** * Write a set of files associated with a tag. */ void SpecFile::writeFiles(QTextStream& stream, QDomDocument& xmlDoc, QDomElement& rootElement, const QString& tagName, const std::vector& names, const std::vector& selected) const { for (unsigned int i = 0; i < names.size(); i++) { if (names[i].isEmpty() == false) { bool writeIt = true; if (names[i][0] == '*') { writeIt = false; } if (writeOnlySelectedFiles && (selected[i] == SPEC_FALSE)) { writeIt = false; } if (writeIt) { switch (getFileWriteType()) { case FILE_FORMAT_ASCII: stream << tagName << " " << names[i] << "\n"; break; case FILE_FORMAT_BINARY: throw FileException(filename, "Writing in Binary format not supported."); break; case FILE_FORMAT_XML: { QDomElement tagElem = xmlDoc.createElement(tagName); QDomElement tag1 = xmlDoc.createElement(getXmlFileTagName1()); QDomCDATASection tagValue1 = xmlDoc.createCDATASection(names[i]); tag1.appendChild(tagValue1); tagElem.appendChild(tag1); rootElement.appendChild(tagElem); } break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Writing XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Writing in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Comma Separated Value File Format not supported."); break; } } } } } /** * Write a set of files (two names) associated with a tag. */ void SpecFile::writeFiles(QTextStream& stream, QDomDocument& xmlDoc, QDomElement& rootElement, const QString& tagName, const std::vector& names, const std::vector& names2, const std::vector& selected) const { for (unsigned int i = 0; i < names.size(); i++) { if (names[i].isEmpty() == false) { bool writeIt = true; if (names[i][0] == '*') { writeIt = false; } if (writeOnlySelectedFiles && (selected[i] == SPEC_FALSE)) { writeIt = false; } if (writeIt) { switch (getFileWriteType()) { case FILE_FORMAT_ASCII: stream << tagName << " " << names[i]; if ((names2[i].isEmpty() == false) && (names2[i] != names[i])) { stream << " " << names2[i]; } stream << "\n"; break; case FILE_FORMAT_BINARY: throw FileException(filename, "Writing in Binary format not supported."); break; case FILE_FORMAT_XML: { QDomElement tagElem = xmlDoc.createElement(tagName); QDomElement tag1 = xmlDoc.createElement(getXmlFileTagName1()); QDomCDATASection tagValue1 = xmlDoc.createCDATASection(names[i]); tag1.appendChild(tagValue1); tagElem.appendChild(tag1); if ((names2[i].isEmpty() == false) && (names2[i] != names[i])) { QDomElement tag2 = xmlDoc.createElement(getXmlFileTagName2()); QDomCDATASection tagValue2 = xmlDoc.createCDATASection(names2[i]); tag2.appendChild(tagValue2); tagElem.appendChild(tag2); } rootElement.appendChild(tagElem); } break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Writing XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Writing in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Comma Separated Value File Format not supported."); break; } } } } } /** * Write a set of files with a set of tags. */ void SpecFile::writeFiles(QTextStream& stream, QDomDocument& xmlDoc, QDomElement& rootElement, const std::vector& tagName, const std::vector& names, const std::vector& selected) const { for (unsigned int i = 0; i < names.size(); i++) { if (names[i].isEmpty() == false) { bool writeIt = true; if (names[i][0] == '*') { writeIt = false; } if (writeOnlySelectedFiles && (selected[i] == SPEC_FALSE)) { writeIt = false; } if (writeIt) { switch (getFileWriteType()) { case FILE_FORMAT_ASCII: stream << tagName[i] << " " << names[i] << "\n"; break; case FILE_FORMAT_BINARY: throw FileException(filename, "Writing in Binary format not supported."); break; case FILE_FORMAT_XML: { QDomElement tagElem = xmlDoc.createElement(tagName[i]); QDomElement tag1 = xmlDoc.createElement(getXmlFileTagName1()); QDomCDATASection tagValue1 = xmlDoc.createCDATASection(names[i]); tag1.appendChild(tagValue1); tagElem.appendChild(tag1); rootElement.appendChild(tagElem); } break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Writing XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Writing in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Comma Separated Value File Format not supported."); break; } } } } } /** * Write a file associated with a tag. */ void SpecFile::writeFiles(QTextStream& stream, QDomDocument& xmlDoc, QDomElement& rootElement, const QString& tagName, const QString& name, const SPEC_FILE_BOOL selected) const { if (name.isEmpty() == false) { bool writeIt = true; if (name[0] == '*') { writeIt = false; } if (writeOnlySelectedFiles && (selected == SPEC_FALSE)) { writeIt = false; } if (writeIt) { switch (getFileWriteType()) { case FILE_FORMAT_ASCII: stream << tagName << " " << name << "\n"; break; case FILE_FORMAT_BINARY: throw FileException(filename, "Writing in Binary format not supported."); break; case FILE_FORMAT_XML: { QDomElement tagElem = xmlDoc.createElement(tagName); QDomElement tag1 = xmlDoc.createElement(getXmlFileTagName1()); QDomCDATASection tagValue1 = xmlDoc.createCDATASection(name); tag1.appendChild(tagValue1); tagElem.appendChild(tag1); rootElement.appendChild(tagElem); } break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Writing XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Writing in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Comma Separated Value File Format not supported."); break; } } } } /** * Select files for use by WebCaret. */ void SpecFile::setWebFileSelections() { setAllFileSelections(SPEC_FALSE); if (closedTopoFile.files.size() > 0) { closedTopoFile.files[0].selected = SPEC_TRUE; } if (cutTopoFile.files.size() > 0) { cutTopoFile.files[0].selected = SPEC_TRUE; } if (fiducialCoordFile.files.size() > 0) { fiducialCoordFile.files[0].selected = SPEC_TRUE; } if (inflatedCoordFile.files.size() > 0) { inflatedCoordFile.files[0].selected = SPEC_TRUE; } if (veryInflatedCoordFile.files.size() > 0) { veryInflatedCoordFile.files[0].selected = SPEC_TRUE; } if (sphericalCoordFile.files.size() > 0) { sphericalCoordFile.files[0].selected = SPEC_TRUE; } if (flatCoordFile.files.size() > 0) { flatCoordFile.files[0].selected = SPEC_TRUE; } if (surfaceShapeFile.files.size() > 0) { surfaceShapeFile.files[0].selected = SPEC_TRUE; } if (areaColorFile.files.size() > 0) { areaColorFile.files[0].selected = SPEC_TRUE; } if (paintFile.files.size() > 0) { paintFile.files[0].selected = SPEC_TRUE; } if (metricFile.files.size() > 0) { metricFile.files[0].selected = SPEC_TRUE; } if (rgbPaintFile.files.size() > 0) { rgbPaintFile.files[0].selected = SPEC_TRUE; } sceneFile.setAllSelections(SPEC_TRUE); } /** * read the spec file from a scene. */ void SpecFile::showScene(const SceneFile::Scene& scene, QString& /*errorMessage*/) { clear(); const int numClasses = scene.getNumberOfSceneClasses(); for (int nc = 0; nc < numClasses; nc++) { const SceneFile::SceneClass* sc = scene.getSceneClass(nc); if (sc->getName() == "SpecFile") { const int num = sc->getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc->getSceneInfo(i); const QString infoName = si->getName(); const QString val = si->getValueAsString(); QString name1, name2; if (val.indexOf(':') == -1) { name1 = val; } else { std::vector tokens; StringUtilities::token(val, ":", tokens); if (tokens.size() > 0) { name1 = tokens[0]; if (tokens.size() > 1) { name2 = tokens[1]; } } } if (name1.isEmpty() == false) { std::vector tokens; tokens.push_back(infoName); tokens.push_back(name1); if (name2.isEmpty() == false) { tokens.push_back(name2); } // // Do all but Scene Files // if (infoName != getSceneFileTag()) { processTag(tokens); } } } } } } /** * write the spec file to a scene. */ void SpecFile::saveScene(SceneFile::Scene& scene, const bool selectedFilesOnlyFlag) { SceneFile::SceneClass sc("SpecFile"); for (unsigned int i = 0; i < allEntries.size(); i++) { allEntries[i]->saveScene(sc, selectedFilesOnlyFlag); } if (sc.getNumberOfSceneInfo() > 0) { scene.addSceneClass(sc); } } /** * clear selection status for file name/selection pair. */ void SpecFile::clearSelectionStatus(const std::vector& specNames, std::vector& selectionStatus, const QString fileName) { for (unsigned int i = 0; i < specNames.size(); i++) { if (FileUtilities::basename(specNames[i]) == FileUtilities::basename(fileName)) { selectionStatus[i] = SPEC_FALSE; break; } } } /** * deselect any of "my files" if they are selected in the "other spec". */ void SpecFile::deselectFilesSelectedInOtherSpecFile(SpecFile& otherSpecFile) { for (unsigned int i = 0; i < allEntries.size(); i++) { allEntries[i]->deselectFilesOtherSpec(otherSpecFile); } } /** Returns true if "this" spec file is a subset of the "other" spec file. * In other words, all of the files listed in this spec file are in * the other spec file. */ bool SpecFile::isSubsetOfOtherSpecFile(const SpecFile& otherSpecFile, QString& msg) const { msg = ""; for (unsigned int i = 0; i < allEntries.size(); i++) { allEntries[i]->isSubset(otherSpecFile, msg); } return (msg.isEmpty()); } /** * get all entries. */ void SpecFile::getAllEntries(std::vector& allEntriesOut) { allEntriesOut.clear(); for (unsigned int i = 0; i < allEntries.size(); i++) { allEntriesOut.push_back(*(allEntries[i])); } std::sort(allEntriesOut.begin(), allEntriesOut.end()); } /** * Get the number of entries. */ int SpecFile::getNumberOfEntries() const { return this->allEntries.size(); } /** * Get the entry at the specified index. */ SpecFile::Entry* SpecFile::getEntry(int indx) { return this->allEntries[indx]; } /** * Convert to caret6 spec file tag, returns empty string if tag invalid for Caret6. */ QString SpecFile::convertToCaret6SpecFileTag(const QString& tagCaret5) { static bool firstTimeFlag = true; static std::map tags; if (firstTimeFlag) { firstTimeFlag = false; tags["area_color_file"] = "AREA_COLOR"; tags["border_color_file"] = "BORDER_COLOR"; tags["borderproj_file"] = "BORDER_PROJECTION"; tags["coord_file"] = "COORDINATE_GENERIC"; tags["FIDUCIALcoord_file"] = "COORDINATE_ANATOMICAL"; tags["ELLIPSOIDcoord_file"] = "COORDINATE_ELLIPSOID"; tags["FLATcoord_file"] = "COORDINATE_FLAT"; tags["LOBAR_FLATcoord_file"] = "COORDINATE_FLAT"; tags["HULLcoord_file"] = "COORDINATE_HULL"; tags["INFLATEDcoord_file"] = "COORDINATE_INFLATED"; tags["VERY_INFLATEDcoord_file"] = "COORDINATE_VERY_INFLATED"; tags["RAWcoord_file"] = "COORDINATE_RECONSTRUCTION"; tags["COMPRESSED_MEDIAL_WALLcoord_file"] = "COORDINATE_SEMI_SPHERE"; tags["SPHERICALcoord_file"] = "COORDINATE_SPHERE"; tags["fociproj_file"] = "FOCI_PROJECTION"; tags["foci_color_file"] = "FOCI_COLOR"; tags["foci_search_file"] = "FOCI_SEARCH"; tags["gar_file"] = "GAR_GENERIC"; tags["image_file"] = "IMAGE"; tags["label_file"] = "LABEL"; tags["metric_file"] = "METRIC"; tags["paint_file"] = "LABEL"; tags["study_collection_file"] = "STUDY_COLLECTION"; tags["study_metadata_file"] = "STUDY_METADATA"; tags["surface_file"] = "SURFACE_GENERIC"; tags["FIDUCIALsurface_file"] = "SURFACE_ANATOMICAL"; tags["ELLIPSOIDsurface_file"] = "SURFACE_ELLIPSOID"; tags["FLATsurface_file"] = "SURFACE_FLAT"; tags["LOBAR_FLATsurface_file"] = "SURFACE_FLAT"; tags["HULLsurface_file"] = "SURFACE_HULL"; tags["INFLATEDsurface_file"] = "SURFACE_INFLATED"; tags["VERY_INFLATEDsurface_file"] = "SURFACE_VERY_INFLATED"; tags["RAWsurface_file"] = "SURFACE_RECONSTRUCTION"; tags["COMPRESSED_MEDIAL_WALLsurface_file"] = "SURFACE_SEMI_SPHERE"; tags["SPHERICALsurface_file"] = "SURFACE_SPHERE"; tags["surface_shape_file"] = "SHAPE"; tags["topo_file"] = "TOPOLOGY_GENERIC"; tags["CLOSEDtopo_file"] = "TOPOLOGY_CLOSED"; tags["CUTtopo_file"] = "TOPOLOGY_CUT"; tags["LOBAR_CUTtopo_file"] = "TOPOLOGY_CUT"; tags["OPENtopo_file"] = "TOPOLOGY_OPEN"; tags["vector_file"] = "VECTOR"; tags["vocabulary_file"] = "VOCABULARY"; tags["volume_file"] = "VOLUME_GENERIC"; tags["volume_anatomy_file"] = "VOLUME_ANATOMY"; tags["volume_functional_file"] = "VOLUME_FUNCTIONAL"; tags["volume_label_file"] = "VOLUME_LABEL"; tags["volume_paint_file"] = "VOLUME_LABEL"; tags["volume_prob_atlas_file"] = "VOLUME_PROB_ATLAS"; tags["volume_rgb_file"] = "VOLUME_RGB"; tags["volume_segmentation_file"] = "VOLUME_SEGMENTATION"; tags["volume_vector_file"] = "VOLUME_VECTOR"; } QString newTag; for (std::map::iterator iter = tags.begin(); iter != tags.end(); iter++) { if (iter->first == tagCaret5) { newTag = iter->second; break; } } return newTag; } /** * Write the file's memory in caret6 format to the specified name. */ QString SpecFile::writeFileInCaret6Format(const QString& filenameIn, Structure structure,const ColorFile* colorFileIn, const bool useCaret6ExtensionFlag) throw (FileException) { if (allEntries.size() <= 0) { throw FileException("Contains no foci"); } QFile file(filenameIn); if (AbstractFile::getOverwriteExistingFilesAllowed() == false) { if (file.exists()) { throw FileException("file exists and overwrite is prohibited."); } } if (file.open(QFile::WriteOnly) == false) { throw FileException("Unable to open for writing"); } QTextStream stream(&file); XmlGenericWriter xmlWriter(stream); xmlWriter.writeStartDocument(); XmlGenericWriterAttributes attributes; attributes.addAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); attributes.addAttribute("xsi:noNamespaceSchemaLocation", "http://brainvis.wustl.edu/caret6/xml_schemas/SpecFileSchema.xsd"); attributes.addAttribute("CaretFileType", "Specification"); attributes.addAttribute("Version", "6.0"); xmlWriter.writeStartElement("CaretDataFile", attributes); this->writeHeaderXMLWriter(xmlWriter); for (unsigned int i = 0; i < allEntries.size(); i++) { Entry* entry = allEntries[i]; if (entry->getNumberOfFiles() > 0) { XmlGenericWriterAttributes attributes; QString specFileTag = SpecFile::convertToCaret6SpecFileTag(entry->getSpecFileTag()); if (specFileTag.isEmpty() == false) { QString structureName = structure.getTypeAsString(); if (specFileTag.startsWith("COORDINATE") || specFileTag.startsWith("LABEL") || specFileTag.startsWith("METRIC") || specFileTag.startsWith("SHAPE") || specFileTag.startsWith("SURFACE") || specFileTag.startsWith("TOPOLOGY")) { if (structureName == "cerebellum") { structureName = "Cerebellum"; } else if (structureName == "left") { structureName = "CortexLeft"; } else if (structureName == "right") { structureName = "CortexRight"; } } else { structureName = ""; } attributes.addAttribute("DataFileType", specFileTag); attributes.addAttribute("Structure", structureName); for (int j = 0; j < entry->getNumberOfFiles(); j++) { QString outName = entry->getFileName(j); if (outName.isEmpty() == false) { xmlWriter.writeElementCData("DataFile", attributes, outName); } } } else { std::cout << "WARNING, Unsupported specification file tag: " << entry->getSpecFileTag().toAscii().constData() << std::endl; } } } xmlWriter.writeEndElement(); xmlWriter.writeEndDocument(); file.close(); return filenameIn; } //!!*********************************************************************************** //!!*********************************************************************************** //!!*********************************************************************************** //!!*********************************************************************************** /** * constructor. */ SpecFile::Entry::Entry() { } /** * destructor. */ SpecFile::Entry::~Entry() { } /** * initialize. */ void SpecFile::Entry::initialize(const QString& descriptiveNameIn, const QString& specFileTagIn, const FILE_TYPE fileTypeIn, const bool specFilePatternMatchFlagIn) { descriptiveName = descriptiveNameIn; specFileTag = specFileTagIn; fileType = fileTypeIn; specFilePatternMatchFlag = specFilePatternMatchFlagIn; } /** * add if tag matches (returns true if tag matched). */ bool SpecFile::Entry::addFile(const QString& tagReadIn, const QString& filenameIn, const QString& dataFileNameIn, const Structure& structureIn) { bool matches = false; if (specFilePatternMatchFlag) { if (tagReadIn.contains(specFileTag)) { matches = true; } } else if (tagReadIn == specFileTag) { matches = true; } if (matches) { if (specFileTag.isEmpty() == false) { // // Ignore if already present // for (unsigned int i = 0; i < files.size(); i++) { if (files[i].filename == filenameIn) { // // If already present, set its selection status and also // override the data file name since a volume's data file // name may change if zipped or unzipped // files[i].selected = SPEC_TRUE; files[i].dataFileName = dataFileNameIn; return true; } } files.push_back(Files(filenameIn, dataFileNameIn, structureIn)); return true; } } return false; } /** * clear selection status for a file. */ void SpecFile::Entry::clearSelectionStatus(const QString& filenameIn) { for (unsigned int i = 0; i < files.size(); i++) { if (files[i].filename == filenameIn) { files[i].selected = SPEC_FALSE; } } } /** * Set file selected based upon name. * Returns true if the file was selected. */ bool SpecFile::Entry::setSelected(const QString& name, const bool addIfNotFound, const Structure& structureIn) { bool selected = false; if (name.isEmpty()) { return false; } for (unsigned int i = 0; i < files.size(); i++) { if (FileUtilities::basename(files[i].filename) == FileUtilities::basename(name)) { files[i].selected = SPEC_TRUE; selected = true; } } if (selected == false) { if (addIfNotFound) { files.push_back(Files(name, "", structureIn)); selected = true; } } return selected; } /** * Returns true if all of myFiles are in otherFiles. */ bool SpecFile::Entry::isSubset(const SpecFile& otherSpecFile, QString& errorMessage) const { bool isSubset = true; for (unsigned int m = 0; m < otherSpecFile.allEntries.size(); m++) { const Entry& otherEntry = *(otherSpecFile.allEntries[m]); if (otherEntry.specFileTag == specFileTag) { for (unsigned int i = 0; i < files.size(); i++) { bool found = false; for (unsigned int j = 0; j < otherEntry.files.size(); j++) { if (files[i].filename == otherEntry.files[j].filename) { found = true; break; } } if (found == false) { std::ostringstream str; str << " " << descriptiveName.toAscii().constData() << " " << files[i].filename.toAscii().constData() << " is not in spec file but is in scene.\n"; errorMessage.append(str.str().c_str()); isSubset = false; } } return isSubset; } } return isSubset; } /** * add path to files. */ void SpecFile::Entry::prependPath(const QString& path, const bool ignoreFilesWithAbsPaths) { for (unsigned int i = 0; i < files.size(); i++) { QString f(files[i].filename); if (f.isEmpty() == false) { if (ignoreFilesWithAbsPaths) { if (FileUtilities::isAbsolutePath(f)) { continue; } } f = path; f.append("/"); f.append(files[i].filename); files[i].filename = f; } } for (unsigned int i = 0; i < files.size(); i++) { QString f(files[i].dataFileName); if (f.isEmpty() == false) { if (ignoreFilesWithAbsPaths) { if (FileUtilities::isAbsolutePath(f)) { continue; } } f = path; f.append("/"); f.append(files[i].dataFileName); files[i].dataFileName = f; } } } /** * Get all files (excluding data files) to input vector. */ void SpecFile::Entry::getAllFilesNoDataFile(std::vector& allFiles) { allFiles.clear(); for (unsigned int i = 0; i < files.size(); i++) { QString name = files[i].filename; if (name.isEmpty() == false) { if (name != ".") { allFiles.push_back(name); } } } } /** * add files to input vector. */ void SpecFile::Entry::getAllFiles(std::vector& allFiles) { allFiles.clear(); for (unsigned int i = 0; i < files.size(); i++) { allFiles.push_back(files[i].filename); if (files[i].dataFileName.isEmpty() == false) { if (files[i].dataFileName != ".") { allFiles.push_back(files[i].dataFileName); } } } } /** * clear all members except type and tag. */ void SpecFile::Entry::clear(const bool removeFilesFromDiskToo) { if (removeFilesFromDiskToo) { for (unsigned int i = 0; i < files.size(); i++) { QFile::remove(files[i].filename); if (files[i].dataFileName.isEmpty() == false) { QFile::remove(files[i].dataFileName); } } } files.clear(); } /** * sort the files. */ void SpecFile::Entry::sort(const SORT sortMethod) { Files::setSortMethod(sortMethod); std::sort(files.begin(), files.end()); } /** * get number of files selected. */ int SpecFile::Entry::getNumberOfFilesSelected() const { int cnt = 0; for (unsigned int i = 0; i < files.size(); i++) { if (files[i].selected) { cnt++; } } return cnt; } /** * clean up this entry (remove entries for files that do not exist). */ bool SpecFile::Entry::cleanup() { std::vector temp; for (unsigned int i = 0; i < files.size(); i++) { QFileInfo fi1(files[i].filename); if (fi1.exists()) { temp.push_back(files[i]); } } if (temp.size() != files.size()) { files = temp; return true; } return false; } /** * make sure all files exist and are readable (returns true if valid). */ void SpecFile::Entry::validate(QString& errorMessage) const { for (unsigned int i = 0; i < files.size(); i++) { QFileInfo fi1(files[i].filename); if (fi1.exists() == false) { errorMessage.append(FileUtilities::basename(files[i].filename)); errorMessage.append(" does not exist.\n"); } else if (fi1.isReadable() == false) { errorMessage.append(FileUtilities::basename(files[i].filename)); errorMessage.append(" is not readable.\n"); } QFileInfo fi2(files[i].dataFileName); if (fi2.exists() == false) { errorMessage.append(FileUtilities::basename(files[i].dataFileName)); errorMessage.append(" does not exist.\n"); } else if (fi2.isReadable() == false) { errorMessage.append(FileUtilities::basename(files[i].dataFileName)); errorMessage.append(" is not readable.\n"); } } } /** * set all file selections. */ void SpecFile::Entry::setAllSelections(const SPEC_FILE_BOOL selStatus) { for (unsigned int i = 0; i < files.size(); i++) { files[i].selected = selStatus; } } /** * deselect files from other spec file. */ void SpecFile::Entry::deselectFilesOtherSpec(const SpecFile& otherSpecFile) { if (getNumberOfFilesSelected() <= 0) { return; } // // Loop through other spec file's entries // for (unsigned int m = 0; m < otherSpecFile.allEntries.size(); m++) { const Entry& otherEntry = *(otherSpecFile.allEntries[m]); if (otherEntry.getNumberOfFiles() > 0) { if (otherEntry.specFileTag == specFileTag) { for (unsigned int i = 0; i < files.size(); i++) { if (files[i].selected == SPEC_TRUE) { const QString myName = files[i].filename; for (unsigned int j = 0; j < otherEntry.files.size(); j++) { if (otherEntry.files[j].selected == SPEC_TRUE) { if (myName == otherEntry.files[j].filename) { files[i].selected = SPEC_FALSE; break; } } } } } //return; } } } } /** * remove paths from all files. */ void SpecFile::Entry::removePaths() { for (unsigned int i = 0; i < files.size(); i++) { files[i].filename = FileUtilities::basename(files[i].filename); files[i].dataFileName = FileUtilities::basename(files[i].dataFileName); } } /** * save scene. */ void SpecFile::Entry::saveScene(SceneFile::SceneClass& sc, const bool selectedFilesOnlyFlag) { for (unsigned int i = 0; i < files.size(); i++) { const Files f = files[i]; bool addIt = true; if (selectedFilesOnlyFlag) { addIt = (f.selected == SPEC_TRUE); } if (addIt && (f.filename.isEmpty() == false)) { QString n(f.filename); if (f.dataFileName.isEmpty() == false) { n.append(":"); n.append(f.dataFileName); } sc.addSceneInfo(SceneFile::SceneInfo(specFileTag, n)); } } } /** * write the files. */ void SpecFile::Entry::writeFiles(QTextStream& stream, QDomDocument& xmlDoc, QDomElement& rootElement, const FILE_FORMAT fileFormat, const int fileVersionNumber, const bool writeOnlySelectedFiles) throw (FileException) { for (unsigned int i = 0; i < files.size(); i++) { bool writeIt = true; if (writeOnlySelectedFiles) { writeIt = files[i].selected; } // // Files flagged for deletion begin with a splat (asterisk) // if (files[i].filename.isEmpty() == false) { if (files[i].filename[0] == '*') { writeIt = false; } } if (writeIt) { switch (fileFormat) { case FILE_FORMAT_ASCII: stream << specFileTag << " "; if (fileVersionNumber > 0) { stream << files[i].structure.getTypeAsAbbreviatedString() << " "; } stream << files[i].filename << " "; if (files[i].dataFileName.isEmpty() == false) { if (files[i].filename != files[i].dataFileName) { stream << files[i].dataFileName; } } stream << "\n"; break; case FILE_FORMAT_BINARY: throw FileException("", "Writing new spec in binary format not supported"); break; case FILE_FORMAT_XML: { QDomElement tagElem = xmlDoc.createElement(specFileTag); if (fileVersionNumber > 0) { QDomElement structElement = xmlDoc.createElement(getXmlFileTagStructure()); QDomCDATASection structValue = xmlDoc.createCDATASection(files[i].structure.getTypeAsAbbreviatedString()); structElement.appendChild(structValue); tagElem.appendChild(structElement); } QDomElement tag1 = xmlDoc.createElement(getXmlFileTagName1()); QDomCDATASection tagValue1 = xmlDoc.createCDATASection(files[i].filename); tag1.appendChild(tagValue1); tagElem.appendChild(tag1); if (files[i].dataFileName.isEmpty() == false) { if (files[i].filename != files[i].dataFileName) { QDomElement tag2 = xmlDoc.createElement(getXmlFileTagName2()); QDomCDATASection tagValue2 = xmlDoc.createCDATASection(files[i].dataFileName); tag2.appendChild(tagValue2); tagElem.appendChild(tag2); } } rootElement.appendChild(tagElem); } break; case FILE_FORMAT_XML_BASE64: throw FileException("", "Writing new spec in XML Base64 format not supported"); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException("", "Writing new spec in XML GZIP Base64 format not supported"); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException("", "Writing XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException("", "Writing new spec in OTHER format not supported"); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException("", "Comma Separated Value File Format not supported."); break; } } } } //!!*********************************************************************************** //!!*********************************************************************************** //!!*********************************************************************************** //!!*********************************************************************************** /** * constructor. */ SpecFile::Entry::Files::Files(const QString& filenameIn, const QString& dataFileNameIn, const Structure& structureIn, const SPEC_FILE_BOOL selectionStatus) { filename = filenameIn; dataFileName = dataFileNameIn; structure = structureIn; selected = selectionStatus; } /** * destructor. */ SpecFile::Entry::Files::~Files() { } /** * comparison operator. */ bool SpecFile::Entry::Files::operator<(const Files& fi) const { switch (sortMethod) { case SpecFile::SORT_NONE: return false; break; case SpecFile::SORT_DATE: { QFileInfo fi1(filename); const unsigned long time1 = static_cast(fi1.lastModified().toTime_t()); QFileInfo fi2(fi.filename); const unsigned long time2 = static_cast(fi2.lastModified().toTime_t()); return (time1 > time2); } break; case SpecFile::SORT_NAME: return (filename < fi.filename); break; } return false; } /** * sort the files. */ void SpecFile::Entry::Files::setSortMethod(const SpecFile::SORT sortMethodIn) { sortMethod = sortMethodIn; } caret-5.6.4~dfsg.1.orig/caret_files/SegmentationMaskListFile.h0000664000175000017500000000674511572067322024133 0ustar michaelmichael #ifndef __SEGMENTATION_MASK_LIST_FILE_H__ #define __SEGMENTATION_MASK_LIST_FILE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "AbstractFile.h" /// class for reading a segmentation mask list file used in stereotaxic segmentation class SegmentationMaskListFile : public AbstractFile { public: /// class for a segmentation mask class SegmentationMask { public: /// stereotaxic space name QString stereotaxicSpaceName; /// structure name QString structureName; /// mask volume file name QString maskVolumeFileName; /// less than operator bool operator<(const SegmentationMask& sm) const; }; // constructor SegmentationMaskListFile(); // destructor ~SegmentationMaskListFile(); // clear the file void clear(); // returns true if file contains no data bool empty() const; // get the number of segmentation masks int getNumberOfSegmentationMasks() const { return masks.size(); } // get a mask SegmentationMask getSegmentationMask(const int indx) const { return masks[indx]; } // get name of segmentation mask volume file QString getSegmentationMaskFileName(const QString& stereotaxicSpaceName, const QString& structureName) const; // find out if comma separated file conversion supported void getCommaSeparatedFileSupport(bool& readFromCSV, bool& writeToCSV) const; // read the file's data from a comma separated values file (throws exception if not supported) void readDataFromCommaSeparatedValuesTable(const CommaSeparatedValueFile& csv) throw (FileException); // get the available masks QString getAvailableMasks(const QString& indentation) const; protected: // Read the contents of the file (header has already been read) void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& rootElement) throw (FileException); // Write the file's data (header has already been written) void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& xmlDoc, QDomElement& rootElement) throw (FileException); /// the masks std::vector masks; }; #endif // __SEGMENTATION_MASK_LIST_FILE_H__ caret-5.6.4~dfsg.1.orig/caret_files/SegmentationMaskListFile.cxx0000664000175000017500000002105611572067322024476 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "CommaSeparatedValueFile.h" #include "FileUtilities.h" #include "SegmentationMaskListFile.h" #include "SpecFile.h" #include "StringTable.h" /** * constructor. */ SegmentationMaskListFile::SegmentationMaskListFile() : AbstractFile("Segmentation Mask List File", SpecFile::getCommaSeparatedValueFileExtension(), true, // has header FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE, // default format FILE_IO_NONE, // supports ascii FILE_IO_NONE, // supports binary FILE_IO_NONE, // supports XML FILE_IO_NONE, // supports XML Base64 FILE_IO_NONE, // supports XML Base64 GZIP FILE_IO_NONE, // supports other FILE_IO_READ_ONLY) // supports CSV { } /** * destructor. */ SegmentationMaskListFile::~SegmentationMaskListFile() { } /** * clear the file. */ void SegmentationMaskListFile::clear() { clearAbstractFile(); masks.clear(); } /** * returns true if file contains no data. */ bool SegmentationMaskListFile::empty() const { return (getNumberOfSegmentationMasks() == 0); } /** * get name of segmentation mask volume file. */ QString SegmentationMaskListFile::getSegmentationMaskFileName(const QString& stereotaxicSpaceNameIn, const QString& structureNameIn) const { QString stereotaxicSpaceName(stereotaxicSpaceNameIn); if (stereotaxicSpaceName.startsWith("711-2")) { stereotaxicSpaceName = "711-2C"; } stereotaxicSpaceName = stereotaxicSpaceName.toLower(); const QString structureName(structureNameIn.toLower()); const int numMasks = getNumberOfSegmentationMasks(); for (int i = 0; i < numMasks; i++) { const SegmentationMask mask = getSegmentationMask(i); if ((stereotaxicSpaceName == mask.stereotaxicSpaceName.toLower()) && (structureName == mask.structureName.toLower())) { QString name(FileUtilities::dirname(getFileName())); if (name.isEmpty() == false) { name += "/"; } name += mask.maskVolumeFileName; return name; } } return ""; } /** * get the available masks. */ QString SegmentationMaskListFile::getAvailableMasks(const QString& indentation) const { QString msg; const int numSegentationMasks = getNumberOfSegmentationMasks(); if (numSegentationMasks <= 0) { msg += (indentation +"No segmentation masks were found. They should be in the file \n" + indentation + " " + getFileName()); return msg; } int longestSpaceName = 0; for (int i = 0; i < numSegentationMasks; i++) { longestSpaceName = std::max(getSegmentationMask(i).stereotaxicSpaceName.length(), longestSpaceName); } longestSpaceName += 2; for (int i = 0; i < numSegentationMasks; i++) { const SegmentationMask mask = getSegmentationMask(i); msg += (indentation + mask.stereotaxicSpaceName.leftJustified(longestSpaceName) + " " + mask.structureName + "\n"); } return msg; } /** * find out if comma separated file conversion supported. */ void SegmentationMaskListFile::getCommaSeparatedFileSupport(bool& readFromCSV, bool& writeToCSV) const { readFromCSV = true; writeToCSV = false; } /** * read the file's data from a comma separated values file (throws exception if not supported). */ void SegmentationMaskListFile::readDataFromCommaSeparatedValuesTable(const CommaSeparatedValueFile& csv) throw (FileException) { masks.clear(); const QString maskTableName("MaskVolumes"); const StringTable* maskVolumesTable = csv.getDataSectionByName(maskTableName); if (maskVolumesTable == NULL) { throw FileException("Unable to find table named " + maskTableName + " in " + getFileName()); } // // Find columns numbers of data // const int spaceCol = maskVolumesTable->getColumnIndexFromName("Space"); const int structureCol = maskVolumesTable->getColumnIndexFromName("Structure"); const int volumeCol = maskVolumesTable->getColumnIndexFromName("MaskVolume"); if ((spaceCol < 0) || (structureCol < 0) || (volumeCol < 0)) { throw FileException("Missing required columns in " + getFileName()); } // // read the mask volume names // const int numRows = maskVolumesTable->getNumberOfRows(); for (int i = 0; i < numRows; i++) { SegmentationMask mask; mask.stereotaxicSpaceName = maskVolumesTable->getElement(i, spaceCol); mask.structureName = maskVolumesTable->getElement(i, structureCol); mask.maskVolumeFileName = maskVolumesTable->getElement(i, volumeCol); masks.push_back(mask); } } /** * Read the contents of the file (header has already been read). */ void SegmentationMaskListFile::readFileData(QFile& file, QTextStream& stream, QDataStream& /*binStream*/, QDomElement& /*rootElement*/) throw (FileException) { // // Should reading data be skipped ? // if (getReadMetaDataOnlyFlag()) { return; } switch (getFileReadType()) { case FILE_FORMAT_ASCII: throw FileException(filename, "Reading in Ascii format not supported."); break; case FILE_FORMAT_BINARY: throw FileException(filename, "Reading in Binary format not supported."); break; case FILE_FORMAT_XML: throw FileException(filename, "Reading XML not supported."); break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "Reading XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "Reading XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Reading XML-External Binary Encoding file format not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Reading in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: { CommaSeparatedValueFile csvf; csvf.readFromTextStream(file, stream); readDataFromCommaSeparatedValuesTable(csvf); } break; } std::sort(masks.begin(), masks.end()); } /** * Write the file's data (header has already been written). */ void SegmentationMaskListFile::writeFileData(QTextStream& /*stream*/, QDataStream& /*binStream*/, QDomDocument& /*xmlDoc*/, QDomElement& /*rootElement*/) throw (FileException) { throw FileException("Writing of SegmentationMaskListFile not supported."); } //================================================================================================= /** * less than operator. */ bool SegmentationMaskListFile::SegmentationMask::operator<(const SegmentationMask& sm) const { if (stereotaxicSpaceName == sm.stereotaxicSpaceName) { if (structureName == sm.structureName) { return (maskVolumeFileName < sm.maskVolumeFileName); } return (structureName < sm.structureName); } return (stereotaxicSpaceName < sm.stereotaxicSpaceName); } caret-5.6.4~dfsg.1.orig/caret_files/SectionFile.h0000664000175000017500000000760511572067322021426 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_SECTIONS_FILE__ #define __VE_SECTIONS_FILE__ #include "NodeAttributeFile.h" /// This file contains section information for a surface. class SectionFile : public NodeAttributeFile { public: /// constructor SectionFile(); /// destructor ~SectionFile(); /// append a node attribute file to this one void append(NodeAttributeFile& naf) throw (FileException); /// append a node attribute file to this one but selectively load/overwrite columns /// columnDestination is where naf's columns should be (-1=new, -2=do not load) void append(NodeAttributeFile& naf, std::vector columnDestination, const FILE_COMMENT_MODE fcm) throw (FileException); /// add columns to this sections file void addColumns(const int numberOfNewColumns); /// Add nodes to the file void addNodes(const int numberOfNodesToAdd); /// clears sections memory void clear(); /// deform "this" node attribute file placing the output in "deformedFile". void deformFile(const DeformationMapFile& dmf, NodeAttributeFile& deformedFile, const DEFORM_TYPE dt) const throw (FileException); /// reset a column of data void resetColumn(const int columnNumber); /// remove a column of data void removeColumn(const int columnNumber); /// get the minimum section int getMinimumSection(const int col) const; /// get the maximum section int getMaximumSection(const int col) const; /// set number of nodes void setNumberOfNodesAndColumns(const int numNodes, const int numCols); /// get section for a node int getSection(const int nodeNumber, const int columnNumber) const; /// set section for a node void setSection(const int nodeNumber, const int columnNumber, const int sectionNum); /// should be called after a new column is created and the sections are set void postColumnCreation(const int columnNumber); private: /// sections storage std::vector sections; /// minimum section for each column std::vector minimumSection; /// maximum section for each column std::vector maximumSection; /// read file version 0 data void readFileDataVersion0(QTextStream& stream, QDataStream& binStream) throw (FileException); /// read an sections file data void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException); /// write an setctions file data void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException); public: }; #endif // __VE_SECTIONS_FILE__ caret-5.6.4~dfsg.1.orig/caret_files/SectionFile.cxx0000664000175000017500000003446611572067322022006 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #define _SECTION_FILE_MAIN_ #include "SectionFile.h" #undef _SECTION_FILE_MAIN_ #include "SpecFile.h" #include "StringUtilities.h" /** * Constructor. */ SectionFile::SectionFile() : NodeAttributeFile("Section File", SpecFile::getSectionFileExtension(), AbstractFile::FILE_FORMAT_ASCII, FILE_IO_READ_AND_WRITE, FILE_IO_READ_AND_WRITE, FILE_IO_NONE, FILE_IO_NONE) { clear(); } /** * Destructor. */ SectionFile::~SectionFile() { clear(); } /** * append a node attribute file to this one but selectively load/overwrite columns * columnDestination is where naf's columns should be (-1=new, -2=do not load). */ void SectionFile::append(NodeAttributeFile& /*naf*/, std::vector /*columnDestination*/, const FILE_COMMENT_MODE /*fcm*/) throw (FileException) { throw FileException("Not implemented yet."); } /** * append an section file to this one */ void SectionFile::append(NodeAttributeFile& naf) throw (FileException) { SectionFile& sf = dynamic_cast(naf); if (getNumberOfNodes() != sf.getNumberOfNodes()) { throw FileException("Cannot append Section, number of columns does not match."); } const int oldNumCols = getNumberOfColumns(); const int appendNumCols = sf.getNumberOfColumns(); // // Add the additional columns to the file // addColumns(appendNumCols); // // Transfer section data // for (int i = 0; i < numberOfNodes; i++) { for (int j = 0; j < appendNumCols; j++) { setSection(i, oldNumCols + j, sf.getSection(i, j)); } } // // Transfer column information // Note: minimumSection and maximum section are set by "setSection()" // for (int j = 0; j < appendNumCols; j++) { setColumnName(oldNumCols + j, sf.getColumnName(j)); setColumnComment(oldNumCols + j, sf.getColumnComment(j)); } // // transfer the file's comment // appendFileComment(sf); } /** * add columns to this section file */ void SectionFile::addColumns(const int numberOfNewColumns) { const int oldNumberOfColumns = numberOfColumns; const int totalColumns = numberOfColumns + numberOfNewColumns; // // Save existing section data // const std::vector sect = sections; // // Setup file for new number of columns (will expand space for column naming) // setNumberOfNodesAndColumns(numberOfNodes, totalColumns); // // transfer existing section data // for (int i = 0; i < numberOfNodes; i++) { for (int j = 0; j < numberOfColumns; j++) { if (j < oldNumberOfColumns) { const int oldIndex = (oldNumberOfColumns * i) + j; setSection(i, j, sect[oldIndex]); } else { setSection(i, j, 0); } } } setModified(); } /** * Add node to the file. */ void SectionFile::addNodes(const int numberOfNodesToAdd) { setNumberOfNodesAndColumns(numberOfNodes + numberOfNodesToAdd, numberOfColumns); } /** * Clear the file. */ void SectionFile::clear() { clearNodeAttributeFile(); setNumberOfNodesAndColumns(0, 0); } /** * returns true if an error occurs. */ void SectionFile::deformFile(const DeformationMapFile& /*dmf*/, NodeAttributeFile& /*deformedFile*/, const DEFORM_TYPE /*dt*/) const throw (FileException) { throw FileException("Deformation of Section files not supported."); } /** * reset a column of data. */ void SectionFile::resetColumn(const int columnNumber) { setColumnName(columnNumber, ""); setColumnComment(columnNumber, ""); for (int i = 0; i < numberOfNodes; i++) { setSection(i, columnNumber, 0); } setModified(); } /** * remove a column of data. */ void SectionFile::removeColumn(const int columnNumber) { if (numberOfColumns <= 1) { clear(); return; } int ctr = 0; for (int i = 0; i < numberOfColumns; i++) { if (i != columnNumber) { setColumnName(ctr, getColumnName(i)); setColumnComment(ctr, getColumnComment(i)); ctr++; } } SectionFile sf; sf.setNumberOfNodesAndColumns(numberOfNodes, numberOfColumns - 1); for (int i = 0; i < numberOfNodes; i++) { int ctr = 0; for (int j = 0; j < numberOfColumns; j++) { if (j != columnNumber) { setSection(i, ctr, getSection(i, j)); ctr++; } } } setNumberOfNodesAndColumns(numberOfNodes, numberOfColumns - 1); sections = sf.sections; setModified(); } /** * Set number of nodes in the file. */ void SectionFile::setNumberOfNodesAndColumns(const int numNodes, const int numCols) { //const int oldNumberOfColumns = numberOfColumns; numberOfNodes = numNodes; numberOfColumns = numCols; const int num = numberOfNodes * numberOfColumns * numberOfItemsPerColumn; if (num <= 0) { sections.clear(); minimumSection.clear(); maximumSection.clear(); } else { sections.resize(num, 0); minimumSection.resize(numberOfColumns, std::numeric_limits::max()); maximumSection.resize(numberOfColumns, std::numeric_limits::min()); } numberOfNodesColumnsChanged(); } /** * get the minimum section */ int SectionFile::getMinimumSection(const int col) const { return minimumSection[col]; } /** * get the maximum section */ int SectionFile::getMaximumSection(const int col) const { return maximumSection[col]; } /** * Get the section for a node. */ int SectionFile::getSection(const int nodeNumber, const int columnNumber) const { const int index = getOffset(nodeNumber, columnNumber); return sections[index]; } /** * Set the section for a node. */ void SectionFile::setSection(const int nodeNumber, const int columnNumber, const int sectionNum) { const int index = getOffset(nodeNumber, columnNumber); sections[index] = sectionNum; maximumSection[columnNumber] = std::max(maximumSection[columnNumber], sectionNum); minimumSection[columnNumber] = std::min(minimumSection[columnNumber], sectionNum); setModified(); } /** * Set minimum and maximum sections and selected */ void SectionFile::postColumnCreation(const int columnNumber) { minimumSection[columnNumber] = std::numeric_limits::max(); maximumSection[columnNumber] = std::numeric_limits::min(); for (int i = 0; i < numberOfNodes; i++) { minimumSection[columnNumber] = std::min(minimumSection[columnNumber], getSection(i, columnNumber)); maximumSection[columnNumber] = std::max(maximumSection[columnNumber], getSection(i, columnNumber)); } } /** * Read the section file's version 1 data. */ void SectionFile::readFileDataVersion0(QTextStream& stream, QDataStream& binStream) throw (FileException) { int numNodes = -1; int numCols = -1; bool readingTags = true; while(readingTags) { QString tag, tagValue; readTagLine(stream, tag, tagValue); if (tag == tagBeginData) { readingTags = false; } else if (tag == tagNumberOfNodes) { numNodes = tagValue.toInt(); if ((numNodes > 0) && (numCols > 0)) { setNumberOfNodesAndColumns(numNodes, numCols); } } else if (tag == tagNumberOfColumns) { numCols = tagValue.toInt(); if ((numNodes > 0) && (numCols > 0)) { setNumberOfNodesAndColumns(numNodes, numCols); } } else if (tag == tagColumnName) { QString name; const int index = splitTagIntoColumnAndValue(tagValue, name); columnNames[index] = name; } else if (tag == tagColumnComment) { QString name; const int index = splitTagIntoColumnAndValue(tagValue, name); columnComments[index] = StringUtilities::setupCommentForDisplay(name); } else if (tag == tagFileTitle) { fileTitle = tagValue; } else { std::cerr << "WARNING: Unknown Section File Tag: " << tag.toAscii().constData() << std::endl; } } // // Should reading data be skipped ? // if (getReadMetaDataOnlyFlag()) { return; } if (numNodes <= 0) { throw FileException(filename, "No data in Section file"); } switch (getFileReadType()) { case FILE_FORMAT_ASCII: { std::vector tokens; QString line; for (int i = 0; i < numberOfNodes; i++) { readLineIntoTokens(stream, line, tokens); if (static_cast(tokens.size()) == (numberOfColumns + 1)) { for (int j = 0; j < numberOfColumns; j++) { const int sectionNum = tokens[j + 1].toInt(); setSection(i, j, sectionNum); } } else { QString msg("Reading Section file line: "); msg.append(line); throw FileException(filename, msg); } } } break; case FILE_FORMAT_BINARY: // // Needed for QT 4.2.2 // binStream.device()->seek(stream.pos()); int section; for (int i = 0; i < numNodes; i++) { for (int j = 0; j < numCols; j++) { binStream >> section; setSection(i, j, section); } } break; case FILE_FORMAT_XML: throw FileException(filename, "Writing in XML format not supported."); break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Writing XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Writing in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Comma Separated Value File Format not supported."); break; } } /** * Read the section file's data. */ void SectionFile::readFileData(QFile& /*file*/, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException) { QString line; QString versionStr, versionNumberStr; readTagLine(stream, versionStr, versionNumberStr); int fileVersion = 0; if (versionStr == tagFileVersion) { fileVersion = versionNumberStr.toInt(); } switch(fileVersion) { case 0: readFileDataVersion0(stream, binStream); break; default: throw FileException(filename, "Invalid Section file version"); break; } for (int i = 0; i < numberOfColumns; i++) { postColumnCreation(i); } } /** * Write the section file's data. */ void SectionFile::writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException) { const int numNodes = getNumberOfNodes(); const int numCols = getNumberOfColumns(); stream << tagFileVersion << " 0" << "\n"; stream << tagNumberOfNodes << " " << numNodes << "\n"; stream << tagNumberOfColumns << " " << numCols << "\n"; stream << tagFileTitle << " " << fileTitle << "\n"; for (int j = 0; j < numberOfColumns; j++) { stream << tagColumnName << " " << j << " " << columnNames[j] << "\n"; stream << tagColumnComment << " " << j << " " << StringUtilities::setupCommentForStorage(columnComments[j]) << "\n"; } stream << tagBeginData << "\n"; switch (getFileWriteType()) { case FILE_FORMAT_ASCII: for (int i = 0; i < numNodes; i++) { stream << i; for (int j = 0; j < numCols; j++) { stream << " " << getSection(i, j); } stream << "\n"; } break; case FILE_FORMAT_BINARY: #ifdef QT4_FILE_POS_BUG setBinaryFilePosQT4Bug(); #else // QT4_FILE_POS_BUG // // still a bug in QT 4.2.2 // setBinaryFilePosQT4Bug(); #endif // QT4_FILE_POS_BUG for (int i = 0; i < numNodes; i++) { for (int j = 0; j < numCols; j++) { binStream << getSection(i, j); } } break; case FILE_FORMAT_XML: throw FileException(filename, "Writing in XML format not supported."); break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Writing XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Writing in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Comma Separated Value File Format not supported."); break; } } caret-5.6.4~dfsg.1.orig/caret_files/SceneFile.h0000664000175000017500000003107511572067322021055 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __SCENE_FILE_H__ #define __SCENE_FILE_H__ class QStringList; #include "AbstractFile.h" #include "FileException.h" /// File for storing, reading, and writing a Caret coordinate file class SceneFile : public AbstractFile { public: /// scene information class SceneInfo { public: /// Constructor for Node Attributes with Multiple Overlays explicit SceneInfo(const QString& nameIn, const QString& modelNameIn, const int overlayNumberIn, const QString& valueIn); /// Constructor explicit SceneInfo(const QString& nameIn, const QString& modelNameIn, const QString& valueIn); /// Constructor explicit SceneInfo(const QString& nameIn, const QString& modelNameIn, const float valueIn); /// Constructor explicit SceneInfo(const QString& nameIn, const QString& modelNameIn, const int valueIn); /// Constructor explicit SceneInfo(const QString& nameIn, const QString& modelNameIn, const bool valueIn); /// Constructor explicit SceneInfo(const QString& nameIn, const float valueIn); /// Constructor explicit SceneInfo(const QString& nameIn, const int valueIn); /// Constructor explicit SceneInfo(const QString& nameIn, const bool valueIn); /// Constructor explicit SceneInfo(const QString& nameIn, const QString& valueIn); /// Constructor explicit SceneInfo(const QString& nameIn, const QStringList& valueIn); /// Constructor explicit SceneInfo(const QString& nameIn, const char* valueIn); /// Destructor ~SceneInfo(); /// get the name QString getName() const { return name; } /// get the model name QString getModelName() const { return modelName; } /// get the value as a string void getValue(QString& val) const { val = getValueAsString(); } /// get the value as a float void getValue(float& val) const { val = getValueAsFloat(); } /// get the value as an int void getValue(int& val) const { val = getValueAsInt(); } /// get the value as a bool void getValue(bool& val) const { val = getValueAsBool(); } /// get the value as a string QString getValueAsString() const; /// get the value as a float float getValueAsFloat() const; /// get the value as an int int getValueAsInt() const; /// get the value as a bool bool getValueAsBool() const; /// get default surfaces special name static QString getDefaultSurfacesName() { return "___DEFAULT___"; } /// get the overlay number (-1 if invalid) int getOverlayNumber() const { return overlayNumber; } /// set the overlay number void setOverlayNumber(const int on) { overlayNumber = on; } /// set the name void setName(const QString& n) { name = n; } /// set the model name void setModelName(const QString& n) { modelName = n; } /// set the value void setValue(const QString& v) { value = v; } protected: /// initialize the scene info void initialize(const QString& nameIn, const QString& modelNameIn, const int overlayNumberIn, const QString& valueIn); /// the name QString name; /// the model name QString modelName; /// the value QString value; /// the overlay number int overlayNumber; }; /// scene class class SceneClass { public: /// Constructor SceneClass(const QString& nameIn); /// Destructor ~SceneClass(); /// get the name of the scene class QString getName() const { return name; } /// set the name void setName(const QString& n) { name = n; } /// add a scene info void addSceneInfo(const SceneInfo& si); /// clear the scene class void clear(); /// get the number of scene info's int getNumberOfSceneInfo() const { return info.size(); } /// get a scene info (const method) const SceneInfo* getSceneInfo(const int indx) const; /// get a scene info SceneInfo* getSceneInfo(const int indx); protected: /// name of scene class QString name; /// the scene info std::vector info; }; /// scene class Scene { public: /// Constructor Scene(const QString& nameIn); /// Destructor ~Scene(); /// get the name of the scene QString getName() const { return name; } /// set the name of a scene void setName(const QString& s) { name = s; } /// add a scene data for a class void addSceneClass(const SceneClass& sc); /// clear the scene info void clear(); /// get the number of scene classes int getNumberOfSceneClasses() const { return classes.size(); } /// get a scene class (const method) const SceneClass* getSceneClass(const int indx) const; /// get a scene class SceneClass* getSceneClass(const int indx); /// get a class with the specified name SceneClass* getSceneClassWithName(const QString& name); /// get a class with the specified name (const method) const SceneClass* getSceneClassWithName(const QString& name) const; /// remove a class with the specified name void removeClassWithName(const QString& name); protected: /// name of scene QString name; /// the scene classes std::vector classes; }; /// constructor SceneFile(); /// copy constructor SceneFile(const SceneFile& cf); /// destructor ~SceneFile(); /// add a scene void addScene(const Scene& ss); /// insert a scene void insertScene(const int insertAfterIndex, const Scene& ss); /// replace a scene void replaceScene(const int sceneIndex, const Scene& si) throw (FileException); /// delete a scene void deleteScene(const int indx); /// get the number of scenes int getNumberOfScenes() const { return scenes.size(); } /// get a scene Scene* getScene(const int indx); /// get a scene const Scene* getScene(const int indx) const; /// get a scene from the scene name (NULL if not found) Scene* getSceneFromName(const QString& sceneName); /// get a scene from the scene name (NULL if not found) const Scene* getSceneFromName(const QString& sceneName) const; /// get a scene index from the scene name (-1 if not found) int getSceneIndexFromName(const QString& sceneName) const; /// append a scene file to this one void append(SceneFile& sf) throw (FileException); /// clear the coordinate file void clear(); /// returns true if the file is isEmpty (contains no data) bool empty() const { return scenes.empty(); } /// remove paths from all of the scene spec file's data file names void removePathsFromAllSpecFileDataFileNames(); /// add paths to all of the scene spec file's data file names void addPathToAllSpecFileDataFileNames(const QString& path); /// transfer a scene class from one scene to other scene(s) void transferSceneClass(const int fromSceneNumber, const std::vector& toSceneNumbers, const QString& nameOfClassToTransfer) throw (FileException); /// remove paths from all of the scene' spec file data names for a file on disk static void removePathsFromAllSpecFileDataFileNames(const QString& sceneFileName) throw (FileException); /// add paths to all of the scene spec file's data file names for a file on disk static void addPathToAllSpecFileDataFileNames(const QString& sceneFileName, const QString& path) throw (FileException); protected: /// read coordinate file data void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException); /// write coordinate file data void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException); // // NOTE: If any variables are added be sure to update the copy constructor. // /// the scenes std::vector scenes; /// scene tag name static const QString sceneTagName; /// scene name tag name static const QString sceneNameTagName; /// scene class tag name static const QString sceneClassTagName; /// scene name attribute name static const QString sceneNameAttributeName; /// name for overlay attribute static const QString overlayAttributeName; /// name for model attribute static const QString modelAttributeName; /// name for value attribute name static const QString valueAttributeName; }; #endif // SCENE_FILE #ifdef __SCENE_FILE_MAIN__ const QString SceneFile::sceneTagName = "Scene"; const QString SceneFile::sceneNameTagName = "SceneName"; const QString SceneFile::sceneClassTagName = "Class"; const QString SceneFile::sceneNameAttributeName = "name"; const QString SceneFile::modelAttributeName = "model"; const QString SceneFile::overlayAttributeName = "overlay"; const QString SceneFile::valueAttributeName = "value"; #endif // __SCENE_FILE_MAIN__ caret-5.6.4~dfsg.1.orig/caret_files/SceneFile.cxx0000664000175000017500000007114311572067322021430 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #ifdef Q_OS_WIN32 #define NOMINMAX #endif #include #include #include #include #include #include "DebugControl.h" #include "FileUtilities.h" #define __SCENE_FILE_MAIN__ #include "SceneFile.h" #undef __SCENE_FILE_MAIN__ #include "SpecFile.h" #include "StringUtilities.h" /** * The constructor. */ SceneFile::SceneFile() : AbstractFile("Scene File", SpecFile::getSceneFileExtension(), true, FILE_FORMAT_XML, FILE_IO_NONE, FILE_IO_NONE, FILE_IO_READ_AND_WRITE, FILE_IO_NONE) { clear(); } /** * The copy constructor. */ SceneFile::SceneFile(const SceneFile& cf) : AbstractFile(cf) { } /** * The destructor. */ SceneFile::~SceneFile() { clear(); } /** * append a scene file to this one. */ void SceneFile::append(SceneFile& sf) throw (FileException) { scenes.insert(scenes.end(), sf.scenes.begin(), sf.scenes.end()); } /** * Clear the coordinate file. */ void SceneFile::clear() { clearAbstractFile(); scenes.clear(); } /** * add a scene. */ void SceneFile::addScene(const Scene& s) { scenes.push_back(s); setModified(); } /** * insert a scene. */ void SceneFile::insertScene(const int insertAfterIndex, const Scene& ss) { if ((insertAfterIndex >= 0) && (insertAfterIndex < (getNumberOfScenes() - 1))) { scenes.insert(scenes.begin() + insertAfterIndex + 1, ss); } else { addScene(ss); } } /** * replace a scene. */ void SceneFile::replaceScene(const int sceneIndex, const Scene& s) throw (FileException) { if ((sceneIndex >= 0) && (sceneIndex < getNumberOfScenes())) { scenes[sceneIndex] = s; setModified(); } } /** * delete a scene. */ void SceneFile::deleteScene(const int indx) { if (indx < getNumberOfScenes()) { scenes.erase(scenes.begin() + indx); } setModified(); } /** * get a scene set. */ SceneFile::Scene* SceneFile::getScene(const int indx) { if (indx < getNumberOfScenes()) { return &scenes[indx]; } return NULL; } /** * get a scene set. */ const SceneFile::Scene* SceneFile::getScene(const int indx) const { if (indx < getNumberOfScenes()) { return &scenes[indx]; } return NULL; } /** * get a scene index from the scene name (-1 if not found). */ int SceneFile::getSceneIndexFromName(const QString& sceneName) const { for (int i = 0; i < getNumberOfScenes(); i++) { if (scenes[i].getName() == sceneName) { return i; } } return -1; } /** * get a scene from the scene name (NULL if not found). */ SceneFile::Scene* SceneFile::getSceneFromName(const QString& sceneName) { for (int i = 0; i < getNumberOfScenes(); i++) { if (scenes[i].getName() == sceneName) { return &scenes[i]; } } return NULL; } /** * get a scene from the scene name (NULL if not found). */ const SceneFile::Scene* SceneFile::getSceneFromName(const QString& sceneName) const { for (int i = 0; i < getNumberOfScenes(); i++) { if (scenes[i].getName() == sceneName) { return &scenes[i]; } } return NULL; } /** * Read the scene file data. May throw FileException. */ void SceneFile::readFileData(QFile& /*file*/, QTextStream& /*stream*/, QDataStream& /*binStream*/, QDomElement& rootElement) throw (FileException) { // // Should reading data be skipped ? // if (getReadMetaDataOnlyFlag()) { return; } switch (getFileReadType()) { case FILE_FORMAT_ASCII: throw FileException(filename, "Reading in Ascii format not supported."); break; case FILE_FORMAT_BINARY: throw FileException(filename, "Reading in Binary format not supported."); break; case FILE_FORMAT_XML: { QDomNode node = rootElement.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (DebugControl::getDebugOn()) { std::cout << "Tag Name: " << elem.tagName().toAscii().constData() << std::endl; } // // Is this a "Scene" element // if (elem.tagName() == sceneTagName) { const QString sceneName = elem.attribute(sceneNameAttributeName, ""); // // Create a new scene // Scene scene(sceneName); // // First child // QDomNode classNode = elem.firstChild(); // // Loop the the classes // while (classNode.isNull() == false) { QDomElement classElem = classNode.toElement(); // // Is this the scene name // if (classElem.tagName() == sceneNameTagName) { QString s = getXmlElementFirstChildAsString(classElem); if (s.isEmpty() == false) { scene.setName(s); } } // // Is this a "Scene" element // else if (classElem.tagName() == sceneClassTagName) { const QString sceneClassName = classElem.attribute(sceneNameAttributeName, ""); // // Make sure the scene has a name // if (sceneClassName.isEmpty() == false) { SceneClass sceneClass(sceneClassName); // // Look at the scene's children // QDomNode sceneClassNode = classElem.firstChild(); while (sceneClassNode.isNull() == false) { QDomElement sceneElem = sceneClassNode.toElement(); const QString sceneDataType = sceneElem.tagName(); if (DebugControl::getDebugOn()) { std::cout << "Scene Data Type: " << sceneDataType.toAscii().constData() << std::endl; } // // Get the associated model and the value // QString modelName; int overlayNumber = -1; QString valueName; QDomNodeList nodeList = sceneClassNode.childNodes(); for (int j = 0; j < static_cast(nodeList.count()); j++) { QDomNode childNode = nodeList.item(j); const QDomElement childElem = childNode.toElement(); const QString val = getXmlElementFirstChildAsString(childElem); if (DebugControl::getDebugOn()) { std::cout << "Child: " << childElem.tagName().toAscii().constData() << " " << val.toAscii().constData() << std::endl; } if (childElem.tagName() == modelAttributeName) { modelName = val; } else if (childElem.tagName() == overlayAttributeName) { bool ok = false; overlayNumber = val.toInt(&ok); if (ok == false) { overlayNumber = -1; } } else if (childElem.tagName() == valueAttributeName) { valueName = val; } } // // Make sure scene data type and value are valid // if ((sceneDataType.isEmpty() == false) && (valueName.isEmpty() == false)) { // // Create the scene info // SceneInfo si(sceneDataType, modelName, overlayNumber, valueName); sceneClass.addSceneInfo(si); } // // Next sibling // sceneClassNode = sceneClassNode.nextSibling(); } // while (sceneClassNode.isNull() .... // // Add the scene set // if (sceneClass.getNumberOfSceneInfo() > 0) { scene.addSceneClass(sceneClass); } } else { std::cout << "ERROR: Scene name is isEmpty reading scene file." << std::endl; } // else } // if (classElem.tagName()... // // Get next scene class // classNode = classNode.nextSibling(); } // while (classNode.isNull()... // // // if (scene.getNumberOfSceneClasses() > 0) { addScene(scene); } } // if (elem.tagName()... } // if (elem.isNull()... node = node.nextSibling(); } /// while (node.isNull } break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Reading XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Reading in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Comma Separated Value File Format not supported."); break; } setModified(); } /** * Read the scene file data. May throw FileException. */ void SceneFile::writeFileData(QTextStream& /*stream*/, QDataStream& /*binStream*/, QDomDocument& xmlDoc, QDomElement& rootElement) throw (FileException) { switch (getFileWriteType()) { case FILE_FORMAT_ASCII: throw FileException(filename, "Writing in Ascii format not supported."); break; case FILE_FORMAT_BINARY: throw FileException(filename, "Writing in Binary format not supported."); break; case FILE_FORMAT_XML: { const int numScenes = getNumberOfScenes(); for (int j = 0; j < numScenes; j++) { const Scene* scene = getScene(j); QString sceneName = scene->getName(); if (sceneName.isEmpty()) { sceneName = "NoName"; } QString attSceneName = sceneName; const int len = static_cast(attSceneName.length()); for (int i = 0; i < len; i++) { bool validCharFlag = false; QCharRef c = attSceneName[i]; if (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z'))) { validCharFlag = true; } if (i > 0) { if (((c >= '0') && (c <= '9')) || (c == '-') || (c == '_') || (c == ' ')) { validCharFlag = true; } } if (validCharFlag == false) { if (i == 0) { attSceneName[i] = 'A'; } else { attSceneName[i] = '_'; } } } QDomElement sceneElement = xmlDoc.createElement(sceneTagName); sceneElement.setAttribute(sceneNameAttributeName, attSceneName); // // This scene name overrides the attribute contained in the scene tag // QDomElement sceneNameElement = xmlDoc.createElement(sceneNameTagName); QDomCDATASection sceneNameValue = xmlDoc.createCDATASection(sceneName); sceneNameElement.appendChild(sceneNameValue); sceneElement.appendChild(sceneNameElement); const int numClasses = scene->getNumberOfSceneClasses(); for (int i = 0; i < numClasses; i++) { const SceneClass* sc = scene->getSceneClass(i); const QString sceneClassName = sc->getName(); if (sceneClassName.isEmpty() == false) { QDomElement sceneClassElement = xmlDoc.createElement(sceneClassTagName); sceneClassElement.setAttribute(sceneNameAttributeName, sceneClassName); const int numSceneInfo = sc->getNumberOfSceneInfo(); for (int j = 0; j < numSceneInfo; j++) { const SceneInfo* si = sc->getSceneInfo(j); const QString sceneName = si->getName(); if (sceneName.isEmpty() == false) { QDomElement infoElement = xmlDoc.createElement(sceneName); QDomElement modelElem = xmlDoc.createElement(modelAttributeName); QDomCDATASection modelValue = xmlDoc.createCDATASection(si->getModelName()); modelElem.appendChild(modelValue); infoElement.appendChild(modelElem); QDomElement overlayElem = xmlDoc.createElement(overlayAttributeName); QDomCDATASection overlayValue = xmlDoc.createCDATASection(QString::number(si->getOverlayNumber())); overlayElem.appendChild(overlayValue); infoElement.appendChild(overlayElem); QDomElement valueElem = xmlDoc.createElement(valueAttributeName); QDomCDATASection valValue = xmlDoc.createCDATASection(si->getValueAsString()); valueElem.appendChild(valValue); infoElement.appendChild(valueElem); sceneClassElement.appendChild(infoElement); } else { std::cout << "ERROR: scene info has no name. It has not been written." << std::endl; } } sceneElement.appendChild(sceneClassElement); } else { std::cout << "ERROR: scene class has no name. It has not been written." << std::endl; } } rootElement.appendChild(sceneElement); } } break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Writing XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Writing in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Comma Separated Value File Format not supported."); break; } } /** * remove paths from all of the scene spec file's data file names. */ void SceneFile::removePathsFromAllSpecFileDataFileNames() { const int numScenes = getNumberOfScenes(); for (int i = 0; i < numScenes; i++) { Scene* s = getScene(i); if (s->getSceneClassWithName("SpecFile") != NULL) { // // Get the spec file // SpecFile sf; QString msg; sf.showScene(*s, msg); // // Remove spec file from scene // s->removeClassWithName("SpecFile"); // // Remove paths from spec file // sf.removePathsFromAllFiles(); // // Add spec file back to scene // sf.saveScene(*s, false); } } } /** * transfer a scene class from one scene to other scene(s). */ void SceneFile::transferSceneClass(const int fromSceneNumber, const std::vector& toSceneNumbers, const QString& nameOfClassToTransfer) throw (FileException) { // // Get the from scene // const int numScenes = getNumberOfScenes(); if ((fromSceneNumber < 0) || (fromSceneNumber >= numScenes)) { throw FileException("\"From\" scene number is invalid."); } const Scene* fromScene = getScene(fromSceneNumber); if (fromScene == NULL) { throw FileException("\"From\" scene not found."); } // // Find the class to transer // const SceneClass* fromBMI = fromScene->getSceneClassWithName(nameOfClassToTransfer); if (fromBMI == NULL) { throw FileException("Scene class " + nameOfClassToTransfer + " not found in \"from\" scene."); } // // Transfer the class // const int numScenesToChange = static_cast(toSceneNumbers.size()); for (int i = 0; i < numScenesToChange; i++) { const int sceneNumber = toSceneNumbers[i]; if ((sceneNumber >= 0) && (sceneNumber < numScenes)) { Scene* toScene = getScene(sceneNumber); if (toScene != NULL) { SceneClass* toBMI = toScene->getSceneClassWithName(nameOfClassToTransfer); if (toBMI != NULL) { *toBMI = *fromBMI; setModified(); } } } } } /** * add paths to all of the scene spec file's data file names. */ void SceneFile::addPathToAllSpecFileDataFileNames(const QString& path) { const int numScenes = getNumberOfScenes(); for (int i = 0; i < numScenes; i++) { Scene* s = getScene(i); if (s->getSceneClassWithName("SpecFile") != NULL) { // // Get the spec file // SpecFile sf; QString msg; sf.showScene(*s, msg); // // Remove spec file from scene // s->removeClassWithName("SpecFile"); // // Remove paths from spec file // sf.prependPathsToAllFiles(path, true); // // Add spec file back to scene // sf.saveScene(*s, false); } } } /** * remove paths from all of the scene' spec file data names for a file on disk. */ void SceneFile::removePathsFromAllSpecFileDataFileNames(const QString& sceneFileName) throw (FileException) { SceneFile sf; sf.readFile(sceneFileName); sf.removePathsFromAllSpecFileDataFileNames(); sf.writeFile(sceneFileName); } /** * add paths to all of the scene spec file's data file names for a file on disk. */ void SceneFile::addPathToAllSpecFileDataFileNames(const QString& sceneFileName, const QString& path) throw (FileException) { SceneFile sf; sf.readFile(sceneFileName); sf.addPathToAllSpecFileDataFileNames(path); sf.writeFile(sceneFileName); } /*--------------------------------------------------------------------------------------*/ /** * Constructor. */ SceneFile::Scene::Scene(const QString& nameIn) { clear(); name = nameIn; } /** * Destructor. */ SceneFile::Scene::~Scene() { clear(); } /** * add a scene data for a class. */ void SceneFile::Scene::addSceneClass(const SceneClass& sc) { classes.push_back(sc); } /** * clear the scene info. */ void SceneFile::Scene::clear() { name = ""; classes.clear(); } /** * get a scene class (const method). */ const SceneFile::SceneClass* SceneFile::Scene::getSceneClass(const int indx) const { if ((indx >= 0) && (indx < getNumberOfSceneClasses())) { return &classes[indx]; } return NULL; } /** * get a scene class. */ SceneFile::SceneClass* SceneFile::Scene::getSceneClass(const int indx) { if ((indx >= 0) && (indx < getNumberOfSceneClasses())) { return &classes[indx]; } return NULL; } /** * get a class with the specified name. */ SceneFile::SceneClass* SceneFile::Scene::getSceneClassWithName(const QString& name) { for (int i = 0; i < getNumberOfSceneClasses(); i++) { SceneClass* sc = getSceneClass(i); if (sc->getName() == name) { return sc; } } return NULL; } /** * get a class with the specified name (const method). */ const SceneFile::SceneClass* SceneFile::Scene::getSceneClassWithName(const QString& name) const { for (int i = 0; i < getNumberOfSceneClasses(); i++) { const SceneClass* sc = getSceneClass(i); if (sc->getName() == name) { return sc; } } return NULL; } /** * remove a class with the specified name. */ void SceneFile::Scene::removeClassWithName(const QString& name) { for (int i = 0; i < getNumberOfSceneClasses(); i++) { SceneClass* sc = getSceneClass(i); if (sc->getName() == name) { classes.erase(classes.begin() + i); return ; } } } /*--------------------------------------------------------------------------------------*/ /** * Constructor. */ SceneFile::SceneClass::SceneClass(const QString& nameIn) { name = nameIn; } /** * Destructor. */ SceneFile::SceneClass::~SceneClass() { } /** * clear the scene class. */ void SceneFile::SceneClass::clear() { name = ""; info.clear(); } /** * add a scene info. */ void SceneFile::SceneClass::addSceneInfo(const SceneInfo& si) { info.push_back(si); } /** * get a scene info (const method). */ const SceneFile::SceneInfo* SceneFile::SceneClass::getSceneInfo(const int indx) const { if (indx < getNumberOfSceneInfo()) { return &info[indx]; } return NULL; } /** * get a scene info. */ SceneFile::SceneInfo* SceneFile::SceneClass::getSceneInfo(const int indx) { if (indx < getNumberOfSceneInfo()) { return &info[indx]; } return NULL; } /*--------------------------------------------------------------------------------------*/ /** * Constructor for Node Attributes with Multiple Overlays. */ SceneFile::SceneInfo::SceneInfo(const QString& nameIn, const QString& modelNameIn, const int overlayNumberIn, const QString& valueIn) { initialize(nameIn, modelNameIn, overlayNumberIn, valueIn); } /** * Constructor. */ SceneFile::SceneInfo::SceneInfo(const QString& nameIn, const QString& modelNameIn, const QString& valueIn) { initialize(nameIn, modelNameIn, -1, valueIn); } /** * Constructor. */ SceneFile::SceneInfo::SceneInfo(const QString& nameIn, const QString& modelNameIn, const float valueIn) { initialize(nameIn, modelNameIn, -1, QString::number(valueIn, 'f', 6)); } /** * Constructor. */ SceneFile::SceneInfo::SceneInfo(const QString& nameIn, const QString& modelNameIn, const int valueIn) { initialize(nameIn, modelNameIn, -1, QString::number(valueIn)); } /** * Constructor. */ SceneFile::SceneInfo::SceneInfo(const QString& nameIn, const QString& modelNameIn, const bool valueIn) { initialize(nameIn, modelNameIn, -1, StringUtilities::fromBool(valueIn)); } /** * Constructor. */ SceneFile::SceneInfo::SceneInfo(const QString& nameIn, const QString& valueIn) { initialize(nameIn, "", -1, valueIn); } /** * Constructor. */ SceneFile::SceneInfo::SceneInfo(const QString& nameIn, const QStringList& valueIn) { initialize(nameIn, "", -1, valueIn.join(" ")); } /** * Constructor. */ SceneFile::SceneInfo::SceneInfo(const QString& nameIn, const char* valueIn) { initialize(nameIn, "", -1, valueIn); } /** * Constructor. */ SceneFile::SceneInfo::SceneInfo(const QString& nameIn, const float valueIn) { initialize(nameIn, "", -1, QString::number(valueIn, 'f', 6)); } /** * Constructor. */ SceneFile::SceneInfo::SceneInfo(const QString& nameIn, const int valueIn) { initialize(nameIn, "", -1, QString::number(valueIn)); } /** * Constructor. */ SceneFile::SceneInfo::SceneInfo(const QString& nameIn, const bool valueIn) { initialize(nameIn, "", -1, StringUtilities::fromBool(valueIn)); } /** * Destructor. */ SceneFile::SceneInfo::~SceneInfo() { } /** * initialize the scene info. */ void SceneFile::SceneInfo::initialize(const QString& nameIn, const QString& modelNameIn, const int overlayNumberIn, const QString& valueIn) { name = nameIn; modelName = modelNameIn; overlayNumber = overlayNumberIn; value = valueIn; } /** * get the value as a string. */ QString SceneFile::SceneInfo::getValueAsString() const { return value; } /** * get the value as a float. */ float SceneFile::SceneInfo::getValueAsFloat() const { return StringUtilities::toFloat(value); } /** * get the value as an int. */ int SceneFile::SceneInfo::getValueAsInt() const { return StringUtilities::toInt(value); } /** * get the value as a bool */ bool SceneFile::SceneInfo::getValueAsBool() const { return StringUtilities::toBool(value); } caret-5.6.4~dfsg.1.orig/caret_files/SAVEDanalyze_dbh.h0000664000175000017500000001145711572067322022265 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ /* * * (c) Copyright, 1986-1995 * Biomedical Imaging Resource * Mayo Foundation * * dbh.h * * * database sub-definitions */ struct header_key /* header_key */ { /* off + size*/ int sizeof_hdr; /* 0 + 4 */ char data_type[10]; /* 4 + 10 */ char db_name[18]; /* 14 + 18 */ int extents; /* 32 + 4 */ short int session_error; /* 36 + 2 */ char regular; /* 38 + 1 */ char hkey_un0; /* 39 + 1 */ }; /* total=40 */ struct image_dimension /* image_dimension */ { /* off + size*/ short int dim[8]; /* 0 + 16 */ char vox_units[4]; /* 16 + 4 */ char cal_units[8]; /* 20 + 4 */ short int unused1; /* 24 + 2 */ short int datatype; /* 30 + 2 */ short int bitpix; /* 32 + 2 */ short int dim_un0; /* 34 + 2 */ float pixdim[8]; /* 36 + 32 */ /* pixdim[] specifies the voxel dimensions: pixdim[1] - voxel width pixdim[2] - voxel height pixdim[3] - interslice distance ..etc */ float vox_offset; /* 68 + 4 */ float roi_scale; /* 72 + 4 */ float funused1; /* 76 + 4 */ float funused2; /* 80 + 4 */ float cal_max; /* 84 + 4 */ float cal_min; /* 88 + 4 */ int compressed; /* 92 + 4 */ int verified; /* 96 + 4 */ int glmax, glmin; /* 100 + 8 */ }; /* total=108 */ struct data_history /* data_history */ { /* off + size*/ char descrip[80]; /* 0 + 80 */ char aux_file[24]; /* 80 + 24 */ char orient; /* 104 + 1 */ char originator[10]; /* 105 + 10 */ char generated[10]; /* 115 + 10 */ char scannum[10]; /* 125 + 10 */ char patient_id[10]; /* 135 + 10 */ char exp_date[10]; /* 145 + 10 */ char exp_time[10]; /* 155 + 10 */ char hist_un0[3]; /* 165 + 3 */ int views; /* 168 + 4 */ int vols_added; /* 172 + 4 */ int start_field; /* 176 + 4 */ int field_skip; /* 180 + 4 */ int omax,omin; /* 184 + 8 */ int smax,smin; /* 192 + 8 */ }; /* total=200 */ struct dsr /* dsr */ { /* off + size*/ struct header_key hk; /* 0 + 40 */ struct image_dimension dime; /* 40 + 108 */ struct data_history hist; /* 148 + 200 */ }; /* total=348 */ caret-5.6.4~dfsg.1.orig/caret_files/RgbPaintFile.h0000664000175000017500000002176711572067322021535 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_RGB_PAINT_FILE_H__ #define __VE_RGB_PAINT_FILE_H__ #include "NodeAttributeFile.h" class DeformationMapFile; class MniObjSurfaceFile; class vtkPolyData; /// RGB Paint File - associates RGB Values with each node class RgbPaintFile : public NodeAttributeFile { private: /// title for the red component std::vector redComponentTitle; /// title for the green component std::vector greenComponentTitle; /// title for the blue component std::vector blueComponentTitle; /// comment for each red component std::vector redComponentComment; /// comment for each green component std::vector greenComponentComment; /// comment for each blue component std::vector blueComponentComment; /// red column scaling minimum std::vector redComponentScaleMin; /// green column scaling minimum std::vector greenComponentScaleMin; /// blue column scaling minimum std::vector blueComponentScaleMin; /// red column scaling maximum std::vector redComponentScaleMax; /// green column scaling maximum std::vector greenComponentScaleMax; /// blue column scaling maximum std::vector blueComponentScaleMax; /// red color components std::vector redComponents; /// green color components std::vector greenComponents; /// blue color components std::vector blueComponents; /// read rgb paint file data void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException); /// read rgb paint file data for version 0 file void readFileDataVersion0(QFile& file, QTextStream& stream) throw (FileException); /// read rgb paint file data for version 1 file void readFileDataVersion1(QTextStream& stream) throw (FileException); /// read rgb paint file data for version 2 file void readFileDataVersion2(QTextStream& stream, QDataStream& binStream) throw (FileException); /// write rgb paint file data void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException); static const QString tagCommentRed; static const QString tagCommentGreen; static const QString tagCommentBlue; static const QString tagTitleRed; static const QString tagTitleGreen; static const QString tagTitleBlue; static const QString tagScaleRed; static const QString tagScaleGreen; static const QString tagScaleBlue; public: /// Constructor RgbPaintFile(); /// Destructor ~RgbPaintFile(); /// append a node attribute file to this one void append(NodeAttributeFile& naf) throw (FileException); /// append a node attribute file to this one but selectively load/overwrite columns /// columnDestination is where naf's columns should be (-1=new, -2=do not load) void append(NodeAttributeFile& naf, std::vector columnDestination, const FILE_COMMENT_MODE fcm) throw (FileException); /// add columns to this rgb paint file void addColumns(const int numberOfNewColumns); /// Add nodes to the file void addNodes(const int numberOfNodesToAdd); /// clear contents of this Rgb paint file void clear(); /// deform "this" node attribute file placing the output in "deformedFile". void deformFile(const DeformationMapFile& dmf, NodeAttributeFile& deformedFile, const DEFORM_TYPE dt) const throw (FileException); /// reset a column of data void resetColumn(const int columnNumber); /// remove a column of data void removeColumn(const int columnNumber); /// get the rgb paints for a node void getRgb(const int nodeNumber, const int columnNumber, float& red, float& green, float& blue) const; /// get the title for red component QString getTitleRed(const int columnNumber) const { return redComponentTitle[columnNumber]; } /// get the title for green component QString getTitleGreen(const int columnNumber) const { return greenComponentTitle[columnNumber]; } /// get the title for blue component QString getTitleBlue(const int columnNumber) const { return blueComponentTitle[columnNumber]; } /// get the comments for red component QString getCommentRed(const int columnNumber) const; /// get the comments for green component QString getCommentGreen(const int columnNumber) const; /// get the comments for blue component QString getCommentBlue(const int columnNumber) const; /// get the scale for red component void getScaleRed(const int columnNumber, float& minScale, float& maxScale) const; /// get the scale for green component void getScaleGreen(const int columnNumber, float& minScale, float& maxScale) const; /// get the scale for blue component void getScaleBlue(const int columnNumber, float& minScale, float& maxScale) const; /// import colors from vtk poly data void importFromVtkFile(vtkPolyData* polyData); /// Import colors from a SUMA file. void importFromSuma(const QString& name) throw (FileException); /// get the colors from a MNI OBJ surface file void importFromMniObjSurfaceFile(const MniObjSurfaceFile& mni) throw (FileException); /// set the rgb paints for a node void setRgb(const int nodeNumber, const int columnNumber, const float red, const float green, const float blue); /// set the rgb paints for a node void setRgb(const int nodeNumber, const int columnNumber, const double red, const double green, const double blue); /// set the title for a red column void setTitleRed(const int columnNumber, const QString& title); /// set the title for a green column void setTitleGreen(const int columnNumber, const QString& title); /// set the title for a blue column void setTitleBlue(const int columnNumber, const QString& title); /// set the comment for a red column void setCommentRed(const int columnNumber, const QString& comment); /// set the comment for a green column void setCommentGreen(const int columnNumber, const QString& comment); /// set the comment for a blue column void setCommentBlue(const int columnNumber, const QString& comment); /// set the scale for a red column component void setScaleRed(const int columnNumber, const float minScale, const float maxScale); /// set the scale for a green column component void setScaleGreen(const int columnNumber, const float minScale, const float maxScale); /// set the scale for a blue column component void setScaleBlue(const int columnNumber, const float minScale, const float maxScale); /// set the number of nodes and column void setNumberOfNodesAndColumns(const int numNodes, const int numColumns); }; #endif // __RGB_PAINT_FILE_H__ #ifdef _RGB_PAINT_FILE_MAIN_ const QString RgbPaintFile::tagCommentRed = "tag-comment-red"; const QString RgbPaintFile::tagCommentGreen = "tag-comment-green"; const QString RgbPaintFile::tagCommentBlue = "tag-comment-blue"; const QString RgbPaintFile::tagTitleRed = "tag-title-red"; const QString RgbPaintFile::tagTitleGreen = "tag-title-green"; const QString RgbPaintFile::tagTitleBlue = "tag-title-blue"; const QString RgbPaintFile::tagScaleRed = "tag-scale-red"; const QString RgbPaintFile::tagScaleGreen = "tag-scale-green"; const QString RgbPaintFile::tagScaleBlue = "tag-scale-blue"; #endif // _RGB_PAINT_FILE_MAIN_ caret-5.6.4~dfsg.1.orig/caret_files/RgbPaintFile.cxx0000664000175000017500000011315711572067322022103 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #define _RGB_PAINT_FILE_MAIN_ #include "RgbPaintFile.h" #undef _RGB_PAINT_FILE_MAIN_ #include "DeformationMapFile.h" #include "FileUtilities.h" #include "MniObjSurfaceFile.h" #include "RgbPaintFile.h" #include "SpecFile.h" #include "StringUtilities.h" #include "vtkLookupTable.h" #include "vtkPointData.h" #include "vtkPolyData.h" /** * The constructor */ RgbPaintFile::RgbPaintFile() : NodeAttributeFile("RGB Paint File", SpecFile::getRgbPaintFileExtension(), AbstractFile::FILE_FORMAT_ASCII, FILE_IO_READ_AND_WRITE, FILE_IO_READ_AND_WRITE, FILE_IO_NONE, FILE_IO_NONE) { clear(); } /** * The destructor */ RgbPaintFile::~RgbPaintFile() { clear(); } /** * append a node attribute file to this one but selectively load/overwrite columns * columnDestination is where naf's columns should be (-1=new, -2=do not load). */ void RgbPaintFile::append(NodeAttributeFile& /*naf*/, std::vector /*columnDestination*/, const FILE_COMMENT_MODE /*fcm*/) throw (FileException) { throw FileException("Not implemented yet."); } /** * append an rgb paint file to this one */ void RgbPaintFile::append(NodeAttributeFile &naf) throw (FileException) { RgbPaintFile& rpf = dynamic_cast(naf); if (getNumberOfNodes() != rpf.getNumberOfNodes()) { throw FileException("Cannot append RGB paint, number of columns does not match."); } const int oldNumCols = getNumberOfColumns(); const int appendNumCols = rpf.getNumberOfColumns(); // // Add the additional columns to the file // addColumns(appendNumCols); // // Transfer column attributes // for (int n = 0; n < appendNumCols; n++) { setColumnComment(oldNumCols + n, rpf.getColumnComment(n)); setColumnName(oldNumCols + n, rpf.getColumnName(n)); setTitleRed(oldNumCols + n, rpf.getTitleRed(n)); setTitleGreen(oldNumCols + n, rpf.getTitleGreen(n)); setTitleBlue(oldNumCols + n, rpf.getTitleBlue(n)); setCommentRed(oldNumCols + n, rpf.getCommentRed(n)); setCommentGreen(oldNumCols + n, rpf.getCommentGreen(n)); setCommentBlue(oldNumCols + n, rpf.getCommentBlue(n)); float minScale, maxScale; rpf.getScaleRed(n, minScale, maxScale); setScaleRed(oldNumCols + n, minScale, maxScale); rpf.getScaleGreen(n, minScale, maxScale); setScaleGreen(oldNumCols + n, minScale, maxScale); rpf.getScaleBlue(n, minScale, maxScale); setScaleBlue(oldNumCols + n, minScale, maxScale); } // // Transfer rgb data // float r, g, b; for (int i = 0; i < numberOfNodes; i++) { for (int k = 0; k < appendNumCols; k++) { rpf.getRgb(i, k, r, g, b); setRgb(i, oldNumCols + k, r, g, b); } } // // transfer the file's comment // appendFileComment(naf); } /** * add columns to this rgb paint file */ void RgbPaintFile::addColumns(const int numberOfNewColumns) { const int oldNumberOfColumns = numberOfColumns; const int totalColumns = numberOfColumns + numberOfNewColumns; // // Keep track of existing rgb paint data // const std::vector redData = redComponents; const std::vector greenData = greenComponents; const std::vector blueData = blueComponents; // // Setup file for new number of columns (will expand space for column naming) // setNumberOfNodesAndColumns(numberOfNodes, totalColumns); // // Transfer existing rgb paint data // for (int i = 0; i < numberOfNodes; i++) { for (int j = 0; j < numberOfColumns; j++) { float r = 0.0, g = 0.0, b = 0.0; if (j < oldNumberOfColumns) { const int oldIndex = (oldNumberOfColumns * i) + j; r = redData[oldIndex]; g = greenData[oldIndex]; b = blueData[oldIndex]; } setRgb(i, j, r, g, b); } } setModified(); } /** * Add nodes to the file */ void RgbPaintFile::addNodes(const int numberOfNodesToAdd) { setNumberOfNodesAndColumns(numberOfNodes + numberOfNodesToAdd, numberOfColumns); } /** * clear the RGB Paint file */ void RgbPaintFile::clear() { clearNodeAttributeFile(); setNumberOfNodesAndColumns(0, 0); } /** * get the comments for red component */ QString RgbPaintFile::getCommentRed(const int columnNumber) const { //return StringUtilities::setupCommentForDisplay(redComponentComment[columnNumber]); return redComponentComment[columnNumber]; } /** * get the comments for green component */ QString RgbPaintFile::getCommentGreen(const int columnNumber) const { //return StringUtilities::setupCommentForDisplay(greenComponentComment[columnNumber]); return greenComponentComment[columnNumber]; } /** * get the comments for blue component */ QString RgbPaintFile::getCommentBlue(const int columnNumber) const { //return StringUtilities::setupCommentForDisplay(blueComponentComment[columnNumber]); return blueComponentComment[columnNumber]; } /** * Deform the rgb paint file. */ void RgbPaintFile::deformFile(const DeformationMapFile& dmf, NodeAttributeFile& deformedFile, const DEFORM_TYPE /*dt*/) const throw (FileException) { RgbPaintFile& deformedRgbPaintFile = dynamic_cast(deformedFile); const int numNodes = dmf.getNumberOfNodes(); deformedRgbPaintFile.setNumberOfNodesAndColumns(numNodes, getNumberOfColumns()); // // Transfer stuff in AbstractFile and NodeAttributeFile // transferFileDataForDeformation(dmf, deformedRgbPaintFile); // // transfer the descriptive data // for (int j = 0; j < getNumberOfColumns(); j++) { deformedRgbPaintFile.setTitleRed(j, getTitleRed(j)); deformedRgbPaintFile.setTitleGreen(j, getTitleGreen(j)); deformedRgbPaintFile.setTitleBlue(j, getTitleBlue(j)); deformedRgbPaintFile.setCommentRed(j, getCommentRed(j)); deformedRgbPaintFile.setCommentGreen(j, getCommentGreen(j)); deformedRgbPaintFile.setCommentBlue(j, getCommentBlue(j)); float minScale, maxScale; getScaleRed(j, minScale, maxScale); deformedRgbPaintFile.setScaleRed(j, minScale, maxScale); getScaleGreen(j, minScale, maxScale); deformedRgbPaintFile.setScaleGreen(j, minScale, maxScale); getScaleBlue(j, minScale, maxScale); deformedRgbPaintFile.setScaleBlue(j, minScale, maxScale); } // // transfer the node // int tileNodes[3]; float tileAreas[3]; for (int i = 0; i < numNodes; i++) { dmf.getDeformDataForNode(i, tileNodes, tileAreas); for (int j = 0; j < getNumberOfColumns(); j++) { float r = 0, g = 0, b = 0; if (tileNodes[0] > -1) { getRgb(tileNodes[0], j, r, g, b); } deformedRgbPaintFile.setRgb(i, j, r, g, b); } } } /** * reset a column of data. */ void RgbPaintFile::resetColumn(const int columnNumber) { for (int i = 0; i < numberOfNodes; i++) { setRgb(i, columnNumber, 0.0, 0.0, 0.0); } setColumnName(columnNumber, ""); setColumnComment(columnNumber, ""); setTitleRed(columnNumber, ""); setTitleGreen(columnNumber, ""); setTitleBlue(columnNumber, ""); setCommentRed(columnNumber, ""); setCommentGreen(columnNumber, ""); setCommentBlue(columnNumber, ""); setScaleRed(columnNumber, 0.0, 0.0); setScaleGreen(columnNumber, 0.0, 0.0); setScaleBlue(columnNumber, 0.0, 0.0); setModified(); } /** * remove a column of data. */ void RgbPaintFile::removeColumn(const int columnNumber) { if (numberOfColumns <= 1) { clear(); return; } // // Transfer column attributes // int ctr = 0; for (int n = 0; n < numberOfColumns; n++) { if (n != columnNumber) { setColumnComment(ctr, getColumnComment(n)); setColumnName(ctr, getColumnName(n)); setTitleRed(ctr, getTitleRed(n)); setTitleGreen(ctr, getTitleGreen(n)); setTitleBlue(ctr, getTitleBlue(n)); setCommentRed(ctr, getCommentRed(n)); setCommentGreen(ctr, getCommentGreen(n)); setCommentBlue(ctr, getCommentBlue(n)); float minScale, maxScale; getScaleRed(n, minScale, maxScale); setScaleRed(ctr, minScale, maxScale); getScaleGreen(n, minScale, maxScale); setScaleGreen(ctr, minScale, maxScale); getScaleBlue(n, minScale, maxScale); setScaleBlue(ctr, minScale, maxScale); ctr++; } } // // Transfer rgb data // RgbPaintFile tempRGB; tempRGB.setNumberOfNodesAndColumns(numberOfNodes, numberOfColumns - 1); float r, g, b; for (int i = 0; i < numberOfNodes; i++) { int ctr = 0; for (int k = 0; k < numberOfColumns; k++) { if (k != columnNumber) { getRgb(i, k, r, g, b); tempRGB.setRgb(i, ctr, r, g, b); ctr++; } } } setNumberOfNodesAndColumns(numberOfNodes, numberOfColumns - 1); redComponents = tempRGB.redComponents; greenComponents = tempRGB.greenComponents; blueComponents = tempRGB.blueComponents; setModified(); } /** * Get the rgb values for a node */ void RgbPaintFile::getRgb(const int nodeNumber, const int columnNumber, float& red, float& green, float& blue) const { const int index = getOffset(nodeNumber, columnNumber); red = redComponents[index]; green = greenComponents[index]; blue = blueComponents[index]; } /** * Get the red scale. */ void RgbPaintFile::getScaleRed(const int columnNumber, float& minScale, float& maxScale) const { minScale = redComponentScaleMin[columnNumber]; maxScale = redComponentScaleMax[columnNumber]; } /** * Get the green scale. */ void RgbPaintFile::getScaleGreen(const int columnNumber, float& minScale, float& maxScale) const { minScale = greenComponentScaleMin[columnNumber]; maxScale = greenComponentScaleMax[columnNumber]; } /** * Get the blue scale. */ void RgbPaintFile::getScaleBlue(const int columnNumber, float& minScale, float& maxScale) const { minScale = blueComponentScaleMin[columnNumber]; maxScale = blueComponentScaleMax[columnNumber]; } /** * Set the RGB values for a node. */ void RgbPaintFile::setRgb(const int nodeNumber, const int columnNumber, const float red, const float green, const float blue) { const int index = getOffset(nodeNumber, columnNumber); redComponents[index] = red; greenComponents[index] = green; blueComponents[index] = blue; setModified(); } /** * Set the RGB values for a node. */ void RgbPaintFile::setRgb(const int nodeNumber, const int columnNumber, const double red, const double green, const double blue) { const int index = getOffset(nodeNumber, columnNumber); redComponents[index] = red; greenComponents[index] = green; blueComponents[index] = blue; setModified(); } /** * Set the red scale. */ void RgbPaintFile::setScaleRed(const int columnNumber, const float minScale, const float maxScale) { redComponentScaleMin[columnNumber] = minScale; redComponentScaleMax[columnNumber] = maxScale; setModified(); } /** * Set the green scale for a node. */ void RgbPaintFile::setScaleGreen(const int columnNumber, const float minScale, const float maxScale) { greenComponentScaleMin[columnNumber] = minScale; greenComponentScaleMax[columnNumber] = maxScale; setModified(); } /** * Set the blue scale for a node. */ void RgbPaintFile::setScaleBlue(const int columnNumber, const float minScale, const float maxScale) { blueComponentScaleMin[columnNumber] = minScale; blueComponentScaleMax[columnNumber] = maxScale; setModified(); } /** * Set the title for a red component */ void RgbPaintFile::setTitleRed(const int columnNumber, const QString& title) { redComponentTitle[columnNumber] = title; setModified(); } /** * Set the title for a green component */ void RgbPaintFile::setTitleGreen(const int columnNumber, const QString& title) { greenComponentTitle[columnNumber] = title; setModified(); } /** * Set the title for a blue component */ void RgbPaintFile::setTitleBlue(const int columnNumber, const QString& title) { blueComponentTitle[columnNumber] = title; setModified(); } /** * set the comment for a red column */ void RgbPaintFile::setCommentRed(const int columnNumber, const QString& comment) { //redComponentComment[columnNumber] = StringUtilities::setupCommentForStorage(comment)); redComponentComment[columnNumber] = comment; setModified(); } /** * set the comment for a green column */ void RgbPaintFile::setCommentGreen(const int columnNumber, const QString& comment) { //greenComponentComment[columnNumber] = StringUtilities::setupCommentForStorage(comment)); greenComponentComment[columnNumber] = comment; setModified(); } /** * set the comment for a blue column */ void RgbPaintFile::setCommentBlue(const int columnNumber, const QString& comment) { //blueComponentComment[columnNumber] = StringUtilities::setupCommentForStorage(comment)); blueComponentComment[columnNumber] = comment; setModified(); } /** * Set the number of nodes. */ void RgbPaintFile::setNumberOfNodesAndColumns(const int numNodes, const int numColumns) { const int oldNumberOfColumns = numberOfColumns; if ((numNodes == 0) || (numColumns == 0)) { redComponentTitle.clear(); greenComponentTitle.clear(); blueComponentTitle.clear(); redComponentComment.clear(); greenComponentComment.clear(); blueComponentComment.clear(); redComponentScaleMin.clear(); greenComponentScaleMin.clear(); blueComponentScaleMin.clear(); redComponentScaleMax.clear(); greenComponentScaleMax.clear(); blueComponentScaleMax.clear(); redComponents.clear(); greenComponents.clear(); blueComponents.clear(); } numberOfNodes = numNodes; numberOfColumns = numColumns; if (numberOfNodes > 0) { const int totalItems = numberOfNodes * numberOfColumns * numberOfItemsPerColumn; redComponents.resize(totalItems); greenComponents.resize(totalItems); blueComponents.resize(totalItems); for (int i = 0; i < totalItems; i++) { redComponents[i] = 0.0; greenComponents[i] = 0.0; blueComponents[i] = 0.0; } redComponentTitle.resize(numberOfColumns); greenComponentTitle.resize(numberOfColumns); blueComponentTitle.resize(numberOfColumns); redComponentComment.resize(numberOfColumns); greenComponentComment.resize(numberOfColumns); blueComponentComment.resize(numberOfColumns); redComponentScaleMin.resize(numberOfColumns); greenComponentScaleMin.resize(numberOfColumns); blueComponentScaleMin.resize(numberOfColumns); redComponentScaleMax.resize(numberOfColumns); greenComponentScaleMax.resize(numberOfColumns); blueComponentScaleMax.resize(numberOfColumns); for (int i = 0; i < numberOfColumns; i++) { if (i >= oldNumberOfColumns) { redComponentTitle[i] = "Red"; greenComponentTitle[i] = "Green"; blueComponentTitle[i] = "Blue"; redComponentScaleMin[i] = 0.0; redComponentScaleMax[i] = 255.0; greenComponentScaleMin[i] = 0.0; greenComponentScaleMax[i] = 255.0; blueComponentScaleMin[i] = 0.0; blueComponentScaleMax[i] = 255.0; } } } numberOfNodesColumnsChanged(); setModified(); } /** * Import colors from a SUMA file. */ void RgbPaintFile::importFromSuma(const QString& name) throw (FileException) { /* * Sample SUMS RGB file * #FileContents = Node Colors #RowFormat = n R G B #N_Nodes = 137680 #Source = SUMA, surface lh.inflated.asc (idcode: XYZ_xKtbVhfo4zqCj8PwZ07D9Q) 0 0.373684 0.373684 0.373684 1 0.386842 0.386842 0.386842 2 0.360526 0.360526 0.360526 */ QFile file(name); if (file.open(QIODevice::ReadOnly) == false) { QString msg("Unable to open file named "); msg.append(name); throw FileException(name, msg); } QTextStream stream(&file); int columnNumber = -1; bool readData = false; bool gotScale = false; QString line; readLine(stream, line); while (stream.atEnd() == false) { if (columnNumber >= 0) { if (line.isEmpty() == false) { if (line[0] != '#') { std::vector tokens; StringUtilities::token(line, " \t", tokens); if (tokens.size() >= 4) { setRgb(StringUtilities::toInt(tokens[0]), columnNumber, StringUtilities::toFloat(tokens[1]), StringUtilities::toFloat(tokens[2]), StringUtilities::toFloat(tokens[3])); // // Suma RGB files appear to be scaled [0.0, 1.0] // if (gotScale == false) { for (int i = 1; i <= 3; i++) { const float val = StringUtilities::toFloat(tokens[1]); if ((val > 0.0) && (val < 1.0)) { redComponentScaleMin[columnNumber] = 0.0; redComponentScaleMax[columnNumber] = 1.0; greenComponentScaleMin[columnNumber] = 0.0; greenComponentScaleMax[columnNumber] = 1.0; blueComponentScaleMin[columnNumber] = 0.0; blueComponentScaleMax[columnNumber] = 1.0; gotScale = true; break; } } } readData = true; } } } } else { if (StringUtilities::startsWith(line, "#N_Nodes")) { std::vector tokens; StringUtilities::token(line, " \t", tokens); if (tokens.size() == 3) { const int num = StringUtilities::toInt(tokens[2]); if (numberOfNodes <= 0) { setNumberOfNodesAndColumns(num, 1); columnNumber = 0; } else { if (num != numberOfNodes) { file.close(); throw FileException(filename, "File has wrong number of nodes."); } else { addColumns(1); columnNumber = numberOfColumns - 1; } } } } } readLine(stream, line); } file.close(); if (readData == false) { throw FileException(filename, "Never found RGB data."); } } /** * get the coordinates from a MNI OBJ surface file. */ void RgbPaintFile::importFromMniObjSurfaceFile(const MniObjSurfaceFile& /*mni*/) throw (FileException) { } /** * Import colors from a vtk surface file */ void RgbPaintFile::importFromVtkFile(vtkPolyData* polyData) { const int numPoints = polyData->GetNumberOfPoints(); if (numPoints <= 0) { return; } // // Determine column to use in RGB Paint file. // int column = 0; if (getNumberOfNodes() == 0) { clear(); setNumberOfNodesAndColumns(numPoints, 1); } else if (numPoints != getNumberOfNodes()) { std::cout << "Number of nodes in VTK file does not match number in RGB Paint file." << std::endl; } else { addColumns(1); column = getNumberOfColumns() - 1; } vtkPointData* pointData = polyData->GetPointData(); vtkDataArray* scalars = pointData->GetScalars(); if (scalars != NULL) { if ( (scalars->GetDataType() == VTK_UNSIGNED_CHAR) && (scalars->GetNumberOfComponents() == 3) ) { vtkUnsignedCharArray* colors = (vtkUnsignedCharArray*)scalars; for (int i = 0; i < numPoints; i++) { #ifdef HAVE_VTK5 double rgb[3]; #else // HAVE_VTK5 float rgb[3]; #endif // HAVE_VTK5 colors->GetTuple(i, rgb); setRgb(i, column, rgb[0], rgb[1], rgb[2]); } } else if ( (scalars->GetDataType() == VTK_FLOAT) && (scalars->GetNumberOfComponents() == 1) ) { float maxValue = -100000.0; for (int j = 0; j < numPoints; j++) { if (scalars->GetComponent(j, 0) > maxValue) { maxValue = scalars->GetComponent(j, 0); } } vtkLookupTable* lookupTable = scalars->GetLookupTable(); if (maxValue <= 1.0) { setScaleRed(column, 0.0, 1.0); setScaleGreen(column, 0.0, 1.0); setScaleBlue(column, 0.0, 1.0); } for (int i = 0; i < numPoints; i++) { const float value = scalars->GetComponent(i, 0); if (lookupTable == NULL) { setRgb(i, column, value, value, value); } else { #ifdef HAVE_VTK5 double rgb[3] = { 0.0, 0.0, 0.0 }; lookupTable->GetColor((double)value, rgb); #else // HAVE_VTK5 float rgb[3] = { 0.0, 0.0, 0.0 }; lookupTable->GetColor((float)value, rgb); #endif // HAVE_VTK5 setRgb(i, column, rgb[0], rgb[1], rgb[2]); } } } } } /** * Read the RGB Paint file's data. */ void RgbPaintFile::readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException) { // // save file position since version 0 has no tags // qint64 oldFilePosition = stream.pos(); //file.pos(); QString line; QString versionStr, versionNumberStr; readTagLine(stream, versionStr, versionNumberStr); int fileVersion = 0; if (versionStr == tagFileVersion) { fileVersion = versionNumberStr.toInt(); } switch(fileVersion) { case 0: file.seek(oldFilePosition); stream.seek(oldFilePosition); readFileDataVersion0(file, stream); break; case 1: readFileDataVersion1(stream); break; case 2: readFileDataVersion2(stream, binStream); break; default: throw FileException(filename, "Invalid RGB paint file version"); break; } } /** * Read file version 0 */ void RgbPaintFile::readFileDataVersion0(QFile& file, QTextStream& stream) throw (FileException) { long oldFilePosition = stream.pos(); //file.pos(); // // version 0 RGB paint file does not store the number of nodes in it // so figure out how many. // int numNodes = 0; QString line; readLine(stream, line); while (stream.atEnd() == false) { numNodes++; readLine(stream, line); } setNumberOfNodesAndColumns(numNodes, 1); if (numberOfNodes <= 0) { throw FileException(filename, "RGB Paint file has no data"); } // // Should reading data be skipped ? // if (getReadMetaDataOnlyFlag()) { return; } file.seek(oldFilePosition); stream.seek(oldFilePosition); std::vector tokens; QString line1; for (int i = 0; i < numberOfNodes; i++) { readLineIntoTokens(stream, line1, tokens); if (tokens.size() == 3) { redComponents[i] = tokens[0].toInt(); greenComponents[i] = tokens[1].toInt(); blueComponents[i] = tokens[2].toInt(); } else { throw FileException(filename, "Reading RGB Paint file data line "); } } } /** * Read version 1 of the RGB paint file. */ void RgbPaintFile::readFileDataVersion1(QTextStream& stream) throw (FileException) { int numNodes = -1; QString fileTitleTemp; QString commentRed; QString commentGreen; QString commentBlue; QString titleRed; QString titleGreen; QString titleBlue; QString scaleRed; QString scaleGreen; QString scaleBlue; float redMin = 0.0, redMax = 0.0; float greenMin = 0.0, greenMax = 0.0; float blueMin = 0.0, blueMax = 0.0; bool readingTags = true; while(readingTags) { QString tag, tagValue; readTagLine(stream, tag, tagValue); if (tag == tagBeginData) { readingTags = false; } else if (tag == tagNumberOfNodes) { numNodes = tagValue.toInt(); } else if (tag == tagFileTitle) { fileTitleTemp = tagValue; } else if (tag == tagCommentRed) { commentRed = tagValue; } else if (tag == tagCommentGreen) { commentGreen = tagValue; } else if (tag == tagCommentBlue) { commentBlue = tagValue; } else if (tag == tagTitleRed) { titleRed = tagValue; } else if (tag == tagTitleGreen) { titleGreen = tagValue; } else if (tag == tagTitleBlue) { titleBlue = tagValue; } else if (tag == tagScaleRed) { std::vector tokens; StringUtilities::token(tagValue, " \t", tokens); if (tokens.size() == 2) { redMin = tokens[0].toFloat(); redMax = tokens[1].toFloat(); } } else if (tag == tagScaleGreen) { std::vector tokens; StringUtilities::token(tagValue, " \t", tokens); if (tokens.size() == 2) { greenMin = tokens[0].toFloat(); greenMax = tokens[1].toFloat(); } } else if (tag == tagScaleBlue) { std::vector tokens; StringUtilities::token(tagValue, " \t", tokens); if (tokens.size() == 2) { blueMin = tokens[0].toFloat(); blueMax = tokens[1].toFloat(); } } else { std::cerr << "WARNING: Unknown RGB Paint File Tag: " << tag.toAscii().constData() << std::endl; } } if (numNodes <= 0) { throw FileException(filename, "No data in RGB paint file"); } setNumberOfNodesAndColumns(numNodes, 1); fileTitle = fileTitleTemp; columnNames[0] = fileTitleTemp; columnComments[0] = fileTitle; redComponentTitle[0] = titleRed; greenComponentTitle[0] = titleGreen; blueComponentTitle[0] = titleBlue; redComponentComment[0] = StringUtilities::setupCommentForDisplay(commentRed); greenComponentComment[0] = StringUtilities::setupCommentForDisplay(commentGreen); blueComponentComment[0] = StringUtilities::setupCommentForDisplay(commentBlue); redComponentScaleMin[0] = redMin; redComponentScaleMax[0] = redMax; greenComponentScaleMin[0] = greenMin; greenComponentScaleMax[0] = greenMax; blueComponentScaleMin[0] = blueMin; blueComponentScaleMax[0] = blueMax; // // Should reading data be skipped ? // if (getReadMetaDataOnlyFlag()) { return; } std::vector tokens; QString line; for (int i = 0; i < numberOfNodes; i++) { readLineIntoTokens(stream, line, tokens); if (tokens.size() == 4) { redComponents[i] = tokens[1].toFloat(); greenComponents[i] = tokens[2].toFloat(); blueComponents[i] = tokens[3].toFloat(); } else { throw FileException(filename, "Reading RGB Paint file"); } } } /** * Read version 2 of the RGB paint file. */ void RgbPaintFile::readFileDataVersion2(QTextStream& stream, QDataStream& binStream) throw (FileException) { int numNodes = -1; int numCols = -1; bool readingTags = true; while(readingTags) { QString tag, tagValue; readTagLine(stream, tag, tagValue); if (tag == tagBeginData) { readingTags = false; } else if (tag == tagNumberOfNodes) { numNodes = tagValue.toInt(); if ((numNodes > 0) && (numCols > 0)) { setNumberOfNodesAndColumns(numNodes, numCols); } } else if (tag == tagNumberOfColumns) { numCols = tagValue.toInt(); if ((numNodes > 0) && (numCols > 0)) { setNumberOfNodesAndColumns(numNodes, numCols); } } else if (tag == tagFileTitle) { fileTitle = tagValue; } else if (tag == tagColumnName) { QString name; const int index = splitTagIntoColumnAndValue(tagValue, name); columnNames[index] = name; } else if (tag == tagColumnComment) { QString name; const int index = splitTagIntoColumnAndValue(tagValue, name); columnComments[index] = StringUtilities::setupCommentForDisplay(name); } else if (tag == tagCommentRed) { QString name; const int index = splitTagIntoColumnAndValue(tagValue, name); redComponentComment[index] = StringUtilities::setupCommentForDisplay(name); } else if (tag == tagCommentGreen) { QString name; const int index = splitTagIntoColumnAndValue(tagValue, name); greenComponentComment[index] = StringUtilities::setupCommentForDisplay(name); } else if (tag == tagCommentBlue) { QString name; const int index = splitTagIntoColumnAndValue(tagValue, name); blueComponentComment[index] = StringUtilities::setupCommentForDisplay(name); } else if (tag == tagTitleRed) { QString name; const int index = splitTagIntoColumnAndValue(tagValue, name); redComponentTitle[index] = name; } else if (tag == tagTitleGreen) { QString name; const int index = splitTagIntoColumnAndValue(tagValue, name); greenComponentTitle[index] = name; } else if (tag == tagTitleBlue) { QString name; const int index = splitTagIntoColumnAndValue(tagValue, name); blueComponentTitle[index] = name; } else if (tag == tagScaleRed) { std::vector tokens; StringUtilities::token(tagValue, " \t", tokens); if (tokens.size() == 3) { const int index = tokens[0].toInt(); redComponentScaleMin[index] = tokens[1].toFloat(); redComponentScaleMax[index] = tokens[2].toFloat(); } } else if (tag == tagScaleGreen) { std::vector tokens; StringUtilities::token(tagValue, " \t", tokens); if (tokens.size() == 3) { const int index = tokens[0].toInt(); greenComponentScaleMin[index] = tokens[1].toFloat(); greenComponentScaleMax[index] = tokens[2].toFloat(); } } else if (tag == tagScaleBlue) { std::vector tokens; StringUtilities::token(tagValue, " \t", tokens); if (tokens.size() == 3) { const int index = tokens[0].toInt(); blueComponentScaleMin[index] = tokens[1].toFloat(); blueComponentScaleMax[index] = tokens[2].toFloat(); } } } // // Should reading data be skipped ? // if (getReadMetaDataOnlyFlag()) { return; } if (numNodes <= 0) { throw FileException(filename, "No data in RGB paint file"); } switch (getFileReadType()) { case FILE_FORMAT_ASCII: { std::vector tokens; QString line; for (int i = 0; i < numberOfNodes; i++) { readLineIntoTokens(stream, line, tokens); if (static_cast(tokens.size()) == (numberOfColumns * 3 + 1)) { for (int j = 0; j < numberOfColumns; j++) { const float r = tokens[j * 3 + 1].toFloat(); const float g = tokens[j * 3 + 2].toFloat(); const float b = tokens[j * 3 + 3].toFloat(); setRgb(i, j, r, g, b); } } else { QString msg("Reading RGB Paint file line: "); msg.append(line); throw FileException(filename, msg); } } } break; case FILE_FORMAT_BINARY: { binStream.device()->seek(stream.pos()); float r, g, b; for (int i = 0; i < numberOfNodes; i++) { for (int j = 0; j < numberOfColumns; j++) { binStream >> r >> g >> b; setRgb(i, j, r, g, b); } } } break; case FILE_FORMAT_XML: throw FileException(filename, "Writing in XML format not supported."); break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Writing XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Writing in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Comma Separated Value File Format not supported."); break; } } /** * Write the RGB paint file. */ void RgbPaintFile::writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException) { // // output tags // stream << tagFileVersion << " 2\n"; stream << tagNumberOfNodes << " " << numberOfNodes << "\n"; stream << tagNumberOfColumns << " " << numberOfColumns << "\n"; stream << tagFileTitle << " " << fileTitle << "\n"; for (int j = 0; j < numberOfColumns; j++) { stream << tagColumnComment << " " << j << " " << StringUtilities::setupCommentForStorage(columnComments[j]) << "\n"; stream << tagColumnName << " " << j << " " << columnNames[j] << "\n"; stream << tagCommentRed << " " << j << " " << StringUtilities::setupCommentForStorage(redComponentComment[j]) << "\n"; stream << tagCommentGreen << " " << j << " " << StringUtilities::setupCommentForStorage(greenComponentComment[j]) << "\n"; stream << tagCommentBlue << " " << j << " " << StringUtilities::setupCommentForStorage(blueComponentComment[j]) << "\n"; stream << tagTitleRed << " " << j << " " << redComponentTitle[j] << "\n"; stream << tagTitleGreen << " " << j << " " << greenComponentTitle[j] << "\n"; stream << tagTitleBlue << " " << j << " " << blueComponentTitle[j] << "\n"; stream << tagScaleRed << " " << j << " " << redComponentScaleMin[j] << " " << redComponentScaleMax[j] << "\n"; stream << tagScaleGreen << " " << j << " " << greenComponentScaleMin[j] << " " << greenComponentScaleMax[j] << "\n"; stream << tagScaleBlue << " " << j << " " << blueComponentScaleMin[j] << " " << blueComponentScaleMax[j] << "\n"; } stream << tagBeginData << "\n"; switch (getFileWriteType()) { case FILE_FORMAT_ASCII: { float r, g, b; for (int i = 0; i < numberOfNodes; i++) { stream << i; for (int j = 0; j < numberOfColumns; j++) { getRgb(i, j, r, g, b); stream << " " << r << " " << g << " " << b; } stream << "\n"; } } break; case FILE_FORMAT_BINARY: #ifdef QT4_FILE_POS_BUG setBinaryFilePosQT4Bug(); #else // QT4_FILE_POS_BUG // // still a bug in QT 4.2.2 // setBinaryFilePosQT4Bug(); #endif // QT4_FILE_POS_BUG { float r, g, b; for (int i = 0; i < numberOfNodes; i++) { for (int j = 0; j < numberOfColumns; j++) { getRgb(i, j, r, g, b); binStream << r << g << b; } } } break; case FILE_FORMAT_XML: throw FileException(filename, "Writing in XML format not supported."); break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Writing XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Writing in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Comma Separated Value File Format not supported."); break; } } caret-5.6.4~dfsg.1.orig/caret_files/PubMedArticleFile.h0000664000175000017500000001206011572067322022471 0ustar michaelmichael #ifndef __PUB_MED_ARTICLE_FILE_H__ #define __PUB_MED_ARTICLE_FILE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "AbstractFile.h" // class for process a PubMed file retrieved via an HTTP request class PubMedArticleFile : public AbstractFile { public: // constructor PubMedArticleFile(); // destructor ~PubMedArticleFile(); // retrieve the article information for the specified PubMed ID void retrieveArticleWithPubMedID(const QString& pubMedIDIn) throw (FileException); // clear the file void clear(); // returns true if the file is isEmpty (contains no data) bool empty() const; // the article title QString getArticleTitle() const { return articleTitle; } // the list of authors QString getAuthors() const { return authors; } // the journal title QString getJournalTitle() const { return journalTitle; } // the Document Object Identifier QString getDocumentObjectIdentifier() const { return documentObjectIdentifier; } // the abstract QString getAbstractText() const { return abstractText; } // the PubMed ID QString getPubMedID() const { return pubMedID; } // get the medical subject headings QString getMedicalSubjectHeadings() const { return medicalSubjectHeadings; } // parse the xml string void parseXML(const QString xmlString) throw (FileException); protected: // read the file void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& rootElement) throw (FileException); // write the file void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& xmlDoc, QDomElement& rootElement) throw (FileException); // process the PubMedArticle children void processPubMedArticleChildren(QDomNode node) throw (FileException); // process the MedlineCitation children void processMedlineCitationChildren(QDomNode node) throw (FileException); // process the PubmedData children void processPubmedDataChildren(QDomNode node) throw (FileException); // process the Article children void processArticleChildren(QDomNode node) throw (FileException); // process the Journal children void processJournalChildren(QDomNode node) throw (FileException); // process the Journal Issue children void processJournalIssueChildren(QDomNode node) throw (FileException); // process the Journal Pub Date children void processJournalPubDateChildren(QDomNode node) throw (FileException); // process the AuthorList children void processAuthorListChildren(QDomNode node) throw (FileException); // process the ArticleIdList children void processArticleIdListChildren(QDomNode node) throw (FileException); // process the Pagination children void processPaginationChildren(QDomNode node) throw (FileException); // process the mesh heading list children void processMeshHeadingListChildren(QDomNode node) throw (FileException); // process the mesh heading children void processMeshHeadingChildren(QDomNode node) throw (FileException); // process the children //void processChildren(QDomNode node) throw (FileException); /// the article title QString articleTitle; /// the list of authors QString authors; /// the journal pages QString journalPages; /// the journal title QString journalTitle; /// the journal volume QString journalVolume; /// the journal year QString journalYear; /// the medical subject headings QString medicalSubjectHeadings; /// the Document Object Identifier QString documentObjectIdentifier; /// the abstract QString abstractText; /// the PubMed ID QString pubMedID; }; #endif // __PUB_MED_ARTICLE_FILE_H__ caret-5.6.4~dfsg.1.orig/caret_files/PubMedArticleFile.cxx0000664000175000017500000004742011572067322023054 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include "DebugControl.h" #include "HttpFileDownload.h" #include "PubMedArticleFile.h" #include "TextFile.h" /** * constructor. */ PubMedArticleFile::PubMedArticleFile() : AbstractFile("PubMed Article File", ".xml", false, FILE_FORMAT_XML, // default format FILE_IO_NONE, // read/write ascii FILE_IO_NONE, // read/write binary FILE_IO_NONE, // read/write xml FILE_IO_NONE, // read/write xml base64 FILE_IO_NONE, // read/write xml gzip FILE_IO_NONE, // read/write other FILE_IO_NONE) // read/write csv { clear(); } /** * destructor. */ PubMedArticleFile::~PubMedArticleFile() { clear(); } /** * clear the file. */ void PubMedArticleFile::clear() { articleTitle = ""; authors = ""; journalPages = ""; journalTitle = ""; journalVolume = ""; journalYear = ""; medicalSubjectHeadings = ""; documentObjectIdentifier = ""; abstractText = ""; pubMedID = ""; } /** * retrieve the article information for the specified PubMed ID. */ void PubMedArticleFile::retrieveArticleWithPubMedID(const QString& pubMedIDIn) throw (FileException) { clear(); pubMedID = pubMedIDIn.trimmed(); if (pubMedID.isEmpty()) { throw FileException("PubMed ID is empty."); } // // Construct the URL // const QString pubMedURL = ("http://www.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=pubmed&id=" + pubMedID + "&retmode=xml&rettype=citation"); if (DebugControl::getDebugOn()) { std::cout << "URL to get PubMed Info: " << pubMedURL.toAscii().constData() << std::endl; } // // Download the file // const int timeOutInSeconds = 30; HttpFileDownload http(pubMedURL, timeOutInSeconds); http.download(); if (http.getDownloadSuccessful()) { QString pubMedString; http.getContentUTF8(pubMedString); if (DebugControl::getDebugOn()) { std::cout << "Retrieved from PubMed: " << std::endl << "Response Code: " << http.getResponseCode() << std::endl << pubMedString.toAscii().constData() << std::endl << std::endl; } parseXML(pubMedString); } else { throw FileException("HTTP Error: " + http.getErrorMessage()); } } /** * parse the xml string. */ void PubMedArticleFile::parseXML(const QString xmlString) throw (FileException) { // // Use the DOM parser and set its content // QDomDocument dom("PubMed-File"); QString domErrorMessage; int domErrorLine, domErrorColumn; if (dom.setContent(xmlString, &domErrorMessage, &domErrorLine, &domErrorColumn) == false) { // // Creation of DOM structure failed // QString msg = ("Error parsing document at line " + QString::number(domErrorLine) + ", column " + QString::number(domErrorColumn)); if (DebugControl::getDebugOn()) { TextFile tf; tf.setText(xmlString); try { const QString textFileName("pubmed.txt"); tf.writeFile(textFileName); msg += "\nDownloaded content is in " + textFileName + "."; } catch (FileException&) { } } throw FileException(msg); } // // Get the root element // QDomElement rootElement = dom.documentElement(); if (rootElement.tagName().toLower() == "error") { const QString msg = ("ERROR retrienving data. Is PubMed ID " + pubMedID + " valid?\n"); throw FileException(msg); } else if (rootElement.tagName() != "PubmedArticleSet") { const QString msg("Root element is " + rootElement.tagName() + " but should be PubmedArticleSet"); throw FileException(msg); } QDomNode node = rootElement.firstChild(); if (node.hasChildNodes() == false) { const QString msg = "ERROR retrienving data (root element has no children).\n" "Is PubMed ID " + pubMedID + " valid?\n"; throw FileException(msg); } // // Loop through children // while (node.isNull() == false) { // // Convert to element // QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (DebugControl::getDebugOn()) { std::cout << "Element is: " << elem.tagName().toAscii().constData() << std::endl; } if (elem.tagName() == "PubmedArticle") { processPubMedArticleChildren(node.firstChild()); } } // // next sibling // node = node.nextSibling(); } if (journalYear.isEmpty() == false) { journalTitle += (" " + journalYear + ";"); } if (journalVolume.isEmpty() == false) { journalTitle += (" " + journalVolume + ":"); } if (journalPages.isEmpty() == false) { journalTitle += journalPages; } } /** * process the PubMedArticle child. */ void PubMedArticleFile::processPubMedArticleChildren(QDomNode node) throw (FileException) { // // Loop through children // while (node.isNull() == false) { // // Convert to element // QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (DebugControl::getDebugOn()) { std::cout << "PubMedArticle child is: " << elem.tagName().toAscii().constData() << std::endl; } if (elem.tagName() == "MedlineCitation") { processMedlineCitationChildren(node.firstChild()); } else if (elem.tagName() == "PubmedData") { processPubmedDataChildren(node.firstChild()); } } // // next sibling // node = node.nextSibling(); } } /** * process the mesh heading list children. * For more info: http://www.nlm.nih.gov/bsd/licensee/elements_descriptions.html#meshheadinglist */ void PubMedArticleFile::processMeshHeadingListChildren(QDomNode node) throw (FileException) { // // Loop through children // while (node.isNull() == false) { // // Convert to element // QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (DebugControl::getDebugOn()) { std::cout << "MeshHeadingList child is: " << elem.tagName().toAscii().constData() << std::endl; } if (elem.tagName() == "MeshHeading") { processMeshHeadingChildren(node.firstChild()); } } // // next sibling // node = node.nextSibling(); } } /** * process the mesh heading children. * For more info: http://www.nlm.nih.gov/bsd/licensee/elements_descriptions.html#meshheadinglist */ void PubMedArticleFile::processMeshHeadingChildren(QDomNode node) throw (FileException) { QString descriptor; QString qualifier; bool descriptorValid = false; bool qualifierValid = false; // // Loop through children // while (node.isNull() == false) { // // Convert to element // QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (DebugControl::getDebugOn()) { std::cout << "MeshHeading child is: " << elem.tagName().toAscii().constData() << std::endl; } if (elem.tagName() == "DescriptorName") { const QString majorTopicYN = elem.attribute("MajorTopicYN"); descriptor = elem.text(); if (majorTopicYN == "Y") { descriptorValid = true; } } else if (elem.tagName() == "QualifierName") { const QString majorTopicYN = elem.attribute("MajorTopicYN"); if (majorTopicYN == "Y") { if (qualifier.isEmpty() == false) { qualifier += ", "; } qualifier += elem.text(); qualifierValid = true; } } } // // next sibling // node = node.nextSibling(); } if (descriptor.isEmpty() == false) { if (qualifierValid) { if (medicalSubjectHeadings.isEmpty() == false) { medicalSubjectHeadings += "; "; } medicalSubjectHeadings += (descriptor + ": " + qualifier); } else if (descriptorValid) { if (medicalSubjectHeadings.isEmpty() == false) { medicalSubjectHeadings += "; "; } medicalSubjectHeadings += descriptor; } } } /** * process the MedlineCitation children. */ void PubMedArticleFile::processMedlineCitationChildren(QDomNode node) throw (FileException) { // // Loop through children // while (node.isNull() == false) { // // Convert to element // QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (DebugControl::getDebugOn()) { std::cout << "MedlineCitation child is: " << elem.tagName().toAscii().constData() << std::endl; } if (elem.tagName() == "Article") { processArticleChildren(node.firstChild()); } else if (elem.tagName() == "MeshHeadingList") { processMeshHeadingListChildren(node.firstChild()); } } // // next sibling // node = node.nextSibling(); } } /** * process the Article children. */ void PubMedArticleFile::processArticleChildren(QDomNode node) throw (FileException) { // // Loop through children // while (node.isNull() == false) { // // Convert to element // QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (DebugControl::getDebugOn()) { std::cout << "Article child is: " << elem.tagName().toAscii().constData() << std::endl; } if (elem.tagName() == "Journal") { processJournalChildren(node.firstChild()); } if (elem.tagName() == "Abstract") { abstractText = elem.text(); } if (elem.tagName() == "ArticleTitle") { articleTitle = elem.text(); } if (elem.tagName() == "AuthorList") { processAuthorListChildren(node.firstChild()); } if (elem.tagName() == "Pagination") { processPaginationChildren(node.firstChild()); } } // // next sibling // node = node.nextSibling(); } } /** * process the Pagination children. */ void PubMedArticleFile::processPaginationChildren(QDomNode node) throw (FileException) { // // Loop through children // while (node.isNull() == false) { // // Convert to element // QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (DebugControl::getDebugOn()) { std::cout << "Article child is: " << elem.tagName().toAscii().constData() << std::endl; } if (elem.tagName() == "MedlinePgn") { journalPages = elem.text(); } } // // next sibling // node = node.nextSibling(); } } /** * process the Journal children. */ void PubMedArticleFile::processJournalChildren(QDomNode node) throw (FileException) { // // Loop through children // while (node.isNull() == false) { // // Convert to element // QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (DebugControl::getDebugOn()) { std::cout << "Journal child is: " << elem.tagName().toAscii().constData() << std::endl; } if (elem.tagName() == "JournalIssue") { processJournalIssueChildren(node.firstChild()); } if (elem.tagName() == "Title") { journalTitle = elem.text(); } } // // next sibling // node = node.nextSibling(); } } /** * process the Journal Issue children. */ void PubMedArticleFile::processJournalIssueChildren(QDomNode node) throw (FileException) { // // Loop through children // while (node.isNull() == false) { // // Convert to element // QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (DebugControl::getDebugOn()) { std::cout << "Journal Issue child is: " << elem.tagName().toAscii().constData() << std::endl; } if (elem.tagName() == "PubDate") { processJournalPubDateChildren(node.firstChild()); } if (elem.tagName() == "Volume") { journalVolume = elem.text(); } } // // next sibling // node = node.nextSibling(); } } /** * process the Journal Pub Date children. */ void PubMedArticleFile::processJournalPubDateChildren(QDomNode node) throw (FileException) { // // Loop through children // while (node.isNull() == false) { // // Convert to element // QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (DebugControl::getDebugOn()) { std::cout << "Journal Issue child is: " << elem.tagName().toAscii().constData() << std::endl; } if (elem.tagName() == "Year") { journalYear = elem.text(); } } // // next sibling // node = node.nextSibling(); } } /** * process the AuthorList children. */ void PubMedArticleFile::processAuthorListChildren(QDomNode node) throw (FileException) { // // Loop through children // while (node.isNull() == false) { // // Convert to element // QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (DebugControl::getDebugOn()) { std::cout << "AuthorList child is: " << elem.tagName().toAscii().constData() << std::endl; } // // Get author names // if (elem.tagName() == "Author") { QString authorName; QDomNode authorNode = node.firstChild(); while (authorNode.isNull() == false) { QDomElement authorElement = authorNode.toElement(); if (authorElement.isNull() == false) { if (authorElement.tagName() == "LastName") { authorName = authorElement.text(); } else if (authorElement.tagName() == "Initials") { authorName += (" " + authorElement.text()); } } authorNode = authorNode.nextSibling(); } if (authorName.isEmpty() == false) { if (authors.isEmpty() == false) { authors += ", "; } authors += authorName; } } } // // next sibling // node = node.nextSibling(); } } /** * process the PubmedData children. */ void PubMedArticleFile::processPubmedDataChildren(QDomNode node) throw (FileException) { // // Loop through children // while (node.isNull() == false) { // // Convert to element // QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (DebugControl::getDebugOn()) { std::cout << "PubmedData child is: " << elem.tagName().toAscii().constData() << std::endl; } if (elem.tagName() == "ArticleIdList") { processArticleIdListChildren(node.firstChild()); } } // // next sibling // node = node.nextSibling(); } } /** * process the ArticleIdList children. */ void PubMedArticleFile::processArticleIdListChildren(QDomNode node) throw (FileException) { // // Loop through children // while (node.isNull() == false) { // // Convert to element // QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (DebugControl::getDebugOn()) { std::cout << "ArticleIdList child is: " << elem.tagName().toAscii().constData() << std::endl; } if (elem.tagName() == "ArticleId") { const QString idTypeValue = elem.attribute("IdType"); if (idTypeValue == "doi") { documentObjectIdentifier = elem.text(); } } } // // next sibling // node = node.nextSibling(); } } /** * returns true if the file is isEmpty (contains no data). */ bool PubMedArticleFile::empty() const { bool isEmpty = (articleTitle.isEmpty() && authors.isEmpty() && journalTitle.isEmpty() && documentObjectIdentifier.isEmpty() && abstractText.isEmpty() && pubMedID.isEmpty()); return isEmpty; } /** * read the file. */ void PubMedArticleFile::readFileData(QFile& /* file */, QTextStream& /* stream */, QDataStream& /* binStream */, QDomElement& /* rootElement */) throw (FileException) { throw FileException("Reading of PubMedArticleFile not supported.\n" "Use the retrieveArticleWithPubMedID() method."); } /** * write the file. */ void PubMedArticleFile::writeFileData(QTextStream& /* stream */, QDataStream& /* binStream */, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException) { throw FileException("Writing of PubMedArticleFile not supported."); } caret-5.6.4~dfsg.1.orig/caret_files/ProbabilisticAtlasFile.h0000664000175000017500000000240111572067322023562 0ustar michaelmichael #ifndef __PROBABILISTIC_ATLAS_FILE_H__ #define __PROBABILISTIC_ATLAS_FILE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "PaintFile.h" /// class for probabilistic atlas file class ProbabilisticAtlasFile : public PaintFile { public: /// Constructor ProbabilisticAtlasFile(); /// Destructor ~ProbabilisticAtlasFile(); protected: }; #endif // __PROBABILISTIC_ATLAS_FILE_H__ caret-5.6.4~dfsg.1.orig/caret_files/ProbabilisticAtlasFile.cxx0000664000175000017500000000224511572067322024143 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "ProbabilisticAtlasFile.h" #include "SpecFile.h" /** * Constructor */ ProbabilisticAtlasFile::ProbabilisticAtlasFile() : PaintFile("Probabilistic Atlas File", SpecFile::getProbabilisticAtlasFileExtension()) { } /** * Destructor */ ProbabilisticAtlasFile::~ProbabilisticAtlasFile() { } caret-5.6.4~dfsg.1.orig/caret_files/PreferencesFile.h0000664000175000017500000005135411572067322022263 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_PREFERENCES_FILE_H__ #define __VE_PREFERENCES_FILE_H__ #include "AbstractFile.h" #include "VolumeFile.h" /// This class is used to store user preferences. class PreferencesFile : public AbstractFile { public: /// class for storing user views class UserView { public: /// constructor UserView(const QString& nameIn, const float rotationIn[16], const float translationIn[3], const float scalingIn[3], const bool rotationValidIn, const bool translationValidIn, const bool scalingValidIn); /// get user view information void getViewInfo(QString& nameOut, float rotationOut[16], float translationOut[3], float scalingOut[3], bool& rotationValidOut, bool& translationValidOut, bool& scalingValidOut) const; /// get the name of the view QString getViewName() const { return name; } private: /// name of view QString name; /// rotation matrix float rotation[16]; /// translation float translation[3]; /// scaling float scaling[3]; /// rotation valid bool rotationValid; /// translation valid bool translationValid; /// scaling valid bool scalingValid; }; /// image capture type enum IMAGE_CAPTURE_TYPE { IMAGE_CAPTURE_PIXMAP = 0, IMAGE_CAPTURE_OPENGL_BUFFER = 1 }; /// Constructor PreferencesFile(); /// Destructor ~PreferencesFile(); /// clear the preferences file void clear(); /// returns true if the file is isEmpty (contains no data) bool empty() const { return false; } /// get the fmri algorithm parameters (const method) const QString getFmriAlgorithmParameters() const { return fmriParametersString; } /// set the fmri algorithm parameters void setFmriAlgorithmParameters(const QString& s); /// get the surface background color void getSurfaceBackgroundColor(unsigned char& r, unsigned char& g, unsigned char& b) const; /// set the surface background color void setSurfaceBackgroundColor(const unsigned char r, const unsigned char g, const unsigned char b); /// get the surface foreground color void getSurfaceForegroundColor(unsigned char& r, unsigned char& g, unsigned char& b) const; /// set the surface foreground color void setSurfaceForegroundColor(const unsigned char r, const unsigned char g, const unsigned char b); /// get the light position void getLightPosition(float& x, float& y, float& z) const; /// set the light position void setLightPosition(const float x, const float y, const float z); /// get the mouse speed float getMouseSpeed() const; /// set the mouse speed void setMouseSpeed(const float speed); /// add to recent spec files void addToRecentSpecFiles(const QString& specFileName, const bool writePreferencesFile); /// get the recent spec files void getRecentSpecFiles(std::vector& files) const; /// set the recent spec files void setRecentSpecFiles(const std::vector& files); /// add to recent copied spec files void addToRecentCopiedSpecFiles(const QString& specFileName, const bool writePreferencesFile); /// get the recent copied spec files (used in fmri mapper) void getRecentCopiedSpecFiles(std::vector& files) const; /// set the recent copied spec files (used in fmri mapper) void setRecentCopiedSpecFiles(const std::vector& files); /// add to recent data file directories void addToRecentDataFileDirectories(const QString& dirName, const bool writePreferencesFile); /// get the recent data file directories void getRecentDataFileDirectories(std::vector& dirs) const; /// get the recent data file directories QStringList getRecentDataFileDirectories() const; // get the test flag 1 bool getTestFlag1() const; // set the test flag 1 void setTestFlag1(const bool val); // get the test flag 2 bool getTestFlag2() const; // set the test flag 2 void setTestFlag2(const bool val); // get the OpenGL debug bool getOpenGLDebug() const; // set the OpenGL debug void setOpenGLDebug(const bool val); /// get the debug default value bool getDebugOn() const; /// set the debug default value void setDebugOn(const bool val); /// get the debug node number int getDebugNodeNumber() const; /// set the debug node number void setDebugNodeNumber(const int num); /// get the iterative update int getIterativeUpdate() const; /// set the iterative update void setIterativeUpdate(const int iter); /// get the web browser QString getWebBrowser() const { return webBrowser; } /// set the web browser void setWebBrowser(const QString wb); /// get the number of user views int getNumberOfUserViews() const { return userViews.size(); } /// get a user view const UserView* getUserView(const int viewNumber) const; /// add a user view void addUserView(const PreferencesFile::UserView& uv); /// get the image capture type IMAGE_CAPTURE_TYPE getImageCaptureType() const { return imageCaptureType; } /// set the image capture type void setImageCaptureType(const IMAGE_CAPTURE_TYPE ict); /// get the anatomy volume contrast int getAnatomyVolumeContrast() const { return anatomyVolumeContrast; } /// set the anatomy volume contrast void setAnatomyVolumeContrast(const int c); /// get the anatomy volume brightness int getAnatomyVolumeBrightness() const { return anatomyVolumeBrightness; } /// set the anatomy volume brightness void setAnatomyVolumeBrightness(const int b); /// get number of file reading threads int getNumberOfFileReadingThreads() const { return numberOfFileReadingThreads; } /// set number of file reading threads void setNumberOfFileReadingThreads(const int num) { numberOfFileReadingThreads = num; } /// get the maximum number of threads int getMaximumNumberOfThreads() const; /// set the maximum number of threads void setMaximumNumberOfThreads(const int num); /// get the number of digits right of the decimal when writing float to text files int getTextFileDigitsRightOfDecimal() { return textFileDigitsRightOfDecimal; } /// set the number of digits right of the decimal when writing float to text files void setTextFileDigitsRightOfDecimal(const int num) { textFileDigitsRightOfDecimal = num; } /// get the preferred volume file type VolumeFile::FILE_READ_WRITE_TYPE getPreferredVolumeWriteType() const { return preferredVolumeWriteType; } /// set the prefered volume file type void setPreferredVolumeWriteType(const VolumeFile::FILE_READ_WRITE_TYPE pt) { preferredVolumeWriteType = pt; } /// get the preferred file writing data type std::vector getPreferredWriteDataType() const { return preferredWriteDataType; } /// set the preferred file writing data type void setPreferredWriteDataType(const std::vector pt) { preferredWriteDataType = pt; } /// get SuMS login information void getSumsLoginInformation(QString& userName, QString& password, QString& hostName, bool& useLogin, bool& infoValid) const; /// set SuMS login information void setSumsLoginInformation(const QString& userName, const QString& password, const QString& hostName, const bool useLogin, const bool infoValid); /// get the SuMS database hosts QString getSumsDatabaseHosts() const { return sumsDatabaseHosts; } /// set the SuMS database hosts void setSumsDatabaseHosts(const QString& hosts) { sumsDatabaseHosts = hosts; } /// get the SuMS database file timeout length in seconds int getSumsDatabaseDataFileTimeout() const { return sumsDataFileTimeOut; } /// set the SuMS database file timeout length in seconds void setSumsDatabaseDataFileTimeout(const int t) { sumsDataFileTimeOut = t; } /// get the significant digits display int getSignificantDigitsDisplay() const { return significantDigitsDisplay; } /// set the significant digits display void setSignificantDigitsDisplay(const int n) { significantDigitsDisplay = n; } /// get display lists enabled bool getDisplayListsEnabled() const { return displayListsEnabled; } /// set display lists enabled void setDisplayListsEnabled(const bool b) { displayListsEnabled = b; } /// get override the random seed bool getRandomSeedOverride() const { return randomSeedOverrideFlag; } /// set override the random seed void setRandomSeedOverride(const bool b) { randomSeedOverrideFlag = b; } /// get override random seed value unsigned int getRandomSeedOverrideValue() const { return randomSeedOverrideValue; } /// set override random seed value void setRandomSeedOverrideValue(const unsigned int ui) { randomSeedOverrideValue = ui; } /// set caret tips void setCaretTips(const int tipIndex, const bool showTips); /// get caret tips void getCaretTips(int& tipIndex, bool& showTips) const; private: /// fmri mapping parameters string QString fmriParametersString; /// the user views std::vector userViews; /// the image capture type IMAGE_CAPTURE_TYPE imageCaptureType; /// surface background color unsigned char surfaceBackgroundColor[3]; /// surface foreground color unsigned char surfaceForegroundColor[3]; /// light position float lightPosition[3]; /// mouse speed multiplier float mouseSpeed; /// recent spec files std::vector recentSpecFiles; /// recent spec copied files std::vector recentCopiedSpecFiles; /// recent data file directories std::vector recentDataFileDirectories; /// web browser QString webBrowser; /// anatomy volume contrast int anatomyVolumeContrast; /// anatomy volume brightness int anatomyVolumeBrightness; /// maximum number of threads int maximumNumberOfThreads; /// number of file reading threads int numberOfFileReadingThreads; /// update debuggin stuff void updateDebugging(); /// the number of digits right of the decimal when writing float to text files int textFileDigitsRightOfDecimal; /// preferred data write type for files std::vector preferredWriteDataType; /// SuMS user name QString sumsUserName; /// SuMS password QString sumsPassWord; /// SuMS host name QString sumsHostName; /// SuMS use login bool sumsLoginWithUserNameAndPassWord; /// SuMS user information valid bool sumsUserInfoValid; /// additional SuMS database host QString sumsDatabaseHosts; /// SuMS data file timeout (seconds) int sumsDataFileTimeOut; /// significant digits display int significantDigitsDisplay; /// display list enabled bool displayListsEnabled; /// random seed override bool randomSeedOverrideFlag; /// random seed override value unsigned int randomSeedOverrideValue; /// index of current tip int caretTipIndex; /// caret tips enabled bool caretTipsEnabled; /// preferred volume write type VolumeFile::FILE_READ_WRITE_TYPE preferredVolumeWriteType; /// Read the preference file data void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException); /// Write the preference file data void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException); static const QString tagSurfaceBackgroundColor; static const QString tagSurfaceForegroundColor; static const QString tagMouseSpeed; static const QString tagLightPosition; static const QString tagRecentSpecFiles; static const QString tagRecentCopiedSpecFiles; static const QString tagRecentDataFileDirectories; static const QString tagOpenGLDebugOn; static const QString tagDebugOn; static const QString tagTestFlag1; static const QString tagTestFlag2; static const QString tagDebugNodeNumber; static const QString tagIterativeUpdate; static const QString tagWebBrowser; static const QString tagImageCaptureType; static const QString tagUserViewMatrix; static const QString tagAnatomyVolumeBrightness; static const QString tagAnatomyVolumeContrast; static const QString tagMaximumNumberOfThreads; static const QString tagNumberOfFileReadingThreads; static const QString tagSpeechEnabled; static const QString tagFloatDigitsRightOfDecimal; static const QString tagPreferredWriteDataType; static const QString tagSumsLoginData; static const QString tagSumsDatabaseHosts; static const QString tagSumsDataFileTimeout; static const QString tagSignificantDigits; static const QString tagDisplayListsEnabled; static const QString tagRandomSeedOverride; static const QString tagPreferredVolumeWriteType; static const QString tagCaretTips; static const QString tagFmriParameters; static const QString tagFmriAlgorithm; static const QString tagFmriAvgVoxelNeighbors; static const QString tagFmriMaxVoxelNeighbors; static const QString tagFmriStrongestVoxelNeighbors; static const QString tagFmriGaussNeighbors; static const QString tagFmriGaussSigmaNorm; static const QString tagFmriGaussSigmaTang; static const QString tagFmriGaussNormBelow; static const QString tagFmriGaussNormAbove; static const QString tagFmriGaussTang; static const QString tagFmriBfMaxDist; static const QString tagFmriBfSplat; }; #endif // __VE_PREFERENCES_FILE_H__ #ifdef __PREFERENCES_FILE_MAIN__ const QString PreferencesFile::tagSurfaceBackgroundColor = "tag-surface-background-color"; const QString PreferencesFile::tagSurfaceForegroundColor = "tag-surface-foreground-color"; const QString PreferencesFile::tagMouseSpeed = "tag-mouse-speed"; const QString PreferencesFile::tagLightPosition = "tag-light-position"; const QString PreferencesFile::tagRecentSpecFiles = "tag-recent-spec-files"; const QString PreferencesFile::tagRecentCopiedSpecFiles = "tag-recent-copied-spec-files"; const QString PreferencesFile::tagRecentDataFileDirectories = "tag-recent-data-file-directories"; const QString PreferencesFile::tagTestFlag1 = "tag-flag-1"; const QString PreferencesFile::tagTestFlag2 = "tag-flag-2"; const QString PreferencesFile::tagOpenGLDebugOn = "tag-opengl-debug-on"; const QString PreferencesFile::tagDebugOn = "tag-debug-on"; const QString PreferencesFile::tagDebugNodeNumber = "tag-debug-node"; const QString PreferencesFile::tagIterativeUpdate = "tag-iterative-update"; const QString PreferencesFile::tagWebBrowser = "tag-web-browser"; const QString PreferencesFile::tagImageCaptureType = "tag-image-capture-type"; const QString PreferencesFile::tagUserViewMatrix = "tag-user-view-matrix"; const QString PreferencesFile::tagAnatomyVolumeBrightness = "tag-anatomy-volume-brightness"; const QString PreferencesFile::tagAnatomyVolumeContrast = "tag-anatomy-volume-contrast"; const QString PreferencesFile::tagMaximumNumberOfThreads = "tag-maximum-number-of-threads"; const QString PreferencesFile::tagNumberOfFileReadingThreads = "tag-number-of-file-reading-threads"; const QString PreferencesFile::tagSpeechEnabled = "tag-speech-enabled"; const QString PreferencesFile::tagFloatDigitsRightOfDecimal = "tag-float-digits-right-of-decimal"; const QString PreferencesFile::tagPreferredWriteDataType = "tag-preferred-data-type"; const QString PreferencesFile::tagSumsLoginData = "tag-sums-login-data"; const QString PreferencesFile::tagSumsDatabaseHosts = "tag-sums-database-hosts"; const QString PreferencesFile::tagSumsDataFileTimeout = "tag-sums-data-file-timeout"; const QString PreferencesFile::tagSignificantDigits = "tag-significant-digits"; const QString PreferencesFile::tagDisplayListsEnabled = "tag-display-lists-enabled"; const QString PreferencesFile::tagRandomSeedOverride = "tag-random-seed"; const QString PreferencesFile::tagPreferredVolumeWriteType = "tag-volume-write-type"; const QString PreferencesFile::tagCaretTips = "tag-caret-tips"; const QString PreferencesFile::tagFmriParameters = "tag-fmri-parameters"; const QString PreferencesFile::tagFmriAlgorithm = "tag-fmri-algorithm"; const QString PreferencesFile::tagFmriAvgVoxelNeighbors = "tag-fmri-av-neighbors"; const QString PreferencesFile::tagFmriMaxVoxelNeighbors = "tag-fmri-mv-neighbors"; const QString PreferencesFile::tagFmriStrongestVoxelNeighbors = "tag-fmri-sv-neighbors"; const QString PreferencesFile::tagFmriGaussNeighbors = "tag-fmri-gauss-algorithm-neighbors"; const QString PreferencesFile::tagFmriGaussSigmaNorm = "tag-fmri-gauss-algorithm-sigma-norm"; const QString PreferencesFile::tagFmriGaussSigmaTang = "tag-fmri-gauss-algorithm-sigma-tang"; const QString PreferencesFile::tagFmriGaussNormBelow = "tag-fmri-gauss-algorithm-norm-below"; const QString PreferencesFile::tagFmriGaussNormAbove = "tag-fmri-gauss-algorithm-norm-above"; const QString PreferencesFile::tagFmriGaussTang = "tag-fmri-gauss-algorithm-tang"; const QString PreferencesFile::tagFmriBfMaxDist = "tag-fmri-bf-algorithm-max-dist"; const QString PreferencesFile::tagFmriBfSplat = "tag-fmri-bf-algorithm-splat"; #endif // __PREFERENCES_FILE_MAIN__ caret-5.6.4~dfsg.1.orig/caret_files/PreferencesFile.cxx0000664000175000017500000010766311572067322022643 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #define __PREFERENCES_FILE_MAIN__ #include "PreferencesFile.h" #undef __PREFERENCES_FILE_MAIN__ #include "DebugControl.h" #include "GaussianComputation.h" #include "SpecFile.h" #include "StringUtilities.h" #include "SystemUtilities.h" /** * The constructor. */ PreferencesFile::PreferencesFile() : AbstractFile("Preferences File", SpecFile::getPreferencesFileExtension()) { clear(); } /** * Thre destructor. */ PreferencesFile::~PreferencesFile() { clear(); } /** * Clear this file's contents. */ void PreferencesFile::clear() { clearAbstractFile(); fmriParametersString = ""; surfaceBackgroundColor[0] = 0; surfaceBackgroundColor[1] = 0; surfaceBackgroundColor[2] = 0; surfaceForegroundColor[0] = 255; surfaceForegroundColor[1] = 255; surfaceForegroundColor[2] = 255; lightPosition[0] = 0.0; lightPosition[1] = 0.0; lightPosition[2] = 1000.0; mouseSpeed = 1.0; anatomyVolumeBrightness = 0; anatomyVolumeContrast = 0; webBrowser = ""; recentSpecFiles.clear(); recentCopiedSpecFiles.clear(); recentDataFileDirectories.clear(); significantDigitsDisplay = 1; userViews.clear(); sumsUserName = ""; sumsHostName = ""; sumsPassWord = ""; sumsLoginWithUserNameAndPassWord = false; sumsUserInfoValid = false; sumsDatabaseHosts = ""; sumsDataFileTimeOut = 600; //maximumNumberOfThreads = SystemUtilities::getNumberOfProcessors(); maximumNumberOfThreads = 0; numberOfFileReadingThreads = 1; #ifdef Q_OS_WIN32 maximumNumberOfThreads = 1; #endif #ifdef Q_OS_MACX maximumNumberOfThreads = 1; #endif #ifdef Q_OS_LINUX maximumNumberOfThreads = 1; #endif imageCaptureType = IMAGE_CAPTURE_OPENGL_BUFFER; #ifdef Q_OS_WIN32 imageCaptureType = IMAGE_CAPTURE_PIXMAP; #endif // Q_OS_WIN32 #ifdef Q_OS_MACX imageCaptureType = IMAGE_CAPTURE_PIXMAP; #endif // Q_OS_MACX textFileDigitsRightOfDecimal = 6; std::vector fileFormats; std::vector fileFormatNames; AbstractFile::getFileFormatTypesAndNames(fileFormats, fileFormatNames); preferredWriteDataType.resize(fileFormats.size()); std::fill(preferredWriteDataType.begin(), preferredWriteDataType.end(), AbstractFile::FILE_FORMAT_XML_GZIP_BASE64); // // Default display lists off since they blow away the X-server on Linux with // Mesa OpenGL libraries. // #ifdef Q_MAC_OSX displayListsEnabled = true; #else displayListsEnabled = false; #endif randomSeedOverrideFlag = false; randomSeedOverrideValue = 1; preferredVolumeWriteType = VolumeFile::FILE_READ_WRITE_TYPE_NIFTI_GZIP; caretTipIndex = 0; caretTipsEnabled = false; } /** * get the surface background color */ void PreferencesFile::getSurfaceBackgroundColor(unsigned char& r, unsigned char& g, unsigned char& b) const { r = surfaceBackgroundColor[0]; g = surfaceBackgroundColor[1]; b = surfaceBackgroundColor[2]; } /** * set the surface background color */ void PreferencesFile::setSurfaceBackgroundColor(const unsigned char r, const unsigned char g, const unsigned char b) { surfaceBackgroundColor[0] = r; surfaceBackgroundColor[1] = g; surfaceBackgroundColor[2] = b; setModified(); } /** * get the surface foreground color */ void PreferencesFile::getSurfaceForegroundColor(unsigned char& r, unsigned char& g, unsigned char& b) const { r = surfaceForegroundColor[0]; g = surfaceForegroundColor[1]; b = surfaceForegroundColor[2]; } /** * set the surface foreground color */ void PreferencesFile::setSurfaceForegroundColor(const unsigned char r, const unsigned char g, const unsigned char b) { surfaceForegroundColor[0] = r; surfaceForegroundColor[1] = g; surfaceForegroundColor[2] = b; setModified(); } /** * get the light position */ void PreferencesFile::getLightPosition(float& x, float& y, float& z) const { x = lightPosition[0]; y = lightPosition[1]; z = lightPosition[2]; } /** * set the light position */ void PreferencesFile::setLightPosition(const float x, const float y, const float z) { lightPosition[0] = x; lightPosition[1] = y; lightPosition[2] = z; setModified(); } /** * get the mouse speed */ float PreferencesFile::getMouseSpeed() const { return mouseSpeed; } /** * set the mouse speed */ void PreferencesFile::setMouseSpeed(const float speed) { mouseSpeed = speed; setModified(); } /** * add to recent spec files. */ void PreferencesFile::addToRecentSpecFiles(const QString& specFileName, const bool writePreferencesFile) { int foundIndex = -1; for (unsigned int i = 0; i < recentSpecFiles.size(); i++) { if (recentSpecFiles[i] == specFileName) { if (i == 0) { // name is last file - do not need to do anything return; } foundIndex = i; break; } } // // Make file just opened the first file.. // std::vector filesOut; filesOut.push_back(specFileName); for (int j = 0; j < static_cast(recentSpecFiles.size()); j++) { if (j != foundIndex) { filesOut.push_back(recentSpecFiles[j]); } if (filesOut.size() >= 20) { break; } } recentSpecFiles = filesOut; if (writePreferencesFile) { if (getFileName().isEmpty() == false) { try { writeFile(getFileName()); } catch(FileException& e) { std::cerr << "Error writing preferences file (" << getFileName().toAscii().constData() << "): " << e.whatQString().toAscii().constData() << "\n"; } } } } /** * get the recent spec files */ void PreferencesFile::getRecentSpecFiles(std::vector& files) const { files = recentSpecFiles; } /** * set the recent spec files */ void PreferencesFile::setRecentSpecFiles(const std::vector& files) { recentSpecFiles = files; setModified(); } /** * add to recent data file directories. */ void PreferencesFile::addToRecentDataFileDirectories(const QString& dirName, const bool writePreferencesFile) { int foundIndex = -1; for (unsigned int i = 0; i < recentDataFileDirectories.size(); i++) { if (recentDataFileDirectories[i] == dirName) { if (i == 0) { // name is last file - do not need to do anything return; } foundIndex = i; break; } } // // Make file just opened the first file.. // std::vector filesOut; filesOut.push_back(dirName); for (int j = 0; j < static_cast(recentDataFileDirectories.size()); j++) { if (j != foundIndex) { filesOut.push_back(recentDataFileDirectories[j]); } if (filesOut.size() >= 20) { break; } } recentDataFileDirectories = filesOut; if (writePreferencesFile) { if (getFileName().isEmpty() == false) { try { writeFile(getFileName()); } catch(FileException& /*e*/) { } } } } /** * get the recent data file directories. */ void PreferencesFile::getRecentDataFileDirectories(std::vector& dirs) const { dirs = recentDataFileDirectories; } /** * get the recent data file directories. */ QStringList PreferencesFile::getRecentDataFileDirectories() const { QStringList sl; for (unsigned int i = 0; i < recentDataFileDirectories.size(); i++) { sl << recentDataFileDirectories[i]; } return sl; } /** * add to recent copied spec files. */ void PreferencesFile::addToRecentCopiedSpecFiles(const QString& specFileName, const bool writePreferencesFile) { int foundIndex = -1; for (unsigned int i = 0; i < recentCopiedSpecFiles.size(); i++) { if (recentCopiedSpecFiles[i] == specFileName) { if (i == 0) { // name is last file - do not need to do anything return; } foundIndex = i; break; } } // // Make file just opened the first file.. // std::vector filesOut; filesOut.push_back(specFileName); for (int j = 0; j < static_cast(recentCopiedSpecFiles.size()); j++) { if (j != foundIndex) { filesOut.push_back(recentCopiedSpecFiles[j]); } if (filesOut.size() >= 20) { break; } } recentCopiedSpecFiles = filesOut; if (writePreferencesFile) { if (getFileName().isEmpty() == false) { try { writeFile(getFileName()); } catch(FileException& /*e*/) { } } } } /** * get the recent copied spec files */ void PreferencesFile::getRecentCopiedSpecFiles(std::vector& files) const { files = recentCopiedSpecFiles; } /** * set the recent copied spec files */ void PreferencesFile::setRecentCopiedSpecFiles(const std::vector& files) { recentCopiedSpecFiles = files; setModified(); } /** * get the test flag 1 default value */ bool PreferencesFile::getTestFlag1() const { return DebugControl::getTestFlag1(); } /** * set the test flag 1 value */ void PreferencesFile::setTestFlag1(const bool val) { DebugControl::setTestFlag1(val); setModified(); } /** * get the test flag 2 default value */ bool PreferencesFile::getTestFlag2() const { return DebugControl::getTestFlag2(); } /** * set the test flag 2 value */ void PreferencesFile::setTestFlag2(const bool val) { DebugControl::setTestFlag2(val); setModified(); } /** * get the OpenGL debug. */ bool PreferencesFile::getOpenGLDebug() const { return DebugControl::getOpenGLDebugOn(); } /** * set the OpenGL debug. */ void PreferencesFile::setOpenGLDebug(const bool val) { DebugControl::setOpenGLDebugOn(val); setModified(); } /** * get the debug default value */ bool PreferencesFile::getDebugOn() const { return DebugControl::getDebugOn(); } /** * set the debug default value */ void PreferencesFile::setDebugOn(const bool val) { DebugControl::setDebugOn(val); setModified(); } /** * get the debug node number */ int PreferencesFile::getDebugNodeNumber() const { return DebugControl::getDebugNodeNumber(); } /** * set the debug node number */ void PreferencesFile::setDebugNodeNumber(const int num) { DebugControl::setDebugNodeNumber(num); setModified(); } /** * get the iterative update */ int PreferencesFile::getIterativeUpdate() const { return DebugControl::getIterativeUpdate(); } /** * set the iterative update */ void PreferencesFile::setIterativeUpdate(const int iter) { DebugControl::setIterativeUpdate(iter); setModified(); } /** * get a user view. */ const PreferencesFile::UserView* PreferencesFile::getUserView(const int viewNumber) const { if ((viewNumber >= 0) && (viewNumber < getNumberOfUserViews())) { return &userViews[viewNumber]; } return NULL; } /** * add a user view. */ void PreferencesFile::addUserView(const PreferencesFile::UserView& uv) { userViews.push_back(uv); setModified(); } /** * set the web browser. */ void PreferencesFile::setWebBrowser(const QString wb) { webBrowser = wb; setModified(); } /** * set the image capture type. */ void PreferencesFile::setImageCaptureType(const IMAGE_CAPTURE_TYPE ict) { imageCaptureType = ict; setModified(); } /** * set the anatomy volume contrast. */ void PreferencesFile::setAnatomyVolumeContrast(const int c) { anatomyVolumeContrast = c; setModified(); } /** * set the anatomy volume brightness. */ void PreferencesFile::setAnatomyVolumeBrightness(const int b) { anatomyVolumeBrightness = b; setModified(); } /** * get the maximum number of threads. */ int PreferencesFile::getMaximumNumberOfThreads() const { //if (DebugControl::getDebugOn()) { return maximumNumberOfThreads; //} //return 1; } /** * Set the maximum number of threads. */ void PreferencesFile::setMaximumNumberOfThreads(int numThreads) { this->maximumNumberOfThreads = numThreads; } /** * get SuMS login information. */ void PreferencesFile::getSumsLoginInformation(QString& userName, QString& passWord, QString& hostName, bool& useLogin, bool& infoValid) const { userName = sumsUserName; passWord = sumsPassWord; hostName = sumsHostName; useLogin = sumsLoginWithUserNameAndPassWord; infoValid = sumsUserInfoValid; } /** * set SuMS login information. */ void PreferencesFile::setSumsLoginInformation(const QString& userName, const QString& passWord, const QString& hostName, const bool useLogin, const bool infoValid) { sumsUserName = userName; sumsPassWord = passWord; sumsHostName = hostName; sumsLoginWithUserNameAndPassWord = useLogin; sumsUserInfoValid = infoValid; } /** * set caret tips. */ void PreferencesFile::setCaretTips(const int tipIndex, const bool showTips) { caretTipIndex = tipIndex; caretTipsEnabled = showTips; } /** * get caret tips. */ void PreferencesFile::getCaretTips(int& tipIndex, bool& showTips) const { tipIndex = caretTipIndex; showTips = caretTipsEnabled; } /** * set the fmri algorithm parameters. */ void PreferencesFile::setFmriAlgorithmParameters(const QString& s) { fmriParametersString = s; } /** * Read the preferences file's data. */ void PreferencesFile::readFileData(QFile& /*file*/, QTextStream& stream, QDataStream&, QDomElement& /* rootElement */) throw (FileException) { // // Clear out version_id's since this file is frequentyly written and does not need // a version_id. // setHeaderTag(AbstractFile::headerTagVersionID, ""); QString tag, value; QString fileNameSeparatorCharacter(" "); while(stream.atEnd() == false) { readTagLine(stream, tag, value); if (tag.isEmpty() == false) { if (tag == tagSurfaceBackgroundColor) { std::vector tokens; StringUtilities::token(value, " ", tokens); if (tokens.size() >= 3) { surfaceBackgroundColor[0] = tokens[0].toInt(); surfaceBackgroundColor[1] = tokens[1].toInt(); surfaceBackgroundColor[2] = tokens[2].toInt(); } } else if (tag == tagFileVersion) { if (value.isEmpty() == false) { const int versionNumber = StringUtilities::toInt(value); switch (versionNumber) { case 1: fileNameSeparatorCharacter = "*"; break; default: fileNameSeparatorCharacter = " "; break; } } } else if (tag == tagSurfaceForegroundColor) { std::vector tokens; StringUtilities::token(value, " ", tokens); if (tokens.size() >= 3) { surfaceForegroundColor[0] = tokens[0].toInt(); surfaceForegroundColor[1] = tokens[1].toInt(); surfaceForegroundColor[2] = tokens[2].toInt(); } } else if (tag == tagMouseSpeed) { mouseSpeed = value.toFloat(); } else if (tag == tagLightPosition) { std::vector tokens; StringUtilities::token(value, " ", tokens); if (tokens.size() >= 3) { lightPosition[0] = tokens[0].toFloat(); lightPosition[1] = tokens[1].toFloat(); lightPosition[2] = tokens[2].toFloat(); } } else if ((tag == tagRecentSpecFiles) || (tag == "recent-spec-files")) { StringUtilities::token(value, fileNameSeparatorCharacter, recentSpecFiles); } else if (tag == tagRecentCopiedSpecFiles) { StringUtilities::token(value, fileNameSeparatorCharacter, recentCopiedSpecFiles); } else if (tag == tagRecentDataFileDirectories) { StringUtilities::token(value, fileNameSeparatorCharacter, recentDataFileDirectories); } else if (tag == tagDebugOn) { if (value == "true") { setDebugOn(true); } else if (value == "false") { setDebugOn(false); } } else if (tag == tagDebugNodeNumber) { setDebugNodeNumber(value.toInt()); } else if (tag == tagDisplayListsEnabled) { setDisplayListsEnabled(value == "true"); } else if (tag == tagTestFlag1) { if (value == "true") { setTestFlag1(true); } else if (value == "false") { setTestFlag1(false); } } else if (tag == tagTestFlag2) { if (value == "true") { setTestFlag2(true); } else if (value == "false") { setTestFlag2(false); } } else if (tag == tagOpenGLDebugOn) { if (value == "true") { setOpenGLDebug(true); } else if (value == "false") { setOpenGLDebug(false); } } else if (tag == tagIterativeUpdate) { setIterativeUpdate(value.toInt()); } else if (tag == tagWebBrowser) { webBrowser = value; if (webBrowser == tagWebBrowser) { webBrowser = ""; } } else if (tag == tagImageCaptureType) { imageCaptureType = static_cast(QString(value).toInt()); } else if (tag == tagUserViewMatrix) { std::vector tokens; StringUtilities::token(value, " ", tokens); if (tokens.size() == 17) { QString name = StringUtilities::replace(tokens[0], '~', ' '); float matrix[16]; for (int i = 0; i < 16; i++) { matrix[i] = QString(tokens[i+1]).toFloat(); } const float t[3] = { 0.0, 0.0, 0.0 }; const float s[3] = { 1.0, 1.0, 1.0 }; UserView uv(name, matrix, t, s, true, false, false); addUserView(uv); } else if (tokens.size() >= 25) { QString name = StringUtilities::replace(tokens[0], '~', ' '); float matrix[16]; for (int i = 0; i < 16; i++) { matrix[i] = QString(tokens[i+1]).toFloat(); } float trans[3]; for (int i = 0; i < 3; i++) { trans[i] = QString(tokens[i+17]).toFloat(); } float scale[3]; scale[0] = QString(tokens[20]).toFloat(); scale[1] = QString(tokens[21]).toFloat(); scale[2] = QString(tokens[22]).toFloat(); const bool matrixValid = (tokens[23][0] == 'T'); const bool transValid = (tokens[24][0] == 'T'); const bool scaleValid = (tokens[25][0] == 'T'); UserView uv(name, matrix, trans, scale, matrixValid, transValid, scaleValid); addUserView(uv); } else if (tokens.size() >= 23) { QString name = StringUtilities::replace(tokens[0], '~', ' '); float matrix[16]; for (int i = 0; i < 16; i++) { matrix[i] = QString(tokens[i+1]).toFloat(); } float trans[3]; for (int i = 0; i < 3; i++) { trans[i] = QString(tokens[i+17]).toFloat(); } const float s = QString(tokens[20]).toFloat(); const float scale[3] = { s, s, s }; const bool matrixValid = (tokens[21][0] == 'T'); const bool transValid = (tokens[22][0] == 'T'); const bool scaleValid = (tokens[23][0] == 'T'); UserView uv(name, matrix, trans, scale, matrixValid, transValid, scaleValid); addUserView(uv); } } else if (tag == tagAnatomyVolumeBrightness) { setAnatomyVolumeBrightness(value.toInt()); } else if (tag == tagAnatomyVolumeContrast) { setAnatomyVolumeContrast(value.toInt()); } else if (tag == tagMaximumNumberOfThreads) { setMaximumNumberOfThreads(StringUtilities::toInt(value)); setMaximumNumberOfThreads(1); } else if (tag == tagNumberOfFileReadingThreads) { setNumberOfFileReadingThreads(value.toInt()); } else if (tag == tagSpeechEnabled) { // obsolete tag so ignore it } else if (tag == tagSumsLoginData) { std::vector tokens; StringUtilities::token(value, " ", tokens); if (tokens.size() >= 1) { if (tokens[0] == "true") { sumsUserInfoValid = true; } else { sumsUserInfoValid = false; } } if (tokens.size() >= 2) { if (tokens[1] == "true") { sumsLoginWithUserNameAndPassWord = true; } else { sumsLoginWithUserNameAndPassWord = false; } } if (tokens.size() >= 3) { sumsHostName = tokens[2]; } if (tokens.size() >= 4) { sumsUserName = tokens[3]; } if (tokens.size() >= 5) { sumsPassWord = tokens[4]; } } else if (tag == tagSumsDatabaseHosts) { sumsDatabaseHosts = value; } else if (tag == tagSumsDataFileTimeout) { sumsDataFileTimeOut = value.toInt(); } else if (tag == tagFloatDigitsRightOfDecimal) { setTextFileDigitsRightOfDecimal(StringUtilities::toInt(value)); } else if (tag == tagSignificantDigits) { setSignificantDigitsDisplay(StringUtilities::toInt(value)); } else if (tag == tagRandomSeedOverride) { std::vector tokens; StringUtilities::token(value, " ", tokens); if (tokens.size() >= 2) { randomSeedOverrideFlag = (tokens[0] == "true"); randomSeedOverrideValue = QString(tokens[1]).toUInt(); } } else if (tag == tagCaretTips) { std::vector tokens; StringUtilities::token(value, " ", tokens); if (tokens.size() >= 2) { caretTipsEnabled = (tokens[0] == "true"); caretTipIndex = tokens[1].toInt(); } } else if (tag == tagPreferredVolumeWriteType) { preferredVolumeWriteType = VolumeFile::FILE_READ_WRITE_TYPE_AFNI; if (value == "AFNI") { preferredVolumeWriteType = VolumeFile::FILE_READ_WRITE_TYPE_AFNI; } else if (value == "ANALYZE") { preferredVolumeWriteType = VolumeFile::FILE_READ_WRITE_TYPE_ANALYZE; } else if (value == "NIFTI") { preferredVolumeWriteType = VolumeFile::FILE_READ_WRITE_TYPE_NIFTI; } else if (value == "NIFTI_GZIP") { preferredVolumeWriteType = VolumeFile::FILE_READ_WRITE_TYPE_NIFTI_GZIP; } else if (value == "SPM") { preferredVolumeWriteType = VolumeFile::FILE_READ_WRITE_TYPE_SPM_OR_MEDX; } else if (value == "WUNIL") { preferredVolumeWriteType = VolumeFile::FILE_READ_WRITE_TYPE_WUNIL; } } else if (tag == tagFmriParameters) { fmriParametersString = value; } else if (tag == tagFmriAlgorithm) { fmriParametersString.append("algorithmName=" + value + ";"); } else if (tag == tagFmriAvgVoxelNeighbors) { fmriParametersString.append("averageVoxelNeighbors=" + value + ";"); } else if (tag == tagFmriMaxVoxelNeighbors) { fmriParametersString.append("maximumVoxelNeighbors=" + value + ";"); } else if (tag == tagFmriStrongestVoxelNeighbors) { fmriParametersString.append("strongestVoxelNeighbors=" + value + ";"); } else if (tag == tagFmriGaussNeighbors) { fmriParametersString.append("gaussianNeighbors=" + value + ";"); } else if (tag == tagFmriGaussSigmaNorm) { fmriParametersString.append("gaussianSigmaNorm=" + value + ";"); } else if (tag == tagFmriGaussSigmaTang) { fmriParametersString.append("gaussianSigmaTang=" + value + ";"); } else if (tag == tagFmriGaussNormBelow) { fmriParametersString.append("gaussianNormBelow=" + value + ";"); } else if (tag == tagFmriGaussNormAbove) { fmriParametersString.append("gaussianNormAbove=" + value + ";"); } else if (tag == tagFmriGaussTang) { fmriParametersString.append("gaussianTang=" + value + ";"); } else if (tag == tagFmriBfMaxDist) { fmriParametersString.append("brainFishMaxDistance=" + value + ";"); } else if (tag == tagFmriBfSplat) { fmriParametersString.append("brainFishSplatFactor=" + value + ";"); } else if (tag == tagPreferredWriteDataType) { const QStringList sl = value.split(':', QString::SkipEmptyParts); for (int i = 0; i < sl.count(); i++) { bool validFlag = false; const AbstractFile::FILE_FORMAT formatType = AbstractFile::convertFormatNameToType(sl.at(i), &validFlag); if (validFlag) { if (i < static_cast(preferredWriteDataType.size())) { preferredWriteDataType[i] = formatType; } else { preferredWriteDataType.push_back(formatType); } } else { std::cout << "Unrecognized preferences data type " << sl.at(i).toAscii().constData() << std::endl; } } } else { if (DebugControl::getDebugOn()) { std::cerr << "Unrecognized preferences file tag " << tag.toAscii().constData() << std::endl; } } } } } /** * Write the preferences file's data. */ void PreferencesFile::writeFileData(QTextStream& stream, QDataStream&, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException) { // // Clear out version_id's since this file is frequentyly written and does not need // a version_id. // setHeaderTag(AbstractFile::headerTagVersionID, ""); const QString fileNameSeparatorCharacter("*"); stream << tagFileVersion << " 1" << "\n"; stream << tagSurfaceBackgroundColor << " " << surfaceBackgroundColor[0] << " " << surfaceBackgroundColor[1] << " " << surfaceBackgroundColor[2] << "\n"; stream << tagSurfaceForegroundColor << " " << surfaceForegroundColor[0] << " " << surfaceForegroundColor[1] << " " << surfaceForegroundColor[2] << "\n"; stream << tagMouseSpeed << " " << mouseSpeed << "\n"; stream << tagLightPosition << " " << lightPosition[0] << " " << lightPosition[1] << " " << lightPosition[2] << "\n"; stream << tagRecentSpecFiles << " " << StringUtilities::combine(recentSpecFiles, fileNameSeparatorCharacter) << "\n"; stream << tagWebBrowser << " " << webBrowser << "\n"; stream << tagRecentCopiedSpecFiles << " " << StringUtilities::combine(recentCopiedSpecFiles, fileNameSeparatorCharacter) << "\n"; stream << tagRecentDataFileDirectories << " " << StringUtilities::combine(recentDataFileDirectories, fileNameSeparatorCharacter) << "\n"; stream << tagDebugOn << " "; if (getDebugOn()) stream << "true" << "\n"; else stream << "false" << "\n"; stream << tagDebugNodeNumber << " " << getDebugNodeNumber() << "\n"; if (getDisplayListsEnabled()) { stream << tagDisplayListsEnabled << " true" << "\n"; } else { stream << tagDisplayListsEnabled << " false" << "\n"; } stream << "\n"; stream << tagTestFlag1 << " "; if (getTestFlag1()) stream << "true" << "\n"; else stream << "false" << "\n"; stream << tagTestFlag2 << " "; if (getTestFlag2()) stream << "true" << "\n"; else stream << "false" << "\n"; stream << "\n"; stream << tagOpenGLDebugOn << " "; if (getOpenGLDebug()) stream << "true" << "\n"; else stream << "false" << "\n"; stream << "\n"; stream << tagIterativeUpdate << " " << getIterativeUpdate() << "\n"; stream << tagImageCaptureType << " " << imageCaptureType << "\n"; stream << tagAnatomyVolumeBrightness << " " << anatomyVolumeBrightness << "\n"; stream << tagAnatomyVolumeContrast << " " << anatomyVolumeContrast << "\n"; stream << "\n"; stream << tagMaximumNumberOfThreads << " " << maximumNumberOfThreads << "\n"; stream << "\n"; stream << tagNumberOfFileReadingThreads << " " << numberOfFileReadingThreads << "\n"; stream << "\n"; stream << tagFloatDigitsRightOfDecimal << " " << textFileDigitsRightOfDecimal << "\n"; stream << "\n"; QStringList formatNames; for (unsigned int i = 0; i < preferredWriteDataType.size(); i++) { formatNames.push_back( AbstractFile::convertFormatTypeToName(preferredWriteDataType[i])); } const QString writeStr(formatNames.join(":")); stream << tagPreferredWriteDataType << " " << writeStr << "\n"; stream << "\n"; stream << tagSumsLoginData << " "; if (sumsUserInfoValid) { stream << "true "; } else { stream << "false "; } if (sumsLoginWithUserNameAndPassWord) { stream << "true "; } else { stream << "false "; } stream << sumsHostName << " "; stream << sumsUserName << " "; stream << sumsPassWord << " "; stream << "\n"; stream << "\n"; stream << tagRandomSeedOverride << " "; if (randomSeedOverrideFlag) { stream << "true"; } else { stream << "false"; } stream << " " << randomSeedOverrideValue << "\n"; stream << tagSignificantDigits << " " << significantDigitsDisplay << "\n"; stream << tagSumsDatabaseHosts << " " << sumsDatabaseHosts << "\n"; stream << tagSumsDataFileTimeout << " " << sumsDataFileTimeOut << "\n"; stream << "\n"; stream << tagCaretTips << " " << (caretTipsEnabled ? "true" : "false") << " " << caretTipIndex << "\n"; stream << "\n"; QString volType; switch (preferredVolumeWriteType) { case VolumeFile::FILE_READ_WRITE_TYPE_RAW: volType = "IGNORE"; break; case VolumeFile::FILE_READ_WRITE_TYPE_AFNI: volType = "AFNI"; break; case VolumeFile::FILE_READ_WRITE_TYPE_ANALYZE: volType = "ANALYZE"; break; case VolumeFile::FILE_READ_WRITE_TYPE_NIFTI: volType = "NIFTI"; break; case VolumeFile::FILE_READ_WRITE_TYPE_NIFTI_GZIP: volType = "NIFTI_GZIP"; break; case VolumeFile::FILE_READ_WRITE_TYPE_SPM_OR_MEDX: volType = "SPM"; break; case VolumeFile::FILE_READ_WRITE_TYPE_WUNIL: volType = "WUNIL"; break; case VolumeFile::FILE_READ_WRITE_TYPE_UNKNOWN: volType = "IGNORE"; break; } if (volType != "IGNORE") { stream << tagPreferredVolumeWriteType << " " << volType<< "\n"; stream << "\n"; } stream << tagFmriParameters << " " << fmriParametersString << "\n"; stream << "\n"; for (int i = 0; i < getNumberOfUserViews(); i++) { QString name; float matrix[16]; float trans[3]; float scale[3]; bool matrixValid; bool transValid; bool scaleValid; const UserView* uv = getUserView(i); uv->getViewInfo(name, matrix, trans, scale, matrixValid, transValid, scaleValid); stream << tagUserViewMatrix << " " << StringUtilities::replace(name, ' ', '~'); for (int j = 0; j < 16; j++) { stream << " " << matrix[j]; } for (int j = 0; j < 3; j++) { stream << " " << trans[j]; } stream << " " << scale[0] << " " << scale[1] << " " << scale[2]; stream << " " << (matrixValid ? 'T' : 'F'); stream << " " << (transValid ? 'T' : 'F'); stream << " " << (scaleValid ? 'T' : 'F'); stream << "\n"; } } //============================================================================== /** * constructor. */ PreferencesFile::UserView::UserView(const QString& nameIn, const float rotationIn[16], const float translationIn[3], const float scalingIn[3], const bool rotationValidIn, const bool translationValidIn, const bool scalingValidIn) { name = nameIn; for (int i = 0; i < 16; i++) { rotation[i] = rotationIn[i]; } for (int i = 0; i < 3; i++) { translation[i] = translationIn[i]; scaling[i] = scalingIn[i]; } rotationValid = rotationValidIn; translationValid = translationValidIn; scalingValid = scalingValidIn; } /** * get user view information. */ void PreferencesFile::UserView::getViewInfo(QString& nameOut, float rotationOut[16], float translationOut[3], float scalingOut[3], bool& rotationValidOut, bool& translationValidOut, bool& scalingValidOut) const { nameOut = name; for (int i = 0; i < 16; i++) { rotationOut[i] = rotation[i]; } for (int i = 0; i < 3; i++) { translationOut[i] = translation[i]; scalingOut[i] = scaling[i]; } rotationValidOut = rotationValid; translationValidOut = translationValid; scalingValidOut = scalingValid; } caret-5.6.4~dfsg.1.orig/caret_files/ParamsFile.h0000664000175000017500000001657511572067322021253 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_PARAMS_FILE_H__ #define __VE_PARAMS_FILE_H__ #include #include #include "AbstractFile.h" /// Class for the Parameters File class ParamsFile : public AbstractFile { public: /// parameter map for storing parameters typedef std::map ParameterMap; /// iterator for access to ParameterMap typedef ParameterMap::const_iterator ParameterMapConstIterator; // NOTE: If you add more keys, be sure to update the clear() method // with initial values. static const QString keyComment; static const QString keyXdim; static const QString keyYdim; static const QString keyZdim; static const QString keyACx; static const QString keyACy; static const QString keyACz; static const QString keyPadded; static const QString keyCropped; static const QString keyCropMinX; static const QString keyCropMaxX; static const QString keyCropMinY; static const QString keyCropMaxY; static const QString keyCropMinZ; static const QString keyCropMaxZ; static const QString keyXmin; static const QString keyYmin; static const QString keyZmin; static const QString keyOldPadNegX; static const QString keyOldPadPosX; static const QString keyOldPadNegY; static const QString keyOldPadPosY; static const QString keyOldPadNegZ; static const QString keyOldPadPosZ; static const QString keyResolution; static const QString keyWholeXdim; static const QString keyWholeYdim; static const QString keyWholeZdim; static const QString keyWholeVolumeACx; static const QString keyWholeVolumeACy; static const QString keyWholeVolumeACz; static const QString keyCGMpeak; static const QString keyWMpeak; static const QString keyWMThreshSet; static const QString keyWMThresh; static const QString keyHem; static const QString keyValueYes; static const QString keyValueNo; private: /// storage of parameters ParameterMap params; /// get the parameter as a string bool getParameterAsString(const QString& parameterName, QString& parameterValue) const; /// read parameter file data void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException); /// write parameter file data void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException); public: /// constructor ParamsFile(); /// destructor ~ParamsFile(); /// append a parameters file to this one void append(ParamsFile& pf, QString errorMessage); /// clear the parameters void clear(); /// see if file contains no data bool empty() const { return params.empty(); } /// method to get all parameters void getAllParameters(std::vector& keys, std::vector& values) const; /// get all of the parameters ParameterMap getAllParameters() const { return params; } /// set all parameters void setAllParameters(ParameterMap pm) { params = pm; setModified(); } /// methods to get parameters as string bool getParameter(const QString& parameterName, QString& parameterValue) const; /// methods to get parameters as int bool getParameter(const QString& parameterName, int& parameterValue) const; /// methods to get parameters as float bool getParameter(const QString& parameterName, float& parameterValue) const; // methods to set parameters with string void setParameter(const QString& parameterName, const QString& parameterValue); // methods to set parameters with int void setParameter(const QString& parameterName, const int& parameterValue); // methods to set parameters with float void setParameter(const QString& parameterName, const float& parameterValue); }; #endif // __VE_PARAMS_FILE_H__ #ifdef PARAMS_FILE_DEFINE const QString ParamsFile::keyComment = "comment"; const QString ParamsFile::keyXdim = "xdim"; const QString ParamsFile::keyYdim = "ydim"; const QString ParamsFile::keyZdim = "zdim"; const QString ParamsFile::keyACx = "ACx"; const QString ParamsFile::keyACy = "ACy"; const QString ParamsFile::keyACz = "ACz"; const QString ParamsFile::keyPadded = "padded"; const QString ParamsFile::keyCropped = "cropped"; const QString ParamsFile::keyCropMinX = "CropMinX"; const QString ParamsFile::keyCropMaxX = "CropMaxX"; const QString ParamsFile::keyCropMinY = "CropMinY"; const QString ParamsFile::keyCropMaxY = "CropMaxY"; const QString ParamsFile::keyCropMinZ = "CropMinZ"; const QString ParamsFile::keyCropMaxZ = "CropMaxZ"; const QString ParamsFile::keyXmin = "Xmin"; const QString ParamsFile::keyYmin = "Ymin"; const QString ParamsFile::keyZmin = "Zmin"; const QString ParamsFile::keyOldPadNegX = "OldPadNegX"; const QString ParamsFile::keyOldPadPosX = "OldPadPosX"; const QString ParamsFile::keyOldPadNegY = "OldPadNegY"; const QString ParamsFile::keyOldPadPosY = "OldPadPosY"; const QString ParamsFile::keyOldPadNegZ = "OldPadNegZ"; const QString ParamsFile::keyOldPadPosZ = "OldPadPosZ"; const QString ParamsFile::keyResolution = "resolution"; const QString ParamsFile::keyWholeXdim = "WholeXdim"; const QString ParamsFile::keyWholeYdim = "WholeYdim"; const QString ParamsFile::keyWholeZdim = "WholeZdim"; const QString ParamsFile::keyWholeVolumeACx = "ACx_WholeVolume"; const QString ParamsFile::keyWholeVolumeACy = "ACy_WholeVolume"; const QString ParamsFile::keyWholeVolumeACz = "ACz_WholeVolume"; const QString ParamsFile::keyCGMpeak = "CGMpeak"; const QString ParamsFile::keyWMpeak = "WMpeak"; const QString ParamsFile::keyWMThreshSet = "WMThreshSet"; const QString ParamsFile::keyWMThresh = "WMThresh"; const QString ParamsFile::keyHem = "Hem"; const QString ParamsFile::keyValueYes = "yes"; const QString ParamsFile::keyValueNo = "no"; #endif // PARAMS_FILE_DEFINE caret-5.6.4~dfsg.1.orig/caret_files/ParamsFile.cxx0000664000175000017500000001560511572067322021617 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #define PARAMS_FILE_DEFINE #include "ParamsFile.h" #undef PARAMS_FILE_DEFINE #include "SpecFile.h" /** * Constructor */ ParamsFile::ParamsFile() : AbstractFile("Params File", SpecFile::getParamsFileExtension()) { clear(); } /** * Destructor */ ParamsFile::~ParamsFile() { clear(); } /** * Clear the parameters file. */ void ParamsFile::clear() { clearAbstractFile(); params.clear(); setParameter(keyComment, ""); setParameter(keyXdim, ""); setParameter(keyYdim, ""); setParameter(keyZdim, ""); setParameter(keyACx, ""); setParameter(keyACy, ""); setParameter(keyACz, ""); setParameter(keyPadded, ""); setParameter(keyCropped, ""); setParameter(keyCropMinX, ""); setParameter(keyCropMaxX, ""); setParameter(keyCropMinY, ""); setParameter(keyCropMaxY, ""); setParameter(keyCropMinZ, ""); setParameter(keyCropMaxZ, ""); setParameter(keyXmin, ""); setParameter(keyYmin, ""); setParameter(keyZmin, ""); setParameter(keyOldPadNegX, ""); setParameter(keyOldPadPosX, ""); setParameter(keyOldPadNegY, ""); setParameter(keyOldPadPosY, ""); setParameter(keyOldPadNegZ, ""); setParameter(keyOldPadPosZ, ""); setParameter(keyResolution, ""); setParameter(keyWholeXdim, ""); setParameter(keyWholeYdim, ""); setParameter(keyWholeZdim, ""); setParameter(keyWholeVolumeACx, ""); setParameter(keyWholeVolumeACy, ""); setParameter(keyWholeVolumeACz, ""); setParameter(keyCGMpeak, ""); setParameter(keyWMpeak, ""); setParameter(keyWMThreshSet, ""); clearModified(); } /** * Append a parameters file to this one. */ void ParamsFile::append(ParamsFile& pf, QString errorMessage) { errorMessage = ""; std::vector keys, values; pf.getAllParameters(keys, values); for (unsigned int i = 0; i < keys.size(); i++) { setParameter(keys[i], values[i]); } // // transfer the file's comment // appendFileComment(pf); setModified(); } /** * Get all parameters in the file. */ void ParamsFile::getAllParameters(std::vector& keys, std::vector& values) const { keys.clear(); values.clear(); for (ParameterMapConstIterator pi = params.begin(); pi != params.end(); pi++) { keys.push_back(pi->first); values.push_back(pi->second); } } /** * Get a parameter as a string. Returns false if not found. */ bool ParamsFile::getParameterAsString(const QString& parameterName, QString& parameterValue) const { parameterValue = ""; ParameterMap::const_iterator pos = params.find(parameterName); if (pos != params.end()) { parameterValue = pos->second; return true; } return false; } /** * Get a parameter as an string. Returns false if not found. */ bool ParamsFile::getParameter(const QString& parameterName, QString& parameterValue) const { parameterValue = ""; QString stringParam; if (getParameterAsString(parameterName, stringParam)) { if (stringParam.length() > 1) { if (stringParam[0] == '"') { // remove quotes stringParam = stringParam.mid(1); stringParam.resize(stringParam.length() - 1); } } parameterValue = stringParam; return true; } return false; } /** * Get a parameter as an int. Return false if not found */ bool ParamsFile::getParameter(const QString& parameterName, int& parameterValue) const { parameterValue = 0; QString stringParam; if (getParameterAsString(parameterName, stringParam)) { parameterValue = stringParam.toInt(); return true; } return false; } /** * Get a parameters as a float. Returns false if not found. */ bool ParamsFile::getParameter(const QString& parameterName, float& parameterValue) const { parameterValue = 0.0; QString stringParam; if (getParameterAsString(parameterName, stringParam)) { parameterValue = stringParam.toFloat(); return true; } return false; } /** * Set a parameter with a string. */ void ParamsFile::setParameter(const QString& parameterName, const QString& parameterValue) { setModified(); ParameterMap::iterator pos = params.find(parameterName); if (pos != params.end()) { pos->second = parameterValue; return; } params.insert(ParameterMap::value_type(parameterName, parameterValue)); } /** * Set a parameter with an int. */ void ParamsFile::setParameter(const QString& parameterName, const int& parameterValue) { setModified(); std::ostringstream str; str << parameterValue; setParameter(parameterName, str.str().c_str()); } /** * Set a parameter with a float. */ void ParamsFile::setParameter(const QString& parameterName, const float& parameterValue) { setModified(); std::ostringstream str; str << parameterValue; setParameter(parameterName, str.str().c_str()); } /** * read the parameters file's data. */ void ParamsFile::readFileData(QFile& /*file*/, QTextStream& stream, QDataStream&, QDomElement& /* rootElement */) throw (FileException) { // // Should reading data be skipped ? // if (getReadMetaDataOnlyFlag()) { return; } while (!stream.atEnd()) { QString line; readLine(stream, line); int equalsPos = line.indexOf('='); if (equalsPos != -1) { const QString key = line.mid(0, equalsPos); const QString value = line.mid(equalsPos + 1); setParameter(key, value); } } } /** * Write the parameters file's data. */ void ParamsFile::writeFileData(QTextStream& stream, QDataStream&, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException) { for (ParameterMap::iterator pos = params.begin(); pos != params.end(); pos++) { stream << pos->first << "=" << pos->second << "\n"; } } caret-5.6.4~dfsg.1.orig/caret_files/PaletteFile.h0000664000175000017500000002322511572067322021414 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_PALETTE_FILE_H__ #define __VE_PALETTE_FILE_H__ #include "AbstractFile.h" class ColorFile; class PaletteFile; // forward declaration class Palette; /// Class for storing a color in the palette. class PaletteColor { private: /// rgb components of color unsigned char colorRGB[3]; /// name of color QString colorName; /// palette file using this color PaletteFile* myPaletteFile; /// Set this palette color modified. void setModified(); public: static const QString noneColorName; static const QString missingColorName; /// constructor PaletteColor(const QString& name, const unsigned char rgb[3]); /// get rgb color components void getRGB(unsigned char rgb[3]) const; /// get name of color QString getName() const; /// set rgb color components void setRGB(const unsigned char rgb[3]); /// set name of color void setName(const QString& name); /// color is the none color bool isNoneColor() const; friend class PaletteFile; }; /// /// Class for storing an entry in the color palette. /// class PaletteEntry { private: /// index of color int colorIndex; /// scalar value float tableValue; /// Palette this entry is part of Palette* myPalette; /// set this palette entry modified void setModified(); public: /// Constructor PaletteEntry(const float value, const int colorIndexIn = -1); /// Copy contructor PaletteEntry(const PaletteEntry& pe); /// get the index of the color int getColorIndex() const { return colorIndex; } /// set the color index void setColorIndex(const int indx) { colorIndex = indx; setModified(); } /// get the scalar value float getValue() const { return tableValue; } /// set the scalar value void setValue(const float f) { tableValue = f; setModified(); } friend class PaletteFile; friend class Palette; }; /// Class for an AFNI palette. class Palette { private: /// entries in the palette std::vector paletteEntries; /// name of the palette QString paletteName; /// palette is positive only bool positiveOnly; /// PaletteFile this palette is part of PaletteFile* myPaletteFile; public: /// Constructor Palette(PaletteFile* myPaletteFileIn); /// set the palette file void setPaletteFile(PaletteFile* myPaletteFileIn) { myPaletteFile = myPaletteFileIn; } /// Copy constructor Palette(const Palette& p); /// palette has been modified void setModified(); /// Add an entry to the palette void addPaletteEntry(const float tableScalar, const QString& colorName); /// insert a palette entry void insertPaletteEntry(const int afterPaletteEntryNumber, const PaletteEntry& pe); /// remove a palette entry void removePaletteEntry(const int indx); /// get the appropriate color for a scalar value void getColor(const float scalar, const bool interpolateColorIn, bool& noneColorFlagOut, unsigned char colorOut[3]) const; /// Get the number of palette entries in this palette. int getNumberOfPaletteEntries() const { return paletteEntries.size(); } /// Get the name of this palette QString getName() const { return paletteName; } /// set the name of this palette void setName(const QString& name); /// Get an entry from this palette (const method) const PaletteEntry* getPaletteEntry(const int idx) const { return &paletteEntries[idx]; } /// Get an entry from this palette PaletteEntry* getPaletteEntry(const int idx) { return &paletteEntries[idx]; } /// Get the min and max values for this palette void getMinMax(float& minPalette, float& maxPalette) const; /// Get the positive only flag bool getPositiveOnly() const { return positiveOnly; } /// Set the positive only flag void setPositiveOnly(const bool posOnly); /// Write this palette to a file void writeFileData(QTextStream& stream) const throw (FileException); friend class paletteEntry; friend class PaletteFile; }; /// This class represents an AFNI palette file. class PaletteFile : public AbstractFile { private: /// name for gray interpolated palette static const QString grayInterpPaletteName; /// Colors from all palettes std::vector colors; /// storage for all palettes std::vector palettes; /// convert an RGB format to X color format QString convertToXColor(unsigned char rgb[3]) const; /// get the color components for a color int getColorComponents(const QString& colorName, bool& noneColorFlag, unsigned char rgb[3]) const; /// Convert from X color format bool convertFromXColor(const char* colorString, unsigned char rgb[3]) const; /// Convert a hexadecimal number to base 10 int hexToInt(char c) const; /// See if palette with specified name exists bool paletteNameExists(const QString& name); // read an PaletteFile void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException); // write an PaletteFile void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException); public: /// constructor for the PaletteFile PaletteFile(); /// destructor for the PaletteFile ~PaletteFile(); /// add the default palettes to this palette file void addDefaultPalettes(); /// add a palette to the palette file void addPalette(const Palette& pal); /// get the palette colors into a color file void getPaletteColorsUsingColorFile(ColorFile& cf) const; /// replace the palette colors using a ColorFile (update color assignments too) void replacePaletteColorsUsingColorFile(const ColorFile& cf); /// get the number of palette colors int getNumberOfPaletteColors() const { return colors.size(); } /// get a palette color PaletteColor* getPaletteColor(const int indx) { return &colors[indx]; } /// get a palette color (const method) const PaletteColor* getPaletteColor(const int indx) const { return &colors[indx]; } /// get a palette color index by name int getColorIndexFromName(const QString& name) const; /// add a color to the palette void addPaletteColor(const PaletteColor& pc); /// add a color to the palette file void addPaletteColor(const QString& name, const unsigned char rgb[3]); /// append a palette file to this one void append(PaletteFile& pf); /// clear memory void clear(); /// returns true if the file is isEmpty (contains no data) bool empty() const { return (getNumberOfPalettes() == 0); } /// get the number of palettes int getNumberOfPalettes() const { return palettes.size(); } /// get the index of the "gray interp" palette int getGrayInterPaletteIndex() const; /// get palette index from name or number (number ranges 1..N) int getPaletteIndexFromNameOrNumber(const QString& nameOrNumber) const throw (FileException); /// get a palette (const method) const Palette* getPalette(const int palNum) const { return &palettes[palNum]; } /// get a palette Palette* getPalette(const int palNum) { return &palettes[palNum]; } /// remove a palette void removePalette(const int palNum); /// write the file's memory in caret6 format to the specified name virtual QString writeFileInCaret6Format(const QString& filenameIn, Structure structure,const ColorFile* colorFileIn, const bool useCaret6ExtensionFlag) throw (FileException); }; #endif // __VE_PALETTE_FILE_H__ #ifdef __PALETTE_FILE_DEFINED__ const QString PaletteColor::noneColorName = "none"; const QString PaletteColor::missingColorName = "missing"; const QString PaletteFile::grayInterpPaletteName = "Gray_Interp"; #endif // __PALETTE_FILE_DEFINED__ caret-5.6.4~dfsg.1.orig/caret_files/PaletteFile.cxx0000664000175000017500000017123011572067322021767 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #ifdef Q_OS_WIN32 #define NOMINMAX #endif #include #include #include #include #include "ColorFile.h" #include "FileUtilities.h" #define __PALETTE_FILE_DEFINED__ #include "PaletteFile.h" #undef __PALETTE_FILE_DEFINED__ #include "SpecFile.h" // // Example of a Palette File's contents: // // ***COLORS // yellow = yellow // oran-yell = #ff9900 // oran-red = #ff4400 // dk-blue = rgbi:0.0/0.0/1.0 // lt-blue1 = #0069ff // blue-cyan = #00ccff // // ***PALETTES palette7 [7] // 1.000000 -> yellow // 0.660000 -> oran-yell // 0.330000 -> oran-red // 0.050000 -> none // -0.050000 -> dk-blue // -0.398438 -> lt-blue1 // -0.660000 -> blue-cyan // //--------------------------------------------------------------------------- /** * The constructor. */ PaletteColor::PaletteColor(const QString& name, const unsigned char rgb[3]) { myPaletteFile = NULL; setName(name); setRGB(rgb); } /** * Set this palette color modified. */ void PaletteColor::setModified() { if (myPaletteFile != NULL) { myPaletteFile->setModified(); } } /** * Get the RGB components. */ void PaletteColor::getRGB(unsigned char rgb[3]) const { rgb[0] = colorRGB[0]; rgb[1] = colorRGB[1]; rgb[2] = colorRGB[2]; } /** * Get the name. */ QString PaletteColor::getName() const { return colorName; } /** * set the RGB components. */ void PaletteColor::setRGB(const unsigned char rgb[3]) { colorRGB[0] = rgb[0]; colorRGB[1] = rgb[1]; colorRGB[2] = rgb[2]; setModified(); } /** * color is the none color. */ bool PaletteColor::isNoneColor() const { return (colorName == noneColorName); } /** * set the name. */ void PaletteColor::setName(const QString& name) { colorName = name; setModified(); } //--------------------------------------------------------------------------- // // Palette Entry Class Methods // /** * The constructor. */ PaletteEntry::PaletteEntry(const float value, const int colorIndexIn) { tableValue = value; colorIndex = colorIndexIn; myPalette = NULL; } /** * Copy contructor. */ PaletteEntry::PaletteEntry(const PaletteEntry& pe) { tableValue = pe.tableValue; colorIndex = pe.colorIndex; myPalette = NULL; } /** * set this palette entry modified. */ void PaletteEntry::setModified() { if (myPalette != NULL) { myPalette->setModified(); } } //--------------------------------------------------------------------------- // // Palette methods // /** * Palette Constructor */ Palette::Palette(PaletteFile* myPaletteFileIn) { myPaletteFile = myPaletteFileIn; positiveOnly = false; } /** * Copy constructor. */ Palette::Palette(const Palette& p) { paletteEntries = p.paletteEntries; for (int i = 0; i < static_cast(paletteEntries.size()); i++) { paletteEntries[i].myPalette = this; } paletteName = p.paletteName; positiveOnly = p.positiveOnly; myPaletteFile = p.myPaletteFile; } /** * palette has been modified. */ void Palette::setModified() { if (myPaletteFile != NULL) { myPaletteFile->setModified(); } } /** * Set the name of this palette. */ void Palette::setName(const QString& name) { paletteName = name; setModified(); } /** * Set the positive only flag for this palette. */ void Palette::setPositiveOnly(const bool posOnly) { positiveOnly = posOnly; setModified(); } /** * Return the minimum and maximum values for the palette */ void Palette::getMinMax(float& minPalette, float& maxPalette) const { if (paletteEntries.size() > 0) { maxPalette = paletteEntries[0].tableValue; minPalette = paletteEntries[paletteEntries.size() - 1].tableValue; } else { minPalette = 0.0; maxPalette = 0.0; } } /** * Add a Palette entry to the palette. */ void Palette::addPaletteEntry(const float tableScalar, const QString& colorName) { int colorIndex = -1; if (colorName.isEmpty() == false) { if (myPaletteFile != NULL) { colorIndex = myPaletteFile->getColorIndexFromName(colorName); } } if (colorIndex < 0) { if (colorName == "none") { const unsigned char none[3] = { 0xff, 0xff, 0xff }; myPaletteFile->addPaletteColor(PaletteColor("none", none)); colorIndex = myPaletteFile->getColorIndexFromName(colorName); } else { std::cout << "PALETTE FILE ERROR: color \"" << colorName.toAscii().constData() << "\" not found for palette \"" << getName().toAscii().constData() << "\"" << std::endl; return; } } PaletteEntry pe(tableScalar, colorIndex); paletteEntries.push_back(pe); const int num = getNumberOfPaletteEntries() - 1; paletteEntries[num].myPalette = this; setModified(); } /** * insert a palette entry. */ void Palette::insertPaletteEntry(const int afterPaletteEntryNumber, const PaletteEntry& pe) { paletteEntries.insert(paletteEntries.begin() + afterPaletteEntryNumber, pe); paletteEntries[afterPaletteEntryNumber + 1].myPalette = this; setModified(); } /** * remove a palette entry. */ void Palette::removePaletteEntry(const int indx) { paletteEntries.erase(paletteEntries.begin() + indx); setModified(); } /** * The Palette colors are in a range -1.0 to 1.0. "scalar" must be within * the inclusive range -1.0 to 1.0 */ void Palette::getColor(const float scalar, const bool interpolateColorIn, bool& noneColorFlagOut, unsigned char colorOut[3]) const { colorOut[0] = 0; colorOut[1] = 0; colorOut[2] = 0; if (paletteEntries.size() <= 0) return; if (myPaletteFile == NULL) return; bool interpolateColor = interpolateColorIn; if (paletteEntries.size() == 1) { interpolateColor = false; } int paletteIndex = -1; if (scalar >= paletteEntries[0].tableValue) { paletteIndex = 0; interpolateColor = false; } const int lastPalette = paletteEntries.size() - 1; if (scalar <= paletteEntries[lastPalette].tableValue) { paletteIndex = lastPalette; interpolateColor = false; } for (unsigned int i = 1; i < paletteEntries.size(); i++) { const PaletteEntry& pe = paletteEntries[i]; if (scalar > pe.tableValue) { paletteIndex = i - 1; break; } } if (paletteIndex >= 0) { const int colorIndex = paletteEntries[paletteIndex].getColorIndex(); if ((colorIndex < 0) && (colorIndex >= myPaletteFile->getNumberOfPaletteColors())) { return; } const PaletteColor* pc = myPaletteFile->getPaletteColor(colorIndex); noneColorFlagOut = pc->isNoneColor(); if (noneColorFlagOut == false) { unsigned char rgbColor[3]; pc->getRGB(rgbColor); if (interpolateColor) { float red = 0.0; float green = 0.0; float blue = 0.0; if (paletteEntries.size() == 2) { const int colorIndex1 = paletteEntries[0].getColorIndex(); unsigned char rgbColor1[3]; const PaletteColor* pc1 = myPaletteFile->getPaletteColor(colorIndex1); pc1->getRGB(rgbColor1); const int colorIndex2 = paletteEntries[1].getColorIndex(); unsigned char rgbColor2[3]; const PaletteColor* pc2 = myPaletteFile->getPaletteColor(colorIndex2); pc2->getRGB(rgbColor2); red = scalar * rgbColor1[0] + (1.0 - scalar) * rgbColor2[0]; green = scalar * rgbColor1[1] + (1.0 - scalar) * rgbColor2[1]; blue = scalar * rgbColor1[2] + (1.0 - scalar) * rgbColor2[2]; } else { const int paletteIndex2 = paletteIndex + 1; // // Cannot interpolate to the "none" color // const int colorIndex2 = paletteEntries[paletteIndex2].getColorIndex(); const PaletteColor* pc2 = myPaletteFile->getPaletteColor(colorIndex2); if (pc2->isNoneColor()) { red = rgbColor[0]; green = rgbColor[1]; blue = rgbColor[2]; } else { const float d2 = paletteEntries[paletteIndex].tableValue - scalar; const float d1 = scalar - paletteEntries[paletteIndex2].tableValue; float pct1 = 0.0; float pct2 = 0.0; const float dTable = paletteEntries[paletteIndex].tableValue - paletteEntries[paletteIndex2].tableValue; if (dTable > 0.0) { pct1 = d1 / dTable; pct2 = d2 / dTable; } unsigned char rgbColor2[3]; pc2->getRGB(rgbColor2); red = pct1 * rgbColor[0] + pct2 * rgbColor2[0]; green = pct1 * rgbColor[1] + pct2 * rgbColor2[1]; blue = pct1 * rgbColor[2] + pct2 * rgbColor2[2]; } } if (red > 255.0) red = 255.0; if (red < 0.0) red = 0.0; if (green > 255.0) green = 255.0; if (green < 0.0) green = 0.0; if (blue > 255.0) blue = 255.0; if (blue < 0.0) blue = 0.0; colorOut[0] = static_cast(red); colorOut[1] = static_cast(green); colorOut[2] = static_cast(blue); } else { colorOut[0] = rgbColor[0]; colorOut[1] = rgbColor[1]; colorOut[2] = rgbColor[2]; } } } } /** * Write the palette's data. */ void Palette::writeFileData(QTextStream& stream) const throw (FileException) { if (positiveOnly) { stream << "***PALETTES " << paletteName << " [" << paletteEntries.size() << "+]\n"; } else { stream << "***PALETTES " << paletteName << " [" << paletteEntries.size() << "]\n"; } for (unsigned int j = 0; j < paletteEntries.size(); j++) { const int indx = paletteEntries[j].getColorIndex(); if ((indx >= 0) && (indx < myPaletteFile->getNumberOfPaletteColors())) { const PaletteColor* pc = myPaletteFile->getPaletteColor(indx); stream << " " << paletteEntries[j].getValue() << " -> " << pc->getName() << "\n"; } } stream << "\n"; } //--------------------------------------------------------------------------- // // Palette File Class Methods // /** * The constructor. */ PaletteFile::PaletteFile() : AbstractFile("Palette File", SpecFile::getPaletteFileExtension()) { clear(); addDefaultPalettes(); clearModified(); } /** * get a palette color index by name. */ int PaletteFile::getColorIndexFromName(const QString& name) const { int indx = -1; const int num = getNumberOfPaletteColors(); for (int i = 0; i < num; i++) { const PaletteColor* pc = getPaletteColor(i); if (pc->getName() == name) { return i; } } return indx; } /** * Create the default palettes */ void PaletteFile::addDefaultPalettes() { const unsigned char none[3] = { 0xff, 0xff, 0xff }; addPaletteColor(PaletteColor("none", none)); const unsigned char yellow[3] = { 0xff, 0xff, 0x00 }; addPaletteColor(PaletteColor("_yellow", yellow)); const unsigned char black[3] = { 0x00, 0x00, 0x00 }; addPaletteColor(PaletteColor("_black", black)); const unsigned char orange[3] = { 0xff, 0x69, 0x00 }; addPaletteColor(PaletteColor("_orange", orange)); //---------------------------------------------------------------------- // Psych palette // if (paletteNameExists("PSYCH") == false) { const unsigned char pyell_oran[3] = { 0xff, 0xcc, 0x00 }; addPaletteColor(PaletteColor("_pyell-oran", pyell_oran)); const unsigned char poran_red[3] = { 0xff, 0x44, 0x00 }; addPaletteColor(PaletteColor("_poran-red", poran_red)); const unsigned char pblue[3] = { 0x00, 0x44, 0xff }; addPaletteColor(PaletteColor("_pblue", pblue)); const unsigned char pltblue1[3] = { 0x00, 0x69, 0xff }; addPaletteColor(PaletteColor("_pltblue1", pltblue1)); const unsigned char pltblue2[3] = { 0x00, 0x99, 0xff }; addPaletteColor(PaletteColor("_pltblue2", pltblue2)); const unsigned char pbluecyan[3] = { 0x00, 0xcc, 0xff }; addPaletteColor(PaletteColor("_pbluecyan", pbluecyan)); Palette psych(this); psych.setName("PSYCH"); psych.setPositiveOnly(false); psych.addPaletteEntry(1.00, "_yellow"); psych.addPaletteEntry(0.75, "_pyell-oran"); psych.addPaletteEntry(0.50, "_orange"); psych.addPaletteEntry(0.25, "_poran-red"); psych.addPaletteEntry(0.05, "none"); psych.addPaletteEntry(-0.05, "_pblue"); psych.addPaletteEntry(-0.25, "_pltblue1"); psych.addPaletteEntry(-0.50, "_pltblue2"); psych.addPaletteEntry(-0.75, "_pbluecyan"); addPalette(psych); } //---------------------------------------------------------------------- // Psych palette // if (paletteNameExists("PSYCH-NO-NONE") == false) { Palette psychNo(this); psychNo.setName("PSYCH-NO-NONE"); psychNo.setPositiveOnly(false); psychNo.addPaletteEntry(1.00, "_yellow"); psychNo.addPaletteEntry(0.75, "_pyell-oran"); psychNo.addPaletteEntry(0.50, "_orange"); psychNo.addPaletteEntry(0.25, "_poran-red"); psychNo.addPaletteEntry(0.00, "_pblue"); psychNo.addPaletteEntry(-0.25, "_pltblue1"); psychNo.addPaletteEntry(-0.50, "_pltblue2"); psychNo.addPaletteEntry(-0.75, "_pbluecyan"); addPalette(psychNo); } // // Geodesic palette // if (paletteNameExists("Geodesic") == false) { Palette geodesic(this); geodesic.setName("Geodesic"); geodesic.setPositiveOnly(true); const float geo_color2[3] = { 255, 255, 0 }; const float geo_color1[3] = { 255, 0, 0 }; float dx = 1.0; for (int colorIndex = 1; colorIndex <= 11; colorIndex++) { const float dx1 = 1.0 - dx; const float color[3] = { geo_color2[0]*dx + geo_color1[0]*dx1, geo_color2[1]*dx + geo_color1[1]*dx1, geo_color2[2]*dx + geo_color1[2]*dx1 }; const unsigned char c255 = 255; const unsigned char c[3] = { std::min(static_cast(color[0]), c255), std::min(static_cast(color[1]), c255), std::min(static_cast(color[2]), c255) }; std::ostringstream name; name << "geo_" << colorIndex; addPaletteColor(PaletteColor(name.str().c_str(), c)); if (dx < 0.05) { dx = 0.02; } geodesic.addPaletteEntry(dx, name.str().c_str()); dx -= 0.1; } const unsigned char geo_blue[3] = { 0, 0, 0xaa }; addPaletteColor(PaletteColor("geo_blue", geo_blue)); geodesic.addPaletteEntry( 0.01, "geo_blue"); geodesic.addPaletteEntry(-0.01, "none"); geodesic.addPaletteEntry(-1.00, "none"); addPalette(geodesic); } //------------------------------------------------------------------------ // // Palette by David Van Essen // const unsigned char oran_yell[3] = { 0xff, 0x99, 0x00 }; addPaletteColor(PaletteColor("_oran-yell", oran_yell)); const unsigned char red[3] = { 0xff, 0x00, 0x00 }; addPaletteColor(PaletteColor("_red", red)); const unsigned char cyan[3] = { 0x00, 0xff, 0xff }; addPaletteColor(PaletteColor("_cyan", cyan)); const unsigned char green[3] = { 0x00, 0xff, 0x00 }; addPaletteColor(PaletteColor("_green", green)); const unsigned char limegreen[3] = { 0x10, 0xb0, 0x10 }; addPaletteColor(PaletteColor("_limegreen", limegreen)); const unsigned char violet[3] = { 0xe2, 0x51, 0xe2 }; addPaletteColor(PaletteColor("_violet", violet)); const unsigned char hotpink[3] = { 0xff, 0x38, 0x8d }; addPaletteColor(PaletteColor("_hotpink", hotpink)); const unsigned char white[3] = { 0xff, 0xff, 0xff }; addPaletteColor(PaletteColor("_white", white)); const unsigned char gry_dd[3] = { 0xdd, 0xdd, 0xdd }; addPaletteColor(PaletteColor("_gry-dd", gry_dd )); const unsigned char gry_bb[3] = { 0xbb, 0xbb, 0xbb }; addPaletteColor(PaletteColor("_gry-bb", gry_bb)); const unsigned char purple2[3] = { 0x66, 0x00, 0x33 }; addPaletteColor(PaletteColor("_purple2", purple2)); const unsigned char blue_videen11[3] = { 0x33, 0x33, 0x4c }; addPaletteColor(PaletteColor("_blue_videen11", blue_videen11)); const unsigned char blue_videen9[3] = { 0x4c, 0x4c, 0x7f }; addPaletteColor(PaletteColor("_blue_videen9", blue_videen9)); const unsigned char blue_videen7[3] = { 0x7f, 0x7f, 0xcc }; addPaletteColor(PaletteColor("_blue_videen7", blue_videen7)); if (paletteNameExists("clear_brain") == false) { Palette clearBrain(this); clearBrain.setName("clear_brain"); clearBrain.addPaletteEntry(1.0 , "_red"); clearBrain.addPaletteEntry(0.9 , "_orange"); clearBrain.addPaletteEntry(0.8 , "_oran-yell"); clearBrain.addPaletteEntry(0.7 , "_yellow"); clearBrain.addPaletteEntry(0.6 , "_limegreen"); clearBrain.addPaletteEntry(0.5 , "_green"); clearBrain.addPaletteEntry(0.4 , "_blue_videen7"); clearBrain.addPaletteEntry(0.3 , "_blue_videen9"); clearBrain.addPaletteEntry(0.2 , "_blue_videen11"); clearBrain.addPaletteEntry(0.1 , "_purple2"); clearBrain.addPaletteEntry(0.0 , "none"); clearBrain.addPaletteEntry(-0.1 , "_cyan"); clearBrain.addPaletteEntry(-0.2 , "_green"); clearBrain.addPaletteEntry(-0.3 , "_limegreen"); clearBrain.addPaletteEntry(-0.4 , "_violet"); clearBrain.addPaletteEntry(-0.5 , "_hotpink"); clearBrain.addPaletteEntry(-0.6 , "_white"); clearBrain.addPaletteEntry(-0.7 , "_gry-dd"); clearBrain.addPaletteEntry(-0.8 , "_gry-bb"); clearBrain.addPaletteEntry(-0.9 , "_black"); addPalette(clearBrain); } if (paletteNameExists("videen_style") == false) { Palette videenStyle(this); videenStyle.setName("videen_style"); videenStyle.addPaletteEntry(1.0 , "_red"); videenStyle.addPaletteEntry(0.9 , "_orange"); videenStyle.addPaletteEntry(0.8 , "_oran-yell"); videenStyle.addPaletteEntry(0.7 , "_yellow"); videenStyle.addPaletteEntry(0.6 , "_limegreen"); videenStyle.addPaletteEntry(0.5 , "_green"); videenStyle.addPaletteEntry(0.4 , "_blue_videen7"); videenStyle.addPaletteEntry(0.3 , "_blue_videen9"); videenStyle.addPaletteEntry(0.2 , "_blue_videen11"); videenStyle.addPaletteEntry(0.1 , "_purple2"); videenStyle.addPaletteEntry(0.0 , "_black"); videenStyle.addPaletteEntry(-0.1 , "_cyan"); videenStyle.addPaletteEntry(-0.2 , "_green"); videenStyle.addPaletteEntry(-0.3 , "_limegreen"); videenStyle.addPaletteEntry(-0.4 , "_violet"); videenStyle.addPaletteEntry(-0.5 , "_hotpink"); videenStyle.addPaletteEntry(-0.6 , "_white"); videenStyle.addPaletteEntry(-0.7 , "_gry-dd"); videenStyle.addPaletteEntry(-0.8 , "_gry-bb"); videenStyle.addPaletteEntry(-0.9 , "_black"); addPalette(videenStyle); } if (paletteNameExists("fidl") == false) { const unsigned char Bright_Yellow[3] = { 0xee, 0xee, 0x55 }; addPaletteColor(PaletteColor("_Bright_Yellow", Bright_Yellow)); const unsigned char Mustard[3] = { 0xdd, 0xdd, 0x66 }; addPaletteColor(PaletteColor("_Mustard", Mustard)); const unsigned char Brown_Mustard[3] = { 0xdd, 0x99, 0x00 }; addPaletteColor(PaletteColor("_Brown_Mustard", Brown_Mustard)); const unsigned char Bright_Red[3] = { 0xff, 0x00, 0x00 }; addPaletteColor(PaletteColor("_Bright_Red", Bright_Red)); const unsigned char Fire_Engine_Red[3] = { 0xdd, 0x00, 0x00 }; addPaletteColor(PaletteColor("_Fire_Engine_Red", Fire_Engine_Red)); const unsigned char Brick[3] = { 0xbb, 0x00, 0x00 }; addPaletteColor(PaletteColor("_Brick", Brick)); const unsigned char Beet[3] = { 0x99, 0x00, 0x00 }; addPaletteColor(PaletteColor("_Beet", Beet)); const unsigned char Beaujolais[3] = { 0x77, 0x00, 0x00 }; addPaletteColor(PaletteColor("_Beaujolais", Beaujolais)); const unsigned char Burgundy[3] = { 0x55, 0x00, 0x00 }; addPaletteColor(PaletteColor("_Burgundy", Burgundy)); const unsigned char Thrombin[3] = { 0x11, 0x00, 0x00 }; addPaletteColor(PaletteColor("_Thrombin", Thrombin)); const unsigned char Deep_Green[3] = { 0x00, 0x11, 0x00 }; addPaletteColor(PaletteColor("_Deep_Green", Deep_Green)); const unsigned char British_Racing_Green[3] = { 0x00, 0x55, 0x00 }; addPaletteColor(PaletteColor("_British_Racing_Green", British_Racing_Green)); const unsigned char Kelp[3] = { 0x00, 0x77, 0x00 }; addPaletteColor(PaletteColor("_Kelp", Kelp)); const unsigned char Lime[3] = { 0x00, 0x99, 0x00 }; addPaletteColor(PaletteColor("_Lime", Lime)); const unsigned char Mint[3] = { 0x00, 0xbb, 0x00 }; addPaletteColor(PaletteColor("_Mint", Mint)); const unsigned char Brussell_Sprout[3] = { 0x00, 0xdd, 0x00 }; addPaletteColor(PaletteColor("_Brussell_Sprout", Brussell_Sprout)); const unsigned char Bright_Green[3] = { 0x00, 0xff, 0x00 }; addPaletteColor(PaletteColor("_Bright_Green", Bright_Green)); const unsigned char Periwinkle[3] = { 0x66, 0x66, 0xbb }; addPaletteColor(PaletteColor("_Periwinkle", Periwinkle)); const unsigned char Azure[3] = { 0x88, 0x88, 0xee }; addPaletteColor(PaletteColor("_Azure", Azure)); const unsigned char Turquoise[3] = { 0x00, 0xcc, 0xcc }; addPaletteColor(PaletteColor("_Turquoise", Turquoise)); Palette fidl(this); fidl.setName("fidl"); fidl.addPaletteEntry(1.0, "_Bright_Yellow"); fidl.addPaletteEntry(0.9, "_Mustard"); fidl.addPaletteEntry(0.8, "_Brown_Mustard"); fidl.addPaletteEntry(0.7, "_Bright_Red"); fidl.addPaletteEntry(0.6, "_Fire_Engine_Red"); fidl.addPaletteEntry(0.5, "_Brick"); fidl.addPaletteEntry(0.4, "_Beet"); fidl.addPaletteEntry(0.3, "_Beaujolais"); fidl.addPaletteEntry(0.2, "_Burgundy"); fidl.addPaletteEntry(0.1, "_Thrombin"); fidl.addPaletteEntry(0.0, "none"); fidl.addPaletteEntry(-0.1, "_Deep_Green"); fidl.addPaletteEntry(-0.2, "_British_Racing_Green"); fidl.addPaletteEntry(-0.3, "_Kelp"); fidl.addPaletteEntry(-0.4, "_Lime"); fidl.addPaletteEntry(-0.5, "_Mint"); fidl.addPaletteEntry(-0.6, "_Brussell_Sprout"); fidl.addPaletteEntry(-0.7, "_Bright_Green"); fidl.addPaletteEntry(-0.8, "_Periwinkle"); fidl.addPaletteEntry(-0.9, "_Azure"); fidl.addPaletteEntry(-1.0, "_Turquoise"); addPalette(fidl); } //------------------------------------------------------------------------ // // Palette by Jon Wieser @ mcw // const unsigned char rbgyr20_01[3] = { 0xCC, 0x10, 0x33 }; addPaletteColor(PaletteColor("_rbgyr20_01", rbgyr20_01)); const unsigned char rbgyr20_02[3] = { 0x99, 0x20, 0x66 }; addPaletteColor(PaletteColor("_rbgyr20_02", rbgyr20_02)); const unsigned char rbgyr20_03[3] = { 0x66, 0x31, 0x99 }; addPaletteColor(PaletteColor("_rbgyr20_03", rbgyr20_03)); const unsigned char rbgyr20_04[3] = { 0x34, 0x41, 0xCC }; addPaletteColor(PaletteColor("_rbgyr20_04", rbgyr20_04)); const unsigned char rbgyr20_05[3] = { 0x00, 0x51, 0xFF }; addPaletteColor(PaletteColor("_rbgyr20_05", rbgyr20_05)); const unsigned char rbgyr20_06[3] = { 0x00, 0x74, 0xCC }; addPaletteColor(PaletteColor("_rbgyr20_06", rbgyr20_06)); const unsigned char rbgyr20_07[3] = { 0x00, 0x97, 0x99 }; addPaletteColor(PaletteColor("_rbgyr20_07", rbgyr20_07)); const unsigned char rbgyr20_08[3] = { 0x00, 0xB9, 0x66 }; addPaletteColor(PaletteColor("_rbgyr20_08", rbgyr20_08)); const unsigned char rbgyr20_09[3] = { 0x00, 0xDC, 0x33 }; addPaletteColor(PaletteColor("_rbgyr20_09", rbgyr20_09)); const unsigned char rbgyr20_10[3] = { 0x00, 0xFF, 0x00 }; addPaletteColor(PaletteColor("_rbgyr20_10", rbgyr20_10)); const unsigned char rbgyr20_11[3] = { 0x33, 0xFF, 0x00 }; addPaletteColor(PaletteColor("_rbgyr20_11", rbgyr20_11)); const unsigned char rbgyr20_12[3] = { 0x66, 0xFF, 0x00 }; addPaletteColor(PaletteColor("_rbgyr20_12", rbgyr20_12)); const unsigned char rbgyr20_13[3] = { 0x99, 0xFF, 0x00 }; addPaletteColor(PaletteColor("_rbgyr20_13", rbgyr20_13)); const unsigned char rbgyr20_14[3] = { 0xCC, 0xFF, 0x00 }; addPaletteColor(PaletteColor("_rbgyr20_14", rbgyr20_14)); const unsigned char rbgyr20_15[3] = { 0xFF, 0xFF, 0x00 }; addPaletteColor(PaletteColor("_rbgyr20_15", rbgyr20_15)); const unsigned char rbgyr20_16[3] = { 0xFF, 0xCC, 0x00 }; addPaletteColor(PaletteColor("_rbgyr20_16", rbgyr20_16)); const unsigned char rbgyr20_17[3] = { 0xFF, 0x99, 0x00 }; addPaletteColor(PaletteColor("_rbgyr20_17", rbgyr20_17)); const unsigned char rbgyr20_18[3] = { 0xFF, 0x66, 0x00 }; addPaletteColor(PaletteColor("_rbgyr20_18", rbgyr20_18)); const unsigned char rbgyr20_19[3] = { 0xFF, 0x33, 0x00 }; addPaletteColor(PaletteColor("_rbgyr20_19", rbgyr20_19)); const unsigned char rbgyr20_20[3] = { 0xFF, 0x00, 0x00 }; addPaletteColor(PaletteColor("_rbgyr20_20", rbgyr20_20)); if (paletteNameExists("RBGYR20") == false) { Palette pal2(this); pal2.setName("RBGYR20"); pal2.addPaletteEntry( 1.0, "_rbgyr20_01"); pal2.addPaletteEntry( 0.9, "_rbgyr20_02"); pal2.addPaletteEntry( 0.8, "_rbgyr20_03"); pal2.addPaletteEntry( 0.7, "_rbgyr20_04"); pal2.addPaletteEntry( 0.6, "_rbgyr20_05"); pal2.addPaletteEntry( 0.5, "_rbgyr20_06"); pal2.addPaletteEntry( 0.4, "_rbgyr20_07"); pal2.addPaletteEntry( 0.3, "_rbgyr20_08"); pal2.addPaletteEntry( 0.2, "_rbgyr20_09"); pal2.addPaletteEntry( 0.1, "_rbgyr20_10"); pal2.addPaletteEntry( 0.0, "_rbgyr20_11"); pal2.addPaletteEntry(-0.1, "_rbgyr20_12"); pal2.addPaletteEntry(-0.2, "_rbgyr20_13"); pal2.addPaletteEntry(-0.3, "_rbgyr20_14"); pal2.addPaletteEntry(-0.4, "_rbgyr20_15"); pal2.addPaletteEntry(-0.5, "_rbgyr20_16"); pal2.addPaletteEntry(-0.6, "_rbgyr20_17"); pal2.addPaletteEntry(-0.7, "_rbgyr20_18"); pal2.addPaletteEntry(-0.8, "_rbgyr20_19"); pal2.addPaletteEntry(-0.9, "_rbgyr20_20"); addPalette(pal2); Palette pal3(this); pal3.setName("RBGYR20"); pal3.setPositiveOnly(true); pal3.addPaletteEntry(1.00, "_rbgyr20_01"); pal3.addPaletteEntry(0.95, "_rbgyr20_02"); pal3.addPaletteEntry(0.90, "_rbgyr20_03"); pal3.addPaletteEntry(0.85, "_rbgyr20_04"); pal3.addPaletteEntry(0.80, "_rbgyr20_05"); pal3.addPaletteEntry(0.75, "_rbgyr20_06"); pal3.addPaletteEntry(0.70, "_rbgyr20_07"); pal3.addPaletteEntry(0.65, "_rbgyr20_08"); pal3.addPaletteEntry(0.60, "_rbgyr20_09"); pal3.addPaletteEntry(0.55, "_rbgyr20_10"); pal3.addPaletteEntry(0.50, "_rbgyr20_11"); pal3.addPaletteEntry(0.45, "_rbgyr20_12"); pal3.addPaletteEntry(0.40, "_rbgyr20_13"); pal3.addPaletteEntry(0.35, "_rbgyr20_14"); pal3.addPaletteEntry(0.30, "_rbgyr20_15"); pal3.addPaletteEntry(0.25, "_rbgyr20_16"); pal3.addPaletteEntry(0.20, "_rbgyr20_17"); pal3.addPaletteEntry(0.15, "_rbgyr20_18"); pal3.addPaletteEntry(0.10, "_rbgyr20_19"); pal3.addPaletteEntry(0.05, "_rbgyr20_20"); addPalette(pal3); } { //------------------------------------------------------------------------ // // Colors by Russ H. // const unsigned char _rbgyr20_10[3] = { 0x00, 0xff, 0x00 }; addPaletteColor(PaletteColor("_rbgyr20_10", _rbgyr20_10)); const unsigned char _rbgyr20_15[3] = { 0xff, 0xff, 0x00 }; addPaletteColor(PaletteColor("_rbgyr20_15", _rbgyr20_15)); const unsigned char _rbgyr20_20[3] = { 0xff, 0x00, 0x00 }; addPaletteColor(PaletteColor("_rbgyr20_20", _rbgyr20_20)); const unsigned char _rbgyr20_21[3] = { 0x9d, 0x22, 0xc1 }; addPaletteColor(PaletteColor("_rbgyr20_21", _rbgyr20_21)); const unsigned char _rbgyr20_22[3] = { 0x81, 0x06, 0xa5 }; addPaletteColor(PaletteColor("_rbgyr20_22", _rbgyr20_22)); const unsigned char _rbgyr20_23[3] = { 0xff, 0xec, 0x00 }; addPaletteColor(PaletteColor("_rbgyr20_23", _rbgyr20_23)); const unsigned char _rbgyr20_24[3] = { 0xff, 0xd6, 0x00 }; addPaletteColor(PaletteColor("_rbgyr20_24", _rbgyr20_24)); const unsigned char _rbgyr20_25[3] = { 0xff, 0xbc, 0x00 }; addPaletteColor(PaletteColor("_rbgyr20_25", _rbgyr20_25)); const unsigned char _rbgyr20_26[3] = { 0xff, 0x9c, 0x00 }; addPaletteColor(PaletteColor("_rbgyr20_26", _rbgyr20_26)); const unsigned char _rbgyr20_27[3] = { 0xff, 0x7c, 0x00 }; addPaletteColor(PaletteColor("_rbgyr20_27", _rbgyr20_27)); const unsigned char _rbgyr20_28[3] = { 0xff, 0x5c, 0x00 }; addPaletteColor(PaletteColor("_rbgyr20_28", _rbgyr20_28)); const unsigned char _rbgyr20_29[3] = { 0xff, 0x3d, 0x00 }; addPaletteColor(PaletteColor("_rbgyr20_29", _rbgyr20_29)); const unsigned char _rbgyr20_30[3] = { 0xff, 0x23, 0x00 }; addPaletteColor(PaletteColor("_rbgyr20_30", _rbgyr20_30)); const unsigned char _rbgyr20_31[3] = { 0x00, 0xed, 0x12 }; addPaletteColor(PaletteColor("_rbgyr20_31", _rbgyr20_31)); const unsigned char _rbgyr20_32[3] = { 0x00, 0xd5, 0x2a }; addPaletteColor(PaletteColor("_rbgyr20_32", _rbgyr20_32)); const unsigned char _rbgyr20_33[3] = { 0x00, 0xb9, 0x46 }; addPaletteColor(PaletteColor("_rbgyr20_33", _rbgyr20_33)); const unsigned char _rbgyr20_34[3] = { 0x00, 0x9b, 0x64 }; addPaletteColor(PaletteColor("_rbgyr20_34", _rbgyr20_34)); const unsigned char _rbgyr20_35[3] = { 0x00, 0x7b, 0x84 }; addPaletteColor(PaletteColor("_rbgyr20_35", _rbgyr20_35)); const unsigned char _rbgyr20_36[3] = { 0x00, 0x5b, 0xa4 }; addPaletteColor(PaletteColor("_rbgyr20_36", _rbgyr20_36)); const unsigned char _rbgyr20_37[3] = { 0x00, 0x44, 0xbb }; addPaletteColor(PaletteColor("_rbgyr20_37", _rbgyr20_37)); const unsigned char _rbgyr20_38[3] = { 0x00, 0x24, 0xdb }; addPaletteColor(PaletteColor("_rbgyr20_38", _rbgyr20_38)); const unsigned char _rbgyr20_39[3] = { 0x00, 0x00, 0xff }; addPaletteColor(PaletteColor("_rbgyr20_39", _rbgyr20_39)); const unsigned char _rbgyr20_40[3] = { 0xff, 0xf1, 0x00 }; addPaletteColor(PaletteColor("_rbgyr20_40", _rbgyr20_40)); const unsigned char _rbgyr20_41[3] = { 0xff, 0xdc, 0x00 }; addPaletteColor(PaletteColor("_rbgyr20_41", _rbgyr20_41)); const unsigned char _rbgyr20_42[3] = { 0xff, 0xcb, 0x00 }; addPaletteColor(PaletteColor("_rbgyr20_42", _rbgyr20_42)); const unsigned char _rbgyr20_43[3] = { 0xff, 0xc2, 0x00 }; addPaletteColor(PaletteColor("_rbgyr20_43", _rbgyr20_43)); const unsigned char _rbgyr20_44[3] = { 0xff, 0xae, 0x00 }; addPaletteColor(PaletteColor("_rbgyr20_44", _rbgyr20_44)); const unsigned char _rbgyr20_45[3] = { 0xff, 0x9f, 0x00 }; addPaletteColor(PaletteColor("_rbgyr20_45", _rbgyr20_45)); const unsigned char _rbgyr20_46[3] = { 0xff, 0x86, 0x00 }; addPaletteColor(PaletteColor("_rbgyr20_46", _rbgyr20_46)); const unsigned char _rbgyr20_47[3] = { 0xff, 0x59, 0x00 }; addPaletteColor(PaletteColor("_rbgyr20_47", _rbgyr20_47)); const unsigned char _rbgyr20_48[3] = { 0x00, 0xff, 0x2d }; addPaletteColor(PaletteColor("_rbgyr20_48", _rbgyr20_48)); const unsigned char _rbgyr20_49[3] = { 0x00, 0xff, 0x65 }; addPaletteColor(PaletteColor("_rbgyr20_49", _rbgyr20_49)); const unsigned char _rbgyr20_50[3] = { 0x00, 0xff, 0xa5 }; addPaletteColor(PaletteColor("_rbgyr20_50", _rbgyr20_50)); const unsigned char _rbgyr20_51[3] = { 0x00, 0xff, 0xdd }; addPaletteColor(PaletteColor("_rbgyr20_51", _rbgyr20_51)); const unsigned char _rbgyr20_52[3] = { 0x00, 0xff, 0xff }; addPaletteColor(PaletteColor("_rbgyr20_52", _rbgyr20_52)); const unsigned char _rbgyr20_53[3] = { 0x00, 0xe9, 0xff }; addPaletteColor(PaletteColor("_rbgyr20_53", _rbgyr20_53)); const unsigned char _rbgyr20_54[3] = { 0x00, 0xad, 0xff }; addPaletteColor(PaletteColor("_rbgyr20_54", _rbgyr20_54)); const unsigned char _rbgyr20_55[3] = { 0x00, 0x69, 0xff }; addPaletteColor(PaletteColor("_rbgyr20_55", _rbgyr20_55)); const unsigned char _rbgyr20_56[3] = { 0xff, 0x00, 0xb9 }; addPaletteColor(PaletteColor("_rbgyr20_56", _rbgyr20_56)); const unsigned char _rbgyr20_57[3] = { 0xff, 0x00, 0x63 }; addPaletteColor(PaletteColor("_rbgyr20_57", _rbgyr20_57)); const unsigned char _rbgyr20_58[3] = { 0xff, 0x05, 0x00 }; addPaletteColor(PaletteColor("_rbgyr20_58", _rbgyr20_58)); const unsigned char _rbgyr20_59[3] = { 0xff, 0x32, 0x00 }; addPaletteColor(PaletteColor("_rbgyr20_59", _rbgyr20_59)); const unsigned char _rbgyr20_60[3]= { 0xff, 0x70, 0x00 }; addPaletteColor(PaletteColor("_rbgyr20_60", _rbgyr20_60)); const unsigned char _rbgyr20_61[3] = { 0xff, 0xa4, 0x00 }; addPaletteColor(PaletteColor("_rbgyr20_61", _rbgyr20_61)); const unsigned char _rbgyr20_62[3] = { 0xff, 0xba, 0x00 }; addPaletteColor(PaletteColor("_rbgyr20_62", _rbgyr20_62)); const unsigned char _rbgyr20_63[3] = { 0xff, 0xd3, 0x00 }; addPaletteColor(PaletteColor("_rbgyr20_63", _rbgyr20_63)); const unsigned char _rbgyr20_64[3] = { 0x42, 0x21, 0xdb }; addPaletteColor(PaletteColor("_rbgyr20_64", _rbgyr20_64)); const unsigned char _rbgyr20_65[3] = { 0x10, 0x08, 0xf6 }; addPaletteColor(PaletteColor("_rbgyr20_65", _rbgyr20_65)); const unsigned char _rbgyr20_66[3] = { 0x00, 0x13, 0xff }; addPaletteColor(PaletteColor("_rbgyr20_66", _rbgyr20_66)); const unsigned char _rbgyr20_67[3] = { 0x00, 0x5b, 0xff }; addPaletteColor(PaletteColor("_rbgyr20_67", _rbgyr20_67)); const unsigned char _rbgyr20_68[3] = { 0x00, 0xb3, 0xff }; addPaletteColor(PaletteColor("_rbgyr20_68", _rbgyr20_68)); const unsigned char _rbgyr20_69[3] = { 0x00, 0xfc, 0xff }; addPaletteColor(PaletteColor("_rbgyr20_69", _rbgyr20_69)); const unsigned char _rbgyr20_70[3] = { 0x00, 0xff, 0xcd }; addPaletteColor(PaletteColor("_rbgyr20_70", _rbgyr20_70)); const unsigned char _rbgyr20_71[3] = { 0x00, 0xff, 0x74 }; addPaletteColor(PaletteColor("_rbgyr20_71", _rbgyr20_71)); const unsigned char _rbgyr20_72[3] = { 0xff, 0x00, 0xf9 }; addPaletteColor(PaletteColor("_rbgyr20_72", _rbgyr20_72)); const unsigned char _rbgyr20_73[3] = { 0x62, 0x31, 0xc9 }; addPaletteColor(PaletteColor("_rbgyr20_73", _rbgyr20_73)); //------------------------------------------------------------------------ // // Palette by Russ H. // if (paletteNameExists("raich4_clrmid") == false) { Palette r4(this); r4.setName("raich4_clrmid"); r4.addPaletteEntry(1.000000, "_rbgyr20_20"); r4.addPaletteEntry(0.900000, "_rbgyr20_30"); r4.addPaletteEntry(0.800000, "_rbgyr20_29"); r4.addPaletteEntry(0.700000, "_rbgyr20_28"); r4.addPaletteEntry(0.600000, "_rbgyr20_27"); r4.addPaletteEntry(0.500000, "_rbgyr20_26"); r4.addPaletteEntry(0.400000, "_rbgyr20_25"); r4.addPaletteEntry(0.300000, "_rbgyr20_24"); r4.addPaletteEntry(0.200000, "_rbgyr20_23"); r4.addPaletteEntry(0.100000, "_rbgyr20_15"); r4.addPaletteEntry(0.000000, "none"); r4.addPaletteEntry(-0.100000, "_rbgyr20_10"); r4.addPaletteEntry(-0.200000, "_rbgyr20_31"); r4.addPaletteEntry(-0.300000, "_rbgyr20_32"); r4.addPaletteEntry(-0.400000, "_rbgyr20_33"); r4.addPaletteEntry(-0.500000, "_rbgyr20_34"); r4.addPaletteEntry(-0.600000, "_rbgyr20_35"); r4.addPaletteEntry(-0.700000, "_rbgyr20_36"); r4.addPaletteEntry(-0.800000, "_rbgyr20_37"); r4.addPaletteEntry(-0.900000, "_rbgyr20_38"); r4.addPaletteEntry(-1.000000, "_rbgyr20_39"); addPalette(r4); } //------------------------------------------------------------------------ // // Palette by Russ H. // if (paletteNameExists("raich6_clrmid") == false) { Palette r6(this); r6.setName("raich6_clrmid"); r6.addPaletteEntry(1.000000, "_rbgyr20_20"); r6.addPaletteEntry(0.900000, "_rbgyr20_47"); r6.addPaletteEntry(0.800000, "_rbgyr20_46"); r6.addPaletteEntry(0.700000, "_rbgyr20_45"); r6.addPaletteEntry(0.600000, "_rbgyr20_44"); r6.addPaletteEntry(0.500000, "_rbgyr20_43"); r6.addPaletteEntry(0.400000, "_rbgyr20_42"); r6.addPaletteEntry(0.300000, "_rbgyr20_41"); r6.addPaletteEntry(0.200000, "_rbgyr20_40"); r6.addPaletteEntry(0.100000, "_rbgyr20_15"); r6.addPaletteEntry(0.000000, "none"); r6.addPaletteEntry(-0.100000, "_rbgyr20_10"); r6.addPaletteEntry(-0.200000, "_rbgyr20_48"); r6.addPaletteEntry(-0.300000, "_rbgyr20_49"); r6.addPaletteEntry(-0.400000, "_rbgyr20_50"); r6.addPaletteEntry(-0.500000, "_rbgyr20_51"); r6.addPaletteEntry(-0.600000, "_rbgyr20_52"); r6.addPaletteEntry(-0.700000, "_rbgyr20_53"); r6.addPaletteEntry(-0.800000, "_rbgyr20_54"); r6.addPaletteEntry(-0.900000, "_rbgyr20_55"); r6.addPaletteEntry(-1.000000, "_rbgyr20_39"); addPalette(r6); } //------------------------------------------------------------------------ // // Palette by Russ H. // if (paletteNameExists("HSB8_clrmid") == false) { Palette hsb8(this); hsb8.setName("HSB8_clrmid"); hsb8.addPaletteEntry(1.000000, "_rbgyr20_15"); hsb8.addPaletteEntry(0.900000, "_rbgyr20_63"); hsb8.addPaletteEntry(0.800000, "_rbgyr20_62"); hsb8.addPaletteEntry(0.700000, "_rbgyr20_61"); hsb8.addPaletteEntry(0.600000, "_rbgyr20_60"); hsb8.addPaletteEntry(0.500000, "_rbgyr20_59"); hsb8.addPaletteEntry(0.400000, "_rbgyr20_58"); hsb8.addPaletteEntry(0.300000, "_rbgyr20_57"); hsb8.addPaletteEntry(0.200000, "_rbgyr20_56"); hsb8.addPaletteEntry(0.100000, "_rbgyr20_72"); hsb8.addPaletteEntry(0.000000, "none"); hsb8.addPaletteEntry(-0.100000, "_rbgyr20_73"); hsb8.addPaletteEntry(-0.200000, "_rbgyr20_64"); hsb8.addPaletteEntry(-0.300000, "_rbgyr20_65"); hsb8.addPaletteEntry(-0.400000, "_rbgyr20_66"); hsb8.addPaletteEntry(-0.500000, "_rbgyr20_67"); hsb8.addPaletteEntry(-0.600000, "_rbgyr20_68"); hsb8.addPaletteEntry(-0.700000, "_rbgyr20_69"); hsb8.addPaletteEntry(-0.800000, "_rbgyr20_70"); hsb8.addPaletteEntry(-0.900000, "_rbgyr20_71"); hsb8.addPaletteEntry(-1.000000, "_rbgyr20_10"); addPalette(hsb8); } } //---------------------------------------------------------------------- // Orange-Yellow palette // if (paletteNameExists("Orange-Yellow") == false) { const unsigned char oy1[3] = { 0, 0, 0 }; addPaletteColor(PaletteColor("_oy1", oy1)); const unsigned char oy2[3] = { 130, 2, 0 }; addPaletteColor(PaletteColor("_oy2", oy2)); const unsigned char oy3[3] = { 254, 130, 2 }; addPaletteColor(PaletteColor("_oy3", oy3)); const unsigned char oy4[3] = { 254, 254, 126 }; addPaletteColor(PaletteColor("_oy4", oy4)); const unsigned char oy5[3] = { 254, 254, 254 }; addPaletteColor(PaletteColor("_oy5", oy5)); Palette orangeYellow(this); orangeYellow.setName("Orange-Yellow"); orangeYellow.addPaletteEntry( 1.0, "_oy5"); orangeYellow.addPaletteEntry( 0.5, "_oy4"); orangeYellow.addPaletteEntry( 0.0, "_oy3"); orangeYellow.addPaletteEntry(-0.5, "_oy2"); orangeYellow.addPaletteEntry(-1.0, "_oy1"); addPalette(orangeYellow); } //---------------------------------------------------------------------- // Gray scale palette // if (paletteNameExists("Gray") == false) { const unsigned char maxIntensity = 255; // 230; const unsigned char minIntensity = 0; // 25; unsigned char intensity = maxIntensity; const int numSteps = 10; const int stepSize = (maxIntensity - minIntensity) / numSteps; const float tableStep = 2.0 / static_cast(numSteps); float tableValue = 1.0; Palette pal(this); pal.setName("Gray"); for (int i = 0; i < numSteps; i++) { unsigned char rgb[3] = { intensity, intensity, intensity }; std::ostringstream str; str << "_gray_" << i << std::ends; PaletteColor pc(str.str().c_str(), rgb); addPaletteColor(pc); pal.addPaletteEntry(tableValue, str.str().c_str()); tableValue -= tableStep; intensity -= stepSize; } addPalette(pal); } // // Create a palette with just white and black designed to be used // with the interpolate option // if (paletteNameExists(grayInterpPaletteName) == false) { Palette palGrayInterp(this); palGrayInterp.setName(grayInterpPaletteName); const unsigned char white[3] = { 255, 255, 255 }; addPaletteColor(PaletteColor("_white_gray_interp", white)); const unsigned char black[3] = { 0, 0, 0 }; addPaletteColor(PaletteColor("_black_gray_interp", black)); palGrayInterp.addPaletteEntry( 1.0, "_white_gray_interp"); palGrayInterp.addPaletteEntry(-1.0, "_black_gray_interp"); addPalette(palGrayInterp); } // // Inverse gray positive palette // if (paletteNameExists("Gray_Inverse_Interp") == false) { Palette inverseGray(this); inverseGray.setPositiveOnly(true); inverseGray.setName("Gray_Inverse_Interp"); const unsigned char white[3] = { 255, 255, 255 }; addPaletteColor(PaletteColor("_white_gray_interp", white)); const unsigned char black[3] = { 0, 0, 0 }; addPaletteColor(PaletteColor("_black_gray_interp", black)); inverseGray.addPaletteEntry(1.0, "_black_gray_interp"); inverseGray.addPaletteEntry(0.001, "_white_gray_interp"); inverseGray.addPaletteEntry(0.0009, "none"); addPalette(inverseGray); } if (paletteNameExists("Plus_Minus") == false) { Palette plusMinus(this); plusMinus.setName("Plus_Minus"); plusMinus.addPaletteEntry(1.00, "_yellow"); plusMinus.addPaletteEntry(0.00001, "none"); plusMinus.addPaletteEntry(-0.00001, "_pbluecyan"); addPalette(plusMinus); } } /** * See if a palette with specified name exists */ bool PaletteFile::paletteNameExists(const QString& name) { for (int i = 0; i < getNumberOfPalettes(); i++) { const Palette* palette = getPalette(i); if (palette->getName() == name) { return true; } } return false; } /** * The destructor. */ PaletteFile::~PaletteFile() { clear(); } /** * add a palette to the palette file. */ void PaletteFile::addPalette(const Palette& pal) { palettes.push_back(pal); const int num = getNumberOfPalettes() - 1; palettes[num].myPaletteFile = this; setModified(); } /** * get the palette colors into a color file. */ void PaletteFile::getPaletteColorsUsingColorFile(ColorFile& cf) const { // // Initially clear the color file // cf.clear(); // // Get the number of palette colors // const int numPaletteColors = getNumberOfPaletteColors(); // // Loop through the palette colors // for (int i = 0; i < numPaletteColors; i++) { // // Get the palette color // const PaletteColor* pc = getPaletteColor(i); // // Add onto the color file // unsigned char rgb[3]; pc->getRGB(rgb); cf.addColor(pc->getName(), rgb[0], rgb[1], rgb[2]); } } /** * replace the palette colors using a ColorFile (update color assignments too) */ void PaletteFile::replacePaletteColorsUsingColorFile(const ColorFile& cf) { // // Keeps track of palette entries without a valid color // std::vector paletteEntriesMissingColor; // // Get the number of palette colors // const int numPaletteColors = getNumberOfPaletteColors(); // // Loop through the palettes // for (int i = 0; i < getNumberOfPalettes(); i++) { // // Get the palette // Palette* pal = getPalette(i); // // Get the number of entries in the palette // const int numEntries = pal->getNumberOfPaletteEntries(); // // Loop through the palette entries // for (int j = 0; j < numEntries; j++) { // // Get the palette entry // PaletteEntry* pe = pal->getPaletteEntry(j); // // Get the name of the current color for this palette entry // int colorIndex = pe->getColorIndex(); // // Assume color is not found // bool colorFound = false; // // If valid color index // if ((colorIndex >= 0) && (colorIndex < numPaletteColors)) { // // Get the palette color for this index // PaletteColor* pc = getPaletteColor(colorIndex); // // Find the color in the color file // bool match = false; const int fileIndex = cf.getColorIndexByName(pc->getName(), match); if (match && (fileIndex >= 0)) { colorIndex = fileIndex; colorFound = true; } } // // If the color was found // if (colorFound) { // // Update palette entry's index // pe->setColorIndex(colorIndex); } else { // // keep track of palette entries missing the correct color // paletteEntriesMissingColor.push_back(pe); } } } // // Get rid of the existing colors. // colors.clear(); // // Copy the colors from the palette file // const int numFileColors = cf.getNumberOfColors(); for (int i = 0; i < numFileColors; i++) { // // Get name and color components from color file // unsigned char rgb[3]; cf.getColorByIndex(i, rgb[0], rgb[1], rgb[2]); // // Add to palette colors // addPaletteColor(cf.getColorNameByIndex(i), rgb); } // // Are there missing colors // if (paletteEntriesMissingColor.empty() == false) { // // Find index of missing color // int missingColorIndex = getColorIndexFromName(PaletteColor::missingColorName); if (missingColorIndex < 0) { unsigned char rgb[3] = { 0, 0, 0 }; addPaletteColor(PaletteColor::missingColorName, rgb); missingColorIndex = getNumberOfPaletteColors() -1; } // // Set colors indices to point to missing colors // const int num = static_cast(paletteEntriesMissingColor.size()); for (int i = 0; i < num; i++) { paletteEntriesMissingColor[i]->setColorIndex(missingColorIndex); } } } /** * Add a color to the palette. */ void PaletteFile::addPaletteColor(const QString& name, const unsigned char rgb[3]) { addPaletteColor(PaletteColor(name, rgb)); } /** * Add a color to the palette. */ void PaletteFile::addPaletteColor(const PaletteColor& pc) { // // see if color exists // setModified(); for (unsigned int i = 0; i < colors.size(); i++) { if (colors[i].getName() == pc.getName()) { unsigned char oldrgb[3]; colors[i].getRGB(oldrgb); unsigned char newrgb[3]; pc.getRGB(newrgb); if ((oldrgb[0] == newrgb[0]) && (oldrgb[1] == newrgb[1]) && (oldrgb[2] == newrgb[2])) { //printf("INFO: color \"%s\" specified multiple times in " // "palette file with same RGB.\n", pc.getName()); } else if (pc.getName() != "none") { std::cout << "WARNING: Color \"" << pc.getName().toAscii().constData() << "\" defined multiple times in palette file\n"; std::cout << " old color (" << (int)oldrgb[0] << ", " << (int)oldrgb[1] << ", " << (int)oldrgb[2] << ") new color (" << (int)newrgb[0] << ", " << (int)newrgb[1] << ", " << (int)newrgb[2] << ")\n"; colors[i].setRGB(newrgb); } return; } } colors.push_back(pc); PaletteColor* pt = getPaletteColor(getNumberOfPaletteColors() -1); pt->myPaletteFile = this; setModified(); } /** * Append a palette file to this palette file */ void PaletteFile::append(PaletteFile& pf) { // // Copy colors // for (int i = 0; i < pf.getNumberOfPaletteColors(); i++) { addPaletteColor(*(pf.getPaletteColor(i))); } // // Copy palettes and be sure to update color indices // for (int i = 0; i < pf.getNumberOfPalettes(); i++) { // // Make copy of the palette // Palette p = *(pf.getPalette(i)); // // Loop through the palette's entries // for (int j = 0; j < p.getNumberOfPaletteEntries(); j++) { // // Update the color indices // PaletteEntry* pe = p.getPaletteEntry(j); int colorIndex = pe->getColorIndex(); QString colorName(PaletteColor::missingColorName); if (colorIndex >= 0) { const PaletteColor* pc = pf.getPaletteColor(colorIndex); if (pc != NULL) { colorName = pc->getName(); } } colorIndex = getColorIndexFromName(colorName); if (colorIndex < 0) { colorIndex = getColorIndexFromName(PaletteColor::missingColorName); if (colorIndex < 0) { const unsigned char rgb[3] = { 0, 0, 0 }; addPaletteColor(PaletteColor::missingColorName, rgb); colorIndex = getColorIndexFromName(PaletteColor::missingColorName); } } pe->setColorIndex(colorIndex); } // // Add the palette to this palette file // addPalette(p); } // // transfer the file's comment // appendFileComment(pf); } /** * Clear the palette file. */ void PaletteFile::clear() { clearAbstractFile(); colors.clear(); palettes.clear(); // // Always have "none" color // const unsigned char none[3] = { 0xff, 0xff, 0xff }; addPaletteColor(PaletteColor("none", none)); } /** * get palette index from name or number (number ranges 1..N). */ int PaletteFile::getPaletteIndexFromNameOrNumber(const QString& nameOrNumber) const throw (FileException) { // // Find the palette by name // const int numberOfPalettes = getNumberOfPalettes(); for (int i = 0; i < numberOfPalettes; i++) { if (getPalette(i)->getName() == nameOrNumber) { return i; } } // // Search by number // bool ok = false; const int num = nameOrNumber.toInt(&ok); if (ok) { if ((num > 0) || (num <= numberOfPalettes)) { return (num - 1); } throw FileException("ERROR Invalid palette number: " + nameOrNumber + ". Number should range 1 to " + QString::number(numberOfPalettes)); } // // faild to find // throw FileException("ERROR palette name/number " + nameOrNumber + " not found in file " + FileUtilities::basename(getFileName())); } /** * Get the gray interpolate palette. */ int PaletteFile::getGrayInterPaletteIndex() const { for (int i = 0; i < getNumberOfPalettes(); i++) { if (palettes[i].getName() == grayInterpPaletteName) { return i; } } return -1; } /** * get color compontents for a color with specified name. */ int PaletteFile::getColorComponents(const QString& colorName, bool& noneColorFlag, unsigned char rgb[3]) const { noneColorFlag = false; if (colorName == PaletteColor::noneColorName) { rgb[0] = 0; rgb[0] = 1; rgb[0] = 2; noneColorFlag = true; return 0; } for (unsigned int i = 0; i < colors.size(); i++) { if (colors[i].getName() == colorName) { colors[i].getRGB(rgb); return 0; } } return 1; } /** * Convert from hex to base 10 */ int PaletteFile::hexToInt(char c) const { if ((c >= 'a') && (c <= 'f')) { return (c - 'a' + 10); } return (c - '0'); } /** * Convert from X color format */ bool PaletteFile::convertFromXColor(const char* colorString, unsigned char rgb[3]) const { // color is of the form "#ff4400" if (colorString[0] == '#') { const int r2 = hexToInt(colorString[1]); const int r1 = hexToInt(colorString[2]); const int g2 = hexToInt(colorString[3]); const int g1 = hexToInt(colorString[4]); const int b2 = hexToInt(colorString[5]); const int b1 = hexToInt(colorString[6]); rgb[0] = (r2 * 16) + r1; rgb[1] = (g2 * 16) + g1; rgb[2] = (b2 * 16) + b1; } // color is of the form "rgbi:0.5/0.3/1.0" else if (strncmp(colorString, "rgbi:", 5) == 0) { char* redStr = strtok((char*)&colorString[5], "/"); char* greenStr = strtok(NULL, "/"); char* blueStr = strtok(NULL, "/"); rgb[0] = static_cast(QString(redStr).toFloat() * 255.0); rgb[1] = static_cast(QString(greenStr).toFloat() * 255.0); rgb[2] = static_cast(QString(blueStr).toFloat() * 255.0); } else { std::cerr << "ERROR: Unable to determine RGB for Palette Color " << colorString << std::endl; return true; } return false; } /** * remove a palette. */ void PaletteFile::removePalette(const int palNum) { if ((palNum >= 0) && (palNum < getNumberOfPalettes())) { palettes.erase(palettes.begin() + palNum); } setModified(); } /** * Read the Palette file. */ void PaletteFile::readFileData(QFile& /*file*/, QTextStream& stream, QDataStream&, QDomElement& /* rootElement */) throw (FileException) { // // Should reading data be skipped ? // if (getReadMetaDataOnlyFlag()) { return; } bool readColors = false; bool readPalette = false; enum { READING_COLORS, READING_PALETTE, READING_OTHER } reading = READING_OTHER; QString line; readLine(stream, line); while(stream.atEnd() == false) { // comments are like C++ style comments int comment = line.indexOf("//"); if (comment != -1) { line.resize(comment); } if (line.indexOf("***COLORS") != -1) { reading = READING_COLORS; } else if (line.indexOf("***PALETTES") != -1) { reading = READING_PALETTE; QString palettes; QString name; QString numberAndPlus; bool positiveOnly = false; int numColorsInPalette = 0; QTextStream stin(&line, QIODevice::ReadOnly); stin >> palettes >> name >> numberAndPlus; if (numberAndPlus.isEmpty()) { if (name[0] == '[') { numberAndPlus = name; name = "no-name"; } } else if (name.isEmpty()) { throw FileException(filename, "Unreadable palette line"); } const int openBracket = numberAndPlus.indexOf('['); int closeBracket = numberAndPlus.indexOf(']'); const int positiveOnlyPos = numberAndPlus.indexOf('+'); if (positiveOnlyPos != -1) { closeBracket = positiveOnlyPos; positiveOnly = true; } if ((openBracket != -1) && (closeBracket != -1)) { const int len = closeBracket - openBracket - 1; const QString s(numberAndPlus.mid(openBracket + 1, len)); numColorsInPalette = s.toInt(); } else { throw FileException(filename, "Unable to determine number of colors in palette"); } Palette pal(this); pal.setPositiveOnly(positiveOnly); pal.setName(name); for (int i = 0; i < numColorsInPalette; i++) { readLine(stream, line); // comments are like C++ style comments int comment = line.indexOf("//"); if (comment != -1) { line.resize(comment); } float value; QString pointer; QString colorName; QTextStream ins(&line, QIODevice::ReadOnly); ins >> value >> pointer >> colorName; if (colorName.isEmpty() == false) { pal.addPaletteEntry(value, colorName); } else { QString msg("Invalid line in ***PALETTES "); msg.append(name); msg.append(" section: \""); msg.append(line); msg.append("\""); throw FileException(filename, msg); } } addPalette(pal); readPalette = true; } else { switch(reading) { case READING_COLORS: { QString equals; QString name; QString value; QTextStream ins(&line, QIODevice::ReadOnly); ins >> name >> equals >> value; if (value.isEmpty() == false) { unsigned char rgb[3]; if (convertFromXColor(value.toAscii().constData(), rgb) == 0) { PaletteColor pc(name, rgb); addPaletteColor(pc); } } readColors = true; } break; case READING_PALETTE: break; case READING_OTHER: break; } } readLine(stream, line); } } /** * Convert RGB components to X hexadecimal form */ QString PaletteFile::convertToXColor(unsigned char rgb[3]) const { char line[256]; sprintf(line, "#%02x%02x%02x", rgb[0], rgb[1], rgb[2]); return line; } /** * Write the palette file. */ void PaletteFile::writeFileData(QTextStream& stream, QDataStream&, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException) { stream << "***COLORS\n"; for (unsigned int i = 0; i < colors.size(); i++) { unsigned char rgb[3]; colors[i].getRGB(rgb); const QString xColor = convertToXColor(rgb); stream << " " << colors[i].getName() << " = " << xColor << "\n"; } stream << "\n"; for (int k = 0; k < getNumberOfPalettes(); k++) { const Palette* pal = getPalette(k); pal->writeFileData(stream); } } /** * Write the file's memory in caret6 format to the specified name. */ QString PaletteFile::writeFileInCaret6Format(const QString& filenameIn, Structure structure,const ColorFile* colorFileIn, const bool useCaret6ExtensionFlag) throw (FileException) { throw FileException(filenameIn + " cannot be written in Caret6 format at this time."); } caret-5.6.4~dfsg.1.orig/caret_files/PaintFile.h0000664000175000017500000002563611572067322021101 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __PAINT_FILE_H__ #define __PAINT_FILE_H__ #include "FileException.h" #include "GiftiNodeDataFile.h" #include "SpecFile.h" class AreaColorFile; class ColorFile; class CoordinateFile; class DeformationMapFile; class NodeRegionOfInterestFile; class TopologyFile; class VolumeFile; /// This file contains node paint information. class PaintFile : public GiftiNodeDataFile { public: /// name for "Lobes" column static const QString columnNameLobes; /// name for "Geography" column static const QString columnNameGeography; /// name for "Functional" column static const QString columnNameFunctional; /// name for "Brodmann" column static const QString columnNameBrodmann; /// name for "Modality" column static const QString columnNameModality; static const QString tagNumberOfPaintNames; /// number of original paint file columns enum { COLUMN_LOBE = 0, COLUMN_GEO = 1, COLUMN_FCN = 2, COLUMN_BROD = 3, COLUMN_MODALITY = 4 // NUMBER_OF_PAINT_COLUMNS = 5 } COLUMN_INDICES; // constructors PaintFile(const QString& descriptiveName = "Paint File", const QString& defaultExtensionIn = SpecFile::getPaintFileExtension()); // copy constructor PaintFile(const PaintFile& nndf); /// destructor virtual ~PaintFile(); // assignment operator PaintFile& operator=(const PaintFile& nndf); // add a paint name - returns its index int addPaintName(const QString& nameIn); // assign colors to the labels void assignColors(const ColorFile& colorFile); // assign paint from an ROI file void assignNodesFromROIFile(const int columnNumber, const NodeRegionOfInterestFile& roiFile, const QString& paintName, const bool assignNodesInRoiOnlyFlag) throw (FileException); // Clean up paint names (eliminate unused ones) void cleanUpPaintNames(); // clear contents of the current paint file void clear(); // deform "this" node attribute file placing the output in "deformedFile". void deformFile(const DeformationMapFile& dmf, GiftiNodeDataFile& deformedFile, const DEFORM_TYPE dt) const throw (FileException); // get the index for a paint name int getPaintIndexFromName(const QString& nameIn) const; // assign paints by intersecting with a volume file void assignPaintColumnWithVolumeFile(const VolumeFile* vf, const CoordinateFile* cf, const int columnToAssign, const QString& paintName) throw (FileException); // get the name for a paint index QString getPaintNameFromIndex(const int indexIn) const; // get indices to all paint names used by a column void getPaintNamesForColumn(const int column, std::vector& indices) const; // get all the paints for a node void getPaints(const int nodeNumber, int* paints) const; // get paint for a node and column int getPaint(const int nodeNumber, const int columnNumber) const; // find the column of the paint file containing geography int getGeographyColumnNumber() const; // get the number of paint names int getNumberOfPaintNames() const; /// get all paint names and indices sorted by name (may contain duplicate names) void getAllPaintNamesAndIndices(std::vector& namesOut, std::vector& indicesOut) const; // get all paint names (could be duplicates) void getAllPaintNames(std::vector& namesOut) const; // get all paint count (# nodes using each paint) void getAllPaintCounts(std::vector& countsOut) const; // copy one paint column to another in this paint file void copyColumns(const PaintFile* fromPaintFile, const int fromColumnNumber, const int newColumnNumber, const QString& newColumnName = "") throw (FileException); // dilate a paint column void dilateColumn(const TopologyFile* tf, const int columnNumber, const int iterations) throw (FileException); // dilate paint ID "paintIndex" if neighbors paint index >= 0 do only those int dilatePaintID(const TopologyFile* tf, const CoordinateFile* cf, const int columnNumber, const int iterations, const int paintIndex, const int neighborOnlyWithPaintIndex, const float maximumExtent[6]) throw (FileException); // set all the paints for a node void setPaints(const int nodeNumber, const int* paints); // set paint for a node and column void setPaint(const int nodeNumber, const int columnNumber, const int value); // set the name of a paint at an index. void setPaintName(const int indexIn, const QString& name); // get paint enabled by index bool getPaintNameEnabled(const int paintIndex) const; // set paint enable by index void setPaintNameEnabled(const int paintIndex, const bool b); // set all paint names enabled void setAllPaintNamesEnabled(const bool b); // append most common column (if name empty, column is not created) void appendMostCommon(const QString& mostCommonColumnName, const QString& mostCommonExcludeQuestionColumnName) throw (FileException); // delete a paint any nodes using paint become ??? void deletePaintName(const int paintIndex); // deassign a paint any nodes in column using paint become ??? // if columnNumber is negative, operation is applied to all columns void deassignPaintName(const int columnNumber, const int paintIndex); // reassign a paint // if columnNumber is negative, operation is applied to all columns void reassignPaintName(const int columnNumber, const int oldPaintIndex, const int newPaintIndex); // Export to a free surfer label file. void exportFreeSurferAsciiLabelFile(const int columnNumber, const QString& filenamePrefix, const CoordinateFile* cf) throw (FileException); // import free surfer label file(s) void importFreeSurferAsciiLabelFile(const int numNodes, const QString& filename, AreaColorFile* cf, const bool importAllInDirectory) throw (FileException); /// write the file's memory in caret6 format to the specified name virtual QString writeFileInCaret6Format(const QString& filenameIn, Structure structure,const ColorFile* colorFileIn, const bool useCaret6ExtensionFlag) throw (FileException); /// remove prefixes (chars before first period) and/or suffixes (chars after last period) /// from all paint names. void removePrefixesAndSuffixesFromNames(const bool removePrefixesFlag, const bool removeSuffixesFlag); protected: // validate the data arrays (optional for subclasses) virtual void validateDataArrays() throw (FileException); // import a single free surfer label file void importSingleFreeSurferLabelFile(const int column, const int numNodes, AreaColorFile* cf, const QString& filename) throw (FileException); // read the paint node data void readPaintDataForNodes(const std::vector& paintToPaintNameIndex, QFile& file, QTextStream& stream, QDataStream& binStream) throw (FileException); // read paint file data void readLegacyNodeFileData(QFile& file, QTextStream& stream, QDataStream& binStream) throw (FileException); // read paint file data void readFileDataVersion0(QFile& file, QTextStream& stream, QDataStream& binStream) throw (FileException); // read paint file data void readFileDataVersion1(QFile& file, QTextStream& stream, QDataStream& binStream) throw (FileException); // write paint file data void writeLegacyNodeFileData(QTextStream& stream, QDataStream& binStream) throw (FileException); private: // copy helper used by assignment operator and copy constructor void copyHelperPaint(const PaintFile& pf); }; #endif // __PAINT_FILE_H__ #ifdef _PAINT_FILE_MAIN_ const QString PaintFile::columnNameLobes = "Lobes"; const QString PaintFile::columnNameGeography = "Geography"; const QString PaintFile::columnNameFunctional = "Functional"; const QString PaintFile::columnNameBrodmann = "Brodmann"; const QString PaintFile::columnNameModality = "Modality"; const QString PaintFile::tagNumberOfPaintNames = "tag-number-of-paint-names"; #endif // _PAINT_FILE_MAIN_ caret-5.6.4~dfsg.1.orig/caret_files/PaintFile.cxx0000664000175000017500000015207011572067322021445 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #define _PAINT_FILE_MAIN_ #include "PaintFile.h" #undef _PAINT_FILE_MAIN_ #include "AreaColorFile.h" #include "CoordinateFile.h" #include "DeformationMapFile.h" #include "FileUtilities.h" #include "FreeSurferLabelFile.h" #include "GiftiCommon.h" #include "NameIndexSort.h" #include "NodeRegionOfInterestFile.h" #include "SpecFile.h" #include "StringUtilities.h" #include "TopologyFile.h" #include "TopologyHelper.h" #include "VolumeFile.h" /** * Constructor. */ PaintFile::PaintFile(const QString& descriptiveName, const QString& defaultExtensionIn) : GiftiNodeDataFile(descriptiveName, GiftiCommon::intentLabels, GiftiDataArray::DATA_TYPE_INT32, 1, defaultExtensionIn, AbstractFile::FILE_FORMAT_ASCII, FILE_IO_READ_AND_WRITE, FILE_IO_READ_AND_WRITE, FILE_IO_NONE, FILE_IO_NONE, true) { clear(); } /** * copy constructor. */ PaintFile::PaintFile(const PaintFile& pf) : GiftiNodeDataFile(pf) { copyHelperPaint(pf); } /** * Destructor. */ PaintFile::~PaintFile() { clear(); } /** * assignment operator. */ PaintFile& PaintFile::operator=(const PaintFile& pf) { if (this != &pf) { GiftiNodeDataFile::operator=(pf); copyHelperPaint(pf); } return *this; } /** * copy helper used by assignment operator and copy constructor. */ void PaintFile::copyHelperPaint(const PaintFile& /*pf*/) { } class LabelOldToNew { public: LabelOldToNew(const QString& nameIn) { this->name = nameIn; this->newIndex = -1; this->usedFlag = false; this->duplicateFlag = false; } int newIndex; QString name; bool usedFlag; bool duplicateFlag; }; /** * Clean up paint names (elminate unused ones). */ void PaintFile::cleanUpPaintNames() { const int numNodes = getNumberOfNodes(); const int numCols = getNumberOfColumns(); if ((numNodes == 0) || (numCols == 0)) { labelTable.clear(); return; } int numLabels = this->labelTable.getNumberOfLabels(); if (numLabels <= 0) { return; } /* * Create a mapping that will map old indices to new indices * after unused and duplicate labels are removed. */ std::vector labelsOldToNew; labelsOldToNew.reserve(numLabels); for (int m = 0; m < numLabels; m++) { LabelOldToNew lotn(this->labelTable.getLabel(m)); labelsOldToNew.push_back(lotn); } /* * Find duplicate label names. */ for (int m = 0; m < (numLabels - 1); m++) { if (labelsOldToNew[m].duplicateFlag == false) { const QString& labelName = this->labelTable.getLabel(m); for (int n = (m + 1); n < numLabels; n++) { const QString& dupLabelName = this->labelTable.getLabel(n); if (labelName == dupLabelName) { labelsOldToNew[n].duplicateFlag = true; if (DebugControl::getDebugOn()) { std::cout << "Duplicate label: " << dupLabelName.toAscii().constData() << std::endl; } } } } } /* * Find labels that are used. */ for (int i = 0; i < numNodes; i++) { for (int j = 0; j < numCols; j++) { const int labelIndex = this->getPaint(i, j); labelsOldToNew[labelIndex].usedFlag = true; } } /* * Remove duplicate and unused labels * Need to start at last index since labels are * being removed. */ int numUsedLabels = 0; for (int m = (numLabels - 1); m >= 0; m--) { const QString& labelName = this->getLabelTable()->getLabel(m); if (labelsOldToNew[m].usedFlag == false) { this->labelTable.deleteLabel(m); if (DebugControl::getDebugOn()) { std::cout << "Label is not used: " << labelName.toAscii().constData() << std::endl; } } else if (labelsOldToNew[m].duplicateFlag) { this->labelTable.deleteLabel(m); if (DebugControl::getDebugOn()) { std::cout << "Label is duplicate: " << labelName.toAscii().constData() << std::endl; } } else { numUsedLabels++; } } if (DebugControl::getDebugOn()) { std::cout << "Labels UNused: " << (numLabels - numUsedLabels) << std::endl; std::cout << "Labels used: " << numUsedLabels << std::endl; } /* * If no labels are removed, then exit. */ if (numLabels == numUsedLabels) { return; } /* * Create a mapping from old indices to new indices * now that labels have been removed. */ int numOldLabels = static_cast(labelsOldToNew.size()); for (int m = 0; m < numOldLabels; m++) { const QString& labelName = labelsOldToNew[m].name; int newIndex = this->labelTable.getLabelIndex(labelName); labelsOldToNew[m].newIndex = newIndex; } /* * Update to new label indices. */ for (int i = 0; i < numNodes; i++) { for (int j = 0; j < numCols; j++) { int oldIndex = this->getPaint(i, j); int newIndex = labelsOldToNew[oldIndex].newIndex; if (newIndex >= 0) { this->setPaint(i, j, newIndex); } else { std::cout << "PROGRAM ERROR Cleaning paint names: " << "New index for " << labelsOldToNew[oldIndex].name.toAscii().constData() << " is invalid."; } } } // GiftiLabelTable newLabelTable; // // // // Loop through all label names mapping into new label table // // // std::map namesToIndicesMap; // std::vector remapIndices; // namesToIndicesMap.insert(std::make_pair("???", newLabelTable.getNumberOfLabels())); // int remapCount = 0; // for (int i = 0; i < numPaintNames; i++) { // if (i > 0) { // if ((i % 10000) == 0) { // std::cout << "Remap " // << i // << " of " // << numPaintNames // << std::endl; // } // } // const QString paintName = this->getPaintNameFromIndex(i); // std::map::iterator iter = namesToIndicesMap.find(paintName); // int newIndex = -1; // if (iter != namesToIndicesMap.end()) { // newIndex = iter->second; // } // else { // newIndex = newLabelTable.addLabel(paintName);; // namesToIndicesMap.insert(std::make_pair(paintName, newIndex)); // } // if (newIndex != i) { // remapCount++; // } // remapIndices.push_back(newIndex); // } // if (remapCount == 0) { // return; // } // std::cout << "Remapping " // << remapCount // << " paint names." // << std::endl; // // // // Update any indices // // // for (int i = 0; i < numNodes; i++) { // for (int j = 0; j < numCols; j++) { // int paintIndex = this->getPaint(i, j); // if ((paintIndex >=0) && // (paintIndex < numPaintNames)) { // paintIndex = remapIndices[paintIndex]; // this->setPaint(i, j, paintIndex); // } // } // } // // // // Update paint names // // // labelTable.clear(); // int numNewNames = newLabelTable.getNumberOfLabels(); // for (int i = 0; i < numNewNames; i++) { // labelTable.addLabel(newLabelTable.getLabel(i)); // } setModified(); } /** * add a paint name to this paint file. */ int PaintFile::addPaintName(const QString& nameIn) { if (labelTable.empty()) { labelTable.addLabel("???"); } int indx = getPaintIndexFromName(nameIn); if (indx >= 0) { return indx; } setModified(); return labelTable.addLabel(nameIn); } /** * Deform the paint file. */ void PaintFile::deformFile(const DeformationMapFile& dmf, GiftiNodeDataFile& deformedFile, const DEFORM_TYPE /*dt*/) const throw (FileException) { PaintFile& deformedPaintFile = dynamic_cast(deformedFile); const int numNodes = dmf.getNumberOfNodes(); const int numColumns = getNumberOfColumns(); deformedPaintFile.setNumberOfNodesAndColumns(numNodes, numColumns); // // transfer paint names // deformedPaintFile.labelTable = labelTable; // // Transfer stuff in AbstractFile and NodeAttributeFile // transferFileDataForDeformation(dmf, deformedPaintFile); // // transfer the paint columns // int* paints = new int[numColumns]; int tileNodes[3]; float tileAreas[3]; for (int i = 0; i < numNodes; i++) { dmf.getDeformDataForNode(i, tileNodes, tileAreas); if (tileNodes[0] > -1) { getPaints(tileNodes[0], paints); } else { for (int j = 0; j < numColumns; j++) { paints[j] = 0; } } deformedPaintFile.setPaints(i, paints); } delete[] paints; deformedPaintFile.cleanUpPaintNames(); } /** * assign paint from an ROI file. */ void PaintFile::assignNodesFromROIFile(const int columnNumber, const NodeRegionOfInterestFile& roiFile, const QString& paintName, const bool assignNodesInRoiOnlyFlag) throw (FileException) { if ((columnNumber < 0) || (columnNumber >= getNumberOfColumns())) { throw FileException("Column number for ROI paint assignment is invalid."); } const int numNodes = getNumberOfNodes(); if (roiFile.getNumberOfNodes() != numNodes) { throw FileException("ROI paint number of nodes does not match."); } const int paintNameIndex = addPaintName(paintName); if (assignNodesInRoiOnlyFlag) { for (int i = 0; i < numNodes; i++) { if (roiFile.getNodeSelected(i)) { setPaint(i, columnNumber, paintNameIndex); } } } else { const int questionNameIndex = addPaintName("???"); for (int i = 0; i < numNodes; i++) { if (roiFile.getNodeSelected(i)) { setPaint(i, columnNumber, paintNameIndex); } else { setPaint(i, columnNumber, questionNameIndex); } } } } /** * Get the index of the column named "geography" */ int PaintFile::getGeographyColumnNumber() const { const QString geography("geography"); const int numberOfColumns = getNumberOfColumns(); for (int i = 0; i < numberOfColumns; i++) { const QString colNameLowCase(StringUtilities::makeLowerCase(getColumnName(i))); if (colNameLowCase.indexOf(geography) != -1) { return i; } } return -1; } /** * assign colors to the labels. */ void PaintFile::assignColors(const ColorFile& colorFile) { labelTable.assignColors(colorFile); } /** * get the index of a paint name. */ int PaintFile::getPaintIndexFromName(const QString& nameIn) const { return labelTable.getLabelIndex(nameIn); } /** * get the name of a paint at an index. */ QString PaintFile::getPaintNameFromIndex(const int indexIn) const { return labelTable.getLabel(indexIn); } /** * delete a paint any nodes using paint become ???. */ void PaintFile::deletePaintName(const int paintIndex) { const int questPaintIndex = addPaintName("???"); const int numNodes = getNumberOfNodes(); const int numCols = getNumberOfColumns(); for (int i = 0; i < numNodes; i++) { for (int j = 0; j < numCols; j++) { const int indx = getPaint(i, j); if (indx == paintIndex) { setPaint(i, j, questPaintIndex); } else if (indx > paintIndex) { // // Move "higher" paint indices down one since "paintIndex" // will be removed. // setPaint(i, j, indx - 1); } } } labelTable.deleteLabel(paintIndex); } /** * deassign a paint any nodes in column using paint become ??? * if columnNumber is negative, operation is applied to all columns. */ void PaintFile::deassignPaintName(const int columnNumber, const int paintIndex) { const int questPaintIndex = addPaintName("???"); reassignPaintName(columnNumber, paintIndex, questPaintIndex); } /** * reassign a paint * if columnNumber is negative, operation is applied to all columns. */ void PaintFile::reassignPaintName(const int columnNumber, const int oldPaintIndex, const int newPaintIndex) { int colStart = 0; int colEnd = getNumberOfColumns(); if ((columnNumber >= 0) && (columnNumber < getNumberOfColumns())) { colStart = columnNumber; colEnd = columnNumber + 1; } else if (columnNumber >= getNumberOfColumns()) { return; } const int numNodes = getNumberOfNodes(); for (int i = 0; i < numNodes; i++) { for (int j = colStart; j < colEnd; j++) { const int indx = getPaint(i, j); if (indx == oldPaintIndex) { setPaint(i, j, newPaintIndex); } } } } /** * set the name of a paint at an index. */ void PaintFile::setPaintName(const int indexIn, const QString& name) { labelTable.setLabel(indexIn, name); setModified(); } /** * get paint enabled by index. */ bool PaintFile::getPaintNameEnabled(const int paintIndex) const { return labelTable.getLabelEnabled(paintIndex); } /** * set paint enable by index. */ void PaintFile::setPaintNameEnabled(const int paintIndex, const bool b) { labelTable.setLabelEnabled(paintIndex, b); } /** * set all paint names enabled. */ void PaintFile::setAllPaintNamesEnabled(const bool b) { labelTable.setAllLabelsEnabled(b); } /** * get the number of paint names. */ int PaintFile::getNumberOfPaintNames() const { return labelTable.getNumberOfLabels(); } /** * get all paint names and indices sorted by name (may contain duplicate names). */ void PaintFile::getAllPaintNamesAndIndices(std::vector& namesOut, std::vector& indicesOut) const { namesOut.clear(); indicesOut.clear(); // // Sort by name // NameIndexSort nis; const int num = getNumberOfPaintNames(); for (int i = 0; i < num; i++) { nis.add(i, getPaintNameFromIndex(i)); } nis.sortByNameCaseSensitive(); // // Output sorted names/indices // const int numNames = nis.getNumberOfItems(); for (int i = 0; i < numNames; i++) { int indx; QString name; nis.getSortedNameAndIndex(i, indx, name); namesOut.push_back(name); indicesOut.push_back(indx); } } /** * get all paint names (could be duplicates). */ void PaintFile::getAllPaintNames(std::vector& namesOut) const { namesOut.clear(); const int num = getNumberOfPaintNames(); for (int i = 0; i < num; i++) { namesOut.push_back(getPaintNameFromIndex(i)); } } /** * get all paint count (# nodes using each paint). */ void PaintFile::getAllPaintCounts(std::vector& countsOut) const { countsOut.clear(); const int num = getNumberOfPaintNames(); if (num <= 0) { return; } countsOut.resize(num, 0); const int numNodes = getNumberOfNodes(); const int numCols = getNumberOfColumns(); for (int i = 0; i < numNodes; i++) { for (int j = 0; j < numCols; j++) { countsOut[getPaint(i, j)]++; } } } /** * Get indices to all paint names used by a column. */ void PaintFile::getPaintNamesForColumn(const int column, std::vector& indices) const { indices.clear(); std::set invalidPaintIndices; const int numNames = getNumberOfPaintNames(); if (numNames > 0) { std::vector namesUsed(numNames, -1); const int numNodes = getNumberOfNodes(); for (int i = 0; i < numNodes; i++) { int paintIndex = this->getPaint(i, column); if ((paintIndex >= 0) && (paintIndex < numNames)) { namesUsed[paintIndex] = 1; } else { invalidPaintIndices.insert(paintIndex); } } for (int i = 0; i < numNames; i++) { if (namesUsed[i] >= 0) { indices.push_back(i); } } if (invalidPaintIndices.empty() == false) { std::cout << "Invalid paint indices:"; for (std::set::iterator iter = invalidPaintIndices.begin(); iter != invalidPaintIndices.end(); iter++) { std::cout << " " << *iter; } std::cout << std::endl; } } } /** * Clear this file. */ void PaintFile::clear() { GiftiNodeDataFile::clear(); setNumberOfNodesAndColumns(0, 0); } /** * Get all of the paints for a node. User must allocate "getNumberOfNodes" number * of ints for seconds parameter. */ void PaintFile::getPaints(const int nodeNumber, int* paints) const { const int numberOfColumns = getNumberOfColumns(); for (int i = 0; i < numberOfColumns; i++) { int32_t* nodePaints = dataArrays[i]->getDataPointerInt(); paints[i] = nodePaints[nodeNumber]; } } /** * Get a paint for a specified node and index. */ int PaintFile::getPaint(const int nodeNumber, const int columnNumber) const { if ((columnNumber >= 0) && (columnNumber < getNumberOfDataArrays())) { int32_t* nodePaints = dataArrays[columnNumber]->getDataPointerInt(); return nodePaints[nodeNumber]; } return 0; } /** * Set all of the paints for a node. */ void PaintFile::setPaints(const int nodeNumber, const int* paints) { const int numberOfColumns = getNumberOfColumns(); for (int i = 0; i < numberOfColumns; i++) { int32_t* nodePaints = dataArrays[i]->getDataPointerInt(); nodePaints[nodeNumber] = paints[i]; } setModified(); } /** * Set a paint for a specified node and column. */ void PaintFile::setPaint(const int nodeNumber, const int columnNumber, const int paint) { if ((columnNumber >= 0) && (columnNumber < getNumberOfDataArrays())) { int32_t* nodePaints = dataArrays[columnNumber]->getDataPointerInt(); nodePaints[nodeNumber] = paint; setModified(); } } /** * copy one paint column to another. */ void PaintFile::copyColumns(const PaintFile* fromPaintFile, const int fromColumnNumber, const int newColumnNumberIn, const QString& newColumnName) throw (FileException) { if (fromPaintFile == NULL) { throw FileException("PaintFile::copyColumns() fromPaintFile is NULL."); } // // Validate column numbers // if ((fromColumnNumber < 0) || (fromColumnNumber >= fromPaintFile->getNumberOfColumns())) { throw FileException("PaintFile::copyColumns() fromColumnNumber is invalid."); } int newColumnNumber = newColumnNumberIn; if ((newColumnNumber < 0) || (newColumnNumber >= getNumberOfColumns())) { addColumns(1, fromPaintFile->getNumberOfNodes()); newColumnNumber = getNumberOfColumns() - 1; } // // Copy the metadata // GiftiMetaData* newColMetaData = getDataArray(newColumnNumber)->getMetaData(); GiftiMetaData* oldColMetaData = (GiftiMetaData*)fromPaintFile->getDataArray(fromColumnNumber)->getMetaData(); *newColMetaData = *oldColMetaData; // // Index for copying of paint names // std::vector paintNameIndexTranslation(fromPaintFile->getNumberOfPaintNames(), -1); const int numNodes = getNumberOfNodes(); for (int i = 0; i < numNodes; i++) { const int paintIndex = fromPaintFile->getPaint(i, fromColumnNumber); if (paintIndex >= 0) { paintNameIndexTranslation[paintIndex] = -2; } } for (int i = 0; i < static_cast(paintNameIndexTranslation.size()); i++) { if (paintNameIndexTranslation[i] == -2) { paintNameIndexTranslation[i] = addPaintName(fromPaintFile->getPaintNameFromIndex(i)); } } // // Copy the paint data // for (int i = 0; i < numNodes; i++) { setPaint(i, newColumnNumber, paintNameIndexTranslation[fromPaintFile->getPaint(i, fromColumnNumber)]); } if (newColumnName.isEmpty() == false) { setColumnName(newColumnNumber, newColumnName); } } /** * Dilate a paint column. */ void PaintFile::dilateColumn(const TopologyFile* tf, const int columnNumber, const int iterations) throw (FileException) { // // Validate column numbers // if (tf == NULL) { throw FileException("PaintFile::dilateColumn() topology is invalid."); } if ((columnNumber < 0) || (columnNumber >= getNumberOfColumns())) { throw FileException("PaintFile::dilateColumn() columnNumber is invalid."); } // // Get unassigned paint index // const int unassignedPaintIndex = addPaintName("???"); // // Get topology helper for neighbor information // const TopologyHelper* th = tf->getTopologyHelper(false, true, false); // // temporary and used to during dilation // const int numNodes = getNumberOfNodes(); int* outputPaints = new int[numNodes]; // // Do for specified number of iterations // for (int iter = 0; iter < iterations; iter++) { // // Copy current paints // for (int i = 0; i < numNodes; i++) { outputPaints[i] = getPaint(i, columnNumber); } // // Check each node // for (int i = 0; i < numNodes; i++) { // // Dilate into neighboring nodes // const int paintIndex = getPaint(i, columnNumber); if (paintIndex != unassignedPaintIndex) { int numNeighbors; const int* neighbors = th->getNodeNeighbors(i, numNeighbors); for (int j = 0; j < numNeighbors; j++) { const int neighborNodeNum = neighbors[j]; if (outputPaints[neighborNodeNum] == unassignedPaintIndex) { outputPaints[neighborNodeNum] = paintIndex; } } } } // // Set current paints // for (int i = 0; i < numNodes; i++) { setPaint(i, columnNumber, outputPaints[i]); } } // // Free memory // delete[] outputPaints; } /** * dilate paint ID "paintIndex" if neighbors paint index >= 0 do only those. */ int PaintFile::dilatePaintID(const TopologyFile* tf, const CoordinateFile* cf, const int columnNumber, const int iterations, const int paintIndex, const int neighborOnlyWithPaintIndex, const float maximumExtent[6]) throw (FileException) { int numDilated = 0; // // Validate column numbers // if ((columnNumber < 0) || (columnNumber >= getNumberOfColumns())) { throw FileException("PaintFile::dilatePaintID() columnNumber is invalid."); } if (iterations <= 0) { return numDilated; } const int numNodes = getNumberOfNodes(); if (numNodes <= 0) { return numDilated; } // // Get topology helper for neighbor information // const TopologyHelper* th = tf->getTopologyHelper(false, true, false); // // temporary and used to during dilation // int* outputPaints = new int[numNodes]; // // Do for specified number of iterations // for (int iter = 0; iter < iterations; iter++) { // // Copy current paints // for (int i = 0; i < numNodes; i++) { outputPaints[i] = getPaint(i, columnNumber); } // // Check each node // for (int i = 0; i < numNodes; i++) { // // does node contain paint that is to be smoothed // const int paint = getPaint(i, columnNumber); if (paint == paintIndex) { // // Check extent // const float* nodeXYZ = cf->getCoordinate(i); if ((nodeXYZ[0] >= maximumExtent[0]) && (nodeXYZ[0] <= maximumExtent[1]) && (nodeXYZ[1] >= maximumExtent[2]) && (nodeXYZ[1] <= maximumExtent[3]) && (nodeXYZ[2] >= maximumExtent[4]) && (nodeXYZ[2] <= maximumExtent[5])) { // // get neighbors and loop through them // int numNeighbors; const int* neighbors = th->getNodeNeighbors(i, numNeighbors); for (int j = 0; j < numNeighbors; j++) { const int neighborNodeNum = neighbors[j]; // // Limited to neighbors with specific paint index? // if (neighborOnlyWithPaintIndex >= 0) { if (getPaint(neighborNodeNum, columnNumber) == neighborOnlyWithPaintIndex) { outputPaints[neighborNodeNum] = paintIndex; numDilated++; } } else { outputPaints[neighborNodeNum] = paintIndex; numDilated++; } } } } } // // Set current paints // for (int i = 0; i < numNodes; i++) { setPaint(i, columnNumber, outputPaints[i]); } } delete[] outputPaints; return numDilated; } /** * append most common column (if name empty, column is not created). */ void PaintFile::appendMostCommon(const QString& mostCommonColumnName, const QString& mostCommonExcludeQuestionColumnName) throw (FileException) { const int numNodes = getNumberOfNodes(); const int numCols = getNumberOfColumns(); if ((numNodes <= 0) || (numCols <= 0)) { return; } if ((mostCommonColumnName.isEmpty() == true) && (mostCommonExcludeQuestionColumnName.isEmpty() == true)) { return; } int mostCommonColumn = -1; if (mostCommonColumnName.isEmpty() == false) { addColumns(1); mostCommonColumn = getNumberOfColumns() - 1; setColumnName(mostCommonColumn, mostCommonColumnName); } int mostCommonExcludeQuestionColumn = -1; if (mostCommonExcludeQuestionColumnName.isEmpty() == false) { addColumns(1); mostCommonExcludeQuestionColumn = getNumberOfColumns() - 1; setColumnName(mostCommonExcludeQuestionColumn, mostCommonExcludeQuestionColumnName); } const int questionPaintIndex = getPaintIndexFromName("???"); for (int i = 0; i < numNodes; i++) { // // Track use of paint indices for the node // std::map indexCounterMap, indexCounterMapExcludeQuestion; for (int j = 0; j < numCols; j++) { const int paintIndex = getPaint(i, j); // // Doing most common? // if (mostCommonColumn >= 0) { // // Update count for paint index // std::map::iterator iter = indexCounterMap.find(paintIndex); if (iter != indexCounterMap.end()) { iter->second++; } else { indexCounterMap[paintIndex] = 1; } } // // Doing most common but excluding ??? paints // if ((mostCommonExcludeQuestionColumn >= 0) && (paintIndex != questionPaintIndex)) { // // Update count for paint index // std::map::iterator iter = indexCounterMapExcludeQuestion.find(paintIndex); if (iter != indexCounterMapExcludeQuestion.end()) { iter->second++; } else { indexCounterMapExcludeQuestion[paintIndex] = 1; } } } // // set paint most common index // if (mostCommonColumn >= 0) { int maxIndex = questionPaintIndex; int maxCount = -1; for (std::map::iterator iter = indexCounterMap.begin(); iter != indexCounterMap.end(); iter++) { if (iter->second > maxCount) { maxIndex = iter->first; maxCount = iter->second; } } setPaint(i, mostCommonColumn, maxIndex); } // // set paint most common index // if (mostCommonExcludeQuestionColumn >= 0) { int maxIndex = questionPaintIndex; int maxCount = -1; for (std::map::iterator iter = indexCounterMapExcludeQuestion.begin(); iter != indexCounterMapExcludeQuestion.end(); iter++) { if (iter->second > maxCount) { maxIndex = iter->first; maxCount = iter->second; } } setPaint(i, mostCommonExcludeQuestionColumn, maxIndex); } } } /** * assign paints by intersecting with a volume file. * If a coordinate is within a non-zero voxel, the paintName is assigned for that coordinate. * This was known as IntersectVolumeWithSurface in SureFit. */ void PaintFile::assignPaintColumnWithVolumeFile(const VolumeFile* vf, const CoordinateFile* cf, const int columnToAssign, const QString& paintName) throw (FileException) { if (vf == NULL) { throw FileException("Invalid volume file (NULL)."); } if (cf == NULL) { throw FileException("Invalid coordinate file (NULL)."); } if (getNumberOfNodes() <= 0) { throw FileException("Paint file has not been allocated (no nodes)."); } if ((columnToAssign < 0) || (columnToAssign >= getNumberOfColumns())) { throw FileException("Paint column is invalid."); } if (getNumberOfNodes() != cf->getNumberOfCoordinates()) { throw FileException("Paint file has different number of coordinates that coordinate file."); } // // Index of paint name // const int paintIndex = addPaintName(paintName); // // Loop through coordinates // const int numCoords = cf->getNumberOfCoordinates(); for (int i = 0; i < numCoords; i++) { // // Convert coordinate to a voxel index // int ijk[3]; if (vf->convertCoordinatesToVoxelIJK(cf->getCoordinate(i), ijk)) { // // assign the paint column for the node if the voxel is non-zero // if (vf->getVoxel(ijk) != 0) { setPaint(i, columnToAssign, paintIndex); } } } } /** * Remove prefixes (chars before first period) and/or suffixes (chars after last period) * from all paint names. */ void PaintFile::removePrefixesAndSuffixesFromNames(const bool removePrefixesFlag, const bool removeSuffixesFlag) { int numPaintNames = this->getNumberOfPaintNames(); for (int i = 0; i < numPaintNames; i++) { QString name = this->getPaintNameFromIndex(i); bool nameChangedFlag = false; if (removePrefixesFlag) { int firstPeriod = name.indexOf("."); if (firstPeriod >= 0) { name = name.mid(firstPeriod + 1); nameChangedFlag = true; } } if (removeSuffixesFlag) { int lastPeriod = name.lastIndexOf("."); if (lastPeriod >= 0) { name = name.left(lastPeriod); nameChangedFlag = true; } } if (nameChangedFlag) { this->setPaintName(i, name); } } } /** * Read a paint file' data. */ void PaintFile::readLegacyNodeFileData(QFile& file, QTextStream& stream, QDataStream& binStream) throw (FileException) { QString line; //const qint64 pos = stream.pos(); //file.pos(); const qint64 pos = this->getQTextStreamPosition(stream); readLine(stream, line); int fileVersion = 0; QString versionTag; QTextStream(&line, QIODevice::ReadOnly) >> versionTag >> fileVersion; if (tagFileVersion != versionTag) { fileVersion = 0; if (file.seek(pos) == false) { std::cout << "ERROR: file.seek(" << pos << ") failed at " << __LINE__ << " in " << __FILE__ << std::endl; } stream.seek(pos); } switch(fileVersion) { case 0: readFileDataVersion0(file, stream, binStream); break; case 1: readFileDataVersion1(file, stream, binStream); break; default: throw FileException(filename, "Unknown version number. Perhaps paint file format is " "newer than the caret you are using."); break; } } /** * Read a version 1 paint file. */ void PaintFile::readFileDataVersion1(QFile& file, QTextStream& stream, QDataStream& binStream) throw (FileException) { QString line; int numNodes = -1; int numCols = -1; int numPaintNames = -1; bool readingTags = true; while(readingTags) { QString tag, tagValue; readTagLine(stream, tag, tagValue); if (tag == tagBeginData) { readingTags = false; } else if (tag == tagNumberOfNodes) { numNodes = tagValue.toInt(); if ((numNodes > 0) && (numCols > 0)) { setNumberOfNodesAndColumns(numNodes, numCols); } } else if (tag == tagNumberOfColumns) { numCols = tagValue.toInt(); if ((numNodes > 0) && (numCols > 0)) { setNumberOfNodesAndColumns(numNodes, numCols); } } else if (tag == tagFileTitle) { fileTitle = tagValue; } else if (tag == tagColumnName) { QString name; const int indx = splitTagIntoColumnAndValue(tagValue, name); setColumnName(indx, name); } else if (tag == tagColumnComment) { QString name; const int indx = splitTagIntoColumnAndValue(tagValue, name); setColumnComment(indx, StringUtilities::setupCommentForDisplay(name)); } else if (tag == tagColumnStudyMetaData) { QString name; const int indx = splitTagIntoColumnAndValue(tagValue, name); StudyMetaDataLinkSet smdls; smdls.setLinkSetFromCodedText(name); setColumnStudyMetaDataLinkSet(indx, smdls); } else if (tag == tagNumberOfPaintNames) { numPaintNames = tagValue.toInt(); } else { std::cerr << "WARNING: Unknown Paint File Tag: " << tag.toAscii().constData() << std::endl; } } if ((numNodes <= 0) && (numCols <= 0)) { throw FileException(filename, "Number of nodes or columns invalid "); } if (numPaintNames <= 0) { throw FileException(filename, "Number of paint names invalid "); } // // Should reading data be skipped ? // if (getReadMetaDataOnlyFlag()) { return; } // // Duplicate paint names will be discarded by "addPaintName" which will // return the index to use for the paint name // #ifdef QT4_FILE_POS_BUG QString lastLineRead; #endif // QT4_FILE_POS_BUG std::vector paintToPaintNameIndex; for (int m = 0; m < numPaintNames; m++) { QString nameLine; #ifdef QT4_FILE_POS_BUG nameLine = file.readLine().trimmed(); #else // QT4_FILE_POS_BUG readLine(stream, nameLine); #endif // QT4_FILE_POS_BUG QString name; int n; #ifdef QT4_FILE_POS_BUG lastLineRead = nameLine; #endif // QT4_FILE_POS_BUG QTextStream(&nameLine, QIODevice::ReadOnly) >> n >> name; paintToPaintNameIndex.push_back(addPaintName(name)); } #ifdef QT4_FILE_POS_BUG if (getFileReadType() == FILE_FORMAT_BINARY) { if (lastLineRead.isEmpty() == false) { qint64 offset = findBinaryDataOffsetQT4Bug(file, lastLineRead.toAscii().constData()); if (offset > 0) { offset++; file.seek(offset); } } } #endif // QT4_FILE_POS_BUG readPaintDataForNodes(paintToPaintNameIndex, file, stream, binStream); } /** * Read a version 0 paint file. */ void PaintFile::readFileDataVersion0(QFile& file, QTextStream& stream, QDataStream& binStream) throw (FileException) { bool readingPaints = true; // // Need to keep paint names here because "setNumberOfNodesAndColumns" // would erase them // std::vector tempPaintNames; QString line; while (readingPaints) { std::vector tokens; readLineIntoTokens(stream, line, tokens); if (tokens.size() == 2) { tempPaintNames.push_back(tokens[1]); } else { readingPaints = false; } } const int numNodes = line.toInt(); //QString line; //readLine(stream, line); //const int numNodes = line.toInt(); const int numColumns = 5; setNumberOfNodesAndColumns(numNodes, numColumns); setColumnName(0, "Lobes"); setColumnName(1, "Geography"); setColumnName(2, "Functional"); setColumnName(3, "Brodmann"); setColumnName(4, "Modality"); // // Should reading data be skipped ? // if (getReadMetaDataOnlyFlag()) { return; } // // Duplicate paint names will be discarded by "addPaintName" which will // return the index to use for the paint name // std::vector paintToPaintNameIndex; // // Transfer paint names now that setNumberOfNodesAndColumns has been called // for (unsigned int m = 0; m < tempPaintNames.size(); m++) { paintToPaintNameIndex.push_back(addPaintName(tempPaintNames[m])); } readPaintDataForNodes(paintToPaintNameIndex, file, stream, binStream); } /** * Read the paint data for the nodes. */ void PaintFile::readPaintDataForNodes(const std::vector& paintToPaintNameIndex, QFile& file, QTextStream& stream, QDataStream& binStream) throw (FileException) { //file.seek(stream.pos()); // QT 4.2.2 const qint64 streamPos = this->getQTextStreamPosition(stream); file.seek(streamPos); QString line; std::vector tokens; const int numberOfNodes = getNumberOfNodes(); const int numberOfColumns = getNumberOfColumns(); int* cols = new int[numberOfColumns]; switch (getFileReadType()) { case FILE_FORMAT_ASCII: for (int i = 0; i < numberOfNodes; i++) { readLineIntoTokens(stream, line, tokens); if (static_cast(tokens.size()) < (numberOfColumns+ 1)) { throw FileException(filename, "invalid paint data line: \n" + line); } for (int n = 0; n < numberOfColumns; n++) { const int indx = tokens[n+1].toInt(); if ((indx < 0) || (indx >= static_cast(paintToPaintNameIndex.size()))) { throw FileException(filename, "invalid paint index =" + QString::number(indx) + " node=" + QString::number(i)); } else { cols[n] = paintToPaintNameIndex[indx]; } } setPaints(i, cols); } break; case FILE_FORMAT_BINARY: for (int j = 0; j < numberOfNodes; j++) { for (int k = 0; k < numberOfColumns; k++) { binStream >> cols[k]; } setPaints(j, cols); } break; case FILE_FORMAT_XML: throw FileException(filename, "Writing in XML format not supported."); break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Writing XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Writing in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Comma Separated Value File Format not supported."); break; } delete[] cols; } /** * Write a paint file's data. */ void PaintFile::writeLegacyNodeFileData(QTextStream& stream, QDataStream& binStream) throw (FileException) { const int numberOfNodes = getNumberOfNodes(); const int numberOfColumns = getNumberOfColumns(); // // output tags // stream << tagFileVersion << " 1\n"; stream << tagNumberOfNodes << " " << numberOfNodes << "\n"; stream << tagNumberOfColumns << " " << numberOfColumns << "\n"; stream << tagFileTitle << " " << fileTitle << "\n"; const int numLabels = labelTable.getNumberOfLabels(); stream << tagNumberOfPaintNames << " " << numLabels << "\n"; for (int m = 0; m < numberOfColumns; m++) { stream << tagColumnName << " " << m << " " << getColumnName(m) << "\n"; stream << tagColumnComment << " " << m << " " << StringUtilities::setupCommentForStorage(getColumnComment(m)) << "\n"; } for (int k = 0; k < numberOfColumns; k++) { stream << tagColumnStudyMetaData << " " << k << " " << getColumnStudyMetaDataLinkSet(k).getLinkSetAsCodedText().toAscii().constData() << "\n"; } stream << tagBeginData << "\n"; // // Output Paint names // for (int i = 0; i < numLabels; i++) { stream << i << " " << labelTable.getLabel(i) << "\n"; } // // Output paint columns // int* pti = new int[numberOfColumns]; switch (getFileWriteType()) { case FILE_FORMAT_ASCII: for (int j = 0; j < numberOfNodes; j++) { stream << j; getPaints(j, pti); for (int k = 0; k < numberOfColumns; k++) { stream << " " << pti[k]; } stream << "\n"; } break; case FILE_FORMAT_BINARY: #ifdef QT4_FILE_POS_BUG setBinaryFilePosQT4Bug(); #else // QT4_FILE_POS_BUG // // still a bug in QT 4.2.2 // setBinaryFilePosQT4Bug(); #endif // QT4_FILE_POS_BUG for (int j = 0; j < numberOfNodes; j++) { getPaints(j, pti); for (int k = 0; k < numberOfColumns; k++) { binStream << pti[k]; } } break; case FILE_FORMAT_XML: throw FileException(filename, "Writing in XML format not supported."); break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Writing XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Writing in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Comma Separated Value File Format not supported."); break; } delete[] pti; } /** * Export to a free surfer label file. */ void PaintFile::exportFreeSurferAsciiLabelFile(const int columnNumber, const QString& filenamePrefix, const CoordinateFile* cf) throw (FileException) { if ((columnNumber >= 0) && (columnNumber < getNumberOfColumns())) { // // Find paints that are to be exported // std::set exportedPaints; const int numNodes = getNumberOfNodes(); for (int i = 0; i < numNodes; i++) { const int value = getPaint(i, columnNumber); if (value > 0) { if (exportedPaints.find(value) == exportedPaints.end()) { exportedPaints.insert(value); const QString paintName(getPaintNameFromIndex(value)); QString filename(""); if (filenamePrefix.isEmpty() == false) { filename.append(filenamePrefix); filename.append(QDir::separator()); } filename.append(paintName); //filename.append(".label"); // // Find the nodes that have this paint // std::vector matchingNodes; for (int j = i; j < numNodes; j++) { if (getPaint(j, columnNumber) == value) { matchingNodes.push_back(j); } } // // are there any matching nodes // const int numMatchingNodes = matchingNodes.size(); if (numMatchingNodes > 0) { FreeSurferLabelFile fslf; fslf.setNumberOfLabelItems(numMatchingNodes); // // Transfer the label data // for (int k = 0; k < numMatchingNodes; k++) { float xyz[3]; cf->getCoordinate(matchingNodes[k], xyz); fslf.setLabelItem(k, matchingNodes[k], xyz); } // // Write the file // fslf.writeFile(filename); } } } } } else { throw FileException(filename, "Invalid column number for export."); } } /** * Import Free Surfer label file(s). */ void PaintFile::importFreeSurferAsciiLabelFile(const int numNodes, const QString& filename, AreaColorFile* colorFile, const bool importAllInDirectory) throw (FileException) { if (numNodes == 0) { throw FileException(filename, "A surface must be loaded prior to importing a " "FreeSurfer label file."); } // // Add a column to this surface shape file // if (getNumberOfColumns() == 0) { setNumberOfNodesAndColumns(numNodes, 1); } else { addColumns(1); } const int columnNumber = getNumberOfColumns() - 1; // // Set the name of the column to the name of the curvature file // setColumnName(columnNumber, FileUtilities::basename(filename)); setModified(); if (importAllInDirectory) { // // Find all label files in the directory // QString directoryName(FileUtilities::dirname(filename)); if (directoryName.isEmpty()) { directoryName = "."; } std::vector labelFiles; FileUtilities::findFilesInDirectory(directoryName, QStringList("*.label"), labelFiles); // // Import all of the label files found // for (int i = 0; i < static_cast(labelFiles.size()); i++) { QString name; if (directoryName.isEmpty() == false) { name = directoryName; name.append("/"); } name.append(labelFiles[i]); importSingleFreeSurferLabelFile(columnNumber, numNodes, colorFile, name); } if (labelFiles.size() > 0) { appendToFileComment(" Imported from multiple files starting with "); appendToFileComment(FileUtilities::basename(labelFiles[0])); } else { throw FileException("No file found in directory \"" + directoryName + "\" that have file name extension \".label\""); } } else { // // Import just this label file // importSingleFreeSurferLabelFile(columnNumber, numNodes, colorFile, filename); appendToFileComment(" Imported from "); appendToFileComment(FileUtilities::basename(filename)); } } /** * Import a single free surfer label file to the specified paint column. */ void PaintFile::importSingleFreeSurferLabelFile(const int columnNumber, const int numNodes, AreaColorFile* colorFile, const QString& filename) throw (FileException) { FreeSurferLabelFile fslf; fslf.readFile(filename); // // Extract the paint area/name from the file's name // QString nameOfPaint; QString fileBasename(FileUtilities::basename(filename)); const int nameStart = filename.indexOf(fileBasename, '-'); const int nameEnd = filename.indexOf(fileBasename, '.'); if ((nameStart != -1) && (nameEnd != -1) && (nameEnd > nameStart)) { const int len = nameEnd - nameStart - 1; nameOfPaint = fileBasename.mid(nameStart + 1, len); } else { nameOfPaint = fileBasename; } const int paintIndex = addPaintName(nameOfPaint); // // Add name to area colors // if (colorFile != NULL) { bool match = false; const int colorIndex = colorFile->getColorIndexByName(nameOfPaint, match); if ((match == false) || (colorIndex < 0)) { colorFile->addColor(nameOfPaint, 255, 0, 0); } } // // Read in label data // const int numItems = fslf.getNumberOfLabelItems(); for (int i = 0; i < numItems; i++) { int nodeNumber; float xyz[3]; fslf.getLabelItem(i, nodeNumber, xyz); if (nodeNumber >= numNodes) { std::ostringstream str; str << "Node " << nodeNumber << " from label file " << nameOfPaint.toAscii().constData() << " is greater than number of nodes in the surface."; throw FileException(filename, str.str().c_str()); } setPaint(nodeNumber, columnNumber, paintIndex); } } /** * Write the file's memory in caret6 format to the specified name. */ QString PaintFile::writeFileInCaret6Format(const QString& filenameIn, Structure structure,const ColorFile* colorFileIn, const bool useCaret6ExtensionFlag) throw (FileException) { QString name = filenameIn; if (useCaret6ExtensionFlag) { name = FileUtilities::replaceExtension(filenameIn, ".paint", SpecFile::getGiftiLabelFileExtension()); } if (colorFileIn != NULL) { this->assignColors(*colorFileIn); } this->setFileWriteType(AbstractFile::FILE_FORMAT_XML_GZIP_BASE64); this->writeFile(name); return name; } /** * validate the data arrays (optional for subclasses). */ void PaintFile::validateDataArrays() throw (FileException) { int numNodes = this->getNumberOfNodes(); int numCols = this->getNumberOfColumns(); int numberOfPaintNames = this->getNumberOfPaintNames(); bool negativeIndexCount = 0; std::set invalidPaintIndices; for (int i = 0; i < numNodes; i++) { for (int j = 0; j < numCols; j++) { int paintIndex = this->getPaint(i, j); if (paintIndex >= numberOfPaintNames) { invalidPaintIndices.insert(paintIndex); } else if (paintIndex < 0) { negativeIndexCount++; this->setPaint(i, j, 0); } } } if (negativeIndexCount > 0) { std::cout << negativeIndexCount << " Negative Paint Indices changed to zero." << std::endl; } if (invalidPaintIndices.empty() == false) { for (std::set::iterator iter = invalidPaintIndices.begin(); iter != invalidPaintIndices.end(); iter++) { int indx = *iter; QString name("InvalidIndex_" + QString::number(indx)); this->getLabelTable()->setLabel(indx, name); std::cout << "INFO: added paint name " << name.toAscii().constData() << " for invalid index " << indx << std::endl; } } this->clearModified(); } caret-5.6.4~dfsg.1.orig/caret_files/NodeRegionOfInterestFile.h0000664000175000017500000000517311572067322024054 0ustar michaelmichael #ifndef __NODE_REGION_OF_INTEREST_FILE_H__ #define __NODE_REGION_OF_INTEREST_FILE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "PaintFile.h" class CoordinateFile; class TopologyFile; class VolumeFile; /// class for storing the nodes in a region of interest class NodeRegionOfInterestFile : public PaintFile { public: // constructor NodeRegionOfInterestFile(); // destructor ~ NodeRegionOfInterestFile(); // set number of nodes void setNumberOfNodes(const int numNodes); // get node selected bool getNodeSelected(const int nodeNumber) const; // set node selected void setNodeSelected(const int nodeNumber, const bool status); // get the ROI description QString getRegionOfInterestDescription() const; // set the ROI description (number of nodes must have been set) void setRegionOfInterestDescription(const QString& s); // assign nodes in ROI by intersecting with a volume file void assignSelectedNodesWithVolumeFile(const VolumeFile* vf, const CoordinateFile* cf, const TopologyFile* tf) throw (FileException); protected: /// set the number of nodes and columns in the file virtual void setNumberOfNodesAndColumns(const int numNodes, const int numCols, const int numElementsPerCol = 1); /// paint name index for selected nodes int selectedPaintIndex; /// paint name index for deselected nodes; int deselectedPaintIndex; }; #endif // __NODE_REGION_OF_INTEREST_FILE_H__ caret-5.6.4~dfsg.1.orig/caret_files/NodeRegionOfInterestFile.cxx0000664000175000017500000001143211572067322024422 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CoordinateFile.h" #include "NodeRegionOfInterestFile.h" #include "SpecFile.h" #include "TopologyFile.h" #include "TopologyHelper.h" #include "VolumeFile.h" /** * constructor. */ NodeRegionOfInterestFile::NodeRegionOfInterestFile() : PaintFile("Node Region Of Interest", SpecFile::getRegionOfInterestFileExtension()) { clear(); } /** * destructor. */ NodeRegionOfInterestFile::~NodeRegionOfInterestFile() { } /** * set number of nodes. */ void NodeRegionOfInterestFile::setNumberOfNodes(const int numNodes) { if (numNodes > 0) { setNumberOfNodesAndColumns(numNodes, 1); } else { setNumberOfNodesAndColumns(numNodes, 0); } } /** * set the number of nodes and columns in the file. */ void NodeRegionOfInterestFile::setNumberOfNodesAndColumns(const int numNodes, const int numCols, const int numElementsPerCol) { PaintFile::setNumberOfNodesAndColumns(numNodes, numCols, numElementsPerCol); selectedPaintIndex = addPaintName("Selected"); deselectedPaintIndex = addPaintName("Deselected"); for (int i = 0; i < numNodes; i++) { for (int j = 0; j < numCols; j++) { setPaint(i, j, deselectedPaintIndex); } } } /** * get node selected. */ bool NodeRegionOfInterestFile::getNodeSelected(const int nodeNumber) const { if (getPaint(nodeNumber, 0) == selectedPaintIndex) { return true; } return false; } /** * set node selected. */ void NodeRegionOfInterestFile::setNodeSelected(const int nodeNumber, const bool status) { if (status) { setPaint(nodeNumber, 0, selectedPaintIndex); } else { setPaint(nodeNumber, 0, deselectedPaintIndex); } } /** * assign nodes in ROI by intersecting with a volume file. * If a coordinate is within a non-zero voxel, the node is. * set to selected in the ROI. */ void NodeRegionOfInterestFile::assignSelectedNodesWithVolumeFile(const VolumeFile* vf, const CoordinateFile* cf, const TopologyFile* tf) throw (FileException) { if (vf == NULL) { throw FileException("Invalid volume file (NULL)."); } if (cf == NULL) { throw FileException("Invalid coordinate file (NULL)."); } if (tf == NULL) { throw FileException("Invalid topology file (NULL)."); } if (getNumberOfNodes() <= 0) { throw FileException("Region of Interest file has not been allocated (no nodes)."); } if (getNumberOfNodes() != cf->getNumberOfCoordinates()) { throw FileException("ROI file has different number of coordinates that coordinate file."); } // // Get a topology helper // const TopologyHelper* th = tf->getTopologyHelper(false, true, false); // // // Loop through coordinates // const int numCoords = cf->getNumberOfCoordinates(); for (int i = 0; i < numCoords; i++) { // // If node has neighbors // if (th->getNodeHasNeighbors(i)) { // // Convert coordinate to a voxel index // int ijk[3]; if (vf->convertCoordinatesToVoxelIJK(cf->getCoordinate(i), ijk)) { // // assign the roi for the node if the voxel is non-zero // if (vf->getVoxel(ijk) != 0) { setNodeSelected(i, true); } } } } } /** * get the ROI description. */ QString NodeRegionOfInterestFile::getRegionOfInterestDescription() const { if (getNumberOfColumns() > 0) { return getColumnComment(0); } return ""; } /** * set the ROI description (number of nodes must have been set). */ void NodeRegionOfInterestFile::setRegionOfInterestDescription(const QString& s) { if (getNumberOfColumns() > 0) { setColumnComment(0, s); } } caret-5.6.4~dfsg.1.orig/caret_files/NodeAttributeFile.h0000664000175000017500000001763511572067322022577 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_NODE_ATTRIBUTE_FILE_H__ #define __VE_NODE_ATTRIBUTE_FILE_H__ #include "AbstractFile.h" #include "StudyMetaDataLinkSet.h" class DeformationMapFile; /// This abstract class defines some variables and methods used for node attribute files. class NodeAttributeFile : public AbstractFile { public: /// deformation type enum DEFORM_TYPE { DEFORM_NEAREST_NODE, DEFORM_TILE_AVERAGE }; /// append column index values enum APPEND_COLUMN_INDEX { APPEND_COLUMN_NEW = -1, APPEND_COLUMN_DO_NOT_LOAD = -2 }; /// constructor NodeAttributeFile(const QString& descriptiveName, const QString& defaultExt = "", const FILE_FORMAT defaultWriteTypeIn = FILE_FORMAT_ASCII, const FILE_IO supportsAsciiFormat = FILE_IO_READ_AND_WRITE, const FILE_IO supportsBinaryFormat = FILE_IO_NONE, const FILE_IO supportsXMLFormat = FILE_IO_NONE, const FILE_IO supportsOtherFormat = FILE_IO_NONE); /// destructor virtual ~NodeAttributeFile(); /// append a node attribute file to this one virtual void append(NodeAttributeFile& naf) throw (FileException) = 0; /// append a node attribute file to this one but selectively load/overwrite columns /// columnDestination is where naf's columns should be (-1=new, -2=do not load) virtual void append(NodeAttributeFile& naf, std::vector columnDestination, const FILE_COMMENT_MODE fcm) throw (FileException) = 0; /// add columns to this node attribute file virtual void addColumns(const int numberOfNewColumns) = 0; /// add nodes to this file virtual void addNodes(const int numberOfNodesToAdd) = 0; /// deform "this" node attribute file placing the output in "deformedFile". virtual void deformFile(const DeformationMapFile& dmf, NodeAttributeFile& deformedFile, const DEFORM_TYPE dt) const throw (FileException) = 0; /// deform "this" node attribute file placing the output in "deformedFile". void deform(const DeformationMapFile& dmf, NodeAttributeFile& deformedFile, const DEFORM_TYPE dt) const throw (FileException); /// returns true if the file is isEmpty (contains no data) virtual bool empty() const { return (numberOfNodes == 0); } /// get the number of nodes in the file virtual int getNumberOfNodes() const { return numberOfNodes; } /// get the number of columns in the file virtual int getNumberOfColumns() const { return numberOfColumns; } /// set the number of nodes and columns in the file virtual void setNumberOfNodesAndColumns(const int numNodes, const int numCols) = 0; /// reset a column of data virtual void resetColumn(const int columnNumber) = 0; /// remove a column of data virtual void removeColumn(const int columnNumber) = 0; /// get all of the column names void getAllColumnNames(std::vector& names) const { names = columnNames; } /// get the specified columns name QString getColumnName(const int col) const; /// get the index of the column with the specified name int getColumnWithName(const QString& n) const; // get a node attribute file column number where input may be a column // name or number. Input numbers range 1..N and output column // numbers range 0..(N-1) int getColumnFromNameOrNumber(const QString& columnNameOrNumber, const bool addColumnIfNotFoundAndNotNumber) throw (FileException); /// get the comment for a column QString getColumnComment(const int col) const; /// set the name of a column void setColumnName(const int col, const QString& name); /// set the comment for a column void setColumnComment(const int col, const QString& comm); /// append to the comment for a column void appendToColumnComment(const int col, const QString& comm); /// prepend to the comment for a column void prependToColumnComment(const int col, const QString& comm); /// get PubMedID's of all linked studies void getPubMedIDsOfAllLinkedStudyMetaData(std::vector& studyPMIDs) const; // get the study metadata link for a column StudyMetaDataLinkSet getColumnStudyMetaDataLinkSet(const int col) const; // set the study metadata link for a column void setColumnStudyMetaDataLinkSet(const int col, const StudyMetaDataLinkSet smdls); /// transfer file data for deformation void transferFileDataForDeformation(const DeformationMapFile& dmf, NodeAttributeFile& destinationFile) const; /// check for columns with the same name (returns true if there are any) bool checkForColumnsWithSameName(std::vector& multipleColumnNames) const; protected: /// get the offset for a data item virtual int getOffset(const int nodeNumber, const int columnNumber) const; /// Deriving classes should call this from its setNumberOfNodesAndColumns() method /// anytime numberOfNodes or numberOfColumns are changed so that column names and /// comments are properly allocated. void numberOfNodesColumnsChanged(); /// Deriving classes should call this from their "clear()" method. The first thing this /// method will do is call clearAbstractFile(). void clearNodeAttributeFile(); /// number of nodes in the file int numberOfNodes; /// number of data columns in the file int numberOfColumns; /// number of items per column in the file int numberOfItemsPerColumn; /// names of data columns std::vector columnNames; /// coments for data columns std::vector columnComments; /// study metadata link sets std::vector studyMetaDataLinkSet; static const QString tagColumnName; static const QString tagColumnComment; static const QString tagNumberOfNodes; static const QString tagNumberOfColumns; static const QString tagColumnStudyMetaData; }; #endif // __VE_NODE_ATTRIBUTE_FILE_H__ #ifdef _NODE_ATTRIBUTE_MAIN_ const QString NodeAttributeFile::tagColumnName = "tag-column-name"; const QString NodeAttributeFile::tagColumnComment = "tag-column-comment"; const QString NodeAttributeFile::tagNumberOfNodes = "tag-number-of-nodes"; const QString NodeAttributeFile::tagNumberOfColumns = "tag-number-of-columns"; const QString NodeAttributeFile::tagColumnStudyMetaData = "tag-column-study-meta-data"; #endif // _NODE_ATTRIBUTE_MAIN_ caret-5.6.4~dfsg.1.orig/caret_files/NodeAttributeFile.cxx0000664000175000017500000002613711572067322023147 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "DeformationMapFile.h" #include "FileUtilities.h" #define _NODE_ATTRIBUTE_MAIN_ #include "NodeAttributeFile.h" #undef _NODE_ATTRIBUTE_MAIN_ #include "StringUtilities.h" /** * Constructor */ NodeAttributeFile::NodeAttributeFile(const QString& descriptiveName, const QString& defaultExt, const FILE_FORMAT defaultWriteTypeIn, const FILE_IO supportsAsciiFormat, const FILE_IO supportsBinaryFormat, const FILE_IO supportsXMLFormat, const FILE_IO supportsOtherFormat) : AbstractFile(descriptiveName, defaultExt, true, defaultWriteTypeIn, supportsAsciiFormat, supportsBinaryFormat, supportsXMLFormat, supportsOtherFormat) { numberOfNodes = 0; numberOfColumns = 0; numberOfItemsPerColumn = 1; } /** * Destructor */ NodeAttributeFile::~NodeAttributeFile() { } /** * Get an offset for indexing into file's data */ int NodeAttributeFile::getOffset(const int nodeNumber, const int columnNumber) const { const int index = (nodeNumber * numberOfColumns * numberOfItemsPerColumn) + (columnNumber * numberOfItemsPerColumn); return index; } /** * get the specified columns name. */ QString NodeAttributeFile::getColumnName(const int col) const { if ((col >= 0) && (col < numberOfColumns)) { return columnNames[col]; } return ""; } /** * Set the name of a data column. */ void NodeAttributeFile::setColumnName(const int col, const QString& name) { columnNames[col] = name; setModified(); } /** * get a node attribute file column number where input may be a column * name or number. Input numbers range 1..N and output column * numbers range 0..(N-1). */ int NodeAttributeFile::getColumnFromNameOrNumber(const QString& columnNameOrNumber, const bool addColumnIfNotFoundAndNotNumber) throw (FileException) { // // Try name first // const int numCols = getNumberOfColumns(); for (int i = 0; i < numCols; i++) { if (getColumnName(i) == columnNameOrNumber) { return i; } } // // To see if it is a number, simply convert to int and check for success // bool ok = false; const int columnNumber = columnNameOrNumber.toInt(&ok); if (ok) { if ((columnNumber > 0) && (columnNumber <= getNumberOfColumns())) { return (columnNumber - 1); } else { throw FileException("ERROR Invalid column name/number " + QString::number(columnNumber) + " in file " + FileUtilities::basename(getFileName())); } } // // Add column if there are nodes // if (addColumnIfNotFoundAndNotNumber) { if (getNumberOfNodes() > 0) { addColumns(1); const int col = getNumberOfColumns() - 1; setColumnName(col, columnNameOrNumber); return col; } } // // faild to find // throw FileException("ERROR column name/number " + columnNameOrNumber + " not found in file " + FileUtilities::basename(getFileName())); } /** * Get the column index for a column with the specified name. If the * name is not found a negative number is returned. */ int NodeAttributeFile::getColumnWithName(const QString& n) const { for (int i = 0; i < getNumberOfColumns(); i++) { if (getColumnName(i) == n) { return i; } } return -1; } /** * Set the comment for a data column. */ void NodeAttributeFile::setColumnComment(const int col, const QString& comm) { //columnComments[col] = StringUtilities::setupCommentForStorage(comm)); columnComments[col] = comm; setModified(); } /** * Append to the comment for a data column. */ void NodeAttributeFile::appendToColumnComment(const int col, const QString& comm) { if (comm.isEmpty() == false) { QString s(getColumnComment(col)); s.append(comm); setColumnComment(col, s); setModified(); } } /** * Prepend to the comment for a data column. */ void NodeAttributeFile::prependToColumnComment(const int col, const QString& comm) { if (comm.isEmpty() == false) { QString s(comm); s.append(getColumnComment(col)); setColumnComment(col, s); setModified(); } } /** * get indices to all linked studies. */ void NodeAttributeFile::getPubMedIDsOfAllLinkedStudyMetaData(std::vector& studyPMIDs) const { std::set pmidSet; const int numColumns= getNumberOfColumns(); for (int i = 0; i < numColumns; i++) { const StudyMetaDataLinkSet smdl = getColumnStudyMetaDataLinkSet(i); std::vector pmids; smdl.getAllLinkedPubMedIDs(pmids); pmidSet.insert(pmids.begin(), pmids.end()); } studyPMIDs.clear(); studyPMIDs.insert(studyPMIDs.end(), pmidSet.begin(), pmidSet.end()); } /** * get the study metadata link set for a column. */ StudyMetaDataLinkSet NodeAttributeFile::getColumnStudyMetaDataLinkSet(const int columnNumber) const { StudyMetaDataLinkSet smdls; if ((columnNumber >= 0) && (columnNumber < getNumberOfColumns())) { smdls = studyMetaDataLinkSet[columnNumber]; } return smdls; } /** * set the study metadata link for a column. */ void NodeAttributeFile::setColumnStudyMetaDataLinkSet(const int columnNumber, const StudyMetaDataLinkSet smdls) { if ((columnNumber >= 0) && (columnNumber < getNumberOfColumns())) { studyMetaDataLinkSet[columnNumber] = smdls; setModified(); } } /** * Get the comment for a column. */ QString NodeAttributeFile::getColumnComment(const int col) const { //return StringUtilities::setupCommentForDisplay(columnComments[col]); return columnComments[col]; } /** * */ void NodeAttributeFile::numberOfNodesColumnsChanged() { const int oldNumberOfColumns = static_cast(columnNames.size()); if (numberOfColumns == 0) { columnNames.clear(); columnComments.clear(); studyMetaDataLinkSet.clear(); } else { columnNames.resize(numberOfColumns); columnComments.resize(numberOfColumns); studyMetaDataLinkSet.resize(numberOfColumns); for (int i = oldNumberOfColumns; i < numberOfColumns; i++) { std::ostringstream str; str << "column " << i << " "; columnNames[i] = str.str().c_str(); } } } /** * */ void NodeAttributeFile::clearNodeAttributeFile() { clearAbstractFile(); columnNames.clear(); columnComments.clear(); studyMetaDataLinkSet.clear(); } /** * transfer file data. */ void NodeAttributeFile::transferFileDataForDeformation(const DeformationMapFile& dmf, NodeAttributeFile& destinationFile) const { /* destinationFile.setFileTitle(getFileTitle()); QString comment("Deformed from: "); comment.append(FileUtilities::basename(getFileName())); comment.append("\n"); comment.append("Deformed with: "); comment.append(FileUtilities::basename(dmf.getFileName())); comment.append("\n"); comment.append(getFileComment()); destinationFile.setFileComment(comment); */ for (int j = 0; j < numberOfColumns; j++) { QString name(dmf.getDeformedColumnNamePrefix()); name.append(getColumnName(j)); destinationFile.setColumnName(j, name); QString comment(getColumnComment(j)); if (comment.isEmpty() == false) { comment.append("\n"); } comment.append("Deformed with: "); comment.append(FileUtilities::basename(dmf.getFileName())); destinationFile.setColumnComment(j, comment); destinationFile.studyMetaDataLinkSet = studyMetaDataLinkSet; } } /** * Deform the metric file */ void NodeAttributeFile::deform(const DeformationMapFile& dmf, NodeAttributeFile& deformedFile, const DEFORM_TYPE dt) const throw (FileException) { // // Check deformation file to make sure it contains data // if (dmf.getNumberOfNodes() <= 0) { throw FileException("Deformation map file is isEmpty."); } // // Check "this" data file to make sure it has data // if ((getNumberOfNodes() <= 0) || (getNumberOfColumns() <= 0)) { QString msg(filename); msg.append(" is isEmpty."); throw FileException(msg); } // // Make sure deformation map will work with this data file // int maxNodeNum = -1; const int numNodes = dmf.getNumberOfNodes(); for (int i = 0; i < numNodes; i++) { int nodes[3]; float areas[3]; dmf.getDeformDataForNode(i, nodes, areas); maxNodeNum = std::max(maxNodeNum, nodes[0]); maxNodeNum = std::max(maxNodeNum, nodes[1]); maxNodeNum = std::max(maxNodeNum, nodes[2]); } if (maxNodeNum >= getNumberOfNodes()) { std::ostringstream str; str << filename.toAscii().constData() << "\n has " << getNumberOfNodes() << " nodes but deformation map expects it to have at least " << maxNodeNum << " nodes."; throw FileException(str.str().c_str()); } // // Deform the data file. // deformFile(dmf, deformedFile, dt); } /** * check for columns with the same name (returns true if there are any). */ bool NodeAttributeFile::checkForColumnsWithSameName(std::vector& multipleColumnNames) const { multipleColumnNames.clear(); if (numberOfColumns > 0) { std::set badNames; for (int i = 0; i < (numberOfColumns - 1); i++) { for (int j = i + 1; j < numberOfColumns; j++) { if (columnNames[i] == columnNames[j]) { badNames.insert(columnNames[i]); } } } if (badNames.empty() == false) { multipleColumnNames.insert(multipleColumnNames.begin(), badNames.begin(), badNames.end()); } } return (multipleColumnNames.size() > 0); } caret-5.6.4~dfsg.1.orig/caret_files/NiftiHelper.h0000664000175000017500000001132611572067322021426 0ustar michaelmichael#ifndef __NIFTI_HELPER_H__ #define __NIFTI_HELPER_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ /*****===================================================================*****/ /***** Sample functions to deal with NIFTI-1 and ANALYZE files *****/ /*****...................................................................*****/ /***** This code is released to the public domain. *****/ /*****...................................................................*****/ /***** Author: Robert W Cox, SSCC/DIRP/NIMH/NIH/DHHS/USA/EARTH *****/ /***** Date: August 2003 *****/ /*****...................................................................*****/ /***** Neither the National Institutes of Health (NIH), nor any of its *****/ /***** employees imply any warranty of usefulness of this software for *****/ /***** any purpose, and do not assume any liability for damages, *****/ /***** incidental or otherwise, caused by any use of this document. *****/ /*****===================================================================*****/ #include "VolumeFile.h" #include "nifti1.h" /// class for help with NIFTI files. Code stolen from nifti1_io.c/h that is part of nifticlib /// available from http://sourceforge.net/projects/niftilib class NiftiHelper { public: enum { NIFTI_L2R = 1, /* Left to Right */ NIFTI_R2L = 2, /* Right to Left */ NIFTI_P2A = 3, /* Posterior to Anterior */ NIFTI_A2P = 4, /* Anterior to Posterior */ NIFTI_I2S = 5, /* Inferior to Superior */ NIFTI_S2I = 6 /* Superior to Inferior */ }; typedef struct { /** 4x4 matrix struct **/ float m[4][4] ; } mat44 ; typedef struct { /** 3x3 matrix struct **/ float m[3][3] ; } mat33 ; static void nifti_mat44_to_orientation( mat44 R , int *icod, int *jcod, int *kcod ) ; static float nifti_mat33_determ( mat33 R ) ; static mat33 nifti_mat33_mul( mat33 A , mat33 B ) ; static mat44 nifti_quatern_to_mat44( float qb, float qc, float qd, float qx, float qy, float qz, float dx, float dy, float dz, float qfac ); //------------------------------------------------------- // Methods below are caret unique static void mat44ToCaretOrientation(mat44 R, VolumeFile::ORIENTATION& xOrient, VolumeFile::ORIENTATION& yOrient, VolumeFile::ORIENTATION& zOrient); // convert NIFTI orientation to Caret orientation static VolumeFile::ORIENTATION niftiOrientationToCaretOrientation(const int niftiOrientation); // get the NIFTI intention (such as statistical parameters) information static void getNiftiIntentionInformation(const nifti_1_header& hdr, QString& niftiIntentCodeAndParam, QString& niftiIntentName); // analyze HDR file is actually a NIFTI HDR file static bool hdrIsNiftiFile(const QString& hdrFileName); // read the NIFTI header static void getNiftiHeaderInformation(const QString& filenameIn, nifti_1_header& niftiHeaderOut, float qformMatrixOut[4][4], float sformMatrixOut[4][4], QString& headerDescriptionOut, QString& errorMessageOut); // get a string representation of the Q/S Form code static QString getQSFormCodeAsString(const int qsForm); }; #endif // __NIFTI_HELPER_H__ caret-5.6.4~dfsg.1.orig/caret_files/NiftiHelper.cxx0000664000175000017500000011553611572067322022011 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ /*****===================================================================*****/ /***** Sample functions to deal with NIFTI-1 and ANALYZE files *****/ /*****...................................................................*****/ /***** This code is released to the public domain. *****/ /*****...................................................................*****/ /***** Author: Robert W Cox, SSCC/DIRP/NIMH/NIH/DHHS/USA/EARTH *****/ /***** Date: August 2003 *****/ /*****...................................................................*****/ /***** Neither the National Institutes of Health (NIH), nor any of its *****/ /***** employees imply any warranty of usefulness of this software for *****/ /***** any purpose, and do not assume any liability for damages, *****/ /***** incidental or otherwise, caused by any use of this document. *****/ /*****===================================================================*****/ #include // used for NULL #include #include #include #include "ByteSwapping.h" #include "NiftiHelper.h" /** * Methods below are caret unique. */ void NiftiHelper::mat44ToCaretOrientation(mat44 R, VolumeFile::ORIENTATION& xOrient, VolumeFile::ORIENTATION& yOrient, VolumeFile::ORIENTATION& zOrient) { int x, y, z; nifti_mat44_to_orientation(R, &x, &y, &z); xOrient = niftiOrientationToCaretOrientation(x); yOrient = niftiOrientationToCaretOrientation(y); zOrient = niftiOrientationToCaretOrientation(z); } /** * convert NIFTI orientation to Caret orientation. */ VolumeFile::ORIENTATION NiftiHelper::niftiOrientationToCaretOrientation(const int niftiOrientation) { VolumeFile::ORIENTATION orient = VolumeFile::ORIENTATION_UNKNOWN; switch(niftiOrientation) { case NIFTI_L2R: orient = VolumeFile::ORIENTATION_LEFT_TO_RIGHT; break; case NIFTI_R2L: orient = VolumeFile::ORIENTATION_RIGHT_TO_LEFT; break; case NIFTI_P2A: orient = VolumeFile::ORIENTATION_POSTERIOR_TO_ANTERIOR; break; case NIFTI_A2P: orient = VolumeFile::ORIENTATION_ANTERIOR_TO_POSTERIOR; break; case NIFTI_I2S: orient = VolumeFile::ORIENTATION_INFERIOR_TO_SUPERIOR; break; case NIFTI_S2I: orient = VolumeFile::ORIENTATION_SUPERIOR_TO_INFERIOR; break; } return orient; } void NiftiHelper::nifti_mat44_to_orientation( mat44 R , int *icod, int *jcod, int *kcod ) { float xi,xj,xk , yi,yj,yk , zi,zj,zk , val,detQ,detP ; mat33 P , Q , M ; int i,j,k=0,p,q,r , ibest,jbest,kbest,pbest,qbest,rbest ; float vbest ; if( icod == NULL || jcod == NULL || kcod == NULL ) return ; /* bad */ *icod = *jcod = *kcod = 0 ; /* error returns, if sh*t happens */ /* load column vectors for each (i,j,k) direction from matrix */ /*-- i axis --*/ /*-- j axis --*/ /*-- k axis --*/ xi = R.m[0][0] ; xj = R.m[0][1] ; xk = R.m[0][2] ; yi = R.m[1][0] ; yj = R.m[1][1] ; yk = R.m[1][2] ; zi = R.m[2][0] ; zj = R.m[2][1] ; zk = R.m[2][2] ; /* normalize column vectors to get unit vectors along each ijk-axis */ /* normalize i axis */ val = std::sqrt( xi*xi + yi*yi + zi*zi ) ; if( val == 0.0 ) return ; /* stupid input */ xi /= val ; yi /= val ; zi /= val ; /* normalize j axis */ val = std::sqrt( xj*xj + yj*yj + zj*zj ) ; if( val == 0.0 ) return ; /* stupid input */ xj /= val ; yj /= val ; zj /= val ; /* orthogonalize j axis to i axis, if needed */ val = xi*xj + yi*yj + zi*zj ; /* dot product between i and j */ if( std::fabs(val) > 1.e-4 ){ xj -= val*xi ; yj -= val*yi ; zj -= val*zi ; val = std::sqrt( xj*xj + yj*yj + zj*zj ) ; /* must renormalize */ if( val == 0.0 ) return ; /* j was parallel to i? */ xj /= val ; yj /= val ; zj /= val ; } /* normalize k axis; if it is zero, make it the cross product i x j */ val = std::sqrt( xk*xk + yk*yk + zk*zk ) ; if( val == 0.0 ){ xk = yi*zj-zi*yj; yk = zi*xj-zj*xi ; zk=xi*yj-yi*xj ; } else { xk /= val ; yk /= val ; zk /= val ; } /* orthogonalize k to i */ val = xi*xk + yi*yk + zi*zk ; /* dot product between i and k */ if( std::fabs(val) > 1.e-4 ){ xk -= val*xi ; yk -= val*yi ; zk -= val*zi ; val = std::sqrt( xk*xk + yk*yk + zk*zk ) ; if( val == 0.0 ) return ; /* bad */ xk /= val ; yk /= val ; zk /= val ; } /* orthogonalize k to j */ val = xj*xk + yj*yk + zj*zk ; /* dot product between j and k */ if( std::fabs(val) > 1.e-4 ){ xk -= val*xj ; yk -= val*yj ; zk -= val*zj ; val = std::sqrt( xk*xk + yk*yk + zk*zk ) ; if( val == 0.0 ) return ; /* bad */ xk /= val ; yk /= val ; zk /= val ; } Q.m[0][0] = xi ; Q.m[0][1] = xj ; Q.m[0][2] = xk ; Q.m[1][0] = yi ; Q.m[1][1] = yj ; Q.m[1][2] = yk ; Q.m[2][0] = zi ; Q.m[2][1] = zj ; Q.m[2][2] = zk ; /* at this point, Q is the rotation matrix from the (i,j,k) to (x,y,z) axes */ detQ = nifti_mat33_determ( Q ) ; if( detQ == 0.0 ) return ; /* shouldn't happen unless user is a DUFIS */ /* Build and test all possible +1/-1 coordinate permutation matrices P; then find the P such that the rotation matrix M=PQ is closest to the identity, in the sense of M having the smallest total rotation angle. */ /* Despite the formidable looking 6 nested loops, there are only 3*3*3*2*2*2 = 216 passes, which will run very quickly. */ vbest = -666.0 ; ibest=pbest=qbest=rbest=1 ; jbest=2 ; kbest=3 ; for( i=1 ; i <= 3 ; i++ ){ /* i = column number to use for row #1 */ for( j=1 ; j <= 3 ; j++ ){ /* j = column number to use for row #2 */ if( i == j ) continue ; for( k=1 ; k <= 3 ; k++ ){ /* k = column number to use for row #3 */ if( i == k || j == k ) continue ; P.m[0][0] = P.m[0][1] = P.m[0][2] = P.m[1][0] = P.m[1][1] = P.m[1][2] = P.m[2][0] = P.m[2][1] = P.m[2][2] = 0.0 ; for( p=-1 ; p <= 1 ; p+=2 ){ /* p,q,r are -1 or +1 */ for( q=-1 ; q <= 1 ; q+=2 ){ /* and go into rows #1,2,3 */ for( r=-1 ; r <= 1 ; r+=2 ){ P.m[0][i-1] = p ; P.m[1][j-1] = q ; P.m[2][k-1] = r ; detP = nifti_mat33_determ(P) ; /* sign of permutation */ if( detP * detQ <= 0.0 ) continue ; /* doesn't match sign of Q */ M = nifti_mat33_mul(P,Q) ; /* angle of M rotation = 2.0*acos(0.5*sqrt(1.0+trace(M))) */ /* we want largest trace(M) == smallest angle == M nearest to I */ val = M.m[0][0] + M.m[1][1] + M.m[2][2] ; /* trace */ if( val > vbest ){ vbest = val ; ibest = i ; jbest = j ; kbest = k ; pbest = p ; qbest = q ; rbest = r ; } }}}}}} /* At this point ibest is 1 or 2 or 3; pbest is -1 or +1; etc. The matrix P that corresponds is the best permutation approximation to Q-inverse; that is, P (approximately) takes (x,y,z) coordinates to the (i,j,k) axes. For example, the first row of P (which contains pbest in column ibest) determines the way the i axis points relative to the anatomical (x,y,z) axes. If ibest is 2, then the i axis is along the y axis, which is direction P2A (if pbest > 0) or A2P (if pbest < 0). So, using ibest and pbest, we can assign the output code for the i axis. Mutatis mutandis for the j and k axes, of course. */ switch( ibest*pbest ){ case 1: i = NIFTI_L2R ; break ; case -1: i = NIFTI_R2L ; break ; case 2: i = NIFTI_P2A ; break ; case -2: i = NIFTI_A2P ; break ; case 3: i = NIFTI_I2S ; break ; case -3: i = NIFTI_S2I ; break ; } switch( jbest*qbest ){ case 1: j = NIFTI_L2R ; break ; case -1: j = NIFTI_R2L ; break ; case 2: j = NIFTI_P2A ; break ; case -2: j = NIFTI_A2P ; break ; case 3: j = NIFTI_I2S ; break ; case -3: j = NIFTI_S2I ; break ; } switch( kbest*rbest ){ case 1: k = NIFTI_L2R ; break ; case -1: k = NIFTI_R2L ; break ; case 2: k = NIFTI_P2A ; break ; case -2: k = NIFTI_A2P ; break ; case 3: k = NIFTI_I2S ; break ; case -3: k = NIFTI_S2I ; break ; } *icod = i ; *jcod = j ; *kcod = k ; return ; } /*----------------------------------------------------------------------*/ /*! compute the determinant of a 3x3 matrix *//*--------------------------------------------------------------------*/ float NiftiHelper::nifti_mat33_determ( mat33 R ) /* determinant of 3x3 matrix */ { double r11,r12,r13,r21,r22,r23,r31,r32,r33 ; /* INPUT MATRIX: */ r11 = R.m[0][0]; r12 = R.m[0][1]; r13 = R.m[0][2]; /* [ r11 r12 r13 ] */ r21 = R.m[1][0]; r22 = R.m[1][1]; r23 = R.m[1][2]; /* [ r21 r22 r23 ] */ r31 = R.m[2][0]; r32 = R.m[2][1]; r33 = R.m[2][2]; /* [ r31 r32 r33 ] */ return r11*r22*r33-r11*r32*r23-r21*r12*r33 +r21*r32*r13+r31*r12*r23-r31*r22*r13 ; } /*----------------------------------------------------------------------*/ /*! multiply 2 3x3 matrices *//*--------------------------------------------------------------------*/ NiftiHelper::mat33 NiftiHelper::nifti_mat33_mul( mat33 A , mat33 B ) /* multiply 2 3x3 matrices */ { mat33 C ; int i,j ; for( i=0 ; i < 3 ; i++ ) for( j=0 ; j < 3 ; j++ ) C.m[i][j] = A.m[i][0] * B.m[0][j] + A.m[i][1] * B.m[1][j] + A.m[i][2] * B.m[2][j] ; return C ; } NiftiHelper::mat44 NiftiHelper::nifti_quatern_to_mat44( float qb, float qc, float qd, float qx, float qy, float qz, float dx, float dy, float dz, float qfac ) { mat44 R ; double a,b=qb,c=qc,d=qd , xd,yd,zd ; /* last row is always [ 0 0 0 1 ] */ R.m[3][0]=R.m[3][1]=R.m[3][2] = 0.0 ; R.m[3][3]= 1.0 ; /* compute a parameter from b,c,d */ a = 1.0l - (b*b + c*c + d*d) ; if( a < 1.e-7l ){ /* special case */ a = 1.0l / sqrt(b*b+c*c+d*d) ; b *= a ; c *= a ; d *= a ; /* normalize (b,c,d) vector */ a = 0.0l ; /* a = 0 ==> 180 degree rotation */ } else{ a = std::sqrt(a) ; /* angle = 2*arccos(a) */ } /* load rotation matrix, including scaling factors for voxel sizes */ xd = (dx > 0.0) ? dx : 1.0l ; /* make sure are positive */ yd = (dy > 0.0) ? dy : 1.0l ; zd = (dz > 0.0) ? dz : 1.0l ; if( qfac < 0.0 ) zd = -zd ; /* left handedness? */ R.m[0][0] = (a*a+b*b-c*c-d*d) * xd ; R.m[0][1] = 2.0l * (b*c-a*d ) * yd ; R.m[0][2] = 2.0l * (b*d+a*c ) * zd ; R.m[1][0] = 2.0l * (b*c+a*d ) * xd ; R.m[1][1] = (a*a+c*c-b*b-d*d) * yd ; R.m[1][2] = 2.0l * (c*d-a*b ) * zd ; R.m[2][0] = 2.0l * (b*d-a*c ) * xd ; R.m[2][1] = 2.0l * (c*d+a*b ) * yd ; R.m[2][2] = (a*a+d*d-c*c-b*b) * zd ; /* load offsets */ R.m[0][3] = qx ; R.m[1][3] = qy ; R.m[2][3] = qz ; return R ; } /** * get the NIFTI intention (such as statistical parameters) information. */ void NiftiHelper::getNiftiIntentionInformation(const nifti_1_header& hdr, QString& niftiIntentCodeAndParam, QString& niftiIntentName) { niftiIntentName = ("NIFTI_INTENT_NOT_RECOGNIZED_CODE_" + QString::number(hdr.intent_code)); QString intentDescription; QString p1; QString p2; QString p3; switch (hdr.intent_code) { case NIFTI_INTENT_NONE: niftiIntentName = "NIFTI_INTENT_NONE"; intentDescription = "None" ; p1 = ""; p2 = ""; p3 = ""; break; case NIFTI_INTENT_CORREL: niftiIntentName = "NIFTI_INTENT_CORREL"; intentDescription = "Correlation statistic" ; p1 = "DOF"; p2 = ""; p3 = ""; break; case NIFTI_INTENT_TTEST: niftiIntentName = "NIFTI_INTENT_TTEST"; intentDescription = "T-statistic" ; p1 = "DOF"; p2 = ""; p3 = ""; break; case NIFTI_INTENT_FTEST: niftiIntentName = "NIFTI_INTENT_FTEST"; intentDescription = "F-statistic" ; p1 = "Numerator DOF"; p2 = "Denorminator DOF"; p3 = ""; break; case NIFTI_INTENT_ZSCORE: niftiIntentName = "NIFTI_INTENT_ZSCORE"; intentDescription = "Z-score" ; p1 = ""; p2 = ""; p3 = ""; break; case NIFTI_INTENT_CHISQ: niftiIntentName = "NIFTI_INTENT_CHISQ"; intentDescription = "Chi-squared distribution" ; p1 = "DOF"; p2 = ""; p3 = ""; break; case NIFTI_INTENT_BETA: niftiIntentName = "NIFTI_INTENT_BETA"; intentDescription = "Beta distribution" ; p1 = "a"; p2 = "b"; p3 = ""; break; case NIFTI_INTENT_BINOM: niftiIntentName = "NIFTI_INTENT_BINOM"; intentDescription = "Binomial distribution" ; p1 = "Number of Trials"; p2 = "Probability per Trial"; p3 = ""; break; case NIFTI_INTENT_GAMMA: niftiIntentName = "NIFTI_INTENT_GAMMA"; intentDescription = "Gamma distribution" ; p1 = "Shape"; p2 = "Scale"; p3 = ""; break; case NIFTI_INTENT_POISSON: niftiIntentName = "NIFTI_INTENT_POISSON"; intentDescription = "Poisson distribution" ; p1 = "Mean"; p2 = ""; p3 = ""; break; case NIFTI_INTENT_NORMAL: niftiIntentName = "NIFTI_INTENT_NORMAL"; intentDescription = "Normal distribution" ; p1 = "Mean"; p2 = "Standard Deviation"; p3 = ""; break; case NIFTI_INTENT_FTEST_NONC: niftiIntentName = "NIFTI_INTENT_FTEST_NONC"; intentDescription = "F-statistic noncentral" ; p1 = "Numerator DOF"; p2 = "Denominator DOF"; p3 = "Numerator Noncentrality Parameter"; break; case NIFTI_INTENT_CHISQ_NONC: niftiIntentName = "NIFTI_INTENT_CHISQ_NONC"; intentDescription = "Chi-squared noncentral" ; p1 = "DOF"; p2 = "Noncentrality Parameter"; p3 = ""; break; case NIFTI_INTENT_LOGISTIC: niftiIntentName = "NIFTI_INTENT_LOGISTIC"; intentDescription = "Logistic distribution" ; p1 = "Location"; p2 = "Scale"; p3 = ""; break; case NIFTI_INTENT_LAPLACE: niftiIntentName = "NIFTI_INTENT_LAPLACE"; intentDescription = "Laplace distribution" ; p1 = "Location"; p2 = "Scale"; p3 = ""; break; case NIFTI_INTENT_UNIFORM: niftiIntentName = "NIFTI_INTENT_UNIFORM"; intentDescription = "Uniform distribition" ; p1 = "Lower End"; p2 = "Upper End"; p3 = ""; break; case NIFTI_INTENT_TTEST_NONC: niftiIntentName = "NIFTI_INTENT_TTEST_NONC"; intentDescription = "T-statistic noncentral" ; p1 = "DOF"; p2 = "Noncentrality Parameter"; p3 = ""; break; case NIFTI_INTENT_WEIBULL: niftiIntentName = "NIFTI_INTENT_WEIBULL"; intentDescription = "Weibull distribution" ; p1 = "Location"; p2 = "Scale"; p3 = "Power"; break; case NIFTI_INTENT_CHI: niftiIntentName = "NIFTI_INTENT_CHI"; intentDescription = "Chi distribution" ; p1 = "Half Normal Distribution"; p2 = "Rayleigh Distritibution"; p3 = "Maxwell-Boltzmann Distribution"; break; case NIFTI_INTENT_INVGAUSS: niftiIntentName = "NIFTI_INTENT_INVGAUSS"; intentDescription = "Inverse Gaussian distribution" ; p1 = "MU"; p2 = "Lambda"; p3 = ""; break; case NIFTI_INTENT_EXTVAL: niftiIntentName = "NIFTI_INTENT_EXTVAL"; intentDescription = "Extreme Value distribution" ; p1 = "Location"; p2 = "Scale"; p3 = ""; break; case NIFTI_INTENT_PVAL: niftiIntentName = "NIFTI_INTENT_PVAL"; intentDescription = "P-value" ; p1 = ""; p2 = ""; p3 = ""; break; case NIFTI_INTENT_LOGPVAL: niftiIntentName = "NIFTI_INTENT_LOGPVAL"; intentDescription = "Log P-value" ; p1 = ""; p2 = ""; p3 = ""; break; case NIFTI_INTENT_LOG10PVAL: niftiIntentName = "NIFTI_INTENT_LOG10PVAL"; intentDescription = "Log10 P-value" ; p1 = ""; p2 = ""; p3 = ""; break; case NIFTI_INTENT_ESTIMATE: niftiIntentName = "NIFTI_INTENT_ESTIMATE"; intentDescription = "Estimate" ; p1 = ""; p2 = ""; p3 = ""; break; case NIFTI_INTENT_LABEL: niftiIntentName = "NIFTI_INTENT_LABEL"; intentDescription = "Label index" ; p1 = ""; p2 = ""; p3 = ""; break; case NIFTI_INTENT_NEURONAME: niftiIntentName = "NIFTI_INTENT_NEURONAME"; intentDescription = "NeuroNames index" ; p1 = ""; p2 = ""; p3 = ""; break; case NIFTI_INTENT_GENMATRIX: niftiIntentName = "NIFTI_INTENT_GENMATRIX"; intentDescription = "General matrix" ; p1 = ""; p2 = ""; p3 = ""; break; case NIFTI_INTENT_SYMMATRIX: niftiIntentName = "NIFTI_INTENT_SYMMATRIX"; intentDescription = "Symmetric matrix" ; p1 = ""; p2 = ""; p3 = ""; break; case NIFTI_INTENT_DISPVECT: niftiIntentName = "NIFTI_INTENT_DISPVECT"; intentDescription = "Displacement vector" ; p1 = ""; p2 = ""; p3 = ""; break; case NIFTI_INTENT_VECTOR: niftiIntentName = "NIFTI_INTENT_VECTOR"; intentDescription = "Vector" ; p1 = ""; p2 = ""; p3 = ""; break; case NIFTI_INTENT_POINTSET: niftiIntentName = "NIFTI_INTENT_POINTSET"; intentDescription = "Pointset" ; p1 = ""; p2 = ""; p3 = ""; break; case NIFTI_INTENT_TRIANGLE: niftiIntentName = "NIFTI_INTENT_TRIANGLE"; intentDescription = "Triangle" ; p1 = ""; p2 = ""; p3 = ""; break; case NIFTI_INTENT_QUATERNION: niftiIntentName = "NIFTI_INTENT_QUATERNION"; intentDescription = "Quaternion" ; p1 = ""; p2 = ""; p3 = ""; break; case NIFTI_INTENT_DIMLESS: niftiIntentName = "NIFTI_INTENT_DIMLESS"; intentDescription = "Dimensionless number" ; p1 = ""; p2 = ""; p3 = ""; break; } QString s; if (intentDescription.isEmpty() == false) { s += intentDescription; if (p1.isEmpty() == false) { s += (" " + p1 + "=" + QString::number(hdr.intent_p1, 'f', 2)); } if (p2.isEmpty() == false) { s += (" " + p2 + "=" + QString::number(hdr.intent_p2, 'f', 2)); } if (p3.isEmpty() == false) { s += (" " + p3 + "=" + QString::number(hdr.intent_p3, 'f', 2)); } } niftiIntentCodeAndParam = s; } /** * analyze HDR file is actually a NIFTI HDR file. */ bool NiftiHelper::hdrIsNiftiFile(const QString& hdrFileName) { QFile file(hdrFileName); if (file.open(QIODevice::ReadOnly)) { // // read bytes 348 // int numBytesToRead = 348; char bytes[numBytesToRead]; QDataStream stream(&file); const bool errorFlag = (stream.readRawData(bytes, numBytesToRead) != numBytesToRead); file.close(); if (errorFlag) { return false; } // // Is this the NIFTI code "ni1"? // if ((bytes[344] == 'n') && (bytes[345] == 'i') && (bytes[346] == '1')) { return true; } } return false; } /** * Get the information NIFTI header. */ void NiftiHelper::getNiftiHeaderInformation(const QString& fileNameIn, nifti_1_header& niftiHeaderOut, float qformMatrixOut[4][4], float sformMatrixOut[4][4], QString& headerDescriptionOut, QString& errorMessageOut) { headerDescriptionOut = ""; errorMessageOut = ""; gzFile dataFile = gzopen(fileNameIn.toAscii().constData(), "rb"); if (dataFile == NULL) { errorMessageOut = "Unable to open " + fileNameIn + "with ZLIB for reading."; } // // Read the NIFTI header and close file after reading header // const unsigned long headerSize = sizeof(niftiHeaderOut); const unsigned long numBytesRead = gzread(dataFile, (voidp)&niftiHeaderOut, headerSize); if (numBytesRead != headerSize) { gzclose(dataFile); std::ostringstream str; str << "Tried to read " << headerSize << " bytes from header.\n" << "Only read " << numBytesRead << "."; errorMessageOut = str.str().c_str(); return; } // // Make sure it is a NIFTI file // const int version = NIFTI_VERSION(niftiHeaderOut); switch (version) { case 0: gzclose(dataFile); errorMessageOut = fileNameIn + "Is not a NIFTI volume file."; return; break; case 1: break; default: { gzclose(dataFile); std::ostringstream str; str << fileNameIn.toAscii().constData() << " is an invalid NIFTI version: " << version << "."; errorMessageOut = str.str().c_str(); return; } break; } // // Do bytes need to be swapped ? // bool byteSwapFlag = false; if (NIFTI_NEEDS_SWAP(niftiHeaderOut)) { byteSwapFlag = true; ByteSwapping::swapBytes(&niftiHeaderOut.sizeof_hdr, 1); ByteSwapping::swapBytes(&niftiHeaderOut.extents, 1); ByteSwapping::swapBytes(&niftiHeaderOut.session_error, 1); ByteSwapping::swapBytes(niftiHeaderOut.dim, 8); ByteSwapping::swapBytes(&niftiHeaderOut.intent_p1, 1); ByteSwapping::swapBytes(&niftiHeaderOut.intent_p2, 1); ByteSwapping::swapBytes(&niftiHeaderOut.intent_p3, 1); ByteSwapping::swapBytes(&niftiHeaderOut.intent_code, 1); ByteSwapping::swapBytes(&niftiHeaderOut.datatype, 1); ByteSwapping::swapBytes(&niftiHeaderOut.bitpix, 1); ByteSwapping::swapBytes(&niftiHeaderOut.slice_start, 1); ByteSwapping::swapBytes(niftiHeaderOut.pixdim, 8); ByteSwapping::swapBytes(&niftiHeaderOut.vox_offset, 1); ByteSwapping::swapBytes(&niftiHeaderOut.scl_slope, 1); ByteSwapping::swapBytes(&niftiHeaderOut.scl_inter, 1); ByteSwapping::swapBytes(&niftiHeaderOut.slice_end, 1); ByteSwapping::swapBytes(&niftiHeaderOut.cal_max, 1); ByteSwapping::swapBytes(&niftiHeaderOut.cal_min, 1); ByteSwapping::swapBytes(&niftiHeaderOut.slice_duration, 1); ByteSwapping::swapBytes(&niftiHeaderOut.toffset, 1); ByteSwapping::swapBytes(&niftiHeaderOut.glmax, 1); ByteSwapping::swapBytes(&niftiHeaderOut.glmin, 1); ByteSwapping::swapBytes(&niftiHeaderOut.qform_code, 1); ByteSwapping::swapBytes(&niftiHeaderOut.sform_code, 1); ByteSwapping::swapBytes(&niftiHeaderOut.quatern_b, 1); ByteSwapping::swapBytes(&niftiHeaderOut.quatern_c, 1); ByteSwapping::swapBytes(&niftiHeaderOut.quatern_d, 1); ByteSwapping::swapBytes(&niftiHeaderOut.qoffset_x, 1); ByteSwapping::swapBytes(&niftiHeaderOut.qoffset_y, 1); ByteSwapping::swapBytes(&niftiHeaderOut.qoffset_z, 1); ByteSwapping::swapBytes(niftiHeaderOut.srow_x, 4); ByteSwapping::swapBytes(niftiHeaderOut.srow_y, 4); ByteSwapping::swapBytes(niftiHeaderOut.srow_z, 4); } VolumeFile::ORIENTATION qformOrientation[3] = { VolumeFile::ORIENTATION_UNKNOWN, VolumeFile::ORIENTATION_UNKNOWN, VolumeFile::ORIENTATION_UNKNOWN }; VolumeFile::ORIENTATION sformOrientation[3] = { VolumeFile::ORIENTATION_UNKNOWN, VolumeFile::ORIENTATION_UNKNOWN, VolumeFile::ORIENTATION_UNKNOWN }; if (niftiHeaderOut.sform_code > 0) { // // NIFTI origin is in the center of the voxel // so move the origin to the corner of voxel // //volumeRead.origin[0] -= volumeRead.spacing[0] * 0.5; //volumeRead.origin[1] -= volumeRead.spacing[1] * 0.5; //volumeRead.origin[2] -= volumeRead.spacing[2] * 0.5; NiftiHelper::mat44 m; m.m[0][0] = niftiHeaderOut.srow_x[0]; m.m[0][1] = niftiHeaderOut.srow_x[1]; m.m[0][2] = niftiHeaderOut.srow_x[2]; m.m[0][3] = niftiHeaderOut.srow_x[3]; m.m[1][0] = niftiHeaderOut.srow_y[0]; m.m[1][1] = niftiHeaderOut.srow_y[1]; m.m[1][2] = niftiHeaderOut.srow_y[2]; m.m[1][3] = niftiHeaderOut.srow_y[3]; m.m[2][0] = niftiHeaderOut.srow_z[0]; m.m[2][1] = niftiHeaderOut.srow_z[1]; m.m[2][2] = niftiHeaderOut.srow_z[2]; m.m[2][3] = niftiHeaderOut.srow_z[3]; m.m[3][0] = 0.0; m.m[3][1] = 0.0; m.m[3][2] = 0.0; m.m[3][3] = 1.0; NiftiHelper::mat44ToCaretOrientation(m, sformOrientation[0], sformOrientation[1], sformOrientation[2]); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { sformMatrixOut[i][j] = m.m[i][j]; } } } if (niftiHeaderOut.qform_code > 0) { float qfac = (niftiHeaderOut.pixdim[0] < 0.0) ? -1.0 : 1.0 ; /* left-handedness? */ NiftiHelper::mat44 m = NiftiHelper::nifti_quatern_to_mat44(niftiHeaderOut.quatern_b, niftiHeaderOut.quatern_c, niftiHeaderOut.quatern_c, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, qfac); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { qformMatrixOut[i][j] = m.m[i][j]; } } NiftiHelper::mat44ToCaretOrientation(m, qformOrientation[0], qformOrientation[1], qformOrientation[2]); } int precision = 3; QStringList keys, values; keys << "sizeof_hdr"; values << QString::number(niftiHeaderOut.sizeof_hdr); keys << "data_type"; QString dataTypeString; for (int i = 0; i < 10; i++) { if (niftiHeaderOut.data_type[i] == '\0') { break; } dataTypeString += niftiHeaderOut.data_type[i]; } values << dataTypeString; keys << "db_name"; QString dbNameString; for (int i = 0; i < 18; i++) { if (niftiHeaderOut.db_name[i] == '\0') { break; } dbNameString += niftiHeaderOut.db_name[i]; } values << dbNameString; keys << "extents"; values << QString::number(niftiHeaderOut.extents); keys << "session_error"; values << QString::number(niftiHeaderOut.session_error); keys << "regular"; values << QChar(niftiHeaderOut.regular); keys << "dim_info"; values << QString::number(niftiHeaderOut.dim_info); keys << "dim"; QString dimString; for (int i = 0; i < 8; i++) { dimString += QString::number(niftiHeaderOut.dim[i]) + " "; } values << dimString; keys << "intent_p1"; values << QString::number(niftiHeaderOut.intent_p1, 'f', precision); keys << "intent_p2"; values << QString::number(niftiHeaderOut.intent_p2, 'f', precision); keys << "intent_p3"; values << QString::number(niftiHeaderOut.intent_p3, 'f', precision); keys << "intent_code"; values << QString::number(niftiHeaderOut.intent_code); keys << "datatype"; values << QString::number(niftiHeaderOut.datatype); keys << "bitpix"; values << QString::number(niftiHeaderOut.bitpix); keys << "slice_start"; values << QString::number(niftiHeaderOut.slice_start); keys << "pixdim"; QString pixDimString; for (int i = 0; i < 8; i++) { pixDimString += QString::number(niftiHeaderOut.pixdim[i], 'f', precision) + " "; } values << pixDimString; keys << "vox_offset"; values << QString::number(niftiHeaderOut.vox_offset, 'f', precision); keys << "scl_slope"; values << QString::number(niftiHeaderOut.scl_slope, 'f', precision); keys << "scl_inter"; values << QString::number(niftiHeaderOut.scl_inter, 'f', precision); keys << "slice_end"; values << QString::number(niftiHeaderOut.slice_end); keys << "slice_code"; values << QString::number(niftiHeaderOut.slice_code); keys << "xyzt_units"; values << QString::number(niftiHeaderOut.xyzt_units); keys << "cal_max"; values << QString::number(niftiHeaderOut.cal_max, 'f', precision); keys << "cal_min"; values << QString::number(niftiHeaderOut.cal_min, 'f', precision); keys << "slice_duration"; values << QString::number(niftiHeaderOut.slice_duration, 'f', precision); keys << "toffset"; values << QString::number(niftiHeaderOut.toffset, 'f', precision); keys << "glmax"; values << QString::number(niftiHeaderOut.glmax); keys << "glmin"; values << QString::number(niftiHeaderOut.glmin); QString description; for (int i = 0; i < 80; i++) { if (niftiHeaderOut.descrip[i] == '\0') { break; } description += niftiHeaderOut.descrip[i]; } keys << "description"; values << description; QString auxFile; for (int i = 0; i < 24; i++) { if (niftiHeaderOut.aux_file[i] == '\0') { break; } auxFile += niftiHeaderOut.aux_file[i]; } keys << "aux_file"; values << auxFile; keys << "qform_code"; values << QString::number(niftiHeaderOut.qform_code); keys << "sform_code"; values << QString::number(niftiHeaderOut.sform_code); keys << "quatern_b"; values << QString::number(niftiHeaderOut.quatern_b, 'f', precision); keys << "quatern_c"; values << QString::number(niftiHeaderOut.quatern_c, 'f', precision); keys << "quatern_d"; values << QString::number(niftiHeaderOut.quatern_d, 'f', precision); keys << "qoffset_x"; values << QString::number(niftiHeaderOut.qoffset_x, 'f', precision); keys << "qoffset_y"; values << QString::number(niftiHeaderOut.qoffset_y, 'f', precision); keys << "qoffset_z"; values << QString::number(niftiHeaderOut.qoffset_z, 'f', precision); QString sRowX; for (int i = 0; i < 4; i++) { sRowX += QString::number(niftiHeaderOut.srow_x[i], 'f', precision) + " "; } keys << "srow_x"; values << sRowX; QString sRowY; for (int i = 0; i < 4; i++) { sRowY += QString::number(niftiHeaderOut.srow_y[i], 'f', precision) + " "; } keys << "srow_y"; values << sRowY; QString sRowZ; for (int i = 0; i < 4; i++) { sRowZ += QString::number(niftiHeaderOut.srow_z[i], 'f', precision) + " "; } keys << "srow_z"; values << sRowZ; QString intentName; for (int i = 0; i < 16; i++) { if (niftiHeaderOut.intent_name[i] == '\0') { break; } intentName += niftiHeaderOut.intent_name[i]; } keys << "intent_name"; values << intentName; QString magic; for (int i = 0; i < 3; i++) { if (niftiHeaderOut.magic[i] == '\0') { break; } magic += niftiHeaderOut.magic[i]; } keys << "magic"; values << magic; // // Get key maximum length // int maxLength = 0; for (int i = 0; i < keys.count(); i++) { maxLength = std::max(maxLength, keys.at(i).length()); } // // Place data into header description // for (int i = 0; i < keys.count(); i++) { headerDescriptionOut += QString("%1: %2\n").arg(keys.at(i), maxLength).arg(values.at(i)); } headerDescriptionOut += "\n"; // // Intent Information // QString niftiIntentCodeAndParam; QString niftiIntentName; NiftiHelper::getNiftiIntentionInformation(niftiHeaderOut, niftiIntentCodeAndParam, niftiIntentName); headerDescriptionOut += ("Intent Name: " + niftiIntentName + "\n"); headerDescriptionOut += ("Intent Parameters:" + niftiIntentCodeAndParam + "\n"); headerDescriptionOut += "\n"; // // qform matrix and orientation // headerDescriptionOut += ("QFORM: " + NiftiHelper::getQSFormCodeAsString(niftiHeaderOut.qform_code) + "\n"); for (int i = 0; i < 4; i++) { headerDescriptionOut += " "; for (int j = 0; j < 4; j++) { headerDescriptionOut += QString::number(qformMatrixOut[i][j], 'f', precision).rightJustified(12, ' '); } headerDescriptionOut += "\n"; } headerDescriptionOut += "QFORM Orientation\n"; for (int i = 0; i < 3; i++) { headerDescriptionOut += (" " + VolumeFile::getOrientationLabel(qformOrientation[i]) + "\n"); } headerDescriptionOut += "\n"; // // sform matrix and orientation // headerDescriptionOut += ("SFORM: " + NiftiHelper::getQSFormCodeAsString(niftiHeaderOut.sform_code) + "\n"); for (int i = 0; i < 4; i++) { headerDescriptionOut += " "; for (int j = 0; j < 4; j++) { headerDescriptionOut += QString::number(sformMatrixOut[i][j], 'f', precision).rightJustified(12, ' '); } headerDescriptionOut += "\n"; } headerDescriptionOut += "SFORM Orientation\n"; for (int i = 0; i < 3; i++) { headerDescriptionOut += (" " + VolumeFile::getOrientationLabel(sformOrientation[i]) + "\n"); } headerDescriptionOut += "\n"; QString dataCodeString = ("Unrecognized data type code = " + QString::number(niftiHeaderOut.datatype)); switch (niftiHeaderOut.datatype) { case DT_UNKNOWN: dataCodeString = "DT_UNKNOWN"; break; case DT_BINARY: dataCodeString = "DT_BINARY"; break; case NIFTI_TYPE_UINT8: dataCodeString = "NIFTI_TYPE_UINT8"; break; case NIFTI_TYPE_INT16: dataCodeString = "NIFTI_TYPE_INT16"; break; case NIFTI_TYPE_INT32: dataCodeString = "NIFTI_TYPE_INT32"; break; case NIFTI_TYPE_FLOAT32: dataCodeString = "NIFTI_TYPE_FLOAT32"; break; case NIFTI_TYPE_COMPLEX64: dataCodeString = "NIFTI_TYPE_COMPLEX64"; break; case NIFTI_TYPE_FLOAT64: dataCodeString = "NIFTI_TYPE_FLOAT64"; break; case NIFTI_TYPE_RGB24: dataCodeString = "NIFTI_TYPE_RGB24"; break; case NIFTI_TYPE_INT8: dataCodeString = "NIFTI_TYPE_INT8"; break; case NIFTI_TYPE_UINT16: dataCodeString = "NIFTI_TYPE_UINT16"; break; case NIFTI_TYPE_UINT32: dataCodeString = "NIFTI_TYPE_UINT32"; break; case NIFTI_TYPE_INT64: dataCodeString = "NIFTI_TYPE_INT64"; break; case NIFTI_TYPE_UINT64: dataCodeString = "NIFTI_TYPE_UINT64"; break; case NIFTI_TYPE_FLOAT128: dataCodeString = "NIFTI_TYPE_FLOAT128"; break; case NIFTI_TYPE_COMPLEX128: dataCodeString = "NIFTI_TYPE_COMPLEX128"; break; case NIFTI_TYPE_COMPLEX256: dataCodeString = "NIFTI_TYPE_COMPLEX256"; break; } headerDescriptionOut += ("Data Type: " + dataCodeString + "\n"); headerDescriptionOut += "\n"; const int spaceUnits = XYZT_TO_SPACE(niftiHeaderOut.xyzt_units); QString spaceUnitString("Unrecognized space code: " + QString::number(spaceUnits)); switch (spaceUnits) { case NIFTI_UNITS_UNKNOWN: spaceUnitString = "NIFTI_UNITS_UNKNOWN"; break; case NIFTI_UNITS_METER: spaceUnitString = "NIFTI_UNITS_METER"; break; case NIFTI_UNITS_MM: spaceUnitString = "NIFTI_UNITS_MM"; break; case NIFTI_UNITS_MICRON: spaceUnitString = "NIFTI_UNITS_MICRON"; break; } headerDescriptionOut +=("Space Units: " + spaceUnitString + "\n"); const int timeUnits = XYZT_TO_TIME(niftiHeaderOut.xyzt_units); QString timeUnitString("Unrecognized time code: " + QString::number(timeUnits)); switch (timeUnits) { case NIFTI_UNITS_UNKNOWN: timeUnitString = "NIFTI_UNITS_UNKNOWN"; break; case NIFTI_UNITS_SEC: timeUnitString = "NIFTI_UNITS_SEC"; break; case NIFTI_UNITS_MSEC: timeUnitString = "NIFTI_UNITS_MSEC"; break; case NIFTI_UNITS_USEC: timeUnitString = "NIFTI_UNITS_USEC"; break; case NIFTI_UNITS_HZ: timeUnitString = "NIFTI_UNITS_HZ"; break; case NIFTI_UNITS_PPM: timeUnitString = "NIFTI_UNITS_PPM"; break; } headerDescriptionOut +=("Time Units: " + timeUnitString + "\n"); headerDescriptionOut += "\n"; } /** * get a string representation of the Q/S Form code. */ QString NiftiHelper::getQSFormCodeAsString(const int qsForm) { QString s = "Invalid Code: " + QString::number(qsForm); switch (qsForm) { case NIFTI_XFORM_UNKNOWN: s = "NIFTI_XFORM_UNKNOWN"; break; case NIFTI_XFORM_SCANNER_ANAT: s = "NIFTI_XFORM_SCANNER_ANAT"; break; case NIFTI_XFORM_ALIGNED_ANAT: s = "NIFTI_XFORM_ALIGNED_ANAT"; break; case NIFTI_XFORM_TALAIRACH: s = "NIFTI_XFORM_TALAIRACH"; break; case NIFTI_XFORM_MNI_152: s = "NIFTI_XFORM_MNI_152"; break; } return s; } caret-5.6.4~dfsg.1.orig/caret_files/NiftiFileHeader.h0000664000175000017500000001704411572067322022202 0ustar michaelmichael #ifndef __NIFTI_FILE_HEADER_H__ #define __NIFTI_FILE_HEADER_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ /*****===================================================================*****/ /***** Sample functions to deal with NIFTI-1 and ANALYZE files *****/ /*****...................................................................*****/ /***** This code is released to the public domain. *****/ /*****...................................................................*****/ /***** Author: Robert W Cox, SSCC/DIRP/NIMH/NIH/DHHS/USA/EARTH *****/ /***** Date: August 2003 *****/ /*****...................................................................*****/ /***** Neither the National Institutes of Health (NIH), nor any of its *****/ /***** employees imply any warranty of usefulness of this software for *****/ /***** any purpose, and do not assume any liability for damages, *****/ /***** incidental or otherwise, caused by any use of this document. *****/ /*****===================================================================*****/ #include "TransformationMatrixFile.h" #include "nifti1.h" #include "VolumeFile.h" #include "zlib.h" /// class for storing a NIFTI header and its information. class NiftiFileHeader { public: enum { NIFTI_L2R = 1, /* Left to Right */ NIFTI_R2L = 2, /* Right to Left */ NIFTI_P2A = 3, /* Posterior to Anterior */ NIFTI_A2P = 4, /* Anterior to Posterior */ NIFTI_I2S = 5, /* Inferior to Superior */ NIFTI_S2I = 6 /* Superior to Inferior */ }; /// type of stereotaxic coordinate enum STEREOTAXIC_TYPE { /// no type (qform == sform == 0) STEREOTAXIC_TYPE_NONE, /// use qform STEREOTAXIC_TYPE_QFORM, /// use sform STEREOTAXIC_TYPE_SFORM }; // constructor NiftiFileHeader(); // constructor NiftiFileHeader(const nifti_1_header niftiHeaderStructIn); // destructor ~NiftiFileHeader(); // read the header void readHeader(const QString& filename) throw (FileException); // read the header from a compressed file void readHeader(gzFile dataFile, const QString& filenameForErrorMessage) throw (FileException); // get the coordinate of a voxel (returns true if coord valid) bool getVoxelCoordinate(const int ijk[3], const STEREOTAXIC_TYPE stereotaxicType, float xyzOut[3]) const; // get a copy of the NIFTI header struct nifti_1_header getNiftiHeaderStruct() const; // set the NIFTI header struct void setNiftiHeaderStruct(const nifti_1_header niftiHeaderStructIn); // get the data type as a string QString getDataTypeAsString() const; // get a full description of the header's contents QString getDescriptionOfHeader() const; // get the sform transformation matrix TransformationMatrix getSFormTransformationMatrix() const; // get the qform transformation matrix TransformationMatrix getQFormTransformationMatrix() const; // get the sform orientation void getSFormOrientation(VolumeFile::ORIENTATION orientationOut[3]) const; // get the qform orientation void getQFormOrientation(VolumeFile::ORIENTATION orientationOut[3]) const; // get the sform orientation as a string QString getSFormOrientationAsString() const; // get the qform orientation as a string QString getQFormOrientationAsString() const; // get the qform code as a string QString getQFormCodeAsString() const; // get the sform code as a string QString getSFormCodeAsString() const; // get the spacing units as a string QString getSpacingUnitsAsString() const; // get the time units as a string QString getTimeUnitsAsString() const; // get the NIFTI intention (such as statistical parameters) information. void getNiftiIntentionInformation(QString& niftiIntentCodeAndParam, QString& niftiIntentName) const; // analyze HDR file is actually a NIFTI HDR file. static bool hdrIsNiftiFile(const QString& hdrFileName); // See if the data needs byte swapping bool doesDataNeedByteSwapping() const { return dataNeedsByteSwapping; } // set the read extension flag void setReadExtensionFlag(const bool flag) { readExtensionFlag = flag; } protected: typedef struct { /** 4x4 matrix struct **/ float m[4][4] ; } mat44 ; typedef struct { /** 3x3 matrix struct **/ float m[3][3] ; } mat33 ; // read NIFTI extension from the header void readHeaderExtension(gzFile dataFile, nifti_1_header& hdr, const bool byteSwapFlag) throw (FileException); // Methods below are caret unique static void mat44ToCaretOrientation(const TransformationMatrix& tm, VolumeFile::ORIENTATION& xOrient, VolumeFile::ORIENTATION& yOrient, VolumeFile::ORIENTATION& zOrient); // convert NIFTI orientation to Caret orientation static VolumeFile::ORIENTATION niftiOrientationToCaretOrientation( const int niftiOrientation); // get the qform or sform code as a string. QString getQOrSFormCodeAsString(const int qsForm) const; // Convert quaternions to a transformation matrix. TransformationMatrix nifti_quatern_to_mat44( float qb, float qc, float qd, float qx, float qy, float qz, float dx, float dy, float dz, float qfac ); // get orientation from a 4x4 transform static void nifti_mat44_to_orientation( mat44 R , int *icod, int *jcod, int *kcod ); // 3x3 determinant static float nifti_mat33_determ( mat33 R ) ; // 3x3 multiplication static mat33 nifti_mat33_mul( mat33 A , mat33 B ) ; // transformation matrix used by SFORM TransformationMatrix sFormTransformationMatrix; // transformation matrix used by QFORM TransformationMatrix qFormTransformationMatrix; // the NIFTI header struct nifti_1_header niftiHeaderStruct; // qform's qfac float qFormQFac; bool dataNeedsByteSwapping; QString extensionInformation; bool readExtensionFlag; }; #endif /* __NIFTI_HEADER_H__ */ caret-5.6.4~dfsg.1.orig/caret_files/NiftiFileHeader.cxx0000664000175000017500000015102611572067322022554 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ /*****===================================================================*****/ /***** Sample functions to deal with NIFTI-1 and ANALYZE files *****/ /*****...................................................................*****/ /***** This code is released to the public domain. *****/ /*****...................................................................*****/ /***** Author: Robert W Cox, SSCC/DIRP/NIMH/NIH/DHHS/USA/EARTH *****/ /***** Date: August 2003 *****/ /*****...................................................................*****/ /***** Neither the National Institutes of Health (NIH), nor any of its *****/ /***** employees imply any warranty of usefulness of this software for *****/ /***** any purpose, and do not assume any liability for damages, *****/ /***** incidental or otherwise, caused by any use of this document. *****/ /*****===================================================================*****/ #include #include #include "ByteSwapping.h" #include "NiftiFileHeader.h" /** * constructor. */ NiftiFileHeader::NiftiFileHeader() { readExtensionFlag = false; } /** * constructor. */ NiftiFileHeader::NiftiFileHeader(const nifti_1_header niftiHeaderStructIn) { readExtensionFlag = false; this->setNiftiHeaderStruct(niftiHeaderStructIn); } /** * destructor. */ NiftiFileHeader::~NiftiFileHeader() { } /** * read the header. */ void NiftiFileHeader::readHeader(const QString& filename) throw (FileException) { gzFile dataFile = gzopen(filename.toAscii().constData(), "rb"); if (dataFile == NULL) { throw FileException("Unable to open " + filename + "with ZLIB for reading."); } QString errorMessage; try { readHeader(dataFile, filename); } catch (FileException e) { errorMessage = e.whatQString(); } gzclose(dataFile); if (errorMessage.isEmpty() == false) { throw FileException(errorMessage); } } /** * read the header from a compressed file. */ void NiftiFileHeader::readHeader(gzFile dataFile, const QString& filenameForErrorMessage) throw (FileException) { if (dataFile == NULL) { throw FileException("Compressed file structure (gzFile) is invalid."); } // // Read the NIFTI header and close file after reading header // nifti_1_header hdr; const unsigned long headerSize = sizeof(hdr); const unsigned long numBytesRead = gzread(dataFile, (voidp)&hdr, headerSize); if (numBytesRead != headerSize) { std::ostringstream str; str << "Tried to read " << headerSize << " bytes from header.\n" << "Only read " << numBytesRead << " for file " << filenameForErrorMessage.toAscii().constData() << "."; throw FileException(str.str().c_str()); return; } // // Make sure it is a NIFTI file // const int version = NIFTI_VERSION(hdr); switch (version) { case 0: throw FileException(filenameForErrorMessage + "Is not a NIFTI volume file."); return; break; case 1: break; default: { std::ostringstream str; str << filenameForErrorMessage.toAscii().constData() << " is an invalid NIFTI version: " << version << "."; throw FileException(str.str().c_str()); return; } break; } // // Do bytes need to be swapped ? // dataNeedsByteSwapping = false; if (NIFTI_NEEDS_SWAP(hdr)) { dataNeedsByteSwapping = true; ByteSwapping::swapBytes(&hdr.sizeof_hdr, 1); ByteSwapping::swapBytes(&hdr.extents, 1); ByteSwapping::swapBytes(&hdr.session_error, 1); ByteSwapping::swapBytes(hdr.dim, 8); ByteSwapping::swapBytes(&hdr.intent_p1, 1); ByteSwapping::swapBytes(&hdr.intent_p2, 1); ByteSwapping::swapBytes(&hdr.intent_p3, 1); ByteSwapping::swapBytes(&hdr.intent_code, 1); ByteSwapping::swapBytes(&hdr.datatype, 1); ByteSwapping::swapBytes(&hdr.bitpix, 1); ByteSwapping::swapBytes(&hdr.slice_start, 1); ByteSwapping::swapBytes(hdr.pixdim, 8); ByteSwapping::swapBytes(&hdr.vox_offset, 1); ByteSwapping::swapBytes(&hdr.scl_slope, 1); ByteSwapping::swapBytes(&hdr.scl_inter, 1); ByteSwapping::swapBytes(&hdr.slice_end, 1); ByteSwapping::swapBytes(&hdr.cal_max, 1); ByteSwapping::swapBytes(&hdr.cal_min, 1); ByteSwapping::swapBytes(&hdr.slice_duration, 1); ByteSwapping::swapBytes(&hdr.toffset, 1); ByteSwapping::swapBytes(&hdr.glmax, 1); ByteSwapping::swapBytes(&hdr.glmin, 1); ByteSwapping::swapBytes(&hdr.qform_code, 1); ByteSwapping::swapBytes(&hdr.sform_code, 1); ByteSwapping::swapBytes(&hdr.quatern_b, 1); ByteSwapping::swapBytes(&hdr.quatern_c, 1); ByteSwapping::swapBytes(&hdr.quatern_d, 1); ByteSwapping::swapBytes(&hdr.qoffset_x, 1); ByteSwapping::swapBytes(&hdr.qoffset_y, 1); ByteSwapping::swapBytes(&hdr.qoffset_z, 1); ByteSwapping::swapBytes(hdr.srow_x, 4); ByteSwapping::swapBytes(hdr.srow_y, 4); ByteSwapping::swapBytes(hdr.srow_z, 4); } this->setNiftiHeaderStruct(hdr); if (readExtensionFlag) { readHeaderExtension(dataFile, hdr, dataNeedsByteSwapping); } } /** * read NIFTI extension from the header */ void NiftiFileHeader::readHeaderExtension(gzFile dataFile, nifti_1_header& hdr, const bool byteSwapFlag) throw (FileException) { extensionInformation = ""; // // Read the extender // if (hdr.vox_offset >= 352) { nifti1_extender extender; const unsigned long extLength = sizeof(extender); const unsigned long numBytesRead = gzread(dataFile, (voidp)&extender, extLength); //if (extLength == numBytesRead) { // if (DebugControl::getDebugOn()) { // std::cout << "NIFTI extension[0] " << static_cast(extender.extension[0]) << std::endl; // } //} int extCount = 1; z_off_t pos = gztell(dataFile); while (pos < hdr.vox_offset) { // // Read in the extension size and code // int extensionSize, extensionCode; if ((gzread(dataFile, (voidp)&extensionSize, sizeof(extensionSize)) != 4) || (gzread(dataFile, (voidp)&extensionCode, sizeof(extensionCode)) != 4)) { extensionInformation += ("WARNING: Problem reading extension" + QString::number(extCount) + "\n" + "This and all other extensions ignored.\n"); break; } else { extensionInformation += ( "Extension " + QString::number(extCount) + " before byte swap\n" + " Size: " + QString::number(extensionSize) + "\n" + " Code: " + QString::number(extensionCode) + "\n"); if (byteSwapFlag) { ByteSwapping::swapBytes(&extensionSize, 1); ByteSwapping::swapBytes(&extensionCode, 1); } extensionInformation += ( "Extension " + QString::number(extCount) + " after byte swap\n" + " Size: " + QString::number(extensionSize) + "\n" + " Code: " + QString::number(extensionCode) + "\n"); // // Check the code // const int evenNum = (extensionCode / 2) * 2; if ((evenNum < 0) || (evenNum > 100)) { extensionInformation += ("WARNING: Invalid extension code for extension " + QString::number(extCount) + "\n" + ". This and all other extensions ignored.\n"); break; } // // Check extension size // if ((extensionSize % 16) != 0) { extensionInformation += ("WARNING: NIFTI extension has size that is not a multiple of 16.\n"); } // // The 8-byte extension size/code is included in extensionSize // const int dataSize = extensionSize - 8; if (dataSize > 0) { char* data = new char[dataSize + 1]; if (gzread(dataFile, (voidp)data, dataSize) != dataSize) { extensionInformation += ("WARNING: Problem reading extension.\n" "This and all other extensions ignored.\n"); break; } data[dataSize] = '\0'; // // Is this the AFNI extension // if (extensionCode == 4) { // NIFTI_ECODE_AFNI) { extensionInformation += "AFNI extension:\n"; } delete[] data; } } extCount++; pos = gztell(dataFile); } } } /** * get the coordinate of a voxel. * Returns true if valid coordinate was created. */ bool NiftiFileHeader::getVoxelCoordinate(const int ijk[3], const STEREOTAXIC_TYPE stereotaxicType, float xyzOut[3]) const { bool validCoordFlag = false; switch (stereotaxicType) { case STEREOTAXIC_TYPE_NONE: xyzOut[0] = this->niftiHeaderStruct.pixdim[1] * ijk[0]; xyzOut[1] = this->niftiHeaderStruct.pixdim[2] * ijk[1]; xyzOut[2] = this->niftiHeaderStruct.pixdim[3] * ijk[2]; validCoordFlag = true; break; case STEREOTAXIC_TYPE_QFORM: if (this->niftiHeaderStruct.qform_code > 0) { float p[4] = { this->niftiHeaderStruct.pixdim[1] * ijk[0], this->niftiHeaderStruct.pixdim[2] * ijk[1], (this->niftiHeaderStruct.pixdim[3] * ijk[2] * this->qFormQFac), 1.0 }; this->qFormTransformationMatrix.multiplyPoint(p); xyzOut[0] = p[0] + this->niftiHeaderStruct.qoffset_x; xyzOut[1] = p[1] + this->niftiHeaderStruct.qoffset_y; xyzOut[2] = p[2] + this->niftiHeaderStruct.qoffset_z; validCoordFlag = true; } break; case STEREOTAXIC_TYPE_SFORM: if (this->niftiHeaderStruct.sform_code > 0) { float p[4] = { ijk[0], ijk[1], ijk[2], 1.0 }; this->sFormTransformationMatrix.multiplyPoint(p); xyzOut[0] = p[0]; xyzOut[1] = p[1]; xyzOut[2] = p[2]; validCoordFlag = true; } break; } return validCoordFlag; } /** * get a copy of the NIFTI header struct. */ nifti_1_header NiftiFileHeader::getNiftiHeaderStruct() const { return this->niftiHeaderStruct; } /** * set the NIFTI header struct. */ void NiftiFileHeader::setNiftiHeaderStruct(const nifti_1_header niftiHeaderStructIn) { niftiHeaderStruct = niftiHeaderStructIn; VolumeFile::ORIENTATION qformOrientation[3] = { VolumeFile::ORIENTATION_UNKNOWN, VolumeFile::ORIENTATION_UNKNOWN, VolumeFile::ORIENTATION_UNKNOWN }; VolumeFile::ORIENTATION sformOrientation[3] = { VolumeFile::ORIENTATION_UNKNOWN, VolumeFile::ORIENTATION_UNKNOWN, VolumeFile::ORIENTATION_UNKNOWN }; if (niftiHeaderStruct.sform_code > 0) { // // NIFTI origin is in the center of the voxel // so move the origin to the corner of voxel // //volumeRead.origin[0] -= volumeRead.spacing[0] * 0.5; //volumeRead.origin[1] -= volumeRead.spacing[1] * 0.5; //volumeRead.origin[2] -= volumeRead.spacing[2] * 0.5; TransformationMatrix sm; sm.setMatrixElement(0, 0, niftiHeaderStruct.srow_x[0]); sm.setMatrixElement(0, 1, niftiHeaderStruct.srow_x[1]); sm.setMatrixElement(0, 2, niftiHeaderStruct.srow_x[2]); sm.setMatrixElement(0, 3, niftiHeaderStruct.srow_x[3]); sm.setMatrixElement(1, 0, niftiHeaderStruct.srow_y[0]); sm.setMatrixElement(1, 1, niftiHeaderStruct.srow_y[1]); sm.setMatrixElement(1, 2, niftiHeaderStruct.srow_y[2]); sm.setMatrixElement(1, 3, niftiHeaderStruct.srow_y[3]); sm.setMatrixElement(2, 0, niftiHeaderStruct.srow_z[0]); sm.setMatrixElement(2, 1, niftiHeaderStruct.srow_z[1]); sm.setMatrixElement(2, 2, niftiHeaderStruct.srow_z[2]); sm.setMatrixElement(2, 3, niftiHeaderStruct.srow_z[3]); sm.setMatrixElement(3, 0, 0.0); sm.setMatrixElement(3, 1, 0.0); sm.setMatrixElement(3, 2, 0.0); sm.setMatrixElement(3, 3, 1.0); NiftiFileHeader::mat44ToCaretOrientation(sm, sformOrientation[0], sformOrientation[1], sformOrientation[2]); this->sFormTransformationMatrix = sm; } else { this->sFormTransformationMatrix.identity(); } if (niftiHeaderStruct.qform_code > 0) { this->qFormQFac = (niftiHeaderStruct.pixdim[0] < 0.0) ? -1.0 : 1.0 ; /* left-handedness? */ qFormTransformationMatrix = nifti_quatern_to_mat44(niftiHeaderStruct.quatern_b, niftiHeaderStruct.quatern_c, niftiHeaderStruct.quatern_d, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, this->qFormQFac); NiftiFileHeader::mat44ToCaretOrientation(this->qFormTransformationMatrix, qformOrientation[0], qformOrientation[1], qformOrientation[2]); } } /** * get the data type as a string. */ QString NiftiFileHeader::getDataTypeAsString() const { QString dataCodeString = ("Unrecognized data type code = " + QString::number(this->niftiHeaderStruct.datatype)); switch (this->niftiHeaderStruct.datatype) { case DT_UNKNOWN: dataCodeString = "DT_UNKNOWN"; break; case DT_BINARY: dataCodeString = "DT_BINARY"; break; case NIFTI_TYPE_UINT8: dataCodeString = "NIFTI_TYPE_UINT8"; break; case NIFTI_TYPE_INT16: dataCodeString = "NIFTI_TYPE_INT16"; break; case NIFTI_TYPE_INT32: dataCodeString = "NIFTI_TYPE_INT32"; break; case NIFTI_TYPE_FLOAT32: dataCodeString = "NIFTI_TYPE_FLOAT32"; break; case NIFTI_TYPE_COMPLEX64: dataCodeString = "NIFTI_TYPE_COMPLEX64"; break; case NIFTI_TYPE_FLOAT64: dataCodeString = "NIFTI_TYPE_FLOAT64"; break; case NIFTI_TYPE_RGB24: dataCodeString = "NIFTI_TYPE_RGB24"; break; case NIFTI_TYPE_INT8: dataCodeString = "NIFTI_TYPE_INT8"; break; case NIFTI_TYPE_UINT16: dataCodeString = "NIFTI_TYPE_UINT16"; break; case NIFTI_TYPE_UINT32: dataCodeString = "NIFTI_TYPE_UINT32"; break; case NIFTI_TYPE_INT64: dataCodeString = "NIFTI_TYPE_INT64"; break; case NIFTI_TYPE_UINT64: dataCodeString = "NIFTI_TYPE_UINT64"; break; case NIFTI_TYPE_FLOAT128: dataCodeString = "NIFTI_TYPE_FLOAT128"; break; case NIFTI_TYPE_COMPLEX128: dataCodeString = "NIFTI_TYPE_COMPLEX128"; break; case NIFTI_TYPE_COMPLEX256: dataCodeString = "NIFTI_TYPE_COMPLEX256"; break; } return dataCodeString; } /** * get the qform code as a string. */ QString NiftiFileHeader::getQFormCodeAsString() const { return this->getQOrSFormCodeAsString(this->niftiHeaderStruct.qform_code); } /** * get the sform code as a string. */ QString NiftiFileHeader::getSFormCodeAsString() const { return this->getQOrSFormCodeAsString(this->niftiHeaderStruct.sform_code); } /** * get the qform or sform code as a string. */ QString NiftiFileHeader::getQOrSFormCodeAsString(const int qsForm) const { QString s = "Invalid Code: " + QString::number(qsForm); switch (qsForm) { case NIFTI_XFORM_UNKNOWN: s = "NIFTI_XFORM_UNKNOWN"; break; case NIFTI_XFORM_SCANNER_ANAT: s = "NIFTI_XFORM_SCANNER_ANAT"; break; case NIFTI_XFORM_ALIGNED_ANAT: s = "NIFTI_XFORM_ALIGNED_ANAT"; break; case NIFTI_XFORM_TALAIRACH: s = "NIFTI_XFORM_TALAIRACH"; break; case NIFTI_XFORM_MNI_152: s = "NIFTI_XFORM_MNI_152"; break; } return s; } /** * get a full description of the header's contents. */ QString NiftiFileHeader::getDescriptionOfHeader() const { int precision = 3; QStringList keys, values; keys << "sizeof_hdr"; values << QString::number(this->niftiHeaderStruct.sizeof_hdr); keys << "data_type"; QString dataTypeString; for (int i = 0; i < 10; i++) { if (this->niftiHeaderStruct.data_type[i] == '\0') { break; } dataTypeString += this->niftiHeaderStruct.data_type[i]; } values << dataTypeString; keys << "db_name"; QString dbNameString; for (int i = 0; i < 18; i++) { if (this->niftiHeaderStruct.db_name[i] == '\0') { break; } dbNameString += this->niftiHeaderStruct.db_name[i]; } values << dbNameString; keys << "extents"; values << QString::number(this->niftiHeaderStruct.extents); keys << "session_error"; values << QString::number(this->niftiHeaderStruct.session_error); keys << "regular"; values << QChar(this->niftiHeaderStruct.regular); keys << "dim_info"; values << QString::number(this->niftiHeaderStruct.dim_info); keys << "dim"; QString dimString; for (int i = 0; i < 8; i++) { dimString += QString::number(this->niftiHeaderStruct.dim[i]) + " "; } values << dimString; keys << "intent_p1"; values << QString::number(this->niftiHeaderStruct.intent_p1, 'f', precision); keys << "intent_p2"; values << QString::number(this->niftiHeaderStruct.intent_p2, 'f', precision); keys << "intent_p3"; values << QString::number(this->niftiHeaderStruct.intent_p3, 'f', precision); keys << "intent_code"; values << QString::number(this->niftiHeaderStruct.intent_code); keys << "datatype"; values << QString::number(this->niftiHeaderStruct.datatype); keys << "bitpix"; values << QString::number(this->niftiHeaderStruct.bitpix); keys << "slice_start"; values << QString::number(this->niftiHeaderStruct.slice_start); keys << "pixdim"; QString pixDimString; for (int i = 0; i < 8; i++) { pixDimString += QString::number(this->niftiHeaderStruct.pixdim[i], 'f', precision) + " "; } values << pixDimString; keys << "vox_offset"; values << QString::number(this->niftiHeaderStruct.vox_offset, 'f', precision); keys << "scl_slope"; values << QString::number(this->niftiHeaderStruct.scl_slope, 'f', precision); keys << "scl_inter"; values << QString::number(this->niftiHeaderStruct.scl_inter, 'f', precision); keys << "slice_end"; values << QString::number(this->niftiHeaderStruct.slice_end); keys << "slice_code"; values << QString::number(this->niftiHeaderStruct.slice_code); keys << "xyzt_units"; values << QString::number(this->niftiHeaderStruct.xyzt_units); keys << "cal_max"; values << QString::number(this->niftiHeaderStruct.cal_max, 'f', precision); keys << "cal_min"; values << QString::number(this->niftiHeaderStruct.cal_min, 'f', precision); keys << "slice_duration"; values << QString::number(this->niftiHeaderStruct.slice_duration, 'f', precision); keys << "toffset"; values << QString::number(this->niftiHeaderStruct.toffset, 'f', precision); keys << "glmax"; values << QString::number(this->niftiHeaderStruct.glmax); keys << "glmin"; values << QString::number(this->niftiHeaderStruct.glmin); QString description; for (int i = 0; i < 80; i++) { if (this->niftiHeaderStruct.descrip[i] == '\0') { break; } description += this->niftiHeaderStruct.descrip[i]; } keys << "description"; values << description; QString auxFile; for (int i = 0; i < 24; i++) { if (this->niftiHeaderStruct.aux_file[i] == '\0') { break; } auxFile += this->niftiHeaderStruct.aux_file[i]; } keys << "aux_file"; values << auxFile; keys << "qform_code"; values << QString::number(this->niftiHeaderStruct.qform_code); keys << "sform_code"; values << QString::number(this->niftiHeaderStruct.sform_code); keys << "quatern_b"; values << QString::number(this->niftiHeaderStruct.quatern_b, 'f', precision); keys << "quatern_c"; values << QString::number(this->niftiHeaderStruct.quatern_c, 'f', precision); keys << "quatern_d"; values << QString::number(this->niftiHeaderStruct.quatern_d, 'f', precision); keys << "qoffset_x"; values << QString::number(this->niftiHeaderStruct.qoffset_x, 'f', precision); keys << "qoffset_y"; values << QString::number(this->niftiHeaderStruct.qoffset_y, 'f', precision); keys << "qoffset_z"; values << QString::number(this->niftiHeaderStruct.qoffset_z, 'f', precision); QString sRowX; for (int i = 0; i < 4; i++) { sRowX += QString::number(this->niftiHeaderStruct.srow_x[i], 'f', precision) + " "; } keys << "srow_x"; values << sRowX; QString sRowY; for (int i = 0; i < 4; i++) { sRowY += QString::number(this->niftiHeaderStruct.srow_y[i], 'f', precision) + " "; } keys << "srow_y"; values << sRowY; QString sRowZ; for (int i = 0; i < 4; i++) { sRowZ += QString::number(this->niftiHeaderStruct.srow_z[i], 'f', precision) + " "; } keys << "srow_z"; values << sRowZ; QString intentName; for (int i = 0; i < 16; i++) { if (this->niftiHeaderStruct.intent_name[i] == '\0') { break; } intentName += this->niftiHeaderStruct.intent_name[i]; } keys << "intent_name"; values << intentName; QString magic; for (int i = 0; i < 3; i++) { if (this->niftiHeaderStruct.magic[i] == '\0') { break; } magic += this->niftiHeaderStruct.magic[i]; } keys << "magic"; values << magic; // // Get key maximum length // int maxLength = 0; for (int i = 0; i < keys.count(); i++) { maxLength = std::max(maxLength, keys.at(i).length()); } QString headerDescriptionOut; // // Place data into header description // for (int i = 0; i < keys.count(); i++) { headerDescriptionOut += QString("%1: %2\n").arg(keys.at(i), maxLength).arg(values.at(i)); } headerDescriptionOut += "\n"; // // Intent Information // QString niftiIntentCodeAndParam; QString niftiIntentName; NiftiFileHeader::getNiftiIntentionInformation(niftiIntentCodeAndParam, niftiIntentName); headerDescriptionOut += ("Intent Name: " + niftiIntentName + "\n"); headerDescriptionOut += ("Intent Parameters:" + niftiIntentCodeAndParam + "\n"); headerDescriptionOut += "\n"; int firstVoxelIJK[3] = { 0, 0, 0 }; int secondVoxelIJK[3] = { 1, 1, 1 }; float voxelXYZ[3]; if (this->getVoxelCoordinate(firstVoxelIJK, NiftiFileHeader::STEREOTAXIC_TYPE_NONE, voxelXYZ)) { headerDescriptionOut += (" First Voxel XYZ (method 1): " + QString::number(voxelXYZ[0], 'f', precision) + ", " + QString::number(voxelXYZ[1], 'f', precision) + ", " + QString::number(voxelXYZ[2], 'f', precision) + "\n"); float voxelTwoXYZ[3]; if (this->getVoxelCoordinate(secondVoxelIJK, NiftiFileHeader::STEREOTAXIC_TYPE_NONE, voxelTwoXYZ)) { const float spacing[3] = { voxelTwoXYZ[0] - voxelXYZ[0], voxelTwoXYZ[1] - voxelXYZ[1], voxelTwoXYZ[2] - voxelXYZ[2] }; headerDescriptionOut += ( " Spacing: " + QString::number(spacing[0], 'f', precision) + ", " + QString::number(spacing[1], 'f', precision) + ", " + QString::number(spacing[2], 'f', precision) + "\n"); } } headerDescriptionOut += "\n"; // // qform matrix and orientation // headerDescriptionOut += ("QFORM: " + this->getQFormCodeAsString() + "\n"); for (int i = 0; i < 4; i++) { headerDescriptionOut += " "; for (int j = 0; j < 4; j++) { headerDescriptionOut += QString::number(this->qFormTransformationMatrix.getMatrixElement(i, j), 'f', precision).rightJustified(12, ' '); } headerDescriptionOut += "\n"; } headerDescriptionOut += (" Orientation: " + this->getQFormOrientationAsString() + "\n"); float qformXYZ[3]; if (this->getVoxelCoordinate(firstVoxelIJK, NiftiFileHeader::STEREOTAXIC_TYPE_QFORM, qformXYZ)) { headerDescriptionOut += (" First Voxel XYZ (Method 2): " + QString::number(qformXYZ[0], 'f', precision) + ", " + QString::number(qformXYZ[1], 'f', precision) + ", " + QString::number(qformXYZ[2], 'f', precision) + "\n"); float voxelTwoXYZ[3]; if (this->getVoxelCoordinate(secondVoxelIJK, NiftiFileHeader::STEREOTAXIC_TYPE_QFORM, voxelTwoXYZ)) { const float spacing[3] = { voxelTwoXYZ[0] - qformXYZ[0], voxelTwoXYZ[1] - qformXYZ[1], voxelTwoXYZ[2] - qformXYZ[2] }; headerDescriptionOut += ( " Spacing: " + QString::number(spacing[0], 'f', precision) + ", " + QString::number(spacing[1], 'f', precision) + ", " + QString::number(spacing[2], 'f', precision) + "\n"); } } headerDescriptionOut += "\n"; // // sform matrix and orientation // headerDescriptionOut += ("SFORM: " + this->getSFormCodeAsString() + "\n"); for (int i = 0; i < 4; i++) { headerDescriptionOut += " "; for (int j = 0; j < 4; j++) { headerDescriptionOut += QString::number(this->sFormTransformationMatrix.getMatrixElement(i, j), 'f', precision).rightJustified(12, ' '); } headerDescriptionOut += "\n"; } headerDescriptionOut += (" Orientation: " + this->getSFormOrientationAsString() + "\n"); float sformXYZ[3]; if (this->getVoxelCoordinate(firstVoxelIJK, NiftiFileHeader::STEREOTAXIC_TYPE_SFORM, sformXYZ)) { headerDescriptionOut += (" First Voxel XYZ (Method 3): " + QString::number(sformXYZ[0], 'f', precision) + ", " + QString::number(sformXYZ[1], 'f', precision) + ", " + QString::number(sformXYZ[2], 'f', precision) + "\n"); float voxelTwoXYZ[3]; if (this->getVoxelCoordinate(secondVoxelIJK, NiftiFileHeader::STEREOTAXIC_TYPE_SFORM, voxelTwoXYZ)) { const float spacing[3] = { voxelTwoXYZ[0] - sformXYZ[0], voxelTwoXYZ[1] - sformXYZ[1], voxelTwoXYZ[2] - sformXYZ[2] }; headerDescriptionOut += ( " Spacing: " + QString::number(spacing[0], 'f', precision) + ", " + QString::number(spacing[1], 'f', precision) + ", " + QString::number(spacing[2], 'f', precision) + "\n"); } } headerDescriptionOut += "\n"; headerDescriptionOut += ("Data Type: " + this->getDataTypeAsString() + "\n"); headerDescriptionOut += "\n"; headerDescriptionOut +=("Space Units: " + this->getSpacingUnitsAsString() + "\n"); headerDescriptionOut +=("Time Units: " + this->getTimeUnitsAsString() + "\n"); headerDescriptionOut += "\n"; if (extensionInformation.isEmpty() == false) { headerDescriptionOut += extensionInformation; headerDescriptionOut += "\n"; } return headerDescriptionOut; } /** * get the sform transformation matrix. */ TransformationMatrix NiftiFileHeader::getSFormTransformationMatrix() const { return this->sFormTransformationMatrix; } /** * get the qform transformation matrix. */ TransformationMatrix NiftiFileHeader::getQFormTransformationMatrix() const { return this->qFormTransformationMatrix; } /** * get the sform orientation. */ void NiftiFileHeader::getSFormOrientation(VolumeFile::ORIENTATION orientationOut[3]) const { orientationOut[0] = VolumeFile::ORIENTATION_UNKNOWN; orientationOut[1] = VolumeFile::ORIENTATION_UNKNOWN; orientationOut[2] = VolumeFile::ORIENTATION_UNKNOWN; if (this->niftiHeaderStruct.sform_code > 0) { NiftiFileHeader::mat44ToCaretOrientation(this->sFormTransformationMatrix, orientationOut[0], orientationOut[1], orientationOut[2]); } } void NiftiFileHeader::nifti_mat44_to_orientation( mat44 R , int *icod, int *jcod, int *kcod ) { float xi,xj,xk , yi,yj,yk , zi,zj,zk , val,detQ,detP ; mat33 P , Q , M ; int i,j,k=0,p,q,r , ibest,jbest,kbest,pbest,qbest,rbest ; float vbest ; if( icod == NULL || jcod == NULL || kcod == NULL ) return ; /* bad */ *icod = *jcod = *kcod = 0 ; /* error returns, if sh*t happens */ /* load column vectors for each (i,j,k) direction from matrix */ /*-- i axis --*/ /*-- j axis --*/ /*-- k axis --*/ xi = R.m[0][0] ; xj = R.m[0][1] ; xk = R.m[0][2] ; yi = R.m[1][0] ; yj = R.m[1][1] ; yk = R.m[1][2] ; zi = R.m[2][0] ; zj = R.m[2][1] ; zk = R.m[2][2] ; /* normalize column vectors to get unit vectors along each ijk-axis */ /* normalize i axis */ val = std::sqrt( xi*xi + yi*yi + zi*zi ) ; if( val == 0.0 ) return ; /* stupid input */ xi /= val ; yi /= val ; zi /= val ; /* normalize j axis */ val = std::sqrt( xj*xj + yj*yj + zj*zj ) ; if( val == 0.0 ) return ; /* stupid input */ xj /= val ; yj /= val ; zj /= val ; /* orthogonalize j axis to i axis, if needed */ val = xi*xj + yi*yj + zi*zj ; /* dot product between i and j */ if( std::fabs(val) > 1.e-4 ){ xj -= val*xi ; yj -= val*yi ; zj -= val*zi ; val = std::sqrt( xj*xj + yj*yj + zj*zj ) ; /* must renormalize */ if( val == 0.0 ) return ; /* j was parallel to i? */ xj /= val ; yj /= val ; zj /= val ; } /* normalize k axis; if it is zero, make it the cross product i x j */ val = std::sqrt( xk*xk + yk*yk + zk*zk ) ; if( val == 0.0 ){ xk = yi*zj-zi*yj; yk = zi*xj-zj*xi ; zk=xi*yj-yi*xj ; } else { xk /= val ; yk /= val ; zk /= val ; } /* orthogonalize k to i */ val = xi*xk + yi*yk + zi*zk ; /* dot product between i and k */ if( std::fabs(val) > 1.e-4 ){ xk -= val*xi ; yk -= val*yi ; zk -= val*zi ; val = std::sqrt( xk*xk + yk*yk + zk*zk ) ; if( val == 0.0 ) return ; /* bad */ xk /= val ; yk /= val ; zk /= val ; } /* orthogonalize k to j */ val = xj*xk + yj*yk + zj*zk ; /* dot product between j and k */ if( std::fabs(val) > 1.e-4 ){ xk -= val*xj ; yk -= val*yj ; zk -= val*zj ; val = std::sqrt( xk*xk + yk*yk + zk*zk ) ; if( val == 0.0 ) return ; /* bad */ xk /= val ; yk /= val ; zk /= val ; } Q.m[0][0] = xi ; Q.m[0][1] = xj ; Q.m[0][2] = xk ; Q.m[1][0] = yi ; Q.m[1][1] = yj ; Q.m[1][2] = yk ; Q.m[2][0] = zi ; Q.m[2][1] = zj ; Q.m[2][2] = zk ; /* at this point, Q is the rotation matrix from the (i,j,k) to (x,y,z) axes */ detQ = nifti_mat33_determ( Q ) ; if( detQ == 0.0 ) return ; /* shouldn't happen unless user is a DUFIS */ /* Build and test all possible +1/-1 coordinate permutation matrices P; then find the P such that the rotation matrix M=PQ is closest to the identity, in the sense of M having the smallest total rotation angle. */ /* Despite the formidable looking 6 nested loops, there are only 3*3*3*2*2*2 = 216 passes, which will run very quickly. */ vbest = -666.0 ; ibest=pbest=qbest=rbest=1 ; jbest=2 ; kbest=3 ; for( i=1 ; i <= 3 ; i++ ){ /* i = column number to use for row #1 */ for( j=1 ; j <= 3 ; j++ ){ /* j = column number to use for row #2 */ if( i == j ) continue ; for( k=1 ; k <= 3 ; k++ ){ /* k = column number to use for row #3 */ if( i == k || j == k ) continue ; P.m[0][0] = P.m[0][1] = P.m[0][2] = P.m[1][0] = P.m[1][1] = P.m[1][2] = P.m[2][0] = P.m[2][1] = P.m[2][2] = 0.0 ; for( p=-1 ; p <= 1 ; p+=2 ){ /* p,q,r are -1 or +1 */ for( q=-1 ; q <= 1 ; q+=2 ){ /* and go into rows #1,2,3 */ for( r=-1 ; r <= 1 ; r+=2 ){ P.m[0][i-1] = p ; P.m[1][j-1] = q ; P.m[2][k-1] = r ; detP = nifti_mat33_determ(P) ; /* sign of permutation */ if( detP * detQ <= 0.0 ) continue ; /* doesn't match sign of Q */ M = nifti_mat33_mul(P,Q) ; /* angle of M rotation = 2.0*acos(0.5*sqrt(1.0+trace(M))) */ /* we want largest trace(M) == smallest angle == M nearest to I */ val = M.m[0][0] + M.m[1][1] + M.m[2][2] ; /* trace */ if( val > vbest ){ vbest = val ; ibest = i ; jbest = j ; kbest = k ; pbest = p ; qbest = q ; rbest = r ; } }}}}}} /* At this point ibest is 1 or 2 or 3; pbest is -1 or +1; etc. The matrix P that corresponds is the best permutation approximation to Q-inverse; that is, P (approximately) takes (x,y,z) coordinates to the (i,j,k) axes. For example, the first row of P (which contains pbest in column ibest) determines the way the i axis points relative to the anatomical (x,y,z) axes. If ibest is 2, then the i axis is along the y axis, which is direction P2A (if pbest > 0) or A2P (if pbest < 0). So, using ibest and pbest, we can assign the output code for the i axis. Mutatis mutandis for the j and k axes, of course. */ switch( ibest*pbest ){ case 1: i = NIFTI_L2R ; break ; case -1: i = NIFTI_R2L ; break ; case 2: i = NIFTI_P2A ; break ; case -2: i = NIFTI_A2P ; break ; case 3: i = NIFTI_I2S ; break ; case -3: i = NIFTI_S2I ; break ; } switch( jbest*qbest ){ case 1: j = NIFTI_L2R ; break ; case -1: j = NIFTI_R2L ; break ; case 2: j = NIFTI_P2A ; break ; case -2: j = NIFTI_A2P ; break ; case 3: j = NIFTI_I2S ; break ; case -3: j = NIFTI_S2I ; break ; } switch( kbest*rbest ){ case 1: k = NIFTI_L2R ; break ; case -1: k = NIFTI_R2L ; break ; case 2: k = NIFTI_P2A ; break ; case -2: k = NIFTI_A2P ; break ; case 3: k = NIFTI_I2S ; break ; case -3: k = NIFTI_S2I ; break ; } *icod = i ; *jcod = j ; *kcod = k ; return ; } /** * Methods below are caret unique. */ void NiftiFileHeader::mat44ToCaretOrientation(const TransformationMatrix& tm, VolumeFile::ORIENTATION& xOrient, VolumeFile::ORIENTATION& yOrient, VolumeFile::ORIENTATION& zOrient) { mat44 m; tm.getMatrix(m.m); int x, y, z; NiftiFileHeader::nifti_mat44_to_orientation(m, &x, &y, &z); xOrient = niftiOrientationToCaretOrientation(x); yOrient = niftiOrientationToCaretOrientation(y); zOrient = niftiOrientationToCaretOrientation(z); } /** * convert NIFTI orientation to Caret orientation. */ VolumeFile::ORIENTATION NiftiFileHeader::niftiOrientationToCaretOrientation(const int niftiOrientation) { VolumeFile::ORIENTATION orient = VolumeFile::ORIENTATION_UNKNOWN; switch(niftiOrientation) { case NiftiFileHeader::NIFTI_L2R: orient = VolumeFile::ORIENTATION_LEFT_TO_RIGHT; break; case NiftiFileHeader::NIFTI_R2L: orient = VolumeFile::ORIENTATION_RIGHT_TO_LEFT; break; case NiftiFileHeader::NIFTI_P2A: orient = VolumeFile::ORIENTATION_POSTERIOR_TO_ANTERIOR; break; case NiftiFileHeader::NIFTI_A2P: orient = VolumeFile::ORIENTATION_ANTERIOR_TO_POSTERIOR; break; case NiftiFileHeader::NIFTI_I2S: orient = VolumeFile::ORIENTATION_INFERIOR_TO_SUPERIOR; break; case NiftiFileHeader::NIFTI_S2I: orient = VolumeFile::ORIENTATION_SUPERIOR_TO_INFERIOR; break; } return orient; } /** * get the qform orientation. */ void NiftiFileHeader::getQFormOrientation(VolumeFile::ORIENTATION orientationOut[3]) const { orientationOut[0] = VolumeFile::ORIENTATION_UNKNOWN; orientationOut[1] = VolumeFile::ORIENTATION_UNKNOWN; orientationOut[2] = VolumeFile::ORIENTATION_UNKNOWN; if (this->niftiHeaderStruct.qform_code > 0) { NiftiFileHeader::mat44ToCaretOrientation(this->qFormTransformationMatrix, orientationOut[0], orientationOut[1], orientationOut[2]); } } /** * get the sform orientation as a string. */ QString NiftiFileHeader::getSFormOrientationAsString() const { VolumeFile::ORIENTATION orientation[3]; this->getSFormOrientation(orientation); const QString s = (VolumeFile::getOrientationLabel(orientation[0]) + ", " + VolumeFile::getOrientationLabel(orientation[1]) + ", " + VolumeFile::getOrientationLabel(orientation[2])); return s; } /** * get the qform orientation as a string. */ QString NiftiFileHeader::getQFormOrientationAsString() const { VolumeFile::ORIENTATION orientation[3]; this->getQFormOrientation(orientation); const QString s = (VolumeFile::getOrientationLabel(orientation[0]) + ", " + VolumeFile::getOrientationLabel(orientation[1]) + ", " + VolumeFile::getOrientationLabel(orientation[2])); return s; } /** * get the spacing units as a string. */ QString NiftiFileHeader::getSpacingUnitsAsString() const { const int spaceUnits = XYZT_TO_SPACE(this->niftiHeaderStruct.xyzt_units); QString spaceUnitString("Unrecognized space code: " + QString::number(spaceUnits)); switch (spaceUnits) { case NIFTI_UNITS_UNKNOWN: spaceUnitString = "NIFTI_UNITS_UNKNOWN"; break; case NIFTI_UNITS_METER: spaceUnitString = "NIFTI_UNITS_METER"; break; case NIFTI_UNITS_MM: spaceUnitString = "NIFTI_UNITS_MM"; break; case NIFTI_UNITS_MICRON: spaceUnitString = "NIFTI_UNITS_MICRON"; break; } return spaceUnitString; } /** * get the time units as a string. */ QString NiftiFileHeader::getTimeUnitsAsString() const { const int timeUnits = XYZT_TO_TIME(this->niftiHeaderStruct.xyzt_units); QString timeUnitString("Unrecognized time code: " + QString::number(timeUnits)); switch (timeUnits) { case NIFTI_UNITS_UNKNOWN: timeUnitString = "NIFTI_UNITS_UNKNOWN"; break; case NIFTI_UNITS_SEC: timeUnitString = "NIFTI_UNITS_SEC"; break; case NIFTI_UNITS_MSEC: timeUnitString = "NIFTI_UNITS_MSEC"; break; case NIFTI_UNITS_USEC: timeUnitString = "NIFTI_UNITS_USEC"; break; case NIFTI_UNITS_HZ: timeUnitString = "NIFTI_UNITS_HZ"; break; case NIFTI_UNITS_PPM: timeUnitString = "NIFTI_UNITS_PPM"; break; } return timeUnitString; } /** * get the NIFTI intention (such as statistical parameters) information. */ void NiftiFileHeader::getNiftiIntentionInformation(QString& niftiIntentCodeAndParam, QString& niftiIntentName) const { niftiIntentName = ("NIFTI_INTENT_NOT_RECOGNIZED_CODE_" + QString::number(this->niftiHeaderStruct.intent_code)); QString intentDescription; QString p1; QString p2; QString p3; switch (this->niftiHeaderStruct.intent_code) { case NIFTI_INTENT_NONE: niftiIntentName = "NIFTI_INTENT_NONE"; intentDescription = "None" ; p1 = ""; p2 = ""; p3 = ""; break; case NIFTI_INTENT_CORREL: niftiIntentName = "NIFTI_INTENT_CORREL"; intentDescription = "Correlation statistic" ; p1 = "DOF"; p2 = ""; p3 = ""; break; case NIFTI_INTENT_TTEST: niftiIntentName = "NIFTI_INTENT_TTEST"; intentDescription = "T-statistic" ; p1 = "DOF"; p2 = ""; p3 = ""; break; case NIFTI_INTENT_FTEST: niftiIntentName = "NIFTI_INTENT_FTEST"; intentDescription = "F-statistic" ; p1 = "Numerator DOF"; p2 = "Denorminator DOF"; p3 = ""; break; case NIFTI_INTENT_ZSCORE: niftiIntentName = "NIFTI_INTENT_ZSCORE"; intentDescription = "Z-score" ; p1 = ""; p2 = ""; p3 = ""; break; case NIFTI_INTENT_CHISQ: niftiIntentName = "NIFTI_INTENT_CHISQ"; intentDescription = "Chi-squared distribution" ; p1 = "DOF"; p2 = ""; p3 = ""; break; case NIFTI_INTENT_BETA: niftiIntentName = "NIFTI_INTENT_BETA"; intentDescription = "Beta distribution" ; p1 = "a"; p2 = "b"; p3 = ""; break; case NIFTI_INTENT_BINOM: niftiIntentName = "NIFTI_INTENT_BINOM"; intentDescription = "Binomial distribution" ; p1 = "Number of Trials"; p2 = "Probability per Trial"; p3 = ""; break; case NIFTI_INTENT_GAMMA: niftiIntentName = "NIFTI_INTENT_GAMMA"; intentDescription = "Gamma distribution" ; p1 = "Shape"; p2 = "Scale"; p3 = ""; break; case NIFTI_INTENT_POISSON: niftiIntentName = "NIFTI_INTENT_POISSON"; intentDescription = "Poisson distribution" ; p1 = "Mean"; p2 = ""; p3 = ""; break; case NIFTI_INTENT_NORMAL: niftiIntentName = "NIFTI_INTENT_NORMAL"; intentDescription = "Normal distribution" ; p1 = "Mean"; p2 = "Standard Deviation"; p3 = ""; break; case NIFTI_INTENT_FTEST_NONC: niftiIntentName = "NIFTI_INTENT_FTEST_NONC"; intentDescription = "F-statistic noncentral" ; p1 = "Numerator DOF"; p2 = "Denominator DOF"; p3 = "Numerator Noncentrality Parameter"; break; case NIFTI_INTENT_CHISQ_NONC: niftiIntentName = "NIFTI_INTENT_CHISQ_NONC"; intentDescription = "Chi-squared noncentral" ; p1 = "DOF"; p2 = "Noncentrality Parameter"; p3 = ""; break; case NIFTI_INTENT_LOGISTIC: niftiIntentName = "NIFTI_INTENT_LOGISTIC"; intentDescription = "Logistic distribution" ; p1 = "Location"; p2 = "Scale"; p3 = ""; break; case NIFTI_INTENT_LAPLACE: niftiIntentName = "NIFTI_INTENT_LAPLACE"; intentDescription = "Laplace distribution" ; p1 = "Location"; p2 = "Scale"; p3 = ""; break; case NIFTI_INTENT_UNIFORM: niftiIntentName = "NIFTI_INTENT_UNIFORM"; intentDescription = "Uniform distribition" ; p1 = "Lower End"; p2 = "Upper End"; p3 = ""; break; case NIFTI_INTENT_TTEST_NONC: niftiIntentName = "NIFTI_INTENT_TTEST_NONC"; intentDescription = "T-statistic noncentral" ; p1 = "DOF"; p2 = "Noncentrality Parameter"; p3 = ""; break; case NIFTI_INTENT_WEIBULL: niftiIntentName = "NIFTI_INTENT_WEIBULL"; intentDescription = "Weibull distribution" ; p1 = "Location"; p2 = "Scale"; p3 = "Power"; break; case NIFTI_INTENT_CHI: niftiIntentName = "NIFTI_INTENT_CHI"; intentDescription = "Chi distribution" ; p1 = "Half Normal Distribution"; p2 = "Rayleigh Distritibution"; p3 = "Maxwell-Boltzmann Distribution"; break; case NIFTI_INTENT_INVGAUSS: niftiIntentName = "NIFTI_INTENT_INVGAUSS"; intentDescription = "Inverse Gaussian distribution" ; p1 = "MU"; p2 = "Lambda"; p3 = ""; break; case NIFTI_INTENT_EXTVAL: niftiIntentName = "NIFTI_INTENT_EXTVAL"; intentDescription = "Extreme Value distribution" ; p1 = "Location"; p2 = "Scale"; p3 = ""; break; case NIFTI_INTENT_PVAL: niftiIntentName = "NIFTI_INTENT_PVAL"; intentDescription = "P-value" ; p1 = ""; p2 = ""; p3 = ""; break; case NIFTI_INTENT_LOGPVAL: niftiIntentName = "NIFTI_INTENT_LOGPVAL"; intentDescription = "Log P-value" ; p1 = ""; p2 = ""; p3 = ""; break; case NIFTI_INTENT_LOG10PVAL: niftiIntentName = "NIFTI_INTENT_LOG10PVAL"; intentDescription = "Log10 P-value" ; p1 = ""; p2 = ""; p3 = ""; break; case NIFTI_INTENT_ESTIMATE: niftiIntentName = "NIFTI_INTENT_ESTIMATE"; intentDescription = "Estimate" ; p1 = ""; p2 = ""; p3 = ""; break; case NIFTI_INTENT_LABEL: niftiIntentName = "NIFTI_INTENT_LABEL"; intentDescription = "Label index" ; p1 = ""; p2 = ""; p3 = ""; break; case NIFTI_INTENT_NEURONAME: niftiIntentName = "NIFTI_INTENT_NEURONAME"; intentDescription = "NeuroNames index" ; p1 = ""; p2 = ""; p3 = ""; break; case NIFTI_INTENT_GENMATRIX: niftiIntentName = "NIFTI_INTENT_GENMATRIX"; intentDescription = "General matrix" ; p1 = ""; p2 = ""; p3 = ""; break; case NIFTI_INTENT_SYMMATRIX: niftiIntentName = "NIFTI_INTENT_SYMMATRIX"; intentDescription = "Symmetric matrix" ; p1 = ""; p2 = ""; p3 = ""; break; case NIFTI_INTENT_DISPVECT: niftiIntentName = "NIFTI_INTENT_DISPVECT"; intentDescription = "Displacement vector" ; p1 = ""; p2 = ""; p3 = ""; break; case NIFTI_INTENT_VECTOR: niftiIntentName = "NIFTI_INTENT_VECTOR"; intentDescription = "Vector" ; p1 = ""; p2 = ""; p3 = ""; break; case NIFTI_INTENT_POINTSET: niftiIntentName = "NIFTI_INTENT_POINTSET"; intentDescription = "Pointset" ; p1 = ""; p2 = ""; p3 = ""; break; case NIFTI_INTENT_TRIANGLE: niftiIntentName = "NIFTI_INTENT_TRIANGLE"; intentDescription = "Triangle" ; p1 = ""; p2 = ""; p3 = ""; break; case NIFTI_INTENT_QUATERNION: niftiIntentName = "NIFTI_INTENT_QUATERNION"; intentDescription = "Quaternion" ; p1 = ""; p2 = ""; p3 = ""; break; case NIFTI_INTENT_DIMLESS: niftiIntentName = "NIFTI_INTENT_DIMLESS"; intentDescription = "Dimensionless number" ; p1 = ""; p2 = ""; p3 = ""; break; } QString s; if (intentDescription.isEmpty() == false) { s += intentDescription; if (p1.isEmpty() == false) { s += (" " + p1 + "=" + QString::number(this->niftiHeaderStruct.intent_p1, 'f', 2)); } if (p2.isEmpty() == false) { s += (" " + p2 + "=" + QString::number(this->niftiHeaderStruct.intent_p2, 'f', 2)); } if (p3.isEmpty() == false) { s += (" " + p3 + "=" + QString::number(this->niftiHeaderStruct.intent_p3, 'f', 2)); } } niftiIntentCodeAndParam = s; } /** * Convert quaternions to a transformation matrix. */ TransformationMatrix NiftiFileHeader::nifti_quatern_to_mat44( float qb, float qc, float qd, float qx, float qy, float qz, float dx, float dy, float dz, float qfac ) { float m[4][4] ; double a,b=qb,c=qc,d=qd , xd,yd,zd ; /* last row is always [ 0 0 0 1 ] */ m[3][0]=m[3][1]=m[3][2] = 0.0 ; m[3][3]= 1.0 ; /* compute a parameter from b,c,d */ a = 1.0l - (b*b + c*c + d*d) ; if( a < 1.e-7l ){ /* special case */ a = 1.0l / std::sqrt(b*b+c*c+d*d) ; b *= a ; c *= a ; d *= a ; /* normalize (b,c,d) vector */ a = 0.0l ; /* a = 0 ==> 180 degree rotation */ } else{ a = std::sqrt(a) ; /* angle = 2*arccos(a) */ } /* load rotation matrix, including scaling factors for voxel sizes */ xd = (dx > 0.0) ? dx : 1.0l ; /* make sure are positive */ yd = (dy > 0.0) ? dy : 1.0l ; zd = (dz > 0.0) ? dz : 1.0l ; if( qfac < 0.0 ) zd = -zd ; /* left handedness? */ m[0][0] = (a*a+b*b-c*c-d*d) * xd ; m[0][1] = 2.0l * (b*c-a*d ) * yd ; m[0][2] = 2.0l * (b*d+a*c ) * zd ; m[1][0] = 2.0l * (b*c+a*d ) * xd ; m[1][1] = (a*a+c*c-b*b-d*d) * yd ; m[1][2] = 2.0l * (c*d-a*b ) * zd ; m[2][0] = 2.0l * (b*d-a*c ) * xd ; m[2][1] = 2.0l * (c*d+a*b ) * yd ; m[2][2] = (a*a+d*d-c*c-b*b) * zd ; /* load offsets */ m[0][3] = qx ; m[1][3] = qy ; m[2][3] = qz ; TransformationMatrix tm; tm.setMatrix(m); return tm; } /*----------------------------------------------------------------------*/ /*! compute the determinant of a 3x3 matrix *//*--------------------------------------------------------------------*/ float NiftiFileHeader::nifti_mat33_determ( mat33 R ) /* determinant of 3x3 matrix */ { double r11,r12,r13,r21,r22,r23,r31,r32,r33 ; /* INPUT MATRIX: */ r11 = R.m[0][0]; r12 = R.m[0][1]; r13 = R.m[0][2]; /* [ r11 r12 r13 ] */ r21 = R.m[1][0]; r22 = R.m[1][1]; r23 = R.m[1][2]; /* [ r21 r22 r23 ] */ r31 = R.m[2][0]; r32 = R.m[2][1]; r33 = R.m[2][2]; /* [ r31 r32 r33 ] */ return r11*r22*r33-r11*r32*r23-r21*r12*r33 +r21*r32*r13+r31*r12*r23-r31*r22*r13 ; } /*----------------------------------------------------------------------*/ /*! multiply 2 3x3 matrices *//*--------------------------------------------------------------------*/ NiftiFileHeader::mat33 NiftiFileHeader::nifti_mat33_mul( mat33 A , mat33 B ) /* multiply 2 3x3 matrices */ { mat33 C ; int i,j ; for( i=0 ; i < 3 ; i++ ) for( j=0 ; j < 3 ; j++ ) C.m[i][j] = A.m[i][0] * B.m[0][j] + A.m[i][1] * B.m[1][j] + A.m[i][2] * B.m[2][j] ; return C ; } /** * analyze HDR file is actually a NIFTI HDR file. */ bool NiftiFileHeader::hdrIsNiftiFile(const QString& hdrFileName) { QFile file(hdrFileName); if (file.open(QIODevice::ReadOnly)) { // // read bytes 348 // const int numBytesToRead = 348; char bytes[numBytesToRead]; QDataStream stream(&file); stream.setVersion(QDataStream::Qt_4_3); const bool errorFlag = (stream.readRawData(bytes, numBytesToRead) != numBytesToRead); file.close(); if (errorFlag) { return false; } // // Is this the NIFTI code "ni1"? // if ((bytes[344] == 'n') && (bytes[345] == 'i') && (bytes[346] == '1')) { return true; } } return false; } caret-5.6.4~dfsg.1.orig/caret_files/NiftiCaretExtension.h0000664000175000017500000000337611572067322023150 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __NIFTI_CARET_EXTENSION_H__ #define __NIFTI_CARET_EXTENSION_H__ #include #include class ColorFile; class FileException; class VolumeFile; /** * Contains caret data for placement in a NIFTI extension. */ class NiftiCaretExtension { public: /** * Constructor. */ NiftiCaretExtension(std::vector& volumes, const ColorFile* labelColorsIn); /** * Get the extension in a string for writing. */ QString getExtensionAsString(); /** * Apply the extension to the volumes. */ void readAndApplyExtensionToVolumes(QString& extensionXML, QString& fileCommentOut) throw (FileException); private: std::vector volumes; const ColorFile* labelColors; }; #endif /* __NIFTI_CARET_EXTENSION_H__ */ caret-5.6.4~dfsg.1.orig/caret_files/NiftiCaretExtension.cxx0000664000175000017500000002702511572067322023520 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include "AbstractFile.h" #include "ColorFile.h" #include "DebugControl.h" #include "GiftiLabelTable.h" #include "NiftiCaretExtension.h" #include "XmlGenericWriter.h" #include "XmlGenericWriterAttributes.h" #include "VolumeFile.h" static const QString TAG_CARET_EXTENSION = "CaretExtension"; static const QString TAG_COMMENT = "Comment"; static const QString TAG_DATE = "Date"; static const QString TAG_GUI_LABEL = "GuiLabel"; static const QString TAG_INDEX = "Index"; static const QString TAG_VOLUME_INFORMATION = "VolumeInformation"; static const QString TAG_VOLUME_TYPE = "VolumeType"; /** * Constructor. */ NiftiCaretExtension::NiftiCaretExtension(std::vector& volumesIn, const ColorFile* labelColorsIn) : volumes(volumesIn), labelColors(labelColorsIn) { } /** * Apply the extension to the volumes. */ void NiftiCaretExtension::readAndApplyExtensionToVolumes(QString& extensionXML, QString& fileCommentOut) throw (FileException) { int numVolumes = static_cast(this->volumes.size()); // // Place the CARET extension into a DOM XML Parser // QDomDocument doc("nifti_caret_extension"); QString errorMessage; int errorLine, errorColumn; if (doc.setContent(extensionXML, &errorMessage, &errorLine, &errorColumn) == false) { QString msg("Error parsing Caret extension at line "); msg += QString::number(errorLine); msg += ", column "; msg += QString::number(errorColumn); throw FileException(msg); } // // Get the root element // QDomElement rootElement = doc.documentElement(); if (rootElement.isNull()) { throw FileException("Caret extension root element is NULL"); } if (DebugControl::getDebugOn()) { std::cout << "Caret extension root element: " << rootElement.tagName().toAscii().constData() << std::endl; } if (rootElement.tagName() != TAG_CARET_EXTENSION) { throw FileException("Caret extension root element is not " + TAG_CARET_EXTENSION); } // // Loop through the children of the root element // QDomNode node = rootElement.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); QString nodeName = elem.tagName(); if (DebugControl::getDebugOn()) { std::cout << "CARET extension element: " << nodeName.toAscii().constData() << std::endl; } if (nodeName == TAG_COMMENT) { fileCommentOut = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (nodeName == TAG_DATE) { } else if (nodeName == TAG_VOLUME_INFORMATION) { QString indexString = elem.attribute("Index"); if (indexString.length() > 0) { int indx = indexString.toInt(NULL); //std::cout << "Index=" << indx << std::endl; if ((indx >= 0) && (indx < numVolumes)) { VolumeFile* vf = this->volumes[indx]; QDomNode volInfoChild = node.firstChild(); while (volInfoChild.isNull() == false) { QDomElement volInfoChildElement = volInfoChild.toElement(); QString volInfoChildName = volInfoChildElement.tagName(); //std::cout << "Child of " // << TAG_VOLUME_INFORMATION.toAscii().constData() // << " is " // << volInfoChildName.toAscii().constData() // << std::endl; if (volInfoChildName == TAG_COMMENT) { vf->setFileComment(AbstractFile::getXmlElementFirstChildAsString(volInfoChildElement)); } else if (volInfoChildName == TAG_GUI_LABEL) { vf->setDescriptiveLabel(AbstractFile::getXmlElementFirstChildAsString(volInfoChildElement)); } else if (volInfoChildName == "LabelTable") { QDomNode labelChild = volInfoChild.firstChild(); while (labelChild.isNull() == false) { QDomElement labelElement = labelChild.toElement(); QString labelIndexString = labelElement.attribute("Index"); QString labelName = AbstractFile::getXmlElementFirstChildAsString(labelElement); if (labelIndexString.isEmpty() == false) { int labelIndex = labelIndexString.toInt(NULL); //std::cout << "Label " // << labelIndex // << ": " // << labelName.toAscii().constData() // << std::endl; int numRegionNames = vf->getNumberOfRegionNames(); while (numRegionNames < labelIndex) { vf->addRegionName(""); } vf->addRegionName(labelName); } labelChild = labelChild.nextSibling(); } } else if (volInfoChildName == "StudyMetaDataLinkSet") { StudyMetaDataLinkSet smdls; smdls.readXML(volInfoChild); vf->setStudyMetaDataLinkSet(smdls); } else if (volInfoChildName == TAG_VOLUME_TYPE) { QString typeName = AbstractFile::getXmlElementFirstChildAsString(volInfoChildElement); if (typeName == "Anatomy") { vf->setVolumeType(VolumeFile::VOLUME_TYPE_ANATOMY); } else if (typeName == "Functional") { vf->setVolumeType(VolumeFile::VOLUME_TYPE_FUNCTIONAL); } else if (typeName == "Label") { vf->setVolumeType(VolumeFile::VOLUME_TYPE_PAINT); } else if (typeName == "Paint") { vf->setVolumeType(VolumeFile::VOLUME_TYPE_PAINT); } else if (typeName == "Probabilistic Atlas") { vf->setVolumeType(VolumeFile::VOLUME_TYPE_PROB_ATLAS); } else if (typeName == "RGB") { vf->setVolumeType(VolumeFile::VOLUME_TYPE_RGB); } else if (typeName == "ROI") { vf->setVolumeType(VolumeFile::VOLUME_TYPE_ROI); } else if (typeName == "Segmentation") { vf->setVolumeType(VolumeFile::VOLUME_TYPE_SEGMENTATION); } else if (typeName == "Vector") { vf->setVolumeType(VolumeFile::VOLUME_TYPE_VECTOR); } else { std::cout << "Unrecognized volume type " << typeName.toAscii().constData() << " in Caret Extension" << std::endl; } } volInfoChild = volInfoChild.nextSibling(); } } //else { // throw FileException("Invalid volume index=" // + QString::number(indx) // + " in Caret Extension."); //} } else throw FileException("Missing attribute Index in node" + TAG_VOLUME_INFORMATION); } else { std::cout << "Unrecognized child of " << TAG_CARET_EXTENSION.toAscii().constData() << " is " << nodeName.toAscii().constData() << std::endl; } // // Move to next node // node = node.nextSibling(); } } /** * Get the extension in a string. */ QString NiftiCaretExtension::getExtensionAsString() { int numVolumes = this->volumes.size(); // // Is this a paint or prob atlas volume // QString labelTableString; if (numVolumes > 0) { VolumeFile* firstVolume = this->volumes[0]; if ((firstVolume->getVolumeType() == VolumeFile::VOLUME_TYPE_PAINT) || (firstVolume->getVolumeType() == VolumeFile::VOLUME_TYPE_PROB_ATLAS)) { std::vector regNames; for (int i = 0; i < firstVolume->getNumberOfRegionNames(); i++) { // // Cannot have '~' character in the name // QString name(firstVolume->getRegionNameFromIndex(i)); name = name.replace(QChar('~'), QChar('_')); regNames.push_back(name); } // // Label table // GiftiLabelTable labelTable; int numNames = static_cast(regNames.size()); for (int i = 0; i < numNames; i++) { QString name = regNames[i]; labelTable.addLabel(name); } if (labelColors != NULL) { labelTable.assignColors(*labelColors); } QTextStream labelStream(&labelTableString, QIODevice::WriteOnly); labelTable.writeAsXML(labelStream, 0); } } QString dataString; QTextStream xmlDataStream(&dataString, QIODevice::WriteOnly); XmlGenericWriter xmlWriter(xmlDataStream); xmlWriter.writeStartDocument(); xmlWriter.writeStartElement(TAG_CARET_EXTENSION); xmlWriter.writeElementCData(TAG_DATE, QDateTime::currentDateTime().toString(Qt::ISODate)); for (int i = 0; i < numVolumes; i++) { const VolumeFile* volume = volumes[i]; XmlGenericWriterAttributes volumeAttributes; volumeAttributes.addAttribute(TAG_INDEX, i); xmlWriter.writeStartElement(TAG_VOLUME_INFORMATION, volumeAttributes); xmlWriter.writeElementCData(TAG_COMMENT, volume->getFileComment()); xmlWriter.writeElementCData(TAG_GUI_LABEL, volume->getDescriptiveLabel()); xmlWriter.writeCharacters(labelTableString); volume->getStudyMetaDataLinkSet().writeXML(xmlWriter); QString volumeTypeName = volume->getVolumeTypeDescription(); if (volumeTypeName == "Paint") { volumeTypeName = "Label"; } xmlWriter.writeElementCData(TAG_VOLUME_TYPE, volumeTypeName); xmlWriter.writeEndElement(); } xmlWriter.writeEndElement(); xmlWriter.writeEndDocument(); return dataString; } caret-5.6.4~dfsg.1.orig/caret_files/NeurolucidaFile.h0000664000175000017500000000766111572067322022276 0ustar michaelmichael #ifndef __NEUROLUCIDA_FILE_H__ #define __NEUROLUCIDA_FILE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "AbstractFile.h" #include "CellFile.h" #include "ColorFile.h" #include "ContourFile.h" class QDomNode; // class for a Neurolucida File class NeurolucidaFile : public AbstractFile { public: // constructor NeurolucidaFile(); // destructor ~NeurolucidaFile(); // clear the file void clear(); // returns true if the file is isEmpty (contains no data) bool empty() const; // get the number of contours int getNumberOfContours() const { return contours.size(); } // get a contour CaretContour* getContour(const int indx); // get a contour const CaretContour* getContour(const int indx) const; // get the number of markers int getNumberOfMarkers() const { return markers.size(); } // get a marker CellData* getMarker(const int indx); // get a marker const CellData* getMarker(const int indx) const; /// get the number of marker colors int getNumberOfMarkerColors() const { return markerColors.size(); } // get a marker color ColorFile::ColorStorage* getMarkerColor(const int indx); // get a marker color const ColorFile::ColorStorage* getMarkerColor(const int indx) const; protected: // read the file void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& rootElement) throw (FileException); // write the file void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& xmlDoc, QDomElement& rootElement) throw (FileException); // parse the xml void parseXML(QDomNode node) throw (FileException); // process a contour node void processContourNode(QDomNode node) throw (FileException); // process the point void processPointNode(QDomNode node, float& xOut, float& yOut, float& zOut, float& diameterOut, QString& sidOut, bool& pointValidOut) throw (FileException); // process the marker node void processMarkerNode(QDomNode node) throw (FileException); // process the children //void processChildren(QDomNode node) throw (FileException); /// the contours std::vector contours; /// the markers std::vector markers; /// the marker colors std::vector markerColors; /// convert microns to millimeters static float micronsToMillimeters; }; #endif // __NEUROLUCIDA_FILE_H__ #ifdef __NEUROLUCIDA_MAIN__ float NeurolucidaFile::micronsToMillimeters = 0.001; #endif // __NEUROLUCIDA_MAIN__ caret-5.6.4~dfsg.1.orig/caret_files/NeurolucidaFile.cxx0000664000175000017500000003125511572067322022645 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include "DebugControl.h" #include "HtmlColors.h" #define __NEUROLUCIDA_MAIN__ #include "NeurolucidaFile.h" #undef __NEUROLUCIDA_MAIN__ #include "SpecFile.h" /** * constructor. */ NeurolucidaFile::NeurolucidaFile() : AbstractFile("Neurolucida File", SpecFile::getNeurolucidaFileExtension(), false, FILE_FORMAT_XML, // default format FILE_IO_NONE, // read/write ascii FILE_IO_NONE, // read/write binary FILE_IO_READ_ONLY, // read/write xml FILE_IO_NONE, // read/write xml base64 FILE_IO_NONE, // read/write xml gzip FILE_IO_NONE, // read/write other FILE_IO_NONE) // read/write csv { clear(); } /** * destructor. */ NeurolucidaFile::~NeurolucidaFile() { clear(); } /** * clear the file. */ void NeurolucidaFile::clear() { AbstractFile::clearAbstractFile(); setRootXmlElementTagName("mbf"); contours.clear(); markers.clear(); markerColors.clear(); } /** * get a contour. */ CaretContour* NeurolucidaFile::getContour(const int indx) { if ((indx >= 0) && (indx < getNumberOfContours())) { return &contours[indx]; } return NULL; } /** * get a contour. */ const CaretContour* NeurolucidaFile::getContour(const int indx) const { if ((indx >= 0) && (indx < getNumberOfContours())) { return &contours[indx]; } return NULL; } /** * get a marker. */ CellData* NeurolucidaFile::getMarker(const int indx) { if ((indx >= 0) && (indx < getNumberOfMarkers())) { return &markers[indx]; } return NULL; } /** * get a marker. */ const CellData* NeurolucidaFile::getMarker(const int indx) const { if ((indx >= 0) && (indx < getNumberOfMarkers())) { return &markers[indx]; } return NULL; } /** * parse the xml. */ void NeurolucidaFile::parseXML(QDomNode node) throw (FileException) { if (node.hasChildNodes() == false) { const QString msg = "ERROR retrienving data (root element has no children for NeurolucidaFile).\n"; throw FileException(msg); } if (DebugControl::getDebugOn()) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { std::cout << "Root element for NeurolucidaFile is: " << elem.tagName().toAscii().constData() << std::endl; } } // // Loop through children // node = node.firstChild(); while (node.isNull() == false) { // // Convert to element // QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (DebugControl::getDebugOn()) { std::cout << "Element is: " << elem.tagName().toAscii().constData() << std::endl; } if (elem.tagName() == "contour") { processContourNode(node); } else if (elem.tagName() == "marker") { processMarkerNode(node); } } // // next sibling // node = node.nextSibling(); } if (DebugControl::getDebugOn()) { std::cout << "Number of contours in Neurolucida File: " << getNumberOfContours() << std::endl; } } /** * process a contour node. */ void NeurolucidaFile::processContourNode(QDomNode contourNode) throw (FileException) { // // Create a contour // CaretContour contour; bool sectionHasBeenSet = false; int sectionNumber = 0; // // Loop through children // QDomNode node = contourNode.firstChild(); while (node.isNull() == false) { // // Convert to element // QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (DebugControl::getDebugOn()) { std::cout << "contour child is: " << elem.tagName().toAscii().constData() << std::endl; } if (elem.tagName() == "point") { float x, y, z, diameter; QString sid; bool valid; processPointNode(node, x, y, z, diameter, sid, valid); if (valid) { contour.addPoint(x, y, z); if (sectionHasBeenSet == false) { if (sid.isEmpty() == false) { if (sid.startsWith("S")) { const QString sectionString(sid.mid(1)); bool ok = false; const int num = sectionString.toInt(&ok); if (ok) { sectionNumber = num; sectionHasBeenSet = true; } } } else { sectionNumber = static_cast(z); sectionHasBeenSet = true; } } } } } // // next sibling // node = node.nextSibling(); } contour.setSectionNumber(sectionNumber); if (contour.getNumberOfPoints() > 0) { contours.push_back(contour); } } /** * process the point node. */ void NeurolucidaFile::processPointNode(QDomNode node, float& xOut, float& yOut, float& zOut, float& diameterOut, QString& sidOut, bool& pointValidOut) throw (FileException) { pointValidOut = false; sidOut = ""; QDomElement elem = node.toElement(); if (elem.isNull() == false) { const QString xAttr = elem.attribute("x"); const QString yAttr = elem.attribute("y"); const QString zAttr = elem.attribute("z"); if ((xAttr.isEmpty() == false) && (yAttr.isEmpty() == false) && (zAttr.isEmpty() == false)) { xOut = xAttr.toFloat() * micronsToMillimeters; yOut = yAttr.toFloat() * micronsToMillimeters; zOut = zAttr.toFloat() * micronsToMillimeters; pointValidOut = true; const QString diameterAttr = elem.attribute("d"); diameterOut = 1.0; if (diameterAttr.isEmpty() == false) { diameterOut = diameterAttr.toFloat(); } sidOut = elem.attribute("sid", ""); } } } /** * process the marker node. */ void NeurolucidaFile::processMarkerNode(QDomNode markerNode) throw (FileException) { QString name; QString colorString; // // Process the childrent // QDomElement markerElement = markerNode.toElement(); if (markerElement.isNull() == false) { name = markerElement.attribute("name"); colorString = markerElement.attribute("color"); } if (name.isEmpty()) { return; } // // Create the marker color // if (colorString.isEmpty() == false) { unsigned char red = 127, green = 127, blue = 127, alpha = 255; const float pointSize = 1.0; const float lineSize = 1.0; const ColorFile::ColorStorage::SYMBOL symbol = ColorFile::ColorStorage::SYMBOL_OPENGL_POINT; if (colorString[0] == '#') { if (colorString.size() >= 7) { bool ok = false; red = static_cast(colorString.mid(1, 2).toInt(&ok, 16)); green = static_cast(colorString.mid(3, 2).toInt(&ok, 16)); blue = static_cast(colorString.mid(5, 2).toInt(&ok, 16)); } } else { const bool valid = HtmlColors::getRgbFromColorName(colorString, red, green, blue); if (valid == false) { std::cout << "WARNING: Neurolucida file import - no matching color for " << colorString.toAscii().constData() << std::endl; } } // // Create a new color with the marker name and specified color // ColorFile::ColorStorage cs(name, red, green, blue, alpha, pointSize, lineSize, symbol); markerColors.push_back(cs); } // // Loop through children // QDomNode node = markerNode.firstChild(); while (node.isNull() == false) { // // Convert to element // QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (DebugControl::getDebugOn()) { std::cout << "marker child is: " << elem.tagName().toAscii().constData() << std::endl; } if (elem.tagName() == "point") { float x, y, z, diameter; QString sid; bool valid; processPointNode(node, x, y, z, diameter, sid, valid); if (valid) { CellData cd(name, x, y, z); markers.push_back(cd); } } } // // next sibling // node = node.nextSibling(); } } /** * get a marker color. */ ColorFile::ColorStorage* NeurolucidaFile::getMarkerColor(const int indx) { if ((indx >= 0) && (indx < getNumberOfMarkers())) { return &markerColors[indx]; } return NULL; } /** * get a marker color. */ const ColorFile::ColorStorage* NeurolucidaFile::getMarkerColor(const int indx) const { if ((indx >= 0) && (indx < getNumberOfMarkers())) { return &markerColors[indx]; } return NULL; } /** * returns true if the file is isEmpty (contains no data). */ bool NeurolucidaFile::empty() const { const bool isEmpty = ((getNumberOfContours() == 0) && (getNumberOfMarkers() == 0) && (getNumberOfMarkerColors() == 0)); return isEmpty; } /** * read the file. */ void NeurolucidaFile::readFileData(QFile& /* file */, QTextStream& /* stream */, QDataStream& /* binStream */, QDomElement& rootElement) throw (FileException) { switch (getFileReadType()) { case FILE_FORMAT_ASCII: throw FileException("Reading of Ascii format Neurolucida files not supported.."); break; case FILE_FORMAT_BINARY: throw FileException("Reading of Binary format Neurolucida files not supported.."); break; case FILE_FORMAT_XML: { QDomNode node = rootElement.firstChild(); if (node.isNull() == false) { parseXML(rootElement); } } break; case FILE_FORMAT_XML_BASE64: throw FileException("Reading of XML Base64 format Neurolucida files not supported.."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException("Reading of XMK GZip Base64 format Neurolucida files not supported.."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException("\"XML-External Binary Encoding\" file format not supported."); break; case FILE_FORMAT_OTHER: throw FileException("Reading of other format Neurolucida files not supported.."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException("Reading of Comma Separated Value File format Neurolucida files not supported.."); break; } } /** * write the file. */ void NeurolucidaFile::writeFileData(QTextStream& /* stream */, QDataStream& /* binStream */, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException) { throw FileException("Writing of Neurolucida not supported."); } caret-5.6.4~dfsg.1.orig/caret_files/MultiResMorphFile.h0000664000175000017500000003416311572067322022573 0ustar michaelmichael #ifndef __MULTI_RES_MORPH_FILE_H__ #define __MULTI_RES_MORPH_FILE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "AbstractFile.h" /** * Multi-Resolution Morphing cycle. */ class MultiResolutionMorphingCycle { public: enum { MAXIMUM_NUMBER_OF_LEVELS = 7 }; /** * Constructor. */ MultiResolutionMorphingCycle() { this->smoothingStrength = 1.0; this->smoothingIterations = 10; this->smoothingIterationsEdges = 10; this->linearForce = 0.5; this->angularForce = 0.3; this->stepSize = 0.5; } /** * Destructor. */ virtual ~MultiResolutionMorphingCycle() { } /** * Get the number of iterations at a level. * @param level Level for which an iteration is sought. * (0 == Fine, 2, 3, ..., N-1 == Course). * @return Number of iterations at the level. */ int getIteration(const int level) { return this->iterations[level]; } /** * Set the number of iterations at a level. * @param level The level (0 == Fine, 2, 3, ..., N-1 == Course) * @param iterations Number of iterations for level. */ void setIteration(const int level, int iterations) { this->iterations[level] = iterations; } /** * Get all iterations for the levels. * @param iterationsOut Output array into which iterations are loaded. */ void getIterationsAll(int iterationsOut[]) const { for (int i = 0; i < MAXIMUM_NUMBER_OF_LEVELS; i++) { iterationsOut[i] = this->iterations[i]; } } /** * Set all iterations at all levels. * @param iterationsIn Output array from which iterations are obtained. */ void setIterationsAll(const int iterationsIn[]) { for (int i = 0; i < MAXIMUM_NUMBER_OF_LEVELS; i++) { this->iterations[i] = iterationsIn[i]; } } /** * Get the smoothing strength. * @return Strength value. */ float getSmoothingStrength() const { return this->smoothingStrength; } /** * Get the iterations. * @return Number of iterations of smoothing. */ int getSmoothingIterations() const { return this->smoothingIterations; } /** * Get the edge iterations. * @return Edge iterations. */ int getSmoothingIterationEdges() const { return this->smoothingIterationsEdges; } /** * Set the strength. * @param smoothingStrength - New strength value. */ void setSmoothingStrength(const float smoothingStrength) { this->smoothingStrength = smoothingStrength; } /** * Set the iterations. * @param smoothingIterations New iterations value. */ void setSmoothingIterations(const int smoothingIterations) { this->smoothingIterations = smoothingIterations; } /** * Set the edge iterations. * @param smoothingIterationsEdges New edge iterations value. */ void setSmoothingIterationsEdges(const int smoothingIterationsEdges) { this->smoothingIterationsEdges = smoothingIterationsEdges; } /** * Get the linear force. * @return Linear force value. */ float getLinearForce() const { return this->linearForce; } /** * Set the linear force. * @param linearForce new linear force value. */ void setLinearForce(float linearForce) { this->linearForce = linearForce; } /** * Get the angular force. * @return Angular force value. */ float getAngularForce() const { return this->angularForce; } /** * Set the angular force. * @param angularForce new angular force value. */ void setAngularForce(float angularForce) { this->angularForce = angularForce; } /** * Get the step size. * @return step size value. */ float getStepSize() const { return this->stepSize; } /** * Set the step size. * @param stepSize new step size value. */ void setStepSize(float stepSize) { this->stepSize = stepSize; } /** * Read from XML. */ void readXML(QDomNode& nodeIn) throw (FileException); /** * Write as XML. */ void writeXML(QDomDocument& xmlDoc, QDomElement& parentElement, const int cycleIndex); static const QString XML_TAG_MORPH_CYCLE; private: int iterations[MAXIMUM_NUMBER_OF_LEVELS]; float smoothingStrength; int smoothingIterations; int smoothingIterationsEdges; float linearForce; float angularForce; float stepSize; static const QString XML_TAG_ITERATIONS; static const QString XML_TAG_LINEAR_FORCE; static const QString XML_TAG_ANGULAR_FORCE; static const QString XML_TAG_STEP_SIZE; static const QString XML_TAG_SMOOTHING_STRENGTH; static const QString XML_TAG_SMOOTHING_ITERATIONS; static const QString XML_TAG_SMOOTHING_ITERATIONS_EDGES; }; #ifdef __MULTI_RES_MORPH_FILE_MAIN__ const QString MultiResolutionMorphingCycle::XML_TAG_ITERATIONS = "iterations"; const QString MultiResolutionMorphingCycle::XML_TAG_LINEAR_FORCE = "linearForce"; const QString MultiResolutionMorphingCycle::XML_TAG_ANGULAR_FORCE = "angularForce"; const QString MultiResolutionMorphingCycle::XML_TAG_STEP_SIZE = "stepSize"; const QString MultiResolutionMorphingCycle::XML_TAG_SMOOTHING_STRENGTH = "smoothingStrength"; const QString MultiResolutionMorphingCycle::XML_TAG_SMOOTHING_ITERATIONS = "smoothingIterations"; const QString MultiResolutionMorphingCycle::XML_TAG_SMOOTHING_ITERATIONS_EDGES = "smoothingIterationsEdges"; const QString MultiResolutionMorphingCycle::XML_TAG_MORPH_CYCLE = "cycle"; #endif // __MULTI_RES_MORPH_FILE_MAIN__ class MultiResMorphFile : public AbstractFile { public: enum { MAXIMUM_NUMBER_OF_CYCLES = 10 }; // constructor MultiResMorphFile(); // constructor ~MultiResMorphFile() { } /** * Get the number of cycles. * @return The number of cycles. */ int getNumberOfCycles() const { return this->numberOfCycles; } /** * Set the number of cycles. * @param numberOfCycles New number of cycles. */ void setNumberOfCycles(const int numberOfCycles) { this->numberOfCycles = numberOfCycles; this->numberOfCycles = std::min(this->numberOfCycles, static_cast(MAXIMUM_NUMBER_OF_CYCLES)); this->numberOfCycles = std::max(this->numberOfCycles, 1); } /** * Get the number of levels. * @return The number of levels. */ int getNumberOfLevels() const { return this->numberOfLevels; } /** * Set the number of levels. * @param numberOfLevels New number of levels. */ void setNumberOfLevels(const int numberOfLevels) { this->numberOfLevels = numberOfLevels; this->numberOfLevels = std::min(this->numberOfLevels, static_cast(MultiResolutionMorphingCycle::MAXIMUM_NUMBER_OF_LEVELS)); this->numberOfLevels = std::max(this->numberOfLevels, 1); } /** * Get pointer to cycle for updating. */ MultiResolutionMorphingCycle* getCycle(int cycleIndex) { return &this->cycles[cycleIndex]; } /** * Get pointer to cycle for reading. */ const MultiResolutionMorphingCycle* getCycle(int cycleIndex) const { return &this->cycles[cycleIndex]; } /** * Should temporary files be deleted. * @return true if temporary files should be deleted, else false. */ bool isDeleteTemporaryFiles() const { return this->deleteTemporaryFilesFlag; } /** * Set temporary files. * @param deleteTemporaryFilesFlag true to delete files, else false. */ void setDeleteTemporaryFiles(const bool deleteTemporaryFilesFlag) { this->deleteTemporaryFilesFlag = deleteTemporaryFilesFlag; } /** * Should crossovers be smoothed to eliminate them. * @return true if crossovers should be smoothed, else false. */ bool isSmoothOutCrossovers() const { return this->smoothOutCrossoversFlag; } /** * Set crossovers should be smoothed to eliminate them on surface. * @param smoothOutCrossovers true to smooth, else false. */ void setSmoothOutCrossovers(const bool smoothOutCrossoversFlag) { this->smoothOutCrossoversFlag = smoothOutCrossoversFlag; } /** * Should flat surface overlap be smoothed to eliminate it. * @return true if surface overlap should be smoothed, else false. */ bool isSmoothOutFlatSurfaceOverlap() const { return this->smoothOutFlatSurfaceOverlapFlag; } /** * Set surface overlap should be smoothed to eliminate it. * @param smoothOutSurfaceOverlapFlag true to smooth, else false. */ void setSmoothOutFlatSurfaceOverlap(const bool smoothOutFlatSurfaceOverlapFlag) { this->smoothOutFlatSurfaceOverlapFlag = smoothOutFlatSurfaceOverlapFlag; } /** * Should the surface be aligned using the Central Sulcus Landmark? * @return true if align, else false. */ bool isAlignToCentralSulcalsLandmark() const { return this->alignToCentralSulcusLandmarkFlag; } /** * Set the surface be aligned using the Central Sulcus Landmark. * @@param alignToCentralSulcusLandmarkFlag True if align, else false. */ void setAlignToCentralSulcusLandmark(const bool alignToCentralSulcusLandmarkFlag) { this->alignToCentralSulcusLandmarkFlag = alignToCentralSulcusLandmarkFlag; } /** * Get the name of the Central Sulcus Landmark. * @return Name of Central Sulcus Landmark. */ QString getCentralSulcusLandmarkName() { return this->centralSulcusLandmarkName; } /** * Set the name of the Central Sulcus Landmark. * @param centralSulcusLandmarkName Name of Central Sulcus Landmark. */ void setCentralSulcusLandmarkName(const QString& centralSulcusLandmarkName) { this->centralSulcusLandmarkName = centralSulcusLandmarkName; } /** * Should spherical surface triangles be oriented so normal point out of the sphere? * @return true if so, else false. */ bool isPointSphericalTrianglesOutward() const { return this->pointSphericalTrianglesOutwardFlag; } /** * Set spherical surface triangles should be oriented so normal points out of the sphere. * @param pointSphericalTrianglesOutwardFlag true if so, else false. */ void setPointSphericalTrianglesOutward(const bool pointSphericalTrianglesOutwardFlag) { this->pointSphericalTrianglesOutwardFlag = pointSphericalTrianglesOutwardFlag; } /** * * Clears current file data in memory. Deriving classes must override this method and * call AbstractFile::clearAbstractFile() from its clear method. */ void clear(); /** * returns true if the file is isEmpty (contains no data) */ bool empty() const; /** * Initialize parameters to their default values for flat morphing. */ void initializeParametersFlat(); /** * Initialize parameters to their default values for spherical morphing. */ void initializeParametersSpherical(); /** * Read the contents of the file (header has already been read). */ void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& rootElement) throw (FileException); /** * Write the file's data (header has already been written). */ void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& xmlDoc, QDomElement& rootElement) throw (FileException); private: MultiResolutionMorphingCycle cycles[MAXIMUM_NUMBER_OF_CYCLES]; int numberOfCycles; int numberOfLevels; bool deleteTemporaryFilesFlag; bool smoothOutCrossoversFlag; bool smoothOutFlatSurfaceOverlapFlag; bool pointSphericalTrianglesOutwardFlag; bool alignToCentralSulcusLandmarkFlag; QString centralSulcusLandmarkName; static const QString XML_TAG_NUMBER_OF_CYCLES; static const QString XML_TAG_NUMBER_OF_LEVELS; static const QString XML_TAG_DELETE_TEMPORARY_FILES; static const QString XML_TAG_SMOOTH_OUT_CROSSOVERS; static const QString XML_TAG_POINT_SPHERICAL_TRIANGLES; static const QString XML_TAG_ALIGN_TO_CES; static const QString XML_TAG_CES_LANDMARK_NAME; static const QString XML_TAG_SMOOTH_OUT_FLAT_OVERLAP; }; #ifdef __MULTI_RES_MORPH_FILE_MAIN__ const QString MultiResMorphFile::XML_TAG_NUMBER_OF_CYCLES = "numberOfCycles"; const QString MultiResMorphFile::XML_TAG_NUMBER_OF_LEVELS = "numberOfLevels"; const QString MultiResMorphFile::XML_TAG_DELETE_TEMPORARY_FILES = "deleteTemporaryFilesFlag"; const QString MultiResMorphFile::XML_TAG_SMOOTH_OUT_CROSSOVERS = "smoothOutCrossoversFlag"; const QString MultiResMorphFile::XML_TAG_POINT_SPHERICAL_TRIANGLES = "pointSphericalTrianglesOutwardFlag"; const QString MultiResMorphFile::XML_TAG_ALIGN_TO_CES = "alignToCentralSulcusLandmarkFlag"; const QString MultiResMorphFile::XML_TAG_CES_LANDMARK_NAME = "centralSulcusLandmarkName"; const QString MultiResMorphFile::XML_TAG_SMOOTH_OUT_FLAT_OVERLAP = "smoothOutFlatSurfaceOverlapFlag"; #endif #endif // __MULTI_RES_MORPH_FILE_H__ caret-5.6.4~dfsg.1.orig/caret_files/MultiResMorphFile.cxx0000664000175000017500000004535111572067322023147 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #define __MULTI_RES_MORPH_FILE_MAIN__ #include "MultiResMorphFile.h" #undef __MULTI_RES_MORPH_FILE_MAIN__ #include "SpecFile.h" #include "StringUtilities.h" MultiResMorphFile::MultiResMorphFile() : AbstractFile("Multi-Resolution Morphing Parameters File", SpecFile::getMultiResMorphFileExtension(), true, AbstractFile::FILE_FORMAT_XML, AbstractFile::FILE_IO_NONE, AbstractFile::FILE_IO_NONE, AbstractFile::FILE_IO_READ_AND_WRITE, AbstractFile::FILE_IO_NONE, AbstractFile::FILE_IO_NONE, AbstractFile::FILE_IO_NONE, AbstractFile::FILE_IO_NONE) { this->initializeParametersSpherical(); } /** * * Clears current file data in memory. Deriving classes must override this method and * call AbstractFile::clearAbstractFile() from its clear method. */ void MultiResMorphFile::clear() { AbstractFile::clearAbstractFile(); } /** * returns true if the file is isEmpty (contains no data) */ bool MultiResMorphFile::empty() const { return false; } /** * Initialize parameters to their default values for spherical morphing. */ void MultiResMorphFile::initializeParametersSpherical() { this->deleteTemporaryFilesFlag = true; this->smoothOutCrossoversFlag = true;; this->smoothOutFlatSurfaceOverlapFlag = true; this->pointSphericalTrianglesOutwardFlag = false; this->alignToCentralSulcusLandmarkFlag = true; this->centralSulcusLandmarkName = "LANDMARK.CentralSulcus"; this->setNumberOfCycles(4); this->setNumberOfLevels(6); /* * Default the parameters for all cycles. */ for (int i = 0; i < MAXIMUM_NUMBER_OF_CYCLES; i++) { MultiResolutionMorphingCycle* cycle = this->getCycle(i); cycle->setIteration(0, 0); cycle->setIteration(1, 25); cycle->setIteration(2, 10); cycle->setIteration(3, 10); cycle->setIteration(4, 5); cycle->setIteration(5, 2); cycle->setIteration(6, 1); cycle->setLinearForce(0.5); cycle->setAngularForce(0.3); cycle->setStepSize(0.5); cycle->setSmoothingStrength(1.0); cycle->setSmoothingIterations(10); cycle->setSmoothingIterationsEdges(10); } /* * Cycle 4 (index 3) */ { MultiResolutionMorphingCycle* cycle = this->getCycle(3); cycle->setIteration(0, 2); cycle->setIteration(1, 5); cycle->setIteration(2, 10); cycle->setIteration(3, 20); cycle->setIteration(4, 5); cycle->setIteration(5, 0); cycle->setIteration(6, 0); } /* * Cycle 3 (index 2) */ { MultiResolutionMorphingCycle* cycle = this->getCycle(2); cycle->setIteration(0, 2); cycle->setIteration(1, 5); cycle->setIteration(2, 10); cycle->setIteration(3, 10); cycle->setIteration(4, 10); cycle->setIteration(5, 0); cycle->setIteration(6, 0); } /* * Cycle 2 (index 1) */ { MultiResolutionMorphingCycle* cycle = this->getCycle(1); cycle->setIteration(0, 2); cycle->setIteration(1, 3); cycle->setIteration(2, 15); cycle->setIteration(3, 20); cycle->setIteration(4, 15); cycle->setIteration(5, 0); cycle->setIteration(6, 0); } /* * Cycle 1 (index 0) */ { MultiResolutionMorphingCycle* cycle = this->getCycle(0); cycle->setIteration(0, 2); cycle->setIteration(1, 3); cycle->setIteration(2, 5); cycle->setIteration(3, 20); cycle->setIteration(4, 20); cycle->setIteration(5, 15); cycle->setIteration(6, 0); } } /** * Initialize parameters to their default values for flat morphing. */ void MultiResMorphFile::initializeParametersFlat() { this->deleteTemporaryFilesFlag = true; this->smoothOutCrossoversFlag = true;; this->smoothOutFlatSurfaceOverlapFlag = true; this->pointSphericalTrianglesOutwardFlag = false; this->alignToCentralSulcusLandmarkFlag = true; this->centralSulcusLandmarkName = "LANDMARK.CentralSulcus"; this->setNumberOfCycles(5); this->setNumberOfLevels(7); /* * Default the parameters for all cycles. */ for (int i = 0; i < MAXIMUM_NUMBER_OF_CYCLES; i++) { MultiResolutionMorphingCycle* cycle = this->getCycle(i); for (int i = 0; i < MultiResolutionMorphingCycle::MAXIMUM_NUMBER_OF_LEVELS; i++) { cycle->setIteration(i, 0); } cycle->setIteration(0, 0); cycle->setIteration(1, 10); cycle->setIteration(2, 20); cycle->setIteration(3, 40); cycle->setIteration(4, 60); cycle->setIteration(5, 80); cycle->setIteration(6, 100); cycle->setLinearForce(0.5); cycle->setAngularForce(0.5); cycle->setStepSize(0.5); cycle->setSmoothingStrength(1.0); cycle->setSmoothingIterations(50); cycle->setSmoothingIterationsEdges(10); } /* * Cycle 5 (index 4) */ { MultiResolutionMorphingCycle* cycle = this->getCycle(4); cycle->setIteration(0, 0); cycle->setIteration(1, 20); cycle->setIteration(2, 20); cycle->setIteration(3, 40); cycle->setIteration(4, 60); cycle->setIteration(5, 50); cycle->setIteration(6, 30); cycle->setLinearForce(0.4); } /* * Cycle 4 (index 3) */ { MultiResolutionMorphingCycle* cycle = this->getCycle(3); cycle->setIteration(0, 0); cycle->setIteration(1, 20); cycle->setIteration(2, 20); cycle->setIteration(3, 40); cycle->setIteration(4, 60); cycle->setIteration(5, 50); cycle->setIteration(6, 30); } /* * Cycle 3 (index 2) */ { MultiResolutionMorphingCycle* cycle = this->getCycle(2); cycle->setIteration(0, 0); cycle->setIteration(1, 10); cycle->setIteration(2, 20); cycle->setIteration(3, 40); cycle->setIteration(4, 60); cycle->setIteration(5, 60); cycle->setIteration(6, 50); } /* * Cycle 2 (index 1) */ { MultiResolutionMorphingCycle* cycle = this->getCycle(1); cycle->setIteration(0, 0); cycle->setIteration(1, 10); cycle->setIteration(2, 20); cycle->setIteration(3, 40); cycle->setIteration(4, 60); cycle->setIteration(5, 60); cycle->setIteration(6, 50); } /* * Cycle 1 (index 0) */ { MultiResolutionMorphingCycle* cycle = this->getCycle(0); cycle->setIteration(0, 0); cycle->setIteration(1, 10); cycle->setIteration(2, 20); cycle->setIteration(3, 40); cycle->setIteration(4, 60); cycle->setIteration(5, 70); cycle->setIteration(6, 60); } } /** * Read the contents of the file (header has already been read). */ void MultiResMorphFile::readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& rootElement) throw (FileException) { switch (getFileWriteType()) { case FILE_FORMAT_ASCII: throw FileException(filename, "Writing in Ascii format not supported."); break; case FILE_FORMAT_BINARY: throw FileException(filename, "Writing in Binary format not supported."); break; case FILE_FORMAT_XML: { int cycleCounter = 0; QDomNode node = rootElement.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { // // Is this a "cycle" element // if (elem.tagName() == MultiResMorphFile::XML_TAG_NUMBER_OF_CYCLES) { this->numberOfCycles = AbstractFile::getXmlElementFirstChildAsInt(elem); } else if (elem.tagName() == MultiResMorphFile::XML_TAG_NUMBER_OF_LEVELS) { this->numberOfLevels = AbstractFile::getXmlElementFirstChildAsInt(elem); } else if (elem.tagName() == MultiResMorphFile::XML_TAG_DELETE_TEMPORARY_FILES) { this->deleteTemporaryFilesFlag = (AbstractFile::getXmlElementFirstChildAsInt(elem) != 0); } else if (elem.tagName() == MultiResMorphFile::XML_TAG_SMOOTH_OUT_CROSSOVERS) { this->smoothOutCrossoversFlag = (AbstractFile::getXmlElementFirstChildAsInt(elem) != 0); } else if (elem.tagName() == MultiResMorphFile::XML_TAG_SMOOTH_OUT_FLAT_OVERLAP) { this->smoothOutFlatSurfaceOverlapFlag = (AbstractFile::getXmlElementFirstChildAsInt(elem) != 0); } else if (elem.tagName() == MultiResMorphFile::XML_TAG_POINT_SPHERICAL_TRIANGLES) { this->pointSphericalTrianglesOutwardFlag = (AbstractFile::getXmlElementFirstChildAsInt(elem) != 0); } else if (elem.tagName() == MultiResMorphFile::XML_TAG_ALIGN_TO_CES) { this->alignToCentralSulcusLandmarkFlag = (AbstractFile::getXmlElementFirstChildAsInt(elem) != 0); } else if (elem.tagName() == MultiResMorphFile::XML_TAG_CES_LANDMARK_NAME) { this->centralSulcusLandmarkName = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == MultiResolutionMorphingCycle::XML_TAG_MORPH_CYCLE) { MultiResolutionMorphingCycle* cycle = this->getCycle(cycleCounter); cycle->readXML(node); cycleCounter++; } else if ((elem.tagName() == xmlHeaderOldTagName) || (elem.tagName() == xmlHeaderTagName)) { // ignore, read by AbstractFile::readFile() } else { std::cout << "WARNING: unrecognized Multi-Res Morph File element: " << elem.tagName().toAscii().constData() << std::endl; } } node = node.nextSibling(); } } break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "Writing XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "Writing XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Writing XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Writing in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Writing in CSV format not supported."); break; } } /** * Write the file's data (header has already been written). */ void MultiResMorphFile::writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& xmlDoc, QDomElement& rootElement) throw (FileException) { switch (getFileWriteType()) { case FILE_FORMAT_ASCII: throw FileException(filename, "Writing in Ascii format not supported."); break; case FILE_FORMAT_BINARY: throw FileException(filename, "Writing in Binary format not supported."); break; case FILE_FORMAT_XML: { // // Write the number of cycles and other parameters // AbstractFile::addXmlTextElement(xmlDoc, rootElement, XML_TAG_NUMBER_OF_CYCLES, this->numberOfCycles); AbstractFile::addXmlTextElement(xmlDoc, rootElement, XML_TAG_NUMBER_OF_LEVELS, this->numberOfLevels); AbstractFile::addXmlTextElement(xmlDoc, rootElement, XML_TAG_DELETE_TEMPORARY_FILES, this->deleteTemporaryFilesFlag); AbstractFile::addXmlTextElement(xmlDoc, rootElement, XML_TAG_SMOOTH_OUT_CROSSOVERS, this->smoothOutCrossoversFlag); AbstractFile::addXmlTextElement(xmlDoc, rootElement, XML_TAG_SMOOTH_OUT_FLAT_OVERLAP, this->smoothOutFlatSurfaceOverlapFlag); AbstractFile::addXmlTextElement(xmlDoc, rootElement, XML_TAG_POINT_SPHERICAL_TRIANGLES, this->pointSphericalTrianglesOutwardFlag); AbstractFile::addXmlTextElement(xmlDoc, rootElement, XML_TAG_ALIGN_TO_CES, this->alignToCentralSulcusLandmarkFlag); AbstractFile::addXmlTextElement(xmlDoc, rootElement, XML_TAG_CES_LANDMARK_NAME, this->centralSulcusLandmarkName); // // Write the cycles // for (int i = 0; i < this->numberOfCycles; i++) { cycles[i].writeXML(xmlDoc, rootElement, i); } } break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "Writing XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "Writing XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Writing XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Writing in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Writing in CSV format not supported."); break; } } /** * called to read from an XML structure. */ void MultiResolutionMorphingCycle::readXML(QDomNode& nodeIn) throw (FileException) { if (nodeIn.isNull()) { return; } QDomElement elem = nodeIn.toElement(); if (elem.isNull()) { return; } if (elem.tagName() != MultiResolutionMorphingCycle::XML_TAG_MORPH_CYCLE) { QString msg("Incorrect element type passed to MultiResMorphFileCycle::readXML(): \""); msg.append(elem.tagName()); msg.append("\""); throw FileException("", msg); } QDomNode node = nodeIn.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (elem.tagName() == MultiResolutionMorphingCycle::XML_TAG_ITERATIONS) { QString iterString = AbstractFile::getXmlElementFirstChildAsString(elem); std::vector intValues; StringUtilities::token(iterString, " ", intValues); int iterMax = std::min(static_cast(MultiResolutionMorphingCycle::MAXIMUM_NUMBER_OF_LEVELS), static_cast(intValues.size())); for (int i = 0; i < iterMax; i++) { this->iterations[i] = intValues[i]; } } else if (elem.tagName() == MultiResolutionMorphingCycle::XML_TAG_ANGULAR_FORCE) { this->angularForce = AbstractFile::getXmlElementFirstChildAsFloat(elem); } else if (elem.tagName() == MultiResolutionMorphingCycle::XML_TAG_LINEAR_FORCE) { this->linearForce = AbstractFile::getXmlElementFirstChildAsFloat(elem); } else if (elem.tagName() == MultiResolutionMorphingCycle::XML_TAG_STEP_SIZE) { this->stepSize = AbstractFile::getXmlElementFirstChildAsFloat(elem); } else if (elem.tagName() == MultiResolutionMorphingCycle::XML_TAG_SMOOTHING_STRENGTH) { this->smoothingStrength = AbstractFile::getXmlElementFirstChildAsFloat(elem); } else if (elem.tagName() == MultiResolutionMorphingCycle::XML_TAG_SMOOTHING_ITERATIONS) { this->smoothingIterations = AbstractFile::getXmlElementFirstChildAsInt(elem); } else if (elem.tagName() == MultiResolutionMorphingCycle::XML_TAG_SMOOTHING_ITERATIONS_EDGES) { this->smoothingIterationsEdges = AbstractFile::getXmlElementFirstChildAsInt(elem); } else { std::cout << "WARNING: unrecognized MultiResolutionMorphingCycleQ element: " << elem.tagName().toAscii().constData() << std::endl; } } node = node.nextSibling(); } } /** * called to write to an XML structure. */ void MultiResolutionMorphingCycle::writeXML(QDomDocument& xmlDoc, QDomElement& parentElement, const int cycleIndex) { // // Create the element for this class instance's data // QDomElement cycleElement = xmlDoc.createElement(XML_TAG_MORPH_CYCLE); // // cycle data // AbstractFile::addXmlTextElement(xmlDoc, cycleElement, XML_TAG_ITERATIONS, this->iterations, MAXIMUM_NUMBER_OF_LEVELS); AbstractFile::addXmlTextElement(xmlDoc, cycleElement, XML_TAG_ANGULAR_FORCE, this->angularForce); AbstractFile::addXmlTextElement(xmlDoc, cycleElement, XML_TAG_LINEAR_FORCE, this->linearForce); AbstractFile::addXmlTextElement(xmlDoc, cycleElement, XML_TAG_STEP_SIZE, this->stepSize); AbstractFile::addXmlTextElement(xmlDoc, cycleElement, XML_TAG_SMOOTHING_STRENGTH, smoothingStrength); AbstractFile::addXmlTextElement(xmlDoc, cycleElement, XML_TAG_SMOOTHING_ITERATIONS, smoothingIterations); AbstractFile::addXmlTextElement(xmlDoc, cycleElement, XML_TAG_SMOOTHING_ITERATIONS_EDGES, smoothingIterationsEdges); // // Add class instance's data to the parent // parentElement.appendChild(cycleElement); } caret-5.6.4~dfsg.1.orig/caret_files/MniObjSurfaceFile.h0000664000175000017500000000550611572067322022507 0ustar michaelmichael #ifndef __MNI_OBJ_SURFACE_FILE_H__ #define __MNI_OBJ_SURFACE_FILE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "AbstractFile.h" /// class for reading an MNI OBJ surface file /// http://www.bic.mni.mcgill.ca/users/mishkin/mni_obj_format.pdf /// http://www.bic.mni.mcgill.ca/~david/FAQ/polygons_format.txt class MniObjSurfaceFile : public AbstractFile { public: // constructor MniObjSurfaceFile(); // destructor ~MniObjSurfaceFile(); // clear the file void clear(); // see if the file is emtpy bool empty() const; /// get the number of points int getNumberOfPoints() const { return points.size() / 3; } // get a point const float* getPointXYZ(const int indx) const; /// get the number of triangles int getNumberOfTriangles() const { return triangles.size() / 3; } // get a triangle const int* getTriangle(const int indx) const; // get a normal const float* getNormal(const int indx) const; // get rgba color const unsigned char* getColorRGBA(const int indx) const; protected: /// Read the contents of the file (header has already been read) void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& rootElement) throw (FileException); /// Write the file's data (header has already been written) void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& xmlDoc, QDomElement& rootElement) throw (FileException); /// points std::vector points; /// normals std::vector normals; /// colors std::vector colors; /// triangles std::vector triangles; }; #endif // __MNI_OBJ_SURFACE_FILE_H__ caret-5.6.4~dfsg.1.orig/caret_files/MniObjSurfaceFile.cxx0000664000175000017500000002053011572067322023054 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "MniObjSurfaceFile.h" #include "SpecFile.h" /** * constructor. */ MniObjSurfaceFile::MniObjSurfaceFile() : AbstractFile("MNI OBJ Surface File", SpecFile::getMniObjeSurfaceFileExtension(), false, // no header FILE_FORMAT_OTHER, // default format FILE_IO_NONE, // supports ascii FILE_IO_NONE, // supports binary FILE_IO_NONE, // supports xml FILE_IO_NONE, // supports xml base64 FILE_IO_NONE, // supports xml gzip base64 FILE_IO_READ_ONLY, // supports other FILE_IO_NONE) // supports csv { } /** * destructor. */ MniObjSurfaceFile::~MniObjSurfaceFile() { } /** * clear the file. */ void MniObjSurfaceFile::clear() { points.clear(); normals.clear(); colors.clear(); triangles.clear(); } /** * see if the file is empty. */ bool MniObjSurfaceFile::empty() const { return (points.empty() && normals.empty() && colors.empty() && triangles.empty()); } /** * get a point. */ const float* MniObjSurfaceFile::getPointXYZ(const int indx) const { return &points[indx*3]; } /** * get a triangle. */ const int* MniObjSurfaceFile::getTriangle(const int indx) const { return &triangles[indx*3]; } /** * get a normal. */ const float* MniObjSurfaceFile::getNormal(const int indx) const { return &normals[indx*3]; } /** * get rgba color. */ const unsigned char* MniObjSurfaceFile::getColorRGBA(const int indx) const { return &colors[indx*4]; } /** * Read the contents of the file (header has already been read). */ void MniObjSurfaceFile::readFileData(QFile& /*file*/, QTextStream& stream, QDataStream& /*binStream*/, QDomElement& /*rootElement*/) throw (FileException) { /// http://www.bic.mni.mcgill.ca/users/mishkin/mni_obj_format.pdf /// http://www.bic.mni.mcgill.ca/~david/FAQ/polygons_format.txt // // Check object class // QString objectClass; stream >> objectClass; if (objectClass != "P") { throw FileException("MNI OBJ file does not contains polygons (1st char == 'P')"); } // // Ignore these lighting items // float ambientCoefficient, diffusionCoefficient, specularCoefficient, specularExponent, opacity; stream >> ambientCoefficient >> diffusionCoefficient >> specularCoefficient >> specularExponent >> opacity; // // number of points // int numPoints = 0; stream >> numPoints; if (numPoints <= 0) { throw FileException("MNI OBJ file contains no points."); } // // Size data structures // const int numPointComponents = numPoints * 3; points.resize(numPointComponents); normals.resize(numPointComponents); const int numPointColorComponents = numPoints * 4; colors.resize(numPointColorComponents); // // Read points // for (int i = 0; i < numPointComponents; i++) { stream >> points[i]; } // // Read normals // for (int i = 0; i < numPointComponents; i++) { stream >> normals[i]; } // // Read number of triangles // int numTriangles = 0; stream >> numTriangles; if (numTriangles <= 0) { throw FileException("MNI OBJ file contains no triangles."); } const int numTriangleComponents = numTriangles * 3; triangles.resize(numTriangleComponents); // // Read the color flag // bool haveTriangleColors = false; std::vector triangleColors; const int numTriangleColorComponents = numTriangles * 4; int colorFlag = -1; stream >> colorFlag; switch (colorFlag) { case 0: // same color applies to all points { float rf, gf, bf, af; stream >> rf >> gf >> bf >> af; const unsigned char r = static_cast(rf * 255.0); const unsigned char g = static_cast(gf * 255.0); const unsigned char b = static_cast(bf * 255.0); const unsigned char a = static_cast(af * 255.0); for (int i = 0; i < numPoints; i++) { const int i4 = i * 4; colors[i4] = r; colors[i4+1] = g; colors[i4+2] = b; colors[i4+3] = a; } } break; case 1: // colors provided for each triangles triangleColors.resize(numTriangleColorComponents); for (int i = 0; i < numTriangleColorComponents; i++) { stream >> triangleColors[i]; } haveTriangleColors = true; break; case 2: // colors provided for each point { for (int i = 0; i < numPoints; i++) { float rf, gf, bf, af; stream >> rf >> gf >> bf >> af; const unsigned char r = static_cast(rf * 255.0); const unsigned char g = static_cast(gf * 255.0); const unsigned char b = static_cast(bf * 255.0); const unsigned char a = static_cast(af * 255.0); const int i4 = i * 4; colors[i4] = r; colors[i4+1] = g; colors[i4+2] = b; colors[i4+3] = a; } } break; default: throw FileException("MNI OBJ file has invalid color flag (< 0)"); break; } // // Ignore "end indices" // for (int i = 0; i < numTriangles; i++) { int endIndex; stream >> endIndex; } // // Read in the triangles // for (int i = 0; i < numTriangleComponents; i++) { stream >> triangles[i]; } // // Handle triangle colors // if (haveTriangleColors) { std::vector nodeCount(numPoints, 0.0); std::vector nodeColorComponents(numPointColorComponents, 0.0); for (int i = 0; i < numTriangles; i++) { // // Get the color for the triangle // const int i4 = i*4; const int* t = getTriangle(i); const float* triColor = &triangleColors[i4]; // // Loop through triangles 3 nodes // for (int j = 0; j < 3; j++) { // // Loop through 4 color components // for (int k = 0; k < 4; k++) { const int pointIndex = t[j]; nodeColorComponents[pointIndex*4 + k] += triColor[k]; } nodeCount[i] += 1.0; } } for (int i = 0; i < numPoints; i++) { if (nodeCount[i] > 0.0) { const int i4 = i * 4; for (int k = 0; k < 4; k++) { colors[i4+k] = static_cast( (nodeColorComponents[i4+k] / nodeCount[i]) * 255.0); } } } throw FileException("Triangle colors not supported at this time."); } } /** * Write the file's data (header has already been written). */ void MniObjSurfaceFile::writeFileData(QTextStream& /*stream*/, QDataStream& /*binStream*/, QDomDocument& /*xmlDoc*/, QDomElement& /*rootElement*/) throw (FileException) { throw FileException("Writing of MniObjSurfaceFile files not supported."); } caret-5.6.4~dfsg.1.orig/caret_files/MetricFile.h0000664000175000017500000006533211572067322021246 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __METRIC_FILE__CLASS_H__ #define __METRIC_FILE__CLASS_H__ #include "CoordinateFile.h" #include "FileException.h" #include "GiftiCommon.h" #include "GiftiNodeDataFile.h" #include "SpecFile.h" class DeformationMapFile; class TopologyFile; /// MetricMappingInfo is a class used when mapping functional volumes to a metric file. /// It is not stored in the MetricFile. class MetricMappingInfo { public: /// Constructor MetricMappingInfo(); /// Constructor MetricMappingInfo(const QString& surfaceNameIn, const int surfaceIndexNumberIn, const QString& volumeNameIn, const QString& subVolumeNameIn, const int volumeNumberIn, const int subVolumeNumberIn); /// Destructor virtual ~MetricMappingInfo(); /// reset the data void reset(); /// set the data void setData(const QString& surfaceNameIn, const int surfaceIndexNumberIn, const QString& volumeNameIn, const QString& subVolumeNameIn, const int volumeNumberIn, const int subVolumeNumberIn); /// get the data void getData(QString& surfaceNameOut, int& surfaceIndexNumberOut, QString& volumeNameOut, QString& subVolumeNameOut, int& volumeNumberOut, int& subVolumeNumberOut) const; protected: /// the volume number int volumeNumber; /// the sub-volume number int subVolumeNumber; /// the name of the volume QString volumeName; /// the sub volume name QString subVolumeName; /// the name of the surface QString surfaceName; /// the surface index number int surfaceIndexNumber; }; /// MetricFile - a class that associates one or more floating point values with each surface node class MetricFile : public GiftiNodeDataFile { public: /* /// smoothing algorithms enum SMOOTH_ALGORITHM { SMOOTH_ALGORITHM_AVERAGE_NEIGHBORS, SMOOTH_ALGORITHM_SURFACE_NORMAL_GAUSSIAN, SMOOTH_ALGORITHM_WEIGHTED_AVERAGE_NEIGHBORS, SMOOTH_ALGORITHM_NONE }; */ /// concatenate columns mode enum CONCATENATE_COLUMNS_MODE { /// concatenate all columns from all files CONCATENATE_COLUMNS_MODE_ALL, /// concatenate columns with exact matching name CONCATENATE_COLUMNS_MODE_NAME_EXACT }; /// coordinate difference mode enum COORDINATE_DIFFERENCE_MODE { /// absolute difference COORDINATE_DIFFERENCE_MODE_ABSOLUTE, /// signed difference COORDINATE_DIFFERENCE_MODE_SIGNED }; // constructor MetricFile(const QString& descriptiveName = "MetricFile", const QString& defaultDataArrayCategoryIn = GiftiCommon::intentUnknown, const QString& defaultExt = SpecFile::getMetricFileExtension()); // constructor MetricFile(const int initialNumberNodes, const int initialNumberOfColumns, const QString& descriptiveName = "MetricFile", const QString& defaultDataArrayCategoryIn = GiftiCommon::intentUnknown, const QString& defaultExt = SpecFile::getMetricFileExtension()); // copy constructor MetricFile(const MetricFile& nndf); // destructor virtual ~MetricFile(); // assignment operator MetricFile& operator=(const MetricFile& mf); // clear the metric file void clear(); // add a data array virtual void addDataArray(GiftiDataArray* nda); // append a data array file to this one virtual void append(const GiftiDataArrayFile& naf) throw (FileException); // 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 GiftiDataArrayFile& naf, std::vector& indexDestination, const FILE_COMMENT_MODE fcm) throw (FileException); /// reset a data array virtual void resetDataArray(const int arrayIndex); /// remove a data array virtual void removeDataArray(const int arrayIndex); /// add a column that is distance between nodes in two coordinate files (c1 - c2) void addColumnOfCoordinateDifference(const COORDINATE_DIFFERENCE_MODE diffMode, const CoordinateFile* c1, const CoordinateFile* c2, const TopologyFile* topologyFile, const int column, const QString& columnName, const QString& columnComment, const int xDiffColumn = -1, const int yDiffColumn = -1, const int zDiffColumn = -1) throw (FileException); /// add a column that is T-Map of distances in two coordinate files (c1 - c2) void addColumnOfCoordinateDifferenceTMap(const CoordinateFile* c1, const CoordinateFile* c2, const TopologyFile* topologyFile, const int column, const QString& columnName, const QString& columnComment, const MetricFile* deviationSquaredDividedByN_1, const int deviation1Column, const MetricFile* deviationSquaredDividedByN_2, const int deviation2Column, const bool addCoordinateDifferencesFlag) throw (FileException); // return a metric file that contains descriptive statistics about "this" metric file MetricFile* descriptiveStatistics(const bool keepDataColumns = false, const QString& meanColumnName = "Mean", const QString& varianceColumnName = "Variance", const QString& sampleVarianceColumnName = "Sample Variance", const QString& standardDeviationColumnName = "Standard Deviation", const QString& sampleStandardDeviationColumnName = "Sample Standard Deviation", const QString& standardErrorOfTheMeanColumnName = "Standard Error of the Mean", const QString& rootMeanSquareColumnName = "Root Mean Square", const QString& minimumColumnName = "Minimum", const QString& maximumColumnName = "Maximum", const QString& medianColumnName = "Median", const QString& skewnessColumnName = "Skewness", const QString& kurtosisColumnName = "Kurtosis") const throw (FileException); // compute the average, deviation, error for all columns for each node void computeStatistics(const QString& averageColumnName = "Average", const QString& standardDeviationColumnName = "Deviation", const QString& standardErrorColumnName = "Standard Error", const QString& minimumAbsColumnName = "MinimumAbs", const QString& maximumAbsColumnName = "MaximumAbs"); // compute the average, deviation, error for specified columns for each node void computeStatistics(const std::vector& useColumn, const QString& averageColumnName = "Average", const QString& standardDeviationColumnName = "Deviation", const QString& standardErrorColumnName = "Standard Error", const QString& minimumAbsColumnName = "MinimumAbs", const QString& maximumAbsColumnName = "MaximumAbs"); // Compute the correlation coefficient for a column in relation to all other columns. void correlationCoefficient(const int columnOfInterest, std::vector& correlationCoefficients, const std::vector* limitToTheseNodes = NULL) const; // compute and return a metric file that is a Z-map of "this" metric file // Z-map is (Xi - Mean)/Dev for all elements in each row MetricFile* computeStatisticalZMap() const throw (FileException); // compute and return a metric file that contains permuted T-Values of "this" metric file // permutation is perfomred by genernating a random plus or minus one for each column // and multiplying the row by +/-1 and then computing the T-Value MetricFile* computePermutedTValues(const float constant, const int iterations, const TopologyFile* topologyFile, const int varianceSmoothingIterations, const float varianceSmoothingStrength) const throw (FileException); // compute and return a metric file that computes T-Values of "this" metric file // T-Value = (mean - constant) / (sample-dev / sqrt(N)) MetricFile* computeTValues(const float constant, const TopologyFile* topologyFile, const int varianceSmoothingIterations, const float varianceSmoothingStrength) const throw (FileException); // compute and return a T-map for the rows of two metric files static MetricFile* computeStatisticalTMap(const MetricFile* m1, const MetricFile* m2, const TopologyFile* topologyFile, const int varianceSmoothingIterations, const float varianceSmoothingStrength, const bool poolTheVariance, const float falseDiscoveryRateQ, const bool doFalseDiscoveryRateFlag, const bool doDegreesOfFreedomFlag, const bool doPValuesFlag) throw (FileException); // compute and return a Levene map for the rows of the metric files static MetricFile* computeStatisticalLeveneMap(const std::vector& inputFiles) throw (FileException); // subract the average of both files form each file (output files are replaced) static void subtractMeanFromRowElements(const MetricFile* inputFile1, const MetricFile* inputFile2, MetricFile* outputFile1, MetricFile* outputFile2) throw (FileException); // concatenate columns from a group of metric files (all must have same number of nodes) static void concatenateColumnsFromFiles(const QString& outputFileName, const std::vector& inputFileNames, const CONCATENATE_COLUMNS_MODE mode, const QString& columnName) throw (FileException); // extract columns (indices starting at zero) from a metric file and store in another metric file static void extractColumnsFromFile(const QString& inputFileName, const QString& outputFileName, const std::vector& columnsToExtract) throw (FileException); // shuffle the values amongst group of metric files (input and output files must be same dimensions) static void shuffle(const std::vector& metricFilesIn, std::vector& metricFilesOut) throw (FileException); // compute T-map on shuffled columns split into two groups MetricFile* computeStatisticalShuffledTMap(const int numberOfRepetitions, const int numberInGroup1, const TopologyFile* topologyFile, const int varianceSmoothingIterations, const float varianceSmoothingStrength, const bool poolTheVariance) const throw (FileException); // compute shuffled cross correlation maps MetricFile* computeShuffledCrossCorrelationsMap(const int numberOfRepetitions) const throw (FileException); // compute normalization of all columns MetricFile* computeNormalization(const float mean, const float standardDeviation) const throw (FileException); // compute correlation coefficient map static MetricFile* computeCorrelationCoefficientMap(const MetricFile* m1, const MetricFile* m2) throw (FileException); // compute correlation coefficient map. static MetricFile* computeMultipleCorrelationCoefficientMap(const MetricFile* dependentMetricFile, const std::vector& independentMetricFiles) throw (FileException); // remap values in a column so that they fit a normal distribution // with the media at the normal distribution's mean void remapColumnToNormalDistribution(const int inputColumnNumber, const int outputColumnNumber, const QString& outputColumnName, const float normalDistributionMean, const float normalDistributionDeviation) throw (FileException); // deform "this" node attribute file placing the output in "deformedFile". void deformFile(const DeformationMapFile& dmf, GiftiNodeDataFile& deformedFile, const DEFORM_TYPE dt) const throw (FileException); /// get the mapping information MetricMappingInfo* getColumnMappingInfo(const int columnNumber); /// get the mapping information (const method) const MetricMappingInfo* getColumnMappingInfo(const int columnNumber) const; /// set the color mapping min/max for all columns to the column min/max values void setColorMappingToColumnMinMax(); /// get column color mapping min/max void getColumnColorMappingMinMax(const int columnNumber, float& minValue, float& maxValue) const; /// get column color mapping min/max void setColumnColorMappingMinMax(const int columnNumber, const float minValue, const float maxValue); /// get min/max for a data column void getDataColumnMinMax(const int columnNumber, float& minValue, float& maxValue); /// get thresholding for a column void getColumnThresholding(const int columnNumber, float& negThreshOut, float& posThreshOut) const; /// set thresholding for a column void setColumnThresholding(const int columnNumber, const float negThreshIn, const float posThreshIn); /// get average thresholding for a column void getColumnAverageThresholding(const int columnNumber, float& negThreshOut, float& posThreshOut) const; /// set average thresholding for a column void setColumnAverageThresholding(const int columnNumber, const float negThreshIn, const float posThreshIn); /// get the number of nodes that exceed each of the thresholds void getThresholdExceededCounts(const int columnNumber, const float negThresh, const float posThresh, int& numNegExceeded, int& numPosExceeded) const; /// get data column min/max for the specified percentages void getMinMaxValuesFromPercentages(const int columnNumber, const float negMaxPct, const float negMinPct, const float posMinPct, const float posMaxPct, float& negMaxValueOut, float& negMinValueOut, float& posMinValueOut, float& posMaxValueOut); /// get a metric for specifed node and column float getValue(const int nodeNumber, const int columnNumber) const; /// get metrics for all columns of a specified node /// "metrics" must be allocated by user to contain getNumberOfColumns() elements void getAllColumnValuesForNode(const int nodeNumber, float* metrics) const; /// get metrics for all columns of a specified node void getAllColumnValuesForNode(const int nodeNumber, std::vector& metrics) const; /// set a metric for specified node and column void setValue(const int nodeNumber, const int columnNumber, const float metric); /// set all columns metrics for a specified node void setAllColumnValuesForNode(const int nodeNumber, const float* metrics); /// Get a column of values for all nodes void getColumnForAllNodes(const int columnNumber, std::vector& values) const; /// Get a column of values for all nodes (values must be allocated to getNumberOfNodes() elements) void getColumnForAllNodes(const int columnNumber, float* values) const; /// Set a column of values for all nodes void setColumnForAllNodes(const int columnNumber, const std::vector& values); /// Set a column of values for all nodes void setColumnForAllNodes(const int columnNumber, const float* values); /// Set a column with a scalar for all nodes void setColumnAllNodesToScalar(const int columnNumber, const float value); /// get the column number for the column with the specified name int getNamedColumnNumber(const QString& name) const; /// change a range of values to zero void setRangeOfValuesToZero(const int inputColumnNumber, const int outputColumnNumber, const QString& outputColumnName, const float minValue, const float maxValue, const bool inclusiveRangeFlag) throw (FileException); /// perform binary opertion on columns of metric file void performBinaryOperation(const BINARY_OPERATION operation, const int columnA, const int columnB, const int resultColumn, const QString& resultColumnName) throw (FileException); /// perform unary opertion on columns of metric file void performUnaryOperation(const UNARY_OPERATION operation, const int column, const int resultColumn, const QString& resultColumnName, const float scalar) throw (FileException); /// average neighbor smooth a metric column (if output column is negative a new column is created) void smoothAverageNeighbors(const int column, const int outputColumnIn, const QString& outputColumnName, const float strength, const int iterations, const TopologyFile* topologyFile); /// neighbor value smoothing void smoothNeighbors(const TopologyFile* tf, const int column); /// log 10 scale a column (do all columns if column number is negative) void scaleColumnLog10(const int columnIn); /// read just the column names from the file //void readFileColumnNames(const QString& filename, // std::vector& columnNames) throw (FileException); /// Export to a free surfer functional file. void exportFreeSurferAsciiFunctionalFile(const int columnNumber, const QString& filename) throw (FileException); /// Import free surfer functional as metric void importFreeSurferFunctionalFile(const int numNodes, const QString& filename, const FILE_FORMAT fileFormat = AbstractFile::FILE_FORMAT_ASCII) throw (FileException); /// write the file's memory in caret6 format to the specified name virtual QString writeFileInCaret6Format(const QString& filenameIn, Structure structure,const ColorFile* colorFileIn, const bool useCaret6ExtensionFlag) throw (FileException); protected: // copy helper used by assignment operator and copy constructor void copyHelperMetric(const MetricFile& mf); /// used when mapping volumes to metric file (not stored in metric file) mutable std::vector columnMappingInfo; /// column minimum/maximum values valid std::vector columnMinimumMaximumValid; // copy a column of values to another column void copyColumn(const int inputColumnNumber, const int outputColumnNumber); // read metric file version 0 void readFileVersion_0(QFile& file, QTextStream& stream, QDataStream& binStream) throw (FileException); // read metric file version 1 void readFileVersion_1(QTextStream& stream, QDataStream& binStream) throw (FileException); // read metric file version 2 void readFileVersion_2(QFile& file, QTextStream& stream, QDataStream& binStream) throw (FileException); // read the metric data for the nodes void readMetricNodeData(QTextStream& stream, QDataStream& binStream) throw (FileException); // read the metric file's data void readLegacyNodeFileData(QFile& file, QTextStream& stream, QDataStream& binStream) throw (FileException); // write metric file void writeLegacyNodeFileData(QTextStream& stream, QDataStream& binStream) throw (FileException); /// allows files to do processing after a file is read virtual void postFileReadingProcessing() throw (FileException); static const QString tagColumnColorMapping; static const QString tagColumnThreshold; static const QString tagColumnAverageThreshold; static const QString metaDataColumnColorMapping; static const QString metaDataColumnThreshold; static const QString metaDataColumnAverageThreshold; }; #endif // __METRIC_FILE__CLASS_H__ #ifdef _METRIC_MAIN_ const QString MetricFile::tagColumnColorMapping = "tag-column-color-mapping"; const QString MetricFile::tagColumnThreshold = "tag-column-threshold"; const QString MetricFile::tagColumnAverageThreshold = "tag-column-average-threshold"; const QString MetricFile::metaDataColumnColorMapping = "column-color-mapping"; const QString MetricFile::metaDataColumnThreshold = "column-threshold"; const QString MetricFile::metaDataColumnAverageThreshold = "column-average-threshold"; #endif // _METRIC_MAIN_ caret-5.6.4~dfsg.1.orig/caret_files/MetricFile.cxx0000664000175000017500000047413011572067322021621 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "FileUtilities.h" #include "MathUtilities.h" #define _METRIC_MAIN_ #include "MetricFile.h" #undef _METRIC_MAIN_ #include "CoordinateFile.h" #include "DebugControl.h" #include "DeformationMapFile.h" #include "StatisticDataGroup.h" #include "StatisticFalseDiscoveryRate.h" #include "FreeSurferFunctionalFile.h" #include "GaussianComputation.h" #include "MathUtilities.h" #include "StatisticConvertToZScore.h" #include "StatisticCorrelationCoefficient.h" #include "StatisticDataGroup.h" #include "StatisticDescriptiveStatistics.h" #include "StatisticsUtilities.h" #include "StatisticGeneratePValue.h" #include "StatisticLeveneVarianceEquality.h" #include "StatisticMeanAndDeviation.h" #include "StatisticMultipleRegression.h" #include "StatisticNormalizeDistribution.h" #include "StatisticPermutation.h" #include "StatisticRandomNumber.h" #include "StringUtilities.h" #include "TopologyFile.h" #include "TopologyHelper.h" /** * The constructor */ MetricFile::MetricFile(const QString& descriptiveName, const QString& defaultDataArrayCategoryIn, const QString& defaultExt) : GiftiNodeDataFile(descriptiveName, defaultDataArrayCategoryIn, GiftiDataArray::DATA_TYPE_FLOAT32, 1, defaultExt, AbstractFile::FILE_FORMAT_ASCII, FILE_IO_READ_AND_WRITE, FILE_IO_READ_AND_WRITE, FILE_IO_NONE, FILE_IO_READ_AND_WRITE) { clear(); } /** * constructor. */ MetricFile::MetricFile(const int initialNumberOfNodes, const int initialNumberOfColumns, const QString& descriptiveName, const QString& defaultDataArrayCategoryIn, const QString& defaultExt) : GiftiNodeDataFile(descriptiveName, defaultDataArrayCategoryIn, GiftiDataArray::DATA_TYPE_FLOAT32, 1, defaultExt, AbstractFile::FILE_FORMAT_ASCII, FILE_IO_READ_AND_WRITE, FILE_IO_READ_AND_WRITE, FILE_IO_NONE, FILE_IO_READ_AND_WRITE) { setNumberOfNodesAndColumns(initialNumberOfNodes, initialNumberOfColumns); for (int j = 0; j < initialNumberOfColumns; j++) { setColumnAllNodesToScalar(j, 0.0); } } /** * copy constructor. */ MetricFile::MetricFile(const MetricFile& mf) : GiftiNodeDataFile(mf) { copyHelperMetric(mf); } /** * The destructor */ MetricFile::~MetricFile() { clear(); } /** * assignment operator. */ MetricFile& MetricFile::operator=(const MetricFile& mf) { if (this != &mf) { GiftiNodeDataFile::operator=(mf); copyHelperMetric(mf); } return *this; } /** * copy helper used by assignment operator and copy constructor. */ void MetricFile::copyHelperMetric(const MetricFile& mf) { columnMappingInfo = mf.columnMappingInfo; } /** * Clear the contents of the metric file */ void MetricFile::clear() { GiftiNodeDataFile::clear(); setNumberOfNodesAndColumns(0, 0); //readColumnNamesOnly = false; } /** * add a data array. */ void MetricFile::addDataArray(GiftiDataArray* nda) { GiftiNodeDataFile::addDataArray(nda); columnMappingInfo.resize(getNumberOfDataArrays()); } /** * append a data array file to this one. */ void MetricFile::append(const GiftiDataArrayFile& naf) throw (FileException) { const MetricFile& mf = dynamic_cast(naf); int num = getNumberOfDataArrays(); GiftiNodeDataFile::append(naf); int newNum = getNumberOfDataArrays(); columnMappingInfo.resize(newNum); for (int i = num; i < newNum; i++) { columnMappingInfo[i] = mf.columnMappingInfo[i - num]; } } /** * 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). * "indexDestination" will be updated with the columns actually used. */ void MetricFile::append(const GiftiDataArrayFile& naf, std::vector& indexDestination, const FILE_COMMENT_MODE fcm) throw (FileException) { const MetricFile& mf = dynamic_cast(naf); const int numAppendArrays = naf.getNumberOfDataArrays(); if (numAppendArrays <= 0) { return; } // // indexDestination will be incorrect if the metric file had // a column that was multi-dimensional and was split up into // new single dimension data arrays. New -1 for new arrays // meaning create a new column. // while (static_cast(indexDestination.size()) < numAppendArrays) { indexDestination.push_back(-1); } GiftiNodeDataFile::append(naf, indexDestination, fcm); columnMappingInfo.resize(getNumberOfDataArrays()); // // Note: indexDestination is modified by GiftiDataArrayFile so that it always // contains the destination column indices // for (int i = 0; i < numAppendArrays; i++) { const int arrayIndex = indexDestination[i]; if (arrayIndex >= 0) { columnMappingInfo[arrayIndex] = mf.columnMappingInfo[i]; } } } /** * reset a data array. */ void MetricFile::resetDataArray(const int arrayIndex) { GiftiNodeDataFile::resetDataArray(arrayIndex); columnMappingInfo[arrayIndex].reset(); } /** * remove a data array. */ void MetricFile::removeDataArray(const int arrayIndex) { GiftiNodeDataFile::removeDataArray(arrayIndex); for (int i = arrayIndex; i < (arrayIndex - 1); i++) { columnMappingInfo[i] = columnMappingInfo[i + 1]; } columnMappingInfo.resize(getNumberOfDataArrays()); } /** * get the mapping information. */ MetricMappingInfo* MetricFile::getColumnMappingInfo(const int columnNumber) { columnMappingInfo.resize(getNumberOfColumns()); if (columnNumber < getNumberOfColumns()) { return &columnMappingInfo[columnNumber]; } return NULL; } /** * get the mapping information (const method). */ const MetricMappingInfo* MetricFile::getColumnMappingInfo(const int columnNumber) const { if (columnNumber < getNumberOfColumns()) { return &columnMappingInfo[columnNumber]; } return NULL; } /** * Deform the metric file */ void MetricFile::deformFile(const DeformationMapFile& dmf, GiftiNodeDataFile& deformedFile, const DEFORM_TYPE dt) const throw (FileException) { MetricFile& deformedMetricFile = dynamic_cast(deformedFile); const int numNodes = dmf.getNumberOfNodes(); const int numCols = getNumberOfColumns(); deformedMetricFile.setNumberOfNodesAndColumns(numNodes, numCols); // // Transfer stuff in AbstractFile and NodeAttributeFile // transferFileDataForDeformation(dmf, deformedMetricFile); // // Transfer metric file title and column names/comments // for (int k = 0; k < numCols; k++) { float minValue, maxValue; getColumnColorMappingMinMax(k, minValue, maxValue); deformedMetricFile.setColumnColorMappingMinMax(k, minValue, maxValue); float negThresh, posThresh; getColumnThresholding(k, negThresh, posThresh); deformedMetricFile.setColumnThresholding(k, negThresh, posThresh); } // // transfer the metric columns // float* data0 = new float[numCols]; float* data1 = new float[numCols]; float* data2 = new float[numCols]; float* dataOut = new float[numCols]; int tileNodes[3]; float tileAreas[3]; for (int i = 0; i < numNodes; i++) { dmf.getDeformDataForNode(i, tileNodes, tileAreas); if (dt == DEFORM_NEAREST_NODE) { if (tileNodes[0] > -1) { getAllColumnValuesForNode(tileNodes[0], data0); for (int j = 0; j < numCols; j++) { dataOut[j] = data0[j]; } } else { for (int j = 0; j < numCols; j++) { dataOut[j] = 0.0; } } } else { if ((tileNodes[0] > -1) && (tileNodes[1] > -1) && (tileNodes[2] > -1)) { getAllColumnValuesForNode(tileNodes[0], data0); getAllColumnValuesForNode(tileNodes[1], data1); getAllColumnValuesForNode(tileNodes[2], data2); for (int j = 0; j < numCols; j++) { const float totalArea = tileAreas[0] + tileAreas[1] + tileAreas[2]; if (totalArea > 0.0) { // // Note: Caret has historically done its barycentric calculations // skewed one index // dataOut[j] = data0[j] * (tileAreas[1] / totalArea) + data1[j] * (tileAreas[2] / totalArea) + data2[j] * (tileAreas[0] / totalArea); } } } else { for (int j = 0; j < numCols; j++) { dataOut[j] = 0.0; } } } deformedMetricFile.setAllColumnValuesForNode(i, dataOut); } delete[] data0; delete[] data1; delete[] data2; delete[] dataOut; } /** * Get the number of a column with the specified name. */ int MetricFile::getNamedColumnNumber(const QString& name) const { return getColumnWithName(name); } /** * Get the color mapping min/max for a column. */ void MetricFile::getColumnColorMappingMinMax(const int columnNumber, float& minValue, float& maxValue) const { minValue = -1.0; maxValue = 1.0; std::vector f; if ((columnNumber >= 0) && (columnNumber < getNumberOfDataArrays())) { if (dataArrays[columnNumber]->getMetaData()->get(metaDataColumnColorMapping, f)) { if (f.size() == 2) { minValue = f[0]; maxValue = f[1]; return; } } f.clear(); f.push_back(minValue); f.push_back(maxValue); dataArrays[columnNumber]->getMetaData()->set(metaDataColumnColorMapping, f); } } /** * set the color mapping min/max for all columns to the column min/max values. */ void MetricFile::setColorMappingToColumnMinMax() { const int numCols = getNumberOfColumns(); for (int i = 0; i < numCols; i++) { float minVal, maxVal; getDataColumnMinMax(i, minVal, maxVal); setColumnColorMappingMinMax(i, minVal, maxVal); } } /** * set color mapping min/max for a column. */ void MetricFile::setColumnColorMappingMinMax(const int columnNumber, const float minValue, const float maxValue) { float neg, pos; getColumnColorMappingMinMax(columnNumber, neg, pos); bool saveIt = false; if (neg != minValue) { saveIt = true; } if (pos != maxValue) { saveIt = true; } if (saveIt) { std::vector f; f.push_back(minValue); f.push_back(maxValue); dataArrays[columnNumber]->getMetaData()->set(metaDataColumnColorMapping, f); setModified(); } } /** * Get the min/max values for a column */ void MetricFile::getDataColumnMinMax(const int columnNumber, float& minValue, float& maxValue) { minValue = -10000.0; maxValue = 10000.0; if ((columnNumber >= 0) && (columnNumber < getNumberOfDataArrays())) { dataArrays[columnNumber]->getMinMaxValues(minValue, maxValue); } /* if (columnMinimumMaximumValid[columnNumber] == false) { float minVal = std::numeric_limits::max(); float maxVal = -minVal; for (int i = 0; i < numberOfNodes; i++) { const int offset = getOffset(i, columnNumber); if (data[offset] < minVal) minVal = data[offset]; if (data[offset] > maxVal) maxVal = data[offset]; } columnMinimumValue[columnNumber] = minVal; columnMaximumValue[columnNumber] = maxVal; columnMinimumMaximumValid[columnNumber] = true; } minValue = columnMinimumValue[columnNumber]; maxValue = columnMaximumValue[columnNumber]; */ } /** * Get data column min/max for the specified percentages. */ void MetricFile::getMinMaxValuesFromPercentages(const int columnNumber, const float negMaxPct, const float negMinPct, const float posMinPct, const float posMaxPct, float& negMaxValueOut, float& negMinValueOut, float& posMinValueOut, float& posMaxValueOut) { negMaxValueOut = 0.0; negMinValueOut = 0.0; posMinValueOut = 0.0; posMaxValueOut = 0.0; if ((columnNumber >= 0) && (columnNumber < getNumberOfDataArrays())) { dataArrays[columnNumber]->getMinMaxValuesFromPercentages(negMaxPct, negMinPct, posMinPct, posMaxPct, negMaxValueOut, negMinValueOut, posMinValueOut, posMaxValueOut); } if (DebugControl::getDebugOn()) { std::cout << "NegMax/NegMin/PosMin/PosMax " << negMaxValueOut << "/" << negMinValueOut << "/" << posMinValueOut << "/" << posMaxValueOut << std::endl; } } /** * get thresholding for a column. */ void MetricFile::getColumnThresholding(const int columnNumber, float& negThreshOut, float& posThreshOut) const { std::vector f; if (dataArrays[columnNumber]->getMetaData()->get(metaDataColumnThreshold, f)) { if (f.size() == 2) { negThreshOut = f[0]; posThreshOut = f[1]; return; } } f.clear(); negThreshOut = 0.0; posThreshOut = 0.0; f.push_back(negThreshOut); f.push_back(posThreshOut); dataArrays[columnNumber]->getMetaData()->set(metaDataColumnThreshold, f); } /** * set thresholding for a column. */ void MetricFile::setColumnThresholding(const int columnNumber, const float negThreshIn, const float posThreshIn) { float oldNeg, oldPos; getColumnThresholding(columnNumber, oldNeg, oldPos); bool saveIt = false; if (oldNeg != negThreshIn) { const float diff = std::fabs(oldNeg - negThreshIn); if (diff > 0.001) { saveIt = true; } } if (oldPos != posThreshIn) { const float diff = std::fabs(oldPos - posThreshIn); if (diff > 0.001) { saveIt = true; } } if (saveIt) { std::vector f; f.push_back(negThreshIn); f.push_back(posThreshIn); dataArrays[columnNumber]->getMetaData()->set(metaDataColumnThreshold, f); setModified(); } } /** * get average thresholding for a column. */ void MetricFile::getColumnAverageThresholding(const int columnNumber, float& negThreshOut, float& posThreshOut) const { std::vector f; if (dataArrays[columnNumber]->getMetaData()->get(metaDataColumnAverageThreshold, f)) { if (f.size() == 2) { negThreshOut = f[0]; posThreshOut = f[1]; return; } } f.clear(); negThreshOut = 0.0; posThreshOut = 0.0; f.push_back(negThreshOut); f.push_back(posThreshOut); dataArrays[columnNumber]->getMetaData()->set(metaDataColumnAverageThreshold, f); } /** * set average thresholding for a column. */ void MetricFile::setColumnAverageThresholding(const int columnNumber, const float negThreshIn, const float posThreshIn) { float oldNeg, oldPos; getColumnAverageThresholding(columnNumber, oldNeg, oldPos); bool saveIt = false; if (oldNeg != negThreshIn) { const float diff = std::fabs(oldNeg - negThreshIn); if (diff > 0.001) { saveIt = true; } } if (oldPos != posThreshIn) { const float diff = std::fabs(oldPos - posThreshIn); if (diff > 0.001) { saveIt = true; } } if (saveIt) { std::vector f; f.push_back(negThreshIn); f.push_back(posThreshIn); dataArrays[columnNumber]->getMetaData()->set(metaDataColumnAverageThreshold, f); setModified(); } } /** * get the number of nodes that exceed each of the thresholds. */ void MetricFile::getThresholdExceededCounts(const int columnNumber, const float negThresh, const float posThresh, int& numNegExceeded, int& numPosExceeded) const { numNegExceeded = 0; numPosExceeded = 0; const int numNodes = getNumberOfNodes(); if (numNodes <= 0) { return; } if ((columnNumber < 0) || (columnNumber >= getNumberOfColumns())) { return; } for (int i = 0; i < numNodes; i++) { const float v = getValue(i, columnNumber); if (v > posThresh) { numPosExceeded++; } if (v < negThresh) { numNegExceeded++; } } } /** * Get the metric value for a node's column. */ float MetricFile::getValue(const int nodeNumber, const int columnNumber) const { float* data = dataArrays[columnNumber]->getDataPointerFloat(); return data[nodeNumber]; } /** * get metrics for all columns of a specified node *"metrics" must be allocated by user to contain getNumberOfColumns() elements. */ void MetricFile::getAllColumnValuesForNode(const int nodeNumber, float* metrics) const { for (int i = 0; i < getNumberOfColumns(); i++) { float* data = dataArrays[i]->getDataPointerFloat(); metrics[i] = data[nodeNumber]; } } /** * Get the metrics (all columns) for a node. */ void MetricFile::getAllColumnValuesForNode(const int nodeNumber, std::vector& metrics) const { const int num = getNumberOfColumns(); if (num > 0) { metrics.resize(num); for (int i = 0; i < num; i++) { float* data = dataArrays[i]->getDataPointerFloat(); metrics[i] = data[nodeNumber]; } } else { metrics.clear(); } } /** * Set the metric value for a node's column. */ void MetricFile::setValue(const int nodeNumber, const int columnNumber, const float metric) { float* data = dataArrays[columnNumber]->getDataPointerFloat(); data[nodeNumber] = metric; dataArrays[columnNumber]->clearMinMaxFloatValuesValid(); dataArrays[columnNumber]->clearMaxMaxPercentageValuesValid(); setModified(); } /** * Set all column metrics for a specified node. */ void MetricFile::setAllColumnValuesForNode(const int nodeNumber, const float* metrics) { for (int i = 0; i < getNumberOfColumns(); i++) { float* data = dataArrays[i]->getDataPointerFloat(); data[nodeNumber] = metrics[i]; dataArrays[i]->clearMinMaxFloatValuesValid(); dataArrays[i]->clearMaxMaxPercentageValuesValid(); } setModified(); } /** * Compute the correlation coefficient for a column in relation to all other columns. */ void MetricFile::correlationCoefficient(const int columnOfInterestNumber, std::vector& correlationCoefficients, const std::vector* limitToTheseNodes) const { const int numberOfColumns = getNumberOfColumns(); const int numberOfNodes = getNumberOfNodes(); if ((numberOfColumns <= 0) || (numberOfNodes <= 0)) { return; } correlationCoefficients.resize(numberOfColumns); std::vector columnOfInterest; if (limitToTheseNodes == NULL) { getColumnForAllNodes(columnOfInterestNumber, columnOfInterest); } else { for (int j = 0; j < numberOfNodes; j++) { if ((*limitToTheseNodes)[j]) { columnOfInterest.push_back(getValue(j, columnOfInterestNumber)); } } } for (int i = 0; i < numberOfColumns; i++) { std::vector otherColumn; if (limitToTheseNodes == NULL) { getColumnForAllNodes(i, otherColumn); } else { for (int j = 0; j < numberOfNodes; j++) { if ((*limitToTheseNodes)[j]) { otherColumn.push_back(getValue(j, i)); } } } StatisticDataGroup colX(&columnOfInterest, StatisticDataGroup::DATA_STORAGE_MODE_POINT); StatisticDataGroup colY(&otherColumn, StatisticDataGroup::DATA_STORAGE_MODE_POINT); StatisticCorrelationCoefficient coeff; coeff.addDataGroup(&colX); coeff.addDataGroup(&colY); try { coeff.execute(); } catch (StatisticException& e) { const FileException fe(e); std::cout << "Correlation coeffiecient error: " << fe.whatQString().toAscii().constData() << std::endl; } correlationCoefficients[i] = coeff.getCorrelationCoefficientR2(); } } /** * return a metric file that contains descriptive statistics about "this" metric file. * If the column name is not empty, it corresponding statistic will be computed. */ MetricFile* MetricFile::descriptiveStatistics(const bool keepDataColumns, const QString& meanColumnName, const QString& varianceColumnName, const QString& sampleVarianceColumnName, const QString& standardDeviationColumnName, const QString& sampleStandardDeviationColumnName, const QString& standardErrorOfTheMeanColumnName, const QString& rootMeanSquareColumnName, const QString& minimumColumnName, const QString& maximumColumnName, const QString& medianColumnName, const QString& skewnessColumnName, const QString& kurtosisColumnName) const throw (FileException) { if (empty()) { throw FileException("Metric file contains no data."); } int numCols = 0; if (keepDataColumns) { numCols = getNumberOfColumns(); } int meanColumn = -1; if (meanColumnName.isEmpty() == false) { meanColumn = numCols; numCols++; } int varianceColumn = -1; if (varianceColumnName.isEmpty() == false) { varianceColumn = numCols; numCols++; } int sampleVarianceColumn = -1; if (sampleVarianceColumnName.isEmpty() == false) { sampleVarianceColumn = numCols; numCols++; } int standardDeviationColumn = -1; if (standardDeviationColumnName.isEmpty() == false) { standardDeviationColumn = numCols; numCols++; } int sampleStandardDeviationColumn = -1; if (sampleStandardDeviationColumnName.isEmpty() == false) { sampleStandardDeviationColumn = numCols; numCols++; } int standardErrorOfTheMeanColumn = -1; if (standardErrorOfTheMeanColumnName.isEmpty() == false) { standardErrorOfTheMeanColumn = numCols; numCols++; } int rootMeanSquareColumn = -1; if (rootMeanSquareColumnName.isEmpty() == false) { rootMeanSquareColumn = numCols; numCols++; } int minimumColumn = -1; if (minimumColumnName.isEmpty() == false) { minimumColumn = numCols; numCols++; } int maximumColumn = -1; if (maximumColumnName.isEmpty() == false) { maximumColumn = numCols; numCols++; } int medianColumn = -1; if (medianColumnName.isEmpty() == false) { medianColumn = numCols; numCols++; } int skewnessColumn = -1; if (skewnessColumnName.isEmpty() == false) { skewnessColumn = numCols; numCols++; } int kurtosisColumn = -1; if (kurtosisColumnName.isEmpty() == false) { kurtosisColumn = numCols; numCols++; } // // Create the metric file // if (numCols <= 0) { throw FileException("No statistics were selected."); } const int numNodes = getNumberOfNodes(); MetricFile* mf = new MetricFile; mf->setNumberOfNodesAndColumns(numNodes, numCols); // // Name the columns // if (meanColumn >= 0) { mf->setColumnName(meanColumn, meanColumnName); } if (varianceColumn >= 0) { mf->setColumnName(varianceColumn, varianceColumnName); } if (sampleVarianceColumn >= 0) { mf->setColumnName(sampleVarianceColumn, sampleVarianceColumnName); } if (standardDeviationColumn >= 0) { mf->setColumnName(standardDeviationColumn, standardDeviationColumnName); } if (sampleStandardDeviationColumn >= 0) { mf->setColumnName(sampleStandardDeviationColumn, sampleStandardDeviationColumnName); } if (standardErrorOfTheMeanColumn >= 0) { mf->setColumnName(standardErrorOfTheMeanColumn, standardErrorOfTheMeanColumnName); } if (rootMeanSquareColumn >= 0) { mf->setColumnName(rootMeanSquareColumn, rootMeanSquareColumnName); } if (minimumColumn >= 0) { mf->setColumnName(minimumColumn, minimumColumnName); } if (maximumColumn >= 0) { mf->setColumnName(maximumColumn, maximumColumnName); } if (medianColumn >= 0) { mf->setColumnName(medianColumn, medianColumnName); } if (skewnessColumn >= 0) { mf->setColumnName(skewnessColumn, skewnessColumnName); } if (kurtosisColumn >= 0) { mf->setColumnName(kurtosisColumn, kurtosisColumnName); } // // Number of data columns in input data // const int inputDataNumberOfColumns = getNumberOfColumns(); // // copy existing data and set column names? // if (keepDataColumns) { for (int j = 0; j < inputDataNumberOfColumns; j++) { // // Copy metadata including column names // const GiftiDataArray* gdaInput = getDataArray(j); const GiftiMetaData* mdInput = gdaInput->getMetaData(); GiftiDataArray* gdaOutput = mf->getDataArray(j); GiftiMetaData* mdOutput = gdaOutput->getMetaData(); *mdOutput = *mdInput; } // // Copy data // for (int i = 0; i < numNodes; i++) { for (int j = 0; j < inputDataNumberOfColumns; j++) { mf->setValue(i, j, getValue(i, j)); } } } // // Array for data // float* theData = new float[inputDataNumberOfColumns]; // // Loop through nodes // for (int i = 0; i < numNodes; i++) { // // Load the data array // for (int j = 0; j < inputDataNumberOfColumns; j++) { theData[j] = getValue(i, j); } // // Compute the descriptive statistics // StatisticDataGroup sdg(theData, inputDataNumberOfColumns, StatisticDataGroup::DATA_STORAGE_MODE_POINT); StatisticDescriptiveStatistics sds; sds.addDataGroup(&sdg); try { sds.execute(); } catch (StatisticException& e) { throw FileException(e); } // // set the data for selected statistics // if (meanColumn >= 0) { mf->setValue(i, meanColumn, sds.getMean()); } if (varianceColumn >= 0) { mf->setValue(i, varianceColumn, sds.getVariance()); } if (sampleVarianceColumn >= 0) { mf->setValue(i, sampleVarianceColumn, sds.getPopulationSampleVariance()); } if (standardDeviationColumn >= 0) { mf->setValue(i, standardDeviationColumn, sds.getStandardDeviation()); } if (sampleStandardDeviationColumn >= 0) { mf->setValue(i, sampleStandardDeviationColumn, sds.getPopulationSampleStandardDeviation()); } if (standardErrorOfTheMeanColumn >= 0) { mf->setValue(i, standardErrorOfTheMeanColumn, sds.getStandardErrorOfTheMean()); } if (rootMeanSquareColumn >= 0) { mf->setValue(i, rootMeanSquareColumn, sds.getRootMeanSquare()); } float minValue, maxValue; sds.getMinimumAndMaximum(minValue, maxValue); if (minimumColumn >= 0) { mf->setValue(i, minimumColumn, minValue); } if (maximumColumn >= 0) { mf->setValue(i, maximumColumn, maxValue); } if (medianColumn >= 0) { mf->setValue(i, medianColumn, sds.getMedian()); } if (skewnessColumn >= 0) { mf->setValue(i, skewnessColumn, sds.getSkewness()); } if (kurtosisColumn >= 0) { mf->setValue(i, kurtosisColumn, sds.getKurtosis()); } } delete[] theData; return mf; } /** * Compute the average and standard deviation for all metric values for each node. * If the column name is blank, that statistical measurement is not calculated. If a * columns exists with one of the column names, that column is replaced. */ void MetricFile::computeStatistics(const QString& averageColumnName, const QString& standardDeviationColumnName, const QString& standardErrorColumnName, const QString& minimumAbsColumnName, const QString& maximumAbsColumnName) { if (getNumberOfColumns() < 1) { return; } std::vector colFlag(getNumberOfColumns(), true); computeStatistics(colFlag, averageColumnName, standardDeviationColumnName, standardErrorColumnName, minimumAbsColumnName, maximumAbsColumnName); } /** * Compute the average and standard deviation for all metric values for each node. * If the column name is blank, that statistical measurement is not calculated. If a * columns exists with one of the column names, that column is replaced. */ void MetricFile::computeStatistics(const std::vector& useColumn, const QString& averageColumnName, const QString& standardDeviationColumnName, const QString& standardErrorColumnName, const QString& minimumAbsColumnName, const QString& maximumAbsColumnName) { if (getNumberOfColumns() < 1) { return; } // // Find or set the column for the average // int averageColumn = -1; if (averageColumnName.isEmpty() == false) { averageColumn = getColumnWithName(averageColumnName); if (averageColumn < 0) { averageColumn = getNumberOfColumns(); addColumns(1); setColumnName(averageColumn, averageColumnName); } } // // Find or set the column for the standard deviation // int deviationColumn = -1; if (standardDeviationColumnName.isEmpty() == false) { deviationColumn = getColumnWithName(standardDeviationColumnName); if (deviationColumn < 0) { deviationColumn = getNumberOfColumns(); addColumns(1); setColumnName(deviationColumn, standardDeviationColumnName); } } // // Find or set the column for the standard error // int standardErrorColumn = -1; if (standardErrorColumnName.isEmpty() == false) { standardErrorColumn = getColumnWithName(standardErrorColumnName); if (standardErrorColumn < 0) { standardErrorColumn = getNumberOfColumns(); addColumns(1); setColumnName(standardErrorColumn, standardErrorColumnName); } } // // Find or set the column for the minimum // int minimumAbsColumn = -1; if (minimumAbsColumnName.isEmpty() == false) { minimumAbsColumn = getColumnWithName(minimumAbsColumnName); if (minimumAbsColumn < 0) { minimumAbsColumn = getNumberOfColumns(); addColumns(1); setColumnName(minimumAbsColumn, minimumAbsColumnName); } } // // Find or set the column for the maximum // int maximumAbsColumn = -1; if (maximumAbsColumnName.isEmpty() == false) { maximumAbsColumn = getColumnWithName(maximumAbsColumnName); if (maximumAbsColumn < 0) { maximumAbsColumn = getNumberOfColumns(); addColumns(1); setColumnName(maximumAbsColumn, maximumAbsColumnName); } } int numNodes = getNumberOfNodes(); const int numCols = getNumberOfColumns(); for (int i= 0; i < numNodes; i++) { std::vector values; values.reserve(numCols); for (int j = 0; j < numCols; j++) { if ((j != averageColumn) && (j != deviationColumn) && (j != standardErrorColumn) && (j != minimumAbsColumn) && (j != maximumAbsColumn) && useColumn[j]) { values.push_back(getValue(i, j)); } } if (values.empty()) { continue; } // // Compute the statistics // /* StatisticDescriptiveStatistics ds(StatisticDescriptiveStatistics::DATA_TYPE_SAMPLE); StatisticDataGroup sdg(&values, StatisticDataGroup::DATA_STORAGE_MODE_POINT); ds.addDataGroup(&sdg); try { ds.execute(); } catch (StatisticException&) { } const StatisticDescriptiveStatistics::DescriptiveStatistics stats = ds.getDescriptiveStatistics(); */ StatisticsUtilities::DescriptiveStatistics stats; StatisticsUtilities::computeStatistics(values, true, stats); if (averageColumn >= 0) { setValue(i, averageColumn, stats.average); } if (deviationColumn >= 0) { setValue(i, deviationColumn, stats.standardDeviation); } if (standardErrorColumn >= 0) { setValue(i, standardErrorColumn, stats.standardError); } if (minimumAbsColumn >= 0) { if (stats.leastPositiveValue == 0.0) { setValue(i, minimumAbsColumn, stats.leastNegativeValue); } else if (stats.leastNegativeValue == 0.0) { setValue(i, minimumAbsColumn, stats.leastPositiveValue); } else { if (std::fabs(stats.leastPositiveValue) < std::fabs(stats.leastNegativeValue)) { setValue(i, minimumAbsColumn, stats.leastPositiveValue); } else { setValue(i, minimumAbsColumn, stats.leastNegativeValue); } } } if (maximumAbsColumn >= 0) { if (stats.mostPositiveValue == 0.0) { setValue(i, maximumAbsColumn, stats.mostNegativeValue); } else if (stats.mostNegativeValue == 0.0) { setValue(i, maximumAbsColumn, stats.mostPositiveValue); } else { if (std::fabs(stats.mostPositiveValue) > std::fabs(stats.mostNegativeValue)) { setValue(i, maximumAbsColumn, stats.mostPositiveValue); } else { setValue(i, maximumAbsColumn, stats.mostNegativeValue); } } } } // // set color mapping used for surface shape file // if (averageColumn >= 0) { float minValue, maxValue; getDataColumnMinMax(averageColumn, minValue, maxValue); setColumnColorMappingMinMax(averageColumn, minValue, maxValue); } if (deviationColumn>= 0) { float minValue, maxValue; getDataColumnMinMax(deviationColumn, minValue, maxValue); setColumnColorMappingMinMax(deviationColumn, minValue, maxValue); } if (standardErrorColumn >= 0) { float minValue, maxValue; getDataColumnMinMax(standardErrorColumn, minValue, maxValue); setColumnColorMappingMinMax(standardErrorColumn, minValue, maxValue); } if (minimumAbsColumn >= 0) { float minValue, maxValue; getDataColumnMinMax(minimumAbsColumn, minValue, maxValue); setColumnColorMappingMinMax(minimumAbsColumn, minValue, maxValue); } if (maximumAbsColumn >= 0) { float minValue, maxValue; getDataColumnMinMax(maximumAbsColumn, minValue, maxValue); setColumnColorMappingMinMax(maximumAbsColumn, minValue, maxValue); } } /** * Read the metric data for the nodes. */ void MetricFile::readMetricNodeData(QTextStream& stream, QDataStream& binStream) throw (FileException) { // // Should reading data be skipped ? // if (getReadMetaDataOnlyFlag()) { return; } const int numberOfNodes = getNumberOfNodes(); const int numberOfColumns = getNumberOfColumns(); if (numberOfColumns <= 0) { return; } //if (readColumnNamesOnly) { // return; //} float** dataPtr = new float*[numberOfColumns]; for (int i = 0; i < numberOfColumns; i++) { dataPtr[i] = dataArrays[i]->getDataPointerFloat(); } QString line; std::vector tokens; switch (getFileReadType()) { case FILE_FORMAT_ASCII: for (int i = 0; i < numberOfNodes; i++) { readLineIntoTokens(stream, line, tokens); if (static_cast(tokens.size()) < (numberOfColumns + 1)) { throw FileException(filename, "invalid metric line"); } for (int j = 0; j < numberOfColumns; j++) { dataPtr[j][i] = tokens[j + 1].toFloat(); } } break; case FILE_FORMAT_BINARY: for (int i = 0; i < numberOfNodes; i++) { for (int j = 0; j < numberOfColumns; j++) { binStream >> dataPtr[j][i]; } } break; case FILE_FORMAT_XML: throw FileException(filename, "Writing in XML format not supported."); break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Writing XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Writing in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Comma Separated Value File Format not supported."); break; } delete[] dataPtr; } /** * change a range of values to zero. */ void MetricFile::setRangeOfValuesToZero(const int inputColumnNumber, const int outputColumnNumberIn, const QString& outputColumnName, const float minValue, const float maxValue, const bool inclusiveRangeFlag) throw (FileException) { // // Check for valid input column // const int numberOfColumns = getNumberOfColumns(); const int numberOfNodes = getNumberOfNodes(); if ((numberOfColumns <= 0) || (numberOfNodes <= 0)) { throw FileException("There are no nodes in the metric file."); } if ((inputColumnNumber < 0) || (inputColumnNumber >= numberOfColumns)) { throw FileException("Input column index is invalid."); } // // Create a new column if needed. // int outputColumnNumber = outputColumnNumberIn; if ((outputColumnNumber < 0) || (outputColumnNumber >= numberOfColumns)){ addColumns(1); outputColumnNumber = getNumberOfDataArrays() - 1; } setColumnName(outputColumnNumber, outputColumnName); for (int i = 0; i < numberOfNodes; i++) { float value = getValue(i, inputColumnNumber); if (inclusiveRangeFlag) { if ((value >= minValue) && (value <= maxValue)) { value = 0.0; } } else { if ((value > minValue) && (value < maxValue)) { value = 0.0; } } setValue(i, outputColumnNumber, value); } } /** * perform binary opertion on columns of metric file. */ void MetricFile::performBinaryOperation(const BINARY_OPERATION operation, const int columnA, const int columnB, const int resultColumnIn, const QString& resultColumnName) throw (FileException) { // // Check for valid input column // const int numberOfNodes = getNumberOfNodes(); const int numberOfColumns = getNumberOfColumns(); if ((numberOfColumns <= 0) || (numberOfNodes <= 0)) { throw FileException("There are no nodes in the metric file."); } if ((columnA < 0) || (columnA >= numberOfColumns)) { throw FileException("First column index is invalid."); } if ((columnB < 0) || (columnB >= numberOfColumns)) { throw FileException("Second column index is invalid."); } // // Create a new column if needed. // int resultColumn = resultColumnIn; if ((resultColumn < 0) || (resultColumn >= numberOfColumns)){ addColumns(1); resultColumn = getNumberOfDataArrays() - 1; } setColumnName(resultColumn, resultColumnName); QString columnComment; QString addverb; switch(operation) { case BINARY_OPERATION_ADD: columnComment = "Added columns "; addverb = " and "; break; case BINARY_OPERATION_SUBTRACT: columnComment = "Subtracted columns "; addverb = " minus "; break; case BINARY_OPERATION_MULTIPLY: columnComment = "Multiplied columns "; addverb = " times "; break; case BINARY_OPERATION_DIVIDE: columnComment = "Divided columns "; addverb = " divided by "; break; case BINARY_OPERATION_AVERAGE: columnComment = "Average columns "; addverb = " averaged with "; } columnComment.append(getColumnName(columnA)); columnComment.append(addverb); columnComment.append(getColumnName(columnB)); setColumnComment(resultColumn, columnComment); for (int i = 0; i < numberOfNodes; i++) { float valueA = getValue(i, columnA); float valueB = getValue(i, columnB); float result = 0.0; switch(operation) { case BINARY_OPERATION_ADD: result = valueA + valueB; break; case BINARY_OPERATION_SUBTRACT: result = valueA - valueB; break; case BINARY_OPERATION_MULTIPLY: result = valueA * valueB; break; case BINARY_OPERATION_DIVIDE: if (valueB == 0.0) { result = 0.0; } else { result = valueA / valueB; } break; case BINARY_OPERATION_AVERAGE: result = (valueA + valueB) * 0.5; break; } setValue(i, resultColumn, result); } } /** * perform unary opertion on columns of metric file. */ void MetricFile::performUnaryOperation(const UNARY_OPERATION operation, const int column, const int resultColumnIn, const QString& resultColumnName, const float scalar) throw (FileException) { // // Check for valid input column // const int numberOfNodes = getNumberOfNodes(); const int numberOfColumns = getNumberOfColumns(); if ((numberOfColumns <= 0) || (numberOfNodes <= 0)) { throw FileException("There are no nodes in the metric file."); } if ((column < 0) || (column >= numberOfColumns)) { throw FileException("The column selected is invalid."); } // // Create a new column if needed. // int resultColumn = resultColumnIn; if ((resultColumn < 0) || (resultColumn >= numberOfColumns)){ addColumns(1); resultColumn = getNumberOfDataArrays() - 1; } setColumnName(resultColumn, resultColumnName); QString columnComment; QString adverb; switch (operation) { case UNARY_OPERATION_ADD: columnComment = "Added "; adverb = " to "; break; case UNARY_OPERATION_CEILING: columnComment = "Ceiling "; break; case UNARY_OPERATION_FLOOR: columnComment = "Floor "; break; case UNARY_OPERATION_MULTIPLY: columnComment = "Multiplied "; adverb = " by "; break; case UNARY_OPERATION_FIX_NOT_A_NUMBER: columnComment = "Fixed not-a-number"; break; case UNARY_OPERATION_ABS_VALUE: columnComment = "Abs value"; break; case UNARY_OPERATION_SQUARE_ROOT: columnComment = "Square Root"; break; case UNARY_OPERATION_SUBTRACT_FROM_ONE: columnComment = "Subtract from One"; break; case UNARY_OPERATION_LOG2: columnComment = "Log2"; break; } columnComment.append(StringUtilities::fromNumber(scalar)); columnComment.append(adverb); columnComment.append(getColumnName(column)); setColumnComment(resultColumn, columnComment); for (int i = 0; i < numberOfNodes; i++) { float value = getValue(i, column); switch (operation) { case UNARY_OPERATION_ADD: value += scalar; break; case UNARY_OPERATION_ABS_VALUE: if (value < 0.0) { value = -value; } break; case UNARY_OPERATION_CEILING: value = std::min(value, scalar); break; case UNARY_OPERATION_FLOOR: value = std::max(value, scalar); break; case UNARY_OPERATION_MULTIPLY: value *= scalar; break; case UNARY_OPERATION_FIX_NOT_A_NUMBER: if (MathUtilities::isNaN(value)) { value = 0.0; } break; case UNARY_OPERATION_SQUARE_ROOT: if (value > 0.0) { value = std::sqrt(value); } break; case UNARY_OPERATION_SUBTRACT_FROM_ONE: value = 1.0 - value; break; case UNARY_OPERATION_LOG2: // use scalar as base value = MathUtilities::log(scalar, value); break; } setValue(i, resultColumn, value); } } /** * log 10 scale a column (do all columns if column number is negative). */ void MetricFile::scaleColumnLog10(const int columnIn) { int startColumn = 0; int endColumn = getNumberOfColumns() - 1; if ((columnIn >= 0) && (columnIn < getNumberOfColumns())) { startColumn = columnIn; endColumn = columnIn; } else if (columnIn >= getNumberOfColumns()) { return; } const int numNodes = getNumberOfNodes(); for (int i = startColumn; i <= endColumn; i++) { for (int j = 0; j < numNodes; j++) { float value = getValue(j, i); if (value < 0.00001) { value = -5.0; } else { value = std::log10(value); } setValue(j, i, value); } } } /** * neighbor value smoothing. */ void MetricFile::smoothNeighbors(const TopologyFile* tf, const int column) { // // Get the topology helper // if (tf == NULL) return; const TopologyHelper* topologyHelper = tf->getTopologyHelper(false, true, false); if ((column < 0) || (column >= getNumberOfColumns())) { return; } // // Loop until no nodes have their values modified // bool nodeModified = true; while (nodeModified) { nodeModified = false; // // Loop through the nodes // const int numNodes = getNumberOfNodes(); for (int i = 0; i < numNodes; i++) { // // Get neighbors // int numNeighbors = 0; const int* neighbors = topologyHelper->getNodeNeighbors(i, numNeighbors); // // Do I have neighbors // if (numNeighbors >= 0) { // // Get my value // const float value = getValue(i, column); // // If my value is non-zero // if (value != 0.0) { // // Loop through neighbors // for (int j = 0; j < numNeighbors; j++) { // // If neighbor is connected // const int neigh = neighbors[j]; if (topologyHelper->getNodeHasNeighbors(neigh)) { // // If the neighbor is zero // if (getValue(neigh, column) == 0.0) { // // Set to my value // setValue(neigh, column, value); // // Mark that a node was modified this iteration // nodeModified = true; } } } } } } } } /** * average neighbor smooth a metric column. * (if output column is negative a new column is created). */ void MetricFile::smoothAverageNeighbors(const int column, const int outputColumnIn, const QString& outputColumnName, const float strength, const int iterations, const TopologyFile* topologyFile) { // // Check for valid input column // const int numberOfNodes = getNumberOfNodes(); const int numberOfColumns = getNumberOfColumns(); if ((numberOfColumns <= 0) || (numberOfNodes <= 0)) { return; } if ((column < 0) || (column >= numberOfColumns)) { return; } // // Inverse of strength is applied to the node's current metric value // const float oneMinusStrength = 1.0 - strength; // // Create a new column if needed. // int outputColumn = outputColumnIn; if ((outputColumn < 0) || (outputColumn >= numberOfColumns)){ addColumns(1); outputColumn = getNumberOfDataArrays() - 1; } setColumnName(outputColumn, outputColumnName); // // Copy the input column to the output column // if (column != outputColumn) { std::vector values; getColumnForAllNodes(column, values); setColumnForAllNodes(outputColumn, values); } // // column now being smoothed // const int smoothColumn = outputColumn; // // Get the topology helper // const TopologyHelper* topologyHelper = topologyFile->getTopologyHelper(false, true, false); // // Allocate arrays for storing data of column being smoothed // float* inputValues = new float[numberOfNodes]; float* outputValues = new float[numberOfNodes]; // // smooth the data for the specified number of iterations // for (int iter = 0; iter < iterations; iter++) { // // allow other events to process // AbstractFile::allowEventsToProcess(); // // load arrays for smoothing data // //std::vector columnValues(numberOfNodes); //getColumnForAllNodes(outputColumn, columnValues); getColumnForAllNodes(smoothColumn, inputValues); // // smooth all of the nodes // for (int i = 0; i < numberOfNodes; i++) { // // copy input to output in event this node is not smoothed // outputValues[i] = inputValues[i]; // // Get the neighbors for this node // //std::vector neighbors; //topologyHelper->getNodeNeighbors(i, neighbors); int numNeighbors = 0; const int* neighbors = topologyHelper->getNodeNeighbors(i, numNeighbors); // // Does this node have neighbors // //const int numNeighbors = static_cast(neighbors.size()); if (numNeighbors > 0) { // // smooth metric data for this node // float neighborSum = 0.0; for (int j = 0; j < numNeighbors; j++) { // // Note: outputColumn has output from last iteration of smoothing // neighborSum += inputValues[neighbors[j]]; } const float neighborAverage = neighborSum / static_cast(numNeighbors); // // Apply smoothing to the node // outputValues[i] = (inputValues[i] * oneMinusStrength) + (neighborAverage * strength); } } // // Copy the smoothed values to the output column // setColumnForAllNodes(smoothColumn, outputValues); } // // Add comments describing smoothing // QString smoothComment(getColumnComment(column)); if (smoothComment.isEmpty() == false) { smoothComment.append("\n"); } smoothComment.append("Average Neighbors Smoothing: \n"); smoothComment.append(" Stength/Iterations: "); smoothComment.append(StringUtilities::fromNumber(strength)); smoothComment.append(" "); smoothComment.append(StringUtilities::fromNumber(iterations)); smoothComment.append("\n"); setColumnComment(smoothColumn, smoothComment); delete[] inputValues; delete[] outputValues; setModified(); } /* void MetricFile::smooth(const SMOOTH_ALGORITHM algorithm, const int column, const int outputColumnIn, const QString& outputColumnName, const float strength, const int iterations, const TopologyFile* topologyFile, const CoordinateFile* coordinateFile, const CoordinateFile* nodeNormalVectors, const float gaussNormBelowCutoff, const float gaussNormAboveCutoff, const float gaussSigmaNorm, const float gaussSigmaTang, const float gaussTangentCutoff) { // // Check for valid input column // const int numberOfNodes = getNumberOfNodes(); const int numberOfColumns = getNumberOfColumns(); if ((numberOfColumns <= 0) || (numberOfNodes <= 0)) { return; } if ((column < 0) || (column >= numberOfColumns)) { return; } // // Inverse of strength is applied to the node's current metric value // const float oneMinusStrength = 1.0 - strength; // // Create a new column if needed. // int outputColumn = outputColumnIn; if ((outputColumn < 0) || (outputColumn >= numberOfColumns)){ addColumns(1); outputColumn = getNumberOfDataArrays() - 1; } setColumnName(outputColumn, outputColumnName); // // Copy the input column to the output column // if (column != outputColumn) { std::vector values; getColumnForAllNodes(column, values); setColumnForAllNodes(outputColumn, values); } // // column now being smoothed // const int smoothColumn = outputColumn; // // Get the topology helper // const TopologyHelper* topologyHelper = topologyFile->getTopologyHelper(false, true, false); // // Allocate arrays for storing data of column being smoothed // float* inputValues = new float[numberOfNodes]; float* outputValues = new float[numberOfNodes]; // // Used if gaussian smoothing is being performed // GaussianComputation gauss(gaussNormBelowCutoff, gaussNormAboveCutoff, gaussSigmaNorm, gaussSigmaTang, gaussTangentCutoff); // // smooth the data for the specified number of iterations // for (int iter = 0; iter < iterations; iter++) { // // allow other events to process // AbstractFile::allowEventsToProcess(); // // load arrays for smoothing data // //std::vector columnValues(numberOfNodes); //getColumnForAllNodes(outputColumn, columnValues); getColumnForAllNodes(smoothColumn, inputValues); // // smooth all of the nodes // for (int i = 0; i < numberOfNodes; i++) { // // copy input to output in event this node is not smoothed // outputValues[i] = inputValues[i]; // // Get the neighbors for this node // //std::vector neighbors; //topologyHelper->getNodeNeighbors(i, neighbors); int numNeighbors = 0; const int* neighbors = topologyHelper->getNodeNeighbors(i, numNeighbors); // // Does this node have neighbors // //const int numNeighbors = static_cast(neighbors.size()); if (numNeighbors > 0) { switch (algorithm) { case SMOOTH_ALGORITHM_NONE: break; case SMOOTH_ALGORITHM_AVERAGE_NEIGHBORS: { // // smooth metric data for this node // float neighborSum = 0.0; for (int j = 0; j < numNeighbors; j++) { // // Note: outputColumn has output from last iteration of smoothing // neighborSum += inputValues[neighbors[j]]; } const float neighborAverage = neighborSum / static_cast(numNeighbors); // // Apply smoothing to the node // outputValues[i] = (inputValues[i] * oneMinusStrength) + (neighborAverage * strength); }; break; case SMOOTH_ALGORITHM_SURFACE_NORMAL_GAUSSIAN: { // // Coordinates of all nodes // const float* allNodesCoords = coordinateFile->getCoordinate(0); const float* allNormalVectors = (nodeNormalVectors != NULL) ? nodeNormalVectors->getCoordinate(0) : NULL; std::vector points; for (int j = 0; j < numNeighbors; j++) { const int neigh = neighbors[j]; points.push_back(GaussianComputation::Point3D(&allNodesCoords[neigh*3], inputValues[neigh])); } outputValues[i] = gauss.evaluate(&allNodesCoords[i*3], &allNormalVectors[i*3], points); } break; case SMOOTH_ALGORITHM_WEIGHTED_AVERAGE_NEIGHBORS: { // // Distances to each neighbor // std::vector neighborDistance(numNeighbors); float totalDistance = 0.0; for (int j = 0; j < numNeighbors; j++) { neighborDistance[j] = coordinateFile->getDistanceBetweenCoordinates(i, neighbors[j]); totalDistance += neighborDistance[j]; } if (totalDistance == 0.0) { totalDistance = 1.0; } // // compute neighbor weighted average // std::vector neighborWeights(numNeighbors); float totalWeight = 0.0; for (int j = 0; j < numNeighbors; j++) { neighborWeights[j] = 1.0 - (neighborDistance[j] / totalDistance); totalWeight += neighborWeights[j]; } if (totalWeight == 0.0) { totalWeight = 1.0; } // // compute neighbor weighted average // float neighborSum = 0.0; for (int j = 0; j < numNeighbors; j++) { const float weight = neighborWeights[j] / totalWeight; neighborSum += inputValues[neighbors[j]] * weight; } // // Apply smoothing to the node // outputValues[i] = (inputValues[i] * oneMinusStrength) + (neighborSum * strength); } break; } } } // // Copy the smoothed values to the output column // setColumnForAllNodes(smoothColumn, outputValues); } // // Add comments describing smoothing // QString smoothComment(getColumnComment(smoothColumn)); if (smoothComment.isEmpty() == false) { smoothComment.append("\n"); } switch (algorithm) { case SMOOTH_ALGORITHM_NONE: smoothComment.append("Invalid smoothing algorithm: \n"); break; case SMOOTH_ALGORITHM_AVERAGE_NEIGHBORS: smoothComment.append("Average Neighbors Smoothing: \n"); break; case SMOOTH_ALGORITHM_SURFACE_NORMAL_GAUSSIAN: smoothComment.append("Gaussian Smoothing (Surface Normal-Based: \n"); smoothComment.append(" Norm Below Cutoff: "); smoothComment.append(StringUtilities::fromNumber(gaussNormBelowCutoff)); smoothComment.append("\n"); smoothComment.append(" Norm Above Cutoff: "); smoothComment.append(StringUtilities::fromNumber(gaussNormAboveCutoff)); smoothComment.append("\n"); smoothComment.append(" Sigma Norm: "); smoothComment.append(StringUtilities::fromNumber(gaussSigmaNorm)); smoothComment.append("\n"); smoothComment.append(" Sigma Tang: "); smoothComment.append(StringUtilities::fromNumber(gaussSigmaTang)); smoothComment.append("\n"); smoothComment.append(" Tangend Cutoff: "); smoothComment.append(StringUtilities::fromNumber(gaussTangentCutoff)); smoothComment.append("\n"); break; case SMOOTH_ALGORITHM_WEIGHTED_AVERAGE_NEIGHBORS: smoothComment.append("Weighted Average Neighbors Smoothing: \n"); break; } smoothComment.append(" Stength/Iterations: "); smoothComment.append(StringUtilities::fromNumber(strength)); smoothComment.append(" "); smoothComment.append(StringUtilities::fromNumber(iterations)); smoothComment.append("\n"); setColumnComment(smoothColumn, smoothComment); delete[] inputValues; delete[] outputValues; setModified(); } */ /** * Get a column of values for all nodes */ void MetricFile::getColumnForAllNodes(const int columnNumber, std::vector& values) const { const int numberOfNodes = getNumberOfNodes(); const int numberOfColumns = getNumberOfColumns(); if (columnNumber >= numberOfColumns) { std::cout << "PROGRAM ERROR: Invalid column number " << columnNumber << " in MetricFile::getColumnForAllNodes()." << std::endl; return; } values.resize(numberOfNodes); for (int i = 0; i < numberOfNodes; i++) { values[i] = getValue(i, columnNumber); } } /** * Set a column of values for all nodes */ void MetricFile::setColumnForAllNodes(const int columnNumber, const std::vector& values) { const int numberOfNodes = getNumberOfNodes(); const int numberOfColumns = getNumberOfColumns(); if (columnNumber >= numberOfColumns) { std::cout << "PROGRAM ERROR: Invalid column number " << columnNumber << " in MetricFile::setColumnForAllNodes()." << std::endl; return; } const int numValues = static_cast(values.size()); const int num = std::min(numValues, numberOfNodes); for (int i = 0; i < num; i++) { setValue(i, columnNumber, values[i]); } } /** * Set a column with a scalar for all nodes. */ void MetricFile::setColumnAllNodesToScalar(const int columnNumber, const float value) { const int numberOfNodes = getNumberOfNodes(); for (int i = 0; i < numberOfNodes; i++) { setValue(i, columnNumber, value); } setColumnColorMappingMinMax(columnNumber, value, value); } /** * Get a column of values for all nodes (values should have getNumberOfNodes() elements) */ void MetricFile::getColumnForAllNodes(const int columnNumber, float* values) const { const int numberOfNodes = getNumberOfNodes(); const int numberOfColumns = getNumberOfColumns(); if (columnNumber >= numberOfColumns) { std::cout << "PROGRAM ERROR: Invalid column number " << columnNumber << " in MetricFile::getColumnForAllNodes()." << std::endl; return; } for (int i = 0; i < numberOfNodes; i++) { values[i] = getValue(i, columnNumber); } } /** * Set a column of values for all nodes (values should have getNumberOfNodes() elements) */ void MetricFile::setColumnForAllNodes(const int columnNumber, const float* values) { const int numberOfNodes = getNumberOfNodes(); const int numberOfColumns = getNumberOfColumns(); if (columnNumber >= numberOfColumns) { std::cout << "PROGRAM ERROR: Invalid column number " << columnNumber << " in MetricFile::setColumnForAllNodes()." << std::endl; return; } for (int i = 0; i < numberOfNodes; i++) { setValue(i, columnNumber, values[i]); } } /** * Read only the column names from the metric file. */ /* void MetricFile::readFileColumnNames(const QString& filename, std::vector& columnNamesOut) throw (FileException) { columnNamesOut.clear(); readColumnNamesOnly = true; try { readFile(filename); } catch (FileException& e) { throw(e); } for (int i = 0; i < numberOfColumns; i++) { columnNamesOut.push_back(columnNames[i]); } clear(); readColumnNamesOnly = false; } */ /** * Read metric file version 0 */ void MetricFile::readFileVersion_0(QFile& file, QTextStream& stream, QDataStream& binStream) throw (FileException) { int numNodes = 0; int numCols = 0; // get starting position of data //qint64 startOfMetricData = stream.pos(); //file.pos(); qint64 startOfMetricData = this->getQTextStreamPosition(stream); // read through file once to get number of nodes and number of columns QString line; while(stream.atEnd() == false) { readLine(stream, line); if (numNodes == 0) { std::vector tokens; StringUtilities::token(line, " ", tokens); numCols = tokens.size() - 1; } numNodes++; } if ((numNodes <= 0) || (numCols <= 0)) { throw FileException(filename, "metric file has no data"); } setNumberOfNodesAndColumns(numNodes, numCols); // set file position as data will now be read file.seek(startOfMetricData); stream.seek(startOfMetricData); return readMetricNodeData(stream, binStream); } /** * Read version 1 of the metric file. */ void MetricFile::readFileVersion_1(QTextStream& stream, QDataStream& binStream) throw (FileException) { int numNodes = 0; int numCols = 0; QString line; readLine(stream, line); QTextStream(&line, QIODevice::ReadOnly) >> numNodes >> numCols; if ((numNodes <= 0) || (numCols <= 0)) { throw FileException(filename, "Number of nodes/columns missing"); } setNumberOfNodesAndColumns(numNodes, numCols); readLine(stream, line); float userMinimum, userMaximum; QTextStream(&line, QIODevice::ReadOnly) >> userMinimum >> userMaximum; for (int j = 0; j < numCols; j++) { QString colNum, value; readTagLine(stream, colNum, value); setColumnName(j, value); } readMetricNodeData(stream, binStream); } /** * Read metric file version 2 */ void MetricFile::readFileVersion_2(QFile& file, QTextStream& stream, QDataStream& binStream) throw (FileException) { int numNodes = -1; int numCols = -1; bool readingTags = true; while (readingTags) { QString tag, tagValue; readTagLine(stream, tag, tagValue); if (tag == tagNumberOfNodes) { if (tagValue.isEmpty()) { throw FileException(filename, "Reading line containing number of nodes"); } else { numNodes = tagValue.toInt(); if (numCols > 0) { setNumberOfNodesAndColumns(numNodes, numCols); } } } else if (tag == tagNumberOfColumns) { if (tagValue.isEmpty()) { throw FileException(filename, "Reading line containing number of columns"); } else { numCols = tagValue.toInt(); if (numNodes > 0) { setNumberOfNodesAndColumns(numNodes, numCols); } } } else if (tag == tagFileTitle) { fileTitle = tagValue; } else if (tag == tagBeginData) { readingTags = false; } else if (tag == tagColumnName) { QString name; const int indx = splitTagIntoColumnAndValue(tagValue, name); setColumnName(indx, name); } else if (tag == tagColumnComment) { QString name; const int indx = splitTagIntoColumnAndValue(tagValue, name); setColumnComment(indx, StringUtilities::setupCommentForDisplay(name)); } else if (tag == tagColumnStudyMetaData) { QString name; const int indx = splitTagIntoColumnAndValue(tagValue, name); StudyMetaDataLinkSet smdls; smdls.setLinkSetFromCodedText(name); setColumnStudyMetaDataLinkSet(indx, smdls); } else if (tag == tagColumnColorMapping) { std::vector tokens; StringUtilities::token(tagValue, " ", tokens); if (tokens.size() == 3) { int columnNumber = tokens[0].toInt(); if (columnNumber >= 0) { setColumnColorMappingMinMax(columnNumber, tokens[1].toFloat(), tokens[2].toFloat()); } else { throw FileException(filename, "column min/max color index invalid"); } } else { throw FileException(filename, "reading column min/max color mapping"); } } else if (tag == tagColumnThreshold) { std::vector tokens; StringUtilities::token(tagValue, " ", tokens); if (tokens.size() == 3) { int columnNumber = tokens[0].toInt(); if (columnNumber >= 0) { setColumnThresholding(columnNumber, tokens[1].toFloat(), tokens[2].toFloat()); } else { throw FileException(filename, "column threshold index invalid"); } } else { throw FileException(filename, "reading column threshold"); } } else if (tag == tagColumnAverageThreshold) { std::vector tokens; StringUtilities::token(tagValue, " ", tokens); if (tokens.size() == 3) { int columnNumber = tokens[0].toInt(); if (columnNumber >= 0) { setColumnAverageThresholding(columnNumber, tokens[1].toFloat(), tokens[2].toFloat()); } else { throw FileException(filename, "column average threshold index invalid"); } } else { throw FileException(filename, "reading column average thresholding"); } } else { std::cerr << "WARNING: Unknown Metric File Tag: " << tag.toAscii().constData() << std::endl; } } #ifdef QT4_FILE_POS_BUG if (getFileReadType() == FILE_FORMAT_BINARY) { qint64 offset = findBinaryDataOffsetQT4Bug(file, "tag-BEGIN-DATA"); if (offset > 0) { offset++; file.seek(offset); } } #else file.reset(); file.seek(0); qint64 offset = findBinaryDataOffsetQT4Bug(file, "tag-BEGIN-DATA"); offset++; #endif // QT4_FILE_POS_BUG file.reset(); file.seek(0); stream.reset(); stream.seek(0); QDataStream binStream2(&file); binStream2.setVersion(QDataStream::Qt_4_3); binStream2.skipRawData(offset); readMetricNodeData(stream, binStream2); // readMetricNodeData(stream, binStream); } /** * Read the metric file */ void MetricFile::readLegacyNodeFileData(QFile& file, QTextStream& stream, QDataStream& binStream) throw (FileException) { // get starting position of data //const qint64 startOfMetricData = stream.pos(); //file.pos(); const qint64 startOfMetricData = this->getQTextStreamPosition(stream); int version = 0; // read first line to see if it is version 1 or later QString versionStr, versionNumberStr; readTagLine(stream, versionStr, versionNumberStr); if ((versionStr == "metric-version") || (versionStr == tagFileVersion)) { switch(versionNumberStr.toInt()) { case 1: version = 1; break; case 2: version = 2; break; default: throw FileException(filename, "Unknown version of metric file"); } } //printf("Metric File Version: %d\n", version); switch(version) { case 1: readFileVersion_1(stream, binStream); break; case 2: readFileVersion_2(file, stream, binStream); break; default: // set file position as data will now be read file.seek(startOfMetricData); stream.seek(startOfMetricData); readFileVersion_0(file, stream, binStream); break; } } /** * Allows files to do processing after a file is read. */ void MetricFile::postFileReadingProcessing() throw (FileException) { std::vector newArrays; std::vector arrayIndicesToRemove; const long numDataArrays = this->getNumberOfDataArrays(); for (long i = 0; i < numDataArrays; i++) { GiftiDataArray* gda = this->getDataArray(i); std::vector dims = gda->getDimensions(); if (dims.size() > 2) { throw FileException("data dimensions must be 2 or less"); } else if (dims.size() == 2) { if (dims[1] > 1 && dims[0] > 1) { // // Split the two dimensional array into single dim arrays // GiftiDataArray* twoDimArray = this->getDataArray(i); long numNewArrays = dims[1]; long numNodes = dims[0]; float* twoDimData = twoDimArray->getDataPointerFloat(); // // Dimensions for the new arrays // std::vector newDim; newDim.push_back(numNodes); newDim.push_back(1); for (long j = 0; j < numNewArrays; j++) { // // Create the new data arrays and fill them with the data // GiftiDataArray* gda = new GiftiDataArray(this, twoDimArray->getIntent(), twoDimArray->getDataType(), newDim, GiftiDataArray::ENCODING_INTERNAL_COMPRESSED_BASE64_BINARY); float* data = gda->getDataPointerFloat(); long twoDimDataOffset = numNodes * j; for (long m = 0; m < numNodes; m++) { data[m] = twoDimData[twoDimDataOffset + m]; } newArrays.push_back(gda); } arrayIndicesToRemove.push_back(i); } else if(dims[1] > 1 && dims[0] == 1) { // // Split the two dimensional array into single dim arrays // GiftiDataArray* twoDimArray = this->getDataArray(i); long numNewArrays = dims[0]; long numNodes = dims[1]; float* twoDimData = twoDimArray->getDataPointerFloat(); // // Dimensions for the new arrays // std::vector newDim; newDim.push_back(numNodes); newDim.push_back(1); for (long j = 0; j < numNewArrays; j++) { // // Create the new data arrays and fill them with the data // GiftiDataArray* gda = new GiftiDataArray(this, twoDimArray->getIntent(), twoDimArray->getDataType(), newDim, GiftiDataArray::ENCODING_INTERNAL_COMPRESSED_BASE64_BINARY); float* data = gda->getDataPointerFloat(); long twoDimDataOffset = numNodes * j; for (long m = 0; m < numNodes; m++) { data[m] = twoDimData[twoDimDataOffset + m]; } newArrays.push_back(gda); } arrayIndicesToRemove.push_back(i); } } } // // Remove arrays that were split up. // for (long i = static_cast(arrayIndicesToRemove.size() - 1); i >= 0; i--) { int arrayIndex = arrayIndicesToRemove[i]; this->removeDataArray(arrayIndex); } // // Add the new single dim arrays // for (unsigned long i = 0; i < newArrays.size(); i++) { this->addDataArray(newArrays[i]); int lastCol = this->getNumberOfColumns() - 1; this->setColumnName(lastCol, "#" + QString::number(lastCol)); } } /** * Write the metric file data */ void MetricFile::writeLegacyNodeFileData(QTextStream& stream, QDataStream& binStream) throw (FileException) { const int numberOfNodes = getNumberOfNodes(); const int numberOfColumns = getNumberOfColumns(); stream << tagFileVersion << " 2" << "\n"; //"metric-version 2\n"; stream << tagNumberOfNodes << " " << numberOfNodes << "\n"; stream << tagNumberOfColumns << " " << numberOfColumns << "\n"; stream << tagFileTitle << " " << fileTitle << "\n"; for (int j = 0; j < numberOfColumns; j++) { stream << tagColumnName << " " << j << " " << getColumnName(j) << "\n"; } for (int m = 0; m < numberOfColumns; m++) { stream << tagColumnComment << " " << m << " " << StringUtilities::setupCommentForStorage(getColumnComment(m)) << "\n"; } for (int k = 0; k < numberOfColumns; k++) { stream << tagColumnStudyMetaData << " " << k << " " << getColumnStudyMetaDataLinkSet(k).getLinkSetAsCodedText().toAscii().constData() << "\n"; } for (int k = 0; k < numberOfColumns; k++) { float neg, pos; getColumnColorMappingMinMax(k, neg, pos); stream << tagColumnColorMapping << " " << k << " " << neg << " " << pos << "\n"; } for (int k = 0; k < numberOfColumns; k++) { float neg, pos; getColumnThresholding(k, neg, pos); stream << tagColumnThreshold << " " << k << " " << neg << " " << pos << "\n"; } for (int k = 0; k < numberOfColumns; k++) { float neg, pos; getColumnAverageThresholding(k, neg, pos); stream << tagColumnAverageThreshold << " " << k << " " << neg << " " << pos << "\n"; } stream << tagBeginData << "\n"; if (numberOfColumns > 0) { float** dataPtr = new float*[numberOfColumns]; for (int i = 0; i < numberOfColumns; i++) { dataPtr[i] = dataArrays[i]->getDataPointerFloat(); } switch (getFileWriteType()) { case FILE_FORMAT_ASCII: for (int i = 0; i < numberOfNodes; i++) { stream << i; for (int j = 0; j < numberOfColumns; j++) { stream << " " << dataPtr[j][i]; } stream << "\n"; } break; case FILE_FORMAT_BINARY: #ifdef QT4_FILE_POS_BUG setBinaryFilePosQT4Bug(); #else // QT4_FILE_POS_BUG // // still a bug in QT 4.2.2 // setBinaryFilePosQT4Bug(); #endif // QT4_FILE_POS_BUG for (int i = 0; i < numberOfNodes; i++) { for (int j = 0; j < numberOfColumns; j++) { binStream << dataPtr[j][i]; } } break; case FILE_FORMAT_XML: throw FileException(filename, "Writing in XML format not supported."); break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Writing XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Writing in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Comma Separated Value File Format not supported."); break; } delete[] dataPtr; } } /** * Export to a free surfer functional file. */ void MetricFile::exportFreeSurferAsciiFunctionalFile(const int columnNumber, const QString& filename) throw (FileException) { if ((columnNumber >= 0) && (columnNumber < getNumberOfColumns())) { FreeSurferFunctionalFile fsff; const int numNodes = getNumberOfNodes(); //fsff.setNumberOfFunctionalItems(numNodes); for (int i = 0; i < numNodes; i++) { const float metric = getValue(i, columnNumber); if (metric != 0.0) { fsff.addFunctionalData(i, metric); } } fsff.writeFile(filename); } else { throw FileException(filename, "Invalid column number for export"); } } /** * Import free surfer functional as metric. */ void MetricFile::importFreeSurferFunctionalFile(const int numNodes, const QString& filename, const AbstractFile::FILE_FORMAT fileFormat) throw (FileException) { if (numNodes == 0) { throw FileException(filename, "Number of nodes must be set prior to importing a \n" "FreeSurfer functional file. This is usually\n" "accomplished by importing an \"orig\" surface prior\n" "to importing functional data."); } // // Add a column to this surface shape file // if (getNumberOfColumns() == 0) { setNumberOfNodesAndColumns(numNodes, 1); } else { addColumns(1); } const int columnNumber = getNumberOfColumns() - 1; // // Set the name of the column to the name of the curvature file // setColumnName(columnNumber, FileUtilities::basename(filename)); setModified(); // // Read in the free surfer functional file // FreeSurferFunctionalFile fsff; fsff.setFileReadType(fileFormat); fsff.readFile(filename); // // Read in functional data // const int numItems = fsff.getNumberOfFunctionalItems(); int nodeNumber; float value; for (int i = 0; i < numItems; i++) { fsff.getFunctionalData(i, nodeNumber, value); if (nodeNumber >= numNodes) { throw FileException(filename, "Functional data found for node with index " "larger than there are nodes in the surface."); } setValue(nodeNumber, columnNumber, value); } appendToFileComment(" Imported from "); appendToFileComment(FileUtilities::basename(filename)); } /** * compute and return a metric file that is a Z-map of "this" metric file * Z-map is (Xi - Mean)/Dev for all elements in each row. */ MetricFile* MetricFile::computeStatisticalZMap() const throw (FileException) { const int numberOfNodes = getNumberOfNodes(); const int numberOfColumns = getNumberOfColumns(); if ((numberOfNodes <= 0) || (numberOfColumns <= 0)) { throw FileException("Input Metric File is isEmpty."); } if (numberOfColumns == 1) { throw FileException("Input Metric File has only one column."); } // // Create the new metric file by making a copy of the existing metric file // MetricFile* metricOut = new MetricFile(*this); // // Process each row in the metric file // float* values = new float[numberOfColumns]; for (int i = 0; i < numberOfNodes; i++) { // // Convert to Z-score // getAllColumnValuesForNode(i, values); StatisticConvertToZScore zAlg; StatisticDataGroup sdg(values, numberOfColumns, StatisticDataGroup::DATA_STORAGE_MODE_POINT); try { zAlg.execute(); } catch (StatisticException&) { } for (int m = 0; m < numberOfColumns; m++) { zAlg.convertToZScore(values[m]); } metricOut->setAllColumnValuesForNode(i, values); } delete[] values; // // Update the column names and color mapping // for (int j = 0; j < numberOfColumns; j++) { QString name("Z-map - "); name.append(getColumnName(j)); metricOut->setColumnName(j, name); metricOut->setColumnColorMappingMinMax(j, -5.0, 5.0); } metricOut->appendToFileComment("\nZ-map of "); metricOut->appendToFileComment(FileUtilities::basename(getFileName())); metricOut->appendToFileComment("\n"); return metricOut; } /** * compute and return a metric file that has each column fit to a * normal distribution. */ MetricFile* MetricFile::computeNormalization(const float mean, const float standardDeviation) const throw (FileException) { const int numberOfNodes = getNumberOfNodes(); const int numberOfColumns = getNumberOfColumns(); if ((numberOfNodes <= 0) || (numberOfColumns <= 0)) { throw FileException("Input Metric File is isEmpty."); } // // Create the new metric file by making a copy of the existing metric file // MetricFile* metricOut = new MetricFile(*this); // // For column comment // std::ostringstream str; str << "Mean: " << mean << " Std Dev: " << standardDeviation; // // Process each column in the metric file // for (int j = 0; j < numberOfColumns; j++) { QString colName("Normalized - "); colName.append(metricOut->getColumnName(j)); metricOut->remapColumnToNormalDistribution(j, j, colName, mean, standardDeviation); } metricOut->appendToFileComment("\nNormalization of "); metricOut->appendToFileComment(FileUtilities::basename(getFileName())); metricOut->appendToFileComment("\n"); return metricOut; } /** * compute and return a metric file that computes T-Values of "this" metric file * T-Value = (mean - constant) / (sample-dev / sqrt(N)). */ MetricFile* MetricFile::computeTValues(const float constant, const TopologyFile* varianceSmoothingTopologyFile, const int varianceSmoothingIterations, const float varianceSmoothingStrength) const throw (FileException) { // // Check input metric file // const int numNodes = getNumberOfNodes(); if (numNodes <= 0) { throw FileException("Metric file contains no nodes."); } const int numCols = getNumberOfColumns(); if (numCols < 2) { throw FileException("Metric file contains less than two columns."); } // // Create output metric file // MetricFile* mf = new MetricFile; mf->setNumberOfNodesAndColumns(numNodes, 1); mf->setColumnName(0, "T-Values"); mf->setFileComment("T-Value from " + getFileName()); const float squareRootN = std::sqrt((float)numCols); // // Compute mean and deviation for each node // float* mean = new float[numNodes]; float* deviation = new float[numNodes]; float* values = new float[numCols]; for (int i = 0; i < numNodes; i++) { getAllColumnValuesForNode(i, values); StatisticDataGroup sdg(values, numCols, StatisticDataGroup::DATA_STORAGE_MODE_POINT); StatisticMeanAndDeviation smad; smad.addDataGroup(&sdg); try { smad.execute(); } catch (StatisticException&) { } mean[i] = smad.getMean(); deviation[i] = smad.getPopulationSampleStandardDeviation(); } delete[] values; values = NULL; // // Should variance smoothing be done ? // if (varianceSmoothingIterations > 0) { // // Do variance smoothing // Note: variance is the square of deviation // MetricFile m; m.setNumberOfNodesAndColumns(numNodes, 1); for (int i = 0; i < numNodes; i++) { const float variance = deviation[i]*deviation[i]; m.setValue(i, 0, variance); } m.smoothAverageNeighbors(0, 0, "", varianceSmoothingStrength, varianceSmoothingIterations, varianceSmoothingTopologyFile); for (int i = 0; i < numNodes; i++) { const float variance = m.getValue(i, 0); deviation[i] = std::sqrt(variance); } } // // Process each node // for (int i = 0; i < numNodes; i++) { // // Compute the T-Value // const float denom = deviation[i] / squareRootN; float tValue = mean[i] - constant; if (denom != 0.0) { tValue /= denom; } // // Store the T-Value // mf->setValue(i, 0, tValue); } delete[] mean; delete[] deviation; return mf; } /** * compute and return a metric file that contains permuted T-Values of "this" metric file * permutation is perfomred by genernating a random plus or minus one for each column * and multiplying the row by +/-1 and then computing the T-Value. */ MetricFile* MetricFile::computePermutedTValues(const float constant, const int iterations, const TopologyFile* topologyFile, const int varianceSmoothingIterations, const float varianceSmoothingStrength) const throw (FileException) { // // Check input metric file // const int numNodes = getNumberOfNodes(); if (numNodes <= 0) { throw FileException("Metric file contains no nodes."); } const int numCols = getNumberOfColumns(); if (numCols < 2) { throw FileException("Metric file contains less than two columns."); } if (iterations <= 0) { throw FileException("Number of iteration is less than or equal to zero."); } // // Create output metric file // MetricFile* mf = new MetricFile; mf->setNumberOfNodesAndColumns(numNodes, iterations); mf->setColumnName(0, "Permuted T-Values"); mf->setFileComment("Sign Flipped Permuted T-Values from " + getFileName()); float* signFlips = new float[numCols]; float* values = new float[numCols]; float* oneColumn = new float[numNodes]; // // For the specified number of iterations // for (int iter = 0; iter < iterations; iter++) { // // Generate sign flips by randomly generating an array of plus and minus ones // for (int j = 0; j < numCols; j++) { signFlips[j] = 1.0; } StatisticDataGroup sdg(signFlips, numCols, StatisticDataGroup::DATA_STORAGE_MODE_POINT); StatisticPermutation permuteSigns(StatisticPermutation::PERMUTATION_METHOD_RANDOM_SIGN_FLIP); permuteSigns.addDataGroup(&sdg); try { permuteSigns.execute(); } catch (StatisticException& e) { throw FileException(e); } const StatisticDataGroup* flipOutDataGroup = permuteSigns.getOutputData(); for (int j = 0; j < numCols; j++) { signFlips[j] = flipOutDataGroup->getData(j); } /* // // generate the permutation sign flips // for (int j = 0; j < numCols; j++) { signFlips[j] = 1.0; if (MathUtilities::randomInteger(-1000, 1000) < 0) { signFlips[j] = -1.0; } } */ // // Copy this metric file // MetricFile metricCopy(*this); // // Get the value for all nodes from the copy metric file and apply sign flips // for (int k = 0; k < numNodes; k++) { metricCopy.getAllColumnValuesForNode(k, values); for (int j = 0; j < numCols; j++) { values[j] *= signFlips[j]; } metricCopy.setAllColumnValuesForNode(k, values); } // // Compute T-Values // MetricFile* tValuesMetric = metricCopy.computeTValues(constant, topologyFile, varianceSmoothingIterations, varianceSmoothingStrength); // // Place the T-Values into the output permuted metric file // tValuesMetric->getColumnForAllNodes(0, oneColumn); mf->setColumnForAllNodes(iter, oneColumn); delete tValuesMetric; } delete[] signFlips; delete[] values; delete[] oneColumn; return mf; } /** * compute and return a Levene map for the rows of the metric files. */ MetricFile* MetricFile::computeStatisticalLeveneMap(const std::vector& inputFiles) throw (FileException) { // // Need at least two files // const int numFiles = static_cast(inputFiles.size()); if (numFiles < 2) { throw FileException("A Levene Map requires at least two metric files"); } // // Make sure all files have same number of nodes // const int numNodes = inputFiles[0]->getNumberOfNodes(); for (int i = 0; i < numFiles; i++) { if (inputFiles[i]->getNumberOfNodes() != numNodes) { throw FileException("Not all files sent to Levene's test have the same number of nodes."); } } // // Verify that at least one file has three columns // bool haveThreeColumns = false; for (int i = 0; i < numFiles; i++) { if (inputFiles[i]->getNumberOfColumns() <= 0) { throw FileException("A file passed to Levene test has no columns (data)."); } if (inputFiles[i]->getNumberOfColumns() >= 3) { haveThreeColumns = true; break; } } if (haveThreeColumns == false) { throw FileException("A Levene Map requires at least one file with three columns of data."); } // // Create the output file // int numCols = 0; const int fCol = numCols++; const int dofNumCol = numCols++; const int dofDenCol = numCols++; const int pCol = numCols++; MetricFile* outputMetricFile = new MetricFile; outputMetricFile->setNumberOfNodesAndColumns(numNodes, numCols); outputMetricFile->setColumnName(fCol, "Levene-F"); outputMetricFile->setColumnName(dofNumCol, "DOF - numerator"); outputMetricFile->setColumnName(dofDenCol, "DOF - denominator"); outputMetricFile->setColumnName(pCol, "P-Value"); // // Perform levene's test on each node // StatisticDataGroup **dataGroups= new StatisticDataGroup *[numFiles]; for (int i = 0; i < numNodes; i++) { StatisticLeveneVarianceEquality levene; for (int j = 0; j < numFiles; j++) { const MetricFile* mf = inputFiles[j]; std::vector* metricData = new std::vector; mf->getAllColumnValuesForNode(i, *metricData); dataGroups[j] = new StatisticDataGroup(metricData, StatisticDataGroup::DATA_STORAGE_MODE_TAKE_OWNERSHIP); levene.addDataGroup(dataGroups[j], true); // 2nd arg true => take possession and delete when done } // // Peform the test // try { levene.execute(); outputMetricFile->setValue(i, fCol, levene.getLeveneF()); outputMetricFile->setValue(i, dofNumCol, levene.getDegreesOfFreedom1()); outputMetricFile->setValue(i, dofDenCol, levene.getDegreesOfFreedom2()); outputMetricFile->setValue(i, pCol, levene.getPValue()); } catch (StatisticException& e) { delete outputMetricFile; throw FileException(e); } } delete dataGroups; // // Set the min/max values for the columns // for (int i = 0; i < numCols; i++) { float minVal, maxVal; outputMetricFile->getDataColumnMinMax(i, minVal, maxVal); outputMetricFile->setColumnColorMappingMinMax(i, minVal, maxVal); } return outputMetricFile; } /** * compute and return a T-map for the rows of two metric files. */ MetricFile* MetricFile::computeStatisticalTMap(const MetricFile* m1, const MetricFile* m2, const TopologyFile* varianceSmoothingTopologyFile, const int varianceSmoothingIterations, const float varianceSmoothingStrength, const bool poolTheVariance, const float falseDiscoveryRateQ, const bool doFalseDiscoveryRateFlag, const bool doDegreesOfFreedomFlag, const bool doPValuesFlagIn) throw (FileException) { const bool doPValuesFlag = (doPValuesFlagIn || doFalseDiscoveryRateFlag); const int m1NumberOfNodes = m1->getNumberOfNodes(); const int m1NumberOfColumns = m1->getNumberOfColumns(); const int m2NumberOfNodes = m2->getNumberOfNodes(); const int m2NumberOfColumns = m2->getNumberOfColumns(); if (m1 == NULL) { throw FileException("First Input File is isEmpty (NULL)."); } if (m2 == NULL) { throw FileException("Second Input File is isEmpty (NULL)."); } if ((m1NumberOfNodes <= 0) || (m1NumberOfColumns <= 0)) { throw FileException("First Input File is isEmpty."); } if ((m2NumberOfNodes <= 0) || (m2NumberOfColumns <= 0)) { throw FileException("Second Input File is isEmpty."); } if (m1NumberOfNodes != m2NumberOfNodes) { throw FileException("Input files have different number of nodes."); } // // Initialize the output metric file // int numColumns = 0; const int meanGroup1Column = numColumns++; const int meanGroup2Column = numColumns++; const int tStatColumn = numColumns++; int dofColumn = -1; if (doDegreesOfFreedomFlag) { dofColumn = numColumns; numColumns++; } int pValueColumn = -1; if (doPValuesFlag) { pValueColumn = numColumns; numColumns++; } // // If doing P-Value also compute false discovery rates // int fdrC1Column = -1; int fdrCSumColumn = -1; if (doFalseDiscoveryRateFlag) { fdrC1Column = numColumns; numColumns++; fdrCSumColumn = numColumns; numColumns++; } MetricFile* outputMetric = new MetricFile; outputMetric->setNumberOfNodesAndColumns(m1NumberOfNodes, numColumns); std::ostringstream str; str << "T-map of the metric files " << FileUtilities::basename(m1->getFileName()).toAscii().constData() << " and " << FileUtilities::basename(m2->getFileName()).toAscii().constData(); outputMetric->setFileComment(str.str().c_str()); // // Set the output metric column names // str.str(""); str << "Mean - " << FileUtilities::basename(m1->getFileName()).toAscii().constData(); outputMetric->setColumnName(meanGroup1Column, str.str().c_str()); outputMetric->setColumnColorMappingMinMax(meanGroup1Column, -30.0, 10.0); str.str(""); str << "Mean - " << FileUtilities::basename(m2->getFileName()).toAscii().constData(); outputMetric->setColumnName(meanGroup2Column, str.str().c_str()); outputMetric->setColumnColorMappingMinMax(meanGroup2Column, -30.0, 10.0); outputMetric->setColumnName(tStatColumn, "T-Map"); outputMetric->setColumnColorMappingMinMax(tStatColumn, -5.0, 5.0); float dofMax = 0.0; if (dofColumn >= 0) { outputMetric->setColumnName(dofColumn, "Degrees of Freedom"); outputMetric->setColumnColorMappingMinMax(dofColumn, 0.0, 20.0); } float pValueMax = 0.0; if (pValueColumn >= 0) { outputMetric->setColumnName(pValueColumn, "P-Value"); outputMetric->setColumnColorMappingMinMax(pValueColumn, 0.0, 20.0); } if (fdrC1Column >= 0) { outputMetric->setColumnName(fdrC1Column, "P Thresh->FDR C=1"); outputMetric->setColumnColorMappingMinMax(fdrC1Column, 0.0, 20.0); } if (fdrCSumColumn >= 0) { outputMetric->setColumnName(fdrCSumColumn, "P Thresh->FDR C-Sum"); outputMetric->setColumnColorMappingMinMax(fdrCSumColumn, 0.0, 20.0); } // // Compute mean and variance for each node in first file // float* values1 = new float[m1NumberOfColumns]; float* mean1 = new float[m1NumberOfNodes]; float* var1 = new float[m1NumberOfNodes]; for (int i = 0; i < m1NumberOfNodes; i++) { m1->getAllColumnValuesForNode(i, values1); StatisticDataGroup sdg(values1, m1NumberOfColumns, StatisticDataGroup::DATA_STORAGE_MODE_POINT); StatisticMeanAndDeviation smad; smad.addDataGroup(&sdg); try { smad.execute(); } catch (StatisticException&) { } mean1[i] = smad.getMean(); float dev = smad.getPopulationSampleStandardDeviation(); var1[i] = dev*dev; } delete[] values1; values1 = NULL; // // Compute mean and variance for each node in second file // float* values2 = new float[m2NumberOfColumns]; float* mean2 = new float[m2NumberOfNodes]; float* var2 = new float[m2NumberOfNodes]; for (int i = 0; i < m2NumberOfNodes; i++) { m2->getAllColumnValuesForNode(i, values2); StatisticDataGroup sdg(values2, m2NumberOfColumns, StatisticDataGroup::DATA_STORAGE_MODE_POINT); StatisticMeanAndDeviation smad; smad.addDataGroup(&sdg); try { smad.execute(); } catch (StatisticException&) { } mean2[i] = smad.getMean(); float dev = smad.getPopulationSampleStandardDeviation(); var2[i] = dev*dev; } delete[] values2; values2 = NULL; // // Should variance smoothing be done ? // if (varianceSmoothingIterations > 0) { // // Variance smooth 1st file // MetricFile m; m.setNumberOfNodesAndColumns(m1NumberOfNodes, 1); for (int i = 0; i < m1NumberOfNodes; i++) { m.setValue(i, 0, var1[i]); } m.smoothAverageNeighbors(0, 0, "", varianceSmoothingStrength, varianceSmoothingIterations, varianceSmoothingTopologyFile); for (int i = 0; i < m1NumberOfNodes; i++) { var1[i] = m.getValue(i, 0); } // // Variance smooth 2nd file // m.setNumberOfNodesAndColumns(m2NumberOfNodes, 1); for (int i = 0; i < m2NumberOfNodes; i++) { m.setValue(i, 0, var2[i]); } m.smoothAverageNeighbors(0, 0, "", varianceSmoothingStrength, varianceSmoothingIterations, varianceSmoothingTopologyFile); for (int i = 0; i < m2NumberOfNodes; i++) { var2[i] = m.getValue(i, 0); } } // // Used for pooled variance computation // float pooledOneOverSqrtN1N2 = std::sqrt((1.0 / m1NumberOfColumns) + (1.0 / m2NumberOfColumns)); // // Compute the t-statistic for each node // for (int i = 0; i < m1NumberOfNodes; i++) { // // Denominator of t-statistic // float denom = 1.0; if (poolTheVariance) { // // Pooled variance // const float s2Pooled = ((m1NumberOfColumns - 1) * var1[i] + (m2NumberOfColumns - 1) * var2[i]) / (m1NumberOfColumns + m2NumberOfColumns - 2); denom = std::sqrt(s2Pooled) * pooledOneOverSqrtN1N2; } else { // // Unpooled variance // denom = std::sqrt(((var1[i]) / static_cast(m1NumberOfColumns)) + ((var2[i]) / static_cast(m2NumberOfColumns))); } if (denom == 0.0) { denom = 1.0; } // // Return the t-statistic // const float tStat = (mean1[i] - mean2[i]) / denom; outputMetric->setValue(i, meanGroup1Column, mean1[i]); outputMetric->setValue(i, meanGroup2Column, mean2[i]); outputMetric->setValue(i, tStatColumn, tStat); // // Do degrees of freedom ? // if ((dofColumn >= 0) || (pValueColumn >= 0)) { const float num1 = m1NumberOfColumns; const float num2 = m2NumberOfColumns; const float num1M1 = num1 - 1.0; const float num2M1 = num2 - 1.0; float numerator = var1[i]/num1 + var2[i]/num2; numerator = numerator * numerator; float denom = (1.0 / num1M1) * (var1[i]/num1) * (var1[i]/num1) + (1.0 / num2M1) * (var2[i]/num2) * (var2[i]/num2); float dof = 0.0; if (denom != 0.0) { dof = static_cast(numerator / denom); dofMax = std::max(dofMax, dof); } if (dofColumn >= 0) { outputMetric->setValue(i, dofColumn, dof); } } } // // Do P-Value computation // if ((dofColumn >= 0) && (pValueColumn >= 0)) { // // Gen mean and degrees of freedom // std::vector tStats, dofs, pValues(m1NumberOfNodes, 0.0); outputMetric->getColumnForAllNodes(tStatColumn, tStats); outputMetric->getColumnForAllNodes(dofColumn, dofs); // // Create the data groups // StatisticDataGroup tStatGroup(&tStats, StatisticDataGroup::DATA_STORAGE_MODE_POINT); StatisticDataGroup dofGroup(&dofs, StatisticDataGroup::DATA_STORAGE_MODE_POINT); // // Create and execute the algorithm // StatisticGeneratePValue genP(StatisticGeneratePValue::INPUT_STATISTIC_T_TWO_TALE); genP.addDataGroup(&tStatGroup); genP.addDataGroup(&dofGroup); try { genP.execute(); // // Put the P-Values back into the metric file // const StatisticDataGroup* pValuesGroup = genP.getOutputDataGroupContainingPValues(); outputMetric->setColumnForAllNodes(pValueColumn, pValuesGroup->getPointerToData()); // // Set the maximum p value // for (int i = 0; i < m1NumberOfNodes; i++) { pValueMax = std::max(pValueMax, pValues[i]); } } catch (StatisticException& e) { const FileException fe(e); std::cout << "Generation of P-Values failed." << std::endl << " " << fe.whatQString().toAscii().constData() << std::endl; } } delete[] mean1; mean1 = NULL; delete[] var1; var1 = NULL; delete[] mean2; mean2 = NULL; delete[] var2; var2 = NULL; // // Set Degree of Freedom Max Value // if (dofColumn >= 0) { outputMetric->setColumnColorMappingMinMax(dofColumn, 0.0, dofMax); } // // Set P-Value Max // if (pValueColumn >= 0) { outputMetric->setColumnColorMappingMinMax(pValueColumn, 0.0, pValueMax); } // // Do False Discovery Rate ? // if (fdrC1Column >= 0) { // // get the P-Values // std::vector values; outputMetric->getColumnForAllNodes(pValueColumn, values); // // Determine the false discovery rate // StatisticFalseDiscoveryRate fdr(falseDiscoveryRateQ, StatisticFalseDiscoveryRate::C_CONSTANT_1); StatisticDataGroup sdg(&values, StatisticDataGroup::DATA_STORAGE_MODE_POINT); fdr.addDataGroup(&sdg); try { fdr.execute(); } catch (StatisticException& e) { throw FileException(e); } // // Set values above "p-cutoff" to -1 // const float pCutoff = fdr.getPCutoff(); const int numValues = static_cast(values.size()); for (int m = 0; m < numValues; m++) { if (values[m] > pCutoff) { values[m] = -1.0; } } // // place output into metric file // outputMetric->setColumnForAllNodes(fdrC1Column, values); // // Update color mapping min/max // float minValue, maxValue; outputMetric->getDataColumnMinMax(fdrC1Column, minValue, maxValue); outputMetric->setColumnColorMappingMinMax(fdrC1Column, 0.0, maxValue); } // // Do False Discovery Rate ? // if (fdrCSumColumn >= 0) { // // get the P-Values // std::vector values; outputMetric->getColumnForAllNodes(pValueColumn, values); // // Determine the false discovery rate // StatisticFalseDiscoveryRate fdr(falseDiscoveryRateQ, StatisticFalseDiscoveryRate::C_CONSTANT_SUMMATION); StatisticDataGroup sdg(&values, StatisticDataGroup::DATA_STORAGE_MODE_POINT); fdr.addDataGroup(&sdg); try { fdr.execute(); } catch (StatisticException& e) { throw FileException(e); } // // Set values above "p-cutoff" to -1 // const float pCutoff = fdr.getPCutoff(); const int numValues = static_cast(values.size()); for (int m = 0; m < numValues; m++) { if (values[m] > pCutoff) { values[m] = -1.0; } } // // place output into metric file // outputMetric->setColumnForAllNodes(fdrCSumColumn, values); // // Update color mapping min/max // float minValue, maxValue; outputMetric->getDataColumnMinMax(fdrCSumColumn, minValue, maxValue); outputMetric->setColumnColorMappingMinMax(fdrCSumColumn, 0.0, maxValue); } return outputMetric; } /** * compute correlation coefficient map. */ MetricFile* MetricFile::computeMultipleCorrelationCoefficientMap(const MetricFile* dependentMetricFile, const std::vector& independentMetricFiles) throw (FileException) { // // Check inputs // if (dependentMetricFile == NULL) { throw FileException("Dependent metric file is NULL (invalid)."); } const int numIndepMetricFiles = static_cast(independentMetricFiles.size()); if (numIndepMetricFiles <= 0) { throw FileException("No Independent metric files."); } const int numNodes = dependentMetricFile->getNumberOfNodes(); if (numNodes <= 0) { throw FileException("Dependent metric file has an invalid number of nodes."); } const int numCols = dependentMetricFile->getNumberOfColumns(); if (numCols <= 0) { throw FileException("Dependent metric file has an invalid number of columns."); } for (int i = 0; i < numIndepMetricFiles; i++) { if (numNodes != independentMetricFiles[i]->getNumberOfNodes()) { const QString msg("Independent metric file " + QString::number(i + 1) + " has a different number of nodes than dependent metric file."); throw FileException(msg); } else if (numCols != independentMetricFiles[i]->getNumberOfColumns()) { const QString msg("Independent metric file " + QString::number(i + 1) + " has a different number of columns than dependent metric file."); throw FileException(msg); } } // // Create output metric file // int colCtr = 0; const int r2ColumnNumber = colCtr++; const int rColumnNumber = colCtr++; const int fColumnNumber = colCtr++; const int pColumnNumber = colCtr++; const int dofNumeratorColumnNumber = colCtr++; const int dofDenominatorColumnNumber = colCtr++; const int numOutputColumns = colCtr; MetricFile* metricOut = new MetricFile(numNodes, numOutputColumns); if (r2ColumnNumber >= 0) { metricOut->setColumnName(r2ColumnNumber, "r2 - Coefficient of Multiple Determination"); } if (rColumnNumber >= 0) { metricOut->setColumnName(rColumnNumber, "r - Correlation Coefficient"); } if (fColumnNumber >= 0) { metricOut->setColumnName(fColumnNumber, "F-Value"); } if (pColumnNumber >= 0) { metricOut->setColumnName(pColumnNumber, "P-Value"); } if (dofNumeratorColumnNumber >= 0) { metricOut->setColumnName(dofNumeratorColumnNumber, "DOF (numerator)- Degrees of Freedom"); } if (dofDenominatorColumnNumber >= 0) { metricOut->setColumnName(dofDenominatorColumnNumber, "DOF (denomenator)- Degrees of Freedom"); } // // Compute correlation coefficients // float* dependentData = new float[numCols]; std::vector independentData(numIndepMetricFiles); for (int m = 0; m < numIndepMetricFiles; m++) { independentData[m] = new float[numCols]; } for (int i = 0; i < numNodes; i++) { for (int j = 0; j < numCols; j++) { dependentData[j] = dependentMetricFile->getValue(i, j); } for (int m = 0; m < numIndepMetricFiles; m++) { float* d = independentData[m]; for (int j = 0; j < numCols; j++) { d[j] = independentMetricFiles[m]->getValue(i, j); } } // // Create multiple regression object and load data // StatisticMultipleRegression smr; smr.setDependentDataArray(dependentData, numCols); smr.setNumberOfIndependentDataGroups(numIndepMetricFiles); for (int m = 0; m < numIndepMetricFiles; m++) { smr.setIndependentDataArray(m, independentData[m], numCols); } // // Execute multiple regression // try { smr.execute(); } catch (StatisticException& e) { throw FileException(e); } float SSTO, SSE, SSR, MSR, MSE, F, pValue, R2; int regressionDOF, errorDOF, totalDOF; smr.getAnovaParameters(SSTO, SSE, SSR, MSR, MSE, F, pValue, R2, regressionDOF, errorDOF, totalDOF); if (r2ColumnNumber >= 0) { metricOut->setValue(i, r2ColumnNumber, R2); } if (rColumnNumber >= 0) { metricOut->setValue(i, rColumnNumber, std::sqrt(R2)); } if (fColumnNumber >= 0) { metricOut->setValue(i, fColumnNumber, F); } if (pColumnNumber >= 0) { metricOut->setValue(i, pColumnNumber, pValue); } if (dofNumeratorColumnNumber >= 0) { metricOut->setValue(i, dofNumeratorColumnNumber, regressionDOF); } if (dofDenominatorColumnNumber >= 0) { metricOut->setValue(i, dofDenominatorColumnNumber, errorDOF); } } delete[] dependentData; dependentData = NULL; for (int m = 0; m < numIndepMetricFiles; m++) { delete[] independentData[m]; independentData[m] = NULL; } return metricOut; } /** * compute correlation coefficient map. */ MetricFile* MetricFile::computeCorrelationCoefficientMap(const MetricFile* m1, const MetricFile* m2) throw (FileException) { // // Check inputs // if (m1 == NULL) { throw FileException("First metric file is NULL (invalid)."); } if (m2 == NULL) { throw FileException("Second metric file is NULL (invalid)."); } const int numNodes = m1->getNumberOfNodes(); if (numNodes <= 0) { throw FileException("First metric file has an invalid number of nodes."); } if (numNodes != m2->getNumberOfNodes()) { throw FileException("Input metric files have a different number of nodes."); } const int numCols = m1->getNumberOfColumns(); if (numCols <= 0) { throw FileException("First metric file has an invalid number of columns."); } if (numCols != m2->getNumberOfColumns()) { throw FileException("Input metric files have a different number of columns."); } // // Create output metric file // int colCtr = 0; const int rColumnNumber = colCtr++; const int tColumnNumber = colCtr++; const int pColumnNumber = colCtr++; const int dofColumnNumber = colCtr++; const int numOutputColumns = colCtr; MetricFile* metricOut = new MetricFile(numNodes, numOutputColumns); if (rColumnNumber >= 0) { metricOut->setColumnName(rColumnNumber, "r - Correlation Coefficient"); } if (tColumnNumber >= 0) { metricOut->setColumnName(tColumnNumber, "T-Value"); } if (pColumnNumber >= 0) { metricOut->setColumnName(pColumnNumber, "P-Value"); } if (dofColumnNumber >= 0) { metricOut->setColumnName(dofColumnNumber, "DOF - Degrees of Freedom"); } // // Compute correlation coefficients // float* data1 = new float[numCols]; float* data2 = new float[numCols]; for (int i = 0; i < numNodes; i++) { for (int j = 0; j < numCols; j++) { data1[j] = m1->getValue(i, j); data2[j] = m2->getValue(i, j); } StatisticDataGroup sdg1(data1, numCols, StatisticDataGroup::DATA_STORAGE_MODE_POINT); StatisticDataGroup sdg2(data2, numCols, StatisticDataGroup::DATA_STORAGE_MODE_POINT); StatisticCorrelationCoefficient scc; scc.addDataGroup(&sdg1); scc.addDataGroup(&sdg2); try { scc.execute(); } catch (StatisticException& e) { throw FileException(e); } if (rColumnNumber >= 0) { metricOut->setValue(i, rColumnNumber, scc.getCorrelationCoefficientR()); } if (tColumnNumber >= 0) { metricOut->setValue(i, tColumnNumber, scc.getTValue()); } if (pColumnNumber >= 0) { metricOut->setValue(i, pColumnNumber, scc.getPValue()); } if (dofColumnNumber >= 0) { metricOut->setValue(i, dofColumnNumber, scc.getDegreesOfFreedom()); } } delete[] data1; data1 = NULL; delete[] data2; data2 = NULL; return metricOut; } /** * subract the average of both files form each file (output files are replaced) */ void MetricFile::subtractMeanFromRowElements(const MetricFile* inputFile1, const MetricFile* inputFile2, MetricFile* outputFile1, MetricFile* outputFile2) throw (FileException) { if (inputFile1 == NULL) { throw FileException("Input File 1 is invalid (NULL)."); } if (inputFile2 == NULL) { throw FileException("Input File 2 is invalid (NULL)."); } if (outputFile1 == NULL) { throw FileException("Output File 1 is invalid (NULL)."); } if (outputFile2 == NULL) { throw FileException("Output File 2 is invalid (NULL)."); } if ((inputFile1->getNumberOfNodes() <= 0) || (inputFile1->getNumberOfColumns() <= 0)) { throw FileException("Input File 1 is isEmpty."); } if ((inputFile2->getNumberOfNodes() <= 0) || (inputFile2->getNumberOfColumns() <= 0)) { throw FileException("Input File 2 is isEmpty."); } if (inputFile1->getNumberOfNodes() != inputFile2->getNumberOfNodes()) { throw FileException("Input Files have a different number of nodes."); } const int numNodes = inputFile1->getNumberOfNodes(); const int col1 = inputFile1->getNumberOfColumns(); const int col2 = inputFile2->getNumberOfColumns(); const float totalColumns = col1 + col2; // // Copy the metric files // *outputFile1 = *inputFile1; *outputFile2 = *inputFile2; // // Process each row in the metric file // for (int i = 0; i < numNodes; i++) { // // Determine mean // float mean = 0.0; for (int j = 0; j < col1; j++) { mean += outputFile1->getValue(i, j); } for (int j = 0; j < col2; j++) { mean += outputFile2->getValue(i, j); } mean /= totalColumns; // // Subtract mean from each element // for (int j = 0; j < col1; j++) { outputFile1->setValue(i, j, outputFile1->getValue(i, j) - mean); } for (int j = 0; j < col2; j++) { outputFile2->setValue(i, j, outputFile2->getValue(i, j) - mean); } } std::ostringstream commentStr; commentStr << "\nSubtracted group average of " << FileUtilities::basename(inputFile1->getFileName()).toAscii().constData() << "\nand" << FileUtilities::basename(inputFile2->getFileName()).toAscii().constData() << ".\n"; // // Update the column names and color mapping // for (int j = 0; j < col1; j++) { QString name("Avg-subtracted - "); name.append(outputFile1->getColumnName(j)); outputFile1->setColumnName(j, name); outputFile1->setColumnColorMappingMinMax(j, -5.0, 5.0); QString s(commentStr.str().c_str()); s.append(outputFile1->getColumnComment(j)); outputFile1->setColumnComment(j, s); } for (int j = 0; j < col2; j++) { QString name("Avg-subtracted - "); name.append(outputFile2->getColumnName(j)); outputFile2->setColumnName(j, name); outputFile2->setColumnColorMappingMinMax(j, -5.0, 5.0); QString s(commentStr.str().c_str()); s.append(outputFile2->getColumnComment(j)); outputFile2->setColumnComment(j, s); } outputFile1->appendToFileComment(commentStr.str().c_str()); outputFile2->appendToFileComment(commentStr.str().c_str()); } /** * compute shuffled cross correlation maps. */ MetricFile* MetricFile::computeShuffledCrossCorrelationsMap(const int numberOfRepetitions) const throw (FileException) { if (empty()) { throw FileException("Metric file contains no data."); } if (getNumberOfColumns() < 2) { throw FileException("Mmetric file must have at least two columns."); } if (numberOfRepetitions <= 0) { throw FileException("Number of repetitions is less than or equal to zero."); } const int numberOfNodes = getNumberOfNodes(); const int numberOfColumns = getNumberOfColumns(); // // Create a new metric file with the number of columns beign the number of repetitions // MetricFile* metricOut = new MetricFile; metricOut->setNumberOfNodesAndColumns(numberOfNodes, numberOfRepetitions); metricOut->appendToFileComment("Shuffled cross-correlation maps of: "); metricOut->appendToFileComment(getFileComment()); // // Each column is the multiplication of two randomly selected columns of the input metric // for (int j = 0; j < numberOfRepetitions; j++) { // // allow other events to process // AbstractFile::allowEventsToProcess(); // // Randomly select the columns // const int col1 = StatisticRandomNumber::randomInteger(0, numberOfColumns - 1); int col2 = col1; while (col1 == col2) { col2 = StatisticRandomNumber::randomInteger(0, numberOfColumns - 1); } // // Multiply the two columns // for (int i = 0; i < numberOfNodes; i++) { metricOut->setValue(i, j, getValue(i, col1) * getValue(i, col2)); } // // set the column comment // std::ostringstream str; str << "Column " << getColumnName(col1).toAscii().constData() << " * " << " Column " << getColumnName(col2).toAscii().constData(); metricOut->setColumnName(j, str.str().c_str()); str << " from " << FileUtilities::basename(getFileName()).toAscii().constData(); metricOut->setColumnComment(j, str.str().c_str()); // // Set color mapping // metricOut->setColumnColorMappingMinMax(j, -16.0, 16.0); } return metricOut; } /** * shuffle the values amongst group of input metric files and place * into the output files which must already be allocated. */ void MetricFile::shuffle(const std::vector& metricFilesIn, std::vector& metricFilesOut) throw (FileException) { // // Check for input files // const int numFiles = static_cast(metricFilesIn.size()); if (numFiles <= 0) { throw FileException("No input metric files to shuffle."); } if (static_cast(metricFilesOut.size()) != numFiles) { throw FileException("Number of input metric files different than number of output metric files."); } // // Check for valid files and count total columns // const int numNodes = metricFilesIn[0]->getNumberOfNodes(); int totalColumns = 0; for (int i = 0; i < numFiles; i++) { const MetricFile* mf = metricFilesIn[i]; if (mf->empty()) { const QString msg("Metric file " + FileUtilities::basename(mf->getFileName()) + " contains no data."); throw FileException(msg); } if (mf->getNumberOfNodes() != numNodes) { const QString msg("Metric files " + FileUtilities::basename(mf->getFileName()) + " and " + FileUtilities::basename(metricFilesIn[0]->getFileName()) + " contains a different number of nodes."); throw FileException(msg); } if ((mf->getNumberOfNodes() != metricFilesOut[i]->getNumberOfNodes()) || (mf->getNumberOfColumns() != metricFilesOut[i]->getNumberOfColumns())) { const QString msg("Input Metric File " + QString::number(i) + " does not match its corresponding output metric file" + " in number of nodes and/or columns."); throw FileException(msg); } totalColumns += mf->getNumberOfColumns(); } // // Create shuffled columns' indices and randomly shuffle them // std::vector columnsShuffledFloat(totalColumns); for (int i = 0; i < totalColumns; i++) { columnsShuffledFloat[i] = i; } StatisticDataGroup sdg(&columnsShuffledFloat, StatisticDataGroup::DATA_STORAGE_MODE_POINT); StatisticPermutation perm(StatisticPermutation::PERMUTATION_METHOD_RANDOM_ORDER); perm.addDataGroup(&sdg); try { perm.execute(); } catch (StatisticException& e) { throw FileException(e); } const StatisticDataGroup* permOut = perm.getOutputData(); if (permOut->getNumberOfData() != totalColumns) { throw FileException("Program error: StatisticPermutation return wrong number of values."); } int* columnsShuffled = new int[totalColumns]; for (int i = 0; i < totalColumns; i++) { columnsShuffled[i] = static_cast(permOut->getData(i)); } // // Loop through the nodes // float* values = new float[totalColumns]; for (int i = 0; i < numNodes; i++) { // // Place all of the values for the node in a single array // int indx = 0; for (int j = 0; j < numFiles; j++) { const MetricFile* mf = metricFilesIn[j]; const int numCols = mf->getNumberOfColumns(); for (int k = 0; k < numCols; k++) { values[indx] = mf->getValue(i, k); indx++; } } // // add the metric values using the shuffled indices // indx = 0; for (int j = 0; j < numFiles; j++) { MetricFile* mf = metricFilesOut[j]; const int numCols = mf->getNumberOfColumns(); for (int k = 0; k < numCols; k++) { const int shuffIndex = columnsShuffled[indx]; mf->setValue(i, k, values[shuffIndex]); indx++; } } } // // Free memory // delete[] columnsShuffled; delete[] values; } /** * compute T-map on shuffled columns split into two groups. * If the number in group 1 is negative or zero, the columns are split * into two groups of the same size. */ MetricFile* MetricFile::computeStatisticalShuffledTMap(const int numberOfRepetitions, const int numberInGroup1, const TopologyFile* topologyFile, const int varianceSmoothingIterations, const float varianceSmoothingStrength, const bool poolTheVariance) const throw (FileException) { const int numberOfNodes = getNumberOfNodes(); const int numberOfColumns = getNumberOfColumns(); if ((numberOfNodes <= 0) || (numberOfColumns <= 0)) { throw FileException("Input Metric File is isEmpty."); } if (numberOfColumns == 1) { throw FileException("Input Metric File has only one column."); } if (numberInGroup1 >= numberOfColumns) { throw FileException("Size of first group is greater than or equal to the number of colunms."); } // // Create the output metric file that will contain the tmaps // MetricFile* metricOut = new MetricFile; metricOut->setNumberOfNodesAndColumns(numberOfNodes, numberOfRepetitions); metricOut->appendToFileComment("Shuffled Columns T-Map from "); metricOut->appendToFileComment(FileUtilities::basename(getFileName())); // // Create metric files for the two groups // int halfIndex = numberOfColumns / 2; if (numberInGroup1 > 0) { halfIndex = numberInGroup1; } const int numColumnsFile1 = halfIndex; const int numColumnsFile2 = numberOfColumns - halfIndex; MetricFile file1, file2; file1.setNumberOfNodesAndColumns(numberOfNodes, numColumnsFile1); file2.setNumberOfNodesAndColumns(numberOfNodes, numColumnsFile2); // // Do for the number of repetitions // for (int nr = 0; nr < numberOfRepetitions; nr++) { // // allow other events to process // AbstractFile::allowEventsToProcess(); // // Create shuffled columns' indices // std::vector columnsShuffledFloat(numberOfColumns); for (int i = 0; i < numberOfColumns; i++) { columnsShuffledFloat[i] = i; } /* RandomNumberOp randOp; // used to rand() is called std::random_shuffle(columnsShuffled.begin(), columnsShuffled.end(), randOp); */ // // Randomly shuffle the columns // StatisticDataGroup sdg(&columnsShuffledFloat, StatisticDataGroup::DATA_STORAGE_MODE_POINT); StatisticPermutation perm(StatisticPermutation::PERMUTATION_METHOD_RANDOM_ORDER); perm.addDataGroup(&sdg); try { perm.execute(); } catch (StatisticException& e) { throw FileException(e); } const StatisticDataGroup* permOut = perm.getOutputData(); if (permOut->getNumberOfData() != numberOfColumns) { throw FileException("Program error: StatisticPermutation return wrong number of values."); } std::vector columnsShuffled(numberOfColumns); for (int i = 0; i < numberOfColumns; i++) { columnsShuffled[i] = static_cast(permOut->getData(i)); } // // Set the values for each of the two split metric files // for (int j = 0; j < numColumnsFile1; j++) { const int indx = columnsShuffled[j]; for (int i = 0; i < numberOfNodes; i++) { file1.setValue(i, j, getValue(i, indx)); } } // // Set the values for each of the two split metric files // for (int j = 0; j < numColumnsFile2; j++) { const int indx = columnsShuffled[j + halfIndex]; for (int i = 0; i < numberOfNodes; i++) { file2.setValue(i, j, getValue(i, indx)); } } // // Compute the T-Map for the two files // MetricFile* tMapMetricFile = computeStatisticalTMap(&file1, &file2, topologyFile, varianceSmoothingIterations, varianceSmoothingStrength, poolTheVariance, 0.05, false, false, false); const int tMapColumn = tMapMetricFile->getColumnWithName("T-Map"); if (tMapColumn < 0) { throw FileException("Unable to find columns named \"T-Map\""); } // // Add T-map to output metric file // for (int i = 0; i < numberOfNodes; i++) { metricOut->setValue(i, nr, tMapMetricFile->getValue(i, tMapColumn)); } // // Update column name and comment // std::ostringstream str1, str1Com, str2, str2Com; for (int j = 0; j < numberOfColumns; j++) { if (j < halfIndex) { str1 << columnsShuffled[j] << " "; str1Com << getColumnName(columnsShuffled[j]).toAscii().constData() << " "; } else { str2 << columnsShuffled[j] << " "; str2Com << getColumnName(columnsShuffled[j]).toAscii().constData() << " "; } } std::ostringstream str; str << "T-Test on " << str1.str() << " versus " << str2.str(); metricOut->setColumnName(nr, str.str().c_str()); std::ostringstream strCom; strCom << "T-Test on " << str1Com.str() << " versus " << str2Com.str(); metricOut->setColumnComment(nr, strCom.str().c_str()); // // Set column color mapping // metricOut->setColumnColorMappingMinMax(nr, -5.0, 5.0); delete tMapMetricFile; } return metricOut; } /** * remap values in a column so that they fit a normal distribution * with the median at the normal distribution's mean. */ void MetricFile::remapColumnToNormalDistribution(const int inputColumnNumber, const int outputColumnNumberIn, const QString& outputColumnName, const float normalDistributionMean, const float normalDistributionDeviation) throw (FileException) { const int numberOfNodes = getNumberOfNodes(); const int numberOfColumns = getNumberOfColumns(); // // Check for valid input column // if ((numberOfColumns <= 0) || (numberOfNodes <= 0)) { throw FileException("There are no nodes in the metric file."); } if ((inputColumnNumber < 0) || (inputColumnNumber >= numberOfColumns)) { throw FileException("Input column index is invalid."); } // // Create a new column if needed. // int outputColumnNumber = outputColumnNumberIn; if ((outputColumnNumber < 0) || (outputColumnNumber >= numberOfColumns)){ addColumns(1); outputColumnNumber = getNumberOfDataArrays() - 1; } setColumnName(outputColumnNumber, outputColumnName); // // Get the input values // std::vector values; getColumnForAllNodes(inputColumnNumber, values); // // Normalize the values // StatisticNormalizeDistribution normDist(normalDistributionMean, normalDistributionDeviation); StatisticDataGroup sdg(&values, StatisticDataGroup::DATA_STORAGE_MODE_POINT); normDist.addDataGroup(&sdg); try { normDist.execute(); const StatisticDataGroup* sdgNormalized = normDist.getOutputDataGroupContainingNormalizeValues(); setColumnForAllNodes(outputColumnNumber, sdgNormalized->getPointerToData()); } catch (StatisticException& e) { throw FileException(e); } // // Set color mapping // setColumnColorMappingMinMax(outputColumnNumber, -normalDistributionDeviation * 4.0, normalDistributionDeviation * 4.0); // // create the new column comment // std::ostringstream str; str << "Mean = " << normalDistributionMean << " Std Dev = " << normalDistributionDeviation << "\n" << getColumnComment(inputColumnNumber).toAscii().constData(); setColumnComment(outputColumnNumber, str.str().c_str()); } /** * copy a column of values to another column. */ void MetricFile::copyColumn(const int inputColumnNumber, const int outputColumnNumber) { GiftiDataArray* ndaIn = dataArrays[inputColumnNumber]; GiftiDataArray* ndaOut = dataArrays[outputColumnNumber]; if (ndaIn->getNumberOfRows() == ndaOut->getNumberOfRows()) { float* dataIn = ndaIn->getDataPointerFloat(); float* dataOut = ndaOut->getDataPointerFloat(); const int num = ndaIn->getNumberOfRows(); for (int i = 0; i < num; i++) { dataOut[i] = dataIn[i]; } } } /** * extract columns (indices starting at zero) from a metric file and store in another metric file. */ void MetricFile::extractColumnsFromFile(const QString& inputFileName, const QString& outputFileName, const std::vector& columnsToExtract) throw (FileException) { // // Check inputs // if (inputFileName.isEmpty()) { throw FileException("input file name is empty."); } if (outputFileName.isEmpty()) { throw FileException("output file name is empty."); } if (columnsToExtract.empty()) { throw FileException("No column are specified for extraction."); } // // Read input file // MetricFile inputFile; inputFile.readFile(inputFileName); // // Check input metric file // const int numNodes = inputFile.getNumberOfNodes(); const int numCols = inputFile.getNumberOfColumns(); if ((numNodes <= 0) || (numCols <= 0)) { throw FileException("Input file contains no data."); } // // Validate columns for extraction // const int numColumnsToExtract = static_cast(columnsToExtract.size()); for (int i = 0; i < numColumnsToExtract; i++) { const int col = columnsToExtract[i]; if ((col < 0) || (col >= numCols)) { QString msg("Trying to extract invalid column=" + QString::number(col) + ".\n" "Column numbers should range 0 to " + QString::number(numCols - 1) + "."); throw FileException(msg); } } // // Create the output file // MetricFile outputFile; // // Use append() method to copy the data // std::vector indexDestination(numCols, APPEND_ARRAY_DO_NOT_LOAD); for (int i = 0; i < numColumnsToExtract; i++) { indexDestination[columnsToExtract[i]] = APPEND_COLUMN_NEW; } outputFile.append(inputFile, indexDestination, FILE_COMMENT_MODE_LEAVE_AS_IS); outputFile.setFileComment("Data extracted from " + inputFileName); // // Write the output file // outputFile.writeFile(outputFileName); } /** * concatenate columns from a group of metric files (all must have same number of nodes). */ void MetricFile::concatenateColumnsFromFiles(const QString& outputFileName, const std::vector& inputFileNames, const CONCATENATE_COLUMNS_MODE mode, const QString& columnName) throw (FileException) { // // check input files // if (outputFileName.isEmpty()) { throw FileException("No output file name specified."); } const int num = static_cast(inputFileNames.size()); if (num == 0) { throw FileException("No input file names specified."); } for (int i = 0; i < num; i++) { if (inputFileNames[i].isEmpty()) { throw FileException("One or more input file names is not specified."); } } // // Check mode specified inputs // switch (mode) { case CONCATENATE_COLUMNS_MODE_ALL: break; case CONCATENATE_COLUMNS_MODE_NAME_EXACT: if (columnName.isEmpty()) { throw FileException("Column name not specified."); } break; } // // the output file // MetricFile outputFile; // // Loop through the input files // for (int i = 0; i < num; i++) { // // Name of metric file // const QString metricName = inputFileNames[i]; // // read metric file // MetricFile m; m.readFile(metricName); // // Check append mode // switch (mode) { case CONCATENATE_COLUMNS_MODE_ALL: for (int j = 0; j < m.getNumberOfColumns(); j++) { // // Append name of file to column name // QString colName = m.getColumnName(j); colName.append(" - "); colName.append(FileUtilities::basename(metricName)); m.setColumnName(j, colName); } // // Append the entire file // outputFile.append(m); break; case CONCATENATE_COLUMNS_MODE_NAME_EXACT: { // // Keep track of which column to append // const int numCols = m.getNumberOfColumns(); std::vector destination(numCols, APPEND_COLUMN_DO_NOT_LOAD); // initial values // // Find the columns with the specified name // bool foundColumn = false; for (int j = 0; j < numCols; j++) { if (m.getColumnName(j) == columnName) { // // column matches // destination[j] = APPEND_COLUMN_NEW; foundColumn = true; // // Append name of file to column name // QString colName = m.getColumnName(j); colName.append(" - "); colName.append(FileUtilities::basename(metricName)); m.setColumnName(j, colName); } } // // Make sure columns were found // if (foundColumn == false) { QString msg(FileUtilities::basename(metricName)); msg.append(" does not contain any columns named "); msg.append(columnName); throw FileException(msg); } // // append the specified column only // outputFile.append(m, destination, FILE_COMMENT_MODE_LEAVE_AS_IS); } break; } } // // Write the output file // outputFile.writeFile(outputFileName); } /** * add a column that is distance between nodes in two coordinate files (c1 - c2) * NOTE: x/y/z diff columns must already exist, they will not be created */ void MetricFile::addColumnOfCoordinateDifference(const COORDINATE_DIFFERENCE_MODE diffMode, const CoordinateFile* c1, const CoordinateFile* c2, const TopologyFile* topologyFile, const int columnIn, const QString& columnName, const QString& columnComment, const int xDiffColumn, const int yDiffColumn, const int zDiffColumn) throw (FileException) { // // Check inputs // if (c1 == NULL) { throw FileException("First coordinate file invalid"); } if (c2 == NULL) { throw FileException("Second coordinate file invalid"); } if (topologyFile == NULL) { throw FileException("Topology file invalid"); } if (columnName.isEmpty()) { throw FileException("Column name is empty."); } // // Check number of nodes // const int numNodes = c1->getNumberOfCoordinates(); if (numNodes <= 0) { throw FileException("First coordinate file contains no coordinates"); } if (numNodes != c2->getNumberOfCoordinates()) { throw FileException("Coordinate files have a different number of nodes"); } const int metricNodes = getNumberOfNodes(); if (metricNodes > 0) { if (metricNodes != numNodes) { throw FileException("Coordinate and metric files have different number of nodes."); } } // // create/find desired metric column // int column = columnIn; if (metricNodes == 0) { setNumberOfNodesAndColumns(numNodes, 1); column = 0; } else { if ((column < 0) || (column >= getNumberOfColumns())) { addColumns(1); column = getNumberOfColumns() - 1; } } // // Set the column name and comment // setColumnName(column, columnName); setColumnComment(column, columnComment); // // X/Y/Z-Diff column names // if (xDiffColumn >= 0) { setColumnName(xDiffColumn, "dX"); } if (yDiffColumn >= 0) { setColumnName(yDiffColumn, "dY"); } if (zDiffColumn >= 0) { setColumnName(zDiffColumn, "dZ"); } // // Create a topoogy helper // const TopologyHelper* th = topologyFile->getTopologyHelper(false, true, false); // // Set the metric data with distance between coordinates // float maxDist = 0.0; for (int i = 0; i < numNodes; i++) { float dist = 0; if (th->getNodeHasNeighbors(i)) { dist = MathUtilities::distance3D(c1->getCoordinate(i), c2->getCoordinate(i)); } setValue(i, column, dist); maxDist = std::max(maxDist, dist); if ((xDiffColumn >= 0) || (yDiffColumn >= 0) || (zDiffColumn >= 0)) { float diff[3]; MathUtilities::subtractVectors(c1->getCoordinate(i), c2->getCoordinate(i), diff); switch (diffMode) { case COORDINATE_DIFFERENCE_MODE_ABSOLUTE: diff[0] = std::fabs(diff[0]); diff[1] = std::fabs(diff[1]); diff[2] = std::fabs(diff[2]); break; case COORDINATE_DIFFERENCE_MODE_SIGNED: break; } if (xDiffColumn >= 0) { setValue(i, xDiffColumn, diff[0]); } if (yDiffColumn >= 0) { setValue(i, yDiffColumn, diff[1]); } if (zDiffColumn >= 0) { setValue(i, zDiffColumn, diff[2]); } } } setColumnColorMappingMinMax(column, 0.0, maxDist); // // Set color mapping for x/y/z diff columns // if (xDiffColumn >= 0) { float minValue, maxValue; getDataColumnMinMax(xDiffColumn, minValue, maxValue); setColumnColorMappingMinMax(xDiffColumn, minValue, maxValue); } if (yDiffColumn >= 0) { float minValue, maxValue; getDataColumnMinMax(yDiffColumn, minValue, maxValue); setColumnColorMappingMinMax(yDiffColumn, minValue, maxValue); } if (zDiffColumn >= 0) { float minValue, maxValue; getDataColumnMinMax(zDiffColumn, minValue, maxValue); setColumnColorMappingMinMax(zDiffColumn, minValue, maxValue); } setModified(); } /** * add a column that is T-Map of distances in two coordinate files (c1 - c2). * NOTE: the deviation input files should contain the deviation squared divided * by the number of subjects. */ void MetricFile::addColumnOfCoordinateDifferenceTMap(const CoordinateFile* c1, const CoordinateFile* c2, const TopologyFile* topologyFile, const int columnIn, const QString& columnName, const QString& columnComment, const MetricFile* deviationSquaredDividedByN_1, const int deviation1Column, const MetricFile* deviationSquaredDividedByN_2, const int deviation2Column, const bool addCoordinateDifferencesFlag) throw (FileException) { // // Check inputs // if (c1 == NULL) { throw FileException("First coordinate file invalid"); } if (c2 == NULL) { throw FileException("Second coordinate file invalid"); } if (topologyFile == NULL) { throw FileException("Topology file invalid"); } if (columnName.isEmpty()) { throw FileException("Column name is empty."); } // // Check number of nodes // const int numNodes = c1->getNumberOfCoordinates(); if (numNodes <= 0) { throw FileException("First coordinate file contains no coordinates"); } if (numNodes != c2->getNumberOfCoordinates()) { throw FileException("Coordinate files have a different number of nodes"); } const int metricNodes = getNumberOfNodes(); if (metricNodes > 0) { if (metricNodes != numNodes) { throw FileException("Coordinate and metric files have different number of nodes."); } } // // create/find desired metric column // int column = columnIn; if (metricNodes == 0) { setNumberOfNodesAndColumns(numNodes, 1); column = 0; } else { if ((column < 0) || (column >= getNumberOfColumns())) { addColumns(1); column = getNumberOfColumns() - 1; } } // // Set the column name and comment // setColumnName(column, columnName); setColumnComment(column, columnComment); // // Create a topoogy helper // const TopologyHelper* th = topologyFile->getTopologyHelper(false, true, false); // // Set the metric data with distance between coordinates // float minT = std::numeric_limits::max(); float maxT = -std::numeric_limits::max(); for (int i = 0; i < numNodes; i++) { float t = 0.0; if (th->getNodeHasNeighbors(i)) { const float dist = MathUtilities::distance3D(c1->getCoordinate(i), c2->getCoordinate(i)); const float denom = std::sqrt(deviationSquaredDividedByN_1->getValue(i, deviation1Column) + deviationSquaredDividedByN_2->getValue(i, deviation2Column)); if (denom != 0.0) { t = dist / denom; } maxT = std::max(maxT, t); minT = std::min(minT, t); } setValue(i, column, t); } setColumnColorMappingMinMax(column, minT, maxT); // // Are distances desired ? // if (addCoordinateDifferencesFlag) { // // Add 4 columns for distance, dx, dy, dz // const int lastCol = getNumberOfColumns(); addColumns(4); // // Just use plain coordinate differences method to get distance, and dx, dy, dz // addColumnOfCoordinateDifference(COORDINATE_DIFFERENCE_MODE_ABSOLUTE, c1, c2, topologyFile, lastCol, "Distance", "", lastCol + 1, lastCol + 2, lastCol + 3); } setModified(); } /** * Write the file's memory in caret6 format to the specified name. */ QString MetricFile::writeFileInCaret6Format(const QString& filenameIn, Structure structure,const ColorFile* colorFileIn, const bool useCaret6ExtensionFlag) throw (FileException) { QString name = filenameIn; if (useCaret6ExtensionFlag) { name = FileUtilities::replaceExtension(filenameIn, ".metric", SpecFile::getGiftiFunctionalFileExtension()); } this->setFileWriteType(AbstractFile::FILE_FORMAT_XML_GZIP_BASE64); this->writeFile(name); return name; } // //------------------------------------------------------------------------------------------ // /** * Constructor. */ MetricMappingInfo::MetricMappingInfo() { reset(); } /** * Constructor. */ MetricMappingInfo::MetricMappingInfo(const QString& surfaceNameIn, const int surfaceIndexNumberIn, const QString& volumeNameIn, const QString& subVolumeNameIn, const int volumeNumberIn, const int subVolumeNumberIn) { setData(surfaceNameIn, surfaceIndexNumberIn, volumeNameIn, subVolumeNameIn, volumeNumberIn, subVolumeNumberIn); } /** * Destructor. */ MetricMappingInfo::~MetricMappingInfo() { } /** * reset the data. */ void MetricMappingInfo::reset() { setData("", -1, "", "", -1, -1); } /** * set the data. */ void MetricMappingInfo::setData(const QString& surfaceNameIn, const int surfaceIndexNumberIn, const QString& volumeNameIn, const QString& subVolumeNameIn, const int volumeNumberIn, const int subVolumeNumberIn) { surfaceName = surfaceNameIn; surfaceIndexNumber = surfaceIndexNumberIn; volumeName = volumeNameIn; subVolumeName = subVolumeNameIn; volumeNumber = volumeNumberIn; subVolumeNumber = subVolumeNumberIn; } /** * get the data. */ void MetricMappingInfo::getData(QString& surfaceNameOut, int& surfaceIndexNumberOut, QString& volumeNameOut, QString& subVolumeNameOut, int& volumeNumberOut, int& subVolumeNumberOut) const { surfaceNameOut = surfaceName; surfaceIndexNumberOut = surfaceIndexNumber; volumeNameOut = volumeName; subVolumeNameOut = subVolumeName; volumeNumberOut = volumeNumber; subVolumeNumberOut = subVolumeNumber; } caret-5.6.4~dfsg.1.orig/caret_files/MDPlotFile.h0000664000175000017500000002564611572067322021166 0ustar michaelmichael#ifndef __MDPLOT_FILE_H__ #define __MDPLOT_FILE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "AbstractFile.h" class MDPlotFile; /// class for MDPlot Colors class MDPlotColor { public: /// MDPlot Colors enum COLOR { /// dark red color COLOR_DARK_RED = 0, /// red color COLOR_RED = 1, /// dark green color COLOR_DARK_GREEN = 2, /// green color COLOR_GREEN = 3, /// dark blue color COLOR_DARK_BLUE = 4, /// blue color COLOR_BLUE = 5, /// dark magenta color COLOR_DARK_MAGENTA = 6, /// magenta color COLOR_MAGENTA = 7, /// dark yellow color COLOR_DARK_YELLOW = 8, /// yellow color COLOR_YELLOW = 9, /// dark cyan color COLOR_DARK_CYAN = 10, /// cyan color COLOR_CYAN = 11, /// black color COLOR_BLACK = 12, /// dark gray color COLOR_DARK_GRAY = 13, /// light gray color COLOR_LIGHT_GRAY = 14, /// white color COLOR_WHITE = 15, /// number of colors NUMBER_OF = 16 }; /// get the number of colors static int getNumberOfColors() { return NUMBER_OF; } /// get the color name static QString getColorName(const COLOR color); /// get the color components (red, green, blue, alpha) static const unsigned char* getColorComponents(const COLOR color); /// get the color components static void getColorComponents(const COLOR color, unsigned char& red, unsigned char& green, unsigned char& blue); /// get the color components (red, green, blue) static void getColorComponents(const COLOR color, unsigned char rgb[3]); protected: /// initialize the colors static void initializeColors(); /// the actual colors static unsigned char colors[NUMBER_OF][3]; /// the color names static QString colorNames[NUMBER_OF]; /// colors valid flag static bool colorsValid; }; #ifdef __MDPLOT_FILE_MAIN__ unsigned char MDPlotColor::colors[MDPlotColor::NUMBER_OF][3]; QString MDPlotColor::colorNames[MDPlotColor::NUMBER_OF]; bool MDPlotColor::colorsValid = false; #endif // __MDPLOT_FILE_MAIN__ /// class for an MDPlot Vertex class MDPlotVertex { public: // constructor MDPlotVertex(); // constructor MDPlotVertex(const float x, const float y, const float z); // copy constructor MDPlotVertex(const MDPlotVertex& mv); // assignment operator MDPlotVertex& operator=(const MDPlotVertex& mv); // set the X/Y void setXYZ(const float x, const float y, const float z); // set the X/Y/Z void setXYZ(const float xyzIn[3]); // get the X/Y/Z const float* getXYZ() const { return xyz; } // get the X/Y/Z void getXYZ(float& x, float& y, float& z) const; // get the X/Y void getXYZ(float xyOut[3]) const; // set the MDPlot File in which this is an item void setMDPlotFile(MDPlotFile* mdpf); protected: /// copy helper void copyHelper(const MDPlotVertex& mv); /// the X, Y, & Z float xyz[3]; /// MDPlot File in which this item is a member MDPlotFile* mdplotFile; }; /// class for an MDPlot Point class MDPlotPoint { public: /// point symbols enum SYMBOL { /// plus symbol SYMBOL_PLUS, /// X symbol SYMBOL_X, /// square symbol SYMBOL_SQUARE, /// circle symbol SYMBOL_CIRCLE, /// filled circle symbol SYMBOL_CIRCLE_FILLED, /// asterisk symbol SYMBOL_ASTERISK, /// dot symbol SYMBOL_DOT, /// filled square symbol SYMBOL_SQUARE_FILLED, /// triangle symbol SYMBOL_TRIANGLE, /// filled triangle symbol SYMBOL_TRIANGLE_FILLED }; // constructor MDPlotPoint(const int vertexIn, const SYMBOL symbolIn = SYMBOL_SQUARE, const float sizeIn = 1, const MDPlotColor::COLOR colorIn = MDPlotColor::COLOR_GREEN); // constructor MDPlotPoint(); // destructor ~MDPlotPoint(); // copy constructor MDPlotPoint(const MDPlotPoint& mv); // assignment operator MDPlotPoint& operator=(const MDPlotPoint& mv); /// get the symbol SYMBOL getSymbol() const { return symbol; } // set the symbol void setSymbol(const SYMBOL symbolIn); /// get the size float getSize() const { return size; } // set the size void setSize(const float sizeIn); /// get the color MDPlotColor::COLOR getColor() const { return color; } // set the color void setColor(const MDPlotColor::COLOR colorIn); /// get the vertex index int getVertex() const { return vertexIndex; } // set the vertex index void setVertex(const int vertexIn); // set the MDPlot File in which this is an item void setMDPlotFile(MDPlotFile* mdpf); protected: /// copy helper void copyHelper(const MDPlotPoint& mv); /// the symbol SYMBOL symbol; /// the size float size; /// the color MDPlotColor::COLOR color; /// the vertex index int vertexIndex; /// MDPlot File in which this item is a member MDPlotFile* mdplotFile; }; /// class for an MDPlot line class MDPlotLine { public: /// line style enum STYLE { /// solid style STYLE_SOLID, /// dashed style STYLE_DASHED, /// dotted style STYLE_DOTTED, /// dash-dot style STYLE_DASH_DOT, /// dash-dot-dot style STYLE_DASH_DOT_DOT }; // constructor MDPlotLine(); // constructor MDPlotLine(const std::vector verticesIn, const STYLE styleIn = STYLE_SOLID, MDPlotColor::COLOR colorIn = MDPlotColor::COLOR_RED, const float widthIn = 1); // destructor ~MDPlotLine(); // copy constructor MDPlotLine(const MDPlotLine& mv); // assignment operator MDPlotLine& operator=(const MDPlotLine& mv); /// get the style STYLE getStyle() const { return style; } // set the style void setStyle(const STYLE styleIn); /// get the width float getWidth() const { return width; } // set the width void setWidth(const float widthIn); /// get the color MDPlotColor::COLOR getColor() const { return color; } // set the color void setColor(const MDPlotColor::COLOR colorIn); /// get the vertices int getNumberOfVertices() const { return vertices.size(); } /// get a vertex index int getVertexIndex(const int vertexNum) const; // set a vertex index void setVertexIndex(const int vertexNum, const int value); // add a vertex index void addVertexIndex(const int value); // set the MDPlot File in which this is an item void setMDPlotFile(MDPlotFile* mdpf); protected: /// copy helper void copyHelper(const MDPlotLine& mv); /// the style STYLE style; /// the color MDPlotColor::COLOR color; /// the width float width; /// vertices in the line std::vector vertices; /// MDPlot File in which this item is a member MDPlotFile* mdplotFile; }; /// class for reading and writing an MDPlot file class MDPlotFile : public AbstractFile { public: // constructor MDPlotFile(); // destructor ~MDPlotFile(); /// clear the file void clear(); /// returns true if the file is isEmpty (contains no data) bool empty() const; /// get the number of vertices int getNumberOfVertices() const { return vertices.size(); } /// get a vertex MDPlotVertex* getVertex(const int indx); /// get a vertex const MDPlotVertex* getVertex(const int indx) const; // add a vertex void addVertex(const MDPlotVertex& mv); /// get the number of points int getNumberOfPoints() const { return points.size(); } /// get a point MDPlotPoint* getPoint(const int indx); /// get a point const MDPlotPoint* getPoint(const int indx) const; // add a point void addPoint(const MDPlotPoint& mp); /// get the number of lines int getNumberOfLines() const { return lines.size(); } /// get a line MDPlotLine* getLine(const int indx); /// get a line const MDPlotLine* getLine(const int indx) const; // add a line void addLine(const MDPlotLine& ml); protected: /// Read the contents of the file (header has already been read) void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& rootElement) throw (FileException); /// Write the file's data (header has already been written) void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& xmlDoc, QDomElement& rootElement) throw (FileException); /// the vertices std::vector vertices; /// the points std::vector points; /// the lines std::vector lines; }; #endif // __MDPLOT_FILE_H__ caret-5.6.4~dfsg.1.orig/caret_files/MDPlotFile.cxx0000664000175000017500000005735311572067322021541 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include "DebugControl.h" #include "FileUtilities.h" #define __MDPLOT_FILE_MAIN__ #include "MDPlotFile.h" #undef __MDPLOT_FILE_MAIN__ #include "SpecFile.h" /** * get the color name. */ QString MDPlotColor::getColorName(const COLOR color) { if (colorsValid == false) { initializeColors(); } if ((color >= 0) && (color < NUMBER_OF)) { return colorNames[color]; } return ""; } /** * get the color components (red, green, blue, alpha). */ const unsigned char* MDPlotColor::getColorComponents(const COLOR color) { static const unsigned char gray[3] = { 127, 127, 127 }; if (colorsValid == false) { initializeColors(); } if ((color >= 0) && (color < NUMBER_OF)) { return colors[color]; } return gray; } /** * get the color components. */ void MDPlotColor::getColorComponents(const COLOR color, unsigned char& red, unsigned char& green, unsigned char& blue) { if (colorsValid == false) { initializeColors(); } if ((color >= 0) && (color < NUMBER_OF)) { red = colors[color][0]; green = colors[color][1]; blue = colors[color][2]; return; } red = 127; green = 127; blue = 127; } /** * get the color components (red, green, blue). */ void MDPlotColor::getColorComponents(const COLOR color, unsigned char rgb[3]) { if (colorsValid == false) { initializeColors(); } if ((color >= 0) && (color < NUMBER_OF)) { rgb[0] = colors[color][0]; rgb[1] = colors[color][1]; rgb[2] = colors[color][2]; return; } rgb[0] = 127; rgb[1] = 127; rgb[2] = 127; } /** * initialize the colors. */ void MDPlotColor::initializeColors() { colorNames[COLOR_DARK_RED] = "Red - Dark"; colors[COLOR_DARK_RED][0] = 128; colors[COLOR_DARK_RED][1] = 0; colors[COLOR_DARK_RED][2] = 0; colorNames[COLOR_RED] = "Red"; colors[COLOR_RED][0] = 255; colors[COLOR_RED][1] = 0; colors[COLOR_RED][2] = 0; colorNames[COLOR_DARK_GREEN] = "Green - Dark"; colors[COLOR_DARK_GREEN][0] = 0; colors[COLOR_DARK_GREEN][1] = 128; colors[COLOR_DARK_GREEN][2] = 0; colorNames[COLOR_GREEN] = "Green"; colors[COLOR_GREEN][0] = 0; colors[COLOR_GREEN][1] = 255; colors[COLOR_GREEN][2] = 0; colorNames[COLOR_DARK_BLUE] = "Blue - Dark"; colors[COLOR_DARK_BLUE][0] = 0; colors[COLOR_DARK_BLUE][1] = 0; colors[COLOR_DARK_BLUE][2] = 128; colorNames[COLOR_BLUE] = "Blue"; colors[COLOR_BLUE][0] = 0; colors[COLOR_BLUE][1] = 0; colors[COLOR_BLUE][2] = 255; colorNames[COLOR_DARK_MAGENTA] = "Magenta - Dark"; colors[COLOR_DARK_MAGENTA][0] = 128; colors[COLOR_DARK_MAGENTA][1] = 0; colors[COLOR_DARK_MAGENTA][2] = 128; colorNames[COLOR_MAGENTA] = "Magenta"; colors[COLOR_MAGENTA][0] = 255; colors[COLOR_MAGENTA][1] = 0; colors[COLOR_MAGENTA][2] = 255; colorNames[COLOR_DARK_YELLOW] = "Yellow - Dark"; colors[COLOR_DARK_YELLOW][0] = 128; colors[COLOR_DARK_YELLOW][1] = 128; colors[COLOR_DARK_YELLOW][2] = 0; colorNames[COLOR_YELLOW] = "Yellow"; colors[COLOR_YELLOW][0] = 255; colors[COLOR_YELLOW][1] = 255; colors[COLOR_YELLOW][2] = 0; colorNames[COLOR_DARK_CYAN] = "Cyan - Dark"; colors[COLOR_DARK_CYAN][0] = 0; colors[COLOR_DARK_CYAN][1] = 128; colors[COLOR_DARK_CYAN][2] = 128; colorNames[COLOR_CYAN] = "Cyan"; colors[COLOR_CYAN][0] = 0; colors[COLOR_CYAN][1] = 255; colors[COLOR_CYAN][2] = 255; colorNames[COLOR_BLACK] = "Black"; colors[COLOR_BLACK][0] = 0; colors[COLOR_BLACK][1] = 0; colors[COLOR_BLACK][2] = 0; colorNames[COLOR_DARK_GRAY] = "Gray - Dark"; colors[COLOR_DARK_GRAY][0] = 128; colors[COLOR_DARK_GRAY][1] = 128; colors[COLOR_DARK_GRAY][2] = 128; colorNames[COLOR_LIGHT_GRAY] = "Gray - Light"; colors[COLOR_LIGHT_GRAY][0] = 192; colors[COLOR_LIGHT_GRAY][1] = 192; colors[COLOR_LIGHT_GRAY][2] = 192; colorNames[COLOR_WHITE] = "White"; colors[COLOR_WHITE][0] = 255; colors[COLOR_WHITE][1] = 255; colors[COLOR_WHITE][2] = 255; colorsValid = true; } //******************************************************************************************* //******************************************************************************************* //* //* //******************************************************************************************* //******************************************************************************************* /** * constructor. */ MDPlotVertex::MDPlotVertex() { mdplotFile = NULL; setXYZ(0.0, 0.0, 0.0); } /** * constructor. */ MDPlotVertex::MDPlotVertex(const float x, const float y, const float z) { mdplotFile = NULL; setXYZ(x, y, z); } /** * copy helper. */ void MDPlotVertex::copyHelper(const MDPlotVertex& mv) { xyz[0] = mv.xyz[0]; xyz[1] = mv.xyz[1]; xyz[2] = mv.xyz[2]; mdplotFile = NULL; } /** * copy constructor. */ MDPlotVertex::MDPlotVertex(const MDPlotVertex& mv) { copyHelper(mv); } /** * assignment operator. */ MDPlotVertex& MDPlotVertex::operator=(const MDPlotVertex& mv) { if (this != &mv) { copyHelper(mv); } return *this; } /** * set the X/Y. */ void MDPlotVertex::setXYZ(const float x, const float y, const float z) { xyz[0] = x; xyz[1] = y; xyz[2] = z; if (mdplotFile != NULL) { mdplotFile->setModified(); } } /** * set the X/Y/Z. */ void MDPlotVertex::setXYZ(const float xyzIn[3]) { xyz[0] = xyzIn[0]; xyz[1] = xyzIn[1]; xyz[2] = xyzIn[2]; if (mdplotFile != NULL) { mdplotFile->setModified(); } } /** * get the X/Y/Z. */ void MDPlotVertex::getXYZ(float& x, float& y, float& z) const { x = xyz[0]; y = xyz[1]; z = xyz[2]; } /** * get the X/Y. */ void MDPlotVertex::getXYZ(float xyzOut[3]) const { xyzOut[0] = xyz[0]; xyzOut[1] = xyz[1]; xyzOut[2] = xyz[2]; } /** * set the MDPlot File in which this is an item. */ void MDPlotVertex::setMDPlotFile(MDPlotFile* mdpf) { mdplotFile = mdpf; } //******************************************************************************************* //******************************************************************************************* //* //* //******************************************************************************************* //******************************************************************************************* /** * constructor. */ MDPlotPoint::MDPlotPoint(const int vertexIn, const SYMBOL symbolIn, const float sizeIn, const MDPlotColor::COLOR colorIn) { mdplotFile = NULL; setVertex(vertexIn); setSymbol(symbolIn); setSize(sizeIn); setColor(colorIn); } /** * constructor. */ MDPlotPoint::MDPlotPoint() { mdplotFile = NULL; } /** * destructor. */ MDPlotPoint::~MDPlotPoint() { } /** * copy helper. */ void MDPlotPoint::copyHelper(const MDPlotPoint& mp) { symbol = mp.symbol; color = mp.color; vertexIndex = mp.vertexIndex; mdplotFile = NULL; } /** * copy constructor. */ MDPlotPoint::MDPlotPoint(const MDPlotPoint& mp) { copyHelper(mp); } /** * assignment operator. */ MDPlotPoint& MDPlotPoint::operator=(const MDPlotPoint& mp) { if (this != &mp) { copyHelper(mp); } return *this; } /** * set the symbol. */ void MDPlotPoint::setSymbol(const SYMBOL symbolIn) { symbol = symbolIn; if (mdplotFile != NULL) { mdplotFile->setModified(); } } /** * set the size. */ void MDPlotPoint::setSize(const float sizeIn) { size = sizeIn; if (mdplotFile != NULL) { mdplotFile->setModified(); } } /** * set the color. */ void MDPlotPoint::setColor(const MDPlotColor::COLOR colorIn) { color = colorIn; if (mdplotFile != NULL) { mdplotFile->setModified(); } } /** * set the vertex index. */ void MDPlotPoint::setVertex(const int vertexIn) { vertexIndex = vertexIn; if (mdplotFile != NULL) { mdplotFile->setModified(); } } /** * set the MDPlot File in which this is an item. */ void MDPlotPoint::setMDPlotFile(MDPlotFile* mdpf) { mdplotFile = mdpf; } //******************************************************************************************* //******************************************************************************************* //* //* //******************************************************************************************* //******************************************************************************************* /** * constructor. */ MDPlotLine::MDPlotLine() { mdplotFile = NULL; setStyle(STYLE_SOLID); setColor(MDPlotColor::COLOR_RED); setWidth(1); } /** * constructor. */ MDPlotLine::MDPlotLine(const std::vector verticesIn, const STYLE styleIn, MDPlotColor::COLOR colorIn, const float widthIn) { mdplotFile = NULL; vertices = verticesIn; setStyle(styleIn); setColor(colorIn); setWidth(widthIn); } /** * destructor. */ MDPlotLine::~MDPlotLine() { } /** * copy constructor. */ MDPlotLine::MDPlotLine(const MDPlotLine& ml) { copyHelper(ml); } /** * assignment operator. */ MDPlotLine& MDPlotLine::operator=(const MDPlotLine& ml) { if (this != &ml) { copyHelper(ml); } return *this; } /** * copy helper. */ void MDPlotLine::copyHelper(const MDPlotLine& ml) { style = ml.style; width = ml.width; color = ml.color; vertices = ml.vertices; mdplotFile = NULL; } /** * set the style. */ void MDPlotLine::setStyle(const STYLE styleIn) { style = styleIn; if (mdplotFile != NULL) { mdplotFile->setModified(); } } /** * set the width. */ void MDPlotLine::setWidth(const float widthIn) { width = widthIn; if (mdplotFile != NULL) { mdplotFile->setModified(); } } /** * set the color. */ void MDPlotLine::setColor(const MDPlotColor::COLOR colorIn) { color = colorIn; if (mdplotFile != NULL) { mdplotFile->setModified(); } } /** * set a vertex index. */ void MDPlotLine::setVertexIndex(const int vertexNum, const int value) { if ((vertexNum < 0) || (vertexNum >= getNumberOfVertices())) { std::cout << "PROGRAM ERROR line " << __LINE__ << " file " << __FILE__ << " : Invalid vertex index in MDPlot::setVertexIndex(): " << vertexNum << std::endl; return; } vertices[vertexNum] = value; if (mdplotFile != NULL) { mdplotFile->setModified(); } } /** * get a vertex index. */ int MDPlotLine::getVertexIndex(const int vertexNum) const { if ((vertexNum < 0) || (vertexNum >= getNumberOfVertices())) { std::cout << "PROGRAM ERROR line " << __LINE__ << " file " << __FILE__ << " :: Invalid vertex index in MDPlot::getVertexIndex(): " << vertexNum << std::endl; return -1; } return vertices[vertexNum]; } /** * add a vertex index. */ void MDPlotLine::addVertexIndex(const int value) { vertices.push_back(value); if (mdplotFile != NULL) { mdplotFile->setModified(); } } /** * set the MDPlot File in which this is an item. */ void MDPlotLine::setMDPlotFile(MDPlotFile* mdpf) { mdplotFile = mdpf; } //******************************************************************************************* //******************************************************************************************* //* //* //******************************************************************************************* //******************************************************************************************* /** * constructor. */ MDPlotFile::MDPlotFile() : AbstractFile("MDPlot File", SpecFile::getMDPlotFileExtension(), false, FILE_FORMAT_ASCII, FILE_IO_READ_AND_WRITE, FILE_IO_NONE, FILE_IO_NONE, FILE_IO_NONE) { clear(); } /** * destructor. */ MDPlotFile::~MDPlotFile() { clear(); } /** * clear the file. */ void MDPlotFile::clear() { clearAbstractFile(); vertices.clear(); points.clear(); lines.clear(); } /** * returns true if the file is isEmpty (contains no data). */ bool MDPlotFile::empty() const { return (vertices.empty() && points.empty() && lines.empty()); } /** * add a vertex. */ void MDPlotFile::addVertex(const MDPlotVertex& mv) { vertices.push_back(mv); vertices[vertices.size() - 1].setMDPlotFile(this); setModified(); } /** * get a vertex. */ MDPlotVertex* MDPlotFile::getVertex(const int indx) { if ((indx < 0) || (indx >= getNumberOfVertices())) { std::cout << "PROGRAM ERROR line " << __LINE__ << " file " << __FILE__ << " :: Invalid index sent to MDPlotFile::getVertex(): " << indx << std::endl; return NULL; } return &vertices[indx]; } /** * get a vertex. */ const MDPlotVertex* MDPlotFile::getVertex(const int indx) const { if ((indx < 0) || (indx >= getNumberOfVertices())) { std::cout << "PROGRAM ERROR line " << __LINE__ << " file " << __FILE__ << " :: Invalid index sent to MDPlotFile::getVertex(): " << indx << std::endl; return NULL; } return &vertices[indx]; } /** * add a point. */ void MDPlotFile::addPoint(const MDPlotPoint& mp) { points.push_back(mp); points[points.size() - 1].setMDPlotFile(this); setModified(); } /** * get a point. */ MDPlotPoint* MDPlotFile::getPoint(const int indx) { if ((indx < 0) || (indx >= getNumberOfPoints())) { std::cout << "PROGRAM ERROR line " << __LINE__ << " file " << __FILE__ << " :: Invalid index sent to MDPlotFile::getPoint(): " << indx << std::endl; return NULL; } return &points[indx]; } /** * get a point. */ const MDPlotPoint* MDPlotFile::getPoint(const int indx) const { if ((indx < 0) || (indx >= getNumberOfPoints())) { std::cout << "PROGRAM ERROR line " << __LINE__ << " file " << __FILE__ << " :: Invalid index sent to MDPlotFile::getPoint(): " << indx << std::endl; return NULL; } return &points[indx]; } /** * add a line. */ void MDPlotFile::addLine(const MDPlotLine& ml) { lines.push_back(ml); lines[lines.size() - 1].setMDPlotFile(this); setModified(); } /** * get a line. */ MDPlotLine* MDPlotFile::getLine(const int indx) { if ((indx < 0) || (indx >= getNumberOfLines())) { std::cout << "PROGRAM ERROR line " << __LINE__ << " file " << __FILE__ << " :: Invalid index sent to MDPlotFile::getLine(): " << indx << std::endl; return NULL; } return &lines[indx]; } /** * get a line. */ const MDPlotLine* MDPlotFile::getLine(const int indx) const { if ((indx < 0) || (indx >= getNumberOfLines())) { std::cout << "PROGRAM ERROR line " << __LINE__ << " file " << __FILE__ << " :: Invalid index sent to MDPlotFile::getLine(): " << indx << std::endl; return NULL; } return &lines[indx]; } /** * Read the contents of the file (header has already been read). */ void MDPlotFile::readFileData(QFile& /*file*/, QTextStream& stream, QDataStream& /* binStream */, QDomElement& /* rootElement */) throw (FileException) { const QRegExp splitRegExp("\\s"); int vertexOffset = 0; float zValue = 0.0; while (stream.atEnd() == false) { QString line = stream.readLine().trimmed(); if (DebugControl::getDebugOn()) { //std::cout << "Line : " << line.toAscii().constData() << std::endl; } QString lineClean = line.section('#', 0, 0); if (lineClean.isNull() == false) { if (DebugControl::getDebugOn()) { //std::cout << "Clean: " << lineClean.toAscii().constData() << std::endl; } // // Is this line continued to the next line // if (lineClean.endsWith("\\")) { lineClean.truncate(lineClean.length() - 1); bool done = false; while (done == false) { done = true; if (stream.atEnd() == false) { QString line2 = stream.readLine().trimmed(); QString line2Clean = line2.section('#', 0, 0); if (line2Clean.isNull()) { done = true; } else if (line2Clean.isEmpty()) { done = true; } else { if (line2Clean.endsWith("\\")) { line2Clean.truncate(line2Clean.length() - 1); done = false; } lineClean += " "; lineClean += line2Clean; } } } } //QStringList sl = QStringList::split(splitRegExp, lineClean); QStringList sl = lineClean.split(splitRegExp, QString::SkipEmptyParts); if (sl.count() > 1) { const QString key(sl.at(0)); if (key =="SECTION") { if (DebugControl::getDebugOn()) { std::cout << "Section: " << (sl.at(1).toAscii().constData()) << std::endl; } // // Each section has its vertice indices start at zero (I believe) // vertexOffset = getNumberOfVertices(); if (DebugControl::getDebugOn()) { std::cout << "Vertex Offset: " << vertexOffset << std::endl; } zValue = 0.0; } else if (lineClean.startsWith("ZVALUE")) { zValue = (sl.at(1)).toInt(); if (DebugControl::getDebugOn()) { std::cout << "ZVALUE: " << zValue << std::endl; } } else if (key == "V") { if (sl.count() >= 3) { const float x = (sl.at(1)).toFloat(); const float y = (sl.at(2)).toFloat(); MDPlotVertex v(x, y, zValue); addVertex(v); } else { std::ostringstream str; str << "MDPlot File Invalid vertex: " << line.toAscii().constData(); throw FileException(filename, str.str().c_str()); } } else if (key == "P") { if (sl.count() >= 5) { const int pointType = (sl.at(1)).toInt(); const int pointSize = (sl.at(2)).toInt(); const int pointColor = (sl.at(3)).toInt(); int pointVertex = (sl.at(4)).toInt() + vertexOffset - 1; // we index at 0 if ((pointVertex < 0) || (pointVertex >= getNumberOfVertices())) { std::cout << "MDPlot File: Point (" << sl.join(" ").toAscii().constData() << ") has invalid vertex index. Total=" << getNumberOfVertices() << std::endl; } else { MDPlotPoint p(pointVertex, static_cast(pointType), pointSize, static_cast(pointColor)); addPoint(p); } } else { std::ostringstream str; str << "MDPlot File Invalid vertex: " << line.toAscii().constData(); throw FileException(filename, str.str().c_str()); } } else if (key == "L") { if (sl.count() >= 5) { if (DebugControl::getDebugOn()) { std::cout << "LINE DATA: " << sl.join(" ").toAscii().constData() << std::endl; } const int lineType = (sl.at(1)).toInt(); const int lineColor = (sl.at(2)).toInt(); const float lineWidth = (sl.at(3)).toFloat(); std::vector verts; const int numItems = sl.count(); for (int m = 4; m < numItems; m++) { const QString s(sl.at(m)); if (DebugControl::getDebugOn()) { std::cout << "MDPlot Line Element (" << m << ") " << s.toAscii().constData() << std::endl; } int lineVertex = s.toInt() + vertexOffset - 1; // we index at zero if ((lineVertex < 0) || (lineVertex >= getNumberOfVertices())) { std::cout << "MDPlot::readFileData() line has invalid vertex index=" << lineVertex << " Num-Vertices=" << getNumberOfVertices() << std::endl; } else { verts.push_back(lineVertex); } } MDPlotLine theLine(verts, static_cast(lineType), static_cast(lineColor), lineWidth); addLine(theLine); } else { std::ostringstream str; str << "MDPlot File Invalid line: " << line.toAscii().constData(); throw FileException(filename, str.str().c_str()); } } else if (key.isEmpty() == false) { if (DebugControl::getDebugOn()) { std::cout << "MDPlot INFO: ignoring line with key: " << key.toAscii().constData() << std::endl; } } } } } if (DebugControl::getDebugOn()) { std::cout << "MDPlot File: " << FileUtilities::basename(getFileName()).toAscii().constData() << std::endl; std::cout << "Number of Vertices: " << getNumberOfVertices() << std::endl; std::cout << "Number of Points: " << getNumberOfPoints() << std::endl; std::cout << "Number of Lines: " << getNumberOfLines() << std::endl; std::cout << std::endl; } } /** * Write the file's data (header has already been written). */ void MDPlotFile::writeFileData(QTextStream& /* stream */, QDataStream& /* binStream */, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException) { throw FileException(filename, "Writing of MD Plot files not supported."); } caret-5.6.4~dfsg.1.orig/caret_files/LatLonFile.h0000664000175000017500000001077711572067322021217 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_LAT_LON_FILE__ #define __VE_LAT_LON_FILE__ #include "NodeAttributeFile.h" /// This file contains latitude/longitude information for a surface. class LatLonFile : public NodeAttributeFile { private: /// latitude storage std::vector latitude; /// longitude storage std::vector longitude; /// deformed latitude storage std::vector deformedLatitude; /// deformed longitude storage std::vector deformedLongitude; /// deformed lat/lon valid std::vector deformedLatLonValid; /// read a version 0 file void readFileDataVersion0(QTextStream& stream, const bool readNumNodes) throw (FileException); /// read a version 1 file void readFileDataVersion1(QFile& file, QTextStream& stream, QDataStream& binStream) throw (FileException); /// read an LatLon file data void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException); /// write an LatLon file data void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException); public: /// constructor LatLonFile(); /// destructor ~LatLonFile(); /// append a node attribute file to this one void append(NodeAttributeFile& naf) throw (FileException); /// append a node attribute file to this one but selectively load/overwrite columns /// columnDestination is where naf's columns should be (-1=new, -2=do not load) void append(NodeAttributeFile& naf, std::vector columnDestination, const FILE_COMMENT_MODE fcm) throw (FileException); /// add columns to this lat/lon file void addColumns(const int numberOfNewColumns); /// Add nodes to the file void addNodes(const int numberOfNodesToAdd); /// clears lat/lon memory void clear(); /// deform "this" node attribute file placing the output in "deformedFile". void deformFile(const DeformationMapFile& dmf, NodeAttributeFile& deformedFile, const DEFORM_TYPE dt) const throw (FileException); /// reset a column of data void resetColumn(const int columnNumber); /// remove a column of data void removeColumn(const int columnNumber); // set number of nodes void setNumberOfNodesAndColumns(const int numNodes, const int numCols); /// get lat/lon for a node void getLatLon(const int nodeNumber, const int columnNumber, float& lat, float& lon) const; /// get deformed lat lon for a node void getDeformedLatLon(const int nodeNumber, const int columnNumber, float& lat, float& lon) const; /// get deformed lat/lon valid bool getDeformedLatLonValid(const int columnNumber) const { return deformedLatLonValid[columnNumber]; } /// set lat/lon for a node void setLatLon(const int nodeNumber, const int columnNumber, const float lat, const float lon); /// set deformed lat/lon for a node void setDeformedLatLon(const int nodeNumber, const int columnNumber, const float lat, const float lon); }; #ifdef _LAT_LON_FILE_MAIN_ #endif // _LAT_LON_FILE_MAIN_ #endif caret-5.6.4~dfsg.1.orig/caret_files/LatLonFile.cxx0000664000175000017500000005135211572067322021564 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "DeformationMapFile.h" #include "FileUtilities.h" #define _LAT_LON_FILE_MAIN_ #include "LatLonFile.h" #undef _LAT_LON_FILE_MAIN_ #include "SpecFile.h" #include "StringUtilities.h" /** * Constructor. */ LatLonFile::LatLonFile() : NodeAttributeFile("Lat Lon File", SpecFile::getLatLonFileExtension(), AbstractFile::FILE_FORMAT_ASCII, FILE_IO_READ_AND_WRITE, FILE_IO_READ_AND_WRITE, FILE_IO_NONE, FILE_IO_NONE) { clear(); } /** * Destructor. */ LatLonFile::~LatLonFile() { clear(); } /** * append a node attribute file to this one but selectively load/overwrite columns * columnDestination is where naf's columns should be (-1=new, -2=do not load). */ void LatLonFile::append(NodeAttributeFile& naf, std::vector columnDestinationIn, const FILE_COMMENT_MODE fcm) throw (FileException) { bool setTheFileNameFlag = false; std::vector columnDestination = columnDestinationIn; LatLonFile& llf = dynamic_cast(naf); if (numberOfNodes != llf.numberOfNodes) { if (numberOfNodes > 0) { throw FileException("Trying to append lat lon file with a different number " "of nodes"); } else { setTheFileNameFlag = true; } } setModified(); // // Find out how many columns need to be added // int numColumnsToAdd = 0; int newColumnIndex = numberOfColumns; for (int i = 0; i < llf.getNumberOfColumns(); i++) { if (columnDestination[i] == APPEND_COLUMN_NEW) { numColumnsToAdd++; columnDestination[i] = newColumnIndex; newColumnIndex++; } } // // Add on additional columns // if (getNumberOfNodes() == 0) { setNumberOfNodesAndColumns(llf.getNumberOfNodes(), numColumnsToAdd); } else { addColumns(numColumnsToAdd); } // // copy paint column names from other file // for (int k = 0; k < llf.numberOfColumns; k++) { if (columnDestination[k] >= 0) { const int col = columnDestination[k]; setColumnName(col, llf.getColumnName(k)); setColumnComment(col, llf.getColumnComment(k)); } } // // copy lat/lon data from other file // for (int j = 0; j < llf.numberOfColumns; j++) { if (columnDestination[j] >= 0) { const int col = columnDestination[j]; for (int i = 0; i < numberOfNodes; i++) { float lat, lon; llf.getLatLon(i, j, lat, lon); setLatLon(i, col, lat, lon); llf.getDeformedLatLon(i, j, lat, lon); setDeformedLatLon(i, col, lat, lon); } } } if (setTheFileNameFlag) { setFileName(llf.getFileName()); } // // transfer the file's comment // appendFileComment(llf, fcm); } /** * append an lat/lon file to this one */ void LatLonFile::append(NodeAttributeFile& naf) throw (FileException) { LatLonFile& llf = dynamic_cast(naf); if (getNumberOfNodes() != llf.getNumberOfNodes()) { throw FileException("Cannot append LatLon, number of columns does not match."); } const int oldNumCols = getNumberOfColumns(); const int appendNumCols = llf.getNumberOfColumns(); // // Add the additional columns to the file // addColumns(appendNumCols); // // Transfer lat/lon data // for (int i = 0; i < numberOfNodes; i++) { for (int j = 0; j < appendNumCols; j++) { float lat, lon; llf.getLatLon(i, j, lat, lon); setLatLon(i, oldNumCols + j, lat, lon); llf.getDeformedLatLon(i, j, lat, lon); setDeformedLatLon(i, oldNumCols + j, lat, lon); } } // // Transfer column information // for (int j = 0; j < appendNumCols; j++) { setColumnName(oldNumCols + j, llf.getColumnName(j)); setColumnComment(oldNumCols + j, llf.getColumnComment(j)); } // // transfer the file's comment // appendFileComment(llf); } /** * add columns to this lat/lon file */ void LatLonFile::addColumns(const int numberOfNewColumns) { const int oldNumberOfColumns = numberOfColumns; const int totalColumns = numberOfColumns + numberOfNewColumns; // // Save existing lat lon data // const std::vector lat = latitude; const std::vector lon = longitude; const std::vector deflat = deformedLatitude; const std::vector deflon = deformedLongitude; const std::vector defValid = deformedLatLonValid; // // Setup file for new number of columns (will expand space for column naming) // setNumberOfNodesAndColumns(numberOfNodes, totalColumns); // // transfer existing lat lon data // for (int i = 0; i < numberOfNodes; i++) { for (int j = 0; j < numberOfColumns; j++) { if (j < oldNumberOfColumns) { const int oldIndex = (oldNumberOfColumns * i) + j; setLatLon(i, j, lat[oldIndex], lon[oldIndex]); setDeformedLatLon(i, j, deflat[oldIndex], deflon[oldIndex]); } else { setLatLon(i, j, 0.0, 0.0); setDeformedLatLon(i, j, 0.0, 0.0); } } } for (int j = 0; j < numberOfColumns; j++) { if (j < oldNumberOfColumns) { deformedLatLonValid[j] = defValid[j]; } else { deformedLatLonValid[j] = false; } } setModified(); } /** * Add node to the file. */ void LatLonFile::addNodes(const int numberOfNodesToAdd) { setNumberOfNodesAndColumns(numberOfNodes + numberOfNodesToAdd, numberOfColumns); } /** * Clear the file. */ void LatLonFile::clear() { clearNodeAttributeFile(); setNumberOfNodesAndColumns(0, 0); } /** * Set number of nodes in the file. */ void LatLonFile::setNumberOfNodesAndColumns(const int numNodes, const int numCols) { const int oldNumberOfColumns = numberOfColumns; numberOfNodes = numNodes; numberOfColumns = numCols; const int num = numberOfNodes * numberOfColumns * numberOfItemsPerColumn; if (num <= 0) { latitude.clear(); longitude.clear(); deformedLatitude.clear(); deformedLongitude.clear(); deformedLatLonValid.clear(); } else { latitude.resize(num); longitude.resize(num); deformedLatitude.resize(num); deformedLongitude.resize(num); deformedLatLonValid.resize(numberOfColumns); for (int i = oldNumberOfColumns; i < numberOfColumns; i++) { deformedLatLonValid[i] = false; } } numberOfNodesColumnsChanged(); } /** * Get the lat/lon for a node. */ void LatLonFile::getLatLon(const int nodeNumber, const int columnNumber, float& lat, float& lon) const { const int index = getOffset(nodeNumber, columnNumber); lat = latitude[index]; lon = longitude[index]; } /** * Get the deformed lat/lon for a node. */ void LatLonFile::getDeformedLatLon(const int nodeNumber, const int columnNumber, float& lat, float& lon) const { const int index = getOffset(nodeNumber, columnNumber); lat = deformedLatitude[index]; lon = deformedLongitude[index]; } /** * Set the lat/lon for a node. */ void LatLonFile::setLatLon(const int nodeNumber, const int columnNumber, const float lat, const float lon) { const int index = getOffset(nodeNumber, columnNumber); latitude[index] = lat; longitude[index] = lon; setModified(); } /** * Set the deformed lat/lon for a node. */ void LatLonFile::setDeformedLatLon(const int nodeNumber, const int columnNumber, const float lat, const float lon) { const int index = getOffset(nodeNumber, columnNumber); deformedLatitude[index] = lat; deformedLongitude[index] = lon; if ((lat != 0.0) || (lon != 0.0)) { deformedLatLonValid[columnNumber] = true; } setModified(); } /** * Deform the paint file. */ void LatLonFile::deformFile(const DeformationMapFile& dmf, NodeAttributeFile& deformedFile, const DEFORM_TYPE /*dt*/) const throw (FileException) { LatLonFile& deformedLatLonFile = dynamic_cast(deformedFile); const int numNodes = dmf.getNumberOfNodes(); const int numCols = getNumberOfColumns(); deformedLatLonFile.setNumberOfNodesAndColumns(numNodes, numCols); // // Transfer stuff in AbstractFile and NodeAttributeFile // transferFileDataForDeformation(dmf, deformedLatLonFile); // // transfer the latlon columns // int tileNodes[3]; float tileAreas[3]; for (int i = 0; i < numNodes; i++) { dmf.getDeformDataForNode(i, tileNodes, tileAreas); for (int j = 0; j < numCols; j++) { float lat = 0.0, lon = 0.0, deflat = 0.0, deflon = 0.0; if (tileNodes[0] >= 0) { getLatLon(tileNodes[0], j, lat, lon); getDeformedLatLon(tileNodes[0], j, deflat, deflon); } deformedLatLonFile.setLatLon(i, j, lat, lon); deformedLatLonFile.setDeformedLatLon(i, j, lat, lon); } } } /** * reset a column of data. */ void LatLonFile::resetColumn(const int columnNumber) { for (int i = 0; i < numberOfNodes; i++) { setLatLon(i, columnNumber, 0.0, 0.0); setDeformedLatLon(i, columnNumber, 0.0, 0.0); } deformedLatLonValid[columnNumber] = true; setModified(); } /** * remove a column of data. */ void LatLonFile::removeColumn(const int columnNumber) { if (numberOfColumns <= 1) { clear(); return; } // // Transfer lat/lon data // LatLonFile llf; llf.setNumberOfNodesAndColumns(numberOfNodes, numberOfColumns - 1); for (int i = 0; i < numberOfNodes; i++) { int ctr = 0; for (int j = 0; j < numberOfColumns; j++) { if (j != columnNumber) { float lat, lon; getLatLon(i, j, lat, lon); llf.setLatLon(i, ctr, lat, lon); getDeformedLatLon(i, j, lat, lon); llf.setDeformedLatLon(i, ctr, lat, lon); ctr++; } } } // // Transfer column information // int ctr = 0; for (int j = 0; j < numberOfColumns; j++) { if (j != columnNumber) { setColumnName(ctr, getColumnName(j)); setColumnComment(ctr, getColumnComment(j)); deformedLatLonValid[ctr] = deformedLatLonValid[j]; ctr++; } } setNumberOfNodesAndColumns(numberOfNodes, numberOfColumns - 1); latitude = llf.latitude; longitude = llf.longitude; deformedLatitude = llf.deformedLatitude; deformedLongitude = llf.deformedLongitude; deformedLatLonValid = llf.deformedLatLonValid; setModified(); } /** * Read the lat/lon file's version 1 data. */ void LatLonFile::readFileDataVersion1(QFile& file, QTextStream& stream, QDataStream& binStream) throw (FileException) { int numNodes = -1; int numCols = -1; bool readingTags = true; while(readingTags) { QString tag, tagValue; readTagLine(stream, tag, tagValue); if (tag == tagBeginData) { readingTags = false; } else if (tag == tagNumberOfNodes) { numNodes = tagValue.toInt(); if ((numNodes > 0) && (numCols > 0)) { setNumberOfNodesAndColumns(numNodes, numCols); } } else if (tag == tagNumberOfColumns) { numCols = tagValue.toInt(); if ((numNodes > 0) && (numCols > 0)) { setNumberOfNodesAndColumns(numNodes, numCols); } } else if (tag == tagColumnName) { QString name; const int index = splitTagIntoColumnAndValue(tagValue, name); columnNames[index] = name; } else if (tag == tagColumnComment) { QString name; const int index = splitTagIntoColumnAndValue(tagValue, name); columnComments[index] = StringUtilities::setupCommentForDisplay(name); } else if (tag == tagFileTitle) { fileTitle = tagValue; } else { std::cerr << "WARNING: Unknown Lat Lon File Tag: " << tag.toAscii().constData() << std::endl; } } if (numNodes <= 0) { throw FileException(filename, "No data in Lat/Lon file"); } // // Should reading data be skipped ? // if (getReadMetaDataOnlyFlag()) { return; } // // Fixes reading of binary files // file.seek(stream.pos()); switch (getFileReadType()) { case FILE_FORMAT_ASCII: { std::vector tokens; QString line; for (int i = 0; i < numberOfNodes; i++) { readLineIntoTokens(stream, line, tokens); if (static_cast(tokens.size()) == (numberOfColumns * 4 + 1)) { for (int j = 0; j < numberOfColumns; j++) { const int index = getOffset(i, j); latitude[index] = tokens[j * 4 + 1].toFloat(); longitude[index] = tokens[j * 4 + 2].toFloat(); deformedLatitude[index] = tokens[j * 4 + 3].toFloat(); deformedLongitude[index] = tokens[j * 4 + 4].toFloat(); } } else { QString msg("Reading Lat/Lon file line: "); msg.append(line); throw FileException(filename, msg); } } } break; case FILE_FORMAT_BINARY: for (int i = 0; i < numNodes; i++) { for (int j = 0; j < numCols; j++) { float lat, lon, deflat, deflon; binStream >> lat >> lon >> deflat >> deflon; setLatLon(i, j, lat, lon); setDeformedLatLon(i, j, deflat, deflon); } } break; case FILE_FORMAT_XML: throw FileException(filename, "Writing in XML format not supported."); case FILE_FORMAT_XML_BASE64: throw FileException(filename, "XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Writing XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Writing in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Comma Separated Value File Format not supported."); break; } } /** * Read the lat/lon file's version 0 data. */ void LatLonFile::readFileDataVersion0(QTextStream& stream, const bool readNumNodes) throw (FileException) { QString line; if (readNumNodes) { readLine(stream, line); const int num = line.toInt(); setNumberOfNodesAndColumns(num, 1); } // // Should reading data be skipped ? // if (getReadMetaDataOnlyFlag()) { return; } int nodeNum; float lat, lon, deflat, deflon; for (int i = 0; i < numberOfNodes; i++) { readLine(stream, line); const int numItems = sscanf(line.toAscii().constData(), "%d %f %f %f %f", &nodeNum, &lat, &lon, &deflat, &deflon); if ((numItems == 3) || (numItems == 5)) { const int index = getOffset(i, 0); latitude[index] = lat; longitude[index] = lon; if (numItems == 5) { deformedLatitude[index] = deflat; deformedLongitude[index] = deflon; } else { deformedLatitude[index] = 0.0; deformedLongitude[index] = 0.0; } } else { QString str("Invalid lat/lon file line: "); str.append(line); throw FileException(filename, str); } } setModified(); } /** * Read the lat/lon file's data. */ void LatLonFile::readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException) { // // save file position since version 0 has no tags // const qint64 oldTextStreamPosition = stream.pos(); QString line; QString versionStr, versionNumberStr; readTagLine(stream, line, versionStr, versionNumberStr); int fileVersion = 0; if (versionStr == tagFileVersion) { fileVersion = versionNumberStr.toInt(); } switch(fileVersion) { case 0: #ifdef QT4_FILE_POS_BUG setNumberOfNodesAndColumns(line.toInt(), 1); readFileDataVersion0(stream, false); #else // QT4_FILE_POS_BUG file.seek(oldTextStreamPosition); stream.seek(oldTextStreamPosition); readFileDataVersion0(stream, true); #endif // QT4_FILE_POS_BUG break; case 1: readFileDataVersion1(file, stream, binStream); break; default: throw FileException(filename, "Invalid Lat/Lon file version"); break; } } /** * Write the lat/lon file's data. */ void LatLonFile::writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException) { const int numNodes = getNumberOfNodes(); const int numCols = getNumberOfColumns(); stream << tagFileVersion << " 1" << "\n"; stream << tagNumberOfNodes << " " << numNodes << "\n"; stream << tagNumberOfColumns << " " << numCols << "\n"; stream << tagFileTitle << " " << fileTitle << "\n"; for (int j = 0; j < numberOfColumns; j++) { stream << tagColumnName << " " << j << " " << columnNames[j] << "\n"; stream << tagColumnComment << " " << j << " " << StringUtilities::setupCommentForStorage(columnComments[j]) << "\n"; } stream << tagBeginData << "\n"; switch (getFileWriteType()) { case FILE_FORMAT_ASCII: for (int i = 0; i < numNodes; i++) { stream << i; for (int j = 0; j < numCols; j++) { float lat, lon, deflat, deflon; getLatLon(i, j, lat, lon); getDeformedLatLon(i, j, deflat, deflon); stream << " " << lat << " " << lon << " " << deflat << " " << deflon; } stream << "\n"; } break; case FILE_FORMAT_BINARY: #ifdef QT4_FILE_POS_BUG setBinaryFilePosQT4Bug(); #else // QT4_FILE_POS_BUG // // still a bug in QT 4.2.2 // setBinaryFilePosQT4Bug(); #endif // QT4_FILE_POS_BUG for (int i = 0; i < numNodes; i++) { for (int j = 0; j < numCols; j++) { float lat, lon, deflat, deflon; getLatLon(i, j, lat, lon); getDeformedLatLon(i, j, deflat, deflon); binStream << lat << lon << deflat << deflon; } } break; case FILE_FORMAT_XML: throw FileException(filename, "Writing in XML format not supported."); case FILE_FORMAT_XML_BASE64: throw FileException(filename, "XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Writing XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Writing in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Comma Separated Value File Format not supported."); break; } } caret-5.6.4~dfsg.1.orig/caret_files/ImageFile.h0000664000175000017500000001167611572067322021047 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __IMAGE_FILE_H__ #define __IMAGE_FILE_H__ #include #include "AbstractFile.h" /// class for reading/writing accessing images class ImageFile : public AbstractFile { public: /// Constructor ImageFile(); /// Constructor ImageFile(const QImage& img); /// Destructor ~ImageFile(); /// append an image file to the bottom of this image file void appendImageAtBottom(const ImageFile& img); /// Clears current file data in memory. void clear(); /// compare a file for unit testing (tolerance ignored) virtual bool compareFileForUnitTesting(const AbstractFile* af, const float tolerance, QString& messageOut) const; /// returns true if the file is isEmpty bool empty() const; /// get the image QImage* getImage() { return ℑ } /// get the pixmap (const method) const QImage* getImage() const { return ℑ } /// insert an image into this image which must be large enought for insertion of image void insertImage(const QImage& otherImage, const int x, const int y) throw (FileException); /// insert an image into another image static void insertImage(const QImage& insertThisImage, QImage& intoThisImage, const int positionX, const int positionY) throw (FileException); /// set the image void setImage(const QImage img) { image = img; } /// read the file header and its volume data void readFile(const QString& fileNameIn) throw (FileException); /// write the volume file void writeFile(const QString& filenameIn) throw (FileException); /// crop an image by removing the background from the image static void cropImageRemoveBackground(QImage& image, const int marginSize, const int backgroundColor[3]); /// find inclusive bounds (Left, top, right, bottom) of image object (pixel not background color) static void findImageObject(const QImage& image, const int backgroundColor[3], int objectBoundsOut[4]); /// add a margin to an image static void addMargin(QImage& image, const int marginSize, const int backgroundColor[3]); /// add a margin to an image static void addMargin(QImage& image, const int marginSizeX, const int marginSizeY, const int backgroundColor[3]); /// combine images retaining aspect and stretching and filling if needed static void combinePreservingAspectAndFillIfNeeded(const std::vector& images, const int numImagesPerRow, const int backgroundColor[3], QImage& imageOut); protected: /// Read the spec file data (should never be called) void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException); /// Write the spec file data (should never be called) void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException); /// the image data QImage image; }; #endif // __VTK_MODEL_FILE_H__ caret-5.6.4~dfsg.1.orig/caret_files/ImageFile.cxx0000664000175000017500000004647011572067322021422 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "DebugControl.h" #include "FileUtilities.h" #include "ImageFile.h" #include "SpecFile.h" #include "StringUtilities.h" /** * Constructor. */ ImageFile::ImageFile() : AbstractFile("Image File", ".jpg", //SpecFile::getImageFileExtension(), false, AbstractFile::FILE_FORMAT_OTHER, FILE_IO_NONE, FILE_IO_NONE, FILE_IO_NONE, FILE_IO_NONE, FILE_IO_NONE, FILE_IO_READ_AND_WRITE) // be sure to update all constructors { clear(); } /** * Constructor. */ ImageFile::ImageFile(const QImage& img) : AbstractFile("Image File", ".jpg", //SpecFile::getImageFileExtension(), false, AbstractFile::FILE_FORMAT_OTHER, FILE_IO_NONE, FILE_IO_NONE, FILE_IO_NONE, FILE_IO_NONE, FILE_IO_NONE, FILE_IO_READ_AND_WRITE) // be sure to update all constructors { clear(); image = img; } /** * Destructor. */ ImageFile::~ImageFile() { clear(); } /** * Clears current file data in memory. */ void ImageFile::clear() { image = QImage(); } /** * returns true if the file is isEmpty. */ bool ImageFile::empty() const { return (image.width() <= 0); } /** * find inclusive bounds (Left, top, right, bottom) of image object (pixel not background color). */ void ImageFile::findImageObject(const QImage& image, const int backgroundColor[3], int objectBoundsOut[4]) { // // Dimensions of image // const int numX = image.width(); const int numY = 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 = 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 = 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 = 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 = 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 an image. */ void ImageFile::addMargin(QImage& image, const int marginSize, const int backgroundColor[3]) { 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 (FileException&) { } } /** * add a margin to an image. */ void ImageFile::addMargin(QImage& image, const int marginSizeX, const int marginSizeY, const int backgroundColor[3]) { if ((marginSizeX <= 0) && (marginSizeY <= 0)) { return; } // // Add margin // const int width = image.width(); const int height = 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.setImage(QImage(newWidth, newHeight, image.format())); imageFile.getImage()->fill(backgroundColorRGB); try { imageFile.insertImage(image, marginSizeX, marginSizeY); image = (*imageFile.getImage()); } catch (FileException&) { } } /** * crop an image by removing the background from the image. */ void ImageFile::cropImageRemoveBackground(QImage& image, const int marginSize, const int backgroundColor[3]) { // // Get cropping bounds // int leftTopRightBottom[4]; ImageFile::findImageObject(image, backgroundColor, leftTopRightBottom); if (DebugControl::getDebugOn()) { std::cout << "cropping: " << leftTopRightBottom[0] << " " << leftTopRightBottom[1] << " " << leftTopRightBottom[2] << " " << leftTopRightBottom[3] << std::endl; } // // If cropping is valid // const int width = leftTopRightBottom[2] - leftTopRightBottom[0] + 1; const int height = leftTopRightBottom[3] - leftTopRightBottom[1] + 1; if ((width > 0) && (height > 0)) { image = image.copy(leftTopRightBottom[0], leftTopRightBottom[1], width, height); // // Process margin // if (marginSize > 0) { ImageFile::addMargin(image, marginSize, backgroundColor); } } } /** * combine images retaining aspect and stretching and filling if needed. */ void ImageFile::combinePreservingAspectAndFillIfNeeded(const std::vector& images, const int numImagesPerRow, const int backgroundColor[3], QImage& imageOut) { const int numImages = static_cast(images.size()); if (numImages <= 0) { return; } if (numImages == 1) { imageOut = images[0]; 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, images[i].width()); maxImageHeight = std::max(maxImageHeight, images[i].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; imageOut = QImage(outputImageSizeX, outputImageSizeY, images[0].format()); imageOut.fill(backgroundColorRGB); // // Loop through the images // int rowCounter = 0; int columnCounter = 0; for (int i = 0; i < numImages; i++) { // // Scale image // const QImage imageScaled = images[i].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, imageOut, positionX, positionY); } catch (FileException& e) { std::cout << "QImageFile::insertImage() error: " << e.whatQString().toAscii().constData() << std::endl; } // // Update row and column counters // columnCounter++; if (columnCounter >= numImagesPerRow) { columnCounter = 0; rowCounter++; } } } /** * read the file (overridden since file has no header). */ void ImageFile::readFile(const QString& fileNameIn) throw (FileException) { clear(); if (fileNameIn.isEmpty()) { throw FileException(fileNameIn, "Filename for reading is isEmpty"); } filename = fileNameIn; if (image.load(filename) == false) { throw FileException(filename, "Unable to load file."); } QTime timer; timer.start(); if (DebugControl::getDebugOn()) { std::cout << "Time to read " << FileUtilities::basename(filename).toAscii().constData() << " was " << (static_cast(timer.elapsed()) / 1000.0) << " seconds." << std::endl; } clearModified(); } /** * append an image file to the bottom of this image file. */ void ImageFile::appendImageAtBottom(const ImageFile& img) { // // Determine size of new image // const QImage* otherImage = img.getImage(); const int newWidth = std::max(image.width(), otherImage->width()); const int newHeight = image.height() + otherImage->height(); const int oldHeight = image.height(); // // Copy the current image // const QImage currentImage = image; if (DebugControl::getDebugOn()) { 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); if (DebugControl::getDebugOn()) { std::cout << "nw: " << newImage.width() << std::endl; std::cout << "nh: " << newImage.height() << std::endl; } setImage(newImage); if (DebugControl::getDebugOn()) { 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); setModified(); } /** * insert an image into this image which must be large enough for insertion of image. */ void ImageFile::insertImage(const QImage& otherImage, const int x, const int y) throw (FileException) { if (x < 0) { throw FileException("X position is less than zero."); } if (y < 0) { throw FileException("Y position is less than zero."); } const int otherWidth = otherImage.width(); const int otherHeight = otherImage.height(); const int myWidth = image.width(); const int myHeight = image.height(); if ((otherWidth + x) > myWidth) { throw FileException("This image is not large enough to insert other image."); } if ((otherHeight + y) > myHeight) { throw FileException("This image is not large enough to insert other image."); } for (int i = 0; i < otherWidth; i++) { for (int j = 0; j < otherHeight; j++) { image.setPixel(x + i, y + j, otherImage.pixel(i, j)); } } setModified(); } /** * insert an image into another image. */ void ImageFile::insertImage(const QImage& insertThisImage, QImage& intoThisImage, const int positionX, const int positionY) throw (FileException) { if (positionX < 0) { throw FileException("X position is less than zero."); } if (positionY < 0) { throw FileException("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 FileException("This image is not large enough to insert other image."); } if ((otherHeight + positionY) > myHeight) { throw FileException("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)); } } } /** * compare a file for unit testing (tolerance ignored). */ bool ImageFile::compareFileForUnitTesting(const AbstractFile* af, const float tolerance, QString& messageOut) const { // // Cast to an image file // const ImageFile* img = dynamic_cast(af); if (img == NULL) { messageOut = ("ERROR: File for comparison (" + af->getFileName() + " does not appear to be an image file."); return false; } // // Get the image from the other file // const QImage* otherImage = img->getImage(); // // Confirm width/height // const int width = image.width(); const int height = 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 = 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 file. */ void ImageFile::writeFile(const QString& fileNameIn) throw (FileException) { if (fileNameIn.isEmpty()) { throw FileException(fileNameIn, "Filename for reading is isEmpty"); } filename = fileNameIn; QString errorMessage; if (image.width() <= 0) { errorMessage = "Image width is zero."; } if (image.height() <= 0) { if (errorMessage.isEmpty() == false) errorMessage += "\n"; errorMessage = "Image height is zero."; } if (errorMessage.isEmpty() == false) { throw FileException(FileUtilities::basename(filename) + " " + errorMessage); } QString format(StringUtilities::makeUpperCase(FileUtilities::filenameExtension(filename))); if (format == "JPG") { format = "JPEG"; } QImageWriter writer(filename); writer.setFormat(format.toAscii().constData()); writer.setFileName(filename); if (writer.write(image) == false) { throw FileException(writer.errorString()); } //image.save(filename, format.toAscii().constData()); // // Update file permissions ? // if (getFileWritePermissions() != 0) { QFile::setPermissions(filename, getFileWritePermissions()); } clearModified(); } /** * Read the vtk model file data (should never be called). */ void ImageFile::readFileData(QFile& /*file*/, QTextStream& /*stream*/, QDataStream&, QDomElement& /* rootElement */) throw (FileException) { throw FileException(filename, "Program Error: ImageFile::readFileData should never be called."); } /** * Write the vtk model file data (should never be called). */ void ImageFile::writeFileData(QTextStream& /*stream*/, QDataStream&, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException) { throw FileException(filename, "Program Error: ImageFile::writeFileData should never be called."); } caret-5.6.4~dfsg.1.orig/caret_files/GiftiNodeDataFile.h0000664000175000017500000002243611572067322022463 0ustar michaelmichael#ifndef __GIFTI_NODE_DATA_FILE_H__ #define __GIFTI_NODE_DATA_FILE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "GiftiDataArrayFile.h" #include "StudyMetaDataLinkSet.h" /// This abstract class defines some variables and methods used for node data files. class GiftiNodeDataFile : public GiftiDataArrayFile { public: /// deformation type enum DEFORM_TYPE { DEFORM_NEAREST_NODE, DEFORM_TILE_AVERAGE }; /// append column index values enum APPEND_COLUMN_INDEX { APPEND_COLUMN_NEW = -1, APPEND_COLUMN_DO_NOT_LOAD = -2 }; // destructor virtual ~GiftiNodeDataFile(); // add a data array virtual void addDataArray(GiftiDataArray* nda); // append a data array file to this one virtual void append(const GiftiDataArrayFile& naf) throw (FileException); // 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 GiftiDataArrayFile& naf, std::vector& indexDestination, const FILE_COMMENT_MODE fcm) throw (FileException); // add columns to this node data file void addColumns(const int numberOfNewColumns, const int numberOfNodes = -1) throw (FileException); // add nodes to this file void addNodes(const int numberOfNodesToAdd); // Clear the node data file. virtual void clear(); // deform "this" node data file placing the output in "deformedFile". void deform(const DeformationMapFile& dmf, GiftiNodeDataFile& deformedFile, const DEFORM_TYPE dt) const throw (FileException); /// get the number of nodes in the file virtual int getNumberOfNodes() const; /// get the number of columns in the file virtual int getNumberOfColumns() const { return dataArrays.size(); } /// set the number of nodes and columns in the file virtual void setNumberOfNodesAndColumns(const int numNodes, const int numCols, const int numElementsPerCol = 1); /// reset a column of data void resetColumn(const int columnNumber); /// remove a column of data void removeColumn(const int columnNumber); /// reset a data array virtual void resetDataArray(const int arrayIndex); /// remove a data array virtual void removeDataArray(const int arrayIndex); // get all of the column names void getAllColumnNames(std::vector& names) const; // get the specified columns name QString getColumnName(const int col) const; // get the index of the column with the specified name int getColumnWithName(const QString& n) const; // get a node attribute file column number where input may be a column // name or number. Input numbers range 1..N and output column // numbers range 0..(N-1) int getColumnFromNameOrNumber(const QString& columnNameOrNumber, const bool addColumnIfNotFound) throw (FileException); // get the comment for a column QString getColumnComment(const int col) const; // set the name of a column void setColumnName(const int col, const QString& name); // set the comment for a column void setColumnComment(const int col, const QString& comm); // append to the comment for a column void appendToColumnComment(const int col, const QString& comm); // prepend to the comment for a column void prependToColumnComment(const int col, const QString& comm); /// get PubMedID's of all linked studies void getPubMedIDsOfAllLinkedStudyMetaData(std::vector& studyPMIDs) const; // get the study metadata link for a column StudyMetaDataLinkSet getColumnStudyMetaDataLinkSet(const int col) const; // set the study metadata link for a column void setColumnStudyMetaDataLinkSet(const int col, const StudyMetaDataLinkSet smdls); // transfer file data for deformation void transferFileDataForDeformation(const DeformationMapFile& dmf, GiftiNodeDataFile& destinationFile) const; // check for columns with the same name (returns true if there are any) bool checkForColumnsWithSameName(std::vector& multipleColumnNames) const; /// find out if comma separated file conversion supported virtual void getCommaSeparatedFileSupport(bool& readFromCSV, bool& writeToCSV) const; /// write the file's data into a comma separated values file (throws exception if not supported) virtual void writeDataIntoCommaSeparatedValueFile(CommaSeparatedValueFile& csv) throw (FileException); /// read the file's data from a comma separated values file (throws exception if not supported) virtual void readDataFromCommaSeparatedValuesTable(const CommaSeparatedValueFile& csv) throw (FileException); protected: /// constructor GiftiNodeDataFile(const QString& descriptiveName, const QString& giftiElementNameIn, const GiftiDataArray::DATA_TYPE defaultDataTypeIn, const int numberOfElementsPerColumnIn = 1, const QString& defaultExt = "", const FILE_FORMAT defaultWriteTypeIn = FILE_FORMAT_ASCII, const FILE_IO supportsAsciiFormat = FILE_IO_READ_AND_WRITE, const FILE_IO supportsBinaryFormat = FILE_IO_NONE, const FILE_IO supportsOtherFormat = FILE_IO_NONE, const FILE_IO supportsCSVfFormat = FILE_IO_NONE, const bool dataAreIndicesIntoLabelTableIn = false); // copy constructor GiftiNodeDataFile(const GiftiNodeDataFile& nndf); // assignment operator GiftiNodeDataFile& operator=(const GiftiNodeDataFile& nndf); // copy helper void copyHelperGiftiNodeDataFile(const GiftiNodeDataFile& nndf); /// deform "this" node data file placing the output in "deformedFile". virtual void deformFile(const DeformationMapFile& dmf, GiftiNodeDataFile& deformedFile, const DEFORM_TYPE dt) const throw (FileException) = 0; /// read legacy file format data virtual void readLegacyFileData(QFile& file, QTextStream& stream, QDataStream& binStream) throw (FileException); /// write legacy file format data virtual void writeLegacyFileData(QTextStream& stream, QDataStream& binStream) throw (FileException); /// read legacy file format data virtual void readLegacyNodeFileData(QFile& file, QTextStream& stream, QDataStream& binStream) throw (FileException) = 0; /// write legacy file format data virtual void writeLegacyNodeFileData(QTextStream& stream, QDataStream& binStream) throw (FileException) = 0; /// number of elements per column int numberOfElementsPerColumn; /// legacy format tag names static const QString tagColumnName; /// legacy format tag names static const QString tagColumnComment; // legacy format tag names static const QString tagColumnStudyMetaData; /// legacy format tag names static const QString tagNumberOfNodes; /// legacy format tag names static const QString tagNumberOfColumns; }; #endif // __GIFTI_NODE_DATA_FILE_H__ #ifdef __GIFTI_NODE_DATA_FILE_MAIN_H__ const QString GiftiNodeDataFile::tagColumnName = "tag-column-name"; const QString GiftiNodeDataFile::tagColumnComment = "tag-column-comment"; const QString GiftiNodeDataFile::tagColumnStudyMetaData = "tag-column-study-meta-data"; const QString GiftiNodeDataFile::tagNumberOfNodes = "tag-number-of-nodes"; const QString GiftiNodeDataFile::tagNumberOfColumns = "tag-number-of-columns"; #endif // __GIFTI_NODE_DATA_FILE_MAIN_H__ caret-5.6.4~dfsg.1.orig/caret_files/GiftiNodeDataFile.cxx0000664000175000017500000005765411572067322023050 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #define __GIFTI_NODE_DATA_FILE_MAIN_H__ #include "GiftiNodeDataFile.h" #undef __GIFTI_NODE_DATA_FILE_MAIN_H__ #include "CommaSeparatedValueFile.h" #include "CoordinateFile.h" #include "DeformationMapFile.h" #include "FileUtilities.h" #include "GiftiCommon.h" #include "StringTable.h" #include "StringUtilities.h" static const QString studyLinkMetaDataTag("tagStudyMetaDataLink"); static const QString studyLinkSetMetaDataTag("tagStudyMetaDataLinkSet"); /** * Constructor */ GiftiNodeDataFile::GiftiNodeDataFile(const QString& descriptiveName, const QString& defaultDataArrayCategoryIn, const GiftiDataArray::DATA_TYPE defaultDataTypeIn, const int numberOfComponentsPerColumnIn, const QString& defaultExt, const FILE_FORMAT defaultWriteTypeIn, const FILE_IO supportsAsciiFormat, const FILE_IO supportsBinaryFormat, const FILE_IO supportsOtherFormat, const FILE_IO supportsCSVfFormat, const bool dataAreIndicesIntoLabelTableIn) : GiftiDataArrayFile(descriptiveName, defaultDataArrayCategoryIn, defaultDataTypeIn, defaultExt, defaultWriteTypeIn, supportsAsciiFormat, supportsBinaryFormat, supportsOtherFormat, supportsCSVfFormat, dataAreIndicesIntoLabelTableIn) { numberOfElementsPerColumn = numberOfComponentsPerColumnIn; } /** * copy constructor. */ GiftiNodeDataFile::GiftiNodeDataFile(const GiftiNodeDataFile& nndf) : GiftiDataArrayFile(nndf) { copyHelperGiftiNodeDataFile(nndf); } /** * assignment operator. */ GiftiNodeDataFile& GiftiNodeDataFile::operator=(const GiftiNodeDataFile& nndf) { if (this != &nndf) { GiftiDataArrayFile::operator=(nndf); copyHelperGiftiNodeDataFile(nndf); } return *this; } /** * copy helper. */ void GiftiNodeDataFile::copyHelperGiftiNodeDataFile(const GiftiNodeDataFile& nndf) { numberOfElementsPerColumn = nndf.numberOfElementsPerColumn; } /** * Destructor */ GiftiNodeDataFile::~GiftiNodeDataFile() { clear(); } /** * Set the name of a data column. */ void GiftiNodeDataFile::setColumnName(const int col, const QString& name) { setDataArrayName(col, name); } /** * get a node attribute file column number where input may be a column * name or number. Input numbers range 1..N and output column * numbers range 0..(N-1). */ int GiftiNodeDataFile::getColumnFromNameOrNumber(const QString& columnNameOrNumber, const bool addColumnIfNotFound) throw (FileException) { // // Try number first // // // To see if it is a number, simply convert to int and check for success // bool ok = false; const int columnNumber = columnNameOrNumber.toInt(&ok); if (ok) { if ((columnNumber > 0) && (columnNumber <= getNumberOfColumns())) { return (columnNumber - 1); } else { if (addColumnIfNotFound && columnNumber - getNumberOfColumns() < 2) {//only add column if integer specifies exactly one column further if (getNumberOfNodes() > 0) { addColumns(1); const int col = getNumberOfColumns() - 1; setColumnName(col, "new column"); return col; } else { setNumberOfNodesAndColumns(1, 1);//will not accept 0 for either argument setColumnName(0, "new column"); return 0; } }//if add flag is false, it tries to find it as a column name } } // // Try Name // const int numCols = getNumberOfColumns(); for (int i = 0; i < numCols; i++) { const QString name = getColumnName(i); if (name == columnNameOrNumber) { return i; } } // // Add column if there are nodes // if (addColumnIfNotFound) { if (getNumberOfNodes() > 0) { addColumns(1); const int col = getNumberOfColumns() - 1; setColumnName(col, columnNameOrNumber); return col; } else { setNumberOfNodesAndColumns(1, 1);//will not accept 0 for either argument setColumnName(0, columnNameOrNumber); return 0; } } // // failed to find // throw FileException("ERROR column name/number " + columnNameOrNumber + " not found in file " + FileUtilities::basename(getFileName())); } /** * Get the column index for a column with the specified name. If the * name is not found a negative number is returned. */ int GiftiNodeDataFile::getColumnWithName(const QString& n) const { return getDataArrayWithNameIndex(n); } /** * Get the name for a column. */ QString GiftiNodeDataFile::getColumnName(const int col) const { if ((col >= 0) && (col < getNumberOfDataArrays())) { return getDataArrayName(col); } return ""; } /** * Set the comment for a data column. */ void GiftiNodeDataFile::setColumnComment(const int col, const QString& comm) { setDataArrayComment(col, comm); } /** * Append to the comment for a data column. */ void GiftiNodeDataFile::appendToColumnComment(const int col, const QString& comm) { appendToDataArrayComment(col, comm); } /** * Prepend to the comment for a data column. */ void GiftiNodeDataFile::prependToColumnComment(const int col, const QString& comm) { prependToDataArrayComment(col, comm); } /** * Get the comment for a column. */ QString GiftiNodeDataFile::getColumnComment(const int col) const { return getDataArrayComment(col); } /** * get indices to all linked studies. */ void GiftiNodeDataFile::getPubMedIDsOfAllLinkedStudyMetaData(std::vector& studyPMIDs) const { std::set pmidSet; const int numColumns= getNumberOfColumns(); for (int i = 0; i < numColumns; i++) { const StudyMetaDataLinkSet smdl = getColumnStudyMetaDataLinkSet(i); std::vector pmids; smdl.getAllLinkedPubMedIDs(pmids); pmidSet.insert(pmids.begin(), pmids.end()); } studyPMIDs.clear(); studyPMIDs.insert(studyPMIDs.end(), pmidSet.begin(), pmidSet.end()); } /** * get the study metadata link set for a column. */ StudyMetaDataLinkSet GiftiNodeDataFile::getColumnStudyMetaDataLinkSet(const int columnNumber) const { StudyMetaDataLinkSet smdls; if ((columnNumber >= 0) && (columnNumber < getNumberOfDataArrays())) { QString s; if (dataArrays[columnNumber]->getMetaData()->get(studyLinkSetMetaDataTag, s)) { smdls.setLinkSetFromCodedText(s); } if (dataArrays[columnNumber]->getMetaData()->get(studyLinkMetaDataTag, s)) { StudyMetaDataLink smdl; smdl.setLinkFromCodedText(s); smdls.addStudyMetaDataLink(smdl); } } return smdls; } /** * set the study metadata link for a column. */ void GiftiNodeDataFile::setColumnStudyMetaDataLinkSet(const int columnNumber, const StudyMetaDataLinkSet smdls) { if ((columnNumber >= 0) && (columnNumber < getNumberOfDataArrays())) { const QString s = smdls.getLinkSetAsCodedText(); dataArrays[columnNumber]->getMetaData()->set(studyLinkSetMetaDataTag, s); setModified(); } } /** * */ void GiftiNodeDataFile::clear() { GiftiDataArrayFile::clear(); } /** * transfer file data. */ void GiftiNodeDataFile::transferFileDataForDeformation(const DeformationMapFile& dmf, GiftiNodeDataFile& destinationFile) const { /* destinationFile.setFileTitle(getFileTitle()); QString comment("Deformed from: "); comment.append(FileUtilities::basename(getFileName())); comment.append("\n"); comment.append("Deformed with: "); comment.append(FileUtilities::basename(dmf.getFileName())); comment.append("\n"); comment.append(getFileComment()); destinationFile.setFileComment(comment); */ for (int j = 0; j < getNumberOfColumns(); j++) { GiftiDataArray* destDataArray = destinationFile.getDataArray(j); const GiftiDataArray* myDataArray = getDataArray(j); destDataArray->setMetaData(myDataArray->getMetaData()); } for (int j = 0; j < getNumberOfColumns(); j++) { QString name(dmf.getDeformedColumnNamePrefix()); name.append(getColumnName(j)); destinationFile.setColumnName(j, name); QString comment(getColumnComment(j)); if (comment.isEmpty() == false) { comment.append("\n"); } comment.append("Deformed with: "); comment.append(FileUtilities::basename(dmf.getFileName())); destinationFile.setColumnComment(j, comment); } } /** * Deform the metric file */ void GiftiNodeDataFile::deform(const DeformationMapFile& dmf, GiftiNodeDataFile& deformedFile, const DEFORM_TYPE dt) const throw (FileException) { // // Check deformation file to make sure it contains data // if (dmf.getNumberOfNodes() <= 0) { throw FileException("Deformation map file is isEmpty."); } // // Check "this" data file to make sure it has data // if ((getNumberOfNodes() <= 0) || (getNumberOfColumns() <= 0)) { QString msg(filename); msg.append(" is isEmpty."); throw FileException(msg); } // // Make sure deformation map will work with this data file // int maxNodeNum = -1; const int numNodes = dmf.getNumberOfNodes(); for (int i = 0; i < numNodes; i++) { int nodes[3]; float areas[3]; dmf.getDeformDataForNode(i, nodes, areas); maxNodeNum = std::max(maxNodeNum, nodes[0]); maxNodeNum = std::max(maxNodeNum, nodes[1]); maxNodeNum = std::max(maxNodeNum, nodes[2]); } if (maxNodeNum >= getNumberOfNodes()) { std::ostringstream str; str << filename.toAscii().constData() << "\n has " << getNumberOfNodes() << " nodes but deformation map expects it to have at least " << maxNodeNum << " nodes."; throw FileException(str.str().c_str()); } // // Deform the data file. // deformFile(dmf, deformedFile, dt); } /** * check for columns with the same name (returns true if there are any). */ bool GiftiNodeDataFile::checkForColumnsWithSameName(std::vector& multipleColumnNames) const { checkForDataArraysWithSameName(multipleColumnNames); return (multipleColumnNames.size() > 0); } /** * add a data array. */ void GiftiNodeDataFile::addDataArray(GiftiDataArray* nda) { GiftiDataArrayFile::addDataArray(nda); } /** * append a data array file to this one. */ void GiftiNodeDataFile::append(const GiftiDataArrayFile& naf) throw (FileException) { GiftiDataArrayFile::append(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) * "indexDestination" will be updated with the columns actually used. */ void GiftiNodeDataFile::append(const GiftiDataArrayFile& naf, std::vector& indexDestination, const FILE_COMMENT_MODE fcm) throw (FileException) { GiftiDataArrayFile::append(naf, indexDestination, fcm); } /** * add columns to this node data file. * If the number of nodes is less than zero the number of nodes in the * first dataColumn is used. */ void GiftiNodeDataFile::addColumns(const int numberOfNewColumns, const int numberOfNodesIn) throw (FileException) { int numNodes = numberOfNodesIn; if (numNodes < 0) { if (dataArrays.empty() == false) { numNodes = dataArrays[0]->getNumberOfRows(); } } if (numNodes <= 0) { throw FileException("Cannot append file, number of nodes is unknown."); } std::vector dim; dim.push_back(numNodes); if (numberOfElementsPerColumn > 1) { dim.push_back(numberOfElementsPerColumn); } for (int i = 0; i < numberOfNewColumns; i++) { addDataArray(new GiftiDataArray(this, getDefaultDataArrayIntent(), defaultDataType, dim)); } setModified(); } /** * get the number of nodes in the file. */ int GiftiNodeDataFile::getNumberOfNodes() const { if (dataArrays.empty()) { return 0; } return dataArrays[0]->getNumberOfRows(); } /** * add nodes to this file. */ void GiftiNodeDataFile::addNodes(const int numberOfNodesToAdd) { if (numberOfNodesToAdd > 0) { if (dataArrays.empty()) { std::vector dim; dim.push_back(numberOfNodesToAdd); dim.push_back(numberOfElementsPerColumn); addDataArray(new GiftiDataArray(this, getDefaultDataArrayIntent(), defaultDataType, dim)); setModified(); } else { addRows(numberOfNodesToAdd); } } } /** * get all of the column names. */ void GiftiNodeDataFile::getAllColumnNames(std::vector& names) const { getAllArrayNames(names); } /** * set the number of nodes and columns in the file. */ void GiftiNodeDataFile::setNumberOfNodesAndColumns(const int numNodes, const int numCols, const int numElementsPerCol) { const int nc = getNumberOfColumns(); for (int i = 0; i < nc; i++) { delete dataArrays[i]; } dataArrays.clear(); numberOfElementsPerColumn = numElementsPerCol; if ((numCols > 0) && (numNodes > 0)){ addColumns(numCols, numNodes); } setModified(); } /** * reset a data array. */ void GiftiNodeDataFile::resetDataArray(const int arrayIndex) { GiftiDataArrayFile::resetDataArray(arrayIndex); } /** * remove a data array. */ void GiftiNodeDataFile::removeDataArray(const int arrayIndex) { GiftiDataArrayFile::removeDataArray(arrayIndex); } /** * reset a column of data. */ void GiftiNodeDataFile::resetColumn(const int columnNumber) { resetDataArray(columnNumber); } /** * remove a column of data. */ void GiftiNodeDataFile::removeColumn(const int columnNumber) { removeDataArray(columnNumber); } /** * find out if comma separated file conversion supported. */ void GiftiNodeDataFile::getCommaSeparatedFileSupport(bool& readFromCSV, bool& writeToCSV) const { readFromCSV = true; writeToCSV = true; readFromCSV = true; writeToCSV = true; } /** * write the file's data into a comma separated values file (throws exception if not supported). */ void GiftiNodeDataFile::writeDataIntoCommaSeparatedValueFile(CommaSeparatedValueFile& csv) throw (FileException) { csv.clear(); const int numNodes = getNumberOfNodes(); const int numFileCols = getNumberOfColumns(); if ((numNodes <= 0) || (numFileCols <= 0)) { return; } // // Determine number columns including multiple elements per column // int numCols = 0; for (int j = 0; j < numFileCols; j++) { const GiftiDataArray* gda = getDataArray(j); numCols += gda->getNumberOfComponents(); } // // Create and add to string table // StringTable* ct = new StringTable(numNodes, numCols, "Data"); int colIndex = 0; for (int j = 0; j < numFileCols; j++) { const GiftiDataArray* gda = getDataArray(j); for (int k = 0; k < gda->getNumberOfComponents(); k++) { ct->setColumnTitle(colIndex, getColumnName(j)); colIndex++; } } // // See if this is a coordinate file // const bool coordFileFlag = (dynamic_cast(this) != NULL); if (coordFileFlag) { if (colIndex == 3) { ct->setColumnTitle(0, "X"); ct->setColumnTitle(1, "Y"); ct->setColumnTitle(2, "Z"); } } colIndex = 0; for (int j = 0; j < numFileCols; j++) { const GiftiDataArray* gda = getDataArray(j); const int numComp = gda->getNumberOfComponents(); switch (gda->getDataType()) { case GiftiDataArray::DATA_TYPE_FLOAT32: { const float* data = gda->getDataPointerFloat(); for (int i = 0; i < numNodes; i++) { for (int k = 0; k < numComp; k++) { ct->setElement(i, colIndex + k, data[i*numComp+k]); } } } break; case GiftiDataArray::DATA_TYPE_INT32: { const int32_t* data = gda->getDataPointerInt(); for (int i = 0; i < numNodes; i++) { for (int k = 0; k < numComp; k++) { ct->setElement(i, colIndex + k, data[i*numComp+k]); } } } break; case GiftiDataArray::DATA_TYPE_UINT8: { const uint8_t* data = gda->getDataPointerUByte(); for (int i = 0; i < numNodes; i++) { for (int k = 0; k < numComp; k++) { ct->setElement(i, colIndex + k, data[i*numComp+k]); } } } break; } colIndex += numComp; } // // Header // StringTable* headerTable = new StringTable(0, 0); writeHeaderDataIntoStringTable(*headerTable); csv.addDataSection(headerTable); // // Labels // if (getLabelTable()->getNumberOfLabels() > 0) { StringTable* tableOfLabels = new StringTable(0, 0); getLabelTable()->writeDataIntoStringTable(*tableOfLabels); csv.addDataSection(tableOfLabels); } // // Column metadata // for (int i = 0; i < numFileCols; i++) { const GiftiDataArray* gda = getDataArray(i); StringTable* mt = new StringTable(0, 0); gda->getMetaData()->writeDataIntoStringTable(*mt); csv.addDataSection(mt); } csv.addDataSection(ct); } /** * read the file's data from a comma separated values file (throws exception if not supported). */ void GiftiNodeDataFile::readDataFromCommaSeparatedValuesTable(const CommaSeparatedValueFile& csv) throw (FileException) { clear(); const StringTable* dt = csv.getDataSectionByName("Data"); if (dt == NULL) { throw FileException("No data found."); } int numNodes = dt->getNumberOfRows(); int numCols = dt->getNumberOfColumns(); if ((numNodes <= 0) || (numCols <= 0)) { throw FileException("Number of rows or columns is zero."); } setNumberOfNodesAndColumns(numNodes, numCols); std::vector columnNames(numCols, ""); for (int j = 0; j < numCols; j++) { GiftiDataArray* gda = getDataArray(j); columnNames[j] = dt->getColumnTitle(j); switch (gda->getDataType()) { case GiftiDataArray::DATA_TYPE_FLOAT32: { float* data = gda->getDataPointerFloat(); for (int i = 0; i < numNodes; i++) { data[i] = dt->getElementAsFloat(i, j); } } break; case GiftiDataArray::DATA_TYPE_INT32: { int32_t* data = gda->getDataPointerInt(); for (int i = 0; i < numNodes; i++) { data[i] = dt->getElementAsInt(i, j); } } break; case GiftiDataArray::DATA_TYPE_UINT8: { uint8_t* data = gda->getDataPointerUByte(); for (int i = 0; i < numNodes; i++) { data[i] = dt->getElementAsInt(i, j); } } break; } } // // Do header // const StringTable* stHeader = csv.getDataSectionByName("header"); if (stHeader != NULL) { readHeaderDataFromStringTable(*stHeader); } // // Labels // const StringTable* stLabels = csv.getDataSectionByName(GiftiCommon::tagLabelTable); if (stLabels != NULL) { GiftiLabelTable* labels = getLabelTable(); labels->readDataFromStringTable(*stLabels); } // // Look for metadata Match metadata "Name" with table data column name // for (int i = 0; i < csv.getNumberOfDataSections(); i++) { const StringTable* st = csv.getDataSection(i); if (st->getTableTitle() == GiftiCommon::tagMetaData) { GiftiMetaData gmd; gmd.readDataFromStringTable(*st); QString name; if (gmd.get("Name", name)) { for (int j = 0; j < numCols; j++) { if (name == columnNames[j]) { GiftiMetaData* metaData = getDataArray(j)->getMetaData(); *metaData = gmd; } } } } } } /** * read legacy file format data. */ void GiftiNodeDataFile::readLegacyFileData(QFile& file, QTextStream& stream, QDataStream& binStream) throw (FileException) { bool dataWasRead = false; switch (getFileReadType()) { case FILE_FORMAT_ASCII: break; case FILE_FORMAT_BINARY: break; case FILE_FORMAT_XML: break; case FILE_FORMAT_XML_BASE64: break; case FILE_FORMAT_XML_GZIP_BASE64: break; case FILE_FORMAT_XML_EXTERNAL_BINARY: break; case FILE_FORMAT_OTHER: break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: { CommaSeparatedValueFile csvf; csvf.readFromTextStream(file, stream); readDataFromCommaSeparatedValuesTable(csvf); dataWasRead = true; } break; } if (dataWasRead == false) { readLegacyNodeFileData(file, stream, binStream); } } /** * write legacy file format data. */ void GiftiNodeDataFile::writeLegacyFileData(QTextStream& stream, QDataStream& binStream) throw (FileException) { bool dataWasWritten = false; switch (getFileWriteType()) { case FILE_FORMAT_ASCII: break; case FILE_FORMAT_BINARY: break; case FILE_FORMAT_XML: break; case FILE_FORMAT_XML_BASE64: break; case FILE_FORMAT_XML_GZIP_BASE64: break; case FILE_FORMAT_XML_EXTERNAL_BINARY: break; case FILE_FORMAT_OTHER: break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: { CommaSeparatedValueFile csvf; writeDataIntoCommaSeparatedValueFile(csvf); csvf.writeToTextStream(stream); dataWasWritten = true; } break; } if (dataWasWritten == false) { writeLegacyNodeFileData(stream, binStream); } } caret-5.6.4~dfsg.1.orig/caret_files/GiftiMetaData.h0000664000175000017500000001046711572067322021665 0ustar michaelmichael #ifndef __GIFTI_META_DATA_H__ #define __GIFTI_META_DATA_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include "FileException.h" class AbstractFile; class StringTable; class QTextStream; /// class for GIFTI metadata class GiftiMetaData { public: /// container for metadata typedef std::map MetaDataContainer; /// iterator for metadata typedef MetaDataContainer::iterator MetaDataIterator; /// const iterator for metadata typedef MetaDataContainer::const_iterator ConstMetaDataIterator; // constructor GiftiMetaData(); // copy constructor GiftiMetaData(const GiftiMetaData& nmd); // destructor ~GiftiMetaData(); // assignment operator GiftiMetaData& operator=(const GiftiMetaData& nmd); // clear the metadata void clear(); // get all of the meta data "names" of the name/value pairs void getAllNames(std::vector& allNames) const; /// get the metadata const MetaDataContainer* getMetaData() const { return &metaData; } // get metadata as string (returns true if found) bool get(const QString& name, QString& value) const; // set metadata as string void set(const QString& name, const QString& value); // get metadata as int (returns true if found) bool get(const QString& name, int32_t& value) const; // get metadata as vector of ints (returns true if found) bool get(const QString& name, std::vector& values) const; // set metadata as int void set(const QString& name, const int32_t value); // set metadata as vector of ints void set(const QString& name, const std::vector& values); // get metadata as float (returns true if found) bool get(const QString& name, float& value) const; // get metadata as vector of float (returns true if found) bool get(const QString& name, std::vector& values) const; // set metadata as float void set(const QString& name, const float value); // set metadata as vector of float void set(const QString& name, const std::vector& values); /// remove a metadata element void remove(const QString& name); /// metadata name element static QString getMetaDataName() { return "Name"; } /// metadata description element static QString getMetaDataDescription() { return "Description"; } // write metadata void writeAsXML(QTextStream& stream, const int indentOffset) const; /// write the data into a StringTable void writeDataIntoStringTable(StringTable& table) const; /// read the data from a StringTable void readDataFromStringTable(const StringTable& table) throw (FileException); /// copy the metadata from a caret file void copyMetaDataFromCaretFile(const AbstractFile* af); /// copy the metadata into a caret file void copyMetaDataToCaretFile(AbstractFile* af) const; protected: // copy helper used by copy constructor and assignment operator void copyHelperGiftiMetaData(const GiftiMetaData& nmd); /// the meta data MetaDataContainer metaData; }; #endif // __GIFTI_META_DATA_H__ caret-5.6.4~dfsg.1.orig/caret_files/GiftiMetaData.cxx0000664000175000017500000002226311572067322022235 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include "AbstractFile.h" #include "GiftiCommon.h" #include "GiftiMetaData.h" #include "StringTable.h" #include "StringUtilities.h" /** * constructor. */ GiftiMetaData::GiftiMetaData() { clear(); } /** * copy constructor. */ GiftiMetaData::GiftiMetaData(const GiftiMetaData& nmd) { copyHelperGiftiMetaData(nmd); } /** * destructor. */ GiftiMetaData::~GiftiMetaData() { clear(); } /** * assignment operator. */ GiftiMetaData& GiftiMetaData::operator=(const GiftiMetaData& nmd) { if (this != &nmd) { copyHelperGiftiMetaData(nmd); } return *this; } /** * copy helper used by copy constructor and assignment operator. */ void GiftiMetaData::copyHelperGiftiMetaData(const GiftiMetaData& nmd) { metaData = nmd.metaData; } /** * clear the metadata. */ void GiftiMetaData::clear() { metaData.clear(); } /** * get metadata as string (returns true if found). */ bool GiftiMetaData::get(const QString& name, QString& value) const { const QString nameLower(name.toLower()); for (ConstMetaDataIterator iter = metaData.begin(); iter != metaData.end(); iter++) { QString tagLower = iter->first.toLower(); // std::cout << "Comparing \"" // << nameLower.toAscii().constData() // << "\" to \"" // << tagLower.toAscii().constData() // << "\"." // << std::endl; if (nameLower == tagLower) { //std::cout << "Found \"" // << nameLower.toAscii().constData() // << "\"" // << std::endl; value = iter->second; return true; } } /* ConstMetaDataIterator iter = metaData.find(name); if (iter != metaData.end()) { value = iter->second; return true; } */ return false; } /** * set metadata as string. */ void GiftiMetaData::set(const QString& name, const QString& value) { const QString nameLower(name.toLower()); // // Since case may vary, remove matching item // for (MetaDataIterator iter = metaData.begin(); iter != metaData.end(); iter++) { const QString tagName(iter->first); const QString tagNameLower(tagName.toLower()); if (nameLower == tagNameLower) { metaData.erase(iter); break; } } metaData[name] = value; } /** * get metadata as int (returns true if found). */ bool GiftiMetaData::get(const QString& name, int32_t& value) const { QString s; if (get(name, s)) { StringUtilities::toNumber(s, value); return true; } return false; } /** * get metadata as vector of ints (returns true if found). */ bool GiftiMetaData::get(const QString& name, std::vector& values) const { QString md; if (get(name, md)) { StringUtilities::token(md, " \t", values); return true; } return false; } /** * set metadata as int. */ void GiftiMetaData::set(const QString& name, const int32_t value) { metaData[name] = StringUtilities::fromNumber(value); } /** * set metadata as vector of ints. */ void GiftiMetaData::set(const QString& name, const std::vector& values) { metaData[name] = StringUtilities::combine(values, " "); } /** * remove a metadata element. */ void GiftiMetaData::remove(const QString& name) { metaData.erase(name); } /** * get metadata as float (returns true if found). */ bool GiftiMetaData::get(const QString& name, float& value) const { QString s; if (get(name, s)) { StringUtilities::toNumber(s, value); return true; } return false; } /** * get metadata as vector of float (returns true if found). */ bool GiftiMetaData::get(const QString& name, std::vector& values) const { QString md; if (get(name, md)) { StringUtilities::token(md, " \t", values); return true; } return false; } /** * set metadata as float. */ void GiftiMetaData::set(const QString& name, const float value) { metaData[name] = StringUtilities::fromNumber(value); } /** * set metadata as vector of float. */ void GiftiMetaData::set(const QString& name, const std::vector& values) { metaData[name] = StringUtilities::combine(values, " "); } /** * write metadata (used by other classes so static). */ void GiftiMetaData::writeAsXML(QTextStream& stream, const int indentOffset) const { int indent = indentOffset; if (metaData.empty()) { GiftiCommon::writeIndentationXML(stream, indent); stream << "<" << GiftiCommon::tagMetaData << "/>" << "\n"; } else { GiftiCommon::writeIndentationXML(stream, indent); stream << "<" << GiftiCommon::tagMetaData << ">" << "\n"; indent++; for (ConstMetaDataIterator iter = metaData.begin(); iter != metaData.end(); iter++) { GiftiCommon::writeIndentationXML(stream, indent); stream << "<" << GiftiCommon::tagMD << ">" << "\n"; indent++; GiftiCommon::writeIndentationXML(stream, indent); stream << "<" << GiftiCommon::tagName << ">first << "]]>" << "\n"; GiftiCommon::writeIndentationXML(stream, indent); stream << "<" << GiftiCommon::tagValue << ">second << "]]>" << "\n"; indent--; GiftiCommon::writeIndentationXML(stream, indent); stream << "" << "\n"; } indent--; GiftiCommon::writeIndentationXML(stream, indent); stream << "" << "\n"; } } /** * get all of the meta data "names" of the name/value pairs. */ void GiftiMetaData::getAllNames(std::vector& allNames) const { allNames.clear(); for (ConstMetaDataIterator iter = metaData.begin(); iter != metaData.end(); iter++) { allNames.push_back(iter->first); } } /** * write the data into a StringTable. */ void GiftiMetaData::writeDataIntoStringTable(StringTable& table) const { const int numRows = metaData.size(); table.setNumberOfRowsAndColumns(numRows, 2, GiftiCommon::tagMetaData); table.setTableTitle(GiftiCommon::tagMetaData); table.setColumnTitle(0, GiftiCommon::tagName); table.setColumnTitle(1, GiftiCommon::tagValue); int rowCount = 0; for (ConstMetaDataIterator iter = metaData.begin(); iter != metaData.end(); iter++) { table.setElement(rowCount, 0, iter->first); table.setElement(rowCount, 1, iter->second); rowCount++; } } /** * read the data from a StringTable. */ void GiftiMetaData::readDataFromStringTable(const StringTable& st) throw (FileException) { clear(); int numCols = st.getNumberOfColumns(); int nameCol = -1; int valueCol = -1; for (int i = 0; i < numCols; i++) { const QString columnTitle = st.getColumnTitle(i); if (columnTitle == GiftiCommon::tagName) { nameCol = i; } else if (columnTitle == GiftiCommon::tagValue) { valueCol = i; } } for (int i = 0; i < st.getNumberOfRows(); i++) { QString name, value; if (nameCol >= 0) { name = st.getElement(i, nameCol); } if (valueCol >= 0) { value = st.getElement(i, valueCol); } set(name, value); } } /** * copy the metadata from a caret file. */ void GiftiMetaData::copyMetaDataFromCaretFile(const AbstractFile* af) { if (af != NULL) { AbstractFile::AbstractFileHeaderContainer header = af->getHeader(); std::map::iterator iter; for (iter = header.begin(); iter != header.end(); iter++) { const QString tag(iter->first); const QString value(iter->second); set(tag, value); } } } /** * copy the metadata into a caret file. */ void GiftiMetaData::copyMetaDataToCaretFile(AbstractFile* af) const { if (af != NULL) { for (ConstMetaDataIterator iter = metaData.begin(); iter != metaData.end(); iter++) { const QString tag(iter->first); const QString value(iter->second); af->setHeaderTag(tag, value); } } } caret-5.6.4~dfsg.1.orig/caret_files/GiftiMatrix.h0000664000175000017500000000561111572067322021444 0ustar michaelmichael #ifndef __GIFTI_MATRIX_H__ #define __GIFTI_MATRIX_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include class QTextStream; /// matrix used with coordinates class GiftiMatrix { public: // constructor GiftiMatrix(); // copy constructor GiftiMatrix(const GiftiMatrix& nlt); // destructor ~GiftiMatrix(); // assignment operator GiftiMatrix& operator=(const GiftiMatrix& nlt); // clear the matrix (removes spaces, sets matrix to identity) void clear(); // is the matrix empty (identity matrix with spaces unknown) bool isEmpty() const; // is the matrix the identity matrix ? bool isIdentity() const; /// get the data (pre-transformed) space name QString getDataSpaceName() const; // set the data (pre-transformed) space name void setDataSpaceName(const QString& space); /// get the transformed space name QString getTransformedSpaceName() const; // set the transformed space name void setTransformedSpaceName(const QString& space); // get the matrix void getMatrix(double matrix[4][4]) const; // set the matrix void setMatrix(const double matrix[4][4]); // multiply a point void multiplyPoint(double& x, double& y, double& z) const; // multiply a point void multiplyPoint(double xyz[3]) const; // write the label table void writeAsXML(QTextStream& stream, const int indentOffset) const; protected: // copy helper used by copy constructor and assignement operators void copyHelperGiftiMatrix(const GiftiMatrix& gm); // the matrix double m[4][4]; // the data space name QString dataSpaceName; // the transformed space name QString transformedSpaceName; /*** IF ADDITIONAL MEMBERS ARE ADDED UPDATE copyHelperGiftiLabelTable() ***/ }; #endif // __GIFTI_MATRIX_H__ caret-5.6.4~dfsg.1.orig/caret_files/GiftiMatrix.cxx0000664000175000017500000001342411572067322022020 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "GiftiCommon.h" #include "GiftiMatrix.h" /** * constructor. */ GiftiMatrix::GiftiMatrix() { clear(); } /** * copy constructor. */ GiftiMatrix::GiftiMatrix(const GiftiMatrix& gm) { copyHelperGiftiMatrix(gm); } /** * destructor. */ GiftiMatrix::~GiftiMatrix() { clear(); } /** * assignment operator. */ GiftiMatrix& GiftiMatrix::operator=(const GiftiMatrix& gm) { if (this != &gm) { copyHelperGiftiMatrix(gm); } return *this; } /** * copy helper used by copy constructor and assignement operators. */ void GiftiMatrix::copyHelperGiftiMatrix(const GiftiMatrix& gm) { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { m[i][j] = gm.m[i][j]; } } dataSpaceName = gm.dataSpaceName; transformedSpaceName = gm.transformedSpaceName; } /** * clear the matrix (removes spaces, sets matrix to identity). */ void GiftiMatrix::clear() { m[0][0] = 1.0; m[0][1] = 0.0; m[0][2] = 0.0; m[0][3] = 0.0; m[1][0] = 0.0; m[1][1] = 1.0; m[1][2] = 0.0; m[1][3] = 0.0; m[2][0] = 0.0; m[2][1] = 0.0; m[2][2] = 1.0; m[2][3] = 0.0; m[3][0] = 0.0; m[3][1] = 0.0; m[3][2] = 0.0; m[3][3] = 1.0; dataSpaceName = ""; transformedSpaceName = ""; } /** * is the matrix empty (identity matrix with no spaces specified). */ bool GiftiMatrix::isEmpty() const { return (dataSpaceName.isEmpty() && transformedSpaceName.isEmpty() && isIdentity()); } /** * is the matrix the identity matrix ? */ bool GiftiMatrix::isIdentity() const { if ((m[0][0] == 1.0) && (m[0][1] == 0.0) && (m[0][2] == 0.0) && (m[0][3] == 0.0) && (m[1][0] == 0.0) && (m[1][1] == 1.0) && (m[1][2] == 0.0) && (m[1][3] == 0.0) && (m[2][0] == 0.0) && (m[2][1] == 0.0) && (m[2][2] == 1.0) && (m[2][3] == 0.0) && (m[3][0] == 0.0) && (m[3][1] == 0.0) && (m[3][2] == 0.0) && (m[3][3] == 1.0)) { return true; } return false; } /** * get the data (pre-transformed) space name. */ QString GiftiMatrix::getDataSpaceName() const { return dataSpaceName; } /** * set the data (pre-transformed) space name. */ void GiftiMatrix::setDataSpaceName(const QString& spaceName) { dataSpaceName = spaceName; } /** * get the transformed space name. */ QString GiftiMatrix::getTransformedSpaceName() const { return transformedSpaceName; } /** * set the transformed space name. */ void GiftiMatrix::setTransformedSpaceName(const QString& spaceName) { transformedSpaceName = spaceName; } /** * get the matrix. */ void GiftiMatrix::getMatrix(double matrix[4][4]) const { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { matrix[i][j] = m[i][j]; } } } /** * set the matrix. */ void GiftiMatrix::setMatrix(const double matrix[4][4]) { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { m[i][j] = matrix[i][j]; } } } /** * multiply a point. */ void GiftiMatrix::multiplyPoint(double& x, double& y, double& z) const { const double xp = m[0][0]*x + m[0][1]*y + m[0][2]*z + m[0][3]; const double yp = m[1][0]*x + m[1][1]*y + m[1][2]*z + m[1][3]; const double zp = m[2][0]*x + m[2][1]*y + m[2][2]*z + m[2][3]; x = xp; y = yp; z = zp; } /** * multiply a point. */ void GiftiMatrix::multiplyPoint(double xyz[3]) const { multiplyPoint(xyz[0], xyz[1], xyz[2]); } /** * write metadata (used by other classes so static). */ void GiftiMatrix::writeAsXML(QTextStream& stream, const int indentOffset) const { if (isEmpty()) { return; } int indent = indentOffset; GiftiCommon::writeIndentationXML(stream, indent); stream << "<" << GiftiCommon::tagMatrix << ">" << "\n"; indent++; GiftiCommon::writeIndentationXML(stream, indent); stream << "<" << GiftiCommon::tagMatrixDataSpace << ">" << "\n"; GiftiCommon::writeIndentationXML(stream, indent); stream << "<" << GiftiCommon::tagMatrixTransformedSpace << ">" << "\n"; GiftiCommon::writeIndentationXML(stream, indent); stream << "<" << GiftiCommon::tagMatrixData << ">" << "\n"; indent++; for (int i = 0; i < 4; i++) { GiftiCommon::writeIndentationXML(stream, indent); for (int j = 0; j < 4; j++) { stream << m[i][j] << " "; } stream << "\n"; } indent--; GiftiCommon::writeIndentationXML(stream, indent); stream << "" << "\n"; indent--; GiftiCommon::writeIndentationXML(stream, indent); stream << "" << "\n"; } caret-5.6.4~dfsg.1.orig/caret_files/GiftiLabelTable.h0000664000175000017500000002527111572067322022173 0ustar michaelmichael #ifndef __GIFTI_LABEL_TABLE_H__ #define __GIFTI_LABEL_TABLE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "FileException.h" class ColorFile; class QTextStream; class StringTable; /// table for label indices and names class GiftiLabelTable { public: // constructor GiftiLabelTable(); // copy constructor GiftiLabelTable(const GiftiLabelTable& nlt); // destructor ~GiftiLabelTable(); // assignment operator GiftiLabelTable& operator=(const GiftiLabelTable& nlt); // add a label (returns the label's index) int addLabel(const QString& labelName); // append a label table to this one void append(const GiftiLabelTable& nlt, const std::vector* labelsWithTheseIndicesOnly = NULL); // assign colors to the labels void assignColors(const ColorFile& colorFile); // get colors from the labels void addColorsToColorFile(ColorFile& colorFile); // Create a label from each of the colors in a color file void createLabelsFromColors(const ColorFile& colorFile); // clear out the labels void clear(); // delete a label void deleteLabel(const int labelIndex); // are there labels ? bool empty() const { return labels.empty(); } // get the index of a label int getLabelIndex(const QString& labelName) const; // get label using its index QString getLabel(const int indx) const; // get all labels void getAllLabels(std::vector& labelsOut) const; /// get the number of labels int getNumberOfLabels() const { return labels.size(); } // set the label for a specified index (index must be >= 0) void setLabel(const int indx, const QString& labelName); // set a label's color file index void setColorFileIndex(const int indx, const int colorFileIndex); // get a labels color file index int getColorFileIndex(const int indx) const; // get label enabled using its index bool getLabelEnabled(const int indx) const; // set label enabled for a specified index (index must be >= 0) void setLabelEnabled(const int indx, const bool b); // set all labels enabled void setAllLabelsEnabled(const bool b); // Set LabelTable had colors when it was read void setHadColorsWhenRead(bool b) { this->hadColorsWhenRead = b; } // Get LabelTable had colors when it was read bool getHadColorsWhenRead() const { return this->hadColorsWhenRead; } // get teh color components as floats ranging 0.0 to 1.0 void getColorFloat(const int indx, float& red, float& green, float& blue, float& alpha) const; // set the color components from floats ranging 0.0 to 1.0 void setColorFloat(const int indx, float red, float green, float blue, float alpha); // get teh color components void getColor(const int indx, unsigned char& red, unsigned char& green, unsigned char& blue, unsigned char& alpha) const; // set the color components void setColor(const int indx, unsigned char red, unsigned char green, unsigned char blue, unsigned char alpha); // write the label table void writeAsXML(QTextStream& stream, const int indentOffset) const; // write as Caret6 XML void writeAsXML(XmlGenericWriter& xmlWriter) const; /// write the data into a StringTable void writeDataIntoStringTable(StringTable& table) const; /// read the data from a StringTable void readDataFromStringTable(const StringTable& table) throw (FileException); /// get the default color components static void getDefaultColor(unsigned char& redOut, unsigned char& greenOut, unsigned char& blueOut, unsigned char& alphaOut) { redOut = 255; greenOut = 255; blueOut = 255; alphaOut = 255; } /// get the default color components as floats static void getDefaultColorFloat(float& redOut, float& greenOut, float& blueOut, float& alphaOut) { unsigned char r, g, b, a; getDefaultColor(r, g, b, a); redOut = ((float)r / 255.0); greenOut = ((float)g / 255.0); blueOut = ((float)b / 255.0); alphaOut = ((float)a / 255.0); } protected: /// class used for storing a label and its corresponding color index class LabelData { public: /// constructor LabelData(const QString& labelNameIn) { labelName = labelNameIn; colorFileIndex = -1; labelEnabled = true; GiftiLabelTable::getDefaultColor(red, green, blue, alpha); }; /// constructor LabelData(const QString& labelNameIn, const unsigned char redIn, const unsigned char greenIn, const unsigned char blueIn, const unsigned char alphaIn = 255) { labelName = labelNameIn; colorFileIndex = -1; labelEnabled = true; red = redIn; green = greenIn; blue = blueIn; alpha = alphaIn; }; /// destructor ~LabelData() { } /// get the label name QString getLabelName() const { return labelName; } /// set the label name void setLabelName(const QString& labelNameIn) { labelName = labelNameIn; } /// get the color file index int getColorFileIndex() const { return colorFileIndex; } /// set the color file index void setColorFileIndex(const int indx) { colorFileIndex = indx; } /// set the label is enabled void setLabelEnabled(const bool b) { labelEnabled = b; } /// get the label is enabled bool getLabelEnabled() const { return labelEnabled; } /// get the color components void getColor(unsigned char& redOut, unsigned char& greenOut, unsigned char& blueOut, unsigned char& alphaOut) const { redOut = red; greenOut = green; blueOut = blue; alphaOut = alpha; } /// set the color components void setColor(const unsigned char redIn, const unsigned char greenIn, const unsigned char blueIn, const unsigned char alphaIn) { red = redIn; green = greenIn; blue = blueIn; alpha = alphaIn; } /// get the color components as floats ranging 0.0 to 1.0 void getColorFloat(float& redOut, float& greenOut, float& blueOut, float& alphaOut) const { redOut = ((float)red / 255.0); greenOut = ((float)green / 255.0); blueOut = ((float)blue / 255.0); alphaOut = ((float)alpha / 255.0); } /// set the color components from floats ranging 0.0 to 1.0 void setColorFloat(const float redIn, const float greenIn, const float blueIn, const float alphaIn) { red = (unsigned char)(redIn * 255.0); green = (unsigned char)(greenIn * 255.0); blue = (unsigned char)(blueIn * 255.0); alpha = (unsigned char)(alphaIn * 255.0); } protected: /// name of label QString labelName; /// red component unsigned char red; /// green component unsigned char green; /// blue component unsigned char blue; /// alpha component unsigned char alpha; /// index in color file int colorFileIndex; /// label is enabled bool labelEnabled; }; // copy helper used by copy constructor and assignement operators void copyHelperGiftiLabelTable(const GiftiLabelTable& nlt); /// container for labels typedef std::vector LabelContainer; /// iterator for label container typedef LabelContainer::iterator LabelContainerIterator; /// iterator for label container typedef LabelContainer::const_iterator ConstLabelContainerIterator; // the labels LabelContainer labels; // colors were present when label table was read bool hadColorsWhenRead; /*** IF ADDITIONAL MEMBERS ARE ADDED UPDATE copyHelperGiftiLabelTable() ***/ }; #endif // __GIFTI_LABEL_TABLE_H__ caret-5.6.4~dfsg.1.orig/caret_files/GiftiLabelTable.cxx0000664000175000017500000003374211572067322022550 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "ColorFile.h" #include "GiftiCommon.h" #include "GiftiLabelTable.h" #include "StringTable.h" /** * constructor. */ GiftiLabelTable::GiftiLabelTable() { clear(); } /** * copy constructor. */ GiftiLabelTable::GiftiLabelTable(const GiftiLabelTable& nlt) { copyHelperGiftiLabelTable(nlt); } /** * destructor. */ GiftiLabelTable::~GiftiLabelTable() { clear(); } /** * assignment operator. */ GiftiLabelTable& GiftiLabelTable::operator=(const GiftiLabelTable& nlt) { if (this != &nlt) { copyHelperGiftiLabelTable(nlt); } return *this; } /** * add a label (returns the label's index). * If the label is already in the table its index is returned. */ int GiftiLabelTable::addLabel(const QString& labelName) { const int indx = getLabelIndex(labelName); if (indx >= 0) { return indx; } labels.push_back(LabelData(labelName)); return (labels.size() - 1); } /** * delete a label. */ void GiftiLabelTable::deleteLabel(const int labelIndex) { labels.erase(labels.begin() + labelIndex); } /** * append a label table to this one. */ void GiftiLabelTable::append(const GiftiLabelTable& nlt, const std::vector* labelsWithTheseIndicesOnly) { const int numLabels = nlt.getNumberOfLabels(); if (numLabels > 0) { // // Determine which labels should be appended // std::vector appendThisLabel(numLabels, false); if (labelsWithTheseIndicesOnly != NULL) { const int num = static_cast(labelsWithTheseIndicesOnly->size()); for (int i = 0; i < num; i++) { const int indx = (*labelsWithTheseIndicesOnly)[i]; appendThisLabel[indx] = true; } } else { std::fill(appendThisLabel.begin(), appendThisLabel.end(), true); } // // Append the labels // for (int i = 0; i < numLabels; i++) { if (appendThisLabel[i]) { addLabel(nlt.getLabel(i)); } } } } /** * clear out the labels. */ void GiftiLabelTable::clear() { labels.clear(); hadColorsWhenRead = false; } /** * get the index of a label (returns -1 if not found). */ int GiftiLabelTable::getLabelIndex(const QString& labelName) const { int numLabels = getNumberOfLabels(); for (int i = 0; i < numLabels; i++) { if (labels[i].getLabelName() == labelName) { return i; } } return -1; } /** * get label using its index. */ QString GiftiLabelTable::getLabel(const int indx) const { if ((indx >= 0) && (indx < static_cast(labels.size()))) { return labels[indx].getLabelName(); } return ""; } /** * set the label for a specified index. */ void GiftiLabelTable::setLabel(const int indx, const QString& labelName) { // // Add space if needed // if (indx >= getNumberOfLabels()) { labels.resize(indx + 1, LabelData("")); } labels[indx].setLabelName(labelName); } /** * Get the color components as floats ranging 0.0 to 1.0 */ void GiftiLabelTable::getColorFloat(const int indx, float& red, float& green, float& blue, float& alpha) const { if ((indx >= 0) && (indx < static_cast(labels.size()))) { labels[indx].getColorFloat(red, green, blue, alpha); } } /** * Set the color components from floats ranging 0.0 to 1.0 . */ void GiftiLabelTable::setColorFloat(const int indx, float red, float green, float blue, float alpha) { // // Add space if needed // if (indx >= getNumberOfLabels()) { labels.resize(indx + 1, LabelData("")); } labels[indx].setColorFloat(red, green, blue, alpha); } /** * Get teh color components. */ void GiftiLabelTable::getColor(const int indx, unsigned char& red, unsigned char& green, unsigned char& blue, unsigned char& alpha) const { if ((indx >= 0) && (indx < static_cast(labels.size()))) { labels[indx].getColor(red, green, blue, alpha); } } /** * Set the color components. */ void GiftiLabelTable::setColor(const int indx, unsigned char red, unsigned char green, unsigned char blue, unsigned char alpha) { // // Add space if needed // if (indx >= getNumberOfLabels()) { labels.resize(indx + 1, LabelData("")); } float r = ((float)red) / 255.0; float g = ((float)green) / 255.0; float b = ((float)blue) / 255.0; float a = ((float)alpha) / 255.0; labels[indx].setColorFloat(r, g, b, a); } /** * get label enabled using its index. */ bool GiftiLabelTable::getLabelEnabled(const int indx) const { if ((indx >= 0) && (indx < static_cast(labels.size()))) { return labels[indx].getLabelEnabled(); } return false; } /** * set label enabled for a specified index (index must be >= 0). */ void GiftiLabelTable::setLabelEnabled(const int indx, const bool b) { if ((indx >= 0) && (indx < static_cast(labels.size()))) { labels[indx].setLabelEnabled(b); } } /** * set all labels enabled. */ void GiftiLabelTable::setAllLabelsEnabled(const bool b) { const int num = getNumberOfLabels(); for (int i = 0; i < num; i++) { setLabelEnabled(i, b); } } /** * set a label's color file index. */ void GiftiLabelTable::setColorFileIndex(const int indx, const int colorFileIndex) { if ((indx >= 0) && (indx < getNumberOfLabels())) { labels[indx].setColorFileIndex(colorFileIndex); } } /** * get a labels color file index. */ int GiftiLabelTable::getColorFileIndex(const int indx) const { if ((indx >= 0) && (indx < getNumberOfLabels())) { return labels[indx].getColorFileIndex(); } return -1; } /** * get all labels. */ void GiftiLabelTable::getAllLabels(std::vector& labelsOut) const { const int num = getNumberOfLabels(); labelsOut.clear(); for (int i = 0; i < num; i++) { labelsOut.push_back(labels[i].getLabelName()); } } /** * copy helper used by copy constructor and assignement operators. */ void GiftiLabelTable::copyHelperGiftiLabelTable(const GiftiLabelTable& nlt) { labels = nlt.labels; hadColorsWhenRead = nlt.hadColorsWhenRead; } /** * Get colors from the labels. */ void GiftiLabelTable::addColorsToColorFile(ColorFile& colorFile) { unsigned char defRed, defGreen, defBlue, defAlpha; GiftiLabelTable::getDefaultColor(defRed, defGreen, defBlue, defAlpha); const int numLabels = getNumberOfLabels(); for (int i = 0; i < numLabels; i++) { unsigned char r, g, b, a; labels[i].getColor(r, g, b, a); QString labelName = labels[i].getLabelName(); bool haveColorInColorFile = colorFile.getColorExists(labelName); if (haveColorInColorFile == false) { // // Add color since it does not exist in color file // colorFile.addColor(labelName, r, g, b, a); } else { // // Color is in color file so override only if // label color is not the default color // if ((r != defRed) || (g != defGreen) || (b != defBlue) || (a != defAlpha)) { colorFile.addColor(labelName, r, g, b, a); } } } } /** * Create a label from each of the colors in a color file. */ void GiftiLabelTable::createLabelsFromColors(const ColorFile& colorFile) { int numColors = colorFile.getNumberOfColors(); for (int i = 0; i < numColors; i++) { const ColorFile::ColorStorage* cs = colorFile.getColor(i); QString name = cs->getName(); unsigned char r, g, b, a; cs->getRgba(r, g, b, a); this->labels.push_back(LabelData(name, r, g, b, a)); } } /** * assign colors to the labels. */ void GiftiLabelTable::assignColors(const ColorFile& colorFile) { // // Use alpha of zero for ??? // bool colorExactMatch = false; unsigned char cur, cug, cub, cua; int colorFileUnknownIndex = colorFile.getColorByName("???", colorExactMatch, cur, cug, cub, cua); unsigned char r, g, b, a; GiftiLabelTable::getDefaultColor(r, g, b, a); bool exactMatch = false; const int numLabels = getNumberOfLabels(); for (int i = 0; i < numLabels; i++) { QString labelName = labels[i].getLabelName(); int indx = colorFile.getColorByName(labelName, exactMatch, r, g, b, a); if (indx >= 0) { labels[i].setColorFileIndex(indx); labels[i].setColor(r, g, b, a); } else if (colorFileUnknownIndex >= 0) { labels[i].setColorFileIndex(-1); labels[i].setColor(cur, cug, cub, 0); } } // // Use alpha of zero for ??? // index might change // int unknownIndex = this->addLabel("???"); if (unknownIndex >= 0) { float ur, ug, ub, ua; this->getColorFloat(unknownIndex, ur, ug, ub, ua); this->setColorFloat(unknownIndex, ur, ug, ub, 0.0); } } /** * write metadata (used by other classes so static). */ void GiftiLabelTable::writeAsXML(QTextStream& stream, const int indentOffset) const { int indent = indentOffset; if (labels.empty()) { GiftiCommon::writeIndentationXML(stream, indent); stream << "<" << GiftiCommon::tagLabelTable << "/>" << "\n"; } else { GiftiCommon::writeIndentationXML(stream, indent); stream << "<" << GiftiCommon::tagLabelTable << ">" << "\n"; indent++; const int numLabels = getNumberOfLabels(); for (int i = 0; i < numLabels; i++) { float red, green, blue, alpha; labels[i].getColorFloat(red, green, blue, alpha); GiftiCommon::writeIndentationXML(stream, indent); stream << "<" << GiftiCommon::tagLabel << " " << GiftiCommon::attKey << "=\"" << i << "\" " << GiftiCommon::attRed << "=\"" << QString::number(red, 'f', 3) << "\" " << GiftiCommon::attGreen << "=\"" << QString::number(green, 'f', 3) << "\" " << GiftiCommon::attBlue << "=\"" << QString::number(blue, 'f', 3) << "\" " << GiftiCommon::attAlpha << "=\"" << QString::number(alpha, 'f', 3) << "\"" << ">"; stream << ""; stream << "" << "\n"; } indent--; GiftiCommon::writeIndentationXML(stream, indent); stream << "" << "\n"; } } /** * Write as Caret6 XML. */ void GiftiLabelTable::writeAsXML(XmlGenericWriter& xmlWriter) const { xmlWriter.writeStartElement(GiftiCommon::tagLabelTable); const int numLabels = getNumberOfLabels(); for (int i = 0; i < numLabels; i++) { float red, green, blue, alpha; labels[i].getColorFloat(red, green, blue, alpha); XmlGenericWriterAttributes attributes; attributes.addAttribute(GiftiCommon::attKey, i); attributes.addAttribute(GiftiCommon::attRed, red); attributes.addAttribute(GiftiCommon::attGreen, green); attributes.addAttribute(GiftiCommon::attBlue, blue); attributes.addAttribute(GiftiCommon::attAlpha, alpha); xmlWriter.writeElementCData(GiftiCommon::tagLabel, attributes, labels[i].getLabelName()); } xmlWriter.writeEndElement(); } /** * write the data into a StringTable. */ void GiftiLabelTable::writeDataIntoStringTable(StringTable& table) const { const int numLabels = getNumberOfLabels(); if (numLabels <= 0) { return; } table.setNumberOfRowsAndColumns(numLabels, 2, GiftiCommon::tagLabelTable); table.setTableTitle(GiftiCommon::tagLabelTable); table.setColumnTitle(0, "index"); table.setColumnTitle(1, GiftiCommon::tagLabel); int rowCount = 0; for (int i = 0; i < numLabels; i++) { table.setElement(rowCount, 0, i); table.setElement(rowCount, 1, labels[i].getLabelName()); rowCount++; } } /** * read the data from a StringTable. */ void GiftiLabelTable::readDataFromStringTable(const StringTable& table) throw (FileException) { clear(); int indexCol = -1; int labelCol = -1; for (int j = 0; j < table.getNumberOfColumns(); j++) { if (table.getColumnTitle(j) == "index") { indexCol = j; } else if (table.getColumnTitle(j) == GiftiCommon::tagLabel) { labelCol = j; } } if ((indexCol < 0) || (labelCol < 0)) { throw FileException("GiftiLabelTable: Unable to find index and label column titles."); } for (int i = 0; i < table.getNumberOfRows(); i++) { const int indx = table.getElementAsInt(i, indexCol); const QString label = table.getElement(i, labelCol); setLabel(indx, label); } } caret-5.6.4~dfsg.1.orig/caret_files/GiftiDataArrayReadListener.h0000664000175000017500000000120411572067322024344 0ustar michaelmichael#ifndef __GIFTI_DATA_ARRAY_READ_LISTENER_H__ #define __GIFTI_DATA_ARRAY_READ_LISTENER_H__ #include class GiftiDataArray; /** * Classes should extend this class to get data * arrays as they are read. */ class GiftiDataArrayReadListener { public: GiftiDataArrayReadListener() { } /// constructor virtual ~GiftiDataArrayReadListener() { } /// returns non-empty string if there is an error virtual QString dataArrayWasRead(GiftiDataArray* gda, const int dataArrayIndex, const int numberOfDataArrays) = 0; }; #endif // __GIFTI_DATA_ARRAY_ADDED_LISTENER_H__ caret-5.6.4~dfsg.1.orig/caret_files/GiftiDataArrayFileStreamReader.h0000664000175000017500000000535211572067322025151 0ustar michaelmichael #ifndef __GIFTI_DATA_ARRAY_FILE_STREAM_READER_H__ #define __GIFTI_DATA_ARRAY_FILE_STREAM_READER_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "FileException.h" class GiftiDataArrayFile; class GiftiDataArrayReadListener; class GiftiLabelTable; class GiftiMetaData; class QFile; /// class for reading a GIFTI Data Array file class GiftiDataArrayFileStreamReader : QXmlStreamReader { public: /// constructor GiftiDataArrayFileStreamReader(QFile* file, GiftiDataArrayFile* giftiFileIn); /// For incrementally reading arrays /// the listener is called with each array as it is read and /// it is the responsibility of the listener to delete the array. static void readFileAndReportDataArraysAsTheyAreRead(const QString& filename, GiftiDataArrayReadListener* giftiDataArrayReadListenerIn) throw (FileException); /// destructor ~GiftiDataArrayFileStreamReader(); // read the data void readData() throw (FileException); protected: // read GIFTI element void readGiftiVersion1(); // read MetaData element void readMetaData(GiftiMetaData* metaData); // read LabelTable element void readLabelTable(GiftiLabelTable* labelTable); // read DataArray element void readDataArray(); // read the coordinate transform matrix void readCoordinateTransformMatrix(GiftiMatrix* matrix); /// GIFTI Data Array File being read GiftiDataArrayFile* giftiFile; /// Optional listener GiftiDataArrayReadListener* giftiDataArrayReadListener; /// number of data arrays in GIFTI attribute int numberOfDataArraysInFile; /// increments as data arrays are read int dataArrayReadIndex; }; #endif // __GIFTI_DATA_ARRAY_FILE_STREAM_READER_H__ caret-5.6.4~dfsg.1.orig/caret_files/GiftiDataArrayFileStreamReader.cxx0000664000175000017500000005240411572067322025524 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include "DebugControl.h" #include "GiftiCommon.h" #include "GiftiDataArrayFile.h" #include "GiftiDataArrayFileStreamReader.h" #include "GiftiDataArrayReadListener.h" #include "GiftiLabelTable.h" #include "GiftiMatrix.h" #include "GiftiMetaData.h" #include "StringUtilities.h" /** * constructor. */ GiftiDataArrayFileStreamReader::GiftiDataArrayFileStreamReader(QFile* file, GiftiDataArrayFile* giftiFileIn) : QXmlStreamReader(file) { giftiFile = giftiFileIn; this->numberOfDataArraysInFile = 0; this->dataArrayReadIndex = 0; this->giftiDataArrayReadListener = NULL; } /// For incrementally reading arrays /// the listener is called with each array as it is read and /// it is the responsibility of the listener to delete the array. void GiftiDataArrayFileStreamReader::readFileAndReportDataArraysAsTheyAreRead( const QString& filename, GiftiDataArrayReadListener* giftiDataArrayReadListenerIn) throw (FileException) { QFile file(filename); if (file.open(QIODevice::ReadOnly)) { try { GiftiDataArrayFile gdaf; GiftiDataArrayFileStreamReader streamReader(&file, &gdaf); streamReader.giftiDataArrayReadListener = giftiDataArrayReadListenerIn; streamReader.readData(); file.close(); } catch (FileException e) { file.close(); throw FileException(e); } } else { throw FileException(filename, file.errorString()); } } /** * destructor. */ GiftiDataArrayFileStreamReader::~GiftiDataArrayFileStreamReader() { } /** * read the data. */ void GiftiDataArrayFileStreamReader::readData() throw (FileException) { if (giftiFile == NULL) { throw FileException("GIFTI file is invalid (NULL)."); } // // Loop until done // while (atEnd() == false) { // // Read the next token // readNext(); // // Is this the GIFTI element // if (isStartElement()) { const QString elemName = name().toString(); if (elemName == GiftiCommon::tagGIFTI) { // // Check Version // const QString versionString = attributes().value(GiftiCommon::attVersion).toString(); if (versionString.isEmpty()) { raiseError("GIFTI file version unknown."); } const float version = versionString.toFloat(); /* * Number of Data Arrays. */ const QString numberOfDataArraysString = attributes().value(GiftiCommon::attNumberOfDataArrays).toString(); if (numberOfDataArraysString.isEmpty()) { raiseError("GIFTI file number of data arrays is missing."); } this->numberOfDataArraysInFile = numberOfDataArraysString.toInt(); if (version == 1.0) { readGiftiVersion1(); } else { raiseError("GIFTI file must be version 1.0 but is " + versionString); } } else { raiseError("File is not a GIFTI file. Element is " + elemName + " but should be " + GiftiCommon::tagGIFTI + "."); } } if (error()) { break; } } if (error()) { throw FileException(errorString()); } } /** * read GIFTI element. */ void GiftiDataArrayFileStreamReader::readGiftiVersion1() { // // Loop through the file // while (atEnd() == false) { // // Read next element // readNext(); // // If end of element, get out of loop // if (isEndElement()) { break; } // // Is this a starting element // if (isStartElement()) { // // Is this a MetaData, LabelTable, or DataArray element // if (name() == GiftiCommon::tagMetaData) { readMetaData(giftiFile->getMetaData()); } else if (name() == GiftiCommon::tagLabelTable) { readLabelTable(giftiFile->getLabelTable()); } else if (name() == GiftiCommon::tagDataArray) { readDataArray(); } else { raiseError("Unrecognized child (" + name().toString() + ") of " + GiftiCommon::tagGIFTI + " element."); } } } } /** * read MetaData element. */ void GiftiDataArrayFileStreamReader::readMetaData(GiftiMetaData* metaData) { QString mdName, mdValue; // // Loop through the file // while (atEnd() == false) { // // Read next element // readNext(); // // If end element // if (isEndElement()) { // // If end of metadata, stop reading // if (name() == GiftiCommon::tagMetaData) { break; } else if (name() == GiftiCommon::tagMD) { if (mdName.isEmpty() == false) { metaData->set(mdName, mdValue); } } } // // Is this a starting element // if (isStartElement()) { // // Is this a MD, Name, or Value element // if (name() == GiftiCommon::tagMD) { mdName = ""; mdValue = ""; } else if (name() == GiftiCommon::tagName) { mdName = readElementText(); } else if (name() == GiftiCommon::tagValue) { mdValue = readElementText(); } else { raiseError("Unrecognized element (" + name().toString() + " in metadata."); } } } } /** * read LabelTable element. */ void GiftiDataArrayFileStreamReader::readLabelTable(GiftiLabelTable* labelTable) { // // Loop through the file // while (atEnd() == false) { // // Read next element // readNext(); // // If end element // if (isEndElement()) { // // If end of metadata, stop reading // if (name() == GiftiCommon::tagLabelTable) { break; } } // // If start element // if (isStartElement()) { if (name() == GiftiCommon::tagLabel) { QString keyString = attributes().value(GiftiCommon::attKey).toString(); if (keyString == NULL) { keyString = attributes().value("Index").toString(); } else if (keyString.isEmpty()) { keyString = attributes().value("Index").toString(); } float labelRed, labelGreen, labelBlue, labelAlpha; GiftiLabelTable::getDefaultColorFloat(labelRed, labelGreen, labelBlue, labelAlpha); labelAlpha = 0.0; const QString redString = attributes().value(GiftiCommon::attRed).toString(); if (redString.isEmpty() == false) { labelRed = StringUtilities::toFloat(redString); labelTable->setHadColorsWhenRead(true); } const QString greenString = attributes().value(GiftiCommon::attGreen).toString(); if (greenString.isEmpty() == false) { labelGreen = StringUtilities::toFloat(greenString); labelTable->setHadColorsWhenRead(true); } const QString blueString = attributes().value(GiftiCommon::attBlue).toString(); if (blueString.isEmpty() == false) { labelBlue = StringUtilities::toFloat(blueString); labelTable->setHadColorsWhenRead(true); } const QString alphaString = attributes().value(GiftiCommon::attAlpha).toString(); if (alphaString.isEmpty() == false) { labelAlpha = StringUtilities::toFloat(alphaString); labelTable->setHadColorsWhenRead(true); } const QString name = readElementText(); bool valid = false; const int indx = keyString.toInt(&valid); if (valid) { if (indx >= 0) { labelTable->setLabel(indx, name); labelTable->setColorFloat(indx, labelRed, labelGreen, labelBlue, labelAlpha); } } } } } } /** * read DataArray element. */ void GiftiDataArrayFileStreamReader::readDataArray() { // // Get the attributes // const QString intentName = attributes().value(GiftiCommon::attIntent).toString(); const QString arrayIndexOrderName = attributes().value(GiftiCommon::attArraySubscriptingOrder).toString(); const QString dataTypeName = attributes().value(GiftiCommon::attDataType).toString(); const QString dimensionalityName = attributes().value(GiftiCommon::attDimensionality).toString(); const QString encodingName = attributes().value(GiftiCommon::attEncoding).toString(); const QString endianName = attributes().value(GiftiCommon::attEndian).toString(); QString externalFileName = attributes().value(GiftiCommon::attExternalFileName).toString(); const QString externalFileOffsetString = attributes().value(GiftiCommon::attExternalFileOffset).toString(); // // Check the intent name // if (GiftiDataArray::intentNameValid(intentName) == false) { raiseError("Intent name invalid: " + intentName); return; } // // Data type name // bool dataTypeNameValid = false; GiftiDataArray::DATA_TYPE dataTypeForReadingArrayData = GiftiDataArray::getDataTypeFromName(dataTypeName, &dataTypeNameValid); if (dataTypeNameValid == false) { raiseError("Attribute " + GiftiCommon::attDataType + "is invalid: " + dataTypeName); return; } // // Encoding // bool validEncoding = false; GiftiDataArray::ENCODING encodingForReadingArrayData = GiftiDataArray::getEncodingFromName(encodingName, &validEncoding); if (validEncoding == false) { raiseError("Attribute " + GiftiCommon::attEncoding + "is invalid: " + encodingName); return; } bool externalDataFlag = (encodingForReadingArrayData == GiftiDataArray::ENCODING_EXTERNAL_FILE_BINARY); // // External File Offset // long externalFileOffsetForReadingData = 0; if (externalFileOffsetString.isEmpty() == false) { bool validOffsetFlag = false; externalFileOffsetForReadingData = externalFileOffsetString.toLong(&validOffsetFlag); if (validOffsetFlag == false) { raiseError("File Offset is not a long integer (" + externalFileOffsetString + ")"); return; } } // // Determine full path to external file name // if (externalFileName.isEmpty() == false) { if (QFileInfo(externalFileName).isAbsolute() == false) { // // If exernal file name path is not absolute, // use path from the gifti data file that refers // to the external binary file. // QFileInfo fileInfo(this->giftiFile->getFileName()); QString fullPathName = fileInfo.absolutePath() + QDir::separator() + externalFileName; if (DebugControl::getDebugOn()) { std::cout << "External Name: " << externalFileName.toAscii().constData() << std::endl; std::cout << "External Full Path: " << fullPathName.toAscii().constData() << std::endl; std::cout << std::endl; } externalFileName = fullPathName; } } // // Endian // if ((endianName != GiftiCommon::endianBig) && (endianName != GiftiCommon::endianLittle)) { raiseError("Attribute " + GiftiCommon::attEndian + "is invalid: " + endianName); return; } // // Dimensions // if (dimensionalityName.isEmpty()) { raiseError("Required attribute " + GiftiCommon::attDimensionality + " not found for DataArray"); return; } const int numDimensions = dimensionalityName.toInt(); std::vector dimensionsForReadingArrayData; for (int i = 0; i < numDimensions; i++) { const QString dimNumString = attributes().value(GiftiCommon::getAttDim(i)).toString(); if (dimNumString.isEmpty()) { raiseError("Required dimension " + GiftiCommon::getAttDim(i) + " not found for DataArray"); return; } const int dim = dimNumString.toInt(); dimensionsForReadingArrayData.push_back(dim); } // // Subscript order // bool validArraySubscriptingOrder = false; GiftiDataArray::ARRAY_SUBSCRIPTING_ORDER arraySubscriptingOrderForReadingArrayData = GiftiDataArray::getArraySubscriptingOrderFromName( arrayIndexOrderName, &validArraySubscriptingOrder); if (validArraySubscriptingOrder == false) { raiseError("Attribute " + GiftiCommon::attArraySubscriptingOrder + "is invalid: " + arrayIndexOrderName); return; } GiftiDataArray* dataArray = new GiftiDataArray(giftiFile, intentName); // // Loop through the file // bool dataWasReadFlag = false; while (atEnd() == false) { // // Read next element // readNext(); // // If end element // if (isEndElement()) { // // If end of data array, stop reading // if (name() == GiftiCommon::tagDataArray) { if (dataWasReadFlag == false) { // // If we get here, the file had external data without // a set of tags // if (externalDataFlag) { try { // // Read the data // dataWasReadFlag = true; if (this->giftiFile->getReadMetaDataOnlyFlag() == false) { QString text = ""; dataArray->readFromText(text, endianName, arraySubscriptingOrderForReadingArrayData, dataTypeForReadingArrayData, dimensionsForReadingArrayData, encodingForReadingArrayData, externalFileName, externalFileOffsetForReadingData); } // // Add GIFTI array to GIFTI file // if (this->giftiDataArrayReadListener != NULL) { const QString errorMessage = this->giftiDataArrayReadListener->dataArrayWasRead( dataArray, this->dataArrayReadIndex, this->numberOfDataArraysInFile); if (errorMessage.isEmpty() == false) { raiseError(errorMessage); } this->dataArrayReadIndex++; } else { giftiFile->addDataArray(dataArray); } } catch (FileException& e) { delete dataArray; raiseError(e.whatQString()); return; } } } break; } } // // If starting element // if (isStartElement()) { const QString elemName(name().toString()); if (elemName == GiftiCommon::tagMetaData) { readMetaData(dataArray->getMetaData()); } else if (elemName == GiftiCommon::tagData) { try { dataWasReadFlag = true; if (this->giftiFile->getReadMetaDataOnlyFlag() == false) { // // Read the data // QString text = readElementText(); dataArray->readFromText(text, endianName, arraySubscriptingOrderForReadingArrayData, dataTypeForReadingArrayData, dimensionsForReadingArrayData, encodingForReadingArrayData, externalFileName, externalFileOffsetForReadingData); } // // Add GIFTI array to GIFTI file // if (this->giftiDataArrayReadListener != NULL) { const QString errorMessage = this->giftiDataArrayReadListener->dataArrayWasRead( dataArray, this->dataArrayReadIndex, this->numberOfDataArraysInFile); if (errorMessage.isEmpty() == false) { raiseError(errorMessage); } this->dataArrayReadIndex++; } else { giftiFile->addDataArray(dataArray); } } catch (FileException& e) { delete dataArray; raiseError(e.whatQString()); return; } } else if (elemName == GiftiCommon::tagMatrix) { dataArray->addMatrix(GiftiMatrix()); GiftiMatrix* matrix = dataArray->getMatrix(dataArray->getNumberOfMatrices() - 1); readCoordinateTransformMatrix(matrix); } else { raiseError("Unrecognized element (" + elemName + " in " + GiftiCommon::tagDataArray + "."); return; } } } } /** * read the coordinate transform matrix. */ void GiftiDataArrayFileStreamReader::readCoordinateTransformMatrix(GiftiMatrix* matrix) { // // Loop through the file // while (atEnd() == false) { // // Read next element // readNext(); // // If end element // if (isEndElement()) { // // If end of matrix, stop reading // if (name() == GiftiCommon::tagMatrix) { break; } } // // If starting element // if (isStartElement()) { const QString elemName(name().toString()); if (elemName == GiftiCommon::tagMatrixDataSpace) { matrix->setDataSpaceName(readElementText()); } else if (elemName == GiftiCommon::tagMatrixTransformedSpace) { matrix->setTransformedSpaceName(readElementText()); } else if (elemName == GiftiCommon::tagMatrixData) { QString text(readElementText()); QTextStream ts(&text); double m[4][4]; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { ts >> m[i][j]; } } matrix->setMatrix(m); } else { raiseError("Unrecognized element (" + elemName + " in " + GiftiCommon::tagMatrix + "."); return; } } } } caret-5.6.4~dfsg.1.orig/caret_files/GiftiDataArrayFileSaxReader.h0000664000175000017500000001244111572067322024446 0ustar michaelmichael #ifndef __GIFTI_DATA_ARRAY_FILE_SAX_READER_H__ #define __GIFTI_DATA_ARRAY_FILE_SAX_READER_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include class GiftiLabelTable; class GiftiMetaData; class GiftiDataArrayFile; #include "GiftiDataArray.h" /// class for reading a GIFTI Node Data File with a SAX Parser class GiftiDataArrayFileSaxReader : public QXmlDefaultHandler { public: // constructor GiftiDataArrayFileSaxReader(GiftiDataArrayFile* giftiFileIn); // destructor virtual ~GiftiDataArrayFileSaxReader(); // start an element bool startElement(const QString& namespaceURI, const QString& localName, const QString& qName, const QXmlAttributes& attributes); // end an element bool endElement(const QString& namspaceURI, const QString& localName, const QString& qName); // get characters in an element bool characters(const QString& s); // a fatal error occurs bool fatalError(const QXmlParseException& e); // get the error message QString getErrorMessage() const { return errorMessage; } protected: /// file reading states enum STATE { /// no state STATE_NONE, /// processing GIFTI tag STATE_GIFTI, /// 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, /// processing LabelTable tag STATE_LABEL_TABLE, /// processing LabelTable Label STATE_LABEL_TABLE_LABEL, /// 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 bool processArrayData(); // create a data array bool createDataArray(const QXmlAttributes& attributes); /// file reading state STATE state; /// the state stack used when reading a file std::stack stateStack; /// the error message QString errorMessage; /// GIFTI file that is being read GiftiDataArrayFile* giftiFile; /// meta data name QString metaDataName; /// meta data value QString metaDataValue; /// element text QString elementText; /// GIFTI data array being read GiftiDataArray* dataArray; /// GIFTI label table being read GiftiLabelTable* labelTable; /// GIFTI meta data being read GiftiMetaData* metaData; /// GIFTI matrix data being read GiftiMatrix* matrix; /// label index int labelIndex; /// label color component float labelRed; /// label color component float labelGreen; /// label color component float labelBlue; /// label color component float labelAlpha; /// endian attribute data QString endianAttributeNameForReadingArrayData; /// array subscripting order for reading GiftiDataArray::ARRAY_SUBSCRIPTING_ORDER arraySubscriptingOrderForReadingArrayData; /// data type for reading GiftiDataArray::DATA_TYPE dataTypeForReadingArrayData; /// dimension for reading std::vector dimensionsForReadingArrayData; /// encoding for reading GiftiDataArray::ENCODING encodingForReadingArrayData; /// data location for reading //GiftiDataArray::DATA_LOCATION dataLocationForReadingArrayData; /// external file name QString externalFileNameForReadingData; /// external file offset int externalFileOffsetForReadingData; }; #endif // __GIFTI_DATA_ARRAY_FILE_SAX_READER_H__ caret-5.6.4~dfsg.1.orig/caret_files/GiftiDataArrayFileSaxReader.cxx0000664000175000017500000005636411572067322025035 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include "DebugControl.h" #include "GiftiCommon.h" #include "GiftiDataArrayFile.h" #include "GiftiDataArrayFileSaxReader.h" #include "StringUtilities.h" /** * constructor. */ GiftiDataArrayFileSaxReader::GiftiDataArrayFileSaxReader(GiftiDataArrayFile* giftiFileIn) { giftiFile = giftiFileIn; state = STATE_NONE; stateStack.push(state); metaDataName = ""; metaDataValue = ""; elementText = ""; dataArray = NULL; labelTable = NULL; metaData = NULL; } /** * destructor. */ GiftiDataArrayFileSaxReader::~GiftiDataArrayFileSaxReader() { } /** * start an element. */ bool GiftiDataArrayFileSaxReader::startElement(const QString& /* namespaceURI */, const QString& /* localName */, const QString& qName, const QXmlAttributes& attributes) { if (DebugControl::getDebugOn()) { std::cout << "Start Element: " << qName.toAscii().constData() << std::endl; } const STATE previousState = state; switch (state) { case STATE_NONE: if (qName == GiftiCommon::tagGIFTI) { state = STATE_GIFTI; // // Check version of file being read // const float version = attributes.value(GiftiCommon::attVersion).toFloat(); if (version > GiftiDataArrayFile::getCurrentFileVersion()) { std::ostringstream str; str << "File version is " << version << " but this Caret" << " does not support versions newer than " << GiftiDataArrayFile::getCurrentFileVersion() << ".\n" << "You may need a newer version of Caret."; errorMessage = str.str().c_str(); return false; } else if (version < 1.0) { errorMessage = "File version is " + QString::number(version, 'f', 3) + " but this Caret" " does not support versions before 1.0"; return false; } } else { std::ostringstream str; str << "Root element is \"" << qName.toAscii().constData() << "\" but should be " << GiftiCommon::tagGIFTI.toAscii().constData(); errorMessage = str.str().c_str(); return false; } break; case STATE_GIFTI: if (qName == GiftiCommon::tagMetaData) { state = STATE_METADATA; metaData = giftiFile->getMetaData(); } else if (qName == GiftiCommon::tagDataArray) { state = STATE_DATA_ARRAY; if (createDataArray(attributes) == false) { return false; } } else if (qName == GiftiCommon::tagLabelTable) { state = STATE_LABEL_TABLE; labelTable = giftiFile->getLabelTable(); } else { std::ostringstream str; str << "Child of " << GiftiCommon::tagGIFTI.toAscii().constData() << " is \"" << qName.toAscii().constData() << "\" but should be one of \n" << " " << GiftiCommon::tagMetaData.toAscii().constData() << "\n" << " " << GiftiCommon::tagDataArray.toAscii().constData() << "\n" << " " << GiftiCommon::tagLabelTable.toAscii().constData(); errorMessage = str.str().c_str(); return false; } break; case STATE_METADATA: if (qName == GiftiCommon::tagMD) { state = STATE_METADATA_MD; } else { std::ostringstream str; str << "Child of " << GiftiCommon::tagMetaData.toAscii().constData() << " is \"" << qName.toAscii().constData() << "\" but should be " << GiftiCommon::tagMD.toAscii().constData(); errorMessage = str.str().c_str(); return false; } break; case STATE_METADATA_MD: if (qName == GiftiCommon::tagName) { state = STATE_METADATA_MD_NAME; } else if (qName == GiftiCommon::tagValue) { state = STATE_METADATA_MD_VALUE; } else { std::ostringstream str; str << "Child of " << GiftiCommon::tagMD.toAscii().constData() << " is \"" << qName.toAscii().constData() << "\" but should be one of \n" << " " << GiftiCommon::tagName.toAscii().constData() << "\n" << " " << GiftiCommon::tagValue.toAscii().constData(); errorMessage = str.str().c_str(); return false; } break; case STATE_METADATA_MD_NAME: { std::ostringstream str; str << GiftiCommon::tagName.toAscii().constData() << " has child \"" << qName.toAscii().constData() << "\" but should not have any child nodes"; errorMessage = str.str().c_str(); return false; } break; case STATE_METADATA_MD_VALUE: { std::ostringstream str; str << GiftiCommon::tagValue.toAscii().constData() << " has child \"" << qName.toAscii().constData() << "\" but should not have any child nodes"; errorMessage = str.str().c_str(); return false; } break; case STATE_LABEL_TABLE: if (qName == GiftiCommon::tagLabel) { state = STATE_LABEL_TABLE_LABEL; QString s = attributes.value(GiftiCommon::attKey); if (s == NULL) { s = attributes.value("Index"); } else { s = attributes.value("Index"); } if (s.isEmpty()) { std::ostringstream str; str << "Tag " << GiftiCommon::tagLabel.toAscii().constData() << " is missing its " << GiftiCommon::attKey.toAscii().constData(); errorMessage = str.str().c_str(); return false; } labelIndex = s.toInt(); { GiftiLabelTable::getDefaultColorFloat(labelRed, labelGreen, labelBlue, labelAlpha); const QString redString = attributes.value(GiftiCommon::attRed); if (redString.isEmpty() == false) { labelRed = StringUtilities::toFloat(redString); labelTable->setHadColorsWhenRead(true); } const QString greenString = attributes.value(GiftiCommon::attGreen); if (greenString.isEmpty() == false) { labelGreen = StringUtilities::toFloat(greenString); labelTable->setHadColorsWhenRead(true); } const QString blueString = attributes.value(GiftiCommon::attBlue); if (blueString.isEmpty() == false) { labelBlue = StringUtilities::toFloat(blueString); labelTable->setHadColorsWhenRead(true); } const QString alphaString = attributes.value(GiftiCommon::attAlpha); if (alphaString.isEmpty() == false) { labelAlpha = StringUtilities::toFloat(alphaString); labelTable->setHadColorsWhenRead(true); } } } else { std::ostringstream str; str << "Child of " << GiftiCommon::tagLabelTable.toAscii().constData() << " is \"" << qName.toAscii().constData() << "\" but should be " << GiftiCommon::tagLabel.toAscii().constData(); errorMessage = str.str().c_str(); return false; } break; case STATE_LABEL_TABLE_LABEL: { std::ostringstream str; str << GiftiCommon::tagLabel.toAscii().constData() << " has child \"" << qName.toAscii().constData() << "\" but should not have any child nodes"; errorMessage = str.str().c_str(); return false; } break; case STATE_DATA_ARRAY: if (qName == GiftiCommon::tagMetaData) { state = STATE_METADATA; metaData = dataArray->getMetaData(); } else if (qName == GiftiCommon::tagData) { state = STATE_DATA_ARRAY_DATA; } else if (qName == GiftiCommon::tagMatrix) { state = STATE_DATA_ARRAY_MATRIX; dataArray->addMatrix(GiftiMatrix()); matrix = dataArray->getMatrix(dataArray->getNumberOfMatrices() - 1); } else { std::ostringstream str; str << "Child of " << GiftiCommon::tagDataArray.toAscii().constData() << " is \"" << qName.toAscii().constData() << "\" but should be one of \n" << " " << GiftiCommon::tagMetaData.toAscii().constData() << "\n" << " " << GiftiCommon::tagMatrix.toAscii().constData() << "\n" << " " << GiftiCommon::tagData.toAscii().constData(); errorMessage = str.str().c_str(); return false; } break; case STATE_DATA_ARRAY_DATA: { std::ostringstream str; str << GiftiCommon::tagData.toAscii().constData() << " has child \"" << qName.toAscii().constData() << "\" but should not have any child nodes"; errorMessage = str.str().c_str(); return false; } break; case STATE_DATA_ARRAY_MATRIX: if (qName == GiftiCommon::tagMatrixDataSpace) { state = STATE_DATA_ARRAY_MATRIX_DATA_SPACE; } else if (qName == GiftiCommon::tagMatrixTransformedSpace) { state = STATE_DATA_ARRAY_MATRIX_TRANSFORMED_SPACE; } else if (qName == GiftiCommon::tagMatrixData) { state = STATE_DATA_ARRAY_MATRIX_DATA; } else { std::ostringstream str; str << "Child of " << GiftiCommon::tagMatrix.toAscii().constData() << " is \"" << qName.toAscii().constData() << "\" but should be one of \n" << " " << GiftiCommon::tagMatrixDataSpace.toAscii().constData() << "\n" << " " << GiftiCommon::tagMatrixTransformedSpace.toAscii().constData() << "\n" << " " << GiftiCommon::tagMatrixData.toAscii().constData(); errorMessage = str.str().c_str(); return false; } break; case STATE_DATA_ARRAY_MATRIX_DATA_SPACE: { std::ostringstream str; str << GiftiCommon::tagMatrixDataSpace.toAscii().constData() << " has child \"" << qName.toAscii().constData() << "\" but should not have any child nodes"; errorMessage = str.str().c_str(); return false; } break; case STATE_DATA_ARRAY_MATRIX_TRANSFORMED_SPACE: { std::ostringstream str; str << GiftiCommon::tagMatrixTransformedSpace.toAscii().constData() << " has child \"" << qName.toAscii().constData() << "\" but should not have any child nodes"; errorMessage = str.str().c_str(); return false; } break; case STATE_DATA_ARRAY_MATRIX_DATA: { std::ostringstream str; str << GiftiCommon::tagMatrixData.toAscii().constData() << " has child \"" << qName.toAscii().constData() << "\" but should not have any child nodes"; errorMessage = str.str().c_str(); return false; } break; } // // Save previous state // stateStack.push(previousState); elementText = ""; // // Continue parsing // return true; } /** * end an element. */ bool GiftiDataArrayFileSaxReader::endElement(const QString& /* namspaceURI */, const QString& /* localName */, const QString& qName) { if (DebugControl::getDebugOn()) { std::cout << "End Element: " << qName.toAscii().constData() << std::endl; } switch (state) { case STATE_NONE: break; case STATE_GIFTI: break; case STATE_METADATA: metaData = NULL; break; case STATE_METADATA_MD: if ((metaDataName.isEmpty() == false) && (metaDataValue.isEmpty() == false)) { if (metaData != NULL) { metaData->set(metaDataName, metaDataValue); } else { errorMessage = "ERROR: Have metadata name/value but no MetaDeta."; return false; } metaDataName = ""; metaDataValue = ""; } break; case STATE_METADATA_MD_NAME: metaDataName = elementText; break; case STATE_METADATA_MD_VALUE: metaDataValue = elementText; break; case STATE_LABEL_TABLE: labelTable = NULL; break; case STATE_LABEL_TABLE_LABEL: labelTable->setLabel(labelIndex, elementText); labelTable->setColorFloat(labelIndex, labelRed, labelGreen, labelBlue, labelAlpha); break; case STATE_DATA_ARRAY: if (dataArray != NULL) { giftiFile->addDataArray(dataArray); dataArray = NULL; } else { } break; case STATE_DATA_ARRAY_DATA: if (processArrayData() == false) { return false; } break; case STATE_DATA_ARRAY_MATRIX: matrix = NULL; break; case STATE_DATA_ARRAY_MATRIX_DATA_SPACE: matrix->setDataSpaceName(elementText); break; case STATE_DATA_ARRAY_MATRIX_TRANSFORMED_SPACE: matrix->setTransformedSpaceName(elementText); break; case STATE_DATA_ARRAY_MATRIX_DATA: { QTextStream ts(&elementText); double m[4][4]; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { ts >> m[i][j]; } } matrix->setMatrix(m); } break; } // // Clear out for new elements // elementText = ""; // // Go to previous state // if (stateStack.empty()) { errorMessage = "State stack is isEmpty while reading XML NiftDataFile."; return false; } state = stateStack.top(); stateStack.pop(); // // Continue parsing // return true; } /** * create a data array. */ bool GiftiDataArrayFileSaxReader::createDataArray(const QXmlAttributes& attributes) { // // Intent // QString intentName = attributes.value(GiftiCommon::attIntent); if (intentName.isEmpty()) { intentName = attributes.value("Intent"); } if (intentName.isEmpty()) { errorMessage = "Required attribute " + GiftiCommon::attIntent + " not found for DataArray"; return false; } if (GiftiDataArray::intentNameValid(intentName) == false) { errorMessage = "Intent name invalid: " + intentName; return false; } // // Data type name // const QString dataTypeName = attributes.value(GiftiCommon::attDataType); if (dataTypeName.isEmpty()) { errorMessage = "Required attribute " + GiftiCommon::attDataType + " not found for DataArray"; return false; } bool dataTypeNameValid = false; dataTypeForReadingArrayData = GiftiDataArray::getDataTypeFromName(dataTypeName, &dataTypeNameValid); if (dataTypeNameValid == false) { errorMessage = "Attribute " + GiftiCommon::attDataType + "is invalid: " + dataTypeName; return false; } // // Encoding // const QString encodingName = attributes.value(GiftiCommon::attEncoding); if (encodingName.isEmpty()) { errorMessage = "Required attribute " + GiftiCommon::attEncoding + " not found for DataArray"; return false; } bool validEncoding = false; encodingForReadingArrayData = GiftiDataArray::getEncodingFromName(encodingName, &validEncoding); if (validEncoding == false) { errorMessage = "Attribute " + GiftiCommon::attEncoding + "is invalid: " + encodingName; return false; } // // External File Name // externalFileNameForReadingData = attributes.value(GiftiCommon::attExternalFileName); // // External File Offset // externalFileOffsetForReadingData = 0; const QString offsetString = attributes.value(GiftiCommon::attExternalFileOffset); if (offsetString.isEmpty() == false) { bool validOffsetFlag = false; externalFileOffsetForReadingData = offsetString.toInt(&validOffsetFlag); if (validOffsetFlag == false) { throw FileException("File Offset is not an integer (" + offsetString + ")"); } } // // Endian // endianAttributeNameForReadingArrayData = attributes.value(GiftiCommon::attEndian); if (endianAttributeNameForReadingArrayData.isEmpty()) { errorMessage = "Required attribute " + GiftiCommon::attEndian + " not found for DataArray"; return false; } if ((endianAttributeNameForReadingArrayData != GiftiCommon::endianBig) && (endianAttributeNameForReadingArrayData != GiftiCommon::endianLittle)) { errorMessage = "Attribute " + GiftiCommon::attEndian + "is invalid: " + endianAttributeNameForReadingArrayData; return false; } // // Dimensions // const QString dimString = attributes.value(GiftiCommon::attDimensionality); if (dimString.isEmpty()) { errorMessage = "Required attribute " + GiftiCommon::attDimensionality + " not found for DataArray"; return false; } const int numDimensions = dimString.toInt(); dimensionsForReadingArrayData.clear(); for (int i = 0; i < numDimensions; i++) { const QString dimNumString = attributes.value(GiftiCommon::getAttDim(i)); if (dimNumString.isEmpty()) { errorMessage = "Required dimension " + GiftiCommon::getAttDim(i) + " not found for DataArray"; return false; } const int dim = dimNumString.toInt(); dimensionsForReadingArrayData.push_back(dim); } // // Data Location // /* const QString dataLocationString = attributes.value(GiftiCommon::attDataLocation); if (dataLocationString.isEmpty()) { errorMessage = "Required attribute " + GiftiCommon::attDataLocation + " not found for DataArray"; return false; } bool validDataLocation = false; dataLocationForReadingArrayData = GiftiDataArray::getDataLocationFromName(dataLocationString, &validDataLocation); if (validDataLocation == false) { errorMessage = "Attribute " + GiftiCommon::attDataLocation + "is invalid: " + dataLocationString; return false; } if (dataLocationForReadingArrayData == GiftiDataArray::DATA_LOCATION_EXTERNAL) { errorMessage = "External data storage not supported."; return false; } */ // // Subscript order // const QString subscriptOrderString = attributes.value(GiftiCommon::attArraySubscriptingOrder); if (subscriptOrderString.isEmpty()) { errorMessage = "Required attribute " + GiftiCommon::attArraySubscriptingOrder + " not found for DataArray"; return false; } bool validArraySubscriptingOrder = false; arraySubscriptingOrderForReadingArrayData = GiftiDataArray::getArraySubscriptingOrderFromName( subscriptOrderString, &validArraySubscriptingOrder); if (validArraySubscriptingOrder == false) { errorMessage = "Attribute " + GiftiCommon::attArraySubscriptingOrder + "is invalid: " + subscriptOrderString; return false; } dataArray = new GiftiDataArray(giftiFile, intentName); return true; } /** * process the array data into numbers. */ bool GiftiDataArrayFileSaxReader::processArrayData() { // // Should the data arrays be read ? // //if (giftiFile->getReadMetaDataOnlyFlag()) { // return true; //} try { dataArray->readFromText(elementText, endianAttributeNameForReadingArrayData, arraySubscriptingOrderForReadingArrayData, dataTypeForReadingArrayData, dimensionsForReadingArrayData, encodingForReadingArrayData, externalFileNameForReadingData, externalFileOffsetForReadingData); } catch (FileException& e) { errorMessage = e.whatQString(); return false; } return true; } /** * get characters in an element. */ bool GiftiDataArrayFileSaxReader::characters(const QString& s) { if (DebugControl::getDebugOn()) { std::cout << "Characters (50 max): " << s.left(50).toAscii().constData() << std::endl; } elementText += s; // // Continue parsing // return true; } /** * a fatal error occurs. */ bool GiftiDataArrayFileSaxReader::fatalError(const QXmlParseException& e) { std::ostringstream str; str << "Fatal Error at line number: " << e.lineNumber() << "\n" << "Column number: " << e.columnNumber() << "\n" << "Message: " << e.message().toAscii().constData(); if (errorMessage.isEmpty() == false) { str << "\n" << errorMessage.toAscii().constData(); } errorMessage = str.str().c_str(); // // Stop parsing // return false; } caret-5.6.4~dfsg.1.orig/caret_files/GiftiDataArrayFile.h0000664000175000017500000002426511572067322022656 0ustar michaelmichael#ifndef __GIFTI_DATA_ARRAY_FILE_H__ #define __GIFTI_DATA_ARRAY_FILE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "AbstractFile.h" #include "FileException.h" #include "GiftiDataArray.h" #include "GiftiLabelTable.h" class DeformationMapFile; class QDataStream; class QDomDocument; class QDomElement; class QFile; class QTextStream; /// 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 GiftiDataArrayFile : public AbstractFile { public: /// append array index values enum APPEND_ARRAY_INDEX { APPEND_ARRAY_NEW = -1, APPEND_ARRAY_DO_NOT_LOAD = -2 }; /// constructor GiftiDataArrayFile(const QString& descriptiveName, const QString& defaultDataArrayIntentIn, const GiftiDataArray::DATA_TYPE defaultDataTypeIn, const QString& defaultExt, const FILE_FORMAT defaultWriteTypeIn, const FILE_IO supportsAsciiFormat, const FILE_IO supportsBinaryFormat, const FILE_IO supportsOtherFormat, const FILE_IO supportsCSVfFormat, const bool dataAreIndicesIntoLabelTableIn); /// constructor for generic gifti data array file GiftiDataArrayFile(); // copy constructor GiftiDataArrayFile(const GiftiDataArrayFile& nndf); // destructor virtual ~GiftiDataArrayFile(); // assignment operator GiftiDataArrayFile& operator=(const GiftiDataArrayFile& nndf); // add a data array virtual void addDataArray(GiftiDataArray* nda); // add rows to this file. void addRows(const int numberOfRowsToAdd); // append a data array file to this one virtual void append(const GiftiDataArrayFile& naf) throw (FileException); // 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 GiftiDataArrayFile& naf, std::vector& indexDestination, const FILE_COMMENT_MODE fcm) throw (FileException); /// compare a file for unit testing (returns true if "within tolerance") virtual bool compareFileForUnitTesting(const AbstractFile* af, const float tolerance, QString& messageOut) const; // Clear the gifti array data file. virtual void clear(); // returns true if the file is isEmpty (contains no data) virtual bool empty() const; /// get the number of data arrays int getNumberOfDataArrays() const { return dataArrays.size() ; } /// get a data array GiftiDataArray* getDataArray(const int arrayNumber) { return dataArrays[arrayNumber]; } /// get a data array (const method) const GiftiDataArray* getDataArray(const int arrayNumber) const { return dataArrays[arrayNumber]; } /// reset a data array virtual void resetDataArray(const int arrayIndex); /// remove a data array virtual void removeDataArray(const GiftiDataArray* arrayPointer); /// remove a data array virtual void removeDataArray(const int arrayIndex); // get all of the data array names void getAllArrayNames(std::vector& names) const; // get the specified data array's name QString getDataArrayName(const int arrayIndex) const; // get the index of the data array with the specified name int getDataArrayWithNameIndex(const QString& n) const; // get the data array with the specified name GiftiDataArray* getDataArrayWithName(const QString& n); // get the data array with the specified name const GiftiDataArray* getDataArrayWithName(const QString& n) const; // get the index of the data array of the specified intent int getDataArrayWithIntentIndex(const QString& catName) const; // get the data array of the specified intent GiftiDataArray* getDataArrayWithIntent(const QString& catName); // get the data array of the specified intent (const method) const GiftiDataArray* getDataArrayWithIntent(const QString& catName) const; // get the comment for a data array QString getDataArrayComment(const int arrayIndex) const; // set the name of a data array void setDataArrayName(const int arrayIndex, const QString& name); // set the comment for a data array void setDataArrayComment(const int arrayIndex, const QString& comm); // append to the comment for a data array void appendToDataArrayComment(const int arrayIndex, const QString& comm); // prepend to the comment for a data array void prependToDataArrayComment(const int arrayIndex, const QString& 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; } /// see if gifti data array data files are enabled static bool getGiftiXMLEnabled() { return giftiXMLFilesEnabled; } /// set gifti data array files enabled static void setGiftiXMLEnabled(const bool b) { giftiXMLFilesEnabled = b; } /// get the current version for GiftiDataArrayFiles static float getCurrentFileVersion() { return 1.0; } /// get the default data array intent QString getDefaultDataArrayIntent() const { return defaultDataArrayIntent; } /// get the default data array intent void setDefaultDataArrayIntent(const QString& newIntentName); /// set the number of nodes for sparse node index files (NIFTI_INTENT_NODE_INDEX) void setNumberOfNodesForSparseNodeIndexFiles(const int numNodes); protected: // append helper for files where data are label indices void appendLabelDataHelper(const GiftiDataArrayFile& naf, const std::vector& arrayWillBeAppended, std::vector& oldIndicesToNewIndicesTable); // copy helper void copyHelperGiftiDataArrayFile(const GiftiDataArrayFile& nndf); /// read legacy file format data virtual void readLegacyFileData(QFile& file, QTextStream& stream, QDataStream& binStream) throw (FileException); /// write legacy file format data virtual void writeLegacyFileData(QTextStream& stream, QDataStream& binStream) throw (FileException); // read the XML file virtual void readFileDataXML(QFile& file) throw (FileException); // write the XML file virtual void writeFileDataXML(QTextStream& stream) throw (FileException); /// Read the contents of the file (header has already been read) virtual void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& rootElement) throw (FileException); /// Write the file's data (header has already been written) virtual void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& xmlDoc, QDomElement& rootElement) throw (FileException); // process NIFTI_INTENT_NODE_INDEX arrays void procesNiftiIntentNodeIndexArrays() throw (FileException); // validate the data arrays (optional for subclasses) virtual void validateDataArrays() throw (FileException); /// the data arrays std::vector dataArrays; /// the label table GiftiLabelTable labelTable; /// the file's metadata GiftiMetaData metaData; /// the default data type GiftiDataArray::DATA_TYPE defaultDataType; /// default data array intent for this file QString defaultDataArrayIntent; /// data arrays contain indices into label table bool dataAreIndicesIntoLabelTable; /// gifti XML files enabled static bool giftiXMLFilesEnabled; /// number of nodes in sparse node index files (NIFTI_INTENT_NODE_INDEX array) int numberOfNodesForSparseNodeIndexFile; /*!!!! be sure to update copyHelperGiftiDataArrayFile if new member added !!!!*/ // // friends // }; #endif // __GIFTI_DATA_ARRAY_FILE_H__ #ifdef __GIFTI_DATA_ARRAY_FILE_MAIN__ bool GiftiDataArrayFile::giftiXMLFilesEnabled = true; #endif // __GIFTI_DATA_ARRAY_FILE_MAIN__ caret-5.6.4~dfsg.1.orig/caret_files/GiftiDataArrayFile.cxx0000664000175000017500000012515711572067322023233 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "PaintFile.h" #include #include #include #include "DebugControl.h" #include "FileUtilities.h" #include "GiftiCommon.h" #define __GIFTI_DATA_ARRAY_FILE_MAIN__ #include "GiftiDataArrayFile.h" #undef __GIFTI_DATA_ARRAY_FILE_MAIN__ #include "GiftiDataArrayFileStreamReader.h" #include "GiftiDataArrayFileSaxReader.h" #include "MetricFile.h" #include "SurfaceShapeFile.h" #include "PaintFile.h" #include "StringUtilities.h" /** * Constructor */ GiftiDataArrayFile::GiftiDataArrayFile(const QString& descriptiveName, const QString& defaultDataArrayIntentIn, const GiftiDataArray::DATA_TYPE defaultDataTypeIn, const QString& defaultExt, const FILE_FORMAT defaultWriteTypeIn, const FILE_IO supportsAsciiFormat, const FILE_IO supportsBinaryFormat, const FILE_IO supportsOtherFormat, const FILE_IO supportsCSVfFormat, const bool dataAreIndicesIntoLabelTableIn) : AbstractFile(descriptiveName, defaultExt, true, defaultWriteTypeIn, supportsAsciiFormat, supportsBinaryFormat, AbstractFile::FILE_IO_READ_AND_WRITE, AbstractFile::FILE_IO_READ_AND_WRITE, AbstractFile::FILE_IO_READ_AND_WRITE, supportsOtherFormat, supportsCSVfFormat) { defaultDataArrayIntent = defaultDataArrayIntentIn; defaultDataType = defaultDataTypeIn; dataAreIndicesIntoLabelTable = dataAreIndicesIntoLabelTableIn; numberOfNodesForSparseNodeIndexFile = 0; if (giftiXMLFilesEnabled) { setFileReadWriteType(FILE_FORMAT_XML, FILE_IO_READ_AND_WRITE); setFileReadWriteType(FILE_FORMAT_XML_BASE64, FILE_IO_READ_AND_WRITE); setFileReadWriteType(FILE_FORMAT_XML_GZIP_BASE64, FILE_IO_READ_AND_WRITE); setFileReadWriteType(FILE_FORMAT_XML_EXTERNAL_BINARY, FILE_IO_READ_AND_WRITE); } else { setFileReadWriteType(FILE_FORMAT_XML, FILE_IO_READ_ONLY); setFileReadWriteType(FILE_FORMAT_XML_BASE64, FILE_IO_READ_ONLY); setFileReadWriteType(FILE_FORMAT_XML_GZIP_BASE64, FILE_IO_READ_ONLY); setFileReadWriteType(FILE_FORMAT_XML_EXTERNAL_BINARY, FILE_IO_READ_ONLY); } // // Set write type and possibly override with the preferred write type // // NOTE: This code is also in the AbstractFile constructor // but is needed here since supported write types are altered above // const std::vector availableWriteTypes = getPreferredWriteType(); for (unsigned int i = 0; i < availableWriteTypes.size(); i++) { if (getCanWrite(availableWriteTypes[i])) { setFileWriteType(availableWriteTypes[i]); break; } } } /** * Constructor for generic gifti data array file */ GiftiDataArrayFile::GiftiDataArrayFile() : AbstractFile("GiftiDataArrayFile", // descriptive name ".gii", // default extension true, // has a header (metadata) FILE_FORMAT_XML, // default writing format is XML FILE_IO_NONE, // does not support caret ascii format FILE_IO_NONE, // does not support caret binary format FILE_IO_READ_AND_WRITE, // reads and writes XML ascii data #ifdef HAVE_VTK FILE_IO_READ_AND_WRITE, // reads and writes XML base64 binary data FILE_IO_READ_AND_WRITE, // reads and writes XML compressed base64 binary data #else // HAVE_VTK FILE_IO_NONE, // DOES NOT read and write XML base64 binary data FILE_IO_NONE, // DOES NOT read and write XML compressed base64 binary data #endif // HAVE_VTK FILE_IO_NONE, // does not support "other" format FILE_IO_NONE) // does not support "csvf" format { defaultDataArrayIntent = "NIFTI_INTENT_NONE"; defaultDataType = GiftiDataArray::DATA_TYPE_FLOAT32; dataAreIndicesIntoLabelTable = false; numberOfNodesForSparseNodeIndexFile = 0; setFileReadWriteType(FILE_FORMAT_XML, FILE_IO_READ_AND_WRITE); #ifdef HAVE_VTK setFileReadWriteType(FILE_FORMAT_XML_BASE64, FILE_IO_READ_AND_WRITE); setFileReadWriteType(FILE_FORMAT_XML_GZIP_BASE64, FILE_IO_READ_AND_WRITE); #else // HAVE_VTK setFileReadWriteType(FILE_FORMAT_XML_BASE64, FILE_IO_NONE); setFileReadWriteType(FILE_FORMAT_XML_GZIP_BASE64, FILE_IO_NONE); #endif // HAVE_VTK setFileReadWriteType(FILE_FORMAT_XML_EXTERNAL_BINARY, FILE_IO_READ_AND_WRITE); } /** * copy constructor. */ GiftiDataArrayFile::GiftiDataArrayFile(const GiftiDataArrayFile& nndf) : AbstractFile(nndf) { copyHelperGiftiDataArrayFile(nndf); } /** * assignment operator. */ GiftiDataArrayFile& GiftiDataArrayFile::operator=(const GiftiDataArrayFile& nndf) { if (this != &nndf) { AbstractFile::operator=(nndf); copyHelperGiftiDataArrayFile(nndf); } return *this; } /** * copy helper. */ void GiftiDataArrayFile::copyHelperGiftiDataArrayFile(const GiftiDataArrayFile& nndf) { labelTable = nndf.labelTable; metaData = nndf.metaData; defaultDataType = nndf.defaultDataType; defaultDataArrayIntent = nndf.defaultDataArrayIntent; dataAreIndicesIntoLabelTable = nndf.dataAreIndicesIntoLabelTable; numberOfNodesForSparseNodeIndexFile = nndf.numberOfNodesForSparseNodeIndexFile; int numArrays = this->getNumberOfDataArrays(); for (int i = (numArrays - 1); i >= 0; i--) { this->removeDataArray(i); } for (unsigned int i = 0; i < nndf.dataArrays.size(); i++) { addDataArray(new GiftiDataArray(*nndf.dataArrays[i])); } } /** * Destructor */ GiftiDataArrayFile::~GiftiDataArrayFile() { clear(); } /** * compare a file for unit testing (returns true if "within tolerance"). */ bool GiftiDataArrayFile::compareFileForUnitTesting(const AbstractFile* af, const float tolerance, QString& messageOut) const { messageOut = ""; const GiftiDataArrayFile* gdaf = dynamic_cast(af); if (gdaf == NULL) { messageOut += "ERROR: File for comparison is not a GiftiDataArrayFile or subtype.\n"; return false; } const int numLabels = labelTable.getNumberOfLabels(); if (numLabels != gdaf->labelTable.getNumberOfLabels()) { messageOut += "ERROR: The files contain a different number of labels.\n"; } else { int labelCount = 0; for (int k = 0; k < numLabels; k++) { if (labelTable.getLabel(k) != gdaf->getLabelTable()->getLabel(k)) { labelCount++; } } if (labelCount > 0) { messageOut += "ERROR: The files have " + QString::number(labelCount) + " different labels.\n"; } } const int numArrays = getNumberOfDataArrays(); if (numArrays != gdaf->getNumberOfDataArrays()) { messageOut += "ERROR: The files contain a different number of data arrays (data columns)"; } else { for (int i = 0; i < numArrays; i++) { const GiftiDataArray* gdf1 = getDataArray(i); const GiftiDataArray* gdf2 = gdaf->getDataArray(i); const std::vector dim1 = gdf1->getDimensions(); const std::vector dim2 = gdf2->getDimensions(); if (dim1 != dim2) { messageOut += "ERROR: Data Array " + QString::number(i) + " have a different number of dimensions.\n"; } else { if (gdf1->getDataType() != gdf2->getDataType()) { messageOut += "ERROR: Data Array " + QString::number(i) + " are different data types.\n"; } else if (gdf1->getTotalNumberOfElements() != gdf2->getTotalNumberOfElements()) { messageOut += "ERROR: Data Array " + QString::number(i) + " have a different number of total elements.\n"; } else { const int numElem = gdf1->getTotalNumberOfElements(); int diffCount = 0; switch (gdf1->getDataType()) { case GiftiDataArray::DATA_TYPE_FLOAT32: { const float* p1 = gdf1->getDataPointerFloat(); const float* p2 = gdf2->getDataPointerFloat(); for (int m = 0; m < numElem; m++) { float diff = p1[m] - p2[m]; if (diff < 0.0) diff = -diff; if (diff > tolerance) { diffCount++; } } } break; case GiftiDataArray::DATA_TYPE_INT32: { const int tol = static_cast(tolerance); const int32_t* p1 = gdf1->getDataPointerInt(); const int32_t* p2 = gdf2->getDataPointerInt(); for (int m = 0; m < numElem; m++) { float diff = p1[m] - p2[m]; if (diff < 0.0) diff = -diff; if (diff > tol) { diffCount++; } } } break; case GiftiDataArray::DATA_TYPE_UINT8: { const uint8_t tol = static_cast(tolerance); const uint8_t* p1 = gdf1->getDataPointerUByte(); const uint8_t* p2 = gdf2->getDataPointerUByte(); for (int m = 0; m < numElem; m++) { float diff = p1[m] - p2[m]; if (diff < 0.0) diff = -diff; if (diff > tol) { diffCount++; } } } break; } if (diffCount > 0) { messageOut += "ERROR: There are " + QString::number(diffCount) + " elements with a difference that are greater than " + QString::number(tolerance, 'f', 3) + " in data array " + QString::number(i) + ".\n"; } } } } } return (messageOut.isEmpty()); } /** * Set the name of a data array. */ void GiftiDataArrayFile::setDataArrayName(const int arrayIndex, const QString& name) { dataArrays[arrayIndex]->getMetaData()->set(GiftiMetaData::getMetaDataName(), name); setModified(); } /** * returns true if the file is isEmpty (contains no data). */ bool GiftiDataArrayFile::empty() const { return dataArrays.empty(); } /** * get the data array with the specified name. */ GiftiDataArray* GiftiDataArrayFile::getDataArrayWithName(const QString& n) { for (int i = 0; i < getNumberOfDataArrays(); i++) { if (getDataArrayName(i) == n) { return getDataArray(i); } } return NULL; } /** * get the data array with the specified name. */ const GiftiDataArray* GiftiDataArrayFile::getDataArrayWithName(const QString& n) const { for (int 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 GiftiDataArrayFile::getDataArrayWithNameIndex(const QString& n) const { for (int i = 0; i < getNumberOfDataArrays(); i++) { if (getDataArrayName(i) == n) { return i; } } return -1; } /** * get the data array of the specified intent. */ GiftiDataArray* GiftiDataArrayFile::getDataArrayWithIntent(const QString& catName) { for (int i = 0; i < getNumberOfDataArrays(); i++) { GiftiDataArray* gda = getDataArray(i); if (gda->getIntent() == catName) { return gda; } } return NULL; } /** * get the data array of the specified intent (const method). */ const GiftiDataArray* GiftiDataArrayFile::getDataArrayWithIntent(const QString& catName) const { for (int i = 0; i < getNumberOfDataArrays(); i++) { const GiftiDataArray* gda = getDataArray(i); if (gda->getIntent() == catName) { return gda; } } return NULL; } /** * get the index of the data array of the specified intent. */ int GiftiDataArrayFile::getDataArrayWithIntentIndex(const QString& catName) const { for (int i = 0; i < getNumberOfDataArrays(); i++) { const GiftiDataArray* gda = getDataArray(i); if (gda->getIntent() == catName) { return i; } } return -1; } /** * Get the name for a data array. */ QString GiftiDataArrayFile::getDataArrayName(const int arrayIndex) const { QString s; (void)dataArrays[arrayIndex]->getMetaData()->get(GiftiMetaData::getMetaDataName(), s); return s; } /** * Set the comment for a data array. */ void GiftiDataArrayFile::setDataArrayComment(const int arrayIndex, const QString& comm) { dataArrays[arrayIndex]->getMetaData()->set(GiftiMetaData::getMetaDataDescription(), comm); setModified(); } /** * Append to the comment for a data array. */ void GiftiDataArrayFile::appendToDataArrayComment(const int arrayIndex, const QString& comm) { if (comm.isEmpty() == false) { QString s(getDataArrayComment(arrayIndex)); s.append(comm); setDataArrayComment(arrayIndex, s); setModified(); } } /** * Prepend to the comment for a data array. */ void GiftiDataArrayFile::prependToDataArrayComment(const int arrayIndex, const QString& comm) { if (comm.isEmpty() == false) { QString s(comm); s.append(getDataArrayComment(arrayIndex)); setDataArrayComment(arrayIndex, s); setModified(); } } /** * Get the comment for a data array. */ QString GiftiDataArrayFile::getDataArrayComment(const int arrayIndex) const { QString s; (void)dataArrays[arrayIndex]->getMetaData()->get(GiftiMetaData::getMetaDataDescription(), s); return s; } /** * get the default data array intent. */ void GiftiDataArrayFile::setDefaultDataArrayIntent(const QString& newIntentName) { defaultDataArrayIntent = newIntentName; setModified(); } /** * */ void GiftiDataArrayFile::clear() { clearAbstractFile(); for (unsigned int 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 } /** * get all of the data array names. */ void GiftiDataArrayFile::getAllArrayNames(std::vector& names) const { names.clear(); for (int 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 GiftiDataArrayFile::checkForDataArraysWithSameName(std::vector& multipleArrayNames) const { multipleArrayNames.clear(); const int numArrays = getNumberOfDataArrays(); if (numArrays > 0) { std::set badNames; for (int i = 0; i < (numArrays - 1); i++) { for (int 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 GiftiDataArrayFile::addDataArray(GiftiDataArray* nda) { nda->setMyParentGiftiDataArrayFile(this); dataArrays.push_back(nda); setModified(); } /** * append a gifti array data file to this one. */ void GiftiDataArrayFile::append(const GiftiDataArrayFile& naf) throw (FileException) { const int numArrays = naf.getNumberOfDataArrays(); if (numArrays <= 0) { return; } // // Replace filename if "this" file is isEmpty // if (getNumberOfDataArrays() == 0) { setFileName(naf.getFileName()); } // // Handle cases where arrays are indices into the label table // std::vector labelIndicesRemapTable; if ((dataAreIndicesIntoLabelTable) || (naf.dataAreIndicesIntoLabelTable)) { std::vector arrayWillBeAppended(numArrays, true); appendLabelDataHelper(naf, arrayWillBeAppended, labelIndicesRemapTable); } // // Append the data arrays // for (int i = 0; i < naf.getNumberOfDataArrays(); i++) { GiftiDataArray* ndc = new GiftiDataArray(*(naf.dataArrays[i])); ndc->remapIntValues(labelIndicesRemapTable); ndc->setMyParentGiftiDataArrayFile(this); dataArrays.push_back(ndc); } 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. */ void GiftiDataArrayFile::append(const GiftiDataArrayFile& naf, std::vector& indexDestination, const FILE_COMMENT_MODE fcm) throw (FileException) { const int numArrays = naf.getNumberOfDataArrays(); if (numArrays <= 0) { return; } // // Handle cases where arrays are indices into the label table // std::vector labelIndicesRemapTable; if ((dataAreIndicesIntoLabelTable) || (naf.dataAreIndicesIntoLabelTable)) { bool haveOne = false; std::vector arrayWillBeAppended(numArrays, false); for (int i = 0; i < numArrays; i++) { if (indexDestination[i] >= -1) { arrayWillBeAppended[i] = true; haveOne = true; } } if (haveOne) { appendLabelDataHelper(naf, arrayWillBeAppended, labelIndicesRemapTable); } } // // Replace file name if this file is isEmpty // if (getNumberOfDataArrays() == 0) { setFileName(naf.getFileName()); } // // append the data arrays // for (int i = 0; i < numArrays; i++) { const int arrayIndex = indexDestination[i]; // // Replacing existing array ? // if (arrayIndex >= 0) { delete dataArrays[arrayIndex]; dataArrays[arrayIndex] = new GiftiDataArray(*(naf.dataArrays[i])); dataArrays[arrayIndex]->remapIntValues(labelIndicesRemapTable); dataArrays[arrayIndex]->setMyParentGiftiDataArrayFile(this); } // // create new array // else if (arrayIndex == -1) { GiftiDataArray* ndc = new GiftiDataArray(*(naf.dataArrays[i])); ndc->remapIntValues(labelIndicesRemapTable); ndc->setMyParentGiftiDataArrayFile(this); dataArrays.push_back(ndc); // // Lets others know where the array was placed // indexDestination[i] = getNumberOfDataArrays() - 1; } // // Ignore array // else { // nothing } } appendFileComment(naf, fcm); setModified(); } /** * 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 GiftiDataArrayFile::appendLabelDataHelper(const GiftiDataArrayFile& naf, const std::vector& arrayWillBeAppended, std::vector& oldIndicesToNewIndicesTable) { oldIndicesToNewIndicesTable.clear(); if ((dataAreIndicesIntoLabelTable == false) || (naf.dataAreIndicesIntoLabelTable == false)) { return; } const int numArrays = naf.getNumberOfDataArrays(); if (numArrays != static_cast(arrayWillBeAppended.size())) { return; } const GiftiLabelTable* nltNew = naf.getLabelTable(); const int numLabelsNew = nltNew->getNumberOfLabels(); if (numLabelsNew <= 0) { return; } oldIndicesToNewIndicesTable.resize(numLabelsNew, -1); // // Determine which labels will be appended // for (int i = 0; i < numArrays; i++) { GiftiDataArray* nda = naf.dataArrays[i]; if (nda->getDataType() == GiftiDataArray::DATA_TYPE_INT32) { const int numElem = nda->getTotalNumberOfElements(); if (numElem >= 0) { int32_t* dataPtr = nda->getDataPointerInt(); for (int i = 0; i < numElem; i++) { const int 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 (int i = 0; i < numLabelsNew; i++) { if (oldIndicesToNewIndicesTable[i] == -2) { int indx = myLabelTable->addLabel(nltNew->getLabel(i)); oldIndicesToNewIndicesTable[i] = indx; 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 GiftiDataArrayFile::addRows(const int numberOfRowsToAdd) { for (int i = 0; i < getNumberOfDataArrays(); i++) { dataArrays[i]->addRows(numberOfRowsToAdd); } setModified(); } /** * reset a data array. */ void GiftiDataArrayFile::resetDataArray(const int arrayIndex) { dataArrays[arrayIndex]->zeroize(); } /** * remove a data array. */ void GiftiDataArrayFile::removeDataArray(const int arrayIndex) { int numArrays = getNumberOfDataArrays(); if ((arrayIndex >= 0) && (arrayIndex < numArrays)) { delete dataArrays[arrayIndex]; for (int i = arrayIndex; i < (numArrays - 1); i++) { dataArrays[i] = dataArrays[i + 1]; } dataArrays.resize(numArrays - 1); } } /** * remove a data array. */ void GiftiDataArrayFile::removeDataArray(const GiftiDataArray* arrayPointer) { for (int i = 0; i < getNumberOfDataArrays(); i++) { if (getDataArray(i) == arrayPointer) { removeDataArray(i); break; } } } /** * Read the contents of the file (header has already been read). */ void GiftiDataArrayFile::readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& /*rootElement*/) throw (FileException) { switch (getFileReadType()) { case FILE_FORMAT_ASCII: readLegacyFileData(file, stream, binStream); break; case FILE_FORMAT_BINARY: readLegacyFileData(file, stream, binStream); break; case FILE_FORMAT_XML: readFileDataXML(file); break; case FILE_FORMAT_XML_BASE64: readFileDataXML(file); break; case FILE_FORMAT_XML_GZIP_BASE64: readFileDataXML(file); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: readFileDataXML(file); break; case FILE_FORMAT_OTHER: readLegacyFileData(file, stream, binStream); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: readLegacyFileData(file, stream, binStream); break; } if (getReadMetaDataOnlyFlag() == false) { procesNiftiIntentNodeIndexArrays(); } // // Force metric, paint, shape data arrays to float // if ((dynamic_cast(this) != NULL) || (dynamic_cast(this) != NULL) || (dynamic_cast(this) != NULL)) { int numDataArrays = this->getNumberOfDataArrays(); for (int i = 0; i < numDataArrays; i++) { this->getDataArray(i)->convertToDataType(this->defaultDataType); } } this->validateDataArrays(); } /** * Write the file's data (header has already been written). */ void GiftiDataArrayFile::writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException) { switch (getFileWriteType()) { case FILE_FORMAT_ASCII: writeLegacyFileData(stream, binStream); break; case FILE_FORMAT_BINARY: writeLegacyFileData(stream, binStream); break; case FILE_FORMAT_XML: writeFileDataXML(stream); break; case FILE_FORMAT_XML_BASE64: writeFileDataXML(stream); break; case FILE_FORMAT_XML_GZIP_BASE64: writeFileDataXML(stream); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: writeFileDataXML(stream); break; case FILE_FORMAT_OTHER: writeLegacyFileData(stream, binStream); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: writeLegacyFileData(stream, binStream); break; } } /** * read the XML file. */ void GiftiDataArrayFile::readFileDataXML(QFile& file) throw (FileException) { const bool readWithStreamReader = true; if (readWithStreamReader) { GiftiDataArrayFileStreamReader streamReader(&file, this); streamReader.readData(); } else { QXmlSimpleReader reader; GiftiDataArrayFileSaxReader saxReader(this); reader.setContentHandler(&saxReader); reader.setErrorHandler(&saxReader); // // Some constant to determine how to read a file based upon the file's size // const int oneMegaByte = 1048576; const qint64 bigFileSize = 25 * oneMegaByte; if (file.size() < bigFileSize) { // // This call reads the entire file at once but this is a problem // since the XML files can be very large and will cause the // QT XML parsing to crash // if (reader.parse(&file) == false) { throw FileException(filename, saxReader.getErrorMessage()); } } else { // // The following code reads the XML file in pieces // and hopefully will prevent QT from crashing when // reading large files // // // Create a data stream // QDataStream stream(&file); stream.setVersion(QDataStream::Qt_4_3); // // buffer for data read // const int bufferSize = oneMegaByte; char buffer[bufferSize]; // // the XML input source // QXmlInputSource xmlInput; int totalRead = 0; bool firstTime = true; while (stream.atEnd() == false) { int numRead = stream.readRawData(buffer, bufferSize); totalRead += numRead; if (DebugControl::getDebugOn()) { std::cout << "GIFTI large file read, total: " << numRead << ", " << totalRead << std::endl; } // // Place the input data into the XML input // xmlInput.setData(QByteArray(buffer, numRead)); // // Process the data that was just read // if (firstTime) { if (reader.parse(&xmlInput, true) == false) { throw FileException(filename, saxReader.getErrorMessage()); } } else { if (reader.parseContinue() == false) { throw FileException(filename, saxReader.getErrorMessage()); } } firstTime = false; } // // Tells parser that there is no more data // xmlInput.setData(QByteArray()); if (reader.parseContinue() == false) { throw FileException(filename, saxReader.getErrorMessage()); } } } // // Transfer MetaData // const GiftiMetaData::MetaDataContainer* data = metaData.getMetaData(); for (GiftiMetaData::ConstMetaDataIterator iter = data->begin(); iter != data->end(); iter++) { setHeaderTag(iter->first, iter->second); } // // Some GIFTI Label files have just a few labels with very large indices // which causes many empty indices in the LabelTable. Cleaning up // the label table compacts these into sequential indices starting // at zero. // //PaintFile* pf = dynamic_cast(this); //if (pf != NULL) { // if (pf->getNumberOfPaintNames() > 1000) { // pf->cleanUpPaintNames(); // } //} } /* { QXmlSimpleReader reader; GiftiDataArrayFileSaxReader saxReader(this); reader.setContentHandler(&saxReader); reader.setErrorHandler(&saxReader); // // Some constant to determine how to read a file based upon the file's size // const int oneMegaByte = 1048576; const qint64 bigFileSize = 25 * oneMegaByte; if (file.size() < bigFileSize) { // // This call reads the entire file at once but this is a problem // since the XML files can be very large and will cause the // QT XML parsing to crash // if (reader.parse(&file) == false) { throw FileException(filename, saxReader.getErrorMessage()); } } else { // // The following code reads the XML file in pieces // and hopefully will prevent QT from crashing when // reading large files // // // Create a data stream // QDataStream stream(&file); stream.setVersion(QDataStream::Qt_4_3); // // buffer for data read // const int bufferSize = oneMegaByte; char buffer[bufferSize]; // // the XML input source // QXmlInputSource xmlInput; int totalRead = 0; bool firstTime = true; while (stream.atEnd() == false) { int numRead = stream.readRawData(buffer, bufferSize); totalRead += numRead; if (DebugControl::getDebugOn()) { std::cout << "GIFTI large file read, total: " << numRead << ", " << totalRead << std::endl; } // // Place the input data into the XML input // xmlInput.setData(QByteArray(buffer, numRead)); // // Process the data that was just read // if (firstTime) { if (reader.parse(&xmlInput, true) == false) { throw FileException(filename, saxReader.getErrorMessage()); } } else { if (reader.parseContinue() == false) { throw FileException(filename, saxReader.getErrorMessage()); } } firstTime = false; } // // Tells parser that there is no more data // xmlInput.setData(QByteArray()); if (reader.parseContinue() == false) { throw FileException(filename, saxReader.getErrorMessage()); } } // // Transfer MetaData // const GiftiMetaData::MetaDataContainer* data = metaData.getMetaData(); for (GiftiMetaData::ConstMetaDataIterator iter = data->begin(); iter != data->end(); iter++) { setHeaderTag(iter->first, iter->second); } } */ /** * write the XML file. */ void GiftiDataArrayFile::writeFileDataXML(QTextStream& stream) throw (FileException) { // // 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; } QString giftiFileVersionString = QString::number(GiftiDataArrayFile::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"; int indent = 0; // // External binary file. // QString externalBinaryFileName; long externalBinaryFileDataOffset = 0; std::ofstream* externalBinaryOutputStream = NULL; if (encoding == GiftiDataArray::ENCODING_EXTERNAL_FILE_BINARY) { externalBinaryFileName = getFileNameNoPath() + ".data"; externalBinaryOutputStream = new std::ofstream(externalBinaryFileName.toAscii().constData(), std::ofstream::binary); if (externalBinaryOutputStream == NULL) { throw FileException("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 QString tag(iter->first); const QString 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 int 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(); } } /** * read legacy file format data. */ void GiftiDataArrayFile::readLegacyFileData(QFile& /*file*/, QTextStream& /* stream */, QDataStream& /* binStream */) throw (FileException) { throw FileException(filename, "GiftiDataArrayFile does not support reading legacy files."); } /** * write legacy file format data. */ void GiftiDataArrayFile::writeLegacyFileData(QTextStream& /* stream */, QDataStream& /* binStream */) throw (FileException) { throw FileException(filename, "GiftiDataArrayFile does not support writing legacy files."); } /** * set the number of nodes for sparse node index files (NIFTI_INTENT_NODE_INDEX). */ void GiftiDataArrayFile::setNumberOfNodesForSparseNodeIndexFiles(const int numNodes) { numberOfNodesForSparseNodeIndexFile = numNodes; } /** * process NIFTI_INTENT_NODE_INDEX arrays. */ void GiftiDataArrayFile::procesNiftiIntentNodeIndexArrays() throw (FileException) { // // See if there is a node index array // GiftiDataArray* nodeIndexArray = getDataArrayWithIntent(GiftiCommon::intentNodeIndex); if (nodeIndexArray != NULL) { // // Make sure node index array is integer type and one dimensional // if (nodeIndexArray->getDataType() != GiftiDataArray::DATA_TYPE_INT32) { throw FileException("Data type other than \"int\" not supported for data intent: " + GiftiCommon::intentNodeIndex); } if (nodeIndexArray->getNumberOfDimensions() < 1) { throw FileException("Dimensions other than one not supported for data intent: " + GiftiCommon::intentNodeIndex); } // // Make node index array integer // nodeIndexArray->convertToDataType(GiftiDataArray::DATA_TYPE_INT32); // // Get the node indices // const int numNodeIndices = nodeIndexArray->getDimension(0); if (numNodeIndices <= 0) { throw FileException("Dimension is zero for data intent: " + GiftiCommon::intentNodeIndex); } const int zeroIndex[2] = { 0, 0 }; const int32_t* indexData = nodeIndexArray->getDataInt32Pointer(zeroIndex); // // Find the true number of nodes // int numNodes = numberOfNodesForSparseNodeIndexFile; if (numNodes <= 0) { int minNodeIndex = 0; nodeIndexArray->getMinMaxValues(minNodeIndex, numNodes); } // // Check each data array // const int numArrays = getNumberOfDataArrays(); for (int i = 0; i < numArrays; i++) { GiftiDataArray* dataArray = getDataArray(i); if (dataArray->getIntent() != GiftiCommon::intentNodeIndex) { if (dataArray->getNumberOfDimensions() < 1) { throw FileException("Data Array with intent \"" + dataArray->getIntent() + " is not one-dimensional in sparse node file."); } if (dataArray->getDimension(0) != numNodeIndices) { throw FileException("Data Array with intent \"" + dataArray->getIntent() + " has a different number of nodes than the " "NIFTI_INTENT_NODE_INDEX array in the file."); } switch (dataArray->getDataType()) { case GiftiDataArray::DATA_TYPE_FLOAT32: { std::vector dataFloat(numNodes, 0.0); const float* readPtr = dataArray->getDataFloat32Pointer(zeroIndex); for (int m = 0; m < numNodeIndices; m++) { dataFloat[indexData[m]] = readPtr[m]; } std::vector newDim(1, numNodes); dataArray->setDimensions(newDim); for (int n = 0; n < numNodes; n++) { const int indxs[2] = { n, 0 }; dataArray->setDataFloat32(indxs, dataFloat[n]); } } break; case GiftiDataArray::DATA_TYPE_INT32: { std::vector dataInt(numNodes, 0); const int32_t* readPtr = dataArray->getDataInt32Pointer(zeroIndex); for (int m = 0; m < numNodeIndices; m++) { dataInt[indexData[m]] = readPtr[m]; } std::vector newDim(1, numNodes); dataArray->setDimensions(newDim); for (int n = 0; n < numNodes; n++) { const int indxs[2] = { n, 0 }; dataArray->setDataInt32(indxs, dataInt[n]); } } break; case GiftiDataArray::DATA_TYPE_UINT8: { std::vector dataByte(numNodes, 0); const uint8_t* readPtr = dataArray->getDataUInt8Pointer(zeroIndex); for (int m = 0; m < numNodeIndices; m++) { dataByte[indexData[m]] = readPtr[m]; } std::vector newDim(1, numNodes); dataArray->setDimensions(newDim); for (int n = 0; n < numNodes; n++) { const int indxs[2] = { n, 0 }; dataArray->setDataUInt8(indxs, dataByte[n]); } } break; } } } // // Remove the node index array // removeDataArray(nodeIndexArray); } } /** * validate the data arrays (optional for subclasses). */ void GiftiDataArrayFile::validateDataArrays() throw (FileException) { } caret-5.6.4~dfsg.1.orig/caret_files/GiftiDataArray.h0000664000175000017500000004516511572067322022060 0ustar michaelmichael #ifndef __GIFTI_DATA_ARRAY_H__ #define __GIFTI_DATA_ARRAY_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "FileException.h" #include "GiftiMatrix.h" #include "GiftiMetaData.h" class GiftiDataArrayFile; class QDomElement; class QTextStream; /// class GiftiDataArray. class GiftiDataArray { public: /// data types supported enum DATA_TYPE { /// 32 bit floating point DATA_TYPE_FLOAT32, /// 32 bit signed integer DATA_TYPE_INT32, /// 8 bit unsigned integer DATA_TYPE_UINT8 }; /// encoding enum ENCODING { /// internal ascii ENCODING_INTERNAL_ASCII, /// internal Base 64 Binary ENCODING_INTERNAL_BASE64_BINARY, /// internal Compressed Base 64 Binary ENCODING_INTERNAL_COMPRESSED_BASE64_BINARY, /// external file binary ENCODING_EXTERNAL_FILE_BINARY }; /// array subscripting order enum ARRAY_SUBSCRIPTING_ORDER { /// highest order first ARRAY_SUBSCRIPTING_ORDER_HIGHEST_FIRST, /// lowest order first (FORTRAN style) ARRAY_SUBSCRIPTING_ORDER_LOWEST_FIRST }; /// data endian enum ENDIAN { /// little endian ENDIAN_LITTLE, /// big endian ENDIAN_BIG }; /// data location /* enum DATA_LOCATION { /// location of data inside file DATA_LOCATION_INTERNAL, /// location of data external file DATA_LOCATION_EXTERNAL }; */ // constructor GiftiDataArray(GiftiDataArrayFile* parentGiftiDataArrayFileIn, const QString& intentIn, const DATA_TYPE dataTypeIn, const std::vector dimensionsIn, const ENCODING encodingIn = ENCODING_INTERNAL_ASCII); // constructor used when reading data GiftiDataArray(GiftiDataArrayFile* parentGiftiDataArrayFileIn, const QString& 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 int numRowsToAdd); // delete rows void deleteRows(const std::vector& rowsToDelete); // convert all data arrays to data type void convertToDataType(const DATA_TYPE newDataType); // set the dimensions void setDimensions(const std::vector dimensionsIn); // reset column virtual void clear(); /// set the node data file of which I am a member void setMyParentGiftiDataArrayFile(GiftiDataArrayFile* ndf) { parentGiftiDataArrayFile = ndf; } /// get the number of dimensions int getNumberOfDimensions() const { return dimensions.size(); } /// get the dimensions std::vector getDimensions() const { return dimensions; } /// current size of the data (in bytes) long getDataSizeInBytes() const { return data.size(); } /// get a dimension int getDimension(const int dimIndex) const { return dimensions[dimIndex]; } // get the number of rows (1st dimension) long getNumberOfRows() const; // get number of components per node (2nd dimension) long getNumberOfComponents() const; // get the total number of elements long getTotalNumberOfElements() const; // get data offset long getDataOffset(const long nodeNum, const long componentNum) const; // read a data array from text void readFromText(QString& text, const QString& dataEndianForReading, const ARRAY_SUBSCRIPTING_ORDER arraySubscriptingOrderForReading, const DATA_TYPE dataTypeForReading, const std::vector& dimensionsForReading, const ENCODING encodingForReading, const QString& externalFileNameForReading, const long externalFileOffsetForReading) throw (FileException); // write the data as XML void writeAsXML(QTextStream& stream, const int indentOffset, std::ofstream* externalBinaryOutputStream) throw (FileException); // get the data type name static QString getDataTypeName(const DATA_TYPE dataType); // convert a data type name to data type static DATA_TYPE getDataTypeFromName(const QString& name, bool* validDataTypeOut = NULL); // get encoding type name static QString getEncodingName(const ENCODING encoding); /// convert encoding name to encoding type static ENCODING getEncodingFromName(const QString& name, bool* validEncodingOut = NULL); /// get endian ENDIAN getEndian() const { return endian; } // set endian void setEndian(const ENDIAN e) { endian = e; } /// convert endian name to endian static ENDIAN getEndianFromName(const QString& name, bool* validEndianOut = NULL); /// get endian name static QString getEndianName(const ENDIAN e); /// get the system's endian static ENDIAN getSystemEndian(); /// get the data location type name //static QString getDataLocationName(const DATA_LOCATION& location); /// convert data location name to type //static DATA_LOCATION getDataLocationFromName(const QString& name, // bool* validDataLocationOut = NULL); /// get array subscripting order name static QString getArraySubscriptingOrderName(const ARRAY_SUBSCRIPTING_ORDER aso); /// convert array subscripting name to type static ARRAY_SUBSCRIPTING_ORDER getArraySubscriptingOrderFromName(const QString& name, bool* validArraySubscriptingOrderOut = NULL); // get external file information void getExternalFileInformation(QString& nameOut, long& offsetOut) const; // set external file information void setExternalFileInformation(const QString& nameIn, const long 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 int getNumberOfMatrices() const { return matrices.size(); } /// add a matrix void addMatrix(const GiftiMatrix& gm) { matrices.push_back(gm); } /// get a matrix GiftiMatrix* getMatrix(const int indx) { return &matrices[indx]; } /// remove all matrices void removeAllMatrices(); /// remove a matrix void removeMatrix(const int indx); /// get the matrix (const method) const GiftiMatrix* getMatrix(const int 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 DATA_TYPE getDataType() const { return dataType; } /// set the data type void setDataType(const DATA_TYPE dt) { dataType = dt; setModified(); } /// get the encoding ENCODING getEncoding() const { return encoding; } /// set the encoding void setEncoding(const ENCODING e) { encoding = e; setModified(); } /// get the data intent QString getIntent() const { return intentName; } /// set the data intent void setIntent(const QString& cat) { intentName = cat; setModified(); } /// valid intent name static bool intentNameValid(const QString& intentNameIn); /// get array subscripting order ARRAY_SUBSCRIPTING_ORDER getArraySubscriptingOrder() const { return arraySubscriptingOrder; } /// set array subscripting order void setArraySubscriptingOrder(const ARRAY_SUBSCRIPTING_ORDER 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 the data array modified (actually set's the modified flag for file containing this) void setModified(); // 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; // get minimum and maximum values (valid for float data only) void getMinMaxValues(float& minValue, float& maxValue) const; // set min max values invalid inline void clearMinMaxFloatValuesValid() { minMaxFloatValuesValid = false; } /// get data column min/max for the specified percentages void getMinMaxValuesFromPercentages(const float negMaxPct, const float negMinPct, const float posMinPct, const float posMaxPct, float& negMaxValueOut, float& negMinValueOut, float& posMinValueOut, float& posMaxValueOut); inline void clearMaxMaxPercentageValuesValid() { minMaxPercentageValuesValid = false; } // remap integer values that are indices to a table void remapIntValues(const std::vector& remappingTable); // get the data type appropriate for the intent (returns true if valid intent) static bool getDataTypeAppropriateForIntent(const QString& intentIn, DATA_TYPE& dataTypeOut); // get an offset for indices into data (dimensionality of indices must be same as data) long getDataOffset(const int indices[]) const; // get a float value (data type must be float and dimensionality of indices must be same as data) float getDataFloat32(const int 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 int indices[]) const; // get an int value (data type must be int and dimensionality of indices must be same as data) int32_t getDataInt32(const int 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 int 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 int 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 int indices[]) const; // set a float value (data type must be float and dimensionality of indices must be same as data) void setDataFloat32(const int 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 int 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 int indices[], const uint8_t dataValue) const; protected: // 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 ENDIAN newEndian); /// update the array's metadata after reading the array void updateMetaDataAfterReading(); /// update the array's metadata before writing the array void updateMetaDataBeforeWriting(); /// convert array indexing order of data void convertArrayIndexingOrder() throw (FileException); /// 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; /// data array file of which this is a member GiftiDataArrayFile* parentGiftiDataArrayFile; /// dimensions of the data std::vector dimensions; /// data type DATA_TYPE dataType; /// encoding of data ENCODING encoding; // endian of data ENDIAN endian; /// location of data //DATA_LOCATION dataLocation; /// intent name QString intentName; /// array subscripting order ARRAY_SUBSCRIPTING_ORDER arraySubscriptingOrder; /// external file name QString externalFileName; /// external file offset long externalFileOffset; /// 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 int minValueInt; /// maximum int value mutable int 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; // ***** BE SURE TO UPDATE copyHelper() if elements are added ****** /// allow NodeDataFile access to protected elements friend class GiftiDataArrayFile; }; /* /// floating point GIFTI data array class GiftiDataArrayFloat : public GiftiDataArray { public: /// constructor GiftiDataArrayFloat(GiftiNodeDataFile* ndf, const std::vector dimensionsIn) : GiftiDataArray(ndf, DATA_TYPE_FLOAT32, dimensionsIn) { }; /// destructor virtual ~GiftiDataArrayFloat(); }; /// 32 bit integer GIFTI data array class GiftiDataArrayInt32 : public GiftiDataArray { public: /// constructor GiftiDataArrayInt32(GiftiNodeDataFile* ndf, const std::vector dimensionsIn) : GiftiDataArray(ndf, DATA_TYPE_INT32, dimensionsIn) { }; /// destructor virtual ~GiftiDataArrayInt32(); }; /// 8-bit unsigned byte GIFTI data array class GiftiDataArrayUInt8 : public GiftiDataArray { public: /// constructor GiftiDataArrayUInt8(GiftiNodeDataFile* ndf, const std::vector dimensionsIn) : GiftiDataArray(ndf, DATA_TYPE_UINT8, dimensionsIn) { }; /// destructor virtual ~GiftiDataArrayUInt8(); }; */ #endif // __GIFTI_DATA_ARRAY_H__ caret-5.6.4~dfsg.1.orig/caret_files/GiftiDataArray.cxx0000664000175000017500000020404711572067322022427 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include "DebugControl.h" #include "FileUtilities.h" #include "GiftiCommon.h" #include "GiftiDataArray.h" #include "GiftiDataArrayFile.h" #include "StringUtilities.h" #ifdef HAVE_VTK #include "vtkBase64Utilities.h" #include "vtkByteSwap.h" #include "vtkZLibDataCompressor.h" #endif // HAVE_VTK /** * constructor. */ GiftiDataArray::GiftiDataArray(GiftiDataArrayFile* parentGiftiDataArrayFileIn, const QString& intentIn, const DATA_TYPE dataTypeIn, const std::vector dimensionsIn, const ENCODING encodingIn) { parentGiftiDataArrayFile = parentGiftiDataArrayFileIn; intentName = intentIn; dataTypeSize = 0; dataPointerFloat = NULL; dataPointerInt = NULL; dataPointerUByte = NULL; clear(); dataType = dataTypeIn; setDimensions(dimensionsIn); encoding = encodingIn; endian = getSystemEndian(); arraySubscriptingOrder = ARRAY_SUBSCRIPTING_ORDER_HIGHEST_FIRST; externalFileName = ""; externalFileOffset = 0; //dataLocation = DATA_LOCATION_INTERNAL; if (intentName == GiftiCommon::intentCoordinates) { GiftiMatrix gm; gm.setDataSpaceName(GiftiCommon::spaceLabelTalairach); gm.setTransformedSpaceName(GiftiCommon::spaceLabelTalairach); matrices.push_back(gm); } //getDataTypeAppropriateForIntent(intent, dataType); metaData.set(GiftiCommon::metaDataNameUniqueID, QUuid::createUuid().toString()); } /** * constructor. */ GiftiDataArray::GiftiDataArray(GiftiDataArrayFile* parentGiftiDataArrayFileIn, const QString& intentIn) { parentGiftiDataArrayFile = parentGiftiDataArrayFileIn; intentName = intentIn; dataTypeSize = 0; dataPointerFloat = NULL; dataPointerInt = NULL; dataPointerUByte = NULL; clear(); dimensions.clear(); encoding = ENCODING_INTERNAL_ASCII; endian = getSystemEndian(); arraySubscriptingOrder = ARRAY_SUBSCRIPTING_ORDER_HIGHEST_FIRST; externalFileName = ""; externalFileOffset = 0; //dataLocation = DATA_LOCATION_INTERNAL; if (intentName == GiftiCommon::intentCoordinates) { GiftiMatrix gm; gm.setDataSpaceName(GiftiCommon::spaceLabelTalairach); gm.setTransformedSpaceName(GiftiCommon::spaceLabelTalairach); matrices.push_back(gm); } dataType = DATA_TYPE_FLOAT32; getDataTypeAppropriateForIntent(intentName, dataType); } /** * destructor. */ GiftiDataArray::~GiftiDataArray() { clear(); } /** * copy constructor. */ GiftiDataArray::GiftiDataArray(const GiftiDataArray& nda) { 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) { intentName = nda.intentName; encoding = nda.encoding; arraySubscriptingOrder = nda.arraySubscriptingOrder; dataType = nda.dataType; //dataLocation = nda.dataLocation; dataTypeSize = nda.dataTypeSize; endian = nda.endian; parentGiftiDataArrayFile = NULL; // caused modified to be set !! nda.parentGiftiDataArrayFile; 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 QString& intentIn, DATA_TYPE& dataTypeOut) { if (intentIn == GiftiCommon::intentCoordinates) { dataTypeOut = GiftiDataArray::DATA_TYPE_FLOAT32; } else if (intentIn == GiftiCommon::intentTimeSeries) { dataTypeOut = GiftiDataArray::DATA_TYPE_FLOAT32; } else if (intentIn == GiftiCommon::intentNormals) { dataTypeOut = GiftiDataArray::DATA_TYPE_FLOAT32; } else if (intentIn == GiftiCommon::intentLabels) { dataTypeOut = GiftiDataArray::DATA_TYPE_INT32; } else if ((intentIn == GiftiCommon::intentRGBA) || (intentIn == GiftiCommon::intentRGB)) { dataTypeOut = GiftiDataArray::DATA_TYPE_UINT8; } else if (intentIn == GiftiCommon::intentShape) { dataTypeOut = GiftiDataArray::DATA_TYPE_FLOAT32; } else if (intentIn == GiftiCommon::intentTensors) { dataTypeOut = GiftiDataArray::DATA_TYPE_FLOAT32; } else if (intentIn == GiftiCommon::intentTopologyTriangles) { dataTypeOut = GiftiDataArray::DATA_TYPE_INT32; } else if (intentIn.startsWith(GiftiCommon::intentPrefix)) { dataTypeOut = GiftiDataArray::DATA_TYPE_FLOAT32; } else { std::cout << "WARNING: unrecogized intent \"" << intentIn.toAscii().constData() << " in GiftiDataArray::getDataTypeAppropriateForIntent()." << std::endl; return false; } return true; } /** * add nodes. */ void GiftiDataArray::addRows(const int 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 // long numBytesInRow = 1; for (unsigned int i = 1; i < dimensions.size(); i++) { numBytesInRow = dimensions[i]; } numBytesInRow *= dataTypeSize; // // Remove the unneeded rows // for (unsigned int i = 0; i < rowsToDelete.size(); i++) { const int 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 // long dataSizeInBytes = 1; for (unsigned int i = 0; i < dimensions.size(); i++) { dataSizeInBytes *= dimensions[i]; } // // Bytes required by each data type // dataTypeSize = 0; switch (dataType) { case DATA_TYPE_FLOAT32: dataTypeSize = sizeof(float); break; case DATA_TYPE_INT32: dataTypeSize = sizeof(int32_t); break; case DATA_TYPE_UINT8: dataTypeSize = sizeof(uint8_t); 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 DATA_TYPE_FLOAT32: dataPointerFloat = (float*)&data[0]; break; case DATA_TYPE_INT32: dataPointerInt = (int32_t*)&data[0]; break; case DATA_TYPE_UINT8: dataPointerUByte = (uint8_t*)&data[0]; break; } } } /** * reset column. */ void GiftiDataArray::clear() { arraySubscriptingOrder = ARRAY_SUBSCRIPTING_ORDER_HIGHEST_FIRST; encoding = ENCODING_INTERNAL_ASCII; dataType = DATA_TYPE_FLOAT32; endian = getSystemEndian(); dataTypeSize = sizeof(float); metaData.clear(); nonWrittenMetaData.clear(); dimensions.clear(); setDimensions(dimensions); externalFileName = ""; externalFileOffset = 0; minMaxFloatValuesValid = false; minMaxPercentageValuesValid = false; // do not clear // parentGiftiDataFile; // arrayType; // setDimensions will call allocateData() which will set // dataPointer // dataPointerFloat // dataPointerInt // dataPointerUByte; } /** * get the number of nodes (1st dimension). */ long GiftiDataArray::getNumberOfRows() const { if (dimensions.empty() == false) { return dimensions[0]; } return 0; } /** * get the total number of elements. */ long GiftiDataArray::getTotalNumberOfElements() const { if (dimensions.empty()) { return 0; } long num = 1; for (unsigned int i = 0; i < dimensions.size(); i++) { num *= dimensions[i]; } return num; } /** * get number of components per node (2nd dimension). */ long GiftiDataArray::getNumberOfComponents() const { if (dimensions.size() > 1) { return dimensions[1]; } else if (dimensions.size() == 1) { return 1; } return 0; } /** * get data offset. */ long GiftiDataArray::getDataOffset(const long nodeNum, const long componentNum) const { const long off = nodeNum * dimensions[1] + componentNum; return off; } /** * get the data type name. */ QString GiftiDataArray::getDataTypeName(const DATA_TYPE dataType) { switch (dataType) { case DATA_TYPE_FLOAT32: return GiftiCommon::typeNameFloat32; break; case DATA_TYPE_INT32: return GiftiCommon::typeNameInt32; break; case DATA_TYPE_UINT8: return GiftiCommon::typeNameUInt8; break; } return ""; } /** * convert a data type name to data type. */ GiftiDataArray::DATA_TYPE GiftiDataArray::getDataTypeFromName(const QString& name, bool* validDataTypeOut) { if (validDataTypeOut != NULL) { *validDataTypeOut = true; } if (name == GiftiCommon::typeNameFloat32) { return DATA_TYPE_FLOAT32; } else if (name == GiftiCommon::typeNameInt32) { return DATA_TYPE_INT32; } else if (name == GiftiCommon::typeNameUInt8) { return DATA_TYPE_UINT8; } if (validDataTypeOut != NULL) { *validDataTypeOut = false; } return DATA_TYPE_FLOAT32; } /** * get the data location type name. */ /* QString GiftiDataArray::getDataLocationName(const DATA_LOCATION& location) { switch (location) { case DATA_LOCATION_INTERNAL: return GiftiCommon::dataLocationInternal; break; case DATA_LOCATION_EXTERNAL: return GiftiCommon::dataLocationExternal; break; } return GiftiCommon::dataLocationInternal; } */ /** * convert data location name to type. */ /* GiftiDataArray::DATA_LOCATION GiftiDataArray::getDataLocationFromName(const QString& name, bool* validDataLocationOut) { if (validDataLocationOut != NULL) { *validDataLocationOut = true; } if (name == GiftiCommon::dataLocationInternal) { return DATA_LOCATION_INTERNAL; } else if (name == GiftiCommon::dataLocationExternal) { return DATA_LOCATION_EXTERNAL; } if (validDataLocationOut != NULL) { *validDataLocationOut = false; } return DATA_LOCATION_INTERNAL; } */ /** * convert endian name to endian. */ GiftiDataArray::ENDIAN GiftiDataArray::getEndianFromName(const QString& name, bool* validEndianOut) { if (validEndianOut != NULL) { *validEndianOut = true; } if (name == GiftiCommon::endianBig) { return ENDIAN_BIG; } else if (name == GiftiCommon::endianLittle) { return ENDIAN_LITTLE; } if (validEndianOut != NULL) { *validEndianOut = false; } return getSystemEndian(); } /** * get endian name. */ QString GiftiDataArray::getEndianName(const ENDIAN e) { switch (e) { case ENDIAN_BIG: return GiftiCommon::endianBig; break; case ENDIAN_LITTLE: return GiftiCommon::endianLittle; break; } return ""; } /** * get the system's endian. */ GiftiDataArray::ENDIAN GiftiDataArray::getSystemEndian() { if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { return ENDIAN_BIG; } return ENDIAN_LITTLE; } /** * get encoding type name. */ QString GiftiDataArray::getEncodingName(const ENCODING encoding) { switch (encoding) { case ENCODING_INTERNAL_ASCII: return GiftiCommon::encodingNameInternalAscii; break; case ENCODING_INTERNAL_BASE64_BINARY: return GiftiCommon::encodingNameInternalBase64Binary; break; case ENCODING_INTERNAL_COMPRESSED_BASE64_BINARY: return GiftiCommon::encodingNameInternalBase64BinaryGZip; break; case ENCODING_EXTERNAL_FILE_BINARY: return GiftiCommon::encodingNameExternalBinary; } return ""; } /** * convert encoding name to encoding type. */ GiftiDataArray::ENCODING GiftiDataArray::getEncodingFromName(const QString& name, bool* validEncodingOut) { if (validEncodingOut != NULL) { *validEncodingOut = true; } if (name == GiftiCommon::encodingNameInternalAscii) { return ENCODING_INTERNAL_ASCII; } else if (name == GiftiCommon::encodingNameInternalBase64Binary) { return ENCODING_INTERNAL_BASE64_BINARY; } else if (name == GiftiCommon::encodingNameInternalBase64BinaryGZip) { return ENCODING_INTERNAL_COMPRESSED_BASE64_BINARY; } else if (name == GiftiCommon::encodingNameExternalBinary) { return ENCODING_EXTERNAL_FILE_BINARY; } if (validEncodingOut != NULL) { *validEncodingOut = false; } return ENCODING_INTERNAL_ASCII; } /** * get array subscripting order name. */ QString GiftiDataArray::getArraySubscriptingOrderName(const ARRAY_SUBSCRIPTING_ORDER aso) { switch (aso) { case ARRAY_SUBSCRIPTING_ORDER_HIGHEST_FIRST: return GiftiCommon::arraySubscriptingOrderHighestFirst; case ARRAY_SUBSCRIPTING_ORDER_LOWEST_FIRST: return GiftiCommon::arraySubscriptingOrderLowestFirst; } return GiftiCommon::arraySubscriptingOrderHighestFirst; } /** * convert array subscripting name to type. */ GiftiDataArray::ARRAY_SUBSCRIPTING_ORDER GiftiDataArray::getArraySubscriptingOrderFromName(const QString& name, bool* validArraySubscriptingOrderOut) { if (validArraySubscriptingOrderOut != NULL) { *validArraySubscriptingOrderOut = true; } if (name == GiftiCommon::arraySubscriptingOrderHighestFirst) { return ARRAY_SUBSCRIPTING_ORDER_HIGHEST_FIRST; } else if (name == GiftiCommon::arraySubscriptingOrderLowestFirst) { return ARRAY_SUBSCRIPTING_ORDER_LOWEST_FIRST; } if (validArraySubscriptingOrderOut != NULL) { *validArraySubscriptingOrderOut = false; } return ARRAY_SUBSCRIPTING_ORDER_HIGHEST_FIRST; } /** * get external file information. */ void GiftiDataArray::getExternalFileInformation(QString& nameOut, long& offsetOut) const { nameOut = externalFileName; offsetOut = externalFileOffset; } /** * set external file information. */ void GiftiDataArray::setExternalFileInformation(const QString& nameIn, const long offsetIn) { externalFileName = nameIn; externalFileOffset = offsetIn; } /** * remap integer values that are indices to a table. */ void GiftiDataArray::remapIntValues(const std::vector& remappingTable) { if (remappingTable.empty()) { return; } if (dataType != DATA_TYPE_INT32) { return; } const long num = getTotalNumberOfElements(); for (long i = 0; i < num; i++) { dataPointerInt[i] = remappingTable[dataPointerInt[i]]; } } /** * read a GIFTI data array from text. * Data array should already be initialized and allocated. */ void GiftiDataArray::readFromText(QString& text, const QString& dataEndianForReading, const ARRAY_SUBSCRIPTING_ORDER arraySubscriptingOrderForReading, const DATA_TYPE dataTypeForReading, const std::vector& dimensionsForReading, const ENCODING encodingForReading, const QString& externalFileNameForReading, const long externalFileOffsetForReading) throw (FileException) { const DATA_TYPE requiredDataType = dataType; dataType = dataTypeForReading; encoding = encodingForReading; endian = getEndianFromName(dataEndianForReading); setDimensions(dimensionsForReading); if (dimensionsForReading.size() == 0) { throw FileException("Data array has no dimensions."); } setExternalFileInformation(externalFileNameForReading, externalFileOffsetForReading); // // If NOT metadata only // if (parentGiftiDataArrayFile->getReadMetaDataOnlyFlag() == false) { // // Total number of elements in Data Array // const long numElements = getTotalNumberOfElements(); switch (encoding) { case ENCODING_INTERNAL_ASCII: { QTextStream stream(&text, QIODevice::ReadOnly); switch (dataType) { case DATA_TYPE_FLOAT32: { float* ptr = dataPointerFloat; for (long i = 0; i < numElements; i++) { stream >> *ptr; ptr++; } } break; case DATA_TYPE_INT32: { int32_t* ptr = dataPointerInt; for (long i = 0; i < numElements; i++) { stream >> *ptr; ptr++; } } break; case DATA_TYPE_UINT8: { uint8_t* ptr = dataPointerUByte; char c; for (long i = 0; i < numElements; i++) { stream >> c; *ptr = static_cast(c); ptr++; } } break; } } break; case ENCODING_INTERNAL_BASE64_BINARY: #ifdef HAVE_VTK { // // Decode the Base64 data using VTK's algorithm // const QByteArray ba = text.toAscii(); const char* textChars = ba.constData(); // crashes const char* textChars = text.toAscii().constData(); const unsigned long numDecoded = vtkBase64Utilities::Decode((const unsigned char*)textChars, data.size(), &data[0]); if (numDecoded != data.size()) { std::ostringstream str; str << "Decoding of Base64 Binary data failed.\n" << "Decoded " << numDecoded << " bytes but should be " << data.size() << " bytes."; throw FileException("", str.str().c_str()); } // // Is byte swapping needed ? // if (endian != getSystemEndian()) { byteSwapData(getSystemEndian()); } } #else // HAVE_VTK throw FileException("No support for Base64 data since VTK not available at compile time."); #endif // HAVE_VTK break; case ENCODING_INTERNAL_COMPRESSED_BASE64_BINARY: #ifdef HAVE_VTK { // // Decode the Base64 data using VTK's algorithm // unsigned char* dataBuffer = new unsigned char[data.size()]; const QByteArray ba = text.toAscii(); const char* textChars = ba.constData(); // crashes const char* textChars = text.toAscii().constData(); const unsigned long numDecoded = vtkBase64Utilities::Decode((const unsigned char*)textChars, data.size(), dataBuffer); if (numDecoded == 0) { throw FileException("", "Decoding of GZip Base64 Binary data failed."); } // // Uncompress the data using VTK's algorithm // vtkZLibDataCompressor* compressor = vtkZLibDataCompressor::New(); const unsigned long uncompressedDataLength = compressor->Uncompress(dataBuffer, numDecoded, &data[0], data.size()); if (uncompressedDataLength != data.size()) { std::ostringstream str; str << "Decompression of Binary data failed.\n" << "Uncompressed " << uncompressedDataLength << " bytes but should be " << data.size() << " bytes."; throw FileException("", str.str().c_str()); } // // Free memory // delete[] dataBuffer; compressor->Delete(); // // Is byte swapping needed ? // if (endian != getSystemEndian()) { byteSwapData(getSystemEndian()); } } #else // HAVE_VTK throw FileException("No support for Base64 data since VTK not available at compile time."); #endif // HAVE_VTK break; case ENCODING_EXTERNAL_FILE_BINARY: { if (externalFileName.isEmpty()) { throw FileException("External file name is empty."); } QFile file(externalFileName); if (file.open(QFile::ReadOnly)) { // // Move to the offset of the data // if (file.seek(externalFileOffset) == false) { throw FileException("Error moving to offset " + QString::number(externalFileOffset) + " in file " + externalFileName); } // // Set the number of bytes that must be read // long numberOfBytesToRead = 0; char* pointerToForReadingData = NULL; switch (dataType) { case DATA_TYPE_FLOAT32: numberOfBytesToRead = numElements * sizeof(float); pointerToForReadingData = (char*)dataPointerFloat; break; case DATA_TYPE_INT32: numberOfBytesToRead = numElements * sizeof(int32_t); pointerToForReadingData = (char*)dataPointerInt; break; case DATA_TYPE_UINT8: numberOfBytesToRead = numElements * sizeof(uint8_t); pointerToForReadingData = (char*)dataPointerUByte; break; } // // Read the data // All data may not be read in one call to stream.readRawData() // so loop until all data is read. // QDataStream stream(&file); stream.setVersion(QDataStream::Qt_4_3); long actualNumberOfBytesRead = 0; while (actualNumberOfBytesRead < numberOfBytesToRead) { const long numBytesRead = stream.readRawData( (char*)&pointerToForReadingData[actualNumberOfBytesRead], numberOfBytesToRead); if (numBytesRead <= 0) { break; } actualNumberOfBytesRead += numBytesRead; } if (actualNumberOfBytesRead != numberOfBytesToRead) { throw FileException("Tried to read " + QString::number(numberOfBytesToRead) + " from " + externalFileName + " but only read " + QString::number(actualNumberOfBytesRead) + "."); } // // Is byte swapping needed ? // if (endian != getSystemEndian()) { byteSwapData(getSystemEndian()); } } else { throw FileException("Error opening \"" + externalFileName + "\" \n" + file.errorString()); } } break; } // // Check if data type needs to be converted // if (requiredDataType != dataType) { if (intentName != GiftiCommon::intentNodeIndex) { convertToDataType(requiredDataType); } } // // Are array indices in opposite order // if (arraySubscriptingOrderForReading != arraySubscriptingOrder) { convertArrayIndexingOrder(); } // // Update metadata (GIFTI to Caret) // updateMetaDataAfterReading(); } // If NOT metadata only setModified(); } /** * convert array indexing order of data. */ void GiftiDataArray::convertArrayIndexingOrder() throw (FileException) { const int numDim = static_cast(dimensions.size()); if (numDim <= 1) { return; } if (numDim > 2) { throw FileException("Row/Column Major order conversion unavailable for arrays " "with dimensions greater than two."); } // // Swap data // if (numDim == 2) { int dimI = dimensions[0]; int dimJ = dimensions[1]; /* * If a dimensions is "1", the data does not need to be transposed. */ if ((dimI == 1) || (dimJ == 1)) { return; } // // Is matrix square? // if (dimI == dimJ) { switch (dataType) { case DATA_TYPE_FLOAT32: { for (long i = 1; i < dimI; i++) { for (long j = 0; j < i; j++) { const long indexLowerLeft = (i * dimJ) + j; const long indexUpperRight = (j * dimI) + i; float temp = dataPointerFloat[indexLowerLeft]; dataPointerFloat[indexLowerLeft] = dataPointerFloat[indexUpperRight]; dataPointerFloat[indexUpperRight] = temp; } } } break; case DATA_TYPE_INT32: { for (long i = 1; i < dimI; i++) { for (long j = 0; j < i; j++) { const long indexLowerLeft = (i * dimJ) + j; const long indexUpperRight = (j * dimI) + i; float temp = dataPointerInt[indexLowerLeft]; dataPointerInt[indexLowerLeft] = dataPointerInt[indexUpperRight]; dataPointerInt[indexUpperRight] = temp; } } } break; case DATA_TYPE_UINT8: { for (long i = 1; i < dimI; i++) { for (long j = 0; j < i; j++) { const long indexLowerLeft = (i * dimJ) + j; const long indexUpperRight = (j * dimI) + i; float temp = dataPointerUByte[indexLowerLeft]; dataPointerUByte[indexLowerLeft] = dataPointerUByte[indexUpperRight]; dataPointerUByte[indexUpperRight] = temp; } } } break; } } else { // // Copy the data // std::vector dataCopy = data; switch (dataType) { case DATA_TYPE_FLOAT32: { float* ptr = (float*)&(dataCopy[0]); for (long i = 0; i < dimI; i++) { for (long j = 0; j < dimJ; j++) { const long indx = (i * dimJ) + j; const long ptrIndex = (j * dimI) + i; dataPointerFloat[indx] = ptr[ptrIndex]; } } } break; case DATA_TYPE_INT32: { uint32_t* ptr = (uint32_t*)&(dataCopy[0]); for (long i = 0; i < dimI; i++) { for (long j = 0; j < dimJ; j++) { const long indx = (i * dimJ) + j; const long ptrIndex = (j * dimI) + i; dataPointerInt[indx] = ptr[ptrIndex]; } } } break; case DATA_TYPE_UINT8: { uint8_t* ptr = (uint8_t*)&(dataCopy[0]); for (long i = 0; i < dimI; i++) { for (long j = 0; j < dimJ; j++) { const long indx = (i * dimJ) + j; const long ptrIndex = (j * dimI) + i; dataPointerUByte[indx] = ptr[ptrIndex]; } } } break; } dimensions[0] = dimJ; dimensions[1] = dimI; } } } /** * write the data as XML. */ void GiftiDataArray::writeAsXML(QTextStream& stream, const int indentOffset, std::ofstream* externalBinaryOutputStream) throw (FileException) { // // Do not write if data array is isEmpty // const long numRows = dimensions[0]; if (numRows <= 0) { return; } // // 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] // const int dimensionality = static_cast(dimensions.size()); for (int i = (dimensionality - 1); i >= 1; i--) { if (dimensions[i] <= 1) { dimensions.resize(i); } } // // Check name of data type and encoding // if (intentName.isEmpty()) { throw FileException("", "Invalid (isEmpty) XML Intent."); } if (intentName == "NIFTI_INTENT_UNKNOWN") { intentName = "NIFTI_INTENT_NONE"; } const QString dataTypeName(getDataTypeName(dataType)); if (dataTypeName.isEmpty()) { throw FileException("", "Invalid (isEmpty) XML DataArray type."); } const QString encodingName(getEncodingName(encoding)); if (encodingName.isEmpty()) { throw FileException("", "Invalid (isEmpty) XML encoding type."); } const QString arraySubscriptingName(getArraySubscriptingOrderName(arraySubscriptingOrder)); if (arraySubscriptingName.isEmpty()) { throw FileException("", "Invalid (isEmpty) XML array subscripting order type."); } // // Update metadata // updateMetaDataBeforeWriting(); // // Indentation to improve file readability // int indent = indentOffset; // // External file not supported // //const QString externalFileName = ""; //const QString externalFileOffset = "0"; // // Write the opening tag // GiftiCommon::writeIndentationXML(stream, indent); stream << "<" << GiftiCommon::tagDataArray << " " << GiftiCommon::attIntent << "=\"" << intentName << "\"" << "\n"; GiftiCommon::writeIndentationXML(stream, indent); stream << " " << GiftiCommon::attDataType << "=\"" << dataTypeName << "\"" << "\n"; GiftiCommon::writeIndentationXML(stream, indent); //stream << " " << GiftiCommon::attDataLocation << "=\"" // << GiftiCommon::dataLocationInternal << "\"" << "\n"; //GiftiCommon::writeIndentationXML(stream, indent); stream << " " << GiftiCommon::attArraySubscriptingOrder << "=\"" << arraySubscriptingName << "\"" << "\n"; GiftiCommon::writeIndentationXML(stream, indent); stream << " " << GiftiCommon::attDimensionality << "=\"" << dimensions.size() << "\"" << "\n"; for (unsigned int i = 0; i < dimensions.size(); i++) { GiftiCommon::writeIndentationXML(stream, indent); stream << " " << GiftiCommon::getAttDim(i) << "=\"" << dimensions[i] << "\"" << "\n"; } GiftiCommon::writeIndentationXML(stream, indent); stream << " " << GiftiCommon::attEncoding << "=\"" << encodingName << "\"" << "\n"; GiftiCommon::writeIndentationXML(stream, indent); stream << " " << GiftiCommon::attEndian << "=\"" << GiftiCommon::getSystemsEndianName() << "\"" << "\n"; GiftiCommon::writeIndentationXML(stream, indent); stream << " " << GiftiCommon::attExternalFileName << "=\"" << externalFileName << "\"" << "\n"; GiftiCommon::writeIndentationXML(stream, indent); stream << " " << GiftiCommon::attExternalFileOffset << "=\"" << externalFileOffset << "\"" << ">" << "\n"; indent++; // // Write the metadata // metaData.writeAsXML(stream, indent); // // Write the matrices // for (int i = 0; i < getNumberOfMatrices(); i++) { matrices[i].writeAsXML(stream, indent); } // // Write the data element opening tag // GiftiCommon::writeIndentationXML(stream, indent); stream << "<" << GiftiCommon::tagData << ">"; indent++; // // Want closing immediately after data for gzip & base64 // bool addCloseTagImmediatelyAfterData = false; // // NOTE: for the base64 and ZLIB-Base64 data, it is important that there are // no spaces between the and tags. // switch (encoding) { case ENCODING_INTERNAL_ASCII: { // // Newline after tag (only do this for ASCII !!!) // stream << "\n"; // // determine the number of items per row (node) // long numItemsPerRow = 1; for (unsigned int i = 1; i < dimensions.size(); i++) { numItemsPerRow *= dimensions[i]; } // // Write the rows // int offset = 0; for (int i = 0; i < numRows; i++) { GiftiCommon::writeIndentationXML(stream, indent); switch (dataType) { case DATA_TYPE_FLOAT32: for (long j = 0; j < numItemsPerRow; j++) { stream << dataPointerFloat[offset + j] << " "; } break; case DATA_TYPE_INT32: for (long j = 0; j < numItemsPerRow; j++) { stream << dataPointerInt[offset + j] << " "; } break; case DATA_TYPE_UINT8: for (long j = 0; j < numItemsPerRow; j++) { stream << dataPointerUByte[offset + j] << " "; } break; } stream << "\n"; offset += numItemsPerRow; } } break; case ENCODING_INTERNAL_BASE64_BINARY: #ifdef HAVE_VTK { // // Encode the data with VTK's Base64 algorithm // const unsigned long bufferLength = static_cast(data.size() * 1.5); char* buffer = new char[bufferLength]; const unsigned long compressedLength = vtkBase64Utilities::Encode(&data[0], data.size(), (unsigned char*)buffer); if (compressedLength >= bufferLength) { throw FileException( "Base64 encoding buffer length (" + QString::number(bufferLength) + ") is too small but needs to be " + compressedLength); } buffer[compressedLength] = '\0'; // // Write the data // stream << buffer; addCloseTagImmediatelyAfterData = true; // // Free memory // delete[] buffer; } #else // HAVE_VTK throw FileException("No support for Base64 data since VTK not available at compile time."); #endif // HAVE_VTK break; case ENCODING_INTERNAL_COMPRESSED_BASE64_BINARY: #ifdef HAVE_VTK { // // Compress the data with VTK's ZLIB algorithm // vtkZLibDataCompressor* compressor = vtkZLibDataCompressor::New(); unsigned long compressedDataBufferLength = compressor->GetMaximumCompressionSpace(data.size()); unsigned char* compressedDataBuffer = new unsigned char[compressedDataBufferLength]; unsigned long compressedDataLength = compressor->Compress(&data[0], data.size(), compressedDataBuffer, compressedDataBufferLength); compressor->Delete(); // // Encode the data with VTK's Base64 algorithm // char* buffer = new char[static_cast(compressedDataLength * 1.5)]; const unsigned long compressedLength = vtkBase64Utilities::Encode(compressedDataBuffer, compressedDataLength, (unsigned char*)buffer); buffer[compressedLength] = '\0'; if (DebugControl::getDebugOn()) { if (compressedLength > 4) { std::cout << "Bytes: " << (int)buffer[0] << " " << (int)buffer[1] << " " << (int)buffer[2] << " " << (int)buffer[3] << std::endl; } } // // Write the data // stream << buffer; addCloseTagImmediatelyAfterData = true; // // Free memory // delete[] buffer; delete[] compressedDataBuffer; } #else // HAVE_VTK throw FileException("No support for Base64 data since VTK not available at compile time."); #endif // HAVE_VTK break; case ENCODING_EXTERNAL_FILE_BINARY: { const long dataLength = data.size(); externalBinaryOutputStream->write((const char*)&data[0], dataLength); if (externalBinaryOutputStream->bad()) { throw FileException("Output stream for external file reports its status as bad."); } } break; } // // Write the closing tag // indent--; if (addCloseTagImmediatelyAfterData == false) { GiftiCommon::writeIndentationXML(stream, indent); } stream << "" << "\n"; // // write the closing data array tag // indent--; GiftiCommon::writeIndentationXML(stream, indent); stream << "" << "\n"; } /** * convert to data type. */ void GiftiDataArray::convertToDataType(const DATA_TYPE newDataType) { if (newDataType != dataType) { if (DebugControl::getDebugOn()) { std::cout << "Converting GIFTI DataArray \"" << intentName.toAscii().constData() << "\"" << " from type " << getDataTypeName(dataType).toAscii().constData() << " to type " << getDataTypeName(newDataType).toAscii().constData() << "\n"; } // // make a copy of myself // GiftiDataArray copyOfMe(*this); // // Set my new data type and reallocate memory // const DATA_TYPE oldDataType = dataType; dataType = newDataType; allocateData(); if (data.empty() == false) { // // Get total number of elements // long numElements = 1; for (unsigned int i = 0; i < dimensions.size(); i++) { numElements *= dimensions[i]; } // // copy the data // for (long i = 0; i < numElements; i++) { switch (dataType) { case DATA_TYPE_FLOAT32: switch (oldDataType) { case DATA_TYPE_FLOAT32: dataPointerFloat[i] = static_cast(copyOfMe.dataPointerFloat[i]); break; case DATA_TYPE_INT32: dataPointerFloat[i] = static_cast(copyOfMe.dataPointerInt[i]); break; case DATA_TYPE_UINT8: dataPointerFloat[i] = static_cast(copyOfMe.dataPointerUByte[i]); break; } break; case DATA_TYPE_INT32: switch (oldDataType) { case DATA_TYPE_FLOAT32: dataPointerInt[i] = static_cast(copyOfMe.dataPointerFloat[i]); break; case DATA_TYPE_INT32: dataPointerInt[i] = static_cast(copyOfMe.dataPointerInt[i]); break; case DATA_TYPE_UINT8: dataPointerInt[i] = static_cast(copyOfMe.dataPointerUByte[i]); break; } break; case DATA_TYPE_UINT8: switch (oldDataType) { case DATA_TYPE_FLOAT32: dataPointerUByte[i] = static_cast(copyOfMe.dataPointerFloat[i]); break; case DATA_TYPE_INT32: dataPointerUByte[i] = static_cast(copyOfMe.dataPointerInt[i]); break; case DATA_TYPE_UINT8: dataPointerUByte[i] = static_cast(copyOfMe.dataPointerUByte[i]); break; } break; } } } } setModified(); } /** * byte swap the data (data read is different endian than this system). */ void GiftiDataArray::byteSwapData(const ENDIAN newEndian) { #ifdef HAVE_VTK endian = newEndian; switch (dataType) { case DATA_TYPE_FLOAT32: if (DebugControl::getDebugOn()) { std::cout << "Byte swapping float data for GiftiDataArray." << std::endl; } vtkByteSwap::SwapVoidRange(dataPointerFloat, getTotalNumberOfElements(), sizeof(float)); break; case DATA_TYPE_INT32: if (DebugControl::getDebugOn()) { std::cout << "Byte swapping int data for GiftiDataArray." << std::endl; } vtkByteSwap::SwapVoidRange(dataPointerInt, getTotalNumberOfElements(), sizeof(int32_t)); break; case DATA_TYPE_UINT8: // should not need to swap ?? break; } #endif // HAVE_VTK } // set the data array modified (actually set's the modified flag for file containing this) void GiftiDataArray::setModified() { if (parentGiftiDataArrayFile != NULL) { parentGiftiDataArrayFile->setModified(); } } /** * 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(); long numItems = getTotalNumberOfElements(); for (long i = 0; i < numItems; i++) { minValueInt = std::min(minValueInt, dataPointerInt[i]); maxValueInt = std::max(maxValueInt, dataPointerInt[i]); } minMaxIntValuesValid = true; } minValue = minValueInt; maxValue = maxValueInt; } /** * get minimum and maximum values (valid for float data only). */ void GiftiDataArray::getMinMaxValues(float& minValue, float& maxValue) const { if (minMaxFloatValuesValid == false) { minValueFloat = std::numeric_limits::max(); maxValueFloat = -std::numeric_limits::max(); long numItems = getTotalNumberOfElements(); for (long i = 0; i < numItems; i++) { minValueFloat = std::min(minValueFloat, dataPointerFloat[i]); maxValueFloat = std::max(maxValueFloat, dataPointerFloat[i]); } minMaxFloatValuesValid = true; } minValue = minValueFloat; maxValue = maxValueFloat; } /** * Get data column min/max for the specified percentages. */ void GiftiDataArray::getMinMaxValuesFromPercentages(const float negMaxPctIn, const float negMinPctIn, const float posMinPctIn, const float posMaxPctIn, float& negMaxPctValueOut, float& negMinPctValueOut, float& posMinPctValueOut, float& posMaxPctValueOut) { if ((negMaxPctIn != negMaxPct) || (negMinPctIn != negMinPct) || (posMinPctIn != posMinPct) || (posMaxPctIn != posMaxPct)) { minMaxPercentageValuesValid = false; } if (minMaxPercentageValuesValid == false) { negMaxPct = negMaxPctIn; negMinPct = negMinPctIn; posMinPct = posMinPctIn; posMaxPct = posMaxPctIn; negMaxPctValue = 0.0; negMinPctValue = 0.0; posMinPctValue = 0.0; posMaxPctValue = 0.0; const long num = getTotalNumberOfElements(); if (num > 0) { std::vector negatives, positives; negatives.reserve(num); positives.reserve(num); for (long i = 0; i < num; i++) { if (dataPointerFloat[i] > 0.0) { positives.push_back(dataPointerFloat[i]); } else if (dataPointerFloat[i] < 0.0) { negatives.push_back(dataPointerFloat[i]); } } int numPos = static_cast(positives.size()); if (numPos > 0) { std::sort(positives.begin(), positives.end()); if (numPos == 1) { posMinPctValue = positives[0]; posMaxPctValue = positives[0]; } else { int minIndex = numPos * (posMinPct / 100.0); if (minIndex < 0) minIndex = 0; if (minIndex >= numPos) minIndex = numPos - 1; posMinPctValue = positives[minIndex]; int maxIndex = numPos * (posMaxPct / 100.0); if (maxIndex < 0) maxIndex = 0; if (maxIndex >= numPos) maxIndex = numPos - 1; posMaxPctValue = positives[maxIndex]; } } int numNeg = static_cast(negatives.size()); if (numNeg > 0) { std::sort(negatives.begin(), negatives.end()); if (numNeg == 1) { negMinPctValue = negatives[0]; negMaxPctValue = negatives[0]; } else { int maxIndex = numNeg * ((100.0 - negMaxPct) / 100.0); if (maxIndex < 0) maxIndex = 0; if (maxIndex >= numNeg) maxIndex = numNeg - 1; negMaxPctValue = negatives[maxIndex]; int minIndex = numNeg * ((100.0 - negMinPct) / 100.0); if (minIndex < 0) minIndex = 0; if (minIndex >= numNeg) minIndex = numNeg - 1; negMinPctValue = negatives[minIndex]; } } } minMaxPercentageValuesValid = true; } negMaxPctValueOut = negMaxPctValue; negMinPctValueOut = negMinPctValue; posMaxPctValueOut = posMaxPctValue; posMinPctValueOut = posMinPctValue; } /** * 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). */ long GiftiDataArray::getDataOffset(const int indices[]) const { const int numDim = static_cast(dimensions.size()); long offset = 0; long dimProduct = 1; switch (arraySubscriptingOrder) { case ARRAY_SUBSCRIPTING_ORDER_HIGHEST_FIRST: for (int d = (numDim - 1); d >= 0; d--) { offset += indices[d] * dimProduct; dimProduct *= dimensions[d]; } break; case ARRAY_SUBSCRIPTING_ORDER_LOWEST_FIRST: // correct??? for (int 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 int indices[]) const { const long 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 int indices[]) const { const long 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 int indices[]) const { const long 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 int indices[]) const { const long 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 int indices[]) const { const long 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 int indices[]) const { const long 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 int indices[], const float dataValue) const { const long 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 int indices[], const int32_t dataValue) const { const long 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 int indices[], const uint8_t dataValue) const { const long offset = getDataOffset(indices); dataPointerUByte[offset] = dataValue; } /** * valid intent name. */ bool GiftiDataArray::intentNameValid(const QString& intentNameIn) { if (intentNameIn.startsWith(GiftiCommon::intentPrefix)) { return true; } /* if ((intentNameIn == GiftiCommon::intentCoordinates) || (intentNameIn == GiftiCommon::intentFunctional) || (intentNameIn == GiftiCommon::intentNormals) || (intentNameIn == GiftiCommon::intentLabels) || (intentNameIn == GiftiCommon::intentRGBA) || (intentNameIn == GiftiCommon::intentShape) || (intentNameIn == GiftiCommon::intentTensors) || (intentNameIn == GiftiCommon::intentTopologyTriangles)) { return true; } */ return false; } /** * update the array's metadata after reading the array. */ void GiftiDataArray::updateMetaDataAfterReading() { if (intentName == GiftiCommon::intentCoordinates) { // // Convert GIFTI geometry type to caret surface type // QString giftiGeomType; if (metaData.get(GiftiCommon::metaDataNameGeometricType, giftiGeomType)) { QString caretGeomType; if (giftiGeomType == GiftiCommon::metaDataValueGeometricTypeReconstruction) { caretGeomType = "Raw"; } else if (giftiGeomType == GiftiCommon::metaDataValueGeometricTypeAnatomical) { caretGeomType = "Fiducial"; } else if (giftiGeomType == GiftiCommon::metaDataValueGeometricTypeInflated) { caretGeomType = "Inflated"; } else if (giftiGeomType == GiftiCommon::metaDataValueGeometricTypeVeryInflated) { caretGeomType = "Very_Inflated"; } else if (giftiGeomType == GiftiCommon::metaDataValueGeometricTypeSpherical) { caretGeomType = "Spherical"; } else if (giftiGeomType == GiftiCommon::metaDataValueGeometricTypeSemiSpherical) { caretGeomType = "CompMedWall"; } else if (giftiGeomType == GiftiCommon::metaDataValueGeometricTypeEllipsoid) { caretGeomType = "Ellipsoidal"; } else if (giftiGeomType == GiftiCommon::metaDataValueGeometricTypeFlat) { caretGeomType = "Flat"; } else if (giftiGeomType == GiftiCommon::metaDataValueGeometricTypeFlatLobar) { caretGeomType = "FlatLobar"; } else if (giftiGeomType == GiftiCommon::metaDataValueGeometricTypeHull) { caretGeomType = "Hull"; } if (caretGeomType.isEmpty() == false) { metaData.set(AbstractFile::headerTagConfigurationID, caretGeomType); metaData.remove(GiftiCommon::metaDataNameGeometricType); } } // // Convert GIFTI anatomical structure to Caret structure // QString giftiAnatomicalStructurePrimary; if (metaData.get(GiftiCommon::metaDataNameAnatomicalStructurePrimary, giftiAnatomicalStructurePrimary)) { QString caretStructure; if (giftiAnatomicalStructurePrimary == GiftiCommon::metaDataValueAnatomicalStructurePrimaryCortexLeft) { caretStructure = "left"; } else if (giftiAnatomicalStructurePrimary == GiftiCommon::metaDataValueAnatomicalStructurePrimaryCortexRight) { caretStructure = "right"; } else if (giftiAnatomicalStructurePrimary == GiftiCommon::metaDataValueAnatomicalStructurePrimaryCortexRightAndLeft) { caretStructure = "both"; } else if (giftiAnatomicalStructurePrimary == GiftiCommon::metaDataValueAnatomicalStructurePrimaryCerebellum) { caretStructure = "cerebellum"; } else if (giftiAnatomicalStructurePrimary == GiftiCommon::metaDataValueAnatomicalStructurePrimaryHead) { caretStructure = "head"; } if (caretStructure.isEmpty() == false) { metaData.set(AbstractFile::headerTagStructure, caretStructure); metaData.remove(GiftiCommon::metaDataNameAnatomicalStructurePrimary); } } } else if (intentName == GiftiCommon::intentTopologyTriangles) { // // Convert GIFTI topology type to Caret Topology Type // QString giftiTopoType; if (metaData.get(GiftiCommon::metaDataNameTopologicalType, giftiTopoType)) { QString caretTopoType; if (giftiTopoType == GiftiCommon::metaDataValueTopologicalTypeClosed) { caretTopoType = "CLOSED"; } else if (giftiTopoType == GiftiCommon::metaDataValueTopologicalTypeOpen) { caretTopoType = "OPEN"; } else if (giftiTopoType == GiftiCommon::metaDataValueTopologicalTypeCut) { caretTopoType = "CUT"; } else if (giftiTopoType == GiftiCommon::metaDataValueTopologicalTypeCutLobar) { caretTopoType = "LOBAR_CUT"; } if (caretTopoType.isEmpty() == false) { metaData.set(AbstractFile::headerTagPerimeterID, caretTopoType); metaData.remove(GiftiCommon::metaDataNameTopologicalType); } } } //QString commentText; //if (metaData.get("Description", commentText)) { // metaData.remove("Description"); // metaData.set("comment", commentText); //} } /** * update the array's metadata before writing the array. */ void GiftiDataArray::updateMetaDataBeforeWriting() { if (intentName == GiftiCommon::intentCoordinates) { // // Convert Caret surface type to GIFTI geometry type // QString caretGeomType; if (metaData.get(AbstractFile::headerTagConfigurationID, caretGeomType)) { QString giftiGeomType; if (caretGeomType == "Raw") { giftiGeomType = GiftiCommon::metaDataValueGeometricTypeReconstruction; } else if (caretGeomType == "Fiducial") { giftiGeomType = GiftiCommon::metaDataValueGeometricTypeAnatomical; } else if (caretGeomType == "Inflated") { giftiGeomType = GiftiCommon::metaDataValueGeometricTypeInflated; } else if ((caretGeomType == "Very_Inflated") || (caretGeomType == "VeryInflated")) { giftiGeomType = GiftiCommon::metaDataValueGeometricTypeVeryInflated; } else if (caretGeomType == "Spherical") { giftiGeomType = GiftiCommon::metaDataValueGeometricTypeSpherical; } else if (caretGeomType == "Ellipsoidal") { giftiGeomType = GiftiCommon::metaDataValueGeometricTypeEllipsoid; } else if (caretGeomType == "CompMedWall") { giftiGeomType = GiftiCommon::metaDataValueGeometricTypeSemiSpherical; } else if (caretGeomType == "Flat") { giftiGeomType = GiftiCommon::metaDataValueGeometricTypeFlat; } else if (caretGeomType == "FlatLobar") { giftiGeomType = GiftiCommon::metaDataValueGeometricTypeFlatLobar; } else if (caretGeomType == "Hull") { giftiGeomType = GiftiCommon::metaDataValueGeometricTypeHull; } if (giftiGeomType.isEmpty() == false) { metaData.set(GiftiCommon::metaDataNameGeometricType, giftiGeomType); metaData.remove(AbstractFile::headerTagConfigurationID); } } // // Convert Caret structure to GIFTI structure // QString caretStructureName; if (metaData.get(AbstractFile::headerTagStructure, caretStructureName)) { caretStructureName = caretStructureName.toLower(); QString giftiPrimaryStructureName; if (caretStructureName == "left") { giftiPrimaryStructureName = GiftiCommon::metaDataValueAnatomicalStructurePrimaryCortexLeft; } else if (caretStructureName == "right") { giftiPrimaryStructureName = GiftiCommon::metaDataValueAnatomicalStructurePrimaryCortexRight; } else if (caretStructureName == "both") { giftiPrimaryStructureName = GiftiCommon::metaDataValueAnatomicalStructurePrimaryCortexRightAndLeft; } else if (caretStructureName == "cerebellum") { giftiPrimaryStructureName = GiftiCommon::metaDataValueAnatomicalStructurePrimaryCerebellum; } else if (caretStructureName == "head") { giftiPrimaryStructureName = GiftiCommon::metaDataValueAnatomicalStructurePrimaryHead; } if (giftiPrimaryStructureName.isEmpty() == false) { metaData.set(GiftiCommon::metaDataNameAnatomicalStructurePrimary, giftiPrimaryStructureName); metaData.remove(AbstractFile::headerTagStructure); // // If no secondary structure assume midlayer since // caret does layer 4 // QString giftiSecondaryStructure; if (metaData.get(GiftiCommon::metaDataNameAnatomicalStructureSecondary, giftiSecondaryStructure) == false) { metaData.set(GiftiCommon::metaDataNameAnatomicalStructureSecondary, GiftiCommon::metaDataValueAnatomicalStructureSecondaryMidLayer); } } } metaData.remove("coordframe_id"); } else if (intentName == GiftiCommon::intentTopologyTriangles) { // // Convert Caret Topology Type to GIFTI Topology Type // QString caretTopoType; if (metaData.get(AbstractFile::headerTagPerimeterID, caretTopoType)) { QString giftiTopoType; if (caretTopoType == "CLOSED") { giftiTopoType = GiftiCommon::metaDataValueTopologicalTypeClosed; } else if (caretTopoType == "OPEN") { giftiTopoType = GiftiCommon::metaDataValueTopologicalTypeOpen; } else if (caretTopoType == "CUT") { giftiTopoType = GiftiCommon::metaDataValueTopologicalTypeCut; } else if (caretTopoType == "LOBAR_CUT") { giftiTopoType = GiftiCommon::metaDataValueTopologicalTypeCutLobar; } if (giftiTopoType.isEmpty() == false) { metaData.set(GiftiCommon::metaDataNameTopologicalType, giftiTopoType); metaData.remove(AbstractFile::headerTagPerimeterID); } } metaData.remove("perimeter_id"); } QString uuidValue; if (metaData.get(GiftiCommon::metaDataNameUniqueID, uuidValue) == false) { metaData.set(GiftiCommon::metaDataNameUniqueID, QUuid::createUuid().toString()); } //QString commentText; //if (metaData.get("comment", commentText)) { // metaData.remove("comment"); // metaData.set("Description", commentText); //} // // Remove these obsolete or unneeded caret header items // metaData.remove(AbstractFile::headerTagEncoding); metaData.remove(AbstractFile::headerTagResolution); metaData.remove(AbstractFile::headerTagSampling); metaData.remove(AbstractFile::headerTagScale); } /** * remove all matrices. */ void GiftiDataArray::removeAllMatrices() { matrices.clear(); setModified(); } /** * remove a matrix. */ void GiftiDataArray::removeMatrix(const int indx) { matrices.erase(matrices.begin() + indx); setModified(); } caret-5.6.4~dfsg.1.orig/caret_files/GiftiCommon.h0000664000175000017500000004243611572067322021436 0ustar michaelmichael#ifndef __GIFTI_COMMON_H__ #define __GIFTI_COMMON_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include class QTextStream; /// class for things common to various GIFTI containers class GiftiCommon { public: // get name for this system's endian static QString getSystemsEndianName(); // used to write indentation space static void writeIndentationXML(QTextStream& stream, const int indentOffset); /// get attribute for a specific dimensions static QString getAttDim(const int dimNum); /// get all space labels static void getAllSpaceLabels(QStringList& labels); /// tag for reading/writing GIFTI files static const QString tagGIFTI; /// tag for reading/writing GIFTI files static const QString tagMetaData; /// tag for reading/writing GIFTI files static const QString tagMD; /// tag for reading/writing GIFTI files static const QString tagName; /// tag for reading/writing GIFTI files static const QString tagValue; /// tag for reading/writing GIFTI files static const QString tagDataArray; /// tag for reading/writing GIFTI files static const QString tagData; /// tag for reading/writing GIFTI files static const QString tagLabelTable; /// tag for reading/writing GIFTI files static const QString tagLabel; /// tag for reading/writing GIFTI files static const QString tagMatrix; /// tag for reading/writing GIFTI files static const QString tagMatrixDataSpace; /// tag for reading/writing GIFTI files static const QString tagMatrixTransformedSpace; /// tag for reading/writing GIFTI files static const QString tagMatrixData; /// tag for reading/writing GIFTI files //static const QString tagExternalFileName; /// tag for reading/writing GIFTI files //static const QString tagExternalFileOffset; /// attribute for reading/writing GIFTI files static const QString attVersion; /// attribute for reading/writing GIFTI files static const QString attNumberOfDataArrays; /// attribute for reading/writing GIFTI files static const QString attArraySubscriptingOrder; /// attribute for reading/writing GIFTI files static const QString attKey; /// attribute for reading/writing GIFTI files static const QString attRed; /// attribute for reading/writing GIFTI files static const QString attGreen; /// attribute for reading/writing GIFTI files static const QString attBlue; /// attribute for reading/writing GIFTI files static const QString attAlpha; /// attribute for reading/writing GIFTI files //static const QString attDataLocation; /// attribute for reading/writing GIFTI files static const QString attIntent; /// attribute for reading/writing GIFTI files static const QString attDataType; /// attribute for reading/writing GIFTI files static const QString attDimensionality; /// attribute for reading/writing GIFTI files static const QString attDim; /// attribute for reading/writing GIFTI files static const QString attEncoding; /// attribute for reading/writing GIFTI files static const QString attEndian; /// attribute for reading/writing GIFTI files static const QString attExternalFileName; /// attribute for reading/writing GIFTI files static const QString attExternalFileOffset; /// data type name static const QString typeNameFloat32; /// data type name static const QString typeNameInt32; /// data type name static const QString typeNameUInt8; /// encoding type name static const QString encodingNameInternalAscii; /// encoding type name static const QString encodingNameInternalBase64Binary; /// encoding type name static const QString encodingNameInternalBase64BinaryGZip; /// encoding type name static const QString encodingNameExternalBinary; /// encoding type name static const QString endianBig; /// encoding type name static const QString endianLittle; /// data location internal name //static const QString dataLocationInternal; /// data location external name //static const QString dataLocationExternal; /// array subscripting highest order first static const QString arraySubscriptingOrderHighestFirst; /// array subscripting lowest order first static const QString arraySubscriptingOrderLowestFirst; /// label for unknown space static const QString spaceLabelUnknown; /// label for scanner space static const QString spaceLabelScannerCoords; /// label for aligned to anatomical space static const QString spaceLabelAlignedAnatomical; /// label for talairach space static const QString spaceLabelTalairach; /// label for MNI 152 space static const QString spaceLabelMNI152; /// nifti intent unknown static const QString intentUnknown; /// nifti intent prefix static const QString intentPrefix; /// intent for coordinates static const QString intentCoordinates; /// intent for time series static const QString intentTimeSeries; /// intent for node index static const QString intentNodeIndex; /// intent for normals static const QString intentNormals; /// intent for labels static const QString intentLabels; /// intent for rgba static const QString intentRGBA; /// intent for rgb static const QString intentRGB; /// intent for shape static const QString intentShape; /// intent for tensors static const QString intentTensors; /// intent for triangles static const QString intentTopologyTriangles; /// intent for vectors static const QString intentVectors; /// metadata unique id name static const QString metaDataNameUniqueID; /// topological type metadata name static const QString metaDataNameTopologicalType; /// topological type closed value static const QString metaDataValueTopologicalTypeClosed; /// topological type open value static const QString metaDataValueTopologicalTypeOpen; /// topological type cut value static const QString metaDataValueTopologicalTypeCut; /// topological type cut lobar value static const QString metaDataValueTopologicalTypeCutLobar; /// geometric type metadata name static const QString metaDataNameGeometricType; /// geometric type reconstruction value static const QString metaDataValueGeometricTypeReconstruction; /// geometric type anatomical value static const QString metaDataValueGeometricTypeAnatomical; /// geometric type inflated value static const QString metaDataValueGeometricTypeInflated; /// geometric type very inflated value static const QString metaDataValueGeometricTypeVeryInflated; /// geometric type spherical value static const QString metaDataValueGeometricTypeSpherical; /// geometric type spherical value static const QString metaDataValueGeometricTypeSemiSpherical; /// geometric type ellipsoid value static const QString metaDataValueGeometricTypeEllipsoid; /// geometric type flat value static const QString metaDataValueGeometricTypeFlat; /// geometric type flat lobar value static const QString metaDataValueGeometricTypeFlatLobar; /// geometric type hull value static const QString metaDataValueGeometricTypeHull; /// anatomical structure primary metadata name static const QString metaDataNameAnatomicalStructurePrimary; /// anatomical structure primary cortex left value static const QString metaDataValueAnatomicalStructurePrimaryCortexLeft; /// anatomical structure primary cortex right value static const QString metaDataValueAnatomicalStructurePrimaryCortexRight; /// anatomical structure primary cortex right and left value static const QString metaDataValueAnatomicalStructurePrimaryCortexRightAndLeft; /// anatomical structure primary cerebellum value static const QString metaDataValueAnatomicalStructurePrimaryCerebellum; /// anatomical structure primary head value static const QString metaDataValueAnatomicalStructurePrimaryHead; /// anatomical structure secondary metadata name static const QString metaDataNameAnatomicalStructureSecondary; /// anatomical structure secondary white/gray boundary value static const QString metaDataValueAnatomicalStructureSecondaryWhiteGray; /// anatomical structure secondary gray/CSF boundary value static const QString metaDataValueAnatomicalStructureSecondarGrayCSF; /// anatomical structure secondary MidLayer value static const QString metaDataValueAnatomicalStructureSecondaryMidLayer; }; #endif // __GIFTI_COMMON_H__ #ifdef __GIFTI_COMMON_MAIN__ const QString GiftiCommon::tagGIFTI = "GIFTI"; const QString GiftiCommon::tagMetaData = "MetaData"; const QString GiftiCommon::tagMD = "MD"; const QString GiftiCommon::tagName = "Name"; const QString GiftiCommon::tagValue = "Value"; const QString GiftiCommon::tagDataArray = "DataArray"; const QString GiftiCommon::tagData = "Data"; const QString GiftiCommon::tagLabelTable = "LabelTable"; const QString GiftiCommon::tagLabel = "Label"; const QString GiftiCommon::tagMatrix = "CoordinateSystemTransformMatrix"; const QString GiftiCommon::tagMatrixDataSpace = "DataSpace"; const QString GiftiCommon::tagMatrixTransformedSpace = "TransformedSpace"; const QString GiftiCommon::tagMatrixData = "MatrixData"; //const QString GiftiCommon::tagExternalFileName = "ExternalFileName"; //const QString GiftiCommon::tagExternalFileOffset = "ExternalFileOffset"; const QString GiftiCommon::attVersion = "Version"; const QString GiftiCommon::attNumberOfDataArrays = "NumberOfDataArrays"; const QString GiftiCommon::attArraySubscriptingOrder = "ArrayIndexingOrder"; const QString GiftiCommon::attKey = "Key"; const QString GiftiCommon::attRed = "Red"; const QString GiftiCommon::attGreen = "Green"; const QString GiftiCommon::attBlue = "Blue"; const QString GiftiCommon::attAlpha = "Alpha"; const QString GiftiCommon::attIntent = "Intent"; //const QString GiftiCommon::attIntent = "Category"; //const QString GiftiCommon::attDataLocation = "DataLocation"; const QString GiftiCommon::attDataType = "DataType"; const QString GiftiCommon::attDimensionality = "Dimensionality"; const QString GiftiCommon::attDim = "Dim"; const QString GiftiCommon::attEncoding = "Encoding"; const QString GiftiCommon::attEndian = "Endian"; const QString GiftiCommon::attExternalFileName = "ExternalFileName"; const QString GiftiCommon::attExternalFileOffset = "ExternalFileOffset"; const QString GiftiCommon::typeNameFloat32 = "NIFTI_TYPE_FLOAT32"; const QString GiftiCommon::typeNameInt32 = "NIFTI_TYPE_INT32"; const QString GiftiCommon::typeNameUInt8 = "NIFTI_TYPE_UINT8"; const QString GiftiCommon::encodingNameInternalAscii = "ASCII"; const QString GiftiCommon::encodingNameInternalBase64Binary = "Base64Binary"; const QString GiftiCommon::encodingNameInternalBase64BinaryGZip = "GZipBase64Binary"; const QString GiftiCommon::encodingNameExternalBinary = "ExternalFileBinary"; const QString GiftiCommon::endianBig = "BigEndian"; const QString GiftiCommon::endianLittle = "LittleEndian"; const QString GiftiCommon::arraySubscriptingOrderHighestFirst = "RowMajorOrder"; const QString GiftiCommon::arraySubscriptingOrderLowestFirst = "ColumnMajorOrder"; //const QString GiftiCommon::dataLocationInternal = "Internal"; //const QString GiftiCommon::dataLocationExternal = "External"; const QString GiftiCommon::spaceLabelUnknown = "NIFTI_XFORM_UNKNOWN"; const QString GiftiCommon::spaceLabelScannerCoords = "NIFTI_XFORM_SCANNER_ANAT"; const QString GiftiCommon::spaceLabelAlignedAnatomical = "NIFTI_XFORM_ALIGNED_ANAT"; const QString GiftiCommon::spaceLabelTalairach = "NIFTI_XFORM_TALAIRACH"; const QString GiftiCommon::spaceLabelMNI152 = "NIFTI_XFORM_MNI_152"; const QString GiftiCommon::intentUnknown = "NIFTI_INTENT_UNKNOWN"; const QString GiftiCommon::intentPrefix = "NIFTI_INTENT"; const QString GiftiCommon::intentCoordinates = "NIFTI_INTENT_POINTSET"; const QString GiftiCommon::intentTimeSeries = "NIFTI_INTENT_TIME_SERIES"; const QString GiftiCommon::intentNodeIndex = "NIFTI_INTENT_NODE_INDEX"; const QString GiftiCommon::intentNormals = "NIFTI_INTENT_VECTOR"; const QString GiftiCommon::intentLabels = "NIFTI_INTENT_LABEL"; const QString GiftiCommon::intentRGB = "NIFTI_INTENT_RGB_VECTOR"; const QString GiftiCommon::intentRGBA = "NIFTI_INTENT_RGBA_VECTOR"; const QString GiftiCommon::intentShape = "NIFTI_INTENT_SHAPE"; const QString GiftiCommon::intentTensors = "NIFTI_INTENT_GENMATRIX"; const QString GiftiCommon::intentTopologyTriangles = "NIFTI_INTENT_TRIANGLE"; const QString GiftiCommon::intentVectors = "NIFTI_INTENT_VECTOR"; const QString GiftiCommon::metaDataNameUniqueID = "UniqueID"; const QString GiftiCommon::metaDataNameTopologicalType = "TopologicalType"; const QString GiftiCommon::metaDataValueTopologicalTypeClosed = "Closed"; const QString GiftiCommon::metaDataValueTopologicalTypeOpen = "Open"; const QString GiftiCommon::metaDataValueTopologicalTypeCut = "Cut"; const QString GiftiCommon::metaDataValueTopologicalTypeCutLobar = "CutLobar"; const QString GiftiCommon::metaDataNameGeometricType = "GeometricType"; const QString GiftiCommon::metaDataValueGeometricTypeReconstruction = "Reconstruction"; const QString GiftiCommon::metaDataValueGeometricTypeAnatomical = "Anatomical"; const QString GiftiCommon::metaDataValueGeometricTypeInflated = "Inflated"; const QString GiftiCommon::metaDataValueGeometricTypeVeryInflated = "VeryInflated"; const QString GiftiCommon::metaDataValueGeometricTypeSpherical = "Spherical"; const QString GiftiCommon::metaDataValueGeometricTypeSemiSpherical = "SemiSpherical"; const QString GiftiCommon::metaDataValueGeometricTypeEllipsoid = "Ellipsoid"; const QString GiftiCommon::metaDataValueGeometricTypeFlat = "Flat"; const QString GiftiCommon::metaDataValueGeometricTypeFlatLobar = "FlatLobar"; const QString GiftiCommon::metaDataValueGeometricTypeHull = "Hull"; const QString GiftiCommon::metaDataNameAnatomicalStructurePrimary = "AnatomicalStructurePrimary"; const QString GiftiCommon::metaDataValueAnatomicalStructurePrimaryCortexLeft = "CortexLeft"; const QString GiftiCommon::metaDataValueAnatomicalStructurePrimaryCortexRight = "CortexRight"; const QString GiftiCommon::metaDataValueAnatomicalStructurePrimaryCortexRightAndLeft = "CortexRightAndLeft"; const QString GiftiCommon::metaDataValueAnatomicalStructurePrimaryCerebellum = "Cerebellum"; const QString GiftiCommon::metaDataValueAnatomicalStructurePrimaryHead = "Head"; const QString GiftiCommon::metaDataNameAnatomicalStructureSecondary = "AnatomicalStructureSecondary"; const QString GiftiCommon::metaDataValueAnatomicalStructureSecondaryWhiteGray = "WhiteGray"; const QString GiftiCommon::metaDataValueAnatomicalStructureSecondarGrayCSF = "GrayCSF"; const QString GiftiCommon::metaDataValueAnatomicalStructureSecondaryMidLayer = "MidLayer"; #endif // __GIFTI_COMMON_MAIN__ caret-5.6.4~dfsg.1.orig/caret_files/GiftiCommon.cxx0000664000175000017500000000403611572067322022003 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #define __GIFTI_COMMON_MAIN__ #include "GiftiCommon.h" #undef __GIFTI_COMMON_MAIN__ /** * get name for this system's endian. */ QString GiftiCommon::getSystemsEndianName() { //int wordSize; //bool bigEndian; //qSysInfo(&wordSize, &bigEndian); if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { return GiftiCommon::endianBig; } return GiftiCommon::endianLittle; } /** * used to write indentation space. */ void GiftiCommon::writeIndentationXML(QTextStream& stream, const int indentOffset) { const int offsetTotal = indentOffset * 3; for (int i = 0; i < offsetTotal; i++) { stream << " "; } } /** * get attribute for a specific dimensions. */ QString GiftiCommon::getAttDim(const int dimNum) { QString d(attDim); d += QString::number(dimNum); return d; } /** * get all space labels. */ void GiftiCommon::getAllSpaceLabels(QStringList& labels) { labels.clear(); labels << spaceLabelUnknown; labels << spaceLabelScannerCoords; labels << spaceLabelAlignedAnatomical; labels << spaceLabelTalairach; labels << spaceLabelMNI152; } caret-5.6.4~dfsg.1.orig/caret_files/GeodesicHelper.h0000664000175000017500000001716411572067322022105 0ustar michaelmichael #ifndef __GEODESIC_HELPER_H__ #define __GEODESIC_HELPER_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include //for inlining #include class CoordinateFile; class TopologyFile; //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 //For only a few calls, the constructor may take longer than simply using a well restricted BranModelSurfaceGeodesic //This is because it copies neighbors and precomputes all 1 hop and 2 hop shared edge distances in the constructor class GeodesicHelper { class myheap {//yes, I know its in the stl algorithms, sue me struct data { int node; float dist; }; std::vector store; public: inline bool isEmpty() { return store.empty(); }; inline int pop() { int ret = store[0].node; int prev = 0, next = 1, next1 = 2, size = store.size(); int last = size - 1; if (next1 < size && store[next].dist > store[next1].dist) next = next1; while (next < size && store[last].dist > store[next].dist) { store[prev] = store[next]; prev = next; next = (prev << 1) + 1; next1 = next + 1; if (next1 < size && store[next].dist > store[next1].dist) next = next1; } store[prev] = store[last]; store.pop_back(); return ret; }; inline void push(int node, float dist) { int prev = store.size(); data mydata; mydata.node = node; mydata.dist = dist; store.push_back(mydata);//placeholder int next = (prev - 1) >> 1; while (prev > 0 && store[next].dist > dist) { store[prev] = store[next]; prev = next; next = (prev - 1) >> 1; } store[prev] = mydata; }; inline void clear() { store.clear(); }; }; float* output, **distances, **distances2;//use primitives for speed, and they don't need to change size int** nodeNeighbors, **nodeNeighbors2;//copy neighbors at constructor, because I don't want to mess with inheritance, and I want speed of repeated calls int* numNeighbors, *numNeighbors2, *marked, *changed, *parent; int numNodes; GeodesicHelper() { marked = NULL; };//Don't allow construction without arguments void dijkstra(const int root, const float maxdist, std::vector& nodes, std::vector& dists, bool smooth);//geodesic distance restricted void dijkstra(const int root, bool smooth);//full surface void alltoall(float** out, int** parents, bool smooth);//must be fully allocated void dijkstra(const int root, const std::vector& interested, bool smooth);//partial surface QMutex inUse; public: static void crossProd(const float in1[3], const float in2[3], float out[3]);//DO NOT PASS AN INPUT AS OUT static float dotProd(const float in1[3], const float in2[3]); static float normalize(float in[3]); static void coordDiff(const float* coord1, const float* coord2, float out[3]); GeodesicHelper(const CoordinateFile* coordsIn, const TopologyFile* topoFileIn); ~GeodesicHelper() { if (marked) { delete[] output; delete[] numNeighbors; delete[] numNeighbors2; delete[] marked; delete[] changed; delete[] parent; for (int i = 0; i < numNodes; ++i) { delete[] nodeNeighbors[i]; delete[] nodeNeighbors2[i]; delete[] distances[i]; delete[] distances2[i]; } delete[] nodeNeighbors; delete[] nodeNeighbors2; delete[] distances; delete[] distances2; } }; /// Get distances from root node, up to a geodesic distance cutoff (stops computing when no more nodes are within that distance) void getNodesToGeoDist(const int 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 itself as parent) void getNodesToGeoDist(const int 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 - fastest method for full surface for only one node, but allocate the array first void getGeoFromNode(const int 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 (not as fast) void getGeoFromNode(const int node, std::vector& valuesOut, const bool smoothflag = true);//MUST be already allocated to number of nodes /// Get distances from root node to entire surface and parents - fastest method with parents for full surface, single node, allocate both arrays first (root node has self as parent) void getGeoFromNode(const int node, float* valuesOut, int* parentsOut, const bool smoothflag = true); /// Get distances from root node to entire surface, and their parents, vector method (not as fast, root node has self as parent) void getGeoFromNode(const int node, std::vector& valuesOut, std::vector& parentsOut, const bool smoothflag = true); /// Get distances from all nodes to all nodes, passes back NULL if cannot allocate, if successful you must eventually delete the memory float** getGeoAllToAll(const bool smooth = true);//i really don't think this needs an overloaded function that outputs parents /// 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 int root, const std::vector& ofInterest, std::vector& distsOut, bool smoothflag = true); }; inline void GeodesicHelper::crossProd(const float in1[3], const float in2[3], float out[3]) {//avoid loops for speed - NOT SAFE TO PASS AN INPUT AS OUTPUT out[0] = in1[1] * in2[2] - in1[2] * in2[1]; out[1] = in1[2] * in2[0] - in1[0] * in2[2]; out[2] = in1[0] * in2[1] - in1[1] * in2[0]; } inline float GeodesicHelper::dotProd(const float in1[3], const float in2[3]) { return in1[0] * in2[0] + in1[1] * in2[1] + in1[2] * in2[2]; } inline float GeodesicHelper::normalize(float in[3]) { float mag = std::sqrt(in[0] * in[0] + in[1] * in[1] + in[2] * in[2]); in[0] /= mag; in[1] /= mag; in[2] /= mag; return mag; } inline void GeodesicHelper::coordDiff(const float* coord1, const float* coord2, float out[3]) { out[0] = coord1[0] - coord2[0]; out[1] = coord1[1] - coord2[1]; out[2] = coord1[2] - coord2[2]; } #endif caret-5.6.4~dfsg.1.orig/caret_files/GeodesicHelper.cxx0000664000175000017500000007345111572067322022461 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CoordinateFile.h" #include "GeodesicHelper.h" #include "TopologyFile.h" #include "TopologyHelper.h" #include #include GeodesicHelper::GeodesicHelper(const CoordinateFile* coordsIn, const TopologyFile* topoFileIn) { marked = NULL; if (coordsIn->getNumberOfNodes() != topoFileIn->getNumberOfNodes()) { numNodes = 0; return; }//sanity checks passed const TopologyHelper* topoHelpIn = topoFileIn->getTopologyHelper(false, true, false); int i, j, k, m, myneigh, myneigh2, farnode, farbase, coordbase, neigh2base, neighbase; numNodes = coordsIn->getNumberOfNodes(); //allocate float* coords = new float[3 * numNodes]; output = new float[numNodes]; numNeighbors = new int[numNodes]; marked = new int[numNodes]; changed = new int[numNodes]; parent = new int[numNodes]; nodeNeighbors = new int*[numNodes]; distances = new float*[numNodes]; coordsIn->getAllCoordinates(coords);//get coords float d[3], g[3], ac[3], abhat[3], abmag, ad[3], efhat[3], efmag, ea[3], cdmag, eg[3], eh[3], ah[3], tempvec[3], tempf; for (i = 0; i < numNodes; ++i) {//get neighbors const int* neighbors = topoHelpIn->getNodeNeighbors(i, numNeighbors[i]); nodeNeighbors[i] = new int[numNeighbors[i]]; distances[i] = new float[numNeighbors[i]]; coordbase = i * 3; for (j = 0; j < numNeighbors[i]; ++j) { nodeNeighbors[i][j] = neighbors[j]; coordDiff(coords + coordbase, coords + neighbors[j] * 3, tempvec); distances[i][j] = std::sqrt(tempvec[0] * tempvec[0] + tempvec[1] * tempvec[1] + tempvec[2] * tempvec[2]);//precompute for speed in calls }//so few floating point operations, this should turn out symmetric marked[i] = 0;//initialize } std::vector tempneigh2; std::vector tempdist2; std::vector maintiles, neightiles; nodeNeighbors2 = new int*[numNodes]; numNeighbors2 = new int[numNodes]; distances2 = new float*[numNodes]; for (i = 0; i < numNodes; ++i) {//find shared neighbors, for smoothed dijkstra tempneigh2.clear(); tempdist2.clear(); coordbase = i * 3;//precompute the multiplicative part of the coordinate index, for efficiency topoHelpIn->getNodeTiles(i, maintiles); for (j = 0; j < (int)maintiles.size(); ++j) { const int* tile1 = topoFileIn->getTile(maintiles[j]); myneigh = -1; myneigh2 = -1; for (k = 0; k < 3; ++k) { if (tile1[k] != i) { if (myneigh == -1) { myneigh = tile1[k]; } else { myneigh2 = tile1[k]; } } } if (myneigh2 == -1) continue;//a tile has less than 3 distinct node numbers, move to next tile neighbase = myneigh * 3; neigh2base = myneigh2 * 3; topoHelpIn->getNodeTiles(myneigh, neightiles); for (k = 0; k < (int)neightiles.size(); ++k) { const int* tile2 = topoFileIn->getTile(neightiles[k]); farnode = -1; for (m = 0; m < 3; ++m) { if (tile2[m] == i) break;//discard both tiles that have the root node if (tile2[m] != myneigh && tile2[m] != myneigh2) {//check for matching edge between myneigh and myneigh2 by looking for exactly 1 node that doesn't match either if (farnode == -1) { farnode = tile2[m]; } else break;//if 2 nodes do not belong to the close triangle, this is not the right tile } } if (m == 3)//loop completed without break (correct triangle found), time to do some math { if (farnode < i)//we have already computed from anything less than i to all possibilities, so grab that value instead { for (m = 0; m < numNeighbors2[farnode]; ++m) {//so find it if (nodeNeighbors2[farnode][m] == i) { tempneigh2.push_back(farnode); tempdist2.push_back(distances2[farnode][m]); break; } }//if it wasn't found, then it was invalid (obtuse tetralateral after unfolding) break;//consider next root tile } farbase = farnode * 3; coordDiff(coords + neigh2base, coords + neighbase, abhat);//a is neigh, b is neigh2, b - a = (vector)ab abmag = normalize(abhat); coordDiff(coords + farbase, coords + neighbase, ac);//c is farnode, c - a = (vector)ac tempf = dotProd(abhat, ac); ad[0] = abhat[0] * tempf;//d is the point on the shared edge that farnode (c) is closest to ad[1] = abhat[1] * tempf;//this way we can "unfold" the triangles by projecting the unit vector of the root node to closest point on shared edge from d, the distance of cd ad[2] = abhat[2] * tempf; d[0] = coords[neighbase] + ad[0];//and now we have the point d d[1] = coords[neighbase + 1] + ad[1]; d[2] = coords[neighbase + 2] + ad[2]; coordDiff(coords + neighbase, coords + coordbase, ea);//e is node i, the root node, a - e = (vector)ea tempf = dotProd(abhat, ea);//find the component of ea perpendicular to the shared edge tempvec[0] = abhat[0] * tempf;//find vector fa, f being the point on shared edge closest to e, the root node tempvec[1] = abhat[1] * tempf; tempvec[2] = abhat[2] * tempf; efhat[0] = ea[0] - tempvec[0];//and subtract it to obtain only the perpendicular efhat[1] = ea[1] - tempvec[1]; efhat[2] = ea[2] - tempvec[2]; efmag = normalize(efhat);//normalize to get unit vector coordDiff(&d[0], coords + farbase, tempvec);//this is vector cd, perpendicular to shared edge, from shared edge to far point cdmag = normalize(tempvec);//get its magnitude tempvec[0] = efhat[0] * cdmag;//vector dg, from shared edge at closest point to c (far node), to the unfolded position of farnode (g) tempvec[1] = efhat[1] * cdmag; tempvec[2] = efhat[2] * cdmag; g[0] = d[0] + tempvec[0];//add vector dg to point d to get point g, the unfolded position of farnode g[1] = d[1] + tempvec[1]; g[2] = d[2] + tempvec[2]; coordDiff(&g[0], coords + coordbase, eg);//this is the vector from root (e) to far node after unfolding (g), this is our distance tempf = efmag / (efmag + cdmag);//now we need to check that the path stays inside the tetralateral (ie, that it is convex) eh[0] = eg[0] * tempf;//this is a vector from e (root node) to the point on the shared edge that the full path (eg) crosses eh[1] = eg[1] * tempf;//this is because the lengths of the two perpendiculars to the root and far nodes from the shared edge establishes proportionality eh[2] = eg[2] * tempf; ah[0] = eh[0] - ea[0];//eh - ea = eh + ae = ae + eh = ah, vector from neigh to the point on shared edge the path goes through ah[1] = eh[1] - ea[1]; ah[2] = eh[2] - ea[2]; tempf = normalize(ah);//get the magnitude so we can test that it is positive and less than |ab| if (tempf <= 0.0f || tempf >= abmag) break;//tetralateral is obtuse or triangular, our path is invalid or not shorter, so consider next root tile tempf = normalize(eg);//this is our path length tempneigh2.push_back(farnode); tempdist2.push_back(tempf); break;//there should not be 3 tiles sharing one edge, move to next root tile } } } numNeighbors2[i] = tempneigh2.size(); nodeNeighbors2[i] = new int[numNeighbors2[i]]; distances2[i] = new float[numNeighbors2[i]]; for (j = 0; j < numNeighbors2[i]; ++j) { nodeNeighbors2[i][j] = tempneigh2[j]; distances2[i][j] = tempdist2[j]; } } } void GeodesicHelper::getNodesToGeoDist(const int node, const float maxdist, std::vector& nodesOut, std::vector& distsOut, const bool smoothflag) {//public methods sanity check, private methods process nodesOut.clear(); distsOut.clear(); if (node >= numNodes || maxdist < 0.0f || node < 0) return; QMutexLocker locked(&inUse);//let sanity checks go multithreaded, as if it mattered dijkstra(node, maxdist, nodesOut, distsOut, smoothflag); } void GeodesicHelper::getNodesToGeoDist(const int 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(); if (node >= numNodes || maxdist < 0.0f || node < 0) return; QMutexLocker locked(&inUse);//we need the parents array to stay put, so don't scope this dijkstra(node, maxdist, nodesOut, distsOut, smoothflag); int mysize = (int)nodesOut.size(); parentsOut.resize(mysize); for (int i = 0; i < mysize; ++i) { parentsOut[i] = parent[nodesOut[i]]; } } void GeodesicHelper::dijkstra(const int root, const float maxdist, std::vector& nodes, std::vector& dists, bool smooth) { int i, j, whichnode, whichneigh, numNeigh, numChanged = 0; int* neighbors; float tempf; output[root] = 0.0f; marked[root] |= 4; parent[root] = root;//idiom for end of path changed[numChanged++] = root; myheap active; active.push(root, 0.0f); //we keep values greater than maxdist off the stack, so anything pulled from the stack which is unmarked belongs in the list while (!active.isEmpty()) { whichnode = active.pop(); if (!(marked[whichnode] & 1)) { nodes.push_back(whichnode); dists.push_back(output[whichnode]); marked[whichnode] |= 1;//anything pulled from stack will already be marked as having a valid value (flag 4) neighbors = nodeNeighbors[whichnode]; numNeigh = numNeighbors[whichnode]; for (j = 0; j < numNeigh; ++j) { whichneigh = neighbors[j]; if (!(marked[whichneigh] & 1)) {//skip floating point math if marked 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)) { parent[whichneigh] = whichnode; marked[whichneigh] |= 4; changed[numChanged++] = whichneigh; output[whichneigh] = tempf; active.push(whichneigh, tempf); } else if (tempf < output[whichneigh]) { output[whichneigh] = tempf; active.push(whichneigh, tempf); } } } } if (smooth)//repeat with numNeighbors2, nodeNeighbors2, distance2 { neighbors = nodeNeighbors2[whichnode]; numNeigh = numNeighbors2[whichnode]; for (j = 0; j < numNeigh; ++j) { whichneigh = neighbors[j]; if (!(marked[whichneigh] & 1)) {//skip floating point math if marked tempf = output[whichnode] + distances2[whichnode][j];//isn't precomputation wonderful if (tempf <= maxdist) {//keep it off the heap if it is too far if (!(marked[whichneigh] & 4)) { parent[whichneigh] = whichnode; marked[whichneigh] |= 4; changed[numChanged++] = whichneigh; output[whichneigh] = tempf; active.push(whichneigh, tempf); } else if (tempf < output[whichneigh]) { output[whichneigh] = tempf; active.push(whichneigh, tempf); } } } } } } } for (i = 0; i < numChanged; ++i) { marked[changed[i]] = 0;//minimize reinitialization of arrays } } void GeodesicHelper::dijkstra(const int root, bool smooth) {//straightforward dijkstra, no cutoffs, full surface int i, j, whichnode, whichneigh, numNeigh; int* neighbors; float tempf; output[root] = 0.0f; parent[root] = root;//idiom for end of path myheap active; active.push(root, 0.0f); while (!active.isEmpty()) { whichnode = active.pop(); if (!(marked[whichnode] & 1)) { marked[whichnode] |= 1; neighbors = nodeNeighbors[whichnode]; numNeigh = numNeighbors[whichnode]; for (j = 0; j < numNeigh; ++j) { whichneigh = neighbors[j]; if (!(marked[whichneigh] & 1)) {//skip floating point math if marked tempf = output[whichnode] + distances[whichnode][j]; if (!(marked[whichneigh] & 4)) { parent[whichneigh] = whichnode; marked[whichneigh] |= 4; output[whichneigh] = tempf; active.push(whichneigh, tempf); } else if (tempf < output[whichneigh]) { output[whichneigh] = tempf; active.push(whichneigh, tempf); } } } if (smooth) { neighbors = nodeNeighbors2[whichnode]; numNeigh = numNeighbors2[whichnode]; for (j = 0; j < numNeigh; ++j) { whichneigh = neighbors[j]; if (!(marked[whichneigh] & 1)) {//skip floating point math if marked tempf = output[whichnode] + distances2[whichnode][j]; if (!(marked[whichneigh] & 4)) { parent[whichneigh] = whichnode; marked[whichneigh] |= 4; output[whichneigh] = tempf; active.push(whichneigh, tempf); } else if (tempf < output[whichneigh]) { output[whichneigh] = tempf; active.push(whichneigh, tempf); } } } } } } for (i = 0; i < numNodes; ++i) { marked[i] = 0; } } float** GeodesicHelper::getGeoAllToAll(const bool smooth) { long long bytes = (((long long)numNodes) * numNodes * (sizeof(float) + sizeof(int)) + numNodes * (sizeof(float*) + sizeof(int*))) * 100;//fixed point short index = 0; static const char *labels[9] = {" Bytes", " Kilobytes", " Megabytes", " Gigabytes", " Terabytes", " Petabytes", " Exabytes", " Zettabytes", " Yottabytes"}; while (index < 8 && bytes > 80000) {//add 2 zeroes, thats 800.00 ++index; bytes = bytes >> 10; } QMutexLocker locked(&inUse);//don't sit there with memory allocated but locked out of computation, lock early - also before status messages std::cout << "attempting to allocate " << bytes / 100 << "." << bytes % 100 << labels[index] << "..."; std::cout.flush(); int i = -1, j; bool fail = false; float** ret = NULL; int** parents = NULL; try { ret = new float*[numNodes]; if (ret != NULL) { for (i = 0; i < numNodes; ++i) { ret[i] = new float[numNodes]; if (ret[i] == NULL) { fail = true; break;//have to break so it doesn't increment i } } } } catch (std::bad_alloc e) {//should catch if new likes to throw exceptions instead of returning null fail = true; } if (ret == NULL) { std::cout << "failed" << std::endl; return NULL; } if (fail) { std::cout << "failed" << std::endl; for (j = 0; j < i; ++j) delete[] ret[j]; if (i > -1) delete[] ret; return NULL; } i = -1; try { parents = new int*[numNodes]; if (parents != NULL) { for (i = 0; i < numNodes; ++i) { parents[i] = new int[numNodes]; if (parents[i] == NULL) { fail = true; break;//have to break so it doesn't increment i } } } } catch (std::bad_alloc e) {//should catch if new likes to throw exceptions instead of returning null fail = true; } if (parents == NULL) { std::cout << "failed" << std::endl; for (i = 0; i < numNodes; ++i) delete[] ret[i]; delete[] ret; return NULL; } if (fail) { std::cout << "failed" << std::endl; for (j = 0; j < i; ++j) delete[] parents[j]; if (i > -1) delete[] parents; for (i = 0; i < numNodes; ++i) delete[] ret[i]; delete[] ret; return NULL; } std::cout << "success" << std::endl; alltoall(ret, parents, smooth); for (i = 0; i < numNodes; ++i) delete[] parents[i]; delete[] parents; return ret; } void GeodesicHelper::alltoall(float** out, int** parents, bool smooth) {//propagates info about shortest paths not containing root to other roots, hopefully making the problem tractable int root, i, j, whichnode, whichneigh, numNeigh, remain, myparent, myparent2, myparent3, prevdots = 0, dots; int* neighbors; float tempf, tempf2; myheap active; for (i = 0; i < numNodes; ++i) { for (j = 0; j < numNodes; ++j) { out[i][j] = -1.0f; } } remain = numNodes; std::cout << "|0% calculating geodesic distances 100%|" << std::endl; // .................................................. for (root = 0; root < numNodes; ++root) { //std::cout << root << std::endl; dots = (50 * root) / numNodes;//simple progress indicator while (prevdots < dots) { std::cout << '.'; std::cout.flush(); ++prevdots; } if (root != 0) { remain = 0; for (i = 0; i < numNodes; ++i)//find known values { if (out[root][i] > 0.0f) { marked[i] = 2;//mark that we already have a value, skip calculation, but not yet added to active list } else { marked[i] = 0; ++remain;//count how many more we need to compute so we can stop early } } active.clear(); }//marking done, dijkstra time out[root][root] = 0.0f; parents[root][root] = root;//idiom for end of path active.push(root, 0.0f); while (remain && !active.isEmpty()) { whichnode = active.pop(); if (!(marked[whichnode] & 1)) { if (!(marked[whichnode] & 2)) --remain; marked[whichnode] |= 1; neighbors = nodeNeighbors[whichnode]; numNeigh = numNeighbors[whichnode]; for (j = 0; j < numNeigh; ++j) { whichneigh = neighbors[j]; if (marked[whichneigh] & 2) {//already has a value and parent for this root if (!(marked[whichneigh] & 8)) {//not yet in active list active.push(whichneigh, out[root][whichneigh]); marked[whichneigh] |= 8; } } else { if (!(marked[whichneigh] & 1)) {//skip floating point math if marked tempf = out[root][whichnode] + distances[whichnode][j]; if (!(marked[whichneigh] & 4)) { out[root][whichneigh] = tempf; parents[root][whichneigh] = whichnode; marked[whichneigh] |= 4; active.push(whichneigh, tempf); } else if (tempf < out[root][whichneigh]) { out[root][whichneigh] = tempf; parents[root][whichneigh] = whichnode; active.push(whichneigh, tempf); } } } } if (smooth) { neighbors = nodeNeighbors2[whichnode]; numNeigh = numNeighbors2[whichnode]; for (j = 0; j < numNeigh; ++j) { whichneigh = neighbors[j]; if (marked[whichneigh] & 2) {//already has a value and parent for this root if (!(marked[whichneigh] & 8)) {//not yet in active list active.push(whichneigh, out[root][whichneigh]); marked[whichneigh] |= 8; } } else { if (!(marked[whichneigh] & 1)) {//skip floating point math if marked tempf = out[root][whichnode] + distances2[whichnode][j]; if (!(marked[whichneigh] & 4)) { out[root][whichneigh] = tempf; parents[root][whichneigh] = whichnode; marked[whichneigh] |= 4; active.push(whichneigh, tempf); } else if (tempf < out[root][whichneigh]) { out[root][whichneigh] = tempf; parents[root][whichneigh] = whichnode; active.push(whichneigh, tempf); } } } } } } }//dijkstra done...lotsa brackets...now to propagate the information gained to other roots for (i = root + 1; i < numNodes; ++i) {//any node smaller than root already has all distances calculated for entire surface if (!(marked[i] & 2)) {//if endpoint already had distance to root precomputed, all available info from this node has been propagated previously myparent2 = i; myparent = parents[root][i]; myparent3 = myparent; tempf = out[root][i]; while (myparent != root) { tempf2 = tempf - out[root][myparent]; if (myparent > root) {//try to be swap-friendly by not setting values in finished columns out[myparent][i] = tempf2;//use midpoint as root, parent of endpoint is myparent3 parents[myparent][i] = myparent3; } out[i][myparent] = tempf2;//use endpoint as root, parent of midpoint is myparent2 parents[i][myparent] = myparent2; myparent2 = myparent;//step along path myparent = parents[root][myparent]; } out[i][root] = out[root][i];//finally, fill the transpose parents[i][root] = myparent2; } }//propagation of best paths to other roots complete, dijkstra again } while (prevdots < 50) { std::cout << '.'; ++prevdots; } std::cout << std::endl; for (i = 0; i < numNodes; ++i) { marked[i] = 0; } } void GeodesicHelper::getGeoFromNode(const int node, float* valuesOut, const bool smoothflag) { if (node < 0 || node >= numNodes || !valuesOut) { return; } QMutexLocker 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 int node, float* valuesOut, int* parentsOut, const bool smoothflag) { if (node < 0 || node >= numNodes || !valuesOut || !parentsOut) { return; } QMutexLocker locked(&inUse);//don't screw with member variables while in use float* temp = output;//swap out the output pointer to avoid allocation int* tempi = parent; output = valuesOut; parent = parentsOut; dijkstra(node, smoothflag); output = temp;//restore the pointers to the original memory parent = tempi; } void GeodesicHelper::getGeoFromNode(const int node, std::vector& valuesOut, const bool smoothflag) { if (node < 0 || node >= numNodes) { return; } QMutexLocker locked(&inUse); dijkstra(node, smoothflag); valuesOut.resize(numNodes); for (int i = 0; i < numNodes; ++i) { valuesOut[i] = output[i]; } } void GeodesicHelper::getGeoFromNode(const int node, std::vector& valuesOut, std::vector& parentsOut, const bool smoothflag) { if (node < 0 || node >= numNodes) { return; } QMutexLocker locked(&inUse); dijkstra(node, smoothflag); valuesOut.resize(numNodes); parentsOut.resize(numNodes); for (int i = 0; i < numNodes; ++i) { valuesOut[i] = output[i]; parentsOut[i] = parent[i]; } } void GeodesicHelper::dijkstra(const int root, const std::vector& interested, bool smooth) { int i, j, whichnode, whichneigh, numNeigh, numChanged = 0, remain = 0; int* 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] = root;//idiom for end of path myheap active; active.push(root, 0.0f); while (remain && !active.isEmpty()) { whichnode = active.pop(); if (!(marked[whichnode] & 1)) { if (marked[whichnode] & 2) { --remain; } marked[whichnode] |= 1;//anything pulled from stack will already be marked as having a valid value (flag 4), so already in changed list neighbors = nodeNeighbors[whichnode]; numNeigh = numNeighbors[whichnode]; for (j = 0; j < numNeigh; ++j) { whichneigh = neighbors[j]; if (!(marked[whichneigh] & 1)) {//skip floating point math if marked 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; active.push(whichneigh, tempf); } else if (tempf < output[whichneigh]) { output[whichneigh] = tempf; active.push(whichneigh, tempf); } } } if (smooth)//repeat with numNeighbors2, nodeNeighbors2, distance2 { neighbors = nodeNeighbors2[whichnode]; numNeigh = numNeighbors2[whichnode]; for (j = 0; j < numNeigh; ++j) { whichneigh = neighbors[j]; if (!(marked[whichneigh] & 1)) {//skip floating point math if marked 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; active.push(whichneigh, tempf); } else if (tempf < output[whichneigh]) { output[whichneigh] = tempf; active.push(whichneigh, tempf); } } } } } } for (i = 0; i < numChanged; ++i) { marked[changed[i]] = 0;//minimize reinitialization of arrays } } void GeodesicHelper::getGeoToTheseNodes(const int root, const std::vector& ofInterest, std::vector& distsOut, bool smoothflag) { if (root < 0 || root >= numNodes) { distsOut.clear();//empty array is error condition return; } int 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; } } QMutexLocker 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]]; } } caret-5.6.4~dfsg.1.orig/caret_files/GeodesicDistanceFile.h0000664000175000017500000001037411572067322023214 0ustar michaelmichael #ifndef __GEODESIC_DISTANCE_FILE_H__ #define __GEODESIC_DISTANCE_FILE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "NodeAttributeFile.h" /// class for storing geodesic distance file class GeodesicDistanceFile : public NodeAttributeFile { public: /// Constructor GeodesicDistanceFile(); /// Destructor ~GeodesicDistanceFile(); /// append a node attribute file to this one void append(NodeAttributeFile& naf) throw (FileException); /// append a node attribute file to this one but selectively load/overwrite columns /// columnDestination is where naf's columns should be (-1=new, -2=do not load) void append(NodeAttributeFile& naf, std::vector columnDestination, const FILE_COMMENT_MODE fcm) throw (FileException); /// add columns to this node attribute file void addColumns(const int numberOfNewColumns); /// add nodes to this file void addNodes(const int numberOfNodesToAdd); /// Clears current file data in memory. void clear(); /// deform "this" node attribute file placing the output in "deformedFile". void deformFile(const DeformationMapFile& dmf, NodeAttributeFile& deformedFile, const DEFORM_TYPE dt) const throw (FileException); /// set the number of nodes and columns in the file void setNumberOfNodesAndColumns(const int numNodes, const int numCols); /// reset a column of data void resetColumn(const int columnNumber); /// remove a column of data void removeColumn(const int columnNumber); /// get the parent for a node int getNodeParent(const int nodeNumber, const int columnNumber) const; /// set the parent for a node void setNodeParent(const int nodeNumber, const int columnNumber, const int parent); /// get the distance to a parent for a node float getNodeParentDistance(const int nodeNumber, const int columnNumber) const; /// set the distance to a parent for a node void setNodeParentDistance(const int nodeNumber, const int columnNumber, const float distance); /// get the root node int getRootNode(const int columnNumber) const; /// set the root node void setRootNode(const int columnNumber, const int node); protected: /// Read the contents of the file (header has already been read) void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException); /// Write the file's data (header has already been written) void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException); /// root node of geodesic std::vector rootNode; /// parent for node in path that leads to root node std::vector nodeParent; // distance to parent in path that leads to root node std::vector nodeParentDistance; }; #endif // __GEODESIC_DISTANCE_FILE_H__ caret-5.6.4~dfsg.1.orig/caret_files/GeodesicDistanceFile.cxx0000664000175000017500000004167411572067322023576 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "GeodesicDistanceFile.h" #include "SpecFile.h" #include "StringUtilities.h" /** * Constructor. */ GeodesicDistanceFile::GeodesicDistanceFile() : NodeAttributeFile("geodesic distance file", SpecFile::getGeodesicDistanceFileExtension(), AbstractFile::FILE_FORMAT_ASCII, FILE_IO_READ_AND_WRITE, FILE_IO_READ_AND_WRITE, FILE_IO_NONE, FILE_IO_NONE) { clear(); } /** * Destructor. */ GeodesicDistanceFile::~GeodesicDistanceFile() { clear(); } /** * append a node attribute file to this one. */ void GeodesicDistanceFile::append(NodeAttributeFile& naf) throw (FileException) { if (naf.getNumberOfColumns() > 0) { std::vector destinationColumns(naf.getNumberOfColumns(), APPEND_COLUMN_NEW); append(naf, destinationColumns, FILE_COMMENT_MODE_APPEND); } } /** * append a node attribute file to this one but selectively load/overwrite columns * columnDestination is where naf's columns should be (-1=new, -2=do not load). */ void GeodesicDistanceFile::append(NodeAttributeFile& naf, std::vector columnDestinationIn, const FILE_COMMENT_MODE fcm) throw (FileException) { bool setTheFileNameFlag = false; std::vector columnDestination = columnDestinationIn; GeodesicDistanceFile& gdf = dynamic_cast(naf); if (numberOfNodes != gdf.numberOfNodes) { if (numberOfNodes > 0) { throw FileException("Trying to append geodesic distance file with a different number " "of nodes"); } else { setTheFileNameFlag = true; } } setModified(); // // Find out how many columns need to be added // int numColumnsToAdd = 0; int newColumnIndex = numberOfColumns; for (int i = 0; i < gdf.getNumberOfColumns(); i++) { if (columnDestination[i] == APPEND_COLUMN_NEW) { numColumnsToAdd++; columnDestination[i] = newColumnIndex; newColumnIndex++; } } // // Add on additional columns // if (getNumberOfNodes() == 0) { setNumberOfNodesAndColumns(gdf.getNumberOfNodes(), numColumnsToAdd); } else { addColumns(numColumnsToAdd); } // // copy column names from other file // for (int k = 0; k < gdf.numberOfColumns; k++) { if (columnDestination[k] >= 0) { const int col = columnDestination[k]; setColumnName(col, gdf.getColumnName(k)); setColumnComment(col, gdf.getColumnComment(k)); } } // // copy geodesic data from other file // for (int j = 0; j < gdf.numberOfColumns; j++) { if (columnDestination[j] >= 0) { const int col = columnDestination[j]; for (int i = 0; i < numberOfNodes; i++) { setNodeParent(i, col, gdf.getNodeParent(i, j)); setNodeParentDistance(i, col, getNodeParentDistance(i, j)); } setRootNode(col, gdf.getRootNode(j)); } } if (setTheFileNameFlag) { setFileName(gdf.getFileName()); } // // transfer the file's comment // appendFileComment(gdf, fcm); } /** * add columns to this node attribute file. */ void GeodesicDistanceFile::addColumns(const int numberOfNewColumns) { const int oldNumberOfColumns = numberOfColumns; const int totalColumns = numberOfColumns + numberOfNewColumns; // // Save existing lat lon data // const std::vector parents = nodeParent; const std::vector distances = nodeParentDistance; // // Setup file for new number of columns (will expand space for column naming) // setNumberOfNodesAndColumns(numberOfNodes, totalColumns); // // transfer existing data // for (int i = 0; i < numberOfNodes; i++) { for (int j = 0; j < numberOfColumns; j++) { if (j < oldNumberOfColumns) { const int oldIndex = (oldNumberOfColumns * i) + j; setNodeParent(i, j, parents[oldIndex]); setNodeParentDistance(i, j, distances[oldIndex]); } else { setNodeParent(i, j, -1); setNodeParentDistance(i, j, 0.0); } } } setModified(); } /** * add nodes to this file. */ void GeodesicDistanceFile::addNodes(const int numberOfNodesToAdd) { setNumberOfNodesAndColumns(numberOfNodes + numberOfNodesToAdd, numberOfColumns); } /** * Clears current file data in memory. */ void GeodesicDistanceFile::clear() { clearNodeAttributeFile(); setNumberOfNodesAndColumns(0, 0); } /** * deform "this" node attribute file placing the output in "deformedFile". */ void GeodesicDistanceFile::deformFile(const DeformationMapFile& /*dmf*/, NodeAttributeFile& /*deformedFile*/, const DEFORM_TYPE /*dt*/) const throw (FileException) { throw FileException("Deformation of Geodesic Distance File not supported."); } /** * set the number of nodes and columns in the file. */ void GeodesicDistanceFile::setNumberOfNodesAndColumns(const int numNodes, const int numCols) { numberOfNodes = numNodes; numberOfColumns = numCols; const int num = numberOfNodes * numberOfColumns * numberOfItemsPerColumn; if (num <= 0) { nodeParent.clear(); nodeParentDistance.clear(); rootNode.clear(); } else { nodeParent.resize(num); nodeParentDistance.resize(num); rootNode.resize(numberOfColumns, -1); } numberOfNodesColumnsChanged(); } /** * reset a column of data. */ void GeodesicDistanceFile::resetColumn(const int columnNumber) { for (int i = 0; i < numberOfNodes; i++) { setNodeParent(i, columnNumber, -1); setNodeParentDistance(i, columnNumber, 0.0); } rootNode[columnNumber] = -1; setModified(); } /** * remove a column of data. */ void GeodesicDistanceFile::removeColumn(const int columnNumber) { if (numberOfColumns <= 1) { clear(); return; } // // Transfer lat/lon data // GeodesicDistanceFile gdf; gdf.setNumberOfNodesAndColumns(numberOfNodes, numberOfColumns - 1); for (int i = 0; i < numberOfNodes; i++) { int ctr = 0; for (int j = 0; j < numberOfColumns; j++) { if (j != columnNumber) { gdf.setNodeParent(i, ctr, getNodeParent(i, j)); gdf.setNodeParentDistance(i, ctr, getNodeParentDistance(i, j)); ctr++; } } } int colCtr = 0; for (int j = 0; j < numberOfColumns; j++) { if (j != columnNumber) { gdf.setRootNode(colCtr, getRootNode(j)); colCtr++; } } // // Transfer column information // int ctr = 0; for (int j = 0; j < numberOfColumns; j++) { if (j != columnNumber) { setColumnName(ctr, getColumnName(j)); setColumnComment(ctr, getColumnComment(j)); ctr++; } } setNumberOfNodesAndColumns(numberOfNodes, numberOfColumns - 1); nodeParent = gdf.nodeParent; nodeParentDistance = gdf.nodeParentDistance; rootNode = gdf.rootNode; setModified(); } /** * get the parent for a node. */ int GeodesicDistanceFile::getNodeParent(const int nodeNumber, const int columnNumber) const { const int index = getOffset(nodeNumber, columnNumber); return nodeParent[index]; } /** * set the parent for a node. */ void GeodesicDistanceFile::setNodeParent(const int nodeNumber, const int columnNumber, const int parent) { const int index = getOffset(nodeNumber, columnNumber); nodeParent[index] = parent; } /** * get the distance to a parent for a node. */ float GeodesicDistanceFile::getNodeParentDistance(const int nodeNumber, const int columnNumber) const { const int index = getOffset(nodeNumber, columnNumber); return nodeParentDistance[index]; } /** * set the distance to a parent for a node. */ void GeodesicDistanceFile::setNodeParentDistance(const int nodeNumber, const int columnNumber, const float distance) { const int index = getOffset(nodeNumber, columnNumber); nodeParentDistance[index] = distance; } /** * get the root node. */ int GeodesicDistanceFile::getRootNode(const int columnNumber) const { return rootNode[columnNumber]; } /** * set the root node. */ void GeodesicDistanceFile::setRootNode(const int columnNumber, const int node) { rootNode[columnNumber] = node; } /** * Read the contents of the file (header has already been read). */ void GeodesicDistanceFile::readFileData(QFile& /*file*/, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException) { int numNodes = -1; int numCols = -1; int fileVersion = -1; bool readingTags = true; while(readingTags) { QString tag, tagValue; readTagLine(stream, tag, tagValue); if (tag == tagBeginData) { readingTags = false; } else if (tag == tagFileVersion) { fileVersion = tagValue.toInt(); } else if (tag == tagNumberOfNodes) { numNodes = tagValue.toInt(); if ((numNodes > 0) && (numCols > 0)) { setNumberOfNodesAndColumns(numNodes, numCols); } } else if (tag == tagNumberOfColumns) { numCols = tagValue.toInt(); if ((numNodes > 0) && (numCols > 0)) { setNumberOfNodesAndColumns(numNodes, numCols); } } else if (tag == tagColumnName) { QString name; const int index = splitTagIntoColumnAndValue(tagValue, name); columnNames[index] = name; } else if (tag == tagColumnComment) { QString name; const int index = splitTagIntoColumnAndValue(tagValue, name); columnComments[index] = StringUtilities::setupCommentForDisplay(name); } else if (tag == tagFileTitle) { fileTitle = tagValue; } else { std::cout << "WARNING: Unknown Geodesic File Tag: " << tag.toAscii().constData() << std::endl; } } if (fileVersion != 1) { QString msg("Geodesic Distance File Version "); msg.append(StringUtilities::fromNumber(fileVersion)); msg.append(" is not supported in this version of Caret5. You may need a newer " "version of Caret5."); throw FileException(filename, msg); } if (numNodes <= 0) { throw FileException(filename, "No data in Geodesic file"); } // // Should reading data be skipped ? // if (getReadMetaDataOnlyFlag()) { return; } switch (getFileReadType()) { case FILE_FORMAT_ASCII: { std::vector tokens; QString line; readLineIntoTokens(stream, line, tokens); if (static_cast(tokens.size()) >= numberOfColumns) { for (int j = 0; j < numberOfColumns; j++) { rootNode[j] = tokens[j].toInt(); } } for (int i = 0; i < numberOfNodes; i++) { readLineIntoTokens(stream, line, tokens); if (static_cast(tokens.size()) == (numberOfColumns * 2 + 1)) { for (int j = 0; j < numberOfColumns; j++) { const int index = getOffset(i, j); nodeParent[index] = tokens[j * 2 + 1].toInt(); nodeParentDistance[index] = tokens[j * 2 + 2].toFloat(); } } else { QString msg("Reading Geodesic Distance file line: "); msg.append(line); throw FileException(filename, msg); } } } break; case FILE_FORMAT_BINARY: // // Needed for QT 4.2.2 // binStream.device()->seek(stream.pos()); for (int j = 0; j < numCols; j++) { binStream >> rootNode[j]; } for (int i = 0; i < numNodes; i++) { for (int j = 0; j < numCols; j++) { int parent; float distance; binStream >> parent >> distance; const int index = getOffset(i, j); nodeParent[index] = parent; nodeParentDistance[index] = distance; } } break; case FILE_FORMAT_XML: throw FileException(filename, "Reading in XML format not supported."); case FILE_FORMAT_XML_BASE64: throw FileException(filename, "Reading XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "Reading XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Reading XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Reading in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Comma Separated Value File Format not supported."); break; } } /** * Write the file's data (header has already been written). */ void GeodesicDistanceFile::writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException) { const int numNodes = getNumberOfNodes(); const int numCols = getNumberOfColumns(); stream << tagFileVersion << " 1" << "\n"; stream << tagNumberOfNodes << " " << numNodes << "\n"; stream << tagNumberOfColumns << " " << numCols << "\n"; stream << tagFileTitle << " " << fileTitle << "\n"; for (int j = 0; j < numberOfColumns; j++) { stream << tagColumnName << " " << j << " " << columnNames[j] << "\n"; stream << tagColumnComment << " " << j << " " << StringUtilities::setupCommentForStorage(columnComments[j]) << "\n"; } stream << tagBeginData << "\n"; switch (getFileWriteType()) { case FILE_FORMAT_ASCII: for (int j = 0; j < numCols; j++) { if (j > 0) { stream << " "; } stream << rootNode[j]; } stream << "\n"; for (int i = 0; i < numNodes; i++) { stream << i; for (int j = 0; j < numCols; j++) { stream << " " << getNodeParent(i, j) << " " << getNodeParentDistance(i, j); } stream << "\n"; } break; case FILE_FORMAT_BINARY: #ifdef QT4_FILE_POS_BUG setBinaryFilePosQT4Bug(); #else // QT4_FILE_POS_BUG // // still a bug in QT 4.2.2 // setBinaryFilePosQT4Bug(); #endif // QT4_FILE_POS_BUG for (int j = 0; j < numCols; j++) { binStream << rootNode[j]; } for (int i = 0; i < numNodes; i++) { for (int j = 0; j < numCols; j++) { binStream << getNodeParent(i, j) << getNodeParentDistance(i, j); } } break; case FILE_FORMAT_XML: throw FileException(filename, "Writing in XML format not supported."); break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Writing XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Writing in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Comma Separated Value File Format not supported."); break; } } caret-5.6.4~dfsg.1.orig/caret_files/GenericXmlFile.h0000664000175000017500000000513511572067322022053 0ustar michaelmichael #ifndef __GENERIC_XML_FILE_H__ #define __GENERIC_XML_FILE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include class QDomDocument; class QDomNode; #include "AbstractFile.h" /// Class for stroring an XML file. class GenericXmlFile : public AbstractFile { public: /// Constructor GenericXmlFile(); /// Destructor ~GenericXmlFile(); /// clear the file void clear(); /// returns true if the file is isEmpty (contains no data) bool empty() const { return false; } //sumsFileInfo.isEmpty(); } /// Get element(s) from the XML file. void getValue(const QString& elementName, std::vector& elements); /// Get an element from the XML file. QString getValue(const QString& elementName); protected: /// read the file void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException); /// write the file void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException); /// Search the XML tree to find the specified element. void getValueSearchTree(const std::vector& elementNameComponents, const int nameComponentIndex, const QDomNode node, std::vector& elements); /// root element of the document QDomElement rootElement; }; #endif // __GENERIC_XML_FILE_H__ caret-5.6.4~dfsg.1.orig/caret_files/GenericXmlFile.cxx0000664000175000017500000001577411572067322022440 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include "DebugControl.h" #include "FileUtilities.h" #include "GenericXmlFile.h" #include "StringUtilities.h" /** * Constructor. */ GenericXmlFile::GenericXmlFile() : AbstractFile("Generic XML File", ".xml", true, FILE_FORMAT_XML, FILE_IO_NONE, FILE_IO_NONE, FILE_IO_READ_ONLY, FILE_IO_NONE) { clear(); } /** * Destructor. */ GenericXmlFile::~GenericXmlFile() { clear(); } /** * clear the file. */ void GenericXmlFile::clear() { clearAbstractFile(); rootElement.clear(); } /** * Get an element from the XML file. */ QString GenericXmlFile::getValue(const QString& elementName) { QString value; std::vector elems; getValue(elementName, elems); if (elems.empty() == false) { value = elems[0]; } return value; } /** * Get element(s) from the XML file. */ void GenericXmlFile::getValue(const QString& elementName, std::vector& elements) { elements.clear(); if (elementName.isEmpty() == false) { std::vector nameComponents; StringUtilities::token(elementName, ":", nameComponents); if (nameComponents.empty() == false) { if (nameComponents[0] == rootElement.tagName()) { getValueSearchTree(nameComponents, 1, rootElement.firstChild(), elements); } } } } /** * Search the XML tree to find the specified element. */ void GenericXmlFile::getValueSearchTree(const std::vector& elementNameComponents, const int nameComponentIndex, const QDomNode nodeIn, std::vector& elements) { QDomNode node = nodeIn; while (node.isNull() == false) { bool continueLoop = false; QDomElement elem = node.toElement(); if (elem.isNull() == false) { continueLoop = true; // // Does this element tag match the current name component // QString tagName(elem.tagName()); if (tagName == elementNameComponents[nameComponentIndex]) { // // Is this last name component // if (nameComponentIndex == static_cast(elementNameComponents.size() - 1)) { elements.push_back(getXmlElementFirstChildAsString(elem)); } else { // // Continue searching // getValueSearchTree(elementNameComponents, nameComponentIndex + 1, elem.firstChild(), elements); continueLoop = false; } } } node = node.nextSibling(); if (continueLoop == false) { return; } } } /** * Process files tag. * void GenericXmlFile::processFiles(QDomElement& filesElem) throw (FileException) { QDomNode node = filesElem.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (DebugControl::getDebugOn()) { std::cout << "Tag Name: " << elem.tagName().toAscii().constData() << std::endl; } if (elem.tagName() == "header") { readHeaderXML(elem); } else if (elem.tagName() == "file-version") { processFileVersion(elem); } else if (elem.tagName() == "file") { processFile(elem); } else { std::cerr << "Atlas Space node not recognized in root " << elem.tagName().toAscii().constData() << std::endl; } } node = node.nextSibling(); } } */ /** * read the file. */ void GenericXmlFile::readFileData(QFile&, QTextStream& /* stream */, QDataStream&, QDomElement& rootElementIn) throw (FileException) { rootElement.clear(); rootElement = rootElementIn; /* // // Place the file contents into a QDomDocument which will parse file. // QString errorMessage; int errorLine = 0, errorColumn = 0; QDomDocument doc("atlas-space-file-document"); if (doc.setContent(s, &errorMessage, &errorLine, &errorColumn) == false) { std::ostringstream str; str << "Error parsing at line " << errorLine << " column " << errorColumn << ". "; str << errorMessage << std::ends; throw FileException("", str.str().c_str()); } // // Traverse the direct children just to get the file header. // rootElement = doc.documentElement(); */ if (rootXmlElementTagName.isEmpty() == false) { const QString rootElementNameFound(rootElement.tagName()); if (rootElementNameFound != rootXmlElementTagName) { QString msg("\nNot an GenericXmlFile. Root element is: "); msg.append(rootElementNameFound); msg.append(".\nRoot element should be: "); msg.append(rootXmlElementTagName); throw FileException(filename, msg); } } QDomNode node = rootElement.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (DebugControl::getDebugOn()) { std::cout << "Tag Name: " << elem.tagName().toAscii().constData() << std::endl; } if ((elem.tagName() == xmlHeaderOldTagName) || (elem.tagName() == xmlHeaderTagName)) { // ignore } else if (elem.tagName() == "version") { // processFileVersion(elem); } else if (elem.tagName() == "files") { // processFiles(elem); } } node = node.nextSibling(); } } /** * write the file. */ void GenericXmlFile::writeFileData(QTextStream&, QDataStream&, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException) { throw FileException(filename, "Writing GenericXmlFile not supported."); } caret-5.6.4~dfsg.1.orig/caret_files/FreeSurferSurfaceFile.h0000664000175000017500000000726311572067322023403 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __FREE_SURFER_SURFACE_FILE_H__ #define __FREE_SURFER_SURFACE_FILE_H__ #include "AbstractFile.h" /// Class for reading and writing a free surfer surface file class FreeSurferSurfaceFile : public AbstractFile { public: /// Constructor FreeSurferSurfaceFile(); /// Destructor ~FreeSurferSurfaceFile(); /// clear the file void clear(); /// returns true if the file is isEmpty (contains no data) bool empty() const; /// get the number of vertices int getNumberOfVertices() const; /// get the number of triangles int getNumberOfTriangles() const; /// get the vertex for an index int getVertexNumber(const int indx) const; /// get coordinates of a vertex void getVertexCoordinates(const int indx, int& vertexNumber, float xyz[3]) const; /// set coordinates of a vertex void setVertexCoordinates(const int indx, const int vertexNumber, const float xyz[3]); /// get vertices of a triangle void getTriangle(const int triangleNumber, int verts[3]) const; /// set vertices of a triangle void setTriangle(const int triangleNumber, const int verts[3]); /// get is a free surfer an ascii patch surface file bool getIsAsciiPatchFile() const { return patchAsciiFileFlag; } /// get is a free surfer a binary patch surface file bool getIsBinaryPatchFile() const { return patchBinaryFileFlag; } /// set number of vertices and triangles void setNumberOfVerticesAndTriangles(const int numVertices, const int numTriangles); /// read the specified file //void readFile(const QString& filenameIn) throw (FileException); /// Write the current file's memory to the specified name //void writeFile(const QString& filenameIn) throw (FileException); private: /// read file void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException); /// write file void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException); /// class for storing vertices class Vertex { public: int vertexNumber; float xyz[3]; }; /// the vertices std::vector vertices; /// the triangles (3 per triangle) std::vector triangles; /// this is a free surfer ascii patch file bool patchAsciiFileFlag; /// this is a free surfer binary patch file bool patchBinaryFileFlag; }; #endif // caret-5.6.4~dfsg.1.orig/caret_files/FreeSurferSurfaceFile.cxx0000664000175000017500000004610711572067322023756 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "DebugControl.h" #include "FreeSurferSurfaceFile.h" #include "SpecFile.h" /** * Constructor * Format Info: http://wideman-one.com/gw/brain/fs/surfacefileformats.htm */ FreeSurferSurfaceFile::FreeSurferSurfaceFile() : AbstractFile("Free Surfer Surface File", SpecFile::getFreeSurferAsciiSurfaceFileExtension(), false, AbstractFile::FILE_FORMAT_ASCII, AbstractFile::FILE_IO_READ_AND_WRITE, AbstractFile::FILE_IO_READ_ONLY) { } /** * Destructor */ FreeSurferSurfaceFile::~FreeSurferSurfaceFile() { } /** * clear the file. */ void FreeSurferSurfaceFile::clear() { clearAbstractFile(); patchAsciiFileFlag = false; patchBinaryFileFlag = false; vertices.clear(); triangles.clear(); } /** * returns true if the file is isEmpty (contains no data). */ bool FreeSurferSurfaceFile::empty() const { return (getNumberOfVertices() == 0); } /** * get the number of vertices. */ int FreeSurferSurfaceFile::getNumberOfVertices() const { return vertices.size(); } /** * get the number of triangles. */ int FreeSurferSurfaceFile::getNumberOfTriangles() const { return (triangles.size() / 3); } /** * get the vertex for an index. */ int FreeSurferSurfaceFile::getVertexNumber(const int indx) const { return vertices[indx].vertexNumber; } /** * get coordinates of a vertex. */ void FreeSurferSurfaceFile::getVertexCoordinates(const int indx, int& vertexNumber, float xyz[3]) const { vertexNumber = vertices[indx].vertexNumber; xyz[0] = vertices[indx].xyz[0]; xyz[1] = vertices[indx].xyz[1]; xyz[2] = vertices[indx].xyz[2]; } /** * set coordinates of a vertex. */ void FreeSurferSurfaceFile::setVertexCoordinates(const int indx, const int vertexNumber, const float xyz[3]) { vertices[indx].vertexNumber = vertexNumber; vertices[indx].xyz[0] = xyz[0]; vertices[indx].xyz[1] = xyz[1]; vertices[indx].xyz[2] = xyz[2]; } /** * get vertices of a triangle. */ void FreeSurferSurfaceFile::getTriangle(const int triangleNumber, int verts[3]) const { const int i3 = triangleNumber * 3; verts[0] = triangles[i3]; verts[1] = triangles[i3 + 1]; verts[2] = triangles[i3 + 2]; } /** * set vertices of a triangle. */ void FreeSurferSurfaceFile::setTriangle(const int triangleNumber, const int verts[3]) { const int i3 = triangleNumber * 3; triangles[i3] = verts[0]; triangles[i3 + 1] = verts[1]; triangles[i3 + 2] = verts[2]; } /** * set number of vertices and triangles. */ void FreeSurferSurfaceFile::setNumberOfVerticesAndTriangles(const int numVertices, const int numTriangles) { vertices.resize(numVertices); triangles.resize(numTriangles * 3); } /** * read the specified file. */ /* void FreeSurferSurfaceFile::readFile(const QString& filenameIn) throw (FileException) { // // Open the file as a text stream // clear(); filename = filenameIn); QFile file(filename); if (file.open(IO_ReadOnly)) { QTextStream stream(&file); try { readFileData(file, stream); } catch (FileException& e) { file.close(); throw e; } file.close(); } else { throw FileException(filename, "Failure trying to open: "); } } */ /** * Write the current file's memory to the specified name. */ /* void FreeSurferSurfaceFile::writeFile(const QString& filenameIn) throw (FileException) { filename = filenameIn); QFile file(filename); if (file.open(IO_ReadOnly)) { QTextStream stream(&file); stream.setf(QTextStream::fixed); stream.precision(6); try { writeFileData(stream) } catch (FileException& e) { file.close(); throw e; } } file.close(); } */ /** * read file. */ void FreeSurferSurfaceFile::readFileData(QFile& file, QTextStream& stream, QDataStream& dataStream, QDomElement& /* rootElement */) throw (FileException) { /* * Example of "orig" file: * * #!ascii version of rh.orig * 12389 24774 * 7.500000 -22.500000 43.500000 0 * 6.500000 -22.500000 43.500000 0 * 5.500000 -22.500000 43.500000 0 * ... * 0 1 5 0 * 6 5 1 0 * 0 61 62 0 * 0 62 1 0 * *------------------------------------------------------------------------ * Example of older patch file (probably before FreeSurfer version 3.0.5): * * #!ascii version of patch /sums2/vanessen/TSAO_TEMP/FALCO_TEMP/rh.orig * 6876 13408 * 0 * -9.240000 -26.459999 0.000000 * 1 * -9.590000 -26.680000 0.000000 * 2 * -10.400000 -26.750000 0.000000 * ... * 0 * 0 1 5 * 1 * 6 5 1 * 2 * 0 61 62 * *------------------------------------------------------------------------- * Example of new patch file (probably FreeSurface version 3.0.5 and later) * * #!ascii version of patch ./lh.orig. The 1st index is not a vertex number * 35660 70518 * 2502 vno=2501 * -48.213696 96.493965 0.000000 * 2503 vno=2502 * -48.014599 96.371674 0.000000 * 2504 vno=2503 * -47.598007 96.246620 0.000000 * ... * 5177 * 2501 2502 2506 * 5178 * 2501 2506 2505 * 5179 * 2501 3048 2502 * */ switch (getFileReadType()) { case FILE_FORMAT_ASCII: { // // First line is a comment // QString commentLine; readLine(filename, stream, commentLine); if (commentLine.left(3) != "#!a") { throw FileException(filename, " is not an ASCII Free Surfer file."); } patchAsciiFileFlag = (commentLine.indexOf("patch") != -1); setFileComment(commentLine); // // Next line is number of points and tiles // QString pointsTilesLine; readLine(filename, stream, pointsTilesLine); int numPoints = 0; int numTiles = 0; QTextStream(&pointsTilesLine) >> numPoints >> numTiles; if ((numPoints <= 0) || (numTiles <= 0)) { throw FileException(filename, "Number of nodes and tiles not found."); } // // Allocate memory // setNumberOfVerticesAndTriangles(numPoints, numTiles); // // Read in the points // if (patchAsciiFileFlag) { // // Read in the patch coordinate // int nodeNumber; float xyz[3]; for (int i = 0; i < numPoints; i++) { QString line; readLine(filename, stream, line); const int equalPos = line.indexOf('='); if (equalPos >= 0) { QString nodeString(line.mid(equalPos + 1)); QTextStream(&nodeString) >> nodeNumber; } else { QTextStream(&line) >> nodeNumber; } readLine(filename, stream, line); QTextStream(&line) >> xyz[0] >> xyz[1] >> xyz[2]; setVertexCoordinates(i, nodeNumber, xyz); } } else { // // Read a normal FreeSurfer surface file // float xyz[3], w; for (int i = 0; i < numPoints; i++) { stream >> xyz[0] >> xyz[1] >> xyz[2] >> w; setVertexCoordinates(i, i, xyz); } } if (patchAsciiFileFlag) { // // Read in patch tiles // for (int i = 0; i < numTiles; i++) { int tile; stream >> tile; int v[3]; stream >> v[0] >> v[1] >> v[2]; setTriangle(i, v); } } else { // // Read in normal surface tiles // for (int i = 0; i < numTiles; i++) { if (stream.atEnd()) { throw FileException(filename, "At end of file before done reading topology."); } int v[3], dummy; stream >> v[0] >> v[1] >> v[2] >> dummy; setTriangle(i, v); } } } break; case FILE_FORMAT_BINARY: { quint8 magic[3] = { 0, 0, 0 }; dataStream >> magic[0] >> magic[1] >> magic[2]; if (DebugControl::getDebugOn()) { std::cout << "magic " << (unsigned int)magic[0] << " " << (unsigned int)magic[1] << " " << (unsigned int)magic[2] << " " << std::endl; } if ((magic[0] == 0xff) && (magic[1] == 0xff) && (magic[2] == 0xfe)) { // // FreeSurfer Files are reportedly big endian // dataStream.setByteOrder(QDataStream::BigEndian); // // Comment ends with two line feeds '\n' (0x0A) // QString commentLine; char prevChar = 0; while (dataStream.atEnd() == false) { qint8 c; dataStream >> c; if ((c == '\n') && (prevChar == '\n')) { commentLine.chop(1); // remove last '\n' break; } commentLine += (char)c; prevChar = c; } if (dataStream.atEnd()) { throw FileException(filename, "Unexpectedly encountered end of file while reading comment."); } // // get vertex and face counts // int numPoints, numTiles; dataStream >> numPoints; dataStream >> numTiles; if (DebugControl::getDebugOn()) { std::cout << "Vertices/Faces/comment: " << numPoints << " " << numTiles << " " << commentLine.toAscii().constData() << std::endl; } if ((numPoints < 0) || (numTiles < 0)) { throw FileException(filename, "Vertex or Face count less than zero.\n" "File should be in big endian order."); } // // Allocate memory // setNumberOfVerticesAndTriangles(numPoints, numTiles); // // Read in vertices // float xyz[3]; for (int i = 0; i < numPoints; i++) { dataStream >> xyz[0] >> xyz[1] >> xyz[2]; setVertexCoordinates(i, i, xyz); } // // Read in normal surface tiles // for (int i = 0; i < numTiles; i++) { if (stream.atEnd()) { throw FileException(filename, "At end of file before done reading topology."); } int v[3]; dataStream >> v[0] >> v[1] >> v[2]; setTriangle(i, v); } } // // Could be a binary patch format // else if (filename.contains("patch")) { // // We're reading a patch file // patchBinaryFileFlag = true; // // FreeSurfer Files are reportedly big endian // dataStream.setByteOrder(QDataStream::BigEndian); // // Reset to 4th byte // if (file.seek(4) == false) { throw FileException("Seeking to 4th byte of file failed."); } // // Get number of points // qint32 numPoints; dataStream >> numPoints; if (DebugControl::getDebugOn()) { std::cout << "FreeSurface patch point count: " << numPoints << std::endl; } if ((numPoints < 0) || (numPoints > 10000000)) { throw FileException(filename, "Vertex count=" + QString::number(numPoints) + " invalid.\n" "File is not in big endian order or format has changed."); } // // Allocate memory // setNumberOfVerticesAndTriangles(numPoints, 0); // // Read in vertices // for (int i = 0; i < numPoints; i++) { qint32 vertexNumber; float x, y, z; dataStream >> vertexNumber >> x >> y >> z; const float xyz[3] = { x, y, z }; // // Vertex indices are negative if part of border ??? // vertexNumber = std::abs(vertexNumber); vertexNumber--; if (vertexNumber < 0) { throw FileException(filename, "Free Surfer vertex number less than zero " + QString::number(vertexNumber)); } setVertexCoordinates(i, vertexNumber, xyz); } } // // Could be a binary patch format // else if (filename.contains("patchOLD")) { // // We're reading a patch file // patchBinaryFileFlag = true; // // FreeSurfer Files are reportedly big endian // dataStream.setByteOrder(QDataStream::BigEndian); // // Reset to beginning of file // if (file.seek(0) == false) { throw FileException("Seeking to beginning of file failed."); } // // Get number of points // qint32 numPoints; dataStream >> numPoints; if (DebugControl::getDebugOn()) { std::cout << "FreeSurface patch point count: " << numPoints << std::endl; } if ((numPoints < 0) || (numPoints > 10000000)) { throw FileException(filename, "Vertex count=" + QString::number(numPoints) + " invalid.\n" "File is not in big endian order or format has changed."); } // // Allocate memory // setNumberOfVerticesAndTriangles(numPoints, 0); // // Read in vertices // for (int i = 0; i < numPoints; i++) { qint32 vertexNumber; qint16 x, y, z; dataStream >> vertexNumber >> x >> y >> z; const float xyz[3] = { x, y, z }; // // Vertex indices are negative if part of border ??? // vertexNumber = std::abs(vertexNumber); vertexNumber--; if (vertexNumber < 0) { throw FileException(filename, "Free Surfer vertex number less than zero " + QString::number(vertexNumber)); } setVertexCoordinates(i, vertexNumber, xyz); } } else { QString str("FreeSurfer File, invalid magic number (hex): "); str += QString::number(magic[0], 16); str += " "; str += QString::number(magic[1], 16); str += " "; str += QString::number(magic[2], 16); throw FileException(filename, str); } } break; case FILE_FORMAT_XML: throw FileException(filename, "\"XML\" file format not supported."); break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "\"XML-Base64 Encoding\" file format not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "\"XML-Base64 GZIP Encoding\" file format not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "\"XML-External Binary Encoding\" file format not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "\"Other\" file format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Comma Separated Value File Format not supported."); break; } } /** * write file. */ void FreeSurferSurfaceFile::writeFileData(QTextStream& stream, QDataStream&, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException) { stream << "#!ascii version written be Caret\n"; const int numVertices = getNumberOfVertices(); const int numTriangles = getNumberOfTriangles(); stream << numVertices << " " << numTriangles << "\n"; for (int i = 0; i < numVertices; i++) { const Vertex& v = vertices[i]; stream << v.xyz[0] << " " << v.xyz[1] << " " << v.xyz[2] << " 0\n"; } for (int i = 0; i < numTriangles; i++) { const int i3 = i * 3; stream << triangles[i3] << " " << triangles[i3+1] << " " << triangles[i3+2] << " 0\n"; } } caret-5.6.4~dfsg.1.orig/caret_files/FreeSurferLabelFile.h0000664000175000017500000000567111572067322023033 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __FREE_SURFER_LABEL_FILE_H__ #define __FREE_SURFER_LABEL_FILE_H__ #include "AbstractFile.h" /// class for reading/writing free surfer label file class FreeSurferLabelFile : public AbstractFile { public: /// Constructor FreeSurferLabelFile(); /// Destructor ~FreeSurferLabelFile(); /// clear the file void clear(); /// returns true if the file is isEmpty (contains no data) bool empty() const; /// get the number of label items int getNumberOfLabelItems() const; /// set number of vertices void setNumberOfLabelItems(const int numLabelItems); /// get label value void getLabelItem(const int index, int& vertexNumber, float xyz[3]) const; /// set label value void setLabelItem(const int index, const int vertexNumber, const float xyz[3]); /// add label value void addLabelItem(const int vertexNumber, const float xyz[3]); private: /// read file void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException); /// write file void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException); /// class storage of curvature class LabelData { public: LabelData() { xyz[0] = 0.0; xyz[1] = 0.0; xyz[2] = 0.0; vertexNumber = 0; } LabelData(const int vertexNumberIn, const float xyzIn[3]) { vertexNumber = vertexNumberIn; xyz[0] = xyzIn[0]; xyz[1] = xyzIn[1]; xyz[2] = xyzIn[2]; } float xyz[3]; int vertexNumber; }; /// the curvature std::vector labelData; }; #endif // __FREE_SURFER_LABEL_FILE_H__ caret-5.6.4~dfsg.1.orig/caret_files/FreeSurferLabelFile.cxx0000664000175000017500000000752011572067322023401 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "FreeSurferLabelFile.h" #include "SpecFile.h" /** * Constructor. */ FreeSurferLabelFile::FreeSurferLabelFile() : AbstractFile("Free Surfer Label File", SpecFile::getFreeSurferLabelFileExtension(), false) { } /** * Destructor. */ FreeSurferLabelFile::~FreeSurferLabelFile() { } /** * clear the file. */ void FreeSurferLabelFile::clear() { clearAbstractFile(); labelData.clear(); } /** * returns true if the file is isEmpty (contains no data). */ bool FreeSurferLabelFile::empty() const { return (getNumberOfLabelItems() == 0); } /** * get the number of vertices. */ int FreeSurferLabelFile::getNumberOfLabelItems() const { return labelData.size(); } /** * set number of vertices. */ void FreeSurferLabelFile::setNumberOfLabelItems(const int numLabelItems) { labelData.resize(numLabelItems); } /** * get label item. */ void FreeSurferLabelFile::getLabelItem(const int index, int& vertexNumber, float xyz[3]) const { xyz[0] = labelData[index].xyz[0]; xyz[1] = labelData[index].xyz[1]; xyz[2] = labelData[index].xyz[2]; vertexNumber = labelData[index].vertexNumber; } /** * set label item. */ void FreeSurferLabelFile::setLabelItem(const int index, const int vertexNumber, const float xyz[3]) { labelData[index].xyz[0] = xyz[0]; labelData[index].xyz[1] = xyz[1]; labelData[index].xyz[2] = xyz[2]; labelData[index].vertexNumber = vertexNumber; } /** * set label item. */ void FreeSurferLabelFile::addLabelItem(const int vertexNumber, const float xyz[3]) { LabelData ld(vertexNumber, xyz); labelData.push_back(ld); } /** * read file. */ void FreeSurferLabelFile::readFileData(QFile& /*file*/, QTextStream& stream, QDataStream&, QDomElement& /* rootElement */) throw (FileException) { // // Read comment line // QString commentLine; readLine(stream, commentLine); // // read number of items // QString itemsLine; readLine(stream, itemsLine); const int numItems = itemsLine.toInt(); // // Read until end of file // int nodeNum; float xyz[3], w; for (int i = 0; i < numItems; i++) { stream >> nodeNum >> xyz[0] >> xyz[1] >> xyz[2] >> w; addLabelItem(nodeNum, xyz); } } /** * write file. */ void FreeSurferLabelFile::writeFileData(QTextStream& stream, QDataStream&, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException) { // // Write comment // stream << "#!ascii label, written by caret\n"; // // Write the number of items // const int num = getNumberOfLabelItems(); stream << num << "\n"; // // Write the data // for (int i = 0; i < num; i++) { const LabelData& ld = labelData[i]; stream << ld.vertexNumber << " " << ld.xyz[0] << " " << ld.xyz[1] << " " << ld.xyz[2] << " " << 0.0 << "\n"; } } caret-5.6.4~dfsg.1.orig/caret_files/FreeSurferFunctionalFile.h0000664000175000017500000000567611572067322024123 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __FREE_SURFER_FUNCTIONAL_FILE_H__ #define __FREE_SURFER_FUNCTIONAL_FILE_H__ #include "AbstractFile.h" /// class for reading/writing free surfer functional file class FreeSurferFunctionalFile : public AbstractFile { public: /// Constructor FreeSurferFunctionalFile(); /// Destructor ~FreeSurferFunctionalFile(); /// clear the file void clear(); /// returns true if the file is isEmpty (contains no data) bool empty() const; /// get the number of vertices int getNumberOfFunctionalItems() const; /// set number of vertices void setNumberOfFunctionalItems(const int numVertices); /// get functional value void getFunctionalData(const int index, int& vertexNumber, float& funcValue) const; /// add functional value void addFunctionalData(const int vertexNumber, const float funcValue); /// set functional value void setFunctionalData(const int index, const int vertexNumber, const float funcValue); private: /// read file void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException); /// write file void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException); /// class for storing functional items class FuncData { public: int vertexNumber; float funcValue; FuncData() { vertexNumber = 0; funcValue = 0.0; } FuncData(const int vertexNumberIn, const float funcValueIn) { vertexNumber = vertexNumberIn; funcValue = funcValueIn; } }; /// the functional values std::vector functionalData; }; #endif // __FREE_SURFER_FUNCTIONAL_FILE_H__ caret-5.6.4~dfsg.1.orig/caret_files/FreeSurferFunctionalFile.cxx0000664000175000017500000001470011572067322024462 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "DebugControl.h" #include "FreeSurferFunctionalFile.h" #include "SpecFile.h" /** * Constructor. * Format Info: http://wideman-one.com/gw/brain/fs/surfacefileformats.htm */ FreeSurferFunctionalFile::FreeSurferFunctionalFile() : AbstractFile("Free Surfer Functional File", SpecFile::getFreeSurferAsciiFunctionalFileExtension(), false, AbstractFile::FILE_FORMAT_ASCII, AbstractFile::FILE_IO_READ_AND_WRITE, AbstractFile::FILE_IO_READ_ONLY) { } /** * Destructor. */ FreeSurferFunctionalFile::~FreeSurferFunctionalFile() { } /** * clear the file. */ void FreeSurferFunctionalFile::clear() { clearAbstractFile(); functionalData.clear(); } /** * returns true if the file is isEmpty (contains no data). */ bool FreeSurferFunctionalFile::empty() const { return (getNumberOfFunctionalItems() == 0); } /** * get the number of vertices. */ int FreeSurferFunctionalFile::getNumberOfFunctionalItems() const { return functionalData.size(); } /** * set number of vertices. */ void FreeSurferFunctionalFile::setNumberOfFunctionalItems(const int numItems) { functionalData.resize(numItems); } /** * get functional value value. */ void FreeSurferFunctionalFile::getFunctionalData(const int index, int& vertexNumber, float& funcValue) const { vertexNumber = functionalData[index].vertexNumber; funcValue = functionalData[index].funcValue; } /** * set curvature value. */ void FreeSurferFunctionalFile::setFunctionalData(const int index, const int vertexNumber, const float funcValue) { functionalData[index].vertexNumber = vertexNumber; functionalData[index].funcValue = funcValue; } /** * add functional value. */ void FreeSurferFunctionalFile::addFunctionalData(const int vertexNumber, const float funcValue) { FuncData fd(vertexNumber, funcValue); functionalData.push_back(fd); } /** * read file. */ void FreeSurferFunctionalFile::readFileData(QFile& /*file*/, QTextStream& stream, QDataStream& dataStream, QDomElement& /* rootElement */) throw (FileException) { switch (getFileReadType()) { case FILE_FORMAT_ASCII: { // // Read in the latency line // QString latencyLine; readLine(stream, latencyLine); // // Read number of points in file // QString numPointsInFileLine; readLine(stream, numPointsInFileLine); const int numPoints = numPointsInFileLine.toInt(); setNumberOfFunctionalItems(numPoints); // // Read in functional data // int nodeNumber; float value; for (int i = 0; i < numPoints; i++) { stream >> nodeNumber >> value; setFunctionalData(i, nodeNumber, value); } } break; case FILE_FORMAT_BINARY: { // // ignore latency // qint16 latency; dataStream >> latency; // // Read number of vertex-value pairs // const int numVertexValuePairs = readThreeByteInteger(dataStream); setNumberOfFunctionalItems(numVertexValuePairs); if (DebugControl::getDebugOn()) { std::cout << "FreeSurfer binary wieght file number of vertex-value pairs: " << numVertexValuePairs << std::endl; } // // Read in the functional data // for (int i = 0; i < numVertexValuePairs; i++) { const int vertex = readThreeByteInteger(dataStream); float f; dataStream >> f; setFunctionalData(i, vertex, f); } } break; case FILE_FORMAT_XML: throw FileException(filename, "\"XML\" file format not supported."); break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "\"XML-Base64 Encoding\" file format not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "\"XML-Base64 GZIP Encoding\" file format not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "\"XML-External Binary Encoding\" file format not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "\"Other\" file format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Reading Comma Separated Value File Format not supported."); break; } } /** * write file. */ void FreeSurferFunctionalFile::writeFileData(QTextStream& stream, QDataStream&, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException) { // // Write latency // stream << "0.0" << "\n"; // // Write number of vertices // const int num = getNumberOfFunctionalItems(); stream << num << "\n"; // // Write the functional data // for (int i = 0; i < num; i++) { const FuncData& fd = functionalData[i]; stream << fd.vertexNumber << " " << fd.funcValue << "\n"; } } caret-5.6.4~dfsg.1.orig/caret_files/FreeSurferCurvatureFile.h0000664000175000017500000000617611572067322023775 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __FREE_SURFER_CURVATURE_FILE_H__ #define __FREE_SURFER_CURVATURE_FILE_H__ #include "AbstractFile.h" /// class for reading/writing free surfer curvature file class FreeSurferCurvatureFile : public AbstractFile { public: /// Constructor FreeSurferCurvatureFile(); /// Destructor ~FreeSurferCurvatureFile(); /// clear the file void clear(); /// returns true if the file is isEmpty (contains no data) bool empty() const; /// get the number of vertices int getNumberOfVertices() const; /// set number of vertices void setNumberOfVertices(const int numVertices); /// get curvature value void getCurvature(const int vertexNumber, float xyz[3], float& curve) const; /// set curvature value void setCurvature(const int vertexNumber, const float xyz[3], const float curve); /// read the specified file //void readFile(const QString& filenameIn) throw (FileException); /// Write the current file's memory to the specified name //void writeFile(const QString& filenameIn) throw (FileException); private: /// read file void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException); /// write file void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException); /// class storage of curvature class Curvature { public: Curvature() { xyz[0] = 0.0; xyz[1] = 0.0; xyz[2] = 0.0; curve = 0.0; } Curvature(const float xyzIn[3], const float c) { xyz[0] = xyzIn[0]; xyz[1] = xyzIn[1]; xyz[2] = xyzIn[2]; curve = c; } float xyz[3]; float curve; }; /// the curvature std::vector curvature; }; #endif // __FREE_SURFER_CURVATURE_FILE_H__ caret-5.6.4~dfsg.1.orig/caret_files/FreeSurferCurvatureFile.cxx0000664000175000017500000001656611572067322024354 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "DebugControl.h" #include "FreeSurferCurvatureFile.h" #include "SpecFile.h" #include "StringUtilities.h" /** * Constructor. * Format Info: http://wideman-one.com/gw/brain/fs/surfacefileformats.htm */ FreeSurferCurvatureFile::FreeSurferCurvatureFile() : AbstractFile("Free Surfer Curvature File", SpecFile::getFreeSurferAsciiCurvatureFileExtension(), false) { } /** * Destructor. */ FreeSurferCurvatureFile::~FreeSurferCurvatureFile() { } /** * clear the file. */ void FreeSurferCurvatureFile::clear() { clearAbstractFile(); curvature.clear(); } /** * returns true if the file is isEmpty (contains no data). */ bool FreeSurferCurvatureFile::empty() const { return (getNumberOfVertices() == 0); } /** * get the number of vertices. */ int FreeSurferCurvatureFile::getNumberOfVertices() const { return curvature.size(); } /** * set number of vertices. */ void FreeSurferCurvatureFile::setNumberOfVertices(const int numVertices) { curvature.resize(numVertices); } /** * get curvature value. */ void FreeSurferCurvatureFile::getCurvature(const int vertexNumber, float xyz[3], float& curve) const { xyz[0] = curvature[vertexNumber].xyz[0]; xyz[1] = curvature[vertexNumber].xyz[1]; xyz[2] = curvature[vertexNumber].xyz[2]; curve = curvature[vertexNumber].curve; } /** * set curvature value. */ void FreeSurferCurvatureFile::setCurvature(const int vertexNumber, const float xyz[3], const float curve) { curvature[vertexNumber].xyz[0] = xyz[0]; curvature[vertexNumber].xyz[1] = xyz[1]; curvature[vertexNumber].xyz[2] = xyz[2]; curvature[vertexNumber].curve = curve; } /** * read the specified file. */ /* void FreeSurferCurvatureFile::readFile(const QString& filenameIn) throw (FileException) { } */ /** * Write the current file's memory to the specified name. */ /* void FreeSurferCurvatureFile::writeFile(const QString& filenameIn) throw (FileException) { } */ /** * read file. */ void FreeSurferCurvatureFile::readFileData(QFile& file, QTextStream& stream, QDataStream& dataStream, QDomElement& /* rootElement */) throw (FileException) { switch (getFileReadType()) { case FILE_FORMAT_ASCII: { float xyz[3], curv; QString line; std::vector tokens; while(stream.atEnd() == false) { readLineIntoTokens(filename, stream, line, tokens); xyz[0] = StringUtilities::toFloat(tokens[1]); xyz[1] = StringUtilities::toFloat(tokens[2]); xyz[2] = StringUtilities::toFloat(tokens[3]); curv = StringUtilities::toFloat(tokens[4]); if (tokens.size() >= 5) { Curvature c(xyz, curv); curvature.push_back(c); } else if (tokens.size() == 0) { break; } else { QString msg("Invalid line: "); msg.append(line); throw FileException(filename, msg); } } } break; case FILE_FORMAT_BINARY: { const int magic = readThreeByteInteger(dataStream); if (DebugControl::getDebugOn()) { std::cout << "FreeSurfer Binary Curvature File" << std::endl; std::cout << " magic: " << magic << std::endl; } if (magic == 16777215) { int vertexCount, faceCount, valuesPerVertex; dataStream >> vertexCount >> faceCount >> valuesPerVertex; if (DebugControl::getDebugOn()) { std::cout << " vertex count: " << vertexCount << std::endl; std::cout << " face count: " << faceCount << std::endl; std::cout << " values per vertex: " << valuesPerVertex << std::endl; } float xyz[3] = { 0.0, 0.0, 0.0 }; for (int i = 0; i < vertexCount; i++) { float f; dataStream >> f; Curvature c(xyz, f); curvature.push_back(c); } } else { file.seek(0); const int vertexCount = readThreeByteInteger(dataStream); const int faceCount = readThreeByteInteger(dataStream); if (DebugControl::getDebugOn()) { std::cout << " vertex count: " << vertexCount << std::endl; std::cout << " face count: " << faceCount << std::endl; } float xyz[3] = { 0.0, 0.0, 0.0 }; for (int i = 0; i < vertexCount; i++) { qint16 curv; dataStream >> curv; Curvature c(xyz, static_cast(curv) / 100.0); curvature.push_back(c); } } } break; case FILE_FORMAT_XML: throw FileException(filename, "\"XML\" file format not supported."); break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "\"XML-Base64 Encoding\" file format not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "\"XML-Base64 GZIP Encoding\" file format not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "\"XML-External Binary Encoding\" file format not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "\"Other\" file format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Comma Separated Value File Format not supported."); break; } // // Read until end of file // } /** * write file. */ void FreeSurferCurvatureFile::writeFileData(QTextStream& stream, QDataStream&, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException) { const int num = getNumberOfVertices(); for (int i = 0; i < num; i++) { const Curvature& c = curvature[i]; stream << i << " " << c.xyz[0] << " " << c.xyz[1] << " " << c.xyz[2] << " " << c.curve << "\n"; } } caret-5.6.4~dfsg.1.orig/caret_files/FociSearchFile.h0000664000175000017500000003131711572067322022025 0ustar michaelmichael #ifndef __FOCI_SEARCH_FILE_H__ #define __FOCI_SEARCH_FILE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "AbstractFile.h" class ColorFile; class FociProjectionFile; class FociSearch; class FociSearchSet; class StudyMetaDataFile; class XmlGenericWriter; /// class for saving foci searches class FociSearchFile : public AbstractFile { public: // constructor FociSearchFile(); // copy constructor FociSearchFile(const FociSearchFile& fs); // destructor ~FociSearchFile(); // assignment operator FociSearchFile& operator=(const FociSearchFile& fs); // append a file void append(const FociSearchFile& fsf); // add a default empty search void addDefaultSearch(); // clear method. void clear(); // clear foci searches void clearFociSearches(); // copy a search set to a new search set // returns positive number of new search set, else -1 if error int copySearchSetToNewSearchSet(const int copySearchSetNumber); // returns true if the file is isEmpty (contains no data) bool empty() const; /// get number of search sets int getNumberOfFociSearchSets() const { return fociSearchSets.size(); } /// get a search set FociSearchSet* getFociSearchSet(const int indx); /// get a search set (const method) const FociSearchSet* getFociSearchSet(const int indx) const; // delete a search set void deleteFociSearchSet(const int indx); // add a search set void addFociSearchSet(FociSearchSet* fs); // insert a foci search set void insertFociSearchSet(FociSearchSet* fs, const int afterIndex); /// write the file's memory in caret6 format to the specified name virtual QString writeFileInCaret6Format(const QString& filenameIn, Structure structure,const ColorFile* colorFileIn, const bool useCaret6ExtensionFlag) throw (FileException); protected: // copy helper void copyHelper(const FociSearchFile& fs); // Read the contents of the file (header has already been read) void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& rootElement) throw (FileException); // Write the file's data (header has already been written) void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& xmlDoc, QDomElement& rootElement) throw (FileException); /// the foci search sets std::vector fociSearchSets; // NOTE: If additional members are added, update "copyHelper()". }; /// class for a set of searches class FociSearchSet { public: /// search mode enum SEARCH_MODE { /// search all foci SEARCH_MODE_ALL_FOCI, /// search only those marked as searched SEARCH_MODE_DISPLAYED_FOCI }; // constructor FociSearchSet(); // copy constructor FociSearchSet(const FociSearchSet& fs); // destructor ~FociSearchSet(); // assignment operator FociSearchSet& operator=(const FociSearchSet& fs); // clear the search set void clear(); // set parent foci search file void setParentFociSearchFile(FociSearchFile* fsf); /// get number of searches int getNumberOfFociSearches() const { return fociSearches.size(); } /// get a search FociSearch* getFociSearch(const int indx) { return fociSearches[indx]; } /// get a search const method const FociSearch* getFociSearch(const int indx) const { return fociSearches[indx]; } // delete a search void deleteFociSearch(const int indx); // add a search void addFociSearch(FociSearch* fs); // insert a foci search void insertFociSearch(FociSearch* fs, const int afterIndex); /// get the name of the search QString getName() const { return name; } // set the name of the search void setName(const QString& s); // set the file's modified status void setModified(); // called to read from an XML structure void readXML(QDomNode& node) throw (FileException); // called to write to an XML structure void writeXML(QDomDocument& xmlDoc, QDomElement& parentElement); // called to write XML void writeXML(XmlGenericWriter& xmlWriter) const throw (FileException); protected: // copy helper void copyHelper(const FociSearchSet& fs); /// foci search file this search belongs to FociSearchFile* parentFociSearchFile; /// the foci searches std::vector fociSearches; /// name of search set QString name; // NOTE: If additional members are added, update "copyHelper()". /// tag for reading and writing XML static const QString tagFociSearchSet; /// tag for reading and writing XML static const QString tagFociSearchSetName; /// FociSearchFile is a friend friend class FociSearchFile; }; #ifdef __FOCI_SEARCH_FILE_MAIN__ const QString FociSearchSet::tagFociSearchSet = "FociSearchSet"; const QString FociSearchSet::tagFociSearchSetName = "Name"; #endif // __FOCI_SEARCH_FILE_MAIN__ /// class for a single foci search class FociSearch { public: /// logic for searching enum LOGIC { /// union LOGIC_UNION, /// intersection LOGIC_INTERSECTION }; // // If the order in the ATTRIBUTE enumerated type changes, // FociSearch::getAttributeTypesAndNames() must be updated. // /// attribute for searching enum ATTRIBUTE { /// all attributes ATTRIBUTE_ALL, // Must be first for BrainModelSurfaceFociSearch::applySearchToFocus /// focus area ATTRIBUTE_FOCUS_AREA, // IF MOVED update BrainModelSurfaceFociSearch::applySearchToFocus /// study authors ATTRIBUTE_STUDY_AUTHORS, /// study citation ATTRIBUTE_STUDY_CITATION, /// focus class ATTRIBUTE_FOCUS_CLASS, /// focus comment ATTRIBUTE_FOCUS_COMMENT, /// study comment ATTRIBUTE_STUDY_COMMENT, /// study data format ATTRIBUTE_STUDY_DATA_FORMAT, /// study data type ATTRIBUTE_STUDY_DATA_TYPE, /// focus geography ATTRIBUTE_FOCUS_GEOGRAPHY, /// study keywords ATTRIBUTE_STUDY_KEYWORDS, /// study Medical Subject Headings terms ATTRIBUTE_STUDY_MESH_TERMS, /// study name ATTRIBUTE_STUDY_NAME, /// focus ROI ATTRIBUTE_FOCUS_ROI, /// focus spatial search ATTRIBUTE_FOCUS_SPATIAL, /// study species ATTRIBUTE_STUDY_SPECIES, /// focus structure ATTRIBUTE_FOCUS_STRUCTURE, /// study stereotaxic space ATTRIBUTE_STUDY_STEREOTAXIC_SPACE, /// study table header ATTRIBUTE_STUDY_TABLE_HEADER, /// study table sub-header ATTRIBUTE_STUDY_TABLE_SUBHEADER, /// study title ATTRIBUTE_STUDY_TITLE, /// number of attributes (NOT USED IN SEARCH) ATTRIBUTE_NUMBER_OF }; /// matching for searches enum MATCHING { /// matching MATCHING_ANY_OF, /// matching MATCHING_ALL_OF, /// matching MATCHING_NONE_OF, /// matching MATCHING_EXACT_PHRASE }; // constructor FociSearch(); // copy constructor FociSearch(const FociSearch& fs); // destructor ~FociSearch(); // assignment operator FociSearch& operator=(const FociSearch& fs); // set parent foci search set void setParentFociSearchSet(FociSearchSet* fss); /// get the logic for the search LOGIC getLogic() const { return logic; } // set the logic for the search void setLogic(const LOGIC lg); // convert a logic type to name static QString convertLogicTypeToName(const LOGIC lg); // convert a logic name to type static LOGIC convertLogicNameToType(const QString& s); /// get the attribute ATTRIBUTE getAttribute() const { return attribute; } // set the attribute void setAttribute(const ATTRIBUTE a); // convert an attribute type to name static QString convertAttributeTypeToName(const ATTRIBUTE att); // convert an attribute name to type static ATTRIBUTE convertAttributeNameToType(const QString& s); /// get the matching MATCHING getMatching() const { return matching; } // set the matching void setMatching(const MATCHING m); // convert a matching type to name static QString convertMatchingTypeToName(const MATCHING m); // convert a matching name to type static MATCHING convertMatchingNameToType(const QString& s); /// get the search text QString getSearchText() const { return searchText; } /// set the search text void setSearchText(const QString& st); // get types and names for logic static void getLogicTypesAndNames(std::vector& typesOut, std::vector& namesOut); // get types and names for attributes static void getAttributeTypesAndNames(std::vector& typesOut, std::vector& namesOut); // get types and names for matching static void getMatchingTypesAndNames(std::vector& typesOut, std::vector& namesOut); // called to read from an XML structure void readXML(QDomNode& node) throw (FileException); // called to write to an XML structure void writeXML(QDomDocument& xmlDoc, QDomElement& parentElement); // called to write XML void writeXML(XmlGenericWriter& xmlWriter) const throw (FileException); protected: // copy helper void copyHelper(const FociSearch& fs); // set the file's modified status void setModified(); /// foci search file this search belongs to FociSearchSet* parentFociSearchSet; /// the search logic LOGIC logic; /// the attribute to search ATTRIBUTE attribute; /// the type of matching MATCHING matching; /// the text for search QString searchText; // NOTE: If additional members are added, update "copyHelper()". /// tag for reading and writing XML static const QString tagFociSearch; /// tag for reading and writing XML static const QString tagFociSearchLogic; /// tag for reading and writing XML static const QString tagFociSearchAttribute; /// tag for reading and writing XML static const QString tagFociSearchMatching; /// tag for reading and writing XML static const QString tagFociSearchText; friend class FociSearchSet; }; #endif // __FOCI_SEARCH_FILE_H__ #ifdef __FOCI_SEARCH_FILE_MAIN__ const QString FociSearch::tagFociSearch = "FociSearch"; const QString FociSearch::tagFociSearchLogic = "Logic"; const QString FociSearch::tagFociSearchAttribute = "Attribute"; const QString FociSearch::tagFociSearchMatching = "Matching"; const QString FociSearch::tagFociSearchText = "Text"; #endif // __FOCI_SEARCH_FILE_MAIN__ caret-5.6.4~dfsg.1.orig/caret_files/FociSearchFile.cxx0000664000175000017500000007774411572067322022416 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "FociProjectionFile.h" #define __FOCI_SEARCH_FILE_MAIN__ #include "FociSearchFile.h" #undef __FOCI_SEARCH_FILE_MAIN__ #include "MathUtilities.h" #include "SpecFile.h" #include "StudyMetaDataFile.h" #include "StudyMetaDataLinkSet.h" #include "XmlGenericWriter.h" /** * constructor. */ FociSearchFile::FociSearchFile() : AbstractFile("Foci Search File", SpecFile::getFociSearchFileExtension(), true, FILE_FORMAT_XML, FILE_IO_NONE, // ascii FILE_IO_NONE, // binary FILE_IO_READ_AND_WRITE, // xml FILE_IO_NONE, // xml base64 FILE_IO_NONE, // xml gzip base64 FILE_IO_NONE, // other FILE_IO_NONE) // csv { } /** * copy constructor. */ FociSearchFile::FociSearchFile(const FociSearchFile& fsf) : AbstractFile("Foci Search File", SpecFile::getFociSearchFileExtension(), true, FILE_FORMAT_XML, FILE_IO_NONE, // ascii FILE_IO_NONE, // binary FILE_IO_READ_AND_WRITE, // xml FILE_IO_NONE, // xml base64 FILE_IO_NONE, // xml gzip base64 FILE_IO_NONE, // other FILE_IO_NONE) // csv { copyHelper(fsf); } /** * assignment operator. */ FociSearchFile& FociSearchFile::operator=(const FociSearchFile& fsf) { if (&fsf != this) { AbstractFile::operator=(fsf); copyHelper(fsf); } return *this; } /** * copy helper. */ void FociSearchFile::copyHelper(const FociSearchFile& fsf) { setFileName(""); clear(); append(fsf); } /** * destructor. */ FociSearchFile::~FociSearchFile() { clear(); } /** * append a file. */ void FociSearchFile::append(const FociSearchFile& fsf) { const int num = fsf.getNumberOfFociSearchSets(); for (int i = 0; i < num; i++) { FociSearchSet* fss = new FociSearchSet(*fsf.getFociSearchSet(i)); addFociSearchSet(fss); } } /** * add a default empty search. */ void FociSearchFile::addDefaultSearch() { if (getNumberOfFociSearchSets() <= 0) { // // Add a search set with one search // //FociSearch* fs = new FociSearch; FociSearchSet* fss = new FociSearchSet; //fss->addFociSearch(fs); addFociSearchSet(fss); clearModified(); } } /** * copy a search set to a new search set * returns positive number of new search set, else -1 if error. */ int FociSearchFile::copySearchSetToNewSearchSet(const int copySearchSetNumber) { const FociSearchSet* copySearchSet = getFociSearchSet(copySearchSetNumber); if (copySearchSet != NULL) { FociSearchSet* fss = new FociSearchSet(*copySearchSet); fss->setName("Copy of " + fss->getName()); addFociSearchSet(fss); const int indx = getNumberOfFociSearchSets() - 1; return indx; } return -1; } /** * get a search set. */ FociSearchSet* FociSearchFile::getFociSearchSet(const int indx) { if ((indx >= 0) && (indx < getNumberOfFociSearchSets())) { return fociSearchSets[indx]; } return NULL; } /** * get a search set (const method). */ const FociSearchSet* FociSearchFile::getFociSearchSet(const int indx) const { if ((indx >= 0) && (indx < getNumberOfFociSearchSets())) { return fociSearchSets[indx]; } return NULL; } /** * call AbstractFile::clearAbstractFile() from its clear method. */ void FociSearchFile::clear() { AbstractFile::clearAbstractFile(); clearFociSearches(); setModified(); } /** * clear foci searches. */ void FociSearchFile::clearFociSearches() { const int num = getNumberOfFociSearchSets(); for (int i = 0; i < num; i++) { delete fociSearchSets[i]; fociSearchSets[i] = NULL; } fociSearchSets.clear(); setModified(); } /** * returns true if the file is isEmpty (contains no data). */ bool FociSearchFile::empty() const { return (getNumberOfFociSearchSets() == 0); } /** * delete a search set. */ void FociSearchFile::deleteFociSearchSet(const int indx) { if ((indx >= 0) && (indx < getNumberOfFociSearchSets())) { fociSearchSets.erase(fociSearchSets.begin() + indx); setModified(); } } /** * add a search set. */ void FociSearchFile::addFociSearchSet(FociSearchSet* fss) { fss->setParentFociSearchFile(this); fociSearchSets.push_back(fss); setModified(); } /** * insert a foci search set. */ void FociSearchFile::insertFociSearchSet(FociSearchSet* fss, const int afterIndex) { // // Set parent // fss->setParentFociSearchFile(this); // // No existing searchers? // if (getNumberOfFociSearchSets() <= 0) { fociSearchSets.push_back(fss); } else { // // Copy searches // std::vector copyOfFociSearchSets = fociSearchSets; fociSearchSets.clear(); const int num = static_cast(copyOfFociSearchSets.size()); // // Insert new search set in proper location // for (int i = 0; i < num; i++) { if ((i == 0) && (afterIndex < 0)) { fociSearchSets.push_back(fss); } fociSearchSets.push_back(copyOfFociSearchSets[i]); if (afterIndex == i) { fociSearchSets.push_back(fss); } } if (afterIndex >= num) { fociSearchSets.push_back(fss); } } setModified(); } /** * Read the contents of the file (header has already been read). */ void FociSearchFile::readFileData(QFile& /*file*/, QTextStream& /*stream*/, QDataStream& /*binStream*/, QDomElement& rootElement) throw (FileException) { // // Should reading data be skipped ? // if (getReadMetaDataOnlyFlag()) { return; } switch (getFileReadType()) { case FILE_FORMAT_ASCII: throw FileException(filename, "Reading in Ascii format not supported."); break; case FILE_FORMAT_BINARY: throw FileException(filename, "Reading in Binary format not supported."); break; case FILE_FORMAT_XML: { clearFociSearches(); QDomNode node = rootElement.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { // // Is this a "FociSearchSet" element // if (elem.tagName() == FociSearchSet::tagFociSearchSet) { FociSearchSet* fss = new FociSearchSet; fss->readXML(node); addFociSearchSet(fss); } else if ((elem.tagName() == xmlHeaderOldTagName) || (elem.tagName() == xmlHeaderTagName)) { // ignore, read by AbstractFile::readFile() } else { std::cout << "WARNING: unrecognized FociSearchFile element: " << elem.tagName().toAscii().constData() << std::endl; } } node = node.nextSibling(); } } break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "Reading XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "Reading XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Reading XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Reading in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Reading in CSV format not supported."); break; } } /** * Write the file's data (header has already been written). */ void FociSearchFile::writeFileData(QTextStream& /*stream*/, QDataStream& /*binStream*/, QDomDocument& xmlDoc, QDomElement& rootElement) throw (FileException) { switch (getFileWriteType()) { case FILE_FORMAT_ASCII: throw FileException(filename, "Writing in Ascii format not supported."); break; case FILE_FORMAT_BINARY: throw FileException(filename, "Writing in Binary format not supported."); break; case FILE_FORMAT_XML: { // // Write the search sets // const int numSearchSets = getNumberOfFociSearchSets(); for (int i = 0; i < numSearchSets; i++) { FociSearchSet* fss = getFociSearchSet(i); fss->writeXML(xmlDoc, rootElement); } } break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "Writing XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "Writing XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Writing XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Writing in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Writing in CSV format not supported."); break; } } /** * Write the file's memory in caret6 format to the specified name. */ QString FociSearchFile::writeFileInCaret6Format(const QString& filenameIn, Structure structure,const ColorFile* colorFileIn, const bool useCaret6ExtensionFlag) throw (FileException) { const int numSearchSets = getNumberOfFociSearchSets(); if (numSearchSets <= 0) { throw FileException("Contains no foci searches"); } QFile file(filenameIn); if (AbstractFile::getOverwriteExistingFilesAllowed() == false) { if (file.exists()) { throw FileException("file exists and overwrite is prohibited."); } } if (file.open(QFile::WriteOnly) == false) { throw FileException("Unable to open for writing"); } QTextStream stream(&file); XmlGenericWriter xmlWriter(stream); xmlWriter.writeStartDocument(); XmlGenericWriterAttributes attributes; attributes.addAttribute("CaretFileType", "FociSearch"); attributes.addAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); attributes.addAttribute("xsi:noNamespaceSchemaLocation", "http://brainvis.wustl.edu/caret6/xml_schemas/FociSearchFileSchema.xsd"); attributes.addAttribute("Version", "6.0"); xmlWriter.writeStartElement("CaretDataFile", attributes); this->writeHeaderXMLWriter(xmlWriter); for (int i = 0; i < numSearchSets; i++) { FociSearchSet* fss = getFociSearchSet(i); fss->writeXML(xmlWriter); } xmlWriter.writeEndElement(); xmlWriter.writeEndDocument(); file.close(); return filenameIn; } //============================================================================ /** * constructor. */ FociSearchSet::FociSearchSet() { parentFociSearchFile = NULL; name = "Name of Search"; FociSearch* fs = new FociSearch; fs->setLogic(FociSearch::LOGIC_INTERSECTION); addFociSearch(fs); } /** * copy constructor. */ FociSearchSet::FociSearchSet(const FociSearchSet& fss) { copyHelper(fss); } /** * assignment operator. */ FociSearchSet& FociSearchSet::operator=(const FociSearchSet& fss) { if (&fss != this) { copyHelper(fss); } return *this; } /** * copy helper. */ void FociSearchSet::copyHelper(const FociSearchSet& fs) { parentFociSearchFile = NULL; clear(); const int num = fs.getNumberOfFociSearches(); for (int i = 0; i < num; i++) { addFociSearch(new FociSearch(*fs.getFociSearch(i))); } name = fs.name; } /** * destructor. */ FociSearchSet::~FociSearchSet() { clear(); } /** * clear the search set. */ void FociSearchSet::clear() { const int num = getNumberOfFociSearches(); for (int i = 0; i < num; i++) { delete fociSearches[i]; fociSearches[i] = NULL; } fociSearches.clear(); setModified(); } /** * set parent foci search file. */ void FociSearchSet::setParentFociSearchFile(FociSearchFile* fsf) { parentFociSearchFile = fsf; } /** * delete a search. */ void FociSearchSet::deleteFociSearch(const int indx) { if ((indx >= 0) && (indx < getNumberOfFociSearches())) { fociSearches.erase(fociSearches.begin() + indx); setModified(); } } /** * add a search. */ void FociSearchSet::addFociSearch(FociSearch* fs) { fs->setParentFociSearchSet(this); fociSearches.push_back(fs); setModified(); } /** * insert a foci search. */ void FociSearchSet::insertFociSearch(FociSearch* fs, const int afterIndex) { // // Set parent // fs->setParentFociSearchSet(this); // // No existing searchers? // if (getNumberOfFociSearches() <= 0) { fociSearches.push_back(fs); } else { // // Copy searches // std::vector copyOfFociSearches = fociSearches; fociSearches.clear(); const int num = static_cast(copyOfFociSearches.size()); // // Insert new search in proper location // for (int i = 0; i < num; i++) { if ((i == 0) && (afterIndex < 0)) { fociSearches.push_back(fs); } fociSearches.push_back(copyOfFociSearches[i]); if (afterIndex == i) { fociSearches.push_back(fs); } } } setModified(); } /** * set the name of the search. */ void FociSearchSet::setName(const QString& s) { if (name != s) { name = s; setModified(); } } /** * set the file's modified status. */ void FociSearchSet::setModified() { if (parentFociSearchFile != NULL) { parentFociSearchFile->setModified(); } } /** * called to read from an XML structure. */ void FociSearchSet::readXML(QDomNode& nodeIn) throw (FileException) { clear(); if (nodeIn.isNull()) { return; } QDomElement elem = nodeIn.toElement(); if (elem.isNull()) { return; } if (elem.tagName() != tagFociSearchSet) { QString msg("Incorrect element type passed to FociSearchSet::readXML() "); msg.append(elem.tagName()); throw FileException("", msg); } QDomNode node = nodeIn.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (elem.tagName() == tagFociSearchSetName) { name = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == FociSearch::tagFociSearch) { FociSearch* fs = new FociSearch; fs->readXML(node); addFociSearch(fs); } else { std::cout << "WARNING: unrecognized FociSearchSet element: " << elem.tagName().toAscii().constData() << std::endl; } } node = node.nextSibling(); } } /** * called to write to an XML structure. */ void FociSearchSet::writeXML(QDomDocument& xmlDoc, QDomElement& parentElement) { // // Create the element for this class instance's data // QDomElement searchSetElement = xmlDoc.createElement(tagFociSearchSet); // // Name of search // AbstractFile::addXmlTextElement(xmlDoc, searchSetElement, tagFociSearchSetName, name); // // Write the searches // const int numSearches = getNumberOfFociSearches(); for (int i = 0; i < numSearches; i++) { FociSearch* fs = getFociSearch(i); fs->writeXML(xmlDoc, searchSetElement); } // // Add class instance's data to the parent // parentElement.appendChild(searchSetElement); } /** * called to write XML. */ void FociSearchSet::writeXML(XmlGenericWriter& xmlWriter) const throw (FileException) { xmlWriter.writeStartElement(tagFociSearchSet); xmlWriter.writeElementCData(tagFociSearchSetName, name); const int numSearches = getNumberOfFociSearches(); for (int i = 0; i < numSearches; i++) { const FociSearch* fs = getFociSearch(i); fs->writeXML(xmlWriter); } xmlWriter.writeEndElement(); } //============================================================================ /** * constructor. */ FociSearch::FociSearch() { parentFociSearchSet = NULL; logic = LOGIC_UNION; attribute = ATTRIBUTE_ALL; matching = MATCHING_ANY_OF; searchText = ""; } /** * copy constructor. */ FociSearch::FociSearch(const FociSearch& fs) { copyHelper(fs); } /** * assignment operator. */ FociSearch& FociSearch::operator=(const FociSearch& fs) { if (&fs != this) { copyHelper(fs); } return *this; } /** * copy helper. */ void FociSearch::copyHelper(const FociSearch& fs) { parentFociSearchSet = NULL; logic = fs.logic; attribute = fs.attribute; matching = fs.matching; searchText = fs.searchText; } /** * destructor. */ FociSearch::~FociSearch() { } /** * set parent foci search set. */ void FociSearch::setParentFociSearchSet(FociSearchSet* fss) { parentFociSearchSet = fss; } /** * set the file's modified status. */ void FociSearch::setModified() { if (parentFociSearchSet != NULL) { parentFociSearchSet->setModified(); } } /** * set the logic for the search. */ void FociSearch::setLogic(const LOGIC lg) { if (logic != lg) { logic = lg; setModified(); } } /** * set the attribute. */ void FociSearch::setAttribute(const ATTRIBUTE a) { if (attribute != a) { attribute = a; setModified(); } } /** * set the matching. */ void FociSearch::setMatching(const MATCHING m) { if (matching != m) { matching = m; setModified(); } } /** * set the search text. */ void FociSearch::setSearchText(const QString& st) { if (searchText != st) { searchText = st; setModified(); } } /** * called to read from an XML structure. */ void FociSearch::readXML(QDomNode& nodeIn) throw (FileException) { if (nodeIn.isNull()) { return; } QDomElement elem = nodeIn.toElement(); if (elem.isNull()) { return; } if (elem.tagName() != tagFociSearch) { QString msg("Incorrect element type passed to FociSearch::readXML() "); msg.append(elem.tagName()); throw FileException("", msg); } QDomNode node = nodeIn.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (elem.tagName() == tagFociSearchLogic) { logic = convertLogicNameToType( AbstractFile::getXmlElementFirstChildAsString(elem)); } else if (elem.tagName() == tagFociSearchAttribute) { attribute = convertAttributeNameToType( AbstractFile::getXmlElementFirstChildAsString(elem)); } else if (elem.tagName() == tagFociSearchMatching) { matching = convertMatchingNameToType( AbstractFile::getXmlElementFirstChildAsString(elem)); } else if (elem.tagName() == tagFociSearchText) { searchText = AbstractFile::getXmlElementFirstChildAsString(elem); } else { std::cout << "WARNING: unrecognized FociSearch element: " << elem.tagName().toAscii().constData() << std::endl; } } node = node.nextSibling(); } } /** * called to write to an XML structure. */ void FociSearch::writeXML(QDomDocument& xmlDoc, QDomElement& parentElement) { // // Create the element for this class instance's data // QDomElement searchElement = xmlDoc.createElement(tagFociSearch); // // Search attributes // AbstractFile::addXmlTextElement(xmlDoc, searchElement, tagFociSearchLogic, convertLogicTypeToName(logic)); AbstractFile::addXmlTextElement(xmlDoc, searchElement, tagFociSearchAttribute, convertAttributeTypeToName(attribute)); AbstractFile::addXmlTextElement(xmlDoc, searchElement, tagFociSearchMatching, convertMatchingTypeToName(matching)); AbstractFile::addXmlTextElement(xmlDoc, searchElement, tagFociSearchText, searchText); // // Add class instance's data to the parent // parentElement.appendChild(searchElement); } /** * called to write XML. */ void FociSearch::writeXML(XmlGenericWriter& xmlWriter) const throw (FileException) { xmlWriter.writeStartElement(tagFociSearch); xmlWriter.writeElementCData(tagFociSearchLogic, convertLogicTypeToName(logic)); xmlWriter.writeElementCData(tagFociSearchAttribute, convertAttributeTypeToName(attribute)); xmlWriter.writeElementCData(tagFociSearchMatching, convertMatchingTypeToName(matching)); xmlWriter.writeElementCData(tagFociSearchText, searchText); xmlWriter.writeEndElement(); } /** * get types and names for logic. */ void FociSearch::getLogicTypesAndNames(std::vector& typesOut, std::vector& namesOut) { typesOut.clear(); namesOut.clear(); typesOut.push_back(LOGIC_UNION); namesOut.push_back(convertLogicTypeToName(LOGIC_UNION)); //"Union (OR)"); typesOut.push_back(LOGIC_INTERSECTION); namesOut.push_back(convertLogicTypeToName(LOGIC_INTERSECTION)); //"Intersection (AND)"); } /** * convert a logic type to name. */ QString FociSearch::convertLogicTypeToName(const LOGIC lg) { QString s; switch (lg) { case LOGIC_UNION: s = "Union"; break; case LOGIC_INTERSECTION: s = "Intersection"; break; } return s; } /** * convert a logic name to type. */ FociSearch::LOGIC FociSearch::convertLogicNameToType(const QString& s) { LOGIC lg = LOGIC_UNION; if (s == "Union") { lg = LOGIC_UNION; } else if (s == "Intersection") { lg = LOGIC_INTERSECTION; } return lg; } /** * get types and names for attributes. */ void FociSearch::getAttributeTypesAndNames(std::vector& typesOut, std::vector& namesOut) { typesOut.clear(); namesOut.clear(); for (int i = 0; i < ATTRIBUTE_NUMBER_OF; i++) { const ATTRIBUTE attr = static_cast(i); typesOut.push_back(attr); namesOut.push_back(convertAttributeTypeToName(attr)); } /* // // NOTE: These MUST be in the same order as the ATTRIBUTE // enumerated type. // typesOut.push_back(ATTRIBUTE_ALL); namesOut.push_back(convertAttributeTypeToName(ATTRIBUTE_ALL)); typesOut.push_back(ATTRIBUTE_FOCUS_AREA); namesOut.push_back(convertAttributeTypeToName(ATTRIBUTE_FOCUS_AREA)); typesOut.push_back(ATTRIBUTE_STUDY_AUTHORS); namesOut.push_back(convertAttributeTypeToName(ATTRIBUTE_STUDY_AUTHORS)); typesOut.push_back(ATTRIBUTE_STUDY_CITATION); namesOut.push_back(convertAttributeTypeToName(ATTRIBUTE_STUDY_CITATION)); typesOut.push_back(ATTRIBUTE_FOCUS_CLASS); namesOut.push_back(convertAttributeTypeToName(ATTRIBUTE_FOCUS_CLASS)); typesOut.push_back(ATTRIBUTE_FOCUS_COMMENT); namesOut.push_back(convertAttributeTypeToName(ATTRIBUTE_FOCUS_COMMENT)); typesOut.push_back(ATTRIBUTE_STUDY_COMMENT); namesOut.push_back(convertAttributeTypeToName(ATTRIBUTE_STUDY_COMMENT)); typesOut.push_back(ATTRIBUTE_STUDY_DATA_FORMAT); namesOut.push_back(convertAttributeTypeToName(ATTRIBUTE_STUDY_DATA_FORMAT)); typesOut.push_back(ATTRIBUTE_STUDY_DATA_TYPE); namesOut.push_back(convertAttributeTypeToName(ATTRIBUTE_STUDY_DATA_TYPE)); typesOut.push_back(ATTRIBUTE_FOCUS_GEOGRAPHY); namesOut.push_back(convertAttributeTypeToName(ATTRIBUTE_FOCUS_GEOGRAPHY)); typesOut.push_back(ATTRIBUTE_FOCUS_ROI); namesOut.push_back(convertAttributeTypeToName(ATTRIBUTE_FOCUS_ROI)); typesOut.push_back(ATTRIBUTE_STUDY_KEYWORDS); namesOut.push_back(convertAttributeTypeToName(ATTRIBUTE_STUDY_KEYWORDS)); typesOut.push_back(ATTRIBUTE_STUDY_MESH_TERMS); namesOut.push_back(convertAttributeTypeToName(ATTRIBUTE_STUDY_MESH_TERMS)); typesOut.push_back(ATTRIBUTE_STUDY_NAME); namesOut.push_back(convertAttributeTypeToName(ATTRIBUTE_STUDY_NAME)); typesOut.push_back(ATTRIBUTE_FOCUS_SPATIAL); namesOut.push_back(convertAttributeTypeToName(ATTRIBUTE_FOCUS_SPATIAL)); typesOut.push_back(ATTRIBUTE_FOCUS_STRUCTURE); namesOut.push_back(convertAttributeTypeToName(ATTRIBUTE_FOCUS_STRUCTURE)); typesOut.push_back(ATTRIBUTE_STUDY_STEREOTAXIC_SPACE); namesOut.push_back(convertAttributeTypeToName(ATTRIBUTE_STUDY_STEREOTAXIC_SPACE)); typesOut.push_back(ATTRIBUTE_STUDY_TABLE_HEADER); namesOut.push_back(convertAttributeTypeToName(ATTRIBUTE_STUDY_TABLE_HEADER)); typesOut.push_back(ATTRIBUTE_STUDY_TABLE_SUBHEADER); namesOut.push_back(convertAttributeTypeToName(ATTRIBUTE_STUDY_TABLE_SUBHEADER)); typesOut.push_back(ATTRIBUTE_STUDY_TITLE); namesOut.push_back(convertAttributeTypeToName(ATTRIBUTE_STUDY_TITLE)); */ } /** * convert an attribute type to name. */ QString FociSearch::convertAttributeTypeToName(const ATTRIBUTE att) { QString s; switch (att) { case ATTRIBUTE_ALL: s = "ALL"; break; case ATTRIBUTE_FOCUS_AREA: s = "Area"; break; case ATTRIBUTE_STUDY_AUTHORS: s = "Authors"; break; case ATTRIBUTE_STUDY_CITATION: s = "Citation"; break; case ATTRIBUTE_FOCUS_CLASS: s = "Class"; break; case ATTRIBUTE_FOCUS_COMMENT: s = "Comment (Focus)"; break; case ATTRIBUTE_STUDY_COMMENT: s = "Comment (Study)"; break; case ATTRIBUTE_STUDY_DATA_FORMAT: s = "Data Format"; break; case ATTRIBUTE_STUDY_DATA_TYPE: s = "Data Type"; break; case ATTRIBUTE_FOCUS_GEOGRAPHY: s = "Geography"; break; case ATTRIBUTE_STUDY_KEYWORDS: s = "Keywords"; break; case ATTRIBUTE_STUDY_MESH_TERMS: s = "MESH Terms"; break; case ATTRIBUTE_STUDY_NAME: s = "Name"; break; case ATTRIBUTE_FOCUS_ROI: s = "ROI"; break; case ATTRIBUTE_FOCUS_SPATIAL: s = "Spatial"; break; case ATTRIBUTE_STUDY_SPECIES: s = "Species"; break; case ATTRIBUTE_FOCUS_STRUCTURE: s = "Structure"; break; case ATTRIBUTE_STUDY_STEREOTAXIC_SPACE: s = "Stereotaxic Space"; break; case ATTRIBUTE_STUDY_TABLE_HEADER: s = "Table Header"; break; case ATTRIBUTE_STUDY_TABLE_SUBHEADER: s = "Table Subheader"; break; case ATTRIBUTE_STUDY_TITLE: s = "Title"; break; case ATTRIBUTE_NUMBER_OF: s = "Number of Attributes"; break; } return s; } /** * convert an attribute name to type. */ FociSearch::ATTRIBUTE FociSearch::convertAttributeNameToType(const QString& s) { ATTRIBUTE att = ATTRIBUTE_ALL; if (s == "ALL") { att = ATTRIBUTE_ALL; } else if (s == "Area") { att = ATTRIBUTE_FOCUS_AREA; } else if (s == "Authors") { att = ATTRIBUTE_STUDY_AUTHORS; } else if (s == "Citation") { att = ATTRIBUTE_STUDY_CITATION; } else if (s == "Class") { att = ATTRIBUTE_FOCUS_CLASS; } else if (s == "Comment (Focus)") { att = ATTRIBUTE_FOCUS_COMMENT; } else if (s == "Comment (Study)") { att = ATTRIBUTE_STUDY_COMMENT; } else if (s == "Data Format") { att = ATTRIBUTE_STUDY_DATA_FORMAT; } else if (s == "Data Type") { att = ATTRIBUTE_STUDY_DATA_TYPE; } else if (s == "Geography") { att = ATTRIBUTE_FOCUS_GEOGRAPHY; } else if (s == "Keywords") { att = ATTRIBUTE_STUDY_KEYWORDS; } else if (s == "MESH Terms") { att = ATTRIBUTE_STUDY_MESH_TERMS; } else if (s == "Name") { att = ATTRIBUTE_STUDY_NAME; } else if (s == "ROI") { att = ATTRIBUTE_FOCUS_ROI; } else if (s == "Spatial") { att = ATTRIBUTE_FOCUS_SPATIAL; } else if (s == "Stereotaxic Space") { att = ATTRIBUTE_STUDY_STEREOTAXIC_SPACE; } else if (s == "Structure") { att = ATTRIBUTE_FOCUS_STRUCTURE; } else if (s == "Table Header") { att = ATTRIBUTE_STUDY_TABLE_HEADER; } else if (s == "Table Subheader") { att = ATTRIBUTE_STUDY_TABLE_SUBHEADER; } else if (s == "Title") { att = ATTRIBUTE_STUDY_TITLE; } else if (s == "Number of Attributes") { att = ATTRIBUTE_NUMBER_OF; } return att; } /** * get types and names for matching. */ void FociSearch::getMatchingTypesAndNames(std::vector& typesOut, std::vector& namesOut) { typesOut.clear(); namesOut.clear(); typesOut.push_back(MATCHING_ANY_OF); namesOut.push_back(convertMatchingTypeToName(MATCHING_ANY_OF)); typesOut.push_back(MATCHING_ALL_OF); namesOut.push_back(convertMatchingTypeToName(MATCHING_ALL_OF)); typesOut.push_back(MATCHING_NONE_OF); namesOut.push_back(convertMatchingTypeToName(MATCHING_NONE_OF)); typesOut.push_back(MATCHING_EXACT_PHRASE); namesOut.push_back(convertMatchingTypeToName(MATCHING_EXACT_PHRASE)); } /** * convert a matching type to name. */ QString FociSearch::convertMatchingTypeToName(const MATCHING m) { QString s; switch (m) { case MATCHING_ANY_OF: s = "ANY of"; break; case MATCHING_ALL_OF: s = "ALL of"; break; case MATCHING_NONE_OF: s = "NONE of"; break; case MATCHING_EXACT_PHRASE: s = "EXACT PHRASE"; break; } return s; } /** * convert a matching name to type. */ FociSearch::MATCHING FociSearch::convertMatchingNameToType(const QString& s) { MATCHING m = MATCHING_ANY_OF; if (s == "ANY of") { m = MATCHING_ANY_OF; } else if (s == "ALL of") { m = MATCHING_ALL_OF; } else if (s == "NONE of") { m = MATCHING_NONE_OF; } else if (s == "EXACT PHRASE") { m = MATCHING_EXACT_PHRASE; } return m; } caret-5.6.4~dfsg.1.orig/caret_files/FociProjectionFile.h0000664000175000017500000000276611572067322022742 0ustar michaelmichael #ifndef __FOCI_PROJECTION_FILE_H__ #define __FOCI_PROJECTION_FILE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CellProjectionFile.h" /// class for foci projection file class FociProjectionFile : public CellProjectionFile { public: /// Constructor FociProjectionFile(); /// Destructor ~FociProjectionFile(); /// write the file's memory in caret6 format to the specified name virtual QString writeFileInCaret6Format(const QString& filenameIn, Structure structure,const ColorFile* colorFileIn, const bool useCaret6ExtensionFlag) throw (FileException); protected: }; #endif // __FOCI_PROJECTION_FILE_H__ caret-5.6.4~dfsg.1.orig/caret_files/FociProjectionFile.cxx0000664000175000017500000001711111572067322023303 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "Caret6ProjectedItem.h" #include "FociProjectionFile.h" #include "GiftiLabelTable.h" #include "SpecFile.h" #include "StringUtilities.h" #include "XmlGenericWriter.h" /** * Constructor */ FociProjectionFile::FociProjectionFile() : CellProjectionFile("Foci Projection File", SpecFile::getFociProjectionFileExtension()) { } /** * Destructor */ FociProjectionFile::~FociProjectionFile() { } /** * Write the file's memory in caret6 format to the specified name. */ QString FociProjectionFile::writeFileInCaret6Format(const QString& filenameIn, Structure structureIn,const ColorFile* colorFileIn, const bool useCaret6ExtensionFlag) throw (FileException) { int numFoci = this->getNumberOfCellProjections(); if (numFoci <= 0) { throw FileException("Contains no foci"); } QFile file(filenameIn); if (AbstractFile::getOverwriteExistingFilesAllowed() == false) { if (file.exists()) { throw FileException("file exists and overwrite is prohibited."); } } if (file.open(QFile::WriteOnly) == false) { throw FileException("Unable to open for writing"); } QTextStream stream(&file); XmlGenericWriter xmlWriter(stream); xmlWriter.writeStartDocument(); XmlGenericWriterAttributes attributes; attributes.addAttribute("CaretFileType", "FociProjection"); attributes.addAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); attributes.addAttribute("xsi:noNamespaceSchemaLocation", "http://brainvis.wustl.edu/caret6/xml_schemas/FociProjectionFileSchema.xsd"); attributes.addAttribute("Version", "6.0"); xmlWriter.writeStartElement("CaretDataFile", attributes); this->writeHeaderXMLWriter(xmlWriter); GiftiLabelTable labelTable; if (colorFileIn != NULL) { labelTable.createLabelsFromColors(*colorFileIn); } labelTable.writeAsXML(xmlWriter); int fociNumber = 0; for (int n = 0; n < numFoci; n++) { CellProjection* fp = this->getCellProjection(n); if (fp->getDuplicateFlag()) { continue; } Structure structure; structure.setType(Structure::STRUCTURE_TYPE_INVALID); if (fp->structure.isLeftCortex()) { structure.setType(Structure::STRUCTURE_TYPE_CORTEX_LEFT); } else if (fp->structure.isRightCortex()) { structure.setType(Structure::STRUCTURE_TYPE_CORTEX_RIGHT); } else if (fp->structure.isCerebellum()) { structure.setType(Structure::STRUCTURE_TYPE_CEREBELLUM); } else if (structureIn.isInvalid() == false) { structure = structureIn; } // // Ignore foci not on cortex or cerebellum or ambiguous // //if (structure.isInvalid()) { // continue; //} XmlGenericWriterAttributes attributes; attributes.addAttribute("Index", fociNumber); xmlWriter.writeStartElement("FocusProjection", attributes); xmlWriter.writeElementCData("Name", fp->getName()); xmlWriter.writeElementCharacters("SearchXYZ", StringUtilities::combine(fp->searchXYZ, 3, " ")); xmlWriter.writeElementCData("Geography", fp->getGeography()); xmlWriter.writeElementCData("Area", fp->getArea()); xmlWriter.writeElementCData("RegionOfInterest", fp->getRegionOfInterest()); xmlWriter.writeElementCharacters("Size", fp->getSize()); xmlWriter.writeElementCData("Statistic", fp->getStatistic()); xmlWriter.writeElementCData("Comment", fp->getComment()); xmlWriter.writeElementCData("ClassName", fp->getClassName()); xmlWriter.writeElementCData("SumsIDNumber", fp->getSumsIDNumber()); xmlWriter.writeElementCData("SumsRepeatNumber", fp->getSumsRepeatNumber()); xmlWriter.writeElementCData("SumsParentFocusBaseID", fp->getSumsParentCellBaseID()); xmlWriter.writeElementCData("SumsVersionNumber", fp->getSumsVersionNumber()); xmlWriter.writeElementCData("SumsMSLID", fp->getSumsMSLID()); xmlWriter.writeElementCData("AttributeID", fp->getAttributeID()); fp->getStudyMetaDataLinkSet().writeXML(xmlWriter); Caret6ProjectedItem pi; pi.projectionType = Caret6ProjectedItem::UNPROJECTED; switch (fp->projectionType) { case CellProjection::PROJECTION_TYPE_UNKNOWN: pi.projectionType = Caret6ProjectedItem::UNPROJECTED; break; case CellProjection::PROJECTION_TYPE_INSIDE_TRIANGLE: pi.projectionType = Caret6ProjectedItem::BARYCENTRIC; // // Area and node indices do not match in Caret5 but // they do in Caret6 // In Caret5: node-index area-index // 0 1 // 1 2 // 2 0 // // But caret5 was clockwise order and we want // counter clockwise so // // node-index area-index // 2 0 // 1 2 // 0 1 // // pi.closestTriangleAreas[0] = fp->closestTileAreas[0]; pi.closestTriangleAreas[1] = fp->closestTileAreas[2]; pi.closestTriangleAreas[2] = fp->closestTileAreas[1]; pi.closestTriangleVertices[0] = fp->closestTileVertices[2]; pi.closestTriangleVertices[1] = fp->closestTileVertices[1]; pi.closestTriangleVertices[2] = fp->closestTileVertices[0]; pi.signedDistanceAboveSurface = fp->signedDistanceAboveSurface; break; case CellProjection::PROJECTION_TYPE_OUTSIDE_TRIANGLE: pi.projectionType = Caret6ProjectedItem::VANESSEN; pi.dR = fp->dR; for (int i = 0; i < 2; i++) { for (int j = 0; j < 3; j++) { for (int k = 0; k < 3; k++) { pi.triAnatomical[i][j][k] = fp->triFiducial[i][j][k]; } pi.triVertices[i][j] = fp->triVertices[i][j]; pi.vertexAnatomical[i][j] = fp->vertexFiducial[i][j]; } pi.vertex[i] = fp->vertex[i]; } for (int i = 0; i < 3; i++) { pi.posAnatomical[i] = fp->posFiducial[i]; } pi.thetaR = fp->thetaR; pi.phiR = fp->phiR; pi.fracRI = fp->fracRI; pi.fracRJ = fp->fracRJ; break; } for (int i = 0; i < 3; i++) { pi.volumeXYZ[i] = fp->volumeXYZ[i]; pi.xyz[i] = fp->xyz[i]; } pi.structure = structure; pi.writeXML(xmlWriter); xmlWriter.writeEndElement(); fociNumber++; } xmlWriter.writeEndElement(); xmlWriter.writeEndDocument(); file.close(); return filenameIn; } caret-5.6.4~dfsg.1.orig/caret_files/FociFile.h0000664000175000017500000000262711572067322020701 0ustar michaelmichael #ifndef __FOCI_FILE_H__ #define __FOCI_FILE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CellFile.h" /// class for foci file class FociFile : public CellFile { public: /// Constructor FociFile(); /// Destructor ~FociFile(); /// write the file's memory in caret6 format to the specified name virtual QString writeFileInCaret6Format(const QString& filenameIn, Structure structure,const ColorFile* colorFileIn, const bool useCaret6ExtensionFlag) throw (FileException); protected: }; #endif // __FOCI_FILE_H__ caret-5.6.4~dfsg.1.orig/caret_files/FociFile.cxx0000664000175000017500000001103511572067322021245 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "Caret6ProjectedItem.h" #include "FileUtilities.h" #include "GiftiLabelTable.h" #include "FociFile.h" #include "SpecFile.h" #include "StringUtilities.h" /** * Constructor */ FociFile::FociFile() : CellFile("Foci File", SpecFile::getFociFileExtension()) { } /** * Destructor */ FociFile::~FociFile() { } /** * Write the file's memory in caret6 format to the specified name. */ QString FociFile::writeFileInCaret6Format(const QString& filenameIn, Structure structureIn,const ColorFile* colorFileIn, const bool useCaret6ExtensionFlag) throw (FileException) { int numFoci = this->getNumberOfCells(); if (numFoci <= 0) { throw FileException("Contains no foci"); } QString name = FileUtilities::filenameWithoutExtension(filenameIn) + SpecFile::getFociProjectionFileExtension(); QFile file(name); if (file.open(QFile::WriteOnly) == false) { throw FileException("Unable to open for writing"); } QTextStream stream(&file); XmlGenericWriter xmlWriter(stream); xmlWriter.writeStartDocument(); XmlGenericWriterAttributes attributes; attributes.addAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); attributes.addAttribute("xsi:noNamespaceSchemaLocation", "http://brainvis.wustl.edu/caret6/xml_schemas/FociProjectionFileSchema.xsd"); attributes.addAttribute("CaretFileType", "FociProjection"); attributes.addAttribute("Version", "6.0"); xmlWriter.writeStartElement("CaretDataFile", attributes); this->writeHeaderXMLWriter(xmlWriter); GiftiLabelTable labelTable; if (colorFileIn != NULL) { labelTable.createLabelsFromColors(*colorFileIn); } labelTable.writeAsXML(xmlWriter); for (int n = 0; n < numFoci; n++) { CellData* cd = this->getCell(n); Structure structure; structure.setType(Structure::STRUCTURE_TYPE_INVALID); if (structureIn.isInvalid() == false) { structure = structureIn; } // // Ignore foci not on cortex or cerebellum or ambiguous // if (structure.isInvalid()) { continue; } XmlGenericWriterAttributes attributes; attributes.addAttribute("Index", n); xmlWriter.writeStartElement("FocusProjection", attributes); xmlWriter.writeElementCData("Name", cd->getName()); xmlWriter.writeElementCharacters("SearchXYZ", StringUtilities::combine(cd->getSearchXYZ(), 3, " ")); xmlWriter.writeElementCData("Geography", cd->getGeography()); xmlWriter.writeElementCData("Area", cd->getArea()); xmlWriter.writeElementCData("RegionOfInterest", cd->getRegionOfInterest()); xmlWriter.writeElementCharacters("Size", cd->getSize()); xmlWriter.writeElementCData("Statistic", cd->getStatistic()); xmlWriter.writeElementCData("Comment", cd->getComment()); xmlWriter.writeElementCData("ClassName", cd->getClassName()); xmlWriter.writeElementCData("SumsIDNumber", cd->getSumsIDNumber()); xmlWriter.writeElementCData("SumsRepeatNumber", cd->getSumsRepeatNumber()); xmlWriter.writeElementCData("SumsParentCellBaseID", cd->getSumsParentCellBaseID()); xmlWriter.writeElementCData("SumsVersionNumber", cd->getSumsVersionNumber()); xmlWriter.writeElementCData("SumsMSLID", cd->getSumsMSLID()); xmlWriter.writeElementCData("AttributeID", cd->getAttributeID()); Caret6ProjectedItem pi; pi.projectionType = Caret6ProjectedItem::UNPROJECTED; cd->getXYZ(pi.xyz); pi.structure = structure; pi.writeXML(xmlWriter); xmlWriter.writeEndElement(); } xmlWriter.writeEndElement(); xmlWriter.writeEndDocument(); file.close(); return name; } caret-5.6.4~dfsg.1.orig/caret_files/FociColorFile.h0000664000175000017500000000335711572067322021701 0ustar michaelmichael #ifndef __FOCI_COLOR_FILE_H__ #define __FOCI_COLOR_FILE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "ColorFile.h" class FociProjectionFile; /// class for foci colors file class FociColorFile : public ColorFile { public: /// Constructor FociColorFile(); /// Destructor ~FociColorFile(); // remove colors not matching the names in the cell projection file void removeNonMatchingColors(const FociProjectionFile* fpf); /// get color indices sorted by name case insensitive void getColorIndicesSortedByName(const FociProjectionFile* fpf, std::vector& indicesSortedByNameOut, const bool reverseOrderFlag, const bool limitToColorsUsedByDisplayedFociFlag) const; protected: }; #endif // __FOCI_COLOR_FILE_H__ caret-5.6.4~dfsg.1.orig/caret_files/FociColorFile.cxx0000664000175000017500000001122111572067322022241 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "FociColorFile.h" #include "FociProjectionFile.h" #include "NameIndexSort.h" #include "SpecFile.h" /** * Constructor */ FociColorFile::FociColorFile() : ColorFile("Foci Color File", SpecFile::getFociColorFileExtension()) { } /** * Destructor */ FociColorFile::~FociColorFile() { } /** * remove colors not matching the names in the cell projection file. */ void FociColorFile::removeNonMatchingColors(const FociProjectionFile* fpf) { const int numColors = getNumberOfColors(); if (numColors <= 0) { return; } const int numFoci = fpf->getNumberOfCellProjections(); // // Colors that are used // std::vector colorsUsed; // // Loop through colors // for (int i = 0; i < numColors; i++) { // // Get the name ofr the color // const ColorStorage cs = *(getColor(i)); const QString colorName = cs.getName(); bool colorUsedFlag = false; // // Never delete the unknown color // if (colorName == "???") { colorUsedFlag = true; } else { // // loop through foci projections to see if color is used // for (int j = 0; j < numFoci; j++) { // // Get the name of the focus // const CellProjection* cf = fpf->getCellProjection(j); const QString focusName = cf->getName(); // // Does the focus start with the name of the colors // if (focusName.startsWith(colorName)) { // // Keep this color // colorUsedFlag = true; break; } } } // // Was this color used // if (colorUsedFlag) { // // Keep this color // colorsUsed.push_back(cs); } } // // Were colors removed // if (static_cast(colorsUsed.size()) != numColors) { // // Simply replace colors // colors = colorsUsed; setModified(); } } /** * get color indices sorted by name case insensitive. */ void FociColorFile::getColorIndicesSortedByName(const FociProjectionFile* fpf, std::vector& indicesSortedByNameOut, const bool reverseOrderFlag, const bool limitToColorsUsedByDisplayedFociFlag) const { indicesSortedByNameOut.clear(); // // Sort indices by name // NameIndexSort nis; if (limitToColorsUsedByDisplayedFociFlag) { const int numFoci = fpf->getNumberOfCellProjections(); const int numColors = getNumberOfColors(); std::vector colorIndexUsed(numColors, false); for (int i = 0; i < numFoci; i++) { const CellProjection* focus = fpf->getCellProjection(i); if (focus->getDisplayFlag()) { const int colorIndex = focus->getColorIndex(); if (colorIndex >= 0) { colorIndexUsed[colorIndex] = true; } } } for (int i = 0; i < numColors; i++) { if (colorIndexUsed[i]) { nis.add(i, getColorNameByIndex(i)); } } } else { const int num = getNumberOfColors(); for (int i = 0; i < num; i++) { nis.add(i, getColorNameByIndex(i)); } } nis.sortByNameCaseInsensitive(); const int numItems = nis.getNumberOfItems(); indicesSortedByNameOut.resize(numItems, 0); for (int i = 0; i < numItems; i++) { indicesSortedByNameOut[i] = nis.getSortedIndex(i); } if (reverseOrderFlag) { std::reverse(indicesSortedByNameOut.begin(), indicesSortedByNameOut.end()); } } caret-5.6.4~dfsg.1.orig/caret_files/FileFilters.h0000664000175000017500000007453611572067322021441 0ustar michaelmichael #ifndef __FILE_FILTERS_H__ #define __FILE_FILTERS_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "SpecFile.h" /// class for file filters class FileFilters { public: /// get all file filters static void getAllFileFilters(QStringList& allFileFiltersOut); /// get all caret file filters static void getAllCaretFileFilters(QStringList& allFileFiltersOut); /// file filer for file static QString getAnyFileFilter() { return "Any File (*)"; } /// file filer for file static QString getAreaColorFileFilter() { return QString("Area Color File (*%1)").arg(SpecFile::getAreaColorFileExtension()); } /// file filer for file static QString getArealEstimationFileFilter() { return QString("Areal Estimation Files (*%1)").arg(SpecFile::getArealEstimationFileExtension()); } /// file filer for file static QString getBorderRawFileFilter() { return QString("Border Files RAW (*%1)").arg(SpecFile::getBorderFileExtension()); } /// file filer for file static QString getBorderFiducialFileFilter() { return QString("Border Files FIDUCIAL (*%1)").arg(SpecFile::getBorderFileExtension()); } /// file filer for file static QString getBorderInflatedFileFilter() { return QString("Border Files INFLATED (*%1)").arg(SpecFile::getBorderFileExtension()); } /// file filer for file static QString getBorderVeryInflatedFileFilter() { return QString("Border Files VERY INFLATED (*%1)").arg(SpecFile::getBorderFileExtension()); } /// file filer for file static QString getBorderSphericalFileFilter() { return QString("Border Files SPHERICAL (*%1)").arg(SpecFile::getBorderFileExtension()); } /// file filer for file static QString getBorderEllipsoidalFileFilter() { return QString("Border Files ELLIPSOIDAL (*%1)").arg(SpecFile::getBorderFileExtension()); } /// file filer for file static QString getBorderCompressedFileFilter() { return QString("Border Files COMPRESSED (*%1)").arg(SpecFile::getBorderFileExtension()); } /// file filer for file static QString getBorderFlatFileFilter() { return QString("Border Files FLAT (*%1)").arg(SpecFile::getBorderFileExtension()); } /// file filer for file static QString getBorderFlatLobarFileFilter() { return QString("Border Files FLAT LOBAR (*%1)").arg(SpecFile::getBorderFileExtension()); } /// file filer for file static QString getBorderHullFileFilter() { return QString("Border Files HULL (*%1)").arg(SpecFile::getBorderFileExtension()); } /// file filer for file static QString getBorderUnknownFileFilter() { return QString("Border Files UNKNOWN (*%1)").arg(SpecFile::getBorderFileExtension()); } /// file filer for file static QString getBorderGenericFileFilter() { return QString("Border Files - Surface (*%1)").arg(SpecFile::getBorderFileExtension()); } /// file filer for file static QString getBorderVolumeFileFilter() { return QString("Border Files - Volume (*%1)").arg(SpecFile::getBorderFileExtension()); } /// file filer for file static QString getBorderColorFileFilter() { return QString("Border Color Files (*%1)").arg(SpecFile::getBorderColorFileExtension()); } /// file filer for file static QString getBorderProjectionFileFilter() { return QString("Border Projection Files (*%1)").arg(SpecFile::getBorderProjectionFileExtension()); } /// file filer for file static QString getCellFileFilter() { return QString("Cell Files (*%1)").arg(SpecFile::getCellFileExtension()); } /// file filer for file static QString getCellColorFileFilter() { return QString("Cell Color Files (*%1)").arg(SpecFile::getCellColorFileExtension()); } /// file filer for file static QString getCellProjectionFileFilter() { return QString("Cell Projection Files (*%1)").arg(SpecFile::getCellProjectionFileExtension()); } /// file filer for file static QString getCellVolumeFileFilter() { return QString("Cell Files - Volume (*%1)").arg(SpecFile::getCellFileExtension()); } /// file filer for file static QString getCocomacFileFilter() { return QString("CoCoMac Files (*%1 *.xml)").arg(SpecFile::getCocomacConnectivityFileExtension()); } /// file filer for file static QString getContourFileFilter() { return QString("Contour Files (*%1)").arg(SpecFile::getContourFileExtension()); } /// file filer for file static QString getContourCellFileFilter() { return QString("Contour Cell Files (*%1)").arg(SpecFile::getContourCellFileExtension()); } /// file filer for file static QString getContourCellColorFileFilter() { return QString("Contour Cell Color Files (*%1)").arg(SpecFile::getContourCellColorFileExtension()); } /// file filer for file static QString getCoordinateRawFileFilter() { return QString("Coordinate Files RAW (*%1)").arg(SpecFile::getCoordinateFileExtension()); } /// file filer for file static QString getCoordinateFiducialFileFilter() { return QString("Coordinate Files FIDUCIAL (*%1)").arg(SpecFile::getCoordinateFileExtension()); } /// file filer for file static QString getCoordinateInflatedFileFilter() { return QString("Coordinate Files INFLATED (*%1)").arg(SpecFile::getCoordinateFileExtension()); } /// file filer for file static QString getCoordinateVeryInflatedFileFilter() { return QString("Coordinate Files VERY INFLATED (*%1)").arg(SpecFile::getCoordinateFileExtension()); } /// file filer for file static QString getCoordinateSphericalFileFilter() { return QString("Coordinate Files SPHERICAL (*%1)").arg(SpecFile::getCoordinateFileExtension()); } /// file filer for file static QString getCoordinateEllipsoidalFileFilter() { return QString("Coordinate Files ELLIPSOIDAL (*%1)").arg(SpecFile::getCoordinateFileExtension()); } /// file filer for file static QString getCoordinateCompressedFileFilter() { return QString("Coordinate Files COMPRESSED (*%1)").arg(SpecFile::getCoordinateFileExtension()); } /// file filer for file static QString getCoordinateFlatFileFilter() { return QString("Coordinate Files FLAT (*%1)").arg(SpecFile::getCoordinateFileExtension()); } /// file filer for file static QString getCoordinateFlatLobarFileFilter() { return QString("Coordinate Files FLAT LOBAR (*%1)").arg(SpecFile::getCoordinateFileExtension()); } /// file filer for file static QString getCoordinateHullFileFilter() { return QString("Coordinate Files HULL (*%1)").arg(SpecFile::getCoordinateFileExtension()); } /// file filer for file static QString getCoordinateUnknownFileFilter() { return QString("Coordinate Files UNKNOWN (*%1)").arg(SpecFile::getCoordinateFileExtension()); } /// file filer for file static QString getCoordinateGenericFileFilter() { return QString("Coordinate Files (*%1)").arg(SpecFile::getCoordinateFileExtension()); } /// file filer for file static QString getCutsFileFilter() { return QString("Cuts Files (*%1)").arg(SpecFile::getCutsFileExtension()); } /// file filer for file static QString getDeformationFieldFileFilter() { return QString("Deformation Field Files (*%1)").arg(SpecFile::getDeformationFieldFileExtension()); } /// file filer for file static QString getDeformationMapFileFilter() { return QString("Deformation Map Files (*%1)").arg(SpecFile::getDeformationMapFileExtension()); } /// file filer for file static QString getFociFileFilter() { return QString("Foci Files (*%1 *%2)").arg(SpecFile::getFociFileExtension()).arg( SpecFile::getFociFileExtension() + ".csv"); } /// file filer for file static QString getFociColorFileFilter() { return QString("Foci Color Files (*%1)").arg(SpecFile::getFociColorFileExtension()); } /// file filer for file static QString getFociProjectionFileFilter() { return QString("Foci Projection Files (*%1)").arg(SpecFile::getFociProjectionFileExtension()); } /// file filer for file static QString getFociSearchFileFilter() { return QString("Foci Search Files (*%1)").arg(SpecFile::getFociSearchFileExtension()); } /// file filer for file static QString getGeodesicDistanceFileFilter() { return QString("Geodesic Distance Files (*%1)").arg(SpecFile::getGeodesicDistanceFileExtension()); } /// file filer for file static QString getLatitudeLongitudeFileFilter() { return QString("Latitude Longitude Files (*%1)").arg(SpecFile::getLatLonFileExtension()); } /// file filer for file static QString getMetricFileFilter() { return QString("Metric Files (*%1)").arg(SpecFile::getMetricFileExtension()); } /// file filer for metric or shape as metric file static QString getMetricOrShapeAsMetricFileFilter() { return QString("Metric [or Shape] Files (*%1 *%2 *%3 *%4)").arg(SpecFile::getMetricFileExtension()).arg(SpecFile::getSurfaceShapeFileExtension()).arg(SpecFile::getGiftiFunctionalFileExtension()).arg(SpecFile::getGiftiShapeFileExtension()); } /// file filer for file static QString getMetricShapeFileFilter() { return QString("Metric/Shape Files (*%1 *%2)").arg(SpecFile::getMetricFileExtension()).arg(SpecFile::getSurfaceShapeFileExtension()); } /// file filer for file static QString getPaintFileFilter() { return QString("Paint Files (*%1)").arg(SpecFile::getPaintFileExtension()); } /// file filer for file static QString getPaletteFileFilter() { return QString("Palette Files (*%1 *.pal)").arg(SpecFile::getPaletteFileExtension()); } /// file filer for file static QString getParamsFileFilter() { return QString("Params Files (*%1)").arg(SpecFile::getParamsFileExtension()); } /// file filer for file static QString getProbAtlasFileFilter() { return QString("Probabilistic Atlas Files (*%1 *atlas.paint*)").arg(SpecFile::getProbabilisticAtlasFileExtension()); } /// file filer for file static QString getRgbPaintFileFilter() { return QString("RGB Paint Files (*%1)").arg(SpecFile::getRgbPaintFileExtension()); } /// file filer for file static QString getRegionOfInterestFileFilter() { return QString("Region of Interest Files (*%1)").arg(SpecFile::getRegionOfInterestFileExtension()); } /// file filer for file static QString getSceneFileFilter() { return QString("Scene Files (*%1)").arg(SpecFile::getSceneFileExtension()); } /// file filer for file static QString getSectionFileFilter() { return QString("Section Files (*%1)").arg(SpecFile::getSectionFileExtension()); } /// file filer for file static QString getSurfaceShapeFileFilter() { return QString("Surface Shape Files (*%1)").arg(SpecFile::getSurfaceShapeFileExtension()); } /// file filer for shape or metric as shape file static QString getSurfaceShapeOrMetricAsShapeFileFilter() { return QString("Surface Shape [or Metric] Files (*%1 *%2 *%3 *%4)").arg(SpecFile::getMetricFileExtension()).arg(SpecFile::getSurfaceShapeFileExtension()).arg(SpecFile::getGiftiFunctionalFileExtension()).arg(SpecFile::getGiftiShapeFileExtension()); } /// file filer for file static QString getTopographyFileFilter() { return QString("Topography Files (*%1)").arg(SpecFile::getTopographyFileExtension()); } /// file filer for file static QString getTopologyClosedFileFilter() { return QString("Topology Files CLOSED (*%1)").arg(SpecFile::getTopoFileExtension()); } /// file filer for file static QString getTopologyOpenFileFilter() { return QString("Topology Files OPEN (*%1)").arg(SpecFile::getTopoFileExtension()); } /// file filer for file static QString getTopologyCutFileFilter() { return QString("Topology Files CUT (*%1)").arg(SpecFile::getTopoFileExtension()); } /// file filer for file static QString getTopologyCutLobarFileFilter() { return QString("Topology Files CUT LOBAR (*%1)").arg(SpecFile::getTopoFileExtension()); } /// file filer for file static QString getTopologyUnknownFileFilter() { return QString("Topology Files UNKNOWN (*%1)").arg(SpecFile::getTopoFileExtension()); } /// file filer for file static QString getTopologyGenericFileFilter() { return QString("Topology Files (*%1)").arg(SpecFile::getTopoFileExtension()); } /// file filer for file static QString getTransformationMatrixFileFilter() { return QString("Transformation Matrix Files (*%1)").arg(SpecFile::getTransformationMatrixFileExtension()); } /// file filer for file static QString getTransformationDataFileFilter() { return QString("Transformation Data Files (*%1 *%3 *.vtp *%4 *%5)" ).arg(SpecFile::getCellFileExtension()).arg( SpecFile::getVtkModelFileExtension()).arg( SpecFile::getContourFileExtension()).arg( SpecFile::getContourCellFileExtension()); } /// file filer for file static QString getVolumeAnatomyFileFilter() { return QString("Volume Anatomy Files (*%1 *%2 *%3 *%4 *%5)").arg( SpecFile::getAfniVolumeFileExtension()).arg( SpecFile::getAnalyzeVolumeFileExtension()).arg( SpecFile::getNiftiVolumeFileExtension()).arg( SpecFile::getNiftiGzipVolumeFileExtension()).arg( SpecFile::getWustlVolumeFileExtension()); } /// file filer for file static QString getVolumeFunctionalFileFilter() { return QString("Volume Functional Files (*%1 *%2 *%3 *%4 *%5)").arg( SpecFile::getAfniVolumeFileExtension()).arg( SpecFile::getAnalyzeVolumeFileExtension()).arg( SpecFile::getNiftiVolumeFileExtension()).arg( SpecFile::getNiftiGzipVolumeFileExtension()).arg( SpecFile::getWustlVolumeFileExtension()); } /// file filer for file static QString getVolumePaintFileFilter() { return QString("Volume Paint Files (*%1 *%2 *%3 *%4 *%5)").arg( SpecFile::getAfniVolumeFileExtension()).arg( SpecFile::getAnalyzeVolumeFileExtension()).arg( SpecFile::getNiftiVolumeFileExtension()).arg( SpecFile::getNiftiGzipVolumeFileExtension()).arg( SpecFile::getWustlVolumeFileExtension()); } /// file filer for file static QString getVolumeProbAtlasFileFilter() { return QString("Volume Prob Atlas Files (*%1 *%2 *%3 *%4 *%5)").arg( SpecFile::getAfniVolumeFileExtension()).arg( SpecFile::getAnalyzeVolumeFileExtension()).arg( SpecFile::getNiftiVolumeFileExtension()).arg( SpecFile::getNiftiGzipVolumeFileExtension()).arg( SpecFile::getWustlVolumeFileExtension()); } /// file filer for file static QString getVolumeRgbFileFilter() { return QString("Volume Rgb Files (*%1 *%2 *%3 *%4 *%5)").arg( SpecFile::getAfniVolumeFileExtension()).arg( SpecFile::getAnalyzeVolumeFileExtension()).arg( SpecFile::getNiftiVolumeFileExtension()).arg( SpecFile::getNiftiGzipVolumeFileExtension()).arg( SpecFile::getWustlVolumeFileExtension()); } /// file filer for file static QString getVolumeSegmentationFileFilter() { return QString("Volume Segmentation Files (*%1 *%2 *%3 *%4 *%5)").arg( SpecFile::getAfniVolumeFileExtension()).arg( SpecFile::getAnalyzeVolumeFileExtension()).arg( SpecFile::getNiftiVolumeFileExtension()).arg( SpecFile::getNiftiGzipVolumeFileExtension()).arg( SpecFile::getWustlVolumeFileExtension()); } /// file filer for file static QString getVolumeVectorFileFilter() { return QString("Volume Vector Files (*%1 *%2 *%3 *%4 *%5)").arg( SpecFile::getAfniVolumeFileExtension()).arg( SpecFile::getAnalyzeVolumeFileExtension()).arg( SpecFile::getNiftiVolumeFileExtension()).arg( SpecFile::getNiftiGzipVolumeFileExtension()).arg( SpecFile::getWustlVolumeFileExtension()); } /// file filer for file static QString getVolumeGenericFileFilter() { return QString("Volume Files (*%1 *%2 *%3 *%4 *%5)").arg( SpecFile::getAfniVolumeFileExtension()).arg( SpecFile::getAnalyzeVolumeFileExtension()).arg( SpecFile::getNiftiVolumeFileExtension()).arg( SpecFile::getNiftiGzipVolumeFileExtension()).arg( SpecFile::getWustlVolumeFileExtension()); } /// file filer for file static QString getVolumeFileAfniFilter() { return QString("Volume File - AFNI (*%1)").arg(SpecFile::getAfniVolumeFileExtension()); } /// file filer for file static QString getVolumeMultiFileAfniFilter() { return QString("Volume Files MULTIPLE - AFNI (*%1)").arg(SpecFile::getAfniVolumeFileExtension()); } /// file filer for file static QString getVolumeFileNiftiReadFilter() { return QString("Volume Files - NIFTI (*%1 *%2 %3)").arg(SpecFile::getAnalyzeVolumeFileExtension()).arg( SpecFile::getNiftiVolumeFileExtension()).arg( SpecFile::getNiftiGzipVolumeFileExtension()); } /// file filer for file static QString getVolumeFileNiftiWriteFilter() { return QString("Volume Files - NIFTI (*%1 *%2)").arg(SpecFile::getNiftiVolumeFileExtension()).arg( SpecFile::getNiftiGzipVolumeFileExtension()); } /// file filer for file static QString getVolumeMultiFileNiftiFilter() { return QString("Volume Files MULTIPLE - NIFTI (*%1 *%2)").arg(SpecFile::getNiftiVolumeFileExtension()).arg( SpecFile::getNiftiGzipVolumeFileExtension()); } /// file filer for file static QString getVolumeFileSpmMedxFilter() { return QString("Volume Files - SPM and MEDx (*%1)").arg(SpecFile::getAnalyzeVolumeFileExtension()); } /// file filer for file static QString getVolumeFileWuNilFilter() { return QString("Volume Files - WUNIL (*%1)").arg(SpecFile::getWustlVolumeFileExtension()); } /// file filer for file static QString getVtkModelFileFilter() { return QString("VTK Model File (*%1 *.vtp)").arg(SpecFile::getVtkModelFileExtension()); } /// file filer for file static QString getVocabularyFileFilter() { return QString("Vocabulary File (*%1)").arg(SpecFile::getVocabularyFileExtension()); } /// file filer for file static QString getWustlRegionFileFilter() { return QString("Wustl Region File (*%1)").arg(SpecFile::getWustlRegionFileExtension()); } /// file filer for file static QString getStudyCollectionFileFilter() { return QString("Study Collection File (*%1)").arg(SpecFile::getStudyCollectionFileExtension()); } /// file filer for file static QString getStudyMetaDataFileFilter() { return QString("Study Metadata File (*%1)").arg(SpecFile::getStudyMetaDataFileExtension()); } /// file filer for file static QString getSpecFileFilter() { return QString("Spec File (*%1)").arg(SpecFile::getSpecFileExtension()); } /// file filer for file static QString getMdPlotFileFilter() { return QString("MD Plot File (*%1)").arg(SpecFile::getMDPlotFileExtension()); } /// file filer for file static QString getNeurolucidaFileFilter() { return QString("Neurolucida File (*%1)").arg(SpecFile::getNeurolucidaFileExtension()); } /// file filer for file static QString getBrainVoyagerFileFilter() { return QString("Brain Voyager File (*%1)").arg(SpecFile::getBrainVoyagerFileExtension()); } /// file filer for file static QString getVtkSurfaceFileFilter() { return QString("VTK Surface File (*%1)").arg(SpecFile::getVtkModelFileExtension()); } /// file filer for file static QString getVtkXmlSurfaceFileFilter() { return "VTK XML Surface File (*.vtp)"; } /// file filer for file static QString getByuSurfaceFileFilter() { return "BYU Surface File (*.byu)"; } /// file filer for file static QString getStlSurfaceFileFilter() { return "STL Surface File (*.stl)"; } /// file filer for file static QString getStudio3DSurfaceFileFilter() { return "3D Studio Max Ascii Scene (*.ase)"; } /// file filer for file static QString getWavefrontObjFileFilter() { return "Wavefront OBJ Surface File (*.obj)"; } /// file filer for file static QString getVrmlSurfaceFileFilter() { return "VRML Surface File (*.wrl)"; } /// file filer for file static QString getSumaRgbFileFilter() { return "SUMA RGB file (*.col)"; } /// file filer for file static QString getTextFileFilter() { return "Text File (*.txt *.text)"; } /// file filer for file static QString getCommaSeparatedValuesFileFilter() { return QString("Comma Separated Value File (*%1)").arg(SpecFile::getCommaSeparatedValueFileExtension()); } /// file filer for file static QString getOpenInventorSurfaceFileFilter() { return "Open Inventor Surface File (*.iv)"; } /// file filer for file static QString getFreeSurferAsciiSurfaceFileFilter() { return QString("Free Surfer Ascii Surface File (*%1)").arg(SpecFile::getFreeSurferAsciiSurfaceFileExtension()); } /// file filer for file static QString getFreeSurferBinarySurfaceFileFilter() { return QString("Free Surfer Binary Surface File (*)"); } /// file filer for file static QString getFreeSurferAsciiCurvatureFileFilter() { return QString("Free Surface Ascii Curvature File As Surface Shape (*%1)").arg(SpecFile::getFreeSurferAsciiCurvatureFileExtension()); } /// file filer for file static QString getFreeSurferBinaryCurvatureFileFilter() { return QString("Free Surface Binary Curvature File As Surface Shape (*%1)").arg(SpecFile::getFreeSurferBinaryCurvatureFileExtension()); } /// file filer for file static QString getFreeSurferAsciiFunctionalFileFilter() { return QString("Free Surfer Ascii Functional File As Metric(*%1)").arg(SpecFile::getFreeSurferAsciiFunctionalFileExtension()); } /// file filer for file static QString getFreeSurferBinaryFunctionalFileFilter() { return QString("Free Surfer Binary Functional File As Metric(*%1)").arg(SpecFile::getFreeSurferBinaryFunctionalFileExtension()); } /// file filer for file static QString getFreeSurferAsciiLabelFileFilter() { return QString("Free Surfer Ascii Label File As Paint(*%1)").arg(SpecFile::getFreeSurferLabelFileExtension()); } /// file filer for file static QString getAnalyzeVolumeFileFilter() { return QString("Analyze Volume File (*%1)").arg(SpecFile::getAnalyzeVolumeFileExtension()); } /// file filer for file static QString getMincVolumeFileFilter() { return QString("MINC Volume File (*%1)").arg(SpecFile::getMincVolumeFileExtension()); } /// file filter for file static QString getMniObjSurfaceFileFilter() { return QString("MNI OBJ Surface File (*%1 *%1.txt)").arg(SpecFile::getMniObjeSurfaceFileExtension()); } /// file filer for file static QString getVtkVolumeFileFilter() { return QString("VTK Volume File (*%1)").arg(SpecFile::getVtkModelFileExtension()); } /// file filer for file static QString getRawVolumeFileFilter() { return "Raw Volume File (*)"; } /// file filer for file static QString getGiftiGenericFileFilter() { return QString("GIfTI Generic File (*%1)").arg(SpecFile::getGiftiGenericFileExtension()); } /// file filer for file static QString getGiftiCoordinateFileFilter() { return QString("GIfTI Coordinate File (*%1)").arg(SpecFile::getGiftiCoordinateFileExtension()); } /// file filer for file static QString getGiftiFunctionalFileFilter() { return QString("GIfTI Functional File (*%1)").arg(SpecFile::getGiftiFunctionalFileExtension()); } /// file filer for file static QString getGiftiLabelFileFilter() { return QString("GIfTI Label File (*%1)").arg(SpecFile::getGiftiLabelFileExtension()); } /// file filer for file static QString getGiftiRgbaFileFilter() { return QString("GIfTI RGBA File (*%1)").arg(SpecFile::getGiftiRgbaFileExtension()); } /// file filer for file static QString getGiftiShapeFileFilter() { return QString("GIfTI Shape File (*%1)").arg(SpecFile::getGiftiShapeFileExtension()); } /// file filer for file static QString getGiftiSurfaceFileFilter() { return QString("GIfTI Surface File (*%1)").arg(SpecFile::getGiftiSurfaceFileExtension()); } /// file filer for file static QString getGiftiTensorFileFilter() { return QString("GIfTI Tensor File (*%1)").arg(SpecFile::getGiftiTensorFileExtension()); } /// file filer for file static QString getGiftiTimeSeriesFileFilter() { return QString("GIfTI Time Series File (*%1)").arg(SpecFile::getGiftiTimeSeriesFileExtension()); } /// file filer for file static QString getGiftiTopologyFileFilter() { return QString("GIfTI Topology File (*%1)").arg(SpecFile::getGiftiTopologyFileExtension()); } /// file filter for GIFTI vector file static QString getGiftiVectorFileFilter() { return QString("GIFTI Vector File (*%1)").arg(SpecFile::getGiftiVectorFileExtension()); } /// file filters for opening images static void getImageOpenFileFilters(QStringList& fileFiltersOut, QStringList& fileExtensionsOut); /// file filter containing all image open formats static QString getImageOpenFileFilter(); /// file filters for saving images static void getImageSaveFileFilters(QStringList& fileFiltersOut, QStringList& fileExtensionsOut); /// file filter containing all image save formats static QString getImageSaveFileFilter(); /// file filter for vector file static QString getSureFitVectorFileFilter() { return QString("Vector File (%1)").arg(SpecFile::getSureFitVectorFileExtension()); } /// file filter for Caret Script File static QString getCaretScriptFileFilter() { return QString("Caret Script File (*%1)").arg(SpecFile::getCaretScriptFileExtension()); } /// file filter for PDF file static QString getPDFFileFilter() { return "PDF File (*.pdf)"; } /// file filter for HTML file static QString getHTMLFileFilter() { return "HTML File (*.html)"; } /// file filter for zip file static QString getZipFileFilter() { return QString("Zip File (*%1)").arg(SpecFile::getZipFileExtension()); } /// file filter for python script static QString getPythonFileFilter() { return "Python Script File (*.py)"; } /// file filter for perl script static QString getPerlFileFilter() { return "Perl Script File (*.pl)"; } /// file filter for bourne shell script static QString getBourneShellFileFilter() { return "Bourne Shell Script File (*.sh)"; } /// file filter for C Shell script static QString getCShellFileFilter() { return "C-Shell Script File (*.csh)"; } /// file filter for Windows BAT script static QString getWindowsBATFileFilter() { return "Windows DOS Script File (*.bat)"; } }; #endif // __FILE_FILTERS_H__ caret-5.6.4~dfsg.1.orig/caret_files/FileFilters.cxx0000664000175000017500000003261611572067322022005 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include "FileFilters.h" /** * file filters for opening images. */ void FileFilters::getImageOpenFileFilters(QStringList& fileFiltersOut, QStringList& fileExtensionsOut) { fileFiltersOut.clear(); fileExtensionsOut.clear(); for (int i = 0; i < QImageReader::supportedImageFormats().count(); i++) { QString str = QString(QImageReader::supportedImageFormats().at(i)); QString strLower = str.toLower(); const QString f = (str + " Image File (*." + strLower + ")"); fileFiltersOut << f; fileExtensionsOut << strLower; } } /** * file filter containing all image open formats. */ QString FileFilters::getImageOpenFileFilter() { QStringList filterList; for (int i = 0; i < QImageReader::supportedImageFormats().count(); i++) { QString str = QString(QImageReader::supportedImageFormats().at(i)); QString strLower = str.toLower(); filterList << ("*." + strLower); } const QString filters = ("Image File (" + filterList.join(" ") + ")"); return filters; } /** * file filters for saving images. */ void FileFilters::getImageSaveFileFilters(QStringList& fileFiltersOut, QStringList& fileExtensionsOut) { fileFiltersOut.clear(); fileExtensionsOut.clear(); for (int i = 0; i < QImageWriter::supportedImageFormats().count(); i++) { QString str = QString(QImageWriter::supportedImageFormats().at(i)); QString strLower = str.toLower(); const QString f = (str + " Image File (*." + strLower + ")"); fileFiltersOut << f; fileExtensionsOut << strLower; } } /** * file filter containing all image save formats. */ QString FileFilters::getImageSaveFileFilter() { QStringList filterList; for (int i = 0; i < QImageWriter::supportedImageFormats().count(); i++) { QString str = QString(QImageWriter::supportedImageFormats().at(i)); QString strLower = str.toLower(); filterList << ("*." + strLower); } const QString filters = ("Image File (" + filterList.join(" ") + ")"); return filters; } /** * get all file filters. */ void FileFilters::getAllFileFilters(QStringList& allFileFiltersOut) { allFileFiltersOut.clear(); allFileFiltersOut.append(getAreaColorFileFilter()); allFileFiltersOut.append(getArealEstimationFileFilter()); allFileFiltersOut.append(getBorderRawFileFilter()); allFileFiltersOut.append(getBorderFiducialFileFilter()); allFileFiltersOut.append(getBorderInflatedFileFilter()); allFileFiltersOut.append(getBorderVeryInflatedFileFilter()); allFileFiltersOut.append(getBorderSphericalFileFilter()); allFileFiltersOut.append(getBorderEllipsoidalFileFilter()); allFileFiltersOut.append(getBorderCompressedFileFilter()); allFileFiltersOut.append(getBorderFlatFileFilter()); allFileFiltersOut.append(getBorderFlatLobarFileFilter()); allFileFiltersOut.append(getBorderHullFileFilter()); allFileFiltersOut.append(getBorderUnknownFileFilter()); allFileFiltersOut.append(getBorderGenericFileFilter()); allFileFiltersOut.append(getBorderVolumeFileFilter()); allFileFiltersOut.append(getBorderColorFileFilter()); allFileFiltersOut.append(getBorderProjectionFileFilter()); allFileFiltersOut.append(getCellFileFilter()); allFileFiltersOut.append(getCellColorFileFilter()); allFileFiltersOut.append(getCellProjectionFileFilter()); allFileFiltersOut.append(getCellVolumeFileFilter()); allFileFiltersOut.append(getCocomacFileFilter()); allFileFiltersOut.append(getContourFileFilter()); allFileFiltersOut.append(getContourCellFileFilter()); allFileFiltersOut.append(getContourCellColorFileFilter()); allFileFiltersOut.append(getCoordinateRawFileFilter()); allFileFiltersOut.append(getCoordinateFiducialFileFilter()); allFileFiltersOut.append(getCoordinateInflatedFileFilter()); allFileFiltersOut.append(getCoordinateVeryInflatedFileFilter()); allFileFiltersOut.append(getCoordinateSphericalFileFilter()); allFileFiltersOut.append(getCoordinateEllipsoidalFileFilter()); allFileFiltersOut.append(getCoordinateCompressedFileFilter()); allFileFiltersOut.append(getCoordinateFlatFileFilter()); allFileFiltersOut.append(getCoordinateFlatLobarFileFilter()); allFileFiltersOut.append(getCoordinateHullFileFilter()); allFileFiltersOut.append(getCoordinateUnknownFileFilter()); allFileFiltersOut.append(getCoordinateGenericFileFilter()); allFileFiltersOut.append(getCutsFileFilter()); allFileFiltersOut.append(getDeformationFieldFileFilter()); allFileFiltersOut.append(getDeformationMapFileFilter()); allFileFiltersOut.append(getFociFileFilter()); allFileFiltersOut.append(getFociColorFileFilter()); allFileFiltersOut.append(getFociProjectionFileFilter()); allFileFiltersOut.append(getGeodesicDistanceFileFilter()); allFileFiltersOut.append(getImageSaveFileFilter()); allFileFiltersOut.append(getLatitudeLongitudeFileFilter()); allFileFiltersOut.append(getMetricFileFilter()); allFileFiltersOut.append(getMetricShapeFileFilter()); allFileFiltersOut.append(getPaintFileFilter()); allFileFiltersOut.append(getPaletteFileFilter()); allFileFiltersOut.append(getParamsFileFilter()); allFileFiltersOut.append(getProbAtlasFileFilter()); allFileFiltersOut.append(getRgbPaintFileFilter()); allFileFiltersOut.append(getRegionOfInterestFileFilter()); allFileFiltersOut.append(getSceneFileFilter()); allFileFiltersOut.append(getSectionFileFilter()); allFileFiltersOut.append(getSurfaceShapeFileFilter()); allFileFiltersOut.append(getTopographyFileFilter()); allFileFiltersOut.append(getTopologyClosedFileFilter()); allFileFiltersOut.append(getTopologyOpenFileFilter()); allFileFiltersOut.append(getTopologyCutFileFilter()); allFileFiltersOut.append(getTopologyCutLobarFileFilter()); allFileFiltersOut.append(getTopologyUnknownFileFilter()); allFileFiltersOut.append(getTopologyGenericFileFilter()); allFileFiltersOut.append(getTransformationMatrixFileFilter()); allFileFiltersOut.append(getTransformationDataFileFilter()); allFileFiltersOut.append(getVolumeAnatomyFileFilter()); allFileFiltersOut.append(getVolumeFunctionalFileFilter()); allFileFiltersOut.append(getVolumePaintFileFilter()); allFileFiltersOut.append(getVolumeProbAtlasFileFilter()); allFileFiltersOut.append(getVolumeRgbFileFilter()); allFileFiltersOut.append(getVolumeSegmentationFileFilter()); allFileFiltersOut.append(getVolumeVectorFileFilter()); allFileFiltersOut.append(getVolumeGenericFileFilter()); allFileFiltersOut.append(getVolumeFileAfniFilter()); allFileFiltersOut.append(getVolumeMultiFileAfniFilter()); allFileFiltersOut.append(getVolumeFileNiftiReadFilter()); allFileFiltersOut.append(getVolumeFileNiftiWriteFilter()); allFileFiltersOut.append(getVolumeMultiFileNiftiFilter()); allFileFiltersOut.append(getVolumeFileSpmMedxFilter()); allFileFiltersOut.append(getVolumeFileWuNilFilter()); allFileFiltersOut.append(getVtkModelFileFilter()); allFileFiltersOut.append(getVocabularyFileFilter()); allFileFiltersOut.append(getWustlRegionFileFilter()); allFileFiltersOut.append(getStudyCollectionFileFilter()); allFileFiltersOut.append(getStudyMetaDataFileFilter()); allFileFiltersOut.append(getSpecFileFilter()); allFileFiltersOut.append(getMdPlotFileFilter()); allFileFiltersOut.append(getNeurolucidaFileFilter()); allFileFiltersOut.append(getBrainVoyagerFileFilter()); allFileFiltersOut.append(getVtkSurfaceFileFilter()); allFileFiltersOut.append(getVtkXmlSurfaceFileFilter()); allFileFiltersOut.append(getByuSurfaceFileFilter()); allFileFiltersOut.append(getStlSurfaceFileFilter()); allFileFiltersOut.append(getStudio3DSurfaceFileFilter()); allFileFiltersOut.append(getWavefrontObjFileFilter()); allFileFiltersOut.append(getVrmlSurfaceFileFilter()); allFileFiltersOut.append(getSumaRgbFileFilter()); allFileFiltersOut.append(getTextFileFilter()); allFileFiltersOut.append(getCommaSeparatedValuesFileFilter()); allFileFiltersOut.append(getOpenInventorSurfaceFileFilter()); allFileFiltersOut.append(getFreeSurferAsciiSurfaceFileFilter()); allFileFiltersOut.append(getFreeSurferBinarySurfaceFileFilter()); allFileFiltersOut.append(getFreeSurferAsciiCurvatureFileFilter()); allFileFiltersOut.append(getFreeSurferBinaryCurvatureFileFilter()); allFileFiltersOut.append(getFreeSurferAsciiFunctionalFileFilter()); allFileFiltersOut.append(getFreeSurferBinaryFunctionalFileFilter()); allFileFiltersOut.append(getFreeSurferAsciiLabelFileFilter()); allFileFiltersOut.append(getAnalyzeVolumeFileFilter()); allFileFiltersOut.append(getMincVolumeFileFilter()); allFileFiltersOut.append(getMniObjSurfaceFileFilter()); allFileFiltersOut.append(getVtkVolumeFileFilter()); allFileFiltersOut.append(getRawVolumeFileFilter()); allFileFiltersOut.append(getGiftiCoordinateFileFilter()); allFileFiltersOut.append(getGiftiTopologyFileFilter()); allFileFiltersOut.append(getGiftiSurfaceFileFilter()); allFileFiltersOut.append(getGiftiFunctionalFileFilter()); allFileFiltersOut.append(getGiftiShapeFileFilter()); allFileFiltersOut.append(getGiftiLabelFileFilter()); allFileFiltersOut.append(getGiftiVectorFileFilter()); allFileFiltersOut.append(getSureFitVectorFileFilter()); allFileFiltersOut.append(getPDFFileFilter()); allFileFiltersOut.append(getHTMLFileFilter()); allFileFiltersOut.append(getZipFileFilter()); allFileFiltersOut.append(getPythonFileFilter()); allFileFiltersOut.append(getPerlFileFilter()); allFileFiltersOut.append(getBourneShellFileFilter()); allFileFiltersOut.append(getCShellFileFilter()); allFileFiltersOut.append(getWindowsBATFileFilter()); allFileFiltersOut.append(getCaretScriptFileFilter()); std::sort(allFileFiltersOut.begin(), allFileFiltersOut.end()); allFileFiltersOut.insert(allFileFiltersOut.begin(), getAnyFileFilter()); } /** * get all file Caret filters. */ void FileFilters::getAllCaretFileFilters(QStringList& allFileFiltersOut) { allFileFiltersOut.clear(); allFileFiltersOut.append(getAreaColorFileFilter()); allFileFiltersOut.append(getArealEstimationFileFilter()); allFileFiltersOut.append(getBorderGenericFileFilter()); allFileFiltersOut.append(getBorderColorFileFilter()); allFileFiltersOut.append(getBorderProjectionFileFilter()); allFileFiltersOut.append(getCellFileFilter()); allFileFiltersOut.append(getCellColorFileFilter()); allFileFiltersOut.append(getCellProjectionFileFilter()); allFileFiltersOut.append(getCocomacFileFilter()); allFileFiltersOut.append(getContourFileFilter()); allFileFiltersOut.append(getContourCellFileFilter()); allFileFiltersOut.append(getContourCellColorFileFilter()); allFileFiltersOut.append(getCoordinateGenericFileFilter()); allFileFiltersOut.append(getCutsFileFilter()); allFileFiltersOut.append(getDeformationFieldFileFilter()); allFileFiltersOut.append(getDeformationMapFileFilter()); allFileFiltersOut.append(getFociFileFilter()); allFileFiltersOut.append(getFociColorFileFilter()); allFileFiltersOut.append(getFociProjectionFileFilter()); allFileFiltersOut.append(getGeodesicDistanceFileFilter()); allFileFiltersOut.append(getLatitudeLongitudeFileFilter()); allFileFiltersOut.append(getMetricFileFilter()); allFileFiltersOut.append(getPaintFileFilter()); allFileFiltersOut.append(getPaletteFileFilter()); allFileFiltersOut.append(getParamsFileFilter()); allFileFiltersOut.append(getProbAtlasFileFilter()); allFileFiltersOut.append(getRgbPaintFileFilter()); allFileFiltersOut.append(getRegionOfInterestFileFilter()); allFileFiltersOut.append(getSceneFileFilter()); allFileFiltersOut.append(getSectionFileFilter()); allFileFiltersOut.append(getSpecFileFilter()); allFileFiltersOut.append(getStudyMetaDataFileFilter()); allFileFiltersOut.append(getSurfaceShapeFileFilter()); allFileFiltersOut.append(getTopographyFileFilter()); allFileFiltersOut.append(getTopologyGenericFileFilter()); allFileFiltersOut.append(getTransformationMatrixFileFilter()); allFileFiltersOut.append(getVolumeGenericFileFilter()); allFileFiltersOut.append(getWustlRegionFileFilter()); allFileFiltersOut.append(getCaretScriptFileFilter()); std::sort(allFileFiltersOut.begin(), allFileFiltersOut.end()); } caret-5.6.4~dfsg.1.orig/caret_files/FileException.h0000664000175000017500000000341611572067322021754 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __FILE_EXCEPTION_H__ #define __FILE_EXCEPTION_H__ #include #include class StatisticException; /// Exception involving data files class FileException : public std::exception { public: // Constructor FileException(const QString& msg); /// Constructor FileException(const QString& filename, const QString& msg); // Constructor FileException(const StatisticException& se); /// Destructor virtual ~FileException() throw(); /// get description of exception virtual QString whatQString() const throw(); protected: /// Description of the exception QString exceptionDescription; private: /// get description of exception (private to prevent its use) virtual const char* what() const throw() { return ""; } }; #endif // __FILE_EXCEPTION_H__ caret-5.6.4~dfsg.1.orig/caret_files/FileException.cxx0000664000175000017500000000343311572067322022326 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "FileException.h" #include "StatisticException.h" #include "StringUtilities.h" FileException::FileException(const QString& msg) { exceptionDescription = msg; } /** * Constructor. */ FileException::FileException(const QString& filename, const QString& msg) { QString s("Error "); s.append(filename); s.append(": "); s.append(msg); exceptionDescription = s; } /** * Constructor. */ FileException::FileException(const StatisticException& se) { exceptionDescription = StringUtilities::fromStdString(se.whatStdString()); } /** * Destructor. */ FileException::~FileException() throw() { } /** * Text message describing exception. */ /* const char* FileException::what() const throw() { return exceptionDescription.toAscii().constData(); } */ /** * Text message describing exception. */ QString FileException::whatQString() const throw() { return exceptionDescription; } caret-5.6.4~dfsg.1.orig/caret_files/DeformationMapFile.h0000664000175000017500000011106011572067322022716 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __DEFORMATION_MAP_FILE__CLASS_H__ #define __DEFORMATION_MAP_FILE__CLASS_H__ #include "AbstractFile.h" /// Deformation data for a node class DeformMapNodeData { public: /// tile's nodes int tileNodes[3]; /// tile's node's barycentric areas float tileBarycentric[3]; // constructor DeformMapNodeData(); }; /// class for file describing a deformation class DeformationMapFile : public AbstractFile{ public: /// type of deformation enum DEFORMATION_TYPE { DEFORMATION_TYPE_FLAT, DEFORMATION_TYPE_SPHERE, DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR, DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR }; /// border resampling type enum BORDER_RESAMPLING_TYPE { BORDER_RESAMPLING_NONE, BORDER_RESAMPLING_FROM_BORDER_FILE, BORDER_RESAMPLING_VALUE }; /// border file types enum BORDER_FILE_TYPE { BORDER_FILE_UNKNOWN, BORDER_FILE_FLAT, BORDER_FILE_FLAT_LOBAR, BORDER_FILE_SPHERICAL, BORDER_FILE_PROJECTION }; /// metric deform type enum METRIC_DEFORM_TYPE { METRIC_DEFORM_NEAREST_NODE, METRIC_DEFORM_AVERAGE_TILE_NODES }; enum { MAX_SPHERICAL_CYCLES = 50 }; enum { MAX_SPHERICAL_STAGES = 20 }; private: static const QString deformMapFileVersionTag; static const QString deformedFileNamePrefixTag; static const QString deformedColumnNamePrefixTag; static const QString sphereResolutionTag; static const QString borderResampleTag; static const QString sphericalNumberOfStagesTag; static const QString sphericalNumberOfCyclesTag; static const QString smoothingParamtersTag; static const QString morphingParametersTag; static const QString flatParametersTag; static const QString sphereFiducialSphereRatioTag; static const QString smoothDeformedSurfaceTag; static const QString landmarkVectorParametersTag; static const QString landmarkVectorStageParametersTag; static const QString sourceDirectoryTag; static const QString sourceSpecTag; static const QString sourceBorderTag; static const QString sourceClosedTopoTag; static const QString sourceCutTopoTag; static const QString sourceFiducialCoordTag; static const QString sourceSphericalCoordTag; static const QString sourceDeformedSphericalCoordTag; static const QString sourceDeformedFlatCoordTag; static const QString sourceFlatCoordTag; static const QString sourceResampledFlatCoordTag; static const QString sourceResampledDeformedFlatCoordTag; static const QString sourceResampledCutTopoTag; static const QString targetDirectoryTag; static const QString targetSpecTag; static const QString targetBorderTag; static const QString targetClosedTopoTag; static const QString targetCutTopoTag; static const QString targetFiducialCoordTag; static const QString targetSphericalCoordTag; static const QString targetFlatCoordTag; static const QString flatOrSphereSelectionTag; static const QString DeformationFlatValue; static const QString DeformationSphereValue; static const QString DeformationSphereSingleStageVectorValue; static const QString DeformationSphereMultiStageVectorValue; static const QString outputSpecFileTag; static const QString pauseForCrossoversConfirmationTag; static const QString inverseDeformationFlagTag; static const QString startOfDataTag; static const int DEFAULT_DEFORMATION_MAP_VERSION; /// read deformation files data void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException); /// write deformation files data void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException); /// Write a tag/value pair and make it relative to a directory void writeFileTagRelative(QTextStream& stream, const QString& directory, const QString& tag, const QString& valueIn); /// Write a tag/value pair and make it relative to a directory void writeFileTagRelative(QTextStream& stream, const QString& directory, const QString& tag, const QString valueIn[], const int index); /// deformation data for each node std::vector deformData; /// deformation type DEFORMATION_TYPE flatOrSphereSelection; /// name of source spec file QString sourceSpecFileName; /// name of source border file QString sourceBorderFileName; /// type of source border file BORDER_FILE_TYPE sourceBorderFileType; /// name of source closed topo file QString sourceClosedTopoFileName; /// name of source cut topo file QString sourceCutTopoFileName; /// name of source fiducial coord file QString sourceFiducialCoordFileName; /// name of source spherical coord file QString sourceSphericalCoordFileName; /// name of source deformed spherical coord file QString sourceDeformedSphericalCoordFileName; /// name of source deformed flat coord file QString sourceDeformedFlatCoordFileName; /// name of source flat coord file QString sourceFlatCoordFileName; /// name of source flat resampled coord file QString sourceResampledFlatCoordFileName; /// name of source resampled deformed flat file QString sourceResampledDeformedFlatCoordFileName; /// name of source resampled cut topo file QString sourceResampledCutTopoFileName; /// name of source directory QString sourceDirectoryName; /// name of target spec file QString targetSpecFileName; /// name of target border file QString targetBorderFileName[MAX_SPHERICAL_CYCLES]; /// type of target border file BORDER_FILE_TYPE targetBorderFileType[MAX_SPHERICAL_CYCLES]; /// name of target closed topo file QString targetClosedTopoFileName; /// name of target cut topo file QString targetCutTopoFileName; /// name of target fiducial coord file QString targetFiducialCoordFileName; /// name of target spherical coord file QString targetSphericalCoordFileName; /// name of target flat coord file QString targetFlatCoordFileName; /// name of target directory QString targetDirectoryName; /// name of output spec file QString outputSpecFileName; /// deformed file name prefix QString deformedFileNamePrefix; /// deformed column name prefix QString deformedColumnNamePrefix; /// index to sphere file's for different resolution spheres int sphereResolution[MAX_SPHERICAL_STAGES]; /// border resampling type BORDER_RESAMPLING_TYPE borderResampleType; /// border resampling value float borderResampleValue; /// number of spherical cycles int sphericalNumberOfCycles[MAX_SPHERICAL_STAGES]; /// nmber of spherical stages int sphericalNumberOfStages; /// smoothing strength at each cycle float smoothingStrength[MAX_SPHERICAL_STAGES][MAX_SPHERICAL_CYCLES]; /// number of smoothing cycles int smoothingCycles[MAX_SPHERICAL_STAGES][MAX_SPHERICAL_CYCLES]; /// number of smoothing iterations at each cycle int smoothingIterations[MAX_SPHERICAL_STAGES][MAX_SPHERICAL_CYCLES]; /// number of neighbor smoothing iterations at each cycle int smoothingNeighborIterations[MAX_SPHERICAL_STAGES][MAX_SPHERICAL_CYCLES]; /// number of final smoothing iterations at each cycle int smoothingFinalIterations[MAX_SPHERICAL_STAGES][MAX_SPHERICAL_CYCLES]; /// number of morphing cycles int morphingCycles[MAX_SPHERICAL_STAGES][MAX_SPHERICAL_CYCLES]; /// morphing linear force at each cycle float morphingLinearForce[MAX_SPHERICAL_STAGES][MAX_SPHERICAL_CYCLES]; /// morphing angular force at each cycle float morphingAngularForce[MAX_SPHERICAL_STAGES][MAX_SPHERICAL_CYCLES]; /// morphing step size at each cycle float morphingStepSize[MAX_SPHERICAL_STAGES][MAX_SPHERICAL_CYCLES]; /// morphing landmark step size at each cycle float morphingLandmarkStepSize[MAX_SPHERICAL_STAGES][MAX_SPHERICAL_CYCLES]; /// morphing iterations at each cycle int morphingIterations[MAX_SPHERICAL_STAGES][MAX_SPHERICAL_CYCLES]; /// morphing smoothing iterations at each cycle int morphingSmoothIterations[MAX_SPHERICAL_STAGES][MAX_SPHERICAL_CYCLES]; /// flat deformation sub sampling tiles int flatSubSamplingTiles; /// flat deformation beta parameter float flatBeta; /// flat deformation variance multiplier float flatVarMult; /// flat deformation number of iterations int flatNumIters; /// version of this deformation map file int fileVersion; /// inverse deformation flag bool inverseDeformationFlag; /// delete intermediate files flag bool deleteIntermediateFilesFlag; /// deform both ways flag (indiv-to-atlas and atlas-to-indiv) bool deformBothWaysFlag; /// metric deformation type METRIC_DEFORM_TYPE metricDeformationType; /// fiducial sphere ratio float fiducialSphereRatio; /// fiducial sphere ratio enabled bool fiducialSphereRatioEnabled; /// smoothe deformed surfaces flag bool smoothDeformedSurfacesFlag; /// landmark vector smoothing iterations int landmarkVectorSmoothingIteratons[MAX_SPHERICAL_STAGES][MAX_SPHERICAL_CYCLES]; /// landmark vector displacement factor float landmarkVectorDisplacementFactor[MAX_SPHERICAL_STAGES][MAX_SPHERICAL_CYCLES]; /// landmark vector endpoint factor float landmarkVectorEndpointFactor[MAX_SPHERICAL_STAGES]; bool pauseForCrossoversConfirmation; public: /// constructor DeformationMapFile(); /// destructor ~DeformationMapFile(); /// clear the data void clear(); /// see if the file is isEmpty bool empty() const { return deformData.empty(); } /// compare a file for unit testing (returns true if "within tolerance") virtual bool compareFileForUnitTesting(const AbstractFile* af, const float tolerance, QString& messageOut) const; /// get the version of the file int getFileVersion() const { return fileVersion; } /// get deform data for a node void getDeformDataForNode(const int nodeNumber, int tileNodesOut[3], float tileBarycentricOut[3]) const; /// get the deformed file name prefix QString getDeformedFileNamePrefix() const { return deformedFileNamePrefix; } /// get the deformed column name prefix QString getDeformedColumnNamePrefix() const { return deformedColumnNamePrefix; } /// get the delete intermediate files flag bool getDeleteIntermediateFiles() const { return deleteIntermediateFilesFlag; } /// get the deform both ways (I to A and A to I) bool getDeformBothWays() const { return deformBothWaysFlag; } /// get the flat/sphere deformation flag DEFORMATION_TYPE getFlatOrSphereSelection() const { return flatOrSphereSelection; } /// get the metric deformation type METRIC_DEFORM_TYPE getMetricDeformationType() const { return metricDeformationType; } /// get the number of nodes int getNumberOfNodes() const { return deformData.size(); } /// set deform data for a node void setDeformDataForNode(const int nodeNumber, const int tileNodesIn[3], const float tileBarycentricIn[3]); // set the number of nodes void setNumberOfNodes(const int numNodes); /// make paths in the filenames relative to the specified directory void makePathsRelative(const QString& path); /// make the file "name" relative to the path "path" void makeFileRelative(const QString& path, QString& name); /// Make the source files relative to a path. void makeSourceFilesRelativeToPath(const QString& path); /// Make the target files relative to a path. void makeTargetFilesRelativeToPath(const QString& path); /// get the source directory QString getSourceDirectory() const { return sourceDirectoryName; } /// get the source spec file name QString getSourceSpecFileName() const { return sourceSpecFileName; } /// get the source border file name void getSourceBorderFileName(QString& name, BORDER_FILE_TYPE& fileType) const { name = sourceBorderFileName; fileType = sourceBorderFileType; } /// get the source closed topo file name QString getSourceClosedTopoFileName() const { return sourceClosedTopoFileName; } /// get the source cut topo file name QString getSourceCutTopoFileName() const { return sourceCutTopoFileName; } /// get the source fiducial coord file name QString getSourceFiducialCoordFileName() const { return sourceFiducialCoordFileName; } /// get the source spherical coord file name QString getSourceSphericalCoordFileName() const { return sourceSphericalCoordFileName; } /// get the source deformed spherical coord file name QString getSourceDeformedSphericalCoordFileName() const { return sourceDeformedSphericalCoordFileName; } /// get the source deformed flat coord file name QString getSourceDeformedFlatCoordFileName() const { return sourceDeformedFlatCoordFileName; } /// get the source flat coord file name QString getSourceFlatCoordFileName() const { return sourceFlatCoordFileName; } /// get the source resampled flat coord file name QString getSourceResampledFlatCoordFileName() const { return sourceResampledFlatCoordFileName; } /// get the source deformed resampled float coord file name QString getSourceResampledDeformedFlatCoordFileName() const { return sourceResampledDeformedFlatCoordFileName; } /// get the source resampled cut file name QString getSourceResampledCutTopoFileName() const { return sourceResampledCutTopoFileName; } /// get the target directory QString getTargetDirectory() const { return targetDirectoryName; } /// get the target spec file name QString getTargetSpecFileName() const { return targetSpecFileName; } /// get the target border file name void getTargetBorderFileName(const int index, QString& name, BORDER_FILE_TYPE& fileType) const { name = targetBorderFileName[index]; fileType = targetBorderFileType[index]; } /// get the target closed topo file name QString getTargetClosedTopoFileName() const { return targetClosedTopoFileName; } /// get the target cut topo file name QString getTargetCutTopoFileName() const { return targetCutTopoFileName; } /// get the target fiducial coord file name QString getTargetFiducialCoordFileName() const { return targetFiducialCoordFileName; } /// get the target spherical file name QString getTargetSphericalCoordFileName() const { return targetSphericalCoordFileName; } /// get the target flat coord file name QString getTargetFlatCoordFileName() const { return targetFlatCoordFileName; } /// get the output spec file name QString getOutputSpecFileName() const { return outputSpecFileName; } /// set the deformed file name prefix void setDeformedFileNamePrefix(const QString& s) { deformedFileNamePrefix = s; } /// set the deformed column name prefix void setDeformedColumnNamePrefix(const QString& s) { deformedColumnNamePrefix = s; } /// set the delete intermediate files flag void setDeleteIntermediateFiles(const bool f) { deleteIntermediateFilesFlag = f; } /// set the deform both ways flag void setDeformBothWays(const bool f) { deformBothWaysFlag = f; } /// set the metric deformation type void setMetricDeformationType(const METRIC_DEFORM_TYPE mdt) { metricDeformationType = mdt; } /// set the source directory void setSourceDirectory(const QString& name) { sourceDirectoryName = name; setModified(); } /// set the source spec file name void setSourceSpecFileName(const QString& name) { sourceSpecFileName = name; setModified(); } /// set the source border file name void setSourceBorderFileName(const QString& name, const BORDER_FILE_TYPE fileType) { sourceBorderFileName = name; sourceBorderFileType = fileType; setModified(); } /// set the source closed topo file name void setSourceClosedTopoFileName(const QString& name) { sourceClosedTopoFileName = name; setModified(); } /// set the source cut topo file name void setSourceCutTopoFileName(const QString& name) { sourceCutTopoFileName = name; setModified(); } /// set the source fiducial coord file name void setSourceFiducialCoordFileName(const QString& name) { sourceFiducialCoordFileName = name; setModified(); } /// set the source spherical coord file name void setSourceSphericalCoordFileName(const QString& name) { sourceSphericalCoordFileName = name; setModified(); } /// set the source deformed spherical coord file name void setSourceDeformedSphericalCoordFileName(const QString& name) { sourceDeformedSphericalCoordFileName = name; setModified(); } /// set the source deformed flat coord file name void setSourceDeformedFlatCoordFileName(const QString& name) { sourceDeformedFlatCoordFileName = name; setModified(); } /// set the source flat coord file name void setSourceFlatCoordFileName(const QString& name) { sourceFlatCoordFileName = name; setModified(); } /// set the source resampled flat coord file name void setSourceResampledFlatCoordFileName(const QString& name) { sourceResampledFlatCoordFileName = name; setModified(); } /// set the source deformed resampled flat coord file name void setSourceResampledDeformedFlatCoordFileName(const QString& name) { sourceResampledDeformedFlatCoordFileName = name; setModified(); } /// set the file source resampled cut topo name void setSourceResampledCutTopoFileName(const QString& name) { sourceResampledCutTopoFileName = name; } /// set the target directory void setTargetDirectory(const QString& name) { targetDirectoryName = name; setModified(); } /// set the target spec file name void setTargetSpecFileName(const QString& name) { targetSpecFileName = name; setModified(); } /// set the target border file name void setTargetBorderFileName(const int index, const QString& name, const BORDER_FILE_TYPE fileType) { targetBorderFileName[index] = name; targetBorderFileType[index] = fileType; setModified(); } /// set the target closed topo file name void setTargetClosedTopoFileName(const QString& name) { targetClosedTopoFileName = name; setModified(); } /// set the target cut topo file name void setTargetCutTopoFileName(const QString& name) { targetCutTopoFileName = name; setModified(); } /// set the target fiducial coord file name void setTargetFiducialCoordFileName(const QString& name) { targetFiducialCoordFileName = name; setModified(); } /// set the target spherical coord file name void setTargetSphericalCoordFileName(const QString& name) { targetSphericalCoordFileName = name; setModified(); } /// set the target flat coord file name void setTargetFlatCoordFileName(const QString& name) { targetFlatCoordFileName = name; setModified(); } /// set the output spec file name void setOutputSpecFileName(const QString& name) { outputSpecFileName = name; setModified(); } /// set the type of deformation void setFlatOrSphereSelection(const DEFORMATION_TYPE foss) { flatOrSphereSelection = foss; setModified(); } /// get the sphere resolution index int getSphereResolution(const int stageNumber) const { return sphereResolution[stageNumber]; } /// get the spherical number of cycles int getSphericalNumberOfCycles(const int stageNumber) const { return sphericalNumberOfCycles[stageNumber]; } /// get the spherical number of stages int getSphericalNumberOfStages() const { return sphericalNumberOfStages; } /// get the border resampling parameters void getBorderResampling(BORDER_RESAMPLING_TYPE& resampleTypeOut, float& resampleValueOut) const { resampleTypeOut = borderResampleType; resampleValueOut = borderResampleValue; } /// get the smoothing parameters specific cycle void getSmoothingParameters(const int stageNumber, const int cycleNumber, float& strengthOut, int& cyclesOut, int& iterationsOut, int& neighborIterationsOut, int& finalIterationsOut) const { strengthOut = smoothingStrength[stageNumber][cycleNumber]; cyclesOut = smoothingCycles[stageNumber][cycleNumber]; iterationsOut = smoothingIterations[stageNumber][cycleNumber]; neighborIterationsOut = smoothingNeighborIterations[stageNumber][cycleNumber]; finalIterationsOut = smoothingFinalIterations[stageNumber][cycleNumber]; } /// get the morphing parameters for a specific cycle void getMorphingParameters(const int stageNumber, const int cycleNumber, int& cyclesOut, float& linearForceOut, float& angularForceOut, float& stepSizeOut, float& landmarkStepSizeOut, int& iterationsOut, int& smoothIterationsOut) const { cyclesOut = morphingCycles[stageNumber][cycleNumber]; linearForceOut = morphingLinearForce[stageNumber][cycleNumber]; angularForceOut = morphingAngularForce[stageNumber][cycleNumber]; stepSizeOut = morphingStepSize[stageNumber][cycleNumber]; landmarkStepSizeOut = morphingLandmarkStepSize[stageNumber][cycleNumber]; iterationsOut = morphingIterations[stageNumber][cycleNumber]; smoothIterationsOut = morphingSmoothIterations[stageNumber][cycleNumber]; } /// get the flat deformation parameters void getFlatParameters(int& subSamplingTilesOut, float& betaOut, float& varMultOut, int& numItersOut) const { subSamplingTilesOut = flatSubSamplingTiles; betaOut = flatBeta; varMultOut = flatVarMult; numItersOut = flatNumIters; } /// set the sphere resolution void setSphereResolution(const int stageNumber, const int sphereResolutionIn) { sphereResolution[stageNumber] = sphereResolutionIn; } /// set the spherical number of cycles void setSphericalNumberOfCycles(const int stageNumber, const int sphericalNumberOfCyclesIn) { sphericalNumberOfCycles[stageNumber] = sphericalNumberOfCyclesIn; } /// set the spherical number of stages void setSphericalNumberOfStages(const int sphericalNumberOfStagesIn) { sphericalNumberOfStages = sphericalNumberOfStagesIn; } /// set the border resampling parameters void setBorderResampling(const BORDER_RESAMPLING_TYPE resampleTypeIn, const float resampleValueIn) { borderResampleType = resampleTypeIn; borderResampleValue = resampleValueIn; setModified(); } /// set the smoothing parameters for a specific cycle void setSmoothingParameters(const int stageNumber, const int cycleNumber, const float strengthIn, const int cyclesIn, const int iterationsIn, const int neighborIterationsIn, const int finalIterationsIn) { smoothingStrength[stageNumber][cycleNumber] = strengthIn; smoothingCycles[stageNumber][cycleNumber] = cyclesIn; smoothingIterations[stageNumber][cycleNumber] = iterationsIn; smoothingNeighborIterations[stageNumber][cycleNumber] = neighborIterationsIn; smoothingFinalIterations[stageNumber][cycleNumber] = finalIterationsIn; setModified(); } /// set the morphing parameters for a specific cycle void setMorphingParameters(const int stageNumber, const int cycleNumber, const int cyclesIn, const float linearForceIn, const float angularForceIn, const float stepSizeIn, const float landmarkStepSizeIn, const int iterationsIn, const int smoothIterationsIn) { morphingCycles[stageNumber][cycleNumber] = cyclesIn; morphingLinearForce[stageNumber][cycleNumber] = linearForceIn; morphingAngularForce[stageNumber][cycleNumber] = angularForceIn; morphingStepSize[stageNumber][cycleNumber] = stepSizeIn; morphingLandmarkStepSize[stageNumber][cycleNumber] = landmarkStepSizeIn; morphingIterations[stageNumber][cycleNumber] = iterationsIn; morphingSmoothIterations[stageNumber][cycleNumber] = smoothIterationsIn; setModified(); } /// get the landmark vector parameters void getLandmarkVectorParameters(const int stageNumber, const int cycleNumber, int& vectorSmoothingIterations, float& vectorDisplacementFactor) const { vectorSmoothingIterations = landmarkVectorSmoothingIteratons[stageNumber][cycleNumber]; vectorDisplacementFactor = this->landmarkVectorDisplacementFactor[stageNumber][cycleNumber]; } /// get the landmark vector stage parameters void getLandmarkVectorStageParameters(const int stageNumber, float& vectorEndpointFactor) { vectorEndpointFactor = this->landmarkVectorEndpointFactor[stageNumber]; } /// set the landmark vector parameters void setLandmarkVectorParameters(const int stageNumber, const int cycleNumber, const int vectorSmoothingIterations, const float vectorDisplacementFactor) { landmarkVectorSmoothingIteratons[stageNumber][cycleNumber] = vectorSmoothingIterations; landmarkVectorDisplacementFactor[stageNumber][cycleNumber] = vectorDisplacementFactor; } /// set the landmark stage parameters void setLandmarkVectorStageParameters(const int stageNumber, const float vectorEndpointFactor) { landmarkVectorEndpointFactor[stageNumber] = vectorEndpointFactor; } /// set the flat morphing parameters void setFlatParameters(const int subSamplingTilesIn, const float betaIn, const float varMultIn, const int numItersIn) { flatSubSamplingTiles = subSamplingTilesIn; flatBeta = betaIn; flatVarMult = varMultIn; flatNumIters = numItersIn; setModified(); } /// get the inverse deformation flag bool getInverseDeformationFlag() const { return inverseDeformationFlag; } /// set the inverse deformation flag void setInverseDeformationFlag(const bool idf) { inverseDeformationFlag = idf; setModified(); } /// get the sphere fiducial ratios void getSphereFiducialRatio(bool& on, float& ratio) const { ratio = fiducialSphereRatio; on = fiducialSphereRatioEnabled; } /// set the sphere fiducial ratios void setSphereFiducialRatio(const bool on, const float ratio) { fiducialSphereRatio = ratio; fiducialSphereRatioEnabled = on; setModified(); } /// get smoot the deformed surfaces flag bool getSmoothDeformedSurfacesFlag() const { return smoothDeformedSurfacesFlag; } /// set smooth the deformed surfaces flag void setSmoothDeformedSurfacesFlag(const bool b) { smoothDeformedSurfacesFlag = b; setModified(); } /// switch the source files with the target files void swapSourceAndTargetFiles(); /// See if algorithm should get confirmation when there are crossovers bool getPauseForCrossoversConfirmation() { return pauseForCrossoversConfirmation; } /// Set if algorithm should get confirmation when there are crossovers void setPauseForCrossoversConfirmation(const bool pauseIt) { pauseForCrossoversConfirmation = pauseIt; } }; #endif // __DEFORMATION_MAP_FILE__CLASS_H__ #ifdef DEFORMATION_MAP_FILE_DEFINE const QString DeformationMapFile::deformMapFileVersionTag = "deform-map-file-version"; const QString DeformationMapFile::deformedFileNamePrefixTag = "deformed-file-name-prefix"; const QString DeformationMapFile::deformedColumnNamePrefixTag = "deformed-column-name-prefix"; const QString DeformationMapFile::sphereResolutionTag = "sphere-resolution"; const QString DeformationMapFile::borderResampleTag = "border-resampling"; const QString DeformationMapFile::sphericalNumberOfCyclesTag = "spherical-number-of-cycles"; const QString DeformationMapFile::sphericalNumberOfStagesTag = "spherical-number-of-stages"; const QString DeformationMapFile::smoothingParamtersTag = "smoothing-parameters"; const QString DeformationMapFile::morphingParametersTag = "morphing-parameters"; const QString DeformationMapFile::flatParametersTag = "flat-parameters"; const QString DeformationMapFile::sphereFiducialSphereRatioTag = "sphere-fiducial-sphere-ratio"; const QString DeformationMapFile::smoothDeformedSurfaceTag = "smooth-deformed-surface-flag"; const QString DeformationMapFile::landmarkVectorParametersTag = "landmark-vector-parameters"; const QString DeformationMapFile::landmarkVectorStageParametersTag = "landmark-vector-stage-parameters"; const QString DeformationMapFile::sourceDirectoryTag = "source-directory"; const QString DeformationMapFile::sourceSpecTag = "source-spec"; const QString DeformationMapFile::sourceBorderTag = "source-landmark-border"; const QString DeformationMapFile::sourceClosedTopoTag = "source-closed-topo"; const QString DeformationMapFile::sourceCutTopoTag = "source-cut-topo"; const QString DeformationMapFile::sourceFiducialCoordTag = "source-fiducial-coord"; const QString DeformationMapFile::sourceSphericalCoordTag = "source-sphere-coord"; const QString DeformationMapFile::sourceDeformedSphericalCoordTag = "source-deform-sphere-coord"; const QString DeformationMapFile::sourceDeformedFlatCoordTag = "source-deform-flat-coord"; const QString DeformationMapFile::sourceFlatCoordTag = "source-flat-coord"; const QString DeformationMapFile::sourceResampledFlatCoordTag = "source-resampled-flat-coord"; const QString DeformationMapFile::sourceResampledDeformedFlatCoordTag = "source-resampled-deformed-flat-coord"; const QString DeformationMapFile::sourceResampledCutTopoTag = "source-resampled-cut-topo"; const QString DeformationMapFile::targetDirectoryTag = "target-directory"; const QString DeformationMapFile::targetSpecTag = "target-spec"; const QString DeformationMapFile::targetBorderTag = "target-landmark-border"; const QString DeformationMapFile::targetClosedTopoTag = "target-closed-topo"; const QString DeformationMapFile::targetCutTopoTag = "target-cut-topo"; const QString DeformationMapFile::targetFiducialCoordTag = "target-fiducial-coord"; const QString DeformationMapFile::targetSphericalCoordTag = "target-sphere-coord"; const QString DeformationMapFile::targetFlatCoordTag = "target-flat-coord"; const QString DeformationMapFile::flatOrSphereSelectionTag = "flat-or-sphere"; const QString DeformationMapFile::DeformationFlatValue = "DEFORM_FLAT"; const QString DeformationMapFile::DeformationSphereValue = "DEFORM_SPHERE"; const QString DeformationMapFile::DeformationSphereMultiStageVectorValue = "DEFORM_SPHERE_VECTOR"; const QString DeformationMapFile::DeformationSphereSingleStageVectorValue = "DEFORM_SPHERE_VECTOR_SINGLE_STAGE"; const QString DeformationMapFile::outputSpecFileTag = "output-spec-file"; const QString DeformationMapFile::startOfDataTag = "DATA-START"; const QString DeformationMapFile::pauseForCrossoversConfirmationTag = "crossover-pause"; const QString DeformationMapFile::inverseDeformationFlagTag = "inverse-deformation"; const int DeformationMapFile::DEFAULT_DEFORMATION_MAP_VERSION = 3; #endif // DEFORMATION_MAP_FILE_DEFINE caret-5.6.4~dfsg.1.orig/caret_files/DeformationMapFile.cxx0000664000175000017500000011330611572067322023276 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #define DEFORMATION_MAP_FILE_DEFINE #include "DeformationMapFile.h" #undef DEFORMATION_MAP_FILE_DEFINE #include #include #include #include #include "FileUtilities.h" #include "SpecFile.h" /** * Constructor */ DeformMapNodeData::DeformMapNodeData() { tileNodes[0] = -1; tileNodes[1] = -1; tileNodes[2] = -1; tileBarycentric[0] = 0.0; tileBarycentric[1] = 0.0; tileBarycentric[2] = 0.0; } /** * Constructor */ DeformationMapFile::DeformationMapFile() : AbstractFile("Deformation Map File", SpecFile::getDeformationMapFileExtension(), true, FILE_FORMAT_ASCII, FILE_IO_READ_AND_WRITE, FILE_IO_READ_AND_WRITE, FILE_IO_NONE, FILE_IO_NONE) { clear(); } /** * Destructor */ DeformationMapFile::~DeformationMapFile() { clear(); } /** * compare a file for unit testing (returns true if "within tolerance"). */ bool DeformationMapFile::compareFileForUnitTesting(const AbstractFile* af, const float tolerance, QString& messageOut) const { messageOut = ""; const DeformationMapFile* dmf = dynamic_cast(af); if (dmf == NULL) { messageOut += "ERROR: File for comparison is not a Deformation Map File.\n"; return false; } const int numNodes = getNumberOfNodes(); if (numNodes != dmf->getNumberOfNodes()) { messageOut += "ERROR number of nodes do not match for file comparison."; return false; } for (int i = 0; i < numNodes; i++) { int tilesMe[3], tilesOther[3]; float areasMe[3], areasOther[3]; getDeformDataForNode(i, tilesMe, areasMe); dmf->getDeformDataForNode(i, tilesOther, areasOther); for (int i = 0; i < 3; i++) { if (tilesMe[i] != tilesOther[i]) { messageOut += "ERROR: There are tiles that do not match between the files.\n"; return false; } const float diff = std::fabs((float)(areasMe[i] != areasOther[i])); if (diff > tolerance) { messageOut +="ERROR: tile areas are not within tolerance."; return false; } } } return true; } /** * clear the contents of the file */ void DeformationMapFile::clear() { clearAbstractFile(); flatOrSphereSelection = DEFORMATION_TYPE_SPHERE; borderResampleType = BORDER_RESAMPLING_VALUE; borderResampleValue = 10.0; //15.0; sphericalNumberOfStages = 1; for (int i = 0; i < MAX_SPHERICAL_STAGES; i++) { sphericalNumberOfCycles[i] = 3; //1; sphereResolution[i] = 4610; //18434; for (int j = 0; j < MAX_SPHERICAL_CYCLES; j++) { smoothingStrength[i][j] = 1.0; smoothingCycles[i][j] = 100; smoothingIterations[i][j] = 20; smoothingNeighborIterations[i][j] = 10; smoothingFinalIterations[i][j] = 5; morphingCycles[i][j] = 1; morphingLinearForce[i][j] = 0.3; morphingAngularForce[i][j] = 0.4; morphingStepSize[i][j] = 0.5; morphingLandmarkStepSize[i][j] = 0.5; morphingIterations[i][j] = 80; morphingSmoothIterations[i][j] = 5; landmarkVectorSmoothingIteratons[i][j] = 10; landmarkVectorDisplacementFactor[i][j] = 1.0; landmarkVectorEndpointFactor[i] = 1.0; } smoothingStrength[i][0] = 1.0; smoothingCycles[i][0] = 100; smoothingIterations[i][0] = 20; smoothingNeighborIterations[i][0] = 10; smoothingFinalIterations[i][0] = 30; morphingCycles[i][0] = 1; morphingLinearForce[i][0] = 0.3; morphingAngularForce[i][0] = 0.6; morphingStepSize[i][0] = 0.5; morphingLandmarkStepSize[i][0] = 0.5; morphingIterations[i][0] = 300; morphingSmoothIterations[i][0] = 20; smoothingStrength[i][1] = 1.0; smoothingCycles[i][1] = 100; smoothingIterations[i][1] = 20; smoothingNeighborIterations[i][1] = 10; smoothingFinalIterations[i][1] = 5; morphingCycles[i][1] = 1; morphingLinearForce[i][1] = 0.3; morphingAngularForce[i][1] = 0.6; morphingStepSize[i][1] = 0.5; morphingLandmarkStepSize[i][1] = 0.5; morphingIterations[i][1] = 300; morphingSmoothIterations[i][1] = 5; smoothingStrength[i][2] = 1.0; smoothingCycles[i][2] = 50; smoothingIterations[i][2] = 20; smoothingNeighborIterations[i][2] = 10; smoothingFinalIterations[i][2] = 1; morphingCycles[i][2] = 1; morphingLinearForce[i][2] = 0.3; morphingAngularForce[i][2] = 0.6; morphingStepSize[i][2] = 0.5; morphingLandmarkStepSize[i][2] = 0.5; morphingIterations[i][2] = 300; morphingSmoothIterations[i][2] = 2; } fiducialSphereRatio = 0.5; fiducialSphereRatioEnabled = true; flatSubSamplingTiles = 900; flatBeta = 0.00001; flatVarMult = 1.0; flatNumIters = 20; fileVersion = DeformationMapFile::DEFAULT_DEFORMATION_MAP_VERSION; deformData.clear(); const QString noValue(""); setSourceDirectory(noValue); setSourceSpecFileName(noValue); setSourceBorderFileName(noValue, BORDER_FILE_UNKNOWN); setSourceClosedTopoFileName(noValue); setSourceCutTopoFileName(noValue); setSourceFiducialCoordFileName(noValue); setSourceSphericalCoordFileName(noValue); setSourceFlatCoordFileName(noValue); setSourceDeformedSphericalCoordFileName(noValue); setSourceDeformedFlatCoordFileName(noValue); setSourceResampledFlatCoordFileName(noValue); setSourceResampledDeformedFlatCoordFileName(noValue); setSourceResampledCutTopoFileName(noValue); setTargetDirectory(noValue); setTargetSpecFileName(noValue); for (int i = 0; i < MAX_SPHERICAL_STAGES; i++) { setTargetBorderFileName(i, noValue, BORDER_FILE_UNKNOWN); } setTargetClosedTopoFileName(noValue); setTargetCutTopoFileName(noValue); setTargetFiducialCoordFileName(noValue); setTargetSphericalCoordFileName(noValue); setTargetFlatCoordFileName(noValue); setOutputSpecFileName(noValue); inverseDeformationFlag = false; deleteIntermediateFilesFlag = true; deformBothWaysFlag = true; metricDeformationType = METRIC_DEFORM_NEAREST_NODE; deformedFileNamePrefix = "deformed_"; deformedColumnNamePrefix = "deformed_"; smoothDeformedSurfacesFlag = true; pauseForCrossoversConfirmation = false; } /** * Get the deformation for a node. */ void DeformationMapFile::getDeformDataForNode(const int nodeNumber, int tileNodesOut[3], float tileBarycentricOut[3]) const { for (int i = 0; i < 3; i++) { tileNodesOut[i] = deformData[nodeNumber].tileNodes[i]; tileBarycentricOut[i] = deformData[nodeNumber].tileBarycentric[i]; } } /** * Set the deformation for a node. */ void DeformationMapFile::setDeformDataForNode(const int nodeNumber, const int tileNodesIn[3], const float tileBarycentricIn[3]) { for (int i = 0; i < 3; i++) { deformData[nodeNumber].tileNodes[i] = tileNodesIn[i]; deformData[nodeNumber].tileBarycentric[i] = tileBarycentricIn[i]; } setModified(); } /** * Set the number of nodes for the file. */ void DeformationMapFile::setNumberOfNodes(const int numNodesIn) { deformData.resize(numNodesIn); setModified(); } /** * Make a filname relative to that "path". */ void DeformationMapFile::makeFileRelative(const QString& path, QString& name) { if (name.isEmpty() == false) { //printf("... %s is now: ", name); if (name[0] != '/') { return; } const QString filename(FileUtilities::basename(name)); QString filepath(FileUtilities::dirname(name)); QString result; FileUtilities::relativePath(filepath, path, result); if (result.isEmpty() == false) { QString s(result); s.append("/"); s.append(filename); name = s; } else { name = filename; } //printf("%s\n", name); } } /** * Make the source files relative to a path. */ void DeformationMapFile::makeSourceFilesRelativeToPath(const QString& path) { makeFileRelative(path, sourceSpecFileName); makeFileRelative(path, sourceBorderFileName); makeFileRelative(path, sourceClosedTopoFileName); makeFileRelative(path, sourceCutTopoFileName); makeFileRelative(path, sourceFiducialCoordFileName); makeFileRelative(path, sourceSphericalCoordFileName); makeFileRelative(path, sourceDeformedSphericalCoordFileName); makeFileRelative(path, sourceDeformedFlatCoordFileName); makeFileRelative(path, sourceFlatCoordFileName); makeFileRelative(path, sourceResampledFlatCoordFileName); makeFileRelative(path, sourceResampledDeformedFlatCoordFileName); makeFileRelative(path, sourceResampledCutTopoFileName); setModified(); } /** * Make the target files relative to a path. */ void DeformationMapFile::makeTargetFilesRelativeToPath(const QString& path) { makeFileRelative(path, targetSpecFileName); for (int i = 0; i < MAX_SPHERICAL_STAGES; i++) { makeFileRelative(path, targetBorderFileName[i]); } makeFileRelative(path, targetClosedTopoFileName); makeFileRelative(path, targetCutTopoFileName); makeFileRelative(path, targetFiducialCoordFileName); makeFileRelative(path, targetSphericalCoordFileName); makeFileRelative(path, targetFlatCoordFileName); makeFileRelative(path, outputSpecFileName); setModified(); } /** * make file name's relative paths. */ void DeformationMapFile::makePathsRelative(const QString& path) { makeSourceFilesRelativeToPath(path); makeTargetFilesRelativeToPath(path); } /** * Swap the source files with the target files. */ void DeformationMapFile::swapSourceAndTargetFiles() { std::swap(sourceDirectoryName, targetDirectoryName); std::swap(sourceSpecFileName, targetSpecFileName); std::swap(sourceBorderFileName, targetBorderFileName[0]); std::swap(sourceBorderFileType, targetBorderFileType[0]); std::swap(sourceClosedTopoFileName, targetClosedTopoFileName); std::swap(sourceCutTopoFileName, targetCutTopoFileName); std::swap(sourceFiducialCoordFileName, targetFiducialCoordFileName); std::swap(sourceSphericalCoordFileName, targetSphericalCoordFileName); std::swap(sourceFlatCoordFileName, targetFlatCoordFileName); } /** * Read the deformation map file's data. */ void DeformationMapFile::readFileData(QFile& /*file*/, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException) { // // first section of deformation file contains a list of files that // were used to perform deformation. // bool readingFiles = true; QString lastLineRead; while(readingFiles) { // // Read a line from the file // QString tag, tagValue; readTagLine(stream, lastLineRead, tag, tagValue); if (tag == startOfDataTag) { readingFiles = false; } else if (tag == deformMapFileVersionTag) { fileVersion = QString(tagValue).toInt(); if (fileVersion > DEFAULT_DEFORMATION_MAP_VERSION) { throw FileException( "The deformation map file is from a newer version of Caret. " "You need to update your Caret software."); } } else if (tag == deformedFileNamePrefixTag) { setDeformedFileNamePrefix(tagValue); } else if (tag == deformedColumnNamePrefixTag) { setDeformedColumnNamePrefix(tagValue); } else if (tag == sourceDirectoryTag) { setSourceDirectory(tagValue); } else if (tag == sourceSpecTag) { setSourceSpecFileName(tagValue); } else if (tag == sourceBorderTag) { setSourceBorderFileName(tagValue, BORDER_FILE_UNKNOWN); } else if (tag == sourceClosedTopoTag) { setSourceClosedTopoFileName(tagValue); } else if (tag == sourceCutTopoTag) { setSourceCutTopoFileName(tagValue); } else if (tag == sourceFiducialCoordTag) { setSourceFiducialCoordFileName(tagValue); } else if (tag == sourceSphericalCoordTag) { setSourceSphericalCoordFileName(tagValue); } else if (tag == sourceDeformedSphericalCoordTag) { setSourceDeformedSphericalCoordFileName(tagValue); } else if (tag == sourceDeformedFlatCoordTag) { setSourceDeformedFlatCoordFileName(tagValue); } else if (tag == sourceFlatCoordTag) { setSourceFlatCoordFileName(tagValue); } else if (tag == sourceResampledFlatCoordTag) { setSourceResampledFlatCoordFileName(tagValue); } else if (tag == sourceResampledDeformedFlatCoordTag) { setSourceResampledDeformedFlatCoordFileName(tagValue); } else if (tag == sourceResampledCutTopoTag) { setSourceResampledCutTopoFileName(tagValue); } else if (tag == targetDirectoryTag) { setTargetDirectory(tagValue); } else if (tag == targetSpecTag) { setTargetSpecFileName(tagValue); } else if (tag == targetBorderTag) { if (fileVersion >= 3) { int index = 0; QString name; QTextStream stream(&tagValue, QIODevice::ReadOnly); stream >> index >> name; setTargetBorderFileName(index, name, BORDER_FILE_UNKNOWN); } else { setTargetBorderFileName(0, tagValue, BORDER_FILE_UNKNOWN); } } else if (tag == targetClosedTopoTag) { setTargetClosedTopoFileName(tagValue); } else if (tag == targetCutTopoTag) { setTargetCutTopoFileName(tagValue); } else if (tag == targetFiducialCoordTag) { setTargetFiducialCoordFileName(tagValue); } else if (tag == targetSphericalCoordTag) { setTargetSphericalCoordFileName(tagValue); } else if (tag == targetFlatCoordTag) { setTargetFlatCoordFileName(tagValue); } else if (tag == outputSpecFileTag) { setOutputSpecFileName(tagValue); } else if (tag == sphereResolutionTag) { if (fileVersion >= 3) { int stageNumber = 0; int resolution = 4610; QTextStream textStream(&tagValue, QIODevice::ReadOnly); textStream >> stageNumber >> resolution; sphereResolution[stageNumber] = resolution; } else { sphereResolution[0] = tagValue.toInt(); } } else if (tag == flatOrSphereSelectionTag) { if (tagValue == DeformationFlatValue) { flatOrSphereSelection = DEFORMATION_TYPE_FLAT; } else if (tagValue == DeformationSphereValue) { flatOrSphereSelection = DEFORMATION_TYPE_SPHERE; } else if (tagValue == DeformationSphereMultiStageVectorValue) { flatOrSphereSelection = DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR; } else if (tagValue == DeformationSphereSingleStageVectorValue) { flatOrSphereSelection = DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR; } else { QString msg("ERROR invalid deformation flat/sphere value "); msg.append(tagValue); throw FileException(filename, msg); } } else if (tag == borderResampleTag) { QTextStream textStream(&tagValue, QIODevice::ReadOnly); int resampleTypeInt; textStream >> resampleTypeInt >> borderResampleValue; borderResampleType = static_cast(resampleTypeInt); } else if (tag == sphericalNumberOfStagesTag) { sphericalNumberOfStages = tagValue.toInt(); } else if (tag == sphericalNumberOfCyclesTag) { if (fileVersion >= 3) { int stageNumber = 0; int cycles = 3; QTextStream textStream(&tagValue, QIODevice::ReadOnly); textStream >> stageNumber >> cycles; sphericalNumberOfCycles[stageNumber] = cycles; } else { sphericalNumberOfCycles[0] = tagValue.toInt(); } } else if (tag == smoothingParamtersTag) { if (fileVersion >= 3) { int stageNumber; int cycleNumber; float strength; int cycles; int iterations; int neighborIterations; int finalIterations; QTextStream textStream(&tagValue, QIODevice::ReadOnly); textStream >> stageNumber >> cycleNumber >> strength >> cycles >> iterations >> neighborIterations >> finalIterations; smoothingStrength[stageNumber][cycleNumber] = strength; smoothingCycles[stageNumber][cycleNumber] = cycles; smoothingIterations[stageNumber][cycleNumber] = iterations; smoothingNeighborIterations[stageNumber][cycleNumber] = neighborIterations; smoothingFinalIterations[stageNumber][cycleNumber] = finalIterations; } else if (fileVersion > 0) { int cycleNumber; float strength; int cycles; int iterations; int neighborIterations; int finalIterations; QTextStream textStream(&tagValue, QIODevice::ReadOnly); textStream >> cycleNumber >> strength >> cycles >> iterations >> neighborIterations >> finalIterations; smoothingStrength[0][cycleNumber] = strength; smoothingCycles[0][cycleNumber] = cycles; smoothingIterations[0][cycleNumber] = iterations; smoothingNeighborIterations[0][cycleNumber] = neighborIterations; smoothingFinalIterations[0][cycleNumber] = finalIterations; } else { QTextStream textStream(&tagValue, QIODevice::ReadOnly); textStream >> smoothingStrength[0][0] >> smoothingCycles[0][0] >> smoothingIterations[0][0] >> smoothingNeighborIterations[0][0] >> smoothingFinalIterations[0][0]; } } else if (tag == landmarkVectorParametersTag) { if (fileVersion >= 3) { QTextStream textStream(&tagValue, QIODevice::ReadOnly); int stageNumber = 0; int cycleNumber = 0; textStream >> stageNumber; textStream >> cycleNumber; textStream >> landmarkVectorSmoothingIteratons[stageNumber][cycleNumber]; textStream >> landmarkVectorDisplacementFactor[stageNumber][cycleNumber]; } else { QTextStream textStream(&tagValue, QIODevice::ReadOnly); int cycleNumber = 0; textStream >> cycleNumber; if (textStream.atEnd() == false) { textStream >> landmarkVectorSmoothingIteratons[0][cycleNumber]; textStream >> landmarkVectorDisplacementFactor[0][cycleNumber]; } else { for (int mm = 0; mm < MAX_SPHERICAL_CYCLES; mm++) { landmarkVectorSmoothingIteratons[0][mm] = cycleNumber; } } } } else if (tag == landmarkVectorStageParametersTag) { QTextStream textStream(&tagValue, QIODevice::ReadOnly); int stageNumber = 0; textStream >> stageNumber; textStream >> landmarkVectorEndpointFactor[stageNumber]; } else if (tag == morphingParametersTag) { if (fileVersion >= 3) { int stageNumber; int cycleNumber; int cycles; float linearForce; float angularForce; float stepSize; float landmarkStepSize; int iterations; int smoothIterations; QTextStream textStream(&tagValue, QIODevice::ReadOnly); textStream >> stageNumber >> cycleNumber >> cycles >> linearForce >> angularForce >> stepSize >> landmarkStepSize >> iterations >> smoothIterations; morphingCycles[stageNumber][cycleNumber] = cycles; morphingLinearForce[stageNumber][cycleNumber] = linearForce; morphingAngularForce[stageNumber][cycleNumber] = angularForce; morphingStepSize[stageNumber][cycleNumber] = stepSize; morphingLandmarkStepSize[stageNumber][cycleNumber] = landmarkStepSize; morphingIterations[stageNumber][cycleNumber] = iterations; morphingSmoothIterations[stageNumber][cycleNumber] = smoothIterations; } else if (fileVersion > 0) { int cycleNumber; int cycles; float linearForce; float angularForce; float stepSize; float landmarkStepSize; int iterations; int smoothIterations; QTextStream textStream(&tagValue, QIODevice::ReadOnly); textStream >> cycleNumber >> cycles >> linearForce >> angularForce >> stepSize >> landmarkStepSize >> iterations >> smoothIterations; morphingCycles[0][cycleNumber] = cycles; morphingLinearForce[0][cycleNumber] = linearForce; morphingAngularForce[0][cycleNumber] = angularForce; morphingStepSize[0][cycleNumber] = stepSize; morphingLandmarkStepSize[0][cycleNumber] = landmarkStepSize; morphingIterations[0][cycleNumber] = iterations; morphingSmoothIterations[0][cycleNumber] = smoothIterations; } else { // // Some older files may only have 5 parameters // morphingCycles[0][0] = 1; morphingLandmarkStepSize[0][0] = morphingStepSize[0][0]; morphingSmoothIterations[0][0] = 0; QTextStream textStream(&tagValue, QIODevice::ReadOnly); textStream >> morphingCycles[0][0] >> morphingLinearForce[0][0] >> morphingAngularForce[0][0] >> morphingStepSize[0][0] >> morphingLandmarkStepSize[0][0] >> morphingIterations[0][0] >> morphingSmoothIterations[0][0]; } } else if (tag == inverseDeformationFlagTag) { inverseDeformationFlag = (tagValue == "true"); } else if (tag == pauseForCrossoversConfirmationTag) { pauseForCrossoversConfirmation = (tagValue == "true"); } else if (tag == flatParametersTag) { QTextStream textStream(&tagValue, QIODevice::ReadOnly); textStream >> flatSubSamplingTiles >> flatBeta >> flatVarMult >> flatNumIters; } else if (tag == startOfDataTag) { readingFiles = false; } else if (tag == sphereFiducialSphereRatioTag) { QTextStream istr(&tagValue, QIODevice::ReadOnly); QString enabled; istr >> enabled >> fiducialSphereRatio; fiducialSphereRatioEnabled = (enabled == "true"); } else if (tag == smoothDeformedSurfaceTag) { smoothDeformedSurfacesFlag = (tagValue == "true"); } else { std::cout << "WARNING unrecognzied deformation map file tag: " << tag.toAscii().constData() << std::endl; } } // // Should reading data be skipped ? // if (getReadMetaDataOnlyFlag()) { return; } switch (getFileReadType()) { case FILE_FORMAT_ASCII: { int numNodes; stream >> numNodes; setNumberOfNodes(numNodes); for (int i = 0; i < numNodes; i++) { int nodeNumber; int nodes[3]; float areas[3]; stream >> nodeNumber >> nodes[0] >> nodes[1] >> nodes[2] >> areas[0] >> areas[1] >> areas[2]; setDeformDataForNode(nodeNumber, nodes, areas); } } break; case FILE_FORMAT_BINARY: { #ifdef QT4_FILE_POS_BUG qint64 offset = findBinaryDataOffsetQT4Bug(file, lastLineRead.toAscii().constData()); if (offset > 0) { offset++; file.seek(offset); } #endif // QT4_FILE_POS_BUG // // Needed for QT 4.2.2 // binStream.device()->seek(stream.pos()); int numNodes; binStream >> numNodes; setNumberOfNodes(numNodes); for (int i = 0; i < numNodes; i++) { int nodes[3]; float areas[3]; binStream >> nodes[0] >> nodes[1] >> nodes[2] >> areas[0] >> areas[1] >> areas[2]; setDeformDataForNode(i, nodes, areas); } } break; case FILE_FORMAT_XML: throw FileException(filename, "Reading in XML format not supported."); break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "Reading XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "Reading XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Reading XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Reading in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Reading Comma Separated Value File Format not supported."); break; } } /** * Write a tag/value pair and make it relative to a directory */ void DeformationMapFile::writeFileTagRelative(QTextStream& stream, const QString& directory, const QString& tag, const QString& valueIn) { QString value = valueIn; // // Only do so for version 2 and later files // if (fileVersion >= 2) { if (directory.isEmpty() == false) { makeFileRelative(directory, value); } } stream << tag << " " << value << "\n"; } /** * Write a tag/value pair and make it relative to a directory */ void DeformationMapFile::writeFileTagRelative(QTextStream& stream, const QString& directory, const QString& tag, const QString valueIn[], const int index) { QString value = valueIn[index]; // // Only do so for version 2 and later files // if (fileVersion >= 2) { if (directory.isEmpty() == false) { makeFileRelative(directory, value); } } stream << tag << " " << index << " " << value << "\n"; } /** * Write the file's data. */ void DeformationMapFile::writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException) { fileVersion = DEFAULT_DEFORMATION_MAP_VERSION; stream << deformMapFileVersionTag << " " << fileVersion << "\n"; switch(flatOrSphereSelection) { case DEFORMATION_TYPE_FLAT: stream << flatOrSphereSelectionTag << " " << DeformationFlatValue << "\n"; break; case DEFORMATION_TYPE_SPHERE: stream << flatOrSphereSelectionTag << " " << DeformationSphereValue << "\n"; break; case DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: stream << flatOrSphereSelectionTag << " " << DeformationSphereMultiStageVectorValue << "\n"; break; case DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: stream << flatOrSphereSelectionTag << " " << DeformationSphereSingleStageVectorValue << "\n"; break; } stream << deformedFileNamePrefixTag << " " << deformedFileNamePrefix << "\n"; stream << deformedColumnNamePrefixTag << " " << deformedColumnNamePrefix << "\n"; stream << sourceDirectoryTag << " " << sourceDirectoryName << "\n"; writeFileTagRelative(stream, sourceDirectoryName, sourceSpecTag, sourceSpecFileName); writeFileTagRelative(stream, sourceDirectoryName, sourceBorderTag, sourceBorderFileName); writeFileTagRelative(stream, sourceDirectoryName, sourceClosedTopoTag, sourceClosedTopoFileName); writeFileTagRelative(stream, sourceDirectoryName, sourceCutTopoTag, sourceCutTopoFileName); writeFileTagRelative(stream, sourceDirectoryName, sourceFiducialCoordTag, sourceFiducialCoordFileName); writeFileTagRelative(stream, sourceDirectoryName, sourceSphericalCoordTag, sourceSphericalCoordFileName); writeFileTagRelative(stream, sourceDirectoryName, sourceDeformedSphericalCoordTag, sourceDeformedSphericalCoordFileName); writeFileTagRelative(stream, sourceDirectoryName, sourceDeformedFlatCoordTag, sourceDeformedFlatCoordFileName); writeFileTagRelative(stream, sourceDirectoryName, sourceFlatCoordTag, sourceFlatCoordFileName); writeFileTagRelative(stream, sourceDirectoryName, sourceResampledFlatCoordTag, sourceResampledFlatCoordFileName); writeFileTagRelative(stream, sourceDirectoryName, sourceResampledDeformedFlatCoordTag, sourceResampledDeformedFlatCoordFileName); writeFileTagRelative(stream, sourceDirectoryName, sourceResampledCutTopoTag, sourceResampledCutTopoFileName); for (int i = 0; i < sphericalNumberOfStages; i++) { stream << sphereResolutionTag << " " << i << " " << sphereResolution[i] << "\n"; } stream << borderResampleTag << " " << static_cast(borderResampleType) << " " << borderResampleValue << "\n"; stream << sphericalNumberOfStagesTag << " " << sphericalNumberOfStages << "\n"; for (int i = 0; i < sphericalNumberOfStages; i++) { stream << sphericalNumberOfCyclesTag << " " << i << " " << sphericalNumberOfCycles[i] << "\n"; } for (int i = 0; i < sphericalNumberOfStages; i++) { for (int j = 0; j < sphericalNumberOfCycles[i]; j++) { stream << smoothingParamtersTag << " " << i << " " << j << " " << smoothingStrength[i][j] << " " << smoothingCycles[i][j] << " " << smoothingIterations[i][j] << " " << smoothingNeighborIterations[i][j] << " " << smoothingFinalIterations[i][j] << "\n"; stream << morphingParametersTag << " " << i << " " << j << " " << morphingCycles[i][j] << " " << morphingLinearForce[i][j] << " " << morphingAngularForce[i][j] << " " << morphingStepSize[i][j] << " " << morphingLandmarkStepSize[i][j] << " " << morphingIterations[i][j] << " " << morphingSmoothIterations[i][j] << "\n"; stream << landmarkVectorParametersTag << " " << i << " " << j << " " << landmarkVectorSmoothingIteratons[i][j] << " " << landmarkVectorDisplacementFactor[i][j] << "\n"; } stream << landmarkVectorStageParametersTag << " " << i << " " << landmarkVectorEndpointFactor[i] << "\n"; } stream << flatParametersTag << " " << flatSubSamplingTiles << " " << flatBeta << " " << flatVarMult << " " << flatNumIters << "\n"; stream << targetDirectoryTag << " " << targetDirectoryName << "\n"; stream << smoothDeformedSurfaceTag << (smoothDeformedSurfacesFlag ? " true" : " false") << "\n"; writeFileTagRelative(stream, targetDirectoryName, targetSpecTag, targetSpecFileName); for (int i = 0; i < sphericalNumberOfStages; i++) { writeFileTagRelative(stream, targetDirectoryName, targetBorderTag, targetBorderFileName, i); } writeFileTagRelative(stream, targetDirectoryName, targetClosedTopoTag, targetClosedTopoFileName); writeFileTagRelative(stream, targetDirectoryName, targetCutTopoTag, targetCutTopoFileName); writeFileTagRelative(stream, targetDirectoryName, targetSphericalCoordTag, targetSphericalCoordFileName); writeFileTagRelative(stream, targetDirectoryName, targetFiducialCoordTag, targetFiducialCoordFileName); writeFileTagRelative(stream, targetDirectoryName, targetFlatCoordTag, targetFlatCoordFileName); writeFileTagRelative(stream, targetDirectoryName, outputSpecFileTag, outputSpecFileName); QString ratioString("false"); if (fiducialSphereRatioEnabled) { ratioString = "true"; } stream << sphereFiducialSphereRatioTag << " " << ratioString << " " << fiducialSphereRatio << "\n"; stream << pauseForCrossoversConfirmationTag << (pauseForCrossoversConfirmation ? " true" : " false") << "\n"; if (inverseDeformationFlag) { stream << inverseDeformationFlagTag << " true\n"; } else { stream << inverseDeformationFlagTag << " false\n"; } stream << startOfDataTag << "\n"; const int numNodes = getNumberOfNodes(); switch (getFileWriteType()) { case FILE_FORMAT_ASCII: stream << numNodes << "\n"; for (int i = 0; i < numNodes; i++) { int nodes[3]; float areas[3]; getDeformDataForNode(i, nodes, areas); stream << i << " " << nodes[0] << " " << nodes[1] << " " << nodes[2] << " " << areas[0] << " " << areas[1] << " " << areas[2] << "\n"; } break; case FILE_FORMAT_BINARY: #ifdef QT4_FILE_POS_BUG setBinaryFilePosQT4Bug(); #else // QT4_FILE_POS_BUG // // still a bug in QT 4.2.2 // setBinaryFilePosQT4Bug(); #endif // QT4_FILE_POS_BUG binStream << static_cast(numNodes); for (int i = 0; i < numNodes; i++) { int nodes[3]; float areas[3]; getDeformDataForNode(i, nodes, areas); binStream << static_cast(nodes[0]) << static_cast(nodes[1]) << static_cast(nodes[2]) << areas[0] << areas[1] << areas[2]; } break; case FILE_FORMAT_XML: throw FileException(filename, "Writing in XML format not supported."); break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Writing XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Writing in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Writing Comma Separated Value File Format not supported."); break; } } caret-5.6.4~dfsg.1.orig/caret_files/DeformationFieldFile.h0000664000175000017500000001622011572067322023226 0ustar michaelmichael #ifndef __DEFORMATION_FIELD_FILE_H__ #define __DEFORMATION_FIELD_FILE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "NodeAttributeFile.h" /// class for storing deformed barycentric location class DeformationFieldNodeInfo { public: /// constructor DeformationFieldNodeInfo(); /// destructor ~DeformationFieldNodeInfo(); /// get the data void getData(int tileNodesOut[3], float tileBarycentricAreasOut[3]) const; /// set the data void setData(const int tileNodesIn[3], const float tileBarycentricAreasIn[3]); /// reset the data void reset(); protected: /// nodes of tile containing deformed position int tileNodes[3]; /// barycentric areas of tile containing deformed position float tileBarycentricAreas[3]; }; /// class stores deformation field for a surface class DeformationFieldFile : public NodeAttributeFile { public: /// Constructor DeformationFieldFile(); /// Destructor ~DeformationFieldFile(); /// append a node attribute file to this one void append(NodeAttributeFile& naf) throw (FileException); /// append a node attribute file to this one but selectively load/overwrite columns /// columnDestination is where naf's columns should be (-1=new, -2=do not load) void append(NodeAttributeFile& naf, std::vector columnDestination, const FILE_COMMENT_MODE fcm) throw (FileException); /// add columns to this node attribute file void addColumns(const int numberOfNewColumns); /// add nodes to this file void addNodes(const int numberOfNodesToAdd); /// Clears current file data in memory. void clear(); /// deform "this" node attribute file placing the output in "deformedFile". void deformFile(const DeformationMapFile& dmf, NodeAttributeFile& deformedFile, const DEFORM_TYPE dt) const throw (FileException); /// set the number of nodes and columns in the file void setNumberOfNodesAndColumns(const int numNodes, const int numCols); /// reset a column of data void resetColumn(const int columnNumber); /// remove a column of data void removeColumn(const int columnNumber); /// get deformation field info for a node DeformationFieldNodeInfo* getDeformationInfo(const int node, const int column); /// get deformation field info for a node (const method) const DeformationFieldNodeInfo* getDeformationInfo(const int node, const int column) const; /// get the name of the pre-deformed coordinate file QString getPreDeformedCoordinateFileName(const int columnNumber) const; /// set the name of the pre-deformed coordinate file void setPreDeformedCoordinateFileName(const int columnNumber, const QString& name); /// get the name of the deformed coordinate file QString getDeformedCoordinateFileName(const int columnNumber) const; /// set the name of the deformed coordinate file void setDeformedCoordinateFileName(const int columnNumber, const QString& name); /// get the name of the deform topology file QString getDeformedTopologyFileName(const int columnNumber) const; /// set the name of the deform topology file void setDeformedTopologyFileName(const int columnNumber, const QString& name); /// get the name of the topology file QString getTopologyFileName(const int columnNumber) const; /// set the name of the topology file void setTopologyFileName(const int columnNumber, const QString& name); /// get the name of the coordinate file QString getCoordinateFileName(const int columnNumber) const; /// set the name of the coordinate file void setCoordinateFileName(const int columnNumber, const QString& name); /// Read the contents of the file (header has already been read) void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException); /// Write the file's data (header has already been written) void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException); protected: /// vector endpoints std::vector deformNodeInfo; /// the deforming topology files std::vector deformedTopologyFileName; /// the original coordinate file names std::vector preDeformedCoordinateFileName; /// the deformed coordinate file names std::vector deformedCoordinateFileName; /// coordinate file on which map computed std::vector coordinateFileName; /// topology file on which map computed std::vector topologyFileName; /// pre-deformed coordinate file tag static const QString tagPreDeformedCoordinateFile; /// deformed coordinate file tag static const QString tagDeformedCoordinateFile; /// deformed topology file tag static const QString tagDeformedTopologyFile; /// coordinate file tag static const QString tagCoordinateFile; /// topology file tag static const QString tagTopologyFile; }; #endif // __DEFORMATION_FIELD_FILE_H__ #ifdef __DEFORMATION_FIELD_FILE_MAIN__ const QString DeformationFieldFile::tagPreDeformedCoordinateFile = "tag-pre-deform-coord-file"; const QString DeformationFieldFile::tagDeformedCoordinateFile = "tag-deformed-coord-file"; const QString DeformationFieldFile::tagDeformedTopologyFile = "tag-deformed-topology-file"; const QString DeformationFieldFile::tagCoordinateFile = "tag-input-coord-file"; const QString DeformationFieldFile::tagTopologyFile = "tag-input-topology-file"; #endif // __DEFORMATION_FIELD_FILE_MAIN__ caret-5.6.4~dfsg.1.orig/caret_files/DeformationFieldFile.cxx0000664000175000017500000005444111572067322023610 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #define __DEFORMATION_FIELD_FILE_MAIN__ #include "DeformationFieldFile.h" #undef __DEFORMATION_FIELD_FILE_MAIN__ #include "SpecFile.h" #include "StringUtilities.h" /** * Constructor. */ DeformationFieldFile::DeformationFieldFile() : NodeAttributeFile("Deformation Field File", SpecFile::getDeformationFieldFileExtension(), AbstractFile::FILE_FORMAT_ASCII, FILE_IO_READ_AND_WRITE, FILE_IO_NONE, // no binary true, FILE_IO_NONE, FILE_IO_NONE) { clear(); } /** * Destructor. */ DeformationFieldFile::~DeformationFieldFile() { clear(); } /** * Clears current file data in memory. */ void DeformationFieldFile::clear() { clearNodeAttributeFile(); setNumberOfNodesAndColumns(0, 0); } /** * append a node attribute file to this one. */ void DeformationFieldFile::append(NodeAttributeFile& naf) throw (FileException) { if (naf.getNumberOfColumns() > 0) { std::vector columnDestination(naf.getNumberOfColumns(), APPEND_COLUMN_NEW); append(naf, columnDestination, FILE_COMMENT_MODE_APPEND); } } /** * append a node attribute file to this one but selectively load/overwrite columns * columnDestination is where naf's columns should be (-1=new, -2=do not load) */ void DeformationFieldFile::append(NodeAttributeFile& naf, std::vector columnDestinationIn, const FILE_COMMENT_MODE fcm) throw (FileException) { bool setTheFileNameFlag = false; std::vector columnDestination = columnDestinationIn; DeformationFieldFile& dff = dynamic_cast(naf); int numNodes = getNumberOfNodes(); const int numCols = getNumberOfColumns(); const int appendNumCols = dff.getNumberOfColumns(); const int appendNumNodes = dff.getNumberOfNodes(); if (numNodes != appendNumNodes) { if (numNodes > 0) { throw FileException("Cannot append DeformationFieldFile, number of columns does not match."); } else { numNodes = appendNumNodes; setTheFileNameFlag = true; } } setModified(); // // Find out how many columns need to be added // int numColumnsToAdd = 0; int newColumnIndex = numCols; for (int i = 0; i < dff.getNumberOfColumns(); i++) { if (columnDestination[i] == APPEND_COLUMN_NEW) { numColumnsToAdd++; columnDestination[i] = newColumnIndex; newColumnIndex++; } } // // Add additional columns to this file // addColumns(numColumnsToAdd); // // add new data // for (int n = 0; n < appendNumCols; n++) { if (columnDestination[n] >= 0) { // // Add column info // const int col = columnDestination[n]; columnNames[col] = dff.columnNames[n]; columnComments[col] = dff.columnComments[n]; // // Add file names // deformedTopologyFileName[col] = dff.deformedTopologyFileName[n]; preDeformedCoordinateFileName[col] = dff.preDeformedCoordinateFileName[n]; deformedCoordinateFileName[col] = dff.deformedCoordinateFileName[n]; coordinateFileName[col] = dff.coordinateFileName[n]; topologyFileName[col] = dff.topologyFileName[n]; // // Add deform node data // for (int i = 0; i < numNodes; i++) { const int index = getOffset(i, col); const int dffOffset = dff.getOffset(i, n); deformNodeInfo[index] = dff.deformNodeInfo[dffOffset]; } } } // // transfer the file's comment // appendFileComment(dff, fcm); } /** * add columns to this node attribute file. */ void DeformationFieldFile::addColumns(const int numberOfNewColumns) { int numNodes = getNumberOfNodes(); const int numCols = getNumberOfColumns(); setModified(); const int newNumCols = numCols + numberOfNewColumns; DeformationFieldFile defField; defField.setNumberOfNodesAndColumns(numNodes, newNumCols); // // transfer column names // for (int j = 0; j < numCols; j++) { defField.columnNames[j] = columnNames[j]; defField.columnComments[j] = columnComments[j]; } for (int n = 0; n < numberOfNewColumns; n++) { std::ostringstream str; str << "Column " << (numCols + n + 1) << " "; defField.columnNames[numCols + n] = str.str().c_str(); defField.columnComments[numCols + n] = str.str().c_str(); } // // Transfer the data // for (int i = 0; i < numNodes; i++) { for (int j = 0; j < numCols; j++) { const int index = defField.getOffset(i, j); const int otherIndex = getOffset(i, j); defField.deformNodeInfo[index] = deformNodeInfo[otherIndex]; } } numberOfColumns = newNumCols; numberOfNodes = defField.numberOfNodes; deformNodeInfo = defField.deformNodeInfo; columnNames = defField.columnNames; columnComments = defField.columnComments; } /** * add nodes to this file. */ void DeformationFieldFile::addNodes(const int numberOfNodesToAdd) { setNumberOfNodesAndColumns(numberOfNodes + numberOfNodesToAdd, numberOfColumns); } /** *deform "this" node attribute file placing the output in "deformedFile". */ void DeformationFieldFile::deformFile(const DeformationMapFile& /*dmf*/, NodeAttributeFile& /*deformedFile*/, const DEFORM_TYPE /*dt*/) const throw (FileException) { throw FileException( "Deformation of DeformationFieldFile files not supported."); } /** * set the number of nodes and columns in the file. */ void DeformationFieldFile::setNumberOfNodesAndColumns(const int numNodes, const int numColumns) { numberOfNodes = numNodes; numberOfColumns = numColumns; const int num = numberOfNodes * numberOfColumns * numberOfItemsPerColumn; if (num == 0) { deformNodeInfo.clear(); deformedTopologyFileName.clear(); preDeformedCoordinateFileName.clear(); deformedCoordinateFileName.clear(); coordinateFileName.clear(); topologyFileName.clear(); } else { deformNodeInfo.resize(num); deformedTopologyFileName.resize(num); preDeformedCoordinateFileName.resize(num); deformedCoordinateFileName.resize(num); coordinateFileName.resize(num); topologyFileName.resize(num); } numberOfNodesColumnsChanged(); setModified(); } /** * reset a column of data. */ void DeformationFieldFile::resetColumn(const int columnNumber) { for (int i = 0; i < numberOfNodes; i++) { const int offset = getOffset(i, columnNumber); deformNodeInfo[offset].reset(); } deformedTopologyFileName[columnNumber] = ""; preDeformedCoordinateFileName[columnNumber] = ""; deformedCoordinateFileName[columnNumber] = ""; coordinateFileName[columnNumber] = ""; topologyFileName[columnNumber] = ""; } /** * remove a column of data. */ void DeformationFieldFile::removeColumn(const int columnNumber) { if (numberOfColumns <= 1) { clear(); return; } // // Make a copy of this file // DeformationFieldFile dff = *this; // // Set columns that should be saved // std::vector columnsToAppend(numberOfColumns, APPEND_COLUMN_NEW); columnsToAppend[columnNumber] = APPEND_COLUMN_DO_NOT_LOAD; // // Clear this file // clear(); // // Append copied file to this file minus the column being removed // append(dff, columnsToAppend, FILE_COMMENT_MODE_APPEND); } /** * get deformation field info for a node. */ DeformationFieldNodeInfo* DeformationFieldFile::getDeformationInfo(const int node, const int column) { const int index = getOffset(node, column); if (index >= 0) { return &deformNodeInfo[index]; } return NULL; } /** * get deformation field info for a node (const method). */ const DeformationFieldNodeInfo* DeformationFieldFile::getDeformationInfo(const int node, const int column) const { const int index = getOffset(node, column); if (index >= 0) { return &deformNodeInfo[index]; } return NULL; } /** * get the name of the pre-deformed coordinate file. */ QString DeformationFieldFile::getPreDeformedCoordinateFileName(const int columnNumber) const { return preDeformedCoordinateFileName[columnNumber]; } /** * set the name of the pre-deformed coordinate file. */ void DeformationFieldFile::setPreDeformedCoordinateFileName(const int columnNumber, const QString& name) { preDeformedCoordinateFileName[columnNumber] = name; } /** * get the name of the deformed coordinate file. */ QString DeformationFieldFile::getDeformedCoordinateFileName(const int columnNumber) const { return deformedCoordinateFileName[columnNumber]; } /** * set the name of the deformed coordinate file. */ void DeformationFieldFile::setDeformedCoordinateFileName(const int columnNumber, const QString& name) { deformedCoordinateFileName[columnNumber] = name; } /** * get the name of the deformed topology file. */ QString DeformationFieldFile::getDeformedTopologyFileName(const int columnNumber) const { return deformedTopologyFileName[columnNumber]; } /** * set the name of the deformed topology file. */ void DeformationFieldFile::setDeformedTopologyFileName(const int columnNumber, const QString& name) { deformedTopologyFileName[columnNumber] = name; } /** * get the name of the topology file. */ QString DeformationFieldFile::getTopologyFileName(const int columnNumber) const { return topologyFileName[columnNumber]; } /** * set the name of the topology file. */ void DeformationFieldFile::setTopologyFileName(const int columnNumber, const QString& name) { topologyFileName[columnNumber] = name; } /** * get the name of the coordinate file. */ QString DeformationFieldFile::getCoordinateFileName(const int columnNumber) const { return coordinateFileName[columnNumber]; } /** * set the name of the coordinate file. */ void DeformationFieldFile::setCoordinateFileName(const int columnNumber, const QString& name) { coordinateFileName[columnNumber] = name; } /** * Read the contents of the file (header has already been read) */ void DeformationFieldFile::readFileData(QFile& /*file*/, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException) { int numNodes = -1; int numCols = -1; int fileVersion = -1; bool readingTags = true; while (readingTags) { QString tag, tagValue; readTagLine(stream, tag, tagValue); if (tag == tagFileVersion) { fileVersion = StringUtilities::toInt(tagValue); } else if (tag == tagNumberOfNodes) { if (tagValue.isEmpty()) { throw FileException(filename, "Reading line containing number of nodes"); } else { numNodes = tagValue.toInt(); if (numCols > 0) { setNumberOfNodesAndColumns(numNodes, numCols); } } } else if (tag == tagNumberOfColumns) { if (tagValue.isEmpty()) { throw FileException(filename, "Reading line containing number of columns"); } else { numCols = tagValue.toInt(); if (numNodes > 0) { setNumberOfNodesAndColumns(numNodes, numCols); } } } else if (tag == tagFileTitle) { fileTitle = tagValue; } else if (tag == tagBeginData) { readingTags = false; } else if (tag == tagColumnName) { QString name; const int index = splitTagIntoColumnAndValue(tagValue, name); columnNames[index] = name; } else if (tag == tagColumnComment) { QString name; const int index = splitTagIntoColumnAndValue(tagValue, name); columnComments[index] = StringUtilities::setupCommentForDisplay(name); } else if ((tag == tagPreDeformedCoordinateFile) || (tag == "tag-original-coord-file")) { QString name; const int index = splitTagIntoColumnAndValue(tagValue, name); preDeformedCoordinateFileName[index] = name; } else if (tag == tagDeformedCoordinateFile) { QString name; const int index = splitTagIntoColumnAndValue(tagValue, name); deformedCoordinateFileName[index] = name; } else if ((tag == tagDeformedTopologyFile) || (tag == "tag-topology-file")) { QString name; const int index = splitTagIntoColumnAndValue(tagValue, name); deformedTopologyFileName[index] = name; } else if (tag == tagTopologyFile) { QString name; const int index = splitTagIntoColumnAndValue(tagValue, name); topologyFileName[index] = name; } else if (tag == tagCoordinateFile) { QString name; const int index = splitTagIntoColumnAndValue(tagValue, name); coordinateFileName[index] = name; } else { std::cerr << "WARNING: Unknown DeformationFieldFile File Tag: " << tag.toAscii().constData() << std::endl; } } if (fileVersion != 1) { throw FileException(filename, "Only version 1 of DeformationFieldFile supported."); } // // Should reading data be skipped ? // if (getReadMetaDataOnlyFlag()) { return; } QString line; std::vector tokens; switch (getFileReadType()) { case FILE_FORMAT_ASCII: for (int i = 0; i < numberOfNodes; i++) { readLineIntoTokens(stream, line, tokens); if (static_cast(tokens.size()) < (numberOfColumns + 1)) { throw FileException(filename, "invalid def field line"); } const int offset = getOffset(i, 0); for (int j = 0; j < numberOfColumns; j++) { const int j6 = j * 6 + 1; int tileNodes[3]; float tileAreas[3]; tileNodes[0] = StringUtilities::toInt(tokens[j6]); tileNodes[1] = StringUtilities::toInt(tokens[j6+1]); tileNodes[2] = StringUtilities::toInt(tokens[j6+2]); tileAreas[0] = StringUtilities::toFloat(tokens[j6+3]); tileAreas[1] = StringUtilities::toFloat(tokens[j6+4]); tileAreas[2] = StringUtilities::toFloat(tokens[j6+5]); deformNodeInfo[offset+j].setData(tileNodes, tileAreas); } } break; case FILE_FORMAT_BINARY: binStream.device()->seek(stream.pos()); for (int i = 0; i < numberOfNodes; i++) { const int offset = getOffset(i, 0); for (int j = 0; j < numberOfColumns; j++) { int tileNodes[3]; float tileAreas[3]; binStream >> tileNodes[0] >> tileNodes[1] >> tileNodes[2]; binStream >> tileAreas[0] >> tileAreas[1] >> tileAreas[2]; deformNodeInfo[offset+j].setData(tileNodes, tileAreas); } } break; case FILE_FORMAT_XML: throw FileException(filename, "Reading in XML format not supported."); case FILE_FORMAT_XML_BASE64: throw FileException(filename, "Reading XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "Reading XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Reading XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Reading in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Reading Comma Separated Value File Format not supported."); break; } } /** * Write the file's data (header has already been written). */ void DeformationFieldFile::writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException) { stream << tagFileVersion << " " << 1 << "\n"; stream << tagNumberOfNodes << " " << numberOfNodes << "\n"; stream << tagNumberOfColumns << " " << numberOfColumns << "\n"; stream << tagFileTitle << " " << fileTitle << "\n"; for (int j = 0; j < numberOfColumns; j++) { stream << tagColumnName << " " << j << " " << columnNames[j] << "\n"; } for (int m = 0; m < numberOfColumns; m++) { stream << tagColumnComment << " " << m << " " << StringUtilities::setupCommentForStorage(columnComments[m]) << "\n"; } for (int m = 0; m < numberOfColumns; m++) { stream << tagPreDeformedCoordinateFile << " " << m << " " << preDeformedCoordinateFileName[m] << "\n"; } for (int m = 0; m < numberOfColumns; m++) { stream << tagDeformedCoordinateFile << " " << m << " " << deformedCoordinateFileName[m] << "\n"; } for (int m = 0; m < numberOfColumns; m++) { stream << tagDeformedTopologyFile << " " << m << " " << deformedTopologyFileName[m] << "\n"; } for (int m = 0; m < numberOfColumns; m++) { stream << tagTopologyFile << " " << m << " " << topologyFileName[m] << "\n"; } for (int m = 0; m < numberOfColumns; m++) { stream << tagCoordinateFile << " " << m << " " << coordinateFileName[m] << "\n"; } stream << tagBeginData << "\n"; switch (getFileWriteType()) { case FILE_FORMAT_ASCII: for (int i = 0; i < numberOfNodes; i++) { stream << i; const int offset = getOffset(i, 0); for (int j = 0; j < numberOfColumns; j++) { int tileNodes[3]; float tileAreas[3]; deformNodeInfo[offset + j].getData(tileNodes, tileAreas); stream << " " << tileNodes[0] << " " << tileNodes[1] << " " << tileNodes[2] << " " << tileAreas[0] << " " << tileAreas[1] << " " << tileAreas[2]; } stream << "\n"; } break; case FILE_FORMAT_BINARY: setBinaryFilePosQT4Bug(); for (int i = 0; i < numberOfNodes; i++) { const int offset = getOffset(i, 0); for (int j = 0; j < numberOfColumns; j++) { int tileNodes[3]; float tileAreas[3]; deformNodeInfo[offset + j].getData(tileNodes, tileAreas); binStream << tileNodes[0] << tileNodes[1] << tileNodes[2] << tileAreas[0] << tileAreas[1] << tileAreas[2]; } } break; case FILE_FORMAT_XML: throw FileException(filename, "Writing in XML format not supported."); case FILE_FORMAT_XML_BASE64: throw FileException(filename, "XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Writing XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Writing in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Writing Comma Separated Value File Format not supported."); break; } } //************************************************************************************** /** * Constructor */ DeformationFieldNodeInfo::DeformationFieldNodeInfo() { reset(); } /** * destructor. */ DeformationFieldNodeInfo::~DeformationFieldNodeInfo() { } /** * Reset the data. */ void DeformationFieldNodeInfo::reset() { tileNodes[0] = -1; tileNodes[1] = -1; tileNodes[2] = -1; tileBarycentricAreas[0] = 0.0; tileBarycentricAreas[1] = 0.0; tileBarycentricAreas[2] = 0.0; } /** * get the data. */ void DeformationFieldNodeInfo::getData(int tileNodesOut[3], float tileBarycentricAreasOut[3]) const { tileNodesOut[0] = tileNodes[0]; tileNodesOut[1] = tileNodes[1]; tileNodesOut[2] = tileNodes[2]; tileBarycentricAreasOut[0] = tileBarycentricAreas[0]; tileBarycentricAreasOut[1] = tileBarycentricAreas[1]; tileBarycentricAreasOut[2] = tileBarycentricAreas[2]; } /** * set the data. */ void DeformationFieldNodeInfo::setData(const int tileNodesIn[3], const float tileBarycentricAreasIn[3]) { tileNodes[0] = tileNodesIn[0]; tileNodes[1] = tileNodesIn[1]; tileNodes[2] = tileNodesIn[2]; tileBarycentricAreas[0] = tileBarycentricAreasIn[0]; tileBarycentricAreas[1] = tileBarycentricAreasIn[1]; tileBarycentricAreas[2] = tileBarycentricAreasIn[2]; } caret-5.6.4~dfsg.1.orig/caret_files/CutsFile.h0000664000175000017500000000223511572067322020732 0ustar michaelmichael #ifndef __CUTS_FILE_H__ #define __CUTS_FILE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BorderFile.h" /// class for cuts file class CutsFile : public BorderFile { public: /// Constructor CutsFile(); /// Destructor ~CutsFile(); protected: }; #endif // __CUTS_FILE_H__ caret-5.6.4~dfsg.1.orig/caret_files/CutsFile.cxx0000664000175000017500000000210111572067322021275 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CutsFile.h" #include "SpecFile.h" /** * Constructor */ CutsFile::CutsFile() : BorderFile("Cuts File", SpecFile::getCutsFileExtension()) { } /** * Destructor */ CutsFile::~CutsFile() { } caret-5.6.4~dfsg.1.orig/caret_files/CoordinateFile.h0000664000175000017500000002075011572067322022105 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __COORDINATE_FILE_H__ #define __COORDINATE_FILE_H__ #include "GiftiNodeDataFile.h" #include "BrainVoyagerFile.h" #include "FileException.h" #include "FreeSurferSurfaceFile.h" class MetricFile; class MniObjSurfaceFile; class TransformationMatrix; class vtkPolyData; /// Coordinate File /** * File for storing, reading, and writing a Caret coordinate file */ class CoordinateFile : public GiftiNodeDataFile { public: // constructor CoordinateFile(); // copy constructor CoordinateFile(const CoordinateFile& cf); // destructor ~CoordinateFile(); // assignment operator CoordinateFile& operator=(const CoordinateFile& cf); // add a coordinate to the coordinate file void addCoordinate(const float xyz[3]); // Apply transformation matrix to coordinate file void applyTransformationMatrix(const TransformationMatrix& tm); // clear the coordinate file void clear(); // get the coordinates out of a brain voyager file void importFromBrainVoyagerFile(const BrainVoyagerFile& bvf); // get the coordinates out of a free surfer surface file void importFromFreeSurferSurfaceFile(const FreeSurferSurfaceFile& fssf, const int numNodes = -1) throw (FileException); // add the coordinates to of a free surfer surface file void exportToFreeSurferSurfaceFile(FreeSurferSurfaceFile& fssf); // Get the coordinates out of a vtkPolyData object void importFromVtkFile(vtkPolyData* polyData); /// get the coordinates from a MNI OBJ surface file void importFromMniObjSurfaceFile(const MniObjSurfaceFile& mni) throw (FileException); /// returns true if the file is isEmpty (contains no data) bool empty() const { return (getNumberOfNodes() == 0); } // get the bounds of the coordindate file void getBounds(float bounds[6]) const; // get a coordinate void getCoordinate(const int coordinateNumber, float& x, float& y, float& z) const; // get a coordinate void getCoordinate(const int coordinateNumber, double& x, double& y, double& z) const; // get a coordinate void getCoordinate(const int coordinateNumber, float xyz[3]) const; // get a coordinate as doubles void getCoordinate(const int coordinateNumber, double xyz[3]) const; // get a coordinate float* getCoordinate(const int coordinateNumber); // get a coordinate (const method) const float* getCoordinate(const int coordinateNumber) const; // get all coordinates (3 elements per coordinate) void getAllCoordinates(std::vector& coordsOut) const; // get all coordinates (allocate coords to 3 * getNumberOfCoordinates()) void getAllCoordinates(float* coordsOut) const; // set all coordinates (3 elements per coordinate) void setAllCoordinates(const std::vector& coordsIn); // set all coordinates (allocate coords to 3 * getNumberOfCoordinates()) void setAllCoordinates(const float* coordsIn); // set a coordinate void setCoordinate(const int coordinateNumber, const float x, const float y, const float z); // set a coordinate void setCoordinate(const int coordinateNumber, const double x, const double y, const double z); // set a coordinate void setCoordinate(const int coordinateNumber, const float xyz[3]); // set a coordinate void setCoordinate(const int coordinateNumber, const double xyz[3]); // get coordinate closest to a point int getCoordinateIndexClosestToPoint( const float x, const float y, const float z, const int startSearchAtCoordinateIndex = 0) const; // get coordinate closest to a point int getCoordinateIndexClosestToPoint( const float xyz[3], const int startSearchAtCoordinateIndex = 0) const; /// get the number of coordinates int getNumberOfCoordinates() const { return getNumberOfNodes(); } /// set the number of coordinates void setNumberOfCoordinates(const int numCoordinates); // get the distance between two coordinates float getDistanceBetweenCoordinates(const int c1, const int c2) const; // get the distance squared between two coordinates float getDistanceBetweenCoordinatesSquared(const int c1, const int c2) const; // get the distance from a 3D point to a coordinate float getDistanceToPoint(const int coordIndex, const float* point3D) const; // get the distance squared from a 3D point to a coordinate float getDistanceToPointSquared(const int coordIndex, const float* point3D) const; // compute shuffled average coordinate files static void createShuffledAverageCoordinatesFiles(const std::vector& files, const int numberInGroup1, CoordinateFile& coordFileOut1, CoordinateFile& coordFileOut2) throw (FileException); // compute an average coordinate file static void createAverageCoordinateFile(const std::vector& files, CoordinateFile& averageFile, MetricFile* ssf = NULL) throw (FileException); // deform "this" node data file placing the output in "deformedFile". virtual void deformFile(const DeformationMapFile& dmf, GiftiNodeDataFile& deformedFile, const DEFORM_TYPE dt) const throw (FileException); // apply GIFTI transformation matrix void applyGiftiTransformationMatrix(); // get spec file tag from configuration id QString getSpecFileTagUsingConfigurationID() const; // convert configuration ID to spec file tag static QString convertConfigurationIDToSpecFileTag(const QString& configID); /// Update the file's metadata for Caret6 virtual void updateMetaDataForCaret6(); /// write the file's memory in caret6 format to the specified name virtual QString writeFileInCaret6Format(const QString& filenameIn, Structure structure,const ColorFile* colorFileIn, const bool useCaret6ExtensionFlag) throw (FileException); protected: // copy helper used by assignment operator and copy constructor void copyHelperCoordinate(const CoordinateFile& mf); // read coordinate file data void readLegacyNodeFileData(QFile& file, QTextStream& stream, QDataStream& binStream) throw (FileException); // write coordinate file data void writeLegacyNodeFileData(QTextStream& stream, QDataStream& binStream) throw (FileException); // // NOTE: If any variables are added be sure to update the copy constructor. // friend class BrainModelSurface; }; #endif // __COORDINATE_FILE_H__ caret-5.6.4~dfsg.1.orig/caret_files/CoordinateFile.cxx0000664000175000017500000010660311572067322022462 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include "CoordinateFile.h" #include "DebugControl.h" #include "FileUtilities.h" #include "MathUtilities.h" #include "MniObjSurfaceFile.h" #include "GiftiDataArray.h" #include "MetricFile.h" #include "SpecFile.h" #include "StatisticDataGroup.h" #include "StatisticMeanAndDeviation.h" #include "StatisticRandomNumber.h" #include "StatisticRandomNumberOperator.h" #include "StringUtilities.h" #include "TransformationMatrixFile.h" #include "vtkBase64Utilities.h" #include "vtkPolyData.h" #define USE_VTK_BASE64 /** * The constructor. */ CoordinateFile::CoordinateFile() : GiftiNodeDataFile("Coordinate File", GiftiCommon::intentCoordinates, GiftiDataArray::DATA_TYPE_FLOAT32, 3, SpecFile::getCoordinateFileExtension(), FILE_FORMAT_ASCII, FILE_IO_READ_AND_WRITE, FILE_IO_READ_AND_WRITE, FILE_IO_NONE, FILE_IO_NONE) { clear(); } /** * The copy constructor. */ CoordinateFile::CoordinateFile(const CoordinateFile& cf) : GiftiNodeDataFile(cf) { copyHelperCoordinate(cf); } /** * The destructor. */ CoordinateFile::~CoordinateFile() { clear(); } /** * assignment operator. */ CoordinateFile& CoordinateFile::operator=(const CoordinateFile& cf) { if (this != &cf) { GiftiNodeDataFile::operator=(cf); copyHelperCoordinate(cf); } return *this; } /** * copy helper used by assignment operator and copy constructor. */ void CoordinateFile::copyHelperCoordinate(const CoordinateFile& /* cf */) { } /** * Add a coordinate to the file. */ void CoordinateFile::addCoordinate(const float xyz[3]) { addNodes(1); float* coords = &dataArrays[0]->getDataPointerFloat()[0]; const int indx = getNumberOfNodes() - 1; coords[indx*3] = xyz[0]; coords[indx*3 + 1] = xyz[1]; coords[indx*3 + 2] = xyz[2]; } /** * apply GIFTI transformation matrix. */ void CoordinateFile::applyGiftiTransformationMatrix() { if (getNumberOfDataArrays() > 0) { GiftiDataArray* gda = getDataArray(0); GiftiMatrix* bestMatrix = NULL; const int num = gda->getNumberOfMatrices(); for (int i = 0; i < num; i++) { GiftiMatrix* gm = gda->getMatrix(i); if (gm->getDataSpaceName() == GiftiCommon::spaceLabelTalairach) { // // If data is already Talairach, do not need to do anything to the data // return; } else if (gm->getTransformedSpaceName() == GiftiCommon::spaceLabelTalairach) { // // This matrix will make the coordinates Talairach // bestMatrix = gm; } } // // If a matrix was found, apply it // if (bestMatrix != NULL) { double m[4][4]; bestMatrix->getMatrix(m); TransformationMatrix tm; tm.setMatrix(m); applyTransformationMatrix(tm); gda->removeAllMatrices(); GiftiMatrix gm; gm.setDataSpaceName(GiftiCommon::spaceLabelTalairach); gm.setTransformedSpaceName(GiftiCommon::spaceLabelTalairach); gda->addMatrix(gm); } } } /** * Apply transformation matrix to coordinate file. */ void CoordinateFile::applyTransformationMatrix(const TransformationMatrix& tmIn) { TransformationMatrix& tm = const_cast(tmIn); const int num = getNumberOfCoordinates(); float* coords = dataArrays[0]->getDataPointerFloat(); for (int i = 0; i < num; i++) { float p[3] = { coords[i*3], coords[i*3+1], coords[i*3+2] }; tm.multiplyPoint(p); coords[i*3] = p[0]; coords[i*3+1] = p[1]; coords[i*3+2] = p[2]; } setModified(); } /** * Clear the coordinate file. */ void CoordinateFile::clear() { GiftiNodeDataFile::clear(); } /** * Set the number of coordinates and initialize the coordinates to all zeros. */ void CoordinateFile::setNumberOfCoordinates(const int numCoordinates) { setNumberOfNodesAndColumns(numCoordinates, 1, 3); setModified(); } /** * Get a coordinate at the specified index. No check is made of index validity. */ void CoordinateFile::getCoordinate(const int coordinateNumber, float& x, float& y, float& z) const { float* coords = dataArrays[0]->getDataPointerFloat(); x = coords[coordinateNumber * 3]; y = coords[coordinateNumber * 3 + 1]; z = coords[coordinateNumber * 3 + 2]; } /** * Get a coordinate at the specified index. No check is made of index validity. */ void CoordinateFile::getCoordinate(const int coordinateNumber, double& x, double& y, double& z) const { float* coords = dataArrays[0]->getDataPointerFloat(); x = coords[coordinateNumber * 3]; y = coords[coordinateNumber * 3 + 1]; z = coords[coordinateNumber * 3 + 2]; } /** * Get a coordinate at the specified index. No check is made of index validity. */ void CoordinateFile::getCoordinate(const int coordinateNumber, float xyz[3]) const { float* coords = dataArrays[0]->getDataPointerFloat(); xyz[0] = coords[coordinateNumber * 3]; xyz[1] = coords[coordinateNumber * 3 + 1]; xyz[2] = coords[coordinateNumber * 3 + 2]; } /** * Get a coordinate at the specified index. No check is made of index validity. */ void CoordinateFile::getCoordinate(const int coordinateNumber, double xyz[3]) const { float* coords = dataArrays[0]->getDataPointerFloat(); xyz[0] = coords[coordinateNumber * 3]; xyz[1] = coords[coordinateNumber * 3 + 1]; xyz[2] = coords[coordinateNumber * 3 + 2]; } /** * Get a coordinate at the specified index. No check is made of index validity. * Returns const pointer to XYZ coordinates. */ const float* CoordinateFile::getCoordinate(const int coordinateNumber) const { return &dataArrays[0]->getDataPointerFloat()[coordinateNumber * 3]; } /** * Get a coordinate at the specified index. No check is made of index validity. * Returns pointer to XYZ coordinates. */ float* CoordinateFile::getCoordinate(const int coordinateNumber) { return &dataArrays[0]->getDataPointerFloat()[coordinateNumber * 3]; } /** * get all coordinates (3 elements per coordinate). */ void CoordinateFile::getAllCoordinates(std::vector& coordsOut) const { float* coords = dataArrays[0]->getDataPointerFloat(); const int num = getNumberOfNodes() * 3; coordsOut.clear(); for (int i = 0; i < num; i++) { coordsOut.push_back(coords[i]); } } /** * get all coordinates (allocate coords to 3 * getNumberOfCoordinates()). */ void CoordinateFile::getAllCoordinates(float* coordsOut) const { float* coords = dataArrays[0]->getDataPointerFloat(); const int num = 3 * getNumberOfCoordinates(); for (int i = 0; i < num; i += 3) { coordsOut[i] = coords[i]; coordsOut[i+1] = coords[i+1]; coordsOut[i+2] = coords[i+2]; } } /** * set all coordinates (3 elements per coordinate). */ void CoordinateFile::setAllCoordinates(const std::vector& coordsIn) { float* coords = dataArrays[0]->getDataPointerFloat(); const int num = getNumberOfNodes() * 3; for (int i = 0; i < num; i++) { coords[i] = coordsIn[i]; } setModified(); } /** * set all coordinates (allocate coords to 3 * getNumberOfCoordinates()). */ void CoordinateFile::setAllCoordinates(const float* coordsIn) { float* ptr = dataArrays[0]->getDataPointerFloat(); const int num = getNumberOfNodes() * 3; for (int i = 0; i < num; i++) { ptr[i] = coordsIn[i]; } setModified(); } /** * Set a coordinate at the specified index. No check is made of index validity. */ void CoordinateFile::setCoordinate(const int coordinateNumber, const float x, const float y, const float z) { float* coords = dataArrays[0]->getDataPointerFloat(); coords[coordinateNumber * 3] = x; coords[coordinateNumber * 3 + 1] = y; coords[coordinateNumber * 3 + 2] = z; setModified(); } /** * Set a coordinate at the specified index. No check is made of index validity. */ void CoordinateFile::setCoordinate(const int coordinateNumber, const double x, const double y, const double z) { float* coords = dataArrays[0]->getDataPointerFloat(); coords[coordinateNumber * 3] = x; coords[coordinateNumber * 3 + 1] = y; coords[coordinateNumber * 3 + 2] = z; setModified(); } /** * Set a coordinate at the specified index. No check is made of index validity. */ void CoordinateFile::setCoordinate(const int coordinateNumber, const float xyz[3]) { float* coords = dataArrays[0]->getDataPointerFloat(); coords[coordinateNumber * 3] = xyz[0]; coords[coordinateNumber * 3 + 1] = xyz[1]; coords[coordinateNumber * 3 + 2] = xyz[2]; setModified(); } /** * Set a coordinate at the specified index. No check is made of index validity. */ void CoordinateFile::setCoordinate(const int coordinateNumber, const double xyz[3]) { float* coords = dataArrays[0]->getDataPointerFloat(); coords[coordinateNumber * 3] = xyz[0]; coords[coordinateNumber * 3 + 1] = xyz[1]; coords[coordinateNumber * 3 + 2] = xyz[2]; setModified(); } /** * deform "this" node data file placing the output in "deformedFile". */ void CoordinateFile::deformFile(const DeformationMapFile& /*dmf*/, GiftiNodeDataFile& /*deformedFile*/, const DEFORM_TYPE /*dt*/) const throw (FileException) { throw FileException("Coordinate file deformation not supported."); } /** * Get the bounds of the coordinate file. * Bounds contains minx, maxx, miny, maxy, minz, maxz. */ void CoordinateFile::getBounds(float bounds[6]) const { float* coords = dataArrays[0]->getDataPointerFloat(); bounds[0] = coords[0]; bounds[1] = coords[0]; bounds[2] = coords[1]; bounds[3] = coords[1]; bounds[4] = coords[2]; bounds[5] = coords[2]; const int num = getNumberOfCoordinates(); for (int i = 0; i < num; i++) { if (coords[i * 3] < bounds[0]) bounds[0] = coords[i * 3]; if (coords[i * 3] > bounds[1]) bounds[1] = coords[i * 3]; if (coords[i * 3 + 1] < bounds[2]) bounds[2] = coords[i * 3 + 1]; if (coords[i * 3 + 1] > bounds[3]) bounds[3] = coords[i * 3 + 1]; if (coords[i * 3 + 2] < bounds[4]) bounds[4] = coords[i * 3 + 2]; if (coords[i * 3 + 2] > bounds[5]) bounds[5] = coords[i * 3 + 2]; } } /** * Get the coordinate closest to the point at (xp, yp, zp). */ int CoordinateFile::getCoordinateIndexClosestToPoint(const float xyz[3], const int startSearchAtCoordinateIndex) const { return getCoordinateIndexClosestToPoint(xyz[0], xyz[1], xyz[2], startSearchAtCoordinateIndex); } /** * Get the coordinate closest to the point at (xp, yp, zp). */ int CoordinateFile::getCoordinateIndexClosestToPoint(const float xp, const float yp, const float zp, const int startSearchAtCoordinateIndex) const { float* coords = dataArrays[0]->getDataPointerFloat(); int closest = -1; float closestDist = std::numeric_limits::max(); const int num = getNumberOfCoordinates(); for (int i = startSearchAtCoordinateIndex; i < num; i++) { const float dx = coords[i * 3] - xp; const float dy = coords[i * 3 + 1] - yp; const float dz = coords[i * 3 + 2] - zp; const float dist = dx*dx + dy*dy + dz*dz; if (dist < closestDist) { closest = i; closestDist = dist; } } return closest; } /** * get the distance from a 3D point to a coordinate. */ float CoordinateFile::getDistanceToPoint(const int coordIndex, const float* point3D) const { float* coords = dataArrays[0]->getDataPointerFloat(); const float dx = coords[coordIndex*3] - point3D[0]; const float dy = coords[coordIndex*3+1] - point3D[1]; const float dz = coords[coordIndex*3+2] - point3D[2]; return sqrt(dx*dx + dy*dy + dz*dz); } /** * get the distance squared from a 3D point to a coordinate. */ float CoordinateFile::getDistanceToPointSquared(const int coordIndex, const float* point3D) const { float* coords = dataArrays[0]->getDataPointerFloat(); const float dx = coords[coordIndex*3] - point3D[0]; const float dy = coords[coordIndex*3+1] - point3D[1]; const float dz = coords[coordIndex*3+2] - point3D[2]; return (dx*dx + dy*dy + dz*dz); } /** * Get the distance between two coordinates */ float CoordinateFile::getDistanceBetweenCoordinates(const int c1, const int c2) const { float* coords = dataArrays[0]->getDataPointerFloat(); const float dx = coords[c1*3] - coords[c2*3]; const float dy = coords[c1*3+1] - coords[c2*3+1]; const float dz = coords[c1*3+2] - coords[c2*3+2]; return sqrt(dx*dx + dy*dy + dz*dz); } /** * Get the distance between two coordinates squared. */ float CoordinateFile::getDistanceBetweenCoordinatesSquared(const int c1, const int c2) const { float* coords = dataArrays[0]->getDataPointerFloat(); const float dx = coords[c1*3] - coords[c2*3]; const float dy = coords[c1*3+1] - coords[c2*3+1]; const float dz = coords[c1*3+2] - coords[c2*3+2]; return (dx*dx + dy*dy + dz*dz); } /** * Compute shuffled average coordinate files. The inputs files are randomly split into * two groups and from these two groups two average coordinate files are created. * numberInGroup1 is the size of the first group but if this value is non-positive, the * groups are sized to one-half of the number of input files. */ void CoordinateFile::createShuffledAverageCoordinatesFiles(const std::vector& files, const int numberInGroup1, CoordinateFile& coordFileOut1, CoordinateFile& coordFileOut2) throw (FileException) { // // Check inputs // const int numFiles = static_cast(files.size()); if (numFiles < 2) { throw FileException("Shuffled average coordinate files requires at least two files."); } const int numCoords = files[0]->getNumberOfCoordinates(); if (numCoords <= 0) { throw FileException("Shuffled average coordinate files has at least one file with no nodes."); } for (int i = 1; i < numFiles; i++) { if (files[i]->getNumberOfCoordinates() != numCoords) { throw FileException("Shuffled average coordinate files have different numbers of nodes."); } } if (numberInGroup1 >= numFiles) { throw FileException("Shuffled average coordinate files group one size equals number of files or larger."); } // // Create shuffled files' indices // std::vector indicesShuffled(numFiles); for (int i = 0; i < numFiles; i++) { indicesShuffled[i] = i; } //RandomNumberOp randOp; // used to rand() is called StatisticRandomNumberOperator randOp; // used to rand() is called std::random_shuffle(indicesShuffled.begin(), indicesShuffled.end(), randOp); // // set the half files index // int halfIndex = numFiles / 2; if (numberInGroup1 > 0) { halfIndex = numberInGroup1; } // // Create two groups of files // std::vector group1; std::vector group2; for (int i = 0; i < numFiles; i++) { const int indx = indicesShuffled[i]; if (i < halfIndex) { group1.push_back(files[indx]); } else { group2.push_back(files[indx]); } } // // Create the two average coordinate files // createAverageCoordinateFile(group1, coordFileOut1); createAverageCoordinateFile(group2, coordFileOut2); } /** * compute an average coordinate file. */ void CoordinateFile::createAverageCoordinateFile(const std::vector& files, CoordinateFile& averageFile, MetricFile* ssf) throw (FileException) { const int numFiles = static_cast(files.size()); if (numFiles <= 0) { return; } // // Verify that files all have the same number of coordinates // int numCoords = files[0]->getNumberOfCoordinates(); for (int j = 1; j < numFiles; j++) { if (files[j]->getNumberOfCoordinates() != numCoords) { throw FileException("Files have different numbers of coordinates"); } } // // Setup the average file // averageFile.clear(); averageFile.setNumberOfCoordinates(numCoords); averageFile.setHeaderTag(headerTagStructure, files[0]->getHeaderTag(headerTagStructure)); QString comment("This file is the average of:"); for (int j = 0; j < numFiles; j++) { comment.append("\n "); comment.append(FileUtilities::basename(files[j]->getFileName())); } averageFile.setFileComment(comment); averageFile.setHeaderTag(AbstractFile::headerTagConfigurationID, files[0]->getHeaderTag(AbstractFile::headerTagConfigurationID)); // // Setup surface shape file // int surfaceShapeColumn = -1; if (ssf != NULL) { if (ssf->getNumberOfNodes() == 0) { ssf->setNumberOfNodesAndColumns(numCoords, 1); } else { ssf->addColumns(1); } surfaceShapeColumn = ssf->getNumberOfColumns() - 1; ssf->setColumnName(surfaceShapeColumn, "SHAPE_STANDARD_UNCERTAINTY"); ssf->setColumnComment(surfaceShapeColumn, comment); ssf->setColumnColorMappingMinMax(surfaceShapeColumn, 0.0, 5.0); } // // Average the coordinates // const float numFilesFloat = numFiles; for (int i = 0; i < numCoords; i++) { float sum[3] = { 0.0, 0.0, 0.0 }; for (int j = 0; j < numFiles; j++) { float xyz[3]; files[j]->getCoordinate(i, xyz); sum[0] += xyz[0]; sum[1] += xyz[1]; sum[2] += xyz[2]; } sum[0] /= numFilesFloat; sum[1] /= numFilesFloat; sum[2] /= numFilesFloat; averageFile.setCoordinate(i, sum); // // Should uncertainty be placed in surface shape file // if (surfaceShapeColumn >= 0) { // // Get distance of each surfaces' node from the average // std::vector deltas(numFiles); for (int k = 0; k < numFiles; k++) { deltas[k] = MathUtilities::distance3D(files[k]->getCoordinate(i), sum); } // // Get mean of distances // StatisticDataGroup sdg(&deltas, StatisticDataGroup::DATA_STORAGE_MODE_POINT); StatisticMeanAndDeviation smad; smad.addDataGroup(&sdg); try { smad.execute(); } catch (StatisticException&) { } // // Place the average into the surface shape file // ssf->setValue(i, surfaceShapeColumn, smad.getMean()); } } } /** * get the coordinates from a MNI OBJ surface file. */ void CoordinateFile::importFromMniObjSurfaceFile(const MniObjSurfaceFile& mni) throw (FileException) { clear(); const int numVertices = mni.getNumberOfPoints(); if (numVertices > 0) { setNumberOfCoordinates(numVertices); for (int i = 0; i < numVertices; i++) { const float* xyz = mni.getPointXYZ(i); setCoordinate(i, xyz); } } appendToFileComment(" Imported from "); appendToFileComment(FileUtilities::basename(mni.getFileName())); setModified(); } /** * Get the coordinates out of a brain voyager file. */ void CoordinateFile::importFromBrainVoyagerFile(const BrainVoyagerFile& bvf) { clear(); const int numVertices = bvf.getNumberOfVertices(); if (numVertices > 0) { setNumberOfCoordinates(numVertices); for (int i = 0; i < numVertices; i++) { float xyz[3]; bvf.getVertexCoordinates(i, xyz); setCoordinate(i, xyz); } } appendToFileComment(" Imported from "); appendToFileComment(FileUtilities::basename(bvf.getFileName())); setModified(); } /** * get the coordinates out of a free surfer surface file. */ void CoordinateFile::importFromFreeSurferSurfaceFile(const FreeSurferSurfaceFile& fssf, const int numNodesIn) throw (FileException) { clear(); const int numVertices = fssf.getNumberOfVertices(); int numNodes = numNodesIn; if (numNodes < 0) { numNodes = numVertices; } // // If this is a patch file // if (fssf.getIsAsciiPatchFile() || fssf.getIsBinaryPatchFile()) { // // A non-patch surface must have been read prior to reading a patch file // if (numNodes <= 0) { throw FileException(fssf.getFileName(), "This is a FreeSurfer patch surface file.\n" "It must be read after a non-patch surface file."); } setNumberOfCoordinates(numNodes); } else { if (numNodes > 0) { if (numNodes != numVertices) { throw FileException(fssf.getFileName(), "This free surfer file has a different " "number of nodes than the current surface(s)."); } } setNumberOfCoordinates(numVertices); } if (numVertices > 0) { for (int i = 0; i < numVertices; i++) { float xyz[3]; int vertNumber; fssf.getVertexCoordinates(i, vertNumber, xyz); setCoordinate(vertNumber, xyz); } } appendToFileComment(" Imported from "); appendToFileComment(FileUtilities::basename(fssf.getFileName())); setModified(); } /** * add the coordinates to of a free surfer surface file */ void CoordinateFile::exportToFreeSurferSurfaceFile(FreeSurferSurfaceFile& fssf) { const int numCoords = getNumberOfCoordinates(); for (int i = 0; i < numCoords; i++) { float xyz[3]; getCoordinate(i, xyz); fssf.setVertexCoordinates(i, i, xyz); } } /** * Get the coordinates out of a vtkPolyData object */ void CoordinateFile::importFromVtkFile(vtkPolyData* polyData) { clear(); const int numVertices = polyData->GetNumberOfPoints(); if (numVertices > 0) { setNumberOfCoordinates(numVertices); vtkPoints* points = polyData->GetPoints(); for (int i = 0; i < numVertices; i++) { #ifdef HAVE_VTK5 double xyz[3]; #else // HAVE_VTK5 float xyz[3]; #endif // HAVE_VTK5 points->GetPoint(i, xyz); setCoordinate(i, xyz); } } setModified(); } /** * Read the coordinate file data. May throw FileException. */ void CoordinateFile::readLegacyNodeFileData(QFile& /*file*/, QTextStream& stream, QDataStream& binStream) throw (FileException) { // // Should reading data be skipped ? // if (getReadMetaDataOnlyFlag()) { return; } //if we ever want to switch to qt_4_6 above enable the line below //binStream.setFloatingPointPrecision(QDataStream::SinglePrecision); binStream.setVersion(QDataStream::Qt_4_3); switch (getFileReadType()) { case FILE_FORMAT_ASCII: { QString line; readLine(stream, line); const int num = line.toInt(); if (num < 0) { throw FileException(filename, "Number of coordinates is less than zero."); } setNumberOfCoordinates(num); float* coordPtr = dataArrays[0]->getDataPointerFloat(); float x, y, z; int index; for (int i = 0; i < num; i++) { readLine(stream, line); sscanf(line.toAscii().constData(), "%d %f %f %f", &index, &x, &y, &z); const int i3 = i * 3; coordPtr[i3] = x; coordPtr[i3 + 1] = y; coordPtr[i3 + 2] = z; } } break; case FILE_FORMAT_BINARY: { int numCoords; binStream >> numCoords; if (numCoords > 0) { setNumberOfCoordinates(static_cast(numCoords)); float* coordPtr = dataArrays[0]->getDataPointerFloat(); for (int i = 0; i < numCoords; i++) { const int i3 = i * 3; binStream >> coordPtr[i3]; binStream >> coordPtr[i3 + 1]; binStream >> coordPtr[i3 + 2]; } } } break; case FILE_FORMAT_XML: /* { //throw FileException(filename, "Reading in XML format not supported."); QDomNode node = rootElement.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (DebugControl::getDebugOn()) { std::cout << "Tag Name: " << elem.tagName() << std::endl; } if (elem.tagName() == "number-of-coords") { const QString strNum = getXmlElementFirstChildAsString(elem); if (strNum.isEmpty()) { throw FileException(filename, "XML tag \"number-of-coords\" is isEmpty."); } const int num = StringUtilities::toInt(strNum); if (num > 0) { setNumberOfCoordinates(num); } } else if (elem.tagName() == "coords") { if (getNumberOfCoordinates() <= 0) { throw FileException(filename, "XML file have coords but number of coordinates is zero."); } QDomNode node = static_cast(elem.firstChild()); if (node.isNull() == false) { const QDomText textNode = node.toText(); if (textNode.isNull() == false) { #ifdef USE_VTK_BASE64 const unsigned long numBytes = getNumberOfCoordinates() * 12; const unsigned long numDecoded = vtkBase64Utilities::Decode( (const unsigned char*)textNode.data(), numBytes, (unsigned char*)&coords[0]); if (numBytes != numDecoded) { std::ostringstream str; str << "Error reading XML coordinates.\n" << "Number of decoded bytes: " << numDecoded << "\n." << "Number of bytes expected: " << numBytes << "."; throw FileException(filename, str.str().c_str()); } #else QCodecs::base64Decode(textNode.data(), textNode.data().length(), &coords[0]); #endif / * QByteArray ba; ba.duplicate(textNode.data(), textNode.data().length()); QByteArray base64; QCodecs::base64Decode(ba, base64); // xyz = 12 bytes memcpy(&coords[0], base64.data(), 12 * getNumberOfCoordinates()); * / } } } } node = node.nextSibling(); } } */ break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "Reading XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "Reading XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Reading XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Reading in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Writing Comma Separated Value File Format not supported."); break; } setModified(); } /** * Read the coordinate file data. May throw FileException. */ void CoordinateFile::writeLegacyNodeFileData(QTextStream& stream, QDataStream& binStream) throw (FileException) { const int numCoords = getNumberOfCoordinates(); //if we ever want to switch to qt_4_6 above enable the line below //binStream.setFloatingPointPrecision(QDataStream::SinglePrecision); binStream.setVersion(QDataStream::Qt_4_3); //stream.setVersion(QDataStream::Qt_4_3); switch (getFileWriteType()) { case FILE_FORMAT_ASCII: stream << numCoords << "\n"; for (int i = 0; i < numCoords; i++) { float x, y, z; getCoordinate(i, x, y, z); stream << i << " " << x << " " << y << " " << z << "\n"; } break; case FILE_FORMAT_BINARY: binStream << static_cast(numCoords); if (numCoords > 0) { const float* xyz = getCoordinate(0); for (int i = 0; i < numCoords; i++) { const int i3 = i * 3; binStream << xyz[i3]; binStream << xyz[i3+1]; binStream << xyz[i3+2]; } } break; case FILE_FORMAT_XML: /* { //throw FileException(filename, "Writing in XML format not supported."); QDomElement numElem = xmlDoc.createElement("number-of-coords"); QDomText numText = xmlDoc.createTextNode(QString::number(numCoords)); numElem.appendChild(numText); #ifdef USE_VTK_BASE64 const unsigned long numBytes = numCoords * 12; const unsigned long buffSize = (numBytes * 2); unsigned char* buff = new unsigned char[buffSize]; const float* xyz = getCoordinate(0); const int num = vtkBase64Utilities::Encode((const unsigned char*)&xyz[0], numBytes, buff); buff[num] = '\0'; QDomElement coordsElem = xmlDoc.createElement("coords"); QDomText coordsText = xmlDoc.createTextNode((const char*)buff); coordsElem.appendChild(coordsText); #else const float* xyz = getCoordinate(0); QByteArray ba; ba.duplicate((const char*)&xyz[0], numCoords * 12); // xyz = 12 bytes QByteArray base64; QCodecs::base64Encode(ba, base64, true); QDomElement coordsElem = xmlDoc.createElement("coords"); QDomText coordsText = xmlDoc.createTextNode(base64); coordsElem.appendChild(coordsText); #endif rootElement.appendChild(numElem); rootElement.appendChild(coordsElem); } */ break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Writing XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Writing in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Writing Comma Separated Value File Format not supported."); break; } } /** * get spec file tag from configuration id. */ QString CoordinateFile::getSpecFileTagUsingConfigurationID() const { const QString name = getHeaderTag(AbstractFile::headerTagConfigurationID); return convertConfigurationIDToSpecFileTag(name); } /** * convert configuration ID to spec file tag. */ QString CoordinateFile::convertConfigurationIDToSpecFileTag(const QString& nameIn) { const QString name(nameIn.toUpper()); if (name == "RAW") return SpecFile::getRawCoordFileTag(); else if (name == "FIDUCIAL") return SpecFile::getFiducialCoordFileTag(); else if (name == "INFLATED") return SpecFile::getInflatedCoordFileTag(); else if (name == "VERY_INFLATED") return SpecFile::getVeryInflatedCoordFileTag(); else if (name == "SPHERICAL") return SpecFile::getSphericalCoordFileTag(); else if (name == "ELLIPSOIDAL") return SpecFile::getEllipsoidCoordFileTag(); else if (name == "CMW") return SpecFile::getCompressedCoordFileTag(); else if (name == "FLAT") return SpecFile::getFlatCoordFileTag(); else if (name == "FLAT_LOBAR") return SpecFile::getLobarFlatCoordFileTag(); else if (name == "HULL") return SpecFile::getHullCoordFileTag(); else return SpecFile::getUnknownCoordFileMatchTag(); } /** * Update the file's metadata for Caret6. */ void CoordinateFile::updateMetaDataForCaret6() { AbstractFile::updateMetaDataForCaret6(); this->removeHeaderTag("topo_file"); } /** * Write the file's memory in caret6 format to the specified name. */ QString CoordinateFile::writeFileInCaret6Format(const QString& filenameIn, Structure structure,const ColorFile* colorFileIn, const bool useCaret6ExtensionFlag) throw (FileException) { QString name = filenameIn; if (useCaret6ExtensionFlag) { name = FileUtilities::replaceExtension(filenameIn, ".coord", SpecFile::getGiftiCoordinateFileExtension()); } this->setFileWriteType(AbstractFile::FILE_FORMAT_XML_GZIP_BASE64); this->writeFile(name); return name; } caret-5.6.4~dfsg.1.orig/caret_files/ContourFile.h0000664000175000017500000002701411572067322021447 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_CONTOUR_FILE_H__ #define __VE_CONTOUR_FILE_H__ #include #include "AbstractFile.h" #include "TransformationMatrixFile.h" class ContourFile; class MDPlotFile; class NeurolucidaFile; /// This class holds a single contour. class CaretContour { private: /// points in the contour class ContourPoint { public: // constructor ContourPoint(); // constructor ContourPoint(const float xi, const float yi, const float zi, const bool special = false); // destructor ~ContourPoint(); /// contour x coordinates float x; /// contour y coordinates float y; /// contour z coordinates float z; /// highlight flag bool highlightFlag; /// special flag used for some operations bool specialFlag; }; /// points in the contour std::vector points; /// section number of this contour int sectionNumber; /// contour file this section is part of ContourFile* contourFile; /// copy helper void copyHelper(const CaretContour& cc); public: /// Create the contour CaretContour(const int estimatedNumberOfPointsInContour = 0); /// Destructor ~CaretContour(); /// copy constructor CaretContour(const CaretContour& cc); /// assignment operator CaretContour& operator=(const CaretContour& cc); /// Add a point to the contour void addPoint(const float xIn, const float yIn, const float zIn = -10000000); /// Add points to the contour void addPoints(const float* xIn, const float* yIn, const int numPoints); /// clear the contour points void clearPoints(); /// Delete a point from the contour void deletePoint(const int pointIndex); /// Get number of points in the contour int getNumberOfPoints() const; /// Get a point from the contour void getPointXY(const int pointIndex, float& xOut, float& yOut) const; /// Get a point from the contour void getPointXYZ(const int pointIndex, float& xOut, float& yOut, float& zOut) const; /// Get a point from the contour void getPointXYZ(const int pointIndex, float xyzOut[3]) const; /// get the estimated distance between each point in the contour float getAverageDistanceBetweenPoints() const; /// resample the contour void resample(const float distanceBetweenPoints); /// remove consecutive duplicate points (same x/y) void removeDuplicatePoints(); /// reverse the order of the points in a contour void reversePointOrder(); /// Get the z for a contour int getSectionNumber() const; /// Set a point from the contour void setPointXY(const int pointIndex, const float xIn, const float yIn); /// Set a point from the contour void setPointXYZ(const int pointIndex, const float xIn, const float yIn, const float zIn); /// clear the highlight flags void clearHighlightFlags(); /// Clear the special flag for all points void clearSpecialFlags(); /// Returns true if any of the contour point's special flag is set bool getAnySpecialFlagSet() const; /// get the highlight flag for a point bool getHighlightFlag(const int pointIndex) const; /// set the special flag for a point void setHighlightFlag(const int pointIndex, const bool flag); /// Get the special flag for a point bool getSpecialFlag(const int pointIndex) const; /// Set the special flag for a point void setSpecialFlag(const int pointIndex, const bool flag); /// Set the section void setSectionNumber(const int sectionNumberIn); /// operator for comparing contours by section number bool operator<(const CaretContour& cc) const; friend class ContourFile; }; /// This class contains contours class ContourFile : public AbstractFile { public: /// section selection type enum SECTION_TYPE { SECTION_TYPE_SINGLE, SECTION_TYPE_MULTIPLE, SECTION_TYPE_ALL, SECTION_TYPE_HIDE }; private: static const QString tagNumberOfContours; static const QString tagSectionSpacing; static const QString tagMainWindowScaling; /// selected section type SECTION_TYPE sectionType; /// minimum section int minimumSection; /// maximumSection int maximumSection; /// storage for the contours (do not change to pointer else sorting will break) std::vector contours; /// spacing between each consecutive section number (millimeters) float sectionSpacing; /// minimum selected section int minimumSelectedSection; /// maximum selected section int maximumSelectedSection; /// scaling for main window float mainWindowScaling[3]; /// Set the minimum and maximum section numbers. void setMinMaxSections(); /// Update minimum and maximum section numbers. void updateMinMaxSections(const int sectionNumber); /// read a version 0 contour file void readFileDataVersion0(QTextStream& fp) throw (FileException); /// read a version 1 contour file void readFileDataVersion1(QTextStream& fp) throw (FileException); public: /// Constructor ContourFile(); /// Destructor ~ContourFile(); /// Append a contour file to this one void append(ContourFile& cf, QString& errorMessage); /// Clear the file void clear(); /// cleanup contours bool cleanupContours(); /// see if file contains no data bool empty() const { return contours.empty(); } /// Add a contour (returns index number of contour) void addContour(const CaretContour& contourIn); /// apply a transformation matrix to the contours void applyTransformationMatrix(const int sectionLow, const int sectionHigh, const TransformationMatrix& matrix, const bool limitToSpecialFlagNodes); /// set the special flag for all contour points in the section range and box void setSpecialFlags(const int sectionLow, const int sectionHigh, const float bounds[4]); /// Clear the special flag in all contours void clearSpecialFlags(); /// Clear the highlight flags void clearHighlightFlags(); /// Delete a contour void deleteContour(const int indexNumber); /// Get a contour CaretContour* getContour(const int indexNumber); /// Get a contour (const method) const CaretContour* getContour(const int indexNumber) const; /// Get the number of contours int getNumberOfContours() const; /// Get the extent (min and max X & Y) of the contours void getExtent(float& minX, float& maxX, float& minY, float& maxY) const; /// Get the center of gravity for a section. /// Returns number of points for the section int getSectionCOG(const int sectionNumber, float& cogX, float& cogY) const; /// Get the range of sections void getSectionExtent(int& lowest, int& highest) const; /// Get the section spacing float getSectionSpacing() const; /// Merge two contours into a single contour void mergeContours(const int contour1, const int contour2); /// Set the section spacing void setSectionSpacing(const float sectionSpacingIn); /// Sort the contours by section number void sortBySectionNumber(); /// get the section type SECTION_TYPE getSectionType() const; /// set the selection type void setSectionType(const SECTION_TYPE type); /// get the minimum section int getMinimumSection() const { return minimumSection; } /// get the maximum section int getMaximumSection() const { return maximumSection; } /// get the minimum selected section int getMinimumSelectedSection() const; /// get the maximum selected section int getMaximumSelectedSection() const; /// set the minimum selected section void setMinimumSelectedSection(const int sect); /// set the maximum selected section void setMaximumSelectedSection(const int sect); /// get main window scaling (invalid if negative values) void getMainWindowScaling(float scaleOut[3]) const; /// set the main window scaling void setMainWindowScaling(const float scaleIn[3]); /// resample all of the contours void resampleAllContours(const float distanceBetweenPoints); /// find contour point within distance of coordinate void findContourPoint(const float xyz[3], const float withinDistance, int& contourNumber, int& contourPointNumber) const; /// import contours from an MD Plot File void importMDPlotFile(const MDPlotFile& mdf) throw (FileException); /// import contours from a Nuerolucida File void importNeurolucidaFile(const NeurolucidaFile& nf) throw (FileException); /// Read the file's data void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException); /// Write the file's data void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException); friend class CaretContour; }; #endif // __VE_CONTOUR_FILE_H__ #ifdef _CONTOUR_FILE_MAIN_ const QString ContourFile::tagNumberOfContours = "tag-number-of-contours"; const QString ContourFile::tagSectionSpacing = "tag-section-spacing"; const QString ContourFile::tagMainWindowScaling = "tag-main-window-scaling"; #endif // _CONTOUR_FILE_MAIN_ caret-5.6.4~dfsg.1.orig/caret_files/ContourFile.cxx0000664000175000017500000007673511572067322022040 0ustar michaelmichael/*LICENSE_START*/ #include /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include "BorderFile.h" #define _CONTOUR_FILE_MAIN_ #include "ContourFile.h" #undef _CONTOUR_FILE_MAIN_ #include "DebugControl.h" #include "MathUtilities.h" #include "MDPlotFile.h" #include "NeurolucidaFile.h" #include "SpecFile.h" /** * constructor. */ CaretContour::ContourPoint::ContourPoint() { x = 0.0; y = 0.0; z = 0.0; specialFlag = false; highlightFlag = false; } /** * constructor. */ CaretContour::ContourPoint::ContourPoint(const float xi, const float yi, const float zi, const bool special) { x = xi; y = yi; z = zi; specialFlag = special; highlightFlag = false; } /** * destructor. */ CaretContour::ContourPoint::~ContourPoint() { } /** * Constructor */ CaretContour::CaretContour(const int estimatedNumberOfPointsInContour) { contourFile = NULL; sectionNumber = -1; if (estimatedNumberOfPointsInContour > 0) { points.reserve(estimatedNumberOfPointsInContour); } } /** * Destructor */ CaretContour::~CaretContour() { clearPoints(); contourFile = NULL; } /** * copy constructor. */ CaretContour::CaretContour(const CaretContour& cc) { copyHelper(cc); } /** * assignment operator. */ CaretContour& CaretContour::operator=(const CaretContour& cc) { if (this != &cc) { copyHelper(cc); } return *this; } /** * copy helper. */ void CaretContour::copyHelper(const CaretContour& cc) { points = cc.points; sectionNumber = cc.sectionNumber; contourFile = NULL; } /** * operator for comparing contours by section number. */ bool CaretContour::operator<(const CaretContour& cc) const { const bool lessThan = (this->sectionNumber < cc.sectionNumber); return lessThan; } /** * Add a point to this contour. */ void CaretContour::addPoint(const float xIn, const float yIn, const float zIn) { ContourPoint cp(xIn, yIn, zIn, false); points.push_back(cp); if (contourFile != NULL) { contourFile->setModified(); } } /** * Add a number of points to this contour. */ void CaretContour::addPoints(const float* xIn, const float* yIn, const int numPoints) { for (int i = 0; i < numPoints; i++) { ContourPoint cp(xIn[i], yIn[i], sectionNumber, false); points.push_back(cp); } if (contourFile != NULL) { contourFile->setModified(); } } /** * delete a point from this contour. */ void CaretContour::deletePoint(const int pointIndex) { if ((pointIndex >= 0) && (pointIndex < getNumberOfPoints())) { points.erase(points.begin() + pointIndex); } if (contourFile != NULL) { contourFile->setModified(); } } /** * get the number of points in this contour. */ int CaretContour::getNumberOfPoints() const { return static_cast(points.size()); } /** * See if any "special flags" are set. */ bool CaretContour::getAnySpecialFlagSet() const { const int num = getNumberOfPoints(); for (int i = 0; i < num; i++) { if (points[i].specialFlag) { return true; } } return false; } /** * Get the coordinates of a point in this contour. */ void CaretContour::getPointXY(const int pointIndex, float& xOut, float& yOut) const { xOut = points[pointIndex].x; yOut = points[pointIndex].y; } /** * Get the coordinates of a point in this contour. */ void CaretContour::getPointXYZ(const int pointIndex, float& xOut, float& yOut, float& zOut) const { xOut = points[pointIndex].x; yOut = points[pointIndex].y; zOut = points[pointIndex].z; } /** * Get the coordinates of a point in this contour. */ void CaretContour::getPointXYZ(const int pointIndex, float xyzOut[3]) const { xyzOut[0] = points[pointIndex].x; xyzOut[1] = points[pointIndex].y; xyzOut[2] = points[pointIndex].z; } /** * get the estimated distance between each point in the contour. */ float CaretContour::getAverageDistanceBetweenPoints() const { float dist = 0.0; const int num = getNumberOfPoints() - 1; for (int i = 0; i < num; i++) { float x1, x2, y1, y2, z1, z2; getPointXYZ(i, x1, y1, z1); getPointXYZ(i + 1, x2, y2, z2); const float dx = x2 - x1; const float dy = y2 - y1; const float dz = z2 - z1; const float d = std::sqrt(dx*dx + dy*dy + dz*dz); dist += d; } if (num > 0) { dist = dist / static_cast(num); } return dist; } /** * resample the contour. */ void CaretContour::resample(const float distanceBetweenPoints) { const int num = getNumberOfPoints() - 1; if (num > 1) { // // Convert to border // Border b; for (int i = 0; i < num; i++) { float x, y, z; getPointXYZ(i, x, y, z); const float xyz[3] = { x, y, z }; b.addBorderLink(xyz); } // // Resample the border // int newNum = 0; b.resampleBorderToDensity(distanceBetweenPoints, 2, newNum); // // Clear this contour // clearPoints(); // // Convert border back to contours // const int numLinks = b.getNumberOfLinks(); for (int i = 0; i < numLinks; i++) { const float* xyz = b.getLinkXYZ(i); addPoint(xyz[0], xyz[1], xyz[2]); } } } /** * clear the contour points. */ void CaretContour::clearPoints() { points.clear(); } /** * Get the section number of this contour. */ int CaretContour::getSectionNumber() const { return sectionNumber; } /** * Set the coordinates for a point in this contour. */ void CaretContour::setPointXY(const int pointIndex, const float xIn, const float yIn) { points[pointIndex].x = xIn; points[pointIndex].y = yIn; if (contourFile != NULL) { contourFile->setModified(); } } /** * Set the coordinates for a point in this contour. */ void CaretContour::setPointXYZ(const int pointIndex, const float xIn, const float yIn, const float zIn) { if ((pointIndex >= 0) && (pointIndex < getNumberOfPoints())) { points[pointIndex].x = xIn; points[pointIndex].y = yIn; points[pointIndex].z = zIn; if (contourFile != NULL) { contourFile->setModified(); } } } /** * clear the highlight flags. */ void CaretContour::clearHighlightFlags() { for (int i = 0; i < getNumberOfPoints(); i++) { points[i].highlightFlag = false; } } /** * get the highlight flag for a point. */ bool CaretContour::getHighlightFlag(const int pointIndex) const { return points[pointIndex].highlightFlag; } /** * set the special flag for a point. */ void CaretContour::setHighlightFlag(const int pointIndex, const bool flag) { if ((pointIndex >= 0) && (pointIndex < getNumberOfPoints())) { points[pointIndex].highlightFlag = flag; } } /** * Set the special flag for a point. */ void CaretContour::setSpecialFlag(const int pointIndex, const bool flag) { if ((pointIndex >= 0) && (pointIndex < getNumberOfPoints())) { points[pointIndex].specialFlag = flag; } } /** * Get the special flag for a point. */ bool CaretContour::getSpecialFlag(const int pointIndex) const { return points[pointIndex].specialFlag; } /** * Clear the special flag for all points. */ void CaretContour::clearSpecialFlags() { for (int i = 0; i < getNumberOfPoints(); i++) { points[i].specialFlag = false; } } /** * Set the section number for this contour. */ void CaretContour::setSectionNumber(const int sectionNumberIn) { sectionNumber = sectionNumberIn; for (int i = 0; i < getNumberOfPoints(); i++) { points[i].z = sectionNumber; } if (contourFile != NULL) { contourFile->updateMinMaxSections(sectionNumber); contourFile->setModified(); } } /** * reverse the order of the points in a contour. */ void CaretContour::reversePointOrder() { const int num = getNumberOfPoints(); if (num > 1) { std::reverse(points.begin(), points.end()); if (contourFile != NULL) { contourFile->setModified(); } } } /** * remove consecutive duplicate points (same x/y). */ void CaretContour::removeDuplicatePoints() { const int num = getNumberOfPoints(); if (num > 0) { // // containers for retained contour points // std::vector newPoints; // // get first point in contour // float xLast, yLast, zLast; getPointXYZ(0, xLast, yLast, zLast); bool specialLast = getSpecialFlag(0); newPoints.push_back(points[0]); // // loop through remaining contours // for (int i = 1; i < num; i++) { float x, y, z; getPointXYZ(i, x, y, z); bool special = getSpecialFlag(i); // // Did the X or Y change from the previous point // if ((x != xLast) || (y != yLast)) { xLast = x; yLast = y; zLast = z; specialLast = special; newPoints.push_back(points[i]); } } // // replace the contour // const int numPts = static_cast(newPoints.size()); if (num != numPts) { points = newPoints; if (contourFile != NULL) { contourFile->setModified(); } if (DebugControl::getDebugOn()) { std::cout << "INFO: contour had " << (num - newPoints.size()) << " duplicate points." << std::endl; } } } } /** * Constructor. */ ContourFile::ContourFile() : AbstractFile("Contour File", SpecFile::getContourFileExtension()) { clear(); } /** * Destructor. */ ContourFile::~ContourFile() { clear(); } /** * Append a contour file to this contour file. */ void ContourFile::append(ContourFile& cf, QString& errorMessage) { errorMessage = ""; const int num = cf.getNumberOfContours(); for (int i = 0; i < num; i++) { CaretContour* cc = cf.getContour(i); addContour(*cc); } // // transfer the file's comment // appendFileComment(cf); setMinMaxSections(); minimumSelectedSection = minimumSection; maximumSelectedSection = maximumSection; setSectionType(SECTION_TYPE_ALL); setModified(); } /** * Clear this contour file. */ void ContourFile::clear() { clearAbstractFile(); contours.clear(); sectionSpacing = 1.0; sectionType = SECTION_TYPE_ALL; setMinMaxSections(); mainWindowScaling[0] = -1.0; mainWindowScaling[1] = -1.0; mainWindowScaling[2] = -1.0; } /** * cleanup contours - remove duplicate points in contours and contours with less than 3 points. */ bool ContourFile::cleanupContours() { const int num = getNumberOfContours(); std::vector newContours; bool changeFlag = false; for (int i = 0; i < num; i++) { CaretContour& cc = contours[i]; // // Remove duplicate points from the contours // const int oldPts = cc.getNumberOfPoints(); cc.removeDuplicatePoints(); // // Only keep those contours with more than 2 points // int numPts = cc.getNumberOfPoints(); if (numPts > 2) { newContours.push_back(cc); } else { numPts = 0; } if (oldPts != numPts) { changeFlag = true; } } if (changeFlag) { contours = newContours; setModified(); if (DebugControl::getDebugOn()) { std::cout << "INFO: " << (num - newContours.size()) << " contours were removed during cleanup." << std::endl; } } newContours.clear(); return changeFlag; } /** * Clear all of the special flags. */ void ContourFile::clearSpecialFlags() { const int num = getNumberOfContours(); for (int i = 0; i < num; i++) { contours[i].clearSpecialFlags(); } } /** * Clear all of the highlight flags. */ void ContourFile::clearHighlightFlags() { const int num = getNumberOfContours(); for (int i = 0; i < num; i++) { contours[i].clearHighlightFlags(); } } /** * Add a contour to this contour file. */ void ContourFile::addContour(const CaretContour& contourIn) { contours.push_back(contourIn); const int contourIndex = getNumberOfContours() - 1; CaretContour* cc = getContour(contourIndex); cc->contourFile = this; if (contourIndex == 0) { minimumSection = cc->sectionNumber; maximumSection = cc->sectionNumber; } updateMinMaxSections(cc->sectionNumber); setModified(); } /** * set the special flag for all contour points in the section range and box */ void ContourFile::setSpecialFlags(const int sectionLow, const int sectionHigh, const float bounds[4]) { const int num = getNumberOfContours(); const float minX = std::min(bounds[0], bounds[2]); const float maxX = std::max(bounds[0], bounds[2]); const float minY = std::min(bounds[1], bounds[3]); const float maxY = std::max(bounds[1], bounds[3]); for (int i = 0; i < num; i++) { if ((contours[i].sectionNumber >= sectionLow) && (contours[i].sectionNumber <= sectionHigh)) { const int numPoints = contours[i].getNumberOfPoints(); for (int j = 0; j < numPoints; j++) { const float x = contours[i].points[j].x; const float y = contours[i].points[j].y; if ((x >= minX) && (x <= maxX) && (y >= minY) && (y <= maxY)) { contours[i].points[j].specialFlag = true; } } } } } /** * find contour point within distance of coordinate. */ void ContourFile::findContourPoint(const float xyz[3], const float withinDistance, int& contourNumber, int& contourPointNumber) const { const float withinDistanceSQ = withinDistance * withinDistance; float closestDistanceSQ = std::numeric_limits::max(); contourNumber = -1; contourPointNumber = -1; const int numContours = getNumberOfContours(); for (int i = 0; i < numContours; i++) { const CaretContour* cc = getContour(i); const int numPoints = cc->getNumberOfPoints(); for (int j = 0; j < numPoints; j++) { float pointXYZ[3]; cc->getPointXYZ(j, pointXYZ[0], pointXYZ[1], pointXYZ[2]); const float distSQ = MathUtilities::distanceSquared3D(xyz, pointXYZ); if (distSQ < withinDistanceSQ) { if (distSQ < closestDistanceSQ) { contourNumber = i; contourPointNumber = j; closestDistanceSQ = distSQ; } } } } } /** * Apply a transformation matrix to this contour file. */ void ContourFile::applyTransformationMatrix(const int sectionLow, const int sectionHigh, const TransformationMatrix& matrixIn, const bool limitToSpecialFlagNodes) { TransformationMatrix& matrix = const_cast(matrixIn); const int num = getNumberOfContours(); for (int i = 0; i < num; i++) { if ((contours[i].sectionNumber >= sectionLow) && (contours[i].sectionNumber <= sectionHigh)) { const int numPoints = contours[i].getNumberOfPoints(); for (int j = 0; j < numPoints; j++) { bool transformIt = true; if (limitToSpecialFlagNodes) { transformIt = contours[i].points[j].specialFlag; } if (transformIt) { double p[4] = { contours[i].points[j].x, contours[i].points[j].y, contours[i].points[j].z, 1.0 }; matrix.multiplyPoint(p); contours[i].points[j].x = p[0]; contours[i].points[j].y = p[1]; contours[i].points[j].z = p[2]; } } } } setModified(); } /** * delete a contour from this contour file. */ void ContourFile::deleteContour(const int indexNumber) { const int num = getNumberOfContours(); if ((indexNumber >= 0) && (indexNumber < num)) { contours.erase(contours.begin() + indexNumber); setModified(); setMinMaxSections(); } } /** * Get a contour from this contour file. */ CaretContour* ContourFile::getContour(const int indexNumber) { return &contours[indexNumber]; } /** * Get a contour from this contour file (const method). */ const CaretContour* ContourFile::getContour(const int indexNumber) const { return &contours[indexNumber]; } /** * Get the extent of this contour file. */ void ContourFile::getExtent(float& minX, float& maxX, float& minY, float& maxY) const { const int numContours = getNumberOfContours(); minX = std::numeric_limits::max(); maxX = -std::numeric_limits::max(); minY = std::numeric_limits::max(); maxY = -std::numeric_limits::max(); for (int i = 0; i < numContours; i++) { const int numPoints = contours[i].getNumberOfPoints(); for (int j = 0; j < numPoints; j++) { if (contours[i].points[j].x < minX) { minX = contours[i].points[j].x; } if (contours[i].points[j].x > maxX) { maxX = contours[i].points[j].x; } if (contours[i].points[j].y < minY) { minY = contours[i].points[j].y; } if (contours[i].points[j].y > maxY) { maxY = contours[i].points[j].y; } } } } /** * Get the number of contours in this contour file. */ int ContourFile::getNumberOfContours() const { return static_cast(contours.size()); } /** * For a specified section, get the center of gravity of its contour points. */ int ContourFile::getSectionCOG(const int sectionNumber, float& cogX, float& cogY) const { const int numContours = getNumberOfContours(); cogX = 0.0; cogY = 0.0; int cnt = 0; for (int i = 0; i < numContours; i++) { if (contours[i].sectionNumber == sectionNumber) { const int numPoints = contours[i].getNumberOfPoints(); for (int j = 0; j < numPoints; j++) { cogX += contours[i].points[j].x; cogY += contours[i].points[j].y; cnt++; } } } if (cnt > 0) { cogX /= static_cast(cnt); cogY /= static_cast(cnt); } return cnt; } /** * resample all of the contours. */ void ContourFile::resampleAllContours(const float distanceBetweenPoints) { const int numContours = getNumberOfContours(); for (int i = 0; i < numContours; i++) { contours[i].resample(distanceBetweenPoints); } } /** * Get the extents of a single section. */ void ContourFile::getSectionExtent(int& lowest, int& highest) const { lowest = minimumSection; highest = maximumSection; } /** * Set the minimum and maximum section numbers. */ void ContourFile::setMinMaxSections() { const int numContours = getNumberOfContours(); if (numContours <= 0) { minimumSection = std::numeric_limits::max(); maximumSection = std::numeric_limits::min();; return; } minimumSection = contours[0].sectionNumber; maximumSection = contours[0].sectionNumber; for (int i = 0; i < numContours; i++) { maximumSection = std::max(contours[i].sectionNumber, maximumSection); minimumSection = std::min(contours[i].sectionNumber, minimumSection); } } /** * Get the spacing between sections (millimeters). */ float ContourFile::getSectionSpacing() const { return sectionSpacing; } /** * Merge two contours (append contour2 to contour1). */ void ContourFile::mergeContours(const int contour1, const int contour2) { if ((contour1 >= 0) && (contour1 < getNumberOfContours()) && (contour2 >= 0) && (contour2 < getNumberOfContours())) { CaretContour* first = getContour(contour1); CaretContour* second = getContour(contour2); const float dist = std::max(first->getAverageDistanceBetweenPoints(), second->getAverageDistanceBetweenPoints()); const int num = second->getNumberOfPoints(); for (int i = 0; i < num; i++) { float x, y, z; second->getPointXYZ(i, x, y, z); first->addPoint(x, y, z); } if (dist > 0.0) { first->resample(dist); } deleteContour(contour2); } setModified(); setMinMaxSections(); } /** * Set the spacing between sections (millimeters). */ void ContourFile::setSectionSpacing(const float sectionSpacingIn) { sectionSpacing = sectionSpacingIn; setModified(); } /** * Sort the contours by section number. */ void ContourFile::sortBySectionNumber() { if (DebugControl::getDebugOn()) { std::cout << "Before sorting: "; const int num = getNumberOfContours(); for (int i = 0; i < num; i++) { std::cout << " " << getContour(i)->getSectionNumber(); } std::cout << std::endl; } std::sort(contours.begin(), contours.end()); const int num1 = getNumberOfContours(); for (int i = 0; i < num1; i++) { getContour(i)->contourFile = this; } if (DebugControl::getDebugOn()) { std::cout << "After sorting: "; const int num2 = getNumberOfContours(); for (int i = 0; i < num2; i++) { std::cout << " " << getContour(i)->getSectionNumber(); } std::cout << std::endl; } } /** * import contours from a Nuerolucida File. */ void ContourFile::importNeurolucidaFile(const NeurolucidaFile& nf) throw (FileException) { const int num = nf.getNumberOfContours(); for (int i = 0; i < num; i++) { addContour(*(nf.getContour(i))); } } /** * import contours from an MD Plot File. */ void ContourFile::importMDPlotFile(const MDPlotFile& mdf) throw (FileException) { const int numLines = mdf.getNumberOfLines(); const int numVerticesInFile = mdf.getNumberOfVertices(); for (int i = 0; i < numLines; i++) { const MDPlotLine* mdl = mdf.getLine(i); bool sectionHasBeenSetFlag = false; const int numVerticesInLine = mdl->getNumberOfVertices(); CaretContour cc; //(numVerticesInLine); for (int j = 0; j < numVerticesInLine; j++) { const int vertexIndex = mdl->getVertexIndex(j); if ((vertexIndex < 0) || (vertexIndex >= numVerticesInFile)) { std::cout << "PROGRAM ERROR line " << __LINE__ << " file " << __FILE__ << " :: Invalid MDPlot Vertex (" << j << ") Index in ContourFile::importMDPlotFile: " << vertexIndex << std::endl; continue; } const MDPlotVertex* mdv = mdf.getVertex(vertexIndex); if (mdv == NULL) { std::cout << "PROGRAM ERROR line " << __LINE__ << " file " << __FILE__ << " :: NULL MDPlot Vertex in ContourFile::importMDPlotFile" << std::endl; continue; } float x, y, z; mdv->getXYZ(x, y, z); if (sectionHasBeenSetFlag == false) { sectionHasBeenSetFlag = true; cc.setSectionNumber(static_cast(z)); } cc.addPoint(x, y, z); } if (cc.getNumberOfPoints() > 0) { addContour(cc); } } } /** * Get main window scaling (invalid if negative values). */ void ContourFile::getMainWindowScaling(float scaleOut[3]) const { scaleOut[0] = mainWindowScaling[0]; scaleOut[1] = mainWindowScaling[1]; scaleOut[2] = mainWindowScaling[2]; } /** * Set the main window scaling */ void ContourFile::setMainWindowScaling(const float scaleIn[3]) { mainWindowScaling[0] = scaleIn[0]; mainWindowScaling[1] = scaleIn[1]; mainWindowScaling[2] = scaleIn[2]; setModified(); } /** * Read a version 1 contour file. */ void ContourFile::readFileDataVersion1(QTextStream& stream) throw (FileException) { int numContours = -1; bool readingTags = true; while(readingTags) { QString tag, tagValue; readTagLine(stream, tag, tagValue); if (tag == tagBeginData) { readingTags = false; } else if (tag == tagNumberOfContours) { numContours = tagValue.toInt(); } else if (tag == tagSectionSpacing) { sectionSpacing = tagValue.toFloat(); } else if (tag == tagMainWindowScaling) { std::vector scaling; StringUtilities::token(tagValue, " ", scaling); if (scaling.size() >= 3) { mainWindowScaling[0] = scaling[0]; mainWindowScaling[1] = scaling[1]; mainWindowScaling[2] = scaling[2]; } } } if (numContours <= 0) { throw FileException(filename, "Contour File contains 0 contours."); } QString line, lastLine; std::vector tokens; for (int i = 0; i < numContours; i++) { lastLine = line; readLineIntoTokens(stream, line, tokens); //if (DebugControl::getDebugOn()) { // std::cout << "reading contour i: " << i; // if (tokens.empty() == false) { // std::cout << " contour num: " << tokens[0].toInt(); // } // std::cout << std::endl; //} if (tokens.size() == 3) { const int numPoints = tokens[1].toInt(); const int section = tokens[2].toInt(); //if (DebugControl::getDebugOn()) { std::cout << "contour " << i << ", section " << section << ", contains " << numPoints << " points." << std::endl; //} CaretContour cc; cc.setSectionNumber(section); for (int j = 0; j < numPoints; j++) { lastLine = line; readLineIntoTokens(stream, line, tokens); if (tokens.size() == 2) { const float x = tokens[0].toFloat(); const float y = tokens[1].toFloat(); if (sectionSpacing != 0.0) { cc.addPoint(x, y, section * sectionSpacing); } else { cc.addPoint(x, y, section); } } else { QString msg("ERROR: Reading contour file data line "); msg.append(line); msg.append("\nPrevious line read: "); msg.append(lastLine); throw FileException(filename, msg); } } if (cc.getNumberOfPoints() > 0) { addContour(cc); } } else { QString msg("ERROR: Reading contour file data line: "); msg.append(line); msg.append("\nPrevious line read: "); msg.append(lastLine); throw FileException(filename, msg); } } } /** * Read a version 0 contour file. */ void ContourFile::readFileDataVersion0(QTextStream& /*stream*/) throw (FileException) { throw FileException(filename, "Reading version 0 contour files not supported."); } /** * Read a contour file's data. */ void ContourFile::readFileData(QFile& file, QTextStream& stream, QDataStream&, QDomElement& /* rootElement */) throw (FileException) { // // Should reading data be skipped ? // if (getReadMetaDataOnlyFlag()) { return; } // // save file position since version 0 has no tags // const qint64 oldFilePosition = stream.pos(); //file.pos(); int fileVersion = 0; QString versionStr, versionNumberStr; readTagLine(stream, versionStr, versionNumberStr); if (versionStr == tagFileVersion) { fileVersion = versionNumberStr.toInt(); } switch(fileVersion) { case 0: file.seek(oldFilePosition); stream.seek(oldFilePosition); readFileDataVersion0(stream); break; case 1: readFileDataVersion1(stream); break; default: throw FileException(filename, "Invalid Contour File version. Perhaps you need a newer version of Caret."); break; } setMinMaxSections(); minimumSelectedSection = minimumSection; maximumSelectedSection = maximumSection; setSectionType(SECTION_TYPE_ALL); } /** * write a contour file's data. */ void ContourFile::writeFileData(QTextStream& stream, QDataStream&, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException) { const int numContours = getNumberOfContours(); stream << tagFileVersion << " 1\n"; stream << tagNumberOfContours << " " << numContours << "\n"; stream << tagSectionSpacing << " " << sectionSpacing << "\n"; stream << tagMainWindowScaling << " " << mainWindowScaling[0] << " " << mainWindowScaling[1] << " " << mainWindowScaling[2] << "\n"; stream << tagBeginData << "\n"; for (int i = 0; i < numContours; i++) { CaretContour* cc = getContour(i); const int numPoints = cc->getNumberOfPoints(); stream << i << " " << numPoints << " " << cc->sectionNumber << "\n"; for (int j = 0; j < numPoints; j++) { stream << cc->points[j].x << " " << cc->points[j].y << "\n"; } } } /** * get the section type. */ ContourFile::SECTION_TYPE ContourFile::getSectionType() const { return sectionType; } /** * Set the selection type. */ void ContourFile::setSectionType(const SECTION_TYPE type) { sectionType = type; switch(sectionType) { case SECTION_TYPE_SINGLE: maximumSelectedSection = minimumSelectedSection; break; case SECTION_TYPE_MULTIPLE: break; case SECTION_TYPE_ALL: minimumSelectedSection = minimumSection; maximumSelectedSection = maximumSection; break; case SECTION_TYPE_HIDE: break; } } /** * get the minimum selected section */ int ContourFile::getMinimumSelectedSection() const { return minimumSelectedSection; } /** * get the maximum selected section */ int ContourFile::getMaximumSelectedSection() const { return maximumSelectedSection; } /** * set the minimum selected section */ void ContourFile::setMinimumSelectedSection(const int sect) { minimumSelectedSection = sect; } /** * set the maximum selected section */ void ContourFile::setMaximumSelectedSection(const int sect) { maximumSelectedSection = sect; } /** * Update minimum and maximum section numbers. */ void ContourFile::updateMinMaxSections(const int sectionNumber) { if (sectionNumber < minimumSection) { minimumSection = sectionNumber; } if (sectionNumber > maximumSection) { maximumSection = sectionNumber; } if (sectionType == SECTION_TYPE_ALL) { minimumSelectedSection = minimumSection; maximumSelectedSection = maximumSection; } } caret-5.6.4~dfsg.1.orig/caret_files/ContourCellFile.h0000664000175000017500000000277511572067322022256 0ustar michaelmichael #ifndef __CONTOUR_CELL_FILE_H__ #define __CONTOUR_CELL_FILE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CellFile.h" class MDPlotFile; class NeurolucidaFile; /// class for cell colors file class ContourCellFile : public CellFile { public: /// Constructor ContourCellFile(); /// Destructor ~ContourCellFile(); /// import cells from an MD Plot File void importMDPlotFile(const MDPlotFile& mdf) throw (FileException); /// import cells from a Nuerolucida File void importNeurolucidaFile(const NeurolucidaFile& nf) throw (FileException); protected: }; #endif // __CONTOUR_CELL_FILE_H__ caret-5.6.4~dfsg.1.orig/caret_files/ContourCellFile.cxx0000664000175000017500000000376611572067322022632 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "ContourCellFile.h" #include "MDPlotFile.h" #include "NeurolucidaFile.h" #include "SpecFile.h" /** * Constructor */ ContourCellFile::ContourCellFile() : CellFile("Contour Cell File", SpecFile::getContourCellFileExtension()) { } /** * Destructor */ ContourCellFile::~ContourCellFile() { } /** * import cells from an MD Plot File. */ void ContourCellFile::importMDPlotFile(const MDPlotFile& mdf) throw (FileException) { for (int i = 0; i < mdf.getNumberOfPoints(); i++) { const MDPlotPoint* mp = mdf.getPoint(i); const MDPlotColor::COLOR color = mp->getColor(); const int vertexIndex = mp->getVertex(); const MDPlotVertex* vertex = mdf.getVertex(vertexIndex); const float* xyz = vertex->getXYZ(); const QString name = MDPlotColor::getColorName(color); CellData cd(name, xyz[0], xyz[1], xyz[2], static_cast(xyz[2])); addCell(cd); } } /** * import cells from a Nuerolucida File. */ void ContourCellFile::importNeurolucidaFile(const NeurolucidaFile& nf) throw (FileException) { for (int i = 0; i < nf.getNumberOfMarkers(); i++) { addCell(*(nf.getMarker(i))); } } caret-5.6.4~dfsg.1.orig/caret_files/ContourCellColorFile.h0000664000175000017500000000305411572067322023244 0ustar michaelmichael #ifndef __CONTOUR_CELL_COLOR_FILE_H__ #define __CONTOUR_CELL_COLOR_FILE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "ColorFile.h" #include "MDPlotFile.h" #include "NeurolucidaFile.h" /// class for contour cell colors file class ContourCellColorFile : public ColorFile { public: /// Constructor ContourCellColorFile(); /// Destructor ~ContourCellColorFile(); /// import colors from an MD Plot File void importMDPlotFileColors() throw (FileException); /// import colors from an Neurolucida File void importNeurolucidaFileColors(const NeurolucidaFile& nf) throw (FileException); protected: }; #endif // __CONTOUR_CELL_COLOR_FILE_H__ caret-5.6.4~dfsg.1.orig/caret_files/ContourCellColorFile.cxx0000664000175000017500000000407211572067322023620 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "ContourCellColorFile.h" #include "MDPlotFile.h" #include "NeurolucidaFile.h" #include "SpecFile.h" /** * Constructor */ ContourCellColorFile::ContourCellColorFile() : ColorFile("Contour Cell Color File", SpecFile::getContourCellColorFileExtension()) { } /** * Destructor */ ContourCellColorFile::~ContourCellColorFile() { } /** * import colors from an Neurolucida File. */ void ContourCellColorFile::importNeurolucidaFileColors(const NeurolucidaFile& nf) throw (FileException) { for (int i = 0; i < nf.getNumberOfMarkerColors(); i++) { colors.push_back(*(nf.getMarkerColor(i))); } setModified(); } /** * import colors from an MD Plot File. */ void ContourCellColorFile::importMDPlotFileColors() throw (FileException) { for (int i = 0; i < MDPlotColor::getNumberOfColors(); i++) { const MDPlotColor::COLOR color = static_cast(i); const QString name = MDPlotColor::getColorName(color); bool exactMatch = false; getColorIndexByName(name, exactMatch); if (exactMatch == false) { unsigned char r, g, b; MDPlotColor::getColorComponents(color, r, g, b); addColor(name, r, g, b); } } } caret-5.6.4~dfsg.1.orig/caret_files/CommaSeparatedValueFile.h0000664000175000017500000001046311572067322023700 0ustar michaelmichael #ifndef __COMMA_SEPARATED_VALUE_FILE_H__ #define __COMMA_SEPARATED_VALUE_FILE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "AbstractFile.h" class StringTable; /// stores data in a CSV (comma separated values) file class CommaSeparatedValueFile : public AbstractFile { public: // constructor CommaSeparatedValueFile(); // destructor ~CommaSeparatedValueFile(); // clear the file void clear(); // returns true if the file is isEmpty (contains no data) bool empty() const; /// get the number of data sections int getNumberOfDataSections() const { return dataSections.size(); } /// get a data section StringTable* getDataSection(const int indx) { return dataSections[indx]; } /// get a data section (const method) const StringTable* getDataSection(const int indx) const { return dataSections[indx]; } /// get a data section (const method) const StringTable* getDataSectionByName(const QString& name) const; /// get a data section (const method) StringTable* getDataSectionByName(const QString& name); /// add a data section (returns its index) int addDataSection(StringTable* dataSectionToAdd); /// read from the data to the stream void readFromTextStream(QFile& file, QTextStream& stream) throw (FileException); /// write the data to the stream void writeToTextStream(QTextStream& stream) throw (FileException); /// get the first line in a comma separated value file static QString getFirstLineCommaSeparatedValueFileIdentifier() { return "CSVF-FILE"; } protected: // read the file void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException); // add any extra commas and then a newline void addExtraCommasAndNewline(QTextStream& stream, const int numCommas); // write file void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException); /// write a section to a file void writeDataSection(QTextStream& stream, const StringTable* section, const int maximumColumns) throw (FileException); /// write a data element void writeDataElement(QTextStream& stream, const QString& dataElement); /// clean up read item that was read (remove quotes, trim whitespace, etc) void cleanupItem(QString& element); /// the sections in the file std::vector dataSections; /// section start tag static const QString sectionStartTag; /// section end tag static const QString sectionEndTag; /// current file version static const int currentFileVersion; }; #endif // __COMMA_SEPARATED_VALUE_FILE_H__ #ifdef __COMMA_SEPARATED_FILE_MAIN__ const QString CommaSeparatedValueFile::sectionStartTag = "csvf-section-start"; const QString CommaSeparatedValueFile::sectionEndTag = "csvf-section-end"; const int CommaSeparatedValueFile::currentFileVersion = 0; #endif // __COMMA_SEPARATED_FILE_MAIN__ caret-5.6.4~dfsg.1.orig/caret_files/CommaSeparatedValueFile.cxx0000664000175000017500000005325411572067322024260 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #define __COMMA_SEPARATED_FILE_MAIN__ #include "CommaSeparatedValueFile.h" #undef __COMMA_SEPARATED_FILE_MAIN__ #include "DebugControl.h" #include "StringTable.h" #include "SpecFile.h" /** * constructor. */ CommaSeparatedValueFile::CommaSeparatedValueFile() : AbstractFile("Comma Separated Values File", SpecFile::getCommaSeparatedValueFileExtension(), false, // no header FILE_FORMAT_OTHER, FILE_IO_NONE, FILE_IO_NONE, FILE_IO_NONE, FILE_IO_NONE, FILE_IO_NONE, FILE_IO_READ_AND_WRITE) { } /** * destructor. */ CommaSeparatedValueFile::~CommaSeparatedValueFile() { clear(); } /** * clear the file. */ void CommaSeparatedValueFile::clear() { clearAbstractFile(); for (unsigned int i = 0; i < dataSections.size(); i++) { delete dataSections[i]; dataSections[i] = NULL; } dataSections.clear(); } /** * returns true if the file is isEmpty (contains no data). */ bool CommaSeparatedValueFile::empty() const { return dataSections.empty(); } /** * get a data section (const method). */ const StringTable* CommaSeparatedValueFile::getDataSectionByName(const QString& name) const { for (unsigned int i = 0; i < dataSections.size(); i++) { if (dataSections[i]->getTableTitle().compare(name, Qt::CaseInsensitive) == 0) { return dataSections[i]; } } return NULL; } /** * read from the data to the text stream */ void CommaSeparatedValueFile::readFromTextStream(QFile& file, QTextStream& stream) throw (FileException) { QDataStream dummyDataStream(&file); dummyDataStream.setVersion(QDataStream::Qt_4_3); QDomElement dummyDomElement; readFileData(file, stream, dummyDataStream, dummyDomElement); } /** * write the data to the text stream. */ void CommaSeparatedValueFile::writeToTextStream(QTextStream& stream) throw (FileException) { QDataStream dummyDataStream; dummyDataStream.setVersion(QDataStream::Qt_4_3); QDomDocument dummyDomDocument; QDomElement dummyDomElement; writeFileData(stream, dummyDataStream, dummyDomDocument, dummyDomElement); } /** * get a data section (const method). */ StringTable* CommaSeparatedValueFile::getDataSectionByName(const QString& name) { for (unsigned int i = 0; i < dataSections.size(); i++) { if (dataSections[i]->getTableTitle().compare(name, Qt::CaseInsensitive) == 0) { return dataSections[i]; } } return NULL; } /** * read the file. */ void CommaSeparatedValueFile::readFileData(QFile& /*file*/, QTextStream& stream, QDataStream& /*binStream*/, QDomElement& /* rootElement */) throw (FileException) { // // Notes about reading a Comma Separated Value File: // // * There may be newline characters (\n or \r) within a string delimeted // by double quotes // * If an element contains a double quote a second double quote is added // * Each element is separated by commas (but not commas embedded in strings // delimeted by double quotes // * each record is delimeted by newlines (but not newlines in string delimeted // by double quotes // const qint64 bufferSize = 4096; QString buffer; // // Some flags for reading file // bool endOfItem = false; bool endOfRecord = false; bool inString = false; QChar nextCharacter = 0; bool firstRecordFlag = true; int recordCount = 0; // // Table currently being loaded // StringTable* currentTable = NULL; bool currentTableColumnNamesHaveBeenSet = false; // // QString for current item and vector for items in record // QString currentItem; std::vector currentRecord; // // Read until done // QString nextBuffer; bool done = false; while (done == false) { // // read some data // if (nextBuffer.isEmpty() == false) { buffer = nextBuffer; nextBuffer.clear(); } else { buffer = stream.read(bufferSize); } const qint64 numRead = buffer.length(); if (numRead <= 0) { done = true; } else { // // Process characters in the buffer // for (int i = 0; i < numRead; i++) { // // get character from the buffer // const QChar ch = buffer[i]; // // Also want to know the next character // nextCharacter = 0; if (i < (numRead - 1)) { nextCharacter = buffer[i+1]; } else if (stream.atEnd() == false) { nextBuffer = stream.read(bufferSize); if (nextBuffer.isEmpty() == false) { nextCharacter = nextBuffer[0]; } /* const qint64 oldPos = stream.pos(); const QString temp = stream.read(1); if (temp.isEmpty() == false) { nextCharacter = temp[0]; } stream.seek(oldPos); */ } // // By default we want to use the current character // bool useCharacter = true; // // Under some circumstances, a character may be skipped // bool skipNextCharacter = false; // // Check for characters that delineate lines or elements // if (ch.toAscii() == QChar('"')) { // double quotes in a string are two consecutive double quotes // If currently reading the contents of a string // if (inString) { // // If Double quotes within a string then do not need two of them so skip next // if (nextCharacter.toAscii() == QChar('"')) { skipNextCharacter = true; } else { // // Just a single quote so at end of the string // inString = false; } } else { // // Starting a string // inString = true; } } else if (ch.toAscii() == QChar(',')) { // comma // // Commas not within a string delineate elements // if (inString == false) { endOfItem = true; useCharacter = false; } } else if (ch.toAscii() == QChar('\r')) { // carriage return 0x0d if (inString == false) { // // carriage return not in a string denotes end of element and end of line // endOfItem = true; endOfRecord = true; useCharacter = false; } // // Some operating systems follow a carriage return with a newline // if (nextCharacter.toAscii() == QChar('\n')) { skipNextCharacter = true; } } else if (ch.toAscii() == QChar('\n')) { // line feed 0x0a if (inString == false) { // // Line feed not in a string denotes end of element and end of line // endOfItem = true; endOfRecord = true; useCharacter = false; } } // // Save the character just parsed // if (useCharacter) { currentItem.append(ch); } // // At end of item? // if (endOfItem) { // // Add to current record // cleanupItem(currentItem); currentRecord.push_back(currentItem); // // clear current item // currentItem = ""; endOfItem = false; // // At end of record? // if (endOfRecord) { // // is there data in the record // const int numItems = static_cast(currentRecord.size()); if (numItems > 0) { if (DebugControl::getDebugOn()) { if (currentRecord[0] == "305") { std::cout << "At focus 305" << std::endl; } } // // The first record must be the CSVF identifier // if (firstRecordFlag) { if (currentRecord[0] != getFirstLineCommaSeparatedValueFileIdentifier()) { QString msg("First line in file must be \""); msg += getFirstLineCommaSeparatedValueFileIdentifier(); msg += ".\""; throw FileException(msg); } // // Check file version // int fileVersion = 0; if (numItems > 1) { fileVersion = currentRecord[1].toInt(); } if (fileVersion > currentFileVersion) { QString msg = "CSVF version read is " + currentRecord[1] + " but this version of Caret only supports version " + QString::number(currentFileVersion) + " and earlier Comma Separated Value Files."; throw FileException(msg); } firstRecordFlag = false; } else if (currentRecord[0].compare(sectionStartTag, Qt::CaseInsensitive) == 0) { // // Start a new StringTable // if (numItems >= 3) { const int numColumns = currentRecord[2].toInt(); currentTable = new StringTable(0, numColumns, currentRecord[1]); currentTableColumnNamesHaveBeenSet = false; } else { QString msg("CSVF File section start must have table title and " "number of columns for record number="); msg += QString::number(recordCount); throw FileException(msg); } } else if (currentRecord[0].compare(sectionEndTag, Qt::CaseInsensitive) == 0) { // // Add current StringTable to the file // if (currentTable != NULL) { addDataSection(currentTable); currentTable = NULL; } else { throw FileException("CSVF File has currentTable NULL at end of section."); } } else { if (currentTable != NULL) { // // First row is the column titles // if (currentTableColumnNamesHaveBeenSet == false) { for (int jj = 0; jj < std::min(currentTable->getNumberOfColumns(), numItems); jj++) { currentTable->setColumnTitle(jj, currentRecord[jj]); } currentTableColumnNamesHaveBeenSet = true; } else { // // Add a row of data // currentTable->addRow(currentRecord); } } else { bool allEmpty = true; for (unsigned int im = 0; im < currentRecord.size(); im++) { if (currentRecord[im].trimmed().isEmpty() == false) { allEmpty = false; break; } } if (allEmpty == false) { throw FileException("CSVF File has currentTable NULL when adding data."); } } } } if (DebugControl::getDebugOn()) { const int numItems = static_cast(currentRecord.size()); std::cout << "CSVF: Read record with count items: " << numItems << std::endl; //QStringList sl; //for (int mm = 0; mm < numItems; mm++) { // sl << currentRecord[mm]; //} //std::cout << sl.join("|").toAscii().constData() << std::endl; } currentRecord.clear(); endOfRecord = false; recordCount++; } } // // Should next character be skipped // if (skipNextCharacter) { // // At end of buffer? // if (i >= (numRead - 1)) { // // Read and ignore one character // (void)stream.read(1); } else { // // Skip one character forward in the buffer // i++; } } } } } // // Was something stil being read? // if (currentItem.isEmpty() == false) { cleanupItem(currentItem); currentRecord.push_back(currentItem); } // // Is there data for another line // if (currentRecord.empty() == false) { if (DebugControl::getDebugOn()) { std::cout << "LAST Read record with count items: " << currentRecord.size() << std::endl; } if (currentRecord[0].compare(sectionEndTag, Qt::CaseInsensitive) == 0) { // // Add current StringTable to the file // if (currentTable != NULL) { addDataSection(currentTable); currentTable = NULL; currentTableColumnNamesHaveBeenSet = false; } else { throw FileException("CSVF File has currentTable NULL at end of section."); } } } // // If a table was being read then it is missing its end tag // if (currentTable != NULL) { const QString msg("Data section named " + currentTable->getTableTitle() + "\n" + "is missing its \"" + CommaSeparatedValueFile::sectionEndTag + "\" tag."); throw FileException(msg); } } /** * clean up read item that was read (remove quotes, trim whitespace, etc). */ void CommaSeparatedValueFile::cleanupItem(QString& item) { // // Get rid of leading and trailing whitespace // item = item.trimmed(); const int len = item.length(); if (len >= 2) { // // Check for and remove double quotes at beggining and end // if (item.startsWith('"') && item.endsWith('"')) { item = item.mid(1, len - 2); } } } /** * write file. */ void CommaSeparatedValueFile::writeFileData(QTextStream& stream, QDataStream& /*binStream*/, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException) { // // Determine the maximum columns of all of the data sections // const int numSections = getNumberOfDataSections(); int maximumColumns = 0; for (int i = 0; i < numSections; i++) { maximumColumns = std::max(maximumColumns, getDataSection(i)->getNumberOfColumns()); } if (maximumColumns <= 0) { throw FileException("No data for writing."); } // // Must have at least 3 columns since section start records have // three items, csvf-section-start,header,#columns-in-data // maximumColumns = std::max(maximumColumns, 3); // // Write the first line indicating this is a CSVF format // stream << getFirstLineCommaSeparatedValueFileIdentifier() << "," << currentFileVersion; addExtraCommasAndNewline(stream, maximumColumns - 2); // // Write the data sections // for (int i = 0; i < numSections; i++) { writeDataSection(stream, getDataSection(i), maximumColumns); } } /** * write a section to a file. */ void CommaSeparatedValueFile::writeDataSection(QTextStream& stream, const StringTable* section, const int maximumColumns) throw (FileException) { // // Make sure there is data to write // const int numRows = section->getNumberOfRows(); const int numColumns = section->getNumberOfColumns(); if ((numRows <= 0) || (numColumns <= 0)) { return; } // // Write the start of the section // stream << sectionStartTag << "," << section->getTableTitle() << "," << numColumns; addExtraCommasAndNewline(stream, maximumColumns - 3); // // write the column titles // for (int i = 0; i < numColumns; i++) { if (i > 0) { stream << ","; } stream << section->getColumnTitle(i); } addExtraCommasAndNewline(stream, maximumColumns - numColumns); // // Write the data // for (int i = 0; i < numRows; i++) { for (int j = 0; j < numColumns; j++) { if (j > 0) { stream << ","; } writeDataElement(stream, section->getElement(i, j)); } addExtraCommasAndNewline(stream, maximumColumns - numColumns); } // // Write the end of the section // stream << sectionEndTag << "," << section->getTableTitle(); addExtraCommasAndNewline(stream, maximumColumns - 2); } /** * write a data element. */ void CommaSeparatedValueFile::writeDataElement(QTextStream& stream, const QString& dataElementIn) { QString dataElement = dataElementIn; bool needsQuotes = false; // // In a CSV file, a double quote is replaced by two double quotes // and the whole thing must be enclosed in double quotes // if (dataElement.indexOf('"') >= 0) { needsQuotes = true; dataElement = dataElement.replace('"', "\"\""); } // // If the element contains commas the whole thing must be put in double quotes // if (dataElement.indexOf(',') >= 0) { needsQuotes = true; } // // If it has carriage return, convert to line feed // if (dataElement.indexOf('\r') >= 0) { dataElement = dataElement.replace('\r', '\n'); } // // If it has line feed surround with quotes // if (dataElement.indexOf('\n') >= 0) { needsQuotes = true; } // // If needed enclose in double quotes // if (needsQuotes) { stream << "\""; stream << dataElement; stream << "\""; } else { stream << dataElement; } } /** * add any extra commas and then a newline. */ void CommaSeparatedValueFile::addExtraCommasAndNewline(QTextStream& stream, const int numCommas) { for (int i = 0; i < numCommas; i++) { stream << ","; } stream << endl; } /** * add a data section (returns its index). */ int CommaSeparatedValueFile::addDataSection(StringTable* dataSectionToAdd) { dataSections.push_back(dataSectionToAdd); return (dataSections.size() - 1); } caret-5.6.4~dfsg.1.orig/caret_files/ColorFile.h0000664000175000017500000003357711572067322021107 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_COLOR_FILE_H__ #define __VE_COLOR_FILE_H__ #include "AbstractFile.h" class CommaSeparatedValueFile; class QDomNode; /// Color File class ColorFile : public AbstractFile { public: /// Class for color's name and RGB components class ColorStorage { public: /// symbol enum SYMBOL { /// box SYMBOL_BOX, /// diamond SYMBOL_DIAMOND, /// disk symbol SYMBOL_DISK, /// point SYMBOL_OPENGL_POINT, /// ring SYMBOL_RING, /// sphere SYMBOL_SPHERE, /// square SYMBOL_SQUARE, /// no symbol SYMBOL_NONE }; // constructor ColorStorage(); // constructor ColorStorage(const QString& nameIn, const unsigned char red, const unsigned char green, const unsigned char blue, const float pointSizeIn, const float lineSizeIn); // constructor ColorStorage(const QString& nameIn, const unsigned char red, const unsigned char green, const unsigned char blue, const unsigned char alpha, const float pointSizeIn, const float lineSizeIn, const SYMBOL symmbolIn = SYMBOL_OPENGL_POINT, const QString& sumsIDIn = ""); // destructor virtual ~ColorStorage(); // is the color selected bool getSelected() const; // set the selection status void setSelected(const bool b); // get the symbol SYMBOL getSymbol() const; // set the symbol void setSymbol(const SYMBOL s); // get the name QString getName() const; // set the name void setName(const QString& n); // get the line size float getLineSize() const; // set the line size void setLineSize(const float s); // get the point size float getPointSize() const; // set the point size void setPointSize(const float s); // get rgb colors const unsigned char* getRgb() const; // get the rgb colors void getRgb(unsigned char& r, unsigned char& g, unsigned char& b) const; // set the rgb colors void setRgb(const unsigned char rgbIn[3]); // set the rgb colors void setRgb(const unsigned char r, const unsigned char g, const unsigned char b); // get rgba colors const unsigned char* getRgba() const; // get the rgba colors void getRgba(unsigned char& r, unsigned char& g, unsigned char& b, unsigned char& a) const; // set the rgba colors void setRgba(const unsigned char rgbaIn[4]); // set the rgba colors void setRgba(const unsigned char r, const unsigned char g, const unsigned char b, const unsigned char a); // get the SuMS color id QString getSuMSColorID() const; // set the SuMS color id void setSuMSColorID(const QString& id); // called to read from an XML structure. void readXML(QDomNode& nodeIn) throw (FileException); // called to write to an XML structure. void writeXML(QDomDocument& xmlDoc, QDomElement& parentElement); // symbol enum to text static QString symbolToText(const SYMBOL s); // text to symbol enum static SYMBOL textToSymbol(const QString& s); // get all symbol types as strings static void getAllSymbolTypesAsStrings(std::vector& symbolStrings); protected: /// name of color QString name; /// color components unsigned char rgba[4]; /// point size float pointSize; /// line size float lineSize; /// color selected bool selected; /// the symbol SYMBOL symbol; /// color id QString sumsColorID; }; protected: /// Constructor ColorFile(const QString& descriptiveName, const QString& defaultExtensionIn); /// storage of colors std::vector colors; /// read the color file void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException); /// write the color file void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException); // write the file's data into a comma separated values file (throws exception if not supported) virtual void writeDataIntoCommaSeparatedValueFile(CommaSeparatedValueFile& csv) throw (FileException); // read the file's data from a comma separated values file (throws exception if not supported) virtual void readDataFromCommaSeparatedValuesTable(const CommaSeparatedValueFile& csv) throw (FileException); public: /// Destructor virtual ~ColorFile(); /// get a "new" color file from the file name's extension /// Note: file is not read, just a new file is returned. static ColorFile* getColorFileFromFileNameExtension(const QString& fileNameIn) throw (FileException); /// add a color int addColor(const QString& name, const unsigned char r, const unsigned char g, const unsigned char b, const unsigned char alpha = 255, const float pointSize = 2.0, const float lineSize = 1.0, ColorStorage::SYMBOL symbol = ColorStorage::SYMBOL_OPENGL_POINT, const QString& colorIdIn = ""); /// add a color if it does not exist int addColorIfItDoesNotExist(const QString& name, const unsigned char r, const unsigned char g, const unsigned char b, const unsigned char alpha = 255, const float pointSize = 2.0, const float lineSize = 1.0, ColorStorage::SYMBOL symbol = ColorStorage::SYMBOL_OPENGL_POINT, const QString& colorIdIn = ""); /// append a color file to this one void append(const ColorFile& cf); /// clear the color file void clear(); /// returns true if the file is isEmpty (contains no data) bool empty() const { return (getNumberOfColors() == 0); } /// Generate random colors for any name that does not match an area color name. /// if "requireExactMatchFlag" is true, a new color is created in there is not /// a color that exactly matches name. If "requireExactMatchFlag" is false /// and the "name" begins with the color name, a new color is not created, /// so, for example, if "name" is "SUL.CeS" and there is a color named "SUL", /// a new color is not created. void generateColorsForNamesWithoutColors(const std::vector& names, const bool requireExactMatchFlag); /// get the number of colors int getNumberOfColors() const { return colors.size(); } /// Get a color ColorStorage* getColor(const int indx) { return &colors[indx]; } /// Get a color (const method) const ColorStorage* getColor(const int indx) const { return &colors[indx]; } /// get color indices sorted by name case insensitive void getColorIndicesSortedByName(std::vector& indicesSortedByNameOut, const bool reverseOrderFlag) const; /// get color by index void getColorByIndex(const int index, unsigned char& red, unsigned char& green, unsigned char& blue) const; /// get color by index void getColorByIndex(const int index, unsigned char& red, unsigned char& green, unsigned char& blue, unsigned char& alpha) const; /// get line and point size by index void getPointLineSizeByIndex(const int index, float& pointSize, float& lineSize) const; /// get the symbol by the color index ColorStorage::SYMBOL getSymbolByIndex(const int indx) const; /// get the SuMS color id by index QString getSumsColorIDByIndex(const int indx) const; /// set the SuMS color id by index void setSumsColorIDByIndex(const int indx, const QString& idIn); /// get color name by index QString getColorNameByIndex(const int index) const; /// set color name by index void setColorNameByIndex(const int index, const QString& name); /// get color index by name int getColorIndexByName(const QString& name, bool& exactMatch) const; /// get color by name int getColorByName(const QString& name, bool& exactMatch, unsigned char& red, unsigned char& green, unsigned char& blue) const; /// get color by name int getColorByName(const QString& name, bool& exactMatch, unsigned char& red, unsigned char& green, unsigned char& blue, unsigned char& alpha) const; /// see if a color exists bool getColorExists(const QString& name) const; /// get color selected bool getSelected(const int index) const { return colors[index].getSelected(); } /// set color selected void setSelected(const int index, const bool sel) { colors[index].setSelected(sel); } /// remove color at specified index void removeColorByIndex(const int index); /// set status of all colors selected void setAllSelectedStatus(const bool sel); /// set color by index void setColorByIndex(const int index, const QString& name, const unsigned char red, const unsigned char green, const unsigned char blue); /// set color by index void setColorByIndex(const int index, const QString& name, const unsigned char red, const unsigned char green, const unsigned char blue, const unsigned char alpha); /// set color by index void setColorByIndex(const int index, const unsigned char red, const unsigned char green, const unsigned char blue); /// set color by index void setColorByIndex(const int index, const unsigned char red, const unsigned char green, const unsigned char blue, const unsigned char alpha); /// set line and point size by index void setPointLineSizeByIndex(const int index, const float pointSize, const float lineSize); /// set symbol by index void setSymbolByIndex(const int indx, const ColorStorage::SYMBOL s); /// set the number of colors void setNumberOfColors(const int numColors); // find out if comma separated file conversion supported virtual void getCommaSeparatedFileSupport(bool& readFromCSV, bool& writeToCSV) const; /// write the file's memory in caret6 format to the specified name virtual QString writeFileInCaret6Format(const QString& filenameIn, Structure structure,const ColorFile* colorFileIn, const bool useCaret6ExtensionFlag) throw (FileException); }; #endif caret-5.6.4~dfsg.1.orig/caret_files/ColorFile.cxx0000664000175000017500000011772611572067322021461 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include "AreaColorFile.h" #include "BorderColorFile.h" #include "CellColorFile.h" #include "ColorFile.h" #include "CommaSeparatedValueFile.h" #include "ContourCellColorFile.h" #include "GiftiDataArrayFile.h" #include "GiftiLabelTable.h" #include "FociColorFile.h" #include "NameIndexSort.h" #include "StringTable.h" /** * The constructor. */ ColorFile::ColorFile(const QString& descriptiveName, const QString& defaultExtensionIn) : AbstractFile(descriptiveName, defaultExtensionIn, true, FILE_FORMAT_XML, FILE_IO_READ_ONLY, // ascii FILE_IO_NONE, // binary FILE_IO_READ_AND_WRITE, // xml FILE_IO_NONE, // xml base-64 FILE_IO_NONE, // xml gzip FILE_IO_NONE, // other FILE_IO_READ_AND_WRITE) // Comma Separated Value File { clear(); } /** * The destructor. */ ColorFile::~ColorFile() { clear(); } /** * get a "new" color file from the file name's extension * Note: file is not read, just a new file is returned. */ ColorFile* ColorFile::getColorFileFromFileNameExtension(const QString& fileNameIn) throw (FileException) { ColorFile* colorFile = NULL; if (fileNameIn.endsWith(SpecFile::getAreaColorFileExtension())) { colorFile = new AreaColorFile; } else if (fileNameIn.endsWith(SpecFile::getBorderColorFileExtension())) { colorFile = new BorderColorFile; } else if (fileNameIn.endsWith(SpecFile::getCellColorFileExtension())) { colorFile = new CellColorFile; } else if (fileNameIn.endsWith(SpecFile::getContourCellColorFileExtension())) { colorFile = new ContourCellColorFile; } else if (fileNameIn.endsWith(SpecFile::getFociColorFileExtension())) { colorFile = new FociColorFile; } else { const QString errorMessageOut = ("ERROR: Unrecognized color file name extension. " "The input color file name must end with one of: " "(Area Color File, \"" + SpecFile::getAreaColorFileExtension() + "\") " + "(Border Color File, \"" + SpecFile::getBorderColorFileExtension() + "\") " + "(Cell Color File, \"" + SpecFile::getCellColorFileExtension() + "\") " + "(Contour Cell Color File, \"" + SpecFile::getContourCellColorFileExtension() + "\") " + "(Foci Color File, \"" + SpecFile::getFociColorFileExtension() + "\")"); throw FileException(errorMessageOut); } return colorFile; } /** * Clear the file's contents. */ void ColorFile::clear() { clearAbstractFile(); colors.clear(); } /** * Append a color file to the current color file. */ void ColorFile::append(const ColorFile& cf) { const int numColors = cf.getNumberOfColors(); for (int i = 0; i < numColors; i++) { QString name(cf.getColorNameByIndex(i)); unsigned char r, g, b, a; cf.getColorByIndex(i, r, g, b, a); float pointSize, lineSize; cf.getPointLineSizeByIndex(i, pointSize, lineSize); const ColorStorage::SYMBOL symbol = cf.getSymbolByIndex(i); const QString sumsColorID = cf.getSumsColorIDByIndex(i); /// if color already exists, replace its color components bool match; const int indx = getColorIndexByName(name, match); if ((indx >= 0) && match) { setColorByIndex(indx, name, r, g, b, a); setPointLineSizeByIndex(indx, pointSize, lineSize); setSymbolByIndex(indx, symbol); setSumsColorIDByIndex(indx, sumsColorID); } else { addColor(name, r, g, b, a, pointSize, lineSize, symbol, sumsColorID); } } // // transfer the file's comment // appendFileComment(cf); } /** * add a color if it does not exist. */ int ColorFile::addColorIfItDoesNotExist(const QString& name, const unsigned char r, const unsigned char g, const unsigned char b, const unsigned char alpha, const float pointSize, const float lineSize, ColorStorage::SYMBOL symbol, const QString& colorIdIn) { bool exactMatch = false; int indx = getColorIndexByName(name, exactMatch); if ((indx < 0) || (exactMatch == false)) { indx = addColor(name, r, g, b, alpha, pointSize, lineSize, symbol, colorIdIn); } return indx; } /** * Add a color to the color file. Returns the index of the color. */ int ColorFile::addColor(const QString& name, const unsigned char r, const unsigned char g, const unsigned char b, const unsigned char alpha, const float pointSize, const float lineSize, ColorStorage::SYMBOL symbol, const QString& colorIdIn) { if ((colors.size() == 0) && (name != "???")) { colors.push_back(ColorStorage("???", 170, 170, 170, 0, 2.0, 1.0, ColorStorage::SYMBOL_OPENGL_POINT)); } // // see if color already exists // bool match = false; unsigned char rt, gt, bt, at; const int indx = getColorByName(name, match, rt, gt, bt, at); if ((indx >= 0) && match) { if ((r == rt) && (g == gt) && (b == bt) && (alpha == at)) { std::cout << "Color " << name.toAscii().constData() << " specified multiple times with same color components." << std::endl; } else { setColorByIndex(indx, name, r, g, b, alpha); std::cout << "Color " << name.toAscii().constData() << " specified multiple times with different color components." << " Using (" << static_cast(r) << "," << static_cast(g) << "," << static_cast(b) << "," << static_cast(alpha) << ")" << std::endl; } return indx; } setModified(); colors.push_back(ColorStorage(name, r, g, b, alpha, pointSize, lineSize, symbol, colorIdIn)); return colors.size() - 1; } /** * get color indices sorted by name case insensitive. */ void ColorFile::getColorIndicesSortedByName(std::vector& indicesSortedByNameOut, const bool reverseOrderFlag) const { indicesSortedByNameOut.clear(); const int num = getNumberOfColors(); // // Sort indices by name // NameIndexSort nis; for (int i = 0; i < num; i++) { nis.add(i, getColorNameByIndex(i)); } nis.sortByNameCaseInsensitive(); indicesSortedByNameOut.resize(num, 0); for (int i = 0; i < num; i++) { indicesSortedByNameOut[i] = nis.getSortedIndex(i); } if (reverseOrderFlag) { std::reverse(indicesSortedByNameOut.begin(), indicesSortedByNameOut.end()); } } /** * Get a color by its index (no validity check is made for the index). */ void ColorFile::getColorByIndex(const int indx, unsigned char& red, unsigned char& green, unsigned char& blue) const { if ((indx >= 0) && (indx < static_cast(colors.size()))) { colors[indx].getRgb(red, green, blue); } else { red = 0; green = 0; blue = 0; } } /** * Get a color by its index (no validity check is made for the index). */ void ColorFile::getColorByIndex(const int indx, unsigned char& red, unsigned char& green, unsigned char& blue, unsigned char& alpha) const { if ((indx >= 0) && (indx < static_cast(colors.size()))) { colors[indx].getRgba(red, green, blue, alpha); } else { red = 0; green = 0; blue = 0; alpha = 255; } } /** * Get the line size and point size by index. */ void ColorFile::getPointLineSizeByIndex(const int indx, float& pointSize, float& lineSize) const { pointSize = colors[indx].getPointSize(); lineSize = colors[indx].getLineSize(); } /** * Get a color's name by its indx (no validity check is made for the indx). */ QString ColorFile::getColorNameByIndex(const int indx) const { return colors[indx].getName(); } /** * set color name by index. */ void ColorFile::setColorNameByIndex(const int indx, const QString& name) { colors[indx].setName(name); } /** * get the symbol by the color index. */ ColorFile::ColorStorage::SYMBOL ColorFile::getSymbolByIndex(const int indx) const { return colors[indx].getSymbol(); } /** * get the sums color id by index. */ QString ColorFile::getSumsColorIDByIndex(const int indx) const { return colors[indx].getSuMSColorID(); } /** * see if a color exists. */ bool ColorFile::getColorExists(const QString& name) const { bool exactMatch = false; const int indx = getColorIndexByName(name, exactMatch); if ((indx >= 0) && exactMatch) { return true; } return false; } /** * Get a color by its name. Returns indx of color if a matching color is * found, else -1. * "exactMatch will be true if the color's name was an exact match. Otherwise, * the color is a substring of "name". */ int ColorFile::getColorIndexByName(const QString& name, bool& exactMatch) const { int matchFound = -1; int matchLength = -1; exactMatch = false; const int numColors = getNumberOfColors(); for (int i = 0; i < numColors; i++) { if (colors[i].getName() == name) { matchFound = i; exactMatch = true; break; } else { const int nameLength = name.length(); const int colorLength = colors[i].getName().length(); if (colorLength < nameLength) { if (colors[i].getName() == name.mid(0, colorLength)) { if (matchFound >= 0) { if (colorLength > matchLength) { matchFound = i; matchLength = colorLength; } } else { matchFound = i; matchLength = colorLength; } } } } } return matchFound; } /** * Get a color by its name. Returns indx of color if a matching color is * found, else -1. * "exactMatch will be true if the color's name was an exact match. Otherwise, * the color is a substring of "name". */ int ColorFile::getColorByName(const QString& name, bool& exactMatch, unsigned char& red, unsigned char& green, unsigned char& blue) const { const int matchFound = getColorIndexByName(name, exactMatch); if (matchFound >= 0) { colors[matchFound].getRgb(red, green, blue); } return matchFound; } /** * Get a color by its name. Returns indx of color if a matching color is * found, else -1. * "exactMatch will be true if the color's name was an exact match. Otherwise, * the color is a substring of "name". */ int ColorFile::getColorByName(const QString& name, bool& exactMatch, unsigned char& red, unsigned char& green, unsigned char& blue, unsigned char& alpha) const { const int matchFound = getColorIndexByName(name, exactMatch); if (matchFound >= 0) { colors[matchFound].getRgba(red, green, blue, alpha); } return matchFound; } /** * Set a color by it's indx (the index is not checked for validity). */ void ColorFile::setColorByIndex(const int indx, const QString& nameIn, const unsigned char red, const unsigned char green, const unsigned char blue) { colors[indx].setName(nameIn); colors[indx].setRgb(red, green, blue); setModified(); } /** * Set a color by it's indx (the index is not checked for validity). */ void ColorFile::setColorByIndex(const int indx, const QString& nameIn, const unsigned char red, const unsigned char green, const unsigned char blue, const unsigned char alpha) { colors[indx].setName(nameIn); colors[indx].setRgba(red, green, blue, alpha); setModified(); } /** * Set a color by it's index (the index is not checked for validity). */ void ColorFile::setColorByIndex(const int indx, const unsigned char red, const unsigned char green, const unsigned char blue) { colors[indx].setRgb(red, green, blue); setModified(); } /** * Set a color by it's index (the index is not checked for validity). */ void ColorFile::setColorByIndex(const int indx, const unsigned char red, const unsigned char green, const unsigned char blue, const unsigned char alpha) { colors[indx].setRgba(red, green, blue, alpha); setModified(); } /** * */ void ColorFile::setPointLineSizeByIndex(const int indx, const float pointSize, const float lineSize) { colors[indx].setPointSize(pointSize); colors[indx].setLineSize(lineSize); setModified(); } /** * set symbol by index. */ void ColorFile::setSymbolByIndex(const int indx, const ColorFile::ColorStorage::SYMBOL s) { colors[indx].setSymbol(s); setModified(); } /** * set the SuMS color id by index. */ void ColorFile::setSumsColorIDByIndex(const int indx, const QString& idIn) { colors[indx].setSuMSColorID(idIn); setModified(); } /** * set selection status of all colors */ void ColorFile::setAllSelectedStatus(const bool sel) { const int num = getNumberOfColors(); for (int i = 0; i < num; i++) { setSelected(i, sel); } } /** * Set the number of colors in the file (clears its contents too). */ void ColorFile::setNumberOfColors(const int numColors) { clear(); colors.resize(numColors); setModified(); } /** * Remove color at specified index */ void ColorFile::removeColorByIndex(const int indx) { if (indx < getNumberOfColors()) { colors.erase(colors.begin() + indx); } } /** * find out if comma separated file conversion supported. */ void ColorFile::getCommaSeparatedFileSupport(bool& readFromCSV, bool& writeToCSV) const { readFromCSV = true; writeToCSV = true; } /** * Generate random colors for any name that does not match an area color name. * if "requireExactMatchFlag" is true, a new color is created in there is not * a color that exactly matches name. If "requireExactMatchFlag" is false * and the "name" begins with the color name, a new color is not created. * so, for example, if "name" is "SUL.CeS" and there is a color named "SUL", * a new color is not created. */ void ColorFile::generateColorsForNamesWithoutColors(const std::vector& names, const bool requireExactMatchFlag) { int ctr = 0; const int numNames = static_cast(names.size()); for (int i = 0; i < numNames; i++) { const QString name(names[i]); bool exactlyMatchingColorFoundFlag = false; const int colorIndex = getColorIndexByName(name, exactlyMatchingColorFoundFlag); bool createColorFlag = false; if (colorIndex < 0) { createColorFlag = true; } else if (requireExactMatchFlag) { if (exactlyMatchingColorFoundFlag == false) { createColorFlag = true; } } if (createColorFlag) { if (name == "???") { addColor(name, 170, 170, 170); } else { switch (ctr) { case 0: addColor(name, 255, 0, 0); break; case 1: addColor(name, 255, 0, 127); break; case 2: addColor(name, 255, 0, 255); break; case 3: addColor(name, 255, 127, 0); break; case 4: addColor(name, 255, 127, 127); break; case 5: addColor(name, 255, 127, 255); break; case 6: addColor(name, 0, 0, 127); break; case 7: addColor(name, 0, 0, 255); break; case 8: addColor(name, 127, 0, 0); break; case 9: addColor(name, 127, 0, 127); break; case 10: addColor(name, 127, 0, 255); break; case 11: addColor(name, 127, 127, 0); break; case 12: addColor(name, 127, 127, 127); break; case 13: addColor(name, 127, 127, 255); break; case 14: addColor(name, 127, 255, 0); break; case 15: addColor(name, 127, 255, 127); break; case 16: addColor(name, 127, 255, 255); ctr = -1; // start over break; } ctr++; } } } } /** * write the file's data into a comma separated values file (throws exception if not supported). */ void ColorFile::writeDataIntoCommaSeparatedValueFile(CommaSeparatedValueFile& csv) throw (FileException) { csv.clear(); const int numColors = getNumberOfColors(); if (numColors <= 0) { return; } // // Column numbers for data // int numCols = 0; const int nameCol = numCols++; const int redCol = numCols++; const int greenCol = numCols++; const int blueCol = numCols++; const int alphaCol = numCols++; const int pointSizeCol = numCols++; const int lineSizeCol = numCols++; const int symbolCol = numCols++; const int idCol = numCols++; // // Create and add to string table // StringTable* ct = new StringTable(numColors, numCols, "Colors"); ct->setColumnTitle(nameCol, "Name"); ct->setColumnTitle(redCol, "Red"); ct->setColumnTitle(greenCol, "Green"); ct->setColumnTitle(blueCol, "Blue"); ct->setColumnTitle(alphaCol, "Alpha"); ct->setColumnTitle(pointSizeCol, "Point-Size"); ct->setColumnTitle(lineSizeCol, "Line-Size"); ct->setColumnTitle(symbolCol, "Symbol"); ct->setColumnTitle(idCol, "SuMSColorID"); // // Load the data // for (int i = 0; i < numColors; i++) { const ColorStorage* color = getColor(i); unsigned char red, green, blue, alpha; color->getRgba(red, green, blue, alpha); ct->setElement(i, nameCol, color->getName()); ct->setElement(i, redCol, red); ct->setElement(i, greenCol, green); ct->setElement(i, blueCol, blue); ct->setElement(i, alphaCol, alpha); ct->setElement(i, pointSizeCol, color->getPointSize()); ct->setElement(i, lineSizeCol, color->getLineSize()); ct->setElement(i, symbolCol, ColorStorage::symbolToText(color->getSymbol())); ct->setElement(i, idCol, color->getSuMSColorID()); } StringTable* headerTable = new StringTable(0, 0); writeHeaderDataIntoStringTable(*headerTable); csv.addDataSection(headerTable); csv.addDataSection(ct); } /** * read the file's data from a comma separated values file (throws exception if not supported). */ void ColorFile::readDataFromCommaSeparatedValuesTable(const CommaSeparatedValueFile& csv) throw (FileException) { const QString filenameSaved(filename); clear(); filename = filenameSaved; const StringTable* ct = csv.getDataSectionByName("Colors"); if (ct == NULL) { throw FileException("No colors found"); } int nameCol = -1; int redCol = -1; int greenCol = -1; int blueCol = -1; int alphaCol = -1; int pointSizeCol = -1; int lineSizeCol = -1; int symbolCol = -1; int idCol = -1; int numCols = ct->getNumberOfColumns(); for (int i = 0; i < numCols; i++) { const QString columnTitle = ct->getColumnTitle(i).toLower(); if (columnTitle == "name") { nameCol = i; } else if (columnTitle == "red") { redCol = i; } else if (columnTitle == "green") { greenCol = i; } else if (columnTitle == "blue") { blueCol = i; } else if (columnTitle == "alpha") { alphaCol = i; } else if (columnTitle == "point-size") { pointSizeCol = i; } else if (columnTitle == "line-size") { lineSizeCol = i; } else if (columnTitle == "symbol") { symbolCol = i; } else if (columnTitle == "sumscolorid") { idCol = i; } } for (int i = 0; i < ct->getNumberOfRows(); i++) { ColorStorage cs; unsigned char red, green, blue, alpha; cs.getRgba(red, green, blue, alpha); float lineSize = cs.getLineSize(); float pointSize = cs.getPointSize(); ColorStorage::SYMBOL symbol = cs.getSymbol(); QString name("unnamed color"); QString id; if (nameCol >= 0) { name = ct->getElement(i, nameCol); } if (redCol >= 0) { red = ct->getElementAsInt(i, redCol); } if (greenCol >= 0) { green = ct->getElementAsInt(i, greenCol); } if (blueCol >= 0) { blue = ct->getElementAsInt(i, blueCol); } if (alphaCol >= 0) { alpha = ct->getElementAsInt(i, alphaCol); } if (pointSizeCol >= 0) { pointSize = ct->getElementAsFloat(i, pointSizeCol); } if (lineSizeCol >= 0) { lineSize = ct->getElementAsFloat(i, lineSizeCol); } if (symbolCol >= 0) { symbol = ColorStorage::textToSymbol(ct->getElement(i, symbolCol)); } if (idCol >= 0) { id = ct->getElement(i, idCol); } addColor(name, red, green, blue, alpha, pointSize, lineSize, symbol, id); } // // Do header // const StringTable* stHeader = csv.getDataSectionByName("header"); if (stHeader != NULL) { readHeaderDataFromStringTable(*stHeader); } } /** * Read the color file. */ void ColorFile::readFileData(QFile& file, QTextStream& stream, QDataStream&, QDomElement& rootElement) throw (FileException) { // // Should reading data be skipped ? // if (getReadMetaDataOnlyFlag()) { return; } switch (getFileReadType()) { case FILE_FORMAT_ASCII: while(stream.atEnd() == false) { QString line; std::vector tokens; readLineIntoTokens(stream, line, tokens); if (tokens.size() < 4) { QString s("Invalid color file line: "); s.append(line); throw FileException(filename, s); } const QString name(tokens[0]); const int r = tokens[1].toInt(); const int g = tokens[2].toInt(); const int b = tokens[3].toInt(); // // Fifth item is point size (optional & may be float) // float pointSize = 1.0; if (tokens.size() >= 5) { pointSize = tokens[4].toFloat(); if (pointSize < 1) { pointSize = 1; } } // // Sixth item is line-width or class-name (both optional and class-name is obsolete) // float lineSize = 1.0; if (tokens.size() >= 6) { if ((tokens[5][0] >= '0') && (tokens[5][0] <= '9')) { lineSize = tokens[5].toFloat(); if (lineSize < 1) { lineSize = 1; } } } colors.push_back(ColorStorage(name, static_cast(r), static_cast(g), static_cast(b), pointSize, lineSize)); } break; case FILE_FORMAT_BINARY: throw FileException(filename, "Reading in Binary format not supported."); break; case FILE_FORMAT_XML: { QDomNode node = rootElement.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { // // Is this a "CellData" element // if (elem.tagName() == "Color") { ColorStorage cs; cs.readXML(node); colors.push_back(cs); } else if ((elem.tagName() == xmlHeaderOldTagName) || (elem.tagName() == xmlHeaderTagName)) { // ignore, read by AbstractFile::readFile() } else { std::cout << "WARNING: unrecognized Color File element: " << elem.tagName().toAscii().constData() << std::endl; } } node = node.nextSibling(); } } break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "Reading XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "Reading XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Reading XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Reading in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: { CommaSeparatedValueFile csvf; csvf.readFromTextStream(file, stream); readDataFromCommaSeparatedValuesTable(csvf); } break; } } /** * Write the color file. */ void ColorFile::writeFileData(QTextStream& stream, QDataStream&, QDomDocument& xmlDoc, QDomElement& rootElement) throw (FileException) { const int numColors = getNumberOfColors(); switch (getFileWriteType()) { case FILE_FORMAT_ASCII: throw FileException(filename, "Writing in Ascii format not supported."); /* for (int i = 0; i < numColors; i++) { unsigned char r, g, b; getColorByIndex(i, r, g, b); float pointSize, lineSize; getPointLineSizeByIndex(i, pointSize, lineSize); stream << getColorNameByIndex(i) << " " << r << " " << g << " " << b << " " << pointSize << " " << lineSize << " " << "\n"; } */ break; case FILE_FORMAT_BINARY: throw FileException(filename, "Writing in Binary format not supported."); break; case FILE_FORMAT_XML: { // // Write the colors // for (int i = 0; i < numColors; i++) { ColorStorage* cs = getColor(i); cs->writeXML(xmlDoc, rootElement); } } break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Writing XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Writing in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: { CommaSeparatedValueFile csvf; writeDataIntoCommaSeparatedValueFile(csvf); csvf.writeToTextStream(stream); } break; } } /** * Write the file's memory in caret6 format to the specified name. */ QString ColorFile::writeFileInCaret6Format(const QString& filenameIn, Structure structure,const ColorFile* colorFileIn, const bool useCaret6ExtensionFlag) throw (FileException) { int numColors = this->getNumberOfColors(); GiftiDataArrayFile gdaf; GiftiLabelTable* labelTable = gdaf.getLabelTable(); for (int i = 0; i < numColors; i++) { const ColorStorage* color = getColor(i); unsigned char red, green, blue, alpha; color->getRgba(red, green, blue, alpha); labelTable->setLabel(i, color->getName()); labelTable->setColor(i, red, green, blue, alpha); } gdaf.writeFile(filenameIn); return filenameIn; } //-------------------------------------------------------------------------------------------- /** * constructor. */ ColorFile::ColorStorage::ColorStorage() { name = ""; rgba[0] = 0; rgba[1] = 0; rgba[2] = 0; rgba[3] = 255; symbol = SYMBOL_OPENGL_POINT; pointSize = 2.0; lineSize = 1; selected = true; } /** * constructor. */ ColorFile::ColorStorage::ColorStorage(const QString& nameIn, const unsigned char red, const unsigned char green, const unsigned char blue, const float pointSizeIn, const float lineSizeIn) { name = nameIn; rgba[0] = red; rgba[1] = green; rgba[2] = blue; rgba[3] = 255; symbol = SYMBOL_OPENGL_POINT; pointSize = pointSizeIn; lineSize = lineSizeIn; selected = true; } /** * constructor. */ ColorFile::ColorStorage::ColorStorage(const QString& nameIn, const unsigned char red, const unsigned char green, const unsigned char blue, const unsigned char alpha, const float pointSizeIn, const float lineSizeIn, const SYMBOL symbolIn, const QString& sumsIDIn) { name = nameIn; rgba[0] = red; rgba[1] = green; rgba[2] = blue; rgba[3] = alpha; symbol = symbolIn; pointSize = pointSizeIn; lineSize = lineSizeIn; selected = true; sumsColorID = sumsIDIn; } /** * destructor. */ ColorFile::ColorStorage::~ColorStorage() { } /** * is the color selected. */ bool ColorFile::ColorStorage::getSelected() const { return selected; } /** * set the selection status. */ void ColorFile::ColorStorage::setSelected(const bool b) { selected = b; } /** * get the name. */ QString ColorFile::ColorStorage::getName() const { return name; } /** * set the name. */ void ColorFile::ColorStorage::setName(const QString& n) { name = n; } /** * get the line size. */ float ColorFile::ColorStorage::getLineSize() const { return lineSize; } /** * set the line size. */ void ColorFile::ColorStorage::setLineSize(const float s) { lineSize = s; } /** * get the point size. */ float ColorFile::ColorStorage::getPointSize() const { return pointSize; } /** * set the point size. */ void ColorFile::ColorStorage::setPointSize(const float s) { pointSize = s; } /** * get the symbol. */ ColorFile::ColorStorage::SYMBOL ColorFile::ColorStorage::getSymbol() const { return symbol; } /** * set the symbol. */ void ColorFile::ColorStorage::setSymbol(const SYMBOL s) { symbol = s; } /** * get rgb colors. */ const unsigned char* ColorFile::ColorStorage::getRgb() const { return &rgba[0]; } /** * get the rgb colors. */ void ColorFile::ColorStorage::getRgb(unsigned char& r, unsigned char& g, unsigned char& b) const { r = rgba[0]; g = rgba[1]; b = rgba[2]; } /** * set the rgb colors. */ void ColorFile::ColorStorage::setRgb(const unsigned char rgbIn[3]) { rgba[0] = rgbIn[0]; rgba[1] = rgbIn[1]; rgba[2] = rgbIn[2]; rgba[3] = 255; } /** * set the rgb colors. */ void ColorFile::ColorStorage::setRgb(const unsigned char r, const unsigned char g, const unsigned char b) { rgba[0] = r; rgba[1] = g; rgba[2] = b; rgba[3] = 255; } /** * get rgba colors. */ const unsigned char* ColorFile::ColorStorage::getRgba() const { return &rgba[0]; } /** * get the rgba colors. */ void ColorFile::ColorStorage::getRgba(unsigned char& r, unsigned char& g, unsigned char& b, unsigned char& a) const { r = rgba[0]; g = rgba[1]; b = rgba[2]; a = rgba[3]; } /** * set the rgba colors. */ void ColorFile::ColorStorage::setRgba(const unsigned char rgbaIn[4]) { rgba[0] = rgbaIn[0]; rgba[1] = rgbaIn[1]; rgba[2] = rgbaIn[2]; rgba[3] = rgbaIn[3]; } /** * set the rgba colors. */ void ColorFile::ColorStorage::setRgba(const unsigned char r, const unsigned char g, const unsigned char b, const unsigned char a) { rgba[0] = r; rgba[1] = g; rgba[2] = b; rgba[3] = a; } /** * get the color id. */ QString ColorFile::ColorStorage::getSuMSColorID() const { return sumsColorID; } /** * set the color id. */ void ColorFile::ColorStorage::setSuMSColorID(const QString& id) { sumsColorID = id; } /** * symbol enum to text. */ QString ColorFile::ColorStorage::symbolToText(const SYMBOL symbol) { QString symbolStr("POINT"); switch (symbol) { case SYMBOL_BOX: symbolStr = "BOX"; break; case SYMBOL_DIAMOND: symbolStr = "DIAMOND"; break; case SYMBOL_DISK: symbolStr = "DISK"; break; case SYMBOL_OPENGL_POINT: symbolStr = "POINT"; break; case SYMBOL_SPHERE: symbolStr = "SPHERE"; break; case SYMBOL_RING: symbolStr = "RING"; break; case SYMBOL_NONE: symbolStr = "NONE"; break; case SYMBOL_SQUARE: symbolStr = "SQUARE"; break; } return symbolStr; } /** * text to symbol enum. */ ColorFile::ColorStorage::SYMBOL ColorFile::ColorStorage::textToSymbol(const QString& symbolStrIn) { SYMBOL symbol = SYMBOL_OPENGL_POINT; const QString symbolStr(symbolStrIn.toUpper()); if (symbolStr == "BOX") { symbol = SYMBOL_BOX; } else if (symbolStr == "DIAMOND") { symbol = SYMBOL_DIAMOND; } else if (symbolStr == "DISK") { symbol = SYMBOL_DISK; } else if (symbolStr == "POINT") { symbol = SYMBOL_OPENGL_POINT; } else if (symbolStr == "SPHERE") { symbol = SYMBOL_SPHERE; } else if (symbolStr == "RING") { symbol = SYMBOL_RING; } else if (symbolStr == "NONE") { symbol = SYMBOL_NONE; } else if (symbolStr == "SQUARE") { symbol = SYMBOL_SQUARE; } else { std::cout << "WARNING: unrecognized symbol type: " << symbolStr.toAscii().constData() << ". Defaulting to POINT." << std::endl; } return symbol; } /** * get all symbol types as strings. */ void ColorFile::ColorStorage::getAllSymbolTypesAsStrings(std::vector& symbolStrings) { symbolStrings.clear(); for (int i = 0; i <= SYMBOL_NONE; i++) { symbolStrings.push_back(symbolToText(static_cast(i))); } } /** * called to read from an XML structure. */ void ColorFile::ColorStorage::readXML(QDomNode& nodeIn) throw (FileException) { if (nodeIn.isNull()) { return; } QDomElement elem = nodeIn.toElement(); if (elem.isNull()) { return; } if (elem.tagName() != "Color") { QString msg("Incorrect element type passed to CellData::readXML(): \""); msg.append(elem.tagName()); msg.append("\""); throw FileException("", msg); } QDomNode node = nodeIn.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (elem.tagName() == "name") { name = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "red") { rgba[0] = AbstractFile::getXmlElementFirstChildAsInt(elem); } else if (elem.tagName() == "green") { rgba[1] = AbstractFile::getXmlElementFirstChildAsInt(elem); } else if (elem.tagName() == "blue") { rgba[2] = AbstractFile::getXmlElementFirstChildAsInt(elem); } else if (elem.tagName() == "alpha") { rgba[3] = AbstractFile::getXmlElementFirstChildAsInt(elem); } else if (elem.tagName() == "pointSize") { pointSize = AbstractFile::getXmlElementFirstChildAsFloat(elem); } else if (elem.tagName() == "lineSize") { lineSize = AbstractFile::getXmlElementFirstChildAsFloat(elem); } else if (elem.tagName() == "symbol") { symbol = textToSymbol(AbstractFile::getXmlElementFirstChildAsString(elem)); } else if (elem.tagName() == "sumscolorid") { sumsColorID = AbstractFile::getXmlElementFirstChildAsString(elem); } else { std::cout << "WARNING: unrecognized CellData element: " << elem.tagName().toAscii().constData() << std::endl; } } node = node.nextSibling(); } } /** * called to write to an XML structure. */ void ColorFile::ColorStorage::writeXML(QDomDocument& xmlDoc, QDomElement& parentElement) { // // Create the element for this class instance's data // QDomElement colorDataElement = xmlDoc.createElement("Color"); // // color elements // AbstractFile::addXmlCdataElement(xmlDoc, colorDataElement, "name", name); AbstractFile::addXmlTextElement(xmlDoc, colorDataElement, "red", rgba[0]); AbstractFile::addXmlTextElement(xmlDoc, colorDataElement, "green", rgba[1]); AbstractFile::addXmlTextElement(xmlDoc, colorDataElement, "blue", rgba[2]); AbstractFile::addXmlTextElement(xmlDoc, colorDataElement, "alpha", rgba[3]); AbstractFile::addXmlTextElement(xmlDoc, colorDataElement, "pointSize", pointSize); AbstractFile::addXmlTextElement(xmlDoc, colorDataElement, "lineSize", lineSize); const QString symbolStr(symbolToText(symbol)); AbstractFile::addXmlCdataElement(xmlDoc, colorDataElement, "symbol", symbolStr); AbstractFile::addXmlCdataElement(xmlDoc, colorDataElement, "sumscolorid", sumsColorID); // // Add class instance's data to the parent // parentElement.appendChild(colorDataElement); } caret-5.6.4~dfsg.1.orig/caret_files/CocomacConnectivityFile.h0000664000175000017500000001111611572067322023755 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ // // CoCoMac files are in XML format. see www.cocomac.org for more information. // #ifndef __COCOMAC_CONNECTIVITY_FILE__ #define __COCOMAC_CONNECTIVITY_FILE__ class QDomElement; class QDomNode; #include "AbstractFile.h" /// Class for storing a single CoCoMac projection. class CocomacProjection { private: QString sourceSite; QString targetSite; QString laminaeA; QString laminaeB; QString density; public: CocomacProjection() {} QString getSourceSite() const { return sourceSite; } QString getTargetSite() const { return targetSite; } QString getLaminaeA() const { return laminaeA; } QString getLaminaeB() const { return laminaeB; } QString getDensity() const { return density; } void setSourceSite(const QString& s) { sourceSite = s; } void setTargetSite(const QString& s) { targetSite = s; } void setLaminaeA(const QString& s) { laminaeA = s; } void setLaminaeB(const QString& s) { laminaeB = s; } void setDensity(const QString& s) { density = s; } }; /// Class for read/write/storing CoCoMac file class CocomacConnectivityFile : public AbstractFile { private: QString version; QString exportDate; QString dataType; QString comments; /// the CoCoMac projections std::vector projections; /// print a node type (used for debugging) void printNodeType(QDomNode& n); /// process the header node void processHeaderNode(QDomElement& headerNode) throw (FileException); /// process the connectivity data node void processConnectivityNode(QDomElement& connectNode) throw (FileException); /// process the primary projection node void processPrimaryProjectionNode(QDomElement& connectNode) throw (FileException); /// process a site node void processSiteNode(QDomElement& siteNode, CocomacProjection& projection); /// process a density node void processDensityNode(QDomElement& siteNode, CocomacProjection& projection); /// read the file void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException); /// write the file void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException); public: /// constructor CocomacConnectivityFile(); /// destructor ~CocomacConnectivityFile(); /// append a cocomac file to this one void append(CocomacConnectivityFile& ccf, QString& errorMessage); /// clear the cocomac file void clear(); /// returns true if the file is isEmpty (contains no data) bool empty() const { return (getNumberOfCocomacProjections() == 0); } /// get the comment QString getComments() const { return comments; } /// get the data type QString getDataType() const { return dataType; } /// get the export date QString getExportDate() const { return exportDate; } /// get the number of projections int getNumberOfCocomacProjections() const { return (int)projections.size(); } /// get a projection by index CocomacProjection* getCocomacProjection(const int i) { return &projections[i]; } /// get version QString getVersion() const { return version; } }; #endif caret-5.6.4~dfsg.1.orig/caret_files/CocomacConnectivityFile.cxx0000664000175000017500000002623611572067322024341 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include "CocomacConnectivityFile.h" #include "SpecFile.h" /** * The constructor. */ CocomacConnectivityFile::CocomacConnectivityFile() : AbstractFile("CoCoMac File", SpecFile::getCocomacConnectivityFileExtension(), false, FILE_FORMAT_XML, FILE_IO_NONE, FILE_IO_NONE, FILE_IO_READ_ONLY, FILE_IO_NONE) { clear(); setRootXmlElementTagName("CoCoMacExport"); } /** * The destructor. */ CocomacConnectivityFile::~CocomacConnectivityFile() { clear(); } /** * Append a CoCoMac file to this one */ void CocomacConnectivityFile::append(CocomacConnectivityFile& ccf, QString& errorMessage) { errorMessage = ""; for (int i = 0; i < ccf.getNumberOfCocomacProjections(); i++) { projections.push_back(*(ccf.getCocomacProjection(i))); } // // transfer the file's comment // appendFileComment(ccf); } /** * Clear the file. */ void CocomacConnectivityFile::clear() { clearAbstractFile(); projections.clear(); version = ""; exportDate = ""; dataType = ""; comments = ""; } /** * Read the file. */ void CocomacConnectivityFile::readFileData(QFile& /*file*/, QTextStream& /*stream*/, QDataStream&, QDomElement& rootElement) throw (FileException) { /* // // Read the remainder of the file into a QString. // const QString remainderOfFile = stream.read(); // // Place the file contents into a QDomDocument which will parse file. // QString errorMessage; int errorLine = 0, errorColumn = 0; QDomDocument doc("cocomac"); if (doc.setContent(remainderOfFile, &errorMessage, &errorLine, &errorColumn) == false) { std::ostringstream str; str << "Error parsing at line " << errorLine << " column " << errorColumn << ". "; str << errorMessage << std::ends; throw FileException(filename, str.str().c_str()); } // // Traverse the direct children // QDomElement docElem = doc.documentElement(); QDomNode node = docElem.firstChild(); */ QDomNode node = rootElement.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (elem.tagName() == "Header") { processHeaderNode(elem); } else if (elem.tagName() == "ProcessedConnectivityData") { processConnectivityNode(elem); } else { std::cerr << "Cocomac node not recognized in root " << elem.tagName().toAscii().constData() << std::endl; } } node = node.nextSibling(); } } void CocomacConnectivityFile::printNodeType(QDomNode& n) { if (n.isNull() == false) { std::cout << " is type "; switch(n.nodeType()) { case QDomNode::ElementNode: std::cout << "ElementNode"; break; case QDomNode::AttributeNode: std::cout << "AttributeNode"; break; case QDomNode::TextNode: std::cout << "TextNode"; break; case QDomNode::CDATASectionNode: std::cout << "CDATASectionNode"; break; case QDomNode::EntityReferenceNode: std::cout << "EntityReferenceNode"; break; case QDomNode::EntityNode: std::cout << "EntityNode"; break; case QDomNode::ProcessingInstructionNode: std::cout << "ProcessingInstructionNode"; break; case QDomNode::CommentNode: std::cout << "CommentNode"; break; case QDomNode::DocumentNode: std::cout << "DocumentNode"; break; case QDomNode::DocumentTypeNode: std::cout << "DocumentTypeNode"; break; case QDomNode::DocumentFragmentNode: std::cout << "DocumentFragmentNode"; break; case QDomNode::NotationNode: std::cout << "NotationNode"; break; case QDomNode::BaseNode: std::cout << "BaseNode"; break; case QDomNode::CharacterDataNode: std::cout << "CharacterDataNode"; break; default: std::cout << "Unknown node type"; break; } std::cout << std::endl; } } /** * Process the header node. */ void CocomacConnectivityFile::processHeaderNode(QDomElement& headerNode) throw (FileException) { QDomNode node = headerNode.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (elem.tagName() == "CoCoMacVersion") { QDomNode vNode = elem.firstChild(); if (vNode.isNull() == false) { QDomText textNode = vNode.toText(); if (textNode.isNull() == false) { version = textNode.data(); } } } else if (elem.tagName() == "ExportDate") { QDomNode vNode = elem.firstChild(); if (vNode.isNull() == false) { QDomText textNode = vNode.toText(); if (textNode.isNull() == false) { exportDate = textNode.data(); } } } else if (elem.tagName() == "DataType") { QDomNode vNode = elem.firstChild(); if (vNode.isNull() == false) { QDomText textNode = vNode.toText(); if (textNode.isNull() == false) { dataType = textNode.data(); } } } else if (elem.tagName() == "Comments") { QDomNode vNode = elem.firstChild(); if (vNode.isNull() == false) { QDomText textNode = vNode.toText(); if (textNode.isNull() == false) { comments = textNode.data(); } } } } node = node.nextSibling(); } } /** * Process the connectivity data node */ void CocomacConnectivityFile::processConnectivityNode(QDomElement& connectNode) throw (FileException) { QDomNode node = connectNode.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { if ((elem.tagName() == "PrimaryProjection") || (elem.tagName() == "IntegratedPrimaryProjection") || (elem.tagName() == "IntegratedResultingProjection")) { processPrimaryProjectionNode(elem); } } node = node.nextSibling(); } } /** * Process a primary projection node. */ void CocomacConnectivityFile::processPrimaryProjectionNode(QDomElement& connectNode) throw (FileException) { CocomacProjection projection; QDomNode node = connectNode.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { if ((elem.tagName() == "SourceSite") || (elem.tagName() == "TargetSite")) { processSiteNode(elem, projection); } else if (elem.tagName() == "Density") { processDensityNode(elem, projection); } } node = node.nextSibling(); } projections.push_back(projection); } /** * Process a "SourceSite" or "TargetSite" node. */ void CocomacConnectivityFile::processSiteNode(QDomElement& siteNode, CocomacProjection& projection) { const bool targetSiteNode = (siteNode.tagName() == "TargetSite"); QDomNode node = siteNode.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (elem.tagName() == "ID_BrainSite") { QDomNode vNode = elem.firstChild(); if (vNode.isNull() == false) { QDomText textNode = vNode.toText(); if (textNode.isNull() == false) { if (targetSiteNode) { projection.setTargetSite(textNode.data()); } else { projection.setSourceSite(textNode.data()); } } } } } else if ((elem.tagName() == "Laminae") || (elem.tagName() == "LaminaeA") || (elem.tagName() == "LaminaeB")) { QDomNode vNode = elem.firstChild(); if (vNode.isNull() == false) { QDomElement vElem = vNode.toElement(); if (vElem.isNull() == false) { if (vElem.tagName() == "Pattern") { vNode = vNode.firstChild(); if (vNode.isNull() == false) { QDomText textNode = vNode.toText(); if (textNode.isNull() == false) { if (targetSiteNode) { projection.setLaminaeA(textNode.data()); } else { projection.setLaminaeB(textNode.data()); } } } } } } } node = node.nextSibling(); } } /** * Process a "Density" node. */ void CocomacConnectivityFile::processDensityNode(QDomElement& siteNode, CocomacProjection& projection) { QDomNode node = siteNode.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (elem.tagName() == "Degree") { QDomNode vNode = elem.firstChild(); if (vNode.isNull() == false) { QDomText textNode = vNode.toText(); if (textNode.isNull() == false) { projection.setDensity(textNode.data()); } } } } node = node.nextSibling(); } } void CocomacConnectivityFile::writeFileData(QTextStream& /*stream*/, QDataStream&, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw(FileException) { throw FileException(filename, "Writing CoCoMac is not supported"); } caret-5.6.4~dfsg.1.orig/caret_files/CellStudyInfo.h0000664000175000017500000001543211572067322021743 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __CELL_STUDY_INFO_H__ #define __CELL_STUDY_INFO_H__ #include #include class QDomDocument; class QDomElement; class QDomNode; class StringTable; #include "FileException.h" /// Class for storing cell study info class CellStudyInfo { public: /// constructor CellStudyInfo(); /// destructor ~CellStudyInfo(); /// equality operator bool operator==(const CellStudyInfo& cci) const; /// clear the study info void clear(); /// set element from text (used by SAX XML parser) void setElementFromText(const QString& elementName, const QString& textValue); /// called to read from an XML structure void readXML(QDomNode& node) throw (FileException); /// called to write to an XML structure void writeXML(QDomDocument& xmlDoc, QDomElement& parentElement, const int studyNumber); /// write the data into a StringTable static void writeDataIntoStringTable(const std::vector& csi, StringTable& table); /// read the data from a StringTable static void readDataFromStringTable(std::vector& csi, const StringTable& table) throw (FileException); /// get full description of all fields for display to user QString getFullDescriptionForDisplayToUser(const bool useHTML) const; /// get url QString getURL() const { return url; } /// set url void setURL(const QString& s) { url = s; } /// get keywords QString getKeywords() const { return keywords; } /// set keywords void setKeywords(const QString& s) { keywords = s; } /// get title QString getTitle() const { return title; } /// set title void setTitle(const QString& s) { title = s; } /// get authors QString getAuthors() const { return authors; } /// set authors void setAuthors(const QString& s) { authors = s; } /// get citation QString getCitation() const { return citation; } /// set citation void setCitation(const QString& s) { citation = s; } /// get stereotaxic Space QString getStereotaxicSpace() const { return stereotaxicSpace; } /// set Stereotaxic Space void setStereotaxicSpace(const QString& s) { stereotaxicSpace = s; } /// get comment QString getComment() const { return comment; } /// set comment void setComment(const QString& s) { comment = s; } /// get partitioning scheme abbreviation QString getPartitioningSchemeAbbreviation() const { return partitioningSchemeAbbreviation; } /// set partitioning scheme abbreviation void setPartitioningSchemeAbbreviation(const QString& s) { partitioningSchemeAbbreviation = s; } /// get partitioning scheme full name QString getPartitioningSchemeFullName() const { return partitioningSchemeFullName; } /// set partitioning scheme full name void setPartitioningSchemeFullName(const QString& s) { partitioningSchemeFullName = s; } protected: /// study web page URL QString url; /// study key words QString keywords; /// study title QString title; /// study authors QString authors; /// study citation (journal) QString citation; /// stereotaxic space QString stereotaxicSpace; /// comment QString comment; /// partitioning scheme abbreviation QString partitioningSchemeAbbreviation; /// partitioning scheme full name QString partitioningSchemeFullName; /// tag for reading and writing study info static const QString tagCellStudyInfo; /// tag for reading and writing study info static const QString tagUrl; /// tag for reading and writing study info static const QString tagKeywords; /// tag for reading and writing study info static const QString tagTitle; /// tag for reading and writing study info static const QString tagAuthors; /// tag for reading and writing study info static const QString tagCitation; /// tag for reading and writing study info static const QString tagStereotaxicSpace; /// tag for reading and writing study info static const QString tagComment; /// tag for reading and writing study info static const QString tagStudyNumber; /// tag for reading and writing study info static const QString tagPartitioningSchemeAbbreviation; /// tag for reading and writing study info static const QString tagPartitioningSchemeFullName; friend class CellFile; friend class CellProjectionFile; friend class VocabularyFile; }; #endif // __CELL_STUDY_INFO_H__ #ifdef __CELL_STUDY_INFO_MAIN__ const QString CellStudyInfo::tagCellStudyInfo = "CellStudyInfo"; const QString CellStudyInfo::tagUrl = "url"; const QString CellStudyInfo::tagKeywords = "keywords"; const QString CellStudyInfo::tagTitle = "title"; const QString CellStudyInfo::tagAuthors = "authors"; const QString CellStudyInfo::tagCitation = "citation"; const QString CellStudyInfo::tagStereotaxicSpace = "stereotaxicSpace"; const QString CellStudyInfo::tagComment = "comment"; const QString CellStudyInfo::tagStudyNumber = "studyNumber"; const QString CellStudyInfo::tagPartitioningSchemeAbbreviation = "partitioningSchemeAbbreviation"; const QString CellStudyInfo::tagPartitioningSchemeFullName = "partitioningSchemeFullName"; #endif // __CELL_STUDY_INFO_MAIN__ caret-5.6.4~dfsg.1.orig/caret_files/CellStudyInfo.cxx0000664000175000017500000003436611572067322022325 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "AbstractFile.h" #define __CELL_STUDY_INFO_MAIN__ #include "CellStudyInfo.h" #undef __CELL_STUDY_INFO_MAIN__ #include "StringTable.h" /** * Constructor */ CellStudyInfo::CellStudyInfo() { clear(); } /** * Destructor */ CellStudyInfo::~CellStudyInfo() { } /** * equality operator. */ bool CellStudyInfo::operator==(const CellStudyInfo& cci) const { return ((url == cci.url) && (keywords == cci.keywords) && (title == cci.title) && (authors == cci.authors) && (citation == cci.citation) && (comment == cci.comment) && (stereotaxicSpace == cci.stereotaxicSpace) && (partitioningSchemeAbbreviation == cci.partitioningSchemeAbbreviation) && (partitioningSchemeFullName == cci.partitioningSchemeFullName)); } /** * clear the study info. */ void CellStudyInfo::clear() { url = ""; keywords = ""; title = ""; authors = ""; citation = ""; comment = ""; stereotaxicSpace = ""; partitioningSchemeAbbreviation = ""; partitioningSchemeFullName = ""; } /** * set element from text (used by SAX XML parser). */ void CellStudyInfo::setElementFromText(const QString& elementName, const QString& textValue) { if (elementName == tagUrl) { url = textValue; } else if (elementName == tagKeywords) { keywords = textValue; } else if (elementName == tagTitle) { title = textValue; } else if (elementName == tagAuthors) { authors = textValue; } else if (elementName == tagCitation) { citation = textValue; } else if (elementName == tagStereotaxicSpace) { stereotaxicSpace = textValue; } else if (elementName == tagComment) { comment = textValue; } else if (elementName == tagStudyNumber) { // ignore studyNumber } else if (elementName == tagPartitioningSchemeAbbreviation) { partitioningSchemeAbbreviation = textValue; } else if (elementName == tagPartitioningSchemeFullName) { partitioningSchemeFullName = textValue; } else { std::cout << "WARNING: unrecognized CellStudyInfo element: " << elementName.toAscii().constData() << std::endl; } } /** * called to read from an XML structure. */ void CellStudyInfo::readXML(QDomNode& nodeIn) throw (FileException) { if (nodeIn.isNull()) { return; } QDomElement elem = nodeIn.toElement(); if (elem.isNull()) { return; } if (elem.tagName() != tagCellStudyInfo) { QString msg("Incorrect element type passed to CellStudyInfo::readXML() "); msg.append(elem.tagName()); throw FileException("", msg); } QDomNode node = nodeIn.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (elem.tagName() == tagUrl) { url = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == tagKeywords) { keywords = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == tagTitle) { title = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == tagAuthors) { authors = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == tagCitation) { citation = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == tagStereotaxicSpace) { stereotaxicSpace = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == tagComment) { comment = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == tagStudyNumber) { // ignore studyNumber } else if (elem.tagName() == tagPartitioningSchemeAbbreviation) { partitioningSchemeAbbreviation = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == tagPartitioningSchemeFullName) { partitioningSchemeFullName = AbstractFile::getXmlElementFirstChildAsString(elem); } else { std::cout << "WARNING: unrecognized CellStudyInfo element: " << elem.tagName().toAscii().constData() << std::endl; } } node = node.nextSibling(); } } /** * called to write to an XML structure. */ void CellStudyInfo::writeXML(QDomDocument& xmlDoc, QDomElement& parentElement, const int studyNumber) { // // Create the element for this class instance's data // QDomElement cellStudyElement = xmlDoc.createElement(tagCellStudyInfo); // // study number // AbstractFile::addXmlTextElement(xmlDoc, cellStudyElement, tagStudyNumber, studyNumber); // // url // AbstractFile::addXmlCdataElement(xmlDoc, cellStudyElement, tagUrl, url); // // keywords // AbstractFile::addXmlCdataElement(xmlDoc, cellStudyElement, tagKeywords, keywords); // // title // AbstractFile::addXmlCdataElement(xmlDoc, cellStudyElement, tagTitle, title); // // authors // AbstractFile::addXmlCdataElement(xmlDoc, cellStudyElement, tagAuthors, authors); // // citation // AbstractFile::addXmlCdataElement(xmlDoc, cellStudyElement, tagCitation, citation); // // stereotaxicSpace // AbstractFile::addXmlCdataElement(xmlDoc, cellStudyElement, tagStereotaxicSpace, stereotaxicSpace); // // comment // AbstractFile::addXmlCdataElement(xmlDoc, cellStudyElement, tagComment, comment); // // partitioning scheme abbreviation // AbstractFile::addXmlCdataElement(xmlDoc, cellStudyElement, tagPartitioningSchemeAbbreviation, partitioningSchemeAbbreviation); // // partitioning scheme full name // AbstractFile::addXmlCdataElement(xmlDoc, cellStudyElement, tagPartitioningSchemeFullName, partitioningSchemeFullName); // // Add to parent // parentElement.appendChild(cellStudyElement); } /** * write the data into a StringTable. */ void CellStudyInfo::writeDataIntoStringTable(const std::vector& studyInfo, StringTable& table) { table.clear(); const int numInfo = static_cast(studyInfo.size()); if (numInfo <= 0) { return; } // // Column numbers for info // int numCols = 0; const int studyNumberCol = numCols++; const int spaceCol = numCols++; const int keywordsCol = numCols++; const int urlCol = numCols++; const int titleCol = numCols++; const int authorsCol = numCols++; const int citationCol = numCols++; const int commentCol = numCols++; const int partSchemeAbbrevCol = numCols++; const int partSchemeFullNameCol = numCols++; // // Load the table // table.setNumberOfRowsAndColumns(numInfo, numCols, "Cell Study Info"); table.setColumnTitle(studyNumberCol, "Study Number"); table.setColumnTitle(urlCol, "URL"); table.setColumnTitle(keywordsCol, "Keywords"); table.setColumnTitle(titleCol, "Title"); table.setColumnTitle(authorsCol, "Authors"); table.setColumnTitle(citationCol, "Citation"); table.setColumnTitle(spaceCol, "Stereotaxic Space"); table.setColumnTitle(commentCol, "Comment"); table.setColumnTitle(partSchemeAbbrevCol, "Partitioning Scheme Abbreviation"); table.setColumnTitle(partSchemeFullNameCol, "Partitioning Scheme Full Name"); for (int i = 0; i < numInfo; i++) { const CellStudyInfo& csi = studyInfo[i]; table.setElement(i, studyNumberCol, i); table.setElement(i, urlCol, csi.getURL()); table.setElement(i, keywordsCol, csi.getKeywords()); table.setElement(i, titleCol, csi.getTitle()); table.setElement(i, authorsCol, csi.getAuthors()); table.setElement(i, citationCol, csi.getCitation()); table.setElement(i, spaceCol, csi.getStereotaxicSpace()); table.setElement(i, partSchemeAbbrevCol, csi.getPartitioningSchemeAbbreviation()); table.setElement(i, partSchemeFullNameCol, csi.getPartitioningSchemeFullName()); table.setElement(i, commentCol, csi.getComment()); } } /** * read the data from a StringTable. */ void CellStudyInfo::readDataFromStringTable(std::vector& studyInfo, const StringTable& table) throw (FileException) { if (table.getTableTitle() != "Cell Study Info") { throw FileException("String table for CellStudyInfo does not have name Cell Study Info"); } studyInfo.clear(); int studyNumberCol = -1; int urlCol = -1; int keywordsCol = -1; int titleCol = -1; int authorsCol = -1; int citationCol = -1; int spaceCol = -1; int commentCol = -1; int partitioningSchemeAbbrevCol = -1; int partitioningSchemeFullNameCol = -1; const int numCols = table.getNumberOfColumns(); for (int i = 0; i < numCols; i++) { const QString name = table.getColumnTitle(i).toLower(); if (name == "study number") { studyNumberCol = i; } else if (name == "url") { urlCol = i; } else if (name == "keywords") { keywordsCol = i; } else if (name == "title") { titleCol = i; } else if (name == "authors") { authorsCol = i; } else if (name == "citation") { citationCol = i; } else if (name == "stereotaxic space") { spaceCol = i; } else if (name == "comment") { commentCol = i; } else if (name == "partitioning scheme abbreviation") { partitioningSchemeAbbrevCol = i; } else if (name == "partitioning scheme full name") { partitioningSchemeFullNameCol = i; } } const int numItems = table.getNumberOfRows(); for (int i = 0; i < numItems; i++) { CellStudyInfo csi; if (urlCol >= 0) { csi.setURL(table.getElement(i, urlCol)); } if (keywordsCol >= 0) { csi.setKeywords(table.getElement(i, keywordsCol)); } if (titleCol >= 0) { csi.setTitle(table.getElement(i, titleCol)); } if (authorsCol >= 0) { csi.setAuthors(table.getElement(i, authorsCol)); } if (citationCol >= 0) { csi.setCitation(table.getElement(i, citationCol)); } if (spaceCol >= 0) { csi.setStereotaxicSpace(table.getElement(i, spaceCol)); } if (commentCol >= 0) { csi.setComment(table.getElement(i, commentCol)); } if (partitioningSchemeAbbrevCol >= 0) { csi.setPartitioningSchemeAbbreviation(table.getElement(i, partitioningSchemeAbbrevCol)); } if (partitioningSchemeFullNameCol >= 0) { csi.setPartitioningSchemeFullName(table.getElement(i, partitioningSchemeFullNameCol)); } studyInfo.push_back(csi); } } /** * get full description of all fields for display to user. */ QString CellStudyInfo::getFullDescriptionForDisplayToUser(const bool useHTML) const { const QString boldStart(""); const QString boldEnd(""); QString newLine("\n"); if (useHTML) { newLine = "
"; } QString s; if (useHTML) s += boldStart; s += "Study Title"; if (useHTML) s += boldEnd; s += ": "; s += title; s += newLine; if (authors.isEmpty() == false) { if (useHTML) s += boldStart; s += "Study Authors"; if (useHTML) s += boldEnd; s += ": "; s += authors; s += newLine; } if (citation.isEmpty() == false) { if (useHTML) s += boldStart; s += "Study Citation"; if (useHTML) s += boldEnd; s += ": "; s += citation; s += newLine; } if (keywords.isEmpty() == false) { if (useHTML) s += boldStart; s += "Keywords"; if (useHTML) s += boldEnd; s += ": "; s += keywords; s += newLine; } if (stereotaxicSpace.isEmpty() == false) { if (useHTML) s += boldStart; s += "Study Stereotaxic Space"; if (useHTML) s += boldEnd; s += ": "; s += stereotaxicSpace; s += newLine; } if (url.isEmpty() == false) { if (useHTML) s += boldStart; s += "Study URL"; if (useHTML) s += boldEnd; s += ": "; //if (useHTML) { // s += "
"; //} s += url; //if (useHTML) { // s += ""; //} s += newLine; } if (partitioningSchemeAbbreviation.isEmpty() == false) { if (useHTML) s += boldStart; s += "Study Partitioning Scheme Abbreviation"; if (useHTML) s += boldEnd; s += ": "; s += partitioningSchemeAbbreviation; s += newLine; } if (partitioningSchemeFullName.isEmpty() == false) { if (useHTML) s += boldStart; s += "Study Partitioning Scheme Full Name"; if (useHTML) s += boldEnd; s += ": "; s += partitioningSchemeFullName; s += newLine; } if (comment.isEmpty() == false) { if (useHTML) s += boldStart; s += "Study Comment"; if (useHTML) s += boldEnd; s += ": "; s += comment; s += newLine; } return s; } caret-5.6.4~dfsg.1.orig/caret_files/CellProjectionFile.h0000664000175000017500000006075611572067322022744 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __CELL_PROJECTION_FILE_H__ #define __CELL_PROJECTION_FILE_H__ #include "AbstractFile.h" #include "CellBase.h" #include "CellClass.h" #include "CellStudyInfo.h" #include "SpecFile.h" class CellFile; class CellProjectionFile; class ColorFile; class CoordinateFile; class Structure; class StudyMetaDataFile; class TopologyFile; /// Storage for a cell projection. class CellProjection : public CellBase { public: /// cell projection type enum PROJECTION_TYPE { PROJECTION_TYPE_UNKNOWN, PROJECTION_TYPE_INSIDE_TRIANGLE, PROJECTION_TYPE_OUTSIDE_TRIANGLE }; /// Constructor CellProjection(const QString& fileNameIn = ""); /// Constructor for placing cell projection at a node (no need to project) CellProjection(const QString& nameIn, const CoordinateFile* fiducialCoordinateFile, const int nodeNumber, const Structure& structureIn); /// Destructor ~CellProjection(); // initialize the cell projection void initialize(const QString& fileNameIn = ""); /// Get the projected position of this cell (returns true if valid projection) bool getProjectedPosition(const CoordinateFile* cf, const TopologyFile* tf, const bool fiducialSurfaceFlag, const bool flatSurfaceFlag, const bool pasteOntoSurfaceFlag, float xyzOut[3]) const; /// get the volume position void getVolumeXYZ(float xyzOut[3]) const; /// set the volume position void setVolumeXYZ(const float xyzIn[3]); /// called to read from an XML DOM structure virtual void readXMLWithDOM(QDomNode& node) throw (FileException); /// called to write to an XML structure virtual void writeXML(QDomDocument& xmlDoc, QDomElement& parentElement, const int cellNumber); /// Set the cell's class name void setClassName(const QString& name); /// set the cell's name void setName(const QString& name); /// Get the index of the unique name int getUniqueNameIndex() const { return uniqueNameIndex; } /// set element from text (used by SAX XML parser) void setElementFromText(const QString& elementName, const QString& textValue); /// get duplicate cell projection flag bool getDuplicateFlag() const { return duplicateFlag; } /// set the duplicate cell projection flag void setDuplicateFlag(const bool b); protected: /// called when data modified void setModified(); /// compute a projection point void computeProjectionPoint(float projection[3]) const; /// Unproject an inside triangle projection bool unprojectInsideTriangle(const CoordinateFile& cf, const TopologyFile& tf, const bool pasteOntoSurfaceFlag, float xyzOut[3]) const; /// Unproject an outside triangle projection bool unprojectOutsideTriangle(const CoordinateFile& cf, const TopologyFile& tf, const bool pasteOntoSurfaceFlag, float xyzOut[3]) const; /// Add a cell class //int addCellClass(const QString& className); /// The cell classes //std::vector cellClasses; /// projection is inside triangle static const QString tagInsideTriangle; /// projection is outside triangle static const QString tagOutsideTriangle; /// projection is unknown static const QString tagUnknownTriangle; /// set when reading a cell projection file for throwing exceptions QString filename; /// the unique name index int uniqueNameIndex; /// cell projection type PROJECTION_TYPE projectionType; /// INSIDE TRIANGLE PROJECTION vertices int closestTileVertices[3]; /// INSIDE TRIANGLE PROJECTION tile areas float closestTileAreas[3]; /// INSIDE TRIANGLE PROJECTION distances float cdistance[3]; /// OUTSIDE TRIANGLE DR float dR; /// OUTSIDE TRIANGLE fiducial coords float triFiducial[2][3][3]; /// OUTSIDE TRIANGLE theta float thetaR; /// OUTSIDE TRIANGLE phi float phiR; /// OUTSIDE TRIANGLE triangle vertices int triVertices[2][3]; /// OUTSIDE TRIANGLE vertices int vertex[2]; /// OUTSIDE TRIANGLE fiducial vertices float vertexFiducial[2][3]; /// OUTSIDE TRIANGLE fiducial position float posFiducial[3]; // cell's Fiducial surface position /// OUTSIDE TRIANGLE fracRI float fracRI; /// OUTSIDE TRIANGLE fracRJ float fracRJ; /// position of focus in a volume float volumeXYZ[3]; /// duplicate flag (used when near both cerebral and cerebellar) bool duplicateFlag; /// cell projection file which the projection is a member of CellProjectionFile* cellProjectionFile; /// Read this cell projection version 1 file void readFileDataVersion1(QTextStream& stream) throw (FileException); /// Read this cell projection version 2 file void readFileDataVersion2(QTextStream& stream) throw (FileException); /// Write this cell projection void writeFileData(QTextStream& stream, const int cellNumber) throw (FileException); /// tag for reading and writing cells static const QString tagCellProjection; /// tag for reading and writing cells static const QString tagCellProjNumber; /// tag for reading and writing cells static const QString tagProjectionType; /// tag for reading and writing cells static const QString tagClosestTileVertices; /// tag for reading and writing cells static const QString tagClosestTileAreas; /// tag for reading and writing cells static const QString tagCDistance; /// tag for reading and writing cells static const QString tagDR; /// tag for reading and writing cells static const QString tagTriFiducial; /// tag for reading and writing cells static const QString tagThetaR; /// tag for reading and writing cells static const QString tagPhiR; /// tag for reading and writing cells static const QString tagTriVertices; /// tag for reading and writing cells static const QString tagVertex; /// tag for reading and writing cells static const QString tagVertexFiducial; /// tag for reading and writing cells static const QString tagPosFiducial; /// tag for reading and writing cells static const QString tagFracRI; /// tag for reading and writing cells static const QString tagFracRJ; /// tag for reading and writing cells static const QString tagVolumeXYZ; /// tag for reading and writing cells static const QString tagDuplicateFlag; friend class CellFileProjector; friend class CellProjectionFile; friend class CellProjectionUnprojector; friend class FociFileToPalsProjector; friend class FociProjectionFile; }; #ifdef __CELL_PROJECTION_MAIN__ const QString CellProjection::tagCellProjection = "CellProjection"; const QString CellProjection::tagCellProjNumber = "cellProjNumber"; const QString CellProjection::tagProjectionType = "projectionType"; const QString CellProjection::tagClosestTileVertices = "closestTileVertices"; const QString CellProjection::tagClosestTileAreas = "closestTileAreas"; const QString CellProjection::tagCDistance = "cdistance"; const QString CellProjection::tagDR = "dR"; const QString CellProjection::tagTriFiducial = "triFiducial"; const QString CellProjection::tagThetaR = "thetaR"; const QString CellProjection::tagPhiR = "phiR"; const QString CellProjection::tagTriVertices = "triVertices"; const QString CellProjection::tagVertex = "vertex"; const QString CellProjection::tagVertexFiducial = "vertexFiducial"; const QString CellProjection::tagPosFiducial = "posFiducial"; const QString CellProjection::tagFracRI = "fracRI"; const QString CellProjection::tagFracRJ = "fracRJ"; const QString CellProjection::tagVolumeXYZ = "volumeXYZ"; const QString CellProjection::tagDuplicateFlag = "duplicateFlag"; const QString CellProjection::tagInsideTriangle = "INSIDE"; const QString CellProjection::tagOutsideTriangle = "OUTSIDE"; const QString CellProjection::tagUnknownTriangle = "UNKNOWN"; #endif // __CELL_PROJECTION_MAIN__ /// class for storing cell projections class CellProjectionFile : public AbstractFile { private: static const QString tagFileVersion; static const QString tagNumberOfCellProjections; static const QString tagNumberOfComments; static const QString tagCommentUrl; static const QString tagCommentKeyWords; static const QString tagCommentTitle; static const QString tagCommentAuthors; static const QString tagCommentCitation; static const QString tagCommentStereotaxicSpace; /// The cell projections std::vector cellProjections; /// Cell projection study info std::vector studyInfo; /// The cell classes std::vector cellClasses; /// The cell unique names std::vector cellUniqueNames; /// read the version number only flag bool readVersionNumberOnly; /// version number of this file int versionNumber; // read the file with an XML stream reader void readFileWithXmlStreamReader(QFile& file) throw (FileException); /// read file version 1 data void readFileVersion1(QTextStream&, const int numProjections, const int numStudyInfo) throw (FileException); /// read file version 2 data void readFileVersion2(QTextStream&, const int numProjections, const int numStudyInfo) throw (FileException); /// read file version 3 data void readFileVersion3(QFile& file, QTextStream&, const int numProjections) throw (FileException); // read file's data void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException); // write version 2 file's data void writeFileVersion2(QTextStream& stream) throw (FileException); // write version 3 file's data void writeFileVersion3(QTextStream& stream) throw (FileException); // write file's data void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException); public: /// Constructor CellProjectionFile(const QString& descriptiveName = "Cell Projection File", const QString& defaultExtensionIn = SpecFile::getCellProjectionFileExtension()); /// Destructor virtual ~CellProjectionFile(); /// add a cell projection void addCellProjection(const CellProjection& cp); /// Add a cell class int addCellClass(const QString& className); /// Add a cell unique name int addCellUniqueName(const QString& uniqueName); /// append a cell projection file to this cell projection file void append(const CellProjectionFile& cpf); /// append a fiducial cell file void appendFiducialCellFile(const CellFile& cf); /// assign colors to these cell projections void assignColors(ColorFile& cf, const CellBase::CELL_COLOR_MODE colorMode); /// apply a transformation matrix to the cells //void applyTransformationMatrix(const int sectionLow, // const int sectionHigh, // const float matrix[16], // const bool onlySpecialCells); /// apply a transformation matrix to the cells void applyTransformationMatrix(const CoordinateFile* cf, const TopologyFile* tf, const bool fiducialSurfaceFlag, const int sectionLow, const int sectionHigh, const TransformationMatrix& matrix, const bool onlySpecialCells); /// apply a transformation matrix to the cells //void applyTransformationMatrix(const TransformationMatrix& matrix, // const bool onlySpecialCells = false); /// clear the file in memory void clear(); /// returns true if the file is isEmpty (contains no data) bool empty() const { return (getNumberOfCellProjections() == 0); } /// get the version number of this file int getVersionNumber() const { return versionNumber; } /// get cell class indices sorted by name case insensitive void getCellClassIndicesSortedByName(std::vector& indicesSortedByNameOut, const bool reverseOrderFlag, const bool limitToDisplayedCellsFlag) const; /// get number of cell classes int getNumberOfCellClasses() const { return cellClasses.size(); } /// get cell class index by its name int getCellClassIndexByName(const QString& name) const; /// get cell class selected by index bool getCellClassSelectedByIndex(const int index) const; /// set cell class selected by index void setCellClassSelectedByIndex(const int index, const bool sel); /// get cell class selected by name bool getCellClassSelectedByName(const QString& name) const; /// get cell class name QString getCellClassNameByIndex(const int index) const; /// set the status of all cell classes void setAllCellClassStatus(const bool selected); /// transfer table subheader short name to cell classes void transferTableSubHeaderShortNameToCellClass(const StudyMetaDataLink& smdl, const QString& shortName); /// set the search status of all cells void setAllSearchStatus(const bool inSearchFlag); /// get cell unique name indices sorted by name case insensitive void getCellUniqueNameIndicesSortedByName(std::vector& indicesSortedByNameOut, const bool reverseOrderFlag, const bool limitToDisplayedCellsFlag) const; /// get number of cell unique names int getNumberOfCellUniqueNames() const { return cellUniqueNames.size(); } /// get cell unique name index by its name int getCellUniqueNameIndexByName(const QString& name) const; /// get cell unique name selected by index bool getCellUniqueNameSelectedByIndex(const int index) const; /// set cell unique name selected by index void setCellUniqueNameSelectedByIndex(const int index, const bool sel); /// get cell unique name selected by name bool getCellUniqueNameSelectedByName(const QString& name) const; /// get cell unique name name QString getCellUniqueNameByIndex(const int index) const; /// set the status of all cell unique names void setAllCellUniqueNameStatus(const bool selected); /// get indices of displayed cell projections void getIndicesOfDisplayedCells(std::vector& indicesOut) const; /// get a cell projection CellProjection* getCellProjection(const int i) { return &cellProjections[i]; } /// get a cell projection (const method) const CellProjection* getCellProjection(const int i) const { return &cellProjections[i]; } /// get first cell projection with specified name CellProjection* getFirstCellProjectionWithName(const QString& name); /// get last cell projection with specified name CellProjection* getLastCellProjectionWithName(const QString& name); /// get first cell projection with specified name (const method) const CellProjection* getFirstCellProjectionWithName(const QString& name) const; /// get last cell projection with specified name (const method) const CellProjection* getLastCellProjectionWithName(const QString& name) const; /// get number of cell projections int getNumberOfCellProjections() const { return cellProjections.size(); } /// get number of study info int getNumberOfStudyInfo() const { return studyInfo.size(); } /// get a cell file containing the origin (unprojected) coordinates void getCellFileOriginalCoordinates(CellFile& cellFileOut) const; /// get a cell file projecting to supplied coord/topo void getCellFile(const CoordinateFile* cf, const TopologyFile* tf, const bool fiducialSurfaceFlag, CellFile& cellFileOut) const; /// get a cell file projecting to supplied coord/topo for left and right hemispheres void getCellFileForRightLeftFiducials(const CoordinateFile* leftCF, const TopologyFile* leftTF, const CoordinateFile* rightCF, const TopologyFile* rightTF, const CoordinateFile* cerebellumCF, const TopologyFile* cerebellumTF, CellFile& cellFileOut) const; // get all cell areas void getAllCellAreas(std::vector& allAreasOut) const; // get all comments void getAllCellComments(std::vector& allCommentsOut) const; // get all cell geography void getAllCellGeography(std::vector& allGeographyOut) const; /// delete cell projection at specified index void deleteCellProjection(const int index); // get all cell regions of interest void getAllCellRegionsOfInterest(std::vector& allRegionsOfInterestOut) const; /// delete all duplicate cell projections void deleteAllDuplicateCellProjections(); /// delete cell projections with name void deleteCellProjectionsWithName(const QString& name); /// delete cell projections whose indices are not specified void deleteAllButTheseCellProjections(const int* indices, const int numIndices); /// delete all cell projections whose display flag is false void deleteAllNonDisplayedCellProjections(const Structure& keepThisStructureOnly); /// assign class to all displayed foci void assignClassToDisplayedFoci(const QString& className); /// get a pointer to the study info std::vector* getPointerToStudyInfo() { return &studyInfo; } /// get the study info index from the study info's value int getStudyInfoFromValue(const CellStudyInfo& studyInfo) const; /// get a study info (const method) const CellStudyInfo* getStudyInfo(const int index) const; /// get a study info CellStudyInfo* getStudyInfo(const int index); /// add a study info int addStudyInfo(const CellStudyInfo& studyInfo); /// delete all study info and clear links to study info void deleteAllStudyInfo(); /// delete study info void deleteStudyInfo(const int indx); /// set a study info void setStudyInfo(const int index, const CellStudyInfo& csi); /// Get the version number of the cell projection file static int readFilesVersionNumber(const QString& filename); /// set the special flag for all cells within the section numbers and bounds void setSpecialFlags(const int sectionLow, const int sectionHigh, const float bounds[4]); /// clear all special flags void clearAllSpecialFlags(); /// clear all highlight flags void clearAllHighlightFlags(); /// get PubMedID's of all linked studies void getPubMedIDsOfAllLinkedStudyMetaData(std::vector& studyPMIDs, const bool displayedFociOnlyFlag = false) const; /// update cell PubMed ID if cell name matches study name void updatePubMedIDIfCellNameMatchesStudyName(const StudyMetaDataFile* smdf); /// update cell name with linked study name void updateCellNameWithStudyNameForMatchingPubMedIDs(const StudyMetaDataFile* smdf); /// update cell class if linked to table subheader void updateCellClassWithLinkedStudyTableSubheaderShortNames(const StudyMetaDataFile* smdf); /// update cell class with linked tabel subheader name, linked figure panel task /// description, or page reference subheader short name void updateCellClassWithLinkedTableFigureOrPageReference(const StudyMetaDataFile* smdf); /// find out if comma separated file conversion supported virtual void getCommaSeparatedFileSupport(bool& readFromCSV, bool& writeToCSV) const; /// write the file's data into a comma separated values file (throws exception if not supported) virtual void writeDataIntoCommaSeparatedValueFile(CommaSeparatedValueFile& csv) throw (FileException); /// read the file's data from a comma separated values file (throws exception if not supported) virtual void readDataFromCommaSeparatedValuesTable(const CommaSeparatedValueFile& csv) throw (FileException); }; #endif // __CELL_PROJECTION_FILE_H__ #ifdef __CELL_PROJECTION_FILE_MAIN__ const QString CellProjectionFile::tagFileVersion = "tag-version"; const QString CellProjectionFile::tagNumberOfCellProjections = "tag-number-of-cell-projections"; const QString CellProjectionFile::tagNumberOfComments = "tag-number-of-comments"; const QString CellProjectionFile::tagCommentUrl = "tag-url"; const QString CellProjectionFile::tagCommentKeyWords = "tag-key-words"; const QString CellProjectionFile::tagCommentTitle = "tag-title"; const QString CellProjectionFile::tagCommentAuthors = "tag-authors"; const QString CellProjectionFile::tagCommentCitation = "tag-citation"; const QString CellProjectionFile::tagCommentStereotaxicSpace = "tag-space"; #endif // __CELL_PROJECTION_FILE_MAIN__ caret-5.6.4~dfsg.1.orig/caret_files/CellProjectionFile.cxx0000664000175000017500000035724211572067322023316 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #define __CELL_PROJECTION_FILE_MAIN__ #define __CELL_PROJECTION_MAIN__ #include "CellProjectionFile.h" #undef __CELL_PROJECTION_MAIN__ #undef __CELL_PROJECTION_FILE_MAIN__ #include "CellClass.h" #include "CellFile.h" #include "ColorFile.h" #include "CommaSeparatedValueFile.h" #include "CoordinateFile.h" #include "MathUtilities.h" #include "NameIndexSort.h" #include "SpecFile.h" #include "StringTable.h" #include "StringUtilities.h" #include "StudyMetaDataFile.h" #include "TopologyFile.h" #include "TopologyHelper.h" #include "TransformationMatrixFile.h" #include "vtkMath.h" /** * Constructor. */ CellProjection::CellProjection(const QString& filenameIn) { initialize(filenameIn); } /** * Constructor for placing cell projection at a node (no need to project). */ CellProjection::CellProjection(const QString& nameIn, const CoordinateFile* fiducialCoordinateFile, const int nodeNumber, const Structure& structureIn) { initialize(); const float* fidXYZ = fiducialCoordinateFile->getCoordinate(nodeNumber); setXYZ(fidXYZ); setName(nameIn); // // Set fiducial position // posFiducial[0] = fidXYZ[0]; posFiducial[1] = fidXYZ[1]; posFiducial[2] = fidXYZ[2]; // // save original hemisphere // if (structureIn.getType() != Structure::STRUCTURE_TYPE_INVALID) { structure = structureIn; } else { if (fidXYZ[0] < 0.0) { structure.setType(Structure::STRUCTURE_TYPE_CORTEX_LEFT); } else { structure.setType(Structure::STRUCTURE_TYPE_CORTEX_RIGHT); } } // // Project // setSignedDistanceAboveSurface(0.0); projectionType = CellProjection::PROJECTION_TYPE_INSIDE_TRIANGLE; closestTileVertices[0] = nodeNumber; closestTileVertices[1] = nodeNumber; closestTileVertices[2] = nodeNumber; closestTileAreas[0] = 0.33333; closestTileAreas[1] = 0.33333; closestTileAreas[2] = 0.33333; cdistance[0] = 0.0; cdistance[1] = 0.0; cdistance[2] = 0.0; volumeXYZ[0] = fidXYZ[0]; volumeXYZ[1] = fidXYZ[1]; volumeXYZ[2] = fidXYZ[2]; } /** * Initialize the cell projection */ void CellProjection::initialize(const QString& filenameIn) { filename = filenameIn; CellBase::initialize(); uniqueNameIndex = -1; cellProjectionFile = NULL; projectionType = PROJECTION_TYPE_UNKNOWN; duplicateFlag = false; for (int i = 0; i < 3; i++) { posFiducial[i] = 0.0; closestTileVertices[i] = 0; closestTileAreas[i] = 0.0; cdistance[i] = 0.0; } for (int j = 0; j < 2; j++) { vertex[j] = -1; for (int k = 0; k < 3; k++) { vertexFiducial[j][k] = 0.0; triVertices[j][k] = -1; for (int m = 0; m < 3; m++) { triFiducial[j][k][m] = 0.0; } } } dR = 0.0; thetaR = 0.0; phiR = 0.0; fracRI = 0.0; fracRJ = 0.0; volumeXYZ[0] = 0.0; volumeXYZ[1] = 0.0; volumeXYZ[2] = 0.0; } /** * update modification status */ void CellProjection::setModified() { if (cellProjectionFile != NULL) { cellProjectionFile->setModified(); } } /** * Destructor. */ CellProjection::~CellProjection() { } /** * Get the projected position of this cell (returns true if valid projection). */ bool CellProjection::getProjectedPosition(const CoordinateFile* cf, const TopologyFile* tf, const bool fiducialSurfaceFlag, const bool flatSurfaceFlag, const bool pasteOntoSurfaceFlagIn, float xyzOut[3]) const { // // Do not use paste onto surface if the surface is flat // bool pasteOntoSurfaceFlag = pasteOntoSurfaceFlagIn; if (flatSurfaceFlag) { pasteOntoSurfaceFlag = false; } bool valid = false; switch(projectionType) { case CellProjection::PROJECTION_TYPE_INSIDE_TRIANGLE: valid = unprojectInsideTriangle(*cf, *tf, pasteOntoSurfaceFlag, xyzOut); break; case CellProjection::PROJECTION_TYPE_OUTSIDE_TRIANGLE: valid = unprojectOutsideTriangle(*cf, *tf, pasteOntoSurfaceFlag, xyzOut); break; case CellProjection::PROJECTION_TYPE_UNKNOWN: if (fiducialSurfaceFlag) { if ((xyz[0] != 0.0) || (xyz[1] != 0.0) || (xyz[2] != 0.0)) { xyzOut[0] = xyz[0]; xyzOut[1] = xyz[1]; xyzOut[2] = xyz[2]; valid = true; } else if ((posFiducial[0] != 0.0) || (posFiducial[1] != 0.0) || (posFiducial[2] != 0.0)) { xyzOut[0] = posFiducial[0]; xyzOut[1] = posFiducial[1]; xyzOut[2] = posFiducial[2]; valid = true; } } break; } // // If flat surface and cells were to be pasted onto the surface, // just push cells above flat surface // if (flatSurfaceFlag && pasteOntoSurfaceFlagIn) { xyzOut[2] = 1.0; } return valid; } /** * Unproject an outside triangle projections. */ bool CellProjection::unprojectOutsideTriangle(const CoordinateFile& cf, const TopologyFile& tf, const bool pasteOntoSurfaceFlag, float xyzOut[3]) const { const int is = 0; const int js = 1; const TopologyHelper* th = tf.getTopologyHelper(false, true, false); if ((th->getNodeHasNeighbors(vertex[is]) == false) || (th->getNodeHasNeighbors(vertex[js]) == false)) { return false; } float v[3], v_t1[3]; MathUtilities::subtractVectors(vertexFiducial[js], vertexFiducial[is], v); MathUtilities::subtractVectors(posFiducial, vertexFiducial[is], v_t1); float s_t2 = MathUtilities::dotProduct(v, v); float s_t3 = MathUtilities::dotProduct(v_t1, v); float QR[3]; for (int j = 0; j < 3; j++) { QR[j] = vertexFiducial[is][j] + ((s_t3/s_t2) * v[j]); } const int pis = vertex[0]; const int pjs = vertex[1]; const float* posPIS = cf.getCoordinate(pis); const float* posPJS = cf.getCoordinate(pjs); if (pasteOntoSurfaceFlag) { xyzOut[0] = (posPIS[0] + posPJS[0]) / 2.0; xyzOut[1] = (posPIS[1] + posPJS[1]) / 2.0; xyzOut[2] = (posPIS[2] + posPJS[2]) / 2.0; return true; } MathUtilities::subtractVectors(posPJS, posPIS, v); float QS[3]; if ((fracRI <= 1.0) && (fracRJ <= 1.0)) { for (int j = 0; j < 3; j++) { QS[j] = posPIS[j] + fracRI * v[j]; } } else if ((fracRI > 1.0) && (fracRI > fracRJ)) { MathUtilities::subtractVectors(QR, vertexFiducial[js], v_t1); s_t2 = MathUtilities::vectorLength(v_t1); MathUtilities::subtractVectors(posPJS, posPIS, v); s_t3 = MathUtilities::vectorLength(v); for (int j = 0; j < 3; j++) { QS[j] = posPJS[j] + s_t2 * (v[j]/s_t3); } } else if ((fracRJ > 1.0) && (fracRJ > fracRI)) { MathUtilities::subtractVectors(QR, vertexFiducial[is], v_t1); s_t2 = MathUtilities::vectorLength(v_t1); MathUtilities::subtractVectors(posPIS, posPJS, v); s_t3 = MathUtilities::vectorLength(v); for (int j = 0; j < 3; j++) { QS[j] = posPIS[j] + s_t2 * (v[j]/s_t3); } } else { // printf("CellProjectionFile: Unrecognized case for fracRI and fracRJ: " // "%.2f %.2f\n", fracRI, fracRJ); return false; } if ((triVertices[0][0] < 0) || (triVertices[1][0] < 0)) { return false; } float normalB[3]; MathUtilities::computeNormal((float*)cf.getCoordinate(triVertices[1][0]), (float*)cf.getCoordinate(triVertices[1][1]), (float*)cf.getCoordinate(triVertices[1][2]), normalB); float normalA[3]; MathUtilities::computeNormal((float*)cf.getCoordinate(triVertices[0][0]), (float*)cf.getCoordinate(triVertices[0][1]), (float*)cf.getCoordinate(triVertices[0][2]), normalA); s_t2 = MathUtilities::dotProduct(normalA, normalB); s_t2 = std::min(s_t2, (float)1.0); // limit to <= 1.0 float phiS = std::acos(s_t2); float thetaS = 0.0; if (phiR > 0.0) { thetaS = (thetaR/phiR) * phiS; } else { thetaS = 0.5 * phiS; } MathUtilities::subtractVectors(posPJS, posPIS, v); MathUtilities::normalize(v); float v_t3[3]; MathUtilities::crossProduct(normalA, v, v_t3); float projection[3] = { 0.0, 0.0, 0.0 }; computeProjectionPoint(projection); MathUtilities::subtractVectors(projection, QR, v_t1); MathUtilities::normalize(v_t1); MathUtilities::subtractVectors(vertexFiducial[js], vertexFiducial[is], v); MathUtilities::normalize(v); float normalA_3D[3]; MathUtilities::computeNormal(triFiducial[0][0], triFiducial[0][1], triFiducial[0][2], normalA_3D); float v_t2[3]; MathUtilities::crossProduct(normalA_3D, v, v_t2); s_t3 = MathUtilities::dotProduct(v_t1, v_t2); float TS[3]; for (int k = 0; k < 3; k++) { TS[k] = QS[k] + (s_t3 * (dR * std::sin(thetaS)) * v_t2[k]); } MathUtilities::subtractVectors(posFiducial, projection, v); MathUtilities::normalize(v); s_t3 = MathUtilities::dotProduct(normalA_3D, v); for (int i = 0; i < 3; i++) { xyzOut[i] = TS[i] + (dR * s_t3 * std::cos(thetaS)) * normalA[i]; } return true; } /** * Compute the projection point. */ void CellProjection::computeProjectionPoint(float projection[3]) const { float v[3], w[3], tnormal[3]; MathUtilities::subtractVectors(triFiducial[0][1], triFiducial[0][0], v); MathUtilities::subtractVectors(triFiducial[0][1], triFiducial[0][2], w); MathUtilities::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] = MathUtilities::dotProduct(v, posFiducial); b[1] = MathUtilities::dotProduct(w, posFiducial); b[2] = MathUtilities::dotProduct(tnormal, triFiducial[0][2]); vtkMath::LinearSolve3x3(a, b, projection); } /** * Unproject an inside triangle projection. */ bool CellProjection::unprojectInsideTriangle(const CoordinateFile& cf, const TopologyFile& tf, const bool pasteOntoSurfaceFlag, float xyzOut[3]) const { const float* v1 = cf.getCoordinate(closestTileVertices[0]); const float* v2 = cf.getCoordinate(closestTileVertices[1]); const float* v3 = cf.getCoordinate(closestTileVertices[2]); const TopologyHelper* th = tf.getTopologyHelper(true, true, true); if ((th->getNodeHasNeighbors(closestTileVertices[0]) == false) || (th->getNodeHasNeighbors(closestTileVertices[1]) == false) || (th->getNodeHasNeighbors(closestTileVertices[2]) == false)) { return false; } float t1[3], t2[3], t3[3]; for (int i = 0; i < 3; i++) { t1[i] = closestTileAreas[0] * v3[i]; t2[i] = closestTileAreas[1] * v1[i]; t3[i] = closestTileAreas[2] * v2[i]; } const float area = closestTileAreas[0] + closestTileAreas[1] + closestTileAreas[2]; float projection[3] = { 0.0, 0.0, 0.0 }; if (area != 0) { for (int i = 0; i < 3; i++) { projection[i] = (t1[i] + t2[i] + t3[i]) / area; } } // // Note: that does caret4 style clockwise orientation // float tileNormal[3]; MathUtilities::computeNormal((float*)v3, (float*)v2, (float*)v1, tileNormal); // // Are all of the node the same (focus projects to a single node, not a tile) // if ((closestTileVertices[0] == closestTileVertices[1]) && (closestTileVertices[1] == closestTileVertices[2])) { // // Compute node's normal by averaging its tiles' normals // float normalSum[3] = { 0.0, 0.0, 0.0 }; int node = closestTileVertices[0]; int numNeighbors = 0; const int* neighbors = th->getNodeNeighbors(node, numNeighbors); for (int i = 0; i < numNeighbors; i++) { int neigh1 = neighbors[i]; int nextNeighborIndex = i + 1; if (nextNeighborIndex >= numNeighbors) { nextNeighborIndex = 0; } int nextNeighbor = neighbors[nextNeighborIndex]; const float* c1 = cf.getCoordinate(node); const float* c2 = cf.getCoordinate(neigh1); const float* c3 = cf.getCoordinate(nextNeighbor); float neighborNormal[3]; MathUtilities::computeNormal((float*)c1, (float*)c2, (float*)c3, neighborNormal); normalSum[0] += neighborNormal[0]; normalSum[1] += neighborNormal[1]; normalSum[2] += neighborNormal[2]; } if (numNeighbors > 0) { tileNormal[0] = normalSum[0] / (float)numNeighbors; tileNormal[1] = normalSum[1] / (float)numNeighbors; tileNormal[2] = normalSum[2] / (float)numNeighbors; MathUtilities::normalize(tileNormal); } } for (int j = 0; j < 3; j++) { if (pasteOntoSurfaceFlag) { xyzOut[j] = projection[j]; } else if (signedDistanceAboveSurface != 0.0) { xyzOut[j] = projection[j] + tileNormal[j] * signedDistanceAboveSurface; } else { xyzOut[j] = projection[j] + cdistance[j]; } } return true; } /** * Set the cell's class name */ void CellProjection::setClassName(const QString& name) { className = name; if (cellProjectionFile != NULL) { classIndex = cellProjectionFile->addCellClass(name); } else { classIndex = -1; // 0; } setModified(); } /** * Set the cell's name */ void CellProjection::setName(const QString& name) { if (cellProjectionFile != NULL) { uniqueNameIndex = cellProjectionFile->addCellUniqueName(name); } else { uniqueNameIndex = -1; // 0; } CellBase::setName(name); setModified(); } /** * set the duplicate cell projection flag. */ void CellProjection::setDuplicateFlag(const bool b) { duplicateFlag = b; setModified(); } /** * get the volume position. */ void CellProjection::getVolumeXYZ(float xyzOut[3]) const { xyzOut[0] = volumeXYZ[0]; xyzOut[1] = volumeXYZ[1]; xyzOut[2] = volumeXYZ[2]; } /** * set the volume position. */ void CellProjection::setVolumeXYZ(const float xyzIn[3]) { volumeXYZ[0] = xyzIn[0]; volumeXYZ[1] = xyzIn[1]; volumeXYZ[2] = xyzIn[2]; setModified(); } /** * Read a version 1 cell projection. */ void CellProjection::readFileDataVersion1(QTextStream& stream) throw (FileException) { PROJECTION_TYPE tempProjectionType = PROJECTION_TYPE_UNKNOWN; projectionType = tempProjectionType; std::vector tokens; QString line; AbstractFile::readLineIntoTokens(filename, stream, line, tokens); if (tokens.size() < 6) { QString s("Reading cell projection 1st line "); s.append(line); throw FileException(filename, s); } sectionNumber = tokens[1].toInt(); name = tokens[2]; const QString typeName(tokens[3]); studyNumber = tokens[4].toInt(); structure.setTypeFromString(tokens[5]); /* if (tokens[5] == tagLeftHemisphere) { hemisphere = ORIGINAL_HEMISPHERE_LEFT; } else if (tokens[5] == tagRightHemisphere) { hemisphere = ORIGINAL_HEMISPHERE_RIGHT; } else { hemisphere = ORIGINAL_HEMISPHERE_UNKNOWN; } */ signedDistanceAboveSurface = 0.0; if (tokens.size() >= 7) { signedDistanceAboveSurface = tokens[6].toFloat(); } if (typeName == tagInsideTriangle) { tempProjectionType = PROJECTION_TYPE_INSIDE_TRIANGLE; AbstractFile::readLineIntoTokens(filename, stream, line, tokens); if (tokens.size() < 9) { QString s("Reading CellProjection INSIDE line "); s.append(line); throw FileException(filename, s); } closestTileVertices[0] = tokens[0].toInt(); closestTileVertices[1] = tokens[1].toInt(); closestTileVertices[2] = tokens[2].toInt(); closestTileAreas[0] = tokens[3].toFloat(); closestTileAreas[1] = tokens[4].toFloat(); closestTileAreas[2] = tokens[5].toFloat(); cdistance[0] = tokens[6].toFloat(); cdistance[1] = tokens[7].toFloat(); cdistance[2] = tokens[8].toFloat(); } else if (typeName == tagOutsideTriangle) { tempProjectionType = PROJECTION_TYPE_OUTSIDE_TRIANGLE; AbstractFile::readLineIntoTokens(filename, stream, line, tokens); if (tokens.size() < 5) { QString s("reading CellProjection OUTSIDE 1st line "); s.append(line); throw FileException(filename, s); } fracRI = tokens[0].toFloat(); fracRJ = tokens[1].toFloat(); dR = tokens[2].toFloat(); thetaR = tokens[3].toFloat(); phiR = tokens[4].toFloat(); AbstractFile::readLineIntoTokens(filename, stream, line, tokens); if (tokens.size() < 18) { QString s("Reading CellProjection OUTSIDE line "); s.append(line); throw FileException(filename, s); } int i = 0; int ctr = 0; for (i = 0; i < 2; i++) { for (int j = 0; j < 3; j++) { for (int k = 0; k < 3; k++) { triFiducial[i][j][k] = tokens[ctr].toFloat(); ctr++; } } } AbstractFile::readLineIntoTokens(filename, stream, line, tokens); if (tokens.size() < 6) { QString s("reading CellProjection OUTSIDE 3rd line "); s.append(line); throw FileException(filename, s); } ctr = 0; for (i = 0; i < 2; i++) { for (int j = 0; j < 3; j++) { triVertices[i][j] = tokens[ctr].toInt(); ctr++; } } AbstractFile::readLineIntoTokens(filename, stream, line, tokens); if (tokens.size() < 6) { QString s("reading CellProjection OUTSIDE 4th line "); s.append(line); throw FileException(filename, line); } ctr = 0; for (i = 0; i < 2; i++) { for (int j = 0; j < 3; j++) { vertexFiducial[i][j] = tokens[ctr].toFloat(); ctr++; } } AbstractFile::readLineIntoTokens(filename, stream, line, tokens); if (tokens.size() < 5) { QString s("reading CellProjection OUTSIDE 5th line "); s.append(line); throw FileException(filename, s); } vertex[0] = tokens[0].toInt(); vertex[1] = tokens[1].toInt(); posFiducial[0] = tokens[2].toFloat(); posFiducial[1] = tokens[3].toFloat(); posFiducial[2] = tokens[4].toFloat(); volumeXYZ[0] = posFiducial[0]; volumeXYZ[1] = posFiducial[1]; volumeXYZ[2] = posFiducial[2]; } else if (typeName == tagUnknownTriangle) { return; } else { QString s("reading CellProjection invalid projection type "); s.append(line); throw FileException(filename, line); } projectionType = tempProjectionType; } /** * Read a version 2 cell projection. */ void CellProjection::readFileDataVersion2(QTextStream& stream) throw (FileException) { PROJECTION_TYPE tempProjectionType = PROJECTION_TYPE_UNKNOWN; projectionType = tempProjectionType; std::vector tokens; QString line; AbstractFile::readLineIntoTokens(filename, stream, line, tokens); if (tokens.size() < 6) { QString s("Reading cell projection 1st line "); s.append(line); throw FileException(filename, s); } sectionNumber = tokens[1].toInt(); name = tokens[2]; className = tokens[3]; if (className == "???") { className = ""; } const QString typeName(tokens[4]); studyNumber = tokens[5].toInt(); structure.setTypeFromString(tokens[6]); /* if (tokens[6] == tagLeftHemisphere) { hemisphere = ORIGINAL_HEMISPHERE_LEFT; } else if (tokens[6] == tagRightHemisphere) { hemisphere = ORIGINAL_HEMISPHERE_RIGHT; } else { hemisphere = ORIGINAL_HEMISPHERE_UNKNOWN; } */ signedDistanceAboveSurface = 0.0; if (tokens.size() >= 8) { signedDistanceAboveSurface = tokens[7].toFloat(); } if (typeName == tagInsideTriangle) { tempProjectionType = PROJECTION_TYPE_INSIDE_TRIANGLE; AbstractFile::readLineIntoTokens(filename, stream, line, tokens); if (tokens.size() < 9) { QString s("Reading CellProjection INSIDE line "); s.append(line); throw FileException(filename, s); } closestTileVertices[0] = tokens[0].toInt(); closestTileVertices[1] = tokens[1].toInt(); closestTileVertices[2] = tokens[2].toInt(); closestTileAreas[0] = tokens[3].toFloat(); closestTileAreas[1] = tokens[4].toFloat(); closestTileAreas[2] = tokens[5].toFloat(); cdistance[0] = tokens[6].toFloat(); cdistance[1] = tokens[7].toFloat(); cdistance[2] = tokens[8].toFloat(); } else if (typeName == tagOutsideTriangle) { tempProjectionType = PROJECTION_TYPE_OUTSIDE_TRIANGLE; AbstractFile::readLineIntoTokens(filename, stream, line, tokens); if (tokens.size() < 5) { QString s("reading CellProjection OUTSIDE 1st line "); s.append(line); throw FileException(filename, s); } fracRI = tokens[0].toFloat(); fracRJ = tokens[1].toFloat(); dR = tokens[2].toFloat(); thetaR = tokens[3].toFloat(); phiR = tokens[4].toFloat(); AbstractFile::readLineIntoTokens(filename, stream, line, tokens); if (tokens.size() < 18) { QString s("Reading CellProjection OUTSIDE line "); s.append(line); throw FileException(filename, s); } int i = 0; int ctr = 0; for (i = 0; i < 2; i++) { for (int j = 0; j < 3; j++) { for (int k = 0; k < 3; k++) { triFiducial[i][j][k] = tokens[ctr].toFloat(); ctr++; } } } AbstractFile::readLineIntoTokens(filename, stream, line, tokens); if (tokens.size() < 6) { QString s("reading CellProjection OUTSIDE 3rd line "); s.append(line); throw FileException(filename, s); } ctr = 0; for (i = 0; i < 2; i++) { for (int j = 0; j < 3; j++) { triVertices[i][j] = tokens[ctr].toInt(); ctr++; } } AbstractFile::readLineIntoTokens(filename, stream, line, tokens); if (tokens.size() < 6) { QString s("reading CellProjection OUTSIDE 4th line "); s.append(line); throw FileException(filename, line); } ctr = 0; for (i = 0; i < 2; i++) { for (int j = 0; j < 3; j++) { vertexFiducial[i][j] = tokens[ctr].toFloat(); ctr++; } } AbstractFile::readLineIntoTokens(filename, stream, line, tokens); if (tokens.size() < 5) { QString s("reading CellProjection OUTSIDE 5th line "); s.append(line); throw FileException(filename, s); } vertex[0] = tokens[0].toInt(); vertex[1] = tokens[1].toInt(); posFiducial[0] = tokens[2].toFloat(); posFiducial[1] = tokens[3].toFloat(); posFiducial[2] = tokens[4].toFloat(); volumeXYZ[0] = posFiducial[0]; volumeXYZ[1] = posFiducial[1]; volumeXYZ[2] = posFiducial[2]; } else if (typeName == tagUnknownTriangle) { return; } else { QString s("reading CellProjection invalid projection type "); s.append(line); throw FileException(filename, line); } projectionType = tempProjectionType; } /** * Write a cell projection. */ void CellProjection::writeFileData(QTextStream& stream, const int cellNumber) throw (FileException) { char projStr[256]; switch(projectionType) { case PROJECTION_TYPE_INSIDE_TRIANGLE: strcpy(projStr, tagInsideTriangle.toAscii().constData()); break; case PROJECTION_TYPE_OUTSIDE_TRIANGLE: strcpy(projStr, tagOutsideTriangle.toAscii().constData()); break; case PROJECTION_TYPE_UNKNOWN: default: strcpy(projStr, tagUnknownTriangle.toAscii().constData()); break; } if (className.isEmpty()) { className = "???"; } stream << cellNumber << " " << sectionNumber << " " << name << " " << className << " " << projStr << " " << studyNumber << " " << StringUtilities::makeUpperCase(structure.getTypeAsString()) << " " << signedDistanceAboveSurface << "\n"; switch(projectionType) { case PROJECTION_TYPE_INSIDE_TRIANGLE: stream << closestTileVertices[0] << " " << closestTileVertices[1] << " " << closestTileVertices[2] << " " << closestTileAreas[0] << " " << closestTileAreas[1] << " " << closestTileAreas[2] << " " << cdistance[0] << " " << cdistance[1] << " " << cdistance[2] << "\n"; break; case PROJECTION_TYPE_OUTSIDE_TRIANGLE: { stream << fracRI << " " << fracRJ << " " << dR << " " << thetaR << " " << phiR << "\n"; int i = 0; for (i = 0; i < 2; i++) { for (int j = 0; j < 3; j++) { for (int k = 0; k < 3; k++) { stream << triFiducial[i][j][k] << " "; } } } stream << "\n"; for (i = 0; i < 2; i++) { for (int j = 0; j < 3; j++) { stream << triVertices[i][j] << " "; } } stream << "\n"; for (i = 0; i < 2; i++) { for (int j = 0; j < 3; j++) { stream << vertexFiducial[i][j] << " "; } } stream << "\n"; stream << vertex[0] << " " << vertex[1] << " " << posFiducial[0] << " " << posFiducial[1] << " " << posFiducial[2] << "\n"; } break; case PROJECTION_TYPE_UNKNOWN: default: break; } } /** * set element from text (used by SAX XML parser). */ void CellProjection::setElementFromText(const QString& elementName, const QString& textValue) { const QStringList sl = textValue.split(QRegExp("\\s+"), QString::SkipEmptyParts); const int numItems = sl.count(); if (elementName == CellProjection::tagCellProjNumber) { // ignore } else if (elementName == CellProjection::tagProjectionType) { if (textValue == tagInsideTriangle) { projectionType = PROJECTION_TYPE_INSIDE_TRIANGLE; } else if (textValue == tagOutsideTriangle) { projectionType = PROJECTION_TYPE_OUTSIDE_TRIANGLE; } } else if (elementName == CellProjection::tagClosestTileVertices) { if (numItems == 3) { for (int i = 0; i < 3; i++) { closestTileVertices[i] = sl.at(i).toInt(); } } } else if (elementName == CellProjection::tagClosestTileAreas) { if (numItems == 3) { for (int i = 0; i < 3; i++) { closestTileAreas[i] = sl.at(i).toFloat(); } } } else if (elementName == CellProjection::tagCDistance) { if (numItems == 3) { for (int i = 0; i < 3; i++) { cdistance[i] = sl.at(i).toFloat(); } } } else if (elementName == tagDR) { dR = textValue.toFloat(); } else if (elementName == CellProjection::tagTriFiducial) { if (numItems == 18) { float* data = (float*)triFiducial; for (int i = 0; i < 18; i++) { data[i] = sl.at(i).toFloat(); } } } else if (elementName == CellProjection::tagThetaR) { thetaR = textValue.toFloat(); } else if (elementName == CellProjection::tagPhiR) { phiR = textValue.toFloat(); } else if (elementName == CellProjection::tagTriVertices) { if (numItems == 6) { int* data = (int*)triVertices; for (int i = 0; i < 6; i++) { data[i] = sl.at(i).toInt(); } } } else if (elementName == CellProjection::tagVertex) { if (numItems == 2) { for (int i = 0; i < 2; i++) { vertex[i] = sl.at(i).toInt(); } } } else if (elementName == CellProjection::tagVertexFiducial) { if (numItems == 6) { float* data = (float*)vertexFiducial; for (int i = 0; i < 6; i++) { data[i] = sl.at(i).toFloat(); } } } else if (elementName == CellProjection::tagPosFiducial) { if (numItems == 3) { for (int i = 0; i < 3; i++) { posFiducial[i] = sl.at(i).toFloat(); } } } else if (elementName == CellProjection::tagFracRI) { fracRI = textValue.toFloat(); } else if (elementName == CellProjection::tagFracRJ) { fracRJ = textValue.toFloat(); } else if (elementName == CellProjection::tagVolumeXYZ) { if (numItems == 3) { for (int i = 0; i < 3; i++) { volumeXYZ[i] = sl.at(i).toFloat(); } } } else if (elementName == CellProjection::tagDuplicateFlag) { duplicateFlag = false; if (textValue == "true") { duplicateFlag = true; } } else { std::cout << "WARNING: Unrecognized child of CellProjection element " << elementName.toAscii().constData() << std::endl; } } /** * called to read from an XML structure. */ void CellProjection::readXMLWithDOM(QDomNode& nodeIn) throw (FileException) { if (nodeIn.isNull()) { return; } QDomElement elem = nodeIn.toElement(); if (elem.isNull()) { return; } if (elem.tagName() != tagCellProjection) { QString msg("Incorrect element type passed to CellProjection::readXMLWithDOM() "); msg.append(elem.tagName()); throw FileException("", msg); } projectionType = PROJECTION_TYPE_UNKNOWN; QDomNode node = nodeIn.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (elem.tagName() == tagCellProjNumber) { // ignore } else if (elem.tagName() == tagProjectionType) { const QString value = AbstractFile::getXmlElementFirstChildAsString(elem); if (value == tagInsideTriangle) { projectionType = PROJECTION_TYPE_INSIDE_TRIANGLE; } else if (value == tagOutsideTriangle) { projectionType = PROJECTION_TYPE_OUTSIDE_TRIANGLE; } } else if (elem.tagName() == tagClosestTileVertices) { AbstractFile::getXmlElementFirstChildAsInt(elem, closestTileVertices, 3); } else if (elem.tagName() == tagClosestTileAreas) { AbstractFile::getXmlElementFirstChildAsFloat(elem, closestTileAreas, 3); } else if (elem.tagName() == tagCDistance) { AbstractFile::getXmlElementFirstChildAsFloat(elem, cdistance, 3); } else if (elem.tagName() == tagDR) { dR = AbstractFile::getXmlElementFirstChildAsFloat(elem); } else if (elem.tagName() == tagTriFiducial) { AbstractFile::getXmlElementFirstChildAsFloat(elem, (float*)triFiducial, 18); } else if (elem.tagName() == tagThetaR) { thetaR = AbstractFile::getXmlElementFirstChildAsFloat(elem); } else if (elem.tagName() == tagPhiR) { phiR = AbstractFile::getXmlElementFirstChildAsFloat(elem); } else if (elem.tagName() == tagTriVertices) { AbstractFile::getXmlElementFirstChildAsInt(elem, (int*)triVertices, 6); } else if (elem.tagName() == tagVertex) { AbstractFile::getXmlElementFirstChildAsInt(elem, vertex, 2); } else if (elem.tagName() == tagVertexFiducial) { AbstractFile::getXmlElementFirstChildAsFloat(elem, (float*)vertexFiducial, 6); } else if (elem.tagName() == tagPosFiducial) { AbstractFile::getXmlElementFirstChildAsFloat(elem, posFiducial, 3); } else if (elem.tagName() == tagFracRI) { fracRI = AbstractFile::getXmlElementFirstChildAsFloat(elem); } else if (elem.tagName() == tagFracRJ) { fracRJ = AbstractFile::getXmlElementFirstChildAsFloat(elem); } else if (elem.tagName() == tagVolumeXYZ) { AbstractFile::getXmlElementFirstChildAsFloat(elem, volumeXYZ, 3); } else if (elem.tagName() == CellBase::tagSignedDistanceAboveSurface) { signedDistanceAboveSurface = AbstractFile::getXmlElementFirstChildAsFloat(elem); } else if (elem.tagName() == CellBase::tagClassName) { className = AbstractFile::getXmlElementFirstChildAsString(elem); if (className == "???") { className = ""; } } else if (elem.tagName() == CellProjection::tagDuplicateFlag) { duplicateFlag = false; if (AbstractFile::getXmlElementFirstChildAsString(elem) == "true") { duplicateFlag = true; } } else if (elem.tagName() == CellBase::tagCellBase) { CellBase::readXMLWithDOM(node); } else { std::cout << "WARNING: unrecognized CellProjection element: " << elem.tagName().toAscii().constData() << std::endl; } } node = node.nextSibling(); } } /** * called to write to an XML structure. */ void CellProjection::writeXML(QDomDocument& xmlDoc, QDomElement& parentElement, const int cellProjNumber) { // // Create the element for this class instance's data // QDomElement cellProjElement = xmlDoc.createElement(tagCellProjection); // // cell number // AbstractFile::addXmlTextElement(xmlDoc, cellProjElement, tagCellProjNumber, cellProjNumber); switch(projectionType) { case PROJECTION_TYPE_INSIDE_TRIANGLE: AbstractFile::addXmlTextElement(xmlDoc, cellProjElement, tagProjectionType, tagInsideTriangle); break; case PROJECTION_TYPE_OUTSIDE_TRIANGLE: AbstractFile::addXmlTextElement(xmlDoc, cellProjElement, tagProjectionType, tagOutsideTriangle); break; case PROJECTION_TYPE_UNKNOWN: default: AbstractFile::addXmlTextElement(xmlDoc, cellProjElement, tagProjectionType, tagUnknownTriangle); break; } AbstractFile::addXmlTextElement(xmlDoc, cellProjElement, tagClosestTileVertices, closestTileVertices, 3); AbstractFile::addXmlTextElement(xmlDoc, cellProjElement, tagClosestTileAreas, closestTileAreas, 3); AbstractFile::addXmlTextElement(xmlDoc, cellProjElement, tagCDistance, cdistance, 3); AbstractFile::addXmlTextElement(xmlDoc, cellProjElement, tagDR, dR); AbstractFile::addXmlTextElement(xmlDoc, cellProjElement, tagTriFiducial, (float*)(triFiducial), 18); AbstractFile::addXmlTextElement(xmlDoc, cellProjElement, tagThetaR, thetaR); AbstractFile::addXmlTextElement(xmlDoc, cellProjElement, tagPhiR, phiR); AbstractFile::addXmlTextElement(xmlDoc, cellProjElement, tagTriVertices, (int*)triVertices, 6); AbstractFile::addXmlTextElement(xmlDoc, cellProjElement, tagVertex, (int*)vertex, 2); AbstractFile::addXmlTextElement(xmlDoc, cellProjElement, tagVertexFiducial, (float*)vertexFiducial, 6); AbstractFile::addXmlTextElement(xmlDoc, cellProjElement, tagPosFiducial, posFiducial, 3); AbstractFile::addXmlTextElement(xmlDoc, cellProjElement, tagFracRI, fracRI); AbstractFile::addXmlTextElement(xmlDoc, cellProjElement, tagFracRJ, fracRJ); AbstractFile::addXmlTextElement(xmlDoc, cellProjElement, tagVolumeXYZ, volumeXYZ, 3); //AbstractFile::addXmlTextElement(xmlDoc, cellProjElement, // CellData::tagClassName, className); //AbstractFile::addXmlTextElement(xmlDoc, cellProjElement, // CellBase::tagSignedDistanceAboveSurface, signedDistanceAboveSurface); if (duplicateFlag) { AbstractFile::addXmlTextElement(xmlDoc, cellProjElement, tagDuplicateFlag, "true"); } else { AbstractFile::addXmlTextElement(xmlDoc, cellProjElement, tagDuplicateFlag, "false"); } // // Write the base class' data // CellBase::writeXML(xmlDoc, cellProjElement); // // Add class instance's data to the parent // parentElement.appendChild(cellProjElement); } //---------------------------------------------------------------------------- /** * Constructor. */ CellProjectionFile::CellProjectionFile(const QString& descriptiveName, const QString& defaultExtensionIn) : AbstractFile(descriptiveName, defaultExtensionIn, true, FILE_FORMAT_XML, FILE_IO_READ_ONLY, FILE_IO_NONE, FILE_IO_READ_AND_WRITE, FILE_IO_NONE, FILE_IO_NONE, FILE_IO_NONE, FILE_IO_READ_ONLY) { readVersionNumberOnly = 0; clear(); //if (DebugControl::getTestFlag2()) { // setXmlVersionReadWithSaxParser(true); //} } /** * Destructor. */ CellProjectionFile::~CellProjectionFile() { clear(); } /** * append a fiducial cell file. */ void CellProjectionFile::appendFiducialCellFile(const CellFile& cf) { const int origNumberOfStudyInfo = getNumberOfStudyInfo(); const int num = cf.getNumberOfCells(); for (int i = 0; i < num; i++) { CellProjection cp; const CellData* cd = cf.getCell(i); cp.copyData(*cd); cp.setVolumeXYZ(cd->getXYZ()); // // Update study info indexes // int studyNum = cd->getStudyNumber(); if (studyNum >= 0) { studyNum += origNumberOfStudyInfo; } cp.setStudyNumber(studyNum); addCellProjection(cp); } // // Transfer the study info // for (int j = 0; j < cf.getNumberOfStudyInfo(); j++) { addStudyInfo((*cf.getStudyInfo(j))); } // // transfer the file's comment // appendToFileComment(cf.getFileComment()); } /** * get a cell file containing the origin (unprojected) coordinates. */ void CellProjectionFile::getCellFileOriginalCoordinates(CellFile& cellFileOut) const { cellFileOut.clear(); const int num = getNumberOfCellProjections(); for (int i = 0; i < num; i++) { const CellProjection* cp = getCellProjection(i); CellData cd; cd.copyData(*cp); cd.setXYZ(cp->getXYZ()); cellFileOut.addCell(cd); } const int numStudyInfo = getNumberOfStudyInfo(); for (int i = 0; i < numStudyInfo; i++) { cellFileOut.addStudyInfo(*getStudyInfo(i)); } cellFileOut.setFileComment(getFileComment()); } /** * get a cell file projecting to supplied coord/topo for left and right hemispheres. */ void CellProjectionFile::getCellFileForRightLeftFiducials(const CoordinateFile* leftCF, const TopologyFile* leftTF, const CoordinateFile* rightCF, const TopologyFile* rightTF, const CoordinateFile* cerebellumCF, const TopologyFile* cerebellumTF, CellFile& cellFileOut) const { cellFileOut.clear(); const int num = getNumberOfCellProjections(); for (int i = 0; i < num; i++) { const CellProjection* cp = getCellProjection(i); float xyz[3] = { 0.0, 0.0, 0.0 }; switch (cp->getCellStructure()) { case Structure::STRUCTURE_TYPE_CORTEX_LEFT_OR_CEREBELLUM: case Structure::STRUCTURE_TYPE_CORTEX_LEFT: if (leftCF != NULL) { cp->getProjectedPosition(leftCF, leftTF, true, false, false, xyz); } break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT: case Structure::STRUCTURE_TYPE_CORTEX_RIGHT_OR_CEREBELLUM: if (rightCF != NULL) { cp->getProjectedPosition(rightCF, rightTF, true, false, false, xyz); } break; case Structure::STRUCTURE_TYPE_CEREBRUM_CEREBELLUM: case Structure::STRUCTURE_TYPE_CORTEX_BOTH: break; case Structure::STRUCTURE_TYPE_CEREBELLUM: case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_LEFT: case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_RIGHT: if (cerebellumCF != NULL) { cp->getProjectedPosition(cerebellumCF, cerebellumTF, true, false, false, xyz); } break; case Structure::STRUCTURE_TYPE_SUBCORTICAL: case Structure::STRUCTURE_TYPE_ALL: case Structure::STRUCTURE_TYPE_INVALID: break; } CellData cd; cd.copyData(*cp); cd.setXYZ(xyz); cellFileOut.addCell(cd); } const int numStudyInfo = getNumberOfStudyInfo(); for (int i = 0; i < numStudyInfo; i++) { cellFileOut.addStudyInfo(*getStudyInfo(i)); } cellFileOut.setFileComment(getFileComment()); } /** * get first cell projection with specified name (const method) */ const CellProjection* CellProjectionFile::getFirstCellProjectionWithName(const QString& name) const { const int numCellProj = getNumberOfCellProjections(); for (int i = 0; i < numCellProj; i++) { const CellProjection* cp = getCellProjection(i); if (cp->getName() == name) { return cp; } } return NULL; } /** * get first cell projection with specified name. */ CellProjection* CellProjectionFile::getFirstCellProjectionWithName(const QString& name) { const int numCellProj = getNumberOfCellProjections(); for (int i = 0; i < numCellProj; i++) { CellProjection* cp = getCellProjection(i); if (cp->getName() == name) { return cp; } } return NULL; } /** * get last cell projection with specified name. */ CellProjection* CellProjectionFile::getLastCellProjectionWithName(const QString& name) { const int numCellProj = getNumberOfCellProjections(); for (int i = (numCellProj - 1); i >= 0; i--) { CellProjection* cp = getCellProjection(i); if (cp->getName() == name) { return cp; } } return NULL; } /** * get last cell projection with specified name (const method). */ const CellProjection* CellProjectionFile::getLastCellProjectionWithName(const QString& name) const { const int numCellProj = getNumberOfCellProjections(); for (int i = (numCellProj - 1); i >= 0; i--) { const CellProjection* cp = getCellProjection(i); if (cp->getName() == name) { return cp; } } return NULL; } /** * get a cell file projecting to supplied coord/topo. */ void CellProjectionFile::getCellFile(const CoordinateFile* cf, const TopologyFile* tf, const bool fiducialSurfaceFlag, CellFile& cellFileOut) const { cellFileOut.clear(); const int num = getNumberOfCellProjections(); for (int i = 0; i < num; i++) { const CellProjection* cp = getCellProjection(i); float xyz[3]; cp->getProjectedPosition(cf, tf, fiducialSurfaceFlag, false, false, xyz); CellData cd; cd.copyData(*cp); cd.setXYZ(xyz); cellFileOut.addCell(cd); } const int numStudyInfo = getNumberOfStudyInfo(); for (int i = 0; i < numStudyInfo; i++) { cellFileOut.addStudyInfo(*getStudyInfo(i)); } cellFileOut.setFileComment(getFileComment()); } /** * Append a cell projection file to this cell projection file. */ void CellProjectionFile::append(const CellProjectionFile& cpf) { const int numCellProjections = cpf.getNumberOfCellProjections(); const int origNumberOfStudyInfo = getNumberOfStudyInfo(); // // Transfer the cell projections // for (int i = 0; i < numCellProjections; i++) { CellProjection cp = *(cpf.getCellProjection(i)); // // Update study info indexes // if (cp.studyNumber >= 0) { cp.studyNumber += origNumberOfStudyInfo; } addCellProjection(cp); } // // Transfer the study info // for (int j = 0; j < cpf.getNumberOfStudyInfo(); j++) { addStudyInfo((*cpf.getStudyInfo(j))); } // // transfer the file's comment // appendFileComment(cpf); } /** * Apply a transformation matrix to the cells. */ /* void CellProjectionFile::applyTransformationMatrix(const int sectionLow, const int sectionHigh, const float matrix[16], const bool onlySpecialCells) { const int num = getNumberOfCellProjections(); for (int i = 0; i < num; i++) { if ((cellProjections[i].sectionNumber >= sectionLow) && (cellProjections[i].sectionNumber <= sectionHigh)) { bool transformIt = true; if (onlySpecialCells && (cellProjections[i].specialFlag == false)) { transformIt = false; } if (transformIt) { const float x = cellProjections[i].xyz[0]; const float y = cellProjections[i].xyz[1]; const float z = cellProjections[i].xyz[2]; cellProjections[i].xyz[0] = x*matrix[0] + y*matrix[4] + z*matrix[8] + matrix[12]; cellProjections[i].xyz[1] = x*matrix[1] + y*matrix[5] + z*matrix[9] + matrix[13]; cellProjections[i].xyz[2] = x*matrix[2] + y*matrix[6] + z*matrix[10] + matrix[14]; } } } setModified(); } */ /** * apply a transformation matrix to the cells. */ /* void CellProjectionFile::applyTransformationMatrix(const TransformationMatrix& matrix, const bool onlySpecialCells) { applyTransformationMatrix(std::numeric_limits::min(), std::numeric_limits::max(), matrix, onlySpecialCells); } */ /** * Apply a transformation matrix to the cells. */ void CellProjectionFile::applyTransformationMatrix(const CoordinateFile* cf, const TopologyFile* tf, const bool fiducialSurfaceFlag, const int sectionLow, const int sectionHigh, const TransformationMatrix& matrixIn, const bool onlySpecialCells) { TransformationMatrix& matrix = const_cast(matrixIn); const int num = getNumberOfCellProjections(); for (int i = 0; i < num; i++) { CellProjection* cp = getCellProjection(i); if ((cp->sectionNumber >= sectionLow) && (cp->sectionNumber <= sectionHigh)) { bool transformIt = true; if (onlySpecialCells && (cp->specialFlag == false)) { transformIt = false; } if (transformIt) { float xyz[3] = { 0.0, 0.0, 0.0 }; if (cp->getProjectedPosition(cf, tf, fiducialSurfaceFlag, false, false, xyz)) { matrix.multiplyPoint(xyz); } cp->setXYZ(xyz); cp->projectionType = CellProjection::PROJECTION_TYPE_UNKNOWN; } } } setModified(); } /** * Add a cell projection to the file. */ void CellProjectionFile::addCellProjection(const CellProjection& cp) { cellProjections.push_back(cp); const int indx = getNumberOfCellProjections() - 1; cellProjections[indx].cellProjectionFile = this; cellProjections[indx].classIndex = addCellClass(cp.className); cellProjections[indx].uniqueNameIndex = addCellUniqueName(cp.name); setModified(); } /** * Add a cell class (if class already exists its selection status * is set to true). */ int CellProjectionFile::addCellClass(const QString& className) { if (className.isEmpty()) { return -1; } const int index = getCellClassIndexByName(className); if (index >= 0) { cellClasses[index].selected = true; return index; } cellClasses.push_back(CellClass(className)); return (getNumberOfCellClasses() - 1); } /** * Clear all of the cell's special flags. */ void CellProjectionFile::clearAllSpecialFlags() { const int numCells = getNumberOfCellProjections(); for (int i = 0; i < numCells; i++) { cellProjections[i].specialFlag = false; } } /** * clear all highlight flags */ void CellProjectionFile::clearAllHighlightFlags() { const int numCells = getNumberOfCellProjections(); for (int i = 0; i < numCells; i++) { cellProjections[i].highlightFlag = false; } } /** * get cell class indices sorted by name case insensitive. */ void CellProjectionFile::getCellClassIndicesSortedByName(std::vector& indicesSortedByNameOut, const bool reverseOrderFlag, const bool limitToDisplayedCellsFlag) const { NameIndexSort nis; if (limitToDisplayedCellsFlag) { std::vector displayedCellIndices; getIndicesOfDisplayedCells(displayedCellIndices); std::set classNames; const int numDisplayedCells = static_cast(displayedCellIndices.size()); for (int i = 0; i < numDisplayedCells; i++) { const int indx = displayedCellIndices[i]; classNames.insert(getCellProjection(indx)->getClassName()); } for (std::set::const_iterator iter = classNames.begin(); iter != classNames.end(); iter++) { const QString s(*iter); const int indx = getCellClassIndexByName(s); if (indx >= 0) { nis.add(indx, s); } } } else { const int num = getNumberOfCellClasses(); for (int i = 0; i < num; i++) { nis.add(i, cellClasses[i].name); } } nis.sortByNameCaseInsensitive(); const int num = nis.getNumberOfItems(); indicesSortedByNameOut.resize(num, 0); for (int i = 0; i < num; i++) { indicesSortedByNameOut[i] = nis.getSortedIndex(i); } if (reverseOrderFlag) { std::reverse(indicesSortedByNameOut.begin(), indicesSortedByNameOut.end()); } } /** * get cell class selected by index. */ bool CellProjectionFile::getCellClassSelectedByIndex(const int indx) const { if ((indx >= 0) && (indx < getNumberOfCellClasses())) { return cellClasses[indx].selected; } // // If no class, just enable it for display // return true; } /** * Set cell class selected by index. */ void CellProjectionFile::setCellClassSelectedByIndex(const int index, const bool sel) { if (index < getNumberOfCellClasses()) { cellClasses[index].selected = sel; } } /** * Get a class index from its name */ int CellProjectionFile::getCellClassIndexByName(const QString& name) const { const int numClasses = getNumberOfCellClasses(); for (int i = 0; i < numClasses; i++) { if (name == cellClasses[i].name) { return i; } } return -1; } /** * get cell class selected by name. */ bool CellProjectionFile::getCellClassSelectedByName(const QString& name) const { if (name.isEmpty()) { return false; } const int index = getCellClassIndexByName(name); if (index >= 0) { return cellClasses[index].selected; } return false; } /** * get cell class name. */ QString CellProjectionFile::getCellClassNameByIndex(const int index) const { if (index < getNumberOfCellClasses()) { return cellClasses[index].name; } return ""; //"???"; } /** * set the status of all cell classes. */ void CellProjectionFile::setAllCellClassStatus(const bool selected) { const int numClasses = getNumberOfCellClasses(); for (int i = 0; i < numClasses; i++) { cellClasses[i].selected = selected; } } /** * set the search status of all cells. */ void CellProjectionFile::setAllSearchStatus(const bool inSearchFlag) { const int numCells = getNumberOfCellProjections(); for (int i = 0; i < numCells; i++) { cellProjections[i].inSearchFlag = inSearchFlag; } } /** * update cell class if linked to table subheader. */ void CellProjectionFile::updateCellClassWithLinkedStudyTableSubheaderShortNames(const StudyMetaDataFile* smdf) { const int numStudyMetaData = smdf->getNumberOfStudyMetaData(); for (int i = 0; i < numStudyMetaData; i++) { const StudyMetaData* smd = smdf->getStudyMetaData(i); const QString pmid = smd->getPubMedID(); if (pmid.isEmpty() == false) { const int numTables = smd->getNumberOfTables(); for (int j = 0; j < numTables; j++) { const StudyMetaData::Table* table = smd->getTable(j); const QString tableNumber = table->getNumber(); if (tableNumber.isEmpty() == false) { const int numSubHeaders = table->getNumberOfSubHeaders(); for (int k = 0; k < numSubHeaders; k++) { const StudyMetaData::SubHeader* sh = table->getSubHeader(k); const QString subHeaderNumber = sh->getNumber(); if (subHeaderNumber.isEmpty() == false) { const QString shortName = sh->getShortName(); if (shortName.isEmpty() == false) { StudyMetaDataLink smdl; smdl.setPubMedID(pmid); smdl.setTableSubHeaderNumber(subHeaderNumber); smdl.setTableNumber(tableNumber); transferTableSubHeaderShortNameToCellClass(smdl, shortName); } } } } } } } } /** * update cell class with linked tabel subheader name, linked figure panel task * description, or page reference subheader short name. */ void CellProjectionFile::updateCellClassWithLinkedTableFigureOrPageReference(const StudyMetaDataFile* smdf) { const int numCells = getNumberOfCellProjections(); for (int i = 0; i < numCells; i++) { CellProjection* cp = getCellProjection(i); const StudyMetaDataLinkSet cellSMDLS = cp->getStudyMetaDataLinkSet(); const int numSMDL = cellSMDLS.getNumberOfStudyMetaDataLinks(); for (int j = 0; j < numSMDL; j++) { const StudyMetaDataLink cellSMDL = cellSMDLS.getStudyMetaDataLink(j); const int studyIndex = smdf->getStudyIndexFromLink(cellSMDL); if (studyIndex >= 0) { const StudyMetaData* smd = smdf->getStudyMetaData(studyIndex); const QString figNum = cellSMDL.getFigureNumber(); const QString pageRefNum = cellSMDL.getPageReferencePageNumber(); const QString tableNum = cellSMDL.getTableNumber(); if (figNum.isEmpty() == false) { const StudyMetaData::Figure* figure = smd->getFigureByFigureNumber(figNum); if (figure != NULL) { const StudyMetaData::Figure::Panel* panel = figure->getPanelByPanelNumberOrLetter(cellSMDL.getFigurePanelNumberOrLetter()); if (panel != NULL) { const QString txt = panel->getTaskDescription(); if (txt.isEmpty() == false) { cp->setClassName(txt); } } } } if (pageRefNum.isEmpty() == false) { const StudyMetaData::PageReference* pageRef = smd->getPageReferenceByPageNumber(pageRefNum); if (pageRef != NULL) { const StudyMetaData::SubHeader* subHeader = pageRef->getSubHeaderBySubHeaderNumber(cellSMDL.getPageReferenceSubHeaderNumber()); if (subHeader != NULL) { const QString txt = subHeader->getShortName(); if (txt.isEmpty() == false) { cp->setClassName(txt); } } } } if (tableNum.isEmpty() == false) { const StudyMetaData::Table* table = smd->getTableByTableNumber(tableNum); if (table != NULL) { const StudyMetaData::SubHeader* subHeader = table->getSubHeaderBySubHeaderNumber(cellSMDL.getTableSubHeaderNumber()); if (subHeader != NULL) { const QString txt = subHeader->getShortName(); if (txt.isEmpty() == false) { cp->setClassName(txt); } } } } } } } } /** * transfer table subheader short name to cell classes. */ void CellProjectionFile::transferTableSubHeaderShortNameToCellClass(const StudyMetaDataLink& smdl, const QString& shortName) { const int numCells = getNumberOfCellProjections(); for (int i = 0; i < numCells; i++) { CellProjection* cp = getCellProjection(i); const StudyMetaDataLinkSet cellSMDLS = cp->getStudyMetaDataLinkSet(); const int numSMDL = cellSMDLS.getNumberOfStudyMetaDataLinks(); for (int j = 0; j < numSMDL; j++) { const StudyMetaDataLink cellSMDL = cellSMDLS.getStudyMetaDataLink(j); if ((smdl.getPubMedID() == cellSMDL.getPubMedID()) && (smdl.getTableNumber() == cellSMDL.getTableNumber()) && (smdl.getTableSubHeaderNumber() == cellSMDL.getTableSubHeaderNumber())) { cp->setClassName(shortName); } } } } /** * Add a cell unique name. */ int CellProjectionFile::addCellUniqueName(const QString& uniqueName) { if (uniqueName.isEmpty()) { return -1; } const int index = getCellUniqueNameIndexByName(uniqueName); if (index >= 0) { cellUniqueNames[index].selected = true; return index; } cellUniqueNames.push_back(CellClass(uniqueName)); return (getNumberOfCellUniqueNames() - 1); } /** * get indices of displayed cell projections. */ void CellProjectionFile::getIndicesOfDisplayedCells(std::vector& indicesOut) const { indicesOut.clear(); const int numCells = getNumberOfCellProjections(); for (int i = 0; i < numCells; i++) { if (getCellProjection(i)->getDisplayFlag()) { indicesOut.push_back(i); } } } /** * get cell unique name indices sorted by name case insensitive. */ void CellProjectionFile::getCellUniqueNameIndicesSortedByName(std::vector& indicesSortedByNameOut, const bool reverseOrderFlag, const bool limitToDisplayedCellsFlag) const { NameIndexSort nis; if (limitToDisplayedCellsFlag) { std::vector displayedCellIndices; getIndicesOfDisplayedCells(displayedCellIndices); std::set names; const int numDisplayedCells = static_cast(displayedCellIndices.size()); for (int i = 0; i < numDisplayedCells; i++) { const int indx = displayedCellIndices[i]; names.insert(getCellProjection(indx)->getName()); } for (std::set::const_iterator iter = names.begin(); iter != names.end(); iter++) { const QString s(*iter); const int indx = getCellUniqueNameIndexByName(s); if (indx >= 0) { nis.add(indx, s); } } } else { const int numUN = getNumberOfCellUniqueNames(); for (int i = 0; i < numUN; i++) { nis.add(i, getCellUniqueNameByIndex(i)); } } nis.sortByNameCaseInsensitive(); const int numUniqueNames = nis.getNumberOfItems(); indicesSortedByNameOut.resize(numUniqueNames, 0); for (int i = 0; i < numUniqueNames; i++) { indicesSortedByNameOut[i] = nis.getSortedIndex(i); } if (reverseOrderFlag) { std::reverse(indicesSortedByNameOut.begin(), indicesSortedByNameOut.end()); } } /** * get cell unique name index by its name. */ int CellProjectionFile::getCellUniqueNameIndexByName(const QString& name) const { const int numNames = getNumberOfCellUniqueNames(); for (int i = 0; i < numNames; i++) { if (name == cellUniqueNames[i].name) { return i; } } return -1; } /** * get cell unique name selected by index. */ bool CellProjectionFile::getCellUniqueNameSelectedByIndex(const int indx) const { if ((indx >= 0) && (indx < getNumberOfCellUniqueNames())) { return cellUniqueNames[indx].selected; } // // If no unique name, just enable it for display // return true; } /** * set cell unique name selected by index. */ void CellProjectionFile::setCellUniqueNameSelectedByIndex(const int index, const bool sel) { if (index < getNumberOfCellUniqueNames()) { cellUniqueNames[index].selected = sel; } } /** * get cell unique name selected by name. */ bool CellProjectionFile::getCellUniqueNameSelectedByName(const QString& name) const { if (name.isEmpty()) { return false; } const int index = getCellUniqueNameIndexByName(name); if (index >= 0) { return cellUniqueNames[index].selected; } return false; } /** * get cell unique name name. */ QString CellProjectionFile::getCellUniqueNameByIndex(const int index) const { if (index < getNumberOfCellUniqueNames()) { return cellUniqueNames[index].name; } return ""; //"???"; } /** * set the status of all cell unique names. */ void CellProjectionFile::setAllCellUniqueNameStatus(const bool selected) { const int numUniqueNames = getNumberOfCellUniqueNames(); for (int i = 0; i < numUniqueNames; i++) { cellUniqueNames[i].selected = selected; } } /** * get all cell areas. */ void CellProjectionFile::getAllCellAreas(std::vector& allAreasOut) const { allAreasOut.clear(); std::set areaSet; const int num = getNumberOfCellProjections(); for (int i = 0; i < num; i++) { const CellProjection* cp = getCellProjection(i); const QString s = cp->getArea(); if (s.isEmpty() == false) { const QStringList sl = s.split(';', QString::SkipEmptyParts); for (int k = 0; k < sl.size(); k++) { const QString area = sl.at(k).trimmed(); if (area.isEmpty() == false) { areaSet.insert(area); } } } } allAreasOut.insert(allAreasOut.end(), areaSet.begin(), areaSet.end()); } /** * get all cell geography. */ void CellProjectionFile::getAllCellGeography(std::vector& allGeographyOut) const { allGeographyOut.clear(); std::set geographySet; const int num = getNumberOfCellProjections(); for (int i = 0; i < num; i++) { const CellProjection* cp = getCellProjection(i); const QString s = cp->getGeography(); if (s.isEmpty() == false) { const QStringList sl = s.split(';', QString::SkipEmptyParts); for (int k = 0; k < sl.size(); k++) { const QString geography = sl.at(k).trimmed(); if (geography.isEmpty() == false) { geographySet.insert(geography); } } } } allGeographyOut.insert(allGeographyOut.end(), geographySet.begin(), geographySet.end()); } /** * get all comments. */ void CellProjectionFile::getAllCellComments(std::vector& allCommentsOut) const { allCommentsOut.clear(); std::set commentSet; const int num = getNumberOfCellProjections(); for (int i = 0; i < num; i++) { const CellProjection* cp = getCellProjection(i); const QString s = cp->getComment(); if (s.isEmpty() == false) { const QStringList sl = s.split(';', QString::SkipEmptyParts); for (int k = 0; k < sl.size(); k++) { const QString comment = sl.at(k).trimmed(); if (comment.isEmpty() == false) { commentSet.insert(comment); } } } } allCommentsOut.insert(allCommentsOut.end(), commentSet.begin(), commentSet.end()); } /** * get all cell regions of interest. */ void CellProjectionFile::getAllCellRegionsOfInterest(std::vector& allRegionsOfInterestOut) const { allRegionsOfInterestOut.clear(); std::set regionsOfInterestSet; const int num = getNumberOfCellProjections(); for (int i = 0; i < num; i++) { const CellProjection* cp = getCellProjection(i); const QString s = cp->getRegionOfInterest(); if (s.isEmpty() == false) { const QStringList sl = s.split(';', QString::SkipEmptyParts); for (int k = 0; k < sl.size(); k++) { const QString regionsOfInterest = sl.at(k).trimmed(); if (regionsOfInterest.isEmpty() == false) { regionsOfInterestSet.insert(regionsOfInterest); } } } } allRegionsOfInterestOut.insert(allRegionsOfInterestOut.end(), regionsOfInterestSet.begin(), regionsOfInterestSet.end()); } /** * set the special flag for all cells in the section range and box */ void CellProjectionFile::setSpecialFlags(const int sectionLow, const int sectionHigh, const float bounds[4]) { const int num = getNumberOfCellProjections(); const float minX = std::min(bounds[0], bounds[2]); const float maxX = std::max(bounds[0], bounds[2]); const float minY = std::min(bounds[1], bounds[3]); const float maxY = std::max(bounds[1], bounds[3]); for (int i = 0; i < num; i++) { if ((cellProjections[i].sectionNumber >= sectionLow) && (cellProjections[i].sectionNumber <= sectionHigh)) { const float x = cellProjections[i].xyz[0]; const float y = cellProjections[i].xyz[1]; if ((x >= minX) && (x <= maxX) && (y >= minY) && (y <= maxY)) { cellProjections[i].specialFlag = true; } } } } /** * Assign colors to these cells. */ void CellProjectionFile::assignColors(ColorFile& colorFile, const CellBase::CELL_COLOR_MODE colorMode) { const int numCellProjections = getNumberOfCellProjections(); for (int i = 0; i < numCellProjections; i++) { CellProjection* cp = getCellProjection(i); bool match; switch (colorMode) { case CellBase::CELL_COLOR_MODE_NAME: cp->setColorIndex(colorFile.getColorIndexByName(cp->getName(), match)); break; case CellBase::CELL_COLOR_MODE_CLASS: cp->setColorIndex(colorFile.getColorIndexByName(cp->getClassName(), match)); break; } } } /** * Clear the cell projection file. */ void CellProjectionFile::clear() { clearAbstractFile(); cellProjections.clear(); studyInfo.clear(); cellClasses.clear(); cellUniqueNames.clear(); versionNumber = -1; } /** * delete cell projections with name. */ void CellProjectionFile::deleteCellProjectionsWithName(const QString& name) { const int num = getNumberOfCellProjections(); for (int i = (num - 1); i >= 0; i--) { CellProjection* cp = getCellProjection(i); if (cp->getName() == name) { deleteCellProjection(i); } } } /** * delete all duplicate cell projections. */ void CellProjectionFile::deleteAllDuplicateCellProjections() { const int num = getNumberOfCellProjections(); for (int i = (num - 1); i >= 0; i--) { CellProjection* cp = getCellProjection(i); if (cp->getDuplicateFlag()) { deleteCellProjection(i); } } } /** * Delete the cell projection at the specified index */ void CellProjectionFile::deleteCellProjection(const int index) { if (index < getNumberOfCellProjections()) { cellProjections.erase(cellProjections.begin() + index); setModified(); } } /** * assign class to all displayed foci. */ void CellProjectionFile::assignClassToDisplayedFoci(const QString& className) { // // Loop through the cell projections and add them to "this" file // const int num = getNumberOfCellProjections(); for (int i = 0; i < num; i++) { // // Get the cell projection // CellProjection* cp = getCellProjection(i); // // Is this cell projection displayed // if (cp->getDisplayFlag()) { // // Set its class // cp->setClassName(className); } } } /** * delete cell projections whose indices are not specified. */ void CellProjectionFile::deleteAllButTheseCellProjections(const int* indices, const int numIndices) { if ((getNumberOfCellProjections() <= 0) || (numIndices <= 0)) { return; } // // Place indices of cells that are to be kept into a sorted vector // std::vector cellIndicesToKeep; for (int i = 0; i < numIndices; i++) { cellIndicesToKeep.push_back(indices[i]); } std::sort(cellIndicesToKeep.begin(), cellIndicesToKeep.end()); // // Copy this cell projection file // CellProjectionFile cpf = *this; // // Clear out "this" file's data // cellProjections.clear(); studyInfo.clear(); cellClasses.clear(); cellUniqueNames.clear(); // // Keep track of which study info are needed // const int numStudyInfo = cpf.getNumberOfStudyInfo(); std::vector studyInfoTransferIndex; if (numStudyInfo > 0) { studyInfoTransferIndex.resize(numStudyInfo, -1); } // // Loop through the cell projections and add them to "this" file // for (int i = 0; i < static_cast(cellIndicesToKeep.size()); i++) { // // Copy the cell projection // CellProjection cp = *(cpf.getCellProjection(cellIndicesToKeep[i])); // // See if the study info is used // const int studyInfoIndex = cp.getStudyNumber(); if ((studyInfoIndex >= 0) && (studyInfoIndex < numStudyInfo)) { // // study info has not been transferred // if (studyInfoTransferIndex[studyInfoIndex] < 0) { // // add the study info to "this" file and keep track of its new index // studyInfoTransferIndex[studyInfoIndex] = addStudyInfo(*(cpf.getStudyInfo(studyInfoIndex))); } // // Set the index for the study info // cp.setStudyNumber(studyInfoTransferIndex[studyInfoIndex]); } // // Add the cell projection to "this" file // addCellProjection(cp); } } /** * delete all cell projections whose display flag is false. */ void CellProjectionFile::deleteAllNonDisplayedCellProjections(const Structure& keepThisStructureOnly) { std::vector indicesToKeep; // // find cell projections that are to be kept // const int num = getNumberOfCellProjections(); for (int i = 0; i < num; i++) { // // Copy the cell projection // const CellProjection* cp = getCellProjection(i); // // Is this cell projection displayed // if (cp->getDisplayFlag()) { bool isLeftCellFlag = false; bool isRightCellFlag = false; bool isCerebellumCellFlag = false; switch (cp->getCellStructure()) { case Structure::STRUCTURE_TYPE_CORTEX_LEFT: isLeftCellFlag = true; break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT: isRightCellFlag = true; break; case Structure::STRUCTURE_TYPE_CORTEX_BOTH: isCerebellumCellFlag = true; break; case Structure::STRUCTURE_TYPE_CEREBELLUM: isCerebellumCellFlag = true; break; case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_LEFT: isCerebellumCellFlag = true; break; case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_RIGHT: isCerebellumCellFlag = true; break; case Structure::STRUCTURE_TYPE_CORTEX_LEFT_OR_CEREBELLUM: isLeftCellFlag = true; break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT_OR_CEREBELLUM: isRightCellFlag = true; break; case Structure::STRUCTURE_TYPE_CEREBRUM_CEREBELLUM: break; case Structure::STRUCTURE_TYPE_SUBCORTICAL: break; case Structure::STRUCTURE_TYPE_ALL: break; case Structure::STRUCTURE_TYPE_INVALID: break; } // // Limit to a specific structure // switch (keepThisStructureOnly.getType()) { case Structure::STRUCTURE_TYPE_CORTEX_LEFT: if (isLeftCellFlag == false) { continue; } break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT: if (isRightCellFlag == false) { continue; } break; case Structure::STRUCTURE_TYPE_CORTEX_BOTH: case Structure::STRUCTURE_TYPE_CEREBELLUM: if (isCerebellumCellFlag == false) { continue; } break; case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_LEFT: case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_RIGHT: case Structure::STRUCTURE_TYPE_CORTEX_LEFT_OR_CEREBELLUM: case Structure::STRUCTURE_TYPE_CORTEX_RIGHT_OR_CEREBELLUM: case Structure::STRUCTURE_TYPE_CEREBRUM_CEREBELLUM: case Structure::STRUCTURE_TYPE_SUBCORTICAL: case Structure::STRUCTURE_TYPE_ALL: case Structure::STRUCTURE_TYPE_INVALID: break; } /* isdff (keepThisStructureOnly.isLeftCortex() || keepThisStructureOnly.isRightCortex()) { if (cp->getCellStructure() != keepThisStructureOnly.getType()) { continue; } } */ // // Keep this one // indicesToKeep.push_back(i); } } const int numToKeep = static_cast(indicesToKeep.size()); if (numToKeep > 0) { deleteAllButTheseCellProjections(&indicesToKeep[0], numToKeep); } /* if (getNumberOfCellProjections() <= 0) { return; } // // Copy this cell projection file // CellProjectionFile cpf = *this; // // Clear out "this" file's data // cellProjections.clear(); studyInfo.clear(); cellClasses.clear(); cellUniqueNames.clear(); // // Keep track of which study info are needed // const int numStudyInfo = cpf.getNumberOfStudyInfo(); std::vector studyInfoTransferIndex; if (numStudyInfo > 0) { studyInfoTransferIndex.resize(numStudyInfo, -1); } // // Loop through the cell projections and add them to "this" file // const int num = cpf.getNumberOfCellProjections(); for (int i = 0; i < num; i++) { // // Copy the cell projection // CellProjection cp = *(cpf.getCellProjection(i)); // // Is this cell projection displayed // if (cp.getDisplayFlag()) { // // Limit to a specific structure // if (keepThisStructureOnly.isLeftCortex() || keepThisStructureOnly.isRightCortex()) { if (cp.getCellStructure() != keepThisStructureOnly.getType()) { continue; } } // // See if the study info is used // const int studyInfoIndex = cp.getStudyNumber(); if ((studyInfoIndex >= 0) && (studyInfoIndex < numStudyInfo)) { // // study info has not been transferred // if (studyInfoTransferIndex[studyInfoIndex] < 0) { // // add the study info to "this" file and keep track of its new index // studyInfoTransferIndex[studyInfoIndex] = addStudyInfo(*(cpf.getStudyInfo(studyInfoIndex))); } // // Set the index for the study info // cp.setStudyNumber(studyInfoTransferIndex[studyInfoIndex]); } // // Add the cell projection to "this" file // addCellProjection(cp); } } */ } /** * Get the study info index based upon the study info's value. */ int CellProjectionFile::getStudyInfoFromValue(const CellStudyInfo& csi) const { const int num = getNumberOfStudyInfo(); for (int i = 0; i < num; i++) { if ((*getStudyInfo(i)) == csi) { return i; } } return -1; } /** * Get a study info (const method). */ const CellStudyInfo* CellProjectionFile::getStudyInfo(const int indx) const { if ((indx >= 0) && (indx < getNumberOfStudyInfo())) { return &studyInfo[indx]; } return NULL; } /** * Get a study info. */ CellStudyInfo* CellProjectionFile::getStudyInfo(const int indx) { if ((indx >= 0) && (indx < getNumberOfStudyInfo())) { return &studyInfo[indx]; } return NULL; } /** * Add a study info. */ int CellProjectionFile::addStudyInfo(const CellStudyInfo& csi) { studyInfo.push_back(csi); const int index = studyInfo.size() - 1; return index; } /** * delete all study info and clear links to study info */ void CellProjectionFile::deleteAllStudyInfo() { const int num = getNumberOfCellProjections(); for (int i = 0; i < num; i++) { CellProjection* cp = getCellProjection(i); cp->setStudyNumber(-1); } studyInfo.clear(); } /** * delete study info. */ void CellProjectionFile::deleteStudyInfo(const int indx) { if ((indx >= 0) && (indx < getNumberOfStudyInfo())) { for (int i = 0; i < getNumberOfCellProjections(); i++) { const int studyNum = cellProjections[i].getStudyNumber(); if (studyNum == indx) { cellProjections[i].setStudyNumber(-1); } else if (studyNum > indx) { cellProjections[i].setStudyNumber(studyNum - 1); } } studyInfo.erase(studyInfo.begin() + indx); } } /** * Set a study info. */ void CellProjectionFile::setStudyInfo(const int index, const CellStudyInfo& csi) { studyInfo[index] = csi; } /** * get indices to all linked studies. */ void CellProjectionFile::getPubMedIDsOfAllLinkedStudyMetaData(std::vector& studyPMIDs, const bool displayedFociOnlyFlag) const { std::set pmidSet; const int numCells = getNumberOfCellProjections(); for (int i = 0; i < numCells; i++) { const CellProjection* cp = getCellProjection(i); bool useIt = true; if (displayedFociOnlyFlag) { useIt = cp->getDisplayFlag(); } if (useIt) { const StudyMetaDataLinkSet smdl = cp->getStudyMetaDataLinkSet(); std::vector pmids; smdl.getAllLinkedPubMedIDs(pmids); pmidSet.insert(pmids.begin(), pmids.end()); } } studyPMIDs.clear(); studyPMIDs.insert(studyPMIDs.end(), pmidSet.begin(), pmidSet.end()); } /** * update cell name with linked study name. */ void CellProjectionFile::updateCellNameWithStudyNameForMatchingPubMedIDs(const StudyMetaDataFile* smdf) { const int numCells = getNumberOfCellProjections(); for (int i = 0; i < numCells; i++) { CellProjection* cp = getCellProjection(i); // // Get the links // StudyMetaDataLinkSet smdls = cp->getStudyMetaDataLinkSet(); // // Loop through the cell's links // for (int m = 0; m < smdls.getNumberOfStudyMetaDataLinks(); m++) { // // Get a link // StudyMetaDataLink smdl = smdls.getStudyMetaDataLink(m); // // Get cell PubMed ID and see if there is a study with the same PubMedID // const QString cellPubMedID = smdl.getPubMedID(); int studyNum = smdf->getStudyIndexFromPubMedID(cellPubMedID); if (studyNum >= 0) { const StudyMetaData* smd = smdf->getStudyMetaData(studyNum); if (smd != NULL) { cp->setName(smd->getName()); break; } } } } } /** * update cell PubMed ID if cell name matches study name. */ void CellProjectionFile::updatePubMedIDIfCellNameMatchesStudyName(const StudyMetaDataFile* smdf) { const int numCells = getNumberOfCellProjections(); const int numStudies = smdf->getNumberOfStudyMetaData(); for (int i = 0; i < numCells; i++) { CellProjection* cp = getCellProjection(i); const QString name = cp->getName().trimmed(); for (int j = 0; j < numStudies; j++) { const StudyMetaData* smd = smdf->getStudyMetaData(j); // // Does study name match cell name? // if (name == smd->getName().trimmed()) { // // Get the links // StudyMetaDataLinkSet smdls = cp->getStudyMetaDataLinkSet(); bool linkModified = false; // // If the focus has no links add a link // if (smdls.getNumberOfStudyMetaDataLinks() <= 0) { StudyMetaDataLink smdl; smdls.addStudyMetaDataLink(smdl); } // // Loop through the cell's links // for (int m = 0; m < smdls.getNumberOfStudyMetaDataLinks(); m++) { // // Get a link // StudyMetaDataLink smdl = smdls.getStudyMetaDataLink(m); // // Only update if PubMed ID is different // const QString studyPubMedID = smd->getPubMedID(); if (smdl.getPubMedID() != studyPubMedID) { // // Is the link to the study's Project ID? // if (smdl.getPubMedID() == smd->getProjectID()) { // // Do nothing // } else { // // Clear study to clear out links to figures and tables since different study // // 08/10/2007 smdl.clear(); } // // Update only the link's PubMed ID // smdl.setPubMedID(studyPubMedID); smdls.setStudyMetaDataLink(m, smdl); linkModified = true; } } if (linkModified) { cp->setStudyMetaDataLinkSet(smdls); } } } } } /** * find out if comma separated file conversion supported. */ void CellProjectionFile::getCommaSeparatedFileSupport(bool& readFromCSV, bool& writeToCSV) const { readFromCSV = true; writeToCSV = false; } /** * write the file's data into a comma separated values file (throws exception if not supported). */ void CellProjectionFile::writeDataIntoCommaSeparatedValueFile(CommaSeparatedValueFile& csv) throw (FileException) { csv.clear(); const int numCells = getNumberOfCellProjections(); if (numCells <= 0) { return; } // // Column numbers for data // int numCols = 0; const int cellNumberCol = numCols++; const int xCol = numCols++; const int yCol = numCols++; const int zCol = numCols++; const int sectionNumberCol = numCols++; const int nameCol = numCols++; const int studyNumberCol = numCols++; const int geographyCol = numCols++; const int areaCol = numCols++; const int sizeCol = numCols++; const int statisticCol = numCols++; const int commentCol = numCols++; const int structureCol = numCols++; const int classNameCol = numCols++; const int volumeXYZCol = numCols++; const int duplicateFlagCol = numCols++; const int studyMetaPubMedCol = numCols++; const int studyMetaTableCol = numCols++; const int studyMetaTableSubHeaderCol = numCols++; const int studyMetaFigureCol = numCols++; const int studyMetaFigurePanelCol = numCols++; //const int studyMetaPageNumberCol = numCols++; // new stuff const int signedDistCol = numCols++; const int projTypeCol = numCols++; const int closestTileVerticesCol = numCols++; const int closestTileAreaCol = numCols++; const int cDistanceCol = numCols++; const int drCol = numCols++; const int triFiducialCol = numCols++; const int thetaRCol = numCols++; const int phiRCol = numCols++; const int triVerticesCol = numCols++; const int vertexCol = numCols++; const int vertexFiducialCol = numCols++; const int posFiducialCol= numCols++; const int fracRICol = numCols++; const int fracRJCol = numCols++; // // Create and add to string table // StringTable* ct = new StringTable(numCells, numCols, "Cells"); ct->setColumnTitle(cellNumberCol, "Cell Number"); ct->setColumnTitle(xCol, "X"); ct->setColumnTitle(yCol, "Y"); ct->setColumnTitle(zCol, "Z"); ct->setColumnTitle(sectionNumberCol, "Section"); ct->setColumnTitle(nameCol, "Name"); ct->setColumnTitle(studyNumberCol, "Study Number"); ct->setColumnTitle(geographyCol, "Geography"); ct->setColumnTitle(areaCol, "Area"); ct->setColumnTitle(sizeCol, "Size"); ct->setColumnTitle(statisticCol, "Statistic"); ct->setColumnTitle(commentCol, "Comment"); ct->setColumnTitle(structureCol, "Structure"); ct->setColumnTitle(classNameCol, "Class Name"); ct->setColumnTitle(volumeXYZCol, "Volume XYZ"); ct->setColumnTitle(duplicateFlagCol, "Duplicate Flag"); ct->setColumnTitle(studyMetaPubMedCol, "Study PubMed ID"); ct->setColumnTitle(studyMetaTableCol, "Study Table Number"); ct->setColumnTitle(studyMetaTableSubHeaderCol, "Study Table Subheader"); ct->setColumnTitle(studyMetaFigureCol, "Study Figure Number"); ct->setColumnTitle(studyMetaFigurePanelCol, "Study Figure Panel"); //ct->setColumnTitle(studyMetaPageNumberCol, "Study Page Number"); ct->setColumnTitle(signedDistCol, "Signed Dist"); ct->setColumnTitle(projTypeCol, "Proj Type"); ct->setColumnTitle(closestTileVerticesCol, "Closest Tile Vert"); ct->setColumnTitle(closestTileAreaCol, "Closest Tile Areas"); ct->setColumnTitle(cDistanceCol, "C Distance"); ct->setColumnTitle(drCol, "dR"); ct->setColumnTitle(triFiducialCol, "Tri Fiducial"); ct->setColumnTitle(thetaRCol, "thetaR"); ct->setColumnTitle(phiRCol, "phiR"); ct->setColumnTitle(triVerticesCol, "Tri Vertices"); ct->setColumnTitle(vertexCol, "Vertex"); ct->setColumnTitle(vertexFiducialCol, "Vertex Fiducial"); ct->setColumnTitle(posFiducialCol, "Pos Fiducial"); ct->setColumnTitle(fracRICol, "fracRI"); ct->setColumnTitle(fracRJCol, "fracRJ"); for (int i = 0; i < numCells; i++) { const CellProjection* cd = getCellProjection(i); const float* xyz = cd->getXYZ(); ct->setElement(i, cellNumberCol, i); ct->setElement(i, xCol, xyz[0]); ct->setElement(i, yCol, xyz[1]); ct->setElement(i, zCol, xyz[2]); ct->setElement(i, sectionNumberCol, cd->getSectionNumber()); ct->setElement(i, nameCol, cd->getName()); ct->setElement(i, studyNumberCol, cd->getStudyNumber()); ct->setElement(i, geographyCol, cd->getGeography()); ct->setElement(i, areaCol, cd->getArea()); ct->setElement(i, sizeCol, cd->getSize()); ct->setElement(i, statisticCol, cd->getStatistic()); ct->setElement(i, commentCol, cd->getComment()); ct->setElement(i, structureCol, Structure::convertTypeToString(cd->getCellStructure())); ct->setElement(i, classNameCol, cd->getClassName()); ct->setElement(i, volumeXYZCol, (float*)cd->volumeXYZ, 3); if (cd->getDuplicateFlag()) { ct->setElement(i, duplicateFlagCol, "true"); } else { ct->setElement(i, duplicateFlagCol, "false"); } ct->setElement(i, signedDistCol, cd->getSignedDistanceAboveSurface()); switch (cd->projectionType) { case CellProjection::PROJECTION_TYPE_UNKNOWN: ct->setElement(i, projTypeCol, "UNKNOWN"); break; case CellProjection::PROJECTION_TYPE_INSIDE_TRIANGLE: ct->setElement(i, projTypeCol, "INSIDE"); break; case CellProjection::PROJECTION_TYPE_OUTSIDE_TRIANGLE: ct->setElement(i, projTypeCol, "OUTSIDE"); break; } ct->setElement(i, closestTileVerticesCol, (int*)(cd->closestTileVertices), 3); ct->setElement(i, closestTileAreaCol, cd->closestTileAreas, 3); ct->setElement(i, cDistanceCol, cd->cdistance, 3); ct->setElement(i, drCol, cd->dR); ct->setElement(i, triFiducialCol, (float*)cd->triFiducial, 2*3*3); ct->setElement(i, thetaRCol, cd->thetaR); ct->setElement(i, phiRCol, cd->phiR); ct->setElement(i, triVerticesCol, (int*)cd->triVertices, 2*3); ct->setElement(i, vertexCol, (int*)cd->vertex, 2); ct->setElement(i, vertexFiducialCol, (float*)cd->vertexFiducial, 6); ct->setElement(i, posFiducialCol, (float*)cd->posFiducial, 3); ct->setElement(i, fracRICol, cd->fracRI); ct->setElement(i, fracRJCol, cd->fracRJ); const StudyMetaDataLinkSet smdls = cd->getStudyMetaDataLinkSet(); StudyMetaDataLink smdl; if (smdls.getNumberOfStudyMetaDataLinks() > 1) { const QString msg("Cell[" + QString::number(i) + "] named \"" + cd->getName() + "\" has more than one Study Metadata Link so it " "cannot be written as a Comma Separated Value File"); throw FileException(msg); } else if (smdls.getNumberOfStudyMetaDataLinks() == 1) { smdl = smdls.getStudyMetaDataLink(0); } ct->setElement(i, studyMetaPubMedCol, smdl.getPubMedID()); ct->setElement(i, studyMetaTableCol, smdl.getTableNumber()); ct->setElement(i, studyMetaTableSubHeaderCol, smdl.getTableSubHeaderNumber()); ct->setElement(i, studyMetaFigureCol, smdl.getFigureNumber()); ct->setElement(i, studyMetaFigurePanelCol, smdl.getFigurePanelNumberOrLetter()); //ct->setElement(i, studyMetaPageNumberCol, smdl.getPageNumber()); } StringTable* headerTable = new StringTable(0, 0); writeHeaderDataIntoStringTable(*headerTable); csv.addDataSection(headerTable); csv.addDataSection(ct); StringTable* studyInfoTable = new StringTable(0, 0); CellStudyInfo::writeDataIntoStringTable(studyInfo, *studyInfoTable); csv.addDataSection(studyInfoTable); } /** * read the file's data from a comma separated values file (throws exception if not supported). */ void CellProjectionFile::readDataFromCommaSeparatedValuesTable(const CommaSeparatedValueFile& csv) throw (FileException) { clear(); const StringTable* ct = csv.getDataSectionByName("Cells"); if (ct == NULL) { throw FileException("No cells found"); } int numCols = ct->getNumberOfColumns(); int cellNumberCol = -1; int xCol = -1; int yCol = -1; int zCol = -1; int sectionNumberCol = -1; int nameCol = -1; int studyNumberCol = -1; int geographyCol = -1; int areaCol = -1; int sizeCol = -1; int statisticCol = -1; int commentCol = -1; int structureCol = -1; int classNameCol = -1; int volumeXYZCol = -1; int duplicateFlagCol = -1; int studyMetaPubMedCol = -1; int studyMetaTableCol = -1; int studyMetaTableSubHeaderCol = -1; int studyMetaFigureCol = -1; int studyMetaFigurePanelCol = -1; //int studyMetaPageNumberCol = -1; int signedDistCol = -1; int projTypeCol = -1; int closestTileVerticesCol = -1; int closestTileAreaCol = -1; int cDistanceCol = -1; int drCol = -1; int triFiducialCol = -1; int thetaRCol = -1; int phiRCol = -1; int triVerticesCol = -1; int vertexCol = -1; int vertexFiducialCol = -1; int posFiducialCol= -1; int fracRICol = -1; int fracRJCol = -1; for (int i = 0; i < numCols; i++) { const QString columnTitle = ct->getColumnTitle(i).toLower(); if (columnTitle == "cell number") { cellNumberCol = i; } else if (columnTitle == "x") { xCol = i; } else if (columnTitle == "y") { yCol = i; } else if (columnTitle == "z") { zCol = i; } else if (columnTitle == "section") { sectionNumberCol = i; } else if (columnTitle == "name") { nameCol = i; } else if (columnTitle == "study number") { studyNumberCol = i; } else if (columnTitle == "geography") { geographyCol = i; } else if (columnTitle == "area") { areaCol = i; } else if (columnTitle == "size") { sizeCol = i; } else if (columnTitle == "statistic") { statisticCol = i; } else if (columnTitle == "comment") { commentCol = i; } else if (columnTitle == "structure") { structureCol = i; } else if (columnTitle == "class name") { classNameCol = i; } else if (columnTitle == "volume xyz") { volumeXYZCol = i; } else if (columnTitle == "duplicate flag") { duplicateFlagCol = i; } else if (columnTitle == "signed dist") { signedDistCol = i; } else if (columnTitle == "proj type") { projTypeCol = i; } else if (columnTitle == "closest tile vert") { closestTileVerticesCol = i; } else if (columnTitle == "closest tile areas") { closestTileAreaCol = i; } else if (columnTitle == "c distance") { cDistanceCol = i; } else if (columnTitle == "dr") { drCol = i; } else if (columnTitle == "tri fiducial") { triFiducialCol = i; } else if (columnTitle == "thetar") { thetaRCol = i; } else if (columnTitle == "phir") { phiRCol = i; } else if (columnTitle == "tri vertices") { triVerticesCol = i; } else if (columnTitle == "vertex") { vertexCol = i; } else if (columnTitle == "vertex fiducial") { vertexFiducialCol = i; } else if (columnTitle == "pos fiducial") { posFiducialCol= i; } else if (columnTitle == "fracri") { fracRICol = i; } else if (columnTitle == "fracrj") { fracRJCol = i; } else if (columnTitle == "study pubmed id") { studyMetaPubMedCol = i; } else if (columnTitle == "study table number") { studyMetaTableCol = i; } else if (columnTitle == "study table subheader") { studyMetaTableSubHeaderCol = i; } else if (columnTitle == "study figure number") { studyMetaFigureCol = i; } else if (columnTitle == "study figure panel") { studyMetaFigurePanelCol = i; } //else if (columnTitle == "study page number") { // studyMetaPageNumberCol = i; //} } for (int i = 0; i < ct->getNumberOfRows(); i++) { CellProjection cd(csv.getFileName()); float xyz[3] = { 0.0, 0.0, 0.0 }; int section = 0; QString name; int studyNumber = -1; QString geography; QString area; float size = 0.0; QString statistic; QString comment; Structure::STRUCTURE_TYPE structure = Structure::STRUCTURE_TYPE_INVALID; QString className; StudyMetaDataLink smdl; if (xCol >= 0) { xyz[0] = ct->getElementAsFloat(i, xCol); } if (yCol >= 0) { xyz[1] = ct->getElementAsFloat(i, yCol); } if (zCol >= 0) { xyz[2] = ct->getElementAsFloat(i, zCol); } if (sectionNumberCol >= 0) { section = ct->getElementAsInt(i, sectionNumberCol); } if (nameCol >= 0) { name = ct->getElement(i, nameCol); } if (studyNumberCol >= 0) { studyNumber = ct->getElementAsInt(i, studyNumberCol); } if (geographyCol >= 0) { geography = ct->getElement(i, geographyCol); } if (areaCol >= 0) { area = ct->getElement(i, areaCol); } if (sizeCol >= 0) { size = ct->getElementAsFloat(i, sizeCol); } if (statisticCol >= 0) { statistic = ct->getElement(i, statisticCol); } if (commentCol >= 0) { comment = ct->getElement(i, commentCol); } if (structureCol >= 0) { structure = Structure::convertStringToType(ct->getElement(i, structureCol)); } if (classNameCol >= 0) { className = ct->getElement(i, classNameCol); if (className == "???") { className = ""; } } if (volumeXYZCol >= 0) { ct->getElement(i, volumeXYZCol, (float*)cd.volumeXYZ, 3); } if (duplicateFlagCol >= 0) { cd.setDuplicateFlag(false); if (ct->getElement(i, duplicateFlagCol) == "true") { cd.setDuplicateFlag(true); } } if (signedDistCol >= 0) { cd.signedDistanceAboveSurface = ct->getElementAsFloat(i, signedDistCol); } if (projTypeCol >= 0) { cd.projectionType = CellProjection::PROJECTION_TYPE_UNKNOWN; if (ct->getElement(i, projTypeCol) == "UNKNOWN") { cd.projectionType = CellProjection::PROJECTION_TYPE_UNKNOWN; } if (ct->getElement(i, projTypeCol) == "INSIDE") { cd.projectionType = CellProjection::PROJECTION_TYPE_INSIDE_TRIANGLE; } if (ct->getElement(i, projTypeCol) == "OUTSIDE") { cd.projectionType = CellProjection::PROJECTION_TYPE_OUTSIDE_TRIANGLE; } } if (closestTileVerticesCol >= 0) { ct->getElement(i, closestTileVerticesCol, (int*)cd.closestTileVertices, 3); } if (closestTileAreaCol >= 0) { ct->getElement(i, closestTileAreaCol, (float*)cd.closestTileAreas, 3); } if (cDistanceCol >= 0) { ct->getElement(i, cDistanceCol, cd.cdistance, 3); } if (drCol >= 0) { cd.dR = ct->getElementAsFloat(i, drCol); } if (triFiducialCol >= 0) { ct->getElement(i, triFiducialCol, (float*)cd.triFiducial, 2*3*3); } if (thetaRCol >= 0) { cd.thetaR = ct->getElementAsFloat(i, thetaRCol); } if (phiRCol >= 0) { cd.phiR = ct->getElementAsFloat(i, phiRCol); } if (triVerticesCol >= 0) { ct->getElement(i, triVerticesCol, (int*)cd.triVertices, 2*3); } if (vertexCol >= 0) { ct->getElement(i, vertexCol, (int*)cd.vertex, 2); } if (vertexFiducialCol >= 0) { ct->getElement(i, vertexFiducialCol, (float*)cd.vertexFiducial, 2*3); } if (posFiducialCol >= 0) { ct->getElement(i, posFiducialCol, (float*)cd.posFiducial, 3); } if (fracRICol >= 0) { cd.fracRI = ct->getElementAsFloat(i, fracRICol); } if (fracRJCol >= 0) { cd.fracRJ = ct->getElementAsFloat(i, fracRJCol); } if (studyMetaPubMedCol >= 0) { smdl.setPubMedID(ct->getElement(i, studyMetaPubMedCol)); } if (studyMetaTableCol >= 0) { smdl.setTableNumber(ct->getElement(i, studyMetaTableCol)); } if (studyMetaTableSubHeaderCol >= 0) { smdl.setTableSubHeaderNumber(ct->getElement(i, studyMetaTableSubHeaderCol)); } if (studyMetaFigureCol >= 0) { smdl.setFigureNumber(ct->getElement(i, studyMetaFigureCol)); } if (studyMetaFigurePanelCol >= 0) { smdl.setFigurePanelNumberOrLetter(ct->getElement(i, studyMetaFigurePanelCol)); } //if (studyMetaPageNumberCol >= 0) { // smdl.setPageNumber(ct->getElement(i, studyMetaPageNumberCol)); //} cd.setXYZ(xyz); cd.setSectionNumber(section); cd.setName(name); cd.setStudyNumber(studyNumber); cd.setGeography(geography); cd.setArea(area); cd.setSize(size); cd.setStatistic(statistic); cd.setComment(comment); cd.setCellStructure(structure); cd.setClassName(className); StudyMetaDataLinkSet smdls; if (smdl.getPubMedID().isEmpty() == false) { smdls.addStudyMetaDataLink(smdl); } cd.setStudyMetaDataLinkSet(smdls); addCellProjection(cd); } // // Do header // const StringTable* stHeader = csv.getDataSectionByName("header"); if (stHeader != NULL) { readHeaderDataFromStringTable(*stHeader); } // // Do study info // const StringTable* stcsi = csv.getDataSectionByName("Cell Study Info"); if (stcsi != NULL) { CellStudyInfo::readDataFromStringTable(studyInfo, *stcsi); } } /** * Read a cell projection file's version number. */ int CellProjectionFile::readFilesVersionNumber(const QString& filename) { CellProjectionFile cpf; cpf.readVersionNumberOnly = 1; cpf.readFile(filename); cpf.readVersionNumberOnly = 0; return cpf.versionNumber; } /** * Read a cell projection version 1 file. */ void CellProjectionFile::readFileVersion1(QTextStream& stream, const int numProjections, const int numStudyInfo) throw (FileException) { for (int i = 0; i < numProjections; i++) { CellProjection cp(getFileName()); cp.readFileDataVersion1(stream); addCellProjection(cp); } for (int j = 0; j < numStudyInfo; j++) { QString line; readLine(stream, line); int firstBlank = line.indexOf(' '); if (firstBlank != -1) { line = line.mid(firstBlank + 1); } CellStudyInfo csi; csi.setTitle(StringUtilities::setupCommentForDisplay(line)); addStudyInfo(csi); } } /** * Read a version 2 cell projection file. */ void CellProjectionFile::readFileVersion2(QTextStream& stream, const int numProjections, const int numStudyInfo) throw (FileException) { for (int i = 0; i < numProjections; i++) { CellProjection cp(getFileName()); cp.readFileDataVersion2(stream); addCellProjection(cp); } for (int j = 0; j < numStudyInfo; j++) { QString line; readLine(stream, line); int firstBlank = line.indexOf(' '); if (firstBlank != -1) { line = line.mid(firstBlank + 1); } CellStudyInfo csi; csi.setTitle(StringUtilities::setupCommentForDisplay(line)); addStudyInfo(csi); } } /** * Read a version 3 cell projection file. */ void CellProjectionFile::readFileVersion3(QFile& /*file*/, QTextStream& stream, const int numProjections) throw (FileException) { for (int i = 0; i < numProjections; i++) { CellProjection cp(getFileName()); cp.readFileDataVersion2(stream); addCellProjection(cp); } // // studies may not begin at zero. So, this converts study numbers // to their numbers in this file // std::vector studyIndexer; while (stream.atEnd() == false) { // // Get number, tag, and value // int number; QString tag; QString tagValue; readNumberedTagLine(stream, number, tag, tagValue); if (tagValue.isEmpty() == false) { int index = -1; for (int k = 0; k < static_cast(studyIndexer.size()); k++) { if (studyIndexer[k] == number) { index = k; break; } } if (index < 0) { CellStudyInfo csi; index = addStudyInfo(csi); studyIndexer.push_back(number); } tagValue = StringUtilities::setupCommentForDisplay(tagValue); if (tag == tagCommentUrl) { studyInfo[index].setURL(tagValue); } else if (tag == tagCommentKeyWords) { studyInfo[index].setKeywords(tagValue); } else if (tag == tagCommentTitle) { studyInfo[index].setTitle(tagValue); } else if (tag == tagCommentAuthors) { studyInfo[index].setAuthors(tagValue); } else if (tag == tagCommentCitation) { studyInfo[index].setCitation(tagValue); } else if (tag == tagCommentStereotaxicSpace) { studyInfo[index].setStereotaxicSpace(tagValue); } else { std::cout << "Unrecognized cell/foci tag: " << tag.toAscii().constData() << std::endl; } } } } /** * read the file with an xml stream reader. */ void CellProjectionFile::readFileWithXmlStreamReader(QFile& /*file*/) throw (FileException) { /* // // Move to beginning of file // file.reset(); QXmlSimpleReader reader; CellProjectionFileSaxReader saxReader(this); reader.setContentHandler(&saxReader); reader.setErrorHandler(&saxReader); // // Some constant to determine how to read a file based upon the file's size // const int oneMegaByte = 1048576; const qint64 bigFileSize = 25 * oneMegaByte; if (file.size() < bigFileSize) { // // This call reads the entire file at once but this is a problem // since the XML files can be very large and will cause the // QT XML parsing to crash // if (reader.parse(&file) == false) { throw FileException(filename, saxReader.getErrorMessage()); } } else { // // The following code reads the XML file in pieces // and hopefully will prevent QT from crashing when // reading large files // // // Create a data stream // QDataStream stream(&file); stream.setVersion(QDataStream::Qt_4_3); // // buffer for data read // const int bufferSize = oneMegaByte; char buffer[bufferSize]; // // the XML input source // QXmlInputSource xmlInput; int totalRead = 0; bool firstTime = true; while (stream.atEnd() == false) { int numRead = stream.readRawData(buffer, bufferSize); totalRead += numRead; if (DebugControl::getDebugOn()) { std::cout << "Cell Projection large file read, total: " << numRead << ", " << totalRead << std::endl; } // // Place the input data into the XML input // xmlInput.setData(QByteArray(buffer, numRead)); // // Process the data that was just read // if (firstTime) { if (reader.parse(&xmlInput, true) == false) { throw FileException(filename, saxReader.getErrorMessage()); } } else { if (reader.parseContinue() == false) { throw FileException(filename, saxReader.getErrorMessage()); } } firstTime = false; } // // Tells parser that there is no more data // xmlInput.setData(QByteArray()); if (reader.parseContinue() == false) { throw FileException(filename, saxReader.getErrorMessage()); } } */ } /** * Read the cell projection file. */ void CellProjectionFile::readFileData(QFile& file, QTextStream& stream, QDataStream&, QDomElement& rootElement) throw (FileException) { // // Should reading data be skipped ? // if (getReadMetaDataOnlyFlag()) { return; } versionNumber = -1; switch (getFileReadType()) { case FILE_FORMAT_ASCII: { bool readingTags = true; bool firstTag = true; int numProjections = -1; int numStudyInfo = 0; qint64 pos = stream.pos(); //file.pos(); while(readingTags) { QString tag, value; readTagLine(stream, tag, value); if (tag == tagFileVersion) { versionNumber = value.toInt(); } else if (tag == tagNumberOfCellProjections) { numProjections = value.toInt(); } else if (tag == tagBeginData) { readingTags = false; } else if (tag == tagNumberOfComments) { numStudyInfo = value.toInt(); } else if (firstTag) { // // Must be old version since there are no tags // versionNumber = 0; file.seek(pos); stream.seek(pos); readingTags = false; } else { std::cerr << "WARNING: Unrecognized cell projection file tag " << tag.toAscii().constData() << std::endl; } firstTag = false; } if (readVersionNumberOnly) { return; } switch (versionNumber) { case 0: throw FileException(filename, "Version 0 projection file no longer supported." " Reproject your original cell file."); break; case 1: readFileVersion1(stream, numProjections, numStudyInfo); break; case 2: readFileVersion2(stream, numProjections, numStudyInfo); break; case 3: readFileVersion3(file, stream, numProjections); break; default: throw FileException(filename, "Unrecognized cell projection file version"); break; } } break; case FILE_FORMAT_BINARY: throw FileException(filename, "Reading in Binary format not supported."); break; case FILE_FORMAT_XML: if (DebugControl::getTestFlag2()) { readFileWithXmlStreamReader(file); } else { QDomNode node = rootElement.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { // // Is this a "CellData" element // if (elem.tagName() == CellProjection::tagCellProjection) { CellProjection cp(getFileName()); cp.readXMLWithDOM(node); addCellProjection(cp); } else if (elem.tagName() == CellStudyInfo::tagCellStudyInfo) { CellStudyInfo csi; csi.readXML(node); addStudyInfo(csi); } else if ((elem.tagName() == xmlHeaderOldTagName) || (elem.tagName() == xmlHeaderTagName)) { // ignore, read by AbstractFile::readFile() } else { std::cout << "WARNING: unrecognized CellFile element: " << elem.tagName().toAscii().constData() << std::endl; } } node = node.nextSibling(); } } versionNumber = 10; break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "Reading XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "Reading XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Reading XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Reading in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: { CommaSeparatedValueFile csvf; csvf.readFromTextStream(file, stream); readDataFromCommaSeparatedValuesTable(csvf); } break; } const int numProj = getNumberOfCellProjections(); for (int i = 0; i < numProj; i++) { CellProjection* cp = getCellProjection(i); cp->updateInvalidCellStructureUsingXCoordinate(); const int studyNumber = cp->getStudyNumber(); if (studyNumber >= 0) { if (studyNumber >= getNumberOfStudyInfo()) { cp->setStudyNumber(-1); } } } } /** * Write the cell projection file. */ void CellProjectionFile::writeFileData(QTextStream& stream, QDataStream&, QDomDocument& xmlDoc, QDomElement& rootElement) throw (FileException) { //writeFileVersion2(stream); //writeFileVersion3(stream); switch (getFileWriteType()) { case FILE_FORMAT_ASCII: throw FileException(filename, "Writing in Ascii format not supported."); break; case FILE_FORMAT_BINARY: throw FileException(filename, "Writing in Binary format not supported."); break; case FILE_FORMAT_XML: { // // Write the cell projections // const int numCellProjections = getNumberOfCellProjections(); for (int i = 0; i < numCellProjections; i++) { CellProjection* cp = getCellProjection(i); cp->writeXML(xmlDoc, rootElement, i); } // // Write the study info // const int numStudyInfo = getNumberOfStudyInfo(); for (int i = 0; i < numStudyInfo; i++) { studyInfo[i].writeXML(xmlDoc, rootElement, i); } } break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "Writing XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "Writing XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Writing XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Writing in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: { CommaSeparatedValueFile csvf; writeDataIntoCommaSeparatedValueFile(csvf); csvf.writeToTextStream(stream); } break; } } /** * Write a version 2 cell file. */ void CellProjectionFile::writeFileVersion2(QTextStream& stream) throw (FileException) { stream << tagFileVersion << " 2\n"; stream << tagNumberOfCellProjections << " " < cells; /// studies for the cells std::vector studyInfo; /// The cell classes std::vector cellClasses; /// Add a cell class int addCellClass(const QString& className); /// read the version 0 cell file void readFileVersion0(QTextStream & stream, const QString& lineIn) throw (FileException); /// read the version 1 cell file void readFileVersion1(QTextStream& stream, const int numCells, const int numStudyInfo) throw (FileException); /// read the version 2 cell file void readFileVersion2(QFile& file, QTextStream& stream, const int numCells) throw (FileException); /// read a cell file's data void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException); /// write a cell file's data void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException); /// write a version 1 cell file's data void writeFileVersion1(QTextStream& stream) throw (FileException); /// write a version 2 cell file's data void writeFileVersion2(QTextStream& stream) throw (FileException); public: /// constructor CellFile(const QString& descriptiveName = "Cell File", const QString& defaultExtensionIn = SpecFile::getCellFileExtension()); /// destructor virtual ~CellFile(); /// clear cells void clear(); /// compare a file for unit testing (returns true if "within tolerance") bool compareFileForUnitTesting(const AbstractFile* af, const float tolerance, QString& messageOut) const; /// add a cell void addCell(const CellData& cd); /// append the contents of a cell file to this file void append(CellFile& cf); /// apply a transformation matrix to the cells void applyTransformationMatrix(const int sectionLow, const int sectionHigh, const float matrix[16], const bool onlySpecialCells); /// apply a transformation matrix to the cells void applyTransformationMatrix(const int sectionLow, const int sectionHigh, const TransformationMatrix& matrix, const bool onlySpecialCells); /// apply a transformation matrix to the cells void applyTransformationMatrix(const TransformationMatrix& matrix, const bool onlySpecialCells = false); /// set the special flag for all cells within the section numbers and bounds void setSpecialFlags(const int sectionLow, const int sectionHigh, const float bounds[4]); /// assign colors to these cells void assignColors(const ColorFile& cf, const CellBase::CELL_COLOR_MODE colorMode); /// clear all special flags void clearAllSpecialFlags(); /// delete a cell void deleteCell(const int indexNumber); /// get number of cell classes int getNumberOfCellClasses() const { return cellClasses.size(); } /// get cell class index by its name int getCellClassIndexByName(const QString& name) const; /// get cell class selected by index bool getCellClassSelectedByIndex(const int index) const; /// set cell class selected by index void setCellClassSelectedByIndex(const int index, const bool sel); /// get cell class selected by name bool getCellClassSelectedByName(const QString& name) const; /// get cell class name QString getCellClassNameByIndex(const int index) const; /// set the status of all cell classes void setAllCellClassStatus(const bool selected); /// returns true if the file is isEmpty (contains no data) bool empty() const { return (getNumberOfCells() == 0); } /// get pointer to a cell CellData* getCell(const int cellNumber); /// get pointer to a cell (const method) const CellData* getCell(const int cellNumber) const; /// get the number of cells int getNumberOfCells() const { return cells.size(); } /// get number of study info int getNumberOfStudyInfo() const { return studyInfo.size(); } /// get the study info index from the study info's value int getStudyInfoIndexFromValue(const CellStudyInfo& studyInfo) const; /// get a study info const CellStudyInfo* getStudyInfo(const int index) const; /// get a study info CellStudyInfo* getStudyInfo(const int index); /// add a study info int addStudyInfo(const CellStudyInfo& studyInfo); /// delete all study info and clear links to study info void deleteAllStudyInfo(); /// delete study info void deleteStudyInfo(const int indx); /// set a study info void setStudyInfo(const int index, const CellStudyInfo& studyInfo); /// find out if comma separated file conversion supported virtual void getCommaSeparatedFileSupport(bool& readFromCSV, bool& writeToCSV) const; /// write the file's data into a comma separated values file (throws exception if not supported) virtual void writeDataIntoCommaSeparatedValueFile(CommaSeparatedValueFile& csv) throw (FileException); /// read the file's data from a comma separated values file (throws exception if not supported) virtual void readDataFromCommaSeparatedValuesTable(const CommaSeparatedValueFile& csv) throw (FileException); friend class CellData; }; #endif // __CELL_FILE_H__ #ifdef __CELL_FILE_MAIN__ const QString CellFile::tagFileVersion = "tag-version"; const QString CellFile::tagNumberOfCells = "tag-number-of-cells"; const QString CellFile::tagNumberOfComments = "tag-number-of-comments"; const QString CellFile::tagCommentUrl = "tag-url"; const QString CellFile::tagCommentKeyWords = "tag-key-words"; const QString CellFile::tagCommentTitle = "tag-title"; const QString CellFile::tagCommentAuthors = "tag-authors"; const QString CellFile::tagCommentCitation = "tag-citation"; const QString CellFile::tagCommentStereotaxicSpace = "tag-space"; #endif // __CELL_FILE_MAIN__ caret-5.6.4~dfsg.1.orig/caret_files/CellFile.cxx0000664000175000017500000013734511572067322021261 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #define __CELL_FILE_MAIN__ #define __CELL_DATA_MAIN__ #include "CellFile.h" #undef __CELL_DATA_MAIN__ #undef __CELL_FILE_MAIN__ #include "CellStudyInfo.h" #include "ColorFile.h" #include "CommaSeparatedValueFile.h" #include "DebugControl.h" #include "StringTable.h" #include "StringUtilities.h" #include "TransformationMatrixFile.h" /** * Initialize a cell. */ void CellData::initialize() { CellBase::initialize(); cellFile = NULL; } /** * Constructor. */ CellData::CellData(const QString& nameIn, const float xIn, const float yIn, const float zIn, const int sectionIn, const QString& classNameIn, const int studyNumberIn, const int colorIndexIn) { initialize(); setName(nameIn); setXYZ(xIn, yIn, zIn); setSearchXYZ(0.0, 0.0, 0.0); setSectionNumber(sectionIn); className = classNameIn; //if (className.isEmpty()) { // className = "???"; //} setStudyNumber(studyNumberIn); setColorIndex(colorIndexIn); } /** * Constructor. */ CellData::CellData() { initialize(); } /** * Destructor. */ CellData::~CellData() { } /** * called when this cell is modified. */ void CellData::setModified() { if (cellFile != NULL) { cellFile->setModified(); } } /** * Set the cell's class name */ void CellData::setClassName(const QString& name) { className = name; if (cellFile != NULL) { classIndex = cellFile->addCellClass(name); } else { classIndex = -1; // 0; } setModified(); } /** * called to read from an XML structure. */ void CellData::readXML(QDomNode& nodeIn) throw (FileException) { if (nodeIn.isNull()) { return; } QDomElement elem = nodeIn.toElement(); if (elem.isNull()) { return; } if (elem.tagName() != tagCellData) { QString msg("Incorrect element type passed to CellData::readXML() "); msg.append(elem.tagName()); throw FileException("", msg); } QDomNode node = nodeIn.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (elem.tagName() == tagCellNumber) { } else if (elem.tagName() == tagClassName) { className = AbstractFile::getXmlElementFirstChildAsString(elem); if (className == "???") { className = ""; } } else if (elem.tagName() == tagCellBase) { CellBase::readXMLWithDOM(node); } else { std::cout << "WARNING: unrecognized CellData element: " << elem.tagName().toAscii().constData() << std::endl; } } node = node.nextSibling(); } } /** * called to write to an XML structure. */ void CellData::writeXML(QDomDocument& xmlDoc, QDomElement& parentElement, const int cellNumber) { // // Create the element for this class instance's data // QDomElement cellDataElement = xmlDoc.createElement(CellData::tagCellData); // // cell number // AbstractFile::addXmlTextElement(xmlDoc, cellDataElement, tagCellNumber, cellNumber); // // name of cell // AbstractFile::addXmlCdataElement(xmlDoc, cellDataElement, tagClassName, className); // // Write the base class' data // CellBase::writeXML(xmlDoc, cellDataElement); // // Add class instance's data to the parent // parentElement.appendChild(cellDataElement); } // //------------------------------------------------------------------------------------------- // /** * Constructor. */ CellFile::CellFile(const QString& descriptiveName, const QString& defaultExtensionIn) : AbstractFile(descriptiveName, defaultExtensionIn, true, FILE_FORMAT_XML, FILE_IO_READ_ONLY, FILE_IO_NONE, FILE_IO_READ_AND_WRITE, FILE_IO_NONE, FILE_IO_NONE, FILE_IO_NONE, FILE_IO_READ_AND_WRITE) { clear(); } /** * Destructor. */ CellFile::~CellFile() { clear(); } /** * Clear the cell file. */ void CellFile::clear() { clearAbstractFile(); cells.clear(); studyInfo.clear(); cellClasses.clear(); //addCellClass("???"); } /** * Append a cell file to this cell file. */ void CellFile::append(CellFile& cf) { const int numCells = cf.getNumberOfCells(); const int origNumberOfStudyInfo = getNumberOfStudyInfo(); // // Transfer the cells // for (int i = 0; i < numCells; i++) { CellData* cd = cf.getCell(i); // // Update study info indexes // if (cd->studyNumber >= 0) { cd->studyNumber += origNumberOfStudyInfo; } addCell(*cd); } // // Transfer the study info // for (int j = 0; j < cf.getNumberOfStudyInfo(); j++) { addStudyInfo(*(cf.getStudyInfo(j))); } // // transfer the file's comment // appendFileComment(cf); setModified(); } /** * Add a cell to the cell file. */ void CellFile::addCell(const CellData& cd) { cells.push_back(cd); const int index = static_cast(cells.size()) - 1; cells[index].cellFile = this; cells[index].classIndex = addCellClass(cd.className); setModified(); } /** * set the special flag for all cells in the section range and box */ void CellFile::setSpecialFlags(const int sectionLow, const int sectionHigh, const float bounds[4]) { const int num = getNumberOfCells(); const float minX = std::min(bounds[0], bounds[2]); const float maxX = std::max(bounds[0], bounds[2]); const float minY = std::min(bounds[1], bounds[3]); const float maxY = std::max(bounds[1], bounds[3]); for (int i = 0; i < num; i++) { if ((cells[i].sectionNumber >= sectionLow) && (cells[i].sectionNumber <= sectionHigh)) { const float x = cells[i].xyz[0]; const float y = cells[i].xyz[1]; if ((x >= minX) && (x <= maxX) && (y >= minY) && (y <= maxY)) { cells[i].specialFlag = true; } } } } /** * Apply a transformation matrix to the cells. */ void CellFile::applyTransformationMatrix(const int sectionLow, const int sectionHigh, const float matrix[16], const bool onlySpecialCells) { const int num = getNumberOfCells(); for (int i = 0; i < num; i++) { if ((cells[i].sectionNumber >= sectionLow) && (cells[i].sectionNumber <= sectionHigh)) { bool transformIt = true; if (onlySpecialCells && (cells[i].specialFlag == false)) { transformIt = false; } if (transformIt) { const float x = cells[i].xyz[0]; const float y = cells[i].xyz[1]; const float z = cells[i].xyz[2]; cells[i].xyz[0] = x*matrix[0] + y*matrix[4] + z*matrix[8] + matrix[12]; cells[i].xyz[1] = x*matrix[1] + y*matrix[5] + z*matrix[9] + matrix[13]; cells[i].xyz[2] = x*matrix[2] + y*matrix[6] + z*matrix[10] + matrix[14]; } } } setModified(); } /** * apply a transformation matrix to the cells. */ void CellFile::applyTransformationMatrix(const TransformationMatrix& matrix, const bool onlySpecialCells) { applyTransformationMatrix(std::numeric_limits::min(), std::numeric_limits::max(), matrix, onlySpecialCells); } /** * Apply a transformation matrix to the cells. */ void CellFile::applyTransformationMatrix(const int sectionLow, const int sectionHigh, const TransformationMatrix& matrixIn, const bool onlySpecialCells) { TransformationMatrix& matrix = const_cast(matrixIn); const int num = getNumberOfCells(); for (int i = 0; i < num; i++) { if ((cells[i].sectionNumber >= sectionLow) && (cells[i].sectionNumber <= sectionHigh)) { bool transformIt = true; if (onlySpecialCells && (cells[i].specialFlag == false)) { transformIt = false; } if (transformIt) { double p[4] = { cells[i].xyz[0], cells[i].xyz[1], cells[i].xyz[2], 1.0 }; matrix.multiplyPoint(p); cells[i].xyz[0] = p[0]; cells[i].xyz[1] = p[1]; cells[i].xyz[2] = p[2]; } } } setModified(); } /** * Assign colors to these cells. */ void CellFile::assignColors(const ColorFile& colorFile, const CellBase::CELL_COLOR_MODE colorMode) { const int numCells = getNumberOfCells(); for (int i = 0; i < numCells; i++) { CellData* cd = getCell(i); bool match; switch (colorMode) { case CellBase::CELL_COLOR_MODE_NAME: cd->setColorIndex(colorFile.getColorIndexByName(cd->getName(), match)); break; case CellBase::CELL_COLOR_MODE_CLASS: cd->setColorIndex(colorFile.getColorIndexByName(cd->getClassName(), match)); break; } } } /** * Clear all of the cell's special flags. */ void CellFile::clearAllSpecialFlags() { const int numCells = getNumberOfCells(); for (int i = 0; i < numCells; i++) { cells[i].specialFlag = false; } } /** * Delete a cell. */ void CellFile::deleteCell(const int indexNumber) { const int newSize = static_cast(cells.size()) - 1; for (int i = indexNumber; i < newSize; i++) { cells[i] = cells[i+1]; } cells.resize(newSize); setModified(); } /** * Get a cell. */ CellData* CellFile::getCell(const int cellNumber) { return &cells[cellNumber]; } /** * Get a cell (const method). */ const CellData* CellFile::getCell(const int cellNumber) const { return &cells[cellNumber]; } /** * Get the study info index based upon the study info's value. */ int CellFile::getStudyInfoIndexFromValue(const CellStudyInfo& csi) const { const int num = getNumberOfStudyInfo(); for (int i = 0; i < num; i++) { if ((*getStudyInfo(i)) == csi) { return i; } } return -1; } /** * Get a study info. */ const CellStudyInfo* CellFile::getStudyInfo(const int indx) const { if ((indx >= 0) && (indx < getNumberOfStudyInfo())) { return &studyInfo[indx]; } return NULL; } /** * Get a study info. */ CellStudyInfo* CellFile::getStudyInfo(const int indx) { if ((indx >= 0) && (indx < getNumberOfStudyInfo())) { return &studyInfo[indx]; } return NULL; } /** * Add a study info. */ int CellFile::addStudyInfo(const CellStudyInfo& csi) { studyInfo.push_back(csi); const int index = studyInfo.size() - 1; return index; } /** * delete all study info and clear links to study info */ void CellFile::deleteAllStudyInfo() { const int num = getNumberOfCells(); for (int i = 0; i < num; i++) { CellData* cd = getCell(i); cd->setStudyNumber(-1); } studyInfo.clear(); } /** * delete study info. */ void CellFile::deleteStudyInfo(const int indx) { if ((indx >= 0) && (indx < getNumberOfStudyInfo())) { for (int i = 0; i < getNumberOfCells(); i++) { const int studyNum = cells[i].getStudyNumber(); if (studyNum == indx) { cells[i].setStudyNumber(-1); } else if (studyNum > indx) { cells[i].setStudyNumber(studyNum - 1); } } studyInfo.erase(studyInfo.begin() + indx); } } /** * Set a study info. */ void CellFile::setStudyInfo(const int index, const CellStudyInfo& csi) { studyInfo[index] = csi; } /** * get cell class selected by index. */ bool CellFile::getCellClassSelectedByIndex(const int index) const { if (index < getNumberOfCellClasses()) { return cellClasses[index].selected; } return false; } /** * Set cell class selected by index. */ void CellFile::setCellClassSelectedByIndex(const int index, const bool sel) { if (index < getNumberOfCellClasses()) { cellClasses[index].selected = sel; } } /** * Get a class index from its name */ int CellFile::getCellClassIndexByName(const QString& name) const { const int numClasses = getNumberOfCellClasses(); for (int i = 0; i < numClasses; i++) { if (name == cellClasses[i].name) { return i; } } return -1; } /** * get cell class selected by name. */ bool CellFile::getCellClassSelectedByName(const QString& name) const { const int index = getCellClassIndexByName(name); if (index >= 0) { return cellClasses[index].selected; } return false; } /** * get cell class name. */ QString CellFile::getCellClassNameByIndex(const int index) const { if (index < getNumberOfCellClasses()) { return cellClasses[index].name; } return ""; // "???"; } /** * Add a cell class (if class already exists its selection status * is set to true). */ int CellFile::addCellClass(const QString& className) { if (className.isEmpty()) { return -1; } const int index = getCellClassIndexByName(className); if (index >= 0) { cellClasses[index].selected = true; return index; } cellClasses.push_back(CellClass(className)); return (getNumberOfCellClasses() - 1); } /** * set the status of all cell classes. */ void CellFile::setAllCellClassStatus(const bool selected) { const int numClasses = getNumberOfCellClasses(); for (int i = 0; i < numClasses; i++) { cellClasses[i].selected = selected; } } /** * compare a file for unit testing (returns true if "within tolerance"). */ bool CellFile::compareFileForUnitTesting(const AbstractFile* af, const float tolerance, QString& messageOut) const { messageOut = ""; const CellFile* cf = dynamic_cast(af); if (cf == NULL) { messageOut = "File for comparison is not a Cell/Foci File"; return false; } const int numCells = getNumberOfCells(); if (numCells != cf->getNumberOfCells()) { messageOut = "Number of cells does not match."; } for (int i = 0; i < numCells; i++) { const CellData* cd1 = getCell(i); const CellData* cd2 = cf->getCell(i); if (cd1->getName() != cd2->getName()) { messageOut = "Cells " + QString::number(i) + " have a different name."; return false; } const float* xyz1 = cd1->getXYZ(); const float* xyz2 = cd2->getXYZ(); for (int j = 0; j < 3; j++) { if (std::fabs(xyz1[j] - xyz2[j]) > tolerance) { messageOut = "Cells " + QString::number(i) + " coordinates do no match."; return false; } } } return true; } /** * find out if comma separated file conversion supported. */ void CellFile::getCommaSeparatedFileSupport(bool& readFromCSV, bool& writeToCSV) const { readFromCSV = true; writeToCSV = true; } /** * write the file's data into a comma separated values file (throws exception if not supported). */ void CellFile::writeDataIntoCommaSeparatedValueFile(CommaSeparatedValueFile& csv) throw (FileException) { csv.clear(); const int numCells = getNumberOfCells(); if (numCells <= 0) { return; } // // Column numbers for data // int numCols = 0; const int cellNumberCol = numCols++; const int xCol = numCols++; const int yCol = numCols++; const int zCol = numCols++; const int sectionNumberCol = numCols++; const int nameCol = numCols++; const int studyNumberCol = numCols++; const int geographyCol = numCols++; const int areaCol = numCols++; const int sizeCol = numCols++; const int statisticCol = numCols++; const int commentCol = numCols++; const int structureCol = numCols++; const int classNameCol = numCols++; const int sumsIDNumberCol = numCols++; const int sumsRepeatNumberCol = numCols++; const int sumsParentCellBaseIDCol = numCols++; const int sumsVersionNumberCol = numCols++; const int sumsMSLIDCol = numCols++; const int attributeIDCol = numCols++; const int studyMetaPubMedCol = numCols++; const int studyMetaTableCol = numCols++; const int studyMetaTableSubHeaderCol = numCols++; const int studyMetaFigureCol = numCols++; const int studyMetaFigurePanelCol = numCols++; //const int studyMetaPageNumberCol = numCols++; const int studyMetaPageReferenceNumberCol = numCols++; const int studyMetaPageReferenceSubheaderCol = numCols++; // // Create and add to string table // StringTable* ct = new StringTable(numCells, numCols, "Cells"); ct->setColumnTitle(cellNumberCol, "Cell Number"); ct->setColumnTitle(xCol, "X"); ct->setColumnTitle(yCol, "Y"); ct->setColumnTitle(zCol, "Z"); ct->setColumnTitle(sectionNumberCol, "Section"); ct->setColumnTitle(nameCol, "Name"); ct->setColumnTitle(studyNumberCol, "Study Number"); ct->setColumnTitle(geographyCol, "Geography"); ct->setColumnTitle(areaCol, "Area"); ct->setColumnTitle(sizeCol, "Size"); ct->setColumnTitle(statisticCol, "Statistic"); ct->setColumnTitle(commentCol, "Comment"); ct->setColumnTitle(structureCol, "Structure"); ct->setColumnTitle(classNameCol, "Class Name"); ct->setColumnTitle(sumsIDNumberCol, "SuMS ID Number"); ct->setColumnTitle(sumsRepeatNumberCol, "SuMS Repeat Number"); ct->setColumnTitle(sumsParentCellBaseIDCol, "SuMS Parent Cell Base ID"); ct->setColumnTitle(sumsVersionNumberCol, "SuMS Version Number"); ct->setColumnTitle(sumsMSLIDCol, "SuMS MSLID"); ct->setColumnTitle(attributeIDCol, "Attribute ID"); ct->setColumnTitle(studyMetaPubMedCol, "Study PubMed ID"); ct->setColumnTitle(studyMetaTableCol, "Study Table Number"); ct->setColumnTitle(studyMetaTableSubHeaderCol, "Study Table Subheader"); ct->setColumnTitle(studyMetaFigureCol, "Study Figure Number"); ct->setColumnTitle(studyMetaFigurePanelCol, "Study Figure Panel"); //ct->setColumnTitle(studyMetaPageNumberCol, "Study Page Number"); ct->setColumnTitle(studyMetaPageReferenceNumberCol, "Study Page Reference Number"); ct->setColumnTitle(studyMetaPageReferenceSubheaderCol, "Study Page Reference Subheader"); for (int i = 0; i < numCells; i++) { const CellData* cd = getCell(i); const float* xyz = cd->getXYZ(); ct->setElement(i, cellNumberCol, i); ct->setElement(i, xCol, xyz[0]); ct->setElement(i, yCol, xyz[1]); ct->setElement(i, zCol, xyz[2]); ct->setElement(i, sectionNumberCol, cd->getSectionNumber()); ct->setElement(i, nameCol, cd->getName()); ct->setElement(i, studyNumberCol, cd->getStudyNumber()); ct->setElement(i, geographyCol, cd->getGeography()); // // Some area entries are like "9/6", which, unfortunately, Excel // converts to 9-Sep but placing a space at the beginning prevents // this // QString area = cd->getArea(); if (area.isEmpty() == false) { if ((area[0] >= '0') && (area[0] <= '9')) { area = ' ' + area; } } ct->setElement(i, areaCol, area); ct->setElement(i, sizeCol, cd->getSize()); ct->setElement(i, statisticCol, cd->getStatistic()); ct->setElement(i, commentCol, cd->getComment()); ct->setElement(i, structureCol, Structure::convertTypeToString(cd->getCellStructure())); ct->setElement(i, classNameCol, cd->getClassName()); ct->setElement(i, sumsIDNumberCol, cd->getSumsIDNumber()); ct->setElement(i, sumsRepeatNumberCol, cd->getSumsRepeatNumber()); ct->setElement(i, sumsParentCellBaseIDCol, cd->getSumsParentCellBaseID()); ct->setElement(i, sumsVersionNumberCol, cd->getSumsVersionNumber()); ct->setElement(i, sumsMSLIDCol, cd->getSumsMSLID()); ct->setElement(i, attributeIDCol, cd->getAttributeID()); const StudyMetaDataLinkSet smdls = cd->getStudyMetaDataLinkSet(); StudyMetaDataLink smdl; if (smdls.getNumberOfStudyMetaDataLinks() > 1) { const QString msg("Cell[" + QString::number(i) + "] named \"" + cd->getName() + "\" has more than one Study Metadata Link so it " "cannot be written as a Comma Separated Value File"); throw FileException(msg); } else if (smdls.getNumberOfStudyMetaDataLinks() == 1) { smdl = smdls.getStudyMetaDataLink(0); } ct->setElement(i, studyMetaPubMedCol, smdl.getPubMedID()); ct->setElement(i, studyMetaTableCol, smdl.getTableNumber()); ct->setElement(i, studyMetaTableSubHeaderCol, smdl.getTableSubHeaderNumber()); ct->setElement(i, studyMetaFigureCol, smdl.getFigureNumber()); ct->setElement(i, studyMetaFigurePanelCol, smdl.getFigurePanelNumberOrLetter()); //ct->setElement(i, studyMetaPageNumberCol, smdl.getPageNumber()); ct->setElement(i, studyMetaPageReferenceNumberCol, smdl.getPageReferencePageNumber()); ct->setElement(i, studyMetaPageReferenceSubheaderCol, smdl.getPageReferenceSubHeaderNumber()); } // // Create table of study info // /* const int numStudyInfo = getNumberOfStudyInfo(); for (int i = 0; i < numStudyInfo; i++) { sdfstudyInfo[i].writeXML(xmlDoc, rootElement, i); } */ StringTable* headerTable = new StringTable(0, 0); writeHeaderDataIntoStringTable(*headerTable); csv.addDataSection(headerTable); csv.addDataSection(ct); StringTable* studyInfoTable = new StringTable(0, 0); CellStudyInfo::writeDataIntoStringTable(studyInfo, *studyInfoTable); csv.addDataSection(studyInfoTable); } /** * read the file's data from a comma separated values file (throws exception if not supported). */ void CellFile::readDataFromCommaSeparatedValuesTable(const CommaSeparatedValueFile& csv) throw (FileException) { const QString filenameSaved(filename); clear(); filename = filenameSaved; const StringTable* ct = csv.getDataSectionByName("Cells"); if (ct == NULL) { throw FileException("No cells found"); } int numCols = ct->getNumberOfColumns(); int cellNumberCol = -1; int xCol = -1; int yCol = -1; int zCol = -1; int sectionNumberCol = -1; int nameCol = -1; int studyNumberCol = -1; int geographyCol = -1; int areaCol = -1; int sizeCol = -1; int statisticCol = -1; int commentCol = -1; int structureCol = -1; int classNameCol = -1; int sumsIDNumberCol = -1; int sumsRepeatNumberCol = -1; int sumsParentCellBaseIDCol = -1; int sumsVersionNumberCol = -1; int sumsMSLIDCol = -1; int attributeIDCol = -1; int studyMetaPubMedCol = -1; int studyMetaTableCol = -1; int studyMetaTableSubHeaderCol = -1; int studyMetaFigureCol = -1; int studyMetaFigurePanelCol = -1; //int studyMetaPageNumberCol = -1; int oldPageNumberCol = -1; int studyMetaPageReferenceNumberCol = -1; int studyMetaPageReferenceSubheaderCol = -1; for (int i = 0; i < numCols; i++) { const QString columnTitle = ct->getColumnTitle(i).toLower(); if (columnTitle == "cell number") { cellNumberCol = i; } else if (columnTitle == "x") { xCol = i; } else if (columnTitle == "y") { yCol = i; } else if (columnTitle == "z") { zCol = i; } else if (columnTitle == "section") { sectionNumberCol = i; } else if (columnTitle == "name") { nameCol = i; } else if (columnTitle == "study number") { studyNumberCol = i; } else if (columnTitle == "geography") { geographyCol = i; } else if (columnTitle == "area") { areaCol = i; } else if (columnTitle == "size") { sizeCol = i; } else if (columnTitle == "statistic") { statisticCol = i; } else if (columnTitle == "comment") { commentCol = i; } else if (columnTitle == "structure") { structureCol = i; } else if (columnTitle == "class name") { classNameCol = i; } else if (columnTitle == "study pubmed id") { studyMetaPubMedCol = i; } else if (columnTitle == "study table number") { studyMetaTableCol = i; } else if (columnTitle == "study table subheader") { studyMetaTableSubHeaderCol = i; } else if (columnTitle == "study figure number") { studyMetaFigureCol = i; } else if (columnTitle == "study figure panel") { studyMetaFigurePanelCol = i; } else if (columnTitle == "study page number") { //studyMetaPageNumberCol = i; oldPageNumberCol = i; } else if (columnTitle == "study page reference number") { studyMetaPageReferenceNumberCol = i; } else if (columnTitle == "study page reference subheader") { studyMetaPageReferenceSubheaderCol = i; } else if (columnTitle == "sums id number") { sumsIDNumberCol = i; } else if (columnTitle == "sums repeat number") { sumsRepeatNumberCol = i; } else if (columnTitle == "sums parent cell base id") { sumsParentCellBaseIDCol = i; } else if (columnTitle == "sums version number") { sumsVersionNumberCol = i; } else if (columnTitle == "sums mslid") { sumsMSLIDCol = i; } else if (columnTitle == "attribute id") { attributeIDCol = i; } } for (int i = 0; i < ct->getNumberOfRows(); i++) { float xyz[3] = { 0.0, 0.0, 0.0 }; int section = 0; QString name; int studyNumber = -1; QString geography; QString area; float size = 1.0; QString statistic; QString comment; Structure::STRUCTURE_TYPE structure = Structure::STRUCTURE_TYPE_INVALID; QString className; StudyMetaDataLink smdl; QString sumsIDNumber = "-1"; QString sumsRepeatNumber = "-1"; QString sumsParentCellBaseID = "-1"; QString sumsVersionNumber = "-1"; QString sumsMSLID = "-1"; QString attributeID = "-1"; if (xCol >= 0) { xyz[0] = ct->getElementAsFloat(i, xCol); if (structureCol < 0) { if (xyz[0] < 0.0) { structure = Structure::STRUCTURE_TYPE_CORTEX_LEFT; } else { structure = Structure::STRUCTURE_TYPE_CORTEX_RIGHT; } } } if (yCol >= 0) { xyz[1] = ct->getElementAsFloat(i, yCol); } if (zCol >= 0) { xyz[2] = ct->getElementAsFloat(i, zCol); } if (sectionNumberCol >= 0) { section = ct->getElementAsInt(i, sectionNumberCol); } if (nameCol >= 0) { name = ct->getElement(i, nameCol); } if (studyNumberCol >= 0) { studyNumber = ct->getElementAsInt(i, studyNumberCol); } if (geographyCol >= 0) { geography = ct->getElement(i, geographyCol); } if (areaCol >= 0) { area = ct->getElement(i, areaCol); } if (sizeCol >= 0) { size = ct->getElementAsFloat(i, sizeCol); } if (statisticCol >= 0) { statistic = ct->getElement(i, statisticCol); } if (commentCol >= 0) { comment = ct->getElement(i, commentCol); } if (structureCol >= 0) { structure = Structure::convertStringToType(ct->getElement(i, structureCol)); } if (classNameCol >= 0) { className = ct->getElement(i, classNameCol); if (className == "???") { className = ""; } } if (sumsIDNumberCol >= 0) { sumsIDNumber = ct->getElement(i, sumsIDNumberCol); } if (sumsRepeatNumberCol >= 0) { sumsRepeatNumber = ct->getElement(i, sumsRepeatNumberCol); } if (sumsParentCellBaseIDCol >= 0) { sumsParentCellBaseID = ct->getElement(i, sumsParentCellBaseIDCol); } if (sumsVersionNumberCol >= 0) { sumsVersionNumber = ct->getElement(i, sumsVersionNumberCol); } if (sumsMSLIDCol >= 0) { sumsMSLID = ct->getElement(i, sumsMSLIDCol); } if (attributeIDCol >= 0) { attributeID = ct->getElement(i, attributeIDCol); } if (studyMetaPubMedCol >= 0) { smdl.setPubMedID(ct->getElement(i, studyMetaPubMedCol)); } if (studyMetaTableCol >= 0) { smdl.setTableNumber(ct->getElement(i, studyMetaTableCol)); } if (studyMetaTableSubHeaderCol >= 0) { smdl.setTableSubHeaderNumber(ct->getElement(i, studyMetaTableSubHeaderCol)); } if (studyMetaFigureCol >= 0) { smdl.setFigureNumber(ct->getElement(i, studyMetaFigureCol)); } if (studyMetaFigurePanelCol >= 0) { smdl.setFigurePanelNumberOrLetter(ct->getElement(i, studyMetaFigurePanelCol)); } //if (studyMetaPageNumberCol >= 0) { // smdl.setPageNumber(ct->getElement(i, studyMetaPageNumberCol)); //} if (studyMetaPageReferenceNumberCol >= 0) { QString pageNumber = ct->getElement(i, studyMetaPageReferenceNumberCol).trimmed(); if (pageNumber.isEmpty()) { if (oldPageNumberCol >= 0) { pageNumber = ct->getElement(i, oldPageNumberCol); } } smdl.setPageReferencePageNumber(pageNumber); } if (studyMetaPageReferenceSubheaderCol >= 0) { smdl.setPageReferenceSubHeaderNumber(ct->getElement(i, studyMetaPageReferenceSubheaderCol)); } CellData cd; cd.setXYZ(xyz); cd.setSectionNumber(section); cd.setName(name); cd.setStudyNumber(studyNumber); cd.setGeography(geography); cd.setArea(area); cd.setSize(size); cd.setStatistic(statistic); cd.setComment(comment); cd.setCellStructure(structure); cd.setClassName(className); cd.setSumsIDNumber(sumsIDNumber); cd.setSumsRepeatNumber(sumsRepeatNumber); cd.setSumsParentCellBaseID(sumsParentCellBaseID); cd.setSumsVersionNumber(sumsVersionNumber); cd.setSumsMSLID(sumsMSLID); cd.setAttributeID(attributeID); StudyMetaDataLinkSet smdls; //if (smdl.getPubMedID().isEmpty() == false) { smdls.addStudyMetaDataLink(smdl); //} cd.setStudyMetaDataLinkSet(smdls); addCell(cd); } // // Do header // const StringTable* stHeader = csv.getDataSectionByName("header"); if (stHeader != NULL) { readHeaderDataFromStringTable(*stHeader); } // // Do study info // const StringTable* stcsi = csv.getDataSectionByName("Cell Study Info"); if (stcsi != NULL) { CellStudyInfo::readDataFromStringTable(studyInfo, *stcsi); } } /** * Read the data for a version 0 cell file. */ void CellFile::readFileVersion0(QTextStream& stream, const QString& lineIn) throw (FileException) { QString line = lineIn; // 1st line contains number of cells //readLine(stream, line); const int numCells = line.toInt(); for (int i = 0; i < numCells; i++) { // line contains cell data readLine(stream, line); int cellNumber; QString unusedName, name; int section, node; float x, y, z; QString className; int studyNumber = -1; QTextStream(&line, QIODevice::ReadOnly) >> cellNumber >> section >> node >> name >> x >> y >> z >> className; CellData cd(name, x, y, z, section, className, studyNumber); addCell(cd); } } /** * Read the data for a version 1 cell file. */ void CellFile::readFileVersion1(QTextStream& stream, const int numCells, const int numStudyInfo) throw (FileException) { for (int i = 0; i < numCells; i++) { QString line; std::vector tokens; readLineIntoTokens(stream, line, tokens); if (tokens.size() < 5) { QString s("reading line: "); s.append(line); throw FileException(filename, s); } const float x = tokens[1].toFloat(); const float y = tokens[2].toFloat(); const float z = tokens[3].toFloat(); const QString name(tokens[4]); int studyInfoNumber = -1; if (tokens.size() >= 6) { studyInfoNumber = tokens[5].toInt(); } int section = 0; if (tokens.size() >= 7) { section = tokens[6].toInt(); } QString className; if (tokens.size() >= 8) { className = tokens[7]; if (className == "???") { className = ""; } } CellData cd(name, x, y, z, section, className, studyInfoNumber); if (x > 0.0) { cd.setCellStructure(Structure::STRUCTURE_TYPE_CORTEX_RIGHT); } else { cd.setCellStructure(Structure::STRUCTURE_TYPE_CORTEX_LEFT); } addCell(cd); } for (int j = 0; j < numStudyInfo; j++) { QString line; readLine(stream, line); int firstBlank = line.indexOf(' '); if (firstBlank != -1) { line = line.mid(firstBlank + 1); } CellStudyInfo csi; csi.setTitle(StringUtilities::setupCommentForDisplay(line)); addStudyInfo(csi); } } /** * Read the data for a version 2 cell file. */ void CellFile::readFileVersion2(QFile& /*file*/, QTextStream& stream, const int numCells) throw (FileException) { // // Read the cells // for (int i = 0; i < numCells; i++) { QString line; std::vector tokens; readLineIntoTokens(stream, line, tokens); if (tokens.size() < 5) { QString s("reading line: "); s.append(line); throw FileException(filename, s); } const float x = tokens[1].toFloat(); const float y = tokens[2].toFloat(); const float z = tokens[3].toFloat(); const QString name(tokens[4]); int studyInfoNumber = -1; if (tokens.size() >= 6) { studyInfoNumber = tokens[5].toInt(); } int section = 0; if (tokens.size() >= 7) { section = tokens[6].toInt(); } QString className(""); //"???"); if (tokens.size() >= 8) { className = tokens[7]; if (className == "???") { className = ""; } } CellData cd(name, x, y, z, section, className, studyInfoNumber); if (x > 0.0) { cd.setCellStructure(Structure::STRUCTURE_TYPE_CORTEX_RIGHT); } else { cd.setCellStructure(Structure::STRUCTURE_TYPE_CORTEX_LEFT); } addCell(cd); } // // study info may not begin at zero. So, this converts study numbers // to their numbers in this file // std::vector studyIndexer; // // Read the study info // //for (int j = 0; j < numComments; j++) { while (stream.atEnd() == false) { // // Get number, tag, and value // int number; QString tag; QString tagValue; readNumberedTagLine(stream, number, tag, tagValue); if (tagValue.isEmpty() == false) { int index = -1; for (int k = 0; k < static_cast(studyIndexer.size()); k++) { if (studyIndexer[k] == number) { index = k; break; } } if (index < 0) { CellStudyInfo csi; index = addStudyInfo(csi); studyIndexer.push_back(number); } tagValue = StringUtilities::setupCommentForDisplay(tagValue); if (tag == tagCommentUrl) { studyInfo[index].setURL(tagValue); } else if (tag == tagCommentKeyWords) { studyInfo[index].setKeywords(tagValue); } else if (tag == tagCommentTitle) { studyInfo[index].setTitle(tagValue); } else if (tag == tagCommentAuthors) { studyInfo[index].setAuthors(tagValue); } else if (tag == tagCommentCitation) { studyInfo[index].setCitation(tagValue); } else if (tag == tagCommentStereotaxicSpace) { studyInfo[index].setStereotaxicSpace(tagValue); } else { std::cout << "Unrecognized cell/foci tag: " << tag.toAscii().constData() << std::endl; } } } // // Update the cell study info indices // for (int i = 0; i < numCells; i++) { CellData* cd = getCell(i); for (int j = 0; j < static_cast(studyIndexer.size()); j++) { if (cd->studyNumber == studyIndexer[j]) { cd->studyNumber = j; break; } } } } /** * Read the cell file data. */ void CellFile::readFileData(QFile& file, QTextStream& stream, QDataStream&, QDomElement& rootElement) throw (FileException) { // // Should reading data be skipped ? // if (getReadMetaDataOnlyFlag()) { return; } switch (getFileReadType()) { case FILE_FORMAT_ASCII: { bool readingTags = true; bool firstTag = true; int numCells = -1; int numStudyInfo = 0; int readingFileVersion = -1; //const QIODevice::Offset pos = file.at(); QString line; while(readingTags) { QString tag, value; readTagLine(stream, line, tag, value); if (tag == tagFileVersion) { readingFileVersion = value.toInt(); } else if (tag == tagNumberOfCells) { numCells = value.toInt(); } else if (tag == tagBeginData) { readingTags = false; } else if (tag == tagNumberOfComments) { numStudyInfo = value.toInt(); } else if (firstTag) { // // Must be old version since there are no tags // readingFileVersion = 0; //file.at(pos); readingTags = false; } else { std::cout << "WARNING: Unrecognized cell file tag " << tag.toAscii().constData() << std::endl; } firstTag = false; } switch (readingFileVersion) { case 0: readFileVersion0(stream, line); break; case 1: readFileVersion1(stream, numCells, numStudyInfo); break; case 2: readFileVersion2(file, stream, numCells); break; default: { std::ostringstream str; str << "Unrecognized cell file version " << readingFileVersion; throw FileException(filename, str.str().c_str()); } break; } } break; case FILE_FORMAT_BINARY: throw FileException(filename, "Reading in Binary format not supported."); break; case FILE_FORMAT_XML: { QDomNode node = rootElement.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { // // Is this a "CellData" element // if (elem.tagName() == CellData::tagCellData) { CellData cd; cd.readXML(node); addCell(cd); } else if (elem.tagName() == CellStudyInfo::tagCellStudyInfo) { CellStudyInfo csi; csi.readXML(node); addStudyInfo(csi); } else if ((elem.tagName() == xmlHeaderOldTagName) || (elem.tagName() == xmlHeaderTagName)) { // ignore, read by AbstractFile::readFile() } else { if (elem.tagName() != "FileHeader") { std::cout << "WARNING: unrecognized CellFile element: " << elem.tagName().toAscii().constData() << std::endl; } } } node = node.nextSibling(); } } break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "Reading XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "Reading XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Reading XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Reading in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: { CommaSeparatedValueFile csvf; csvf.readFromTextStream(file, stream); readDataFromCommaSeparatedValuesTable(csvf); } break; } const int numCells = getNumberOfCells(); for (int i = 0; i < numCells; i++) { getCell(i)->updateInvalidCellStructureUsingXCoordinate(); } } /** * Write a cell file's data. */ void CellFile::writeFileData(QTextStream& stream, QDataStream&, QDomDocument& xmlDoc, QDomElement& rootElement) throw (FileException) { //writeFileVersion2(stream); //writeFileVersion1(stream); switch (getFileWriteType()) { case FILE_FORMAT_ASCII: throw FileException(filename, "Writing in Ascii format not supported."); break; case FILE_FORMAT_BINARY: throw FileException(filename, "Writing in Binary format not supported."); break; case FILE_FORMAT_XML: { // // Write the cells // const int numCells = getNumberOfCells(); for (int i = 0; i < numCells; i++) { CellData* cd = getCell(i); cd->writeXML(xmlDoc, rootElement, i); } // // Write the study info // const int numStudyInfo = getNumberOfStudyInfo(); for (int i = 0; i < numStudyInfo; i++) { studyInfo[i].writeXML(xmlDoc, rootElement, i); } } break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "Writing XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "Writing XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Writing XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Writing in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: { CommaSeparatedValueFile csvf; writeDataIntoCommaSeparatedValueFile(csvf); csvf.writeToTextStream(stream); } break; } } /** * Write a version 1 cell file's data. */ void CellFile::writeFileVersion1(QTextStream& stream) throw (FileException) { const int numCells = getNumberOfCells(); stream << tagFileVersion << " 1" << "\n"; stream << tagNumberOfCells << " " << numCells << "\n"; stream << tagNumberOfComments << " " << studyInfo.size() << "\n"; stream << tagBeginData << "\n"; for (int i = 0; i < numCells; i++) { CellData* cd = getCell(i); float xyz[3]; cd->getXYZ(xyz); stream << i << " " << xyz[0] << " " << xyz[1] << " " << xyz[2] << " " << cd->getName() << " " << cd->getStudyNumber() << " " << cd->getSectionNumber() << " " << cd->getClassName() << "\n"; } for (unsigned int j = 0; j < studyInfo.size(); j++) { stream << j << " " << StringUtilities::setupCommentForStorage(studyInfo[j].getTitle()) << "\n"; } } /** * Write a version 2 cell file's data. */ void CellFile::writeFileVersion2(QTextStream& stream) throw (FileException) { const int numCells = getNumberOfCells(); stream << tagFileVersion << " 2" << "\n"; stream << tagNumberOfCells << " " << numCells << "\n"; stream << tagNumberOfComments << " " << studyInfo.size() << "\n"; stream << tagBeginData << "\n"; for (int i = 0; i < numCells; i++) { CellData* cd = getCell(i); float xyz[3]; cd->getXYZ(xyz); QString className(cd->getClassName()); if (className.isEmpty()) { className = ""; //"???"; } stream << i << " " << xyz[0] << " " << xyz[1] << " " << xyz[2] << " " << cd->getName() << " " << cd->getStudyNumber() << " " << cd->getSectionNumber() << " " << className << "\n"; } for (unsigned int j = 0; j < studyInfo.size(); j++) { stream << j << " " << tagCommentUrl << " " << StringUtilities::setupCommentForStorage(studyInfo[j].getURL()) << "\n"; stream << j << " " << tagCommentKeyWords << " " << StringUtilities::setupCommentForStorage(studyInfo[j].getKeywords()) << "\n"; stream << j << " " << tagCommentTitle << " " << StringUtilities::setupCommentForStorage(studyInfo[j].getTitle()) << "\n"; stream << j << " " << tagCommentAuthors << " " << StringUtilities::setupCommentForStorage(studyInfo[j].getAuthors()) << "\n"; stream << j << " " << tagCommentCitation << " " << StringUtilities::setupCommentForStorage(studyInfo[j].getCitation()) << "\n"; stream << j << " " << tagCommentStereotaxicSpace << " " << studyInfo[j].getStereotaxicSpace() << "\n"; } } caret-5.6.4~dfsg.1.orig/caret_files/CellColorFile.h0000664000175000017500000000230111572067322021664 0ustar michaelmichael #ifndef __CELL_COLOR_FILE_H__ #define __CELL_COLOR_FILE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "ColorFile.h" /// class for cell colors file class CellColorFile : public ColorFile { public: // Constructor CellColorFile(); // Destructor ~CellColorFile(); protected: }; #endif // __CELL_COLOR_FILE_H__ caret-5.6.4~dfsg.1.orig/caret_files/CellColorFile.cxx0000664000175000017500000000214411572067322022244 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CellColorFile.h" #include "SpecFile.h" /** * Constructor */ CellColorFile::CellColorFile() : ColorFile("Cell Color File", SpecFile::getCellColorFileExtension()) { } /** * Destructor */ CellColorFile::~CellColorFile() { } caret-5.6.4~dfsg.1.orig/caret_files/CellClass.h0000664000175000017500000000205311572067322021057 0ustar michaelmichael #ifndef __CELL_CLASS_H__ #define __CELL_CLASS_H__ /// This holds cell class information class CellClass { public: /// Constructor CellClass(const QString& nameIn) { name = nameIn; selected = true; } /// get the class name QString getName() const { return name; } /// get selected status bool getSelected() const { return selected; } /// set selected status void setSelected(const bool sel) { selected = sel; } /// comparison operator bool operator<(const CellClass& cc) const { return (name < cc.name); } /// equality operator bool operator==(const CellClass& cc) const { return (name == cc.name); } private: /// name of class QString name; /// class selected bool selected; friend class CellData; friend class CellBase; friend class CellFile; friend class CellProjection; friend class CellProjectionFile; }; #endif // __CELL_CLASS_H__ caret-5.6.4~dfsg.1.orig/caret_files/CellBase.h0000664000175000017500000003136711572067322020676 0ustar michaelmichael #ifndef __CELL_BASE__ #define __CELL_BASE__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "Structure.h" #include "StudyMetaDataLinkSet.h" class QDomDocument; class QDomElement; class QDomNode; class StudyMetaDataFile; /// base class for CellData and CellProjection class CellBase { public: /// Coloring mode enum CELL_COLOR_MODE { /// color by cell name CELL_COLOR_MODE_NAME, /// color by class name CELL_COLOR_MODE_CLASS }; // constructor CellBase(); // destructor virtual ~CellBase(); // copy the data from another cell base class void copyData(const CellBase& cb); // initialize a cell virtual void initialize(); /// get xyz const float* getXYZ() const { return &xyz[0]; } /// get xyz void getXYZ(float xyzOut[3]) const; // set xyz void setXYZ(const float xyzIn[3]); // set xyz void setXYZ(const float x, const float y, const float z); /// get search xyz const float* getSearchXYZ() const { return &searchXYZ[0]; } /// get search xyz void getSearchXYZ(float xyzOut[3]) const; // set search xyz void setSearchXYZ(const float xyzIn[3]); // set search xyz void setSearchXYZ(const float x, const float y, const float z); /// get name QString getName() const { return name; } // set name virtual void setName(const QString& n); /// get section number int getSectionNumber() const { return sectionNumber; } // set section number void setSectionNumber(const int sn); /// get study number int getStudyNumber() const { return studyNumber; } // set study number void setStudyNumber(const int sn); /// get the study metadata link set StudyMetaDataLinkSet getStudyMetaDataLinkSet() const { return studyMetaDataLinkSet; } /// set the study metadata link set void setStudyMetaDataLinkSet(const StudyMetaDataLinkSet smdls); /// get region of interest QString getRegionOfInterest() const { return regionOfInterest; } /// set region of interest void setRegionOfInterest(const QString& roi); /// get geography QString getGeography() const { return geography; } // set geography void setGeography(const QString& g); /// get area QString getArea() const { return area; } // set area void setArea(const QString& a); /// get size float getSize() const { return size; } // set size void setSize(const float s); /// get statistic QString getStatistic() const { return statistic; } // set statistic void setStatistic(const QString& s); /// get comment QString getComment() const { return comment; } // set comment void setComment(const QString& c); /// get the display flag bool getDisplayFlag() const { return displayFlag; } // set the display flag void setDisplayFlag(const bool df); /// get the color index int getColorIndex() const { return colorIndex; } /// set the color index void setColorIndex(const int ci); /// Get the cell's class name QString getClassName() const { return className; } /// Set the cell's class name virtual void setClassName(const QString& name) = 0; /// Get the index of the class int getClassIndex() const { return classIndex; } /// Get the flag used for some operations bool getSpecialFlag() const { return specialFlag; } /// Set the flag used for some operations void setSpecialFlag(const bool value) { specialFlag = value; } /// get flag to indicate if cell is within search parameters bool getInSearchFlag() const { return inSearchFlag; } /// set flag to indicate if cell is within search parameters void setInSearchFlag(const bool b) { inSearchFlag = b; } /// get the signed distance above the surface (positive = above surface) float getSignedDistanceAboveSurface() const { return signedDistanceAboveSurface; } /// set the signed distance above the surface (positive = above surface) void setSignedDistanceAboveSurface(const float dist) { signedDistanceAboveSurface = dist; } /// get the structure Structure::STRUCTURE_TYPE getCellStructure() const { return structure.getType(); } /// set the structure void setCellStructure(const Structure::STRUCTURE_TYPE cst); /// update the cell's invalid structure using the X coordinate if it is not zero void updateInvalidCellStructureUsingXCoordinate(); /// copy data void copyCellBaseData(const CellBase& cb, const bool copyXYZ = false); /// get the highlight flag bool getHighlightFlag() const { return highlightFlag; } /// set the highlight flag void setHighlightFlag(const bool value) { highlightFlag = value; } /// get the SuMS repeat number QString getSumsRepeatNumber() const { return sumsRepeatNumber; } /// set the SuMS repeat number void setSumsRepeatNumber(const QString& s); /// get the SuMS ID number QString getSumsIDNumber() const { return sumsIDNumber; } /// set the SuMS ID number void setSumsIDNumber(const QString& s); /// get the SuMS parent cell base ID QString getSumsParentCellBaseID() const { return sumsParentCellBaseID; } /// set the SuMS parent cell base ID void setSumsParentCellBaseID(const QString& s); /// get the SuMS version number QString getSumsVersionNumber() const { return sumsVersionNumber; } /// set the SuMS version number void setSumsVersionNumber(const QString& s); /// get the SuMS mslid QString getSumsMSLID() const { return sumsMSLID; } /// set the SuMS mslid void setSumsMSLID(const QString& s); /// get the attribute ID QString getAttributeID() const { return attributeID; } /// set the attribute ID void setAttributeID(const QString& s); /// validate the study metadata link (returns error message) QStringList validateStudyMetaDataLink(StudyMetaDataFile* smdf) const; protected: /// called to read from an XML DOM structure virtual void readXMLWithDOM(QDomNode& node) throw (FileException); /// called to write to an XML structure virtual void writeXML(QDomDocument& xmlDoc, QDomElement& parentElement); /// called when a "set" method is called virtual void setModified() = 0; /// position of cell float xyz[3]; /// position of cell for searching float searchXYZ[3]; /// section number int sectionNumber; /// name of cell QString name; /// study number int studyNumber; /// the link to study metadata StudyMetaDataLinkSet studyMetaDataLinkSet; /// geography QString geography; /// area QString area; /// region of interest QString regionOfInterest; /// size float size; /// statistic QString statistic; /// comment QString comment; /// the display flag bool displayFlag; /// the color index int colorIndex; /// class name of cell QString className; /// index of class name int classIndex; /// flag used for some operations bool specialFlag; /// flag to indicate if cell is within search parameters bool inSearchFlag; /// signed distance above the surface (positive if above surface, negative if below) float signedDistanceAboveSurface; /// structure of cell Structure structure; /// highlight flag bool highlightFlag; /// SuMS ID number QString sumsIDNumber; /// SuMS repeat number QString sumsRepeatNumber; /// SuMS parent cell base ID QString sumsParentCellBaseID; /// SuMS version number QString sumsVersionNumber; /// SuMS mslid QString sumsMSLID; /// the attribute id QString attributeID; /// tag for reading and writing cells static const QString tagCellBase; /// tag for reading and writing cells static const QString tagXYZ; /// tag for reading and writing cells static const QString tagSearchXYZ; /// tag for reading and writing cells static const QString tagSectionNumber; /// tag for reading and writing cells static const QString tagName; /// tag for reading and writing cells static const QString tagStudyNumber; /// tag for reading and writing cells static const QString tagGeography; /// tag for reading and writing cells static const QString tagArea; /// tag for reading and writing cells static const QString tagRegionOfInterest; /// tag for reading and writing cells static const QString tagSize; /// tag for reading and writing cells static const QString tagStatistic; /// tag for reading and writing cells static const QString tagComment; /// tag for reading and writing cells static const QString tagClassName; /// tag for reading and writing cells static const QString tagSignedDistanceAboveSurface; /// tag for reading and writing cells static const QString tagStructure; /// tag for reading and writing cells static const QString tagSumsIDNumber; /// tag for reading and writing cells static const QString tagSumsRepeatNumber; /// tag for reading and writing cells static const QString tagSumsParentCellBaseID; /// tag for reading and writing cells static const QString tagSumsVersionNumber; /// tag for reading and writing cells static const QString tagSumsMSLID; /// tag for reading and writing cells static const QString tagAttributeID; }; #endif // __CELL_BASE__ #ifdef __CELL_BASE_MAIN__ const QString CellBase::tagCellBase = "CellBase"; const QString CellBase::tagXYZ = "xyz"; const QString CellBase::tagSearchXYZ = "SearchXYZ"; const QString CellBase::tagSectionNumber = "sectionNumber"; const QString CellBase::tagName = "name"; const QString CellBase::tagStudyNumber = "studyNumber"; const QString CellBase::tagGeography = "geography"; const QString CellBase::tagArea = "area"; const QString CellBase::tagRegionOfInterest = "regionOfInterest"; const QString CellBase::tagSize = "size"; const QString CellBase::tagStatistic = "statistic"; const QString CellBase::tagComment = "comment"; const QString CellBase::tagClassName = "className"; const QString CellBase::tagSignedDistanceAboveSurface = "signedDistanceAboveSurface"; const QString CellBase::tagStructure = "structure"; const QString CellBase::tagSumsIDNumber = "tagSumsIDNumber"; const QString CellBase::tagSumsRepeatNumber = "tagSumsRepeatNumber"; const QString CellBase::tagSumsParentCellBaseID = "tagSumsParentCellBaseID"; const QString CellBase::tagSumsVersionNumber = "tagSumsVersionNumber"; const QString CellBase::tagSumsMSLID = "tagSumsMSLID"; const QString CellBase::tagAttributeID = "tagAttributeID"; #endif // __CELL_BASE_MAIN__ caret-5.6.4~dfsg.1.orig/caret_files/CellBase.cxx0000664000175000017500000005623311572067322021250 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "AbstractFile.h" #define __CELL_BASE_MAIN__ #include "CellBase.h" #undef __CELL_BASE_MAIN__ #include "StringUtilities.h" #include "StudyMetaDataFile.h" /** * constructor. */ CellBase::CellBase() { initialize(); } /** * destructor. */ CellBase::~CellBase() { } /** * Initialize the data */ void CellBase::initialize() { xyz[0] = 0.0; xyz[1] = 0.0; xyz[2] = 0.0; searchXYZ[0] = 0.0; searchXYZ[1] = 0.0; searchXYZ[2] = 0.0; sectionNumber = -1; name = ""; studyNumber = -1; studyMetaDataLinkSet.clear(); geography = ""; area = ""; regionOfInterest = ""; size = 0.0; statistic = ""; comment = ""; displayFlag = false; colorIndex = -1; className = ""; // "???"; classIndex = -1; inSearchFlag = true; specialFlag = false; signedDistanceAboveSurface = 0.0; structure.setType(Structure::STRUCTURE_TYPE_INVALID); highlightFlag = false; sumsIDNumber = "-1"; sumsRepeatNumber = "-1"; sumsParentCellBaseID = "-1"; sumsVersionNumber = "-1"; sumsMSLID = "-1"; attributeID = "-1"; } /** * copy the data from another cell base class. */ void CellBase::copyData(const CellBase& cb) { xyz[0] = cb.xyz[0]; xyz[1] = cb.xyz[1]; xyz[2] = cb.xyz[2]; searchXYZ[0] = cb.searchXYZ[0]; searchXYZ[1] = cb.searchXYZ[1]; searchXYZ[2] = cb.searchXYZ[2]; sectionNumber = cb.sectionNumber; name = cb.name; studyNumber = cb.studyNumber; studyMetaDataLinkSet = cb.studyMetaDataLinkSet; geography = cb.geography; area = cb.area; regionOfInterest = cb.regionOfInterest; size = cb.size; statistic = cb.statistic; comment = cb.comment; displayFlag = cb.displayFlag; colorIndex = cb.colorIndex; className = cb.className; classIndex = cb.classIndex; inSearchFlag = cb.inSearchFlag; specialFlag = cb.specialFlag; signedDistanceAboveSurface = cb.signedDistanceAboveSurface; structure = cb.structure; highlightFlag = cb.highlightFlag; sumsIDNumber = cb.sumsIDNumber; sumsRepeatNumber = cb.sumsRepeatNumber; sumsParentCellBaseID = cb.sumsParentCellBaseID; sumsVersionNumber = cb.sumsVersionNumber; sumsMSLID = cb.sumsMSLID; attributeID = cb.attributeID; } /** * get xyz. */ void CellBase::getXYZ(float xyzOut[3]) const { xyzOut[0] = xyz[0]; xyzOut[1] = xyz[1]; xyzOut[2] = xyz[2]; } /** * set xyz. */ void CellBase::setXYZ(const float xyzIn[3]) { xyz[0] = xyzIn[0]; xyz[1] = xyzIn[1]; xyz[2] = xyzIn[2]; setModified(); } /** * set xyz. */ void CellBase::setXYZ(const float x, const float y, const float z) { xyz[0] = x; xyz[1] = y; xyz[2] = z; setModified(); } /** * get search xyz. */ void CellBase::getSearchXYZ(float xyzOut[3]) const { xyzOut[0] = searchXYZ[0]; xyzOut[1] = searchXYZ[1]; xyzOut[2] = searchXYZ[2]; } /** * set search xyz. */ void CellBase::setSearchXYZ(const float xyzIn[3]) { searchXYZ[0] = xyzIn[0]; searchXYZ[1] = xyzIn[1]; searchXYZ[2] = xyzIn[2]; setModified(); } /** * set search xyz. */ void CellBase::setSearchXYZ(const float x, const float y, const float z) { searchXYZ[0] = x; searchXYZ[1] = y; searchXYZ[2] = z; setModified(); } /** * set the SuMS ID number. */ void CellBase::setSumsIDNumber(const QString& s) { sumsIDNumber = s; setModified(); } /** * set the SuMS repeat number. */ void CellBase::setSumsRepeatNumber(const QString& s) { sumsRepeatNumber = s; setModified(); } /** * set the SuMS parent cell base ID. */ void CellBase::setSumsParentCellBaseID(const QString& s) { sumsParentCellBaseID = s; setModified(); } /** * set SuMS version number. */ void CellBase::setSumsVersionNumber(const QString& s) { sumsVersionNumber = s; setModified(); } /** * set mslid. */ void CellBase::setSumsMSLID(const QString& s) { sumsMSLID = s; setModified(); } /** * set the attribute ID. */ void CellBase::setAttributeID(const QString& s) { attributeID = s; setModified(); } /** * update the cell's invalid structure using the X coordinate if it is not zero. */ void CellBase::updateInvalidCellStructureUsingXCoordinate() { if (structure.getType() == Structure::STRUCTURE_TYPE_INVALID) { if (xyz[0] > 0.0) { structure.setType(Structure::STRUCTURE_TYPE_CORTEX_RIGHT); } else if (xyz[0] < 0.0) { structure.setType(Structure::STRUCTURE_TYPE_CORTEX_LEFT); } } } /** * set name. */ void CellBase::setName(const QString& n) { name = n; setModified(); } /** * set section number. */ void CellBase::setSectionNumber(const int sn) { sectionNumber = sn; setModified(); } /** * set study number. */ void CellBase::setStudyNumber(const int sn) { studyNumber = sn; setModified(); } /** * set the study metadata link. */ void CellBase::setStudyMetaDataLinkSet(const StudyMetaDataLinkSet smdls) { studyMetaDataLinkSet = smdls; setModified(); } /** * set region of interest. */ void CellBase::setRegionOfInterest(const QString& roi) { regionOfInterest = roi; setModified(); } /** * set geography. */ void CellBase::setGeography(const QString& g) { geography = g; setModified(); } /** * set area. */ void CellBase::setArea(const QString& a) { area = a; setModified(); } /** * set size. */ void CellBase::setSize(const float s) { size = s; setModified(); } /** * set statistic. */ void CellBase::setStatistic(const QString& s) { statistic = s; setModified(); } /** * set comment. */ void CellBase::setComment(const QString& c) { comment = c; setModified(); } /** * set the display flag. */ void CellBase::setDisplayFlag(const bool df) { displayFlag = df; // does NOT modify file setModified(); } /** * set the color index. */ void CellBase::setColorIndex(const int ci) { colorIndex = ci; // does NOT modify file setModified(); } /** * copy data. */ void CellBase::copyCellBaseData(const CellBase& cb, const bool copyXYZ) { if (copyXYZ) { xyz[0] = cb.xyz[0]; xyz[1] = cb.xyz[1]; xyz[2] = cb.xyz[2]; } searchXYZ[0] = cb.searchXYZ[0]; searchXYZ[1] = cb.searchXYZ[1]; searchXYZ[2] = cb.searchXYZ[2]; sectionNumber = cb.sectionNumber; name = cb.name; studyNumber = cb.studyNumber; geography = cb.geography; area = cb.area; regionOfInterest = cb.regionOfInterest; size = cb.size; statistic = cb.statistic; comment = cb.comment; className = cb.className; displayFlag = cb.displayFlag; colorIndex = cb.colorIndex; structure = cb.structure; highlightFlag = cb.highlightFlag; sumsIDNumber = cb.sumsIDNumber; sumsRepeatNumber = cb.sumsRepeatNumber; sumsParentCellBaseID = cb.sumsParentCellBaseID; sumsVersionNumber = cb.sumsVersionNumber; sumsMSLID = cb.sumsMSLID; attributeID = cb.attributeID; } /** * set the structure. */ void CellBase::setCellStructure(const Structure::STRUCTURE_TYPE cst) { structure.setType(cst); setModified(); } /** * validate the study metadata link (returns error message). */ QStringList CellBase::validateStudyMetaDataLink(StudyMetaDataFile* smdf) const { QStringList msg; if (studyMetaDataLinkSet.getNumberOfStudyMetaDataLinks() > 0) { StudyMetaDataLink smdl = studyMetaDataLinkSet.getStudyMetaDataLink(0); const QString pubMedID = smdl.getPubMedID(); if (pubMedID.isEmpty()) { msg += "has link with an empty PubMed ID"; } else { const int nameIndx = smdf->getStudyIndexFromName(name); const int studyIndex = smdf->getStudyIndexFromPubMedID(pubMedID); if ((nameIndx >= 0) && (studyIndex >= 0) && (nameIndx != studyIndex)) { msg += " name links to study " + QString::number(nameIndx + 1) + " but PubMedID links to " + QString::number(studyIndex + 1); } else if (nameIndx < 0) { msg += " does not link to a study with matching name."; } if (studyIndex < 0) { msg += " has link with PubMedID=" + pubMedID + " not in Study Metadata File."; } else { const QString studyNumberText(QString::number(studyIndex+1)); StudyMetaData* smd = smdf->getStudyMetaData(studyIndex); if (getName() != smd->getName()) { msg += " has non-matching study name " + smd->getName(); } const QString tableNumber = smdl.getTableNumber(); const QString tableSubHeader = smdl.getTableSubHeaderNumber(); const QString figureNumber = smdl.getFigureNumber(); const QString figurePanel = smdl.getFigurePanelNumberOrLetter(); const QString pageRefNumber = smdl.getPageReferencePageNumber(); const QString pageRefSubHeader = smdl.getPageReferenceSubHeaderNumber(); bool haveFigurePageOrTableLinkForClass = false; if (tableNumber.isEmpty() == false) { StudyMetaData::Table* table = smd->getTableByTableNumber(tableNumber); if (table == NULL) { msg += "has link to study " + studyNumberText + " but invalid table " + tableNumber; } else { if (tableSubHeader.isEmpty() == false) { StudyMetaData::SubHeader* subHeader = table->getSubHeaderBySubHeaderNumber(tableSubHeader); if (subHeader != NULL) { if (subHeader->getShortName() != className) { msg += "has '" + className + "' as Class entry, but corresponding table subheader study entry is '" + subHeader->getShortName() + "'"; } if (subHeader->getShortName().isEmpty() == false) { haveFigurePageOrTableLinkForClass = true; } } else { msg += "has link to study " + studyNumberText + " but invalid table " + tableNumber + " but invalid subheader " + tableSubHeader; } } } } if (figureNumber.isEmpty() == false) { StudyMetaData::Figure* figure = smd->getFigureByFigureNumber(figureNumber); if (figure == NULL) { msg += "has link to study " + studyNumberText + " but invalid figure " + figureNumber; } else { if (figurePanel.isEmpty() == false) { StudyMetaData::Figure::Panel* panel = figure->getPanelByPanelNumberOrLetter(figurePanel); if (panel != NULL) { if (panel->getTaskDescription() != className) { msg += "has '" + className + "' as Class entry, but corresponding figure panel study entry is '" + panel->getTaskDescription() + "'"; } if (panel->getTaskDescription().isEmpty() == false) { haveFigurePageOrTableLinkForClass = true; } } else { msg += "has link to study " + studyNumberText + ", figure " + figureNumber + " but invalid panel " + figurePanel; } } } } if (pageRefNumber.isEmpty() == false) { StudyMetaData::PageReference* pageRef = smd->getPageReferenceByPageNumber(pageRefNumber); if (pageRef == NULL) { msg += "has link to study " + studyNumberText + " but invalid page ref " + pageRefNumber; } else { if (pageRefSubHeader.isEmpty() == false) { StudyMetaData::SubHeader* subHeader = pageRef->getSubHeaderBySubHeaderNumber(pageRefSubHeader); if (subHeader != NULL) { if (subHeader->getShortName() != className) { msg += "has '" + className + "' as Class entry, but corresponding page reference subheader study entry is '" + subHeader->getShortName() + "'"; } if (subHeader->getShortName().isEmpty() == false) { haveFigurePageOrTableLinkForClass = true; } } else { msg += "has link to study " + studyNumberText + ", Page Ref " + pageRefNumber + " but invalid subheader " + pageRefSubHeader; } } } } if (haveFigurePageOrTableLinkForClass == false) { if (className.isEmpty()) { msg += "has no Class entry and there is no designated table/fig/page subheader"; } } } } } else { msg += "has no study metadata links."; } return msg; } /** * called to read from an XML DOM structure. */ void CellBase::readXMLWithDOM(QDomNode& nodeIn) throw (FileException) { if (nodeIn.isNull()) { return; } QDomElement elem = nodeIn.toElement(); if (elem.isNull()) { return; } if (elem.tagName() != tagCellBase) { QString msg("Incorrect element type passed to CellData::readXMLWithDOM() "); msg.append(elem.tagName()); throw FileException("", msg); } QDomNode node = nodeIn.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { //std::cout << "CellBase: " << elem.tagName() << std::endl; if (elem.tagName() == tagXYZ) { const QString xyzString = AbstractFile::getXmlElementFirstChildAsString(elem); std::vector elems; StringUtilities::token(xyzString, " ", elems); if (elems.size() >= 3) { xyz[0] = StringUtilities::toFloat(elems[0]); xyz[1] = StringUtilities::toFloat(elems[1]); xyz[2] = StringUtilities::toFloat(elems[2]); } } else if (elem.tagName() == tagSearchXYZ) { const QString xyzString = AbstractFile::getXmlElementFirstChildAsString(elem); std::vector elems; StringUtilities::token(xyzString, " ", elems); if (elems.size() >= 3) { searchXYZ[0] = StringUtilities::toFloat(elems[0]); searchXYZ[1] = StringUtilities::toFloat(elems[1]); searchXYZ[2] = StringUtilities::toFloat(elems[2]); } } else if (elem.tagName() == tagSectionNumber) { sectionNumber = StringUtilities::toInt(AbstractFile::getXmlElementFirstChildAsString(elem)); } else if (elem.tagName() == tagName) { name = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == tagStudyNumber) { studyNumber = StringUtilities::toInt(AbstractFile::getXmlElementFirstChildAsString(elem)); } else if (elem.tagName() == tagGeography) { geography = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == tagArea) { area = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == tagRegionOfInterest) { regionOfInterest = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == tagSize) { size = StringUtilities::toFloat(AbstractFile::getXmlElementFirstChildAsString(elem)); } else if (elem.tagName() == tagStatistic) { statistic = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == tagComment) { comment = AbstractFile::getXmlElementFirstChildAsString(elem); } else if ((elem.tagName() == "hemisphere") || (elem.tagName() == tagStructure)) { structure.setTypeFromString(AbstractFile::getXmlElementFirstChildAsString(elem)); } else if (elem.tagName() == tagClassName) { className = AbstractFile::getXmlElementFirstChildAsString(elem); if (className == "???") { className = ""; } } else if (elem.tagName() == tagSignedDistanceAboveSurface) { signedDistanceAboveSurface = AbstractFile::getXmlElementFirstChildAsString(elem).toFloat(); } else if ((elem.tagName() == StudyMetaDataLink::tagStudyMetaDataLink) || (elem.tagName() == StudyMetaDataLinkSet::tagStudyMetaDataLinkSet)) { studyMetaDataLinkSet.readXML(node); } else if (elem.tagName() == tagSumsIDNumber) { sumsIDNumber = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == tagSumsRepeatNumber) { sumsRepeatNumber = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == tagSumsParentCellBaseID) { sumsParentCellBaseID = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == tagSumsVersionNumber) { sumsVersionNumber = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == tagSumsMSLID) { sumsMSLID = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == tagAttributeID) { attributeID = AbstractFile::getXmlElementFirstChildAsString(elem); } else { std::cout << "WARNING: unrecognized CellBase element: " << elem.tagName().toAscii().constData() << std::endl; } } node = node.nextSibling(); } } /** * called to write to an XML structure. */ void CellBase::writeXML(QDomDocument& xmlDoc, QDomElement& parentElement) { // // Create the element for this class instance's data // QDomElement cellBaseElement = xmlDoc.createElement(tagCellBase); // // XYZ coordinates // std::vector xyzVec; xyzVec.push_back(xyz[0]); xyzVec.push_back(xyz[1]); xyzVec.push_back(xyz[2]); AbstractFile::addXmlTextElement(xmlDoc, cellBaseElement, tagXYZ, StringUtilities::combine(xyzVec, " ")); // // Search XYZ coordinates // xyzVec.clear(); xyzVec.push_back(searchXYZ[0]); xyzVec.push_back(searchXYZ[1]); xyzVec.push_back(searchXYZ[2]); AbstractFile::addXmlTextElement(xmlDoc, cellBaseElement, tagSearchXYZ, StringUtilities::combine(xyzVec, " ")); // // section number // AbstractFile::addXmlTextElement(xmlDoc, cellBaseElement, tagSectionNumber, sectionNumber); // // name of cell // AbstractFile::addXmlCdataElement(xmlDoc, cellBaseElement, tagName, name); // // study number // AbstractFile::addXmlTextElement(xmlDoc, cellBaseElement, tagStudyNumber, studyNumber); // // geography // AbstractFile::addXmlCdataElement(xmlDoc, cellBaseElement, tagGeography, geography); // // area // AbstractFile::addXmlCdataElement(xmlDoc, cellBaseElement, tagArea, area); // // region of interest // AbstractFile::addXmlCdataElement(xmlDoc, cellBaseElement, tagRegionOfInterest, regionOfInterest); // // size of cell // AbstractFile::addXmlTextElement(xmlDoc, cellBaseElement, tagSize, size); // // statistic // AbstractFile::addXmlCdataElement(xmlDoc, cellBaseElement, tagStatistic, statistic); // // comment // AbstractFile::addXmlCdataElement(xmlDoc, cellBaseElement, tagComment, comment); // // class name // AbstractFile::addXmlCdataElement(xmlDoc, cellBaseElement, tagClassName, className); // // signed distance above surface // AbstractFile::addXmlCdataElement(xmlDoc, cellBaseElement, tagSignedDistanceAboveSurface, QString::number(signedDistanceAboveSurface, 'f', 6)); // // SuMS ID, repeat number and parent cell base ID, version numer, mslid // AbstractFile::addXmlTextElement(xmlDoc, cellBaseElement, tagSumsIDNumber, sumsIDNumber); AbstractFile::addXmlTextElement(xmlDoc, cellBaseElement, tagSumsRepeatNumber, sumsRepeatNumber); AbstractFile::addXmlTextElement(xmlDoc, cellBaseElement, tagSumsParentCellBaseID, sumsParentCellBaseID); AbstractFile::addXmlTextElement(xmlDoc, cellBaseElement, tagSumsVersionNumber, sumsVersionNumber); AbstractFile::addXmlTextElement(xmlDoc, cellBaseElement, tagSumsMSLID, sumsMSLID); AbstractFile::addXmlTextElement(xmlDoc, cellBaseElement, tagAttributeID, attributeID); // // structure // AbstractFile::addXmlTextElement(xmlDoc, cellBaseElement, tagStructure, structure.getTypeAsString()); // // study metadata // studyMetaDataLinkSet.writeXML(xmlDoc, cellBaseElement); // // Add class instance's data to the parent // parentElement.appendChild(cellBaseElement); } caret-5.6.4~dfsg.1.orig/caret_files/CaretScriptFile.h0000664000175000017500000001631311572067322022241 0ustar michaelmichael #ifndef __CARET_SCRIPT_FILE_H__ #define __CARET_SCRIPT_FILE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "AbstractFile.h" class QDomNode; class QWidget; /// class for storing a caret command script class CaretScriptFile : public AbstractFile { public: /// class for caret command operations class CaretCommandOperation { public: /// constructor CaretCommandOperation() { lastParameterIsVariableListFlag = false; } /// constructor CaretCommandOperation(const QString& commandSwitchIn, const QStringList& parametersIn, const bool lastParameterIsVariableListFlagIn, const QString& shortDescriptionIn, const QString& commentIn) { setSwitch(commandSwitchIn); setParameters(parametersIn); setLastParameterIsVariableListFlag(lastParameterIsVariableListFlagIn); setShortDescription(shortDescriptionIn); setComment(commentIn); } /// destructor ~CaretCommandOperation() { } /// get switch QString getSwitch() const { return commandSwitch; } /// get parameters for GUI display QStringList getParametersForGUI() const { return parameters; } /// get parameters for command execution (variable list is split up) QStringList getParametersForCommandExecution() const; /// get comment QString getComment() const { return comment; } /// get last parameter is variable list flag bool getLastParameterIsVariableListFlag() { return lastParameterIsVariableListFlag; } /// set last parameter is variable list flag void setLastParameterIsVariableListFlag(const bool flag) { lastParameterIsVariableListFlag = flag; } /// set the switch void setSwitch(const QString& switchIn) { commandSwitch = switchIn; } /// set parameters void setParameters(const QStringList& parametersIn) { parameters = parametersIn; } /// set comment void setComment(const QString& commentIn) { comment = commentIn; } /// get the short description QString getShortDescription() const { return shortDescription; } /// set the short description void setShortDescription(const QString& s) { shortDescription = s; } // read from XML void readXML(QDomNode& nodeIn) throw (FileException); // write as XML void writeXML(QDomDocument& xmlDoc, QDomElement& parentElement); protected: // the command switch QString commandSwitch; // the parameters QStringList parameters; // the last parameter is variable list flag bool lastParameterIsVariableListFlag; // the comment QString comment; // the short description QString shortDescription; }; /// class for sorting variable names by length class Variable { public: // constructor Variable(const QString& nameIn, const QString& valueIn) { name = nameIn; value = valueIn; nameLength = name.length(); } /// destructor ~Variable() { } /// get the variable name QString getVariableName() const { return name; } /// get the variable value QString getVariableValue() const { return value; } /// comparison operator so LONGEST FIRST bool operator<(const Variable& v) const { return nameLength > v.nameLength; } protected: /// name of variable QString name; /// value of variable QString value; /// length of variable name int nameLength; }; // constructor CaretScriptFile(); // destructor ~CaretScriptFile(); // call AbstractFile::clearAbstractFile() from its clear method. void clear(); // returns true if the file is isEmpty (contains no data) bool empty() const; // add an operation void addCommandOperation(CaretCommandOperation* commandOperation); // delete an operation void deleteOperation(CaretCommandOperation* commandOperation); // delete an operation void deleteOperation(const int indx); // get the number of operations int getNumberOfCommandOperations() const { return commandOperations.size(); } // get an operation CaretCommandOperation* getCommandOperation(const int indx) { return commandOperations[indx]; } // get an operation (const method) const CaretCommandOperation* getCommandOperation(const int indx) const { return commandOperations[indx]; } // run the commands in the script file void runCommandsInFile(QWidget* parentWidget, const QString& caretCommandProgramName, QString& commandsOutputText) throw (FileException); protected: // Read the contents of the file (header has already been read) void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& rootElement) throw (FileException); // Write the file's data (header has already been written) void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& xmlDoc, QDomElement& rootElement) throw (FileException); // the operations std::vector commandOperations; }; #endif // __CARET_SCRIPT_FILE_H__ caret-5.6.4~dfsg.1.orig/caret_files/CaretScriptFile.cxx0000664000175000017500000005524011572067322022616 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include "CaretScriptFile.h" #include "CommandScriptComment.h" #include "CommandScriptVariableRead.h" #include "CommandScriptVariableSet.h" #include "DebugControl.h" #include "ProgramParameters.h" #include "QtScriptInputDialog.h" #include "SpecFile.h" #include "StringUtilities.h" /** * constructor. */ CaretScriptFile::CaretScriptFile() : AbstractFile("Caret Script File", SpecFile::getCaretScriptFileExtension(), true, // has header FILE_FORMAT_XML, // default write type FILE_IO_NONE, // ASCII read/write FILE_IO_NONE, // Binary read/write FILE_IO_READ_AND_WRITE, // XML read/write FILE_IO_NONE, // XML Base64 read/write FILE_IO_NONE, // XML GZip Base64 FILE_IO_NONE, // other read/write FILE_IO_NONE) // CSVF read/write { clear(); } /** * destructor. */ CaretScriptFile::~CaretScriptFile() { clear(); } /** * call AbstractFile::clearAbstractFile() from its clear method.. */ void CaretScriptFile::clear() { AbstractFile::clearAbstractFile(); const int num = static_cast(commandOperations.size()); for (int i = 0; i < num; i++) { delete commandOperations[i]; commandOperations[i] = NULL; } commandOperations.clear(); } /** * returns true if the file is isEmpty (contains no data). */ bool CaretScriptFile::empty() const { return true; } /** * add an operation. */ void CaretScriptFile::addCommandOperation(CaretCommandOperation* commandOperation) { commandOperations.push_back(commandOperation); setModified(); } /** * delete an operation. */ void CaretScriptFile::deleteOperation(CaretCommandOperation* commandOperation) { const int num = getNumberOfCommandOperations(); for (int i = 0; i < num; i++) { CaretCommandOperation* cco = getCommandOperation(i); if (cco == commandOperation) { deleteOperation(i); break; } } } /** * delete an operation. */ void CaretScriptFile::deleteOperation(const int indx) { commandOperations.erase(commandOperations.begin() + indx); } /** * run the commands in the script file. * If parent is a widget, a progress dialog will be displayed. * If parent is zero, no progress dialog is displayed. */ void CaretScriptFile::runCommandsInFile(QWidget* parentWidget, const QString& caretCommandProgramName, QString& commandsOutputText) throw (FileException) { commandsOutputText.clear(); QString errorMessage; // // Names of variables and their values // std::multiset variables; // // Get number of command operations // const int num = getNumberOfCommandOperations(); if (num <= 0) { return; } // // Command used for reading and setting variables // CommandScriptComment commandScriptComment; CommandScriptVariableRead commandScriptVariableRead; CommandScriptVariableSet commandScriptVariableSet; // // Use progress dialog only if parent widget is valid // QProgressDialog* progressDialog = NULL; if (parentWidget != NULL) { progressDialog = new QProgressDialog(parentWidget); progressDialog->setMinimum(0); progressDialog->setMaximum(num); progressDialog->setMinimumDuration(0); } // // Loop through the commands // for (int i = 0; i < num; i++) { // // Get the operation // const CaretCommandOperation* op = getCommandOperation(i); const QString commandSwitch = op->getSwitch(); QStringList commandParameters = op->getParametersForCommandExecution(); // // If this is neither a read nor set variable command // if ((commandSwitch != commandScriptVariableRead.getOperationSwitch()) && (commandSwitch != commandScriptVariableSet.getOperationSwitch()) && (commandSwitch != commandScriptComment.getOperationSwitch())) { // // Replace any variables in the parameters with the corresponding value // for (int j = 0; j < commandParameters.count(); j++) { QString paramName = commandParameters.at(j); // // Try all variable substitutions // for (std::multiset::iterator iter = variables.begin(); iter != variables.end(); iter++) { paramName = paramName.replace(iter->getVariableName(), iter->getVariableValue()); } if (paramName.indexOf('$') >= 0) { throw FileException("Variable substitution failed for \"" + paramName + "\""); } commandParameters[j] = paramName; } } // // Assemble the parameters // QStringList commandSwitchAndParameters; commandSwitchAndParameters << commandSwitch; commandSwitchAndParameters << commandParameters; const QString cmdText = caretCommandProgramName + " " + commandSwitchAndParameters.join(" "); const QString comment(op->getComment()); if (DebugControl::getDebugOn()) { std::cout << "Comment: " << comment.toAscii().constData() << std::endl; std::cout << "Command: " << cmdText.toAscii().constData() << std::endl; } // // Remove double quotes from any parameters // for (int m = 0; m < commandSwitchAndParameters.count(); m++) { // // Remove anything enclosed in double quotes // QString param = commandSwitchAndParameters[m]; if (param.startsWith("\"") && param.endsWith("\"")) { const int len = param.length(); if (len >= 2) { param = param.mid(1, len - 2); commandSwitchAndParameters[m] = param; } } } // // Update progress dialog // if (progressDialog != NULL) { allowEventsToProcess(); progressDialog->setValue(i); progressDialog->setLabelText("Running " + op->getShortDescription()); progressDialog->show(); if (progressDialog->wasCanceled()) { throw FileException("Script execution canceled by user."); } } else { std::cout << "Running " << op->getShortDescription().toAscii().constData() << std::endl; } // // Allow other events to be processed (do not hog CPU) // allowEventsToProcess(); // // Is this a read parameters command ? // if (commandSwitch == commandScriptVariableRead.getOperationSwitch()) { // // Create the parameters and get the variable name and value // ProgramParameters setVarParams(caretCommandProgramName, commandSwitchAndParameters); commandScriptVariableRead.setParameters(&setVarParams); const QString switchName = setVarParams.getNextParameterAsString("switch"); //skip switch try { // // Execute to get variable name and prompt message // commandScriptVariableRead.execute(errorMessage); const QString variableName = commandScriptVariableRead.getVariableName(); const QString promptMessage = commandScriptVariableRead.getPromptMessage(); if (DebugControl::getDebugOn()) { std::cout << "Variable: " << variableName.toAscii().constData() << std::endl << " Prompt: " << promptMessage.toAscii().constData() << std::endl; } // // If GUI available? // QString variableValue; if (progressDialog != NULL) { // // Use GUI to get variable's value // QApplication::restoreOverrideCursor(); QtScriptInputDialog inputDialog(progressDialog, promptMessage, true); if (inputDialog.exec() == QtScriptInputDialog::Accepted) { variableValue = inputDialog.getInputText(); } else { commandsOutputText = ""; errorMessage = "Cancel pressed. Script execution terminated."; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); } else { // // Read variables value from terminal // std::cout << promptMessage.toAscii().constData() << std::endl; std::string str; std::getline(std::cin, str); variableValue = StringUtilities::fromStdString(str); } // // Save variable names and values // variables.insert(Variable(variableName, variableValue)); } catch (CommandException& e) { throw FileException(e.whatQString()); } } else if (commandSwitch == commandScriptVariableSet.getOperationSwitch()) { // set variable // // Create the parameters and get the variable name and value // ProgramParameters setVarParams(caretCommandProgramName, commandSwitchAndParameters); commandScriptVariableSet.setParameters(&setVarParams); const QString switchName = setVarParams.getNextParameterAsString("switch"); //skip switch try { // // Execute to get variable name and value // commandScriptVariableSet.execute(errorMessage); const QString variableName = commandScriptVariableSet.getVariableName(); const QString variableValue = commandScriptVariableSet.getVariableValue(); if (DebugControl::getDebugOn()) { std::cout << "Variable: " << variableName.toAscii().constData() << std::endl << " Value: " << variableValue.toAscii().constData() << std::endl; } // // Save variable names and values // variables.insert(Variable(variableName, variableValue)); } catch (CommandException& e) { throw FileException(e.whatQString()); } } else { // normal command so run it // // Create a new QProcess and add its arguments // QProcess process(parentWidget); // // Start execution of the command // process.start(caretCommandProgramName, commandSwitchAndParameters); if (!process.waitForStarted()) { QString msg("Error starting command: "); msg.append(cmdText); errorMessage.append(msg); } // // Wait until the program is complete // if (!process.waitForFinished(100000000)) { QString msg("Error waiting for command to finish: "); msg.append(caretCommandProgramName); msg.append(cmdText); msg.append("\nError Message" + process.errorString()); errorMessage.append(msg); } //const QString processOutput(process.readAll()); QString processOutput(process.readAllStandardOutput()); processOutput.append(process.readAllStandardError()); commandsOutputText.append(processOutput); if (process.exitStatus() == QProcess::NormalExit) { if (process.exitCode() == 0) { commandsOutputText.append("COMMAND SUCCESSFUL: "); commandsOutputText.append(cmdText + "\n\n"); } else { //std::cout << "Text output: " // << commandsOutputText.toAscii().constData() // << std::endl; errorMessage.append("COMMAND FAILED1: "); errorMessage.append(cmdText); errorMessage.append("\nExit Code " + QString::number(process.exitCode())); errorMessage.append("\nError Message" + process.errorString()); errorMessage.append("\nCommand output: " + processOutput); } } else { errorMessage.append("COMMAND FAILED2: "); errorMessage.append(cmdText + processOutput); } } // // Did something go wrong // if (errorMessage.isEmpty() == false) { break; } } // // Remove progress dialog // if (progressDialog != NULL) { progressDialog->setValue(progressDialog->maximum()); delete progressDialog; progressDialog = NULL; } if (errorMessage.isEmpty() == false) { commandsOutputText.append("\n" + errorMessage); throw FileException(errorMessage); } } /** * Read the contents of the file (header has already been read). */ void CaretScriptFile::readFileData(QFile& /*file*/, QTextStream& /*stream*/, QDataStream& /*binStream*/, QDomElement& rootElement) throw (FileException) { // // Should reading data be skipped ? // if (getReadMetaDataOnlyFlag()) { return; } switch (getFileReadType()) { case FILE_FORMAT_ASCII: throw FileException(filename, "Reading in Ascii format not supported."); break; case FILE_FORMAT_BINARY: throw FileException(filename, "Reading in Binary format not supported."); break; case FILE_FORMAT_XML: { QDomNode node = rootElement.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { // // Is this a "CellData" element // if (elem.tagName() == "Command") { CaretCommandOperation* op = new CaretCommandOperation; op->readXML(node); addCommandOperation(op); } else if ((elem.tagName() == xmlHeaderOldTagName) || (elem.tagName() == xmlHeaderTagName)) { // ignore, read by AbstractFile::readFile() } else { std::cout << "WARNING: unrecognized Caret Script File element: " << elem.tagName().toAscii().constData() << std::endl; } } node = node.nextSibling(); } } break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "Reading XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "Reading XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Reading XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Reading in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Reading in Comma Separated Value File format not supported."); break; } } /** * Write the file's data (header has already been written). */ void CaretScriptFile::writeFileData(QTextStream& /*stream*/, QDataStream& /*binStream*/, QDomDocument& xmlDoc, QDomElement& rootElement) throw (FileException) { switch (getFileWriteType()) { case FILE_FORMAT_ASCII: throw FileException(filename, "Writing in Ascii format not supported."); break; case FILE_FORMAT_BINARY: throw FileException(filename, "Writing in Binary format not supported."); break; case FILE_FORMAT_XML: { const int num = getNumberOfCommandOperations(); for (int i = 0; i < num; i++) { CaretCommandOperation* op = getCommandOperation(i); op->writeXML(xmlDoc, rootElement); } } break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "Writing in XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "Writing in XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Writing XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Writing in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Writing in Comma Separated Value File format not supported."); break; } } //======================================================================= /** * get parameters for command execution (variable list is split up). */ QStringList CaretScriptFile::CaretCommandOperation::getParametersForCommandExecution() const { QStringList paramsOut; // // Loop through parameters // const int numParams = parameters.count(); for (int i = 0; i < numParams; i++) { // // Get the parameter // const QString param(parameters.at(i)); // // is this the last parameter and is last parameter // a variable list // if ((i == (numParams - 1)) && (lastParameterIsVariableListFlag)) { QStringList splitParams; StringUtilities::tokenStringsWithQuotes(param, splitParams); paramsOut << splitParams; } else { paramsOut << param; } } return paramsOut; } /** * read from XML. */ void CaretScriptFile::CaretCommandOperation::readXML(QDomNode& nodeIn) throw (FileException) { if (nodeIn.isNull()) { return; } QDomElement elem = nodeIn.toElement(); if (elem.isNull()) { return; } if (elem.tagName() != "Command") { QString msg("Incorrect element type passed to CaretCommandOperation::readXML(): \""); msg.append(elem.tagName()); msg.append("\""); throw FileException("", msg); } commandSwitch = ""; parameters.clear(); lastParameterIsVariableListFlag = false; comment = ""; shortDescription = ""; QDomNode node = nodeIn.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (elem.tagName() == "commandSwitch") { commandSwitch = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "comment") { comment = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "parameters") { const QString s = AbstractFile::getXmlElementFirstChildAsString(elem); parameters.append(s); } else if (elem.tagName() == "shortDescription") { shortDescription = AbstractFile::getXmlElementFirstChildAsString(elem); } else if (elem.tagName() == "lastParameterIsVariableListFlag") { lastParameterIsVariableListFlag = false; if (AbstractFile::getXmlElementFirstChildAsString(elem) == "true") { lastParameterIsVariableListFlag = true; } } else { std::cout << "WARNING: unrecognized CaretCommandOperation element: " << elem.tagName().toAscii().constData() << std::endl; } } node = node.nextSibling(); } } /** * write as XML. */ void CaretScriptFile::CaretCommandOperation::writeXML(QDomDocument& xmlDoc, QDomElement& parentElement) { // // Create the element for the command // QDomElement commandElement = xmlDoc.createElement("Command"); // // Create the elements for the switch and the parameters // AbstractFile::addXmlCdataElement(xmlDoc, commandElement, "commandSwitch", commandSwitch); AbstractFile::addXmlCdataElement(xmlDoc, commandElement, "comment", comment); AbstractFile::addXmlCdataElement(xmlDoc, commandElement, "shortDescription", shortDescription); for (int i = 0; i < parameters.count(); i++) { AbstractFile::addXmlCdataElement(xmlDoc, commandElement, "parameters", parameters.at(i)); } AbstractFile::addXmlCdataElement(xmlDoc, commandElement, "lastParameterIsVariableListFlag", (lastParameterIsVariableListFlag ? "true" : "false")); // // Add to parent element // parentElement.appendChild(commandElement); } caret-5.6.4~dfsg.1.orig/caret_files/Caret6ProjectedItem.h0000664000175000017500000000353011572067322023016 0ustar michaelmichael/* * File: Caret6ProjectedItem.h * Author: john * * Created on November 6, 2009, 10:10 AM */ #ifndef __CARET6_PROJECTED_ITEM_H__ #define __CARET6_PROJECTED_ITEM_H__ #include "Structure.h" class CellProjection; class BorderProjection; class XmlGenericWriter; // stores projected item class Caret6ProjectedItem { public: /// projection type enum ProjectionType { UNPROJECTED, BARYCENTRIC, VANESSEN }; /// constructor Caret6ProjectedItem(); /// destructor ~Caret6ProjectedItem(); /// write projected item in XML void writeXML(XmlGenericWriter& xmlWriter); /// projection type ProjectionType projectionType; /// unprojected position float xyz[3]; /// BARYCENTRIC TRIANGLE PROJECTION vertices int closestTriangleVertices[3]; /// BARYCENTRIC TRIANGLE PROJECTION tile areas float closestTriangleAreas[3]; /// BARYCENTRIC TRIANGLE PROJECTION distance above surface float signedDistanceAboveSurface; /// OUTSIDE TRIANGLE DR float dR; /// OUTSIDE TRIANGLE anatomical coords float triAnatomical[2][3][3]; /// OUTSIDE TRIANGLE theta float thetaR; /// OUTSIDE TRIANGLE phi float phiR; /// OUTSIDE TRIANGLE triangle vertices int triVertices[2][3]; /// OUTSIDE TRIANGLE vertices int vertex[2]; /// OUTSIDE TRIANGLE anatomical vertices float vertexAnatomical[2][3]; /// OUTSIDE TRIANGLE anatomical position float posAnatomical[3]; // cell's Anatomical surface position /// OUTSIDE TRIANGLE fracRI float fracRI; /// OUTSIDE TRIANGLE fracRJ float fracRJ; /// position of focus in a volume float volumeXYZ[3]; Structure structure; }; #endif /* __CARET6_PROJECTED_ITEM_H__ */ caret-5.6.4~dfsg.1.orig/caret_files/Caret6ProjectedItem.cxx0000664000175000017500000001044611572067322023375 0ustar michaelmichael #include #include "Caret6ProjectedItem.h" #include "StringUtilities.h" #include "XmlGenericWriter.h" /** * constructor. */ Caret6ProjectedItem::Caret6ProjectedItem() { projectionType = Caret6ProjectedItem::UNPROJECTED; for (int i = 0; i < 3; i++) { xyz[i] = 0.0; closestTriangleVertices[i] = 0.0;; closestTriangleAreas[i] = 0.0;; volumeXYZ[i] = 0.0; posAnatomical[i] = 0.0; } signedDistanceAboveSurface = 0.0; dR = 0.0; for (int i = 0; i < 2; i++) { vertex[i] = 0; for (int j = 0; j < 3; j++) { for (int k = 0; k < 3; k++) { triAnatomical[i][j][k] = 0.0; } triVertices[i][j] = 0.0; vertexAnatomical[i][j] = 0.0; } } thetaR = 0.0; phiR = 0.0; fracRI = 0.0; fracRJ = 0.0; structure.setType(Structure::STRUCTURE_TYPE_INVALID); } /** * destructor. */ Caret6ProjectedItem::~Caret6ProjectedItem() { } /** * write projected item in XML. */ void Caret6ProjectedItem::writeXML(XmlGenericWriter& xmlWriter) { QString typeName = ""; switch (this->projectionType) { case Caret6ProjectedItem::UNPROJECTED: typeName = "UNPROJECTED"; break; case Caret6ProjectedItem::BARYCENTRIC: typeName = "BARYCENTRIC"; break; case Caret6ProjectedItem::VANESSEN: typeName = "VANESSEN"; break; } xmlWriter.writeStartElement("SurfaceProjectedItem"); QString structureName = "Invalid"; if (this->structure.isLeftCortex()) { structureName = "CortexLeft"; } else if (this->structure.isRightCortex()) { structureName = "CortexRight"; } else if (this->structure.isCerebellum()) { structureName = "Cerebellum"; } xmlWriter.writeElementCharacters("Structure", structureName); xmlWriter.writeElementCharacters("OriginalXYZ", this->xyz, 3); xmlWriter.writeElementCharacters("VolumeXYZ", this->volumeXYZ, 3); xmlWriter.writeElementCharacters("ProjectionType", typeName); switch (this->projectionType) { case Caret6ProjectedItem::UNPROJECTED: { xmlWriter.writeElementCharacters("Unprojected", ""); } break; case Caret6ProjectedItem::BARYCENTRIC: { xmlWriter.writeStartElement("BarycentricProjection"); xmlWriter.writeElementCharacters("TriangleVertices", this->closestTriangleVertices, 3); xmlWriter.writeElementCharacters("TriangleAreas", this->closestTriangleAreas, 3); xmlWriter.writeElementCharacters("SignedDistanceAboveSurface", signedDistanceAboveSurface); xmlWriter.writeEndElement(); } break; case Caret6ProjectedItem::VANESSEN: xmlWriter.writeStartElement("VanEssenProjection"); xmlWriter.writeElementCharacters("DR", this->dR); xmlWriter.writeElementCharacters("TriAnatomical", (float*)this->triAnatomical, 18); xmlWriter.writeElementCharacters("ThetaR", this->thetaR); xmlWriter.writeElementCharacters("PhiR", this->phiR); xmlWriter.writeElementCharacters("TriVertices", (int*)this->triVertices, 6); xmlWriter.writeElementCharacters("Vertex", this->vertex, 2); xmlWriter.writeElementCharacters("VertexAnatomical", (float*)this->vertexAnatomical, 6); xmlWriter.writeElementCharacters("PosAnatomical", this->posAnatomical, 3); xmlWriter.writeElementCharacters("FracRI", this->fracRI); xmlWriter.writeElementCharacters("FracRJ", this->fracRJ); xmlWriter.writeEndElement(); break; } xmlWriter.writeEndElement(); } caret-5.6.4~dfsg.1.orig/caret_files/ByteSwapping.h0000664000175000017500000000173611572067322021635 0ustar michaelmichael #ifndef __VE_BYTE_SWAPPING__ #define __VE_BYTE_SWAPPING__ /// This class contains static methods for byte swapping data, typically used /// when reading binary data files. class ByteSwapping { public: /// byte swap the data static void swapBytes(short* n, int numToSwap); /// byte swap the data static void swapBytes(unsigned short* n, int numToSwap); /// byte swap the data static void swapBytes(int* n, int numToSwap); /// byte swap the data static void swapBytes(unsigned int* n, int numToSwap); /// byte swap the data static void swapBytes(long long* n, int numToSwap); /// byte swap the data static void swapBytes(unsigned long long* n, int numToSwap); /// byte swap the data static void swapBytes(float* n, int numToSwap); /// byte swap the data static void swapBytes(double* n, int numToSwap); }; #endif // __VE_BYTE_SWAPPING__ caret-5.6.4~dfsg.1.orig/caret_files/ByteSwapping.cxx0000664000175000017500000000344611572067322022210 0ustar michaelmichael #include "ByteSwapping.h" /** * Swap bytes for the specified type. */ void ByteSwapping::swapBytes(short* n, int numToSwap) { for (int 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(unsigned short* n, int numToSwap) { swapBytes((short*)n, numToSwap); } /** * Swap bytes for the specified type. */ void ByteSwapping::swapBytes(int* n, int numToSwap) { for (int 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(unsigned int* n, int numToSwap) { swapBytes((int*)n, numToSwap); } /** * Swap bytes for the specified type. */ void ByteSwapping::swapBytes(long long* n, int numToSwap) { for (int 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(unsigned long long* n, int numToSwap) { swapBytes((long long*)n, numToSwap); } /** * Swap bytes for the specified type. */ void ByteSwapping::swapBytes(float* n, int numToSwap) { swapBytes((int*)n, numToSwap); } /** * Swap bytes for the specified type. */ void ByteSwapping::swapBytes(double* n, int numToSwap) { swapBytes((long long*)n, numToSwap); } caret-5.6.4~dfsg.1.orig/caret_files/BrainVoyagerFile.h0000664000175000017500000001137611572067322022412 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_BRAIN_VOYAGER_FILE_H__ #define __VE_BRAIN_VOYAGER_FILE_H__ #include "AbstractFile.h" /// class to hold colors class BrainVoyagerColorTableElement { public: /// constructor BrainVoyagerColorTableElement(const int brainVoyagerIndexIn); /// constructor BrainVoyagerColorTableElement(); /// destructor ~BrainVoyagerColorTableElement(); /// get the color name QString getColorName() const { return name; } /// get the rgb components void getRgb(unsigned char rgbOut[3]) const; private: /// initialize the instance void initialize(); /// name of color QString name; /// rgb components unsigned char rgb[3]; /// index in BrainVoyagerFile int brainVoyagerIndex; friend class BrainVoyagerFile; }; /// class to read a brain voyager file class BrainVoyagerFile : public AbstractFile { public: /// constructor BrainVoyagerFile(); /// constructor ~BrainVoyagerFile(); /// clear the file void clear(); /// returns true if the file is isEmpty (contains no data) bool empty() const { return false; } //(getNumberOfTiles() == 0); } /// get number of color table elements int getColorTableSize() { return colorTable.size(); } /// get a color table element const BrainVoyagerColorTableElement* getColorTableElement(const int index) const { return &colorTable[index]; } /// get the number of vertices int getNumberOfVertices() const { return numberOfVertices; } /// get the number of triangles int getNumberOfTriangles() const { return numberOfTriangles; } /// get coordinates of a vertex void getVertexCoordinates(const int vertexNumber, float xyz[3]) const; /// get vertices of a tile void getTriangle(const int triangleNumber, int verts[3]) const; /// get the vertex color void getVertexColor(const int vertexNumber, unsigned char rgb[3]) const; /// get the vertices color index int getVertexColorIndex(const int vertexNumber) const { return vertexColorTableIndices[vertexNumber]; }; /// read the specified file void readFile(const QString& filenameIn) throw (FileException); /// Write the current file's memory to the specified name void writeFile(const QString& filenameIn) throw (FileException); private: /// read file void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException); /// write file void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException); /// version of brain voyager file float version; /// number of vertices int numberOfVertices; /// number of triangles int numberOfTriangles; /// X coordinates of vertices float* verticesX; /// X coordinates of vertices float* verticesY; /// X coordinates of vertices float* verticesZ; /// color indices std::vector colorTable; /// color table indices int* vertexColorTableIndices; /// red vertex color unsigned char* vertexRedComponent; /// green vertex color unsigned char* vertexGreenComponent; /// blue vertex color unsigned char* vertexBlueComponent; /// alpha vertex color unsigned char* vertexAlphaComponent; /// the triangles int* triangles; }; #endif // __VE_BRAIN_VOYAGER_FILE_H__ caret-5.6.4~dfsg.1.orig/caret_files/BrainVoyagerFile.cxx0000664000175000017500000006241711572067322022767 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include "BrainVoyagerFile.h" #include "ByteSwapping.h" #include "DebugControl.h" #include "FileUtilities.h" #include "SpecFile.h" /** * Constructor. */ BrainVoyagerFile::BrainVoyagerFile() : AbstractFile("Brain Voyager File", SpecFile::getBrainVoyagerFileExtension(), false, AbstractFile::FILE_FORMAT_BINARY, FILE_IO_NONE, FILE_IO_READ_ONLY, FILE_IO_NONE, FILE_IO_NONE) { verticesX = NULL; verticesY = NULL; verticesZ = NULL; vertexRedComponent = NULL; vertexGreenComponent = NULL; vertexBlueComponent = NULL; vertexAlphaComponent = NULL; vertexColorTableIndices = NULL; triangles = NULL; clear(); } /** * Destructor. */ BrainVoyagerFile::~BrainVoyagerFile() { clear(); } /** * clear the files contents. */ void BrainVoyagerFile::clear() { clearAbstractFile(); version = -1.0; numberOfVertices = 0; numberOfTriangles = 0; if (verticesX != NULL) { delete[] verticesX; verticesX = NULL; } if (verticesY != NULL) { delete[] verticesY; verticesY = NULL; } if (verticesZ != NULL) { delete[] verticesZ; verticesZ = NULL; } if (vertexRedComponent != NULL) { delete[] vertexRedComponent; vertexRedComponent = NULL; } if (vertexGreenComponent != NULL) { delete[] vertexGreenComponent; vertexGreenComponent = NULL; } if (vertexBlueComponent != NULL) { delete[] vertexBlueComponent; vertexBlueComponent = NULL; } if (vertexAlphaComponent != NULL) { delete[] vertexAlphaComponent; vertexAlphaComponent = NULL; } if (vertexColorTableIndices != NULL) { delete[] vertexColorTableIndices; vertexColorTableIndices = NULL; } if (triangles != NULL) { delete[] triangles; triangles = NULL; } colorTable.clear(); } /** * get coordinates of a vertex. */ void BrainVoyagerFile::getVertexCoordinates(const int vertexNumber, float xyz[3]) const { if (vertexNumber < numberOfVertices) { xyz[0] = verticesX[vertexNumber]; xyz[1] = verticesY[vertexNumber]; xyz[2] = verticesZ[vertexNumber]; } } /** * get vertices of a tile. */ void BrainVoyagerFile::getTriangle(const int triangleNumber, int verts[3]) const { if (triangleNumber < numberOfTriangles) { verts[0] = triangles[triangleNumber * 3]; verts[1] = triangles[triangleNumber * 3 + 1]; verts[2] = triangles[triangleNumber * 3 + 2]; } } /** * get the vertex color. */ void BrainVoyagerFile::getVertexColor(const int vertexNumber, unsigned char rgb[3]) const { if (vertexNumber < numberOfVertices) { rgb[0] = static_cast(vertexRedComponent[vertexNumber]); rgb[1] = static_cast(vertexGreenComponent[vertexNumber]); rgb[2] = static_cast(vertexBlueComponent[vertexNumber]); } } /** * Write the file's data (not used). */ void BrainVoyagerFile::readFileData(QFile& /*file*/, QTextStream& /*stream*/, QDataStream&, QDomElement& /* rootElement */) throw (FileException) { throw FileException(filename, "Program Error: BrainVoyagerFile::readFileData should never be called"); } /** * Read the file's data (not used). */ void BrainVoyagerFile::writeFileData(QTextStream& /*stream*/, QDataStream&, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException) { throw FileException(filename, "Program Error: BrainVoyagerFile::writeFileData should never be called"); } /** * Read the file (overrides AbstractFile method). */ void BrainVoyagerFile::readFile(const QString& filenameIn) throw (FileException) { const QString filename2(filenameIn); clear(); filename = filename2; // // MSB systems will need to byte swap // //int wordSize; //bool bigEndian; //qSysInfo(&wordSize, &bigEndian); const bool needToByteSwap = (QSysInfo::ByteOrder == QSysInfo::BigEndian); QTime timer; timer.start(); std::ifstream file(filename.toAscii().constData(), std::ios::in | std::ios::binary); if (file.bad() || file.fail()) { throw FileException(filename, "Failure trying to open: "); } else { try { int intDummy; float floatDummy; file.read((char*)&version, sizeof(version));; file.read((char*)&intDummy, sizeof(intDummy)); file.read((char*)&numberOfVertices, sizeof(numberOfVertices)); file.read((char*)&numberOfTriangles, sizeof(numberOfTriangles)); if (DebugControl::getDebugOn()) { float fv = version; ByteSwapping::swapBytes(&fv, 1); std::cout << "version: " << version << " version byte swapped: " << fv << std::endl; } file.read((char*)&floatDummy, sizeof(floatDummy)); // mesh center x file.read((char*)&floatDummy, sizeof(floatDummy)); // mesh center y file.read((char*)&floatDummy, sizeof(floatDummy)); // mesh center z if (needToByteSwap) { ByteSwapping::swapBytes(&version, 1); ByteSwapping::swapBytes(&numberOfVertices, 1); ByteSwapping::swapBytes(&numberOfTriangles, 1); } if (numberOfVertices > 0) { // // Read vertices // verticesX = new float[numberOfVertices]; verticesY = new float[numberOfVertices]; verticesZ = new float[numberOfVertices]; file.read((char*)verticesX, (numberOfVertices * 4)); file.read((char*)verticesY, (numberOfVertices * 4)); file.read((char*)verticesZ, (numberOfVertices * 4)); if (needToByteSwap) { ByteSwapping::swapBytes(verticesX, numberOfVertices); ByteSwapping::swapBytes(verticesY, numberOfVertices); ByteSwapping::swapBytes(verticesZ, numberOfVertices); } // // Skip normals // file.seekg(numberOfVertices * 4 * 3, std::ios::cur); } float redConvexCurvature, greenConvexCurvature, blueConvexCurvature; file.read((char*)&redConvexCurvature, sizeof(redConvexCurvature)); file.read((char*)&greenConvexCurvature, sizeof(greenConvexCurvature)); file.read((char*)&blueConvexCurvature, sizeof(blueConvexCurvature)); file.read((char*)&floatDummy, sizeof(floatDummy)); // alpha convex curvature if (needToByteSwap) { ByteSwapping::swapBytes(&redConvexCurvature, 1); ByteSwapping::swapBytes(&greenConvexCurvature, 1); ByteSwapping::swapBytes(&blueConvexCurvature, 1); } const unsigned char redConvex = static_cast(redConvexCurvature * 255.0); const unsigned char greenConvex = static_cast(greenConvexCurvature * 255.0); const unsigned char blueConvex = static_cast(blueConvexCurvature * 255.0); float redConcaveCurvature, greenConcaveCurvature, blueConcaveCurvature; file.read((char*)&redConcaveCurvature, sizeof(redConcaveCurvature)); file.read((char*)&greenConcaveCurvature, sizeof(greenConcaveCurvature)); file.read((char*)&blueConcaveCurvature, sizeof(blueConcaveCurvature)); file.read((char*)&floatDummy, sizeof(floatDummy)); // alpha concave curvature if (needToByteSwap) { ByteSwapping::swapBytes(&redConcaveCurvature, 1); ByteSwapping::swapBytes(&greenConcaveCurvature, 1); ByteSwapping::swapBytes(&blueConcaveCurvature, 1); } const unsigned char redConcave = static_cast(redConcaveCurvature * 255.0); const unsigned char greenConcave = static_cast(greenConcaveCurvature * 255.0); const unsigned char blueConcave = static_cast(blueConcaveCurvature * 255.0); // // Color indicies - Create color table // if (numberOfVertices > 0) { vertexColorTableIndices = new int[numberOfVertices]; unsigned char dummyUnsignedChar; for (int i = 0; i < numberOfVertices; i++) { unsigned char index; file.read((char*)&index, sizeof(index)); file.read((char*)&dummyUnsignedChar, sizeof(dummyUnsignedChar)); file.read((char*)&dummyUnsignedChar, sizeof(dummyUnsignedChar)); file.read((char*)&dummyUnsignedChar, sizeof(dummyUnsignedChar)); // // See if color index already in color table // int colorTableIndex = -1; for (unsigned int j = 0; j < colorTable.size(); j++) { if (colorTable[j].brainVoyagerIndex == index) { colorTableIndex = static_cast(j); } } // // Create new color table element ? // if (colorTableIndex < 0) { colorTable.push_back(BrainVoyagerColorTableElement(index)); colorTableIndex = static_cast(colorTable.size()) - 1; } // // set vertice's color table index // vertexColorTableIndices[i] = colorTableIndex; } // // Set the convex and concave colors that are colors 0 & 1 // if (colorTable.size() > 1) { colorTable[0].name.append("_convex"); colorTable[0].rgb[0] = redConvex; colorTable[0].rgb[1] = greenConvex; colorTable[0].rgb[2] = blueConvex; colorTable[1].name.append("_concave"); colorTable[1].rgb[0] = redConcave; colorTable[1].rgb[1] = greenConcave; colorTable[1].rgb[2] = blueConcave; } } /* // // Color components // if (numberOfVertices > 0) { vertexRedComponent = new unsigned char[numberOfVertices]; vertexGreenComponent = new unsigned char[numberOfVertices]; vertexBlueComponent = new unsigned char[numberOfVertices]; vertexAlphaComponent = new unsigned char[numberOfVertices]; for (int i = 0; i < numberOfVertices; i++) { stream >> vertexRedComponent[i]; stream >> vertexGreenComponent[i]; stream >> vertexBlueComponent[i]; stream >> vertexAlphaComponent[i]; if (vertexRedComponent[i] == 0) { vertexRedComponent[i] = redConvex; vertexGreenComponent[i] = greenConvex; vertexBlueComponent[i] = blueConvex; } else if (vertexRedComponent[i] == 1) { vertexRedComponent[i] = redConcave; vertexGreenComponent[i] = greenConcave; vertexBlueComponent[i] = blueConcave; } //if (vertexRedComponent[i] != 0) { std::cout << "node " << i << " (" << static_cast(vertexRedComponent[i]) << " ," << static_cast(vertexGreenComponent[i]) << " ," << static_cast(vertexBlueComponent[i]) << " ," << static_cast(vertexAlphaComponent[i]) << ")" << std::endl; //} } } */ // // Vertex Neighbors // for (int i = 0; i < numberOfVertices; i++) { int numNeighbors; file.read((char*)&numNeighbors, sizeof(numNeighbors)); if (needToByteSwap) { ByteSwapping::swapBytes(&numNeighbors, 1); } if (i == 147644) { std::cout << "Node " << i << " has " << numNeighbors << " neighbors." << std::endl; } for (int j = 0; j < numNeighbors; j++) { file.read((char*)&intDummy, sizeof(intDummy)); } } // // Triangles // triangles = new int[numberOfTriangles * 3]; file.read((char*)triangles, numberOfTriangles * 3 * 4); if (needToByteSwap) { ByteSwapping::swapBytes(triangles, numberOfTriangles * 3); } // // Number of string elements // int numberOfStripElements; file.read((char*)&numberOfStripElements, sizeof(numberOfStripElements)); if (needToByteSwap) { ByteSwapping::swapBytes(&numberOfStripElements, 1); } //if (DebugControl::getDebugOn()) { std::cout << "Version: " << version << std::endl; std::cout << "Number of vertices: " << numberOfVertices << std::endl; std::cout << "Number of triangles: " << numberOfTriangles << std::endl; std::cout << "Number of strip elements: " << numberOfStripElements << std::endl; std::cout << "Color table size: " << colorTable.size() << std::endl; //} clearModified(); } catch (FileException& e) { file.close(); clearModified(); throw e; } file.close(); } if (DebugControl::getDebugOn()) { std::cout << "Time to read " << FileUtilities::basename(filename).toAscii().constData() << " was " << (static_cast(timer.elapsed()) / 1000.0) << " seconds." << std::endl; } } /** * Read the file. */ /* void BrainVoyagerFile::readFile(const QString& filenameIn) throw (FileException) { const QString filename2(filenameIn); clear(); filename = filename2); // // We always need to byte swap on both MSB & LSB systems. It is // something to do with the way QDataStream works. // const bool needToByteSwap = true; QTime timer; timer.start(); QFile file(filename); if (file.open(IO_ReadOnly)) { try { QDataStream stream(&file); stream.setVersion(QDataStream::Qt_4_3); if (DebugControl::getDebugOn()) { switch(stream.byteOrder()) { case QDataStream::BigEndian: std::cout << "Brain Voyager File stream is big endian" << std::endl; break; case QDataStream::LittleEndian: std::cout << "Brain Voyager File stream is little endian" << std::endl; break; } } int intDummy; float floatDummy; stream >> version; stream >> intDummy; stream >> numberOfVertices; stream >> numberOfTriangles; if (DebugControl::getDebugOn()) { float fv = version; ByteSwapping::swapBytes(&fv, 1); std::cout << "version: " << version << " version byte swapped: " << fv << std::endl; } stream >> floatDummy; // mesh center x stream >> floatDummy; // mesh center y stream >> floatDummy; // mesh center z if (needToByteSwap) { ByteSwapping::swapBytes(&version, 1); ByteSwapping::swapBytes(&numberOfVertices, 1); ByteSwapping::swapBytes(&numberOfTriangles, 1); } if (numberOfVertices > 0) { // // Read vertices // verticesX = new float[numberOfVertices]; verticesY = new float[numberOfVertices]; verticesZ = new float[numberOfVertices]; stream.readRawBytes((char*)verticesX, (numberOfVertices * 4)); stream.readRawBytes((char*)verticesY, (numberOfVertices * 4)); stream.readRawBytes((char*)verticesZ, (numberOfVertices * 4)); if (needToByteSwap) { ByteSwapping::swapBytes(verticesX, numberOfVertices); ByteSwapping::swapBytes(verticesY, numberOfVertices); ByteSwapping::swapBytes(verticesZ, numberOfVertices); } // // Skip normals // QIODevice::Offset pos = file.at(); pos += numberOfVertices * 4 * 3; file.at(pos); } float redConvexCurvature, greenConvexCurvature, blueConvexCurvature; stream >> redConvexCurvature; stream >> greenConvexCurvature; stream >> blueConvexCurvature; stream >> floatDummy; // alpha convex curvature if (needToByteSwap) { ByteSwapping::swapBytes(&redConvexCurvature, 1); ByteSwapping::swapBytes(&greenConvexCurvature, 1); ByteSwapping::swapBytes(&blueConvexCurvature, 1); } const unsigned char redConvex = static_cast(redConvexCurvature * 255.0); const unsigned char greenConvex = static_cast(greenConvexCurvature * 255.0); const unsigned char blueConvex = static_cast(blueConvexCurvature * 255.0); float redConcaveCurvature, greenConcaveCurvature, blueConcaveCurvature; stream >> redConcaveCurvature; stream >> greenConcaveCurvature; stream >> blueConcaveCurvature; stream >> floatDummy; // alpha concave curvature if (needToByteSwap) { ByteSwapping::swapBytes(&redConcaveCurvature, 1); ByteSwapping::swapBytes(&greenConcaveCurvature, 1); ByteSwapping::swapBytes(&blueConcaveCurvature, 1); } const unsigned char redConcave = static_cast(redConcaveCurvature * 255.0); const unsigned char greenConcave = static_cast(greenConcaveCurvature * 255.0); const unsigned char blueConcave = static_cast(blueConcaveCurvature * 255.0); // // Color indicies - Create color table // if (numberOfVertices > 0) { vertexColorTableIndices = new int[numberOfVertices]; unsigned char dummyUnsignedChar; for (int i = 0; i < numberOfVertices; i++) { unsigned char index; stream >> index; stream >> dummyUnsignedChar; stream >> dummyUnsignedChar; stream >> dummyUnsignedChar; // // See if color index already in color table // int colorTableIndex = -1; for (unsigned int j = 0; j < colorTable.size(); j++) { if (colorTable[j].brainVoyagerIndex == index) { colorTableIndex = static_cast(j); } } // // Create new color table element ? // if (colorTableIndex < 0) { colorTable.push_back(BrainVoyagerColorTableElement(index)); colorTableIndex = static_cast(colorTable.size()); } // // set vertice's color table index // vertexColorTableIndices[i] = colorTableIndex; } // // Set the convex and concave colors that are colors 0 & 1 // if (colorTable.size() > 1) { colorTable[0].name.append("_convex"); colorTable[0].rgb[0] = redConvex; colorTable[0].rgb[1] = greenConvex; colorTable[0].rgb[2] = blueConvex; colorTable[1].name.append("_concave"); colorTable[1].rgb[0] = redConcave; colorTable[1].rgb[1] = greenConcave; colorTable[1].rgb[2] = blueConcave; } } // // Vertex Neighbors // for (int i = 0; i < numberOfVertices; i++) { int numNeighbors; stream >> numNeighbors; if (needToByteSwap) { ByteSwapping::swapBytes(&numNeighbors, 1); } if (i == 147644) { std::cout << "Node " << i << " has " << numNeighbors << " neighbors." << std::endl; } for (int j = 0; j < numNeighbors; j++) { stream >> intDummy; } } // // Triangles // triangles = new int[numberOfTriangles * 3]; stream.readRawBytes((char*)triangles, numberOfTriangles * 3 * 4); if (needToByteSwap) { ByteSwapping::swapBytes(triangles, numberOfTriangles * 3); } // // Number of string elements // int numberOfStripElements; stream >> numberOfStripElements; if (needToByteSwap) { ByteSwapping::swapBytes(&numberOfStripElements, 1); } //if (DebugControl::getDebugOn()) { std::cout << "Version: " << version << std::endl; std::cout << "Number of vertices: " << numberOfVertices << std::endl; std::cout << "Number of triangles: " << numberOfTriangles << std::endl; std::cout << "Number of strip elements: " << numberOfStripElements << std::endl; //} clearModified(); } catch (FileException& e) { file.close(); clearModified(); throw e; } file.close(); } else { throw FileException(filename, "Failure trying to open: "); } if (DebugControl::getDebugOn()) { std::cout << "Time to read " << FileUtilities::basename(filename) << " was " << (static_cast(timer.elapsed()) / 1000.0) << " seconds." << std::endl; } } */ /** * Write the file. */ void BrainVoyagerFile::writeFile(const QString& filenameIn) throw (FileException) { throw FileException(filenameIn, "Writing brain voyager file not supported."); } //--------------------------------------------------------------------------------- /** * Constructor. */ BrainVoyagerColorTableElement::BrainVoyagerColorTableElement(const int brainVoyagerIndexIn) { initialize(); brainVoyagerIndex = brainVoyagerIndexIn; std::ostringstream str; str << "Color_" << brainVoyagerIndex; name = str.str().c_str(); switch(brainVoyagerIndex) { case 24: name.append("_white_med_wall_and_cuts"); rgb[0] = 255; rgb[1] = 255; rgb[2] = 255; break; case 32: name.append("_bright_blue"); rgb[0] = 24; rgb[1] = 93; rgb[2] = 255; break; case 33: name.append("_dark_blue"); rgb[0] = 16; rgb[1] = 80; rgb[2] = 222; break; case 34: name.append("_bright_green"); rgb[0] = 16; rgb[1] = 255; rgb[2] = 98; break; case 35: name.append("_dark_green"); rgb[0] = 24; rgb[1] = 218; rgb[2] = 82; break; case 240: name.append("_light_gray_cuts"); rgb[0] = 200; rgb[1] = 200; rgb[2] = 200; break; } } /** * Constructor. */ BrainVoyagerColorTableElement::BrainVoyagerColorTableElement() { initialize(); } /** * Destructor. */ BrainVoyagerColorTableElement::~BrainVoyagerColorTableElement() { } /** * */ void BrainVoyagerColorTableElement::getRgb(unsigned char rgbOut[3]) const { rgbOut[0] = rgb[0]; rgbOut[1] = rgb[1]; rgbOut[2] = rgb[2]; } /** * Initialize the elements. */ void BrainVoyagerColorTableElement::initialize() { brainVoyagerIndex = -1; rgb[0] = 255; rgb[1] = 0; rgb[2] = 0; } caret-5.6.4~dfsg.1.orig/caret_files/BorderProjectionFile.h0000664000175000017500000003633711572067322023300 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_BORDER_PROJECTION_FILE_H__ #define __VE_BORDER_PROJECTION_FILE_H__ #include "AbstractFile.h" class Border; class BorderProjectionFile; class ColorFile; class CoordinateFile; class TopologyHelper; /// Class for storing a border projection link. class BorderProjectionLink { public: /// Constructor BorderProjectionLink(const int sectionIn, const int verticesIn[3], const float areasIn[3], const float radiusIn); /// Destructor ~BorderProjectionLink(); /// determine if two border projection links are the same bool operator==(const BorderProjectionLink& bpl) const; /// set border data void setData(const int sectionIn, const int verticesIn[3], const float areasIn[3], const float radiusIn); /// get border data void getData(int& sectionOut, int verticesOut[3], float areasOut[3], float& radiusOut) const; /// unproject a border link void unprojectLink(const CoordinateFile* unprojectCoordFile, float xyzOut[3]) const; private: /// border projection file this border projection belongs to BorderProjectionFile* borderProjectionFile; /// section of this border projection point int section; /// vertices for this border projection point int vertices[3]; /// barycentric areas for this border projection point float areas[3]; /// radius of border point float radius; friend class BorderProjection; friend class BorderProjectionFile; }; /// Class for storing a border projection. class BorderProjection { public: /// constructor BorderProjection(const QString& nameIn = "_no_name_", const float* centerIn3 = NULL, const float samplingDensityIn = 25.0, const float varianceIn = 1.0, const float topographyIn = 0.0, const float arealUncertaintyIn = 0.0); /// destructor ~BorderProjection(); /// determine if two border projections are the same bool operator==(const BorderProjection& bp) const; /// append a border projection to this border projection void append(const BorderProjection& bp); /// add a border projection link void addBorderProjectionLink(const BorderProjectionLink& bl); /// add border projection link directly on node void addBorderProjectionLinkOnNode(const int nodeNumber); /// get borders attribute data void getData(QString& nameOut, float centerOut[3], float& samplingDensityOut, float& varianceOut, float& topographyOut, float& arealUncertaintyOut) const; /// get the sampling density for a border projection float getSamplingDensity() const { return samplingDensity; } /// set a borders attribute data void setData(const QString& nameIn, const float centerIn[3], const float samplingDensityIn, const float varianceIn, const float topographyIn, const float arealUncertaintyIn); /// return a pointer to a border link BorderProjectionLink* getBorderProjectionLink(const int i) { return &links[i]; } /// return a pointer to a border link const BorderProjectionLink* getBorderProjectionLink(const int i) const { return &links[i]; } /// get border color index int getBorderColorIndex() const { return borderColorIndex; } /// set border color index void setBorderColorIndex(const int bci) { borderColorIndex = bci; } /// get a border's name QString getName() const { return name; } /// set a border's name void setName(const QString& s) { name = s; } // return the number of links in this border projection int getNumberOfLinks() const { return links.size(); } /// get the unique ID int getUniqueID() const { return uniqueID; } /// get center of gravity void getCenterOfGravity(const CoordinateFile* coordFile, float centerOfGravityOut[3]) const; /// insert a border projection link before the specified link number (use number of links for end) void insertBorderProjectionLink(const int linkIndex, const BorderProjectionLink& bl); /// insert a border projection link before the specified link number (use number of links for end) void insertBorderProjectionLinkOnNode(const int linkIndex, const int nodeNumber); /// get a subset of the links as a border projection BorderProjection getSubSetOfBorderProjectionLinks(const int startLinkNumber, const int endLinkNumber) const; /// unproject a border void unprojectBorderProjection(const CoordinateFile* cf, Border& borderOut) const; /// unproject a border void unprojectBorderProjection(const CoordinateFile* cf, const TopologyHelper* th, Border& borderOut) const; /// get the link number nearest to a coordinate int getLinkNumberNearestToCoordinate(const CoordinateFile* cf, const float xyz[3]) const; /// get the link number furthest from a coordinate int getLinkNumberFurthestFromCoordinate(const CoordinateFile* cf, const float xyz[3]) const; /// split a border that is approximately linear in shape bool splitClosedBorderProjection(const CoordinateFile* cf, const int startingLinkNumber, const QString& newNameSuffix, BorderProjection& halfOneOut, BorderProjection& halfTwoOut, const int endingLinkNumber = -1); /// get the center of gravity for a border (returns true if valid) bool getCenterOfGravity(const CoordinateFile* cf, const TopologyHelper* th, float cogXYZOut[3]) const; /// change the starting link of a closed border so it is close to a point void changeStartingLinkOfClosedBorderToBeNearPoint(const CoordinateFile* cf, const float pointXYZ[3]); /// remove links from border within specified distances of point /// if a specified distance is zero or less it is ignored void removeLinksNearPoint(const CoordinateFile* unprojectCoordFile, const float pointXYZ[3], const float xDistance, const float yDistance, const float zDistance, const float straightLineDistance); /// remove links from border greater than specified distances of point /// if a specified distance is zero or less it is ignored void removeLinksAwayFromPoint(const CoordinateFile* unprojectCoordFile, const float pointXYZ[3], const float xDistance, const float yDistance, const float zDistance, const float straightLineDistance); /// remove links in border before/after link nearest to point void removeLinksBeforeAfterLinkNearestPoint(const CoordinateFile* cf, const float pointXYZ[3], const bool removeAfterFlag, const bool removeBeforeFlag); /// remove links from border that are not within the specified extent void removeLinksOutsideExtent(const CoordinateFile* unprojectCoordFile, const float extent[6]); /// remove the border projection link at the specified index void removeBorderProjectionLink(const int linkNumber); /// remove duplicate border projection links void removeDuplicateBorderProjectionLinks(); /// remove the last border projection link void removeLastBorderProjectionLink(); /// reverse the order of the border projection links void reverseOrderOfBorderProjectionLinks(); private: /// border projection file this border projection belongs to BorderProjectionFile* borderProjectionFile; /// the links in this border projection std::vector links; /// name of this border QString name; /// center of border (obsolete and unused) float center[3]; /// sampline density of this border float samplingDensity; /// variance of this border float variance; /// topography of this border float topographyValue; /// uncertainty of this border float arealUncertainty; /// index into border color file int borderColorIndex; /// unique identifier for this border projection int uniqueID; /// unique ID source static int uniqueIDSource; friend class BorderProjectionFile; }; /// Class for storing a border projection file. class BorderProjectionFile : public AbstractFile { public: /// constructor BorderProjectionFile(); /// destructor ~BorderProjectionFile(); /// append another border projection file to this one. void append(BorderProjectionFile& bpf); /// assign colors to the borders void assignColors(const ColorFile& colorFile); /// clear a border projection file void clear(); /// add a border projection void addBorderProjection(const BorderProjection& b); /// returns true if the file is isEmpty (contains no data) bool empty() const { return (getNumberOfBorderProjections() == 0); } /// get the indices of border projections that area duplicates of other border projections. void getDuplicateBorderProjectionIndices(std::vector& duplicateBorderProjIndices) const; /// get a specified border by index BorderProjection* getBorderProjection(const int i) { return &links[i]; } /// get a specified border by index const BorderProjection* getBorderProjection(const int i) const { return &links[i]; } /// get the index of a border projection int getBorderProjectionIndex(const BorderProjection* bp) const; /// get first specified border by name BorderProjection* getFirstBorderProjectionByName(const QString& name); /// get first specified border by name const BorderProjection* getFirstBorderProjectionByName(const QString& name) const; /// get last specified border by name BorderProjection* getLastBorderProjectionByName(const QString& name); /// get last specified border by name const BorderProjection* getLastBorderProjectionByName(const QString& name) const; /// get number of borders in this file int getNumberOfBorderProjections() const { return links.size(); } /// get a border projection with the specified unique ID BorderProjection* getBorderProjectionWithUniqueID(const int uniqueID); /// get the index of border projection with the specified unique ID int getBorderProjectionIndexWithUniqueID(const int uniqueID) const; /// get the border projection with the largest number of links BorderProjection* getBorderProjectionWithLargestNumberOfLinks(); /// remove border projection with the specified unique ID void removeBorderProjectionWithUniqueID(const int uniqueID); /// remove border projection at specified index void removeBorderProjection(const int index); /// remove borders with the specified indices. void removeBordersWithIndices(const std::vector& borderProjectionIndicesIn); /// remove borders with the specified name. void removeBordersWithName(const QString& nameIn); /// reverse order of links in all border projections void reverseOrderOfAllBorderProjections(); /// read the file's data void readFileData(QFile& file, QTextStream& stream, QDataStream&, QDomElement& /* rootElement */) throw (FileException); /// Write the file's data void writeFileData(QTextStream& stream, QDataStream&, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException); /// compare a file for unit testing (returns true if "within tolerance") virtual bool compareFileForUnitTesting(const AbstractFile* af, const float tolerance, QString& messageOut) const; /// write the file's memory in caret6 format to the specified name virtual QString writeFileInCaret6Format(const QString& filenameIn, Structure structure,const ColorFile* colorFileIn, const bool useCaret6ExtensionFlag) throw (FileException); private: /// this file's border projections std::vector links; friend class BorderProjection; friend class BorderProjectionLink; }; #endif // __VE_BORDER_PROJECTION_FILE_H__ #ifdef __BORDER_PROJECTION_MAIN__ int BorderProjection::uniqueIDSource = 1; #endif // __BORDER_PROJECTION_MAIN__ caret-5.6.4~dfsg.1.orig/caret_files/BorderProjectionFile.cxx0000664000175000017500000012645211572067322023651 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "XmlGenericWriter.h" #include #include #include "BorderFile.h" #define __BORDER_PROJECTION_MAIN__ #include "BorderProjectionFile.h" #undef __BORDER_PROJECTION_MAIN__ #include "ColorFile.h" #include "CoordinateFile.h" #include "MathUtilities.h" #include "SpecFile.h" #include "TopologyHelper.h" #include "Caret6ProjectedItem.h" /** * Constructor. */ BorderProjectionLink::BorderProjectionLink(const int sectionIn, const int verticesIn[3], const float areasIn[3], const float radiusIn) { borderProjectionFile = NULL; setData(sectionIn, verticesIn, areasIn, radiusIn); } /** * Destructor. */ BorderProjectionLink::~BorderProjectionLink() { } /// determine if two border projection links are the same bool BorderProjectionLink::operator==(const BorderProjectionLink& bpl) const { for (int i = 0; i < 3; i++) { if (vertices[i] != bpl.vertices[i]) { return false; } if (areas[i] != bpl.areas[i]) { return false; } } return true; } /** * Set the Link's data. */ void BorderProjectionLink::setData(const int sectionIn, const int verticesIn[3], const float areasIn[3], const float radiusIn) { section = sectionIn; vertices[0] = verticesIn[0]; vertices[1] = verticesIn[1]; vertices[2] = verticesIn[2]; areas[0] = areasIn[0]; areas[1] = areasIn[1]; areas[2] = areasIn[2]; radius = radiusIn; if (borderProjectionFile != NULL) { borderProjectionFile->setModified(); } } /** * Get the link's data. */ void BorderProjectionLink::getData(int& sectionOut, int verticesOut[3], float areasOut[3], float& radiusOut) const { sectionOut = section; verticesOut[0] = vertices[0]; verticesOut[1] = vertices[1]; verticesOut[2] = vertices[2]; areasOut[0] = areas[0]; areasOut[1] = areas[1]; areasOut[2] = areas[2]; radiusOut = radius; } /** * unproject a border link. */ void BorderProjectionLink::unprojectLink(const CoordinateFile* unprojectCoordFile, float xyzOut[3]) const { const float totalArea = areas[0] + areas[1] + areas[2]; if (totalArea > 0.0) { const float* v1 = unprojectCoordFile->getCoordinate(vertices[0]); const float* v2 = unprojectCoordFile->getCoordinate(vertices[1]); const float* v3 = unprojectCoordFile->getCoordinate(vertices[2]); xyzOut[0] = (v1[0] * areas[1] + v2[0] * areas[2] + v3[0] * areas[0]) / totalArea; xyzOut[1] = (v1[1] * areas[1] + v2[1] * areas[2] + v3[1] * areas[0]) / totalArea; xyzOut[2] = (v1[2] * areas[1] + v2[2] * areas[2] + v3[2] * areas[0]) / totalArea; } } /** * get center of gravity. */ void BorderProjection::getCenterOfGravity(const CoordinateFile* coordFile, float centerOfGravityOut[3]) const { centerOfGravityOut[0] = 0.0; centerOfGravityOut[1] = 0.0; centerOfGravityOut[2] = 0.0; if (coordFile == NULL) { return; } const int numLinks = getNumberOfLinks(); if (numLinks <= 0) { return; } // // Loop through links and compute center of gravity // double sum[3] = { 0.0, 0.0, 0.0 }; for (int i = 0; i < numLinks; i++) { // // Get link XYZ // float linkXYZ[3]; links[i].unprojectLink(coordFile, linkXYZ); sum[0] += linkXYZ[0]; sum[1] += linkXYZ[1]; sum[2] += linkXYZ[2]; } // // Set COG // centerOfGravityOut[0] = sum[0] / numLinks; centerOfGravityOut[1] = sum[1] / numLinks; centerOfGravityOut[2] = sum[2] / numLinks; } /** * remove links from border that are not within the specified extent. */ void BorderProjection::removeLinksOutsideExtent(const CoordinateFile* unprojectCoordFile, const float extent[6]) { // // Keeps track of links that are NOT nibbled // std::vector linkTemp; // // Loop through links // const int numLinks = getNumberOfLinks(); for (int i = 0; i < numLinks; i++) { // // Get link XYZ // float linkXYZ[3]; links[i].unprojectLink(unprojectCoordFile, linkXYZ); // // Keep link if it is within extent // if ((linkXYZ[0] >= extent[0]) && (linkXYZ[0] <= extent[1]) && (linkXYZ[1] >= extent[2]) && (linkXYZ[1] <= extent[3]) && (linkXYZ[2] >= extent[4]) && (linkXYZ[2] <= extent[5])) { linkTemp.push_back(links[i]); } } // // were links removed // if (links.size() != linkTemp.size()) { links = linkTemp; if (borderProjectionFile != NULL) { borderProjectionFile->setModified(); } } } /** * get the link number nearest to a coordinate. */ int BorderProjection::getLinkNumberNearestToCoordinate(const CoordinateFile* cf, const float xyz[3]) const { int nearestLinkNumber = -1; float nearestDistanceSQ = std::numeric_limits::max(); const int numLinks = getNumberOfLinks(); for (int i = 0; i < numLinks; i++) { float pos[3]; getBorderProjectionLink(i)->unprojectLink(cf, pos); const float distSQ = MathUtilities::distanceSquared3D(xyz, pos); if (distSQ < nearestDistanceSQ) { nearestDistanceSQ = distSQ; nearestLinkNumber = i; } } return nearestLinkNumber; } /** * get the link number furthest from a coordinate. */ int BorderProjection::getLinkNumberFurthestFromCoordinate(const CoordinateFile* cf, const float xyz[3]) const { int furthestLinkNumber = -1; float furthestDistanceSQ = -1.0; const int numLinks = getNumberOfLinks(); for (int i = 0; i < (numLinks - 1); i++) { float pos[3]; getBorderProjectionLink(i)->unprojectLink(cf, pos); const float distSQ = MathUtilities::distanceSquared3D(xyz, pos); if (distSQ > furthestDistanceSQ) { furthestDistanceSQ = distSQ; furthestLinkNumber = i; } } return furthestLinkNumber; } /** * split a border that is approximately linear in shape. * Returns true if successful. */ bool BorderProjection::splitClosedBorderProjection(const CoordinateFile* cf, const int startingLinkNumber, const QString& newNameSuffix, BorderProjection& halfOneOut, BorderProjection& halfTwoOut, const int endingLinkNumber) { const int numLinks = getNumberOfLinks(); if (numLinks < 3) { return false; } // // Get coordinate of starting link // float startXYZ[3]; getBorderProjectionLink(startingLinkNumber)->unprojectLink(cf, startXYZ); // // Get the border link furthest from the starting link // const int splitLinkNumber = ((endingLinkNumber >= 0) ? endingLinkNumber: getLinkNumberFurthestFromCoordinate(cf, startXYZ)); // // Set indices for splitting // int oneEnd = splitLinkNumber - 1; if (oneEnd < 0) { oneEnd = getNumberOfLinks() - 1; } int twoEnd = startingLinkNumber - 1; if (twoEnd < 0) { twoEnd = getNumberOfLinks() - 1; } // // Create the new borders // halfOneOut = getSubSetOfBorderProjectionLinks(startingLinkNumber, oneEnd); halfTwoOut = getSubSetOfBorderProjectionLinks(splitLinkNumber, twoEnd); // // Set the names of the output projections // halfOneOut.setName(getName() + newNameSuffix); halfTwoOut.setName(getName() + newNameSuffix); return true; } /** * unproject a border. */ void BorderProjection::unprojectBorderProjection(const CoordinateFile* cf, Border& borderOut) const { borderOut.clearLinks(); borderOut.setName(getName()); const int numLinks = getNumberOfLinks(); for (int i = 0; i < numLinks; i++) { const BorderProjectionLink* bpl = getBorderProjectionLink(i); float xyz[3]; bpl->unprojectLink(cf, xyz); borderOut.addBorderLink(xyz); } } /** * unproject a border. */ void BorderProjection::unprojectBorderProjection(const CoordinateFile* cf, const TopologyHelper* th, Border& borderOut) const { borderOut.clearLinks(); borderOut.setName(getName()); const int numLinks = getNumberOfLinks(); for (int i = 0; i < numLinks; i++) { const BorderProjectionLink* bpl = getBorderProjectionLink(i); if (th->getNodeHasNeighbors(bpl->vertices[0]) && th->getNodeHasNeighbors(bpl->vertices[1]) && th->getNodeHasNeighbors(bpl->vertices[2])) { float xyz[3]; bpl->unprojectLink(cf, xyz); borderOut.addBorderLink(xyz); } } } /** * get the center of gravity for a border. */ bool BorderProjection::getCenterOfGravity(const CoordinateFile* cf, const TopologyHelper* th, float cogXYZOut[3]) const { // // Unproject to get border // Border border; unprojectBorderProjection(cf, th, border); // // get border's COG // const bool valid = border.getCenterOfGravity(cogXYZOut); return valid; } /** * change the starting link of a closed border so it is close to a point. */ void BorderProjection::changeStartingLinkOfClosedBorderToBeNearPoint(const CoordinateFile* cf, const float pointXYZ[3]) { // // Unproject to a border // Border border; unprojectBorderProjection(cf, border); // // Find link nearest point // int closestLinkNumber = -1; float closestLinkDistance = std::numeric_limits::max(); const int numLinks = border.getNumberOfLinks(); for (int i = 0; i < numLinks; i++) { float xyz[3]; border.getLinkXYZ(i, xyz); const float dist = MathUtilities::distanceSquared3D(xyz, pointXYZ); if (dist < closestLinkDistance) { closestLinkDistance = dist; closestLinkNumber = i; } } // // If no links or closest link is first link // if (closestLinkNumber <= 0) { return; } // // Reorganize the links // const std::vector linksCopy = links; links.clear(); for (int i = closestLinkNumber; i < numLinks; i++) { addBorderProjectionLink(linksCopy[i]); } for (int i = 0; i < closestLinkNumber; i++) { addBorderProjectionLink(linksCopy[i]); } } /** * remove links in border before/after link nearest to point. */ void BorderProjection::removeLinksBeforeAfterLinkNearestPoint(const CoordinateFile* cf, const float pointXYZ[3], const bool removeAfterFlag, const bool removeBeforeFlag) { // // Unproject to a border // Border border; unprojectBorderProjection(cf, border); // // Find link nearest point // int closestLinkNumber = -1; float closestLinkDistance = std::numeric_limits::max(); const int numLinks = border.getNumberOfLinks(); for (int i = 0; i < numLinks; i++) { float xyz[3]; border.getLinkXYZ(i, xyz); const float dist = MathUtilities::distanceSquared3D(xyz, pointXYZ); if (dist < closestLinkDistance) { closestLinkDistance = dist; closestLinkNumber = i; } } // // If no links or closest link is first link // if (closestLinkNumber <= 0) { return; } // // keep needed the links // const std::vector linksCopy = links; links.clear(); if (removeBeforeFlag == false) { for (int i = 0; i < closestLinkNumber; i++) { addBorderProjectionLink(linksCopy[i]); } } if (removeAfterFlag == false) { for (int i = closestLinkNumber + 1; i < numLinks; i++) { addBorderProjectionLink(linksCopy[i]); } } } /** * remove links from border greater than specified distances of point * if a specified distance is zero or less it is ignored. */ void BorderProjection::removeLinksAwayFromPoint(const CoordinateFile* unprojectCoordFile, const float pointXYZ[3], const float xDistance, const float yDistance, const float zDistance, const float straightLineDistance) { // // Squared nibble distance // float squaredStraightLineDistance = straightLineDistance * straightLineDistance; // // Keeps track of links that are NOT nibbled // std::vector linkTemp; // // Loop through links // const int numLinks = getNumberOfLinks(); for (int i = 0; i < numLinks; i++) { // // Get link XYZ // float linkXYZ[3]; links[i].unprojectLink(unprojectCoordFile, linkXYZ); // // intially keep the link // bool keepLinkFlag = true; // // Get distance components // const float dx = std::fabs(pointXYZ[0] - linkXYZ[0]); const float dy = std::fabs(pointXYZ[1] - linkXYZ[1]); const float dz = std::fabs(pointXYZ[2] - linkXYZ[2]); // // Check distances // if (dx > xDistance) { keepLinkFlag = false; } else if (dy > yDistance) { keepLinkFlag = false; } else if (dz > zDistance) { keepLinkFlag = false; } else { // // Distance Squared from point to link // const float distanceSquared = dx*dx + dy*dy + dz*dz; if (distanceSquared > squaredStraightLineDistance) { keepLinkFlag = false; } } // // Should this link be kept // if (keepLinkFlag) { linkTemp.push_back(links[i]); } } // // were links removed // if (links.size() != linkTemp.size()) { links = linkTemp; if (borderProjectionFile != NULL) { borderProjectionFile->setModified(); } } } /** * remove links from border within specified distance of point. * if a specified distance is zero or less it is ignored */ void BorderProjection::removeLinksNearPoint(const CoordinateFile* unprojectCoordFile, const float pointXYZ[3], const float xDistance, const float yDistance, const float zDistance, const float straightLineDistance) { // // Squared nibble distance // float squaredStraightLineDistance = straightLineDistance * straightLineDistance; // // Keeps track of links that are NOT nibbled // std::vector linkTemp; // // Loop through links // const int numLinks = getNumberOfLinks(); for (int i = 0; i < numLinks; i++) { // // Get link XYZ // float linkXYZ[3]; links[i].unprojectLink(unprojectCoordFile, linkXYZ); // // intially keep the link // bool keepLinkFlag = true; // // Get distance components // const float dx = std::fabs(pointXYZ[0] - linkXYZ[0]); const float dy = std::fabs(pointXYZ[1] - linkXYZ[1]); const float dz = std::fabs(pointXYZ[2] - linkXYZ[2]); // // Check distances // if (dx < xDistance) { keepLinkFlag = false; } else if (dy < yDistance) { keepLinkFlag = false; } else if (dz < zDistance) { keepLinkFlag = false; } else { // // Distance Squared from point to link // const float distanceSquared = dx*dx + dy*dy + dz*dz; if (distanceSquared < squaredStraightLineDistance) { keepLinkFlag = false; } } // // Should this link be kept // if (keepLinkFlag) { linkTemp.push_back(links[i]); } } // // were links removed // if (links.size() != linkTemp.size()) { links = linkTemp; if (borderProjectionFile != NULL) { borderProjectionFile->setModified(); } } } /** * Remove the border projection link at the specified index */ void BorderProjection::removeBorderProjectionLink(const int linkNumber) { if (linkNumber < getNumberOfLinks()) { links.erase(links.begin() + linkNumber); if (borderProjectionFile != NULL) { borderProjectionFile->setModified(); } } } /** * reverse the order of the border projection links. */ void BorderProjection::reverseOrderOfBorderProjectionLinks() { if (links.empty() == false) { std::reverse(links.begin(), links.end()); if (borderProjectionFile != NULL) { borderProjectionFile->setModified(); } } } /** * Constructor. */ BorderProjection::BorderProjection(const QString& nameIn, const float* centerIn3, const float samplingDensityIn, const float varianceIn, const float topographyIn, const float arealUncertaintyIn) { uniqueID = uniqueIDSource++; borderProjectionFile = NULL; borderColorIndex = 0; float center[3] = { 0.0, 0.0, 0.0 }; if (centerIn3 != NULL) { center[0] = centerIn3[0]; center[1] = centerIn3[1]; center[2] = centerIn3[2]; } setData(nameIn, center, samplingDensityIn, varianceIn, topographyIn, arealUncertaintyIn); } /** * Destructor */ BorderProjection::~BorderProjection() { } /** * determine if two border projections are the same. */ bool BorderProjection::operator==(const BorderProjection& bp) const { const int numLinks = getNumberOfLinks(); if (numLinks != bp.getNumberOfLinks()) { return false; } if (getName() != bp.getName()) { return false; } for (int i = 0; i < numLinks; i++) { const BorderProjectionLink* b1 = getBorderProjectionLink(i); const BorderProjectionLink* b2 = bp.getBorderProjectionLink(i); if ((*b1 == *b2) == false) { return false; } } return true; } /** * Get the data from a border. */ void BorderProjection::getData(QString& nameOut, float centerOut[3], float& samplingDensityOut, float& varianceOut, float& topographyOut, float& arealUncertaintyOut) const { nameOut = name; centerOut[0] = center[0]; centerOut[1] = center[1]; centerOut[2] = center[2]; samplingDensityOut = samplingDensity; varianceOut = variance; topographyOut = topographyValue; arealUncertaintyOut = arealUncertainty; } /** * Set the data in a border. */ void BorderProjection::setData(const QString& nameIn, const float centerIn[3], const float samplingDensityIn, const float varianceIn, const float topographyIn, const float arealUncertaintyIn) { name = nameIn; center[0] = centerIn[0]; center[1] = centerIn[1]; center[2] = centerIn[2]; samplingDensity = samplingDensityIn; variance = varianceIn; topographyValue = topographyIn; arealUncertainty = arealUncertaintyIn; if (borderProjectionFile != NULL) { borderProjectionFile->setModified(); } } /** * append a border projection to this border projection. */ void BorderProjection::append(const BorderProjection& bp) { const int num = bp.getNumberOfLinks(); for (int i = 0; i < num; i++) { addBorderProjectionLink(*(bp.getBorderProjectionLink(i))); } } /** * add border projection link directly on node. */ void BorderProjection::addBorderProjectionLinkOnNode(const int nodeNumber) { const int nodes[3] = { nodeNumber, nodeNumber, nodeNumber }; const float areas[3] = { 0.333, 0.333, 0.334 }; BorderProjectionLink bpl(0, nodes, areas, 1.0); addBorderProjectionLink(bpl); } /** * Add a link to the border. */ void BorderProjection::addBorderProjectionLink(const BorderProjectionLink& bl) { // // Make sure border projection link is valid // if ((bl.vertices[0] >= 0) || (bl.vertices[1] >= 0) || (bl.vertices[2] >= 0.0)) { links.push_back(bl); const int indx = static_cast(links.size()) - 1; links[indx].borderProjectionFile = borderProjectionFile; } } /** * insert a border projection link before the specified link number (use number of links for end). */ void BorderProjection::insertBorderProjectionLink(const int linkIndex, const BorderProjectionLink& bl) { if (linkIndex >= getNumberOfLinks()) { addBorderProjectionLink(bl); } else if (linkIndex < getNumberOfLinks()) { links.insert(links.begin() + linkIndex, bl); links[linkIndex].borderProjectionFile = borderProjectionFile; } } /** * get a subset of the links as a border projection. */ BorderProjection BorderProjection::getSubSetOfBorderProjectionLinks(const int startLinkNumber, const int endLinkNumber) const { BorderProjection bp("Subset of " + getName()); if (startLinkNumber < endLinkNumber) { for (int i = startLinkNumber; i <= endLinkNumber; i++) { bp.addBorderProjectionLink(*getBorderProjectionLink(i)); } } else { const int numLinks = getNumberOfLinks() - 1; for (int i = startLinkNumber; i < numLinks; i++) { bp.addBorderProjectionLink(*getBorderProjectionLink(i)); } for (int i = 0; i <= endLinkNumber; i++) { bp.addBorderProjectionLink(*getBorderProjectionLink(i)); } } return bp; } /** * insert a border projection link before the specified link number (use number of links for end). */ void BorderProjection::insertBorderProjectionLinkOnNode(const int linkIndex, const int nodeNumber) { const int nodes[3] = { nodeNumber, nodeNumber, nodeNumber }; const float areas[3] = { 0.333, 0.333, 0.334 }; BorderProjectionLink bpl(0, nodes, areas, 1.0); insertBorderProjectionLink(linkIndex, bpl); } /** * remove duplicate border projection links. */ void BorderProjection::removeDuplicateBorderProjectionLinks() { const int num = getNumberOfLinks(); if (num > 0) { std::vector linksToDelete; for (int i = 0; i < (num - 1); i++) { const BorderProjectionLink* bpl = getBorderProjectionLink(i); for (int j = i + 1; j < num; j++) { const BorderProjectionLink* bpl2 = getBorderProjectionLink(j); if (*bpl == *bpl2) { linksToDelete.push_back(j); } } } std::unique(linksToDelete.begin(), linksToDelete.end()); std::sort(linksToDelete.begin(), linksToDelete.end()); std::reverse(linksToDelete.begin(), linksToDelete.end()); const int numToDelete = static_cast(linksToDelete.size()); for (int i = 0; i < numToDelete; i++) { removeBorderProjectionLink(linksToDelete[i]); } } } /** * remove the last border projection link. */ void BorderProjection::removeLastBorderProjectionLink() { const int num = getNumberOfLinks(); if (num > 0) { removeBorderProjectionLink(num - 1); } } /** * Constructor. */ BorderProjectionFile::BorderProjectionFile() : AbstractFile("Border Projection File", SpecFile::getBorderProjectionFileExtension()) { clear(); } /** * Destructor. */ BorderProjectionFile::~BorderProjectionFile() { clear(); } /** * Append a border projection file to this one. */ void BorderProjectionFile::append(BorderProjectionFile& bpf) { const int numProj = bpf.getNumberOfBorderProjections(); for (int i = 0; i < numProj; i++) { BorderProjection* bp = bpf.getBorderProjection(i); addBorderProjection(*bp); } // // transfer the file's comment // appendFileComment(bpf); } /** * Assign colors to these border projections. */ void BorderProjectionFile::assignColors(const ColorFile& colorFile) { const int numProj = getNumberOfBorderProjections(); for (int i = 0; i < numProj; i++) { BorderProjection* bp = getBorderProjection(i); bool match; bp->setBorderColorIndex(colorFile.getColorIndexByName(bp->getName(), match)); } } /** * Clear the border projection file's data. */ void BorderProjectionFile::clear() { clearAbstractFile(); BorderProjection::uniqueIDSource = 1; links.clear(); } /** * add a border projection to the file. */ void BorderProjectionFile::addBorderProjection(const BorderProjection& b) { links.push_back(b); const int indx = static_cast(links.size()) - 1; links[indx].borderProjectionFile = this; for (int i = 0; i < links[indx].getNumberOfLinks(); i++) { BorderProjectionLink* bpl = links[indx].getBorderProjectionLink(i); bpl->borderProjectionFile = this; } setModified(); } /** * get the indices of border projections that area duplicates of other border projections. */ void BorderProjectionFile::getDuplicateBorderProjectionIndices( std::vector& duplicateBorderProjIndices) const { duplicateBorderProjIndices.clear(); const int numBorders = getNumberOfBorderProjections(); for (int i = 0; i < (numBorders - 1); i++) { const BorderProjection* b = getBorderProjection(i); for (int j = i + 1; j < numBorders; j++) { const BorderProjection* b2 = getBorderProjection(j); if (*b == *b2) { duplicateBorderProjIndices.push_back(j); } } } } /** * get first specified border by name. */ BorderProjection* BorderProjectionFile::getFirstBorderProjectionByName(const QString& name) { const int numBorders = getNumberOfBorderProjections(); for (int i = 0; i < numBorders; i++) { BorderProjection* b = getBorderProjection(i); if (b->getName() == name) { return b; } } return NULL; } /** * get first specified border by name. */ const BorderProjection* BorderProjectionFile::getFirstBorderProjectionByName(const QString& name) const { const int numBorders = getNumberOfBorderProjections(); for (int i = 0; i < numBorders; i++) { const BorderProjection* b = getBorderProjection(i); if (b->getName() == name) { return b; } } return NULL; } /** * get last specified border by name. */ BorderProjection* BorderProjectionFile::getLastBorderProjectionByName(const QString& name) { const int numBorders = getNumberOfBorderProjections(); for (int i = (numBorders - 1); i >= 0; i--) { BorderProjection* b = getBorderProjection(i); if (b->getName() == name) { return b; } } return NULL; } /** * get last specified border by name. */ const BorderProjection* BorderProjectionFile::getLastBorderProjectionByName(const QString& name) const { const int numBorders = getNumberOfBorderProjections(); for (int i = (numBorders - 1); i >= 0; i--) { const BorderProjection* b = getBorderProjection(i); if (b->getName() == name) { return b; } } return NULL; } /** * Get the border projection with the unique ID */ BorderProjection* BorderProjectionFile::getBorderProjectionWithUniqueID(const int uniqueID) { const int indx = getBorderProjectionIndexWithUniqueID(uniqueID); if (indx >= 0) { return getBorderProjection(indx); } return NULL; } /** * Get the index of the border projection with the unique ID */ int BorderProjectionFile::getBorderProjectionIndexWithUniqueID(const int uniqueID) const { const int num = getNumberOfBorderProjections(); for (int i = 0; i < num; i++) { const BorderProjection* b = getBorderProjection(i); if (b->getUniqueID() == uniqueID) { return i; } } return -1; } /** * Remove the border projection with the specified ID */ void BorderProjectionFile::removeBorderProjectionWithUniqueID(const int uniqueID) { const int indx = getBorderProjectionIndexWithUniqueID(uniqueID); if (indx >= 0) { removeBorderProjection(indx); setModified(); } } /** * Remove the border projection at the specified index */ void BorderProjectionFile::removeBorderProjection(const int indx) { if (indx < getNumberOfBorderProjections()) { links.erase(links.begin() + indx); setModified(); } } /** * get the index of a border projection. */ int BorderProjectionFile::getBorderProjectionIndex(const BorderProjection* bp) const { const int num = getNumberOfBorderProjections(); for (int i = 0; i < num; i++) { if (bp == getBorderProjection(i)) { return i; } } return -1; } /** * get the border projection with the largest number of links. */ BorderProjection* BorderProjectionFile::getBorderProjectionWithLargestNumberOfLinks() { const int num = getNumberOfBorderProjections(); int mostLinks = -1; BorderProjection* mostLinksBJ = NULL; for (int i = 0; i < num; i++) { BorderProjection* bj = getBorderProjection(i); if (bj->getNumberOfLinks() > mostLinks) { mostLinks = bj->getNumberOfLinks(); mostLinksBJ = bj; } } return mostLinksBJ; } /** * reverse order of links in all border projections. */ void BorderProjectionFile::reverseOrderOfAllBorderProjections() { const int num = getNumberOfBorderProjections(); for (int i = 0; i < num; i++) { BorderProjection* bp = getBorderProjection(i); bp->reverseOrderOfBorderProjectionLinks(); } setModified(); } /** * remove borders with the specified name. */ void BorderProjectionFile::removeBordersWithName(const QString& nameIn) { std::vector indicesOfBorderToDelete; const int num = getNumberOfBorderProjections(); for (int i = 0; i < num; i++) { BorderProjection* bp = getBorderProjection(i); const QString s = bp->getName(); if (s == nameIn) { indicesOfBorderToDelete.push_back(i); } } removeBordersWithIndices(indicesOfBorderToDelete); } /** * remove borders with the specified indices. */ void BorderProjectionFile::removeBordersWithIndices(const std::vector& borderProjectionIndicesIn) { std::vector borderProjectionIndices = borderProjectionIndicesIn; std::sort(borderProjectionIndices.begin(), borderProjectionIndices.end()); const int num = static_cast(borderProjectionIndices.size()); for (int i = (num - 1); i >= 0; i--) { removeBorderProjection(borderProjectionIndices[i]); } } /** * compare a file for unit testing (returns true if "within tolerance"). */ bool BorderProjectionFile::compareFileForUnitTesting(const AbstractFile* af, const float tolerance, QString& messageOut) const { const BorderProjectionFile* bpf = dynamic_cast(af); if (bpf == NULL) { messageOut = "File for comparison is not a border projection file."; return false; } const int numProj = getNumberOfBorderProjections(); if (numProj != bpf->getNumberOfBorderProjections()) { messageOut = "Files have a different number of border projections."; return false; } for (int i = 0; i < numProj; i++) { const BorderProjection* bp1 = getBorderProjection(i); const BorderProjection* bp2 = bpf->getBorderProjection(i); if (bp1->getName() != bp2->getName()) { messageOut = "Border " + QString::number(i) + " names to not match " + bp1->getName() + " and " + bp2->getName(); return false; } const int numLinks = bp1->getNumberOfLinks(); if (numLinks != bp2->getNumberOfLinks()) { messageOut = "Border Projection has a different number of links."; return false; } for (int j = 0; j < numLinks; j++) { const BorderProjectionLink* link1 = bp1->getBorderProjectionLink(j); const BorderProjectionLink* link2 = bp2->getBorderProjectionLink(j); int s1, s2; int v1[3], v2[3]; float a1[3], a2[3]; float r1, r2; link1->getData(s1, v1, a1, r1); link2->getData(s2, v2, a2, r2); if ((v1[0] != v2[0]) || (v1[1] != v2[1]) || (v1[2] != v2[2])) { messageOut = "border link has non-matching vertices"; return false; } const float da1 = std::fabs(a1[0] - a2[0]); const float da2 = std::fabs(a1[1] - a2[1]); const float da3 = std::fabs(a1[2] - a2[2]); if ((da1 > tolerance) || (da2 > tolerance) || (da3 > tolerance)) { messageOut = "border link has non-matching areas"; return false; } } } return true; } /** * Read the border projection file data. */ void BorderProjectionFile::readFileData(QFile& /*file*/, QTextStream& stream, QDataStream&, QDomElement& /* rootElement */) throw (FileException) { // // Should reading data be skipped ? // if (getReadMetaDataOnlyFlag()) { return; } QString line; // 1st line contains number of borders readLine(stream, line); const int numBorders = line.toInt(); for (int i = 0; i < numBorders; i++) { readLine(stream, line); int borderNumber; int numLinks = 0; QString borderName; float samplingDensity = 25.0, variance = 1.0, topography = 0.0, uncertainty = 1.0; QTextStream(&line, QIODevice::ReadOnly) >> borderNumber >> numLinks >> borderName >> samplingDensity >> variance >> topography >> uncertainty; // line containing the center (ignore) float center[3] = { 0.0, 0.0, 0.0 }; readLine(stream, line); // create the border BorderProjection borderProj(borderName, center, samplingDensity, variance, topography, uncertainty); for (int j = 0; j < numLinks; j++) { readLine(stream, line); int sectionNumber; int vertices[3]; float areas[3]; float radius = 0.0; QTextStream(&line, QIODevice::ReadOnly) >> vertices[0] >> vertices[1] >> vertices[2] >> sectionNumber >> areas[0] >> areas[1] >> areas[2] >> radius; BorderProjectionLink bl(sectionNumber, vertices, areas, radius); bl.borderProjectionFile = this; borderProj.addBorderProjectionLink(bl); } addBorderProjection(borderProj); } } /** * Write the border projection file data. */ void BorderProjectionFile::writeFileData(QTextStream& stream, QDataStream&, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException) { int numBorders = getNumberOfBorderProjections(); // // only write borders that have links // int numBordersToWrite = 0; for (int i = 0; i < numBorders; i++) { if (getBorderProjection(i)->getNumberOfLinks() > 0) { numBordersToWrite++; } } stream << numBordersToWrite << "\n"; for (int i = 0; i < numBorders; i++) { BorderProjection* border = getBorderProjection(i); const int numLinks = border->getNumberOfLinks(); // // Only write borders with links // if (numLinks <= 0) { continue; } // write border number, number links, name, sampling, variance, topography QString name; float center[3]; float samplingDensity, variance, topography, uncertainty; border->getData(name, center, samplingDensity, variance, topography, uncertainty); stream << i << " " << numLinks << " " << name << " " << samplingDensity << " " << variance << " " << topography << " " << uncertainty << "\n"; // write border center (unused) stream << center[0] << " " << center[1] << " " << center[2] << "\n"; for (int j = 0; j < numLinks; j++) { BorderProjectionLink* bl = border->getBorderProjectionLink(j); // write vertices, section, and areas float areas[3]; float radius; int vertices[3]; int section; bl->getData(section, vertices, areas, radius); stream << vertices[0] << " " << vertices[1] << " " << vertices[2] << " " << section << " " << areas[0] << " " << areas[1] << " " << areas[2] << " " << radius << "\n"; } } } /** * Write the file's memory in caret6 format to the specified name. */ QString BorderProjectionFile::writeFileInCaret6Format(const QString& filenameIn, Structure structure,const ColorFile* colorFileIn, const bool useCaret6ExtensionFlag) throw (FileException) { int numBorders = this->getNumberOfBorderProjections(); if (numBorders <= 0) { throw FileException("Contains no borders"); } QFile file(filenameIn); if (AbstractFile::getOverwriteExistingFilesAllowed() == false) { if (file.exists()) { throw FileException("file exists and overwrite is prohibited."); } } if (file.open(QFile::WriteOnly) == false) { throw FileException("Unable to open for writing"); } QTextStream stream(&file); XmlGenericWriter xmlWriter(stream); xmlWriter.writeStartDocument(); XmlGenericWriterAttributes attributes; attributes.addAttribute("CaretFileType", "BorderProjection"); attributes.addAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); attributes.addAttribute("xsi:noNamespaceSchemaLocation", "http://brainvis.wustl.edu/caret6/xml_schemas/BorderProjectionFileSchema.xsd"); attributes.addAttribute("Version", "6.0"); xmlWriter.writeStartElement("CaretDataFile", attributes); this->writeHeaderXMLWriter(xmlWriter); GiftiLabelTable labelTable; if (colorFileIn != NULL) { labelTable.createLabelsFromColors(*colorFileIn); } labelTable.writeAsXML(xmlWriter); for (int i = 0; i < numBorders; i++) { BorderProjection* bp = this->getBorderProjection(i); int numLinks = bp->getNumberOfLinks(); if (numLinks > 0) { XmlGenericWriterAttributes attributes; attributes.addAttribute("Index", i); xmlWriter.writeStartElement("BorderProjection", attributes); xmlWriter.writeElementCData("Name", bp->getName()); QString structureName = "Invalid"; if (structure.isLeftCortex()) { structureName = "CortexLeft"; } else if (structure.isRightCortex()) { structureName = "CortexRight"; } else if (structure.isCerebellum()) { structureName = "Cerebellum"; } xmlWriter.writeElementCharacters("Structure", structureName); for (int j = 0; j < numLinks; j++) { BorderProjectionLink* bpl = bp->getBorderProjectionLink(j); int section, nodes[3]; float areas[3], radius; bpl->getData(section, nodes, areas, radius); // // Area and node indices do not match in Caret5 but // they do in Caret6 // In Caret5: node-index area-index // 0 1 // 1 2 // 2 0 // // But caret5 was clockwise order and we want // counter clockwise so // // node-index area-index // 2 0 // 1 2 // 0 1 // // int nodesCaret6[3]; float areasCaret6[3]; areasCaret6[0] = areas[0]; areasCaret6[1] = areas[2]; areasCaret6[2] = areas[1]; nodesCaret6[0] = nodes[2]; nodesCaret6[1] = nodes[1]; nodesCaret6[2] = nodes[0]; xmlWriter.writeStartElement("Projection"); xmlWriter.writeElementCharacters("Nodes", nodesCaret6, 3); xmlWriter.writeElementCharacters("Areas", areasCaret6, 3); xmlWriter.writeEndElement(); } xmlWriter.writeEndElement(); } } xmlWriter.writeEndElement(); xmlWriter.writeEndDocument(); file.close(); return filenameIn; } caret-5.6.4~dfsg.1.orig/caret_files/BorderFile.h0000664000175000017500000004461211572067322021236 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_BORDER_FILE_H__ #define __VE_BORDER_FILE_H__ #include #include "AbstractFile.h" #include "FileException.h" #include "SpecFile.h" class BorderFile; class ColorFile; class CoordinateFile; class TopologyFile; class TransformationMatrix; /// class for storing a single border class Border { private: /// Border File this border belongs to BorderFile* borderFile; /// the link coordinates in this border (3 per link) std::vector linkXYZ; /// the link radii (1 per link) std::vector linkRadii; /// the link flat normal vectors (3 per link) std::vector linkFlatNormal; /// the link section (1 per link) std::vector linkSection; /// name of this border QString name; /// center of border (obsolete and unused) float center[3]; /// sampline density of this border float samplingDensity; /// variance of this border float variance; /// topography of this border float topographyValue; /// uncertainty of this border float arealUncertainty; /// index into border color file int borderColorIndex; /// border projection identifier for this border (negative if not from border proj file) int borderProjectionID; /// border display flag (show the border) bool displayFlag; /// border name selected for display flag bool nameDisplayFlag; /// resample a border void resampleBorder(const float* xorig, const float* yorig, const float* zorig, const int numPointsIn, const float density, float* xout, float* yout, float* zout, const int numPointsOut); public: /// constructor Border(const QString& nameIn = "", const float* centerIn = NULL, const float samplingDensityIn = 25.0, const float varianceIn = 1.0, const float topographyIn = 0.0, const float arealUncertaintyIn = 0.0); /// determine if two borders are the same (same name and links) bool operator==(const Border& b) const; /// append a border this "this" one void appendBorder(const Border& b); /// Apply transformation matrix to border void applyTransformationMatrix(TransformationMatrix& tm); /// get the position for a link const float* getLinkXYZ(const int linkNumber) const { return &linkXYZ[linkNumber * 3]; } /// get the position for a link void getLinkXYZ(const int linkNumber, float xyz[3]) const; /// set the position of a link void setLinkXYZ(const int linkNumber, const float xyz[3]); /// get the radius for a link float getLinkRadius(const int linkNumber) const; /// set the radius for a link void setLinkRadius(const int linkNumber, const float radius); /// create a border with a subset of the border's links Border* getSubSet(const int linkStart, const int linkEnd) const; /// get the flat normal for a link const float* getLinkFlatNormal(const int linkNumber) const { return &linkFlatNormal[linkNumber * 3]; } /// set the flat normal for a link void setLinkFlatNormal(const int linkNumber, const float normal[3]); /// get the section number for a link int getLinkSectionNumber(const int linkNumber) const { return linkSection[linkNumber]; } /// compute flat normals for each link void computeFlatNormals(); /// set the section number of a link void setLinkSectionNumber(const int linkNumber, const int section); /// get the topography value float getTopographyValue() const { return topographyValue; } /// clear the border links void clearLinks(); /// add a border link void addBorderLink(const float xyz[3], const int section = 0, const float radius = 0.0); /// insert a border link before the specified link number (use number of links for end) void insertBorderLink(const int linkIndex, const float xyz[3], const int section = 0, const float radius = 0.0); /// find links where another border intersects this border (2D borders in X-Y plane) bool intersection2D(const Border* otherBorder, const bool thisBorderIsClosed, const bool otherBorderIsClosed, int& myLinkIntersect, int& otherLinkIntersect) const; /// find first link in "this" border that is within "tolerance" distance /// of a link in "other border" bool intersection3D(const Border* otherBorder, const float intersectionTolerance, int& myLinkIntersect, int& otherLinkIntersect) const; /// get total length of a border float getBorderLength() const; /// get borders attribute data void getData(QString& nameOut, float centerOut[3], float& samplingDensityOut, float& varianceOut, float& topographyOut, float& arealUncertaintyOut) const; /// get the uncertainty float getArealUncertainty() const { return arealUncertainty; } // set the uncertainty void setArealUncertainty(const float uncertainty); /// get the sampling density for a border float getSamplingDensity() const { return samplingDensity; } /// get the variance float getVariance() const { return variance; } /// set a borders attribute data void setData(const QString& nameIn, const float centerIn[3], const float samplingDensityIn, const float varianceIn, const float topographyIn, const float arealUncertaintyIn); /// return a pointer to a border link //BorderLink* getBorderLink(const int i) { return &links[i]; } /// get border color index int getBorderColorIndex() const { return borderColorIndex; } /// set border color index void setBorderColorIndex(const int bci) { borderColorIndex = bci; } /// get border projection identifier int getBorderProjectionID() const { return borderProjectionID; } /// set the border projection identifier void setBorderProjectionID(const int indx) { borderProjectionID = indx; } /// distance between two border links float distanceBetweenLinks(const int link1, const int link2) const; /// get a border's name QString getName() const { return name; } /// set a border's name void setName(const QString& nameIn) { name = nameIn; } /// get border selected for display (show the border) bool getDisplayFlag() const { return displayFlag; } /// set border selected for display (show the border) void setDisplayFlag(const bool df) { displayFlag = df; } /// get name selected for display flag bool getNameDisplayFlag() { return nameDisplayFlag; } /// set name selected for display flag void setNameDisplayFlag(const bool df) { nameDisplayFlag = df; } /// return the number of links in this border int getNumberOfLinks() const { return (linkXYZ.size() / 3); } /// get the bounds of border void getBounds(float bounds[6]) const; /// get the center of gravity of the border (returns true if valid) bool getCenterOfGravity(float cogXYZOut[3]) const; /// get the link number nearest to a coordinate int getLinkNumberNearestToCoordinate(const float xyz[3]) const; /// get the link number furthest from a coordinate int getLinkNumberFurthestFromCoordinate(const float xyz[3]) const; /// remove links on negative side of plane void removePointsOnNegativeSideOfPlane(const float planeNormal[3], const float pointInPlane[3]); /// orient the links clockwise void orientLinksClockwise(); /// orient the links counter-clockwise void orientLinksCounterClockwise(); /// See if points are inside a border (border assumed flat in X-Y plane) void pointsInsideBorder2D(const float* points, const int numPoints, std::vector& insideFlags, const bool checkNonNegativeZPointsOnly = false, const float zMinimum = 0.0) const; /// See if 3D points are inside a 3D border (transform all to screen axis) void pointsInsideBorder3D(const GLdouble* modelMatrix, const GLdouble* projectionMatrix, const GLint* viewport, const float* points, const int numPoints, std::vector& insideFlags, const bool checkNonNegativeScreenZPointsOnly = true) const; /// remove a border link void removeLink(const int linkNumber); // resample a border to the specified density (distance between links) void resampleBorderToDensity(const float density, const int minimumNumberOfLinks, int& newNumberOfLinks); /// resample a border so that it has the specified number of links void resampleBorderToNumberOfLinks(const int numberOfLinks); /// reverse the order of the links in a border void reverseBorderLinks(); /// remove landmark rater from name of border void removeLandmarkRaterInfoFromBorderName(); /// get the character that begins the landmark rater into in a border name static char getLandmarkRaterFirstChar() { return ':'; } /// smooth the border links void smoothBorderLinks(const int numberOfIterations, const bool closedBorderFlag, const std::vector* smoothTheseLinksOnly = NULL); /// remove intersecting loops in a border void removeIntersectingLoops(const char axisXYZ) throw (FileException); /// compare the name of two landmark borders /// only compares text before the semi-colon in the name static bool compareLandmarkBorderNames(const QString& name1, const QString& name2); /// interpolate two borders to create new borders (input borders will be resampled too) static void createInterpolatedBorders(Border* b1, Border* b2, const QString& namePrefix, const int numberOfNewBorders, const float sampling, std::vector& outputInterpolatedBorders) throw (FileException); friend class BorderFile; }; /// class for storing a border file class BorderFile : public AbstractFile { private: /// The borders std::vector borders; public: /// constructor BorderFile(const QString& descriptiveName = "Border File", const QString& defaultExtensionIn = SpecFile::getBorderFileExtension()); /// constructor that creates a border file from the tiles and coordinates BorderFile(const TopologyFile* tf, const CoordinateFile* cf); /// Constructor that creates a BorderFile from the coordinates in a coordinate file. BorderFile(const CoordinateFile* cf, const int maxLinksPerBorder = -1); /// destructor virtual ~BorderFile(); /// clear a border file void clear(); /// copy all the links into a coordinate file void copyLinksToCoordinateFile(CoordinateFile* cf); /// Create a border file that is an average of a group of border files static void createAverageBorderFile(const std::vector& inputBorderFiles, const float borderResampling, const bool sphereFlag, BorderFile& averageBorderFileOut) throw (FileException); /// add a border void addBorder(const Border& b); /// append a border file to this one void append(BorderFile& bf); /// assign colors to the borders void assignColors(const ColorFile& colorFile); /// Apply transformation matrix to border file void applyTransformationMatrix(TransformationMatrix& tm); /// compute the flat border file normals void computeFlatNormals(); /// returns true if the file is isEmpty (contains no data) bool empty() const { return (getNumberOfBorders() == 0); } /// get the indices of borders that area duplicates of other borders void getDuplicateBorderIndices(std::vector& duplicateBorderIndices) const; /// set status of all border display flags void setAllNameDisplayFlags(const bool status); /// set display flag for borders with specified name void setNameDisplayFlagForBordersWithName(const QString& name, const bool flag); /// get a specified border by index Border* getBorder(const int i) { return &borders[i]; } /// get a specified border by index (const method) const Border* getBorder(const int i) const { return &borders[i]; } /// get a specified border by its name Border* getBorderByName(const QString& nameToFind, const bool landmarkBordersFlag = false); /// get a specified border by its name (const method) const Border* getBorderByName(const QString& nameToFind, const bool landmarkBordersFlag = false) const; /// get a specified border index by its name int getBorderIndexByName(const QString& nameToFind, const bool landmarkBordersFlag = false) const; /// get a border with a projection ID Border* getBorderWithProjectionID(const int projectionID); /// get border index for border with projectionID int getBorderIndexForBorderWithProjectionID(const int projectionID) const; /// get number of borders in this file int getNumberOfBorders() const { return borders.size(); } /// get total number of links in a border file int getTotalNumberOfLinks(); /// remove a border from the border file void removeBorder(const int borderNumber); /// remove borders with the specified indices void removeBordersWithIndices(const std::vector& borderIndices); /// remove a border with the projection identifier void removeBorderWithProjectionID(const int projectionID); /// remove all projected borders (projection borders have projection ID >= 0) void removeAllProjectedBorders(); /// reset the border projection IDs so not linked to border projections void resetBorderProjectionIDs(); /// resample displayed borders void resampleDisplayedBorders(const float density); /// resample all borders void resampleAllBorders(const float density); /// resample to match landmark border file (borders with same names have same number of points) void resampleToMatchLandmarkBorders(const BorderFile& landmarkBorderFile) throw (FileException); /// compute landmark variability static void evaluateLandmarkVariability(const BorderFile& indivBorderFile, const BorderFile& atlasBorderFile, const float badThreshold, const float extremeThreshold, const bool useAbsoluteDistanceFlag, BorderFile& outputBorderFile, QString& outputTextReport) throw (FileException); /// orient displayed borders clockwise void orientDisplayedBordersClockwise(); /// reverse displayed borders void reverseDisplayedBorders(); /// set the radius of a spherical border file void setSphericalBorderRadius(const float radius); // convert configuration ID to spec file tag static QString convertConfigurationIDToSpecFileTag(const QString& configID); /// write the file's memory in caret6 format to the specified name virtual QString writeFileInCaret6Format(const QString& filenameIn, Structure structure,const ColorFile* colorFileIn, const bool useCaret6ExtensionFlag) throw (FileException); protected: /// read the file's data void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException); /// Write the file's data void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException); friend class Border; }; #endif caret-5.6.4~dfsg.1.orig/caret_files/BorderFile.cxx0000664000175000017500000022245211572067322021611 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #ifdef Q_OS_WIN32 #define NOMINMAX #endif #include #include #include #include #include #include "BorderFile.h" #include "ColorFile.h" #include "CoordinateFile.h" #include "DebugControl.h" #include "FileUtilities.h" #include "GiftiLabelTable.h" #include "MathUtilities.h" #include "StatisticDataGroup.h" #include "StatisticMeanAndDeviation.h" #include "TopologyFile.h" #include "TransformationMatrixFile.h" #include "Caret6ProjectedItem.h" /** * Constructor. */ Border::Border(const QString& nameIn, const float* centerIn, const float samplingDensityIn, const float varianceIn, const float topographyIn, const float arealUncertaintyIn) { borderFile = NULL; displayFlag = true; nameDisplayFlag = true; borderColorIndex = 0; borderProjectionID = -1; float center[3] = { 0.0, 0.0, 0.0 }; if (centerIn != NULL) { center[0] = centerIn[0]; center[1] = centerIn[1]; center[2] = centerIn[2]; } setData(nameIn, center, samplingDensityIn, varianceIn, topographyIn, arealUncertaintyIn); } /** * determine if two borders are the same (same name and links). */ bool Border::operator==(const Border& b) const { const int numLinks = getNumberOfLinks(); if (numLinks != b.getNumberOfLinks()) { return false; } if (getName() != b.getName()) { return false; } for (int i = 0 ; i < numLinks; i++) { float me[3], other[3]; getLinkXYZ(i, me); b.getLinkXYZ(i, other); for (int j = 0; j < 3; j++) { if (me[j] != other[j]) { return false; } } } return true; } /** * Apply transformation matrix to a border. */ void Border::applyTransformationMatrix(TransformationMatrix& tm) { const int numLinks = getNumberOfLinks(); for (int j = 0; j < numLinks; j++) { float xyz[3]; getLinkXYZ(j, xyz); double p[4] = { xyz[0], xyz[1], xyz[2], 1.0 }; tm.multiplyPoint(p); xyz[0] = p[0]; xyz[1] = p[1]; xyz[2] = p[2]; setLinkXYZ(j, xyz); } if (borderFile != NULL) { borderFile->setModified(); } } /** * append a border this "this" one. */ void Border::appendBorder(const Border& b) { const int numLinks = b.getNumberOfLinks(); for (int j = 0; j < numLinks; j++) { this->addBorderLink(b.getLinkXYZ(j), b.getLinkSectionNumber(j)); } } /** * Get the data from a border. */ void Border::getData(QString& nameOut, float centerOut[3], float& samplingDensityOut, float& varianceOut, float& topographyOut, float& arealUncertaintyOut) const { nameOut = name; centerOut[0] = center[0]; centerOut[1] = center[1]; centerOut[2] = center[2]; samplingDensityOut = samplingDensity; varianceOut = variance; topographyOut = topographyValue; arealUncertaintyOut = arealUncertainty; } /** * Set the data in a border. */ void Border::setData(const QString& nameIn, const float centerIn[3], const float samplingDensityIn, const float varianceIn, const float topographyIn, const float arealUncertaintyIn) { name = nameIn; center[0] = centerIn[0]; center[1] = centerIn[1]; center[2] = centerIn[2]; samplingDensity = samplingDensityIn; variance = varianceIn; topographyValue = topographyIn; arealUncertainty = arealUncertaintyIn; if (borderFile != NULL) { borderFile->setModified(); } } /** * Get the position of a link. */ void Border::getLinkXYZ(const int linkNumber, float xyz[3]) const { xyz[0] = linkXYZ[linkNumber * 3]; xyz[1] = linkXYZ[linkNumber * 3 + 1]; xyz[2] = linkXYZ[linkNumber * 3 + 2]; } /** * Set the position of a link. */ void Border::setLinkXYZ(const int linkNumber, const float xyz[3]) { linkXYZ[linkNumber * 3] = xyz[0]; linkXYZ[linkNumber * 3 + 1] = xyz[1]; linkXYZ[linkNumber * 3 + 2] = xyz[2]; if (borderFile != NULL) { borderFile->setModified(); } } /** * get the radius for a link. */ float Border::getLinkRadius(const int linkNumber) const { const float r = linkRadii[linkNumber]; return r; } /** * set the radius for a link. */ void Border::setLinkRadius(const int linkNumber, const float radius) { linkRadii[linkNumber] = radius; if (borderFile != NULL) { borderFile->setModified(); } } /** * set the uncertainty. */ void Border::setArealUncertainty(const float uncertainty) { arealUncertainty = uncertainty; if (borderFile != NULL) { borderFile->setModified(); } } /** * find first link in "this" border that is within "tolerance" distance * of a link in "other border". */ bool Border::intersection3D(const Border* otherBorder, const float intersectionTolerance, int& myLinkIntersect, int& otherLinkIntersect) const { const float intersectionToleranceSquared = intersectionTolerance * intersectionTolerance; myLinkIntersect = -1; otherLinkIntersect = -1; const int myNumLinks = getNumberOfLinks(); const int otherNumLinks = otherBorder->getNumberOfLinks(); for (int i = 0; i < myNumLinks; i++) { for (int j = 0; j < otherNumLinks; j++) { if (MathUtilities::distanceSquared3D(getLinkXYZ(i), otherBorder->getLinkXYZ(j)) < intersectionToleranceSquared) { myLinkIntersect = i; otherLinkIntersect = j; return true; } } } return false; } /** * find links where another border intersects this border (2D borders in X-Y plane). */ bool Border::intersection2D(const Border* otherBorder, const bool thisBorderIsClosed, const bool otherBorderIsClosed, int& myLinkIntersect, int& otherLinkIntersect) const { myLinkIntersect = -1; otherLinkIntersect = -1; const int myNumLinks = getNumberOfLinks(); const int otherNumLinks = otherBorder->getNumberOfLinks(); float intersection[2]; for (int i = 0; i < myNumLinks; i++) { int iNext = i + 1; if (i == (myNumLinks - 1)) { if (thisBorderIsClosed) { iNext = 0; } else { continue; } } for (int j = 0; j < (otherNumLinks - 1); j++) { int jNext = j + 1; if (j == (otherNumLinks - 1)) { if (otherBorderIsClosed) { jNext = 0; } else { continue; } } if (MathUtilities::lineIntersection2D(getLinkXYZ(i), getLinkXYZ(iNext), otherBorder->getLinkXYZ(j), otherBorder->getLinkXYZ(jNext), intersection)) { myLinkIntersect = i; otherLinkIntersect = j; return true; } } } return false; } /** * create a border with a subset of the border's links from linkStart to * linkEnd (inclusive). */ Border* Border::getSubSet(const int linkStart, const int linkEnd) const { Border* b = new Border(name, center, samplingDensity, variance, topographyValue, arealUncertainty); if (linkEnd > linkStart) { for (int i = linkStart; i <= linkEnd; i++) { b->addBorderLink(getLinkXYZ(i), getLinkSectionNumber(i)); } } else { const int numLinks = getNumberOfLinks(); for (int i = linkStart; i < numLinks; i++) { b->addBorderLink(getLinkXYZ(i), getLinkSectionNumber(i)); } for (int i = 0; i <= linkEnd; i++) { b->addBorderLink(getLinkXYZ(i), getLinkSectionNumber(i)); } } if (b->getNumberOfLinks() > 0) { return b; } else { delete b; return NULL; } } /** * Set the flat normal for a link. */ void Border::setLinkFlatNormal(const int linkNumber, const float normal[3]) { linkFlatNormal[linkNumber * 2] = normal[0]; linkFlatNormal[linkNumber * 2 + 1] = normal[1]; linkFlatNormal[linkNumber * 2 + 2] = normal[2]; if (borderFile != NULL) { borderFile->setModified(); } } /** * Set the section number of a link. */ void Border::setLinkSectionNumber(const int linkNumber, const int section) { linkSection[linkNumber] = section; if (borderFile != NULL) { borderFile->setModified(); } } /** * Distance between two links. */ float Border::distanceBetweenLinks(const int link1, const int link2) const { const float dx = linkXYZ[link1 * 3] - linkXYZ[link2 * 3]; const float dy = linkXYZ[link1 * 3 + 1] - linkXYZ[link2 * 3 + 1]; const float dz = linkXYZ[link1 * 3 + 2] - linkXYZ[link2 * 3 + 2]; const float dist = std::sqrt(dx*dx + dy*dy + dz*dz); return dist; } /** * Add a link to the border. */ void Border::addBorderLink(const float xyz[3], const int section, const float radius) { // // Note: Links are placed at origin when they cannot be projected successfully so ignore them // if ((xyz[0] != 0.0) || (xyz[1] != 0.0) || (xyz[2] != 0.0)) { linkXYZ.push_back(xyz[0]); linkXYZ.push_back(xyz[1]); linkXYZ.push_back(xyz[2]); linkRadii.push_back(radius); linkFlatNormal.push_back(0.0); linkFlatNormal.push_back(0.0); linkFlatNormal.push_back(1.0); linkSection.push_back(section); if (borderFile != NULL) { borderFile->setModified(); } } } /** * insert a border link before the specified link number (use number of links for end). */ void Border::insertBorderLink(const int linkIndex, const float xyz[3], const int section, const float radius) { if (linkIndex >= getNumberOfLinks()) { addBorderLink(xyz, section, radius); } else if (linkIndex >= 0) { const int offset3 = linkIndex * 3; linkXYZ.insert(linkXYZ.begin() + offset3, xyz[2]); linkXYZ.insert(linkXYZ.begin() + offset3, xyz[1]); linkXYZ.insert(linkXYZ.begin() + offset3, xyz[0]); linkRadii.insert(linkRadii.begin() + linkIndex, radius); linkSection.insert(linkSection.begin() + linkIndex, section); linkFlatNormal.insert(linkFlatNormal.begin() + offset3, 0.0); linkFlatNormal.insert(linkFlatNormal.begin() + offset3, 0.0); linkFlatNormal.insert(linkFlatNormal.begin() + offset3, 1.0); if (borderFile != NULL) { borderFile->setModified(); } } } /** * Get the length of border. */ float Border::getBorderLength() const { float len = 0; const int numLinks = getNumberOfLinks(); for (int i = 1; i < numLinks; i++) { len += distanceBetweenLinks(i, i - 1); } return len; } /** * Clear border links */ void Border::clearLinks() { linkXYZ.clear(); linkRadii.clear(); linkFlatNormal.clear(); linkSection.clear(); if (borderFile != NULL) { borderFile->setModified(); } } /** * remove links on negative side of plane. */ void Border::removePointsOnNegativeSideOfPlane(const float planeNormal[3], const float pointInPlane[3]) { const int num = getNumberOfLinks(); for (int i = (num - 1); i >= 0; i--) { const float signedDistance = MathUtilities::signedDistanceToPlane(planeNormal, pointInPlane, getLinkXYZ(i)); if (signedDistance < 0.0) { removeLink(i); } } } /** * Remove a border link */ void Border::removeLink(const int linkNumber) { if (linkNumber < getNumberOfLinks()) { const int offset3 = linkNumber * 3; linkXYZ.erase(linkXYZ.begin() + offset3, linkXYZ.begin() + offset3 + 3); const int offset2 = linkNumber * 3; linkFlatNormal.erase(linkFlatNormal.begin() + offset2, linkFlatNormal.begin() + offset2 + 3); linkSection.erase(linkSection.begin() + linkNumber); linkRadii.erase(linkRadii.begin() + linkNumber); if (borderFile != NULL) { borderFile->setModified(); } } } /** * remove intersecting loops in a border. */ void Border::removeIntersectingLoops(const char axisXYZ) throw (FileException) { if ((axisXYZ != 'X') && (axisXYZ != 'Y') && (axisXYZ != 'Z')) { throw FileException("PROGRAM ERROR axis passed to \"Border::removeIntersectingLoops\"" "must be one of X, Y, or Z"); } bool done = false; while (done == false) { done = true; const int numLinks = getNumberOfLinks(); // // Loop through links // bool foundIntersectionFlag = false; for (int i = 0; i < (numLinks - 3); i++) { const float* p13D = getLinkXYZ(i); const float* p23D = getLinkXYZ(i + 1); // // Loop through links after "i" // for (int j = i + 2; j < (numLinks - 1); j++) { // // Do not test first and last // if ((i == 0) && (j == (numLinks - 2))) { continue; } const float* q13D = getLinkXYZ(j); const float* q23D = getLinkXYZ(j + 1); // // Convert 3D to Planar 2D // float p1[2], p2[2], q1[2], q2[2]; switch (axisXYZ) { case 'X': p1[0] = p13D[1]; p1[1] = p13D[2]; p2[0] = p23D[1]; p2[1] = p23D[2]; q1[0] = q13D[1]; q1[1] = q13D[2]; q2[0] = q23D[1]; q2[1] = q23D[2]; break; case 'Y': p1[0] = p13D[0]; p1[1] = p13D[2]; p2[0] = p23D[0]; p2[1] = p23D[2]; q1[0] = q13D[0]; q1[1] = q13D[2]; q2[0] = q23D[0]; q2[1] = q23D[2]; break; case 'Z': p1[0] = p13D[0]; p1[1] = p13D[1]; p2[0] = p23D[0]; p2[1] = p23D[1]; q1[0] = q13D[0]; q1[1] = q13D[1]; q2[0] = q23D[0]; q2[1] = q23D[1]; break; } // // Do the segments intersect? // float intersection[2]; if (MathUtilities::lineIntersection2D(p1, p2, q1, q2, intersection)) { // // Remove links between intersection // for (int k = j; k >= (i + 1); k--) { removeLink(k); } foundIntersectionFlag = true; done = false; break; } } // for j... if (foundIntersectionFlag) { break; } } // for i... } } /** * smooth the border links. */ void Border::smoothBorderLinks(const int numberOfIterations, const bool closedBorderFlag, const std::vector* smoothTheseLinksOnlyIn) { const int numLinks = getNumberOfLinks(); if (numLinks <= 2) { return; } std::vector smoothFlags(numLinks, true); if (smoothTheseLinksOnlyIn != NULL) { if (static_cast(smoothTheseLinksOnlyIn->size()) != numLinks) { return; } smoothFlags = *smoothTheseLinksOnlyIn; } int jStart = 1; int jEnd = numLinks - 1; if (closedBorderFlag) { jStart = 0; jEnd = numLinks; } if (DebugControl::getDebugOn()) { std::cout << "Smoothing: "; for (int j = jStart; j < jEnd; j++) { if (smoothFlags[j]) { std::cout << j << " "; } } std::cout << std::endl; } for (int i = 0; i < numberOfIterations; i++) { for (int j = jStart; j < jEnd; j++) { if (smoothFlags[j]) { int jPrev = j - 1; if (jPrev < 0) { jPrev = numLinks - 1; } int jNext = j + 1; if (jNext >= numLinks) { jNext = 0; } const float* xyzPrev = getLinkXYZ(jPrev); const float* xyzNext = getLinkXYZ(jNext); float xyz[3]; getLinkXYZ(j, xyz); for (int k = 0; k < 3; k++) { xyz[k] = (xyzPrev[k] + xyzNext[k] + xyz[k]) / 3.0; } setLinkXYZ(j, xyz); } } } } /** * Resample a border to a specified density. */ void Border::resampleBorderToDensity(const float densityIn, const int minimumNumberOfLinks, int& newNumberOfLinks) { float density = densityIn; const float borderLength = getBorderLength(); newNumberOfLinks = static_cast(borderLength / density) + 1; if (minimumNumberOfLinks > 1) { if (newNumberOfLinks < minimumNumberOfLinks) { newNumberOfLinks = minimumNumberOfLinks; //density = borderLength / (minimumNumberOfLinks - 1); } } // recompute density so that starting and ending points of border are used density = borderLength / (newNumberOfLinks - 1); const int oldNumberOfLinks = static_cast(getNumberOfLinks()); float* x1 = new float[oldNumberOfLinks]; float* y1 = new float[oldNumberOfLinks]; float* z1 = new float[oldNumberOfLinks]; float* x2 = new float[newNumberOfLinks]; float* y2 = new float[newNumberOfLinks]; float* z2 = new float[newNumberOfLinks]; for (int j = 0; j < oldNumberOfLinks; j++) { const float* xyz = getLinkXYZ(j); x1[j] = xyz[0]; y1[j] = xyz[1]; z1[j] = xyz[2]; } resampleBorder(x1, y1, z1, oldNumberOfLinks, density, x2, y2, z2, newNumberOfLinks); Border savedCopy = *this; clearLinks(); for (int i = 0; i < newNumberOfLinks; i++) { float xyz[3] = { x2[i], y2[i], z2[i] }; addBorderLink(xyz, 0, savedCopy.getLinkRadius( savedCopy.getLinkNumberNearestToCoordinate(xyz))); } delete[] x1; delete[] y1; delete[] z1; delete[] x2; delete[] y2; delete[] z2; if (borderFile != NULL) { borderFile->setModified(); } } /** * Resample a border to a specified number of links. */ void Border::resampleBorderToNumberOfLinks(const int newNumberOfLinks) { const float borderLength = getBorderLength(); const int oldNumberOfLinks = static_cast(getNumberOfLinks()); const float density = borderLength / static_cast(newNumberOfLinks - 1); float* x1 = new float[oldNumberOfLinks]; float* y1 = new float[oldNumberOfLinks]; float* z1 = new float[oldNumberOfLinks]; float* x2 = new float[newNumberOfLinks]; float* y2 = new float[newNumberOfLinks]; float* z2 = new float[newNumberOfLinks]; for (int j = 0; j < oldNumberOfLinks; j++) { const float* xyz = getLinkXYZ(j); x1[j] = xyz[0]; y1[j] = xyz[1]; z1[j] = xyz[2]; } resampleBorder(x1, y1, z1, oldNumberOfLinks, density, x2, y2, z2, newNumberOfLinks); Border savedCopy = *this; clearLinks(); for (int i = 0; i < newNumberOfLinks; i++) { const float xyz[3] = { x2[i], y2[i], z2[i] }; addBorderLink(xyz, 0, savedCopy.getLinkRadius( savedCopy.getLinkNumberNearestToCoordinate(xyz))); } delete[] x1; delete[] y1; delete[] z1; delete[] x2; delete[] y2; delete[] z2; if (borderFile != NULL) { borderFile->setModified(); } } /** * orient the links counter-clockwise. */ void Border::orientLinksCounterClockwise() { orientLinksClockwise(); reverseBorderLinks(); } /** * Orient the links in the border clockwise. */ void Border::orientLinksClockwise() { float minX = std::numeric_limits::max(); int minXIndex = -1; const int num = getNumberOfLinks(); for (int i = 0; i < num; i++) { const float *pos = getLinkXYZ(i); if (i == 0) { minX = pos[0]; minXIndex = i; } else if (pos[0] < minX) { minX = pos[0]; minXIndex = i; } } if (minXIndex >= 0) { int iNext = minXIndex + 1; if (iNext >= num) { iNext = 0; } const float *nextPos = getLinkXYZ(iNext); const float *minPos = getLinkXYZ(minXIndex); if (nextPos[1] < minPos[1]) { reverseBorderLinks(); } } if (borderFile != NULL) { borderFile->setModified(); } } /** * Compute the flat normals for a border. */ void Border::computeFlatNormals() { const int numLinks = getNumberOfLinks(); for (int i = 0; i < numLinks; i++) { int iNext = i + 1; if (iNext >= numLinks) iNext = 0; int iPrev = i - 1; if (iPrev < 0) iPrev = numLinks - 1; float vec[3]; MathUtilities::subtractVectors(getLinkXYZ(iNext), getLinkXYZ(iPrev), vec); MathUtilities::normalize(vec); // points 90 to right const int i3 = i * 3; linkFlatNormal[i3] = vec[1]; linkFlatNormal[i3+1] = -vec[0]; linkFlatNormal[i3+2] = 0.0; } } /** * Reverse the order of the links in a border. */ void Border::reverseBorderLinks() { std::vector xyz; std::vector normal; std::vector section; std::vector radii; for (int i = getNumberOfLinks() - 1; i >= 0; i--) { const float* pos = getLinkXYZ(i); const float* norm = getLinkFlatNormal(i); const int sect = getLinkSectionNumber(i); const float radius = getLinkRadius(i); xyz.push_back(pos[0]); xyz.push_back(pos[1]); xyz.push_back(pos[2]); radii.push_back(radius); normal.push_back(norm[0]); normal.push_back(norm[1]); normal.push_back(norm[2]); section.push_back(sect); } linkXYZ = xyz; linkRadii = radii; linkFlatNormal = normal; linkSection = section; if (borderFile != NULL) { borderFile->setModified(); } } /** * remove landmark rater from name of border. */ void Border::removeLandmarkRaterInfoFromBorderName() { const int landmarkChar = Border::getLandmarkRaterFirstChar(); const int indx = name.indexOf(landmarkChar); if (indx >= 0) { name = name.left(indx); } } /** * compare the name of two landmark borders * only compares text before the semi-colon in the name. */ bool Border::compareLandmarkBorderNames(const QString& name1, const QString& name2) { // // for comparison, use substring of name up to but not including the colon // const char landmarkChar = Border::getLandmarkRaterFirstChar(); int name1Length = name1.indexOf(landmarkChar); if (name1Length < 0) { name1Length = name1.length(); } int name2Length = name2.indexOf(landmarkChar); if (name2Length < 0) { name2Length = name2.length(); } // // Only need to compare if same length // if (name1Length == name2Length) { return (name1.left(name1Length) == name2.left(name2Length)); } return false; } /* distance between two points */ static double dist (const float x1, const float y1, const float z1, const float x2, const float y2, const float z2) { const float dxyz[3] = { x2 - x1, y2 - y1, z2 - z1 }; return MathUtilities::vectorLength(dxyz); } /** * Helpful resample function. */ void Border::resampleBorder(const float* xorig, const float* yorig, const float* zorig, const int numPointsIn, const float density, float* xout, float* yout, float* zout, const int numPointsOut) { /* Now find the next point dist away from the previous point */ xout [0] = xorig [0]; yout [0] = yorig [0]; zout [0] = zorig [0]; int j = 0; /* index of the points processed */ //05/07/01 for (int i = 0; i < numPointsOut-1; i++){ for (int i = 0; i < numPointsOut-2; i++){ float x1 = xout [i]; float y1 = yout [i]; float z1 = zout [i]; float dj1 = 0; float dj = dist (x1, y1, z1, xorig [j], yorig [j], zorig [j]); int k = j; /* find the distance to the jth point */ while (dj < density){ dj1 = dj; dj = dj+dist (xorig [j], yorig [j], zorig [j], xorig [j+1], yorig [j+1], zorig [j+1]); j++; } /* The new point lies in the jth segment */ float frac = (density - dj1)/(dj-dj1); if (k != j) { x1 = xorig [j-1]; y1 = yorig [j-1]; z1 = zorig [j-1]; } xout [i+1] = (1-frac)*x1 + frac*xorig[j]; yout [i+1] = (1-frac)*y1 + frac*yorig[j]; zout [i+1] = (1-frac)*z1 + frac*zorig[j]; } // last point xout[numPointsOut-1] = xorig[numPointsIn-1]; yout[numPointsOut-1] = yorig[numPointsIn-1]; zout[numPointsOut-1] = zorig[numPointsIn-1]; } /** * Determine the bounds of a border. */ void Border::getBounds(float bounds[6]) const { bounds[0] = std::numeric_limits::max(); bounds[1] = -std::numeric_limits::max(); bounds[2] = std::numeric_limits::max(); bounds[3] = -std::numeric_limits::max(); bounds[4] = std::numeric_limits::max(); bounds[5] = -std::numeric_limits::max(); const int numLinks = getNumberOfLinks(); for (int i = 0; i < numLinks; i++) { const float* pos = getLinkXYZ(i); bounds[0] = std::min(bounds[0], pos[0]); bounds[1] = std::max(bounds[1], pos[0]); bounds[2] = std::min(bounds[2], pos[1]); bounds[3] = std::max(bounds[3], pos[1]); bounds[4] = std::min(bounds[4], pos[2]); bounds[5] = std::max(bounds[5], pos[2]); } } /** * get the center of gravity of the border (returns true if valid). */ bool Border::getCenterOfGravity(float cogXYZOut[3]) const { double sum[3] = { 0.0, 0.0, 0.0 }; double numSum = 0.0; const int numLinks = getNumberOfLinks(); for (int i = 0; i < numLinks; i++) { const float* pos = getLinkXYZ(i); sum[0] += pos[0]; sum[1] += pos[1]; sum[2] += pos[2]; numSum += 1.0; } if (numSum >= 1.0) { cogXYZOut[0] = sum[0] / numSum; cogXYZOut[1] = sum[1] / numSum; cogXYZOut[2] = sum[2] / numSum; return true; } return false; } /** * get the link number nearest to a coordinate. */ int Border::getLinkNumberNearestToCoordinate(const float xyz[3]) const { int nearestLinkNumber = -1; float nearestDistanceSQ = std::numeric_limits::max(); const int numLinks = getNumberOfLinks(); for (int i = 0; i < numLinks; i++) { const float* pos = getLinkXYZ(i); const float distSQ = MathUtilities::distanceSquared3D(xyz, pos); if (distSQ < nearestDistanceSQ) { nearestDistanceSQ = distSQ; nearestLinkNumber = i; } } return nearestLinkNumber; } /** * get the link number furthest from a coordinate. */ int Border::getLinkNumberFurthestFromCoordinate(const float xyz[3]) const { int furthestLinkNumber = -1; float furthestDistanceSQ = -1.0; const int numLinks = getNumberOfLinks(); for (int i = 0; i < (numLinks - 1); i++) { const float* pos = getLinkXYZ(i); const float distSQ = MathUtilities::distanceSquared3D(xyz, pos); if (distSQ > furthestDistanceSQ) { furthestDistanceSQ = distSQ; furthestLinkNumber = i; } } return furthestLinkNumber; } /** * See if 3D points are inside a 3D border (transform all to screen axis). */ void Border::pointsInsideBorder3D(const GLdouble* modelMatrix, const GLdouble* projectionMatrix, const GLint* viewport, const float* points, const int numPoints, std::vector& insideFlags, const bool checkNonNegativeScreenZPointsOnly) const { if (static_cast(insideFlags.size()) < numPoints) { insideFlags.resize(numPoints); } std::fill(insideFlags.begin(), insideFlags.end(), false); // // Since the coordinates are typically less than 100, this can cause // problems with the point in polygon algorithm (it will report a // degenerate polygon). Scaling all coordinates elminates this problem. // Using every other point in the border also helps. // const float scaleFactor = 1000.0; const int numLinks = getNumberOfLinks(); float bounds[6]; bounds[0] = std::numeric_limits::max(); bounds[1] = -std::numeric_limits::max(); bounds[2] = std::numeric_limits::max(); bounds[3] = -std::numeric_limits::max(); bounds[4] = -1.0; bounds[5] = 1.0; // // Create a polygon consisting of the border links projection to screen space // std::vector polygon; int numToSkip = 1; int numInPolygon = 0; for (int i = 0; i < (numLinks - 1); i++) { const float* pos = getLinkXYZ(i); GLdouble x = pos[0]; GLdouble y = pos[1]; GLdouble z = pos[2]; GLdouble sx = 0.0, sy = 0.0, sz = 0.0; gluProject(x, y, z, modelMatrix, projectionMatrix, viewport, &sx, &sy, &sz); polygon.push_back(sx * scaleFactor); polygon.push_back(sy * scaleFactor); polygon.push_back(0.0); // test in plane so do not need Z numInPolygon++; i += numToSkip; bounds[0] = std::min(bounds[0], static_cast(sx * scaleFactor)); bounds[1] = std::max(bounds[1], static_cast(sx * scaleFactor)); bounds[2] = std::min(bounds[2], static_cast(sy * scaleFactor)); bounds[3] = std::max(bounds[3], static_cast(sy * scaleFactor)); } if (numInPolygon < 3) { return; } float normal[3] = { 0.0, 0.0, 1.0 }; for (int i = 0; i < numPoints; i++) { GLdouble x = points[i*3]; GLdouble y = points[i*3+1]; GLdouble z = points[i*3+2]; GLdouble sx = 0.0, sy = 0.0, sz = 0.0; gluProject(x, y, z, modelMatrix, projectionMatrix, viewport, &sx, &sy, &sz); int result = 0; bool checkIt = true; if (checkNonNegativeScreenZPointsOnly) { if (sz >= 0.5) { // Z ranges 0 to 1 with 0 closest to viewer checkIt = false; } } if (checkIt) { float xyz[3] = { sx * scaleFactor, sy * scaleFactor, 0.0 }; // use 0 for Z result = MathUtilities::pointInPolygon(xyz, numInPolygon, (float*)&polygon[0], bounds, normal); } if (result > 0) { insideFlags[i] = true; } else if (result < 0) { std::cerr << "Border polygon passed to MathUtilities::pointInPolygon " " is degenerate." << std::endl; std::cerr << "Polygon: " << std::endl; for (int j = 0; j < numInPolygon; j++) { std::cerr << " " << j << " " << polygon[j*3] << " " << polygon[j*3+1] << " " << polygon[j*3+2] << std::endl; } break; } } } /** * Determine if points are inside this border. * The border is assumed to be flat, in the X-Y plane. */ void Border::pointsInsideBorder2D(const float* points, const int numPoints, std::vector& insideFlags, const bool checkNonNegativeZPointsOnly, const float zMinimum) const { if (static_cast(insideFlags.size()) < numPoints) { insideFlags.resize(numPoints); } std::fill(insideFlags.begin(), insideFlags.end(), false); // // Since the coordinates are typically less than 100, this can cause // problems with the point in polygon algorithm (it will report a // degenerate polygon). Scaling all coordinates elminates this problem. // Using every other point in the border also helps. // const float scaleFactor = 1000.0; // // Copy the border and orient CCW // Border border = *this; const int numLinks = border.getNumberOfLinks(); for (int i = 0; i < numLinks; i++) { float pos[3]; border.getLinkXYZ(i, pos); pos[2] = 0.0; border.setLinkXYZ(i, pos); } border.orientLinksCounterClockwise(); std::vector polygon; int numToSkip = 1; int numInPolygon = 0; for (int i = 0; i < (numLinks - 1); i++) { const float* pos = border.getLinkXYZ(i); polygon.push_back(pos[0] * scaleFactor); polygon.push_back(pos[1] * scaleFactor); polygon.push_back(0.0); //JWH 5/14/2008 pos[2] * scaleFactor); numInPolygon++; i += numToSkip; } if (numInPolygon < 3) { return; } float bounds[6]; border.getBounds(bounds); bounds[0] *= scaleFactor - 1.0; bounds[1] *= scaleFactor + 1.0; bounds[2] *= scaleFactor - 1.0; bounds[3] *= scaleFactor + 1.0; bounds[4] = -1.0; bounds[5] = 1.0; float normal[3] = { 0.0, 0.0, 1.0 }; for (int i = 0; i < numPoints; i++) { float xyz[3]; xyz[0] = points[i*3]; xyz[1] = points[i*3+1]; xyz[2] = points[i*3+2]; bool checkIt = true; if (checkNonNegativeZPointsOnly) { if (xyz[2] < zMinimum) { checkIt = false; } } int result = 0; if (checkIt) { xyz[0] *= scaleFactor; xyz[1] *= scaleFactor; xyz[2] = 0.0; result = MathUtilities::pointInPolygon(xyz, numInPolygon, (float*)&polygon[0], bounds, normal); } if (result > 0) { insideFlags[i] = true; } else if (result < 0) { std::cerr << "Border polygon passed to MathUtilities::pointInPolygon " " is degenerate." << std::endl; std::cerr << "Polygon: " << std::endl; for (int j = 0; j < numInPolygon; j++) { std::cerr << " " << j << " " << polygon[j*3] << " " << polygon[j*3+1] << " " << polygon[j*3+2] << std::endl; } break; } } } /** * interpolate two borders to create new borders. */ void Border::createInterpolatedBorders(Border* b1, Border* b2, const QString& namePrefix, const int numberOfNewBorders, const float sampling, std::vector& outputInterpolatedBorders) throw (FileException) { outputInterpolatedBorders.clear(); // // Check inputs // if (b1 == NULL) { throw FileException("Border 1 is invalid."); } if (b2 == NULL) { throw FileException("Border 2 is invalid."); } if (b1->getNumberOfLinks() < 2) { throw FileException("Border 1 must have at least two links."); } if (b2->getNumberOfLinks() < 2) { throw FileException("Border 2 must have at least two links."); } if (numberOfNewBorders < 1) { throw FileException("Number of new borders must be at least one."); } if (sampling <= 0.0) { throw FileException("Sampling must be greater than zero."); } if (namePrefix.isEmpty()) { throw FileException("Name prefix contains no characters."); } // // resample the longest border to the specified sampling and resample the other // border to the same number of links // Border* longestBorder = NULL; Border* shortestBorder = NULL; if (b1->getBorderLength() > b2->getBorderLength()) { longestBorder = b1; shortestBorder = b2; } else { shortestBorder = b1; longestBorder = b2; } // // Resample the borders // int numLinks = 0; longestBorder->resampleBorderToDensity(sampling, 2, numLinks); if (numLinks < 2) { throw FileException("PROGRAM ERROR: Resampling of first border resulted in less than two links."); } shortestBorder->resampleBorderToNumberOfLinks(numLinks); if (b1->getNumberOfLinks() != b2->getNumberOfLinks()) { throw FileException("PROGRAM ERROR: After resampling the borders have a different number of links."); } // // Create the specified number of interpolated borders // const float totalSteps = numberOfNewBorders + 1; for (int i = 0; i < numberOfNewBorders; i++) { const float stepNum = i + 1; // // Create the new border // const QString borderName(namePrefix + "." + QString::number(i + 1)); Border* newBorder = new Border(borderName); // // Create and add new links to new border // const float stepDelta = stepNum / totalSteps; for (int j = 0; j < numLinks; j++) { // // Determine the offset from link in first border to corresponding link in second border // const float* b1XYZ = b1->getLinkXYZ(j); const float* b2XYZ = b2->getLinkXYZ(j); const float dxyz[3] = { b2XYZ[0] - b1XYZ[0], b2XYZ[1] - b1XYZ[1], b2XYZ[2] - b1XYZ[2] }; // // Create XYZ of point in new border // const float xyz[3] = { b1XYZ[0] + dxyz[0] * stepDelta, b1XYZ[1] + dxyz[1] * stepDelta, b1XYZ[2] + dxyz[2] * stepDelta }; // // Add a link to the new border // newBorder->addBorderLink(xyz); } // // Add the new border // outputInterpolatedBorders.push_back(newBorder); } } //-------------------------------------------------------------------------------- /** * Constructor. */ BorderFile::BorderFile(const QString& descriptiveName, const QString& defaultExtensionIn) : AbstractFile(descriptiveName, defaultExtensionIn) { clear(); } /** * Constructor that creates a BorderFile from the coordinates in a coordinate file. * If "maxLinksPerBorder" is negative one border containing all coordinates will * be created. Otherwise, multiple borders will be created no more than * "maxLinksPerBorder" points. */ BorderFile::BorderFile(const CoordinateFile* cf, const int maxLinksPerBorder) : AbstractFile("Border File", SpecFile::getBorderFileExtension()) { if (cf == NULL) { return; } const int numCoords = cf->getNumberOfCoordinates(); if (maxLinksPerBorder > 0) { Border border("Nodes"); for (int i = 0; i < numCoords; i++) { border.addBorderLink(cf->getCoordinate(i)); if (border.getNumberOfLinks() >= maxLinksPerBorder) { addBorder(border); border.clearLinks(); } } if (border.getNumberOfLinks() > 0) { addBorder(border); } } else { Border border("Nodes"); for (int i = 0; i < numCoords; i++) { border.addBorderLink(cf->getCoordinate(i)); } addBorder(border); } } /** * Constructor that creates a BorderFile from the tiles in a Topology and Coordinate File. */ BorderFile::BorderFile(const TopologyFile* tf, const CoordinateFile* cf) : AbstractFile("Border File", SpecFile::getBorderFileExtension()) { // // Get topology and coordinate information // if ((tf == NULL) || (cf == NULL)) { return; } const int numTiles = tf->getNumberOfTiles(); for (int i = 0; i < numTiles; i++) { // // Get the nodes in the tile // int p1, p2, p3; tf->getTile(i, p1, p2, p3); // // Create a closed border with the tiles vertices // Border b("Tile"); b.addBorderLink(cf->getCoordinate(p1)); b.addBorderLink(cf->getCoordinate(p2)); b.addBorderLink(cf->getCoordinate(p3)); b.addBorderLink(cf->getCoordinate(p1)); // closes the border addBorder(b); } } /** * copy all the links into a coordinate file. */ void BorderFile::copyLinksToCoordinateFile(CoordinateFile* cf) { // // Set the number of coordinates // cf->setNumberOfCoordinates(getTotalNumberOfLinks()); // // Set the coordinates with the links // int ctr = 0; for (int i = 0; i < getNumberOfBorders(); i++) { Border* border = getBorder(i); const int numLinks = border->getNumberOfLinks(); for (int j = 0; j < numLinks; j++) { float xyz[3]; border->getLinkXYZ(j, xyz); cf->setCoordinate(ctr, xyz); ctr++; } } } /** * Destructor. */ BorderFile::~BorderFile() { clear(); } /** * Append a border file to this one. */ void BorderFile::append(BorderFile& bf) { const int numProj = bf.getNumberOfBorders(); for (int i = 0; i < numProj; i++) { Border* b = bf.getBorder(i); addBorder(*b); } // // transfer the file's comment // appendFileComment(bf); } /** * Assign colors to these borders. */ void BorderFile::assignColors(const ColorFile& colorFile) { const int numProj = getNumberOfBorders(); for (int i = 0; i < numProj; i++) { Border* b = getBorder(i); bool match; b->setBorderColorIndex(colorFile.getColorIndexByName(b->getName(), match)); } } /** * resample to match landmark border file (borders with same names have same number of points). */ void BorderFile::resampleToMatchLandmarkBorders(const BorderFile& landmarkBorderFile) throw (FileException) { const int numBorders = getNumberOfBorders(); for (int i = 0; i < numBorders; i++) { Border* myBorder = getBorder(i); const QString name = myBorder->getName(); // // Find matching landmark border // const Border* landmarkBorder = landmarkBorderFile.getBorderByName(name, true); if (landmarkBorder == NULL) { throw FileException("Matching landmark border not found for border named " + name); } // // resample this border to the same number of links as landmark border // const int numLinks = landmarkBorder->getNumberOfLinks(); myBorder->resampleBorderToNumberOfLinks(numLinks); // // Set variability ratio for this border // for (int j = 0; j < numLinks; j++) { const float dist = MathUtilities::distance3D(myBorder->getLinkXYZ(j), landmarkBorder->getLinkXYZ(j)); const float landmarkVariability = landmarkBorder->getLinkRadius(j); float ratio = 0.0; if (landmarkVariability != 0.0) { ratio = dist / landmarkVariability; } myBorder->setLinkRadius(j, ratio); } } } /** * compute landmark variability. */ void BorderFile::evaluateLandmarkVariability(const BorderFile& indivBorderFile, const BorderFile& atlasBorderFile, const float badThreshold, const float extremeThreshold, const bool useAbsoluteDistanceFlag, BorderFile& outputBorderFile, QString& outputTextReport) throw (FileException) { outputBorderFile.clear(); outputTextReport = ""; // // Copy and resample the atlas border // BorderFile resampledAtlasBorderFile(atlasBorderFile); resampledAtlasBorderFile.resampleAllBorders(0.25); // // Set individual border variability // int longestBorderNameLength = 0; int numIndivBorders = indivBorderFile.getNumberOfBorders(); for (int i = 0; i < numIndivBorders; i++) { // // Copy indiv border and find atlas border with same name // Border indivBorder = *(indivBorderFile.getBorder(i)); const Border* atlasBorder = resampledAtlasBorderFile.getBorderByName(indivBorder.getName()); if (atlasBorder == NULL) { throw FileException("No atlas border named " + indivBorder.getName() + " found."); } // // Track longest border name length // longestBorderNameLength = std::max(longestBorderNameLength, indivBorder.getName().length()); // // Loop through indiv border points // int numLinks = indivBorder.getNumberOfLinks(); for (int j = 0; j < numLinks; j++) { // // Find nearest atlas link to indiv link // const float* xyz = indivBorder.getLinkXYZ(j); const int atlasLinkNumber = atlasBorder->getLinkNumberNearestToCoordinate(xyz); if (atlasLinkNumber >= 0) { // // Compute and set indiv variability // const float distance = MathUtilities::distance3D(xyz, atlasBorder->getLinkXYZ(atlasLinkNumber)); if (useAbsoluteDistanceFlag) { indivBorder.setLinkRadius(j, distance); } else { float atlasVariability = atlasBorder->getLinkRadius(atlasLinkNumber); if (atlasVariability <= 0.0) { atlasVariability = 1.0; } const float indivVariability = distance / atlasVariability; indivBorder.setLinkRadius(j, indivVariability); } } else { throw FileException("No nearest point in atlas border named " + atlasBorder->getName()); } } // // Add indiv border to output border file // outputBorderFile.addBorder(indivBorder); } // // Copy and resample the atlas border // BorderFile resampledIndivBorderFile(indivBorderFile); resampledIndivBorderFile.resampleAllBorders(0.25); // // Set atlas border variability // int numAtlasBorders = atlasBorderFile.getNumberOfBorders(); for (int i = 0; i < numAtlasBorders; i++) { // // Copy atlas border and find indiv border with same name // Border atlasBorder = *(atlasBorderFile.getBorder(i)); const Border* indivBorder = resampledIndivBorderFile.getBorderByName(atlasBorder.getName()); if (indivBorder == NULL) { throw FileException("No indiv border named " + atlasBorder.getName() + " found."); } // // Loop through atlas border points // int numLinks = atlasBorder.getNumberOfLinks(); for (int j = 0; j < numLinks; j++) { // // Find nearest indiv link to atlas link // const float* xyz = atlasBorder.getLinkXYZ(j); const int indivLinkNumber = indivBorder->getLinkNumberNearestToCoordinate(xyz); if (indivLinkNumber >= 0) { // // Compute and set atlas variability which is distance from // indiv to atlas divided by ATLAS (yes ATLAS) variability // const float distance = MathUtilities::distance3D(xyz, indivBorder->getLinkXYZ(indivLinkNumber)); if (useAbsoluteDistanceFlag) { atlasBorder.setLinkRadius(j, distance); } else { float atlasVariability = atlasBorder.getLinkRadius(j); if (atlasVariability <= 0.0) { atlasVariability = 1.0; } atlasVariability = distance / atlasVariability; atlasBorder.setLinkRadius(j, atlasVariability); } } else { throw FileException("No nearest point in indiv border named " + indivBorder->getName()); } } // // Add atlas border to output border file // outputBorderFile.addBorder(atlasBorder); } // // Header for text report // const QString borderNameHeader("Border Name"); const QString badCountHeader("Bad Count"); const int badCountLength = badCountHeader.length(); const QString extremeCountHeader("Extreme Count"); const int extremeCountLength = extremeCountHeader.length(); const QString overlapPercentageHeader("Overlap Percentage"); const int overlapPercentageLength = overlapPercentageHeader.length(); longestBorderNameLength = std::max(longestBorderNameLength, borderNameHeader.length()); QString s = QString("%1 %2 %3 %4\n").arg(borderNameHeader, longestBorderNameLength) .arg(badCountHeader, badCountLength) .arg(extremeCountHeader, extremeCountLength) .arg(overlapPercentageHeader, overlapPercentageLength); outputTextReport.append(s); // // Loop through indiv borders in output border file // int totalNumberOfBorders = outputBorderFile.getNumberOfBorders(); for (int i = 0; i < numIndivBorders; i++) { Border* indivBorder = outputBorderFile.getBorder(i); const QString name = indivBorder->getName(); // // Find corresponding atlas border // Border* atlasBorder = NULL; for (int j = numIndivBorders; j < totalNumberOfBorders; j++) { Border* b = outputBorderFile.getBorder(j); if (b->getName() == name) { atlasBorder = b; break; } } if (atlasBorder == NULL) { throw FileException("Unable to find atlas border named " + name + " in output border file. "); } // // Count bad and extreme points in atlas and indiv borders // int badCount = 0; int extremeCount = 0; for (int j = 0; j < indivBorder->getNumberOfLinks(); j++) { if (indivBorder->getLinkRadius(j) > badThreshold) { badCount++; } if (indivBorder->getLinkRadius(j) > extremeThreshold) { extremeCount++; } } for (int j = 0; j < atlasBorder->getNumberOfLinks(); j++) { if (atlasBorder->getLinkRadius(j) > badThreshold) { badCount++; } if (atlasBorder->getLinkRadius(j) > extremeThreshold) { extremeCount++; } } // // Determine bad and extreme counts // const int totalPoints = indivBorder->getNumberOfLinks() + atlasBorder->getNumberOfLinks(); const float overlapPercentage = (static_cast(totalPoints - badCount) / static_cast(totalPoints)) * 100.0; // // Add to text report // QString s = QString("%1 %2 %3 %4\n").arg(name, longestBorderNameLength) .arg(badCount, badCountLength) .arg(extremeCount, extremeCountLength) .arg(overlapPercentage, overlapPercentageLength, 'f', 1); outputTextReport.append(s); // // Change the atlas border name // atlasBorder->setName("ATLAS_" + name); } } /** * Create a border file that is an average of a group of border files. * Returns NULL if error. */ void BorderFile::createAverageBorderFile(const std::vector& inputBorderFiles, const float borderResampling, const bool sphereFlag, BorderFile& averageBorderFileOut) throw (FileException) { // // Need at least two borders files to resample // if (inputBorderFiles.size() < 2) { throw FileException("There must be at least two border files."); } // // Clear the output border file // averageBorderFileOut.clear(); // // Stuff for spherical borders // float sphereRadius = 1.0; bool sphereRadiusSet = false; // // Number of border files we have // const int numFiles = static_cast(inputBorderFiles.size()); // // Use the first border files and loop through its borders // const int numBorders = inputBorderFiles[0]->getNumberOfBorders(); for (int i = 0; i < numBorders; i++) { // // Get a border from the first tile // Border b1 = *(inputBorderFiles[0]->getBorder(i)); // // Set sphere radius // if (sphereRadiusSet == false) { for (int j = 0; j < b1.getNumberOfLinks(); j++) { float xyz[3]; b1.getLinkXYZ(j, xyz); if ((xyz[0] != 0.0) || (xyz[1] != 0.0) || (xyz[2] != 0.0)) { sphereRadius = std::sqrt(xyz[0]*xyz[0] + xyz[1]*xyz[1] + xyz[2]*xyz[2]); sphereRadiusSet = true; break; } } } // // Resample it to the specified amount // int numLinks = 0; b1.resampleBorderToDensity(borderResampling, 2, numLinks); if (numLinks > 0) { // // Will contain the additional resampled borders // std::vector resampledBorders; // // Loop through the remaining files // for (int j = 1; j < numFiles; j++) { // // Find the border with the same name as from first file // Border* bj = inputBorderFiles[j]->getBorderByName(b1.getName(), true); if (bj != NULL) { // // Resmaple it and add to resampled borders // Border b = *bj; b.removeLandmarkRaterInfoFromBorderName(); b.resampleBorderToNumberOfLinks(numLinks); resampledBorders.push_back(b); } else { // // bummer // QString errorMessage; errorMessage = "Unable to find border named "; errorMessage.append(b1.getName()); errorMessage.append("in file "); errorMessage.append(inputBorderFiles[j]->getFileName()); throw FileException(errorMessage); } } // // Compute the average at each link // const int numLinks = b1.getNumberOfLinks(); for (int j = 0; j < numLinks; j++) { // // Position in first border file // float xyzSum[3] = { 0.0, 0.0, 0.0 }; float xyz[3]; b1.getLinkXYZ(j, xyz); xyzSum[0] += xyz[0]; xyzSum[1] += xyz[1]; xyzSum[2] += xyz[2]; // // Add in positions of other resampled borders // const int numResampledBorders = static_cast(resampledBorders.size()); for (int k = 0; k < numResampledBorders; k++) { resampledBorders[k].getLinkXYZ(j, xyz); xyzSum[0] += xyz[0]; xyzSum[1] += xyz[1]; xyzSum[2] += xyz[2]; } // // Average for this link // const float num = numResampledBorders + 1; const float average[3] = { xyzSum[0] / num, xyzSum[1] / num, xyzSum[2] / num }; // // Compute mean distance from average // std::vector distances; distances.push_back(MathUtilities::distance3D(b1.getLinkXYZ(j), average)); for (int k = 0; k < numResampledBorders; k++) { distances.push_back(MathUtilities::distance3D(average, resampledBorders[k].getLinkXYZ(j))); } StatisticDataGroup sdg(&distances, StatisticDataGroup::DATA_STORAGE_MODE_POINT); StatisticMeanAndDeviation smad; smad.addDataGroup(&sdg); try { smad.execute(); } catch (StatisticException&) { } b1.setLinkRadius(j, smad.getMean()); // // Set the average radius for this link // b1.setLinkXYZ(j, average); } // // add new average border to the border file that will be returned // averageBorderFileOut.addBorder(b1); } } // // Project to sphere if needed // if (averageBorderFileOut.getNumberOfBorders() > 0) { if (sphereFlag) { averageBorderFileOut.setSphericalBorderRadius(sphereRadius); } } QString comment("Average borders from: \n"); for (int i = 0; i < numFiles; i++) { comment.append(FileUtilities::basename(inputBorderFiles[i]->getFileName())); comment.append("\n"); } averageBorderFileOut.setFileComment(comment); averageBorderFileOut.setHeaderTag(AbstractFile::headerTagConfigurationID, inputBorderFiles[0]->getHeaderTag(AbstractFile::headerTagConfigurationID)); } /** * Clear the border file. */ void BorderFile::clear() { clearAbstractFile(); borders.clear(); } /** * Add a border to this file. */ void BorderFile::addBorder(const Border& b) { borders.push_back(b); const int index = static_cast(borders.size()) - 1; borders[index].borderFile = this; setModified(); } /** * Get a border index from its name. */ int BorderFile::getBorderIndexByName(const QString& nameToFind, const bool landmarkBordersFlag) const { for (unsigned int i = 0; i < borders.size(); i++) { if (landmarkBordersFlag) { if (Border::compareLandmarkBorderNames(borders[i].getName(), nameToFind)) { return i; } } else { if (borders[i].getName() == nameToFind) { return i; } } } return -1; } /** * Get a border by name (const method) */ const Border* BorderFile::getBorderByName(const QString& nameToFind, const bool landmarkBordersFlag) const { const int index = getBorderIndexByName(nameToFind, landmarkBordersFlag); if (index >= 0) { return &borders[index]; } return NULL; } /** * Get a border by name. */ Border* BorderFile::getBorderByName(const QString& nameToFind, const bool landmarkBordersFlag) { const int index = getBorderIndexByName(nameToFind, landmarkBordersFlag); if (index >= 0) { return &borders[index]; } return NULL; } /** * Apply transformation matrix to border file. */ void BorderFile::applyTransformationMatrix(TransformationMatrix& tm) { for (int i = 0; i < getNumberOfBorders(); i++) { Border* border = getBorder(i); border->applyTransformationMatrix(tm); /* const int numLinks = border->getNumberOfLinks(); for (int j = 0; j < numLinks; j++) { float xyz[3]; border->getLinkXYZ(j, xyz); double p[4] = { xyz[0], xyz[1], xyz[2], 1.0 }; tm.multiplyPoint(p); xyz[0] = p[0]; xyz[1] = p[1]; xyz[2] = p[2]; border->setLinkXYZ(j, xyz); } */ } setModified(); } /** * Get a border with the specified projection ID */ Border* BorderFile::getBorderWithProjectionID(const int projectionID) { const int index = getBorderIndexForBorderWithProjectionID(projectionID); if (index >= 0) { return getBorder(index); } return NULL; } /** * Get the index for the border with the specified projection ID */ int BorderFile::getBorderIndexForBorderWithProjectionID(const int projectionID) const { const int num = getNumberOfBorders(); for (int i = 0; i < num; i++) { const Border* b = getBorder(i); if (b->getBorderProjectionID() == projectionID) { return i; } } return -1; } /** * Remove a border at the specified index */ void BorderFile::removeBorder(const int borderNumber) { if (borderNumber < getNumberOfBorders()) { borders.erase(borders.begin() + borderNumber); } setModified(); } /** * remove borders with the specified indices. */ void BorderFile::removeBordersWithIndices(const std::vector& borderIndicesIn) { std::vector borderIndices = borderIndicesIn; std::sort(borderIndices.begin(), borderIndices.end()); const int num = static_cast(borderIndices.size()); for (int i = (num - 1); i >= 0; i--) { removeBorder(borderIndices[i]); } } /** * get the indices of borders that area duplicates of other borders. */ void BorderFile::getDuplicateBorderIndices(std::vector& duplicateBorderIndices) const { duplicateBorderIndices.clear(); const int numBorders = getNumberOfBorders(); for (int i = 0; i < (numBorders - 1); i++) { const Border* b = getBorder(i); for (int j = i + 1; j < numBorders; j++) { const Border* b2 = getBorder(j); if (*b == *b2) { duplicateBorderIndices.push_back(j); } } } } /** * Remove the border with the specified projection ID */ void BorderFile::removeBorderWithProjectionID(const int projectionID) { const int index = getBorderIndexForBorderWithProjectionID(projectionID); if (index >= 0) { removeBorder(index); setModified(); } } /** * Reset the border projection IDs on all borders so that they do not * appear to be projected borders. */ void BorderFile::resetBorderProjectionIDs() { const int num = getNumberOfBorders(); for (int i = 0; i < num; i++) { borders[i].setBorderProjectionID(-1); } } /** * Remove all projected borders from this border file. */ void BorderFile::removeAllProjectedBorders() { std::vector temp; const int num = getNumberOfBorders(); bool removedBorders = false; for (int i = 0; i < num; i++) { if (borders[i].getBorderProjectionID() >= 0) { removedBorders = true; } else { temp.push_back(borders[i]); } } if (removedBorders) { borders = temp; setModified(); } } /** * Set the status of all border name display flags */ void BorderFile::setAllNameDisplayFlags(const bool status) { const int num = getNumberOfBorders(); for (int i = 0; i < num; i++) { getBorder(i)->setNameDisplayFlag(status); } } /** * Set the status of all border display flags for borders with the specified name. */ void BorderFile::setNameDisplayFlagForBordersWithName(const QString& name, const bool flag) { const int num = getNumberOfBorders(); for (int i = 0; i < num; i++) { if (borders[i].getName() == name) { borders[i].setNameDisplayFlag(flag); } } } /** * Compute flat normals for borders. */ void BorderFile::computeFlatNormals() { const int num = getNumberOfBorders(); for (int i = 0; i < num; i++) { Border* b = getBorder(i); b->computeFlatNormals(); } } /** * Resample the displayed borders. */ void BorderFile::resampleDisplayedBorders(const float density) { const int num = getNumberOfBorders(); for (int i = 0; i < num; i++) { Border* b = getBorder(i); if (b->getDisplayFlag()) { int dummy; b->resampleBorderToDensity(density, 2, dummy); } } } /** * Resample all borders. */ void BorderFile::resampleAllBorders(const float density) { const int num = getNumberOfBorders(); for (int i = 0; i < num; i++) { Border* b = getBorder(i); int dummy; b->resampleBorderToDensity(density, 2, dummy); } } /** * Orient the displayed borders clockwise. */ void BorderFile::orientDisplayedBordersClockwise() { const int num = getNumberOfBorders(); for (int i = 0; i < num; i++) { Border* b = getBorder(i); if (b->getDisplayFlag()) { b->orientLinksClockwise(); } } } /** * Reverse the order of the links in the displayed borders. */ void BorderFile::reverseDisplayedBorders() { const int num = getNumberOfBorders(); for (int i = 0; i < num; i++) { Border* b = getBorder(i); if (b->getDisplayFlag()) { b->reverseBorderLinks(); } } } /** * Read the border file data. */ void BorderFile::readFileData(QFile& /*file*/, QTextStream& stream, QDataStream&, QDomElement& /* rootElement */) throw (FileException) { // // Should reading data be skipped ? // if (getReadMetaDataOnlyFlag()) { return; } QString line; // 1st line contains number of borders readLine(stream, line); const int numBorders = line.toInt(); for (int i = 0; i < numBorders; i++) { readLine(stream, line); int borderNumber; int numLinks = 0; QString borderName; float samplingDensity = 25.0, variance = 1.0, topography = 0.0, uncertainty = 1.0; QTextStream(&line, QIODevice::ReadOnly) >> borderNumber >> numLinks >> borderName >> samplingDensity >> variance >> topography >> uncertainty; // line containing the center (ignore) float center[3] = { 0.0, 0.0, 0.0 }; readLine(stream, line); // create the border Border border(borderName, center, samplingDensity, variance, topography, uncertainty); for (int j = 0; j < numLinks; j++) { readLine(stream, line); int linkNumber, sectionNumber; float xyz[3]; float radius = 0.0; QTextStream(&line, QIODevice::ReadOnly) >> linkNumber >> sectionNumber >> xyz[0] >> xyz[1] >> xyz[2] >> radius; border.addBorderLink(xyz, sectionNumber, radius); } addBorder(border); } } /** * Get the total number of links in a border. */ int BorderFile::getTotalNumberOfLinks() { int total = 0; for (int i = 0; i < getNumberOfBorders(); i++) { Border *border = getBorder(i); total += border->getNumberOfLinks(); } return total; } /** * Write the border file data. */ void BorderFile::writeFileData(QTextStream& stream, QDataStream&, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException) { int numBorders = getNumberOfBorders(); // // only write borders that have links // int numBordersToWrite = 0; for (int i = 0; i < numBorders; i++) { if (getBorder(i)->getNumberOfLinks() > 0) { numBordersToWrite++; } } stream << numBordersToWrite << "\n"; for (int i = 0; i < numBorders; i++) { Border* border = getBorder(i); const int numLinks = border->getNumberOfLinks(); // // Only write border if it has links // if (numLinks <= 0) { continue; } // write border number, number links, name, sampling, variance, topography QString name; float center[3]; float samplingDensity, variance, topography, uncertainty; border->getData(name, center, samplingDensity, variance, topography, uncertainty); stream << i << " " << numLinks << " " << name << " " << samplingDensity << " " << variance << " " << topography << " " << uncertainty << "\n"; // write border center (unused) stream << center[0] << " " << center[1] << " " << center[2] << "\n"; for (int j = 0; j < numLinks; j++) { // write link number, section, and xyz const float* xyz = border->getLinkXYZ(j); stream << j << " " << border->getLinkSectionNumber(j) << " " << xyz[0] << " " << xyz[1] << " " << xyz[2] << " " << border->getLinkRadius(j) << "\n"; } } } /** * Set the radius of all border links in a spherical border file. */ void BorderFile::setSphericalBorderRadius(const float newRadius) { if (newRadius <= 0.0) { return; } const int numBorders = getNumberOfBorders(); for (int i = 0; i < numBorders; i++) { Border* border = getBorder(i); const int numLinks = border->getNumberOfLinks(); for (int j = 0; j < numLinks; j++) { float xyz[3]; border->getLinkXYZ(j, xyz); const float oldRadius = sqrt(xyz[0]*xyz[0] + xyz[1]*xyz[1] + xyz[2]*xyz[2]); if (oldRadius != 0.0) { const float scale = newRadius / oldRadius; xyz[0] *= scale; xyz[1] *= scale; xyz[2] *= scale; border->setLinkXYZ(j, xyz); } } } } /** * convert configuration ID to spec file tag. */ QString BorderFile::convertConfigurationIDToSpecFileTag(const QString& nameIn) { const QString name(nameIn.toUpper()); if (name == "RAW") return SpecFile::getRawBorderFileTag(); else if (name == "FIDUCIAL") return SpecFile::getFiducialBorderFileTag(); else if (name == "INFLATED") return SpecFile::getInflatedBorderFileTag(); else if (name == "VERY_INFLATED") return SpecFile::getVeryInflatedBorderFileTag(); else if (name == "SPHERICAL") return SpecFile::getSphericalBorderFileTag(); else if (name == "ELLIPSOIDAL") return SpecFile::getEllipsoidBorderFileTag(); else if (name == "CMW") return SpecFile::getCompressedBorderFileTag(); else if (name == "FLAT") return SpecFile::getFlatBorderFileTag(); else if (name == "FLAT_LOBAR") return SpecFile::getLobarFlatBorderFileTag(); else if (name == "HULL") return SpecFile::getHullBorderFileTag(); else return SpecFile::getUnknownBorderFileMatchTag(); } /** * Write the file's memory in caret6 format to the specified name. */ QString BorderFile::writeFileInCaret6Format(const QString& filenameIn, Structure structure,const ColorFile* colorFileIn, const bool useCaret6ExtensionFlag) throw (FileException) { int numBorders = this->getNumberOfBorders(); if (numBorders <= 0) { throw FileException("Contains no borders"); } QString name = FileUtilities::filenameWithoutExtension(filenameIn) + SpecFile::getBorderProjectionFileExtension(); QFile file(name); if (file.open(QFile::WriteOnly) == false) { throw FileException("Unable to open for writing"); } QTextStream stream(&file); XmlGenericWriter xmlWriter(stream); xmlWriter.writeStartDocument(); XmlGenericWriterAttributes attributes; attributes.addAttribute("CaretFileType", "BorderProjection"); attributes.addAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); attributes.addAttribute("xsi:noNamespaceSchemaLocation", "http://brainvis.wustl.edu/caret6/xml_schemas/BorderProjectionFileSchema.xsd"); attributes.addAttribute("Version", "6.0"); xmlWriter.writeStartElement("CaretDataFile", attributes); this->writeHeaderXMLWriter(xmlWriter); GiftiLabelTable labelTable; if (colorFileIn != NULL) { labelTable.createLabelsFromColors(*colorFileIn); } labelTable.writeAsXML(xmlWriter); for (int i = 0; i < numBorders; i++) { Border* b = this->getBorder(i); int numLinks = b->getNumberOfLinks(); if (numLinks > 0) { XmlGenericWriterAttributes attributes; attributes.addAttribute("Index", i); xmlWriter.writeStartElement("BorderProjection", attributes); xmlWriter.writeElementCData("Name", b->getName()); for (int j = 0; j < numLinks; j++) { Caret6ProjectedItem pi; pi.projectionType = Caret6ProjectedItem::UNPROJECTED; b->getLinkXYZ(j, pi.xyz); pi.structure = structure; pi.writeXML(xmlWriter); } xmlWriter.writeEndElement(); } } xmlWriter.writeEndElement(); xmlWriter.writeEndDocument(); file.close(); return name; } caret-5.6.4~dfsg.1.orig/caret_files/BorderColorFile.h0000664000175000017500000000231311572067322022225 0ustar michaelmichael #ifndef __BORDER_COLOR_FILE_H #define __BORDER_COLOR_FILE_H /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "ColorFile.h" /// class for border colors file class BorderColorFile : public ColorFile { public: /// Constructor BorderColorFile(); /// Destructor ~BorderColorFile(); protected: }; #endif // __BORDER_COLOR_FILE_H caret-5.6.4~dfsg.1.orig/caret_files/BorderColorFile.cxx0000664000175000017500000000216511572067322022605 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BorderColorFile.h" #include "SpecFile.h" /** * Constructor */ BorderColorFile::BorderColorFile() : ColorFile("Border Color File", SpecFile::getBorderColorFileExtension()) { } /** * Destructor */ BorderColorFile::~BorderColorFile() { } caret-5.6.4~dfsg.1.orig/caret_files/AtlasSurfaceDirectoryFile.h0000664000175000017500000001366311572067322024265 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_ATLAS_SURFACE_DIRECTORY_FILE_H__ #define __VE_ATLAS_SURFACE_DIRECTORY_FILE_H__ #include "AbstractFile.h" /// This class maintains an atlas surface for used by the fMRI mapper class AtlasSurface { public: /// Type of Anatomy enum ATLAS_SURFACE_ANATOMY_TYPE { ATLAS_SURFACE_TYPE_NONE, ATLAS_SURFACE_TYPE_CEREBRAL_LEFT, ATLAS_SURFACE_TYPE_CEREBRAL_RIGHT, ATLAS_SURFACE_TYPE_CEREBELLUM }; /// Type of surface file enum ATLAS_SURFACE_FILE_TYPE { ATLAS_SURFACE_FILE_TYPE_NONE, ATLAS_SURFACE_FILE_TYPE_VTK_POLYDATA }; private: /// name of the atlas QString atlasName; /// a descriptive name of the atlas QString descriptiveName; /// type of anatomy ATLAS_SURFACE_ANATOMY_TYPE anatomyType; /// name of file QString fileName; /// type of file ATLAS_SURFACE_FILE_TYPE filetype; /// name of spec file QString specFileName; static const QString anatomyCerebralLeft; static const QString anatomyCerebralRight; static const QString anatomyCerebellum; static const QString fileTypeVTK; public: /// Constructor AtlasSurface(const QString& atlasNameIn, const QString& fileNameIn, const QString& descriptiveNameIn, const QString& specFileNameIn, const ATLAS_SURFACE_ANATOMY_TYPE anatomyTypeIn, const ATLAS_SURFACE_FILE_TYPE fileTypeIn); /// Destructor ~AtlasSurface(); /// Get the name of the atlas QString getAtlasName() const { return atlasName; } /// Get a descriptive name of the atlas QString getDescriptiveName() const { return descriptiveName; } /// Get the name of the file QString getFileName() const { return fileName; } /// Get the name of the spec file QString getSpecFileName() const { return specFileName; } /// Get the type of anatomy ATLAS_SURFACE_ANATOMY_TYPE getAnatomyType() const { return anatomyType; } /// Get all of the data attributes void getData(QString& atlasNameOut, QString& fileNameOut, QString& descriptiveNameOut, QString& specFileNameOut, ATLAS_SURFACE_ANATOMY_TYPE& anatomyTypeOut, ATLAS_SURFACE_FILE_TYPE& fileTypeOut) const; /// Set all of the data attributes void setData(const QString& atlasNameIn, const QString& fileNameIn, const QString& descriptiveNameIn, const QString& specFileNameIn, const ATLAS_SURFACE_ANATOMY_TYPE anatomyTypeIn, const ATLAS_SURFACE_FILE_TYPE fileTypeIn); friend class AtlasSurfaceDirectoryFile; }; /// This class reads an atlas directory file class AtlasSurfaceDirectoryFile : public AbstractFile { private: /// Storage for atlas surfaces std::vector atlasSurfaces; /// Pathname to the atlases QString fileLocationPathName; /// version of the file int fileVersion; static const QString tagFileVersion; /// write the file's data void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException); /// read the file's data void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException); public: /// Constructors AtlasSurfaceDirectoryFile(); /// Destructor ~AtlasSurfaceDirectoryFile(); /// Add an atlas surface to the file void addAtlasSurface(const AtlasSurface& as); /// Clear the file void clear(); /// is the file isEmpty bool empty() const { return (getNumberOfAtlasSurfaces() == 0); } /// get the file's version int getFileVersion() const { return fileVersion; } /// Get an atlas surface AtlasSurface* getAtlasSurface(const int index); /// Get the number of atlases int getNumberOfAtlasSurfaces() const; /// Set the pathname of where the data files are located. This /// needs to be called before "readFile". void setFileLocationPathName(const QString& path); }; #endif // __VE_ATLAS_SURFACE_DIRECTORY_FILE_H__ #ifdef VE_ATLAS_SURFACE_DIRECTORY_FILE_DEFINE const QString AtlasSurface::anatomyCerebralLeft = "Cerebral-Left"; const QString AtlasSurface::anatomyCerebralRight = "Cerebral-Right"; const QString AtlasSurface::anatomyCerebellum = "Cerebellum"; const QString AtlasSurface::fileTypeVTK = "VTK"; const QString AtlasSurfaceDirectoryFile::tagFileVersion = "tag-file-version"; #endif // VE_ATLAS_SURFACE_DIRECTORY_FILE_DEFINE caret-5.6.4~dfsg.1.orig/caret_files/AtlasSurfaceDirectoryFile.cxx0000664000175000017500000002013211572067322024625 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #define VE_ATLAS_SURFACE_DIRECTORY_FILE_DEFINE #include "AtlasSurfaceDirectoryFile.h" #undef VE_ATLAS_SURFACE_DIRECTORY_FILE_DEFINE #include "FileUtilities.h" #include "SpecFile.h" #include "StringUtilities.h" /** * Constructor. */ AtlasSurface::AtlasSurface(const QString& atlasNameIn, const QString& fileNameIn, const QString& descriptiveNameIn, const QString& specFileNameIn, const ATLAS_SURFACE_ANATOMY_TYPE anatomyTypeIn, const ATLAS_SURFACE_FILE_TYPE fileTypeIn) { setData(atlasNameIn, fileNameIn, descriptiveNameIn, specFileNameIn, anatomyTypeIn, fileTypeIn); } /** * Destructor. */ AtlasSurface::~AtlasSurface() { } /** * Get attribute data for an atlas surface. */ void AtlasSurface::getData(QString& atlasNameOut, QString& fileNameOut, QString& descriptiveNameOut, QString& specFileNameOut, ATLAS_SURFACE_ANATOMY_TYPE& anatomyTypeOut, ATLAS_SURFACE_FILE_TYPE& fileTypeOut) const { atlasNameOut = atlasName; fileNameOut = fileName; descriptiveNameOut = descriptiveName; specFileNameOut = specFileName; anatomyTypeOut = anatomyType; fileTypeOut = filetype; } /** * Set attribute data for an atlas surface. */ void AtlasSurface::setData(const QString& atlasNameIn, const QString& fileNameIn, const QString& descriptiveNameIn, const QString& specFileNameIn, const ATLAS_SURFACE_ANATOMY_TYPE anatomyTypeIn, const ATLAS_SURFACE_FILE_TYPE fileTypeIn) { atlasName = atlasNameIn; descriptiveName = descriptiveNameIn; specFileName = specFileNameIn; anatomyType = anatomyTypeIn; fileName = fileNameIn; filetype = fileTypeIn; } /** * Constructor. */ AtlasSurfaceDirectoryFile::AtlasSurfaceDirectoryFile() : AbstractFile("Atlas Surface Directory File", SpecFile::getAtlasSurfaceDirectoryFileExtension(), true, FILE_FORMAT_ASCII, FILE_IO_READ_ONLY, FILE_IO_NONE, FILE_IO_NONE, FILE_IO_NONE) { clear(); } /** * Destructor. */ AtlasSurfaceDirectoryFile::~AtlasSurfaceDirectoryFile() { clear(); } /** * Clear the file. */ void AtlasSurfaceDirectoryFile::clear() { clearAbstractFile(); atlasSurfaces.clear(); fileVersion = 0; } /** * Add an atlas surface. */ void AtlasSurfaceDirectoryFile::addAtlasSurface(const AtlasSurface& as) { atlasSurfaces.push_back(as); } /** * Get an atlas surface. */ AtlasSurface* AtlasSurfaceDirectoryFile::getAtlasSurface(const int index) { return &atlasSurfaces[index]; } /** * Get the number of atlas surfaces. */ int AtlasSurfaceDirectoryFile::getNumberOfAtlasSurfaces() const { return (int)atlasSurfaces.size(); } /** * Set the file location path. */ void AtlasSurfaceDirectoryFile::setFileLocationPathName(const QString& path) { fileLocationPathName = path; } /** * Read the file's data. */ void AtlasSurfaceDirectoryFile::readFileData(QFile& /*file*/, QTextStream& stream, QDataStream&, QDomElement& /* rootElement */) throw (FileException) { bool readingData = false; while (stream.atEnd() == false) { QString line; readLineChopComment(stream, line); if (line.isEmpty() == false) { if (readingData) { std::vector items; StringUtilities::token(line, "|", items); if (items.size() == 6) { const QString atlasName(items[0]); QString filename(items[3]); const QString descriptiveName(items[4]); const QString anatomyTypeString(items[1]); const QString fileTypeString(items[2]); const QString specFileName(items[5]); bool errorFlag = false; AtlasSurface::ATLAS_SURFACE_ANATOMY_TYPE anatomyType = AtlasSurface::ATLAS_SURFACE_TYPE_NONE; if (anatomyTypeString == AtlasSurface::anatomyCerebralLeft) { anatomyType = AtlasSurface::ATLAS_SURFACE_TYPE_CEREBRAL_LEFT; } else if (anatomyTypeString == AtlasSurface::anatomyCerebralRight) { anatomyType = AtlasSurface::ATLAS_SURFACE_TYPE_CEREBRAL_RIGHT; } else if (anatomyTypeString == AtlasSurface::anatomyCerebellum) { anatomyType = AtlasSurface::ATLAS_SURFACE_TYPE_CEREBELLUM; } else { QString msg("AtlasSurfaceDirectoryFile: Unknown anatomy type: "); msg.append(anatomyTypeString); throw FileException(FileUtilities::basename(filename), msg); } AtlasSurface::ATLAS_SURFACE_FILE_TYPE fileType = AtlasSurface::ATLAS_SURFACE_FILE_TYPE_NONE; if (fileTypeString.compare(AtlasSurface::fileTypeVTK) == 0) { fileType = AtlasSurface::ATLAS_SURFACE_FILE_TYPE_VTK_POLYDATA; } else { QString msg("AtlasSurfaceDirectoryFile: Unknown file type: "); msg.append(fileTypeString); throw FileException(FileUtilities::basename(filename), msg); errorFlag = true; } // // add directory to files that are relative // if (fileLocationPathName.length() > 0) { if (filename.length() > 0) { if (filename[0] != '/') { QString temp(fileLocationPathName); temp.append("/"); temp.append(filename); filename = temp; } } } if (errorFlag == false) { AtlasSurface as(atlasName, filename, descriptiveName, specFileName, anatomyType, fileType); addAtlasSurface(as); } } else { std::cout << "AtlasSurfaceDirectoryFile: bad data line " << line.toAscii().constData() << std::endl; } } else { QString tag; QTextStream istr(&line, QIODevice::ReadOnly); istr >> tag >> fileVersion; readingData = true; } } } } /** * Write the file's data. */ void AtlasSurfaceDirectoryFile::writeFileData(QTextStream& /*stream*/, QDataStream&, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException) { throw FileException(filename, "Writing AtlasSurfaceDirectoryFile files not supported."); } caret-5.6.4~dfsg.1.orig/caret_files/AtlasSpaceFile.h0000664000175000017500000001313711572067322022037 0ustar michaelmichael#ifndef __ATLAS_SPACE_FILE__ #define __ATLAS_SPACE_FILE__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ class QDomElement; class QDomNode; #include "AbstractFile.h" /// Class for storing information about an atlas surface class AtlasSpaceSurface { public: /// type of data files enum ATLAS_FILE_FORMAT { ATLAS_FILE_FORMAT_CARET, ATLAS_FILE_FORMAT_VTK }; /// Constructor for caret format AtlasSpaceSurface(const QString& directoryPathIn, const QString& descriptionIn, const QString& speciesIn, const QString& spaceIn, const QString& hemisphereIn, const QString& topologyFileNameIn, const QString& coordinateFileNameIn); /// Constructor for vtk format AtlasSpaceSurface(const QString& directoryPathIn, const QString& descriptionIn, const QString& speciesIn, const QString& spaceIn, const QString& hemisphereIn, const QString& vtkFileNameIn); /// Destructor for ~AtlasSpaceSurface(); /// get the atlas file format ATLAS_FILE_FORMAT getAtlasFileFormat() const { return atlasFileFormat; } /// get the description QString getDescription() const { return description; } /// get the species QString getSpecies() const { return species; } /// get the space QString getSpace() const { return space; } /// get the structure QString getStructure() const { return structure; } /// get the topology file name QString getTopologyFileName() const { return topologyFileName; } /// get the coordinate file name QString getCoordinateFileName() const { return coordinateFileName; } /// get the vtk file name QString getVtkFileName() const { return vtkFileName; } /// get the directory path QString getDirectoryPath() const { return directoryPath; } /// less than operator for sorting bool operator<(const AtlasSpaceSurface& asf) const; protected: /// type of surface file ATLAS_FILE_FORMAT atlasFileFormat; /// directory of files QString directoryPath; /// description QString description; /// species QString species; /// stereotaxic space QString space; /// structure QString structure; /// topology file (if ATLAS_FILE_FORMAT_CARET) QString topologyFileName; /// coordinate file (if ATLAS_FILE_FORMAT_CARET) QString coordinateFileName; /// vtk polydata file (if ATLAS_FILE_FORMAT_VTK) QString vtkFileName; }; /// class for file containing atlas surfaces class AtlasSpaceFile : public AbstractFile { public: /// constructor AtlasSpaceFile(); /// destructor ~AtlasSpaceFile(); /// append an atlas surface file to this one void append(AtlasSpaceFile& ccf) throw (FileException); /// clear the atlas surface file void clear(); /// returns true if the file is isEmpty (contains no data) bool empty() const { return (getNumberOfAtlasSurfaces() == 0); } /// add an atlas surface void addAtlasSurface(const AtlasSpaceSurface& as) { atlasSurfaces.push_back(as); } /// get the number of atlas surfaces int getNumberOfAtlasSurfaces() const { return atlasSurfaces.size(); } /// get an atlas surface by index AtlasSpaceSurface* getAtlasSurface(const int i) { return &atlasSurfaces[i]; } /// get file version int getFileVersion() const { return fileVersion; } /// sort the files void sort(); protected: /// version of the file int fileVersion; /// name of the root element //QString rootElementName; /// the atlas surface std::vector atlasSurfaces; /// Process the file version. void processFileVersion(QDomElement& elem) throw (FileException); /// Process an atlas surface. void processAtlasSurface(QDomElement& elem) throw (FileException); /// read the file void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException); /// write the file void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException); }; #endif // __ATLAS_SPACE_FILE__ caret-5.6.4~dfsg.1.orig/caret_files/AtlasSpaceFile.cxx0000664000175000017500000002500011572067322022402 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include "AtlasSpaceFile.h" #include "DebugControl.h" #include "FileUtilities.h" #include "SpecFile.h" #include "StringUtilities.h" /** * The constructor. */ AtlasSpaceFile::AtlasSpaceFile() : AbstractFile("Atlas Space File", SpecFile::getAtlasSpaceFileExtension(), true, FILE_FORMAT_XML, FILE_IO_NONE, FILE_IO_NONE, FILE_IO_READ_ONLY, FILE_IO_NONE) { clear(); } /** * The destructor. */ AtlasSpaceFile::~AtlasSpaceFile() { clear(); } /** * Append a Atlas Surface file to this one */ void AtlasSpaceFile::append(AtlasSpaceFile& asf) throw (FileException) { for (int i = 0; i < asf.getNumberOfAtlasSurfaces(); i++) { addAtlasSurface(*asf.getAtlasSurface(i)); } // // transfer the file's comment // appendFileComment(asf); } /** * Clear the file. */ void AtlasSpaceFile::clear() { clearAbstractFile(); //rootElementName = "atlas-space-file"); atlasSurfaces.clear(); fileVersion = -1; } /** * sort the files. */ void AtlasSpaceFile::sort() { std::sort(atlasSurfaces.begin(), atlasSurfaces.end()); } /** * Read the file. */ void AtlasSpaceFile::readFileData(QFile& /*file*/, QTextStream& /* stream */, QDataStream&, QDomElement& rootElement) throw (FileException) { /* // // Read the remainder of the file into a QString. // const QString remainderOfFile = stream.read(); // // Place the file contents into a QDomDocument which will parse file. // QString errorMessage; int errorLine = 0, errorColumn = 0; QDomDocument doc("atlas-surface-file-document"); if (doc.setContent(remainderOfFile, &errorMessage, &errorLine, &errorColumn) == false) { std::ostringstream str; str << "Error parsing at line " << errorLine << " column " << errorColumn << ". "; str << errorMessage << std::ends; throw FileException(filename, str.str().c_str()); } // // Traverse the direct children // //QDomElement docElem = doc.documentElement(); const QString rootElementNameFound(rootElement.tagName()); if (rootElementNameFound != rootElementName) { QString msg("\nNot an AtlasSurfaceFile. Root element is: "); msg.append(rootElementNameFound); msg.append(".\nRoot element should be: "); msg.append(rootElementName); throw FileException(filename, msg); } */ QDomNode node = rootElement.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (DebugControl::getDebugOn()) { std::cout << "Tag Name: " << elem.tagName().toAscii().constData() << std::endl; } if ((elem.tagName() == xmlHeaderOldTagName) || (elem.tagName() == xmlHeaderTagName)) { readHeaderXML(elem); } else if (elem.tagName() == "file-version") { processFileVersion(elem); } else if (elem.tagName() == "surface") { processAtlasSurface(elem); } else { std::cerr << "Atlas Surface node not recognized in root " << elem.tagName().toAscii().constData() << std::endl; } } node = node.nextSibling(); } sort(); } /** * Process the file version. */ void AtlasSpaceFile::processFileVersion(QDomElement& elem) throw (FileException) { QDomNode vNode = elem.firstChild(); if (vNode.isNull() == false) { QDomText textNode = vNode.toText(); if (textNode.isNull() == false) { fileVersion = StringUtilities::toInt(textNode.data()); } } } /** * Process an atlas surface. */ void AtlasSpaceFile::processAtlasSurface(QDomElement& elem) throw (FileException) { QString description; QString format; QString species; QString space; QString structure; QString topoFileName; QString coordFileName; QString vtkFileName; QDomNode node = elem.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { const QString tagName(elem.tagName()); if (tagName == "description") { description = getXmlElementFirstChildAsString(elem); } else if (tagName == "format") { format = getXmlElementFirstChildAsString(elem); } else if (tagName == "species") { species = getXmlElementFirstChildAsString(elem); } else if (tagName == "space") { space = getXmlElementFirstChildAsString(elem); } else if ((tagName == "hemisphere") || (tagName == "structure")) { structure = getXmlElementFirstChildAsString(elem); } else if (tagName == "topo-file") { topoFileName = getXmlElementFirstChildAsString(elem); } else if (tagName == "coord-file") { coordFileName = getXmlElementFirstChildAsString(elem); } else if (tagName == "vtk-file") { vtkFileName = getXmlElementFirstChildAsString(elem); } } node = node.nextSibling(); } bool valid = false; if ((description.isEmpty() == false) && (format.isEmpty() == false) && (species.isEmpty() == false) && (space.isEmpty() == false) && (structure.isEmpty() == false)) { const QString dirPath(FileUtilities::dirname(getFileName())); if ((topoFileName.isEmpty() == false) && (coordFileName.isEmpty() == false) && (format == "caret")) { valid = true; addAtlasSurface(AtlasSpaceSurface( dirPath, description, species, space, structure, topoFileName, coordFileName)); } else if ((vtkFileName.isEmpty() == false) && (format == "vtk")) { valid = true; addAtlasSurface(AtlasSpaceSurface( dirPath, description, species, space, structure, vtkFileName)); } } if (valid == false) { std::cout << "Atlas Surface File Error: " << std::endl; std::cout << " description: " << description.toAscii().constData() << std::endl; std::cout << " format: " << format.toAscii().constData() << std::endl; std::cout << " species: " << species.toAscii().constData() << std::endl; std::cout << " space: " << space.toAscii().constData() << std::endl; std::cout << " structure: " << structure.toAscii().constData() << std::endl; std::cout << " topoFileName: " << topoFileName.toAscii().constData() << std::endl; std::cout << " coordFileName: " << coordFileName.toAscii().constData() << std::endl; std::cout << " vtkFileName: " << vtkFileName.toAscii().constData() << std::endl; std::cout << std::endl; } } /** * Write and atlas surface file. */ void AtlasSpaceFile::writeFileData(QTextStream& /*stream*/, QDataStream&, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw(FileException) { throw FileException(filename, "Writing Atlas Surface is not supported"); } // //=================================================================================== // /** * Constructor for caret format. */ AtlasSpaceSurface::AtlasSpaceSurface(const QString& directoryPathIn, const QString& descriptionIn, const QString& speciesIn, const QString& spaceIn, const QString& structureIn, const QString& topologyFileNameIn, const QString& coordinateFileNameIn) { atlasFileFormat = ATLAS_FILE_FORMAT_CARET; directoryPath = directoryPathIn; description = descriptionIn; species = speciesIn; space = spaceIn; structure = structureIn; topologyFileName = topologyFileNameIn; coordinateFileName = coordinateFileNameIn; } /** * Constructor for vtk format. */ AtlasSpaceSurface::AtlasSpaceSurface(const QString& directoryPathIn, const QString& descriptionIn, const QString& speciesIn, const QString& spaceIn, const QString& structureIn, const QString& vtkFileNameIn) { atlasFileFormat = ATLAS_FILE_FORMAT_VTK; directoryPath = directoryPathIn; description = descriptionIn; species = speciesIn; space = spaceIn; structure = structureIn; vtkFileName = vtkFileNameIn; } /** * Destructor */ AtlasSpaceSurface::~AtlasSpaceSurface() { } /** * less than operator for sorting. */ bool AtlasSpaceSurface::operator<(const AtlasSpaceSurface& asf) const { if (species < asf.species) { return true; } else if (species == asf.species) { if (space < asf.space) { return true; } else if (space == asf.space) { if (structure < asf.structure) { return true; } } } return false; } caret-5.6.4~dfsg.1.orig/caret_files/ArealEstimationFile.h0000664000175000017500000001504711572067322023102 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __AREAL_ESTIMATION_FILE__ #define __AREAL_ESTIMATION_FILE__ class ArealEstimationFile; class DeformationMapFile; #include "NodeAttributeFile.h" /// Areal Estimation Data for a node class ArealEstimationNode { private: /// Areal Estimation File this node belongs to ArealEstimationFile* arealEstimationFile; /// area names for a node int areaNamesIndex[4]; /// probability of each area for anode float areaProbability[4]; public: /// Constructor ArealEstimationNode(); /// Destructor ~ArealEstimationNode(); /// reset the data void reset(); /// Get the data void getData(int areaNamesIndexOut[4], float areaProbabilityOut[4]) const; /// Set the data void setData(const int areaNamesIndexIn[4], const float areaProbabilityIn[4]); friend class ArealEstimationFile; }; /// Areal Estimation File ("fuzzy" borders) class ArealEstimationFile : public NodeAttributeFile { private: /// area names (common to all columns) std::vector areaNames; /// areal estimation data for all nodes std::vector nodeData; /// long name for columns std::vector longName; /// long name for reading version 1 file QString version1LongName; /// short name for reading version 1 file QString version1ShortName; /// read version 2 of the file void readFileDataVersion2(QFile& file, QTextStream& stream, QDataStream& binStream) throw (FileException); /// read version 1 of the file void readFileDataVersion1(QTextStream& stream) throw (FileException); void readTags(QTextStream& stream, const int fileVersion) throw (FileException); static const QString tagLongName; public: /// Constructor ArealEstimationFile(); /// Destructor ~ArealEstimationFile(); /// Add an area name int addAreaName(const QString& name); /// append a node attribute file to this one void append(NodeAttributeFile& naf) throw (FileException); /// append a node attribute file to this one but selectively load/overwrite columns /// columnDestination is where naf's columns should be (-1=new, -2=do not load) void append(NodeAttributeFile& naf, std::vector columnDestination, const FILE_COMMENT_MODE fcm) throw (FileException); /// Add isEmpty columns to this areal estimation file void addColumns(const int numberOfNewColumns); /// Add nodes to the file void addNodes(const int numberOfNodesToAdd); /// Clear current file in memory void clear(); /// deform "this" node attribute file placing the output in "deformedFile". void deformFile(const DeformationMapFile& dmf, NodeAttributeFile& deformedFile, const DEFORM_TYPE dt) const throw (FileException); /// reset a column of data void resetColumn(const int columnNumber); /// remove a column of data void removeColumn(const int columnNumber); /// Get an area name QString getAreaName(const int index) const; /// Get the long name for a column QString getLongName(const int columnNumber) const { return longName[columnNumber]; } /// Get the node's data with string names void getNodeData(const int nodeNumber, const int columnNumber, QString areaNamesOut[4], float areaProbabilityOut[4]) const; /// Get the node's data with name indices void getNodeData(const int nodeNumber, const int columnNumber, int areaNamesIndexOut[4], float areaProbabilityOut[4]) const; /// Get number of area names inline int getNumberOfAreaNames() const { return areaNames.size(); } /// Set the long name void setLongName(const int columnNumber, const QString& ln); /// Set the node's data with names void setNodeData(const int nodeNumber, const int columnNumber, const QString areaNamesIn[4], const float areaProbabilityIn[4]); /// Set the node's data with name indices void setNodeData(const int nodeNumber, const int columnNumber, const int areaNamesIndexIn[4], const float areaProbabilityIn[4]); /// Set Number of Nodes - clears node data. area names unchanged void setNumberOfNodesAndColumns(const int numNodes, const int numCols); /// Read data from the filepointer (header has already been read) void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException); /// Write data to the filepointer (header has already been written) void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException); friend class ArealEstimationNode; }; #endif // __AREAL_ESTIMATION_FILE__ #ifdef __AREAL_ESTIMATION_FILE_DEFINE__ const QString ArealEstimationFile::tagLongName = "tag-long-name"; #endif // __AREAL_ESTIMATION_FILE_DEFINE__ caret-5.6.4~dfsg.1.orig/caret_files/ArealEstimationFile.cxx0000664000175000017500000006633211572067322023460 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #define __AREAL_ESTIMATION_FILE_DEFINE__ #include "ArealEstimationFile.h" #undef __AREAL_ESTIMATION_FILE_DEFINE__ #include "DeformationMapFile.h" #include "FileUtilities.h" #include "SpecFile.h" #include "StringUtilities.h" /** * The constructor. */ ArealEstimationNode::ArealEstimationNode() { arealEstimationFile = NULL; reset(); } /** * The destructor. */ ArealEstimationNode::~ArealEstimationNode() { } /** * Reset the node. */ void ArealEstimationNode::reset() { for (int i = 0; i < 4; i++) { areaProbability[i] = 0.0; areaNamesIndex[i] = 0; } } /** * Get the data for the node. */ void ArealEstimationNode::getData(int areaNamesIndexOut[4], float areaProbabilityOut[4]) const { for (int i = 0; i < 4; i++) { areaNamesIndexOut[i] = areaNamesIndex[i]; areaProbabilityOut[i] = areaProbability[i]; } } /** * Set the data for the node. */ void ArealEstimationNode::setData(const int areaNamesIndexIn[4], const float areaProbabilityIn[4]) { for (int i = 0; i < 4; i++) { areaNamesIndex[i] = areaNamesIndexIn[i]; areaProbability[i] = areaProbabilityIn[i]; } if (arealEstimationFile != NULL) { arealEstimationFile->setModified(); } } /** * The constructor. */ ArealEstimationFile::ArealEstimationFile() : NodeAttributeFile("Areal Estimation File", SpecFile::getArealEstimationFileExtension(), AbstractFile::FILE_FORMAT_ASCII, FILE_IO_READ_AND_WRITE, FILE_IO_READ_AND_WRITE, FILE_IO_NONE, FILE_IO_NONE) { clear(); clearModified(); } /** * The destructor. */ ArealEstimationFile::~ArealEstimationFile() { clear(); } /** * Add an area name. */ int ArealEstimationFile::addAreaName(const QString& name) { for (unsigned int i = 0; i < areaNames.size(); i++) { if (name.compare(areaNames[i]) == 0) { return i; } } setModified(); areaNames.push_back(name); return (areaNames.size() - 1); } /** * Clear the file. */ void ArealEstimationFile::clear() { clearNodeAttributeFile(); areaNames.clear(); setNumberOfNodesAndColumns(0, 0); addAreaName("???"); } /** * append a node attribute file to this one but selectively load/overwrite columns * columnDestination is where naf's columns should be (-1=new, -2=do not load). */ void ArealEstimationFile::append(NodeAttributeFile& naf, std::vector columnDestinationIn, const FILE_COMMENT_MODE fcm) throw (FileException) { bool setTheFileNameFlag = false; std::vector columnDestination = columnDestinationIn; ArealEstimationFile& aef = dynamic_cast(naf); if (numberOfNodes != aef.numberOfNodes) { if (numberOfNodes > 0) { throw FileException("Trying to append areal estimtation file with a different number " "of nodes"); } else { setTheFileNameFlag = true; } } setModified(); // // Find out how many columns need to be added // int numColumnsToAdd = 0; int newColumnIndex = numberOfColumns; for (int i = 0; i < aef.getNumberOfColumns(); i++) { if (columnDestination[i] == APPEND_COLUMN_NEW) { numColumnsToAdd++; columnDestination[i] = newColumnIndex; newColumnIndex++; } } // // Add on additional columns // if (getNumberOfNodes() == 0) { setNumberOfNodesAndColumns(aef.getNumberOfNodes(), numColumnsToAdd); } else { addColumns(numColumnsToAdd); } // // copy column names from other file // for (int k = 0; k < aef.numberOfColumns; k++) { if (columnDestination[k] >= 0) { const int col = columnDestination[k]; setColumnName(col, aef.getColumnName(k)); setColumnComment(col, aef.getColumnComment(k)); setLongName(col, aef.getLongName(k)); } } // // Transfer area names // std::vector areaNameIndex; for (int k = 0; k < aef.getNumberOfAreaNames(); k++) { areaNameIndex.push_back(addAreaName(aef.getAreaName(k))); } // // copy areal estimation data from other file // int areaNamesData[4]; float probData[4]; for (int j = 0; j < aef.numberOfColumns; j++) { if (columnDestination[j] >= 0) { const int col = columnDestination[j]; for (int i = 0; i < numberOfNodes; i++) { aef.getNodeData(i, j, areaNamesData, probData); for (int m = 0; m < 4; m++) { areaNamesData[m] = areaNameIndex[areaNamesData[m]]; } setNodeData(i, col, areaNamesData, probData); } } } if (setTheFileNameFlag) { setFileName(aef.getFileName()); } // // transfer the file's comment // appendFileComment(aef, fcm); } /** * Append an areal estimation file to this one. */ void ArealEstimationFile::append(NodeAttributeFile& naf) throw (FileException) { ArealEstimationFile& aef = dynamic_cast(naf); if (getNumberOfNodes() != aef.getNumberOfNodes()) { throw FileException("Cannot append areal estimation, number of columns does not match."); } const int oldNumCols = getNumberOfColumns(); const int appendNumCols = aef.getNumberOfColumns(); // // Add the additional columns to the file // addColumns(appendNumCols); // // Transfer column attributes // for (int n = 0; n < appendNumCols; n++) { setColumnComment(oldNumCols + n, aef.getColumnComment(n)); setColumnName(oldNumCols + n, aef.getColumnName(n)); setLongName(oldNumCols + n, aef.getLongName(n)); } // // Transfer area names // std::vector areaNameIndex; for (int k = 0; k < aef.getNumberOfAreaNames(); k++) { areaNameIndex.push_back(addAreaName(aef.getAreaName(k))); } // // Transfer areal estimation data // int areaNamesData[4]; float probData[4]; for (int i = 0; i < numberOfNodes; i++) { for (int k = 0; k < appendNumCols; k++) { aef.getNodeData(i, k, areaNamesData, probData); for (int m = 0; m < 4; m++) { areaNamesData[m] = areaNameIndex[areaNamesData[m]]; } setNodeData(i, oldNumCols + k, areaNamesData, probData); } } // // transfer the file's comment // appendFileComment(aef); setModified(); } /** * Add column(s) to the file */ void ArealEstimationFile::addColumns(const int numberOfNewColumns) { const int oldNumberOfColumns = numberOfColumns; const int totalColumns = numberOfColumns + numberOfNewColumns; // // Keep track of existing areal estimation node data // const std::vector oldData = nodeData; // // Setup file for new number of columns (will expand space for column naming) // setNumberOfNodesAndColumns(numberOfNodes, totalColumns); // // Transfer existing areal estimation node data // for (int i = 0; i < numberOfNodes; i++) { for (int j = 0; j < numberOfColumns; j++) { int areaNameData[4] = { 0, 0, 0, 0 }; float probData[4] = { 0.0, 0.0, 0.0, 0.0 }; if (j < oldNumberOfColumns) { const int oldIndex = (oldNumberOfColumns * i) + j; oldData[oldIndex].getData(areaNameData, probData); } setNodeData(i, j, areaNameData, probData); } } setModified(); } /** * Add nodes to the file */ void ArealEstimationFile::addNodes(const int numberOfNodesToAdd) { setNumberOfNodesAndColumns(numberOfNodes + numberOfNodesToAdd, numberOfColumns); setModified(); } /** * Set the long name for a column. */ void ArealEstimationFile::setLongName(const int columnNumber, const QString& name) { longName[columnNumber] = name; setModified(); } /** * Deform this areal estimation data into the deformed file passed in. * Returns true if an error occurs. */ void ArealEstimationFile::deformFile(const DeformationMapFile& dmf, NodeAttributeFile& deformedFile, const DEFORM_TYPE /*dt*/) const throw (FileException) { ArealEstimationFile& deformedArealEstimationFile = dynamic_cast(deformedFile); const int numNodes = dmf.getNumberOfNodes(); deformedArealEstimationFile.setNumberOfNodesAndColumns(numNodes, getNumberOfColumns()); // // Transfer the area names // for (int j = 0; j < getNumberOfAreaNames(); j++) { deformedArealEstimationFile.addAreaName(getAreaName(j)); } // // Transfer stuff in AbstractFile and NodeAttributeFile // transferFileDataForDeformation(dmf, deformedArealEstimationFile); for (int j = 0; j < getNumberOfColumns(); j++) { deformedArealEstimationFile.setLongName(j, getLongName(j)); } // // Transfer the node probability data // int tileNodes[3]; float tileAreas[3]; int areaNameIndex[4]; float areaProbability[4]; for (int i = 0; i < numNodes; i++) { for (int j = 0; j < getNumberOfColumns(); j++) { dmf.getDeformDataForNode(i, tileNodes, tileAreas); if (tileNodes[0] > -1) { getNodeData(tileNodes[0], j, areaNameIndex, areaProbability); } else { for (int j = 0; j < 4; j++) { areaNameIndex[j] = 0; areaProbability[j] = 0.0; } } deformedArealEstimationFile.setNodeData(i, j, areaNameIndex, areaProbability); } } } /** * reset a column of data. */ void ArealEstimationFile::resetColumn(const int columnNumber) { for (int i = 0; i < numberOfNodes; i++) { const int index = getOffset(i, columnNumber); nodeData[index].reset(); } setModified(); } /** * remove a column of data. */ void ArealEstimationFile::removeColumn(const int columnNumber) { if (numberOfColumns <= 1) { clear(); return; } ArealEstimationFile tempAEF; if (numberOfColumns > 1) { // // Transfer column attributes // int ctr = 0; for (int n = 0; n < numberOfColumns; n++) { if (n != columnNumber) { setColumnComment(ctr, getColumnComment(n)); setColumnName(ctr, getColumnName(n)); setLongName(ctr, getLongName(n)); ctr++; } } // // Transfer areal estimation data // tempAEF.setNumberOfNodesAndColumns(numberOfNodes, numberOfColumns - 1); int areaNamesData[4]; float probData[4]; for (int i = 0; i < numberOfNodes; i++) { int ctr = 0; for (int k = 0; k < numberOfColumns; k++) { if (k != columnNumber) { getNodeData(i, k, areaNamesData, probData); tempAEF.setNodeData(i, ctr, areaNamesData, probData); ctr++; } } } } setNumberOfNodesAndColumns(numberOfNodes, numberOfColumns - 1); nodeData = tempAEF.nodeData; setModified(); } /** * Get an area name. */ QString ArealEstimationFile::getAreaName(const int index) const { if ((index >= 0) && (index <= static_cast(areaNames.size()))) { return areaNames[index]; } return "???"; } /** * Get data for the specified node and column. */ void ArealEstimationFile::getNodeData(const int nodeNumber, const int columnNumber, QString areaNamesOut[4], float areaProbabilityOut[4]) const { const int index = getOffset(nodeNumber, columnNumber); if (index >= 0) { int areaNamesIndexOut[4]; nodeData[index].getData(areaNamesIndexOut, areaProbabilityOut); for (int i = 0; i < 4; i++) { areaNamesOut[i] = getAreaName(areaNamesIndexOut[i]); } } else { for (int i = 0; i < 4; i++) { areaNamesOut[i] = "???"; areaProbabilityOut[i] = 0.0; } } } /** * Get data for the specified node and column. */ void ArealEstimationFile::getNodeData(const int nodeNumber, const int columnNumber, int areaNamesIndexOut[4], float areaProbabilityOut[4]) const { const int index = getOffset(nodeNumber, columnNumber); if (index >= 0) { nodeData[index].getData(areaNamesIndexOut, areaProbabilityOut); } else { for (int i = 0; i < 4; i++) { areaNamesIndexOut[i] = 0; areaProbabilityOut[i] = 0.0; } } } /** * Set the data for the node and column. */ void ArealEstimationFile::setNodeData(const int nodeNumber, const int columnNumber, const QString areaNamesIn[4], const float areaProbabilityIn[4]) { const int index = getOffset(nodeNumber, columnNumber); if (index >= 0) { int areaNamesIndexIn[4]; for (int i = 0; i < 4; i++) { areaNamesIndexIn[i] = addAreaName(areaNamesIn[i]); } nodeData[index].setData(areaNamesIndexIn, areaProbabilityIn); setModified(); } } /** * Set the data for the node and column. */ void ArealEstimationFile::setNodeData(const int nodeNumber, const int columnNumber, const int areaNamesIndexIn[4], const float areaProbabilityIn[4]) { const int index = getOffset(nodeNumber, columnNumber); if (index >= 0) { nodeData[index].setData(areaNamesIndexIn, areaProbabilityIn); setModified(); } } /** * Set the number of nodes and columnsfor this file. */ void ArealEstimationFile::setNumberOfNodesAndColumns(const int numNodes, const int numColumns) { if ((numNodes == 0) || (numColumns == 0)) { longName.clear(); nodeData.clear(); } else { longName.resize(numColumns); nodeData.resize(numNodes * numColumns); } numberOfNodes = numNodes; numberOfColumns = numColumns; numberOfNodesColumnsChanged(); setModified(); for (int i = 0; i < (numNodes * numColumns); i++) { nodeData[i].arealEstimationFile = this; } } /** * Read version 1 of the file. */ void ArealEstimationFile::readFileDataVersion1(QTextStream& stream) throw (FileException) { QString line; readLine(stream, line); const int numAreaNames = line.toInt(); if (numAreaNames < 1) { throw FileException(filename, "No area names in file"); } areaNames.reserve(numAreaNames); for (int i = 0; i < numAreaNames; i++) { QString indexStr, name; readTagLine(stream, indexStr, name); if (name.isEmpty()) { throw FileException(filename, "reading line with area name"); } addAreaName(name); } readLine(stream, line); const int numNodes = line.toInt(); if (numNodes < 1) { throw FileException(filename, "Reading line with number of nodes"); } setNumberOfNodesAndColumns(numNodes, 1); setColumnComment(0, getFileComment()); longName[0] = version1LongName; setColumnName(0,version1ShortName); // // Should reading data be skipped ? // if (getReadMetaDataOnlyFlag()) { return; } for (int j = 0; j < numNodes; j++) { readLine(stream, line); std::vector tokens; StringUtilities::token(line, " ", tokens); if (tokens.size() != 9) { throw FileException(filename, "Reading a line of data"); } int n[4]; float p[4]; n[0] = tokens[1].toInt(); p[0] = tokens[2].toFloat(); n[1] = tokens[3].toInt(); p[1] = tokens[4].toFloat(); n[2] = tokens[5].toInt(); p[2] = tokens[6].toFloat(); n[3] = tokens[7].toInt(); p[3] = tokens[8].toFloat(); setNodeData(j, 0, n, p); } } /** * Read version 2 of the file. */ void ArealEstimationFile::readFileDataVersion2(QFile& file, QTextStream& stream, QDataStream& binStream) throw (FileException) { QString line; readLine(stream, line); const int numAreaNames = line.toInt(); if (numAreaNames < 1) { throw FileException(filename, "No area names in file"); } areaNames.reserve(numAreaNames); #ifdef QT4_FILE_POS_BUG QString lastLineRead; #endif // QT4_FILE_POS_BUG for (int i = 0; i < numAreaNames; i++) { QString indexStr, line, name; readTagLine(stream, line, indexStr, name); if (name.isEmpty()) { throw FileException(filename, "reading line with area name"); } addAreaName(name); #ifdef QT4_FILE_POS_BUG lastLineRead = line; #endif // QT4_FILE_POS_BUG } // // Should reading data be skipped ? // if (getReadMetaDataOnlyFlag()) { return; } #ifdef QT4_FILE_POS_BUG if (getFileReadType() == FILE_FORMAT_BINARY) { if (lastLineRead.isEmpty() == false) { qint64 offset = findBinaryDataOffsetQT4Bug(file, lastLineRead.toAscii().constData()); if (offset > 0) { offset++; file.seek(offset); } } } #endif // QT4_FILE_POS_BUG switch (getFileReadType()) { case FILE_FORMAT_ASCII: for (int j = 0; j < numberOfNodes; j++) { readLine(stream, line); std::vector tokens; StringUtilities::token(line, " ", tokens); if (static_cast(tokens.size()) != (numberOfColumns * 8 + 1)) { QString msg("Reading a line of data"); msg.append(line); //std::cout << "Number of tokens is " << tokens.size() // << " numberOfColumns is " << numberOfColumns << std::endl; throw FileException(filename, msg); } for (int k = 0; k < numberOfColumns; k++) { int n[4]; float p[4]; n[0] = tokens[k * 8 + 1].toInt(); p[0] = tokens[k * 8 + 2].toFloat(); n[1] = tokens[k * 8 + 3].toInt(); p[1] = tokens[k * 8 + 4].toFloat(); n[2] = tokens[k * 8 + 5].toInt(); p[2] = tokens[k * 8 + 6].toFloat(); n[3] = tokens[k * 8 + 7].toInt(); p[3] = tokens[k * 8 + 8].toFloat(); setNodeData(j, k, n, p); } } break; case FILE_FORMAT_BINARY: // // Needed for QT 4.2.2 // file.seek(stream.pos()); for (int j = 0; j < numberOfNodes; j++) { for (int k = 0; k < numberOfColumns; k++) { int namesIndex[4]; float prob[4]; binStream >> namesIndex[0] >> prob[0] >> namesIndex[1] >> prob[1] >> namesIndex[2] >> prob[2] >> namesIndex[3] >> prob[3]; setNodeData(j, k, namesIndex, prob); } } break; case FILE_FORMAT_XML: throw FileException(filename, "Reading in XML format not supported."); break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "Reading XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "Reading XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Reading XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Reading in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Reading Comma Separated Value File Format not supported."); break; } } /** * Read the file's tags. */ void ArealEstimationFile::readTags(QTextStream& stream, const int fileVersion) throw (FileException) { int numNodes = 0; int numCols = 0; bool readingTags = true; while(readingTags) { QString tag, tagValue; readTagLine(stream, tag, tagValue); if (tag == tagBeginData) { readingTags = false; } else if (tag == tagNumberOfNodes) { numNodes = tagValue.toInt(); if ((numCols > 0) && (numNodes > 0)) { setNumberOfNodesAndColumns(numNodes, numCols); } } else if (tag == tagNumberOfColumns) { numCols = tagValue.toInt(); if ((numCols > 0) && (numNodes > 0)) { setNumberOfNodesAndColumns(numNodes, numCols); } } else if ((tag == tagColumnName) || (tag == "tag-short-name")) { if (fileVersion == 1) { version1ShortName = tagValue; } else { QString name; const int index = splitTagIntoColumnAndValue(tagValue, name); setColumnName(index, name); } } else if (tag == tagLongName) { if (fileVersion == 1) { version1LongName = tagValue; } else { QString name; const int index = splitTagIntoColumnAndValue(tagValue, name); longName[index] = name; } } else if (tag == tagColumnComment) { QString name; const int index = splitTagIntoColumnAndValue(tagValue, name); columnComments[index] = StringUtilities::setupCommentForDisplay(name); } else if (tag == "tag-comment") { setFileComment(tagValue); } else if (tag == tagFileTitle) { setFileTitle(tagValue); } else if (tag == tagColumnStudyMetaData) { QString name; const int index = splitTagIntoColumnAndValue(tagValue, name); studyMetaDataLinkSet[index].setLinkSetFromCodedText(name); } else { std::cerr << "WARNING: Unknown Areal Estimation File Tag: " << tag.toAscii().constData() << std::endl; } } } /** * Read the areal estimation file. */ void ArealEstimationFile::readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& /* rootElement */) throw (FileException) { int fileVersion = 0; QString versionTag; QString versionNumStr; readTagLine(stream, versionTag, versionNumStr); if ((versionTag != tagFileVersion) && (versionTag != "tag-file-version")) { throw FileException(filename, "Unable to find line with version tag"); } if (versionNumStr.isEmpty()) { throw FileException(filename, "Reading line containing file version number"); } fileVersion = versionNumStr.toInt(); readTags(stream, fileVersion); switch(fileVersion) { case 2: readFileDataVersion2(file, stream, binStream); break; case 1: readFileDataVersion1(stream); break; default: throw FileException(filename, "Unsupported version of areal estimation file"); break; } } /** * Write the areal estimation file. */ void ArealEstimationFile::writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& /* xmlDoc */, QDomElement& /* rootElement */) throw (FileException) { stream << tagFileVersion << " 2\n"; stream << tagNumberOfNodes << " " << numberOfNodes << "\n"; stream << tagNumberOfColumns << " " << numberOfColumns << "\n"; stream << tagFileTitle << " " << fileTitle << "\n"; for (int k = 0; k < numberOfColumns; k++) { stream << tagColumnComment << " " << k << " " << StringUtilities::setupCommentForStorage(columnComments[k]) << "\n"; stream << tagLongName << " " << k << " " << longName[k] << "\n"; stream << tagColumnName << " " << k << " "<< columnNames[k] << "\n"; stream << tagColumnStudyMetaData << " " << k << " " << studyMetaDataLinkSet[k].getLinkSetAsCodedText() << "\n"; } stream << tagBeginData << "\n"; stream << static_cast(areaNames.size()) << "\n"; for (unsigned int i = 0; i < areaNames.size(); i++) { stream << static_cast(i) << " " << areaNames[i] << "\n"; } switch (getFileWriteType()) { case FILE_FORMAT_ASCII: for (int j = 0; j < numberOfNodes; j++) { stream << j; for (int k = 0; k < numberOfColumns; k++) { int namesIndex[4]; float prob[4]; getNodeData(j, k, namesIndex, prob); stream << " " << namesIndex[0] << " " << prob[0] << " " << namesIndex[1] << " " << prob[1] << " " << namesIndex[2] << " " << prob[2] << " " << namesIndex[3] << " " << prob[3] << " "; } stream << "\n"; } break; case FILE_FORMAT_BINARY: #ifdef QT4_FILE_POS_BUG setBinaryFilePosQT4Bug(); #else // QT4_FILE_POS_BUG // // still a bug in QT 4.2.2 // setBinaryFilePosQT4Bug(); #endif // QT4_FILE_POS_BUG for (int j = 0; j < numberOfNodes; j++) { for (int k = 0; k < numberOfColumns; k++) { int namesIndex[4]; float prob[4]; getNodeData(j, k, namesIndex, prob); binStream << namesIndex[0] << prob[0] << namesIndex[1] << prob[1] << namesIndex[2] << prob[2] << namesIndex[3] << prob[3]; } } break; case FILE_FORMAT_XML: throw FileException(filename, "Writing in XML format not supported."); break; case FILE_FORMAT_XML_BASE64: throw FileException(filename, "Writing XML Base64 not supported."); break; case FILE_FORMAT_XML_GZIP_BASE64: throw FileException(filename, "Writing XML GZip Base64 not supported."); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: throw FileException(filename, "Writing XML External Binary not supported."); break; case FILE_FORMAT_OTHER: throw FileException(filename, "Writing in Other format not supported."); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: throw FileException(filename, "Writing Comma Separated Value File Format not supported."); break; } } caret-5.6.4~dfsg.1.orig/caret_files/AreaColorFile.h0000664000175000017500000000230111572067322021655 0ustar michaelmichael #ifndef __AREA_COLOR_FILE_H__ #define __AREA_COLOR_FILE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "ColorFile.h" /// class for area colors file class AreaColorFile : public ColorFile { public: /// Constructor AreaColorFile(); /// Destructor ~AreaColorFile(); protected: }; #endif // __AREA_COLOR_FILE_H__ caret-5.6.4~dfsg.1.orig/caret_files/AreaColorFile.cxx0000664000175000017500000000214611572067322022237 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "AreaColorFile.h" #include "SpecFile.h" /** * Constructor */ AreaColorFile::AreaColorFile() : ColorFile("Area Color File", SpecFile::getAreaColorFileExtension()) { } /** * Destructor */ AreaColorFile::~AreaColorFile() { } caret-5.6.4~dfsg.1.orig/caret_files/AfniHeader.h0000664000175000017500000001763611572067322021215 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_AFNI_ATTRIBUTES_H__ #define __VE_AFNI_ATTRIBUTES_H__ #include #include #include "FileException.h" class ColorFile; class VolumeFile; class nifti_1_header; /// class for storing an AFNI attribute /// For more info: http://afni.nimh.nih.gov/afni/docREADME/README.attributes class AfniAttribute { public: enum ATTRIBUTE_TYPE { ATTRIBUTE_TYPE_FLOAT, ATTRIBUTE_TYPE_INTEGER, ATTRIBUTE_TYPE_STRING }; /// constructor for single double but stored as float. AfniAttribute(const QString& name, const double value); /// constructor for single float AfniAttribute(const QString& name, const float value); /// constructor for single int AfniAttribute(const QString& name, const int value); /// constructor for array of floats AfniAttribute(const QString& name, const float values[], const int numValues); /// constructor for array of ints AfniAttribute(const QString& name, const int values[], const int numValues); /// constructor for vector of floats AfniAttribute(const QString& name, const std::vector& values); /// constructor for vector of ints AfniAttribute(const QString& name, const std::vector& values); /// constructor AfniAttribute(const QString& name, const QString& value); /// get the name of the attribute QString getName() const { return attributeName; } /// get the type of the attribute ATTRIBUTE_TYPE getType() const { return attributeType; } /// get the values for an int attribute void getValue(std::vector& value) const { value = intValue; } /// get the values for a float void getValue(std::vector& value) const { value = floatValue; } /// get the value for a string QString getValue() const; /// type of the attribute ATTRIBUTE_TYPE attributeType; /// name of the attribute QString attributeName; /// storage for a string attribute QString stringValue; /// storage for float value(s) std::vector floatValue; /// storage for integer value(s) std::vector intValue; static const QString NAME_BRICK_FLOAT_FACS; static const QString NAME_BRICK_LABS; static const QString NAME_BRICK_STATS; static const QString NAME_BRICK_TYPES; static const QString NAME_BRICK_COMMENTS; static const QString NAME_BYTEORDER_STRING; static const QString NAME_CARET_METADATA_LINK; static const QString NAME_CARET_TYPE; static const QString NAME_CARET_PUBMED_ID; static const QString NAME_DATASET_NAME; static const QString NAME_DATASET_DIMENSIONS; static const QString NAME_DATASET_RANK; static const QString NAME_DELTA; static const QString NAME_HISTORY_NOTE; static const QString NAME_IDCODE_DATE; static const QString NAME_IDCODE_STRING; static const QString NAME_LABEL_1; static const QString NAME_LABEL_2; static const QString NAME_LABEL_TABLE; static const QString NAME_LUT_NAMES; static const QString NAME_ORIENT_SPECIFIC; static const QString NAME_ORIGIN; static const QString NAME_SCENE_DATA; static const QString NAME_TYPESTRING; static const QString NAME_VOLUME_FILENAMES; }; /// class for storing the AFNI attributes in an AFNI header class AfniHeader { public: /// Constructor AfniHeader(); /// Destructor ~AfniHeader(); /// add an attribute void addAttribute(AfniAttribute& attr); /// remove an attribute void removeAttribute(const QString& name); /// clear the afni header and reset to default values void clear(); /// get the number of attributes int getNumberOfAttributes() const { return attributes.size(); } /// Get an attribute by its index AfniAttribute* getAttribute(const int index); /// Get an attribute for the specified name (returns NULL if attribute not found) AfniAttribute* getAttribute(const QString& name); /// Read a header file void readHeader(const QString& headerFileName, QFile& file, QTextStream& stream) throw (FileException); /// Write to a header file void writeHeader(QTextStream& stream) throw (FileException); /// read the AFNI extension stored in a NIFTI volume file void readFromNiftiExtension(const QString& niftiExtension) throw (FileException); /// setup the AfniHeader from volume file(s) void setupFromVolumeFiles(const std::vector& volumes, const ColorFile* colorFile) throw (FileException); /// write the AFNI attributes to a NIFTI volume extension void writeToNiftiExtension(QString& niftiExtension, const nifti_1_header* hdr) throw (FileException); private: /// storage for the attributes std::vector attributes; }; #endif // __VE_AFNI_ATTRIBUTES_H__ #ifdef __AFNI_HEADER_DEFINE__ const QString AfniAttribute::NAME_BRICK_FLOAT_FACS = "BRICK_FLOAT_FACS"; const QString AfniAttribute::NAME_BRICK_LABS = "BRICK_LABS"; const QString AfniAttribute::NAME_BRICK_STATS = "BRICK_STATS"; const QString AfniAttribute::NAME_BRICK_TYPES = "BRICK_TYPES"; const QString AfniAttribute::NAME_BRICK_COMMENTS = "BRICK_COMMENTS"; const QString AfniAttribute::NAME_BYTEORDER_STRING = "BYTEORDER_STRING"; const QString AfniAttribute::NAME_CARET_METADATA_LINK = "CARET_METADATA_LINK"; const QString AfniAttribute::NAME_CARET_TYPE = "CARET_TYPE"; const QString AfniAttribute::NAME_CARET_PUBMED_ID = "CARET_PUBMED_ID"; const QString AfniAttribute::NAME_DATASET_NAME = "DATASET_NAME"; const QString AfniAttribute::NAME_DATASET_DIMENSIONS = "DATASET_DIMENSIONS"; const QString AfniAttribute::NAME_DATASET_RANK = "DATASET_RANK"; const QString AfniAttribute::NAME_DELTA = "DELTA"; const QString AfniAttribute::NAME_HISTORY_NOTE = "HISTORY_NOTE"; const QString AfniAttribute::NAME_IDCODE_DATE = "IDCODE_DATE"; const QString AfniAttribute::NAME_IDCODE_STRING = "IDCODE_STRING"; const QString AfniAttribute::NAME_LABEL_1 = "LABEL_1"; const QString AfniAttribute::NAME_LABEL_2 = "LABEL_2"; const QString AfniAttribute::NAME_LABEL_TABLE = "GIFTI_LABEL_TABLE"; const QString AfniAttribute::NAME_LUT_NAMES = "LUT_NAMES"; const QString AfniAttribute::NAME_ORIENT_SPECIFIC = "ORIENT_SPECIFIC"; const QString AfniAttribute::NAME_ORIGIN = "ORIGIN"; const QString AfniAttribute::NAME_SCENE_DATA = "SCENE_DATA"; const QString AfniAttribute::NAME_TYPESTRING = "TYPESTRING"; const QString AfniAttribute::NAME_VOLUME_FILENAMES = "VOLUME_FILENAMES"; #endif // __AFNI_HEADER_DEFINE__ caret-5.6.4~dfsg.1.orig/caret_files/AfniHeader.cxx0000664000175000017500000010357411572067322021565 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #define __AFNI_HEADER_DEFINE__ #include "AfniHeader.h" #undef __AFNI_HEADER_DEFINE__ #include "DateAndTime.h" #include "DebugControl.h" #include "FileUtilities.h" #include "StringUtilities.h" #include "VolumeFile.h" #include "nifti1.h" #include "GiftiLabelTable.h" /** * Constructor. */ AfniHeader::AfniHeader() { clear(); } /** * Destructor. */ AfniHeader::~AfniHeader() { } /** * Clear the afni header and set to default values */ void AfniHeader::clear() { // // Create the required default attributes assuming a single subvolume // attributes.clear(); const int ranks[8] = { 3, 1, 0, 0, 0, 0, 0, 0 }; AfniAttribute rank(AfniAttribute::NAME_DATASET_RANK, ranks, 8); addAttribute(rank); const int dims[3] = { 0, 0, 0 }; AfniAttribute dim(AfniAttribute::NAME_DATASET_DIMENSIONS, dims, 3); addAttribute(dim); AfniAttribute typeString(AfniAttribute::NAME_TYPESTRING, "3DIM_HEAD_ANAT"); addAttribute(typeString); const int sceneData[8] = { 0, 3, 0, -999, -999, -999, -999, -999 }; AfniAttribute scene(AfniAttribute::NAME_SCENE_DATA, sceneData, 8); addAttribute(scene); const int orientData[3] = { 1, 2, 4 }; // LPI AfniAttribute orient(AfniAttribute::NAME_ORIENT_SPECIFIC, orientData, 3); addAttribute(orient); const float origin[3] = { 0.0, 0.0, 0.0 }; AfniAttribute originData(AfniAttribute::NAME_ORIGIN, origin, 3); addAttribute(originData); const float delta[3] = { 1.0, 1.0, 1.0 }; AfniAttribute deltaData(AfniAttribute::NAME_DELTA, delta, 3); addAttribute(deltaData); // // Create the almost required default attributes // AfniAttribute icodeString(AfniAttribute::NAME_IDCODE_STRING, DateAndTime::getDateAndTimeForNaming()); //QDateTime::currentDateTime().toString("dd_MMMM_yyyy_hh_mm_ss_zzz")); addAttribute(icodeString); AfniAttribute icodeDate(AfniAttribute::NAME_IDCODE_DATE, DateAndTime::getDateAndTimeAsString()); // QDateTime::currentDateTime().toString("ddd MMM d hh:mm::ss yyyy")); addAttribute(icodeDate); const float stats[2] = { 0.0, 255.0 }; AfniAttribute brickStats(AfniAttribute::NAME_BRICK_STATS, stats, 2); addAttribute(brickStats); AfniAttribute brickTypes(AfniAttribute::NAME_BRICK_TYPES, 3); // 3 = float addAttribute(brickTypes); AfniAttribute facs(AfniAttribute::NAME_BRICK_FLOAT_FACS, 0.0); addAttribute(facs); //AfniAttribute brickLabs(AfniAttribute::NAME_BRICK_LABS, "#0"); //addAttribute(brickLabs); // // Not necessary but do them anyway // AfniAttribute history(AfniAttribute::NAME_HISTORY_NOTE, "Created by CARET"); addAttribute(history); // // Nearly useless attributes // AfniAttribute label1(AfniAttribute::NAME_LABEL_1, "orig"); addAttribute(label1); AfniAttribute label2(AfniAttribute::NAME_LABEL_2, "Bigfoot Lives"); addAttribute(label2); AfniAttribute datasetName(AfniAttribute::NAME_DATASET_NAME, "caret volume"); addAttribute(datasetName); } /** * add an attribute (replaces it if it exists) */ void AfniHeader::addAttribute(AfniAttribute& attr) { AfniAttribute* a = getAttribute(attr.attributeName); if (a != NULL) { *a = attr; } else { attributes.push_back(attr); } } /** * Remove an attribute */ void AfniHeader::removeAttribute(const QString& name) { for (std::vector::iterator iter = attributes.begin(); iter != attributes.end(); iter++) { if (iter->attributeName == name) { attributes.erase(iter); break; } } } /** * Get an attribute by its index */ AfniAttribute* AfniHeader::getAttribute(const int index) { if (index < getNumberOfAttributes()) { return &attributes[index]; } return NULL; } /** * get an attribute for the specified name (returns NULL if not found) */ AfniAttribute* AfniHeader::getAttribute(const QString& name) { const int numAttrs = getNumberOfAttributes(); for (int i = 0; i < numAttrs; i++) { if (attributes[i].attributeName == name) { return &attributes[i]; } } return NULL; } /** * Read an AFNI header. */ void AfniHeader::readHeader(const QString& headerFileName, QFile& /*file*/, QTextStream& stream) throw (FileException) { attributes.clear(); QString name; QString type; int count = 0; // // Read until end of file // while(stream.atEnd() == false) { const QString line(stream.readLine()); std::vector tokens; StringUtilities::token(line, " \t", tokens); if (tokens.size() == 3) { if (tokens[0] == "type") { name = ""; count = 0; type = tokens[2]; } else if (tokens[0] == "name") { name = tokens[2]; } else if (tokens[0] == "count") { count = tokens[2].toInt(); if ((count > 0) && (name.isEmpty() == false) && (type.isEmpty() == false)) { if (DebugControl::getDebugOn()) { std::cout << "Reading AFNI have " << name.toAscii().constData() << " with type " << type.toAscii().constData() << " and count " << count << std::endl; } if (type == "float-attribute") { float* data = new float[count]; int i = 0; while(i < count) { stream >> data[i]; i++; } if (DebugControl::getDebugOn()) { std::cout << "AFNI Float name: " << name.toAscii().constData() << " has values "; for (int j = 0; j < count; j++) { std::cout << data[j] << " "; } std::cout << std::endl; } AfniAttribute attr(name, data, count); addAttribute(attr); delete[] data; } else if (type == "integer-attribute") { int* data = new int[count]; int i = 0; while(i < count) { stream >> data[i]; i++; } if (DebugControl::getDebugOn()) { std::cout << "AFNI Int name: " << name.toAscii().constData() << " has values "; for (int j = 0; j < count; j++) { std::cout << data[j] << " "; } std::cout << std::endl; } AfniAttribute attr(name, data, count); addAttribute(attr); delete[] data; } else if (type == "string-attribute") { char* dataChars = new char[count+1]; while(stream.atEnd() == false) { QChar c; // use QChar since ">> char" skips whitespace stream >> c; if (c == '\'') { int i = 0; while (i < (count -1)) { stream >> c; dataChars[i] = c.toLatin1(); i++; } dataChars[count - 1] = '\0'; break; } } const QString data(dataChars); delete[] dataChars; AfniAttribute attr(name, data); addAttribute(attr); if (DebugControl::getDebugOn()) { std::cout << "AFNI String name: " << name.toAscii().constData() << " has value " << data.toAscii().constData() << std::endl; } } else { std::ostringstream str; str << "Unknown AFNI header type: " << type.toAscii().constData() << std::ends; throw FileException(FileUtilities::basename(headerFileName), str.str().c_str()); } } } } } } /** * Write an AFNI header. */ void AfniHeader::writeHeader(QTextStream& stream) throw (FileException) { // // Set the byte ordering // //int wordSize; //bool bigEndian; //qSysInfo(&wordSize, &bigEndian); if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { AfniAttribute byteOrder(AfniAttribute::NAME_BYTEORDER_STRING, "MSB_FIRST"); addAttribute(byteOrder); } else { AfniAttribute byteOrder(AfniAttribute::NAME_BYTEORDER_STRING, "LSB_FIRST"); addAttribute(byteOrder); } // // Set the date // AfniAttribute icodeDate(AfniAttribute::NAME_IDCODE_DATE, DateAndTime::getDateAndTimeAsString()); //QDateTime::currentDateTime().toString("ddd MMM d hh:mm::ss yyyy")); addAttribute(icodeDate); // // Write all of the attributes // const int numAttr = getNumberOfAttributes(); for (int i = 0; i < numAttr; i++) { stream << "\n"; const AfniAttribute& a = attributes[i]; // // write attribute type // switch (a.attributeType) { case AfniAttribute::ATTRIBUTE_TYPE_FLOAT: stream << "type = float-attribute\n"; break; case AfniAttribute::ATTRIBUTE_TYPE_INTEGER: stream << "type = integer-attribute\n"; break; case AfniAttribute::ATTRIBUTE_TYPE_STRING: stream << "type = string-attribute\n"; break; } // // write attribute name // stream << "name = " << a.attributeName << "\n"; // // Write the attribute data // const char* offset = " "; switch (a.attributeType) { case AfniAttribute::ATTRIBUTE_TYPE_FLOAT: { const int count = a.floatValue.size(); stream << "count = " << count << "\n"; stream << offset; for (int j = 0; j < count; j++) { stream << a.floatValue[j] << " "; if ((j > 0) && ((j % 5) == 0) && (j != (count - 1))) { stream << "\n"; stream << offset; } } } break; case AfniAttribute::ATTRIBUTE_TYPE_INTEGER: { const int count = a.intValue.size(); stream << "count = " << count << "\n"; stream << offset; for (int j = 0; j < count; j++) { stream << a.intValue[j] << " "; if ((j > 0) && ((j % 5) == 0) && (j != (count - 1))) { stream << "\n"; stream << offset; } } } break; case AfniAttribute::ATTRIBUTE_TYPE_STRING: stream << "count = " << (a.stringValue.length() + 1) << "\n"; stream << "'" << a.stringValue << "~"; break; } stream << "\n"; } stream << "\n"; } /** * read the AFNI extension stored in a NIFTI volume file. */ void AfniHeader::readFromNiftiExtension(const QString& niftiExtension) throw (FileException) { // // Place the AFNI extension into a DOM XML Parser // QDomDocument doc("nifti_afni_extension"); QString errorMessage; int errorLine, errorColumn; if (doc.setContent(niftiExtension, &errorMessage, &errorLine, &errorColumn) == false) { QString msg("Error parsing afni extension at line "); msg += QString::number(errorLine); msg += ", column "; msg += QString::number(errorColumn); throw FileException(msg); } // // Get the root element // QDomElement rootElement = doc.documentElement(); if (rootElement.isNull()) { throw FileException("AFNI extension root element is NULL"); } if (DebugControl::getDebugOn()) { std::cout << "AFNI extension root element: " << rootElement.tagName().toAscii().constData() << std::endl; } // // Loop through the children of the root element // QDomNode node = rootElement.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (DebugControl::getDebugOn()) { std::cout << "AFNI extension element: " << elem.tagName().toAscii().constData() << std::endl; } const QString niType = elem.attribute("ni_type"); const QString niDim = elem.attribute("ni_dimen"); const QString atrName = elem.attribute("atr_name"); QString text = elem.text(); if (DebugControl::getDebugOn()) { std::cout << " type: " << niType.toAscii().constData() << std::endl; std::cout << " dim: " << niDim.toAscii().constData() << std::endl; std::cout << " name: " << atrName.toAscii().constData() << std::endl; std::cout << " text: " << text.toAscii().constData() << std::endl; } // // Remove whitespace and skip over empty items // text = text.trimmed(); if (text.isEmpty() == false) { // // Create an attribute // if (niType == "String") { // // Remove any leading/trailing double quotes and "~" // int len = text.length(); if (text.right(1) == "\"") { text.remove(len - 1, 1); } if (text.right(1) == "~") { len = text.length(); text.remove(len - 1, 1); } if (text.left(1) == "\"") { text.remove(0, 1); } if (text.isEmpty() == false) { AfniAttribute attr(atrName, text); addAttribute(attr); } } else if (niType == "int") { std::vector intData; StringUtilities::token(text, " ", intData); if (intData.empty() == false) { AfniAttribute attr(atrName, intData); addAttribute(attr); } } else if (niType == "float") { std::vector floatData; StringUtilities::token(text, " ", floatData); if (floatData.empty() == false) { AfniAttribute attr(atrName, floatData); addAttribute(attr); } } else { std::cout << "WARNING: Unrecognized AFNI extension \"ni_type\": " << niType.toAscii().constData() << std::endl; } } // // Move to next node // node = node.nextSibling(); } // // Get the ID code // const QString idCode = rootElement.attribute("self_idcode"); if (idCode.isEmpty() == false) { AfniAttribute attr(AfniAttribute::NAME_IDCODE_STRING, idCode); addAttribute(attr); } } /** * setup the AfniHeader from volume file(s). */ void AfniHeader::setupFromVolumeFiles(const std::vector& volumesToWrite, const ColorFile* colorFile) throw (FileException) { if (volumesToWrite.empty()) { return; } VolumeFile* firstVolume = volumesToWrite[0]; // // Add comments and label // QString labelString, commentString; for (unsigned int i = 0; i < volumesToWrite.size(); i++) { const VolumeFile* vf = volumesToWrite[i]; labelString += vf->getDescriptiveLabel(); labelString += "~"; if (i <= 0) { commentString += vf->getFileComment(); } } AfniAttribute labs(AfniAttribute::NAME_BRICK_LABS, labelString); addAttribute(labs); AfniAttribute comms(AfniAttribute::NAME_HISTORY_NOTE, commentString); addAttribute(comms); // // Update dimensions // int dimensions[3]; firstVolume->getDimensions(dimensions); AfniAttribute dims(AfniAttribute::NAME_DATASET_DIMENSIONS, dimensions, 3); addAttribute(dims); // // update orientation // VolumeFile::ORIENTATION orientation[3]; firstVolume->getOrientation(orientation); int orient[3] = { 0, 0, 0 }; for (int i = 0; i < 3; i++) { switch(orientation[i]) { case VolumeFile::ORIENTATION_UNKNOWN: orient[i] = 1; break; case VolumeFile::ORIENTATION_RIGHT_TO_LEFT: orient[i] = 0; break; case VolumeFile::ORIENTATION_LEFT_TO_RIGHT: orient[i] = 1; break; case VolumeFile::ORIENTATION_POSTERIOR_TO_ANTERIOR: orient[i] = 2; break; case VolumeFile::ORIENTATION_ANTERIOR_TO_POSTERIOR: orient[i] = 3; break; case VolumeFile::ORIENTATION_INFERIOR_TO_SUPERIOR: orient[i] = 4; break; case VolumeFile::ORIENTATION_SUPERIOR_TO_INFERIOR: orient[i] = 5; break; } } AfniAttribute ori(AfniAttribute::NAME_ORIENT_SPECIFIC, orient, 3); addAttribute(ori); float spacing[3]; firstVolume->getSpacing(spacing); // // Update origin (always LPI) Note that AFNI has origin in center of voxel // float volumeOrigin[3]; firstVolume->getOrigin(volumeOrigin); /* float originTemp[3] = { std::fabs(origin[0] + spacing[0]*0.5), std::fabs(origin[1] + spacing[1]*0.5), -std::fabs(origin[2] + spacing[2]*0.5) }; AfniAttribute orig(AfniAttribute::NAME_ORIGIN, originTemp, 3); */ // // Caret always writes LPI and in AFNI left is positive-X, posterior // is positive Y, and inferior is negative Z // volumeOrigin[0] = std::fabs(volumeOrigin[0]); volumeOrigin[1] = std::fabs(volumeOrigin[1]); volumeOrigin[2] = -std::fabs(volumeOrigin[2]); AfniAttribute orig(AfniAttribute::NAME_ORIGIN, volumeOrigin, 3); addAttribute(orig); // // Update spacing (always LPI) // const float spacingTemp[3] = { -std::fabs(spacing[0]), -std::fabs(spacing[1]), std::fabs(spacing[2]) }; AfniAttribute space(AfniAttribute::NAME_DELTA, spacingTemp, 3); addAttribute(space); // // Caret volume type // QString fileTypeString("Unknown"); switch (firstVolume->getVolumeType()) { case VolumeFile::VOLUME_TYPE_ANATOMY: fileTypeString = "Anatomy"; break; case VolumeFile::VOLUME_TYPE_FUNCTIONAL: fileTypeString = "Functional"; break; case VolumeFile::VOLUME_TYPE_PAINT: fileTypeString = "Paint"; break; case VolumeFile::VOLUME_TYPE_PROB_ATLAS: fileTypeString = "Prob Atlas"; break; case VolumeFile::VOLUME_TYPE_RGB: fileTypeString = "RGB"; break; case VolumeFile::VOLUME_TYPE_ROI: fileTypeString = "ROI"; break; case VolumeFile::VOLUME_TYPE_SEGMENTATION: fileTypeString = "Segmentation"; break; case VolumeFile::VOLUME_TYPE_VECTOR: fileTypeString = "Vector"; break; case VolumeFile::VOLUME_TYPE_UNKNOWN: fileTypeString = "Unknown"; break; } AfniAttribute fta(AfniAttribute::NAME_CARET_TYPE, fileTypeString); addAttribute(fta); // // Set the voxel data type // std::vector dataTypeVector; switch(firstVolume->getVoxelDataType()) { case VolumeFile::VOXEL_DATA_TYPE_UNKNOWN: throw FileException(firstVolume->getFileName(), "Unknown data type"); break; case VolumeFile::VOXEL_DATA_TYPE_CHAR: dataTypeVector.push_back(-1); // invalid type for AFNI break; case VolumeFile::VOXEL_DATA_TYPE_CHAR_UNSIGNED: dataTypeVector.push_back(0); break; case VolumeFile::VOXEL_DATA_TYPE_SHORT: dataTypeVector.push_back(1); break; case VolumeFile::VOXEL_DATA_TYPE_SHORT_UNSIGNED: dataTypeVector.push_back(-1); // invalid type for AFNI break; case VolumeFile::VOXEL_DATA_TYPE_INT: dataTypeVector.push_back(2); break; case VolumeFile::VOXEL_DATA_TYPE_INT_UNSIGNED: dataTypeVector.push_back(-1); // invalid type for AFNI break; case VolumeFile::VOXEL_DATA_TYPE_LONG: dataTypeVector.push_back(-1); // invalid type for AFNI break; case VolumeFile::VOXEL_DATA_TYPE_LONG_UNSIGNED: dataTypeVector.push_back(-1); // invalid type for AFNI break; case VolumeFile::VOXEL_DATA_TYPE_FLOAT: dataTypeVector.push_back(3); break; case VolumeFile::VOXEL_DATA_TYPE_DOUBLE: dataTypeVector.push_back(4); break; case VolumeFile::VOXEL_DATA_TYPE_RGB_VOXEL_INTERLEAVED: dataTypeVector.push_back(6); break; case VolumeFile::VOXEL_DATA_TYPE_RGB_SLICE_INTERLEAVED: dataTypeVector.push_back(6); break; case VolumeFile::VOXEL_DATA_TYPE_VECTOR: dataTypeVector.push_back(3); break; } // // Voxel min max values and date types for each sub volume // int numSubVolumes = static_cast(volumesToWrite.size()); std::vector minMaxValues; for (int i = 0; i < numSubVolumes; i++) { float mn, mx; volumesToWrite[i]->getMinMaxVoxelValues(mn, mx); minMaxValues.push_back(mn); minMaxValues.push_back(mx); if (i >= 1) { dataTypeVector.push_back(dataTypeVector[0]); } } AfniAttribute brickType(AfniAttribute::NAME_BRICK_TYPES, dataTypeVector); addAttribute(brickType); AfniAttribute stats(AfniAttribute::NAME_BRICK_STATS, minMaxValues); addAttribute(stats); // // Dataset rank // const int rankData[2] = { 3, numSubVolumes }; AfniAttribute rank(AfniAttribute::NAME_DATASET_RANK, rankData, 2); addAttribute(rank); // // Is this a functional volume // if (firstVolume->getVolumeType() == VolumeFile::VOLUME_TYPE_FUNCTIONAL) { // // Change header to denote functional volume // AfniAttribute typeString(AfniAttribute::NAME_TYPESTRING, "3DIM_HEAD_FUNC"); addAttribute(typeString); const int sceneData[8] = { 0, 1, 1, -999, -999, -999, -999, -999 }; AfniAttribute scene(AfniAttribute::NAME_SCENE_DATA, sceneData, 8); addAttribute(scene); } else { // // Change header to denote anatomical volume // AfniAttribute typeString(AfniAttribute::NAME_TYPESTRING, "3DIM_HEAD_ANAT"); addAttribute(typeString); const int sceneData[8] = { 0, 3, 0, -999, -999, -999, -999, -999 }; AfniAttribute scene(AfniAttribute::NAME_SCENE_DATA, sceneData, 8); addAttribute(scene); } // // Is this a paint or prob atlas volume // if ((firstVolume->getVolumeType() == VolumeFile::VOLUME_TYPE_PAINT) || (firstVolume->getVolumeType() == VolumeFile::VOLUME_TYPE_PROB_ATLAS)) { std::vector regNames; for (int i = 0; i < firstVolume->getNumberOfRegionNames(); i++) { // // Cannot have '~' character in the name // QString name(firstVolume->getRegionNameFromIndex(i)); name = name.replace(QChar('~'), QChar('_')); regNames.push_back(name); } const QString names = StringUtilities::combine(regNames, "~"); AfniAttribute typeString(AfniAttribute::NAME_LUT_NAMES, names); addAttribute(typeString); // // Label table used by Caret6 // GiftiLabelTable labelTable; int numNames = static_cast(regNames.size()); for (int i = 0; i < numNames; i++) { QString name = regNames[i]; labelTable.addLabel(name); } if (colorFile != NULL) { labelTable.assignColors(*colorFile); } QString labelString; QTextStream labelStream(&labelString, QIODevice::WriteOnly); labelTable.writeAsXML(labelStream, 0); labelString = labelString.remove(QRegExp("\\n")); // remove newlines AfniAttribute labelAttr(AfniAttribute::NAME_LABEL_TABLE, labelString); addAttribute(labelAttr); } // // Add study meta data link // QString metaDataString; for (unsigned int i = 0; i < volumesToWrite.size(); i++) { const VolumeFile* vf = volumesToWrite[i]; if (i > 0) { metaDataString += "~"; } metaDataString += vf->getStudyMetaDataLinkSet().getLinkSetAsCodedText(); } AfniAttribute md(AfniAttribute::NAME_CARET_METADATA_LINK, metaDataString); addAttribute(md); // // Add PubMed ID // AfniAttribute pmid(AfniAttribute::NAME_CARET_PUBMED_ID, volumesToWrite[0]->getFilePubMedID()); addAttribute(pmid); } /** * write the AFNI attributes to a NIFTI volume extension. */ void AfniHeader::writeToNiftiExtension(QString& niftiExtension, const nifti_1_header* nifti1) throw (FileException) { // // Set the date // AfniAttribute icodeDate(AfniAttribute::NAME_IDCODE_DATE, DateAndTime::getDateAndTimeAsString()); //QDateTime::currentDateTime().toString("ddd MMM d hh:mm::ss yyyy")); addAttribute(icodeDate); AfniAttribute caretMessage("AAA_CARET_MESSAGE", "This AFNI extension is used only by Caret versions " "5.613 and earlier. Caret versions 5.614 and later " "use the Caret extension in a NIFTI Volume File."); addAttribute(caretMessage); // // Clear the extension // niftiExtension = ""; // // Create the root element // QDomDocument xmlDoc("nifti_afni_extension"); QDomElement rootElement = xmlDoc.createElement("AFNI_attributes"); const AfniAttribute* attr = getAttribute("NAME_IDCODE_STRING"); if (attr != NULL) { rootElement.setAttribute("self_idcode", attr->getValue()); } else { rootElement.setAttribute("self_idcode", DateAndTime::getDateAndTimeForNaming()); //QDateTime::currentDateTime().toString("dd_MMMM_yyyy_hh_mm_ss_zzz")); } rootElement.setAttribute("ni_form", "ni_group"); QString niftiNums; QTextStream(&niftiNums, QIODevice::WriteOnly) << nifti1->dim[1] // x-dim << "," << nifti1->dim[2] // y-dim << "," << nifti1->dim[3] // z-dim << "," << nifti1->dim[4] // num-time-series << "," << nifti1->dim[5] // num-components-per-voxel << "," << nifti1->datatype; rootElement.setAttribute("NIfTI_nums", niftiNums); xmlDoc.appendChild(rootElement); // // Add XML information // QDomNode xmlNode = xmlDoc.createProcessingInstruction("xml", "version=\"1.0\""); xmlDoc.insertBefore(xmlNode, xmlDoc.firstChild()); // // Loop through the attributes // const int num = getNumberOfAttributes(); for (int i = 0; i < num; i++) { const AfniAttribute* attr = getAttribute(i); const QString name = attr->getName(); const AfniAttribute::ATTRIBUTE_TYPE type = attr->getType(); // // Should this attribute be excluded (conflicts with NIFTI data) // http://nifti.nimh.nih.gov/nifti-1/AFNIextension1 // if ((name == AfniAttribute::NAME_BRICK_FLOAT_FACS) || (name == AfniAttribute::NAME_BRICK_TYPES) || (name == AfniAttribute::NAME_BYTEORDER_STRING) || (name == AfniAttribute::NAME_CARET_TYPE) || (name == AfniAttribute::NAME_DATASET_NAME) || (name == AfniAttribute::NAME_DATASET_DIMENSIONS) || (name == AfniAttribute::NAME_DATASET_RANK) || (name == AfniAttribute::NAME_DELTA) || (name == AfniAttribute::NAME_IDCODE_STRING) || (name == AfniAttribute::NAME_LABEL_1) || (name == AfniAttribute::NAME_LABEL_2) || (name == AfniAttribute::NAME_ORIENT_SPECIFIC) || (name == AfniAttribute::NAME_ORIGIN) || (name == AfniAttribute::NAME_SCENE_DATA) || (name == "STAT_AUX") || (name == "TAXIS_NUMS") || (name == "TAXIS_FLOATS") || (name == "TAXIS_OFFSETS") || (name == AfniAttribute::NAME_TYPESTRING)) { continue; } // // Get the attribute and element // QString niType; QString niDim; QString text; switch (type) { case AfniAttribute::ATTRIBUTE_TYPE_FLOAT: { std::vector values; attr->getValue(values); const int num = static_cast(values.size()); if (num > 0) { niType = "float"; niDim = QString::number(num); text = StringUtilities::combine(values, " "); } } break; case AfniAttribute::ATTRIBUTE_TYPE_INTEGER: { std::vector values; attr->getValue(values); const int num = static_cast(values.size()); if (num > 0) { niType = "int"; niDim = QString::number(num); text = StringUtilities::combine(values, " "); } } break; case AfniAttribute::ATTRIBUTE_TYPE_STRING: { const QString value = attr->getValue(); if (value.isEmpty() == false) { niType = "String"; niDim = "1"; text = "\""; text += value; text += "\""; } } break; } // // Convert to DomNode // if (text.isEmpty() == false) { // // create the element // QDomElement elem = xmlDoc.createElement("AFNI_atr"); elem.setAttribute("ni_type", niType); elem.setAttribute("ni_dimen", niDim); elem.setAttribute("atr_name", name); elem.appendChild(xmlDoc.createTextNode(text)); // // Add the element // rootElement.appendChild(elem); } } // // Were elements created ? // if (rootElement.hasChildNodes()) { // // convert the XML to a string // niftiExtension = xmlDoc.toString(3).trimmed(); } } //================================================================================ // // AfniAttribute methods // /** * constructor for single double but stored as float. The compiler treats a * floating point number (e.g. 4.5) as a double so this contructor is required. */ AfniAttribute::AfniAttribute(const QString& name, const double value) { attributeName = name; attributeType = ATTRIBUTE_TYPE_FLOAT; floatValue.push_back(static_cast(value)); } /** * constructor for single float */ AfniAttribute::AfniAttribute(const QString& name, const float value) { attributeName = name; attributeType = ATTRIBUTE_TYPE_FLOAT; floatValue.push_back(value); } /** * constructor for single int */ AfniAttribute::AfniAttribute(const QString& name, const int value) { attributeName = name; attributeType = ATTRIBUTE_TYPE_INTEGER; intValue.push_back(value); } /** * constructor for float array */ AfniAttribute::AfniAttribute(const QString& name, const float values[], const int numValues) { attributeName = name; attributeType = ATTRIBUTE_TYPE_FLOAT; for (int i = 0; i < numValues; i++) { floatValue.push_back(values[i]); } } /** * constructor for int array */ AfniAttribute::AfniAttribute(const QString& name, const int values[], const int numValues) { attributeName = name; attributeType = ATTRIBUTE_TYPE_INTEGER; for (int i = 0; i < numValues; i++) { intValue.push_back(values[i]); } } /** * constructor for vector of floats */ AfniAttribute::AfniAttribute(const QString& name, const std::vector& values) { attributeName = name; attributeType = ATTRIBUTE_TYPE_FLOAT; floatValue = values; } /** * constructor for vector of ints */ AfniAttribute::AfniAttribute(const QString& name, const std::vector& values) { attributeName = name; attributeType = ATTRIBUTE_TYPE_INTEGER; intValue = values; } /** * constructor for string */ AfniAttribute::AfniAttribute(const QString& name, const QString& value) { attributeName = name; attributeType = ATTRIBUTE_TYPE_STRING; stringValue = value; } /** * get the value for a string. */ QString AfniAttribute::getValue() const { return StringUtilities::trimWhitespace(stringValue); } caret-5.6.4~dfsg.1.orig/caret_files/AbstractFile.h0000664000175000017500000010573711572067322021572 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_ABSTRACT_FILE_H__ #define __VE_ABSTRACT_FILE_H__ #include #include #include #include #include #include #include #include "FileException.h" #include "StudyMetaDataLinkSet.h" #include "Structure.h" #include "XmlGenericWriter.h" class ColorFile; class CommaSeparatedValueFile; class QDomDocument; class QDomElement; class StringTable; class TransformationMatrix; // // In QT4, both file.atEnd() and file.pos() return invalid results // Needed if QT version is less than 4.2.2 // //#define QT4_FILE_POS_BUG 1 /// AbstractFile - a base class for all data files. /** * Provides methods that must be implemented by all derived data files and convenience * methods for the deriving data files to use. * * Deriving classes must override these methods * clear() - must call clearAbstractFile from clear() * isEmpty() - to find out if there is data in the file * readFileData - handles reading data after the header * writeFileData - handles writing data after the header */ class AbstractFile { public: /// file format types (not all files support all types) enum FILE_FORMAT { /// ascii file format FILE_FORMAT_ASCII, /// binary file format FILE_FORMAT_BINARY, /// XML file format FILE_FORMAT_XML, /// XML Base64 file format FILE_FORMAT_XML_BASE64, /// XML GZip Base64 file format FILE_FORMAT_XML_GZIP_BASE64, /// XML External Binary format FILE_FORMAT_XML_EXTERNAL_BINARY, /// Other file format FILE_FORMAT_OTHER, /// comma separated value file format FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE }; /// file I/O support enum FILE_IO { FILE_IO_NONE, FILE_IO_READ_ONLY, FILE_IO_WRITE_ONLY, FILE_IO_READ_AND_WRITE }; /// binary operationss enum BINARY_OPERATION { BINARY_OPERATION_ADD, BINARY_OPERATION_SUBTRACT, BINARY_OPERATION_MULTIPLY, BINARY_OPERATION_DIVIDE, BINARY_OPERATION_AVERAGE }; /// unary operations enum UNARY_OPERATION { UNARY_OPERATION_ADD, UNARY_OPERATION_ABS_VALUE, UNARY_OPERATION_CEILING, UNARY_OPERATION_FLOOR, UNARY_OPERATION_MULTIPLY, UNARY_OPERATION_FIX_NOT_A_NUMBER, UNARY_OPERATION_SQUARE_ROOT, UNARY_OPERATION_SUBTRACT_FROM_ONE, UNARY_OPERATION_LOG2 }; /// file comment mode enum FILE_COMMENT_MODE { FILE_COMMENT_MODE_APPEND, FILE_COMMENT_MODE_LEAVE_AS_IS, FILE_COMMENT_MODE_REPLACE }; /// Destructor (Needs to be public) virtual ~AbstractFile(); /// container for storing the file's header typedef std::map AbstractFileHeaderContainer; /// Clears current file data in memory. Deriving classes must override this method and /// call AbstractFile::clearAbstractFile() from its clear method. virtual void clear() = 0; /// returns true if the file is isEmpty (contains no data) virtual bool empty() const = 0; /// returns non-zero if the file has been modified without being saved unsigned long getModified() const; /// set file has been modified void setModified(); /// set modified counter void setModifiedCounter(const unsigned long value); /// clear file has been modified without being saved void clearModified(); /// get the name of the file (description only used if file name is isEmpty) virtual QString getFileName(const QString& description = "") const; /// get the name of the file without any path (description only used if file name is isEmpty) virtual QString getFileNameNoPath(const QString& description = "") const; /// set the name of the file void setFileName(const QString name) { filename = name; } /// get the default file name (also overrides current file name) virtual QString makeDefaultFileName(const QString& description = "") const; /// replace the caret standard file name's description void replaceFileNameDescription(const QString& newDescription); /// get the path of the file QString getFileNamePath() const; /// get the file's comment QString getFileComment() const; /// set the file's comment void setFileComment(const QString& fc); /// get the file's PubMed ID QString getFilePubMedID() const; /// set the file's PubMed ID void setFilePubMedID(const QString& pmid); /// append to the file's comment void appendToFileComment(const QString& fc); /// append software version to file comment void appendSoftwareVersionToFileComment(const QString& msg); /// get the file's title QString getFileTitle() const { return fileTitle; } /// set the file's title void setFileTitle(const QString& ft); /// get the header (note: comment is stored in header). AbstractFile::AbstractFileHeaderContainer getHeader() const { return header; } /// replace the header (note: comment is stored in header) void setHeader(const AbstractFile::AbstractFileHeaderContainer& hdr) { header = hdr; } /// get a header tag value QString getHeaderTag(const QString& name) const; /// set a header tag value void setHeaderTag(const QString& name, const QString& value); /// remove header tag void removeHeaderTag(const QString& name); /// Append a header tag. void appendToHeaderTag(const QString& nameIn, const QString& value, const QString& separator); /// see if the file has a header bool getFileHasHeader() const { return fileHasHeader; } /// set file has header void setFileHasHeader(const bool hh) { fileHasHeader = hh; } // get the study metadata link for this file StudyMetaDataLinkSet getStudyMetaDataLinkSet() const; // set the study metadata link for this file void setStudyMetaDataLinkSet(const StudyMetaDataLinkSet smdls); /// Read a file tag's line (form: tag value) static void readTagLine(const QString& filenameIn, QTextStream& stream , QString& tag, QString& tagValue) throw (FileException); /// read a line and parse into whitespace separated tokens /// filenameIn is used if an exception is thrown static void readLineIntoTokens(const QString& filenameIn, QTextStream& stream, QString& lineOut, std::vector& tokens) throw (FileException); /// Read a line into a string list QStringList readLineIntoStringList(QTextStream& stream) throw (FileException); /// Read a line from a file static void readLine(const QString& filenameIn, QTextStream& stream, QString& lineOut) throw (FileException); /// read the specified file but just the metadata, NO DATA void readFileMetaDataOnly(const QString& filenameIn) throw (FileException); /// read the specified file (override for files without headers, ie: binary) virtual void readFile(const QString& filenameIn) throw (FileException); /// read the contents of a file stored in memory virtual void readFileFromArray(const char* data, const unsigned int dataLength, const QString& debugFileName) throw (FileException); /// Write the current file's memory to the specified name // (override for files without headers, ie: binary) virtual void writeFile(const QString& filenameIn) throw (FileException); /// Write the current file's memory to a byte array virtual void writeFileToArray(QByteArray& ba) throw (FileException); /// Update the file's metadata for Caret6 virtual void updateMetaDataForCaret6(); /// write the file's memory in caret6 format to the specified name virtual QString writeFileInCaret6Format(const QString& filenameIn, Structure structure,const ColorFile* colorFileIn, const bool useCaret6ExtensionFlag) throw (FileException); /// Read any subclass of AbstractFile static AbstractFile* readAnySubClassDataFile(const QString& filenameIn, const bool readMetaDataOnly, QString& errorMessageOut); /// Get a file type name based upon its extension. If the file's type is not /// recognized, the file name's extension is returned. static QString getFileTypeNameFromFileName(const QString& filename); /// Create a subclass of abstract file based upon the file name's extension. /// Returns NULL if not recognized. static AbstractFile* getSubClassDataFile(const QString& filename, QString& errorMessageOut); /// Get all filetype names and extensions. static void getAllFileTypeNamesAndExtensions(std::vector& typeNames, std::vector& extensions); /// tag for comment static QString getHeaderTagComment() { return headerTagComment; } /// tag for PubMed ID static QString getHeaderTagPubMedID() { return headerTagPubMedID; } /// see if the format can be read bool getCanRead(const FILE_FORMAT ff) const; /// see if the format can be writte bool getCanWrite(const FILE_FORMAT ff) const; /// get the data type of file for writing FILE_FORMAT getFileWriteType() const { return fileWriteType; } /// get the data type of file that was read FILE_FORMAT getFileReadType() const { return fileReadType; } /// convert a format type to its name static QString convertFormatTypeToName(const FILE_FORMAT formatIn); /// convert a file format name to its type static FILE_FORMAT convertFormatNameToType(const QString& name, bool* validNameOut = NULL); /// get file format types and names static void getFileFormatTypesAndNames(std::vector& typesOut, std::vector& namesOut); /// set read/write type for a format void setFileReadWriteType(const FILE_FORMAT format, const FILE_IO readAndOrWrite); /// set the data type of file for writing void setFileWriteType(const FILE_FORMAT wt) { fileWriteType = wt; } /// set the data type of file for reading void setFileReadType(const FILE_FORMAT wt) { fileReadType = wt; } /// get the descriptive name QString getDescriptiveName() const { return descriptiveName; } /// get the display list number (negative if invalid) unsigned int getDisplayListNumber() const { return displayListNumber; } /// set the display list number void setDisplayListNumber(const unsigned int dln) { displayListNumber = dln; } /// clear the display list void clearDisplayList(); /// get the number of digits right of the decimal when writing float to text files static int getTextFileDigitsRightOfDecimal() { return textFileDigitsRightOfDecimal; } /// set the number of digits right of the decimal when writing float to text files static void setTextFileDigitsRightOfDecimal(const int num); /// get the read meta data only flag bool getReadMetaDataOnlyFlag() const { return readMetaDataOnlyFlag; } /// get the default file name extension QString getDefaultFileNameExtension() const { return defaultExtension; } /// set the default file name extension void setDefaultFileNameExtension(const QString& s) { defaultExtension = s; } /// get the preferred write type static std::vector getPreferredWriteType() { return preferredWriteType; } /// set the preferred write type static void setPreferredWriteType(const std::vector t) { preferredWriteType = t; } /// set the preferred write type for caret commmand static void setPreferredWriteTypeCaretCommand(const std::vector t) { preferredWriteTypeCaretCommand = t; } /// set the preferred METRIC write type for caret commmand static void setPreferredMetricWriteTypeCaretCommand(const FILE_FORMAT t) { preferredMetricWriteTypeCaretCommand = t; } /// get the preferred METRIC write type for caret commmand static FILE_FORMAT getPreferredMetricWriteTypeCaretCommand() { return preferredMetricWriteTypeCaretCommand; } /// set the default file name prefix and number of nodes static void setDefaultFileNamePrefix(const QString& s, const int numNodes); /// get the default file name prefix static void getDefaultFileNamePrefix(QString& prefix, int& numNodes); /// get the root element name QString getRootXmlElementTagName() const { return rootXmlElementTagName; } /// set the root element name void setRootXmlElementTagName(const QString& s) { rootXmlElementTagName = s; } /// get the transformation matrix associated with this file const TransformationMatrix* getAssociatedTransformationMatrix() const { return transMatrix; } /// set the transformation matrix associated with this file void setAssociatedTransformationMatrix(TransformationMatrix* tm) { transMatrix = tm; } /// Get an XML element's first child and return it as a string. static QString getXmlElementFirstChildAsString(const QDomElement& elem); /// Get an XML element's first child and return it as a float. static float getXmlElementFirstChildAsFloat(const QDomElement& elem); /// Get an XML element's first child and return it as a double. static double getXmlElementFirstChildAsDouble(const QDomElement& elem); /// Get an XML element's first child and return it as an int. static int getXmlElementFirstChildAsInt(const QDomElement& elem); /// Get an XML element's first child and return it as a float. static void getXmlElementFirstChildAsFloat(const QDomElement& elem, float* values, const int numValues); /// Get an XML element's first child and return it as an int. static void getXmlElementFirstChildAsInt(const QDomElement& elem, int* values, const int numValues); /// add a text CDATA element to an XML Dom Element static void addXmlCdataElement(QDomDocument& xmlDoc, QDomElement& parentElement, const QString& childElementName, const QString& childElementData); /// add a Text element to an XML Dom Element static void addXmlTextElement(QDomDocument& xmlDoc, QDomElement& parentElement, const QString& childElementName, const QString& childElementData); /// add a float element to an XML Dom Element static void addXmlTextElement(QDomDocument& xmlDoc, QDomElement& parentElement, const QString& childElementName, const float childElementData); /// add a float element to an XML Dom Element static void addXmlTextElement(QDomDocument& xmlDoc, QDomElement& parentElement, const QString& childElementName, const double childElementData); /// add a Text element to an XML Dom Element static void addXmlTextElement(QDomDocument& xmlDoc, QDomElement& parentElement, const QString& childElementName, const float* childElementData, const int numChildElements); /// add a int element to an XML Dom Element static void addXmlTextElement(QDomDocument& xmlDoc, QDomElement& parentElement, const QString& childElementName, const int childElementData); /// add a Text element to an XML Dom Element static void addXmlTextElement(QDomDocument& xmlDoc, QDomElement& parentElement, const QString& childElementName, const int* childElementData, const int numChildElements); /// find out if comma separated file conversion supported virtual void getCommaSeparatedFileSupport(bool& readFromCSV, bool& writeToCSV) const; /// write the file's data into a comma separated values file (throws exception if not supported) virtual void writeDataIntoCommaSeparatedValueFile(CommaSeparatedValueFile& csv) throw (FileException); /// read the file's data from a comma separated values file (throws exception if not supported) virtual void readDataFromCommaSeparatedValuesTable(const CommaSeparatedValueFile& csv) throw (FileException); /// compare a file for unit testing (returns true if "within tolerance") virtual bool compareFileForUnitTesting(const AbstractFile* af, const float tolerance, QString& messageOut) const; // allow events to process (call when doing "busy" operations static void allowEventsToProcess(); /// get the time (in seconds) that it took to read the file float getTimeToReadFileInSeconds() const { return timeToReadFileInSeconds; } // generate a unique timestamp that is all numeric static QString generateUniqueNumericTimeStampAsString(); // generate a date and time timestamp static QString generateDateAndTimeStamp(); /// set permission assigned to files as they are written static void setFileWritePermissions(const QFile::Permissions& pin) { fileWritePermissions = pin; } /// get permission assigned to files as they are written static QFile::Permissions getFileWritePermissions() { return fileWritePermissions; } /// set overwriting of existing files allowed static void setOverwriteExistingFilesAllowed(bool allowIt) { allowExistingFileOverwriteFlag = allowIt; } /// get overwriting of existing files allowed static bool getOverwriteExistingFilesAllowed() { return allowExistingFileOverwriteFlag; } protected: /// Constructor AbstractFile(const QString& descriptiveName, const QString& defaultExtensionIn, const bool fileHasHeaderIn = true, const FILE_FORMAT defaultWriteTypeIn = FILE_FORMAT_ASCII, const FILE_IO supportsAsciiFormat = FILE_IO_READ_AND_WRITE, const FILE_IO supportsBinaryFormat = FILE_IO_NONE, const FILE_IO supportsXMLFormat = FILE_IO_NONE, const FILE_IO supportsXMLBase64Format = FILE_IO_NONE, const FILE_IO supportsXMLGZipBase64Format = FILE_IO_NONE, const FILE_IO supportsOtherFormat = FILE_IO_NONE, const FILE_IO supportsCsvfFormat = FILE_IO_NONE); /// Copy Constructor AbstractFile(const AbstractFile& af); /// equality operator AbstractFile& operator=(const AbstractFile& af); // append the files comment void appendFileComment(const AbstractFile& af, const FILE_COMMENT_MODE fcm = FILE_COMMENT_MODE_APPEND); /// copy an abstract file to this one (used by copy constructor and operator=) void copyHelperAbstractFile(const AbstractFile& af); /// set XML version read with SAX parser void setXmlVersionReadWithSaxParser(const bool b) { xmlVersionReadWithSaxParserFlag = b; } /// get XML version read with SAX parser bool getXmlVersionReadWithSaxParser() const { return xmlVersionReadWithSaxParserFlag; } /// set the read meta data only flag void setReadMetaDataOnlyFlag(const bool flag) { readMetaDataOnlyFlag = flag; } /// set enable/disable appending to file comment void setEnableAppendFileComment(const bool en) { enableAppendFileComment = en; } /// get enable/disable appending to file comment bool getEnableAppendFileComment() const { return enableAppendFileComment; } /// clear the abstract file's members void clearAbstractFile(); /// get the position of the QTextStream and try to fix it if the QT bug is detected qint64 getQTextStreamPosition(QTextStream& textStream) throw (FileException); /// read header data from an XML file void readHeaderXML(QDomElement& rootElement); /// write header data to an XML file void writeHeaderXML(QDomDocument& doc, QDomElement& rootElement); /// write header to XML writer void writeHeaderXMLWriter(XmlGenericWriter& xmlWriter) throw (FileException); /// Read the contents of the file (header has already been read) virtual void readFileData(QFile& file, QTextStream& stream, QDataStream& binStream, QDomElement& rootElement) throw (FileException) = 0; /// Write the file's data (header has already been written) virtual void writeFileData(QTextStream& stream, QDataStream& binStream, QDomDocument& xmlDoc, QDomElement& rootElement) throw (FileException) = 0; // read a 3 byte integer from binary file int readThreeByteInteger(QDataStream& binStream) throw (FileException); /// Read a file tag's line (form: tag value) void readTagLine(QTextStream& stream, QString& tag, QString& tagValue) throw (FileException); /// Read a file tag's line (form: tag value) void readTagLine(QTextStream& stream, QString& line, QString& tag, QString& tagValue) throw (FileException); /// Read a numbered file tag's line (form: tag value) void readNumberedTagLine(QTextStream& stream, int& number, QString& tag, QString& tagValue) throw (FileException); /// Read a line from a file void readLine(QTextStream& stream, QString& lineOut) throw (FileException); /// read a line and chop off the comments. void readLineChopComment(QTextStream& stream, QString& lineOut) throw (FileException); /// read a line and parse into whitespace separated tokens void readLineIntoTokens(QTextStream& stream, QString& lineOut, std::vector& tokens) throw (FileException); /// split a tag that begins with column number into number and value int splitTagIntoColumnAndValue(const QString s, QString& value) const; /// read the data file's header. void readHeader(QFile& file, QTextStream& stream) throw(FileException); /// write the data file's header void writeHeader(QTextStream& stream) throw (FileException); /// write the header's data into a StringTable void writeHeaderDataIntoStringTable(StringTable& table) const; /// read the header's data from a StringTable void readHeaderDataFromStringTable(const StringTable& table) throw (FileException); /// find the binary data offset for QT4 bug work around qint64 findBinaryDataOffsetQT4Bug(QFile& file, const char* stringToFind) throw (FileException); /// set file postion for binary files for QT4 bug work around void setBinaryFilePosQT4Bug() throw (FileException); /// allows files to do processing after a file is read virtual void postFileReadingProcessing() throw (FileException); /// Name that was passed to read method mutable QString filename; /// the header AbstractFileHeaderContainer header; /// the file's title QString fileTitle; /// name for root xml element QString rootXmlElementTagName; /// QFile used for writing files QFile* writingQFile; private: /// determine if the file is an XML file bool isFileXML(QFile& file); /// determine if the file is a comma separated value file bool isCommaSeparatedValueFile(QFile& file); /// method used while reading files void readFileContents(QFile& file) throw (FileException); /// method used for writing files void writeFileContents(QTextStream& stream, QDataStream& dataStream) throw (FileException); /// contents modified (incremented each modification) unsigned long modified; /// display list number (do not clear) unsigned int displayListNumber; /// supports ascii format files (do not clear) FILE_IO fileSupportAscii; /// supports binary format files (do not clear) FILE_IO fileSupportBinary; /// supports xml format files (do not clear) FILE_IO fileSupportXML; /// supports xml base64 encodedformat files (do not clear) FILE_IO fileSupportXMLBase64; /// supports xml gzipped base64 format files (do not clear) FILE_IO fileSupportXMLGZipBase64; /// supports xml external binary format files (do not clear) FILE_IO fileSupportXMLExternalBinary; /// supports comma separated value format (do not clear) FILE_IO fileSupportCommaSeparatedValueFile; /// supports other format file (do not clear) FILE_IO fileSupportOther; /// data type of file for writing (do not clear) FILE_FORMAT fileWriteType; /// data type of file that was read (do not clear) FILE_FORMAT fileReadType; /// the descriptive name (do not clear) QString descriptiveName; /// the default extension (do not clear) QString defaultExtension; /// the default name (do not clear) QString defaultFileName; /// file has a header (do not clear) bool fileHasHeader; /// enable/disable append to file comment bool enableAppendFileComment; /// if set before reading, only the meta data is read, no data bool readMetaDataOnlyFlag; /// unique number for the file int uniqueFileNumber; /// matrix associated with this file TransformationMatrix* transMatrix; /// xml version of file is read with sax parser bool xmlVersionReadWithSaxParserFlag; /// append version id when files written static bool appendVersionIdWhenFilesWritten; /// write to this data type whenever possible static std::vector preferredWriteType; /// write to this data type whenever possible when running caret command static std::vector preferredWriteTypeCaretCommand; /// write metric files to this data type when running caret command static FILE_FORMAT preferredMetricWriteTypeCaretCommand; /// the number of digits right of the decimal when writing float to text files static int textFileDigitsRightOfDecimal; /// default file name prefix static QString defaultFileNamePrefix; /// default file name number of nodes static int defaultFileNameNumberOfNodes; /// the unique file naming counter static int uniqueFileNameCounter; /// permission assigned to files as they are written static QFile::Permissions fileWritePermissions; /// allow the overwriting of existing files static bool allowExistingFileOverwriteFlag; protected: /// time to read the file in seconds float timeToReadFileInSeconds; public: static const QString xmlHeaderTagName; static const QString xmlHeaderElementTagName; static const QString xmlHeaderElementName; static const QString xmlHeaderElementValue; protected: static const QString tagFileTitle; static const QString tagFileVersion; static const QString tagBeginData; static const QString xmlHeaderOldTagName; static const QString headerTagPubMedID; static const QString headerTagComment; // keep this private // use get/setHeaderComment public: static QString getHeaderTagEncodingValueAscii() { return "ASCII"; } static QString getHeaderTagEncodingValueBinary() { return "BINARY"; } static QString getHeaderTagEncodingValueXML() { return "XML"; } static QString getHeaderTagEncodingValueXMLBase64() { return "XML_BASE64"; } static QString getHeaderTagEncodingValueXMLGZipBase64() { return "XML_BASE64_GZIP"; } static QString getHeaderTagEncodingValueXMLExternalBinary() { return "XML_EXTERNAL_BINARY"; } static QString getHeaderTagEncodingValueOther() { return "OTHER"; } static QString getHeaderTagEncodingValueCommaSeparatedValueFile() { return "COMMA_SEPARATED_VALUE_FILE"; } static const QString headerTagConfigurationID; static const QString headerTagCoordFrameID; static const QString headerTagDate; static const QString headerTagEncoding; static const QString headerTagOrientation; static const QString headerTagPerimeterID; static const QString headerTagResolution; static const QString headerTagSampling; static const QString headerTagScale; static const QString headerTagStudyMetaDataLinkSet; static const QString headerTagVersionID; static const QString headerTagSpace; static const QString headerTagStructure; static const QString headerTagSpecies; static const QString headerTagCategory; static const QString headerTagSubject; }; #endif // __VE_ABSTRACT_FILE_H__ #ifdef _ABSTRACT_MAIN_ const QString AbstractFile::xmlHeaderTagName = "FileHeader"; const QString AbstractFile::xmlHeaderElementTagName = "Element"; const QString AbstractFile::xmlHeaderElementName = "Name"; const QString AbstractFile::xmlHeaderElementValue = "Value"; const QString AbstractFile::xmlHeaderOldTagName = "header"; const QString AbstractFile::tagFileTitle = "tag-title"; const QString AbstractFile::tagFileVersion = "tag-version"; const QString AbstractFile::tagBeginData = "tag-BEGIN-DATA"; const QString AbstractFile::headerTagPubMedID = "pubmed_id"; const QString AbstractFile::headerTagComment = "comment"; const QString AbstractFile::headerTagConfigurationID = "configuration_id"; const QString AbstractFile::headerTagCoordFrameID = "coordframe_id"; const QString AbstractFile::headerTagDate = "Date"; const QString AbstractFile::headerTagEncoding = "encoding"; const QString AbstractFile::headerTagOrientation = "orientation"; const QString AbstractFile::headerTagPerimeterID = "perimeter_id"; const QString AbstractFile::headerTagResolution = "resolution"; const QString AbstractFile::headerTagSampling = "sampling"; const QString AbstractFile::headerTagScale = "scale"; const QString AbstractFile::headerTagStudyMetaDataLinkSet = "study_metadata_link_set"; const QString AbstractFile::headerTagVersionID = "version_id"; const QString AbstractFile::headerTagSpace = "space"; const QString AbstractFile::headerTagStructure = "structure"; const QString AbstractFile::headerTagSpecies = "species"; const QString AbstractFile::headerTagCategory = "category"; const QString AbstractFile::headerTagSubject = "subject"; int AbstractFile::textFileDigitsRightOfDecimal = 6; std::vector AbstractFile::preferredWriteType; std::vector AbstractFile::preferredWriteTypeCaretCommand; AbstractFile::FILE_FORMAT AbstractFile::preferredMetricWriteTypeCaretCommand = AbstractFile::FILE_FORMAT_OTHER; bool AbstractFile::appendVersionIdWhenFilesWritten = false; QString AbstractFile::defaultFileNamePrefix = ""; int AbstractFile::defaultFileNameNumberOfNodes = 0; int AbstractFile::uniqueFileNameCounter = 0; QFile::Permissions AbstractFile::fileWritePermissions(0); bool AbstractFile::allowExistingFileOverwriteFlag = true; #endif // _ABSTRACT_MAIN_ caret-5.6.4~dfsg.1.orig/caret_files/AbstractFile.cxx0000664000175000017500000032641011572067322022136 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #ifdef Q_OS_WIN32 #define NOMINMAX #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define _ABSTRACT_MAIN_ #include "AbstractFile.h" #undef _ABSTRACT_MAIN_ #include "DateAndTime.h" #include "DebugControl.h" #include "FileUtilities.h" #include "StringUtilities.h" #include "GiftiDataArrayFile.h" #ifdef CARET_FLAG #include "AreaColorFile.h" #include "ArealEstimationFile.h" #include "AtlasSpaceFile.h" #include "AtlasSurfaceDirectoryFile.h" #include "BorderColorFile.h" #include "BorderFile.h" #include "BorderProjectionFile.h" #include "BrainVoyagerFile.h" #include "CaretVersion.h" #include "CellColorFile.h" #include "CellFile.h" #include "CellProjectionFile.h" #include "CommaSeparatedValueFile.h" #include "CocomacConnectivityFile.h" #include "ContourCellColorFile.h" #include "ContourCellFile.h" #include "ContourFile.h" #include "CoordinateFile.h" #include "CutsFile.h" #include "DeformationFieldFile.h" #include "DeformationMapFile.h" #include "FileUtilities.h" #include "FociColorFile.h" #include "FociFile.h" #include "FociProjectionFile.h" #include "FociSearchFile.h" #include "FreeSurferCurvatureFile.h" #include "FreeSurferFunctionalFile.h" #include "FreeSurferLabelFile.h" #include "FreeSurferSurfaceFile.h" #include "GiftiNodeDataFile.h" #include "GeodesicDistanceFile.h" #include "ImageFile.h" #include "LatLonFile.h" #include "MetricFile.h" #include "NodeRegionOfInterestFile.h" #include "PaintFile.h" #include "PaletteFile.h" #include "ParamsFile.h" #include "PreferencesFile.h" #include "ProbabilisticAtlasFile.h" #include "StringTable.h" #include "RgbPaintFile.h" #include "SceneFile.h" #include "SectionFile.h" #include "SpecFile.h" #include "StringUtilities.h" #include "StudyCollectionFile.h" #include "StudyMetaDataFile.h" #include "SurfaceFile.h" #include "SurfaceShapeFile.h" #include "TextFile.h" #include "TopographyFile.h" #include "TopologyFile.h" #include "TransformationMatrixFile.h" #include "SureFitVectorFile.h" #include "VectorFile.h" #include "VocabularyFile.h" #include "VolumeFile.h" #include "VtkModelFile.h" #include "WustlRegionFile.h" #endif // CARET_FLAG const int commentLengthWarning = 20000; /** * The constructor */ AbstractFile::AbstractFile(const QString& descriptiveNameIn, const QString& defaultExtensionIn, const bool fileHasHeaderIn, const FILE_FORMAT defaultWriteTypeIn, const FILE_IO supportsAsciiFormat, const FILE_IO supportsBinaryFormat, const FILE_IO supportsXMLFormat, const FILE_IO supportsXMLBase64Format, const FILE_IO supportsXMLGZipBase64Format, const FILE_IO supportsOtherFormat, const FILE_IO supportsCsvfFormat) { if (preferredWriteType.empty()) { std::vector fileFormats; std::vector fileFormatNames; AbstractFile::getFileFormatTypesAndNames(fileFormats, fileFormatNames); preferredWriteType.resize(fileFormats.size()); std::fill(preferredWriteType.begin(), preferredWriteType.end(), AbstractFile::FILE_FORMAT_XML_GZIP_BASE64); } writingQFile = NULL; // // Update copy constructor too // uniqueFileNumber = uniqueFileNameCounter; uniqueFileNameCounter++; descriptiveName = descriptiveNameIn; rootXmlElementTagName = StringUtilities::replace(descriptiveName, ' ', '_'); defaultExtension = defaultExtensionIn; fileHasHeader = fileHasHeaderIn; fileReadType = defaultWriteTypeIn; fileWriteType = defaultWriteTypeIn; fileSupportAscii = supportsAsciiFormat; fileSupportBinary = supportsBinaryFormat; fileSupportXML = supportsXMLFormat; fileSupportXMLBase64 = supportsXMLBase64Format; fileSupportXMLGZipBase64 = supportsXMLGZipBase64Format; fileSupportXMLExternalBinary = FILE_IO_NONE; fileSupportOther = supportsOtherFormat; fileSupportCommaSeparatedValueFile = supportsCsvfFormat; displayListNumber = 0; defaultFileName = StringUtilities::makeLowerCase(descriptiveName); defaultFileName = StringUtilities::replace(defaultFileName, ' ', '_'); enableAppendFileComment = true; setXmlVersionReadWithSaxParser(false); readMetaDataOnlyFlag = false; // // Set write type and possibly override with the preferred write type // // NOTE: This code is also in the GiftiDataArrayFile constructor // since it may change the supported write types //fileWriteType = fileReadType; for (unsigned int i = 0; i < preferredWriteType.size(); i++) { if (getCanWrite(preferredWriteType[i])) { fileWriteType = preferredWriteType[i]; break; } } } /** * The copy constructor */ AbstractFile::AbstractFile(const AbstractFile& af) { copyHelperAbstractFile(af); } /** * equality operator. */ AbstractFile& AbstractFile::operator=(const AbstractFile& af) { if (this != &af) { copyHelperAbstractFile(af); } return *this; } /** * copy an abstract file to this one (used by copy constructor and operator=). */ void AbstractFile::copyHelperAbstractFile(const AbstractFile& af) { clearModified(); uniqueFileNumber = uniqueFileNameCounter; uniqueFileNameCounter++; displayListNumber = 0; fileTitle = af.fileTitle; header = af.header; filename = af.filename; // This must be done for proper spec file reading descriptiveName = af.descriptiveName; fileHasHeader = af.fileHasHeader; defaultFileName = af.defaultFileName; defaultExtension = af.defaultExtension; fileReadType = af.fileReadType; setFileWriteType(af.fileWriteType); fileSupportAscii = af.fileSupportAscii; fileSupportBinary = af.fileSupportBinary; fileSupportXML = af.fileSupportXML; fileSupportXMLBase64 = af.fileSupportXMLBase64; fileSupportXMLGZipBase64 = af.fileSupportXMLGZipBase64; fileSupportXMLExternalBinary = af.fileSupportXMLExternalBinary; fileSupportOther = af.fileSupportOther; fileSupportCommaSeparatedValueFile = af.fileSupportCommaSeparatedValueFile; enableAppendFileComment = af.enableAppendFileComment; readMetaDataOnlyFlag = af.readMetaDataOnlyFlag; rootXmlElementTagName = af.rootXmlElementTagName; xmlVersionReadWithSaxParserFlag = af.xmlVersionReadWithSaxParserFlag; } /** * The Destructor */ AbstractFile::~AbstractFile() { clearAbstractFile(); } /** * append the files comment. */ void AbstractFile::appendFileComment(const AbstractFile& af, const FILE_COMMENT_MODE fcm) { switch (fcm) { case FILE_COMMENT_MODE_APPEND: { const QString otherFileComment(af.getFileComment()); if (otherFileComment.isEmpty() == false) { QString comment = getFileComment(); if (af.getFileName().isEmpty() == false) { comment.append("\nAppended File: "); comment.append(af.getFileName()); } else { comment.append("\nAppended Unnamed File"); } comment.append("\n"); comment.append(otherFileComment); setFileComment(comment); } } break; case FILE_COMMENT_MODE_LEAVE_AS_IS: break; case FILE_COMMENT_MODE_REPLACE: setFileComment(af.getFileComment()); break; } } /** * Clear the abstract file's members. * This must be called from the deriving file's clear() method. */ void AbstractFile::clearAbstractFile() { clearModified(); timeToReadFileInSeconds = 0.0; fileTitle = ""; filename = ""; header.clear(); transMatrix = NULL; /* if (defaultFileName.isEmpty() == false) { std::ostringstream str; str << defaultFileName << "_" << uniqueFileNumber; filename = str.str().c_str()); } */ clearDisplayList(); // // Do not clear these items // // fileSupportAscii; // fileSupportBinary; // fileSupportXML; // fileSupportXMLBase64 // fileSupportXMLGZipBase64 // fileSupportXMLExternalBinary // fileSupportOther // fileSupportCommaSeparatedValueFile // fileWriteType // descriptiveName // defaultFileName // defaultExtension // fileHasHeader // updateVersionIdEnabledFlag // rootXmlElementTagName } /** * set read/write type for a format. */ void AbstractFile::setFileReadWriteType(const FILE_FORMAT format, const FILE_IO readAndOrWrite) { switch (format) { case FILE_FORMAT_ASCII: fileSupportAscii = readAndOrWrite; break; case FILE_FORMAT_BINARY: fileSupportBinary = readAndOrWrite; break; case FILE_FORMAT_XML: fileSupportXML = readAndOrWrite; break; case FILE_FORMAT_XML_BASE64: fileSupportXMLBase64 = readAndOrWrite; break; case FILE_FORMAT_XML_GZIP_BASE64: fileSupportXMLGZipBase64 = readAndOrWrite; break; case FILE_FORMAT_XML_EXTERNAL_BINARY: fileSupportXMLExternalBinary = readAndOrWrite; break; case FILE_FORMAT_OTHER: fileSupportOther = readAndOrWrite; break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: fileSupportCommaSeparatedValueFile = readAndOrWrite; break; } } /** * get the name of the file without any path (description only used if file name is isEmpty). */ QString AbstractFile::getFileNameNoPath(const QString& description) const { QString name(FileUtilities::basename(getFileName(description))); return name; } /** * get the name of the file. */ QString AbstractFile::getFileName(const QString& description) const { const bool useDateInFileName = false; if (filename.isEmpty()) { if (defaultFileNamePrefix.isEmpty() == false) { filename.append(defaultFileNamePrefix); filename.append("."); } if (defaultFileName.isEmpty() == false) { std::ostringstream str; if (description.isEmpty()) { str << defaultFileName.toAscii().constData() << "_" << uniqueFileNumber; } else { str << description.toAscii().constData(); } if (useDateInFileName) { str << "." << DateAndTime::getDateForNaming().toAscii().constData(); //<< QDateTime::currentDateTime().toString("yyyy-MM-dd").toAscii().constData(); } if (defaultFileNameNumberOfNodes > 0) { bool showNumNodes = false; #ifdef CARET_FLAG showNumNodes = ((dynamic_cast(this) != NULL) || (dynamic_cast(this) != NULL) || (dynamic_cast(this) != NULL) || (dynamic_cast(this) != NULL)); #endif // CARET_FLAG if (showNumNodes) { str << "." << defaultFileNameNumberOfNodes; } } if (defaultExtension.isEmpty() == false) { str << defaultExtension.toAscii().constData(); } filename.append(str.str().c_str()); } if (filename.isEmpty()) { std::ostringstream str; str << "caret_file_" << uniqueFileNumber; filename.append(str.str().c_str()); if (defaultExtension.isEmpty() == false) { filename.append(defaultExtension); } } } return filename; } /** * get the default file name (also overrides current file name). */ QString AbstractFile::makeDefaultFileName(const QString& description) const { filename = ""; return getFileName(description); } /** * replace the caret standard file name's description. */ void AbstractFile::replaceFileNameDescription(const QString& newDescription) { QString name = getFileName(); name = FileUtilities::changeCaretDataFileDescription(name, newDescription); setFileName(name); } /** * Return the path of the file */ QString AbstractFile::getFileNamePath() const { QString path(FileUtilities::dirname(getFileName())); if (path.isEmpty()) { path = "."; } return path; } /** * get the study metadata link for this file. */ StudyMetaDataLinkSet AbstractFile::getStudyMetaDataLinkSet() const { StudyMetaDataLinkSet smdls; const QString textLink = getHeaderTag(headerTagStudyMetaDataLinkSet); if (textLink.isEmpty() == false) { smdls.setLinkSetFromCodedText(textLink); } return smdls; } /** * set the study metadata link for this file. */ void AbstractFile::setStudyMetaDataLinkSet(const StudyMetaDataLinkSet smdls) { setHeaderTag(headerTagStudyMetaDataLinkSet, smdls.getLinkSetAsCodedText()); } /** * Get a tag from the header. */ QString AbstractFile::getHeaderTag(const QString& name) const { const QString nameLower(name.toLower()); for (AbstractFileHeaderContainer::const_iterator iter = header.begin(); iter != header.end(); iter++) { if (nameLower == iter->first.toLower()) { return iter->second; break; } } /* const std::map::const_iterator iter = header.find(name); if (iter != header.end()) { return iter->second; } */ return ""; } /** * Set a tag in the header. */ void AbstractFile::setHeaderTag(const QString& name, const QString& value) { QString nameLower(name.toLower()); // // "hem_flag" has been replaced by "structure" // if (nameLower == "hem_flag") { nameLower = AbstractFile::headerTagStructure; } // // ignore "version_id" // if (nameLower == headerTagVersionID) { return; } // // Since case may vary, remove matching item // for (AbstractFileHeaderContainer::iterator iter = header.begin(); iter != header.end(); iter++) { const QString tagName(iter->first); const QString tagNameLower(tagName.toLower()); if (nameLower == tagNameLower) { header.erase(iter); break; } } // // Add to header // header[name] = value; setModified(); } /** * remove header tag. */ void AbstractFile::removeHeaderTag(const QString& name) { header.erase(name); } /** * Append a header tag. */ void AbstractFile::appendToHeaderTag(const QString& nameIn, const QString& value, const QString& separator) { QString tagValue(getHeaderTag(nameIn)); if (tagValue.isEmpty() == false) { tagValue.append(separator); } tagValue.append(value); setHeaderTag(nameIn, tagValue); } /** * append software version to file comment. The version is added after "msg" and * followed by a carriage return. */ void AbstractFile::appendSoftwareVersionToFileComment(const QString& msg) { QString s(msg); if (msg.isEmpty() == false) { s.append(" "); } #ifdef CARET_FLAG s.append("CARET v"); s.append(CaretVersion::getCaretVersionAsString()); s.append("\n"); #endif // CARET_FLAG appendToFileComment(s); } /** * Get the file's comment. */ QString AbstractFile::getFileComment() const { QString s(getHeaderTag(headerTagComment)); //if (s.isEmpty() == false) { // return StringUtilities::setupCommentForDisplay(s); //} return s; } /** * Set the file's comment. */ void AbstractFile::setFileComment(const QString& fc) { //setHeaderTag(headerTagComment, StringUtilities::setupCommentForStorage(fc)); setHeaderTag(headerTagComment, fc); } /** * get the file's PubMed ID. */ QString AbstractFile::getFilePubMedID() const { QString s(getHeaderTag(headerTagPubMedID)); return s; } /** * set the file's PubMed ID. */ void AbstractFile::setFilePubMedID(const QString& pmid) { setHeaderTag(headerTagPubMedID, pmid); } /** * Append to the file's comment. */ void AbstractFile::appendToFileComment(const QString& fc) { if (enableAppendFileComment) { if (fc.isEmpty() == false) { QString s(getFileComment()); s.append(fc); setFileComment(s); } } } /** * see if the format can be read. */ bool AbstractFile::getCanRead(const FILE_FORMAT ff) const { FILE_IO fio = FILE_IO_NONE; switch (ff) { case FILE_FORMAT_ASCII: fio = fileSupportAscii; break; case FILE_FORMAT_BINARY: fio = fileSupportBinary; break; case FILE_FORMAT_XML: fio = fileSupportXML; break; case FILE_FORMAT_XML_BASE64: fio = fileSupportXMLBase64; break; case FILE_FORMAT_XML_GZIP_BASE64: fio = fileSupportXMLGZipBase64; break; case FILE_FORMAT_XML_EXTERNAL_BINARY: fio = fileSupportXMLExternalBinary; break; case FILE_FORMAT_OTHER: fio = fileSupportOther; break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: fio = fileSupportCommaSeparatedValueFile; break; } const bool b = ((fio == FILE_IO_READ_ONLY) || (fio == FILE_IO_READ_AND_WRITE)); return b; } /** * see if the format can be written. */ bool AbstractFile::getCanWrite(const FILE_FORMAT ff) const { FILE_IO fio = FILE_IO_NONE; switch (ff) { case FILE_FORMAT_ASCII: fio = fileSupportAscii; break; case FILE_FORMAT_BINARY: fio = fileSupportBinary; break; case FILE_FORMAT_XML: fio = fileSupportXML; break; case FILE_FORMAT_XML_BASE64: fio = fileSupportXMLBase64; break; case FILE_FORMAT_XML_GZIP_BASE64: fio = fileSupportXMLGZipBase64; break; case FILE_FORMAT_XML_EXTERNAL_BINARY: fio = fileSupportXMLExternalBinary; break; case FILE_FORMAT_OTHER: fio = fileSupportOther; break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: fio = fileSupportCommaSeparatedValueFile; break; } const bool b = ((fio == FILE_IO_WRITE_ONLY) || (fio == FILE_IO_READ_AND_WRITE)); return b; } /** * convert a format type to its name. */ QString AbstractFile::convertFormatTypeToName(const FILE_FORMAT formatIn) { QString s; switch (formatIn) { case FILE_FORMAT_ASCII: s = getHeaderTagEncodingValueAscii(); break; case FILE_FORMAT_BINARY: s = getHeaderTagEncodingValueBinary(); break; case FILE_FORMAT_XML: s = getHeaderTagEncodingValueXML(); break; case FILE_FORMAT_XML_BASE64: s = getHeaderTagEncodingValueXMLBase64(); break; case FILE_FORMAT_XML_GZIP_BASE64: s = getHeaderTagEncodingValueXMLGZipBase64(); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: s = getHeaderTagEncodingValueXMLExternalBinary(); break; case FILE_FORMAT_OTHER: s = getHeaderTagEncodingValueOther(); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: s = getHeaderTagEncodingValueCommaSeparatedValueFile(); break; } return s; } /** * convert a file format name to its type. */ AbstractFile::FILE_FORMAT AbstractFile::convertFormatNameToType(const QString& name, bool* validNameOut) { if (validNameOut != NULL) { *validNameOut = true; } FILE_FORMAT format = FILE_FORMAT_ASCII; if (name == getHeaderTagEncodingValueAscii()) { format = FILE_FORMAT_ASCII; } else if (name == getHeaderTagEncodingValueBinary()) { format = FILE_FORMAT_BINARY; } else if (name == getHeaderTagEncodingValueXML()) { format = FILE_FORMAT_XML; } else if (name == getHeaderTagEncodingValueXMLBase64()) { format = FILE_FORMAT_XML_BASE64; } else if (name == getHeaderTagEncodingValueXMLGZipBase64()) { format = FILE_FORMAT_XML_GZIP_BASE64; } else if (name == getHeaderTagEncodingValueXMLExternalBinary()) { format = FILE_FORMAT_XML_EXTERNAL_BINARY; } else if (name == getHeaderTagEncodingValueOther()) { format = FILE_FORMAT_OTHER; } else if (name == getHeaderTagEncodingValueCommaSeparatedValueFile()) { format = FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE; } else { if (validNameOut != NULL) { *validNameOut = false; } } return format; } /** * get file format types and names. */ void AbstractFile::getFileFormatTypesAndNames(std::vector& typesOut, std::vector& namesOut) { typesOut.clear(); namesOut.clear(); typesOut.push_back(FILE_FORMAT_ASCII); namesOut.push_back(convertFormatTypeToName(FILE_FORMAT_ASCII)); typesOut.push_back(FILE_FORMAT_BINARY); namesOut.push_back(convertFormatTypeToName(FILE_FORMAT_BINARY)); typesOut.push_back(FILE_FORMAT_XML); namesOut.push_back(convertFormatTypeToName(FILE_FORMAT_XML)); typesOut.push_back(FILE_FORMAT_XML_BASE64); namesOut.push_back(convertFormatTypeToName(FILE_FORMAT_XML_BASE64)); typesOut.push_back(FILE_FORMAT_XML_GZIP_BASE64); namesOut.push_back(convertFormatTypeToName(FILE_FORMAT_XML_GZIP_BASE64)); typesOut.push_back(FILE_FORMAT_XML_EXTERNAL_BINARY); namesOut.push_back(convertFormatTypeToName(FILE_FORMAT_XML_EXTERNAL_BINARY)); typesOut.push_back(FILE_FORMAT_OTHER); namesOut.push_back(convertFormatTypeToName(FILE_FORMAT_OTHER)); typesOut.push_back(FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE); namesOut.push_back(convertFormatTypeToName(FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE)); } /** * Set the file's title. */ void AbstractFile::setFileTitle(const QString& ft) { fileTitle = ft; setModified(); } /** * clear the display list. */ void AbstractFile::clearDisplayList() { if (displayListNumber > 0) { if (glIsList(displayListNumber) == GL_TRUE) { glDeleteLists(displayListNumber, 1); } displayListNumber = 0; } } /** * Find out if the file is modified. */ unsigned long AbstractFile::getModified() const { return modified; } /** * set file has been modified. */ void AbstractFile::setModified() { modified++; clearDisplayList(); } /** * set modified counter. */ void AbstractFile::setModifiedCounter(const unsigned long value) { modified = value; } /** * clear file has been modified without being saved. */ void AbstractFile::clearModified() { modified = 0; } /** * determine if the file is a comma separated value file. */ bool AbstractFile::isCommaSeparatedValueFile(QFile& file) { bool isCSVF = false; // // There is a bug in some versions of QT in that QFile::peek() returns // 1 fewer characters than it should, so read extra // const QString id(CommaSeparatedValueFile::getFirstLineCommaSeparatedValueFileIdentifier()); const qint64 len = id.length() + 5; if (len > 0) { const QString charsRead = file.peek(len); if (charsRead.indexOf(id) >= 0) { isCSVF = true; } } return isCSVF; } /** * determine if the file is an XML file. */ bool AbstractFile::isFileXML(QFile& file) { bool isXML = false; // // Save current position in the file // const qint64 filePos = file.pos(); // // Create a buffer for the data read // const qint64 NUM = 512; unsigned char buffer[NUM]; // // Set number of bytes to read // const int numToRead = std::min(file.size(), NUM); // // Read the bytes // const qint64 numRead = file.read((char*)(buffer), numToRead); // // loop through characters // for (qint64 i = 0; i < numRead; i++) { const unsigned char c = buffer[i]; if (c >= 127) { // not ascii isXML = false; break; } else if ((c >= 32) && (c <= 126)) { // visibile characters if (c == '<') { isXML = true; break; } else if ((c == 32) || // blank character (space) (c == 9) || // tab (c == 10) || // line feed (c == 13)) { // carriage return // ignore whitespace } else { isXML = false; break; } } /* else if ((c != 9) && // tab (c != 10) && // line feed (c != 13)) { // carriage return isXML = false; break; } */ } // // Restor position in file // file.seek(filePos); return isXML; } /** * read the contents of a file stored in memory. */ void AbstractFile::readFileFromArray(const char* data, const unsigned int dataLength, const QString& debugFileName) throw (FileException) { // // Put data into a file object, then reset position to zero // QString tempFileName("caret_temp.file"); bool keepTempFile = false; if (DebugControl::getDebugOn() && (debugFileName.isEmpty() == false)) { tempFileName = debugFileName; keepTempFile = true; } QFile::remove(tempFileName); QFile file(tempFileName); if (file.open(QFile::ReadWrite) == false) { throw FileException("", "Unable to create temporary read/write file in AbstractFile::readFile"); } QDataStream stream(&file); stream.setVersion(QDataStream::Qt_4_3); stream.writeRawData(data, dataLength); //char newline[2] = { '\n', '\0' }; //stream.writeRawBytes(newline, 1); file.seek(0); readFileContents(file); file.close(); if (keepTempFile == false) { QFile::remove(tempFileName); } } /** * method used while reading files. */ void AbstractFile::readFileContents(QFile& file) throw (FileException) { // // create the text and binary streams // QTextStream stream(&file); QDataStream binStream(&file); binStream.setVersion(QDataStream::Qt_4_3); // // Determine if GIFTI node data file // const bool giftiDataArrayFileFlag = (dynamic_cast(this) != NULL); // // See if this is an XML file // bool csvFileFlag = false; bool xmlFileFlag = false; if (getCanRead(FILE_FORMAT_OTHER) == false) { xmlFileFlag = isFileXML(file); stream.seek(0); file.seek(0); if (xmlFileFlag) { if (DebugControl::getDebugOn()) { std::cout << filename.toAscii().constData() << " is an XML file." << std::endl; } if ((getCanRead(FILE_FORMAT_XML) == false) && (getCanRead(FILE_FORMAT_XML_BASE64) == false) && (getCanRead(FILE_FORMAT_XML_GZIP_BASE64) == false) && (getCanRead(FILE_FORMAT_XML_EXTERNAL_BINARY) == false)) { throw FileException(filename, "is an XML file but XML is not supported for this type of file.\n" "Perhaps you need a new version of Caret."); } } else { if (DebugControl::getDebugOn()) { std::cout << filename.toAscii().constData() << " is NOT an XML file." << std::endl; } } if (isCommaSeparatedValueFile(file)) { csvFileFlag = true; } } // // Special processing for TextFile // if (dynamic_cast(this) != NULL) { csvFileFlag = false; xmlFileFlag = false; } QDomDocument doc(rootXmlElementTagName); QDomElement rootElement; // // Gifti Node data files do not use DOM parser // if ((xmlFileFlag) && (giftiDataArrayFileFlag == false) && (getXmlVersionReadWithSaxParser() == false)) { // // Parse the file if it is an XML file // QString errorMessage; int errorLine = 0, errorColumn = 0; if (doc.setContent(&file, &errorMessage, &errorLine, &errorColumn) == false) { std::ostringstream str; str << "Error parsing XML at line " << errorLine << " column " << errorColumn << ". "; str << errorMessage.toAscii().constData() << std::ends; throw FileException(filename, str.str().c_str()); } rootElement = doc.documentElement(); // // Verify that the root element tag name is correct // if (rootElement.tagName() != rootXmlElementTagName) { // // Special case // const QString abName("Abstract"); if (rootXmlElementTagName != "html") { if (rootXmlElementTagName.left(abName.length()) != abName) { std::ostringstream str; str << "File's XML Root Element Tag Name should be " << rootXmlElementTagName.toAscii().constData() << "\n" << "but it is " << rootElement.tagName().toAscii().constData() << ".\n"; throw FileException(filename, str.str().c_str()); } } } } if (giftiDataArrayFileFlag && xmlFileFlag) { fileReadType = FILE_FORMAT_XML; } else if (getXmlVersionReadWithSaxParser() && xmlFileFlag) { fileReadType = FILE_FORMAT_XML; } else if (fileHasHeader) { if (xmlFileFlag) { readHeaderXML(rootElement); setHeaderTag(headerTagEncoding, getHeaderTagEncodingValueXML()); } else if (csvFileFlag) { setHeaderTag(headerTagEncoding, getHeaderTagEncodingValueCommaSeparatedValueFile()); } else { //std::cout << "File position/size/end/stream end (before header): " // << file.pos() << ", " << file.size() << ", " // << file.atEnd() << ", " << stream.atEnd() << std::endl; readHeader(file, stream); //std::cout << "File position/size/end/stream end (after header): " // << file.pos() << ", " << file.size() << ", " // << file.atEnd() << ", " << stream.atEnd() << std::endl; } // // Check type of file // const QString encoding = StringUtilities::makeUpperCase(getHeaderTag(headerTagEncoding)); if (encoding == getHeaderTagEncodingValueAscii()) { if (getCanRead(FILE_FORMAT_ASCII) == false) { throw FileException(getFileName(), "Ascii format file not supported for this type of file.\n" "Perhaps you need a newer version of Caret."); } fileReadType = FILE_FORMAT_ASCII; } else if (encoding == getHeaderTagEncodingValueBinary()) { if (getCanRead(FILE_FORMAT_BINARY) == false) { throw FileException(getFileName(), "Binary format file not supported for this type of file.\n" "Perhaps you need a newer version of Caret."); } fileReadType = FILE_FORMAT_BINARY; #ifdef QT4_FILE_POS_BUG qint64 offset = findBinaryDataOffsetQT4Bug(file, "EndHeader"); if (offset > 0) { offset++; file.seek(offset); } #endif // QT4_FILE_POS_BUG /* throw FileException(getFileName(), "Due to a bug in QT4, Caret is unable to read binary files at this time.\n" "Use \"caret_file_convert\" on the command line to convert files to text\n" "format (caret_file_convert -text *)."); */ } else if (encoding == getHeaderTagEncodingValueXML()) { if (getCanRead(FILE_FORMAT_XML) == false) { throw FileException(getFileName(), "XML format file not supported for this type of file.\n" "Perhaps you need a newer version of Caret."); } fileReadType = FILE_FORMAT_XML; } else if (encoding == getHeaderTagEncodingValueCommaSeparatedValueFile()) { if (getCanRead(FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE) == false) { throw FileException(getFileName(), "Comma Separated Value format file not supported for this type of file.\n" "Perhaps you need a newer version of Caret."); } fileReadType = FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE; } else if (encoding == getHeaderTagEncodingValueOther()) { if (getCanRead(FILE_FORMAT_OTHER) == false) { throw FileException(getFileName(), "Other format file not supported for this type of file.\n" "Perhaps you need a newer version of Caret."); } fileReadType = FILE_FORMAT_OTHER; } else { // // Assume ascii // fileReadType = FILE_FORMAT_ASCII; } } // // Set write type and possibly override with the preferred write type // if (getCanWrite(fileReadType)) { setFileWriteType(fileReadType); } for (unsigned int i = 0; i < preferredWriteType.size(); i++) { if (getCanWrite(preferredWriteType[i])) { fileWriteType = preferredWriteType[i]; break; } } //QTextStream stream(&file); //QDataStream binStream(&file); //std::cout << "File position/size: " << file.pos() << ", " << file.size() << std::endl; //std::cout << "Stream atEnd(): " << stream.atEnd() << std::endl; //if (readMetaDataOnlyFlag == false) { readFileData(file, stream, binStream, rootElement); //} // // Eliminate "hem_flag" as it is replaced with "structure" // const QString hemFlagTag("hem_flag"); const QString structureValue = getHeaderTag(AbstractFile::headerTagStructure); const QString hemFlagValue = getHeaderTag(hemFlagTag); if (structureValue.isEmpty() && (hemFlagValue.isEmpty() == false)) { setHeaderTag(AbstractFile::headerTagStructure, hemFlagValue); } removeHeaderTag(hemFlagTag); this->postFileReadingProcessing(); clearModified(); } /** * Allows files to do processing after a file is read. */ void AbstractFile::postFileReadingProcessing() throw (FileException) { /// this method may be over ridden by sub classes } /** * Read the specified file. Will throw a FileException if an * error occurs while reading the file. */ void AbstractFile::readFileMetaDataOnly(const QString& filenameIn) throw(FileException) { setReadMetaDataOnlyFlag(true); readFile(filenameIn); } /** * Read the specified file. Will throw a FileException if an * error occurs while reading the file. */ void AbstractFile::readFile(const QString& filenameIn) throw(FileException) { if (filenameIn.isEmpty()) { throw FileException("Filename for reading a file of type " + descriptiveName + "is empty."); } QFileInfo fi(filenameIn); if (fi.exists()) { if (fi.isDir()) { throw FileException(filenameIn + " is a directory, not a file"); } } else { throw FileException(filenameIn + " does not exist."); } // Note: filenameIn could possibly be "this's" filename so make a // copy of it before calling "clear()" to prevent it from being erased. const QString filenameIn2(filenameIn); clear(); filename = filenameIn2; QFile file(getFileName()); const float fileSize = file.size() / 1048576.0; QTime timer; timer.start(); if (file.open(QFile::ReadOnly)) { try { readFileContents(file); } catch (FileException& e) { file.close(); clearModified(); throw e; } file.close(); } else { throw FileException(getFileName(), file.errorString()); //"Failure trying to open: "); } // // See how long it took to read the file // timeToReadFileInSeconds = static_cast(timer.elapsed()) / 1000.0; if (DebugControl::getDebugOn() || DebugControl::getFileReadTimingFlag()) { std::cout << "Time to read " << getFileName().toAscii().constData() << " (" << fileSize << " MB) was " << timeToReadFileInSeconds << " seconds." << std::endl; } } /** * read header data from an XML file. */ void AbstractFile::readHeaderXML(QDomElement& rootElement) { // // Loop through children of the root node // QDomNode rootChildNode = rootElement.firstChild(); while (rootChildNode.isNull() == false) { // // Is this the old style header node ? // //

// // // // //
// if (rootChildNode.toElement().tagName() == xmlHeaderOldTagName) { QDomNode node = rootChildNode.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { const QString tagName(elem.tagName()); QString tagValue = getXmlElementFirstChildAsString(elem); setHeaderTag(tagName, tagValue); if (tagName == headerTagComment) { const int len = tagValue.length(); if (len > commentLengthWarning) { std::cout << "WARNING " << FileUtilities::basename(getFileName()).toAscii().constData() << " comment is " << len << " characters." << std::endl; } } if (DebugControl::getDebugOn()) { std::cout << "XML Header Tag/Value (" << tagName.toAscii().constData() << "," << tagValue.toAscii().constData() << ")" << std::endl; } } node = node.nextSibling(); } } else if (rootChildNode.toElement().tagName() == xmlHeaderTagName) { // // Is this the current style header node ? // // QDomNode node = rootChildNode.firstChild(); while (node.isNull() == false) { QDomElement elem = node.toElement(); if (elem.isNull() == false) { if (elem.tagName() == xmlHeaderElementTagName) { const QDomNode nameNode = elem.namedItem(xmlHeaderElementName); const QDomNode valueNode = elem.namedItem(xmlHeaderElementValue); if ((nameNode.isNull() == false) && (valueNode.isNull() == false)) { const QDomElement nameElement = nameNode.toElement(); const QDomElement valueElement = valueNode.toElement(); if ((nameElement.isNull() == false) && (valueElement.isNull() == false)) { const QString tagName = getXmlElementFirstChildAsString(nameElement); const QString tagValue = getXmlElementFirstChildAsString(valueElement); if (tagName.isEmpty() == false) { setHeaderTag(tagName, tagValue); if (tagName == headerTagComment) { const int len = tagValue.length(); if (len > commentLengthWarning) { std::cout << "WARNING " << FileUtilities::basename(getFileName()).toAscii().constData() << " comment is " << len << " characters." << std::endl; } } if (DebugControl::getDebugOn()) { std::cout << "XML Header Tag/Value (" << tagName.toAscii().constData() << "," << tagValue.toAscii().constData() << ")" << std::endl; } } } } } } node = node.nextSibling(); } } rootChildNode = rootChildNode.nextSibling(); } } /** * write header data to an XML file. */ void AbstractFile::writeHeaderXML(QDomDocument& doc, QDomElement& rootElement) { // // GIFTI XML files have their own header format // if (dynamic_cast(this) != NULL) { return; } // // Create the header element // QDomElement headerElement = doc.createElement(xmlHeaderTagName); // // Loop through the header elements // std::map::iterator iter; for (iter = header.begin(); iter != header.end(); iter++) { // // Get the tag and its value // const QString tag(iter->first); const QString value(iter->second); // // Create the new element and add it to the header // QDomText tagName = doc.createCDATASection(tag); QDomElement elementName = doc.createElement(xmlHeaderElementName); elementName.appendChild(tagName); QDomText tagValue = doc.createCDATASection(value); QDomElement elementValue = doc.createElement(xmlHeaderElementValue); elementValue.appendChild(tagValue); QDomElement elem = doc.createElement(xmlHeaderElementTagName); elem.appendChild(elementName); elem.appendChild(elementValue); headerElement.appendChild(elem); } // // Add the header to the root element // rootElement.appendChild(headerElement); } /** * Write header to XML writer. */ void AbstractFile::writeHeaderXMLWriter(XmlGenericWriter& xmlWriter) throw (FileException) { if (this->header.begin() == this->header.end()) { return; } xmlWriter.writeStartElement(GiftiCommon::tagMetaData); // // Loop through the header elements // std::map::iterator iter; for (iter = header.begin(); iter != header.end(); iter++) { // // Get the tag and its value // const QString tag(iter->first); const QString value(iter->second); xmlWriter.writeStartElement(GiftiCommon::tagMD); xmlWriter.writeElementCData(GiftiCommon::tagName, tag); xmlWriter.writeElementCData(GiftiCommon::tagValue, value); xmlWriter.writeEndElement(); } xmlWriter.writeEndElement(); } /** * Get an XML element's first child and return it as a string. */ QString AbstractFile::getXmlElementFirstChildAsString(const QDomElement& elem) { QString value; QDomNode vNode = static_cast(elem.firstChild()); if (vNode.isNull() == false) { const QDomText textNode = vNode.toText(); if (textNode.isNull() == false) { value = textNode.data(); } } return value; } /** * Get an XML element's first child and return it as a float. */ float AbstractFile::getXmlElementFirstChildAsFloat(const QDomElement& elem) { QString value; QDomNode vNode = static_cast(elem.firstChild()); if (vNode.isNull() == false) { const QDomText textNode = vNode.toText(); if (textNode.isNull() == false) { value = textNode.data(); } } const float valueFloat = StringUtilities::toFloat(value); return valueFloat; } /** * Get an XML element's first child and return it as a double. */ double AbstractFile::getXmlElementFirstChildAsDouble(const QDomElement& elem) { QString value; QDomNode vNode = static_cast(elem.firstChild()); if (vNode.isNull() == false) { const QDomText textNode = vNode.toText(); if (textNode.isNull() == false) { value = textNode.data(); } } const double valueDouble = value.toDouble(); return valueDouble; } /** * Get an XML element's first child and return it as an int. */ int AbstractFile::getXmlElementFirstChildAsInt(const QDomElement& elem) { QString value; QDomNode vNode = static_cast(elem.firstChild()); if (vNode.isNull() == false) { const QDomText textNode = vNode.toText(); if (textNode.isNull() == false) { value = textNode.data(); } } const int valueInt = StringUtilities::toInt(value); return valueInt; } /** * Get an XML element's first child and return it as a float. */ void AbstractFile::getXmlElementFirstChildAsFloat(const QDomElement& elem, float* values, const int numValues) { QString value; QDomNode vNode = static_cast(elem.firstChild()); if (vNode.isNull() == false) { const QDomText textNode = vNode.toText(); if (textNode.isNull() == false) { value = textNode.data(); } } std::vector tokens; StringUtilities::token(value, " ", tokens); for (int i = 0; i < numValues; i++) { if (i < static_cast(tokens.size())) { values[i] = tokens[i]; } else { values[i] = 0.0; } } } /** * Get an XML element's first child and return it as an int. */ void AbstractFile::getXmlElementFirstChildAsInt(const QDomElement& elem, int* values, const int numValues) { QString value; QDomNode vNode = static_cast(elem.firstChild()); if (vNode.isNull() == false) { const QDomText textNode = vNode.toText(); if (textNode.isNull() == false) { value = textNode.data(); } } std::vector tokens; StringUtilities::token(value, " ", tokens); for (int i = 0; i < numValues; i++) { if (i < static_cast(tokens.size())) { values[i] = tokens[i]; } else { values[i] = 0; } } } /** * add a CDATA element to an XML Dom Element. */ void AbstractFile::addXmlCdataElement(QDomDocument& xmlDoc, QDomElement& parentElement, const QString& childElementName, const QString& childElementData) { QDomElement element = xmlDoc.createElement(childElementName); QDomCDATASection node = xmlDoc.createCDATASection(childElementData); element.appendChild(node); parentElement.appendChild(element); } /* * add a Text element to an XML Dom Element. */ void AbstractFile::addXmlTextElement(QDomDocument& xmlDoc, QDomElement& parentElement, const QString& childElementName, const QString& childElementData) { // // Use CDATA so that the text can be anything // addXmlCdataElement(xmlDoc, parentElement, childElementName, childElementData); /* QDomElement element = xmlDoc.createElement(childElementName); QDomText node = xmlDoc.createTextNode(childElementData); element.appendChild(node); parentElement.appendChild(element); */ } /** * add a Text element to an XML Dom Element. */ void AbstractFile::addXmlTextElement(QDomDocument& xmlDoc, QDomElement& parentElement, const QString& childElementName, const int childElementData) { QDomElement element = xmlDoc.createElement(childElementName); QDomText node = xmlDoc.createTextNode(StringUtilities::fromNumber(childElementData)); element.appendChild(node); parentElement.appendChild(element); } /** * add a Text element to an XML Dom Element. */ void AbstractFile::addXmlTextElement(QDomDocument& xmlDoc, QDomElement& parentElement, const QString& childElementName, const int* childElementData, const int numChildElements) { QDomElement element = xmlDoc.createElement(childElementName); QString data; for (int i = 0; i < numChildElements; i++) { if (i > 0) { data.append(" "); } data.append(StringUtilities::fromNumber(childElementData[i])); } QDomText node = xmlDoc.createTextNode(data); element.appendChild(node); parentElement.appendChild(element); } /** * add a float element to an XML Dom Element. */ void AbstractFile::addXmlTextElement(QDomDocument& xmlDoc, QDomElement& parentElement, const QString& childElementName, const float childElementData) { QDomElement element = xmlDoc.createElement(childElementName); QDomText node = xmlDoc.createTextNode(StringUtilities::fromNumber(childElementData)); element.appendChild(node); parentElement.appendChild(element); } /** * add a float element to an XML Dom Element. */ void AbstractFile::addXmlTextElement(QDomDocument& xmlDoc, QDomElement& parentElement, const QString& childElementName, const double childElementData) { QDomElement element = xmlDoc.createElement(childElementName); QDomText node = xmlDoc.createTextNode(QString::number(childElementData, 'f', 24)); element.appendChild(node); parentElement.appendChild(element); } /** * add a Text element to an XML Dom Element. */ void AbstractFile::addXmlTextElement(QDomDocument& xmlDoc, QDomElement& parentElement, const QString& childElementName, const float* childElementData, const int numChildElements) { QDomElement element = xmlDoc.createElement(childElementName); QString data; for (int i = 0; i < numChildElements; i++) { if (i > 0) { data.append(" "); } data.append(StringUtilities::fromNumber(childElementData[i])); } QDomText node = xmlDoc.createTextNode(data); element.appendChild(node); parentElement.appendChild(element); } /** * Read the header from "this" file. */ void AbstractFile::readHeader(QFile& file, QTextStream& stream) throw(FileException) { QString tag, value; //const qint64 origFilePos = stream.pos(); qint64 origFilePos = this->getQTextStreamPosition(stream); readTagLine(stream, tag, value); if (tag == "BeginHeader") { bool done = false; while (done == false) { readTagLine(stream, tag, value); //std::cout << "File position/size/end (while reading header): " // << file.pos() << ", " << file.size() << ", " << file.atEnd() << " " // << stream.atEnd() << std::endl; if (tag[0] == '#') { tag = tag.mid(1); } if (tag == "EndHeader") { done = true; } else { if (tag == headerTagComment) { value = StringUtilities::setupCommentForDisplay(value); const int len = value.length(); if (len > commentLengthWarning) { std::cout << "WARNING " << FileUtilities::basename(getFileName()).toAscii().constData() << " comment is " << len << " characters." << std::endl; } } setHeaderTag(tag, value); } } // // Need to set so binary data read correctly // //file.seek(stream.pos()); qint64 streamPos = this->getQTextStreamPosition(stream); if (file.seek(streamPos) == false) { std::cout << "ERROR: file.seek(" << streamPos << ") failed at " << __LINE__ << " in " << __FILE__ << std::endl; } } else { // // Close and reopen the file. I tried to get the file position // prior to reading and then setting the file position but the first // read from the file would get the first character twice. (JWH) // //file.close(); //if (file.open(IO_ReadOnly) == false) { // throw FileException(getFileName(), "Failure trying to open while reading header: "); //} #ifdef QT4_FILE_POS_BUG file.reset(); file.seek(0); file.close(); if (file.open(QFile::ReadOnly) == false) { throw FileException(filename, "Failed to reopen file after closing file since there\n" "is no header to get around QT4 file bugs."); } file.seek(0); file.reset(); #else // QT4_FILE_POS_BUG file.reset(); stream.reset(); file.seek(origFilePos); stream.seek(origFilePos); #endif // QT4_FILE_POS_BUG } } /** * As of QT 4.7.1 there is a bug in QT such that QTextStream::pos() * alters its position and corrupts further reading from the stream. * This method will try to detect this error and, if detected, it * will try to correct the error. If the error is detected a * message is printed to the console. */ qint64 AbstractFile::getQTextStreamPosition(QTextStream& textStream) throw (FileException) { const bool abortIfErrorFlag = true; // // Need to set so binary data read correctly // //file.seek(stream.pos()); qint64 streamPos = textStream.pos(); qint64 streamPos2 = textStream.pos(); if (streamPos != streamPos2) { if (abortIfErrorFlag) { QString message = "PROGRAM ERROR: A bug in QT software (qt.nokia.com) prevents this file (" + this->getFileName() + ") from being read correctly. You may be able to work around " + "this problem by editing the file and removing any long lines " + "in the FileHeader such as the \"comment\". Make a backup copy " + "if you are going to alter the file.\n" + "QT Version (Compiled): " + QT_VERSION_STR + "\n" + "QT Version (Runtime): " + qVersion(); throw FileException(message); } std::cout << "PROGRAM ERROR while reading: " << this->filename.toAscii().constData() << ". QT Software's QTextStream::pos() " << "has altered the file position and the file being " << "read may be read incorrectly or Caret will crash." << std::endl << "QT Version (Compiled): " << QT_VERSION_STR << "QT Version (Runtime): " << qVersion() << std::endl << "Correct position is " << streamPos << " and altered, incorrect position is " << streamPos2 << ". Caret will try to fix the file position." << std::endl; if (textStream.seek(streamPos) == false) { std::cout << "Caret failed to fix the file position." << std::endl; } } return streamPos; } /** * Read a line and chop off comment beginning with "#". */ void AbstractFile::readLineChopComment(QTextStream& stream, QString& lineOut) throw (FileException) { readLine(stream, lineOut); int commentCharPos = lineOut.indexOf('#'); if (commentCharPos != -1) { lineOut.resize(commentCharPos); } } #ifdef QT4_FILE_POS_BUG static const int BIG_BUFFER_SIZE = 1024 * 1024; static char bigBuffer[BIG_BUFFER_SIZE]; #endif // QT4_FILE_POS_BUG /** * Read a line from the file and return in a QString. May throw FileException */ void AbstractFile::readLine(QTextStream& stream, QString& lineOut) throw (FileException) { lineOut = ""; #ifdef QT4_FILE_POS_BUG QFile* file = dynamic_cast(stream.device()); if (file != NULL) { // readLine BUG http://www.trolltech.com/developer/task-tracker/index_html?method=entry&id=104776 // readLine BUG readLine() will read only a maximum of 4095 characters // readLine BUG lineOut = file->readLine(); if (file->readLine(bigBuffer, BIG_BUFFER_SIZE) > 0) { lineOut = bigBuffer; lineOut = lineOut.trimmed(); } } else { lineOut = stream.readLine(); } if (lineOut.isNull()) { lineOut = ""; } #else // QT4_FILE_POS_BUG lineOut = stream.readLine(); #endif // QT4_FILE_POS_BUG if (lineOut.isNull()) { lineOut = ""; // 3/25/05 palette file problems throw FileException(getFileName(), "Premature end of file. Is file damaged?"); } } /** * Read a line from the file and return in a c++ string. May throw FileException */ /* void AbstractFile::readLine(QTextStream& stream, QString& lineOut) throw (FileException) { const QString line = stream.readLine(); if (line.isNull()) { lineOut = ""); // 3/25/05 return; // 3/25/05 // 3/25/05 throw FileException(getFileName(), "Premature end of file. Is file damaged?"); } lineOut = line); } */ /** * Read a line from the file and return in a c++ string. May throw FileException */ void AbstractFile::readLine(const QString& /*filenameIn*/, QTextStream& stream, QString& lineOut) throw (FileException) { lineOut = ""; #ifdef QT4_FILE_POS_BUG QFile* file = dynamic_cast(stream.device()); if (file != NULL) { // readLine BUG http://www.trolltech.com/developer/task-tracker/index_html?method=entry&id=104776 // readLine BUG readLine() will read only a maximum of 4095 characters // readLine BUG lineOut = file->readLine(); if (file->readLine(bigBuffer, BIG_BUFFER_SIZE) > 0) { lineOut = bigBuffer; } //lineOut = lineOut.trimmed(); } else { lineOut = stream.readLine(); } if (lineOut.isNull()) { lineOut = ""; } #else // QT4_FILE_POS_BUG const QString line = stream.readLine(); if (line.isNull()) { lineOut = ""; // 3/25/05 return; // 3/25/05 // 3/25/05 throw FileException(filenameIn, "Premature end of file. Is file damaged?"); } lineOut = line; #endif // QT4_FILE_POS_BUG } /** * Read a line that contains a tag and its associated value */ void AbstractFile::readTagLine(const QString& fileNameIn, QTextStream& stream, QString& tag, QString& tagValue) throw (FileException) { tag = ""; tagValue = ""; QString sline; AbstractFile::readLine(fileNameIn, stream, sline); QString line(sline); QString tagStr; QTextStream(&line, QIODevice::ReadOnly) >> tagStr; if (tagStr.isEmpty()) { return; //throw FileException(filename, "Invalid line in tags section."); } tag = tagStr; char* lineCh = new char[line.length() + 1]; strcpy(lineCh, line.toAscii().constData()); int blankCount = 0; int offset = 0; for (unsigned int i = 0; i < strlen(lineCh); i++) { if (lineCh[i] == '\n') { lineCh[i] = '\0'; if (blankCount == 0) { offset = i; } break; } else if (lineCh[i] == ' ') { blankCount++; if (blankCount == 1) { offset = i + 1; } } } tagValue = &lineCh[offset]; tagValue = StringUtilities::trimWhitespace(tagValue); delete[] lineCh; } /** * Read a line that contains a tag and its associated value */ void AbstractFile::readTagLine(QTextStream& stream, QString& tag, QString& tagValue) throw (FileException) { static bool debugFlag = false; tag = ""; tagValue = ""; QString line; readLine(stream, line); if (debugFlag) std::cout << "Line: " << line.toAscii().constData() << std::endl; QString tagStr; QTextStream(&line, QIODevice::ReadOnly) >> tagStr; if (debugFlag) std::cout << "tagStr: " << tagStr.toAscii().constData() << std::endl; if (tagStr.isEmpty()) { return; //throw FileException(filename, "Invalid line in tags section."); } tag = tagStr; char* lineCh = new char[line.length() + 1]; strcpy(lineCh, line.toAscii().constData()); int blankCount = 0; int offset = 0; for (unsigned int i = 0; i < strlen(lineCh); i++) { if (lineCh[i] == '\n') { lineCh[i] = '\0'; if (blankCount == 0) { offset = i; } break; } else if (lineCh[i] == ' ') { blankCount++; if (blankCount == 1) { offset = i + 1; } } } tagValue = &lineCh[offset]; tagValue = StringUtilities::trimWhitespace(tagValue); delete[] lineCh; } /** * Read a line that contains a tag and its associated value */ void AbstractFile::readTagLine(QTextStream& stream, QString& line, QString& tag, QString& tagValue) throw (FileException) { static bool debugFlag = false; line = ""; tag = ""; tagValue = ""; readLine(stream, line); if (debugFlag) std::cout << "Line: " << line.toAscii().constData() << std::endl; QString tagStr; QTextStream(&line, QIODevice::ReadOnly) >> tagStr; if (debugFlag) std::cout << "tagStr: " << tagStr.toAscii().constData() << std::endl; if (tagStr.isEmpty()) { return; //throw FileException(filename, "Invalid line in tags section."); } tag = tagStr; char* lineCh = new char[line.length() + 1]; strcpy(lineCh, line.toAscii().constData()); int blankCount = 0; int offset = 0; for (unsigned int i = 0; i < strlen(lineCh); i++) { if (lineCh[i] == '\n') { lineCh[i] = '\0'; if (blankCount == 0) { offset = i; } break; } else if (lineCh[i] == ' ') { blankCount++; if (blankCount == 1) { offset = i + 1; } } } tagValue = &lineCh[offset]; tagValue = StringUtilities::trimWhitespace(tagValue); delete[] lineCh; } /** * Read a line that contains a number, a tag, and its associated value */ void AbstractFile::readNumberedTagLine(QTextStream& stream, int& number, QString& tag, QString& tagValue) throw (FileException) { static bool debugFlag = false; number = -1; tag = ""; tagValue = ""; QString qline; readLine(stream, qline); if (debugFlag) std::cout << "Line: " << qline.toAscii().constData() << std::endl; int numberRead = -1; QString tagStr; QTextStream(&qline, QIODevice::ReadOnly) >> numberRead >> tagStr; if (debugFlag) { std::cout << "number: " << numberRead << std::endl; std::cout << "tagStr: " << tagStr.toAscii().constData() << std::endl; } if (tagStr.isEmpty()) { return; //throw FileException(filename, "Invalid line in tags section."); } number = numberRead; tag = tagStr; // // Find first character after tag // QString line(qline); int pos = line.indexOf(tag); if (pos != -1) { pos += tag.length(); } // // Find first non-whitespace character and make it the tag value // const int len = line.length(); for (int i = pos; i < len; i++) { if ((line[i] != ' ') && (line[i] != '\t')) { tagValue = line.mid(i); tagValue = StringUtilities::trimWhitespace(tagValue); return; } } } /** * Read a line and store tokens in a string list */ QStringList AbstractFile::readLineIntoStringList(QTextStream& stream) throw (FileException) { QString line; readLine(stream, line); QStringList sl = line.split(" "); return sl; //return QStringList::split(" ", line); } /** * Read a line separating each white spaced string into "tokens" */ void AbstractFile::readLineIntoTokens(QTextStream& stream, QString& lineOut, std::vector& tokens) throw (FileException) { tokens.clear(); readLine(stream, lineOut); StringUtilities::token(lineOut, " \t", tokens); } /** * Read a line separating each white spaced string into "tokens" */ void AbstractFile::readLineIntoTokens(const QString& filenameIn, QTextStream& stream, QString& lineOut, std::vector& tokens) throw (FileException) { tokens.clear(); readLine(filenameIn, stream, lineOut); StringUtilities::token(lineOut, " \t", tokens); } /** * Split a tag that start with a column number into the column number * and the tag's value. Returns column number. */ int AbstractFile::splitTagIntoColumnAndValue(const QString s, QString& value) const { std::vector tokens; StringUtilities::token(s, " ", tokens); if (tokens.size() == 0) { return -1; } const int columnNumber = tokens[0].toInt(); if (tokens.size() == 1) { return columnNumber; } value = tokens[1]; for (unsigned int i = 2; i < tokens.size(); i++) { value.append(" "); value.append(tokens[i]); } return columnNumber; } /** * Write the current file's memory to a byte array. */ void AbstractFile::writeFileToArray(QByteArray& ba) throw (FileException) { QTextStream ts(ba, QIODevice::WriteOnly); QDataStream ds(&ba, QIODevice::WriteOnly); ds.setVersion(QDataStream::Qt_4_3); writeFileContents(ts, ds); } /** * method used for writing files. */ void AbstractFile::writeFileContents(QTextStream& stream, QDataStream& dataStream) throw (FileException) { bool isXmlFile = false; bool isCsvFile = false; switch (fileWriteType) { case FILE_FORMAT_ASCII: if (getCanWrite(FILE_FORMAT_ASCII) == false) { throw FileException(filename, "Ascii (Text) type file not supported."); } break; case FILE_FORMAT_BINARY: if (getCanWrite(FILE_FORMAT_BINARY) == false) { throw FileException(filename, "Binary type file not supported."); } break; case FILE_FORMAT_XML: if (getCanWrite(FILE_FORMAT_XML) == false) { throw FileException(filename, "XML type file not supported."); } isXmlFile = true; break; case FILE_FORMAT_XML_BASE64: if (getCanWrite(FILE_FORMAT_XML_BASE64) == false) { throw FileException(filename, "XML Base64 type file not supported."); } isXmlFile = true; break; case FILE_FORMAT_XML_GZIP_BASE64: if (getCanWrite(FILE_FORMAT_XML_GZIP_BASE64) == false) { throw FileException(filename, "XML GZip Base64 type file not supported."); } isXmlFile = true; break; case FILE_FORMAT_XML_EXTERNAL_BINARY: if (getCanWrite(FILE_FORMAT_XML_EXTERNAL_BINARY) == false) { throw FileException(filename, "XML External Binary type file not suppported."); } isXmlFile = true; break; case FILE_FORMAT_OTHER: if (getCanWrite(FILE_FORMAT_OTHER) == false) { throw FileException(filename, "\"Other\" type file not supported."); } break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: if (getCanWrite(FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE) == false) { throw FileException(filename, "\"Comma Separated File Format\" type file not supported."); } isCsvFile = true; break; } // // Setup for XML file // QDomDocument xmlDoc; QDomElement rootElement; if (isXmlFile) { // // Create the root element // rootElement = xmlDoc.createElement(rootXmlElementTagName); xmlDoc.appendChild(rootElement); // // Add the encoding information // QDomNode encodeNode = xmlDoc.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\""); xmlDoc.insertBefore(encodeNode, xmlDoc.firstChild()); } stream.setRealNumberNotation(QTextStream::FixedNotation); stream.setRealNumberPrecision(textFileDigitsRightOfDecimal); if (fileHasHeader) { setHeaderTag(headerTagDate, QDateTime::currentDateTime().toString(Qt::ISODate)); switch (fileWriteType) { case FILE_FORMAT_ASCII: setHeaderTag(headerTagEncoding, getHeaderTagEncodingValueAscii()); break; case FILE_FORMAT_BINARY: setHeaderTag(headerTagEncoding, getHeaderTagEncodingValueBinary()); break; case FILE_FORMAT_XML: setHeaderTag(headerTagEncoding, getHeaderTagEncodingValueXML()); break; case FILE_FORMAT_XML_BASE64: setHeaderTag(headerTagEncoding, getHeaderTagEncodingValueXMLBase64()); break; case FILE_FORMAT_XML_GZIP_BASE64: setHeaderTag(headerTagEncoding, getHeaderTagEncodingValueXMLGZipBase64()); break; case FILE_FORMAT_XML_EXTERNAL_BINARY: setHeaderTag(headerTagEncoding, getHeaderTagEncodingValueXMLExternalBinary()); break; case FILE_FORMAT_OTHER: setHeaderTag(headerTagEncoding, getHeaderTagEncodingValueOther()); break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: setHeaderTag(headerTagEncoding, getHeaderTagEncodingValueCommaSeparatedValueFile()); break; } // // Add caret version to header // #ifdef CARET_FLAG setHeaderTag("Caret-Version", CaretVersion::getCaretVersionAsString()); #endif // CARET_FLAG if (isXmlFile) { writeHeaderXML(xmlDoc, rootElement); } else if (isCsvFile) { } else { writeHeader(stream); } } #ifdef QT4_FILE_POS_BUG setBinaryFilePosQT4Bug(); #else // // Still a bug in QT4 // setBinaryFilePosQT4Bug(); #endif // QT4_FILE_POS_BUG writeFileData(stream, dataStream, xmlDoc, rootElement); // // Handle XML files // if (isXmlFile) { // // Do not set for GIFTI data files // if (dynamic_cast(this) == NULL) { xmlDoc.save(stream, 3); } } } /** * Write the data file. */ void AbstractFile::writeFile(const QString& filenameIn) throw (FileException) { if (filenameIn.isEmpty()) { throw FileException(filenameIn, "Filename for writing is isEmpty"); } filename = filenameIn; // // Caret command may set a file format preference // for (unsigned int i = 0; i < preferredWriteTypeCaretCommand.size(); i++) { if (getCanWrite(preferredWriteTypeCaretCommand[i])) { fileWriteType = preferredWriteTypeCaretCommand[i]; break; } } // // Special case for metric file // if (dynamic_cast(this) != NULL) { if (getCanWrite(preferredMetricWriteTypeCaretCommand)) { fileWriteType = preferredMetricWriteTypeCaretCommand; } } // // Check file type here to avoid opening and clearing a file on disk. // switch (fileWriteType) { case FILE_FORMAT_ASCII: if (getCanWrite(FILE_FORMAT_ASCII) == false) { throw FileException(filename, "Ascii (Text) type file not supported."); } break; case FILE_FORMAT_BINARY: if (getCanWrite(FILE_FORMAT_BINARY) == false) { throw FileException(filename, "Binary type file not supported."); } break; case FILE_FORMAT_XML: if (getCanWrite(FILE_FORMAT_XML) == false) { throw FileException(filename, "XML type file not supported."); } break; case FILE_FORMAT_XML_BASE64: if (getCanWrite(FILE_FORMAT_XML_BASE64) == false) { throw FileException(filename, "XML Base64 type file not supported."); } break; case FILE_FORMAT_XML_GZIP_BASE64: if (getCanWrite(FILE_FORMAT_XML_GZIP_BASE64) == false) { throw FileException(filename, "XML GZip Base64 type file not supported."); } break; case FILE_FORMAT_XML_EXTERNAL_BINARY: if (getCanWrite(FILE_FORMAT_XML_EXTERNAL_BINARY) == false) { throw FileException(filename, "XML External Binary type file not supported."); } break; case FILE_FORMAT_OTHER: if (getCanWrite(FILE_FORMAT_OTHER) == false) { throw FileException(filename, "\"Other\" type file not supported."); } break; case FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: if (getCanWrite(FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE) == false) { throw FileException(filename, "\"Comma Separated Value File\" type file not supported."); } break; } QTime timer; timer.start(); writingQFile = new QFile(this->filename); if (AbstractFile::getOverwriteExistingFilesAllowed() == false) { if (writingQFile->exists()) { throw FileException("file exists and overwrite is prohibited."); } } QString errMsg; if (writingQFile->open(QFile::WriteOnly)) { QTextStream stream(writingQFile); QDataStream binStream(writingQFile); binStream.setVersion(QDataStream::Qt_4_3); try { writeFileContents(stream, binStream); writingQFile->close(); delete writingQFile; writingQFile = NULL; // // Update file permissions ? // if (fileWritePermissions != 0) { QFile::setPermissions(getFileName(), fileWritePermissions); } } catch (FileException& e) { writingQFile->close(); errMsg = writingQFile->errorString(); delete writingQFile; writingQFile = NULL; throw e; } clearModified(); } else { errMsg = " Open for writing, " + writingQFile->errorString(); delete writingQFile; writingQFile = NULL; throw FileException(getFileName(), errMsg); /* QFileInfo fileInfo(getFileName()); if (fileInfo.exists() && (fileInfo.isWritable() == false)) { throw FileException(getFileName(), "File exists but it is not writable"); } else { QString msg("Unable to open for writing. Current path: "); msg.append(QDir::currentPath()); throw FileException(getFileName(), msg); } */ } // // See how long it took to read the file // const float timeToWriteFileInSeconds = static_cast(timer.elapsed()) / 1000.0; if (DebugControl::getDebugOn()) { std::cout << "Time to write " << getFileName().toAscii().constData() << " was " << timeToWriteFileInSeconds << " seconds." << std::endl; } } /** * Update the file's metadata for Caret6. */ void AbstractFile::updateMetaDataForCaret6() { this->removeHeaderTag("encoding"); this->removeHeaderTag("pubmed_id"); this->setHeaderTag("Caret-Version", CaretVersion::getCaretVersionAsString()); this->removeHeaderTag("date"); this->setHeaderTag("Date", QDateTime::currentDateTime().toString(Qt::ISODate)); this->setHeaderTag("UserName", SystemUtilities::getUserName()); } /** * Write the file's memory in caret6 format to the specified name. */ QString AbstractFile::writeFileInCaret6Format(const QString& filenameIn, Structure structure,const ColorFile* colorFileIn, const bool useCaret6ExtensionFlag) throw (FileException) { throw FileException(filenameIn + " cannot be written in Caret6 format at this time."); } /** * Write the file's header. */ void AbstractFile::writeHeader(QTextStream& stream) throw (FileException) { stream << "BeginHeader\n"; std::map::iterator iter; for (iter = header.begin(); iter != header.end(); iter++) { const QString tag(iter->first); const QString value(iter->second); if (tag == headerTagComment) { stream << tag << " " << StringUtilities::setupCommentForStorage(value) << "\n"; } else { stream << tag << " " << value << "\n"; } } stream << "EndHeader\n"; } /** * Create a subclass of abstract file based upon the file name's extension. * Returns NULL if not recognized. */ AbstractFile* AbstractFile::getSubClassDataFile(const QString& filename, QString& errorMessageOut) { AbstractFile* af = NULL; errorMessageOut = ""; // // Get the filename's extension to determine the type of file // Prepend with a period. // QString ext("."); ext.append(FileUtilities::filenameExtension(filename)); if (ext.isEmpty() || (ext.length() == 1)) { errorMessageOut = "filename has no extension which is needed to determine type of file."; return NULL; } #ifdef CARET_FLAG if (ext == ".xml") { if (StringUtilities::endsWith(filename, SpecFile::getAtlasSpaceFileExtension())) { ext = SpecFile::getAtlasSpaceFileExtension(); } if (StringUtilities::endsWith(filename, SpecFile::getCocomacConnectivityFileExtension())) { ext = SpecFile::getCocomacConnectivityFileExtension(); } } else if (ext == ".gz") { if (filename.endsWith(SpecFile::getNiftiGzipVolumeFileExtension())) { ext = SpecFile::getNiftiVolumeFileExtension(); } } else if (ext == SpecFile::getFreeSurferAsciiSurfaceFileExtension()) { if (StringUtilities::endsWith(filename, SpecFile::getFreeSurferAsciiCurvatureFileExtension())) { ext = SpecFile::getFreeSurferAsciiCurvatureFileExtension(); } else if (StringUtilities::endsWith(filename, SpecFile::getFreeSurferAsciiFunctionalFileExtension())) { ext = SpecFile::getFreeSurferAsciiFunctionalFileExtension(); } } const QString imageExt = QImageReader::imageFormat(filename); if (imageExt.isEmpty() == false) { af = new ImageFile; } else if (filename.endsWith(SpecFile::getAreaColorFileExtension())) { af = new AreaColorFile; } else if (filename.endsWith(SpecFile::getArealEstimationFileExtension())) { af = new ArealEstimationFile; } else if (filename.endsWith(SpecFile::getAtlasSpaceFileExtension())) { af = new AtlasSpaceFile; } else if (filename.endsWith(SpecFile::getAtlasSurfaceDirectoryFileExtension())) { af = new AtlasSurfaceDirectoryFile; } else if (filename.endsWith(SpecFile::getBorderFileExtension())) { af = new BorderFile; } else if (filename.endsWith(SpecFile::getBorderColorFileExtension())) { af = new BorderColorFile; } else if (filename.endsWith(SpecFile::getBorderProjectionFileExtension())) { af = new BorderProjectionFile; } else if (filename.endsWith(SpecFile::getBrainVoyagerFileExtension())) { af = new BrainVoyagerFile; } else if (filename.endsWith(SpecFile::getCellFileExtension())) { af = new CellFile; } else if (filename.endsWith(SpecFile::getCellColorFileExtension())) { af = new CellColorFile; } else if (filename.endsWith(SpecFile::getCellProjectionFileExtension())) { af = new CellProjectionFile; } else if (filename.endsWith(SpecFile::getCocomacConnectivityFileExtension())) { af = new CocomacConnectivityFile; } else if (filename.endsWith(SpecFile::getContourFileExtension())) { af = new ContourFile; } else if (filename.endsWith(SpecFile::getContourCellColorFileExtension())) { af = new ContourCellColorFile; } else if (filename.endsWith(SpecFile::getContourCellFileExtension())) { af = new ContourCellFile; } else if (filename.endsWith(SpecFile::getCoordinateFileExtension())) { af = new CoordinateFile; } else if (filename.endsWith(SpecFile::getCutsFileExtension())) { af = new CutsFile; } else if (filename.endsWith(SpecFile::getDeformationMapFileExtension())) { af = new DeformationMapFile; } else if (filename.endsWith(SpecFile::getDeformationFieldFileExtension())) { af = new DeformationFieldFile; } else if (filename.endsWith(SpecFile::getFreeSurferAsciiCurvatureFileExtension())) { af = new FreeSurferCurvatureFile; af->setFileReadType(AbstractFile::FILE_FORMAT_ASCII); } else if (filename.endsWith(SpecFile::getFreeSurferBinaryCurvatureFileExtension())) { af = new FreeSurferCurvatureFile; af->setFileReadType(AbstractFile::FILE_FORMAT_BINARY); } else if (filename.endsWith(SpecFile::getFreeSurferAsciiFunctionalFileExtension())) { af = new FreeSurferFunctionalFile; af->setFileReadType(AbstractFile::FILE_FORMAT_ASCII); } else if (filename.endsWith(SpecFile::getFreeSurferBinaryFunctionalFileExtension())) { af = new FreeSurferFunctionalFile; af->setFileReadType(AbstractFile::FILE_FORMAT_BINARY); } else if (filename.endsWith(SpecFile::getFreeSurferLabelFileExtension())) { af = new FreeSurferLabelFile; } else if (filename.endsWith(SpecFile::getFreeSurferAsciiSurfaceFileExtension())) { af = new FreeSurferSurfaceFile; af->setFileReadType(AbstractFile::FILE_FORMAT_ASCII); } else if (filename.endsWith(SpecFile::getFociFileExtension())) { af = new FociFile; } else if (filename.endsWith(SpecFile::getFociColorFileExtension())) { af = new FociColorFile; } else if (filename.endsWith(SpecFile::getFociProjectionFileExtension())) { af = new FociProjectionFile; } else if (filename.endsWith(SpecFile::getFociSearchFileExtension())) { af = new FociSearchFile; } else if (filename.endsWith(SpecFile::getLatLonFileExtension())) { af = new LatLonFile; } else if (filename.endsWith(SpecFile::getMetricFileExtension())) { af = new MetricFile; } else if (filename.endsWith(SpecFile::getRegionOfInterestFileExtension())) { af = new NodeRegionOfInterestFile; } else if (filename.endsWith(SpecFile::getPaintFileExtension())) { af = new PaintFile; } else if (filename.endsWith(SpecFile::getPaletteFileExtension())) { af = new PaletteFile; } else if (filename.endsWith(SpecFile::getParamsFileExtension())) { af = new ParamsFile; } else if (filename.endsWith(SpecFile::getPreferencesFileExtension())) { af = new PreferencesFile; } else if (filename.endsWith(SpecFile::getProbabilisticAtlasFileExtension())) { af = new ProbabilisticAtlasFile; } else if (filename.endsWith(SpecFile::getRgbPaintFileExtension())) { af = new RgbPaintFile; } else if (filename.endsWith(SpecFile::getSceneFileExtension())) { af = new SceneFile; } else if (filename.endsWith(SpecFile::getSectionFileExtension())) { af = new SectionFile; } else if (filename.endsWith(SpecFile::getSpecFileExtension())) { af = new SpecFile; } else if (filename.endsWith(SpecFile::getSurfaceShapeFileExtension())) { af = new SurfaceShapeFile; } else if (filename.endsWith(SpecFile::getTextFileExtension())) { af = new TextFile; } else if (filename.endsWith(SpecFile::getTopographyFileExtension())) { af = new TopographyFile; } else if (filename.endsWith(SpecFile::getTopoFileExtension())) { af = new TopologyFile; } else if (filename.endsWith(SpecFile::getTransformationMatrixFileExtension())) { af = new TransformationMatrixFile; } else if (filename.endsWith(SpecFile::getAnalyzeVolumeFileExtension())) { af = new VolumeFile; } else if (filename.endsWith(SpecFile::getAfniVolumeFileExtension())) { af = new VolumeFile; } else if (filename.endsWith(SpecFile::getWustlVolumeFileExtension())) { af = new VolumeFile; } else if (filename.endsWith(SpecFile::getNiftiVolumeFileExtension())) { af = new VolumeFile; } else if (filename.endsWith(SpecFile::getNiftiGzipVolumeFileExtension())) { af = new VolumeFile; } else if (filename.endsWith(SpecFile::getVtkModelFileExtension())) { af = new VtkModelFile; } else if (filename.endsWith(SpecFile::getTopoFileExtension())) { af = new TopologyFile; } else if (filename.endsWith(SpecFile::getGeodesicDistanceFileExtension())) { af = new GeodesicDistanceFile; } else if (filename.endsWith(SpecFile::getWustlRegionFileExtension())) { af = new WustlRegionFile; } else if (filename.endsWith(SpecFile::getStudyMetaDataFileExtension())) { af = new StudyMetaDataFile; } else if (filename.endsWith(SpecFile::getStudyCollectionFileExtension())) { af = new StudyCollectionFile; } else if (filename.endsWith(SpecFile::getVocabularyFileExtension())) { af = new VocabularyFile; } else if (filename.endsWith(SpecFile::getSureFitVectorFileExtension())) { af = new SureFitVectorFile; } else if (filename.endsWith(SpecFile::getGiftiCoordinateFileExtension())) { af = new CoordinateFile; } else if (filename.endsWith(SpecFile::getGiftiFunctionalFileExtension())) { af = new MetricFile; } else if (filename.endsWith(SpecFile::getGiftiLabelFileExtension())) { af = new PaintFile; } else if (filename.endsWith(SpecFile::getGiftiRgbaFileExtension())) { af = new RgbPaintFile; } else if (filename.endsWith(SpecFile::getGiftiShapeFileExtension())) { af = new SurfaceShapeFile; } else if (filename.endsWith(SpecFile::getGiftiSurfaceFileExtension())) { af = new SurfaceFile; } else if (filename.endsWith(SpecFile::getGiftiTensorFileExtension())) { af = NULL; // not tensor file at this time } else if (filename.endsWith(SpecFile::getGiftiTimeSeriesFileExtension())) { af = new MetricFile; } else if (filename.endsWith(SpecFile::getGiftiTopologyFileExtension())) { af = new TopologyFile; } else if (filename.endsWith(SpecFile::getGiftiVectorFileExtension())) { af = new VectorFile; } else if (ext == SpecFile::getGiftiGenericFileExtension()) { af = new GiftiDataArrayFile; } else { errorMessageOut = "Unrecognized file extension = "; errorMessageOut.append(ext); return NULL; } return af; #else // CARET_FLAG // // Must be GIFTI API // if (ext == ".gii") { af = new GiftiDataArrayFile; } else { errorMessageOut = "Unrecognized file extension = "; errorMessageOut.append(ext); return NULL; } return af; #endif // CARET_FLAG } /** * Get a file type name based upon its extension. If the file's type is not * recognized, the file name's extension is returned. */ QString AbstractFile::getFileTypeNameFromFileName(const QString& filename) { QString typeName; QString errorMessageOut; AbstractFile* af = getSubClassDataFile(filename, errorMessageOut); if (af != NULL) { typeName = af->getDescriptiveName(); delete af; } if (typeName.isEmpty()) { typeName = FileUtilities::filenameExtension(filename); if (typeName == "gz") { QString f(FileUtilities::filenameWithoutExtension(filename)); typeName = FileUtilities::filenameExtension(f); } if ((typeName == "BRIK") || (typeName == "img")) { typeName = "Volume File Data"; } } if (typeName.isEmpty()) { typeName = "unknown"; } //std::cout << "Filename: " << filename // << " Typename: " << typeName << std::endl; return typeName; } /** * set the default file name prefix. */ void AbstractFile::setDefaultFileNamePrefix(const QString& s, const int numNodes) { defaultFileNamePrefix = s; defaultFileNameNumberOfNodes = numNodes; } /** * get the default file name prefix. */ void AbstractFile::getDefaultFileNamePrefix(QString& prefix, int& numNodes) { prefix = defaultFileNamePrefix; numNodes = defaultFileNameNumberOfNodes; } /** * Read any Caret data file. The type of file is determined by its extension. The caller * must "dynamic_cast" the returned pointer to the appropriate file type to access * class specific data/methods. If returned pointer is NULL check the errorMessage * to see a description of why the file was not read successfully. */ AbstractFile* AbstractFile::readAnySubClassDataFile(const QString& filename, const bool readMetaDataOnly, QString& errorMessageOut) { AbstractFile* af = getSubClassDataFile(filename, errorMessageOut); if (af == NULL) { return NULL; } try { af->setReadMetaDataOnlyFlag(readMetaDataOnly); af->readFile(filename); if (readMetaDataOnly) { af->setReadMetaDataOnlyFlag(false); } } catch (FileException& e) { if (af != NULL) { delete af; } errorMessageOut = e.whatQString(); return NULL; } return af; } /// used by AbstractFile class TypeExt { public: TypeExt(const QString& e, const QString& t) { extension = e.mid(5); typeName = t; typeName.append(" (*."); typeName.append(extension); typeName.append(")"); } bool operator<(const TypeExt& te) const { return (typeName < te.typeName); } QString typeName; QString extension; }; /** * Get all filetype names and extensions. */ void AbstractFile::getAllFileTypeNamesAndExtensions(std::vector& typeNames, std::vector& extensions) { typeNames.clear(); extensions.clear(); QString ext; std::vector typeAndExtension; #ifdef CARET_FLAG ext = "file"; ext.append(SpecFile::getTopoFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getCoordinateFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getLatLonFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getSectionFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getTransformationMatrixFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getRegionOfInterestFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getPaintFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getAreaColorFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getRgbPaintFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getBorderFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getBorderColorFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getBorderProjectionFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getPaletteFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getTopographyFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getCellFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getCellColorFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getCellProjectionFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getContourFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getContourCellFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getContourCellColorFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getFociFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getFociColorFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getFociProjectionFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getFociSearchFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getProbabilisticAtlasFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getMetricFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getSurfaceShapeFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getGiftiVectorFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getCocomacConnectivityFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getArealEstimationFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getCutsFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getParamsFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getDeformationMapFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getDeformationFieldFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getVtkModelFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getAtlasSpaceFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getAtlasSurfaceDirectoryFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getBrainVoyagerFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getFreeSurferAsciiCurvatureFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getFreeSurferBinaryCurvatureFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getFreeSurferAsciiFunctionalFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getFreeSurferBinaryFunctionalFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getFreeSurferLabelFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getFreeSurferAsciiSurfaceFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getSpecFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getAnalyzeVolumeFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getAfniVolumeFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getWustlVolumeFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getNiftiVolumeFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getStudyMetaDataFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getVocabularyFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getWustlRegionFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getGeodesicDistanceFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getSceneFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(".jpg"); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getSureFitVectorFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getGiftiCoordinateFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getGiftiFunctionalFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getGiftiLabelFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getGiftiRgbaFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getGiftiShapeFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getGiftiSurfaceFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getGiftiTensorFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getGiftiTimeSeriesFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getGiftiTopologyFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getGiftiGenericFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); ext = "file"; ext.append(SpecFile::getTextFileExtension()); typeAndExtension.push_back(TypeExt(ext, getFileTypeNameFromFileName(ext))); #endif // CARET_FLAG std::sort(typeAndExtension.begin(), typeAndExtension.end()); for (unsigned int i = 0; i < typeAndExtension.size(); i++) { extensions.push_back(typeAndExtension[i].extension); typeNames.push_back(typeAndExtension[i].typeName); } } /** * find out if comma separated file conversion supported. */ void AbstractFile::getCommaSeparatedFileSupport(bool& readFromCSV, bool& writeToCSV) const { readFromCSV = false; writeToCSV = false; } /** * write the file's data into a comma separated values file (throws exception if not supported). */ void AbstractFile::writeDataIntoCommaSeparatedValueFile(CommaSeparatedValueFile& /*csv*/) throw (FileException) { throw FileException("Comma Separated File not supported for this file type."); } /** * read the file's data from a comma separated values file (throws exception if not supported). */ void AbstractFile::readDataFromCommaSeparatedValuesTable(const CommaSeparatedValueFile& /*csv*/) throw (FileException) { throw FileException("Comma Separated File not supported for this file type."); } /** * write the header's data into a StringTable. */ void AbstractFile::writeHeaderDataIntoStringTable(StringTable& table) const { const int numRows = header.size(); table.setNumberOfRowsAndColumns(numRows, 2, "Header"); table.setTableTitle("header"); table.setColumnTitle(0, "tag"); table.setColumnTitle(1, "value"); int rowCount = 0; for (std::map::const_iterator iter = header.begin(); iter != header.end(); iter++) { const QString tag(iter->first); QString value(iter->second); if (tag == headerTagComment) { value = StringUtilities::setupCommentForStorage(value); } table.setElement(rowCount, 0, tag); table.setElement(rowCount, 1, value); rowCount++; } } /** * read the header's data from a StringTable. */ void AbstractFile::readHeaderDataFromStringTable(const StringTable& table) throw (FileException) { if (table.getTableTitle() != "header") { throw FileException("Table title is not named \"header\" when reading the header " "from a string table."); } if (table.getNumberOfColumns() < 2) { throw FileException("Table containing header has less than two columns"); } // // clear the header // header.clear(); // // Read the header // for (int i = 0; i < table.getNumberOfRows(); i++) { const QString tag(table.getElement(i, 0)); const QString value(table.getElement(i, 1)); setHeaderTag(tag, value); } } /** * generate a date and time timestamp. */ QString AbstractFile::generateDateAndTimeStamp() { // // In form "03 Jan 2007 13:41:25" // //const QString s(QDateTime::currentDateTime().toString("dd MMM yyyy hh:mm:ss")); const QString s(DateAndTime::getDateAndTimeForNaming()); return s; } /** * generate a unique timestamp that is all numeric but in a string * since too large for an 4 bit integer */ QString AbstractFile::generateUniqueNumericTimeStampAsString() { static int counter = 0; // used so timestamp is unique if two calls within 1msec of each other // // Four digit number with leading zeros // QString fiveDigitNumber; if (counter < 10000) { fiveDigitNumber += "0"; } if (counter < 1000) { fiveDigitNumber += "0"; } if (counter < 100) { fiveDigitNumber += "0"; } if (counter < 10) { fiveDigitNumber += "0"; } fiveDigitNumber += QString::number(counter); // where yyyy = 2 digit year // MM = 2 digit month // dd = 2 digit date // hh = 2 digit hour // mm = 2 digit minumte // zzz = 3 digit milliseconds // UUU = 3 digit number from counter // // // TimeStamp string // const QString s(QDateTime::currentDateTime().toString("yyyyMMddhhmmzzz") + fiveDigitNumber); // // update counter // counter++; if (counter > 99999) { counter = 0; } return s; } /** * allow events to process (call when doing "busy" operations */ void AbstractFile::allowEventsToProcess() { if (qApp != NULL) { qApp->processEvents(); } } /** * compare a file for unit testing (returns true if "within tolerance"). */ bool AbstractFile::compareFileForUnitTesting(const AbstractFile* /*af*/, const float /*tolerance*/, QString& messageOut) const { messageOut = ("ERROR: Comparison for unit testing of " + descriptiveName + " has not been implemented. The method \"compareFileForUnitTesting\"" + " must be implemented for its class."); return false; } /** * set the number of digits right of the decimal when writing float to text files. */ void AbstractFile::setTextFileDigitsRightOfDecimal(const int num) { textFileDigitsRightOfDecimal = num; StringUtilities::setFloatDigitsRightOfDecimal(num); } /** * read a 3 byte integer from binary file. */ int AbstractFile::readThreeByteInteger(QDataStream& binStream) throw (FileException) { quint8 d[3]; binStream >> d[0] >> d[1] >> d[2]; int i[3] = { d[0], d[1], d[2] }; const int result = i[0] * 65536 + i[1] * 256 + i[2]; return result; } /** * set file postion for binary files for QT4 bug work around. */ void AbstractFile::setBinaryFilePosQT4Bug() throw (FileException) { if (getFileWriteType() == FILE_FORMAT_BINARY) { if (writingQFile != NULL) { if (writingQFile->isOpen()) { writingQFile->close(); if (writingQFile->open(QIODevice::Append) == false) { throw FileException(filename, "Unable to close and open file for appending\n" "to work around bugs in QT4 software."); } } } } } /** * find the binary data offset for QT4 bug work around (returns >= 0 if found). */ qint64 AbstractFile::findBinaryDataOffsetQT4Bug(QFile& file, const char* stringToFind) throw (FileException) { file.seek(0); QDataStream dataStream(&file); dataStream.setVersion(QDataStream::Qt_4_3); const int arraySize = 2048; char buffer[arraySize]; const int bufferLength = arraySize - 1; qint64 offset = 0; const qint64 fileSize = file.size() - 1; bool firstTime = true; while (firstTime || (offset < fileSize)) { firstTime = false; const qint64 numRead = dataStream.readRawData(buffer, bufferLength); if (numRead > 0) { buffer[bufferLength] = '\0'; const char* found = strstr(buffer, stringToFind); if (found != NULL) { const qint64 dataOffset = (qint64)(found - buffer) + offset + strlen(stringToFind); if (DebugControl::getDebugOn()) { std::cout << "Binary data offset is: " << dataOffset << std::endl; } return dataOffset; } else if (numRead >= bufferLength) { offset += bufferLength - strlen(stringToFind); file.seek(offset); } else { break; } } else { break; } } return -1; } caret-5.6.4~dfsg.1.orig/caret_files/.project0000664000175000017500000000470011572067322020511 0ustar michaelmichael caret_files org.eclipse.wst.common.project.facet.core.builder org.eclipse.cdt.managedbuilder.core.genmakebuilder clean,full,incremental, ?name? org.eclipse.cdt.make.core.append_environment true org.eclipse.cdt.make.core.autoBuildTarget all org.eclipse.cdt.make.core.buildArguments org.eclipse.cdt.make.core.buildCommand make org.eclipse.cdt.make.core.cleanBuildTarget clean org.eclipse.cdt.make.core.contents org.eclipse.cdt.make.core.activeConfigSettings org.eclipse.cdt.make.core.enableAutoBuild false org.eclipse.cdt.make.core.enableCleanBuild true org.eclipse.cdt.make.core.enableFullBuild true org.eclipse.cdt.make.core.fullBuildTarget all org.eclipse.cdt.make.core.stopOnError true org.eclipse.cdt.make.core.useDefaultBuildCmd true org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder org.eclipse.cdt.core.cnature org.eclipse.cdt.core.ccnature org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature org.eclipse.wst.common.project.facet.core.nature caret-5.6.4~dfsg.1.orig/caret_files/.cproject0000664000175000017500000002071511572067322020660 0ustar michaelmichael make all true true true caret-5.6.4~dfsg.1.orig/caret_edit/0000775000175000017500000000000011572067322016664 5ustar michaelmichaelcaret-5.6.4~dfsg.1.orig/caret_edit/main.cxx0000664000175000017500000000661511572067322020344 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include "BrainSet.h" #include "CaretVersion.h" #include "FileUtilities.h" #include "QtTextFileEditorDialog.h" #include "PreferencesFile.h" /*---------------------------------------------------------------------------------------- * Print help information. */ static void printHelp(const QString progNameIn) { const QString progName(progNameIn); std::cout << std::endl << "PROGRAM" << std::endl << " " << progName.toAscii().constData() << " v" << CaretVersion::getCaretVersionAsString().toAscii().constData() << " (" << __DATE__ << ")" << std::endl << std::endl << "SYNOPSIS" << std::endl << " " << progName.toAscii().constData() << " [-help] [name-of-file-to-edit]" << std::endl << "" << std::endl << "DESCRIPTION OF OPERATIONS" << std::endl << " Edit a text file. This program handles all types of" << std::endl << " platform dependent line feeds." << std::endl << "" << std::endl << " -help" << std::endl << " Display usage information about this program." << std::endl << "" << std::endl << " If \"name-of-file-to-edit\" is present, that file is " << std::endl << " automatically loaded into the editor. " << std::endl << "" << std::endl; } /*---------------------------------------------------------------------------------------- * The main function. */ int main(int argc, char* argv[]) { std::cout << std::endl; std::cout << "INFO: To see command line options, Run with \"-help\"" << std::endl; std::cout << std::endl; int fileIndex = -1; for (int i = 1; i < argc; i++) { QString arg(argv[i]); if (arg[0] != '-') { fileIndex = i; break; } else if (arg == "-help") { printHelp(argv[0]); return 0; } } QString defaultFileName; if (fileIndex > 0) { defaultFileName = argv[fileIndex]; } // // QT application // QApplication app(argc, argv, true); app.connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit())); // // Get the preferences file // BrainSet bs; PreferencesFile* pf = bs.getPreferencesFile(); // // Create the editor // QtTextFileEditorDialog* editor = new QtTextFileEditorDialog(0); //app.setMainWidget(editor); editor->setPreferencesFile(pf); editor->show(); if (defaultFileName.isEmpty() == false) { editor->loadFile(defaultFileName); } int result = app.exec(); return result; } caret-5.6.4~dfsg.1.orig/caret_edit/caret_edit.pro0000755000175000017500000001105311572067322021512 0ustar michaelmichael###################################################################### # Automatically generated by qmake (1.04a) Tue Jan 14 11:58:13 2003 ###################################################################### !vs:TEMPLATE = app vs:TEMPLATE=vcapp CONFIG += console INCLUDEPATH += . include(../caret_qmake_include.pro) win32 { !vs:!nmake { debug { LIBS += ..\caret_widgets\debug\libCaretWidgets.a \ ..\caret_brain_set\debug\libCaretBrainSet.a \ ..\caret_files\debug\libCaretFiles.a \ ..\caret_uniformize\debug\libCaretUniformize.a \ ..\caret_common\debug\libCaretCommon.a \ ..\caret_statistics\debug\libCaretStatistics.a } release { LIBS += ..\caret_widgets\release\libCaretWidgets.a \ ..\caret_brain_set\release\libCaretBrainSet.a \ ..\caret_files\release\libCaretFiles.a \ ..\caret_uniformize\release\libCaretUniformize.a \ ..\caret_common\release\libCaretCommon.a \ ..\caret_statistics\release\libCaretStatistics.a } } else { #else it's either vs or nmake CONFIG(debug,debug|release) { LIBS += ..\caret_common\debug\CaretCommon.lib \ ..\caret_command_operations\debug\CaretCommandOperations.lib \ ..\caret_brain_set\debug\CaretBrainSet.lib \ ..\caret_vtk4_classes\debug\CaretVtk4Classes.lib \ ..\caret_files\debug\CaretFiles.lib \ ..\caret_uniformize\debug\CaretUniformize.lib \ ..\caret_statistics\debug\CaretStatistics.lib \ ..\caret_widgets\debug\CaretWidgets.lib \ ..\caret_common\debug\CaretCommon.lib LIBS-=$$VTK_RELEASE_LIBS LIBS+=$$VTK_LIBS } CONFIG(release,debug|release) { LIBS += ..\caret_common\release\CaretCommon.lib \ ..\caret_command_operations\release\CaretCommandOperations.lib \ ..\caret_brain_set\release\CaretBrainSet.lib \ ..\caret_vtk4_classes\release\CaretVtk4Classes.lib \ ..\caret_files\release\CaretFiles.lib \ ..\caret_uniformize\release\CaretUniformize.lib \ ..\caret_statistics\release\CaretStatistics.lib \ ..\caret_widgets\release\CaretWidgets.lib \ ..\caret_common\release\CaretCommon.lib LIBS-=$$VTK_LIBS LIBS+=$$VTK_RELEASE_LIBS } } } win32 { CONFIG += console CONFIG -= windows } unix:!ubuntu { !dll { PRE_TARGETDEPS += \ ../caret_brain_set/libCaretBrainSet.a \ ../caret_files/libCaretFiles.a \ ../caret_uniformize/libCaretUniformize.a \ ../caret_statistics/libCaretStatistics.a \ ../caret_common/libCaretCommon.a \ ../caret_widgets/libCaretWidgets.a } dll { PRE_TARGETDEPS += \ ../caret_brain_set/libCaretBrainSet.so \ ../caret_files/libCaretFiles.so \ ../caret_uniformize/libCaretUniformize.so \ ../caret_statistics/libCaretStatistics.so \ ../caret_common/libCaretCommon.so \ ../caret_widgets/libCaretWidgets.so LIBS += -ldl } } macx { LIBS += -L../caret_widgets -lCaretWidgets \ -L../caret_brain_set -lCaretBrainSet \ -L../caret_files -lCaretFiles \ -L../caret_uniformize -lCaretUniformize \ -L../caret_common -lCaretCommon \ -L../caret_statistics -lCaretStatistics # # QMAKE_POST_LINK may have "strip" if release # so need semicolon between commands # # qt_menu.nib must be in resources or application will abort # !isEmpty( QMAKE_POST_LINK) { QMAKE_POST_LINK += ; } QMAKE_POST_LINK += cp -r $$(QTDIR)/src/gui/mac/qt_menu.nib ./caret_edit.app/Contents/Resources } unix:!macx { LIBS += -L../caret_command_operations -lCaretCommandOperations \ -L../caret_widgets -lCaretWidgets \ -L../caret_brain_set -lCaretBrainSet \ -L../caret_files -lCaretFiles \ -L../caret_uniformize -lCaretUniformize \ -L../caret_common -lCaretCommon \ -L../caret_statistics -lCaretStatistics # for SGI systems exists( /usr/lib/libgen.so ) { LIBS += -lgen -LD_LAYOUT:lgot_buffer=500 } } contains( DEFINES, HAVE_MINC ) { LIBS += $$NETCDF_LIBS } !vs:!nmake:LIBS += $$VTK_LIBS # Input #HEADERS += SOURCES += main.cxx caret-5.6.4~dfsg.1.orig/caret_edit/.project0000664000175000017500000000436711572067322020345 0ustar michaelmichael caret_edit org.eclipse.cdt.managedbuilder.core.genmakebuilder clean,full,incremental, ?name? org.eclipse.cdt.make.core.append_environment true org.eclipse.cdt.make.core.autoBuildTarget all org.eclipse.cdt.make.core.buildArguments org.eclipse.cdt.make.core.buildCommand make org.eclipse.cdt.make.core.cleanBuildTarget clean org.eclipse.cdt.make.core.contents org.eclipse.cdt.make.core.activeConfigSettings org.eclipse.cdt.make.core.enableAutoBuild false org.eclipse.cdt.make.core.enableCleanBuild true org.eclipse.cdt.make.core.enableFullBuild true org.eclipse.cdt.make.core.fullBuildTarget all org.eclipse.cdt.make.core.stopOnError true org.eclipse.cdt.make.core.useDefaultBuildCmd true org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder org.eclipse.cdt.core.cnature org.eclipse.cdt.core.ccnature org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature caret-5.6.4~dfsg.1.orig/caret_edit/.cproject0000664000175000017500000002072611572067322020505 0ustar michaelmichael make all true true true caret-5.6.4~dfsg.1.orig/caret_common/0000775000175000017500000000000011572067322017227 5ustar michaelmichaelcaret-5.6.4~dfsg.1.orig/caret_common/caret_common.pro0000664000175000017500000000361011572067322022417 0ustar michaelmichael###################################################################### # Automatically generated by qmake (1.04a) Wed Jan 15 08:28:52 2003 ###################################################################### TARGET = CaretCommon CONFIG += staticlib INCLUDEPATH += . include(../caret_qmake_include.pro) !vs:TEMPLATE = lib vs:TEMPLATE=vclib # turn off unicode for displaying windows web browser win32 { DEFINES -= UNICODE } #macx { # INCLUDEPATH += /System/Library/Frameworks//ApplicationServices.framework/Versions/A/Frameworks/SpeechSynthesis.framework/Versions/A/Headers #} dll { CONFIG -= staticlib CONFIG += plugin } # Input HEADERS += Basename.h \ CaretException.h \ CaretLinkedList.h \ CaretTips.h \ Category.h \ CommandLineUtilities.h \ DateAndTime.h \ DebugControl.h \ FileUtilities.h \ GaussianComputation.h \ HtmlColors.h \ HttpFileDownload.h \ MathUtilities.h \ NameIndexSort.h \ PointLocator.h \ ProgramParameters.h \ ProgramParametersException.h \ StatisticsUtilities.h \ StringTable.h \ Species.h \ StereotaxicSpace.h \ StringUtilities.h \ Structure.h \ SystemUtilities.h \ UbuntuMessage.h \ ValueIndexSort.h \ CaretVersion.h SOURCES += Basename.cxx \ CaretLinkedList.cxx \ CaretTips.cxx \ Category.cxx \ CommandLineUtilities.cxx \ DateAndTime.cxx \ DebugControl.cxx \ FileUtilities.cxx \ GaussianComputation.cxx \ HtmlColors.cxx \ HttpFileDownload.cxx \ MathUtilities.cxx \ NameIndexSort.cxx \ PointLocator.cxx \ ProgramParameters.cxx \ ProgramParametersException.cxx \ StatisticsUtilities.cxx \ StringTable.cxx \ Species.cxx \ StereotaxicSpace.cxx \ StringUtilities.cxx \ Structure.cxx \ SystemUtilities.cxx \ ValueIndexSort.cxx caret-5.6.4~dfsg.1.orig/caret_common/ValueIndexSort.h0000664000175000017500000000426611572067322022324 0ustar michaelmichael #ifndef __VALUE_INDEX_SORT_H__ #define __VALUE_INDEX_SORT_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include /// name and index sort class ValueIndexSort { protected: /// class for storing names and indices class ValueIndexPair { public: /// constructor ValueIndexPair(const int indexIn, const float valueIn); /// the value float value; /// the index int indx; /// less than operator bool operator<(const ValueIndexPair& vip) const; }; public: /// Constructor ValueIndexSort(); /// Constructor ~ValueIndexSort(); /// add an index value pair (must call sort() after all are added) void addValueIndexPair(const int indx, const float value); /// sort the items by value void sort(); /// get number of value index pairs int getNumberOfItems() const; /// get value and index for an item void getValueAndIndex(const int itemNum, int& indexOut, float& valueOut) const; protected: /// the value and indices std::vector values; }; #endif // __NAME_INDEX_SORT_H__ caret-5.6.4~dfsg.1.orig/caret_common/ValueIndexSort.cxx0000664000175000017500000000417611572067322022677 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "ValueIndexSort.h" /** * Constructor. */ ValueIndexSort::ValueIndexSort() { values.clear(); } /** * Constructor. */ ValueIndexSort::~ValueIndexSort() { } /** * add an index value pair (must call sort() when all added). */ void ValueIndexSort::addValueIndexPair(const int indx, const float value) { values.push_back(ValueIndexPair(indx, value)); } /** * sort the items (use if addValueIndexPair) was used. */ void ValueIndexSort::sort() { std::sort(values.begin(), values.end()); } /** * get number of value indice pairs. */ int ValueIndexSort::getNumberOfItems() const { return values.size(); } /** * get value and index for an item. */ void ValueIndexSort::getValueAndIndex(const int itemNum, int& indexOut, float& valueOut) const { indexOut = values[itemNum].indx; valueOut = values[itemNum].value; } /** * constructor. */ ValueIndexSort::ValueIndexPair::ValueIndexPair(const int indexIn, const float valueIn) { indx = indexIn; value = valueIn; } /** * less than operator. */ bool ValueIndexSort::ValueIndexPair::operator<(const ValueIndexPair& nip) const { return (value < nip.value); } caret-5.6.4~dfsg.1.orig/caret_common/UbuntuMessage.h0000664000175000017500000000342211572067322022170 0ustar michaelmichael#ifndef __UBUNTU_MESSAGE_H__ #define __UBUNTU_MESSAGE_H__ #include /** * Provides a warning message to Ubuntu users. */ class UbuntuMessage { public: static QString getWarningMessage() { QString s = "The official version of Caret software is produced by the " "Van Essen Laboratory at Washington University and is " "available from:\n" " http://brainvis.wustl.edu/wiki/index.php/Caret:About\n" "\n" "Only versions of Caret downloaded from the above web site " "are supported by the Van Essen Laboratory." "\n\n" "This version of Caret is an Ubuntu package and is neither " "distributed, nor supported, by the Van Essen Laboratory." "\n\n" "Some functionality may be missing if Caret cannot locate " "resources that are included in the official distribution. " "These functions include, but are not limited to: \n" " - Help Menu Documentation\n" " - Landmark Border Drawing\n" " - Map Volumes to Surface via PALS Atlas\n" " - Movie Making\n" " - Multi-Resolution Morphing\n" " - Projection of Foci via PALS Atlas\n" " - Surface-Based Registration\n" " - Surface Flattening\n" "\n" "The official Caret distribution contains specific versions " "of third party software known to function correctly with " "Caret. However, this Ubuntu version of Caret relies on " "separately installed Ubuntu packages that contain the third party " "software and these third party packages may not be " "compatible with Caret. As a result, some functions in Caret " "may not operate correctly. Faulty surface drawing is one " "symptom."; return s; } }; #endif // __UBUNTU_MESSAGE_H__caret-5.6.4~dfsg.1.orig/caret_common/SystemUtilities.h0000664000175000017500000000352411572067322022564 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_SYSTEM_UTILITIES_H__ #define __VE_SYSTEM_UTILITIES_H__ #include /// This class contains system independent version of system dependent functions class SystemUtilities { public: /// get the user's name static QString getUserName(); /// see if external program exists (can be executed - ie: in path) static bool externalProgramExists(const QString& programName); /// Get the number of processors on this computer. static int getNumberOfProcessors(); /// display a web page in the web browser (specifying web browser is optional). /// Returns non-zero if error. static int displayInWebBrowser(const QString& webPage, const QString& webBrowserPath = ""); /// sleep for the specified number of seconds static void sleepForSeconds(const int numberOfSeconds); }; #endif // __VE_SYSTEM_UTILITIES_H__ caret-5.6.4~dfsg.1.orig/caret_common/SystemUtilities.cxx0000664000175000017500000001506011572067322023135 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ /*========================================================================= Program: Visualization Toolkit Module: $RCSfile: SystemUtilities.cxx,v $ Language: C++ Date: $Date: 2009/04/09 15:47:56 $ Version: $Revision: 1.1.1.1 $ Copyright (c) 1993-2001 Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither name of Ken Martin, Will Schroeder, or Bill Lorensen nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. * Modified source versions must be plainly marked as such, and must not be misrepresented as being the original software. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =========================================================================*/ #include #include #include #include #include #include #ifdef Q_OS_WIN32 #include #else // Q_OS_WIN32 #include #include #include #endif // Q_OS_WIN32 #ifdef Q_OS_MACX #include #endif #include "SystemUtilities.h" /** * get the user's name. */ QString SystemUtilities::getUserName() { #ifdef Q_OS_WIN32 const QString name(getenv("USERNAME")); #else // Q_OS_WIN32 QString name(getlogin()); if (name.isEmpty()) { name = getenv("USERNAME"); } #endif // Q_OS_WIN32 return name; } /** * see if external program exists (can be executed - ie: in path). */ bool SystemUtilities::externalProgramExists(const QString& programName) { QProcess p; p.start(programName); p.waitForStarted(); p.waitForFinished(); QProcess::ProcessError error = p.error(); //QProcess::ExitStatus status = p.exitStatus(); const bool programValid = (error == QProcess::UnknownError); return programValid; } /** * Get the number of processors on this computer. * This code lifted from "vtkMultiThreader.h". */ int SystemUtilities::getNumberOfProcessors() { int numProcessors = 1; #ifdef Q_OS_WIN32 SYSTEM_INFO sysInfo; GetSystemInfo(&sysInfo); numProcessors = sysInfo.dwNumberOfProcessors; #endif // Q_OS_WIN32 #ifdef Q_OS_MACX numProcessors = MPProcessors(); #endif #ifdef Q_OS_UNIX #ifndef Q_OS_MACX #ifdef _SC_NPROCESSORS_ONLN numProcessors = sysconf(_SC_NPROCESSORS_ONLN); #elif defined(_SC_NPROC_ONLN) numProcessors = sysconf(_SC_NPROC_ONLN); #endif // _SC_NPROCESSORS_ONLN #endif // Q_OS_MACX #endif // Q_OS_UNIX return numProcessors; } /** * sleep for the specified number of seconds. */ void SystemUtilities::sleepForSeconds(const int numberOfSeconds) { #ifdef Q_OS_WIN32 SleepEx(numberOfSeconds * 1000, FALSE); #else // Q_OS_WIN32 sleep(numberOfSeconds); #endif // Q_OS_WIN32 } /// display a web page in the web browser (specifying web browser is optional). /// Returns non-zero if error. int SystemUtilities::displayInWebBrowser(const QString& webPage, const QString& webBrowserPath) { int result = -1; #ifdef Q_OS_WIN32 result = reinterpret_cast(ShellExecute( NULL, "open", webPage.toAscii().constData(), NULL, NULL, SW_SHOWNORMAL)); // // less than 32 is an error from ShellExecute // if (result > 32) { result = 0; } #endif #ifdef Q_OS_MAC // // Note: web page is placed in quotes so that "&" is not used as background // QString command(webBrowserPath); command = ""; // don't use webBrowserPath if (command.isEmpty()) { command = "open"; } command.append(" \""); command.append(webPage); command.append("\" &"); result = system(command.toAscii().constData()); #endif #ifdef Q_OS_UNIX #ifndef Q_OS_MAC QString command(webBrowserPath); if (command.isEmpty()) { const char* browser = getenv("CARET_WEB_BROWSER"); if (browser == NULL) { browser = getenv("BROWSER"); } if (browser != NULL) { command = browser; } else { command = "netscape"; } } // // Note: web page is placed in quotes so that "&" is not used as background // command.append(" \""); command.append(webPage); command.append("\" &"); result = system(command.toAscii().constData()); #endif #endif return result; } caret-5.6.4~dfsg.1.orig/caret_common/Structure.h0000664000175000017500000001564411572067322021412 0ustar michaelmichael #ifndef __STRUCTURE_H__ #define __STRUCTURE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include /// class for structure information class Structure { public: /// anatomical structure enum STRUCTURE_TYPE { /// left cerebral cortex STRUCTURE_TYPE_CORTEX_LEFT, /// right cerebral cortex STRUCTURE_TYPE_CORTEX_RIGHT, /// left and right cerebral cortex STRUCTURE_TYPE_CORTEX_BOTH, /// cerebrellum STRUCTURE_TYPE_CEREBELLUM, /// cerebral cortex or cerebellum STRUCTURE_TYPE_CEREBRUM_CEREBELLUM, /// cerebellum or left cerebral cortex (used with foci that could be associated with either) STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_LEFT, /// cerebellum or right cerebral cortex (used with foci that could be associated with either) STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_RIGHT, /// left cerebral cortex or cerebellum (used with foci that could be associated with either) STRUCTURE_TYPE_CORTEX_LEFT_OR_CEREBELLUM, /// right cerebral cortex or cerebellum (used with foci that could be associated with either) STRUCTURE_TYPE_CORTEX_RIGHT_OR_CEREBELLUM, /// subcortical STRUCTURE_TYPE_SUBCORTICAL, /// all structures STRUCTURE_TYPE_ALL, /// invalid STRUCTURE_TYPE_INVALID }; // constructor Structure(); // constructor Structure(const STRUCTURE_TYPE st); // constructor Structure(const QString& structureName); // operator equals bool operator==(const Structure& st) const; // operator not equals bool operator!=(const Structure& st) const; // destructor ~Structure(); // get the structure type STRUCTURE_TYPE getType() const; // get the structure type as a string QString getTypeAsString() const; // get the type as a one or two character string QString getTypeAsAbbreviatedString() const; // is left cortex structure bool isLeftCortex() const { return (structure == STRUCTURE_TYPE_CORTEX_LEFT); } // is right cortex structure bool isRightCortex() const { return (structure == STRUCTURE_TYPE_CORTEX_RIGHT); } // is both cortex structure bool isBothCortex() const { return (structure == STRUCTURE_TYPE_CORTEX_BOTH); } // is cerebellum structure bool isCerebellum() const { return (structure == STRUCTURE_TYPE_CEREBELLUM); } // is cerebellum or left cerebral structure bool isCerebellumOrLeftCerebral() const { return ((structure == STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_LEFT) || (structure == STRUCTURE_TYPE_CORTEX_LEFT_OR_CEREBELLUM)); } // is cerebellum or right cerebral structure bool isCerebellumOrRightCerebral() const { return ((structure == STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_RIGHT) || (structure == STRUCTURE_TYPE_CORTEX_RIGHT_OR_CEREBELLUM)); } // is invalid structure bool isInvalid() const { return (structure == STRUCTURE_TYPE_INVALID); } // is valid structure bool isValid() const { return (structure != STRUCTURE_TYPE_INVALID); } // set the structure type void setType(const STRUCTURE_TYPE st); // set the structure type from a string (returns true if valid) bool setTypeFromString(const QString& hts); // convert string to type static STRUCTURE_TYPE convertStringToType(const QString& s); // convert type to string static QString convertTypeToString(const STRUCTURE_TYPE ht); // convert type to abbreviated string static QString convertTypeToAbbreviatedString(const STRUCTURE_TYPE ht); /// get the string value for left cortex structure static QString getCortextLeftAsString() { return "left"; } /// get the string value for right cortex structure static QString getCortexRightAsString() { return "right"; } /// get the string value for cerebellum structure static QString getCerebellumAsString() { return "cerebellum"; } /// get the string value for cerebellum or left cerebral structure static QString getCerebellumOrLeftCerebralAsString() { return "cerebellum_or_left_cerebral"; } /// get the string value for cerebellum or right cerebral structure static QString getCerebellumOrRightCerebralAsString() { return "cerebellum_or_right_cerebral"; } /// get the string value for cerebellum or left cerebral structure static QString getLeftCerebralOrCerebellumAsString() { return "left_cerebral_or_cerebellum"; } /// get the string value for cerebellum or right cerebral structure static QString getRightCerebralOrCerebellumAsString() { return "right_cerebral_or_cerebellum"; } /// get the string value for both (right&left) cortex structure static QString getCortexBothAsString() { return "both"; } /// get the string for cerebrum and cerebellum static QString getCerebrumAndCerebellumAsString() { return "cerebrum_cerebellum"; } /// get the string for subcortical static QString getSubCorticalAsString() { return "subcortical"; } /// get the string for all structures static QString getAllAsString() { return "all"; } /// get the string value for invalid structure static QString getInvalidAsString() { return "invalid"; } /// get all structure types and names static void getAllTypesAndNames(std::vector& types, std::vector& names, const bool includeInvalid, const bool includeAmbiguousCerebralOrCerebellum = false); protected: /// the structure STRUCTURE_TYPE structure; }; #endif // __STRUCTURE_H__ caret-5.6.4~dfsg.1.orig/caret_common/Structure.cxx0000664000175000017500000002013511572067322021754 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "Structure.h" #include "StringUtilities.h" /** * constructor. */ Structure::Structure() { structure = STRUCTURE_TYPE_INVALID; } /** * constructor. */ Structure::Structure(const STRUCTURE_TYPE ht) { structure = ht; } /** * constructor. */ Structure::Structure(const QString& structureName) { structure = convertStringToType(structureName); } /** * destructor. */ Structure::~Structure() { } /** * operator equals. */ bool Structure::operator==(const Structure& st) const { return (structure == st.structure); } /** * operator not equals. */ bool Structure::operator!=(const Structure& st) const { return (structure != st.structure); } /** * get the structure type. */ Structure::STRUCTURE_TYPE Structure::getType() const { return structure; } /** * get the structure type as a string. */ QString Structure::getTypeAsString() const { return convertTypeToString(structure); } /** * get the structure type as a string. */ QString Structure::getTypeAsAbbreviatedString() const { return convertTypeToAbbreviatedString(structure); } /** * set the structure type. */ void Structure::setType(const STRUCTURE_TYPE st) { structure = st; } /** * set the structure type from a string (returns true if valid). */ bool Structure::setTypeFromString(const QString& hts) { structure = convertStringToType(hts); return (structure != STRUCTURE_TYPE_INVALID); } /** * convert string to type. */ Structure::STRUCTURE_TYPE Structure::convertStringToType(const QString& sin) { const QString s(StringUtilities::makeLowerCase(sin)); STRUCTURE_TYPE st = STRUCTURE_TYPE_INVALID; if (s == getInvalidAsString()) { st = STRUCTURE_TYPE_INVALID; } else if ((s == getCortextLeftAsString()) || (s == "left") || (s == "l")) { st = STRUCTURE_TYPE_CORTEX_LEFT; } else if ((s == getCortexRightAsString()) || (s == "right") || (s == "r")) { st = STRUCTURE_TYPE_CORTEX_RIGHT; } else if ((s == getCerebellumAsString()) || (s == "c")) { st = STRUCTURE_TYPE_CEREBELLUM; } else if ((s == getCortexBothAsString()) || (s == "b")) { st = STRUCTURE_TYPE_CORTEX_BOTH; } else if (s == getCerebrumAndCerebellumAsString()) { st = STRUCTURE_TYPE_CEREBRUM_CEREBELLUM; } else if (s == getCerebellumOrLeftCerebralAsString()) { st = STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_LEFT; } else if (s == getCerebellumOrRightCerebralAsString()) { st = STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_RIGHT; } else if (s == getLeftCerebralOrCerebellumAsString()) { st = STRUCTURE_TYPE_CORTEX_LEFT_OR_CEREBELLUM; } else if (s == getRightCerebralOrCerebellumAsString()) { st = STRUCTURE_TYPE_CORTEX_RIGHT_OR_CEREBELLUM; } else if (s == getSubCorticalAsString()) { st = STRUCTURE_TYPE_SUBCORTICAL; } else if (s == getAllAsString()) { st = STRUCTURE_TYPE_ALL; } return st; } /** * convert type to string. */ QString Structure::convertTypeToString(const STRUCTURE_TYPE st) { QString s(getInvalidAsString()); switch (st) { case STRUCTURE_TYPE_INVALID: s = getInvalidAsString(); break; case STRUCTURE_TYPE_CORTEX_LEFT: s = getCortextLeftAsString(); break; case STRUCTURE_TYPE_CORTEX_RIGHT: s = getCortexRightAsString(); break; case STRUCTURE_TYPE_CORTEX_BOTH: s = getCortexBothAsString(); break; case STRUCTURE_TYPE_CEREBELLUM: s = getCerebellumAsString(); break; case STRUCTURE_TYPE_CEREBRUM_CEREBELLUM: s = getCerebrumAndCerebellumAsString(); break; case STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_LEFT: s = getCerebellumOrLeftCerebralAsString(); break; case STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_RIGHT: s = getCerebellumOrRightCerebralAsString(); break; case STRUCTURE_TYPE_CORTEX_LEFT_OR_CEREBELLUM: s = getLeftCerebralOrCerebellumAsString(); break; case STRUCTURE_TYPE_CORTEX_RIGHT_OR_CEREBELLUM: s = getRightCerebralOrCerebellumAsString(); break; case STRUCTURE_TYPE_SUBCORTICAL: s = getSubCorticalAsString(); break; case STRUCTURE_TYPE_ALL: s = getAllAsString(); break; } return s; } /** * convert type to string. */ QString Structure::convertTypeToAbbreviatedString(const STRUCTURE_TYPE st) { QString s("U"); switch (st) { case STRUCTURE_TYPE_INVALID: s = "U"; break; case STRUCTURE_TYPE_CORTEX_LEFT: s = "L"; break; case STRUCTURE_TYPE_CORTEX_RIGHT: s = "R"; break; case STRUCTURE_TYPE_CORTEX_BOTH: s = "LR"; break; case STRUCTURE_TYPE_CEREBELLUM: s = "C"; break; case STRUCTURE_TYPE_CEREBRUM_CEREBELLUM: s = "CC"; break; case STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_LEFT: s = "CL"; break; case STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_RIGHT: s = "CR"; break; case STRUCTURE_TYPE_CORTEX_LEFT_OR_CEREBELLUM: s = "LC"; break; case STRUCTURE_TYPE_CORTEX_RIGHT_OR_CEREBELLUM: s = "RC"; break; case STRUCTURE_TYPE_SUBCORTICAL: s = "S"; break; case STRUCTURE_TYPE_ALL: s = "A"; break; } return s; } /** * get all structure types and names (does not include invalid type). */ void Structure::getAllTypesAndNames(std::vector& types, std::vector& names, const bool includeInvalid, const bool includeAmbiguousCerebralOrCerebellum) { types.clear(); names.clear(); types.push_back(STRUCTURE_TYPE_CEREBELLUM); names.push_back(getCerebellumAsString()); if (includeAmbiguousCerebralOrCerebellum) { types.push_back(STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_LEFT); names.push_back(getCerebellumOrLeftCerebralAsString()); types.push_back(STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_RIGHT); names.push_back(getCerebellumOrRightCerebralAsString()); } types.push_back(STRUCTURE_TYPE_CORTEX_LEFT); names.push_back(getCortextLeftAsString()); types.push_back(STRUCTURE_TYPE_CORTEX_BOTH); names.push_back(getCortexBothAsString()); types.push_back(STRUCTURE_TYPE_CORTEX_RIGHT); names.push_back(getCortexRightAsString()); types.push_back(STRUCTURE_TYPE_CEREBRUM_CEREBELLUM); names.push_back(getCerebrumAndCerebellumAsString()); if (includeAmbiguousCerebralOrCerebellum) { types.push_back(STRUCTURE_TYPE_CORTEX_LEFT_OR_CEREBELLUM); names.push_back(getLeftCerebralOrCerebellumAsString()); types.push_back(STRUCTURE_TYPE_CORTEX_RIGHT_OR_CEREBELLUM); names.push_back(getRightCerebralOrCerebellumAsString()); } types.push_back(STRUCTURE_TYPE_SUBCORTICAL); names.push_back(getSubCorticalAsString()); types.push_back(STRUCTURE_TYPE_ALL); names.push_back(getAllAsString()); if (includeInvalid) { types.push_back(STRUCTURE_TYPE_INVALID); names.push_back(getInvalidAsString()); } } caret-5.6.4~dfsg.1.orig/caret_common/StringUtilities.h0000664000175000017500000002147111572067322022547 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __STRING_UTILITIES_H__ #define __STRING_UTILITIES_H__ #include #include #include /// class contains static methods for handling C++ strings class StringUtilities { public: // sort elements case insensitive static void sortCaseInsensitive(std::vector& elements, const bool reverseOrderFlag, const bool removeDuplicatesFlag); // convert to a C++ standard string static std::string toStdString(const QString& qs); // convert from a C++ standard string static QString fromStdString(const std::string& ss); // replace occurances of string "findThis" in "s" with "replaceWith" static QString replace(const QString& s, const QString& findThis, const QString& replaceWith); // replace occurances of character "findThis" in "s" with "replaceWith" static QString replace(const QString& s, const char findThis, const char replaceWith); // split "s" into "tokens" splitting with any characters in "separators" static void token(const QString& s, const QString& separators, std::vector& tokens); // split "s" into "float tokens" splitting with any characters in "separators" static void token(const QString& s, const QString& separators, std::vector& tokenFloats); // split "s" into "double tokens" splitting with any characters in "separators" static void token(const QString& s, const QString& separators, std::vector& tokenDoubles); // split "s" into "int tokens" splitting with any characters in "separators" static void token(const QString& s, const QString& separators, std::vector& tokenInts); // split "s" into "bool tokens" splitting with any characters in "separators" static void token(const QString& s, const QString& separators, std::vector& tokenBools); // split "s" into tokens breaking at whitespace but maintaining string in double quotes static void tokenStringsWithQuotes(const QString& s, QStringList& stringsOut); // split "s" into "tokens" splitting with the literal string "separatorString" static void tokenSingleSeparator(const QString& stin, const QString& separatorString, std::vector& tokens); // combine "tokens" into a string delinated by "separators" static QString combine(const std::vector& tokens, const QString& separator); // combine "token floats" into a string delinated by "separators" static QString combine(const std::vector& tokenFloats, const QString& separator); // combine "token floats" into a string delinated by "separators" static QString combine(const float* tokenFloats, const int numFloats, const QString& separator); // combine "token doubles" into a string delinated by "separators" static QString combine(const std::vector& tokenDoubles, const QString& separator); // combine "token ints" into a string delinated by "separators" static QString combine(const std::vector& tokenInts, const QString& separator); // combine "token ints" into a string delinated by "separators" static QString combine(const int* tokenInts, const int numInts, const QString& separator); // combine "token bools" into a string delinated by "separators" static QString combine(const std::vector& tokenBools, const QString& separator); // determine if the string "s1" ends with the string "s2" static bool endsWith(const QString& s1, const QString& s2); // determine if the string "s1" starts with the string "s2" static bool startsWith(const QString& s1, const QString& s2); // return a string made lowercase static QString makeLowerCase(const QString& s); // return a string made uppercase static QString makeUpperCase(const QString& s); // setup a comment for storage (replace tabs with spaces, replace newlines with tabs) static QString setupCommentForStorage(const QString& stin); // setup a comment for display (replace tabs with newlines) static QString setupCommentForDisplay(const QString& stin); // trim the blanks and tabs from both ends of a string static QString trimWhitespace(const QString& stin); // right justify a string by prepending blanks to it so the // string contains "totalSize" characters. static QString rightJustify(const QString& s, const int totalSize); // left justify a string by adding blanks to it so the // string contains "totalSize" characters. static QString leftJustify(const QString& s, const int totalSize); // convert any URLs found in the string into an HTML hyperlink static QString convertURLsToHyperlinks(const QString& sIn); // convert a string to an unsigned byte static unsigned char toUnsignedByte(const QString& s); // convert a string to an unsigned byte static void toNumber(const QString& s, unsigned char& b); // convert a unsigned byte to a string static QString fromNumber(const unsigned char b); // convert a string to an integer static int toInt(const QString& s); // convert a string to an int static void toNumber(const QString& s, int& i); // convert an integer to a string static QString fromNumber(const int i); // Convert an string to a float. Handles "em" or "en" dash (various width dashes) static float toFloat(const QString& s); // convert a string to a float static void toNumber(const QString& s, float& f); // convert a float to a string static QString fromNumber(const float i); // Convert an string to a double. Handles "em" or "en" dash (various width dashes) static double toDouble(const QString& s); // convert a string to a double static void toNumber(const QString& s, double& d); // convert a double to a string static QString fromNumber(const double d); // convert a string to an bool static bool toBool(const QString& s); // convert an bool to a string static QString fromBool(const bool b); // get the white space characters static QString getWhiteSpaceCharacters(); // set the digits right of decimal for float/string conversions static void setFloatDigitsRightOfDecimal(const int numRightOfDecimal); // find the first of any of the characters in "lookForChars" static int findFirstOf(const QString& s, const QString& lookForChars, const int startPos = 0); // linewrap a string with no more than maxCharsPerLine static void lineWrapString(const int maxCharsPerLine, QString& s); protected: /// digits right of decimal for float/string conversions static int digitsRightOfDecimal; }; #ifdef __STRING_UTILITIES_MAIN_H__ int StringUtilities::digitsRightOfDecimal = 6; #endif // __STRING_UTILITIES_MAIN_H__ #endif // __STRING_UTILITIES_H__ caret-5.6.4~dfsg.1.orig/caret_common/StringUtilities.cxx0000664000175000017500000006057011572067322023125 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include "DebugControl.h" #define __STRING_UTILITIES_MAIN_H__ #include "StringUtilities.h" #undef __STRING_UTILITIES_MAIN_H__ /** * sort elements case insensitive. */ static bool lessThanCaseInsensitive(const QString& s1, const QString& s2) { return (QString::compare(s1, s2, Qt::CaseInsensitive) < 0); } static bool compareCaseInsensitive(const QString& s1, const QString& s2) { return (QString::compare(s1, s2, Qt::CaseInsensitive) == 0); } void StringUtilities::sortCaseInsensitive(std::vector& elements, const bool reverseOrderFlag, const bool removeDuplicatesFlag) { std::sort(elements.begin(), elements.end(), lessThanCaseInsensitive); if (removeDuplicatesFlag) { std::vector::iterator it = std::unique(elements.begin(), elements.end(), compareCaseInsensitive); if (it != elements.end()) { elements.resize(it - elements.begin()); } } if (reverseOrderFlag) { std::reverse(elements.begin(), elements.end()); } } /** * replace part of a string */ QString StringUtilities::replace(const QString& s, const QString& findThis, const QString& replaceWith) { QString str(s); const int findThisLength = findThis.length(); int pos = str.indexOf(findThis); while (pos != -1) { str.replace(pos, findThisLength, replaceWith); pos = str.indexOf(findThis); } return str; } /** * replace part of a string */ QString StringUtilities::replace(const QString& s, const char findThis, const char replaceWith) { QString str(s); for (int i = 0; i < str.length(); i++) { if (str[i] == findThis) { str[i] = replaceWith; } } return str; } /** * split "s" into tokens breaking at whitespace but maintaining string in double quotes. */ void StringUtilities::tokenStringsWithQuotes(const QString& s, QStringList& stringsOut) { stringsOut.clear(); bool done = false; int pos = 0; while (done == false) { const int quoteIndex = s.indexOf('\"', pos); if (quoteIndex >= 0) { // // Get stuff before double quote // const int startIndex = pos; const int endIndex = quoteIndex - 1; if (endIndex > startIndex) { const QString str = s.mid(startIndex, endIndex - startIndex + 1); stringsOut << str.split(QRegExp("\\s+"), QString::SkipEmptyParts); } // // Find next double quote // const int nextQuoteIndex = s.indexOf('\"', quoteIndex + 1); if (nextQuoteIndex >= 0) { // // Include doubled quotes // const int startIndex = quoteIndex; const int endIndex = nextQuoteIndex; if (endIndex > startIndex) { const QString str = s.mid(startIndex, endIndex - startIndex + 1); stringsOut << str; // DO NOT SPLIT ON WHITESPACE } // // Next character to search // pos = nextQuoteIndex + 1; } else { // // Did not find second double quote so gobble rest of string // and add double quote // const int startIndex = quoteIndex; QString str = s.mid(startIndex); if (str.isEmpty() == false) { str += '\"'; stringsOut << str; } done = true; } } else { // // Get rest of string split at white space // const QString str = s.mid(pos); if (str.isEmpty() == false) { stringsOut << str.split(QRegExp("\\s+"), QString::SkipEmptyParts); } done = true; } } if (DebugControl::getDebugOn()) { std::cout << "STRING IN: " << s.toAscii().constData() << std::endl; std::cout << "STRING SPLIT: " << std::endl; for (int i = 0; i < stringsOut.count(); i++) { std::cout << " [" << stringsOut.at(i).toAscii().constData() << "]" << std::endl; } } } /** * like strtok() function. * Split string "s" at any of the characters in "separators" and place each * piece in float tokens. */ void StringUtilities::token(const QString& s, const QString& separators, std::vector& tokenFloats) { std::vector tokens; token(s, separators, tokens); tokenFloats.clear(); for (unsigned int i = 0; i < tokens.size(); i++) { tokenFloats.push_back(toFloat(tokens[i])); } } /** * like strtok() function. * Split string "s" at any of the characters in "separators" and place each * piece in double tokens. */ void StringUtilities::token(const QString& s, const QString& separators, std::vector& tokenDoubles) { std::vector tokens; token(s, separators, tokens); tokenDoubles.clear(); for (unsigned int i = 0; i < tokens.size(); i++) { tokenDoubles.push_back(toDouble(tokens[i])); } } /** * like strtok() function. * Split string "s" at any of the characters in "separators" and place each * piece in int tokens. */ void StringUtilities::token(const QString& s, const QString& separators, std::vector& tokenInts) { std::vector tokens; token(s, separators, tokens); tokenInts.clear(); for (unsigned int i = 0; i < tokens.size(); i++) { tokenInts.push_back(toInt(tokens[i])); } } /** * split "s" into "bool tokens" splitting with any characters in "separators". */ void StringUtilities::token(const QString& s, const QString& separators, std::vector& tokenBools) { std::vector intBools; StringUtilities::token(s, separators, intBools); tokenBools.clear(); const int num = static_cast(intBools.size()); for (int i = 0; i < num; i++) { if (intBools[i] != 0) { tokenBools.push_back(1); } else { tokenBools.push_back(0); } } } /** * like strtok() function. * Split string "s" at any of the characters in "separators" and place each * piece in tokens. */ void StringUtilities::token(const QString& s, const QString& separators, std::vector& tokens) { tokens.clear(); int start = 0; for (int i = 0; i < (int)s.length(); i++) { for (int j = 0; j < (int)separators.length(); j++) { if (s[i] == separators[j]) { QString token = s.mid(start, i - start); if (token.length() > 0) { tokens.push_back(token); } start = i + 1; break; } } } QString token = s.mid(start); if (token.length() > 0) { tokens.push_back(token); } } /** * Split the string "stin" with the literal string "separatorString" and * return in "tokens". */ void StringUtilities::tokenSingleSeparator(const QString& stin, const QString& separatorString, std::vector& tokens) { tokens.clear(); QString s(stin); const int separatorLength = separatorString.length(); bool done = false; while (done == false) { const int pos = s.indexOf(separatorString); if (pos != -1) { const QString t(s.mid(0, pos)); if (t.isEmpty() == false) { tokens.push_back(t); } s = s.mid(pos + separatorLength); } else { done = true; } } if (s.isEmpty() == false) { tokens.push_back(s); } } /** * Combine all strings in "tokens" with "separator" between each pair */ QString StringUtilities::combine(const std::vector& tokens, const QString& separator) { QString s; for (unsigned int i = 0; i < tokens.size(); i++) { if (i > 0) { s.append(separator); } s.append(tokens[i]); } return s; } /* * Combine all floats in "tokens" with "separator" between each pair */ QString StringUtilities::combine(const std::vector& tokenFloats, const QString& separator) { QString s; for (unsigned int i = 0; i < tokenFloats.size(); i++) { if (i > 0) { s.append(separator); } s.append(fromNumber(tokenFloats[i])); } return s; } /* * Combine all floats in "tokens" with "separator" between each pair */ QString StringUtilities::combine(const float* tokenFloats, const int numFloats, const QString& separator) { QString s; for (int i = 0; i < numFloats; i++) { if (i > 0) { s.append(separator); } s.append(fromNumber(tokenFloats[i])); } return s; } /** * Combine all doubles in "tokens" with "separator" between each pair */ QString StringUtilities::combine(const std::vector& tokenDoubles, const QString& separator) { QString s; for (unsigned int i = 0; i < tokenDoubles.size(); i++) { if (i > 0) { s.append(separator); } s.append(fromNumber(tokenDoubles[i])); } return s; } /** * Combine all ints in "tokens" with "separator" between each pair */ QString StringUtilities::combine(const std::vector& tokenInts, const QString& separator) { QString s; for (unsigned int i = 0; i < tokenInts.size(); i++) { if (i > 0) { s.append(separator); } s.append(fromNumber(tokenInts[i])); } return s; } /** * Combine all ints in "tokens" with "separator" between each pair */ QString StringUtilities::combine(const int* tokenInts, const int numInts, const QString& separator) { QString s; for (int i = 0; i < numInts; i++) { if (i > 0) { s.append(separator); } s.append(fromNumber(tokenInts[i])); } return s; } /** * combine "token bools" into a string delinated by "separators". */ QString StringUtilities::combine(const std::vector& tokenBools, const QString& separator) { std::vector ints; const int num = static_cast(tokenBools.size()); for (int i = 0; i < num; i++) { if (tokenBools[i]) { ints.push_back(1); } else { ints.push_back(0); } } return StringUtilities::combine(ints, separator); } /** * make a string lower case */ QString StringUtilities::makeLowerCase(const QString& s) { return s.toLower(); /* QString s1(s); for (unsigned int i = 0; i < s1.length(); i++) { s1[i] = (char)tolower(s1[i]); } return s1; */ } /** * make a string upper case */ QString StringUtilities::makeUpperCase(const QString& s) { return s.toUpper(); /* QString s1(s); for (unsigned int i = 0; i < s1.length(); i++) { s1[i] = (char)toupper(s1[i]); } return s1; */ } /** * Convert a string for storage on a single line in a text file. */ QString StringUtilities::setupCommentForStorage(const QString& stin) { // NOTE: // unix ends lines with "\n" // mac ends lines with "\r" // dos ends lines with "\r\n". QString s = stin; const int num = static_cast(s.length()); for (int i = 0; i < num; i++) { if (s[i] == '\t') { s[i] = ' '; } else if (s[i] == '\r') { if (i < (num - 1)) { if (s[i+1] == '\n') { s[i] = ' '; // '\n' will get handled on next iteration } else { s[i] = '\t'; } } else { s[i] = '\t'; } } else if (s[i] == '\n') { s[i] = '\t'; } } return s; } /** * Convert a string saved for storage back to display representation. */ QString StringUtilities::setupCommentForDisplay(const QString& stin) { QString s(stin); const int num = static_cast(s.length()); for (int i = 0; i < num; i++) { if (s[i] == '\t') { s[i] = '\n'; } } return s; } /** * Determine if the string "s1" starts with the string "s2". */ bool StringUtilities::startsWith(const QString& s1, const QString& s2) { const int s1len = s1.length(); const int s2len = s2.length(); if (s1len < s2len) { return false; } return (s1.left(s2len) == s2); } /** * Determine if the string "s1" ends with the string "s2". */ bool StringUtilities::endsWith(const QString& s1, const QString& s2) { const int s1len = s1.length(); const int s2len = s2.length(); bool itDoes = false; if (s2len <= s1len) { QString sub = s1.right(s2len); if (sub == s2) { itDoes = true; } } return itDoes; } /** * Trim the blanks and tabs from both ends of a string. */ QString StringUtilities::trimWhitespace(const QString& stin) { if (stin.isEmpty()) { return stin; } return stin.trimmed(); /* QString s(stin); const int firstNonBlank = StringUtilities::findFirstOf(s, " \t"); if (firstNonBlank != -1) { s = s.mid(firstNonBlank); } else { s = ""; } const int lastNonBlank = s.find_last_not_of(" \t"); if (lastNonBlank != -1) { s.resize(lastNonBlank + 1); } return s; */ } /** * right justify a string by prepending blanks to it so the * string contains "totalSize" characters. */ QString StringUtilities::rightJustify(const QString& s, const int totalSize) { return s.rightJustified(totalSize); /* const int len = static_cast(s.length()); if (len < totalSize) { QString str; str.fill(totalSize - len, ' '); str.append(s); return str; } else { return s; } */ } /** * left justify a string by adding blanks to it so the * string contains "totalSize" characters. */ QString StringUtilities::leftJustify(const QString& s, const int totalSize) { return s.leftJustified(totalSize); /* const int len = static_cast(s.length()); if (len < totalSize) { QString s2; s2.fill(totalSize - len, ' '); QString str(s); str += s2; return str; } else { return s; } */ } /** * convert http URLs to hyperlinks. * "http://www.wustl.edu" becomes "http://wwww.wustl.edu" */ QString StringUtilities::convertURLsToHyperlinks(const QString& sIn) { std::vector url; std::vector urlStart; if (sIn.indexOf("http://") == -1) { return sIn; } else { // // Create a modifiable copy // QString 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 = StringUtilities::findFirstOf(s, " \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 QString 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 // QString trailingHyperLink("\">"); trailingHyperLink.append(url[i]); trailingHyperLink.append(""); s.insert(urlStart[i] + len, trailingHyperLink); // // Insert the beginning of the hyperlink // s.insert(urlStart[i], " (s.toInt()); } /** * convert a string to an unsigned byte. */ void StringUtilities::toNumber(const QString& s, unsigned char& b) { b = toUnsignedByte(s); } /** * convert a unsigned byte to a string. */ QString StringUtilities::fromNumber(const unsigned char b) { return QString::number(static_cast(b)); } /** * Convert an string to an integer. */ int StringUtilities::toInt(const QString& s) { return s.toInt(); } /** * convert a string to an int. */ void StringUtilities::toNumber(const QString& s, int& i) { i = toInt(s); } /** * Convert an integer to a string. */ QString StringUtilities::fromNumber(const int i) { return QString::number(i); } /** * Convert an string to a float. Handles "em" or "en" dash (various width dashes) */ float StringUtilities::toFloat(const QString& sin) { float f = 0.0; QString s = sin.trimmed(); if (s.isEmpty() == false) { QChar c = s[0]; // // Underscore // if (c == QChar('_')) { s[0] = '-'; } // // Some type of unicode "en-dash", "em-dash" -- unicode characters 8208 to 8213 // else if ((c.unicode() >= 0x2010) && // 0x2010 == 8208 variouse types of dashs (c.unicode() <= 0x2015)) { // 0x2015 == 8213 s[0] = '-'; } // // Check for a failure to convert to a floating point number // bool ok = true; f = s.toFloat(&ok); if (ok == false) { std::cout << "WARNING: Conversion of string to floating point number failed." << std::endl; std::cout << " ascii: " << s.toAscii().constData() << std::endl; std::cout << " unicode (hex): "; for (int i = 0; i < s.length(); i++) { std::cout << QString::number(s[i].unicode(), 16).toAscii().constData() << " "; } std::cout << std::endl << std::endl; } } return f; } /** * Convert an string to a double. Handles "em" or "en" dash (various width dashes) */ double StringUtilities::toDouble(const QString& sin) { double f = 0.0; QString s = sin.trimmed(); if (s.isEmpty() == false) { QChar c = s[0]; // // Underscore // if (c == QChar('_')) { s[0] = '-'; } // // Some type of unicode "en-dash", "em-dash" -- unicode characters 8208 to 8213 // else if ((c.unicode() >= 0x2010) && // 0x2010 == 8208 variouse types of dashs (c.unicode() <= 0x2015)) { // 0x2015 == 8213 s[0] = '-'; } // // Check for a failure to convert to a double precision floating point number // bool ok = true; f = s.toDouble(&ok); if (ok == false) { std::cout << "WARNING: Conversion of string to floating point number failed." << std::endl; std::cout << " ascii: " << s.toAscii().constData() << std::endl; std::cout << " unicode (hex): "; for (int i = 0; i < s.length(); i++) { std::cout << QString::number(s[i].unicode(), 16).toAscii().constData() << " "; } std::cout << std::endl << std::endl; } } return f; } /** * convert a string to a float. */ void StringUtilities::toNumber(const QString& s, float& f) { f = toFloat(s); } /** * Convert a float to a string. Remove extra zeros right of decimal place. */ QString StringUtilities::fromNumber(const float f) { QString s = QString::number(f, 'f', StringUtilities::digitsRightOfDecimal); int decimal = s.indexOf("."); int num = s.length() - 1; if (decimal >= 0) { decimal++; for (int i = num; i > decimal; i--) { if (s[i] == '0') { s[i] = ' '; } else { break; } } s = s.trimmed(); } return s; } /** * convert a string to a double. */ void StringUtilities::toNumber(const QString& s, double& d) { d = toDouble(s); } /** * Convert a double to a string. */ QString StringUtilities::fromNumber(const double f) { std::ostringstream str; str.setf(std::ios::fixed); str.precision(digitsRightOfDecimal); str << f; return str.str().c_str(); } /** * convert a string to an bool. */ bool StringUtilities::toBool(const QString& s) { if (s.isEmpty() == false) { if ((s[0] == 'T') || (s[0] == 't')) { return true; } } return false; } /** * convert an bool to a string. */ QString StringUtilities::fromBool(const bool b) { if (b) return "true"; else return "false"; } /** * get the white space characters. */ QString StringUtilities::getWhiteSpaceCharacters() { return "\n\r\t "; } /** * set the digits right of decimal for float/string conversions. */ void StringUtilities::setFloatDigitsRightOfDecimal(const int numRightOfDecimal) { digitsRightOfDecimal = numRightOfDecimal; } /** * find the first of any of the characters in "lookForChars". */ int StringUtilities::findFirstOf(const QString& s, const QString& lookForChars, const int startPos) { const int len = s.length(); const int len2 = lookForChars.length(); for (int i = startPos; i < len; i++) { for (int j = 0; j < len2; j++) { if (s[i] == lookForChars[j]) { return i; } } } return -1; } /** * linewrap a string with no more than maxCharsPerLine. */ void StringUtilities::lineWrapString(const int maxCharsPerLine, QString& s) { int iStart = 0; int cnt = 0; const int stringLength = s.length(); int pos = iStart + cnt; int lastSpace = -1; while (pos < stringLength) { if (s[pos] == ' ') { lastSpace = pos; } if (s[pos] == '\n') { iStart = iStart; } if (cnt >= maxCharsPerLine) { if (lastSpace >= 0) { s[lastSpace] = '\n'; iStart = lastSpace; cnt = 0; lastSpace = -1; } } cnt++; pos = iStart + cnt; } } /** * convert to a C++ standard string. */ std::string StringUtilities::toStdString(const QString& qs) { std::string ss; const int len = qs.length(); if (len <= 0) { ss = ""; } else { ss.resize(len); for (int i = 0; i < len; i++) { ss[i] = qs[i].toAscii(); } } return ss; } /** * convert from a C++ standard string. */ QString StringUtilities::fromStdString(const std::string& ss) { QString qs; const int len = ss.length(); if (len <= 0) { qs = ""; } else { qs.resize(len); for (int i = 0; i < len; i++) { qs[i] = ss[i]; } } return qs; } caret-5.6.4~dfsg.1.orig/caret_common/StringTable.h0000664000175000017500000001072311572067322021621 0ustar michaelmichael#ifndef __STRING_TABLE_H__ #define __STRING_TABLE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include /// class for storing a table of QString's class StringTable { public: // constructor StringTable(const int numRowsIn, const int numColumnsIn, const QString& tableTitleIn = ""); // destructor ~StringTable(); // clear the table void clear(); // add a row to the table void addRow(const std::vector& newRow); // get an element QString getElement(const int row, const int col) const; // get an element as an int int getElementAsInt(const int row, const int col) const; // get an element as a float float getElementAsFloat(const int row, const int col) const; // get an element as a double double getElementAsDouble(const int row, const int col) const; // get a point to an element const QString* getElementPointer(const int row, const int col) const; // set an element void setElement(const int row, const int col, const QString& s); // set an element void setElement(const int row, const int col, const int i); // set an element void setElement(const int row, const int col, const float f); // set an element void setElement(const int row, const int col, const double f); // set array element void setElement(const int row, const int col, const int i[], const int num); // set array element void setElement(const int row, const int col, const float f[], const int num); // get array element void getElement(const int row, const int col, int i[], const int num) const; // get array element void getElement(const int row, const int col, float f[], const int num) const; /// get a column title QString getColumnTitle(const int col) const { return columnTitles[col]; } /// get the index of a column with the specified title int getColumnIndexFromName(const QString& columnTitle) const; /// set a column title void setColumnTitle(const int col, const QString& s) { columnTitles[col] = s; } /// get the number of rows int getNumberOfRows() const { return numberOfRows; } /// get the number of columns int getNumberOfColumns() const { return numberOfCols; } // set the number of rows and columns void setNumberOfRowsAndColumns(const int numRows, const int numCols, const QString& tableTitleIn); // set max integer for column void setColumnMaxInteger(const int col, const int maxInt); /// get the table title QString getTableTitle() const { return tableTitle; } /// set the table title void setTableTitle(const QString& tt) { tableTitle = tt; } protected: /// compute an index to an element int getIndex(const int row, const int col) const { return (row * numberOfCols + col); } /// the string table std::vector stringTable; /// number of rows in the string table int numberOfRows; /// number of columns in the string table int numberOfCols; /// titles of columns QString* columnTitles; /// max number of integer digits in a column int* colMaxIntDigits; /// title of table QString tableTitle; }; #endif // __STRING_TABLE_H__ caret-5.6.4~dfsg.1.orig/caret_common/StringTable.cxx0000664000175000017500000001527111572067322022177 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "StringTable.h" #include "StringUtilities.h" /** * constructor. */ StringTable::StringTable(const int numRowsIn, const int numColsIn, const QString& tableTitleIn) { columnTitles = NULL; colMaxIntDigits = NULL; setNumberOfRowsAndColumns(numRowsIn, numColsIn, tableTitleIn); } /** * destructor. */ StringTable::~StringTable() { clear(); } /** * add a row to the table. */ void StringTable::addRow(const std::vector& newRow) { const int numElements = static_cast(newRow.size()); if (numElements > 0) { if (numberOfCols <= 0) { setNumberOfRowsAndColumns(1, numElements, ""); } else { stringTable.insert(stringTable.end(), numberOfCols, QString()); numberOfRows++; } } const int lastRow = numberOfRows -1; for (int i = 0; i < numberOfCols; i++) { if (i < numElements) { setElement(lastRow, i, newRow[i]); } } } /** * clear the table. */ void StringTable::clear() { stringTable.clear(); if (columnTitles != NULL) { delete[] columnTitles; columnTitles = NULL; } if (colMaxIntDigits != NULL) { delete[] colMaxIntDigits; colMaxIntDigits = NULL; } numberOfRows = 0; numberOfCols = 0; tableTitle = ""; } /** * set the number of rows and columns. */ void StringTable::setNumberOfRowsAndColumns(const int numRowsIn, const int numColsIn, const QString& tableTitleIn) { clear(); tableTitle = tableTitleIn; numberOfRows = numRowsIn; numberOfCols = numColsIn; const int numElements = numberOfRows * numberOfCols; if (numElements > 0) { stringTable.resize(numElements); } if (numberOfCols > 0) { columnTitles = new QString[numberOfCols]; colMaxIntDigits = new int[numberOfCols]; for (int i = 0; i < numberOfCols; i++) { colMaxIntDigits[i] = -1; } } } /** * get an element. */ QString StringTable::getElement(const int row, const int col) const { return stringTable[getIndex(row, col)]; } /** * get an element as an int. */ int StringTable::getElementAsInt(const int row, const int col) const { return getElement(row, col).toInt(); } /** * get an element as a float. */ float StringTable::getElementAsFloat(const int row, const int col) const { // // Watch for "en-dash", "em-dash" -- unicode characters 8208 to 8213 // so use the StringUtilities::toFloat() which will catch these problems // return StringUtilities::toFloat(getElement(row, col)); } /** * get an element as a double. */ double StringTable::getElementAsDouble(const int row, const int col) const { // // Watch for "en-dash", "em-dash" -- unicode characters 8208 to 8213 // so use the StringUtilities::toDouble() which will catch these problems // return StringUtilities::toDouble(getElement(row, col)); } /** * get a point to an element. */ const QString* StringTable::getElementPointer(const int row, const int col) const { return &stringTable[getIndex(row, col)]; } /** * set an element. */ void StringTable::setElement(const int row, const int col, const QString& s) { stringTable[getIndex(row, col)] = s; } /** * set an element. */ void StringTable::setElement(const int row, const int col, const int i) { QString s; s.setNum(i); if (colMaxIntDigits[col] > 0) { const int num = colMaxIntDigits[col] - s.length(); for (int j = 0; j < num; j++) { s.insert(0, '0'); } } stringTable[getIndex(row, col)] = s; } /** * set an element. */ void StringTable::setElement(const int row, const int col, const float f) { stringTable[getIndex(row, col)].setNum(f, 'f', 6); } /** * set an element. */ void StringTable::setElement(const int row, const int col, const double f) { stringTable[getIndex(row, col)].setNum(f, 'f', 24); } /** * Set max integer for column. Must be called before setElement(). * As the integers are converted to strings they are padded with zeros * so that they can be sorted correctly when sorted as text strings. */ void StringTable::setColumnMaxInteger(const int col, const int maxInt) { colMaxIntDigits[col] = static_cast(std::log10(static_cast(maxInt))) + 1; if (colMaxIntDigits[col] <= 0) { colMaxIntDigits[col] = 1; } } /** * set array element. */ void StringTable::setElement(const int row, const int col, const int i[], const int num) { QString s; for (int j = 0; j < num; j++) { s.append(QString::number(i[j]) + " "); } setElement(row, col, s); } /** * set array element. */ void StringTable::setElement(const int row, const int col, const float f[], const int num) { QString s; for (int j = 0; j < num; j++) { s.append(QString::number(f[j], 'f', 6) + " "); } setElement(row, col, s); } /** * get array element. */ void StringTable::getElement(const int row, const int col, int i[], const int num) const { QString s = getElement(row, col); QTextStream stream(&s, QIODevice::ReadOnly); for (int j = 0; j < num; j++) { stream >> i[j]; } } /** * get array element. */ void StringTable::getElement(const int row, const int col, float f[], const int num) const { QString s = getElement(row, col); QTextStream stream(&s, QIODevice::ReadOnly); for (int j = 0; j < num; j++) { stream >> f[j]; } } /** * get the index of a column with the specified title. */ int StringTable::getColumnIndexFromName(const QString& columnTitleIn) const { const QString columnTitle(columnTitleIn.toLower()); const int num = getNumberOfColumns(); for (int i = 0; i < num; i++) { if (columnTitle == getColumnTitle(i).toLower()) { return i; } } return -1; } caret-5.6.4~dfsg.1.orig/caret_common/StereotaxicSpace.h0000664000175000017500000001420311572067322022646 0ustar michaelmichael #ifndef __STEREOTAXIC_SPACE_H__ #define __STEREOTAXIC_SPACE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include /// class for storing a stereotaxic space class StereotaxicSpace { public: /// stereotaxic spaces available enum SPACE { /// 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, /// always last SPACE_NUMBER_OF_SPACES }; /// constructor StereotaxicSpace(const SPACE spaceIn); /// constructor space name StereotaxicSpace(const QString& nameIn); /// constructor StereotaxicSpace(); /// destructor ~StereotaxicSpace(); /// equality operator bool operator==(const StereotaxicSpace& ss) { return (space == ss.space); } /// equality operator bool operator!=(const StereotaxicSpace& ss) { return (space != ss.space); } /// reset void reset(); /// is a valid space (not unknown) bool isValid() const { return (space != SPACE_UNKNOWN); } /// get the space SPACE getSpace() const { return space; } /// get the name of the space QString getName() const { return name; } /// get the dimensions of the space void getDimensions(int dimensionsOut[3]) const; /// get the origin of the space void getOrigin(float originOut[3]) const; /// get the voxel size of the space void getVoxelSize(float voxelSizeOut[3]) const; /// get information about a stereotaxic space static StereotaxicSpace getStereotaxicSpace(const SPACE space); /// get information about a stereotaxic space static StereotaxicSpace getStereotaxicSpace(const QString& spaceName); /// get all stereotaxic spaces static void getAllStereotaxicSpaces(std::vector& allSpacesOut); /// get teh space from the name static QString cleanupSpaceName(const QString& name); /// get a space from its name static SPACE getSpaceFromName(const QString& name); /// is the name that of a valid stereotaxic space static bool validStereotaxicSpaceName(const QString& name); /// set data from space void setDataFromSpace(const SPACE spaceIn); /// set data from space name void setDataFromSpaceName(const QString& spaceNameIn); protected: /// constructor StereotaxicSpace(const QString& nameIn, const int dimensionsIn[3], const float originIn[3], const float voxelSizeIn[3]); /// set the space data void setData(const QString& nameIn, const int dimX, const int dimY, const int dimZ, const float voxSizeX, const float voxSizeY, const float voxSizeZ, const float originX, const float originY, const float originZ); /// the space SPACE space; /// name of the space QString name; /// dimensions of the space int dimensions[3]; /// origin of the spcae float origin[3]; /// voxel size of the space float voxelSize[3]; }; #endif // __STEREOTAXIC_SPACE_H__ caret-5.6.4~dfsg.1.orig/caret_common/StereotaxicSpace.cxx0000664000175000017500000003262311572067322023227 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "StereotaxicSpace.h" #include "StringUtilities.h" /** * constructor. */ StereotaxicSpace::StereotaxicSpace(const QString& nameIn, const int dimensionsIn[3], const float originIn[3], const float voxelSizeIn[3]) { reset(); name = nameIn; for (int i = 0; i < 3; i++) { dimensions[i] = dimensionsIn[i]; origin[i] = originIn[i]; voxelSize[i] = voxelSizeIn[i]; } } /** * constructor space name. */ StereotaxicSpace::StereotaxicSpace(const QString& nameIn) { reset(); setDataFromSpace(getSpaceFromName(nameIn)); } /** * constructor. */ StereotaxicSpace::StereotaxicSpace(const SPACE spaceIn) { reset(); setDataFromSpace(spaceIn); } /** * set data from space name. */ void StereotaxicSpace::setDataFromSpaceName(const QString& spaceNameIn) { setDataFromSpace(getSpaceFromName(spaceNameIn)); } /** * set data from space. */ void StereotaxicSpace::setDataFromSpace(const SPACE spaceIn) { space = spaceIn; setData("UNKNOWN", 0, 0, 0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0); // // NOTE ORIGINS ARE CORNER OF THE VOXEL // switch (space) { case SPACE_UNKNOWN: setData("UNKNOWN", 0, 0, 0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0); break; case SPACE_OTHER: setData("OTHER", 0, 0, 0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0); break; case SPACE_AFNI_TALAIRACH: setData("AFNI", 161, 191, 151, 1.0, 1.0, 1.0, -80.0, -110.0, -65.0); break; case SPACE_FLIRT: setData("FLIRT", 182, 217, 182, 1.0, 1.0, 1.0, -90.0, -126.0, -72.0); break; case SPACE_FLIRT_222: setData("FLIRT-222", 91, 109, 91, 2.0, 2.0, 2.0, -90.0, -126.0, -72.0); break; case SPACE_MACAQUE_F99: setData("MACAQUE-F99", 143, 187, 118, 0.5, 0.5, 0.5, -35.75, -54.75, -30.25); break; case SPACE_MACAQUE_F6: setData("MACAQUE-F6", 143, 187, 118, 0.5, 0.5, 0.5, -35.75, -54.75, -30.25); break; case SPACE_MRITOTAL: setData("MRITOTAL", 182, 217, 182, 1.0, 1.0, 1.0, -90.0, -126.0, -72.0); break; case SPACE_SPM: setData("SPM", 182, 217, 182, 1.0, 1.0, 1.0, -90.0, -126.0, -72.0); break; case SPACE_SPM_95: setData("SPM95", 182, 217, 182, 1.0, 1.0, 1.0, -90.0, -126.0, -72.0); break; case SPACE_SPM_96: setData("SPM96", 182, 217, 182, 1.0, 1.0, 1.0, -90.0, -126.0, -72.0); break; case SPACE_SPM_99: setData("SPM99", 182, 217, 182, 1.0, 1.0, 1.0, -90.0, -126.0, -72.0); break; case SPACE_SPM_2: setData("SPM2", 182, 217, 182, 1.0, 1.0, 1.0, -90.0, -126.0, -72.0); break; case SPACE_SPM_5: setData("SPM5", 182, 217, 182, 1.0, 1.0, 1.0, -90.0, -126.0, -72.0); break; case SPACE_T88: setData("T88", 161, 191, 151, 1.0, 1.0, 1.0, -80.0, -110.0, -65.0); break; case SPACE_WU_7112B: setData("711-2B", 176, 208, 176, 1.0, 1.0, 1.0, -88.5, -123.5, -75.5); //-89.0, -124.0, -75.0); //-88.0, -122.0, -73.0); break; case SPACE_WU_7112B_111: setData("711-2B-111", 176, 208, 176, 1.0, 1.0, 1.0, -88.5, -123.5, -75.5); //-89.0, -124.0, -75.0); //-88.0, -122.0, -73.0); break; case SPACE_WU_7112B_222: setData("711-2B-222", 128, 128, 75, 2.0, 2.0, 2.0, -128, -128, -69); //-129.0, -129.0, -68.0); break; case SPACE_WU_7112B_333: setData("711-2B-333", 48, 64, 48, 3.0, 3.0, 3.0, -72.0, -106.5, -61.5); //-73.5, -108.0, -60.0); break; case SPACE_WU_7112C: setData("711-2C", 176, 208, 176, 1.0, 1.0, 1.0, -88.5, -123.5, -75.5); //-89.0, -124.0, -75.0); //-88.0, -122.0, -73.0); break; case SPACE_WU_7112C_111: setData("711-2C-111", 176, 208, 176, 1.0, 1.0, 1.0, -88.5, -123.5, -75.5); //-89.0, -124.0, -75.0); //-89.0, -122.0, -73.0); break; case SPACE_WU_7112C_222: setData("711-2C-222", 128, 128, 75, 2.0, 2.0, 2.0, -128, -128, -69); //-129.0, -129.0, -68.0); break; case SPACE_WU_7112C_333: setData("711-2C-333", 48, 64, 48, 3.0, 3.0, 3.0, -72.0, -106.5, -61.5); //-73.5, -108.0, -60.0); break; case SPACE_WU_7112O: setData("711-2O", 176, 208, 176, 1.0, 1.0, 1.0, -88.5, -123.5, -75.5); //-89.0, -124.0, -75.0); //-89.0, -124.0, -75.0); break; case SPACE_WU_7112O_111: setData("711-2O-111", 176, 208, 176, 1.0, 1.0, 1.0, -88.5, -123.5, -75.5); //-89.0, -124.0, -75.0); //-89.0, -124.0, -75.0); break; case SPACE_WU_7112O_222: setData("711-2O-222", 128, 128, 75, 2.0, 2.0, 2.0, -128, -128, -69); //-129.0, -129.0, -68.0); break; case SPACE_WU_7112O_333: setData("711-2O-333", 48, 64, 48, 3.0, 3.0, 3.0, -72.0, -106.5, -61.5); //-73.5, -108.0, -60.0); break; case SPACE_WU_7112Y: setData("711-2Y", 176, 208, 176, 1.0, 1.0, 1.0, -88.5, -123.5, -75.5); //-89.0, -124.0, -75.0); //-88.0, -122.0, -73.0); break; case SPACE_WU_7112Y_111: setData("711-2Y-111", 176, 208, 176, 1.0, 1.0, 1.0, -88.5, -123.5, -75.5); //-89.0, -124.0, -75.0); //-88.0, -122.0, -73.0); break; case SPACE_WU_7112Y_222: setData("711-2Y-222", 128, 128, 75, 2.0, 2.0, 2.0, -128, -128, -69); //-129.0, -129.0, -68.0); break; case SPACE_WU_7112Y_333: setData("711-2Y-333", 48, 64, 48, 3.0, 3.0, 3.0, -72.0, -106.5, -61.5); //-73.5, -108.0, -60.0); break; case SPACE_NUMBER_OF_SPACES: setData("UNKNOWN", 0, 0, 0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0); break; } } /** * constructor. */ void StereotaxicSpace::setData(const QString& nameIn, const int dimX, const int dimY, const int dimZ, const float voxSizeX, const float voxSizeY, const float voxSizeZ, const float originX, const float originY, const float originZ) { name = nameIn; dimensions[0] = dimX; dimensions[1] = dimY; dimensions[2] = dimZ; origin[0] = originX + (voxSizeX * 0.5); origin[1] = originY + (voxSizeY * 0.5); origin[2] = originZ + (voxSizeZ * 0.5); voxelSize[0] = voxSizeX; voxelSize[1] = voxSizeY; voxelSize[2] = voxSizeZ; } /** * constructor. */ StereotaxicSpace::StereotaxicSpace() { reset(); } /** * destructor. */ StereotaxicSpace::~StereotaxicSpace() { } /** * reset. */ void StereotaxicSpace::reset() { space = SPACE_UNKNOWN; name = ""; dimensions[0] = 0; dimensions[1] = 0; dimensions[2] = 0; origin[0] = 0.0; origin[1] = 0.0; origin[2] = 0.0; voxelSize[0] = 0.0; voxelSize[1] = 0.0; voxelSize[2] = 0.0; } /** * get the dimensions of the space. */ void StereotaxicSpace::getDimensions(int dimensionsOut[3]) const { for (int i = 0; i < 3; i++) { dimensionsOut[i] = dimensions[i]; } } /** * get the origin of the space. */ void StereotaxicSpace::getOrigin(float originOut[3]) const { for (int i = 0; i < 3; i++) { originOut[i] = origin[i]; } } /** * get the voxel size of the space. */ void StereotaxicSpace::getVoxelSize(float voxelSizeOut[3]) const { for (int i = 0; i < 3; i++) { voxelSizeOut[i] = voxelSize[i]; } } /** * get information about a stereotaxic space. */ StereotaxicSpace StereotaxicSpace::getStereotaxicSpace(const SPACE space) { StereotaxicSpace ss(space); return ss; } /** * get teh space from the name. */ QString StereotaxicSpace::cleanupSpaceName(const QString& spaceNameIn) { QString spaceName(spaceNameIn.toUpper()); if (spaceName == "7112B") { spaceName = "711-2B"; } else if(spaceName == "7112C") { spaceName = "711-2C"; } else if(spaceName == "7112O") { spaceName = "711-2O"; } else if(spaceName == "7112Y") { spaceName = "711-2Y"; } else if (spaceName == "MACAQUE") { spaceName = "MACAQUE-F99"; } //else if (spaceName.left(5) == "711-2") { // spaceName == "711-2B-111"; //} else if (spaceName == "SPM_DEFAULT") { spaceName = "SPM99"; } else if (spaceName == "SPM_TEMPLATE") { spaceName = "SPM99"; } return spaceName; } /** * get a space from its name. */ StereotaxicSpace::SPACE StereotaxicSpace::getSpaceFromName(const QString& name) { return getStereotaxicSpace(name).getSpace(); } /** * get information about a stereotaxic space. * Returns the space SPACE_NON_STANDARD_OR_UNKNOWN if name is not recognized. */ StereotaxicSpace StereotaxicSpace::getStereotaxicSpace(const QString& spaceNameIn) { const QString spaceName = cleanupSpaceName(spaceNameIn); for (int i = 0; i < SPACE_NUMBER_OF_SPACES; i++) { StereotaxicSpace ss = getStereotaxicSpace(static_cast(i)); if (ss.getName() == StringUtilities::makeUpperCase(spaceName)) { return ss; } } return getStereotaxicSpace(SPACE_UNKNOWN); } /** * is the name that of a valid stereotaxic space. */ bool StereotaxicSpace::validStereotaxicSpaceName(const QString& name) { StereotaxicSpace ss = getStereotaxicSpace(name); return (ss.getSpace() != SPACE_UNKNOWN); } /** * get all stereotaxic spaces. */ void StereotaxicSpace::getAllStereotaxicSpaces(std::vector& allSpacesOut) { allSpacesOut.clear(); for (int i = 0; i < SPACE_NUMBER_OF_SPACES; i++) { allSpacesOut.push_back(getStereotaxicSpace(static_cast(i))); } } caret-5.6.4~dfsg.1.orig/caret_common/StatisticsUtilities.h0000664000175000017500000001217011572067322023427 0ustar michaelmichael #ifndef __STATISTICS_UTILITIES_H__ #define __STATISTICS_UTILITIES_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include /// This class contains static methods for performing statisical computations class StatisticsUtilities { public: /// class for holding statistics results class DescriptiveStatistics { public: /// Constructor DescriptiveStatistics(); /// Destructor ~DescriptiveStatistics(); /// reset all members void reset(); /// average of values float average; /// standard deviation of values float standardDeviation; /// standard error (dev / sqrt(num - 1)) float standardError; /// most positive value float mostPositiveValue; /// least positive value float leastPositiveValue; /// most negative value float mostNegativeValue; /// least negative value float leastNegativeValue; /// average of absolute values float absAverage; /// standard deviation of absolute values float absStandardDeviation; /// standard error (dev / sqrt(num - 1)) of absolute values float absStandardError; /// minimum value float minValue; /// maximum value float maxValue; /// range of values float range; /// median value float median; /// median of absolute values float absMedian; /// average of values with top and bottom 2% excluded float average96; /// standard deviation of values with top and bottom 2% excluded float standardDeviation96; /// standard error (dev / sqrt(num - 1)) with top and bottom 2% excluded float standardError96; /// most positive value float mostPositiveValue96; /// least positive value float leastPositiveValue96; /// most negative value float mostNegativeValue96; /// least negative value float leastNegativeValue96; /// average of absolute values with top and bottom 2% excluded float absAverage96; /// standard deviation of absolute values with top and bottom 2% excluded float absStandardDeviation96; /// standard error (dev / sqrt(num - 1)) of absolute valueswith top and bottom 2% excluded float absStandardError96; /// minimum value with top and bottom 2% excluded float minValue96; /// maximum value with top and bottom 2% excluded float maxValue96; /// range of values with top and bottom 2% excluded float range96; /// median value with top and bottom 2% excluded float median96; /// median of absolute values with top and bottom 2% excluded float absMedian96; /// the "96%" values (top and bottom 2% excluded) std::vector values96Percent; }; // determine statistics for a set of values static void computeStatistics(const std::vector& valuesIn, const bool dataIsSampleFlag, DescriptiveStatistics& statisticsOut); protected: // compute statistics helper static void computeStatisticsHelper(const std::vector& valuesIn, const bool do96Percent, const bool dataIsSampleFlag, DescriptiveStatistics& statisticsOut); }; #endif // __STATISTICS_UTILITIES_H__ caret-5.6.4~dfsg.1.orig/caret_common/StatisticsUtilities.cxx0000664000175000017500000002207211572067322024004 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ /***************************************************************************** Major portions of this software are copyrighted by the Medical College of Wisconsin, 1994-2000, and are released under the Gnu General Public License, Version 2. See the file README.Copyright for details. The tStatisticToPValue method and related code is from AFNI ******************************************************************************/ #include #include #include #include #include #include "DebugControl.h" #include "StatisticsUtilities.h" #include "ValueIndexSort.h" /** * Compute statistics for a set of values. * If "dataIsSampleFlag" is true, the data is assumed to be a sample where the true * mean is unknown and so the deviation is computed by dividing by "N - 1". If * "dataIsSampleFlag" is false, then the data is assumed to be the total population * so that the true mean is known and the deviation is computed by dividing by "N". */ void StatisticsUtilities::computeStatistics(const std::vector& valuesIn, const bool dataIsSampleFlag, DescriptiveStatistics& statisticsOut) { statisticsOut.reset(); const int numValues = static_cast(valuesIn.size()); if (numValues == 0) { return; } // // Sort input values // std::vector valuesSorted = valuesIn; std::sort(valuesSorted.begin(), valuesSorted.end()); // // Compute statistics for all values // computeStatisticsHelper(valuesSorted, false, dataIsSampleFlag, statisticsOut); // // Throw out top and bottom 2% // const int percent2 = std::min(static_cast(valuesSorted.size() * 0.02), numValues); const int percent98 = std::min(static_cast(valuesSorted.size() * 0.98), numValues); for (int i = percent2; i < percent98; i++) { statisticsOut.values96Percent.push_back(valuesSorted[i]); } // // Compute statistics with the top and bottom 2% excluded // computeStatisticsHelper(statisticsOut.values96Percent, true, dataIsSampleFlag, statisticsOut); } /** * compute statistics helper */ void StatisticsUtilities::computeStatisticsHelper(const std::vector& values, const bool do96Percent, const bool dataIsSampleFlag, DescriptiveStatistics& statisticsOut) { const int num = static_cast(values.size()); if (num == 0) { return; } // // Compute average and averages of absolute values. // float smallNumber = 0.0000000001; double sum = 0.0; double absSum = 0.0; double mostPositiveValue = 0; double leastPositiveValue = std::numeric_limits::max(); double mostNegativeValue = 0; double leastNegativeValue = -std::numeric_limits::max(); bool hadPositiveValues = false; bool hadNegativeValues = false; std::vector valuesForAbsMedian; for (int i = 0; i < num; i++) { float v = values[i]; sum += v; if (v > smallNumber) { hadPositiveValues = true; if (v > mostPositiveValue) { mostPositiveValue = v; } if (v < leastPositiveValue) { leastPositiveValue = v; } } else if (v < -smallNumber) { hadNegativeValues = true; if (v < mostNegativeValue) { mostNegativeValue = v; } if (v > leastNegativeValue) { leastNegativeValue = v; } } if (v < 0.0) v = -v; absSum += v; valuesForAbsMedian.push_back(v); } const double numValues = static_cast(num); const float average = sum / static_cast(numValues); const float absAverage = absSum / static_cast(numValues); if (hadPositiveValues == false) { mostPositiveValue = 0.0; leastPositiveValue = 0.0; } if (hadNegativeValues == false) { mostNegativeValue = 0.0; leastNegativeValue = 0.0; } // // Compute Standard Deviation and standard deviation of absolute values. // sum = 0.0; absSum = 0.0; for (int i = 0; i < num; i++) { double v = values[i]; double diff = v - average; sum += diff * diff; if (v < 0.0) v = -v; diff = v - absAverage; absSum += diff * diff; } double devNumValues = numValues; if (dataIsSampleFlag) { devNumValues = numValues - 1.0; } if (devNumValues <= 0.0) { devNumValues = 1.0; } const float standardDeviation = std::sqrt(sum / devNumValues); const float standardError = standardDeviation / std::sqrt(numValues); const float absStandardDeviation = std::sqrt(absSum / devNumValues); const float absStandardError = absStandardDeviation / std::sqrt(numValues); const float minValue = values[0]; const float maxValue = values[num-1]; const float range = maxValue - minValue; const int medianIndex = num / 2; const float median = values[medianIndex]; const float absMedian = valuesForAbsMedian[medianIndex]; if (do96Percent) { statisticsOut.average96 = average; statisticsOut.absAverage96 = absAverage; statisticsOut.standardDeviation96 = standardDeviation; statisticsOut.standardError96 = standardError; statisticsOut.absStandardDeviation96 = absStandardDeviation; statisticsOut.absStandardError96 = absStandardError; statisticsOut.mostPositiveValue96 = mostPositiveValue; statisticsOut.leastPositiveValue96 = leastPositiveValue; statisticsOut.mostNegativeValue96 = mostNegativeValue; statisticsOut.leastNegativeValue96 = leastNegativeValue; statisticsOut.minValue96 = minValue; statisticsOut.maxValue96 = maxValue; statisticsOut.range96 = range; statisticsOut.median96 = median; statisticsOut.absMedian96 = absMedian; } else { statisticsOut.average = average; statisticsOut.absAverage = absAverage; statisticsOut.standardDeviation = standardDeviation; statisticsOut.standardError = standardError; statisticsOut.absStandardDeviation = absStandardDeviation; statisticsOut.absStandardError = absStandardError; statisticsOut.mostPositiveValue = mostPositiveValue; statisticsOut.leastPositiveValue = leastPositiveValue; statisticsOut.mostNegativeValue = mostNegativeValue; statisticsOut.leastNegativeValue = leastNegativeValue; statisticsOut.minValue = minValue; statisticsOut.maxValue = maxValue; statisticsOut.range = range; statisticsOut.median = median; statisticsOut.absMedian = absMedian; } } //**************************************************************************************** // // DescriptiveStatistics methods // //**************************************************************************************** /** * Constructor. */ StatisticsUtilities::DescriptiveStatistics::DescriptiveStatistics() { reset(); } /** * Destructor. */ StatisticsUtilities::DescriptiveStatistics::~DescriptiveStatistics() { } /** * reset all members. */ void StatisticsUtilities::DescriptiveStatistics::reset() { average = 0.0; standardDeviation = 0.0; standardError = 0.0; absAverage = 0.0; absStandardDeviation = 0.0; absStandardError = 0.0; minValue = 0.0; maxValue = 0.0; range = 0.0; mostPositiveValue = 0.0; leastPositiveValue = 0.0; mostNegativeValue = 0.0; leastNegativeValue = 0.0; median = 0.0; absMedian = 0.0; average96 = 0.0; standardDeviation96 = 0.0; standardError96 = 0.0; absAverage96 = 0.0; absStandardDeviation96 = 0.0; absStandardError96 = 0.0; minValue96 = 0.0; maxValue96 = 0.0; mostPositiveValue96 = 0.0; leastPositiveValue96 = 0.0; mostNegativeValue96 = 0.0; leastNegativeValue96 = 0.0; range96 = 0.0; median96 = 0.0; absMedian96 = 0.0; values96Percent.clear(); } caret-5.6.4~dfsg.1.orig/caret_common/Species.h0000664000175000017500000000555711572067322021007 0ustar michaelmichael #ifndef __SPECIES_H__ #define __SPECIES_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include /// defines valid species class Species { public: /// type of species enum TYPE { /// 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 }; // get a list of valid species types and names static void getAllSpeciesTypesAndNames(std::vector& speciesTypesOut, std::vector& speciesNamesOut); // constructor Species(); // constructor Species(const TYPE t); // constructor Species(const QString& name); // destructor ~Species(); /// equality operator bool operator==(const Species& ss) { return (type == ss.type); } /// inequality operator bool operator!=(const Species& ss) { return (type != ss.type); } // reset void reset(); // get species name QString getName() const; /// get the species type TYPE getType() const { return type; } // set the species using type void setUsingType(const TYPE typeIn); // set the species using name void setUsingName(const QString& nameIn); // is human bool isHuman() const { return type == TYPE_HUMAN; } // is valid (not unknown) bool isValid() const { return type != TYPE_UNKNOWN; } protected: /// the species type TYPE type; }; #endif // __SPECIES_H__ caret-5.6.4~dfsg.1.orig/caret_common/Species.cxx0000664000175000017500000000717511572067322021360 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "Species.h" /** * get a list of valid species types and names. */ void Species::getAllSpeciesTypesAndNames(std::vector& speciesTypesOut, std::vector& speciesNamesOut) { speciesTypesOut.clear(); speciesNamesOut.clear(); speciesTypesOut.push_back(TYPE_UNKNOWN); speciesNamesOut.push_back("Unknown"); speciesTypesOut.push_back(TYPE_BABOON); speciesNamesOut.push_back("Baboon"); speciesTypesOut.push_back(TYPE_CHIMPANZEE); speciesNamesOut.push_back("Chimpanzee"); speciesTypesOut.push_back(TYPE_FERRET); speciesNamesOut.push_back("Ferret"); speciesTypesOut.push_back(TYPE_GALAGO); speciesNamesOut.push_back("Galago"); speciesTypesOut.push_back(TYPE_GIBBON); speciesNamesOut.push_back("Gibbon"); speciesTypesOut.push_back(TYPE_GORILLA); speciesNamesOut.push_back("Gorilla"); speciesTypesOut.push_back(TYPE_HUMAN); speciesNamesOut.push_back("Human"); speciesTypesOut.push_back(TYPE_MACAQUE); speciesNamesOut.push_back("Macaque"); speciesTypesOut.push_back(TYPE_MOUSE); speciesNamesOut.push_back("Mouse"); speciesTypesOut.push_back(TYPE_ORANGUTAN); speciesNamesOut.push_back("Orangutan"); speciesTypesOut.push_back(TYPE_RAT); speciesNamesOut.push_back("Rat"); speciesTypesOut.push_back(TYPE_OTHER); speciesNamesOut.push_back("Other"); } /** * constructor. */ Species::Species() { reset(); } /** * constructor. */ Species::Species(const TYPE t) { reset(); setUsingType(t); } /** * constructor. */ Species::Species(const QString& name) { reset(); setUsingName(name); } /** * destructor. */ Species::~Species() { } /** * reset. */ void Species::reset() { type = TYPE_UNKNOWN; } /** * get species name. */ QString Species::getName() const { std::vector speciesTypes; std::vector speciesNames; getAllSpeciesTypesAndNames(speciesTypes, speciesNames); QString name("Unknown"); const int num = static_cast(speciesTypes.size()); for (int i = 0; i < num; i++) { if (type == speciesTypes[i]) { name = speciesNames[i]; break; } } return name; } /** * set the species using type. */ void Species::setUsingType(const TYPE typeIn) { type = typeIn; } /** * set the species using name. */ void Species::setUsingName(const QString& nameIn) { const QString name(nameIn.toLower()); std::vector speciesTypes; std::vector speciesNames; getAllSpeciesTypesAndNames(speciesTypes, speciesNames); type = TYPE_UNKNOWN; const int num = static_cast(speciesTypes.size()); for (int i = 0; i < num; i++) { if (name == speciesNames[i].toLower()) { type = speciesTypes[i]; break; } } } caret-5.6.4~dfsg.1.orig/caret_common/ProgramParametersException.h0000664000175000017500000000316511572067322024717 0ustar michaelmichael#ifndef __PROGRAM_PARAMETERS_EXCEPTION_H__ #define __PROGRAM_PARAMETERS_EXCEPTION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include /// class for an exception for program parameters class ProgramParametersException :public std::exception { public: /// Constructor ProgramParametersException(const QString& msg); /// Destructor virtual ~ProgramParametersException() throw(); /// get description of exception virtual QString whatQString() const throw(); protected: /// Description of the exception QString description; private: /// get description of exception (private to prevent its use) virtual const char* what() const throw() { return ""; } }; #endif // __PROGRAM_ARGUMENTS_EXCEPTION_H__ caret-5.6.4~dfsg.1.orig/caret_common/ProgramParametersException.cxx0000664000175000017500000000240011572067322025261 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "ProgramParametersException.h" /** * Constructor. */ ProgramParametersException::ProgramParametersException(const QString& msg) { description = msg; } /** * Destructor. */ ProgramParametersException::~ProgramParametersException() throw() { } /** * get description of exception. */ QString ProgramParametersException::whatQString() const throw() { return description; } caret-5.6.4~dfsg.1.orig/caret_common/ProgramParameters.h0000664000175000017500000001533211572067322023037 0ustar michaelmichael #ifndef __PROGRAM_PARAMETERS_H__ #define __PROGRAM_PARAMETERS_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "ProgramParametersException.h" #include "Structure.h" /// class for handling and accessing a programs parameters class ProgramParameters { public: // constructor ProgramParameters(const int argc, char* argv[]); // constructor ProgramParameters(const QString& programName, const QStringList& programParameters); // destructor ~ProgramParameters(); // get the number of parameters (value will change if splitUpRemainingParameters() called) int getNumberOfParameters() const throw (ProgramParametersException); // reset the parameters index void resetParametersIndex() throw (ProgramParametersException); // get the program name without the path QString getProgramNameWithoutPath() const throw (ProgramParametersException); // get the program name with the path QString getProgramNameWithPath() const throw (ProgramParametersException); // see if parameters are remaining bool getParametersAvailable() const throw (ProgramParametersException); // get next parameter as a string QString getNextParameterAsString(const QString& parameterNameForErrorMessage) throw (ProgramParametersException); // get next parameter as an int int getNextParameterAsInt(const QString& parameterNameForErrorMessage) throw (ProgramParametersException); // get next parameter as a float float getNextParameterAsFloat(const QString& parameterNameForErrorMessage) throw (ProgramParametersException); // get next parameter as a double double getNextParameterAsDouble(const QString& parameterNameForErrorMessage) throw (ProgramParametersException); // get next parameter as boolean bool getNextParameterAsBoolean(const QString& parameterNameForErrorMessage) throw (ProgramParametersException); // get several parameters as strings void getNextParametersAsStrings(const QString& parameterNameForErrorMessage, const int numberOfParametersToGet, std::vector& parametersOut) throw (ProgramParametersException); // get several parameters as ints void getNextParametersAsInts(const QString& parameterNameForErrorMessage, const int numberOfParametersToGet, std::vector& parametersOut) throw (ProgramParametersException); // get several parameters as floats void getNextParametersAsFloats(const QString& parameterNameForErrorMessage, const int numberOfParametersToGet, std::vector& parametersOut) throw (ProgramParametersException); // get several parameters as doubles void getNextParametersAsDoubles(const QString& parameterNameForErrorMessage, const int numberOfParametersToGet, std::vector& parametersOut) throw (ProgramParametersException); // get remaining parameters as strings void getRemainingParametersAsStrings(const QString& parameterNameForErrorMessage, std::vector& parametersOut) throw (ProgramParametersException); // get remaining parameters as ints void getRemainingParametersAsInts(const QString& parameterNameForErrorMessage, std::vector& parametersOut) throw (ProgramParametersException); // get remaining parameters as floats void getRemainingParametersAsFloats(const QString& parameterNameForErrorMessage, std::vector& parametersOut) throw (ProgramParametersException); // get remaining parameters as doubles void getRemainingParametersAsDoubles(const QString& parameterNameForErrorMessage, std::vector& parametersOut) throw (ProgramParametersException); // get the next parameter as structure Structure getNextParameterAsStructure(const QString& parameterNameForErrorMessage) throw (ProgramParametersException); // get the next parameter as a volume file name and label separated by a semicolon void getNextParameterAsVolumeFileNameAndLabel(const QString& parameterNameForErrorMessage, QString& volumeFileNameOut, QString& volumeFileLabelOut) throw (ProgramParametersException); // get the volume file name and label delimeter static QString getVolumeFileNameAndLabelDelimeter() { return ":::"; } // see if there is a parameter with specified name (does not affect "next parameter") bool getParameterWithValueExists(const QString& value) const; // get index of a parameter with specified name (returns -1 if not found) int getIndexOfParameterWithValue(const QString& value) const; // get a parameter at a specified index (does not affect "next parameter") QString getParameterAtIndex(const int indx) const; // remove parameter at a specified index void removeParameterAtIndex(const int indx); // unget the last parameter void ungetLastParameter() throw (ProgramParametersException); // split up remaining parameters (may have more than one in single string) void splitUpRemainingParameters(); protected: // the list of parameters std::vector parameters; // index of current parameter int parametersIndex; }; #endif // __PROGRAM_PARAMETERS_H__ caret-5.6.4~dfsg.1.orig/caret_common/ProgramParameters.cxx0000664000175000017500000003473511572067322023422 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "DebugControl.h" #include "FileUtilities.h" #include "ProgramParameters.h" /** * constructor. */ ProgramParameters::ProgramParameters(const int argc, char* argv[]) { parameters.clear(); for (int i = 0; i < argc; i++) { parameters.push_back(argv[i]); } resetParametersIndex(); } /** * constructor. */ ProgramParameters::ProgramParameters(const QString& programName, const QStringList& programParameters) { parameters.clear(); parameters.push_back(programName); for (int i = 0; i < programParameters.count(); i++) { parameters.push_back(programParameters.at(i)); } resetParametersIndex(); } /** * destructor. */ ProgramParameters::~ProgramParameters() { } /** * get the number of parameters (value will change if splitUpRemainingParameters() called) */ int ProgramParameters::getNumberOfParameters() const throw (ProgramParametersException) { return parameters.size(); } /** * reset the parameters index. */ void ProgramParameters::resetParametersIndex() throw (ProgramParametersException) { parametersIndex = 1; } /** * get the program name without the path. */ QString ProgramParameters::getProgramNameWithoutPath() const throw (ProgramParametersException) { if (parameters.empty()) { throw ProgramParametersException("Parameters passed to constructor were empty."); } const QString name(FileUtilities::basename(parameters[0])); return name; } /** * get the program name with the path. */ QString ProgramParameters::getProgramNameWithPath() const throw (ProgramParametersException) { if (parameters.empty()) { throw ProgramParametersException("Parameters passed to constructor were empty."); } const QString name(parameters[0]); return name; } /** * see if parameters are remaining. */ bool ProgramParameters::getParametersAvailable() const throw (ProgramParametersException) { if (parametersIndex < static_cast(parameters.size())) { return true; } return false; } /** * get next parameter as a string. */ QString ProgramParameters::getNextParameterAsString(const QString& parameterNameForErrorMessage) throw (ProgramParametersException) { if (getParametersAvailable() == false) { const QString msg("Parameter named \"" + parameterNameForErrorMessage + "\" is missing."); throw ProgramParametersException(msg); } const QString name(parameters[parametersIndex]); parametersIndex++; if (DebugControl::getDebugOn()) { if (parameterNameForErrorMessage.isEmpty() == false) { std::cout << "Parameter (" << parameterNameForErrorMessage.toAscii().constData() << ") " << name.toAscii().constData() << std::endl; } } return name; } /** * get next parameter as an int. */ int ProgramParameters::getNextParameterAsInt(const QString& parameterNameForErrorMessage) throw (ProgramParametersException) { const QString s(getNextParameterAsString(parameterNameForErrorMessage)); bool ok = false; const int i = s.toInt(&ok); if (ok == false) { throw ProgramParametersException("Error converting parameter named \"" + parameterNameForErrorMessage + "\" with value \"" + s + "\" to an integer"); } return i; } /** * get next parameter as a float. */ float ProgramParameters::getNextParameterAsFloat(const QString& parameterNameForErrorMessage) throw (ProgramParametersException) { const QString s(getNextParameterAsString(parameterNameForErrorMessage)); bool ok = false; const float f = s.toFloat(&ok); if (ok == false) { throw ProgramParametersException("Error converting parameter named \"" + parameterNameForErrorMessage + "\" with value \"" + s + "\" to a float"); } return f; } /** * get next parameter as a double */ double ProgramParameters::getNextParameterAsDouble(const QString& parameterNameForErrorMessage) throw (ProgramParametersException) { const QString s(getNextParameterAsString(parameterNameForErrorMessage)); bool ok = false; const double d = s.toDouble(&ok); if (ok == false) { throw ProgramParametersException("Error converting parameter named \"" + parameterNameForErrorMessage + "\" with value \"" + s + "\" to an double"); } return d; } /** * get next parameter as boolean. */ bool ProgramParameters::getNextParameterAsBoolean(const QString& parameterNameForErrorMessage) throw (ProgramParametersException) { const QString s(getNextParameterAsString(parameterNameForErrorMessage).toLower()); if (s == "true") return true; if (s == "false") return false; throw ProgramParametersException("Error converting parameter named \"" + parameterNameForErrorMessage + "\" with value \"" + s + "\" to a boolean (\"true\" or \"false\")."); } /** * unget the last parameter. */ void ProgramParameters::ungetLastParameter() throw (ProgramParametersException) { if (parametersIndex <= 1) { throw ProgramParametersException("Cannot unget last parameter, already " "at first parameter"); } } /** * get several parameters as strings. */ void ProgramParameters::getNextParametersAsStrings(const QString& parameterNameForErrorMessage, const int numberOfParametersToGet, std::vector& parametersOut) throw (ProgramParametersException) { parametersOut.clear(); for (int i = 0; i < numberOfParametersToGet; i++) { const QString paramName(parameterNameForErrorMessage + "[" + QString::number(i) + "]"); parametersOut.push_back(getNextParameterAsString(paramName)); } } /** * get several parameters as ints. */ void ProgramParameters::getNextParametersAsInts(const QString& parameterNameForErrorMessage, const int numberOfParametersToGet, std::vector& parametersOut) throw (ProgramParametersException) { parametersOut.clear(); for (int i = 0; i < numberOfParametersToGet; i++) { const QString paramName(parameterNameForErrorMessage + "[" + QString::number(i) + "]"); parametersOut.push_back(getNextParameterAsInt(paramName)); } } /** * get several parameters as floats. */ void ProgramParameters::getNextParametersAsFloats(const QString& parameterNameForErrorMessage, const int numberOfParametersToGet, std::vector& parametersOut) throw (ProgramParametersException) { parametersOut.clear(); for (int i = 0; i < numberOfParametersToGet; i++) { const QString paramName(parameterNameForErrorMessage + "[" + QString::number(i) + "]"); parametersOut.push_back(getNextParameterAsFloat(paramName)); } } /** * get several parameters as doubles. */ void ProgramParameters::getNextParametersAsDoubles(const QString& parameterNameForErrorMessage, const int numberOfParametersToGet, std::vector& parametersOut) throw (ProgramParametersException) { parametersOut.clear(); for (int i = 0; i < numberOfParametersToGet; i++) { const QString paramName(parameterNameForErrorMessage + "[" + QString::number(i) + "]"); parametersOut.push_back(getNextParameterAsDouble(paramName)); } } /** * get remaining parameters as strings. */ void ProgramParameters::getRemainingParametersAsStrings(const QString& parameterNameForErrorMessage, std::vector& parametersOut) throw (ProgramParametersException) { parametersOut.clear(); while (getParametersAvailable()) { parametersOut.push_back(getNextParameterAsString(parameterNameForErrorMessage)); } } /** * get remaining parameters as ints. */ void ProgramParameters::getRemainingParametersAsInts(const QString& parameterNameForErrorMessage, std::vector& parametersOut) throw (ProgramParametersException) { parametersOut.clear(); while (getParametersAvailable()) { parametersOut.push_back(getNextParameterAsInt(parameterNameForErrorMessage)); } } /** * get remaining parameters as floats. */ void ProgramParameters::getRemainingParametersAsFloats(const QString& parameterNameForErrorMessage, std::vector& parametersOut) throw (ProgramParametersException) { parametersOut.clear(); while (getParametersAvailable()) { parametersOut.push_back(getNextParameterAsFloat(parameterNameForErrorMessage)); } } /** * get remaining parameters as doubles. */ void ProgramParameters::getRemainingParametersAsDoubles(const QString& parameterNameForErrorMessage, std::vector& parametersOut) throw (ProgramParametersException) { parametersOut.clear(); while (getParametersAvailable()) { parametersOut.push_back(getNextParameterAsDouble(parameterNameForErrorMessage)); } } /** * get the next parameter as a volume file name and label separated by a semicolon. */ void ProgramParameters::getNextParameterAsVolumeFileNameAndLabel(const QString& parameterNameForErrorMessage, QString& volumeFileNameOut, QString& volumeFileLabelOut) throw (ProgramParametersException) { volumeFileNameOut = ""; volumeFileLabelOut = ""; volumeFileNameOut = getNextParameterAsString(parameterNameForErrorMessage); const QString delimeter = getVolumeFileNameAndLabelDelimeter(); int colonPos = volumeFileNameOut.indexOf(delimeter); if (colonPos != -1) { volumeFileLabelOut = volumeFileNameOut.mid(0, colonPos); volumeFileNameOut = volumeFileNameOut.mid(colonPos + delimeter.length()); } } /** * get the next parameter as structure. */ Structure ProgramParameters::getNextParameterAsStructure(const QString& parameterNameForErrorMessage) throw (ProgramParametersException) { const QString name(getNextParameterAsString(parameterNameForErrorMessage)); Structure structure; structure.setTypeFromString(name); if (structure.isInvalid()) { throw ProgramParametersException("Structure specified " + name + " is invalid."); } return structure; } /** * see if there is a parameter with specified name (does not affect "next parameter"). */ bool ProgramParameters::getParameterWithValueExists(const QString& value) const { const int indx = getIndexOfParameterWithValue(value); return (indx >= 0); } /** * get index of a parameter with specified name (returns -1 if not found). */ int ProgramParameters::getIndexOfParameterWithValue(const QString& value) const { const int num = getNumberOfParameters(); for (int i = 0; i < num; i++) { if (parameters[i] == value) { return i; } } return -1; } /** * get a parameter at a specified index (does not affect "next parameter"). */ QString ProgramParameters::getParameterAtIndex(const int indx) const { const int num = getNumberOfParameters(); if ((indx >= 0) && (indx < num)) { return parameters[indx]; } return ""; } /** * remove parameter at a specified index. */ void ProgramParameters::removeParameterAtIndex(const int indx) { const int num = getNumberOfParameters(); if ((indx >= 0) && (indx < num)) { parameters.erase(parameters.begin() + indx); } } /** * split up remaining parameters (may have more than one in single string). */ void ProgramParameters::splitUpRemainingParameters() { const int savedParameterIndex = parametersIndex; std::vector paramsSplitUp; while (getParametersAvailable()) { // // Get the next parameter and split it up using whitespace // const QStringList sl = getNextParameterAsString("").split(QRegExp("\\s+"), QString::SkipEmptyParts); for (int i = 0; i < sl.count(); i++) { const QString s = sl.at(i).trimmed(); if (s.isEmpty() == false) { paramsSplitUp.push_back(s); } } } // // Were parameters split up? // if (paramsSplitUp.empty() == false) { // // Remove end of existing parameters // parameters.erase(parameters.begin() + savedParameterIndex, parameters.end()); // // Add on split up parameters // parameters.insert(parameters.end(), paramsSplitUp.begin(), paramsSplitUp.end()); // // Reset index of next parameter // parametersIndex = savedParameterIndex; } } caret-5.6.4~dfsg.1.orig/caret_common/PointLocator.h0000664000175000017500000000667411572067322022032 0ustar michaelmichael #ifndef __POINT_LOCATOR_H__ #define __POINT_LOCATOR_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include /// This class is a 3D point locator. Points may be added at any time. class PointLocator { protected: /// Information about a point class Point { public: /// Constructor Point(const float xyzIn[3], const int idIn = -1); /// Destructor ~Point(); /// point's coordinate float xyz[3]; /// point's ID int idNum; }; public: /// Constructor PointLocator(const float boundsIn[6], const int* numBucketsInEachAxis = NULL); /// Constructor ~PointLocator(); /// add a point to the locator void addPoint(const float xyz[3], const int idIn); /// get nearest point int getNearestPoint(const float xyz[3]) const; protected: /// Class for storing a bucket class Bucket { public: /// constructor Bucket(); /// destructor ~Bucket(); /// get nearest point int getNearestPoint(const float xyz[3], float& nearbyDistSQ, float nearbyXYZ[3]) const; /// the bounds of the bucket float bounds[6]; /// the points in the bucket std::vector points; }; /// get bucket for a point (returns false if not in a bucket - out of bounds) bool getBucket(const float xyz[3], int ijk[3]) const; /// get one dimensional bucket index int getBucketIndex(const int ijk[3]) const; /// get one dimensional bucket index int getBucketIndex(const float xyz[3]) const; /// limit the IJK index to valid buckets void limitIJK(int ijk[3]) const; /// the buckets Bucket* buckets; /// size of buckets in X axis float sizeX; /// size of buckets in X axis float sizeY; /// size of buckets in X axis float sizeZ; /// number of buckets in X axis int numX; /// number of buckets in Y axis int numY; /// number of buckets in Z axis int numZ; /// total number of buckets int totalNumBuckets; /// bounds of the point locator float bounds[6]; /// keeps count of points added int pointCounter; }; #endif // __POINT_LOCATOR_H__ caret-5.6.4~dfsg.1.orig/caret_common/PointLocator.cxx0000664000175000017500000002337611572067322022403 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "MathUtilities.h" #include "PointLocator.h" /** * Constructor. */ PointLocator::PointLocator(const float boundsIn[6], const int* numBucketsInEachAxis) { for (int i = 0; i < 6; i++) { bounds[i] = boundsIn[i]; } numX = 10; numY = 10; numZ = 10; if (numBucketsInEachAxis != NULL) { numX = numBucketsInEachAxis[0]; numY = numBucketsInEachAxis[1]; numZ = numBucketsInEachAxis[2]; } totalNumBuckets = numX * numY * numZ; buckets = new Bucket[totalNumBuckets]; sizeX = (bounds[1] - bounds[0]) / numX; sizeY = (bounds[3] - bounds[2]) / numY; sizeZ = (bounds[5] - bounds[4]) / numZ; for (int i = 0; i < numX; i++) { for (int j = 0; j < numY; j++) { for (int k = 0; k < numZ; k++) { const int ijk[3] = { i, j, k }; const int bi = getBucketIndex(ijk); Bucket& b = buckets[bi]; b.bounds[0] = i * sizeX + bounds[0]; b.bounds[1] = bounds[0] + sizeX; b.bounds[2] = j * sizeY + bounds[2]; b.bounds[3] = bounds[2] + sizeY; b.bounds[4] = k * sizeZ + bounds[4]; b.bounds[5] = bounds[4] + sizeZ; } } } pointCounter = 0; } /** * Constructor. */ PointLocator::~PointLocator() { if (buckets != NULL) { delete[] buckets; } } /** * add a point to the locator. */ void PointLocator::addPoint(const float xyz[3], const int idIn) { // // Determine which bucket point is within // int ijk[3]; if (getBucket(xyz, ijk) == false) { std::cout << "PointLocator: point out of bounds" << std::endl; return; } // // Determine the one-dim bucket index // const int bucketIndex = getBucketIndex(ijk); if ((bucketIndex < 0) || (bucketIndex >= totalNumBuckets)) { std::cout << "PointLocator: point out of bounds" << std::endl; return; } // // Put point into bucket // int idNum = idIn; if (idNum < 0) { idNum = pointCounter; } pointCounter++; Point p(xyz, idNum); buckets[bucketIndex].points.push_back(p); } /** * get nearest point (returns -1 if not found) */ int PointLocator::getNearestPoint(const float xyz[3]) const { // // Determine which bucket point is within // int ijk[3]; if (getBucket(xyz, ijk) == false) { return -1; } // // Determine the one-dim bucket index // const int bucketIndex = getBucketIndex(ijk); if ((bucketIndex < 0) || (bucketIndex > totalNumBuckets)) { return -1; } // // Find nearest point in containing bucket // float nearbyDistSQ, nearbyXYZ[3]; int nearbyPt = buckets[bucketIndex].getNearestPoint(xyz, nearbyDistSQ, nearbyXYZ); // // Keep track of buckets already searched // std::set bucketsAlreadySearched; bucketsAlreadySearched.insert(bucketIndex); // // If bucket is empty, search nearby buckets and expand search if necessary // if (nearbyPt < 0) { bool done = false; int delta = 1; while (done == false) { // // Expand bucket search // const int minI = std::max(ijk[0] - delta, 0); const int maxI = std::min(ijk[0] + delta, numX - 1); const int minJ = std::max(ijk[1] - delta, 0); const int maxJ = std::min(ijk[1] + delta, numY - 1); const int minK = std::max(ijk[2] - delta, 0); const int maxK = std::min(ijk[2] + delta, numZ - 1); for (int i = minI; (i <= maxI) && (done == false); i++) { for (int j = minJ; (j <= maxJ) && (done == false); j++) { for (int k = minK; (k <= maxK) && (done == false); k++) { const int ijk2[3] = { i, j, k }; const int indx = getBucketIndex(ijk2); if (indx >= 0) { nearbyPt = buckets[indx].getNearestPoint(xyz, nearbyDistSQ, nearbyXYZ); if (nearbyPt >= 0) { done = true; } bucketsAlreadySearched.insert(indx); } } // for k } // for j } // for i // // have not found bucket yet ? // if (done == false) { delta++; // // Have all buckets been searched ? // if ((minI == 0) && (maxI == (numX - 1)) && (minJ == 0) && (maxJ == (numY - 1)) && (minK == 0) && (maxK == (numZ - 1))) { done = true; } } } } // // Found point in a bucket // if (nearbyPt >= 0) { const float dist = MathUtilities::distance3D(xyz, nearbyXYZ); const float minSearchXYZ[3] = { xyz[0] - dist, xyz[1] - dist, xyz[2] - dist }; const float maxSearchXYZ[3] = { xyz[0] + dist, xyz[1] + dist, xyz[2] + dist }; // // Minimum bucket to search // int minIJK[3]; getBucket(minSearchXYZ, minIJK); limitIJK(minIJK); // // Maximum bucket to search // int maxIJK[3]; getBucket(maxSearchXYZ, maxIJK); limitIJK(maxIJK); // // Search in the neighboring buckets // for (int i = minIJK[0]; i <= maxIJK[0]; i++) { for (int j = minIJK[1]; j <= maxIJK[1]; j++) { for (int k = minIJK[2]; k <= maxIJK[2]; k++) { const int ijk2[3] = { i, j, k }; const int bi = getBucketIndex(ijk2); if (std::find(bucketsAlreadySearched.begin(), bucketsAlreadySearched.end(), bi) == bucketsAlreadySearched.end()) { const Bucket& b = buckets[bi]; float ptXYZ[3], dist; const int pt = b.getNearestPoint(xyz, dist, ptXYZ); if ((pt >= 0) && (dist < nearbyDistSQ)) { nearbyDistSQ = dist; nearbyPt = pt; } } } } } return nearbyPt; } return -1; } /** * limit the IJK index to valid buckets. */ void PointLocator::limitIJK(int ijk[3]) const { ijk[0] = std::max(0, ijk[0]); ijk[0] = std::min(numX - 1, ijk[0]); ijk[1] = std::max(0, ijk[1]); ijk[1] = std::min(numY - 1, ijk[1]); ijk[2] = std::max(0, ijk[2]); ijk[2] = std::min(numZ - 1, ijk[2]); } /** * get bucket for a point (returns false if not in a bucket - out of bounds). */ bool PointLocator::getBucket(const float xyz[3], int ijk[3]) const { ijk[0] = static_cast((xyz[0] - bounds[0]) / sizeX); ijk[1] = static_cast((xyz[1] - bounds[2]) / sizeY); ijk[2] = static_cast((xyz[2] - bounds[4]) / sizeZ); if ((ijk[0] < 0) || (ijk[0] >= numX) || (ijk[1] < 0) || (ijk[1] >= numY) || (ijk[2] < 0) || (ijk[2] >= numZ)) { return false; } return true; } /** * get bucket index. */ int PointLocator::getBucketIndex(const int ijk[3]) const { const int indx = ijk[0] + ijk[1] * numX + ijk[2] * numX * numY; return indx; } /** * get one dimensional bucket index. */ int PointLocator::getBucketIndex(const float xyz[3]) const { int ijk[3]; if (getBucket(xyz, ijk) == false) { return -1; } return getBucketIndex(ijk); } //****************************************************************************** /** * Constructor. */ PointLocator::Point::Point(const float xyzIn[3], const int idIn) { xyz[0] = xyzIn[0]; xyz[1] = xyzIn[1]; xyz[2] = xyzIn[2]; idNum = idIn; } /** * Destructor */ PointLocator::Point::~Point() { } //****************************************************************************** /** * constructor. */ PointLocator::Bucket::Bucket() { for (int i = 0; i < 6; i++) { bounds[i] = 0.0; } } /** * destructor. */ PointLocator::Bucket::~Bucket() { } /** * get nearest point. */ int PointLocator::Bucket::getNearestPoint(const float xyz[3], float& nearbyDistSQ, float nearbyXYZ[3]) const { int n = -1; float dist = std::numeric_limits::max(); const int num = static_cast(points.size()); for (int i = 0; i < num; i++) { const Point& p = points[i]; const float dx = p.xyz[0] - xyz[0]; const float dy = p.xyz[1] - xyz[1]; const float dz = p.xyz[2] - xyz[2]; const float d = dx*dx + dy*dy + dz*dz; if (d < dist) { dist = d; n = i; } } if (n >= 0) { nearbyXYZ[0] = points[n].xyz[0]; nearbyXYZ[1] = points[n].xyz[1]; nearbyXYZ[2] = points[n].xyz[2]; nearbyDistSQ = dist; const int pointID = points[n].idNum; return pointID; } return -1; } caret-5.6.4~dfsg.1.orig/caret_common/NameIndexSort.h0000664000175000017500000000562411572067322022127 0ustar michaelmichael #ifndef __NAME_INDEX_SORT_H__ #define __NAME_INDEX_SORT_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include /// name and index sort class NameIndexSort { protected: /// class for storing names and indices class NameIndexPair { public: /// constructor NameIndexPair(const int indexIn, const QString& nameIn); /// the name QString name; /// the index int indx; /// less than operator bool operator<(const NameIndexPair& nip) const; /// compare case insensitive static bool lessThanCaseInsensitive(const NameIndexPair& nip1, const NameIndexPair& nip2); }; public: /// Constructor (must call sortByName after adding items); NameIndexSort(); /// Constructor NameIndexSort(const std::vector& indicesIn, const std::vector& namesIn); /// Constructor ~NameIndexSort(); /// add a pair of items (must call sortByName when done adding items) void add(const int indx, const QString& name); /// get number of name indice pairs int getNumberOfItems() const; /// get name and index for an item after sorting void getSortedNameAndIndex(const int itemNum, int& indexOut, QString& nameOut) const; /// get index for an item after sorting int getSortedIndex(const int itemNum) const; /// get name for an item after sorting QString getSortedName(const int itemNum) const; /// sort by name case sensitive void sortByNameCaseSensitive(); /// sort by name case insensitive void sortByNameCaseInsensitive(); protected: /// the names and indices std::vector names; }; #endif // __NAME_INDEX_SORT_H__ caret-5.6.4~dfsg.1.orig/caret_common/NameIndexSort.cxx0000664000175000017500000000643511572067322022503 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "NameIndexSort.h" /** * Constructor. */ NameIndexSort::NameIndexSort() { } /** * Constructor. */ NameIndexSort::NameIndexSort(const std::vector& indicesIn, const std::vector& namesIn) { for (unsigned int i = 0; i < indicesIn.size(); i++) { add(indicesIn[i], namesIn[i]); } sortByNameCaseSensitive(); } /** * Constructor. */ NameIndexSort::~NameIndexSort() { } /** * add a pair of items (must call sort when done adding items). */ void NameIndexSort::add(const int indx, const QString& name) { names.push_back(NameIndexPair(indx, name)); } /** * sort by name case sensitive. */ void NameIndexSort::sortByNameCaseSensitive() { std::sort(names.begin(), names.end()); } /** * sort by name case insensitive. */ void NameIndexSort::sortByNameCaseInsensitive() { std::sort(names.begin(), names.end(), NameIndexPair::lessThanCaseInsensitive); } /** * get number of name indice pairs. */ int NameIndexSort::getNumberOfItems() const { return names.size(); } /** * get name and index for an item after sorting. */ void NameIndexSort::getSortedNameAndIndex(const int itemNum, int& indexOut, QString& nameOut) const { indexOut = names[itemNum].indx; nameOut = names[itemNum].name; } /** * get index for an item after sorting. */ int NameIndexSort::getSortedIndex(const int itemNum) const { return names[itemNum].indx; } /** * get name for an item after sorting. */ QString NameIndexSort::getSortedName(const int itemNum) const { return names[itemNum].name; } /** * constructor. */ NameIndexSort::NameIndexPair::NameIndexPair(const int indexIn, const QString& nameIn) { indx = indexIn; name = nameIn; } /** * less than operator. */ bool NameIndexSort::NameIndexPair::operator<(const NameIndexPair& nip) const { if (name == nip.name) { return (indx < nip.indx); } return (name < nip.name); } //================================================================= /** * compare case insensitive. */ bool NameIndexSort::NameIndexPair::lessThanCaseInsensitive(const NameIndexPair& nip1, const NameIndexPair& nip2) { return (QString::compare(nip1.name, nip2.name, Qt::CaseInsensitive) < 0); } caret-5.6.4~dfsg.1.orig/caret_common/MathUtilities.h0000664000175000017500000002260011572067322022165 0ustar michaelmichael #ifndef __VE_MATH_UTILITIES_H__ #define __VE_MATH_UTILITIES_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include /// This class contains static methods for various mathematical formulas. class MathUtilities { public: /// normalize a vector static float normalize(float v[3]); /// normalize a vector static double normalize(double v[3]); /// get length of a vector static float vectorLength(const float v[3]); /// get length of a vector static double vectorLength(const double v[3]); /// see if point is in a polygon static int pointInPolygon(const double x[3], const int numPts, const double *pts, const double bounds[6], const double n[3]); /// see if point is in a polygon static int pointInPolygon(const float x[3], const int numPts, const float *pts, const float bounds[6], const float n[3]); /// dot product static float dotProduct(const float* p1, const float* p2); /// dot product static double dotProduct(const double* p1, const double* p2); /// distance^2 between two 3d coordinates static float distanceSquared3D(const float* p1, const float* p2); /// distance^2 between two 3d coordinates static double distanceSquared3D(const double* p1, const double* p2); /// distance between two 3d coordinates static float distance3D(const float* p1, const float* p2); /// distance between two 3d coordinates static double distance3D(const double* p1, const double* p2); /// distance of a point to an infinite line in 3D static float distancePointToLine3D(const float pt[3], const float v1[3], const float v2[3]); /// distance of a point to an infinite line in 3D static double distancePointToLine3D(const double pt[3], const double v1[3], const double v2[3]); /// determine if a value is NaN (A comparison with NaN always fails) static bool isNaN(const float f) { return (f != f); } /// subtract vectors (3d) static void subtractVectors(const float v1[3], const float v2[3], float result[3]); /// subtract vectors (3d) static void subtractVectors(const double v1[3], const double v2[3], double result[3]); /// compute angle (in radians) for point p2 static float angle(const float* p1, const float* p2, const float* p3); /// signed angle "jik" static float signedAngle(const float pi[3], const float pj[3], const float pk[3], const float n[3]); /// compute the signed distance of a point to a plane static float signedDistanceToPlane(const float normal[3], const float vertex[3], const float point[3]); /// compute the signed distance of a point to a plane static double signedDistanceToPlane(const double normal[3], const double vertex[3], const double point[3]); /// compute the signed area of a triangle in the X-Y plane static float signedTriangleArea2D(const float* p1, const float* p2, const float* p3); /// compute the signed area of a triangle in 3D space static float signedTriangleArea3D(const float* normal, const float* p1, const float* p2, const float* p3); /// compute the signed area of a triangle in 3D space static double signedTriangleArea3D(const double* normal, const double* p1, const double* p2, const double* p3); /// Compute the area of a triangle (copied from VTK's float version). static double triangleArea(const double p1[3], const double p2[3], const double p3[3]); /// Compute the area of a triangle (copied from VTK's float version). static float triangleArea(const float p1[3], const float p2[3], const float p3[3]); /// Compute the normal of three points (copied from VTK) static void computeNormal(const double v1[3], const double v2[3], const double v3[3], double n[3]); /// Compute the normal of three points (copied from VTK) static void computeNormal(const float v1[3], const float v2[3], const float v3[3], float n[3]); /// normalized cross product static void normalizedCrossProduct(const float* x1, const float* x2, float* product); /// convert radians to degrees static float radiansToDegrees() { return 57.2957795130; } /// convert degrees to radians static float degreesToRadians() { return 0.0174444444; } /// Determine if 2D lines intersect static bool lineIntersection2D(const float p1[2], const float p2[2], const float q1[2], const float q2[2], float intersection[2]); /// Determine if and where a ray intersects a plane static bool rayIntersectPlane(const float p1[3], const float p2[3], const float p3[3], const float rayOrigin[3], const float rayVector[3], float intersection[3], float* signedDistanceFromPlaneOut = NULL); /// Determine if and where a ray intersects a plane static bool rayIntersectPlane(const double p1[3], const double p2[3], const double p3[3], const double rayOrigin[3], const double rayVector[3], double intersection[3], double* signedDistanceFromPlaneOut = NULL); /// make a vector the specified length static void setVectorLength(float vector[3], const float newLength); /// compute the circumcenter of a 3D triangle static void triangleCircumcenter3D(const double a[3], const double b[3], const double c[3], double circumcenter[3], double& circumradius); /// compute the circumcenter of a 3D triangle static void triangleCircumcenter3D(const float a[3], const float b[3], const float c[3], float circumcenter[3], float& circumradius); /// limit a value to be non-negative static float limitToPositive(const float v); /// make the sign of the first arg the same as the sign of the second arg static void sign(float& val, const float useMySignArg); /// make the sign of the first arg the same as the sign of the second arg static void sign(double& val, const double useMySignArg); /// logarithm for general (ie LOG(2, 32) = 5; 2^5 = 32) static double log(const double base, const double num); /// cross product static void crossProduct(const float v1[3], const float v2[3], float crossedVector[3]); /// cross product static void crossProduct(const double v1[3], const double v2[3], double crossedVector[3]); /// factorial static int factorial(const int n); /// permutations (number of possible ordered groups: N=num elements, r=size of permutation) /// permutations = n! / (n - r)! static int permutations(const int n, const int r); /// combinations (number of possible unordered groups: N=num elements, k=size of combination) /// combinations = n! / (k! * (n - k)!) static int combinations(const int n, const int k); protected: }; #endif // __VE_MATH_H__ caret-5.6.4~dfsg.1.orig/caret_common/MathUtilities.cxx0000664000175000017500000007135711572067322022555 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ /*========================================================================= Program: Visualization Toolkit Module: $RCSfile: MathUtilities.cxx,v $ Language: C++ Date: $Date: 2009/04/09 15:47:56 $ Version: $Revision: 1.1.1.1 $ Copyright (c) 1993-2002 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 #include "vtkPlane.h" #include "vtkPolygon.h" #include "vtkTriangle.h" #include "MathUtilities.h" /** * limit a value to be non-negative. */ float MathUtilities::limitToPositive(const float vIn) { float v = vIn; if (v < 0.0) { v = 0.0; } return v; } /** * Distance^2 between two 3D points. */ float MathUtilities::distanceSquared3D(const float* p1, const float* p2) { const float dx = p1[0] - p2[0]; const float dy = p1[1] - p2[1]; const float dz = p1[2] - p2[2]; const float dist2 = dx*dx + dy*dy + dz*dz; return dist2; } /** * Distance^2 between two 3D points. */ double MathUtilities::distanceSquared3D(const double* p1, const double* p2) { const double dx = p1[0] - p2[0]; const double dy = p1[1] - p2[1]; const double dz = p1[2] - p2[2]; const double dist2 = dx*dx + dy*dy + dz*dz; return dist2; } /** * Distance between two 3D points. */ float MathUtilities::distance3D(const float* p1, const float* p2) { const float dx = p1[0] - p2[0]; const float dy = p1[1] - p2[1]; const float dz = p1[2] - p2[2]; const float dist = std::sqrt(dx*dx + dy*dy + dz*dz); return dist; } /** * Distance between two 3D points. */ double MathUtilities::distance3D(const double* p1, const double* p2) { const double dx = p1[0] - p2[0]; const double dy = p1[1] - p2[1]; const double dz = p1[2] - p2[2]; const double dist = std::sqrt(dx*dx + dy*dy + dz*dz); return dist; } /** * distance of a point to an infinite line in 3D. * "pt" is the point. "v1" and "v2" are points on the line. * Formula is from "http://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html". */ float MathUtilities::distancePointToLine3D(const float pt[3], const float v1[3], const float v2[3]) { float dv2v1[3]; subtractVectors(v2, v1, dv2v1); float dv1pt[3]; subtractVectors(v1, pt, dv1pt); float crossed[3]; MathUtilities::crossProduct(dv2v1, dv1pt, crossed); float numerator = MathUtilities::vectorLength(crossed); float denomenator = MathUtilities::vectorLength(dv2v1); float dist = numerator / denomenator; return dist; } /** * distance of a point to an infinite line in 3D. * "pt" is the point. "v1" and "v2" are points on the line. * Formula is from "http://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html". */ double MathUtilities::distancePointToLine3D(const double pt[3], const double v1[3], const double v2[3]) { double dv2v1[3]; subtractVectors(v2, v1, dv2v1); double dv1pt[3]; subtractVectors(v1, pt, dv1pt); double crossed[3]; MathUtilities::crossProduct(dv2v1, dv1pt, crossed); double numerator = MathUtilities::vectorLength(crossed); double denomenator = MathUtilities::vectorLength(dv2v1); double dist = numerator / denomenator; return dist; } /** * subtract vectors (3d) result = v1 - v2. */ void MathUtilities::subtractVectors(const float v1[3], const float v2[3], float result[3]) { result[0] = v1[0] - v2[0]; result[1] = v1[1] - v2[1]; result[2] = v1[2] - v2[2]; } /** * subtract vectors (3d) result = v1 - v2. */ void MathUtilities::subtractVectors(const double v1[3], const double v2[3], double result[3]) { result[0] = v1[0] - v2[0]; result[1] = v1[1] - v2[1]; result[2] = v1[2] - v2[2]; } /** * Compute the signed area of a triangle in the X-Y plane */ float MathUtilities::signedTriangleArea2D(const float* p1, const float* p2, const float* p3) { 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.5; return area; } /** * Compute the signed area of a triangle in the 3D space */ float MathUtilities::signedTriangleArea3D(const float* referenceNormal, const float* p1, const float* p2, const float* p3) { // // Area of the triangle formed by the three points // float area = triangleArea((float*)p1, (float*)p2, (float*)p3); // // Normal for the three points // float triangleNormal[3]; computeNormal(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. // const float dot = MathUtilities::dotProduct(referenceNormal, triangleNormal); if (dot < 0.0) { area = -area; } //std::cout << "dot is " << dot << std::endl; return area; } /** * Compute the area of a triangle (copied from VTK's float version). */ double MathUtilities::triangleArea(const double p1[3], const double p2[3], const double p3[3]) { const double a = distanceSquared3D(p1,p2); const double b = distanceSquared3D(p2,p3); const double c = distanceSquared3D(p3,p1); const double area = (0.25* std::sqrt(fabs(4.0*a*c - (a-b+c)*(a-b+c)))); return area; } /** * Compute the area of a triangle (copied from VTK's float version). */ float MathUtilities::triangleArea(const float p1[3], const float p2[3], const float p3[3]) { const float a = distanceSquared3D(p1,p2); const float b = distanceSquared3D(p2,p3); const float c = distanceSquared3D(p3,p1); const float area = (0.25* std::sqrt(fabs(4.0*a*c - (a-b+c)*(a-b+c)))); return area; } /** * Compute the normal of three points (copied from VTK). */ void MathUtilities::computeNormal(const double v1[3], const double v2[3], const double v3[3], double n[3]) { double length; vtkTriangle::ComputeNormalDirection((double*)v1, (double*)v2, (double*)v3, n); if ( (length = std::sqrt((n[0]*n[0] + n[1]*n[1] + n[2]*n[2]))) != 0.0 ) { n[0] /= length; n[1] /= length; n[2] /= length; } } /** * Compute the normal of three points (copied from VTK). */ void MathUtilities::computeNormal(const float v1[3], const float v2[3], const float v3[3], float n[3]) { double v1d[3] = { v1[0], v1[1], v1[2] }; double v2d[3] = { v2[0], v2[1], v2[2] }; double v3d[3] = { v3[0], v3[1], v3[2] }; double nd[3]; computeNormal(v1d, v2d, v3d, nd); n[0] = nd[0]; n[1] = nd[1]; n[2] = nd[2]; } /** * see if point is in a polygon. */ int MathUtilities::pointInPolygon(const double x[3], const int numPts, const double *pts, const double bounds[6], const double n[3]) { #ifdef HAVE_VTK5 const int result = vtkPolygon::PointInPolygon((double*)x, (int)numPts, (double*)pts, (double*)bounds, (double*)n); return result; #else // HAVE_VTK5 if (numPts > 0) { float* dpts = new float[numPts * 3]; for (int i = 0; i < (numPts * 3); i++) { dpts[i] = pts[i]; } float dx[3] = { x[0], x[1], x[2] }; float dbounds[6] = { bounds[0], bounds[1], bounds[2], bounds[3], bounds[4], bounds[5] }; float dn[3] = { n[0], n[1], n[2] }; int result = pointInPolygon(dx, numPts, dpts, dbounds, dn); delete[] dpts; return result; } else { return 0; } #endif // HAVE_VTK5 } /** * see if point is in a polygon. */ int MathUtilities::pointInPolygon(const float x[3], const int numPts, const float *pts, const float bounds[6], const float n[3]) { #ifdef HAVE_VTK5 if (numPts > 0) { double* dpts = new double[numPts * 3]; for (int i = 0; i < (numPts * 3); i++) { dpts[i] = pts[i]; } double dx[3] = { x[0], x[1], x[2] }; double dbounds[6] = { bounds[0], bounds[1], bounds[2], bounds[3], bounds[4], bounds[5] }; double dn[3] = { n[0], n[1], n[2] }; int result = pointInPolygon(dx, numPts, dpts, dbounds, dn); delete[] dpts; return result; } else { return 0; } #else // HAVE_VTK5 const int result = vtkPolygon::PointInPolygon((float*)x, (int)numPts, (float*)pts, (float*)bounds, (float*)n); return result; #endif // HAVE_VTK5 } /** * dot product. */ float MathUtilities::dotProduct(const float* p1, const float* p2) { const float dot = p1[0]*p2[0] + p1[1]*p2[1] + p1[2]*p2[2]; return dot; } /** * dot product. */ double MathUtilities::dotProduct(const double* p1, const double* p2) { const double dot = p1[0]*p2[0] + p1[1]*p2[1] + p1[2]*p2[2]; return dot; } /** * Compute the signed area of a triangle in the 3D space */ double MathUtilities::signedTriangleArea3D(const double* referenceNormal, const double* p1, const double* p2, const double* p3) { // // Area of the triangle formed by the three points // double area = MathUtilities::triangleArea((double*)p1, (double*)p2, (double*)p3); // // Normal for the three points // double triangleNormal[3]; computeNormal(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. // const double dot = MathUtilities::dotProduct(referenceNormal, triangleNormal); if (dot < 0.0) { area = -area; } //std::cout << "dot is " << dot << std::endl; return area; } /** * Determine the signed distance (positive is "above" plane, negative "below" plane). * normal - normal of the plane * vertex - a point on the plane * point - point distance is computed for. */ float MathUtilities::signedDistanceToPlane(const float normal[3], const float vertex[3], const float point[3]) { // // Project query point onto tile's plane // float projectedOntoPlane[3]; #ifdef HAVE_VTK5 double p[3] = { point[0], point[1], point[2] }; double v[3] = { vertex[0], vertex[1], vertex[2] }; double n[3] = { normal[0], normal[1], normal[2] }; double out[3]; vtkPlane::ProjectPoint((double*)p, (double*)v, (double*)n, out); projectedOntoPlane[0] = out[0]; projectedOntoPlane[1] = out[1]; projectedOntoPlane[2] = out[2]; #else // HAVE_VTK5 vtkPlane::ProjectPoint((float*)point, (float*)vertex, (float*)normal, projectedOntoPlane); #endif // HAVE_VTK5 // // Distance from query point to tile // const float dx = normal[0] * (point[0] - projectedOntoPlane[0]); const float dy = normal[1] * (point[1] - projectedOntoPlane[1]); const float dz = normal[2] * (point[2] - projectedOntoPlane[2]); const float signedDistance = dx + dy + dz; /* const float D = -(normal[0]*vertex[0] + normal[1]*vertex[1] + normal[2]*vertex[2]); const float signedDistance2 = normal[0]*point[0] + normal[1]*point[1] + normal[2]*point[2] + D; std::cout << "signed distance: " << signedDistance << " " << "signed distance2 " << signedDistance2 << std::endl; */ return signedDistance; } /** * Determine the signed distance (positive is "above" plane, negative "below" plane). * normal - normal of the plane * vertex - a point on the plane * point - point distance is computed for. */ double MathUtilities::signedDistanceToPlane(const double normal[3], const double vertex[3], const double point[3]) { // Project query point onto tile's plane // double projectedOntoPlane[3]; vtkPlane::ProjectPoint((double*)point, (double*)vertex, (double*)normal, projectedOntoPlane); // // Distance from query point to tile // const double dx = normal[0] * (point[0] - projectedOntoPlane[0]); const double dy = normal[1] * (point[1] - projectedOntoPlane[1]); const double dz = normal[2] * (point[2] - projectedOntoPlane[2]); const double signedDistance = dx + dy + dz; /* const float D = -(normal[0]*vertex[0] + normal[1]*vertex[1] + normal[2]*vertex[2]); const float signedDistance2 = normal[0]*point[0] + normal[1]*point[1] + normal[2]*point[2] + D; std::cout << "signed distance: " << signedDistance << " " << "signed distance2 " << signedDistance2 << std::endl; */ return signedDistance; } /** * Angle formed by p1, p2, p3 (angle at p2). Returned angle is in radians. */ float MathUtilities::angle(const float* p1, const float* p2, const float* p3) { // // 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 // const float v21len = MathUtilities::normalize(v21); const float v23len = MathUtilities::normalize(v23); float angleOut = 0.0; if ((v21len > 0.0) && (v23len > 0.0)) { // // angle is inverse cosine of the dot product // and be sure to handle numerical errors. // float dot = MathUtilities::dotProduct(v21, v23); if (dot > 1.0) dot = 1.0; else if (dot < -1.0) dot = -1.0; angleOut = std::acos(dot); } return angleOut; } /** * Signed angle for "jik". */ float MathUtilities::signedAngle(const float pi[3], const float pj[3], const float pk[3], const float n[3]) { const float x1 = pj[0] - pi[0]; const float y1 = pj[1] - pi[1]; const float z1 = pj[2] - pi[2]; const float x2 = pk[0] - pi[0]; const float y2 = pk[1] - pi[1]; const float z2 = pk[2] - pi[2]; /* s = |(ji)||(ki)| sin(phi) by cross product */ const float dx = y1*z2 - y2*z1; const float dy = x2*z1 - x1*z2; const float dz = x1*y2 - x2*y1; const float t = (dx*n [0]) + (dy*n [1]) + (dz*n [2]); float s = std::sqrt((dx*dx) + (dy*dy) + (dz*dz)); if (t < 0.0) { s = -s; } /* c = |(ji)||(ki)| cos(phi) by inner product */ const float c = x1*x2 + y1*y2 + z1*z2; const float phi = std::atan2(s,c); return phi; } /** * Normalized cross product */ void MathUtilities::normalizedCrossProduct(const float* x1, const float* x2, float* product) { float v1[3] = { x1[0], x1[1], x1[2] }; float v2[3] = { x2[0], x2[1], x2[2] }; MathUtilities::normalize(v1); MathUtilities::normalize(v2); MathUtilities::crossProduct(v1, v2, product); MathUtilities::normalize(product); /* MathUtilities::crossProduct(x1, x2, product); MathUtilities::vectorLength(product); product[0] = x1[1] * x2[2] - x2[1] * x1[2]; product[1] = x2[0] * x1[2] - x1[0] * x2[2]; product[2] = x1[0] * x2[1] - x2[0] * x1[1]; const float nmag = MathUtilities::vectorLength(product); if (nmag > 0.0) { product[0] /= nmag; product[1] /= nmag; product[2] /= nmag; } else { product[0] = 0.0; product[1] = 0.0; product[2] = 0.0; } */ } /** * Determine if 2D lines intersect. * Algorithm from http://mathworld.wolfram.com/Line-LineIntersection.html */ bool MathUtilities::lineIntersection2D(const float p1[2], const float p2[2], const float q1[2], const float q2[2], float intersection[2]) { const double tol = 0.01; const double x1 = p1[0]; const double y1 = p1[1]; const double x2 = p2[0]; const double y2 = p2[1]; const double x3 = q1[0]; const double y3 = q1[1]; const double x4 = q2[0]; const double y4 = q2[1]; const double denom = ((x1 - x2) * (y3 - y4)) - ((x3 - x4) * (y1 - y2)); if (denom != 0.0) { const double a = (x1 * y2) - (x2 * y1); const double c = (x3 * y4) - (x4 * y3); const double x = ((a * (x3 - x4)) - (c * (x1 - x2))) / denom; const double y = ((a * (y3 - y4)) - (c * (y1 - y2))) / denom; const double pxMax = std::max(x1, x2) + tol; const double pxMin = std::min(x1, x2) - tol; const double pyMax = std::max(y1, y2) + tol; const double pyMin = std::min(y1, y2) - tol; const double qxMax = std::max(x3, x4) + tol; const double qxMin = std::min(x3, x4) - tol; const double qyMax = std::max(y3, y4) + tol; const double qyMin = std::min(y3, y4) - tol; intersection[0] = x; intersection[1] = y; if ((x >= pxMin) && (x <= pxMax) && (x >= qxMin) && (x <= qxMax) && (y >= pyMin) && (y <= pyMax) && (y >= qyMin) && (y <= qyMax)) { return true; } } return false; } /** * make a vector the specified length. */ void MathUtilities::setVectorLength(float vector[3], const float newLength) { const float len = std::sqrt(vector[0]*vector[0] + vector[1]*vector[1] + vector[2]*vector[2]); if (len > 0) { const float scale = newLength / len; vector[0] *= scale; vector[1] *= scale; vector[2] *= scale; } } /** * See if a ray intersects a plane. * The plane is defined by 3 points (p1, p2, p3) * Returns true if the ray intersects the plane and false * if the ray is parallel to the plane. */ bool MathUtilities::rayIntersectPlane(const float p1[3], const float p2[3], const float p3[3], const float rayOrigin[3], const float rayVector[3], float intersection[3], float* signedDistanceFromPlaneOut) { // // Convert the ray into a unit vector // double ray[3] = { rayVector[0], rayVector[1], rayVector[2] }; MathUtilities::normalize(ray); // // Normal of plane // float normal[3]; computeNormal(p1, p2, p3, normal); // // Compute the plane equation // const double A = normal[0]; const double B = normal[1]; const double C = normal[2]; const double D = -(A*p1[0] + B*p1[1] + C*p1[2]); // // Parametric coordinate of where ray intersects plane // const double denom = A * ray[0] + B * ray[1] + C * ray[2]; double t = 0.0; if (denom != 0) { t = -(A * rayOrigin[0] + B * rayOrigin[1] + C * rayOrigin[2] + D) / denom; //if (t != 0.0) { intersection[0] = rayOrigin[0] + ray[0] * t; intersection[1] = rayOrigin[1] + ray[1] * t; intersection[2] = rayOrigin[2] + ray[2] * t; if (signedDistanceFromPlaneOut != NULL) { *signedDistanceFromPlaneOut = t; } return true; //} } return false; } /** * See if a ray intersects a plane. * The plane is defined by 3 points (p1, p2, p3) * Returns true if the ray intersects the plane and false * if the ray is parallel to the plane. */ bool MathUtilities::rayIntersectPlane(const double p1[3], const double p2[3], const double p3[3], const double rayOrigin[3], const double rayVector[3], double intersection[3], double* signedDistanceFromPlaneOut) { // // Convert the ray into a unit vector // double ray[3] = { rayVector[0], rayVector[1], rayVector[2] }; MathUtilities::normalize(ray); // // Normal of plane // double normal[3]; computeNormal(p1, p2, p3, normal); // // Compute the plane equation // const double A = normal[0]; const double B = normal[1]; const double C = normal[2]; const double D = -(A*p1[0] + B*p1[1] + C*p1[2]); // // Parametric coordinate of where ray intersects plane // const double denom = A * ray[0] + B * ray[1] + C * ray[2]; double t = 0.0; if (denom != 0) { t = -(A * rayOrigin[0] + B * rayOrigin[1] + C * rayOrigin[2] + D) / denom; //if (t != 0.0) { intersection[0] = rayOrigin[0] + ray[0] * t; intersection[1] = rayOrigin[1] + ray[1] * t; intersection[2] = rayOrigin[2] + ray[2] * t; if (signedDistanceFromPlaneOut != NULL) { *signedDistanceFromPlaneOut = t; } return true; //} } return false; } /** * From http://www.ics.uci.edu/~eppstein/junkyard/circumcenter.html * * Find the circumcenter and circumradiusof a triangle in 3D. * */ void MathUtilities::triangleCircumcenter3D(const float a[3], const float b[3], const float c[3], float circumcenter[3], float& circumradius) { double ad[3], bd[3], cd[3]; for (int i = 0; i < 3; i++) { ad[i] = a[i]; bd[i] = b[i]; cd[i] = c[i]; } double center[3], radius; triangleCircumcenter3D(ad, bd, cd, center, radius); circumcenter[0] = center[0]; circumcenter[1] = center[1]; circumcenter[2] = center[2]; circumradius = radius; } /** * From http://www.ics.uci.edu/~eppstein/junkyard/circumcenter.html * * Find the circumcenter and circumradiusof a triangle in 3D. * */ void MathUtilities::triangleCircumcenter3D(const double a[3], const double b[3], const double c[3], double circumcenter[3], double& circumradius) { double xba, yba, zba, xca, yca, zca; double balength, calength; double xcrossbc, ycrossbc, zcrossbc; double denominator; double xcirca, ycirca, zcirca; // // Use coordinates relative to point `a' of the triangle. // xba = b[0] - a[0]; yba = b[1] - a[1]; zba = b[2] - a[2]; xca = c[0] - a[0]; yca = c[1] - a[1]; zca = c[2] - a[2]; // // Squares of lengths of the edges incident to `a'. // balength = xba * xba + yba * yba + zba * zba; calength = xca * xca + yca * yca + zca * zca; // // Cross product of these edges. // #ifdef EXACT // // Use orient2d() from http://www.cs.cmu.edu/~quake/robust.html // to ensure a correctly signed (and reasonably accurate) result, // avoiding any possibility of division by zero. // xcrossbc = orient2d(b[1], b[2], c[1], c[2], a[1], a[2]); ycrossbc = orient2d(b[2], b[0], c[2], c[0], a[2], a[0]); zcrossbc = orient2d(b[0], b[1], c[0], c[1], a[0], a[1]); #else /* Take your chances with floating-point roundoff. */ xcrossbc = yba * zca - yca * zba; ycrossbc = zba * xca - zca * xba; zcrossbc = xba * yca - xca * yba; #endif // // Calculate the denominator of the formulae. // denominator = 0.5 / (xcrossbc * xcrossbc + ycrossbc * ycrossbc + zcrossbc * zcrossbc); // // Calculate offset (from `a') of circumcenter. // xcirca = ((balength * yca - calength * yba) * zcrossbc - (balength * zca - calength * zba) * ycrossbc) * denominator; ycirca = ((balength * zca - calength * zba) * xcrossbc - (balength * xca - calength * xba) * zcrossbc) * denominator; zcirca = ((balength * xca - calength * xba) * ycrossbc - (balength * yca - calength * yba) * xcrossbc) * denominator; circumcenter[0] = xcirca; circumcenter[1] = ycirca; circumcenter[2] = zcirca; circumradius = MathUtilities::vectorLength(circumcenter); // // Make coords absolute // circumcenter[0] += a[0]; circumcenter[1] += a[1]; circumcenter[2] += a[2]; } /** * make the sign of the first arg the same as the sign of the second arg. */ void MathUtilities::sign(float& val, const float useMySignArg) { if (useMySignArg > 0.0) { if (val < 0.0) { val = -val; } } else if (useMySignArg < 0.0) { if (val > 0.0) { val = -val; } } } /** * make the sign of the first arg the same as the sign of the second arg. */ void MathUtilities::sign(double& val, const double useMySignArg) { if (useMySignArg > 0.0) { if (val < 0.0) { val = -val; } } else if (useMySignArg < 0.0) { if (val > 0.0) { val = -val; } } } /** * logarithm for 2 (ie log(2, 32) = 5; 2^5 = 32). * * From http://www-lmmb.ncifcrf.gov/~toms/paper/primer/latex/node2.html * log2(num) = (log10(num) / log10(2) */ double MathUtilities::log(const double base, const double num) { if (num < 0.0) { return 0.0; } if (base < 0.0) { return 0.0; } const float val = std::log10(num) / std::log10(base); return val; } /** * normalize a vector. */ float MathUtilities::normalize(float v[3]) { const float len = vectorLength(v); if (len > 0) { v[0] /= len; v[1] /= len; v[2] /= len; } return len; } /** * normalize a vector. */ double MathUtilities::normalize(double v[3]) { const double len = vectorLength(v); if (len > 0) { v[0] /= len; v[1] /= len; v[2] /= len; } return len; } /** * get length of a vector. */ float MathUtilities::vectorLength(const float v[3]) { const float len = std::sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]); return len; } /** * get length of a vector. */ double MathUtilities::vectorLength(const double v[3]) { const float len = std::sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]); return len; } /** * cross product. */ void MathUtilities::crossProduct(const float v1[3], const float v2[3], float crossedVector[3]) { crossedVector[0] = (v1[1] * v2[2]) - (v1[2] * v2[1]); crossedVector[1] = (v1[2] * v2[0]) - (v1[0] * v2[2]); crossedVector[2] = (v1[0] * v2[1]) - (v1[1] * v2[0]); } /** * cross product. */ void MathUtilities::crossProduct(const double v1[3], const double v2[3], double crossedVector[3]) { crossedVector[0] = (v1[1] * v2[2]) - (v1[2] * v2[1]); crossedVector[1] = (v1[2] * v2[0]) - (v1[0] * v2[2]); crossedVector[2] = (v1[0] * v2[1]) - (v1[1] * v2[0]); } /** * factorial. */ int MathUtilities::factorial(const int n) { if (n <= 1) { return 1; } int product = 1; for (int i = 1; i <= n; i++) { product *= i; } return product; } /** * permutations (number of possible ordered groups: N=num elements, r=size of permutation)./ * permutations = n! / (n - r)! */ int MathUtilities::permutations(const int n, const int r) { const int numerator = factorial(n); const int denominator = factorial(n - r); const int p = numerator / denominator; return p; } /** * combinations (number of possible unordered groups: N=num elements, k=size of combination). * combinations = n! / (k! * (n - k)!) */ int MathUtilities::combinations(const int n, const int k) { const int numerator = factorial(n); const int denominator = factorial(k) * factorial(n - k); const int c = numerator / denominator; return c; } caret-5.6.4~dfsg.1.orig/caret_common/HttpFileDownload.h0000664000175000017500000001503311572067322022611 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __HTTP_FILE_DOWNLOAD_H__ #define __HTTP_FILE_DOWNLOAD_H__ #include #include #include #include class QHttp; class QHttpResponseHeader; class QTimer; /// class for downloading a file specified by a URL synchronously class HttpFileDownload : public QObject { Q_OBJECT public: /// the type of HTTP request enum HTTP_REQUEST_TYPE { HTTP_REQUEST_TYPE_GET, HTTP_REQUEST_TYPE_POST }; /// where to place downloaded data enum DOWNLOAD_MODE { DOWNLOAD_MODE_TO_FILE, DOWNLOAD_MODE_TO_STRING }; /// Constructor for downloading to a file HttpFileDownload(const QString& fileUrlIn, const QString& outputFileNameIn, const int timeoutAmountInSeconds); /// Constructor for downloading to a string HttpFileDownload(const QString& fileUrlIn, const int timeoutAmountInSeconds); /// Destructor ~HttpFileDownload(); /// set the type of HTTP request void setHttpRequestType(const HTTP_REQUEST_TYPE hrt) { httpRequestType = hrt; } /// get the type of HTTP request HTTP_REQUEST_TYPE getHttpRequestType() const { return httpRequestType; } /// set the post request content void setPostRequestContent(const QString& s) { postRequestContent = s; } /// get the post request content QString getPostRequestContent() const { return postRequestContent; } /// downloads the file void download(); /// find out if the download was successful bool getDownloadSuccessful() const { return fileDownloadSuccessful; } /// get the error message if the download is unsuccessful QString getErrorMessage() const { return errorMessage; } /// Get the content of the downloaded data. void getContent(QString& content) const; /// Get the content of the downloaded data as UTF-8 string. void getContentUTF8(QString& content) const; /// get the response code int getResponseCode() const { return responseCode; } /// get all response header elements std::map getResponseHeader() const { return responseHeaderElements; } /// additional items for the request header void addToRequestHeader(const std::map& rh) { requestHeaderElements = rh; } /// get a respone header element with the specified key QString getResponseHeaderElement(const QString& key) const; /// set the upload file name void setUploadFileName(const QString& dataFileName, const QString& sumsFileName); /// get the upload file name QString getUploadFileName() const { return uploadFileName; } /// Upload a file to SuMS. void uploadFileToSums(const std::vector& additionalTags, const std::vector& additionalValues); /// set the upload file comment void setUploadFileComment(const QString& s) { uploadFileComment = s; } /// get the upload file comment QString getUploadFileComment() const { return uploadFileComment; } protected slots: /// Called when the download completes void slotDone(bool error); /// Called when timeout occurs void slotTimeout(); /// States of http request. void slotStateChanged(int state); /// http header from get void slotResponseHeaderReceived(const QHttpResponseHeader& resp); /// called when data available to read void slotReadyRead(const QHttpResponseHeader& resp); protected: /// Initialize this instance. void initialize(const QString& fileUrlIn, const int timeoutAmountInSeconds, const DOWNLOAD_MODE downloadModeIn); /// see if the download is complete bool getDownloadComplete(); /// print the request header void printRequestHeader(); /// set the download complete void setDownloadComplete(const bool b); /// type of http request HTTP_REQUEST_TYPE httpRequestType; /// content for a post request QString postRequestContent; /// URL of file that is to be downloaded QString fileUrl; /// timeout amount int timeoutAmount; /// the timeout timer QTimer* timeoutTimer; /// the HTTP object used to download the file QHttp* http; /// mutex for download complete flag QMutex downloadCompleteMutex; /// completed flag bool fileDownloadComplete; /// file download was successful bool fileDownloadSuccessful; /// error message if a failure QString errorMessage; /// output file name when writing to a file QString outputFileName; /// the download mode DOWNLOAD_MODE downloadMode; /// the response code from the HTTP request int responseCode; /// response header elements std::map responseHeaderElements; /// additional header items for request std::map requestHeaderElements; /// name of file for uploading QString uploadFileName; /// name of file to put in sums when uploading QString uploadSumsFileName; /// upload file comment QString uploadFileComment; }; #endif // __HTTP_FILE_DOWNLOAD_H__ caret-5.6.4~dfsg.1.orig/caret_common/HttpFileDownload.cxx0000664000175000017500000005114311572067322023166 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include "AbstractFile.h" #include "DebugControl.h" #include "FileUtilities.h" #include "HttpFileDownload.h" /** * Constructor for download to a string. Use getContent() to get the downloaded data. * If the timeout amount is less than zero, there is no timeout. */ HttpFileDownload::HttpFileDownload(const QString& fileUrlIn, const int timeoutAmountInSeconds) : QObject(0) { initialize(fileUrlIn, timeoutAmountInSeconds, DOWNLOAD_MODE_TO_STRING); } /** * Constructor for downloading to a file. * If the timeout amount is less than zero, there is no timeout. */ HttpFileDownload::HttpFileDownload(const QString& fileUrlIn, const QString& outputFileNameIn, const int timeoutAmountInSeconds) : QObject(0) { initialize(fileUrlIn, timeoutAmountInSeconds, DOWNLOAD_MODE_TO_FILE); outputFileName = outputFileNameIn; } /** * Initialize this instance. */ void HttpFileDownload::initialize(const QString& fileUrlIn, const int timeoutAmountInSeconds, const DOWNLOAD_MODE downloadModeIn) { httpRequestType = HTTP_REQUEST_TYPE_GET; fileUrl = fileUrlIn; timeoutAmount = timeoutAmountInSeconds * 1000; downloadMode = downloadModeIn; timeoutTimer = NULL; http = NULL; errorMessage = ""; postRequestContent = ""; fileDownloadComplete = false; fileDownloadSuccessful = false; responseCode = -1; } /** * Destructor. */ HttpFileDownload::~HttpFileDownload() { if (timeoutTimer != NULL) { delete timeoutTimer; } if (http != NULL) { // // close the connection immediately // http->abort(); } // NOTE: do not delete "http" since it is attached to this object } /** * set the upload file name. */ void HttpFileDownload::setUploadFileName(const QString& dataFileName, const QString& sumsFileName) { uploadFileName = dataFileName; uploadSumsFileName= sumsFileName; } /** * Upload a file to SuMS. */ void HttpFileDownload::uploadFileToSums(const std::vector& additionalTags, const std::vector& additionalValues) { // fileUrl = "http://pulvinar.wustl.edu/cgi-bin/upload2.cgi"; if (DebugControl::getDebugOn()) { std::cout << "Trying to upload file: " << uploadSumsFileName.toAscii().constData() << std::endl; } // // Create a temporary file for uploading // QString temporaryFileName("caret_sums_upload.tmp"); QFile::remove(temporaryFileName); QFile file(temporaryFileName); if (file.open(QIODevice::WriteOnly) == false) { errorMessage = "Unable to open temporary file for writing: "; errorMessage.append(temporaryFileName); return; } QTextStream textStream(&file); const QString carriageReturnLineFeed = "\015\012"; //\r\n"; //"\n\r"; // // Tag for separating different parts in the file // const QString headerBoundaryTag = "----------0xKhTmLbOuNdArY"; const QString boundaryTag = "--" + headerBoundaryTag; // const QString uploadFileNameNoPath(FileUtilities::basename(uploadFileName)); // // Place additional header info into body of file being uploaded. // std::vector tags; std::vector values; tags.push_back("upload"); values.push_back("true"); tags.push_back("dispatch"); values.push_back("upload"); tags.push_back("dir_id"); values.push_back(""); tags.push_back("process"); values.push_back("1"); tags.push_back("longfilename"); values.push_back(""); //uploadFileNameNoPath); tags.push_back("comment"); values.push_back(uploadFileComment); tags.push_back("caret_xml"); values.push_back("yes"); if (additionalTags.empty() == false) { tags.insert(tags.end(), additionalTags.begin(), additionalTags.end()); values.insert(values.end(), additionalValues.begin(), additionalValues.end()); } for (unsigned int i = 0; i < tags.size(); i++) { textStream << boundaryTag << carriageReturnLineFeed; textStream << "Content-Disposition: " << "form-data; name=\"" << tags[i] << "\"" << carriageReturnLineFeed; // textStream << "Content-Type: text/plain" << carriageReturnLineFeed; textStream << carriageReturnLineFeed; textStream << values[i] << carriageReturnLineFeed; } // // Add on the upload file's information // textStream << boundaryTag << carriageReturnLineFeed; textStream << "Content-Disposition: form-data; name=\"theFile\"; " << "filename=\"" << uploadSumsFileName << "\"" << carriageReturnLineFeed; // << "filename=\"" << uploadFileNameNoPath << "\"" << carriageReturnLineFeed; textStream << "Content-Type: application/octet-stream" << carriageReturnLineFeed; textStream << carriageReturnLineFeed; // STILL BROKEN IN QT 4.2.2 //#ifdef QT4_FILE_POS_BUG file.close(); if (file.open(QIODevice::Append) == false) { errorMessage = "Unable to open temporary file for appending due to QT4 bug: "; errorMessage.append(temporaryFileName); return; } //#endif // QT4_FILE_POS_BUG QDataStream dataStream(&file); dataStream.setVersion(QDataStream::Qt_4_3); // file contents QFile inputFile(uploadFileName); if (inputFile.open(QIODevice::ReadOnly)) { QDataStream inputStream(&inputFile); inputStream.setVersion(QDataStream::Qt_4_3); const int inputFileSize = inputFile.size(); const int bufferSize = 4096; char buffer[bufferSize]; int bytesRemaining = inputFileSize - inputFile.pos(); int bytesToRead = std::min(bufferSize, bytesRemaining); inputStream.readRawData(buffer, bytesToRead); while (bytesToRead > 0) { dataStream.writeRawData(buffer, bytesToRead); bytesRemaining = inputFileSize - inputFile.pos(); bytesToRead = std::min(bufferSize, bytesRemaining); if (bytesToRead > 0) { inputStream.readRawData(buffer, bytesToRead); } } inputFile.close(); } else { errorMessage = "Unable to open data file for reading: "; errorMessage.append(uploadFileName); return; } // STILL BROKEN IN QT 4.2.2 //#ifdef QT4_FILE_POS_BUG file.close(); if (file.open(QIODevice::Append) == false) { errorMessage = "Unable to open temporary file for appending due to QT4 bug: "; errorMessage.append(temporaryFileName); return; } QTextStream textStream2(&file); textStream2 << carriageReturnLineFeed; textStream2 << boundaryTag << "--"; textStream2 << carriageReturnLineFeed; //#else // QT4_FILE_POS_BUG // textStream << carriageReturnLineFeed; // textStream << boundaryTag << "--"; // textStream << carriageReturnLineFeed; //#endif // QT4_FILE_POS_BUG // // close the file // file.close(); if (DebugControl::getDebugOn()) { std::cout << "File Size: " << file.size() << std::endl; } // // Reopen the file as readonly // if (file.open(QIODevice::ReadOnly) == false) { errorMessage = "Unable to open temporary file for reading: "; errorMessage.append(temporaryFileName); return; } // // Get the hostname, port, and file name // if (DebugControl::getDebugOn()) { std::cout << "Uploading to: " << fileUrl.toAscii().constData() << std::endl; } QUrl u(fileUrl); const QString urlHostName(u.host()); int urlPort = u.port(); if (urlPort < 0) { urlPort = 80; } //const QString urlFileAndPath(u.encodedPathAndQuery()); if (DebugControl::getDebugOn()) { std::cout << "host: " << urlHostName.toAscii().constData() << std::endl; std::cout << "port: " << urlPort << std::endl; //std::cout << "file: " << urlFileAndPath << std::endl; //std::cout << "filename: " << u.fileName() << std::endl; //std::cout << "path: " << u.path() << std::endl; //NOTE: printing query value causes all printing to terminal to stop. Why? //std::cout << "query: " << u.query() << std::endl; } QString pathAndQuery(u.path()); if (u.encodedQuery().isEmpty() == false) { pathAndQuery.append("?"); pathAndQuery.append(u.encodedQuery()); } // // create the HTTP object // http = new QHttp(urlHostName, urlPort, this); QObject::connect(http, SIGNAL(done(bool)), this, SLOT(slotDone(bool))); QObject::connect(http, SIGNAL(stateChanged(int)), this, SLOT(slotStateChanged(int))); QObject::connect(http, SIGNAL(responseHeaderReceived(const QHttpResponseHeader&)), this, SLOT(slotResponseHeaderReceived(const QHttpResponseHeader&))); QObject::connect(http, SIGNAL(readyRead(const QHttpResponseHeader&)), this, SLOT(slotReadyRead(const QHttpResponseHeader&))); // // Create a timeout timer if requested // if (timeoutAmount > 0) { timeoutTimer = new QTimer; QObject::connect(timeoutTimer, SIGNAL(timeout()), this, SLOT(slotTimeout())); timeoutTimer->setSingleShot(true); timeoutTimer->start(timeoutAmount); } QHttpRequestHeader header("POST", pathAndQuery); QString hp = u.host(); if (urlPort != 80) { hp += ":"; hp += QString::number(urlPort); } header.setValue("host", hp); header.setValue("connection", "close"); http->setHost(urlHostName, urlPort); header.setValue("Accept", "*/*"); header.setContentType("multipart/form-data; boundary=" + headerBoundaryTag); for (std::map::iterator pos = requestHeaderElements.begin(); pos != requestHeaderElements.end(); pos++) { header.setValue(pos->first, pos->second); } http->request(header, &file); printRequestHeader(); if (DebugControl::getDebugOn()) { QHttpRequestHeader req = http->currentRequest(); if (req.isValid()) { std::cout << "Request header path: " << req.path().toAscii().constData() << std::endl; std::cout << "Request method: " << req.method().toAscii().constData() << std::endl; } } // // Wait until done // while (getDownloadComplete() == false) { // // Allow other stuff to do things // qApp->processEvents(); //100); } file.close(); // // Remove the temporary file if debug is off // if (DebugControl::getDebugOn() == false) { QFile::remove(temporaryFileName); } } /** * downloads the file. */ void HttpFileDownload::download() { if (DebugControl::getDebugOn()) { std::cout << "Trying to download file: " << fileUrl.toAscii().constData() << std::endl; } // // Get the hostname, port, and file name // QUrl u(fileUrl); const QString urlHostName(u.host()); int urlPort = u.port(); if (urlPort < 0) { urlPort = 80; } //const QString urlFileAndPath(u.encodedPathAndQuery()); if (DebugControl::getDebugOn()) { std::cout << "host: " << urlHostName.toAscii().constData() << std::endl; std::cout << "port: " << urlPort << std::endl; //std::cout << "file: " << urlFileAndPath << std::endl; //std::cout << "filename: " << u.fileName() << std::endl; //std::cout << "path: " << u.path() << std::endl; //NOTE: printing query value causes all printing to terminal to stop. Why? //std::cout << "query: " << u.query() << std::endl; } QString pathAndQuery(u.path()); if (u.encodedQuery().isEmpty() == false) { pathAndQuery.append("?"); pathAndQuery.append(u.encodedQuery()); } // // create the HTTP object // http = new QHttp(urlHostName, urlPort, this); QObject::connect(http, SIGNAL(done(bool)), this, SLOT(slotDone(bool))); QObject::connect(http, SIGNAL(stateChanged(int)), this, SLOT(slotStateChanged(int))); QObject::connect(http, SIGNAL(responseHeaderReceived(const QHttpResponseHeader&)), this, SLOT(slotResponseHeaderReceived(const QHttpResponseHeader&))); QObject::connect(http, SIGNAL(readyRead(const QHttpResponseHeader&)), this, SLOT(slotReadyRead(const QHttpResponseHeader&))); // // Create a timeout timer if requested // if (timeoutAmount > 0) { timeoutTimer = new QTimer; QObject::connect(timeoutTimer, SIGNAL(timeout()), this, SLOT(slotTimeout())); timeoutTimer->setSingleShot(true); timeoutTimer->start(timeoutAmount); } // // the http request header // QString modeString; switch (httpRequestType) { case HTTP_REQUEST_TYPE_GET: modeString = "GET"; break; case HTTP_REQUEST_TYPE_POST: modeString = "POST"; break; } QHttpRequestHeader header(modeString, pathAndQuery); QString hp = u.host(); if (urlPort != 80) { hp += ":"; hp += QString::number(urlPort); } header.setValue("host", hp); for (std::map::iterator pos = requestHeaderElements.begin(); pos != requestHeaderElements.end(); pos++) { header.setValue(pos->first, pos->second); } header.setValue("connection", "close"); http->setHost(urlHostName, urlPort); switch (httpRequestType) { case HTTP_REQUEST_TYPE_GET: http->request(header); break; case HTTP_REQUEST_TYPE_POST: { header.setValue("pragma", "no-cache"); //header.setValue("Accept", "*/*"); header.setContentType("application/x-www-form-urlencoded"); const QString content(postRequestContent); http->request(header, content.toUtf8()); } break; } printRequestHeader(); if (DebugControl::getDebugOn()) { QHttpRequestHeader req = http->currentRequest(); if (req.isValid()) { std::cout << "Request header path: " << req.path().toAscii().constData() << std::endl; std::cout << "Request method: " << req.method().toAscii().constData() << std::endl; } } // // Wait until done // while (getDownloadComplete() == false) { // // Allow other stuff to do things // qApp->processEvents(); //100); } } void HttpFileDownload::printRequestHeader() { if (DebugControl::getDebugOn() == false) { return; } QHttpRequestHeader head = http->currentRequest(); if (head.isValid()) { QStringList keys = head.keys(); for (QStringList::Iterator it = keys.begin(); it != keys.end(); it++) { const QString key = *it; const QString value = head.value(key); std::cout << "REQUEST HEADER key (" << key.toAscii().constData() << ") value (" << value.toAscii().constData() << ")" << std::endl; } } } /** * Get the content of the downloaded data. */ void HttpFileDownload::getContent(QString& content) const { content = QString(http->readAll()); } /** * Get the content of the downloaded data as UTF-8 string. */ void HttpFileDownload::getContentUTF8(QString& content) const { content = QString::fromUtf8(http->readAll().data()); } /** * Called when the download completes. */ void HttpFileDownload::slotDone(bool error) { if (timeoutTimer != NULL) { timeoutTimer->stop(); } if (error == false) { if (responseCode == 200) { fileDownloadSuccessful = true; } switch (downloadMode) { case DOWNLOAD_MODE_TO_FILE: { // // Create the file // const QByteArray ba = http->readAll(); const int num = ba.size(); if (DebugControl::getDebugOn()) { std::cout << "File size downloaded: " << num << std::endl; } QFile file(outputFileName); if (file.open(QIODevice::WriteOnly)) { QDataStream stream(&file); stream.setVersion(QDataStream::Qt_4_3); stream.writeRawData(ba.data(), num); file.close(); } else { errorMessage.append("Unable to open file for writing: "); errorMessage.append(outputFileName); } } break; case DOWNLOAD_MODE_TO_STRING: break; } } else { errorMessage.append(http->errorString()); } //http->closeConnection(); http->abort(); // force connection to close setDownloadComplete(true); if (DebugControl::getDebugOn()) { std::cout << "In slotDone" << std::endl; } } /** * Called when timeout occurs. */ void HttpFileDownload::slotTimeout() { http->abort(); errorMessage.append("file download timed out."); setDownloadComplete(true); } /** * see if the download is complete. */ bool HttpFileDownload::getDownloadComplete() { bool done = false; downloadCompleteMutex.lock(); done = fileDownloadComplete; downloadCompleteMutex.unlock(); return done; } /** * set the download complete. */ void HttpFileDownload::setDownloadComplete(const bool b) { downloadCompleteMutex.lock(); fileDownloadComplete = b; downloadCompleteMutex.unlock(); } /** * called when data available to read. */ void HttpFileDownload::slotReadyRead(const QHttpResponseHeader&) { /* if (DebugControl::getDebugOn()) { std::cout << "Bytes available to read: " << http->bytesAvailable() << std::endl; } */ } /** * States of http request. */ void HttpFileDownload::slotStateChanged(int state) { if (DebugControl::getDebugOn()) { std::cout << "Download State: "; switch (state) { case QHttp::Unconnected: std::cout << "Unconnected" << std::endl; break; case QHttp::HostLookup: std::cout << "Host Lookup" << std::endl; break; case QHttp::Connecting: std::cout << "Connecting" << std::endl; break; case QHttp::Sending: std::cout << "Sending" << std::endl; break; case QHttp::Reading: std::cout << "Reading" << std::endl; break; case QHttp::Connected: std::cout << "Connected" << std::endl; break; case QHttp::Closing: std::cout << "Closing" << std::endl; break; } printRequestHeader(); } } /** * http header from get. */ void HttpFileDownload::slotResponseHeaderReceived(const QHttpResponseHeader& resp) { responseCode = resp.statusCode(); errorMessage.append(resp.reasonPhrase()); if (DebugControl::getDebugOn()) { std::cout << "HTTP Response Code: " << responseCode << std::endl; } if (resp.isValid()) { QStringList keys = resp.keys(); for (QStringList::Iterator it = keys.begin(); it != keys.end(); it++) { const QString key = *it; const QString value = resp.value(key); responseHeaderElements[key] = value; if (DebugControl::getDebugOn()) { std::cout << "RESPONSE HEADER key (" << key.toAscii().constData() << ") value (" << value.toAscii().constData() << ")" << std::endl; } } } } /** * get a respone header element with the specified key. */ QString HttpFileDownload::getResponseHeaderElement(const QString& key) const { const std::map::const_iterator iter = responseHeaderElements.find(key); if (iter != responseHeaderElements.end()) { return iter->second; } return ""; } caret-5.6.4~dfsg.1.orig/caret_common/HtmlColors.h0000664000175000017500000000607311572067322021474 0ustar michaelmichael #ifndef __HTML_COLOR_H__ #define __HTML_COLOR_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include /// class for html named colors and color values class HtmlColors { public: // get the names of all colors static void getAllColorNames(std::vector& allColorNames); // get the RGB values for a color name (returns true if color name valid) static bool getRgbFromColorName(const QString& colorName, unsigned char& redOut, unsigned char& greenOut, unsigned char& blueOut); // get the number of colors static int getNumberOfColors(); // get color information given a color index static void getColorInformation(const int colorIndex, QString& colorNameOut, unsigned char& redOut, unsigned char& greenOut, unsigned char& blueOut); protected: // intialize the colors static void initializeColors(); // colors initialized flag static bool colorsInitializedFlag; // class for storing names and colors class NameRGB { public: // constructor NameRGB(const QString& nameIn, const unsigned char redIn, const unsigned char greenIn, const unsigned char blueIn); // comparison operator bool operator<(const NameRGB& nrgb) const; // name QString name; // red unsigned char red; // green unsigned char green; // blue unsigned char blue; }; /// the colors static std::vector colors; }; #ifdef __HTML_COLORS_MAIN__ bool HtmlColors::colorsInitializedFlag = false; std::vector HtmlColors::colors; #endif // __HTML_COLORS_MAIN__ #endif // __HTML_COLOR_H__ caret-5.6.4~dfsg.1.orig/caret_common/HtmlColors.cxx0000664000175000017500000002305111572067322022042 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #define __HTML_COLORS_MAIN__ #include "HtmlColors.h" #undef __HTML_COLORS_MAIN__ /** * get the names of all colors. */ void HtmlColors::getAllColorNames(std::vector& allColorNames) { initializeColors(); allColorNames.clear(); for (unsigned int i = 0; i < colors.size(); i++) { allColorNames.push_back(colors[i].name); } } /** * get the RGB values for a color name (returns true if color name valid). */ bool HtmlColors::getRgbFromColorName(const QString& colorName, unsigned char& redOut, unsigned char& greenOut, unsigned char& blueOut) { initializeColors(); bool validColor = false; const int num = getNumberOfColors(); for (int i = 0; i < num; i++) { if (colors[i].name.toLower() == colorName.toLower()) { redOut = colors[i].red; greenOut = colors[i].green; blueOut = colors[i].blue; validColor = true; break; } } return validColor; } /** * get the number of colors. */ int HtmlColors::getNumberOfColors() { initializeColors(); return colors.size(); } /** * get color information given a color index. */ void HtmlColors::getColorInformation(const int colorIndex, QString& colorNameOut, unsigned char& redOut, unsigned char& greenOut, unsigned char& blueOut) { initializeColors(); if ((colorIndex >= 0) && (colorIndex < static_cast(getNumberOfColors()))) { colorNameOut = colors[colorIndex].name; redOut = colors[colorIndex].red; greenOut = colors[colorIndex].green; blueOut = colors[colorIndex].blue; } } /** * intialize the colors. */ void HtmlColors::initializeColors() { if (colorsInitializedFlag) { return; } colorsInitializedFlag = true; { const QString colorsInit[] = { "AliceBlue", "#F0F8FF", "AntiqueWhite", "#FAEBD7", "Aqua", "#00FFFF", "Aquamarine", "#7FFFD4", "Azure", "#F0FFFF", "Beige", "#F5F5DC", "Bisque", "#FFE4C4", "Black", "#000000", "BlanchedAlmond", "#FFEBCD", "Blue", "#0000FF", "BlueViolet", "#8A2BE2", "Brown", "#A52A2A", "BurlyWood", "#DEB887", "CadetBlue", "#5F9EA0", "Chartreuse", "#7FFF00", "Chocolate", "#D2691E", "Coral", "#FF7F50", "CornflowerBlue", "#6495ED", "Cornsilk", "#FFF8DC", "Crimson", "#DC143C", "Cyan", "#00FFFF", "DarkBlue", "#00008B", "DarkCyan", "#008B8B", "DarkGoldenRod", "#B8860B", "DarkGray", "#A9A9A9", "DarkGrey", "#A9A9A9", "DarkGreen", "#006400", "DarkKhaki", "#BDB76B", "DarkMagenta", "#8B008B", "DarkOliveGreen", "#556B2F", "Darkorange", "#FF8C00", "DarkOrchid", "#9932CC", "DarkRed", "#8B0000", "DarkSalmon", "#E9967A", "DarkSeaGreen", "#8FBC8F", "DarkSlateBlue", "#483D8B", "DarkSlateGray", "#2F4F4F", "DarkSlateGrey", "#2F4F4F", "DarkTurquoise", "#00CED1", "DarkViolet", "#9400D3", "DeepPink", "#FF1493", "DeepSkyBlue", "#00BFFF", "DimGray", "#696969", "DimGrey", "#696969", "DodgerBlue", "#1E90FF", "FireBrick", "#B22222", "FloralWhite", "#FFFAF0", "ForestGreen", "#228B22", "Fuchsia", "#FF00FF", "Gainsboro", "#DCDCDC", "GhostWhite", "#F8F8FF", "Gold", "#FFD700", "GoldenRod", "#DAA520", "Gray", "#808080", "Grey", "#808080", "Green", "#008000", "GreenYellow", "#ADFF2F", "HoneyDew", "#F0FFF0", "HotPink", "#FF69B4", "IndianRed", "#CD5C5C", "Indigo", "#4B0082", "Ivory", "#FFFFF0", "Khaki", "#F0E68C", "Lavender", "#E6E6FA", "LavenderBlush", "#FFF0F5", "LawnGreen", "#7CFC00", "LemonChiffon", "#FFFACD", "LightBlue", "#ADD8E6", "LightCoral", "#F08080", "LightCyan", "#E0FFFF", "LightGoldenRodYellow", "#FAFAD2", "LightGray", "#D3D3D3", "LightGrey", "#D3D3D3", "LightGreen", "#90EE90", "LightPink", "#FFB6C1", "LightSalmon", "#FFA07A", "LightSeaGreen", "#20B2AA", "LightSkyBlue", "#87CEFA", "LightSlateGray", "#778899", "LightSlateGrey", "#778899", "LightSteelBlue", "#B0C4DE", "LightYellow", "#FFFFE0", "Lime", "#00FF00", "LimeGreen", "#32CD32", "Linen", "#FAF0E6", "Magenta", "#FF00FF", "Maroon", "#800000", "MediumAquaMarine", "#66CDAA", "MediumBlue", "#0000CD", "MediumOrchid", "#BA55D3", "MediumPurple", "#9370D8", "MediumSeaGreen", "#3CB371", "MediumSlateBlue", "#7B68EE", "MediumSpringGreen", "#00FA9A", "MediumTurquoise", "#48D1CC", "MediumVioletRed", "#C71585", "MidnightBlue", "#191970", "MintCream", "#F5FFFA", "MistyRose", "#FFE4E1", "Moccasin", "#FFE4B5", "NavajoWhite", "#FFDEAD", "Navy", "#000080", "OldLace", "#FDF5E6", "Olive", "#808000", "OliveDrab", "#6B8E23", "Orange", "#FFA500", "OrangeRed", "#FF4500", "Orchid", "#DA70D6", "PaleGoldenRod", "#EEE8AA", "PaleGreen", "#98FB98", "PaleTurquoise", "#AFEEEE", "PaleVioletRed", "#D87093", "PapayaWhip", "#FFEFD5", "PeachPuff", "#FFDAB9", "Peru", "#CD853F", "Pink", "#FFC0CB", "Plum", "#DDA0DD", "PowderBlue", "#B0E0E6", "Purple", "#800080", "Red", "#FF0000", "RosyBrown", "#BC8F8F", "RoyalBlue", "#4169E1", "SaddleBrown", "#8B4513", "Salmon", "#FA8072", "SandyBrown", "#F4A460", "SeaGreen", "#2E8B57", "SeaShell", "#FFF5EE", "Sienna", "#A0522D", "Silver", "#C0C0C0", "SkyBlue", "#87CEEB", "SlateBlue", "#6A5ACD", "SlateGray", "#708090", "SlateGrey", "#708090", "Snow", "#FFFAFA", "SpringGreen", "#00FF7F", "SteelBlue", "#4682B4", "Tan", "#D2B48C", "Teal", "#008080", "Thistle", "#D8BFD8", "Tomato", "#FF6347", "Turquoise", "#40E0D0", "Violet", "#EE82EE", "Wheat", "#F5DEB3", "White", "#FFFFFF", "WhiteSmoke", "#F5F5F5", "Yellow", "#FFFF00", "YellowGreen", "#9ACD32", "THE_END", "THE_END" }; for (int i = 0; ; i += 2) { const int indxName = i; const int indxValue = (indxName + 1); if (colorsInit[indxName] == "THE_END") { break; } const QString cs = colorsInit[indxValue]; if (cs.size() >= 7) { bool ok = false; const unsigned char r = static_cast(cs.mid(1, 2).toInt(&ok, 16)); const unsigned char g = static_cast(cs.mid(3, 2).toInt(&ok, 16)); const unsigned char b = static_cast(cs.mid(5, 2).toInt(&ok, 16)); NameRGB nrgb(colorsInit[indxName], r, g, b); colors.push_back(nrgb); } else { std::cout << "HtmlColors: invalid color value: " << cs.toAscii().constData() << std::endl; } } std::sort(colors.begin(), colors.end()); } } /** * constructor. */ HtmlColors::NameRGB::NameRGB(const QString& nameIn, const unsigned char redIn, const unsigned char greenIn, const unsigned char blueIn) { name = nameIn; red = redIn; green = greenIn; blue = blueIn; } /** * comparison operator. */ bool HtmlColors::NameRGB::operator<(const NameRGB& nrgb) const { return (name < nrgb.name); } caret-5.6.4~dfsg.1.orig/caret_common/GaussianComputation.h0000664000175000017500000001061611572067322023401 0ustar michaelmichael #ifndef __GAUSSIAN_COMPUTATION_H__ #define __GAUSSIAN_COMPUTATION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include /// class for gaussian evaluation class GaussianComputation { public: /// class for a point that will be evaluated class Point3D { public: /// constructor Point3D(const float xyzIn[3], const float valueIn) { xyz[0] = xyzIn[0]; xyz[1] = xyzIn[1]; xyz[2] = xyzIn[2]; value = valueIn; weight = 0.0; } /// Destructor ~Point3D() { } /// get the weight float getWeight() const { return weight; } protected: /// coordinate float xyz[3]; /// value float value; /// weight float weight; friend class GaussianComputation; }; /// Constructor GaussianComputation(const float normBelowCutoffIn = 2.0, const float normAboveCutoffIn = 2.0, const float sigmaNormIn = 2.0, const float sigmaTangIn = 2.0, const float tangentCutoffIn = 3.0); /// destructor ~GaussianComputation(); /// evaluate for a point related to the reference point(returns weight) float evaluate(const float referencePointXYZ[3], const float referencePointNormal[3], const float evaluationPoint[3]) const; /// evaluate for a set of points related to the reference point /// returns gaussian computed from all points. Each "points" /// weight will also be set. float evaluate(const float referencePointXYZ[3], const float referencePointNormal[3], std::vector& points) const; /// tooltip text for norm below cutoff parameter static QString tooltipTextForNormBelowCutoff(); /// tooltip text for norm above cutoff parameter static QString tooltipTextForNormAboveCutoff(); /// tooltip text for tangent cutoff parameter static QString tooltipTextForTangentCutoff(); /// tooltip text for sigma norm parameter static QString tooltipTextForSigmaNorm(); /// tooltip text for sigma tang parameter static QString tooltipTextForSigmaTang(); /// get default parameters static void getDefaultParameters(float& normBelowCutoffOut, float& normAboveCutoffOut, float& sigmaNormOut, float& sigmaTangOut, float& tangentCutoffOut); protected: /// cutoff distance in direction opposite normal /// ("under" a plane tangent to the reference point) float normBelowCutoff; /// cutoff distance in direction of normal /// ("above" a plane tangent to the reference point) float normAboveCutoff; /// cutoff for distance along a plane tangent to the reference point float tangentCutoff; /// standard deviation for gaussian along the normal vector float sigmaNorm; /// standard deviation for gaussian along plane tangent to the reference point float sigmaTang; }; #endif // __GAUSSIAN_COMPUTATION_H__ caret-5.6.4~dfsg.1.orig/caret_common/GaussianComputation.cxx0000664000175000017500000001733211572067322023756 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "GaussianComputation.h" #include "MathUtilities.h" /** * Constructor. * * @param normBelowCutoffIn This is the cutoff distance in a direction opposite to * the normal vector (distance "under" a plane tangent to the reference point). * * @param normAboveCutoffIn This is the cutoff distance in the direction of the * normal vector (distance "above" a plane tangent to the reference point). * * @param sigmaNormIn Standard deviation for gaussian along the normal vector * * @param sigmaTangIn Standard deviation for gaussian alng plane tangenet to ref point * * @tangentCutoffIn Cutoff distance along plane tangent to reference point * * For more info: http://mathworld.wolfram.com/GaussianFunction.html */ GaussianComputation::GaussianComputation(const float normBelowCutoffIn, const float normAboveCutoffIn, const float sigmaNormIn, const float sigmaTangIn, const float tangentCutoffIn) { normBelowCutoff = normBelowCutoffIn; normAboveCutoff = normAboveCutoffIn; tangentCutoff = tangentCutoffIn; sigmaNorm = sigmaNormIn; sigmaTang = sigmaTangIn; } /** * destructor. */ GaussianComputation::~GaussianComputation() { } /** evaluate for a set of points related to the reference point * returns gaussian computed from all points. */ float GaussianComputation::evaluate(const float referencePointXYZ[3], const float referencePointNormal[3], std::vector& points) const { float valueSum = 0.0; float weightSum = 0.0; const int num = static_cast(points.size()); for (int i = 0; i < num; i++) { points[i].weight = evaluate(referencePointXYZ, referencePointNormal, points[i].xyz); valueSum += points[i].value * points[i].weight; weightSum += points[i].weight; } float result = 0.0; if (weightSum > 0.0) { result = valueSum / weightSum; } return result; } /** * evaluate for a point related to the reference point (returns weight). */ float GaussianComputation::evaluate(const float referencePointXYZ[3], const float referencePointNormal[3], const float evaluationPoint[3]) const { float weight = 0.0; // // "DistanceVector" is the offset vector of a voxel from the origin of the gaussian. // const float distanceVector[3] = { evaluationPoint[0] - referencePointXYZ[0], evaluationPoint[1] - referencePointXYZ[1], evaluationPoint[2] - referencePointXYZ[2] }; // // "dNorm" is"distanceVector" projected onto the normal. // See "Computer Graphics" 2nd ed pages 1096-1097 // // nodeNormal // /|\ x // | // | dTang // ------# # = voxelXYZ // d || / // N || / // o || / distanceVector // r || / // m ||/ // * * = nodeXYZ // const float dNorm = MathUtilities::dotProduct(referencePointNormal, distanceVector); // // See if the voxel of interest is within the allowable distances along the normal vector. // float Wnorm = 0.0; if ((dNorm > -normBelowCutoff) && (dNorm < normAboveCutoff)) { // // Wnorm is the weighting for the distance along the normal vector. // The weighting is inversely related to the distance from the node. // Wnorm = exp (-(dNorm * dNorm) / (2.0 * sigmaNorm * sigmaNorm)); } if (Wnorm > 0.0) { // // Tang is the distance vector components from the voxel // to the nearest point on infinitely long normal vector. // float Tang[3]; for (int i = 0; i < 3; i++) { Tang[i] = distanceVector[i] - dNorm*referencePointNormal[i]; } // // dTang is the distance from the end of the voxel to the closest // point on the infinitely long normal vector. // const float dTang = sqrt(Tang[0]*Tang[0] + Tang[1]*Tang[1] + Tang[2]*Tang[2]); // // See if voxel distance tangentially is within the limits. // float Wtang = 0.0; if (dTang < tangentCutoff) { // // Wtang is the weighting for the distance orthogonal to the // normal vector. The weighting is inversely related to the // distance from the origin. // Wtang = exp (-((dTang * dTang) / (2.0 * sigmaTang * sigmaTang))); } if (Wtang > 0.0) { // // Combine the weights and update the metric and weight sums. // weight = Wnorm * Wtang; } } return weight; } /** * tooltip text for norm below cutoff parameter. */ QString GaussianComputation::tooltipTextForNormBelowCutoff() { return "The cutoff distance in direction opposite\n" "of the node's normal vector.\n" "(\"Under\" a plane tangent to the node)."; } /** * tooltip text for norm above cutoff parameter. */ QString GaussianComputation::tooltipTextForNormAboveCutoff() { return "The cutoff distance in the direction of\n" "the node's normal vector.\n" "(\"Above\" a plane tangent to the node)."; } /** * tooltip text for tangent cutoff parameter. */ QString GaussianComputation::tooltipTextForTangentCutoff() { return "Cutoff distance along a plane\n" "tangent to the node."; } /** * tooltip text for sigma norm parameter. */ QString GaussianComputation::tooltipTextForSigmaNorm() { return "Standard deviation for gaussian\n" "along the node's normal vector."; } /** * tooltip text for sigma tang parameter. */ QString GaussianComputation::tooltipTextForSigmaTang() { return "Standard deviation for gaussian\n" "along plane tangent to the node."; } /** * get default parameters. */ void GaussianComputation::getDefaultParameters(float& normBelowCutoffOut, float& normAboveCutoffOut, float& sigmaNormOut, float& sigmaTangOut, float& tangentCutoffOut) { // // Use the constructor to get the values from default arguments // GaussianComputation gc; normBelowCutoffOut = gc.normBelowCutoff; normAboveCutoffOut = gc.normAboveCutoff; sigmaNormOut = gc.sigmaNorm; sigmaTangOut = gc.sigmaTang; tangentCutoffOut = gc.tangentCutoff; } caret-5.6.4~dfsg.1.orig/caret_common/FileUtilities.h0000664000175000017500000001712511572067322022161 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __FILE_UTILITIES_H__ #define __FILE_UTILITIES_H__ #include #include #include #include /// class contains static methods for operations dealing with files class FileUtilities { public: /// copy (or move) a file (returns true if an error occurs) static bool copyFile(const QString& inputName, const QString& outputName, const bool moveFileFlag = false, const bool verboseMode = false); /// download a file specified by a URL (returns true if successful) static bool downloadFileWithHttpGet(const QString& fileUrl, const QString& saveFileInDirectoryName, const int maxTimeToWait, QString& errorMessageOut, std::map* headerTags = NULL, int* returnCode = NULL); /// download file to a QString static bool downloadFileWithHttpGet(const QString& fileUrl, const int maxTimeToWait, QString& fileContentsOut, QString& errorMessageOut, std::map* headerTags = NULL, int* returnCode = NULL); /// download file to a C++ string static bool downloadFileWithHttpPost(const QString& fileUrl, const QString& postContentIn, const int maxTimeToWait, QString& fileContentsOut, QString& errorMessageOut, const std::map* additionalHeaderTagsIn = NULL, std::map* headerTags = NULL, int* returnCode = NULL); /// find files int the specified directory static void findFilesInDirectory(const QString& dirName, const QStringList& regExpMatchList, std::vector& matchingFiles); /// return result of making "myPathIn" relative to "otherPathIn" static void relativePath(const QString& otherPathIn, const QString& myPathIn, QString& result); /// return filename with path removed. static QString basename(const QString& s); /// return path of a filename. static QString dirname(const QString& s); /// return the filename's extension static QString filenameExtension(const QString& s); /// return the filename without extension static QString filenameWithoutExtension(const QString& s); /// parse a spec file name number of nodes (73k_fs_lr => 73k _fs_lr) static bool parseCaretDataFileNumberOfNodes(const QString& numNodesIn, QString& numNodesOut, QString& atlasOut); /// parse a data file name to see if it is a valid Caret file name. /// Returns true if the file's name is a valid Caret name. static bool parseCaretDataFileName(const QString& filenameIn, QString& directory, QString& species, QString& casename, QString& anatomy, QString& hemisphere, QString& description, QString& descriptionNoTypeName, QString& theDate, QString& numNodes, QString& extension); /// Reassemble the Caret data file name from the components. static QString reassembleCaretDataFileName( const QString& directory, const QString& species, const QString& casename, const QString& anatomy, const QString& hemisphere, const QString& description, const QString& theDate, const QString& numNodes, const QString& extension); /// Change the type name in the description string of the caret file name. static QString changeCaretDataFileDescriptionType(const QString& filename, const QString& newDescription); /// Change the description in the name of a caret file name. static QString changeCaretDataFileDescription(const QString& filename, const QString& newDescription); /// turn "path/file" into "file (path)" static QString rearrangeFileName(const QString& fileName, const int maxPathLength = 10000); /// create a directory (returns true if successful) static bool createDirectory(const QString& dirPath); /// see if a directory contains files static bool directoryContainsFiles(const QString& dirPath); /// gunzip a file (returns true if successful) static bool gunzipFile(const QString& inputName, const QString& outputName); /// Get subdirectory prefix. static QString getSubdirectoryPrefix(const QString& s); /// Return the directory separator for the current platform static QString directorySeparator(); /// deterimine if a path is an absolute path static bool isAbsolutePath(const QString& name); // return the name of a temporary directory (empty if invalid) static QString temporaryDirectory(); // see if a file contains the specified text static bool findTextInFile(const QString& fileName, const QString& text, const bool caseSensitiveFlag); // Remove the old extension if it is present. Add new extension. static QString replaceExtension(const QString fileName, const QString oldExtension, const QString newExtension); }; #endif // __FILE_UTILITIES_H__ caret-5.6.4~dfsg.1.orig/caret_common/FileUtilities.cxx0000664000175000017500000012124711572067322022535 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include "Basename.h" #include "DebugControl.h" #include "FileUtilities.h" #include "StringUtilities.h" #ifdef CARET_FLAG #include "HttpFileDownload.h" #include "zlib.h" #endif // CARET_FLAG /** * Find files in the directory that match the regular expression. * To match more than one file type, place a semi-colon between * the regular expressions. */ void FileUtilities::findFilesInDirectory(const QString& dirName, const QStringList& regExpMatchList, std::vector& matchingFiles) { QDir dir(dirName); QStringList files = dir.entryList(regExpMatchList, QDir::Files | QDir::NoSymLinks); matchingFiles.clear(); for (QStringList::Iterator it = files.begin(); it != files.end(); it++) { matchingFiles.push_back((*it)); } } /** * like "basename" for a C-string */ QString FileUtilities::basename(const QString& s) { char *name = new char[s.length() + 1]; strcpy(name, s.toAscii().constData()); QString sout(Basename(name)); delete[] name; return sout; } /** * like "dirname" for a C-string */ QString FileUtilities::dirname(const QString& s) { char *name = new char[s.length() + 1]; strcpy(name, s.toAscii().constData()); QString sout(Dirname(name)); delete[] name; return sout; } /** * Return the filename's extension */ QString FileUtilities::filenameExtension(const QString& s) { QString ext; const int period = s.lastIndexOf('.'); if (period >= 0) { ext = s.mid(period + 1); } return ext; } /** * Return the filename without the extension */ QString FileUtilities::filenameWithoutExtension(const QString& s) { QString name(s); const int period = s.lastIndexOf('.'); if (period >= 0) { name = s.mid(0, period); } return name; } /** * Rearrange a file name so that /usr/local/file.data becomes * file.data (/usr/local). */ QString FileUtilities::rearrangeFileName(const QString& fileName, const int maxPathLength) { QString name(basename(fileName)); QString path(dirname(fileName)); if ((path != ".") && (maxPathLength >= 0)) { name.append(" ("); const int pathLength = static_cast(path.length()); if (pathLength > maxPathLength) { name.append("..."); const int offset = pathLength - maxPathLength; name.append(path.mid(offset)); } else { name.append(path); } name.append(")"); } return name; } /** * Given the directory "mypath", determine the relative path to "otherpath". * * Examples: * mypath - "/surface02/john/caret_data/HUMAN.COLIN.ATLAS/RIGHT_HEM" * otherpath - "/surface02/john/caret_data/HUMAN.COLIN.ATLAS" * result - ".."; * * mypath - "/surface02/john/caret_data/HUMAN.COLIN.ATLAS/RIGHT_HEM" * otherpath - "/surface02/john/caret_data/HUMAN.COLIN.ATLAS/RIGHT_HEM/subdir" * result - "subdir"; * * mypath - "/surface02/john/caret_data/HUMAN.COLIN.ATLAS/RIGHT_HEM" * otherpath - "/surface02/john/caret_data/HUMAN.COLIN.ATLAS/LEFT_HEM/subdir" * result - "../LEFT_HEM/subdir"; */ void FileUtilities::relativePath(const QString& otherPathIn, const QString& myPathIn, QString& result) { result = otherPathIn; // // Check for either path being empty // if (otherPathIn.isEmpty() || myPathIn.isEmpty()) { return; } #ifdef Q_OS_WIN32 // // Both paths must be absolute paths // if (otherPathIn.indexOf(":") < 0) { return; } if (myPathIn.indexOf(":") < 0) { return; } #else // // Both paths must be absolute paths // if ((otherPathIn[0] != '/') || (myPathIn[0] != '/')) { return; } #endif std::vector otherPath; StringUtilities::token(QDir::cleanPath(otherPathIn), "/\\", otherPath); std::vector myPath; StringUtilities::token(QDir::cleanPath(myPathIn), "/\\", myPath); const unsigned int minLength = std::min(myPath.size(), otherPath.size()); unsigned 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; } //const char separator[2] = { QDir::separator(), '\0' }; // // Is other path a subdirectory of mypath // if (sameCount == myPath.size()) { result = ""; for (unsigned int j = sameCount; j < otherPath.size(); j++) { result.append(otherPath[j]); if (j < (otherPath.size() - 1)) { result.append(QDir::separator()); } } } // // otherpath is above this one // result = ""; for (unsigned int j = sameCount; j < myPath.size(); j++) { result.append(".."); if (j < (myPath.size() - 1)) { result.append(QDir::separator()); } } for (unsigned int k = sameCount; k < otherPath.size(); k++) { if (result.isEmpty() == false) { result.append(QDir::separator()); } result.append(otherPath[k]); } } /** * Copy the file "inputName" to the file "outputName". If * "moveFileFlag" is set, inputName will be deleted after * outputName has been written. Returns true if an error * occurs. */ bool FileUtilities::copyFile(const QString& inputName, const QString& outputName, const bool moveFileFlag, const bool verboseMode) { // // Make sure source file exists // QFileInfo srcInfo(inputName); if (srcInfo.exists() == false) { std::cerr << "ERROR: Unable to find source file " << inputName.toAscii().constData() << std::endl; return true; } // // If destination does not exist that is okay // QFileInfo destInfo(outputName); if (destInfo.exists() == false) { // // If destination is a symbolic link, remove it // if (destInfo.isSymLink()) { std::cout << "INFO: Destination " << outputName.toAscii().constData() << " is a symbolic link, " << "deleting it." << std::endl; QFile file(outputName); if (file.remove() == false) { std::cout << "ERROR: Unable to delete symbolic link " << qPrintable(outputName) << std::endl; return true; } } // // Make sure that the source and destination are not the same file // if (srcInfo.absolutePath() == destInfo.absolutePath()) { std::cout << "INFO: Source (" << inputName.toAscii().constData() << ") and Destination (" << outputName.toAscii().constData() << ") files are the same! Not copied." << std::endl; return true; } } QFileInfo inputFileInfo(inputName); QFileInfo outputFileInfo(outputName); if (inputFileInfo.absolutePath() == outputFileInfo.absolutePath()) { std::cerr << "ERROR: Trying to copy file " << inputName.toAscii().constData() << " to itself." << std::endl; return true; } std::ifstream in(inputName.toAscii().constData(), std::ios::in | std::ios::binary); if (!in) { std::cerr << "ERROR: unable to open for reading " << inputName.toAscii().constData() << std::endl; return true; } if (verboseMode) { std::cout << "INFO: Writing File: " << outputName.toAscii().constData() << std::endl; } std::ofstream out(outputName.toAscii().constData(), std::ios::out | std::ios::binary); if (!out) { std::cerr << "ERROR: unable to open for writing " << outputName.toAscii().constData() << std::endl; in.close(); return true; } // // This next line will copy the entire contents of the file // out << in.rdbuf(); in.close(); out.close(); if (moveFileFlag) { QFile file(inputName); file.remove(); } return false; } static void removeTrailingPeriod(QString& s) { if (s.isEmpty()) return; if (StringUtilities::endsWith(s, ".")) { s = s.left(s.length() - 1); } } /** * parse a spec file name number of nodes (73k_fs_lr => 73k _fs_lr). */ bool FileUtilities::parseCaretDataFileNumberOfNodes(const QString& numNodesIn, QString& numNodesOut, QString& atlasOut) { numNodesOut = ""; atlasOut = ""; const QString numNodesNumberRE("^(\\d+\\.)$"); // eg: 71723 const QString numNodesNumberAndTextRE("^(\\d+k)(_.+)$"); // eg: 164k_fs_LR for (int i = 0; i < 2; i++) { QString re = ""; switch(i) { case 0: re = numNodesNumberRE; break; case 1: re = numNodesNumberAndTextRE; break; } QRegExp regexp(re); if (regexp.isValid() == false) { std::cout << "Program Error: " << qPrintable(re) << " is an invalid regular expression." << std::endl; return false; } if (DebugControl::getDebugOn()) { std::cout << "-------------------------------------------------------------" << std::endl; std::cout << "Testing iter " << i << ": " << qPrintable(numNodesIn) << std::endl; } if (regexp.indexIn(numNodesIn) >= 0) { const int numCaptures = regexp.numCaptures(); switch (i) { case 0: if (numCaptures == 1) { numNodesOut = regexp.cap(1); return true; } break; case 1: if (numCaptures == 2) { numNodesOut = regexp.cap(1); atlasOut = regexp.cap(2); return true; } break; } } } return false; } /** * Parse a data file name to see if it is a valid Caret file name. * Returns true if the file name is a valid Caret file name. */ bool FileUtilities::parseCaretDataFileName(const QString& filenameIn, QString& directory, QString& species, QString& casename, QString& anatomy, QString& hemisphere, QString& description, QString& descriptionNoTypeName, QString& theDate, QString& numNodes, QString& extension) { // // set if file's name is a valid Caret file name. // bool validName = false; // // Get the directory // directory = FileUtilities::dirname(filenameIn); if (directory == ".") { directory = ""; } // // Chop off any path on the file's name // QString filename(FileUtilities::basename(filenameIn)); // // Remove GIFTI extension // bool hasGiftiExtension = false; if (filename.endsWith(".gii")) { if (filename.endsWith(".coord.gii") || filename.endsWith(".topo.gii") || filename.endsWith(".func.gii") || filename.endsWith(".label.gii") || filename.endsWith(".shape.gii")) { filename = filename.left(filename.length() - 4); hasGiftiExtension = true; } } // // clear the filename's components. // species = ""; casename = ""; anatomy = ""; hemisphere = ""; description = ""; descriptionNoTypeName = ""; theDate = ""; numNodes = ""; extension = ""; // // species is a string containing one or more letters, numbers, underscores, or dashes // followed by a period. // const QString speciesRE("([\\w_\\-]+\\.)"); // // case is a string containing one or more letters, numbers, undersores, or dashes // followed by a period. // const QString caseRE("([\\w_\\-]+\\.)"); // // brain part is a string containing one or more letters, numbers, undersores, or dashes // followed by a period. OPTIONAL. // const QString brainPartRE("([\\w_\\-]+\\.)?"); // // hemisphere is L, R, or LR followed by a period. // const QString hemisphereRE("(LR|L|R|BOTH)\\."); //const QString hemisphereRE("([LR|L|R|BOTH]\\.)"); // // description is a anything ending with a period. OPTIONAL. // const QString descriptionRE("(.+\\.)?"); // // Date is of the form YYYY-MM-DD, YYYY-MM, YY-MM-DD, or YY-MM // followed by a period. // const QString dateRE("(\\d{2,4}\\-\\d{2}(\\-\\d{2})?\\.)"); // // number of nodes is one or more numbers. // //const QString numNodesRE("(\\d+\\.)"); const QString numNodesNumberRE("(\\d+\\.)"); // eg: 71723 const QString numNodesNumberAndTextRE("(\\d+k_.+\\.)"); // eg: 164k_fs_LR // // extension is a string containing one or more letters, numbers, undersores, or dashes // const QString extensionRE("([\\w_\\-]+)"); // // Loop through the regular expressions. // const int numberOfRegularExpresions = 9; for (int i = 0; i < numberOfRegularExpresions; i++) { for (int nodeTest = 0; nodeTest < 2; nodeTest++) { QString numNodesRE = numNodesNumberRE; switch (nodeTest) { case 0: numNodesRE = numNodesNumberAndTextRE; break; case 1: numNodesRE = numNodesNumberRE; break; } // // Create the regular expression // QString re; switch (i) { case 0: re = "^" + speciesRE + caseRE + brainPartRE + hemisphereRE + descriptionRE + dateRE + numNodesRE + extensionRE + "$"; break; case 1: re = "^" + speciesRE + caseRE + brainPartRE + hemisphereRE + descriptionRE + numNodesRE + extensionRE + "$"; break; case 2: re = "^" + caseRE + hemisphereRE + descriptionRE + dateRE + numNodesRE + extensionRE + "$"; break; case 3: re = "^" + caseRE + hemisphereRE + descriptionRE + numNodesRE + extensionRE + "$"; break; case 4: re = "^" + caseRE + numNodesRE + extensionRE + "$"; break; case 5: re = "^" + caseRE + extensionRE + "$"; break; case 6: re = "^" + speciesRE + caseRE + hemisphereRE + numNodesRE + extensionRE + "$"; break; break; case 7: re = "^" + speciesRE + caseRE + hemisphereRE + descriptionRE + extensionRE + "$"; case 8: re = "^" + caseRE + hemisphereRE + numNodesRE + extensionRE + "$"; break; } // // Create the regular expression object. // QRegExp regexp(re); if (regexp.isValid() == false) { std::cout << "Program Error: " << qPrintable(re) << " is an invalid regular expression." << std::endl; return false; } if (DebugControl::getDebugOn()) { std::cout << "-------------------------------------------------------------" << std::endl; std::cout << "Testing iter " << i << ": " << qPrintable(filename) << std::endl; } if (regexp.indexIn(filename) >= 0) { const int numCaptures = regexp.numCaptures(); if (DebugControl::getDebugOn()) { std::cout << "num captures/patternID/nodeType: " << numCaptures << "/" << i << "/" << nodeTest << std::endl; for (int j = 1; j <= numCaptures; j++) { std::cout << " cap " << j << ": " << regexp.cap(j).toAscii().constData() << std::endl; } } switch (i) { case 0: if (numCaptures == 9) { species = regexp.cap(1); casename = regexp.cap(2); anatomy = regexp.cap(3); hemisphere = regexp.cap(4); description = regexp.cap(5); theDate = regexp.cap(6); numNodes = regexp.cap(8); extension = regexp.cap(9); validName = true; } break; case 1: if (numCaptures == 7) { species = regexp.cap(1); casename = regexp.cap(2); anatomy = regexp.cap(3); hemisphere = regexp.cap(4); description = regexp.cap(5); numNodes = regexp.cap(6); extension = regexp.cap(7); validName = true; } break; case 2: if (numCaptures == 7) { species = regexp.cap(1); hemisphere = regexp.cap(2); description = regexp.cap(3); theDate = regexp.cap(4); numNodes = regexp.cap(6); extension = regexp.cap(7); validName = true; } break; case 3: if (numCaptures == 5) { species = regexp.cap(1); hemisphere = regexp.cap(2); description = regexp.cap(3); numNodes = regexp.cap(4); extension = regexp.cap(5); validName = true; } break; case 4: if (numCaptures == 3) { species = regexp.cap(1); numNodes = regexp.cap(2); extension = regexp.cap(3); validName = true; } break; case 5: if (numCaptures == 2) { species = regexp.cap(1); extension = regexp.cap(2); validName = true; } break; case 6: if (numCaptures == 5) { species = regexp.cap(1); casename = regexp.cap(2); hemisphere = regexp.cap(3); numNodes = regexp.cap(4); extension = regexp.cap(5); validName = true; } break; case 7: if (numCaptures == 5) { species = regexp.cap(1); casename = regexp.cap(2); hemisphere = regexp.cap(3); description = regexp.cap(4); extension = regexp.cap(5); validName = true; } break; case 8: if (numCaptures == 4) { casename = regexp.cap(1); hemisphere = regexp.cap(2); numNodes = regexp.cap(3); extension = regexp.cap(4); validName = true; } } if (validName) { break; } } if (validName) { break; } } if (validName) { break; } } if (validName) { // // Remove periods on end of filename components // removeTrailingPeriod(species); removeTrailingPeriod(casename); removeTrailingPeriod(anatomy); removeTrailingPeriod(hemisphere); removeTrailingPeriod(description); removeTrailingPeriod(theDate); removeTrailingPeriod(numNodes); if (hasGiftiExtension) { extension += ".gii"; } if (description.isEmpty() == false) { descriptionNoTypeName = description; const QString descriptionLowerCase(StringUtilities::makeLowerCase(descriptionNoTypeName)); // // Different types for coordinate files // std::vector typeNames; typeNames.push_back("initialflat"); typeNames.push_back("flat"); typeNames.push_back("lobar"); typeNames.push_back("sphere"); typeNames.push_back("ellipsoid"); typeNames.push_back("inflated"); typeNames.push_back("veryinflated"); typeNames.push_back("very_inflated"); typeNames.push_back("fiducial"); typeNames.push_back("raw"); // // Different types for topo files // typeNames.push_back("closed"); typeNames.push_back("open"); typeNames.push_back("cut"); typeNames.push_back("lobar"); const int numTypeNames = static_cast(typeNames.size()); for (int i = 0; i < numTypeNames; i++) { const int pos = descriptionLowerCase.indexOf(typeNames[i]); if (pos != -1) { descriptionNoTypeName.resize(pos); if (StringUtilities::endsWith(descriptionNoTypeName, ".")) { descriptionNoTypeName.resize(descriptionNoTypeName.length() - 1); } break; } } } if (DebugControl::getDebugOn()) { std::cout << qPrintable(filename) << " is a valid file name" << std::endl; std::cout << "species: " << species.toAscii().constData() << std::endl; std::cout << "case: " << casename.toAscii().constData() << std::endl; std::cout << "anatomy: " << anatomy.toAscii().constData() << std::endl; std::cout << "hemisphere: " << hemisphere.toAscii().constData() << std::endl; std::cout << "description: " << description.toAscii().constData() << std::endl; std::cout << "description no type: " << descriptionNoTypeName.toAscii().constData() << std::endl; std::cout << "date: " << theDate.toAscii().constData() << std::endl; std::cout << "num nodes: " << numNodes.toAscii().constData() << std::endl; std::cout << "extension: " << extension.toAscii().constData() << std::endl; } } else { if (DebugControl::getDebugOn()) { std::cout << filename.toAscii().constData() << " is NOT a valid file name" << std::endl; } } // // Date no longer used // theDate = ""; return validName; } /** * Reassemble the Caret data file name from the components. */ QString FileUtilities::reassembleCaretDataFileName(const QString& directory, const QString& species, const QString& casename, const QString& anatomy, const QString& hemisphere, const QString& description, const QString& theDateIn, const QString& numNodes, const QString& extension) { // // Date is no longer used // QString theDate = theDateIn; theDate = ""; std::vector components; if (species.isEmpty() == false) { components.push_back(species); } if (casename.isEmpty() == false) { components.push_back(casename); } if (anatomy.isEmpty() == false) { components.push_back(anatomy); } if (hemisphere.isEmpty() == false) { components.push_back(hemisphere); } if (description.isEmpty() == false) { components.push_back(description); } if (theDate.isEmpty() == false) { components.push_back(theDate); } if (numNodes.isEmpty() == false) { components.push_back(numNodes); } if (extension.isEmpty() == false) { if (extension[0] == '.') { if (extension.length() > 1) { components.push_back(extension.mid(1)); } } else { components.push_back(extension); } } QString name; // // Add the directory if it is specified // if (directory.isEmpty() == false) { name.append(directory); if (StringUtilities::endsWith(name, "/") == false) { name.append("/"); } } name.append(StringUtilities::combine(components, ".")); return name; } /** * Change the description in the name of a caret file name. */ QString FileUtilities::changeCaretDataFileDescription(const QString& filename, const QString& newDescription) { QString directory, species, casename, anatomy, hemisphere, description, descriptionNoType; QString theDate, numNodes, extension; QString outputName; // // See if a valid caret data file name // if (FileUtilities::parseCaretDataFileName(filename, directory, species, casename, anatomy, hemisphere, description, descriptionNoType, theDate, numNodes, extension)) { // // Set the new file name // outputName = reassembleCaretDataFileName(directory, species, casename, anatomy, hemisphere, newDescription, theDate, numNodes, extension); } else { // // Not a caret data file name so just add description before extension // outputName = filenameWithoutExtension(filename); outputName += newDescription; outputName += filenameExtension(filename); } return outputName; } /** * Change the type name in the description string of the caret file name. */ QString FileUtilities::changeCaretDataFileDescriptionType(const QString& filename, const QString& newDescription) { QString directory, species, casename, anatomy, hemisphere, description, descriptionNoType; QString theDate, numNodes, extension; QString outputName; // // See if a valid caret data file name // if (FileUtilities::parseCaretDataFileName(filename, directory, species, casename, anatomy, hemisphere, description, descriptionNoType, theDate, numNodes, extension)) { // // Add the new description // if (descriptionNoType.isEmpty() == false) { descriptionNoType.append("."); } descriptionNoType.append(newDescription); // // Set the new file name // outputName = reassembleCaretDataFileName(directory, species, casename, anatomy, hemisphere, descriptionNoType, theDate, numNodes, extension); } else { // // Not a caret data file name so just add description before extension // outputName = filenameWithoutExtension(filename); outputName += newDescription; outputName += filenameExtension(filename); } return outputName; } /** * download a file specified by a URL (returns true if successful) */ #ifdef CARET_FLAG bool FileUtilities::downloadFileWithHttpGet(const QString& fileUrl, const QString& saveFileName, const int maxTimeToWait, QString& errorMessageOut, std::map* headerTags, int* returnCode) { HttpFileDownload hfd(fileUrl, saveFileName, maxTimeToWait); hfd.download(); const bool success = hfd.getDownloadSuccessful(); errorMessageOut = StringUtilities::fromNumber(hfd.getResponseCode()); errorMessageOut.append(": "); errorMessageOut.append(hfd.getErrorMessage()); if (headerTags != NULL) { *headerTags = hfd.getResponseHeader(); } if (returnCode != NULL) { *returnCode = hfd.getResponseCode(); } return success; } #endif // CARET_FLAG /** * download file to a QString */ #ifdef CARET_FLAG bool FileUtilities::downloadFileWithHttpGet(const QString& fileUrl, const int maxTimeToWait, QString& fileContents, QString& errorMessageOut, std::map* headerTags, int* returnCode) { HttpFileDownload hfd(fileUrl, maxTimeToWait); hfd.download(); const bool success = hfd.getDownloadSuccessful(); hfd.getContent(fileContents); errorMessageOut = StringUtilities::fromNumber(hfd.getResponseCode()); errorMessageOut.append(": "); errorMessageOut.append(hfd.getErrorMessage()); if (headerTags != NULL) { *headerTags = hfd.getResponseHeader(); } if (returnCode != NULL) { *returnCode = hfd.getResponseCode(); } return success; } #endif // CARET_FLAG /** * download file to a C++ string */ #ifdef CARET_FLAG bool FileUtilities::downloadFileWithHttpPost(const QString& fileUrl, const QString& postContentIn, const int maxTimeToWait, QString& fileContentsOut, QString& errorMessageOut, const std::map* additionalHeaderTagsIn, std::map* headerTagsOut, int* returnCode) { HttpFileDownload hfd(fileUrl, maxTimeToWait); hfd.setHttpRequestType(HttpFileDownload::HTTP_REQUEST_TYPE_POST); hfd.setPostRequestContent(postContentIn); if (additionalHeaderTagsIn != NULL) { hfd.addToRequestHeader(*additionalHeaderTagsIn); } hfd.download(); const bool success = hfd.getDownloadSuccessful(); hfd.getContent(fileContentsOut); errorMessageOut = StringUtilities::fromNumber(hfd.getResponseCode()); errorMessageOut.append(": "); errorMessageOut.append(hfd.getErrorMessage()); if (headerTagsOut != NULL) { *headerTagsOut = hfd.getResponseHeader(); } if (returnCode != NULL) { *returnCode = hfd.getResponseCode(); } return success; } #endif // CARET_FLAG /** * create a directory (returns true if successful). */ bool FileUtilities::createDirectory(const QString& dirPathIn) { // // Just creating a relative path ? // if (StringUtilities::findFirstOf(dirPathIn,"/\\") == -1) { QDir dir; return dir.mkdir(dirPathIn); } // // Save the current directory // const QString savedDirectory = QDir::currentPath(); // // Determine which directories need to be created // std::stack dirStack; QString dirPath(dirPathIn); bool done = false; while (done == false) { if (QFile::exists(dirPath)) { QDir::setCurrent(dirPath); done = true; } else { dirStack.push(QString(FileUtilities::basename(dirPath))); dirPath = FileUtilities::dirname(dirPath); if (dirPath.isEmpty()) { done = true; } } } // // Create any needed directories // while (dirStack.empty() == false) { const QString dirName = dirStack.top(); dirStack.pop(); QDir dir; if (dir.mkdir(dirName) == false) { std::cout << "Unable to create directory " << dirName.toAscii().constData() << " in " << QDir::currentPath().toAscii().constData() << std::endl; return false; } QDir::setCurrent(dirName); } // // Go back to saved directory // QDir::setCurrent(savedDirectory); return true; } /** * see if a directory contains files. */ bool FileUtilities::directoryContainsFiles(const QString& dirPath) { QDir d(dirPath, QString::null, QDir::Name, QDir::Files); return (d.count() > 0); } /** * gunzip a file (returns true if successful). */ #ifdef CARET_FLAG bool FileUtilities::gunzipFile(const QString& inputName, const QString& outputName) { // // Buffer for reading and writing // const unsigned int bufferSize = 4096; unsigned char buffer[bufferSize]; // // Open the input file // gzFile zf = gzopen(inputName.toAscii().constData(), "rb"); if (zf == NULL) { std::cout << "Unable to open " << inputName.toAscii().constData() << " for reading." << std::endl; return false; } // // Open the output file (need binary flags so new lines not manipulated on windows). // std::ofstream outFile(outputName.toAscii().constData(), std::ios::out | std::ios::binary); if (!outFile) { std::cout << "Unable to open " << outputName.toAscii().constData() << " for writing." << std::endl; return false; } // // Copy data from the input to the output file // int numRead = gzread(zf, (void*)buffer, bufferSize); while (numRead > 0) { outFile.write((const char*)buffer, numRead); numRead = gzread(zf, (void*)buffer, bufferSize); } // // Close the input and output files // gzclose(zf); outFile.close(); return true; } #endif // CARET_FLAG /** * Get subdirectory prefix for a file specified with a relative path. * if input is "thedir/filename.txt" this returns "thedir". If there is no subdirectory or * the path is absolute (begins with "/" on unix or "a:\" on windows an empty string is returned. */ QString FileUtilities::getSubdirectoryPrefix(const QString& s) { QFileInfo fi(s); if (fi.isRelative() == false) { return ""; } std::vector components; StringUtilities::token(s, "/\\", components); if (components.size() > 1) { return components[0]; } return ""; } /** * Return the directory separator for the current platform. */ QString FileUtilities::directorySeparator() { // const char sep[2] = { QDir::separator(), '\0' }; const QString sepStr(QDir::separator()); return sepStr; } /** * deterimine if a path is an absolute path. */ bool FileUtilities::isAbsolutePath(const QString& name) { if (name.isEmpty()) { return false; } #ifdef Q_OS_WIN32 if (name.indexOf(":") != -1) { return true; } #else if (name[0] == '/') { return true; } #endif return false; } /** * return the name of a temporary directory (empty if invalid). */ QString FileUtilities::temporaryDirectory() { return QDir::tempPath(); /* QString tempDir(""); #ifdef Q_OS_WIN32 tempDir = std::getenv("TEMP"); if (tempDir.isEmpty()) { tempDir = std::getenv("TMP"); } #else char tmp[L_tmpnam]; tmpnam(tmp); tempDir = FileUtilities::dirname(tmp); #endif return tempDir; */ } /** * see if a file contains the specified text. */ bool FileUtilities::findTextInFile(const QString& fileName, const QString& searchText, const bool caseSensitiveFlag) { Qt::CaseSensitivity caseSensative = Qt::CaseInsensitive; if (caseSensitiveFlag) { caseSensative = Qt::CaseSensitive; } const int searchLen = searchText.length(); if (searchLen <= 0) { return false; } QFile file(fileName); if (file.open(QFile::ReadOnly)) { const int numChars = 4096; QString lastText; QTextStream stream(&file); while (true) { // // Done ? // if (stream.atEnd()) { return false; } // // Read from file // const QString someText = stream.read(numChars); // // Done if no more data to read // if (someText.length() <= 0) { return false; } // // Need to add in some previous text in case search text straddles old and new // const QString allText = lastText + someText; if (allText.contains(searchText, caseSensative)) { file.close(); return true; } // // text in case search text straddles old and newly read data // lastText = someText.right(searchLen); } } return false; } /** * Remove the old extension if it is present. Add new extension. */ QString FileUtilities::replaceExtension(const QString fileName, const QString oldExtension, const QString newExtension) { QString newName = fileName; int oldPos = newName.lastIndexOf(oldExtension); if (oldPos >= 0) { newName = newName.left(oldPos); } if (newName.endsWith(newExtension) == false) { newName.append(newExtension); } return newName; } caret-5.6.4~dfsg.1.orig/caret_common/DebugControl.h0000664000175000017500000000677411572067322022005 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __DEBUG_CONTROL_H__ #define __DEBUG_CONTROL_H__ #include /// Class for controlling debug information. class DebugControl { public: // see if debugging is on static bool getDebugOn(); // turn debugging control on/off static void setDebugOn(const bool onOff); // get the debug node number static int getDebugNodeNumber() { return debugNodeNumber; } // set the debug node number static void setDebugNodeNumber(const int node) { debugNodeNumber = node; } // turn debugging on/off with an environment variable static void setDebugOnWithEnvironmentVariable(const QString& envVarName); // set debug flags using environment variables static void setDebugFlagsFromEnvironmentVariables(); // set the iterative update static void setIterativeUpdate(const int iter) { iterativeUpdate = iter; } // get the iterative update static int getIterativeUpdate() { return iterativeUpdate; } // get the test flag 1 static bool getTestFlag1() { return testFlag1; } // set the test flag 1 static void setTestFlag1(const bool tf) { testFlag1 = tf; } // get the test flag 2 static bool getTestFlag2() { return testFlag2; } // set the test flag 2 static void setTestFlag2(const bool tf) { testFlag2 = tf; } // get the file read timing flag static bool getFileReadTimingFlag() { return fileReadTimingFlag; } // set the file read timing flag static void setFileReadTimingFlag(const bool f) { fileReadTimingFlag = f; } // see if OpenGL debugging is on static bool getOpenGLDebugOn() { return openGLDebugFlag; } // set OpenGL debugging on/off static void setOpenGLDebugOn(const bool b) { openGLDebugFlag = b; } private: /// debugging on/off flag static bool debugOn; /// node number for debugging static int debugNodeNumber; /// iterative update static int iterativeUpdate; /// the test flag 1 static bool testFlag1; /// the test flag 2 static bool testFlag2; /// OpenGL debug on/off flag static bool openGLDebugFlag; /// the file read timing flag static bool fileReadTimingFlag; }; #ifdef __DEBUG_CONTROL_MAIN__ bool DebugControl::debugOn = false; int DebugControl::debugNodeNumber = -1; int DebugControl::iterativeUpdate = 10; bool DebugControl::testFlag1 = false; bool DebugControl::testFlag2 = false; bool DebugControl::fileReadTimingFlag = false; bool DebugControl::openGLDebugFlag = false; #endif #endif // __DEBUG_CONTROL_H__ caret-5.6.4~dfsg.1.orig/caret_common/DebugControl.cxx0000664000175000017500000000400411572067322022340 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * abc */ /*LICENSE_END*/ #include #include "vtkObject.h" #define __DEBUG_CONTROL_MAIN__ #include "DebugControl.h" #undef __DEBUG_CONTROL_MAIN__ #include "StatisticAlgorithm.h" /** * Get debugging on */ bool DebugControl::getDebugOn() { return debugOn; } /** * Set debugging on/off */ void DebugControl::setDebugOn(const bool onOff) { debugOn = onOff; StatisticAlgorithm::setDebugOn(debugOn); vtkObject::SetGlobalWarningDisplay(debugOn); } /** * set debug flags using environment variables. */ void DebugControl::setDebugFlagsFromEnvironmentVariables() { if (std::getenv("CARET_DEBUG") != NULL) { setDebugOn(true); } if (std::getenv("CARET_TEST1") != NULL) { setTestFlag1(true); } if (std::getenv("CARET_TEST2") != NULL) { setTestFlag2(true); } } /** * If the environment variable name passed in is valid, debugging is * set to on, otherwise it is set off. */ void DebugControl::setDebugOnWithEnvironmentVariable(const QString& envVarName) { debugOn = (std::getenv(envVarName.toAscii().constData()) != NULL); StatisticAlgorithm::setDebugOn(debugOn); vtkObject::SetGlobalWarningDisplay(debugOn); } caret-5.6.4~dfsg.1.orig/caret_common/DateAndTime.h0000664000175000017500000000102411572067322021514 0ustar michaelmichael/* * File: dateandtime.h * Author: john * * Created on June 23, 2009, 11:49 AM */ #ifndef __DATE_AND_TIME_H__ #define __DATE_AND_TIME_H__ #include class DateAndTime { public: // get the date and time in a string static QString getDateAndTimeAsString(); // get the date and time in a string for naming static QString getDateAndTimeForNaming(); // get the date in a string for naming static QString getDateForNaming(); private: }; #endif /* __DATE_AND_TIME_H__ */ caret-5.6.4~dfsg.1.orig/caret_common/DateAndTime.cxx0000664000175000017500000000251011572067322022070 0ustar michaelmichael/* * File: dateandtime.cxx * Author: john * * Created on June 23, 2009, 11:49 AM */ #include "DateAndTime.h" #include #include /** * Get the current date and time in a string. This methods returns * a format that should not crash like the locale date format does if * written to a text file. * * Returned date is in form: * 23 Jun 2009 11:57:13 */ QString DateAndTime::getDateAndTimeAsString() { QString s = QDateTime::currentDateTime().toString(Qt::DefaultLocaleShortDate); return s; } /** * Get the current date and time in a string. This methods returns * a format that should not crash like the locale date format does if * written to a text file. * * Returned date is in form: * 23_Jun_2009_11_57_13 */ QString DateAndTime::getDateAndTimeForNaming() { QString s = QDateTime::currentDateTime().toString(Qt::DefaultLocaleShortDate); for (int i = 0; i < s.length(); i++) { if (s.at(i).isLetterOrNumber() == false) { s[i] = '_'; } } return s; } /** * get the date in a string for naming. */ QString DateAndTime::getDateForNaming() { QString s = QDate::currentDate().toString(Qt::DefaultLocaleShortDate); for (int i = 0; i < s.length(); i++) { if (s.at(i).isLetterOrNumber() == false) { s[i] = '_'; } } return s; } caret-5.6.4~dfsg.1.orig/caret_common/CommandLineUtilities.h0000664000175000017500000000544611572067322023473 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __COMMAND_LINE_UTILITIES_H__ #define __COMMAND_LINE_UTILITIES_H__ #include /// class for assistance with command line arguments class CommandLineUtilities { public: ///Get the next parameter as a string. Returns true if the parameter exists. static bool getNextParameter(const QString& optionName, const int argc, char* argv[], const bool exitOnError, int& index, QString& stringOut); /// Get the next parameter as an int. Returns true if the parameter exists. static bool getNextParameter(const QString& optionName, const int argc, char* argv[], const bool exitOnError, int& index, int& intOut); /// Get the next parameter as a float. Returns true if the parameter exists. static bool getNextParameter(const QString& optionName, const int argc, char* argv[], const bool exitOnError, int& index, float& floatOut); /// Get the next parameter as a bool. Returns true if the parameter exists. static bool getNextParameter(const QString& optionName, const int argc, char* argv[], const bool exitOnError, int& index, bool& boolOut); }; #endif // __COMMAND_LINE_UTILITIES_H__ caret-5.6.4~dfsg.1.orig/caret_common/CommandLineUtilities.cxx0000664000175000017500000001030611572067322024035 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "CommandLineUtilities.h" #include "StringUtilities.h" /** * Get the next parameter as a string. * Returns true if the parameter exists. */ bool CommandLineUtilities::getNextParameter(const QString& optionName, const int argc, char* argv[], const bool exitOnError, int& index, QString& stringOut) { stringOut = ""; index++; if (index < argc) { stringOut = argv[index]; return true; } std::cout << "Missing parameter for \"" << optionName.toAscii().constData() << "\" option." << std::endl; if (exitOnError) { std::exit(-1); } return false; } /** * Get the next parameter as an int. * Returns true if the parameter exists. */ bool CommandLineUtilities::getNextParameter(const QString& optionName, const int argc, char* argv[], const bool exitOnError, int& index, int& intOut) { intOut = 0; QString s; if (getNextParameter(optionName, argc, argv, exitOnError, index, s)) { intOut = StringUtilities::toInt(s); return true; } return false; } /** * Get the next parameter as a float. * Returns true if the parameter exists. */ bool CommandLineUtilities::getNextParameter(const QString& optionName, const int argc, char* argv[], const bool exitOnError, int& index, float& floatOut) { QString s; if (getNextParameter(optionName, argc, argv, exitOnError, index, s)) { floatOut = StringUtilities::toFloat(s); return true; } return false; } /** * Get the next parameter as a bool (value should be "true" or "false", or "1" or "0". * Returns true if the parameter exists. */ bool CommandLineUtilities::getNextParameter(const QString& optionName, const int argc, char* argv[], const bool exitOnError, int& index, bool& boolOut) { boolOut = false; QString s; if (getNextParameter(optionName, argc, argv, exitOnError, index, s)) { if ((StringUtilities::makeLowerCase(s) == "true") || (StringUtilities::makeLowerCase(s) == "t") || (s == "1")) { boolOut = true; } else if ((StringUtilities::makeLowerCase(s) == "false") || (StringUtilities::makeLowerCase(s) == "f") || (s == "0")) { boolOut = false; } else { if (exitOnError) { std::cout << "Invalid bool value (not \"true\" or \"false\") \"" << s.toAscii().constData() << "\" for parameter \"" << optionName.toAscii().constData() << "\"." << std::endl; std::exit(-1); } } } return false; } caret-5.6.4~dfsg.1.orig/caret_common/Category.h0000664000175000017500000000445311572067322021163 0ustar michaelmichael #ifndef __CATEGORY_H__ #define __CATEGORY_H__ #include #include /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include /// valid categories class Category { public: /// category type enum TYPE { /// atlas TYPE_ATLAS, /// individual TYPE_INDIVIDUAL, /// tutorial TYPE_TUTORIAL }; // constructor Category(); // constructor Category(const TYPE& t); // constructor Category(const QString& name); // destructor ~Category(); /// equality operator bool operator==(const Category& cat) { return (type == cat.type); } /// inequality operator bool operator!=(const Category& cat) { return (type != cat.type); } // reset void reset(); // get category name QString getName() const; /// get the category type TYPE getType() const { return type; } // set the category using type void setUsingType(const TYPE typeIn); // set the category using name void setUsingName(const QString& nameIn); // get a list of categories and types static void getAllCategoryTypesAndNames(std::vector& typesOut, std::vector& namesOut); protected: /// category type TYPE type; }; #endif // __CATEGORY_H__ caret-5.6.4~dfsg.1.orig/caret_common/Category.cxx0000664000175000017500000000506611572067322021537 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "Category.h" /** * constructor. */ Category::Category() { reset(); } /** * constructor. */ Category::Category(const TYPE& t) { reset(); setUsingType(t); } /** * constructor. */ Category::Category(const QString& name) { reset(); setUsingName(name); } /** * destructor. */ Category::~Category() { } /** * reset. */ void Category::reset() { type = TYPE_INDIVIDUAL; } /** * get category name. */ QString Category::getName() const { QString name; std::vector types; std::vector names; getAllCategoryTypesAndNames(types, names); for (unsigned int i = 0; i < types.size(); i++) { if (types[i] == type) { name = names[i]; break; } } return name; } /** * set the category using type. */ void Category::setUsingType(const TYPE typeIn) { type = typeIn; } /** * set the category using name. */ void Category::setUsingName(const QString& nameIn) { type = TYPE_INDIVIDUAL; std::vector types; std::vector names; getAllCategoryTypesAndNames(types, names); for (unsigned int i = 0; i < types.size(); i++) { if (names[i].toLower() == nameIn.toLower()) { type = types[i]; break; } } } /** * get a list of categories and types. */ void Category::getAllCategoryTypesAndNames(std::vector& typesOut, std::vector& namesOut) { typesOut.clear(); namesOut.clear(); typesOut.push_back(TYPE_ATLAS); namesOut.push_back("Atlas"); typesOut.push_back(TYPE_INDIVIDUAL); namesOut.push_back("Individual"); typesOut.push_back(TYPE_TUTORIAL); namesOut.push_back("Tutorial"); } caret-5.6.4~dfsg.1.orig/caret_common/CaretVersion.h0000664000175000017500000000230411572067322022003 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __CARET_VERSION_H__ #define __CARET_VERSION_H__ #include /// class for caret version information class CaretVersion { public: /// Version 5.64, June 3, 2011 /// get the version of caret as a QString static QString getCaretVersionAsString() { return "5.64"; } }; #endif // __CARET_VERSION_H__ caret-5.6.4~dfsg.1.orig/caret_common/CaretTips.h0000664000175000017500000000347311572067322021305 0ustar michaelmichael #ifndef __CARET_TIPS_H__ #define __CARET_TIPS_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include /// a class for storing tips on how to use Caret class CaretTips { public: // constructor CaretTips(); // destructor ~CaretTips(); // get the number of Caret tips int getNumberOfCaretTips() const; // get a tip void getTip(const int tipNumber, QString& tipText, QString& helpPage) const; protected: /// a tip class Tip { public: // constructor Tip(const QString& tipIn, const QString& helpPageIn = ""); // destructor ~Tip(); /// the tip QString tip; /// the help page QString helpPage; }; /// the tips std::vector tips; }; #endif // __CARET_TIPS_H__ caret-5.6.4~dfsg.1.orig/caret_common/CaretTips.cxx0000664000175000017500000002161711572067322021660 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "CaretTips.h" // constructor CaretTips::CaretTips() { { QString tip("To capture an image of any of Caret's Dialog or Windows, " "hold down the CTRL and SHIFT keys and press the F1 key (on Apple " "computers, hold down the APPLE and SHIFT key and press the F1 key). " "A dialog will appear that asking the user how the captured image " "should be processed."); tips.push_back(Tip(tip)); } { QString tip("To change the model viewed in the Main or Viewing Windows, " "hold down the CTRL key (Apple key on Apple Computers) and " "press the F1, F2, ..., F15 key. F1 corresponds to the first " "model in the Toolbar's Model Selection Control, F2 to the " "second model, etc."); tips.push_back(Tip(tip, "misc/keyboard_commands.html")); } { QString tip("The keyboard may be used to control the view of the " "surface. Use the Arrow Keys, the Page Up Key, and " "the Page Down Key to rotate the surface. While " "holding down the Shift Key, use the Arrow Keys to " "pan the surface. While holding down the CTRL (Apple " "Key on Apple Computers), use the Up or Down Arrow Keys " "to Zoom the Surface."); tips.push_back(Tip(tip, "misc/keyboard_commands.html")); } #ifdef Q_OS_WIN32 { QString tip("The installation instructions contain instructions " "for creating a Shortcut on the Desktop and how to " "start Caret by double-clicking a Spec File in Windows " "Explorer."); tips.push_back(Tip(tip, "installation/caret5_installation.html")); } #endif // Q_OS_WIN32 { QString tip("Keys may be used to select standard views of a surface. " "The Home Key will reset the view. A, D, L, M, P, and V " "correspond to Anterior, Dorsal, Lateral, Medial, Posterior, " "and Ventral Views."); tips.push_back(Tip(tip, "misc/keyboard_commands.html")); } { QString tip("Scenes save the current \"state\" of Caret (displayed " "models and all Display Control settings) so that they " "may be easily reproduced at a later time or by other " "users. More information about scenes is available on " "the Caret Help Window selected from the Help Menu."); tips.push_back(Tip(tip, "faqs/scenes.html")); } { QString tip("Use the popup menu. To display the popup menu, " "click the Right Mouse Button (on Apple Computers " "hold down the CTRL Key and click the mouse button)."); tips.push_back(Tip(tip)); } { QString tip("Use File Menu->Capture Image of Main Window to get " "an image of the graphics contents of the Main Window. " "The captured image may be saved to a file or even " "copied to the Computer's Clipboard so that the image " "may be pasted into another program suchs as Photoshop, " "Powerpoint, or Word."); tips.push_back(Tip(tip, "faqs/images.html")); } { QString tip("caret_command is a command line program for performing " "an ever increasing number of operations in a command " "line or shell window. Run caret_command without any " "arguments to see a list of its operations."); tips.push_back(Tip(tip)); } { QString tip("Use Help Menu->Caret Help for a reference to Caret's " "Graphical User Interface (GUI)."); tips.push_back(Tip(tip, "index.html")); } { QString tip("Use the Preferences Window (available on the File Menu " "or the Apple Menu on Apple Computers) to change the " "background or foreground color. The foreground color " "is used for text such as the text that lists the scale " "on a color palette bar."); tips.push_back(Tip(tip)); } { QString tip("The status bar at the bottom of the Main Window lists " "the Mouse Mode of Caret along the the functions performed " "by Keyboard/Mouse operations."); tips.push_back(Tip(tip)); } { QString tip("Use \"Zip Spec File\" on the File Menu to create a ZIP " "archive of a Spec File and all of its data files."); tips.push_back(Tip(tip)); } { QString tip("Just about any image file can be used as a background " "for the Main Window. Use File Menu->Open Image Files " "to laod the image file. On the Display Control Window, " "select the Images page, select the appropriate image " "file, and check the box next to Show Image in Main " "Window."); tips.push_back(Tip(tip, "faqs/images.html")); } { QString tip("For editing text files, use the Text File Editor " "available from the Window Menu."); tips.push_back(Tip(tip)); } { QString tip("Make a movie (MPEG1 or MPEG2 format) using File Menu->" "Record Main Window Images as Movie. Using Automatic " "mode, adds an image of the Main Window's graphics area " "to the movie each time the graphics area is redrawn. " "Automatic Rotation or " "Interpolate Surfaces, both on the Surface Menu, are " "useful for movie creation. Caret can be started with " "the \"-xy\" option to fix the size of the graphics area." "For example, \"caret5 -xy 320 240\"."); tips.push_back(Tip(tip, "dialogs/record_as_mpeg_dialog.html")); } { QString tip("NIFTI is a newer volume format supported by other " "brain mapping software applications such as AFNI, " "BrainVoyager, FreeSurfer, and SPM"); tips.push_back(Tip(tip, "http://nifti.nimh.nih.gov/")); } { QString tip("AFNI is a useful program for processing volume data."); tips.push_back(Tip(tip, "http://afni.nimh.nih.gov/afni/")); } { QString tip("To automatically load a Spec File and all of its Data Files " "at Caret start up, run \"caret5 -loadspec \"" "where is the name of your spec file."); tips.push_back(Tip(tip)); } { QString tip("At the command line, run \"caret5 -help\" to see " "command line options for caret5."); tips.push_back(Tip(tip)); } { QString tip("\"Color Keys\" display names and corresponding colors " "for many data types such as borders and paint areas. " "Color keys may be displayed by pressing the \"Color " "Key\" button on the appropriate Display Control Dialog " "page or by using the popup menu (press right mouse " "button (control + mouse button on Macs) over the Main " "Window's graphics area."); tips.push_back(Tip(tip)); } } /** * destructor. */ CaretTips::~CaretTips() { } /** * get the number of Caret tips. */ int CaretTips::getNumberOfCaretTips() const { return tips.size(); } /** * get a tip. */ void CaretTips::getTip(const int tipNumber, QString& tipText, QString& helpPage) const { tipText = tips[tipNumber].tip; helpPage = tips[tipNumber].helpPage; } //==================================================================================== /** * constructor. */ CaretTips::Tip::Tip(const QString& tipIn, const QString& helpPageIn) { tip = tipIn; helpPage = helpPageIn; } /** * destructor. */ CaretTips::Tip::~Tip() { } caret-5.6.4~dfsg.1.orig/caret_common/CaretLinkedList.h0000664000175000017500000000510711572067322022424 0ustar michaelmichael #ifndef __CARET_LINKED_LIST_H__ #define __CARET_LINKED_LIST_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ /// Class for a linked list class CaretLinkedList { public: /// class for a node in a linked list class Node { public: /// Constructor Node(); /// Destructor virtual ~Node(); /// get the next node Node* getNext() { return next; } /// get the prev node Node* getPrev() { return prev; } private: /// next node in list Node* next; /// prev node in list Node* prev; friend class CaretLinkedList; }; /// Constructor CaretLinkedList(); /// Destructor (Does not delete node, use clear for that) ~CaretLinkedList(); /// clear the list void clear(); /// see if an item is already in the list bool isInList(Node* n); /// add to front of list void pushFront(Node* n); /// add to front of list void pushFront(CaretLinkedList* n); /// add to end of list void pushBack(Node* n); /// get front of list Node* getFront() { return front; } /// get back of list Node* getBack() { return back; } /// remove a node from the list void remove(Node* n, const bool deleteNode); /// get list is empty bool empty() { return (front == 0); } /// get number of nodes in list int size(); protected: /// front of list Node* front; /// back of list Node* back; }; #endif // caret-5.6.4~dfsg.1.orig/caret_common/CaretLinkedList.cxx0000664000175000017500000000633011572067322022776 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CaretLinkedList.h" /** * Constructor. */ CaretLinkedList::Node::Node() { next = 0; prev = 0; } /** * Destructor. */ CaretLinkedList::Node::~Node() { } //******************************************************************************* /** * Constructor. */ CaretLinkedList::CaretLinkedList() { front = 0; back = 0; } /** * Destructor. */ CaretLinkedList::~CaretLinkedList() { front = 0; back = 0; } /** * clear the list. */ void CaretLinkedList::clear() { Node* n = front; while (n != 0) { Node* temp = n->next; delete n; n = temp; } front = 0; back = 0; } /** * see if an item is already in the list. */ bool CaretLinkedList::isInList(Node* n) { Node* l = front; while (l != 0) { if (l == n) { return true; } l = l->next; } return false; } /** * add to front of list (list passed has all elements removed). */ void CaretLinkedList::pushFront(CaretLinkedList* list) { if (list->front == 0) { return; } if (front == 0) { front = list->front; back = list->back; } else { Node* n = list->back; n->next = front; front->prev = n; front = list->front; } list->front = 0; list->back = 0; } /** * add to front of list. */ void CaretLinkedList::pushFront(Node* n) { if (front != 0) { front->prev = n; } n->next = front; n->prev = 0; front = n; if (back == 0) { back = n; } } /** * add to end of list. */ void CaretLinkedList::pushBack(Node* n) { if (back != 0) { back->next = n; } n->prev = back; n->next = 0; back = n; if (front == 0) { front = n; } } /** * remove a node from the list. */ void CaretLinkedList::remove(Node* n, const bool deleteNode) { Node* nextNode = n->next; Node* prevNode = n->prev; if (prevNode != 0) { prevNode->next = nextNode; } if (nextNode != 0) { nextNode->prev = prevNode; } if (front == n) { front = nextNode; } if (back == n) { back = prevNode; } n->next = 0; n->prev = 0; if (deleteNode) { delete n; } } /** * get number of nodes in list. */ int CaretLinkedList::size() { int cnt = 0; Node* n = front; while (n != 0) { cnt++; n = n->next; } return cnt; } caret-5.6.4~dfsg.1.orig/caret_common/CaretException.h0000664000175000017500000000313011572067322022312 0ustar michaelmichael #ifndef __CARET_EXCEPTION_H__ #define __CARET_EXCEPTION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include /// a simple exception class class CaretException : public std::exception { public: /// constructor CaretException(const QString& msg) { description = msg; } /// destructor virtual ~CaretException() throw () { } /// get description of exception //virtual const char* what() const throw() { return description.toAscii().constData(); } /// get description of exception virtual QString whatQString() const throw() { return description; } protected: /// Description of the exception QString description; }; #endif // __CARET_EXCEPTION_H__ caret-5.6.4~dfsg.1.orig/caret_common/Basename.h0000664000175000017500000000175211572067322021120 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __BASENAME__ #define __BASENAME__ const char* Basename(char* path); const char* Dirname(char* path); #endif caret-5.6.4~dfsg.1.orig/caret_common/Basename.cxx0000664000175000017500000000663611572067322021501 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "QGlobalStatic" // The "basename()" function on some older Linux versions does not work // correctly. It leaves a leading "/" on the returned value. // Mac OSX has neither basename nor dirname. // #if !defined(Q_OS_MAC) && !defined(Q_OS_WIN32) #include #endif #include #if defined(Q_OS_LINUX) || defined(Q_OS_GLIBC) static const char *period = "."; #endif #ifdef Q_OS_MAC static const char *period = "."; #endif #ifdef Q_OS_WIN32 static const char *period = "."; #endif #ifdef Q_OS_FREEBSD static const char *period = "."; #endif const char* Basename(char* path) { #if defined(Q_OS_IRIX) || defined(Q_OS_SOLARIS) return basename(path); #else // // return "." if path is NULL or zero length // if (path == NULL) { return period; } const int len = strlen(path); if (len == 0) { return period; } // // if path is merely "/", return it // if ((len == 1) && (path[0] == '/')) { return path; } // // remove any trailing "/" // if ((path[len-1] == '/') || (path[len-1] == '\\')) { path[len-1] = '\0'; } // // return anything after the last "/" // char* lastSlash1 = strrchr(path, '/'); char* lastSlash2 = strrchr(path, '\\'); if (lastSlash1 != NULL) { if (lastSlash2 != NULL) { if (lastSlash2 > lastSlash1) { return (lastSlash2 + 1); } else { return (lastSlash1 + 1); } } else { return (lastSlash1 + 1); } } else if (lastSlash2 != NULL) { return (lastSlash2 + 1); } return path; #endif } //------------------------------------------------------------ const char* Dirname(char* path) { #if defined(Q_OS_MAC) || defined(Q_OS_WIN32) if (path == NULL) { return period; } else if (strlen(path) == 0) { return period; } else if (strcmp(path, "/") == 0) { return path; } else if (strcmp(path, ".") == 0) { return period; } else if (strcmp(path, "..") == 0) { return period; } const int length = strlen(path); if ((path[length - 1] == '/') || (path[length - 1] == '\\')) { path[length - 1] = '\0'; } for (int i = (strlen(path) - 1); i >= 0; i--) { if ((path[i] == '/') || (path[i] == '\\')) { if (i == 0) { if (path[0] == '/') { path[1] = '\0'; } } else { path[i] = '\0'; } return path; } } return period; #else return dirname(path); #endif } caret-5.6.4~dfsg.1.orig/caret_common/.project0000664000175000017500000000437111572067322020703 0ustar michaelmichael caret_common org.eclipse.cdt.managedbuilder.core.genmakebuilder clean,full,incremental, ?name? org.eclipse.cdt.make.core.append_environment true org.eclipse.cdt.make.core.autoBuildTarget all org.eclipse.cdt.make.core.buildArguments org.eclipse.cdt.make.core.buildCommand make org.eclipse.cdt.make.core.cleanBuildTarget clean org.eclipse.cdt.make.core.contents org.eclipse.cdt.make.core.activeConfigSettings org.eclipse.cdt.make.core.enableAutoBuild false org.eclipse.cdt.make.core.enableCleanBuild true org.eclipse.cdt.make.core.enableFullBuild true org.eclipse.cdt.make.core.fullBuildTarget all org.eclipse.cdt.make.core.stopOnError true org.eclipse.cdt.make.core.useDefaultBuildCmd true org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder org.eclipse.cdt.core.cnature org.eclipse.cdt.core.ccnature org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature caret-5.6.4~dfsg.1.orig/caret_common/.cproject0000664000175000017500000002072211572067322021044 0ustar michaelmichael make all true true true caret-5.6.4~dfsg.1.orig/caret_command_operations/0000775000175000017500000000000011572067322021620 5ustar michaelmichaelcaret-5.6.4~dfsg.1.orig/caret_command_operations/caret_command_operations.pro0000664000175000017500000005457611572067322027422 0ustar michaelmichael###################################################################### # Automatically generated by qmake (1.04a) Tue Jan 14 11:58:13 2003 ###################################################################### !vs:TEMPLATE = lib vs:TEMPLATE=vclib TARGET = CaretCommandOperations CONFIG += staticlib INCLUDEPATH += . include(../caret_qmake_include.pro) dll { CONFIG -= staticlib CONFIG += plugin } # Input HEADERS += CommandBase.h \ CommandCaretFileNamingUnitTesting.h \ CommandCaretHelpCreateHtmlIndexFile.h \ CommandColorFileAddColor.h \ CommandCreateCiftiDenseTimeseries.h \ CommandDataFileCompare.h \ CommandCiftiCorrelationMatrix.h \ CommandConvertDataFileToCaret6.h \ CommandConvertSpecFileToCaret6.h \ CommandColorFileCreateMissingColors.h \ CommandDeformationMapApply.h \ CommandDeformationMapApplyGenericNames.h \ CommandDeformationMapCreate.h \ CommandDeformationMapPathUpdate.h \ CommandException.h \ CommandExtend.h \ CommandFileConvert.h \ CommandFileReadTime.h \ CommandFileSubstitution.h \ CommandGiftiInfo.h \ CommandImageCombine.h \ CommandImageCompare.h \ CommandImageFormatConvert.h \ CommandImageInsertText.h \ CommandImageResize.h \ CommandImageToWebPage.h \ CommandImageView.h \ CommandHelp.h \ CommandHelpFull.h \ CommandHelpGlobalOptions.h \ CommandHelpHTML.h \ CommandHelpPDF.h \ CommandHelpSearch.h \ CommandMetricClustering.h \ CommandMetricComposite.h \ CommandMetricCompositeIdentifiedColumns.h \ CommandMetricCorrelationCoefficientMap.h \ CommandMetricCorrelationMatrix.h \ CommandMetricExtrema.h \ CommandMetricFileCreate.h \ CommandMetricGradient.h \ CommandMetricROIGradient.h \ CommandMetricROIMask.h \ CommandMetricROISmoothing.h \ CommandMetricGradientAll.h \ CommandMetricInGroupDifference.h \ CommandMetricInformation.h \ CommandMetricMath.h \ CommandMetricMathPostfix.h \ CommandMetricMultipleCorrelationCoefficientMap.h \ CommandMetricSetColumnName.h \ CommandMetricSetColumnToScalar.h \ CommandMetricSmoothing.h \ CommandMetricStatisticsAnovaOneWay.h \ CommandMetricStatisticsAnovaTwoWay.h \ CommandMetricStatisticsCoordinateDifference.h \ CommandMetricStatisticsInterhemisphericClusters.h \ CommandMetricStatisticsKruskalWallis.h \ CommandMetricStatisticsLeveneMap.h \ CommandMetricStatisticsNormalization.h \ CommandMetricStatisticsOneSampleTTest.h \ CommandMetricStatisticsPairedTTest.h \ CommandMetricStatisticsShuffledCrossCorrelationMaps.h \ CommandMetricStatisticsShuffledTMap.h \ CommandMetricStatisticsSubtraceGroupAverage.h \ CommandMetricStatisticsTMap.h \ CommandMetricStatisticsTwoSampleTTest.h \ CommandMetricStatisticsZMap.h \ CommandMetricTranspose.h \ CommandMetricTwinComparison.h \ CommandMetricTwinPairedDataDiffs.h \ CommandPaintAddColumns.h \ CommandPaintAssignNodes.h \ CommandPaintAssignNodesRelativeToLine.h \ CommandPaintComposite.h \ CommandPaintDilation.h \ CommandPaintFileCreate.h \ CommandPaintLabelNameUpdate.h \ CommandPaintSetColumnName.h \ CommandPreferencesFileSettings.h \ CommandSceneCreate.h \ CommandScriptComment.h \ CommandScriptConvert.h \ CommandScriptRun.h \ CommandScriptVariableRead.h \ CommandScriptVariableSet.h \ CommandShowScene.h \ CommandShowSurface.h \ CommandShowVolume.h \ CommandSpecFileAdd.h \ CommandSpecFileChangeResolution.h \ CommandSpecFileClean.h \ CommandSpecFileCopy.h \ CommandSpecFileCreate.h \ CommandSpecFileDirectoryClean.h \ CommandSpecFileZip.h \ CommandStatisticSetRandomSeed.h \ CommandStatisticalUnitTesting.h \ CommandStereotaxicSpaces.h \ CommandStudyMetaDataFileDuplicates.h \ CommandStudyMetaDataFileValidate.h \ CommandSurfaceAffineRegression.h \ CommandSurfaceAlignToStandardOrientation.h \ CommandSurfaceApplyTransformationMatrix.h \ CommandSurfaceAverage.h \ CommandSurfaceBankStraddling.h \ CommandSurfaceBorderCreateAverage.h \ CommandSurfaceBorderCreateParallelBorder.h \ CommandSurfaceBorderCutter.h \ CommandSurfaceBorderDelete.h \ CommandSurfaceBorderDrawAroundROI.h \ CommandSurfaceBorderDrawGeodesic.h \ CommandSurfaceBorderDrawMetric.h \ CommandSurfaceBorderFileMerge.h \ CommandSurfaceBorderIntersection.h \ CommandSurfaceBorderLandmarkIdentification.h \ CommandSurfaceBorderLengths.h \ CommandSurfaceBorderLinkToFocus.h \ CommandSurfaceBorderMerge.h \ CommandSurfaceBorderNibbler.h \ CommandSurfaceBorderProjection.h \ CommandSurfaceBorderResample.h \ CommandSurfaceBorderReverse.h \ CommandSurfaceBorderSetVariability.h \ CommandSurfaceBorderToMetric.h \ CommandSurfaceBorderToPaint.h \ CommandSurfaceBorderUnprojection.h \ CommandSurfaceBorderVariability.h \ CommandSurfaceCellCreate.h \ CommandSurfaceCellProjection.h \ CommandSurfaceCellUnprojection.h \ CommandSurfaceCrossoverCheck.h \ CommandSurfaceCurvature.h \ CommandSurfaceDistortion.h \ CommandSurfaceFlatMultiResMorphing.h \ CommandSurfaceFlatten.h \ CommandSurfaceFociAttributeAssignment.h \ CommandSurfaceFociCreate.h \ CommandSurfaceFociDelete.h \ CommandSurfaceFociProjection.h \ CommandSurfaceFociProjectionPals.h \ CommandSurfaceFociReassignStudyNames.h \ CommandSurfaceFociStudyValidate.h \ CommandSurfaceFociUnprojection.h \ CommandSurfaceInflate.h \ CommandSurfaceInformation.h \ CommandSurfaceGenerateInflated.h \ CommandSurfaceGeodesic.h \ CommandSurfaceNormals.h \ CommandSurfacePlaceFociAtExtremum.h \ CommandSurfacePlaceFociAtLimits.h \ CommandSurfaceRegionOfInterestSelection.h \ CommandSurfaceRegistrationPrepareSlits.h \ CommandSurfaceRegistrationSpherical.h \ CommandSurfaceRegistrationSphericalSpecOnly.h \ CommandSurfaceRoiCoordReport.h \ CommandSurfaceRoiFoldingMeasures.h \ CommandSurfaceRoiNodeAreas.h \ CommandSurfaceRoiShapeMeasures.h \ CommandSurfaceRoiStatisticalReport.h \ CommandSurfaceSmoothing.h \ CommandSurfaceSphere.h \ CommandSurfaceSphereProjectUnproject.h \ CommandSurfaceSphericalMultiResMorphing.h \ CommandSurfaceSulcalIdentificationProbabilistic.h \ CommandSurfaceSulcalDepth.h \ CommandSurfaceIdentifySulci.h \ CommandSurfaceToCArrays.h \ CommandSurfaceToCerebralHull.h \ CommandSurfaceToSegmentationVolume.h \ CommandSurfaceToVolume.h \ CommandSurfaceTopologyDisconnectNodes.h \ CommandSurfaceTopologyNeighbors.h \ CommandSurfaceTopologyReport.h \ CommandSurfaceTransformToStandardView.h \ CommandSurfacesToSegmentationVolumeMask.h \ CommandSystemCommandExecute.h \ CommandSystemFileCopy.h \ CommandSystemFileDelete.h \ CommandTransformationMatrixCreate.h \ CommandVerify.h \ CommandVersion.h \ CommandVolumeAnatomyPeaks.h \ CommandVolumeAtlasResamplingAndSmoothing.h \ CommandVolumeBiasCorrection.h \ CommandVolumeBlur.h \ CommandVolumeClassifyIntensities.h \ CommandVolumeConvertVectorToVolume.h \ CommandVolumeCreate.h \ CommandVolumeCreateCorpusCallosumSlice.h \ CommandVolumeCreateInStereotaxicSpace.h \ CommandVolumeDilate.h \ CommandVolumeDilateErode.h \ CommandVolumeDilateErodeWithinMask.h \ CommandVolumeErode.h \ CommandVolumeEulerCount.h \ CommandVolumeFileCombine.h \ CommandVolumeFileMerge.h \ CommandVolumeFillBiggestObject.h \ CommandVolumeFillHoles.h \ CommandVolumeFillSlice.h \ CommandVolumeFindLimits.h \ CommandVolumeFloodFill.h \ CommandVolumeGradient.h \ CommandVolumeHistogram.h \ CommandVolumeImportRawFile.h \ CommandVolumeInformation.h \ CommandVolumeInformationNifti.h \ CommandVolumeMakePlane.h \ CommandVolumeMakeRectangle.h \ CommandVolumeMakeShell.h \ CommandVolumeMakeSphere.h \ CommandVolumeMapToSurface.h \ CommandVolumeMapToSurfacePALS.h \ CommandVolumeMapToSurfaceROIFile.h \ CommandVolumeMapToVtkModel.h \ CommandVolumeMaskVolume.h \ CommandVolumeMaskWithVolume.h \ CommandVolumeNearToPlane.h \ CommandVolumePadVolume.h \ CommandVolumeProbAtlasToFunctional.h \ CommandVolumeReplaceVectorMagnitudeWithVolume.h \ CommandVolumeReplaceVoxelsWithVectorMagnitude.h \ CommandVolumeRemoveIslands.h \ CommandVolumeResample.h \ CommandVolumeRescaleVoxels.h \ CommandVolumeResize.h \ CommandVolumeROIGradient.h \ CommandVolumeROIMinima.h \ CommandVolumeROISmoothing.h \ CommandVolumeScale0to255.h \ CommandVolumeScalePercent0to255.h \ CommandVolumeSculpt.h \ CommandVolumeSegmentation.h \ CommandVolumeSegmentationLigase.h \ CommandVolumeSegmentationStereotaxicSpace.h \ CommandVolumeSegmentationToCerebralHull.h \ CommandVolumeSetOrientation.h \ CommandVolumeSetOrigin.h \ CommandVolumeSetSpacing.h \ CommandVolumeShiftAxis.h \ CommandVolumeSmearAxis.h \ CommandVolumeTFCE.h \ CommandVolumeThreshold.h \ CommandVolumeThresholdDual.h \ CommandVolumeThresholdInverse.h \ CommandVolumeFslToVector.h \ CommandVolumeTopologyCorrector.h \ CommandVolumeTopologyGraph.h \ CommandVolumeTopologyReport.h \ CommandVolumeVectorCombine.h \ OffScreenOpenGLWidget.h \ ScriptBuilderParameters.h \ CommandSurfaceTopologyFixOrientation.h \ CommandCaretFileCopy.h SOURCES += CommandBase.cxx \ CommandCaretFileNamingUnitTesting.cxx \ CommandCaretHelpCreateHtmlIndexFile.cxx \ CommandCiftiCorrelationMatrix.cxx \ CommandColorFileAddColor.cxx \ CommandColorFileCreateMissingColors.cxx \ CommandConvertDataFileToCaret6.cxx \ CommandConvertSpecFileToCaret6.cxx \ CommandCreateCiftiDenseTimeseries.cxx \ CommandDataFileCompare.cxx \ CommandDeformationMapApply.cxx \ CommandDeformationMapApplyGenericNames.cxx \ CommandDeformationMapCreate.cxx \ CommandDeformationMapPathUpdate.cxx \ CommandException.cxx \ CommandExtend.cxx \ CommandFileConvert.cxx \ CommandFileReadTime.cxx \ CommandFileSubstitution.cxx \ CommandGiftiInfo.cxx \ CommandHelp.cxx \ CommandHelpFull.cxx \ CommandHelpGlobalOptions.cxx \ CommandHelpHTML.cxx \ CommandHelpPDF.cxx \ CommandHelpSearch.cxx \ CommandImageCombine.cxx \ CommandImageCompare.cxx \ CommandImageFormatConvert.cxx \ CommandImageInsertText.cxx \ CommandImageResize.cxx \ CommandImageToWebPage.cxx \ CommandImageView.cxx \ CommandMetricClustering.cxx \ CommandMetricComposite.cxx \ CommandMetricCompositeIdentifiedColumns.cxx \ CommandMetricCorrelationCoefficientMap.cxx \ CommandMetricCorrelationMatrix.cxx \ CommandMetricExtrema.cxx \ CommandMetricFileCreate.cxx \ CommandMetricGradientAll.cxx \ CommandMetricGradient.cxx \ CommandMetricROIGradient.cxx \ CommandMetricROIMask.cxx \ CommandMetricROISmoothing.cxx \ CommandMetricInGroupDifference.cxx \ CommandMetricInformation.cxx \ CommandMetricMath.cxx \ CommandMetricMathPostfix.cxx \ CommandMetricMultipleCorrelationCoefficientMap.cxx \ CommandMetricSetColumnName.cxx \ CommandMetricSetColumnToScalar.cxx \ CommandMetricSmoothing.cxx \ CommandMetricStatisticsAnovaOneWay.cxx \ CommandMetricStatisticsAnovaTwoWay.cxx \ CommandMetricStatisticsCoordinateDifference.cxx \ CommandMetricStatisticsInterhemisphericClusters.cxx \ CommandMetricStatisticsKruskalWallis.cxx \ CommandMetricStatisticsLeveneMap.cxx \ CommandMetricStatisticsNormalization.cxx \ CommandMetricStatisticsOneSampleTTest.cxx \ CommandMetricStatisticsPairedTTest.cxx \ CommandMetricStatisticsShuffledCrossCorrelationMaps.cxx \ CommandMetricStatisticsShuffledTMap.cxx \ CommandMetricStatisticsSubtraceGroupAverage.cxx \ CommandMetricStatisticsTMap.cxx \ CommandMetricStatisticsTwoSampleTTest.cxx \ CommandMetricStatisticsZMap.cxx \ CommandMetricTranspose.cxx \ CommandMetricTwinComparison.cxx \ CommandMetricTwinPairedDataDiffs.cxx \ CommandPaintAddColumns.cxx \ CommandPaintAssignNodes.cxx \ CommandPaintAssignNodesRelativeToLine.cxx \ CommandPaintComposite.cxx \ CommandPaintDilation.cxx \ CommandPaintFileCreate.cxx \ CommandPaintLabelNameUpdate.cxx \ CommandPaintSetColumnName.cxx \ CommandPreferencesFileSettings.cxx \ CommandSceneCreate.cxx \ CommandScriptComment.cxx \ CommandScriptConvert.cxx \ CommandScriptRun.cxx \ CommandScriptVariableRead.cxx \ CommandScriptVariableSet.cxx \ CommandShowScene.cxx \ CommandShowSurface.cxx \ CommandShowVolume.cxx \ CommandSpecFileAdd.cxx \ CommandSpecFileChangeResolution.cxx \ CommandSpecFileClean.cxx \ CommandSpecFileCopy.cxx \ CommandSpecFileCreate.cxx \ CommandSpecFileDirectoryClean.cxx \ CommandSpecFileZip.cxx \ CommandStatisticSetRandomSeed.cxx \ CommandStatisticalUnitTesting.cxx \ CommandStereotaxicSpaces.cxx \ CommandStudyMetaDataFileDuplicates.cxx \ CommandStudyMetaDataFileValidate.cxx \ CommandSurfaceAffineRegression.cxx \ CommandSurfaceAlignToStandardOrientation.cxx \ CommandSurfaceApplyTransformationMatrix.cxx \ CommandSurfaceAverage.cxx \ CommandSurfaceBankStraddling.cxx \ CommandSurfaceBorderCreateAverage.cxx \ CommandSurfaceBorderCreateParallelBorder.cxx \ CommandSurfaceBorderCutter.cxx \ CommandSurfaceBorderDelete.cxx \ CommandSurfaceBorderDrawAroundROI.cxx \ CommandSurfaceBorderDrawGeodesic.cxx \ CommandSurfaceBorderDrawMetric.cxx \ CommandSurfaceBorderFileMerge.cxx \ CommandSurfaceBorderIntersection.cxx \ CommandSurfaceBorderLandmarkIdentification.cxx \ CommandSurfaceBorderLengths.cxx \ CommandSurfaceBorderLinkToFocus.cxx \ CommandSurfaceBorderMerge.cxx \ CommandSurfaceBorderNibbler.cxx \ CommandSurfaceBorderProjection.cxx \ CommandSurfaceBorderResample.cxx \ CommandSurfaceBorderReverse.cxx \ CommandSurfaceBorderSetVariability.cxx \ CommandSurfaceBorderToMetric.cxx \ CommandSurfaceBorderToPaint.cxx \ CommandSurfaceBorderUnprojection.cxx \ CommandSurfaceBorderVariability.cxx \ CommandSurfaceCellCreate.cxx \ CommandSurfaceCellProjection.cxx \ CommandSurfaceCellUnprojection.cxx \ CommandSurfaceCrossoverCheck.cxx \ CommandSurfaceCurvature.cxx \ CommandSurfaceDistortion.cxx \ CommandSurfaceFlatMultiResMorphing.cxx \ CommandSurfaceFlatten.cxx \ CommandSurfaceFociAttributeAssignment.cxx \ CommandSurfaceFociCreate.cxx \ CommandSurfaceFociDelete.cxx \ CommandSurfaceFociProjection.cxx \ CommandSurfaceFociProjectionPals.cxx \ CommandSurfaceFociReassignStudyNames.cxx \ CommandSurfaceFociStudyValidate.cxx \ CommandSurfaceFociUnprojection.cxx \ CommandSurfaceGenerateInflated.cxx \ CommandSurfaceGeodesic.cxx \ CommandSurfaceIdentifySulci.cxx \ CommandSurfaceInflate.cxx \ CommandSurfaceInformation.cxx \ CommandSurfaceNormals.cxx \ CommandSurfacePlaceFociAtExtremum.cxx \ CommandSurfacePlaceFociAtLimits.cxx \ CommandSurfaceRegionOfInterestSelection.cxx \ CommandSurfaceRegistrationPrepareSlits.cxx \ CommandSurfaceRegistrationSpherical.cxx \ CommandSurfaceRegistrationSphericalSpecOnly.cxx \ CommandSurfaceRoiCoordReport.cxx \ CommandSurfaceRoiFoldingMeasures.cxx \ CommandSurfaceRoiNodeAreas.cxx \ CommandSurfaceRoiShapeMeasures.cxx \ CommandSurfaceRoiStatisticalReport.cxx \ CommandSurfaceSmoothing.cxx \ CommandSurfaceSphereProjectUnproject.cxx \ CommandSurfaceSphericalMultiResMorphing.cxx \ CommandSurfaceSulcalDepth.cxx \ CommandSurfaceSulcalIdentificationProbabilistic.cxx \ CommandSurfaceSphere.cxx \ CommandSurfaceToCArrays.cxx \ CommandSurfaceToCerebralHull.cxx \ CommandSurfaceToSegmentationVolume.cxx \ CommandSurfaceToVolume.cxx \ CommandSurfaceTopologyDisconnectNodes.cxx \ CommandSurfaceTopologyNeighbors.cxx \ CommandSurfaceTopologyReport.cxx \ CommandSurfaceTransformToStandardView.cxx \ CommandSurfacesToSegmentationVolumeMask.cxx \ CommandSystemCommandExecute.cxx \ CommandSystemFileCopy.cxx \ CommandSystemFileDelete.cxx \ CommandTransformationMatrixCreate.cxx \ CommandVerify.cxx \ CommandVersion.cxx \ CommandVolumeAnatomyPeaks.cxx \ CommandVolumeAtlasResamplingAndSmoothing.cxx \ CommandVolumeBiasCorrection.cxx \ CommandVolumeBlur.cxx \ CommandVolumeClassifyIntensities.cxx \ CommandVolumeConvertVectorToVolume.cxx \ CommandVolumeCreate.cxx \ CommandVolumeCreateCorpusCallosumSlice.cxx \ CommandVolumeCreateInStereotaxicSpace.cxx \ CommandVolumeDilate.cxx \ CommandVolumeDilateErode.cxx \ CommandVolumeDilateErodeWithinMask.cxx \ CommandVolumeErode.cxx \ CommandVolumeEulerCount.cxx \ CommandVolumeFileCombine.cxx \ CommandVolumeFileMerge.cxx \ CommandVolumeFillBiggestObject.cxx \ CommandVolumeFillHoles.cxx \ CommandVolumeFillSlice.cxx \ CommandVolumeFindLimits.cxx \ CommandVolumeFloodFill.cxx \ CommandVolumeGradient.cxx \ CommandVolumeHistogram.cxx \ CommandVolumeImportRawFile.cxx \ CommandVolumeInformation.cxx \ CommandVolumeInformationNifti.cxx \ CommandVolumeMakePlane.cxx \ CommandVolumeMakeRectangle.cxx \ CommandVolumeMakeShell.cxx \ CommandVolumeMakeSphere.cxx \ CommandVolumeMapToSurface.cxx \ CommandVolumeMapToSurfacePALS.cxx \ CommandVolumeMapToSurfaceROIFile.cxx \ CommandVolumeMapToVtkModel.cxx \ CommandVolumeMaskVolume.cxx \ CommandVolumeMaskWithVolume.cxx \ CommandVolumeNearToPlane.cxx \ CommandVolumePadVolume.cxx \ CommandVolumeProbAtlasToFunctional.cxx \ CommandVolumeReplaceVectorMagnitudeWithVolume.cxx \ CommandVolumeReplaceVoxelsWithVectorMagnitude.cxx \ CommandVolumeRemoveIslands.cxx \ CommandVolumeResample.cxx \ CommandVolumeRescaleVoxels.cxx \ CommandVolumeResize.cxx \ CommandVolumeROIGradient.cxx \ CommandVolumeROIMinima.cxx \ CommandVolumeROISmoothing.cxx \ CommandVolumeScale0to255.cxx \ CommandVolumeScalePercent0to255.cxx \ CommandVolumeSculpt.cxx \ CommandVolumeSegmentation.cxx \ CommandVolumeSegmentationLigase.cxx \ CommandVolumeSegmentationStereotaxicSpace.cxx \ CommandVolumeSegmentationToCerebralHull.cxx \ CommandVolumeSetOrientation.cxx \ CommandVolumeSetOrigin.cxx \ CommandVolumeSetSpacing.cxx \ CommandVolumeShiftAxis.cxx \ CommandVolumeSmearAxis.cxx \ CommandVolumeTFCE.cxx \ CommandVolumeThreshold.cxx \ CommandVolumeThresholdDual.cxx \ CommandVolumeThresholdInverse.cxx \ CommandVolumeFslToVector.cxx \ CommandVolumeTopologyCorrector.cxx \ CommandVolumeTopologyGraph.cxx \ CommandVolumeTopologyReport.cxx \ CommandVolumeVectorCombine.cxx \ OffScreenOpenGLWidget.cxx \ ScriptBuilderParameters.cxx \ CommandSurfaceTopologyFixOrientation.cxx \ CommandCaretFileCopy.cxx caret-5.6.4~dfsg.1.orig/caret_command_operations/ScriptBuilderParameters.h0000664000175000017500000002707711572067322026605 0ustar michaelmichael #ifndef __SCRIPT_BUILDER_PARAMTERS_H__ #define __SCRIPT_BUILDER_PARAMTERS_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include /// class for explaing a caret_commands operations to the script builder class ScriptBuilderParameters { public: /// class for storing parameters class Parameter { public: /// parameter type enum TYPE { /// boolean TYPE_BOOLEAN, /// directory TYPE_DIRECTORY, /// data file TYPE_FILE, /// multiple data files TYPE_FILE_MULTIPLE, /// flag //TYPE_FLAG, /// float TYPE_FLOAT, /// integer TYPE_INT, /// list of items TYPE_LIST_OF_ITEMS, /// string TYPE_STRING, /// structure TYPE_STRUCTURE, /// variable list TYPE_VARIABLE_LIST_OF_PARAMETERS }; /// constructor Parameter(const TYPE typeIn, const QString& descriptionIn, const QString& optionalSwitchIn = "") { type = typeIn; description = descriptionIn; optionalSwitch = optionalSwitchIn; } /// destructor ~Parameter() {}; /// get the type TYPE getType() const { return type; } /// get the description QString getDescription() const { return description; } /// get the optional switch QString getOptionalSwitch() const { return optionalSwitch; } /// get the file filter void getFileParameters(QStringList& fileFiltersOut, QString& defaultFileNameOut) const { fileFiltersOut = fileFilters; defaultFileNameOut = defaultFileName; } /// set the file filter void setFileParameters(const QStringList& fileFiltersIn, const QString& defaultFileNameIn) { fileFilters = fileFiltersIn; defaultFileName = defaultFileNameIn; } /// get float parameters void getFloatParameters(float& defaultFloatValueOut, float& minimumFloatValueOut, float& maximumFloatValueOut) const { defaultFloatValueOut = defaultFloatValue; minimumFloatValueOut = minimumFloatValue; maximumFloatValueOut = maximumFloatValue; } /// set float parameters void setFloatParameters(const float defaultFloatValueIn, const float minimumFloatValueIn, const float maximumFloatValueIn) { defaultFloatValue = defaultFloatValueIn; minimumFloatValue = minimumFloatValueIn; maximumFloatValue = maximumFloatValueIn; } /// get int parameters void getIntParameters(int& defaultIntValueOut, int& minimumIntValueOut, int& maximumIntValueOut) const { defaultIntValueOut = defaultIntValue; minimumIntValueOut = minimumIntValue; maximumIntValueOut = maximumIntValue; } /// set int parameters void setIntParameters(const int defaultIntValueIn, const int minimumIntValueIn, const int maximumIntValueIn) { defaultIntValue = defaultIntValueIn; minimumIntValue = minimumIntValueIn; maximumIntValue = maximumIntValueIn; } /// get string parameters void getStringParameters(QString& defaultStringValueOut) const { defaultStringValueOut = defaultStringValue; } /// set string parameters void setStringParameters(const QString& defaultStringValueIn) { defaultStringValue = defaultStringValueIn; } /// get variable list parameters void getVariableListParameters(QString& defaultValueOut) const { defaultValueOut = defaultVariableListValue; } /// set variable list parameters void setVariableListParameters(const QString& defaultValueIn) { defaultVariableListValue = defaultValueIn; } /// get boolean parameters void getBooleanParameters(bool& defaultBooleanValueOut) const { defaultBooleanValueOut = defaultBooleanValue; } /// set boolean parameters void setBooleanParameters(const bool defaultBooleanValueIn) { defaultBooleanValue = defaultBooleanValueIn; } /// get list of item parameters void getListOfItemParameters(std::vector& listOfItemValuesOut, std::vector& listOfItemDescriptionsOut) const { listOfItemValuesOut = listOfItemValues; listOfItemDescriptionsOut = listOfItemDescriptions; } /// set list of item parameters void setListOfItemParameters(const std::vector& listOfItemValuesIn, const std::vector& listOfItemDescriptionsIn) { listOfItemValues = listOfItemValuesIn; listOfItemDescriptions = listOfItemDescriptionsIn; } protected: /// type of parameter TYPE type; /// description of parameter QString description; /// file filter QStringList fileFilters; /// default float value float defaultFloatValue; /// minimum float value float minimumFloatValue; /// maximum float value float maximumFloatValue; /// default int value int defaultIntValue; /// minimum int value int minimumIntValue; /// maximum int value int maximumIntValue; /// default string value QString defaultStringValue; /// variable list default value QString defaultVariableListValue; /// default file name; QString defaultFileName; /// default boolean value bool defaultBooleanValue; /// list of item values std::vector listOfItemValues; /// list of item descriptions std::vector listOfItemDescriptions; /// the optional switch QString optionalSwitch; }; // constructor ScriptBuilderParameters(); // destructor ~ScriptBuilderParameters(); // add a directory void addDirectory(const QString& descriptionIn); // add a float parameters void addFloat(const QString& descriptionIn, const float defaultValueIn = 0.0, const float minimumValueIn = -std::numeric_limits::max(), const float maximumValueIn = std::numeric_limits::max()); // add an int parameter void addInt(const QString& descriptionIn, const int defaultValueIn = 0, const int minimumValueIn = std::numeric_limits::min(), const int maximumValueIn = std::numeric_limits::max()); // add a file void addFile(const QString& descriptionIn, const QStringList& fileFiltersIn, const QString& defaultFileName = "", const QString& optionalSwitchIn = ""); // add a file void addFile(const QString& descriptionIn, const QString& fileFilterIn, const QString& defaultFileName = "", const QString& optionalSwitchIn = ""); // add multiple files void addMultipleFiles(const QString& descriptionIn, const QString& fileFilterIn, const QString& defaultFileName = ""); // add multiple files void addMultipleFiles(const QString& descriptionIn, const QStringList& fileFiltersIn, const QString& defaultFileName = ""); // add a flag //void addFlag(const QString& descriptionIn); // add a list of items void addListOfItems(const QString& descriptionIn, const std::vector& listOfItemValuesIn, const std::vector& listOfItemDescriptionsIn); // add a string parameter void addString(const QString& descriptionIn, const QString& defaultValueIn = ""); // add variable list of parameters void addVariableListOfParameters(const QString& descriptionIn, const QString& defaultValueIn = ""); // add a boolean parameter void addBoolean(const QString& descriptionIn, const bool defaultValueIn = false); // add structure names void addStructure(const QString& descriptionIn); // clear current parameters void clear(); // get the number of parameters int getNumberOfParameters() const { return parameters.size(); } // get a parameter const Parameter* getParameter(const int indx) const { return ¶meters[indx]; } protected: /// the parameters std::vector parameters; }; #endif // __SCRIPT_BUILDER_PARAMTERS_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/ScriptBuilderParameters.cxx0000664000175000017500000001446111572067322027151 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "ScriptBuilderParameters.h" /** * constructor. */ ScriptBuilderParameters::ScriptBuilderParameters() { } /** * destructor. */ ScriptBuilderParameters::~ScriptBuilderParameters() { } /** * add a float parameters. */ void ScriptBuilderParameters::addFloat(const QString& descriptionIn, const float defaultValueIn, const float minimumValueIn, const float maximumValueIn) { Parameter p(Parameter::TYPE_FLOAT, descriptionIn); p.setFloatParameters(defaultValueIn, minimumValueIn, maximumValueIn); parameters.push_back(p); } /** * add an int parameter. */ void ScriptBuilderParameters::addInt(const QString& descriptionIn, const int defaultValueIn, const int minimumValueIn, const int maximumValueIn) { Parameter p(Parameter::TYPE_INT, descriptionIn); p.setIntParameters(defaultValueIn, minimumValueIn, maximumValueIn); parameters.push_back(p); } /** * add a string parameter. */ void ScriptBuilderParameters::addString(const QString& descriptionIn, const QString& defaultValueIn) { Parameter p(Parameter::TYPE_STRING, descriptionIn); p.setStringParameters(defaultValueIn); parameters.push_back(p); } /** * add a file. */ void ScriptBuilderParameters::addFile(const QString& descriptionIn, const QStringList& fileFiltersIn, const QString& defaultFileName, const QString& optionalSwitchIn) { Parameter p(Parameter::TYPE_FILE, descriptionIn, optionalSwitchIn); p.setFileParameters(fileFiltersIn, defaultFileName); parameters.push_back(p); } /** * add a directory. */ void ScriptBuilderParameters::addDirectory(const QString& descriptionIn) { Parameter p(Parameter::TYPE_DIRECTORY, descriptionIn); parameters.push_back(p); } /** * add a file. */ void ScriptBuilderParameters::addFile(const QString& descriptionIn, const QString& fileFilterIn, const QString& defaultFileName, const QString& optionalSwitchIn) { Parameter p(Parameter::TYPE_FILE, descriptionIn, optionalSwitchIn); p.setFileParameters(QStringList(fileFilterIn), defaultFileName); parameters.push_back(p); } /** * add multiple files. */ void ScriptBuilderParameters::addMultipleFiles(const QString& descriptionIn, const QStringList& fileFiltersIn, const QString& defaultFileName) { Parameter p(Parameter::TYPE_FILE_MULTIPLE, descriptionIn); p.setFileParameters(fileFiltersIn, defaultFileName); parameters.push_back(p); } /** * add multiple files. */ void ScriptBuilderParameters::addMultipleFiles(const QString& descriptionIn, const QString& fileFilterIn, const QString& defaultFileName) { Parameter p(Parameter::TYPE_FILE_MULTIPLE, descriptionIn); p.setFileParameters(QStringList(fileFilterIn), defaultFileName); parameters.push_back(p); } /** * add a boolean parameter. */ void ScriptBuilderParameters::addBoolean(const QString& descriptionIn, const bool defaultValueIn) { Parameter p(Parameter::TYPE_BOOLEAN, descriptionIn); p.setBooleanParameters(defaultValueIn); parameters.push_back(p); } /** * add a flag. */ /* void ScriptBuilderParameters::addFlag(const QString& descriptionIn) { Parameter p(Parameter::TYPE_FLAG, descriptionIn); parameters.push_back(p); } */ /** * add a list of items. */ void ScriptBuilderParameters::addListOfItems(const QString& descriptionIn, const std::vector& listOfItemValuesIn, const std::vector& listOfItemDescriptionsIn) { Parameter p(Parameter::TYPE_LIST_OF_ITEMS, descriptionIn); p.setListOfItemParameters(listOfItemValuesIn, listOfItemDescriptionsIn); parameters.push_back(p); } /** * add variable list of parameters. */ void ScriptBuilderParameters::addVariableListOfParameters(const QString& descriptionIn, const QString& defaultValueIn) { Parameter p(Parameter::TYPE_VARIABLE_LIST_OF_PARAMETERS, descriptionIn); p.setVariableListParameters(defaultValueIn); parameters.push_back(p); } /** * add structure names. */ void ScriptBuilderParameters::addStructure(const QString& descriptionIn) { Parameter p(Parameter::TYPE_STRUCTURE, descriptionIn); parameters.push_back(p); } /** * clear current parameters. */ void ScriptBuilderParameters::clear() { parameters.clear(); } //=============================================================================== caret-5.6.4~dfsg.1.orig/caret_command_operations/OffScreenOpenGLWidget.h0000664000175000017500000000401311572067322026052 0ustar michaelmichael #ifndef __OFF_SCREEN_OPENGL_WIDGET_H__ #define __OFF_SCREEN_OPENGL_WIDGET_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include class BrainModel; class BrainSet; /// widget for off screen OpenGL rendering to an image class OffScreenOpenGLWidget : public QGLWidget { public: // constructor OffScreenOpenGLWidget(QWidget* parent = 0, Qt::WFlags f = 0); // destructor ~OffScreenOpenGLWidget(); // draw to an image void drawToImage(BrainSet* bs, BrainModel* bm, QImage& imageOut); protected: // initialize void initializeGL(); // handle resize event void resizeGL(int width, int height); // draw the scene void paintGL(); /// the brain set; BrainSet* brainSet; /// the brain model; BrainModel* brainModel; /// the brain model renderer BrainModelOpenGL* openGL; /// width of window int windowWidth; /// height of window int windowHeight; }; #endif // __OFF_SCREEN_OPENGL_WIDGET_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/OffScreenOpenGLWidget.cxx0000664000175000017500000000734211572067322026435 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include "BrainModelOpenGL.h" #include "BrainSet.h" #include "OffScreenOpenGLWidget.h" #include "PreferencesFile.h" /** * constructor. */ OffScreenOpenGLWidget::OffScreenOpenGLWidget(QWidget* parent, Qt::WFlags f) : QGLWidget(parent, NULL, f) { openGL = new BrainModelOpenGL; } /** * destructor. */ OffScreenOpenGLWidget::~OffScreenOpenGLWidget() { delete openGL; openGL = NULL; } /** * draw to an image (returns true if successful). */ void OffScreenOpenGLWidget::drawToImage(BrainSet* bs, BrainModel* bm, QImage& imageOut) { resizeGL(width(), height()); brainSet = bs; brainModel = bm; imageOut = QImage(); // ".reset()" should not be used PreferencesFile* pf = brainSet->getPreferencesFile(); brainSet->setDisplaySplashImage(false); double orthoLeft, orthoRight, orthoBottom, orthoTop, orthoNear, orthoFar; openGL->getOrthographicBox(0, orthoLeft, orthoRight, orthoBottom, orthoTop, orthoNear, orthoFar); brainSet->setDefaultScaling(orthoRight, orthoTop); // // Display lists do not work during screen capture - do not know why. // brainSet->clearAllDisplayLists(); pf->setDisplayListsEnabled(false); updateGL(); updateGL(); PreferencesFile::IMAGE_CAPTURE_TYPE captureType = pf->getImageCaptureType(); #ifdef Q_OS_LINUX // // Only PIXMAP works on LINUX // captureType = PreferencesFile::IMAGE_CAPTURE_PIXMAP; #endif // Q_OS_LINUX switch(captureType) { case PreferencesFile::IMAGE_CAPTURE_PIXMAP: { imageOut = renderPixmap().toImage(); } break; case PreferencesFile::IMAGE_CAPTURE_OPENGL_BUFFER: { updateGL(); imageOut = grabFrameBuffer(); } break; } } /** * initialize. */ void OffScreenOpenGLWidget::initializeGL() { openGL->initializeOpenGL(true); } /** * handle resize event. */ void OffScreenOpenGLWidget::resizeGL(int widthIn, int heightIn) { windowWidth = widthIn; windowHeight = heightIn; if (windowWidth <= 0) { windowWidth = width(); } if (windowHeight <= 0) { windowHeight = height(); } openGL->updateOrthoSize(0, windowWidth, windowHeight); } /** * draw the scene. */ void OffScreenOpenGLWidget::paintGL() { int viewport[4] = { 0, 0, windowWidth, windowHeight }; openGL->drawBrainModelWebCaret(brainSet, brainModel, 0, viewport); // openGL->drawBrainModel(brainSet, // brainModel, // 0, // viewport, // this); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeVectorCombine.h0000664000175000017500000000346511572067322027227 0ustar michaelmichael #ifndef __COMMAND_VOLUME_VECTOR_COMBINE_H__ #define __COMMAND_VOLUME_VECTOR_COMBINE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for combining vector volume files class CommandVolumeVectorCombine : public CommandBase { public: // constructor CommandVolumeVectorCombine(); // destructor ~CommandVolumeVectorCombine(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_VECTOR_COMBINE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeVectorCombine.cxx0000664000175000017500000001246011572067322027575 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeVectorCombine.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SureFitVectorFile.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeVectorCombine::CommandVolumeVectorCombine() : CommandBase("-volume-vector-combine", "VOLUME VECTOR FILES COMBINE") { } /** * destructor. */ CommandVolumeVectorCombine::~CommandVolumeVectorCombine() { } /** * get the script builder parameters. */ void CommandVolumeVectorCombine::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { std::vector values, descriptions; values.push_back("DOT_SQRT_RECT_MINUS"); descriptions.push_back("DOT_SQRT_RECT_MINUS"); values.push_back("2_VEC_NORMAL"); descriptions.push_back("2_VEC_NORMAL"); values.push_back("2_VEC"); descriptions.push_back("2_VEC"); paramsOut.clear(); paramsOut.addFile("Input Vector File 1 Name", FileFilters::getSureFitVectorFileFilter()); paramsOut.addFile("Input Vector File 2 Name", FileFilters::getSureFitVectorFileFilter()); paramsOut.addFile("Output Vector File Name", FileFilters::getSureFitVectorFileFilter()); paramsOut.addFile("Mask Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addListOfItems("Operation", values, descriptions); paramsOut.addBoolean("Mask Flag"); } /** * get full help information. */ QString CommandVolumeVectorCombine::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Combine vector files.\n" + indent9 + " \"operation\" is one of:\n" + indent9 + " DOT_SQRT_RECT_MINUS\n" + indent9 + " 2_VEC_NORMAL\n" + indent9 + " 2_VEC\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeVectorCombine::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputVectorFile1Name = parameters->getNextParameterAsString("Input Vector File 1 Name"); const QString inputVectorFile2Name = parameters->getNextParameterAsString("Input Vector File 2 Name"); const QString outputVectorFileName = parameters->getNextParameterAsString("Output Vector File Name"); const QString maskVolumeFileName = parameters->getNextParameterAsString("Mask Volume File Name"); const QString operationString = parameters->getNextParameterAsString("Operation").toUpper(); const bool maskFlag = parameters->getNextParameterAsBoolean("Mask Flag"); checkForExcessiveParameters(); SureFitVectorFile::COMBINE_OPERATION operation; if (operationString == "DOT_SQRT_RECT_MINUS") { operation = SureFitVectorFile::COMBINE_OPERATION_DOT_SQRT_RECT_MINUS; } else if (operationString == "2_VEC_NORMAL") { operation = SureFitVectorFile::COMBINE_OPERATION_2_VEC_NORMAL; } else if (operationString == "2_VEC") { operation = SureFitVectorFile::COMBINE_OPERATION_2_VEC; } else { throw CommandException("Invalid operation \"" + operationString + "\""); } // // Read the input files // SureFitVectorFile vector1; vector1.readFile(inputVectorFile1Name); SureFitVectorFile vector2; vector2.readFile(inputVectorFile2Name); VolumeFile maskVolume; maskVolume.readFile(maskVolumeFileName); // // Create the output vector file // SureFitVectorFile outputVector = vector1; // // combine vectors // SureFitVectorFile::combineVectorFiles(maskFlag, operation, &vector1, &vector2, &maskVolume, &outputVector); // // Write the vector file // outputVector.writeFile(outputVectorFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeTopologyReport.h0000664000175000017500000000347111572067322027475 0ustar michaelmichael #ifndef __COMMAND_VOLUME_TOPOLOGY_REPORT_H__ #define __COMMAND_VOLUME_TOPOLOGY_REPORT_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for generating a topology report class CommandVolumeTopologyReport : public CommandBase { public: // constructor CommandVolumeTopologyReport(); // destructor ~CommandVolumeTopologyReport(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_TOPOLOGY_REPORT_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeTopologyReport.cxx0000664000175000017500000000666211572067322030055 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "CommandVolumeTopologyReport.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeTopologyReport::CommandVolumeTopologyReport() : CommandBase("-volume-topology-report", "VOLUME TOPOLOGY REPORT") { } /** * destructor. */ CommandVolumeTopologyReport::~CommandVolumeTopologyReport() { } /** * get the script builder parameters. */ void CommandVolumeTopologyReport::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Segmentation Volume File", FileFilters::getVolumeSegmentationFileFilter()); } /** * get full help information. */ QString CommandVolumeTopologyReport::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "List topology information about the volume by measuring\n" + indent9 + "the topology on a surface generated from the input\n" + indent9 + "segmentation volume file.\n" + indent9 + "\n" + indent9 + "Note: any cavities are filled prior to determining the\n" + indent9 + "Euler Count, Objects, and Holes (handles).\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeTopologyReport::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputSegmentationVolumeFileName = parameters->getNextParameterAsString("Segmentation Volume File Name"); VolumeFile segmentationVolumeFile; segmentationVolumeFile.readFile(inputSegmentationVolumeFileName); int numberOfObjects, numberOfCavities, numberOfHoles, eulerCount; segmentationVolumeFile.getSegmentationTopologyInformation( numberOfObjects, numberOfCavities, numberOfHoles, eulerCount); std::cout << "Objects: " << numberOfObjects << std::endl; std::cout << "Cavities: " << numberOfCavities << std::endl; std::cout << "Holes (handles): " << numberOfHoles << std::endl; std::cout << "Euler Count: " << eulerCount << std::endl; } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeTopologyGraph.h0000664000175000017500000000342711572067322027264 0ustar michaelmichael #ifndef __COMMAND_VOLUME_TOPOLOGY_GRAPH_H__ #define __COMMAND_VOLUME_TOPOLOGY_GRAPH_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandVolumeTopologyGraph : public CommandBase { public: // constructor CommandVolumeTopologyGraph(); // destructor ~CommandVolumeTopologyGraph(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_TOPOLOGY_GRAPH_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeTopologyGraph.cxx0000664000175000017500000002242211572067322027633 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelVolumeTopologyGraph.h" #include "BrainSet.h" #include "CommandVolumeTopologyGraph.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeTopologyGraph::CommandVolumeTopologyGraph() : CommandBase("-volume-topology-graph", "VOLUME TOPOLOGY GRAPH (in development - do not use)") { } /** * destructor. */ CommandVolumeTopologyGraph::~CommandVolumeTopologyGraph() { } /** * get the script builder parameters. */ void CommandVolumeTopologyGraph::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { std::vector xyz; xyz.push_back("X"); xyz.push_back("Y"); xyz.push_back("Z"); std::vector neighbors; neighbors.push_back("6"); neighbors.push_back("18"); neighbors.push_back("26"); std::vector foregroundBackground; foregroundBackground.push_back("FG"); foregroundBackground.push_back("BG"); paramsOut.clear(); paramsOut.addFile("Input Segmentation Volume File Name", FileFilters::getVolumeSegmentationFileFilter()); paramsOut.addListOfItems("AXIS (X/Y/Z)", xyz, xyz); paramsOut.addListOfItems("Neighbors", neighbors, neighbors); paramsOut.addListOfItems("Foreground/Background", foregroundBackground, foregroundBackground); paramsOut.addFile("GraphViz File", "GraphViz File (*.dot)", "graph.dot", "-graphviz-dot-file"); paramsOut.addFile("Graph Paint File", FileFilters::getVolumePaintFileFilter(), "graph.nii.gz", "-graph-paint-volume"); paramsOut.addFile("Handles Paint File", FileFilters::getVolumePaintFileFilter(), "handles.nii.gz", "-handles-paint-volume"); } /** * get full help information. */ QString CommandVolumeTopologyGraph::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-graphviz-dot-file ]\n" + indent9 + "[-graph-paint-volume ]\n" + indent9 + "[-handles-paint-volume ]\n" + indent9 + "\n" + indent9 + "Generaete segmentation volume topology graph.\n" + indent9 + "\n" + indent9 + "Search-Axis is one of:\n" + indent9 + " X\n" + indent9 + " Y\n" + indent9 + " Z\n" + indent9 + "\n" + indent9 + "Neighbor-Connectivity is one of:\n" + indent9 + " 6\n" + indent9 + " 18\n" + indent9 + " 26\n" + indent9 + "\n" + indent9 + "Foreground-or-Background is one of\n" + indent9 + " FG Compute graph of volume.\n" + indent9 + " BG Compute graph of inverse volume.\n" + indent9 + "\n" + indent9 + "\"-graphviz-dot-file\" allows the creation of a \".dot\"\n" + indent9 + "for use with a GraphVis program\n" + indent9 + " (http::graphviz.org).\n" + indent9 + "Run \"neato -Tpdf -o graph.pdf graph.dot\" to create a\n" + indent9 + "PDF file containing the graph.\n" + indent9 + "\n" + indent9 + "\"-graph-paint-volume\" allows the creation of a paint\n" + indent9 + "volume with each graph vertex given an paint identifier.\n" + indent9 + "\n" + indent9 + "\"-handles-paint-volume\" allows the creation of a paint\n" + indent9 + "volume identifying the \"handle-part\" of the handle.\n" + indent9 + "\n" + indent9 + "Note: Names assigned to vertices are identical for the\n" + indent9 + " \"-graphviz-dot-file\" and -graph-paint-volume\" options.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeTopologyGraph::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get parameters // const QString segmentationVolumeFileName = parameters->getNextParameterAsString("Input Segmentation Volume File Name"); const QString axisName = parameters->getNextParameterAsString("Search Axis Name"); const QString neighborConnectivity = parameters->getNextParameterAsString("Neighbor Connectivity"); const QString foregroundBackground = parameters->getNextParameterAsString("Foreground/Background"); QString graphvizFileName; QString graphVolumeFileName; QString handlesVolumeFileName; while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("Optional Parameter"); if (paramName == "-graphviz-dot-file") { graphvizFileName = parameters->getNextParameterAsString("GraphViz File Name"); } else if (paramName == "-graph-paint-volume") { graphVolumeFileName = parameters->getNextParameterAsString("Graph Paint Volume File Name"); } else if (paramName == "-handles-paint-volume") { handlesVolumeFileName = parameters->getNextParameterAsString("Handles Paint Volume File Name"); } else { throw CommandException("Unrecognized Parameter: " + paramName); } } // // Set search axis // BrainModelVolumeTopologyGraph::SEARCH_AXIS searchAxis = BrainModelVolumeTopologyGraph::SEARCH_AXIS_Z; if (axisName == "X") { searchAxis = BrainModelVolumeTopologyGraph::SEARCH_AXIS_X; } else if (axisName == "Y") { searchAxis = BrainModelVolumeTopologyGraph::SEARCH_AXIS_Y; } else if (axisName == "Z") { searchAxis = BrainModelVolumeTopologyGraph::SEARCH_AXIS_Z; } else { throw CommandException("Invalid Search Axis: " + axisName); } // // Neighbor connectivity // BrainModelVolumeTopologyGraph::VOXEL_NEIGHBOR_CONNECTIVITY neighbors = BrainModelVolumeTopologyGraph::VOXEL_NEIGHBOR_CONNECTIVITY_6; if (neighborConnectivity == "6") { neighbors = BrainModelVolumeTopologyGraph::VOXEL_NEIGHBOR_CONNECTIVITY_6; } else if (neighborConnectivity == "18") { neighbors = BrainModelVolumeTopologyGraph::VOXEL_NEIGHBOR_CONNECTIVITY_18; } else if (neighborConnectivity == "26") { neighbors = BrainModelVolumeTopologyGraph::VOXEL_NEIGHBOR_CONNECTIVITY_26; } else { throw CommandException("Invalid Neighbor Connectivity: " + neighborConnectivity); } // // Foreground/Background // bool doForegroundFlag = true; if (foregroundBackground == "FG") { doForegroundFlag = true; } else if (foregroundBackground == "BG") { doForegroundFlag = false; } else { throw CommandException("Invalid Foreground/Background: " + foregroundBackground); } // // Read volume // VolumeFile segmentationVolumeFile; segmentationVolumeFile.readFile(segmentationVolumeFileName); if (doForegroundFlag == false) { segmentationVolumeFile.invertSegmentationVoxels(); } // // Create graph of foreground // BrainSet bs; BrainModelVolumeTopologyGraph graph(&bs, &segmentationVolumeFile, searchAxis, neighbors); QTime timer; timer.start(); graph.execute(); const float totalTime = (static_cast(timer.elapsed()) * 0.001); graph.printResults(); if (graphvizFileName.isEmpty() == false) { graph.writeGraphVizDotFile(graphvizFileName); } if (graphVolumeFileName.isEmpty() == false) { graph.writeGraphToPaintVolumeFile(graphVolumeFileName); } if (handlesVolumeFileName.isEmpty() == false) { VolumeFile handlesVolume; graph.createHandlesPaintVolumeFile(handlesVolume); handlesVolume.writeFile(handlesVolumeFileName); } std::cout << "Time to compute graph: " << totalTime << " seconds." << std::endl; } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeTopologyCorrector.h0000664000175000017500000000345711572067322030170 0ustar michaelmichael #ifndef __COMMAND_VOLUME_TOPOLOGY_CORRECTOR_H__ #define __COMMAND_VOLUME_TOPOLOGY_CORRECTOR_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandVolumeTopologyCorrector : public CommandBase { public: // constructor CommandVolumeTopologyCorrector(); // destructor ~CommandVolumeTopologyCorrector(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_TOPOLOGY_CORRECTOR_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeTopologyCorrector.cxx0000664000175000017500000001512011572067322030531 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainModelVolumeTopologyGraphCorrector.h" #include "BrainSet.h" #include "CommandVolumeTopologyCorrector.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeTopologyCorrector::CommandVolumeTopologyCorrector() : CommandBase("-volume-topology-corrector", "VOLUME TOPOLOGY CORRECTOR (in development - do not use)") { } /** * destructor. */ CommandVolumeTopologyCorrector::~CommandVolumeTopologyCorrector() { } /** * get the script builder parameters. */ void CommandVolumeTopologyCorrector::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { std::vector mode; mode.push_back("NORMAL"); mode.push_back("MINIMAL"); paramsOut.clear(); paramsOut.addFile("Input Segmentation Volume File Name", FileFilters::getVolumeSegmentationFileFilter()); paramsOut.addFile("Output Corrected Segmentation Volume File Name", FileFilters::getVolumeSegmentationFileFilter()); paramsOut.addListOfItems("Mode", mode, mode); paramsOut.addFile("Paint Volume File Showing Corrections", FileFilters::getVolumePaintFileFilter(), "corrections.nii.gz", "-correction-paint-volume"); } /** * get full help information. */ QString CommandVolumeTopologyCorrector::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-correction-paint-volume ]\n" + indent9 + "\n" + indent9 + "Correct segmentation volume topology.\n" + indent9 + "\n" + indent9 + "correction-mode is one of:\n" + indent9 + " MINIMAL fix minimal number of voxels\n" + indent9 + " NORMAL normal correction\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeTopologyCorrector::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get parameters // const QString segmentationVolumeFileName = parameters->getNextParameterAsString("Input Segmentation Volume File Name"); const QString correctedSegmentationVolumeFileName = parameters->getNextParameterAsString("Corrected Output Segmentation Volume File Name"); const QString correctionModeString = parameters->getNextParameterAsString("Corrected Mode"); QString correctionsPaintVolumeFileName; while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("Optional Parameter"); if (paramName == "-correction-paint-volume") { correctionsPaintVolumeFileName = parameters->getNextParameterAsString("Paint Volume File Showing Corrections Name"); } else { throw CommandException("Unrecognized Parameter: " + paramName); } } // // Set the correction mode // BrainModelVolumeTopologyGraphCorrector::CORRECTION_MODE correctionMode = BrainModelVolumeTopologyGraphCorrector::CORRECTION_MODE_NORMAL; if (correctionModeString == "MINIMAL") { correctionMode = BrainModelVolumeTopologyGraphCorrector::CORRECTION_MODE_MINIMAL; } else if (correctionModeString == "NORMAL") { correctionMode = BrainModelVolumeTopologyGraphCorrector::CORRECTION_MODE_NORMAL; } else { throw CommandException("Invalid correction mode: " + correctionModeString); } // // Read volume // VolumeFile segmentationVolumeFile; segmentationVolumeFile.readFile(segmentationVolumeFileName); // // Create graph of foreground // BrainSet bs; BrainModelVolumeTopologyGraphCorrector corrector(&bs, correctionMode, &segmentationVolumeFile); QTime timer; timer.start(); corrector.execute(); const float totalTime = (static_cast(timer.elapsed()) * 0.001); // // Save corrected volume file // if (corrector.getCorrectedSegmentationVolumeFile() != NULL) { VolumeFile correctedVolumeFile(*corrector.getCorrectedSegmentationVolumeFile()); correctedVolumeFile.writeFile(correctedSegmentationVolumeFileName); } if (correctionsPaintVolumeFileName.isEmpty() == false) { VolumeFile* paintVol = new VolumeFile(*corrector.getShowingCorrectionsPaintVolumeFile()); if (paintVol != NULL) { paintVol->writeFile(correctionsPaintVolumeFileName); delete paintVol; } } // // Print percent changed // const int numVoxels = segmentationVolumeFile.getTotalNumberOfVoxels(); const int numChanged = corrector.getNumberOfVoxelsChanged(); const float percentChanged = (static_cast(numChanged) / static_cast(numVoxels)) * 100.0; std::cout << numChanged << " of " << numVoxels << " (" << percentChanged << "%) voxels changed in correction." << std::endl; std::cout << "Time to correct volume topology: " << totalTime << " seconds." << std::endl; } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeThresholdInverse.h0000664000175000017500000000351411572067322027753 0ustar michaelmichael #ifndef __COMMAND_VOLUME_THRESHOLD_INVERSE_H__ #define __COMMAND_VOLUME_THRESHOLD_INVERSE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for inverse thresholding a volume file class CommandVolumeThresholdInverse : public CommandBase { public: // constructor CommandVolumeThresholdInverse(); // destructor ~CommandVolumeThresholdInverse(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_THRESHOLD_INVERSE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeThresholdInverse.cxx0000664000175000017500000000701711572067322030330 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeThresholdInverse.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeThresholdInverse::CommandVolumeThresholdInverse() : CommandBase("-volume-threshold-inverse", "VOLUME THRESHOLDING INVERSE") { } /** * destructor. */ CommandVolumeThresholdInverse::~CommandVolumeThresholdInverse() { } /** * get the script builder parameters. */ void CommandVolumeThresholdInverse::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Output Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFloat("Threshold Value", 128); } /** * get full help information. */ QString CommandVolumeThresholdInverse::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Threshold a volume.\n" + indent9 + "\n" + indent9 + "Voxels greater than the threshold value are set to zero and\n" + indent9 + "all other voxels are set to 255.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeThresholdInverse::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); QString outputVolumeFileName, outputVolumeFileLabel; parameters->getNextParameterAsVolumeFileNameAndLabel("Output Volume File Name/Label", outputVolumeFileName, outputVolumeFileLabel); const float threshold = parameters->getNextParameterAsFloat("Threshold"); // // Read the input file // VolumeFile volume; volume.readFile(inputVolumeFileName); // // Inverse Threshold the volume // volume.inverseThresholdVolume(threshold); // // Write the volume // writeVolumeFile(volume, outputVolumeFileName, outputVolumeFileLabel); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeThresholdDual.h0000664000175000017500000000346711572067322027234 0ustar michaelmichael #ifndef __COMMAND_VOLUME_THRESHOLD_DUAL_H__ #define __COMMAND_VOLUME_THRESHOLD_DUAL_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for dual thresholding a volume file class CommandVolumeThresholdDual : public CommandBase { public: // constructor CommandVolumeThresholdDual(); // destructor ~CommandVolumeThresholdDual(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_THRESHOLD_DUAL_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeThresholdDual.cxx0000664000175000017500000000731611572067322027604 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeThresholdDual.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeThresholdDual::CommandVolumeThresholdDual() : CommandBase("-volume-threshold-dual", "VOLUME THRESHOLDING DUAL") { } /** * destructor. */ CommandVolumeThresholdDual::~CommandVolumeThresholdDual() { } /** * get the script builder parameters. */ void CommandVolumeThresholdDual::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Output Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFloat("Threshold Low Value", 127); paramsOut.addFloat("Threshold High Value", 128); } /** * get full help information. */ QString CommandVolumeThresholdDual::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Threshold a volume file.\n" + indent9 + "\n" + indent9 + "Voxels between the low and high threshold values are set \n" + indent9 + "to 255 and all other voxels are set to zero.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeThresholdDual::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); QString outputVolumeFileName, outputVolumeFileLabel; parameters->getNextParameterAsVolumeFileNameAndLabel("Output Volume File Name/Label", outputVolumeFileName, outputVolumeFileLabel); const float thresholdLow = parameters->getNextParameterAsFloat("Low Threshold"); const float thresholdHigh = parameters->getNextParameterAsFloat("High Threshold"); // // Read the input file // VolumeFile volume; volume.readFile(inputVolumeFileName); // // Threshold the volume // volume.dualThresholdVolume(thresholdLow, thresholdHigh); // // Write the volume // writeVolumeFile(volume, outputVolumeFileName, outputVolumeFileLabel); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeThreshold.h0000664000175000017500000000342711572067322026422 0ustar michaelmichael #ifndef __COMMAND_VOLUME_THRESHOLD_H__ #define __COMMAND_VOLUME_THRESHOLD_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for thresholding a volume file class CommandVolumeThreshold : public CommandBase { public: // constructor CommandVolumeThreshold(); // destructor ~CommandVolumeThreshold(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_THRESHOLD_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeThreshold.cxx0000664000175000017500000000666411572067322027003 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeThreshold.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeThreshold::CommandVolumeThreshold() : CommandBase("-volume-threshold", "VOLUME THRESHOLDING") { } /** * destructor. */ CommandVolumeThreshold::~CommandVolumeThreshold() { } /** * get the script builder parameters. */ void CommandVolumeThreshold::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Output Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFloat("Threshold Value", 128); } /** * get full help information. */ QString CommandVolumeThreshold::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Threshold a volume.\n" + indent9 + "\n" + indent9 + "Voxels less than the threshold value are set to zero and\n" + indent9 + "all other voxels are set to 255.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeThreshold::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); QString outputVolumeFileName, outputVolumeFileLabel; parameters->getNextParameterAsVolumeFileNameAndLabel("Output Volume File Name/Label", outputVolumeFileName, outputVolumeFileLabel); const float threshold = parameters->getNextParameterAsFloat("Threshold"); // // Read the input file // VolumeFile volume; volume.readFile(inputVolumeFileName); // // Threshold the volume // volume.thresholdVolume(threshold); // // Write the volume // writeVolumeFile(volume, outputVolumeFileName, outputVolumeFileLabel); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeTFCE.h0000664000175000017500000000333611572067322025206 0ustar michaelmichael #ifndef __COMMAND_VOLUME_TFCE_H__ #define __COMMAND_VOLUME_TFCE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandVolumeTFCE : public CommandBase { public: // constructor CommandVolumeTFCE(); // destructor ~CommandVolumeTFCE(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_TFCE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeTFCE.cxx0000664000175000017500000001366411572067322025566 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "CommandVolumeTFCE.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "BrainModelVolumeTFCE.h" #include "BrainSet.h" #include "StringUtilities.h" /** * constructor. */ CommandVolumeTFCE::CommandVolumeTFCE() : CommandBase("-volume-TFCE", "VOLUME THRESHHOLD FREE CLUSTER ENHANCEMENT") { } /** * destructor. */ CommandVolumeTFCE::~CommandVolumeTFCE() { } /** * get the script builder parameters. */ void CommandVolumeTFCE::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input functional volume file name", FileFilters::getVolumeFunctionalFileFilter()); paramsOut.addFile("Output funtional volume file name", FileFilters::getVolumeFunctionalFileFilter()); paramsOut.addString("Output volume label"); paramsOut.addInt("Number of steps to approximate integral", BrainModelVolumeTFCE::defaultNumSteps(), 1); paramsOut.addFloat("E (power to raise cluster mass to)", BrainModelVolumeTFCE::defaultE()); paramsOut.addFloat("H (power to raise threshhold to)", BrainModelVolumeTFCE::defaultH()); } /** * get full help information. */ QString CommandVolumeTFCE::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[number-of-steps = " + StringUtilities::fromNumber(BrainModelVolumeTFCE::defaultNumSteps()) + "]\n" + indent9 + "[E = " + StringUtilities::fromNumber(BrainModelVolumeTFCE::defaultE()) + "]\n" + indent9 + "[H = " + StringUtilities::fromNumber(BrainModelVolumeTFCE::defaultH()) + "]\n" + indent9 + "\n" + indent9 + "Enhance clusterlike signal using Threshhold Free Cluster Enhancement\n" + indent9 + "\n" + indent9 + " Optional parameters: (default value specified above)\n" + indent9 + " number-of-steps number of pieces used to approximate the integral\n" + indent9 + " using the value at the center of a piece as the\n" + indent9 + " height of the piece.\n" + indent9 + "\n" + indent9 + " E the power to raise the cluster mass (number of voxels) to in the\n" + indent9 + " integral.\n" + indent9 + "\n" + indent9 + " H the power to raise the threshhold to in the integral.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeTFCE::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Functional Volume File Name"); const QString outputVolumeFileName = parameters->getNextParameterAsString("Output Functional Volume File Name"); const QString outputVolumeLabel = parameters->getNextParameterAsString("Output Functional Volume Label"); int numSteps = BrainModelVolumeTFCE::defaultNumSteps(); float E = BrainModelVolumeTFCE::defaultE(), H = BrainModelVolumeTFCE::defaultH(); if (parameters->getParametersAvailable()) { numSteps = parameters->getNextParameterAsInt("Number Of Steps (optional)"); } if (parameters->getParametersAvailable()) { E = parameters->getNextParameterAsFloat("E (optional)"); } if (parameters->getParametersAvailable()) { H = parameters->getNextParameterAsFloat("H (optional)"); } checkForExcessiveParameters(); // // Create a brain set // BrainSet brainSet; // // Read the volume file // VolumeFile inputVolume; inputVolume.readFile(inputVolumeFileName); // // Create output volume file // VolumeFile outVolume(inputVolume); // // Create the Ligase object // BrainModelVolumeTFCE TFCEObject(&brainSet, &inputVolume, &outVolume, outputVolumeFileName, outputVolumeLabel, numSteps, E, H); // // Execute Ligase // TFCEObject.execute(); // // Write the file // outVolume.writeFile(outputVolumeFileName); const QString warningMessages = TFCEObject.getWarningMessages(); if (warningMessages.isEmpty() == false) { std::cout << "TFCE Warnings: " << warningMessages.toAscii().constData() << std::endl; } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeSmearAxis.h0000664000175000017500000000342411572067322026357 0ustar michaelmichael #ifndef __COMMAND_VOLUME_SMEAR_AXIS_H__ #define __COMMAND_VOLUME_SMEAR_AXIS_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for volume smear an axis class CommandVolumeSmearAxis : public CommandBase { public: // constructor CommandVolumeSmearAxis(); // destructor ~CommandVolumeSmearAxis(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_SMEAR_AXIS_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeSmearAxis.cxx0000664000175000017500000001023611572067322026731 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeSmearAxis.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeSmearAxis::CommandVolumeSmearAxis() : CommandBase("-volume-smear-axis", "VOLUME SMEAR AXIS") { } /** * destructor. */ CommandVolumeSmearAxis::~CommandVolumeSmearAxis() { } /** * get the script builder parameters. */ void CommandVolumeSmearAxis::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { std::vector axisValues, axisNames; axisValues.push_back("X"); axisNames.push_back("Parasagittal View"); axisValues.push_back("Y"); axisNames.push_back("Coronal View"); axisValues.push_back("Z"); axisNames.push_back("Horizontal (axial) View"); paramsOut.clear(); paramsOut.addFile("Input Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Output Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addListOfItems("Axis", axisValues, axisNames); paramsOut.addInt("Mag", 0, -10000, 10000); paramsOut.addInt("Sign", 0, -10000, 10000); paramsOut.addInt("Core", 0, -10000, 10000); } /** * get full help information. */ QString CommandVolumeSmearAxis::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Smear a volume along an axis.\n" + indent9 + "\n" + indent9 + "\"axis\" is one of \"X\", \"Y\", or \"Z\".\n" + indent9 + "\n" //EXPLAIN HOW IT WORKS/WHAT IT DOES + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeSmearAxis::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); QString outputVolumeFileName, outputVolumeFileLabel; parameters->getNextParameterAsVolumeFileNameAndLabel("Output Volume File Name", outputVolumeFileName, outputVolumeFileLabel); const QString axisString = parameters->getNextParameterAsString("Axis"); const VolumeFile::VOLUME_AXIS axis = VolumeFile::getAxisFromString(axisString); const int mag = parameters->getNextParameterAsInt("Mag"); const int sign = parameters->getNextParameterAsInt("Sign"); const int core = parameters->getNextParameterAsInt("Core"); VolumeFile vf; vf.readFile(inputVolumeFileName); vf.smearAxis(axis, mag, sign, core); vf.setDescriptiveLabel(outputVolumeFileLabel); vf.writeFile(outputVolumeFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeShiftAxis.h0000664000175000017500000000337711572067322026374 0ustar michaelmichael #ifndef __COMMAND_VOLUME_SHIFT_AXIS_H__ #define __COMMAND_VOLUME_SHIFT_AXIS_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandVolumeShiftAxis : public CommandBase { public: // constructor CommandVolumeShiftAxis(); // destructor ~CommandVolumeShiftAxis(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_SHIFT_AXIS_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeShiftAxis.cxx0000664000175000017500000000756611572067322026753 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeShiftAxis.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeShiftAxis::CommandVolumeShiftAxis() : CommandBase("-volume-shift-axis", "VOLUME SHIFT AXIS") { } /** * destructor. */ CommandVolumeShiftAxis::~CommandVolumeShiftAxis() { } /** * get the script builder parameters. */ void CommandVolumeShiftAxis::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { std::vector axisValues, axisNames; axisValues.push_back("X"); axisNames.push_back("Parasagittal (X)"); axisValues.push_back("Y"); axisNames.push_back("Coronal (Y)"); axisValues.push_back("Z"); axisNames.push_back("Horizontal (Z)"); paramsOut.clear(); paramsOut.addFile("Input Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Output Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addListOfItems("Axis", axisValues, axisNames); paramsOut.addInt("Offset"); } /** * get full help information. */ QString CommandVolumeShiftAxis::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Shift along an axis.\n" + indent9 + "\n" + indent9 + "\"axis\" is one of \"X\", \"Y\", or \"Z\".\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeShiftAxis::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get inputs // const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); QString outputVolumeFileName, outputVolumeFileLabel; parameters->getNextParameterAsVolumeFileNameAndLabel("Output Volume File Name/Label", outputVolumeFileName, outputVolumeFileLabel); const QString axisString = parameters->getNextParameterAsString("Axis"); const VolumeFile::VOLUME_AXIS axis = VolumeFile::getAxisFromString(axisString); const int offset = parameters->getNextParameterAsInt("Offset"); checkForExcessiveParameters(); // // Read the input file // VolumeFile volume; volume.readFile(inputVolumeFileName); // // shift // volume.shiftAxis(axis, offset); // // Write the volume // writeVolumeFile(volume, outputVolumeFileName, outputVolumeFileLabel); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeSetSpacing.h0000664000175000017500000000343711572067322026527 0ustar michaelmichael #ifndef __COMMAND_VOLUME_SET_SPACING_H__ #define __COMMAND_VOLUME_SET_SPACING_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for setting a volumes spacing class CommandVolumeSetSpacing : public CommandBase { public: // constructor CommandVolumeSetSpacing(); // destructor ~CommandVolumeSetSpacing(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_SET_SPACING_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeSetSpacing.cxx0000664000175000017500000000720711572067322027101 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeSetSpacing.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeSetSpacing::CommandVolumeSetSpacing() : CommandBase("-volume-set-spacing", "VOLUME SET SPACING") { } /** * destructor. */ CommandVolumeSetSpacing::~CommandVolumeSetSpacing() { } /** * get the script builder parameters. */ void CommandVolumeSetSpacing::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Output Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFloat("X-Axis-Spacing"); paramsOut.addFloat("Y-Axis-Spacing"); paramsOut.addFloat("Z-Axis-Spacing"); } /** * get full help information. */ QString CommandVolumeSetSpacing::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Set the spacing for the volume file.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeSetSpacing::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get inputs // const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); QString outputVolumeFileName, outputVolumeFileLabel; parameters->getNextParameterAsVolumeFileNameAndLabel("Output Volume File Name/Label", outputVolumeFileName, outputVolumeFileLabel); const float spacing[3] = { parameters->getNextParameterAsFloat("X-Axis-Spacing"), parameters->getNextParameterAsFloat("Y-Axis-Spacing"), parameters->getNextParameterAsFloat("Z-Axis-Spacing") }; checkForExcessiveParameters(); // // Read the input file // VolumeFile volume; volume.readFile(inputVolumeFileName); // // set the spacing // volume.setSpacing(spacing); // // Write the volume // writeVolumeFile(volume, outputVolumeFileName, outputVolumeFileLabel); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeSetOrigin.h0000664000175000017500000000343111572067322026364 0ustar michaelmichael #ifndef __COMMAND_VOLUME_SET_ORIGIN_H__ #define __COMMAND_VOLUME_SET_ORIGIN_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for setting a volume's origin class CommandVolumeSetOrigin : public CommandBase { public: // constructor CommandVolumeSetOrigin(); // destructor ~CommandVolumeSetOrigin(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_SET_ORIGIN_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeSetOrigin.cxx0000664000175000017500000000751511572067322026746 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeSetOrigin.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeSetOrigin::CommandVolumeSetOrigin() : CommandBase("-volume-set-origin", "VOLUME SET ORIGIN") { } /** * destructor. */ CommandVolumeSetOrigin::~CommandVolumeSetOrigin() { } /** * get the script builder parameters. */ void CommandVolumeSetOrigin::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Output Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFloat("X-Axis-Origin (Center of First Voxel)"); paramsOut.addFloat("Y-Axis-Origin (Center of First Voxel)"); paramsOut.addFloat("Z-Axis-Origin (Center of First Voxel)"); } /** * get full help information. */ QString CommandVolumeSetOrigin::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Set the origin for the volume file.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeSetOrigin::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get inputs // const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); QString outputVolumeFileName, outputVolumeFileLabel; parameters->getNextParameterAsVolumeFileNameAndLabel("Output Volume File Name/Label", outputVolumeFileName, outputVolumeFileLabel); const float origin[3] = { parameters->getNextParameterAsFloat("X-Axis-Origin-At-Center-of-First-Voxel"), parameters->getNextParameterAsFloat("Y-Axis-Origin-At-Center-of-First-Voxel"), parameters->getNextParameterAsFloat("Z-Axis-Origin-At-Center-of-First-Voxel") }; checkForExcessiveParameters(); // // Read the input file // VolumeFile volume; volume.readFile(inputVolumeFileName); // // set the origin // volume.setOrigin(origin); // // Write the volume // writeVolumeFile(volume, outputVolumeFileName, outputVolumeFileLabel); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeSetOrientation.h0000664000175000017500000000347411572067322027437 0ustar michaelmichael #ifndef __COMMAND_VOLUME_SET_ORIENTATION_H__ #define __COMMAND_VOLUME_SET_ORIENTATION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for setting a volume's orientation class CommandVolumeSetOrientation : public CommandBase { public: // constructor CommandVolumeSetOrientation(); // destructor ~CommandVolumeSetOrientation(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_SET_ORIENTATION_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeSetOrientation.cxx0000664000175000017500000001424311572067322030006 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeSetOrientation.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeSetOrientation::CommandVolumeSetOrientation() : CommandBase("-volume-set-orientation", "VOLUME SET ORIENTATION") { } /** * destructor. */ CommandVolumeSetOrientation::~CommandVolumeSetOrientation() { } /** * get the script builder parameters. */ void CommandVolumeSetOrientation::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { std::vector values, descriptions; values.push_back("ANTERIOR"); descriptions.push_back("Anterior-to-Posterior"); values.push_back("INFERIOR"); descriptions.push_back("Interior-to-Superior"); values.push_back("LEFT"); descriptions.push_back("Left-to-Right"); values.push_back("POSTERIOR"); descriptions.push_back("Posterior-to-Inferior"); values.push_back("RIGHT"); descriptions.push_back("Right-to-Left"); values.push_back("SUPERIOR"); descriptions.push_back("Superior-to-Inferior"); values.push_back("UNKNOWN"); descriptions.push_back("Unknown"); paramsOut.clear(); paramsOut.addFile("Input Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Output Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addListOfItems("X-Axis-Orientation", values, descriptions); paramsOut.addListOfItems("Y-Axis-Orientation", values, descriptions); paramsOut.addListOfItems("Z-Axis-Orientation", values, descriptions); } /** * get full help information. */ QString CommandVolumeSetOrientation::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Set the orientation for the volume file\n" + indent9 + "\n" + indent9 + "\"axis-orientation\" values and descriptions:\n" + indent9 + " Value-Entered Description\n" + indent9 + " ------------- -----------\n" + indent9 + " ANTERIOR Anterior-to-Posterior\n" + indent9 + " INFERIOR Interior-to-Superior\n" + indent9 + " LEFT Left-to-Right\n" + indent9 + " POSTERIOR Posterior-to-Inferior\n" + indent9 + " RIGHT Right-to-Left\n" + indent9 + " SUPERIOR Superior-to-Inferior\n" + indent9 + " UNKNOWN Unknown\n" + indent9 + " \n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeSetOrientation::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get inputs // const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); QString outputVolumeFileName, outputVolumeFileLabel; parameters->getNextParameterAsVolumeFileNameAndLabel("Output Volume File Name/Label", outputVolumeFileName, outputVolumeFileLabel); const QString orientString[3] = { parameters->getNextParameterAsString("X-Axis-Orientation"), parameters->getNextParameterAsString("Y-Axis-Orientation"), parameters->getNextParameterAsString("Z-Axis-Orientation") }; checkForExcessiveParameters(); // // Convert orientation strings // VolumeFile::ORIENTATION orientation[3]; for (int i = 0; i < 3; i++) { if (orientString[i] == "UNKNOWN") { orientation[i] = VolumeFile::ORIENTATION_UNKNOWN; } else if (orientString[i] == "RIGHT") { orientation[i] = VolumeFile::ORIENTATION_RIGHT_TO_LEFT; } else if (orientString[i] == "LEFT") { orientation[i] = VolumeFile::ORIENTATION_LEFT_TO_RIGHT; } else if (orientString[i] == "POSTERIOR") { orientation[i] = VolumeFile::ORIENTATION_POSTERIOR_TO_ANTERIOR; } else if (orientString[i] == "ANTERIOR") { orientation[i] = VolumeFile::ORIENTATION_ANTERIOR_TO_POSTERIOR; } else if (orientString[i] == "INFERIOR") { orientation[i] = VolumeFile::ORIENTATION_INFERIOR_TO_SUPERIOR; } else if (orientString[i] == "SUPERIOR") { orientation[i] = VolumeFile::ORIENTATION_SUPERIOR_TO_INFERIOR; } else { throw CommandException("Invalid orientation axis \"" + orientString[i] + "\""); } } // // Read the input file // VolumeFile volume; volume.readFile(inputVolumeFileName); // // set the orientation // volume.setOrientation(orientation); // // Write the volume // writeVolumeFile(volume, outputVolumeFileName, outputVolumeFileLabel); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeSegmentationToCerebralHull.h0000664000175000017500000000362411572067322031712 0ustar michaelmichael #ifndef __COMMAND_VOLUME_SEGMENTATION_TO_CEREBRAL_HULL_H__ #define __COMMAND_VOLUME_SEGMENTATION_TO_CEREBRAL_HULL_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for convert a hull volume into a VTK surface class CommandVolumeSegmentationToCerebralHull : public CommandBase { public: // constructor CommandVolumeSegmentationToCerebralHull(); // destructor ~CommandVolumeSegmentationToCerebralHull(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_SEGMENTATION_TO_CEREBRAL_HULL_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeSegmentationToCerebralHull.cxx0000664000175000017500000001114511572067322032262 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainSet.h" #include "CommandVolumeSegmentationToCerebralHull.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" #include "vtkPolyData.h" #include "vtkPolyDataWriter.h" /** * constructor. */ CommandVolumeSegmentationToCerebralHull::CommandVolumeSegmentationToCerebralHull() : CommandBase("-volume-segmentation-to-cerebral-hull", "VOLUME SEGMENTATION TO CEREBRAL HULL VOLUME AND SURFACE") { } /** * destructor. */ CommandVolumeSegmentationToCerebralHull::~CommandVolumeSegmentationToCerebralHull() { } /** * get the script builder parameters. */ void CommandVolumeSegmentationToCerebralHull::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Segmentation Volume File Name", FileFilters::getVolumeSegmentationFileFilter()); paramsOut.addFile("Output Cerebral Hull Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Output Cerebral Hull VTK Surface File Name", FileFilters::getVtkSurfaceFileFilter()); } /** * get full help information. */ QString CommandVolumeSegmentationToCerebralHull::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Generate cerebral hull volume and VTK surface from a.\n" + indent9 + "segmentation volume file.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeSegmentationToCerebralHull::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get parameters // const QString segmentationVolumeFileName = parameters->getNextParameterAsString("Input Segmentation Volume File Name"); const QString hullVolumeFileName = parameters->getNextParameterAsString("Output Cerebral Hull Volume File Name"); const QString vtkSurfaceFileName = parameters->getNextParameterAsString("Output Cerebral Hull VTK Surface File Name"); // // Read segemtation // VolumeFile segmentationVolume; segmentationVolume.readFile(segmentationVolumeFileName); // // Expand around edges with empty slices // int expDim[3]; segmentationVolume.getDimensions(expDim); const int expSlices = 7; const int resizeCrop[6] = { -expSlices, expDim[0] + expSlices, -expSlices, expDim[1] + expSlices, -expSlices, expDim[2] + expSlices }; segmentationVolume.resize(resizeCrop); // // Generate hull volume and surface // BrainSet bs; VolumeFile* hullVolume = NULL; vtkPolyData* hullSurface = NULL; bs.generateCerebralHullVtkFile(&segmentationVolume, hullVolume, hullSurface); // // Write the hull volume // hullVolume->writeFile(hullVolumeFileName); // // Write the hull surface // vtkPolyDataWriter* writer = vtkPolyDataWriter::New(); writer->SetInput(hullSurface); writer->SetHeader("Written by Caret"); writer->SetFileName((char*)vtkSurfaceFileName.toAscii().constData()); writer->Write(); writer->Delete(); // // free memory // hullSurface->Delete(); delete hullVolume; } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeSegmentationStereotaxicSpace.h0000664000175000017500000000420511572067322032305 0ustar michaelmichael #ifndef __COMMAND_VOLUME_SEGMENTATION_STEREOTAXIC_SPACE_H__ #define __COMMAND_VOLUME_SEGMENTATION_STEREOTAXIC_SPACE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" class SegmentationMaskListFile; /// class for segmentation automatically class CommandVolumeSegmentationStereotaxicSpace : public CommandBase { public: // constructor CommandVolumeSegmentationStereotaxicSpace(); // destructor ~CommandVolumeSegmentationStereotaxicSpace(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); /// get the segmentation mask file void getMaskVolumeListFile(SegmentationMaskListFile& smlf, const bool throwExceptionIfReadErrorFlag) const throw (CommandException); }; #endif // __COMMAND_VOLUME_SEGMENTATION_STEREOTAXIC_SPACE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeSegmentationStereotaxicSpace.cxx0000664000175000017500000002626011572067322032665 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelVolumeSegmentationStereotaxic.h" #include "BrainSet.h" #include "CommandVolumeSegmentationStereotaxicSpace.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SegmentationMaskListFile.h" #include "SpecFile.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeSegmentationStereotaxicSpace::CommandVolumeSegmentationStereotaxicSpace() : CommandBase("-volume-segment-stereo-space", "VOLUME SEGMENTATION STEREOTAXIC SPACE") { } /** * destructor. */ CommandVolumeSegmentationStereotaxicSpace::~CommandVolumeSegmentationStereotaxicSpace() { } /** * get the script builder parameters. */ void CommandVolumeSegmentationStereotaxicSpace::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { std::vector errorCorrectionValues; std::vector errorCorrectionNames; BrainModelVolumeSureFitSegmentation::getErrorCorrectionMethodsAndNames( errorCorrectionNames, errorCorrectionValues); paramsOut.clear(); paramsOut.addFile("Input Anatomical Volume File Name", FileFilters::getVolumeAnatomyFileFilter()); paramsOut.addFile("Spec File Name", FileFilters::getSpecFileFilter()); paramsOut.addListOfItems("Volume Error Correction", errorCorrectionNames, errorCorrectionNames); paramsOut.addVariableListOfParameters("Options"); } /** * get full help information. */ QString CommandVolumeSegmentationStereotaxicSpace::getHelpInformation() const { std::vector errorCorrectionValues; std::vector errorCorrectionNames; BrainModelVolumeSureFitSegmentation::getErrorCorrectionMethodsAndNames( errorCorrectionNames, errorCorrectionValues); SegmentationMaskListFile maskVolumeListFile; getMaskVolumeListFile(maskVolumeListFile, false); QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-ecs]\n" + indent9 + "[-flat]\n" + indent9 + "[-mp]\n" + indent9 + "[-noeye]\n" + indent9 + "\n" + indent9 + "Perform automatic segmentation of an anatomical volume\n" + indent9 + "in a known stereotaxic space.\n" + indent9 + "\n" + indent9 + " \n" + indent9 + " THIS IS EXPERIMENTAL BUT IT WILL PRODUCE A SURFACE \n" + indent9 + " \n" + indent9 + " The input spec file must contain the stereotaxic space and the \n" + indent9 + " structure (LEFT or RIGHT) for this command to operate. A spec \n" + indent9 + " is created by running this program with the \"-spec-file-create\" \n" + indent9 + " command. \n" + indent9 + " \n" + indent9 + " This input volume must be in one of the supported stereotaxic \n" + indent9 + " spaces with the origin at the anterior commissure. The volume \n" + indent9 + " should not have non-uniformity (bias) problems. The input \n" + indent9 + " volume is cropped to a single hemisphere, the voxels are \n" + indent9 + " mapped to the range 0 to 255, the gray and white matter \n" + indent9 + " histogram peaks are estimated, the volume is segmented, and \n" + indent9 + " fiducial and inflated surfaces are generated. \n" + indent9 + " \n" + indent9 + " volume-error-correction-method\n"); for (unsigned int i = 0; i < errorCorrectionNames.size(); i++) { helpInfo += ( indent9 + indent9 + errorCorrectionNames[i] + "\n"); } helpInfo += ("\n" + indent9 + " Stereotaxic Spaces Supported \n" + maskVolumeListFile.getAvailableMasks(indent9 +" ") + indent9 + " \n" + indent9 + " OPTIONS \n" + indent9 + " -ecs Perform error correction of the surface. \n" + indent9 + " \n" + indent9 + " -flat Generate files for flattening (very inflated, ellipsoidal, \n" + indent9 + " paint, and surface shape. \n" + indent9 + " \n" + indent9 + " -mp Generate surface with maxmimum number of polygons. \n" + indent9 + " \n" + indent9 + " -noeye Do NOT disconnect eye and strip skull \n" + indent9 + " \n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeSegmentationStereotaxicSpace::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Anatomical Volume File Name"); const QString specFileName = parameters->getNextParameterAsString("Spec File Name"); const QString volumeErrorCorrectionName = parameters->getNextParameterAsString("Volume Error Correction Name"); bool disconnectEyeAndSkull = true; bool errorCorrectSurfaceFlag = false; bool maxPolygonsFlag = false; bool flatteningFlag = false; int uniformityIterations = BrainModelVolumeSegmentationStereotaxic::getDefaultUniformityIterations(); while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("Segment Option"); if (paramName == "-ecs") { errorCorrectSurfaceFlag = true; } else if (paramName == "-flat") { flatteningFlag = true; } else if (paramName == "-mp") { maxPolygonsFlag = true; } else if (paramName == "-noeye") { disconnectEyeAndSkull = false; } else if (paramName == "-uniform") { uniformityIterations = parameters->getNextParameterAsInt("Uniformity Iterations"); } else { throw CommandException("Unexpected parameter " + paramName); } } // // Get error correction // std::vector errorCorrectionValues; std::vector errorCorrectionNames; BrainModelVolumeSureFitSegmentation::getErrorCorrectionMethodsAndNames( errorCorrectionNames, errorCorrectionValues); BrainModelVolumeSureFitSegmentation::ERROR_CORRECTION_METHOD errorCorrectionMethod = BrainModelVolumeSureFitSegmentation::ERROR_CORRECTION_METHOD_NONE; bool foundErrorCorrectionFlag = false; for (unsigned int i = 0; i < errorCorrectionNames.size(); i++) { if (volumeErrorCorrectionName == errorCorrectionNames[i]) { errorCorrectionMethod = errorCorrectionValues[i]; foundErrorCorrectionFlag = true; break; } } if (foundErrorCorrectionFlag == false) { throw CommandException("Invalid error correction: " + volumeErrorCorrectionName); } // // Read in segmentation masks list file // SegmentationMaskListFile maskVolumeListFile; getMaskVolumeListFile(maskVolumeListFile, true); // // Setup spec file with anatomy volume file name and params file // SpecFile specFile; try { specFile.readFile(specFileName); } catch (FileException& e) { throw CommandException("Unable to read spec file: " + e.whatQString()); } // // Clear surface files from spec file and disk // specFile.clearFiles(false, // volume files true, // surface files, false, // other files true); // remove the files // // Select anatomy and params // specFile.setAllFileSelections(SpecFile::SPEC_FALSE); specFile.addToSpecFile(SpecFile::getVolumeAnatomyFileTag(), inputVolumeFileName, "", false); if (specFile.paramsFile.getNumberOfFiles() > 0) { specFile.paramsFile.setSelected(specFile.paramsFile.getFileName(0), true, Structure::STRUCTURE_TYPE_CORTEX_BOTH); } // // Create a brain set // BrainSet brainSet(true); QString specReadMsg; brainSet.readSpecFile(specFile, specFileName, specReadMsg); if (specReadMsg.isEmpty() == false) { throw CommandException("Reading spec file: " + specReadMsg); } // // Perform the segmentation operations // BrainModelVolumeSegmentationStereotaxic segment(&brainSet, brainSet.getVolumeAnatomyFile(0), uniformityIterations, disconnectEyeAndSkull, errorCorrectionMethod, errorCorrectSurfaceFlag, maxPolygonsFlag, flatteningFlag); // // Execute the segmentation // segment.execute(); } /** * get the segmentation mask file. */ void CommandVolumeSegmentationStereotaxicSpace::getMaskVolumeListFile( SegmentationMaskListFile& smlf, const bool throwExceptionIfReadErrorFlag) const throw (CommandException) { const QString maskVolumesDirectory(BrainSet::getCaretHomeDirectory() + "/data_files/segmentation_masks/"); const QString maskVolumeListFileName = maskVolumesDirectory + "mask_list.txt.csv"; try { smlf.readFile(maskVolumeListFileName); } catch (FileException& e) { if (throwExceptionIfReadErrorFlag) { throw CommandException(e); } else { std::cout << "ERROR: Failed to read :" << maskVolumeListFileName.toAscii().constData() << std::endl; } } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeSegmentationLigase.h0000664000175000017500000000346511572067322030252 0ustar michaelmichael #ifndef __COMMAND_VOLUME_SEGMENTATION_LIGASE_H__ #define __COMMAND_VOLUME_SEGMENTATION_LIGASE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandVolumeSegmentationLigase : public CommandBase { public: // constructor CommandVolumeSegmentationLigase(); // destructor ~CommandVolumeSegmentationLigase(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_SEGMENTATION_LIGASE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeSegmentationLigase.cxx0000664000175000017500000002357611572067322030632 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "CommandVolumeSegmentationLigase.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "BrainModelVolumeLigaseSegmentation.h" #include "BrainSet.h" #include "StringUtilities.h" /** * constructor. */ CommandVolumeSegmentationLigase::CommandVolumeSegmentationLigase() : CommandBase("-volume-segment-ligase", "VOLUME SEGMENTATION LIGASE") { } /** * destructor. */ CommandVolumeSegmentationLigase::~CommandVolumeSegmentationLigase() { } /** * get the script builder parameters. */ void CommandVolumeSegmentationLigase::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input anatomy volume file name", FileFilters::getVolumeAnatomyFileFilter()); paramsOut.addFile("Output segmentation volume file name", FileFilters::getVolumeSegmentationFileFilter()); paramsOut.addString("Output volume label"); paramsOut.addInt("X index of seed", 128, 0); paramsOut.addInt("Y index of seed", 128, 0); paramsOut.addInt("Z index of seed", 128, 0); paramsOut.addFloat("White minimum", 140.0f); paramsOut.addFloat("White peak", 170.0f); paramsOut.addFloat("White maximum", 200.0f); paramsOut.addFloat("Difference cutoff base value", BrainModelVolumeLigaseSegmentation::defaultDiff()); paramsOut.addFloat("Gradient cutoff base value", BrainModelVolumeLigaseSegmentation::defaultGrad()); paramsOut.addFloat("Above peak probability minimum", BrainModelVolumeLigaseSegmentation::defaultHighBias()); paramsOut.addFloat("Below peak probability minimum", BrainModelVolumeLigaseSegmentation::defaultLowBias()); } /** * get full help information. */ QString CommandVolumeSegmentationLigase::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[diff-base = " + StringUtilities::fromNumber(BrainModelVolumeLigaseSegmentation::defaultDiff()) + "]\n" + indent9 + "[grad-base = " + StringUtilities::fromNumber(BrainModelVolumeLigaseSegmentation::defaultGrad()) + "]\n" + indent9 + "[high-bias = " + StringUtilities::fromNumber(BrainModelVolumeLigaseSegmentation::defaultHighBias()) + "]\n" + indent9 + "[low-bias = " + StringUtilities::fromNumber(BrainModelVolumeLigaseSegmentation::defaultLowBias()) + "]\n" + indent9 + "\n" + indent9 + "Use LIGASE to segment the white matter.\n" + indent9 + "\n" + indent9 + " x-seed, y-seed, z-seed specify the voxel for LIGASE to grow\n" + indent9 + " from, make sure it is in the white\n" + indent9 + " matter.\n" + indent9 + "\n" + indent9 + " white-min specifies the minimum intensity of the white matter in\n" + indent9 + " the anatomy volume. \n" + indent9 + " \n" + indent9 + " white-peak specifies the intensity of the white matter peak in\n" + indent9 + " the anatomy volume. \n" + indent9 + " \n" + indent9 + " white-max specifies the maximum intensity of the white matter in\n" + indent9 + " the anatomy volume. \n" + indent9 + "\n" + indent9 + " Optional parameters: (default value specified above)\n" + indent9 + " diff-base specifies how much to rely on the difference from one\n" + indent9 + " voxel to the next when growing, higher numbers allow\n" + indent9 + " more growth. \n" + indent9 + "\n" + indent9 + " grad-base specifies how much to rely on the magnitude of the\n" + indent9 + " local 3D gradient when growing, higher numbers allow\n" + indent9 + " more growth.\n" + indent9 + "\n" + indent9 + " high-bias specifies how low a probability based on intensity\n" + indent9 + " is considered as no chance of being white matter\n" + indent9 + " when intensity is above peak, smaller numbers allow\n" + indent9 + " more growth.\n" + indent9 + "\n" + indent9 + " low-bias specifies how low a probability based on intensity\n" + indent9 + " is considered as no chance of being white matter\n" + indent9 + " when intensity is below peak, smaller numbers allow\n" + indent9 + " more growth.\n" + indent9 + "\n" + indent9 + "Note: This algorithm is generally conservative in estimating the\n" + indent9 + " gray/white boundary, try dilating the output if changing\n" + indent9 + " parameters doesn't give the desired results.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeSegmentationLigase::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Anatomy Volume File Name"); const QString outputVolumeFileName = parameters->getNextParameterAsString("Output Segmentation Volume File Name"); const QString outputVolumeLabel = parameters->getNextParameterAsString("Output Segmentation Volume Label"); const int xSeed = parameters->getNextParameterAsInt("Seed Point X Index"); const int ySeed = parameters->getNextParameterAsInt("Seed Point Y Index"); const int zSeed = parameters->getNextParameterAsInt("Seed Point Z Index"); const float whiteMin = parameters->getNextParameterAsFloat("White Minimum"); const float whitePeak = parameters->getNextParameterAsFloat("White Peak"); const float whiteMax = parameters->getNextParameterAsFloat("White Maximum"); float diffBase = BrainModelVolumeLigaseSegmentation::defaultDiff(), gradBase = BrainModelVolumeLigaseSegmentation::defaultGrad(), highBias = BrainModelVolumeLigaseSegmentation::defaultHighBias(), lowBias = BrainModelVolumeLigaseSegmentation::defaultLowBias(); if (parameters->getParametersAvailable()) { diffBase = parameters->getNextParameterAsFloat("Difference Cutoff Base (optional)"); } if (parameters->getParametersAvailable()) { gradBase = parameters->getNextParameterAsFloat("Gradient Cutoff Base (optional)"); } if (parameters->getParametersAvailable()) { highBias = parameters->getNextParameterAsFloat("High Probability Bias (optional)"); } if (parameters->getParametersAvailable()) { lowBias = parameters->getNextParameterAsFloat("Low Probability Bias (optional)"); } checkForExcessiveParameters(); // // Create a brain set // BrainSet brainSet; // // Read the volume file // VolumeFile inputVolume; inputVolume.readFile(inputVolumeFileName); // // Create output volume file // VolumeFile segVolume(inputVolume); segVolume.setVolumeType(VolumeFile::VOLUME_TYPE_SEGMENTATION); // // Create the Ligase object // BrainModelVolumeLigaseSegmentation ligaseObject(&brainSet, &inputVolume, &segVolume, outputVolumeFileName, outputVolumeLabel, xSeed, ySeed, zSeed, whiteMin, whitePeak, whiteMax, diffBase, gradBase, highBias, lowBias); // // Execute Ligase // ligaseObject.execute(); // // Write the file // segVolume.writeFile(outputVolumeFileName); const QString warningMessages = ligaseObject.getWarningMessages(); if (warningMessages.isEmpty() == false) { std::cout << "Segmentation Warnings: " << warningMessages.toAscii().constData() << std::endl; } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeSegmentation.h0000664000175000017500000000344111572067322027117 0ustar michaelmichael #ifndef __COMMAND_VOLUME_SEGMENTATION_H__ #define __COMMAND_VOLUME_SEGMENTATION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for segmenting volumes class CommandVolumeSegmentation : public CommandBase { public: // constructor CommandVolumeSegmentation(); // destructor ~CommandVolumeSegmentation(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_SEGMENTATION_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeSegmentation.cxx0000664000175000017500000004350311572067322027475 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelSurfaceBorderLandmarkIdentification.h" #include "BrainModelVolumeSureFitSegmentation.h" #include "BrainSet.h" #include "CommandVolumeSegmentation.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "StringUtilities.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeSegmentation::CommandVolumeSegmentation() : CommandBase("-volume-segment", "VOLUME SEGMENTATION") { } /** * destructor. */ CommandVolumeSegmentation::~CommandVolumeSegmentation() { } /** * get the script builder parameters. */ void CommandVolumeSegmentation::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { std::vector values, descriptions; values.push_back("NIFTI"); descriptions.push_back("NIFTI"); values.push_back("AFNI"); descriptions.push_back("AFNI"); values.push_back("SPM"); descriptions.push_back("SPM"); values.push_back("WUNIL"); descriptions.push_back("WUNIL"); std::vector structValues, structDescriptions; structValues.push_back("LEFT"); structDescriptions.push_back("LEFT"); structValues.push_back("RIGHT"); structDescriptions.push_back("RIGHT"); std::vector errorCorrectionValues; std::vector errorCorrectionNames; BrainModelVolumeSureFitSegmentation::getErrorCorrectionMethodsAndNames( errorCorrectionNames, errorCorrectionValues); paramsOut.clear(); paramsOut.addFile("Input Anatomy Volume File Name", FileFilters::getVolumeAnatomyFileFilter()); paramsOut.addFile("Input Segmentation Volume File Name", FileFilters::getVolumeSegmentationFileFilter()); paramsOut.addFile("Spec File Name", FileFilters::getSpecFileFilter()); paramsOut.addString("Operation Code", "YYYYYYYYYNYYYYYY"); paramsOut.addFloat("Gray Peak", 100.0); paramsOut.addFloat("White Peak", 170.0); paramsOut.addString("Padding Code", "NNNNNN"); paramsOut.addListOfItems("Structure", structValues, structDescriptions); paramsOut.addListOfItems("Error Correction", errorCorrectionNames, errorCorrectionNames); paramsOut.addListOfItems("Volume Write Type", values, descriptions); } /** * get full help information. */ QString CommandVolumeSegmentation::getHelpInformation() const { std::vector errorCorrectionValues; std::vector errorCorrectionNames; BrainModelVolumeSureFitSegmentation::getErrorCorrectionMethodsAndNames( errorCorrectionNames, errorCorrectionValues); QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + " \n" + indent9 + "Perform segmentation operations.\n" + indent9 + " \n" + indent9 + " Operation_Code characters \n" + indent9 + " Specify each with either a \"Y\" or \"N\". \n" + indent9 + " All characters must be specified. \n" + indent9 + " Character Operation Description \n" + indent9 + " --------- --------------------- \n" + indent9 + " 1 Disconnect Eye and Skull \n" + indent9 + " 2 Disconnect Hindbrain \n" + indent9 + " 3 Use High Threshold for Hindbrain disconnection \n" + indent9 + " 4 Cut Corpus Callossum \n" + indent9 + " 5 Generate Segmentation \n" + indent9 + " 6 Fill Ventricles \n" + indent9 + " 7 Generate Raw and Fiducial Surfaces \n" + indent9 + " 8 Reduce polygons in surfaces \n" + indent9 + " 9 Correct topological errors in surfaces \n" + indent9 + " 10 Generate Inflated Surface \n" + indent9 + " 11 Generate Very Inflated Surface \n" + indent9 + " 12 Generate Ellipsoid Surface (For Flattening) \n" + indent9 + " 13 Generate Spherical Surface \n" + indent9 + " 14 Generate Comp Med Wall Surface \n" + indent9 + " 15 Generate Hull Surface \n" + indent9 + " 16 Generate Curvature, Depth, and Paint Attributes \n" + indent9 + " 17 Generate Registration and Flattening Landmark Borders\n" + indent9 + " \n" + indent9 + " gray-peak specifies the intensity of the gray matter peak in the \n" + indent9 + " anatomy volume. \n" + indent9 + " \n" + indent9 + " white-peak specifies the intensity of the white matter peak in the \n" + indent9 + " anatomy volume. \n" + indent9 + " \n" + indent9 + " padding-code \n" + indent9 + " Specify padding for any cut faces when segmenting a partial hemisphere. \n" + indent9 + " Specify each with either a \"Y\" for padding or \"N\" for no padding. \n" + indent9 + " All characters must be specified. \n" + indent9 + " Character Padding Description \n" + indent9 + " --------- ------------------- \n" + indent9 + " 1 Pad Negative X \n" + indent9 + " 2 Pad Positive X \n" + indent9 + " 3 Pad Posterior Y \n" + indent9 + " 4 Pad Anterior Y \n" + indent9 + " 5 Pad Inferior Z \n" + indent9 + " 6 Pad Superior Z \n" + indent9 + " \n" + indent9 + " structure Specifies the brain structure. \n" + indent9 + " Acceptable values are RIGHT or LEFT \n" + indent9 + " \n" + indent9 + " spec-file-name Name of specification file. \n" + indent9 + " \n" + indent9 + " input-anatomy-volume-file-name \n" + indent9 + " If there is not an anatomy volume file, leave this\n" + indent9 + " item blank (two consecutive double quotes).\n" + indent9 + " \n" + indent9 + " input-segmentation-volume-file-name \n" + indent9 + " If there is not a segmentation volume file, leave this\n" + indent9 + " item blank (two consecutive double quotes).\n" + indent9 + " \n" + indent9 + " error-correction-method\n"); for (unsigned int i = 0; i < errorCorrectionNames.size(); i++) { helpInfo += ( indent9 + indent9 + errorCorrectionNames[i] + "\n"); } helpInfo += ("\n" + indent9 + " write-volume-type Type of volume files to write. \n" + indent9 + " Specifies the type of the volume files that will be written \n" + indent9 + " during the segmentation process. Valid values are \n" + indent9 + " AFNI \n" + indent9 + " NIFTI \n" + indent9 + " NIFTI_GZIP (RECOMMENDED!!!!) \n" + indent9 + " SPM \n" + indent9 + " WUNIL \n" + indent9 + " \n" + indent9 + " All input volumes must be in a Left-Posterior-Inferior orientation \n" + indent9 + " and their stereotaxic coordinates must be set so that the origin is \n" + indent9 + " at the anterior commissure. \n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeSegmentation::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputAnatomyVolumeFileName = parameters->getNextParameterAsString("Input Anatomy Volume File Name"); const QString inputSegmentationVolumeFileName = parameters->getNextParameterAsString("Input Segmentation Volume File Name"); const QString specFileName = parameters->getNextParameterAsString("Spec File Name"); const QString operationCode = parameters->getNextParameterAsString("Operation Code"); const float grayPeak = parameters->getNextParameterAsFloat("Gray Peak"); const float whitePeak = parameters->getNextParameterAsFloat("White Peak"); const QString paddingCode = parameters->getNextParameterAsString("Padding Code"); const QString structureName = parameters->getNextParameterAsString("Structure Name").toUpper(); const QString errorCorrectionName = parameters->getNextParameterAsString("Error Correction Name"); const QString writeVolumeTypeString = parameters->getNextParameterAsString("Write Volume Type"); checkForExcessiveParameters(); VolumeFile::FILE_READ_WRITE_TYPE writeVolumeType = VolumeFile::FILE_READ_WRITE_TYPE_NIFTI_GZIP; if (writeVolumeTypeString == "AFNI") { writeVolumeType = VolumeFile::FILE_READ_WRITE_TYPE_AFNI; } else if (writeVolumeTypeString == "NIFTI") { writeVolumeType = VolumeFile::FILE_READ_WRITE_TYPE_NIFTI; } else if (writeVolumeTypeString == "NIFTI_GZIP") { writeVolumeType = VolumeFile::FILE_READ_WRITE_TYPE_NIFTI_GZIP; } else if (writeVolumeTypeString == "SPM") { writeVolumeType = VolumeFile::FILE_READ_WRITE_TYPE_SPM_OR_MEDX; } else if (writeVolumeTypeString == "WUNIL") { writeVolumeType = VolumeFile::FILE_READ_WRITE_TYPE_WUNIL; } else { throw CommandException("Invalid volume file write type: " + writeVolumeTypeString); } // // Check the operation code // const int operationCodeLength = 17; if (operationCode.length() != operationCodeLength) { throw CommandException("Operation code must contain exactly " + QString::number(operationCodeLength) + " characters."); } for (int i = 0; i < operationCodeLength; i++) { if ((operationCode[i] != 'Y') && (operationCode[i] != 'N')) { throw CommandException("Operation code character " + QString::number(i + 1) + " must be \"Y\" or \"N\"."); } } const bool disconnectEyeFlag = (operationCode[0] == 'Y'); const bool disconnectHindbrainFlag = (operationCode[1] == 'Y'); const bool disconnectHindHiThreshFlag = (operationCode[2] == 'Y'); const bool cutCorpusCallossumFlag = (operationCode[3] == 'Y'); const bool generateSegmentationFlag = (operationCode[4] == 'Y'); const bool fillVentriclesFlag = (operationCode[5] == 'Y'); const bool rawFiducialSurfaceFlag = (operationCode[6] == 'Y'); const bool reduceSurfacePolygonsFlag = (operationCode[7] == 'Y'); const bool topologicalCorrectFlag = (operationCode[8] == 'Y'); const bool inflatedSurfaceFlag = (operationCode[9] == 'Y'); const bool veryInflatedSurfaceFlag = (operationCode[10] == 'Y'); const bool ellipsoidSurfaceFlag = (operationCode[11] == 'Y'); const bool sphericalSurfaceFlag = (operationCode[12] == 'Y'); const bool compMedWallSurfaceFlag = (operationCode[13] == 'Y'); const bool hullSurfaceFlag = (operationCode[14] == 'Y'); const bool depthCurveGeographyFlag = (operationCode[15] == 'Y'); const bool landmarksFlag = (operationCode[16] == 'Y'); // // Get the structure // Structure::STRUCTURE_TYPE structure; if (structureName == "RIGHT") { structure = Structure::STRUCTURE_TYPE_CORTEX_RIGHT; } else if (structureName == "LEFT") { structure = Structure::STRUCTURE_TYPE_CORTEX_LEFT; } else { throw CommandException("Structure must be either RIGHT or LEFT.\n" " Value entered \"" + structureName + "\""); } // // Determine padding // const int paddingCodeLength = 6; if (paddingCode.length() != paddingCodeLength) { throw CommandException("Padding code must have exactly " + QString::number(paddingCodeLength) + " characters."); } int paddingAmount[6] = { 0, 0, 0, 0, 0, 0 }; for (int i = 0; i < paddingCodeLength; i++) { if (paddingCode[i] == 'Y') { paddingAmount[i] = 30; } else if (paddingCode[i] == 'N') { paddingAmount[i] = 0; } else { throw CommandException("Padding code character " + QString::number(i + 1) + " must be \"Y\" or \"N\"."); } } // // Get error correction // std::vector errorCorrectionValues; std::vector errorCorrectionNames; BrainModelVolumeSureFitSegmentation::getErrorCorrectionMethodsAndNames( errorCorrectionNames, errorCorrectionValues); BrainModelVolumeSureFitSegmentation::ERROR_CORRECTION_METHOD errorCorrectionMethod = BrainModelVolumeSureFitSegmentation::ERROR_CORRECTION_METHOD_NONE; bool foundErrorCorrectionFlag = false; for (unsigned int i = 0; i < errorCorrectionNames.size(); i++) { if (errorCorrectionName == errorCorrectionNames[i]) { errorCorrectionMethod = errorCorrectionValues[i]; foundErrorCorrectionFlag = true; break; } } if (foundErrorCorrectionFlag == false) { throw CommandException("Invalid error correction: " + errorCorrectionName); } // // Check if generating landmarks is valid // if (landmarksFlag) { SpecFile sf; sf.readFile(specFileName); const StereotaxicSpace space = sf.getSpace(); const bool validLandmarkSpaceFlag = BrainModelSurfaceBorderLandmarkIdentification::isStereotaxicSpaceSupported(space); if (validLandmarkSpaceFlag == false) { throw CommandException("Generation of flattening/landmark landmark borders " "not supported for stereotaxic space: " + space.getName()); } } // // Create a brain set // BrainSet brainSet(specFileName, false, true); // // For anterior commissure voxel index // const float zeros[3] = { 0.0, 0.0, 0.0 }; int acIJK[3]; // // Read the anatomy volume file // VolumeFile inputAnatomyVolume; if (inputAnatomyVolumeFileName.isEmpty() == false) { inputAnatomyVolume.readFile(inputAnatomyVolumeFileName); inputAnatomyVolume.convertCoordinatesToVoxelIJK(zeros, acIJK); } // // Read the segmentation volume file // VolumeFile inputSegmentationVolume; if (inputSegmentationVolumeFileName.isEmpty() == false) { inputSegmentationVolume.readFile(inputSegmentationVolumeFileName); inputSegmentationVolume.convertCoordinatesToVoxelIJK(zeros, acIJK); } // // Create the segmentation object // BrainModelVolumeSureFitSegmentation segmentationObject(&brainSet, &inputAnatomyVolume, &inputSegmentationVolume, writeVolumeType, acIJK, paddingAmount, whitePeak, grayPeak, 0.0, structure, disconnectEyeFlag, disconnectHindbrainFlag, disconnectHindHiThreshFlag, cutCorpusCallossumFlag, generateSegmentationFlag, fillVentriclesFlag, errorCorrectionMethod, rawFiducialSurfaceFlag, (reduceSurfacePolygonsFlag == false), topologicalCorrectFlag, inflatedSurfaceFlag, veryInflatedSurfaceFlag, ellipsoidSurfaceFlag, sphericalSurfaceFlag, compMedWallSurfaceFlag, hullSurfaceFlag, depthCurveGeographyFlag, landmarksFlag, true); // // Execute the segmentation // segmentationObject.execute(); const QString warningMessages = segmentationObject.getWarningMessages(); if (warningMessages.isEmpty() == false) { std::cout << "Segmentation Warnings: " << warningMessages.toAscii().constData() << std::endl; } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeSculpt.h0000664000175000017500000000337511572067322025742 0ustar michaelmichael #ifndef __COMMAND_VOLUME_SCULPT_H__ #define __COMMAND_VOLUME_SCULPT_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for sculpting a volume class CommandVolumeSculpt : public CommandBase { public: // constructor CommandVolumeSculpt(); // destructor ~CommandVolumeSculpt(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_SCULPT_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeSculpt.cxx0000664000175000017500000001363611572067322026316 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeSculpt.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeSculpt::CommandVolumeSculpt() : CommandBase("-volume-sculpt", "VOLUME SCULPT") { } /** * destructor. */ CommandVolumeSculpt::~CommandVolumeSculpt() { } /** * get the script builder parameters. */ void CommandVolumeSculpt::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { std::vector values, descriptions; values.push_back("AND"); descriptions.push_back("AND"); values.push_back("SEED-AND"); descriptions.push_back("SEED-AND"); values.push_back("AND-NOT"); descriptions.push_back("AND-NOT"); values.push_back("SEED-AND-NOT"); descriptions.push_back("SEED-AND-NOT"); paramsOut.clear(); paramsOut.addFile("Input Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Other Input Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Output Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addInt("i-minimum"); paramsOut.addInt("i-maximum"); paramsOut.addInt("j-minimum"); paramsOut.addInt("j-maximum"); paramsOut.addInt("k-minimum"); paramsOut.addInt("k-maximum"); paramsOut.addInt("i-seed"); paramsOut.addInt("j-seed"); paramsOut.addInt("k-seed"); paramsOut.addListOfItems("Mode", values, descriptions); paramsOut.addInt("Number Of Steps"); } /** * get full help information. */ QString CommandVolumeSculpt::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Sculpt a volume.\n" + indent9 + "\n" + indent9 + "\"mode\" is one of:\n" + indent9 + " AND\n" + indent9 + " SEED-AND\n" + indent9 + " AND-NOT\n" + indent9 + " SEED-AND-NOT\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeSculpt::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); const QString otherVolumeFileName = parameters->getNextParameterAsString("Other Volume File Name"); QString outputVolumeFileName, outputVolumeFileLabel; parameters->getNextParameterAsVolumeFileNameAndLabel("Output Volume File Name/Label", outputVolumeFileName, outputVolumeFileLabel); int extent[6] = { parameters->getNextParameterAsInt("i-minimum"), parameters->getNextParameterAsInt("i-maximum"), parameters->getNextParameterAsInt("j-minimum"), parameters->getNextParameterAsInt("j-maximum"), parameters->getNextParameterAsInt("k-minimum"), parameters->getNextParameterAsInt("k-maximum") }; int seed[3] = { parameters->getNextParameterAsInt("i-seed"), parameters->getNextParameterAsInt("j-seed"), parameters->getNextParameterAsInt("k-seed") }; const QString modeString = parameters->getNextParameterAsString("Mode"); const int numberOfSteps = parameters->getNextParameterAsInt("Number of Steps"); checkForExcessiveParameters(); VolumeFile::SCULPT_MODE mode; if (modeString == "AND") { mode = VolumeFile::SCULPT_MODE_AND; } else if (modeString == "SEED-AND") { mode = VolumeFile::SCULPT_MODE_SEED_AND; } else if (modeString == "AND-NOT") { mode = VolumeFile::SCULPT_MODE_AND_NOT; } else if (modeString == "SEED-AND-NOT") { mode = VolumeFile::SCULPT_MODE_SEED_AND_NOT; } else { throw CommandException("Invalid sculpt mode: " + modeString); } // // Read the input file // VolumeFile volume; volume.readFile(inputVolumeFileName); // // Read the other volume // VolumeFile otherVolume; otherVolume.readFile(otherVolumeFileName); // // sculpt // volume.sculptVolume(mode, &otherVolume, numberOfSteps, seed, extent); // // Write the volume // writeVolumeFile(volume, outputVolumeFileName, outputVolumeFileLabel); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeScalePercent0to255.h0000664000175000017500000000353711572067322027717 0ustar michaelmichael #ifndef __COMMAND_VOLUME_SCALE_PERCENT_TO_0_TO_255_H__ #define __COMMAND_VOLUME_SCALE_PERCENT_TO_0_TO_255_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for scaling voxels 0 to 255 class CommandVolumeScalePercent0to255 : public CommandBase { public: // constructor CommandVolumeScalePercent0to255(); // destructor ~CommandVolumeScalePercent0to255(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_SCALE_PERCENT_TO_0_TO_255_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeScalePercent0to255.cxx0000664000175000017500000001054711572067322030271 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeScalePercent0to255.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeScalePercent0to255::CommandVolumeScalePercent0to255() : CommandBase("-volume-scale-percent-min-max-255", "VOLUME SCALE VOXELS 0 to 255 WITH PERCENTAGE OF MIN/MAX") { } /** * destructor. */ CommandVolumeScalePercent0to255::~CommandVolumeScalePercent0to255() { } /** * get the script builder parameters. */ void CommandVolumeScalePercent0to255::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Output Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFloat("Percent Minimum", 2.0); paramsOut.addFloat("Percent Maximum", 2.0); } /** * get full help information. */ QString CommandVolumeScalePercent0to255::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + " \n" + indent9 + " \n" + indent9 + "\n" + indent9 + "Scale voxels.\n" + indent9 + "\n" + indent9 + "Scale voxels so that they are in the range 0 to 255 but\n" + indent9 + "map the first \"percent-minimum\" voxels to 0 and map the\n" + indent9 + "last \"percent-maximum\" voxels to 255.\n" + indent9 + "\n" + indent9 + "The \"percent-minimum\" and \"percent-maximum\" values should\n" + indent9 + "range from 0.0 to 100.0. Setting the \"percent-minimum\" to\n" + indent9 + "2.0 and the \"percent-maximum\" to 3.0 will result in the first\n" + indent9 + "two percent of voxel values being mapped to zero and the last\n" + indent9 + "three percent of voxel values being mapped to two hundred\n" + indent9 + "fifty five.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeScalePercent0to255::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); QString outputVolumeFileName, outputVolumeFileLabel; parameters->getNextParameterAsVolumeFileNameAndLabel("Output Volume File Name/Label", outputVolumeFileName, outputVolumeFileLabel); const float percentMinimum = parameters->getNextParameterAsFloat("Percent Minimum"); const float percentMaximum = parameters->getNextParameterAsFloat("Percent Maximum"); checkForExcessiveParameters(); // // Read the input file // VolumeFile volume; volume.readFile(inputVolumeFileName); // // rescale // volume.stretchVoxelValuesExcludePercentage(percentMinimum, percentMaximum); // // Write the volume // writeVolumeFile(volume, outputVolumeFileName, outputVolumeFileLabel); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeScale0to255.h0000664000175000017500000000342111572067322026366 0ustar michaelmichael #ifndef __COMMAND_VOLUME_SCALE_0_TO_255_H__ #define __COMMAND_VOLUME_SCALE_0_TO_255_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandVolumeScale0to255 : public CommandBase { public: // constructor CommandVolumeScale0to255(); // destructor ~CommandVolumeScale0to255(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_SCALE_0_TO_255_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeScale0to255.cxx0000664000175000017500000000626011572067322026745 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeScale0to255.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeScale0to255::CommandVolumeScale0to255() : CommandBase("-volume-scale-255", "VOLUME SCALE VOXELS 0 to 255") { } /** * destructor. */ CommandVolumeScale0to255::~CommandVolumeScale0to255() { } /** * get the script builder parameters. */ void CommandVolumeScale0to255::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Output Volume File Name", FileFilters::getVolumeGenericFileFilter()); } /** * get full help information. */ QString CommandVolumeScale0to255::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Scale voxels so that they range from 0 to 255.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeScale0to255::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); QString outputVolumeFileName, outputVolumeFileLabel; parameters->getNextParameterAsVolumeFileNameAndLabel("Output Volume File Name/Label", outputVolumeFileName, outputVolumeFileLabel); checkForExcessiveParameters(); // // Read the input file // VolumeFile volume; volume.readFile(inputVolumeFileName); // // rescale // volume.stretchVoxelValues(); // // Write the volume // writeVolumeFile(volume, outputVolumeFileName, outputVolumeFileLabel); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeResize.h0000664000175000017500000000335211572067322025724 0ustar michaelmichael #ifndef __COMMAND_VOLUME_RESIZE_H__ #define __COMMAND_VOLUME_RESIZE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandVolumeResize : public CommandBase { public: // constructor CommandVolumeResize(); // destructor ~CommandVolumeResize(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_RESIZE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeResize.cxx0000664000175000017500000000764611572067322026311 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeResize.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeResize::CommandVolumeResize() : CommandBase("-volume-resize", "VOLUME RESIZE") { } /** * destructor. */ CommandVolumeResize::~CommandVolumeResize() { } /** * get the script builder parameters. */ void CommandVolumeResize::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Output Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addInt("x-min", 0); paramsOut.addInt("x-max", 0); paramsOut.addInt("y-min", 0); paramsOut.addInt("y-max", 0); paramsOut.addInt("z-min", 0); paramsOut.addInt("z-max", 0); } /** * get full help information. */ QString CommandVolumeResize::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Resize a volume.\n" + indent9 + "\n" + indent9 + "If \"min\" values are less than zero, voxels will be\n" + indent9 + "added to that side of the volume\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeResize::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); QString outputVolumeFileName, outputVolumeFileLabel; parameters->getNextParameterAsVolumeFileNameAndLabel("Output Volume File Name/Label", outputVolumeFileName, outputVolumeFileLabel); const int cropping[6] = { parameters->getNextParameterAsInt("x-min"), parameters->getNextParameterAsInt("x-max"), parameters->getNextParameterAsInt("y-min"), parameters->getNextParameterAsInt("y-max"), parameters->getNextParameterAsInt("z-min"), parameters->getNextParameterAsInt("z-max") }; // // Read the input file // VolumeFile volume; volume.readFile(inputVolumeFileName); // // resize the volume // volume.resize(cropping); // // Write the volume // writeVolumeFile(volume, outputVolumeFileName, outputVolumeFileLabel); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeRescaleVoxels.h0000664000175000017500000000342711572067322027245 0ustar michaelmichael #ifndef __COMMAND_VOLUME_RESCALE_VOXELS_H__ #define __COMMAND_VOLUME_RESCALE_VOXELS_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandVolumeRescaleVoxels : public CommandBase { public: // constructor CommandVolumeRescaleVoxels(); // destructor ~CommandVolumeRescaleVoxels(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_RESCALE_VOXELS_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeRescaleVoxels.cxx0000664000175000017500000001016411572067322027614 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeRescaleVoxels.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeRescaleVoxels::CommandVolumeRescaleVoxels() : CommandBase("-volume-rescale-voxels", "VOLUME RESCALE VOXELS") { } /** * destructor. */ CommandVolumeRescaleVoxels::~CommandVolumeRescaleVoxels() { } /** * get the script builder parameters. */ void CommandVolumeRescaleVoxels::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Output Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFloat("Input Minimum Value", 0); paramsOut.addFloat("Input Maximum Value", 255); paramsOut.addFloat("Output Minimum Value", 0); paramsOut.addFloat("Output Maximum Value", 255); } /** * get full help information. */ QString CommandVolumeRescaleVoxels::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Rescale a volume's voxels.\n" + indent9 + "\"input-min\" and below are mapped to \"output-min\".\n" + indent9 + "\"input-max\" and above are mapped to \"output-max\".\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeRescaleVoxels::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); QString outputVolumeFileName, outputVolumeFileLabel; parameters->getNextParameterAsVolumeFileNameAndLabel("Output Volume File Name/Label", outputVolumeFileName, outputVolumeFileLabel); const float inputMinimum = parameters->getNextParameterAsFloat("Input Minimum"); const float inputMaximum = parameters->getNextParameterAsFloat("Input Maximum"); const float outputMinimum = parameters->getNextParameterAsFloat("Output Minimum"); const float outputMaximum = parameters->getNextParameterAsFloat("Output Maximum"); checkForExcessiveParameters(); // // Read the input file // VolumeFile volume; volume.readFile(inputVolumeFileName); // // set the orientation // volume.rescaleVoxelValues(inputMinimum, inputMaximum, outputMinimum, outputMaximum); // // Write the volume // writeVolumeFile(volume, outputVolumeFileName, outputVolumeFileLabel); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeResample.h0000664000175000017500000000336611572067322026240 0ustar michaelmichael #ifndef __COMMAND_VOLUME_RESAMPLE_H__ #define __COMMAND_VOLUME_RESAMPLE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandVolumeResample : public CommandBase { public: // constructor CommandVolumeResample(); // destructor ~CommandVolumeResample(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_RESAMPLE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeResample.cxx0000664000175000017500000001267511572067322026616 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeResample.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeResample::CommandVolumeResample() : CommandBase("-volume-resample", "VOLUME RESAMPLE") { } /** * destructor. */ CommandVolumeResample::~CommandVolumeResample() { } /** * get the script builder parameters. */ void CommandVolumeResample::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { std::vector methodValues, methodDescriptions; methodValues.push_back("INTERP_CUBIC"); methodDescriptions.push_back("Cubic (best quality)"); methodValues.push_back("INTERP_LINEAR"); methodDescriptions.push_back("Linear"); methodValues.push_back("INTERP_NEAREST_NEIGHBOR"); methodDescriptions.push_back("Nearest Neighbors (use for paint and probabilistic volumes"); paramsOut.clear(); paramsOut.addFile("Input Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Output Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFloat("New Spacing X"); paramsOut.addFloat("New Spacing Y"); paramsOut.addFloat("New Spacing Z"); paramsOut.addListOfItems("Interpolation Mode", methodValues, methodDescriptions); } /** * get full help information. */ QString CommandVolumeResample::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Resample a volume to the specified spacing.\n" + indent9 + "\n" + indent9 + "\"interpolation-mode\" is one of:\n" + indent9 + " INTERP_CUBIC\n" + indent9 + " INTERP_LINEAR\n" + indent9 + " INTERP_NEAREST_NEIGHBOR\n" + indent9 + "\n" + indent9 + "For paint, probabilistic atlas, and segmentation volumes,\n" + indent9 + " you MUST use INTERP_NEAREST_NEIGHBOR for the interpolation.\n" + indent9 + "mode. INTERP_CUBIC is recommended for all other volume file\n" + indent9 + "types.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeResample::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); QString outputVolumeFileName, outputVolumeFileLabel; parameters->getNextParameterAsVolumeFileNameAndLabel("Output Volume File Name/Label", outputVolumeFileName, outputVolumeFileLabel); const float spacing[3] = { parameters->getNextParameterAsFloat("New Spacing X"), parameters->getNextParameterAsFloat("New Spacing Y"), parameters->getNextParameterAsFloat("New Spacing Z") }; const QString interpolationName = parameters->getNextParameterAsString("Interpolation"); checkForExcessiveParameters(); VolumeFile::INTERPOLATION_TYPE interpolationType = VolumeFile::INTERPOLATION_TYPE_CUBIC; if (interpolationName == "INTERP_CUBIC") { interpolationType = VolumeFile::INTERPOLATION_TYPE_CUBIC; } else if (interpolationName == "INTERP_LINEAR") { interpolationType = VolumeFile::INTERPOLATION_TYPE_LINEAR; } else if (interpolationName == "INTERP_NEAREST_NEIGHBOR") { interpolationType = VolumeFile::INTERPOLATION_TYPE_NEAREST_NEIGHBOR; } else { throw CommandException("Invalid interpolation value \"" + interpolationName + "\""); } // // Read the input file // VolumeFile volume; volume.readFile(inputVolumeFileName); // // set the spacing // volume.resampleToSpacing(spacing, interpolationType); // // Write the volume // writeVolumeFile(volume, outputVolumeFileName, outputVolumeFileLabel); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeReplaceVoxelsWithVectorMagnitude.h0000664000175000017500000000370311572067322033114 0ustar michaelmichael #ifndef __COMMAND_VOLUME_REPLACE_VOXELS_WITH_VECTOR_MAGNITUDE_H__ #define __COMMAND_VOLUME_REPLACE_VOXELS_WITH_VECTOR_MAGNITUDE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for replace voxels with magintude from vector volume class CommandVolumeReplaceVoxelsWithVectorMagnitude : public CommandBase { public: // constructor CommandVolumeReplaceVoxelsWithVectorMagnitude(); // destructor ~CommandVolumeReplaceVoxelsWithVectorMagnitude(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_REPLACE_VOXELS_WITH_VECTOR_MAGNITUDE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeReplaceVoxelsWithVectorMagnitude.cxx0000664000175000017500000000721711572067322033473 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeReplaceVoxelsWithVectorMagnitude.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SureFitVectorFile.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeReplaceVoxelsWithVectorMagnitude::CommandVolumeReplaceVoxelsWithVectorMagnitude() : CommandBase("-volume-copy-vector-mag", "VOLUME COPY VECTOR FILE MAGNITUDE INTO VOXELS") { } /** * destructor. */ CommandVolumeReplaceVoxelsWithVectorMagnitude::~CommandVolumeReplaceVoxelsWithVectorMagnitude() { } /** * get the script builder parameters. */ void CommandVolumeReplaceVoxelsWithVectorMagnitude::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Vector File Name", FileFilters::getVolumeVectorFileFilter()); paramsOut.addFile("Input Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Ooutput Volume File Name", FileFilters::getVolumeGenericFileFilter()); } /** * get full help information. */ QString CommandVolumeReplaceVoxelsWithVectorMagnitude::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Replace the volume's voxels with the vector file's magnitude.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeReplaceVoxelsWithVectorMagnitude::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString vectorFileName = parameters->getNextParameterAsString("Vector File Name"); const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); QString outputVolumeFileName = parameters->getNextParameterAsString("Output Volume File Name"); QString outputVolumeFileLabel; splitOutputVolumeNameIntoNameAndLabel(outputVolumeFileName, outputVolumeFileLabel); VolumeFile volumeFile; volumeFile.readFile(inputVolumeFileName); SureFitVectorFile vectorFile; vectorFile.readFile(vectorFileName); vectorFile.copyMagnitudeToVolume(&volumeFile); writeVolumeFile(volumeFile, outputVolumeFileName, outputVolumeFileLabel); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeReplaceVectorMagnitudeWithVolume.h0000664000175000017500000000367311572067322033111 0ustar michaelmichael #ifndef __COMMAND_VOLUME_REPLACE_VECTOR_MAGNITUDE_WITH_VOLUME_H__ #define __COMMAND_VOLUME_REPLACE_VECTOR_MAGNITUDE_WITH_VOLUME_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for replacing vector magnitude with a volume class CommandVolumeReplaceVectorMagnitudeWithVolume : public CommandBase { public: // constructor CommandVolumeReplaceVectorMagnitudeWithVolume(); // destructor ~CommandVolumeReplaceVectorMagnitudeWithVolume(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_REPLACE_VECTOR_MAGNITUDE_WITH_VOLUME_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeReplaceVectorMagnitudeWithVolume.cxx0000664000175000017500000001107211572067322033454 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeReplaceVectorMagnitudeWithVolume.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SureFitVectorFile.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeReplaceVectorMagnitudeWithVolume::CommandVolumeReplaceVectorMagnitudeWithVolume() : CommandBase("-volume-vector-replace-mag-volume", "VOLUME VECTOR MAGNITUDE - REPLACE WITH VOLUME") { } /** * destructor. */ CommandVolumeReplaceVectorMagnitudeWithVolume::~CommandVolumeReplaceVectorMagnitudeWithVolume() { } /** * get the script builder parameters. */ void CommandVolumeReplaceVectorMagnitudeWithVolume::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { std::vector values, descriptions; values.push_back("REPLACE"); descriptions.push_back("REPLACE"); values.push_back("MULTIPLY"); descriptions.push_back("MULTIPLY"); paramsOut.clear(); paramsOut.addFile("Input Vector File Name", FileFilters::getSureFitVectorFileFilter()); paramsOut.addFile("Output Vector File Name", FileFilters::getSureFitVectorFileFilter()); paramsOut.addFile("Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addListOfItems("Operation", values, descriptions); } /** * get full help information. */ QString CommandVolumeReplaceVectorMagnitudeWithVolume::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Replace vector file's magnitude.\n" + indent9 + "\n" + indent9 + " \"operation\" is one of:\n" + indent9 + " REPLACE - replace magnitude with volume's voxel\n" + indent9 + " MULTIPLY - multiply magnitude with volume's voxel\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeReplaceVectorMagnitudeWithVolume::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputVectorFileName = parameters->getNextParameterAsString("Input Vector File Name"); const QString outputVectorFileName = parameters->getNextParameterAsString("Output Vector File Name"); const QString volumeFileName = parameters->getNextParameterAsString("Volume File Name"); const QString operationString = parameters->getNextParameterAsString("Operation").toUpper(); checkForExcessiveParameters(); SureFitVectorFile::COMBINE_VOLUME_OPERATION operation; if (operationString == "REPLACE") { operation = SureFitVectorFile::COMBINE_VOLUME_REPLACE_MAGNITUDE_WITH_VOLUME; } else if (operationString == "MULTIPLY") { operation = SureFitVectorFile::COMBINE_VOLUME_MULTIPLY_MAGNITUDE_WITH_VOLUME; } else { throw CommandException("Invalid operation \"" + operationString + "\""); } // // Read the input files // SureFitVectorFile vector; vector.readFile(inputVectorFileName); VolumeFile volume; volume.readFile(volumeFileName); // // replace magnitude with volume's voxels // vector.combineWithVolumeOperation(operation, &volume); // // Write the vector file // vector.writeFile(outputVectorFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeRemoveIslands.h0000664000175000017500000000346611572067322027244 0ustar michaelmichael #ifndef __COMMAND_VOLUME_REMOVE_ISLANDS_H__ #define __COMMAND_VOLUME_REMOVE_ISLANDS_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for removing islands from a volume class CommandVolumeRemoveIslands : public CommandBase { public: // constructor CommandVolumeRemoveIslands(); // destructor ~CommandVolumeRemoveIslands(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_REMOVE_ISLANDS_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeRemoveIslands.cxx0000664000175000017500000000634211572067322027613 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeRemoveIslands.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeRemoveIslands::CommandVolumeRemoveIslands() : CommandBase("-volume-remove-islands", "VOLUME REMOVE ISLANDS") { } /** * destructor. */ CommandVolumeRemoveIslands::~CommandVolumeRemoveIslands() { } /** * get the script builder parameters. */ void CommandVolumeRemoveIslands::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Output Volume File Name", FileFilters::getVolumeGenericFileFilter()); } /** * get full help information. */ QString CommandVolumeRemoveIslands::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Remove islands (small disconnected pieces) from a volume file.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeRemoveIslands::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); QString outputVolumeFileName, outputVolumeFileLabel; parameters->getNextParameterAsVolumeFileNameAndLabel("Output Volume File Name/Label", outputVolumeFileName, outputVolumeFileLabel); checkForExcessiveParameters(); // // Read the input file // VolumeFile volume; volume.readFile(inputVolumeFileName); // // remove the idslands // volume.removeIslandsFromSegmentation(); // // Write the volume // writeVolumeFile(volume, outputVolumeFileName, outputVolumeFileLabel); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeROISmoothing.h0000664000175000017500000000366111572067322027007 0ustar michaelmichael//*VolumeROISmooth* *CreateCifti* *VolumeAtlas* main.cxx CommandBase.* CommandVolumeROIGrad* *CommandMetricTrans* *CommandMetricROI* build16 *ModelVolumeROIGrad* #ifndef __COMMAND_VOLUME_ROI_SMOOTHING_H__ #define __COMMAND_VOLUME_ROI_SMOOTHING_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandVolumeROISmoothing : public CommandBase { public: // constructor CommandVolumeROISmoothing(); // destructor ~CommandVolumeROISmoothing(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_ROI_GRADIENT_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeROISmoothing.cxx0000664000175000017500000001073011572067322027355 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "CommandVolumeROISmoothing.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "BrainModelVolumeROISmoothing.h" #include "BrainSet.h" #include "StringUtilities.h" #include "FileUtilities.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeROISmoothing::CommandVolumeROISmoothing() : CommandBase("-volume-roi-smoothing", "PARCEL CONSTRAINED SMOOTHING") { } /** * destructor. */ CommandVolumeROISmoothing::~CommandVolumeROISmoothing() { } /** * get the script builder parameters. */ void CommandVolumeROISmoothing::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Volume File", FileFilters::getVolumeFunctionalFileFilter()); paramsOut.addFile("Input Volume ROI File", FileFilters::getVolumeSegmentationFileFilter()); paramsOut.addFile("Output Volume File", FileFilters::getVolumeFunctionalFileFilter()); paramsOut.addFloat("Weighting Kernel", 1.0, 0.0); } /** * get full help information. */ QString CommandVolumeROISmoothing::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Perform 3D Gaussian weighted smoothing of kernel within\n" + indent9 + "the given ROI. The smoothing only considers voxels inside the\n" + indent9 + "ROI and the output will only contain these voxels. The input\n" + indent9 + "volume and input ROI must have the same image matrix and\n" + indent9 + "dimensions. The command will accept either 3D or 4D inputs and\n" + indent9 + "will do the smoothing frame by frame. It will output either 3D\n" + indent9 + "or 4D outputs." + indent9 + "\n" + indent9 + " values-volume the input file\n" + indent9 + "\n" + indent9 + " region-volume the region file\n" + indent9 + "\n" + indent9 + " output-volume the output file\n" + indent9 + "\n" + indent9 + " sigma sigma for the weighting function for\n" + indent9 + " weighted least squares\n" + indent9 + "\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeROISmoothing::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString values = parameters->getNextParameterAsString("Input Volume File"); const QString region = parameters->getNextParameterAsString("Input Region File"); const QString output = parameters->getNextParameterAsString("Output Volume File"); const float kernel = parameters->getNextParameterAsFloat("Kernel Size"); BrainSet mybs; VolumeFile valueFile, regionFile; valueFile.readFile(values); regionFile.readFile(region); std::vector outFileVec; BrainModelVolumeROISmoothing mysmooth(&mybs, &valueFile, ®ionFile, &outFileVec, kernel); mysmooth.execute(); VolumeFile::writeFile(output, outFileVec[0]->getVolumeType(), outFileVec[0]->getVoxelDataType(), outFileVec); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeROIMinima.h0000664000175000017500000000337711572067322026256 0ustar michaelmichael #ifndef __COMMAND_VOLUME_ROI_MINIMA_H__ #define __COMMAND_VOLUME_ROI_MINIMA_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandVolumeROIMinima : public CommandBase { public: // constructor CommandVolumeROIMinima(); // destructor ~CommandVolumeROIMinima(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_ROI_MINIMA_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeROIMinima.cxx0000664000175000017500000000766211572067322026632 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "CommandVolumeROIMinima.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "BrainModelVolumeROIMinima.h" #include "BrainSet.h" #include "StringUtilities.h" #include "FileUtilities.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeROIMinima::CommandVolumeROIMinima() : CommandBase("-volume-roi-minima", "VOLUME REGION OF INTEREST MINIMA") { } /** * destructor. */ CommandVolumeROIMinima::~CommandVolumeROIMinima() { } /** * get the script builder parameters. */ void CommandVolumeROIMinima::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Volume File", FileFilters::getVolumeFunctionalFileFilter()); paramsOut.addFile("Input Volume ROI File", FileFilters::getVolumeSegmentationFileFilter()); paramsOut.addFile("Output Volume File", FileFilters::getVolumeFunctionalFileFilter()); paramsOut.addFloat("Distance", 1.0, 0.0); } /** * get full help information. */ QString CommandVolumeROIMinima::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Find the minima of part of a volume file. Does not use information\n" + indent9 + "from voxels that are 0 or negative in region-volume.\n" + indent9 + "\n" + indent9 + " values-volume the input file\n" + indent9 + "\n" + indent9 + " region-volume the region file\n" + indent9 + "\n" + indent9 + " output-volume the output file\n" + indent9 + "\n" + indent9 + " distance distance cutoff for range to search for\n" + indent9 + " smaller values\n" + indent9 + "\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeROIMinima::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString values = parameters->getNextParameterAsString("Input Volume File"); const QString region = parameters->getNextParameterAsString("Input Region File"); const QString output = parameters->getNextParameterAsString("Output Volume File"); const float dist = parameters->getNextParameterAsFloat("Distance"); BrainSet mybs; VolumeFile valueFile, regionFile, outFile; valueFile.readFile(values); regionFile.readFile(region); BrainModelVolumeROIMinima mymin(&mybs, &valueFile, ®ionFile, &outFile, dist); mymin.execute(); outFile.writeFile(output); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeROIGradient.h0000664000175000017500000000341311572067322026570 0ustar michaelmichael #ifndef __COMMAND_VOLUME_ROI_GRADIENT_H__ #define __COMMAND_VOLUME_ROI_GRADIENT_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandVolumeROIGradient : public CommandBase { public: // constructor CommandVolumeROIGradient(); // destructor ~CommandVolumeROIGradient(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_ROI_GRADIENT_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeROIGradient.cxx0000664000175000017500000001046711572067322027152 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "CommandVolumeROIGradient.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "BrainModelVolumeROIGradient.h" #include "BrainSet.h" #include "StringUtilities.h" #include "FileUtilities.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeROIGradient::CommandVolumeROIGradient() : CommandBase("-volume-roi-gradient", "VOLUME REGION OF INTEREST GRADIENT MAGNITUDE") { } /** * destructor. */ CommandVolumeROIGradient::~CommandVolumeROIGradient() { } /** * get the script builder parameters. */ void CommandVolumeROIGradient::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Volume File", FileFilters::getVolumeFunctionalFileFilter()); paramsOut.addFile("Input Volume ROI File", FileFilters::getVolumeSegmentationFileFilter()); paramsOut.addFile("Output Volume File", FileFilters::getVolumeFunctionalFileFilter()); paramsOut.addFloat("Weighting Kernel", 1.0, 0.0); } /** * get full help information. */ QString CommandVolumeROIGradient::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Generate the gradient of part of a volume file. Does not use\n" + indent9 + "information from voxels that are 0 or negative in region-volume.\n" + indent9 + "Avoids producing bright edges by using weighted linear regression\n" + indent9 + "to estimate the gradient rather than finite differences.\n" + indent9 + "Weight-kernel is the distance in mm where the weight of a voxel is\n" + indent9 + "0.607, weight of the center voxel is 1.\n" + indent9 + "\n" + indent9 + " values-volume the input file\n" + indent9 + "\n" + indent9 + " region-volume the region file\n" + indent9 + "\n" + indent9 + " output-volume the output file\n" + indent9 + "\n" + indent9 + " weight-kernel sigma for the weighting function for\n" + indent9 + " weighted least squares\n" + indent9 + "\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeROIGradient::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString values = parameters->getNextParameterAsString("Input Volume File"); const QString region = parameters->getNextParameterAsString("Input Region File"); const QString output = parameters->getNextParameterAsString("Output Volume File"); const float kernel = parameters->getNextParameterAsFloat("Kernel Size"); BrainSet mybs; VolumeFile valueFile, regionFile, outFile; valueFile.readFile(values); regionFile.readFile(region); BrainModelVolumeROIGradient mygrad(&mybs, &valueFile, ®ionFile, &outFile, kernel); mygrad.execute(); outFile.writeFile(output); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeProbAtlasToFunctional.h0000664000175000017500000000351511572067322030701 0ustar michaelmichael #ifndef __COMMAND_VOLUME_PROB_ATLAS_TO_FUNCTIONAL_H__ #define __COMMAND_VOLUME_PROB_ATLAS_TO_FUNCTIONAL_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandVolumeProbAtlasToFunctional : public CommandBase { public: // constructor CommandVolumeProbAtlasToFunctional(); // destructor ~CommandVolumeProbAtlasToFunctional(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_PROB_ATLAS_TO_FUNCTIONAL_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeProbAtlasToFunctional.cxx0000664000175000017500000001340511572067322031253 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelVolume.h" #include "BrainModelVolumeProbAtlasToFunctional.h" #include "BrainSet.h" #include "CommandVolumeProbAtlasToFunctional.h" #include "DisplaySettingsProbabilisticAtlas.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeProbAtlasToFunctional::CommandVolumeProbAtlasToFunctional() : CommandBase("-volume-prob-atlas-to-functional", "VOLUME PROB ATLAS TO FUNCTIONAL VOLUMES") { } /** * destructor. */ CommandVolumeProbAtlasToFunctional::~CommandVolumeProbAtlasToFunctional() { } /** * get the script builder parameters. */ void CommandVolumeProbAtlasToFunctional::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Prob Atlas Volume", FileFilters::getVolumeProbAtlasFileFilter()); paramsOut.addString("Functional Volume Name Prefix"); paramsOut.addString("Functional Volume Name Suffix"); } /** * get full help information. */ QString CommandVolumeProbAtlasToFunctional::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "For each region name that is not ???, GYRAL, or GYRUS,\n" + indent9 + "create a functional volume where each voxel is the\n" + indent9 + "number volumes that have the region identified for\n" + indent9 + "the voxel.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeProbAtlasToFunctional::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get inputs // const QString inputProbAtlasVolumeFileName = parameters->getNextParameterAsString("Input Prob Atlas Volume File Name"); const QString functionalVolumePrefixName = parameters->getNextParameterAsString("Output Functional Volume File Name Prefix"); const QString functionalVolumeSuffixName = parameters->getNextParameterAsString("Output Functional Volume File Name Suffix"); // // Create and read the prob atlas volume // BrainSet bs; bs.readVolumeFile(inputProbAtlasVolumeFileName, VolumeFile::VOLUME_TYPE_PROB_ATLAS, false, false); BrainModelVolume* bmv = bs.getBrainModelVolume(); if (bmv == NULL) { throw CommandException("Unable to find volumes after reading files."); } if (bs.getNumberOfVolumeProbAtlasFiles() <= 0) { throw CommandException("No prob atlas volume files were read."); } VolumeFile* firstProbAtlasVolumeFile = NULL; if (bs.getNumberOfVolumeProbAtlasFiles() > 0) { firstProbAtlasVolumeFile = bs.getVolumeProbAtlasFile(0); } // // Create the functional volume // VolumeFile functionalVolume(*bs.getVolumeProbAtlasFile(0)); functionalVolume.setVolumeType(VolumeFile::VOLUME_TYPE_FUNCTIONAL); // // Process each prob atlas name // DisplaySettingsProbabilisticAtlas* dspa = bs.getDisplaySettingsProbabilisticAtlasVolume(); const int numNames = firstProbAtlasVolumeFile->getNumberOfRegionNames(); for (int i = 0; i < numNames; i++) { // // Get the name // const QString areaName = firstProbAtlasVolumeFile->getRegionNameFromIndex(i); if ((areaName != "???") && (areaName != "GYRAL") && (areaName != "GYRUS")) { // // Turn on only this name // for (int j = 0; j < numNames; j++) { if (i == j) { dspa->setAreaSelected(j, true); } else { dspa->setAreaSelected(j, false); } } // // Name for functional volume // const QString funcVolumeName = functionalVolumePrefixName + areaName + functionalVolumeSuffixName; // // Convert to functional volume // BrainModelVolumeProbAtlasToFunctional paf(&bs, &functionalVolume, funcVolumeName, areaName); paf.execute(); // // Write the functional volume // functionalVolume.writeFile(funcVolumeName); } } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumePadVolume.h0000664000175000017500000000342011572067322026353 0ustar michaelmichael #ifndef __COMMAND_VOLUME_PAD_VOLUME_H__ #define __COMMAND_VOLUME_PAD_VOLUME_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for padding a volume class CommandVolumePadVolume : public CommandBase { public: // constructor CommandVolumePadVolume(); // destructor ~CommandVolumePadVolume(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_PAD_VOLUME_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumePadVolume.cxx0000664000175000017500000001061411572067322026731 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumePadVolume.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumePadVolume::CommandVolumePadVolume() : CommandBase("-volume-pad-volume", "VOLUME PAD A VOLUME") { } /** * destructor. */ CommandVolumePadVolume::~CommandVolumePadVolume() { } /** * get the script builder parameters. */ void CommandVolumePadVolume::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Output Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addInt("Pad Neg X", 0, 0); paramsOut.addInt("Pad Pos X", 0, 0); paramsOut.addInt("Pad Neg Y", 0, 0); paramsOut.addInt("Pad Pos Y", 0, 0); paramsOut.addInt("Pad Neg Z", 0, 0); paramsOut.addInt("Pad Pos Z", 0, 0); paramsOut.addBoolean("Erode Padding Flag", true); } /** * get full help information. */ QString CommandVolumePadVolume::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Add padding (empty voxels) around a volume.\n" + indent9 + "\n" + indent9 + "If \"erode-padding-flag\" is \"true\", the padding\n" + indent9 + "will be slightly eroded just as in the SureFit\n" + indent9 + "segmentation algorithm.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumePadVolume::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); QString outputVolumeFileName, outputVolumeFileLabel; parameters->getNextParameterAsVolumeFileNameAndLabel("Output Volume File Name/Label", outputVolumeFileName, outputVolumeFileLabel); const int padding[6] = { parameters->getNextParameterAsInt("pad-neg-x"), parameters->getNextParameterAsInt("pad-pos-x"), parameters->getNextParameterAsInt("pad-neg-y"), parameters->getNextParameterAsInt("pad-pos-y"), parameters->getNextParameterAsInt("pad-neg-z"), parameters->getNextParameterAsInt("pad-pos-z") }; const bool erodePaddingFlag = parameters->getNextParameterAsBoolean("Erode Padding Flag"); checkForExcessiveParameters(); // // Read the input file // VolumeFile volume; volume.readFile(inputVolumeFileName); // // pad the volume // volume.padSegmentation(padding, erodePaddingFlag); // // Write the volume // writeVolumeFile(volume, outputVolumeFileName, outputVolumeFileLabel); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeNearToPlane.h0000664000175000017500000000344311572067322026634 0ustar michaelmichael #ifndef __COMMAND_VOLUME_NEAR_TO_PLANE_H__ #define __COMMAND_VOLUME_NEAR_TO_PLANE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for volume near to plane class CommandVolumeNearToPlane : public CommandBase { public: // constructor CommandVolumeNearToPlane(); // destructor ~CommandVolumeNearToPlane(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_NEAR_TO_PLANE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeNearToPlane.cxx0000664000175000017500000001175211572067322027211 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelVolumeNearToPlane.h" #include "BrainSet.h" #include "CommandVolumeNearToPlane.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SureFitVectorFile.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeNearToPlane::CommandVolumeNearToPlane() : CommandBase("-volume-near-to-plane", "VOLUME NEAR TO PLANE") { } /** * destructor. */ CommandVolumeNearToPlane::~CommandVolumeNearToPlane() { } /** * get the script builder parameters. */ void CommandVolumeNearToPlane::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Mask Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Input Vector File Name", FileFilters::getSureFitVectorFileFilter()); paramsOut.addFile("Output Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFloat("Sigma-N"); paramsOut.addFloat("Sigma-W"); paramsOut.addFloat("Offset"); paramsOut.addInt("Grad Sign"); paramsOut.addBoolean("Down Flag"); paramsOut.addBoolean("Mask Flag"); } /** * get full help information. */ QString CommandVolumeNearToPlane::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Near to plane operation.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeNearToPlane::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputMaskVolumeFileName = parameters->getNextParameterAsString("Input Mask Volume File Name"); const QString inputVectorFileName = parameters->getNextParameterAsString("Input Vector File Name"); QString outputVolumeFileName, outputVolumeFileLabel; parameters->getNextParameterAsVolumeFileNameAndLabel("Output Volume File Name/Label", outputVolumeFileName, outputVolumeFileLabel); const float sigmaN = parameters->getNextParameterAsFloat("Sigma N"); const float sigmaW = parameters->getNextParameterAsFloat("Sigma W"); const float offset = parameters->getNextParameterAsFloat("Offset"); const int gradSign = parameters->getNextParameterAsInt("Grad Sign"); const bool downFlag = parameters->getNextParameterAsFloat("Down Flag"); const bool maskFlag = parameters->getNextParameterAsFloat("Mask Flag"); checkForExcessiveParameters(); // // Read the input file // VolumeFile maskVolume; maskVolume.readFile(inputMaskVolumeFileName); // // Read the vector file // SureFitVectorFile vectorFile; vectorFile.readFile(inputVectorFileName); VolumeFile outputVolume = maskVolume; // // perform near to plane // BrainSet bs; BrainModelVolumeNearToPlane np(&bs, &vectorFile, sigmaN, sigmaW, offset, downFlag, gradSign, maskFlag, &maskVolume, &outputVolume); np.execute(); // // Write the volume // writeVolumeFile(outputVolume, outputVolumeFileName, outputVolumeFileLabel); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeMaskWithVolume.h0000664000175000017500000000346411572067322027406 0ustar michaelmichael #ifndef __COMMAND_VOLUME_MASK_WITH_VOLUME_H__ #define __COMMAND_VOLUME_MASK_WITH_VOLUME_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for masking with volume class CommandVolumeMaskWithVolume : public CommandBase { public: // constructor CommandVolumeMaskWithVolume(); // destructor ~CommandVolumeMaskWithVolume(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_MASK_WITH_VOLUME_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeMaskWithVolume.cxx0000664000175000017500000001100611572067322027750 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeMaskWithVolume.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeMaskWithVolume::CommandVolumeMaskWithVolume() : CommandBase("-volume-mask-with-volume", "VOLUME MASK WITH VOLUME") { } /** * destructor. */ CommandVolumeMaskWithVolume::~CommandVolumeMaskWithVolume() { } /** * get the script builder parameters. */ void CommandVolumeMaskWithVolume::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Input Mask Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Output Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addInt("Dilation Iterations"); } /** * get full help information. */ QString CommandVolumeMaskWithVolume::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Clear all of the voxels in the input volume that map into\n" + indent9 + "a zero voxel in the mask volume. The mapping is performed\n" + indent9 + "using stereotaxic coordinates so the volumes do not need to have\n" + indent9 + "have the same voxel dimensions but must overlap in stereotaxic\n" + indent9 + "coordinates. Create a mask volume using this program with the\n" + indent9 + "\"-surfaces-to-segmentation-volume-mask\" option.\n" + indent9 + "\n" + indent9 + "If \"dilation-iterations\" is non-zero, the mask will be dilated\n" + indent9 + "the specified number of times prior to the application of the mask.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeMaskWithVolume::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); const QString inputMaskVolumeFileName = parameters->getNextParameterAsString("Input MaskVolume File Name"); QString outputVolumeFileName, outputVolumeFileLabel; parameters->getNextParameterAsVolumeFileNameAndLabel("Output Volume File Name/Label", outputVolumeFileName, outputVolumeFileLabel); const int dilationIterations = parameters->getNextParameterAsInt("Dilation Iterations"); checkForExcessiveParameters(); // // Read the input file // VolumeFile volume; volume.readFile(inputVolumeFileName); // // Read the input mask file // VolumeFile maskVolume; maskVolume.readFile(inputMaskVolumeFileName); // // Dilate mask volume if (dilationIterations > 0) { maskVolume.doVolMorphOps(dilationIterations, 0); } // // mask the volume // volume.maskWithVolume(&maskVolume); // // Write the volume // writeVolumeFile(volume, outputVolumeFileName, outputVolumeFileLabel); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeMaskVolume.h0000664000175000017500000000343411572067322026547 0ustar michaelmichael #ifndef __COMMAND_VOLUME_MASK_VOLUME_H__ #define __COMMAND_VOLUME_MASK_VOLUME_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for creating a mask volume class CommandVolumeMaskVolume : public CommandBase { public: // constructor CommandVolumeMaskVolume(); // destructor ~CommandVolumeMaskVolume(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_MASK_VOLUME_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeMaskVolume.cxx0000664000175000017500000000765411572067322027132 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeMaskVolume.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeMaskVolume::CommandVolumeMaskVolume() : CommandBase("-volume-mask-volume", "VOLUME MASK VOLUME") { } /** * destructor. */ CommandVolumeMaskVolume::~CommandVolumeMaskVolume() { } /** * get the script builder parameters. */ void CommandVolumeMaskVolume::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Output Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addInt("i-minimum"); paramsOut.addInt("i-maximum"); paramsOut.addInt("j-minimum"); paramsOut.addInt("j-maximum"); paramsOut.addInt("k-minimum"); paramsOut.addInt("k-maximum"); } /** * get full help information. */ QString CommandVolumeMaskVolume::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Clear all of the voxels outside the specified extent.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeMaskVolume::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); QString outputVolumeFileName, outputVolumeFileLabel; parameters->getNextParameterAsVolumeFileNameAndLabel("Output Volume File Name/Label", outputVolumeFileName, outputVolumeFileLabel); const int extent[6] = { parameters->getNextParameterAsInt("i-minimum"), parameters->getNextParameterAsInt("i-maximum"), parameters->getNextParameterAsInt("j-minimum"), parameters->getNextParameterAsInt("j-maximum"), parameters->getNextParameterAsInt("k-minimum"), parameters->getNextParameterAsInt("k-maximum") }; checkForExcessiveParameters(); // // Read the input file // VolumeFile volume; volume.readFile(inputVolumeFileName); // // make the volume // volume.maskVolume(extent); // // Write the volume // writeVolumeFile(volume, outputVolumeFileName, outputVolumeFileLabel); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeMapToVtkModel.h0000664000175000017500000000343511572067322027153 0ustar michaelmichael #ifndef __COMMAND_VOLUME_MAP_TO_VTK_MODEL_H__ #define __COMMAND_VOLUME_MAP_TO_VTK_MODEL_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandVolumeMapToVtkModel : public CommandBase { public: // constructor CommandVolumeMapToVtkModel(); // destructor ~CommandVolumeMapToVtkModel(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_MAP_TO_VTK_MODEL_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeMapToVtkModel.cxx0000664000175000017500000001457711572067322027537 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelVolumeToVtkSurfaceMapper.h" #include "BrainSet.h" #include "CommandVolumeMapToVtkModel.h" #include "FileFilters.h" #include "PaletteFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" #include "VtkModelFile.h" /** * constructor. */ CommandVolumeMapToVtkModel::CommandVolumeMapToVtkModel() : CommandBase("-volume-map-to-vtk-model", "VOLUME MAP TO VTK MODEL") { } /** * destructor. */ CommandVolumeMapToVtkModel::~CommandVolumeMapToVtkModel() { } /** * get the script builder parameters. */ void CommandVolumeMapToVtkModel::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input VTK Model File", FileFilters::getVtkModelFileFilter()); paramsOut.addFile("Output VTK Model File", FileFilters::getVtkModelFileFilter()); paramsOut.addFile("Input Volume File", FileFilters::getVolumeFunctionalFileFilter()); paramsOut.addInt("Input Sub-Volume Number", 1); paramsOut.addString("Palette Name or Number", "1"); paramsOut.addVariableListOfParameters("Options"); } /** * get full help information. */ QString CommandVolumeMapToVtkModel::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-palette-file input-palette_file-name]\n" + indent9 + "\n" + indent9 + "Map the specified volume to the VTK model and color the\n" + indent9 + "model using the specified palette.\n" + indent9 + "\n" + indent9 + "The sub-volume number is the index of the sub-volume in\n" + indent9 + "the volume file and the numbers start at 1.\n" + indent9 + "\n" + indent9 + "If a number is used for the palette, the numbers start at 1.\n" + indent9 + "\n" + indent9 + "If a palette file is NOT specified, the following palettes\n" + indent9 + "are available:\n"); PaletteFile pf; for (int i = 0; i < pf.getNumberOfPalettes(); i++) { helpInfo += (indent9 + " " + pf.getPalette(i)->getName()); } helpInfo += ( indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeMapToVtkModel::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the parameters // const QString inputVtkModelFileName = parameters->getNextParameterAsString("Input VTK Model File Name"); const QString outputVtkModelFileName = parameters->getNextParameterAsString("Output VTK Model File Name"); const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); const int inputSubVolumeNumber = parameters->getNextParameterAsInt("Input Sub-Volume Number"); const QString inputPaletteNameOrNumber = parameters->getNextParameterAsString("Input Palette Name or Number"); QString inputPaletteFileName; while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("Optional parameter"); if (paramName == "-palette-file") { inputPaletteFileName = parameters->getNextParameterAsString("Palette File Name"); } } // // Read the VTK Model // VtkModelFile vtkModelFile; vtkModelFile.readFile(inputVtkModelFileName); // // Read the volume file // std::vector volumeFiles; VolumeFile::readFile(inputVolumeFileName, -1, volumeFiles); const int numberOfVolumesRead = static_cast(volumeFiles.size()); // // Get the volume for mapping // VolumeFile* mappingVolume; if ((inputSubVolumeNumber > 0) && (inputSubVolumeNumber <= numberOfVolumesRead)) { mappingVolume = volumeFiles[inputSubVolumeNumber - 1]; } else { throw CommandException("The Sub-Volume Number for the input volume must be between 1 and " + QString::number(numberOfVolumesRead) + "."); } // // Read the palette file // PaletteFile paletteFile; if (inputPaletteFileName.isEmpty() == false) { paletteFile.readFile(inputPaletteFileName); } // // Get the index of the palette // const int paletteIndex = paletteFile.getPaletteIndexFromNameOrNumber(inputPaletteNameOrNumber); // // Map the volume // BrainSet brainSet; BrainModelVolumeToVtkSurfaceMapper mapper(&brainSet, &vtkModelFile, mappingVolume, &paletteFile, paletteIndex); mapper.execute(); // // Write the VTK model file // vtkModelFile.writeFile(outputVtkModelFileName); // // free the volumes in memory // for (int i = 0; i < numberOfVolumesRead; i++) { delete volumeFiles[i]; } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeMapToSurfaceROIFile.h0000664000175000017500000000355011572067322030166 0ustar michaelmichael #ifndef __COMMAND_VOLUME_MAP_TO_SURFACE_ROI_H__ #define __COMMAND_VOLUME_MAP_TO_SURFACE_ROI_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for mapping a volume to a node region of interest file class CommandVolumeMapToSurfaceROIFile : public CommandBase { public: // constructor CommandVolumeMapToSurfaceROIFile(); // destructor ~CommandVolumeMapToSurfaceROIFile(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_MAP_TO_SURFACE_ROI_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeMapToSurfaceROIFile.cxx0000664000175000017500000001340511572067322030541 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurface.h" #include "BrainSet.h" #include "CommandVolumeMapToSurfaceROIFile.h" #include "FileFilters.h" #include "NodeRegionOfInterestFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "TransformationMatrixFile.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeMapToSurfaceROIFile::CommandVolumeMapToSurfaceROIFile() : CommandBase("-volume-map-to-surface-roi-file", "VOLUME MAP TO SURFACE ROI FILE") { } /** * destructor. */ CommandVolumeMapToSurfaceROIFile::~CommandVolumeMapToSurfaceROIFile() { } /** * get the script builder parameters. */ void CommandVolumeMapToSurfaceROIFile::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Input Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Input Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Output Region of Interest File Name", FileFilters::getRegionOfInterestFileFilter()); paramsOut.addVariableListOfParameters("Volume Map Options"); } /** * get full help information. */ QString CommandVolumeMapToSurfaceROIFile::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-surface-offset X Y Z]\n" + indent9 + "\n" + indent9 + "Intersect a volume with a surface and for all nodes that are\n" + indent9 + "within a non-zero voxel, assign the node as selcted in the\n" + indent9 + "region of interest file.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeMapToSurfaceROIFile::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get parameters // const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); const QString inputCoordinateFileName = parameters->getNextParameterAsString("Input Coordinate File Name"); const QString inputTopologyFileName = parameters->getNextParameterAsString("Input Topology File Name"); const QString outputROIFileName = parameters->getNextParameterAsString("Output Node Region of Interest File Name"); // // Get optional parmameters // float surfaceOffset[3] = { 0.0, 0.0, 0.0 }; while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("Volume Map to Surface ROI Parameter"); if (paramName == "-surfaceOffset") { surfaceOffset[0] = parameters->getNextParameterAsFloat("Surface Offset X"); surfaceOffset[1] = parameters->getNextParameterAsFloat("Surface Offset Y"); surfaceOffset[2] = parameters->getNextParameterAsFloat("Surface Offset Z"); } else { throw CommandException("unknown parameter " + paramName); } } // // Create a brain set // BrainSet brainSet(inputTopologyFileName, inputCoordinateFileName, "", true); BrainModelSurface* surface = brainSet.getBrainModelSurface(0); if (surface == NULL) { throw CommandException("unable to find surface."); } const TopologyFile* tf = surface->getTopologyFile(); if (tf == NULL) { throw CommandException("unable to find topology."); } const int numNodes = surface->getNumberOfNodes(); if (numNodes == 0) { throw CommandException("surface contains no nodes."); } // // Read the volume file // VolumeFile volumeFile; volumeFile.readFile(inputVolumeFileName); // // Apply the surface translation // TransformationMatrix matrix; matrix.translate(surfaceOffset); surface->applyTransformationMatrix(matrix); // // Create the region of interest file // NodeRegionOfInterestFile roiFile; roiFile.setNumberOfNodes(numNodes); // // Assign the roi // roiFile.assignSelectedNodesWithVolumeFile(&volumeFile, surface->getCoordinateFile(), surface->getTopologyFile()); // // Write the roi file // roiFile.writeFile(outputROIFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeMapToSurfacePALS.h0000664000175000017500000000345611572067322027501 0ustar michaelmichael #ifndef __COMMAND_VOLUME_MAP_TO_SURFACE_PALS_H__ #define __COMMAND_VOLUME_MAP_TO_SURFACE_PALS_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandVolumeMapToSurfacePALS : public CommandBase { public: // constructor CommandVolumeMapToSurfacePALS(); // destructor ~CommandVolumeMapToSurfacePALS(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_MAP_TO_SURFACE_PALS_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeMapToSurfacePALS.cxx0000664000175000017500000003754311572067322030060 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainModelVolumeToSurfaceMapperAlgorithmParameters.h" #include "BrainModelVolumeToSurfaceMapperPALS.h" #include "BrainSet.h" #include "CommandVolumeMapToSurfacePALS.h" #include "FileFilters.h" #include "MetricFile.h" #include "PaintFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandVolumeMapToSurfacePALS::CommandVolumeMapToSurfacePALS() : CommandBase("-volume-map-to-surface-pals", "VOLUME MAP TO SURFACE PALS ATLAS") { } /** * destructor. */ CommandVolumeMapToSurfacePALS::~CommandVolumeMapToSurfacePALS() { } /** * get the script builder parameters. */ void CommandVolumeMapToSurfacePALS::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { // // Get the names of the supported stereotaxic spaces // std::vector spaceNames; BrainModelVolumeToSurfaceMapperPALS::getSupportedStereotaxicSpaceName(spaceNames); // // Get the names of the mapping algorithms // std::vector algNames; std::vector algValues; BrainModelVolumeToSurfaceMapperAlgorithmParameters::getAlgorithmNamesAndValues( algNames, algValues); QStringList metricPaintFileFilters; metricPaintFileFilters << FileFilters::getMetricFileFilter(); metricPaintFileFilters << FileFilters::getPaintFileFilter(); metricPaintFileFilters << FileFilters::getSurfaceShapeFileFilter(); paramsOut.clear(); paramsOut.addFile("Input Metric File Name", metricPaintFileFilters); paramsOut.addFile("Output Metric File Name", metricPaintFileFilters); paramsOut.addListOfItems("Stereotaxic Space", spaceNames, spaceNames); // yes use names for both paramsOut.addStructure("Structure"); paramsOut.addListOfItems("Algorithm", algNames, algNames); // yes use names for both paramsOut.addFile("Input Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addVariableListOfParameters("Mapping Options"); } /** * get full help information. */ QString CommandVolumeMapToSurfacePALS::getHelpInformation() const { // // Get the names of the supported stereotaxic spaces // std::vector spaceNames; BrainModelVolumeToSurfaceMapperPALS::getSupportedStereotaxicSpaceName(spaceNames); // // Get the names of the mapping algorithms // std::vector algNames; std::vector algValues; BrainModelVolumeToSurfaceMapperAlgorithmParameters::getAlgorithmNamesAndValues( algNames, algValues); QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-metric-afm]\n" + indent9 + "[-metric-mfm]\n" + indent9 + "[-metric-min]\n" + indent9 + "[-metric-max]\n" + indent9 + "[-metric-std-dev]\n" + indent9 + "[-metric-std-error]\n" + indent9 + "[-metric-all-cases]\n" + indent9 + "[-paint-afm]\n" + indent9 + "[-paint-most-common]\n" + indent9 + "[-paint-most-common-no-unknown]\n" + indent9 + "[-paint-all-cases]\n" + indent9 + "[-av average-voxel-neighbor-cube-size (mm)]\n" + indent9 + "[-bf brain-fish-max-distance\n" + indent9 + " brain-fish-splat factor]\n" + indent9 + "[-g gaussian-neighbor-cube-size (mm)\n" + indent9 + " sigma-norm\n" + indent9 + " sigma-tang\n" + indent9 + " norm below cutoff (mm)\n" + indent9 + " norm above cutoff (mm)\n" + indent9 + " tang-cutoff (mm)]\n" + indent9 + "[-mv maximum-voxel-neighbor-cube-size (mm)]\n" + indent9 + "[-sv strongest-voxel-neighbor-cube-size (mm)]\n" + indent9 + "\n" + indent9 + "Map a volume to the PALS atlas surfaces.\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\"algorithm\" is one of:\n"); for (unsigned int i = 0; i < algNames.size(); i++) { helpInfo += (indent9 + " " + algNames[i] + "\n"); } helpInfo += ("" + indent9 + "\n" + indent9 + "METRIC MAPPING OPTIONS\n" + indent9 + " \"-metric-afm\" Map to the average fiducial surface \n" + indent9 + " (Average Fiducial Mapping).\n" + indent9 + " \"-metric-mfm\" Multi-Fiducal-Mapping - Output the \n" + indent9 + " average of mapping to all PALS cases (Multi-Fiducial-\n" + indent9 + " Mapping)\n" + indent9 + " \"-metric-min\" Output the minimum of mapping to all\n" + indent9 + " PALS cases.\n" + indent9 + " \"-metric-max\" Output the maximum of mapping to all\n" + indent9 + " PALS cases.\n" + indent9 + " \"-metric-std-dev\" Output the sample standard deviation\n" + indent9 + " of mapping to all PALS cases.\n" + indent9 + " \"-metric-std-error\" Output the standard error of \n" + indent9 + " mapping to all PALS cases.\n" + indent9 + " \"-metric-all-cases\" Output the mapping to each of the\n" + indent9 + " PALS cases.\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "PAINT MAPPING OPTIONS\n" + indent9 + " \"-paint-afm\" Map to the average fiducial surface \n" + indent9 + " (Average Fiducial Mapping).\n" + indent9 + " \"-paint-most-common\" Output the most common paint\n" + indent9 + " of mapping to all PALS cases. \n" + indent9 + " \"-paint-most-common-no-unknown\" Output the most common\n" + indent9 + " paint of mapping to all PALS cases but exclude the \n" + indent9 + " unidentified nodes.\n" + indent9 + " \"-paint-all-cases\" Output the mapping to all PALS \n" + indent9 + " cases.\n" + indent9 + "\n" + indent9 + "Stereotaxic Spaces Supported \n"); for (unsigned int i = 0; i < spaceNames.size(); i++) { helpInfo += (indent9 + " " + spaceNames[i] + "\n"); } helpInfo += ("" + indent9 + "\n" + indent9 + "\"structure\" is one of:\n" + indent9 + " LEFT\n" + indent9 + " RIGHT\n" + indent9 + "\n" + indent9 + "If the input metric or paint file name is not an empty string\n" + indent9 + " (\"\"), the newly create metric or paint columns will be \n" + indent9 + "appended to the file and then written with the output file \n" + indent9 + "name.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeMapToSurfacePALS::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputDataFileName = parameters->getNextParameterAsString("Input Metric/Paint File Name"); const QString outputDataFileName = parameters->getNextParameterAsString("Output Metric/Paint File Name"); const QString stereotaxicSpaceName = parameters->getNextParameterAsString("Stereotaxic Space Name").toUpper(); const QString structureName = parameters->getNextParameterAsString("Structure Name").toUpper(); const QString algorithmName = parameters->getNextParameterAsString("Algorithm Name").toUpper(); const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); BrainModelVolumeToSurfaceMapperAlgorithmParameters mappingParameters; while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("Map To PALS Parameter"); if (paramName == "-metric-afm") { mappingParameters.setPalsMetricAverageFiducialMappingEnabled(true); } else if (paramName == "-metric-mfm") { mappingParameters.setPalsMetricMultiFiducialMappingEnabled(true); } else if (paramName == "-metric-min") { mappingParameters.setPalsMetricMinimumEnabled(true); } else if (paramName == "-metric-max") { mappingParameters.setPalsMetricMaximumEnabled(true); } else if (paramName == "-metric-std-dev") { mappingParameters.setPalsMetricStandardDeviationEnabled(true); } else if (paramName == "-metric-std-error") { mappingParameters.setPalsMetricStandardErrorEnabled(true); } else if (paramName == "-metric-all-cases") { mappingParameters.setPalsMetricAllCasesEnabled(true); } else if (paramName == "-paint-afm") { mappingParameters.setPalsPaintAverageFiducialMappingEnabled(true); } else if (paramName == "-paint-most-common") { mappingParameters.setPalsPaintMostCommonEnabled(true); } else if (paramName == "-paint-most-common-no-unknown") { mappingParameters.setPalsPaintMostCommonExcludeUnidentifiedEnabled(true); } else if (paramName == "-paint-all-cases") { mappingParameters.setPalsPaintAllCasesEnabled(true); } else if (paramName == "-av") { mappingParameters.setAlgorithmMetricAverageVoxelParameters( parameters->getNextParameterAsFloat("Average Voxel Neighbors (mm)")); } else if (paramName == "-bf") { mappingParameters.setAlgorithmMetricMcwBrainFishParameters( parameters->getNextParameterAsFloat("Brain Fish Max Distance"), parameters->getNextParameterAsInt("Brain Fish Splat Factor")); } else if (paramName == "-g") { mappingParameters.setAlgorithmMetricGaussianParameters( parameters->getNextParameterAsFloat("Guassian Neighbor Cube Size (mm)"), parameters->getNextParameterAsFloat("Gaussian Sigma Norm"), parameters->getNextParameterAsFloat("Gaussian Sigma Tangent"), parameters->getNextParameterAsFloat("Gaussina Norm Below Cutoff"), parameters->getNextParameterAsFloat("Gaussian Norm Above Cutoff"), parameters->getNextParameterAsFloat("Gaussian Tangent Cutoff")); } else if (paramName == "-mv") { mappingParameters.setAlgorithmMetricMaximumVoxelParameters( parameters->getNextParameterAsFloat("Maximum Voxel Neighbors (mm)")); } else if (paramName == "-sv") { mappingParameters.setAlgorithmMetricStrongestVoxelParameters( parameters->getNextParameterAsFloat("Strongest Voxel Neighbors (mm)")); } else { throw CommandException("Unrecognized Parameter: " + paramName); } } // // Set the algorithm // std::vector algNames; std::vector algValues; BrainModelVolumeToSurfaceMapperAlgorithmParameters::getAlgorithmNamesAndValues( algNames, algValues); bool algNameValid = false; BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM algorithm; for (unsigned int i = 0; i < algNames.size(); i++) { if (algorithmName == algNames[i]) { algorithm = algValues[i]; algNameValid = true; break; } } if (algNameValid == false) { throw CommandException("Invalid algorithm name \"" + algorithmName + "\"."); } mappingParameters.setAlgorithm(algorithm); // // Get the structure // Structure::STRUCTURE_TYPE structure; if (structureName == "RIGHT") { structure = Structure::STRUCTURE_TYPE_CORTEX_RIGHT; } else if (structureName == "LEFT") { structure = Structure::STRUCTURE_TYPE_CORTEX_LEFT; } else { throw CommandException("Structure must be either RIGHT or LEFT.\n" " Value entered \"" + structureName + "\""); } // // Check Stereotaxic Space // bool spaceNameFound = false; std::vector spaceNames; BrainModelVolumeToSurfaceMapperPALS::getSupportedStereotaxicSpaceName(spaceNames); for (unsigned int i = 0; i < spaceNames.size(); i++) { if (stereotaxicSpaceName == spaceNames[i]) { spaceNameFound = true; break; } } if (spaceNameFound == false) { throw CommandException("Invalid stereotaxic space \"" + stereotaxicSpaceName + "\""); } // // Read the volume file // VolumeFile volumeFile; volumeFile.readFile(inputVolumeFileName); // // Files that will get created // MetricFile mappingMetricFile, outputMetricFile; PaintFile mappingPaintFile, outputPaintFile; GiftiNodeDataFile* mappingDataFile = NULL; GiftiNodeDataFile* outputDataFile = NULL; if (outputDataFileName.endsWith(SpecFile::getMetricFileExtension()) || outputDataFileName.endsWith(SpecFile::getSurfaceShapeFileExtension())) { mappingDataFile = &mappingMetricFile; outputDataFile = &outputMetricFile; } else if (outputDataFileName.endsWith(SpecFile::getPaintFileExtension())) { mappingDataFile = &mappingPaintFile; outputDataFile = &outputPaintFile; } else { throw CommandException("Unable to determine type of output file which " "must end with \"" + SpecFile::getMetricFileExtension() + "\" or \"" + SpecFile::getPaintFileExtension() + "."); } // // Run the mapper // BrainSet bs; BrainModelVolumeToSurfaceMapperPALS palsMapper(&bs, &volumeFile, stereotaxicSpaceName, structure, mappingParameters, mappingDataFile); palsMapper.execute(); // // If input file present, read it // if (inputDataFileName.isEmpty() == false) { if (QFile::exists(inputDataFileName)) { outputDataFile->readFile(inputDataFileName); } } // // Add new data to output file // outputDataFile->append(*mappingDataFile); // // Write the output data file // outputDataFile->writeFile(outputDataFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeMapToSurface.h0000664000175000017500000000357111572067322027017 0ustar michaelmichael #ifndef __COMMAND_VOLUME_MAP_TO_SURFACE_H__ #define __COMMAND_VOLUME_MAP_TO_SURFACE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" class GiftiNodeDataFile; /// class for class CommandVolumeMapToSurface : public CommandBase { public: // constructor CommandVolumeMapToSurface(); // destructor ~CommandVolumeMapToSurface(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); /// datat file for mapping GiftiNodeDataFile* mappingDataFile; }; #endif // __COMMAND_VOLUME_MAP_TO_SURFACE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeMapToSurface.cxx0000664000175000017500000003277611572067322027403 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainSet.h" #include "BrainModelVolumeToSurfaceMapperAlgorithmParameters.h" #include "BrainModelVolumeToSurfaceMapper.h" #include "CommandVolumeMapToSurface.h" #include "FileFilters.h" #include "FileUtilities.h" #include "MetricFile.h" #include "PaintFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SpecFile.h" /** * constructor. */ CommandVolumeMapToSurface::CommandVolumeMapToSurface() : CommandBase("-volume-map-to-surface", "VOLUME MAP TO SURFACE") { mappingDataFile = NULL; } /** * destructor. */ CommandVolumeMapToSurface::~CommandVolumeMapToSurface() { if (mappingDataFile != NULL) { delete mappingDataFile; mappingDataFile = NULL; } } /** * get the script builder parameters. */ void CommandVolumeMapToSurface::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { std::vector algNames; std::vector algValues; BrainModelVolumeToSurfaceMapperAlgorithmParameters::getAlgorithmNamesAndValues( algNames, algValues); QStringList metricPaintFileFilters; metricPaintFileFilters << FileFilters::getMetricFileFilter(); metricPaintFileFilters << FileFilters::getPaintFileFilter(); metricPaintFileFilters << FileFilters::getSurfaceShapeFileFilter(); paramsOut.clear(); paramsOut.addFile("Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Input Metric File Name", metricPaintFileFilters); paramsOut.addFile("Output Metric File Name", metricPaintFileFilters); paramsOut.addFile("Output Spec File Name", FileFilters::getSpecFileFilter()); paramsOut.addListOfItems("Algorithm", algNames, algNames); // yes use names for both paramsOut.addMultipleFiles("Input Volume File Names", FileFilters::getVolumeGenericFileFilter()); paramsOut.addVariableListOfParameters("Mapping Options"); } /** * get full help information. */ QString CommandVolumeMapToSurface::getHelpInformation() const { std::vector algNames; std::vector algValues; BrainModelVolumeToSurfaceMapperAlgorithmParameters::getAlgorithmNamesAndValues( algNames, algValues); QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-av average-voxel-neighbor-cube-size (mm)]\n" + indent9 + "[-bf brain-fish-max-distance\n" + indent9 + " brain-fish-splat factor]\n" + indent9 + "[-g gaussian-neighbor-cube-size (mm)\n" + indent9 + " sigma-norm\n" + indent9 + " sigma-tang\n" + indent9 + " norm below cutoff (mm)\n" + indent9 + " norm above cutoff (mm)\n" + indent9 + " tang-cutoff (mm)]\n" + indent9 + "[-mv maximum-voxel-neighbor-cube-size (mm)]\n" + indent9 + "[-sv strongest-voxel-neighbor-cube-size (mm)]\n" + indent9 + "\n" + indent9 + "Map volume(s) to a surface metric or paint file.\n" + indent9 + "\n" + indent9 + "For successful mapping, both the surface and the volume\n" + indent9 + "must be in the same stereotaxic space.\n" + indent9 + "\n" + indent9 + "\"algorithm\" is one of:\n"); for (unsigned int i = 0; i < algNames.size(); i++) { helpInfo += (indent9 + " " + algNames[i] + "\n"); } helpInfo += ("" + indent9 + "\n" + indent9 + "If the input metric or paint file name is not an empty string\n" + indent9 + " (\"\"), the newly create metric or paint columns will be \n" + indent9 + "appended to the file and then written with the output file \n" + indent9 + "name.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeMapToSurface::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { std::vector algNames; std::vector algValues; BrainModelVolumeToSurfaceMapperAlgorithmParameters::getAlgorithmNamesAndValues( algNames, algValues); BrainModelVolumeToSurfaceMapperAlgorithmParameters mappingParameters; const QString coordinateFileName = parameters->getNextParameterAsString("Coordinate File Name"); const QString topologyFileName = parameters->getNextParameterAsString("Topology File Name"); const QString inputDataFileName = parameters->getNextParameterAsString("Input Metric or Paint File Name"); const QString outputDataFileName = parameters->getNextParameterAsString("Output Metric or PaintFile Name"); const QString algorithmName = parameters->getNextParameterAsString("Algorithm Name"); // // Verify algorithm name // bool algNameValid = false; for (unsigned int i = 0; i < algNames.size(); i++) { if (algorithmName == algNames[i]) { mappingParameters.setAlgorithm(algValues[i]); algNameValid = true; break; } } if (algNameValid == false) { throw CommandException("Invalid algorithm name \"" + algorithmName + "\"."); } std::vector inputVolumeFileNames; bool readingVolumeFileNamesFlag = true; while (parameters->getParametersAvailable()) { const QString paramValue = parameters->getNextParameterAsString("Map Volume Parameter"); if (paramValue.isEmpty() == false) { if (paramValue[0] == '-') { readingVolumeFileNamesFlag = false; if (paramValue == "-av") { mappingParameters.setAlgorithmMetricAverageVoxelParameters( parameters->getNextParameterAsFloat("Average Voxel Neighbors (mm)")); } else if (paramValue == "-bf") { const float md = parameters->getNextParameterAsFloat("Brain Fish Max Distance"); const int sf = parameters->getNextParameterAsInt("Brain Fish Splat Factor"); mappingParameters.setAlgorithmMetricMcwBrainFishParameters(md, sf); } else if (paramValue == "-g") { const float gn = parameters->getNextParameterAsFloat("Gaussian Neighbor Cube Size (mm)"); const float sn = parameters->getNextParameterAsFloat("Gaussian Sigma Norm"); const float st = parameters->getNextParameterAsFloat("Gaussian Sigma Tangent"); const float nb = parameters->getNextParameterAsFloat("Gaussina Norm Below Cutoff"); const float na = parameters->getNextParameterAsFloat("Gaussian Norm Above Cutoff"); const float tc = parameters->getNextParameterAsFloat("Gaussian Tangent Cutoff"); mappingParameters.setAlgorithmMetricGaussianParameters(gn, sn, st, nb, na, tc); } else if (paramValue == "-mv") { mappingParameters.setAlgorithmMetricMaximumVoxelParameters( parameters->getNextParameterAsFloat("Maximum Voxel Neighbors (mm)")); } else if (paramValue == "-sv") { mappingParameters.setAlgorithmMetricStrongestVoxelParameters( parameters->getNextParameterAsFloat("Strongest Voxel Neighbors (mm)")); } else { throw CommandException("Unrecognized option: " + paramValue); } } else if (readingVolumeFileNamesFlag) { inputVolumeFileNames.push_back(paramValue); } else { throw CommandException("Unrecognized parameter: " + paramValue); } } } const int numberOfVolumeFiles = static_cast(inputVolumeFileNames.size()); if (numberOfVolumeFiles <= 0) { throw CommandException("No volume file names were provided for mapping."); } enum MODE { MODE_NONE, MODE_METRIC, MODE_PAINT, }; MODE mode = MODE_NONE; switch (mappingParameters.getAlgorithm()) { case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_METRIC_AVERAGE_NODES: case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_METRIC_AVERAGE_VOXEL: case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_METRIC_ENCLOSING_VOXEL: case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_METRIC_GAUSSIAN: case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_METRIC_INTERPOLATED_VOXEL: case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_METRIC_MAXIMUM_VOXEL: case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_METRIC_MCW_BRAINFISH: case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_METRIC_STRONGEST_VOXEL: mode = MODE_METRIC; break; case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_PAINT_ENCLOSING_VOXEL: mode = MODE_PAINT; break; } if (mode == MODE_NONE) { throw CommandException("Unable determine type of output file from algorithm name."); } // // Create a brain set // BrainSet brainSet(topologyFileName, coordinateFileName, "", true); BrainModelSurface* surface = brainSet.getBrainModelSurface(0); if (surface == NULL) { throw CommandException("unable to find surface."); } const TopologyFile* tf = surface->getTopologyFile(); if (tf == NULL) { throw CommandException("unable to find topology."); } const int numNodes = surface->getNumberOfNodes(); if (numNodes == 0) { throw CommandException("surface contains no nodes."); } // // Metric file for mapping // switch (mode) { case MODE_NONE: break; case MODE_METRIC: mappingDataFile = new MetricFile; break; case MODE_PAINT: mappingDataFile = new PaintFile; break; } // // Read input metric file if it exists // if (inputDataFileName.isEmpty() == false) { if (QFile::exists(inputDataFileName)) { mappingDataFile->readFile(inputDataFileName); } } // // Map all of the volume files // for (int j = 0; j < numberOfVolumeFiles; j++) { // // Read the volume file - all of its subvolumes // std::vector volumes; VolumeFile::readFile(inputVolumeFileNames[j], VolumeFile::VOLUME_READ_SELECTION_ALL, volumes, false); for (unsigned int i = 0; i < volumes.size(); i++) { VolumeFile* vf = volumes[i]; // // Name for output column // QString columnName(FileUtilities::basename(inputVolumeFileNames[j])); if (volumes.size() > 0) { columnName += ("[" + QString::number(i + 1) + "]"); } // // Create the mapper // BrainModelVolumeToSurfaceMapper mapper(&brainSet, surface, vf, mappingDataFile, mappingParameters, -1, columnName); // // Run the mapper // mapper.execute(); // // Delete the volume // delete vf; } } // // Save the metric file // mappingDataFile->writeFile(outputDataFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeMakeSphere.h0000664000175000017500000000340511572067322026506 0ustar michaelmichael #ifndef __COMMAND_VOLUME_MAKE_SPHERE_H__ #define __COMMAND_VOLUME_MAKE_SPHERE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandVolumeMakeSphere : public CommandBase { public: // constructor CommandVolumeMakeSphere(); // destructor ~CommandVolumeMakeSphere(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_MAKE_SPHERE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeMakeSphere.cxx0000664000175000017500000000725411572067322027067 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeMakeSphere.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeMakeSphere::CommandVolumeMakeSphere() : CommandBase("-volume-make-sphere", "VOLUME MAKE SPHERE") { } /** * destructor. */ CommandVolumeMakeSphere::~CommandVolumeMakeSphere() { } /** * get the script builder parameters. */ void CommandVolumeMakeSphere::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Output Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addInt("center-i"); paramsOut.addInt("center-j"); paramsOut.addInt("center-k"); paramsOut.addFloat("Radius"); } /** * get full help information. */ QString CommandVolumeMakeSphere::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Make a sphere within the volume.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeMakeSphere::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); QString outputVolumeFileName, outputVolumeFileLabel; parameters->getNextParameterAsVolumeFileNameAndLabel("Output Volume File Name/Label", outputVolumeFileName, outputVolumeFileLabel); const int center[3] = { parameters->getNextParameterAsInt("center-i"), parameters->getNextParameterAsInt("center-j"), parameters->getNextParameterAsInt("center-k") }; const float radius = parameters->getNextParameterAsInt("Radius"); checkForExcessiveParameters(); // // Read the input file // VolumeFile volume; volume.readFile(inputVolumeFileName); // // make plane // volume.makeSphere(center, radius); // // Write the volume // writeVolumeFile(volume, outputVolumeFileName, outputVolumeFileLabel); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeMakeShell.h0000664000175000017500000000342511572067322026331 0ustar michaelmichael #ifndef __COMMAND_VOLUME_MAKE_SHELL_H__ #define __COMMAND_VOLUME_MAKE_SHELL_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for making a shell volume class CommandVolumeMakeShell : public CommandBase { public: // constructor CommandVolumeMakeShell(); // destructor ~CommandVolumeMakeShell(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_MAKE_SHELL_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeMakeShell.cxx0000664000175000017500000000702711572067322026706 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeMakeShell.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeMakeShell::CommandVolumeMakeShell() : CommandBase("-volume-make-shell", "VOLUME MAKE SHELL") { } /** * destructor. */ CommandVolumeMakeShell::~CommandVolumeMakeShell() { } /** * get the script builder parameters. */ void CommandVolumeMakeShell::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Output Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addInt("Dilation Iterations"); paramsOut.addInt("Erosion Iterations"); } /** * get full help information. */ QString CommandVolumeMakeShell::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Make a shell volume.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeMakeShell::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); QString outputVolumeFileName, outputVolumeFileLabel; parameters->getNextParameterAsVolumeFileNameAndLabel("Output Volume File Name/Label", outputVolumeFileName, outputVolumeFileLabel); const int dilationIterations = parameters->getNextParameterAsInt("Dilation Iterations"); const int erosionIterations = parameters->getNextParameterAsInt("Erosion Iterations"); checkForExcessiveParameters(); // // Read the input file // VolumeFile volume; volume.readFile(inputVolumeFileName); // // make shell volume // volume.makeShellVolume(dilationIterations, erosionIterations); // // Write the volume // writeVolumeFile(volume, outputVolumeFileName, outputVolumeFileLabel); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeMakeRectangle.h0000664000175000017500000000346111572067322027166 0ustar michaelmichael #ifndef __COMMAND_VOLUME_MAKE_RECTANGLE_H__ #define __COMMAND_VOLUME_MAKE_RECTANGLE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for making a volume rectangle class CommandVolumeMakeRectangle : public CommandBase { public: // constructor CommandVolumeMakeRectangle(); // destructor ~CommandVolumeMakeRectangle(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_MAKE_RECTANGLE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeMakeRectangle.cxx0000664000175000017500000001031411572067322027534 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeMakeRectangle.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeMakeRectangle::CommandVolumeMakeRectangle() : CommandBase("-volume-make-rectangle", "VOLUME MAKE RECTANGLE") { } /** * destructor. */ CommandVolumeMakeRectangle::~CommandVolumeMakeRectangle() { } /** * get the script builder parameters. */ void CommandVolumeMakeRectangle::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Output Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addInt("i-minimum"); paramsOut.addInt("i-maximum"); paramsOut.addInt("j-minimum"); paramsOut.addInt("j-maximum"); paramsOut.addInt("k-minimum"); paramsOut.addInt("k-maximum"); paramsOut.addFloat("Voxel Value"); } /** * get full help information. */ QString CommandVolumeMakeRectangle::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Set the voxels within the range [i-min, i-max),\n" + indent9 + "[j-min, j-max), [k-min, k-max) to the specified value.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeMakeRectangle::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); QString outputVolumeFileName, outputVolumeFileLabel; parameters->getNextParameterAsVolumeFileNameAndLabel("Output Volume File Name/Label", outputVolumeFileName, outputVolumeFileLabel); const int extent[6] = { parameters->getNextParameterAsInt("i-minimum"), parameters->getNextParameterAsInt("i-maximum"), parameters->getNextParameterAsInt("j-minimum"), parameters->getNextParameterAsInt("j-maximum"), parameters->getNextParameterAsInt("k-minimum"), parameters->getNextParameterAsInt("k-maximum") }; const float voxelValue = parameters->getNextParameterAsFloat("Voxel Value"), checkForExcessiveParameters(); // // Read the input file // VolumeFile volume; volume.readFile(inputVolumeFileName); // // make rectangle // volume.setAllVoxelsInRectangle(extent, voxelValue); // // Write the volume // writeVolumeFile(volume, outputVolumeFileName, outputVolumeFileLabel); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeMakePlane.h0000664000175000017500000000337711572067322026327 0ustar michaelmichael #ifndef __COMMAND_VOLUME_MAKE_PLANE_H__ #define __COMMAND_VOLUME_MAKE_PLANE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandVolumeMakePlane : public CommandBase { public: // constructor CommandVolumeMakePlane(); // destructor ~CommandVolumeMakePlane(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_MAKE_PLANE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeMakePlane.cxx0000664000175000017500000001043211572067322026670 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeMakePlane.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeMakePlane::CommandVolumeMakePlane() : CommandBase("-volume-make-plane", "VOLUME MAKE PLANE") { } /** * destructor. */ CommandVolumeMakePlane::~CommandVolumeMakePlane() { } /** * get the script builder parameters. */ void CommandVolumeMakePlane::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Output Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addInt("X-slope"); paramsOut.addInt("X-offset"); paramsOut.addInt("Y-slope"); paramsOut.addInt("Y-offset"); paramsOut.addInt("Z-slope"); paramsOut.addInt("Z-offset"); paramsOut.addInt("Offset"); paramsOut.addInt("Thickness"); } /** * get full help information. */ QString CommandVolumeMakePlane::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Make a plane.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeMakePlane::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); QString outputVolumeFileName, outputVolumeFileLabel; parameters->getNextParameterAsVolumeFileNameAndLabel("Output Volume File Name/Label", outputVolumeFileName, outputVolumeFileLabel); const int xSlope = parameters->getNextParameterAsInt("X-Slope"); const int xOffset = parameters->getNextParameterAsInt("X-Offset"); const int ySlope = parameters->getNextParameterAsInt("Y-Slope"); const int yOffset = parameters->getNextParameterAsInt("Y-Offset"); const int zSlope = parameters->getNextParameterAsInt("Z-Slope"); const int zOffset = parameters->getNextParameterAsInt("Z-Offset"); const int offset = parameters->getNextParameterAsInt("Offset"); const int thickness = parameters->getNextParameterAsInt("Thickness"); checkForExcessiveParameters(); // // Read the input file // VolumeFile volume; volume.readFile(inputVolumeFileName); // // make plane // volume.makePlane(xSlope, xOffset, ySlope, yOffset, zSlope, zOffset, offset, thickness); // // Write the volume // writeVolumeFile(volume, outputVolumeFileName, outputVolumeFileLabel); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeInformationNifti.h0000664000175000017500000000354011572067322027741 0ustar michaelmichael #ifndef __COMMAND_VOLUME_INFORMATION_NIFTI_H__ #define __COMMAND_VOLUME_INFORMATION_NIFTI_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for command that gets information from a NIFTI volume file class CommandVolumeInformationNifti : public CommandBase { public: // constructor CommandVolumeInformationNifti(); // destructor ~CommandVolumeInformationNifti(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_INFORMATION_NIFTI_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeInformationNifti.cxx0000664000175000017500000001076611572067322030324 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "CommandVolumeInformationNifti.h" #include "FileFilters.h" #include "FileUtilities.h" #include "NiftiFileHeader.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeInformationNifti::CommandVolumeInformationNifti() : CommandBase("-volume-information-nifti", "VOLUME INFORMATION NIFTI") { } /** * destructor. */ CommandVolumeInformationNifti::~CommandVolumeInformationNifti() { } /** * get the script builder parameters. */ void CommandVolumeInformationNifti::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Volume File Name", FileFilters::getVolumeGenericFileFilter()); } /** * get full help information. */ QString CommandVolumeInformationNifti::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Print information containing the contents of the NIFTI \n" + indent9 + "volume file header.\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeInformationNifti::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); NiftiFileHeader niftiHeader; niftiHeader.setReadExtensionFlag(true); niftiHeader.readHeader(inputVolumeFileName); std::cout << niftiHeader.getDescriptionOfHeader().toAscii().constData() << std::endl; /* * VolumeFile volume; volume.setVolumeSpace(VolumeFile::VOLUME_SPACE_COORD_LPI); volume.readFile(inputVolumeFileName); std::cout << "Volume File: " << FileUtilities::basename(inputVolumeFileName).toAscii().constData() << std::endl; int dim[3]; volume.getDimensions(dim); std::cout << " dimensions: " << dim[0] << ", " << dim[1] << ", " << dim[2] << ", " << volume.getNumberOfComponentsPerVoxel() << std::endl; float space[3]; volume.getSpacing(space); std::cout << " spacing: " << space[0] << ", " << space[1] << ", " << space[2] << std::endl; float org[3]; volume.getOrigin(org); std::cout << " origin (center of first voxel): " << org[0] << ", " << org[1] << ", " << org[2] << std::endl; VolumeFile::ORIENTATION orient[3]; volume.getOrientation(orient); std::cout << " orientation: " << VolumeFile::getOrientationLabel(orient[0]).toAscii().constData() << ", " << VolumeFile::getOrientationLabel(orient[1]).toAscii().constData() << ", " << VolumeFile::getOrientationLabel(orient[2]).toAscii().constData() << std::endl; std::cout << " label: " << volume.getDescriptiveLabel().toAscii().constData() << std::endl; float minValue, maxValue; volume.getMinMaxVoxelValues(minValue, maxValue); std::cout << " voxel range: " << minValue << ", " << maxValue << std::endl; const int numRegionNames = volume.getNumberOfRegionNames(); if (numRegionNames > 0) { std::cout << " Region Names: " << std::endl; for (int i = 0; i < numRegionNames; i++) { std::cout << " " << i << " " << volume.getRegionNameFromIndex(i).toAscii().constData() << std::endl; } } */ } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeInformation.h0000664000175000017500000000341011572067322026743 0ustar michaelmichael #ifndef __COMMAND_VOLUME_INFORMATION_H__ #define __COMMAND_VOLUME_INFORMATION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandVolumeInformation : public CommandBase { public: // constructor CommandVolumeInformation(); // destructor ~CommandVolumeInformation(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_INFORMATION_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeInformation.cxx0000664000175000017500000001171211572067322027322 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "CommandVolumeInformation.h" #include "FileFilters.h" #include "FileUtilities.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" #include /** * constructor. */ CommandVolumeInformation::CommandVolumeInformation() : CommandBase("-volume-information", "VOLUME INFORMATION") { } /** * destructor. */ CommandVolumeInformation::~CommandVolumeInformation() { } /** * get the script builder parameters. */ void CommandVolumeInformation::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Volume File Name", FileFilters::getVolumeGenericFileFilter()); } /** * get full help information. */ QString CommandVolumeInformation::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Print information about the volume. If possible, the\n" + indent9 + "volume data is transformated into LPI (neurological)" + indent9 + "orientation." + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeInformation::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); VolumeFile volume; volume.setVolumeSpace(VolumeFile::VOLUME_SPACE_COORD_LPI); volume.readFile(inputVolumeFileName); std::cout << "Volume File: " << FileUtilities::basename(inputVolumeFileName).toAscii().constData() << std::endl; int dim[3]; volume.getDimensions(dim); std::cout << " dimensions: " << std::endl; std::cout << indent9.toAscii().data() << "X: " << dim[0] << std::endl; std::cout << indent9.toAscii().data() << "Y: " << dim[1] << std::endl; std::cout << indent9.toAscii().data() << "Z: " << dim[2] << std::endl; if(volume.getNumberOfSubVolumes() > 1) std::cout << indent9.toAscii().data() << "Time: " << volume.getNumberOfSubVolumes() << std::endl; if(volume.getNumberOfComponentsPerVoxel() > 1) std::cout << indent9.toAscii().data() << "Components Per Voxel: " << volume.getNumberOfComponentsPerVoxel() << std::endl; float space[3]; volume.getSpacing(space); std::ios_base::fmtflags flags = std::cout.flags( ); std::cout << " spacing: " << std::setprecision(std::numeric_limits::digits10) << std::scientific <::digits10) << std::scientific< 0) { std::cout << " Region Names: " << std::endl; for (int i = 0; i < numRegionNames; i++) { std::cout << " " << i << " " << volume.getRegionNameFromIndex(i).toAscii().constData() << std::endl; } } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeImportRawFile.h0000664000175000017500000000343211572067322027206 0ustar michaelmichael #ifndef __COMMAND_VOLUME_IMPORT_RAW_FILE_H__ #define __COMMAND_VOLUME_IMPORT_RAW_FILE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandVolumeImportRawFile : public CommandBase { public: // constructor CommandVolumeImportRawFile(); // destructor ~CommandVolumeImportRawFile(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_IMPORT_RAW_FILE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeImportRawFile.cxx0000664000175000017500000001576111572067322027571 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeImportRawFile.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeImportRawFile::CommandVolumeImportRawFile() : CommandBase("-volume-raw-import-file", "VOLUME IMPORT RAW FILE") { } /** * destructor. */ CommandVolumeImportRawFile::~CommandVolumeImportRawFile() { } /** * get the script builder parameters. */ void CommandVolumeImportRawFile::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { std::vector values, descriptions; values.push_back("INT8"); descriptions.push_back("8-bit integer"); values.push_back("UINT8"); descriptions.push_back("8-bit unsigned integer"); values.push_back("INT16"); descriptions.push_back("16-bit signed integer"); values.push_back("UINT16"); descriptions.push_back("16-bit unsigned integer"); values.push_back("INT32"); descriptions.push_back("32-bit signed integer"); values.push_back("UINT32"); descriptions.push_back("32-bit unsigned integer"); values.push_back("FLOAT"); descriptions.push_back("Single Precision Floating Point"); values.push_back("DOUBLE"); descriptions.push_back("Double Precision Floating Point"); values.push_back("VIRGB"); descriptions.push_back("Voxel-Interleaved RGB (red-green-blue)"); values.push_back("SIRBB"); descriptions.push_back("Slice-Interleaved RGB (red-green-blue)"); paramsOut.clear(); paramsOut.addFile("Raw Data Volume File Name", FileFilters::getAnyFileFilter()); paramsOut.addFile("Output Volume File Name", FileFilters::getAnyFileFilter()); paramsOut.addInt("X-Dimension", 0, 0, 100000); paramsOut.addInt("Y-Dimension", 0, 0, 100000); paramsOut.addInt("Z-Dimension", 0, 0, 100000); paramsOut.addListOfItems("Data Type", values, descriptions); paramsOut.addBoolean("Byte Swap", false); } /** * get full help information. */ QString CommandVolumeImportRawFile::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Import a raw data file into a volume file.\n" + indent9 + "\n" + indent9 + "\"data-type\" is one of:\n" + indent9 + " INT8 8-bit integer\n" + indent9 + " UINT8 8-bit unsigned integer\n" + indent9 + " INT16 16-bit signed integer\n" + indent9 + " UINT16 16-bit unsigned integer\n" + indent9 + " INT32 32-bit signed integer\n" + indent9 + " UINT32 32-bit unsigned integer\n" + indent9 + " FLOAT Single Precision Floating Point\n" + indent9 + " DOUBLE Double Precision Floating Point\n" + indent9 + " VIRGB Voxel-Interleaved RGB (red-green-blue)\n" + indent9 + " SIRBB Slice-Interleaved RGB (red-green-blue)\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeImportRawFile::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputDataFileName = parameters->getNextParameterAsString("Input Raw Volume File Name"); const QString outputVolumeFileName = parameters->getNextParameterAsString("Output Volume File Name"); const int dimensions[3] = { parameters->getNextParameterAsInt("X-Dimension"), parameters->getNextParameterAsInt("Y-Dimension"), parameters->getNextParameterAsInt("Z-Dimension") }; const QString dataTypeName = parameters->getNextParameterAsString("Data Type Name"); const bool byteSwapFlag = parameters->getNextParameterAsBoolean("Byte Swap"); checkForExcessiveParameters(); VolumeFile::VOXEL_DATA_TYPE dataType = VolumeFile::VOXEL_DATA_TYPE_UNKNOWN; if (dataTypeName == "INT8") { dataType = VolumeFile::VOXEL_DATA_TYPE_CHAR; } else if (dataTypeName == "UINT8") { dataType = VolumeFile::VOXEL_DATA_TYPE_CHAR_UNSIGNED; } else if (dataTypeName == "INT16") { dataType = VolumeFile::VOXEL_DATA_TYPE_SHORT; } else if (dataTypeName == "UINT16") { dataType = VolumeFile::VOXEL_DATA_TYPE_SHORT_UNSIGNED; } else if (dataTypeName == "INT32") { dataType = VolumeFile::VOXEL_DATA_TYPE_INT; } else if (dataTypeName == "UINT32") { dataType = VolumeFile::VOXEL_DATA_TYPE_INT_UNSIGNED; } else if (dataTypeName == "FLOAT") { dataType = VolumeFile::VOXEL_DATA_TYPE_FLOAT; } else if (dataTypeName == "DOUBLE") { dataType = VolumeFile::VOXEL_DATA_TYPE_DOUBLE; } else if (dataTypeName == "VIRGB") { dataType = VolumeFile::VOXEL_DATA_TYPE_RGB_VOXEL_INTERLEAVED; } else if (dataTypeName == "SIRBB") { dataType = VolumeFile::VOXEL_DATA_TYPE_RGB_SLICE_INTERLEAVED; } else { throw CommandException("Invalid data type \"" + dataTypeName + "\""); } VolumeFile volume; const VolumeFile::ORIENTATION orient[3] = { VolumeFile::ORIENTATION_UNKNOWN, VolumeFile::ORIENTATION_UNKNOWN, VolumeFile::ORIENTATION_UNKNOWN }; const float org[3] = { 0.0, 0.0, 0.0 }; const float space[3] = { 1.0, 1.0, 1.0 }; volume.readFileVolumeRaw(inputDataFileName, 0, dataType, dimensions, orient, org, space, byteSwapFlag); volume.writeFile(outputVolumeFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeHistogram.h0000664000175000017500000000354411572067322026423 0ustar michaelmichael #ifndef __COMMAND_VOLUME_HISTOGRAM_H__ #define __COMMAND_VOLUME_HISTOGRAM_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandVolumeHistogram : public CommandBase { public: // constructor CommandVolumeHistogram(); // destructor ~CommandVolumeHistogram(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); /// number of buckets int numberOfBuckets; /// y-maximum float yMaximum; }; #endif // __COMMAND_VOLUME_HISTOGRAM_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeHistogram.cxx0000664000175000017500000001761011572067322026775 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "CommandVolumeHistogram.h" #include "DebugControl.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "StatisticHistogram.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeHistogram::CommandVolumeHistogram() : CommandBase("-volume-histogram", "VOLUME HISTOGRAM") { numberOfBuckets = 64; yMaximum = 500000.0; } /** * destructor. */ CommandVolumeHistogram::~CommandVolumeHistogram() { } /** * get the script builder parameters. */ void CommandVolumeHistogram::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addVariableListOfParameters("Options"); } /** * get full help information. */ QString CommandVolumeHistogram::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "[-list-peaks]\n" + indent9 + "[-number-of-buckets number-of-buckets]\n" + indent9 + "[-y-maximum maximum-y-value]\n" + indent9 + "\n" + indent9 + "Display a histogram of the volume in the terminal window.\n" + indent9 + "\n" + indent9 + "If \"-list-peaks\" is specified, numerical estimates of the\n" + indent9 + "gray and white matter peaks will be listed.\n" + indent9 + "\n" + indent9 + "Use \"-number-of-buckets\" to specify the number of buckets. \n" + indent9 + "The default is " + QString::number(numberOfBuckets) + ".\n" + indent9 + "\n" + indent9 + "Use \"-y-maximum\" to specify the maximum Y-value. The \n" + indent9 + "default is " + QString::number(yMaximum) + ".\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeHistogram::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); bool listPeaksFlag = false; bool yMaxWasSetByUser = false; while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("Histogram Options"); if (paramName == "-list-peaks") { listPeaksFlag = true; } else if (paramName == "-number-of-buckets") { numberOfBuckets = parameters->getNextParameterAsInt("Number of Buckets"); } else if (paramName == "-y-maximum") { yMaximum = parameters->getNextParameterAsFloat("Y-Maximum"); yMaxWasSetByUser = true; } else { throw CommandException("Unrecognized parameter: " + paramName); } } // // Read the input file // VolumeFile volume; volume.readFile(inputVolumeFileName); // // Determine the histogram // StatisticHistogram* histo = volume.getHistogram(numberOfBuckets); // // Adjust Y-Max // float maxBucketValue = 0.0; if (yMaxWasSetByUser == false) { std::set sortedBucketCounts; for (int i = 0; i < numberOfBuckets; i++) { float bucketDataValue, bucketCount; histo->getDataForBucket(i, bucketDataValue, bucketCount); sortedBucketCounts.insert(bucketCount); } int count = 0; for (std::set::reverse_iterator iter = sortedBucketCounts.rbegin(); iter != sortedBucketCounts.rend(); iter++) { if (DebugControl::getDebugOn()) { std::cout << "Find Y-Max: " << *iter << std::endl; } if (count >= 2) { yMaximum = *iter; break; } if (count == 0) { maxBucketValue = *iter; } count++; } } // // Place histogram into a 2D array // std::vector bucketValueStrings; const int numRows = 40; const int arraySize = numRows * numberOfBuckets; char* histoArray = new char[arraySize]; for (int i = 0; i < arraySize; i++) { histoArray[i] = ' ' ; } for (int i = 0; i < numberOfBuckets; i++) { float bucketDataValue, bucketCount; histo->getDataForBucket(i, bucketDataValue, bucketCount); const float percentToSet = bucketCount / yMaximum; const int numYUsed = std::min(static_cast(numRows * percentToSet), numRows); for (int j = 0; j < numYUsed; j++) { const int offset = (j * numberOfBuckets) + i; histoArray[offset] = '*'; } if (DebugControl::getDebugOn()) { std::cout << "Bucket, count, percentToSet, numYUsed: " << i << ", " << bucketCount << ", " << percentToSet << ", " << numYUsed << std::endl; } bucketValueStrings.push_back(QString::number(bucketDataValue, 'f', 0)); } // // Print the array // int maxChars = -1; std::cout << std::endl; for (int j = (numRows - 1); j >= 0; j--) { for (int i = 0; i < numberOfBuckets; i++) { const int offset = (j * numberOfBuckets) + i; std::cout << histoArray[offset]; } // // Print the Y-Value on the right side // const float rowHeight = yMaximum / numRows; const float yValue = rowHeight * (j + 1); QString yString = QString::number(yValue, 'f', 1); if (maxChars < 0) { maxChars = yString.length(); } else { yString = yString.rightJustified(maxChars, ' '); } std::cout << " " << yString.toAscii().constData(); std::cout << std::endl; } // // print value at each column vertically // int maxDigits = 0; for (int i = 0; i < numberOfBuckets; i++) { maxDigits = std::max(maxDigits, bucketValueStrings[i].length()); } for (int i = 0; i < numberOfBuckets; i++) { bucketValueStrings[i] = bucketValueStrings[i].rightJustified(maxDigits, '0'); } for (int i = 0; i < maxDigits; i++) { for (int j = 0; j < numberOfBuckets; j++) { const QString s(bucketValueStrings[j]); const char c = s[i].toAscii(); std::cout << c; } std::cout << std::endl; } std::cout << std::endl; // // Print maximum bucket value // std::cout << "Maximum Y-Value: " << QString::number(maxBucketValue, 'f', 1).toAscii().constData() << std::endl; std::cout << "Max Y-Value Displayed: " << QString::number(yMaximum, 'f', 1).toAscii().constData() << std::endl; std::cout << std::endl; // // Print the histogram peaks // if (listPeaksFlag) { histo->printHistogramPeaks(std::cout); } delete histo; histo = NULL; delete histoArray; histoArray = NULL; } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeGradient.h0000664000175000017500000000342211572067322026216 0ustar michaelmichael #ifndef __COMMAND_VOLUME_GRADIENT_H__ #define __COMMAND_VOLUME_GRADIENT_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for computing a volume gradient class CommandVolumeGradient : public CommandBase { public: // constructor CommandVolumeGradient(); // destructor ~CommandVolumeGradient(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_GRADIENT_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeGradient.cxx0000664000175000017500000001027611572067322026576 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelVolumeGradient.h" #include "BrainSet.h" #include "CommandVolumeGradient.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SureFitVectorFile.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeGradient::CommandVolumeGradient() : CommandBase("-volume-gradient", "VOLUME GRADIENT") { } /** * destructor. */ CommandVolumeGradient::~CommandVolumeGradient() { } /** * get the script builder parameters. */ void CommandVolumeGradient::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Mask Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Output Gradient Vector File", FileFilters::getSureFitVectorFileFilter()); paramsOut.addInt("Lambda"); paramsOut.addBoolean("Grad Flag"); paramsOut.addBoolean("Mask Flag"); } /** * get full help information. */ QString CommandVolumeGradient::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Compute gradient.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeGradient::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); const QString inputMaskVolumeFileName = parameters->getNextParameterAsString("Input Mask Volume File Name"); const QString outputGradientFileName = parameters->getNextParameterAsString("Output Gradient Vector File Name"); const int lambda = parameters->getNextParameterAsInt("Lambda"); const int gradFlag = parameters->getNextParameterAsBoolean("Grad Flag"); const int maskFlag = parameters->getNextParameterAsBoolean("Mask Flag"); // // Read the input and mask volume files // VolumeFile vf; vf.readFile(inputVolumeFileName); VolumeFile maskVolume; maskVolume.readFile(inputMaskVolumeFileName); // // Gradient vector file // int xDim, yDim, zDim; vf.getDimensions(xDim, yDim, zDim); SureFitVectorFile gradFile(xDim, yDim, zDim); // // determine gradient // BrainSet bs; BrainModelVolumeGradient grad(&bs, lambda, gradFlag, maskFlag, &vf, &maskVolume, &gradFile); grad.execute(); // // Write the gradient file // gradFile.writeFile(outputGradientFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeFslToVector.h0000664000175000017500000000346611572067322026703 0ustar michaelmichael #ifndef __COMMAND_VOLUME_FSL_TO_VECTOR_H__ #define __COMMAND_VOLUME_FSL_TO_VECTOR_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for converting fsl volumes to a vector file class CommandVolumeFslToVector : public CommandBase { public: // constructor CommandVolumeFslToVector(); // destructor ~CommandVolumeFslToVector(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_FSL_TO_VECTOR_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeFslToVector.cxx0000664000175000017500000002052111572067322027245 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeFslToVector.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "TransformationMatrixFile.h" #include "VectorFile.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeFslToVector::CommandVolumeFslToVector() : CommandBase("-volume-fsl-to-vector", "VOLUME FSL TO VECTOR") { } /** * destructor. */ CommandVolumeFslToVector::~CommandVolumeFslToVector() { } /** * get the script builder parameters. */ void CommandVolumeFslToVector::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input XYZ Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Input Magnitude Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Input FSL Diffusion to Structureal Matrix File Name", "*.mat"); paramsOut.addFile("Volume in Output Stereotaxic Space", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Output Vector File Name", FileFilters::getGiftiVectorFileFilter()); paramsOut.addVariableListOfParameters("", ""); } /** * get full help information */ QString CommandVolumeFslToVector::getHelpInformation() const { float rgba[4]; VectorFile::getDefaultColorRGBA(rgba); QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-output-matrix output-transformation-matrix-file-name]\n" + indent9 + "[-rgb red green blue]\n" + indent9 + "\n" + indent9 + "Create a vector file from a vector volume file and .\n" + indent9 + "a magnitude volume file. All of the volumes must have \n" + indent9 + "the same IJK dimensions. A vector is created for each\n" + indent9 + "voxel whose magnitude is greater than zero.\n" + indent9 + "\n" + indent9 + "\"input-xyz-volume-file-name\" is a volume file that\n" + indent9 + "contains three sub-volumes containing the X, Y, and Z\n" + indent9 + "components of a unit vector.\n" + indent9 + "\n" + indent9 + "\"input-magnitude-volume-file-name\" is a volume \n" + indent9 + "containing the magnitude of the vectors.\n" + indent9 + "\n" + indent9 + "\"volume-in-output-stereotaxic-space-file-name\" is a \n" + indent9 + "volume whose stereotaxic coordinates are in the \n" + indent9 + "destination space.\n" + indent9 + "\n" + indent9 + "\"input-fsl-diffusion-to-structural-matrix\" is the FSL\n" + indent9 + "diffusion space to structural space matrix file, typically\n" + indent9 + "named \"diff2str.mat\". It contains a 4x4 transformation\n" + indent9 + "matrix with each row of the matrix on a separate line.\n" + indent9 + "\n" + indent9 + "The file name extension for a vector file is \"\n" + indent9 + SpecFile::getGiftiVectorFileExtension() + "\".\n" + indent9 + "\n" + indent9 + "If \"-output-matrix\" is specified, the matrix used to \n" + indent9 + "transform from the input volume to output volume space\n" + indent9 + "is placed in the output transformation matrix file.\n" + indent9 + "\n" + indent9 + "Use the \"-rgb\" option to set the colors of the \n" + indent9 + "vectors. The red, green, and blue components are\n" + indent9 + "specified as floating point number swith a range of \n" + indent9 + "zero to one. The default color is " + indent9 + "(" + QString::number(rgba[0]) + ", " + QString::number(rgba[1]) + ", " + QString::number(rgba[2]) + ")\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeFslToVector::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { float rgba[4]; VectorFile::getDefaultColorRGBA(rgba); QString outputMatrixFileName; const QString inputXYZVolumeFileName = parameters->getNextParameterAsString("Input XYZ Volume File Name"); const QString inputMagnitudeVolumeFileName = parameters->getNextParameterAsString("Input Magnitude Volume File Name"); const QString fslTransformationMatrixFileName = parameters->getNextParameterAsString("FSL Diffusion to Structural Matrix File Name"); const QString outputSpaceVolumeFileName = parameters->getNextParameterAsString("Volume in Output Stereotaxic Space File Name"); const QString outputVectorFileName = parameters->getNextParameterAsString("Output Vector File Name"); while (parameters->getParametersAvailable()) { const QString param = parameters->getNextParameterAsString("Optional Parameter"); if (param == "-output-matrix") { outputMatrixFileName = parameters->getNextParameterAsString("Output Matrix File Name"); } else if (param == "-rgb") { rgba[0] = parameters->getNextParameterAsFloat("Red Color Component"); rgba[1] = parameters->getNextParameterAsFloat("Green Color Component"); rgba[2] = parameters->getNextParameterAsFloat("Blue Color Component"); } else { throw CommandException("Unrecognized parameter: " + param); } } // // Read the input files // TransformationMatrixFile transformMatrixFile; transformMatrixFile.readFile(fslTransformationMatrixFileName); TransformationMatrix* fslMatrix = transformMatrixFile.getTransformationMatrix(0); if (fslMatrix == NULL) { throw CommandException("Unable to find a matrix in FSL Matrix File."); } std::vector xyzVolumes; VolumeFile::setVolumeSpace(VolumeFile::VOLUME_SPACE_VOXEL_NATIVE); // DO NOT make LPI VolumeFile::readFile(inputXYZVolumeFileName, -1, xyzVolumes); if (xyzVolumes.size() != 3) { throw CommandException(inputXYZVolumeFileName + " must contain exactly three subvolumes."); } VolumeFile magnitudeVolume; VolumeFile::setVolumeSpace(VolumeFile::VOLUME_SPACE_VOXEL_NATIVE); // DO NOT make LPI magnitudeVolume.readFile(inputMagnitudeVolumeFileName); VolumeFile outputSpaceVolumeFile; outputSpaceVolumeFile.readFile(outputSpaceVolumeFileName); TransformationMatrix outputTransformationMatrix; VectorFile* vf = VectorFile::createVectorFileFromFSLVectorVolumes( *(xyzVolumes[0]), *(xyzVolumes[1]), *(xyzVolumes[2]), magnitudeVolume, outputSpaceVolumeFile, *fslMatrix, outputTransformationMatrix, rgba); vf->writeFile(outputVectorFileName); if (outputMatrixFileName.isEmpty() == false) { TransformationMatrixFile tm; tm.addTransformationMatrix(outputTransformationMatrix); tm.writeFile(outputMatrixFileName); } delete vf; } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeFloodFill.h0000664000175000017500000000342611572067322026337 0ustar michaelmichael #ifndef __COMMAND_VOLUME_FLOOD_FILL_H__ #define __COMMAND_VOLUME_FLOOD_FILL_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for flood filling a volume class CommandVolumeFloodFill : public CommandBase { public: // constructor CommandVolumeFloodFill(); // destructor ~CommandVolumeFloodFill(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_FLOOD_FILL_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeFloodFill.cxx0000664000175000017500000000735011572067322026712 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeFloodFill.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeFloodFill::CommandVolumeFloodFill() : CommandBase("-volume-flood-fill", "VOLUME FLOOD FILL") { } /** * destructor. */ CommandVolumeFloodFill::~CommandVolumeFloodFill() { } /** * get the script builder parameters. */ void CommandVolumeFloodFill::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Output Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addInt("Seed X", 1, 0, 100000); paramsOut.addInt("Seed Y", 1, 0, 100000); paramsOut.addInt("Seed Z", 1, 0, 100000); } /** * get full help information. */ QString CommandVolumeFloodFill::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Fllod fill the object starting at the seed. All voxels not\n" + indent9 + "connected are set to zero.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeFloodFill::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); QString outputVolumeFileName, outputVolumeFileLabel; parameters->getNextParameterAsVolumeFileNameAndLabel("Output Volume File Name", outputVolumeFileName, outputVolumeFileLabel); const int seedX = parameters->getNextParameterAsInt("Seed X"); const int seedY = parameters->getNextParameterAsInt("Seed Y"); const int seedZ = parameters->getNextParameterAsInt("Seed Z"); // // Read the input volume file // VolumeFile vf; vf.readFile(inputVolumeFileName); // // Find the biggest object and remove any islands. // const int seed[3] = { seedX, seedY, seedZ }; vf.floodFillWithVTK(seed, 255, 255, 0); // // Write the volume file // writeVolumeFile(vf, outputVolumeFileName, outputVolumeFileLabel); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeFindLimits.h0000664000175000017500000000340511572067322026524 0ustar michaelmichael #ifndef __COMMAND_VOLUME_FIND_LIMITS_H__ #define __COMMAND_VOLUME_FIND_LIMITS_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandVolumeFindLimits : public CommandBase { public: // constructor CommandVolumeFindLimits(); // destructor ~CommandVolumeFindLimits(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_FIND_LIMITS_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeFindLimits.cxx0000664000175000017500000000566111572067322027105 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeFindLimits.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeFindLimits::CommandVolumeFindLimits() : CommandBase("-volume-find-limits", "VOLUME FIND LIMITS") { } /** * destructor. */ CommandVolumeFindLimits::~CommandVolumeFindLimits() { } /** * get the script builder parameters. */ void CommandVolumeFindLimits::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Limits File Name", FileFilters::getAnyFileFilter()); } /** * get full help information. */ QString CommandVolumeFindLimits::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Find the limits (non-zero voxel extent) of the volume.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeFindLimits::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the parameters // const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); const QString outputLimitsFileName = parameters->getNextParameterAsString("Output Limits File Name"); checkForExcessiveParameters(); // // Read the input volume file // VolumeFile vf; vf.readFile(inputVolumeFileName); // // find the limits // int extent[6]; vf.findLimits(outputLimitsFileName, extent); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeFillSlice.h0000664000175000017500000000343411572067322026332 0ustar michaelmichael #ifndef __COMMAND_VOLUME_FILL_SLICE_H__ #define __COMMAND_VOLUME_FILL_SLICE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for flood filling a single slice class CommandVolumeFillSlice : public CommandBase { public: // constructor CommandVolumeFillSlice(); // destructor ~CommandVolumeFillSlice(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_FILL_SLICE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeFillSlice.cxx0000664000175000017500000001055711572067322026711 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeFillSlice.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeFillSlice::CommandVolumeFillSlice() : CommandBase("-volume-fill-slice", "VOLUME FILL SLICE") { } /** * destructor. */ CommandVolumeFillSlice::~CommandVolumeFillSlice() { } /** * get the script builder parameters. */ void CommandVolumeFillSlice::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { std::vector axisValues, axisNames; axisValues.push_back("X"); axisNames.push_back("Parasagittal View"); axisValues.push_back("Y"); axisNames.push_back("Coronal View"); axisValues.push_back("Z"); axisNames.push_back("Horizontal (axial) View"); paramsOut.clear(); paramsOut.addFile("Input Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Output Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addListOfItems("Axis", axisValues, axisNames); paramsOut.addInt("Seed X", 1, 0, 100000); paramsOut.addInt("Seed Y", 1, 0, 100000); paramsOut.addInt("Seed Z", 1, 0, 100000); } /** * get full help information. */ QString CommandVolumeFillSlice::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Flood fill a single slice.\n" + indent9 + "\n" + indent9 + " axis is one of: \n" + indent9 + " X => x-axis (parasagittal view)\n" + indent9 + " Y => y-axis (coronal view)\n" + indent9 + " Z => z-axis (horizontal/axial view)\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeFillSlice::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); QString outputVolumeFileName, outputVolumeFileLabel; parameters->getNextParameterAsVolumeFileNameAndLabel("Output Volume File Name", outputVolumeFileName, outputVolumeFileLabel); VolumeFile::VOLUME_AXIS axis = VolumeFile::getAxisFromString(parameters->getNextParameterAsString("AXIS")); const int seedX = parameters->getNextParameterAsInt("Seed X"); const int seedY = parameters->getNextParameterAsInt("Seed Y"); const int seedZ = parameters->getNextParameterAsInt("Seed Z"); // // Read the input volume file // VolumeFile vf; vf.readFile(inputVolumeFileName); // // Find the biggest object and remove any islands. // const int seed[3] = { seedX, seedY, seedZ }; vf.floodFillSliceWithVTK(axis, seed, 255, 255, 0); // // Write the volume file // writeVolumeFile(vf, outputVolumeFileName, outputVolumeFileLabel); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeFillHoles.h0000664000175000017500000000346111572067322026345 0ustar michaelmichael #ifndef __COMMAND_VOLUME_FILL_HOLES_H__ #define __COMMAND_VOLUME_FILL_HOLES_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for filling holes (cavities) in a segmentation volume class CommandVolumeFillHoles : public CommandBase { public: // constructor CommandVolumeFillHoles(); // destructor ~CommandVolumeFillHoles(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_FILL_HOLES_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeFillHoles.cxx0000664000175000017500000000630211572067322026715 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeFillHoles.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeFillHoles::CommandVolumeFillHoles() : CommandBase("-volume-fill-holes", "VOLUME FILL HOLES") { } /** * destructor. */ CommandVolumeFillHoles::~CommandVolumeFillHoles() { } /** * get the script builder parameters. */ void CommandVolumeFillHoles::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Output Volume File Name", FileFilters::getVolumeGenericFileFilter()); } /** * get full help information. */ QString CommandVolumeFillHoles::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Fill holes (cavities) in a segmentation volume.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeFillHoles::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the parameters // const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); QString outputVolumeFileName, outputVolumeFileLabel; parameters->getNextParameterAsVolumeFileNameAndLabel("Output Volume File Name", outputVolumeFileName, outputVolumeFileLabel); checkForExcessiveParameters(); // // Read the input volume file // VolumeFile vf; vf.readFile(inputVolumeFileName); // // fill the holes // vf.fillSegmentationCavities(); // // Write the volume file // writeVolumeFile(vf, outputVolumeFileName, outputVolumeFileLabel); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeFillBiggestObject.h0000664000175000017500000000354211572067322030006 0ustar michaelmichael #ifndef __COMMAND_VOLUME_FILL_BIGGEST_OBJECT_H__ #define __COMMAND_VOLUME_FILL_BIGGEST_OBJECT_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for filling the biggest object and removing islands class CommandVolumeFillBiggestObject : public CommandBase { public: // constructor CommandVolumeFillBiggestObject(); // destructor ~CommandVolumeFillBiggestObject(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_FILL_BIGGEST_OBJECT_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeFillBiggestObject.cxx0000664000175000017500000001044211572067322030356 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeFillBiggestObject.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeFillBiggestObject::CommandVolumeFillBiggestObject() : CommandBase("-volume-fill-biggest-object", "VOLUME FILL BIGGEST OBJECT") { } /** * destructor. */ CommandVolumeFillBiggestObject::~CommandVolumeFillBiggestObject() { } /** * get the script builder parameters. */ void CommandVolumeFillBiggestObject::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Output Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addInt("Min X", 1, 0, 100000); paramsOut.addInt("Max X", 1, 0, 100000); paramsOut.addInt("Min Y", 1, 0, 100000); paramsOut.addInt("Max Y", 1, 0, 100000); paramsOut.addInt("Min Z", 1, 0, 100000); paramsOut.addInt("Max Z", 1, 0, 100000); } /** * get full help information. */ QString CommandVolumeFillBiggestObject::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + "\n" + indent9 + "Fill the biggest object with extent and remove all islands.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeFillBiggestObject::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the parameters // const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); QString outputVolumeFileName, outputVolumeFileLabel; parameters->getNextParameterAsVolumeFileNameAndLabel("Output Volume File Name", outputVolumeFileName, outputVolumeFileLabel); const int minX = parameters->getNextParameterAsInt("Minimum X"); const int maxX = parameters->getNextParameterAsInt("Maximum X"); const int minY = parameters->getNextParameterAsInt("Minimum Y"); const int maxY = parameters->getNextParameterAsInt("Maximum Y"); const int minZ = parameters->getNextParameterAsInt("Minimum Z"); const int maxZ = parameters->getNextParameterAsInt("Maximum Z"); checkForExcessiveParameters(); // // Read the input volume file // VolumeFile vf; vf.readFile(inputVolumeFileName); // // Find the biggest object and remove any islands. // const int extent[6] = { minX, maxX, minY, maxY, minZ, maxZ }; vf.fillBiggestObjectWithinMask(extent, 255.0, 255.0); // // Write the volume file // writeVolumeFile(vf, outputVolumeFileName, outputVolumeFileLabel); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeFileMerge.h0000664000175000017500000000342411572067322026322 0ustar michaelmichael #ifndef __COMMAND_VOLUME_FILE_MERGE_H__ #define __COMMAND_VOLUME_FILE_MERGE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for merging volume files class CommandVolumeFileMerge : public CommandBase { public: // constructor CommandVolumeFileMerge(); // destructor ~CommandVolumeFileMerge(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_FILE_MERGE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeFileMerge.cxx0000664000175000017500000002064011572067322026674 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeFileMerge.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeFileMerge::CommandVolumeFileMerge() : CommandBase("-volume-file-merge", "VOLUME FILE MERGE LEFT and RIGHT") { } /** * destructor. */ CommandVolumeFileMerge::~CommandVolumeFileMerge() { } /** * get the script builder parameters. */ void CommandVolumeFileMerge::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Output Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Left Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Right Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addVariableListOfParameters("Optional Parameters"); } /** * get full help information. */ QString CommandVolumeFileMerge::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[other-input-volume-files]\n" + indent9 + "[-paint]\n" + indent9 + "\n" + indent9 + "Merge the volumes into a single volume file.\n" + indent9 + "\n" + indent9 + "The purpose of this command is to merge left and right \n" + indent9 + "hemisphere volumes into a single volume file. The input\n" + indent9 + "volumes must all have the same dimensions. If the input\n" + indent9 + "volumes are multi-brick volumes, each input file must \n" + indent9 + "contain the same number of bricks, each brick is merged\n" + indent9 + "with the corresponding bricks in the other input volume\n" + indent9 + "files, and the output volume file will contain the same\n" + indent9 + "number of bricks.\n" + indent9 + "\n" + indent9 + "When merging the voxels, the output voxel is set to the \n" + indent9 + "largest of the corresponding input voxels.\n" + indent9 + "\n" + indent9 + "If the volumes are paint or probabilistic atlas volume\n" + indent9 + "files, the \"-paint\" option must be specified so that\n" + indent9 + "paint name indices are synchronized throughout all of\n" + indent9 + "the volumes.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeFileMerge::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get parameters // const QString outputVolumeFileName = parameters->getNextParameterAsString("Output Volume File Name"); std::vector inputVolumeFileNames; inputVolumeFileNames.push_back( parameters->getNextParameterAsString("Left Input Volume File Name")); inputVolumeFileNames.push_back( parameters->getNextParameterAsString("Right Input Volume File Name")); bool paintFlag = false; while (parameters->getParametersAvailable()) { const QString name = parameters->getNextParameterAsString("Optional parameter"); if (name == "-paint") { paintFlag = true; } else { inputVolumeFileNames.push_back(name); } } // // Read all of the input volumes // std::vector allInputVolumes; std::vector > inputVolumes; for (unsigned int i = 0; i < inputVolumeFileNames.size(); i++) { std::vector volumesRead; VolumeFile::readFile(inputVolumeFileNames[i], -1, volumesRead); allInputVolumes.insert(allInputVolumes.end(), volumesRead.begin(), volumesRead.end()); inputVolumes.push_back(volumesRead); } // // Verify all volumes are the same dimensions // const VolumeFile* firstVolume = allInputVolumes[0]; int dim[3]; firstVolume->getDimensions(dim); const int totalNumberOfVolumes = static_cast(allInputVolumes.size()); for (int i = 1; i < totalNumberOfVolumes; i++) { int dimOther[3]; allInputVolumes[i]->getDimensions(dimOther); if ((dim[0] != dimOther[0]) || (dim[1] != dimOther[1]) || (dim[2] != dimOther[2])) { throw CommandException("The input volumes are of different dimensions"); } } // // Verify that the input volumes contain the same number of bricks // const int numberOfInputVolumes = static_cast(inputVolumes.size()); if (numberOfInputVolumes <= 1) { throw CommandException("There must be at least two input volume files."); } const int numBricksPerVolume = static_cast(inputVolumes[0].size()); for (int i = 1; i < numberOfInputVolumes; i++) { if (static_cast(inputVolumes[i].size()) != numBricksPerVolume) { } } // // Handle paint names // VolumeFile::VOLUME_TYPE volumeType = allInputVolumes[0]->getVolumeType(); if (paintFlag) { volumeType = VolumeFile::VOLUME_TYPE_PAINT; } if (volumeType == VolumeFile::VOLUME_TYPE_PAINT) { VolumeFile::synchronizeRegionNames(allInputVolumes); } // // Loop through the bricks // for (int brickNum = 0; brickNum < numBricksPerVolume; brickNum++) { // // Loop through the voxels // for (int i = 0; i < dim[0]; i++) { for (int j = 0; j < dim[1]; j++) { for (int k = 0; k < dim[2]; k++) { // // Get voxel from first volume // float voxel = inputVolumes[0][brickNum]->getVoxel(i, j, k, 0); // // Get the maximum value for the voxel from all corresponding bricks // for (int volumeNum = 1; volumeNum < numberOfInputVolumes; volumeNum++) { voxel = std::max(voxel, inputVolumes[volumeNum][brickNum]->getVoxel(i, j, k, 0)); } // // Save the voxel into the first volume // inputVolumes[0][brickNum]->setVoxel(i, j, k, 0, voxel); } } } } // // Append the comments // QString comment; for (int volumeNum = 0; volumeNum < numberOfInputVolumes; volumeNum++) { comment += inputVolumes[volumeNum][0]->getFileComment() + "\n"; } inputVolumes[0][0]->setFileComment(comment); // // Append the descriptive labels // for (int brickNum = 0; brickNum < numBricksPerVolume; brickNum++) { QString label; for (int volumeNum = 0; volumeNum < numberOfInputVolumes; volumeNum++) { label += inputVolumes[volumeNum][brickNum]->getDescriptiveLabel() + " "; } inputVolumes[0][brickNum]->setDescriptiveLabel(label); } // // Write the output volume file // VolumeFile::writeFile(outputVolumeFileName, volumeType, inputVolumes[0][0]->getVoxelDataType(), inputVolumes[0]); // // Free memory // for (unsigned int i = 0; i < allInputVolumes.size(); i++) { delete allInputVolumes[i]; } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeFileCombine.h0000664000175000017500000000341311572067322026635 0ustar michaelmichael #ifndef __COMMAND_VOLUME_FILE_COMBINE_H__ #define __COMMAND_VOLUME_FILE_COMBINE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandVolumeFileCombine : public CommandBase { public: // constructor CommandVolumeFileCombine(); // destructor ~CommandVolumeFileCombine(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_FILE_COMBINE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeFileCombine.cxx0000664000175000017500000001070311572067322027210 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeFileCombine.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeFileCombine::CommandVolumeFileCombine() : CommandBase("-volume-file-combine", "VOLUME FILE COMBINE") { } /** * destructor. */ CommandVolumeFileCombine::~CommandVolumeFileCombine() { } /** * get the script builder parameters. */ void CommandVolumeFileCombine::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Output Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addMultipleFiles("Input Volume File Name(s)", FileFilters::getVolumeGenericFileFilter()); paramsOut.addVariableListOfParameters("Optional Parameters"); } /** * get full help information. */ QString CommandVolumeFileCombine::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[additional-input-volume-files]\n" + indent9 + "[-paint]\n" + indent9 + "Combine the volumes into a single, multi-volume file.\n" + indent9 + "\n" + indent9 + "If the volumes are paint or probabilistic atlas volume\n" + indent9 + "files, the \"-paint\" option must be specified so that\n" + indent9 + "paint name indices are synchronized throughout all of\n" + indent9 + "the volumes.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeFileCombine::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get parameters // const QString outputVolumeFileName = parameters->getNextParameterAsString("Output Volume File Name"); std::vector inputVolumeFileNames; bool paintFlag = false; while (parameters->getParametersAvailable()) { const QString name = parameters->getNextParameterAsString("Optional parameter"); if (name == "-paint") { paintFlag = true; } else { inputVolumeFileNames.push_back(name); } } // // Read all of the input volumes // std::vector allVolumes; for (unsigned int i = 0; i < inputVolumeFileNames.size(); i++) { std::vector volumesRead; VolumeFile::readFile(inputVolumeFileNames[i], -1, volumesRead); allVolumes.insert(allVolumes.end(), volumesRead.begin(), volumesRead.end()); } if (allVolumes.empty()) { throw CommandException("No volumes were read."); } // // Handle paint names // VolumeFile::VOLUME_TYPE volumeType = allVolumes[0]->getVolumeType(); if (paintFlag) { volumeType = VolumeFile::VOLUME_TYPE_PAINT; } // // Write the output volume file // VolumeFile::writeFile(outputVolumeFileName, volumeType, allVolumes[0]->getVoxelDataType(), allVolumes); // // Free memory // for (unsigned int i = 0; i < allVolumes.size(); i++) { delete allVolumes[i]; } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeEulerCount.h0000664000175000017500000000355511572067322026555 0ustar michaelmichael #ifndef __COMMAND_VOLUME_EULER_COUNT_H__ #define __COMMAND_VOLUME_EULER_COUNT_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for performing an euler count on a volume class CommandVolumeEulerCount : public CommandBase { public: // constructor CommandVolumeEulerCount(); // destructor ~CommandVolumeEulerCount(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // obsolete message QString obsoleteMessage() const; // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_EULER_COUNT_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeEulerCount.cxx0000664000175000017500000001130111572067322027114 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "CommandVolumeEulerCount.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" #include "CommandVolumeTopologyReport.h" /** * constructor. */ CommandVolumeEulerCount::CommandVolumeEulerCount() : CommandBase("-volume-euler", "VOLUME EULER COUNT") { } /** * destructor. */ CommandVolumeEulerCount::~CommandVolumeEulerCount() { } /** * get the script builder parameters. */ void CommandVolumeEulerCount::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); /* paramsOut.addFile("Input Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addInt("Min X", 1, 0, 100000); paramsOut.addInt("Max X", 1, 0, 100000); paramsOut.addInt("Min Y", 1, 0, 100000); paramsOut.addInt("Max Y", 1, 0, 100000); paramsOut.addInt("Min Z", 1, 0, 100000); paramsOut.addInt("Max Z", 1, 0, 100000); */ } /** * obsolete message. */ QString CommandVolumeEulerCount::obsoleteMessage() const { CommandVolumeTopologyReport vtr; QString msg = "This command (" + this->getOperationSwitch() + ") has been replaced by \"" + vtr.getOperationSwitch() + "\"."; return msg; } /** * get full help information. */ QString CommandVolumeEulerCount::getHelpInformation() const { return obsoleteMessage(); /* QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + "\n" + indent9 + "Perform and print the Euler Counts for a segmentation volume\n" + indent9 + "\n"); return helpInfo; */ } /** * execute the command. */ void CommandVolumeEulerCount::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { throw CommandException(obsoleteMessage()); /* // // Get the parameters // const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); const int minX = parameters->getNextParameterAsInt("Minimum X"); const int maxX = parameters->getNextParameterAsInt("Maximum X"); const int minY = parameters->getNextParameterAsInt("Minimum Y"); const int maxY = parameters->getNextParameterAsInt("Maximum Y"); const int minZ = parameters->getNextParameterAsInt("Minimum Z"); const int maxZ = parameters->getNextParameterAsInt("Maximum Z"); checkForExcessiveParameters(); // // Read the input volume file // VolumeFile vf; vf.readFile(inputVolumeFileName); // // Do the euler count // const int extent[6] = { minX, maxX, minY, maxY, minZ, maxZ }; int NumObjects, NumCavities, NumHandles, eulerCount; vf.getEulerCountsForSegmentationSubVolume(NumObjects, NumCavities, NumHandles, eulerCount, extent); // // Print the counts // std::cout << "Num Objects " << NumObjects << std::endl; std::cout << "Num Cavities " << NumCavities << std::endl; std::cout << "Num Handles " << NumHandles << std::endl; std::cout << "Euler Count " << eulerCount << std::endl; */ } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeErode.h0000664000175000017500000000334411572067322025522 0ustar michaelmichael #ifndef __COMMAND_VOLUME_ERODE_H__ #define __COMMAND_VOLUME_ERODE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandVolumeErode : public CommandBase { public: // constructor CommandVolumeErode(); // destructor ~CommandVolumeErode(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_ERODE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeErode.cxx0000664000175000017500000000654411572067322026102 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeErode.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeErode::CommandVolumeErode() : CommandBase("-volume-erode", "VOLUME ERODE") { } /** * destructor. */ CommandVolumeErode::~CommandVolumeErode() { } /** * get the script builder parameters. */ void CommandVolumeErode::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Output Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addInt("Iterations", 5, 0, 100000); } /** * get full help information. */ QString CommandVolumeErode::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Erode the volume for the specified number of iterations.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeErode::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the parameters // const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); QString outputVolumeFileName, outputVolumeFileLabel; parameters->getNextParameterAsVolumeFileNameAndLabel("Output Volume File Name", outputVolumeFileName, outputVolumeFileLabel); const int numberOfIterations = parameters->getNextParameterAsInt("Number of Iterations"); checkForExcessiveParameters(); // // Read the input volume file // VolumeFile vf; vf.readFile(inputVolumeFileName); // // Dilate the volume // vf.doVolMorphOps(0, numberOfIterations); // // Write the volume file // writeVolumeFile(vf, outputVolumeFileName, outputVolumeFileLabel); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeDilateErodeWithinMask.h0000664000175000017500000000360211572067322030641 0ustar michaelmichael #ifndef __COMMAND_VOLUME_DILATE_ERODE_WITHIN_MASK_H__ #define __COMMAND_VOLUME_DILATE_ERODE_WITHIN_MASK_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for dilation followed by erosion (closing) within a mask class CommandVolumeDilateErodeWithinMask : public CommandBase { public: // constructor CommandVolumeDilateErodeWithinMask(); // destructor ~CommandVolumeDilateErodeWithinMask(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_DILATE_ERODE_WITHIN_MASK_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeDilateErodeWithinMask.cxx0000664000175000017500000001144711572067322031222 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeDilateErodeWithinMask.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeDilateErodeWithinMask::CommandVolumeDilateErodeWithinMask() : CommandBase("-volume-dilate-erode-mask", "VOLUME DILATE AND ERODE WITHIN MASK") { } /** * destructor. */ CommandVolumeDilateErodeWithinMask::~CommandVolumeDilateErodeWithinMask() { } /** * get the script builder parameters. */ void CommandVolumeDilateErodeWithinMask::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Output Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addInt("Dilation Iterations", 5, 0, 100000); paramsOut.addInt("Erosion Iterations", 5, 0, 100000); paramsOut.addInt("Min X", 1, 0, 100000); paramsOut.addInt("Max X", 1, 0, 100000); paramsOut.addInt("Min Y", 1, 0, 100000); paramsOut.addInt("Max Y", 1, 0, 100000); paramsOut.addInt("Min Z", 1, 0, 100000); paramsOut.addInt("Max Z", 1, 0, 100000); } /** * get full help information. */ QString CommandVolumeDilateErodeWithinMask::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + "\n" + indent9 + "Dilate the volume for the specified number of iterations\n" + indent9 + "within a mask.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeDilateErodeWithinMask::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the parameters // const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); QString outputVolumeFileName, outputVolumeFileLabel; parameters->getNextParameterAsVolumeFileNameAndLabel("Output Volume File Name", outputVolumeFileName, outputVolumeFileLabel); const int numberOfDilationIterations = parameters->getNextParameterAsInt("Number of Dilation Iterations"); const int numberOfErosionIterations = parameters->getNextParameterAsInt("Number of Erosion Iterations"); const int minX = parameters->getNextParameterAsInt("Minimum X"); const int maxX = parameters->getNextParameterAsInt("Maximum X"); const int minY = parameters->getNextParameterAsInt("Minimum Y"); const int maxY = parameters->getNextParameterAsInt("Maximum Y"); const int minZ = parameters->getNextParameterAsInt("Minimum Z"); const int maxZ = parameters->getNextParameterAsInt("Maximum Z"); checkForExcessiveParameters(); // // Read the input volume file // VolumeFile vf; vf.readFile(inputVolumeFileName); // // Dilate the volume // const int extent[6] = { minX, maxX, minY, maxY, minZ, maxZ }; vf.doVolMorphOpsWithinMask(extent, numberOfDilationIterations, numberOfErosionIterations); // // Write the volume file // writeVolumeFile(vf, outputVolumeFileName, outputVolumeFileLabel); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeDilateErode.h0000664000175000017500000000346211572067322026646 0ustar michaelmichael #ifndef __COMMAND_VOLUME_DILATE_ERODE_H__ #define __COMMAND_VOLUME_DILATE_ERODE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for dilation followed by erosion (closing) class CommandVolumeDilateErode : public CommandBase { public: // constructor CommandVolumeDilateErode(); // destructor ~CommandVolumeDilateErode(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_DILATE_ERODE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeDilateErode.cxx0000664000175000017500000000730111572067322027215 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeDilateErode.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeDilateErode::CommandVolumeDilateErode() : CommandBase("-volume-dilate-erode", "VOLUME DILATE AND ERODE") { } /** * destructor. */ CommandVolumeDilateErode::~CommandVolumeDilateErode() { } /** * get the script builder parameters. */ void CommandVolumeDilateErode::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Output Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addInt("Dilation Iterations", 5, 0, 100000); paramsOut.addInt("Erosion Iterations", 5, 0, 100000); } /** * get full help information. */ QString CommandVolumeDilateErode::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Dilate the volume for the specified number of iterations.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeDilateErode::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the parameters // const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); QString outputVolumeFileName, outputVolumeFileLabel; parameters->getNextParameterAsVolumeFileNameAndLabel("Output Volume File Name", outputVolumeFileName, outputVolumeFileLabel); const int numberOfDilationIterations = parameters->getNextParameterAsInt("Number of Dilation Iterations"); const int numberOfErosionIterations = parameters->getNextParameterAsInt("Number of Erosion Iterations"); checkForExcessiveParameters(); // // Read the input volume file // VolumeFile vf; vf.readFile(inputVolumeFileName); // // Dilate the volume // vf.doVolMorphOps(numberOfDilationIterations, numberOfErosionIterations); // // Write the volume file // writeVolumeFile(vf, outputVolumeFileName, outputVolumeFileLabel); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeDilate.h0000664000175000017500000000337411572067322025671 0ustar michaelmichael #ifndef __COMMAND_VOLUME_DILATE_H__ #define __COMMAND_VOLUME_DILATE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for dilating a volume class CommandVolumeDilate : public CommandBase { public: // constructor CommandVolumeDilate(); // destructor ~CommandVolumeDilate(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_DILATE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeDilate.cxx0000664000175000017500000000655611572067322026251 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeDilate.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeDilate::CommandVolumeDilate() : CommandBase("-volume-dilate", "VOLUME DILATE") { } /** * destructor. */ CommandVolumeDilate::~CommandVolumeDilate() { } /** * get the script builder parameters. */ void CommandVolumeDilate::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Output Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addInt("Iterations", 5, 0, 100000); } /** * get full help information. */ QString CommandVolumeDilate::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Dilate the volume for the specified number of iterations.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeDilate::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the parameters // const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); QString outputVolumeFileName, outputVolumeFileLabel; parameters->getNextParameterAsVolumeFileNameAndLabel("Output Volume File Name", outputVolumeFileName, outputVolumeFileLabel); const int numberOfIterations = parameters->getNextParameterAsInt("Number of Iterations"); checkForExcessiveParameters(); // // Read the input volume file // VolumeFile vf; vf.readFile(inputVolumeFileName); // // Dilate the volume // vf.doVolMorphOps(numberOfIterations, 0); // // Write the volume file // writeVolumeFile(vf, outputVolumeFileName, outputVolumeFileLabel); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeCreateInStereotaxicSpace.h0000664000175000017500000000353711572067322031351 0ustar michaelmichael #ifndef __COMMAND_VOLUME_CREATE_IN_STEREOTAXIC_SPACE_H__ #define __COMMAND_VOLUME_CREATE_IN_STEREOTAXIC_SPACE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandVolumeCreateInStereotaxicSpace : public CommandBase { public: // constructor CommandVolumeCreateInStereotaxicSpace(); // destructor ~CommandVolumeCreateInStereotaxicSpace(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_CREATE_IN_STEREOTAXIC_SPACE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeCreateInStereotaxicSpace.cxx0000664000175000017500000001173211572067322031720 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeCreateInStereotaxicSpace.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "StereotaxicSpace.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeCreateInStereotaxicSpace::CommandVolumeCreateInStereotaxicSpace() : CommandBase("-volume-create-in-stereotaxic-space", "VOLUME CREATE IN STEREOTAXIC SPACE") { } /** * destructor. */ CommandVolumeCreateInStereotaxicSpace::~CommandVolumeCreateInStereotaxicSpace() { } /** * get the script builder parameters. */ void CommandVolumeCreateInStereotaxicSpace::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { std::vector spaces; StereotaxicSpace::getAllStereotaxicSpaces(spaces); std::vector spaceNames; for (unsigned int i = 0; i < spaces.size(); i++) { if ((spaces[i].getSpace() != StereotaxicSpace::SPACE_UNKNOWN) && (spaces[i].getSpace() != StereotaxicSpace::SPACE_OTHER)) { const QString name = spaces[i].getName(); spaceNames.push_back(name); } } paramsOut.clear(); paramsOut.addListOfItems("Stereotaxic Space", spaceNames, spaceNames); paramsOut.addFile("Output Volume File", FileFilters::getVolumeGenericFileFilter()); } /** * get full help information. */ QString CommandVolumeCreateInStereotaxicSpace::getHelpInformation() const { std::vector spaces; StereotaxicSpace::getAllStereotaxicSpaces(spaces); QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Create a volume in the specified stereotaxic space.\n" + indent9 + "Valid spaces are:\n"); for (unsigned int i = 0; i < spaces.size(); i++) { if ((spaces[i].getSpace() != StereotaxicSpace::SPACE_UNKNOWN) && (spaces[i].getSpace() != StereotaxicSpace::SPACE_OTHER)) { const QString name = spaces[i].getName(); helpInfo += (indent9 + " " + name + "\n"); } } return helpInfo; } /** * execute the command. */ void CommandVolumeCreateInStereotaxicSpace::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { std::vector spaces; StereotaxicSpace::getAllStereotaxicSpaces(spaces); const QString stereotaxicSpaceName = parameters->getNextParameterAsString("Stereotaxic Space"); QString outputVolumeFileName, outputVolumeFileLabel; parameters->getNextParameterAsVolumeFileNameAndLabel("Output Volume File Name", outputVolumeFileName, outputVolumeFileLabel); StereotaxicSpace space = StereotaxicSpace::getStereotaxicSpace(stereotaxicSpaceName); if ((space.getSpace() == StereotaxicSpace::SPACE_UNKNOWN) || (space.getSpace() == StereotaxicSpace::SPACE_OTHER)) { throw CommandException("ERROR: Stereotaxic space name not recognized."); } int dimensions[3]; space.getDimensions(dimensions); float spacing[3]; space.getVoxelSize(spacing); float origin[3]; space.getOrigin(origin); const VolumeFile::ORIENTATION orient[3] = { VolumeFile::ORIENTATION_LEFT_TO_RIGHT, VolumeFile::ORIENTATION_POSTERIOR_TO_ANTERIOR, VolumeFile::ORIENTATION_INFERIOR_TO_SUPERIOR }; VolumeFile volume; volume.initialize(VolumeFile::VOXEL_DATA_TYPE_FLOAT, dimensions, orient, origin, spacing); // // Write the volume // writeVolumeFile(volume, outputVolumeFileName, outputVolumeFileLabel); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeCreateCorpusCallosumSlice.h0000664000175000017500000000362611572067322031546 0ustar michaelmichael #ifndef __COMMAND_VOLUME_CREATE_CORPUS_CALLOSUM_SLICE_H__ #define __COMMAND_VOLUME_CREATE_CORPUS_CALLOSUM_SLICE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for creating the corpus callosum slice from a volume class CommandVolumeCreateCorpusCallosumSlice : public CommandBase { public: // constructor CommandVolumeCreateCorpusCallosumSlice(); // destructor ~CommandVolumeCreateCorpusCallosumSlice(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_CREATE_CORPUS_CALLOSUM_SLICE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeCreateCorpusCallosumSlice.cxx0000664000175000017500000001331511572067322032115 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelVolumeSureFitSegmentation.h" #include "CommandVolumeCreateCorpusCallosumSlice.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "Structure.h" /** * constructor. */ CommandVolumeCreateCorpusCallosumSlice::CommandVolumeCreateCorpusCallosumSlice() : CommandBase("-volume-create-corpus-callosum-slice", "VOLUME CREATE CORPUS CALLOSUM SLICE") { } /** * destructor. */ CommandVolumeCreateCorpusCallosumSlice::~CommandVolumeCreateCorpusCallosumSlice() { } /** * get the script builder parameters. */ void CommandVolumeCreateCorpusCallosumSlice::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { std::vector structureTypes; std::vector structureNames; Structure::getAllTypesAndNames(structureTypes, structureNames, false); paramsOut.clear(); paramsOut.addFile("Anatomy Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Output Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addListOfItems("Structure", structureNames, structureNames); paramsOut.addVariableListOfParameters("Callosum Slice Options"); } /** * get full help information. */ QString CommandVolumeCreateCorpusCallosumSlice::getHelpInformation() const { std::vector structureTypes; std::vector structureNames; Structure::getAllTypesAndNames(structureTypes, structureNames, false); QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " [-gray gray-matter-peak]\n" + indent9 + " [-white white-matter-peak]\n" + indent9 + "\n" + indent9 + "Create the corpus callosum slice from an anatomical volume.\n" + indent9 + "If the gray and white matter peaks are not specified, they\n" + indent9 + "will be estimated.\n" + indent9 + "\n"); helpInfo += (indent9 + "Examples of \"structure\" are: \n"); for (int i = 0; i < static_cast(structureNames.size()); i++) { helpInfo += (indent9 + " " + structureNames[i] + "\n"); } helpInfo += (indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeCreateCorpusCallosumSlice::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the parameters // const QString inputVolumeFileName = parameters->getNextParameterAsString("Anatomy Volume File Name"); QString outputVolumeFileName, outputVolumeFileLabel; parameters->getNextParameterAsVolumeFileNameAndLabel("Output Volume File Name", outputVolumeFileName, outputVolumeFileLabel); const Structure structure = parameters->getNextParameterAsStructure("Structure"); // // Optional parameters // float grayMatterPeak = -1.0; float whiteMatterPeak = -1.0; while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("Volume Create Corpus Callosum Option"); if (paramName == "-gray") { grayMatterPeak = parameters->getNextParameterAsFloat("Gray Matter Peak"); } else if (paramName == "-white") { whiteMatterPeak = parameters->getNextParameterAsFloat("White Matter Peak"); } else { throw CommandException("Volume Create Corpus Callosum invalid parameter " + paramName); } } // // Read input file // VolumeFile anatomyVolume; anatomyVolume.readFile(inputVolumeFileName); // // Generate the corpus callosum slice volume // VolumeFile corpusCallosumVolume; BrainModelVolumeSureFitSegmentation::generateCorpusCallosumSlice( anatomyVolume, corpusCallosumVolume, structure, grayMatterPeak, whiteMatterPeak); // // Write the volume file // corpusCallosumVolume.setDescriptiveLabel(outputVolumeFileLabel); corpusCallosumVolume.writeFile(outputVolumeFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeCreate.h0000664000175000017500000000335211572067322025666 0ustar michaelmichael #ifndef __COMMAND_VOLUME_CREATE_H__ #define __COMMAND_VOLUME_CREATE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandVolumeCreate : public CommandBase { public: // constructor CommandVolumeCreate(); // destructor ~CommandVolumeCreate(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_CREATE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeCreate.cxx0000664000175000017500000000715411572067322026245 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeCreate.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeCreate::CommandVolumeCreate() : CommandBase("-volume-create", "VOLUME CREATE") { } /** * destructor. */ CommandVolumeCreate::~CommandVolumeCreate() { } /** * get the script builder parameters. */ void CommandVolumeCreate::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addInt("X-Dimension"); paramsOut.addInt("X-Dimension"); paramsOut.addInt("X-Dimension"); paramsOut.addFile("Output Volume File", FileFilters::getVolumeGenericFileFilter()); } /** * get full help information. */ QString CommandVolumeCreate::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Create a volume using the specified dimensions.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeCreate::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const int dimensions[3] = { parameters->getNextParameterAsInt("X-Dimension"), parameters->getNextParameterAsInt("Y-Dimension"), parameters->getNextParameterAsInt("Z-Dimension") }; QString outputVolumeFileName, outputVolumeFileLabel; parameters->getNextParameterAsVolumeFileNameAndLabel("Output Volume File Name", outputVolumeFileName, outputVolumeFileLabel); const float origin[3] = { 0.0, 0.0, 0.0 }; const float spacing[3] = { 1.0, 1.0, 1.0 }; const VolumeFile::ORIENTATION orient[3] = { VolumeFile::ORIENTATION_LEFT_TO_RIGHT, VolumeFile::ORIENTATION_POSTERIOR_TO_ANTERIOR, VolumeFile::ORIENTATION_INFERIOR_TO_SUPERIOR }; VolumeFile volume; volume.initialize(VolumeFile::VOXEL_DATA_TYPE_FLOAT, dimensions, orient, origin, spacing); // // Write the volume // writeVolumeFile(volume, outputVolumeFileName, outputVolumeFileLabel); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeConvertVectorToVolume.h0000664000175000017500000000356711572067322030771 0ustar michaelmichael #ifndef __COMMAND_VOLUME_CONVERT_VECTOR_TO_VOLUME_H__ #define __COMMAND_VOLUME_CONVERT_VECTOR_TO_VOLUME_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for converting a vector file to a volume file class CommandVolumeConvertVectorToVolume : public CommandBase { public: // constructor CommandVolumeConvertVectorToVolume(); // destructor ~CommandVolumeConvertVectorToVolume(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_CONVERT_VECTOR_TO_VOLUME_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeConvertVectorToVolume.cxx0000664000175000017500000000641211572067322031334 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeConvertVectorToVolume.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SureFitVectorFile.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeConvertVectorToVolume::CommandVolumeConvertVectorToVolume() : CommandBase("-volume-convert-vector-to-volume", "VOLUME CONVERT A VECTOR FILE TO A VOLUME FILE") { } /** * destructor. */ CommandVolumeConvertVectorToVolume::~CommandVolumeConvertVectorToVolume() { } /** * get the script builder parameters. */ void CommandVolumeConvertVectorToVolume::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Vector File Name", FileFilters::getVolumeVectorFileFilter()); paramsOut.addFile("Output Volume File Name", FileFilters::getVolumeVectorFileFilter()); } /** * get full help information. */ QString CommandVolumeConvertVectorToVolume::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Convert a vector file into a vector type volume file.\n" + indent9 + "\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeConvertVectorToVolume::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString vectorFileName = parameters->getNextParameterAsString("Input Vector File Name"); QString outputVolumeFileName = parameters->getNextParameterAsString("Output Volume File Name"); QString outputVolumeFileLabel; splitOutputVolumeNameIntoNameAndLabel(outputVolumeFileName, outputVolumeFileLabel); SureFitVectorFile vectorFile; vectorFile.readFile(vectorFileName); VolumeFile volumeFile(vectorFile); writeVolumeFile(volumeFile, outputVolumeFileName, outputVolumeFileLabel); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeClassifyIntensities.h0000664000175000017500000000352311572067322030457 0ustar michaelmichael #ifndef __COMMAND_VOLUME_CLASSIFY_INTENSITIES_H__ #define __COMMAND_VOLUME_CLASSIFY_INTENSITIES_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for classifying intensities class CommandVolumeClassifyIntensities : public CommandBase { public: // constructor CommandVolumeClassifyIntensities(); // destructor ~CommandVolumeClassifyIntensities(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_CLASSIFY_INTENSITIES_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeClassifyIntensities.cxx0000664000175000017500000000736511572067322031042 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeClassifyIntensities.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeClassifyIntensities::CommandVolumeClassifyIntensities() : CommandBase("-volume-classify-intensity", "VOLUME CLASSIFY INTENSITIES") { } /** * destructor. */ CommandVolumeClassifyIntensities::~CommandVolumeClassifyIntensities() { } /** * get the script builder parameters. */ void CommandVolumeClassifyIntensities::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFloat("Mean", 128); paramsOut.addFloat("Low", 0); paramsOut.addFloat("High", 255); paramsOut.addFloat("Signum", 1); paramsOut.addFile("Input Volume File Name", FileFilters::getVolumeAnatomyFileFilter()); paramsOut.addFile("Ooutput Volume File Name", FileFilters::getVolumeAnatomyFileFilter()); } /** * get full help information. */ QString CommandVolumeClassifyIntensities::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Classify intensities.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeClassifyIntensities::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const float mean = parameters->getNextParameterAsFloat("Mean"); const float low = parameters->getNextParameterAsFloat("Low"); const float high = parameters->getNextParameterAsFloat("High"); const float signum = parameters->getNextParameterAsFloat("Signum"); const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); QString outputVolumeFileName = parameters->getNextParameterAsString("Output Volume File Name"); QString outputVolumeFileLabel; splitOutputVolumeNameIntoNameAndLabel(outputVolumeFileName, outputVolumeFileLabel); VolumeFile volumeFile; volumeFile.readFile(inputVolumeFileName); // // classify // volumeFile.classifyIntensities(mean, low, high, signum); writeVolumeFile(volumeFile, outputVolumeFileName, outputVolumeFileLabel); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeBlur.h0000664000175000017500000000335611572067322025373 0ustar michaelmichael #ifndef __COMMAND_VOLUME_BLUR_H__ #define __COMMAND_VOLUME_BLUR_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for volume blurring class CommandVolumeBlur : public CommandBase { public: // constructor CommandVolumeBlur(); // destructor ~CommandVolumeBlur(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_BLUR_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeBlur.cxx0000664000175000017500000000572011572067322025743 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeBlur.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeBlur::CommandVolumeBlur() : CommandBase("-volume-blur", "VOLUME BLUR") { } /** * destructor. */ CommandVolumeBlur::~CommandVolumeBlur() { } /** * get the script builder parameters. */ void CommandVolumeBlur::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Volume File", FileFilters::getVolumeAnatomyFileFilter()); paramsOut.addFile("Output Volume File", FileFilters::getVolumeAnatomyFileFilter()); } /** * get full help information. */ QString CommandVolumeBlur::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Blur the volume.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeBlur::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); QString outputVolumeFileName = parameters->getNextParameterAsString("Output Volume File Name"); QString outputVolumeFileLabel; splitOutputVolumeNameIntoNameAndLabel(outputVolumeFileName, outputVolumeFileLabel); checkForExcessiveParameters(); VolumeFile volumeFile; volumeFile.readFile(inputVolumeFileName); volumeFile.blur(); writeVolumeFile(volumeFile, outputVolumeFileName, outputVolumeFileLabel); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeBiasCorrection.h0000664000175000017500000000346411572067322027375 0ustar michaelmichael #ifndef __COMMAND_VOLUME_BIAS_CORRECTION_H__ #define __COMMAND_VOLUME_BIAS_CORRECTION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for volume bias correction class CommandVolumeBiasCorrection : public CommandBase { public: // constructor CommandVolumeBiasCorrection(); // destructor ~CommandVolumeBiasCorrection(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_BIAS_CORRECTION_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeBiasCorrection.cxx0000664000175000017500000001066211572067322027746 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandVolumeBiasCorrection.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeBiasCorrection::CommandVolumeBiasCorrection() : CommandBase("-volume-bias-correction", "VOLUME BIAS CORRECTION") { } /** * destructor. */ CommandVolumeBiasCorrection::~CommandVolumeBiasCorrection() { } /** * get the script builder parameters. */ void CommandVolumeBiasCorrection::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addInt("Gray Minimum", 0); paramsOut.addInt("White Maximum", 255); paramsOut.addInt("Iterations", 5); paramsOut.addFile("Input Volume File", FileFilters::getVolumeAnatomyFileFilter()); paramsOut.addFile("Output Volume File", FileFilters::getVolumeAnatomyFileFilter()); } /** * get full help information. */ QString CommandVolumeBiasCorrection::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Perform bias (non-uniformity) correction on an anatomy\n" + indent9 + "volume.\n" + indent9 + "\n" + indent9 + "\"gray-minimum-value\" is an integer that is the minimum\n" + indent9 + "value of the gray matter voxels. \n" + indent9 + "\n" + indent9 + "\"white-maximum-value\" is an integer that is the maximum\n" + indent9 + "value of the white matter voxels. \n" + indent9 + "\n" + indent9 + "\"iterations\" is the number of iterations used in the bias\n" + indent9 + "correction algorithm. A value of 5 is sufficient in most\n" + indent9 + "cases. \n" + indent9 + "\n" + indent9 + "This algorithm (and code) is taken directly from AFNI's \n" + indent9 + "3dUniformize program. \n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeBiasCorrection::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const int grayMinimum = parameters->getNextParameterAsInt("Gray Minimum Value"); const int whiteMaximum = parameters->getNextParameterAsInt("White Maximum Value"); const int iterations = parameters->getNextParameterAsInt("Iterations"); const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); QString outputVolumeFileName = parameters->getNextParameterAsString("Output Volume File Name"); QString outputVolumeFileLabel; splitOutputVolumeNameIntoNameAndLabel(outputVolumeFileName, outputVolumeFileLabel); checkForExcessiveParameters(); VolumeFile volumeFile; volumeFile.readFile(inputVolumeFileName); volumeFile.biasCorrectionWithAFNI(grayMinimum, whiteMaximum, iterations); writeVolumeFile(volumeFile, outputVolumeFileName, outputVolumeFileLabel); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeAtlasResamplingAndSmoothing.h0000664000175000017500000000356111572067322032066 0ustar michaelmichael #ifndef __COMMAND_VOLUME_ATLAS_RESAMPLING_AND_SMOOTHING_H__ #define __COMMAND_VOLUME_ATLAS_RESAMPLING_AND_SMOOTHING_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandVolumeAtlasResamplingAndSmoothing : public CommandBase { public: // constructor CommandVolumeAtlasResamplingAndSmoothing(); // destructor ~CommandVolumeAtlasResamplingAndSmoothing(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_ATLAS_RESAMPLING_AND_SMOOTHING_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeAtlasResamplingAndSmoothing.cxx0000664000175000017500000001207011572067322032434 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "CommandVolumeAtlasResamplingAndSmoothing.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "BrainModelVolumeROIAtlasResamplingAndSmoothing.h" #include "BrainSet.h" #include "StringUtilities.h" #include "FileUtilities.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeAtlasResamplingAndSmoothing::CommandVolumeAtlasResamplingAndSmoothing() : CommandBase("-volume-atlas-resampling-and-smoothing", "PARCEL CONSTRAINED ATLAS RESAMPLING AND SMOOTHING") { } /** * destructor. */ CommandVolumeAtlasResamplingAndSmoothing::~CommandVolumeAtlasResamplingAndSmoothing() { } /** * get the script builder parameters. */ void CommandVolumeAtlasResamplingAndSmoothing::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Volume File", FileFilters::getVolumeFunctionalFileFilter()); paramsOut.addFile("Input Volume ROI File", FileFilters::getVolumeSegmentationFileFilter()); paramsOut.addFile("Output Volume File", FileFilters::getVolumeFunctionalFileFilter()); paramsOut.addFile("Input Atlas Volume ROI File", FileFilters::getVolumeFunctionalFileFilter()); paramsOut.addFloat("Sigma", 1.0, 0.0); } /** * get full help information. */ QString CommandVolumeAtlasResamplingAndSmoothing::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Perform 3D Gaussian weighted smoothing of kernel within\n" + indent9 + "the given ROI. The smoothing only considers voxels inside the\n" + indent9 + "ROI and the output will only contain these voxels. The input\n" + indent9 + "volume and input ROI must have the same image matrix and\n" + indent9 + "dimensions. The command will accept either 3D or 4D inputs and\n" + indent9 + "will do the smoothing frame by frame. It will output either 3D\n" + indent9 + "or 4D outputs.\n" + indent9 + "\n" + indent9 + " values-volume the input file\n" + indent9 + "\n" + indent9 + " region-volume the individual roi\n" + indent9 + "\n" + indent9 + " atlas-volume-region the atlas roi\n" + indent9 + "\n" + indent9 + " output-volume the output file\n" + indent9 + "\n" + indent9 + " sigma sigma for the weighting function for\n" + indent9 + " weighted least squares\n" + indent9 + "\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeAtlasResamplingAndSmoothing::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString values = parameters->getNextParameterAsString("Input Volume File"); const QString region = parameters->getNextParameterAsString("Input Region File"); const QString atlasRegion = parameters->getNextParameterAsString("Input Atlas Region File"); const QString output = parameters->getNextParameterAsString("Output Volume File"); const float kernel = parameters->getNextParameterAsFloat("Kernel Size"); BrainSet mybs; VolumeFile valueFile, regionFile, atlasRegionFile;//, outFile; valueFile.readFile(values); regionFile.readFile(region); atlasRegionFile.readFile(atlasRegion); std::vector outFileVec; BrainModelVolumeROIAtlasResamplingAndSmoothing mysmooth(&mybs, &valueFile, ®ionFile, &atlasRegionFile, &outFileVec, kernel); mysmooth.execute(); VolumeFile::writeFile(output, outFileVec[0]->getVolumeType(), outFileVec[0]->getVoxelDataType(), outFileVec); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeAnatomyPeaks.h0000664000175000017500000000347011572067322027060 0ustar michaelmichael #ifndef __COMMAND_VOLUME_ANATOMY_PEAKS_H__ #define __COMMAND_VOLUME_ANATOMY_PEAKS_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for estiimating peaks of an anatomy volume class CommandVolumeAnatomyPeaks : public CommandBase { public: // constructor CommandVolumeAnatomyPeaks(); // destructor ~CommandVolumeAnatomyPeaks(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_ANATOMY_PEAKS_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVolumeAnatomyPeaks.cxx0000664000175000017500000000547611572067322027443 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "CommandVolumeAnatomyPeaks.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "StatisticHistogram.h" #include "VolumeFile.h" /** * constructor. */ CommandVolumeAnatomyPeaks::CommandVolumeAnatomyPeaks() : CommandBase("-volume-anatomy-peaks", "VOLUME ANATOMY PEAKS") { } /** * destructor. */ CommandVolumeAnatomyPeaks::~CommandVolumeAnatomyPeaks() { } /** * get the script builder parameters. */ void CommandVolumeAnatomyPeaks::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Anatomy Volume File", FileFilters::getVolumeAnatomyFileFilter()); } /** * get full help information. */ QString CommandVolumeAnatomyPeaks::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Estimate the peaks in an anatomy volume file.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVolumeAnatomyPeaks::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString anatomyVolumeFileName = parameters->getNextParameterAsString("Anatomy Volume File Name"); // // Read the anatomy volume file // VolumeFile volumeFile; volumeFile.readFile(anatomyVolumeFileName); // // Get the histogram and the estimated peaks // const StatisticHistogram* histo = volumeFile.getHistogram(); histo->printHistogramPeaks(std::cout); delete histo; histo = NULL; } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVersion.h0000664000175000017500000000346711572067322024727 0ustar michaelmichael #ifndef __COMMAND_VERSION_H__ #define __COMMAND_VERSION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandVersion : public CommandBase { public: // constructor CommandVersion(); // destructor ~CommandVersion(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; /// command has no parameters virtual bool commandHasNoParameters() const { return true; } protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VERSION_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVersion.cxx0000664000175000017500000000506711572067322025300 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "CaretVersion.h" #include "CommandVersion.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "vtkVersion.h" /** * constructor. */ CommandVersion::CommandVersion() : CommandBase("-version", "VERSION") { } /** * destructor. */ CommandVersion::~CommandVersion() { } /** * get the script builder parameters. */ void CommandVersion::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); } /** * get full help information. */ QString CommandVersion::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "Display the version of command operations.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVersion::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { std::cout << "Caret Version: " << CaretVersion::getCaretVersionAsString().toAscii().constData() << std::endl; std::cout << "QT Version: " << qVersion() << std::endl; std::cout << "VTK Version: " << vtkVersion::GetVTKVersion() << std::endl; std::cout << "Date Compiled: " << __DATE__ << std::endl; } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVerify.h0000664000175000017500000000351011572067322024533 0ustar michaelmichael #ifndef __COMMAND_VERIFY_H__ #define __COMMAND_VERIFY_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for verifying all commands class CommandVerify : public CommandBase { public: // constructor CommandVerify(); // destructor ~CommandVerify(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; /// command has no parameters virtual bool commandHasNoParameters() const { return true; } protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VERIFY_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandVerify.cxx0000664000175000017500000000725111572067322025114 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "CommandVerify.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandVerify::CommandVerify() : CommandBase("-verify", "VERIFY (development use only)") { } /** * destructor. */ CommandVerify::~CommandVerify() { } /** * get the script builder parameters. */ void CommandVerify::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addBoolean("Anyting", true); } /** * get full help information. */ QString CommandVerify::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "Verify that all commands have switches, descriptions,\n" + indent9 + "help, and script builder parameters set.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandVerify::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { std::vector allCommands; getAllCommandsSortedByDescription(allCommands); bool allOKFlag = true; const int numCommands = static_cast(allCommands.size()); for (int i = 0; i < numCommands; i++) { CommandBase* command = allCommands[i]; //command->setParameters(parameters); const char* className = typeid(*command).name(); QString errorMessage; if (command->getOperationSwitch().isEmpty() || (command->getOperationSwitch() == "-")) { errorMessage += " Missing Operation Switch\n"; } if (command->getShortDescription().isEmpty()) { errorMessage += " Missing Short Description\n"; } if (command->getHelpInformation().isEmpty()) { errorMessage += " Missing Help Information."; } ScriptBuilderParameters params; command->getScriptBuilderParameters(params); if (params.getNumberOfParameters() <= 0) { if (command->commandHasNoParameters() == false) { errorMessage += " Missing script builder parameters"; } } if (errorMessage.isEmpty() == false) { allOKFlag = false; std::cout << className << std::endl << errorMessage.toAscii().constData() << std::endl; } } if (allOKFlag) { std::cout << "All " << numCommands << " Commands Verified Successfully." << std::endl; } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandTransformationMatrixCreate.h0000664000175000017500000000354211572067322030613 0ustar michaelmichael #ifndef __COMMAND_TRANSFORMATION_MATRIX_CREATE_H__ #define __COMMAND_TRANSFORMATION_MATRIX_CREATE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for creating a transformation matrix class CommandTransformationMatrixCreate : public CommandBase { public: // constructor CommandTransformationMatrixCreate(); // destructor ~CommandTransformationMatrixCreate(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_TRANSFORMATION_MATRIX_CREATE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandTransformationMatrixCreate.cxx0000664000175000017500000001765411572067322031177 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "CommandTransformationMatrixCreate.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "TransformationMatrixFile.h" /** * constructor. */ CommandTransformationMatrixCreate::CommandTransformationMatrixCreate() : CommandBase("-transformation-matrix-create", "TRANSFORMATION MATRIX CREATION") { } /** * destructor. */ CommandTransformationMatrixCreate::~CommandTransformationMatrixCreate() { } /** * get the script builder parameters. */ void CommandTransformationMatrixCreate::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Transformation Matrix File Name", FileFilters::getTransformationMatrixFileFilter()); paramsOut.addFile("Output Transformation Matrix File Name", FileFilters::getTransformationMatrixFileFilter()); paramsOut.addString("Matrix Name"); paramsOut.addVariableListOfParameters("Matrix Options"); } /** * get full help information. */ QString CommandTransformationMatrixCreate::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-matrix-comment comment-text]\n" + indent9 + "[-delete-all-matrices-from-file]\n" + indent9 + "[-identity]\n" + indent9 + "[-inverse]\n" + indent9 + "[-pre-multiply matrix-name]\n" + indent9 + "[-post-multiply matrix-name]\n" + indent9 + "[-rotate X Y Z]\n" + indent9 + "[-scale X Y Z]\n" + indent9 + "[-translate X Y Z]\n" + indent9 + "[-transpose]\n" + indent9 + "\n" + indent9 + "Operations are applied in the order they are specified on the\n" + indent9 + "command line.\n" + indent9 + "\n" + indent9 + "The input transformation matrix file does not need to exist.\n" + indent9 + "If it does exist, new matrices are appended to the file. If\n" + indent9 + "the name of the new matrix is the same as that of an existing\n" + indent9 + "matrix, the existing matrix is replaced.\n" + indent9 + "\n" + indent9 + "Use \"-delete-all-matrices-from-file\" to remove all the \n" + indent9 + "matrices from an existing file.\n" + indent9 + "\n" + indent9 + "If comment-text contains spaces, it must be enclosed in quotes.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandTransformationMatrixCreate::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get required parameters // const QString inputMatrixFileName = parameters->getNextParameterAsString("Input Matrix File Name"); const QString outputMatrixFileName = parameters->getNextParameterAsString("Output Matrix File Name"); const QString matrixName = parameters->getNextParameterAsString("Matrix Name"); // // Create the transformation matrix file and read it if it exists // TransformationMatrixFile tmf; if (inputMatrixFileName.isEmpty() == false) { if (QFile::exists(inputMatrixFileName)) { tmf.readFile(inputMatrixFileName); } } TransformationMatrix matrix; matrix.setMatrixName(matrixName); // // process optional parameters // while (parameters->getParametersAvailable()) { // // Get the next parameter // const QString paramName = parameters->getNextParameterAsString("Create Matrix Parameter"); if (paramName == "-delete-all-matrices-from-file") { tmf.clear(); } else if (paramName == "-matrix-comment") { matrix.setMatrixComment(parameters->getNextParameterAsString("Matrix Comment Text")); } else if (paramName == "-identity") { matrix.identity(); } else if (paramName == "-inverse") { matrix.inverse(); } else if (paramName == "-pre-multiply") { const QString multiplyMatrixName(parameters->getNextParameterAsString("Multiply Matrix Name")); const TransformationMatrix* tm = tmf.getTransformationMatrixWithName(multiplyMatrixName); if (tm == NULL) { throw CommandException("Unable to find matrix " "with name \"" + multiplyMatrixName + "\" for pre-multiplication"); } matrix.preMultiply(*tm); } else if (paramName == "-post-multiply") { const QString multiplyMatrixName(parameters->getNextParameterAsString("Multiply Matrix Name")); const TransformationMatrix* tm = tmf.getTransformationMatrixWithName(multiplyMatrixName); if (tm == NULL) { throw CommandException("Unable to find matrix " "with name \"" + multiplyMatrixName + "\" for post-multiplication"); } matrix.postMultiply(*tm); } else if (paramName == "-rotate") { const float x = parameters->getNextParameterAsFloat("Rotation X"); const float y = parameters->getNextParameterAsFloat("Rotation Y"); const float z = parameters->getNextParameterAsFloat("Rotation Z"); matrix.rotateZ(z); matrix.rotateX(x); matrix.rotateY(y); } else if (paramName == "-scale") { const float x = parameters->getNextParameterAsFloat("Scale X"); const float y = parameters->getNextParameterAsFloat("Scale Y"); const float z = parameters->getNextParameterAsFloat("Scale Z"); matrix.scale(x, y, z); } else if (paramName == "-translate") { const float x = parameters->getNextParameterAsFloat("Translation X"); const float y = parameters->getNextParameterAsFloat("Translation Y"); const float z = parameters->getNextParameterAsFloat("Translation Z"); matrix.translate(x, y, z); } else if (paramName == "-transpose") { matrix.transpose(); } else { throw CommandException("Unrecognized parameter: " + paramName); } } // // Does the matrix exist // TransformationMatrix* oldMatrix = tmf.getTransformationMatrixWithName(matrixName); if (oldMatrix != NULL) { // // Replace old matrix // *oldMatrix = matrix; } else { // // Add new matrix // tmf.addTransformationMatrix(matrix); } // // Write the transformation matrix file // tmf.writeFile(outputMatrixFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSystemFileDelete.h0000664000175000017500000000342411572067322026502 0ustar michaelmichael #ifndef __COMMAND_SYSTEM_FILE_DELETE_H__ #define __COMMAND_SYSTEM_FILE_DELETE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for deleting files class CommandSystemFileDelete : public CommandBase { public: // constructor CommandSystemFileDelete(); // destructor ~CommandSystemFileDelete(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SYSTEM_FILE_DELETE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSystemFileDelete.cxx0000664000175000017500000000610511572067322027054 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "CommandSystemFileDelete.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandSystemFileDelete::CommandSystemFileDelete() : CommandBase("-system-file-delete", "SYSTEM FILE DELETE") { } /** * destructor. */ CommandSystemFileDelete::~CommandSystemFileDelete() { } /** * get the script builder parameters. */ void CommandSystemFileDelete::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Delete File", FileFilters::getAnyFileFilter()); paramsOut.addVariableListOfParameters("Additional Files to Delete"); } /** * get full help information. */ QString CommandSystemFileDelete::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " \n" + indent9 + "[names-of-additional-files-to-delete]\n" + indent9 + "\n" + indent9 + "Delete files from disk. Wildcards not allowed.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSystemFileDelete::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { while (parameters->getParametersAvailable()) { const QString name = parameters->getNextParameterAsString("File Name"); if (QFile::exists(name)) { if (QFile::remove(name) == false) { throw CommandException("Unable to delete \"" + name + "\"."); } } else { std::cout << "WARNING " << getShortDescription().toAscii().constData() << " \"" << name.toAscii().constData() << "\" does not exist." << std::endl; } } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSystemFileCopy.h0000664000175000017500000000341011572067322026205 0ustar michaelmichael #ifndef __COMMAND_SYSTEM_FILE_COPY_H__ #define __COMMAND_SYSTEM_FILE_COPY_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for copying a file class CommandSystemFileCopy : public CommandBase { public: // constructor CommandSystemFileCopy(); // destructor ~CommandSystemFileCopy(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SYSTEM_FILE_COPY_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSystemFileCopy.cxx0000664000175000017500000000663611572067322026575 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include "CommandSystemFileCopy.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandSystemFileCopy::CommandSystemFileCopy() : CommandBase("-system-file-copy", "SYSTEM FILE COPY") { } /** * destructor. */ CommandSystemFileCopy::~CommandSystemFileCopy() { } /** * get the script builder parameters. */ void CommandSystemFileCopy::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Source File Name", FileFilters::getAnyFileFilter()); paramsOut.addFile("Target File Name", FileFilters::getAnyFileFilter()); } /** * get full help information. */ QString CommandSystemFileCopy::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Copy a file.\n" + indent9 + "\n" + indent9 + "If the target file name is an existing file, the file will\n" + indent9 + "not be copied and the command will fail. If the target file\n" + indent9 + "name is a directory, the source file name is copied into the\n" + indent9 + "directory (as long as a file with that name in the directory\n" + indent9 + "does not exist).\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSystemFileCopy::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString sourceFileName = parameters->getNextParameterAsString("Source File Name"); QString targetFileName = parameters->getNextParameterAsString("Target File Name"); // // Is target a directory? // QFileInfo targetFileInfo(targetFileName); if (targetFileInfo.isDir()) { targetFileName += (QDir::separator() + sourceFileName); } if (QFile::exists(targetFileName)) { throw CommandException("Target file exists, will not overwrite it."); } if (QFile::copy(sourceFileName, targetFileName) == false) { throw CommandException("Copy failed."); } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSystemCommandExecute.h0000664000175000017500000000427411572067322027405 0ustar michaelmichael #ifndef __COMMAND_SYSTEM_COMMAND_EXECUTE_H__ #define __COMMAND_SYSTEM_COMMAND_EXECUTE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "CommandBase.h" /// class for class CommandSystemCommandExecute : public CommandBase { public: // constructor CommandSystemCommandExecute(); // destructor ~CommandSystemCommandExecute(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; /// get the system command QString getSystemCommandName() const { return systemCommandName; } ///get the command parameters QStringList getSystemCommandParameters() const { return systemCommandParameters; } protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); /// the system command QString systemCommandName; /// the command parameters QStringList systemCommandParameters; }; #endif // __COMMAND_SYSTEM_COMMAND_EXECUTE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSystemCommandExecute.cxx0000664000175000017500000001200411572067322027746 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include "CommandSystemCommandExecute.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandSystemCommandExecute::CommandSystemCommandExecute() : CommandBase("-system-command-execute", "SYSTEM COMMAND EXECUTE") { } /** * destructor. */ CommandSystemCommandExecute::~CommandSystemCommandExecute() { } /** * get the script builder parameters. */ void CommandSystemCommandExecute::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addString("System Command"); paramsOut.addVariableListOfParameters("Parameters"); } /** * get full help information. */ QString CommandSystemCommandExecute::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Execute a system command such as another program.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSystemCommandExecute::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { systemCommandName = parameters->getNextParameterAsString("System Command Name"); systemCommandParameters.clear(); while (parameters->getParametersAvailable()) { systemCommandParameters += parameters->getNextParameterAsString("System Command Parameters"); } // // Use the system() command. The reason is that when the script executor is run // it is already in a QProcess and this would also run in another QProcess and // running a QProcess in another QProcess does not seem to work. // #define USE_SYSTEM_COMMAND #ifdef USE_SYSTEM_COMMAND const QString cmdText(systemCommandName + " " + systemCommandParameters.join(" ")); const int result = std::system(cmdText.toAscii().constData()); if (result != 0) { throw CommandException("Error Code: " + QString::number(result) + " running: " + cmdText); } #else // USE_SYSTEM_COMMAND // // Create a new QProcess and add its arguments // QProcess process(0); // // Start execution of the command // QString errorMessage; const QString cmdText(systemCommandName + " " + systemCommandParameters.join(" ")); process.start(systemCommandName, systemCommandParameters); if (!process.waitForStarted()) { QString msg("Error starting command: "); msg.append(cmdText); errorMessage.append(msg); } // // Wait until the program is complete // if (!process.waitForFinished(100000000)) { QString msg("Error waiting for command to finish: "); msg.append(cmdText); errorMessage.append(msg); } const QString processOutput(process.readAll()); std::cout << processOutput.toAscii().constData() << std::endl; if (process.exitStatus() == QProcess::NormalExit) { if (process.exitCode() != 0) { //std::cout << "Text output: " // << commandsOutputText.toAscii().constData() // << std::endl; errorMessage.append("COMMAND FAILED1: "); errorMessage.append(cmdText); errorMessage.append("\nExit Code " + QString::number(process.exitCode())); errorMessage.append("\nError Message" + process.errorString()); errorMessage.append("\nCommand output: " + processOutput); } } else { errorMessage.append("COMMAND FAILED2: "); errorMessage.append(cmdText); } if (errorMessage.isEmpty() == false) { throw CommandException(errorMessage); } #endif // USE_SYSTEM_COMMAND } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfacesToSegmentationVolumeMask.h0000664000175000017500000000355311572067322031736 0ustar michaelmichael #ifndef __COMMAND_SURFACES_TO_SEGMENTATION_VOLUME_MASK_H__ #define __COMMAND_SURFACES_TO_SEGMENTATION_VOLUME_MASK_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandSurfacesToSegmentationVolumeMask : public CommandBase { public: // constructor CommandSurfacesToSegmentationVolumeMask(); // destructor ~CommandSurfacesToSegmentationVolumeMask(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACES_TO_SEGMENTATION_VOLUME_MASK_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfacesToSegmentationVolumeMask.cxx0000664000175000017500000001656311572067322032316 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainModelSurface.h" #include "BrainModelSurfaceToVolumeConverter.h" #include "BrainSet.h" #include "CommandSurfacesToSegmentationVolumeMask.h" #include "DebugControl.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandSurfacesToSegmentationVolumeMask::CommandSurfacesToSegmentationVolumeMask() : CommandBase("-surfaces-to-segmentation-volume-mask", "SURFACES TO SEGMENTATION VOLUME MASK") { } /** * destructor. */ CommandSurfacesToSegmentationVolumeMask::~CommandSurfacesToSegmentationVolumeMask() { } /** * get the script builder parameters. */ void CommandSurfacesToSegmentationVolumeMask::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Spec File", FileFilters::getSpecFileFilter()); paramsOut.addFile("Output Volume File", FileFilters::getVolumeSegmentationFileFilter()); paramsOut.addVariableListOfParameters("Optional Parameters"); } /** * get full help information. */ QString CommandSurfacesToSegmentationVolumeMask::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-dilate number-of-iterations]\n" + indent9 + "\n" + indent9 + "For each fiducial surface listed in the spec file, convert it\n" + indent9 + "to a segmentation volume and then merge (union) all of these\n" + indent9 + "segmentation volumes into a single volume. Perform the specified\n" + indent9 + "number of dilation iterations on the output volume prior to \n" + indent9 + "saving it.\n" + indent9 + "\n" + indent9 + "The output volume must exist and a volume may be created by this\n" + indent9 + "program using the \"-volume-create-in-stereotaxic-space\" option.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfacesToSegmentationVolumeMask::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the parameters // const QString inputSpecFileName = parameters->getNextParameterAsString("Input Spec File"); const QString outputVolumeFileName = parameters->getNextParameterAsString("Output Volume File"); int dilationIterations = 0; while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("Param"); if (paramName == "dilate") { dilationIterations = parameters->getNextParameterAsInt("Dilation Iterations"); } } // // Save directory // const QString currentDirectoryName = QDir::currentPath(); // // Create a spec file // SpecFile specFile; specFile.readFile(inputSpecFileName); specFile.setAllFileSelections(SpecFile::SPEC_TRUE); // // Read the spec file into a brain set // QString errorMessage; BrainSet brainSet(true); if (brainSet.readSpecFile(specFile, "", errorMessage)) { throw CommandException("ERROR: Reading spec file: " + errorMessage.toAscii()); } // // Reading brain set will change directory to one containing spec file // QDir::setCurrent(currentDirectoryName); // // Read the volume file and clear it // VolumeFile outputVolumeFile; outputVolumeFile.readFile(outputVolumeFileName); int dimensions[3]; outputVolumeFile.getDimensions(dimensions); float spacing[3]; outputVolumeFile.getSpacing(spacing); float origin[3]; outputVolumeFile.getOrigin(origin); // // Loop through the surfaces // std::vector segmentationVolumeFileNames; for (int i = 0; i < brainSet.getNumberOfBrainModels(); i++) { // // See if model is fiducial surface // BrainModelSurface* bms = brainSet.getBrainModelSurface(i); if (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FIDUCIAL) { // // Convert the surface to a segmentation volume // const float surfaceOffset[3] = { 0.0, 0.0, 0.0 }; const float innerBoundary = -1.5; const float outerBoundary = 1.5; const float intersectionStep = 0.5; BrainModelSurfaceToVolumeConverter bmsv(&brainSet, bms, StereotaxicSpace::SPACE_UNKNOWN, surfaceOffset, dimensions, spacing, origin, innerBoundary, outerBoundary, intersectionStep, BrainModelSurfaceToVolumeConverter::CONVERT_TO_SEGMENTATION_VOLUME_USING_NODES); bmsv.execute(); VolumeFile* vf = bmsv.getOutputVolume(); if (vf != NULL) { const QString name("TempSegmentVolume_" + QString::number(i) + SpecFile::getNiftiVolumeFileExtension()); vf->writeFile(name); segmentationVolumeFileNames.push_back(name); brainSet.deleteVolumeFile(vf); } else { throw CommandException("ERROR: Failed to create volume for surface:" + bms->getFileName()); } } } // // Create the mask // VolumeFile::createSegmentationMask(outputVolumeFileName, segmentationVolumeFileNames, dilationIterations); // // If not debug delete temp volumes // if (DebugControl::getDebugOn() == false) { for (unsigned int i = 0; i < segmentationVolumeFileNames.size(); i++) { QFile::remove(segmentationVolumeFileNames[i]); } } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceTransformToStandardView.h0000664000175000017500000000360511572067322031377 0ustar michaelmichael #ifndef __COMMAND_SURFACE_TRANSFORM_TO_STANDARD_VIEW_H__ #define __COMMAND_SURFACE_TRANSFORM_TO_STANDARD_VIEW_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for transforming surface to standard view class CommandSurfaceTransformToStandardView : public CommandBase { public: // constructor CommandSurfaceTransformToStandardView(); // destructor ~CommandSurfaceTransformToStandardView(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_TRANSFORM_TO_STANDARD_VIEW_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceTransformToStandardView.cxx0000664000175000017500000001423011572067322031746 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurface.h" #include "BrainSet.h" #include "CoordinateFile.h" #include "CommandSurfaceTransformToStandardView.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandSurfaceTransformToStandardView::CommandSurfaceTransformToStandardView() : CommandBase("-surface-transform-to-standard-view", "SURFACE TRANSFORM TO STANDARD VIEW") { } /** * destructor. */ CommandSurfaceTransformToStandardView::~CommandSurfaceTransformToStandardView() { } /** * get the script builder parameters. */ void CommandSurfaceTransformToStandardView::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { std::vector values, descriptions; values.push_back("A"); descriptions.push_back("Anterior"); values.push_back("D"); descriptions.push_back("Dorsal"); values.push_back("L"); descriptions.push_back("Lateral"); values.push_back("M"); descriptions.push_back("Medial"); values.push_back("P"); descriptions.push_back("Posterior"); values.push_back("R"); descriptions.push_back("Reset (default view)"); values.push_back("V"); descriptions.push_back("Ventral"); paramsOut.clear(); paramsOut.addFile("Input Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Input Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Output Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addListOfItems("Standard View", values, descriptions); } /** * get full help information. */ QString CommandSurfaceTransformToStandardView::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Transform a surface in a default (dorsal) view to another\n" + indent9 + "view.\n" + indent9 + "\n" + indent9 + " \"standard-view\" is one of these single characters:\n" + indent9 + " A - Anterior\n" + indent9 + " D - Dorsal\n" + indent9 + " L - Lateral\n" + indent9 + " M - Medial\n" + indent9 + " P - Posterior\n" + indent9 + " R - Reset (default view)\n" + indent9 + " V - Ventral\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceTransformToStandardView::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputCoordinateFileName = parameters->getNextParameterAsString("Input Coordinate File Name"); const QString topologyFileName = parameters->getNextParameterAsString("Input Topology File Name"); const QString outputCoordinateFileName = parameters->getNextParameterAsString("Output Coordinate File Name"); const QString surfaceViewString = parameters->getNextParameterAsString("Standard View"); BrainModel::STANDARD_VIEWS surfaceView = BrainModel::VIEW_NONE; if (surfaceViewString == "A") { surfaceView = BrainModel::VIEW_ANTERIOR; } else if (surfaceViewString == "D") { surfaceView = BrainModel::VIEW_DORSAL; } else if (surfaceViewString == "L") { surfaceView = BrainModel::VIEW_LATERAL; } else if (surfaceViewString == "M") { surfaceView = BrainModel::VIEW_MEDIAL; } else if (surfaceViewString == "P") { surfaceView = BrainModel::VIEW_POSTERIOR; } else if (surfaceViewString == "R") { surfaceView = BrainModel::VIEW_RESET; } else if (surfaceViewString == "V") { surfaceView = BrainModel::VIEW_VENTRAL; } else { throw CommandException("invalid standard view: " + surfaceViewString); } // // Create a brain set // BrainSet brainSet(topologyFileName, inputCoordinateFileName, "", true); BrainModelSurface* bms = brainSet.getBrainModelSurface(0); if (bms == NULL) { throw CommandException("unable to find surface."); } const TopologyFile* tf = bms->getTopologyFile(); if (tf == NULL) { throw CommandException("unable to find topology."); } const int numNodes = bms->getNumberOfNodes(); if (numNodes == 0) { throw CommandException("surface contains not nodes."); } if ((bms->getStructure().getType() != Structure::STRUCTURE_TYPE_CORTEX_RIGHT) && (bms->getStructure().getType() != Structure::STRUCTURE_TYPE_CORTEX_LEFT)) { throw CommandException("Structure must be in the header of the coordinate " "file and be either \"left\" or \"right\""); } bms->applyViewToCoordinates(surfaceView); CoordinateFile* cf = bms->getCoordinateFile(); cf->writeFile(outputCoordinateFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceTopologyReport.h0000664000175000017500000000350711572067322027616 0ustar michaelmichael #ifndef __COMMAND_SURFACE_TOPOLOGY_REPORT_H__ #define __COMMAND_SURFACE_TOPOLOGY_REPORT_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for reporting on the surface's topology class CommandSurfaceTopologyReport : public CommandBase { public: // constructor CommandSurfaceTopologyReport(); // destructor ~CommandSurfaceTopologyReport(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_TOPOLOGY_REPORT_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceTopologyReport.cxx0000664000175000017500000001131111572067322030161 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelSurface.h" #include "BrainSet.h" #include "CommandSurfaceTopologyReport.h" #include "CoordinateFile.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "TopologyFile.h" /** * constructor. */ CommandSurfaceTopologyReport::CommandSurfaceTopologyReport() : CommandBase("-surface-topology-report", "SURFACE TOPOLOGY REPORT") { } /** * destructor. */ CommandSurfaceTopologyReport::~CommandSurfaceTopologyReport() { } /** * get the script builder parameters. */ void CommandSurfaceTopologyReport::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Topology File Name", FileFilters::getTopologyGenericFileFilter()); } /** * get full help information. */ QString CommandSurfaceTopologyReport::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Examine and report on the surface's topology.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceTopologyReport::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the parameters // const QString coordinateFileName = parameters->getNextParameterAsString("Input Coordinate File Name"); const QString topologyFileName = parameters->getNextParameterAsString("Input Topology File Name"); // // Make sure that are no more parameters // checkForExcessiveParameters(); // // Create a brain set // BrainSet brainSet(topologyFileName, coordinateFileName, false, true); BrainModelSurface* bms = brainSet.getBrainModelSurface(0); if (bms == NULL) { throw CommandException("unable to find surface."); } const TopologyFile* tf = bms->getTopologyFile(); if (tf == NULL) { throw CommandException("unable to find topology."); } // // Determine if the surface is 2D or 3D // bool twoDimFlag = true; const CoordinateFile* cf = bms->getCoordinateFile(); const int numCoords = cf->getNumberOfCoordinates(); for (int i = 0; i < numCoords; i++) { const float* xyz = cf->getCoordinate(i); if (xyz[2] != 0.0) { twoDimFlag = false; break; } } int numFaces, numVertices, numEdges, eulerCount, numHoles, numObjects; tf->getEulerCount(twoDimFlag, numFaces, numVertices, numEdges, eulerCount, numHoles, numObjects); int correctEulerCount = 2; if (twoDimFlag) { correctEulerCount = 1; } if (eulerCount == correctEulerCount) { std::cout << "Surface is topologically correct." << std::endl; } else { std::cout << "Surface is NOT topologically correct." << std::endl; std::cout << " Euler Count is " << eulerCount << " but should be " << correctEulerCount << std::endl; if (numObjects != 1) { std::cout << " Number of disjoint objects: " << numObjects << std::endl; } if (numHoles > 0) { std::cout << " Number of holes: " << numHoles << std::endl; } } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceTopologyNeighbors.h0000664000175000017500000000346511572067322030266 0ustar michaelmichael #ifndef __COMMAND_SURFACE_TOPOLOGY_NEIGHBORS_H__ #define __COMMAND_SURFACE_TOPOLOGY_NEIGHBORS_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandSurfaceTopologyNeighbors : public CommandBase { public: // constructor CommandSurfaceTopologyNeighbors(); // destructor ~CommandSurfaceTopologyNeighbors(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_TOPOLOGY_NEIGHBORS_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceTopologyNeighbors.cxx0000664000175000017500000001121711572067322030633 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandSurfaceTopologyNeighbors.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "TextFile.h" #include "TopologyFile.h" #include "TopologyHelper.h" /** * constructor. */ CommandSurfaceTopologyNeighbors::CommandSurfaceTopologyNeighbors() : CommandBase("-surface-topology-neighbors", "SURFACE TOPOLOGY NEIGHBORS") { } /** * destructor. */ CommandSurfaceTopologyNeighbors::~CommandSurfaceTopologyNeighbors() { } /** * get the script builder parameters. */ void CommandSurfaceTopologyNeighbors::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.clear(); paramsOut.addFile("Input Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Output Text File Name", FileFilters::getTextFileFilter()); paramsOut.addVariableListOfParameters("Options"); } /** * get full help information. */ QString CommandSurfaceTopologyNeighbors::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-neighbor-depth depth]\n" + indent9 + "\n" + indent9 + "For each node in the input topology file, generate a list\n" + indent9 + "of the node's neighbors. Each line in the output text file\n" + indent9 + "contains the node number followed by the node's neighbors.\n" + indent9 + "\n" + indent9 + "If the \"-neighbor-depth\" parameter is supplied, neighbors\n" + indent9 + "to the desired depth are output. Otherwise, the depth is 1\n" + indent9 + "(the immediate neighbors).\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceTopologyNeighbors::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputTopologyFileName = parameters->getNextParameterAsString("Input Topology File Name"); const QString outputTextFileName = parameters->getNextParameterAsString("Output Text File Name"); int depth = 1; while (parameters->getParametersAvailable()) { QString paramName = parameters->getNextParameterAsString("Surface Neighbors Parameter"); if (paramName == "-neighbor-depth") { depth = parameters->getNextParameterAsInt("Neighbor Depth"); if (depth < 1) { throw CommandException("Depth must be greater than zero."); } } else { throw CommandException("Invalid Parameter: " + paramName); } } // // Read input topology file // TopologyFile topologyFile; topologyFile.readFile(inputTopologyFileName); TextFile outputTextFile; // // Get the topology helper // const TopologyHelper* th = topologyFile.getTopologyHelper(true, true, true); const int numNodes = th->getNumberOfNodes(); const QString blank(" "); for (int i = 0; i < numNodes; i++) { QString nodeLine(QString::number(i)); std::vector neighbors; th->getNodeNeighborsToDepth(i, depth, neighbors); for (unsigned int j = 0; j < neighbors.size(); j++) { nodeLine += (blank + QString::number(neighbors[j])); } outputTextFile.appendLine(nodeLine); } // // Write the neighbors file // outputTextFile.writeFile(outputTextFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceTopologyFixOrientation.h0000664000175000017500000000365711572067322031313 0ustar michaelmichael #ifndef __COMMAND_SURFACE_TOPOLOGY_FIX_ORIENTATION_H__ #define __COMMAND_SURFACE_TOPOLOGY_FIX_ORIENTATION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for fixing the orientation of triangles so that /// they are consistent and the normals point out of the /// surface. class CommandSurfaceTopologyFixOrientation : public CommandBase { public: // constructor CommandSurfaceTopologyFixOrientation(); // destructor ~CommandSurfaceTopologyFixOrientation(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_TOPOLOGY_FIX_ORIENTATION_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceTopologyFixOrientation.cxx0000664000175000017500000001025211572067322031653 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelSurface.h" #include "BrainSet.h" #include "CommandSurfaceTopologyFixOrientation.h" #include "CoordinateFile.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "TopologyFile.h" /** * constructor. */ CommandSurfaceTopologyFixOrientation::CommandSurfaceTopologyFixOrientation() : CommandBase("-surface-topology-fix-orientation", "SURFACE TOPOLOGY FIX ORIENTATION") { } /** * destructor. */ CommandSurfaceTopologyFixOrientation::~CommandSurfaceTopologyFixOrientation() { } /** * get the script builder parameters. */ void CommandSurfaceTopologyFixOrientation::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Input Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Output Topology File Name", FileFilters::getTopologyGenericFileFilter()); } /** * get full help information. */ QString CommandSurfaceTopologyFixOrientation::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Fix surface topology by consistently ordering the.\n" + indent9 + "vertices in the triangles so that the node normal\n" + indent9 + "vectors point out of the surface.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceTopologyFixOrientation::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the parameters // const QString coordinateFileName = parameters->getNextParameterAsString("Input Coordinate File Name"); const QString inputTopologyFileName = parameters->getNextParameterAsString("Input Topology File Name"); const QString outputTopologyFileName = parameters->getNextParameterAsString("Output Topology File Name"); // // Make sure that are no more parameters // checkForExcessiveParameters(); // // Create a brain set // BrainSet brainSet(inputTopologyFileName, coordinateFileName, false, true); BrainModelSurface* bms = brainSet.getBrainModelSurface(0); if (bms == NULL) { throw CommandException("unable to find surface."); } /* * Orient the nodes in the triangles consistently * so that they point out of the surface. */ bms->orientTilesConsistently(); bms->orientNormalsOut(); TopologyFile* tf = bms->getTopologyFile(); if (tf == NULL) { throw CommandException("unable to find topology."); } /* * Write the topology file. */ tf->writeFile(outputTopologyFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceTopologyDisconnectNodes.h0000664000175000017500000000356011572067322031424 0ustar michaelmichael #ifndef __COMMAND_SURFACE_TOPOLOGY_DISCONNECT_NODES_H__ #define __COMMAND_SURFACE_TOPOLOGY_DISCONNECT_NODES_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for disconnecting nodes class CommandSurfaceTopologyDisconnectNodes : public CommandBase { public: // constructor CommandSurfaceTopologyDisconnectNodes(); // destructor ~CommandSurfaceTopologyDisconnectNodes(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_TOPOLOGY_DISCONNECT_NODES_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceTopologyDisconnectNodes.cxx0000664000175000017500000000717611572067322032006 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandSurfaceTopologyDisconnectNodes.h" #include "FileFilters.h" #include "NodeRegionOfInterestFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "TopologyFile.h" /** * constructor. */ CommandSurfaceTopologyDisconnectNodes::CommandSurfaceTopologyDisconnectNodes() : CommandBase("-surface-topology-disconnect-nodes", "SURFACE TOPOLOGY DISCONNECT NODES") { } /** * destructor. */ CommandSurfaceTopologyDisconnectNodes::~CommandSurfaceTopologyDisconnectNodes() { } /** * get the script builder parameters. */ void CommandSurfaceTopologyDisconnectNodes::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Output Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Region of Interest File Name", FileFilters::getRegionOfInterestFileFilter()); } /** * get full help information. */ QString CommandSurfaceTopologyDisconnectNodes::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Disconnect all nodes that are in the region of interest.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceTopologyDisconnectNodes::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputTopologyFileName = parameters->getNextParameterAsString("Input Topology File Name"); const QString outputTopologyFileName = parameters->getNextParameterAsString("Output Topology File Name"); const QString regionOfInterestFileName = parameters->getNextParameterAsString("Region of Interest File Name"); checkForExcessiveParameters(); // // Read input topology file // TopologyFile topologyFile; topologyFile.readFile(inputTopologyFileName); // // Read the region of interest file // NodeRegionOfInterestFile roiFile; roiFile.readFile(regionOfInterestFileName); // // Disconnec nodes // topologyFile.disconnectNodesInRegionOfInterest(roiFile); // // Write the topology file // topologyFile.writeFile(outputTopologyFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceToVolume.h0000664000175000017500000000344011572067322026354 0ustar michaelmichael #ifndef __COMMAND_SURFACE_TO_VOLUME_H__ #define __COMMAND_SURFACE_TO_VOLUME_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for converting a surface to a volume class CommandSurfaceToVolume : public CommandBase { public: // constructor CommandSurfaceToVolume(); // destructor ~CommandSurfaceToVolume(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_TO_VOLUME_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceToVolume.cxx0000664000175000017500000002323311572067322026731 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurface.h" #include "BrainModelSurfaceToVolumeConverter.h" #include "BrainSet.h" #include "CommandSurfaceToVolume.h" #include "FileFilters.h" #include "MetricFile.h" #include "PaintFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SpecFile.h" #include "SurfaceShapeFile.h" #include "VolumeFile.h" /** * constructor. */ CommandSurfaceToVolume::CommandSurfaceToVolume() : CommandBase("-surface-to-volume", "SURFACE TO VOLUME") { } /** * destructor. */ CommandSurfaceToVolume::~CommandSurfaceToVolume() { } /** * get the script builder parameters. */ void CommandSurfaceToVolume::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Coordinate File", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Topology File", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Metric/Paint/Shape File", FileFilters::getAnyFileFilter()); paramsOut.addString("Metric/Paint/Shape Column"); paramsOut.addFile("Output Volume File", FileFilters::getVolumeGenericFileFilter()); paramsOut.addVariableListOfParameters("Options"); } /** * get full help information. */ QString CommandSurfaceToVolume::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-inner inner-boundary]\n" + indent9 + "[-outer outer-boundary]\n" + indent9 + "[-step intersection-step]\n" + indent9 + "\n" + indent9 + "Intersect a surface with a volume and assign the specified\n" + indent9 + "column's data of the metric, paint, or shape file to the\n" + indent9 + "volume.\n" + indent9 + "\n" + indent9 + "The output volume file must exist and it must be in the \n" + indent9 + "same stereotaxic space as the surface. A volume file may\n" + indent9 + "be created by using the \"-volume-create\" or \n" + indent9 + "\"-volume-create-in-stereotaxic-space\" commands.\n" + indent9 + "\n" + indent9 + "The default inner boundary, outer boundar, and step size\n" + indent9 + "are -1.5, 1.5, and 0.5 respectively.\n" + indent9 + "\n" + indent9 + "The metric, paint, or shape file column is either the \n" + indent9 + "number of the column, which starts at one, or the name of\n" + indent9 + "the column. If a name contains spaces, it must be \n" + indent9 + "enclosed in double quotes. Name has priority over number.\n" + indent9 + "\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceToVolume::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Required parameters // const QString coordinateFileName = parameters->getNextParameterAsString("Coordinate File Name"); const QString topologyFileName = parameters->getNextParameterAsString("Topology File Name"); const QString nodeAttributeFileName = parameters->getNextParameterAsString("Metric/Paint/Shape File Name"); const QString nodeAttributeColumnIdentifier = parameters->getNextParameterAsString("Metric/Paint/Shape File Column"); QString outputVolumeFileName = parameters->getNextParameterAsString("Output Volume File Name and Label"); QString outputVolumeFileLabel; splitOutputVolumeNameIntoNameAndLabel(outputVolumeFileName, outputVolumeFileLabel); // // Optional parameters // float innerBoundary = -1.5; float outerBoundary = 1.5; float intersectionStep = 0.5; while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("Surface to Volume Options"); if (paramName == "-inner") { innerBoundary = parameters->getNextParameterAsFloat("Inner Boundary"); } else if (paramName == "-outer") { outerBoundary = parameters->getNextParameterAsFloat("Outer Boundary"); } else if (paramName == "-step") { intersectionStep = parameters->getNextParameterAsFloat("Intersection Step Size"); } else { throw CommandException("Unrecognized option: " + paramName); } } // // Create a spec file // SpecFile specFile; specFile.setAllFileSelections(SpecFile::SPEC_FALSE); specFile.addToSpecFile(SpecFile::getClosedTopoFileTag(), topologyFileName, "", SpecFile::SPEC_FALSE); specFile.addToSpecFile(SpecFile::getFiducialCoordFileTag(), coordinateFileName, "", SpecFile::SPEC_FALSE); int inputDataFileColumnNumber = -1; BrainModelSurfaceToVolumeConverter::CONVERSION_MODE conversionMode; if (nodeAttributeFileName.endsWith(SpecFile::getMetricFileExtension())) { specFile.addToSpecFile(SpecFile::getMetricFileTag(), nodeAttributeFileName, "", SpecFile::SPEC_FALSE); conversionMode = BrainModelSurfaceToVolumeConverter::CONVERT_TO_ROI_VOLUME_USING_METRIC_INTERPOLATE; MetricFile file; file.readFile(nodeAttributeFileName); inputDataFileColumnNumber = file.getColumnFromNameOrNumber(nodeAttributeColumnIdentifier, false); } else if (nodeAttributeFileName.endsWith(SpecFile::getPaintFileExtension())) { specFile.addToSpecFile(SpecFile::getPaintFileTag(), nodeAttributeFileName, "", SpecFile::SPEC_FALSE); conversionMode = BrainModelSurfaceToVolumeConverter::CONVERT_TO_ROI_VOLUME_USING_PAINT; PaintFile file; file.readFile(nodeAttributeFileName); inputDataFileColumnNumber = file.getColumnFromNameOrNumber(nodeAttributeColumnIdentifier, false); } else if (nodeAttributeFileName.endsWith(SpecFile::getSurfaceShapeFileExtension())) { specFile.addToSpecFile(SpecFile::getSurfaceShapeFileTag(), nodeAttributeFileName, "", SpecFile::SPEC_FALSE); conversionMode = BrainModelSurfaceToVolumeConverter::CONVERT_TO_ROI_VOLUME_USING_SURFACE_SHAPE; SurfaceShapeFile file; file.readFile(nodeAttributeFileName); inputDataFileColumnNumber = file.getColumnFromNameOrNumber(nodeAttributeColumnIdentifier, false); } else { throw CommandException("Metric/Paint/Shape file extension not valid."); } // // Read the spec file into a brain set // QString errorMessage; BrainSet brainSet(true); if (brainSet.readSpecFile(specFile, "", errorMessage)) { throw CommandException("ERROR: Reading spec file: " + errorMessage); } if (errorMessage.length() > 0) { throw CommandException("ERROR: Reading spec file: " + errorMessage); } // // Get the surface // BrainModelSurface* bms = brainSet.getBrainModelSurface(0); if (bms == NULL) { throw CommandException("Unable to find surface, check file names."); } // // Read the volume file // VolumeFile outputVolumeFile; outputVolumeFile.readFile(outputVolumeFileName); int dimensions[3]; outputVolumeFile.getDimensions(dimensions); float spacing[3]; outputVolumeFile.getSpacing(spacing); float origin[3]; outputVolumeFile.getOrigin(origin); // // Convert the surface to a segmentation volume // const float surfaceOffset[3] = { 0.0, 0.0, 0.0 }; BrainModelSurfaceToVolumeConverter bmsv(&brainSet, bms, StereotaxicSpace::SPACE_UNKNOWN, surfaceOffset, dimensions, spacing, origin, innerBoundary, outerBoundary, intersectionStep, conversionMode); bmsv.setNodeAttributeColumn(inputDataFileColumnNumber); bmsv.execute(); VolumeFile* vf = bmsv.getOutputVolume(); if (vf != NULL) { writeVolumeFile(*vf, outputVolumeFileName, outputVolumeFileLabel); } else { throw CommandException("Failed to create volume."); } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceToSegmentationVolume.h0000664000175000017500000000357011572067322030736 0ustar michaelmichael #ifndef __COMMAND_SURFACE_TO_SEGMENTATION_VOLUME_H__ #define __COMMAND_SURFACE_TO_SEGMENTATION_VOLUME_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for converting a surface to a segmentation volume class CommandSurfaceToSegmentationVolume : public CommandBase { public: // constructor CommandSurfaceToSegmentationVolume(); // destructor ~CommandSurfaceToSegmentationVolume(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_TO_SEGMENTATION_VOLUME_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceToSegmentationVolume.cxx0000664000175000017500000001266211572067322031313 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurface.h" #include "BrainModelSurfaceToVolumeSegmentationConverter.h" #include "BrainSet.h" #include "CommandSurfaceToSegmentationVolume.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "VolumeFile.h" /** * constructor. */ CommandSurfaceToSegmentationVolume::CommandSurfaceToSegmentationVolume() : CommandBase("-surface-to-segmentation-volume", "SURFACE TO SEGMENTATION VOLUME") { } /** * destructor. */ CommandSurfaceToSegmentationVolume::~CommandSurfaceToSegmentationVolume() { } /** * get the script builder parameters. */ void CommandSurfaceToSegmentationVolume::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Coordinate File", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Topology File", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Output Volume File", FileFilters::getVolumeGenericFileFilter()); } /** * get full help information. */ QString CommandSurfaceToSegmentationVolume::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[structure-name]\n" + indent9 + "\n" + indent9 + "Intersect a surface with a volume and create a segmentation\n" + indent9 + "volume.\n" + indent9 + "\n" + indent9 + "The coordinate file must have its structure set to \n" + indent9 + "one of \"left\" or \"right\" or else the command will\n" + indent9 + "terminate with an error message. The structure may \n" + indent9 + "be specified with the optional \"structure-name\"\n" + indent9 + "parameter.\n" + indent9 + "\n" + indent9 + "The output volume file must exist and it must be in the \n" + indent9 + "same stereotaxic space as the surface. A volume file may\n" + indent9 + "be created by using the \"-volume-create\" command.\n" + indent9 + "\n" + indent9 + "\"structure-name\" is optional and must be one of \n" + indent9 + "\"left\" or \"right\".\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceToSegmentationVolume::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Required parameters // const QString coordinateFileName = parameters->getNextParameterAsString("Coordinate File Name"); const QString topologyFileName = parameters->getNextParameterAsString("Topology File Name"); QString outputVolumeFileName = parameters->getNextParameterAsString("Output Volume File Name and Label"); QString outputVolumeFileLabel; splitOutputVolumeNameIntoNameAndLabel(outputVolumeFileName, outputVolumeFileLabel); QString structureName = ""; if (parameters->getParametersAvailable()) { structureName = parameters->getNextParameterAsString("Structure Name").toLower(); if ((structureName != "left") && (structureName != "right")) { throw CommandException("\"structure-name\" must be on of \"left\" or \"right\""); } } // // Read the volume file // VolumeFile outputVolumeFile; outputVolumeFile.readFile(outputVolumeFileName); // // Create a brain set from coord and topo // BrainSet brain(topologyFileName, coordinateFileName); BrainModelSurface* bms = brain.getBrainModelSurface(0); if (bms == NULL) { throw CommandException("Unable to find surface after reading files."); } if (structureName.isEmpty() == false) { bms->setStructure(Structure::convertStringToType(structureName)); } // // Create the segmentation volume // BrainModelSurfaceToVolumeSegmentationConverter bmssc(&brain, bms, &outputVolumeFile, false, false); bmssc.execute(); writeVolumeFile(outputVolumeFile, outputVolumeFileName, outputVolumeFileLabel); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceToCerebralHull.h0000664000175000017500000000352011572067322027450 0ustar michaelmichael #ifndef __COMMAND_SURFACE_TO_CEREBRAL_HULL_H__ #define __COMMAND_SURFACE_TO_CEREBRAL_HULL_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for generating a cerebral hull from a surface class CommandSurfaceToCerebralHull : public CommandBase { public: // constructor CommandSurfaceToCerebralHull(); // destructor ~CommandSurfaceToCerebralHull(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_TO_CEREBRAL_HULL_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceToCerebralHull.cxx0000664000175000017500000001723211572067322030030 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurface.h" #include "BrainModelSurfaceToVolumeSegmentationConverter.h" #include "BrainSet.h" #include "CommandSurfaceToCerebralHull.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "vtkPolyDataWriter.h" /** * constructor. */ CommandSurfaceToCerebralHull::CommandSurfaceToCerebralHull() : CommandBase("-surface-to-cerebral-hull", "SURFACE TO CEREBRAL HULL") { } /** * destructor. */ CommandSurfaceToCerebralHull::~CommandSurfaceToCerebralHull() { } /** * get the script builder parameters. */ void CommandSurfaceToCerebralHull::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Fiducial Coordinate File Name", FileFilters::getCoordinateFiducialFileFilter()); paramsOut.addFile("Closed Topology File Name", FileFilters::getTopologyClosedFileFilter()); paramsOut.addFile("Input Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Output Segmentation Volume File Name", FileFilters::getVolumeSegmentationFileFilter()); paramsOut.addFile("Output Hull Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Output Hull Surface VTK File Name", FileFilters::getVtkSurfaceFileFilter()); } /** * get full help information. */ QString CommandSurfaceToCerebralHull::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Generate a cerebral hull surface which is typically used\n" + indent9 + "for generating sulcal depth.\n" + indent9 + "\n" + indent9 + "Note: The \"input-volume-file-name\" must exist and be in\n" + indent9 + "the same stereotaxic space as the surface. The input\n" + indent9 + "volume is only used to get the stereotaxic space information \n" + indent9 + "and its data contents are ignored. If needed a volume can\n" + indent9 + "be created using this program with the command \n" + indent9 + "\"-volume-create\".\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceToCerebralHull::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get required parameters // const QString fiducialCoordinateFileName = parameters->getNextParameterAsString("Fiducial Coordinate File Name"); const QString closedTopologyFileName = parameters->getNextParameterAsString("Closed Topology File Name"); const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Volume File Name"); QString outputSegmentationVolumeFileName, outputSegmentationVolumeFileLabel; parameters->getNextParameterAsVolumeFileNameAndLabel("Output Segmentation Volume File Name and Label", outputSegmentationVolumeFileName, outputSegmentationVolumeFileLabel); QString outputHullVolumeFileName, outputHullVolumeFileLabel; parameters->getNextParameterAsVolumeFileNameAndLabel("Output Hull Volume File Name and Label", outputHullVolumeFileName, outputHullVolumeFileLabel); const QString outputCerebralHullVtkFileName = parameters->getNextParameterAsString("Output Cerebral Hull VTK File Name"); checkForExcessiveParameters(); // // Create a brain set // BrainSet brainSet(closedTopologyFileName, fiducialCoordinateFileName, "", true); BrainModelSurface* bms = brainSet.getBrainModelSurface(0); if (bms == NULL) { throw CommandException("Unable to find surface."); } const TopologyFile* tf = bms->getTopologyFile(); if (tf == NULL) { throw CommandException("Unable to find topology."); } const int numNodes = bms->getNumberOfNodes(); if (numNodes == 0) { throw CommandException("Surface contains no nodes."); } // // Read the volume file // VolumeFile volumeFile; volumeFile.readFile(inputVolumeFileName); // Create the segmentation volume // BrainModelSurfaceToVolumeSegmentationConverter bmssc(&brainSet, bms, &volumeFile, false, false); bmssc.execute(); volumeFile.setDescriptiveLabel(outputSegmentationVolumeFileLabel); volumeFile.writeFile(outputSegmentationVolumeFileName); // // Expand around edges with empty slices // VolumeFile segmentVolumeExpanded(volumeFile); int expDim[3]; segmentVolumeExpanded.getDimensions(expDim); const int expSlices = 7; const int resizeCrop[6] = { -expSlices, expDim[0] + expSlices, -expSlices, expDim[1] + expSlices, -expSlices, expDim[2] + expSlices }; segmentVolumeExpanded.resize(resizeCrop); // // Generate the hull VTK file and volume // VolumeFile* hullVolume = NULL; vtkPolyData* hullPolyData = NULL; brainSet.generateCerebralHullVtkFile(&segmentVolumeExpanded, hullVolume, hullPolyData); // // Write the hull volume // hullVolume->setDescriptiveLabel(outputHullVolumeFileLabel); hullVolume->writeFile(outputHullVolumeFileName); delete hullVolume; // // Write the Hull VTK file // vtkPolyDataWriter* writer = vtkPolyDataWriter::New(); writer->SetInput(hullPolyData); writer->SetHeader("Written by Caret"); writer->SetFileName((char*)outputCerebralHullVtkFileName.toAscii().constData()); writer->Write(); writer->Delete(); hullPolyData->Delete(); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceToCArrays.h0000664000175000017500000000341011572067322026446 0ustar michaelmichael #ifndef __COMMAND_SURFACE_TO_C_ARRAYS_H__ #define __COMMAND_SURFACE_TO_C_ARRAYS_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandSurfaceToCArrays : public CommandBase { public: // constructor CommandSurfaceToCArrays(); // destructor ~CommandSurfaceToCArrays(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_TO_C_ARRAYS_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceToCArrays.cxx0000664000175000017500000000656511572067322027037 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurface.h" #include "BrainSet.h" #include "CommandSurfaceToCArrays.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "TextFile.h" /** * constructor. */ CommandSurfaceToCArrays::CommandSurfaceToCArrays() : CommandBase("-surface-to-c-arrays", "SURFACE CONVERT TO C-LANGUAGE ARRAYS") { } /** * destructor. */ CommandSurfaceToCArrays::~CommandSurfaceToCArrays() { } /** * get the script builder parameters. */ void CommandSurfaceToCArrays::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Coordinate File", FileFilters::getCoordinateUnknownFileFilter()); paramsOut.addFile("Input Topology File", FileFilters::getTopologyUnknownFileFilter()); paramsOut.addString("C-language File"); } /** * get full help information. */ QString CommandSurfaceToCArrays::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Write the coordinates, surface normals, and triangles\n" + indent9 + "that form a surface as C-language arrays.\n" + indent9 + "\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceToCArrays::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString coordFileName = parameters->getNextParameterAsString("Input Coordinate File Name"); const QString topoFileName = parameters->getNextParameterAsString("Input Topology File Name"); const QString cLanguageFileName = parameters->getNextParameterAsString("C-language File Name"); BrainSet bs(topoFileName, coordFileName); BrainModelSurface* bms = bs.getBrainModelSurface(0); if (bms == NULL) { throw CommandException("Problem loading coordinate or topolgy file."); } const QString s = bms->convertToCLanguageArrays(); TextFile tf; tf.setText(s); tf.writeFile(cLanguageFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceSulcalIdentificationProbabilistic.h0000664000175000017500000000362111572067322033407 0ustar michaelmichael #ifndef __COMMAND_SURFACE_SULCAL_IDENTIFICATION_PROBABILISTIC__ #define __COMMAND_SURFACE_SULCAL_IDENTIFICATION_PROBABILISTIC__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandSurfaceSulcalIdentificationProbabilistic : public CommandBase { public: // constructor CommandSurfaceSulcalIdentificationProbabilistic(); // destructor ~CommandSurfaceSulcalIdentificationProbabilistic(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_SULCAL_IDENTIFICATION_PROBABILISTIC__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceSulcalIdentificationProbabilistic.cxx0000664000175000017500000003047711572067322033773 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "AreaColorFile.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceSulcalIdentificationProbabilistic.h" #include "BrainSet.h" #include "CommandSurfaceSulcalIdentificationProbabilistic.h" #include "FileFilters.h" #include "PaintFile.h" #include "ProgramParameters.h" #include "SpecFile.h" #include "SurfaceShapeFile.h" /** * constructor. */ CommandSurfaceSulcalIdentificationProbabilistic::CommandSurfaceSulcalIdentificationProbabilistic() : CommandBase("-surface-sulcal-identification-probabilistic", "SURFACE SULCAL IDENTIFICATION PROBABILISTIC") { } /** * destructor. */ CommandSurfaceSulcalIdentificationProbabilistic::~CommandSurfaceSulcalIdentificationProbabilistic() { } /** * get the script builder parameters. */ void CommandSurfaceSulcalIdentificationProbabilistic::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Fiducial Coord File Name", FileFilters::getCoordinateFiducialFileFilter()); paramsOut.addFile("Input Inflated Coord File Name", FileFilters::getCoordinateInflatedFileFilter()); paramsOut.addFile("Input Very Inflated Coord File Name", FileFilters::getCoordinateVeryInflatedFileFilter()); paramsOut.addFile("Input Closed Topology File Name", FileFilters::getTopologyClosedFileFilter()); paramsOut.addFile("Input Paint File Name", FileFilters::getPaintFileFilter()); paramsOut.addFile("Output Paint File Name", FileFilters::getPaintFileFilter()); paramsOut.addFile("Input Area Color File Name", FileFilters::getAreaColorFileFilter()); paramsOut.addFile("Output Area Color File Name", FileFilters::getAreaColorFileFilter()); paramsOut.addString("Input Paint Geography Column"); paramsOut.addFile("Input Surface Shape File Name", FileFilters::getSurfaceShapeFileFilter()); paramsOut.addString("Input Surface Shape Depth Column"); paramsOut.addFile("Probabilistic Sulcus Volume list", "*.csv"); paramsOut.addFloat("Post Central Sulcus Offset", 25.0); paramsOut.addFloat("Post Central Sulcus Std Dev Squared", 100.0); paramsOut.addFloat("Post Central Sulcus Split", 5.0); } /** * get full help information. */ QString CommandSurfaceSulcalIdentificationProbabilistic::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + "\n" + indent9 + "Identify sulci on a surface by mapping a probabilistic volume. \n" + indent9 + "\n" + indent9 + "Note: Paint and Surface Shape file column numbers start at one. \n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceSulcalIdentificationProbabilistic::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the parameters from those passed to base class // const QString fiducialCoordFileName = parameters->getNextParameterAsString("Input Fiducial Coord File Name"); const QString inflatedCoordFileName = parameters->getNextParameterAsString("Input Inflated Coord File Name"); const QString veryInflatedCoordFileName = parameters->getNextParameterAsString("Input Very Inflated Coord File Name"); const QString inputTopoFileName = parameters->getNextParameterAsString("Input Closed Topology File Name"); const QString paintFileName = parameters->getNextParameterAsString("Input Paint File Name"); const QString outputPaintFileName = parameters->getNextParameterAsString("Output Paint File Name"); const QString paintFileGeographyColumnNameOrNumber = parameters->getNextParameterAsString("Paint File Geography Column Name or Number"); const QString inputAreaColorFileName = parameters->getNextParameterAsString("Input Area Color File Name"); const QString outputAreaColorFileName = parameters->getNextParameterAsString("Output Area Color File Name"); const QString surfaceShapeFileName = parameters->getNextParameterAsString("Surface Shape File Name"); const QString surfaceShapeFileDepthColumnNameOrNumber = parameters->getNextParameterAsString("Surface Shape File Depth Column Name or Number"); const QString probabilisticSulcusVolumeListFileName = parameters->getNextParameterAsString("Probabilistic Sulcus/Volume List File (CSV)"); const float postCentralSulcusOffset = parameters->getNextParameterAsFloat("Post Central Sulcus Offset"); const float postCentralSulcusStdDevSquared = parameters->getNextParameterAsFloat("Post Central Sulcus Std Dev Squared"); const float postCentralSulcusSplit = parameters->getNextParameterAsFloat("Post Central Sulcus Split"); // // Make sure that are no more parameters // checkForExcessiveParameters(); // // Create a spec file // SpecFile specFile; specFile.setAllFileSelections(SpecFile::SPEC_FALSE); specFile.addToSpecFile(SpecFile::getFiducialCoordFileTag(), fiducialCoordFileName, "", SpecFile::SPEC_FALSE); specFile.addToSpecFile(SpecFile::getInflatedCoordFileTag(), inflatedCoordFileName, "", SpecFile::SPEC_FALSE); specFile.addToSpecFile(SpecFile::getVeryInflatedCoordFileTag(), veryInflatedCoordFileName, "", SpecFile::SPEC_FALSE); specFile.addToSpecFile(SpecFile::getClosedTopoFileTag(), inputTopoFileName, "", SpecFile::SPEC_FALSE); specFile.addToSpecFile(SpecFile::getPaintFileTag(), paintFileName, "", SpecFile::SPEC_FALSE); if (inputAreaColorFileName.isEmpty() == false) { if (QFile::exists(inputAreaColorFileName)) { specFile.addToSpecFile(SpecFile::getAreaColorFileTag(), inputAreaColorFileName, "", SpecFile::SPEC_FALSE); } } specFile.addToSpecFile(SpecFile::getSurfaceShapeFileTag(), surfaceShapeFileName, "", SpecFile::SPEC_FALSE); // // Read the spec file into a brain set // QString errorMessage; BrainSet brainSet(true); if (brainSet.readSpecFile(specFile, "temp", errorMessage)) { const QString msg("ERROR: Reading spec file data files: \n" + errorMessage); throw CommandException(msg); } // // Find the fiducial and very inflated surfaces // BrainModelSurface* fiducialSurface = NULL; BrainModelSurface* inflatedSurface = NULL; BrainModelSurface* veryInflatedSurface = NULL; for (int i = 0; i < brainSet.getNumberOfBrainModels(); i++) { BrainModelSurface* bms = brainSet.getBrainModelSurface(i); if (bms != NULL) { if (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FIDUCIAL) { fiducialSurface = bms; } else if (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_INFLATED) { inflatedSurface = bms; } else if (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_VERY_INFLATED) { veryInflatedSurface = bms; } } } if (fiducialSurface == NULL) { throw CommandException("Unable to find fiducial surface."); } if (veryInflatedSurface == NULL) { throw CommandException("Unable to find very inflated surface."); } // // Get the paint and shape column numbers // const int paintFileGeographyColumnNumber = brainSet.getPaintFile()->getColumnFromNameOrNumber(paintFileGeographyColumnNameOrNumber, false); const int surfaceShapeFileDepthColumnNumber = brainSet.getSurfaceShapeFile()->getColumnFromNameOrNumber(surfaceShapeFileDepthColumnNameOrNumber, false); // // Identify the sulci // BrainModelSurfaceSulcalIdentificationProbabilistic bmssi(&brainSet, fiducialSurface, inflatedSurface, veryInflatedSurface, brainSet.getPaintFile(), paintFileGeographyColumnNumber, brainSet.getSurfaceShapeFile(), surfaceShapeFileDepthColumnNumber, probabilisticSulcusVolumeListFileName, postCentralSulcusOffset, postCentralSulcusStdDevSquared, postCentralSulcusSplit); try { bmssi.execute(); if (bmssi.getOutputPaintFile() == NULL) { throw CommandException("output paint file with Identified sulci is NULL."); } try { PaintFile outputPaintFile(*bmssi.getOutputPaintFile()); outputPaintFile.writeFile(outputPaintFileName); } catch (FileException& e) { const QString msg("identifying sulci writing output paint file: " + e.whatQString()); throw CommandException(msg); } if (outputAreaColorFileName.isEmpty() == false) { const AreaColorFile* acf = bmssi.getOutputAreaColorFile(); if (acf != NULL) { brainSet.getAreaColorFile()->append(*acf); try { brainSet.getAreaColorFile()->writeFile(outputAreaColorFileName); } catch (FileException&) { std::cout << "WARNING: Unable to write " << outputAreaColorFileName.toAscii().constData() << std::endl; } } } } catch (BrainModelAlgorithmException& e) { throw CommandException("identifying sulci: " + e.whatQString()); } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceSulcalDepth.h0000664000175000017500000000405011572067322027010 0ustar michaelmichael #ifndef __COMMAND_SURFACE_SULCAL_DEPTH_H__ #define __COMMAND_SURFACE_SULCAL_DEPTH_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for surface sulcal depth class CommandSurfaceSulcalDepth : public CommandBase { public: // constructor CommandSurfaceSulcalDepth(); // destructor ~CommandSurfaceSulcalDepth(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; /// default name for depth column static QString getDefaultDepthColumnName() { return "Depth"; } /// default name for smoothed depth column static QString getDefaultSmoothedDepthColumnName() { return "Smoothed Depth"; } protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_SULCAL_DEPTH_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceSulcalDepth.cxx0000664000175000017500000002064611572067322027374 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurface.h" #include "BrainModelSurfaceSulcalDepthWithNormals.h" #include "BrainSet.h" #include "CommandSurfaceSulcalDepth.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SurfaceShapeFile.h" /** * constructor. */ CommandSurfaceSulcalDepth::CommandSurfaceSulcalDepth() : CommandBase("-surface-sulcal-depth", "SURFACE SULCAL DEPTH") { } /** * destructor. */ CommandSurfaceSulcalDepth::~CommandSurfaceSulcalDepth() { } /** * get the script builder parameters. */ void CommandSurfaceSulcalDepth::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Fiducial Coordinate File", FileFilters::getCoordinateFiducialFileFilter()); paramsOut.addFile("Closed Topology File", FileFilters::getTopologyClosedFileFilter()); paramsOut.addFile("Hull VTK File", FileFilters::getTopologyClosedFileFilter()); paramsOut.addFile("Input Surface Shape File", FileFilters::getTopologyClosedFileFilter()); paramsOut.addFile("Output Surface Shape File", FileFilters::getTopologyClosedFileFilter()); paramsOut.addFile("Output Hull Coordinate File", FileFilters::getTopologyClosedFileFilter()); paramsOut.addVariableListOfParameters("Surface Sulcal Depth Options"); } /** * get full help information. */ QString CommandSurfaceSulcalDepth::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-depth-column-name name]\n" + indent9 + "[-smoothed-depth-column-name name]\n" + indent9 + "[-no-depth]\n" + indent9 + "[-no-smoothed-depth]\n" + indent9 + "\n" + indent9 + "Generate sulcal depth for a surface.\n" + indent9 + "\n" + indent9 + "\"" + getDefaultDepthColumnName() + "\" is the default name for the depth column.\n" + indent9 + "\"" + getDefaultSmoothedDepthColumnName() + "\" is the default name for the depth column.\n" + indent9 + "\n" + indent9 + "Note: The input surface shape file does not need to exist.\n" + indent9 + "If a column exists in the input surface shape file with the\n" + indent9 + "name of the depth or smoothed depth column name, the column\n" + indent9 + "is overwritten.\n" + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceSulcalDepth::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get required parameters // const QString fiducialCoordinateFileName = parameters->getNextParameterAsString("Fiducial Coordinate File Name"); const QString closedTopologyFileName = parameters->getNextParameterAsString("Closed Topology File Name"); const QString hullVtkFileName = parameters->getNextParameterAsString("Hull VTK File Name"); const QString inputSurfaceShapeFileName = parameters->getNextParameterAsString("Input Surface Shape File Name"); const QString outputSurfaceShapeFileName = parameters->getNextParameterAsString("Output Surface Shape File Name"); const QString outputHullCoordinateFileName = parameters->getNextParameterAsString("Output Hull Coordinate File Name"); // // Depth columns // int depthColumn = BrainModelSurfaceSulcalDepthWithNormals::DEPTH_COLUMN_CREATE_NEW; int smoothedDepthColumn = BrainModelSurfaceSulcalDepthWithNormals::DEPTH_COLUMN_CREATE_NEW; QString depthColumnName = getDefaultDepthColumnName(); QString smoothedDepthColumnName = getDefaultSmoothedDepthColumnName(); // // Check optional parameters // while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("Sulcal Depth Param"); if (paramName == "-depth-column-name") { depthColumnName = parameters->getNextParameterAsString("Depth Column Name"); } else if (paramName == "-no-depth") { depthColumn = BrainModelSurfaceSulcalDepthWithNormals::DEPTH_COLUMN_DO_NOT_GENERATE; } else if (paramName == "-no-smoothed-depth") { smoothedDepthColumn = BrainModelSurfaceSulcalDepthWithNormals::DEPTH_COLUMN_DO_NOT_GENERATE; } else if (paramName == "-smoothed-depth-column-name") { smoothedDepthColumnName = parameters->getNextParameterAsString("Depth Column Name"); } else { throw CommandException("unknown parameter: " + paramName); } } // Create a brain set // BrainSet brainSet(closedTopologyFileName, fiducialCoordinateFileName, "", true); BrainModelSurface* bms = brainSet.getBrainModelSurface(0); if (bms == NULL) { throw CommandException("unable to find surface."); } const TopologyFile* tf = bms->getTopologyFile(); if (tf == NULL) { throw CommandException("unable to find topology."); } const int numNodes = bms->getNumberOfNodes(); if (numNodes == 0) { throw CommandException("surface contains no nodes."); } // // Surface Shape File // SurfaceShapeFile surfaceShapeFile; if (inputSurfaceShapeFileName.isEmpty() == false) { if (QFile::exists(inputSurfaceShapeFileName)) { surfaceShapeFile.readFile(inputSurfaceShapeFileName); // // Does depth column exist, if so, reuse it // if (depthColumn != BrainModelSurfaceSulcalDepthWithNormals::DEPTH_COLUMN_DO_NOT_GENERATE) { const int depCol = surfaceShapeFile.getColumnWithName(depthColumnName); if (depCol >= 0) { depthColumn = depCol; } } // // Does smoothed depth column exist, if so, reuse it // if (smoothedDepthColumn != BrainModelSurfaceSulcalDepthWithNormals::DEPTH_COLUMN_DO_NOT_GENERATE) { const int depCol = surfaceShapeFile.getColumnWithName(smoothedDepthColumnName); if (depCol >= 0) { smoothedDepthColumn = depCol; } } } } // // Do sulcal depth // CoordinateFile hullCoordinateFile; BrainModelSurfaceSulcalDepthWithNormals sd(&brainSet, bms, hullVtkFileName, &surfaceShapeFile, 5, 100, depthColumn, smoothedDepthColumn, depthColumnName, smoothedDepthColumnName, &hullCoordinateFile); sd.execute(); // // Write the output files // surfaceShapeFile.writeFile(outputSurfaceShapeFileName); hullCoordinateFile.writeFile(outputHullCoordinateFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceSphericalMultiResMorphing.h0000664000175000017500000000355311572067322031712 0ustar michaelmichael #ifndef __COMMAND_SURFACE_SPHERICAL_MULTI_RES_MORPHING_H__ #define __COMMAND_SURFACE_SPHERICAL_MULTI_RES_MORPHING_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandSurfaceSphericalMultiResMorphing : public CommandBase { public: // constructor CommandSurfaceSphericalMultiResMorphing(); // destructor ~CommandSurfaceSphericalMultiResMorphing(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_SPHERICAL_MULTI_RES_MORPHING_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceSphericalMultiResMorphing.cxx0000664000175000017500000002135111572067322032261 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BorderProjectionFile.h" #include "BrainModelSurfaceMultiresolutionMorphing.h" #include "BrainSet.h" #include "CommandSurfaceSphericalMultiResMorphing.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SpecFile.h" #include "StatisticsUtilities.h" /** * constructor. */ CommandSurfaceSphericalMultiResMorphing::CommandSurfaceSphericalMultiResMorphing() : CommandBase("-surface-sphere-multi-morph", "SURFACE SPHERICAL MULTIRESOLUTION MORPHING") { } /** * destructor. */ CommandSurfaceSphericalMultiResMorphing::~CommandSurfaceSphericalMultiResMorphing() { } /** * get the script builder parameters. */ void CommandSurfaceSphericalMultiResMorphing::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Spec File Name", FileFilters::getSpecFileFilter()); paramsOut.addFile("Fiducial Coordinate File Name", FileFilters::getCoordinateFiducialFileFilter()); paramsOut.addFile("Spherical Coordinate File Name", FileFilters::getCoordinateSphericalFileFilter()); paramsOut.addFile("ClosedTopology File Name", FileFilters::getTopologyClosedFileFilter()); paramsOut.addVariableListOfParameters("Options"); } /** * get full help information. */ QString CommandSurfaceSphericalMultiResMorphing::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-ces-borderprojection-file \n" + indent9 + " \n" + indent9 + " ]\n" + indent9 + "[-parameters multi-res-morph-parameters-file.morph]\n" + indent9 + "\n" + indent9 + "Perform spherical multi-resolution morphing (distortion correction)\n" + indent9 + "\n" + indent9 + "If a border projection file and the name of the central\n" + indent9 + "sulcus border are provided, the surface will be aligned\n" + indent9 + "to standard orientation.\n" + indent9 + "\n" + indent9 + "If a multi-res morph parameters file is specified it\n" + indent9 + "will override the default multi-resolution \n" + indent9 + "morphing parameters.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceSphericalMultiResMorphing::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString specFileName = parameters->getNextParameterAsString("Spec File Name"); const QString fiducialCoordinateFileName = parameters->getNextParameterAsString("Fiducial Coordinate File Name"); const QString sphericalCoordinateFileName = parameters->getNextParameterAsString("Spherical Coordinate File Name"); const QString closedTopologyFileName = parameters->getNextParameterAsString("Closed Topology File Name"); QString borderProjectionFileName; QString centralSulcusBorderName; QString multiResMorphParamsFileName; while (parameters->getParametersAvailable()) { const QString paramName(parameters->getNextParameterAsString("opt-param")); if (paramName == "-ces-borderprojection-file") { borderProjectionFileName = parameters->getNextParameterAsString("Border Projection File Name"); centralSulcusBorderName = parameters->getNextParameterAsString("Central Sulcus Border Name"); } else if (paramName == "-parameters") { multiResMorphParamsFileName = parameters->getNextParameterAsString("Multi-Resolution Morphing Parameters File"); } else { throw CommandException("Unrecognized optional parameter: " + paramName); } } // // Read spec file // SpecFile specFile; specFile.readFile(specFileName); // // Set the selected files // specFile.setAllFileSelections(SpecFile::SPEC_FALSE); specFile.addToSpecFile(SpecFile::getClosedTopoFileTag(), closedTopologyFileName, "", SpecFile::SPEC_FALSE); specFile.addToSpecFile(SpecFile::getFiducialCoordFileTag(), fiducialCoordinateFileName, "", SpecFile::SPEC_FALSE); specFile.addToSpecFile(SpecFile::getSphericalCoordFileTag(), sphericalCoordinateFileName, "", SpecFile::SPEC_FALSE); // // Read the spec file into a brain set // QString errorMessage; BrainSet brainSet(true); if (brainSet.readSpecFile(specFile, specFileName, errorMessage)) { throw CommandException("Reading spec file: " + errorMessage); } // // Find the fiducial surface // BrainModelSurface* fiducialSurface = brainSet.getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_FIDUCIAL); if (fiducialSurface == NULL) { throw CommandException("Unable to find fiducial surface."); } // // Find the spherical surface // BrainModelSurface* sphericalSurface = brainSet.getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_SPHERICAL); if (sphericalSurface == NULL) { throw CommandException("Unable to find spherical surface."); } // // Read the border projection file // BorderProjection centralSulcusBorderProjection; if (borderProjectionFileName.isEmpty() == false) { BorderProjectionFile borderProjectionFile; borderProjectionFile.readFile(borderProjectionFileName); const BorderProjection* cesBP = borderProjectionFile.getFirstBorderProjectionByName(centralSulcusBorderName); if (cesBP != NULL) { centralSulcusBorderProjection = *cesBP; } else { throw CommandException("Unable to find border projection named \"" + centralSulcusBorderName + "\" in border projection file \"" + borderProjectionFileName + "\"."); } } // // Do flat multiresolution morphing // BrainModelSurfaceMultiresolutionMorphing bmsmm(&brainSet, fiducialSurface, sphericalSurface, BrainModelSurfaceMorphing::MORPHING_SURFACE_SPHERICAL, ¢ralSulcusBorderProjection); if (multiResMorphParamsFileName.isEmpty() == false) { bmsmm.getMultiResMorphParametersFile()->readFile(multiResMorphParamsFileName); } bmsmm.execute(); std::cout << "cycle " << "crossovers " << " avg AD " << " dev AD " << " avg LD " << " dev LD " << std::endl; std::vector meas; bmsmm.getMorphingMeasurements(meas); for (int i = 0; i < static_cast(meas.size()); i++) { QString name; StatisticsUtilities::DescriptiveStatistics ad, ld; int nodeCrossovers, tileCrossovers; float elapsedTime; meas[i].get(name, ad, ld, nodeCrossovers, tileCrossovers, elapsedTime); QString s; s.sprintf("%20s %10d %10.4f %10.4f %10.4f %10.4f", name.toAscii().constData(), nodeCrossovers, ad.average, ad.standardDeviation, ld.average, ld.standardDeviation); std::cout << s.toAscii().constData() << std::endl; } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceSphereProjectUnproject.h0000664000175000017500000000352611572067322031256 0ustar michaelmichael #ifndef __COMMAND_SURFACE_SPHERE_PROJECT_UNPROJECT_H__ #define __COMMAND_SURFACE_SPHERE_PROJECT_UNPROJECT_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandSurfaceSphereProjectUnproject : public CommandBase { public: // constructor CommandSurfaceSphereProjectUnproject(); // destructor ~CommandSurfaceSphereProjectUnproject(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_SPHERE_PROJECT_UNPROJECT_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceSphereProjectUnproject.cxx0000664000175000017500000002152311572067322031626 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainSet.h" #include "BrainModelSurface.h" #include "BrainModelSurfacePointProjector.h" #include "CommandSurfaceSphereProjectUnproject.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "TopologyFile.h" #include "TopologyHelper.h" /** * constructor. */ CommandSurfaceSphereProjectUnproject::CommandSurfaceSphereProjectUnproject() : CommandBase("-surface-sphere-project-unproject", "SURFACE SPHERE PROJECT/UNPROJECT") { } /** * destructor. */ CommandSurfaceSphereProjectUnproject::~CommandSurfaceSphereProjectUnproject() { } /** * get the script builder parameters. */ void CommandSurfaceSphereProjectUnproject::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); } /** * get full help information. */ QString CommandSurfaceSphereProjectUnproject::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Transform a spherical surface.\n" + indent9 + "\n" + indent9 + "The input spherical surface is projected to the \n" + indent9 + "\"project-to\" surface using barycentric projections\n" + indent9 + "and then unprojected using the \"unproject-to\" \n" + indent9 + "spherical surface. Typically the \"unproject-to\"\n" + indent9 + "surface is created during surface-based registration\n" + indent9 + "of the \"project-to\" spherical surface to some\n" + indent9 + "target.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceSphereProjectUnproject::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputSphericalCoordinateFileName = parameters->getNextParameterAsString("Input Spherical Coordinate File Name"); const QString inputSphericalTopologyFileName = parameters->getNextParameterAsString("Input Spherical Topology File Name"); const QString outputSphericalCoordinateFileName = parameters->getNextParameterAsString("Output Spherical Coordinate File Name"); const QString projectToSphericalCoordinateFileName = parameters->getNextParameterAsString("Project To Spherical Coordinate File Name"); const QString unprojectToSphericalCoordinateFileName = parameters->getNextParameterAsString("Unproject To Spherical Coordinate File Name"); const QString projectUnprojectSphericalTopologyFileName = parameters->getNextParameterAsString("Project/Unproject Spherical Topology File Name"); checkForExcessiveParameters(); // // Create a brain set for user surface // BrainSet brainSet(inputSphericalTopologyFileName, inputSphericalCoordinateFileName, "", true); BrainModelSurface* inputSphericalSurface = brainSet.getBrainModelSurface(0); if (inputSphericalSurface == NULL) { throw CommandException("unable to find input spherical surface after reading files."); } const TopologyFile* inputSphericalTopologyFile = inputSphericalSurface->getTopologyFile(); if (inputSphericalTopologyFile == NULL) { throw CommandException("unable to find input spherical topology after reading files."); } const int inputSphereNumNodes = inputSphericalSurface->getNumberOfNodes(); if (inputSphereNumNodes == 0) { throw CommandException("input spherical surface contains no nodes."); } // // Create a brain set for project/unproject surfaces // BrainSet projectUnprojectBrainSet(projectUnprojectSphericalTopologyFileName, projectToSphericalCoordinateFileName, unprojectToSphericalCoordinateFileName, true); BrainModelSurface* projectSphericalSurface = projectUnprojectBrainSet.getBrainModelSurface(0); if (projectSphericalSurface == NULL) { throw CommandException("unable to find project to spherical surface after reading files."); } BrainModelSurface* unprojectSphericalSurface = projectUnprojectBrainSet.getBrainModelSurface(1); if (unprojectSphericalSurface == NULL) { throw CommandException("unable to find unproject to spherical surface after reading files."); } const CoordinateFile* unprojectCoordinateFile = unprojectSphericalSurface->getCoordinateFile(); const TopologyFile* projectTopologyFile = projectSphericalSurface->getTopologyFile(); if (projectTopologyFile == NULL) { throw CommandException("unable to find project/unproject spherical topology after reading files."); } const int projectSphereNumNodes = projectSphericalSurface->getNumberOfNodes(); if (projectSphereNumNodes == 0) { throw CommandException("input project to surface contains no nodes."); } // // Topology Helper for input sphere // const TopologyHelper* inputSphereTopologyHelper = inputSphericalTopologyFile->getTopologyHelper(false, true, false); CoordinateFile* inputOutputCoordFile = inputSphericalSurface->getCoordinateFile(); // // Make sure both surfaces are centered and of the same radius and unproject surface // unprojectSphericalSurface->translateMidpointToOrigin(); const float radius = unprojectSphericalSurface->getSphericalSurfaceRadius(); projectSphericalSurface->translateMidpointToOrigin(); projectSphericalSurface->convertToSphereWithRadius(radius); inputSphericalSurface->translateMidpointToOrigin(); inputSphericalSurface->convertToSphereWithRadius(radius); // // Use a point projector to transform the surface nodes // BrainModelSurfacePointProjector pp(projectSphericalSurface, BrainModelSurfacePointProjector::SURFACE_TYPE_HINT_SPHERE, false); for (int i = 0; i < inputSphereNumNodes; i++) { if (inputSphereTopologyHelper->getNodeHasNeighbors(i)) { float xyz[3]; inputOutputCoordFile->getCoordinate(i, xyz); int nearestNode = -1; int baryNodes[3]; float baryAreas[3]; int triangle = pp.projectBarycentric(xyz, nearestNode, baryNodes, baryAreas, false); if (triangle >= 0) { BrainModelSurfacePointProjector::unprojectPoint(baryNodes, baryAreas, unprojectCoordinateFile, xyz); } else if (nearestNode >= 0) { unprojectCoordinateFile->getCoordinate(nearestNode, xyz); } else { throw CommandException("Sphere Project/Unproject failed for node index: " + QString::number(i)); } inputOutputCoordFile->setCoordinate(i, xyz); } } // // Make spherical again // inputSphericalSurface->translateMidpointToOrigin(); inputSphericalSurface->convertToSphereWithRadius(radius); // // Write the output coordinate file // inputOutputCoordFile->writeFile(outputSphericalCoordinateFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceSphere.h0000664000175000017500000000336011572067322026031 0ustar michaelmichael #ifndef __COMMAND_SURFACE_SPHERE_H__ #define __COMMAND_SURFACE_SPHERE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandSurfaceSphere : public CommandBase { public: // constructor CommandSurfaceSphere(); // destructor ~CommandSurfaceSphere(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_SPHERE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceSphere.cxx0000664000175000017500000001075411572067322026411 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurface.h" #include "BrainSet.h" #include "CommandSurfaceSphere.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "TopologyFile.h" /** * constructor. */ CommandSurfaceSphere::CommandSurfaceSphere() : CommandBase("-surface-sphere", "SURFACE TO SPHERE") { } /** * destructor. */ CommandSurfaceSphere::~CommandSurfaceSphere() { } /** * get the script builder parameters. */ void CommandSurfaceSphere::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Output Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Output Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); } /** * get full help information. */ QString CommandSurfaceSphere::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + "\n" + indent9 + "This command does the following:\n" + indent9 + " 1) All options are processed.\n" + indent9 + " 2) The surface is translated so that the midpoint\n" + indent9 + " ((xmin+xmax)/2, (ymin+ymax)/2, (zmin+zmax)/2)\n" + indent9 + " of the surface is at the origin.\n" + indent9 + "\n" + indent9 + "If the input surface file is a sphere and no\n" + indent9 + "options are provided, the spherical surface\n" + indent9 + "is centered at the origin \n" + indent9 + "abs(xmin)==abs(xmax), abs(ymin)==abs(ymax),\n" + indent9 + "abs(zmin)==abs(zmax).\n" + indent9 + "\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceSphere::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the parameters // const QString inputCoordinateFileName = parameters->getNextParameterAsString("Input Coordinate File Name"); const QString inputTopologyFileName = parameters->getNextParameterAsString("Input Topology File Name"); const QString outputCoordinateFileName = parameters->getNextParameterAsString("Output Coordinate File Name"); checkForExcessiveParameters(); // // Create a brain set // BrainSet brainSet(inputTopologyFileName, inputCoordinateFileName, "", true); BrainModelSurface* surface = brainSet.getBrainModelSurface(0); if (surface == NULL) { throw CommandException("unable to find surface."); } const TopologyFile* tf = surface->getTopologyFile(); if (tf == NULL) { throw CommandException("unable to find topology."); } const int numNodes = surface->getNumberOfNodes(); if (numNodes == 0) { throw CommandException("surface contains no nodes."); } // // Place midpoint at origin // surface->translateMidpointToOrigin(); // // Write the coordinate file // CoordinateFile* cf = surface->getCoordinateFile(); cf->writeFile(outputCoordinateFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceSmoothing.h0000664000175000017500000000342411572067322026553 0ustar michaelmichael #ifndef __COMMAND_SURFACE_SMOOTHING_H__ #define __COMMAND_SURFACE_SMOOTHING_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for surface smoothing class CommandSurfaceSmoothing : public CommandBase { public: // constructor CommandSurfaceSmoothing(); // destructor ~CommandSurfaceSmoothing(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_SMOOTHING_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceSmoothing.cxx0000664000175000017500000001651011572067322027126 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurface.h" #include "BrainModelSurfaceROINodeSelection.h" #include "BrainSet.h" #include "CommandSurfaceSmoothing.h" #include "FileFilters.h" #include "NodeRegionOfInterestFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandSurfaceSmoothing::CommandSurfaceSmoothing() : CommandBase("-surface-smoothing", "SURFACE SMOOTHING") { } /** * destructor. */ CommandSurfaceSmoothing::~CommandSurfaceSmoothing() { } /** * get the script builder parameters. */ void CommandSurfaceSmoothing::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Output Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFloat("Strength", 1.0, 0.0, 1.0); paramsOut.addInt("Iterations", 10, 0, 100000); paramsOut.addInt("Edge Iterations", 0, 0, 100000); paramsOut.addVariableListOfParameters("Smoothing Options"); } /** * get full help information. */ QString CommandSurfaceSmoothing::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " [-linear]\n" + indent9 + " [-project-to-sphere every-x-iterations]\n" + indent9 + " [-roi-file roi-file-name]\n" + indent9 + "\n" + indent9 + "Smooth a surface.\n" + indent9 + "\n" + indent9 + "Use \"-linear\" for a linear smoothing algorithm.\n" + indent9 + "\n" + indent9 + "Use \"-project-to-sphere\" to project the surface to a\n" + indent9 + "sphere \"every-x-iterations\".\n" + indent9 + "\n" + indent9 + "Use \"-roi-file\" to limit smoothing to a region of \n" + indent9 + "interest (subset of the surface).\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceSmoothing::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get coord, topo, and roi file names // const QString inputCoordinateFileName = parameters->getNextParameterAsString("Input Coordinate File Name"); const QString outputCoordinateFileName = parameters->getNextParameterAsString("Output Coordinate File Name"); const QString topoFileName = parameters->getNextParameterAsString("Input Topology File Name"); const float smoothingStrength = parameters->getNextParameterAsFloat("Smoothing Strength"); const int smoothingIterations = parameters->getNextParameterAsInt("Smoothing Iterations"); const int smoothingEdgeIterations = parameters->getNextParameterAsInt("Smoothing Edge Iterations"); // // Create a brain set // BrainSet brainSet(topoFileName, inputCoordinateFileName, "", true); BrainModelSurface* bms = brainSet.getBrainModelSurface(0); if (bms == NULL) { throw CommandException("unable to find surface."); } const TopologyFile* tf = bms->getTopologyFile(); if (tf == NULL) { throw CommandException("unable to find topology."); } const int numNodes = bms->getNumberOfNodes(); if (numNodes == 0) { throw CommandException("surface contains not nodes."); } // // Create an ROI of all nodes // BrainModelSurfaceROINodeSelection roi(&brainSet); roi.selectAllNodes(bms); int projectToSphereIterations = -1; bool linearFlag = false; // // Process the parameters for node selection // while (parameters->getParametersAvailable()) { // // Get the parameter // const QString parameterName = parameters->getNextParameterAsString("SURFACE SMOOTHING option"); if (parameterName == "-linear") { linearFlag = true; } else if (parameterName == "-project-to-sphere") { projectToSphereIterations = parameters->getNextParameterAsInt("SURFACE SMOOTHING Project to Sphere Every X Iterations"); } else if (parameterName == "-roi-file") { const QString roiFileName = parameters->getNextParameterAsString("SURFACE SMOOTHING roi-file-name"); NodeRegionOfInterestFile roiFile; roiFile.readFile(roiFileName); roi.getRegionOfInterestFromFile(roiFile); } else if (parameterName == "-num-threads") { int numThreads = parameters->getNextParameterAsInt("Number of threads"); PreferencesFile* pf = BrainSet::getPreferencesFile(); pf->setMaximumNumberOfThreads(numThreads); } else { throw CommandException("Unrecognized operation = \"" + parameterName + "\"."); } } // // Set nodes for smoothing // std::vector nodesToBeSmoothed(numNodes); for (int i = 0; i < numNodes; i++) { nodesToBeSmoothed[i] = roi.getNodeSelected(i); } // // Smooth the surface // if (linearFlag) { bms->linearSmoothing(smoothingStrength, smoothingIterations, smoothingEdgeIterations, &nodesToBeSmoothed, projectToSphereIterations); } else { bms->arealSmoothing(smoothingStrength, smoothingIterations, smoothingEdgeIterations, &nodesToBeSmoothed, projectToSphereIterations); } // // Write the coordinate file // CoordinateFile* outputCoordFile = bms->getCoordinateFile(); outputCoordFile->writeFile(outputCoordinateFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceShrinkToProbVol.h0000664000175000017500000000345711572067322027657 0ustar michaelmichael #ifndef __COMMAND_SURFACE_SHRINK_TO_PROB_VOL_H__ #define __COMMAND_SURFACE_SHRINK_TO_PROB_VOL_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandSurfaceShrinkToProbVol : public CommandBase { public: // constructor CommandSurfaceShrinkToProbVol(); // destructor ~CommandSurfaceShrinkToProbVol(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_SEGMENTATION_LIGASE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceShrinkToProbVol.cxx0000664000175000017500000003043111572067322030222 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "CommandSurfaceShrinkToProbVol.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "BrainModelVolumeLigaseSegmentation.h" #include "BrainSet.h" #include "StringUtilities.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceToVolumeSegmentationConverter.h" #include "BrainModelVolumeGradient.h" #include "VectorFile.h" #include "VolumeFile.h" /** * constructor. */ CommandSurfaceShrinkToProbVol::CommandSurfaceShrinkToProbVol() : CommandBase("-surface-shrink-to-prob-vol", "SURFACE SHRINK TO PROBABILISTIC VOLUME") { } /** * destructor. */ CommandSurfaceShrinkToProbVol::~CommandSurfaceShrinkToProbVol() { } /** * get the script builder parameters. */ void CommandSurfaceShrinkToProbVol::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); } /** * get full help information. */ QString CommandSurfaceShrinkToProbVol::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Generate a segmentation by moving the surface inwards to probability peaks\n" + indent9 + "\n" + indent9 + " iterations number of times to grow inwards, each time a maximum of\n" + indent9 + " one erosion of the segmentation.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceShrinkToProbVol::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputSurfaceTopoName = parameters->getNextParameterAsString("Input Surface Topo Name"); const QString inputSurfaceCoordName = parameters->getNextParameterAsString("Input Surface Coord Name"); const QString inputVolumeFileName = parameters->getNextParameterAsString("Input Probabilistic Volume File Name"); const QString outputVolumeFileName = parameters->getNextParameterAsString("Output Segmentation Volume File Name"); const QString outputVolumeLabel = parameters->getNextParameterAsString("Output Segmentation Volume Label"); const int numberOfIterations = parameters->getNextParameterAsInt("Number of Iterations"); checkForExcessiveParameters(); // // Create a brain set // BrainSet brainSet(inputSurfaceTopoName, inputSurfaceCoordName); // // Read the input files // BrainModelSurface* inputSurf = brainSet.getBrainModelSurface(0); inputSurf->computeNormals(); inputSurf->orientNormalsOut(); VolumeFile inputVol; inputVol.readFile(inputVolumeFileName); // // Create output volume file // VolumeFile segVolume(inputVol); segVolume.setVolumeType(VolumeFile::VOLUME_TYPE_SEGMENTATION); segVolume.setFileComment(outputVolumeLabel); int i, j, k, ti, tj, tk, max_i, max_j, max_k, total_nodes = inputSurf->getNumberOfNodes(), index; inputVol.getDimensions(max_i, max_j, max_k); // // Generate initial segmentation from surface // BrainModelSurfaceToVolumeSegmentationConverter* bmsvsc = new BrainModelSurfaceToVolumeSegmentationConverter(&brainSet, inputSurf, &segVolume, true, false); bmsvsc->execute(); delete bmsvsc; // // Take the gradient of the probability volume to get directionality easily, and the benefits of the filtering/unbiased directionality // VectorFile prob_grad(max_i, max_j, max_k); BrainModelVolumeGradient* bmvg = new BrainModelVolumeGradient(&brainSet, 5, true, false, &inputVol, &segVolume, &prob_grad); std::cout << "starting gradient" << std::endl; bmvg->execute(); std::cout << "gradient done" << std::endl; delete bmvg; // // Voxels not considered in the iteration and voxels that failed to erode, which will not erode with another test // VolumeFile voxelsToLeave, voxelsFailed(segVolume); voxelsFailed.setAllVoxels(0.0f); int coord_length = 3 * total_nodes; float ii, ij, ik, min, temp, tempa, tempb, spacing[3], tempCoord[3], *coord = new float[coord_length]; const float* normals = inputSurf->getNormal(0);//silly hack to get flat array of normals float thisVal, tempVec[3], tempFloat[3], avgspace, weight; inputSurf->getCoordinateFile()->getAllCoordinates(coord); inputVol.getSpacing(spacing); avgspace = pow(spacing[0] * spacing[1] * spacing[2], 1.0f / 3.0f);//geometric average of spacing to estimate "1 voxel away" in stereotaxic space (mm) for (int iter = 0; iter < numberOfIterations; ++iter) { voxelsToLeave = segVolume; voxelsToLeave.doVolMorphOps(0, 1);//erode for (i = 0; i < max_i; ++i) { for (j = 0; j < max_j; ++j) { for (k = 0; k < max_k; ++k) { if (segVolume.getVoxel(i, j, k) > 1.0f && voxelsToLeave.getVoxel(i, j, k) < 1.0f && voxelsFailed.getVoxel(i, j, k) < 1.0f) { // // Voxel is in current segmentation, not in the eroded segmentation, and hasn't been tested before, so try it // inputVol.getVoxelCoordinate(i, j, k, tempCoord); index = 0; temp = coord[0] - tempCoord[0]; tempa = coord[1] - tempCoord[1]; tempb = coord[2] - tempCoord[2]; min = temp * temp + tempa * tempa + tempb * tempb; // // Find closest surface node // for (int node = 3; node < coord_length; node += 3)//NOTE: could be optimized by indexing to find closest node without searching all {//however, that may weaken the stand that the closest node will always be found. Index by surface or volume? temp = coord[node] - tempCoord[0]; tempa = coord[node + 1] - tempCoord[1]; tempb = coord[node + 2] - tempCoord[2]; temp = temp * temp + tempa * tempa + tempb * tempb; if (temp < min) { min = temp; index = node; } } prob_grad.getVector(i, j, k, tempVec); // // Dot product of normal at closest node and vector at voxel // thisVal = normals[index] * tempVec[0] + normals[index + 1] * tempVec[1] + normals[index + 2] * tempVec[2]; //evaluate identical fitness calculation at other node, but using same normal /*ti = i - (int)(normals[index] * 1.9999f);//HACK: multiply by 2, cast to int equals round to integer for (-1, 1) tj = j - (int)(normals[index + 1] * 1.9999f); tk = k - (int)(normals[index + 2] * 1.9999f); inputVol.getVoxelCoordinate(ti, tj, tk, tempCoord);*///replaced by interpolation /*tempCoord[0] -= normals[index] * avgspace;//coordinates used only for searching for closest node tempCoord[1] -= normals[index + 1] * avgspace; tempCoord[2] -= normals[index + 2] * avgspace;*///not used, because using the same normal as the testing voxel // // Interpolate the gradient vector at voxel by interpolating each component separately, with no curvature // tempVec[0] = tempVec[1] = tempVec[2] = 0.0f; ii = i - normals[index] * avgspace / spacing[0];//"index" to interpolate, this is NOT a coordinate, adjusts the "one voxel away" vector back ij = j - normals[index + 1] * avgspace / spacing[1];//into index space ik = k - normals[index + 2] * avgspace / spacing[2]; for (ti = (int)floor(ii); ti <= (int)ceil(ii); ++ti) { for (tj = (int)floor(ij); tj <= (int)ceil(ij); ++tj) { for (tk = (int)floor(ik); tk <= (int)ceil(ik); ++tk) { prob_grad.getVector(ti, tj, tk, tempFloat); weight = fabs(tempCoord[0] - ti) * fabs(tempCoord[1] - tj) * fabs(tempCoord[2] - tk);//linear weighting in all directions tempVec[0] += tempFloat[0] * weight; tempVec[1] += tempFloat[1] * weight; tempVec[2] += tempFloat[2] * weight; } } } /*index = 0;//search for closest node to new coordinate is BAD with a capital BAD for thin white matter temp = coord[0] - tempCoord[0]; tempa = coord[1] - tempCoord[1]; tempb = coord[2] - tempCoord[2]; min = temp * temp + tempa * tempa + tempb * tempb; for (int node = 3; node < coord_length; node += 3) { temp = coord[node] - tempCoord[0]; tempa = coord[node + 1] - tempCoord[1]; tempb = coord[node + 2] - tempCoord[2]; temp = temp * temp + tempa * tempa + tempb * tempb; if (temp < min) { min = temp; index = node; } }*/ if (thisVal < 0.0f)//if the gradient says go inwards { //if the dot product of probability gradient and outward surface normal is farther from the peak than the neighbor voxel //in the opposite direction from the surface normal, erode this voxel //essentially, if following the inward normal would end up farther down the inside slope of the probability peak, dont erode //NOTE: negative values mean gradient is inward (opposed to outward normals) if (thisVal < -(normals[index] * tempVec[0] + normals[index + 1] * tempVec[1] + normals[index + 2] * tempVec[2])) { segVolume.setVoxel(i, j, k, 0, 0.0f); } else { voxelsFailed.setVoxel(i, j, k, 0, 255.0f); } } else { //if the gradient says go outwards, but the next voxel says inwards or less strongly outwards, erode //bad for thin white matter /*if (normals[index] * tempVec[0] + normals[index + 1] * tempVec[1] + normals[index + 2] * tempVec[2] < thisVal) { segVolume.setVoxel(i, j, k, 0, 0.0f); } else {*/ voxelsFailed.setVoxel(i, j, k, 0, 255.0f); //} } } } } } } // // Write the file // segVolume.writeFile(outputVolumeFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceRoiStatisticalReport.h0000664000175000017500000000351211572067322030734 0ustar michaelmichael #ifndef __COMMAND_SURFACE_ROI_STATISTICAL_REPORT_H__ #define __COMMAND_SURFACE_ROI_STATISTICAL_REPORT_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandSurfaceRoiStatisticalReport : public CommandBase { public: // constructor CommandSurfaceRoiStatisticalReport(); // destructor ~CommandSurfaceRoiStatisticalReport(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_ROI_STATISTICAL_REPORT_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceRoiStatisticalReport.cxx0000664000175000017500000002274111572067322031314 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurface.h" #include "BrainModelSurfaceROINodeSelection.h" #include "BrainModelSurfaceROITextReport.h" #include "BrainSet.h" #include "CommandSurfaceRoiStatisticalReport.h" #include "FileFilters.h" #include "LatLonFile.h" #include "MetricFile.h" #include "NodeRegionOfInterestFile.h" #include "PaintFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SpecFile.h" #include "SurfaceShapeFile.h" #include "TextFile.h" #include "TopologyFile.h" /** * constructor. */ CommandSurfaceRoiStatisticalReport::CommandSurfaceRoiStatisticalReport() : CommandBase("-surface-roi-statistical-report", "SURFACE ROI STATISTICAL REPORT") { } /** * destructor. */ CommandSurfaceRoiStatisticalReport::~CommandSurfaceRoiStatisticalReport() { } /** * get the script builder parameters. */ void CommandSurfaceRoiStatisticalReport::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Latitude/Longitude File Name", FileFilters::getLatitudeLongitudeFileFilter()); paramsOut.addFile("Metric File Name", FileFilters::getPaintFileFilter()); paramsOut.addString("Metric Distortion Column Name or Number"); paramsOut.addFile("Paint File Name", FileFilters::getPaintFileFilter()); paramsOut.addFile("Surface Shape File Name", FileFilters::getSurfaceShapeFileFilter()); paramsOut.addFile("Region Of Interest File Name", FileFilters::getRegionOfInterestFileFilter()); paramsOut.addFile("Output Text Report File Name", FileFilters::getTextFileFilter()); paramsOut.addBoolean("Tab Separate Report", false); } /** * get full help information. */ QString CommandSurfaceRoiStatisticalReport::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " \n" + indent9 + "\n" + indent9 + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + " \n" + indent9 + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Generate a staistical report. If any of the data files \n" + indent9 + "(lat/long, paint, metric, or shape) are not available, \n" + indent9 + "specify its name two consecutive double quotes (\"\"). \n" + indent9 + "\n" + indent9 + "If there is not a metric distortion column, specify its\n" + indent9 + "value with two consecutive double quotes (\"\").\n" + indent9 + "\n" + indent9 + "\"tab-separate-report-flag\" value is either \"true\" or \n" + indent9 + "\"false\".\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceRoiStatisticalReport::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the parameters // const QString coordinateFileName = parameters->getNextParameterAsString("Coordinate File Name"); const QString topoFileName = parameters->getNextParameterAsString("Topology File Name"); const QString latLonFileName = parameters->getNextParameterAsString("Lat/Lon File Name"); const QString metricFileName = parameters->getNextParameterAsString("Metric File Name"); const QString metricColumnNameOrNumber = parameters->getNextParameterAsString("Metric Distortion Column Name or Number"); const QString paintFileName = parameters->getNextParameterAsString("Paint File Name"); const QString surfaceShapeFileName = parameters->getNextParameterAsString("Surface Shape File Name"); const QString roiFileName = parameters->getNextParameterAsString("Region of Interest File Name"); const QString textReportFileName = parameters->getNextParameterAsString("Text Report File Name"); const bool tabSeparateReportFlag = parameters->getNextParameterAsBoolean("Tab Separate Report Flag"); // // Read the spec file into a brain set // SpecFile specFile; specFile.addToSpecFile(SpecFile::getFiducialCoordFileTag(), coordinateFileName, "", false); specFile.addToSpecFile(SpecFile::getClosedTopoFileTag(), topoFileName, "", false); specFile.addToSpecFile(SpecFile::getLatLonFileTag(), latLonFileName, "", false); specFile.addToSpecFile(SpecFile::getMetricFileTag(), metricFileName, "", false); specFile.addToSpecFile(SpecFile::getPaintFileTag(), paintFileName, "", false); specFile.addToSpecFile(SpecFile::getSurfaceShapeFileTag(), surfaceShapeFileName, "", false); // // Read the spec file into a brain set // QString errorMessage; BrainSet brainSet(true); brainSet.setIgnoreTopologyFileInCoordinateFileHeaderFlag(true); if (brainSet.readSpecFile(specFile, "", errorMessage)) { throw CommandException("Reading spec file: " + errorMessage); } // // Find the surface // BrainModelSurface* bms = brainSet.getBrainModelSurface(0); if (bms == NULL) { throw CommandException("Unable to find surface after reading files."); } // // Read the roi // BrainModelSurfaceROINodeSelection roi(&brainSet); NodeRegionOfInterestFile roiFile; roiFile.readFile(roiFileName); roi.getRegionOfInterestFromFile(roiFile); // // Find the metric distortion column number and set selected columns // MetricFile* metricFile = brainSet.getMetricFile(); int metricDistortionColumnNumber = -1; if ((metricFile->empty() == false) && (metricColumnNameOrNumber.isEmpty() == false)) { metricDistortionColumnNumber = metricFile->getColumnFromNameOrNumber(metricColumnNameOrNumber, false); } std::vector metricSelections(metricFile->getNumberOfColumns(), true); // // Paint selections // PaintFile* paintFile = brainSet.getPaintFile(); std::vector paintSelections(paintFile->getNumberOfColumns(), true); // // Shape selections // SurfaceShapeFile* shapeFile = brainSet.getSurfaceShapeFile(); std::vector shapeSelections(shapeFile->getNumberOfColumns(), true); // // Verify surface has nodes // const int numNodes = brainSet.getNumberOfNodes(); if (numNodes <= 0) { throw CommandException("The surfaces contain no nodes."); } // // Run the statistical report // BrainModelSurfaceROITextReport bmsri(&brainSet, bms, &roi, metricFile, metricSelections, shapeFile, shapeSelections, paintFile, paintSelections, brainSet.getLatLonFile(), 0, // lat/lon file column "", metricFile, metricDistortionColumnNumber, tabSeparateReportFlag); try { bmsri.execute(); } catch (BrainModelAlgorithmException& e) { throw CommandException(e.whatQString()); return; } // // File for text report // TextFile textReportFile; textReportFile.setText(bmsri.getReportText()); // // Write the text file // textReportFile.writeFile(textReportFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceRoiShapeMeasures.h0000664000175000017500000000346211572067322030025 0ustar michaelmichael #ifndef __COMMAND_SURFACE_ROI_SHAPE_MEASURES_H__ #define __COMMAND_SURFACE_ROI_SHAPE_MEASURES_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandSurfaceRoiShapeMeasures : public CommandBase { public: // constructor CommandSurfaceRoiShapeMeasures(); // destructor ~CommandSurfaceRoiShapeMeasures(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_ROI_SHAPE_MEASURES_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceRoiShapeMeasures.cxx0000664000175000017500000001333311572067322030376 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurface.h" #include "BrainModelSurfaceROIIntegratedFoldingIndexReport.h" #include "BrainModelSurfaceROINodeSelection.h" #include "BrainSet.h" #include "CommandSurfaceRoiShapeMeasures.h" #include "FileFilters.h" #include "NodeRegionOfInterestFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "TextFile.h" /** * constructor. */ CommandSurfaceRoiShapeMeasures::CommandSurfaceRoiShapeMeasures() : CommandBase("-surface-shape-measures", "SURFACE SHAPE MEASURES") { } /** * destructor. */ CommandSurfaceRoiShapeMeasures::~CommandSurfaceRoiShapeMeasures() { } /** * get the script builder parameters. */ void CommandSurfaceRoiShapeMeasures::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Coordinate File", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Input Topology File", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Surface Shape File", FileFilters::getSurfaceShapeFileFilter()); paramsOut.addFile("Output Text File", FileFilters::getTextFileFilter(), "Folding.txt"); paramsOut.addFile("Region Of Interest File", FileFilters::getRegionOfInterestFileFilter(), "", "-roi"); } /** * get full help information. */ QString CommandSurfaceRoiShapeMeasures::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-roi region-of-interest-file-name]\n" + indent9 + "\n" + indent9 + "Generate a report of shape measurements on a surface.\n" + indent9 + "\n" + indent9 + "If an ROI is provided, the shape measurements are \n" + indent9 + "limited to that region of the surface.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceRoiShapeMeasures::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the parameters // const QString coordinateFileName = parameters->getNextParameterAsString("Coordinate File Name"); const QString topoFileName = parameters->getNextParameterAsString("Topology File Name"); const QString surfaceShapeFileName = parameters->getNextParameterAsString("Surface Shape File Name"); const QString textReportFileName = parameters->getNextParameterAsString("Text Report File Name"); QString roiFileName; while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("Optional parameter"); if (paramName == "-roi") { roiFileName = parameters->getNextParameterAsString("Region of Interest File Name"); if (roiFileName.isEmpty()) { throw CommandException("Region of Interest File Name is missing."); } } else { throw CommandException("Unrecognized parameter \"" + paramName + "\"."); } } // // Create a brain set // BrainSet brainSet(topoFileName, coordinateFileName, ""); // // Find the surface // BrainModelSurface* bms = brainSet.getBrainModelSurface(0); if (bms == NULL) { throw CommandException("Unable to find surface after reading files."); } if (bms->getTopologyFile() == NULL) { throw CommandException("Unable to find topology after reading files."); } brainSet.readSurfaceShapeFile(surfaceShapeFileName, false, false); // // Get the ROI // BrainModelSurfaceROINodeSelection* surfaceROI = brainSet.getBrainModelSurfaceRegionOfInterestNodeSelection(); if (roiFileName.isEmpty() == false) { NodeRegionOfInterestFile nroi; nroi.readFile(roiFileName); surfaceROI->getRegionOfInterestFromFile(nroi); } else { surfaceROI->selectAllNodes(bms); } // // Run the report // BrainModelSurfaceROIIntegratedFoldingIndexReport fmr(&brainSet, bms, surfaceROI, brainSet.getSurfaceShapeFile(), "", true); fmr.execute(); // // File for text report // TextFile textReportFile; textReportFile.setText(fmr.getReportText()); // // Write the text file // textReportFile.writeFile(textReportFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceRoiNodeAreas.h0000664000175000017500000000343211572067322027116 0ustar michaelmichael #ifndef __COMMAND_SURFACE_ROI_NODE_AREAS_H__ #define __COMMAND_SURFACE_ROI_NODE_AREAS_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandSurfaceRoiNodeAreas : public CommandBase { public: // constructor CommandSurfaceRoiNodeAreas(); // destructor ~CommandSurfaceRoiNodeAreas(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_ROI_NODE_AREAS_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceRoiNodeAreas.cxx0000664000175000017500000001527311572067322027477 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurface.h" #include "BrainModelSurfaceROIAssignMetricNodeArea.h" #include "BrainModelSurfaceROINodeSelection.h" #include "BrainSet.h" #include "CommandSurfaceRoiNodeAreas.h" #include "FileFilters.h" #include "MetricFile.h" #include "NodeRegionOfInterestFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "TextFile.h" /** * constructor. */ CommandSurfaceRoiNodeAreas::CommandSurfaceRoiNodeAreas() : CommandBase("-surface-roi-node-areas", "SURFACE ROI NODE AREAS") { } /** * destructor. */ CommandSurfaceRoiNodeAreas::~CommandSurfaceRoiNodeAreas() { } /** * get the script builder parameters. */ void CommandSurfaceRoiNodeAreas::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Coordinate File", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Input Topology File", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Input Metric/Shape File", FileFilters::getMetricShapeFileFilter()); paramsOut.addFile("Output Metric/Shape File", FileFilters::getMetricShapeFileFilter()); paramsOut.addVariableListOfParameters("Options"); } /** * get full help information. */ QString CommandSurfaceRoiNodeAreas::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-roi region-of-interest-file-name]\n" + indent9 + "[-percentage]\n" + indent9 + "\n" + indent9 + "Generate a new metric or shape file column containing\n" + indent9 + "the surface area for each node. While nodes technically\n" + indent9 + "do not have area, triangles do. Since a triangle is made\n" + indent9 + "from three nodes, assign one-third of the triangle's\n" + indent9 + "surface area to each node and sum these amounts for each\n" + indent9 + "node.\n" + indent9 + "\n" + indent9 + "If an ROI is provided, the area measurements are limited\n" + indent9 + "to that region of the surface and nodes not in the ROI are\n" + indent9 + "assigned a value of zero.\n" + indent9 + "\n" + indent9 + "If the \"-percentage\" option is specified, the value \n" + indent9 + "assigned to each node is the percentage of total surface \n" + indent9 + "area contributed by that node.\n" + indent9 + " Value = ((node-surface-area / total-surface-area) * 100.0)\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceRoiNodeAreas::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the parameters // const QString coordinateFileName = parameters->getNextParameterAsString("Coordinate File Name"); const QString topoFileName = parameters->getNextParameterAsString("Topology File Name"); const QString inputMetricShapeFileName = parameters->getNextParameterAsString("Input Metric/Surface Shape File Name"); const QString outputMetricShapeFileName = parameters->getNextParameterAsString("Output Metric/Surface Shape File Name"); QString roiFileName; bool percentageFlag = false; while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("Optional parameter"); if (paramName == "-roi") { roiFileName = parameters->getNextParameterAsString("Region of Interest File Name"); if (roiFileName.isEmpty()) { throw CommandException("Region of Interest File Name is missing."); } } else if (paramName == "-percentage") { percentageFlag = true; } else { throw CommandException("Unrecognized parameter \"" + paramName + "\"."); } } // // Create a brain set // BrainSet brainSet(topoFileName, coordinateFileName, ""); // // Find the surface // BrainModelSurface* bms = brainSet.getBrainModelSurface(0); if (bms == NULL) { throw CommandException("Unable to find surface after reading files."); } if (bms->getTopologyFile() == NULL) { throw CommandException("Unable to find topology after reading files."); } // // Read input metric/shape file // MetricFile mf; if (inputMetricShapeFileName.isEmpty() == false) { mf.readFile(inputMetricShapeFileName); } // // Get the ROI // BrainModelSurfaceROINodeSelection* surfaceROI = brainSet.getBrainModelSurfaceRegionOfInterestNodeSelection(); if (roiFileName.isEmpty() == false) { NodeRegionOfInterestFile nroi; nroi.readFile(roiFileName); surfaceROI->getRegionOfInterestFromFile(nroi); } else { surfaceROI->selectAllNodes(bms); } QString columnName = "Node Area"; if (percentageFlag) { columnName += " Percentage"; } // // Get the areas // BrainModelSurfaceROIAssignMetricNodeArea roiOp(&brainSet, bms, surfaceROI, &mf, -1, "Node Area Percentage", percentageFlag); roiOp.execute(); // // Write the metric file // mf.writeFile(outputMetricShapeFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceRoiFoldingMeasures.h0000664000175000017500000000347611572067322030354 0ustar michaelmichael #ifndef __COMMAND_SURFACE_ROI_FOLDING_MEASURES_H__ #define __COMMAND_SURFACE_ROI_FOLDING_MEASURES_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandSurfaceRoiFoldingMeasures : public CommandBase { public: // constructor CommandSurfaceRoiFoldingMeasures(); // destructor ~CommandSurfaceRoiFoldingMeasures(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_ROI_FOLDING_MEASURES_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceRoiFoldingMeasures.cxx0000664000175000017500000001406011572067322030716 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurface.h" #include "BrainModelSurfaceROIFoldingMeasurementReport.h" #include "BrainModelSurfaceROINodeSelection.h" #include "BrainSet.h" #include "CommandSurfaceRoiFoldingMeasures.h" #include "FileFilters.h" #include "NodeRegionOfInterestFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "TextFile.h" /** * constructor. */ CommandSurfaceRoiFoldingMeasures::CommandSurfaceRoiFoldingMeasures() : CommandBase("-surface-folding-measures", "SURFACE FOLDING MEASURES") { } /** * destructor. */ CommandSurfaceRoiFoldingMeasures::~CommandSurfaceRoiFoldingMeasures() { } /** * get the script builder parameters. */ void CommandSurfaceRoiFoldingMeasures::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Coordinate File", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Input Topology File", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Output Text File", FileFilters::getTextFileFilter(), "Folding.txt"); paramsOut.addFile("Region Of Interest File", FileFilters::getRegionOfInterestFileFilter(), "", "-roi"); paramsOut.addFile("Output Metric Measurements File", FileFilters::getMetricFileFilter(), "", "-metric"); } /** * get full help information. */ QString CommandSurfaceRoiFoldingMeasures::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-roi region-of-interest-file-name]\n" + indent9 + "[-metric output-metric-measurements-file-name]\n" + indent9 + "\n" + indent9 + "Generate a report of folding measurements on a surface.\n" + indent9 + "\n" + indent9 + "If an ROI is provided, the folding measurements are \n" + indent9 + "limited to that region of the surface.\n" + indent9 + "\n" + indent9 + "If a metric measurements file is added, it will be output\n" + indent9 + "and contain folding measurements at each node.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceRoiFoldingMeasures::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the parameters // const QString coordinateFileName = parameters->getNextParameterAsString("Coordinate File Name"); const QString topoFileName = parameters->getNextParameterAsString("Topology File Name"); const QString textReportFileName = parameters->getNextParameterAsString("Text Report File Name"); QString roiFileName; QString metricFileName = ""; while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("Optional parameter"); if (paramName == "-roi") { roiFileName = parameters->getNextParameterAsString("Region of Interest File Name"); if (roiFileName.isEmpty()) { throw CommandException("Region of Interest File Name is missing."); } } else if (paramName == "-metric") { metricFileName = parameters->getNextParameterAsString("Metric File Name"); if (metricFileName.isEmpty()) { throw CommandException("Metric File Name is missing."); } } else { throw CommandException("Unrecognized parameter \"" + paramName + "\"."); } } // // Create a brain set // BrainSet brainSet(topoFileName, coordinateFileName, ""); // // Find the surface // const BrainModelSurface* bms = brainSet.getBrainModelSurface(0); if (bms == NULL) { throw CommandException("Unable to find surface after reading files."); } if (bms->getTopologyFile() == NULL) { throw CommandException("Unable to find topology after reading files."); } // // Get the ROI // BrainModelSurfaceROINodeSelection* surfaceROI = brainSet.getBrainModelSurfaceRegionOfInterestNodeSelection(); if (roiFileName.isEmpty() == false) { NodeRegionOfInterestFile nroi; nroi.readFile(roiFileName); surfaceROI->getRegionOfInterestFromFile(nroi); } else { surfaceROI->selectAllNodes(bms); } // // Run the report // BrainModelSurfaceROIFoldingMeasurementReport fmr(&brainSet, bms, surfaceROI, "", false, NULL, metricFileName); fmr.execute(); // // File for text report // TextFile textReportFile; textReportFile.setText(fmr.getReportText()); // // Write the text file // textReportFile.writeFile(textReportFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceRoiCoordReport.h0000664000175000017500000000344611572067322027524 0ustar michaelmichael #ifndef __COMMAND_SURFACE_ROI_COORD_REPORT_H__ #define __COMMAND_SURFACE_ROI_COORD_REPORT_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandSurfaceRoiCoordReport : public CommandBase { public: // constructor CommandSurfaceRoiCoordReport(); // destructor ~CommandSurfaceRoiCoordReport(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_ROI_COORD_REPORT_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceRoiCoordReport.cxx0000664000175000017500000001756011572067322030101 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurfaceROINodeSelection.h" #include "BrainModelSurfaceROISurfaceXYZMeansReport.h" #include "BrainSet.h" #include "CommandSurfaceRoiCoordReport.h" #include "FileFilters.h" #include "PaintFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SpecFile.h" #include "TextFile.h" #include "TopologyFile.h" #include "TopologyHelper.h" /** * constructor. */ CommandSurfaceRoiCoordReport::CommandSurfaceRoiCoordReport() : CommandBase("-surface-roi-coord-report", "SURFACE ROI COORD REPORT") { } /** * destructor. */ CommandSurfaceRoiCoordReport::~CommandSurfaceRoiCoordReport() { } /** * get the script builder parameters. */ void CommandSurfaceRoiCoordReport::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Input Paint File Name", FileFilters::getPaintFileFilter()); paramsOut.addString("Paint Column Name or Number"); paramsOut.addString("Paint Name"); paramsOut.addFile("Output Text File Name", FileFilters::getTextFileFilter()); paramsOut.addMultipleFiles("Coordinate File Names", FileFilters::getCoordinateGenericFileFilter()); } /** * get full help information. */ QString CommandSurfaceRoiCoordReport::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Print a report listing the mean X, Y, and Z coordinates for\n" + indent9 + "the nodes identified by the paint name.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceRoiCoordReport::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the parameters // const QString topoFileName = parameters->getNextParameterAsString("Topology File Name"); const QString paintFileName = parameters->getNextParameterAsString("Paint File Name"); const QString paintColumnNameOrNumber = parameters->getNextParameterAsString("Paint Column Number"); const QString paintName = parameters->getNextParameterAsString("Paint Name"); const QString outputTextFileName = parameters->getNextParameterAsString("Output Text File Name"); // // Coordinate files // std::vector inputCoordFileNames; while (parameters->getParametersAvailable()) { inputCoordFileNames.push_back(parameters->getNextParameterAsString("Coordinate File Names")); } const int numInputCoordFiles = static_cast(inputCoordFileNames.size()); if (numInputCoordFiles <= 0) { throw CommandException("No coordinate files are specified."); } // // Read the spec file into a brain set // SpecFile specFile; for (int i = 0; i < numInputCoordFiles; i++) { specFile.addToSpecFile(SpecFile::getFiducialCoordFileTag(), inputCoordFileNames[i], "", false); } specFile.addToSpecFile(SpecFile::getClosedTopoFileTag(), topoFileName, "", false); specFile.addToSpecFile(SpecFile::getPaintFileTag(), paintFileName, "", false); // // Read the spec file into a brain set // QString errorMessage; BrainSet brainSet(true); brainSet.setIgnoreTopologyFileInCoordinateFileHeaderFlag(true); if (brainSet.readSpecFile(specFile, "", errorMessage)) { throw CommandException("Reading spec file: " + errorMessage); } // // Find the paint file column with the proper name // PaintFile* paintFile = brainSet.getPaintFile(); const int paintColumnNumber = paintFile->getColumnFromNameOrNumber(paintColumnNameOrNumber, false); // // Find the index of the paint name // const int paintIndex = paintFile->getPaintIndexFromName(paintName); if (paintIndex < 0) { throw CommandException("Unable to find a paint named " + paintName + " in the paint file."); } // // Find the coordinate files // std::vector coordFiles; for (int i = 0; i < brainSet.getNumberOfBrainModels(); i++) { BrainModelSurface* bms = brainSet.getBrainModelSurface(i); if (bms != NULL) { coordFiles.push_back(bms->getCoordinateFile()); } } const int numCoordFiles = static_cast(coordFiles.size()); if (numCoordFiles <= 0) { throw CommandException("ERROR: No surfaces were read."); } // // Get topology file // if (brainSet.getNumberOfTopologyFiles() < 0) { throw CommandException("ERROR: No topology file was read."); } else if (brainSet.getNumberOfTopologyFiles() > 1) { throw CommandException("ERROR: There is more than one topology file."); } const TopologyFile* topoFile = brainSet.getTopologyFile(0); // // Verify surface has nodes // const int numNodes = brainSet.getNumberOfNodes(); if (numNodes <= 0) { throw CommandException("The surfaces contain no nodes."); } // // Create a topology helper // const TopologyHelper* topologyHelper = topoFile->getTopologyHelper(false, true, false); // // Flag the nodes for the ROI // BrainModelSurfaceROINodeSelection surfaceROINodeSelection(&brainSet); surfaceROINodeSelection.update(); surfaceROINodeSelection.deselectAllNodes(); for (int i = 0; i < numNodes; i++) { if (topologyHelper->getNodeHasNeighbors(i)) { if (paintFile->getPaint(i, paintColumnNumber) == paintIndex) { surfaceROINodeSelection.setNodeSelected(i, 1); } } } // // Generate the report // BrainModelSurfaceROISurfaceXYZMeansReport surfaceROI(&brainSet, brainSet.getBrainModelSurface(0), &surfaceROINodeSelection, coordFiles); surfaceROI.execute(); // // File for text report // TextFile textReportFile; textReportFile.setText(surfaceROI.getReportText()); // // Write the text file // textReportFile.writeFile(outputTextFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceRegistrationSphericalSpecOnly.h0000664000175000017500000000365711572067322032576 0ustar michaelmichael #ifndef __COMMAND_SURFACE_REGISTRATION_SPHERICAL_SPEC_ONLY_H__ #define __COMMAND_SURFACE_REGISTRATION_SPHERICAL_SPEC_ONLY_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for spherical registration with only spec files class CommandSurfaceRegistrationSphericalSpecOnly : public CommandBase { public: // constructor CommandSurfaceRegistrationSphericalSpecOnly(); // destructor ~CommandSurfaceRegistrationSphericalSpecOnly(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_REGISTRATION_SPHERICAL_SPEC_ONLY_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceRegistrationSphericalSpecOnly.cxx0000664000175000017500000002373711572067322033152 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelSurfaceDeformationSpherical.h" #include "BrainSet.h" #include "CommandSurfaceRegistrationSphericalSpecOnly.h" #include "DeformationMapFile.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SpecFile.h" /** * constructor. */ CommandSurfaceRegistrationSphericalSpecOnly::CommandSurfaceRegistrationSphericalSpecOnly() : CommandBase("-surface-register-sphere-spec-only", "SURFACE SPHERICAL REGISTRATION SPEC ONLY") { } /** * destructor. */ CommandSurfaceRegistrationSphericalSpecOnly::~CommandSurfaceRegistrationSphericalSpecOnly() { } /** * get the script builder parameters. */ void CommandSurfaceRegistrationSphericalSpecOnly::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addString("Options", "N"); paramsOut.addFile("Deformation Map File Name", FileFilters::getDeformationMapFileFilter()); paramsOut.addFile("Individual Spec File Name", FileFilters::getSpecFileFilter()); paramsOut.addFile("Atlas Spec File Name", FileFilters::getSpecFileFilter()); } /** * get full help information. */ QString CommandSurfaceRegistrationSphericalSpecOnly::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Peform spherical registration.\n" + indent9 + "\n" + indent9 + "Some files, such as the flat coordinate files or deformation map file\n" + indent9 + "are optional and in this case the name should be specified with two\n" + indent9 + "consecutive double quotes (eg: \"\").\n" + indent9 + "\n" + indent9 + "options - a single character either 'Y' or 'N' \n" + indent9 + " Y - deform the individual to the atlas and the atlas to the individual.\n" + indent9 + " N - deform the individual to the atlas only.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceRegistrationSphericalSpecOnly::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { QString indivBorderFileName; QString indivClosedTopoFileName; QString indivCutTopologyFileName; QString indivFiducialCoordFileName; QString indivSphericalCoordFileName; QString indivFlatCoordFileName; QString atlasBorderFileName; QString atlasClosedTopoFileName; QString atlasCutTopologyFileName; QString atlasFiducialCoordFileName; QString atlasSphericalCoordFileName; QString atlasFlatCoordFileName; const QString options = parameters->getNextParameterAsString("Options"); const QString defMapFileName = parameters->getNextParameterAsString("Deformation Map File Name"); QString individualSpecFileName = parameters->getNextParameterAsString("Individual Spec File Name"); QString atlasSpecFileName = parameters->getNextParameterAsString("Atlas Spec File Name"); QString errorMessage; SpecFile individualSpecFile; individualSpecFile.readFile(individualSpecFileName); if (individualSpecFile.borderProjectionFile.getNumberOfFiles() == 1) { indivBorderFileName = individualSpecFile.borderProjectionFile.getFileName(0); } else { errorMessage.append("Indiv spec file does not have exactly one border projection file.\n"); } if (individualSpecFile.closedTopoFile.getNumberOfFiles() == 1) { indivClosedTopoFileName = individualSpecFile.closedTopoFile.getFileName(0); } else { errorMessage.append("Indiv spec file does not have exactly one closed topology file.\n"); } if (individualSpecFile.cutTopoFile.getNumberOfFiles() > 1) { errorMessage.append("Indiv spec file has more than one cut topology file.\n"); } else if (individualSpecFile.cutTopoFile.getNumberOfFiles() == 1) { indivCutTopologyFileName = individualSpecFile.cutTopoFile.getFileName(0); } if (individualSpecFile.fiducialCoordFile.getNumberOfFiles() == 1) { indivFiducialCoordFileName = individualSpecFile.fiducialCoordFile.getFileName(0); } else { errorMessage.append("Indiv spec file does not have exactly one fiducial coordinate file.\n"); } if (individualSpecFile.sphericalCoordFile.getNumberOfFiles() == 1) { indivSphericalCoordFileName = individualSpecFile.sphericalCoordFile.getFileName(0); } else { errorMessage.append("Indiv spec file does not have exactly one spherical coordinate file.\n"); } if (individualSpecFile.flatCoordFile.getNumberOfFiles() > 1) { errorMessage.append("Indiv spec file has more than one flat coordinate file.\n"); } else if (individualSpecFile.flatCoordFile.getNumberOfFiles() == 1) { indivFlatCoordFileName = individualSpecFile.flatCoordFile.getFileName(0); } SpecFile atlasSpecFile; atlasSpecFile.readFile(atlasSpecFileName); if (atlasSpecFile.borderProjectionFile.getNumberOfFiles() == 1) { atlasBorderFileName = atlasSpecFile.borderProjectionFile.getFileName(0); } else { errorMessage.append("atlas spec file does not have exactly one border projection file.\n"); } if (atlasSpecFile.closedTopoFile.getNumberOfFiles() == 1) { atlasClosedTopoFileName = atlasSpecFile.closedTopoFile.getFileName(0); } else { errorMessage.append("atlas spec file does not have exactly one closed topology file.\n"); } if (atlasSpecFile.cutTopoFile.getNumberOfFiles() > 1) { errorMessage.append("atlas spec file has more than one cut topology file.\n"); } else if (atlasSpecFile.cutTopoFile.getNumberOfFiles() == 1) { atlasCutTopologyFileName = atlasSpecFile.cutTopoFile.getFileName(0); } if (atlasSpecFile.fiducialCoordFile.getNumberOfFiles() == 1) { atlasFiducialCoordFileName = atlasSpecFile.fiducialCoordFile.getFileName(0); } else { errorMessage.append("atlas spec file does not have exactly one fiducial coordinate file.\n"); } if (atlasSpecFile.sphericalCoordFile.getNumberOfFiles() == 1) { atlasSphericalCoordFileName = atlasSpecFile.sphericalCoordFile.getFileName(0); } else { errorMessage.append("atlas spec file does not have exactly one spherical coordinate file.\n"); } if (atlasSpecFile.flatCoordFile.getNumberOfFiles() > 1) { errorMessage.append("atlas spec file has more than one flat coordinate file.\n"); } else if (atlasSpecFile.flatCoordFile.getNumberOfFiles() == 1) { atlasFlatCoordFileName = atlasSpecFile.flatCoordFile.getFileName(0); } if (errorMessage.isEmpty() == false) { throw CommandException(errorMessage); } // // Read in the deformation map (if specified) // DeformationMapFile defMapFile; if (defMapFileName.isEmpty() == false) { defMapFile.readFile(defMapFileName); } // // Process options // defMapFile.setDeformBothWays(false); if (options.length() > 0) { if (options[0] == 'Y') { defMapFile.setDeformBothWays(true); } } // // Spherical deformation // defMapFile.setFlatOrSphereSelection(DeformationMapFile::DEFORMATION_TYPE_SPHERE); // // Make paths absolute // if (QFileInfo(individualSpecFileName).isRelative()) { individualSpecFileName = QFileInfo(individualSpecFileName).absoluteFilePath(); } if (QFileInfo(atlasSpecFileName).isRelative()) { atlasSpecFileName = QFileInfo(atlasSpecFileName).absoluteFilePath(); } // // Set the files // defMapFile.setSourceSpecFileName(individualSpecFileName); defMapFile.setSourceBorderFileName(indivBorderFileName, DeformationMapFile::BORDER_FILE_PROJECTION); defMapFile.setSourceClosedTopoFileName(indivClosedTopoFileName); defMapFile.setSourceCutTopoFileName(indivCutTopologyFileName); defMapFile.setSourceFiducialCoordFileName(indivFiducialCoordFileName); defMapFile.setSourceSphericalCoordFileName(indivSphericalCoordFileName); defMapFile.setSourceDeformedFlatCoordFileName(indivFlatCoordFileName); defMapFile.setTargetSpecFileName(atlasSpecFileName); defMapFile.setTargetBorderFileName(0, atlasBorderFileName, DeformationMapFile::BORDER_FILE_PROJECTION); defMapFile.setTargetClosedTopoFileName(atlasClosedTopoFileName); defMapFile.setTargetCutTopoFileName(atlasCutTopologyFileName); defMapFile.setTargetFiducialCoordFileName(atlasFiducialCoordFileName); defMapFile.setTargetSphericalCoordFileName(atlasSphericalCoordFileName); defMapFile.setTargetFlatCoordFileName(atlasFlatCoordFileName); // // Run the deformation // BrainSet bs; BrainModelSurfaceDeformationSpherical alg(&bs, &defMapFile); alg.execute(); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceRegistrationSpherical.h0000664000175000017500000000354411572067322031114 0ustar michaelmichael #ifndef __COMMAND_SURFACE_REGISTRATION_SPHERICAL_H__ #define __COMMAND_SURFACE_REGISTRATION_SPHERICAL_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for spherical registration class CommandSurfaceRegistrationSpherical : public CommandBase { public: // constructor CommandSurfaceRegistrationSpherical(); // destructor ~CommandSurfaceRegistrationSpherical(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_REGISTRATION_SPHERICAL_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceRegistrationSpherical.cxx0000664000175000017500000002412611572067322031466 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelSurfaceDeformationSpherical.h" #include "BrainSet.h" #include "CommandSurfaceRegistrationSpherical.h" #include "DeformationMapFile.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SpecFile.h" /** * constructor. */ CommandSurfaceRegistrationSpherical::CommandSurfaceRegistrationSpherical() : CommandBase("-surface-register-sphere", "SURFACE SPHERICAL REGISTRATION") { } /** * destructor. */ CommandSurfaceRegistrationSpherical::~CommandSurfaceRegistrationSpherical() { } /** * get the script builder parameters. */ void CommandSurfaceRegistrationSpherical::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addString("Options", "N"); paramsOut.addFile("Deformation Map File Name", FileFilters::getDeformationMapFileFilter()); paramsOut.addFile("Individual Spec File Name", FileFilters::getSpecFileFilter()); paramsOut.addFile("Individual Border Projection File Name", FileFilters::getBorderProjectionFileFilter()); paramsOut.addFile("Individual Closed Topology File Name", FileFilters::getTopologyClosedFileFilter()); paramsOut.addFile("Individual Cut Topology File Name", FileFilters::getTopologyCutFileFilter()); paramsOut.addFile("Individual Fiducial Coordinate File Name", FileFilters::getCoordinateFiducialFileFilter()); paramsOut.addFile("Individual Spherical Coordinate File Name", FileFilters::getCoordinateSphericalFileFilter()); paramsOut.addFile("Individual Flat Coordinate File Name", FileFilters::getCoordinateFlatFileFilter()); paramsOut.addFile("Atlas Spec File Name", FileFilters::getSpecFileFilter()); paramsOut.addFile("Atlas Border Projection File Name", FileFilters::getBorderProjectionFileFilter()); paramsOut.addFile("Atlas Closed Topology File Name", FileFilters::getTopologyClosedFileFilter()); paramsOut.addFile("Atlas Cut Topology File Name", FileFilters::getTopologyCutFileFilter()); paramsOut.addFile("Atlas Fiducial Coordinate File Name", FileFilters::getCoordinateFiducialFileFilter()); paramsOut.addFile("Atlas Spherical Coordinate File Name", FileFilters::getCoordinateSphericalFileFilter()); paramsOut.addFile("Atlas Flat Coordinate File Name", FileFilters::getCoordinateFlatFileFilter()); } /** * get full help information. */ QString CommandSurfaceRegistrationSpherical::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "The above method requires that the each of the spec file have one and only\n" + indent9 + "one border projection file, closed topology file,fiducial coordinate file,\n" + indent9 + "and spherical coordinate file. The spec files may have zero or one\n" + indent9 + "cut topology file and flat coordinate file.\n" + indent9 + "\n" + indent9 + "Each of the individual or atlas data files MUST be listed\n" + indent9 + "in the respective individual or atlas spec files.\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Peform spherical registration.\n" + indent9 + "\n" + indent9 + "Some files, such as the flat coordinate files or deformation map file\n" + indent9 + "are optional and in this case the name should be specified with two\n" + indent9 + "consecutive double quotes (eg: \"\").\n" + indent9 + "\n" + indent9 + "options - a single character either 'Y' or 'N' \n" + indent9 + " Y - deform the individual to the atlas and the atlas to the individual.\n" + indent9 + " N - deform the individual to the atlas only.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceRegistrationSpherical::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString options = parameters->getNextParameterAsString("Options"); const QString defMapFileName = parameters->getNextParameterAsString("Deformation Map File Name"); QString individualSpecFileName = parameters->getNextParameterAsString("Individual Spec File Name"); const QString indivBorderFileName = parameters->getNextParameterAsString("Individual Border Projection File Name"); const QString indivClosedTopoFileName = parameters->getNextParameterAsString("Individual Closed Topology File Name"); const QString indivCutTopologyFileName = parameters->getNextParameterAsString("Individual Cut Topology File Name"); const QString indivFiducialCoordFileName = parameters->getNextParameterAsString("Individual Fiducial Coordinate File Name"); const QString indivSphericalCoordFileName = parameters->getNextParameterAsString("Individual Spherical Coordinate File Name"); const QString indivFlatCoordFileName = parameters->getNextParameterAsString("Individual Flat Coordinate File Name"); QString atlasSpecFileName = parameters->getNextParameterAsString("Atlas Spec File Name"); const QString atlasBorderFileName = parameters->getNextParameterAsString("Atlas Border Projection File Name"); const QString atlasClosedTopoFileName = parameters->getNextParameterAsString("Atlas Closed Topology File Name"); const QString atlasCutTopologyFileName = parameters->getNextParameterAsString("Atlas Cut Topology File Name"); const QString atlasFiducialCoordFileName = parameters->getNextParameterAsString("Atlas Fiducial Coordinate File Name"); const QString atlasSphericalCoordFileName = parameters->getNextParameterAsString("Atlas Spherical Coordinate File Name"); const QString atlasFlatCoordFileName = parameters->getNextParameterAsString("Atlas Flat Coordinate File Name"); // // Read in the deformation map (if specified) // DeformationMapFile defMapFile; if (defMapFileName.isEmpty() == false) { defMapFile.readFile(defMapFileName); } // // Process options // defMapFile.setDeformBothWays(false); if (options.length() > 0) { if (options[0] == 'Y') { defMapFile.setDeformBothWays(true); } } // // Spherical deformation // defMapFile.setFlatOrSphereSelection(DeformationMapFile::DEFORMATION_TYPE_SPHERE); // // Make paths absolute // if (QFileInfo(individualSpecFileName).isRelative()) { individualSpecFileName = QFileInfo(individualSpecFileName).absoluteFilePath(); } if (QFileInfo(atlasSpecFileName).isRelative()) { atlasSpecFileName = QFileInfo(atlasSpecFileName).absoluteFilePath(); } // // Set the files // defMapFile.setSourceSpecFileName(individualSpecFileName); defMapFile.setSourceBorderFileName(indivBorderFileName, DeformationMapFile::BORDER_FILE_PROJECTION); defMapFile.setSourceClosedTopoFileName(indivClosedTopoFileName); defMapFile.setSourceCutTopoFileName(indivCutTopologyFileName); defMapFile.setSourceFiducialCoordFileName(indivFiducialCoordFileName); defMapFile.setSourceSphericalCoordFileName(indivSphericalCoordFileName); defMapFile.setSourceDeformedFlatCoordFileName(indivFlatCoordFileName); defMapFile.setTargetSpecFileName(atlasSpecFileName); defMapFile.setTargetBorderFileName(0, atlasBorderFileName, DeformationMapFile::BORDER_FILE_PROJECTION); defMapFile.setTargetClosedTopoFileName(atlasClosedTopoFileName); defMapFile.setTargetCutTopoFileName(atlasCutTopologyFileName); defMapFile.setTargetFiducialCoordFileName(atlasFiducialCoordFileName); defMapFile.setTargetSphericalCoordFileName(atlasSphericalCoordFileName); defMapFile.setTargetFlatCoordFileName(atlasFlatCoordFileName); // // Run the deformation // BrainSet bs; BrainModelSurfaceDeformationSpherical alg(&bs, &defMapFile); alg.execute(); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceRegistrationPrepareSlits.h0000664000175000017500000000361511572067322031616 0ustar michaelmichael #ifndef __COMMAND_SURFACE_REGISTRATION_PREPARE_SLITS_H__ #define __COMMAND_SURFACE_REGISTRATION_PREPARE_SLITS_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for preparing slits landmarks for registration class CommandSurfaceRegistrationPrepareSlits : public CommandBase { public: // constructor CommandSurfaceRegistrationPrepareSlits(); // destructor ~CommandSurfaceRegistrationPrepareSlits(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_REGISTRATION_PREPARE_SLITS_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceRegistrationPrepareSlits.cxx0000664000175000017500000002377711572067322032204 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BorderProjectionFile.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceDeformationSphericalSlits.h" #include "BrainSet.h" #include "CommandSurfaceRegistrationPrepareSlits.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SpecFile.h" /** * constructor. */ CommandSurfaceRegistrationPrepareSlits::CommandSurfaceRegistrationPrepareSlits() : CommandBase("-surface-register-prepare-slits", "SURFACE SPHERICAL REGISTRATION PREPARE SLIT LANDMARKS") { } /** * destructor. */ CommandSurfaceRegistrationPrepareSlits::~CommandSurfaceRegistrationPrepareSlits() { } /** * get the script builder parameters. */ void CommandSurfaceRegistrationPrepareSlits::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Spec File Name", FileFilters::getSpecFileFilter()); paramsOut.addFile("Input Spherical Coordinate File Name", FileFilters::getCoordinateSphericalFileFilter()); paramsOut.addFile("Input Closed Topology File Name", FileFilters::getTopologyClosedFileFilter()); paramsOut.addFile("Input Border Projection File Name", FileFilters::getBorderProjectionFileFilter()); paramsOut.addFile("Output Cut Spherical Coordinate File Name", FileFilters::getCoordinateSphericalFileFilter()); paramsOut.addFile("Output Cut Topology File Name", FileFilters::getTopologyCutFileFilter()); paramsOut.addFile("Output Closed Smoothed Spherical Coordinate File Name", FileFilters::getCoordinateSphericalFileFilter()); paramsOut.addFile("Output Closed Topology File Name", FileFilters::getTopologyClosedFileFilter()); paramsOut.addFile("Output Border Projection File Name", FileFilters::getBorderProjectionFileFilter()); } /** * get full help information. */ QString CommandSurfaceRegistrationPrepareSlits::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + ".\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "For all borders that begin with the name \"" + BrainModelSurfaceDeformationSphericalSlits::getSlitLandmarkBorderNamePrefix() + "\"\n" + indent9 + "in the input border projection file, use the border to cut\n" + indent9 + "the input spherical surface. The sphere is then smoothed\n" + indent9 + "to open up the holes caused by the cuts. For each of the\n" + indent9 + "slit borders, two new borders are created around the hole \n" + indent9 + "with the suffixes \"PatchA\" and \"PatchB\". The slit \n" + indent9 + "borders are deleted. Use the output-closed-smoothed-\n" + indent9 + "spherical-coordinate-file, the output-closed-topology-file,\n" + indent9 + "and the output-border-projection-file as inputs to the\n" + indent9 + "spherical registration command.\n" + indent9 + "\n" + indent9 + "When performing registration between species, there may\n" + indent9 + "be functional areas that are present in one species but \n" + indent9 + "not in the other. In this case, draw a border at the\n" + indent9 + "location of the \"missing\" area and use this command\n" + indent9 + "to open up that region. On the target subject, draw\n" + indent9 + "two corresponding borders, with the counter-clockwise\n" + indent9 + "half ending in \"PatchA\" and the clockwise half ending\n" + indent9 + "in \"PatchB\".\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceRegistrationPrepareSlits::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the input parameters // const QString specFileName = parameters->getNextParameterAsString("Spec File Name"); const QString inputSphericalCoordinateFileName = parameters->getNextParameterAsString("Input Spherical Coordinate File Name"); const QString inputClosedTopologyFileName = parameters->getNextParameterAsString("Input Closed Topology File Name"); const QString inputBorderProjectionFileName = parameters->getNextParameterAsString("Input Border Projection File Name"); const QString outputCutSphericalCoordinateFileName = parameters->getNextParameterAsString("Output Cut Spherical Coordinate File Name"); const QString outputCutTopologyFileName = parameters->getNextParameterAsString("Output Cut Topology File Name"); const QString outputClosedSmoothedSphericalCoordinateFileName = parameters->getNextParameterAsString("Output Closed Smoothed Spherical Coordinate File Name"); const QString outputClosedTopologyFileName = parameters->getNextParameterAsString("Output Closed Topology File Name"); const QString outputBorderProjectionFileName = parameters->getNextParameterAsString("Output Border Projection File Name"); checkForExcessiveParameters(); // // Create a brain set // BrainSet brainSet(inputClosedTopologyFileName, inputSphericalCoordinateFileName, "", true); // // Verify files read // BrainModelSurface* inputSphericalSurface = brainSet.getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_SPHERICAL); if (inputSphericalSurface == NULL) { throw CommandException("Problem loading spherical surface."); } if (inputSphericalSurface->getTopologyFile() == NULL) { throw CommandException("Topology is missing."); } // // Read tje border projection file // brainSet.readBorderProjectionFile(inputBorderProjectionFileName, false, false); BorderProjectionFile bpf; BrainModelBorderSet* bmbs = brainSet.getBorderSet(); bmbs->copyBordersToBorderProjectionFile(bpf); if (bpf.getNumberOfBorderProjections() <= 0) { throw CommandException("Border projection file is empty."); } // // Set the name of the spec file // brainSet.setSpecFileName(specFileName); // // Perform the deformation // BrainModelSurfaceDeformationSphericalSlits bmsdss(&brainSet, inputSphericalSurface, &bpf); bmsdss.execute(); // // Write the output files // Do topology first so it gets the proper name that is used by coord writing // TopologyFile* outputCutTopologyFile = bmsdss.getCutSphericalSurfaceTopologyFile(); if (outputCutTopologyFile != NULL) { if (outputCutTopologyFileName.isEmpty() == false) { brainSet.writeTopologyFile(outputCutTopologyFileName, TopologyFile::TOPOLOGY_TYPE_CUT, outputCutTopologyFile); } } BrainModelSurface* outputSphericalBMS = bmsdss.getCutSphericalSurface(); if (outputSphericalBMS != NULL) { if (outputCutSphericalCoordinateFileName.isEmpty() == false) { brainSet.writeCoordinateFile(outputCutSphericalCoordinateFileName, BrainModelSurface::SURFACE_TYPE_SPHERICAL, outputSphericalBMS->getCoordinateFile(), true); } } TopologyFile* outputClosedTopologyFile = bmsdss.getSmoothedClosedSphericalSurfaceTopologyFile(); if (outputClosedTopologyFile != NULL) { if (outputClosedTopologyFileName.isEmpty() == false) { brainSet.writeTopologyFile(outputClosedTopologyFileName, TopologyFile::TOPOLOGY_TYPE_CLOSED, outputClosedTopologyFile); } } BrainModelSurface* outputSmoothedSphericalBMS = bmsdss.getSmoothedClosedSphericalSurface(); if (outputSmoothedSphericalBMS != NULL) { if (outputClosedSmoothedSphericalCoordinateFileName.isEmpty() == false) { brainSet.writeCoordinateFile(outputClosedSmoothedSphericalCoordinateFileName, BrainModelSurface::SURFACE_TYPE_SPHERICAL, outputSmoothedSphericalBMS->getCoordinateFile(), true); } } // // Write the output border projection file // if (outputBorderProjectionFileName.isEmpty() == false) { brainSet.writeBorderProjectionFile(outputBorderProjectionFileName, "", "", false); } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceRegionOfInterestSelection.h0000664000175000017500000000507111572067322031700 0ustar michaelmichael #ifndef __COMMAND_SURFACE_REGION_OF_INTEREST_SELECTION_H__ #define __COMMAND_SURFACE_REGION_OF_INTEREST_SELECTION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurfaceROINodeSelection.h" #include "CommandBase.h" /// class for class CommandSurfaceRegionOfInterestSelection : public CommandBase { public: // constructor CommandSurfaceRegionOfInterestSelection(); // destructor ~CommandSurfaceRegionOfInterestSelection(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // extent xyz limit void extentLimit(const BrainModelSurface* bms, BrainModelSurfaceROINodeSelection* roi, const QString& operationName, const float extentValue); // focus xyz limit void focusLimit(const BrainModelSurface* bms, BrainModelSurfaceROINodeSelection* roi, const QString& operationName); // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); // get the selection type BrainModelSurfaceROINodeSelection::SELECTION_LOGIC getSelectionType(const QString& selectionTypeName) const throw (CommandException); }; #endif // __COMMAND_SURFACE_REGION_OF_INTEREST_SELECTION_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceRegionOfInterestSelection.cxx0000664000175000017500000010213511572067322032252 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BorderFile.h" #include "BorderProjectionFile.h" #include "BorderProjectionUnprojector.h" #include "BrainModelSurface.h" #include "BrainSet.h" #include "CommandSurfaceRegionOfInterestSelection.h" #include "CoordinateFile.h" #include "FileFilters.h" #include "FociProjectionFile.h" #include "LatLonFile.h" #include "MetricFile.h" #include "NodeRegionOfInterestFile.h" #include "PaintFile.h" #include "ProgramParameters.h" #include "SurfaceShapeFile.h" #include "TopologyFile.h" /** * constructor. */ CommandSurfaceRegionOfInterestSelection::CommandSurfaceRegionOfInterestSelection() : CommandBase("-surface-region-of-interest-selection", "SURFACE REGION OF INTEREST SELECTION") { } /** * destructor. */ CommandSurfaceRegionOfInterestSelection::~CommandSurfaceRegionOfInterestSelection() { } /** * get the script builder parameters. */ void CommandSurfaceRegionOfInterestSelection::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Input Region of Interest File Name", FileFilters::getRegionOfInterestFileFilter()); paramsOut.addFile("Output Region of Interest File Name", FileFilters::getRegionOfInterestFileFilter()); paramsOut.addVariableListOfParameters("ROI Options"); } /** * get full help information. */ QString CommandSurfaceRegionOfInterestSelection::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + "[-all-nodes] \n" + indent9 + "[-border-projection \n" + indent9 + " border-projection-file-name \n" + indent9 + " border-projection-name \n" + indent9 + " surface-view \n" + indent9 + " dimension \n" + indent9 + " z-minimum \n" + indent9 + " SEL-TYPE] \n" + indent9 + "[-boundary-only] \n" + indent9 + "[-dilate iterations] \n" + indent9 + "[-dilate-paint paint-file-name column paint-name iterations]\n" + indent9 + "[-edges SEL-TYPE] \n" + indent9 + "[-erode iterations] \n" + indent9 + "[-limit-x-lateral x-value] \n" + indent9 + "[-limit-x-medial x-value] \n" + indent9 + "[-limit-x-min x-value] \n" + indent9 + "[-limit-x-max x-value] \n" + indent9 + "[-limit-y-min y-value] \n" + indent9 + "[-limit-y-max y-value] \n" + indent9 + "[-limit-z-min z-value] \n" + indent9 + "[-limit-z-max z-value] \n" + indent9 + "[-limit-x-min-focus fociProjectionFile focusName] \n" + indent9 + "[-limit-x-max-focus fociProjectionFile focusName] \n" + indent9 + "[-limit-y-min-focus fociProjectionFile focusName] \n" + indent9 + "[-limit-y-max-focus fociProjectionFile focusName] \n" + indent9 + "[-limit-z-min-focus fociProjectionFile focusName] \n" + indent9 + "[-limit-z-max-focus fociProjectionFile focusName] \n" + indent9 + "[-metric metric-file-name column min max SEL-TYPE]\n" + indent9 + "[-invert-selection] \n" + indent9 + "[-latlon file-name column min-lat max-lat min-lon max-lon SEL_TYPE]\n" + indent9 + "[-paint paint-file-name column paint-name SEL-TYPE]\n" + indent9 + "[-remove-islands] \n" + indent9 + "[-shape shape-file-name column min max SEL-TYPE]\n" + indent9 + "\n" + indent9 + "The input region of interest file does not need to exist.\n" + indent9 + "\n" + indent9 + "Perform a surface node region of interest selection\n" + indent9 + "\n" + indent9 + "SEL-TYPE is one of \n" + indent9 + " NORMAL Applies selection to all nodes.\n" + indent9 + " AND And (intersection) new selection with the\n" + indent9 + " existing selection.\n" + indent9 + " OR Or (union) new selection with the\n" + indent9 + " existing selection.\n" + indent9 + " ANDNOT And the inverse of the new selection with\n" + indent9 + " existing selection.\n" + indent9 + "\n" + indent9 + "OPERATIONS\n" + indent9 + "\"-all-nodes\" will place all connected nodes into the ROI.\n" + indent9 + "\n" + indent9 + "\"-border-projection\" will place nodes that are inside of\n" + indent9 + " the border into the ROI. When \"dimension\" is 3D, nodes\n" + indent9 + " within the border and whose screen Z-coordinate is greater\n" + indent9 + " than \"z-minimum\" are assigned to the ROI. In most cases,\n" + indent9 + " a \"z-minimum\" of zero is sufficient. If areas within the\n" + indent9 + " border are not assigned, load the surface, click the mouse\n" + indent9 + " on the unassigned nodes to find the value needed for \n" + indent9 + " \"z-minimum\" and create the ROI again.\n" + indent9 + "\n" + indent9 + " \"surface-view\" is one of these single characters:\n" + indent9 + " A - Anterior\n" + indent9 + " D - Dorsal\n" + indent9 + " L - Lateral\n" + indent9 + " M - Medial\n" + indent9 + " P - Posterior\n" + indent9 + " R - Reset (default view)\n" + indent9 + " V - Ventral\n" + indent9 + " \"dimension\" is one of:\n" + indent9 + " 2D \n" + indent9 + " 3D \n" + indent9 + "\n" + indent9 + "\"-boundary-only\" will retain only those nodes that have\n" + indent9 + " at least one neighbor that is NOT in the ROI (interior\n" + indent9 + " nodes are removed).\n" + indent9 + "\n" + indent9 + "\"-dilate\" will dilate the ROI for the specified iterations.\n" + indent9 + "\n" + indent9 + "\"-dilate-paint\" will dilate the ROI but only nodes that have\n" + indent9 + " the specified paint are added to the ROI.\n" + indent9 + "\n" + indent9 + "\"-erode\" will erode the ROI for the specified iterations.\n" + indent9 + "\n" + indent9 + "\"-invert-selection\" will invert the node selection.\n" + indent9 + "\n" + indent9 + "\"-latlon\" will add nodes to the ROI if the nodes lat/long values\n" + indent9 + " are within the specified range of the column.\n" + indent9 + "\n" + indent9 + "\"-metric\" will add nodes to the ROI if the nodes metric value\n" + indent9 + " is within the specified range of the column.\n" + indent9 + "\n" + indent9 + "\"-paint\" will add nodes to the ROI if the nodes paint name\n" + indent9 + " is the specified paint name for the column.\n" + indent9 + "\n" + indent9 + "\"-remove-islands\" will retain only largest set of \n" + indent9 + " connected nodes in the ROI.\n" + indent9 + "\n" + indent9 + "\"-shape\" will add nodes to the ROI if the nodes shape value\n" + indent9 + " is within the specified range of the column.\n" + indent9 + "\n" + indent9 + "NOTES:\n" + indent9 + " The optional parameters (those enclosed in square\n" + indent9 + " brackets) are performed in the order they are\n" + indent9 + " listed on the command line.\n" + indent9 + "\n" + indent9 + " \"column\" is either the number of the column, which\n" + indent9 + " starts at one, or the name of the column. If a\n" + indent9 + " a name contains spaces, it must be enclosed in double \n" + indent9 + " quotes. Name has priority over number.\n" + indent9 + "\n" + indent9 + " When finding nodes enclosed inside a border projection\n" + indent9 + " use a dimension of 2D for flat surfaces. When the \n" + indent9 + " dimension is 2D, the surface view is ignored.\n" + indent9 + " \n" + indent9 + " For three dimensional surfaces (fiducial, inflated,\n" + indent9 + " spherical, etc.), set the dimension to 3D. When determining \n" + indent9 + " nodes within a border projection on a 3D surface, the \n" + indent9 + " surface-view is applied and those nodes with a Z-coordinate\n" + indent9 + " that is greater than Z-coordinate of the center of gravity\n" + indent9 + " and within the border projection are added to the region\n" + indent9 + " of interest.\n" + indent9 + "\n" + indent9 + " When limits are specified with foci, the last focus \n" + indent9 + " with \"focus-name\" found in the file is used.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceRegionOfInterestSelection::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get coord, topo, and roi file names // const QString coordFileName = parameters->getNextParameterAsString("Input Coordinate File Name"); const QString topoFileName = parameters->getNextParameterAsString("Input Topology File Name"); const QString inputRoiFileName = parameters->getNextParameterAsString("Input Region of Interest File Name"); const QString outputRoiFileName = parameters->getNextParameterAsString("Output Region of Interest File Name"); // // Create a brain set // BrainSet brainSet(topoFileName, coordFileName, "", true); const BrainModelSurface* bms = brainSet.getBrainModelSurface(0); if (bms == NULL) { throw CommandException("unable to find surface."); } const TopologyFile* tf = bms->getTopologyFile(); if (tf == NULL) { throw CommandException("unable to find topology."); } const int numNodes = bms->getNumberOfNodes(); if (numNodes == 0) { throw CommandException("surface contains not nodes."); } // // Get the region of interest node selection // BrainModelSurfaceROINodeSelection* roi = brainSet.getBrainModelSurfaceRegionOfInterestNodeSelection(); roi->deselectAllNodes(); // // Read input ROI file // if (inputRoiFileName.isEmpty() == false) { if (QFile::exists(inputRoiFileName)) { NodeRegionOfInterestFile inputROIFile; inputROIFile.readFile(inputRoiFileName); roi->getRegionOfInterestFromFile(inputROIFile); } } // // Process the parameters for node selection // while (parameters->getParametersAvailable()) { // // Get the parameter // const QString parameterName = parameters->getNextParameterAsString("ROI Operation"); if (parameterName == "-all-nodes") { const QString msg = roi->selectAllNodes(bms); if (msg.isEmpty() == false) { throw CommandException(msg); } } else if (parameterName == "-border-projection") { const QString borderProjectionFileName = parameters->getNextParameterAsString("Border Projection File Name"); const QString borderName = parameters->getNextParameterAsString("Border Projection Name"); const QString surfaceViewString = parameters->getNextParameterAsString("Surface View"); const QString dimensionString = parameters->getNextParameterAsString("Dimension"); const float zMinimum = parameters->getNextParameterAsFloat("Z-Minimum"); const BrainModelSurfaceROINodeSelection::SELECTION_LOGIC selectionType = getSelectionType( parameters->getNextParameterAsString("Lat Lon Selection Type")); BrainModel::STANDARD_VIEWS surfaceView = BrainModel::VIEW_NONE; if (surfaceViewString == "A") { surfaceView = BrainModel::VIEW_ANTERIOR; } else if (surfaceViewString == "D") { surfaceView = BrainModel::VIEW_DORSAL; } else if (surfaceViewString == "L") { surfaceView = BrainModel::VIEW_LATERAL; } else if (surfaceViewString == "M") { surfaceView = BrainModel::VIEW_MEDIAL; } else if (surfaceViewString == "P") { surfaceView = BrainModel::VIEW_POSTERIOR; } else if (surfaceViewString == "R") { surfaceView = BrainModel::VIEW_RESET; } else if (surfaceViewString == "V") { surfaceView = BrainModel::VIEW_VENTRAL; } else { throw CommandException("invalid surface view: " + surfaceViewString); } bool dim3D = false; if (dimensionString == "2D") { dim3D = false; } else if (dimensionString == "3D") { dim3D = true; } else { throw CommandException("invalid dimension: " + dimensionString); } // // Read the border projection file // BorderProjectionFile borderProjectionFile; borderProjectionFile.readFile(borderProjectionFileName); // // Find the border // BorderProjection* borderProjection = borderProjectionFile.getLastBorderProjectionByName(borderName); if (borderProjection == NULL) { throw CommandException("no border projection with name: " + borderName); } // // Copy the surface // BrainModelSurface borderSurface(*bms); // // 3D // if (dim3D) { // // Set view // if ((bms->getStructure().getType() != Structure::STRUCTURE_TYPE_CORTEX_LEFT) && (bms->getStructure().getType() != Structure::STRUCTURE_TYPE_CORTEX_RIGHT)) { throw CommandException("Structure is neither right nor left for for 3D" "within border test."); } borderSurface.applyViewToCoordinates(surfaceView); // // Translate to center of mass // borderSurface.translateToCenterOfMass(); } const CoordinateFile* borderCoordinateFile = borderSurface.getCoordinateFile(); // // Create a border projection file with the single projection // BorderProjectionFile tempBorderProjectionFile; tempBorderProjectionFile.addBorderProjection(*borderProjection); // // Unproject the border // BorderFile borderFile; BorderProjectionUnprojector unprojector; unprojector.unprojectBorderProjections(*borderCoordinateFile, tempBorderProjectionFile, borderFile); if (borderFile.getNumberOfBorders() <= 0) { throw CommandException("unprojecting border projection: " + borderName); } // // Get the border from unprojecting // const Border* border = borderFile.getBorder(0); // // select the nodes // const QString msg = roi->selectNodesWithinBorder(selectionType, &borderSurface, border, dim3D, zMinimum); if (msg.isEmpty() == false) { throw CommandException(msg); } } else if (parameterName == "-boundary-only") { roi->boundaryOnly(bms); } else if (parameterName == "-dilate") { const int numberOfIterations = parameters->getNextParameterAsInt("Dilation Iterations"); roi->dilate(bms, numberOfIterations); } else if (parameterName == "-dilate-paint") { const QString paintFileName = parameters->getNextParameterAsString("Dilate Paint File Name"); const QString paintColumn = parameters->getNextParameterAsString("Dilate Paint Column Name or Number"); const QString paintName = parameters->getNextParameterAsString("Dilate Paint Name"); const int iterations = parameters->getNextParameterAsInt("Dilate Paint Iterations"); // // Read the paint file // PaintFile paintFile; paintFile.readFile(paintFileName); // // Get the column number // const int paintColumnNumber = paintFile.getColumnFromNameOrNumber(paintColumn, false); // // Select the nodes // roi->dilatePaintConstrained(bms, &paintFile, paintColumnNumber, paintName, iterations); } else if (parameterName == "-edges") { const BrainModelSurfaceROINodeSelection::SELECTION_LOGIC selectionType = getSelectionType( parameters->getNextParameterAsString("Lat Lon Selection Type")); roi->selectNodesThatAreEdges(selectionType, bms); } else if (parameterName == "-erode") { const int numberOfIterations = parameters->getNextParameterAsInt("Erosion Iterations"); roi->erode(bms, numberOfIterations); } else if (parameterName == "-invert-selection") { roi->invertSelectedNodes(bms); } else if (parameterName == "-latlon") { // // Get the parameters // const QString latLonFileName = parameters->getNextParameterAsString("Lat Lon File Name"); const QString latLonColumn = parameters->getNextParameterAsString("Lat Lon Column Name or Number"); const float minLatValue = parameters->getNextParameterAsFloat("Lat Min Value"); const float maxLatValue = parameters->getNextParameterAsFloat("Lat Max Value"); const float minLonValue = parameters->getNextParameterAsFloat("Lon Min Value"); const float maxLonValue = parameters->getNextParameterAsFloat("Lon Max Value"); const BrainModelSurfaceROINodeSelection::SELECTION_LOGIC selectionType = getSelectionType( parameters->getNextParameterAsString("Lat Lon Selection Type")); // // Read the metric file // LatLonFile latLonFile; latLonFile.readFile(latLonFileName); // // Get the column number // const int latLonColumnNumber = latLonFile.getColumnFromNameOrNumber(latLonColumn, false); // // Select the nodes // const QString msg = roi->selectNodesWithLatLong(selectionType, bms, &latLonFile, latLonColumnNumber, minLatValue, maxLatValue, minLonValue, maxLonValue); if (msg.isEmpty() == false) { throw CommandException(msg); } } else if ((parameterName == "-limit-x-lateral") || (parameterName == "-limit-x-medial") || (parameterName == "-limit-x-min") || (parameterName == "-limit-x-max") || (parameterName == "-limit-y-min") || (parameterName == "-limit-y-max") || (parameterName == "-limit-z-min") || (parameterName == "-limit-z-max")) { const float value = parameters->getNextParameterAsFloat("ROI " + parameterName + " value"); extentLimit(bms, roi, parameterName, value); } else if ((parameterName == "-limit-x-min-focus") || (parameterName == "-limit-x-max-focus") || (parameterName == "-limit-y-min-focus") || (parameterName == "-limit-y-max-focus") || (parameterName == "-limit-z-min-focus") || (parameterName == "-limit-z-max-focus")) { // // limit the ROI // focusLimit(bms, roi, parameterName); } else if (parameterName == "-metric") { // // Get the parameters // const QString metricFileName = parameters->getNextParameterAsString("Metric File Name"); const QString metricColumn = parameters->getNextParameterAsString("Metric Column Name or Number"); const float minValue = parameters->getNextParameterAsFloat("Metric Min Value"); const float maxValue = parameters->getNextParameterAsFloat("Metric Max Value"); const BrainModelSurfaceROINodeSelection::SELECTION_LOGIC selectionType = getSelectionType( parameters->getNextParameterAsString("Metric Selection Type")); // // Read the metric file // MetricFile metricFile; metricFile.readFile(metricFileName); // // Get the column number // const int metricColumnNumber = metricFile.getColumnFromNameOrNumber(metricColumn, false); // // Select the nodes // const QString msg = roi->selectNodesWithMetric(selectionType, bms, &metricFile, metricColumnNumber, minValue, maxValue); if (msg.isEmpty() == false) { throw CommandException(msg); } } else if (parameterName == "-paint") { // // Get the parameters // const QString paintFileName = parameters->getNextParameterAsString("Paint File Name"); const QString paintColumn = parameters->getNextParameterAsString("Paint Column Name or Number"); const QString paintName = parameters->getNextParameterAsString("Paint Name"); const BrainModelSurfaceROINodeSelection::SELECTION_LOGIC selectionType = getSelectionType( parameters->getNextParameterAsString("Paint Selection Type")); // // Read the paint file // PaintFile paintFile; paintFile.readFile(paintFileName); // // Get the column number // const int paintColumnNumber = paintFile.getColumnFromNameOrNumber(paintColumn, false); // // Select the nodes // const QString msg = roi->selectNodesWithPaint(selectionType, bms, &paintFile, paintColumnNumber, paintName); if (msg.isEmpty() == false) { throw CommandException(msg); } } else if (parameterName == "-remove-islands") { roi->discardIslands(bms); } else if (parameterName == "-shape") { // // Get the parameters // const QString shapeFileName = parameters->getNextParameterAsString("Shape File Name"); const QString shapeColumn = parameters->getNextParameterAsString("Shape Column Name or Number"); const float minValue = parameters->getNextParameterAsFloat("Shape Min Value"); const float maxValue = parameters->getNextParameterAsFloat("Shape Max Value"); const BrainModelSurfaceROINodeSelection::SELECTION_LOGIC selectionType = getSelectionType( parameters->getNextParameterAsString("Shape Selection Type")); // // Read the surface shape file // SurfaceShapeFile shapeFile; shapeFile.readFile(shapeFileName); // // Get the column number // const int shapeColumnNumber = shapeFile.getColumnFromNameOrNumber(shapeColumn, false); // // Select the nodes // const QString msg = roi->selectNodesWithSurfaceShape(selectionType, bms, &shapeFile, shapeColumnNumber, minValue, maxValue); if (msg.isEmpty() == false) { throw CommandException(msg); } } else { throw CommandException("Unrecognized operation = \"" + parameterName + "\"."); } } // // Place the selections in a file and write it // NodeRegionOfInterestFile roiFile; roi->setRegionOfInterestIntoFile(roiFile); roiFile.writeFile(outputRoiFileName); } /** * get the selection type. */ BrainModelSurfaceROINodeSelection::SELECTION_LOGIC CommandSurfaceRegionOfInterestSelection::getSelectionType(const QString& selectionTypeName) const throw (CommandException) { BrainModelSurfaceROINodeSelection::SELECTION_LOGIC selType; if (selectionTypeName == "NORMAL") { selType = BrainModelSurfaceROINodeSelection::SELECTION_LOGIC_NORMAL; } else if (selectionTypeName == "AND") { selType = BrainModelSurfaceROINodeSelection::SELECTION_LOGIC_AND; } else if (selectionTypeName == "OR") { selType = BrainModelSurfaceROINodeSelection::SELECTION_LOGIC_OR; } else if (selectionTypeName == "ANDNOT") { selType = BrainModelSurfaceROINodeSelection::SELECTION_LOGIC_AND_NOT; } else { throw CommandException("Invalid selection type: " + selectionTypeName); } return selType; } /** * focus xyz limit. */ void CommandSurfaceRegionOfInterestSelection::focusLimit(const BrainModelSurface* bms, BrainModelSurfaceROINodeSelection* roi, const QString& operationName) { // // Get parameters // const QString fociProjectionFileName = parameters->getNextParameterAsString("Limit Foci Projection File Name"); const QString focusName = parameters->getNextParameterAsString("Limit Focus Name"); // // Get the position of the focus // FociProjectionFile fpf; fpf.readFile(fociProjectionFileName); const CellProjection* focus = fpf.getLastCellProjectionWithName(focusName); if (focus == NULL) { throw CommandException("ROI LIMIT: focus name " + focusName + " not found."); } const bool fiducialSurfaceFlag = (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FIDUCIAL); const bool flatSurfaceFlag = ((bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FLAT) || (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR)); float focusXYZ[3]; if (focus->getProjectedPosition(bms->getCoordinateFile(), bms->getTopologyFile(), fiducialSurfaceFlag, flatSurfaceFlag, false, focusXYZ) == false) { throw CommandException("ROI LIMIT: unable to get projected position for " + focusName); } // // Set the extent for limiting // float extent[6] = { -std::numeric_limits::max(), std::numeric_limits::max(), -std::numeric_limits::max(), std::numeric_limits::max(), -std::numeric_limits::max(), std::numeric_limits::max() }; if (operationName == "-limit-x-min-focus") { extent[0] = focusXYZ[0]; } else if (operationName == "-limit-x-max-focus") { extent[1] = focusXYZ[0]; } else if (operationName == "-limit-y-min-focus") { extent[2] = focusXYZ[1]; } else if (operationName == "-limit-y-max-focus") { extent[3] = focusXYZ[1]; } else if (operationName == "-limit-z-min-focus") { extent[4] = focusXYZ[2]; } else if (operationName == "-limit-z-max-focus") { extent[5] = focusXYZ[2]; } else { throw CommandException("Invalid limit command " + operationName); } // // Limit the ROI // roi->limitExtent(bms, extent); } /** * extent xyz limit. */ void CommandSurfaceRegionOfInterestSelection::extentLimit(const BrainModelSurface* bms, BrainModelSurfaceROINodeSelection* roi, const QString& operationName, const float extentValue) { // // Set the extent for limiting // float extent[6] = { -std::numeric_limits::max(), std::numeric_limits::max(), -std::numeric_limits::max(), std::numeric_limits::max(), -std::numeric_limits::max(), std::numeric_limits::max() }; if (operationName == "-limit-x-lateral") { if (bms->getStructure().getType() == Structure::STRUCTURE_TYPE_CORTEX_LEFT) { extent[0] = -extentValue; } else if (bms->getStructure().getType() == Structure::STRUCTURE_TYPE_CORTEX_RIGHT) { extent[1] = extentValue; } else { throw CommandException("Structure is neither right nor left for lateral x limit"); } } else if (operationName == "-limit-x-medial") { if (bms->getStructure().getType() == Structure::STRUCTURE_TYPE_CORTEX_LEFT) { extent[1] = extentValue; } else if (bms->getStructure().getType() == Structure::STRUCTURE_TYPE_CORTEX_RIGHT) { extent[0] = -extentValue; } else { throw CommandException("Structure is neither right nor left for lateral x limit"); } } else if (operationName == "-limit-x-min") { extent[0] = extentValue; } else if (operationName == "-limit-x-max") { extent[1] = extentValue; } else if (operationName == "-limit-y-min") { extent[2] = extentValue; } else if (operationName == "-limit-y-max") { extent[3] = extentValue; } else if (operationName == "-limit-z-min") { extent[4] = extentValue; } else if (operationName == "-limit-z-max") { extent[5] = extentValue; } // // Limit the ROI // roi->limitExtent(bms, extent); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfacePlaceFociAtLimits.h0000664000175000017500000000460611572067322030103 0ustar michaelmichael #ifndef __COMMAND_SURFACE_PLACE_FOCI_AT_LIMITS_H__ #define __COMMAND_SURFACE_PLACE_FOCI_AT_LIMITS_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" class BrainModelSurface; class FociFile; class FociProjectionFile; /// class for place foci at surface geometric limits class CommandSurfacePlaceFociAtLimits : public CommandBase { public: // constructor CommandSurfacePlaceFociAtLimits(); // destructor ~CommandSurfacePlaceFociAtLimits(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); // Create a focus projection void createFocusProjection(FociProjectionFile& fpf, const QString& name, const BrainModelSurface* fiducialSurface, const int nodeNumber); // Create a focus void createFocus(FociFile& ff, const QString& name, const float xyz[3]); }; #endif // __COMMAND_SURFACE_PLACE_FOCI_AT_LIMITS_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfacePlaceFociAtLimits.cxx0000664000175000017500000003720411572067322030456 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelSurface.h" #include "BrainModelSurfaceROINodeSelection.h" #include "BrainSet.h" #include "CellFileProjector.h" #include "CommandSurfacePlaceFociAtLimits.h" #include "FileFilters.h" #include "FociFile.h" #include "FociProjectionFile.h" #include "NodeRegionOfInterestFile.h" #include "ProgramParameters.h" #include "TopologyFile.h" /** * constructor. */ CommandSurfacePlaceFociAtLimits::CommandSurfacePlaceFociAtLimits() : CommandBase("-surface-place-foci-at-limits", "SURFACE PLACE FOCI AT LIMITS") { } /** * destructor. */ CommandSurfacePlaceFociAtLimits::~CommandSurfacePlaceFociAtLimits() { } /** * get the script builder parameters. */ void CommandSurfacePlaceFociAtLimits::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Fiducial Coordinate File Name", FileFilters::getCoordinateFiducialFileFilter()); paramsOut.addFile("Limit Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Region of Interest File Name", FileFilters::getRegionOfInterestFileFilter()); paramsOut.addFile("Input Foci Projection File Name", FileFilters::getFociProjectionFileFilter()); paramsOut.addFile("Output Foci Projection File Name", FileFilters::getFociProjectionFileFilter()); paramsOut.addVariableListOfParameters("Place Foci at Limit Options"); } /** * get full help information. */ QString CommandSurfacePlaceFociAtLimits::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + "[-x-most-medial focus-name]\n" + indent9 + "[-x-most-lateral focus-name]\n" + indent9 + "[-x-min focus-name] \n" + indent9 + "[-x-max focus-name] \n" + indent9 + "[-x-abs-min focus-name] \n" + indent9 + "[-x-abs-max focus-name] \n" + indent9 + "[-y-min focus-name] \n" + indent9 + "[-y-max focus-name] \n" + indent9 + "[-y-abs-min focus-name] \n" + indent9 + "[-y-abs-max focus-name] \n" + indent9 + "[-z-min focus-name] \n" + indent9 + "[-z-max focus-name] \n" + indent9 + "[-z-abs-min focus-name] \n" + indent9 + "[-z-abs-max focus-name] \n" + indent9 + "[-cog focus-name] \n" + indent9 + "\n" + indent9 + "Determine the limits of a surface and place foci at\n" + indent9 + "the specified limits. The limits are determined on\n" + indent9 + "the \"limit-coord-file-name>\". The fiducial coordinate\n" + indent9 + "file is used to correctly set the focus fiducial position.\n" + indent9 + "\n" + indent9 + "if append foci files is specified, new foci projections \n" + indent9 + "will be appended to the file. \n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfacePlaceFociAtLimits::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get coord, topo, and roi file names // const QString fiducialCoordFileName = parameters->getNextParameterAsString("Input Fiducial Coordinate File Name"); const QString limitCoordFileName = parameters->getNextParameterAsString("Input Limit Coordinate File Name"); const QString topoFileName = parameters->getNextParameterAsString("Input Topology File Name"); const QString roiFileName = parameters->getNextParameterAsString("Region of Interest File Name"); // // Create a brain set // BrainSet brainSet(topoFileName, fiducialCoordFileName, limitCoordFileName, true); BrainModelSurface* fiducialSurface = brainSet.getBrainModelSurface(0); if (fiducialSurface == NULL) { throw CommandException("unable to find fiducial surface."); } BrainModelSurface* limitSurface = brainSet.getBrainModelSurface(1); if (limitSurface == NULL) { if (limitCoordFileName == fiducialCoordFileName) { limitSurface = fiducialSurface; } else { throw CommandException("unable to find limit surface."); } } const TopologyFile* tf = limitSurface->getTopologyFile(); if (tf == NULL) { throw CommandException("unable to find topology."); } const int numNodes = limitSurface->getNumberOfNodes(); if (numNodes == 0) { throw CommandException("surface contains no nodes."); } // // Read the region of interest file // NodeRegionOfInterestFile regionOfInterestFile; regionOfInterestFile.readFile(roiFileName); // // Get and set the region of interest // BrainModelSurfaceROINodeSelection* roi = brainSet.getBrainModelSurfaceRegionOfInterestNodeSelection(); roi->getRegionOfInterestFromFile(regionOfInterestFile); // // Foci file names // const QString inputFociProjectionFileName = parameters->getNextParameterAsString("Input Foci Projection File Name"); const QString outputFociProjectionFileName = parameters->getNextParameterAsString("Output Foci Projection File Name"); // // Get bounds of the region of interest // float bounds[6]; roi->getExtentOfSelectedNodes(limitSurface, bounds); if (roi->getNumberOfNodesSelected() <= 0) { throw CommandException("There are no nodes in the region of interest."); } // // Coordinate file // //const CoordinateFile* fiducialCoordFile = fiducialSurface->getCoordinateFile(); //const CoordinateFile* limitCoordFile = limitSurface->getCoordinateFile(); // // Get nodes at min/max values // int minXNode, maxXNode, minYNode, maxYNode, minZNode, maxZNode; int mostMedialXNode, mostLateralXNode; int absMinXNode, absMaxXNode, absMinYNode, absMaxYNode, absMinZNode, absMaxZNode; roi->getNodesWithMinMaxXYZValues(limitSurface, mostMedialXNode, mostLateralXNode, minXNode, maxXNode, minYNode, maxYNode, minZNode, maxZNode, absMinXNode, absMaxXNode, absMinYNode, absMaxYNode, absMinZNode, absMaxZNode); // // Foci projection file // FociProjectionFile fociProjectionFile; // // Process the parameters for node selection // while (parameters->getParametersAvailable()) { // // Get the next parameter and process it // const QString paramName = parameters->getNextParameterAsString("Next Operation"); if (paramName == "-x-most-medial") { if (mostMedialXNode < 0) { throw CommandException("most medial node unknown." " Is surface structure set?"); } const QString name = parameters->getNextParameterAsString("X-Most-Medial Focus Name"); createFocusProjection(fociProjectionFile, name, fiducialSurface, mostMedialXNode); } else if (paramName == "-x-most-lateral") { if (mostMedialXNode < 0) { throw CommandException("most lateral node unknown." " Is surface structure set?"); } const QString name = parameters->getNextParameterAsString("X-Most-Lateral Focus Name"); createFocusProjection(fociProjectionFile, name, fiducialSurface, mostLateralXNode); } else if (paramName == "-x-min") { const QString name = parameters->getNextParameterAsString("X-Min Focus Name"); createFocusProjection(fociProjectionFile, name, fiducialSurface, minXNode); } else if (paramName == "-x-max") { const QString name = parameters->getNextParameterAsString("X-Max Focus Name"); createFocusProjection(fociProjectionFile, name, fiducialSurface, maxXNode); } else if (paramName == "-x-abs-min") { const QString name = parameters->getNextParameterAsString("X-Abs-Min Focus Name"); createFocusProjection(fociProjectionFile, name, fiducialSurface, absMinXNode); } else if (paramName == "-x-abs-max") { const QString name = parameters->getNextParameterAsString("X-Abs-Max Focus Name"); createFocusProjection(fociProjectionFile, name, fiducialSurface, absMaxXNode); } else if (paramName == "-y-min") { const QString name = parameters->getNextParameterAsString("Y-Min Focus Name"); createFocusProjection(fociProjectionFile, name, fiducialSurface, minYNode); } else if (paramName == "-y-max") { const QString name = parameters->getNextParameterAsString("Y-Max Focus Name"); createFocusProjection(fociProjectionFile, name, fiducialSurface, maxYNode); } else if (paramName == "-y-abs-min") { const QString name = parameters->getNextParameterAsString("Y-Abs-Min Focus Name"); createFocusProjection(fociProjectionFile, name, fiducialSurface, absMinYNode); } else if (paramName == "-y-abs-max") { const QString name = parameters->getNextParameterAsString("Y-Abs-Max Focus Name"); createFocusProjection(fociProjectionFile, name, fiducialSurface, absMaxYNode); } else if (paramName == "-z-min") { const QString name = parameters->getNextParameterAsString("Z-Min Focus Name"); createFocusProjection(fociProjectionFile, name, fiducialSurface, minZNode); } else if (paramName == "-z-max") { const QString name = parameters->getNextParameterAsString("Z-Max Focus Name"); createFocusProjection(fociProjectionFile, name, fiducialSurface, maxZNode); } else if (paramName == "-z-abs-min") { const QString name = parameters->getNextParameterAsString("Z-Abs-Min Focus Name"); createFocusProjection(fociProjectionFile, name, fiducialSurface, absMinZNode); } else if (paramName == "-z-abs-max") { const QString name = parameters->getNextParameterAsString("Z-Abs-Max Focus Name"); createFocusProjection(fociProjectionFile, name, fiducialSurface, absMaxZNode); } else if (paramName == "-cog") { const QString name = parameters->getNextParameterAsString("COG Focus Name"); float xyz[3]; roi->getCenterOfGravityOfSelectedNodes(limitSurface, xyz); FociFile fociFile; createFocus(fociFile, name, xyz); fociProjectionFile.appendFiducialCellFile(fociFile); CellFileProjector projector(fiducialSurface); projector.projectFile(&fociProjectionFile, 0, CellFileProjector::PROJECTION_TYPE_ALL, 0.0, false, NULL); } else { throw CommandException("Unrecognized operation: " + paramName); } } if (fociProjectionFile.getNumberOfCellProjections() <= 0) { throw CommandException("No foci were created."); } // // Append to existing foci projection file // FociProjectionFile outputFociProjectionFile; if (inputFociProjectionFileName.isEmpty() == false) { // // Read current foci projection file // if (QFile::exists(inputFociProjectionFileName)) { outputFociProjectionFile.readFile(inputFociProjectionFileName); } } outputFociProjectionFile.append(fociProjectionFile); // // Write the projection file // outputFociProjectionFile.writeFile(outputFociProjectionFileName); } /** * Create a focus projection. */ void CommandSurfacePlaceFociAtLimits::createFocusProjection(FociProjectionFile& fpf, const QString& name, const BrainModelSurface* fiducialSurface, const int nodeNumber) { // // Add the focus // fpf.addCellProjection(CellProjection(name, fiducialSurface->getCoordinateFile(), nodeNumber, fiducialSurface->getStructure())); } /** * Create a focus. */ void CommandSurfacePlaceFociAtLimits::createFocus(FociFile& ff, const QString& name, const float xyz[3]) { ff.addCell(CellData(name, xyz[0], xyz[1], xyz[2])); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfacePlaceFociAtExtremum.h0000664000175000017500000000354611572067322030452 0ustar michaelmichael #ifndef __COMMAND_SURFACE_PLACE_FOCI_AT_EXTREMUM_H__ #define __COMMAND_SURFACE_PLACE_FOCI_AT_EXTREMUM_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for place foci at surface extremum class CommandSurfacePlaceFociAtExtremum : public CommandBase { public: // constructor CommandSurfacePlaceFociAtExtremum(); // destructor ~CommandSurfacePlaceFociAtExtremum(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_PLACE_FOCI_AT_EXTREMUM_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfacePlaceFociAtExtremum.cxx0000664000175000017500000003462411572067322031026 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurface.h" #include "BrainModelSurfaceFindExtremum.h" #include "BrainModelSurfaceROINodeSelection.h" #include "BrainSet.h" #include "CellFileProjector.h" #include "CommandSurfacePlaceFociAtExtremum.h" #include "FileFilters.h" #include "FociFile.h" #include "FociProjectionFile.h" #include "NodeRegionOfInterestFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "TopologyFile.h" /** * constructor. */ CommandSurfacePlaceFociAtExtremum::CommandSurfacePlaceFociAtExtremum() : CommandBase("-surface-place-focus-at-extremum", "SURFACE PLACE FOCUS AT EXTREMUM") { } /** * destructor. */ CommandSurfacePlaceFociAtExtremum::~CommandSurfacePlaceFociAtExtremum() { } /** * get the script builder parameters. */ void CommandSurfacePlaceFociAtExtremum::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { std::vector extremums; extremums.push_back("X-LATERAL"); extremums.push_back("X-MEDIAL"); extremums.push_back("X-NEG"); extremums.push_back("X-POS"); extremums.push_back("Y-NEG"); extremums.push_back("Y-POS"); extremums.push_back("Z-NEG"); extremums.push_back("Z-POS"); paramsOut.clear(); paramsOut.addFile("Fiducial Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Extremum Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Input Foci Projection File Name", FileFilters::getFociProjectionFileFilter()); paramsOut.addString("Input Focus Name"); paramsOut.addFile("Output Foci Projection File Name", FileFilters::getFociProjectionFileFilter()); paramsOut.addString("Output Focus Name"); paramsOut.addListOfItems("Direction", extremums, extremums); paramsOut.addFloat("Maximum X Movement", 10000000.0, 0.0, 1000000.0); paramsOut.addFloat("Maximum Y Movement", 10000000.0, 0.0, 1000000.0); paramsOut.addFloat("Maximum Z Movement", 10000000.0, 0.0, 1000000.0); paramsOut.addVariableListOfParameters("Information Options"); } /** * get full help information. */ QString CommandSurfacePlaceFociAtExtremum::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-create-roi-from-path roi-file-name.roi] \n" + indent9 + "[-place-foci-along-path]\n" + indent9 + "[-start-offset X Y Z]\n" + indent9 + "\n" + indent9 + "Starting at the position of the input focus, move in the\n" + indent9 + "specified direction along the node mesh until one can move\n" + indent9 + "no further and place a focus at that location.\n" + indent9 + "\n" + indent9 + "EXTREMUM-DIRECTION is one of:\n" + indent9 + " X-LATERAL\n" + indent9 + " X-MEDIAL\n" + indent9 + " X-NEG\n" + indent9 + " X-POS\n" + indent9 + " Y-NEG\n" + indent9 + " Y-POS\n" + indent9 + " Z-NEG\n" + indent9 + " Z-POS\n" + indent9 + "\n" + indent9 + "Uses the last focus with \"input-focus-name\".\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfacePlaceFociAtExtremum::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString fiducialCoordinateFileName = parameters->getNextParameterAsString("Input Fiducial Coordinate File Name"); const QString extremumCoordinateFileName = parameters->getNextParameterAsString("Input Extremum Coordinate File Name"); const QString inputTopologyFileName = parameters->getNextParameterAsString("Input Topology File Name"); const QString inputFociProjectionFileName = parameters->getNextParameterAsString("Input Foci Projection File"); const QString inputFocusName = parameters->getNextParameterAsString("Input Focus Name"); const QString outputFociProjectionFileName = parameters->getNextParameterAsString("Output Foci Projection File Name"); const QString outputFocusName = parameters->getNextParameterAsString("Output Focus Name"); const QString extremumDirection = parameters->getNextParameterAsString("Extremum Direction"); // // set the search direction // BrainModelSurfaceFindExtremum::DIRECTION searchDirection = BrainModelSurfaceFindExtremum::DIRECTION_INVALID; if (extremumDirection == "X-LATERAL") { searchDirection = BrainModelSurfaceFindExtremum::DIRECTION_LATERAL; } else if (extremumDirection == "X-MEDIAL") { searchDirection = BrainModelSurfaceFindExtremum::DIRECTION_MEDIAL; } else if (extremumDirection == "X-NEG") { searchDirection = BrainModelSurfaceFindExtremum::DIRECTION_X_NEGATIVE; } else if (extremumDirection == "X-POS") { searchDirection = BrainModelSurfaceFindExtremum::DIRECTION_X_POSITIVE; } else if (extremumDirection == "Y-NEG") { searchDirection = BrainModelSurfaceFindExtremum::DIRECTION_Y_NEGATIVE; } else if (extremumDirection == "Y-POS") { searchDirection = BrainModelSurfaceFindExtremum::DIRECTION_Y_POSITIVE; } else if (extremumDirection == "Z-NEG") { searchDirection = BrainModelSurfaceFindExtremum::DIRECTION_Z_NEGATIVE; } else if (extremumDirection == "Z-POS") { searchDirection = BrainModelSurfaceFindExtremum::DIRECTION_Z_POSITIVE; } else { throw CommandException("EXTREMUM DIRECTION value invalid: " + extremumDirection); } // // Maximum movements // const float maximumMovementX = parameters->getNextParameterAsFloat("Maximum X Movement"); const float maximumMovementY = parameters->getNextParameterAsFloat("Maximum Y Movement"); const float maximumMovementZ = parameters->getNextParameterAsFloat("Maximum Z Movement"); // // Optional append file names // QString regionOfInterestFileName; bool createROIFlag = false; // // Process the parameters for node selection // bool placeFociAlongPathFlog = false; float startOffset[3] = { 0.0, 0.0, 0.0 }; while (parameters->getParametersAvailable()) { // // Get the next parameter and process it // const QString paramName = parameters->getNextParameterAsString("Next Operation"); if (paramName == "-create-roi-from-path") { regionOfInterestFileName = parameters->getNextParameterAsString("Region of Interest File Name"); createROIFlag = true; } else if (paramName == "-place-foci-along-path") { placeFociAlongPathFlog = true; } else if (paramName == "-start-offset") { startOffset[0] = parameters->getNextParameterAsFloat("Start Offset X"); startOffset[1] = parameters->getNextParameterAsFloat("Start Offset Y"); startOffset[2] = parameters->getNextParameterAsFloat("Start Offset X"); } else { throw CommandException("Unrecognized operation: " + paramName); } } // // Create a brain set // BrainSet brainSet(inputTopologyFileName, fiducialCoordinateFileName, extremumCoordinateFileName, true); BrainModelSurface* fiducialSurface = brainSet.getBrainModelSurface(0); if (fiducialSurface == NULL) { throw CommandException("unable to find fiducial surface."); } BrainModelSurface* extremumSurface = brainSet.getBrainModelSurface(1); if (extremumSurface == NULL) { if (extremumCoordinateFileName == fiducialCoordinateFileName) { extremumSurface = fiducialSurface; } else { throw CommandException("unable to find extremum surface."); } } const TopologyFile* tf = extremumSurface->getTopologyFile(); if (tf == NULL) { throw CommandException("unable to find topology."); } const int numNodes = extremumSurface->getNumberOfNodes(); if (numNodes == 0) { throw CommandException("surface contains no nodes."); } // // Read the input focus projection file // FociProjectionFile fociProjectionFile; fociProjectionFile.readFile(inputFociProjectionFileName); // // Get the focus with the specified name // const CellProjection* inputFocus = fociProjectionFile.getLastCellProjectionWithName(inputFocusName); if (inputFocus == NULL) { throw CommandException("Cannot find focus " "with name " + inputFocusName); } // // Get position of input focus // const bool fiducialSurfaceFlag = (extremumSurface->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FIDUCIAL); const bool flatSurfaceFlag = ((extremumSurface->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FLAT) || (extremumSurface->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR)); float inputFocusXYZ[3]; if (inputFocus->getProjectedPosition(extremumSurface->getCoordinateFile(), extremumSurface->getTopologyFile(), fiducialSurfaceFlag, flatSurfaceFlag, false, inputFocusXYZ) == false) { throw CommandException("unable to get projected position for " + inputFocusName); } // // Add start offset to // inputFocusXYZ[0] += startOffset[0]; inputFocusXYZ[1] += startOffset[1]; inputFocusXYZ[2] += startOffset[2]; // // Get the extremum // BrainModelSurfaceFindExtremum bmsfe(&brainSet, extremumSurface, searchDirection, inputFocusXYZ, maximumMovementX, maximumMovementY, maximumMovementZ); bmsfe.execute(); // // Get the coordinate of the extremum node // const int extremumNode = bmsfe.getExtremumNode(); if (extremumNode < 0) { throw CommandException("search for extremum node failed."); } // if (DebugControl::getDebugOn()) { const CoordinateFile* extremumCoordFile = extremumSurface->getCoordinateFile(); const float* extremumXYZ = extremumCoordFile->getCoordinate(extremumNode); std::cout << "Extremum (" << outputFocusName.toAscii().constData() << ") start: " << inputFocusXYZ[0] << " " << inputFocusXYZ[1] << " " << inputFocusXYZ[2] << " " << " end: " << extremumXYZ[0] << " " << extremumXYZ[1] << " " << extremumXYZ[2] << std::endl; //} const CoordinateFile* fiducialCoordFile = fiducialSurface->getCoordinateFile(); // // Foci projection file // FociProjectionFile outputFociProjectionFile; // // Add focus projection // fociProjectionFile.addCellProjection(CellProjection(outputFocusName, fiducialCoordFile, extremumNode, fiducialSurface->getStructure())); // // Place foci along the path from start to extremum node? // if (placeFociAlongPathFlog) { // // Get nodes in path // std::vector nodesInPath; bmsfe.getNodeInPathToExtremum(nodesInPath); // // Skip start and final nodes // const int startNode = 1; const int endNode = static_cast(nodesInPath.size()) - 1; for (int i = startNode; i < endNode; i++) { // // Place a focus at the node in the path // fociProjectionFile.addCellProjection(CellProjection(outputFocusName, fiducialCoordFile, nodesInPath[i], fiducialSurface->getStructure())); } } // // Create a region of interest from the path // if (createROIFlag) { BrainModelSurfaceROINodeSelection roi(&brainSet); bmsfe.setRegionOfInterestToNodesInPath(roi); NodeRegionOfInterestFile roiFile; roi.setRegionOfInterestIntoFile(roiFile); roiFile.writeFile(regionOfInterestFileName); } // // Write the projection file // fociProjectionFile.writeFile(outputFociProjectionFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceNormals.h0000664000175000017500000000335511572067322026222 0ustar michaelmichael #ifndef __COMMAND_SURFACE_NORMALS_H__ #define __COMMAND_SURFACE_NORMALS_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for surface normals class CommandSurfaceNormals : public CommandBase { public: // constructor CommandSurfaceNormals(); // destructor ~CommandSurfaceNormals(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_NORMALS_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceNormals.cxx0000664000175000017500000001124011572067322026565 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurface.h" #include "BrainSet.h" #include "CommandSurfaceNormals.h" #include "FileFilters.h" #include "GiftiCommon.h" #include "GiftiDataArray.h" #include "GiftiDataArrayFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandSurfaceNormals::CommandSurfaceNormals() : CommandBase("-surface-normals", "SURFACE NORMALS") { } /** * destructor. */ CommandSurfaceNormals::~CommandSurfaceNormals() { } /** * get the script builder parameters. */ void CommandSurfaceNormals::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Output GIFTI Vector File Name", FileFilters::getGiftiVectorFileFilter()); } /** * get full help information. */ QString CommandSurfaceNormals::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Write surface normals into a GIFTI Vector File.\n" + indent9 + "The GIFTI Vector File will contain a two-dimensional\n" + indent9 + "data array with dimensions (number-of-nodes, 3). \n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceNormals::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString coordinateFileName = parameters->getNextParameterAsString("Coordinate File Name"); const QString topologyFileName = parameters->getNextParameterAsString("Topology File Name"); const QString outputGiftiVectorFileName = parameters->getNextParameterAsString("Output GIFTI Vector File Name"); // // Create a brain set // BrainSet brainSet(topologyFileName, coordinateFileName, "", true); BrainModelSurface* bms = brainSet.getBrainModelSurface(0); if (bms == NULL) { throw CommandException("unable to find surface."); } const TopologyFile* tf = bms->getTopologyFile(); if (tf == NULL) { throw CommandException("unable to find topology."); } const int numNodes = bms->getNumberOfNodes(); if (numNodes == 0) { throw CommandException("surface contains not nodes."); } // // Create the data array for the normals // std::vector dim; dim.push_back(numNodes); dim.push_back(3); GiftiDataArrayFile vectorFile; GiftiDataArray* gda = new GiftiDataArray(&vectorFile, GiftiCommon::intentVectors, GiftiDataArray::DATA_TYPE_FLOAT32, dim); vectorFile.addDataArray(gda); gda->getMetaData()->set("Name", "Surface Normals"); // // Add normals // bms->computeNormals(); for (int i = 0; i < numNodes; i++) { const float* normal = bms->getNormal(i); for (int j = 0; j < 3; j++) { int indices[2] = { i, j }; gda->setDataFloat32(indices, normal[j]); } } // // Write the vector file // vectorFile.writeFile(outputGiftiVectorFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceInformation.h0000664000175000017500000000344211572067322027071 0ustar michaelmichael #ifndef __COMMAND_SURFACE_INFORMATION_H__ #define __COMMAND_SURFACE_INFORMATION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for surface information class CommandSurfaceInformation : public CommandBase { public: // constructor CommandSurfaceInformation(); // destructor ~CommandSurfaceInformation(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_INFORMATION_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceInformation.cxx0000664000175000017500000001353211572067322027445 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelSurface.h" #include "BrainSet.h" #include "CommandSurfaceInformation.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "TextFile.h" /** * constructor. */ CommandSurfaceInformation::CommandSurfaceInformation() : CommandBase("-surface-information", "SURFACE INFORMATION") { } /** * destructor. */ CommandSurfaceInformation::~CommandSurfaceInformation() { } /** * get the script builder parameters. */ void CommandSurfaceInformation::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addVariableListOfParameters("Information Options"); } /** * get full help information. */ QString CommandSurfaceInformation::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + "[-show-volume] \n" + indent9 + "[-text-file output-text-file-name] \n" + indent9 + "\n" + indent9 + "Display information about a surface.\n" + indent9 + "\n" + indent9 + "If \"-show-volume\" is specified, the volume displaced in\n" + indent9 + "cubic millimeters is displayed. The supplied topology file \n" + indent9 + "MUST be CLOSED if this option is used. Use of this option\n" + indent9 + "may significantly increase the execution time of this \n" + indent9 + "command.\n" + indent9 + "\n" + indent9 + "The information is printed to the terminal unless a\n" + indent9 + "text file is specified with the \"-text-file\" option.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceInformation::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString coordinateFileName = parameters->getNextParameterAsString("Coordinate File Name"); const QString topologyFileName = parameters->getNextParameterAsString("Topology File Name"); // // Check optional parameters // QString textFileName; bool showVolumeFlag = false; while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("SURFACE INFORMATION parameter"); if ("-show-volume") { showVolumeFlag = true; } else if (paramName == "-text-file") { textFileName = parameters->getNextParameterAsString("Text File Name"); } else { throw CommandException("unknown parameter: " + paramName); } } // // Create a brain set // BrainSet brainSet(topologyFileName, coordinateFileName, "", true); BrainModelSurface* bms = brainSet.getBrainModelSurface(0); if (bms == NULL) { throw CommandException("unable to find surface."); } const TopologyFile* tf = bms->getTopologyFile(); if (tf == NULL) { throw CommandException("unable to find topology."); } const int numNodes = bms->getNumberOfNodes(); if (numNodes == 0) { throw CommandException("surface contains not nodes."); } // // Get the surface information // std::vector labels, values; bms->getSurfaceInformation(labels, values); if (showVolumeFlag) { const float volumeMM = bms->getSurfaceVolumeDisplacement(); labels.push_back("Volume Displacement"); if (volumeMM < 0.0) { values.push_back("Volume computation failed. Open Topology?"); } else { values.push_back(QString::number(volumeMM, 'f', 3) + " cubic millimeters"); } } // // Determine minimum width for labels // const int numItems = static_cast(labels.size()); int minWidth = 1; for (int i = 0; i < numItems; i++) { minWidth = std::max(minWidth, labels[i].length()); } minWidth += 2; QString s; for (int i = 0; i < numItems; i++) { const QString space((minWidth - labels[i].size()), QChar(' ')); s += (labels[i] + ":" + space + values[i] + "\n"); } if (textFileName.isEmpty() == false) { TextFile textFile; textFile.setText(s); textFile.writeFile(textFileName); } else { std::cout << s.toAscii().constData() << std::endl; } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceInflate.h0000664000175000017500000000336611572067322026173 0ustar michaelmichael #ifndef __COMMAND_SURFACE_INFLATE_H__ #define __COMMAND_SURFACE_INFLATE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandSurfaceInflate : public CommandBase { public: // constructor CommandSurfaceInflate(); // destructor ~CommandSurfaceInflate(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_INFLATE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceInflate.cxx0000664000175000017500000001643211572067322026544 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurface.h" #include "BrainSet.h" #include "CommandSurfaceInflate.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandSurfaceInflate::CommandSurfaceInflate() : CommandBase("-surface-inflate", "SURFACE INFLATE") { } /** * destructor. */ CommandSurfaceInflate::~CommandSurfaceInflate() { } /** * get the script builder parameters. */ void CommandSurfaceInflate::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input FiducialCoordinate File", FileFilters::getCoordinateFiducialFileFilter()); paramsOut.addFile("Input Smoothing Coordinate File", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Input Smoothing Topology File", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Output Smoothed Coordinate File", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addInt("Smoothing Cycles", 2); paramsOut.addFloat("Smoothing Strength", 1.0); paramsOut.addInt("Smoothing Iterations", 100); paramsOut.addFloat("Inflation Factor", 1.4); paramsOut.addInt("Finger Smoothing Iterations", 30); paramsOut.addFloat("Finger Smoothing Strength", 1.0); paramsOut.addFloat("Finger Smoothing Compress/Stretch Threshold", 3.0); } /** * get full help information. */ QString CommandSurfaceInflate::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Inflate a surface.\n" + indent9 + "\n" + indent9 + "Sequence to start with fiducial and create low smooth\n" + indent9 + "(low), inflated (INF), Very Inflated (VI), high smooth\n" + indent9 + "(high), and Ellipse Surfaces.\n" + indent9 + " low INF VI high Ellipse\n" + indent9 + "cycles 1 2 4 6 6\n" + indent9 + "strength 0.2 1.0 1.0 1.0 1.0\n" + indent9 + "iterations 50 30 30 60 50\n" + indent9 + "inflate-factor 1.0 1.4 1.1 1.6 1.4\n" + indent9 + "fing-iter 0 30 0 60 60\n" + indent9 + "fing-strength 1.0 1.0 1.0 1.0 1.0\n" + indent9 + "fing-cst 3.0 3.0 3.0 3.0 4.0\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceInflate::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputFiducialCoordinateFileName = parameters->getNextParameterAsString("Input Fiducial Coordinate File Name"); const QString inputCoordinateFileName = parameters->getNextParameterAsString("Input Smoothing Coordinate File Name"); const QString inputTopologyFileName = parameters->getNextParameterAsString("Input Smoothing Topology File Name"); const QString outputCoordinateFileName = parameters->getNextParameterAsString("Output Smoothed Coordinate File Name"); const int numberOfSmoothingCycles = parameters->getNextParameterAsInt("Number of Smoothing Cycles"); const float smoothingStrength = parameters->getNextParameterAsFloat("Smoothing Strength"); const int smoothingIterations = parameters->getNextParameterAsInt("Smoothing Iterations"); const float inflationFactor = parameters->getNextParameterAsFloat("Inflation Factor"); const int fingerSmoothingIterations = parameters->getNextParameterAsInt("Finger Smoothing Iterations"); const float fingerSmoothingStrength = parameters->getNextParameterAsFloat("Finger Smoothing Strength"); const float fingerSmoothingCompressStretchThreshold = parameters->getNextParameterAsFloat("Finger Smoothing Compress Stretch Threshold"); // // Create a brain set // BrainSet brainSet(inputTopologyFileName, inputFiducialCoordinateFileName, "", true); brainSet.readCoordinateFile(inputCoordinateFileName, BrainModelSurface::SURFACE_TYPE_UNKNOWN, false, true, false); BrainModelSurface* fiducialSurface = brainSet.getBrainModelSurface(0); BrainModelSurface* smoothingSurface = brainSet.getBrainModelSurface(1); if ((fiducialSurface == NULL) || (smoothingSurface == NULL)) { throw CommandException("Problem reading one or both surfaces."); } const TopologyFile* tf = smoothingSurface->getTopologyFile(); if (tf == NULL) { throw CommandException("Problem reading topology file."); } // // Smooth the surface // smoothingSurface->inflateSurfaceAndSmoothFingers(fiducialSurface, numberOfSmoothingCycles, smoothingStrength, smoothingIterations, inflationFactor, fingerSmoothingCompressStretchThreshold, fingerSmoothingStrength, fingerSmoothingIterations, NULL); // // Write the smoothed coordinate file // smoothingSurface->getCoordinateFile()->writeFile(outputCoordinateFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceIdentifySulci.h0000664000175000017500000000345411572067322027362 0ustar michaelmichael #ifndef __COMMAND_SURFACE_IDENTIFY_SULCI_H__ #define __COMMAND_SURFACE_IDENTIFY_SULCI_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for identify sulci class CommandSurfaceIdentifySulci : public CommandBase { public: // constructor CommandSurfaceIdentifySulci(); // destructor ~CommandSurfaceIdentifySulci(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_IDENTIFY_SULCI_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceIdentifySulci.cxx0000664000175000017500000001772611572067322027744 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelVolumeSureFitSegmentation.h" #include "BrainSet.h" #include "CommandSurfaceIdentifySulci.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SpecFile.h" #include "VolumeFile.h" /** * constructor. */ CommandSurfaceIdentifySulci::CommandSurfaceIdentifySulci() : CommandBase("-surface-identify-sulci", "SURFACE IDENTIFY SULCI") { } /** * destructor. */ CommandSurfaceIdentifySulci::~CommandSurfaceIdentifySulci() { } /** * get the script builder parameters. */ void CommandSurfaceIdentifySulci::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { std::vector values, descriptions; values.push_back("NIFTI"); descriptions.push_back("NIFTI"); values.push_back("AFNI"); descriptions.push_back("AFNI"); values.push_back("SPM"); descriptions.push_back("SPM"); values.push_back("WUNIL"); descriptions.push_back("WUNIL"); std::vector structValues, structDescriptions; structValues.push_back("LEFT"); structDescriptions.push_back("LEFT"); structValues.push_back("RIGHT"); structDescriptions.push_back("RIGHT"); paramsOut.clear(); paramsOut.addFile("Spec File Name", FileFilters::getSpecFileFilter()); paramsOut.addListOfItems("Structure", structValues, structDescriptions); paramsOut.addFile("Segmentation Volume File Name", FileFilters::getVolumeSegmentationFileFilter()); paramsOut.addFile("Closed Topology File Name", FileFilters::getTopologyClosedFileFilter()); paramsOut.addFile("Raw Coordinate File Name", FileFilters::getCoordinateRawFileFilter()); paramsOut.addFile("Fiducial Coordinate File Name", FileFilters::getCoordinateFiducialFileFilter()); paramsOut.addListOfItems("Volume Write Type", values, descriptions); } /** * get full help information. */ QString CommandSurfaceIdentifySulci::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Identify Sulci with shape and paint.\n" + indent9 + "\n" + indent9 + "Create a surface shape file containing depth and curvature measurements,\n" + indent9 + "a paint file identifying the sulci, and an area color file. If there\n" + indent9 + "is no raw coordinate file, specify fiducial coordinate file instead.\n" + indent9 + "\n" + indent9 + "NOTE: This command MUST be run in the directory containing the files.\n" + indent9 + "\n" + indent9 + "structure Specifies the brain structure. \n" + indent9 + " Acceptable values are RIGHT or LEFT \n" + indent9 + " \n" + indent9 + "write-volume-type Type of volume files to write. \n" + indent9 + " Specifies the type of the volume files that will be written \n" + indent9 + " during the segmentation process. Valid values are: \n" + indent9 + " AFNI \n" + indent9 + " NIFTI \n" + indent9 + " NIFTI_GZIP (RECOMMENDED!!!!) \n" + indent9 + " SPM \n" + indent9 + " WUNIL \n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceIdentifySulci::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString specFileName = parameters->getNextParameterAsString("Spec File Name"); const QString structureName = parameters->getNextParameterAsString("Structure Name").toUpper(); const QString segmentationVolumeFileName = parameters->getNextParameterAsString("Segmentation Volume File Name"); const QString closedTopologyFileName = parameters->getNextParameterAsString("Closed Topology File Name"); const QString rawCoordinateFileName = parameters->getNextParameterAsString("Raw Coordinate File Name"); const QString fiducialCoordinateFileName = parameters->getNextParameterAsString("Fiducial Coordinate File Name"); const QString writeVolumeTypeString = parameters->getNextParameterAsString("Write Volume Type"); checkForExcessiveParameters(); VolumeFile::FILE_READ_WRITE_TYPE writeVolumeType = VolumeFile::FILE_READ_WRITE_TYPE_NIFTI_GZIP; if (writeVolumeTypeString == "AFNI") { writeVolumeType = VolumeFile::FILE_READ_WRITE_TYPE_AFNI; } else if (writeVolumeTypeString == "NIFTI") { writeVolumeType = VolumeFile::FILE_READ_WRITE_TYPE_NIFTI; } else if (writeVolumeTypeString == "NIFTI_GZIP") { writeVolumeType = VolumeFile::FILE_READ_WRITE_TYPE_NIFTI_GZIP; } else if (writeVolumeTypeString == "SPM") { writeVolumeType = VolumeFile::FILE_READ_WRITE_TYPE_SPM_OR_MEDX; } else if (writeVolumeTypeString == "WUNIL") { writeVolumeType = VolumeFile::FILE_READ_WRITE_TYPE_WUNIL; } else { throw CommandException("Invalid volume file write type: " + + writeVolumeType); } // // Load the segmentation volume to get the data file name // VolumeFile volTest; QString segmentationVolumeDataFileName; volTest.readFileMetaDataOnly(segmentationVolumeFileName); segmentationVolumeDataFileName = volTest.getDataFileName(); // // Read spec file // SpecFile specFile; specFile.readFile(specFileName); // // Set the selected files // specFile.setAllFileSelections(SpecFile::SPEC_FALSE); specFile.addToSpecFile(SpecFile::getVolumeSegmentationFileTag(), segmentationVolumeFileName, segmentationVolumeDataFileName, SpecFile::SPEC_FALSE); specFile.addToSpecFile(SpecFile::getClosedTopoFileTag(), closedTopologyFileName, "", SpecFile::SPEC_FALSE); specFile.addToSpecFile(SpecFile::getRawCoordFileTag(), rawCoordinateFileName, "", SpecFile::SPEC_FALSE); specFile.addToSpecFile(SpecFile::getFiducialCoordFileTag(), fiducialCoordinateFileName, "", SpecFile::SPEC_FALSE); // // Read the spec file into a brain set // QString errorMessage; BrainSet brainSet(true); if (brainSet.readSpecFile(specFile, specFileName, errorMessage)) { throw CommandException("Reading spec file: " + errorMessage); } // // Identify the sulci // Structure structure(structureName); BrainModelVolumeSureFitSegmentation bmsf(&brainSet, structure.getType(), writeVolumeType, true); bmsf.executeIdentifySulci(); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceGeodesic.h0000664000175000017500000000337411572067322026332 0ustar michaelmichael #ifndef __COMMAND_SURFACE_GEODESIC_H__ #define __COMMAND_SURFACE_GEODESIC_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandSurfaceGeodesic : public CommandBase { public: // constructor CommandSurfaceGeodesic(); // destructor ~CommandSurfaceGeodesic(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_GEODESIC_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceGeodesic.cxx0000664000175000017500000001601711572067322026703 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "CommandSurfaceGeodesic.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "BrainSet.h" #include "StringUtilities.h" #include "FileUtilities.h" #include "MetricFile.h" #include "CoordinateFile.h" #include "TopologyFile.h" #include "GeodesicHelper.h" /** * constructor. */ CommandSurfaceGeodesic::CommandSurfaceGeodesic() : CommandBase("-surface-geodesic", "SURFACE GEODESIC DISTANCE") { } /** * destructor. */ CommandSurfaceGeodesic::~CommandSurfaceGeodesic() { } /** * get the script builder parameters. */ void CommandSurfaceGeodesic::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Coordinate File", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Input Topology File", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Output Metric File", FileFilters::getMetricFileFilter()); paramsOut.addBoolean("Smoothing", false); paramsOut.addVariableListOfParameters("Options"); } /** * get full help information. */ QString CommandSurfaceGeodesic::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-node node-number]\n" + indent9 + "\n" + indent9 + "Generate the geodesic distance from all nodes to all other nodes\n" + indent9 + "unless a node number is specified in which case the distances are\n" + indent9 + "output for the specified node to all nodes.\n" + indent9 + "Uses dijkstra's algorithm with reuse of information from previous\n" + indent9 + "root nodes. If smoothed is 'true', it traces paths over adjacent\n" + indent9 + "triangles in order to generate distances for some 2hop neighbors.\n" + indent9 + "This causes the contours of equal distance to be closer to circular,\n" + indent9 + "and also makes the distances more consistent for a mesh which has\n" + indent9 + "been streched nonuniformly. It is almost as fast as unsmoothed.\n" + indent9 + "\n" + indent9 + " surface-coord the surface coord file\n" + indent9 + "\n" + indent9 + " surface-topo the surface topo file\n" + indent9 + "\n" + indent9 + " output-metric output metric file for geodesic distance\n" + indent9 + "\n" + indent9 + " smoothed output smoothed distances by using 2hop neighbors\n" + indent9 + "\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceGeodesic::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString coord = parameters->getNextParameterAsString("Input Coordinate File"); const QString topo = parameters->getNextParameterAsString("Input Topology File"); const QString metricName = parameters->getNextParameterAsString("Output Metric File"); const bool smooth = parameters->getNextParameterAsBoolean("Smoothing"); int nodeNumber = -1; while (parameters->getParametersAvailable()) { QString paramName = parameters->getNextParameterAsString("Geodesic Parameter"); if (paramName == "-node") { nodeNumber = parameters->getNextParameterAsInt("Node Number"); } else { throw CommandException("Invalid Parameter: " + paramName); } } BrainSet mybs(topo, coord);//yes, its hideous, but the BrainSet constructor is such an easy way to load them BrainModelSurface* mysurf = mybs.getBrainModelSurface(0); int numNodes = mysurf->getCoordinateFile()->getNumberOfNodes(); GeodesicHelper gh(mysurf->getCoordinateFile(), mysurf->getTopologyFile()); if (nodeNumber >= 0) { #ifdef _USE_STL_FOR_DATA_ std::vector allNodeIndices; allNodeIndices.reserve(numNodes); for (int i = 0; i < numNodes; i++) { allNodeIndices.push_back(i); } std::vector distances; gh.getGeoToTheseNodes(nodeNumber, allNodeIndices, distances, smooth); if (static_cast(distances.size()) == numNodes) { MetricFile mymetric; mymetric.setNumberOfNodesAndColumns(numNodes, 1); mymetric.setColumnForAllNodes(0, distances); mymetric.setColumnName(0, "Node " + QString::number(nodeNumber)); mymetric.writeFile(metricName); } else { std::cerr << "getGeoToTheseNodes() failed." << std::endl; } #else float* distances = new float[numNodes]; gh.getGeoFromNode(nodeNumber, distances, smooth); MetricFile mymetric; mymetric.setNumberOfNodesAndColumns(numNodes, 1); mymetric.setColumnForAllNodes(0, distances); mymetric.setColumnName(0, "Node " + QString::number(nodeNumber)); mymetric.writeFile(metricName); #endif } else { float** result = gh.getGeoAllToAll(smooth);//PASSES BACK ALLOCATED MEMORY, we must delete[] all of it //was more convinient to write the code to catch malloc failures into that function, does not crash if failed, merely deallocates //everything that it succeeded in allocating, then returns NULL if (result != NULL)//happens if memory runs out { std::cout << "saving to " << metricName.toLocal8Bit().constData() << "..." << std::endl; MetricFile mymetric; mymetric.setNumberOfNodesAndColumns(numNodes, numNodes); for (int i = 0; i < numNodes; ++i) { mymetric.setColumnForAllNodes(i, result[i]); delete[] result[i]; } delete[] result; mymetric.writeFile(metricName); } else { std::cerr << "getGeoAllToAll() failed." << std::endl; } } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceGenerateInflated.h0000664000175000017500000000430111572067322030000 0ustar michaelmichael #ifndef __COMMAND_SURFACE_GENERATE_INFLATED_H__ #define __COMMAND_SURFACE_GENERATE_INFLATED_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" class BrainModelSurface; /// class for generating inflated, ellipsoid, and spherical surfaces class CommandSurfaceGenerateInflated : public CommandBase { public: // constructor CommandSurfaceGenerateInflated(); // destructor ~CommandSurfaceGenerateInflated(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); // write the coordinate file and update the spec file void writeCoordUpdateSpec(BrainModelSurface* surface, const QString& filename, const QString& specFileName, const QString& specFileTag) throw (FileException); }; #endif // __COMMAND_SURFACE_GENERATE_INFLATED_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceGenerateInflated.cxx0000664000175000017500000003111011572067322030351 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurface.h" #include "BrainSet.h" #include "CommandSurfaceGenerateInflated.h" #include "CoordinateFile.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SpecFile.h" #include "TopologyFile.h" /** * constructor. */ CommandSurfaceGenerateInflated::CommandSurfaceGenerateInflated() : CommandBase("-surface-generate-inflated", "SURFACE GENERATE INFLATED AND OTHER SURFACES") { } /** * destructor. */ CommandSurfaceGenerateInflated::~CommandSurfaceGenerateInflated() { } /** * get the script builder parameters. */ void CommandSurfaceGenerateInflated::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addVariableListOfParameters("Inflate Options"); } /** * get full help information. */ QString CommandSurfaceGenerateInflated::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + "[-compression-factor value] \n" + indent9 + "[-iterations-scale value] \n" + indent9 + "[-generate-inflated] \n" + indent9 + "[-generate-very-inflated] \n" + indent9 + "[-generate-ellipsoid] \n" + indent9 + "[-generate-sphere] \n" + indent9 + "[-generate-cmw] \n" + indent9 + "[-output-spec output-spec-file-name]\n" + indent9 + "[-output-inflated-file-name output-inflated-coordinate-file-name]\n" + indent9 + "[-output-very-inflated-file-name output-very-inflated-coordinate-file-name]\n" + indent9 + "[-output-ellipsoid-file-name output-ellipsoid-coordinate-file-name]\n" + indent9 + "[-output-sphere-file-name output-spherical-coordinate-file-name]\n" + indent9 + "[-output-cmw-file-name output-cmw-coordinate-file-name]\n" + indent9 + "\n" + indent9 + "Generate inflated, very-inflated, ellipsoid, spherical,\n" + indent9 + "and compresed medial wall coordinate files. The input \n" + indent9 + "fiducial surface should be free of topological defects.\n" + indent9 + "Run the command \"-surface-topology-report\" to examine\n" + indent9 + "a surface's topology.\n" + indent9 + "\n" + indent9 + "NOTE: At this time, generation of the compressed medial \n" + indent9 + "wall surface from the command line is not supported due\n" + indent9 + "to the algorithm's use of OpenGL for rotations.\n" + indent9 + "\n" + indent9 + "If the file name for a surface is not specified, the name\n" + indent9 + "of the output file will be automatically generated.\n" + indent9 + "\n" + indent9 + "Use the \"-iterations-scale\" to scale the iterations\n" + indent9 + "during the inflation processes. In most cases, it is\n" + indent9 + "not necessary to use this option such as when the \n" + indent9 + "surface has been generated using Caret. However, \n" + indent9 + "surfaces produced by FreeSurfer often contain a large\n" + indent9 + "number of nodes, 150,000 or more. In this case, try\n" + indent9 + "an \"iterations-scale\" of 2.5.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceGenerateInflated::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the parameters // const QString fiducialCoordinateFileName = parameters->getNextParameterAsString("Fiducial Coordinate File Name"); const QString closedTopologyFileName = parameters->getNextParameterAsString("Closed Topology File Name"); // // Process the parameters for output files // bool createInflatedFlag = false; bool createVeryInflatedFlag = false; bool createEllipsoidFlag = false; bool createSphereFlag = false; bool createCompMedWallFlag = false; float iterationsScale = 1.0; float compressionFactor = 0.95; QString outputSpecFileName; QString inflatedCoordinateFileName; QString veryInflateCoordinateFileName; QString ellipsoidCoordinateFileName; QString sphericalCoordinateFileName; QString compMedWallCoordinateFileName; while (parameters->getParametersAvailable()) { // // Get the next parameter and process it // const QString paramName = parameters->getNextParameterAsString("Next Surface Option"); if (paramName == "-output-spec") { outputSpecFileName = parameters->getNextParameterAsString("Output Spec File Name"); } else if (paramName == "-compression-factor") { compressionFactor = parameters->getNextParameterAsFloat("Compression Factor"); } else if (paramName == "-iterations-scale") { iterationsScale = parameters->getNextParameterAsFloat("Iterations Scale Value"); } else if (paramName == "-generate-inflated") { createInflatedFlag = true; } else if (paramName == "-generate-very-inflated") { createVeryInflatedFlag = true; } else if (paramName == "-generate-ellipsoid") { createEllipsoidFlag = true; } else if (paramName == "-generate-sphere") { createSphereFlag = true; } else if (paramName == "-generate-cmw") { createCompMedWallFlag = true; } else if (paramName == "-output-inflated-file-name") { inflatedCoordinateFileName = parameters->getNextParameterAsString("Inflated Coordinate File Name"); } else if (paramName == "-output-very-inflated-file-name") { veryInflateCoordinateFileName = parameters->getNextParameterAsString("Very Inflated Coordinate File Name"); } else if (paramName == "-output-ellipsoid-file-name") { ellipsoidCoordinateFileName = parameters->getNextParameterAsString("Ellipsoid Coordinate File Name"); } else if (paramName == "-output-sphere-file-name") { sphericalCoordinateFileName = parameters->getNextParameterAsString("Sphere Coordinate File Name"); } else if (paramName == "-output-cmw-file-name") { compMedWallCoordinateFileName = parameters->getNextParameterAsString("Comp Med Wall Coordinate File Name"); } else { throw CommandException("Unrecognized surface option: " + paramName); } } // // Create a brain set // BrainSet brainSet(closedTopologyFileName, fiducialCoordinateFileName, "", true); BrainModelSurface* fiducialSurface = brainSet.getBrainModelSurface(0); if (fiducialSurface == NULL) { throw CommandException("unable to find fiducial surface."); } const TopologyFile* tf = fiducialSurface->getTopologyFile(); if (tf == NULL) { throw CommandException("unable to find topology."); } const int numNodes = fiducialSurface->getNumberOfNodes(); if (numNodes == 0) { throw CommandException("surface contains no nodes."); } // // Generate the surfaces // const bool smoothFingersFlag = false; const bool scaleToMatchFiduciaFlag = false; fiducialSurface->createInflatedAndEllipsoidFromFiducial(createInflatedFlag, createVeryInflatedFlag, createEllipsoidFlag, createSphereFlag, createCompMedWallFlag, smoothFingersFlag, scaleToMatchFiduciaFlag, iterationsScale, NULL, compressionFactor); // // Write the output files // if (createInflatedFlag) { BrainModelSurface* surface = brainSet.getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_INFLATED); if (surface == NULL) { throw CommandException("inflated surface generation failed."); } writeCoordUpdateSpec(surface, inflatedCoordinateFileName, outputSpecFileName, SpecFile::getInflatedCoordFileTag()); } if (createVeryInflatedFlag) { BrainModelSurface* surface = brainSet.getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_VERY_INFLATED); if (surface == NULL) { throw CommandException("very inflated surface generation failed."); } writeCoordUpdateSpec(surface, veryInflateCoordinateFileName, outputSpecFileName, SpecFile::getVeryInflatedCoordFileTag()); } if (createEllipsoidFlag) { BrainModelSurface* surface = brainSet.getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL); if (surface == NULL) { throw CommandException("ellipsoid surface generation failed."); } writeCoordUpdateSpec(surface, ellipsoidCoordinateFileName, outputSpecFileName, SpecFile::getEllipsoidCoordFileTag()); } if (createSphereFlag) { BrainModelSurface* surface = brainSet.getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_SPHERICAL); if (surface == NULL) { throw CommandException("spherical surface generation failed."); } writeCoordUpdateSpec(surface, sphericalCoordinateFileName, outputSpecFileName, SpecFile::getSphericalCoordFileTag()); } if (createCompMedWallFlag) { BrainModelSurface* surface = brainSet.getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL); if (surface == NULL) { throw CommandException("compressed medial wall surface generation failed."); } writeCoordUpdateSpec(surface, compMedWallCoordinateFileName, outputSpecFileName, SpecFile::getCompressedCoordFileTag()); } } /** * write the coordinate file and update the spec file. */ void CommandSurfaceGenerateInflated::writeCoordUpdateSpec(BrainModelSurface* surface, const QString& filenameIn, const QString& specFileName, const QString& specFileTag) throw (FileException) { QString filename = filenameIn; CoordinateFile* cf = surface->getCoordinateFile(); if (filename.isEmpty()) { filename = cf->getFileName(); } cf->writeFile(filename); if (specFileName.isEmpty() == false) { SpecFile sf; sf.readFile(specFileName); sf.addToSpecFile(specFileTag, filename, "", false); sf.writeFile(specFileName); } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceFociUnprojection.h0000664000175000017500000000250111572067322030057 0ustar michaelmichael #ifndef __COMMAND_SURFACE_FOCI_UNPROJECTION_H__ #define __COMMAND_SURFACE_FOCI_UNPROJECTION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandSurfaceCellUnprojection.h" /// class for unprojecting foci class CommandSurfaceFociUnprojection : public CommandSurfaceCellUnprojection { public: // constructor CommandSurfaceFociUnprojection(); // destructor virtual ~CommandSurfaceFociUnprojection(); }; #endif // __COMMAND_SURFACE_FOCI_UNPROJECTION_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceFociUnprojection.cxx0000664000175000017500000000241211572067322030433 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandSurfaceFociUnprojection.h" /** * constructor. */ CommandSurfaceFociUnprojection::CommandSurfaceFociUnprojection() : CommandSurfaceCellUnprojection("-surface-foci-unprojection", "SURFACE FOCI UNPROJECTION", true) { } /** * destructor. */ CommandSurfaceFociUnprojection::~CommandSurfaceFociUnprojection() { } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceFociStudyValidate.h0000664000175000017500000000347011572067322030170 0ustar michaelmichael #ifndef __COMMAND_SURFACE_FOCI_STUDY_VALIDATE_H__ #define __COMMAND_SURFACE_FOCI_STUDY_VALIDATE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandSurfaceFociStudyValidate : public CommandBase { public: // constructor CommandSurfaceFociStudyValidate(); // destructor ~CommandSurfaceFociStudyValidate(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_FOCI_STUDY_VALIDATE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceFociStudyValidate.cxx0000664000175000017500000001354011572067322030542 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "CommandSurfaceFociStudyValidate.h" #include "FileFilters.h" #include "FociFile.h" #include "FociProjectionFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "StudyMetaDataFile.h" #include "TextFile.h" /** * constructor. */ CommandSurfaceFociStudyValidate::CommandSurfaceFociStudyValidate() : CommandBase("-surface-foci-study-validate", "SURFACE FOCI STUDY VALIDATE") { } /** * destructor. */ CommandSurfaceFociStudyValidate::~CommandSurfaceFociStudyValidate() { } /** * get the script builder parameters. */ void CommandSurfaceFociStudyValidate::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); QStringList fileFilters; fileFilters << FileFilters::getFociFileFilter(); fileFilters << FileFilters::getFociProjectionFileFilter(); paramsOut.addFile("Foci or Foci Projection File", fileFilters); paramsOut.addFile("Study Metadata File", FileFilters::getStudyMetaDataFileFilter()); paramsOut.addVariableListOfParameters("Output Text File Name"); } /** * get full help information. */ QString CommandSurfaceFociStudyValidate::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-output output-text-file]\n" + indent9 + "\n" + indent9 + "Verify that all foci have valid study metadata links.\n" + indent9 + "Errors include links to invalid studies, foci names \n" + indent9 + "that do not match the study name, or links to invalid\n" + indent9 + "tables, table subheaders, figures, figure panels, \n" + indent9 + "page numbers, and page subheaders.\n" + indent9 + "\n" + indent9 + "If there are any errors, they are written to the output\n" + indent9 + "text file if it is provided. Otherwise, results are \n" + indent9 + "written to the terminal.\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceFociStudyValidate::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString fociFileName = parameters->getNextParameterAsString("Input Foci or Foci Projection File"); const QString studyFileName = parameters->getNextParameterAsString("Input Study Metadata File"); QString textFileName; while (parameters->getParametersAvailable()) { QString paramName = parameters->getNextParameterAsString("Opt Param"); if (paramName == "-output") { textFileName = parameters->getNextParameterAsString("Text File Name"); } else { throw CommandException("Unexpected Parameter: " + paramName); } } FociFile ff; FociProjectionFile fpf; if (fociFileName.endsWith(SpecFile::getFociFileExtension()) || fociFileName.endsWith(SpecFile::getFociFileExtension() + ".csv")) { ff.readFile(fociFileName); } else if (fociFileName.endsWith(SpecFile::getFociProjectionFileExtension())) { fpf.readFile(fociFileName); } else { throw CommandException("The foci or foci projection file must end with " + SpecFile::getFociFileExtension() + " or " + SpecFile::getFociProjectionFileExtension()); } StudyMetaDataFile smdf; smdf.readFile(studyFileName); QString msg; if (ff.getNumberOfCells() > 0) { const int num = ff.getNumberOfCells(); for (int i = 0; i < num; i++) { CellData* cd = ff.getCell(i); QStringList sl = cd->validateStudyMetaDataLink(&smdf); for (int m = 0; m < sl.count(); m++) { msg += "Focus " + QString::number(i) + " " + cd->getName() + ": " + sl.at(m) + "\n"; } } } if (fpf.getNumberOfCellProjections() > 0) { const int num = fpf.getNumberOfCellProjections(); for (int i = 0; i < num; i++) { CellProjection* cd = fpf.getCellProjection(i); QStringList sl = cd->validateStudyMetaDataLink(&smdf); for (int m = 0; m < sl.count(); m++) { msg += "Focus " + QString::number(i) + " " + cd->getName() + ": " + sl.at(m) + "\n"; } } } if (msg.isEmpty()) { std::cout << "No foci/study problems were found." << std::endl; } else { if (textFileName.isEmpty() == false) { TextFile tf; tf.setText(msg); tf.writeFile(textFileName); } else { std::cout << msg.toAscii().constData() << std::endl; } } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceFociReassignStudyNames.h0000664000175000017500000000353111572067322031174 0ustar michaelmichael #ifndef __COMMAND_SURFACE_FOCI_REASSIGN_STUDY_NAMES_H__ #define __COMMAND_SURFACE_FOCI_REASSIGN_STUDY_NAMES_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandSurfaceFociReassignStudyNames : public CommandBase { public: // constructor CommandSurfaceFociReassignStudyNames(); // destructor ~CommandSurfaceFociReassignStudyNames(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_FOCI_REASSIGN_STUDY_NAMES_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceFociReassignStudyNames.cxx0000664000175000017500000000744111572067322031553 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainSet.h" #include "FociProjectionFile.h" #include "CommandSurfaceFociReassignStudyNames.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "StudyMetaDataFile.h" /** * constructor. */ CommandSurfaceFociReassignStudyNames::CommandSurfaceFociReassignStudyNames() : CommandBase("-surface-foci-reassign-study-names", "SURFACE FOCI REASSIGN STUDY NAMES") { } /** * destructor. */ CommandSurfaceFociReassignStudyNames::~CommandSurfaceFociReassignStudyNames() { } /** * get the script builder parameters. */ void CommandSurfaceFociReassignStudyNames::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.addFile("Study Metadata File", FileFilters::getStudyMetaDataFileFilter()); paramsOut.addFile("Input Foci Projection File", FileFilters::getFociProjectionFileFilter()); paramsOut.addFile("Output Foci Projection File", FileFilters::getFociProjectionFileFilter()); } /** * get full help information. */ QString CommandSurfaceFociReassignStudyNames::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "If a focus is linked to a study via a PubMed ID, set \n" + indent9 + "the name of the focus to the name of the study. \n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceFociReassignStudyNames::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString studyMetaDataFileName = parameters->getNextParameterAsString("Study Metadata File Name"); const QString inputFociProjectionFileName = parameters->getNextParameterAsString("Input Foci Projection File Name"); const QString outputFociProjectionFileName = parameters->getNextParameterAsString("Output Foci Projection File Name"); checkForExcessiveParameters(); // // Read the study metadata file // StudyMetaDataFile studyMetaDataFile; studyMetaDataFile.readFile(studyMetaDataFileName); // // Read the foci projection file // FociProjectionFile fociProjectionFile; fociProjectionFile.readFile(inputFociProjectionFileName); // // Rename foci // fociProjectionFile.updateCellNameWithStudyNameForMatchingPubMedIDs(&studyMetaDataFile); // // Write the foci projection file name // fociProjectionFile.writeFile(outputFociProjectionFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceFociProjectionPals.h0000664000175000017500000000354311572067322030343 0ustar michaelmichael #ifndef __COMMAND_SURFACE_FOCI_PROJECTION_PALS_H__ #define __COMMAND_SURFACE_FOCI_PROJECTION_PALS_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for surface foci projection to PALS atlas class CommandSurfaceFociProjectionPals : public CommandBase { public: // constructor CommandSurfaceFociProjectionPals(); // destructor ~CommandSurfaceFociProjectionPals(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_FOCI_PROJECTION_PALS_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceFociProjectionPals.cxx0000664000175000017500000002014711572067322030715 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainSet.h" #include "CommandSurfaceFociProjectionPals.h" #include "FileFilters.h" #include "FociFile.h" #include "FociFileToPalsProjector.h" #include "FociProjectionFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "StudyMetaDataFile.h" /** * constructor. */ CommandSurfaceFociProjectionPals::CommandSurfaceFociProjectionPals() : CommandBase("-surface-foci-projection-pals", "SURFACE FOCI PROJECTION TO PALS ATLAS") { } /** * destructor. */ CommandSurfaceFociProjectionPals::~CommandSurfaceFociProjectionPals() { } /** * get the script builder parameters. */ void CommandSurfaceFociProjectionPals::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { QStringList inputFilters; inputFilters << FileFilters::getFociFileFilter(); inputFilters << FileFilters::getFociProjectionFileFilter(); paramsOut.clear(); paramsOut.addFile("Input Foci or Foci Projection File", inputFilters); paramsOut.addFile("Output Foci Projection File", FileFilters::getFociProjectionFileFilter()); paramsOut.addFile("Study Metadata File", FileFilters::getStudyMetaDataFileFilter()); paramsOut.addVariableListOfParameters(""); } /** * get full help information. */ QString CommandSurfaceFociProjectionPals::getHelpInformation() const { const QString cerebralCutoffValue( QString::number(FociFileToPalsProjector::getDefaultCerebralCutoffDistance(), 'f', 2)); const QString cerebellumCutoffValue( QString::number(FociFileToPalsProjector::getDefaultCerebellumCutoffDistance(), 'f', 2)); QString s = "cell"; QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-cutoffs cerebral-cutoff cerebellum-cutoff]\n" + indent9 + "[-no-cerebellum]\n" + indent9 + "[-project-onto-surface onto-surface-above-distance]\n" + indent9 + "\n" + indent9 + "Project foci to the PALS Atlas.\n" + indent9 + "\n" + indent9 + "The input file may be either a foci file or a foci\n" + indent9 + "projection file. If the input file is a foci file, its\n" + indent9 + "name must end with \"" + SpecFile::getFociFileExtension() + "\".\n" + indent9 + "\n" + indent9 + "Add the \"-no-cerebellum\" option if you DO NOT want foci\n" + indent9 + "projected using the cerebellum.\n" + indent9 + "\n" + indent9 + "Use the \"-project-onto-surface\" option to project the\n" + indent9 + "foci so that they are a specified distance on or above\n" + indent9 + "the surfaces.\n" + indent9 + "\n" + indent9 + "Use the \"-cutoffs\" to control how foci are projected \n" + indent9 + "using a cerebral hemisphere and/or the cerebellum.\n" + indent9 + " A ratio of the distance to the cerebral cortex relative\n" + indent9 + " to the distance to the cerebellum is computed.\n" + indent9 + " If this ratio is less than the \"cerebral-cutoff\", \n" + indent9 + " the focus is assigned to the cerebral cortex. If this\n" + indent9 + " ratio is greater than \"cerebellum-cutoff\", the focus\n" + indent9 + " is assigned to the cerebellum. If the ratio is between\n" + indent9 + " the two cutoffs, the focus is assigned to both a \n" + indent9 + " cerebral hemisphere and the cerebellum.\n" + indent9 + "\n" + indent9 + " Default \"cerebral-cutoff\": " + cerebralCutoffValue + "\n" + indent9 + " Default \"cerebellum-cutoff\": " + cerebellumCutoffValue + "\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceFociProjectionPals::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputFociProjectionFileName = parameters->getNextParameterAsString("Input Foci or Foci Projection File Name"); const QString outputFociProjectionFileName = parameters->getNextParameterAsString("Output Foci Projection File Name"); const QString inputStudyMetaDataFileName = parameters->getNextParameterAsString("Input Study Metadata File Name"); // // Process optional parameters // float cerebralCutoffDistance = FociFileToPalsProjector::getDefaultCerebralCutoffDistance(); float cerebellumCutoffDistance = FociFileToPalsProjector::getDefaultCerebellumCutoffDistance(); bool projectToCerebellumFlag = true; bool projectToSurfaceFlag = false; float surfaceAboveDistance = 0.0; while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("Foci Projection Parameter"); if (paramName == "-cutoffs") { cerebralCutoffDistance = parameters->getNextParameterAsFloat("Cerebral Cutoff Distance"); cerebellumCutoffDistance = parameters->getNextParameterAsFloat("Cerebellum Cutoff Distance"); } else if (paramName == "-no-cerebellum") { projectToCerebellumFlag = false; } else if (paramName == "-project-onto-surface") { projectToSurfaceFlag = true; surfaceAboveDistance = parameters->getNextParameterAsFloat("Foci Projection Parameter: Above surface distance"); } else { throw CommandException("unrecognized option"); } } // // Create a brain set // BrainSet brainSet; // // Read the foci projection file // FociProjectionFile fociProjectionFile; if (inputFociProjectionFileName.endsWith(SpecFile::getFociFileExtension())) { FociFile ff; ff.readFile(inputFociProjectionFileName); fociProjectionFile.appendFiducialCellFile(ff); } else { fociProjectionFile.readFile(inputFociProjectionFileName); } // // Read the study metadata file // StudyMetaDataFile studyMetaDataFile; studyMetaDataFile.readFile(inputStudyMetaDataFileName); // // Project the foci file to the PALS atlas // FociFileToPalsProjector palsProjector(&brainSet, &fociProjectionFile, &studyMetaDataFile, 0, fociProjectionFile.getNumberOfCellProjections() - 1, surfaceAboveDistance, projectToSurfaceFlag, projectToCerebellumFlag, cerebralCutoffDistance, cerebellumCutoffDistance); palsProjector.execute(); // // Write the foci projection file // fociProjectionFile.writeFile(outputFociProjectionFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceFociProjection.h0000664000175000017500000000245711572067322027526 0ustar michaelmichael #ifndef __COMMAND_SURFACE_FOCI_PROJECTION_H__ #define __COMMAND_SURFACE_FOCI_PROJECTION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandSurfaceCellProjection.h" /// class for Projecting foci class CommandSurfaceFociProjection : public CommandSurfaceCellProjection { public: // constructor CommandSurfaceFociProjection(); // destructor virtual ~CommandSurfaceFociProjection(); }; #endif // __COMMAND_SURFACE_FOCI_PROJECTION_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceFociProjection.cxx0000664000175000017500000000237211572067322030075 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandSurfaceFociProjection.h" /** * constructor. */ CommandSurfaceFociProjection::CommandSurfaceFociProjection() : CommandSurfaceCellProjection("-surface-foci-projection", "SURFACE FOCI PROJECTION", true) { } /** * destructor. */ CommandSurfaceFociProjection::~CommandSurfaceFociProjection() { } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceFociDelete.h0000664000175000017500000000344111572067322026606 0ustar michaelmichael #ifndef __COMMAND_SURFACE_FOCI_DELETE_H__ #define __COMMAND_SURFACE_FOCI_DELETE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for deleting foci by name class CommandSurfaceFociDelete : public CommandBase { public: // constructor CommandSurfaceFociDelete(); // destructor ~CommandSurfaceFociDelete(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_FOCI_DELETE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceFociDelete.cxx0000664000175000017500000000771011572067322027164 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "FociProjectionFile.h" #include "CommandSurfaceFociDelete.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandSurfaceFociDelete::CommandSurfaceFociDelete() : CommandBase("-surface-foci-delete", "SURFACE FOCI DELETION") { } /** * destructor. */ CommandSurfaceFociDelete::~CommandSurfaceFociDelete() { } /** * get the script builder parameters. */ void CommandSurfaceFociDelete::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Foci Projection File", FileFilters::getFociProjectionFileFilter()); paramsOut.addFile("Output Foci Projection File", FileFilters::getFociProjectionFileFilter()); paramsOut.addVariableListOfParameters("Foci Names"); } /** * get full help information. */ QString CommandSurfaceFociDelete::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + "[foci-names] \n" + indent9 + "\n" + indent9 + "Delete foci with the specified names from the foci\n" + indent9 + "projection file. If a foci name contains spaces, it must\n" + indent9 + "be enclosed within double quotes.\n" + indent9 + "\n" + indent9 + "If the input foci projection file name does not exist\n" + indent9 + "the command will exit without reporting an error but\n" + indent9 + "it will report a warning.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceFociDelete::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputFociProjectionFileName = parameters->getNextParameterAsString("Input Foci Projection File Name"); const QString outputFociProjectionFileName = parameters->getNextParameterAsString("Output Foci Projection File Name"); if (QFile::exists(inputFociProjectionFileName) == false) { std::cout << "WARNING " << getShortDescription().toAscii().constData() << " \"" << inputFociProjectionFileName.toAscii().constData() << "\" was not found." << std::endl; return; } FociProjectionFile fociProjectionFile; fociProjectionFile.readFile(inputFociProjectionFileName); while (parameters->getParametersAvailable()) { const QString focusName = parameters->getNextParameterAsString("Focus Name"); fociProjectionFile.deleteCellProjectionsWithName(focusName); } fociProjectionFile.writeFile(outputFociProjectionFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceFociCreate.h0000664000175000017500000000241111572067322026603 0ustar michaelmichael #ifndef __COMMAND_SURFACE_FOCI_CREATE_H__ #define __COMMAND_SURFACE_FOCI_CREATE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandSurfaceCellCreate.h" /// class for class CommandSurfaceFociCreate : public CommandSurfaceCellCreate { public: // constructor CommandSurfaceFociCreate(); // destructor ~CommandSurfaceFociCreate(); protected: }; #endif // __COMMAND_SURFACE_FOCI_CREATE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceFociCreate.cxx0000664000175000017500000000232011572067322027155 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandSurfaceFociCreate.h" /** * constructor. */ CommandSurfaceFociCreate::CommandSurfaceFociCreate() : CommandSurfaceCellCreate("-surface-foci-create", "SURFACE FOCI CREATION", true) { } /** * destructor. */ CommandSurfaceFociCreate::~CommandSurfaceFociCreate() { } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceFociAttributeAssignment.h0000664000175000017500000000353411572067322031403 0ustar michaelmichael #ifndef __COMMAND_SURFACE_FOCI_ATTRIBUTE_ASSIGNMENT_H__ #define __COMMAND_SURFACE_FOCI_ATTRIBUTE_ASSIGNMENT_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandSurfaceFociAttributeAssignment : public CommandBase { public: // constructor CommandSurfaceFociAttributeAssignment(); // destructor ~CommandSurfaceFociAttributeAssignment(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_FOCI_ATTRIBUTE_ASSIGNMENT_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceFociAttributeAssignment.cxx0000664000175000017500000003746111572067322031764 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurface.h" #include "BrainModelSurfaceCellAttributeAssignment.h" #include "BrainSet.h" #include "FociProjectionFile.h" #include "CommandSurfaceFociAttributeAssignment.h" #include "FileFilters.h" #include "PaintFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SpecFile.h" /** * constructor. */ CommandSurfaceFociAttributeAssignment::CommandSurfaceFociAttributeAssignment() : CommandBase("-surface-foci-attribute-assignment", "SURFACE FOCI ATTRIBUTE ASSIGNMENT") { } /** * destructor. */ CommandSurfaceFociAttributeAssignment::~CommandSurfaceFociAttributeAssignment() { } /** * get the script builder parameters. */ void CommandSurfaceFociAttributeAssignment::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { std::vector attributeNames; std::vector attributeValues; BrainModelSurfaceCellAttributeAssignment::getAttributeNamesAndValues( attributeNames, attributeValues); std::vector methodNames; std::vector methodValues; BrainModelSurfaceCellAttributeAssignment::getAssignmentNamesAndValues( methodNames, methodValues); paramsOut.clear(); paramsOut.addFile("Left Coordinate File", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Left Topology File", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Right Coordinate File", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Right Topology File", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Cerebellum Coordinate File", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Cerebellum Topology File", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Input Foci Projection File", FileFilters::getFociProjectionFileFilter()); paramsOut.addFile("Output Foci Projection File", FileFilters::getFociProjectionFileFilter()); paramsOut.addFile("Paint File", FileFilters::getPaintFileFilter()); paramsOut.addFloat("Maximum Distance From Surface", 1000.0); paramsOut.addListOfItems("Attribute to Assign", attributeNames, attributeNames); paramsOut.addListOfItems("Assignment Method", methodNames, methodNames); paramsOut.addInt("Attribute ID", -1); paramsOut.addBoolean("Ignore Paint ??? Names", true); paramsOut.addVariableListOfParameters("Paint Column Names/Numbers"); } /** * get full help information. */ QString CommandSurfaceFociAttributeAssignment::getHelpInformation() const { std::vector attributeNames; std::vector attributeValues; BrainModelSurfaceCellAttributeAssignment::getAttributeNamesAndValues( attributeNames, attributeValues); std::vector methodNames; std::vector methodValues; BrainModelSurfaceCellAttributeAssignment::getAssignmentNamesAndValues( methodNames, methodValues); QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[paint-column-name-or-number-1]\n" + indent9 + "[paint-column-name-or-number-2]\n" + indent9 + "...\n" + indent9 + "[paint-column-name-or-number-N]\n" + indent9 + "\n" + indent9 + "Assign paint names to foci attributes.\n" + indent9 + "\n" + indent9 + "\"assign-to-attribute-name\" is one of:\n"); for (unsigned int i = 0; i < attributeNames.size(); i++) { helpInfo += ( indent9 + " " + attributeNames[i] + "\n"); } helpInfo += ("\n" + indent9 + "\"assignment-method-name\" is one of:\n"); for (unsigned int i = 0; i < methodNames.size(); i++) { helpInfo += ( indent9 + " " + methodNames[i] + "\n"); } helpInfo += ( indent9 + "\n" + indent9 + "attribute ID is an integer value:\n" + indent9 + " -1 Indeterminate\n" + indent9 + " 0 Unassigned\n" + indent9 + " 1 \n" + indent9 + "\n" + indent9 + "If a surface is not available or you do not want to \n" + indent9 + "perform assignment to that surface, use a value of \n" + indent9 + "NONE for the coordinate and topology file.\n" + indent9 + "\n" + indent9 + "Paint columns are either the number of a paint column,\n" + indent9 + "which starts at one, or the name of a column. If a name\n" + indent9 + "contains spaces, it must be enclosed in double quotes.\n" + indent9 + "Name has priority over number.\n" + indent9 + "\n" + indent9 + "\"ignore-unknown-paint-names\" is either\n" + indent9 + " true\n" + indent9 + " false\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceFociAttributeAssignment::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString leftCoordinateFileName = parameters->getNextParameterAsString("Left Coordinate File Name"); const QString leftTopologyFileName = parameters->getNextParameterAsString("Left Topology File Name"); const QString rightCoordinateFileName = parameters->getNextParameterAsString("Right Coordinate File Name"); const QString rightTopologyFileName = parameters->getNextParameterAsString("Right Topology File Name"); const QString cerebellumCoordinateFileName = parameters->getNextParameterAsString("Cerebellum Coordinate File Name"); const QString cerebellumTopologyFileName = parameters->getNextParameterAsString("Cerebellum Topology File Name"); const QString inputFociProjectionFileName = parameters->getNextParameterAsString("Input Foci Projection File Name"); const QString outputFociProjectionFileName = parameters->getNextParameterAsString("Output Foci Projection File Name"); const QString paintFileName = parameters->getNextParameterAsString("Paint File Name"); const float maximumDistanceFromSurface = parameters->getNextParameterAsFloat("Maximum Distance from Surface"); const QString attributeName = parameters->getNextParameterAsString("Assign to Attribute Name"); const QString assignmentMethodName = parameters->getNextParameterAsString("Assignment Method Name"); const int attributeID = parameters->getNextParameterAsInt("Attribute ID"); const bool ignoreUnknownPaintNamesFlag = parameters->getNextParameterAsBoolean("Ignore ??? Paint Names"); std::vector paintColumnNamesAndNumbers; while (parameters->getParametersAvailable()) { paintColumnNamesAndNumbers.push_back( parameters->getNextParameterAsString("Paint Column Name or Number")); } bool doLeft = true; bool doRight = true; bool doCerebellum = true; const QString noneValue("NONE"); if ((leftCoordinateFileName == noneValue) || (leftTopologyFileName == noneValue)) { doLeft = false; } if ((rightCoordinateFileName == noneValue) || (rightTopologyFileName == noneValue)) { doRight = false; } if ((cerebellumCoordinateFileName == noneValue) || (cerebellumTopologyFileName == noneValue)) { doCerebellum = false; } // // Create a spec file and add coordinate and topology files to it // SpecFile sf; if (doLeft) { sf.addToSpecFile(SpecFile::getFiducialCoordFileTag(), leftCoordinateFileName, "", false); sf.addToSpecFile(SpecFile::getClosedTopoFileTag(), leftTopologyFileName, "", false); } if (doRight) { sf.addToSpecFile(SpecFile::getFiducialCoordFileTag(), rightCoordinateFileName, "", false); sf.addToSpecFile(SpecFile::getClosedTopoFileTag(), rightTopologyFileName, "", false); } if (doCerebellum) { sf.addToSpecFile(SpecFile::getFiducialCoordFileTag(), cerebellumCoordinateFileName, "", false); sf.addToSpecFile(SpecFile::getClosedTopoFileTag(), cerebellumTopologyFileName, "", false); } // // Read the spec file // BrainSet brainSet(true); QString errorMessage; brainSet.readSpecFile(sf, "", errorMessage); if (errorMessage.isEmpty() == false) { throw CommandException(errorMessage); } // // Find the topology files // TopologyFile* leftTopologyFile = NULL; TopologyFile* rightTopologyFile = NULL; TopologyFile* cerebellumTopologyFile = NULL; for (int i = 0; i < brainSet.getNumberOfTopologyFiles(); i++) { TopologyFile* tf = brainSet.getTopologyFile(i); if (tf->getFileName().endsWith(leftTopologyFileName)) { leftTopologyFile = tf; } if (tf->getFileName().endsWith(rightTopologyFileName)) { rightTopologyFile = tf; } if (tf->getFileName().endsWith(cerebellumTopologyFileName)) { cerebellumTopologyFile = tf; } } if (doLeft && (leftTopologyFile == NULL)) { throw CommandException("Unable to find left topology file after reading files."); } if (doRight && (rightTopologyFile == NULL)) { throw CommandException("Unable to find right topology file after reading files."); } if (doCerebellum && (cerebellumTopologyFile == NULL)) { throw CommandException("Unable to find cerebellum topology file after reading files."); } // // Find the surfaces and assign topology // BrainModelSurface* leftSurface = NULL; BrainModelSurface* rightSurface = NULL; BrainModelSurface* cerebellumSurface = NULL; for (int i = 0; i < brainSet.getNumberOfBrainModels(); i++) { BrainModelSurface* bms = brainSet.getBrainModelSurface(i); if (bms != NULL) { if (bms->getCoordinateFile()->getFileName().endsWith(leftCoordinateFileName)) { leftSurface = bms; leftSurface->setTopologyFile(leftTopologyFile); } if (bms->getCoordinateFile()->getFileName().endsWith(rightCoordinateFileName)) { rightSurface = bms; rightSurface->setTopologyFile(rightTopologyFile); } if (bms->getCoordinateFile()->getFileName().endsWith(cerebellumCoordinateFileName)) { cerebellumSurface = bms; cerebellumSurface->setTopologyFile(cerebellumTopologyFile); } } } if (doLeft && (leftSurface == NULL)) { throw CommandException("Unable to find left surface file after reading files."); } if (doRight && (rightSurface == NULL)) { throw CommandException("Unable to find right surface file after reading files."); } if (doCerebellum && (cerebellumSurface == NULL)) { throw CommandException("Unable to find cerebellum surface file after reading files."); } // // Read the foci projection file // FociProjectionFile fociProjectionFile; fociProjectionFile.readFile(inputFociProjectionFileName); // // Read the paint file // PaintFile paintFile; paintFile.readFile(paintFileName); // // Select the paint columns // std::vector paintColumnsSelected; const int numCols = paintFile.getNumberOfColumns(); if (numCols > 0) { paintColumnsSelected.resize(numCols, false); } for (unsigned int i = 0; i < paintColumnNamesAndNumbers.size(); i++) { const int colNum = paintFile.getColumnFromNameOrNumber( paintColumnNamesAndNumbers[i], false); if ((colNum >= 0) && (colNum < paintFile.getNumberOfColumns())) { paintColumnsSelected[colNum] = true; } else { throw CommandException("Invalid paint column name or number " + paintColumnNamesAndNumbers[i]); } } // // Get the attribute // std::vector attributeNames; std::vector attributeValues; BrainModelSurfaceCellAttributeAssignment::ASSIGN_ATTRIBUTE attribute = BrainModelSurfaceCellAttributeAssignment::ASSIGN_ATTRIBUTE_AREA; BrainModelSurfaceCellAttributeAssignment::getAttributeNamesAndValues( attributeNames, attributeValues); bool attributeFound = false; for (unsigned int i = 0; i < attributeNames.size(); i++) { if (attributeNames[i] == attributeName) { attribute = attributeValues[i]; attributeFound = true; } } if (attributeFound == false) { throw CommandException("Invalid attribute: " + attributeName); } // // Get the assignemnt method // std::vector methodNames; std::vector methodValues; BrainModelSurfaceCellAttributeAssignment::getAssignmentNamesAndValues( methodNames, methodValues); BrainModelSurfaceCellAttributeAssignment::ASSIGNMENT_METHOD assignmentMethod = BrainModelSurfaceCellAttributeAssignment::ASSIGNMENT_METHOD_APPEND; bool methodFound = false; for (unsigned int i = 0; i < attributeNames.size(); i++) { if (methodNames[i] == assignmentMethodName) { assignmentMethod = methodValues[i]; methodFound = true; } } if (methodFound == false) { throw CommandException("Invalid assignment method: " + assignmentMethodName); } // // Run the algorithm // BrainModelSurfaceCellAttributeAssignment assignFoci(&brainSet, leftSurface, rightSurface, cerebellumSurface, &fociProjectionFile, &paintFile, paintColumnsSelected, maximumDistanceFromSurface, attribute, assignmentMethod, QString::number(attributeID), ignoreUnknownPaintNamesFlag); assignFoci.execute(); fociProjectionFile.writeFile(outputFociProjectionFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceFlatten.h0000664000175000017500000000336611572067322026206 0ustar michaelmichael #ifndef __COMMAND_SURFACE_FLATTEN_H__ #define __COMMAND_SURFACE_FLATTEN_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandSurfaceFlatten : public CommandBase { public: // constructor CommandSurfaceFlatten(); // destructor ~CommandSurfaceFlatten(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_FLATTEN_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceFlatten.cxx0000664000175000017500000002305011572067322026551 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "AreaColorFile.h" #include "BorderProjectionFile.h" #include "BrainSet.h" #include "BrainModelSurfaceFlattenHemisphere.h" #include "CommandSurfaceFlatten.h" #include "FileFilters.h" #include "PaintFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SpecFile.h" /** * constructor. */ CommandSurfaceFlatten::CommandSurfaceFlatten() : CommandBase("-surface-flatten", "SURFACE FLATTEN") { } /** * destructor. */ CommandSurfaceFlatten::~CommandSurfaceFlatten() { } /** * get the script builder parameters. */ void CommandSurfaceFlatten::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); } /** * get full help information. */ QString CommandSurfaceFlatten::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Flatten the ellipsoid/spherical surface.\n" + indent9 + "\n" + indent9 + "The input border projection file must contain a border \n" + indent9 + "projection that identifies the medial wall (its name \n" + indent9 + "must be \"FLATTEN.HOLE.MedialWall\") and cuts (names of \n" + indent9 + "cuts start with \"FLATTEN.CUT.Std.\".)\n" + indent9 + "\n" + indent9 + "All of the output file names are optional. If you do not\n" + indent9 + "want an output file written, specify the file's name as\n" + indent9 + "two consecutive double quotes (\"\", an empty string).\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceFlatten::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString fiducialCoordinateFileName = parameters->getNextParameterAsString("Fiducial Coordinate File Name"); const QString ellipsoidSphericalCoordinateFileName = parameters->getNextParameterAsString("Ellipsoid/Spherical Coordinate File Name"); const QString closedTopologyFileName = parameters->getNextParameterAsString("Closed Topology File Name"); const QString flattenBorderProjectionFileName = parameters->getNextParameterAsString("Flatten Border Projection File Name"); const QString outputFiducialSmoothedMedialWallCoordinateFileName = parameters->getNextParameterAsString("Output Fiducial Smoothed Medial Wall Coordinate File Name"); const QString outputSphericalCoordinateFileName = parameters->getNextParameterAsString("Output Spherical Coordinate File Name"); const QString outputInitialFlatCoordinateFileName = parameters->getNextParameterAsString("Output Initial Flat Coordinate File Name"); const QString outputOpenTopologyFileName = parameters->getNextParameterAsString("Output Open Topology File Name"); const QString outputCutTopologyFileName = parameters->getNextParameterAsString("Output Cut Topology File Name"); const QString inputPaintFileName = parameters->getNextParameterAsString("Input Paint File Name"); const QString outputPaintFileName = parameters->getNextParameterAsString("Output Paint File Name"); const QString inputAreaColorFileName = parameters->getNextParameterAsString("Input Area Color File Name"); const QString outputAreaColorFileName = parameters->getNextParameterAsString("Output Area Color File Name"); checkForExcessiveParameters(); // // Read spec file // SpecFile specFile; // // Set the selected files // specFile.setAllFileSelections(SpecFile::SPEC_FALSE); specFile.addToSpecFile(SpecFile::getClosedTopoFileTag(), closedTopologyFileName, "", SpecFile::SPEC_FALSE); specFile.addToSpecFile(SpecFile::getFiducialCoordFileTag(), fiducialCoordinateFileName, "", SpecFile::SPEC_FALSE); specFile.addToSpecFile(SpecFile::getEllipsoidCoordFileTag(), ellipsoidSphericalCoordinateFileName, "", SpecFile::SPEC_FALSE); // // Read the spec file into a brain set // QString errorMessage; BrainSet brainSet(true); if (brainSet.readSpecFile(specFile, "Temp.spec", errorMessage)) { throw CommandException("Reading spec file: " + errorMessage); } // // Find the fiducial surface // BrainModelSurface* fiducialSurface = brainSet.getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_FIDUCIAL); if (fiducialSurface == NULL) { throw CommandException("Unable to find fiducial surface."); } // // Find the flat surface // BrainModelSurface* ellipsoidSurface = brainSet.getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL); if (ellipsoidSurface == NULL) { throw CommandException("Unable to find ellipsoid/spherical surface."); } // // Read the borders // BorderProjectionFile borderProjectionFile; borderProjectionFile.readFile(flattenBorderProjectionFileName); // // Read the paint file // PaintFile paintFile; if (inputPaintFileName.isEmpty() == false) { paintFile.readFile(inputPaintFileName); } // // Read the area color file // AreaColorFile areaColorFile; if (inputAreaColorFileName.isEmpty() == false) { areaColorFile.readFile(inputAreaColorFileName); } // // Execute the algorithm // BrainModelSurfaceFlattenHemisphere bmsfh(&brainSet, fiducialSurface, ellipsoidSurface, &borderProjectionFile, &paintFile, &areaColorFile, (outputFiducialSmoothedMedialWallCoordinateFileName.isEmpty() == false), false); bmsfh.execute(); // // Write paint file // if (outputPaintFileName.isEmpty() == false) { paintFile.writeFile(outputPaintFileName); } // // Write area color file // if (outputAreaColorFileName.isEmpty() == false) { areaColorFile.writeFile(outputAreaColorFileName); } // // Write the fiducial surface with smoothed medial wall name surface // if (outputFiducialSmoothedMedialWallCoordinateFileName.isEmpty() == false) { BrainModelSurface* bms = bmsfh.getFiducialSurfaceWithSmoothedMedialWall(); if (bms != NULL) { CoordinateFile* cf = bms->getCoordinateFile(); cf->writeFile(outputFiducialSmoothedMedialWallCoordinateFileName); } } // // Write the spherical surface // if (outputSphericalCoordinateFileName.isEmpty() == false) { BrainModelSurface* bms = bmsfh.getSphericalSurface(); if (bms != NULL) { CoordinateFile* cf = bms->getCoordinateFile(); cf->writeFile(outputSphericalCoordinateFileName); } } // // Write the initial flat surface // if (outputInitialFlatCoordinateFileName.isEmpty() == false) { BrainModelSurface* bms = bmsfh.getInitialFlatSurface(); if (bms != NULL) { CoordinateFile* cf = bms->getCoordinateFile(); cf->writeFile(outputInitialFlatCoordinateFileName); } } // // Write the open topology file // if (outputOpenTopologyFileName.isEmpty() == false) { TopologyFile* tf = bmsfh.getOpenTopologyFile(); if (tf != NULL) { tf->writeFile(outputOpenTopologyFileName); } } // // Write the cut topology file // if (outputCutTopologyFileName.isEmpty() == false) { TopologyFile* tf = bmsfh.getCutTopologyFile(); if (tf != NULL) { tf->writeFile(outputCutTopologyFileName); } } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceFlatMultiResMorphing.h0000664000175000017500000000356311572067322030667 0ustar michaelmichael #ifndef __COMMAND_SURFACE_FLAT_MULTI_RES_MORPHING_H__ #define __COMMAND_SURFACE_FLAT_MULTI_RES_MORPHING_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for surface flat multiresolution morphing class CommandSurfaceFlatMultiResMorphing : public CommandBase { public: // constructor CommandSurfaceFlatMultiResMorphing(); // destructor ~CommandSurfaceFlatMultiResMorphing(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_FLAT_MULTI_RES_MORPHING_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceFlatMultiResMorphing.cxx0000664000175000017500000001770311572067322031243 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BorderProjectionFile.h" #include "BrainModelSurfaceMultiresolutionMorphing.h" #include "BrainSet.h" #include "CommandSurfaceFlatMultiResMorphing.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SpecFile.h" #include "StatisticsUtilities.h" /** * constructor. */ CommandSurfaceFlatMultiResMorphing::CommandSurfaceFlatMultiResMorphing() : CommandBase("-surface-flat-multi-morph", "SURFACE FLAT MULTIRESOLUTION MORPHING") { } /** * destructor. */ CommandSurfaceFlatMultiResMorphing::~CommandSurfaceFlatMultiResMorphing() { } /** * get the script builder parameters. */ void CommandSurfaceFlatMultiResMorphing::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Spec File Name", FileFilters::getSpecFileFilter()); paramsOut.addFile("Fiducial Coordinate File Name", FileFilters::getCoordinateFiducialFileFilter()); paramsOut.addFile("Flat Coordinate File Name", FileFilters::getCoordinateFlatFileFilter()); paramsOut.addFile("Cut Topology File Name", FileFilters::getTopologyCutFileFilter()); paramsOut.addVariableListOfParameters("Options"); } /** * get full help information. */ QString CommandSurfaceFlatMultiResMorphing::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-ces-borderprojection-file \n" + indent9 + " \n" + indent9 + " ]\n" + indent9 + "\n" + indent9 + "Peform flat multi-resolution morphing (distortion correction)\n" + indent9 + "\n" + indent9 + "If a border projection file and the name of the central\n" + indent9 + "sulcus border are provided, the surface will be aligned\n" + indent9 + "to standard orientation.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceFlatMultiResMorphing::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString specFileName = parameters->getNextParameterAsString("Spec File Name"); const QString fiducialCoordinateFileName = parameters->getNextParameterAsString("Fiducial Coordinate File Name"); const QString flatCoordinateFileName = parameters->getNextParameterAsString("Flat Coordinate File Name"); const QString cutTopologyFileName = parameters->getNextParameterAsString("Cut Topology File Name"); QString borderProjectionFileName; QString centralSulcusBorderName; while (parameters->getParametersAvailable()) { const QString paramName(parameters->getNextParameterAsString("opt-param")); if (paramName == "-ces-borderprojection-file") { borderProjectionFileName = parameters->getNextParameterAsString("Border Projection File Name"); centralSulcusBorderName = parameters->getNextParameterAsString("Central Sulcus Border Name"); } else { throw CommandException("Unrecognized optional parameter: " + paramName); } } // // Read spec file // SpecFile specFile; specFile.readFile(specFileName); // // Set the selected files // specFile.setAllFileSelections(SpecFile::SPEC_FALSE); specFile.addToSpecFile(SpecFile::getCutTopoFileTag(), cutTopologyFileName, "", SpecFile::SPEC_FALSE); specFile.addToSpecFile(SpecFile::getFiducialCoordFileTag(), fiducialCoordinateFileName, "", SpecFile::SPEC_FALSE); specFile.addToSpecFile(SpecFile::getFlatCoordFileTag(), flatCoordinateFileName, "", SpecFile::SPEC_FALSE); // // Read the spec file into a brain set // QString errorMessage; BrainSet brainSet(true); if (brainSet.readSpecFile(specFile, specFileName, errorMessage)) { throw CommandException("Reading spec file: " + errorMessage); } // // Find the fiducial surface // BrainModelSurface* fiducialSurface = brainSet.getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_FIDUCIAL); if (fiducialSurface == NULL) { throw CommandException("Unable to find fiducial surface."); } // // Find the flat surface // BrainModelSurface* flatSurface = brainSet.getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_FLAT); if (flatSurface == NULL) { throw CommandException("Unable to find flat surface."); } // // Read the border projection file // BorderProjection centralSulcusBorderProjection; if (borderProjectionFileName.isEmpty() == false) { BorderProjectionFile borderProjectionFile; borderProjectionFile.readFile(borderProjectionFileName); const BorderProjection* cesBP = borderProjectionFile.getFirstBorderProjectionByName(centralSulcusBorderName); if (cesBP != NULL) { centralSulcusBorderProjection = *cesBP; } else { throw CommandException("Unable to find border projection named \"" + centralSulcusBorderName + "\" in border projection file \"" + borderProjectionFileName + "\"."); } } // // Do flat multiresolution morphing // BrainModelSurfaceMultiresolutionMorphing bmsmm(&brainSet, fiducialSurface, flatSurface, BrainModelSurfaceMorphing::MORPHING_SURFACE_FLAT, ¢ralSulcusBorderProjection); bmsmm.execute(); std::cout << "cycle " << "crossovers " << " avg AD " << " dev AD " << " avg LD " << " dev LD " << std::endl; std::vector meas; bmsmm.getMorphingMeasurements(meas); for (int i = 0; i < static_cast(meas.size()); i++) { QString name; StatisticsUtilities::DescriptiveStatistics ad, ld; int nodeCrossovers, tileCrossovers; float elapsedTime; meas[i].get(name, ad, ld, nodeCrossovers, tileCrossovers, elapsedTime); QString s; s.sprintf("%20s %10d %10.4f %10.4f %10.4f %10.4f", name.toAscii().constData(), nodeCrossovers, ad.average, ad.standardDeviation, ld.average, ld.standardDeviation); std::cout << s.toAscii().constData() << std::endl; } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceDistortion.h0000664000175000017500000000343311572067322026742 0ustar michaelmichael #ifndef __COMMAND_SURFACE_DISTORTION_H__ #define __COMMAND_SURFACE_DISTORTION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for surface distortion class CommandSurfaceDistortion : public CommandBase { public: // constructor CommandSurfaceDistortion(); // destructor ~CommandSurfaceDistortion(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_DISTORTION_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceDistortion.cxx0000664000175000017500000002035311572067322027315 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurface.h" #include "BrainModelSurfaceDistortion.h" #include "BrainSet.h" #include "CommandSurfaceDistortion.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SurfaceShapeFile.h" /** * constructor. */ CommandSurfaceDistortion::CommandSurfaceDistortion() : CommandBase("-surface-distortion", "SURFACE DISTORTION") { } /** * destructor. */ CommandSurfaceDistortion::~CommandSurfaceDistortion() { } /** * get the script builder parameters. */ void CommandSurfaceDistortion::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Fiducial Coordinate File Name", FileFilters::getCoordinateFiducialFileFilter()); paramsOut.addFile("Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Input Surface Shape File Name", FileFilters::getSurfaceShapeFileFilter()); paramsOut.addFile("Output Surface Shape File Name", FileFilters::getSurfaceShapeFileFilter()); paramsOut.addVariableListOfParameters("Distortion\nOptions"); } /** * get full help information. */ QString CommandSurfaceDistortion::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-generate-areal-distortion]\n" + indent9 + "[-generate-linear-distortion]\n" + indent9 + "[-areal-distortion-column-name name]\n" + indent9 + "[-linear-distortion-column-name name]\n" + indent9 + "\n" + indent9 + "Generate distortion measurements for the surfaces.\n" + indent9 + "\n" + indent9 + "The column names are optional, and, if not specified \n" + indent9 + "are " + SurfaceShapeFile::arealDistortionColumnName + "\n" + indent9 + "and " + SurfaceShapeFile::linearDistortionColumnName + " \n" + indent9 + "respectively.\n" + indent9 + "\n" + indent9 + "The \"input-surface-shape-file-name\" does not needs\n" + indent9 + "to exist.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceDistortion::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString fiducialCoordinateFileName = parameters->getNextParameterAsString("Fiducial Coordinate File Name"); const QString coordinateFileName = parameters->getNextParameterAsString("Coordinate File Name"); const QString topologyFileName = parameters->getNextParameterAsString("Topology File Name"); const QString inputSurfaceShapeFileName = parameters->getNextParameterAsString("Input Surface Shape File Name"); const QString outputSurfaceShapeFileName = parameters->getNextParameterAsString("Output Surface Shape File Name"); bool doArealFlag = false; bool doLinearFlag = false; QString arealDistortionColumnName(SurfaceShapeFile::arealDistortionColumnName); QString linearDistortionColumnName(SurfaceShapeFile::linearDistortionColumnName); // // Check optional parameters // while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("SURFACE DISTORTION parameter"); if (paramName == "-generate-areal-distortion") { doArealFlag = true; } else if (paramName == "-generate-linear-distortion") { doLinearFlag = true; } else if (paramName == "-areal-distortion-column-name") { arealDistortionColumnName = parameters->getNextParameterAsString("Areal Distortion column name"); } else if (paramName == "-linear-distortion-column-name") { linearDistortionColumnName = parameters->getNextParameterAsString("Linear Distortion column name"); } else { throw CommandException("unknown parameter: " + paramName); } } // // Check inputs // if ((doArealFlag == false) && (doLinearFlag == false)) { throw CommandException("At least one of " "\"-generate-areal-distortion\" or " "\"-generate-linear-distortion\" must be provided."); } // // Create a brain set // BrainSet brainSet(topologyFileName, fiducialCoordinateFileName, coordinateFileName, true); BrainModelSurface* fiducialBMS = brainSet.getBrainModelSurface(0); if (fiducialBMS == NULL) { throw CommandException("unable to find fiducial surface."); } TopologyFile* tf = fiducialBMS->getTopologyFile(); if (tf == NULL) { throw CommandException("unable to find topology."); } const int numNodes = fiducialBMS->getNumberOfNodes(); if (numNodes == 0) { throw CommandException("surface contains not nodes."); } BrainModelSurface* surfaceBMS = brainSet.getBrainModelSurface(1); if (surfaceBMS == NULL) { throw CommandException("unable to find second surface."); } // // Read input surface shape file // SurfaceShapeFile surfaceShapeFile; if (QFile::exists(inputSurfaceShapeFileName)) { surfaceShapeFile.readFile(inputSurfaceShapeFileName); } // // Set areal distortion column number // int arealColumnNumber = BrainModelSurfaceDistortion::DISTORTION_COLUMN_DO_NOT_GENERATE; if (doArealFlag) { arealColumnNumber = BrainModelSurfaceDistortion::DISTORTION_COLUMN_CREATE_NEW; const int col = surfaceShapeFile.getColumnWithName(arealDistortionColumnName); if (col >= 0) { arealColumnNumber = col; } } // // Set linear distortion column number // int linearColumnNumber = BrainModelSurfaceDistortion::DISTORTION_COLUMN_DO_NOT_GENERATE; if (doLinearFlag) { linearColumnNumber = BrainModelSurfaceDistortion::DISTORTION_COLUMN_CREATE_NEW; const int col = surfaceShapeFile.getColumnWithName(linearDistortionColumnName); if (col >= 0) { linearColumnNumber = col; } } // // Generate curvature // BrainModelSurfaceDistortion bmsd(&brainSet, surfaceBMS, fiducialBMS, tf, &surfaceShapeFile, arealColumnNumber, linearColumnNumber, arealDistortionColumnName, linearDistortionColumnName); bmsd.execute(); // // Write the surface shape file // surfaceShapeFile.writeFile(outputSurfaceShapeFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceCurvature.h0000664000175000017500000000342411572067322026564 0ustar michaelmichael #ifndef __COMMAND_SURFACE_CURVATURE_H__ #define __COMMAND_SURFACE_CURVATURE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for surface curvature class CommandSurfaceCurvature : public CommandBase { public: // constructor CommandSurfaceCurvature(); // destructor ~CommandSurfaceCurvature(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_CURVATURE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceCurvature.cxx0000664000175000017500000001703311572067322027140 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurface.h" #include "BrainModelSurfaceCurvature.h" #include "BrainSet.h" #include "CommandSurfaceCurvature.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SurfaceShapeFile.h" /** * constructor. */ CommandSurfaceCurvature::CommandSurfaceCurvature() : CommandBase("-surface-curvature", "SURFACE CURVATURE") { } /** * destructor. */ CommandSurfaceCurvature::~CommandSurfaceCurvature() { } /** * get the script builder parameters. */ void CommandSurfaceCurvature::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Input Surface Shape File Name", FileFilters::getSurfaceShapeFileFilter()); paramsOut.addFile("Output Surface Shape File Name", FileFilters::getSurfaceShapeFileFilter()); paramsOut.addVariableListOfParameters("Curvature Options"); } /** * get full help information. */ QString CommandSurfaceCurvature::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-generate-mean-curvature]\n" + indent9 + "[-generate-gaussian-curvature]\n" + indent9 + "[-mean-column-name name]\n" + indent9 + "[-gaussian-column-name name]\n" + indent9 + "\n" + indent9 + "Generate curvature measurements for the surface.\n" + indent9 + "\n" + indent9 + "The column names are optional, and, if not specified \n" + indent9 + "are " + SurfaceShapeFile::meanCurvatureColumnName + "\n" + indent9 + "and " + SurfaceShapeFile::gaussianCurvatureColumnName + " \n" + indent9 + "respectively.\n" + indent9 + "\n" + indent9 + "The \"input-surface-shape-file-name\" does not needs\n" + indent9 + "to exist.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceCurvature::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString coordinateFileName = parameters->getNextParameterAsString("Coordinate File Name"); const QString topologyFileName = parameters->getNextParameterAsString("Topology File Name"); const QString inputSurfaceShapeFileName = parameters->getNextParameterAsString("Input Surface Shape File Name"); const QString outputSurfaceShapeFileName = parameters->getNextParameterAsString("Output Surface Shape File Name"); bool doMean = false; bool doGaussian = false; QString meanCurvatureColumnName(SurfaceShapeFile::meanCurvatureColumnName); QString gaussianCurvatureColumnName(SurfaceShapeFile::gaussianCurvatureColumnName); // // Check optional parameters // while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("SURFACE CURVATURE parameter"); if (paramName == "-generate-mean-curvature") { doMean = true; } else if (paramName == "-generate-gaussian-curvature") { doGaussian = true; } else if (paramName == "-mean-column-name") { meanCurvatureColumnName = parameters->getNextParameterAsString("SURFACE CURVATURE mean column name"); } else if (paramName == "-gaussian-column-name") { gaussianCurvatureColumnName = parameters->getNextParameterAsString("SURFACE CURVATURE gaussian column name"); } else { throw CommandException("unknown parameter: " + paramName); } } // // Check inputs // if ((doMean == false) && (doGaussian == false)) { throw CommandException("At least one of " "\"-generate-mean-curvature\" or " "\"-generate-gaussian-curvature\" must be provided."); } // // Create a brain set // BrainSet brainSet(topologyFileName, coordinateFileName, "", true); BrainModelSurface* bms = brainSet.getBrainModelSurface(0); if (bms == NULL) { throw CommandException("unable to find surface."); } const TopologyFile* tf = bms->getTopologyFile(); if (tf == NULL) { throw CommandException("unable to find topology."); } const int numNodes = bms->getNumberOfNodes(); if (numNodes == 0) { throw CommandException("surface contains not nodes."); } // // Read input surface shape file // SurfaceShapeFile surfaceShapeFile; if (QFile::exists(inputSurfaceShapeFileName)) { surfaceShapeFile.readFile(inputSurfaceShapeFileName); } // // Set mean column number // int meanColumnNumber = BrainModelSurfaceCurvature::CURVATURE_COLUMN_DO_NOT_GENERATE; if (doMean) { meanColumnNumber = BrainModelSurfaceCurvature::CURVATURE_COLUMN_CREATE_NEW; const int col = surfaceShapeFile.getColumnWithName(meanCurvatureColumnName); if (col >= 0) { meanColumnNumber = col; } } // // Set gaussian column number // int gaussianColumnNumber = BrainModelSurfaceCurvature::CURVATURE_COLUMN_DO_NOT_GENERATE; if (doGaussian) { gaussianColumnNumber = BrainModelSurfaceCurvature::CURVATURE_COLUMN_CREATE_NEW; const int col = surfaceShapeFile.getColumnWithName(gaussianCurvatureColumnName); if (col >= 0) { gaussianColumnNumber = col; } } // // Generate curvature // BrainModelSurfaceCurvature bmsc(&brainSet, bms, &surfaceShapeFile, meanColumnNumber, gaussianColumnNumber, meanCurvatureColumnName, gaussianCurvatureColumnName); bmsc.execute(); // // Write the surface shape file // surfaceShapeFile.writeFile(outputSurfaceShapeFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceCrossoverCheck.h0000664000175000017500000000347311572067322027533 0ustar michaelmichael #ifndef __COMMAND_SURFACE_CROSSOVER_CHECK_H__ #define __COMMAND_SURFACE_CROSSOVER_CHECK_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for surface crossover check class CommandSurfaceCrossoverCheck : public CommandBase { public: // constructor CommandSurfaceCrossoverCheck(); // destructor ~CommandSurfaceCrossoverCheck(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_CROSSOVER_CHECK_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceCrossoverCheck.cxx0000664000175000017500000001464011572067322030104 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurface.h" #include "BrainSet.h" #include "BrainSetNodeAttribute.h" #include "CommandSurfaceCrossoverCheck.h" #include "FileFilters.h" #include "FileUtilities.h" #include "NodeRegionOfInterestFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "TopologyFile.h" /** * constructor. */ CommandSurfaceCrossoverCheck::CommandSurfaceCrossoverCheck() : CommandBase("-surface-crossover-check", "SURFACE CROSSOVER CHECK") { } /** * destructor. */ CommandSurfaceCrossoverCheck::~CommandSurfaceCrossoverCheck() { } /** * get the script builder parameters. */ void CommandSurfaceCrossoverCheck::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addVariableListOfParameters("Crossover Options"); } /** * get full help information. */ QString CommandSurfaceCrossoverCheck::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-roi-file roi-file-name]\n" + indent9 + "[-surface-type SURFACE-TYPE]\n" + indent9 + "\n" + indent9 + "Perform a crossover check on a surface.\n" + indent9 + "\n" + indent9 + "If a region of interest file name is supplied, the ROI is\n" + indent9 + "set to the nodes identified as crossovers.\n" + indent9 + "\n" + indent9 + "If a SURFACE-TYPE is specified it must be one of the \n" + indent9 + "types listed below. If no SURFACE-TYPE is supplied, the\n" + indent9 + "type contained in coordinate file will be used.\n"); std::vector surfaceTypes; std::vector surfaceTypeNames; BrainModelSurface::getSurfaceTypesAndNames(surfaceTypes, surfaceTypeNames); for (int i = 0; i < static_cast(surfaceTypeNames.size()); i++) { helpInfo += (indent9 + " " + surfaceTypeNames[i] + "\n"); } helpInfo += "\n"; return helpInfo; } /** * execute the command. */ void CommandSurfaceCrossoverCheck::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString coordinateFileName = parameters->getNextParameterAsString("Coordinate File Name"); const QString topologyFileName = parameters->getNextParameterAsString("Topology File Name"); // // Create a brain set // BrainSet brainSet(topologyFileName, coordinateFileName, "", true); BrainModelSurface* bms = brainSet.getBrainModelSurface(0); if (bms == NULL) { throw CommandException("unable to find surface."); } const TopologyFile* tf = bms->getTopologyFile(); if (tf == NULL) { throw CommandException("unable to find topology."); } const int numNodes = bms->getNumberOfNodes(); if (numNodes == 0) { throw CommandException("surface contains not nodes."); } // // Check optional parameters // QString roiFileName; while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("SURFACE CROSSOVER CHECK parameter"); if (paramName == "-roi-file") { roiFileName = parameters->getNextParameterAsString("SURFACE CROSSOVER ROI file name"); } else if (paramName == "-surface-type") { const QString surfaceTypeString = parameters->getNextParameterAsString("SURFACE CROSSOVER SURFACE-TYPE"); const BrainModelSurface::SURFACE_TYPES surfaceType = BrainModelSurface::getSurfaceTypeFromConfigurationID(surfaceTypeString); bms->setSurfaceType(surfaceType); } else { throw CommandException("unknown parameter: " + paramName); } } // // Do the crossover check // int tileCrossovers = 0; int nodeCrossovers = 0; bms->crossoverCheck(tileCrossovers, nodeCrossovers, bms->getSurfaceType()); // // Create optional ROI file // if (roiFileName.isEmpty() == false) { NodeRegionOfInterestFile roiFile; roiFile.setNumberOfNodes(numNodes); for (int i = 0; i < numNodes; i++) { if (brainSet.getNodeAttributes(i)->getCrossover() == BrainSetNodeAttribute::CROSSOVER_YES) { roiFile.setNodeSelected(i, true); } } roiFile.writeFile(roiFileName); } // // Print results // std::cout << "Crossover Check for " << FileUtilities::basename(coordinateFileName).toAscii().constData() << " " << FileUtilities::basename(topologyFileName).toAscii().constData() << std::endl; std::cout << " Tile Crossovers: " << tileCrossovers << std::endl; std::cout << " Node Crossovers: " << nodeCrossovers << std::endl; } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceCellUnprojection.h0000664000175000017500000000414311572067322030062 0ustar michaelmichael #ifndef __COMMAND_SURFACE_CELL_UNPROJECTION_H__ #define __COMMAND_SURFACE_CELL_UNPROJECTION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandSurfaceCellUnprojection : public CommandBase { public: // constructor CommandSurfaceCellUnprojection(const QString& operationSwitchIn = "-surface-cell-unprojection", const QString& shortDescriptionIn = "SURFACE CELL UNPROJECTION", const bool fociFlagIn = false); // destructor virtual ~CommandSurfaceCellUnprojection(); // get full help information virtual QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command virtual void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); // foci processing flag bool fociFlag; }; #endif // __COMMAND_SURFACE_CELL_UNPROJECTION_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceCellUnprojection.cxx0000664000175000017500000001312711572067322030437 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurface.h" #include "BrainSet.h" #include "CellFile.h" #include "CellProjectionUnprojector.h" #include "CellProjectionFile.h" #include "FociFile.h" #include "FociProjectionFile.h" #include "CommandSurfaceCellUnprojection.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandSurfaceCellUnprojection::CommandSurfaceCellUnprojection(const QString& operationSwitchIn, const QString& shortDescriptionIn, const bool fociFlagIn) : CommandBase(operationSwitchIn, shortDescriptionIn) { fociFlag = fociFlagIn; } /** * destructor. */ CommandSurfaceCellUnprojection::~CommandSurfaceCellUnprojection() { } /** * get the script builder parameters. */ void CommandSurfaceCellUnprojection::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Topology File Name", FileFilters::getTopologyGenericFileFilter()); if (fociFlag) { paramsOut.addFile("Input Foci Projection File", FileFilters::getFociProjectionFileFilter()); paramsOut.addFile("Output Foci File", FileFilters::getFociFileFilter()); } else { paramsOut.addFile("Input Cell Projection File", FileFilters::getCellProjectionFileFilter()); paramsOut.addFile("Output Cell File", FileFilters::getCellFileFilter()); } } /** * get full help information. */ QString CommandSurfaceCellUnprojection::getHelpInformation() const { QString s = "cell"; if (fociFlag) s = "foci"; QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Unproject the " + s + " projections to the surface and save\n" + indent9 + "the " + s + " file.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceCellUnprojection::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { QString s = "Cell"; if (fociFlag) s = "Foci"; const QString coordinateFileName = parameters->getNextParameterAsString("Coordinate File Name"); const QString topologyFileName = parameters->getNextParameterAsString("Topology File Name"); const QString cellProjectionFileName = parameters->getNextParameterAsString(s + " Projection File Name"); const QString cellFileName = parameters->getNextParameterAsString(s + " File Name"); checkForExcessiveParameters(); // // Create a brain set // BrainSet brainSet(topologyFileName, coordinateFileName, "", true); BrainModelSurface* bms = brainSet.getBrainModelSurface(0); if (bms == NULL) { throw CommandException("unable to find surface."); } const TopologyFile* tf = bms->getTopologyFile(); if (tf == NULL) { throw CommandException("unable to find topology."); } const int numNodes = bms->getNumberOfNodes(); if (numNodes == 0) { throw CommandException("surface contains not nodes."); } // // Load the cell projection file // CellProjectionFile* cellProjectionFile = NULL; if (fociFlag) { cellProjectionFile = new FociProjectionFile; } else { cellProjectionFile = new CellProjectionFile; } cellProjectionFile->readFile(cellProjectionFileName); // // Unproject the cells // CellFile* cellFile = NULL; if (fociFlag) { cellFile = new FociFile; } else { cellFile = new CellFile; } CellProjectionUnprojector unprojector; unprojector.unprojectCellProjections(*cellProjectionFile, bms, *cellFile, 0); // // Write the cell file // cellFile->writeFile(cellFileName); // // Clean up // delete cellFile; delete cellProjectionFile; } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceCellProjection.h0000664000175000017500000000410411572067322027514 0ustar michaelmichael #ifndef __COMMAND_SURFACE_CELL_PROJECTION_H__ #define __COMMAND_SURFACE_CELL_PROJECTION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for surface cell projection class CommandSurfaceCellProjection : public CommandBase { public: // constructor CommandSurfaceCellProjection(const QString& operationSwitchIn = "-surface-cell-projection", const QString& shortDescriptionIn = "SURFACE CELL PROJECTION", const bool fociFlagIn = false); // destructor ~CommandSurfaceCellProjection(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); // foci flag bool fociFlag; }; #endif // __COMMAND_SURFACE_CELL_PROJECTION_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceCellProjection.cxx0000664000175000017500000001462511572067322030100 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurface.h" #include "BrainSet.h" #include "CellFile.h" #include "CellFileProjector.h" #include "CellProjectionFile.h" #include "CommandSurfaceCellProjection.h" #include "FileFilters.h" #include "FociFile.h" #include "FociProjectionFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandSurfaceCellProjection::CommandSurfaceCellProjection(const QString& operationSwitchIn, const QString& shortDescriptionIn, const bool fociFlagIn) : CommandBase(operationSwitchIn, shortDescriptionIn) { fociFlag = fociFlagIn; } /** * destructor. */ CommandSurfaceCellProjection::~CommandSurfaceCellProjection() { } /** * get the script builder parameters. */ void CommandSurfaceCellProjection::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Topology File Name", FileFilters::getTopologyGenericFileFilter()); if (fociFlag) { paramsOut.addFile("Input Foci File", FileFilters::getFociFileFilter()); paramsOut.addFile("Output Foci Projection File", FileFilters::getFociProjectionFileFilter()); } else { paramsOut.addFile("Input Cell File", FileFilters::getCellFileFilter()); paramsOut.addFile("Output Cell Projection File", FileFilters::getCellProjectionFileFilter()); } } /** * get full help information. */ QString CommandSurfaceCellProjection::getHelpInformation() const { QString s = "cell"; if (fociFlag) s = "foci"; QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-project-onto-surface onto-surface-above-distance]\n" + indent9 + "\n" + indent9 + "Project the " + s + " to the surface and save into the " + s + "\n" + indent9 + "projection file.\n" + indent9 + "\n" + indent9 + "\"-project-onto-surface\" is used to project the " + s + " so that\n" + indent9 + "they are a specified distance above the surface.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceCellProjection::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { QString s = "Cell"; if (fociFlag) s = "Foci"; const QString coordinateFileName = parameters->getNextParameterAsString("Coordinate File Name"); const QString topologyFileName = parameters->getNextParameterAsString("Topology File Name"); const QString cellFileName = parameters->getNextParameterAsString(s + " File Name"); const QString cellProjectionFileName = parameters->getNextParameterAsString(s + " Projection File Name"); // // Process optional parameters // bool projectToSurfaceFlag = false; float surfaceAboveDistance = 0.0; while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString(s + " Projection Parameter"); if (paramName == "-project-onto-surface") { projectToSurfaceFlag = true; surfaceAboveDistance = parameters->getNextParameterAsFloat(s + " Projection Parameter: Above surface distance"); } else { throw CommandException("unrecognized option"); } } // // Create a brain set // BrainSet brainSet(topologyFileName, coordinateFileName, "", true); const BrainModelSurface* bms = brainSet.getBrainModelSurface(0); if (bms == NULL) { throw CommandException("unable to find surface."); } const TopologyFile* tf = bms->getTopologyFile(); if (tf == NULL) { throw CommandException("unable to find topology."); } const int numNodes = bms->getNumberOfNodes(); if (numNodes == 0) { throw CommandException("surface contains no nodes."); } // // Read the cell file // CellFile* cellFile = NULL; if (fociFlag) { cellFile = new FociFile; } else { cellFile = new CellFile; } cellFile->readFile(cellFileName); // // Project the cell file // CellProjectionFile* cellProjectionFile = NULL; if (fociFlag) { cellProjectionFile = new FociProjectionFile; } else { cellProjectionFile = new CellProjectionFile; } cellProjectionFile->appendFiducialCellFile(*cellFile); CellFileProjector projector(bms); projector.projectFile(cellProjectionFile, 0, CellFileProjector::PROJECTION_TYPE_ALL, surfaceAboveDistance, projectToSurfaceFlag, NULL); // // Write the cell projection file // cellProjectionFile->writeFile(cellProjectionFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceCellCreate.h0000664000175000017500000000406411572067322026610 0ustar michaelmichael #ifndef __COMMAND_SURFACE_CELL_CREATE_H__ #define __COMMAND_SURFACE_CELL_CREATE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for creating surface cells class CommandSurfaceCellCreate : public CommandBase { public: // constructor CommandSurfaceCellCreate(const QString& operationSwitchIn = "-surface-cell-create", const QString& shortDescriptionIn = "SURFACE CELL CREATION", const bool fociFlagIn = false); // destructor virtual ~CommandSurfaceCellCreate(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); // foci flag bool fociFlag; }; #endif // __COMMAND_SURFACE_CELL_CREATE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceCellCreate.cxx0000664000175000017500000003212311572067322027160 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelSurface.h" #include "BrainSet.h" #include "CellFile.h" #include "CellFileProjector.h" #include "CellProjectionFile.h" #include "CommandSurfaceCellCreate.h" #include "FileFilters.h" #include "FociProjectionFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "TopologyFile.h" /** * constructor. */ CommandSurfaceCellCreate::CommandSurfaceCellCreate(const QString& operationSwitchIn, const QString& shortDescriptionIn, const bool fociFlagIn) : CommandBase(operationSwitchIn, shortDescriptionIn) { fociFlag = fociFlagIn; } /** * destructor. */ CommandSurfaceCellCreate::~CommandSurfaceCellCreate() { } /** * get the script builder parameters. */ void CommandSurfaceCellCreate::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { QString s = "Cell"; if (fociFlag) s = "Foci"; paramsOut.clear(); paramsOut.addFile("Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Input " + s + " Projection File Name", FileFilters::getCellProjectionFileFilter()); paramsOut.addFile("Output " + s + " Projection File Name", FileFilters::getCellProjectionFileFilter()); paramsOut.addVariableListOfParameters(s + " Options"); } /** * get full help information. */ QString CommandSurfaceCellCreate::getHelpInformation() const { QString s = "cell"; QString s2 = "cell"; if (fociFlag) { s = "foci"; s2 = "focus"; } QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-at-node " + s2 + " -name node-number]\n" + indent9 + "[-" + s2 + " " + s2 + "-name X Y Z]\n" + indent9 + "[-" + s2 + "-offset " + s2 + "-name " + s + "-offset-name off-X off-Y off-Z]\n" + indent9 + "[-" + s2 + "-offset-xyz " + s2 + "-name \n" + indent9 + " x-" + s2 + "-offset-name offset-X \n" + indent9 + " y-" + s2 + "-offset-name offset-Y \n" + indent9 + " z-" + s2 + "-offset-name offset-Z] \n" + indent9 + "\n" + indent9 + "Create new " + s2 + " located at either an XYZ coordinate or on\n" + indent9 + "a node. The input " + s + " projection file does not need to exist.\n" + indent9 + "\n" + indent9 + "The offset mode creates a new " + s2 + " that is offset from \n" + indent9 + "the \"" + s2 + "-offset-name\" by (off-X, off-Y, off-Z).\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceCellCreate::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { QString s = "Cell"; if (fociFlag) s = "Foci"; const QString coordinateFileName = parameters->getNextParameterAsString("Coordinate File Name"); const QString topologyFileName = parameters->getNextParameterAsString("Topology File Name"); const QString inputCellProjectionFileName = parameters->getNextParameterAsString("Input " + s + " Projection File Name"); const QString outputCellProjectionFileName = parameters->getNextParameterAsString("Output " + s + " Projection File Name"); // // Create a brain set // BrainSet brainSet(topologyFileName, coordinateFileName, "", true); BrainModelSurface* bms = brainSet.getBrainModelSurface(0); if (bms == NULL) { throw CommandException("unable to find surface."); } const TopologyFile* tf = bms->getTopologyFile(); if (tf == NULL) { throw CommandException("unable to find topology."); } const int numNodes = bms->getNumberOfNodes(); if (numNodes == 0) { throw CommandException("surface contains no nodes."); } // // Always assume surface is a fiducial // bms->setSurfaceType(BrainModelSurface::SURFACE_TYPE_FIDUCIAL); // // Read input cell projection file // CellProjectionFile* cellProjectionFile = NULL; if (fociFlag) { cellProjectionFile = new FociProjectionFile; } else { cellProjectionFile = new CellProjectionFile; } if (QFile::exists(inputCellProjectionFileName)) { cellProjectionFile->readFile(inputCellProjectionFileName); } // // File for new cells // CellFile cellFile; // // Loop through options // while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("Create " + s + " Parameter"); if ((paramName == "-cell") || (paramName == "-focus")) { const QString cellName = parameters->getNextParameterAsString(s + " Name"); const float x = parameters->getNextParameterAsFloat(s + " X"); const float y = parameters->getNextParameterAsFloat(s + " Y"); const float z = parameters->getNextParameterAsFloat(s + " Z"); CellData cd(cellName, x, y, z); cellFile.addCell(cd); } else if ((paramName == "-cell-offset") || (paramName == "-focus-offset")) { const QString cellName = parameters->getNextParameterAsString(s + " Name"); const QString cellOffsetName = parameters->getNextParameterAsString(s + "Offset Name"); const float xOffset = parameters->getNextParameterAsFloat(s + " Off-X"); const float yOffset = parameters->getNextParameterAsFloat(s + " Off-Y"); const float zOffset = parameters->getNextParameterAsFloat(s + " Off-Z"); // // Find offset cell // const CellProjection* cp = cellProjectionFile->getLastCellProjectionWithName(cellOffsetName); if (cp == NULL) { throw CommandException(" offset " + s + " named " + cellOffsetName + " not found."); } float xyz[3]; if (cp->getProjectedPosition(bms->getCoordinateFile(), tf, bms->getIsFiducialSurface(), bms->getIsFlatSurface(), false, xyz) == false) { throw CommandException("offset " + s + " named " + cellOffsetName + " does not have valid projected position."); } // // Create new cell with offset // const float x = xyz[0] + xOffset; const float y = xyz[1] + yOffset; const float z = xyz[2] + zOffset; CellData cd(cellName, x, y, z); cellFile.addCell(cd); } else if ((paramName == "-cell-offset-xyz") || (paramName == "-focus-offset-xyz")) { const QString cellName = parameters->getNextParameterAsString(s + " Name"); const QString cellXOffsetName = parameters->getNextParameterAsString(s + " X-Offset Name"); const float xOffset = parameters->getNextParameterAsFloat(s + " Off-X"); const QString cellYOffsetName = parameters->getNextParameterAsString(s + " X-Offset Name"); const float yOffset = parameters->getNextParameterAsFloat(s + " Off-Y"); const QString cellZOffsetName = parameters->getNextParameterAsString(s + " X-Offset Name"); const float zOffset = parameters->getNextParameterAsFloat(s + " Off-Z"); // // Find offset cell X // const CellProjection* cpX = cellProjectionFile->getLastCellProjectionWithName(cellXOffsetName); if (cpX == NULL) { throw CommandException(" offset " + s + " named " + cellXOffsetName + " not found."); } float xyz[3]; if (cpX->getProjectedPosition(bms->getCoordinateFile(), tf, bms->getIsFiducialSurface(), bms->getIsFlatSurface(), false, xyz) == false) { throw CommandException("offset " + s + " named " + cellXOffsetName + " does not have valid projected position."); } const float newCellX = xyz[0] + xOffset; // // Find offset cell Y // const CellProjection* cpY = cellProjectionFile->getLastCellProjectionWithName(cellYOffsetName); if (cpY == NULL) { throw CommandException(" offset " + s + " named " + cellYOffsetName + " not found."); } if (cpY->getProjectedPosition(bms->getCoordinateFile(), tf, bms->getIsFiducialSurface(), bms->getIsFlatSurface(), false, xyz) == false) { throw CommandException("offset " + s + " named " + cellYOffsetName + " does not have valid projected position."); } const float newCellY = xyz[1] + yOffset; // // Find offset cell Z // const CellProjection* cpZ = cellProjectionFile->getLastCellProjectionWithName(cellZOffsetName); if (cpZ == NULL) { throw CommandException(" offset " + s + " named " + cellZOffsetName + " not found."); } if (cpZ->getProjectedPosition(bms->getCoordinateFile(), tf, bms->getIsFiducialSurface(), bms->getIsFlatSurface(), false, xyz) == false) { throw CommandException("offset " + s + " named " + cellZOffsetName + " does not have valid projected position."); } const float newCellZ = xyz[2] + zOffset; // // Create new cell with offset // CellData cd(cellName, newCellX, newCellY, newCellZ); cellFile.addCell(cd); } else if (paramName == "-at-node") { const QString cellName = parameters->getNextParameterAsString(s + " Name"); const int nodeNumber = parameters->getNextParameterAsInt(s + " Node Number"); if ((nodeNumber >= 0) && (nodeNumber < numNodes)) { const float* xyz = bms->getCoordinateFile()->getCoordinate(nodeNumber); CellData cd(cellName, xyz[0], xyz[1], xyz[2]); cellFile.addCell(cd); } else { throw CommandException("invalid node number: " + QString::number(nodeNumber)); } } else { throw CommandException("Create unknown parameter: " + paramName); } } if (cellFile.getNumberOfCells() <= 0) { throw CommandException("No " + s + " were created."); } // // Project the cells // CellProjectionFile projCellFile; projCellFile.appendFiducialCellFile(cellFile); CellFileProjector cfp(bms); cfp.projectFile(&projCellFile, 0, CellFileProjector::PROJECTION_TYPE_ALL, 0.0, false, NULL); // // Append new cells // cellProjectionFile->append(projCellFile); // // Write cell projection file // cellProjectionFile->writeFile(outputCellProjectionFileName); delete cellProjectionFile; } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderVariability.h0000664000175000017500000000447411572067322030227 0ustar michaelmichael #ifndef __COMMAND_SURFACE_BORDER_VARIABILITY_H__ #define __COMMAND_SURFACE_BORDER_VARIABILITY_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" class BorderFile; /// class for surface border variability class CommandSurfaceBorderVariability : public CommandBase { public: // constructor CommandSurfaceBorderVariability(); // destructor ~CommandSurfaceBorderVariability(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); /// do the border report void doBorderReport(const BorderFile& bf, const float threshold, const bool showRatiosExceededFlag); /// do the border point report void doBorderPointReport(const BorderFile& bf, const BorderFile& avgBorderFile, const float threshold) throw (CommandException); }; #endif // __COMMAND_SURFACE_BORDER_VARIABILITY_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderVariability.cxx0000664000175000017500000002757311572067322030607 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BorderFile.h" #include "CommandSurfaceBorderVariability.h" #include "FileFilters.h" #include "FileUtilities.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "StatisticDataGroup.h" #include "StatisticDescriptiveStatistics.h" /** * constructor. */ CommandSurfaceBorderVariability::CommandSurfaceBorderVariability() : CommandBase("-surface-border-variability", "SURFACE BORDER VARIABILITY") { } /** * destructor. */ CommandSurfaceBorderVariability::~CommandSurfaceBorderVariability() { } /** * get the script builder parameters. */ void CommandSurfaceBorderVariability::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Border File", FileFilters::getBorderGenericFileFilter()); paramsOut.addFile("Input Landmark Average Border File", FileFilters::getBorderGenericFileFilter()); paramsOut.addFile("Output Border File", FileFilters::getBorderGenericFileFilter()); //paramsOut.addBoolean("Do Report", false); paramsOut.addVariableListOfParameters("Options"); } /** * get full help information. */ QString CommandSurfaceBorderVariability::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-abs-distance] \n" + indent9 + "[-border-report] \n" + indent9 + "[-border-point-report] \n" + indent9 + "[-threshold value] \n" + indent9 + "\n" + indent9 + "Create a new border file that shows the variability.\n" + indent9 + "of the input and corresponding landmark variability.\n" + indent9 + "\n" + indent9 + "if \"-abs-distance\" is used, the variability is set\n" + indent9 + "to the distance between the border point and the nearest\n" + indent9 + "location in the corresponding border. Otherwise, the\n" + indent9 + "variability is set to the distance divided by the\n" + indent9 + "landmark variability.\n" + indent9 + "\n" + indent9 + "The threshold default value is 2.5.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceBorderVariability::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputBorderFileName = parameters->getNextParameterAsString("Input Border File Name"); const QString inputLandmarkAverageBorderFileName = parameters->getNextParameterAsString("Input Landmark Average Border File Name"); const QString outputBorderFileName = parameters->getNextParameterAsString("Output Border File Name"); bool borderReportFlag = false; bool borderPointReportFlag = false; bool absoluteDistanceFlag = false; float threshold = 2.5; float extremeThreshold = 4.5; while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("Optional Parameter"); if (paramName == "-border-report") { borderReportFlag = true; } else if (paramName == "-border-point-report") { borderPointReportFlag = true; } else if (paramName == "-threshold") { threshold = parameters->getNextParameterAsFloat("Threshold"); } else if (paramName == "-abs-distance") { absoluteDistanceFlag = true; } else { throw CommandException("Unrecognized parameter: " + paramName); } } BorderFile inputBorderFile; inputBorderFile.readFile(inputBorderFileName); BorderFile inputLandmarkAverageBorderFile; inputLandmarkAverageBorderFile.readFile(inputLandmarkAverageBorderFileName); //inputBorderFile.resampleToMatchLandmarkBorders(inputLandmarkAverageBorderFile); BorderFile outputBorderFile; QString textReport; BorderFile::evaluateLandmarkVariability(inputBorderFile, inputLandmarkAverageBorderFile, threshold, extremeThreshold, absoluteDistanceFlag, outputBorderFile, textReport); outputBorderFile.writeFile(outputBorderFileName); std::cout << textReport.toAscii().constData() << std::endl; if (borderReportFlag) { doBorderReport(inputBorderFile, threshold, true); doBorderReport(inputLandmarkAverageBorderFile, threshold, false); } if (borderPointReportFlag) { doBorderPointReport(inputBorderFile, inputLandmarkAverageBorderFile, threshold); } } /** * do the border report. */ void CommandSurfaceBorderVariability::doBorderReport(const BorderFile& bf, const float threshold, const bool showRatiosExceededFlag) { std::cout << QString(60, '=').toAscii().constData() << std::endl; std::cout << "Border Summary: " << FileUtilities::basename(bf.getFileName()).toAscii().constData() << std::endl; std::cout << "BorderName Min Max Mean StdDev NumberOfLinks" << std::endl; std::cout << std::endl; std::vector namesWithVariabilityGreaterThanTwo; std::vector countWithVariabilityGreaterThanTwo; const int numBorders = bf.getNumberOfBorders(); for (int i = 0; i < numBorders; i++) { const Border* border = bf.getBorder(i); // // Get the variability from the links // int numLinksWithVariabilityGreaterThanTwo = 0; std::vector variability; const int numLinks = border->getNumberOfLinks(); if (numLinks > 0) { for (int j = 0; j < numLinks; j++) { const float radius = border->getLinkRadius(j); variability.push_back(radius); if (radius > threshold) { numLinksWithVariabilityGreaterThanTwo++; } } } if (numLinksWithVariabilityGreaterThanTwo > 0) { namesWithVariabilityGreaterThanTwo.push_back(border->getName()); countWithVariabilityGreaterThanTwo.push_back(numLinksWithVariabilityGreaterThanTwo); } // // Compute descriptive statistics // StatisticDataGroup sdg(&variability, StatisticDataGroup::DATA_STORAGE_MODE_POINT); StatisticDescriptiveStatistics sds; sds.addDataGroup(&sdg); try { sds.execute(); } catch (StatisticException&) { } // // Print results // float minValue, maxValue; sds.getMinimumAndMaximum(minValue, maxValue); std::cout << border->getName().toAscii().constData() << " " << minValue << " " << maxValue << " " << sds.getMean() << " " << sds.getStandardDeviation() << " " << numLinks << std::endl; } if (showRatiosExceededFlag) { const int numGT2 = static_cast(namesWithVariabilityGreaterThanTwo.size()); if (numGT2 > 0) { std::cout << QString(60, '=').toAscii().constData() << std::endl; std::cout << "The following borders had at least one point whose ratio exceeded " << threshold << ": " << std::endl; for (int i = 0; i < numGT2; i++) { std::cout << namesWithVariabilityGreaterThanTwo[i].toAscii().constData() << " : " << countWithVariabilityGreaterThanTwo[i] << " points" << std::endl; } } } std::cout << std::endl; } /** * do the border point report. */ void CommandSurfaceBorderVariability::doBorderPointReport(const BorderFile& bfIn, const BorderFile& avgBorderFileIn, const float threshold) throw (CommandException) { std::vector originalBorderNames; BorderFile bf = bfIn; const int numBorders = bf.getNumberOfBorders(); for (int i = 0; i < numBorders; i++) { Border* b = bf.getBorder(i); originalBorderNames.push_back(b->getName()); b->removeLandmarkRaterInfoFromBorderName(); } BorderFile avgBorderFile = avgBorderFileIn; const int numAvgBorders = avgBorderFile.getNumberOfBorders(); for (int i = 0; i < numAvgBorders; i++) { avgBorderFile.getBorder(i)->removeLandmarkRaterInfoFromBorderName(); } std::cout << QString(60, '=').toAscii().constData() << std::endl; std::cout << "Source Border: " << FileUtilities::basename(bf.getFileName()).toAscii().constData() << std::endl; for (int i = 0; i < numBorders; i++) { const Border* border = bf.getBorder(i); const Border* avgBorder = avgBorderFile.getBorderByName(border->getName()); if (avgBorder == NULL) { throw CommandException("Border named " + border->getName() + " not found in average border file."); } // // Get the variability from the links // const int numLinks = border->getNumberOfLinks(); if (numLinks != avgBorder->getNumberOfLinks()) { throw CommandException("Border named " + border->getName() + " has different number of links in the border files."); } std::cout << QString(60, '=').toAscii().constData() << std::endl; std::cout << "Border Name: " << originalBorderNames[i].toAscii().constData() << std::endl; std::cout << std::endl; std::cout << "PointIndex Distance TargetVar Ratio" << std::endl; if (numLinks > 0) { for (int j = 0; j < numLinks; j++) { const float avg3dVar = avgBorder->getLinkRadius(j); const float ratio = border->getLinkRadius(j); const float d = ratio * avg3dVar; std::cout << j << " " << d << " " << avg3dVar << " " << ratio; if (ratio > threshold) { std::cout << " ***"; } std::cout << std::endl; } } } std::cout << std::endl; } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderUnprojection.h0000664000175000017500000000352711572067322030425 0ustar michaelmichael #ifndef __COMMAND_SURFACE_BORDER_UNPROJECTION_H__ #define __COMMAND_SURFACE_BORDER_UNPROJECTION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for surface border unprojection class CommandSurfaceBorderUnprojection : public CommandBase { public: // constructor CommandSurfaceBorderUnprojection(); // destructor ~CommandSurfaceBorderUnprojection(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_BORDER_UNPROJECTION_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderUnprojection.cxx0000664000175000017500000001117711572067322031000 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BorderFile.h" #include "BorderProjectionFile.h" #include "BorderProjectionUnprojector.h" #include "BrainModelSurface.h" #include "BrainSet.h" #include "CommandSurfaceBorderUnprojection.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandSurfaceBorderUnprojection::CommandSurfaceBorderUnprojection() : CommandBase("-surface-border-unprojection", "SURFACE BORDER UNPROJECTION") { } /** * destructor. */ CommandSurfaceBorderUnprojection::~CommandSurfaceBorderUnprojection() { } /** * get the script builder parameters. */ void CommandSurfaceBorderUnprojection::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Input Border Projection File", FileFilters::getBorderProjectionFileFilter()); paramsOut.addFile("Output Border File", FileFilters::getBorderGenericFileFilter()); } /** * get full help information. */ QString CommandSurfaceBorderUnprojection::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Unproject the borders using the specified surface.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceBorderUnprojection::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString coordinateFileName = parameters->getNextParameterAsString("Coordinate File Name"); const QString topologyFileName = parameters->getNextParameterAsString("Topology File Name"); const QString borderProjectionFileName = parameters->getNextParameterAsString("Border Projection File Name"); const QString borderFileName = parameters->getNextParameterAsString("Border File Name"); checkForExcessiveParameters(); // // Create a brain set // BrainSet brainSet(topologyFileName, coordinateFileName, "", true); const BrainModelSurface* bms = brainSet.getBrainModelSurface(0); if (bms == NULL) { throw CommandException("unable to find surface."); } const TopologyFile* tf = bms->getTopologyFile(); if (tf == NULL) { throw CommandException("unable to find topology."); } const int numNodes = bms->getNumberOfNodes(); if (numNodes == 0) { throw CommandException("surface contains not nodes."); } // // Read the border projection file // BorderProjectionFile borderProjectionFile; borderProjectionFile.readFile(borderProjectionFileName); // // Project the border file // BorderFile borderFile; BorderProjectionUnprojector unprojector; unprojector.unprojectBorderProjections(*(bms->getCoordinateFile()), borderProjectionFile, borderFile); // // Write the border projection file // borderFile.writeFile(borderFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderToPaint.h0000664000175000017500000000344211572067322027320 0ustar michaelmichael#ifndef __COMMAND_SURFACE_BORDER_TO_PAINT_H__ #define __COMMAND_SURFACE_BORDER_TO_PAINT_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for converting borders to paint class CommandSurfaceBorderToPaint : public CommandBase { public: // constructor CommandSurfaceBorderToPaint(); // destructor ~CommandSurfaceBorderToPaint(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_BORDER_TO_PAINT_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderToPaint.cxx0000664000175000017500000001202111572067322027664 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BorderProjectionFile.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceBorderToPaintConverter.h" #include "BrainSet.h" #include "CommandSurfaceBorderToPaint.h" #include "FileFilters.h" #include "FileUtilities.h" #include "PaintFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandSurfaceBorderToPaint::CommandSurfaceBorderToPaint() : CommandBase("-surface-border-to-paint", "SURFACE BORDER CONVERT TO PAINT") { } /** * destructor. */ CommandSurfaceBorderToPaint::~CommandSurfaceBorderToPaint() { } /** * get the script builder parameters. */ void CommandSurfaceBorderToPaint::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Coordinates File", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Input Topology File", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Input Border Projection File", FileFilters::getBorderProjectionFileFilter()); paramsOut.addFile("Output Paint File", FileFilters::getPaintFileFilter()); } /** * get full help information. */ QString CommandSurfaceBorderToPaint::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Convert the border projection file to a paint file\n" + indent9 + "by assigning the border's name to the node's paint \n" + indent9 + "name.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceBorderToPaint::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the inputs // const QString coordinateFileName = parameters->getNextParameterAsString("Coordinate File"); const QString topologyFileName = parameters->getNextParameterAsString("Topology File"); const QString borderProjectionFileName = parameters->getNextParameterAsString("Border Projection File"); const QString paintFileName = parameters->getNextParameterAsString("Paint File"); // // Create a spec file to read in the data files // SpecFile sf; sf.addToSpecFile(SpecFile::getUnknownCoordFileMatchTag(), coordinateFileName, "", false); sf.addToSpecFile(SpecFile::getUnknownTopoFileMatchTag(), topologyFileName, "", false); sf.addToSpecFile(SpecFile::getBorderProjectionFileTag(), borderProjectionFileName, "", false); // // Read the files // QString errorMessage; BrainSet brainSet; brainSet.readSpecFile(sf, "", errorMessage); if (errorMessage.isEmpty() == false) { throw new CommandException(errorMessage); } BrainModelSurface* surface = brainSet.getBrainModelSurface(0); if (surface == NULL) { throw CommandException("Surface is invalid."); } // // Get the border projections // BorderProjectionFile borderProjectionFile; BrainModelBorderSet* bmbs = brainSet.getBorderSet(); bmbs->copyBordersToBorderProjectionFile(borderProjectionFile); // // Convert the borders to paint // PaintFile mf; BrainModelSurfaceBorderToPaintConverter converter(&brainSet, surface, &borderProjectionFile, &mf, 0, FileUtilities::basename(borderProjectionFileName)); converter.execute(); // // Write the paint file // mf.writeFile(paintFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderToMetric.h0000664000175000017500000000341511572067322027470 0ustar michaelmichael #ifndef __COMMAND_SURFACE_BORDER_TO_METRIC_H__ #define __COMMAND_SURFACE_BORDER_TO_METRIC_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandSurfaceBorderToMetric : public CommandBase { public: // constructor CommandSurfaceBorderToMetric(); // destructor ~CommandSurfaceBorderToMetric(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_BORDER_TO_METRIC_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderToMetric.cxx0000664000175000017500000001220111572067322030034 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BorderProjectionFile.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceBorderToMetricConverter.h" #include "BrainSet.h" #include "CommandSurfaceBorderToMetric.h" #include "FileFilters.h" #include "FileUtilities.h" #include "MetricFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandSurfaceBorderToMetric::CommandSurfaceBorderToMetric() : CommandBase("-surface-border-to-metric", "SURFACE BORDER CONVERT TO METRIC") { } /** * destructor. */ CommandSurfaceBorderToMetric::~CommandSurfaceBorderToMetric() { } /** * get the script builder parameters. */ void CommandSurfaceBorderToMetric::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Coordinates File", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Input Topology File", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Input Border Projection File", FileFilters::getBorderProjectionFileFilter()); paramsOut.addFile("Output Metric File", FileFilters::getMetricFileFilter()); } /** * get full help information. */ QString CommandSurfaceBorderToMetric::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Convert the border projection file to a metric file\n" + indent9 + "by assigning the border's variance to the surface \n" + indent9 + "nodes based upon the triangle which the border point\n" + indent9 + "falls within.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceBorderToMetric::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the inputs // const QString coordinateFileName = parameters->getNextParameterAsString("Coordinate File"); const QString topologyFileName = parameters->getNextParameterAsString("Topology File"); const QString borderProjectionFileName = parameters->getNextParameterAsString("Border Projection File"); const QString metricFileName = parameters->getNextParameterAsString("Metric File"); // // Create a spec file to read in the data files // SpecFile sf; sf.addToSpecFile(SpecFile::getUnknownCoordFileMatchTag(), coordinateFileName, "", false); sf.addToSpecFile(SpecFile::getUnknownTopoFileMatchTag(), topologyFileName, "", false); sf.addToSpecFile(SpecFile::getBorderProjectionFileTag(), borderProjectionFileName, "", false); // // Read the files // QString errorMessage; BrainSet brainSet; brainSet.readSpecFile(sf, "", errorMessage); if (errorMessage.isEmpty() == false) { throw new CommandException(errorMessage); } BrainModelSurface* surface = brainSet.getBrainModelSurface(0); if (surface == NULL) { throw CommandException("Surface is invalid."); } // // Get the border projections // BorderProjectionFile borderProjectionFile; BrainModelBorderSet* bmbs = brainSet.getBorderSet(); bmbs->copyBordersToBorderProjectionFile(borderProjectionFile); // // Convert the borders to metric // MetricFile mf; BrainModelSurfaceBorderToMetricConverter converter(&brainSet, surface, &borderProjectionFile, &mf, 0, FileUtilities::basename(borderProjectionFileName)); converter.execute(); // // Write the metric file // mf.writeFile(metricFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderSetVariability.h0000664000175000017500000000354511572067322030701 0ustar michaelmichael #ifndef __COMMAND_SURFACE_BORDER_SET_VARIABILITY_H__ #define __COMMAND_SURFACE_BORDER_SET_VARIABILITY_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for border variability setting class CommandSurfaceBorderSetVariability : public CommandBase { public: // constructor CommandSurfaceBorderSetVariability(); // destructor ~CommandSurfaceBorderSetVariability(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_BORDER_SET_VARIABILITY_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderSetVariability.cxx0000664000175000017500000000703211572067322031247 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BorderFile.h" #include "BrainSet.h" #include "CommandSurfaceBorderSetVariability.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandSurfaceBorderSetVariability::CommandSurfaceBorderSetVariability() : CommandBase("-surface-border-set-variability", "SURFACE BORDER SET VARIABILITY") { } /** * destructor. */ CommandSurfaceBorderSetVariability::~CommandSurfaceBorderSetVariability() { } /** * get the script builder parameters. */ void CommandSurfaceBorderSetVariability::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.addFile("Input Border File", FileFilters::getBorderGenericFileFilter()); paramsOut.addFile("Output Border File", FileFilters::getBorderGenericFileFilter()); paramsOut.addFloat("New Variability", 1.0, 0.0, 100000.0); } /** * get full help information. */ QString CommandSurfaceBorderSetVariability::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Set the variability for all borders in a file..\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceBorderSetVariability::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputBorderFileName = parameters->getNextParameterAsString("Input Border File Name"); const QString outputBorderFileName = parameters->getNextParameterAsString("Output Border File Name"); const float variability = parameters->getNextParameterAsFloat("Variability"); checkForExcessiveParameters(); // // Read input file // BorderFile borderFile; borderFile.readFile(inputBorderFileName); // // Loop through the borders // const int num = borderFile.getNumberOfBorders(); for (int i = 0; i < num; i++) { // // Get the border projection // Border* bp = borderFile.getBorder(i); bp->setArealUncertainty(variability); } // // Write output border file // borderFile.writeFile(outputBorderFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderReverse.h0000664000175000017500000000345711572067322027363 0ustar michaelmichael #ifndef __COMMAND_SURFACE_BORDER_REVERSE_H__ #define __COMMAND_SURFACE_BORDER_REVERSE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for border resampling class CommandSurfaceBorderReverse : public CommandBase { public: // constructor CommandSurfaceBorderReverse(); // destructor ~CommandSurfaceBorderReverse(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_BORDER_REVERSE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderReverse.cxx0000664000175000017500000001315411572067322027731 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BorderFile.h" #include "BorderFileProjector.h" #include "BorderProjectionFile.h" #include "BorderProjectionUnprojector.h" #include "BrainModelSurface.h" #include "BrainSet.h" #include "CommandSurfaceBorderReverse.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandSurfaceBorderReverse::CommandSurfaceBorderReverse() : CommandBase("-surface-border-reverse", "SURFACE BORDER REVERSE") { } /** * destructor. */ CommandSurfaceBorderReverse::~CommandSurfaceBorderReverse() { } /** * get the script builder parameters. */ void CommandSurfaceBorderReverse::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Border Projection File", FileFilters::getBorderProjectionFileFilter()); paramsOut.addFile("Output Border Projection File", FileFilters::getBorderProjectionFileFilter()); paramsOut.addVariableListOfParameters("Border Reverse Options"); } /** * get full help information. */ QString CommandSurfaceBorderReverse::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-all]\n" + indent9 + "[-border-name border-name]\n" + indent9 + "\n" + indent9 + "Reverse the order of links in borders.\n" + indent9 + "\n" + indent9 + "Either \"-all\", which reverses all borders in the file, or\n" + indent9 + "\"-border-name\", which reverses borders with specific names\n" + indent9 + "MUST be specified. \"-border-name\" may be used multiple\n" + indent9 + "times to reverse additional borders.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceBorderReverse::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputBorderProjectionFileName = parameters->getNextParameterAsString("Input Border Projection File Name"); const QString outputBorderProjectionFileName = parameters->getNextParameterAsString("Output Border Projection File Name"); // // Check optional parameters // bool reverseAllFlag = false; std::vector borderNames; while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("parameter"); if (paramName == "-all") { reverseAllFlag = true;; } else if (paramName == "-border-name") { const QString nameString = parameters->getNextParameterAsString("border name"); borderNames.push_back(nameString); } else { throw CommandException("unknown parameter: " + paramName); } } const int numberOfBorderNames = static_cast(borderNames.size()); if ((reverseAllFlag == false) && (numberOfBorderNames <= 0)) { throw CommandException("either \"-all\" or " "\"-border-name\" must be specified to indicate " "which borders should be reversed."); } // // Read the border projection file // BorderProjectionFile borderProjectionFile; borderProjectionFile.readFile(inputBorderProjectionFileName); // // Loop through the border projections // const int num = borderProjectionFile.getNumberOfBorderProjections(); for (int i = 0; i < num; i++) { // // Get the border projection // BorderProjection* bp = borderProjectionFile.getBorderProjection(i); // // Determine if the border projection should be reversed // bool reverseIt = false; if (reverseAllFlag) { reverseIt = true; } else { if (std::find(borderNames.begin(), borderNames.end(), bp->getName()) != borderNames.end()) { reverseIt = true; } } // // Should border projection be reversed // if (reverseIt) { // // Reverse border projection // bp->reverseOrderOfBorderProjectionLinks(); } } // // Write output border projection file // borderProjectionFile.writeFile(outputBorderProjectionFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderResample.h0000664000175000017500000000346511572067322027517 0ustar michaelmichael #ifndef __COMMAND_SURFACE_BORDER_RESAMPLE_H__ #define __COMMAND_SURFACE_BORDER_RESAMPLE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for border resampling class CommandSurfaceBorderResample : public CommandBase { public: // constructor CommandSurfaceBorderResample(); // destructor ~CommandSurfaceBorderResample(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_BORDER_RESAMPLE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderResample.cxx0000664000175000017500000002153211572067322030065 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BorderFile.h" #include "BorderFileProjector.h" #include "BorderProjectionFile.h" #include "BorderProjectionUnprojector.h" #include "BrainModelSurface.h" #include "BrainSet.h" #include "CommandSurfaceBorderResample.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandSurfaceBorderResample::CommandSurfaceBorderResample() : CommandBase("-surface-border-resample", "SURFACE BORDER RESAMPLE") { } /** * destructor. */ CommandSurfaceBorderResample::~CommandSurfaceBorderResample() { } /** * get the script builder parameters. */ void CommandSurfaceBorderResample::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Input Border Projection File", FileFilters::getBorderProjectionFileFilter()); paramsOut.addFile("Output Border Projection File", FileFilters::getBorderProjectionFileFilter()); paramsOut.addFloat("Sampling Interval", 1.0, 0.000, 100000.0); paramsOut.addVariableListOfParameters("Border Resample Options"); } /** * get full help information. */ QString CommandSurfaceBorderResample::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-all]\n" + indent9 + "[-border-name border-name]\n" + indent9 + "\n" + indent9 + "Resample borders.\n" + indent9 + "\n" + indent9 + "Either \"-all\", which resample all borders in the file, or\n" + indent9 + "\"-border-name\", which resamples borders with specific names\n" + indent9 + "MUST be specified. \"-border-name\" may be used multiple\n" + indent9 + "times to resample additional borders.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceBorderResample::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString coordinateFileName = parameters->getNextParameterAsString("Coordinate File Name"); const QString topologyFileName = parameters->getNextParameterAsString("Topology File Name"); const QString inputBorderProjectionFileName = parameters->getNextParameterAsString("Input Border Projection File Name"); const QString outputBorderProjectionFileName = parameters->getNextParameterAsString("Output Border Projection File Name"); const float resamplingInterval = parameters->getNextParameterAsFloat("Resampling Interval"); // // Create a brain set // BrainSet brainSet(topologyFileName, coordinateFileName, "", true); BrainModelSurface* bms = brainSet.getBrainModelSurface(0); if (bms == NULL) { throw CommandException("unable to find surface."); } const CoordinateFile* cf = bms->getCoordinateFile(); const TopologyFile* tf = bms->getTopologyFile(); if (tf == NULL) { throw CommandException("unable to find topology."); } const int numNodes = bms->getNumberOfNodes(); if (numNodes == 0) { throw CommandException("surface contains not nodes."); } // // Check optional parameters // bool resampleAllFlag = false; std::vector borderNames; QString roiFileName; while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("parameter"); if (paramName == "-all") { resampleAllFlag = true;; } else if (paramName == "-border-name") { const QString nameString = parameters->getNextParameterAsString("border name"); borderNames.push_back(nameString); } else { throw CommandException("unknown parameter: " + paramName); } } const int numberOfBorderNames = static_cast(borderNames.size()); if ((resampleAllFlag == false) && (numberOfBorderNames <= 0)) { throw CommandException("either \"-all\" or " "\"-border-name\" must be specified to indicate " "which borders should be resampled."); } // // Read input file // BorderProjectionFile inputBorderProjectionFile; inputBorderProjectionFile.readFile(inputBorderProjectionFileName); BorderProjectionFile outputBorderProjectionFile; outputBorderProjectionFile.setHeader(inputBorderProjectionFile.getHeader()); // // Loop through the border projections // const int num = inputBorderProjectionFile.getNumberOfBorderProjections(); for (int i = 0; i < num; i++) { // // Get the border projection // BorderProjection* bp = inputBorderProjectionFile.getBorderProjection(i); // // Determine if the border projection should be resampled // bool resampleIt = false; if (resampleAllFlag) { resampleIt = true; } else { if (std::find(borderNames.begin(), borderNames.end(), bp->getName()) != borderNames.end()) { resampleIt = true; } } // // Should border projection be resampled // if (resampleIt) { // // Place the border projection in a temporary file // BorderProjectionFile tempBorderProjectionFile; tempBorderProjectionFile.addBorderProjection(*bp); // // Unproject the border // BorderProjectionUnprojector unprojector; BorderFile tempBorderFile; unprojector.unprojectBorderProjections(*cf, tempBorderProjectionFile, tempBorderFile); // // Get border // if (tempBorderFile.getNumberOfBorders() <= 0) { throw CommandException("unprojection error."); } // // Resample the border // Border* b = tempBorderFile.getBorder(0); int newNumLinks = 0; b->resampleBorderToDensity(resamplingInterval, 2, newNumLinks); // // Reproject the border // tempBorderProjectionFile.clear(); BorderFileProjector projector(bms, true); projector.projectBorderFile(&tempBorderFile, &tempBorderProjectionFile, NULL); // // Add border projection to output file // if (tempBorderProjectionFile.getNumberOfBorderProjections() <= 0) { throw CommandException("reprojection error."); } outputBorderProjectionFile.addBorderProjection( *tempBorderProjectionFile.getBorderProjection(0)); } else { // // Add border projection to output file // outputBorderProjectionFile.addBorderProjection(*bp); } } // // Write output border projection file // outputBorderProjectionFile.writeFile(outputBorderProjectionFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderProjection.h0000664000175000017500000000351111572067322030053 0ustar michaelmichael #ifndef __COMMAND_SURFACE_BORDER_PROJECTION_H__ #define __COMMAND_SURFACE_BORDER_PROJECTION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for surface border projection class CommandSurfaceBorderProjection : public CommandBase { public: // constructor CommandSurfaceBorderProjection(); // destructor ~CommandSurfaceBorderProjection(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_BORDER_PROJECTION_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderProjection.cxx0000664000175000017500000001074111572067322030431 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BorderFile.h" #include "BorderFileProjector.h" #include "BorderProjectionFile.h" #include "BrainModelSurface.h" #include "BrainSet.h" #include "CommandSurfaceBorderProjection.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandSurfaceBorderProjection::CommandSurfaceBorderProjection() : CommandBase("-surface-border-projection", "SURFACE BORDER PROJECTION") { } /** * destructor. */ CommandSurfaceBorderProjection::~CommandSurfaceBorderProjection() { } /** * get the script builder parameters. */ void CommandSurfaceBorderProjection::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Input Border File", FileFilters::getBorderGenericFileFilter()); paramsOut.addFile("Output Border Projection File", FileFilters::getBorderProjectionFileFilter()); } /** * get full help information. */ QString CommandSurfaceBorderProjection::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Project the borders using the specified surface.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceBorderProjection::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString coordinateFileName = parameters->getNextParameterAsString("Coordinate File Name"); const QString topologyFileName = parameters->getNextParameterAsString("Topology File Name"); const QString borderFileName = parameters->getNextParameterAsString("Border File Name"); const QString borderProjectionFileName = parameters->getNextParameterAsString("Border Projection File Name"); checkForExcessiveParameters(); // // Create a brain set // BrainSet brainSet(topologyFileName, coordinateFileName, "", true); const BrainModelSurface* bms = brainSet.getBrainModelSurface(0); if (bms == NULL) { throw CommandException("unable to find surface."); } const TopologyFile* tf = bms->getTopologyFile(); if (tf == NULL) { throw CommandException("unable to find topology."); } const int numNodes = bms->getNumberOfNodes(); if (numNodes == 0) { throw CommandException("surface contains not nodes."); } // // Read the border file // BorderFile borderFile; borderFile.readFile(borderFileName); // // Project the border file // BorderProjectionFile borderProjectionFile; BorderFileProjector projector(bms, true); projector.projectBorderFile(&borderFile, &borderProjectionFile, NULL); // // Write the border projection file // borderProjectionFile.writeFile(borderProjectionFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderNibbler.h0000664000175000017500000000351211572067322027315 0ustar michaelmichael #ifndef __COMMAND_SURFACE_BORDER_NIBBLER_H__ #define __COMMAND_SURFACE_BORDER_NIBBLER_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for nibbling (removing parts) of surface borders class CommandSurfaceBorderNibbler : public CommandBase { public: // constructor CommandSurfaceBorderNibbler(); // destructor ~CommandSurfaceBorderNibbler(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_BORDER_NIBBLER_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderNibbler.cxx0000664000175000017500000003451111572067322027673 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BorderProjectionFile.h" #include "BrainModelSurface.h" #include "BrainSet.h" #include "CommandSurfaceBorderNibbler.h" #include "FileFilters.h" #include "FociProjectionFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandSurfaceBorderNibbler::CommandSurfaceBorderNibbler() : CommandBase("-surface-border-nibbler", "SURFACE BORDER NIBBLER") { } /** * destructor. */ CommandSurfaceBorderNibbler::~CommandSurfaceBorderNibbler() { } /** * get the script builder parameters. */ void CommandSurfaceBorderNibbler::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Input Border Projection File", FileFilters::getBorderProjectionFileFilter()); paramsOut.addFile("Output Border Projection File", FileFilters::getBorderProjectionFileFilter()); paramsOut.addString("Border Name"); paramsOut.addFile("Foci Projection File Name", FileFilters::getFociProjectionFileFilter()); paramsOut.addString("Focus Name"); paramsOut.addVariableListOfParameters("Border Nibble Options"); } /** * get full help information. */ QString CommandSurfaceBorderNibbler::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "output-border-name>\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-greater-than-x x-offset] \n" + indent9 + "[-greater-than-y y-offset] \n" + indent9 + "[-greater-than-z z-offset] \n" + indent9 + "[-less-than-x x-offset] \n" + indent9 + "[-less-than-y y-offset] \n" + indent9 + "[-less-than-z z-offset] \n" + indent9 + "[-remove-after] \n" + indent9 + "[-remove-before] \n" + indent9 + "[-within-x-distance x-distance]\n" + indent9 + "[-within-y-distance y-distance]\n" + indent9 + "[-within-z-distance z-distance]\n" + indent9 + "[-within-linear-distance linear-distance]\n" + indent9 + "\n" + indent9 + "When specifying a \"within\" distance, any borders points\n" + indent9 + "whose distance is LESS THAN a \"linear distance\" from the\n" + indent9 + "focus are removed.\n" + indent9 + "\n" + indent9 + "\"-greater-than-X/Y/Z\" removes border points whose X/Y/Z-coordinate\n" + indent9 + "is greater than the sum of X/Y/Z-coordinate of the focus plus the \n" + indent9 + "\"x/y/z-offset\". \n" + indent9 + "\n" + indent9 + "\"-less-than-X/Y/Z\" removes border points whose X/Y/Z-coordinate\n" + indent9 + "is less than the sum of X/Y/Z-coordinate of the focus plus the \n" + indent9 + "\"x/y/z-offset\". \n" + indent9 + "\n" + indent9 + "\"-remove-after\" removes all links from the border starting\n" + indent9 + "at the link closest to the focus to the end of the border.\n" + indent9 + "\n" + indent9 + "\"-remove-before\" removes all links from the start of the border\n" + indent9 + "to the border link closest to the focus.\n" + indent9 + "\n" + indent9 + "If the input and output border names are different, a new \n" + indent9 + "border is created. \n" + indent9 + "\n" + indent9 + "Uses the last focus with \"focus-name\".\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceBorderNibbler::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputCoordinateFileName = parameters->getNextParameterAsString("Input Coordinate File Name"); const QString inputTopologyFileName = parameters->getNextParameterAsString("Input Topology File Name"); const QString inputBorderProjectionFileName = parameters->getNextParameterAsString("Input Border Projection File Name"); const QString outputBorderProjectionFileName = parameters->getNextParameterAsString("Output Border Projection File Name"); const QString inputBorderName = parameters->getNextParameterAsString("Input Border Name"); const QString outputBorderName = parameters->getNextParameterAsString("Output Border Name"); const QString inputFociProjectionFileName = parameters->getNextParameterAsString("Input Foci Projection File Name"); const QString inputFocusName = parameters->getNextParameterAsString("Input Focus Name"); bool lessGreaterThanFlag = false; float greaterThanOffset[3] = { 0.0, 0.0, 0.0 }; bool greaterThanOffsetValid[3] = { false, false, false }; float lessThanOffset[3] = { 0.0, 0.0, 0.0 }; bool lessThanOffsetValid[3] = { false, false, false }; float withinXDistance = -1.0; float withinYDistance = -1.0; float withinZDistance = -1.0; float withinLinearDistance = -1.0; bool withinDistanceFlag = false; bool removeAfterFlag = false; bool removeBeforeFlag = false; while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("Distance Parameter"); if (paramName == "-greater-than-x") { greaterThanOffset[0] = parameters->getNextParameterAsFloat("Greater Than X-Offset"); greaterThanOffsetValid[0] = true; lessGreaterThanFlag = true; } else if (paramName == "-greater-than-y") { greaterThanOffset[1] = parameters->getNextParameterAsFloat("Greater Than Y-Offset"); greaterThanOffsetValid[1] = true; lessGreaterThanFlag = true; } else if (paramName == "-greater-than-z") { greaterThanOffset[2] = parameters->getNextParameterAsFloat("Greater Than Z-Offset"); greaterThanOffsetValid[2] = true; lessGreaterThanFlag = true; } else if (paramName == "-less-than-x") { lessThanOffset[0] = parameters->getNextParameterAsFloat("Less Than X-Offset"); lessThanOffsetValid[0] = true; lessGreaterThanFlag = true; } else if (paramName == "-less-than-y") { lessThanOffset[1] = parameters->getNextParameterAsFloat("Less Than Y-Offset"); lessThanOffsetValid[1] = true; lessGreaterThanFlag = true; } else if (paramName == "-less-than-z") { lessThanOffset[2] = parameters->getNextParameterAsFloat("Less Than Z-Offset"); lessThanOffsetValid[2] = true; lessGreaterThanFlag = true; } else if (paramName == "-remove-after") { removeAfterFlag = true; } else if (paramName == "-remove-before") { removeBeforeFlag = true; } else if (paramName == "-within-x-distance") { withinXDistance = parameters->getNextParameterAsFloat("Within-X-Distance"); if (withinXDistance < 0.0) { throw CommandException("Within X Distance must be greater than or equal to zero."); } withinDistanceFlag = true; } else if (paramName == "-within-y-distance") { withinYDistance = parameters->getNextParameterAsFloat("Within-Y-Distance"); if (withinYDistance < 0.0) { throw CommandException("Within Y Distance must be greater than or equal to zero."); } withinDistanceFlag = true; } else if (paramName == "-within-z-distance") { withinZDistance = parameters->getNextParameterAsFloat("Within-Z-Distance"); if (withinZDistance < 0.0) { throw CommandException("Within Z Distance must be greater than or equal to zero."); } withinDistanceFlag = true; } else if (paramName == "-within-linear-distance") { withinLinearDistance = parameters->getNextParameterAsFloat("Within-Linear-Distance"); if (withinLinearDistance < 0.0) { throw CommandException("Within Linear Distance must be greater than or equal to zero."); } withinDistanceFlag = true; } else { throw CommandException("Unrecognized distance: " + paramName); } } // // Create a brain set // BrainSet brainSet(inputTopologyFileName, inputCoordinateFileName, "", true); BrainModelSurface* bms = brainSet.getBrainModelSurface(0); if (bms == NULL) { throw CommandException("unable to find surface."); } const TopologyFile* tf = bms->getTopologyFile(); if (tf == NULL) { throw CommandException("unable to find topology."); } const int numNodes = bms->getNumberOfNodes(); if (numNodes == 0) { throw CommandException("surface contains no nodes."); } // // Read the border projection file // BorderProjectionFile borderProjectionFile; borderProjectionFile.readFile(inputBorderProjectionFileName); // // Read the foci projection file // FociProjectionFile inputFociProjectionFile; inputFociProjectionFile.readFile(inputFociProjectionFileName); // // Get the focus with the specified name // const CellProjection* inputFocus = inputFociProjectionFile.getLastCellProjectionWithName(inputFocusName); if (inputFocus == NULL) { throw CommandException("Cannot find focus " "with name " + inputFocusName); } // // Get position of input focus // const bool fiducialSurfaceFlag = (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FIDUCIAL); const bool flatSurfaceFlag = ((bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FLAT) || (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR)); float inputFocusXYZ[3]; if (inputFocus->getProjectedPosition(bms->getCoordinateFile(), bms->getTopologyFile(), fiducialSurfaceFlag, flatSurfaceFlag, false, inputFocusXYZ) == false) { throw CommandException("unable to get projected position for " + inputFocusName); } // // Get the border with the specified name // BorderProjection* bp = borderProjectionFile.getLastBorderProjectionByName(inputBorderName); if (bp == NULL) { throw CommandException("Unable to find border named \"" + inputBorderName + "\""); } // // If the input and output border names are different, create a new border // if (inputBorderName != outputBorderName) { borderProjectionFile.addBorderProjection(*bp); bp = borderProjectionFile.getBorderProjection(borderProjectionFile.getNumberOfBorderProjections() - 1); bp->setName(outputBorderName); } // // nibble the border projection // if (withinDistanceFlag) { bp->removeLinksNearPoint(bms->getCoordinateFile(), inputFocusXYZ, withinXDistance, withinYDistance, withinZDistance, withinLinearDistance); } // // Do nibbling of border points outside extent // if (lessGreaterThanFlag) { float extent[6] = { -std::numeric_limits::max(), std::numeric_limits::max(), -std::numeric_limits::max(), std::numeric_limits::max(), -std::numeric_limits::max(), std::numeric_limits::max() }; if (greaterThanOffsetValid[0]) { extent[1] = inputFocusXYZ[0] + greaterThanOffset[0]; } if (greaterThanOffsetValid[1]) { extent[3] = inputFocusXYZ[1] + greaterThanOffset[1]; } if (greaterThanOffsetValid[2]) { extent[5] = inputFocusXYZ[2] + greaterThanOffset[2]; } if (lessThanOffsetValid[0]) { extent[0] = inputFocusXYZ[0] + lessThanOffset[0]; } if (lessThanOffsetValid[1]) { extent[2] = inputFocusXYZ[1] + lessThanOffset[1]; } if (lessThanOffsetValid[0]) { extent[4] = inputFocusXYZ[2] + lessThanOffset[2]; } bp->removeLinksOutsideExtent(bms->getCoordinateFile(), extent); } // // Remove before and after // if (removeAfterFlag || removeBeforeFlag) { bp->removeLinksBeforeAfterLinkNearestPoint(bms->getCoordinateFile(), inputFocusXYZ, removeAfterFlag, removeBeforeFlag); } // // Write the border projection file // borderProjectionFile.writeFile(outputBorderProjectionFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderMerge.h0000664000175000017500000000430411572067322026777 0ustar michaelmichael #ifndef __COMMAND_SURFACE_BORDER_MERGE_H__ #define __COMMAND_SURFACE_BORDER_MERGE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" class BorderProjection; class BorderProjectionFile; /// class for merging borders class CommandSurfaceBorderMerge : public CommandBase { public: // constructor CommandSurfaceBorderMerge(); // destructor ~CommandSurfaceBorderMerge(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); // get border projection by name and make sure only one const BorderProjection* getBorderProjectionWithUniqueName(const BorderProjectionFile& bpf, const QString& name) const throw (CommandException); }; #endif // __COMMAND_SURFACE_BORDER_MERGE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderMerge.cxx0000664000175000017500000003364411572067322027363 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BorderFile.h" #include "BorderFileProjector.h" #include "BorderProjectionFile.h" #include "BorderProjectionUnprojector.h" #include "BrainModelSurface.h" #include "BrainSet.h" #include "CommandSurfaceBorderMerge.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandSurfaceBorderMerge::CommandSurfaceBorderMerge() : CommandBase("-surface-border-merge", "SURFACE BORDER MERGE") { } /** * destructor. */ CommandSurfaceBorderMerge::~CommandSurfaceBorderMerge() { } /** * get the script builder parameters. */ void CommandSurfaceBorderMerge::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Border Projection File", FileFilters::getBorderProjectionFileFilter()); paramsOut.addFile("Output Border Projection File", FileFilters::getBorderProjectionFileFilter()); paramsOut.addString("Output Border Projection Name"); paramsOut.addString("Input Border Projection 1 Name"); paramsOut.addString("Input Border Projection 2 Name"); paramsOut.addVariableListOfParameters("Options"); } /** * get full help information. */ QString CommandSurfaceBorderMerge::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-border-proj additional-input-border-projection-name]\n" + indent9 + "[-delete-input-border-projections]\n" + indent9 + "[-close-border]\n" + indent9 + "[-smooth-junctions \n" + indent9 + " coordinate-file-name \n" + indent9 + " topology-file-name \n" + indent9 + " junction-neighbors \n" + indent9 + " number-of-iterations] \n" + indent9 + "\n" + indent9 + "Merge two or more border projections into a single\n" + indent9 + "border projection. An option is provided that will\n" + indent9 + "delete all of the input border projections. Use\n" + indent9 + "\"-border-proj\" if more than two border projections\n" + indent9 + "need to be merged.\n" + indent9 + "\n" + indent9 + "Use \"-close-border\" if the borders are to be merged into\n" + indent9 + "a closed border.\n" + indent9 + "\n" + indent9 + "Use \"-smooth-junctions\" to smooth the border links \n" + indent9 + "around the junctions (the border links that are \n" + indent9 + "connected to form the output border). \n" + indent9 + "\"junction-neighbors\" is the number of links on both \n" + indent9 + "sides of the junction that get smoothed for \n" + indent9 + "\"number-of-iterations\". \n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceBorderMerge::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get required parameters // const QString inputBorderProjectionFileName = parameters->getNextParameterAsString("Input Border Projection File"); const QString outputBorderProjectionFileName = parameters->getNextParameterAsString("Output Border Projection File"); const QString outputBorderProjectionName = parameters->getNextParameterAsString("Output Border Projection Name"); std::vector inputBorderProjectionNames; inputBorderProjectionNames.push_back( parameters->getNextParameterAsString("Input Border Projection 1 Name")); inputBorderProjectionNames.push_back( parameters->getNextParameterAsString("Input Border Projection 2 Name")); // // Process optional parameters // bool smoothFlag = false; QString smoothCoordFileName; QString smoothTopoFileName; int smoothJunctionNeighborsCount = 0; int smoothJunctionIterations = 0; bool closeBorderFlag = false; bool deleteInputBorderProjectionsFlag = false; while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("Merge Border Parameter"); if (paramName == "-border-proj") { inputBorderProjectionNames.push_back( parameters->getNextParameterAsString("Additional Border Projection Names")); } else if (paramName == "-close-border") { closeBorderFlag = true; } else if (paramName == "-delete-input-border-projections") { deleteInputBorderProjectionsFlag = true; } else if (paramName == "-smooth-junctions") { smoothCoordFileName = parameters->getNextParameterAsString("Coordinate File Name"); smoothTopoFileName = parameters->getNextParameterAsString("Topology File Name"); smoothJunctionNeighborsCount = parameters->getNextParameterAsInt("Junction Neighbors"); smoothJunctionIterations = parameters->getNextParameterAsInt("Smoothing Iterations"); smoothFlag = true; } else { throw CommandException("Border Merge unrecognized option: \"" + paramName + "\""); } } // // Read the border projection file // BorderProjectionFile borderProjectionFile; borderProjectionFile.readFile(inputBorderProjectionFileName); // // Create a new border projection // BorderProjection borderProjection(outputBorderProjectionName); // // Locations of junctions for smoothing // std::vector junctionLinks; // // loop through input border projections and append // std::vector borderProjectionsForDeletion; const int numInput = static_cast(inputBorderProjectionNames.size()); for (int i = 0; i < numInput; i++) { if (borderProjection.getNumberOfLinks() > 0) { junctionLinks.push_back(borderProjection.getNumberOfLinks() - 1); } const BorderProjection* bp = getBorderProjectionWithUniqueName(borderProjectionFile, inputBorderProjectionNames[i]); borderProjection.append(*bp); borderProjectionsForDeletion.push_back(borderProjectionFile.getBorderProjectionIndex(bp)); } // // Close the border? // if (closeBorderFlag) { const int numLinks = borderProjection.getNumberOfLinks(); if (numLinks > 1) { // // Add first link to the end of the border so it closes // junctionLinks.push_back(numLinks - 1); borderProjection.addBorderProjectionLink(*borderProjection.getBorderProjectionLink(0)); } } // // Should input border projections be deleted // if (deleteInputBorderProjectionsFlag) { borderProjectionFile.removeBordersWithIndices(borderProjectionsForDeletion); } // // Should smoothing be performed ? // if (smoothFlag && (borderProjection.getNumberOfLinks() > 2)) { // // Create a brain set // BrainSet brainSet(smoothTopoFileName, smoothCoordFileName, "", true); BrainModelSurface* bms = brainSet.getBrainModelSurface(0); if (bms == NULL) { throw CommandException("unable to find surface."); } const CoordinateFile* cf = bms->getCoordinateFile(); const TopologyFile* tf = bms->getTopologyFile(); if (tf == NULL) { throw CommandException("unable to find topology."); } const int numNodes = bms->getNumberOfNodes(); if (numNodes == 0) { throw CommandException("surface contains not nodes."); } // // Place the border projection in a temporary file // BorderProjectionFile tempBorderProjectionFile; tempBorderProjectionFile.addBorderProjection(borderProjection); // // Unproject the border // BorderProjectionUnprojector unprojector; BorderFile tempBorderFile; unprojector.unprojectBorderProjections(*cf, tempBorderProjectionFile, tempBorderFile); // // Get border // if (tempBorderFile.getNumberOfBorders() <= 0) { throw CommandException("unprojection error."); } // // Get links for smoothing // const int numLinks = borderProjection.getNumberOfLinks(); std::vector smoothFlags(numLinks, false); for (int m = 0; m < static_cast(junctionLinks.size()); m++) { const int junctionIndex = junctionLinks[m]; // // Smooth links before junction // int mStart = junctionIndex - smoothJunctionNeighborsCount; if (mStart < 0) { // // flag nodes at start of border // for (int n = 0; n <= junctionIndex; n++) { smoothFlags[n] = true; } if (closeBorderFlag) { // // wrap around beginning and flag nodes at end of border // const int remainingLinks = smoothJunctionNeighborsCount - junctionIndex; mStart = numLinks - remainingLinks; if (mStart < 0) { mStart = 0; } for (int n = mStart; n < numLinks; n++) { smoothFlags[n] = true; } } } else { for (int n = mStart; n <= junctionIndex; n++) { smoothFlags[n] = true; } } // // Smooth links after junction // int mEnd = junctionIndex + smoothJunctionNeighborsCount; if (mEnd >= numLinks) { // // Flag nodes at end of border // for (int n = junctionIndex; n <= numLinks; n++) { smoothFlags[n] = true; } if (closeBorderFlag) { // // wrap around beginning and flag nodes at start of border // const int remainingLinks = mEnd - numLinks; mEnd = remainingLinks; if (mEnd > numLinks) { mEnd = numLinks; } for (int n = 0; n < mEnd; n++) { smoothFlags[n] = true; } } } else { for (int n = junctionIndex; n < mEnd; n++) { smoothFlags[n] = true; } } } // // Smooth the border // Border* b = tempBorderFile.getBorder(0); b->smoothBorderLinks(smoothJunctionIterations, closeBorderFlag, &smoothFlags); // // Reproject the border // tempBorderProjectionFile.clear(); BorderFileProjector projector(bms, true); projector.projectBorderFile(&tempBorderFile, &tempBorderProjectionFile, NULL); // // Add border projection to output file // if (tempBorderProjectionFile.getNumberOfBorderProjections() <= 0) { throw CommandException("reprojection error."); } borderProjectionFile.addBorderProjection( *tempBorderProjectionFile.getBorderProjection(0)); } else { // // Add to border projection file // borderProjectionFile.addBorderProjection(borderProjection); } // // Write the border projection file // borderProjectionFile.writeFile(outputBorderProjectionFileName); } /** * get border projection by name and make sure only one. */ const BorderProjection* CommandSurfaceBorderMerge::getBorderProjectionWithUniqueName(const BorderProjectionFile& bpf, const QString& name) const throw (CommandException) { const BorderProjection* bpFirst = bpf.getFirstBorderProjectionByName(name); const BorderProjection* bpLast = bpf.getLastBorderProjectionByName(name); if (bpFirst == bpLast) { if (bpFirst != NULL) { return bpFirst; } else { throw CommandException("no border projection with " + name + " was found."); } } throw CommandException("there is more than one border projection named " + name); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderLinkToFocus.h0000664000175000017500000000353311572067322030143 0ustar michaelmichael #ifndef __COMMAND_SURFACE_BORDER_LINK_TO_FOCUS_H__ #define __COMMAND_SURFACE_BORDER_LINK_TO_FOCUS_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for converting border links to foci class CommandSurfaceBorderLinkToFocus : public CommandBase { public: // constructor CommandSurfaceBorderLinkToFocus(); // destructor ~CommandSurfaceBorderLinkToFocus(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_BORDER_LINK_TO_FOCUS_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderLinkToFocus.cxx0000664000175000017500000002025111572067322030512 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BorderFile.h" #include "BorderProjectionFile.h" #include "BorderProjectionUnprojector.h" #include "BrainModelSurface.h" #include "BrainSet.h" #include "CellFileProjector.h" #include "CommandSurfaceBorderLinkToFocus.h" #include "FileFilters.h" #include "FociFile.h" #include "FociProjectionFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandSurfaceBorderLinkToFocus::CommandSurfaceBorderLinkToFocus() : CommandBase("-surface-border-link-to-focus", "SURFACE BORDER LINK TO FOCUS") { } /** * destructor. */ CommandSurfaceBorderLinkToFocus::~CommandSurfaceBorderLinkToFocus() { } /** * get the script builder parameters. */ void CommandSurfaceBorderLinkToFocus::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Border Projection File Name", FileFilters::getBorderProjectionFileFilter()); paramsOut.addString("Border Name"); paramsOut.addFile("Input Foci Projection File Name", FileFilters::getFociProjectionFileFilter()); paramsOut.addFile("Output Foci Projection File Name", FileFilters::getFociProjectionFileFilter()); paramsOut.addVariableListOfParameters("Border Link to Focus Options"); } /** * get full help information. */ QString CommandSurfaceBorderLinkToFocus::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-first-link focus-name]\n" + indent9 + "[-last-link focus-name]\n" + indent9 + "\n" + indent9 + "Create foci at border link locations.\n" + indent9 + "\n" + indent9 + "Note: The input foci projection file need not exist.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceBorderLinkToFocus::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString coordinateFileName = parameters->getNextParameterAsString("Coordinate File Name"); const QString topologyFileName = parameters->getNextParameterAsString("Topology File Name"); const QString borderProjectionFileName = parameters->getNextParameterAsString("Border Projection File Name"); const QString borderName = parameters->getNextParameterAsString("Border Name"); const QString inputFociProjectionFileName = parameters->getNextParameterAsString("Input Foci Projection File Name"); const QString outputFociProjectionFileName = parameters->getNextParameterAsString("Output Foci Projection File Name"); // // Create a brain set // BrainSet brainSet(topologyFileName, coordinateFileName, "", true); BrainModelSurface* surface = brainSet.getBrainModelSurface(0); if (surface == NULL) { throw CommandException("unable to find surface."); } const TopologyFile* tf = surface->getTopologyFile(); if (tf == NULL) { throw CommandException("unable to find topology."); } const int numNodes = surface->getNumberOfNodes(); if (numNodes == 0) { throw CommandException("surface contains no nodes."); } // // Surface MUST be fiducial for projection to work in some cases // surface->setSurfaceType(BrainModelSurface::SURFACE_TYPE_FIDUCIAL); // // Read the border projection file // BorderProjectionFile borderProjectionFile; borderProjectionFile.readFile(borderProjectionFileName); // // Find the border projection and place it in a file by itself // so only this border is unprojected // const BorderProjection* bp = borderProjectionFile.getLastBorderProjectionByName(borderName); if (bp == NULL) { throw CommandException("Unable to find border named: " + borderName); } BorderProjectionFile tempBorderProjFile; tempBorderProjFile.addBorderProjection(*bp); // // Unproject the borders // BorderFile borderFile; BorderProjectionUnprojector borderUnprojector; borderUnprojector.unprojectBorderProjections(*(surface->getCoordinateFile()), tempBorderProjFile, borderFile); const Border* border = borderFile.getBorder(0); if (border == NULL) { throw CommandException("border unprojection failed."); } if (border->getNumberOfLinks() <= 0) { throw CommandException("Border named \"" + borderName + " has no links after unprojection."); } // // File for new foci // FociFile fociFile; // // Search optional parameters // while (parameters->getParametersAvailable()) { // // Get the next parameter and process it // const QString paramName = parameters->getNextParameterAsString("Border Link to Focus"); if (paramName == "-first-link") { const QString focusName = parameters->getNextParameterAsString("Focus Name"); const float* xyz = border->getLinkXYZ(0); // Create a new focus // CellData focus(focusName, xyz[0], xyz[1], xyz[2]); fociFile.addCell(focus); } else if (paramName == "-last-link") { const QString focusName = parameters->getNextParameterAsString("Focus Name"); const float* xyz = border->getLinkXYZ(border->getNumberOfLinks() - 1); // Create a new focus // CellData focus(focusName, xyz[0], xyz[1], xyz[2]); fociFile.addCell(focus); } else { throw CommandException("Unrecognized parameter: " + paramName); } } // // Project the foci // FociProjectionFile fociFileProjected; fociFileProjected.appendFiducialCellFile(fociFile); CellFileProjector cellProjector(surface); cellProjector.projectFile(&fociFileProjected, 0, CellFileProjector::PROJECTION_TYPE_ALL, 0.0, false, NULL); // // Read the input focus projection file // FociProjectionFile fociProjectionFile; if (inputFociProjectionFileName.isEmpty() == false) { if (QFile::exists(inputFociProjectionFileName)) { fociProjectionFile.readFile(inputFociProjectionFileName); } } // // Append new foci // fociProjectionFile.append(fociFileProjected); // // Write new foci file // fociProjectionFile.writeFile(outputFociProjectionFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderLengths.h0000664000175000017500000000375511572067322027355 0ustar michaelmichael #ifndef __COMMAND_SURFACE_BORDER_LENGTHS_H__ #define __COMMAND_SURFACE_BORDER_LENGTHS_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "CommandBase.h" /// class for getting information about border lengths class CommandSurfaceBorderLengths : public CommandBase { public: // constructor CommandSurfaceBorderLengths(); // destructor ~CommandSurfaceBorderLengths(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // info about borders class BorderLengths { public: QString name; std::vector lengths; }; // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_BORDER_LENGTHS_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderLengths.cxx0000664000175000017500000001200011572067322027707 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include "BorderFile.h" #include "CommandSurfaceBorderLengths.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "StatisticDataGroup.h" #include "StatisticDescriptiveStatistics.h" /** * constructor. */ CommandSurfaceBorderLengths::CommandSurfaceBorderLengths() : CommandBase("-surface-border-lengths", "SURFACE BORDER LENGTHS") { } /** * destructor. */ CommandSurfaceBorderLengths::~CommandSurfaceBorderLengths() { } /** * get the script builder parameters. */ void CommandSurfaceBorderLengths::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addMultipleFiles("Input Border Files", FileFilters::getBorderGenericFileFilter()); } /** * get full help information. */ QString CommandSurfaceBorderLengths::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "[additional-input-border-files]\n" + indent9 + "\n" + indent9 + "Get information about border lengths.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceBorderLengths::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get parameters // std::vector inputBorderFileNames; inputBorderFileNames.push_back( parameters->getNextParameterAsString("Input Border File Name 1")); while (parameters->getParametersAvailable()) { inputBorderFileNames.push_back( parameters->getNextParameterAsString("Input Border File Name")); } // // Border lengths // std::vector borderLengths; // // Read the input border files // const int numBorderFiles = static_cast(inputBorderFileNames.size()); for (int i = 0; i < numBorderFiles; i++) { BorderFile bf; bf.readFile(inputBorderFileNames[i]); std::cout << inputBorderFileNames[i].toAscii().constData() << "------------------" << std::endl; const int numBorders = bf.getNumberOfBorders(); for (int j = 0; j < numBorders; j++) { Border* b = bf.getBorder(j); const QString name = b->getName(); const float length = b->getBorderLength(); std::cout << " " << name.toAscii().constData() << ": " << length << std::endl; BorderLengths* bl = NULL; for (unsigned int i = 0; i < borderLengths.size(); i++) { if (borderLengths[i].name == name) { bl = &borderLengths[i]; } } if (bl == NULL) { BorderLengths blNew; blNew.name = name; borderLengths.push_back(blNew); bl = &borderLengths[borderLengths.size() - 1]; } bl->lengths.push_back(length); } } std::cout << "------------------------------------------------" << std::endl; for (std::vector::iterator iter = borderLengths.begin(); iter != borderLengths.end(); iter++) { QString name = iter->name; std::vector lengths = iter->lengths; StatisticDataGroup sda(&lengths, StatisticDataGroup::DATA_STORAGE_MODE_POINT); StatisticDescriptiveStatistics stats; stats.addDataGroup(&sda, false); stats.execute(); float minValue, maxValue; stats.getMinimumAndMaximum(minValue, maxValue); std::cout << name.toAscii().constData() << " avg=" << stats.getMean() << " dev=" << stats.getStandardDeviation() << " min=" << minValue << " max=" << maxValue << std::endl; } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderLandmarkIdentification.h0000664000175000017500000000363511572067322032351 0ustar michaelmichael #ifndef __COMMAND_SURFACE_BORDER_LANDMARK_IDENTIFICATION_H__ #define __COMMAND_SURFACE_BORDER_LANDMARK_IDENTIFICATION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for identifying landmarks with borders class CommandSurfaceBorderLandmarkIdentification : public CommandBase { public: // constructor CommandSurfaceBorderLandmarkIdentification(); // destructor ~CommandSurfaceBorderLandmarkIdentification(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_BORDER_LANDMARK_IDENTIFICATION_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderLandmarkIdentification.cxx0000664000175000017500000004555011572067322032726 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "AreaColorFile.h" #include "BorderColorFile.h" #include "BorderProjectionFile.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceBorderLandmarkIdentification.h" #include "BrainSet.h" #include "CommandSurfaceBorderLandmarkIdentification.h" #include "FileFilters.h" #include "FociColorFile.h" #include "FociProjectionFile.h" #include "MetricFile.h" #include "PaintFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SurfaceShapeFile.h" #include "VocabularyFile.h" #include "VolumeFile.h" /** * constructor. */ CommandSurfaceBorderLandmarkIdentification::CommandSurfaceBorderLandmarkIdentification() : CommandBase("-surface-border-landmark-identification", "SURFACE BORDER LANDMARK IDENTIFICATION") { } /** * destructor. */ CommandSurfaceBorderLandmarkIdentification::~CommandSurfaceBorderLandmarkIdentification() { } /** * get the script builder parameters. */ void CommandSurfaceBorderLandmarkIdentification::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { std::vector spaces; BrainModelSurfaceBorderLandmarkIdentification::getSupportedStereotaxicSpaces(spaces); std::vector spaceNames; for (unsigned int i = 0; i < spaces.size(); i++) { spaceNames.push_back(spaces[i].getName()); } paramsOut.clear(); paramsOut.addListOfItems("Stereotaxic Space", spaceNames, spaceNames); paramsOut.addFile("Anatomy Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addFile("Fiducial Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Inflated Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Very Inflated Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Ellipsoid Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Closed Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Input Paint File Name", FileFilters::getPaintFileFilter()); paramsOut.addFile("Output Paint File Name", FileFilters::getPaintFileFilter()); paramsOut.addString("Input Paint File Geography Column Name or Number", "Geography"); paramsOut.addFile("Surface Shape File Name", FileFilters::getSurfaceShapeFileFilter()); paramsOut.addString("Surface Shape File Depth Column Name or Number", "Depth"); paramsOut.addFile("Input Area Color File Name", FileFilters::getAreaColorFileFilter()); paramsOut.addFile("Output Area Color File Name", FileFilters::getAreaColorFileFilter()); paramsOut.addFile("Input Vocabulary File Name", FileFilters::getVocabularyFileFilter()); paramsOut.addFile("Output Vocabulary File Name", FileFilters::getVocabularyFileFilter()); paramsOut.addFile("Input Border Projection File Name", FileFilters::getBorderProjectionFileFilter()); paramsOut.addFile("Output Border Projection File Name", FileFilters::getBorderProjectionFileFilter()); paramsOut.addFile("Input Border Color File Name", FileFilters::getBorderColorFileFilter()); paramsOut.addFile("Output Border Color File Name", FileFilters::getBorderColorFileFilter()); // paramsOut.addFile("Output Foci Projection File Name", FileFilters::getFociProjectionFileFilter()); // paramsOut.addFile("Output Foci Color File Name", FileFilters::getFociColorFileFilter()); } /** * get full help information. */ QString CommandSurfaceBorderLandmarkIdentification::getHelpInformation() const { std::vector spaces; BrainModelSurfaceBorderLandmarkIdentification::getSupportedStereotaxicSpaces(spaces); QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" // + indent9 + " \n" // + indent9 + " \n" + indent9 + "\n" + indent9 + "Draw borders on landmarks for flattening and registration.\n" + indent9 + "The landmarks identified are:\n" + indent9 + " Calcarine Sulcus\n" + indent9 + " Central Sulcus\n" + indent9 + " Medial Wall\n" + indent9 + " Superior Temporal Gyrus\n" + indent9 + " Sylvian Fissure\n" + indent9 + "\n" + indent9 + "The anatomical volume is used to generate the corpus\n" + indent9 + "callosum. If desired, you may provide an anatomical \n" + indent9 + "volume that contains ONLY the corpus callosum. If so,\n" + indent9 + "the anatomical volume's filename MUST contain the\n" + indent9 + "case insensitive words \"corpus\" and \"callosum\".\n" + indent9 + "\n" + indent9 + "Supported stereotaxic spaces are: \n"); for (unsigned int i = 0; i < spaces.size(); i++) { helpInfo += (indent9 + " " + spaces[i].getName() + "\n"); } helpInfo += ( indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceBorderLandmarkIdentification::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { bool doLandmarksFlag = true; bool doFlattenFlag = true; const QString stereotaxicSpaceName = parameters->getNextParameterAsString("Stereotaxic Space Name"); const QString anatomicalVolumeFileName = parameters->getNextParameterAsString("Input Anatomical Volume File Name"); const QString fiducialCoordFileName = parameters->getNextParameterAsString("Input Fiducial Coord File Name"); const QString inflatedCoordFileName = parameters->getNextParameterAsString("Input Inflated Coord File Name"); const QString veryInflatedCoordFileName = parameters->getNextParameterAsString("Input Very Inflated Coord File Name"); const QString ellipsoidCoordFileName = parameters->getNextParameterAsString("Input Ellipsoid Coord File Name"); const QString inputTopoFileName = parameters->getNextParameterAsString("Input Closed Topology File Name"); const QString inputPaintFileName = parameters->getNextParameterAsString("Input Paint File Name"); const QString outputPaintFileName = parameters->getNextParameterAsString("Output Paint File Name"); const QString inputPaintFileGeographyColumnNameOrNumber = parameters->getNextParameterAsString("Input Paint File Geography Column Name or Number"); const QString inputSurfaceShapeFileName = parameters->getNextParameterAsString("Input Surface Shape File Name"); const QString inputSurfaceShapeFileDepthColumnNameOrNumber = parameters->getNextParameterAsString("Input Surface Shape File Depth Column Name or Number"); const QString inputAreaColorFileName = parameters->getNextParameterAsString("Input Area Color File Name"); const QString outputAreaColorFileName = parameters->getNextParameterAsString("Output Area Color File Name"); const QString inputVocabularyFileName = parameters->getNextParameterAsString("Input Vocabulary File Name"); const QString outputVocabularyFileName = parameters->getNextParameterAsString("Output Vocabulary File Name"); const QString inputBorderProjectionFileName = parameters->getNextParameterAsString("Input Border Projection File Name"); const QString outputBorderProjectionFileName = parameters->getNextParameterAsString("Output Border Projection File Name"); const QString inputBorderColorFileName = parameters->getNextParameterAsString("Input Border Color File Name"); const QString outputBorderColorFileName = parameters->getNextParameterAsString("Output Border Color File Name"); //const QString outputFociProjectionFileName = // parameters->getNextParameterAsString("Output Foci Projection File Name"); //const QString outputFociColorFileName = // parameters->getNextParameterAsString("Output Foci Color File Name"); // // Optional parameters // while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("Optional Param"); if (paramName == "-no-landmarks") { doLandmarksFlag = false; } else if (paramName == "-no-flatten") { doFlattenFlag = false; } else { throw CommandException("Unrecognized parameter: " + paramName); } } // // Check name of stereotaxic space // if (StereotaxicSpace::validStereotaxicSpaceName(stereotaxicSpaceName) == false) { throw CommandException(stereotaxicSpaceName + " is not the name of a valid stereotaxic space."); } StereotaxicSpace stereotaxicSpace(stereotaxicSpaceName); // // Create a spec file // SpecFile specFile; specFile.setAllFileSelections(SpecFile::SPEC_FALSE); specFile.addToSpecFile(SpecFile::getVolumeAnatomyFileTag(), anatomicalVolumeFileName, "", SpecFile::SPEC_FALSE); specFile.addToSpecFile(SpecFile::getFiducialCoordFileTag(), fiducialCoordFileName, "", SpecFile::SPEC_FALSE); specFile.addToSpecFile(SpecFile::getInflatedCoordFileTag(), inflatedCoordFileName, "", SpecFile::SPEC_FALSE); specFile.addToSpecFile(SpecFile::getVeryInflatedCoordFileTag(), veryInflatedCoordFileName, "", SpecFile::SPEC_FALSE); specFile.addToSpecFile(SpecFile::getEllipsoidCoordFileTag(), ellipsoidCoordFileName, "", SpecFile::SPEC_FALSE); specFile.addToSpecFile(SpecFile::getClosedTopoFileTag(), inputTopoFileName, "", SpecFile::SPEC_FALSE); specFile.addToSpecFile(SpecFile::getPaintFileTag(), inputPaintFileName, "", SpecFile::SPEC_FALSE); specFile.addToSpecFile(SpecFile::getSurfaceShapeFileTag(), inputSurfaceShapeFileName, "", SpecFile::SPEC_FALSE); if (inputAreaColorFileName.isEmpty() == false) { if (QFile::exists(inputAreaColorFileName)) { specFile.addToSpecFile(SpecFile::getAreaColorFileTag(), inputAreaColorFileName, "", SpecFile::SPEC_FALSE); } } if (inputVocabularyFileName.isEmpty() == false) { if (QFile::exists(inputVocabularyFileName)) { specFile.addToSpecFile(SpecFile::getVocabularyFileTag(), inputVocabularyFileName, "", SpecFile::SPEC_FALSE); } } if (inputBorderProjectionFileName.isEmpty() == false) { if (QFile::exists(inputBorderProjectionFileName)) { specFile.addToSpecFile(SpecFile::getBorderProjectionFileTag(), inputBorderProjectionFileName, "", SpecFile::SPEC_FALSE); } } if (inputBorderColorFileName.isEmpty() == false) { if (QFile::exists(inputBorderColorFileName)) { specFile.addToSpecFile(SpecFile::getBorderColorFileTag(), inputBorderColorFileName, "", SpecFile::SPEC_FALSE); } } // // Read the spec file into a brain set // QString errorMessage; BrainSet brainSet(true); if (brainSet.readSpecFile(specFile, "temp", errorMessage)) { const QString msg("ERROR: Reading spec file data files: \n" + errorMessage); throw CommandException(msg); } // // Find the fiducial and very inflated surfaces // BrainModelSurface* fiducialSurface = NULL; BrainModelSurface* inflatedSurface = NULL; BrainModelSurface* veryInflatedSurface = NULL; BrainModelSurface* ellipsoidSurface = NULL; for (int i = 0; i < brainSet.getNumberOfBrainModels(); i++) { BrainModelSurface* bms = brainSet.getBrainModelSurface(i); if (bms != NULL) { if (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FIDUCIAL) { fiducialSurface = bms; } else if (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_INFLATED) { inflatedSurface = bms; } else if (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_VERY_INFLATED) { veryInflatedSurface = bms; } else if (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL) { ellipsoidSurface = bms; } } } if (fiducialSurface == NULL) { throw CommandException("Unable to find fiducial surface."); } if (inflatedSurface == NULL) { throw CommandException("Unable to find inflated surface."); } if (veryInflatedSurface == NULL) { throw CommandException("Unable to find very inflated surface."); } if (ellipsoidSurface == NULL) { throw CommandException("Unable to find ellipsoid surface."); } // // Get the paint and shape column numbers // const int paintFileGeographyColumnNumber = brainSet.getPaintFile()->getColumnFromNameOrNumber(inputPaintFileGeographyColumnNameOrNumber, false); const int surfaceShapeFileDepthColumnNumber = brainSet.getSurfaceShapeFile()->getColumnFromNameOrNumber(inputSurfaceShapeFileDepthColumnNameOrNumber, false); // // Get any existing borders // BorderProjectionFile borderProjectionFile; brainSet.getBorderSet()->copyBordersToBorderProjectionFile(borderProjectionFile); int operation = 0; if (doLandmarksFlag) { operation |= BrainModelSurfaceBorderLandmarkIdentification::OPERATION_ID_REGISTRATION_LANDMARKS; } if (doFlattenFlag) { operation |= BrainModelSurfaceBorderLandmarkIdentification::OPERATION_ID_FLATTENING_LANDMARKS; } // // Identify the sulci // BrainModelSurfaceBorderLandmarkIdentification bmslg(&brainSet, stereotaxicSpace, brainSet.getVolumeAnatomyFile(0), fiducialSurface, inflatedSurface, veryInflatedSurface, ellipsoidSurface, brainSet.getSurfaceShapeFile(), surfaceShapeFileDepthColumnNumber, brainSet.getPaintFile(), paintFileGeographyColumnNumber, brainSet.getAreaColorFile(), &borderProjectionFile, brainSet.getBorderColorFile(), brainSet.getVocabularyFile(), operation); errorMessage = ""; try { bmslg.execute(); } catch (BrainModelAlgorithmException& e) { errorMessage = ("identifying landmarks: " + e.whatQString()); } // // Save the borders // borderProjectionFile.writeFile(outputBorderProjectionFileName); brainSet.getBorderColorFile()->writeFile(outputBorderColorFileName); // // Write the paint file // if (outputPaintFileName.isEmpty() == false) { brainSet.getPaintFile()->writeFile(outputPaintFileName); } // // Write the area color file // if (outputAreaColorFileName.isEmpty() == false) { brainSet.getAreaColorFile()->writeFile(outputAreaColorFileName); } // // Write the vocabulary file // if (outputVocabularyFileName.isEmpty() == false) { brainSet.getVocabularyFile()->writeFile(outputVocabularyFileName); } /* // // Write the foci and foci projection files // FociProjectionFile* fpf = (FociProjectionFile*)bmslg.getFociProjectionFile(); fpf->writeFile(outputFociProjectionFileName); brainSet.addToSpecFile(SpecFile::fociProjectionFileTag, outputFociProjectionFileName); FociColorFile* fcf = (FociColorFile*)bmslg.getFociColorFile(); fcf->writeFile(outputFociColorFileName); brainSet.addToSpecFile(SpecFile::fociColorFileTag, outputFociColorFileName); */ if (errorMessage.isEmpty() == false) { throw CommandException(errorMessage); } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderIntersection.h0000664000175000017500000000355711572067322030417 0ustar michaelmichael #ifndef __COMMAND_SURFACE_BORDER_INTERSECTION_H__ #define __COMMAND_SURFACE_BORDER_INTERSECTION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for finding the approximate intersection of two borders class CommandSurfaceBorderIntersection : public CommandBase { public: // constructor CommandSurfaceBorderIntersection(); // destructor ~CommandSurfaceBorderIntersection(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_BORDER_INTERSECTION_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderIntersection.cxx0000664000175000017500000002071311572067322030763 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BorderFile.h" #include "BorderProjectionFile.h" #include "BorderProjectionUnprojector.h" #include "BrainModelSurface.h" #include "BrainSet.h" #include "CellFileProjector.h" #include "CommandSurfaceBorderIntersection.h" #include "FileFilters.h" #include "FociFile.h" #include "FociProjectionFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandSurfaceBorderIntersection::CommandSurfaceBorderIntersection() : CommandBase("-surface-border-intersection", "SURFACE BORDER INTERSECTION") { } /** * destructor. */ CommandSurfaceBorderIntersection::~CommandSurfaceBorderIntersection() { } /** * get the script builder parameters. */ void CommandSurfaceBorderIntersection::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Coordinate File", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Topology File", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Border Projection File", FileFilters::getBorderProjectionFileFilter()); paramsOut.addFile("Input Foci Projection File", FileFilters::getFociProjectionFileFilter()); paramsOut.addFile("Output Foci Projection File", FileFilters::getFociProjectionFileFilter()); paramsOut.addString("Border 1 Name"); paramsOut.addString("Border 2 Name"); paramsOut.addString("Focus Name"); paramsOut.addFloat("Intersection Tolerance", 3.0, 0.0, 100000.0); } /** * get full help information. */ QString CommandSurfaceBorderIntersection::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Starting at the first border point in border 1, find the closest\n" + indent9 + "point in border 2. If the distance between these two border\n" + indent9 + "points is less than \"intersection-tolerance\", place a focus\n" + indent9 + "at this location. Otherwise, continue use successive points\n" + indent9 + "in border 1.\n" + indent9 + "\n" + indent9 + "The input foci projection file does not need to exist.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceBorderIntersection::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get parameters // const QString coordinateFileName = parameters->getNextParameterAsString("Coordinate File Name"); const QString topologyFileName = parameters->getNextParameterAsString("Topology File Name"); const QString borderProjectionFileName = parameters->getNextParameterAsString("Border Projection File Name"); const QString inputFociProjectionFileName = parameters->getNextParameterAsString("Input Foci Projection File Name"); const QString outputFociProjectionFileName = parameters->getNextParameterAsString("Output Foci Projection File Name"); const QString border1Name = parameters->getNextParameterAsString("Border 1 Name"); const QString border2Name = parameters->getNextParameterAsString("Border 2 Name"); const QString focusName = parameters->getNextParameterAsString("Focus Name"); const float intersectionTolerance = parameters->getNextParameterAsFloat("Intersection Tolerance"); checkForExcessiveParameters(); // // Create a brain set // BrainSet brainSet(topologyFileName, coordinateFileName, "", true); BrainModelSurface* bms = brainSet.getBrainModelSurface(0); if (bms == NULL) { throw CommandException("unable to find surface."); } bms->setSurfaceType(BrainModelSurface::SURFACE_TYPE_FIDUCIAL); // need for projection to work const TopologyFile* tf = bms->getTopologyFile(); if (tf == NULL) { throw CommandException("unable to find topology."); } const int numNodes = bms->getNumberOfNodes(); if (numNodes == 0) { throw CommandException("surface contains no nodes."); } // // Read the border projection file // BorderProjectionFile borderProjectionFile; borderProjectionFile.readFile(borderProjectionFileName); // // Find the borders // BorderProjection* bp1 = borderProjectionFile.getLastBorderProjectionByName(border1Name); if (bp1 == NULL) { throw CommandException("unable to find border named " + border1Name); } BorderProjection* bp2 = borderProjectionFile.getLastBorderProjectionByName(border2Name); if (bp2 == NULL) { throw CommandException("unable to find border named " + border2Name); } // // Create another border projection file containing just the two borders // BorderProjectionFile tempBorderProjFile; tempBorderProjFile.addBorderProjection(*bp1); tempBorderProjFile.addBorderProjection(*bp2); // // Unproject the two borders // BorderFile borderFile; BorderProjectionUnprojector unprojector; unprojector.unprojectBorderProjections(*(bms->getCoordinateFile()), tempBorderProjFile, borderFile); if (borderFile.getNumberOfBorders() != 2) { throw CommandException("unprojection of borders failed."); } // // Find intersection of two borders // const Border* border1 = borderFile.getBorder(0); const Border* border2 = borderFile.getBorder(1); int border1IntersectionLink, border2IntersectionLink; if (border1->intersection3D(border2, intersectionTolerance, border1IntersectionLink, border2IntersectionLink) == false) { throw CommandException("no intersection within tolerance."); } // // Read input foci projection file // FociProjectionFile fociProjectionFile; if (QFile::exists(inputFociProjectionFileName)) { fociProjectionFile.readFile(inputFociProjectionFileName); } // // Add a focus at border intersection // const float* focusXYZ = border1->getLinkXYZ(border1IntersectionLink); CellData focus(focusName, focusXYZ[0], focusXYZ[1], focusXYZ[2]); FociFile fociFile; fociFile.addCell(focus); // // Project the focus // CellProjectionFile tempFociProjFile; tempFociProjFile.appendFiducialCellFile(fociFile); CellFileProjector fociProjector(bms); fociProjector.projectFile(&tempFociProjFile, 0, CellFileProjector::PROJECTION_TYPE_ALL, 0.0, false, NULL); // // Get projected focus // fociProjectionFile.append(tempFociProjFile); // // Write the foci projection file // fociProjectionFile.writeFile(outputFociProjectionFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderFileMerge.h0000664000175000017500000000346211572067322027603 0ustar michaelmichael #ifndef __COMMAND_SURFACE_BORDER_FILE_MERGE_H__ #define __COMMAND_SURFACE_BORDER_FILE_MERGE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for merging border projection files class CommandSurfaceBorderFileMerge : public CommandBase { public: // constructor CommandSurfaceBorderFileMerge(); // destructor ~CommandSurfaceBorderFileMerge(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_BORDER_FILE_MERGE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderFileMerge.cxx0000664000175000017500000001040711572067322030153 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BorderProjectionFile.h" #include "CommandSurfaceBorderFileMerge.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandSurfaceBorderFileMerge::CommandSurfaceBorderFileMerge() : CommandBase("-surface-border-file-merge", "SURFACE BORDER FILE MERGE") { } /** * destructor. */ CommandSurfaceBorderFileMerge::~CommandSurfaceBorderFileMerge() { } /** * get the script builder parameters. */ void CommandSurfaceBorderFileMerge::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Output Border Projection File", FileFilters::getBorderProjectionFileFilter()); paramsOut.addFile("Input Border Projection File 1", FileFilters::getBorderProjectionFileFilter()); paramsOut.addFile("Input Border Projection File 2", FileFilters::getBorderProjectionFileFilter()); paramsOut.addVariableListOfParameters("Additional border projection files"); } /** * get full help information. */ QString CommandSurfaceBorderFileMerge::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[additional-input-border-projections-file-names]\n" + indent9 + "\n" + indent9 + "Merge two or more border projections files into a\n" + indent9 + "single border projection file.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceBorderFileMerge::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get required parameters // const QString outputBorderProjectionFileName = parameters->getNextParameterAsString("Output Border Projection File"); std::vector inputBorderProjectionFileNames; inputBorderProjectionFileNames.push_back( parameters->getNextParameterAsString("Input Border Projection File 1 Name")); inputBorderProjectionFileNames.push_back( parameters->getNextParameterAsString("Input Border Projection File 2 Name")); // // Process optional parameters // while (parameters->getParametersAvailable()) { inputBorderProjectionFileNames.push_back( parameters->getNextParameterAsString("Additional Border Projection File Names")); } // // Border projection file // BorderProjectionFile borderProjectionFile; // // loop through input border projections and append // std::vector borderProjectionsForDeletion; const int numInputFiles = static_cast(inputBorderProjectionFileNames.size()); for (int i = 0; i < numInputFiles; i++) { BorderProjectionFile bpf; bpf.readFile(inputBorderProjectionFileNames[i]); borderProjectionFile.append(bpf); } // // Write the border projection file // borderProjectionFile.writeFile(outputBorderProjectionFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderDrawMetric.h0000664000175000017500000000346211572067322030005 0ustar michaelmichael #ifndef __COMMAND_SURFACE_BORDER_DRAW_METRIC_H__ #define __COMMAND_SURFACE_BORDER_DRAW_METRIC_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandSurfaceBorderDrawMetric : public CommandBase { public: // constructor CommandSurfaceBorderDrawMetric(); // destructor ~CommandSurfaceBorderDrawMetric(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_BORDER_DRAW_METRIC_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderDrawMetric.cxx0000664000175000017500000003656111572067322030366 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BorderFile.h" #include "BorderFileProjector.h" #include "BorderProjectionFile.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceROICreateBorderUsingMetricShape.h" #include "BrainModelSurfaceROINodeSelection.h" #include "BrainSet.h" #include "CommandSurfaceBorderDrawMetric.h" #include "DebugControl.h" #include "FileFilters.h" #include "FileUtilities.h" #include "FociProjectionFile.h" #include "MetricFile.h" #include "NodeRegionOfInterestFile.h" #include "ProgramParameters.h" #include "NodeRegionOfInterestFile.h" #include "ScriptBuilderParameters.h" #include "TopologyFile.h" /** * constructor. */ CommandSurfaceBorderDrawMetric::CommandSurfaceBorderDrawMetric() : CommandBase("-surface-border-draw-metric", "SURFACE BORDER DRAWING ALONG METRIC") { } /** * destructor. */ CommandSurfaceBorderDrawMetric::~CommandSurfaceBorderDrawMetric() { } /** * get the script builder parameters. */ void CommandSurfaceBorderDrawMetric::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { std::vector searchValues, searchDescriptions; searchValues.push_back("POSITIVE"); searchDescriptions.push_back("Search Positive Nodes"); searchValues.push_back("NEGATIVE"); searchDescriptions.push_back("Search Negative Nodes"); paramsOut.clear(); paramsOut.addFile("Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Metric or Shape File Name", FileFilters::getMetricShapeFileFilter()); paramsOut.addString("Metric or Shape Column"); paramsOut.addListOfItems("Search Mode", searchValues, searchDescriptions); paramsOut.addFile("Foci Projection File Name", FileFilters::getFociProjectionFileFilter()); paramsOut.addString("Border Start Focus Name"); paramsOut.addString("Border End Focus Name"); paramsOut.addFile("Input Border Projection File Name", FileFilters::getBorderProjectionFileFilter()); paramsOut.addFile("Output Border Projection File Name", FileFilters::getBorderProjectionFileFilter()); paramsOut.addString("Border Name"); paramsOut.addFloat("Sampling Interval", 1.0, 0.0, 100000.0); paramsOut.addVariableListOfParameters("Border Options"); } /** * get full help information. */ QString CommandSurfaceBorderDrawMetric::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + "[-roi-file roi-file-name] \n" + indent9 + "\n" + indent9 + "Draw a border along nodes in the region of interest\n" + indent9 + "from the node nearest the starting focus to the \n" + indent9 + "ending focus. Each successive node is the next node\n" + indent9 + "connected to the current node that has the most positive\n" + indent9 + "or negative value and is closer to the ending node than\n" + indent9 + "the current node.\n" + indent9 + "\n" + indent9 + "It is best to use a \"lightly folded\" surface such as\n" + indent9 + "a very inflated or ellipsoid surface. When finding the\n" + indent9 + "path the, the distance from the next node to the end \n" + indent9 + "node must be less than the distance from the current\n" + indent9 + "node to the end node. When the surface has big folds,\n" + indent9 + "the next node may move away from the end node and \n" + indent9 + "the algorithm will fail.\n" + indent9 + "\n" + indent9 + "Uses the last focus for starting and stopping foci.\n" + indent9 + "\n" + indent9 + "\"METRIC-SHAPE-SEARCH-MODE\" is one of:\n" + indent9 + " POSITIVE - searches along most positive nodes.\n" + indent9 + " NEGATIVE - searches along most negative nodes.\n" + indent9 + "\n" + indent9 + "If a region of interest file is supplied, only nodes that \n" + indent9 + "are in the region of interest will be searched.\n" + indent9 + "\n" + indent9 + "\"metric-shape-column\" is either the number of the column,\n" + indent9 + "which starts at one, or the name of the column. If a \n" + indent9 + "name contains spaces, it must be enclosed in double \n" + indent9 + "quotes. Name has priority over number. \n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceBorderDrawMetric::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get parameters // const QString coordinateFileName = parameters->getNextParameterAsString("Coordinate File Name"); const QString topologyFileName = parameters->getNextParameterAsString("Topology File Name"); const QString metricFileName = parameters->getNextParameterAsString("Metric/Shape File File Name"); const QString metricColumnString = parameters->getNextParameterAsString("Metric/Shape Column"); const QString metricSearchModeString = parameters->getNextParameterAsString("Metric/Shape Search Mode"); const QString fociProjectionFileName = parameters->getNextParameterAsString("Foci Projection File Name"); const QString focusNameForBorderStart = parameters->getNextParameterAsString("Name of Focus for Border Start"); const QString focusNameForBorderEnd = parameters->getNextParameterAsString("Name of Focus for Border End"); const QString inputBorderProjectionFileName = parameters->getNextParameterAsString("Input Border Projection File Name"); const QString outputBorderProjectionFileName = parameters->getNextParameterAsString("Output Border Projection File Name"); const QString borderName = parameters->getNextParameterAsString("Output Border Name"); const float borderSampling = parameters->getNextParameterAsFloat("Output Border Sampling"); // // Optional append file names // QString regionOfInterestFileName; // // Process the parameters for node selection // while (parameters->getParametersAvailable()) { // // Get the selection type // const QString paramName = parameters->getNextParameterAsString("Optional Border Draw Parameters"); if (paramName == "-roi-file") { regionOfInterestFileName = parameters->getNextParameterAsString("Region of Interest File Name"); } else { throw CommandException("Unrecognized parameter = \"" + paramName + "\"."); } } // Create a brain set // BrainSet brainSet(topologyFileName, coordinateFileName, "", true); BrainModelSurface* bms = brainSet.getBrainModelSurface(0); if (bms == NULL) { throw CommandException("unable to find surface."); } const TopologyFile* tf = bms->getTopologyFile(); if (tf == NULL) { throw CommandException("unable to find topology."); } const int numNodes = bms->getNumberOfNodes(); if (numNodes == 0) { throw CommandException("surface contains no nodes."); } // // Read the metric file // MetricFile metricFile; metricFile.readFile(metricFileName); // // Get the metric shape column // const int metricColumnNumber = metricFile.getColumnFromNameOrNumber(metricColumnString, false); // // Check mode // BrainModelSurfaceROICreateBorderUsingMetricShape::MODE searchMode; if (metricSearchModeString == "NEGATIVE") { searchMode = BrainModelSurfaceROICreateBorderUsingMetricShape::MODE_FOLLOW_MOST_NEGATIVE; } else if (metricSearchModeString == "POSITIVE") { searchMode = BrainModelSurfaceROICreateBorderUsingMetricShape::MODE_FOLLOW_MOST_POSITIVE; } else { throw CommandException("invalid metric mode " + metricSearchModeString); } // // Set the region of interest for the brain set // BrainModelSurfaceROINodeSelection* roi = brainSet.getBrainModelSurfaceRegionOfInterestNodeSelection(); if (regionOfInterestFileName.isEmpty() == false) { // // Get region of interest from file // NodeRegionOfInterestFile roiFile; roiFile.readFile(regionOfInterestFileName); roi->getRegionOfInterestFromFile(roiFile); } else { // // Put all nodes in region of interest // roi->selectAllNodes(bms); } // // Read the foci projection file // FociProjectionFile fociProjectionFile; fociProjectionFile.readFile(fociProjectionFileName); // // Get the start and end foci // const CellProjection* startFocus = fociProjectionFile.getLastCellProjectionWithName(focusNameForBorderStart); if (startFocus == NULL) { throw CommandException("unable to find a focus named \"" + focusNameForBorderStart + "\" in the file " + FileUtilities::basename(fociProjectionFileName)); } const CellProjection* endFocus = fociProjectionFile.getLastCellProjectionWithName(focusNameForBorderEnd); if (endFocus == NULL) { throw CommandException("unable to find a focus named \"" + focusNameForBorderEnd + "\" in the file " + FileUtilities::basename(fociProjectionFileName)); } // // Unproject the foci to the surface // const bool fiducialSurfaceFlag = (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FIDUCIAL); const bool flatSurfaceFlag = ((bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FLAT) || (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR)); float startXYZ[3], endXYZ[3]; if (startFocus->getProjectedPosition(bms->getCoordinateFile(), bms->getTopologyFile(), fiducialSurfaceFlag, flatSurfaceFlag, false, startXYZ) == false) { throw CommandException("unable to get projected position for " + focusNameForBorderStart); } if (endFocus->getProjectedPosition(bms->getCoordinateFile(), bms->getTopologyFile(), fiducialSurfaceFlag, flatSurfaceFlag, false, endXYZ) == false) { throw CommandException("unable to get projected position for " + focusNameForBorderEnd); } //if (DebugControl::getDebugOn()) { std::cout << "Start XYZ: " << startXYZ[0] << " " << startXYZ[1] << " " << startXYZ[2] << std::endl; std::cout << "End XYZ: " << endXYZ[0] << " " << endXYZ[1] << " " << endXYZ[2] << std::endl; //} // // Get the nodes nearest the start and end foci // const int startNode = bms->getNodeClosestToPoint(startXYZ); if (startNode < 0) { throw CommandException("unable to find node closest to start focus."); } const int endNode = bms->getNodeClosestToPoint(endXYZ); if (endNode < 0) { throw CommandException("unable to find node closest to end focus."); } //if (DebugControl::getDebugOn()) { std::cout << "Border Start Node: " << startNode << std::endl; std::cout << "Border End Node: " << endNode << std::endl; //} // // Force the starting and ending nodes to be in the ROI and connected // roi->expandSoNodesAreWithinAndConnected(bms, startNode, endNode); // // Draw the border // BrainModelSurfaceROICreateBorderUsingMetricShape createBorder(&brainSet, bms, roi, searchMode, &metricFile, metricColumnNumber, borderName, startNode, endNode, borderSampling); createBorder.execute(); const Border border = createBorder.getBorder(); if (border.getNumberOfLinks() <= 0) { throw ("Border drawn as " + borderName + "\"has no links."); } BorderFile borderFile; borderFile.addBorder(border); // // Project the border // BorderProjectionFile bpf; BorderFileProjector projector(bms, true); projector.projectBorderFile(&borderFile, &bpf, NULL); // // Write the border projection file // BorderProjectionFile borderProjectionFile; if (inputBorderProjectionFileName.isEmpty() == false) { if (QFile::exists(inputBorderProjectionFileName)) { borderProjectionFile.readFile(inputBorderProjectionFileName); } } borderProjectionFile.append(bpf); borderProjectionFile.writeFile(outputBorderProjectionFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderDrawGeodesic.h0000664000175000017500000000347611572067322030311 0ustar michaelmichael #ifndef __COMMAND_SURFACE_BORDER_DRAW_GEODESIC_H__ #define __COMMAND_SURFACE_BORDER_DRAW_GEODESIC_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandSurfaceBorderDrawGeodesic : public CommandBase { public: // constructor CommandSurfaceBorderDrawGeodesic(); // destructor ~CommandSurfaceBorderDrawGeodesic(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_BORDER_DRAW_GEODESIC_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderDrawGeodesic.cxx0000664000175000017500000003054311572067322030657 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BorderFile.h" #include "BorderFileProjector.h" #include "BorderProjectionFile.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceROICreateBorderUsingGeodesic.h" #include "BrainModelSurfaceROINodeSelection.h" #include "BrainSet.h" #include "CommandSurfaceBorderDrawGeodesic.h" #include "DebugControl.h" #include "FileFilters.h" #include "FileUtilities.h" #include "FociProjectionFile.h" #include "NodeRegionOfInterestFile.h" #include "ProgramParameters.h" #include "NodeRegionOfInterestFile.h" #include "ScriptBuilderParameters.h" #include "TopologyFile.h" /** * constructor. */ CommandSurfaceBorderDrawGeodesic::CommandSurfaceBorderDrawGeodesic() : CommandBase("-surface-border-draw-geodesic", "SURFACE BORDER DRAWING ALONG GEODESIC") { } /** * destructor. */ CommandSurfaceBorderDrawGeodesic::~CommandSurfaceBorderDrawGeodesic() { } /** * get the script builder parameters. */ void CommandSurfaceBorderDrawGeodesic::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Foci Projection File Name", FileFilters::getFociProjectionFileFilter()); paramsOut.addString("Border Start Focus Name"); paramsOut.addString("Border End Focus Name"); paramsOut.addFile("Region of Interest File Name", FileFilters::getRegionOfInterestFileFilter()); paramsOut.addFile("Input Border Projection File Name", FileFilters::getBorderProjectionFileFilter()); paramsOut.addFile("Output Border Projection File Name", FileFilters::getBorderProjectionFileFilter()); paramsOut.addString("Border Name"); paramsOut.addFloat("Sampling Interval", 1.0, 0.0, 100000.0); paramsOut.addVariableListOfParameters("Draw Geodesic Options"); } /** * get full help information. */ QString CommandSurfaceBorderDrawGeodesic::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + "[-allow-start-end-the-same]\n" + indent9 + "\n" + indent9 + "Draw a border along nodes in the region of interest\n" + indent9 + "from the node nearest the starting focus to the \n" + indent9 + "ending focus.\n" + indent9 + "\n" + indent9 + "If \"-allow-start-end-the-same\" is specified and the \n" + indent9 + "starting and stopping foci project to the same node,\n" + indent9 + "a border containing a single point will be output.\n" + indent9 + "\n" + indent9 + "Uses the last focus found with the specified name for \n" + indent9 + "starting and stopping foci.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceBorderDrawGeodesic::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get parameters // const QString coordinateFileName = parameters->getNextParameterAsString("Coordinate File Name"); const QString topologyFileName = parameters->getNextParameterAsString("Topology File Name"); const QString fociProjectionFileName = parameters->getNextParameterAsString("Foci Projection File Name"); const QString focusNameForBorderStart = parameters->getNextParameterAsString("Name of Focus for Border Start"); const QString focusNameForBorderEnd = parameters->getNextParameterAsString("Name of Focus for Border End"); const QString regionOfInterestFileName = parameters->getNextParameterAsString("Region of Interest File Name"); const QString inputBorderProjectionFileName = parameters->getNextParameterAsString("Input Border Projection File Name"); const QString outputBorderProjectionFileName = parameters->getNextParameterAsString("Output Border Projection File Name"); const QString borderName = parameters->getNextParameterAsString("Output Border Name"); const float borderSampling = parameters->getNextParameterAsFloat("Output Border Sampling"); bool allowIdenticalStartEndFlag = false; while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("Border Draw Geodesic option"); if (paramName == "-allow-start-end-the-same") { allowIdenticalStartEndFlag = true; } } // Create a brain set // BrainSet brainSet(topologyFileName, coordinateFileName, "", true); BrainModelSurface* bms = brainSet.getBrainModelSurface(0); if (bms == NULL) { throw CommandException("unable to find surface."); } const TopologyFile* tf = bms->getTopologyFile(); if (tf == NULL) { throw CommandException("unable to find topology."); } const int numNodes = bms->getNumberOfNodes(); if (numNodes == 0) { throw CommandException("surface contains no nodes."); } // // Read the region of interest file // NodeRegionOfInterestFile roiFile; roiFile.readFile(regionOfInterestFileName); // // Set the region of interest for the brain set // BrainModelSurfaceROINodeSelection* roi = brainSet.getBrainModelSurfaceRegionOfInterestNodeSelection(); roi->getRegionOfInterestFromFile(roiFile); // // Read the foci projection file // FociProjectionFile fociProjectionFile; fociProjectionFile.readFile(fociProjectionFileName); // // Get the start and end foci // const CellProjection* startFocus = fociProjectionFile.getLastCellProjectionWithName(focusNameForBorderStart); if (startFocus == NULL) { throw CommandException("unable to find a focus named \"" + focusNameForBorderStart + "\" in the file " + FileUtilities::basename(fociProjectionFileName)); } const CellProjection* endFocus = fociProjectionFile.getLastCellProjectionWithName(focusNameForBorderEnd); if (endFocus == NULL) { throw CommandException("unable to find a focus named \"" + focusNameForBorderEnd + "\" in the file " + FileUtilities::basename(fociProjectionFileName)); } // // Unproject the foci to the surface // const bool fiducialSurfaceFlag = (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FIDUCIAL); const bool flatSurfaceFlag = ((bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FLAT) || (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR)); float startXYZ[3], endXYZ[3]; if (startFocus->getProjectedPosition(bms->getCoordinateFile(), bms->getTopologyFile(), fiducialSurfaceFlag, flatSurfaceFlag, false, startXYZ) == false) { throw CommandException("unable to get projected position for " + focusNameForBorderStart); } if (endFocus->getProjectedPosition(bms->getCoordinateFile(), bms->getTopologyFile(), fiducialSurfaceFlag, flatSurfaceFlag, false, endXYZ) == false) { throw CommandException("unable to get projected position for " + focusNameForBorderEnd); } //if (DebugControl::getDebugOn()) { std::cout << "Start XYZ: " << startXYZ[0] << " " << startXYZ[1] << " " << startXYZ[2] << std::endl; std::cout << "End XYZ: " << endXYZ[0] << " " << endXYZ[1] << " " << endXYZ[2] << std::endl; //} // // Get the nodes nearest the start and end foci // const int startNode = bms->getNodeClosestToPoint(startXYZ); if (startNode < 0) { throw CommandException("unable to find node closest to start focus."); } const int endNode = bms->getNodeClosestToPoint(endXYZ); if (endNode < 0) { throw CommandException("unable to find node closest to end focus."); } if (DebugControl::getDebugOn()) { std::cout << "Border Start Node: " << startNode << std::endl; std::cout << "Border End Node: " << endNode << std::endl; } BorderFile borderFile; // // Are start and end nodes that same and does user allow this // if ((startNode == endNode) && allowIdenticalStartEndFlag) { Border border(borderName); border.addBorderLink(startXYZ); borderFile.addBorder(border); } else { // // Force the starting and ending nodes to be in the ROI and connected // roi->expandSoNodesAreWithinAndConnected(bms, startNode, endNode); // // Draw the border // BrainModelSurfaceROICreateBorderUsingGeodesic createBorder(&brainSet, bms, roi, borderName, startNode, endNode, borderSampling); createBorder.execute(); const Border border = createBorder.getBorder(); if (border.getNumberOfLinks() <= 0) { throw ("Border drawn as " + borderName + "\"has no links."); } borderFile.addBorder(border); } // // Project the border // BorderProjectionFile bpf; BorderFileProjector projector(bms, true); projector.projectBorderFile(&borderFile, &bpf, NULL); // // Write the border projection file // BorderProjectionFile borderProjectionFile; if (inputBorderProjectionFileName.isEmpty() == false) { if (QFile::exists(inputBorderProjectionFileName)) { borderProjectionFile.readFile(inputBorderProjectionFileName); } } borderProjectionFile.append(bpf); borderProjectionFile.writeFile(outputBorderProjectionFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderDrawAroundROI.h0000664000175000017500000000354611572067322030367 0ustar michaelmichael #ifndef __COMMAND_SURFACE_DRAW_BORDER_AROUND_ROI_H__ #define __COMMAND_SURFACE_DRAW_BORDER_AROUND_ROI_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for drawing a border around an ROI class CommandSurfaceBorderDrawAroundROI : public CommandBase { public: // constructor CommandSurfaceBorderDrawAroundROI(); // destructor ~CommandSurfaceBorderDrawAroundROI(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_DRAW_BORDER_AROUND_ROI_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderDrawAroundROI.cxx0000664000175000017500000002354511572067322030743 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BorderProjectionFile.h" #include "BrainModelBorderSet.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceClusterToBorderConverter.h" #include "BrainModelSurfaceROINodeSelection.h" #include "BrainSet.h" #include "CommandSurfaceBorderDrawAroundROI.h" #include "FileFilters.h" #include "FociProjectionFile.h" #include "NodeRegionOfInterestFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandSurfaceBorderDrawAroundROI::CommandSurfaceBorderDrawAroundROI() : CommandBase("-surface-border-draw-around-roi", "SURFACE BORDER DRAW AROUND ROI") { } /** * destructor. */ CommandSurfaceBorderDrawAroundROI::~CommandSurfaceBorderDrawAroundROI() { } /** * get the script builder parameters. */ void CommandSurfaceBorderDrawAroundROI::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Region of Interest File Name", FileFilters::getRegionOfInterestFileFilter()); paramsOut.addFile("Input Border Projection File Name", FileFilters::getBorderProjectionFileFilter()); paramsOut.addFile("Output Border Projection File Name", FileFilters::getBorderProjectionFileFilter()); paramsOut.addString("Border Name"); paramsOut.addVariableListOfParameters("Draw Border ROI Options"); } /** * get full help information. */ QString CommandSurfaceBorderDrawAroundROI::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-output-all-borders]\n" + indent9 + "[-start-near-focus foci-projection-file-name focus-name]\n" + indent9 + "\n" + indent9 + "Draw a border around a surface region of interest. \n" + indent9 + "\n" + indent9 + "By default, if there is more than one disjoint region in\n" + indent9 + "the ROI, only the border with the greatest number of links\n" + indent9 + "is output. \n" + indent9 + "\n" + indent9 + "If the \"-output-all-borders\" option is specified, the\n" + indent9 + " borders for ALL disjoint regions are output.\n" + indent9 + "\n" + indent9 + "If the \"-start-near-focus\" option is specified, all \n" + indent9 + "borders are set up so that the first link in the border is\n" + indent9 + "the link nearest the focus. This option is only applied if\n" + indent9 + "\"-output-all-borders\" is NOT specified.\n" + indent9 + "\n" + indent9 + "Note: The input border projection file does not need to exist.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceBorderDrawAroundROI::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get coord, topo, and roi file names // const QString coordFileName = parameters->getNextParameterAsString("Input Coordinate File Name"); const QString topoFileName = parameters->getNextParameterAsString("Input Topology File Name"); const QString roiFileName = parameters->getNextParameterAsString("Input Region of Interest File Name"); const QString inputBorderProjectionFileName = parameters->getNextParameterAsString("Input Border Projection File Name"); const QString outputBorderProjectionFileName = parameters->getNextParameterAsString("Output Border Projection File Name"); const QString borderName = parameters->getNextParameterAsString("Border Name"); // // Create a brain set // BrainSet brainSet(topoFileName, coordFileName, "", true); BrainModelSurface* bms = brainSet.getBrainModelSurface(0); if (bms == NULL) { throw CommandException("unable to find surface."); } const CoordinateFile* cf = bms->getCoordinateFile(); const TopologyFile* tf = bms->getTopologyFile(); if (tf == NULL) { throw CommandException("unable to find topology."); } const int numNodes = bms->getNumberOfNodes(); if (numNodes == 0) { throw CommandException("surface contains not nodes."); } // // Optional starting location of border // float startXYZ[3]; bool startXYZValid = false; // // Check options parameters // bool outputAllBordersFlag = false; while (parameters->getParametersAvailable()) { const QString paramName(parameters->getNextParameterAsString("Draw Border Option")); if (paramName == "-start-near-focus") { const QString fociProjectionFileName = parameters->getNextParameterAsString("Foci Projection File Name"); const QString focusName = parameters->getNextParameterAsString("Focus Name"); FociProjectionFile fociProjectionFile; fociProjectionFile.readFile(fociProjectionFileName); const CellProjection* focus = fociProjectionFile.getLastCellProjectionWithName(focusName); if (focus == NULL) { throw CommandException("Focus named " + focusName + " not found in file " + fociProjectionFileName); } if (focus->getProjectedPosition(cf, tf, bms->getIsFiducialSurface(), bms->getIsFlatSurface(), false, startXYZ)) { startXYZValid = true; } } else if (paramName == "-output-all-borders") { outputAllBordersFlag = true; } else { throw CommandException("Unrecognized option: " + paramName); } } // // Get the region of interest node selection // BrainModelSurfaceROINodeSelection* roi = brainSet.getBrainModelSurfaceRegionOfInterestNodeSelection(); roi->deselectAllNodes(); // // Read input ROI file // NodeRegionOfInterestFile roiFile; roiFile.readFile(roiFileName); roi->getRegionOfInterestFromFile(roiFile); if (roi->getNumberOfNodesSelected() <= 0) { throw CommandException("No nodes are selected in the ROI."); } // // Create borders around ROI clusters // BrainModelSurfaceClusterToBorderConverter roiToBorders(&brainSet, bms, bms->getTopologyFile(), borderName, roi, true); roiToBorders.execute(); // // Get the borders that were created // BrainModelBorderSet* bmbs = brainSet.getBorderSet(); const int numBorders = bmbs->getNumberOfBorders(); if (numBorders <= 0) { throw CommandException("No borders were created around the ROI."); } // // Get new borders as border projection // BorderProjectionFile newBorderProjectionFile; bmbs->copyBordersToBorderProjectionFile(newBorderProjectionFile); // // Read input border projection file // BorderProjectionFile outputBorderProjectionFile; if (inputBorderProjectionFileName.isEmpty() == false) { if (QFile::exists(inputBorderProjectionFileName)) { outputBorderProjectionFile.readFile(inputBorderProjectionFileName); } } // // Output all borders ? // if (outputAllBordersFlag) { // // Append new borders // outputBorderProjectionFile.append(newBorderProjectionFile); } else { // // Get border projection with the largest number of links // BorderProjection* borderProjection = newBorderProjectionFile.getBorderProjectionWithLargestNumberOfLinks(); // // Should border start in a specified location // if (startXYZValid) { borderProjection->changeStartingLinkOfClosedBorderToBeNearPoint(cf, startXYZ); } // // Append new projections // outputBorderProjectionFile.addBorderProjection(*borderProjection); } // // Write border projections // outputBorderProjectionFile.writeFile(outputBorderProjectionFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderDelete.h0000664000175000017500000000346011572067322027144 0ustar michaelmichael #ifndef __COMMAND_SURFACE_BORDER_DELETE_H__ #define __COMMAND_SURFACE_BORDER_DELETE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for deleting borders by name class CommandSurfaceBorderDelete : public CommandBase { public: // constructor CommandSurfaceBorderDelete(); // destructor ~CommandSurfaceBorderDelete(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_BORDER_DELETE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderDelete.cxx0000664000175000017500000001001311572067322027507 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BorderProjectionFile.h" #include "CommandSurfaceBorderDelete.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandSurfaceBorderDelete::CommandSurfaceBorderDelete() : CommandBase("-surface-border-delete", "SURFACE BORDER DELETION") { } /** * destructor. */ CommandSurfaceBorderDelete::~CommandSurfaceBorderDelete() { } /** * get the script builder parameters. */ void CommandSurfaceBorderDelete::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Border Projection File", FileFilters::getBorderProjectionFileFilter()); paramsOut.addFile("Output Border Projection File", FileFilters::getBorderProjectionFileFilter()); paramsOut.addVariableListOfParameters("Border Names"); } /** * get full help information. */ QString CommandSurfaceBorderDelete::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + "[border-names] \n" + indent9 + "\n" + indent9 + "Delete borders with the specified names from the border\n" + indent9 + "projection file. If a border name contains spaces, it must\n" + indent9 + "be enclosed within double quotes.\n" + indent9 + "\n" + indent9 + "If the input border projection file name does not exist\n" + indent9 + "the command will exit without reporting an error but\n" + indent9 + "it will report a warning.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceBorderDelete::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputBorderProjectionFileName = parameters->getNextParameterAsString("Input Border Projection File Name"); const QString outputBorderProjectionFileName = parameters->getNextParameterAsString("Input Border Projection File Name"); if (QFile::exists(inputBorderProjectionFileName) == false) { std::cout << "WARNING " << getShortDescription().toAscii().constData() << " \"" << inputBorderProjectionFileName.toAscii().constData() << "\" was not found." << std::endl; return; } BorderProjectionFile borderProjectionFile; borderProjectionFile.readFile(inputBorderProjectionFileName); while (parameters->getParametersAvailable()) { const QString borderName = parameters->getNextParameterAsString("Border Name"); borderProjectionFile.removeBordersWithName(borderName); } borderProjectionFile.writeFile(outputBorderProjectionFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderCutter.h0000664000175000017500000000346711572067322027217 0ustar michaelmichael #ifndef __COMMAND_SURFACE_BORDER_CUTTER_H__ #define __COMMAND_SURFACE_BORDER_CUTTER_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for cutting a surface using borders class CommandSurfaceBorderCutter : public CommandBase { public: // constructor CommandSurfaceBorderCutter(); // destructor ~CommandSurfaceBorderCutter(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_BORDER_CUTTER_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderCutter.cxx0000664000175000017500000001603011572067322027560 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BorderProjectionFile.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceBorderCutter.h" #include "BrainSet.h" #include "CommandSurfaceBorderCutter.h" #include "CoordinateFile.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "TopologyFile.h" /** * constructor. */ CommandSurfaceBorderCutter::CommandSurfaceBorderCutter() : CommandBase("-surface-border-cutter", "SURFACE BORDER CUTTER") { } /** * destructor. */ CommandSurfaceBorderCutter::~CommandSurfaceBorderCutter() { } /** * get the script builder parameters. */ void CommandSurfaceBorderCutter::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { std::vector cutModes, cutModeDescriptions; cutModes.push_back("FLAT"); cutModeDescriptions.push_back("Cut Flat Surface"); cutModes.push_back("POS_Z"); cutModeDescriptions.push_back("Cut Only Parts of Surface with Positive Z-Coordinates"); cutModes.push_back("SPHERE"); cutModeDescriptions.push_back("Cut Anywhere on a Sphere"); paramsOut.clear(); paramsOut.addFile("Input Coordinate File", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Input Topology File", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Output Coordinate File", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Output Topology File", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Input Border Projection File", FileFilters::getBorderProjectionFileFilter()); paramsOut.addListOfItems("Cut Mode", cutModes, cutModeDescriptions); } /** * get full help information. */ QString CommandSurfaceBorderCutter::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Cut the surface using as cuts all borders in the border\n" + indent9 + "projection file.\n" + indent9 + "\n" + indent9 + "\"cut-mode\" is one of:\n" + indent9 + " FLAT\n" + indent9 + " POS_Z\n" + indent9 + " SPHERE\n" + indent9 + "Use \"FLAT\" for cutting flat surfaces. Use \"POS_Z\" to\n" + indent9 + "apply the cuts only to nodes with positive Z-coordinates.\n" + indent9 + "Use \"SPHERE\" to process cuts anywhere on a sphere.\n" + indent9 + "\n" + indent9 + "If the \"output-coordinate-file-name\" or the\n" + indent9 + "\"output-topology-file-name\" is empty (consecutive \n" + indent9 + "double quotes), the respective file is not written.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceBorderCutter::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get parameters // const QString inputCoordinateFileName = parameters->getNextParameterAsString("Input Coordinate File Name"); const QString inputTopologyFileName = parameters->getNextParameterAsString("Input Topology File Name"); const QString outputCoordinateFileName = parameters->getNextParameterAsString("Output Coordinate File Name"); const QString outputTopologyFileName = parameters->getNextParameterAsString("Output Topology File Name"); const QString inputBorderProjectionFileName = parameters->getNextParameterAsString("Input Border Projection File Name"); const QString cutModeName = parameters->getNextParameterAsString("Cut Mode"); checkForExcessiveParameters(); // // Get cut mode // BrainModelSurfaceBorderCutter::CUTTING_MODE cutMode; if (cutModeName == "FLAT") { cutMode = BrainModelSurfaceBorderCutter::CUTTING_MODE_FLAT_SURFACE; } else if (cutModeName == "POS_Z") { cutMode = BrainModelSurfaceBorderCutter::CUTTING_MODE_NON_NEGATIVE_Z_ONLY; } else if (cutModeName == "SPHERE") { cutMode = BrainModelSurfaceBorderCutter::CUTTING_MODE_SPHERICAL_SURFACE; } else { throw CommandException("Invalid cut mode: " + cutModeName); } // // Create a brain set and find the surface // BrainSet brainSet(inputTopologyFileName, inputCoordinateFileName, "", true); BrainModelSurface* bms = brainSet.getBrainModelSurface(0); if (bms == NULL) { throw CommandException("Problem reading coordinate file."); } TopologyFile* tf = bms->getTopologyFile(); if (tf == NULL) { throw CommandException("Problem reading topology file."); } // // read the border projections // BorderProjectionFile borderProjectionFile; borderProjectionFile.readFile(inputBorderProjectionFileName); // // Cut the surface // BrainModelSurfaceBorderCutter cmsbc(&brainSet, bms, &borderProjectionFile, cutMode, false); cmsbc.execute(); // // Write the topology file before the coordinate file // if (outputTopologyFileName.isEmpty() == false) { brainSet.writeTopologyFile(outputTopologyFileName, tf->getTopologyType(), tf); } // // Write the coordinate file // if (outputCoordinateFileName.isEmpty() == false) { brainSet.writeCoordinateFile(outputCoordinateFileName, bms->getSurfaceType(), bms->getCoordinateFile(), true); } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderCreateParallelBorder.h0000664000175000017500000000364611572067322031766 0ustar michaelmichael #ifndef __COMMAND_SURFACE_BORDER_CREATE_PARALLEL_BORDER_H__ #define __COMMAND_SURFACE_BORDER_CREATE_PARALLEL_BORDER_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for creating a new border parallel to an existing border class CommandSurfaceBorderCreateParallelBorder : public CommandBase { public: // constructor CommandSurfaceBorderCreateParallelBorder(); // destructor ~CommandSurfaceBorderCreateParallelBorder(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_BORDER_CREATE_PARALLEL_BORDER_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderCreateParallelBorder.cxx0000664000175000017500000002311311572067322032330 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BorderFile.h" #include "BorderFileProjector.h" #include "BorderProjectionFile.h" #include "BorderProjectionUnprojector.h" #include "BrainModelSurface.h" #include "BrainSet.h" #include "CommandSurfaceBorderCreateParallelBorder.h" #include "CoordinateFile.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandSurfaceBorderCreateParallelBorder::CommandSurfaceBorderCreateParallelBorder() : CommandBase("-surface-border-create-parallel-border", "SURFACE BORDER CREATE PARALLEL BORDER") { } /** * destructor. */ CommandSurfaceBorderCreateParallelBorder::~CommandSurfaceBorderCreateParallelBorder() { } /** * get the script builder parameters. */ void CommandSurfaceBorderCreateParallelBorder::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Input Border Projection File Name", FileFilters::getBorderProjectionFileFilter()); paramsOut.addFile("Output Border Projection File Name", FileFilters::getBorderProjectionFileFilter()); paramsOut.addString("Input Border Name"); paramsOut.addString("Output Parallel Border Name"); paramsOut.addVariableListOfParameters("Axes Options"); } /** * get full help information. */ QString CommandSurfaceBorderCreateParallelBorder::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-separation-axis AXIS-NAME AXIS-VALUE]\n" + indent9 + "\n" + indent9 + "Create a new border that is parallel to an existing border.\n" + indent9 + "\n" + indent9 + "\"AXIS-NAME\" is one of:\n" + indent9 + " X\n" + indent9 + " Y\n" + indent9 + " Z\n" + indent9 + " LATERAL\n" + indent9 + " MEDIAL\n" + indent9 + "\n" + indent9 + "Multiple axes may be specified.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceBorderCreateParallelBorder::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get coord, topo, and roi file names // const QString coordFileName = parameters->getNextParameterAsString("Input Coordinate File Name"); const QString topoFileName = parameters->getNextParameterAsString("Input Topology File Name"); const QString inputBorderProjectionFileName = parameters->getNextParameterAsString("Input Border Projection File Name"); const QString outputBorderProjectionFileName = parameters->getNextParameterAsString("Output Border Projection File Name"); const QString inputBorderName = parameters->getNextParameterAsString("Input Border Name"); const QString outputBorderName = parameters->getNextParameterAsString("Output Parallel Border Name"); std::vector axesNames; std::vector axesValues; while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("Parallel Border Axes"); if (paramName == "-separation-axis") { axesNames.push_back(parameters->getNextParameterAsString("AXIS-NAME")); axesValues.push_back(parameters->getNextParameterAsFloat("AXIS-VALUE")); } else { throw CommandException("Unrecognized option: " + paramName); } } // // Check input data // const int numAxes = static_cast(axesNames.size()); if (numAxes <= 0) { throw CommandException("No axes were specified."); } // // Create a brain set // BrainSet brainSet(topoFileName, coordFileName, "", true); BrainModelSurface* bms = brainSet.getBrainModelSurface(0); if (bms == NULL) { throw CommandException("unable to find surface."); } const TopologyFile* tf = bms->getTopologyFile(); if (tf == NULL) { throw CommandException("unable to find topology."); } const int numNodes = bms->getNumberOfNodes(); if (numNodes == 0) { throw CommandException("surface contains not nodes."); } // // Process the offsets // float offset[3] = { 0.0, 0.0, 0.0 }; for (int i = 0; i < numAxes; i++) { const QString separationAxisName = axesNames[i]; const float separationValue = axesValues[i]; if (separationAxisName == "X") { offset[0] += separationValue; } else if (separationAxisName == "Y") { offset[1] += separationValue; } else if (separationAxisName == "Z") { offset[2] += separationValue; } else if (separationAxisName == "LATERAL") { if (bms->getStructure().getType() == Structure::STRUCTURE_TYPE_CORTEX_LEFT) { offset[0] -= separationValue; } else if (bms->getStructure().getType() == Structure::STRUCTURE_TYPE_CORTEX_RIGHT) { offset[0] += separationValue; } else { throw CommandException("Structure is neither right nor left for for " "lateral offset."); } } else if (separationAxisName == "MEDIAL") { if (bms->getStructure().getType() == Structure::STRUCTURE_TYPE_CORTEX_LEFT) { offset[0] += separationValue; } else if (bms->getStructure().getType() == Structure::STRUCTURE_TYPE_CORTEX_RIGHT) { offset[0] -= separationValue; } else { throw CommandException("Structure is neither right nor left for for " "lateral offset."); } } else { throw CommandException("Separation Axis \"" + separationAxisName + "\" is invalid."); } } // // Read the input border projection file // BorderProjectionFile borderProjectionFile; borderProjectionFile.readFile(inputBorderProjectionFileName); // // Find the input border // BorderProjection* borderProjection = borderProjectionFile.getLastBorderProjectionByName(inputBorderName); if (borderProjection == NULL) { throw CommandException("Unable to find border projection named \"" + inputBorderName +"\""); } // // Place the border projection in a temporary file // BorderProjectionFile tempBorderProjectionFile; tempBorderProjectionFile.addBorderProjection(*borderProjection); // // Unproject the border // BorderProjectionUnprojector unprojector; BorderFile tempBorderFile; unprojector.unprojectBorderProjections(*(bms->getCoordinateFile()), tempBorderProjectionFile, tempBorderFile); // // Get border // if (tempBorderFile.getNumberOfBorders() <= 0) { throw CommandException("unprojection error."); } // // Get the border // Border* border = tempBorderFile.getBorder(0); // // Make the parallel border // border->setName(outputBorderName); for (int i = 0; i < border->getNumberOfLinks(); i++) { float xyz[3]; border->getLinkXYZ(i, xyz); xyz[0] += offset[0]; xyz[1] += offset[1]; xyz[2] += offset[2]; border->setLinkXYZ(i, xyz); } // Reproject the border // tempBorderProjectionFile.clear(); BorderFileProjector projector(bms, true); projector.projectBorderFile(&tempBorderFile, &tempBorderProjectionFile, NULL); // // Add border projection to output file // if (tempBorderProjectionFile.getNumberOfBorderProjections() <= 0) { throw CommandException("reprojection error."); } borderProjectionFile.addBorderProjection( *tempBorderProjectionFile.getBorderProjection(0)); // // Write the output file // borderProjectionFile.writeFile(outputBorderProjectionFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderCreateAverage.h0000664000175000017500000000354411572067322030443 0ustar michaelmichael #ifndef __COMMAND_SURFACE_BORDER_CREATE_AVERAGE_H__ #define __COMMAND_SURFACE_BORDER_CREATE_AVERAGE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for creating an average border file class CommandSurfaceBorderCreateAverage : public CommandBase { public: // constructor CommandSurfaceBorderCreateAverage(); // destructor ~CommandSurfaceBorderCreateAverage(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_BORDER_CREATE_AVERAGE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBorderCreateAverage.cxx0000664000175000017500000001150611572067322031013 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BorderFile.h" #include "CommandSurfaceBorderCreateAverage.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandSurfaceBorderCreateAverage::CommandSurfaceBorderCreateAverage() : CommandBase("-surface-border-create-average", "SURFACE BORDER CREATE AVERAGE") { } /** * destructor. */ CommandSurfaceBorderCreateAverage::~CommandSurfaceBorderCreateAverage() { } /** * get the script builder parameters. */ void CommandSurfaceBorderCreateAverage::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFloat("Resampling Distance", 10.0); paramsOut.addBoolean("Project to Sphere", false); paramsOut.addFile("Output Border File Name", FileFilters::getBorderGenericFileFilter()); paramsOut.addMultipleFiles("Input Border Files", FileFilters::getBorderGenericFileFilter()); } /** * get full help information. */ QString CommandSurfaceBorderCreateAverage::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[additional-input-border-files]\n" + indent9 + "\n" + indent9 + "Create an average border file from two or more border files.\n" + indent9 + "\n" + indent9 + " is one of:\n" + indent9 + " true\n" + indent9 + " false\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceBorderCreateAverage::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get parameters // const float resamplingDistance = parameters->getNextParameterAsFloat("Resampling Distance"); const bool projectToSphereFlag = parameters->getNextParameterAsBoolean("Project to Sphere"); const QString outputBorderFileName = parameters->getNextParameterAsString("Output Border File Name"); std::vector inputBorderFileNames; inputBorderFileNames.push_back( parameters->getNextParameterAsString("Input Border File Name 1")); inputBorderFileNames.push_back( parameters->getNextParameterAsString("Input Border File Name 2")); while (parameters->getParametersAvailable()) { inputBorderFileNames.push_back( parameters->getNextParameterAsString("Input Border File Name")); } // // Read the input border files // const int numBorderFiles = static_cast(inputBorderFileNames.size()); std::vector inputBorderFiles; for (int i = 0; i < numBorderFiles; i++) { BorderFile* bf = new BorderFile; try { bf->readFile(inputBorderFileNames[i]); inputBorderFiles.push_back(bf); } catch (FileException& e) { for (unsigned int j = 0; j < inputBorderFiles.size(); j++) { delete inputBorderFiles[j]; } throw e; } } // // Create the average border // BorderFile averageBorderFile; BorderFile::createAverageBorderFile(inputBorderFiles, resamplingDistance, projectToSphereFlag, averageBorderFile); // // Save output border file // averageBorderFile.writeFile(outputBorderFileName); // // Free memory // for (unsigned int j = 0; j < inputBorderFiles.size(); j++) { delete inputBorderFiles[j]; } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBankStraddling.h0000664000175000017500000000343211572067322027472 0ustar michaelmichael #ifndef __COMMAND_SURFACE_BANK_STRADDLING_H__ #define __COMMAND_SURFACE_BANK_STRADDLING_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandSurfaceBankStraddling : public CommandBase { public: // constructor CommandSurfaceBankStraddling(); // destructor ~CommandSurfaceBankStraddling(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_METRIC_EXTREMA_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceBankStraddling.cxx0000664000175000017500000001343711572067322030053 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "CommandSurfaceBankStraddling.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "BrainModelSurfaceBankStraddling.h" #include "BrainSet.h" #include "StringUtilities.h" #include "FileUtilities.h" #include "MetricFile.h" #include "VectorFile.h" #include "CoordinateFile.h" #include "TopologyFile.h" /** * constructor. */ CommandSurfaceBankStraddling::CommandSurfaceBankStraddling() : CommandBase("-surface-bank-straddling", "VOLUME TO SURFACE MAPPING DANGER POINTS") { } /** * destructor. */ CommandSurfaceBankStraddling::~CommandSurfaceBankStraddling() { } /** * get the script builder parameters. */ void CommandSurfaceBankStraddling::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Coordinate File", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Input Topology File", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Output Metric File", FileFilters::getMetricFileFilter()); paramsOut.addInt("Output Metric Column Number", 0, 0); paramsOut.addFloat("Volume Voxel Spacing (x)", 1.0f, 0.0f); paramsOut.addFloat("Volume Voxel Spacing (y)", 1.0f, 0.0f); paramsOut.addFloat("Volume Voxel Spacing (z)", 1.0f, 0.0f); paramsOut.addBoolean("Interpolation"); } /** * get full help information. */ QString CommandSurfaceBankStraddling::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Find areas of a surface prone to high correlation when mapping from\n" + indent9 + "volumes of a given voxel size. Output is pessimistic, with value\n" + indent9 + "equal to maximum possible artificial correlation times geodesic\n" + indent9 + "distance. This is computed for all nodes that can share information\n" + indent9 + "with the considered voxel, and the maximum of these values is used.\n" + indent9 + "Interpolated specifies whether mapping uses interpolation. Trilinear\n" + indent9 + "interpolation is assumed. If output metric exists, output is put into\n" + indent9 + "the specified column if possible, otherwise appended if possible, and\n" + indent9 + "if node numbers do not match, the existing metric file is overwritten.\n" + indent9 + "\n" + indent9 + " surface-coord the surface coord file\n" + indent9 + "\n" + indent9 + " surface-topo the surface topo file\n" + indent9 + "\n" + indent9 + " output-metric output metric file for min/max identification\n" + indent9 + "\n" + indent9 + " out-metric-col which column to put the output into\n" + indent9 + "\n" + indent9 + " *-spacing the dimensions of the voxels for the mapping volume\n" + indent9 + "\n" + indent9 + " interpolated TRUE or FALSE, specifies whether to assume interpolated\n" + indent9 + " mapping. FALSE implies enclosing (nearest) voxel mapping.\n" + indent9 + "\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceBankStraddling::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString coord = parameters->getNextParameterAsString("Input Coordinate File"); const QString topo = parameters->getNextParameterAsString("Input Topology File"); const QString metric = parameters->getNextParameterAsString("Output Metric File"); int metricCol = parameters->getNextParameterAsInt("Output Metric Column Number"); float voxdim[3]; voxdim[0] = parameters->getNextParameterAsFloat("Voxel X Dimension"); voxdim[1] = parameters->getNextParameterAsFloat("Voxel Y Dimension"); voxdim[2] = parameters->getNextParameterAsFloat("Voxel Z Dimension"); bool interp = parameters->getNextParameterAsBoolean("Interpolated Mapping"); BrainSet mybs(topo, coord); MetricFile mymetric; try { mymetric.readFile(metric); } catch (FileException e) {} BrainModelSurfaceBankStraddling myobject(&mybs, 0, &mymetric, metricCol - 1, voxdim, interp); myobject.execute(); mymetric.writeFile(metric); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceAverage.h0000664000175000017500000000342211572067322026154 0ustar michaelmichael #ifndef __COMMAND_SURFACE_AVERAGE_H__ #define __COMMAND_SURFACE_AVERAGE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for creating an average surface class CommandSurfaceAverage : public CommandBase { public: // constructor CommandSurfaceAverage(); // destructor ~CommandSurfaceAverage(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_AVERAGE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceAverage.cxx0000664000175000017500000001177711572067322026543 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandSurfaceAverage.h" #include "CoordinateFile.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SurfaceShapeFile.h" /** * constructor. */ CommandSurfaceAverage::CommandSurfaceAverage() : CommandBase("-surface-average", "SURFACE CREATE AVERAGE") { } /** * destructor. */ CommandSurfaceAverage::~CommandSurfaceAverage() { } /** * get the script builder parameters. */ void CommandSurfaceAverage::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Output Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addMultipleFiles("Input Coordinate File Name(s)", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addVariableListOfParameters("Coordinate Options"); } /** * get full help information. */ QString CommandSurfaceAverage::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[input-coordinate-file-2-name]\n" + indent9 + "...\n" + indent9 + "[input-coordinate-file-N-name]\n" + indent9 + "[output-surface-shape-file-name]\n" + indent9 + "\n" + indent9 + "Create an average surface.\n" + indent9 + "\n" + indent9 + "If a surface shape file name is specified, it will be created\n" + indent9 + "and contain the coordinate uncertainty. The surface shape file\n" + indent9 + "name must end with \"" + SpecFile::getSurfaceShapeFileExtension() + "\".\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceAverage::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the pamameters // const QString outputCoordinateFileName = parameters->getNextParameterAsString("Output Coordinate File Name"); std::vector inputCoordinateFileNames; QString surfaceShapeFileName; while (parameters->getParametersAvailable()) { const QString name = parameters->getNextParameterAsString("Optional File Name"); if (name.endsWith(SpecFile::getSurfaceShapeFileExtension())) { surfaceShapeFileName = name; } else { inputCoordinateFileNames.push_back(name); } } const int numCoordFiles = static_cast(inputCoordinateFileNames.size()); if (numCoordFiles < 1) { throw CommandException("There must be at least one input coordinate file."); } // // Read the input coordinate files // std::vector coordinateFiles; for (int i = 0; i < static_cast(inputCoordinateFileNames.size()); i++) { CoordinateFile* coordFile = new CoordinateFile; coordFile->readFile(inputCoordinateFileNames[i]); coordinateFiles.push_back(coordFile); } // // Should a surface shape file containing uncertainty be created? // SurfaceShapeFile* ssf = NULL; if (surfaceShapeFileName.isEmpty() == false) { ssf = new SurfaceShapeFile; } // // Create the average coordinate file // CoordinateFile outputCoordinateFile; CoordinateFile::createAverageCoordinateFile(coordinateFiles, outputCoordinateFile, ssf); // // Write the coordinate file // outputCoordinateFile.writeFile(outputCoordinateFileName); // // Write surface shape file if it was created // if (ssf != NULL) { ssf->writeFile(surfaceShapeFileName); } // // Free memory // for (unsigned int i = 0; i < coordinateFiles.size(); i++) { delete coordinateFiles[i]; } if (ssf != NULL) { delete ssf; } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceApplyTransformationMatrix.h0000664000175000017500000000362611572067322032011 0ustar michaelmichael #ifndef __COMMAND_SURFACE_APPLY_TRANSFORMATION_MATRIX_H__ #define __COMMAND_SURFACE_APPLY_TRANSFORMATION_MATRIX_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for applying a transformation matrix to a surface class CommandSurfaceApplyTransformationMatrix : public CommandBase { public: // constructor CommandSurfaceApplyTransformationMatrix(); // destructor ~CommandSurfaceApplyTransformationMatrix(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_APPLY_TRANSFORMATION_MATRIX_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceApplyTransformationMatrix.cxx0000664000175000017500000001507511572067322032365 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurface.h" #include "BrainSet.h" #include "CommandSurfaceApplyTransformationMatrix.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "TransformationMatrixFile.h" /** * constructor. */ CommandSurfaceApplyTransformationMatrix::CommandSurfaceApplyTransformationMatrix() : CommandBase("-surface-apply-transformation-matrix", "SURFACE APPLY TRANSFORMATION MATRIX") { } /** * destructor. */ CommandSurfaceApplyTransformationMatrix::~CommandSurfaceApplyTransformationMatrix() { } /** * get the script builder parameters. */ void CommandSurfaceApplyTransformationMatrix::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Output Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addVariableListOfParameters("Matrix Options"); } /** * get full help information. */ QString CommandSurfaceApplyTransformationMatrix::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-matrix-file matrix-file-name matrix-name]\n" + indent9 + "[-matrix matrix-values-left-to-right-and-top-to-bottom]\n" + indent9 + "\n" + indent9 + "Apply a transformation matrix to a surface.\n" + indent9 + "\n" + indent9 + "The matrix may be within a specified file or the matrix\n" + indent9 + "may be specified on the command line.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceApplyTransformationMatrix::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the parameters // const QString inputCoordinateFileName = parameters->getNextParameterAsString("Input Coordinate File Name"); const QString inputTopologyFileName = parameters->getNextParameterAsString("Input Topology File Name"); const QString outputCoordinateFileName = parameters->getNextParameterAsString("Output Coordinate File Name"); // // Get optional parameters // enum MATRIX_SOURCE { MATRIX_SOURCE_NONE, MATRIX_SOURCE_FROM_FILE, MATRIX_SOURCE_VALUES }; MATRIX_SOURCE matrixSource = MATRIX_SOURCE_NONE; QString matrixFileName; QString matrixName; float matrixValues[4][4]; while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("Apply Transform Parameter"); if (paramName == "-matrix-file") { matrixFileName = parameters->getNextParameterAsString("Matrix File Name"); matrixName = parameters->getNextParameterAsString("Matrix Name"); matrixSource = MATRIX_SOURCE_FROM_FILE; } else if (paramName == "-matrix") { int counter = 1; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { const QString text("Matrix value " + QString::number(counter)); matrixValues[i][j] = parameters->getNextParameterAsFloat(text); } counter++; } matrixSource = MATRIX_SOURCE_VALUES; } else { throw CommandException("unrecognized parameter: " + paramName); } } // // Did user forget to supply a matrix // if (matrixSource == MATRIX_SOURCE_NONE) { throw CommandException("A matrix must be supplied " "with either \"-matrix-file\" or \"-matrix\"."); } // // Create a brain set // BrainSet brainSet(inputTopologyFileName, inputCoordinateFileName, "", true); BrainModelSurface* surface = brainSet.getBrainModelSurface(0); if (surface == NULL) { throw CommandException("unable to find fiducial surface."); } const TopologyFile* tf = surface->getTopologyFile(); if (tf == NULL) { throw CommandException("unable to find topology."); } const int numNodes = surface->getNumberOfNodes(); if (numNodes == 0) { throw CommandException("surface contains no nodes."); } // // Apply the transformation matrix // switch (matrixSource) { case MATRIX_SOURCE_NONE: break; case MATRIX_SOURCE_FROM_FILE: { TransformationMatrixFile tmf; tmf.readFile(matrixFileName); TransformationMatrix* matrix = tmf.getTransformationMatrixWithName(matrixName); if (matrix == NULL) { throw CommandException("matrix file does not contain a matrix with that name."); } surface->applyTransformationMatrix(*matrix); } break; case MATRIX_SOURCE_VALUES: { TransformationMatrix matrix; matrix.setMatrix(matrixValues); surface->applyTransformationMatrix(matrix); } break; } // // Write the coordinate file // CoordinateFile* cf = surface->getCoordinateFile(); cf->writeFile(outputCoordinateFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceAlignToStandardOrientation.h0000664000175000017500000000363311572067322032040 0ustar michaelmichael #ifndef __COMMAND_SURFACE_ALIGN_TO_STANDARD_ORIENTATION_H__ #define __COMMAND_SURFACE_ALIGN_TO_STANDARD_ORIENTATION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for surface alignment to standard orientation class CommandSurfaceAlignToStandardOrientation : public CommandBase { public: // constructor CommandSurfaceAlignToStandardOrientation(); // destructor ~CommandSurfaceAlignToStandardOrientation(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SURFACE_ALIGN_TO_STANDARD_ORIENTATION_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceAlignToStandardOrientation.cxx0000664000175000017500000002017111572067322032407 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BorderProjectionFile.h" #include "BrainModelSurface.h" #include "BrainSet.h" #include "CommandSurfaceAlignToStandardOrientation.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandSurfaceAlignToStandardOrientation::CommandSurfaceAlignToStandardOrientation() : CommandBase("-surface-align-to-standard-orientation", "SURFACE ALIGN TO STANDARD ORIENTATION") { } /** * destructor. */ CommandSurfaceAlignToStandardOrientation::~CommandSurfaceAlignToStandardOrientation() { } /** * get the script builder parameters. */ void CommandSurfaceAlignToStandardOrientation::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Fiducial Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Input Sphere or Flat Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Output Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Border Projection File Name", FileFilters::getBorderProjectionFileFilter()); paramsOut.addString("Central Sulcus Border Name", "LANDMARK.CentralSulcus"); } /** * get full help information. */ QString CommandSurfaceAlignToStandardOrientation::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + "\n" + indent9 + "Align a surface to standard orienation.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceAlignToStandardOrientation::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputFiducialCoordinateFileName = parameters->getNextParameterAsString("Input Fiducial Coordinate File Name"); const QString inputSphereOrFlatCoordinateFileName = parameters->getNextParameterAsString("Input Sphere or Flat Coordinate File Name"); const QString outputCoordinateFileName = parameters->getNextParameterAsString("Output Coordinate File Name"); const QString topologyFileName = parameters->getNextParameterAsString("Topology File Name"); const QString borderProjectionFileName = parameters->getNextParameterAsString("Border Projection File Name"); const QString centralSulcusBorderName = parameters->getNextParameterAsString("Central Sulcus Border Name"); checkForExcessiveParameters(); // // Create a brain set // BrainSet brainSet(topologyFileName, inputFiducialCoordinateFileName, inputSphereOrFlatCoordinateFileName, true); BrainModelSurface* fiducialBMS = brainSet.getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_FIDUCIAL); if (fiducialBMS == NULL) { throw CommandException("unable to find fiducial surface."); } BrainModelSurface* bms = brainSet.getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_SPHERICAL); if (bms == NULL) { bms = brainSet.getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_FLAT); } if (bms == NULL) { bms = brainSet.getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR); } if (bms == NULL) { throw CommandException("unable to find spherical or flat surface."); } const TopologyFile* tf = bms->getTopologyFile(); if (tf == NULL) { throw CommandException("unable to find topology."); } const int numNodes = bms->getNumberOfNodes(); if (numNodes == 0) { throw CommandException("surface contains not nodes."); } // // Check surface type // switch (bms->getSurfaceType()) { case BrainModelSurface::SURFACE_TYPE_SPHERICAL: case BrainModelSurface::SURFACE_TYPE_FLAT: case BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR: break; case BrainModelSurface::SURFACE_TYPE_RAW: case BrainModelSurface::SURFACE_TYPE_FIDUCIAL: case BrainModelSurface::SURFACE_TYPE_INFLATED: case BrainModelSurface::SURFACE_TYPE_VERY_INFLATED: case BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL: case BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL: case BrainModelSurface::SURFACE_TYPE_HULL: case BrainModelSurface::SURFACE_TYPE_UNKNOWN: case BrainModelSurface::SURFACE_TYPE_UNSPECIFIED: throw CommandException("The surface type must be flat or spherical but is \"" + bms->getSurfaceTypeName() + "\""); break; } // // Check structure // switch (bms->getStructure().getType()) { case Structure::STRUCTURE_TYPE_CORTEX_LEFT: case Structure::STRUCTURE_TYPE_CORTEX_RIGHT: break; case Structure::STRUCTURE_TYPE_CORTEX_BOTH: case Structure::STRUCTURE_TYPE_CEREBELLUM: case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_LEFT: case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_RIGHT: case Structure::STRUCTURE_TYPE_CORTEX_LEFT_OR_CEREBELLUM: case Structure::STRUCTURE_TYPE_CORTEX_RIGHT_OR_CEREBELLUM: case Structure::STRUCTURE_TYPE_CEREBRUM_CEREBELLUM: case Structure::STRUCTURE_TYPE_SUBCORTICAL: case Structure::STRUCTURE_TYPE_ALL: case Structure::STRUCTURE_TYPE_INVALID: throw CommandException("Structure must be left or right but is \"" + bms->getStructure().getTypeAsString() + "\""); break; } // // Get the border // BorderProjectionFile borderProjectionFile; borderProjectionFile.readFile(borderProjectionFileName); const BorderProjection* centralSulcusBorderProjection = borderProjectionFile.getFirstBorderProjectionByName(centralSulcusBorderName); if (centralSulcusBorderProjection == NULL) { throw CommandException("No border projection named \"" + centralSulcusBorderName + "\" was found in the border projection file."); } // // Align the surface // bms->alignToStandardOrientation(fiducialBMS, centralSulcusBorderProjection, false, true); // // Write the coordinate file // bms->getCoordinateFile()->writeFile(outputCoordinateFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceAffineRegression.h0000664000175000017500000000346011572067322030035 0ustar michaelmichael #ifndef __COMMAND_SURFACE_AFFINE_REGRESSION_H__ #define __COMMAND_SURFACE_AFFINE_REGRESSION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandSurfaceAffineRegression : public CommandBase { public: // constructor CommandSurfaceAffineRegression(); // destructor ~CommandSurfaceAffineRegression(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_VOLUME_SEGMENTATION_LIGASE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSurfaceAffineRegression.cxx0000664000175000017500000001530211572067322030406 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "CommandSurfaceAffineRegression.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "BrainModelSurfaceAffineRegression.h" #include "BrainSet.h" #include "StringUtilities.h" #include "FileUtilities.h" /** * constructor. */ CommandSurfaceAffineRegression::CommandSurfaceAffineRegression() : CommandBase("-surface-affine-regression", "SURFACE TO SURFACE LINEAR REGRESSION AFFINE REGISTRATION") { } /** * destructor. */ CommandSurfaceAffineRegression::~CommandSurfaceAffineRegression() { } /** * get the script builder parameters. */ void CommandSurfaceAffineRegression::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Target Coordinate File", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Input Source Coordinate File", FileFilters::getCoordinateGenericFileFilter()); } /** * get full help information. */ QString CommandSurfaceAffineRegression::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[...]\n" + indent9 + "\n" + indent9 + "Use linear regression to compute and execute an affine transormation,\n" + indent9 + "attempting to minimize the variability from source to target.\n" + indent9 + "File names will be automatically generated by adding \".afftrans.\"\n" + indent9 + "as the third section of the filename, eg, \"test.case5.73730.coord\"\n" + indent9 + "will be output as \"test.case5.afftrans.73730.coord\", in the same\n" + indent9 + "directory.\n" + indent9 + "\n" + indent9 + " target-coord the target to minimize the variability to\n" + indent9 + "\n" + indent9 + " source-coord-1 a source coordinate file to transform\n" + indent9 + "\n" + indent9 + " [source-coord-2...] same as above, but optional. You may\n" + indent9 + " specify as many sources as you wish.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSurfaceAffineRegression::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString target = parameters->getNextParameterAsString("Target Coordinate File"); BrainSet brainSet; CoordinateFile targetCoord, sourceCoord, outCoord; targetCoord.readFile(target); QString source, out, sourceFile, sourcePath, outMat; int i = 1, index; BrainModelSurfaceAffineRegression* affineObject; while (parameters->getParametersAvailable()) { try { source = parameters->getNextParameterAsString("Source Coordinate File " + StringUtilities::fromNumber(i)); sourceFile = FileUtilities::basename(source); sourcePath = FileUtilities::dirname(source); // // Add .afftrans. as 2nd field before extension // index = sourceFile.lastIndexOf('.'); index = sourceFile.lastIndexOf('.', index - 1) + 1; if (index == -1) { index = 0; } outMat = source + ".mat"; out = sourceFile; out.insert(index, "afftrans."); if (sourcePath.right(1) == FileUtilities::directorySeparator() || sourcePath == "") { out = sourcePath + out; } else { out = sourcePath + FileUtilities::directorySeparator() + out; } sourceCoord.readFile(source); outCoord = sourceCoord; // // Create the affine object // affineObject = new BrainModelSurfaceAffineRegression(&brainSet, &sourceCoord, &targetCoord, &outCoord, out); // // Execute regression // affineObject->execute(); outCoord.writeFile(out); QFile affineFile(outMat); if (!affineFile.open(QIODevice::WriteOnly)) { std::cerr << "Error opening output file \"" << outMat.toAscii().constData() << '"' << std::endl; } else { for (short j = 0; j < 3; ++j) { for (short k = 0; k < 4; ++k, affineFile.write(" ", 2)) { affineFile.write(StringUtilities::fromNumber(affineObject->getAffine(j, k)).toAscii()); } affineFile.write("\n", 1); //affineFile.write(StringUtilities::fromStdString(std::endl).toAscii()); } affineFile.write("0 0 0 1 \n", 13); affineFile.close(); //affineFile.write(StringUtilities::fromStdString(std::endl).toAscii()); const QString warningMessages = affineObject->getWarningMessages(); if (warningMessages.isEmpty() == false) { std::cout << "Transformation Warnings: " << warningMessages.toAscii().constData() << std::endl; } } ++i; delete affineObject; } catch(FileException e) { std::cerr << e.whatQString().toAscii().constData() << std::endl; } catch(BrainModelAlgorithmException e) { std::cerr << e.whatQString().toAscii().constData() << std::endl; } } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandStudyMetaDataFileValidate.h0000664000175000017500000000353711572067322030263 0ustar michaelmichael #ifndef __COMMAND_STUDY_METADATA_FILE_VALIDATE_H__ #define __COMMAND_STUDY_METADATA_FILE_VALIDATE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for validating a study metadata file class CommandStudyMetaDataFileValidate : public CommandBase { public: // constructor CommandStudyMetaDataFileValidate(); // destructor ~CommandStudyMetaDataFileValidate(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_STUDY_METADATA_FILE_VALIDATE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandStudyMetaDataFileValidate.cxx0000664000175000017500000001010711572067322030625 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "CommandStudyMetaDataFileValidate.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "StudyMetaDataFile.h" #include "TextFile.h" /** * constructor. */ CommandStudyMetaDataFileValidate::CommandStudyMetaDataFileValidate() : CommandBase("-study-metadata-file-validate", "STUDY METADATA FILE VALIDATION") { } /** * destructor. */ CommandStudyMetaDataFileValidate::~CommandStudyMetaDataFileValidate() { } /** * get the script builder parameters. */ void CommandStudyMetaDataFileValidate::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Study Metadata File", FileFilters::getStudyMetaDataFileFilter()); paramsOut.addVariableListOfParameters("Output Text File Name"); } /** * get full help information. */ QString CommandStudyMetaDataFileValidate::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "[-output output-text-file]\n" + indent9 + "\n" + indent9 + "Validate a study metadata file by searching for missing \n" + indent9 + "or duplicate PubMed ID's or Study Names, missing figure \n" + indent9 + "numbers, figure panel numbers, page reference numbers, \n" + indent9 + "page reference subheader numbers or short names, table\n" + indent9 + "numbers, and table subheader numbers or short names.\n" + indent9 + "\n" + indent9 + "If there are any errors, they are written to the output\n" + indent9 + "text file if it is provided. Otherwise, results are \n" + indent9 + "written to the terminal.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandStudyMetaDataFileValidate::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString studyFileName = parameters->getNextParameterAsString("Input Study Metadata File"); QString textFileName; while (parameters->getParametersAvailable()) { QString paramName = parameters->getNextParameterAsString("Opt Param"); if (paramName == "-output") { textFileName = parameters->getNextParameterAsString("Text File Name"); } else { throw CommandException("Unexpected Parameter: " + paramName); } } StudyMetaDataFile smdf; smdf.readFile(studyFileName); QStringList sl = smdf.validStudyMetaDataFile(); if (sl.count() <= 0) { std::cout << "No study problems were found." << std::endl; } else { const QString msg(sl.join("\n")); if (textFileName.isEmpty() == false) { TextFile tf; tf.setText(msg); tf.writeFile(textFileName); } else { std::cout << msg.toAscii().constData() << std::endl; } } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandStudyMetaDataFileDuplicates.h0000664000175000017500000000351511572067322030623 0ustar michaelmichael #ifndef __COMMAND_STUDY_META_DATA_FILE_DUPLICATES_H__ #define __COMMAND_STUDY_META_DATA_FILE_DUPLICATES_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandStudyMetaDataFileDuplicates : public CommandBase { public: // constructor CommandStudyMetaDataFileDuplicates(); // destructor ~CommandStudyMetaDataFileDuplicates(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_STUDY_META_DATA_FILE_DUPLICATES_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandStudyMetaDataFileDuplicates.cxx0000664000175000017500000000665111572067322031202 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "CommandStudyMetaDataFileDuplicates.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "StudyMetaDataFile.h" /** * constructor. */ CommandStudyMetaDataFileDuplicates::CommandStudyMetaDataFileDuplicates() : CommandBase("-study-metadata-duplicates", "STUDY METADATA DUPLICATES") { } /** * destructor. */ CommandStudyMetaDataFileDuplicates::~CommandStudyMetaDataFileDuplicates() { } /** * get the script builder parameters. */ void CommandStudyMetaDataFileDuplicates::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addVariableListOfParameters("Study Metadata File Name(s)"); } /** * get full help information. */ QString CommandStudyMetaDataFileDuplicates::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Find duplicate studies (studies with the same PubMedID) in\n" + indent9 + "the provided Study Metadata Files.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandStudyMetaDataFileDuplicates::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the inputs // std::vector fileNames; while (parameters->getParametersAvailable()) { fileNames.push_back(parameters->getNextParameterAsString("Study Metadata File Name")); } // // Find the duplicates // std::multimap duplicatesStudies; StudyMetaDataFile::findDuplicateStudies(fileNames, duplicatesStudies); // // Process results // if (duplicatesStudies.empty()) { std::cout << "No duplicate studies found." << std::endl; } else { std::cout << "Duplicate PubMed IDs and File Names" << std::endl; for (std::multimap::iterator iter = duplicatesStudies.begin(); iter != duplicatesStudies.end(); iter++) { std::cout << iter->first.toAscii().constData() << " " << iter->second.toAscii().constData() << std::endl; } } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandStereotaxicSpaces.h0000664000175000017500000000356611572067322026733 0ustar michaelmichael #ifndef __COMMAND_STEREOTAXIC_SPACES_H__ #define __COMMAND_STEREOTAXIC_SPACES_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandStereotaxicSpaces : public CommandBase { public: // constructor CommandStereotaxicSpaces(); // destructor ~CommandStereotaxicSpaces(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; /// command has no parameters virtual bool commandHasNoParameters() const { return true; } protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_STEREOTAXIC_SPACES_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandStereotaxicSpaces.cxx0000664000175000017500000001274611572067322027306 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "CommandStereotaxicSpaces.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "StereotaxicSpace.h" /** * constructor. */ CommandStereotaxicSpaces::CommandStereotaxicSpaces() : CommandBase("-stereotaxic-spaces", "STEREOTAXIC SPACE INFORMATION") { } /** * destructor. */ CommandStereotaxicSpaces::~CommandStereotaxicSpaces() { } /** * get the script builder parameters. */ void CommandStereotaxicSpaces::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); } /** * get full help information. */ QString CommandStereotaxicSpaces::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "List information about stereotaxic spaces.\n" + indent9 + "\n" + indent9 + "This information listed is for an LPI orientation \n" + indent9 + "LPI means:\n" + indent9 + " negative-X => LEFT\n" + indent9 + " negative-Y => POSTERIOR\n" + indent9 + " negative-Z => INFERIOR\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandStereotaxicSpaces::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { std::vector spaces; StereotaxicSpace::getAllStereotaxicSpaces(spaces); QString nameTitle = "NAME"; int nameLength = nameTitle.length(); QString dimTitle = "DIMENSIONS"; int dimLength = dimTitle.length(); QString originTitle = "ORIGIN"; int originLength = originTitle.length(); QString voxelSizeTitle = "VOXEL-SIZE"; int voxelSizeLength = voxelSizeTitle.length(); std::vector nameStrings, dimStrings, originStrings, voxelSizeStrings; for (unsigned int i = 0; i < spaces.size(); i++) { const StereotaxicSpace& ss = spaces[i]; if ((ss.getSpace() == StereotaxicSpace::SPACE_UNKNOWN) || (ss.getSpace() == StereotaxicSpace::SPACE_OTHER)) { continue; } QString name = ss.getName(); nameLength = std::max(nameLength, name.length()); nameStrings.push_back(name); int dim[3]; ss.getDimensions(dim); QString dimString = (QString::number(dim[0]) + "x" + QString::number(dim[1]) + "x" + QString::number(dim[2])); dimLength = std::max(dimLength, dimString.length()); dimStrings.push_back(dimString); float origin[3]; ss.getOrigin(origin); QString originString = (QString::number(origin[0], 'f', 1) + "x" + QString::number(origin[1], 'f', 1) + "x" + QString::number(origin[2], 'f', 1)); originLength = std::max(originLength, originString.length()); originStrings.push_back(originString); float voxelSizes[3]; ss.getVoxelSize(voxelSizes); QString voxelSizeString = (QString::number(voxelSizes[0], 'f', 1) + "x" + QString::number(voxelSizes[1], 'f', 1) + "x" + QString::number(voxelSizes[2], 'f', 1)); voxelSizeLength = std::max(voxelSizeLength, voxelSizeString.length()); voxelSizeStrings.push_back(voxelSizeString); } const int spacing = 5; nameLength += spacing; dimLength += spacing; originLength += spacing; voxelSizeLength += spacing; const QString titleLine = (nameTitle.leftJustified(nameLength) + dimTitle.leftJustified(dimLength) + originTitle.leftJustified(originLength) + voxelSizeTitle.leftJustified(voxelSizeLength)); std::cout << titleLine.toAscii().constData() << std::endl; std::cout << QString(titleLine).replace(QRegExp("[A-Z]"), "-").toAscii().constData() << std::endl; for (unsigned int i = 0; i < nameStrings.size(); i++) { const QString dataLine = (nameStrings[i].leftJustified(nameLength) + dimStrings[i].leftJustified(dimLength) + originStrings[i].leftJustified(originLength) + voxelSizeStrings[i].leftJustified(voxelSizeLength)); std::cout << dataLine.toAscii().constData() << std::endl; } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandStatisticalUnitTesting.h0000664000175000017500000000350211572067322027752 0ustar michaelmichael #ifndef __COMMAND_STATISTICAL_UNIT_TESTING_H__ #define __COMMAND_STATISTICAL_UNIT_TESTING_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for statistical unit testing class CommandStatisticalUnitTesting : public CommandBase { public: // constructor CommandStatisticalUnitTesting(); // destructor ~CommandStatisticalUnitTesting(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_STATISTICAL_UNIT_TESTING_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandStatisticalUnitTesting.cxx0000664000175000017500000000523511572067322030332 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandStatisticalUnitTesting.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "StatisticUnitTesting.h" /** * constructor. */ CommandStatisticalUnitTesting::CommandStatisticalUnitTesting() : CommandBase("-statistic-unit-test", "STATISTICS UNIT TESTING") { } /** * destructor. */ CommandStatisticalUnitTesting::~CommandStatisticalUnitTesting() { } /** * get the script builder parameters. */ void CommandStatisticalUnitTesting::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addBoolean("Show Values", false); } /** * get full help information. */ QString CommandStatisticalUnitTesting::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Perform unit testing on statistical algorithm code.\n" + indent9 + "\n" + indent9 + "\"show-values-flag\" is either \"true\"or \"false\". If true,\n" + indent9 + "all results are displayed, else only errors are displayed.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandStatisticalUnitTesting::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const bool showValuesFlag = parameters->getNextParameterAsBoolean("Show Values Flag"); StatisticUnitTesting sut(showValuesFlag); sut.execute(); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandStatisticSetRandomSeed.h0000664000175000017500000000352511572067322027662 0ustar michaelmichael #ifndef __COMMAND_STATISTIC_SET_RANDOM_SEED_H__ #define __COMMAND_STATISTIC_SET_RANDOM_SEED_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for setting the random number generator seed class CommandStatisticSetRandomSeed : public CommandBase { public: // constructor CommandStatisticSetRandomSeed(); // destructor ~CommandStatisticSetRandomSeed(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_STATISTIC_SET_RANDOM_SEED_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandStatisticSetRandomSeed.cxx0000664000175000017500000000662311572067322030237 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainSet.h" #include "CommandStatisticSetRandomSeed.h" #include "FileFilters.h" #include "PreferencesFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandStatisticSetRandomSeed::CommandStatisticSetRandomSeed() : CommandBase("-statistic-set-random-seed", "STATISTICS SET RANDOM SEED") { } /** * destructor. */ CommandStatisticSetRandomSeed::~CommandStatisticSetRandomSeed() { } /** * get the script builder parameters. */ void CommandStatisticSetRandomSeed::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); } /** * get full help information. */ QString CommandStatisticSetRandomSeed::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " \n" + indent9 + "\n" + indent9 + "Set the seed for the random number generator.\n" + indent9 + "\n" + indent9 + "Set \"seed\" to a positive integer. Using the same seed \n" + indent9 + "results in the same sequence of random numbers being \n" + indent9 + "generated. \n" + indent9 + "\n" + indent9 + "This command sets the random seed that is stored in the \n" + indent9 + "user's Preferences File. The preferences file is read \n" + indent9 + "and the random seed is used each time a Caret program (the\n" + indent9 + "caret5 GUI or caret_command) is started.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandStatisticSetRandomSeed::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the parameters // const unsigned int seedValue = parameters->getNextParameterAsInt("Seed"); if (seedValue <= 1) { throw CommandException("Random seed must be greater than or equal to one."); } checkForExcessiveParameters(); // // Set the seed // BrainSet bs; PreferencesFile* pf = bs.getPreferencesFile(); pf->setRandomSeedOverride(true); pf->setRandomSeedOverrideValue(seedValue); try { pf->writeFile(pf->getFileName()); } catch (FileException& e) { throw CommandException(e.whatQString()); } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSpecFileZip.h0000664000175000017500000000337311572067322025453 0ustar michaelmichael #ifndef __COMMAND_SPEC_FILE_ZIP_H__ #define __COMMAND_SPEC_FILE_ZIP_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for zipping a spec file class CommandSpecFileZip : public CommandBase { public: // constructor CommandSpecFileZip(); // destructor ~CommandSpecFileZip(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SPEC_FILE_ZIP_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSpecFileZip.cxx0000664000175000017500000001030011572067322026012 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "CommandSpecFileZip.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SpecFileUtilities.h" /** * constructor. */ CommandSpecFileZip::CommandSpecFileZip() : CommandBase("-spec-file-zip", "SPEC FILE ZIP") { } /** * destructor. */ CommandSpecFileZip::~CommandSpecFileZip() { } /** * get the script builder parameters. */ void CommandSpecFileZip::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Output Zip File Name", FileFilters::getZipFileFilter()); paramsOut.addString("Unzip Directory Name"); paramsOut.addFile("Input Spec File Name", FileFilters::getSpecFileFilter()); } /** * get full help information. */ QString CommandSpecFileZip::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "The spec file \"spec-file-name\" and its data files are placed \n" + indent9 + "into the zip \"zip-file-name\". When unzipped by the user, the \n" + indent9 + "subdirectory \"unzip-dir-name\" will be created and contain the \n" + indent9 + "contents of the zip file. \n" + indent9 + " \n" + indent9 + "EXAMPLE \n" + indent9 + "Zip the spec file \"Human.spec\" and place into the zip file \n" + indent9 + "\"Human.zip\". When unzipped by the user, the subdirectory\n" + indent9 + "\"human_case_1\" will be created and contain the files from \n" + indent9 + "the zip file. \n" + indent9 + " \n" + indent9 + " " + getOperationSwitch() + " Human.zip human_case_1 Human.spec \n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSpecFileZip::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString zipFileName = parameters->getNextParameterAsString("Output Zip File Name"); const QString unzipDirectoryName = parameters->getNextParameterAsString("Unzip Directory Name"); const QString specFileName = parameters->getNextParameterAsString("Input Spec File Name"); // // Make sure the zip file does not exist // if (QFile::exists(zipFileName)) { throw CommandException("The zip file " + zipFileName + " already exists.\n" + " Delete the zip file and rerun program."); } // // Zip the spec file // QString errorMessage; const bool result = SpecFileUtilities::zipSpecFile(specFileName, zipFileName, unzipDirectoryName, errorMessage); if (result) { throw CommandException(errorMessage); } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSpecFileDirectoryClean.h0000664000175000017500000000405711572067322027620 0ustar michaelmichael #ifndef __COMMAND_SPEC_FILE_DIRECTORY_CLEAN_H__ #define __COMMAND_SPEC_FILE_DIRECTORY_CLEAN_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "CommandBase.h" /// class for class CommandSpecFileDirectoryClean : public CommandBase { public: // constructor CommandSpecFileDirectoryClean(); // destructor ~CommandSpecFileDirectoryClean(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); // see if file is in a spec file (special case for volume data files) bool seeIfFileIsInSpecFile(const std::set& dataFilesInSpecFile, const QString& name) const; }; #endif // __COMMAND_SPEC_FILE_DIRECTORY_CLEAN_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSpecFileDirectoryClean.cxx0000664000175000017500000002517711572067322030201 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "CommandSpecFileDirectoryClean.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SpecFile.h" /** * constructor. */ CommandSpecFileDirectoryClean::CommandSpecFileDirectoryClean() : CommandBase("-spec-file-directory-clean", "SPEC FILE DIRECTORY CLEAN") { } /** * destructor. */ CommandSpecFileDirectoryClean::~CommandSpecFileDirectoryClean() { } /** * get the script builder parameters. */ void CommandSpecFileDirectoryClean::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { std::vector operations; operations.push_back("DELETE"); operations.push_back("LIST"); operations.push_back("MOVE"); paramsOut.clear(); paramsOut.addListOfItems("Operation", operations, operations); paramsOut.addVariableListOfParameters("Options"); } /** * get full help information. */ QString CommandSpecFileDirectoryClean::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "< DELETE | LIST | MOVE > \n" + indent9 + "\n" + indent9 + "This command first identifies all of the spec files in the\n" + indent9 + "current directory. Next, all other files (that are not spec\n" + indent9 + "files) in the current directory are examined to see if the \n" + indent9 + "file is listed in any of the spec files. If a file is not\n" + indent9 + "listed in any of the spec files, one of the desired\n" + indent9 + "operations listed below is performed on the data file.\n" + indent9 + "\n" + indent9 + "OPERATIONS\n" + indent9 + " \"DELETE\" Any file not listed in a spec file is\n" + indent9 + " deleted.\n" + indent9 + " \"LIST\" The name of any file not listed in a spec\n" + indent9 + " file is printed.\n" + indent9 + " \"MOVE\" Any files not listed in the spec file are\n" + indent9 + " moved to the specified directory.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSpecFileDirectoryClean::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { enum OPERATION { OPERATION_NONE, OPERATION_DELETE, OPERATION_LIST, OPERATION_MOVE }; OPERATION operation = OPERATION_NONE; QString moveToDirectoryName; const QString operationString = parameters->getNextParameterAsString("Operation"); if (operationString == "DELETE") { operation = OPERATION_DELETE; } else if (operationString == "LIST") { operation = OPERATION_LIST; } else if (operationString == "MOVE") { operation = OPERATION_MOVE; moveToDirectoryName = parameters->getNextParameterAsString("Directory Name"); QFileInfo dirInfo(moveToDirectoryName); if (dirInfo.exists() == false) { throw CommandException("Directory named \"" + moveToDirectoryName + "\" does not exist."); } else if (dirInfo.isDir() == false) { throw CommandException("\"" +moveToDirectoryName + "\" is not a directory."); } } else { throw CommandException("Invalid operation \"" + operationString + "\""); } checkForExcessiveParameters(); // // Keep track of spec files non-spec files // std::vector specFileNames; std::vector dataFileNames; const QString specFileExtension(SpecFile::getSpecFileExtension()); // // Get all spec files and data files in the current directory // const QString directoryName(QDir::currentPath()); QDirIterator it(directoryName); while (it.hasNext()) { QFileInfo fi(it.next()); const QString name(fi.fileName()); if (fi.isFile() && (fi.isSymLink() == false)) { if (name.endsWith(specFileExtension)) { specFileNames.push_back(name); } else { dataFileNames.push_back(name); } } } // // Verify spec files exist // const int numSpecFiles = static_cast(specFileNames.size()); if (numSpecFiles <= 0) { std::cout << "There are no spec files in the directory named \"" << directoryName.toAscii().constData() << "\"" << std::endl; return; } // // Get all of the files listed in the spec files // std::set specFileDataFiles; for (int i = 0; i < numSpecFiles; i++) { // // Read the spec file // SpecFile sf; sf.readFile(specFileNames[i]); // // Get all files in the spec file // std::vector allFiles; sf.getAllDataFilesInSpecFile(allFiles, true); specFileDataFiles.insert(allFiles.begin(), allFiles.end()); } for (std::set::iterator iter = specFileDataFiles.begin(); iter != specFileDataFiles.end(); iter++) { const QString name(*iter); } // // Determine files that should be processed // const int numFiles = static_cast(dataFileNames.size()); for (int i = 0; i < numFiles; i++) { const QString name(dataFileNames[i]); if (seeIfFileIsInSpecFile(specFileDataFiles, name) == false) { switch (operation) { case OPERATION_NONE: break; case OPERATION_DELETE: if (QFile::remove(name) == false) { std::cout << "ERROR: Unable to delete " << name.toAscii().constData() << std::endl; } break; case OPERATION_LIST: std::cout << name.toAscii().constData() << std::endl; break; case OPERATION_MOVE: { const QString newName = (moveToDirectoryName + "/" + name); if (QFile::rename(name, newName) == false) { std::cout << "ERROR: Unable to rename " << name.toAscii().constData() << " to " << newName.toAscii().constData() << std::endl; } const QFile::Permissions permissions = AbstractFile::getFileWritePermissions(); if (permissions != 0) { QFile::setPermissions(newName, permissions); } } break; } } } } /** * see if file is in a spec file (special case for volume data files). */ bool CommandSpecFileDirectoryClean::seeIfFileIsInSpecFile( const std::set& dataFilesInSpecFile, const QString& name) const { const bool FILE_IS_IN_SPEC_FILE_FLAG = true; const bool FILE_IS_NOT_IN_SPEC_FILE_FLAG = false; // // File in spec file ? // if (dataFilesInSpecFile.find(name) != dataFilesInSpecFile.end()) { // // file is in the spec file // return FILE_IS_IN_SPEC_FILE_FLAG; } // // Some volume's are stored a pair of files with the "header" in one file // and the "data" in another file. Plus, some spec files only contain // the header. So, if a volume data file is found that is not listed in // a spec file, see if the corresponding header is in a spec file, and, // if so, indicate that the data file is in a spec file. // const QString afniDataExt(".BRIK"); const QString afniDataZipExt(".BRIK.gz"); const QString analyzeSpmWuNilDataExt(".img"); const QString analyzeSpmWuNilDataZipExt(".img.gz"); QString headerFileName; if (name.endsWith(afniDataExt) || name.endsWith(afniDataZipExt)) { QString temp = name; if (name.endsWith(afniDataZipExt)) { temp.chop(afniDataZipExt.length()); } else { temp.chop(afniDataExt.length()); } temp.append(".HEAD"); if (QFile::exists(temp)) { headerFileName = temp; } } else if (name.endsWith(analyzeSpmWuNilDataExt) || name.endsWith(analyzeSpmWuNilDataZipExt)) { QString temp = name; if (name.endsWith(analyzeSpmWuNilDataZipExt)) { temp.chop(analyzeSpmWuNilDataZipExt.length()); } else { temp.chop(analyzeSpmWuNilDataExt.length()); } temp.append(".ifh"); if (QFile::exists(temp)) { headerFileName = temp; } else { QString temp = name; if (name.endsWith(analyzeSpmWuNilDataZipExt)) { temp.chop(analyzeSpmWuNilDataZipExt.length()); } else { temp.chop(analyzeSpmWuNilDataExt.length()); } temp.append(".hdr"); if (QFile::exists(temp)) { headerFileName = temp; } } } // // If header exists, do not delete data file // if (headerFileName.isEmpty() == false) { if (dataFilesInSpecFile.find(headerFileName) != dataFilesInSpecFile.end()) { return FILE_IS_IN_SPEC_FILE_FLAG; } } return FILE_IS_NOT_IN_SPEC_FILE_FLAG; } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSpecFileCreate.h0000664000175000017500000000360411572067322026111 0ustar michaelmichael #ifndef __COMMAND_SPEC_FILE_CREATE_H__ #define __COMMAND_SPEC_FILE_CREATE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" class SpecFile; /// class for creating a spec file class CommandSpecFileCreate : public CommandBase { public: // constructor CommandSpecFileCreate(); // destructor ~CommandSpecFileCreate(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); // add all files in the current directory void addFilesInCurrentDirectory(SpecFile& sf); }; #endif // __COMMAND_SPEC_FILE_CREATE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSpecFileCreate.cxx0000664000175000017500000001777011572067322026475 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "Category.h" #include "CommandSpecFileCreate.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SpecFile.h" #include "Species.h" #include "StereotaxicSpace.h" #include "Structure.h" /** * constructor. */ CommandSpecFileCreate::CommandSpecFileCreate() : CommandBase("-spec-file-create", "SPEC FILE CREATE") { } /** * destructor. */ CommandSpecFileCreate::~CommandSpecFileCreate() { } /** * get the script builder parameters. */ void CommandSpecFileCreate::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { std::vector allSpaces; StereotaxicSpace::getAllStereotaxicSpaces(allSpaces); std::vector spaceNames; for (unsigned int i = 0; i < allSpaces.size(); i++) { spaceNames.push_back(allSpaces[i].getName()); } std::vector speciesTypes; std::vector speciesNames; Species::getAllSpeciesTypesAndNames(speciesTypes, speciesNames); std::vector structureTypes; std::vector structureNames; Structure::getAllTypesAndNames(structureTypes, structureNames, false); paramsOut.clear(); paramsOut.addListOfItems("Species", speciesNames, speciesNames); paramsOut.addString("Subject", ""); paramsOut.addListOfItems("Structure", structureNames, structureNames); paramsOut.addListOfItems("Stereotaxic Space", spaceNames, spaceNames); paramsOut.addVariableListOfParameters("Create Spec Options"); } /** * get full help information. */ QString CommandSpecFileCreate::getHelpInformation() const { std::vector allSpaces; StereotaxicSpace::getAllStereotaxicSpaces(allSpaces); std::vector spaceNames; for (int i = 0; i < static_cast(allSpaces.size()); i++) { spaceNames.push_back(allSpaces[i].getName()); } std::sort(spaceNames.begin(), spaceNames.end()); std::vector speciesTypes; std::vector speciesNames; Species::getAllSpeciesTypesAndNames(speciesTypes, speciesNames); std::sort(speciesNames.begin(), speciesNames.end()); std::vector structureTypes; std::vector structureNames; Structure::getAllTypesAndNames(structureTypes, structureNames, false); std::sort(structureNames.begin(), structureNames.end()); std::vector categoryTypes; std::vector categoryNames; Category::getAllCategoryTypesAndNames(categoryTypes, categoryNames); std::sort(structureNames.begin(), structureNames.end()); QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-add-files-in-directory]\n" + indent9 + "[-category category-name]\n" + indent9 + "[-spec-file-name spec-file-name]\n" + indent9 + "\n" + indent9 + "Create a Spec File\n" + indent9 + "\n" + indent9 + "If \"-add-files-in-directory\" is specified, all files in \n" + indent9 + "the directory that end with caret data file extensions are\n" + indent9 + "added to the spec file.\n" + indent9 + "\n" + indent9 + "The \"spec-file-name\" is optional and should only be specified\n" + indent9 + "if you must name the spec file. If the \"spec-file-name\" is not\n" + indent9 + "specified, the spec file name will be created using the Caret \n" + indent9 + "standard which composes the spec file name using the species,\n" + indent9 + "subject, and structure.\n" + indent9 + "\n" + indent9 + "Valid species for \"species\" are: \n"); for (int i = 0; i < static_cast(speciesNames.size()); i++) { helpInfo += (indent9 + " " + speciesNames[i] + "\n"); } helpInfo += "\n"; helpInfo += (indent9 + "Valid structures for \"structure\" are: \n"); for (int i = 0; i < static_cast(structureNames.size()); i++) { helpInfo += (indent9 + " " + structureNames[i] + "\n"); } helpInfo += "\n"; helpInfo += (indent9 + "Valid stereotaxic spaces for \"stereotaxic-space\" are: \n"); for (int i = 0; i < static_cast(spaceNames.size()); i++) { helpInfo += (indent9 + " " + spaceNames[i] + "\n"); } helpInfo += "\n"; helpInfo += (indent9 + "Valid categories for \"category\" are: \n"); for (int i = 0; i < static_cast(categoryNames.size()); i++) { helpInfo += (indent9 + " " + categoryNames[i] + "\n"); } helpInfo += "\n"; return helpInfo; } /** * execute the command. */ void CommandSpecFileCreate::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString speciesName = parameters->getNextParameterAsString("Species Name"); const QString subjectName = parameters->getNextParameterAsString("Subject Name"); const Structure structure = parameters->getNextParameterAsStructure("Structure"); const QString spaceName = parameters->getNextParameterAsString("Stereotaxic Space Name"); // // Optional parameters // QString categoryName; QString specFileName; bool addFilesInCurrentDirectoryFlag = false; while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("Spec File Create Option"); if (paramName == "-add-files-in-directory") { addFilesInCurrentDirectoryFlag = true; } else if (paramName == "-category") { categoryName = parameters->getNextParameterAsString("Category"); } else if (paramName == "-spec-file-name") { specFileName = parameters->getNextParameterAsString("Spec File Name"); } else { throw CommandException("Invalid parameter \"" + paramName + "\""); } } SpecFile sf; if (specFileName.isEmpty()) { specFileName = speciesName + "." + subjectName + "." + structure.getTypeAsAbbreviatedString() + SpecFile::getSpecFileExtension(); } sf.setSpecies(speciesName); sf.setSubject(subjectName); sf.setSpace(spaceName); sf.setStructure(structure.getTypeAsString()); sf.setCategory(categoryName); if (addFilesInCurrentDirectoryFlag) { addFilesInCurrentDirectory(sf); } sf.writeFile(specFileName); } /** * add all files in the current directory. */ void CommandSpecFileCreate::addFilesInCurrentDirectory(SpecFile& sf) { QDir dir(QDir::currentPath()); QFileInfoList list = dir.entryInfoList(QDir::Files); for (int i = 0; i < list.size(); i++) { sf.addUnknownTypeOfFileToSpecFile(list.at(i).fileName()); } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSpecFileCopy.h0000664000175000017500000000335511572067322025623 0ustar michaelmichael #ifndef __COMMAND_SPEC_FILE_COPY_H__ #define __COMMAND_SPEC_FILE_COPY_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandSpecFileCopy : public CommandBase { public: // constructor CommandSpecFileCopy(); // destructor ~CommandSpecFileCopy(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SPEC_FILE_COPY_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSpecFileCopy.cxx0000664000175000017500000001735411572067322026202 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandSpecFileCopy.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SpecFileUtilities.h" /** * constructor. */ CommandSpecFileCopy::CommandSpecFileCopy() : CommandBase("-spec-file-copy", "SPEC FILE COPY") { } /** * destructor. */ CommandSpecFileCopy::~CommandSpecFileCopy() { } /** * get the script builder parameters. */ void CommandSpecFileCopy::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); std::vector values, descriptions; values.push_back("COPY_ALL"); descriptions.push_back("Copy Spec and its Data Files"); values.push_back("MOVE_ALL"); descriptions.push_back("Move Spec and its Data Files"); values.push_back("COPY_SPEC_ONLY"); descriptions.push_back("Copy Spec File and Point to Data Files"); paramsOut.addListOfItems("Copy Mode", values, descriptions); paramsOut.addFile("Input Spec File Name", FileFilters::getSpecFileFilter()); paramsOut.addFile("Target Name", FileFilters::getSpecFileFilter()); } /** * get full help information. */ QString CommandSpecFileCopy::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "The source-spec-file and perhaps its data files are \n" + indent9 + "copied to the new location/spec file. \n" + indent9 + " \n" + indent9 + "if \"target-name\" is a directory, the name of the \n" + indent9 + "target spec file will be the same as the source spec \n" + indent9 + "file. \n" + indent9 + " \n" + indent9 + "\"copy-mode\" is one of \n" + indent9 + " \n" + indent9 + " COPY_ALL Copy the data files to the destination directory. \n" + indent9 + " COPY_SPEC_ONLY Copy only the spec file, the data files \n" + indent9 + " will not be copied. Any absolute or \n" + indent9 + " relative path on the specified spec file \n" + indent9 + " is prepended to the data filenames in \n" + indent9 + " the new spec file. \n" + indent9 + " MOVE ALL Move all files from their old location to their \n" + indent9 + " new location. \n" + indent9 + " \n" + indent9 + "LIMITATIONS \n" + indent9 + " Either the source or target spec file must be in the \n" + indent9 + " current directory. \n" + indent9 + " \n" + indent9 + " If you are using the \"-s\" option to copy only the spec \n" + indent9 + " file and want a relative path to the data files in the \n" + indent9 + " target spec file, you must run the command from the \n" + indent9 + " target directory as shown in the first example and use \n" + indent9 + " a relative path to specify the spec file that is being \n" + indent9 + " copied. \n" + indent9 + " \n" + indent9 + "EXAMPLES \n" + indent9 + " \n" + indent9 + " Copy the spec file brain.spec to the current directory. \n" + indent9 + " The data files will not be copied but the path to each of the\n" + indent9 + " data files in the spec file will be a RELATIVE path \n" + indent9 + " since a relative path is used to specify the spec file. \n" + indent9 + " Note that a \".\" is used to specify the current directory \n" + indent9 + " for the target spec file. \n" + indent9 + " \n" + indent9 + " COPY_SPEC_ONLY ../../brain/brain.spec . \n" + indent9 + " \n" + indent9 + " Copy the spec file brain.spec to the current directory. \n" + indent9 + " The data files will not be copied but the path to each of the\n" + indent9 + " data files in the spec file will be an ABSOLUTE path \n" + indent9 + " since an absolute path is used to specify the spec file. \n" + indent9 + " \n" + indent9 + " COPY_SPEC_ONLY /usr/data/brain/brain.spec . \n" + indent9 + " \n" + indent9 + " Copy the spec file occipital.spec located in the current \n" + indent9 + " directory to the directory /usr/people/bob/brain_data. \n" + indent9 + " The data files will also be copied. \n" + indent9 + " \n" + indent9 + " COPY_ALL occipital.spec /usr/people/bob/brain_data \n" + indent9 + " \n" + indent9 + " Copy the spec file occipital.spec located in the current \n" + indent9 + " directory to the directory /usr/people/bob/brain_data. \n" + indent9 + " The data files will not be copied and the path to each of \n" + indent9 + " the data files in the spec file will be an absolute path \n" + indent9 + " since the command is run from the directory containing \n" + indent9 + " the spec file. \n" + indent9 + " \n" + indent9 + " COPY_SPEC_ONLY occipital.spec /usr/people/bob/brain_data \n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSpecFileCopy::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString copyModeName = parameters->getNextParameterAsString("Copy Mode"); const QString sourceSpecFileName = parameters->getNextParameterAsString("Source Spec File Name"); const QString targetName = parameters->getNextParameterAsString("Target Name"); checkForExcessiveParameters(); SpecFileUtilities::MODE_COPY_SPEC_FILE copyMode; if (copyModeName == "COPY_ALL") { copyMode = SpecFileUtilities::MODE_COPY_SPEC_FILE_COPY_ALL; } else if (copyModeName == "COPY_SPEC_ONLY") { copyMode = SpecFileUtilities::MODE_COPY_SPEC_FILE_POINT_TO_DATA_FILES; } else if (copyModeName == "MOVE_ALL") { copyMode = SpecFileUtilities::MODE_COPY_SPEC_FILE_MOVE_ALL; } else { throw CommandException("Invalid copy mode \"" + copyModeName + "\""); } QString errorMessage; const bool errorFlag = SpecFileUtilities::copySpecFile(sourceSpecFileName, targetName, copyMode, errorMessage, true); if (errorFlag) { throw CommandException(errorMessage); } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSpecFileClean.h0000664000175000017500000000336311572067322025732 0ustar michaelmichael #ifndef __COMMAND_SPEC_FILE_CLEAN_H__ #define __COMMAND_SPEC_FILE_CLEAN_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandSpecFileClean : public CommandBase { public: // constructor CommandSpecFileClean(); // destructor ~CommandSpecFileClean(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SPEC_FILE_CLEAN_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSpecFileClean.cxx0000664000175000017500000000562411572067322026307 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandSpecFileClean.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SpecFile.h" /** * constructor. */ CommandSpecFileClean::CommandSpecFileClean() : CommandBase("-spec-file-clean", "SPEC FILE CLEAN") { } /** * destructor. */ CommandSpecFileClean::~CommandSpecFileClean() { } /** * get the script builder parameters. */ void CommandSpecFileClean::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Spec File Name", FileFilters::getSpecFileFilter()); } /** * get full help information. */ QString CommandSpecFileClean::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Remove spec file entries for files that do not exist.\n" + indent9 + "\n" + indent9 + "If a file listed in a spec file does not exists, the \n" + indent9 + "entry for the file is removed from the spec file.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSpecFileClean::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the parameters // const QString specFileName = parameters->getNextParameterAsString("Spec File Name"); checkForExcessiveParameters(); // // Read the spec file // SpecFile specFile; specFile.readFile(specFileName); // // Clean the spec file // bool filesCleanedFlag = specFile.cleanSpecFile(); // // Write the spec file // if (filesCleanedFlag) { specFile.writeFile(specFileName); } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSpecFileChangeResolution.h0000664000175000017500000000462611572067322030164 0ustar michaelmichael #ifndef __COMMAND_SPEC_FILE_CHANGE_RESOLUTION_H__ #define __COMMAND_SPEC_FILE_CHANGE_RESOLUTION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" class BrainModelSurface; class BrainSet; /// class for changing resolution of spec file and its data files class CommandSpecFileChangeResolution : public CommandBase { public: // constructor CommandSpecFileChangeResolution(); // destructor ~CommandSpecFileChangeResolution(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); QString createOutputSpecFileName(const QString& sourceSpecName, const int numberOfNodes); // create the output directory void createOutputDirectory(const QString& directoryName); // read the user's spec file BrainSet* readUsersSpecFile(const QString& userSpecFileName); // create a spherical surface from a fiducial surface BrainModelSurface* createSphereFromUsersFiducial(BrainSet* bs); }; #endif // __COMMAND_SPEC_FILE_CHANGE_RESOLUTION_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSpecFileChangeResolution.cxx0000664000175000017500000004766611572067322030552 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include "BrainModelSurface.h" #include "BrainModelSurfaceDeformation.h" #include "BrainModelSurfaceDeformationMapCreate.h" #include "BrainModelSurfacePolyhedron.h" #include "BrainModelSurfacePolyhedronNew.h" #include "BrainModelSurfaceStandardSphere.h" #include "BrainSet.h" #include "CommandSpecFileChangeResolution.h" #include "DeformationMapFile.h" #include "FileFilters.h" #include "FileUtilities.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SpecFile.h" #include "TopologyFile.h" /** * constructor. */ CommandSpecFileChangeResolution::CommandSpecFileChangeResolution() : CommandBase("-spec-file-change-resolution", "SPEC FILE CHANGE RESOLUTION") { } /** * destructor. */ CommandSpecFileChangeResolution::~CommandSpecFileChangeResolution() { } /** * get the script builder parameters. */ void CommandSpecFileChangeResolution::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Spec File Name", FileFilters::getSpecFileFilter()); paramsOut.addDirectory("Output Directory Name"); paramsOut.addInt("Number of Nodes", 2562); } /** * get full help information. */ QString CommandSpecFileChangeResolution::getHelpInformation() const { BrainModelSurfacePolyhedron poly(NULL, 0); QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Change (typically reduce) the resolution of the surface \n" + indent9 + "files in the spec file. This is accomplished by replacing\n" + indent9 + "spec file's spherical coordinate file with a spherical \n" + indent9 + "coordinate file generated by iteratively subdividing an \n" + indent9 + "icosahedron. If there is not a spherical surface, a \n" + indent9 + "spherical surface is created from the fiducial surface\n" + indent9 + "via inflation and smoothing.\n" + indent9 + "\n" + indent9 + "The output directory must not exist and will be created\n" + indent9 + "by this program.\n" + indent9 + "\n" + indent9 + "This command should be run from the directory containing\n" + indent9 + "the input spec file.\n" + indent9 + "\n" + indent9 + "If the number of nodes does not match a standard mesh from\n" + indent9 + "the list below, a close resolution is found by dividing\n" + indent9 + "the faces of an icosahedron and projecting to a sphere.\n" + indent9 + "\n" + indent9 + "Number of Nodes Number of Triangles\n" + indent9 + "--------------- -------------------\n"); std::vector iterations, nodes, triangles; BrainModelSurfacePolyhedron::getNumberOfNodesAndTrianglesFromIterations( iterations, nodes, triangles); int numIters = static_cast(iterations.size()); for (int i = 0; i < numIters; i++) { helpInfo += (indent9 + QString("%1%2\n").arg(nodes[i], 15).arg(triangles[i], 22)); } BrainModelSurfaceStandardSphere::getNumberOfNodesAndTriangles(nodes, triangles); const int num = static_cast(nodes.size()); for (int i = 0; i < num; i++) { helpInfo += (indent9 + QString("%1%2\n").arg(nodes[i], 15).arg(triangles[i], 22)); } helpInfo += "\n"; return helpInfo; } /** * execute the command. */ void CommandSpecFileChangeResolution::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString originalPath = QDir::currentPath(); QString deformedPrefix = ""; //LowRes_"; // // Get the inputs // const QString usersSpecFileName = parameters->getNextParameterAsString("Spec File Name"); const QString outputDirectoryName = parameters->getNextParameterAsString("Directory Name"); int numberOfNodes = parameters->getNextParameterAsInt("Number of Nodes"); checkForExcessiveParameters(); // // Validate number of nodes // std::vector iterations, nodes, triangles; BrainModelSurfacePolyhedron::getNumberOfNodesAndTrianglesFromIterations( iterations, nodes, triangles); int numberOfIterations = -1; for (int i = 0; i < static_cast(nodes.size()); i++) { if (numberOfNodes == nodes[i]) { numberOfIterations = i; break; } } int stdSphereNumberOfNodes = -1; if (numberOfIterations < 0) { BrainModelSurfaceStandardSphere::getNumberOfNodesAndTriangles( nodes, triangles); for (int i = 0; i < static_cast(nodes.size()); i++) { if (numberOfNodes == nodes[i]) { stdSphereNumberOfNodes = numberOfNodes; break; } } } int mynodes, mytris, lastnodes = -1000; int newNumberOfDivisions = -1; if ((numberOfIterations < 0) && (stdSphereNumberOfNodes < 0)) {//Instead of crashing, find a close resolution with the new polyhedron if (numberOfNodes < 4) {//in case we throw in tetrahedron sometime throw CommandException("Invalid number of nodes: " + QString::number(numberOfNodes)); } std::cout << "Nonstandard resolution specified..." << std::endl; for (int i = 1; i < 10000; ++i)//10363 divisions overflows an int32 in number of triangles, tighten this sanity check? { BrainModelSurfacePolyhedronNew::getNumberOfNodesAndTrianglesFromDivisions(i, mynodes, mytris); if (abs(numberOfNodes - lastnodes) < abs(mynodes - numberOfNodes)) { newNumberOfDivisions = i - 1; numberOfNodes = lastnodes;//reset node number because it is used in labels elsewhere std::cout << "Using closest divided icosahedron, with " << numberOfNodes << " nodes." << std::endl; break; } lastnodes = mynodes; } } // // Create the spherical target // BrainSet brainSet; if (numberOfIterations >= 0) { BrainModelSurfacePolyhedron tetra(&brainSet, numberOfIterations); tetra.execute(); } else if (stdSphereNumberOfNodes > 0) { BrainModelSurfaceStandardSphere sphere(&brainSet, stdSphereNumberOfNodes); sphere.execute(); brainSet.getLoadedFilesSpecFile()->clear(); QDir::setCurrent(originalPath); } else if (newNumberOfDivisions > 0) { BrainModelSurfacePolyhedronNew tetranew(&brainSet, newNumberOfDivisions); tetranew.execute(); } else { throw CommandException("Invalid number of nodes: " + QString::number(numberOfNodes)); } // // create the output directory // this->createOutputDirectory(outputDirectoryName); BrainModelSurface* targetSphericalSurface = brainSet.getBrainModelSurface(0); if (targetSphericalSurface == NULL) { throw CommandException("Failed to create resampled spherical surface."); } TopologyFile* tf = targetSphericalSurface->getTopologyFile(); if (tf == NULL) { throw CommandException("Created spherical surface has no topology."); } // // Prefix for deformation sphere files // const QString defTargetPrefix = "def_sphere"; const QString defTargetCoordName = defTargetPrefix + SpecFile::getCoordinateFileExtension(); QString defTargetTopoName = defTargetPrefix + SpecFile::getTopoFileExtension(); QString defTargetSpecName = deformedPrefix + FileUtilities::basename(usersSpecFileName); const QString defTargetDefMapName = defTargetPrefix + SpecFile::getDeformationMapFileExtension(); // // Change target def map name to include correct number of nodes // This name gets used for deforming data files so that the data files // have the correct number of nodes. // 9/10/2010 // defTargetSpecName = this->createOutputSpecFileName(defTargetSpecName, targetSphericalSurface->getNumberOfNodes()); // // Read the user's brain set // BrainSet* usersBrainSet = this->readUsersSpecFile(usersSpecFileName); BrainModelSurface* fiducialSurface = usersBrainSet->getBrainModelSurfaceOfType( BrainModelSurface::SURFACE_TYPE_FIDUCIAL); QString fiducialSurfaceName; if (fiducialSurface != NULL) { fiducialSurfaceName = fiducialSurface->getFileName(); } BrainModelSurface* usersSphericalSurface = usersBrainSet->getBrainModelSurfaceOfType( BrainModelSurface::SURFACE_TYPE_SPHERICAL); if (usersSphericalSurface == NULL) { usersSphericalSurface = createSphereFromUsersFiducial(usersBrainSet); } TopologyFile* sourceTopologyFile = fiducialSurface->getTopologyFile(); if (sourceTopologyFile != NULL) { defTargetTopoName = this->createOutputSpecFileName( FileUtilities::basename(sourceTopologyFile->getFileName()), numberOfNodes); defTargetTopoName = BrainModelSurfaceDeformDataFile::createDeformedFileName( sourceTopologyFile->getFileName(), defTargetSpecName, "", numberOfNodes, false); } // // Set the radius of the target sphere // targetSphericalSurface->convertToSphereWithRadius( usersSphericalSurface->getSphericalSurfaceRadius()); // // Update items in target spec // brainSet.setSpecies(usersBrainSet->getSpecies()); brainSet.setStructure(usersBrainSet->getStructure()); brainSet.setSubject(usersBrainSet->getSubject()); brainSet.setStereotaxicSpace(usersBrainSet->getStereotaxicSpace()); // // Write out sphere for debugging // QDir::setCurrent(outputDirectoryName); brainSet.setSpecFileName(defTargetSpecName, false); CoordinateFile* cf = targetSphericalSurface->getCoordinateFile(); brainSet.writeCoordinateFile(defTargetCoordName, targetSphericalSurface->getSurfaceType(), cf, true); brainSet.writeTopologyFile(defTargetTopoName, tf->getTopologyType(), tf); QDir::setCurrent(originalPath); // // Deformation Map File // DeformationMapFile defMapFile; // // Execute the deformation // BrainModelSurfaceDeformationMapCreate bmsdmc(&brainSet, usersSphericalSurface, targetSphericalSurface, &defMapFile, BrainModelSurfaceDeformationMapCreate::DEFORMATION_SURFACE_TYPE_SPHERE); bmsdmc.execute(); defMapFile.setMetricDeformationType(DeformationMapFile::METRIC_DEFORM_AVERAGE_TILE_NODES); // // Write the deformation map file // if (QFileInfo(usersSpecFileName).isAbsolute()) { defMapFile.setSourceSpecFileName(usersSpecFileName); } else { defMapFile.setSourceSpecFileName(QDir::currentPath() + QDir::separator() + usersSpecFileName); } defMapFile.setSourceFiducialCoordFileName(fiducialSurfaceName); defMapFile.setSourceDirectory(QDir::currentPath()); QDir::setCurrent(outputDirectoryName); defMapFile.setTargetDirectory(QDir::currentPath()); if (QFileInfo(defTargetSpecName).isAbsolute()) { defMapFile.setTargetSpecFileName(defTargetSpecName); } else { defMapFile.setTargetSpecFileName(QDir::currentPath() + QDir::separator() + defTargetSpecName); } defMapFile.setOutputSpecFileName(defMapFile.getTargetSpecFileName()); defMapFile.setDeformedFileNamePrefix(deformedPrefix); defMapFile.setDeformedColumnNamePrefix(""); defMapFile.writeFile(defTargetDefMapName); QDir::setCurrent(originalPath); // // Create the deformed fiducial surface and load the fiducial surface // This allows border and foci projections to deform // SpecFile userSpecFile; userSpecFile.readFile(usersSpecFileName); if (userSpecFile.fiducialCoordFile.getNumberOfFiles() > 0) { userSpecFile.readFile(usersSpecFileName); QString deformErrorMessage; BrainModelSurfaceDeformDataFile::deformCoordinateFiles(&defMapFile, userSpecFile.fiducialCoordFile, deformErrorMessage); if (deformErrorMessage.isEmpty()) { QDir::setCurrent(outputDirectoryName); SpecFile tgtSpec; tgtSpec.readFile(defMapFile.getOutputSpecFileName()); if (tgtSpec.fiducialCoordFile.getNumberOfFiles() > 0) { const QString fiducialCoordFileName = tgtSpec.fiducialCoordFile.getFileName(0); brainSet.readCoordinateFile(fiducialCoordFileName, BrainModelSurface::SURFACE_TYPE_FIDUCIAL, false, true, true); defMapFile.setTargetFiducialCoordFileName(fiducialCoordFileName); } QDir::setCurrent(originalPath); } } // // Remove the std sphere from the output spec file // QDir::setCurrent(outputDirectoryName); SpecFile outSpecFile; outSpecFile.readFile(defMapFile.getOutputSpecFileName()); outSpecFile.sphericalCoordFile.clear(false); outSpecFile.writeFile(defMapFile.getOutputSpecFileName()); QDir::setCurrent(originalPath); // // Deform the data files // QString errorMessage; BrainModelSurfaceDeformation::deformDataFiles( usersBrainSet, &brainSet, usersBrainSet->getSpecFileName(), &defMapFile, true, false, // already did fiducial true, true, true, false, errorMessage); if (errorMessage.isEmpty() == false) { throw CommandException(errorMessage); } } /** * create a spherical surface from a fiducial surface. */ BrainModelSurface* CommandSpecFileChangeResolution::createSphereFromUsersFiducial(BrainSet* bs) { BrainModelSurface* bms = bs->getBrainModelSurfaceOfType( BrainModelSurface::SURFACE_TYPE_FIDUCIAL); if (bms == NULL) { throw CommandException("Users spec file contains neither a fiducial " "nor a spherical surface."); } // // Create a spherical surface // bms->createInflatedAndEllipsoidFromFiducial(false, false, false, true, false, false, true, 0, NULL); bms = bs->getBrainModelSurfaceOfType( BrainModelSurface::SURFACE_TYPE_SPHERICAL); if (bms == NULL) { throw CommandException("Failed to create spherical surface from users " "fiducial surface."); } return bms; } /** * create the output directory. */ void CommandSpecFileChangeResolution::createOutputDirectory(const QString& directoryName) { if (QFile::exists(directoryName)) { throw CommandException("Ouput directory \"" + directoryName + "\" exists. The output directory must not " + "and will be created by this program."); } QDir currentDir; if (currentDir.mkdir(directoryName) == false) { throw CommandException("Unable to create directory \"" + directoryName + "\"."); } } /** * read the user's spec file. */ BrainSet* CommandSpecFileChangeResolution::readUsersSpecFile(const QString& usersSpecFileName) { SpecFile sf; sf.readFile(usersSpecFileName); sf.setAllFileSelections(SpecFile::SPEC_TRUE); BrainSet* bs = new BrainSet(); QString errorMessage; bs->readSpecFile(sf, usersSpecFileName, errorMessage); if (errorMessage.isEmpty() == false) { throw CommandException(errorMessage); } return bs; } QString CommandSpecFileChangeResolution::createOutputSpecFileName(const QString& sourceSpecName, const int numberOfNodes) { QString directory, species, casename, anatomy, hemisphere; QString description, descriptionNoTypeName, theDate, numNodes, extension; const bool valid = FileUtilities::parseCaretDataFileName(sourceSpecName, directory, species, casename, anatomy, hemisphere, description, descriptionNoTypeName, theDate, numNodes, extension); if (valid) { QString newNumberOfNodes = QString::number(numberOfNodes); QString nodeString, atlasString; bool nodesValid = FileUtilities::parseCaretDataFileNumberOfNodes(numNodes, nodeString, atlasString); if (nodesValid) { if (atlasString.isEmpty() == false) { QString thousandNodes = QString::number(numberOfNodes / 1000); newNumberOfNodes = thousandNodes + "k" + atlasString; } } const QString newSpecName = FileUtilities::reassembleCaretDataFileName(directory, species, casename, anatomy, hemisphere, description, theDate, newNumberOfNodes, extension); return newSpecName; } return sourceSpecName; } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSpecFileAdd.h0000664000175000017500000000430011572067322025370 0ustar michaelmichael #ifndef __COMMAND_SPEC_FILE_ADD_H__ #define __COMMAND_SPEC_FILE_ADD_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for adding items to a spec file class CommandSpecFileAdd : public CommandBase { public: // constructor CommandSpecFileAdd(); // destructor ~CommandSpecFileAdd(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; // add tag and file to spec file static void addTagAndFileToSpecFile(const QString& specFileName, const QString& specFileTag, const QString& dataFileName, const QString& volumeDataFileName = "") throw (FileException); protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SPEC_FILE_ADD_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSpecFileAdd.cxx0000664000175000017500000001354611572067322025757 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandSpecFileAdd.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SpecFile.h" /** * constructor. */ CommandSpecFileAdd::CommandSpecFileAdd() : CommandBase("-spec-file-add", "SPEC FILE ADD") { } /** * destructor. */ CommandSpecFileAdd::~CommandSpecFileAdd() { } /** * get the script builder parameters. */ void CommandSpecFileAdd::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { std::vector names, tags; std::vector allEntries; SpecFile sf; sf.getAllEntries(allEntries); for (unsigned int i = 0; i < allEntries.size(); i++) { const QString tag(allEntries[i].getSpecFileTag()); const QString name(allEntries[i].getDescriptiveName() + " (" + tag + ")"); names.push_back(name); tags.push_back(tag); } paramsOut.clear(); paramsOut.addFile("Spec File Name", FileFilters::getSpecFileFilter()); paramsOut.addListOfItems("Tag", tags, names); QStringList allFileFilters; FileFilters::getAllFileFilters(allFileFilters); paramsOut.addFile("Data File Name", allFileFilters); paramsOut.addVariableListOfParameters("Add Spec File Options"); } /** * get full help information. */ QString CommandSpecFileAdd::getHelpInformation() const { // // Get all of the spec file entries // std::vector allEntries; SpecFile sf; sf.getAllEntries(allEntries); // // Find the longest tag length // int longestTagLength = 0; for (unsigned int i = 0; i < allEntries.size(); i++) { longestTagLength = std::max(longestTagLength, allEntries[i].getSpecFileTag().length()); } longestTagLength += 1; QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[data-file-second-name]\n" + indent9 + "\n" + indent9 + "Add a file to a spec file\n" + indent9 + "\n" + indent9 + "If adding a volume header/data file pair, enter the header\n" + indent9 + "file name as \"data-file-name\" and the data file as \n" + indent9 + "\"data-file-second-name\".\n" + indent9 + "\n" + indent9 + "The spec file must exist. A spec file is created using.\n" + indent9 + "the command \"-spec-file-create\".\n" + indent9 + "Valid spec file tags are:\n"); const QString title1(QString("TAG").leftJustified(longestTagLength,' ')); QString s = indent9 + title1 + " DESCRIPTION\n"; for (unsigned int i = 0; i < allEntries.size(); i++) { QString tag(allEntries[i].getSpecFileTag()); const QString description(allEntries[i].getDescriptiveName()); tag = tag.leftJustified(longestTagLength, ' '); s += (indent9 + tag + " " + description + "\n"); } helpInfo += s; return helpInfo; } /** * execute the command. */ void CommandSpecFileAdd::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the parameters // const QString specFileName = parameters->getNextParameterAsString("Spec File Name"); QString specFileTag = parameters->getNextParameterAsString("Spec File Tag"); QString dataFileName = parameters->getNextParameterAsString("Data File Name"); QString volumeDataFileName; if (parameters->getParametersAvailable()) { volumeDataFileName = parameters->getNextParameterAsString("Data File Second Name (Volume Data)"); } addTagAndFileToSpecFile(specFileName, specFileTag, dataFileName, volumeDataFileName); } /** * add tag and file to spec file */ void CommandSpecFileAdd::addTagAndFileToSpecFile(const QString& specFileName, const QString& specFileTag, const QString& dataFileName, const QString& volumeDataFileName) throw (FileException) { SpecFile sf; if (specFileName.isEmpty() == false) { if (QFile::exists(specFileName)) { sf.readFile(specFileName); } } sf.addToSpecFile(specFileTag, dataFileName, volumeDataFileName, false); sf.writeFile(specFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandShowVolume.h0000664000175000017500000000355211572067322025405 0ustar michaelmichael #ifndef __COMMAND_SHOW_VOLUME_H__ #define __COMMAND_SHOW_VOLUME_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for showing a volume class CommandShowVolume : public CommandBase { public: // constructor CommandShowVolume(); // destructor ~CommandShowVolume(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; /// command requires GUI flag sent to QApplication to be true virtual bool getHasGUI() const { return true; } protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SHOW_VOLUME_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandShowVolume.cxx0000664000175000017500000001641711572067322025764 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelOpenGL.h" #include "BrainModelVolume.h" #include "BrainModelVolumeVoxelColoring.h" #include "BrainSet.h" #include "CommandImageView.h" #include "CommandShowVolume.h" #include "DisplaySettingsVolume.h" #include "FileFilters.h" #include "OffScreenOpenGLWidget.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SpecFile.h" #include "VolumeFile.h" /** * constructor. */ CommandShowVolume::CommandShowVolume() : CommandBase("-show-volume", "SHOW VOLUME") { } /** * destructor. */ CommandShowVolume::~CommandShowVolume() { } /** * get the script builder parameters. */ void CommandShowVolume::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { std::vector axisValues, axisNames; axisValues.push_back("X"); axisNames.push_back("Parasagittal View"); axisValues.push_back("Y"); axisNames.push_back("Coronal View"); axisValues.push_back("Z"); axisNames.push_back("Horizontal (axial) View"); paramsOut.clear(); paramsOut.addListOfItems("Axis", axisValues, axisNames); paramsOut.addInt("Slice", 0, 10000000, 0); paramsOut.addFile("Volume File Name", FileFilters::getVolumeGenericFileFilter()); paramsOut.addInt("Image Width", 512, 0, 10000000); paramsOut.addInt("Image Height", 512, 0, 10000000); paramsOut.addVariableListOfParameters("Show Volume Options"); } /** * get full help information. */ QString CommandShowVolume::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[image-file-name]\n" + indent9 + "\n" + indent9 + "Render an image of the volume to an image file for the\n" + indent9 + "user's display.\n" + indent9 + "\n" + indent9 + " axis is one of: \n" + indent9 + " X => x-axis (parasagittal view)\n" + indent9 + " Y => y-axis (coronal view)\n" + indent9 + " Z => z-axis (horizontal/axial view)\n" + indent9 + "\n" + indent9 + " NOTE: If the image file name is not specified, the image of \n" + indent9 + " volume the will be shown in a window on the user's display.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandShowVolume::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const int MAIN_WINDOW_INDEX = 0; // // Get the parameters // VolumeFile::VOLUME_AXIS axis = VolumeFile::getAxisFromString(parameters->getNextParameterAsString("AXIS")); const int sliceNumber = parameters->getNextParameterAsInt("Slice Number"); QString volumeFileName = parameters->getNextParameterAsString("Volume File Name"); // // Get the image X size // const int imageWidth = parameters->getNextParameterAsInt("Image Width"); if (imageWidth <= 0) { throw CommandException("Invalid image width = " + QString::number(imageWidth)); } // // Get the image Y size // const int imageHeight = parameters->getNextParameterAsInt("Image Height"); if (imageHeight <= 0) { throw CommandException("Invalid image height = " + QString::number(imageHeight)); } bool saveImageToFile = false; QString imageFileName; if (parameters->getParametersAvailable()) { saveImageToFile = true; // // Image file name // imageFileName = parameters->getNextParameterAsString("Image File Name"); } // // Add the volume to a spec file // SpecFile sf; sf.addToSpecFile(SpecFile::getVolumeAnatomyFileTag(), volumeFileName, "", false); // // Read the spec file into a brain set // BrainSet brainSet; QString errorMessage; if (brainSet.readSpecFile(sf, "", errorMessage)) { throw CommandException("reading volume file: " + errorMessage); } BrainModelVolume* bmv = brainSet.getBrainModelVolume(); if (bmv == NULL) { throw CommandException("Cannot find volume in BrainSet. " "Problem with volume file? "); } // // Set the underlay to anatomy // brainSet.getVoxelColoring()->setUnderlay(BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_ANATOMY); // // Set the view // bmv->setSelectedAxis(MAIN_WINDOW_INDEX, axis); // // Set the slices // int slices[3]; bmv->setToStandardView(MAIN_WINDOW_INDEX, BrainModelVolume::VIEW_RESET); bmv->getSelectedOrthogonalSlices(MAIN_WINDOW_INDEX, slices); switch (axis) { case VolumeFile::VOLUME_AXIS_X: slices[0] = sliceNumber; break; case VolumeFile::VOLUME_AXIS_Y: slices[1] = sliceNumber; break; case VolumeFile::VOLUME_AXIS_Z: slices[2] = sliceNumber; break; default: break; } bmv->setSelectedOrthogonalSlices(MAIN_WINDOW_INDEX, slices); // // Remove crosshairs // DisplaySettingsVolume* dsv = brainSet.getDisplaySettingsVolume(); dsv->setDisplayCrosshairCoordinates(false); dsv->setDisplayCrosshairs(false); dsv->setDisplayOrientationLabels(false); // // setup the off screen renderer // QImage image; OffScreenOpenGLWidget opengl; opengl.setFixedSize(imageWidth, imageHeight); // // Render the image // opengl.drawToImage(&brainSet, bmv, image); // // Write the image file // if (saveImageToFile) { if (image.save(imageFileName, "jpg") == false) { throw CommandException("Unable to write image file: " + imageFileName); } } else { CommandImageView::displayQImage(image); } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandShowSurface.h0000664000175000017500000000356111572067322025526 0ustar michaelmichael #ifndef __COMMAND_SHOW_SURFACE_H__ #define __COMMAND_SHOW_SURFACE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for showing a surface class CommandShowSurface : public CommandBase { public: // constructor CommandShowSurface(); // destructor ~CommandShowSurface(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; /// command requires GUI flag sent to QApplication to be true virtual bool getHasGUI() const { return true; } protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SHOW_SURFACE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandShowSurface.cxx0000664000175000017500000002104211572067322026073 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelOpenGL.h" #include "BrainModelSurface.h" #include "BrainSet.h" #include "CommandImageView.h" #include "CommandShowSurface.h" #include "FileFilters.h" #include "OffScreenOpenGLWidget.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandShowSurface::CommandShowSurface() : CommandBase("-show-surface", "SHOW SURFACE") { } /** * destructor. */ CommandShowSurface::~CommandShowSurface() { } /** * get the script builder parameters. */ void CommandShowSurface::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { std::vector viewValues, viewNames; viewValues.push_back("ALL"); viewNames.push_back("All"); viewValues.push_back("A"); viewNames.push_back("Anterior"); viewValues.push_back("D"); viewNames.push_back("Dorsal"); viewValues.push_back("L"); viewNames.push_back("Lateral"); viewValues.push_back("M"); viewNames.push_back("Medial"); viewValues.push_back("P"); viewNames.push_back("Posterior"); viewValues.push_back("V"); viewNames.push_back("Ventral"); paramsOut.clear(); paramsOut.addFile("Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addListOfItems("View", viewValues, viewNames); paramsOut.addInt("Image Width", 512, 0, 10000000); paramsOut.addInt("Image Height", 512, 0, 10000000); paramsOut.addVariableListOfParameters("Show Surface Options"); } /** * get full help information. */ QString CommandShowSurface::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[image-file-name]\n" + indent9 + "\n" + indent9 + "Render an image of the surface to a file or to the user's screen.\n" + indent9 + "\n" + indent9 + " view is one of: \n" + indent9 + " A => anterior view\n" + indent9 + " ALL => all views in one image\n" + indent9 + " D => dorsal view\n" + indent9 + " L => lateral view\n" + indent9 + " M => medial view\n" + indent9 + " P => posterior view\n" + indent9 + " V => ventral view\n" + indent9 + "\n" + indent9 + " NOTE: If the image file name is not specified, the image of\n" + indent9 + " the surface will be shown in a window on the user's display." + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandShowSurface::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const int MAIN_WINDOW_INDEX = 0; // // Get the parameters // const QString coordFileName = parameters->getNextParameterAsString("Input Coord File"); const QString topoFileName = parameters->getNextParameterAsString("Input Topo File"); // // Get the view // QString viewName = parameters->getNextParameterAsString("View"); BrainModel::STANDARD_VIEWS view; if (viewName == "L") { view = BrainModel::VIEW_LATERAL; } else if (viewName == "M") { view = BrainModel::VIEW_MEDIAL; } else if (viewName == "D") { view = BrainModel::VIEW_DORSAL; } else if (viewName == "V") { view = BrainModel::VIEW_VENTRAL; } else if (viewName == "A") { view = BrainModel::VIEW_ANTERIOR; } else if (viewName == "P") { view = BrainModel::VIEW_POSTERIOR; } else if (viewName == "ALL") { view = BrainModel::VIEW_NONE; } else { throw CommandException("Invalid view \"" + viewName + "\"."); } // // Get the image X size // const int imageWidth = parameters->getNextParameterAsInt("Image Width"); if (imageWidth <= 0) { throw CommandException("Invalid image width = " + QString::number(imageWidth)); } // // Get the image Y size // const int imageHeight = parameters->getNextParameterAsInt("Image Height"); if (imageHeight <= 0) { throw CommandException("Invalid image height = " + QString::number(imageHeight)); } bool saveImageToFile = false; QString imageFileName; if (parameters->getParametersAvailable()) { saveImageToFile = true; // // Image file name // imageFileName = parameters->getNextParameterAsString("Image File Name"); } // // Read the spec file into a brain set // BrainSet brainSet(topoFileName, coordFileName); BrainModelSurface* bms = brainSet.getBrainModelSurface(0); if (bms == NULL) { throw CommandException("Cannot find surface in BrainSet from " + coordFileName + " and " + topoFileName); } // // setup the off screen renderer // QImage image; OffScreenOpenGLWidget opengl; // // "none" is all views in one image // if (view == BrainModel::VIEW_NONE) { const int xSize = imageWidth / 2; const int ySize = imageHeight / 3; opengl.setFixedSize(xSize, ySize); // // Render the surface into size images // QImage a, d, l, m, p, v; bms->setToStandardView(MAIN_WINDOW_INDEX, BrainModel::VIEW_ANTERIOR); opengl.drawToImage(&brainSet, bms, a); bms->setToStandardView(MAIN_WINDOW_INDEX, BrainModel::VIEW_DORSAL); opengl.drawToImage(&brainSet, bms, d); bms->setToStandardView(MAIN_WINDOW_INDEX, BrainModel::VIEW_MEDIAL); opengl.drawToImage(&brainSet, bms, m); bms->setToStandardView(MAIN_WINDOW_INDEX, BrainModel::VIEW_LATERAL); opengl.drawToImage(&brainSet, bms, l); bms->setToStandardView(MAIN_WINDOW_INDEX, BrainModel::VIEW_POSTERIOR); opengl.drawToImage(&brainSet, bms, p); bms->setToStandardView(MAIN_WINDOW_INDEX, BrainModel::VIEW_VENTRAL); opengl.drawToImage(&brainSet, bms, v); // // Assemble the images into one image // image = QImage(imageWidth, imageHeight, a.format()); for (int i = 0; i < xSize; i++) { for (int j = 0; j < ySize; j++) { image.setPixel(i, j, l.pixel(i, j)); image.setPixel(i + xSize, j, m.pixel(i, j)); image.setPixel(i, j + ySize, d.pixel(i, j)); image.setPixel(i + xSize, j + ySize, v.pixel(i, j)); image.setPixel(i, j + 2*ySize, a.pixel(i, j)); image.setPixel(i + xSize, j + 2*ySize, p.pixel(i, j)); } } } else { opengl.setFixedSize(imageWidth, imageHeight); bms->setToStandardView(MAIN_WINDOW_INDEX, view); // // Render the image // opengl.drawToImage(&brainSet, bms, image); } // // save the image file // if (saveImageToFile) { if (image.save(imageFileName, "jpg") == false) { throw CommandException("Unable to write image file: " + imageFileName); } } else { CommandImageView::displayQImage(image); } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandShowScene.h0000664000175000017500000000352311572067322025171 0ustar michaelmichael #ifndef __COMMAND_SHOW_SCENE_H__ #define __COMMAND_SHOW_SCENE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandShowScene : public CommandBase { public: // constructor CommandShowScene(); // destructor ~CommandShowScene(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; /// command requires GUI flag sent to QApplication to be true virtual bool getHasGUI() const { return true; } protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SHOW_SCENE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandShowScene.cxx0000664000175000017500000002726411572067322025554 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelOpenGL.h" #include "BrainModelVolume.h" #include "BrainSet.h" #include "CommandImageView.h" #include "CommandShowScene.h" #include "DebugControl.h" #include "FileFilters.h" #include "ImageFile.h" #include "OffScreenOpenGLWidget.h" #include "PreferencesFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SceneFile.h" #include "SpecFile.h" /** * constructor. */ CommandShowScene::CommandShowScene() : CommandBase("-show-scene", "SHOW SCENE") { } /** * destructor. */ CommandShowScene::~CommandShowScene() { } /** * get the script builder parameters. */ void CommandShowScene::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Spec File Name", FileFilters::getSpecFileFilter()); paramsOut.addFile("Scene File Name", FileFilters::getSceneFileFilter()); paramsOut.addString("Scene Name or Number (1..N)", "1"); paramsOut.addVariableListOfParameters("Optional parameters"); } /** * get full help information. */ QString CommandShowScene::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-image-file image-file-name images-per-row] \n" + indent9 + "\n" + indent9 + "Render an image of a scene into an image file.\n" + indent9 + "Note: the scene numbers start at one.\n" + indent9 + "\n" + indent9 + "If the \"scene-name-or-number\" is numeric it is interpreted\n" + indent9 + "to be the index of the scene (1..N) in the scene file. \n" + indent9 + "Otherwise, it is interpreted to be the name of the scene.\n" + indent9 + "\n" + indent9 + "If the \"-image-file\" option is specified, the images of\n" + indent9 + "the main and viewing windows will be placed into an image\n" + indent9 + "file. \"images-per-row\" specifies how the images (if there\n" + indent9 + "are viewing windows displayed in the scene) will be layed\n" + indent9 + "out.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandShowScene::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { int imageWidth = 512; int imageHeight = 512; // // Get the spec file name // const QString specFileName = parameters->getNextParameterAsString("Spec File Name"); // // Get the scene file name // const QString sceneFileName = parameters->getNextParameterAsString("Scene File Name"); // // Get the scene name or number // const QString sceneNameOrNumber = parameters->getNextParameterAsString("Scene Name or Number"); // // Save image to a file ?? // bool saveImageToFile = false; QString imageFileName; int imagesPerRow = 1; while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("Parameter"); // // Image file name // if (paramName == "-image-file") { imageFileName = parameters->getNextParameterAsString("Image File Name"); imagesPerRow = parameters->getNextParameterAsInt("Images Per Row"); saveImageToFile = true; } else { throw CommandException("Unrecognized parameter: " + paramName); } } // // Read in the spec file // SpecFile specFile; specFile.readFile(specFileName); // // Deselect all files in spec file and add scene file // specFile.setAllFileSelections(SpecFile::SPEC_FALSE); specFile.addToSpecFile(SpecFile::getSceneFileTag(), sceneFileName, "", false); // // Read the spec file into a brain set // QString errorMessage; BrainSet brainSet; if (brainSet.readSpecFile(specFile, specFileName, errorMessage)) { throw CommandException("reading spec file " + specFileName + "\n" + errorMessage.toAscii().constData()); } // // Get the scene file // SceneFile* sceneFile = brainSet.getSceneFile(); const int numScenes = sceneFile->getNumberOfScenes(); if (numScenes <= 0) { throw CommandException("Scene file contains no scenes."); } SceneFile::Scene* scene = NULL; // // Get the number of the scene // bool ok = false; int sceneNumber = sceneNameOrNumber.toInt(&ok); if (ok) { if ((sceneNumber < 1) || (sceneNumber > numScenes)) { throw CommandException("Invalid scene number: " + QString::number(sceneNumber) + "\n Valid Scene Numbers range from 1 to " + QString::number(numScenes)); } // // Users enter scene numbers 1 to N but C++ indexes 0 to N-1 // sceneNumber--; scene = sceneFile->getScene(sceneNumber); } else { // // get number of scene from name // scene = sceneFile->getSceneFromName(sceneNameOrNumber); if (scene == NULL) { throw CommandException("No scene named \"" + sceneNameOrNumber + "\" was found."); } } // // Show number of scene // if (DebugControl::getDebugOn()) { std::cout << "Showing scene num=" << (sceneNumber + 1) <<": " << sceneFile->getScene(sceneNumber)->getName().toAscii().constData() << std::endl; } // // Setup the scene // QString sceneErrorMessage, sceneWarningMessage; brainSet.showScene(scene, false, sceneErrorMessage, sceneWarningMessage); // // Contains images captured of all windows // std::vector capturedImages; // // Loop through main and viewing windows // for (int windowNumber = 0; windowNumber < BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS; windowNumber++) { // // Get the brain model for the main window in the scene // QString modelError; int geometry[4]; int glWidthWidthHeight[2]; bool yokeFlag; BrainModel* brainModel = brainSet.showSceneGetBrainModel(scene, windowNumber, geometry, glWidthWidthHeight, yokeFlag, modelError); // // Was there a brain window in "window number" window // if (brainModel == NULL) { continue; } if (modelError.isEmpty() == false) { sceneErrorMessage += modelError; } // // Copy the transforms from "windowNumber" to window number 0 // since all image captures are performed in the "main window => 0" // brainModel->setTransformationsAsString(0, brainModel->getTransformationsAsString(windowNumber)); BrainModelVolume* bmv = dynamic_cast(brainModel); if (bmv != NULL) { int slices[3]; bmv->getSelectedOrthogonalSlices(windowNumber, slices); bmv->setSelectedOrthogonalSlices(0, slices); bmv->setViewStereotaxicCoordinatesFlag(0, bmv->getViewStereotaxicCoordinatesFlag(windowNumber)); bmv->setObliqueTransformationsAsString(0, bmv->getObliqueTransformationsAsString(windowNumber)); bmv->getSelectedObliqueSliceOffsets(windowNumber, slices); bmv->setSelectedObliqueSliceOffsets(0, slices); bmv->setSelectedAxis(0, bmv->getSelectedAxis(windowNumber)); } // // Use scene window size for image size // note that height includes the toolbar and window title bar so shrink height some // imageWidth = geometry[2]; imageHeight = geometry[3]; if ((glWidthWidthHeight[0] > 0) && (glWidthWidthHeight[1] > 0)) { imageWidth = glWidthWidthHeight[0]; imageHeight = glWidthWidthHeight[1]; } else { if (imageHeight > 200) { imageHeight -= 100; } } // // setup the off screen renderer // QImage image; OffScreenOpenGLWidget opengl; opengl.setFixedSize(imageWidth, imageHeight); // // Render the image // opengl.drawToImage(&brainSet, brainModel, image); // // Track the image // capturedImages.push_back(image); } // // Get background color // const PreferencesFile* pf = brainSet.getPreferencesFile(); unsigned char r, g, b; pf->getSurfaceBackgroundColor(r, g, b); const int backgroundColor[3] = { r, g, b }; // // Combine the images // QImage outputImage; ImageFile::combinePreservingAspectAndFillIfNeeded(capturedImages, imagesPerRow, backgroundColor, outputImage); ImageFile outputImageFile; outputImageFile.setImage(outputImage); // // Write the image file // if (saveImageToFile) { try { outputImageFile.writeFile(imageFileName); } catch (FileException& e) { sceneErrorMessage += e.whatQString(); } //if (outputImageFile.getImage()->save(imageFileName, "jpg") == false) { // throw CommandException("Unable to write image file: " + imageFileName); //} } else { CommandImageView::displayQImage(*outputImageFile.getImage()); } if (sceneWarningMessage.isEmpty() == false) { std::cout << getShortDescription().toAscii().constData() << " WARNING: " << sceneWarningMessage.toAscii().constData() << std::endl; } if (sceneErrorMessage.isEmpty() == false) { throw CommandException(sceneErrorMessage); } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandScriptVariableSet.h0000664000175000017500000000414511572067322026662 0ustar michaelmichael #ifndef __COMMAND_SCRIPT_VARIABLE_SET_H__ #define __COMMAND_SCRIPT_VARIABLE_SET_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandScriptVariableSet : public CommandBase { public: // constructor CommandScriptVariableSet(); // destructor ~CommandScriptVariableSet(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; /// get the variable's name QString getVariableName() const { return variableName; } /// get the variable's value QString getVariableValue() const { return variableValue; } protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); /// the name of the variable QString variableName; /// the value of the variable QString variableValue; }; #endif // __COMMAND_SCRIPT_VARIABLE_SET_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandScriptVariableSet.cxx0000664000175000017500000000644311572067322027240 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandScriptVariableSet.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandScriptVariableSet::CommandScriptVariableSet() : CommandBase("-script-variable-set", "SCRIPT VARIABLE SET") { } /** * destructor. */ CommandScriptVariableSet::~CommandScriptVariableSet() { } /** * get the script builder parameters. */ void CommandScriptVariableSet::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { QStringList allFilters; FileFilters::getAllFileFilters(allFilters); paramsOut.clear(); paramsOut.addString("Variable Name", "$name"); paramsOut.addFile("Variable Value", allFilters, "value"); } /** * get full help information. */ QString CommandScriptVariableSet::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + " \n" + indent9 + "Set a variable for use in a caret script file. \n" + indent9 + " \n" + indent9 + "The variable name must begin with a \"$\" symbol. \n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandScriptVariableSet::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { variableName = parameters->getNextParameterAsString("Variable Name"); variableValue = parameters->getNextParameterAsString("Variable Value"); checkForExcessiveParameters(); if (variableName.isEmpty()) { throw CommandException("Variable Name is empty."); } if (variableName[0] != '$') { throw CommandException("Variable Name (" + variableName + ") must begin with \"$\" symbol."); } if (variableValue.isEmpty() == false) { if (variableValue[0] == '$') { throw CommandException("Variable Name (" + variableName + ") cannot have a value that is another variable."); } } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandScriptVariableRead.h0000664000175000017500000000413211572067322026776 0ustar michaelmichael #ifndef __COMMAND_SCRIPT_VARIABLE_READ_H__ #define __COMMAND_SCRIPT_VARIABLE_READ_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandScriptVariableRead : public CommandBase { public: // constructor CommandScriptVariableRead(); // destructor ~CommandScriptVariableRead(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; /// get the variable's name QString getVariableName() const { return variableName; } /// get the prompt QString getPromptMessage() const { return promptMessage; } protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); /// the name of the variable QString variableName; /// the prompt message QString promptMessage; }; #endif // __COMMAND_SCRIPT_VARIABLE_READ_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandScriptVariableRead.cxx0000664000175000017500000000577111572067322027363 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandScriptVariableRead.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandScriptVariableRead::CommandScriptVariableRead() : CommandBase("-script-variable-read", "SCRIPT VARIABLE READ") { } /** * destructor. */ CommandScriptVariableRead::~CommandScriptVariableRead() { } /** * get the script builder parameters. */ void CommandScriptVariableRead::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addString("Variable Name"); paramsOut.addString("Prompt Message"); } /** * get full help information. */ QString CommandScriptVariableRead::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Request the user to enter a value.\n" + indent9 + "\n" + indent9 + "If the \"prompt-message\" contains spaces, it must be\n" + indent9 + "enclosed in double quotes.\n" + indent9 + "\n" + indent9 + "When entering variable values, Bource and C-Shell scripts\n" + indent9 + "do not allow spaces in the value that is entered. DOS and\n" + indent9 + "Python allow spaces only if the value is enclosed in \n" + indent9 + "double quotes.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandScriptVariableRead::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the parameters // variableName = parameters->getNextParameterAsString("Variable Name"); promptMessage = parameters->getNextParameterAsString("Prompt Message"); checkForExcessiveParameters(); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandScriptRun.h0000664000175000017500000000333011572067322025220 0ustar michaelmichael #ifndef __COMMAND_SCRIPT_RUN_H__ #define __COMMAND_SCRIPT_RUN_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandScriptRun : public CommandBase { public: // constructor CommandScriptRun(); // destructor ~CommandScriptRun(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SCRIPT_RUN_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandScriptRun.cxx0000664000175000017500000000717111572067322025602 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "CaretScriptFile.h" #include "CommandScriptRun.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandScriptRun::CommandScriptRun() : CommandBase("-script-run", "SCRIPT RUN") { } /** * destructor. */ CommandScriptRun::~CommandScriptRun() { } /** * get the script builder parameters. */ void CommandScriptRun::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Caret Script File", FileFilters::getCaretScriptFileFilter()); } /** * get full help information. */ QString CommandScriptRun::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "[-gui] \n" + indent9 + "\n" + indent9 + "Run a caret script file.\n" + indent9 + "\n" + indent9 + "If the \"-gui\" option is specified, a progress dialog\n" + indent9 + "is shown when the script executes and the user is \n" + indent9 + "is prompted for any inputs via a dialog.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandScriptRun::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the parameters // const QString scriptFileName = parameters->getNextParameterAsString("Script File Name"); bool useGUI = false; while (parameters->getParametersAvailable()) { const QString param = parameters->getNextParameterAsString("Script Run Parameter"); if (param == "-gui") { useGUI = true; } else { throw CommandException("Unrecognized parameter: " + param); } } // // Read the script file // CaretScriptFile scriptFile; scriptFile.readFile(scriptFileName); // // Use GUI? // QWidget* w = NULL; if (useGUI) { w = new QWidget; } // // Execute the script file // QString textOutput; scriptFile.runCommandsInFile(w, parameters->getProgramNameWithPath(), textOutput); // // Close widget // if (w != NULL) { w->close(); delete w; w = NULL; } // // Print the output // std::cout << textOutput.toAscii().constData() << std::endl; } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandScriptConvert.h0000664000175000017500000000407011572067322026076 0ustar michaelmichael #ifndef __COMMAND_SCRIPT_CONVERT_H__ #define __COMMAND_SCRIPT_CONVERT_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandScriptConvert : public CommandBase { public: // constructor CommandScriptConvert(); // destructor ~CommandScriptConvert(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: /// output file type enum OUTPUT_FILE_TYPE { /// unix bourne shell OUTPUT_FILE_TYPE_BOURNE_SHELL, /// unix C shell OUTPUT_FILE_TYPE_C_SHELL, /// DOS (windows) shell OUTPUT_FILE_TYPE_DOS_SHELL, /// Python OUTPUT_FILE_TYPE_PYTHON }; // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SCRIPT_CONVERT_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandScriptConvert.cxx0000664000175000017500000004630611572067322026461 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "CaretScriptFile.h" #include "CommandScriptComment.h" #include "CommandScriptConvert.h" #include "CommandScriptVariableRead.h" #include "CommandScriptVariableSet.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "TextFile.h" /** * constructor. */ CommandScriptConvert::CommandScriptConvert() : CommandBase("-script-convert", "SCRIPT CONVERT") { } /** * destructor. */ CommandScriptConvert::~CommandScriptConvert() { } /** * get the script builder parameters. */ void CommandScriptConvert::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { QStringList shellFilters; shellFilters << FileFilters::getAnyFileFilter(); shellFilters << FileFilters::getBourneShellFileFilter(); shellFilters << FileFilters::getCShellFileFilter(); shellFilters << FileFilters::getWindowsBATFileFilter(); shellFilters << FileFilters::getPythonFileFilter(); paramsOut.clear(); paramsOut.addFile("Input Caret Script File Name", FileFilters::getCaretScriptFileFilter()); paramsOut.addFile("Output Shell File Name", shellFilters); paramsOut.addVariableListOfParameters("Options"); } /** * get full help information. */ QString CommandScriptConvert::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + " [-interpreter interpreter-name]\n" + indent9 + "\n" + indent9 + "Create a scripting language file from the commands \n" + indent9 + "contained in a caret script file.\n" + indent9 + "\n" + indent9 + "The scripting language is determined by the filename \n" + indent9 + "extension of the output file name. \n" + indent9 + " file-name scripting default\n" + indent9 + " extension language interpreter\n" + indent9 + " --------- --------- -----------\n" + indent9 + " .bat DOS Windows BAT File\n" + indent9 + " .csh C-Shell /bin/csh \n" + indent9 + " .py Python /usr/bin/python \n" + indent9 + " .sh bourne shell /bin/sh \n" + indent9 + "\n" + indent9 + "WARNING: The C-Shell appears to limit variable names to a\n" + indent9 + "maximum length of 31 characters.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandScriptConvert::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the parameters // const QString inputCaretScriptFileName = parameters->getNextParameterAsString("Input Caret Script File Name"); const QString outputFileName = parameters->getNextParameterAsString("Output File Name"); QString interpreterOverrideName; while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("Script Convert Parameter"); if (paramName == "-interpreter") { interpreterOverrideName = parameters->getNextParameterAsString("Interpreter Name"); } else { throw CommandException("Unrecognized parameter: " + paramName); } } // // Check the output file type // QString interpreterName; OUTPUT_FILE_TYPE outputFileType; if (outputFileName.endsWith(".sh")) { interpreterName = "#!/bin/sh"; outputFileType = OUTPUT_FILE_TYPE_BOURNE_SHELL; } else if (outputFileName.endsWith(".csh")) { interpreterName = "#!/bin/csh"; outputFileType = OUTPUT_FILE_TYPE_C_SHELL; } else if (outputFileName.endsWith(".bat")) { outputFileType = OUTPUT_FILE_TYPE_DOS_SHELL; } else if (outputFileName.endsWith(".py")) { interpreterName = "#!/usr/bin/python"; outputFileType = OUTPUT_FILE_TYPE_PYTHON; } else { throw CommandException("Invalid output file name extension: " + outputFileName); } // // Possibly override name of interpreter // if (interpreterOverrideName.isEmpty() == false) { interpreterName = interpreterOverrideName; } // // Read the Caret script file // CaretScriptFile scriptFile; scriptFile.readFile(inputCaretScriptFileName); // // Create a text file // TextFile textFile; // // Variable name of caret command program // QString caretCommandProgramVariableName("CARET_COMMAND_PROGRAM"); // // Add the appropriate interpreter as the first line // switch (outputFileType) { case OUTPUT_FILE_TYPE_BOURNE_SHELL: textFile.appendLine(interpreterName); textFile.appendLine(" "); textFile.appendLine(caretCommandProgramVariableName + "=\"" + parameters->getProgramNameWithoutPath() + "\""); textFile.appendLine(" "); caretCommandProgramVariableName.insert(0, "${"); caretCommandProgramVariableName += "}"; break; case OUTPUT_FILE_TYPE_C_SHELL: textFile.appendLine(interpreterName); textFile.appendLine(" "); textFile.appendLine("set " + caretCommandProgramVariableName + "=\"" + parameters->getProgramNameWithoutPath() + "\""); textFile.appendLine(" "); caretCommandProgramVariableName.insert(0, "${"); caretCommandProgramVariableName += "}"; break; case OUTPUT_FILE_TYPE_DOS_SHELL: textFile.appendLine(interpreterName); textFile.appendLine("set " + caretCommandProgramVariableName + "=\"" + parameters->getProgramNameWithoutPath() + "\""); textFile.appendLine(" "); caretCommandProgramVariableName.insert(0, "%"); caretCommandProgramVariableName += "%"; break; case OUTPUT_FILE_TYPE_PYTHON: textFile.appendLine(interpreterName); textFile.appendLine(""); textFile.appendLine("import os"); textFile.appendLine("import sys"); textFile.appendLine(""); textFile.appendLine(caretCommandProgramVariableName + " = \"" + parameters->getProgramNameWithoutPath() + "\""); textFile.appendLine(" "); break; } // // Switches for some commands // CommandScriptComment scriptComment; const QString commentSwitch = scriptComment.getOperationSwitch(); CommandScriptVariableSet scriptSetVariable; const QString variableSetSwitch = scriptSetVariable.getOperationSwitch(); CommandScriptVariableRead scriptVariableRead; const QString variableReadSwitch = scriptVariableRead.getOperationSwitch(); // // Loop through the operations // const int num = scriptFile.getNumberOfCommandOperations(); for (int i = 0; i < num; i++) { // // Get the command // CaretScriptFile::CaretCommandOperation* op = scriptFile.getCommandOperation(i); // // Add the comment // switch (outputFileType) { case OUTPUT_FILE_TYPE_BOURNE_SHELL: case OUTPUT_FILE_TYPE_C_SHELL: case OUTPUT_FILE_TYPE_PYTHON: textFile.appendLine("#\n# " + op->getComment() + "\n#"); break; case OUTPUT_FILE_TYPE_DOS_SHELL: textFile.appendLine("REM\nREM " + op->getComment() + "\nREM"); break; } // // Special handle comment and variable read/set // if (op->getSwitch() == variableReadSwitch) { const QStringList params = op->getParametersForGUI(); if (params.count() < 2) { throw CommandException("Parameters missing for variable read (command #" + QString::number(i + 1) + ": \"" + params.join(" ") + "\""); } const QString varName = params.at(0); const QString promptString = params.at(1); if (varName.isEmpty()) { throw CommandException("Missing variable name for variable read (command #" + QString::number(i + 1) + ")"); } if (varName.isEmpty()) { throw CommandException("Missing prompt string for variable read (command #" + QString::number(i + 1) + ")"); } switch (outputFileType) { case OUTPUT_FILE_TYPE_BOURNE_SHELL: textFile.appendLine("echo \"" + promptString + "\""); textFile.appendLine("read " + varName.mid(1)); break; case OUTPUT_FILE_TYPE_C_SHELL: textFile.appendLine("echo \"" + promptString + "\""); textFile.appendLine("set " + varName.mid(1) + "=$<"); break; case OUTPUT_FILE_TYPE_DOS_SHELL: textFile.appendLine("set /p " + varName.mid(1) // remove '$' character + "=\"" + promptString + " "); break; case OUTPUT_FILE_TYPE_PYTHON: textFile.appendLine("print \"" + promptString + "\""); textFile.appendLine(varName.mid(1) + " = sys.stdin.readline()"); break; } } else if (op->getSwitch() == variableSetSwitch) { const QStringList params = op->getParametersForGUI(); if (params.count() < 2) { throw CommandException("Parameters missing for variable set (command #" + QString::number(i + 1) + ": \"" + params.join(" ") + "\""); } const QString varName = params.at(0); const QString varValue = params.at(1); if (varName.isEmpty()) { throw CommandException("Missing variable name for variable set (command #" + QString::number(i + 1) + ")"); } if (varValue.isEmpty()) { throw CommandException("Missing variable value for variable set (command #" + QString::number(i + 1) + ")"); } switch (outputFileType) { case OUTPUT_FILE_TYPE_BOURNE_SHELL: textFile.appendLine(varName.mid(1) // remove '$' character + "=\"" + varValue + "\""); break; case OUTPUT_FILE_TYPE_C_SHELL: textFile.appendLine("set " + varName.mid(1) // remove '$' character + "=\"" + varValue + "\""); if (varName.mid(1).length() > 31) { std::cout << "WARNING: variable named \"" << varName.toAscii().constData() << "\" is more than 31 characters which may not be " << "accepted by the C-Shell." << std::endl; } break; case OUTPUT_FILE_TYPE_DOS_SHELL: textFile.appendLine("set " + varName.mid(1) // remove '$' character + "=\"" + varValue + "\""); break; case OUTPUT_FILE_TYPE_PYTHON: textFile.appendLine(varName.mid(1) // remove '$' character + " = \"" + varValue + "\""); break; } } else if (op->getSwitch() == commentSwitch) { const QStringList params = op->getParametersForGUI(); if (params.count() > 0) { const QStringList commentLines = params.at(0).split('\n'); switch (outputFileType) { case OUTPUT_FILE_TYPE_BOURNE_SHELL: case OUTPUT_FILE_TYPE_C_SHELL: case OUTPUT_FILE_TYPE_PYTHON: textFile.appendLine("#"); for (int j = 0; j < commentLines.count(); j++) { textFile.appendLine("# " + commentLines.at(j)); } textFile.appendLine("#"); break; case OUTPUT_FILE_TYPE_DOS_SHELL: textFile.appendLine("REM"); for (int j = 0; j < commentLines.count(); j++) { textFile.appendLine("REM " + commentLines.at(j)); } textFile.appendLine("REM"); break; } } } else { // // Continue to next line character and newline // QString linePrefix; QString lineSuffix; QString continueToNextLine(" \\\n"); QString opSwitchPrefix; QString opSwitchSuffix; QString programSuffix; switch (outputFileType) { case OUTPUT_FILE_TYPE_BOURNE_SHELL: case OUTPUT_FILE_TYPE_C_SHELL: continueToNextLine= " \\\n"; break; case OUTPUT_FILE_TYPE_DOS_SHELL: continueToNextLine = ""; break; case OUTPUT_FILE_TYPE_PYTHON: linePrefix = "os.system(\" \".join(("; lineSuffix = ")))"; continueToNextLine= " \\\n"; opSwitchPrefix = "\""; opSwitchSuffix = "\","; programSuffix = ","; break; } // // Create the line for execution // QString line(linePrefix); line += (caretCommandProgramVariableName + programSuffix + continueToNextLine); line += (" " + opSwitchPrefix + op->getSwitch() + opSwitchSuffix + continueToNextLine); const QStringList paramList = op->getParametersForCommandExecution(); for (int i = 0; i < paramList.count(); i++) { QString param = paramList.at(i); const int paramLength = param.length(); if (paramLength <= 0) { throw CommandException("parameter is blank for \"" + op->getSwitch() + "\" (command #" + QString::number(i + 1) + ")"); } // // Is this a variable // if (param[0] == '$') { switch (outputFileType) { case OUTPUT_FILE_TYPE_BOURNE_SHELL: case OUTPUT_FILE_TYPE_C_SHELL: param.insert(1, "{"); param += "}"; break; case OUTPUT_FILE_TYPE_DOS_SHELL: param = ("%" + param.mid(1) // remove '$' + "%"); break; case OUTPUT_FILE_TYPE_PYTHON: param = param.mid(1); // remove '$' break; } } else { switch (outputFileType) { case OUTPUT_FILE_TYPE_BOURNE_SHELL: break; case OUTPUT_FILE_TYPE_C_SHELL: break; case OUTPUT_FILE_TYPE_DOS_SHELL: break; case OUTPUT_FILE_TYPE_PYTHON: // // If parameter is in quotes add another set // if (param.startsWith("\"")) { param.insert(param.length() - 1, "\\\""); param.insert(1, "\\\""); } else { param = "\"" + param + "\""; } break; } } switch (outputFileType) { case OUTPUT_FILE_TYPE_BOURNE_SHELL: break; case OUTPUT_FILE_TYPE_C_SHELL: break; case OUTPUT_FILE_TYPE_DOS_SHELL: break; case OUTPUT_FILE_TYPE_PYTHON: if (i < (paramList.count() - 1)) { param += ","; } break; } if (i < (paramList.count() - 1)) { param += continueToNextLine; } line += (" " + param); } // // add suffix to line // line += lineSuffix; // // Add to output file // textFile.appendLine(line); } // // Add blank line // textFile.appendLine(" "); } // // Write the output file // textFile.writeFile(outputFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandScriptComment.h0000664000175000017500000000336011572067322026061 0ustar michaelmichael #ifndef __COMMAND_SCRIPT_COMMENT_H__ #define __COMMAND_SCRIPT_COMMENT_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandScriptComment : public CommandBase { public: // constructor CommandScriptComment(); // destructor ~CommandScriptComment(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_SCRIPT_COMMENT_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandScriptComment.cxx0000664000175000017500000000443711572067322026442 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandScriptComment.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandScriptComment::CommandScriptComment() : CommandBase("-script-comment", "SCRIPT COMMENT") { } /** * destructor. */ CommandScriptComment::~CommandScriptComment() { } /** * get the script builder parameters. */ void CommandScriptComment::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addVariableListOfParameters("Comment"); } /** * get full help information. */ QString CommandScriptComment::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "This operation does nothing but is used by the script\n" + indent9 + "builder for inserting comments into scripts\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandScriptComment::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSceneCreate.h0000664000175000017500000000702311572067322025453 0ustar michaelmichael #ifndef __COMMAND_SCENE_CREATE_H__ #define __COMMAND_SCENE_CREATE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModel.h" #include "CommandBase.h" #include "VolumeFile.h" class BrainModelSurface; class BrainSet; /// class for creating scenes class CommandSceneCreate : public CommandBase { public: // constructor CommandSceneCreate(); // destructor ~CommandSceneCreate(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); // get surface standard view from its name BrainModel::STANDARD_VIEWS getSurfaceStandardView(const QString& viewName) const throw (CommandException); // get the number of a window from its name int getWindowNumber(const QString& windowName) const throw (CommandException); // set the default window scaling void setWindowScaling(BrainSet& bs, const int sizeX, const int sizeY); // find a brain model surface BrainModelSurface* findBrainModelSurface(BrainSet& bs, const QString& coordFileName, const QString& topoFileName) const throw (CommandException); // find a brain model surface from types BrainModelSurface* findBrainModelSurfaceFromTypes(BrainSet& bs, const QString& coordFileType, const QString& topoFileType) const throw (CommandException); // select a volume of the specified type void selectVolumeOfType(BrainSet& brainSet, const VolumeFile::VOLUME_TYPE volumeType, const QString& volumeFileName, const int subVolumeNumber, const bool functionalThresholdFlag = false) throw (CommandException); }; #endif // __COMMAND_SCENE_CREATE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandSceneCreate.cxx0000664000175000017500000012150011572067322026023 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelOpenGL.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceOverlay.h" #include "BrainModelVolume.h" #include "BrainModelVolumeVoxelColoring.h" #include "BrainSet.h" #include "CommandSceneCreate.h" #include "CoordinateFile.h" #include "DisplaySettingsBorders.h" #include "DisplaySettingsCells.h" #include "DisplaySettingsFoci.h" #include "DisplaySettingsVolume.h" #include "FileFilters.h" #include "FileUtilities.h" #include "MetricFile.h" #include "PaintFile.h" #include "ProbabilisticAtlasFile.h" #include "ProgramParameters.h" #include "RgbPaintFile.h" #include "ScriptBuilderParameters.h" #include "SpecFile.h" #include "SurfaceShapeFile.h" #include "TopologyFile.h" #include "VolumeFile.h" /** * constructor. */ CommandSceneCreate::CommandSceneCreate() : CommandBase("-scene-create", "SCENE CREATION") { } /** * destructor. */ CommandSceneCreate::~CommandSceneCreate() { } /** * get the script builder parameters. */ void CommandSceneCreate::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Spec File", FileFilters::getSpecFileFilter()); paramsOut.addFile("Input Scene File Name", FileFilters::getSceneFileFilter()); paramsOut.addFile("Output Scene File Name", FileFilters::getSceneFileFilter()); paramsOut.addString("Scene Name", "scene"); paramsOut.addVariableListOfParameters("Scene Parameters"); } /** * get full help information. */ QString CommandSceneCreate::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-surface-overlay \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " ]\n" + indent9 + "[-show-borders]\n" + indent9 + "[-show-cells]\n" + indent9 + "[-show-foci]\n" + indent9 + "[-volume-overlay \n" + indent9 + " ]\n" + indent9 + "[-volume-overlay-anatomy \n" + indent9 + " ]\n" + indent9 + "[-volume-overlay-functional-view \n" + indent9 + " ]\n" + indent9 + "[-volume-overlay-functional-thresh \n" + indent9 + " ]\n" + indent9 + "[-volume-overlay-paint \n" + indent9 + " ]\n" + indent9 + "[-volume-overlay-rgb \n" + indent9 + " ]\n" + indent9 + "[-volume-overlay-segmentation \n" + indent9 + " ]\n" + indent9 + "[-volume-overlay-vector \n" + indent9 + " ]\n" + indent9 + "[-window-surface-files \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " ]\n" + indent9 + "[-window-surface-types \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " ]\n" + indent9 + "[-window-volume-slice \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " ]\n" + indent9 + "[-window-volume-coord \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " ]\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Create a scene.\n" + indent9 + "\n" + indent9 + "Note that ALL files in the spec file will be loaded\n" + indent9 + "when the scene is loaded.\n" + indent9 + "\n" + indent9 + "If the scene name already exists, that scene will be \n" + indent9 + "replaced.\n" + indent9 + "\n" + indent9 + "\"surface-overlay-name\" is one of:\n" + indent9 + " PRIMARY\n" + indent9 + " SECONDARY\n" + indent9 + " TERTIARY\n" + indent9 + " UNDERLAY\n" + indent9 + "\n" + indent9 + "\"surface-overlay-data-type-name\"\n" + indent9 + " CROSSOVERS\n" + indent9 + " METRIC\n" + indent9 + " NONE\n" + indent9 + " PAINT\n" + indent9 + " PROBABILISTIC_ATLAS\n" + indent9 + " RGB_PAINT\n" + indent9 + " SURFACE_SHAPE\n" + indent9 + "\n" + indent9 + "Both \"-surface-overlay-data-display-column-name-or-number\"\n" + indent9 + "and \"-surface overlay-data-threshold-column-name-or-number\"\n" + indent9 + "may be either a column number, which starts at 1, or the name\n" + indent9 + "ofthe data column. Since all files are loaded by this \n" + indent9 + "command, column numbers should not be used when there are\n" + indent9 + "are multiple files for a data type as the order in which\n" + indent9 + "the files are loaded may change affecting the column orders.\n" + indent9 + "\n" + indent9 + "If an overlay data type does not use the display or \n" + indent9 + "threshold column, enter any value such as \"-1\".\n" + indent9 + "\n" + indent9 + "\"volume-overlay-name\" is one of:\n" + indent9 + " PRIMARY\n" + indent9 + " SECONDARY\n" + indent9 + " UNDERLAY\n" + indent9 + "\n" + indent9 + "\"volume-overlay-name\" is one of:\n" + indent9 + " ANATOMY\n" + indent9 + " FUNCTIONAL\n" + indent9 + " NONE\n" + indent9 + " PAINT\n" + indent9 + " PROBABILISTIC_ATLAS\n" + indent9 + " RGB\n" + indent9 + " SEGMENTATION\n" + indent9 + " VECTOR\n" + indent9 + "\n" + indent9 + "\"sub-volume-number\" ranges from 1 to the number of sub-\n" + indent9 + "volumes contained in the volume file.\n" + indent9 + "\n" + indent9 + "\"volume-view-name\" is one of:\n" + indent9 + " PARASAGITTAL\n" + indent9 + " CORONAL\n" + indent9 + " HORIZONTAL\n" + indent9 + "\n" + indent9 + "Use \"-window-surface-files\" to specify specific \n" + indent9 + "coordinate and topology files for a surface.\n" + indent9 + "\n" + indent9 + "Use \"-window-surface-type\" to use the first coordinate\n" + indent9 + "and topoogy files of the specified types as sorted by date.\n" + indent9 + "\n" + indent9 + "\"window-name\" is one of:\n" + indent9 + " WINDOW_MAIN\n" + indent9 + " WINDOW_2\n" + indent9 + " WINDOW_3\n" + indent9 + " WINDOW_4\n" + indent9 + " WINDOW_5\n" + indent9 + " WINDOW_6\n" + indent9 + " WINDOW_7\n" + indent9 + " WINDOW_8\n" + indent9 + " WINDOW_9\n" + indent9 + " WINDOW_10\n" + indent9 + "\n" + indent9 + "\"coordinate-file-type\" is one of:\n" + indent9 + " CMW\n" + indent9 + " ELLIPSOIDAL\n" + indent9 + " FIDUCIAL\n" + indent9 + " FLAT\n" + indent9 + " FLAT_LOBAR\n" + indent9 + " HULL\n" + indent9 + " INFLATED\n" + indent9 + " RAW\n" + indent9 + " SPHERICAL\n" + indent9 + " VERY_INFLATED\n" + indent9 + "\n" + indent9 + "\"topology-file-type\" is one of:\n" + indent9 + " CLOSED\n" + indent9 + " CUT\n" + indent9 + " OPEN\n" + indent9 + "\n" + indent9 + "\"surface-view-name\" is one of:\n" + indent9 + " ANTERIOR\n" + indent9 + " DEFAULT\n" + indent9 + " DORSAL\n" + indent9 + " LATERAL\n" + indent9 + " MEDIAL\n" + indent9 + " POSTERIOR\n" + indent9 + " VENTRAL\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandSceneCreate::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString specFileName = parameters->getNextParameterAsString("Spec File Name"); const QString inputSceneFileName = parameters->getNextParameterAsString("Input Scene File Name"); const QString outputSceneFileName = parameters->getNextParameterAsString("Output Scene File Name"); const QString sceneName = parameters->getNextParameterAsString("Scene Name"); // // Read the spec file and select all files except scenes // SpecFile specFile; specFile.readFile(specFileName); specFile.setAllFileSelections(SpecFile::SPEC_TRUE); specFile.sceneFile.setAllSelections(SpecFile::SPEC_FALSE); if (inputSceneFileName.isEmpty() == false) { specFile.addToSpecFile(SpecFile::getSceneFileTag(), inputSceneFileName, "", false); } // // Read all files in the spec file // QString errorMessage; BrainSet brainSet(true); brainSet.readSpecFile(specFile, specFileName, errorMessage); if (errorMessage.isEmpty() == false) { throw CommandException(errorMessage); } // // For each window, main and viewing // std::vector windowSceneClasses; // // Check the optional parameters // while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("Optional Parameter"); if (paramName == "-surface-overlay") { const QString surfaceOverlayName = parameters->getNextParameterAsString("Surface Overlay Name"); const QString surfaceOverlayDataTypeName = parameters->getNextParameterAsString("Surface Overlay Data Type Name"); const QString surfaceOverlayDisplayColumnNameNumber = parameters->getNextParameterAsString("Surface Overlay Display Columnn Name/Number"); const QString surfaceOverlayThresholdColumnNameNumber = parameters->getNextParameterAsString("Surface Overlay Threshold Column Name/Number"); BrainModelSurfaceOverlay* surfaceOverlay = NULL; if (surfaceOverlayName == "PRIMARY") { surfaceOverlay = brainSet.getPrimarySurfaceOverlay(); } else if (surfaceOverlayName == "SECONDARY") { surfaceOverlay = brainSet.getSecondarySurfaceOverlay(); } else if (surfaceOverlayName == "TERTIARY") { if (brainSet.getNumberOfSurfaceOverlays() > 3) { surfaceOverlay = brainSet.getSurfaceOverlay(brainSet.getNumberOfSurfaceOverlays() - 3); } else { throw CommandException("Tertiary overlay not supported in this command."); } } else if (surfaceOverlayName == "UNDERLAY") { surfaceOverlay = brainSet.getSurfaceUnderlay(); } else { throw CommandException("Invalid overlay name \"" + surfaceOverlayName + "\""); } if (surfaceOverlayDataTypeName == "CROSSOVERS") { surfaceOverlay->setOverlay(-1, BrainModelSurfaceOverlay::OVERLAY_SHOW_CROSSOVERS); } else if (surfaceOverlayDataTypeName == "METRIC") { surfaceOverlay->setOverlay(-1, BrainModelSurfaceOverlay::OVERLAY_METRIC); surfaceOverlay->setDisplayColumnSelected(-1, brainSet.getMetricFile()->getColumnFromNameOrNumber( surfaceOverlayDisplayColumnNameNumber, false)); surfaceOverlay->setThresholdColumnSelected(-1, brainSet.getMetricFile()->getColumnFromNameOrNumber( surfaceOverlayThresholdColumnNameNumber, false)); } else if (surfaceOverlayDataTypeName == "NONE") { surfaceOverlay->setOverlay(-1, BrainModelSurfaceOverlay::OVERLAY_NONE); } else if (surfaceOverlayDataTypeName == "PAINT") { surfaceOverlay->setOverlay(-1, BrainModelSurfaceOverlay::OVERLAY_PAINT); surfaceOverlay->setDisplayColumnSelected(-1, brainSet.getPaintFile()->getColumnFromNameOrNumber( surfaceOverlayDisplayColumnNameNumber, false)); } else if (surfaceOverlayDataTypeName == "PROBABILISTIC_ATLAS") { surfaceOverlay->setOverlay(-1, BrainModelSurfaceOverlay::OVERLAY_PROBABILISTIC_ATLAS); } else if (surfaceOverlayDataTypeName == "RGB_PAINT") { surfaceOverlay->setOverlay(-1, BrainModelSurfaceOverlay::OVERLAY_RGB_PAINT); surfaceOverlay->setDisplayColumnSelected(-1, brainSet.getRgbPaintFile()->getColumnFromNameOrNumber( surfaceOverlayDisplayColumnNameNumber, false)); } else if (surfaceOverlayDataTypeName == "SURFACE_SHAPE") { surfaceOverlay->setOverlay(-1, BrainModelSurfaceOverlay::OVERLAY_SURFACE_SHAPE); surfaceOverlay->setDisplayColumnSelected(-1, brainSet.getSurfaceShapeFile()->getColumnFromNameOrNumber( surfaceOverlayDisplayColumnNameNumber, false)); } else { throw CommandException("Invalid overlay data type name \"" + surfaceOverlayDataTypeName + "\""); } } else if (paramName == "-show-borders") { DisplaySettingsBorders* dsb = brainSet.getDisplaySettingsBorders(); dsb->setDisplayBorders(true); } else if (paramName == "-show-cells") { DisplaySettingsCells* dsc = brainSet.getDisplaySettingsCells(); dsc->setDisplayCells(true); } else if (paramName == "-show-foci") { DisplaySettingsFoci* dsf = brainSet.getDisplaySettingsFoci(); dsf->setDisplayCells(true); } else if (paramName == "-volume-overlay") { const QString volumeOverlayName = parameters->getNextParameterAsString("Volume Overlay Name"); const QString volumeOverlayDataTypeName = parameters->getNextParameterAsString("Volume Overlay Data Type Name"); BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_TYPE volumeOverlay; if (volumeOverlayDataTypeName == "ANATOMY") { volumeOverlay = BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_ANATOMY; } else if (volumeOverlayDataTypeName == "FUNCTIONAL") { volumeOverlay = BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_FUNCTIONAL; } else if (volumeOverlayDataTypeName == "NONE") { volumeOverlay = BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_NONE; } else if (volumeOverlayDataTypeName == "PAINT") { volumeOverlay = BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_PAINT; } else if (volumeOverlayDataTypeName == "PROBABILISTIC_ATLAS") { volumeOverlay = BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_PROB_ATLAS; } else if (volumeOverlayDataTypeName == "RGB") { volumeOverlay = BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_RGB; } else if (volumeOverlayDataTypeName == "SEGMENTATION") { volumeOverlay = BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_SEGMENTATION; } else if (volumeOverlayDataTypeName == "VECTOR") { volumeOverlay = BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_VECTOR; } else { throw CommandException("Invalid Volume Overlay Data Type Name " + volumeOverlayDataTypeName); } BrainModelVolumeVoxelColoring* voxelColoring = brainSet.getVoxelColoring(); if (volumeOverlayName == "PRIMARY") { voxelColoring->setPrimaryOverlay(volumeOverlay); } else if (volumeOverlayName == "SECONDARY") { voxelColoring->setSecondaryOverlay(volumeOverlay); } else if (volumeOverlayName == "UNDERLAY") { voxelColoring->setUnderlay(volumeOverlay); } else { throw CommandException("Invalid Volume Overlay Name " + volumeOverlayName); } } else if (paramName == "-volume-overlay-anatomy") { const QString volumeFileName = parameters->getNextParameterAsString("Anatomy Volume File Name"); const int subVolumeNumber = parameters->getNextParameterAsInt("Anatomy Sub-Volume Number"); selectVolumeOfType(brainSet, VolumeFile::VOLUME_TYPE_ANATOMY, volumeFileName, subVolumeNumber); } else if (paramName == "-volume-overlay-functional-view") { const QString volumeFileName = parameters->getNextParameterAsString("Functional View Volume File Name"); const int subVolumeNumber = parameters->getNextParameterAsInt("Functional View Sub-Volume Number"); selectVolumeOfType(brainSet, VolumeFile::VOLUME_TYPE_FUNCTIONAL, volumeFileName, subVolumeNumber); } else if (paramName == "-volume-overlay-functional-thresh") { const QString volumeFileName = parameters->getNextParameterAsString("Functional Threshold Volume File Name"); const int subVolumeNumber = parameters->getNextParameterAsInt("Functional Threshold Sub-Volume Number"); selectVolumeOfType(brainSet, VolumeFile::VOLUME_TYPE_FUNCTIONAL, volumeFileName, subVolumeNumber, true); } else if (paramName == "-volume-overlay-paint") { const QString volumeFileName = parameters->getNextParameterAsString("Paint Volume File Name"); const int subVolumeNumber = parameters->getNextParameterAsInt("Paint Sub-Volume Number"); selectVolumeOfType(brainSet, VolumeFile::VOLUME_TYPE_PAINT, volumeFileName, subVolumeNumber); } else if (paramName == "-volume-overlay-rgb") { const QString volumeFileName = parameters->getNextParameterAsString("RGB Volume File Name"); const int subVolumeNumber = parameters->getNextParameterAsInt("RGB Sub-Volume Number"); selectVolumeOfType(brainSet, VolumeFile::VOLUME_TYPE_RGB, volumeFileName, subVolumeNumber); } else if (paramName == "-volume-overlay-segmentation") { const QString volumeFileName = parameters->getNextParameterAsString("Segmentation Volume File Name"); const int subVolumeNumber = parameters->getNextParameterAsInt("Segmentation Sub-Volume Number"); selectVolumeOfType(brainSet, VolumeFile::VOLUME_TYPE_SEGMENTATION, volumeFileName, subVolumeNumber); } else if (paramName == "-volume-overlay-vector") { const QString volumeFileName = parameters->getNextParameterAsString("Vector Volume File Name"); const int subVolumeNumber = parameters->getNextParameterAsInt("Vector Sub-Volume Number"); selectVolumeOfType(brainSet, VolumeFile::VOLUME_TYPE_VECTOR, volumeFileName, subVolumeNumber); } else if (paramName == "-window-surface-files") { const QString windowName = parameters->getNextParameterAsString("Window Name"); const int graphicsSizeX = parameters->getNextParameterAsInt("Graphics Window Size X"); const int graphicsSizeY = parameters->getNextParameterAsInt("Graphics Window Size Y"); const QString coordFileName = parameters->getNextParameterAsString("Coordinate File Name"); const QString topoFileName = parameters->getNextParameterAsString("Topology File Name"); const QString viewName = parameters->getNextParameterAsString("View Name"); // // Find the window and the brain model // const int windowNumber = getWindowNumber(windowName); BrainModelSurface* bms = findBrainModelSurface(brainSet, coordFileName, topoFileName); // // Set the view // const BrainModel::STANDARD_VIEWS stdView = getSurfaceStandardView(viewName); bms->setToStandardView(windowNumber, stdView); // // Window sizing // const int graphicsSize[2] = { graphicsSizeX, graphicsSizeY }; const int windowGeometry[4] = { -1, -1, -1, -1 }; // // Set the default scaling // setWindowScaling(brainSet, graphicsSizeX, graphicsSizeY); // // create the part of the scene for the surface // SceneFile::SceneClass windowSceneClass(""); brainSet.saveSceneForBrainModelWindow(windowNumber, windowGeometry, graphicsSize, bms, false, windowSceneClass); windowSceneClasses.push_back(windowSceneClass); } else if (paramName == "-window-surface-types") { const QString windowName = parameters->getNextParameterAsString("Window Name"); const int graphicsSizeX = parameters->getNextParameterAsInt("Graphics Window Size X"); const int graphicsSizeY = parameters->getNextParameterAsInt("Graphics Window Size Y"); const QString coordFileType = parameters->getNextParameterAsString("Coordinate File Type"); const QString topoFileType = parameters->getNextParameterAsString("Topology File Type"); const QString viewName = parameters->getNextParameterAsString("View Name"); // // Find the window and the brain model // const int windowNumber = getWindowNumber(windowName); BrainModelSurface* bms = findBrainModelSurfaceFromTypes(brainSet, coordFileType, topoFileType); // // Set the view // const BrainModel::STANDARD_VIEWS stdView = getSurfaceStandardView(viewName); bms->setToStandardView(windowNumber, stdView); // // Window sizing // const int graphicsSize[2] = { graphicsSizeX, graphicsSizeY }; const int windowGeometry[4] = { -1, -1, -1, -1 }; // // Set the default scaling // setWindowScaling(brainSet, graphicsSizeX, graphicsSizeY); // // create the part of the scene for the surface // SceneFile::SceneClass windowSceneClass(""); brainSet.saveSceneForBrainModelWindow(windowNumber, windowGeometry, graphicsSize, bms, false, windowSceneClass); windowSceneClasses.push_back(windowSceneClass); } else if ((paramName == "-window-volume-slice") || (paramName == "-window-volume-coord")) { // // Find the volume // BrainModelVolume* bmv = brainSet.getBrainModelVolume(); if (bmv == NULL) { throw CommandException("No volumes were loaded from the spec file."); } const VolumeFile* underlayVolume = bmv->getUnderlayVolumeFile(); if (underlayVolume == NULL) { throw CommandException("Unable to find the underlay volume."); } const QString windowName = parameters->getNextParameterAsString("Window Name"); const int graphicsSizeX = parameters->getNextParameterAsInt("Graphics Window Size X"); const int graphicsSizeY = parameters->getNextParameterAsInt("Graphics Window Size Y"); const QString volumeViewName = parameters->getNextParameterAsString("Volume View Name"); int slices[3] = { -1, -1, -1 }; if (paramName == "-window-volume-slice") { slices[0] = parameters->getNextParameterAsInt("Parasagittal Slice Number"); slices[1] = parameters->getNextParameterAsInt("Coronal Slice Number"); slices[2] = parameters->getNextParameterAsInt("Horizontal Slice Number"); int dim[3]; underlayVolume->getDimensions(dim); if (((slices[0] < 0) || (slices[0] > dim[0])) || ((slices[1] < 0) || (slices[1] > dim[1])) || ((slices[2] < 0) || (slices[2] > dim[2]))) { throw CommandException("Volume slices are not in the volume."); } } else { const float xyz[3] = { parameters->getNextParameterAsFloat("Stereotaxic X-Coordinate"), parameters->getNextParameterAsFloat("Stereotaxic Y-Coordinate"), parameters->getNextParameterAsFloat("Stereotaxic Z-Coordinate") }; if (underlayVolume->convertCoordinatesToVoxelIJK(xyz, slices) == false) { throw CommandException("Volume stereotaxic coordinates are not in the volume."); } } // // Get the view // VolumeFile::VOLUME_AXIS volumeAxis; if (volumeViewName == "PARASAGITTAL") { volumeAxis = VolumeFile::VOLUME_AXIS_X; } else if (volumeViewName == "CORONAL") { volumeAxis = VolumeFile::VOLUME_AXIS_Y; } else if (volumeViewName == "HORIZONTAL") { volumeAxis = VolumeFile::VOLUME_AXIS_Z; } else { throw CommandException("Invalid volume view name: " + volumeViewName); } // // Find the window // const int windowNumber = getWindowNumber(windowName); // // Set the view // bmv->setSelectedAxis(windowNumber, volumeAxis); // // Set the slices // bmv->setSelectedOrthogonalSlices(windowNumber, slices); // // Window sizing // const int graphicsSize[2] = { graphicsSizeX, graphicsSizeY }; const int windowGeometry[4] = { -1, -1, -1, -1 }; // // Set the default scaling // setWindowScaling(brainSet, graphicsSizeX, graphicsSizeY); // // create the part of the scene for the volume // SceneFile::SceneClass windowSceneClass(""); brainSet.saveSceneForBrainModelWindow(windowNumber, windowGeometry, graphicsSize, bmv, false, windowSceneClass); windowSceneClasses.push_back(windowSceneClass); } else { throw CommandException("Unrecognized parameter: " + paramName); } } if (windowSceneClasses.empty()) { throw CommandException("No windows were specified."); } // // See if scene already exists // SceneFile* sceneFile = brainSet.getSceneFile(); const int sceneIndex = sceneFile->getSceneIndexFromName(sceneName); // // Create the scene // QString warningMessage; if (sceneIndex >= 0) { brainSet.replaceScene(sceneFile, sceneIndex, windowSceneClasses, sceneName, false, errorMessage, warningMessage); } else { brainSet.saveScene(brainSet.getSceneFile(), windowSceneClasses, sceneName, false, errorMessage, warningMessage); } if (errorMessage.isEmpty() == false) { throw CommandException("ERROR saving scene: " + errorMessage); } if (warningMessage.isEmpty() == false) { std::cout << "WARNING: " << warningMessage.toAscii().constData() << std::endl; } // // Write the scene file // brainSet.writeSceneFile(outputSceneFileName); } /** * get the number of a window from its name. */ int CommandSceneCreate::getWindowNumber(const QString& windowName) const throw (CommandException) { if (windowName == "WINDOW_MAIN") { return BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW; } else if (windowName == "WINDOW_2") { return BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_2; } else if (windowName == "WINDOW_3") { return BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_3; } else if (windowName == "WINDOW_4") { return BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_4; } else if (windowName == "WINDOW_5") { return BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_5; } else if (windowName == "WINDOW_6") { return BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_6; } else if (windowName == "WINDOW_7") { return BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_7; } else if (windowName == "WINDOW_8") { return BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_8; } else if (windowName == "WINDOW_9") { return BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_9; } else if (windowName == "WINDOW_10") { return BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_10; } else { throw CommandException("Unrecognized window name: " + windowName); } return BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW; } /** * find a brain model surface from types. */ BrainModelSurface* CommandSceneCreate::findBrainModelSurfaceFromTypes(BrainSet& brainSet, const QString& coordFileType, const QString& topoFileType) const throw (CommandException) { const BrainModelSurface::SURFACE_TYPES surfaceType = BrainModelSurface::getSurfaceTypeFromConfigurationID(coordFileType); if (surfaceType == BrainModelSurface::SURFACE_TYPE_UNKNOWN) { throw CommandException("Unreognized coordinate file type name : " + coordFileType); } const TopologyFile::TOPOLOGY_TYPES topologyType = TopologyFile::getTopologyTypeFromPerimeterID(topoFileType); if (topologyType == TopologyFile::TOPOLOGY_TYPE_UNKNOWN) { throw CommandException("Unreognized topology file type name : " + topoFileType); } // // Find the surface // BrainModelSurface* surface = NULL; const int numModels = brainSet.getNumberOfBrainModels(); for (int i = 0; i < numModels; i++) { BrainModelSurface* bms = brainSet.getBrainModelSurface(i); if (bms != NULL) { if (bms->getSurfaceType() == surfaceType) { surface = bms; break; } } } if (surface == NULL) { throw CommandException("No surface found for type: " + coordFileType); } // // Find the topology file // const int numTopo = brainSet.getNumberOfTopologyFiles(); for (int j = 0; j < numTopo; j++) { TopologyFile* tf = brainSet.getTopologyFile(j); if (tf->getTopologyType() == topologyType) { surface->setTopologyFile(tf); return surface; } } throw CommandException("No topology found for type: " + topoFileType); return NULL; } /** * find a brain model surface. */ BrainModelSurface* CommandSceneCreate::findBrainModelSurface(BrainSet& brainSet, const QString& coordFileName, const QString& topoFileName) const throw (CommandException) { // // Search for the files // const int numModels = brainSet.getNumberOfBrainModels(); for (int i = 0; i < numModels; i++) { BrainModelSurface* bms = brainSet.getBrainModelSurface(i); if (bms != NULL) { if (FileUtilities::basename(bms->getCoordinateFile()->getFileName()) == FileUtilities::basename(coordFileName)) { // // Find the topology file // const int numTopo = brainSet.getNumberOfTopologyFiles(); for (int j = 0; j < numTopo; j++) { TopologyFile* tf = brainSet.getTopologyFile(j); if (FileUtilities::basename(tf->getFileName()) == FileUtilities::basename(topoFileName)) { bms = bms; bms->setTopologyFile(tf); return bms; } } throw CommandException("Unable to find topology file named " + topoFileName); } } } throw CommandException("Unable to find surface with coordinate file named " + coordFileName); } /** * get standard view from its name. */ BrainModel::STANDARD_VIEWS CommandSceneCreate::getSurfaceStandardView(const QString& surfaceViewName) const throw (CommandException) { if (surfaceViewName == "ANTERIOR") { return BrainModel::VIEW_ANTERIOR; } else if (surfaceViewName == "DEFAULT") { return BrainModel::VIEW_RESET; } else if (surfaceViewName == "DORSAL") { return BrainModel::VIEW_DORSAL; } else if (surfaceViewName == "LATERAL") { return BrainModel::VIEW_LATERAL; } else if (surfaceViewName == "MEDIAL") { return BrainModel::VIEW_MEDIAL; } else if (surfaceViewName == "POSTERIOR") { return BrainModel::VIEW_POSTERIOR; } else if (surfaceViewName == "VENTRAL") { return BrainModel::VIEW_VENTRAL; } else { throw CommandException("Invalid surface-view-name: " + surfaceViewName); } return BrainModel::VIEW_DORSAL; } /** * select a volume of the specified type. */ void CommandSceneCreate::selectVolumeOfType(BrainSet& brainSet, const VolumeFile::VOLUME_TYPE volumeType, const QString& volumeFileNameIn, const int subVolumeNumber, const bool functionalThresholdFlag) throw (CommandException) { const QString volumeFileName = FileUtilities::basename(volumeFileNameIn); std::vector volumeFiles; switch (volumeType) { case VolumeFile::VOLUME_TYPE_ANATOMY: brainSet.getVolumeAnatomyFiles(volumeFiles); break; case VolumeFile::VOLUME_TYPE_FUNCTIONAL: brainSet.getVolumeFunctionalFiles(volumeFiles); break; case VolumeFile::VOLUME_TYPE_PAINT: brainSet.getVolumePaintFiles(volumeFiles); break; case VolumeFile::VOLUME_TYPE_PROB_ATLAS: brainSet.getVolumeProbAtlasFiles(volumeFiles); break; case VolumeFile::VOLUME_TYPE_RGB: brainSet.getVolumeRgbFiles(volumeFiles); break; case VolumeFile::VOLUME_TYPE_SEGMENTATION: brainSet.getVolumeSegmentationFiles(volumeFiles); break; case VolumeFile::VOLUME_TYPE_VECTOR: brainSet.getVolumeVectorFiles(volumeFiles); break; case VolumeFile::VOLUME_TYPE_ROI: case VolumeFile::VOLUME_TYPE_UNKNOWN: break; } int fileIndex = -1; const int numFiles = static_cast(volumeFiles.size()); for (int i = 0; i < numFiles; i++) { const QString name(FileUtilities::basename(volumeFiles[i]->getFileName())); if (name == volumeFileName) { fileIndex = i + subVolumeNumber - 1; break; } } if ((fileIndex >= 0) && (fileIndex < numFiles)) { } else { throw CommandException("Volume file named " + volumeFileName + " and sub-volume number " + QString::number(subVolumeNumber) + " not found."); } DisplaySettingsVolume* dsv = brainSet.getDisplaySettingsVolume(); switch (volumeType) { case VolumeFile::VOLUME_TYPE_ANATOMY: dsv->setSelectedAnatomyVolume(fileIndex); break; case VolumeFile::VOLUME_TYPE_FUNCTIONAL: if (functionalThresholdFlag == false) { dsv->setSelectedFunctionalVolumeView(fileIndex); } dsv->setSelectedFunctionalVolumeThreshold(fileIndex); break; case VolumeFile::VOLUME_TYPE_PAINT: dsv->setSelectedPaintVolume(fileIndex); break; case VolumeFile::VOLUME_TYPE_PROB_ATLAS: break; case VolumeFile::VOLUME_TYPE_RGB: dsv->setSelectedRgbVolume(fileIndex); break; case VolumeFile::VOLUME_TYPE_SEGMENTATION: dsv->setSelectedSegmentationVolume(fileIndex); break; case VolumeFile::VOLUME_TYPE_VECTOR: dsv->setSelectedVectorVolume(fileIndex); break; case VolumeFile::VOLUME_TYPE_ROI: case VolumeFile::VOLUME_TYPE_UNKNOWN: break; } } /** * set the default window scaling. */ void CommandSceneCreate::setWindowScaling(BrainSet& bs, const int sizeX, const int sizeY) { double orthoRight, orthoTop; BrainModelOpenGL::getDefaultOrthoRightAndTop(sizeX, sizeY, orthoRight, orthoTop); bs.setDefaultScaling(orthoRight, orthoTop); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandPreferencesFileSettings.h0000664000175000017500000000352511572067322030057 0ustar michaelmichael #ifndef __COMMAND_PREFERENCES_FILE_SETTINGS_H__ #define __COMMAND_PREFERENCES_FILE_SETTINGS_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for setting items in the preferences file class CommandPreferencesFileSettings : public CommandBase { public: // constructor CommandPreferencesFileSettings(); // destructor ~CommandPreferencesFileSettings(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_PREFERENCES_FILE_SETTINGS_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandPreferencesFileSettings.cxx0000664000175000017500000000753411572067322030436 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainSet.h" #include "CommandPreferencesFileSettings.h" #include "FileFilters.h" #include "PreferencesFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandPreferencesFileSettings::CommandPreferencesFileSettings() : CommandBase("-preferences-file-settings", "PREFERENCES FILES SETTINGS") { } /** * destructor. */ CommandPreferencesFileSettings::~CommandPreferencesFileSettings() { } /** * get the script builder parameters. */ void CommandPreferencesFileSettings::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); } /** * get full help information. */ QString CommandPreferencesFileSettings::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "[-background-color red green blue]\n" + indent9 + "[-foreground-color red green blue]\n" + indent9 + "[-debug debug-value]\n" + indent9 + "\n" + indent9 + "Set items in the preferences file. The preferences file\n" + indent9 + "is located in the user's home directory and is named\n" + indent9 + " " + BrainSet::getPreferencesFile()->getFileName() + "\n" + indent9 + "\n" + indent9 + "\"debug-value\" must be one of \"true\" or \"false\".\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandPreferencesFileSettings::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { PreferencesFile* pf = BrainSet::getPreferencesFile(); while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("Param"); if (paramName == "-background-color") { const int red = parameters->getNextParameterAsInt("Red"); const int green = parameters->getNextParameterAsInt("Green"); const int blue = parameters->getNextParameterAsInt("Blue"); pf->setSurfaceBackgroundColor(red, green, blue); } else if (paramName == "-foreground-color") { const int red = parameters->getNextParameterAsInt("Red"); const int green = parameters->getNextParameterAsInt("Green"); const int blue = parameters->getNextParameterAsInt("Blue"); pf->setSurfaceForegroundColor(red, green, blue); } else if (paramName == "-debug") { const bool debugOnFlag = parameters->getNextParameterAsBoolean("Debug Value"); pf->setDebugOn(debugOnFlag); } else { throw CommandException("Unrecognized parameter: " + paramName); } } pf->writeFile(pf->getFileName()); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandPaintSetColumnName.h0000664000175000017500000000343311572067322027001 0ustar michaelmichael#ifndef __COMMAND_PAINT_SET_COLUMN_NAME_H__ #define __COMMAND_PAINT_SET_COLUMN_NAME_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for setting name of paint file column class CommandPaintSetColumnName : public CommandBase { public: // constructor CommandPaintSetColumnName(); // destructor ~CommandPaintSetColumnName(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_PAINT_SET_COLUMN_NAME_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandPaintSetColumnName.cxx0000664000175000017500000000744511572067322027363 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandPaintSetColumnName.h" #include "FileFilters.h" #include "PaintFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandPaintSetColumnName::CommandPaintSetColumnName() : CommandBase("-paint-set-column-name", "PAINT SET COLUMN NAME") { } /** * destructor. */ CommandPaintSetColumnName::~CommandPaintSetColumnName() { } /** * get the script builder parameters. */ void CommandPaintSetColumnName::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Paint File Name", FileFilters::getPaintFileFilter()); paramsOut.addFile("Output Paint File Name", FileFilters::getPaintFileFilter()); paramsOut.addVariableListOfParameters("Column Names"); } /** * get full help information. */ QString CommandPaintSetColumnName::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[column new-name]\n" + indent9 + "\n" + indent9 + "Rename columns in a paint file.\n" + indent9 + "\n" + indent9 + "\"column\" is either the number of the column, which\n" + indent9 + "starts at one, or the name of the column. If a\n" + indent9 + "a name contains spaces, it must be enclosed in double\n" + indent9 + "quotes. Name has priority over number.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandPaintSetColumnName::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get output file // const QString inputPaintFileName = parameters->getNextParameterAsString("Input Paint File Name"); const QString outputPaintFileName = parameters->getNextParameterAsString("Output Paint File Name"); PaintFile paintFile; paintFile.readFile(inputPaintFileName); // // Process column names // while (parameters->getParametersAvailable()) { // // Get column identifier and new name // const QString columnID = parameters->getNextParameterAsString("Column Identifier"); const QString newName = parameters->getNextParameterAsString("New Column Name"); // // Set the column name // const int paintColumnNumber = paintFile.getColumnFromNameOrNumber(columnID, false); paintFile.setColumnName(paintColumnNumber, newName); } // // Write paint file // paintFile.writeFile(outputPaintFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandPaintLabelNameUpdate.h0000664000175000017500000000344611572067322027256 0ustar michaelmichael#ifndef __COMMAND_PAINT_LABEL_NAME_UPDATE_H__ #define __COMMAND_PAINT_LABEL_NAME_UPDATE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for update label names in paint file class CommandPaintLabelNameUpdate : public CommandBase { public: // constructor CommandPaintLabelNameUpdate(); // destructor ~CommandPaintLabelNameUpdate(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_PAINT_LABEL_NAME_UPDATE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandPaintLabelNameUpdate.cxx0000664000175000017500000001026311572067322027624 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandPaintLabelNameUpdate.h" #include "FileFilters.h" #include "PaintFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandPaintLabelNameUpdate::CommandPaintLabelNameUpdate() : CommandBase("-paint-label-name-update", "PAINT LABEL NAME UPDATE") { } /** * destructor. */ CommandPaintLabelNameUpdate::~CommandPaintLabelNameUpdate() { } /** * get the script builder parameters. */ void CommandPaintLabelNameUpdate::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Paint File Name", FileFilters::getPaintFileFilter()); paramsOut.addFile("Output Paint File Name", FileFilters::getPaintFileFilter()); paramsOut.addVariableListOfParameters("Label Name Updates"); } /** * get full help information. */ QString CommandPaintLabelNameUpdate::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-remove-prefixes]\n" + indent9 + "[-remove-suffixes]\n" + indent9 + "\n" + indent9 + "Update label names in a paint file.\n" + indent9 + "\n" + indent9 + "\"-remove-prefixes\" removes all characters up to\n" + indent9 + "and including the first period in the names of .\n" + indent9 + "all labels.\n" + indent9 + "\n" + indent9 + "\"-remove-suffixes\" removes all characters starting\n" + indent9 + "at and including the last period in the names of\n" + indent9 + "all labels.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandPaintLabelNameUpdate::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get output file // const QString inputPaintFileName = parameters->getNextParameterAsString("Input Paint File Name"); const QString outputPaintFileName = parameters->getNextParameterAsString("Output Paint File Name"); PaintFile paintFile; paintFile.readFile(inputPaintFileName); // // Process column names // bool removePrefixesFlag = false; bool removeSuffixesFlag = false; while (parameters->getParametersAvailable()) { // // Get column identifier and new name // QString paramName = parameters->getNextParameterAsString("Label Update Parameter"); if (paramName == "-remove-prefixes") { removePrefixesFlag = true; } else if (paramName == "-remove-suffixes") { removeSuffixesFlag = true; } else { throw CommandException("Unrecognized parameter: " + paramName); } } // // Update labels names // paintFile.removePrefixesAndSuffixesFromNames(removePrefixesFlag, removeSuffixesFlag); // // Write paint file // paintFile.writeFile(outputPaintFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandPaintFileCreate.h0000664000175000017500000000342511572067322026273 0ustar michaelmichael #ifndef __COMMAND_PAINT_FILE_CREATE_H__ #define __COMMAND_PAINT_FILE_CREATE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for creating a paint file class CommandPaintFileCreate : public CommandBase { public: // constructor CommandPaintFileCreate(); // destructor ~CommandPaintFileCreate(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_PAINT_FILE_CREATE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandPaintFileCreate.cxx0000664000175000017500000001321711572067322026646 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandPaintFileCreate.h" #include "CoordinateFile.h" #include "FileFilters.h" #include "PaintFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandPaintFileCreate::CommandPaintFileCreate() : CommandBase("-paint-file-create", "PAINT FILE CREATION") { } /** * destructor. */ CommandPaintFileCreate::~CommandPaintFileCreate() { } /** * get full help information. */ QString CommandPaintFileCreate::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + "[-number-of-nodes number-of-nodes] \n" + indent9 + "[-coordinate-file coordinate-file-for-number-of-nodes] \n" + indent9 + "[-set-column-name column-number column-name]\n" + indent9 + "\n" + indent9 + "Create a paint file with the specified number of nodes\n" + indent9 + "and columns with all values initialized to zero. \n" + indent9 + "\n" + indent9 + "The number of columns MUST be specified using either the\n" + indent9 + "\"-number-of-nodes\" option or the \"-coordinate-file\"\n" + indent9 + "in which case the number of nodes is set to the number\n" + indent9 + "of nodes in the coordinate file.\n" + indent9 + "\n" + indent9 + "When setting column names, the \"column-number\" starts at one.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandPaintFileCreate::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get name, columns // const QString paintFileName = parameters->getNextParameterAsString("Paint File Name"); const int numberOfColumns = parameters->getNextParameterAsInt("Number of Columns"); if (numberOfColumns <= 0) { throw CommandException("Number of columns must be " "greater than zero."); } int numberOfNodes = -1; // // Process optional parameters // std::vector paintColumnNames(numberOfColumns, ""); while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("Paint Create Parameter"); if (paramName == "-number-of-nodes") { numberOfNodes = parameters->getNextParameterAsInt("Number of Nodes"); } else if (paramName == "-coordinate-file") { const QString coordinateFileName = parameters->getNextParameterAsString("Coordinate File Name"); CoordinateFile coordinateFile; coordinateFile.readFile(coordinateFileName); numberOfNodes = coordinateFile.getNumberOfCoordinates(); } else if (paramName == "-set-column-name") { int paintColumnNumber = parameters->getNextParameterAsInt("Column Number"); if ((paintColumnNumber < 1) || (paintColumnNumber > numberOfColumns)) { throw CommandException("Invalid paint column number" + QString::number(paintColumnNumber)); } paintColumnNumber--; // index starting at zero paintColumnNames[paintColumnNumber] = parameters->getNextParameterAsString("Column Name"); } else { throw CommandException("Unrecognized parameter: " + paramName); } } // // Error check // if (numberOfNodes <= 0) { throw CommandException("Number of nodes must be " "greater than zero."); } // // Create the file // PaintFile paintFile; paintFile.setNumberOfNodesAndColumns(numberOfNodes, numberOfColumns); paintFile.addPaintName("???"); for (int i = 0; i < numberOfColumns; i++) { if (paintColumnNames[i].isEmpty() == false) { // // Set the column name // paintFile.setColumnName(i, paintColumnNames[i]); } } // // Write the file // paintFile.writeFile(paintFileName); } /** * get the script builder parameters. */ void CommandPaintFileCreate::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Paint File Name", FileFilters::getPaintFileFilter()); paramsOut.addInt("Number of Columns", 1, 1, 100000); paramsOut.addVariableListOfParameters("Input Paint Files/Columns"); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandPaintDilation.h0000664000175000017500000000334511572067322026034 0ustar michaelmichael#ifndef __COMMAND_PAINT_DILATION_H__ #define __COMMAND_PAINT_DILATION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for dilating paint class CommandPaintDilation : public CommandBase { public: // constructor CommandPaintDilation(); // destructor ~CommandPaintDilation(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_PAINT_DILATION_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandPaintDilation.cxx0000664000175000017500000001130111572067322026376 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainSet.h" #include "CommandPaintDilation.h" #include "FileFilters.h" #include "PaintFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandPaintDilation::CommandPaintDilation() : CommandBase("-paint-dilation", "PAINT DILATION") { } /** * destructor. */ CommandPaintDilation::~CommandPaintDilation() { } /** * get the script builder parameters. */ void CommandPaintDilation::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { std::vector values, descriptions; values.push_back("AN"); descriptions.push_back("Average Neighbors"); values.push_back("DILATE"); descriptions.push_back("Dilation"); values.push_back("FWHM"); descriptions.push_back("Full Width Half Maximum"); values.push_back("GAUSS"); descriptions.push_back("Gaussian"); values.push_back("WAN"); descriptions.push_back("Weighted Average Neighbors"); paramsOut.clear(); paramsOut.clear(); paramsOut.addFile("Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Input Paint File Name", FileFilters::getPaintFileFilter()); paramsOut.addFile("Output Paint File Name", FileFilters::getPaintFileFilter()); paramsOut.addInt("Number of Dilation Iterations", 5, 0, 100000); } /** * get full help information. */ QString CommandPaintDilation::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandPaintDilation::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString coordinateFileName = parameters->getNextParameterAsString("Coordinate File Name"); const QString topologyFileName = parameters->getNextParameterAsString("Topology File Name"); const QString inputPaintFileName = parameters->getNextParameterAsString("Input Paint File Name"); const QString outputPaintFileName = parameters->getNextParameterAsString("Output Paint File Name"); const int numberOfDilationIterations = parameters->getNextParameterAsInt("Number of Dilation Iterations"); checkForExcessiveParameters(); // // Create a brain set // BrainSet brainSet(topologyFileName, coordinateFileName, NULL, true); BrainModelSurface* surface = brainSet.getBrainModelSurface(0); if (surface == NULL) { throw CommandException("unable to find surface."); } const TopologyFile* tf = surface->getTopologyFile(); if (tf == NULL) { throw CommandException("unable to find topology."); } const int numNodes = surface->getNumberOfNodes(); if (numNodes == 0) { throw CommandException("surface contains no nodes."); } // // Read input paint file // PaintFile paintFile; paintFile.readFile(inputPaintFileName); // // Perform dilation // const int numberOfColumns = paintFile.getNumberOfColumns(); for (int i = 0; i < numberOfColumns; i++) { paintFile.dilateColumn(tf, i, numberOfDilationIterations); } // // Write the p file // paintFile.writeFile(outputPaintFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandPaintComposite.h0000664000175000017500000000335211572067322026231 0ustar michaelmichael #ifndef __COMMAND_PAINT_COMPOSITE__ #define __COMMAND_PAINT_COMPOSITE__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandPaintComposite : public CommandBase { public: // constructor CommandPaintComposite(); // destructor ~CommandPaintComposite(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_PAINT_COMPOSITE__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandPaintComposite.cxx0000664000175000017500000000703011572067322026601 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandPaintComposite.h" #include "FileFilters.h" #include "PaintFile.h" #include "ProgramParameters.h" /** * constructor. */ CommandPaintComposite::CommandPaintComposite() : CommandBase("-paint-composite", "PAINT FILE COMPOSITE ALL COLUMNS") { } /** * destructor. */ CommandPaintComposite::~CommandPaintComposite() { } /** * get the script builder parameters. */ void CommandPaintComposite::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.clear(); paramsOut.addFile("Output Paint File Name", FileFilters::getPaintFileFilter()); paramsOut.addMultipleFiles("Input Paint File Name(s)", FileFilters::getMetricFileFilter()); } /** * get full help information. */ QString CommandPaintComposite::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Concatenate all columns from the input paint files and place\n" + indent9 + "them into the output paint file\n"); return helpInfo; } /** * execute the command. */ void CommandPaintComposite::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the parameters // const QString outputPaintFileName = parameters->getNextParameterAsString("Output Paint File Name"); std::vector inputPaintFileNames; parameters->getRemainingParametersAsStrings("Input Paint Files", inputPaintFileNames); const int numPaintFiles = static_cast(inputPaintFileNames.size()); if (numPaintFiles <= 0) { throw CommandException("Names of input paint files are missing."); } PaintFile outputPaintFile; for (int i = 0; i < numPaintFiles; i++) { if (outputPaintFile.getNumberOfColumns() == 0) { outputPaintFile.readFile(inputPaintFileNames[i]); } else { PaintFile inputPaintFile; inputPaintFile.readFile(inputPaintFileNames[i]); const int numCols = inputPaintFile.getNumberOfColumns(); if (numCols > 0) { outputPaintFile.append(inputPaintFile); } } } outputPaintFile.writeFile(outputPaintFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandPaintAssignNodesRelativeToLine.h0000664000175000017500000000362011572067322031311 0ustar michaelmichael #ifndef __COMMAND_PAINT_ASSIGN_NODES_RELATIVE_TO_LINE_H__ #define __COMMAND_PAINT_ASSIGN_NODES_RELATIVE_TO_LINE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for assigning nodes paint ID's relative to a line class CommandPaintAssignNodesRelativeToLine : public CommandBase { public: // constructor CommandPaintAssignNodesRelativeToLine(); // destructor ~CommandPaintAssignNodesRelativeToLine(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_PAINT_ASSIGN_NODES_RELATIVE_TO_LINE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandPaintAssignNodesRelativeToLine.cxx0000664000175000017500000003203211572067322031663 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurface.h" #include "BrainModelSurfacePaintAssignRelativeToLine.h" #include "BrainSet.h" #include "CommandPaintAssignNodesRelativeToLine.h" #include "FileFilters.h" #include "FociProjectionFile.h" #include "MathUtilities.h" #include "PaintFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandPaintAssignNodesRelativeToLine::CommandPaintAssignNodesRelativeToLine() : CommandBase("-paint-assign-nodes-relative-to-line", "PAINT ASSIGN NODES RELATIVE TO LINE") { } /** * destructor. */ CommandPaintAssignNodesRelativeToLine::~CommandPaintAssignNodesRelativeToLine() { } /** * get the script builder parameters. */ void CommandPaintAssignNodesRelativeToLine::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Foci Projection File Name", FileFilters::getFociProjectionFileFilter()); paramsOut.addString("Name of Focus at Line Start"); paramsOut.addString("Name of Focus at Line End"); paramsOut.addFile("Input Paint File Name", FileFilters::getPaintFileFilter()); paramsOut.addFile("Output Paint File Name", FileFilters::getPaintFileFilter()); paramsOut.addString("Paint File Column"); paramsOut.addString("Region Paint Name"); paramsOut.addString("New Paint Name"); paramsOut.addFloat("Minimum Distance From Line"); paramsOut.addFloat("Maximum Distance From Line"); paramsOut.addVariableListOfParameters("Line Info"); } /** * get full help information. */ QString CommandPaintAssignNodesRelativeToLine::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + " \n" + indent9 + "\n" + indent9 + " \n" + indent9 + " \n" + indent9 + "[-limit-to-nodes-with-current-paint-name name]\n" + indent9 + "[-node-x-min value]\n" + indent9 + "[-node-x-max value]\n" + indent9 + "[-node-y-min value]\n" + indent9 + "[-node-y-max value]\n" + indent9 + "[-node-z-min value]\n" + indent9 + "[-node-z-max value\n" + indent9 + "\n" + indent9 + "Create an infinite line that goes through the two specified\n" + indent9 + "foci. Assign the new paint name to nodes that are within\n" + indent9 + "the minimum and maximum distances on the right side of the \n" + indent9 + "line. Options limit the nodes assigned to those with an \n" + indent9 + "existing paint name and those nodes whose coordinates are \n" + indent9 + "within geometric specified limits. The initial nodes are\n" + indent9 + "those adjacent to \"region-paint-name\" and this regions\n" + indent9 + "is incrementally expanded until there no additional nodes\n" + indent9 + "have their paint set.\n" + indent9 + "\n" + indent9 + "\"paint-file-column\" is either the number of the column, \n" + indent9 + "which starts at one, or the name of the column. If a\n" + indent9 + "name contains spaces, it must be enclosed in double\n" + indent9 + "quotes. Name has priority over number.\n" + indent9 + "\n" + indent9 + "The input paint file must exist. If the input paint column\n" + indent9 + "is not found and its name is non-numeric, a new column will \n" + indent9 + "be added to the paint file if the paint file contains nodes.\n" + indent9 + "\n" + indent9 + "Uses the last foci with specified names.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandPaintAssignNodesRelativeToLine::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the parameters // const QString coordinateFileName = parameters->getNextParameterAsString("Coordinate File Name"); const QString topologyFileName = parameters->getNextParameterAsString("Topology File Name"); const QString fociProjectionFileName = parameters->getNextParameterAsString("Projection File Name"); const QString focusLineStartName = parameters->getNextParameterAsString("Focus Name for Line Start"); const QString focusLineEndName = parameters->getNextParameterAsString("Focus Name for Line End"); const QString inputPaintFileName = parameters->getNextParameterAsString("Input Paint File Name"); const QString outputPaintFileName = parameters->getNextParameterAsString("Output Paint File Name"); const QString paintFileColumn = parameters->getNextParameterAsString("Paint File Column"); const QString regionPaintName = parameters->getNextParameterAsString("Region Paint Name"); const QString newPaintName = parameters->getNextParameterAsString("New Paint Name"); const float minimumDistanceFromLine = parameters->getNextParameterAsFloat("Minimum Distance From Line"); const float maximumDistanceFromLine = parameters->getNextParameterAsFloat("Maximum Distance From Line"); // // Optional parameter names // std::vector existingPaintNames; float xMin = -std::numeric_limits::max(); float xMax = std::numeric_limits::max(); float yMin = -std::numeric_limits::max(); float yMax = std::numeric_limits::max(); float zMin = -std::numeric_limits::max(); float zMax = std::numeric_limits::max(); // // Get optional parameters // while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("ASSIGN PAINT RELATIVE TO LINE parameter"); if (paramName == "-limit-to-nodes-with-current-paint-name") { existingPaintNames.push_back( parameters->getNextParameterAsString("Existing paint name")); } else if (paramName == "-node-x-min") { xMin = parameters->getNextParameterAsFloat("Node X Minimum"); } else if (paramName == "-node-x-max") { xMax = parameters->getNextParameterAsFloat("Node X Maximum"); } else if (paramName == "-node-y-min") { yMin = parameters->getNextParameterAsFloat("Node Y Minimum"); } else if (paramName == "-node-y-max") { yMax = parameters->getNextParameterAsFloat("Node Y Maximum"); } else if (paramName == "-node-z-min") { zMin = parameters->getNextParameterAsFloat("Node Z Minimum"); } else if (paramName == "-node-z-max") { zMax = parameters->getNextParameterAsFloat("Node Z Maximum"); } else { throw CommandException("unexpected " "parameter: " + paramName); } } // // Create a brain set // BrainSet brainSet(topologyFileName, coordinateFileName, "", true); BrainModelSurface* surface = brainSet.getBrainModelSurface(0); if (surface == NULL) { throw CommandException("unable to find surface."); } const CoordinateFile* cf = surface->getCoordinateFile(); const TopologyFile* tf = surface->getTopologyFile(); if (tf == NULL) { throw CommandException("unable to find topology."); } const int numNodes = surface->getNumberOfNodes(); if (numNodes == 0) { throw CommandException("surface contains no nodes."); } // // Read the input focus projection file // FociProjectionFile fociProjectionFile; fociProjectionFile.readFile(fociProjectionFileName); // // Get the foci for starting and ending the line // const CellProjection* focusStart = fociProjectionFile.getLastCellProjectionWithName(focusLineStartName); if (focusStart == NULL) { throw CommandException("Cannot find focus " "for start of line " + focusLineStartName); } const CellProjection* focusEnd = fociProjectionFile.getLastCellProjectionWithName(focusLineEndName); if (focusEnd == NULL) { throw CommandException("Cannot find focus " "for end of line " + focusLineEndName); } // // Unproject the Foci // const bool fiducialSurfaceFlag = (surface->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FIDUCIAL); const bool flatSurfaceFlag = ((surface->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FLAT) || (surface->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR)); float focusStartXYZ[3]; focusStart->getProjectedPosition(cf, tf, fiducialSurfaceFlag, flatSurfaceFlag, false, focusStartXYZ); float focusEndXYZ[3]; focusEnd->getProjectedPosition(cf, tf, fiducialSurfaceFlag, flatSurfaceFlag, false, focusEndXYZ); // // Open paint file and find column // PaintFile paintFile; paintFile.readFile(inputPaintFileName); // // Get the column number // const int paintFileColumnNumber = paintFile.getColumnFromNameOrNumber(paintFileColumn, true); const int regionPaintNameIndex = paintFile.getPaintIndexFromName(regionPaintName); if (regionPaintNameIndex < 0) { throw CommandException("Paint name " + regionPaintName + " not found in paint file."); } const int newPaintNameIndex = paintFile.addPaintName(newPaintName); // // Find indices of existing paint names // std::vector existingPaintIndices; const int numExistingPaintNames = static_cast(existingPaintNames.size()); for (int i = 0; i < numExistingPaintNames; i++) { const int indx = paintFile.getPaintIndexFromName(existingPaintNames[i]); if (indx < 0) { throw CommandException("existing paint " "name not found " + existingPaintNames[i]); } existingPaintIndices.push_back(indx); } // // Assign nodes // const float nodeExtent[6] = { xMin, xMax, yMin, yMax, zMin, zMax }; BrainModelSurfacePaintAssignRelativeToLine paintAssign(&brainSet, surface, &paintFile, paintFileColumnNumber, regionPaintNameIndex, newPaintNameIndex, focusStartXYZ, focusEndXYZ, minimumDistanceFromLine, maximumDistanceFromLine, existingPaintIndices, nodeExtent); paintAssign.execute(); // // Write paint file // paintFile.writeFile(outputPaintFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandPaintAssignNodes.h0000664000175000017500000000344611572067322026510 0ustar michaelmichael #ifndef __COMMAND_PAINT_ASSIGN_NODES_H__ #define __COMMAND_PAINT_ASSIGN_NODES_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for assigning paint values for nodes class CommandPaintAssignNodes : public CommandBase { public: // constructor CommandPaintAssignNodes(); // destructor ~CommandPaintAssignNodes(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_PAINT_ASSIGN_NODES_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandPaintAssignNodes.cxx0000664000175000017500000001251711572067322027062 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandPaintAssignNodes.h" #include "FileFilters.h" #include "NodeRegionOfInterestFile.h" #include "PaintFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandPaintAssignNodes::CommandPaintAssignNodes() : CommandBase("-paint-assign-to-nodes", "PAINT ASSIGN TO NODES") { } /** * destructor. */ CommandPaintAssignNodes::~CommandPaintAssignNodes() { } /** * get the script builder parameters. */ void CommandPaintAssignNodes::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Paint File Name", FileFilters::getPaintFileFilter()); paramsOut.addFile("Output Paint File Name", FileFilters::getPaintFileFilter()); paramsOut.addString("Paint Column"); paramsOut.addString("Paint Name"); paramsOut.addVariableListOfParameters("Options"); } /** * get full help information. */ QString CommandPaintAssignNodes::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + "[-assign-from-roi-file roi-file-name]\n" + indent9 + "[-set-column-name name]\n" + indent9 + "\n" + indent9 + "Assign paint values to nodes. The input paint file must\n" + indent9 + "exist. If the input paint column is not found and its\n" + indent9 + "name is non-numeric, a new column will be added to the paint\n" + indent9 + "file if the paint file contains nodes.\n" + indent9 + "\n" + indent9 + " \"column\" is either the number of the column, which\n" + indent9 + " starts at one, or the name of the column. If a\n" + indent9 + " a name contains spaces, it must be enclosed in double \n" + indent9 + " quotes. Name has priority over number.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandPaintAssignNodes::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the parameters // const QString inputPaintFileName = parameters->getNextParameterAsString("Input Paint File Name"); const QString outputPaintFileName = parameters->getNextParameterAsString("Output Paint File Name"); const QString paintColumn = parameters->getNextParameterAsString("Paint Column"); const QString paintName = parameters->getNextParameterAsString("Paint Name"); // // Read the paint file // PaintFile paintFile; paintFile.readFile(inputPaintFileName); // // Get the column number // const int paintColumnNumber = paintFile.getColumnFromNameOrNumber(paintColumn, true); // // Get index of paint name // const int paintNameIndex = paintFile.addPaintName(paintName); while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("Paint Parameter"); if (paramName == "-assign-from-roi-file") { const QString roiFileName = parameters->getNextParameterAsString("ROI File Name"); // // Read the ROI file // NodeRegionOfInterestFile nodeRoiFile; nodeRoiFile.readFile(roiFileName); // // Assign paints // const int numNodes = std::max(paintFile.getNumberOfNodes(), nodeRoiFile.getNumberOfNodes()); for (int i = 0; i < numNodes; i++) { if (nodeRoiFile.getNodeSelected(i) != 0) { paintFile.setPaint(i, paintColumnNumber, paintNameIndex); } } } else if (paramName == "-set-column-name") { const QString columnName = parameters->getNextParameterAsString("Set Column Name"); paintFile.setColumnName(paintColumnNumber, columnName); } } // // Write the paint file // paintFile.writeFile(outputPaintFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandPaintAddColumns.h0000664000175000017500000000343611572067322026323 0ustar michaelmichael #ifndef __COMMAND_PAINT_ADD_COLUMNS_H__ #define __COMMAND_PAINT_ADD_COLUMNS_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for adding columns to a paint file class CommandPaintAddColumns : public CommandBase { public: // constructor CommandPaintAddColumns(); // destructor ~CommandPaintAddColumns(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_PAINT_ADD_COLUMNS_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandPaintAddColumns.cxx0000664000175000017500000001061611572067322026674 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandPaintAddColumns.h" #include "FileFilters.h" #include "PaintFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandPaintAddColumns::CommandPaintAddColumns() : CommandBase("-paint-add-columns", "PAINT ADD COLUMNS") { } /** * destructor. */ CommandPaintAddColumns::~CommandPaintAddColumns() { } /** * get the script builder parameters. */ void CommandPaintAddColumns::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Paint File", FileFilters::getPaintFileFilter()); paramsOut.addFile("Output Paint File", FileFilters::getPaintFileFilter()); paramsOut.addVariableListOfParameters("Options"); } /** * get full help information. */ QString CommandPaintAddColumns::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-add column-name]\n" + indent9 + "\n" + indent9 + "Add columns to a paint file. If a paint column with the\n" + indent9 + "specified name already exists, a new column is NOT added.\n" + indent9 + "The paint file must exist.\n" + indent9 + "\n" + indent9 + "See the command \"-paint-file-create\" for how to create\n" + indent9 + "a paint file.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandPaintAddColumns::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get inputs // const QString inputPaintFileName = parameters->getNextParameterAsString("Input Paint File Name"); const QString outputPaintFileName = parameters->getNextParameterAsString("Output Paint File Name"); std::vector columnNames; while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("Paint Add Columns Option"); if (paramName == "-add") { columnNames.push_back(parameters->getNextParameterAsString("Column Name")); } else { throw CommandException("Unknown option."); } } // // Check input // const int numColumnsToAdd = static_cast(columnNames.size()); if (numColumnsToAdd <= 0) { throw CommandException("No columns were specified for adding to the paint file."); } // // Read the paint file // PaintFile paintFile; paintFile.readFile(inputPaintFileName); // // Verify data in the paint file. // if (paintFile.getNumberOfNodes() <= 0) { throw CommandException("Input paint file contains no nodes."); } // // Add each new column // for (int i = 0; i < numColumnsToAdd; i++) { // // Does paint column NOT exist // if (paintFile.getColumnWithName(columnNames[i]) < 0) { // // Add the column // paintFile.addColumns(1); const int col = paintFile.getNumberOfColumns() - 1; paintFile.setColumnName(col, columnNames[i]); } } // // Write the paint file // paintFile.writeFile(outputPaintFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricTwinPairedDataDiffs.h0000664000175000017500000000352311572067322030253 0ustar michaelmichael #ifndef __COMMAND_METRIC_TWIN_PAIRED_DATA_DIFFS_H__ #define __COMMAND_METRIC_TWIN_PAIRED_DATA_DIFFS_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for paired data diffs class CommandMetricTwinPairedDataDiffs : public CommandBase { public: // constructor CommandMetricTwinPairedDataDiffs(); // destructor ~CommandMetricTwinPairedDataDiffs(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_METRIC_TWIN_PAIRED_DATA_DIFFS_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricTwinPairedDataDiffs.cxx0000664000175000017500000002367511572067322030640 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandMetricTwinPairedDataDiffs.h" #include "FileFilters.h" #include "MetricFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandMetricTwinPairedDataDiffs::CommandMetricTwinPairedDataDiffs() : CommandBase("-metric-twin-paired-data-diffs", "METRIC TWIN PAIRED DATA DIFFERENCES") { } /** * destructor. */ CommandMetricTwinPairedDataDiffs::~CommandMetricTwinPairedDataDiffs() { } /** * get the script builder parameters. */ void CommandMetricTwinPairedDataDiffs::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Metric File Name A", FileFilters::getMetricShapeFileFilter()); paramsOut.addFile("InputMetric File Name B", FileFilters::getMetricShapeFileFilter()); paramsOut.addString("Output Directory", "Twins"); } /** * get full help information. */ QString CommandMetricTwinPairedDataDiffs::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Compare the two data files, assuming a paired relationship in the\n" + indent9 + "same column numbers in the two data files, e.g., the first pair of twins\n" + indent9 + "are both the first column in data file A and data file B, respectively\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandMetricTwinPairedDataDiffs::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the parameters // const QString inputAName = parameters->getNextParameterAsString("Group A Input Name"); const QString inputBName = parameters->getNextParameterAsString("Group B Input Name"); QString outputDir = parameters->getNextParameterAsString("Diffs Output Directory"); checkForExcessiveParameters(); char mycharbuff[50]; MetricFile a, b, outtwin, outnontwin; a.readFile(inputAName); b.readFile(inputBName); // // Check assumption that both files have the same number of subjects // Reasonable assumption for twin/nontwin comparison, makes little sense to abandon it, though it is // possible with a little rewriting // WARNING: if this assumption is abandoned, rewrite the loop comparing all subjects within the same // files to two loops, one loop for each file. // if (a.getNumberOfColumns() != b.getNumberOfColumns()) throw FileException("Files must have the same number of subjects."); std::vector adata, bdata; // // Allocate array neccesary to write to files // float* diff; GiftiDataArray* diffarray; int nodes; // // Loop through all columns in composite file A // for(int i = 0; i < a.getNumberOfColumns(); ++i) { a.getColumnForAllNodes(i, adata); nodes = adata.size(); std::vector nodesvect; nodesvect.clear(); nodesvect.push_back(nodes); // // Loop through all columns in composite file B for(int j = 0; j < b.getNumberOfColumns(); ++j) { // // Allocate memory for a new column in the output files // diffarray = new GiftiDataArray(NULL, "Shape"); diffarray->setDataType(GiftiDataArray::DATA_TYPE_FLOAT32); diffarray->setDimensions(nodesvect); diff = diffarray->getDataPointerFloat(); b.getColumnForAllNodes(j, bdata); // // Check assumption that both files have the same number of nodes // Note: because of how this is tested through each loop, it makes absolutely sure that // All columns have the same number of nodes, in both files. // This is partially for peace of mind, as the file format does not allow // different size columns // if (nodes != static_cast(bdata.size())) throw FileException("Files must have the same number of nodes!"); // // Compare all nodes between the two columns // Both files must have the same number of nodes, in the same order // Data must be registered to have the same # node mean the same place on the brain // for (int k = 0; k < nodes; ++k) { diff[k] = adata[k]-bdata[k]; } // // Generate the column label, workaround for changing an int to a string // QString label; // // Separate twin from nontwin data // if (i == j) { outtwin.addDataArray(diffarray); sprintf(mycharbuff, "%d", i + 1); label = "twins #"; label = label + (QString)mycharbuff; outtwin.setColumnName(i, label); } else { outnontwin.addDataArray(diffarray); sprintf(mycharbuff, "%d", i + 1); label = "subjects "; label = label + (QString)mycharbuff; label = label + "A and "; sprintf(mycharbuff, "%d", j + 1); label = label + (QString)mycharbuff; label = label + "B"; outnontwin.setColumnName(outnontwin.getNumberOfColumns() - 1, label); } } } // // Compare the subjects in each file against the others in the same file // Both composite files must have the same number of subjects, again with // the same number of nodes // // Allocate 2 more data columns to analyse both sets at the same time // If the assumption that the composite files have the same number of subjects // is abandoned, rewrite to analyse each file separately // std::vector cdata, ddata; // // Loop through all the subjects // for(int i = 0; i < a.getNumberOfColumns(); ++i) { a.getColumnForAllNodes(i, adata); b.getColumnForAllNodes(i, bdata); nodes = adata.size(); std::vector nodesvect; nodesvect.clear(); nodesvect.push_back(nodes); // // Loop through all subjects below the current subject // for(int j = i + 1; j < a.getNumberOfColumns(); ++j) { diffarray = new GiftiDataArray(NULL, "Shape"); diffarray->setDataType(GiftiDataArray::DATA_TYPE_FLOAT32); diffarray->setDimensions(nodesvect); diff = diffarray->getDataPointerFloat(); a.getColumnForAllNodes(j, cdata); b.getColumnForAllNodes(j, ddata); // // Compare the two subjects at those indexes in file A // for (int k = 0; k < nodes; ++k) { diff[k] = adata[k]-cdata[k]; } // // Record data, label column, reallocate array // outnontwin.addDataArray(diffarray); sprintf(mycharbuff, "%d", i + 1); QString label = "subjects "; label = label + (QString)mycharbuff; label = label + "A and "; sprintf(mycharbuff, "%d", j + 1); label = label + (QString)mycharbuff; label = label + "A"; outnontwin.setColumnName(outnontwin.getNumberOfColumns() - 1, label); diffarray = new GiftiDataArray(NULL, "Shape"); diffarray->setDataType(GiftiDataArray::DATA_TYPE_FLOAT32); diffarray->setDimensions(nodesvect); diff = diffarray->getDataPointerFloat(); // // Compare the two subjects at those indexes in file B // WARNING: the indexes are generated due to the number of subjects in file A ONLY // comparing two files with the second having fewer columns will cause a // null pointer error below at ddata[k], where if the second file is // bigger, not all comparisons in it will be made. // for (int k = 0; k < nodes; ++k) { diff[k] = bdata[k]-ddata[k]; } // // Record data, label column // outnontwin.addDataArray(diffarray); sprintf(mycharbuff, "%d", i + 1); label = "subjects "; label = label + (QString)mycharbuff; label = label + "B and "; sprintf(mycharbuff, "%d", j + 1); label = label + (QString)mycharbuff; label = label + "B"; outnontwin.setColumnName(outnontwin.getNumberOfColumns() - 1, label); } } // // Write output difference files // Note: writing outtwin can be moved to before the comparisons within files // move above if you want more of an idea on progress // when the cross comparison is finished, about 2/3 of the processing is done // outtwin.writeFile(outputDir + "/twin_diff.surface_shape"); outnontwin.writeFile(outputDir + "/non_twin_diff.surface_shape"); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricTwinComparison.h0000664000175000017500000000346411572067322027417 0ustar michaelmichael #ifndef __COMMAND_METRIC_TWIN_COMPARISON_H__ #define __COMMAND_METRIC_TWIN_COMPARISON_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for metric twin comparison class CommandMetricTwinComparison : public CommandBase { public: // constructor CommandMetricTwinComparison(); // destructor ~CommandMetricTwinComparison(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_METRIC_TWIN_COMPARISON_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricTwinComparison.cxx0000664000175000017500000000733611572067322027774 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurfaceMetricTwinComparison.h" #include "BrainSet.h" #include "CommandMetricTwinComparison.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandMetricTwinComparison::CommandMetricTwinComparison() : CommandBase("-metric-twin-comparison", "METRIC TWIN COMPARISON") { } /** * destructor. */ CommandMetricTwinComparison::~CommandMetricTwinComparison() { } /** * get the script builder parameters. */ void CommandMetricTwinComparison::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Metric File Name A", FileFilters::getMetricShapeFileFilter()); paramsOut.addFile("Input Metric File Name B", FileFilters::getMetricShapeFileFilter()); paramsOut.addFile("Output Metric File Name", FileFilters::getMetricShapeFileFilter()); } /** * get full help information. */ QString CommandMetricTwinComparison::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Metric/Shape File A and Metric/Shape File B contain twin subjects\n" + indent9 + "such that one of the twins is in File A and its corresonding twin\n" + indent9 + "is in the same column but in File B.\n" + indent9 + "The output file contains the twin-paired expected variance,\n" + indent9 + "the expected variance of all non-twin pairs, and the the difference\n" + indent9 + "of the two expected variances.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandMetricTwinComparison::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputMetricFileNameA = parameters->getNextParameterAsString("Input Metric File Name A"); const QString inputMetricFileNameB = parameters->getNextParameterAsString("Input Metric File Name B"); const QString outputMetricFileName = parameters->getNextParameterAsString("Output Metric File Name"); checkForExcessiveParameters(); BrainSet bs; BrainModelSurfaceMetricTwinComparison bmsmtc(&bs, inputMetricFileNameA, inputMetricFileNameB, outputMetricFileName); bmsmtc.execute(); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricTranspose.h0000664000175000017500000000344711572067322026422 0ustar michaelmichael #ifndef __COMMAND_METRIC_TRANSPOSE_H__ #define __COMMAND_METRIC_TRANSPOSE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for displaying information about a metric file class CommandMetricTranspose : public CommandBase { public: // constructor CommandMetricTranspose(); // destructor ~CommandMetricTranspose(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_METRIC_TRANSPOSE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricTranspose.cxx0000664000175000017500000000732411572067322026773 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "CommandMetricTranspose.h" #include "FileFilters.h" #include "FileUtilities.h" #include "MetricFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "StatisticDescriptiveStatistics.h" /** * constructor. */ CommandMetricTranspose::CommandMetricTranspose() : CommandBase("-metric-transpose", "METRIC FILE TRANPOSE") { } /** * destructor. */ CommandMetricTranspose::~CommandMetricTranspose() { } /** * get the script builder parameters. */ void CommandMetricTranspose::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Metric File Name", FileFilters::getMetricFileFilter()); } /** * get full help information. */ QString CommandMetricTranspose::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Transpose a Metric File's Matrix.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandMetricTranspose::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the name of the metric file // const QString metricFileName = parameters->getNextParameterAsString("Input Metric File Name"); const QString outputMetricFileName = parameters->getNextParameterAsString("Output Metric File Name"); // // Should not be any more parameters // checkForExcessiveParameters(); MetricFile metricFile; MetricFile outputMetricFile; metricFile.readFile(metricFileName); std::cout << "Input Filename: " << FileUtilities::basename(metricFileName).toAscii().constData() << std::endl; std::cout << "Output Filename: " << FileUtilities::basename(outputMetricFileName).toAscii().constData() << std::endl; const int numNodes = metricFile.getNumberOfNodes(); const int numCols = metricFile.getNumberOfColumns(); std::cout << "Number of Nodes: " << numNodes << std::endl; std::cout << "Number of Columns: " << numCols << std::endl; outputMetricFile.setNumberOfNodesAndColumns(numCols,numNodes); for (int i=0;igetProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Transform the nodes in each row into Z-Scores.\n" + indent9 + "\n" + indent9 + "Z = (Xi - Mean) / Standard Deviation\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandMetricStatisticsZMap::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputMetricFileName = parameters->getNextParameterAsString("Input Metric File Name"); const QString outputMetricFileName = parameters->getNextParameterAsString("Output Metric File Name"); checkForExcessiveParameters(); MetricFile inputMetricFile; inputMetricFile.readFile(inputMetricFileName); MetricFile* outputMetricFile = inputMetricFile.computeStatisticalZMap(); outputMetricFile->writeFile(outputMetricFileName); delete outputMetricFile; } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricStatisticsTwoSampleTTest.h0000664000175000017500000000356411572067322031416 0ustar michaelmichael #ifndef __COMMAND_METRIC_STATISTICS_TWO_SAMPLE_T_TEST_H__ #define __COMMAND_METRIC_STATISTICS_TWO_SAMPLE_T_TEST_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for two sample t-test class CommandMetricStatisticsTwoSampleTTest : public CommandBase { public: // constructor CommandMetricStatisticsTwoSampleTTest(); // destructor ~CommandMetricStatisticsTwoSampleTTest(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_METRIC_STATISTICS_TWO_SAMPLE_T_TEST_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricStatisticsTwoSampleTTest.cxx0000664000175000017500000002630211572067322031764 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurfaceMetricTwoSampleTTest.h" #include "BrainSet.h" #include "CommandMetricStatisticsTwoSampleTTest.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandMetricStatisticsTwoSampleTTest::CommandMetricStatisticsTwoSampleTTest() : CommandBase("-metric-statistics-two-sample-t-test", "METRIC STATISTICS TWO SAMPLE T-TEST and WILCOXON") { } /** * destructor. */ CommandMetricStatisticsTwoSampleTTest::~CommandMetricStatisticsTwoSampleTTest() { } /** * get the script builder parameters. */ void CommandMetricStatisticsTwoSampleTTest::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { std::vector transModeValues, transModeDescriptions; transModeValues.push_back("NO_TRANSFORM"); transModeDescriptions.push_back("Node"); transModeValues.push_back("WILCOXON_TRANSFORM"); transModeDescriptions.push_back("Wilcoxon Rank-Sum input data then T-Test"); std::vector varModeValues, varModeDescriptions; varModeValues.push_back("SIGMA"); varModeDescriptions.push_back("Donna's SIGMA Method"); varModeValues.push_back("POOLED"); varModeDescriptions.push_back("Use Pooled Variance in T Computation"); varModeValues.push_back("UNPOOLED"); varModeDescriptions.push_back("Use Unpooled Variance in T Computation"); paramsOut.clear(); paramsOut.addListOfItems("Data Transform Mode", transModeValues, transModeDescriptions); paramsOut.addListOfItems("Variance Mode", varModeValues, varModeDescriptions); paramsOut.addFile("Metric File Name A", FileFilters::getMetricShapeFileFilter()); paramsOut.addFile("Metric File Name B", FileFilters::getMetricShapeFileFilter()); paramsOut.addFile("Fiducial Coordinate File Name", FileFilters::getCoordinateFiducialFileFilter()); paramsOut.addFile("Open Topology File Name", FileFilters::getTopologyOpenFileFilter()); paramsOut.addFile("Distoration Metric File Name", FileFilters::getMetricShapeFileFilter()); paramsOut.addInt("Distortion Column Number"); paramsOut.addString("Output File Names Prefix"); paramsOut.addInt("Iterations"); paramsOut.addFloat("Negative Threshold"); paramsOut.addFloat("Positive Threshold"); paramsOut.addFloat("P-Value"); paramsOut.addInt("Variance Smoothing Iterations"); paramsOut.addFloat("Variance Smoothing Strength"); paramsOut.addBoolean("Do TMap Degrees of Freedom"); paramsOut.addBoolean("Do TMap P-Values"); paramsOut.addInt("Number of Threads", 1); } /** * get full help information. */ QString CommandMetricStatisticsTwoSampleTTest::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " Perform a two-sample T-Test or perform a Wilcoxon Rank-Sum of the \n" + indent9 + " data and then perform the T-Test. \n" + indent9 + " \n" + indent9 + " data-transform-mode-name one of: \n" + indent9 + " NO_TRANSFORM \n" + indent9 + " WILCOXON_TRANSFORM (Wilcoxon Rank-Sum input data then T-Test) \n" + indent9 + " \n" + indent9 + " variance-mode-name is one of: \n" + indent9 + " SIGMA - Use Donna's SIGMA method \n" + indent9 + " POOLED - Use pooled variance in T computation \n" + indent9 + " UNPOOLED - Use unpooled variance in T computation \n" + indent9 + " \n" + indent9 + " The distortion column number starts at 1. \n" + indent9 + " \n" + indent9 + " Number of threads is the number of concurrent processes run \n" + indent9 + " during the cluster search of the shuffled metric file. \n" + indent9 + " Use \"1\" if you are running on a single processor system. \n" + indent9 + " Users on systems with multiple processors or multi-core systems \n" + indent9 + " should set the number of threads to the number of processors \n" + indent9 + " and/or cores to reduce execution time. \n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandMetricStatisticsTwoSampleTTest::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString dataTransformModeName = parameters->getNextParameterAsString("Data Transform Mode Name"); const QString varianceModeName = parameters->getNextParameterAsString("Variance Mode Name"); const QString metricShapeFileA = parameters->getNextParameterAsString("Metric or Shape File A"); const QString metricShapeFileB = parameters->getNextParameterAsString("Metric or Shape File B"); const QString fiducialCoordFileName = parameters->getNextParameterAsString("Fiducial Coordinate File Name"); const QString openTopoFileName = parameters->getNextParameterAsString("Open Topology File Name"); const QString distortionMetricShapeFileName = parameters->getNextParameterAsString("Distortion Metric/Shape File Name"); int distortionColumnNumber = parameters->getNextParameterAsInt("Distortion Column Number"); const QString outputFileNamePrefix = parameters->getNextParameterAsString("Output File Name Prefix"); const int iterations = parameters->getNextParameterAsInt("Iterations"); const float negativeThreshold = parameters->getNextParameterAsFloat("Negative Threshold"); const float positiveThreshold = parameters->getNextParameterAsFloat("Positive Threshold"); const float pValue = parameters->getNextParameterAsFloat("P-Value"); const int varianceSmoothingIterations = parameters->getNextParameterAsInt("Variance Smoothing Iterations"); const float varianceSmoothingStrength = parameters->getNextParameterAsFloat("Variance Smoothing Strength"); const bool doTMapDOF = parameters->getNextParameterAsBoolean("Do T-MAP Degrees of Freedom"); const bool doTMapPValue = parameters->getNextParameterAsBoolean("Do T-MAP P-Value"); const int numberOfThreads = parameters->getNextParameterAsInt("Number of Threads"); checkForExcessiveParameters(); BrainModelSurfaceMetricTwoSampleTTest::DATA_TRANSFORM_MODE dataTransformMode; if (dataTransformModeName == "NO_TRANSFORM") { dataTransformMode = BrainModelSurfaceMetricTwoSampleTTest::DATA_TRANSFORM_NONE; } else if (dataTransformModeName == "WILCOXON_TRANSFORM") { dataTransformMode = BrainModelSurfaceMetricTwoSampleTTest::DATA_TRANSFORM_WILCOXON_RANK_SUM_THEN_TWO_SAMPLE_T_TEST; } else { throw CommandException("Invalid data transform mode: " + dataTransformModeName); } BrainModelSurfaceMetricTwoSampleTTest::VARIANCE_MODE varianceMode; if (varianceModeName == "POOLED") { varianceMode = BrainModelSurfaceMetricTwoSampleTTest::VARIANCE_MODE_POOLED; } else if (varianceModeName == "UNPOOLED") { varianceMode = BrainModelSurfaceMetricTwoSampleTTest::VARIANCE_MODE_UNPOOLED; } else if (varianceModeName == "SIGMA") { varianceMode = BrainModelSurfaceMetricTwoSampleTTest::VARIANCE_MODE_SIGMA; } else { throw CommandException("Invalid variance mode: " + varianceModeName); } if (distortionColumnNumber <= 0) { throw CommandException("Distortion column number must be >= 1."); } distortionColumnNumber--; // algorithm starts at zero const QString ext = metricShapeFileA.endsWith(SpecFile::getMetricFileExtension()) ? SpecFile::getMetricFileExtension() : SpecFile::getSurfaceShapeFileExtension(); const QString outputTMapFileName(outputFileNamePrefix + "_TMap" + ext); const QString outputShuffledTMapFileName(outputFileNamePrefix + "_ShuffledTMap" + ext); const QString outputPaintFileName(outputFileNamePrefix + "_TMapClusters" + SpecFile::getPaintFileExtension()); const QString outputMetricFileName(outputFileNamePrefix + "_TMapClusters" + SpecFile::getMetricFileExtension()); const QString outputReportFileName(outputFileNamePrefix + "_TMap_Significant_Clusters" + SpecFile::getTextFileExtension()); BrainSet bs; BrainModelSurfaceMetricTwoSampleTTest twoSample(&bs, dataTransformMode, varianceMode, metricShapeFileA, metricShapeFileB, fiducialCoordFileName, openTopoFileName, distortionMetricShapeFileName, outputTMapFileName, outputShuffledTMapFileName, outputPaintFileName, outputMetricFileName, outputReportFileName, distortionColumnNumber, iterations, negativeThreshold, positiveThreshold, pValue, varianceSmoothingIterations, varianceSmoothingStrength, doTMapDOF, doTMapPValue, numberOfThreads); twoSample.execute(); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricStatisticsTMap.h0000664000175000017500000000335211572067322027353 0ustar michaelmichael #ifndef __REPLACE_1__ #define __REPLACE_1__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for computing a T-Map class CommandMetricStatisticsTMap : public CommandBase { public: // constructor CommandMetricStatisticsTMap(); // destructor ~CommandMetricStatisticsTMap(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __REPLACE_1__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricStatisticsTMap.cxx0000664000175000017500000001320711572067322027726 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandMetricStatisticsTMap.h" #include "FileFilters.h" #include "MetricFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "TopologyFile.h" /** * constructor. */ CommandMetricStatisticsTMap::CommandMetricStatisticsTMap() : CommandBase("-metric-statistics-t-map", "METRIC STATISTICS T-MAP") { } /** * destructor. */ CommandMetricStatisticsTMap::~CommandMetricStatisticsTMap() { } /** * get the script builder parameters. */ void CommandMetricStatisticsTMap::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Metric File Name A", FileFilters::getMetricShapeFileFilter()); paramsOut.addFile("Input Metric File Name B", FileFilters::getMetricShapeFileFilter()); paramsOut.addFile("Output Metric File Name", FileFilters::getMetricShapeFileFilter()); paramsOut.addFile("Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addInt("Variance Smoothing Iterations"); paramsOut.addFloat("Variance Smoothing Strength"); paramsOut.addFloat("False Discovery Rate Q"); paramsOut.addBoolean("Pool Variance Flag"); paramsOut.addBoolean("Do False Discovery Rate Flag"); paramsOut.addBoolean("Do Degrees of Freedom Flag"); paramsOut.addBoolean("Do P-Values Flag"); } /** * get full help information. */ QString CommandMetricStatisticsTMap::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Compute a T-Map using the two input files.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandMetricStatisticsTMap::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputMetricFileNameA = parameters->getNextParameterAsString("Input Metric File Name A"); const QString inputMetricFileNameB = parameters->getNextParameterAsString("Input Metric File Name B"); const QString outputMetricFileName = parameters->getNextParameterAsString("Output Metric File Name"); const QString topologyFileName = parameters->getNextParameterAsString("Topology File Name"); const int varianceSmoothingIterations = parameters->getNextParameterAsInt("Variance Smoothing Iterations"); const float varianceSmoothingStrength = parameters->getNextParameterAsFloat("Variance Smoothing Strength"); const float falseDiscoveryRateQ = parameters->getNextParameterAsFloat("False Discovery Rate Q"); const bool poolTheVarianceFlag = parameters->getNextParameterAsBoolean("Pool Variance Flag"); const bool doFalseDiscoveryRateFlag = parameters->getNextParameterAsBoolean("Do False Discovery Rate"); const bool doDegreesOfFreedomFlag = parameters->getNextParameterAsBoolean("Do Degrees of Freedom"); const bool doPValuesFlag = parameters->getNextParameterAsBoolean("Do P-Values Flag"); checkForExcessiveParameters(); MetricFile inputMetricFileA, inputMetricFileB; inputMetricFileA.readFile(inputMetricFileNameA); inputMetricFileB.readFile(inputMetricFileNameB); TopologyFile topologyFile; topologyFile.readFile(topologyFileName); MetricFile* outputMetricFile = MetricFile::computeStatisticalTMap(&inputMetricFileA, &inputMetricFileB, &topologyFile, varianceSmoothingIterations, varianceSmoothingStrength, poolTheVarianceFlag, falseDiscoveryRateQ, doFalseDiscoveryRateFlag, doDegreesOfFreedomFlag, doPValuesFlag); outputMetricFile->writeFile(outputMetricFileName); delete outputMetricFile; } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricStatisticsSubtraceGroupAverage.h0000664000175000017500000000363511572067322032576 0ustar michaelmichael #ifndef __COMMAND_METRIC_STATISTICS_SUBTRACT_GROUP_AVERAGE_H__ #define __COMMAND_METRIC_STATISTICS_SUBTRACT_GROUP_AVERAGE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for subtracting group average class CommandMetricStatisticsSubtraceGroupAverage : public CommandBase { public: // constructor CommandMetricStatisticsSubtraceGroupAverage(); // destructor ~CommandMetricStatisticsSubtraceGroupAverage(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_METRIC_STATISTICS_SUBTRACT_GROUP_AVERAGE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricStatisticsSubtraceGroupAverage.cxx0000664000175000017500000001014511572067322033143 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandMetricStatisticsSubtraceGroupAverage.h" #include "FileFilters.h" #include "MetricFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandMetricStatisticsSubtraceGroupAverage::CommandMetricStatisticsSubtraceGroupAverage() : CommandBase("-metric-statistics-subtract-group-average", "METRIC STATISTICS SUBTRACT GROUP AVERAGE") { } /** * destructor. */ CommandMetricStatisticsSubtraceGroupAverage::~CommandMetricStatisticsSubtraceGroupAverage() { } /** * get the script builder parameters. */ void CommandMetricStatisticsSubtraceGroupAverage::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Metric File Name A", FileFilters::getMetricShapeFileFilter()); paramsOut.addFile("Input Metric File Name B", FileFilters::getMetricShapeFileFilter()); paramsOut.addFile("Output Metric File Name A", FileFilters::getMetricShapeFileFilter()); paramsOut.addFile("Output Metric File Name B", FileFilters::getMetricShapeFileFilter()); } /** * get full help information. */ QString CommandMetricStatisticsSubtraceGroupAverage::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "An average is computed each node in both input files. This\n" + indent9 + "average is subtracted from each node's values and stored in\n" + indent9 + "the output files.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandMetricStatisticsSubtraceGroupAverage::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputMetricFileNameA = parameters->getNextParameterAsString("Input Metric File Name A"); const QString inputMetricFileNameB = parameters->getNextParameterAsString("Input Metric File Name B"); const QString outputMetricFileNameA = parameters->getNextParameterAsString("Output Metric File Name A"); const QString outputMetricFileNameB = parameters->getNextParameterAsString("Output Metric File Name B"); checkForExcessiveParameters(); MetricFile inputMetricFileA, inputMetricFileB; inputMetricFileA.readFile(inputMetricFileNameA); inputMetricFileB.readFile(inputMetricFileNameB); MetricFile outputMetricFileA, outputMetricFileB; MetricFile::subtractMeanFromRowElements(&inputMetricFileA, &inputMetricFileB, &outputMetricFileA, &outputMetricFileB); outputMetricFileA.writeFile(outputMetricFileNameA); outputMetricFileB.writeFile(outputMetricFileNameB); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricStatisticsShuffledTMap.h0000664000175000017500000000354211572067322031035 0ustar michaelmichael #ifndef __COMMAND_METRIC_STATISTICS_SHUFFLED_T_MAP_H__ #define __COMMAND_METRIC_STATISTICS_SHUFFLED_T_MAP_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for shuffled T-Map class CommandMetricStatisticsShuffledTMap : public CommandBase { public: // constructor CommandMetricStatisticsShuffledTMap(); // destructor ~CommandMetricStatisticsShuffledTMap(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_METRIC_STATISTICS_SHUFFLED_T_MAP_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricStatisticsShuffledTMap.cxx0000664000175000017500000001155311572067322031411 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandMetricStatisticsShuffledTMap.h" #include "FileFilters.h" #include "MetricFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "TopologyFile.h" /** * constructor. */ CommandMetricStatisticsShuffledTMap::CommandMetricStatisticsShuffledTMap() : CommandBase("-metric-statistics-shuffled-t-map", "METRIC STATISTICS SHUFFLED T-MAP") { } /** * destructor. */ CommandMetricStatisticsShuffledTMap::~CommandMetricStatisticsShuffledTMap() { } /** * get the script builder parameters. */ void CommandMetricStatisticsShuffledTMap::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Metric File Name", FileFilters::getMetricShapeFileFilter()); paramsOut.addFile("Output Metric File Name", FileFilters::getMetricShapeFileFilter()); paramsOut.addFile("Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addInt("Iterations"); paramsOut.addInt("Number in First Group"); paramsOut.addInt("Variance Smoothing Iterations"); paramsOut.addFloat("Variance Smoothing Strength"); paramsOut.addBoolean("Pool Variance Flag"); } /** * get full help information. */ QString CommandMetricStatisticsShuffledTMap::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Computed a T-Map on shuffled columns split into two groups.\n" + indent9 + "If the number in the first group is negative or zero, the\n" + indent9 + "columns are split into two groups of the same size.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandMetricStatisticsShuffledTMap::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputMetricFileName = parameters->getNextParameterAsString("Input Metric File Name"); const QString outputMetricFileName = parameters->getNextParameterAsString("Output Metric File Name"); const QString topologyFileName = parameters->getNextParameterAsString("Topology File Name"); const int iterations = parameters->getNextParameterAsInt("Iterations"); const int numberInFirstGroup = parameters->getNextParameterAsInt("Number in First Group"); const int varianceSmoothingIterations = parameters->getNextParameterAsInt("Variance Smoothing Iterations"); const float varianceSmoothingStrength = parameters->getNextParameterAsFloat("Variance Smoothing Strength"); const bool poolTheVarianceFlag = parameters->getNextParameterAsBoolean("Pool Variance Flag"); checkForExcessiveParameters(); MetricFile inputMetricFile; inputMetricFile.readFile(inputMetricFileName); TopologyFile topologyFile; topologyFile.readFile(topologyFileName); MetricFile* outputMetricFile = inputMetricFile.computeStatisticalShuffledTMap(iterations, numberInFirstGroup, &topologyFile, varianceSmoothingIterations, varianceSmoothingStrength, poolTheVarianceFlag); outputMetricFile->writeFile(outputMetricFileName); delete outputMetricFile; } ././@LongLink0000000000000000000000000000014700000000000011567 Lustar rootrootcaret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricStatisticsShuffledCrossCorrelationMaps.hcaret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricStatisticsShuffledCrossCorrelationMaps0000664000175000017500000000372611572067322034066 0ustar michaelmichael #ifndef __COMMAND_METRIC_STATISTICS_SHUFFLED_CROSS_CORRELATION_MAPS_H__ #define __COMMAND_METRIC_STATISTICS_SHUFFLED_CROSS_CORRELATION_MAPS_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for shuffled cross correlation maps class CommandMetricStatisticsShuffledCrossCorrelationMaps : public CommandBase { public: // constructor CommandMetricStatisticsShuffledCrossCorrelationMaps(); // destructor ~CommandMetricStatisticsShuffledCrossCorrelationMaps(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_METRIC_STATISTICS_SHUFFLED_CROSS_CORRELATION_MAPS_H__ ././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootcaret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricStatisticsShuffledCrossCorrelationMaps.cxxcaret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricStatisticsShuffledCrossCorrelationMaps0000664000175000017500000000700411572067322034057 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandMetricStatisticsShuffledCrossCorrelationMaps.h" #include "FileFilters.h" #include "MetricFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandMetricStatisticsShuffledCrossCorrelationMaps::CommandMetricStatisticsShuffledCrossCorrelationMaps() : CommandBase("-metric-statistics-shuffled-cross-correlation-map", "METRIC STATISTICS SHUFFLED CROSS CORRELATION MAP") { } /** * destructor. */ CommandMetricStatisticsShuffledCrossCorrelationMaps::~CommandMetricStatisticsShuffledCrossCorrelationMaps() { } /** * get the script builder parameters. */ void CommandMetricStatisticsShuffledCrossCorrelationMaps::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Metric File Name", FileFilters::getMetricShapeFileFilter()); paramsOut.addFile("Output Metric File Name", FileFilters::getMetricShapeFileFilter()); paramsOut.addInt("Iteration", 50); } /** * get full help information. */ QString CommandMetricStatisticsShuffledCrossCorrelationMaps::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Randomly select two data columns and multiply them together\n" + indent9 + "to produce a new column. Repeat for the specified number\n" + indent9 + "of iterations.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandMetricStatisticsShuffledCrossCorrelationMaps::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputMetricFileName = parameters->getNextParameterAsString("Input Metric File Name"); const QString outputMetricFileName = parameters->getNextParameterAsString("Output Metric File Name"); const int iterations = parameters->getNextParameterAsInt("Iterations"); checkForExcessiveParameters(); MetricFile metricFile; metricFile.readFile(inputMetricFileName); MetricFile* outputMetricFile = metricFile.computeShuffledCrossCorrelationsMap(iterations); outputMetricFile->writeFile(outputMetricFileName); delete outputMetricFile; } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricStatisticsPairedTTest.h0000664000175000017500000000354211572067322030703 0ustar michaelmichael #ifndef __COMMAND_METRIC_STATISTICS_PAIRED_T_TEST_H__ #define __COMMAND_METRIC_STATISTICS_PAIRED_T_TEST_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for metric paired T-Test class CommandMetricStatisticsPairedTTest : public CommandBase { public: // constructor CommandMetricStatisticsPairedTTest(); // destructor ~CommandMetricStatisticsPairedTTest(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_METRIC_STATISTICS_PAIRED_T_TEST_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricStatisticsPairedTTest.cxx0000664000175000017500000001743211572067322031261 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurfaceMetricOneAndPairedTTest.h" #include "BrainSet.h" #include "CommandMetricStatisticsPairedTTest.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandMetricStatisticsPairedTTest::CommandMetricStatisticsPairedTTest() : CommandBase("-metric-statistics-paired-t-test", "METRIC STATISTICS PAIRED T-TEST") { } /** * destructor. */ CommandMetricStatisticsPairedTTest::~CommandMetricStatisticsPairedTTest() { } /** * get the script builder parameters. */ void CommandMetricStatisticsPairedTTest::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Metric File Name A", FileFilters::getMetricShapeFileFilter()); paramsOut.addFile("Metric File Name B", FileFilters::getMetricShapeFileFilter()); paramsOut.addFile("Fiducial Coordinate File Name", FileFilters::getCoordinateFiducialFileFilter()); paramsOut.addFile("Open Topology File Name", FileFilters::getTopologyOpenFileFilter()); paramsOut.addFile("Distoration Metric File Name", FileFilters::getMetricShapeFileFilter()); paramsOut.addInt("Distortion Column Number"); paramsOut.addString("Output File Names Prefix"); paramsOut.addFloat("Negative Threshold"); paramsOut.addFloat("Positive Threshold"); paramsOut.addFloat("P-Value"); paramsOut.addInt("Variance Smoothing Iterations"); paramsOut.addFloat("Variance Smoothing Strength"); paramsOut.addInt("Iterations"); paramsOut.addInt("Number of Threads", 1); } /** * get full help information. */ QString CommandMetricStatisticsPairedTTest::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + "Perform a paired T-Test on the metric file. \n" + indent9 + " \n" + indent9 + "The distortion column number starts at 1. \n" + indent9 + " \n" + indent9 + "Number of threads is the number of concurrent processes run \n" + indent9 + "during the cluster search of the shuffled metric file. \n" + indent9 + "Use \"1\" if you are running on a single processor system. \n" + indent9 + "Users on systems with multiple processors or multi-core systems \n" + indent9 + "should set the number of threads to the number of processors \n" + indent9 + "and/or cores to reduce execution time. \n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandMetricStatisticsPairedTTest::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString metricShapeFileA = parameters->getNextParameterAsString("Metric or Shape File A"); const QString metricShapeFileB = parameters->getNextParameterAsString("Metric or Shape File B"); const QString fiducialCoordFileName = parameters->getNextParameterAsString("Fiducial Coordinate File Name"); const QString openTopoFileName = parameters->getNextParameterAsString("Open Topology File Name"); const QString distortionMetricShapeFileName = parameters->getNextParameterAsString("Distortion Metric/Shape File Name"); int distortionColumnNumber = parameters->getNextParameterAsInt("Distortion Column Number"); const QString outputFileNamePrefix = parameters->getNextParameterAsString("Output File Name Prefix"); const float negativeThreshold = parameters->getNextParameterAsFloat("Negative Threshold"); const float positiveThreshold = parameters->getNextParameterAsFloat("Positive Threshold"); const float pValue = parameters->getNextParameterAsFloat("P-Value"); const int varianceSmoothingIterations = parameters->getNextParameterAsInt("Variance Smoothing Iterations"); const float varianceSmoothingStrength = parameters->getNextParameterAsFloat("Variance Smoothing Strength"); const int iterations = parameters->getNextParameterAsInt("Iterations"); const int numberOfThreads = parameters->getNextParameterAsInt("Number of Threads"); checkForExcessiveParameters(); if (distortionColumnNumber <= 0) { throw CommandException("Distortion column number must be >= 1."); } distortionColumnNumber--; // algorithm starts at zero const QString ext = metricShapeFileA.endsWith(SpecFile::getMetricFileExtension()) ? SpecFile::getMetricFileExtension() : SpecFile::getSurfaceShapeFileExtension(); const QString outputTMapFileName(outputFileNamePrefix + "_TMap" + ext); const QString outputShuffledTMapFileName(outputFileNamePrefix + "_ShuffledTMap" + ext); const QString outputPaintFileName(outputFileNamePrefix + "_TMapClusters" + SpecFile::getPaintFileExtension()); const QString outputMetricFileName(outputFileNamePrefix + "_TMapClusters" + SpecFile::getMetricFileExtension()); const QString outputReportFileName(outputFileNamePrefix + "_TMap_Significant_Clusters" + SpecFile::getTextFileExtension()); std::vector metricAndShapeFiles; metricAndShapeFiles.push_back(metricShapeFileA); metricAndShapeFiles.push_back(metricShapeFileB); BrainSet bs; BrainModelSurfaceMetricOneAndPairedTTest oneSample(&bs, BrainModelSurfaceMetricOneAndPairedTTest::T_TEST_MODE_PAIRED, metricAndShapeFiles, fiducialCoordFileName, openTopoFileName, distortionMetricShapeFileName, outputTMapFileName, outputShuffledTMapFileName, outputPaintFileName, outputMetricFileName, outputReportFileName, distortionColumnNumber, negativeThreshold, positiveThreshold, pValue, varianceSmoothingIterations, varianceSmoothingStrength, iterations, 0.0, numberOfThreads); oneSample.execute(); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricStatisticsOneSampleTTest.h0000664000175000017500000000354211572067322031362 0ustar michaelmichael #ifndef __COMMAND_METRIC_STATISTICS_ONE_SAMPLE_T_TEST_H__ #define __COMMAND_METRIC_STATISTICS_ONE_SAMPLE_T_TEST_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandMetricStatisticsOneSampleTTest : public CommandBase { public: // constructor CommandMetricStatisticsOneSampleTTest(); // destructor ~CommandMetricStatisticsOneSampleTTest(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_METRIC_STATISTICS_ONE_SAMPLE_T_TEST_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricStatisticsOneSampleTTest.cxx0000664000175000017500000001744711572067322031746 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurfaceMetricOneAndPairedTTest.h" #include "BrainSet.h" #include "CommandMetricStatisticsOneSampleTTest.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandMetricStatisticsOneSampleTTest::CommandMetricStatisticsOneSampleTTest() : CommandBase("-metric-statistics-one-sample-t-test", "METRIC STATISTICS ONE SAMPLE T-TEST") { } /** * destructor. */ CommandMetricStatisticsOneSampleTTest::~CommandMetricStatisticsOneSampleTTest() { } /** * get the script builder parameters. */ void CommandMetricStatisticsOneSampleTTest::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Metric or Shape File Name", FileFilters::getMetricShapeFileFilter()); paramsOut.addFile("Fiducial Coordinate File Name", FileFilters::getCoordinateFiducialFileFilter()); paramsOut.addFile("Open Topology File Name", FileFilters::getTopologyOpenFileFilter()); paramsOut.addFile("Distoration Metric or ShapeFile Name", FileFilters::getMetricShapeFileFilter()); paramsOut.addInt("Distortion Column Number"); paramsOut.addString("Output File Names Prefix"); paramsOut.addFloat("Negative Threshold"); paramsOut.addFloat("Positive Threshold"); paramsOut.addFloat("P-Value"); paramsOut.addInt("Variance Smoothing Iterations"); paramsOut.addFloat("Variance Smoothing Strength"); paramsOut.addInt("Iterations"); paramsOut.addFloat("T-Test Constant"); paramsOut.addInt("Number of Threads", 1); } /** * get full help information. */ QString CommandMetricStatisticsOneSampleTTest::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + "\n" + indent9 + " Perform a one-sample T-Test on the metric file.\n" + indent9 + " \n" + indent9 + " The distortion column number starts at 1.\n" + indent9 + " \n" + indent9 + " Number of threads is the number of concurrent processes run\n" + indent9 + " during the cluster search of the shuffled metric file.\n" + indent9 + " Use \"1\" if you are running on a single processor system.\n" + indent9 + " Users on systems with multiple processors or multi-core systems\n" + indent9 + " should set the number of threads to the number of processors\n" + indent9 + " and/or cores to reduce execution time.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandMetricStatisticsOneSampleTTest::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString metricShapeFile = parameters->getNextParameterAsString("Metric or Shape File"); const QString fiducialCoordFileName = parameters->getNextParameterAsString("Fiducial Coordinate File Name"); const QString openTopoFileName = parameters->getNextParameterAsString("Open Topology File Name"); const QString distortionMetricShapeFileName = parameters->getNextParameterAsString("Distortion Metric/Shape File Name"); int distortionColumnNumber = parameters->getNextParameterAsInt("Distortion Column Number"); const QString outputFileNamePrefix = parameters->getNextParameterAsString("Output File Name Prefix"); const float negativeThreshold = parameters->getNextParameterAsFloat("Negative Threshold"); const float positiveThreshold = parameters->getNextParameterAsFloat("Positive Threshold"); const float pValue = parameters->getNextParameterAsFloat("P-Value"); const int varianceSmoothingIterations = parameters->getNextParameterAsInt("Variance Smoothing Iterations"); const float varianceSmoothingStrength = parameters->getNextParameterAsFloat("Variance Smoothing Strength"); const int iterations = parameters->getNextParameterAsInt("Iterations"); const float tTestConstant = parameters->getNextParameterAsFloat("T-Test Constant"); const int numberOfThreads = parameters->getNextParameterAsInt("Number of Threads"); checkForExcessiveParameters(); if (distortionColumnNumber <= 0) { throw CommandException("Distortion column number must be >= 1."); } distortionColumnNumber--; // algorithm starts at zero const QString ext = metricShapeFile.endsWith(SpecFile::getMetricFileExtension()) ? SpecFile::getMetricFileExtension() : SpecFile::getSurfaceShapeFileExtension(); const QString outputTMapFileName(outputFileNamePrefix + "_TMap" + ext); const QString outputShuffledTMapFileName(outputFileNamePrefix + "_ShuffledTMap" + ext); const QString outputPaintFileName(outputFileNamePrefix + "_TMapClusters" + SpecFile::getPaintFileExtension()); const QString outputMetricFileName(outputFileNamePrefix + "_TMapClusters" + SpecFile::getMetricFileExtension()); const QString outputReportFileName(outputFileNamePrefix + "_TMap_Significant_Clusters" + SpecFile::getTextFileExtension()); std::vector metricAndShapeFiles; metricAndShapeFiles.push_back(metricShapeFile); BrainSet bs; BrainModelSurfaceMetricOneAndPairedTTest oneSample(&bs, BrainModelSurfaceMetricOneAndPairedTTest::T_TEST_MODE_ONE_SAMPLE, metricAndShapeFiles, fiducialCoordFileName, openTopoFileName, distortionMetricShapeFileName, outputTMapFileName, outputShuffledTMapFileName, outputPaintFileName, outputMetricFileName, outputReportFileName, distortionColumnNumber, negativeThreshold, positiveThreshold, pValue, varianceSmoothingIterations, varianceSmoothingStrength, iterations, tTestConstant, numberOfThreads); oneSample.execute(); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricStatisticsNormalization.h0000664000175000017500000000355011572067322031340 0ustar michaelmichael #ifndef __COMMAND_METRIC_STATISTICS_NORMALIZATION_H__ #define __COMMAND_METRIC_STATISTICS_NORMALIZATION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for metric normalization class CommandMetricStatisticsNormalization : public CommandBase { public: // constructor CommandMetricStatisticsNormalization(); // destructor ~CommandMetricStatisticsNormalization(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_METRIC_STATISTICS_NORMALIZATION_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricStatisticsNormalization.cxx0000664000175000017500000000702411572067322031713 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandMetricStatisticsNormalization.h" #include "FileFilters.h" #include "MetricFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandMetricStatisticsNormalization::CommandMetricStatisticsNormalization() : CommandBase("-metric-statistics-normalization", "METRIC STATISTICS NORMALIZATION") { } /** * destructor. */ CommandMetricStatisticsNormalization::~CommandMetricStatisticsNormalization() { } /** * get the script builder parameters. */ void CommandMetricStatisticsNormalization::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Metric File Name", FileFilters::getMetricShapeFileFilter()); paramsOut.addFile("Output Metric File Name", FileFilters::getMetricShapeFileFilter()); paramsOut.addFloat("Mean", 0.0); paramsOut.addFloat("Standard Deviation", 1.0); } /** * get full help information. */ QString CommandMetricStatisticsNormalization::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Remape each column in the metric file so that its fits\n" + indent9 + "a normalized (gaussian) distribution using the specified\n" + indent9 + "mean an standard deviation.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandMetricStatisticsNormalization::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputMetricFileName = parameters->getNextParameterAsString("Input Metric File Name"); const QString outputMetricFileName = parameters->getNextParameterAsString("Output Metric File Name"); const float mean = parameters->getNextParameterAsFloat("Mean"); const float standardDeviation = parameters->getNextParameterAsFloat("Mean"); checkForExcessiveParameters(); MetricFile metricFile; metricFile.readFile(inputMetricFileName); MetricFile* outputMetricFile = metricFile.computeNormalization(mean, standardDeviation); outputMetricFile->writeFile(outputMetricFileName); delete outputMetricFile; } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricStatisticsLeveneMap.h0000664000175000017500000000353311572067322030367 0ustar michaelmichael #ifndef __COMMAND_METRIC_STATISTICS_LEVENE_MAP_H__ #define __COMMAND_METRIC_STATISTICS_LEVENE_MAP_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for metric statistics levene map class CommandMetricStatisticsLeveneMap : public CommandBase { public: // constructor CommandMetricStatisticsLeveneMap(); // destructor ~CommandMetricStatisticsLeveneMap(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_METRIC_STATISTICS_LEVENE_MAP_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricStatisticsLeveneMap.cxx0000664000175000017500000000711211572067322030737 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandMetricStatisticsLeveneMap.h" #include "FileFilters.h" #include "MetricFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandMetricStatisticsLeveneMap::CommandMetricStatisticsLeveneMap() : CommandBase("-metric-statistics-levene-map", "METRIC STATISTICS LEVENE MAP") { } /** * destructor. */ CommandMetricStatisticsLeveneMap::~CommandMetricStatisticsLeveneMap() { } /** * get the script builder parameters. */ void CommandMetricStatisticsLeveneMap::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Output Metric File Name", FileFilters::getMetricShapeFileFilter()); paramsOut.addMultipleFiles("Input Metric File Names", FileFilters::getMetricShapeFileFilter()); } /** * get full help information. */ QString CommandMetricStatisticsLeveneMap::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Compute a Levene Map. The output metric file will contain\n" + indent9 + "the Levene F-Statistic, the numerator degrees of freedom,\n" + indent9 + "the denominator degrees of freedom, and a P-Value.\n" + indent9 + "\n" + indent9 + "References:\n" + indent9 + " http://www.people.vcu.edu/~wsstreet/courses/314_20033/Handout.Levene.pdf\n" + indent9 + " http://www.itl.nist.gov/div898/handbook/eda/section3/eda35a.htm\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandMetricStatisticsLeveneMap::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString outputMetricFileName = parameters->getNextParameterAsString("Output Metric File Name"); std::vector inputMetricFiles; while (parameters->getParametersAvailable()) { const QString inputMetricFileName = parameters->getNextParameterAsString("Input Metric File Name"); MetricFile* mf = new MetricFile; mf->readFile(inputMetricFileName); inputMetricFiles.push_back(mf); } MetricFile* outputMetricFile = MetricFile::computeStatisticalLeveneMap(inputMetricFiles); outputMetricFile->writeFile(outputMetricFileName); delete outputMetricFile; } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricStatisticsKruskalWallis.h0000664000175000017500000000357411572067322031310 0ustar michaelmichael #ifndef __COMMAND_METRIC_STATISTICS_KRUSKAL_WALLIS_H__ #define __COMMAND_METRIC_STATISTICS_KRUSKAL_WALLIS_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for metric statistics kruskal wallis test class CommandMetricStatisticsKruskalWallis : public CommandBase { public: // constructor CommandMetricStatisticsKruskalWallis(); // destructor ~CommandMetricStatisticsKruskalWallis(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_METRIC_STATISTICS_KRUSKAL_WALLIS_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricStatisticsKruskalWallis.cxx0000664000175000017500000001755011572067322031662 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurfaceMetricKruskalWallisRankTest.h" #include "BrainSet.h" #include "CommandMetricStatisticsKruskalWallis.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandMetricStatisticsKruskalWallis::CommandMetricStatisticsKruskalWallis() : CommandBase("-metric-statistics-kruskal-wallis", "METRIC STATISTICS KRUSKAL-WALLIS") { } /** * destructor. */ CommandMetricStatisticsKruskalWallis::~CommandMetricStatisticsKruskalWallis() { } /** * get the script builder parameters. */ void CommandMetricStatisticsKruskalWallis::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Fiducial Coordinate File Name", FileFilters::getCoordinateFiducialFileFilter()); paramsOut.addFile("Open Topology File Name", FileFilters::getTopologyOpenFileFilter()); paramsOut.addFile("Distoration Metric File Name", FileFilters::getMetricShapeFileFilter()); paramsOut.addInt("Distortion Column Number"); paramsOut.addString("Output File Names Prefix"); paramsOut.addInt("Iterations"); paramsOut.addFloat("Positive Threshold"); paramsOut.addFloat("P-Value"); paramsOut.addBoolean("Do F-Map Degrees of Freedom"); paramsOut.addBoolean("Doe F-Map P-Value"); paramsOut.addInt("Number of Threads", 1); paramsOut.addMultipleFiles("Metric File Names", FileFilters::getMetricShapeFileFilter()); } /** * get full help information. */ QString CommandMetricStatisticsKruskalWallis::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " \\ \n" + indent9 + " \\ \n" + indent9 + " \\ \n" + indent9 + " \\ \n" + indent9 + " \\ \n" + indent9 + " \\ \n" + indent9 + " \\ \n" + indent9 + " \\ \n" + indent9 + " \\ \n" + indent9 + " \\ \n" + indent9 + " \\ \n" + indent9 + " \n" + indent9 + " \n" + indent9 + "Perform a Kruskal-Wallis Rank Test (essentially a non-parametric \n" + indent9 + "one-way analysis of variance) on the input metric files. \n" + indent9 + "There must be at least two metric files and each of the \n" + indent9 + "metric files contains all of the subjects for one factor level. \n" + indent9 + " \n" + indent9 + "The distortion column number starts at 1. \n" + indent9 + " \n" + indent9 + "Number of threads is the number of concurrent processes run \n" + indent9 + "during the cluster search of the shuffled metric file. \n" + indent9 + "Use \"1\" if you are running on a single processor system. \n" + indent9 + "Users on systems with multiple processors or multi-core systems \n" + indent9 + "should set the number of threads to the number of processors \n" + indent9 + "and/or cores to reduce execution time. \n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandMetricStatisticsKruskalWallis::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString fiducialCoordFileName = parameters->getNextParameterAsString("Fiducial Coordinate File Name"); const QString openTopoFileName = parameters->getNextParameterAsString("Open Topology File Name"); const QString distortionMetricShapeFileName = parameters->getNextParameterAsString("Distortion Metric/Shape File Name"); int distortionColumnNumber = parameters->getNextParameterAsInt("Distortion Column Number"); const QString outputFileNamePrefix = parameters->getNextParameterAsString("Output File Name Prefix"); const int iterations = parameters->getNextParameterAsInt("Iterations"); const float positiveThreshold = parameters->getNextParameterAsFloat("Positive Threshold"); const float pValue = parameters->getNextParameterAsFloat("P-Value"); const bool doFMapDOF = parameters->getNextParameterAsBoolean("Do F-Map Degrees of Freedom"); const bool doFMapPValue = parameters->getNextParameterAsBoolean("Do F-Map P-Value"); const int numberOfThreads = parameters->getNextParameterAsInt("Number of Threads"); std::vector metricFileNames; while (parameters->getParametersAvailable()) { metricFileNames.push_back( parameters->getNextParameterAsString("Metric File Names")); } if (distortionColumnNumber <= 0) { throw CommandException("Distortion column number must be >= 1."); } distortionColumnNumber--; // algorithm starts at zero if (metricFileNames.empty()) { throw CommandException("No Metric/Shape files provided."); } const QString ext = metricFileNames[0].endsWith(SpecFile::getMetricFileExtension()) ? SpecFile::getMetricFileExtension() : SpecFile::getSurfaceShapeFileExtension(); const QString outputFMapFileName(outputFileNamePrefix + "_FMap" + ext); const QString outputShuffledFMapFileName(outputFileNamePrefix + "_ShuffledFMap" + ext); const QString outputPaintFileName(outputFileNamePrefix + "_FMapClusters" + SpecFile::getPaintFileExtension()); const QString outputMetricFileName(outputFileNamePrefix + "_FMapClusters" + SpecFile::getMetricFileExtension()); const QString outputReportFileName(outputFileNamePrefix + "_FMap_Significant_Clusters" + SpecFile::getTextFileExtension()); BrainSet bs; BrainModelSurfaceMetricKruskalWallisRankTest kw(&bs, metricFileNames, fiducialCoordFileName, openTopoFileName, distortionMetricShapeFileName, outputFMapFileName, outputShuffledFMapFileName, outputPaintFileName, outputMetricFileName, outputReportFileName, distortionColumnNumber, iterations, positiveThreshold, pValue, doFMapDOF, doFMapPValue, numberOfThreads); kw.execute(); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricStatisticsInterhemisphericClusters.h0000664000175000017500000000367611572067322033552 0ustar michaelmichael #ifndef __COMMAND_METRIC_STATISTICS_INTERHEMISPHERIC_CLUSTERS_H__ #define __COMMAND_METRIC_STATISTICS_INTERHEMISPHERIC_CLUSTERS_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for determining interhemispheric clusters class CommandMetricStatisticsInterhemisphericClusters : public CommandBase { public: // constructor CommandMetricStatisticsInterhemisphericClusters(); // destructor ~CommandMetricStatisticsInterhemisphericClusters(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_METRIC_STATISTICS_INTERHEMISPHERIC_CLUSTERS_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricStatisticsInterhemisphericClusters.cxx0000664000175000017500000002302111572067322034107 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainSet.h" #include "BrainModelSurfaceMetricInterHemClusters.h" #include "CommandMetricStatisticsInterhemisphericClusters.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandMetricStatisticsInterhemisphericClusters::CommandMetricStatisticsInterhemisphericClusters() : CommandBase("-metric-statistics-interhemispheric-clusters", "METRIC STATISTICS INTERHEMISPHERIC CLUSTERS") { } /** * destructor. */ CommandMetricStatisticsInterhemisphericClusters::~CommandMetricStatisticsInterhemisphericClusters() { } /** * get the script builder parameters. */ void CommandMetricStatisticsInterhemisphericClusters::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Right Group A Metric File Name", FileFilters::getMetricShapeFileFilter()); paramsOut.addFile("Right Group B Metric File Name", FileFilters::getMetricShapeFileFilter()); paramsOut.addFile("Left Group A Metric File Name", FileFilters::getMetricShapeFileFilter()); paramsOut.addFile("Left Group B Metric File Name", FileFilters::getMetricShapeFileFilter()); paramsOut.addFile("Fiducial Coordinate File Name", FileFilters::getCoordinateFiducialFileFilter()); paramsOut.addFile("Open Topology File Name", FileFilters::getTopologyOpenFileFilter()); paramsOut.addFile("Distoration Metric File Name", FileFilters::getMetricShapeFileFilter()); paramsOut.addInt("Distortion Column Number"); paramsOut.addString("Output File Names Prefix"); paramsOut.addInt("Iterations Shuffled T-Map"); paramsOut.addInt("Iterations Right/Left Shuffled T-Map"); paramsOut.addFloat("Positive Threshold"); paramsOut.addFloat("Negative Threshold"); paramsOut.addFloat("P-Value"); paramsOut.addInt("Variance Smoothing Iterations"); paramsOut.addFloat("Variance Smoothing Strength"); paramsOut.addBoolean("Do T-Map Degrees of Freedom"); paramsOut.addBoolean("Do T-Map P-Value"); paramsOut.addInt("Number of Threads", 1); } /** * get full help information. */ QString CommandMetricStatisticsInterhemisphericClusters::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + "Search for interhemispheric clusters. \n" + indent9 + " \n" + indent9 + "The distortion column number starts at 1. \n" + indent9 + " \n" + indent9 + "Number of threads is the number of concurrent processes run \n" + indent9 + "during the cluster search of the shuffled metric file. \n" + indent9 + "Use \"1\" if you are running on a single processor system. \n" + indent9 + "Users on systems with multiple processors or multi-core systems \n" + indent9 + "should set the number of threads to the number of processors \n" + indent9 + "and/or cores to reduce execution time. \n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandMetricStatisticsInterhemisphericClusters::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString rightMetricShapeFileA = parameters->getNextParameterAsString("Right Metric or Shape File A"); const QString rightMetricShapeFileB = parameters->getNextParameterAsString("Right Metric or Shape File B"); const QString leftMetricShapeFileA = parameters->getNextParameterAsString("Left Metric or Shape File A"); const QString leftMetricShapeFileB = parameters->getNextParameterAsString("Left Metric or Shape File B"); const QString fiducialCoordFileName = parameters->getNextParameterAsString("Fiducial Coordinate File Name"); const QString openTopoFileName = parameters->getNextParameterAsString("Open Topology File Name"); const QString distortionMetricShapeFileName = parameters->getNextParameterAsString("Distortion Metric/Shape File Name"); int distortionColumnNumber = parameters->getNextParameterAsInt("Distortion Column Number"); const QString outputFileNamePrefix = parameters->getNextParameterAsString("Output File Name Prefix"); const int iterations = parameters->getNextParameterAsInt("Iterations"); const int rightLeftIterations = parameters->getNextParameterAsInt("Right/Left Iterations"); const float negativeThreshold = parameters->getNextParameterAsFloat("Negative Threshold"); const float positiveThreshold = parameters->getNextParameterAsFloat("Positive Threshold"); const float pValue = parameters->getNextParameterAsFloat("P-Value"); const int varianceSmoothingIterations = parameters->getNextParameterAsInt("Variance Smoothing Iterations"); const float varianceSmoothingStrength = parameters->getNextParameterAsFloat("Variance Smoothing Strength"); const bool doTMapDOF = parameters->getNextParameterAsBoolean("Do T-Map DOF"); const bool doTMapPValue = parameters->getNextParameterAsBoolean("Do T-Map P-Value"); const int numberOfThreads = parameters->getNextParameterAsInt("Number of Threads"); if (distortionColumnNumber <= 0) { throw CommandException("Distortion column number must be >= 1."); } distortionColumnNumber--; // algorithm starts at zero const QString ext = rightMetricShapeFileA.endsWith(SpecFile::getMetricFileExtension()) ? SpecFile::getMetricFileExtension() : SpecFile::getSurfaceShapeFileExtension(); QString outputRightTMapFileName(outputFileNamePrefix + "_RIGHT_TMap" + ext); QString outputLeftTMapFileName(outputFileNamePrefix + "_LEFT_TMap" + ext); QString outputRightShuffledTMapFileName(outputFileNamePrefix + "_RIGHT_ShuffledTMap" + ext); QString outputLeftShuffledTMapFileName(outputFileNamePrefix + "_LEFT_ShuffledTMap" + ext); const QString outputTMapFileName(outputFileNamePrefix + "_TMap" + ext); const QString outputShuffledTMapFileName(outputFileNamePrefix + "_ShuffledTMap" + ext); const QString outputPaintFileName(outputFileNamePrefix + "_TMapClusters" + SpecFile::getPaintFileExtension()); const QString outputMetricFileName(outputFileNamePrefix + "_TMapClusters" + SpecFile::getMetricFileExtension()); const QString outputReportFileName(outputFileNamePrefix + "_TMap_Significant_Clusters" + SpecFile::getTextFileExtension()); BrainSet bs; BrainModelSurfaceMetricInterHemClusters interHem(&bs, rightMetricShapeFileA, rightMetricShapeFileB, leftMetricShapeFileA, leftMetricShapeFileB, fiducialCoordFileName, openTopoFileName, distortionMetricShapeFileName, outputRightTMapFileName, outputLeftTMapFileName, outputRightShuffledTMapFileName, outputLeftShuffledTMapFileName, outputTMapFileName, outputShuffledTMapFileName, outputPaintFileName, outputMetricFileName, outputReportFileName, distortionColumnNumber, iterations, rightLeftIterations, negativeThreshold, positiveThreshold, pValue, varianceSmoothingIterations, varianceSmoothingStrength, doTMapDOF, doTMapPValue, numberOfThreads); interHem.execute(); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricStatisticsCoordinateDifference.h0000664000175000017500000000365011572067322032555 0ustar michaelmichael #ifndef __COMMAND_METRIC_STATISTICS_COORDINATE_DIFFERENCE_H__ #define __COMMAND_METRIC_STATISTICS_COORDINATE_DIFFERENCE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for metric statistics coordinate difference class CommandMetricStatisticsCoordinateDifference : public CommandBase { public: // constructor CommandMetricStatisticsCoordinateDifference(); // destructor ~CommandMetricStatisticsCoordinateDifference(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_METRIC_STATISTICS_COORDINATE_DIFFERENCE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricStatisticsCoordinateDifference.cxx0000664000175000017500000002113611572067322033127 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurfaceMetricCoordinateDifference.h" #include "BrainSet.h" #include "CommandMetricStatisticsCoordinateDifference.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandMetricStatisticsCoordinateDifference::CommandMetricStatisticsCoordinateDifference() : CommandBase("-metric-statistics-coordinate-difference", "METRIC STATISTICS COORDINATE DIFFERENCE") { } /** * destructor. */ CommandMetricStatisticsCoordinateDifference::~CommandMetricStatisticsCoordinateDifference() { } /** * get the script builder parameters. */ void CommandMetricStatisticsCoordinateDifference::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { std::vector values, descriptions; values.push_back("COORD_DIFF"); descriptions.push_back("Use Coordinate Difference"); values.push_back("TMAP_DIFF"); descriptions.push_back("Perform T-Test of Coordinate Difference"); paramsOut.clear(); paramsOut.addListOfItems("Mode", values, descriptions); paramsOut.addFile("Fiducial Coordinate File Name", FileFilters::getCoordinateFiducialFileFilter()); paramsOut.addFile("Open Topology File Name", FileFilters::getTopologyOpenFileFilter()); paramsOut.addFile("Distoration Metric File Name", FileFilters::getMetricShapeFileFilter()); paramsOut.addInt("Distortion Column Number"); paramsOut.addString("Output File Names Prefix"); paramsOut.addInt("Iterations"); paramsOut.addFloat("Threshold"); paramsOut.addFloat("P-Value"); paramsOut.addInt("Number of Threads", 1); paramsOut.addVariableListOfParameters("Coordinate Files"); } /** * get full help information. */ QString CommandMetricStatisticsCoordinateDifference::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " -groupA \n" + indent9 + " -groupB \n" + indent9 + " \n" + indent9 + "Find clusters in groups of coordinate files. \n" + indent9 + " \n" + indent9 + "mode is one of: \n" + indent9 + " COORD_DIFF - search for clusters in coordinate difference. \n" + indent9 + " TMAP_DIFF - search for clusters using T-Test of coordinate difference. \n" + indent9 + " \n" + indent9 + "The distortion column number starts at 1. \n" + indent9 + " \n" + indent9 + "Number of threads is the number of concurrent processes run \n" + indent9 + "during the cluster search of the shuffled metric file. \n" + indent9 + "Use \"1\" if you are running on a single processor system. \n" + indent9 + "Users on systems with multiple processors or multi-core systems \n" + indent9 + "should set the number of threads to the number of processors \n" + indent9 + "and/or cores to reduce execution time. \n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandMetricStatisticsCoordinateDifference::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString modeName = parameters->getNextParameterAsString("Mode"); const QString fiducialCoordFileName = parameters->getNextParameterAsString("Fiducial Coordinate File Name"); const QString openTopoFileName = parameters->getNextParameterAsString("Open Topology File Name"); const QString distortionMetricShapeFileName = parameters->getNextParameterAsString("Distortion Metric/Shape File Name"); int distortionColumnNumber = parameters->getNextParameterAsInt("Distortion Column Number"); QString outputFileNamePrefix = parameters->getNextParameterAsString("Output File Name Prefix"); const int iterations = parameters->getNextParameterAsInt("Iterations"); const float threshold = parameters->getNextParameterAsFloat("Threshold"); const float pValue = parameters->getNextParameterAsFloat("P-Value"); const int numberOfThreads = parameters->getNextParameterAsInt("Number of Threads"); std::vector coordFileNamesGroupA, coordFileNamesGroupB; bool doingGroupA = false; bool doingGroupB = false; while (parameters->getParametersAvailable()) { const QString arg = parameters->getNextParameterAsString("Coordinate File Names"); if (arg == "-groupA") { doingGroupA = true; doingGroupB = false; } else if (arg == "-groupB") { doingGroupB = true; doingGroupA = false; } else if (doingGroupA) { coordFileNamesGroupA.push_back(arg); } else if (doingGroupB) { coordFileNamesGroupB.push_back(arg); } else { throw CommandException("Invalid parameter in groups of files: " + arg); } } BrainModelSurfaceMetricCoordinateDifference::MODE mode; if (modeName == "COORD_DIFF") { mode = BrainModelSurfaceMetricCoordinateDifference::MODE_COORDINATE_DIFFERENCE; } else if (modeName == "TMAP_DIFF") { mode = BrainModelSurfaceMetricCoordinateDifference::MODE_TMAP_DIFFERENCE; } else { throw CommandException("Invalid mode: " + modeName); } if (distortionColumnNumber <= 0) { throw CommandException("Distortion column number must be >= 1."); } distortionColumnNumber--; // algorithm starts at zero //const QString ext = metricShapeFileA.endsWith(SpecFile::getMetricFileExtension()) // ? SpecFile::getMetricFileExtension() // : SpecFile::getSurfaceShapeFileExtension(); const QString ext = SpecFile::getMetricFileExtension(); const QString outputDistanceFileName(outputFileNamePrefix + "_DistanceOrTMap" + ext); const QString outputShuffledDistanceFileName(outputFileNamePrefix + "_Shuffled_DistanceOrTMap" + ext); const QString outputPaintFileName(outputFileNamePrefix + "_DistanceOrTMapClusters" + SpecFile::getPaintFileExtension()); const QString outputMetricFileName(outputFileNamePrefix + "_DistanceOrTMapClusters" + SpecFile::getMetricFileExtension()); const QString outputReportFileName(outputFileNamePrefix + "_DistanceOrTMap_Significant_Clusters" + SpecFile::getTextFileExtension()); BrainSet bs; BrainModelSurfaceMetricCoordinateDifference coordDiffAlg(&bs, mode, coordFileNamesGroupA, coordFileNamesGroupB, fiducialCoordFileName, openTopoFileName, distortionMetricShapeFileName, outputDistanceFileName, outputShuffledDistanceFileName, outputPaintFileName, outputMetricFileName, outputReportFileName, distortionColumnNumber, iterations, threshold, pValue, numberOfThreads); coordDiffAlg.execute(); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricStatisticsAnovaTwoWay.h0000664000175000017500000000351511572067322030732 0ustar michaelmichael #ifndef __COMMAND_METRIC_STATISTICS_ANOVA_TWO_WAY_H__ #define __COMMAND_METRIC_STATISTICS_ANOVA_TWO_WAY_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandMetricStatisticsAnovaTwoWay : public CommandBase { public: // constructor CommandMetricStatisticsAnovaTwoWay(); // destructor ~CommandMetricStatisticsAnovaTwoWay(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_METRIC_STATISTICS_ANOVA_TWO_WAY_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricStatisticsAnovaTwoWay.cxx0000664000175000017500000002446211572067322031311 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurfaceMetricAnovaTwoWay.h" #include "BrainSet.h" #include "CommandMetricStatisticsAnovaTwoWay.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandMetricStatisticsAnovaTwoWay::CommandMetricStatisticsAnovaTwoWay() : CommandBase("-metric-statistics-anova-two-way", "METRIC STATISTICS TWO-WAY ANOVA") { } /** * destructor. */ CommandMetricStatisticsAnovaTwoWay::~CommandMetricStatisticsAnovaTwoWay() { } /** * get the script builder parameters. */ void CommandMetricStatisticsAnovaTwoWay::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { std::vector values, descriptions; values.push_back("FIXED"); descriptions.push_back("Both Factors are Fixed"); values.push_back("RANDOM"); descriptions.push_back("Both Factors are Random Effects"); values.push_back("MIXED"); descriptions.push_back("Row Factor Fixed, Column Factor Random"); paramsOut.clear(); paramsOut.addListOfItems("ANOVA Type", values, descriptions); paramsOut.addFile("Fiducial Coordinate File Name", FileFilters::getCoordinateFiducialFileFilter()); paramsOut.addFile("Open Topology File Name", FileFilters::getTopologyOpenFileFilter()); paramsOut.addFile("Distoration Metric File Name", FileFilters::getMetricShapeFileFilter()); paramsOut.addInt("Distortion Column Number"); paramsOut.addString("Output File Names Prefix"); paramsOut.addInt("Iterations"); paramsOut.addFloat("Positive Threshold"); paramsOut.addFloat("P-Value"); paramsOut.addBoolean("Do F-Map Degrees of Freedom"); paramsOut.addBoolean("Do F-Map P-Value"); paramsOut.addInt("Number of Threads", 1); paramsOut.addInt("Number of ANOVA Rows", 1); paramsOut.addInt("Number of ANOVA Columns", 1); paramsOut.addMultipleFiles("Metric File Names", FileFilters::getMetricShapeFileFilter()); } /** * get full help information. */ QString CommandMetricStatisticsAnovaTwoWay::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " ... \n" + indent9 + " \n" + indent9 + " ... \n" + indent9 + " \n" + indent9 + " ... \n" + indent9 + " \n" + indent9 + " \n" + indent9 + "Perform a two-way analysis of variance on the input metric files. \n" + indent9 + " \n" + indent9 + "The number of rows and columns identify the number of factors \n" + indent9 + "for each of the two measurements. \n" + indent9 + " \n" + indent9 + " ANOVA-TYPE is one of \n" + indent9 + " FIXED - both factor are fixed effent \n" + indent9 + " RANDOM - both factors are random effects \n" + indent9 + " MIXED - the row factor is fixed, the column factor is random \n" + indent9 + " \n" + indent9 + "The distortion column number starts at 1. \n" + indent9 + " \n" + indent9 + "Number of threads is the number of concurrent processes run \n" + indent9 + "during the cluster search of the shuffled metric file. \n" + indent9 + "Use \"1\" if you are running on a single processor system. \n" + indent9 + "Users on systems with multiple processors or multi-core systems \n" + indent9 + "should set the number of threads to the number of processors \n" + indent9 + "and/or cores to reduce execution time. \n" + indent9 + "\n" + indent9 + " \n" + indent9 + "DANGER: THIS HAS NOT BEEN TESTED!!!!!!!!!!!!!!!!!!! \n" + indent9 + "DANGER: THIS HAS NOT BEEN TESTED!!!!!!!!!!!!!!!!!!! \n" + indent9 + "DANGER: THIS HAS NOT BEEN TESTED!!!!!!!!!!!!!!!!!!! \n" + indent9 + "DANGER: THIS HAS NOT BEEN TESTED!!!!!!!!!!!!!!!!!!! \n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandMetricStatisticsAnovaTwoWay::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString anovaTypeString = parameters->getNextParameterAsString("ANOVA Type"); const QString fiducialCoordFileName = parameters->getNextParameterAsString("Fiducial Coordinate File Name"); const QString openTopoFileName = parameters->getNextParameterAsString("Open Topology File Name"); const QString distortionMetricShapeFileName = parameters->getNextParameterAsString("Distortion Metric/Shape File Name"); int distortionColumnNumber = parameters->getNextParameterAsInt("Distortion Column Number"); const QString outputFileNamePrefix = parameters->getNextParameterAsString("Output File Name Prefix"); const int iterations = parameters->getNextParameterAsInt("Iterations"); const float positiveThreshold = parameters->getNextParameterAsFloat("Positive Threshold"); const float pValue = parameters->getNextParameterAsFloat("P-Value"); const bool doFMapDOF = parameters->getNextParameterAsBoolean("Do F-Map Degrees of Freedom"); const bool doFMapPValue = parameters->getNextParameterAsBoolean("Do F-Map P-Value"); const int numberOfThreads = parameters->getNextParameterAsInt("Number of Threads"); const int numberOfRowFactors = parameters->getNextParameterAsInt("Number of Row Factors"); const int numberOfColumnFactors = parameters->getNextParameterAsInt("Number of Column Factors"); std::vector metricFileNames; while (parameters->getParametersAvailable()) { metricFileNames.push_back( parameters->getNextParameterAsString("Metric File Names")); } BrainModelSurfaceMetricAnovaTwoWay::ANOVA_MODEL_TYPE anovaType; if (anovaTypeString == "FIXED") { anovaType = BrainModelSurfaceMetricAnovaTwoWay::ANOVA_MODEL_TYPE_FIXED_EFFECT; } else if (anovaTypeString == "RANDOM") { anovaType = BrainModelSurfaceMetricAnovaTwoWay::ANOVA_MODEL_TYPE_RANDOM_EFFECT; } else if (anovaTypeString == "MIXED") { anovaType = BrainModelSurfaceMetricAnovaTwoWay::ANOVA_MODEL_TYPE_ROWS_FIXED_EFFECT_COLUMN_RANDOM_EFFECT; } else { throw CommandException("Invalid ANOVA model type: " + anovaTypeString); } if (distortionColumnNumber <= 0) { throw CommandException("Distortion column number must be >= 1."); } distortionColumnNumber--; // algorithm starts at zero if (metricFileNames.empty()) { throw CommandException("No Metric/Shape files provided."); } const int totalNumFiles = numberOfRowFactors * numberOfColumnFactors; if (static_cast(metricFileNames.size()) != totalNumFiles) { throw CommandException("Number of metric files should be rows * columns"); } const QString ext = metricFileNames[0].endsWith(SpecFile::getMetricFileExtension()) ? SpecFile::getMetricFileExtension() : SpecFile::getSurfaceShapeFileExtension(); const QString outputFMapFileName(outputFileNamePrefix + "_FMap" + ext); const QString outputShuffledFMapFileName(outputFileNamePrefix + "_ShuffledFMap" + ext); const QString outputPaintFileName(outputFileNamePrefix + "_FMapClusters" + SpecFile::getPaintFileExtension()); const QString outputMetricFileName(outputFileNamePrefix + "_FMapClusters" + SpecFile::getMetricFileExtension()); const QString outputReportFileName(outputFileNamePrefix + "_FMap_Significant_Clusters" + SpecFile::getTextFileExtension()); BrainSet bs; BrainModelSurfaceMetricAnovaTwoWay anova(&bs, anovaType, numberOfRowFactors, numberOfColumnFactors, fiducialCoordFileName, openTopoFileName, distortionMetricShapeFileName, outputFMapFileName, outputShuffledFMapFileName, outputPaintFileName, outputMetricFileName, outputReportFileName, distortionColumnNumber, iterations, positiveThreshold, pValue, doFMapDOF, doFMapPValue, numberOfThreads); for (int i = 0; i < numberOfRowFactors; i++) { for (int j = 0; j < numberOfColumnFactors; j++) { const int indx = i * numberOfColumnFactors + j; anova.setMetricShapeFileName(i, j, metricFileNames[indx]); } } anova.execute(); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricStatisticsAnovaOneWay.h0000664000175000017500000000353311572067322030702 0ustar michaelmichael #ifndef __COMMAND_METRIC_STATISTICS_ANOVA_ONE_WAY_H__ #define __COMMAND_METRIC_STATISTICS_ANOVA_ONE_WAY_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for one-way ANOVA class CommandMetricStatisticsAnovaOneWay : public CommandBase { public: // constructor CommandMetricStatisticsAnovaOneWay(); // destructor ~CommandMetricStatisticsAnovaOneWay(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_METRIC_STATISTICS_ANOVA_ONE_WAY_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricStatisticsAnovaOneWay.cxx0000664000175000017500000001633511572067322031261 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurfaceMetricAnovaOneWay.h" #include "BrainSet.h" #include "CommandMetricStatisticsAnovaOneWay.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandMetricStatisticsAnovaOneWay::CommandMetricStatisticsAnovaOneWay() : CommandBase("-metric-statistics-anova-one-way", "METRIC STATISTICS ONE-WAY ANOVA") { } /** * destructor. */ CommandMetricStatisticsAnovaOneWay::~CommandMetricStatisticsAnovaOneWay() { } /** * get the script builder parameters. */ void CommandMetricStatisticsAnovaOneWay::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Fiducial Coordinate File Name", FileFilters::getCoordinateFiducialFileFilter()); paramsOut.addFile("Open Topology File Name", FileFilters::getTopologyOpenFileFilter()); paramsOut.addFile("Distoration Metric File Name", FileFilters::getMetricShapeFileFilter()); paramsOut.addInt("Distortion Column Number"); paramsOut.addString("Output File Names Prefix"); paramsOut.addInt("Iterations"); paramsOut.addFloat("Positive Threshold"); paramsOut.addFloat("P-Value"); paramsOut.addBoolean("Do F-Map Degrees of Freedom"); paramsOut.addBoolean("Do F-Map P-Value"); paramsOut.addInt("Number of Threads", 1); paramsOut.addMultipleFiles("Metric File Names", FileFilters::getMetricShapeFileFilter()); } /** * get full help information. */ QString CommandMetricStatisticsAnovaOneWay::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + "Perform a one-way analysis of variance on the input metric files. \n" + indent9 + "There must be at least two \"metric-file-names\" and each of the \n" + indent9 + "metric files contains all of the subjects for one factor level. \n" + indent9 + " \n" + indent9 + "The distortion column number starts at 1. \n" + indent9 + " \n" + indent9 + "Number of threads is the number of concurrent processes run \n" + indent9 + "during the cluster search of the shuffled metric file. \n" + indent9 + "Use \"1\" if you are running on a single processor system. \n" + indent9 + "Users on systems with multiple processors or multi-core systems \n" + indent9 + "should set the number of threads to the number of processors \n" + indent9 + "and/or cores to reduce execution time. \n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandMetricStatisticsAnovaOneWay::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString fiducialCoordFileName = parameters->getNextParameterAsString("Fiducial Coordinate File Name"); const QString openTopoFileName = parameters->getNextParameterAsString("Open Topology File Name"); const QString distortionMetricShapeFileName = parameters->getNextParameterAsString("Distortion Metric/Shape File Name"); int distortionColumnNumber = parameters->getNextParameterAsInt("Distortion Column Number"); const QString outputFileNamePrefix = parameters->getNextParameterAsString("Output File Name Prefix"); const int iterations = parameters->getNextParameterAsInt("Iterations"); const float positiveThreshold = parameters->getNextParameterAsFloat("Positive Threshold"); const float pValue = parameters->getNextParameterAsFloat("P-Value"); const bool doFMapDOF = parameters->getNextParameterAsBoolean("Do F-Map Degrees of Freedom"); const bool doFMapPValue = parameters->getNextParameterAsBoolean("Do F-Map P-Value"); const int numberOfThreads = parameters->getNextParameterAsInt("Number of Threads"); std::vector metricFileNames; while (parameters->getParametersAvailable()) { metricFileNames.push_back( parameters->getNextParameterAsString("Metric File Names")); } if (distortionColumnNumber <= 0) { throw CommandException("Distortion column number must be >= 1."); } distortionColumnNumber--; // algorithm starts at zero if (metricFileNames.empty()) { throw CommandException("No Metric/Shape files provided."); } const QString ext = metricFileNames[0].endsWith(SpecFile::getMetricFileExtension()) ? SpecFile::getMetricFileExtension() : SpecFile::getSurfaceShapeFileExtension(); const QString outputFMapFileName(outputFileNamePrefix + "_FMap" + ext); const QString outputShuffledFMapFileName(outputFileNamePrefix + "_ShuffledFMap" + ext); const QString outputPaintFileName(outputFileNamePrefix + "_FMapClusters" + SpecFile::getPaintFileExtension()); const QString outputMetricFileName(outputFileNamePrefix + "_FMapClusters" + SpecFile::getMetricFileExtension()); const QString outputReportFileName(outputFileNamePrefix + "_FMap_Significant_Clusters" + SpecFile::getTextFileExtension()); BrainSet bs; BrainModelSurfaceMetricAnovaOneWay anova(&bs, metricFileNames, fiducialCoordFileName, openTopoFileName, distortionMetricShapeFileName, outputFMapFileName, outputShuffledFMapFileName, outputPaintFileName, outputMetricFileName, outputReportFileName, distortionColumnNumber, iterations, positiveThreshold, pValue, doFMapDOF, doFMapPValue, numberOfThreads); anova.execute(); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricSmoothing.h0000664000175000017500000000337411572067322026412 0ustar michaelmichael #ifndef __COMMAND_METRIC_SMOOTHING_H__ #define __COMMAND_METRIC_SMOOTHING_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandMetricSmoothing : public CommandBase { public: // constructor CommandMetricSmoothing(); // destructor ~CommandMetricSmoothing(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_METRIC_SMOOTHING_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricSmoothing.cxx0000664000175000017500000003071511572067322026764 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurfaceMetricSmoothing.h" #include "BrainModelSurfaceMetricSmoothingAll.h" #include "BrainSet.h" #include "CommandMetricSmoothing.h" #include "FileFilters.h" #include "MetricFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandMetricSmoothing::CommandMetricSmoothing() : CommandBase("-metric-smoothing", "METRIC SMOOTHING") { } /** * destructor. */ CommandMetricSmoothing::~CommandMetricSmoothing() { } /** * get the script builder parameters. */ void CommandMetricSmoothing::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { std::vector values, descriptions; values.push_back("AN"); descriptions.push_back("Average Neighbors"); values.push_back("DILATE"); descriptions.push_back("Dilation"); values.push_back("FWHM"); descriptions.push_back("Full Width Half Maximum"); values.push_back("GAUSS"); descriptions.push_back("Gaussian"); values.push_back("GEOGAUSS"); descriptions.push_back("Geodesic Gaussian"); values.push_back("WAN"); descriptions.push_back("Weighted Average Neighbors"); paramsOut.clear(); paramsOut.clear(); paramsOut.addFile("Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Input Metric File Name", FileFilters::getMetricFileFilter()); paramsOut.addFile("Output Metric File Name", FileFilters::getMetricFileFilter()); paramsOut.addListOfItems("Smoothing Algorithm", values, descriptions); paramsOut.addInt("Smoothing Number of Iterations", 50, 1, 100000); paramsOut.addFloat("Smoothing Strength", 1.0, 0.0, 1.0); paramsOut.addVariableListOfParameters("Options"); //TODO: add geodesic Gaussian to parameters...john? } /** * get full help information. */ QString CommandMetricSmoothing::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + " \n" + indent9 + "[-geo-gauss sigma] \n" + indent9 + " \n" + indent9 + "[-fwhm desired-full-width-half-maximum] \n" + indent9 + " \n" + indent9 + "[-gauss spherical-coordinate-file-name\n" + indent9 + " sigma-norm\n" + indent9 + " sigma-tang\n" + indent9 + " norm below cutoff (mm)\n" + indent9 + " norm above cutoff (mm)\n" + indent9 + " tang-cutoff (mm)]\n" + indent9 + "\n" + indent9 + "[-parallel]\n" + indent9 + "\n" + indent9 + "Smooth metric data.\n" + indent9 + "\n" + indent9 + "\"smoothing-algorithm\" is one of:\n" + indent9 + " AN Average Neighbors\n" + indent9 + " DILATE Dilation\n" + indent9 + " FWHM Full-Width Half-Maximum\n" + indent9 + " GAUSS Gaussian, requires -gauss\n" + indent9 + " GEOGAUSS Geodesic Gaussian, uses -geo-gauss, default 2.0\n" + indent9 + " WAN Weighted Average Neighbors\n" + indent9 + "\n" + indent9 + " NOTE: Geodesic Gaussian IGNORES the strength parameter,\n" + indent9 + " amount of smoothing is controlled solely by sigma and\n" + indent9 + " iterations. The intent is to do one iteration of\n" + indent9 + " smoothing, with the sigma specifying how much smoother\n" + indent9 + " the metric is desired to be.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandMetricSmoothing::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString coordinateFileName = parameters->getNextParameterAsString("Coordinate File Name"); const QString topologyFileName = parameters->getNextParameterAsString("Topology File Name"); const QString inputMetricFileName = parameters->getNextParameterAsString("Input Metric File Name"); const QString outputMetricFileName = parameters->getNextParameterAsString("Output Metric File Name"); const QString algorithmName = parameters->getNextParameterAsString("Smoothing Algorithm"); const int smoothingNumberOfIterations = parameters->getNextParameterAsInt("Smoothing Number of Iterations"); const float smoothingStrength = parameters->getNextParameterAsFloat("Smoothing Strength"); float desiredFullWidthHalfMaximum = 0.0; QString gaussianSphericalSurfaceName; float gaussSigmaNorm = 2.0; float gaussSigmaTang = 2.0; float gaussNormBelow = 2.0; float gaussNormAbove = 2.0; float gaussTangCutoff = 3.0; float geoGaussSigma = 2.0; bool parallelFlag = false; while (parameters->getParametersAvailable()) { const QString paramValue = parameters->getNextParameterAsString("Smoothing Parameter"); if (paramValue == "-fwhm") { desiredFullWidthHalfMaximum = parameters->getNextParameterAsFloat("Desired Full Width Half Maximum"); } else if (paramValue == "-gauss") { gaussianSphericalSurfaceName = parameters->getNextParameterAsString("Guassian Spherical Surface"); gaussSigmaNorm = parameters->getNextParameterAsFloat("Gaussian Sigma Norm"); gaussSigmaTang = parameters->getNextParameterAsFloat("Gaussian Sigma Tangent"); gaussNormBelow = parameters->getNextParameterAsFloat("Gaussina Norm Below Cutoff"); gaussNormAbove = parameters->getNextParameterAsFloat("Gaussian Norm Above Cutoff"); gaussTangCutoff = parameters->getNextParameterAsFloat("Gaussian Tangent Cutoff"); } else if (paramValue == "-geo-gauss") { geoGaussSigma = parameters->getNextParameterAsFloat("Geodesic Gaussian Sigma"); } else if (paramValue == "-parallel") { parallelFlag = true; } else { throw CommandException("Unrecognized parameter: " + paramValue); } } // // Get algorithm // BrainModelSurfaceMetricSmoothingAll::SMOOTH_ALGORITHM smoothingAllAlgorithm; BrainModelSurfaceMetricSmoothing::SMOOTH_ALGORITHM smoothingAlgorithm; if (algorithmName == "AN") { smoothingAllAlgorithm = BrainModelSurfaceMetricSmoothingAll::SMOOTH_ALGORITHM_AVERAGE_NEIGHBORS; smoothingAlgorithm = BrainModelSurfaceMetricSmoothing::SMOOTH_ALGORITHM_AVERAGE_NEIGHBORS; } else if (algorithmName == "DILATE") { smoothingAllAlgorithm = BrainModelSurfaceMetricSmoothingAll::SMOOTH_ALGORITHM_DILATE; smoothingAlgorithm = BrainModelSurfaceMetricSmoothing::SMOOTH_ALGORITHM_DILATE; } else if (algorithmName == "FWHM") { smoothingAllAlgorithm = BrainModelSurfaceMetricSmoothingAll::SMOOTH_ALGORITHM_FULL_WIDTH_HALF_MAXIMUM; smoothingAlgorithm = BrainModelSurfaceMetricSmoothing::SMOOTH_ALGORITHM_FULL_WIDTH_HALF_MAXIMUM; } else if (algorithmName == "GAUSS") { smoothingAllAlgorithm = BrainModelSurfaceMetricSmoothingAll::SMOOTH_ALGORITHM_SURFACE_NORMAL_GAUSSIAN; smoothingAlgorithm = BrainModelSurfaceMetricSmoothing::SMOOTH_ALGORITHM_SURFACE_NORMAL_GAUSSIAN; } else if (algorithmName == "GEOGAUSS") { smoothingAllAlgorithm = BrainModelSurfaceMetricSmoothingAll::SMOOTH_ALGORITHM_GEODESIC_GAUSSIAN; smoothingAlgorithm = BrainModelSurfaceMetricSmoothing::SMOOTH_ALGORITHM_GEODESIC_GAUSSIAN; } else if (algorithmName == "WAN") { smoothingAllAlgorithm = BrainModelSurfaceMetricSmoothingAll::SMOOTH_ALGORITHM_WEIGHTED_AVERAGE_NEIGHBORS; smoothingAlgorithm = BrainModelSurfaceMetricSmoothing::SMOOTH_ALGORITHM_WEIGHTED_AVERAGE_NEIGHBORS; } else { throw CommandException("Invalid algorithm: \"" + algorithmName + "\""); } // // Create a brain set // BrainSet brainSet(topologyFileName, coordinateFileName, gaussianSphericalSurfaceName, true); BrainModelSurface* surface = brainSet.getBrainModelSurface(0); if (surface == NULL) { throw CommandException("unable to find surface."); } const TopologyFile* tf = surface->getTopologyFile(); if (tf == NULL) { throw CommandException("unable to find topology."); } BrainModelSurface* gaussianSphericalSurface = NULL; if (gaussianSphericalSurfaceName.isEmpty() == false) { gaussianSphericalSurface = brainSet.getBrainModelSurface(1); if (gaussianSphericalSurface == NULL) { throw CommandException("unable to find spherical surface."); } } const int numNodes = surface->getNumberOfNodes(); if (numNodes == 0) { throw CommandException("surface contains no nodes."); } // // Read input metric file // MetricFile metricFile; metricFile.readFile(inputMetricFileName); bool newSmoothFlag = true; if (newSmoothFlag) { // // Perform smoothing // BrainModelSurfaceMetricSmoothingAll smoothing(&brainSet, surface, gaussianSphericalSurface, &metricFile, smoothingAllAlgorithm, smoothingStrength, smoothingNumberOfIterations, desiredFullWidthHalfMaximum, gaussNormBelow, gaussNormAbove, gaussSigmaNorm, gaussSigmaTang, gaussTangCutoff, geoGaussSigma, parallelFlag); smoothing.execute(); } else { // // Perform smoothing // const int numberOfColumns = metricFile.getNumberOfColumns(); for (int i = 0; i < numberOfColumns; i++) { BrainModelSurfaceMetricSmoothing smoothing(&brainSet, surface, gaussianSphericalSurface, &metricFile, smoothingAlgorithm, i, i, metricFile.getColumnName(i), smoothingStrength, smoothingNumberOfIterations, desiredFullWidthHalfMaximum, gaussNormBelow, gaussNormAbove, gaussSigmaNorm, gaussSigmaTang, gaussTangCutoff, geoGaussSigma); smoothing.execute(); } } // // Write the metric file // metricFile.writeFile(outputMetricFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricSetColumnToScalar.h0000664000175000017500000000354011572067322030000 0ustar michaelmichael #ifndef __COMMAND_METRIC_SET_COLUMN_TO_SCALAR_H__ #define __COMMAND_METRIC_SET_COLUMN_TO_SCALAR_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for setting an entire column to a scalar value class CommandMetricSetColumnToScalar : public CommandBase { public: // constructor CommandMetricSetColumnToScalar(); // destructor ~CommandMetricSetColumnToScalar(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_METRIC_SET_COLUMN_TO_SCALAR_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricSetColumnToScalar.cxx0000664000175000017500000000741111572067322030354 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandMetricSetColumnToScalar.h" #include "FileFilters.h" #include "MetricFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandMetricSetColumnToScalar::CommandMetricSetColumnToScalar() : CommandBase("-metric-set-column-to-scalar", "METRIC SET COLUMN TO SCALAR") { } /** * destructor. */ CommandMetricSetColumnToScalar::~CommandMetricSetColumnToScalar() { } /** * get the script builder parameters. */ void CommandMetricSetColumnToScalar::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Metric File Name", FileFilters::getMetricFileFilter()); paramsOut.addVariableListOfParameters("Column Names/Scalars"); } /** * get full help information. */ QString CommandMetricSetColumnToScalar::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "[column scalar-value]\n" + indent9 + "\n" + indent9 + "Set columns to a scalar value in a metric file.\n" + indent9 + "\n" + indent9 + "\"column\" is either the number of the column, which\n" + indent9 + "starts at one, or the name of the column. If a\n" + indent9 + "a name contains spaces, it must be enclosed in double\n" + indent9 + "quotes. Name has priority over number. If a name is\n" + indent9 + "used for a column and the column does not exist it will\n" + indent9 + "be created.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandMetricSetColumnToScalar::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get output file // const QString metricFileName = parameters->getNextParameterAsString("Metric File Name"); MetricFile metricFile; metricFile.readFile(metricFileName); // // Process column names // while (parameters->getParametersAvailable()) { // // Get column identifier and new name // const QString columnID = parameters->getNextParameterAsString("Column Identifier"); const float scalarValue = parameters->getNextParameterAsFloat("Scalar Value"); // // Set the column // const int metricColumnNumber = metricFile.getColumnFromNameOrNumber(columnID, true); metricFile.setColumnAllNodesToScalar(metricColumnNumber, scalarValue); } // // Write metric file // metricFile.writeFile(metricFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricSetColumnName.h0000664000175000017500000000347511572067322027157 0ustar michaelmichael #ifndef __COMMAND_METRIC_SET_COLUMN_NAME_H__ #define __COMMAND_METRIC_SET_COLUMN_NAME_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for setting name of metric file column class CommandMetricSetColumnName : public CommandBase { public: // constructor CommandMetricSetColumnName(); // destructor ~CommandMetricSetColumnName(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_METRIC_SET_COLUMN_NAME_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricSetColumnName.cxx0000664000175000017500000000707411572067322027531 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandMetricSetColumnName.h" #include "FileFilters.h" #include "MetricFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandMetricSetColumnName::CommandMetricSetColumnName() : CommandBase("-metric-set-column-name", "METRIC SET COLUMN NAME") { } /** * destructor. */ CommandMetricSetColumnName::~CommandMetricSetColumnName() { } /** * get the script builder parameters. */ void CommandMetricSetColumnName::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Metric File Name", FileFilters::getMetricFileFilter()); paramsOut.addVariableListOfParameters("Column Names"); } /** * get full help information. */ QString CommandMetricSetColumnName::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "[column new-name]\n" + indent9 + "\n" + indent9 + "Rename columns in a metric file.\n" + indent9 + "\n" + indent9 + "\"column\" is either the number of the column, which\n" + indent9 + "starts at one, or the name of the column. If a\n" + indent9 + "a name contains spaces, it must be enclosed in double\n" + indent9 + "quotes. Name has priority over number.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandMetricSetColumnName::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get output file // const QString metricFileName = parameters->getNextParameterAsString("Metric File Name"); MetricFile metricFile; metricFile.readFile(metricFileName); // // Process column names // while (parameters->getParametersAvailable()) { // // Get column identifier and new name // const QString columnID = parameters->getNextParameterAsString("Column Identifier"); const QString newName = parameters->getNextParameterAsString("New Column Name"); // // Set the column name // const int metricColumnNumber = metricFile.getColumnFromNameOrNumber(columnID, false); metricFile.setColumnName(metricColumnNumber, newName); } // // Write metric file // metricFile.writeFile(metricFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricROISmoothing.h0000664000175000017500000000342111572067322026755 0ustar michaelmichael #ifndef __COMMAND_METRIC_ROI_SMOOTHING_H__ #define __COMMAND_METRIC_ROI_SMOOTHING_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandMetricROISmoothing : public CommandBase { public: // constructor CommandMetricROISmoothing(); // destructor ~CommandMetricROISmoothing(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_METRIC_ROI_SMOOTHING_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricROISmoothing.cxx0000664000175000017500000002627511572067322027344 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurfaceROIMetricSmoothing.h" #include "BrainSet.h" #include "CommandMetricROISmoothing.h" #include "FileFilters.h" #include "MetricFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandMetricROISmoothing::CommandMetricROISmoothing() : CommandBase("-metric-roi-smoothing", "METRIC ROI SMOOTHING") { } /** * destructor. */ CommandMetricROISmoothing::~CommandMetricROISmoothing() { } /** * get the script builder parameters. */ void CommandMetricROISmoothing::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { std::vector values, descriptions; values.push_back("GEOGAUSS"); descriptions.push_back("Geodesic Gaussian"); paramsOut.clear(); paramsOut.clear(); paramsOut.addFile("Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Input ROI File Name", FileFilters::getMetricFileFilter()); paramsOut.addFile("Input Metric File Name", FileFilters::getMetricFileFilter()); paramsOut.addFile("Output Metric File Name", FileFilters::getMetricFileFilter()); paramsOut.addInt("Smoothing Number of Iterations", 50, 1, 100000); paramsOut.addFloat("Smoothing Strength", 1.0f); paramsOut.addVariableListOfParameters("Options"); //TODO: add geodesic Gaussian to parameters...john? } /** * get full help information. */ QString CommandMetricROISmoothing::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + " \n" + indent9 + "[-sigma]\n" + indent9 + " \n" + indent9 + "[-smooth-col]\n" + indent9 + " \n" + indent9 + "Smooth metric data.\n" + indent9 + "\n" + indent9 + "Currently only Geodesic Gaussian is supported for ROI smoothing.\n" + indent9 + "\n" + indent9 + "\n" + indent9 + " NOTE: The amount of smoothing is controlled solely by sigma\n" + indent9 + " (default 2.0), and iterations. The intent is to do one\n" + indent9 + " iteration of smoothing, with the sigma specifying how\n" + indent9 + " much smoother the metric is desired to be.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandMetricROISmoothing::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString coordinateFileName = parameters->getNextParameterAsString("Coordinate File Name"); const QString topologyFileName = parameters->getNextParameterAsString("Topology File Name"); const QString roiInName = parameters->getNextParameterAsString("Input ROI File Name"); const QString inputMetricFileName = parameters->getNextParameterAsString("Input Metric File Name"); const QString outputMetricFileName = parameters->getNextParameterAsString("Output Metric File Name"); const int smoothingNumberOfIterations = parameters->getNextParameterAsInt("Smoothing Number of Iterations"); const float smoothingStrength = parameters->getNextParameterAsFloat("Smoothing Strength"); float geoGaussSigma = 2.0; bool parallelFlag = true; QString smoothColumnName; int smoothColumnNumber = 0; while (parameters->getParametersAvailable()) { const QString paramValue = parameters->getNextParameterAsString("Smoothing Parameter"); if (paramValue == "-sigma") { geoGaussSigma = parameters->getNextParameterAsFloat("Geodesic Gaussian Sigma"); } else if (paramValue == "-no-parallel") { parallelFlag = true; } else if (paramValue == "-smooth-col") { smoothColumnName = parameters->getNextParameterAsString("Column To Smooth"); } else { throw CommandException("Unrecognized parameter: " + paramValue); } } // // Create a brain set // BrainSet brainSet(topologyFileName, coordinateFileName, "", true); BrainModelSurface* surface = brainSet.getBrainModelSurface(0); if (surface == NULL) { throw CommandException("unable to find surface."); } const TopologyFile* tf = surface->getTopologyFile(); if (tf == NULL) { throw CommandException("unable to find topology."); } const int numNodes = surface->getNumberOfNodes(); if (numNodes == 0) { throw CommandException("surface contains no nodes."); } // // Read input metric file // MetricFile metricFile; metricFile.readFile(inputMetricFileName); // // If SmoothColumnName exists, then convert it to // if(!smoothColumnName.isEmpty()) { //cout << "single column name is" << (char *)(smoothColumnName.toAscii().data()) << endl; smoothColumnNumber = metricFile.getColumnFromNameOrNumber(smoothColumnName, false); } // // Read input roi file // MetricFile roiIn; roiIn.readFile(roiInName); // // Perform smoothing // float gaussSigmaNorm = 2.0; float gaussSigmaTang = 2.0; float gaussNormBelow = 2.0; float gaussNormAbove = 2.0; float gaussTangCutoff = 3.0; if(!smoothColumnName.isEmpty()) { //std::cout << "single column smoothing selected" << std::endl; MetricFile metricOut; int metricOutIndex = 0; metricOut.setNumberOfNodesAndColumns(metricFile.getNumberOfNodes(), 1); float *valuesToSmooth; const int numberOfNodes = metricFile.getNumberOfNodes(); valuesToSmooth = new float[numberOfNodes]; metricFile.getColumnForAllNodes(smoothColumnNumber,valuesToSmooth); metricOut.setColumnForAllNodes(metricOutIndex,valuesToSmooth); //std::cout << "before getting column name" << std::endl; metricOut.setColumnName(metricOutIndex, metricFile.getColumnName(smoothColumnNumber)); metricOut.setFileName(outputMetricFileName); BrainModelSurfaceROIMetricSmoothing smoothing(&brainSet, surface, &metricOut, &roiIn, metricOutIndex, metricOutIndex, metricOut.getColumnName(metricOutIndex), smoothingStrength, smoothingNumberOfIterations, gaussNormBelow, gaussNormAbove, gaussSigmaNorm, gaussSigmaTang, gaussTangCutoff, geoGaussSigma); smoothing.execute(); metricOut.writeFile(outputMetricFileName); } else if(parallelFlag) { // // Perform parallel smoothing // const int numberOfColumns = metricFile.getNumberOfColumns(); cout << "smoothing " << numberOfColumns << " columns." << endl; BrainModelSurfaceROIMetricSmoothing smoothing(&brainSet, surface, &metricFile, &roiIn, smoothingStrength, smoothingNumberOfIterations, gaussNormBelow, gaussNormAbove, gaussSigmaNorm, gaussSigmaTang, gaussTangCutoff, geoGaussSigma, true ); smoothing.execute(); // // Write the metric file // metricFile.writeFile(outputMetricFileName); } else { // // Perform smoothing // const int numberOfColumns = metricFile.getNumberOfColumns(); cout << "smoothing " << numberOfColumns << " columns." << endl; BrainModelSurfaceROIMetricSmoothing smoothing(&brainSet, surface, &metricFile, &roiIn, smoothingStrength, smoothingNumberOfIterations, gaussNormBelow, gaussNormAbove, gaussSigmaNorm, gaussSigmaTang, gaussTangCutoff, geoGaussSigma, false ); smoothing.execute(); // // Write the metric file // metricFile.writeFile(outputMetricFileName); } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricROIMask.h0000664000175000017500000000360111572067322025701 0ustar michaelmichael #ifndef __COMMAND_METRIC_ROI_MASK_H__ #define __COMMAND_METRIC_ROI_MASK_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" #include "MetricFile.h" /// class for class CommandMetricROIMask : public CommandBase { public: // constructor CommandMetricROIMask(); // destructor ~CommandMetricROIMask(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); void MaskSingleColumn(MetricFile * metricIn, int metricInCol,float * roiValues, MetricFile * metricOut); }; #endif // __COMMAND_METRIC_ROI_MASK_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricROIMask.cxx0000664000175000017500000001303711572067322026260 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "CommandMetricROIMask.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "StringUtilities.h" #include "FileUtilities.h" #include "MetricFile.h" /** * constructor. */ CommandMetricROIMask::CommandMetricROIMask() : CommandBase("-metric-roi-mask", "METRIC ROI MASK") { } /** * destructor. */ CommandMetricROIMask::~CommandMetricROIMask() { } /** * get the script builder parameters. */ void CommandMetricROIMask::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Metric File", FileFilters::getMetricFileFilter()); paramsOut.addString("Input Metric Column"); paramsOut.addFile("Input Surface ROI File", FileFilters::getMetricFileFilter()); paramsOut.addFile("Output Metric File", FileFilters::getMetricFileFilter()); } /** * get full help information. */ QString CommandMetricROIMask::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Applies a mask to the input metric file, and zeros out any values\n" + indent9 + "where the mask is 0.0f.\n" + indent9 + "\n" + indent9 + " metric the metric file\n" + indent9 + "\n" + indent9 + " metric-col which column to apply the mask to\n" + indent9 + "\n" + indent9 + " surface-roi the surface roi file\n" + indent9 + "\n" + indent9 + " output-metric output metric file for mask\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandMetricROIMask::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString metricInName = parameters->getNextParameterAsString("Input Metric File"); const QString metricInColName = parameters->getNextParameterAsString("Input Metric Column"); const QString roiInName = parameters->getNextParameterAsString("Input ROI File"); const QString metricOutName = parameters->getNextParameterAsString("Output Metric File"); MetricFile metricIn; metricIn.readFile(metricInName); if ((metricIn.getNumberOfColumns() <= 0) || (metricIn.getNumberOfNodes() <= 0)) { throw CommandException("Metric file contains no data."); } MetricFile roiIn; roiIn.readFile(roiInName); if ((roiIn.getNumberOfColumns() <= 0) || (roiIn.getNumberOfNodes() <= 0)) { throw CommandException("Roi file contains no data."); } if(roiIn.getNumberOfNodes() != metricIn.getNumberOfNodes()) { throw CommandException("Input Metric File and Input ROI File contain different numbers of nodes."); } int metricInCol = metricIn.getColumnFromNameOrNumber(metricInColName, false); MetricFile metricOut; if (metricOutName != QString("NULL")) { metricOut.setFileName(metricOutName); metricOut.setNumberOfNodesAndColumns(metricIn.getNumberOfNodes(),1); metricOut.setColumnName(0,"Masked Column"); } float *roiValues = NULL; int numberOfNodes = 0; numberOfNodes = roiIn.getNumberOfNodes(); // // Get array of ROI values for all nodes // roiValues = new float[numberOfNodes]; roiIn.getColumnForAllNodes(0,roiValues); MaskSingleColumn(&metricIn,metricInCol, roiValues, &metricOut); if(metricOutName != QString("NULL")) metricOut.writeFile(metricOutName); } void CommandMetricROIMask::MaskSingleColumn(MetricFile * metricIn, int metricInCol, float *roiValues, MetricFile * metricOut) { float *metricInValues = NULL; float *metricOutValues = NULL; int numberOfNodes = 0; numberOfNodes = metricIn->getNumberOfNodes(); metricInValues = new float[numberOfNodes]; metricOutValues = new float[numberOfNodes]; metricIn->getColumnForAllNodes(metricInCol, metricInValues); for(int i = 0;isetColumnForAllNodes(0,metricOutValues); delete metricInValues; delete metricOutValues; return; } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricROIGradient.h0000664000175000017500000000341311572067322026544 0ustar michaelmichael #ifndef __COMMAND_METRIC_ROI_GRADIENT_H__ #define __COMMAND_METRIC_ROI_GRADIENT_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandMetricROIGradient : public CommandBase { public: // constructor CommandMetricROIGradient(); // destructor ~CommandMetricROIGradient(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_METRIC_ROI_GRADIENT_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricROIGradient.cxx0000664000175000017500000002346011572067322027123 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "CommandMetricROIGradient.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceROIMetricGradient.h" #include "BrainModelSurfaceROIMetricSmoothing.h" #include "BrainSet.h" #include "StringUtilities.h" #include "FileUtilities.h" #include "MetricFile.h" #include "VectorFile.h" #include "CoordinateFile.h" #include "TopologyFile.h" /** * constructor. */ CommandMetricROIGradient::CommandMetricROIGradient() : CommandBase("-metric-roi-gradient", "METRIC ROI GRADIENT") { } /** * destructor. */ CommandMetricROIGradient::~CommandMetricROIGradient() { } /** * get the script builder parameters. */ void CommandMetricROIGradient::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Coordinate File", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Input Topology File", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Input Metric File", FileFilters::getMetricFileFilter()); paramsOut.addFile("Input Surface ROI File", FileFilters::getMetricFileFilter()); // paramsOut.addFile("Output Vector File", FileFilters::getGiftiVectorFileFilter()); paramsOut.addFile("Output Metric File", FileFilters::getMetricFileFilter()); paramsOut.addBoolean("Average Normals", false); paramsOut.addFloat("Smoothing Kernel", -1.0, -1.0); paramsOut.addVariableListOfParameters("Options"); } /** * get full help information. */ QString CommandMetricROIGradient::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[metric-col]\n" + indent9 + "[out-metric-col-num]\n" + indent9 + "[parallel-flag]\n" //+ indent9 + "[output-vector]\n" + indent9 + "\n" + indent9 + "Generate the surface gradient of a metric file on a ROI. Uses a linear\n" + indent9 + "regression on a projection of the neighbor positions to a plane\n" + indent9 + "perpendicular to the surface normal, for each node.\n" + indent9 + "\n" + indent9 + "Multi-Column computation is the default, and is run in parallel. If\n" + indent9 + "the gradient of a single column is desired, then specify the input\n" + indent9 + "column name.\n" + indent9 + "\n" + indent9 + "For single column computations, the column specified by out-metric-col\n" + indent9 + "is replaced if it exists, otherwise output is appended as a new column.\n" + indent9 + "\n" + indent9 + " surface-coord the surface coord file\n" + indent9 + "\n" + indent9 + " surface-topo the surface topo file\n" + indent9 + "\n" + indent9 + " surface-roi the surface roi file\n" + indent9 + "\n" + indent9 + " metric the metric file\n" + indent9 + "\n" + indent9 + " output-metric output metric file for gradient magnitude\n" + indent9 + "\n" + indent9 + " average-normals uses an average of the normals of the node and all\n" + indent9 + " neighbors, use 'true' if your surface is not smooth.\n" + indent9 + "\n" + indent9 + " smooth-kernel applies smoothing before computing gradient. Uses\n" + indent9 + " geodesic gaussian smoothing with specified kernel.\n" + indent9 + " Give a negative number to skip smoothing. Kernel\n" + indent9 + " specifies the geodesic distance where weight is\n" + indent9 + " 0.607, center node has weight of 1.\n" + indent9 + "\n" + indent9 + "Optional parmeters:\n" + indent9 + " metric-col which column to take the gradient of, if none specified\n" + indent9 + " the command is run on all columns\n" + indent9 + "\n" + indent9 + " out-metric-col-num which column to put the gradient magnitude into, if not\n" + indent9 + " specified, then it is appended to the output metric file.\n" + indent9 + " This parameter is only used for single column computations.\n" + indent9 + "\n" + indent9 + " single-threaded For multi-column gradients, this option disable parallel\n" + indent9 + " processing. This is recommended for troubleshooting purposes\n" + indent9 + " only\n" //+ indent9 + " output-vector the output gradient vector file\n" //+ indent9 + "\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandMetricROIGradient::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString coord = parameters->getNextParameterAsString("Input Coordinate File"); const QString topo = parameters->getNextParameterAsString("Input Topology File"); const QString roi = parameters->getNextParameterAsString("Input ROI File"); const QString metric = parameters->getNextParameterAsString("Input Metric File"); const QString vector = "NULL"; //parameters->getNextParameterAsString("Output Vector File"); const QString mag = parameters->getNextParameterAsString("Output Metric File"); bool avgNormals = parameters->getNextParameterAsBoolean("Average Surface Normals"); float smoothing = parameters->getNextParameterAsFloat("Smoothing Kernel"); QString metricColName; int magCol = -1;//setting to -1 will append to the output metric file by default bool allColumnsFlag = true; bool parallelFlag = true; while (parameters->getParametersAvailable()) { const QString paramValue = parameters->getNextParameterAsString("ROI Gradient Parameter"); if (paramValue == "-metric-col") { metricColName = parameters->getNextParameterAsString("Input Metric Column"); allColumnsFlag = false; } else if (paramValue == "-single-threaded") { parallelFlag = false; } else if (paramValue == "-out-metric-col-num") { magCol = parameters->getNextParameterAsInt("Output Metric Column Number"); } else { throw CommandException("Unrecognized parameter: " + paramValue); } } BrainSet mybs(topo, coord); BrainModelSurface* mysurf = mybs.getBrainModelSurface(0); MetricFile mymetric; mymetric.readFile(metric); MetricFile myroi; myroi.readFile(roi); if(allColumnsFlag) { if (smoothing > 0.0f) { BrainModelSurfaceROIMetricSmoothing mysmooth(&mybs, mysurf, &mymetric, &myroi, 1.0f, 1, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, smoothing, parallelFlag); mysmooth.execute(); } BrainModelSurfaceROIMetricGradient myobject(&mybs, 0, &myroi, &mymetric, avgNormals,parallelFlag); myobject.execute(); if (mag != QString("NULL")) mymetric.writeFile(mag); } else { int metricCol = mymetric.getColumnFromNameOrNumber(metricColName, false); if (smoothing > 0.0f) { BrainModelSurfaceROIMetricSmoothing mysmooth(&mybs, mysurf, &mymetric, &myroi, metricCol, metricCol, metricColName, 1.0f, 1, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, smoothing); mysmooth.execute(); } MetricFile* mymag = NULL; if (mag != QString("NULL")) { mymag = new MetricFile(); mymag->setFileName(mag); try { mymag->readFile(mag); } catch (FileException e) {}//fail silently on nonexistant or no permissions, gets written later } VectorFile* myvec = NULL; if ((vector != QString("NULL"))) { myvec = new VectorFile(); myvec->setFileName(vector); } BrainModelSurfaceROIMetricGradient myobject(&mybs, 0, &myroi, &mymetric, metricCol, myvec, mymag, magCol - 1, avgNormals); myobject.execute(); if (myvec != NULL) myvec->writeFile(vector); if (mymag != NULL) mymag->writeFile(mag); } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricMultipleCorrelationCoefficientMap.h0000664000175000017500000000367611572067322033242 0ustar michaelmichael #ifndef __COMMAND_METRIC_MULTIPLE_CORRELATION_COEFFICIENT_MAP_H__ #define __COMMAND_METRIC_MULTIPLE_CORRELATION_COEFFICIENT_MAP_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for metric multiple correlation coefficients class CommandMetricMultipleCorrelationCoefficientMap : public CommandBase { public: // constructor CommandMetricMultipleCorrelationCoefficientMap(); // destructor ~CommandMetricMultipleCorrelationCoefficientMap(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_METRIC_MULTIPLE_CORRELATION_COEFFICIENT_MAP_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricMultipleCorrelationCoefficientMap.cxx0000664000175000017500000001055311572067322033605 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandMetricMultipleCorrelationCoefficientMap.h" #include "FileFilters.h" #include "MetricFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandMetricMultipleCorrelationCoefficientMap::CommandMetricMultipleCorrelationCoefficientMap() : CommandBase("-metric-multiple-correlation-coefficient-map", "METRIC MULTIPLE CORRELATION COEFFICIENT MAP") { } /** * destructor. */ CommandMetricMultipleCorrelationCoefficientMap::~CommandMetricMultipleCorrelationCoefficientMap() { } /** * get the script builder parameters. */ void CommandMetricMultipleCorrelationCoefficientMap::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Output Metric File Name", FileFilters::getMetricShapeFileFilter()); paramsOut.addFile("Dependent Metric File Name", FileFilters::getMetricShapeFileFilter()); paramsOut.addMultipleFiles("Independent Metric File Names", FileFilters::getMetricShapeFileFilter()); } /** * get full help information. */ QString CommandMetricMultipleCorrelationCoefficientMap::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "For each node, compute a correlation coefficient from the node's values\n" + indent9 + "in the input metric files. The two input files must have the same\n" + indent9 + "number of columns and column 'j' in all files should contain data\n" + indent9 + "for the same subject.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandMetricMultipleCorrelationCoefficientMap::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString outputMetricFileName = parameters->getNextParameterAsString("Output Metric File Name"); const QString dependentMetricFileName = parameters->getNextParameterAsString("Dependent Metric File Name"); std::vector independentMetricFileNames; while (parameters->getParametersAvailable()) { independentMetricFileNames.push_back( parameters->getNextParameterAsString("Independent Metric File Name")); } MetricFile dependentMetricFile; dependentMetricFile.readFile(dependentMetricFileName); std::vector independentMetricFiles; for (unsigned int i = 0; i < independentMetricFileNames.size(); i++) { MetricFile* mf = new MetricFile; mf->readFile(independentMetricFileNames[i]); independentMetricFiles.push_back(mf); } MetricFile* outputMetricFile = MetricFile::computeMultipleCorrelationCoefficientMap(&dependentMetricFile, independentMetricFiles); outputMetricFile->writeFile(outputMetricFileName); delete outputMetricFile; outputMetricFile = NULL; for (unsigned int i = 0; i < independentMetricFileNames.size(); i++) { delete independentMetricFiles[i]; independentMetricFiles[i] = NULL; } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricMathPostfix.h0000664000175000017500000000671211572067322026710 0ustar michaelmichael #ifndef __COMMAND_METRIC_MATH_POSTFIX_H__ #define __COMMAND_METRIC_MATH_POSTFIX_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "CommandBase.h" /// class for metric postfix mathmatics class CommandMetricMathPostfix : public CommandBase { public: // constructor CommandMetricMathPostfix(const QString& operationSwitchIn = "-metric-math-postfix", const QString& shortDescriptionIn = "METRIC MATH POSTFIX"); // destructor ~CommandMetricMathPostfix(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); // convert the input string into a queue of tokens void convertInputToQueueOfTokens(const QString& inputString, std::queue& tokensOut) const throw (CommandException); // process the postfix expression void processPostFixExpression(const QString& inputMetricFileName, const QString& outputMetricFileName, const QString& outputMetricColumnNameOrNumber, std::queue& postFixExpression) throw (CommandException); // get an array with number of nodes elements float* getArray(); // release an array void releaseArray(float* f); // see if whitespace bool isWhiteSpace(const QString& s) const; /// storage for data arrays to avoid extra memory allocations/frees std::queue arrayStorage; /// number of nodes in metric file int numberOfNodes; /// name of metric column identifier QString metricColumnIdentifierName; /// character that identifies a metric column QString metricColumnIdentifierCharacter; /// name of metric file/column separator QString metricFileColumnSeparatorName; /// characters that separate metric file/column QString metricFileColumnSeparatorCharacter; // the whitespace characters QString whitespace; }; #endif // __COMMAND_METRIC_MATH_POSTFIX_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricMathPostfix.cxx0000664000175000017500000005541611572067322027270 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "CommandMetricMathPostfix.h" #include "FileFilters.h" #include "FileUtilities.h" #include "MathUtilities.h" #include "MetricFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandMetricMathPostfix::CommandMetricMathPostfix(const QString& operationSwitchIn, const QString& shortDescriptionIn) : CommandBase(operationSwitchIn, shortDescriptionIn) { whitespace = " \t\n\r"; metricColumnIdentifierName = "at-sign"; metricColumnIdentifierCharacter = "@"; metricFileColumnSeparatorName = "colon"; metricFileColumnSeparatorCharacter = ":"; } /** * destructor. */ CommandMetricMathPostfix::~CommandMetricMathPostfix() { } /** * get the script builder parameters. */ void CommandMetricMathPostfix::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Metric File Name", FileFilters::getMetricFileFilter()); paramsOut.addFile("Output Metric File Name", FileFilters::getMetricFileFilter()); paramsOut.addString("Output Metric Column Name/Number"); paramsOut.addVariableListOfParameters("Expression"); } /** * get full help information. */ QString CommandMetricMathPostfix::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Perform mathematical operations on a metric file. The \n" + indent9 + "mathematical expression must be in post-fix (reverse \n" + indent9 + "polish notation). See \n" + indent9 + " http://en.wikipedia.org/wiki/Reverse_Polish_notation\n" + indent9 + "\n" + indent9 + "The postfix expression must be in double quotes. Otherwise,\n" + indent9 + "operators, such as \"*\" will match all files in the \n" + indent9 + "current directory.\n" + indent9 + "\n" + indent9 + "A metric column is identified by a sequence of characters\n" + indent9 + "the are immediately proceeded and immediately followed by\n" + indent9 + "an " + metricColumnIdentifierName + " (" + metricColumnIdentifierCharacter + "). \n" + indent9 + "\n" + indent9 + "These characters are either the name of the metric column or\n" + indent9 + "the number of the metric column which starts at one. To use\n" + indent9 + "a metric column that is in a metric file other than the input\n" + indent9 + "metric file, start with an " + metricColumnIdentifierName + ", followed by the name of\n" + indent9 + "the metric file, followed by a " + metricFileColumnSeparatorName + " (" + metricFileColumnSeparatorCharacter + "), \n" + indent9 + "followed by the identifier of the metric column, and lastly,\n" + indent9 + "an " + metricColumnIdentifierName + ".\n" + indent9 + "\n" + indent9 + "Spaces are allowed in file names or column identifiers:\n" + indent9 + " Example \"@test file::subject 2@\"\n" + indent9 + "\n" + indent9 + "Examples (for the column named \"activation\" located in:\n" + indent9 + "the file named \"experiment.metric\"\n" + indent9 + " " + metricColumnIdentifierCharacter + "activation" + metricColumnIdentifierCharacter + "\n" + indent9 + " " + metricColumnIdentifierCharacter + "experiment.metric::activation" + metricColumnIdentifierCharacter + "\n" + indent9 + "\n" + indent9 + "If the output metric column is a name and it does not exist\n" + indent9 + "it will be created.\n" + indent9 + "\n" + indent9 + "Binary operators supported are:\n" + indent9 + " + addition\n" + indent9 + " - subtraction\n" + indent9 + " * multiplication\n" + indent9 + " / division\n" + indent9 + " ^ exponention\n" + indent9 + " max2 maximum-value\n" + indent9 + " min2 minimum-value\n" + indent9 + "\n" + indent9 + "Unary operations supported are:\n" + indent9 + " abs absolute-value\n" + indent9 + " exp exponential function\n" + indent9 + " flipsign flip the sign\n" + indent9 + " log natural log\n" + indent9 + " log2 base 2 logarithm\n" + indent9 + " log10 base 10 logarithm\n" + indent9 + " sqrt square root\n" + indent9 + "\n" + indent9 + "Predefined values from each nodes metric values\n" + indent9 + " nodeavg Average value at each node\n" + indent9 + " nodemax Maximum value at each node \n" + indent9 + " nodemin Minimum value at each node \n" + indent9 + " nodesum Sum of values at each node \n" + indent9 + "\n" + indent9 + "Example: \"5 1 2 + 4 * + 3 -\" \n" + indent9 + " Infix => ((1 + 2) * 4 + 5 - 3)\n" + indent9 + " evaluates to 14.\n" + indent9 + "Example: \"2 3 * 2 3 + min2\" \n" + indent9 + " Infix => min2(2 * 3, 2 + 3)\n" + indent9 + " evaluates to 5.\n" + indent9 + "Example: \"" + metricColumnIdentifierCharacter + "one" + metricColumnIdentifierCharacter + indent9 + " " + metricColumnIdentifierCharacter + "two" + metricColumnIdentifierCharacter + " add\" \n" + indent9 + " adds the columns named \"one\" and \"two\"." + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandMetricMathPostfix::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the input and output file names // const QString inputMetricFileName = parameters->getNextParameterAsString("Input Metric File Name"); const QString outputMetricFileName = parameters->getNextParameterAsString("Output Metric File Name"); const QString outputColumnNameNumber = parameters->getNextParameterAsString("Output Metric Column Name/Number"); const QString inputExpression = parameters->getNextParameterAsString("Postfix Expression"); checkForExcessiveParameters(); // // Get the mathematical expression // std::queue expression; convertInputToQueueOfTokens(inputExpression, expression); if (expression.empty()) { throw CommandException("No mathematical expression provided."); } // // Process the postfix expression // processPostFixExpression(inputMetricFileName, outputMetricFileName, outputColumnNameNumber, expression); } /** * convert the input string into a queue of tokens. */ void CommandMetricMathPostfix::convertInputToQueueOfTokens(const QString& inputString, std::queue& tokensOut) const throw (CommandException) { // // The input string should have each operand/operator separated by whitespace. // Metric column identifiers may contain spaces so they need to be handled specially. // const int len = inputString.length(); QString token; for (int i = 0; i < len; i++) { const QString c(inputString[i]); if (isWhiteSpace(c)) { if (token.isEmpty() == false) { tokensOut.push(token); token.clear(); } } else if (c == metricColumnIdentifierCharacter) { token += c; bool done = false; while (done == false) { i++; if (i >= len) { throw CommandException("Metric column identifier is missing closing \"" + metricColumnIdentifierCharacter + "\" \"" + token + "\"."); } const QString c(inputString[i]); token += c; if (c == metricColumnIdentifierCharacter) { tokensOut.push(token); token.clear(); done = true; } } } else { token += c; } } if (token.isEmpty() == false) { tokensOut.push(token); token.clear(); } } /** * process the postfix expression. * Algorithm from http://en.wikipedia.org/wiki/Reverse_Polish_notation */ void CommandMetricMathPostfix::processPostFixExpression(const QString& inputMetricFileName, const QString& outputMetricFileName, const QString& outputMetricColumnNameOrNumber, std::queue& postFixExpression) throw (CommandException) { // // Read the metric file // MetricFile metricFile; metricFile.readFile(inputMetricFileName); // // Check the number of nodes // numberOfNodes = metricFile.getNumberOfNodes(); if (numberOfNodes <= 0) { throw CommandException("Input metric file contains no nodes."); } const int numberOfInputMetricColumns = metricFile.getNumberOfColumns(); // // Find the output column (create if necessary) // const int outputColumnNumber = metricFile.getColumnFromNameOrNumber(outputMetricColumnNameOrNumber, true); // // Stack used for processing the postfix expression // std::stack valueStack; // // Loop through the queue until it is empty // while (postFixExpression.empty() == false) { const QString token = postFixExpression.front(); const int tokenLength = token.length(); postFixExpression.pop(); std::cout << "Processing: \"" << token.toAscii().constData() << "\"" << std::endl; const QChar firstChar = token[0]; // // Examing the first character // if (QString(firstChar) == metricColumnIdentifierCharacter) { // column name/number // // Remove metric column identifier at beginning and end of name // if (token.endsWith(metricColumnIdentifierCharacter) == false) { throw CommandException("Invalid metric column identifier (missing closing " + metricColumnIdentifierCharacter + ")"); } QString columnID = token.mid(1, tokenLength - 2); // // Is this a file name and column ID // QString columnFileName; const int fileColumnSeparatorIndex = columnID.indexOf(metricFileColumnSeparatorCharacter); if (fileColumnSeparatorIndex >= 0) { columnFileName = columnID.left(fileColumnSeparatorIndex); columnID = columnID.mid(fileColumnSeparatorIndex + 1); if (columnFileName.isEmpty()) { throw CommandException("Invalid metric column ID filename \"" + token + "\""); } } if (columnID.isEmpty()) { throw CommandException("Invalid metric column ID \"" + token + "\""); } std::cout << "column ID \"" << columnID.toAscii().constData() << "\"" << std::endl; // // Is data in a metric file that is not the input metric file // if (columnFileName.isEmpty() == false) { MetricFile columnMetricFile; columnMetricFile.readFile(columnFileName); if (columnMetricFile.getNumberOfNodes() == numberOfNodes) { // // Push column value onto stack // try { float* array = getArray(); const int columnNumber = columnMetricFile.getColumnFromNameOrNumber(columnID, false); columnMetricFile.getColumnForAllNodes(columnNumber, array); valueStack.push(array); } catch (FileException& e) { throw CommandException(e); } } else { throw CommandException(FileUtilities::basename(columnFileName) + " has a different number of nodes than " + inputMetricFileName); } } else { // // Push column value onto stack // try { float* array = getArray(); const int columnNumber = metricFile.getColumnFromNameOrNumber(columnID, false); metricFile.getColumnForAllNodes(columnNumber, array); valueStack.push(array); } catch (FileException& e) { throw CommandException(e); } } } else if (firstChar.isDigit()) { // a number // // Convert to a float // bool ok = false; const float f = token.toFloat(&ok); if (ok == false) { throw CommandException("Invalid number " + token); } // // Put the float in an array with size number of nodes // float* array = getArray(); for (int i = 0; i < numberOfNodes; i++) { array[i] = f; } // // Push onto the values stack // valueStack.push(array); } else if ((token == "abs") || // unary operators (token == "exp") || (token == "flipsign") || (token == "log") || (token == "log2") || (token == "log10") || (token == "sqrt")) { if (valueStack.size() < 1) { throw CommandException("Invalid expression (insufficient operands) at " + token); } // // Get the one column of data // float* f1 = valueStack.top(); valueStack.pop(); // // Evaluate the expression // float* value = getArray(); if (token == "abs") { for (int i = 0; i < numberOfNodes; i++) { value[i] = std::fabs(f1[i]); } } else if (token == "exp") { for (int i = 0; i < numberOfNodes; i++) { value[i] = std::exp(f1[i]); } } else if (token == "flipsign") { for (int i = 0; i < numberOfNodes; i++) { value[i] = -f1[i]; } } else if (token == "log") { for (int i = 0; i < numberOfNodes; i++) { value[i] = std::log(f1[i]); } } else if (token == "log2") { for (int i = 0; i < numberOfNodes; i++) { value[i] = MathUtilities::log(2.0, f1[i]); } } else if (token == "log10") { for (int i = 0; i < numberOfNodes; i++) { value[i] = std::log10(f1[i]); } } else if (token == "sqrt") { for (int i = 0; i < numberOfNodes; i++) { value[i] = std::sqrt(f1[i]); } } else { throw CommandException("PROGRAM ERROR unrecognized operator at line " + QString(__LINE__) + " in " + QString(__FILE__)); } // // put result back onto stack // valueStack.push(value); // // Release arrays // releaseArray(f1); } else if ((token == "+") || // binary operators (token == "-") || (token == "*") || (token == "/") || (token == "^") || (token == "max2") || (token == "min2")) { if (valueStack.size() < 2) { throw CommandException("Invalid expression (insufficient operands) at " + token); } // // Get the two column of data // float* f1 = valueStack.top(); valueStack.pop(); float* f2 = valueStack.top(); valueStack.pop(); // // Evaluate the expression // float* value = getArray(); if (token == "+") { for (int i = 0; i < numberOfNodes; i++) { value[i] = f1[i] + f2[i]; } } else if (token == "-") { for (int i = 0; i < numberOfNodes; i++) { value[i] = f2[i] - f1[i]; } } else if (token == "*") { for (int i = 0; i < numberOfNodes; i++) { value[i] = f1[i] * f2[i]; } } else if (token == "/") { for (int i = 0; i < numberOfNodes; i++) { value[i] = f2[i] / f1[i]; } } else if (token == "^") { for (int i = 0; i < numberOfNodes; i++) { value[i] = std::pow(f2[i], f1[i]); } } else if (token == "max2") { for (int i = 0; i < numberOfNodes; i++) { value[i] = std::max(f1[i], f2[i]); } } else if (token == "min2") { for (int i = 0; i < numberOfNodes; i++) { value[i] = std::min(f1[i], f2[i]); } } else { throw CommandException("PROGRAM ERROR unrecognized operator at line " + QString(__LINE__) + " in " + QString(__FILE__)); } // // put result back onto stack // valueStack.push(value); // // Release arrays // releaseArray(f1); releaseArray(f2); } else if ((token == "nodeavg") || (token == "nodemax") || (token == "nodemin") || (token == "nodesum")) { // // Evaluate the expression // float* value = getArray(); if (token == "nodeavg") { for (int i = 0; i < numberOfNodes; i++) { float sum = 0.0; for (int j = 0; j < numberOfInputMetricColumns; j++) { sum += metricFile.getValue(i, j); } value[i] = sum / static_cast(numberOfInputMetricColumns); } } else if (token == "nodemax") { for (int i = 0; i < numberOfNodes; i++) { float nodeMax = -std::numeric_limits::max(); for (int j = 0; j < numberOfInputMetricColumns; j++) { nodeMax = std::max(nodeMax, metricFile.getValue(i, j)); } value[i] = nodeMax; } } else if (token == "nodemin") { for (int i = 0; i < numberOfNodes; i++) { float nodeMin = std::numeric_limits::max(); for (int j = 0; j < numberOfInputMetricColumns; j++) { nodeMin = std::min(nodeMin, metricFile.getValue(i, j)); } value[i] = nodeMin; } } else if (token == "nodesum") { for (int i = 0; i < numberOfNodes; i++) { float sum = 0.0; for (int j = 0; j < numberOfInputMetricColumns; j++) { sum += metricFile.getValue(i, j); } value[i] = sum; } } else { throw CommandException("PROGRAM ERROR unrecognized operator at line " + QString(__LINE__) + " in " + QString(__FILE__)); } // // put result back onto stack // valueStack.push(value); } else { throw CommandException("Invalid expression at " + token); } } if (valueStack.size() != 1) { throw CommandException("Invalid expression"); } // // Get the result array // float* resultArray = valueStack.top(); valueStack.pop(); metricFile.setColumnForAllNodes(outputColumnNumber, resultArray); // // Free memory // releaseArray(resultArray); //std::cout << "Result: " << valueStack.top() << std::endl; // // Write the output metric file // metricFile.writeFile(outputMetricFileName); } /** * get an array with number of nodes elements. */ float* CommandMetricMathPostfix::getArray() { // // Is a previously used array available // if (arrayStorage.empty()) { float* f = new float[numberOfNodes]; return f; } // // Create a new array // float* f = arrayStorage.front(); arrayStorage.pop(); return f; } /** * release an array. */ void CommandMetricMathPostfix::releaseArray(float* f) { arrayStorage.push(f); } /** * see if a character is a whitespace. */ bool CommandMetricMathPostfix::isWhiteSpace(const QString& s) const { if (whitespace.indexOf(s) >= 0) { return true; } return false; } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricMath.h0000664000175000017500000000527411572067322025335 0ustar michaelmichael #ifndef __COMMAND_METRIC_MATH_H__ #define __COMMAND_METRIC_MATH_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandMetricMathPostfix.h" /// class for class CommandMetricMath : public CommandMetricMathPostfix { public: // constructor CommandMetricMath(); // destructor ~CommandMetricMath(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); // see if a character is a delimiter bool isDelimiter(const QString& s) const; // see if operator bool isOperator(const QString& s) const; // get the prcedence of an operator int getOperatorPrecedence(const QString& operatorToken) const; // push the current token into the queue void pushTokenOntoQueueAndClearToken(std::queue& queue, QString& token); // parse the input text void parseInputText(const QString& inputText, std::queue& tokensOut); // convert the infix tokens to postfix void infixToPostfix(std::queue& infixTokens, std::queue& postfixTokens); // the operators QString operators; // the delimeters in a string QString delimiters; }; #endif // __COMMAND_METRIC_MATH_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricMath.cxx0000664000175000017500000004457511572067322025717 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "CommandMetricMath.h" #include "DebugControl.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandMetricMath::CommandMetricMath() : CommandMetricMathPostfix("-metric-math", "METRIC MATH") { delimiters = "(),[]"; operators = "+-*/^"; } /** * destructor. */ CommandMetricMath::~CommandMetricMath() { } /** * get the script builder parameters. */ void CommandMetricMath::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Metric File Name", FileFilters::getMetricFileFilter()); paramsOut.addFile("Output Metric File Name", FileFilters::getMetricFileFilter()); paramsOut.addString("Output Metric Column Name/Number"); paramsOut.addVariableListOfParameters("Expression"); } /** * get full help information. */ QString CommandMetricMath::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Perform mathematical operations on a metric file.\n" + indent9 + "\n" + indent9 + "The math expression must be in double quotes. Otherwise,\n" + indent9 + "operators, such as \"*\" will match all files in the \n" + indent9 + "current directory.\n" + indent9 + "\n" + indent9 + "A metric column is identified by a sequence of characters\n" + indent9 + "the are immediately proceeded and immediately followed by\n" + indent9 + "an " + metricColumnIdentifierName + " (" + metricColumnIdentifierCharacter + "). \n" + indent9 + "\n" + indent9 + "These characters are either the name of the metric column or\n" + indent9 + "the number of the metric column which starts at one. To use\n" + indent9 + "a metric column that is in a metric file other than the input\n" + indent9 + "metric file, start with an " + metricColumnIdentifierName + ", followed by the name of\n" + indent9 + "the metric file, followed by a " + metricFileColumnSeparatorName + " (" + metricFileColumnSeparatorCharacter + "), \n" + indent9 + "followed by the identifier of the metric column, and lastly,\n" + indent9 + "an " + metricColumnIdentifierName + ".\n" + indent9 + "\n" + indent9 + "Spaces are allowed in file names or column identifiers:\n" + indent9 + " Example \"@test file::subject 2@\"\n" + indent9 + "\n" + indent9 + "Examples (for the column named \"activation\" located in:\n" + indent9 + "the file named \"experiment.metric\"\n" + indent9 + " " + metricColumnIdentifierCharacter + "activation" + metricColumnIdentifierCharacter + "\n" + indent9 + " " + metricColumnIdentifierCharacter + "experiment.metric::activation" + metricColumnIdentifierCharacter + "\n" + indent9 + "\n" + indent9 + "If the output metric column is a name and it does not exist\n" + indent9 + "it will be created.\n" + indent9 + "\n" + indent9 + "Operators supported are:\n" + indent9 + " + addition\n" + indent9 + " - subtraction\n" + indent9 + " * multiplication\n" + indent9 + " / division\n" + indent9 + " ^ exponention\n" + indent9 + "\n" + indent9 + "FUNCTIONS\n" + indent9 + " A function's parameters must be contained in square\n" + indent9 + " brackets (example max2[3, 4]).\n" + indent9 + "\n" + indent9 + " Functions accepting two parameters:\n" + indent9 + " max2 maximum-value\n" + indent9 + " min2 minimum-value\n" + indent9 + "\n" + indent9 + " Functions accepting a single parameter:\n" + indent9 + " abs absolute-value\n" + indent9 + " exp exponential function\n" + indent9 + " flipsign flip the sign\n" + indent9 + " log natural log\n" + indent9 + " log2 base 2 logarithm\n" + indent9 + " log10 base 10 logarithm\n" + indent9 + " sqrt square root\n" + indent9 + "\n" + indent9 + "Predefined values from each nodes metric values\n" + indent9 + " nodeavg Average value at each node\n" + indent9 + " nodemax Maximum value at each node \n" + indent9 + " nodemin Minimum value at each node \n" + indent9 + " nodesum Sum of values at each node \n" + indent9 + "\n" + indent9 + "Example mathematical expressions" + indent9 + " 3 + max2[7, 2] \n" + indent9 + " evaluates to 10.\n" + indent9 + "\n" + indent9 + " abs[2 * (3 - 5)] \n" + indent9 + " evaluates to 4.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandMetricMath::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the input and output file names // const QString inputMetricFileName = parameters->getNextParameterAsString("Input Metric File Name"); const QString outputMetricFileName = parameters->getNextParameterAsString("Output Metric File Name"); const QString outputColumnNameNumber = parameters->getNextParameterAsString("Output Metric Column Name/Number"); const QString expressionIn = parameters->getNextParameterAsString("Infix Expression"); checkForExcessiveParameters(); // // Parse the input // std::queue tokens; parseInputText(expressionIn, tokens); // if (DebugControl::getDebugOn()) { std::cout << "METRIC MATH TOKENS" << std::endl; std::queue q = tokens; while (q.empty() == false) { std::cout << " " << q.front().toAscii().constData() << std::endl; q.pop(); } // } if (tokens.empty()) { throw CommandException("No mathematical expression provided."); } std::queue postFixTokens; infixToPostfix(tokens, postFixTokens); // if (DebugControl::getDebugOn()) { std::cout << "POSTFIX: " << std::endl; std::queue qp = postFixTokens; while (qp.empty() == false) { std::cout << " " << qp.front().toAscii().constData(); qp.pop(); } std::cout << std::endl << std::endl; // } //throw CommandException("METRIC MATH IS IN DEVELOPMENT"); // // Process the postfix expression // processPostFixExpression(inputMetricFileName, outputMetricFileName, outputColumnNameNumber, postFixTokens); } // parse the input text void CommandMetricMath::parseInputText(const QString& inputText, std::queue& tokensOut) { // // Break the expression string into tokens // const int textLength = inputText.length(); QString currentToken; for (int i = 0; i < textLength; i++) { // // Next character // const QString c(inputText[i]); // // Is this a delimiter or operator // if (isDelimiter(c) || isOperator(c)) { // // Save current token // pushTokenOntoQueueAndClearToken(tokensOut, currentToken); // // put delimeter in queue // tokensOut.push(c); } else if (isWhiteSpace(c)) { // white space // // Save current token // pushTokenOntoQueueAndClearToken(tokensOut, currentToken); } else if (c == metricColumnIdentifierCharacter) { // start of metric column // // Save current token // pushTokenOntoQueueAndClearToken(tokensOut, currentToken); // // Find closing metric column identifier to create column name // bool validName = false; QString columnIdentifier(c); i++; while (i < textLength) { const QString& c(inputText[i]); columnIdentifier += c; if (c == metricColumnIdentifierCharacter) { validName = true; break; } else { i++; } } if (validName) { tokensOut.push(columnIdentifier); } else { throw CommandException("Metric column identifier \"" + columnIdentifier + "\" missing concluding \"" + metricColumnIdentifierCharacter + "\""); } } else { // // Add to current token // currentToken += c; } } // // Save last token // pushTokenOntoQueueAndClearToken(tokensOut, currentToken); } /** * convert the infix tokens to postfix. * This algorithm is from: * http://montcs.bloomu.edu/~bobmon/Information/RPN/infix2rpn.shtml */ void CommandMetricMath::infixToPostfix(std::queue& infixTokens, std::queue& postfixTokens) { // // Stack for operators // std::stack operatorStack; // // Stack for functions // std::stack functionStack; while (infixTokens.empty() == false) { // // Get and remove next token in input // const QString token = infixTokens.front(); infixTokens.pop(); const char tokenFirstChar = token[0].toLatin1(); // // peek ahead to next token // QString nextToken; if (infixTokens.empty() == false) { nextToken = infixTokens.front(); } const bool isOpenParenFlag = (token == "("); const bool isClosingParenFlag = (token == ")"); const bool isOpenBracketFlag = (token == "["); const bool isClosingBracketFlag = (token == "]"); const bool isCommaFlag = (token == ","); const bool isOperatorFlag = isOperator(token); const bool isOperandFlag = (((tokenFirstChar >= 'a') && (tokenFirstChar <= 'z')) || ((tokenFirstChar >= 'A') && (tokenFirstChar <= 'Z')) || ((tokenFirstChar >= '0') && (tokenFirstChar <= '9')) || (tokenFirstChar == '_') || (QString(tokenFirstChar) == metricColumnIdentifierCharacter)); // // An operand // if (isOperandFlag) { // // If next token is an open bracket then this token is a function name // if (nextToken == "[") { functionStack.push(token); } else { postfixTokens.push(token); } } else if (isOperatorFlag) { // operator ? // // If any operators in the operator stack are of equal or greater // precedence, place them into the output followed by this operator // bool done = false; while (done == false) { if (operatorStack.empty()) { done = true; } else { const QString stackOperator = operatorStack.top(); if (getOperatorPrecedence(token) <= getOperatorPrecedence(stackOperator)) { postfixTokens.push(stackOperator); operatorStack.pop(); } else { done = true; } } } operatorStack.push(token); } else if (isOpenParenFlag) { // // Put open paren into operator stack // operatorStack.push(token); } else if (isClosingParenFlag) { // // while the top of the operator stack is not an open paren // bool done = false; while (done == false) { if (operatorStack.empty()) { throw CommandException("Unbalanced parenthesis in expression."); } const QString stackToken = operatorStack.top(); // // Is an open paren on top of the stack ? // if (stackToken == "(") { // // ignore current token closed paren and done // done = true; } else { postfixTokens.push(stackToken); } operatorStack.pop(); } } else if (isOpenBracketFlag) { // // Put open bracket into operator stack // operatorStack.push(token); } else if (isClosingBracketFlag) { // // while the top of the operator stack is not an open bracket // bool done = false; while (done == false) { if (operatorStack.empty()) { throw CommandException("Unbalanced brackets in expression."); } const QString stackToken = operatorStack.top(); // // Is an open bracket on top of the stack ? // if (stackToken == "[") { // // ignore current token closed bracket and done // done = true; } else { postfixTokens.push(stackToken); } operatorStack.pop(); } if (functionStack.empty()) { throw CommandException("Function name missing before brackets."); } postfixTokens.push(functionStack.top()); functionStack.pop(); } else if (isCommaFlag) { // // while the top of the operator stack is not an open bracket // bool done = false; while (done == false) { if (operatorStack.empty()) { throw CommandException("Unbalanced brackets in expression."); } const QString stackToken = operatorStack.top(); // // Is an open bracket on top of the stack ? // if (stackToken == "[") { // // ignore current token closed bracket and done // leave bracket on stack // done = true; } else { postfixTokens.push(stackToken); operatorStack.pop(); } } } else { throw CommandException("Invalid infix expression."); } } // // Output any remaining tokens from the function stack // while (functionStack.empty() == false) { const QString stackToken = functionStack.top(); postfixTokens.push(stackToken); functionStack.pop(); } // // Output any remaining tokens from the operator stack // while (operatorStack.empty() == false) { const QString stackToken = operatorStack.top(); if (stackToken == "(") { throw CommandException("Unbalanced parenthesis in expression."); } postfixTokens.push(stackToken); operatorStack.pop(); } } /** * get the prcedence of an operator. */ int CommandMetricMath::getOperatorPrecedence(const QString& operatorToken) const { int precedence = -10000; if (operatorToken == "^") { precedence = 9; } else if (operatorToken == "*") { precedence = 8; } else if (operatorToken == "/") { precedence = 8; } else if (operatorToken == "%") { precedence = 8; } else if (operatorToken == "+") { precedence = 6; } else if (operatorToken == "-") { precedence = 6; } else if (operatorToken == "(") { precedence = -1; } else if (operatorToken == ")") { precedence = -10; } else if (operatorToken == "[") { precedence = -1; } else if (operatorToken == "]") { precedence = -10; } else { throw CommandException("Operator \"" + QString(operatorToken) + "\" does not have a precedence."); } return precedence; } /** * push the current token into the queue. */ void CommandMetricMath::pushTokenOntoQueueAndClearToken(std::queue& queue, QString& token) { token = token.trimmed(); if (token.isEmpty() == false) { queue.push(token); } token = ""; } /** * see if operator */ bool CommandMetricMath::isOperator(const QString& s) const { if (operators.indexOf(s) >= 0) { return true; } return false; } /** * see if a character is a delimiter. */ bool CommandMetricMath::isDelimiter(const QString& s) const { if (delimiters.indexOf(s) >= 0) { return true; } return false; } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricInformation.h0000664000175000017500000000346311572067322026727 0ustar michaelmichael #ifndef __COMMAND_METRIC_INFORMATION_H__ #define __COMMAND_METRIC_INFORMATION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for displaying information about a metric file class CommandMetricInformation : public CommandBase { public: // constructor CommandMetricInformation(); // destructor ~CommandMetricInformation(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_METRIC_INFORMATION_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricInformation.cxx0000664000175000017500000001316411572067322027301 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "CommandMetricInformation.h" #include "FileFilters.h" #include "FileUtilities.h" #include "MetricFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "StatisticDescriptiveStatistics.h" /** * constructor. */ CommandMetricInformation::CommandMetricInformation() : CommandBase("-metric-information", "METRIC FILE INFORMATION") { } /** * destructor. */ CommandMetricInformation::~CommandMetricInformation() { } /** * get the script builder parameters. */ void CommandMetricInformation::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Metric File Name", FileFilters::getMetricFileFilter()); } /** * get full help information. */ QString CommandMetricInformation::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Display Information about a metric file's contents.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandMetricInformation::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the name of the metric file // const QString metricFileName = parameters->getNextParameterAsString("Metric File Name"); // // Should not be any more parameters // checkForExcessiveParameters(); MetricFile metricFile; metricFile.readFile(metricFileName); std::cout << "Filename: " << FileUtilities::basename(metricFileName).toAscii().constData() << std::endl; const int numNodes = metricFile.getNumberOfNodes(); const int numCols = metricFile.getNumberOfColumns(); std::cout << "Number of Nodes: " << numNodes << std::endl; std::cout << "Number of Columns: " << numCols << std::endl; std::cout << QString("Column").rightJustified(6).toAscii().constData() << " " << QString("Minimum").rightJustified(12).toAscii().constData() << " " << QString("Maximum").rightJustified(12).toAscii().constData() << " " << QString("Mean").rightJustified(12).toAscii().constData() << " " << QString("Sample Dev").rightJustified(12).toAscii().constData() << " " << QString("% Positive").rightJustified(12).toAscii().constData() << " " << QString("% Negative").rightJustified(12).toAscii().constData() << " " << "Column Name" << std::endl; for (int j = 0; j < numCols; j++) { std::vector values; metricFile.getColumnForAllNodes(j, values); StatisticDescriptiveStatistics stats; stats.addDataArray(&values[0], numNodes); stats.execute(); float minValue, maxValue; stats.getMinimumAndMaximum(minValue, maxValue); float percentNegative = 0.0; float percentPositive = 0.0; for (int i = 0; i < numNodes; i++) { if (values[i] > 0.0) { percentPositive += 1.0; } else if (values[i] < 0.0) { percentNegative += 1.0; } } percentNegative = (percentNegative / numNodes) * 100.0; percentPositive = (percentPositive / numNodes) * 100.0; const QString colString = QString::number(j + 1).rightJustified(6); const QString minString = QString::number(minValue, 'f', 3).rightJustified(12); const QString maxString = QString::number(maxValue, 'f', 3).rightJustified(12); const QString meanString = QString::number(stats.getMean(), 'f', 3).rightJustified(12); const QString devString = QString::number(stats.getPopulationSampleStandardDeviation(), 'f', 3).rightJustified(12); const QString negString = QString::number(percentNegative, 'f', 3).rightJustified(12); const QString posString = QString::number(percentPositive, 'f', 3).rightJustified(12); std::cout << colString.toAscii().constData() << " " << minString.toAscii().constData() << " " << maxString.toAscii().constData() << " " << meanString.toAscii().constData() << " " << devString.toAscii().constData() << " " << posString.toAscii().constData() << " " << negString.toAscii().constData() << " " << metricFile.getColumnName(j).toAscii().constData() << std::endl; } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricInGroupDifference.h0000664000175000017500000000351511572067322027776 0ustar michaelmichael #ifndef __COMMAND_METRIC_IN_GROUP_DIFFERENCE_H__ #define __COMMAND_METRIC_IN_GROUP_DIFFERENCE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for metric in group difference class CommandMetricInGroupDifference : public CommandBase { public: // constructor CommandMetricInGroupDifference(); // destructor ~CommandMetricInGroupDifference(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_METRIC_IN_GROUP_DIFFERENCE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricInGroupDifference.cxx0000664000175000017500000000747111572067322030356 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurfaceMetricInGroupDifference.h" #include "BrainSet.h" #include "CommandMetricInGroupDifference.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandMetricInGroupDifference::CommandMetricInGroupDifference() : CommandBase("-metric-in-group-difference", "METRIC IN GROUP DIFFERENCE") { } /** * destructor. */ CommandMetricInGroupDifference::~CommandMetricInGroupDifference() { } /** * get the script builder parameters. */ void CommandMetricInGroupDifference::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Metric File Name", FileFilters::getMetricShapeFileFilter()); paramsOut.addFile("Output Metric File Name", FileFilters::getMetricShapeFileFilter()); paramsOut.addBoolean("Abs Value Flag"); } /** * get full help information. */ QString CommandMetricInGroupDifference::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Compute the difference between each column in the metric file. \n" + indent9 + "and all other columns in the metric file. The number of columns \n" + indent9 + "in the output metric file is [N! / (K! * (N - K)!)] where N is the. \n" + indent9 + "number of columns in the input metric file and K is 2. \n" + indent9 + "\n" + indent9 + "The abs-value-flag is either \"true\" or \"false\". If the \n" + indent9 + "abs-value-flag is true, the output is all absolute values of \n" + indent9 + "the differences. \n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandMetricInGroupDifference::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputMetricFileName = parameters->getNextParameterAsString("Input Metric/Shape File Name"); const QString outputMetricFileName = parameters->getNextParameterAsString("Output Metric/Shape File Name"); const bool absValueFlag = parameters->getNextParameterAsBoolean("Absolute Value Flag"); checkForExcessiveParameters(); BrainSet bs; BrainModelSurfaceMetricInGroupDifference diffAlg(&bs, inputMetricFileName, outputMetricFileName, absValueFlag); diffAlg.execute(); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricGradientAll.h0000664000175000017500000000341311572067322026623 0ustar michaelmichael #ifndef __COMMAND_METRIC_GRADIENT_ALL_H__ #define __COMMAND_METRIC_GRADIENT_ALL_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandMetricGradientAll : public CommandBase { public: // constructor CommandMetricGradientAll(); // destructor ~CommandMetricGradientAll(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_METRIC_GRADIENT_ALL_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricGradientAll.cxx0000664000175000017500000001621411572067322027201 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include "CommandMetricGradientAll.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceMetricGradient.h" #include "BrainModelSurfaceMetricSmoothingAll.h" #include "BrainSet.h" #include "StringUtilities.h" #include "FileUtilities.h" #include "MetricFile.h" #include "VectorFile.h" #include "CoordinateFile.h" #include "TopologyFile.h" /** * constructor. */ CommandMetricGradientAll::CommandMetricGradientAll() : CommandBase("-metric-gradient-all", "SURFACE GRADIENT OF ALL COLUMNS IN METRIC FILE") { } /** * destructor. */ CommandMetricGradientAll::~CommandMetricGradientAll() { } /** * get the script builder parameters. */ void CommandMetricGradientAll::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Coordinate File", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Input Topology File", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Input Metric File", FileFilters::getMetricFileFilter()); paramsOut.addFile("Output Metric File", FileFilters::getMetricFileFilter()); paramsOut.addBoolean("Average Normals", false); paramsOut.addFloat("Smoothing Kernel", -1.0, -1.0); } /** * get full help information. */ QString CommandMetricGradientAll::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Generate the surface gradient of a metric file. Uses a linear\n" + indent9 + "regression on a projection of the neighbor positions to a plane\n" + indent9 + "perpendicular to the surface normal, for each node. \n" + indent9 + "\n" + indent9 + " surface-coord the surface coord file\n" + indent9 + "\n" + indent9 + " surface-topo the surface topo file\n" + indent9 + "\n" + indent9 + " input-metric the input-metric file\n" + indent9 + "\n" + indent9 + " output-metric the output-metric file\n" + indent9 + "\n" + indent9 + " average-normals uses an average of the normals of the node and all\n" + indent9 + " neighbors, use 'true' if your surface is not smooth.\n" + indent9 + "\n" + indent9 + " smooth-kernel applies smoothing before computing gradient. Uses\n" + indent9 + " geodesic gaussian smoothing with specified kernel.\n" + indent9 + " Give a negative number to skip smoothing. Kernel\n" + indent9 + " specifies the geodesic distance where weight is\n" + indent9 + " 0.607, center node has weight of 1.\n" + indent9 + "\n" + indent9 + " parallel Use true to run in parallel if code was compiled\n" + indent9 + " with OpenMP, otherwise false.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandMetricGradientAll::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString coord = parameters->getNextParameterAsString("Input Coordinate File"); const QString topo = parameters->getNextParameterAsString("Input Topology File"); const QString inputMetricFileName = parameters->getNextParameterAsString("Input Metric File"); const QString outputMetricFileName = parameters->getNextParameterAsString("Output Metric File"); bool avgNormals = parameters->getNextParameterAsBoolean("Average Surface Normals"); float smoothing = parameters->getNextParameterAsFloat("Smoothing Kernel"); bool parallelFlag = parameters->getNextParameterAsBoolean("Parallel"); QTime readTimer; readTimer.start(); BrainSet mybs(topo, coord); BrainModelSurface* mysurf = mybs.getBrainModelSurface(0); MetricFile mymetric; mymetric.readFile(inputMetricFileName); std::cout << "Time to read files: " << (readTimer.elapsed() * 0.001) << " seconds." << std::endl; if (smoothing > 0.0f) { QTime smoothTimer; smoothTimer.start(); BrainModelSurfaceMetricSmoothingAll mysmooth(&mybs, mysurf, mysurf, &mymetric, BrainModelSurfaceMetricSmoothingAll::SMOOTH_ALGORITHM_GEODESIC_GAUSSIAN, 1.0f, 1, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, smoothing, parallelFlag); mysmooth.execute(); const float elapsedTime = (static_cast(smoothTimer.elapsed()) * 0.001); std::cout << "Smooth time: " << elapsedTime << std::endl; } int numCols = mymetric.getNumberOfColumns(); QTime gradientTimer; gradientTimer.start(); bool newFlag = true; if (newFlag) { BrainModelSurfaceMetricGradient myobject( &mybs, 0, &mymetric, &mymetric, avgNormals, parallelFlag); myobject.execute(); } else { for (int i = 0; i < numCols; i++) { BrainModelSurfaceMetricGradient myobject( &mybs, 0, &mymetric, i, NULL, &mymetric, i, avgNormals); myobject.execute(); } } const float elapsedTime = (static_cast(gradientTimer.elapsed()) * 0.001); std::cout << "Gradient time: " << elapsedTime << std::endl; QTime writeTimer; writeTimer.start(); mymetric.writeFile(outputMetricFileName); std::cout << "Time to write files: " << (writeTimer.elapsed() * 0.001) << " seconds." << std::endl; } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricGradient.h0000664000175000017500000000336611572067322026201 0ustar michaelmichael #ifndef __COMMAND_METRIC_GRADIENT_H__ #define __COMMAND_METRIC_GRADIENT_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandMetricGradient : public CommandBase { public: // constructor CommandMetricGradient(); // destructor ~CommandMetricGradient(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_METRIC_GRADIENT_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricGradient.cxx0000664000175000017500000001656311572067322026557 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "CommandMetricGradient.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceMetricGradient.h" #include "BrainModelSurfaceMetricSmoothing.h" #include "BrainSet.h" #include "StringUtilities.h" #include "FileUtilities.h" #include "MetricFile.h" #include "VectorFile.h" #include "CoordinateFile.h" #include "TopologyFile.h" /** * constructor. */ CommandMetricGradient::CommandMetricGradient() : CommandBase("-metric-gradient", "SURFACE GRADIENT OF A METRIC FILE") { } /** * destructor. */ CommandMetricGradient::~CommandMetricGradient() { } /** * get the script builder parameters. */ void CommandMetricGradient::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Coordinate File", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Input Topology File", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Input Metric File", FileFilters::getMetricFileFilter()); paramsOut.addString("Input Metric Column"); paramsOut.addFile("Output Vector File", FileFilters::getGiftiVectorFileFilter()); paramsOut.addFile("Output Metric File", FileFilters::getMetricFileFilter()); paramsOut.addInt("Output Metric Column Number", 1, 1); paramsOut.addBoolean("Average Normals", false); paramsOut.addFloat("Smoothing Kernel", -1.0, -1.0); } /** * get full help information. */ QString CommandMetricGradient::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Generate the surface gradient of a metric file. Uses a linear\n" + indent9 + "regression on a projection of the neighbor positions to a plane\n" + indent9 + "perpendicular to the surface normal, for each node. Use \"NULL\"\n" + indent9 + "for either output file to skip storing that output. If output-metric\n" + indent9 + "exists, the column specified by out-metric-col is replaced if it\n" + indent9 + "exists, otherwise output is appended as a new column.\n" + indent9 + "\n" + indent9 + " surface-coord the surface coord file\n" + indent9 + "\n" + indent9 + " surface-topo the surface topo file\n" + indent9 + "\n" + indent9 + " metric the metric file\n" + indent9 + "\n" + indent9 + " metric-col which column to take the gradient of\n" + indent9 + "\n" + indent9 + " output-vector the output gradient vector file\n" + indent9 + "\n" + indent9 + " output-metric output metric file for gradient magnitude\n" + indent9 + "\n" + indent9 + " out-metric-col-num which column to put the gradient magnitude into\n" + indent9 + "\n" + indent9 + " average-normals uses an average of the normals of the node and all\n" + indent9 + " neighbors, use 'true' if your surface is not smooth.\n" + indent9 + "\n" + indent9 + " smooth-kernel applies smoothing before computing gradient. Uses\n" + indent9 + " geodesic gaussian smoothing with specified kernel.\n" + indent9 + " Give a negative number to skip smoothing. Kernel\n" + indent9 + " specifies the geodesic distance where weight is\n" + indent9 + " 0.607, center node has weight of 1.\n" + indent9 + "\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandMetricGradient::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString coord = parameters->getNextParameterAsString("Input Coordinate File"); const QString topo = parameters->getNextParameterAsString("Input Topology File"); const QString metric = parameters->getNextParameterAsString("Input Metric File"); const QString metricColName = parameters->getNextParameterAsString("Input Metric Column"); const QString vector = parameters->getNextParameterAsString("Output Vector File"); const QString mag = parameters->getNextParameterAsString("Output Metric File"); int magCol = parameters->getNextParameterAsInt("Output Metric Column Number"); bool avgNormals = parameters->getNextParameterAsBoolean("Average Surface Normals"); float smoothing = parameters->getNextParameterAsFloat("Smoothing Kernel"); BrainSet mybs(topo, coord); BrainModelSurface* mysurf = mybs.getBrainModelSurface(0); MetricFile mymetric; mymetric.readFile(metric); int metricCol = mymetric.getColumnFromNameOrNumber(metricColName, false); if (smoothing > 0.0f) { BrainModelSurfaceMetricSmoothing mysmooth(&mybs, mysurf, mysurf, &mymetric, BrainModelSurfaceMetricSmoothing::SMOOTH_ALGORITHM_GEODESIC_GAUSSIAN, metricCol, metricCol, metricColName, 1.0f, 1, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, smoothing); mysmooth.execute(); } MetricFile* mymag = NULL; if (mag != QString("NULL")) { mymag = new MetricFile(); mymag->setFileName(mag); try { mymag->readFile(mag); } catch (FileException e) {}//fail silently on nonexistant or no permissions, gets written later } VectorFile* myvec = NULL; if (vector != QString("NULL")) { myvec = new VectorFile(); myvec->setFileName(vector); } BrainModelSurfaceMetricGradient myobject(&mybs, 0, &mymetric, metricCol, myvec, mymag, magCol - 1, avgNormals); myobject.execute(); if (myvec != NULL) myvec->writeFile(vector); if (mymag != NULL) mymag->writeFile(mag); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricFileCreate.h0000664000175000017500000000343411572067322026443 0ustar michaelmichael #ifndef __COMMAND_METRIC_FILE_CREATE_H__ #define __COMMAND_METRIC_FILE_CREATE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for creating a metric file class CommandMetricFileCreate : public CommandBase { public: // constructor CommandMetricFileCreate(); // destructor ~CommandMetricFileCreate(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_METRIC_FILE_CREATE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricFileCreate.cxx0000664000175000017500000001461311572067322027017 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "CommandMetricFileCreate.h" #include "FileFilters.h" #include "MetricFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandMetricFileCreate::CommandMetricFileCreate() : CommandBase("-metric-file-create", "METRIC FILE CREATION") { } /** * destructor. */ CommandMetricFileCreate::~CommandMetricFileCreate() { } /** * get the script builder parameters. */ void CommandMetricFileCreate::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Metric File Name", FileFilters::getMetricFileFilter()); paramsOut.addInt("Number of Columns", 1); paramsOut.addVariableListOfParameters("Input Metric Files/Columns"); } /** * get full help information. */ QString CommandMetricFileCreate::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + "[-number-of-nodes number-of-nodes] \n" + indent9 + "[-coordinate-file coordinate-file-for-number-of-nodes] \n" + indent9 + "[-set-column-name column-number column-name]\n" + indent9 + "[-random]\n" + indent9 + "\n" + indent9 + "Create a metric file with the specified number of nodes\n" + indent9 + "and columns with all values initialized to zero (default) \n" + indent9 + "or random numbers in the range zero to one if the \n" + indent9 + "\"-random\" option is specified.\n" + indent9 + "\n" + indent9 + "The number of columns MUST be specified using either the\n" + indent9 + "\"-number-of-nodes\" option or the \"-coordinate-file\"\n" + indent9 + "in which case the number of nodes is set to the number\n" + indent9 + "of nodes in the coordinate file.\n" + indent9 + "\n" + indent9 + "When setting column names, the \"column-number\" starts at one.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandMetricFileCreate::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get name, columns // const QString metricFileName = parameters->getNextParameterAsString("Metric File Name"); const int numberOfColumns = parameters->getNextParameterAsInt("Number of Columns"); if (numberOfColumns <= 0) { throw CommandException("Number of columns must be " "greater than zero."); } int numberOfNodes = -1; bool randomFlag = false; // // Process optional parameters // std::vector metricColumnNames(numberOfColumns, ""); while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("Metric Create Parameter"); if (paramName == "-number-of-nodes") { numberOfNodes = parameters->getNextParameterAsInt("Number of Nodes"); } else if (paramName == "-coordinate-file") { const QString coordinateFileName = parameters->getNextParameterAsString("Coordinate File Name"); CoordinateFile coordinateFile; coordinateFile.readFile(coordinateFileName); numberOfNodes = coordinateFile.getNumberOfCoordinates(); } else if (paramName == "-random") { randomFlag = true; } else if (paramName == "-set-column-name") { int metricColumnNumber = parameters->getNextParameterAsInt("Column Number"); if ((metricColumnNumber < 1) || (metricColumnNumber > numberOfColumns)) { throw CommandException("Invalid metric column number" + QString::number(metricColumnNumber)); } metricColumnNumber--; // index starting at zero metricColumnNames[metricColumnNumber] = parameters->getNextParameterAsString("Column Name"); } else { throw CommandException("Unrecognized parameter: " + paramName); } } // // Error check // if (numberOfNodes <= 0) { throw CommandException("Number of nodes must be " "greater than zero."); } // // Create the file // MetricFile metricFile; metricFile.setNumberOfNodesAndColumns(numberOfNodes, numberOfColumns); for (int i = 0; i < numberOfColumns; i++) { if (metricColumnNames[i].isEmpty() == false) { // // Set the column name // metricFile.setColumnName(i, metricColumnNames[i]); } } if (randomFlag) { const double divisor = RAND_MAX + 1.0f; for (int i = 0; i < numberOfColumns; i++) { GiftiDataArray* gda = metricFile.getDataArray(i); float* data = gda->getDataPointerFloat(); for (int j = 0; j < numberOfNodes; j++) { float v = ::rand()/(divisor); if (v < 0.0) { v = 0.0; } else if (v > 1.0) { v = 1.0; } data[j] = v; } } } // // Write the file // metricFile.writeFile(metricFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricExtrema.h0000664000175000017500000000336011572067322026043 0ustar michaelmichael #ifndef __COMMAND_METRIC_EXTREMA_H__ #define __COMMAND_METRIC_EXTREMA_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandMetricExtrema : public CommandBase { public: // constructor CommandMetricExtrema(); // destructor ~CommandMetricExtrema(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_METRIC_EXTREMA_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricExtrema.cxx0000664000175000017500000001252211572067322026416 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "CommandMetricExtrema.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "BrainModelSurfaceMetricExtrema.h" #include "BrainSet.h" #include "StringUtilities.h" #include "FileUtilities.h" #include "MetricFile.h" #include "VectorFile.h" #include "CoordinateFile.h" #include "TopologyFile.h" /** * constructor. */ CommandMetricExtrema::CommandMetricExtrema() : CommandBase("-metric-extrema", "LOCAL EXTREMA OF A METRIC FILE") { } /** * destructor. */ CommandMetricExtrema::~CommandMetricExtrema() { } /** * get the script builder parameters. */ void CommandMetricExtrema::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Coordinate File", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Input Topology File", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Input Metric File", FileFilters::getMetricFileFilter()); paramsOut.addString("Input Metric Column"); paramsOut.addFile("Output Metric File", FileFilters::getMetricFileFilter()); paramsOut.addInt("Output Metric Column Number", 0, 0); paramsOut.addInt("Neighbor Depth", 1, 1); } /** * get full help information. */ QString CommandMetricExtrema::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Find local extrema of a metric file. Nodes with greater value\n" + indent9 + "than all neighbors to hops on the mesh will have a\n" + indent9 + "value of 1 in the output, and likewise nodes less than will have a\n" + indent9 + "value of -1. All other nodes will have value 0. If the output file\n" + indent9 + "exists, the column with number out-metric-col-num is replaced if it\n" + indent9 + "exists, otherwise output is appended as a new column.\n" + indent9 + "\n" + indent9 + " surface-coord the surface coord file\n" + indent9 + "\n" + indent9 + " surface-topo the surface topo file\n" + indent9 + "\n" + indent9 + " metric the metric file\n" + indent9 + "\n" + indent9 + " metric-col which column to find the extrema of\n" + indent9 + "\n" + indent9 + " output-metric output metric file for min/max identification\n" + indent9 + "\n" + indent9 + " out-metric-col-num which column to put the output into\n" + indent9 + "\n" + indent9 + " neighbor-depth distance in hops to include neighbors for calculation\n" + indent9 + "\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandMetricExtrema::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString coord = parameters->getNextParameterAsString("Input Coordinate File"); const QString topo = parameters->getNextParameterAsString("Input Topology File"); const QString metric = parameters->getNextParameterAsString("Input Metric File"); const QString metricColName = parameters->getNextParameterAsString("Input Metric Column"); const QString extrema = parameters->getNextParameterAsString("Output Metric File"); int exCol = parameters->getNextParameterAsInt("Output Metric Column Number"); int depth = parameters->getNextParameterAsInt("Neighbor Depth"); BrainSet mybs(topo, coord); MetricFile mymetric; mymetric.readFile(metric); MetricFile myex; try { myex.readFile(extrema); } catch (FileException e) {} int metricCol = mymetric.getColumnFromNameOrNumber(metricColName, false); BrainModelSurfaceMetricExtrema myobject(&mybs, 0, &mymetric, metricCol, &myex, exCol - 1, depth); myobject.execute(); myex.writeFile(extrema); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricCorrelationMatrix.h0000664000175000017500000000345711572067322030113 0ustar michaelmichael #ifndef __COMMAND_METRIC_CORRELATION_MATRIX_H__ #define __COMMAND_METRIC_CORRELATION_MATRIX_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandMetricCorrelationMatrix : public CommandBase { public: // constructor CommandMetricCorrelationMatrix(); // destructor ~CommandMetricCorrelationMatrix(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_METRIC_CORRELATION_MATRIX_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricCorrelationMatrix.cxx0000664000175000017500000001625611572067322030467 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainModelSurfaceMetricCorrelationMatrix.h" #include "BrainSet.h" #include "CommandMetricCorrelationMatrix.h" #include "FileFilters.h" #include "GiftiDataArrayFile.h" #include "MetricFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandMetricCorrelationMatrix::CommandMetricCorrelationMatrix() : CommandBase("-metric-correlation-matrix", "METRIC CORRELATION MATRIX") { } /** * destructor. */ CommandMetricCorrelationMatrix::~CommandMetricCorrelationMatrix() { } /** * get the script builder parameters. */ void CommandMetricCorrelationMatrix::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Metric File Name", FileFilters::getMetricFileFilter()); paramsOut.addFile("Output Metric File Name", FileFilters::getMetricFileFilter()); paramsOut.addVariableListOfParameters("Options"); } /** * get full help information. */ QString CommandMetricCorrelationMatrix::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-apply-fisher-z-transform]\n" + indent9 + "[-parallel]\n" + indent9 + "\n" + indent9 + "Compute a correlation matrix using the input metric file.\n" + indent9 + "Each row (node) in the metric file is correlated with all\n" + indent9 + "other rows in the metric file. Each column in the metric\n" + indent9 + "file represents an \"observation\" at each node. \n" + indent9 + "\n" + indent9 + "The number of rows and columns are the same in the output\n" + indent9 + "metric file and are equal to the number of rows from the \n" + indent9 + "input metric file. The values in the output metric file \n" + indent9 + "form a symmetric matrix with each element containing \n" + indent9 + "a correlation coefficient for the data of two nodes where\n" + indent9 + "the node numbers are the row and column indices.\n" + indent9 + "\n" + indent9 + "An example input metric file is one in which each row\n" + indent9 + "represents nodes and each column represents timepoints. \n" + indent9 + "The output metric file contains correlation coefficients\n" + indent9 + "that measure the similarity of the timepoints from all\n" + indent9 + "nodes to all nodes.\n" + indent9 + "\n" + indent9 + "If \"-apply-fisher-z-transform\" options is specified a\n" + indent9 + "is applied to the correlation values.\n" + indent9 + "\n" + indent9 + "If the \"-parallel\" option is specified, the algorithm\n" + indent9 + "will run its operations with multiple threads to reduce\n" + indent9 + "execution time.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandMetricCorrelationMatrix::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the input and output file names // const QString inputMetricFileName = parameters->getNextParameterAsString("Input Metric File Name"); const QString outputMetricFileName = parameters->getNextParameterAsString("Output Metric File Name"); bool applyFisherZTransformFlag = false; bool parallelFlag = false; bool giftiFlag = true; bool incrementalFlag = true; // // Process optional parameters // while (parameters->getParametersAvailable()) { // // parameter name // const QString paramName = parameters->getNextParameterAsString("Option"); if (paramName == "-apply-fisher-z-transform") { applyFisherZTransformFlag = true; } else if (paramName == "-parallel") { parallelFlag = true; } else { throw CommandException("Unrecognized parameter: " + paramName); } } // // Read the metric file // MetricFile mf; if (incrementalFlag == false) { QTime readTimer; readTimer.start(); mf.readFile(inputMetricFileName); std::cout << "Time to read file " << (readTimer.elapsed() * 0.001) << " seconds." << std::endl; } QTime algTimer; algTimer.start(); BrainModelSurfaceMetricCorrelationMatrix* alg = NULL; if (incrementalFlag) { alg = new BrainModelSurfaceMetricCorrelationMatrix(inputMetricFileName, outputMetricFileName, applyFisherZTransformFlag, giftiFlag, parallelFlag); } else { BrainSet brainSet; alg = new BrainModelSurfaceMetricCorrelationMatrix(&brainSet, &mf, applyFisherZTransformFlag, giftiFlag, parallelFlag); } alg->execute(); std::cout << "Time to run algorithm " << (algTimer.elapsed() * 0.001) << " seconds." << std::endl; // // Write metric file // if (incrementalFlag == false) { QTime writeTimer; writeTimer.start(); if (giftiFlag) { GiftiDataArrayFile* outputGiftiFile = alg->getOutputGiftiFile(); outputGiftiFile->writeFile(outputMetricFileName); delete outputGiftiFile; } else { MetricFile* outputMetricFile = alg->getOutputMetricFile(); outputMetricFile->writeFile(outputMetricFileName); delete outputMetricFile; } std::cout << "Time to write file " << (writeTimer.elapsed() * 0.001) << " seconds." << std::endl; } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricCorrelationCoefficientMap.h0000664000175000017500000000360111572067322031512 0ustar michaelmichael #ifndef __COMMAND_METRIC_CORRELATION_COEFFICIENT_MAP_H__ #define __COMMAND_METRIC_CORRELATION_COEFFICIENT_MAP_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for metric correlation coefficient class CommandMetricCorrelationCoefficientMap : public CommandBase { public: // constructor CommandMetricCorrelationCoefficientMap(); // destructor ~CommandMetricCorrelationCoefficientMap(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_METRIC_CORRELATION_COEFFICIENT_MAP_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricCorrelationCoefficientMap.cxx0000664000175000017500000000742711572067322032077 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandMetricCorrelationCoefficientMap.h" #include "FileFilters.h" #include "MetricFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandMetricCorrelationCoefficientMap::CommandMetricCorrelationCoefficientMap() : CommandBase("-metric-correlation-coefficient-map", "METRIC CORRELATION COEFFICIENT MAP") { } /** * destructor. */ CommandMetricCorrelationCoefficientMap::~CommandMetricCorrelationCoefficientMap() { } /** * get the script builder parameters. */ void CommandMetricCorrelationCoefficientMap::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Metric File Name A", FileFilters::getMetricShapeFileFilter()); paramsOut.addFile("Input Metric File Name B", FileFilters::getMetricShapeFileFilter()); paramsOut.addFile("Output Metric File Name", FileFilters::getMetricShapeFileFilter()); } /** * get full help information. */ QString CommandMetricCorrelationCoefficientMap::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "For each node, compute a correlation coefficient from the node's values\n" + indent9 + "in the two input metric files. The two input files must have the same\n" + indent9 + "number of columns and column 'j' in the two files should contain data\n" + indent9 + "for the same subject.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandMetricCorrelationCoefficientMap::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString inputMetricFileNameA = parameters->getNextParameterAsString("Input Metric File Name A"); const QString inputMetricFileNameB = parameters->getNextParameterAsString("Input Metric File Name B"); const QString outputMetricFileName = parameters->getNextParameterAsString("Output Metric File Name"); checkForExcessiveParameters(); MetricFile metricFileA, metricFileB; metricFileA.readFile(inputMetricFileNameA); metricFileB.readFile(inputMetricFileNameB); MetricFile* outputMetricFile = MetricFile::computeCorrelationCoefficientMap(&metricFileA, &metricFileB); outputMetricFile->writeFile(outputMetricFileName); delete outputMetricFile; outputMetricFile = NULL; } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricCompositeIdentifiedColumns.h0000664000175000017500000000363111572067322031727 0ustar michaelmichael #ifndef __COMMAND_METRIC_COMPOSITE_IDENTIFIED_COLUMNS_H__ #define __COMMAND_METRIC_COMPOSITE_IDENTIFIED_COLUMNS_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for compositing identified columns from metric files class CommandMetricCompositeIdentifiedColumns : public CommandBase { public: // constructor CommandMetricCompositeIdentifiedColumns(); // destructor ~CommandMetricCompositeIdentifiedColumns(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_METRIC_COMPOSITE_IDENTIFIED_COLUMNS_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricCompositeIdentifiedColumns.cxx0000664000175000017500000001164211572067322032303 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandMetricCompositeIdentifiedColumns.h" #include "FileFilters.h" #include "FileUtilities.h" #include "MetricFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandMetricCompositeIdentifiedColumns::CommandMetricCompositeIdentifiedColumns() : CommandBase("-metric-composite-identified-columns", "METRIC COMPOSITE IDENTIFIED COLUMNS") { } /** * destructor. */ CommandMetricCompositeIdentifiedColumns::~CommandMetricCompositeIdentifiedColumns() { } /** * get the script builder parameters. */ void CommandMetricCompositeIdentifiedColumns::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Output Metric File Name", FileFilters::getMetricFileFilter()); paramsOut.addVariableListOfParameters("Input Metric Files/Columns"); } /** * get full help information. */ QString CommandMetricCompositeIdentifiedColumns::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " \n" + indent9 + "[input-metric-file-1 file-1-column] \n" + indent9 + "...\n" + indent9 + "[input-metric-file-N file-2-column]\n" + indent9 + "\n" + indent9 + "Composite the selected columns from the input metric\n" + indent9 + "files and place them into the output metric file.\n" + indent9 + "\n" + indent9 + "\"column\" is either the number of the column, which\n" + indent9 + "starts at one, or the name of the column. If a\n" + indent9 + "a name contains spaces, it must be enclosed in double\n" + indent9 + "quotes. Name has priority over number.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandMetricCompositeIdentifiedColumns::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get output file // const QString outputMetricFileName = parameters->getNextParameterAsString("Output Metric File Name"); MetricFile outputMetricFile; // // Process input files // while (parameters->getParametersAvailable()) { // // Get input file name and column identifier // const QString inputMetricFileName = parameters->getNextParameterAsString("Input Metric File Name"); const QString columnID = parameters->getNextParameterAsString("Column Identifier"); // // Read the metric file and get the actual column number // MetricFile metricFile; metricFile.readFile(inputMetricFileName); const int numColumns = metricFile.getNumberOfColumns(); if (numColumns <= 0) { throw CommandException(FileUtilities::basename(metricFile.getFileName()) + " contains no columns"); } const int metricColumnNumber = metricFile.getColumnFromNameOrNumber(columnID, false); // // Append only the identified column // std::vector destination(numColumns, MetricFile::APPEND_COLUMN_DO_NOT_LOAD); destination[metricColumnNumber] = MetricFile::APPEND_COLUMN_NEW; outputMetricFile.append(metricFile, destination, MetricFile::FILE_COMMENT_MODE_LEAVE_AS_IS); } // // Check for data // if (outputMetricFile.getNumberOfColumns() <= 0) { throw CommandException("No columns were appended to " + FileUtilities::basename(outputMetricFileName)); } // // Write the output metric file // outputMetricFile.writeFile(outputMetricFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricComposite.h0000664000175000017500000000342311572067322026400 0ustar michaelmichael #ifndef __COMMAND_METRIC_COMPOSITE_H__ #define __COMMAND_METRIC_COMPOSITE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for combining metric files class CommandMetricComposite : public CommandBase { public: // constructor CommandMetricComposite(); // destructor ~CommandMetricComposite(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_METRIC_COMPOSITE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricComposite.cxx0000664000175000017500000000713211572067322026754 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandMetricComposite.h" #include "FileFilters.h" #include "MetricFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandMetricComposite::CommandMetricComposite() : CommandBase("-metric-composite", "METRIC FILE COMPOSITE ALL COLUMNS") { } /** * destructor. */ CommandMetricComposite::~CommandMetricComposite() { } /** * get the script builder parameters. */ void CommandMetricComposite::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Output Metric File Name", FileFilters::getMetricFileFilter()); paramsOut.addMultipleFiles("Input Metric File Name(s)", FileFilters::getMetricFileFilter()); } /** * get full help information. */ QString CommandMetricComposite::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Concatenate all columns from the input metric files and place\n" + indent9 + "them into the output metric file\n"); return helpInfo; } /** * execute the command. */ void CommandMetricComposite::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the parameters // const QString outputMetricFileName = parameters->getNextParameterAsString("Output Metric File Name"); std::vector inputMetricFileNames; parameters->getRemainingParametersAsStrings("Input Metric Files", inputMetricFileNames); const int numMetricFiles = static_cast(inputMetricFileNames.size()); if (numMetricFiles <= 0) { throw CommandException("Names of input metric files are missing."); } MetricFile outputMetricFile; for (int i = 0; i < numMetricFiles; i++) { if (outputMetricFile.getNumberOfColumns() == 0) { outputMetricFile.readFile(inputMetricFileNames[i]); } else { MetricFile inputMetricFile; inputMetricFile.readFile(inputMetricFileNames[i]); const int numCols = inputMetricFile.getNumberOfColumns(); if (numCols > 0) { outputMetricFile.append(inputMetricFile); } } } outputMetricFile.writeFile(outputMetricFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricClustering.h0000664000175000017500000000340211572067322026552 0ustar michaelmichael #ifndef __COMMAND_METRIC_CLUSTERING_H__ #define __COMMAND_METRIC_CLUSTERING_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandMetricClustering : public CommandBase { public: // constructor CommandMetricClustering(); // destructor ~CommandMetricClustering(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_METRIC_CLUSTERING_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandMetricClustering.cxx0000664000175000017500000002004311572067322027125 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurfaceMetricClustering.h" #include "BrainSet.h" #include "CommandMetricClustering.h" #include "FileFilters.h" #include "MetricFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandMetricClustering::CommandMetricClustering() : CommandBase("-metric-clustering", "METRIC CLUSTERING") { } /** * destructor. */ CommandMetricClustering::~CommandMetricClustering() { } /** * get the script builder parameters. */ void CommandMetricClustering::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { std::vector values, descriptions; values.push_back("ANY_SIZE"); descriptions.push_back("Any Size"); values.push_back("MINIMUM_NUMBER_OF_NODES"); descriptions.push_back("Minimum Number of Nodes"); values.push_back("MINIMUM_SURFACE_AREA"); descriptions.push_back("Minimum Surface Area"); paramsOut.clear(); paramsOut.clear(); paramsOut.addFile("Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Input Metric File Name", FileFilters::getMetricFileFilter()); paramsOut.addFile("Output Metric File Name", FileFilters::getMetricFileFilter()); paramsOut.addFloat("Minimum Negative Threshold", -5.0); paramsOut.addFloat("Maximum Negative Threshold", -10.0); paramsOut.addFloat("Minimum Positive Threshold", 5.0); paramsOut.addFloat("Maximum Positive Threshold", 10.0); paramsOut.addListOfItems("Cluster Mode", values, descriptions); paramsOut.addInt("Minimum Number of Nodes", 25); paramsOut.addFloat("Minimum Surface Area", 25.0); } /** * get full help information. */ QString CommandMetricClustering::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Perform clustering on all columns in a metric file.\n" + indent9 + "\n" + indent9 + "\"cluster-mode\" must be one of:\n" + indent9 + " ANY_SIZE\n" + indent9 + " MINIMUM_NUMBER_OF_NODES\n" + indent9 + " MINIMUM_SURFACE_AREA\n" + indent9 + "\n" + indent9 + "Note: The \"maximum-negative-threshold\" should be\n" + indent9 + "LESS THAN (more negative) than the \n" + indent9 + "\"minimum-negative-threshold\".\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandMetricClustering::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString coordinateFileName = parameters->getNextParameterAsString("Coordinate File Name"); const QString topologyFileName = parameters->getNextParameterAsString("Topology File Name"); const QString inputMetricFileName = parameters->getNextParameterAsString("Input Metric File Name"); const QString outputMetricFileName = parameters->getNextParameterAsString("Output Metric File Name"); const float minimumNegativeThreshold = parameters->getNextParameterAsFloat("Minimum Negative Threshold"); const float maximumNegativeThreshold = parameters->getNextParameterAsFloat("Maximum Negative Threshold"); const float minimumPositiveThreshold = parameters->getNextParameterAsFloat("Minimum Positive Threshold"); const float maximumPositiveThreshold = parameters->getNextParameterAsFloat("Maximum Positive Threshold"); const QString modeName = parameters->getNextParameterAsString("Cluster Mode Name"); const int minimumNumberOfNodes = parameters->getNextParameterAsInt("Minimum Number of Nodes"); const float minimumSurfaceArea = parameters->getNextParameterAsFloat("Minimum Surface Area"); checkForExcessiveParameters(); // // Get algorithm // BrainModelSurfaceMetricClustering::CLUSTER_ALGORITHM clusterAlgorithm; if (modeName == "ANY_SIZE") { clusterAlgorithm = BrainModelSurfaceMetricClustering::CLUSTER_ALGORITHM_ANY_SIZE; } else if (modeName == "MINIMUM_SURFACE_AREA") { clusterAlgorithm = BrainModelSurfaceMetricClustering::CLUSTER_ALGORITHM_MINIMUM_SURFACE_AREA; } else if (modeName == "MINIMUM_NUMBER_OF_NODES") { clusterAlgorithm = BrainModelSurfaceMetricClustering::CLUSTER_ALGORITHM_MINIMUM_NUMBER_OF_NODES; } else { throw CommandException("Invalid mode: \"" + modeName + "\""); } // // Create a brain set // BrainSet brainSet(topologyFileName, coordinateFileName, "", true); BrainModelSurface* surface = brainSet.getBrainModelSurface(0); if (surface == NULL) { throw CommandException("unable to find surface."); } const TopologyFile* tf = surface->getTopologyFile(); if (tf == NULL) { throw CommandException("unable to find topology."); } const int numNodes = surface->getNumberOfNodes(); if (numNodes == 0) { throw CommandException("surface contains no nodes."); } // // Read input metric file // MetricFile metricFile; metricFile.readFile(inputMetricFileName); // // Perform clustering // const int numberOfColumns = metricFile.getNumberOfColumns(); for (int i = 0; i < numberOfColumns; i++) { BrainModelSurfaceMetricClustering clustering(&brainSet, surface, &metricFile, clusterAlgorithm, i, i, metricFile.getColumnName(i), minimumNumberOfNodes, minimumSurfaceArea, minimumNegativeThreshold, maximumNegativeThreshold, minimumPositiveThreshold, maximumPositiveThreshold, true); clustering.execute(); } // // Write the metric file // metricFile.writeFile(outputMetricFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandImageView.h0000664000175000017500000000371711572067322025155 0ustar michaelmichael #ifndef __COMMAND_IMAGE_VIEW_H__ #define __COMMAND_IMAGE_VIEW_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" class QImage; /// class for viewing an image file class CommandImageView : public CommandBase { public: // constructor CommandImageView(); // destructor ~CommandImageView(); // get full help information QString getHelpInformation() const; // display a QImage static int displayQImage(const QImage& qimage); // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; /// command requires GUI flag sent to QApplication to be true virtual bool getHasGUI() const { return true; } protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_IMAGE_VIEW_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandImageView.cxx0000664000175000017500000000741411572067322025526 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include "CommandImageView.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandImageView::CommandImageView() : CommandBase("-image-view", "IMAGE VIEW") { } /** * destructor. */ CommandImageView::~CommandImageView() { } /** * get full help information. */ QString CommandImageView::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "View an image file.\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandImageView::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the parameters // const QString imageFileName = parameters->getNextParameterAsString("Image File Name"); // // Make sure that are no more parameters // checkForExcessiveParameters(); // // Read the image // QImage image; if (image.load(imageFileName) == false) { throw CommandException("Unable to load \"" + imageFileName + "\""); } // // Show the image // if (displayQImage(image) != 0) { throw CommandException("Image viewing failed."); } } /** * get the script builder parameters. */ void CommandImageView::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { QStringList fileFilters, fileExtensions; FileFilters::getImageSaveFileFilters(fileFilters, fileExtensions); paramsOut.clear(); paramsOut.addFile("Image File Name", fileFilters); } /** * display a QImage. */ int CommandImageView::displayQImage(const QImage& qimage) { // // Show the image // QLabel* label = new QLabel; label->setPixmap(QPixmap::fromImage(qimage)); // // There is a limitation with the Mac OSX version of QT in that the program // must be built as an application for scrollbars to work correctly. So, on // Mac OSX, simply show the image. // #ifdef Q_OS_MAC label->setFixedSize(qimage.width(), qimage.height()); label->show(); #else // Q_OS_MAC QScrollArea* scrollArea = new QScrollArea; scrollArea->setWidget(label); scrollArea->show(); #endif // Q_OS_MAC // // Allow the event loop to execute // return qApp->exec(); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandImageToWebPage.h0000664000175000017500000000337411572067322026057 0ustar michaelmichael #ifndef __COMMAND_IMAGE_TO_WEB_PAGE_H__ #define __COMMAND_IMAGE_TO_WEB_PAGE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandImageToWebPage : public CommandBase { public: // constructor CommandImageToWebPage(); // destructor ~CommandImageToWebPage(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_IMAGE_TO_WEB_PAGE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandImageToWebPage.cxx0000664000175000017500000002176111572067322026432 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include "CommandImageToWebPage.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandImageToWebPage::CommandImageToWebPage() : CommandBase("-image-to-web-page", "IMAGE INTO WEB PAGE") { } /** * destructor. */ CommandImageToWebPage::~CommandImageToWebPage() { } /** * get the script builder parameters. */ void CommandImageToWebPage::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); } /** * get full help information. */ QString CommandImageToWebPage::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " [page-name-prefix]\n" + indent9 + "\n" + indent9 + "Creates a single web page (.html file) or a set of web pages \n" + indent9 + "for each of the images.\n" + indent9 + "\n" + indent9 + "\"\" is one of:\n" + indent9 + " ALL\n" + indent9 + " SINGLE\n" + indent9 + "\n" + indent9 + "If \"\" is \"ALL\", all of the images are placed \n" + indent9 + "vertically in a single web page.\n" + indent9 + "\n" + indent9 + "If \"\" is \"SINGLE\", each image is placed in its own\n" + indent9 + "web page and each of the web pages is linked to allow\n" + indent9 + "stepping through the images.\n" + indent9 + "\n" + indent9 + "\"\" is not a wild card but is the\n" + indent9 + "last characters of the image filenames.\n" + indent9 + " ie: jpg implies all files ending in \"jpg\"\n" + indent9 + "\n" + indent9 + "\"[page-name-prefix]\" is optional, and, if not specified,\n" + indent9 + "each of the web pages matches the name of its image file.\n" + indent9 + "If \"[page-name-prefix]\" is specified, it is the prefix\n" + indent9 + "for all web page names.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandImageToWebPage::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get parameters // const QString modeName = parameters->getNextParameterAsString("Mode"); const QString imageFileExtension = parameters->getNextParameterAsString("Image Filename Extension"); QString pageNamePrefix; if (parameters->getParametersAvailable()) { pageNamePrefix = parameters->getNextParameterAsString("Page Name Prefix"); } checkForExcessiveParameters(); // // Check mode // enum MODE { MODE_ALL, MODE_SINGLE } mode; if (modeName == "ALL") { mode = MODE_ALL; } else if (modeName == "SINGLE") { mode = MODE_SINGLE; } else { throw CommandException("Invalid mode: " + modeName); } // // Find all of the image files // QStringList imageFileNames; QDir dir(QString::null, "*"); for (unsigned int i = 0; i < dir.count(); i++) { if (dir[i].endsWith(imageFileExtension)) { imageFileNames.push_back(dir[i]); } } // // Verify that there are images // const int numImages = imageFileNames.size(); if (numImages <= 0) { throw CommandException("No files ending with " + imageFileExtension + " were found."); } // // If only one image, then use ALL mode // if (numImages == 1) { mode = MODE_ALL; } // // Create the web-pages // const QString space(" "); switch (mode) { case MODE_ALL: { const QString htmlPageName(pageNamePrefix + imageFileNames[0] + ".html"); QFile file(htmlPageName); if (file.open(QFile::WriteOnly)) { QTextStream stream(&file); stream << "" << "\n"; stream << " " << "\n"; stream << "" << "\n"; for (int i = 0; i < numImages; i++) { stream << "
" << "\n"; stream << space << space << imageFileNames[i] << "\n"; stream << "

" << "\n"; } stream << "" << "\n"; stream << "" << "\n"; file.close(); std::cout << "HTML web page is " << htmlPageName.toAscii().constData() << std::endl; } else { throw CommandException(htmlPageName + " " + file.errorString()); } } break; case MODE_SINGLE: { const QString firstPageName(pageNamePrefix + imageFileNames[0] + ".html"); const QString firstPageLink("first"); const QString lastPageLink("last"); for (int i = 0; i < numImages; i++) { QString prevPageLink; if (i > 0) { prevPageLink = "prev"; } QString nextPageLink; if (i < static_cast((numImages- 1))) { nextPageLink = "next"; } QString name(pageNamePrefix + imageFileNames[i]); name += ".html"; QFile file(name); if (file.open(QFile::WriteOnly)) { QTextStream stream(&file); stream << "" << "\n"; stream << " " << "\n"; stream << "" << "\n"; stream << firstPageLink << "\n"; stream << space << space << "\n"; if (prevPageLink.isEmpty() == false) { stream << prevPageLink << "\n"; } stream << space << space << "\n"; if (nextPageLink.isEmpty() == false) { stream << nextPageLink << "\n"; } stream << space << space << "\n"; stream << lastPageLink << "\n"; stream << "

Image Name:" << space << space << imageFileNames[i] << "\n"; stream << "

" << "\n"; stream << "" << "\n"; stream << "

" << "\n"; stream << firstPageLink << "\n"; stream << space << space << "\n"; if (prevPageLink.isEmpty() == false) { stream << prevPageLink << "\n"; } stream << space << space << "\n"; if (nextPageLink.isEmpty() == false) { stream << nextPageLink << "\n"; } stream << space << space << "\n"; stream << lastPageLink << "\n"; stream << "

Image Name:" << space << space << imageFileNames[i] << "\n"; stream << "" << "\n"; stream << "" << "\n"; file.close(); } else { throw CommandException(name + " " + file.errorString()); } } std::cout << "First web page is " << firstPageName.toAscii().constData() << std::endl; } break; } // // Loop through the images // for (int i = 0; i < numImages; i++) { } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandImageResize.h0000664000175000017500000000336611572067322025504 0ustar michaelmichael #ifndef __COMMAND_IMAGE_RESIZE_H__ #define __COMMAND_IMAGE_RESIZE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for resizing an image class CommandImageResize : public CommandBase { public: // constructor CommandImageResize(); // destructor ~CommandImageResize(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_IMAGE_RESIZE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandImageResize.cxx0000664000175000017500000002027411572067322026054 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "CommandImageResize.h" #include "FileFilters.h" #include "ImageFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandImageResize::CommandImageResize() : CommandBase("-image-resize", "IMAGE RESIZE") { } /** * destructor. */ CommandImageResize::~CommandImageResize() { } /** * get the script builder parameters. */ void CommandImageResize::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { std::vector unitValues, unitNames; unitValues.push_back("CM"); unitNames.push_back("Centimeters"); unitValues.push_back("INCH"); unitNames.push_back("Inches"); unitValues.push_back("PIXEL"); unitNames.push_back("Pixels"); paramsOut.clear(); paramsOut.addFile("Input Image File Name", FileFilters::getImageOpenFileFilter()); paramsOut.addFile("Input Image File Name", FileFilters::getImageSaveFileFilter()); paramsOut.addListOfItems("New Image Units", unitValues, unitNames); paramsOut.addFloat("New Image Width", 512.0, -1); paramsOut.addFloat("New Image Height", 512.0, -1); paramsOut.addInt("Dots Per Meter/Inch", 72, 1); } /** * get full help information. */ QString CommandImageResize::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[dots-per-meter-or-inch]\n" + indent9 + "\n" + indent9 + "Resize an image.\n" + indent9 + "\n" + indent9 + "If \"new-image-width\" (or \"new-image-height\") is zero \n" + indent9 + "or a negative number, the new width (or height) is scaled\n" + indent9 + "so that the aspect ratio of the image is maintained.\n" + indent9 + "\n" + indent9 + "The units of \"new-image-width\" and \"new-image-height\"\n" + indent9 + "are specified by \"new-image-width-and-height-units-type\"\n" + indent9 + "which must be one of the following values:\n" + indent9 + " CM\n" + indent9 + " INCH\n" + indent9 + " PIXEL\n" + indent9 + "\n" + indent9 + "\"If \"dots-per-meter-or-inch\" is not specified, the value \n" + indent9 + "from the input image is used. The units of this value is\n" + indent9 + "is dots per meter if \"new-image-width-and-height-units-type\"\n" + indent9 + "is \"CM\" and this value is dots per inch if \n" + indent9 + "\"new-image-width-and-height-units-type\" is \"INCH\".\n" + indent9 + "\n" + indent9 + "On Linux and Mac OSX, multiple images can be resized by\n" + indent9 + "using the \"apply\" command. For example, to resize all\n" + indent9 + "JPEG images (file extension \".jpg\") in the current \n" + indent9 + "directory so that they are 320 pixels wide and 240 pixels\n" + indent9 + "in height:\n" + indent9 + " apply \"caret_command -image-resize %1 %1 PIXEL 320 240\" *.jpg\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandImageResize::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the parameters // const QString inputImageFileName = parameters->getNextParameterAsString("Input Image File Name"); const QString outputImageFileName = parameters->getNextParameterAsString("Output Image File Name"); const QString imageUnitsTypeName = parameters->getNextParameterAsString("New Image Units Type"); float outputImageWidth = parameters->getNextParameterAsFloat("New Image Width"); float outputImageHeight = parameters->getNextParameterAsFloat("New Image Height"); int outputDotsPerUnit = -1; if (parameters->getParametersAvailable()) { outputDotsPerUnit = parameters->getNextParameterAsInt("Dots Per Meter or Inch"); if (outputDotsPerUnit <= 0) { throw CommandException("Dots per meter or inch must be positive."); } } checkForExcessiveParameters(); // // Check parameters // if ((outputImageWidth <= 0) && (outputImageHeight <= 0)) { throw CommandException("One of Image Width or Height must be positive."); } // // Read the input image // ImageFile imageFile; imageFile.readFile(inputImageFileName); // // Get a pointer to the image // QImage* image = imageFile.getImage(); // // Get the input image width, height, and aspect ratio // const float inputImageWidth = image->width(); const float inputImageHeight = image->height(); if ((inputImageWidth <= 0.0) || (inputImageHeight <= 0.0)) { throw CommandException("Input image contains no data."); } const float inputImageAspectRatio = inputImageHeight / inputImageWidth; // // Set output image width/height as needed // if (outputImageWidth <= 0) { outputImageWidth = outputImageHeight / inputImageAspectRatio; } else if (outputImageHeight <= 0) { outputImageHeight = outputImageWidth * inputImageAspectRatio; } // // Determine size of output image // int width = static_cast(inputImageWidth); int height = static_cast(inputImageHeight); int dotsPerMeter = image->dotsPerMeterX(); if (imageUnitsTypeName == "CM") { float dotsPerCM = dotsPerMeter / 100.0; if (outputDotsPerUnit > 0) { dotsPerCM = outputDotsPerUnit / 100.0; } width = static_cast(outputImageWidth * dotsPerCM); height = static_cast(outputImageHeight * dotsPerCM); dotsPerMeter = static_cast(dotsPerCM * 100); } else if (imageUnitsTypeName == "INCH") { const float INCHES_PER_METER = 39.37; float dotsPerInch = dotsPerMeter / INCHES_PER_METER; if (outputDotsPerUnit > 0) { dotsPerInch = outputDotsPerUnit; } width = static_cast(outputImageWidth * dotsPerInch); height = static_cast(outputImageHeight * dotsPerInch); dotsPerMeter = static_cast(dotsPerInch * INCHES_PER_METER); } else if (imageUnitsTypeName == "PIXEL") { width = static_cast(outputImageWidth); height = static_cast(outputImageHeight); if (outputDotsPerUnit > 0) { dotsPerMeter = outputDotsPerUnit; } } else { throw CommandException("Image Units Type Name invalid: " + imageUnitsTypeName); } // // Resize the image // *image = image->scaled(width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); // // Set dots per meter // image->setDotsPerMeterX(dotsPerMeter); image->setDotsPerMeterY(dotsPerMeter); // // Set image size and dots per inch // // // Write the output image // imageFile.writeFile(outputImageFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandImageInsertText.h0000664000175000017500000000360011572067322026343 0ustar michaelmichael #ifndef __COMMAND_IMAGE_INSERT_TEXT_H__ #define __COMMAND_IMAGE_INSERT_TEXT_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandImageInsertText : public CommandBase { public: // constructor CommandImageInsertText(); // destructor ~CommandImageInsertText(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; /// command requires GUI flag sent to QApplication to be true virtual bool getHasGUI() const { return true; } protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_IMAGE_INSERT_TEXT_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandImageInsertText.cxx0000664000175000017500000001070011572067322026715 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include "CommandImageInsertText.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandImageInsertText::CommandImageInsertText() : CommandBase("-image-insert-text", "IMAGE INSERT TEXT") { } /** * destructor. */ CommandImageInsertText::~CommandImageInsertText() { } /** * get the script builder parameters. */ void CommandImageInsertText::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Image File Name", FileFilters::getImageOpenFileFilter()); paramsOut.addFile("Output Image File Name", FileFilters::getImageSaveFileFilter()); paramsOut.addInt("Text X Position", 20); paramsOut.addInt("Text Y Position", 20); paramsOut.addString("Text"); } /** * get full help information. */ QString CommandImageInsertText::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + " \n" + indent9 + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Place the text into an image at the specified location.\n" + indent9 + "The origin is at the bottom left corner of the image.\n" + indent9 + "\n" + indent9 + "The red, green, and blue color components for the text\n" + indent9 + "range from 0 to 255.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandImageInsertText::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Read the parameters // const QString inputImageFileName = parameters->getNextParameterAsString("Input Image File Name"); const QString outputImageFileName = parameters->getNextParameterAsString("Output Image File Name"); const int textPositionX = parameters->getNextParameterAsInt("Text X Position"); const int textPositionY = parameters->getNextParameterAsInt("Text Y Position"); const int textRed = parameters->getNextParameterAsInt("Text Red"); const int textGreen = parameters->getNextParameterAsInt("Text Green"); const int textBlue = parameters->getNextParameterAsInt("Text Blue"); const QString theText = parameters->getNextParameterAsString("Text"); // // Read the image // QImage image; if (image.load(inputImageFileName) == false) { throw CommandException("ERROR reading: " + inputImageFileName); } // // Create a painter and add the text // QPen pen(QColor(textRed, textGreen, textBlue)); QPainter painter(&image); painter.setPen(pen); QFont font; font.setBold(true); font.setPointSize(16); painter.setFont(font); painter.drawText(textPositionX, image.size().height() - textPositionY, theText); // // Save the image // if (image.save(outputImageFileName, 0, 100) == false) { throw CommandException("ERROR writing: " + inputImageFileName); } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandImageFormatConvert.h0000664000175000017500000000373211572067322027031 0ustar michaelmichael #ifndef __COMMAND_IMAGE_FORMAT_CONVERT_H__ #define __COMMAND_IMAGE_FORMAT_CONVERT_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for comparing converting image formats class CommandImageFormatConvert : public CommandBase { public: // constructor CommandImageFormatConvert(); // destructor ~CommandImageFormatConvert(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; // get text displaying supported formats for use by getHelpInformation() static QString getSupportedImageFormatInformation(const int indentation); protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_IMAGE_FORMAT_CONVERT_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandImageFormatConvert.cxx0000664000175000017500000001361111572067322027401 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "CommandImageFormatConvert.h" #include "FileFilters.h" #include "ImageFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandImageFormatConvert::CommandImageFormatConvert() : CommandBase("-image-format-convert", "IMAGE FORMAT CONVERT") { } /** * destructor. */ CommandImageFormatConvert::~CommandImageFormatConvert() { } /** * get the script builder parameters. */ void CommandImageFormatConvert::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { QStringList fileFilters, fileExtensions; FileFilters::getImageSaveFileFilters(fileFilters, fileExtensions); paramsOut.clear(); paramsOut.addFile("Input Image File Name", fileFilters); paramsOut.addFile("Output Image File Name", fileFilters); } /** * get full help information. */ QString CommandImageFormatConvert::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + "\n" + indent9 + "Convert an image to a different image format. This \n" + indent9 + "program determines the format of an image by the file \n" + indent9 + "name's extension.\n" + indent9 + "\n" + getSupportedImageFormatInformation(9) + indent9 + "\n"); return helpInfo; } /** * get text displaying supported formats for use by getHelpInformation(). */ QString CommandImageFormatConvert::getSupportedImageFormatInformation(const int indentation) { // // Length of longest format name // int maxFormatLength = 0; // // Get formats writter // QList writeByteArrayList = QImageWriter::supportedImageFormats(); std::vector writeFormatList; QListIterator writeByteArrayListIterator(writeByteArrayList); while (writeByteArrayListIterator.hasNext()) { const QString format(writeByteArrayListIterator.next()); writeFormatList.push_back(format); maxFormatLength = std::max(maxFormatLength, format.length()); } // // Get formats read // QList readByteArrayList = QImageReader::supportedImageFormats(); std::vector readFormatList; QListIterator readByteArrayListIterator(readByteArrayList); while (readByteArrayListIterator.hasNext()) { const QString format(readByteArrayListIterator.next()); readFormatList.push_back(format); maxFormatLength = std::max(maxFormatLength, format.length()); } // // Get a set of all formats // std::set allFormats; allFormats.insert(readFormatList.begin(), readFormatList.end()); allFormats.insert(writeFormatList.begin(), writeFormatList.end()); // // Get read and write formats // const QString indentString(indentation, ' '); const QString indentString3(indentString + " "); QString formatStringOut; formatStringOut += (indentString + "Supported Image Formats\n"); for (std::set::const_iterator iter = allFormats.begin(); iter != allFormats.end(); iter++) { const QString formatName(*iter); const bool readFlag = (std::find(readFormatList.begin(), readFormatList.end(), formatName) != readFormatList.end()); const bool writeFlag = (std::find(writeFormatList.begin(), writeFormatList.end(), formatName) != writeFormatList.end()); QString s(formatName.leftJustified(maxFormatLength + 2, ' ')); if (readFlag) { s += "READ "; } else { s += " "; } if (writeFlag) { s += "WRITE "; } else { s += " "; } s += "\n"; formatStringOut += (indentString3 + s); } return formatStringOut; } /** * execute the command. */ void CommandImageFormatConvert::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the parameters // const QString inputImageFileName = parameters->getNextParameterAsString("Input Image File Name"); const QString outputImageFileName = parameters->getNextParameterAsString("Output Image File Name"); checkForExcessiveParameters(); // // Read the image // ImageFile imageFile; imageFile.readFile(inputImageFileName); // // Write the image // imageFile.writeFile(outputImageFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandImageCompare.h0000664000175000017500000000341211572067322025621 0ustar michaelmichael #ifndef __COMMAND_IMAGE_COMPARE_H__ #define __COMMAND_IMAGE_COMPARE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for comparing images pixel by pixel class CommandImageCompare : public CommandBase { public: // constructor CommandImageCompare(); // destructor ~CommandImageCompare(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_IMAGE_COMPARE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandImageCompare.cxx0000664000175000017500000001077711572067322026210 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "CommandImageCompare.h" #include "FileFilters.h" #include "FileUtilities.h" #include "ImageFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandImageCompare::CommandImageCompare() : CommandBase("-image-compare", "IMAGE COMPARE") { } /** * destructor. */ CommandImageCompare::~CommandImageCompare() { } /** * get the script builder parameters. */ void CommandImageCompare::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { QStringList fileFilters, fileExtensions; FileFilters::getImageSaveFileFilters(fileFilters, fileExtensions); paramsOut.clear(); paramsOut.addFile("Image File Name 1", fileFilters); paramsOut.addFile("Image File Name 2", fileFilters); paramsOut.addVariableListOfParameters("Options"); } /** * get full help information. */ QString CommandImageCompare::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + "[-tol pixel-tolerance] \n" + indent9 + "\n" + indent9 + "Compare two image files to determine if the pixels are\n" + indent9 + "different. The default value for \"pixel-tolerance\" \n" + indent9 + "is zero, in which cse the pixels must match exactly.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandImageCompare::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the parameters // const QString imageFileName1 = parameters->getNextParameterAsString("Image File Name 1"); const QString imageFileName2 = parameters->getNextParameterAsString("Image File Name 2"); float pixelTolerance = 0.0; while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("Optional parameter"); if (paramName == "-tol") { pixelTolerance = parameters->getNextParameterAsFloat("Pixel Tolerance"); } else { throw CommandException("Unrecognized parameter = \"" + paramName + "\"."); } } // // Make sure that are no more parameters // checkForExcessiveParameters(); // // Read the images // ImageFile imageFile1, imageFile2; imageFile1.readFile(imageFileName1); imageFile2.readFile(imageFileName2); // // Compare the images // QString comparisonMessage; const bool theSame = imageFile1.compareFileForUnitTesting(&imageFile2, pixelTolerance, comparisonMessage); std::cout << "IMAGE COMPARISON for " << FileUtilities::basename(imageFileName1).toAscii().constData() << " and " << FileUtilities::basename(imageFileName2).toAscii().constData() << " "; if (theSame) { std::cout << "successful." << std::endl; } else { std::cout << "FAILED." << std::endl; std::cout << " " << comparisonMessage.toAscii().constData() << std::endl; throw CommandException(""); } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandImageCombine.h0000664000175000017500000000355311572067322025615 0ustar michaelmichael #ifndef __COMMAND_IMAGE_COMBINE_H__ #define __COMMAND_IMAGE_COMBINE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandImageCombine : public CommandBase { public: // constructor CommandImageCombine(); // destructor ~CommandImageCombine(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; /// command requires GUI flag sent to QApplication to be true virtual bool getHasGUI() const { return true; } protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_IMAGE_COMBINE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandImageCombine.cxx0000664000175000017500000001070711572067322026167 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainSet.h" #include "CommandImageCombine.h" #include "FileFilters.h" #include "ImageFile.h" #include "PreferencesFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandImageCombine::CommandImageCombine() : CommandBase("-image-combine", "IMAGE COMBINE") { } /** * destructor. */ CommandImageCombine::~CommandImageCombine() { } /** * get the script builder parameters. */ void CommandImageCombine::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addInt("Number of Images Per Row", 2); paramsOut.addFile("Output Image File Name", FileFilters::getImageSaveFileFilter()); paramsOut.addFile("Input Image 1 File Name", FileFilters::getImageOpenFileFilter()); paramsOut.addVariableListOfParameters("Additional Image Files"); } /** * get full help information. */ QString CommandImageCombine::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[additional-image-file-names]\n" + indent9 + "\n" + indent9 + "Combine images into a single image.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandImageCombine::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the input parameters // const int numberOfImagesPerRow = parameters->getNextParameterAsInt("Number of Images Per Row"); const QString outputImageFileName = parameters->getNextParameterAsString("Output Image File Name"); std::vector imageFileNames; imageFileNames.push_back( parameters->getNextParameterAsString("Input Image File 1 Name")); while (parameters->getParametersAvailable()) { imageFileNames.push_back( parameters->getNextParameterAsString("Input Image File Name")); } // // Read the images // std::vector images; for (unsigned int i = 0; i < imageFileNames.size(); i++) { QImage image; if (image.load(imageFileNames[i]) == false) { throw CommandException("ERROR reading: " + imageFileNames[i]); } images.push_back(image); } // // Get background color // BrainSet brainSet; const PreferencesFile* pf = brainSet.getPreferencesFile(); unsigned char r, g, b; pf->getSurfaceBackgroundColor(r, g, b); const int backgroundColor[3] = { r, b, b }; // // Combine the images // QImage outputImage; ImageFile::combinePreservingAspectAndFillIfNeeded(images, numberOfImagesPerRow, backgroundColor, outputImage); // // Write the output image // if (outputImage.save(outputImageFileName, 0, 100) == false) { throw CommandException("ERROR writing: " + outputImageFileName); } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandHelpSearch.h0000664000175000017500000000333611572067322025313 0ustar michaelmichael #ifndef __COMMAND_HELP_SEARCH_H__ #define __COMMAND_HELP_SEARCH_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandHelpSearch : public CommandBase { public: // constructor CommandHelpSearch(); // destructor ~CommandHelpSearch(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_HELP_SEARCH_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandHelpSearch.cxx0000664000175000017500000000645511572067322025673 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandHelp.h" #include "CommandHelpSearch.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandHelpSearch::CommandHelpSearch() : CommandBase("-help-search", "HELP SEARCH") { } /** * destructor. */ CommandHelpSearch::~CommandHelpSearch() { } /** * get the script builder parameters. */ void CommandHelpSearch::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addVariableListOfParameters("Search Keywords"); } /** * get full help information. */ QString CommandHelpSearch::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + " Search Help Information.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandHelpSearch::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Store the commands // std::vector commands; CommandBase::getAllCommandsSortedBySwitch(commands); // // Set the parameters for each command since needed for help // const int numCommands = static_cast(commands.size()); for (int i = 0; i < numCommands; i++) { commands[i]->setParameters(parameters); } std::vector keywords; while (parameters->getParametersAvailable()) { keywords.push_back(parameters->getNextParameterAsString("Keywords").toLower()); } const int numKeywords = static_cast(keywords.size()); if (numKeywords <= 0) { throw CommandException("Keywords are missing."); } // // Loop through the commands // for (int i = 0; i < numCommands; i++) { // // Get the command // CommandBase* command = commands[i]; const QString text = command->getHelpInformation().toLower(); for (int j = 0; j < numKeywords; j++) { if (text.indexOf(keywords[j]) >= 0) { CommandHelp::printCommandShortHelpInformation(command); break; } } } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandHelpPDF.h0000664000175000017500000001007211572067322024512 0ustar michaelmichael #ifndef __COMMAND_HELP_PDF_H__ #define __COMMAND_HELP_PDF_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "CommandBase.h" class QFont; class QPainter; class QPrinter; /// class for printing help as PDF /// taken from C++ GUI Programming with QT by Blanchette and Summerfield class CommandHelpPDF : public CommandBase { public: // constructor CommandHelpPDF(); // destructor ~CommandHelpPDF(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; /// command requires GUI flag sent to QApplication to be true virtual bool getHasGUI() const { return true; } protected: // info about command class CommandInfo { public: // the commands help pages QList helpPages; // the page number int pageNumber; // the command CommandBase* command; }; // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); // convert lines of text to pages void createPages(QPainter& painter, QFont& font, const QStringList& textLines, QList& pagesOut) const; // create the command table of contents page void createTableOfContentsPages(QPainter& painter, QFont& font, QList& pagesOut); // create the title page void createTitlePage(QPainter& painter, QFont& font, QList& pagesOut) const; // create the info page void createInfoPage(QPainter& painter, QFont& font, QList& pagesOut) const; // print pages of text void printPages(QPrinter& printer, QPainter& painter, QFont& font, const QList& pages, int& pageNumberInOut, const bool alignCenterFlag = false) const; // get height of text int getTextHeight(QPainter& painter, const QString& text) const; // get width of text int getTextWidth(QPainter& painter, const QString& text) const; /// the command info std::vector commandInfo; /// large gap for pages int largeGapSize; /// small gap for pages int smallGapSize; /// width of page int pageWidth; /// height of page int pageHeight; }; #endif // __COMMAND_HELP_PDF_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandHelpPDF.cxx0000664000175000017500000003145611572067322025076 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include "CaretVersion.h" #include "CommandHelpPDF.h" #include "DateAndTime.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandHelpPDF::CommandHelpPDF() : CommandBase("-help-pdf", "HELP WRITE TO PDF FILE") { // // page gaps // largeGapSize = 12; smallGapSize = 4; } /** * destructor. */ CommandHelpPDF::~CommandHelpPDF() { } /** * get the script builder parameters. */ void CommandHelpPDF::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Output PDF File Name", FileFilters::getPDFFileFilter()); } /** * get full help information. */ QString CommandHelpPDF::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Print the help information to a PDF file.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandHelpPDF::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Store the commands // std::vector commands; CommandBase::getAllCommandsSortedBySwitch(commands); const int numCommands = static_cast(commands.size()); if (numCommands <= 0) { return; } // // Get name of output file // const QString pdfFileExtension(".pdf"); QString pdfFileName = parameters->getNextParameterAsString("PDF File Name"); if (pdfFileName.endsWith(pdfFileExtension) == false) { pdfFileName += pdfFileExtension; } // // Create a printer and painter // QPrinter printer(QPrinter::HighResolution); printer.setOutputFileName(pdfFileName); printer.setOutputFormat(QPrinter::PdfFormat); QPainter painter; painter.begin(&printer); // // page sizes // pageHeight = painter.window().height() - 2 * largeGapSize; pageWidth = painter.window().width() - 2 * smallGapSize; // // Title page font // QFont titlePageFont("Times", 24, QFont::Bold); painter.setFont(titlePageFont); // // Font for text // QFont font("Times", 14, QFont::Normal); painter.setFont(font); // // Create the command help pages and set each commands page offset // commandInfo.resize(numCommands); for (int i = 0; i < numCommands; i++) { createPages(painter, font, commands[i]->getHelpInformation().split('\n'), commandInfo[i].helpPages); if (i == 0) { commandInfo[i].pageNumber = 0; } else { commandInfo[i].pageNumber = (commandInfo[i - 1].pageNumber + commandInfo[i - 1].helpPages.count()); } commandInfo[i].command = commands[i]; } // // page offset for commands // int pageOffset = 1; // // Create the title pages // QList titlePages; createTitlePage(painter, titlePageFont, titlePages); pageOffset += titlePages.count(); // // Create the info pages // QList infoPages; createInfoPage(painter, font, infoPages); pageOffset += infoPages.count(); // // Create the table of contents pages // only to determine the number of pages // QList tableOfContentsPages; createTableOfContentsPages(painter, font, tableOfContentsPages); pageOffset += tableOfContentsPages.count(); // // Update the page numbers of the command help pages // for (int i = 0; i < numCommands; i++) { commandInfo[i].pageNumber += pageOffset; } // // Create the table of contents pages AGAIN // but this time the page numbers of the commands // will be correct // createTableOfContentsPages(painter, font, tableOfContentsPages); // // Page number counter // int pageNumber = 1; // // Print the title pages // printPages(printer, painter, titlePageFont, titlePages, pageNumber, true); // // Print the info pages // printPages(printer, painter, font, infoPages, pageNumber); // // Print the table of contents // printPages(printer, painter, font, tableOfContentsPages, pageNumber); // // Print the command help pages // for (int i = 0; i < numCommands; i++) { printPages(printer, painter, font, commandInfo[i].helpPages, pageNumber); } painter.end(); } /** * print pages of text. */ void CommandHelpPDF::printPages(QPrinter& printer, QPainter& painter, QFont& font, const QList& pages, int& pageNumberInOut, const bool alignCenterFlag) const { // // Set the font // painter.setFont(font); // // Width of half a page // const int halfPageWidth = (pageWidth + smallGapSize * 2) / 2; // // Loop through the pages // for (int i = 0; i < pages.count(); i++) { // // Y coord of page // int pageY = largeGapSize; // // Get a page // const QStringList page = pages.at(i); // // Loop through lines of text in page // for (int j = 0; j < page.count(); j++) { // // Get the line of text // const QString text = page.at(j); // // Height of text // const int textHeight = getTextHeight(painter, text); // // is text being centered // int pageX = smallGapSize; if (alignCenterFlag) { const int textWidth = getTextWidth(painter, text); pageX = halfPageWidth - (textWidth / 2); } // // Print the text // painter.drawText(pageX, pageY, text); pageY += textHeight; } // // print the page number // if (pageNumberInOut > 1) { painter.drawText(painter.window(), Qt::AlignHCenter | Qt::AlignBottom, QString::number(pageNumberInOut)); } // // New page // printer.newPage(); pageNumberInOut++; } } /** * create the title page. */ void CommandHelpPDF::createTitlePage(QPainter& painter, QFont& font, QList& pagesOut) const { pagesOut.clear(); QStringList titlePageText; titlePageText << "Caret Command Manual"; titlePageText << ("Version " + CaretVersion::getCaretVersionAsString()); titlePageText << ("Date Printed " + DateAndTime::getDateAndTimeAsString()); titlePageText << " "; titlePageText << "John Harwell, Heather A. Drury, Donna Dierker,"; titlePageText << "and David C. Van Essen"; titlePageText << " "; titlePageText << "Washington University School of Medicine"; titlePageText << "Department of Anatomy and Neurobiology"; titlePageText << "660 S. Euclid Ave"; titlePageText << "Saint Louis, Missouri 63110"; titlePageText << ("Copyright 1995-" + QDateTime::currentDateTime().toString("yyyy") + " Washington University"); titlePageText << " "; titlePageText << "http://brainmap.wustl.edu/caret"; // // Create the title pages // createPages(painter, font, titlePageText, pagesOut); } /** * create the info page. */ void CommandHelpPDF::createInfoPage(QPainter& painter, QFont& font, QList& pagesOut) const { pagesOut.clear(); QStringList infoPageText = getGeneralHelpInformation().split('\n'); createPages(painter, font, infoPageText, pagesOut); } /** * create the command table of contents page. */ void CommandHelpPDF::createTableOfContentsPages(QPainter& painter, QFont& font, QList& pagesOut) { // // Get the lines for the table of contents // QStringList tocLines; const int numCommands = static_cast(commandInfo.size()); for (int i = 0; i < numCommands; i++) { tocLines << (QString::number(commandInfo[i].pageNumber).leftJustified(7, '.') + commandInfo[i].command->getShortDescription()); } // // Create the table of contents pages // createPages(painter, font, tocLines, pagesOut); } /** * convert lines of text into pages */ void CommandHelpPDF::createPages(QPainter& painter, QFont& font, const QStringList& textLines, QList& pagesOut) const { pagesOut.clear(); // // Font used for printing command information // painter.setFont(font); // // Start a new page // int pageY = largeGapSize; QStringList currentPage; // // loop through the lines of text // for (int i = 0; i < textLines.count(); i++) { // // get a line of the text // const QString text = textLines.at(i); // // Get height of the line // const int textHeight = getTextHeight(painter, text); // // Is new page needed // if (((pageY + textHeight) > pageHeight) && (currentPage.empty() == false)) { pagesOut.append(currentPage); currentPage.clear(); pageY = largeGapSize; } // // Add text to current page // currentPage.append(text); pageY += textHeight; } // // Don't forget last page // if (currentPage.empty() == false) { pagesOut.append(currentPage); } } /** * get height of text. */ int CommandHelpPDF::getTextHeight(QPainter& painter, const QString& text) const { // // Get height of the line // const QRect textSizeRect = painter.boundingRect(0, 0, pageWidth, pageHeight, Qt::TextSingleLine, text); const int textHeight = textSizeRect.height() + 2 * smallGapSize; return textHeight; } /** * get width of text. */ int CommandHelpPDF::getTextWidth(QPainter& painter, const QString& text) const { // // Get height of the line // const QRect textSizeRect = painter.boundingRect(0, 0, pageWidth, pageHeight, Qt::TextSingleLine, text); const int textHeight = textSizeRect.width(); return textHeight; } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandHelpHTML.h0000664000175000017500000000351511572067322024651 0ustar michaelmichael #ifndef __COMMAND_HELP_HTML_H__ #define __COMMAND_HELP_HTML_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandHelpHTML : public CommandBase { public: // constructor CommandHelpHTML(); // destructor ~CommandHelpHTML(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); // convert a string to HTML QString convertToHTML(const QString& s) const; }; #endif // __COMMAND_HELP_HTML_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandHelpHTML.cxx0000664000175000017500000001220111572067322025214 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CaretVersion.h" #include "CommandHelpHTML.h" #include "DateAndTime.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "TextFile.h" /** * constructor. */ CommandHelpHTML::CommandHelpHTML() : CommandBase("-help-html", "HELP WRITE TO HTML FILE") { } /** * destructor. */ CommandHelpHTML::~CommandHelpHTML() { } /** * get the script builder parameters. */ void CommandHelpHTML::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Output HTML File Name", FileFilters::getHTMLFileFilter()); } /** * get full help information. */ QString CommandHelpHTML::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + " Print the help information to an HTML file.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandHelpHTML::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Store the commands // std::vector commands; CommandBase::getAllCommandsSortedBySwitch(commands); const int numCommands = static_cast(commands.size()); // // Get name of output file // const QString htmlFileExtension(".html"); QString htmlFileName = parameters->getNextParameterAsString("PDF File Name"); if (htmlFileName.endsWith(htmlFileExtension) == false) { htmlFileName += htmlFileExtension; } TextFile htmlFile; htmlFile.appendLine(""); htmlFile.appendLine(""); htmlFile.appendLine(""); htmlFile.appendLine("Caret Command Help"); htmlFile.appendLine(""); htmlFile.appendLine("

Caret Command Manual

"); htmlFile.appendLine("

Version " + CaretVersion::getCaretVersionAsString() + "

"); htmlFile.appendLine("

Date Printed " + DateAndTime::getDateAndTimeAsString() + "

"); htmlFile.appendLine("

"); htmlFile.appendLine("

"); htmlFile.appendText(convertToHTML(getGeneralHelpInformation())); if (numCommands > 0) { std::vector anchorNames(numCommands, ""); for (int i = 0; i < numCommands; i++) { const CommandBase* command = commands[i]; const QString anchorName = command->getShortDescription().replace(' ', '_'); anchorNames[i] = anchorName; htmlFile.appendText("" + command->getShortDescription() + "

"); } for (int i = 0; i < numCommands; i++) { if (i > 0) { htmlFile.appendLine(""); } const CommandBase* command = commands[i]; QString htmlString = convertToHTML(command->getHelpInformation()); /* htmlString = htmlString.replace(' ', " "); htmlString = htmlString.replace('<', "<"); htmlString = htmlString.replace('>', ">"); htmlString = htmlString.replace("\n", "

"); // do after less than/greater than conversion */ htmlFile.appendText("" + htmlString); } } htmlFile.appendLine(""); htmlFile.appendLine(""); htmlFile.writeFile(htmlFileName); } /** * convert a string to HTML. */ QString CommandHelpHTML::convertToHTML(const QString& sin) const { QString s = sin; s = s.replace(' ', " "); s = s.replace('<', "<"); s = s.replace('>', ">"); s = s.replace('\n', "
"); // do after less than/greater than conversion return s; } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandHelpGlobalOptions.h0000664000175000017500000000536711572067322026670 0ustar michaelmichael #ifndef __COMMAND_HELP_GLOBAL_OPTIONS_H__ #define __COMMAND_HELP_GLOBAL_OPTIONS_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandHelpGlobalOptions : public CommandBase { public: // constructor CommandHelpGlobalOptions(); // destructor ~CommandHelpGlobalOptions(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; /// command has no parameters virtual bool commandHasNoParameters() const { return true; } // process global options static void processGlobalOptions(ProgramParameters& params) throw (CommandException); protected: // process the change directory command static void processChangeDirectoryCommand(ProgramParameters& params) throw (CommandException); // process the change permissions command static void processSetPermissionsCommand(ProgramParameters& params) throw (CommandException); // process the set random seed static void processSetRandomSeedCommand(ProgramParameters& params) throw (CommandException); // process the file writing format preference static void processFileWritingFormat(ProgramParameters& params) throw (CommandException); // process the METRIC file writing format preference static void processMetricFileWritingFormat(ProgramParameters& params) throw (CommandException); // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_HELP_GLOBAL_OPTIONS_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandHelpGlobalOptions.cxx0000664000175000017500000003431211572067322027233 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include "AbstractFile.h" #include "BrainSet.h" #include "CommandHelpGlobalOptions.h" #include "FileFilters.h" #include "MetricFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandHelpGlobalOptions::CommandHelpGlobalOptions() : CommandBase("-help-global-options", "HELP GLOBAL OPTIONS") { } /** * destructor. */ CommandHelpGlobalOptions::~CommandHelpGlobalOptions() { } /** * get the script builder parameters. */ void CommandHelpGlobalOptions::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); } /** * get full help information. */ QString CommandHelpGlobalOptions::getHelpInformation() const { std::vector fileFormats; std::vector fileFormatNames; AbstractFile::getFileFormatTypesAndNames(fileFormats, fileFormatNames); QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "These options may be specified anywhere AFTER the command's\n" + indent9 + "operation. In other words, these options cannot immediately\n" + indent9 + "follow the program's name.\n" + indent9 + "\n" + indent9 + "Adding the parameter \"-CHDIR \" to \n" + indent9 + "the command will result in the command running from \n" + indent9 + "that directory. This parameter does not affect the \n" + indent9 + "current directory in the shell that executes the \n" + indent9 + "command.\n" + indent9 + "\n" + indent9 + "Adding the parameter \"-CHMOD \" to the \n" + indent9 + "command will result in all files written by the command\n" + indent9 + "receiving the specified permissions. \"permissions\"\n" + indent9 + "is a list of one or more of the following values separated \n" + indent9 + "by commas:\n" + indent9 + " UR - user read\n" + indent9 + " UW - user write\n" + indent9 + " UX - user execute\n" + indent9 + " GR - group read\n" + indent9 + " GW - group write\n" + indent9 + " GX - group execute\n" + indent9 + " AR - all read\n" + indent9 + " AW - all write\n" + indent9 + " AX - all execute\n" + indent9 + "\n" + indent9 + "Adding the parameter \"-RANDOMSEED \" to \n" + indent9 + "the command will result in the random number generator's \n" + indent9 + "seed value being set to the provided value. \n" + indent9 + "\n" + indent9 + "Adding the parameter \"-WRITE-FILE-FORMAT \"\n" + indent9 + "to the command will set the format(s) for writing data\n" + indent9 + "files. \"format-types\" are any of the file format types\n" + indent9 + "listed below and multiple file formats are allowed but must\n" + indent9 + "be separated by a colon.\n" + indent9 + "\n" + indent9 + "Adding the parameter \"-WRITE-FILE-FORMAT-METRIC \"\n" + indent9 + "sets the format for writing metric files. One and only one\n" + indent9 + "format must be specified.\n" + indent9 + "\n" + indent9 + "Available file formats are:\n"); for (unsigned int i = 0; i < fileFormatNames.size(); i++) { helpInfo += (indent9 + " " + fileFormatNames[i] + "\n"); } helpInfo += ("" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandHelpGlobalOptions::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { std::cout << getHelpInformation().toAscii().constData() << std::endl; } /** * process global options. */ void CommandHelpGlobalOptions::processGlobalOptions(ProgramParameters& params) throw (CommandException) { processChangeDirectoryCommand(params); processSetPermissionsCommand(params); processSetRandomSeedCommand(params); processFileWritingFormat(params); processMetricFileWritingFormat(params); } /** * process the change directory command. */ void CommandHelpGlobalOptions::processChangeDirectoryCommand(ProgramParameters& params) throw (CommandException) { // // See if directory should be changed // const int chdirIndex = params.getIndexOfParameterWithValue("-CHDIR"); if (chdirIndex >= 0) { const int dirNameIndex = chdirIndex + 1; if (dirNameIndex < params.getNumberOfParameters()) { const QString directoryName = params.getParameterAtIndex(dirNameIndex); if (directoryName.isEmpty() == false) { // // Is specified directory valid? // QDir dir(directoryName); if (dir.exists() == false) { throw CommandException("ERROR: Directory for -CHDIR \"" + directoryName + "\" is invalid."); } // // Change to the specified directory // QDir::setCurrent(directoryName); } // // Remove the "-CHDIR" and directory name parameters // Remember, remove largest index first since array shrinks // params.removeParameterAtIndex(dirNameIndex); params.removeParameterAtIndex(chdirIndex); } else { throw CommandException("ERROR: Directory name missing for \"-CHDIR\" option."); } } } /** * process the change permissions command. */ void CommandHelpGlobalOptions::processSetPermissionsCommand(ProgramParameters& params) throw (CommandException) { // // See if output file permissions should be set // const int chmodIndex = params.getIndexOfParameterWithValue("-CHMOD"); if (chmodIndex >= 0) { const int modeIndex = chmodIndex + 1; if (modeIndex < params.getNumberOfParameters()) { const QString modeName = params.getParameterAtIndex(modeIndex); if (modeName.isEmpty() == false) { QFile::Permissions permissions; QStringList modes = modeName.split(','); for (int m = 0; m < modes.size(); m++) { const QString md = modes.at(m); if (md == "UR") { permissions |= QFile::ReadOwner; permissions |= QFile::ReadUser; } else if (md == "UW") { permissions |= QFile::WriteOwner; permissions |= QFile::WriteUser; } else if (md == "UX") { permissions |= QFile::ExeOwner; permissions |= QFile::ExeUser; } else if (md == "GR") { permissions |= QFile::ReadGroup; } else if (md == "GW") { permissions |= QFile::WriteGroup; } else if (md == "GX") { permissions |= QFile::ExeGroup; } else if (md == "AR") { permissions |= QFile::ReadOther; } else if (md == "AW") { permissions |= QFile::WriteOther; } else if (md == "AX") { permissions |= QFile::ExeOther; } else { throw CommandException("ERROR: Unrecognzied permission \"" + md + "\" for -CHMOD option."); } } AbstractFile::setFileWritePermissions(permissions); } // // Remove the "-CHMOD" and mode name parameters // Remember, remove largest index first since array shrinks // params.removeParameterAtIndex(modeIndex); params.removeParameterAtIndex(chmodIndex); } else { throw CommandException("ERROR: Mode missing for \"-CHMOD\" option."); } } } /** * process the set random seed. */ void CommandHelpGlobalOptions::processSetRandomSeedCommand(ProgramParameters& params) throw (CommandException) { // // See if seed should be set // const int randomSeedIndex = params.getIndexOfParameterWithValue("-RANDOMSEED"); if (randomSeedIndex >= 0) { const int seedIndex = randomSeedIndex + 1; if (seedIndex < params.getNumberOfParameters()) { const QString seedValueString = params.getParameterAtIndex(seedIndex); if (seedValueString.isEmpty() == false) { bool ok = false; const unsigned int seedValue = seedValueString.toUInt(&ok); if (ok == false) { throw CommandException("Invalid random seed value (" + seedValueString + ")"); } BrainSet::setRandomSeed(seedValue); } // // Remove the "-RANDOMSEED" and mode name parameters // Remember, remove largest index first since array shrinks // params.removeParameterAtIndex(seedIndex); params.removeParameterAtIndex(randomSeedIndex); } else { throw CommandException("ERROR: Value missing for \"-RANDOMSEED\" option."); } } } /** * process the file writing format preference. */ void CommandHelpGlobalOptions::processFileWritingFormat(ProgramParameters& params) throw (CommandException) { // // See if file format write preference should set // const int fileFormatIndex = params.getIndexOfParameterWithValue("-WRITE-FILE-FORMAT"); if (fileFormatIndex >= 0) { const int typesIndex = fileFormatIndex + 1; if (typesIndex < params.getNumberOfParameters()) { const QString typesValueString = params.getParameterAtIndex(typesIndex); if (typesValueString.isEmpty() == false) { std::vector formatList; const QStringList sl = typesValueString.split(':', QString::SkipEmptyParts); for (int i = 0; i < sl.count(); i++) { bool validFlag = false; const AbstractFile::FILE_FORMAT formatType = AbstractFile::convertFormatNameToType(sl.at(i), &validFlag); if (validFlag) { formatList.push_back(formatType); } else { throw CommandException("ERROR: Unrecognized file format data type " + sl.at(i) + " for \"-WRITE-FILE-FORMAT\" option."); } } if (formatList.empty() == false) { AbstractFile::setPreferredWriteTypeCaretCommand(formatList); } } // // Remove the "-WRITE-FILE-FORMAT" and format name parameters // Remember, remove largest index first since array shrinks // params.removeParameterAtIndex(typesIndex); params.removeParameterAtIndex(fileFormatIndex); } else { throw CommandException("ERROR: Value missing for \"-WRITE-FILE-FORMAT\" option."); } } } /** * process the METRIC file writing format preference. */ void CommandHelpGlobalOptions::processMetricFileWritingFormat(ProgramParameters& params) throw (CommandException) { MetricFile mf; // // See if file format write preference should set // const int fileFormatIndex = params.getIndexOfParameterWithValue("-WRITE-FILE-FORMAT-METRIC"); if (fileFormatIndex >= 0) { const int typeIndex = fileFormatIndex + 1; if (typeIndex < params.getNumberOfParameters()) { const QString typeValueString = params.getParameterAtIndex(typeIndex); if (typeValueString.isEmpty() == false) { bool validFlag = false; const AbstractFile::FILE_FORMAT format = AbstractFile::convertFormatNameToType(typeValueString, &validFlag); if (validFlag) { if (mf.getCanWrite(format)) { AbstractFile::setPreferredMetricWriteTypeCaretCommand(format); } else { throw CommandException("ERROR: Metric file cannot write format data type " + typeValueString + " for \"-WRITE-FILE-FORMAT-METRIC\" option."); } } else { throw CommandException("ERROR: Unrecognized file format data type " + typeValueString + " for \"-WRITE-FILE-FORMAT-METRIC\" option."); } } // // Remove the "-WRITE-FILE-FORMAT" and format name parameters // Remember, remove largest index first since array shrinks // params.removeParameterAtIndex(typeIndex); params.removeParameterAtIndex(fileFormatIndex); } else { throw CommandException("ERROR: Value missing for \"-WRITE-FILE-FORMAT-METRIC\" option."); } } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandHelpFull.h0000664000175000017500000000347211572067322025011 0ustar michaelmichael #ifndef __COMMAND_HELP_FULL_H__ #define __COMMAND_HELP_FULL_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandHelpFull : public CommandBase { public: // constructor CommandHelpFull(); // destructor ~CommandHelpFull(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; /// command has no parameters virtual bool commandHasNoParameters() const { return true; } protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_HELP_FULL_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandHelpFull.cxx0000664000175000017500000000567211572067322025370 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "CommandHelp.h" #include "CommandHelpFull.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandHelpFull::CommandHelpFull() : CommandBase("-help-full", "HELP FULL INFORMATION") { } /** * destructor. */ CommandHelpFull::~CommandHelpFull() { } /** * get the script builder parameters. */ void CommandHelpFull::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); } /** * get full help information. */ QString CommandHelpFull::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + " Show full help information.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandHelpFull::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Store the commands // std::vector commands; CommandBase::getAllCommandsSortedBySwitch(commands); std::cout << getGeneralHelpInformation().toAscii().constData() << std::endl; // // Loop through the commands // const int numCommands = static_cast(commands.size()); for (int i = 0; i < numCommands; i++) { // // Get the command // CommandBase* command = commands[i]; // // Print the help information // std::cout << "------------------------------------------------------------------------------" << std::endl; CommandHelp::printCommandLongHelpInformation(command); } if (numCommands > 0) { std::cout << "------------------------------------------------------------------------------" << std::endl; } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandHelp.h0000664000175000017500000000403111572067322024156 0ustar michaelmichael #ifndef __COMMAND_HELP_H__ #define __COMMAND_HELP_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandHelp : public CommandBase { public: // constructor CommandHelp(); // destructor ~CommandHelp(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; /// command has no parameters virtual bool commandHasNoParameters() const { return true; } /// print short help information static void printCommandShortHelpInformation(const CommandBase* command); /// print long help information static void printCommandLongHelpInformation(const CommandBase* command); protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_HELP_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandHelp.cxx0000664000175000017500000001075711572067322024545 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "CommandHelp.h" #include "CommandHelpGlobalOptions.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandHelp::CommandHelp() : CommandBase("-help", "HELP") { } /** * destructor. */ CommandHelp::~CommandHelp() { } /** * get the script builder parameters. */ void CommandHelp::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); } /** * get full help information. */ QString CommandHelp::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + " Show help information.\n" + indent9 + "\n"); return helpInfo; } /** * print short help information. */ void CommandHelp::printCommandShortHelpInformation(const CommandBase* command) { std::cout << " " << command->getShortDescription().toAscii().constData() << " " << command->getOperationSwitch().toAscii().constData() << std::endl; } /** * print long help information. */ void CommandHelp::printCommandLongHelpInformation(const CommandBase* command) { std::cout << command->getHelpInformation().toAscii().constData(); CommandHelpGlobalOptions hgo; const QString moreHelp = (indent9 + "Run \"" + QApplication::applicationName() + " " + hgo.getOperationSwitch() + "\"\n" + indent9 + " for parameters available to all commands.\n" + "\n"); /* const QString moreHelp = (indent9 + "Adding the parameter \"-CHDIR \" to \n" + indent9 + "the command will result in the command running from \n" + indent9 + "that directory. This parameter does not affect the \n" + indent9 + "current directory in the shell that executes the \n" + indent9 + "command.\n" + indent9 + "\n" + indent9 + "Adding the parameter \"-CHMOD \" to the \n" + indent9 + "command will result in all files written by the command\n" + indent9 + "receiving the specified permissions. \"permissions\"\n" + indent9 + "is a list of one or move of the following values separated \n" + indent9 + "by commas:\n" + indent9 + " UR - user read\n" + indent9 + " UW - user write\n" + indent9 + " UX - user execute\n" + indent9 + " GR - group read\n" + indent9 + " GW - group write\n" + indent9 + " GX - group execute\n" + indent9 + " AR - all read\n" + indent9 + " AW - all write\n" + indent9 + " AX - all execute\n" + indent9 + "\n"); */ std::cout << moreHelp.toAscii().constData(); } /** * execute the command. */ void CommandHelp::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Store the commands // std::vector commands; CommandBase::getAllCommandsSortedBySwitch(commands); // // Loop through the commands // const int numCommands = static_cast(commands.size()); for (int i = 0; i < numCommands; i++) { // // Print the command's help information // printCommandShortHelpInformation(commands[i]); } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandGiftiInfo.h0000664000175000017500000000366111572067322025154 0ustar michaelmichael #ifndef __COMMAND_GIFTI_INFO_H__ #define __COMMAND_GIFTI_INFO_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "CommandBase.h" class GiftiMetaData; /// class for class CommandGiftiInfo : public CommandBase { public: // constructor CommandGiftiInfo(); // destructor ~CommandGiftiInfo(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); // print the metadata void printMetaData(std::ostream& outStream, const QString& indent, const GiftiMetaData* md); }; #endif // __COMMAND_GIFTI_INFO_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandGiftiInfo.cxx0000664000175000017500000001611111572067322025521 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "CommandGiftiInfo.h" #include "FileFilters.h" #include "GiftiDataArrayFile.h" #include "GiftiMetaData.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandGiftiInfo::CommandGiftiInfo() : CommandBase("-gifti-info", "GIFTI INFO") { } /** * destructor. */ CommandGiftiInfo::~CommandGiftiInfo() { } /** * get the script builder parameters. */ void CommandGiftiInfo::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addMultipleFiles("GIFTI Files", FileFilters::getAnyFileFilter()); } /** * get full help information. */ QString CommandGiftiInfo::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " \n" + indent9 + "\n" + indent9 + "Display the GIFTI file's information and metadata.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandGiftiInfo::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString indent3(3, QChar(' ')); const QString indent6(6, QChar(' ')); const QString dashes25(25, QChar('-')); const QString dashes75(75, QChar('-')); // // Get the names of the GIFTI files // std::vector fileNames; while (parameters->getParametersAvailable()) { fileNames.push_back(parameters->getNextParameterAsString("GIFTI File Name")); } const int numFiles = static_cast(fileNames.size()); if (numFiles <= 0) { throw CommandException("No GIFTI File Names provided."); } // // Print information about the files // for (int i = 0; i < numFiles; i++) { const QString name(fileNames[i]); // // Print file metadata // std::cout << dashes75.toAscii().constData() << std::endl; std::cout << "Filename: " << fileNames[i].toAscii().constData() << std::endl; try { // // Read the file // GiftiDataArrayFile gifti; //gifti.setReadMetaDataOnlyFlag(true); gifti.readFileMetaDataOnly(name); std::cout << "File Metadata:" << std::endl; printMetaData(std::cout, indent3, gifti.getMetaData()); // // Print info about a data Array // const int numArrays = gifti.getNumberOfDataArrays(); for (int j = 0; j < numArrays; j++) { std::cout << "Data Array " << j + 1 << " " << dashes25.toAscii().constData() << std::endl; GiftiDataArray* gda = gifti.getDataArray(j); std::cout << indent3.toAscii().constData() << "Array Indexing Order: " << GiftiDataArray::getArraySubscriptingOrderName( gda->getArraySubscriptingOrder()).toAscii().constData() << std::endl; std::cout << indent3.toAscii().constData() << "Data Type: " << GiftiDataArray::getDataTypeName( gda->getDataType()).toAscii().constData() << std::endl; std::cout << indent3.toAscii().constData() << "Dimensions: "; const int numDim = gda->getNumberOfDimensions(); for (int id = 0; id < numDim; id++) { if (id > 0) { std::cout << ", "; } std::cout << gda->getDimension(id); } std::cout << std::endl; std::cout << indent3.toAscii().constData() << "Encoding: " << GiftiDataArray::getEncodingName( gda->getEncoding()).toAscii().constData() << std::endl; std::cout << indent3.toAscii().constData() << "Endian: " << GiftiDataArray::getEndianName( gda->getEndian()).toAscii().constData() << std::endl; QString externalFileName; long externalFileOffset = 0; gda->getExternalFileInformation(externalFileName, externalFileOffset); std::cout << indent3.toAscii().constData() << "External File Name: " << externalFileName.toAscii().constData() << std::endl; std::cout << indent3.toAscii().constData() << "External File Offset: " << externalFileOffset << std::endl; std::cout << indent3.toAscii().constData() << "Intent: " << gda->getIntent().toAscii().constData() << std::endl; std::cout << indent3.toAscii().constData() << "Metadata:" << std::endl; printMetaData(std::cout, indent6, gda->getMetaData()); } } catch (FileException& e) { std::cout << e.whatQString().toAscii().constData() << std::endl; } std::cout << std::endl; } } /** * print the metadata. */ void CommandGiftiInfo::printMetaData(std::ostream& outStream, const QString& indent, const GiftiMetaData* md) { std::vector mdNames; md->getAllNames(mdNames); const int num = static_cast(mdNames.size()); for (int i = 0; i < num; i++) { QString value; md->get(mdNames[i], value); outStream << indent.toAscii().constData() << mdNames[i].toAscii().constData() << ": " << value.toAscii().constData() << std::endl; } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandFileSubstitution.h0000664000175000017500000000344211572067322026607 0ustar michaelmichael #ifndef __COMMAND_FILE_SUBSTITUTION_H__ #define __COMMAND_FILE_SUBSTITUTION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for subsituting string(s) in a file class CommandFileSubstitution : public CommandBase { public: // constructor CommandFileSubstitution(); // destructor ~CommandFileSubstitution(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_FILE_SUBSTITUTION_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandFileSubstitution.cxx0000664000175000017500000000776711572067322027200 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandFileSubstitution.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "TextFile.h" /** * constructor. */ CommandFileSubstitution::CommandFileSubstitution() : CommandBase("-file-substitution", "FILE SUBSTITUTION") { } /** * destructor. */ CommandFileSubstitution::~CommandFileSubstitution() { } /** * get the script builder parameters. */ void CommandFileSubstitution::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input File Name", FileFilters::getAnyFileFilter()); paramsOut.addFile("Output File Name", FileFilters::getAnyFileFilter()); paramsOut.addVariableListOfParameters("Substitutions"); } /** * get full help information. */ QString CommandFileSubstitution::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "-s find-text replace-with-text\n" + indent9 + "\n" + indent9 + "Substitute text in a file. Every occurrance of \n" + indent9 + "\"find-text\" is replaced with \"replace-with-text\".\n" + indent9 + "\n" + indent9 + "If either of the text expressions contain spaces, the \n" + indent9 + "text must be enclosed in double quotes.\n" + indent9 + "\n" + indent9 + "Multiple \"-s\" substitution parameters are allowed\n" + indent9 + "\n" + indent9 + "The input and output file names may be the same.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandFileSubstitution::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get file names // const QString inputFileName = parameters->getNextParameterAsString("Input File Name"); const QString outputFileName = parameters->getNextParameterAsString("Output File Name"); // // Open the text file // TextFile tf; tf.readFile(inputFileName); QString text = tf.getText(); // // Loop through parameters // while (parameters->getParametersAvailable()) { const QString param = parameters->getNextParameterAsString("Option"); if (param == "-s") { const QString findText = parameters->getNextParameterAsString("Find Text"); const QString replaceWithText = parameters->getNextParameterAsString("Replace With Text"); text = text.replace(findText, replaceWithText); } else { throw CommandException("Unrecognized parameter " + param); } } // // Add text to file and write the file // tf.setText(text); tf.writeFile(outputFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandFileReadTime.h0000664000175000017500000000423111572067322025562 0ustar michaelmichael #ifndef __COMMAND_FILE_READ_TIME_H__ #define __COMMAND_FILE_READ_TIME_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" class AbstractFile; /// class for class CommandFileReadTime : public CommandBase { public: // constructor CommandFileReadTime(); // destructor ~CommandFileReadTime(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); // read the file for timing purposes void readFileForTiming(AbstractFile* dataFile, const QString& fileName, float& timeToReadOut, float& fileSizeInMBOut); /// iterations of file reading int iterations; /// number of threads int numberOfThreads; }; #endif // __COMMAND_FILE_READ_TIME_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandFileReadTime.cxx0000664000175000017500000002164511572067322026145 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include "BrainSet.h" #include "CommandFileReadTime.h" #include "CoordinateFile.h" #include "BorderProjectionFile.h" #include "FileFilters.h" #include "FileUtilities.h" #include "FociProjectionFile.h" #include "FreeSurferSurfaceFile.h" #include "GiftiDataArrayFile.h" #include "MetricFile.h" #include "PreferencesFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SpecFile.h" #include "SurfaceShapeFile.h" #include "TopologyFile.h" #include "VtkModelFile.h" /** * constructor. */ CommandFileReadTime::CommandFileReadTime() : CommandBase("-file-read-time", "FILE READ TIME") { iterations = 3; numberOfThreads = 1; } /** * destructor. */ CommandFileReadTime::~CommandFileReadTime() { } /** * get the script builder parameters. */ void CommandFileReadTime::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); QStringList filters; filters << FileFilters::getCoordinateGenericFileFilter(); filters << FileFilters::getBorderProjectionFileFilter(); filters << FileFilters::getFociProjectionFileFilter(); filters << FileFilters::getMetricFileFilter(); filters << FileFilters::getSpecFileFilter(); filters << FileFilters::getSurfaceShapeFileFilter(); filters << FileFilters::getTopologyGenericFileFilter(); paramsOut.addFile("File Name", filters); paramsOut.addVariableListOfParameters("File Timing"); } /** * get full help information. */ QString CommandFileReadTime::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "[-iter iterations]\n" + indent9 + "[-threads number-of-threads] \n" + indent9 + "\n" + indent9 + "Time the reading of a caret data file. Not all caret files\n" + indent9 + "are supported for this command.\n" + indent9 + "\n" + indent9 + "The file is read \"iteration\" times and the average of \n" + indent9 + "those times is printed. The default number of iterations\n" + indent9 + "is " + QString::number(iterations) + ". \n" + indent9 + "\n" + indent9 + "File types supported at this time are\n" + indent9 + " Coordinate \n" + indent9 + " Border Projection \n" + indent9 + " Foci Projection \n" + indent9 + " Metric \n" + indent9 + " Spec File \n" + indent9 + " Surface Shape File \n" + indent9 + " Topology File \n" + indent9 + "\n" + indent9 + "The time for a Spec File is the time to read all of the\n" + indent9 + "spec file's data files.\n" + indent9 + "\n" + indent9 + "The number of threads parameter applied only to the \n" + indent9 + "reading of Spec Files. The default number of threads \n" + indent9 + "is " + QString::number(numberOfThreads) + ". \n" + indent9 + "\n"); return helpInfo; } /** * read the file for timing purposes. */ void CommandFileReadTime::readFileForTiming(AbstractFile* dataFile, const QString& fileName, float& timeToReadOut, float& fileSizeInMBOut) { float timeTotal = 0.0; for (int i = 0; i < iterations; i++) { dataFile->readFile(fileName); timeTotal += dataFile->getTimeToReadFileInSeconds(); } timeToReadOut = timeTotal / static_cast(iterations); const float oneMegabyte = 1048576.0; QFileInfo fi(dataFile->getFileName()); fileSizeInMBOut = fi.size() / oneMegabyte; } /** * execute the command. */ void CommandFileReadTime::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the parameters // const QString fileName = parameters->getNextParameterAsString("File Name"); while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("Param Name"); if (paramName == "-iter") { iterations = parameters->getNextParameterAsInt("Iterations"); } else if (paramName == "-threads") { numberOfThreads = parameters->getNextParameterAsInt("Number of Threads"); } else { throw CommandException("Unrecognized parameter: " + paramName); } } const QString fileNameNoPath = FileUtilities::basename(fileName); // // Create a file based upon the file name extension // float timeInSeconds = 0.0; float fileSizeInMB = 0.0; if (fileName.endsWith(SpecFile::getCoordinateFileExtension())) { CoordinateFile cf; readFileForTiming(&cf, fileName, timeInSeconds, fileSizeInMB); } else if (fileName.endsWith(SpecFile::getBorderProjectionFileExtension())) { BorderProjectionFile bpf; readFileForTiming(&bpf, fileName, timeInSeconds, fileSizeInMB); } else if (fileName.endsWith(SpecFile::getFociProjectionFileExtension())) { FociProjectionFile fpf; readFileForTiming(&fpf, fileName, timeInSeconds, fileSizeInMB); } else if (fileName.endsWith(SpecFile::getFreeSurferAsciiSurfaceFileExtension())) { FreeSurferSurfaceFile fs; readFileForTiming(&fs, fileName, timeInSeconds, fileSizeInMB); } else if (fileName.endsWith("fsbin")) { FreeSurferSurfaceFile fs; fs.setFileReadType(AbstractFile::FILE_FORMAT_BINARY); readFileForTiming(&fs, fileName, timeInSeconds, fileSizeInMB); } else if (fileName.endsWith(".func.gii")) { MetricFile mf; readFileForTiming(&mf, fileName, timeInSeconds, fileSizeInMB); } else if (fileName.endsWith(SpecFile::getGiftiGenericFileExtension())) { GiftiDataArrayFile gifti; readFileForTiming(&gifti, fileName, timeInSeconds, fileSizeInMB); } else if (fileName.endsWith(SpecFile::getMetricFileExtension())) { MetricFile mf; readFileForTiming(&mf, fileName, timeInSeconds, fileSizeInMB); } else if (fileName.endsWith(SpecFile::getSpecFileExtension())) { for (int i = 0; i < iterations; i++) { SpecFile sf; sf.readFile(fileName); sf.setAllFileSelections(SpecFile::SPEC_TRUE); BrainSet bs; PreferencesFile* pf = bs.getPreferencesFile(); pf->setNumberOfFileReadingThreads(numberOfThreads); QString errorMessage; QTime timer; timer.start(); bs.readSpecFile(sf, fileName, errorMessage); if (errorMessage.isEmpty() == false) { throw CommandException("Spec File Read error, timing test invalid\n" + errorMessage); } timeInSeconds += (static_cast(timer.elapsed()) / 1000.0); } timeInSeconds /= static_cast(iterations); } else if (fileName.endsWith(SpecFile::getSurfaceShapeFileExtension())) { SurfaceShapeFile ssf; readFileForTiming(&ssf, fileName, timeInSeconds, fileSizeInMB); } else if (fileName.endsWith(SpecFile::getTopoFileExtension())) { TopologyFile tf; readFileForTiming(&tf, fileName, timeInSeconds, fileSizeInMB); } else if (fileName.endsWith(SpecFile::getVtkModelFileExtension())) { VtkModelFile vmf; readFileForTiming(&vmf, fileName, timeInSeconds, fileSizeInMB); } else { throw CommandException("Unsupported file type for timing."); } std::cout << "------ " << fileNameNoPath.toAscii().constData() << " ------" << std::endl; std::cout << " Average time to read: " << timeInSeconds << " seconds." << std::endl; if (fileSizeInMB > 0) { std::cout << " File Size (MB): " << fileSizeInMB << std::endl; } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandFileConvert.h0000664000175000017500000001312011572067322025505 0ustar michaelmichael #ifndef __COMMAND_FILE_CONVERT_H__ #define __COMMAND_FILE_CONVERT_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "AbstractFile.h" #include "CommandBase.h" class AreaColorFile; class BrainSet; class ProgramParameters; /// class for data file conversion class CommandFileConvert : public CommandBase { public: // constructor CommandFileConvert(); // destructor ~CommandFileConvert(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: enum MODE { MODE_NONE, MODE_CONTOUR_CONVERT, MODE_FORMAT_CONVERT, MODE_FORMAT_INFO, MODE_SPEC_CONVERT, MODE_SURFACE_CONVERT, MODE_FREE_SURFER_CURVATURE_TO_CARET, MODE_FREE_SURFER_FUNCTIONAL_TO_CARET, MODE_FREE_SURFER_LABEL_TO_CARET, MODE_CARET_PAINT_TO_FREE_SURFER_LABEL, MODE_CARET_SHAPE_TO_FREE_SURFER_CURVATURE, MODE_VOLUME }; enum SURFACE_FILE_TYPE { SURFACE_TYPE_UNKNOWN, SURFACE_TYPE_BYU, SURFACE_TYPE_CARET, SURFACE_TYPE_FREE_SURFER, SURFACE_TYPE_FREE_SURFER_PATCH, SURFACE_TYPE_GIFTI, SURFACE_TYPE_MNI_OBJ, SURFACE_TYPE_OPEN_INVENTOR, SURFACE_TYPE_STL, SURFACE_TYPE_VTK, SURFACE_TYPE_XML_VTK }; // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); // Convert caret files or display info // info about the file. void fileFormatConvert(const std::vector& dataFileNames, const QString& dataFileFormatList, const AreaColorFile* areaColorFile) throw (CommandException); // Write/Update a spec file. void updateSpecFile(const std::vector& tags, const std::vector& values) throw (CommandException); // Convert a free surfer curvature file to caret surface shape. void freeSurferCurvatureToCaretConvert() throw (CommandException); // Convert a caret paint file to free surfer label file void caretPaintToFreeSurferLabel() throw (CommandException); // Convert a caret shape column to free surfer curvature file void caretShapeToFreeSurferCurvature() throw (CommandException); // Convert a free surfer functional file to caret metric. void freeSurferLabelToCaretConvert() throw (CommandException); // Convert a free surfer functional file to caret metric. void freeSurferFunctionalToCaretConvert() throw (CommandException); // Convert a surface file to another type. void surfaceFileConversion() throw (CommandException); // Convert a surface type name to an enum. SURFACE_FILE_TYPE getSurfaceFileType(const QString& surfaceTypeName, const QString& inputOutputName) throw (CommandException); // convert a volulme void volumeConversion(const QString& inputVolumeName, const QString& outputVolumeName) throw (CommandException); // Convert a spec file's data files void specFileConvert(const QString& dataFileFormatList, const QString& specFileName) throw (CommandException); // Convert a contour file void contourConversion(const QString& contourType, const QString& contourFileName, const QString& caretContourFileName, const QString& caretContourCellFileName) throw (CommandException); SURFACE_FILE_TYPE inputSurfaceType; SURFACE_FILE_TYPE outputSurfaceType; MODE mode; AbstractFile::FILE_FORMAT fileWriteType; QString specFileName; QString structureName; QString inputSurfaceName; QString inputSurfaceName2; QString outputSurfaceName; QString outputSurfaceName2; QString outputCoordTypeName; QString outputTopoTypeName; QString inputShapeName; QString inputShapeColumn; QString outputCurvatureName; BrainSet* brainSet; }; #endif // __COMMAND_FILE_CONVERT_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandFileConvert.cxx0000664000175000017500000016715211572067322026077 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "AreaColorFile.h" #include "BrainSet.h" #include "BrainModelContours.h" #include "CommandFileConvert.h" #include "ContourCellFile.h" #include "ContourFile.h" #include "FileFilters.h" #include "FileUtilities.h" #include "FreeSurferCurvatureFile.h" #include "FreeSurferFunctionalFile.h" #include "FreeSurferSurfaceFile.h" #include "GiftiDataArrayFile.h" #include "MetricFile.h" #include "PaintFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SpecFile.h" #include "SurfaceShapeFile.h" #include "TopologyFile.h" #include "vtkPolyData.h" #include "vtkPolyDataReader.h" /** * constructor. */ CommandFileConvert::CommandFileConvert() : CommandBase("-file-convert", "FILE CONVERSION") { brainSet = NULL; fileWriteType = AbstractFile::FILE_FORMAT_ASCII; mode = MODE_NONE; } /** * destructor. */ CommandFileConvert::~CommandFileConvert() { if (brainSet != NULL) { delete brainSet; brainSet = NULL; } } /** * get the script builder parameters. */ void CommandFileConvert::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addVariableListOfParameters("commands"); } /** * get full help information. */ QString CommandFileConvert::getHelpInformation() const { std::vector fileFormats; std::vector fileFormatNames; AbstractFile::getFileFormatTypesAndNames(fileFormats, fileFormatNames); const QString cmdSwitch(getOperationSwitch()); QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "---------------------------------------------------------------------- \n" + indent9 + "SYNOPSIS for Caret File Format Conversion \n" + indent9 + " " + cmdSwitch + " [options] -format-convert \\ \n" + indent9 + " \n" + indent9 + " \n" + indent9 + "DESCRIPTION for Caret File Format Conversion \n" + indent9 + " Convert Caret data files to the specified formats. \n" + indent9 + " \n" + indent9 + " REQUIRED PARAMETERS \n" + indent9 + " is any combination of the following\n" + indent9 + " separated by a colon:\n"); for (unsigned int i = 0; i < fileFormatNames.size(); i++) { helpInfo += (indent9 + " " + fileFormatNames[i] + "\n"); } helpInfo += ("" + indent9 + " \n" + indent9 + " OPTIONS\n" + indent9 + " [-area-color-file filename]\n" + indent9 + " \n" + indent9 + " Use the area color file option when converting\n" + indent9 + " paint files to GIFTI format. When the LabelTable \n" + indent9 + " in the output GIFTI file is created, color components\n" + indent9 + " will be assigned using the colors in the area color\n" + indent9 + " file. If there is more than one area color file,\n" + indent9 + " precede each of the them with the \"-area-color-file\"\n" + indent9 + " option.\n" + indent9 + " \n" + indent9 + "---------------------------------------------------------------------- \n" + indent9 + "SYNOPSIS for Caret File Format Information \n" + indent9 + " " + cmdSwitch + " -format-info \n" + indent9 + " \n" + indent9 + "DESCRIPTION for Caret File Format Information \n" + indent9 + " Display the file format of each of the specified files. \n" + indent9 + " \n" + indent9 + "---------------------------------------------------------------------- \n" + indent9 + "SYNOPSIS for Converting Data Files in a Spec File \n" + indent9 + " " + cmdSwitch + " -spec-convert spec-file-name \n" + indent9 + " \n" + indent9 + "DESCRIPTION for Converting Data Files in a Spec File \n" + indent9 + " Converts all of the data files listed in a spec file to the \n" + indent9 + " specified formats. \n" + indent9 + " \n" + indent9 + " REQUIRED PARAMETERS \n" + indent9 + " is any combination of the following\n" + indent9 + " separated by a colon:\n"); for (unsigned int i = 0; i < fileFormatNames.size(); i++) { helpInfo += (indent9 + " " + fileFormatNames[i] + "\n"); } helpInfo += ("" + indent9 + " \n" + indent9 + "---------------------------------------------------------------------- \n" + indent9 + "SYNOPSIS for Surface File Conversion \n" + indent9 + " " + cmdSwitch + " -sc -is [name2] \\ \n" + indent9 + " -os [name2] [coord-type] [topo-type] \\ \n" + indent9 + " [-outbin -outtext] \\ \n" + indent9 + " [-spec spec-file-name] [-struct structure] \n" + indent9 + " \n" + indent9 + "DESCRIPTION for Convert surface file formats. \n" + indent9 + " \n" + indent9 + " REQUIRED PARAMETERS \n" + indent9 + " -sc Specifies surface format conversion. \n" + indent9 + " \n" + indent9 + " -is [name2] Specifies the input surface. \n" + indent9 + " type is one of: \n" + indent9 + " BYU input surface is a BYU surface file \n" + indent9 + " This type is followed by the name of the BYU surface\n" + indent9 + " file.\n" + indent9 + " \n" + indent9 + " CARET input surface is Caret Coordinate and Topology \n" + indent9 + " files. This type is followed by the names of the \n" + indent9 + " Caret Coordinatefile, the Caret Topology file. \n" + indent9 + " \n" + indent9 + " FSS input surface is a FreeSurfer surface surface file. \n" + indent9 + " This type is followed by the name of the FreeSurfer \n" + indent9 + " surface file. \n" + indent9 + " \n" + indent9 + " FSP input surface is a FreeSurfer surface patch file. \n" + indent9 + " This type is followed by the name of the FreeSurfer \n" + indent9 + " patch file and the name of a corresponding FreeSurfer \n" + indent9 + " surface file. \n" + indent9 + " \n" + indent9 + " GS input surface is a GIFTI XML surface file.\n" + indent9 + " This type is followed by the name of the GIFTI\n" + indent9 + " surface file.\n" + indent9 + " \n" + indent9 + " MNIOBJ input surface is a MNI OBJ surface file.\n" + indent9 + " This type is followed by the name of the MNI\n" + indent9 + " surface file.\n" + indent9 + " http://www.bic.mni.mcgill.ca/~david/FAQ/FAQ.html#9 \n" + indent9 + " \n" + indent9 + " STL input surface is a BYU surface file \n" + indent9 + " This type is followed by the name of the STL surface \n" + indent9 + " file.\n" + indent9 + " \n" + indent9 + " VTKP input surface is a VTK PolyData file. \n" + indent9 + " This type is followed by the name of the VTK PolyData \n" + indent9 + " file.\n" + indent9 + " \n" + indent9 + " VTKXP input surface is an XML VTK PolyData file. \n" + indent9 + " This type is followed by the name of the XML VTK \n" + indent9 + " PolyData file.\n" + indent9 + " \n" + indent9 + " -os [name2] [coord-type] [topo-type] \n" + indent9 + " Specifies the output surface. \n" + indent9 + " \n" + indent9 + " This option's type name and name2 parameters are the same as\n" + indent9 + " for the \"-is\" option. \n" + indent9 + " \n" + indent9 + " The third and forth parameters are the \n" + indent9 + " coordinate file type and the topology file type. \n" + indent9 + " \n" + indent9 + " In addition to the types listed for input, an\n" + indent9 + " output only type is one of: \n" + indent9 + " OI Output surface is an Open Inventor file. \n" + indent9 + " \n" + indent9 + " Valid topology file types: \n" + indent9 + " CLOSED \n" + indent9 + " OPEN \n" + indent9 + " CUT \n" + indent9 + " LOBAR_CUT \n" + indent9 + " UNKNOWN \n" + indent9 + " \n" + indent9 + " Valid coordinate file types \n" + indent9 + " RAW \n" + indent9 + " FIDUCIAL \n" + indent9 + " INFLATED \n" + indent9 + " VERY_INFLATED \n" + indent9 + " SPHERICAL \n" + indent9 + " ELLIPSOIDAL \n" + indent9 + " CMW \n" + indent9 + " FLAT \n" + indent9 + " FLAT_LOBAR \n" + indent9 + " UNKNOWN \n" + indent9 + " \n" + indent9 + " OPTIONAL PARAMETERS \n" + indent9 + " -outbin Indicates that output Caret files are to be written in \n" + indent9 + " binary format. \n" + indent9 + " \n" + indent9 + " -outtext Indicates that output Caret files are to be written in \n" + indent9 + " text (ascii) format. \n" + indent9 + " \n" + indent9 + " -spec spec-file-name Indicates that output Caret files are to \n" + indent9 + " be written to the spec file . If the spec \n" + indent9 + " file does not exist, it will be created. \n" + indent9 + " \n" + indent9 + " -struct structure Indicates the structure that should be \n" + indent9 + " placed into the spec file when writing Caret files. \n" + indent9 + " Valid structure types \n" + indent9 + " right \n" + indent9 + " left \n" + indent9 + " cerebellum \n" + indent9 + " \n" + indent9 + "---------------------------------------------------------------------- \n" + indent9 + "SYNOPSIS for FreeSurfer Data File / Caret Conversion \n" + indent9 + " " + cmdSwitch + " -fsc2c free-surfer-curvature \\ \n" + indent9 + " free-surfer-surface output-surface-shape \\ \n" + indent9 + " [-outbin -outtext] \\ \n" + indent9 + " [-spec spec-file-name] [-struct structure] \n" + indent9 + " \n" + indent9 + " " + cmdSwitch + " -fsf2c free-surfer-functional \\ \n" + indent9 + " free-surfer-surface output-metric \\ \n" + indent9 + " [-outbin -outtext] \\ \n" + indent9 + " [-spec spec-file-name] [-struct structure] \n" + indent9 + " \n" + indent9 + " " + cmdSwitch + " -cp2fsl caret-paint-file \\ \n" + indent9 + " caret-fiducial-coord-file \n" + indent9 + " \n" + indent9 + " " + cmdSwitch + " -cs2fsc caret-shape-file \\ \n" + indent9 + " shape-column \\ \n" + indent9 + " caret-fiducial-coord-file \\ \n" + indent9 + " free-surfer-curvature-file\n" + indent9 + " \n" + indent9 + "DESCRIPTION for FreeSurfer Data File / Caret Conversion \n" + indent9 + " Convert free surfer data files to Caret format. \n" + indent9 + " \n" + indent9 + " REQUIRED PARAMETERS \n" + indent9 + " \n" + indent9 + " Note: You must specify one of the following: \n" + indent9 + " \n" + indent9 + " " + cmdSwitch + " -fsc2c \n" + indent9 + " Converts a free surfer curvature file into a Caret surface\n" + indent9 + " shape file. This option is followed by the name of the \n" + indent9 + " Free Surfer curvature file, the name of a Free Surfer \n" + indent9 + " surfacefile (used to get number of nodes), and the output \n" + indent9 + " Caret surface shape file. \n" + indent9 + " \n" + indent9 + " " + cmdSwitch + " -fsf2c \n" + indent9 + " Converts a free surfer functional file into a Caret metric\n" + indent9 + " file. This option is followed by the name of the Free \n" + indent9 + " Surfer functional file, the name of a Free Surfer surface \n" + indent9 + " file (used to get number of nodes), and the output Caret \n" + indent9 + " metric file. \n" + indent9 + " \n" + indent9 + " " + cmdSwitch + " -fsl2c \n" + indent9 + " Converts all free surfer label files in the specified \n" + indent9 + " directory into a paint file. This option is followed by \n" + indent9 + " the directory containing the label files, the name of a \n" + indent9 + " Free Surfer surface file (used to get number of nodes), \n" + indent9 + " and the output Caret paint file. \n" + indent9 + " \n" + indent9 + " " + cmdSwitch + " -cp2fsl \n" + indent9 + " Convert a paint file into free surfer label files. No \n" + indent9 + " output name is needed since free surfer uses on file per \n" + indent9 + " paint ID with the name of the file being \"paintID\" \n" + indent9 + " label. \n" + indent9 + " \n" + indent9 + " " + cmdSwitch + " -cs2fsc \n" + indent9 + " Convert a Caret shape file column into a free\n" + indent9 + " surfer curvature file.\n" + indent9 + " \n" + indent9 + " OPTIONAL PARAMETERS for FreeSurfer Data File to Caret Conversion \n" + indent9 + " \n" + indent9 + " See the surface conversion options for explanation. \n" + indent9 + " \n" + indent9 + "---------------------------------------------------------------------- \n" + indent9 + "SYNOPSIS for Converting Volume Files \n" + indent9 + " " + cmdSwitch + " -vc \n" + indent9 + " \n" + indent9 + "DESCRIPTION for Converting Volume Files \n" + indent9 + " The extension of the output volume file name determines the type of \n" + indent9 + " of volume file. \n" + indent9 + " \n" + indent9 + " Extension Type of Volume File \n" + indent9 + " --------- ------------------- \n" + indent9 + " HEAD AFNI Volume File \n" + indent9 + " ifh Washington University Volume File \n" + indent9 + " nii NIFTI Volume File \n" + indent9 + " nii.gz Compressed NIFTI Volume File \n" + indent9 + " \n" + indent9 + " \n" + indent9 + "For best results, run this program from the directory containing \n" + indent9 + "the files \n" + indent9 + " \n" + indent9 + "---------------------------------------------------------------------- \n" + indent9 + "SYNOPSIS for importing contour files \n" + indent9 + " " + cmdSwitch + " -ic [caret-contour-cell-file-name] \n" + indent9 + " \n" + indent9 + "DESCRIPTION for Importing Contour Files \n" + indent9 + " \n" + indent9 + " CONTOUR_TYPE Type of Contour File\n" + indent9 + " ------------ --------------------\n" + indent9 + " MDPLOT MDPLOT .mdo contour file\n" + indent9 + " NEURO Neurolucida XML contour file\n" + indent9 + " \n" + indent9 + " The \"caret-contour-cell-file-name\" is optional. If \n" + indent9 + " there are no contour cells, it is not written.\n" + indent9 + " \n" + indent9 + "---------------------------------------------------------------------- \n" + indent9 + "---------------------------------------------------------------------- \n" + indent9 + "EXAMPLES \n" + indent9 + " \n" + indent9 + " Convert all Caret data files in the current directory that support \n" + indent9 + " binary format into the binary format. If the file does not \n" + indent9 + " support binary, convert the file to XML format. If the file \n" + indent9 + " supports neither binary nor XML format, do not change the file:\n" + indent9 + " " + cmdSwitch + " -format-convert BINARY:XML * \n" + indent9 + " \n" + indent9 + " Convert all files in the current directory that can be\n" + indent9 + " written in GIFTI XML-GZIP format to that format. An\n" + indent9 + " area color file is included so that any paint files \n" + indent9 + " that are converted to GIFTI label files, receive color\n" + indent9 + " assignments in their LabelTables.\n" + indent9 + " " + cmdSwitch + " -area-color-file Human.labels.areacolor \\\n" + indent9 + " -format-convert XML_BASE64_GZIP * \n" + indent9 + " \n" + indent9 + " Convert the two Caret files into ascii format Caret files: \n" + indent9 + " " + cmdSwitch + " -format-convert ASCII file1.top \\ \n" + indent9 + " file3.coord \n" + indent9 + " \n" + indent9 + " List the data type (text or binary) of all Caret files in the \n" + indent9 + " current directory: \n" + indent9 + " " + cmdSwitch + " -format-info * \n" + indent9 + " \n" + indent9 + " Convert the free surfer surface into closed topology and fiducial \n" + indent9 + " coordinate files. Create a spec file for a left cortex. \n" + indent9 + " " + cmdSwitch + " -sc -is FSS lh.orig.asc -os CARET fiducial.coord \\\n" + indent9 + " closed.topo FIDUCIAL CLOSED -spec file.spec -struct LEFT \n" + indent9 + " \n" + indent9 + " Convert the free surfer patch into cut topology and flat \n" + indent9 + " coordinate files. Create or add to the spec file as left cortex. \n" + indent9 + " Write the coord and topo files in text format. \n" + indent9 + " " + cmdSwitch + " -sc -is FSP lh.oc.flat.asc lh.orig.asc \\ \n" + indent9 + " -os CARET flat.coord cut.topo FLAT CUT -spec file.spec \\ \n" + indent9 + " -struct LEFT -outtext \n" + indent9 + " \n" + indent9 + " Convert the free surfer curvature file to a Caret surface shape \n" + indent9 + " file.\n" + indent9 + " " + cmdSwitch + " -fsc2c lh.curv.asc lh.pial.asc \\ \n" + indent9 + " shape.surface_shape -spec file.spec \n" + indent9 + " \n" + indent9 + " Convert the free surfer functional file to a Caret metric file. \n" + indent9 + " " + cmdSwitch + " -fsf2c pho-lh.5.w.asc lh.pial.asc \\ \n" + indent9 + " func.metric -spec file.spec \n" + indent9 + " \n" + indent9 + " Convert the free surfer label files in current directory to a Caret \n" + indent9 + " paint file. \n" + indent9 + " " + cmdSwitch + " -fsl2c . lh.pial.asc \\ \n" + indent9 + " label.paint -spec file.spec \n" + indent9 + " \n" + indent9 + " Convert the caret paint file into free surfer label files \n" + indent9 + " " + cmdSwitch + " -cp2fsl file.paint \\ \n" + indent9 + " fiducial.coord \n" + indent9 + " \n" + indent9 + " Convert the first column in the caret surface shape file \n" + indent9 + " into a Free Surfer curvature file. \n" + indent9 + " " + cmdSwitch + " -cs2fsc Human.surface_shape 1 \\ \n" + indent9 + " Human.FIDUCIAL.coord freesurfer.curv.asc \n" + indent9 + " \n" + indent9 + " Convert the data files listed in the spec file to binary format. \n" + indent9 + " If binary is not supported for a file, try ASCII.\n" + indent9 + " " + cmdSwitch + " -spec-convert BINARY:ASCII human.spec \n" + indent9 + " \n" + indent9 + " Convert the volume file from AFNI to compressed NIFTI format. \n" + indent9 + " " + cmdSwitch + " -vc anat+orig.HEAD anat+orig.nii.gz \n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandFileConvert::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { brainSet = new BrainSet(true); QString inputVolumeName; QString outputVolumeName; QString contourType; QString contourFileName; QString caretContourFileName; QString caretContourCellFileName; // // This gets the preferred write type from the preferences file // fileWriteType = AbstractFile::FILE_FORMAT_OTHER; std::vector areaColorFileNames; // // Process the command line options // std::vector dataFileNames; QString dataFileFormatList; while (parameters->getParametersAvailable()) { const QString arg(parameters->getNextParameterAsString("Parameter")); if (arg == "-area-color-file") { areaColorFileNames.push_back(parameters->getNextParameterAsString("Area Color File Name")); } else if (arg == "-format-convert") { if (mode == MODE_NONE) { mode = MODE_FORMAT_CONVERT; } else { throw CommandException("More than one mode parameter specified."); std::cout << std::endl; } dataFileFormatList = parameters->getNextParameterAsString("File Format"); while (parameters->getParametersAvailable()) { dataFileNames.push_back(parameters->getNextParameterAsString("Data File Name")); } } else if (arg == "-fsc2c") { mode = MODE_FREE_SURFER_CURVATURE_TO_CARET; inputSurfaceName = parameters->getNextParameterAsString("Input Surface Name"); inputSurfaceName2 = parameters->getNextParameterAsString("Input Surface Name 2"); outputSurfaceName = parameters->getNextParameterAsString("Output Surface Name"); } else if (arg == "-fsf2c") { mode = MODE_FREE_SURFER_FUNCTIONAL_TO_CARET; inputSurfaceName = parameters->getNextParameterAsString("Input Surface Name"); inputSurfaceName2 = parameters->getNextParameterAsString("Input Surface Name 2"); outputSurfaceName = parameters->getNextParameterAsString("Output Surface Name"); } else if (arg == "-fsl2c") { mode = MODE_FREE_SURFER_LABEL_TO_CARET; inputSurfaceName = parameters->getNextParameterAsString("Input Surface Name"); inputSurfaceName2 = parameters->getNextParameterAsString("Input Surface Name 2"); outputSurfaceName = parameters->getNextParameterAsString("Output Surface Name"); } else if (arg == "-cp2fsl") { mode = MODE_CARET_PAINT_TO_FREE_SURFER_LABEL; inputSurfaceName = parameters->getNextParameterAsString("Input Surface Name"); inputSurfaceName2 = parameters->getNextParameterAsString("Input Surface Name 2"); } else if (arg == "-cs2fsc") { mode = MODE_CARET_SHAPE_TO_FREE_SURFER_CURVATURE; inputShapeName = parameters->getNextParameterAsString("Input Caret Shape File"); inputShapeColumn = parameters->getNextParameterAsString("Input Caret Shape File Column"); inputSurfaceName = parameters->getNextParameterAsString("Input Fiducial Coordinate Name"); outputCurvatureName = parameters->getNextParameterAsString("Output Free Surfer Curvature Name"); } else if (arg == "-sc") { mode = MODE_SURFACE_CONVERT; } else if (arg == "-format-info") { if (mode == MODE_NONE) { mode = MODE_FORMAT_INFO; } else { throw CommandException("More than one mode parameter specified."); } while (parameters->getParametersAvailable()) { dataFileNames.push_back(parameters->getNextParameterAsString("Data File Name")); } } else if (arg == "-ic") { if (mode == MODE_NONE) { mode = MODE_CONTOUR_CONVERT; } else { throw CommandException("More than one mode parameter specified."); } contourType = parameters->getNextParameterAsString("Contour Type"); contourFileName = parameters->getNextParameterAsString("Contour File Name"); caretContourFileName = parameters->getNextParameterAsString("Caret Contour File Name"); caretContourCellFileName = parameters->getNextParameterAsString("Caret Contour Cell File Name"); } else if (arg == "-is") { QString inputTypeName; inputTypeName = parameters->getNextParameterAsString("Input Type Name"); inputSurfaceType = getSurfaceFileType(inputTypeName, "input"); inputSurfaceName = parameters->getNextParameterAsString("Input Surface Name"); switch(inputSurfaceType) { case SURFACE_TYPE_BYU: break; case SURFACE_TYPE_CARET: inputSurfaceName2 = parameters->getNextParameterAsString("Input Surface Name 2"); break; case SURFACE_TYPE_FREE_SURFER: break; case SURFACE_TYPE_FREE_SURFER_PATCH: inputSurfaceName2 = parameters->getNextParameterAsString("Input Surface Name 2"); break; case SURFACE_TYPE_GIFTI: break; case SURFACE_TYPE_MNI_OBJ: break; case SURFACE_TYPE_OPEN_INVENTOR: throw CommandException("Open Inventor not supported for input."); break; case SURFACE_TYPE_STL: break; case SURFACE_TYPE_VTK: break; case SURFACE_TYPE_XML_VTK: break; case SURFACE_TYPE_UNKNOWN: break; } } else if (arg == "-os") { QString outputTypeName; outputTypeName = parameters->getNextParameterAsString("Output Type Name"); outputSurfaceType = getSurfaceFileType(outputTypeName, "output"); outputSurfaceName = parameters->getNextParameterAsString("Output Surface Name"); switch(outputSurfaceType) { case SURFACE_TYPE_BYU: break; case SURFACE_TYPE_CARET: outputSurfaceName2 = parameters->getNextParameterAsString("Output Surface Name 2"); outputCoordTypeName = parameters->getNextParameterAsString("Output Coord Type Name"); outputTopoTypeName = parameters->getNextParameterAsString("Output Topo Type Name"); break; case SURFACE_TYPE_FREE_SURFER: break; case SURFACE_TYPE_FREE_SURFER_PATCH: outputSurfaceName2 = parameters->getNextParameterAsString("Output Surface Name 2"); break; case SURFACE_TYPE_GIFTI: break; case SURFACE_TYPE_MNI_OBJ: throw CommandException("MNI OBJ not supported for writing."); break; case SURFACE_TYPE_OPEN_INVENTOR: break; case SURFACE_TYPE_STL: break; case SURFACE_TYPE_VTK: break; case SURFACE_TYPE_XML_VTK: break; case SURFACE_TYPE_UNKNOWN: break; } } else if (arg == "-spec") { specFileName = parameters->getNextParameterAsString("Spec File Name"); } else if (arg == "-spec-convert") { if (mode == MODE_NONE) { mode = MODE_SPEC_CONVERT; } else { throw CommandException("More than one mode parameter specified."); } dataFileFormatList = parameters->getNextParameterAsString("File Format"); specFileName = parameters->getNextParameterAsString("Spec File Name"); } else if (arg == "-struct") { structureName = parameters->getNextParameterAsString("Structure").toLower(); } else if (arg == "-outbin") { fileWriteType = AbstractFile::FILE_FORMAT_BINARY; } else if (arg == "-outtext") { fileWriteType = AbstractFile::FILE_FORMAT_ASCII; } else if (arg == "-outxml") { fileWriteType = AbstractFile::FILE_FORMAT_XML; } else if (arg == "-vc") { if (mode == MODE_NONE) { mode = MODE_VOLUME; inputVolumeName = parameters->getNextParameterAsString("Input Volume Name"); outputVolumeName = parameters->getNextParameterAsString("Input Volume Name"); } else { throw CommandException("More than one mode parameter specified."); } } else { throw CommandException("Unrecognized parameter: " + arg); } } if (mode == MODE_NONE) { throw CommandException("You must specify a mode parameter."); } AreaColorFile* areaColorFile = NULL; int numAreaColorFiles = static_cast(areaColorFileNames.size()); if (numAreaColorFiles > 0) { areaColorFile = new AreaColorFile(); for (int i = 0; i < numAreaColorFiles; i++) { AreaColorFile acf; acf.readFile(areaColorFileNames[i]); areaColorFile->append(acf); } } const int numberOfDataFiles = static_cast(dataFileNames.size()); switch (mode) { case MODE_NONE: break; case MODE_CONTOUR_CONVERT: contourConversion(contourType, contourFileName, caretContourFileName, caretContourCellFileName); break; case MODE_FORMAT_CONVERT: if (numberOfDataFiles <= 0) { throw CommandException("No files specified."); } fileFormatConvert(dataFileNames, dataFileFormatList, areaColorFile); break; case MODE_FORMAT_INFO: if (numberOfDataFiles <= 0) { throw CommandException("No files specified."); } fileFormatConvert(dataFileNames, "INFO", areaColorFile); break; case MODE_SPEC_CONVERT: specFileConvert(dataFileFormatList, specFileName); break; case MODE_SURFACE_CONVERT: surfaceFileConversion(); break; case MODE_FREE_SURFER_CURVATURE_TO_CARET: freeSurferCurvatureToCaretConvert(); break; case MODE_FREE_SURFER_FUNCTIONAL_TO_CARET: freeSurferFunctionalToCaretConvert(); break; case MODE_FREE_SURFER_LABEL_TO_CARET: freeSurferLabelToCaretConvert(); break; case MODE_CARET_PAINT_TO_FREE_SURFER_LABEL: caretPaintToFreeSurferLabel(); break; case MODE_CARET_SHAPE_TO_FREE_SURFER_CURVATURE: caretShapeToFreeSurferCurvature(); break; case MODE_VOLUME: volumeConversion(inputVolumeName, outputVolumeName); break; } } /** * Convert a contour file. */ void CommandFileConvert::contourConversion(const QString& contourType, const QString& contourFileName, const QString& caretContourFileName, const QString& caretContourCellFileName) throw (CommandException) { if (caretContourFileName.isEmpty()) { throw CommandException("Caret contour file name is empty."); } try { // // Import contours // BrainSet bs; if (contourType == "MDPLOT") { bs.importMDPlotFile(contourFileName, true, true, false, false); } else if (contourType == "NEURO") { bs.importNeurolucidaFile(contourFileName, true, true, false, false); } // // Write contours // BrainModelContours* bmc = bs.getBrainModelContours(); if (bmc == NULL) { throw CommandException("Contours import failed."); } ContourFile* cf = bmc->getContourFile(); if (cf->getNumberOfContours() <= 0) { throw CommandException("File read but no contours found."); } bs.writeContourFile(caretContourFileName, cf); // // Write contour cells // if (caretContourCellFileName.isEmpty() == false) { ContourCellFile* cells = bs.getContourCellFile(); if (cells->getNumberOfCells() > 0) { bs.writeContourCellFile(caretContourCellFileName); } } } catch (FileException& e) { throw (CommandException(e)); } } /** * Convert caret files between binary and text format or display * info about the file. */ void CommandFileConvert::fileFormatConvert(const std::vector& dataFileNames, const QString& dataFileFormatList, const AreaColorFile* areaColorFile) throw (CommandException) { // // Convert the data format list to file types // const QStringList sl = dataFileFormatList.split(':'); const int numFormats = sl.count(); if (numFormats < 1) { throw CommandException("No file formats provided for file format conversion."); } // // Just Info ? // std::vector conversionFormats; bool infoFlag = false; if ((numFormats == 1) && (sl.at(0) == "INFO")) { infoFlag = true; } else { for (int i = 0; i < numFormats; i++) { const QString formatName(sl.at(i)); bool valid = false; const AbstractFile::FILE_FORMAT format = AbstractFile::convertFormatNameToType(formatName, &valid); if (valid) { conversionFormats.push_back(format); } else { throw CommandException("Invalid file format name \"" + formatName + "\""); } } } // // Process the files // const int numberOfDataFiles = static_cast(dataFileNames.size()); if (numberOfDataFiles < 1) { throw CommandException("No files provided for conversion."); } for (int i = 0; i < numberOfDataFiles; i++) { const QString filename(dataFileNames[i]); QString errorMessage; // // Skip directories and symbolic links // QFileInfo fileInfo(filename); if (fileInfo.isDir() || fileInfo.isSymLink()) { continue; } // // Read the header of the file // AbstractFile* af = AbstractFile::readAnySubClassDataFile(filename, true, errorMessage); std::cout << FileUtilities::basename(filename).toAscii().constData() << ": "; if (af == NULL) { std::cout << "unable to read file or not a caret data file.\n" << "error: " << errorMessage.toAscii().constData(); } else if (af->getFileHasHeader() == false) { std::cout << "file does not have header."; } else { // // Get files current encoding // const QString formatString(af->getHeaderTag(AbstractFile::headerTagEncoding)); bool validFormatFlag = false; const AbstractFile::FILE_FORMAT dataFileFormat = AbstractFile::convertFormatNameToType(formatString, &validFormatFlag); if (infoFlag) { if (validFormatFlag == false) { std::cout << "unrecognized format: " << formatString.toAscii().constData(); } else { std::cout << formatString.toAscii().constData() << "."; } } else { bool fileProcessedFlag = false; for (unsigned int i = 0; i < conversionFormats.size(); i++) { if (validFormatFlag && (dataFileFormat == conversionFormats[i])) { std::cout << " already in " << formatString.toAscii().constData() << " format"; fileProcessedFlag = true; } else if (af->getCanWrite(conversionFormats[i])) { try { af->readFile(filename); af->setFileWriteType(conversionFormats[i]); // // Assign colors to paint files since may be GIFTI output // PaintFile* pf = dynamic_cast(af); if (pf != NULL) { if (areaColorFile != NULL) { pf->assignColors(*areaColorFile); } } af->writeFile(filename); std::cout << "converted to " << AbstractFile::convertFormatTypeToName(conversionFormats[i]).toAscii().constData() << "."; } catch (FileException& e) { std::cout << "error converting or writing: " << e.whatQString().toAscii().constData() << std::endl; } fileProcessedFlag = true; } if (fileProcessedFlag) { break; } } if (fileProcessedFlag == false) { std::cout << " does not support specified formats."; } } } if (af != NULL) { delete af; // can't delete ?? compiler bug ?? } std::cout << std::endl; } } /** * Write/Update a spec file. */ void CommandFileConvert::updateSpecFile(const std::vector& tags, const std::vector& values) throw (CommandException) { try { // // If the user specified a spec file // if (specFileName.isEmpty() == false) { // // Should spec file be created // if (QFile::exists(specFileName) == false) { SpecFile sf; sf.writeFile(specFileName); } // // Try reading the spec file but ignore errors since it may not exist // SpecFile specFile; specFile.readFile(specFileName); // // Add the spec file tags // for (int i = 0; i < static_cast(tags.size()); i++) { specFile.addToSpecFile(tags[i], values[i], "", false); } // // Set the structure // if (structureName.isEmpty() == false) { specFile.setStructure(structureName); } // // Write the spec file // specFile.writeFile(specFileName); } } catch (FileException& e) { throw CommandException(e); } } /** * Convert a free surfer curvature file to caret surface shape. */ void CommandFileConvert::freeSurferCurvatureToCaretConvert() throw (CommandException) { try { QString freeSurfaceCurvatureName(inputSurfaceName); QString freeSurfaceSurfaceName(inputSurfaceName2); QString shapeName(outputSurfaceName); // // Read in the free surfer surface file // AbstractFile::FILE_FORMAT format = AbstractFile::FILE_FORMAT_BINARY; if (freeSurfaceSurfaceName.right(3) == "asc") { format = AbstractFile::FILE_FORMAT_ASCII; } FreeSurferSurfaceFile freeSurferSurfaceFile; freeSurferSurfaceFile.setFileReadType(format); freeSurferSurfaceFile.readFile(freeSurfaceSurfaceName); // // convert the free surface curvature file to the surface shape file. // SurfaceShapeFile shapeFile; format = AbstractFile::FILE_FORMAT_BINARY; if (freeSurfaceCurvatureName.right(3) == "asc") { format = AbstractFile::FILE_FORMAT_ASCII; } shapeFile.importFreeSurferCurvatureFile(freeSurferSurfaceFile.getNumberOfVertices(), freeSurfaceCurvatureName, format); // // Write the surface shape file // if (fileWriteType != AbstractFile::FILE_FORMAT_OTHER) { shapeFile.setFileWriteType(fileWriteType); } shapeFile.writeFile(shapeName); // // Add the surface shape files to the spec file // std::vector tags; std::vector values; tags.push_back(SpecFile::getSurfaceShapeFileTag()); values.push_back(shapeName); updateSpecFile(tags, values); } catch (FileException& e) { throw CommandException(e); } } /** * Convert a caret shape column to free surfer curvature file. */ void CommandFileConvert::caretShapeToFreeSurferCurvature() throw (CommandException) { try { // // Load the shape file // SurfaceShapeFile shapeFile; shapeFile.readFile(inputShapeName); const int columnNumber = shapeFile.getColumnFromNameOrNumber(inputShapeColumn, false); // // Load the coordinate file // CoordinateFile coordFile; coordFile.readFile(inputSurfaceName); // // Export to free surfer // shapeFile.exportFreeSurferAsciiCurvatureFile(columnNumber, &coordFile, outputCurvatureName); } catch (FileException& e) { throw CommandException(e.whatQString()); } } /** * Convert a caret paint file to free surfer label file. */ void CommandFileConvert::caretPaintToFreeSurferLabel() throw (CommandException) { try { // // Load the paint file // PaintFile paintFile; paintFile.readFile(inputSurfaceName); // // Load the coordinate file // CoordinateFile coordFile; coordFile.readFile(inputSurfaceName2); // // Export to label files // for (int i = 0; i < paintFile.getNumberOfColumns(); i++) { paintFile.exportFreeSurferAsciiLabelFile(i, "", &coordFile); } } catch (FileException& e) { throw CommandException(e); } } /** * Convert a free surfer functional file to caret metric. */ void CommandFileConvert::freeSurferLabelToCaretConvert() throw (CommandException) { try { QString freeSurfaceLabelDirName(inputSurfaceName); freeSurfaceLabelDirName.append("/" + inputSurfaceName); QString freeSurfaceSurfaceName(inputSurfaceName2); QString paintName(outputSurfaceName); // // Read in the free surfer surface file // AbstractFile::FILE_FORMAT format = AbstractFile::FILE_FORMAT_BINARY; if (freeSurfaceSurfaceName.right(3) == "asc") { format = AbstractFile::FILE_FORMAT_ASCII; } FreeSurferSurfaceFile freeSurferSurfaceFile; freeSurferSurfaceFile.setFileReadType(format); freeSurferSurfaceFile.readFile(freeSurfaceSurfaceName); // // convert the free surface label files to the paint file. // PaintFile paintFile; paintFile.importFreeSurferAsciiLabelFile(freeSurferSurfaceFile.getNumberOfVertices(), freeSurfaceLabelDirName, NULL, true); // // Write the paint file // if (fileWriteType != AbstractFile::FILE_FORMAT_OTHER) { paintFile.setFileWriteType(fileWriteType); } paintFile.writeFile(paintName); // // Add the surface shape files to the spec file // std::vector tags; std::vector values; tags.push_back(SpecFile::getPaintFileTag()); values.push_back(paintName); updateSpecFile(tags, values); } catch (FileException& e) { throw CommandException(e); } } /** * Convert a free surfer functional file to caret metric. */ void CommandFileConvert::freeSurferFunctionalToCaretConvert() throw (CommandException) { try { QString freeSurfaceFunctionalName(inputSurfaceName); QString freeSurfaceSurfaceName(inputSurfaceName2); QString metricName(outputSurfaceName); // // Read in the free surfer surface file // AbstractFile::FILE_FORMAT format = AbstractFile::FILE_FORMAT_BINARY; if (freeSurfaceSurfaceName.right(3) == "asc") { format = AbstractFile::FILE_FORMAT_ASCII; } FreeSurferSurfaceFile freeSurferSurfaceFile; freeSurferSurfaceFile.setFileReadType(format); freeSurferSurfaceFile.readFile(freeSurfaceSurfaceName); // // convert the free surface functional file to the metric file. // MetricFile metricFile; format = AbstractFile::FILE_FORMAT_BINARY; if (freeSurfaceFunctionalName.right(3) == "asc") { format = AbstractFile::FILE_FORMAT_ASCII; } metricFile.importFreeSurferFunctionalFile(freeSurferSurfaceFile.getNumberOfVertices(), freeSurfaceFunctionalName, format); // // Write the surface shape file // if (fileWriteType != AbstractFile::FILE_FORMAT_OTHER) { metricFile.setFileWriteType(fileWriteType); } metricFile.writeFile(metricName); // // Add the surface shape files to the spec file // std::vector tags; std::vector values; tags.push_back(SpecFile::getMetricFileTag()); values.push_back(metricName); updateSpecFile(tags, values); } catch (FileException& e) { throw CommandException(e); } } /** * Convert a surface file to another type. */ void CommandFileConvert::surfaceFileConversion() throw (CommandException) { try { // // Convert the coordinate type name to a surface type // const BrainModelSurface::SURFACE_TYPES surfaceType = BrainModelSurface::getSurfaceTypeFromConfigurationID(outputCoordTypeName); // // Convert the topology type name to a topology type // const TopologyFile::TOPOLOGY_TYPES topoType = TopologyFile::getTopologyTypeFromPerimeterID(outputTopoTypeName); int brainModelOfInterest = 0; // // Read in the appropriate surface // switch(inputSurfaceType) { case SURFACE_TYPE_BYU: brainSet->importByuSurfaceFile(inputSurfaceName, true, true, surfaceType, topoType); break; case SURFACE_TYPE_CARET: { SpecFile sf; sf.addToSpecFile(SpecFile::getClosedTopoFileTag(), inputSurfaceName2, "", false); sf.addToSpecFile(SpecFile::getFiducialCoordFileTag(), inputSurfaceName, "", true); sf.setAllFileSelections(SpecFile::SPEC_TRUE); QString errorMessages; brainSet->readSpecFile(sf, "spec-name", errorMessages); if (errorMessages.isEmpty() == false) { throw CommandException("Reading coordinate and topology files:" + errorMessages); } } break; case SURFACE_TYPE_FREE_SURFER: { AbstractFile::FILE_FORMAT format = AbstractFile::FILE_FORMAT_BINARY; if (inputSurfaceName.right(3) == "asc") { format = AbstractFile::FILE_FORMAT_ASCII; } brainSet->importFreeSurferSurfaceFile(inputSurfaceName, true, true, format, surfaceType, topoType); } break; case SURFACE_TYPE_FREE_SURFER_PATCH: { AbstractFile::FILE_FORMAT format2 = AbstractFile::FILE_FORMAT_BINARY; if (inputSurfaceName2.right(3) == "asc") { format2 = AbstractFile::FILE_FORMAT_ASCII; } brainSet->importFreeSurferSurfaceFile(inputSurfaceName2, true, true, format2, surfaceType, topoType); AbstractFile::FILE_FORMAT format = AbstractFile::FILE_FORMAT_BINARY; if (inputSurfaceName.right(3) == "asc") { format = AbstractFile::FILE_FORMAT_ASCII; } brainSet->importFreeSurferSurfaceFile(inputSurfaceName, true, true, format, surfaceType, topoType); brainModelOfInterest = 1; } break; case SURFACE_TYPE_GIFTI: brainSet->readSurfaceFile(inputSurfaceName, surfaceType, false, true, false); break; case SURFACE_TYPE_MNI_OBJ: brainSet->importMniObjSurfaceFile(inputSurfaceName, true, true, true, surfaceType, topoType); break; case SURFACE_TYPE_OPEN_INVENTOR: throw CommandException("Open Inventor not supported for input."); break; case SURFACE_TYPE_STL: brainSet->importStlSurfaceFile(inputSurfaceName, true, true, surfaceType, topoType); break; case SURFACE_TYPE_VTK: brainSet->importVtkSurfaceFile(inputSurfaceName, true, true, false, surfaceType, topoType); break; case SURFACE_TYPE_XML_VTK: brainSet->importVtkXmlSurfaceFile(inputSurfaceName, true, true, false, surfaceType, topoType); break; case SURFACE_TYPE_UNKNOWN: break; } // // Make sure the surface is available // BrainModelSurface* bms = brainSet->getBrainModelSurface(brainModelOfInterest); if (bms == NULL) { throw CommandException("problems reading surface, brain model not found."); } // // Write out the appropriate surface // switch(outputSurfaceType) { case SURFACE_TYPE_BYU: brainSet->exportByuSurfaceFile(bms, outputSurfaceName); break; case SURFACE_TYPE_CARET: { // // Get the coordinate and topology files // CoordinateFile* coordFile = bms->getCoordinateFile(); TopologyFile* topoFile = bms->getTopologyFile(); // // Get the coordinate files spec file type tag // const QString coordSpecFileTag( BrainModelSurface::getCoordSpecFileTagFromSurfaceType(surfaceType)); // // Set the coordinate file's type // coordFile->setHeaderTag(AbstractFile::headerTagConfigurationID, BrainModelSurface::getSurfaceConfigurationIDFromType(surfaceType)); // // Get the topo file's spec file tag // const QString topoSpecFileTag( TopologyFile::getSpecFileTagFromTopologyType(topoType)); // // Set the topo file's type // topoFile->setTopologyType(topoType); // // Write the coordinate file // if (fileWriteType != AbstractFile::FILE_FORMAT_OTHER) { coordFile->setFileWriteType(fileWriteType); } if (structureName.isEmpty() == false) { coordFile->setHeaderTag(AbstractFile::headerTagStructure, structureName); } coordFile->writeFile(outputSurfaceName); // // Write the topology file // if (fileWriteType != AbstractFile::FILE_FORMAT_OTHER) { topoFile->setFileWriteType(fileWriteType); } topoFile->writeFile(outputSurfaceName2); // // Update the spec file // std::vector tags; std::vector values; tags.push_back(topoSpecFileTag); values.push_back(outputSurfaceName2); tags.push_back(coordSpecFileTag); values.push_back(outputSurfaceName); updateSpecFile(tags, values); } break; case SURFACE_TYPE_FREE_SURFER: brainSet->exportFreeSurferAsciiSurfaceFile(bms, outputSurfaceName); break; case SURFACE_TYPE_FREE_SURFER_PATCH: brainSet->exportFreeSurferAsciiSurfaceFile(bms, outputSurfaceName); brainModelOfInterest = 1; break; case SURFACE_TYPE_GIFTI: brainSet->writeSurfaceFile(outputSurfaceName, surfaceType, bms, false); break; case SURFACE_TYPE_MNI_OBJ: throw CommandException("MNI OBJ not supported for writing."); break; case SURFACE_TYPE_OPEN_INVENTOR: brainSet->exportInventorSurfaceFile(bms, outputSurfaceName); break; case SURFACE_TYPE_STL: brainSet->exportStlSurfaceFile(bms, outputSurfaceName); break; case SURFACE_TYPE_VTK: brainSet->exportVtkSurfaceFile(bms, outputSurfaceName, false); break; case SURFACE_TYPE_XML_VTK: brainSet->exportVtkXmlSurfaceFile(bms, outputSurfaceName, false); break; case SURFACE_TYPE_UNKNOWN: break; } } catch (FileException& e) { throw CommandException(e); } } /** * Convert a surface type name to an enum. */ CommandFileConvert::SURFACE_FILE_TYPE CommandFileConvert::getSurfaceFileType(const QString& surfaceTypeName, const QString& inputOutputName) throw (CommandException) { if (surfaceTypeName == "BYU") { return SURFACE_TYPE_BYU; } if (surfaceTypeName == "CARET") { return SURFACE_TYPE_CARET; } else if (surfaceTypeName == "FSS") { return SURFACE_TYPE_FREE_SURFER; } else if (surfaceTypeName == "FSP") { return SURFACE_TYPE_FREE_SURFER_PATCH; } else if (surfaceTypeName == "GS") { return SURFACE_TYPE_GIFTI; } else if (surfaceTypeName == "MNIOBJ") { return SURFACE_TYPE_MNI_OBJ; } else if (surfaceTypeName == "OI") { return SURFACE_TYPE_OPEN_INVENTOR; } else if (surfaceTypeName == "STL") { return SURFACE_TYPE_STL; } else if (surfaceTypeName == "VTKP") { return SURFACE_TYPE_VTK; } else if (surfaceTypeName == "VTKXP") { return SURFACE_TYPE_XML_VTK; } else { throw CommandException("Invalid " + inputOutputName + " surface type: " + surfaceTypeName); } return SURFACE_TYPE_UNKNOWN; } /** * convert a volume. */ void CommandFileConvert::volumeConversion(const QString& inputVolumeName, const QString& outputVolumeName) throw (CommandException) { try { // // Read the input file // std::vector volumes; VolumeFile::readFile(inputVolumeName, VolumeFile::VOLUME_READ_SELECTION_ALL, volumes); if (volumes.empty() == false) { // // Write the output file // VolumeFile::writeFile(outputVolumeName, volumes[0]->getVolumeType(), volumes[0]->getVoxelDataType(), volumes); // // Free memory // for (unsigned int i = 0; i < volumes.size(); i++) { delete volumes[i]; } } else { throw FileException("No volumes were read successfully."); } } catch (FileException& e) { throw CommandException(e); } } /** * Convert a spec file's data files. */ void CommandFileConvert::specFileConvert(const QString& dataFileFormatList, const QString& specFileName) throw (CommandException) { std::vector conversionFormats; const QStringList sl = dataFileFormatList.split(':'); for (int i = 0; i < sl.count(); i++) { const QString formatName(sl.at(i)); bool valid = false; const AbstractFile::FILE_FORMAT format = AbstractFile::convertFormatNameToType(formatName, &valid); if (valid) { conversionFormats.push_back(format); } else { throw CommandException("Invalid file format name \"" + formatName + "\""); } } try { SpecFile sf; sf.readFile(specFileName); sf.convertAllDataFilesToType(conversionFormats, true); } catch (FileException& e) { throw CommandException(e); } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandExtend.h0000664000175000017500000000346111572067322024523 0ustar michaelmichael #ifndef __COMMAND_EXTEND_H__ #define __COMMAND_EXTEND_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandExtend : public CommandBase { public: // constructor CommandExtend(); // destructor ~CommandExtend(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; /// command has no parameters virtual bool commandHasNoParameters() const { return true; } protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_EXTEND_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandExtend.cxx0000664000175000017500000001427411572067322025102 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "CommandExtend.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandExtend::CommandExtend() : CommandBase("-extend", "EXTEND CARET COMMAND (HOW-TO)") { } /** * destructor. */ CommandExtend::~CommandExtend() { } /** * get the script builder parameters. */ void CommandExtend::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); } /** * get full help information. */ QString CommandExtend::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "Describes how to extend caret_command.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandExtend::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { std::cout << "\n" << "HOW TO EXTEND CARET_COMMAND\n" << "\n" << "View some of the existing commands to see how the commands are \n" << "typically written.\n" << "\n" << "Each command is sub-class of CommandBase. Each command has both\n" << "a \".h\" and a \".cxx\" file.\n" << "\n" << "* Build caret from the caret source code. See\n" << " http://brainvis.wustl.edu/CaretHelpAccount/caret5_help/source_code/source_code.html\n" << "\n" << "* In caret_source/caret_command_operations:\n" << " copy COMMAND_STUB.cxx to \"new-command-name\".cxx\n" << " copy COMMAND_STUB.h to \"new-command-name\".h\n" << " Example:\n" << " cp COMMAND_STUB.cxx CommandExtend.cxx\n" << " cp COMMAND_STUB.h CommandExtend.h\n" << "\n" << "* In the new command's \".h\" file, replace all instances of\n" << " __REPLACE_1__ with __COMMAND\"new-command-name\"_H__\n" << " Example: Replace __REPLACE_1__ with __COMMAND_EXTEND_H__ \n" << "\n" << "* In the new command's \".h\" and \".cxx\" files, replace all instances\n" << " of _REPLACE_2_ with the new command's class name. The command's\n" << " name should be the same as the name of the command's .h/.cxx file\n" << " without the extension.\n" << " Example: Replace _REPLACE_2_ with CommandExtend\n" << "\n" << "* In the new command's \".cxx\" file, find the constructor and add\n" << " the parameters passed to the CommandBase constructor. The first\n" << " parameter is the \"switch\" used by caret_command and the second\n" << " parameter is a short description of the command in capital letters.\n" << " Example: CommandBase(\"-\", \"\") becomes\n" << " CommandBase(\"-extend\", \"EXTEND CARET COMMAND (HOW-TO)\")\n" << "\n" << "* In the file CommandBase.cxx, add the name of the new command's \n" << " \".h\" file to the \"#include\" section of the file. In the method\n" << " CommandBase::getAllCommandsUnsorted(CommandBase*>& commandsOut), \n" << " add the new command to the \"commandsOut\" vector. This step makes\n" << " the new command visible to both caret_command and the Caret GUI's\n" << " Command Executor interface.\n" << "\n" << "* Add the name of the new command's \".h\" and \".cxx\" file to the \n" << " file caret_command_operations.pro.\n" << "\n" << "* Run \"qmake\" in the caret_command_operation directory to create\n" << " an updated Makefile from the modified caret_command_operations.pro.\n" << "\n" << "* Run \"make\" to compile the new command's files.\n" << "\n" << "* Run \"make build\" to from the caret_source directory to create\n" << " new versions of caret5 and caret_command.\n" << "\n" << "* Add code to the new command's files and compile. All parameters\n" << " that the user placed on the command line are availble from the\n" << " pointer \"parameters\" which is of type ProgramParameters\n" << " The ProgramParameters class is located in the \n" << " caret_source/caret_common directory. If something goes wrong in the\n" << " command, throw a CommandException.\n" << "\n" << "* Add information to the new command's getHelpInformation() method\n" << " so that user's know how to use the command. Please indicate who\n" << " has written the command and include contact information (email .\n" << " address).\n" << "\n" << "* Update getScriptBuilderParameters() so that the user-interface for\n" << " the command is displayed in the Caret GUI's Command Executor. The\n" << " class ScriptBuilderParameters is located in the \n" << " caret_command_operations directory.\n" << "\n" << "* When the command is ready, send the \".h\" and the \".cxx\" file to\n" << " John Harwell, john@brainvis.wustl.edu so that it can be included in\n" << " the next distribution of Caret.\n" << "\n" << std::endl; } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandException.h0000664000175000017500000000323211572067322025226 0ustar michaelmichael#ifndef __COMMAND_EXCEPTION_H__ #define __COMMAND_EXCEPTION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include class FileException; /// class for an exception for command line programs class CommandException :public std::exception { public: /// Constructor CommandException(const QString& msg); /// Constructor CommandException(const FileException& msg); /// Destructor virtual ~CommandException() throw(); /// get description of exception virtual QString whatQString() const throw(); protected: /// Description of the exception QString description; private: /// get description of exception (private to prevent its use) virtual const char* what() const throw() { return ""; } }; #endif // __COMMAND_EXCEPTION_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandException.cxx0000664000175000017500000000253211572067322025603 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandException.h" #include "FileException.h" /** * Constructor. */ CommandException::CommandException(const QString& msg) { description = msg; } /** * Constructor. */ CommandException::CommandException(const FileException& e) { description = e.whatQString(); } /** * Destructor. */ CommandException::~CommandException() throw() { } /** * get description of exception. */ QString CommandException::whatQString() const throw() { return description; } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandDeformationMapPathUpdate.h0000664000175000017500000000347011572067322030161 0ustar michaelmichael #ifndef __COMMAND_DEFORMATION_MAP_PATH_UPDATE_H__ #define __COMMAND_DEFORMATION_MAP_PATH_UPDATE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandDeformationMapPathUpdate : public CommandBase { public: // constructor CommandDeformationMapPathUpdate(); // destructor ~CommandDeformationMapPathUpdate(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_DEFORMATION_MAP_PATH_UPDATE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandDeformationMapPathUpdate.cxx0000664000175000017500000000647211572067322030541 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandDeformationMapPathUpdate.h" #include "DeformationMapFile.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandDeformationMapPathUpdate::CommandDeformationMapPathUpdate() : CommandBase("-deformation-map-path", "DEFORMATION MAP FILE SOURCE/TARGET PATH UPDATE") { } /** * destructor. */ CommandDeformationMapPathUpdate::~CommandDeformationMapPathUpdate() { } /** * get the script builder parameters. */ void CommandDeformationMapPathUpdate::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Deformation Map File Name", FileFilters::getDeformationMapFileFilter()); paramsOut.addDirectory("Source Path"); paramsOut.addDirectory("Target Path"); } /** * get full help information. */ QString CommandDeformationMapPathUpdate::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + "\n" + indent9 + "Update the source (individual) and target (atlas) paths\n" + indent9 + "in a deformation map file.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandDeformationMapPathUpdate::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the parameters // const QString defMapFileName = parameters->getNextParameterAsString("Deformation Map File"); const QString sourcePath = parameters->getNextParameterAsString("Source Path"); const QString targetPath = parameters->getNextParameterAsString("Target Path"); // // Make sure that are no more parameters // checkForExcessiveParameters(); DeformationMapFile defMapFile; defMapFile.readFile(defMapFileName); defMapFile.setSourceDirectory(sourcePath); defMapFile.setTargetDirectory(targetPath); defMapFile.writeFile(defMapFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandDeformationMapCreate.h0000664000175000017500000000351211572067322027322 0ustar michaelmichael #ifndef __COMMAND_DEFORMATION_MAP_CREATE_H__ #define __COMMAND_DEFORMATION_MAP_CREATE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for creating a deformation map from two surfaces class CommandDeformationMapCreate : public CommandBase { public: // constructor CommandDeformationMapCreate(); // destructor ~CommandDeformationMapCreate(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_DEFORMATION_MAP_CREATE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandDeformationMapCreate.cxx0000664000175000017500000001412011572067322027672 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurface.h" #include "BrainModelSurfaceDeformationMapCreate.h" #include "BrainSet.h" #include "CommandDeformationMapCreate.h" #include "DeformationMapFile.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandDeformationMapCreate::CommandDeformationMapCreate() : CommandBase("-deformation-map-create", "DEFORMATION MAP CREATE") { } /** * destructor. */ CommandDeformationMapCreate::~CommandDeformationMapCreate() { } /** * get the script builder parameters. */ void CommandDeformationMapCreate::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); std::vector surfaceTypeNameAndValue; surfaceTypeNameAndValue.push_back("SPHERE"); paramsOut.addListOfItems("Surface Type", surfaceTypeNameAndValue, surfaceTypeNameAndValue); paramsOut.addFile("Source Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Source Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Target Coordinate File Name", FileFilters::getCoordinateGenericFileFilter()); paramsOut.addFile("Target Topology File Name", FileFilters::getTopologyGenericFileFilter()); paramsOut.addFile("Deformation Map File Name", FileFilters::getDeformationMapFileFilter()); } /** * get full help information. */ QString CommandDeformationMapCreate::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Create a deformation map file that maps data from the \n" + indent9 + "source surface to the target surface. The number of \n" + indent9 + "nodes in the output deformation map file is the number \n" + indent9 + "of nodes in the target surface.\n" + indent9 + "\n" + indent9 + "\"SURFACE_TYPE\" is one of:\n" + indent9 + " SPHERE \n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandDeformationMapCreate::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the inputs // const QString surfaceTypeString = parameters->getNextParameterAsString("SURFACE TYPE"); const QString sourceCoordinateFileName = parameters->getNextParameterAsString("Source Coordinate File Name"); const QString sourceTopologyFileName = parameters->getNextParameterAsString("Source Topology File Name"); const QString targetCoordinateFileName = parameters->getNextParameterAsString("Target Coordinate File Name"); const QString targetTopologyFileName = parameters->getNextParameterAsString("Target Topology File Name"); const QString deformationMapFileName = parameters->getNextParameterAsString("Deformation Map File Name"); checkForExcessiveParameters(); BrainModelSurfaceDeformationMapCreate::DEFORMATION_SURFACE_TYPE defType; if (surfaceTypeString == "SPHERE") { defType = BrainModelSurfaceDeformationMapCreate::DEFORMATION_SURFACE_TYPE_SPHERE; } else { throw CommandException("Invalid surface type: " + surfaceTypeString); } // // Create the source surface // BrainSet sourceBrainSet(sourceTopologyFileName, sourceCoordinateFileName, "", true); BrainModelSurface* sourceSurface = sourceBrainSet.getBrainModelSurface(0); if (sourceSurface == NULL) { throw CommandException("Unable to create source surface."); } // // Create the target surface // BrainSet targetBrainSet(targetTopologyFileName, targetCoordinateFileName); BrainModelSurface* targetSurface = targetBrainSet.getBrainModelSurface(0); if (targetSurface == NULL) { throw CommandException("Unable to create target surface."); } // // Deformation Map File // DeformationMapFile defMapFile; // // Execute the deformation // BrainModelSurfaceDeformationMapCreate bmsdmc(&sourceBrainSet, sourceSurface, targetSurface, &defMapFile, defType); bmsdmc.execute(); // // Write the deformation map file // defMapFile.writeFile(deformationMapFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandDeformationMapApplyGenericNames.h0000664000175000017500000000501111572067322031461 0ustar michaelmichael/* * File: CommandDeformationMapApplyGenericNames.h * Author: john * * Created on April 13, 2010, 3:54 PM */ #ifndef __COMMAND_DEFORMATION_MAP_APPLY_GENERIC_NAMES_H__ #define __COMMAND_DEFORMATION_MAP_APPLY_GENERIC_NAMES_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" class BrainSet; class DeformationMapFile; /// class for applying a deformation map to a data file class CommandDeformationMapApplyGenericNames : public CommandBase { public: // constructor CommandDeformationMapApplyGenericNames(); // destructor ~CommandDeformationMapApplyGenericNames(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); /// Read in BrainSets for applying a deformation map to a data file. void readBrainSetsForDeformation(BrainSet& sourceBrainSet, BrainSet& targetBrainSet, DeformationMapFile& deformationMapFile) throw (BrainModelAlgorithmException, CommandException, FileException); }; #endif /* __COMMAND_DEFORMATION_MAP_APPLY_GENERIC_NAMES_H__ */ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandDeformationMapApplyGenericNames.cxx0000664000175000017500000006730411572067322032051 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelSurface.h" #include "BrainModelSurfaceDeformDataFile.h" #include "BrainSet.h" #include "CommandDeformationMapApplyGenericNames.h" #include "DeformationMapFile.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SpecFile.h" #include "StringUtilities.h" /** * constructor. */ CommandDeformationMapApplyGenericNames::CommandDeformationMapApplyGenericNames() : CommandBase("-deformation-map-apply-generic-names", "DEFORMATION MAP APPLY GENERIC NAMES") { } /** * destructor. */ CommandDeformationMapApplyGenericNames::~CommandDeformationMapApplyGenericNames() { } /** * get the script builder parameters. */ void CommandDeformationMapApplyGenericNames::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { std::vector names; names.push_back("AREAL_ESTIMATION"); names.push_back("BORDER_FLAT"); names.push_back("BORDER_PROJECTION"); names.push_back("BORDER_SPHERICAL"); names.push_back("CELL"); names.push_back("CELL_PROJECTION"); names.push_back("COORDINATE"); names.push_back("COORDINATE_FLAT"); names.push_back("FOCI"); names.push_back("FOCI_PROJECTION"); names.push_back("LAT_LON"); names.push_back("METRIC_AVERAGE_TILE"); names.push_back("METRIC_NEAREST_NODE"); names.push_back("PAINT"); names.push_back("PROB_ATLAS"); names.push_back("RGB_PAINT"); names.push_back("SURFACE_SHAPE"); names.push_back("TOPOGRAPHY"); paramsOut.clear(); paramsOut.addFile("Deformation Map File Name", FileFilters::getDeformationMapFileFilter()); paramsOut.addListOfItems("Data File Type", names, names); paramsOut.addFile("Input Data File Name", FileFilters::getAnyFileFilter()); paramsOut.addFile("Output Data File Name", FileFilters::getAnyFileFilter()); paramsOut.addDirectory("Source Directory Name"); paramsOut.addFile("Source Spec File Name", FileFilters::getSpecFileFilter()); paramsOut.addFile("Source Closed Topology File Name", FileFilters::getTopologyClosedFileFilter()); paramsOut.addFile("Source Spherical Coordinate File Name", FileFilters::getCoordinateSphericalFileFilter()); paramsOut.addFile("Source Deformed Spherical Coordinate File Name", FileFilters::getCoordinateSphericalFileFilter()); paramsOut.addFile("Source Cut Topology File Name", FileFilters::getTopologyCutFileFilter()); paramsOut.addFile("Source Deformed Cut Topology File Name", FileFilters::getTopologyCutFileFilter()); paramsOut.addDirectory("Target Directory Name"); paramsOut.addFile("Target Spec File Name", FileFilters::getSpecFileFilter()); paramsOut.addFile("Target Closed Topology File Name", FileFilters::getTopologyClosedFileFilter()); paramsOut.addFile("Target Spherical Coordinate File Name", FileFilters::getCoordinateSphericalFileFilter()); paramsOut.addFile("Target Cut Topology File Name", FileFilters::getTopologyCutFileFilter()); paramsOut.addFile("Output Spec File Name", FileFilters::getSpecFileFilter()); } /** * get full help information. */ QString CommandDeformationMapApplyGenericNames::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Deform a data file.\n" + indent9 + "\n" + indent9 + "Note: \"source-cut-topology-file-name\", \n" + indent9 + "\"source-deformed-cut-topology-file-name\",\n" + indent9 + "and \"target-cut-topology-file-name\" are only required when\n" + indent9 + "deforming coordinate FLAT files and may be empty strings.\n" + indent9 + "(two consecutive double quotes) when not needed.\n" + indent9 + "\n" + indent9 + "\"data-file-type\" is one of:\n" + indent9 + " AREAL_ESTIMATION \n" + indent9 + " BORDER_FLAT \n" + indent9 + " BORDER_PROJECTION \n" + indent9 + " BORDER_SPHERICAL \n" + indent9 + " CELL \n" + indent9 + " CELL_PROJECTION \n" + indent9 + " COORDINATE \n" + indent9 + " COORDINATE_FLAT \n" + indent9 + " FOCI \n" + indent9 + " FOCI_PROJECTION \n" + indent9 + " LAT_LON \n" + indent9 + " METRIC_AVERAGE_TILE \n" + indent9 + " METRIC_NEAREST_NODE \n" + indent9 + " PAINT \n" + indent9 + " PROB_ATLAS \n" + indent9 + " RGB_PAINT \n" + indent9 + " SURFACE_SHAPE \n" + indent9 + " TOPOGRAPHY \n" + indent9 + "\n" + indent9 + "NOTE:\n" + indent9 + " METRIC_AVERAGE_TILE assigns target surface node average\n" + indent9 + " of nodes from the nearest tile in source surface.\n" + indent9 + " METRIC_NEAREST_NODE assigns target surface node metric\n" + indent9 + " value from nearest source node. Use this mode when\n" + indent9 + " it is important that the metric values are NOT \n" + indent9 + " modified.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandDeformationMapApplyGenericNames::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the parameters // const QString deformationMapFileName = parameters->getNextParameterAsString("Deformation Map File Named"); const QString fileType = parameters->getNextParameterAsString("Data File Type"); const QString dataFileName = parameters->getNextParameterAsString("Input Data File Name"); const QString deformedFileName = parameters->getNextParameterAsString("Output Data File Name"); const QString sourceDirectoryName = parameters->getNextParameterAsString("Source Directory Name"); const QString sourceSpecFileName = parameters->getNextParameterAsString("Source Spec File Name"); const QString sourceClosedTopologyFileName = parameters->getNextParameterAsString("Source Closed Topology File Name"); const QString sourceSphericalCoordinateFileName = parameters->getNextParameterAsString("Source Spherical Coordinate File Name"); const QString sourceDeformedSphericalCoordinateFileName = parameters->getNextParameterAsString("Source Deformed Spherical Coordinate File Name"); const QString sourceCutTopologyFileName = parameters->getNextParameterAsString("Source Cut Topology File Name"); const QString sourceDeformedCutTopologyFileName = parameters->getNextParameterAsString("Source Deformed Cut Topology File Name"); const QString targetDirectoryName = parameters->getNextParameterAsString("Target Directory Name"); const QString targetSpecFileName = parameters->getNextParameterAsString("Target Spec File Name"); const QString targetClosedTopologyFileName = parameters->getNextParameterAsString("Target Closed Topology File Name"); const QString targetSphericalCoordinateFileName = parameters->getNextParameterAsString("Target Spherical Coordinate File Name"); const QString targetCutTopologyFileName = parameters->getNextParameterAsString("Target Cut Topology File Name"); const QString outputSpecFileName = parameters->getNextParameterAsString("Output Spec File Name"); // // Get file type // BrainModelSurfaceDeformDataFile::DATA_FILE_TYPE dft; DeformationMapFile::METRIC_DEFORM_TYPE metricDeformType = DeformationMapFile::METRIC_DEFORM_NEAREST_NODE; if (fileType == "AREAL_ESTIMATION") { dft = BrainModelSurfaceDeformDataFile::DATA_FILE_AREAL_ESTIMATION; } else if (fileType == "BORDER_FLAT") { dft = BrainModelSurfaceDeformDataFile::DATA_FILE_BORDER_FLAT; } else if (fileType == "BORDER_SPHERICAL") { dft = BrainModelSurfaceDeformDataFile::DATA_FILE_BORDER_SPHERICAL; } else if (fileType == "BORDER_PROJECTION") { dft = BrainModelSurfaceDeformDataFile::DATA_FILE_BORDER_PROJECTION; } else if (fileType == "CELL") { dft = BrainModelSurfaceDeformDataFile::DATA_FILE_CELL; } else if (fileType == "CELL_PROJECTION") { dft = BrainModelSurfaceDeformDataFile::DATA_FILE_CELL_PROJECTION; } else if (fileType == "COORDINATE") { dft = BrainModelSurfaceDeformDataFile::DATA_FILE_COORDINATE; } else if (fileType == "COORDINATE_FLAT") { dft = BrainModelSurfaceDeformDataFile::DATA_FILE_COORDINATE_FLAT; } else if (fileType == "FOCI") { dft = BrainModelSurfaceDeformDataFile::DATA_FILE_FOCI; } else if (fileType == "FOCI_PROJECTION") { dft = BrainModelSurfaceDeformDataFile::DATA_FILE_FOCI_PROJECTION; } else if (fileType == "LAT_LON") { dft = BrainModelSurfaceDeformDataFile::DATA_FILE_LAT_LON; } else if (fileType == "METRIC_AVERAGE_TILE") { dft = BrainModelSurfaceDeformDataFile::DATA_FILE_METRIC; metricDeformType = DeformationMapFile::METRIC_DEFORM_AVERAGE_TILE_NODES; } else if (fileType == "METRIC_NEAREST_NODE") { dft = BrainModelSurfaceDeformDataFile::DATA_FILE_METRIC; metricDeformType = DeformationMapFile::METRIC_DEFORM_NEAREST_NODE; } else if (fileType == "PAINT") { dft = BrainModelSurfaceDeformDataFile::DATA_FILE_PAINT; } else if (fileType == "PROB_ATLAS") { dft = BrainModelSurfaceDeformDataFile::DATA_FILE_ATLAS; } else if (fileType == "RGB_PAINT") { dft = BrainModelSurfaceDeformDataFile::DATA_FILE_RGB_PAINT; } else if (fileType == "SURFACE_SHAPE") { dft = BrainModelSurfaceDeformDataFile::DATA_FILE_SHAPE; } else if (fileType == "TOPOGRAPHY") { dft = BrainModelSurfaceDeformDataFile::DATA_FILE_TOPOGRAPHY; } else { QString msg("Invalid file type: \""); msg.append(fileType); msg.append("\"\n"); throw CommandException(msg); } // // Read the deformation map file // DeformationMapFile deformationMapFile; deformationMapFile.readFile(deformationMapFileName); // // Update names in the deformation map file // deformationMapFile.setSourceClosedTopoFileName(sourceClosedTopologyFileName); deformationMapFile.setSourceCutTopoFileName(sourceCutTopologyFileName); deformationMapFile.setSourceDeformedSphericalCoordFileName(sourceDeformedSphericalCoordinateFileName); deformationMapFile.setSourceDirectory(sourceDirectoryName); deformationMapFile.setSourceSpecFileName(sourceSpecFileName); deformationMapFile.setSourceSphericalCoordFileName(sourceSphericalCoordinateFileName); deformationMapFile.setTargetClosedTopoFileName(targetClosedTopologyFileName); deformationMapFile.setTargetCutTopoFileName(targetCutTopologyFileName); deformationMapFile.setTargetDirectory(targetDirectoryName); deformationMapFile.setTargetSpecFileName(targetSpecFileName); deformationMapFile.setTargetSphericalCoordFileName(targetSphericalCoordinateFileName); deformationMapFile.setOutputSpecFileName(outputSpecFileName); if (deformationMapFile.getFileVersion() >= 2) { QString msg; if (QFile::exists(deformationMapFile.getSourceDirectory()) == false) { msg.append("Individual directory is invalid. Change the\n" "individual directory to the directory containing\n" "the individual spec file."); } if (QFile::exists(deformationMapFile.getTargetDirectory()) == false) { msg.append("Atlas directory is invalid. Change the\n" "atlas directory to the directory containing\n" "the atlas spec file."); } if (msg.isEmpty() == false) { throw CommandException(msg); } } // // Read the brain sets if needed // BrainSet sourceBrainSet, targetBrainSet; switch(dft) { case BrainModelSurfaceDeformDataFile::DATA_FILE_AREAL_ESTIMATION: case BrainModelSurfaceDeformDataFile::DATA_FILE_ATLAS: case BrainModelSurfaceDeformDataFile::DATA_FILE_COORDINATE: case BrainModelSurfaceDeformDataFile::DATA_FILE_COORDINATE_FLAT: case BrainModelSurfaceDeformDataFile::DATA_FILE_LAT_LON: case BrainModelSurfaceDeformDataFile::DATA_FILE_METRIC: case BrainModelSurfaceDeformDataFile::DATA_FILE_PAINT: case BrainModelSurfaceDeformDataFile::DATA_FILE_RGB_PAINT: case BrainModelSurfaceDeformDataFile::DATA_FILE_SHAPE: case BrainModelSurfaceDeformDataFile::DATA_FILE_TOPOGRAPHY: break; case BrainModelSurfaceDeformDataFile::DATA_FILE_BORDER_FLAT: case BrainModelSurfaceDeformDataFile::DATA_FILE_BORDER_SPHERICAL: case BrainModelSurfaceDeformDataFile::DATA_FILE_BORDER_PROJECTION: case BrainModelSurfaceDeformDataFile::DATA_FILE_CELL: case BrainModelSurfaceDeformDataFile::DATA_FILE_CELL_PROJECTION: case BrainModelSurfaceDeformDataFile::DATA_FILE_FOCI: case BrainModelSurfaceDeformDataFile::DATA_FILE_FOCI_PROJECTION: readBrainSetsForDeformation(sourceBrainSet, targetBrainSet, deformationMapFile); break; } if (deformationMapFile.getFileVersion() >= 2) { // // Prepend with path // QString name(deformationMapFile.getTargetDirectory()); name.append("/"); name.append(deformationMapFile.getOutputSpecFileName()); deformationMapFile.setOutputSpecFileName(name); } // // set metric deformation // deformationMapFile.setMetricDeformationType(metricDeformType); // // Deform the data file // switch(dft) { case BrainModelSurfaceDeformDataFile::DATA_FILE_AREAL_ESTIMATION: case BrainModelSurfaceDeformDataFile::DATA_FILE_ATLAS: case BrainModelSurfaceDeformDataFile::DATA_FILE_LAT_LON: case BrainModelSurfaceDeformDataFile::DATA_FILE_RGB_PAINT: case BrainModelSurfaceDeformDataFile::DATA_FILE_TOPOGRAPHY: BrainModelSurfaceDeformDataFile::deformNodeAttributeFile(&deformationMapFile, dft, false, dataFileName, deformedFileName); break; case BrainModelSurfaceDeformDataFile::DATA_FILE_METRIC: case BrainModelSurfaceDeformDataFile::DATA_FILE_PAINT: case BrainModelSurfaceDeformDataFile::DATA_FILE_SHAPE: BrainModelSurfaceDeformDataFile::deformGiftiNodeDataFile(&deformationMapFile, dft, false, dataFileName, deformedFileName); break; case BrainModelSurfaceDeformDataFile::DATA_FILE_COORDINATE: { QString deformedFileName2(deformedFileName); BrainModelSurfaceDeformDataFile::deformCoordinateFile(&deformationMapFile, dataFileName, deformedFileName2, true, false); } break; case BrainModelSurfaceDeformDataFile::DATA_FILE_COORDINATE_FLAT: BrainModelSurfaceDeformDataFile::deformFlatCoordinateFile( &deformationMapFile, targetCutTopologyFileName, false, dataFileName, sourceCutTopologyFileName, deformedFileName, sourceDeformedCutTopologyFileName, 10.0); //flatCoordMaxEdgeLengthFloatSpinBox->floatValue()); break; case BrainModelSurfaceDeformDataFile::DATA_FILE_BORDER_FLAT: case BrainModelSurfaceDeformDataFile::DATA_FILE_BORDER_SPHERICAL: case BrainModelSurfaceDeformDataFile::DATA_FILE_BORDER_PROJECTION: BrainModelSurfaceDeformDataFile::deformBorderFile( &sourceBrainSet, &targetBrainSet, &deformationMapFile, false, dft, dataFileName, deformedFileName); break; case BrainModelSurfaceDeformDataFile::DATA_FILE_CELL: BrainModelSurfaceDeformDataFile::deformCellOrFociFile( &sourceBrainSet, &targetBrainSet, &deformationMapFile, false, dataFileName, false, deformedFileName); break; case BrainModelSurfaceDeformDataFile::DATA_FILE_CELL_PROJECTION: BrainModelSurfaceDeformDataFile::deformCellOrFociProjectionFile( &sourceBrainSet, &targetBrainSet, &deformationMapFile, false, dataFileName, false, deformedFileName); break; case BrainModelSurfaceDeformDataFile::DATA_FILE_FOCI: BrainModelSurfaceDeformDataFile::deformCellOrFociFile( &sourceBrainSet, &targetBrainSet, &deformationMapFile, false, dataFileName, true, deformedFileName); break; case BrainModelSurfaceDeformDataFile::DATA_FILE_FOCI_PROJECTION: BrainModelSurfaceDeformDataFile::deformCellOrFociProjectionFile( &sourceBrainSet, &targetBrainSet, &deformationMapFile, false, dataFileName, true, deformedFileName); break; } } /*---------------------------------------------------------------------------------------- * Read in BrainSets for applying a deformation map to a data file. */ void CommandDeformationMapApplyGenericNames::readBrainSetsForDeformation(BrainSet& sourceBrainSet, BrainSet& targetBrainSet, DeformationMapFile& deformationMapFile) throw (BrainModelAlgorithmException, CommandException, FileException) { const QString savedDirectory(QDir::currentPath()); // // create source brain set // bool sourceSpecMissing = true; SpecFile sourceSpecFile; try { QString specFileName; if (deformationMapFile.getFileVersion() >= 2) { specFileName.append(deformationMapFile.getSourceDirectory()); specFileName.append("/"); } specFileName.append(deformationMapFile.getSourceSpecFileName()); sourceSpecFile.readFile(specFileName); sourceSpecMissing = false; } catch (FileException& e) { // // David has a bad habit of renaming spec files, so just hope the // data files are still the same name and in the same location. // QDir::setCurrent(deformationMapFile.getSourceDirectory()); //errorMessage = e.whatQString().toAscii().constData()); //return true; } // // Select the deformation files // sourceSpecFile.setDeformationSelectedFiles( deformationMapFile.getSourceClosedTopoFileName(), deformationMapFile.getSourceCutTopoFileName(), deformationMapFile.getSourceFiducialCoordFileName(), deformationMapFile.getSourceSphericalCoordFileName(), deformationMapFile.getSourceFlatCoordFileName(), "", sourceSpecMissing, sourceSpecFile.getStructure()); // // Read in the source brain set // std::vector errorMessages; sourceBrainSet.readSpecFile(BrainSet::SPEC_FILE_READ_MODE_NORMAL, sourceSpecFile, deformationMapFile.getSourceSpecFileName(), errorMessages, NULL, NULL); if (errorMessages.empty() == false) { if (sourceSpecMissing) { errorMessages.push_back("Source spec file was not found.\n" "Tried to load data files.\n"); } const QString errorMessage = StringUtilities::combine(errorMessages, "\n"); throw CommandException(errorMessage); } // // Read in the deformed coordinate file // if (deformationMapFile.getInverseDeformationFlag() == false) { QString coordFileName; BrainModelSurface::SURFACE_TYPES surfaceType = BrainModelSurface::SURFACE_TYPE_UNKNOWN; switch(deformationMapFile.getFlatOrSphereSelection()) { case DeformationMapFile::DEFORMATION_TYPE_FLAT: coordFileName = deformationMapFile.getSourceDeformedFlatCoordFileName(); surfaceType = BrainModelSurface::SURFACE_TYPE_FLAT; break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: coordFileName = deformationMapFile.getSourceDeformedSphericalCoordFileName(); surfaceType = BrainModelSurface::SURFACE_TYPE_SPHERICAL; break; } if (coordFileName.isEmpty()) { throw CommandException("Deformed source coordinate file is missing."); } sourceBrainSet.readCoordinateFile(coordFileName, surfaceType, false, true, false); } QDir::setCurrent(savedDirectory); // // Read in the target spec file // bool targetSpecMissing = true; SpecFile targetSpecFile; try { QString specFileName; if (deformationMapFile.getFileVersion() >= 2) { specFileName.append(deformationMapFile.getTargetDirectory()); specFileName.append("/"); } specFileName.append(deformationMapFile.getTargetSpecFileName()); targetSpecFile.readFile(specFileName); targetSpecMissing = false; } catch (FileException& e) { // // David has a bad habit of renaming spec files, so just hope the // data files are still the same name and in the same location. // QDir::setCurrent(deformationMapFile.getSourceDirectory()); //errorMessage = e.whatQString().toAscii().constData()); //return true; } // // Select the deformation files // targetSpecFile.setDeformationSelectedFiles( deformationMapFile.getTargetClosedTopoFileName(), deformationMapFile.getTargetCutTopoFileName(), deformationMapFile.getTargetFiducialCoordFileName(), deformationMapFile.getTargetSphericalCoordFileName(), deformationMapFile.getTargetFlatCoordFileName(), "", targetSpecMissing, targetSpecFile.getStructure()); // // Read in the target brain set // errorMessages.clear(); targetBrainSet.readSpecFile(BrainSet::SPEC_FILE_READ_MODE_NORMAL, targetSpecFile, deformationMapFile.getTargetSpecFileName(), errorMessages, NULL, NULL); if (errorMessages.empty() == false) { if (targetSpecMissing) { errorMessages.push_back("Target spec file was not found.\n" "Tried to load data files.\n"); } const QString errorMessage = StringUtilities::combine(errorMessages, "\n"); throw CommandException(errorMessage); } // // Read in the deformed coordinate file // if (deformationMapFile.getInverseDeformationFlag()) { QString coordFileName; BrainModelSurface::SURFACE_TYPES surfaceType = BrainModelSurface::SURFACE_TYPE_UNKNOWN; switch(deformationMapFile.getFlatOrSphereSelection()) { case DeformationMapFile::DEFORMATION_TYPE_FLAT: coordFileName = deformationMapFile.getSourceDeformedFlatCoordFileName(); surfaceType = BrainModelSurface::SURFACE_TYPE_FLAT; break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: coordFileName = deformationMapFile.getSourceDeformedSphericalCoordFileName(); surfaceType = BrainModelSurface::SURFACE_TYPE_SPHERICAL; break; } if (coordFileName.isEmpty()) { throw CommandException("Deformed source coordinate file is missing."); } targetBrainSet.readCoordinateFile(coordFileName, surfaceType, false, true, false); } QDir::setCurrent(savedDirectory); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandDeformationMapApply.h0000664000175000017500000000453311572067322027210 0ustar michaelmichael #ifndef __COMMAND_DEFORMATION_MAP_APPLY_H__ #define __COMMAND_DEFORMATION_MAP_APPLY_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" class BrainSet; class DeformationMapFile; /// class for applying a deformation map to a data file class CommandDeformationMapApply : public CommandBase { public: // constructor CommandDeformationMapApply(); // destructor ~CommandDeformationMapApply(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); /// Read in BrainSets for applying a deformation map to a data file. void readBrainSetsForDeformation(BrainSet& sourceBrainSet, BrainSet& targetBrainSet, DeformationMapFile& deformationMapFile) throw (BrainModelAlgorithmException, CommandException, FileException); }; #endif // __COMMAND_DEFORMATION_MAP_APPLY_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandDeformationMapApply.cxx0000664000175000017500000005704511572067322027571 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelSurface.h" #include "BrainModelSurfaceDeformDataFile.h" #include "BrainSet.h" #include "CommandDeformationMapApply.h" #include "DeformationMapFile.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SpecFile.h" #include "StringUtilities.h" /** * constructor. */ CommandDeformationMapApply::CommandDeformationMapApply() : CommandBase("-deformation-map-apply", "DEFORMATION MAP APPLY") { } /** * destructor. */ CommandDeformationMapApply::~CommandDeformationMapApply() { } /** * get the script builder parameters. */ void CommandDeformationMapApply::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { std::vector names; names.push_back("AREAL_ESTIMATION"); names.push_back("BORDER_FLAT"); names.push_back("BORDER_PROJECTION"); names.push_back("BORDER_SPHERICAL"); names.push_back("CELL"); names.push_back("CELL_PROJECTION"); names.push_back("COORDINATE"); names.push_back("COORDINATE_FLAT"); names.push_back("FOCI"); names.push_back("FOCI_PROJECTION"); names.push_back("LAT_LON"); names.push_back("METRIC_AVERAGE_TILE"); names.push_back("METRIC_NEAREST_NODE"); names.push_back("PAINT"); names.push_back("PROB_ATLAS"); names.push_back("RGB_PAINT"); names.push_back("SURFACE_SHAPE"); names.push_back("TOPOGRAPHY"); paramsOut.clear(); paramsOut.addFile("Deformation Map File Name", FileFilters::getDeformationMapFileFilter()); paramsOut.addListOfItems("Data File Type", names, names); paramsOut.addFile("Input Data File Name", FileFilters::getAnyFileFilter()); paramsOut.addFile("Output Data File Name", FileFilters::getAnyFileFilter()); paramsOut.addVariableListOfParameters("Deformation Options"); } /** * get full help information. */ QString CommandDeformationMapApply::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[source-topology-file-name\n" + indent9 + " source-deformed-topology-file-name\n" + indent9 + " target-topology-file-name]\n" + indent9 + "\n" + indent9 + "Deform a data file.\n" + indent9 + "\n" + indent9 + "Note: \"source-topology-file-name\", \n" + indent9 + "\"source-deformed-topology-file-name\",\n" + indent9 + "and \"target-topology-file-name\" are only required when\n" + indent9 + "deforming coordinate FLAT files.\n" + indent9 + "\n" + indent9 + "\"data-file-type\" is one of:\n" + indent9 + " AREAL_ESTIMATION \n" + indent9 + " BORDER_FLAT \n" + indent9 + " BORDER_PROJECTION \n" + indent9 + " BORDER_SPHERICAL \n" + indent9 + " CELL \n" + indent9 + " CELL_PROJECTION \n" + indent9 + " COORDINATE \n" + indent9 + " COORDINATE_FLAT \n" + indent9 + " FOCI \n" + indent9 + " FOCI_PROJECTION \n" + indent9 + " LAT_LON \n" + indent9 + " METRIC_AVERAGE_TILE \n" + indent9 + " METRIC_NEAREST_NODE \n" + indent9 + " PAINT \n" + indent9 + " PROB_ATLAS \n" + indent9 + " RGB_PAINT \n" + indent9 + " SURFACE_SHAPE \n" + indent9 + " TOPOGRAPHY \n" + indent9 + "\n" + indent9 + "NOTE:\n" + indent9 + " METRIC_AVERAGE_TILE assigns target surface node average\n" + indent9 + " of nodes from the nearest tile in source surface.\n" + indent9 + " METRIC_NEAREST_NODE assigns target surface node metric\n" + indent9 + " value from nearest source node. Use this mode when\n" + indent9 + " it is important that the metric values are NOT \n" + indent9 + " modified.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandDeformationMapApply::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the parameters // const QString deformationMapFileName = parameters->getNextParameterAsString("Deformation Map File Named"); const QString fileType = parameters->getNextParameterAsString("Data File Type"); const QString dataFileName = parameters->getNextParameterAsString("Input Data File Name"); const QString deformedFileName = parameters->getNextParameterAsString("Output Data File Name"); QString indivTopoFileName; QString indivDeformTopoFileName; QString atlasTopoFileName; if (fileType == "COORDINATE-FLAT") { indivTopoFileName = parameters->getNextParameterAsString("Source Topology File Name"); indivDeformTopoFileName = parameters->getNextParameterAsString("Source Deformed Topology File Name"); atlasTopoFileName = parameters->getNextParameterAsString("Target Topology File Name"); } // // Get file type // BrainModelSurfaceDeformDataFile::DATA_FILE_TYPE dft; DeformationMapFile::METRIC_DEFORM_TYPE metricDeformType = DeformationMapFile::METRIC_DEFORM_NEAREST_NODE; if (fileType == "AREAL_ESTIMATION") { dft = BrainModelSurfaceDeformDataFile::DATA_FILE_AREAL_ESTIMATION; } else if (fileType == "BORDER_FLAT") { dft = BrainModelSurfaceDeformDataFile::DATA_FILE_BORDER_FLAT; } else if (fileType == "BORDER_SPHERICAL") { dft = BrainModelSurfaceDeformDataFile::DATA_FILE_BORDER_SPHERICAL; } else if (fileType == "BORDER_PROJECTION") { dft = BrainModelSurfaceDeformDataFile::DATA_FILE_BORDER_PROJECTION; } else if (fileType == "CELL") { dft = BrainModelSurfaceDeformDataFile::DATA_FILE_CELL; } else if (fileType == "CELL_PROJECTION") { dft = BrainModelSurfaceDeformDataFile::DATA_FILE_CELL_PROJECTION; } else if (fileType == "COORDINATE") { dft = BrainModelSurfaceDeformDataFile::DATA_FILE_COORDINATE; } else if (fileType == "COORDINATE_FLAT") { dft = BrainModelSurfaceDeformDataFile::DATA_FILE_COORDINATE_FLAT; } else if (fileType == "FOCI") { dft = BrainModelSurfaceDeformDataFile::DATA_FILE_FOCI; } else if (fileType == "FOCI_PROJECTION") { dft = BrainModelSurfaceDeformDataFile::DATA_FILE_FOCI_PROJECTION; } else if (fileType == "LAT_LON") { dft = BrainModelSurfaceDeformDataFile::DATA_FILE_LAT_LON; } else if (fileType == "METRIC_AVERAGE_TILE") { dft = BrainModelSurfaceDeformDataFile::DATA_FILE_METRIC; metricDeformType = DeformationMapFile::METRIC_DEFORM_AVERAGE_TILE_NODES; } else if (fileType == "METRIC_NEAREST_NODE") { dft = BrainModelSurfaceDeformDataFile::DATA_FILE_METRIC; metricDeformType = DeformationMapFile::METRIC_DEFORM_NEAREST_NODE; } else if (fileType == "PAINT") { dft = BrainModelSurfaceDeformDataFile::DATA_FILE_PAINT; } else if (fileType == "PROB_ATLAS") { dft = BrainModelSurfaceDeformDataFile::DATA_FILE_ATLAS; } else if (fileType == "RGB_PAINT") { dft = BrainModelSurfaceDeformDataFile::DATA_FILE_RGB_PAINT; } else if (fileType == "SURFACE_SHAPE") { dft = BrainModelSurfaceDeformDataFile::DATA_FILE_SHAPE; } else if (fileType == "TOPOGRAPHY") { dft = BrainModelSurfaceDeformDataFile::DATA_FILE_TOPOGRAPHY; } else { QString msg("Invalid file type: \""); msg.append(fileType); msg.append("\"\n"); throw CommandException(msg); } // // Read the deformation map file // DeformationMapFile deformationMapFile; deformationMapFile.readFile(deformationMapFileName); if (deformationMapFile.getFileVersion() >= 2) { QString msg; if (QFile::exists(deformationMapFile.getSourceDirectory()) == false) { msg.append("Individual directory is invalid. Change the\n" "individual directory to the directory containing\n" "the individual spec file."); } if (QFile::exists(deformationMapFile.getTargetDirectory()) == false) { msg.append("Atlas directory is invalid. Change the\n" "atlas directory to the directory containing\n" "the atlas spec file."); } if (msg.isEmpty() == false) { throw CommandException(msg); } } // // Read the brain sets if needed // BrainSet sourceBrainSet, targetBrainSet; switch(dft) { case BrainModelSurfaceDeformDataFile::DATA_FILE_AREAL_ESTIMATION: case BrainModelSurfaceDeformDataFile::DATA_FILE_ATLAS: case BrainModelSurfaceDeformDataFile::DATA_FILE_COORDINATE: case BrainModelSurfaceDeformDataFile::DATA_FILE_COORDINATE_FLAT: case BrainModelSurfaceDeformDataFile::DATA_FILE_LAT_LON: case BrainModelSurfaceDeformDataFile::DATA_FILE_METRIC: case BrainModelSurfaceDeformDataFile::DATA_FILE_PAINT: case BrainModelSurfaceDeformDataFile::DATA_FILE_RGB_PAINT: case BrainModelSurfaceDeformDataFile::DATA_FILE_SHAPE: case BrainModelSurfaceDeformDataFile::DATA_FILE_TOPOGRAPHY: break; case BrainModelSurfaceDeformDataFile::DATA_FILE_BORDER_FLAT: case BrainModelSurfaceDeformDataFile::DATA_FILE_BORDER_SPHERICAL: case BrainModelSurfaceDeformDataFile::DATA_FILE_BORDER_PROJECTION: case BrainModelSurfaceDeformDataFile::DATA_FILE_CELL: case BrainModelSurfaceDeformDataFile::DATA_FILE_CELL_PROJECTION: case BrainModelSurfaceDeformDataFile::DATA_FILE_FOCI: case BrainModelSurfaceDeformDataFile::DATA_FILE_FOCI_PROJECTION: readBrainSetsForDeformation(sourceBrainSet, targetBrainSet, deformationMapFile); break; } if (deformationMapFile.getFileVersion() >= 2) { // // Prepend with path // QString name(deformationMapFile.getTargetDirectory()); name.append("/"); name.append(deformationMapFile.getOutputSpecFileName()); deformationMapFile.setOutputSpecFileName(name); } // // set metric deformation // deformationMapFile.setMetricDeformationType(metricDeformType); // // Deform the data file // switch(dft) { case BrainModelSurfaceDeformDataFile::DATA_FILE_AREAL_ESTIMATION: case BrainModelSurfaceDeformDataFile::DATA_FILE_ATLAS: case BrainModelSurfaceDeformDataFile::DATA_FILE_LAT_LON: case BrainModelSurfaceDeformDataFile::DATA_FILE_RGB_PAINT: case BrainModelSurfaceDeformDataFile::DATA_FILE_TOPOGRAPHY: BrainModelSurfaceDeformDataFile::deformNodeAttributeFile(&deformationMapFile, dft, false, dataFileName, deformedFileName); break; case BrainModelSurfaceDeformDataFile::DATA_FILE_METRIC: case BrainModelSurfaceDeformDataFile::DATA_FILE_PAINT: case BrainModelSurfaceDeformDataFile::DATA_FILE_SHAPE: BrainModelSurfaceDeformDataFile::deformGiftiNodeDataFile(&deformationMapFile, dft, false, dataFileName, deformedFileName); break; case BrainModelSurfaceDeformDataFile::DATA_FILE_COORDINATE: { QString deformedFileName2(deformedFileName); BrainModelSurfaceDeformDataFile::deformCoordinateFile(&deformationMapFile, dataFileName, deformedFileName2, true, false); } break; case BrainModelSurfaceDeformDataFile::DATA_FILE_COORDINATE_FLAT: BrainModelSurfaceDeformDataFile::deformFlatCoordinateFile( &deformationMapFile, atlasTopoFileName, false, dataFileName, indivTopoFileName, deformedFileName, indivDeformTopoFileName, 10.0); //flatCoordMaxEdgeLengthFloatSpinBox->floatValue()); break; case BrainModelSurfaceDeformDataFile::DATA_FILE_BORDER_FLAT: case BrainModelSurfaceDeformDataFile::DATA_FILE_BORDER_SPHERICAL: case BrainModelSurfaceDeformDataFile::DATA_FILE_BORDER_PROJECTION: BrainModelSurfaceDeformDataFile::deformBorderFile( &sourceBrainSet, &targetBrainSet, &deformationMapFile, false, dft, dataFileName, deformedFileName); break; case BrainModelSurfaceDeformDataFile::DATA_FILE_CELL: BrainModelSurfaceDeformDataFile::deformCellOrFociFile( &sourceBrainSet, &targetBrainSet, &deformationMapFile, false, dataFileName, false, deformedFileName); break; case BrainModelSurfaceDeformDataFile::DATA_FILE_CELL_PROJECTION: BrainModelSurfaceDeformDataFile::deformCellOrFociProjectionFile( &sourceBrainSet, &targetBrainSet, &deformationMapFile, false, dataFileName, false, deformedFileName); break; case BrainModelSurfaceDeformDataFile::DATA_FILE_FOCI: BrainModelSurfaceDeformDataFile::deformCellOrFociFile( &sourceBrainSet, &targetBrainSet, &deformationMapFile, false, dataFileName, true, deformedFileName); break; case BrainModelSurfaceDeformDataFile::DATA_FILE_FOCI_PROJECTION: BrainModelSurfaceDeformDataFile::deformCellOrFociProjectionFile( &sourceBrainSet, &targetBrainSet, &deformationMapFile, false, dataFileName, true, deformedFileName); break; } } /*---------------------------------------------------------------------------------------- * Read in BrainSets for applying a deformation map to a data file. */ void CommandDeformationMapApply::readBrainSetsForDeformation(BrainSet& sourceBrainSet, BrainSet& targetBrainSet, DeformationMapFile& deformationMapFile) throw (BrainModelAlgorithmException, CommandException, FileException) { const QString savedDirectory(QDir::currentPath()); // // create source brain set // bool sourceSpecMissing = true; SpecFile sourceSpecFile; try { QString specFileName; if (deformationMapFile.getFileVersion() >= 2) { specFileName.append(deformationMapFile.getSourceDirectory()); specFileName.append("/"); } specFileName.append(deformationMapFile.getSourceSpecFileName()); sourceSpecFile.readFile(specFileName); sourceSpecMissing = false; } catch (FileException& e) { // // David has a bad habit of renaming spec files, so just hope the // data files are still the same name and in the same location. // QDir::setCurrent(deformationMapFile.getSourceDirectory()); //errorMessage = e.whatQString().toAscii().constData()); //return true; } // // Select the deformation files // sourceSpecFile.setDeformationSelectedFiles( deformationMapFile.getSourceClosedTopoFileName(), deformationMapFile.getSourceCutTopoFileName(), deformationMapFile.getSourceFiducialCoordFileName(), deformationMapFile.getSourceSphericalCoordFileName(), deformationMapFile.getSourceFlatCoordFileName(), "", sourceSpecMissing, sourceSpecFile.getStructure()); // // Read in the source brain set // std::vector errorMessages; sourceBrainSet.readSpecFile(BrainSet::SPEC_FILE_READ_MODE_NORMAL, sourceSpecFile, deformationMapFile.getSourceSpecFileName(), errorMessages, NULL, NULL); if (errorMessages.empty() == false) { if (sourceSpecMissing) { errorMessages.push_back("Source spec file was not found.\n" "Tried to load data files.\n"); } const QString errorMessage = StringUtilities::combine(errorMessages, "\n"); throw CommandException(errorMessage); } // // Read in the deformed coordinate file // if (deformationMapFile.getInverseDeformationFlag() == false) { QString coordFileName; BrainModelSurface::SURFACE_TYPES surfaceType = BrainModelSurface::SURFACE_TYPE_UNKNOWN; switch(deformationMapFile.getFlatOrSphereSelection()) { case DeformationMapFile::DEFORMATION_TYPE_FLAT: coordFileName = deformationMapFile.getSourceDeformedFlatCoordFileName(); surfaceType = BrainModelSurface::SURFACE_TYPE_FLAT; break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: coordFileName = deformationMapFile.getSourceDeformedSphericalCoordFileName(); surfaceType = BrainModelSurface::SURFACE_TYPE_SPHERICAL; break; } if (coordFileName.isEmpty()) { throw CommandException("Deformed source coordinate file is missing."); } sourceBrainSet.readCoordinateFile(coordFileName, surfaceType, false, true, false); } QDir::setCurrent(savedDirectory); // // Read in the target spec file // bool targetSpecMissing = true; SpecFile targetSpecFile; try { QString specFileName; if (deformationMapFile.getFileVersion() >= 2) { specFileName.append(deformationMapFile.getTargetDirectory()); specFileName.append("/"); } specFileName.append(deformationMapFile.getTargetSpecFileName()); targetSpecFile.readFile(specFileName); targetSpecMissing = false; } catch (FileException& e) { // // David has a bad habit of renaming spec files, so just hope the // data files are still the same name and in the same location. // QDir::setCurrent(deformationMapFile.getSourceDirectory()); //errorMessage = e.whatQString().toAscii().constData()); //return true; } // // Select the deformation files // targetSpecFile.setDeformationSelectedFiles( deformationMapFile.getTargetClosedTopoFileName(), deformationMapFile.getTargetCutTopoFileName(), deformationMapFile.getTargetFiducialCoordFileName(), deformationMapFile.getTargetSphericalCoordFileName(), deformationMapFile.getTargetFlatCoordFileName(), "", targetSpecMissing, targetSpecFile.getStructure()); // // Read in the target brain set // errorMessages.clear(); targetBrainSet.readSpecFile(BrainSet::SPEC_FILE_READ_MODE_NORMAL, targetSpecFile, deformationMapFile.getTargetSpecFileName(), errorMessages, NULL, NULL); if (errorMessages.empty() == false) { if (targetSpecMissing) { errorMessages.push_back("Target spec file was not found.\n" "Tried to load data files.\n"); } const QString errorMessage = StringUtilities::combine(errorMessages, "\n"); throw CommandException(errorMessage); } // // Read in the deformed coordinate file // if (deformationMapFile.getInverseDeformationFlag()) { QString coordFileName; BrainModelSurface::SURFACE_TYPES surfaceType = BrainModelSurface::SURFACE_TYPE_UNKNOWN; switch(deformationMapFile.getFlatOrSphereSelection()) { case DeformationMapFile::DEFORMATION_TYPE_FLAT: coordFileName = deformationMapFile.getSourceDeformedFlatCoordFileName(); surfaceType = BrainModelSurface::SURFACE_TYPE_FLAT; break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: coordFileName = deformationMapFile.getSourceDeformedSphericalCoordFileName(); surfaceType = BrainModelSurface::SURFACE_TYPE_SPHERICAL; break; } if (coordFileName.isEmpty()) { throw CommandException("Deformed source coordinate file is missing."); } targetBrainSet.readCoordinateFile(coordFileName, surfaceType, false, true, false); } QDir::setCurrent(savedDirectory); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandDataFileCompare.h0000664000175000017500000000337111572067322026254 0ustar michaelmichael #ifndef __COMMAND_DATA_FILE_COMPARE_H__ #define __COMMAND_DATA_FILE_COMPARE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandDataFileCompare : public CommandBase { public: // constructor CommandDataFileCompare(); // destructor ~CommandDataFileCompare(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_DATA_FILE_COMPARE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandDataFileCompare.cxx0000664000175000017500000001007311572067322026624 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "AbstractFile.h" #include "CommandDataFileCompare.h" #include "FileFilters.h" #include "FileUtilities.h" #include "ProgramParameters.h" /** * constructor. */ CommandDataFileCompare::CommandDataFileCompare() : CommandBase("-caret-data-file-compare", "CARET DATA FILE COMPARISON") { } /** * destructor. */ CommandDataFileCompare::~CommandDataFileCompare() { } /** * get the script builder parameters. */ void CommandDataFileCompare::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Caret Data File 1", FileFilters::getAnyFileFilter()); paramsOut.addFile("Caret Data File 2", FileFilters::getAnyFileFilter()); paramsOut.addFloat("Tolerance", 0.01, 0.0); } /** * get full help information. */ QString CommandDataFileCompare::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + "[tolerance]\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandDataFileCompare::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the parameters // const QString dataFileName1 = parameters->getNextParameterAsString("Caret Data File 1 Name"); const QString dataFileName2 = parameters->getNextParameterAsString("Caret Data File 2 Name"); float tolerance = 0.0; if (parameters->getParametersAvailable()) { tolerance = parameters->getNextParameterAsFloat("Tolerance"); } QString errorMessage; AbstractFile* af1 = AbstractFile::readAnySubClassDataFile(dataFileName1, false, errorMessage); if (af1 == NULL) { throw CommandException(errorMessage); } errorMessage = ""; AbstractFile* af2 = AbstractFile::readAnySubClassDataFile(dataFileName2, false, errorMessage); if (af2 == NULL) { delete af1; throw CommandException(errorMessage); } QString diffMessage; const bool theSame = af1->compareFileForUnitTesting(af2, tolerance, diffMessage); //std::cout << "---------------------------------------------------------------------" << std::endl; std::cout << "Comparison of " << FileUtilities::basename(dataFileName1).toAscii().constData() << " and " << std::endl << " " << FileUtilities::basename(dataFileName2).toAscii().constData() << std::endl; if (theSame) { std::cout << "OK" << std::endl; } else { std::cout << "FAILED" << std::endl; std::cout << diffMessage.toAscii().constData() << std::endl; delete af1; delete af2; throw CommandException("Files did not match"); } std::cout << std::endl; delete af1; delete af2; } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandCreateCiftiDenseTimeseries.h0000664000175000017500000000336511572067322030472 0ustar michaelmichael #ifndef __COMMAND_CREATE_CIFTI_DENSE_TIMESERIES_H__ #define __COMMAND_CREATE_CIFTI_DENSE_TIMESERIES_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for displaying information about a metric file class CommandCreateCiftiDenseTimeseries : public CommandBase { public: // constructor CommandCreateCiftiDenseTimeseries(); // destructor ~CommandCreateCiftiDenseTimeseries(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (CommandException, FileException, ProgramParametersException); }; #endif // __COMMAND_CREATE_CIFTI_DENSE_TIMESERIES_H__caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandCreateCiftiDenseTimeseries.cxx0000664000175000017500000005333711572067322031051 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "CommandCreateCiftiDenseTimeseries.h" #include "FileFilters.h" #include "FileUtilities.h" #include "MetricFile.h" #include "VolumeFile.h" #include "CiftiFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "CiftiXMLWriter.h" #include #include "nifti2.h" #include /** * constructor. */ CommandCreateCiftiDenseTimeseries::CommandCreateCiftiDenseTimeseries() : CommandBase("-create-cifti-dense-timeseries", "CREATE CIFTI DENSE TIMESERIES") { } /** * destructor. */ CommandCreateCiftiDenseTimeseries::~CommandCreateCiftiDenseTimeseries() { } /** * get the script builder parameters. */ void CommandCreateCiftiDenseTimeseries::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); //paramsOut.addFile("Metric File Name", // FileFilters::getMetricFileFilter()); } /** * get full help information. */ QString CommandCreateCiftiDenseTimeseries::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "[-time-step] (default of 1.0 seconds)\n" + "\n" + indent9 + "[-input-volume]\n" + "\n" + indent9 + "[-cifti-structure-name]\n" + indent9 + "[[-input-surface-roi]]\n" + indent9 + "[-input-timeseries]\n" + indent9 + "\n" + indent9 + "[-cifti-structure-name]\n" + indent9 + "[-input-volumetric-roi]\n" + indent9 + "...\n" + indent9 + "\n" + indent9 + "[-cifti-structure-name]\n" + indent9 + "[[-input-surface-roi]]\n" + indent9 + "[-input-timeseries]\n" + indent9 + "\n" + indent9 + "[-cifti-structure-name]\n" + indent9 + "[-input-volumetric-roi]\n" + indent9 + "...\n" + indent9 + "\n" + indent9 + "<-output-cifti-file>\n" + indent9 + "[-output-header]\n" + indent9 + "[-output-matrix]\n" + indent9 + "\n" + indent9 + "Combine surface and volume timeseries into a single CIFTI dense timeseries\n" + indent9 + "file. All inputs are optional but there must be at least one input. If\n" + indent9 + "any volume structures are specified, a volume timeseries must precede the\n" + indent9 + "inputs. For each column, a name and metric timeseries are required. A\n" + indent9 + "ROI is optional. For each volume, a volume ROI and name are required.\n" + indent9 + "CIFTI files can contain both surface and volume structures, or only one\n" + indent9 + "or the other. All structures must be given a name.\n" + indent9 + "Common names include:\n" + indent9 + "CIFTI_STRUCTURE_ACCUMBENS_LEFT\n" + indent9 + "CIFTI_STRUCTURE_ACCUMBENS_RIGHT\n" + indent9 + "CIFTI_STRUCTURE_AMYGDALA_LEFT\n" + indent9 + "CIFTI_STRUCTURE_AMYGDALA_RIGHT\n" + indent9 + "CIFTI_STRUCTURE_BRAIN_STEM\n" + indent9 + "CIFTI_STRUCTURE_CAUDATE_LEFT\n" + indent9 + "CIFTI_STRUCTURE_CAUDATE_RIGHT\n" + indent9 + "CIFTI_STRUCTURE_CEREBELLUM\n" + indent9 + "CIFTI_STRUCTURE_CEREBELLUM_LEFT\n" + indent9 + "CIFTI_STRUCTURE_CEREBELLUM_RIGHT\n" + indent9 + "CIFTI_STRUCTURE_CORTEX_LEFT\n" + indent9 + "CIFTI_STRUCTURE_CORTEX_RIGHT\n" + indent9 + "CIFTI_STRUCTURE_HIPPOCAMPUS_LEFT\n" + indent9 + "CIFTI_STRUCTURE_HIPPOCAMPUS_RIGHT\n" + indent9 + "CIFTI_STRUCTURE_OTHER\n" + indent9 + "CIFTI_STRUCTURE_PALLIDUM_LEFT\n" + indent9 + "CIFTI_STRUCTURE_PALLIDUM_RIGHT\n" + indent9 + "CIFTI_STRUCTURE_PUTAMEN_LEFT\n" + indent9 + "CIFTI_STRUCTURE_PUTAMEN_RIGHT\n" + indent9 + "CIFTI_STRUCTURE_SUBCORTICAL_WHITE_MATTER_LEFT\n" + indent9 + "CIFTI_STRUCTURE_SUBCORTICAL_WHITE_MATTER_RIGHT\n" + indent9 + "CIFTI_STRUCTURE_THALAMUS_LEFT\n" + indent9 + "CIFTI_STRUCTURE_THALMUS_RIGHT\n" + indent9 + "CIFTI_STRUCTURE_DIENCEPHALON_VENTRAL_LEFT\n" + indent9 + "CIFTI_STRUCTURE_DIENCEPHALON_VENTRAL_RIGHT\n" + indent9 + "\n" + indent9 + "The only names that must be the same as above, if used are\n" + indent9 + "CIFTI_STRUCTURE_CORTEX_LEFT and CIFTI_STRUCTURE_CORTEXT_RIGHT\n" + indent9 + "so that viewers know the structure is a left or right surface.\n" + indent9 + "The CIFTI file output will be ordered in the order of the inputs.\n" + indent9 + "It is possible to also output a text CIFTI header and GIFTI\n" + indent9 + "external binary file for compatibility with Matlab. A CIFTI file\n" + indent9 + "output must be specified.\n" + indent9 + "\n" + indent9 + "\n"); return helpInfo; } typedef enum { VOLUME, SURFACE } structType; typedef struct { QString structureName; union { VolumeFile * roiV; MetricFile * roiM; }; structType type; MetricFile *valuesFile; std::vector < std::vector < unsigned long long > > ijk;//ijk values inside the ROI } ciftiStructType; typedef struct { QString structureName; QString roiFileName; QString valFileName; structType type; } ciftiStructParamsType; //forward declarations for local functions //void getMaskedVolumeValues(VolumeFile *vol, VolumeFile *roi, int timeSlice, std::vector< float > &values, std::vector < std::vector < unsigned long long > > &ijk) throw (FileException); //void getMaskedSurfaceValues(MetricFile *valuesFile, MetricFile *roiFile, int timeSlice, std::vector < float > &maskedValues, std::vector < unsigned long long > & indices) throw (FileException); void createCiftiFile(QString &inputVolume, std::vector < ciftiStructParamsType > &ciftiStructures, Nifti2Header &header, CiftiXML &xml, CiftiMatrix &matrix, float timeStep) throw (FileException); void openCiftiStructures(QString &volumeFileName, VolumeFile *&vol, std::vector < ciftiStructParamsType > &ciftiStructureParams, std::vector < ciftiStructType > &ciftiStructures) throw (FileException); void getVolumeValuesOnly(VolumeFile *&vol, int timeSlice, std::vector < std::vector < unsigned long long > > &ijk, std::vector< float > &values) throw (FileException) { vol->readFile(vol->getFileName(),timeSlice); values.resize(ijk.size()); int size = ijk.size(); for(int i = 0;i < size;i++) { values[i]=vol->getVoxel(ijk.at(i)[0],ijk.at(i)[1],ijk.at(i)[2]); } } void getVolumeValues(VolumeFile *&vol, VolumeFile *roi, int timeSlice, std::vector< float > &values, std::vector < std::vector < unsigned long long > > &ijk) throw (FileException) { int dim[3], roiDim[3]; vol->readFile(vol->getFileName(),timeSlice); vol->getDimensions(dim); roi->getDimensions(roiDim); if((dim[0] != roiDim[0]) || (dim[1] != roiDim[1]) || (dim[2] != roiDim[2])) throw FileException("ROI Dimensions do not match the volume dimensions"); for(int i = 0;i < dim[0];i++) { for(int j = 0;j < dim[1];j++) { for(int k = 0;k < dim[2];k++) { if(roi->getVoxel(i,j,k) > 0.0f) { values.push_back(vol->getVoxel(i,j,k)); ijk.push_back(std::vector (3)); ijk[values.size()-1][0]= i; ijk[values.size()-1][1]= j; ijk[values.size()-1][2]= k; } } } } } void getSurfaceValues(MetricFile* valuesFile, MetricFile* roiFile, int timeSlice, std::vector < float > &maskedValues, std::vector < unsigned long long > & indices) throw (FileException) { std::vector < float > values; std::vector < float > roi; if(roiFile == NULL) { valuesFile->getColumnForAllNodes(timeSlice,maskedValues); return; } valuesFile->getColumnForAllNodes(timeSlice,values); roiFile->getColumnForAllNodes(0,roi); if(values.size() != roi.size()) throw FileException("ROI node count does not match the number of surface nodes."); int count = values.size(); for(long long i = 0;i < count;i++) { if(roi[i] > 0.0f) { maskedValues.push_back(values[i]); indices.push_back(i); } } } void createCiftiFile(QString &inputVolume, std::vector < ciftiStructParamsType > &ciftiStructureParams, Nifti2Header &header, CiftiXML &xml, CiftiMatrix &matrix,float timeStep) throw (FileException) { VolumeFile * vol = NULL; std::vector < ciftiStructType > ciftiStructures; openCiftiStructures(inputVolume, vol, ciftiStructureParams, ciftiStructures); //first we need to create a valid Nifti Header int timeCount = -1; //timeCount should match for each set of metric data that we load, if not, then trigger an error int nodeCount = 0; int dim[3] = { 0, 0, 0 };//dimensions of volume file if(vol) { timeCount = vol->getNumberOfSubVolumes(); if(timeCount < 1) { throw FileException("Volume File doesn't contain enough rows"); } vol->getDimensions(dim); } for(unsigned int i = 0;igetNumberOfColumns(); if(timeCount != -1 && time != timeCount) { CiftiFileException("Input timeseries do not have the same number of time points."); } else if(timeCount == -1) { timeCount = time; } std::vector < float > values; std::vector < unsigned long long > indices; getSurfaceValues(valuesFile, ciftiStructures.at(i).roiM, 0, values, indices); nodeCount += values.size(); } else if(ciftiStructures.at(i).type == VOLUME) { std::vector < float > values; std::vector < std::vector < unsigned long long > > ijk; getVolumeValues(vol,ciftiStructures.at(i).roiV,0,values,ijk); nodeCount += values.size(); } } header.initTimeSeriesHeaderStruct(); nifti_2_header head; header.getHeaderStruct(head); head.dim[5] = nodeCount; head.dim[6] = timeCount; header.SetHeaderStuct(head); //now create the Cifti XML CiftiRootElement root; root.m_version = "1.0"; root.m_numberOfMatrices = 1; root.m_matrices.push_back(CiftiMatrixElement()); CiftiMatrixElement *me = &(root.m_matrices.at(0)); if(vol) { me->m_volume.push_back(CiftiVolume()); CiftiVolume *volume =&(me->m_volume.at(0)); volume->m_volumeDimensions[0] = dim[0]; volume->m_volumeDimensions[1] = dim[1]; volume->m_volumeDimensions[2] = dim[2]; VolumeFile::ORIENTATION orientation[3]; TransformationMatrixVoxelIndicesIJKtoXYZ voxIndTrans; voxIndTrans.m_dataSpace = NIFTI_XFORM_UNKNOWN; vol->getOrientation(orientation); if ((orientation[0] == VolumeFile::ORIENTATION_LEFT_TO_RIGHT) && (orientation[1] == VolumeFile::ORIENTATION_POSTERIOR_TO_ANTERIOR) && (orientation[2] == VolumeFile::ORIENTATION_INFERIOR_TO_SUPERIOR)) { voxIndTrans.m_transformedSpace = NIFTI_XFORM_TALAIRACH; } else { voxIndTrans.m_transformedSpace = NIFTI_XFORM_SCANNER_ANAT; } float spacing[3]; float origin[3]; vol->getSpacing(spacing); vol->getOrigin(origin); voxIndTrans.m_transform[0] = spacing[0]; voxIndTrans.m_transform[1] = 0.0; voxIndTrans.m_transform[2] = 0.0; voxIndTrans.m_transform[3] = origin[0]; voxIndTrans.m_transform[4] = 0.0; voxIndTrans.m_transform[5] = spacing[1]; voxIndTrans.m_transform[6] = 0.0; voxIndTrans.m_transform[7] = origin[1]; voxIndTrans.m_transform[8] = 0.0; voxIndTrans.m_transform[9] = 0.0; voxIndTrans.m_transform[10] = spacing[2]; voxIndTrans.m_transform[11] = origin[2]; voxIndTrans.m_transform[12] = 0.0; voxIndTrans.m_transform[13] = 0.0; voxIndTrans.m_transform[14] = 0.0; voxIndTrans.m_transform[15] = 1.0; voxIndTrans.m_unitsXYZ = NIFTI_UNITS_MM; volume->m_transformationMatrixVoxelIndicesIJKtoXYZ.push_back( voxIndTrans); } // create matrix indices map for spacing root.m_matrices.at(0).m_matrixIndicesMap.push_back(CiftiMatrixIndicesMapElement()); CiftiMatrixIndicesMapElement * mm = &(root.m_matrices.at(0).m_matrixIndicesMap.at(0)); mm->m_indicesMapToDataType = CIFTI_INDEX_TYPE_BRAIN_MODELS; mm->m_appliesToMatrixDimension.push_back(0); //create brain models that belong to matrix indices map int totalIndexCount = 0; for(unsigned int i = 0;i < ciftiStructures.size();i++) { ciftiStructType * item = &(ciftiStructures[i]); mm->m_brainModels.push_back(CiftiBrainModelElement()); CiftiBrainModelElement * bm = &(mm->m_brainModels[i]); bm->m_brainStructure = item->structureName; bm->m_indexOffset = totalIndexCount; if(item->type == SURFACE) { bm->m_modelType = CIFTI_MODEL_TYPE_SURFACE; if(item->roiM) bm->m_surfaceNumberOfNodes = item->roiM->getNumberOfNodes(); else bm->m_surfaceNumberOfNodes = item->valuesFile->getNumberOfNodes(); std::vector < float > values; std::vector < unsigned long long > indices; if(item->roiM) { getSurfaceValues(item->valuesFile, item->roiM, 0, values, indices); bm->m_indexCount = indices.size(); bm->m_nodeIndices = indices; } else // look at spec { bm->m_indexCount = bm->m_surfaceNumberOfNodes; } } else { bm->m_modelType = CIFTI_MODEL_TYPE_VOXELS; std::vector < float > values; std::vector < std::vector < unsigned long long > > ijk; std::vector < unsigned long long > indices; getVolumeValues(vol,item->roiV, 0, values, ijk); item->ijk = ijk; indices.resize(values.size() * 3); for(unsigned int j = 0;jm_voxelIndicesIJK = indices; bm->m_indexCount = ijk.size(); } totalIndexCount += bm->m_indexCount; } //create matrix indices map for time root.m_matrices.at(0).m_matrixIndicesMap.push_back(CiftiMatrixIndicesMapElement()); mm = &(root.m_matrices.at(0).m_matrixIndicesMap[1]); mm->m_indicesMapToDataType = CIFTI_INDEX_TYPE_TIME_POINTS; mm->m_appliesToMatrixDimension.push_back(1); mm->m_timeStep = timeStep; mm->m_timeStepUnits = NIFTI_UNITS_SEC; //finished creating cifti xml, set root element xml.setXMLRoot(root); // now create cifti matrices float *matrixVals = new float[nodeCount*timeCount]; for(int i = 0;i tempval; std::vector < unsigned long long > indices; ciftiStructType *item = &(ciftiStructures.at(s)); if(item->type == SURFACE) getSurfaceValues(item->valuesFile,item->roiM, i, tempval,indices ); else getVolumeValuesOnly(vol, i, item->ijk,tempval); /* we have to increment by points since we don't have an easy way to select a given voxel from multiple sub-volumes at once */ for(unsigned int j = 0;j cifti_dimensions(2,0); cifti_dimensions[0] = nodeCount;//M cifti_dimensions[1] = timeCount;//N matrix.setMatrixData(matrixVals,cifti_dimensions); } void openCiftiStructures(QString &volumeFileName, VolumeFile * &vol, std::vector < ciftiStructParamsType > &ciftiStructureParams, std::vector < ciftiStructType > &ciftiStructures) throw (FileException) { if(volumeFileName.length()) { vol = new VolumeFile; vol->readFile(volumeFileName); } for(unsigned int i=0;i< ciftiStructureParams.size();i++) { ciftiStructures.push_back(ciftiStructType()); ciftiStructures.at(i).structureName = ciftiStructureParams.at(i).structureName; ciftiStructures.at(i).type = ciftiStructureParams.at(i).type; if(ciftiStructures.at(i).type == SURFACE) { if(ciftiStructureParams.at(i).roiFileName.length()) { ciftiStructures.at(i).roiM = new MetricFile(); ciftiStructures.at(i).roiM->readFile(ciftiStructureParams.at(i).roiFileName); } if(ciftiStructureParams.at(i).valFileName.length()) { ciftiStructures.at(i).valuesFile = new MetricFile(); ciftiStructures.at(i).valuesFile->readFile(ciftiStructureParams.at(i).valFileName); } else throw FileException ("Each Surface Brain Structure Requires a corresponding Metric File."); } else if(ciftiStructures.at(i).type == VOLUME) { ciftiStructures.at(i).roiV = new VolumeFile(); ciftiStructures.at(i).roiV->readFile(ciftiStructureParams.at(i).roiFileName); } } } /** * execute the command. */ #include void CommandCreateCiftiDenseTimeseries::executeCommand() throw (CommandException, FileException, ProgramParametersException ) { // // Get the name of the metric file // QString inputVolume; std::vector < ciftiStructParamsType > ciftiStructureParams; // { structure-name, roi-name, input-time-series } -or- { structure-name, input-volumetric-roi } QString outputCiftiFile; QString outputHeaderFile; QString outputMatrixFile; int structLast=-1;//last Element in Cifti Structures vector float timeStep = 1.0; while (parameters->getParametersAvailable()) { const QString paramValue = parameters->getNextParameterAsString("Create Cifti Dense Time Series Parameter"); if (paramValue == "-input-volume") { inputVolume = parameters->getNextParameterAsString("Input Volume"); } else if(paramValue == "-cifti-structure-name") { structLast++; ciftiStructureParams.push_back(ciftiStructParamsType()); ciftiStructureParams.at(structLast).structureName = parameters->getNextParameterAsString("Cifti Structure Name"); } else if(paramValue == "-input-surface-roi") { ciftiStructureParams.at(structLast).roiFileName = parameters->getNextParameterAsString("Input Surface ROI"); } else if(paramValue == "-input-timeseries") { ciftiStructureParams.at(structLast).valFileName = parameters->getNextParameterAsString("Input Timeseries"); ciftiStructureParams.at(structLast).type = SURFACE; } else if(paramValue == "-input-volumetric-roi")//for volumetric structures { ciftiStructureParams.at(structLast).roiFileName = parameters->getNextParameterAsString("Input Volumetric ROI"); ciftiStructureParams.at(structLast).type = VOLUME; } else if(paramValue == "-output-cifti-file") { outputCiftiFile = parameters->getNextParameterAsString("Output Cifti Dense Timeseries File"); } else if(paramValue == "-output-header") { outputHeaderFile = parameters->getNextParameterAsString("Output Cifti XML Header"); } else if(paramValue == "-output-matrix") { outputMatrixFile = parameters->getNextParameterAsString("Output Gifti External Binary Matrix"); } else if(paramValue == "-time-step") { timeStep = parameters->getNextParameterAsFloat("Time Step"); } else { throw CommandException("Unrecognized parameter: " + paramValue); } } Nifti2Header header; CiftiXML xml; CiftiMatrix matrix; try { createCiftiFile(inputVolume, ciftiStructureParams, header, xml, matrix,timeStep); } catch (FileException e) { std::cout << "An exception occured." << e.whatQString().toAscii().data() << std::endl; } CiftiFile outFile; outFile.setHeader(header); outFile.setCiftiXML(xml); outFile.setCiftiMatrix(matrix); outFile.writeFile(outputCiftiFile); //write cifti xml if(outputHeaderFile.length()) { QByteArray text; xml.writeXML(text); QFile file; file.setFileName(outputHeaderFile); file.open(QIODevice::WriteOnly); file.write(text); file.close(); } if(outputMatrixFile.length()) { QFile file; file.setFileName(outputMatrixFile); file.open(QIODevice::WriteOnly); matrix.writeMatrix(file); } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandConvertSpecFileToCaret6.h0000664000175000017500000000504711572067322027701 0ustar michaelmichael#ifndef __COMMAND_CONVERT_SPEC_FILE_TO_CARET6_H__ #define __COMMAND_CONVERT_SPEC_FILE_TO_CARET6_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" #include "AreaColorFile.h" #include "BorderColorFile.h" #include "FociColorFile.h" class Structure; class SpecFile; /// class for class CommandConvertSpecFileToCaret6 : public CommandBase { public: // constructor CommandConvertSpecFileToCaret6(); // destructor ~CommandConvertSpecFileToCaret6(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); // convert a file QString convertFile(const QString& inputFileName, const Structure& structure); // convert a file QString convertCoordTopoToSurfaceFile(const QString& coordFileName, const QString& topoFileName, const Structure& structure, const QString& preExt); // read the color files void readColorFiles(SpecFile& sf); AreaColorFile areaColorFile; AreaColorFile borderColorFile; AreaColorFile fociColorFile; bool writeColorFilesFlag; }; #endif // __COMMAND_CONVERT_SPEC_FILE_TO_CARET6_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandConvertSpecFileToCaret6.cxx0000664000175000017500000004551411572067322030257 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "AbstractFile.h" #include "AreaColorFile.h" #include "BorderFile.h" #include "BorderProjectionFile.h" #include "BrainModelSurface.h" #include "BrainSet.h" #include "CommandConvertSpecFileToCaret6.h" #include "FileFilters.h" #include "FileUtilities.h" #include "FociFile.h" #include "FociProjectionFile.h" #include "PaintFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SpecFile.h" #include "Structure.h" #include "TopologyFile.h" #include "VolumeFile.h" /** * constructor. */ CommandConvertSpecFileToCaret6::CommandConvertSpecFileToCaret6() : CommandBase("-caret6-convert-spec-file", "CONVERT SPEC FILE AND ITS DATA FILES TO CARET6 FORMAT") { } /** * destructor. */ CommandConvertSpecFileToCaret6::~CommandConvertSpecFileToCaret6() { } /** * get the script builder parameters. */ void CommandConvertSpecFileToCaret6::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); } /** * get full help information. */ QString CommandConvertSpecFileToCaret6::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-allow-overwrite]\n" + indent9 + "[-write-color-files]\n" + indent9 + "\n" + indent9 + "\"structure-name\" is one of:\n" + indent9 + " right\n" + indent9 + " left\n" + indent9 + " cerebellum\n" + indent9 + "\n" + indent9 + "Coordinate files are converted into a Surface file using\n" + indent9 + "the best available topology.\n" + indent9 + "\n" + indent9 + "Topology files are converted but are NOT added to the\n" + indent9 + "output spec file.\n" + indent9 + "\n" + indent9 + "By default, color files are not converted. This is\n" + indent9 + "because this command will add the needed colors to\n" + indent9 + "border, foci, label, and volume files as needed. If\n" + indent9 + "overwrite of color files is desired, add the \n" + indent9 + "\"-write-color-files\" option to the command.\n" + indent9 + "\n" + indent9 + "By default, files are not overwritten. To allow \n" + indent9 + "the overwrite of exisiting files, the \"-allow-overwrite\"\n" + indent9 + "option must be added to the command.\n" + indent9 + "\n" + indent9 + "This command ALWAYS writes files to the current directory.\n" + indent9 + "IT IS BEST TO RUN THIS COMMAND FROM AN EMPTY DIRECTORY\n" + indent9 + "AND USE, AS INPUT, A SPEC FILE FROM ANOTHER DIRECTORY. \n" + indent9 + "Running the command in this manner, will prevent the \n" + indent9 + "original files from being corrupted if the command fails.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandConvertSpecFileToCaret6::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { AbstractFile::setOverwriteExistingFilesAllowed(false); Structure structure; QString structureName = parameters->getNextParameterAsString("Structure Name").toLower(); if (structureName == "left") { structure.setType(Structure::STRUCTURE_TYPE_CORTEX_LEFT); } else if (structureName == "right") { structure.setType(Structure::STRUCTURE_TYPE_CORTEX_RIGHT); } else if (structureName == "cerebellum") { structure.setType(Structure::STRUCTURE_TYPE_CEREBELLUM); } else if (structureName == "invalid") { structure.setType(Structure::STRUCTURE_TYPE_INVALID); } else { throw CommandException("Invalid structure name: " + structureName); } QString specFileName = parameters->getNextParameterAsString("Spec File Name"); this->writeColorFilesFlag = false; while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("Convert Spec File to Caret6 Parameter"); if (paramName == "-allow-overwrite") { AbstractFile::setOverwriteExistingFilesAllowed(true); } else if (paramName == "-write-color-files") { this->writeColorFilesFlag = true; } else { throw CommandException("ERROR: Unrecognized parameter: \"" + paramName + "\""); } } SpecFile sf; sf.readFile(specFileName); if (structure.getType() != Structure::STRUCTURE_TYPE_INVALID) { sf.setStructure(structure); } QString path = FileUtilities::dirname(specFileName); if (path.length() > 0) { if (path != ".") { sf.prependPathsToAllFiles(path, true); } } // // Get topology files // QString closedTopoFileName; if (sf.closedTopoFile.getNumberOfFiles() > 0) { closedTopoFileName = sf.closedTopoFile.getFileName(0); } QString openTopoFileName; if (sf.openTopoFile.getNumberOfFiles() > 0) { openTopoFileName = sf.openTopoFile.getFileName(0); } QString cutTopoFileName; if (sf.cutTopoFile.getNumberOfFiles() > 0) { cutTopoFileName = sf.cutTopoFile.getFileName(0); } QString lobarCutTopoFileName; if (sf.lobarCutTopoFile.getNumberOfFiles() > 0) { lobarCutTopoFileName = sf.lobarCutTopoFile.getFileName(0); } readColorFiles(sf); std::vector allEntries; sf.getAllEntries(allEntries); std::vector newSurfaceFileTags; std::vector newSurfaceFileNames; SpecFile outputSpecFile; int numEntries = sf.getNumberOfEntries(); for (int i = 0; i < numEntries; i++) { SpecFile::Entry* sfe = sf.getEntry(i); int numFiles = sfe->getNumberOfFiles(); for (int j = 0; j < numFiles; j++) { QString name = sfe->getFileName(j); if (sfe == &sf.rawCoordFile) { QString outputSurfaceFileName = this->convertCoordTopoToSurfaceFile(name, closedTopoFileName, structure, ""); newSurfaceFileTags.push_back(SpecFile::getRawSurfaceFileTag()); newSurfaceFileNames.push_back(outputSurfaceFileName); } else if (sfe == &sf.fiducialCoordFile) { QString outputSurfaceFileName = this->convertCoordTopoToSurfaceFile(name, closedTopoFileName, structure, ""); newSurfaceFileTags.push_back(SpecFile::getFiducialSurfaceFileTag()); newSurfaceFileNames.push_back(outputSurfaceFileName); if (openTopoFileName.isEmpty() == false) { QString outputSurfaceFileName = this->convertCoordTopoToSurfaceFile(name, openTopoFileName, structure, ".OPEN"); newSurfaceFileTags.push_back(SpecFile::getFiducialSurfaceFileTag()); newSurfaceFileNames.push_back(outputSurfaceFileName); } } else if (sfe == &sf.inflatedCoordFile) { QString outputSurfaceFileName = this->convertCoordTopoToSurfaceFile(name, closedTopoFileName, structure, ""); newSurfaceFileTags.push_back(SpecFile::getInflatedSurfaceFileTag()); newSurfaceFileNames.push_back(outputSurfaceFileName); } else if (sfe == &sf.veryInflatedCoordFile) { QString outputSurfaceFileName = this->convertCoordTopoToSurfaceFile(name, closedTopoFileName, structure, ""); newSurfaceFileTags.push_back(SpecFile::getVeryInflatedSurfaceFileTag()); newSurfaceFileNames.push_back(outputSurfaceFileName); } else if (sfe == &sf.sphericalCoordFile) { QString outputSurfaceFileName = this->convertCoordTopoToSurfaceFile(name, closedTopoFileName, structure, ""); newSurfaceFileTags.push_back(SpecFile::getSphericalSurfaceFileTag()); newSurfaceFileNames.push_back(outputSurfaceFileName); } else if (sfe == &sf.ellipsoidCoordFile) { QString outputSurfaceFileName = this->convertCoordTopoToSurfaceFile(name, closedTopoFileName, structure, ""); newSurfaceFileTags.push_back(SpecFile::getEllipsoidSurfaceFileTag()); newSurfaceFileNames.push_back(outputSurfaceFileName); } else if (sfe == &sf.compressedCoordFile) { QString outputSurfaceFileName = this->convertCoordTopoToSurfaceFile(name, closedTopoFileName, structure, ""); newSurfaceFileTags.push_back(SpecFile::getCompressedSurfaceFileTag()); newSurfaceFileNames.push_back(outputSurfaceFileName); } else if (sfe == &sf.flatCoordFile) { QString outputSurfaceFileName = this->convertCoordTopoToSurfaceFile(name, cutTopoFileName, structure, ""); newSurfaceFileTags.push_back(SpecFile::getFlatSurfaceFileTag()); newSurfaceFileNames.push_back(outputSurfaceFileName); } else if (sfe == &sf.lobarFlatCoordFile) { QString outputSurfaceFileName = this->convertCoordTopoToSurfaceFile(name, lobarCutTopoFileName, structure, ""); newSurfaceFileTags.push_back(SpecFile::getLobarFlatSurfaceFileTag()); newSurfaceFileNames.push_back(outputSurfaceFileName); } else if (sfe == &sf.hullCoordFile) { QString outputSurfaceFileName = this->convertCoordTopoToSurfaceFile(name, closedTopoFileName, structure, ""); newSurfaceFileTags.push_back(SpecFile::getHullSurfaceFileTag()); newSurfaceFileNames.push_back(outputSurfaceFileName); } else { QString outputFileName = this->convertFile(name, structure); if (outputFileName.isEmpty() == false) { // // DO NOT add topology file to the spec file // if (outputFileName.endsWith(".topo.gii") == false) { outputSpecFile.addToSpecFile(sfe->specFileTag, outputFileName, "", false); } } } } } for (unsigned int i = 0; i < newSurfaceFileTags.size(); i++) { outputSpecFile.addToSpecFile(newSurfaceFileTags[i], newSurfaceFileNames[i], "", false); } outputSpecFile.setCategory(sf.getCategory()); outputSpecFile.setFileComment(sf.getFileComment()); outputSpecFile.setSpace(sf.getSpace()); outputSpecFile.setSpecies(sf.getSpecies()); outputSpecFile.setStructure(sf.getStructure()); outputSpecFile.setSubject(sf.getSubject()); outputSpecFile.writeFileInCaret6Format(FileUtilities::basename(specFileName), structure, NULL, true); } /** * Convert a file. */ QString CommandConvertSpecFileToCaret6::convertCoordTopoToSurfaceFile(const QString& coordFileName, const QString& topoFileName, const Structure& structureIn, const QString& preExt) { if (topoFileName.isEmpty()) { throw CommandException("No topology file available for coordinate file: \"" + coordFileName + "\""); } BrainSet bs(topoFileName, coordFileName); BrainModelSurface* bms = bs.getBrainModelSurface(0); if (bms == NULL) { throw CommandException("Unable to create surface from coordinate file: \"" + coordFileName + "\""); } TopologyFile* tf = bms->getTopologyFile(); if (tf == NULL) { throw CommandException("Problems reading topology file coordinate file \"" + coordFileName + "\""); } Structure structure = structureIn; if (structure == Structure::STRUCTURE_TYPE_INVALID) { structure = Structure::convertStringToType( bms->getCoordinateFile()->getHeaderTag( AbstractFile::headerTagStructure)); } QString fileName; try { fileName = bms->writeSurfaceInCaret6Format(coordFileName, preExt, structure, true); std::cout << coordFileName.toAscii().constData() << " and " << topoFileName.toAscii().constData() << " into a surface file " << fileName.toAscii().constData() << " OK" << std::endl; } catch (FileException e) { std::cout << " ERROR CONVERTING " << coordFileName.toAscii().constData() << " and " << topoFileName.toAscii().constData() << " to surface: " << e.whatQString().toAscii().constData() << std::endl; } return fileName; } /** * Read the color files. */ void CommandConvertSpecFileToCaret6::readColorFiles(SpecFile& sf) { std::vector areaColorFileNames; sf.areaColorFile.getAllFilesNoDataFile(areaColorFileNames); for (unsigned int i = 0; i < areaColorFileNames.size(); i++) { try { AreaColorFile acf; acf.readFile(areaColorFileNames[i]); this->areaColorFile.append(acf); } catch (FileException e) { throw CommandException(e.whatQString()); } } std::vector borderColorFileNames; sf.borderColorFile.getAllFilesNoDataFile(borderColorFileNames); for (unsigned int i = 0; i < borderColorFileNames.size(); i++) { try { BorderColorFile bcf; bcf.readFile(borderColorFileNames[i]); this->borderColorFile.append(bcf); } catch (FileException e) { throw CommandException(e.whatQString()); } } std::vector fociColorFileNames; sf.fociColorFile.getAllFilesNoDataFile(fociColorFileNames); for (unsigned int i = 0; i < fociColorFileNames.size(); i++) { try { FociColorFile fcf; fcf.readFile(fociColorFileNames[i]); this->fociColorFile.append(fcf); } catch (FileException e) { throw CommandException(e.whatQString()); } } } /** * Convert a file. */ QString CommandConvertSpecFileToCaret6::convertFile(const QString& inputFileName, const Structure& structure) { QString errorMessage; QString outputFileName; AbstractFile* af = AbstractFile::readAnySubClassDataFile(inputFileName, false, errorMessage); if (af != NULL) { ColorFile* colorFile = NULL; if ((dynamic_cast(af) != NULL) || (dynamic_cast(af) != NULL)) { colorFile = &this->areaColorFile; } else if ((dynamic_cast(af) != NULL) || (dynamic_cast(af) != NULL)) { colorFile = &this->borderColorFile; } else if ((dynamic_cast(af) != NULL) || (dynamic_cast(af) != NULL)) { colorFile = &this->fociColorFile; } else if (dynamic_cast(af) != NULL) { colorFile = &this->areaColorFile; } // // Should color files be skipped // if (this->writeColorFilesFlag == false) { if (dynamic_cast(af) != NULL) { return ""; } } af->updateMetaDataForCaret6(); QString dataFileName = FileUtilities::basename(inputFileName); try { outputFileName = af->writeFileInCaret6Format(dataFileName, structure, colorFile, true); std::cout << inputFileName.toAscii().constData() << " OK" << std::endl; } catch (FileException e) { std::cout << " ERROR CONVERTING " << dataFileName.toAscii().constData() << ": " << e.whatQString().toAscii().constData() << std::endl; } } else { std::cout << " WARNING, UNRECOGNIZED file type for file: " << inputFileName.toAscii().constData() << std::endl; } return outputFileName; } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandConvertDataFileToCaret6.h0000664000175000017500000000420611572067322027654 0ustar michaelmichael#ifndef __COMMAND_CONVERT_DATA_FILE_TO_CARET6_H__ #define __COMMAND_CONVERT_DATA_FILE_TO_CARET6_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" #include "AreaColorFile.h" #include "BorderColorFile.h" #include "FociColorFile.h" class Structure; class SpecFile; /// class for class CommandConvertDataFileToCaret6 : public CommandBase { public: // constructor CommandConvertDataFileToCaret6(); // destructor ~CommandConvertDataFileToCaret6(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); // convert a file QString convertFile(const QString& inputFileName, const Structure& structure); AreaColorFile areaColorFile; AreaColorFile borderColorFile; AreaColorFile fociColorFile; }; #endif // __COMMAND_CONVERT_DATA_FILE_TO_CARET6_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandConvertDataFileToCaret6.cxx0000664000175000017500000002216711572067322030235 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "AbstractFile.h" #include "AreaColorFile.h" #include "BorderFile.h" #include "BorderProjectionFile.h" #include "BrainModelSurface.h" #include "BrainSet.h" #include "CommandConvertDataFileToCaret6.h" #include "FileFilters.h" #include "FileUtilities.h" #include "FociFile.h" #include "FociProjectionFile.h" #include "PaintFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SpecFile.h" #include "Structure.h" #include "TopologyFile.h" #include "VolumeFile.h" /** * constructor. */ CommandConvertDataFileToCaret6::CommandConvertDataFileToCaret6() : CommandBase("-caret6-convert-data-file", "CONVERT DATA FILE TO CARET6 FORMAT") { } /** * destructor. */ CommandConvertDataFileToCaret6::~CommandConvertDataFileToCaret6() { } /** * get the script builder parameters. */ void CommandConvertDataFileToCaret6::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); } /** * get full help information. */ QString CommandConvertDataFileToCaret6::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "[-allow-overwrite]\n" + indent9 + "[-structure structure-name]\n" + indent9 + "[-area-color-file area-color-file-name]\n" + indent9 + "[-border-color-file border-color-file-name]\n" + indent9 + "[-foci-color-file foci-color-file-name]\n" + indent9 + "]\n" + indent9 + "\n" + indent9 + "Since Caret6 expects colors to be within the border, foci\n" + indent9 + ", label, and label volume files, the appropriate color\n" + indent9 + "file should be specified using its color file option. \n" + indent9 + "This results in the colors being added into the border,\n" + indent9 + "foci, label, or label volume file.\n" + indent9 + "\n" + indent9 + "It is highly recommended that the structure be specified\n" + indent9 + "as many Caret6 data files are structure dependent.\n" + indent9 + "\"structure-name\" is one of:\n" + indent9 + " right\n" + indent9 + " left\n" + indent9 + " cerebellum\n" + indent9 + "\n" + indent9 + "By default, files are not overwritten. To allow \n" + indent9 + "the overwrite of exisiting files, the \"-allow-overwrite\"\n" + indent9 + "option must be added to the command.\n" + indent9 + "\n" + indent9 + "This command ALWAYS writes files to the current directory.\n" + indent9 + "IT IS BEST TO RUN THIS COMMAND FROM A DIRECTORY DIFFERENT\n" + indent9 + "THAN THE DIRECTORY THE INPUT FILE IS LOCATED. Running\n" + indent9 + "the command in this manner, will prevent the original files\n" + indent9 + "from being corrupted if the command fails.\n" + indent9 + "\n" + indent9 + "In most cases, you are better off converting a spec file\n" + indent9 + "and its data file to Caret6 format using \n" + indent9 + " \"caret_command -convert-spec-file-to-caret6\" as it\n" + indent9 + " will convert coordinate and topology files into \n" + indent9 + " surface files and create a spec file that is Caret6 \n" + indent9 + " compatible.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandConvertDataFileToCaret6::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { AbstractFile::setOverwriteExistingFilesAllowed(false); Structure structure; QVector filenames; QVector areaColorFileNames; QVector borderColorFileNames; QVector fociColorFileNames; while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("Convert to Caret6 Parameter"); if (paramName == "-allow-overwrite") { AbstractFile::setOverwriteExistingFilesAllowed(true); } else if (paramName == "-area-color-file") { areaColorFileNames.push_back(parameters->getNextParameterAsString("Area Color File Name")); } else if (paramName == "-border-color-file") { borderColorFileNames.push_back(parameters->getNextParameterAsString("Border Color File Name")); } else if (paramName == "-foci-color-file") { fociColorFileNames.push_back(parameters->getNextParameterAsString("Foci Color File Name")); } else if (paramName == "-structure") { QString structureName = parameters->getNextParameterAsString("Structure Name").toLower(); if (structureName == "left") { structure.setType(Structure::STRUCTURE_TYPE_CORTEX_LEFT); } else if (structureName == "right") { structure.setType(Structure::STRUCTURE_TYPE_CORTEX_RIGHT); } else if (structureName == "cerebellum") { structure.setType(Structure::STRUCTURE_TYPE_CEREBELLUM); } else { throw CommandException("Invalid structure name: " + structureName); } } else { filenames.push_back(paramName); } } int numDataFiles = static_cast(filenames.size()); if (numDataFiles <= 0) { throw CommandException("No files were specified for conversion"); } if (areaColorFileNames.size() > 0) { for (int i = 0; i < areaColorFileNames.size(); i++) { AreaColorFile acf; acf.readFile(areaColorFileNames[i]); this->areaColorFile.append(acf); } } if (borderColorFileNames.size() > 0) { for (int i = 0; i < borderColorFileNames.size(); i++) { BorderColorFile bcf; bcf.readFile(borderColorFileNames[i]); this->borderColorFile.append(bcf); } } if (fociColorFileNames.size() > 0) { for (int i = 0; i < fociColorFileNames.size(); i++) { FociColorFile fcf; fcf.readFile(fociColorFileNames[i]); this->fociColorFile.append(fcf); } } for (int i = 0; i < numDataFiles; i++) { QString inputFileName = filenames.at(i); QString outputFileName = this->convertFile(inputFileName, structure); } } /** * Convert a file. */ QString CommandConvertDataFileToCaret6::convertFile(const QString& inputFileName, const Structure& structure) { QString errorMessage; QString outputFileName; AbstractFile* af = AbstractFile::readAnySubClassDataFile(inputFileName, false, errorMessage); if (af != NULL) { ColorFile* colorFile = NULL; if ((dynamic_cast(af) != NULL) || (dynamic_cast(af) != NULL)) { colorFile = &this->areaColorFile; } else if ((dynamic_cast(af) != NULL) || (dynamic_cast(af) != NULL)) { colorFile = &this->borderColorFile; } else if ((dynamic_cast(af) != NULL) || (dynamic_cast(af) != NULL)) { colorFile = &this->fociColorFile; } else if (dynamic_cast(af) != NULL) { colorFile = &this->areaColorFile; } af->updateMetaDataForCaret6(); QString dataFileName = FileUtilities::basename(inputFileName); try { outputFileName = af->writeFileInCaret6Format(dataFileName, structure, colorFile, true); std::cout << inputFileName.toAscii().constData() << " OK" << std::endl; } catch (FileException e) { std::cout << " ERROR CONVERTING " << dataFileName.toAscii().constData() << ": " << e.whatQString().toAscii().constData() << std::endl; } } else { std::cout << " WARNING, UNRECOGNIZED file type for file: " << inputFileName.toAscii().constData() << std::endl; } return outputFileName; } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandColorFileCreateMissingColors.h0000664000175000017500000000357311572067322031016 0ustar michaelmichael #ifndef __COMMAND_COLOR_FILE_CREATE_MISSING_COLORS_H__ #define __COMMAND_COLOR_FILE_CREATE_MISSING_COLORS_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for creating missing colors for data files. class CommandColorFileCreateMissingColors : public CommandBase { public: // constructor CommandColorFileCreateMissingColors(); // destructor ~CommandColorFileCreateMissingColors(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_COLOR_FILE_CREATE_MISSING_COLORS_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandColorFileCreateMissingColors.cxx0000664000175000017500000003122111572067322031360 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include "AreaColorFile.h" #include "BorderColorFile.h" #include "BorderFile.h" #include "BorderProjectionFile.h" #include "CellColorFile.h" #include "CellFile.h" #include "CellProjectionFile.h" #include "CommandColorFileCreateMissingColors.h" #include "FileFilters.h" #include "FileUtilities.h" #include "FociColorFile.h" #include "FociFile.h" #include "FociProjectionFile.h" #include "PaintFile.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SpecFile.h" #include "VolumeFile.h" /** * constructor. */ CommandColorFileCreateMissingColors::CommandColorFileCreateMissingColors() : CommandBase("-color-file-create-missing-colors", "COLOR FILE CREATE MISSING COLORS") { } /** * destructor. */ CommandColorFileCreateMissingColors::~CommandColorFileCreateMissingColors() { } /** * get the script builder parameters. */ void CommandColorFileCreateMissingColors::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { std::vector modeNames; modeNames.push_back("EXACT"); modeNames.push_back("PARTIAL"); QStringList colorFileFilters; colorFileFilters << FileFilters::getAreaColorFileFilter() << FileFilters::getBorderColorFileFilter() << FileFilters::getCellColorFileFilter() << FileFilters::getFociColorFileFilter(); QStringList dataFileFilters; dataFileFilters << FileFilters::getBorderGenericFileFilter() << FileFilters::getBorderProjectionFileFilter() << FileFilters::getCellFileFilter() << FileFilters::getCellProjectionFileFilter() << FileFilters::getFociFileFilter() << FileFilters::getFociProjectionFileFilter() << FileFilters::getPaintFileFilter() << FileFilters::getVolumePaintFileFilter(); paramsOut.clear(); paramsOut.addListOfItems("Mode", modeNames, modeNames); paramsOut.addMultipleFiles("Input Color File", colorFileFilters); paramsOut.addMultipleFiles("Output Color File", colorFileFilters); paramsOut.addMultipleFiles("Data File", dataFileFilters); } /** * get full help information. */ QString CommandColorFileCreateMissingColors::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "Create random colors for names from the data file that do\n" + indent9 + "not have matching colors in the color file.\n" + indent9 + "\n" + indent9 + "\"MODE\" is one of:\n" + indent9 + " EXACT \n" + indent9 + " PARTIAL \n" + indent9 + "\n" + indent9 + "If \"MODE\" is \"EXACT\", a new color is created if there\n" + indent9 + "is not a color name that exactly matches a name from the \n" + indent9 + "data file.\n" + indent9 + "\n" + indent9 + "If \"MODE\" is \"PARTIAL\", a new color is created for a \n" + indent9 + "name only if the name does not start with the name of a \n" + indent9 + "color. For example, if the name is \"SUL.CeS\" and there \n" + indent9 + "is a color named \"SUL\", a new color is NOT created.\n" + indent9 + "\n" + indent9 + "New colors are added to the input color file and written\n" + indent9 + "to the output color file. The input color file does not \n" + indent9 + "need to exist. If there is not an input color file its\n" + indent9 + "name may be specified by two consecutive double quotes (\"\").\n" + indent9 + "\n" + indent9 + "The data file may be a:\n" + indent9 + " Border File\n" + indent9 + " Border Projection File\n" + indent9 + " Cell File\n" + indent9 + " Cell Projection File\n" + indent9 + " Foci File\n" + indent9 + " Foci Projection File\n" + indent9 + " Paint File\n" + indent9 + " Volume Paint File\n" + indent9 + "\n" + indent9 + "The valid color file extensions are:\n" + indent9 + " Area Color: " + SpecFile::getAreaColorFileExtension() + "\n" + indent9 + " Border Color: " + SpecFile::getBorderColorFileExtension() + "\n" + indent9 + " Cell Color: " + SpecFile::getCellColorFileExtension() + "\n" + indent9 + " Foci Color: " + SpecFile::getFociColorFileExtension() + "\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandColorFileCreateMissingColors::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get parameters // const QString modeName = parameters->getNextParameterAsString("MODE"); const QString inputColorFileName = parameters->getNextParameterAsString("Input Color File Name"); const QString outputColorFileName = parameters->getNextParameterAsString("Output Color File Name"); const QString dataFileName = parameters->getNextParameterAsString("Data File Name"); checkForExcessiveParameters(); // // Check mode // bool exactMatchFlag = false; if (modeName == "EXACT") { exactMatchFlag = true; } else if (modeName == "PARTIAL") { exactMatchFlag = false; } else { throw CommandException("\"" + modeName + " is not a valid mode."); } // // Check files // if (outputColorFileName.isEmpty()) { throw CommandException("Output Color File Name is empty."); } if (dataFileName.isEmpty()) { throw CommandException("Data File Name is empty."); } std::set names; // // Read the data file to get the names // if (dataFileName.endsWith(SpecFile::getBorderProjectionFileExtension())) { BorderProjectionFile bpf; bpf.readFile(dataFileName); const int numBorders = bpf.getNumberOfBorderProjections(); for (int i = 0; i < numBorders; i++) { const BorderProjection* bp = bpf.getBorderProjection(i); names.insert(bp->getName()); } } else if (dataFileName.endsWith(SpecFile::getBorderFileExtension())) { BorderFile bf; bf.readFile(dataFileName); const int numBorders = bf.getNumberOfBorders(); for (int i = 0; i < numBorders; i++) { const Border* bp = bf.getBorder(i); names.insert(bp->getName()); } } else if (dataFileName.endsWith(SpecFile::getCellFileExtension())) { CellFile cf; cf.readFile(dataFileName); const int numCells = cf.getNumberOfCells(); for (int i = 0; i < numCells; i++) { const CellData* cd = cf.getCell(i); names.insert(cd->getName()); } } else if (dataFileName.endsWith(SpecFile::getCellProjectionFileExtension())) { CellProjectionFile cpf; cpf.readFile(dataFileName); const int numCells = cpf.getNumberOfCellProjections(); for (int i = 0; i < numCells; i++) { const CellProjection* cp = cpf.getCellProjection(i); names.insert(cp->getName()); } } else if(dataFileName.endsWith(SpecFile::getFociProjectionFileExtension())) { FociProjectionFile fpf; fpf.readFile(dataFileName); const int numCells = fpf.getNumberOfCellProjections(); for (int i = 0; i < numCells; i++) { const CellProjection* cp = fpf.getCellProjection(i); names.insert(cp->getName()); } } else if(dataFileName.endsWith(SpecFile::getFociFileExtension())) { FociFile ff; ff.readFile(dataFileName); const int numCells = ff.getNumberOfCells(); for (int i = 0; i < numCells; i++) { const CellData* cd = ff.getCell(i); names.insert(cd->getName()); } } else if (dataFileName.endsWith(SpecFile::getPaintFileExtension())) { PaintFile pf; pf.readFile(dataFileName); const int num = pf.getNumberOfPaintNames(); for (int i = 0; i < num; i++) { names.insert(pf.getPaintNameFromIndex(i)); } } else if ((dataFileName.endsWith(SpecFile::getAnalyzeVolumeFileExtension())) || (dataFileName.endsWith(SpecFile::getAfniVolumeFileExtension())) || (dataFileName.endsWith(SpecFile::getWustlVolumeFileExtension())) || (dataFileName.endsWith(SpecFile::getNiftiVolumeFileExtension())) || (dataFileName.endsWith(SpecFile::getNiftiGzipVolumeFileExtension()))) { VolumeFile vf; vf.readFile(dataFileName); const int num = vf.getNumberOfRegionNames(); for (int i = 0; i < num; i++) { names.insert(vf.getRegionNameFromIndex(i)); } } else { throw CommandException(FileUtilities::basename(dataFileName) + " does not end with a file extension matching " " a supported data file type."); } // // Read the color file // ColorFile* colorFile = NULL; if (inputColorFileName.isEmpty() == false) { if (QFile::exists(inputColorFileName)) { if (inputColorFileName.endsWith(SpecFile::getAreaColorFileExtension())) { colorFile = new AreaColorFile; } else if (inputColorFileName.endsWith(SpecFile::getBorderColorFileExtension())) { colorFile = new BorderColorFile; } else if (inputColorFileName.endsWith(SpecFile::getCellColorFileExtension())) { colorFile = new CellColorFile; } else if (inputColorFileName.endsWith(SpecFile::getFociColorFileExtension())) { colorFile = new FociColorFile; } else { throw CommandException(FileUtilities::basename(inputColorFileName) + " does not end with a file extension matching " " a supported color file type."); } colorFile->readFile(inputColorFileName); } } // // Create color file if needed // if (colorFile == NULL) { if (outputColorFileName.endsWith(SpecFile::getAreaColorFileExtension())) { colorFile = new AreaColorFile; } else if (outputColorFileName.endsWith(SpecFile::getBorderColorFileExtension())) { colorFile = new BorderColorFile; } else if (outputColorFileName.endsWith(SpecFile::getCellColorFileExtension())) { colorFile = new CellColorFile; } else if (outputColorFileName.endsWith(SpecFile::getFociColorFileExtension())) { colorFile = new FociColorFile; } else { throw CommandException(FileUtilities::basename(outputColorFileName) + " does not end with a file extension matching " " a supported color file type."); } } // // create the needed colors // const int numColors = colorFile->getNumberOfColors(); std::vector nameVector(names.begin(), names.end()); colorFile->generateColorsForNamesWithoutColors(nameVector, exactMatchFlag); // // Write the color file // if (numColors != colorFile->getNumberOfColors()) { colorFile->writeFile(outputColorFileName); } else { std::cout << "No new colors were created, output color file not written." << std::endl; } delete colorFile; } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandColorFileAddColor.h0000664000175000017500000000341611572067322026562 0ustar michaelmichael #ifndef __COMMAND_COLOR_FILE_ADD_COLOR_H__ #define __COMMAND_COLOR_FILE_ADD_COLOR_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandColorFileAddColor : public CommandBase { public: // constructor CommandColorFileAddColor(); // destructor ~CommandColorFileAddColor(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_COLOR_FILE_ADD_COLOR_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandColorFileAddColor.cxx0000664000175000017500000001655111572067322027141 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "AreaColorFile.h" #include "BorderColorFile.h" #include "CellColorFile.h" #include "ContourCellColorFile.h" #include "FileFilters.h" #include "FociColorFile.h" #include "CommandColorFileAddColor.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include "SpecFile.h" /** * constructor. */ CommandColorFileAddColor::CommandColorFileAddColor() : CommandBase("-color-file-add-color", "COLOR FILE ADD COLOR") { } /** * destructor. */ CommandColorFileAddColor::~CommandColorFileAddColor() { } /** * get the script builder parameters. */ void CommandColorFileAddColor::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { QStringList filters; filters << FileFilters::getAreaColorFileFilter(); filters << FileFilters::getBorderColorFileFilter(); filters << FileFilters::getCellColorFileFilter(); filters << FileFilters::getContourCellColorFileFilter(); filters << FileFilters::getFociColorFileFilter(); paramsOut.clear(); paramsOut.addFile("Input Color File Name", filters); paramsOut.addFile("Output Color File Name", filters); paramsOut.addString("Color Name"); paramsOut.addInt("Red", 0, 0, 255); paramsOut.addInt("Green", 0, 0, 255); paramsOut.addInt("Blue", 0, 0, 255); paramsOut.addVariableListOfParameters("Options"); } /** * get full help information. */ QString CommandColorFileAddColor::getHelpInformation() const { ColorFile::ColorStorage color; unsigned char r, g, b, a; color.getRgba(r, g, b, a); const QString lineSize(QString::number(color.getLineSize())); const QString pointSize(QString::number(color.getPointSize())); const QString alpha(QString::number(a)); const QString symbol(ColorFile::ColorStorage::symbolToText(color.getSymbol())); std::vector symbolTypes; ColorFile::ColorStorage::getAllSymbolTypesAsStrings(symbolTypes); QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " [-alpha alpha-color-component]\n" + indent9 + " [-line-size size-value]\n" + indent9 + " [-point-size size-value]\n" + indent9 + " [-symbol symbol-type]\n" + indent9 + "\n" + indent9 + "Add a color to the color file. The input color file\n" + indent9 + "does not need to exist. \n" + indent9 + "\n" + indent9 + "Color components range (0, 255).\n" + indent9 + "\n" + indent9 + "Defaults:\n" + indent9 + " alpha: " + alpha + "\n" + indent9 + " line-size: " + lineSize + "\n" + indent9 + " point-size: " + pointSize + "\n" + indent9 + " symbol: " + symbol + "\n" + indent9 + "\n" + indent9 + "Value symbol types are:\n"); for (int i = 0; i < static_cast(symbolTypes.size()); i++) { helpInfo += (indent9 + " " + symbolTypes[i] + "\n"); } helpInfo += (indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandColorFileAddColor::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { ColorFile::ColorStorage color; unsigned char red, green, blue, alpha; color.getRgba(red, green, blue, alpha); float lineSize = color.getLineSize(); float pointSize = color.getPointSize(); ColorFile::ColorStorage::SYMBOL symbol = color.getSymbol(); std::vector symbolTypes; ColorFile::ColorStorage::getAllSymbolTypesAsStrings(symbolTypes); // // Get the parameters // const QString inputColorFileName = parameters->getNextParameterAsString("Input Color File Name"); const QString outputColorFileName = parameters->getNextParameterAsString("Output Color File Name"); const QString colorName = parameters->getNextParameterAsString("Color Name"); red = parameters->getNextParameterAsInt("Red Color Component"); green = parameters->getNextParameterAsInt("Green Color Component"); blue = parameters->getNextParameterAsInt("Blue Color Component"); while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("Optional Color Parameter"); if (paramName == "-alpha") { alpha = parameters->getNextParameterAsInt("Alpha"); } else if (paramName == "-line-size") { lineSize = parameters->getNextParameterAsFloat("Line Size"); } else if (paramName == "-point-size") { pointSize = parameters->getNextParameterAsFloat("Point Size"); } else if (paramName == "-symbol") { const QString symbolString = parameters->getNextParameterAsString("Symbol"); bool found = false; for (unsigned int i = 0; i < symbolTypes.size(); i++) { if (symbolString == symbolTypes[i]) { found = true; break; } } if (found == false) { throw CommandException("invalid symbol type: " + symbolString); } symbol = ColorFile::ColorStorage::textToSymbol(symbolString); } else { throw CommandException("color parameter: \"" + paramName + "\""); } } ColorFile* colorFile = NULL; if (inputColorFileName.isEmpty() == false) { colorFile = ColorFile::getColorFileFromFileNameExtension(inputColorFileName); if (QFile::exists(inputColorFileName)) { colorFile->readFile(inputColorFileName); } } if (colorFile == NULL) { colorFile = ColorFile::getColorFileFromFileNameExtension(outputColorFileName); } colorFile->addColor(colorName, red, green, blue, alpha, pointSize, lineSize, symbol); colorFile->writeFile(outputColorFileName); delete colorFile; } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandCiftiCorrelationMatrix.h0000664000175000017500000000345111572067322027720 0ustar michaelmichael #ifndef __COMMAND_CIFTI_CORRELATION_MATRIX_H__ #define __COMMAND_CIFTI_CORRELATION_MATRIX_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandCiftiCorrelationMatrix : public CommandBase { public: // constructor CommandCiftiCorrelationMatrix(); // destructor ~CommandCiftiCorrelationMatrix(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_CIFTI_CORRELATION_MATRIX_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandCiftiCorrelationMatrix.cxx0000664000175000017500000001463611572067322030302 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainModelCiftiCorrelationMatrix.h" #include "BrainSet.h" #include "CommandCiftiCorrelationMatrix.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" #include /** * constructor. */ CommandCiftiCorrelationMatrix::CommandCiftiCorrelationMatrix() : CommandBase("-cifti-correlation-matrix", "CIFTI CORRELATION MATRIX") { } /** * destructor. */ CommandCiftiCorrelationMatrix::~CommandCiftiCorrelationMatrix() { } /** * get the script builder parameters. */ void CommandCiftiCorrelationMatrix::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Cifti File Name", FileFilters::getMetricFileFilter()); paramsOut.addFile("Output Cifti File Name", FileFilters::getMetricFileFilter()); paramsOut.addVariableListOfParameters("Options"); } /** * get full help information. */ QString CommandCiftiCorrelationMatrix::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "[-apply-fisher-z-transform]\n" + indent9 + "[-parallel]\n" + indent9 + "\n" + indent9 + "Compute a correlation matrix using the input cifti file.\n" + indent9 + "Each row (node) in the cifti file is correlated with all\n" + indent9 + "other rows in the cifti file. Each column in the cifti\n" + indent9 + "file represents an \"observation\" at each node. \n" + indent9 + "\n" + indent9 + "The number of rows and columns are the same in the output\n" + indent9 + "cifti file and are equal to the number of rows from the \n" + indent9 + "input cifti file. The values in the output cifti file \n" + indent9 + "form a symmetric matrix with each element containing \n" + indent9 + "a correlation coefficient for the data of two nodes where\n" + indent9 + "the node numbers are the row and column indices.\n" + indent9 + "\n" + indent9 + "An example input cifti file is one in which each row\n" + indent9 + "represents nodes and each column represents timepoints. \n" + indent9 + "The output cifti file contains correlation coefficients\n" + indent9 + "that measure the similarity of the timepoints from all\n" + indent9 + "nodes to all nodes.\n" + indent9 + "\n" + indent9 + "If \"-apply-fisher-z-transform\" options is specified a\n" + indent9 + "a fischer transform is applied to the correlation values.\n" + indent9 + "\n" + indent9 + "If the \"-parallel\" option is specified, the algorithm\n" + indent9 + "will run its operations with multiple threads to reduce\n" + indent9 + "execution time.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandCiftiCorrelationMatrix::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get the input and output file names // const QString inputCiftiFileName = parameters->getNextParameterAsString("Input Cifti File Name"); const QString outputCiftiFileName = parameters->getNextParameterAsString("Output Cifti File Name"); bool applyFisherZTransformFlag = false; bool parallelFlag = false; // // Process optional parameters // while (parameters->getParametersAvailable()) { // // parameter name // const QString paramName = parameters->getNextParameterAsString("Option"); if (paramName == "-apply-fisher-z-transform") { applyFisherZTransformFlag = true; } else if (paramName == "-parallel") { parallelFlag = true; } else { throw CommandException("Unrecognized parameter: " + paramName); } } // // Read the cifti file // CiftiFile cf; QTime readTimer; readTimer.start(); cf.openFile(inputCiftiFileName); if(DebugControl::getDebugOn()) std::cout << "Time to read file " << (readTimer.elapsed() * 0.001) << " seconds." << std::endl; QTime algTimer; algTimer.start(); BrainModelCiftiCorrelationMatrix* alg = NULL; BrainSet brainSet; alg = new BrainModelCiftiCorrelationMatrix(&brainSet, &cf, applyFisherZTransformFlag, parallelFlag); alg->execute(); if(DebugControl::getDebugOn()) std::cout << "Time to run algorithm " << (algTimer.elapsed() * 0.001) << " seconds." << std::endl; // // Write cifti file // QTime writeTimer; writeTimer.start(); CiftiFile* outputCiftiFile = alg->getOutputCiftiFile(); outputCiftiFile->writeFile(outputCiftiFileName); //delete outputCiftiFile; delete alg; if(DebugControl::getDebugOn()) std::cout << "Time to write file " << (writeTimer.elapsed() * 0.001) << " seconds." << std::endl; } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandCaretHelpCreateHtmlIndexFile.h0000664000175000017500000000502511572067322030702 0ustar michaelmichael #ifndef __COMMAND_CARET_HELP_CREATE_HTML_INDEX_FILE_H__ #define __COMMAND_CARET_HELP_CREATE_HTML_INDEX_FILE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" class QTextStream; /// class for generating an index to the caret help files class CommandCaretHelpCreateHtmlIndexFile : public CommandBase { public: // constructor CommandCaretHelpCreateHtmlIndexFile(); // destructor ~CommandCaretHelpCreateHtmlIndexFile(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); // get the title from an HTML page QString getHtmlPageTitle(const QString& directoryName, const QString& fileName); // add to the output file void addHtml(QTextStream& streamOut, const QString& htmlStartTag, const QString& htmlEndTag, const QString& text, const int indentation, const bool addLineBreakFlag = false); // convert directory name to title QString convertDirectoryNameToTitle(const QString& dirName); }; #endif // __COMMAND_CARET_HELP_CREATE_HTML_INDEX_FILE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandCaretHelpCreateHtmlIndexFile.cxx0000664000175000017500000002720711572067322031263 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include "CommandCaretHelpCreateHtmlIndexFile.h" #include "DebugControl.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandCaretHelpCreateHtmlIndexFile::CommandCaretHelpCreateHtmlIndexFile() : CommandBase("-caret-help-create-html-index-file", "CARET CREATE HTML INDEX FILE") { } /** * destructor. */ CommandCaretHelpCreateHtmlIndexFile::~CommandCaretHelpCreateHtmlIndexFile() { } /** * get the script builder parameters. */ void CommandCaretHelpCreateHtmlIndexFile::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Output HTML File", "HTML Files (*.htm *.html)", "index.html"); paramsOut.addString("Page Title", "Title Goes Here"); } /** * get full help information. */ QString CommandCaretHelpCreateHtmlIndexFile::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + " \n" + indent9 + "\n" + indent9 + "This command should be run from the top level Caret Help \n" + indent9 + "directory. It generates an HTML file that links to all of\n" + indent9 + "HTML files in the current directory's subdirectories.\n" + indent9 + "\n" + indent9 + "Each subdirectory will become a topic. Each HTML file found \n" + indent9 + "in the subdirectories will be searched for a title element.\n" + indent9 + "The title element will be the name of the page listed in the\n" + indent9 + "output file. If a title element is not found, the name of\n" + indent9 + "the HTML file will be used.\n" + indent9 + "\n" + indent9 + "If the title contains spaces, it must be enclosed in \n" + indent9 + "double quotes. \n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandCaretHelpCreateHtmlIndexFile::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { // // Get parameters // const QString outputHtmlFileName = parameters->getNextParameterAsString("Output HTML File Name"); const QString theTitle = parameters->getNextParameterAsString("Title"); // // Open the output file // QFile fileOut(outputHtmlFileName); if (fileOut.open(QFile::WriteOnly) == false) { throw CommandException("Unable to open " + outputHtmlFileName + " for writing."); } QTextStream streamOut(&fileOut); // // Output start of HTML tags // streamOut << " \n"; streamOut << " \n"; streamOut << " " << theTitle << " \n"; streamOut << " \n"; streamOut << " \n"; streamOut << " \n"; streamOut << "

" << theTitle << "

\n"; streamOut << "
" << "Generated " << QDate::currentDate().toString("dd MMM yyyy") << "

\n"; // // Get all subdirectories of the current directory // QDir topDir("."); QStringList subDirList = topDir.entryList((QDir::AllDirs | QDir::NoDotAndDotDot), QDir::Name); // // HTML filters // QStringList htmlFilters; htmlFilters << "*.html"; htmlFilters << "*.htm"; // // Loop through the subdirectories // for (int i = 0; i < subDirList.count(); i++) { // // Name of a directory // const QString dirName(subDirList.at(i)); if (DebugControl::getDebugOn()) { std::cout << "SubDir: " << dirName.toAscii().constData() << std::endl; } // // Get the HTML files // QDir subDir(dirName); QStringList htmlFileList = subDir.entryList(htmlFilters, (QDir::Files | QDir::NoSymLinks), QDir::Name); // // If HTML files in directory // if (htmlFileList.count() > 0) { // // Place titles and URLs into multimap with title being the key // QMap pagesMap; for (int j = 0; j < htmlFileList.count(); j++) { // // Name of html file and its title // const QString fileName(htmlFileList.at(j)); const QString title = getHtmlPageTitle(dirName, fileName); // // Output List and Link HTML // const QString hrefTag("
  • "); // // Add to list of pages // if (pagesMap.find(title) != pagesMap.end()) { std::cout << "ERROR: more than one page in the directory " << dirName.toAscii().constData() << " has the same title \"" << title.toAscii().constData() << "\"" << std::endl << " Page not output: " << fileName.toAscii().constData() << std::endl; } else { pagesMap[title] = hrefTag; } if (DebugControl::getDebugOn()) { std::cout << " HTML: " << fileName.toAscii().constData() << std::endl; std::cout << " " << " TITLE: " << title.toAscii().constData() << std::endl; } } if (pagesMap.isEmpty() == false) { // // Add Directory Name as H2 to HTML files // addHtml(streamOut, "

    ", "

    ", convertDirectoryNameToTitle(dirName), 3); // // Start an unordered list // addHtml(streamOut, "
    ", "", "", 3); } } } // // End of HTML tags // streamOut << " \n"; streamOut << " \n"; // // Close output file // fileOut.close(); } /** * add to the output file. */ void CommandCaretHelpCreateHtmlIndexFile::addHtml(QTextStream& streamOut, const QString& htmlStartTag, const QString& htmlEndTag, const QString& text, const int indentation, const bool addLineBreakFlag) { QString breakTag; if (addLineBreakFlag) { breakTag = "
    "; } streamOut << QString(indentation, ' ') << htmlStartTag << text << htmlEndTag << breakTag << "\n"; } /** * get the title from an HTML page. */ QString CommandCaretHelpCreateHtmlIndexFile::getHtmlPageTitle(const QString& directoryName, const QString& fileName) { // // Default title to the name of the file // QString title(fileName); if (fileName.endsWith(".htm")) { title = fileName.left(fileName.length() - QString(".htm").length()); } else if (fileName.endsWith(".html")) { title = fileName.left(fileName.length() - QString(".html").length()); } // // Open the file // QFile file(directoryName + "/" + fileName); if (file.open(QFile::ReadOnly)) { // // Read the entire file // QTextStream stream(&file); const QString fileText = stream.readAll(); // // Find the start and end title flags // const QString startTag(""); const QString endTag(""); const int startIndex = fileText.indexOf(startTag, Qt::CaseInsensitive); if (startIndex >= 0) { const int endIndex = fileText.indexOf(endTag, startIndex + 1, Qt::CaseInsensitive); if (endIndex > 0) { const int textStart = startIndex + startTag.length(); const int textLength = endIndex - textStart; if ((textStart > 0) && (textLength > 0)) { title = fileText.mid(textStart, textLength); } } } // // Close the file // file.close(); } return title; } /** * convert directory name to title. */ QString CommandCaretHelpCreateHtmlIndexFile::convertDirectoryNameToTitle(const QString& dirNameIn) { QString dirName(dirNameIn); QString title(dirName.replace('_', ' ')); // // Make first character and first after blanks capitals // for (int i = 0; i < title.length(); i++) { QChar ch = title[i]; if (i == 0) { ch = ch.toUpper(); } else if (title[i - 1] == ' ') { ch = ch.toUpper(); } title[i] = ch; } return title; } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandCaretFileNamingUnitTesting.h0000664000175000017500000000350711572067322030463 0ustar michaelmichael #ifndef __COMMAND_CARET_FILE_NAMING_UNIT_TESTING_H__ #define __COMMAND_CARET_FILE_NAMING_UNIT_TESTING_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandCaretFileNamingUnitTesting : public CommandBase { public: // constructor CommandCaretFileNamingUnitTesting(); // destructor ~CommandCaretFileNamingUnitTesting(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_CARET_FILE_NAMING_UNIT_TESTING_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandCaretFileNamingUnitTesting.cxx0000664000175000017500000001460311572067322031035 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "CommandCaretFileNamingUnitTesting.h" #include "FileUtilities.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandCaretFileNamingUnitTesting::CommandCaretFileNamingUnitTesting() : CommandBase("-caret-file-name-unit-test", "CARET FILE NAME UNIT TESTING") { } /** * destructor. */ CommandCaretFileNamingUnitTesting::~CommandCaretFileNamingUnitTesting() { } /** * get the script builder parameters. */ void CommandCaretFileNamingUnitTesting::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addString("Any Parameter", "test-on"); } /** * get full help information. */ QString CommandCaretFileNamingUnitTesting::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " test-on\n" + indent9 + "\n" + indent9 + "Perform unit testing on caret file naming code. Provide\n" + indent9 + "any single parameter to run test.\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandCaretFileNamingUnitTesting::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { bool fileNameTestsValid = true; { const QString& name = "Human.1582.LR.Full.CLOSED.65950.topo"; QString directory, species, casename, anatomy, hemisphere; QString description, descriptionNoTypeName, theDate, numNodes, extension; const bool valid = FileUtilities::parseCaretDataFileName(name, directory, species, casename, anatomy, hemisphere, description, descriptionNoTypeName, theDate, numNodes, extension); if ((valid == false) || (species != "Human") || (casename != "1582") || (hemisphere != "LR") || (description != "Full.CLOSED") || (numNodes != "65950") || (extension != "topo")) { fileNameTestsValid = false; std::cout << "Parsing " << name.toAscii().constData() << " failed." << std::endl; std::cout << "directory () \"" << directory.toAscii().constData() << "\"" << std::endl; std::cout << "species (Human) \"" << species.toAscii().constData() << "\"" << std::endl; std::cout << "casename (1582) \"" << casename.toAscii().constData() << "\"" << std::endl; std::cout << "anatomy () \"" << anatomy.toAscii().constData() << "\"" << std::endl; std::cout << "hemisphere (LR) \"" << hemisphere.toAscii().constData() << "\"" << std::endl; std::cout << "description (Full.CLOSED) \"" << description.toAscii().constData() << "\"" << std::endl; std::cout << "descriptionNoTypeName (Full) \"" << descriptionNoTypeName.toAscii().constData() << "\"" << std::endl; std::cout << "theDate () \"" << theDate.toAscii().constData() << "\"" << std::endl; std::cout << "numNodes (65950) \"" << numNodes.toAscii().constData() << "\"" << std::endl; std::cout << "extension (topo) \"" << extension.toAscii().constData() << "\"" << std::endl; } } { const QString& name = "Human.colin.Cerebral.R.FIDUCIAL.TLRC.711-2B.71723.coord"; QString directory, species, casename, anatomy, hemisphere; QString description, descriptionNoTypeName, theDate, numNodes, extension; const bool valid = FileUtilities::parseCaretDataFileName(name, directory, species, casename, anatomy, hemisphere, description, descriptionNoTypeName, theDate, numNodes, extension); if ((valid == false) || (species != "Human") || (casename != "colin") || (hemisphere != "R") || (description != "FIDUCIAL.TLRC.711-2B") || (numNodes != "71723") || (extension != "coord")) { fileNameTestsValid = false; std::cout << "Parsing " << name.toAscii().constData() << " failed." << std::endl; std::cout << "directory () \"" << directory.toAscii().constData() << "\"" << std::endl; std::cout << "species (Human) \"" << species.toAscii().constData() << "\"" << std::endl; std::cout << "casename (colin) \"" << casename.toAscii().constData() << "\"" << std::endl; std::cout << "anatomy (Cerebral) \"" << anatomy.toAscii().constData() << "\"" << std::endl; std::cout << "hemisphere (R) \"" << hemisphere.toAscii().constData() << "\"" << std::endl; std::cout << "description (FIDUCIAL.TLRC.711-2B) \"" << description.toAscii().constData() << "\"" << std::endl; std::cout << "descriptionNoTypeName () \"" << descriptionNoTypeName.toAscii().constData() << "\"" << std::endl; std::cout << "theDate () \"" << theDate.toAscii().constData() << "\"" << std::endl; std::cout << "numNodes (71723) \"" << numNodes.toAscii().constData() << "\"" << std::endl; std::cout << "extension (coord) \"" << extension.toAscii().constData() << "\"" << std::endl; } } if (fileNameTestsValid) { std::cout << "All caret file name tests passed." << std::endl; } else { throw CommandException("Caret file naming unit testing failed."); } } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandCaretFileCopy.h0000664000175000017500000000333211572067322025762 0ustar michaelmichael #ifndef __COMMAND_CARET_FILE_COPY_H__ #define __COMMAND_CARET_FILE_COPY_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class CommandCaretFileCopy : public CommandBase { public: // constructor CommandCaretFileCopy(); // destructor ~CommandCaretFileCopy(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __COMMAND_CARET_FILE_COPY_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandCaretFileCopy.cxx0000664000175000017500000001077311572067322026344 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "AbstractFile.h" #include "CommandCaretFileCopy.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ CommandCaretFileCopy::CommandCaretFileCopy() : CommandBase("-caret-file-copy", "CARET FILE COPY") { } /** * destructor. */ CommandCaretFileCopy::~CommandCaretFileCopy() { } /** * get the script builder parameters. */ void CommandCaretFileCopy::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); paramsOut.addFile("Input Caret Data File Name", FileFilters::getAnyFileFilter()); paramsOut.addFile("Output Caret Data File Name", FileFilters::getAnyFileFilter()); paramsOut.addVariableListOfParameters("Optional Parameters"); } /** * get full help information. */ QString CommandCaretFileCopy::getHelpInformation() const { std::vector fileFormats; std::vector fileFormatNames; AbstractFile::getFileFormatTypesAndNames(fileFormats, fileFormatNames); QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + " \n" + indent9 + " \n" + indent9 + " [-output-encoding output-file-encoding]\n" + indent9 + "\n" + indent9 + "Copy a Caret Data File with optional output encoding.\n" + indent9 + "\n" + indent9 + " is any combination of the following\n" + indent9 + " separated by a colon:\n"); for (unsigned int i = 0; i < fileFormatNames.size(); i++) { helpInfo += (indent9 + " " + fileFormatNames[i] + "\n"); } helpInfo += ("" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void CommandCaretFileCopy::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { const QString& inputFileName = parameters->getNextParameterAsString("Input Caret File Name"); const QString& outputFileName = parameters->getNextParameterAsString("Output Caret File Name"); if (inputFileName.isEmpty()) { throw CommandException("Output File Name is empty."); } if (outputFileName.isEmpty()) { throw CommandException("Output File Name is empty."); } QString outputEncodingName; while (parameters->getParametersAvailable()) { const QString paramName = parameters->getNextParameterAsString("Optional Parameter"); if (paramName == "-output-encoding") { outputEncodingName = parameters->getNextParameterAsString("Output File Encoding"); } else { throw CommandException("Unrecogized parameter: " + paramName); } } QString errorMessage; AbstractFile* dataFile = AbstractFile::readAnySubClassDataFile(inputFileName, false, errorMessage); if (dataFile == NULL) { throw CommandException(errorMessage); } AbstractFile::FILE_FORMAT fileFormat = dataFile->getFileWriteType(); if (outputEncodingName.isEmpty() == false) { bool validEncodingFlag = true; fileFormat = AbstractFile::convertFormatNameToType(outputEncodingName, &validEncodingFlag); if (validEncodingFlag == false) { throw CommandException("Invalid encoding name: " + outputEncodingName); } } dataFile->setFileWriteType(fileFormat); dataFile->writeFile(outputFileName); } caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandBase.h0000664000175000017500000001354411572067322024151 0ustar michaelmichael #ifndef __COMMAND_BASE_H__ #define __COMMAND_BASE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainModelAlgorithmException.h" #include "CommandException.h" #include "FileException.h" #include "ProgramParametersException.h" #include "ScriptBuilderParameters.h" #include "StatisticException.h" class GiftiNodeDataFile; class NodeAttributeFile; class ProgramParameters; class VolumeFile; /// base class for caret command line operations class CommandBase { public: // constructor CommandBase(const QString& operationSwitchIn, const QString& shortDescriptionIn); // destructor virtual ~CommandBase(); // get all commands static void getAllCommandsSortedBySwitch(std::vector& commandsOut); // get all commands static void getAllCommandsSortedByDescription(std::vector& commandsOut); // set the parameters for the command void setParameters(ProgramParameters* parametersIn); /// get the operation switch QString getOperationSwitch() const { return operationSwitch; } /// get the short description of the command QString getShortDescription() const { return shortDescription; } // get full help information virtual QString getHelpInformation() const = 0; // execute the command (returns true if successful) bool execute(QString& errorMessageOut); /// get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const = 0; /// command requires GUI flag sent to QApplication to be true virtual bool getHasGUI() const { return false; } /// command has no parameters virtual bool commandHasNoParameters() const { return false; } /// get general help information static QString getGeneralHelpInformation(); /// get the exit code int getExitCode() const { return exitCode; } protected: // get all commands static void getAllCommandsUnsorted(std::vector& commandsOut); // execute the command virtual void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) = 0; /// get the name and label from a volume file name void splitOutputVolumeNameIntoNameAndLabel(QString& nameInOut, QString& labelOut) const; /// read a volume file void readVolumeFile(VolumeFile& vf, const QString& name) throw (FileException); /// write a volume file void writeVolumeFile(VolumeFile& vf, const QString& name, const QString& label) throw (FileException); /* // get a node attribute file column number where input may be a column // name or number. Input numbers range 1..N and output column // numbers range 0..(N-1) int getNodeAttributeFileColumnNumber(const GiftiNodeDataFile& gndf, const QString& columnNameOrNumber) const throw (CommandException); // get a node attribute file column number where input may be a column // name or number. Input numbers range 1..N and output column // numbers range 0..(N-1) int getNodeAttributeFileColumnNumber(const NodeAttributeFile& gndf, const QString& columnNameOrNumber) const throw (CommandException); */ /// checks for excessive parameters and throws exception if any are found void checkForExcessiveParameters() throw (CommandException); /// get pointer to empty parameters static ProgramParameters* getEmptyParameters(); /// sets the exit code for the program (normally zero if no error). void setExitCode(const int exitCodeIn) { exitCode = exitCodeIn; } /// the switch that identifies the command QString operationSwitch; /// a short description of the command QString shortDescription; /// the commands parameters ProgramParameters* parameters; /// indentation of 3 spaces static const QString indent3; /// indentation of 6 spaces static const QString indent6; /// indentation of 9 spaces static const QString indent9; /// exit code for the program int exitCode; }; #ifdef __COMMAND_BASE_MAIN__ const QString CommandBase::indent3 = " "; const QString CommandBase::indent6 = " "; const QString CommandBase::indent9 = " "; #endif // __COMMAND_BASE_MAIN__ #endif // __COMMAND_BASE_H__ caret-5.6.4~dfsg.1.orig/caret_command_operations/CommandBase.cxx0000664000175000017500000010733611572067322024527 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #define __COMMAND_BASE_MAIN__ #include "CommandBase.h" #undef __COMMAND_BASE_MAIN__ #include "CommandException.h" #include "FileUtilities.h" #include "GiftiNodeDataFile.h" #include "NameIndexSort.h" #include "NodeAttributeFile.h" #include "ProgramParameters.h" #include "StringUtilities.h" #include "VolumeFile.h" #include "CommandCaretFileCopy.h" #include "CommandCaretFileNamingUnitTesting.h" #include "CommandCaretHelpCreateHtmlIndexFile.h" #include "CommandCiftiCorrelationMatrix.h" #include "CommandColorFileAddColor.h" #include "CommandColorFileCreateMissingColors.h" #include "CommandConvertDataFileToCaret6.h" #include "CommandConvertSpecFileToCaret6.h" #include "CommandCreateCiftiDenseTimeseries.h" #include "CommandDataFileCompare.h" #include "CommandDeformationMapApply.h" #include "CommandDeformationMapApplyGenericNames.h" #include "CommandDeformationMapCreate.h" #include "CommandDeformationMapPathUpdate.h" #include "CommandExtend.h" #include "CommandFileConvert.h" #include "CommandFileReadTime.h" #include "CommandFileSubstitution.h" #include "CommandGiftiInfo.h" #include "CommandHelp.h" #include "CommandHelpFull.h" #include "CommandHelpGlobalOptions.h" #include "CommandHelpHTML.h" #include "CommandHelpPDF.h" #include "CommandHelpSearch.h" #include "CommandImageCombine.h" #include "CommandImageCompare.h" #include "CommandImageFormatConvert.h" #include "CommandImageInsertText.h" #include "CommandImageResize.h" #include "CommandImageToWebPage.h" #include "CommandImageView.h" #include "CommandMetricClustering.h" #include "CommandMetricComposite.h" #include "CommandMetricCompositeIdentifiedColumns.h" #include "CommandMetricCorrelationCoefficientMap.h" #include "CommandMetricExtrema.h" #include "CommandMetricFileCreate.h" #include "CommandMetricGradient.h" #include "CommandMetricGradientAll.h" #include "CommandMetricROIGradient.h" #include "CommandMetricROIMask.h" #include "CommandMetricROISmoothing.h" #include "CommandMetricInGroupDifference.h" #include "CommandMetricInformation.h" #include "CommandMetricMath.h" #include "CommandMetricMathPostfix.h" #include "CommandMetricMultipleCorrelationCoefficientMap.h" #include "CommandMetricSetColumnName.h" #include "CommandMetricSetColumnToScalar.h" #include "CommandMetricSmoothing.h" #include "CommandMetricStatisticsAnovaOneWay.h" #include "CommandMetricStatisticsAnovaTwoWay.h" #include "CommandMetricStatisticsCoordinateDifference.h" #include "CommandMetricCorrelationMatrix.h" #include "CommandMetricStatisticsInterhemisphericClusters.h" #include "CommandMetricStatisticsKruskalWallis.h" #include "CommandMetricStatisticsLeveneMap.h" #include "CommandMetricStatisticsNormalization.h" #include "CommandMetricStatisticsOneSampleTTest.h" #include "CommandMetricStatisticsPairedTTest.h" #include "CommandMetricStatisticsShuffledCrossCorrelationMaps.h" #include "CommandMetricStatisticsShuffledTMap.h" #include "CommandMetricStatisticsSubtraceGroupAverage.h" #include "CommandMetricStatisticsTMap.h" #include "CommandMetricStatisticsTwoSampleTTest.h" #include "CommandMetricStatisticsZMap.h" #include "CommandMetricTranspose.h" #include "CommandMetricTwinComparison.h" #include "CommandMetricTwinPairedDataDiffs.h" #include "CommandPaintAddColumns.h" #include "CommandPaintAssignNodes.h" #include "CommandPaintAssignNodesRelativeToLine.h" #include "CommandPaintComposite.h" #include "CommandPaintDilation.h" #include "CommandPaintFileCreate.h" #include "CommandPaintLabelNameUpdate.h" #include "CommandPaintSetColumnName.h" #include "CommandPreferencesFileSettings.h" #include "CommandSceneCreate.h" #include "CommandScriptComment.h" #include "CommandScriptConvert.h" #include "CommandScriptRun.h" #include "CommandScriptVariableRead.h" #include "CommandScriptVariableSet.h" #include "CommandShowScene.h" #include "CommandShowSurface.h" #include "CommandShowVolume.h" #include "CommandSpecFileAdd.h" #include "CommandSpecFileChangeResolution.h" #include "CommandSpecFileClean.h" #include "CommandSpecFileCopy.h" #include "CommandSpecFileCreate.h" #include "CommandSpecFileDirectoryClean.h" #include "CommandSpecFileZip.h" #include "CommandStatisticSetRandomSeed.h" #include "CommandStatisticalUnitTesting.h" #include "CommandStereotaxicSpaces.h" #include "CommandStudyMetaDataFileDuplicates.h" #include "CommandStudyMetaDataFileValidate.h" #include "CommandSurfaceAffineRegression.h" #include "CommandSurfaceAlignToStandardOrientation.h" #include "CommandSurfaceApplyTransformationMatrix.h" #include "CommandSurfaceAverage.h" #include "CommandSurfaceBankStraddling.h" #include "CommandSurfaceBorderCreateAverage.h" #include "CommandSurfaceBorderCreateParallelBorder.h" #include "CommandSurfaceBorderCutter.h" #include "CommandSurfaceBorderDelete.h" #include "CommandSurfaceBorderDrawAroundROI.h" #include "CommandSurfaceBorderDrawGeodesic.h" #include "CommandSurfaceBorderDrawMetric.h" #include "CommandSurfaceBorderFileMerge.h" #include "CommandSurfaceBorderToPaint.h" #include "CommandSurfaceBorderIntersection.h" #include "CommandSurfaceBorderLandmarkIdentification.h" #include "CommandSurfaceBorderMerge.h" #include "CommandSurfaceBorderNibbler.h" #include "CommandSurfaceBorderProjection.h" #include "CommandSurfaceBorderResample.h" #include "CommandSurfaceBorderReverse.h" #include "CommandSurfaceBorderLengths.h" #include "CommandSurfaceBorderLinkToFocus.h" #include "CommandSurfaceBorderSetVariability.h" #include "CommandSurfaceBorderToMetric.h" #include "CommandSurfaceBorderUnprojection.h" #include "CommandSurfaceBorderVariability.h" #include "CommandSurfaceCellCreate.h" #include "CommandSurfaceCellProjection.h" #include "CommandSurfaceCellUnprojection.h" #include "CommandSurfaceCrossoverCheck.h" #include "CommandSurfaceCurvature.h" #include "CommandSurfaceDistortion.h" #include "CommandSurfaceFlatMultiResMorphing.h" #include "CommandSurfaceFlatten.h" #include "CommandSurfaceFociAttributeAssignment.h" #include "CommandSurfaceFociCreate.h" #include "CommandSurfaceFociDelete.h" #include "CommandSurfaceFociProjection.h" #include "CommandSurfaceFociProjectionPals.h" #include "CommandSurfaceFociReassignStudyNames.h" #include "CommandSurfaceFociStudyValidate.h" #include "CommandSurfaceFociUnprojection.h" #include "CommandSurfaceGenerateInflated.h" #include "CommandSurfaceGeodesic.h" #include "CommandSurfaceInflate.h" #include "CommandSurfaceInformation.h" #include "CommandSurfaceNormals.h" #include "CommandSurfacePlaceFociAtLimits.h" #include "CommandSurfacePlaceFociAtExtremum.h" #include "CommandSurfaceRegionOfInterestSelection.h" #include "CommandSurfaceRegistrationPrepareSlits.h" #include "CommandSurfaceRegistrationSpherical.h" #include "CommandSurfaceRegistrationSphericalSpecOnly.h" #include "CommandSurfaceRoiCoordReport.h" #include "CommandSurfaceRoiFoldingMeasures.h" #include "CommandSurfaceRoiNodeAreas.h" #include "CommandSurfaceRoiShapeMeasures.h" #include "CommandSurfaceRoiStatisticalReport.h" #include "CommandSurfaceSmoothing.h" #include "CommandSurfaceSphere.h" #include "CommandSurfaceSphereProjectUnproject.h" #include "CommandSurfaceSphericalMultiResMorphing.h" #include "CommandSurfaceSulcalDepth.h" #include "CommandSurfaceSulcalIdentificationProbabilistic.h" #include "CommandSurfaceIdentifySulci.h" #include "CommandSurfaceToCArrays.h" #include "CommandSurfaceToCerebralHull.h" #include "CommandSurfaceToSegmentationVolume.h" #include "CommandSurfaceToVolume.h" #include "CommandSurfaceTopologyDisconnectNodes.h" #include "CommandSurfaceTopologyFixOrientation.h" #include "CommandSurfaceTopologyNeighbors.h" #include "CommandSurfaceTopologyReport.h" #include "CommandSurfaceTransformToStandardView.h" #include "CommandSurfacesToSegmentationVolumeMask.h" #include "CommandSystemCommandExecute.h" #include "CommandSystemFileCopy.h" #include "CommandSystemFileDelete.h" #include "CommandTransformationMatrixCreate.h" #include "CommandVerify.h" #include "CommandVersion.h" #include "CommandVolumeAnatomyPeaks.h" #include "CommandVolumeAtlasResamplingAndSmoothing.h" #include "CommandVolumeBiasCorrection.h" #include "CommandVolumeBlur.h" #include "CommandVolumeClassifyIntensities.h" #include "CommandVolumeConvertVectorToVolume.h" #include "CommandVolumeCreate.h" #include "CommandVolumeCreateCorpusCallosumSlice.h" #include "CommandVolumeCreateInStereotaxicSpace.h" #include "CommandVolumeDilate.h" #include "CommandVolumeDilateErode.h" #include "CommandVolumeDilateErodeWithinMask.h" #include "CommandVolumeErode.h" #include "CommandVolumeEulerCount.h" #include "CommandVolumeFileCombine.h" #include "CommandVolumeFileMerge.h" #include "CommandVolumeFillBiggestObject.h" #include "CommandVolumeFillHoles.h" #include "CommandVolumeFillSlice.h" #include "CommandVolumeFindLimits.h" #include "CommandVolumeFloodFill.h" #include "CommandVolumeGradient.h" #include "CommandVolumeSegmentationToCerebralHull.h" #include "CommandVolumeHistogram.h" #include "CommandVolumeImportRawFile.h" #include "CommandVolumeInformation.h" #include "CommandVolumeInformationNifti.h" #include "CommandVolumeMakePlane.h" #include "CommandVolumeMakeRectangle.h" #include "CommandVolumeMakeShell.h" #include "CommandVolumeMakeSphere.h" #include "CommandVolumeMapToSurface.h" #include "CommandVolumeMapToSurfacePALS.h" #include "CommandVolumeMapToSurfaceROIFile.h" #include "CommandVolumeMapToVtkModel.h" #include "CommandVolumeMaskVolume.h" #include "CommandVolumeMaskWithVolume.h" #include "CommandVolumeNearToPlane.h" #include "CommandVolumePadVolume.h" #include "CommandVolumeProbAtlasToFunctional.h" #include "CommandVolumeRemoveIslands.h" #include "CommandVolumeReplaceVectorMagnitudeWithVolume.h" #include "CommandVolumeReplaceVoxelsWithVectorMagnitude.h" #include "CommandVolumeResample.h" #include "CommandVolumeRescaleVoxels.h" #include "CommandVolumeResize.h" #include "CommandVolumeROIGradient.h" #include "CommandVolumeROIMinima.h" #include "CommandVolumeROISmoothing.h" #include "CommandVolumeScale0to255.h" #include "CommandVolumeScalePercent0to255.h" #include "CommandVolumeSculpt.h" #include "CommandVolumeSegmentation.h" #include "CommandVolumeSegmentationLigase.h" #include "CommandVolumeSegmentationStereotaxicSpace.h" #include "CommandVolumeSetOrientation.h" #include "CommandVolumeSetOrigin.h" #include "CommandVolumeSetSpacing.h" #include "CommandVolumeShiftAxis.h" #include "CommandVolumeSmearAxis.h" #include "CommandVolumeTFCE.h" #include "CommandVolumeThreshold.h" #include "CommandVolumeThresholdDual.h" #include "CommandVolumeThresholdInverse.h" #include "CommandVolumeFslToVector.h" #include "CommandVolumeTopologyCorrector.h" #include "CommandVolumeTopologyGraph.h" #include "CommandVolumeTopologyReport.h" #include "CommandVolumeVectorCombine.h" /** * constructor. */ CommandBase::CommandBase(const QString& operationSwitchIn, const QString& shortDescriptionIn) { operationSwitch = operationSwitchIn; shortDescription = shortDescriptionIn; parameters = getEmptyParameters(); exitCode = 0; } /** * destructor. */ CommandBase::~CommandBase() { } /** * get all commands. */ void CommandBase::getAllCommandsUnsorted(std::vector& commandsOut) { commandsOut.clear(); commandsOut.push_back(new CommandCaretFileCopy); commandsOut.push_back(new CommandCaretFileNamingUnitTesting); commandsOut.push_back(new CommandCaretHelpCreateHtmlIndexFile); commandsOut.push_back(new CommandCiftiCorrelationMatrix); commandsOut.push_back(new CommandColorFileAddColor); commandsOut.push_back(new CommandColorFileCreateMissingColors); commandsOut.push_back(new CommandConvertDataFileToCaret6); commandsOut.push_back(new CommandConvertSpecFileToCaret6); commandsOut.push_back(new CommandCreateCiftiDenseTimeseries); commandsOut.push_back(new CommandDataFileCompare); commandsOut.push_back(new CommandDeformationMapApply); commandsOut.push_back(new CommandDeformationMapApplyGenericNames); commandsOut.push_back(new CommandDeformationMapCreate); commandsOut.push_back(new CommandDeformationMapPathUpdate); commandsOut.push_back(new CommandExtend); commandsOut.push_back(new CommandFileConvert); commandsOut.push_back(new CommandFileReadTime); commandsOut.push_back(new CommandFileSubstitution); commandsOut.push_back(new CommandGiftiInfo); commandsOut.push_back(new CommandHelp); commandsOut.push_back(new CommandHelpFull); commandsOut.push_back(new CommandHelpGlobalOptions); commandsOut.push_back(new CommandHelpPDF); commandsOut.push_back(new CommandHelpHTML); commandsOut.push_back(new CommandHelpSearch); commandsOut.push_back(new CommandImageCombine); commandsOut.push_back(new CommandImageCompare); commandsOut.push_back(new CommandImageFormatConvert); commandsOut.push_back(new CommandImageInsertText); commandsOut.push_back(new CommandImageResize); commandsOut.push_back(new CommandImageToWebPage); commandsOut.push_back(new CommandImageView); commandsOut.push_back(new CommandMetricClustering); commandsOut.push_back(new CommandMetricComposite); commandsOut.push_back(new CommandMetricCompositeIdentifiedColumns); commandsOut.push_back(new CommandMetricCorrelationCoefficientMap); commandsOut.push_back(new CommandMetricCorrelationMatrix); commandsOut.push_back(new CommandMetricExtrema); commandsOut.push_back(new CommandMetricFileCreate); commandsOut.push_back(new CommandMetricGradient); commandsOut.push_back(new CommandMetricGradientAll); commandsOut.push_back(new CommandMetricInGroupDifference); commandsOut.push_back(new CommandMetricInformation); commandsOut.push_back(new CommandMetricMath); commandsOut.push_back(new CommandMetricMathPostfix); commandsOut.push_back(new CommandMetricMultipleCorrelationCoefficientMap); commandsOut.push_back(new CommandMetricROIGradient); commandsOut.push_back(new CommandMetricROIMask); commandsOut.push_back(new CommandMetricROISmoothing); commandsOut.push_back(new CommandMetricSetColumnName); commandsOut.push_back(new CommandMetricSetColumnToScalar); commandsOut.push_back(new CommandMetricSmoothing); commandsOut.push_back(new CommandMetricStatisticsAnovaOneWay); commandsOut.push_back(new CommandMetricStatisticsAnovaTwoWay); commandsOut.push_back(new CommandMetricStatisticsCoordinateDifference); commandsOut.push_back(new CommandMetricStatisticsInterhemisphericClusters); commandsOut.push_back(new CommandMetricStatisticsKruskalWallis); commandsOut.push_back(new CommandMetricStatisticsLeveneMap); commandsOut.push_back(new CommandMetricStatisticsNormalization); commandsOut.push_back(new CommandMetricStatisticsOneSampleTTest); commandsOut.push_back(new CommandMetricStatisticsPairedTTest); commandsOut.push_back(new CommandMetricStatisticsShuffledCrossCorrelationMaps); commandsOut.push_back(new CommandMetricStatisticsShuffledTMap); commandsOut.push_back(new CommandMetricStatisticsSubtraceGroupAverage); commandsOut.push_back(new CommandMetricStatisticsTMap); commandsOut.push_back(new CommandMetricStatisticsTwoSampleTTest); commandsOut.push_back(new CommandMetricStatisticsZMap); commandsOut.push_back(new CommandMetricTranspose); commandsOut.push_back(new CommandMetricTwinComparison); commandsOut.push_back(new CommandMetricTwinPairedDataDiffs); commandsOut.push_back(new CommandPaintAddColumns); commandsOut.push_back(new CommandPaintAssignNodes); commandsOut.push_back(new CommandPaintAssignNodesRelativeToLine); commandsOut.push_back(new CommandPaintComposite); commandsOut.push_back(new CommandPaintDilation); commandsOut.push_back(new CommandPaintFileCreate); commandsOut.push_back(new CommandPaintLabelNameUpdate); commandsOut.push_back(new CommandPaintSetColumnName); commandsOut.push_back(new CommandPreferencesFileSettings); commandsOut.push_back(new CommandSceneCreate); commandsOut.push_back(new CommandScriptComment); commandsOut.push_back(new CommandScriptConvert); commandsOut.push_back(new CommandScriptRun); commandsOut.push_back(new CommandScriptVariableRead); commandsOut.push_back(new CommandScriptVariableSet); commandsOut.push_back(new CommandShowScene); commandsOut.push_back(new CommandShowSurface); commandsOut.push_back(new CommandShowVolume); commandsOut.push_back(new CommandSpecFileAdd); commandsOut.push_back(new CommandSpecFileChangeResolution); commandsOut.push_back(new CommandSpecFileClean); commandsOut.push_back(new CommandSpecFileCopy); commandsOut.push_back(new CommandSpecFileCreate); commandsOut.push_back(new CommandSpecFileDirectoryClean); commandsOut.push_back(new CommandSpecFileZip); commandsOut.push_back(new CommandStatisticSetRandomSeed); commandsOut.push_back(new CommandStatisticalUnitTesting); commandsOut.push_back(new CommandStereotaxicSpaces); commandsOut.push_back(new CommandStudyMetaDataFileDuplicates); commandsOut.push_back(new CommandStudyMetaDataFileValidate); commandsOut.push_back(new CommandSurfaceAffineRegression); commandsOut.push_back(new CommandSurfaceAlignToStandardOrientation); commandsOut.push_back(new CommandSurfaceApplyTransformationMatrix); commandsOut.push_back(new CommandSurfaceAverage); commandsOut.push_back(new CommandSurfaceBankStraddling); commandsOut.push_back(new CommandSurfaceBorderCreateAverage); commandsOut.push_back(new CommandSurfaceBorderCreateParallelBorder); commandsOut.push_back(new CommandSurfaceBorderCutter); commandsOut.push_back(new CommandSurfaceBorderDelete); commandsOut.push_back(new CommandSurfaceBorderDrawAroundROI); commandsOut.push_back(new CommandSurfaceBorderDrawGeodesic); commandsOut.push_back(new CommandSurfaceBorderDrawMetric); commandsOut.push_back(new CommandSurfaceBorderFileMerge); commandsOut.push_back(new CommandSurfaceBorderToPaint); commandsOut.push_back(new CommandSurfaceBorderIntersection); commandsOut.push_back(new CommandSurfaceBorderLandmarkIdentification); commandsOut.push_back(new CommandSurfaceBorderMerge); commandsOut.push_back(new CommandSurfaceBorderNibbler); commandsOut.push_back(new CommandSurfaceBorderProjection); commandsOut.push_back(new CommandSurfaceBorderResample); commandsOut.push_back(new CommandSurfaceBorderReverse); commandsOut.push_back(new CommandSurfaceBorderLengths); commandsOut.push_back(new CommandSurfaceBorderLinkToFocus); commandsOut.push_back(new CommandSurfaceBorderSetVariability); commandsOut.push_back(new CommandSurfaceBorderToMetric); commandsOut.push_back(new CommandSurfaceBorderUnprojection); commandsOut.push_back(new CommandSurfaceBorderVariability); commandsOut.push_back(new CommandSurfaceCrossoverCheck); commandsOut.push_back(new CommandSurfaceCellCreate); commandsOut.push_back(new CommandSurfaceCellProjection); commandsOut.push_back(new CommandSurfaceCellUnprojection); commandsOut.push_back(new CommandSurfaceCurvature); commandsOut.push_back(new CommandSurfaceDistortion); commandsOut.push_back(new CommandSurfaceFlatMultiResMorphing); commandsOut.push_back(new CommandSurfaceFlatten); commandsOut.push_back(new CommandSurfaceFociAttributeAssignment); commandsOut.push_back(new CommandSurfaceFociCreate); commandsOut.push_back(new CommandSurfaceFociDelete); commandsOut.push_back(new CommandSurfaceFociProjection); commandsOut.push_back(new CommandSurfaceFociProjectionPals); commandsOut.push_back(new CommandSurfaceFociReassignStudyNames); commandsOut.push_back(new CommandSurfaceFociStudyValidate); commandsOut.push_back(new CommandSurfaceFociUnprojection); commandsOut.push_back(new CommandSurfaceGenerateInflated); commandsOut.push_back(new CommandSurfaceGeodesic); commandsOut.push_back(new CommandSurfaceIdentifySulci); commandsOut.push_back(new CommandSurfaceInflate); commandsOut.push_back(new CommandSurfaceInformation); commandsOut.push_back(new CommandSurfaceNormals); commandsOut.push_back(new CommandSurfacePlaceFociAtExtremum); commandsOut.push_back(new CommandSurfacePlaceFociAtLimits); commandsOut.push_back(new CommandSurfaceRegionOfInterestSelection); commandsOut.push_back(new CommandSurfaceRegistrationPrepareSlits); commandsOut.push_back(new CommandSurfaceRegistrationSpherical); commandsOut.push_back(new CommandSurfaceRegistrationSphericalSpecOnly); commandsOut.push_back(new CommandSurfaceRoiCoordReport); commandsOut.push_back(new CommandSurfaceRoiFoldingMeasures); commandsOut.push_back(new CommandSurfaceRoiNodeAreas); commandsOut.push_back(new CommandSurfaceRoiShapeMeasures); commandsOut.push_back(new CommandSurfaceRoiStatisticalReport); commandsOut.push_back(new CommandSurfaceSphere()); commandsOut.push_back(new CommandSurfaceSulcalDepth); commandsOut.push_back(new CommandSurfaceSulcalIdentificationProbabilistic); commandsOut.push_back(new CommandSurfaceToCArrays); commandsOut.push_back(new CommandSurfaceToCerebralHull); commandsOut.push_back(new CommandSurfaceToSegmentationVolume); commandsOut.push_back(new CommandSurfaceToVolume); commandsOut.push_back(new CommandSurfaceSmoothing); commandsOut.push_back(new CommandSurfaceSphereProjectUnproject); commandsOut.push_back(new CommandSurfaceSphericalMultiResMorphing); commandsOut.push_back(new CommandSurfaceTopologyFixOrientation); commandsOut.push_back(new CommandSurfaceTopologyDisconnectNodes); commandsOut.push_back(new CommandSurfaceTopologyNeighbors); commandsOut.push_back(new CommandSurfaceTopologyReport); commandsOut.push_back(new CommandSurfaceTransformToStandardView); commandsOut.push_back(new CommandSurfacesToSegmentationVolumeMask); commandsOut.push_back(new CommandSystemCommandExecute); commandsOut.push_back(new CommandSystemFileCopy); commandsOut.push_back(new CommandSystemFileDelete); commandsOut.push_back(new CommandTransformationMatrixCreate); commandsOut.push_back(new CommandVerify); commandsOut.push_back(new CommandVersion); commandsOut.push_back(new CommandVolumeAnatomyPeaks); commandsOut.push_back(new CommandVolumeAtlasResamplingAndSmoothing); commandsOut.push_back(new CommandVolumeBiasCorrection); commandsOut.push_back(new CommandVolumeBlur); commandsOut.push_back(new CommandVolumeClassifyIntensities); commandsOut.push_back(new CommandVolumeConvertVectorToVolume); commandsOut.push_back(new CommandVolumeCreate); commandsOut.push_back(new CommandVolumeCreateCorpusCallosumSlice); commandsOut.push_back(new CommandVolumeCreateInStereotaxicSpace); commandsOut.push_back(new CommandVolumeDilate); commandsOut.push_back(new CommandVolumeDilateErode); commandsOut.push_back(new CommandVolumeDilateErodeWithinMask); commandsOut.push_back(new CommandVolumeErode); commandsOut.push_back(new CommandVolumeEulerCount); commandsOut.push_back(new CommandVolumeFileCombine); commandsOut.push_back(new CommandVolumeFileMerge); commandsOut.push_back(new CommandVolumeFillBiggestObject); commandsOut.push_back(new CommandVolumeFillHoles); commandsOut.push_back(new CommandVolumeFillSlice); commandsOut.push_back(new CommandVolumeFindLimits); commandsOut.push_back(new CommandVolumeFloodFill); commandsOut.push_back(new CommandVolumeGradient); commandsOut.push_back(new CommandVolumeHistogram); commandsOut.push_back(new CommandVolumeSegmentationToCerebralHull); commandsOut.push_back(new CommandVolumeImportRawFile); commandsOut.push_back(new CommandVolumeInformation); commandsOut.push_back(new CommandVolumeInformationNifti); commandsOut.push_back(new CommandVolumeMapToSurface); commandsOut.push_back(new CommandVolumeMapToSurfacePALS); commandsOut.push_back(new CommandVolumeMapToSurfaceROIFile); commandsOut.push_back(new CommandVolumeMapToVtkModel); commandsOut.push_back(new CommandVolumeMakePlane); commandsOut.push_back(new CommandVolumeMakeRectangle); commandsOut.push_back(new CommandVolumeMakeShell); commandsOut.push_back(new CommandVolumeMakeSphere); commandsOut.push_back(new CommandVolumeMaskVolume); commandsOut.push_back(new CommandVolumeMaskWithVolume); commandsOut.push_back(new CommandVolumeNearToPlane); commandsOut.push_back(new CommandVolumePadVolume); commandsOut.push_back(new CommandVolumeProbAtlasToFunctional); commandsOut.push_back(new CommandVolumeRemoveIslands); commandsOut.push_back(new CommandVolumeReplaceVectorMagnitudeWithVolume); commandsOut.push_back(new CommandVolumeReplaceVoxelsWithVectorMagnitude); commandsOut.push_back(new CommandVolumeResample); commandsOut.push_back(new CommandVolumeRescaleVoxels); commandsOut.push_back(new CommandVolumeResize); commandsOut.push_back(new CommandVolumeROIGradient); commandsOut.push_back(new CommandVolumeROIMinima); commandsOut.push_back(new CommandVolumeROISmoothing); commandsOut.push_back(new CommandVolumeScale0to255); commandsOut.push_back(new CommandVolumeScalePercent0to255); commandsOut.push_back(new CommandVolumeSculpt); commandsOut.push_back(new CommandVolumeSegmentation); commandsOut.push_back(new CommandVolumeSegmentationLigase); commandsOut.push_back(new CommandVolumeSegmentationStereotaxicSpace); commandsOut.push_back(new CommandVolumeSetOrientation); commandsOut.push_back(new CommandVolumeSetOrigin); commandsOut.push_back(new CommandVolumeSetSpacing); commandsOut.push_back(new CommandVolumeShiftAxis); commandsOut.push_back(new CommandVolumeSmearAxis); commandsOut.push_back(new CommandVolumeTFCE); commandsOut.push_back(new CommandVolumeThreshold); commandsOut.push_back(new CommandVolumeThresholdDual); commandsOut.push_back(new CommandVolumeThresholdInverse); commandsOut.push_back(new CommandVolumeFslToVector); commandsOut.push_back(new CommandVolumeTopologyCorrector); commandsOut.push_back(new CommandVolumeTopologyGraph); commandsOut.push_back(new CommandVolumeTopologyReport); commandsOut.push_back(new CommandVolumeVectorCombine); } /** * get all commands. */ void CommandBase::getAllCommandsSortedBySwitch(std::vector& commandsOut) { commandsOut.clear(); // // Get the commands // std::vector commands; getAllCommandsUnsorted(commands); // // Sort the commands by indices // const int numCommands = static_cast(commands.size()); NameIndexSort nis; for (int i = 0; i < numCommands; i++) { nis.add(i, commands[i]->getOperationSwitch()); } nis.sortByNameCaseSensitive(); // // Loop through the commands // const int numItems = nis.getNumberOfItems(); for (int i = 0; i < numItems; i++) { // // Get the command and add it to output commands // int commandIndex; QString commandName; nis.getSortedNameAndIndex(i, commandIndex, commandName); commandsOut.push_back(commands[commandIndex]); } } /** * get all commands. */ void CommandBase::getAllCommandsSortedByDescription(std::vector& commandsOut) { commandsOut.clear(); // // Get the commands // std::vector commands; getAllCommandsUnsorted(commands); // // Sort the commands by indices // const int numCommands = static_cast(commands.size()); NameIndexSort nis; for (int i = 0; i < numCommands; i++) { nis.add(i, commands[i]->getShortDescription()); } nis.sortByNameCaseSensitive(); // // Loop through the commands // const int numItems = nis.getNumberOfItems(); for (int i = 0; i < numItems; i++) { // // Get the command and add it to output commands // int commandIndex; QString commandName; nis.getSortedNameAndIndex(i, commandIndex, commandName); commandsOut.push_back(commands[commandIndex]); } } /** * execute the command (returns true if successful). */ bool CommandBase::execute(QString& errorMessageOut) { errorMessageOut = ""; if (parameters == NULL) { errorMessageOut = (QString("PROGRAM ERROR: parameters have not been set for ") + getOperationSwitch()); return false; } errorMessageOut = getShortDescription() + " ERROR: "; /* // // See if directory should be changed // const int chdirIndex = parameters->getIndexOfParameterWithValue("-CHDIR"); if (chdirIndex >= 0) { const int dirNameIndex = chdirIndex + 1; if (dirNameIndex < parameters->getNumberOfParameters()) { const QString directoryName = parameters->getParameterAtIndex(dirNameIndex); if (directoryName.isEmpty() == false) { // // Is specified directory valid? // QDir dir(directoryName); if (dir.exists() == false) { errorMessageOut += (" directory for -CHDIR \"" + directoryName + "\" is invalid."); return false; } // // Change to the specified directory // QDir::setCurrent(directoryName); // // Remove the "-CHDIR" and directory name parameters // Remember, remove largest index first since array shrinks // parameters->removeParameterAtIndex(dirNameIndex); parameters->removeParameterAtIndex(chdirIndex); } } else { errorMessageOut += "directory name missing for \"-CHDIR\" option"; return false; } } */ try { executeCommand(); } catch (BrainModelAlgorithmException& bmae) { errorMessageOut += bmae.whatQString(); return false; } catch (CommandException& ce) { errorMessageOut += ce.whatQString(); return false; } catch (FileException& fe) { errorMessageOut += fe.whatQString(); return false; } catch (ProgramParametersException& ppe) { errorMessageOut += ppe.whatQString(); return false; } catch (StatisticException& se) { errorMessageOut += StringUtilities::fromStdString(se.whatStdString()); return false; } catch (std::exception& e) { errorMessageOut += QString(e.what()); return false; } errorMessageOut = ""; return true; } /** * set the parameters for the command. */ void CommandBase::setParameters(ProgramParameters* parametersIn) { parameters = parametersIn; } /** * get the name and label from a volume file name. */ void CommandBase::splitOutputVolumeNameIntoNameAndLabel(QString& nameInOut, QString& labelOut) const { static const QString outputVolumeDelimeter(":::"); labelOut = ""; int colonPos = nameInOut.indexOf(outputVolumeDelimeter); if (colonPos != -1) { labelOut = nameInOut.mid(0, colonPos); nameInOut = nameInOut.mid(colonPos + outputVolumeDelimeter.length()); } } /** * read a volume file. */ void CommandBase::readVolumeFile(VolumeFile& vf, const QString& name) throw (FileException) { try { vf.readFile(name); } catch (FileException& e) { const QString msg("ERROR reading: " + name + " " + e.whatQString()); throw FileException(msg); } } /** * write a volume file. */ void CommandBase::writeVolumeFile(VolumeFile& vf, const QString& name, const QString& label) throw (FileException) { try { if (label.isEmpty() == false) { vf.setDescriptiveLabel(label); } // // Always write float since some operations have results ranging 0.0 to 1.0 // vf.setVoxelDataType(VolumeFile::VOXEL_DATA_TYPE_FLOAT); vf.writeFile(name); } catch (FileException& e) { const QString msg("ERROR writing: " + name + " " + e.whatQString()); throw FileException(msg); } } /** * checks for excessive parameters and throws exception if any are found. */ void CommandBase::checkForExcessiveParameters() throw (CommandException) { if (parameters->getParametersAvailable()) { throw CommandException("Too many parameters provided for operation " + getOperationSwitch()); } } /** * get pointer to empty parameters. */ ProgramParameters* CommandBase::getEmptyParameters() { /* static const char* progName = "caret_command"; static char* argvDummy[1] = { progName }; static ProgramParameters emptyParameters(1, argvDummy); return &emptyParameters; */ static ProgramParameters emptyParameters("caret_command", QStringList()); return &emptyParameters; } /** * get general help information. */ QString CommandBase::getGeneralHelpInformation() { QString helpInfo = "ADDING ADDITIONAL COMMANDS\n" " To add additional commands:\n" " * Download and build the caret source code and required libraries \n" " (which is not a simple task).\n" " * Derive a new class for the command from the class CommandBase\n" " located in the caret_source/caret_command_operations directory.\n" " * Add the name of the new command's \".h\" and \".cxx\" files to\n" " the \"caret_command_operations.pro file\". In CommandBase.cxx,\n" " add the include for the new command's header file and create a \n" " new instance of the command in the method \n" " getAllCommandsUnsorted().\n" " * In the \"caret_source\" directory, run the command \"make build\"\n" " to update caret and caret_command.\n" " \n" "EXECUTING COMMANDS THROUGH THE GRAPHICAL USER INTERFACE\n" " A graphical-user interface is provided in the Caret program for \n" " executing all of the commands. From Caret's Window Menu, select \n" " \"Caret Command Executor\". \n" " \n" "METRIC FILES\n" " Many of the metric commands have a metric column identifier as one\n" " of the parameters. This metric column may be either the number of \n" " the metric column (which starts at one) or the name of the metric \n" " column. The name has priority over a number, so, if you happen to\n" " name a column \"3\", you will not be able to access column 3 by its\n" " column number. If a column name contains spaces, the name must be\n" " enclosed in double quotes.\n" " \n" "REQUESTING ADDITIONAL COMMANDS\n" " Post requests for additional command line operations to the Caret\n" " User's Mailing List. Information about the list is available at\n" " http://brainmap.wustl.edu/resources/caretnew.html#Help\n" " \n" "RETURN VALUE\n" " If a command is successful, the program's return code will be zero or\n" " greater. A negative return code indicates that an error has occurred.\n" " \n" "SURFACE SHAPE FILES\n" " Surface Shape and Metric files are the same file format. So, any\n" " command that accepts a metric file will also accept a surface shape\n" " file.\n"; return helpInfo; } caret-5.6.4~dfsg.1.orig/caret_command_operations/COMMAND_STUB.h0000664000175000017500000000325011572067322023704 0ustar michaelmichael #ifndef __REPLACE_1__ #define __REPLACE_1__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CommandBase.h" /// class for class _REPLACE_2_ : public CommandBase { public: // constructor _REPLACE_2_(); // destructor ~_REPLACE_2_(); // get full help information QString getHelpInformation() const; // get the script builder parameters virtual void getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const; protected: // execute the command void executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException); }; #endif // __REPLACE_1__ caret-5.6.4~dfsg.1.orig/caret_command_operations/COMMAND_STUB.cxx0000664000175000017500000000474011572067322024264 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "_REPLACE_2_.h" #include "FileFilters.h" #include "ProgramParameters.h" #include "ScriptBuilderParameters.h" /** * constructor. */ _REPLACE_2_::_REPLACE_2_() : CommandBase("-", "") { } /** * destructor. */ _REPLACE_2_::~_REPLACE_2_() { } /** * get the script builder parameters. */ void _REPLACE_2_::getScriptBuilderParameters(ScriptBuilderParameters& paramsOut) const { paramsOut.clear(); } /** * get full help information. */ QString _REPLACE_2_::getHelpInformation() const { QString helpInfo = (indent3 + getShortDescription() + "\n" + indent6 + parameters->getProgramNameWithoutPath() + " " + getOperationSwitch() + " \n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n" + indent9 + "\n"); return helpInfo; } /** * execute the command. */ void _REPLACE_2_::executeCommand() throw (BrainModelAlgorithmException, CommandException, FileException, ProgramParametersException, StatisticException) { } caret-5.6.4~dfsg.1.orig/caret_command_operations/.project0000664000175000017500000000471511572067322023276 0ustar michaelmichael caret_command_operations org.eclipse.wst.common.project.facet.core.builder org.eclipse.cdt.managedbuilder.core.genmakebuilder clean,full,incremental, ?name? org.eclipse.cdt.make.core.append_environment true org.eclipse.cdt.make.core.autoBuildTarget all org.eclipse.cdt.make.core.buildArguments org.eclipse.cdt.make.core.buildCommand make org.eclipse.cdt.make.core.cleanBuildTarget clean org.eclipse.cdt.make.core.contents org.eclipse.cdt.make.core.activeConfigSettings org.eclipse.cdt.make.core.enableAutoBuild false org.eclipse.cdt.make.core.enableCleanBuild true org.eclipse.cdt.make.core.enableFullBuild true org.eclipse.cdt.make.core.fullBuildTarget all org.eclipse.cdt.make.core.stopOnError true org.eclipse.cdt.make.core.useDefaultBuildCmd true org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder org.eclipse.cdt.core.cnature org.eclipse.cdt.core.ccnature org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature org.eclipse.wst.common.project.facet.core.nature caret-5.6.4~dfsg.1.orig/caret_command_operations/.cproject0000664000175000017500000002076511572067322023444 0ustar michaelmichael make all true true true caret-5.6.4~dfsg.1.orig/caret_command/0000775000175000017500000000000011572067322017355 5ustar michaelmichaelcaret-5.6.4~dfsg.1.orig/caret_command/zip_it.sh0000755000175000017500000000014311572067322021206 0ustar michaelmichaelstrip caret_command rm -f caret_command_exe_osx.zip zip -r caret_command_exe_osx.zip caret_command caret-5.6.4~dfsg.1.orig/caret_command/main.cxx0000664000175000017500000002227511572067322021035 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include "BrainSet.h" #include "CaretVersion.h" #include "CommandBase.h" #include "CommandHelpGlobalOptions.h" #include "CommandHelp.h" #include "DebugControl.h" #include "FileUtilities.h" #include "ProgramParameters.h" /*---------------------------------------------------------------------------------------- * Globals */ static QApplication* myApplication = NULL; /*---------------------------------------------------------------------------------------- * Unexpected handler */ void unexpectedHandler() { std::cout << "WARNING: caret_command will be terminating due to an unexpected exception." << std::endl << "abort() will be called and a core file may be created." << std::endl; abort(); } /*---------------------------------------------------------------------------------------- * New handler */ void newHandler() { std::cout << "\n" << "OUT OF MEMORY\n" << "\n" << "This means that Caret 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)." << " (3) Something is wrong with Caret." << std::endl; abort(); } /*---------------------------------------------------------------------------------------- * The MAIN */ int main(int argc, char* argv[]) { //QApplication::setApplicationName(FileUtilities::basename(argv[0])); // // Create a brain set // NEED to do this here so that static members are initialized // //BrainSet brain; // // Program's exit code. // int programExitCode = 0; try { // // The parameters passed to the program // ProgramParameters params(argc, argv); const QString programName(params.getProgramNameWithoutPath()); // // Set handlers in case sh*t happens // std::set_unexpected(unexpectedHandler); std::set_new_handler(newHandler); // // Get image plugins so JPEGs can be loaded // #ifndef UBUNTU #if QT_VERSION < 0x040600 Q_IMPORT_PLUGIN(qjpeg) //QJpegPlugin) Q_IMPORT_PLUGIN(qgif) //QGifPlugin) Q_IMPORT_PLUGIN(qtiff) //QTiffPlugin) #endif //QT_VERSION #endif // // Get all of the available commands // std::vector commands; CommandBase::getAllCommandsSortedBySwitch(commands); const int numCommands = static_cast(commands.size()); if (params.getNumberOfParameters() < 2) { std::cout << programName.toAscii().constData() << " version " << CaretVersion::getCaretVersionAsString().toAscii().constData() << std::endl << std::endl; for (int i = 0; i < numCommands; i++) { if (commands[i]->getOperationSwitch().toLower().startsWith("-help")) { CommandHelp::printCommandShortHelpInformation(commands[i]); } } std::cout << std::endl; std::cout << "To see help for a specific command, specify the command with no parameters." << std::endl << "If the prefix of a command is supplied, a list of matching commands " << std::endl << "will be displayed." << std::endl; std::cout << std::endl; std::cout << "On Linux and Mac OSX, the \"apply\" command may be used to " << std::endl << "run caret_command on multiple files in the current directory." << std::endl << "For example, to resize all of the JPEG images in the current" << std::endl << "directory so that they are a width of 320 and a height of" << std::endl << "240, run the following command:" << std::endl << " apply \"caret_command -image-resize %1 %1 PIXEL 320 240\" *.jpg" << std::endl; std::cout << std::endl; std::exit(0); } // // Get the operation // const QString operation(params.getNextParameterAsString("Operation")); // // Set the parameters for each command since needed for help // and find the command to run // bool commandFound = false; CommandBase* commandToRun = NULL; for (int i = 0; i < numCommands; i++) { commands[i]->setParameters(¶ms); if (operation == commands[i]->getOperationSwitch()) { commandFound = true; commandToRun = commands[i]; } } // // Command line QT application // bool guiFlag = false; if (commandFound) { if (commandToRun->getHasGUI()) { guiFlag = true; } else if (params.getParameterWithValueExists("-gui")) { guiFlag = true; } } QApplication app(argc, argv, guiFlag); myApplication = &app; QApplication::setApplicationName(FileUtilities::basename(argv[0])); // // process the global options // CommandHelpGlobalOptions::processGlobalOptions(params); // // Create the brain set // BrainSet::initializeStaticStuff(); BrainSet brain; // // Check for debugging // DebugControl::setDebugFlagsFromEnvironmentVariables(); //DebugControl::setDebugOnWithEnvironmentVariable("CARET_DEBUG"); const bool testFlag1IsOn = DebugControl::getTestFlag1(); const bool testFlag2IsOn = DebugControl::getTestFlag2(); const bool debugIsOn = DebugControl::getDebugOn(); // // Brain set may turn debugging on via preferences file but do not let this happen // DebugControl::setDebugOn(debugIsOn); DebugControl::setTestFlag1(testFlag1IsOn); DebugControl::setTestFlag2(testFlag2IsOn); if (debugIsOn) { for (int i = 1; i < argc; i++) { std::cout << "arg " << i << ": " << argv[i] << std::endl; } } // // execute the command // if (commandFound) { // // Should help information be displayed // if ((params.getNumberOfParameters() == 2) && (commandToRun->commandHasNoParameters() == false)) { CommandHelp::printCommandLongHelpInformation(commandToRun); } else { // // Run the command // QString errorMessage; QTime timer; timer.start(); if (commandToRun->execute(errorMessage)) { programExitCode = commandToRun->getExitCode(); } else { if (errorMessage.isEmpty() == false) { std::cout << std::endl; std::cout << errorMessage.toAscii().constData() << std::endl; std::cout << std::endl; } std::exit(-1); } //std::cout << "Execution Time (seconds): " // << (timer.elapsed() * 0.001) // << std::endl; } } // // If command was not found, see if it partially matches a command name // then print short help for all that match // if ((commandFound == false) && (params.getNumberOfParameters() == 2)) { for (int i = 0; i < numCommands; i++) { const QString commandSwitch = commands[i]->getOperationSwitch(); if (commandSwitch.startsWith(operation)) { commandFound = true; CommandHelp::printCommandShortHelpInformation(commands[i]); } } } // // Was command not found? // if (commandFound == false) { std::cout << "ERROR: operation \"" << operation.toAscii().constData() << "\" not found." << std::endl; std::exit(-1); } } catch (CommandException& ce) { std::cout << ce.whatQString().toAscii().constData() << std::endl; } catch (ProgramParametersException& ppe) { std::cout << ppe.whatQString().toAscii().constData() << std::endl; } return programExitCode; } caret-5.6.4~dfsg.1.orig/caret_command/caret_command.pro0000755000175000017500000001614511572067322022703 0ustar michaelmichael###################################################################### # Automatically generated by qmake (1.04a) Tue Jan 14 11:58:13 2003 ###################################################################### !vs:TEMPLATE = app vs:TEMPLATE=vcapp # # For JPEG support with static linking # contains(QT_VERSION, ^4\\.[0-6]\\..*) { QTPLUGIN += qgif qjpeg qtiff } LIBS += -L$(QTDIR)/plugins/imageformats CONFIG += qt console INCLUDEPATH += . include(../caret_qmake_include.pro) unix:release:!debug:!profile { QMAKE_POST_LINK=strip -S $(TARGET) !macx:QMAKE_POST_LINK=strip $(TARGET) } unix:!ubuntu { !dll { PRE_TARGETDEPS += \ ../caret_command_operations/libCaretCommandOperations.a \ ../caret_brain_set/libCaretBrainSet.a \ ../caret_vtk4_classes/libCaretVtk4Classes.a \ ../caret_files/libCaretFiles.a \ ../caret_uniformize/libCaretUniformize.a \ ../caret_statistics/libCaretStatistics.a \ ../caret_common/libCaretCommon.a \ ../caret_widgets/libCaretWidgets.a \ ../caret_cifti/libCaretCifti.a } dll { PRE_TARGETDEPS += \ ../caret_command_operations/libCaretCommandOperations.so \ ../caret_brain_set/libCaretBrainSet.so \ ../caret_vtk4_classes/libCaretVtk4Classes.so \ ../caret_files/libCaretFiles.so \ ../caret_uniformize/libCaretUniformize.so \ ../caret_statistics/libCaretStatistics.so \ ../caret_common/libCaretCommon.so \ ../caret_widgets/libCaretWidgets.so \ ../caret_cifti/libCaretCifti.so LIBS += -ldl } } win32 { !vs:!nmake { debug { LIBS += \ ..\caret_command_operations\debug\libCaretCommandOperations.a \ ..\caret_brain_set\debug\libCaretBrainSet.a \ ..\caret_vtk4_classes\debug\libCaretVtk4Classes.a \ ..\caret_files\debug\libCaretFiles.a \ ..\caret_widgets\debug\libCaretWidgets.a \ ..\caret_uniformize\debug\libCaretUniformize.a \ ..\caret_statistics\debug\libCaretStatistics.a \ ..\caret_common\debug\libCaretCommon.a \ ..\caret_cifti\debug\libCaretCifti.a } release { LIBS += \ ..\caret_command_operations\release\libCaretCommandOperations.a \ ..\caret_brain_set\release\libCaretBrainSet.a \ ..\caret_vtk4_classes\release\libCaretVtk4Classes.a \ ..\caret_files\release\libCaretFiles.a \ ..\caret_widgets\release\libCaretWidgets.a \ ..\caret_uniformize\release\libCaretUniformize.a \ ..\caret_statistics\release\libCaretStatistics.a \ ..\caret_common\release\libCaretCommon.a \ ..\caret_cifti\release\libCaretCifti.a } LIBS += $$VTK_LIBS } else { CONFIG(debug,debug|release) { LIBS += ..\caret_common\debug\CaretCommon.lib \ ..\caret_command_operations\debug\CaretCommandOperations.lib \ ..\caret_brain_set\debug\CaretBrainSet.lib \ ..\caret_vtk4_classes\debug\CaretVtk4Classes.lib \ ..\caret_files\debug\CaretFiles.lib \ ..\caret_uniformize\debug\CaretUniformize.lib \ ..\caret_statistics\debug\CaretStatistics.lib \ ..\caret_widgets\debug\CaretWidgets.lib \ ..\caret_common\debug\CaretCommon.lib \ ..\caret_cifti\debug\CaretCifti.lib LIBS-=$$VTK_RELEASE_LIBS LIBS+=$$VTK_LIBS } CONFIG(release,debug|release) { LIBS += ..\caret_common\release\CaretCommon.lib \ ..\caret_command_operations\release\CaretCommandOperations.lib \ ..\caret_brain_set\release\CaretBrainSet.lib \ ..\caret_vtk4_classes\release\CaretVtk4Classes.lib \ ..\caret_files\release\CaretFiles.lib \ ..\caret_uniformize\release\CaretUniformize.lib \ ..\caret_statistics\release\CaretStatistics.lib \ ..\caret_widgets\release\CaretWidgets.lib \ ..\caret_common\release\CaretCommon.lib \ ..\caret_cifti\release\CaretCifti.lib LIBS-=$$VTK_LIBS LIBS+=$$VTK_RELEASE_LIBS } } contains( DEFINES, HAVE_MINC ):LIBS += $$NETCDF_LIBS } win32 { CONFIG += console CONFIG -= windows } macx { #CONFIG -= app_bundle LIBS += \ -L../caret_command_operations -lCaretCommandOperations \ -L../caret_brain_set -lCaretBrainSet \ -L../caret_vtk4_classes -lCaretVtk4Classes \ -L../caret_files -lCaretFiles \ -L../caret_widgets -lCaretWidgets \ -L../caret_uniformize -lCaretUniformize \ -L../caret_statistics -lCaretStatistics \ -L../caret_common -lCaretCommon \ -L../caret_cifti -lCaretCifti contains ( DEFINES, HAVE_ITK ) { LIBS += $$ITK_LIBS } LIBS += $$VTK_LIBS contains( DEFINES, HAVE_MINC ):LIBS += $$NETCDF_LIBS # # QMAKE_POST_LINK may have "strip" if release # so need semicolon between commands # # qt_menu.nib must be in resources or application will abort # !isEmpty( QMAKE_POST_LINK) { QMAKE_POST_LINK += ; } QMAKE_POST_LINK += cp -r $$(QTDIR)/src/gui/mac/qt_menu.nib ./caret_command.app/Contents/Resources } ubuntu { PRE_TARGETDEPS += \ ../caret_command_operations/libCaretCommandOperations.so \ ../caret_brain_set/libCaretBrainSet.so \ ../caret_files/libCaretFiles.so \ ../caret_uniformize/libCaretUniformize.so \ ../caret_statistics/libCaretStatistics.so \ ../caret_common/libCaretCommon.so \ ../caret_widgets/libCaretWidgets.so \ ../caret_cifti/libCaretCifti.so LIBS += \ -L../caret_command_operations -lCaretCommandOperations \ -L../caret_brain_set -lCaretBrainSet \ -L../caret_files -lCaretFiles \ -L../caret_uniformize -lCaretUniformize \ -L../caret_statistics -lCaretStatistics \ -L../caret_common -lCaretCommon \ -L../caret_widgets -lCaretWidgets \ -L../caret_cifti -lCaretCifti LIBS += $$VTK_LIBS contains( DEFINES, HAVE_MINC ):LIBS += $$NETCDF_LIBS LIBS -= -lvtkjpeg -lvtkpng -lvtkexpat -lvtkzlib LIBS += -ldl QTPLUGIN -= qgif qjpeg qtiff QMAKE_CXXFLAGS += -DUBUNTU } unix:!macx:!ubuntu { LIBS += \ -L../caret_command_operations -lCaretCommandOperations \ -L../caret_brain_set -lCaretBrainSet \ -L../caret_vtk4_classes -lCaretVtk4Classes \ -L../caret_files -lCaretFiles \ -L../caret_widgets -lCaretWidgets \ -L../caret_uniformize -lCaretUniformize \ -L../caret_statistics -lCaretStatistics \ -L../caret_common -lCaretCommon \ -L../caret_cifti -lCaretCifti LIBS += $$VTK_LIBS contains( DEFINES, HAVE_MINC ):LIBS += $$NETCDF_LIBS } # Input #HEADERS += SOURCES += main.cxx caret-5.6.4~dfsg.1.orig/caret_command/.project0000664000175000017500000000437211572067322021032 0ustar michaelmichael caret_command org.eclipse.cdt.managedbuilder.core.genmakebuilder clean,full,incremental, ?name? org.eclipse.cdt.make.core.append_environment true org.eclipse.cdt.make.core.autoBuildTarget all org.eclipse.cdt.make.core.buildArguments org.eclipse.cdt.make.core.buildCommand make org.eclipse.cdt.make.core.cleanBuildTarget clean org.eclipse.cdt.make.core.contents org.eclipse.cdt.make.core.activeConfigSettings org.eclipse.cdt.make.core.enableAutoBuild false org.eclipse.cdt.make.core.enableCleanBuild true org.eclipse.cdt.make.core.enableFullBuild true org.eclipse.cdt.make.core.fullBuildTarget all org.eclipse.cdt.make.core.stopOnError true org.eclipse.cdt.make.core.useDefaultBuildCmd true org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder org.eclipse.cdt.core.cnature org.eclipse.cdt.core.ccnature org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature caret-5.6.4~dfsg.1.orig/caret_command/.cproject0000664000175000017500000002072711572067322021177 0ustar michaelmichael make all true true true caret-5.6.4~dfsg.1.orig/caret_cifti/0000775000175000017500000000000011572067322017035 5ustar michaelmichaelcaret-5.6.4~dfsg.1.orig/caret_cifti/nifti2.h0000664000175000017500000001221611572067322020403 0ustar michaelmichael#include "nifti1.h" /*! \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. */ #ifndef __NIFTI2_HEADER #define __NIFTI2_HEADER /*=================*/ #ifdef __cplusplus extern "C" { #endif /*=================*/ /*extended nifti intent codes*/ #define NIFTI_INTENT_CONNECTIVITY_DENSE 3000 #define NIFTI_INTENT_CONNECTIVITY_DENSE_TIME 3001 #define NIFTI_INTENT_CONNECTIVITY_PARCELLATED 3002 #define NIFTI_INTENT_CONNECTIVITY_PARCELLATED_TIME 3003 #define NIFTI_INTENT_CONNECTIVITY_CONNECTIVITY_TRAJECTORY 3004 #define NIFTI_INTENT_COMPRESSED_SPARSE_CRS 3005 #define NIFTI_INTENT_COMPRESSED_GZIP_ROWS 3006 #define NIFTI_ECODE_CIFTI 32 #define NIFTI2_HEADER_SIZE 540 #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 /*#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 )*/ /*************************/ /************************/ /************/ struct nifti_2_header { /* NIFTI-2 usage */ /* NIFTI-1 usage */ /* offset */ /*************************/ /************************/ /************/ int sizeof_hdr; /*!< MUST be 540 */ /* int sizeof_hdr; (348) */ /* 0 */ char magic[8] ; /*!< MUST be valid signature. */ /* char magic[4]; */ /* 4 */ short datatype; /*!< Defines data type! */ /* short datatype; */ /* 12 */ short bitpix; /*!< Number bits/voxel. */ /* short bitpix; */ /* 14 */ long long 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 */ long long 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 */ long long slice_start; /*!< First slice index. */ /* short slice_start; */ /* 224 */ long long 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 */ int qform_code ; /*!< NIFTI_XFORM_* code. */ /* short qform_code; */ /* 344 */ int 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 */ int slice_code ; /*!< Slice timing order. */ /* char slice_code; */ /* 496 */ int xyzt_units ; /*!< Units of pixdim[1..4] */ /* char xyzt_units; */ /* 500 */ int 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 ; /*=================*/ #ifdef __cplusplus } #endif /*=================*/ #endif //__NIFTI2_HEADERcaret-5.6.4~dfsg.1.orig/caret_cifti/nifti1.h0000664000175000017500000020536011572067322020406 0ustar michaelmichael/** \file nifti1.h \brief Official definition of the nifti1 header. Written by Bob Cox, SSCC, NIMH. */ #ifndef _NIFTI_HEADER_ #define _NIFTI_HEADER_ /***************************************************************************** ** 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 /*=================*/ /*! \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 ; /*---------------------------------------------------------------------------*/ /* 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 */ /*! \defgroup NIFTI1_DATATYPES \brief nifti1 datatype codes @{ */ /*--- the original ANALYZE 7.5 type codes ---*/ #define DT_NONE 0 #define DT_UNKNOWN 0 /* what it says, dude */ #define DT_BINARY 1 /* binary (1 bit/voxel) */ #define DT_UNSIGNED_CHAR 2 /* unsigned char (8 bits/voxel) */ #define DT_SIGNED_SHORT 4 /* signed short (16 bits/voxel) */ #define DT_SIGNED_INT 8 /* signed int (32 bits/voxel) */ #define DT_FLOAT 16 /* float (32 bits/voxel) */ #define DT_COMPLEX 32 /* complex (64 bits/voxel) */ #define DT_DOUBLE 64 /* double (64 bits/voxel) */ #define DT_RGB 128 /* RGB triple (24 bits/voxel) */ #define DT_ALL 255 /* not very useful (?) */ /*----- another set of names for the same ---*/ #define DT_UINT8 2 #define DT_INT16 4 #define DT_INT32 8 #define DT_FLOAT32 16 #define DT_COMPLEX64 32 #define DT_FLOAT64 64 #define DT_RGB24 128 /*------------------- new codes for NIFTI ---*/ #define DT_INT8 256 /* signed char (8 bits) */ #define DT_UINT16 512 /* unsigned short (16 bits) */ #define DT_UINT32 768 /* unsigned int (32 bits) */ #define DT_INT64 1024 /* long long (64 bits) */ #define DT_UINT64 1280 /* unsigned long long (64 bits) */ #define DT_FLOAT128 1536 /* long double (128 bits) */ #define DT_COMPLEX128 1792 /* double pair (128 bits) */ #define 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. */ #define NIFTI_TYPE_UINT8 2 /*! signed short. */ #define NIFTI_TYPE_INT16 4 /*! signed int. */ #define NIFTI_TYPE_INT32 8 /*! 32 bit float. */ #define NIFTI_TYPE_FLOAT32 16 /*! 64 bit complex = 2 32 bit floats. */ #define NIFTI_TYPE_COMPLEX64 32 /*! 64 bit float = double. */ #define NIFTI_TYPE_FLOAT64 64 /*! 3 8 bit bytes. */ #define NIFTI_TYPE_RGB24 128 /*! signed char. */ #define NIFTI_TYPE_INT8 256 /*! unsigned short. */ #define NIFTI_TYPE_UINT16 512 /*! unsigned int. */ #define NIFTI_TYPE_UINT32 768 /*! signed long long. */ #define NIFTI_TYPE_INT64 1024 /*! unsigned long long. */ #define NIFTI_TYPE_UINT64 1280 /*! 128 bit float = long double. */ #define NIFTI_TYPE_FLOAT128 1536 /*! 128 bit complex = 2 64 bit floats. */ #define NIFTI_TYPE_COMPLEX128 1792 /*! 256 bit complex = 2 128 bit floats */ #define 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. */ #define 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 @{ */ #define NIFTI_INTENT_CORREL 2 /*! [C2, chap 28] Student t statistic (1 param): p1 = DOF. */ #define NIFTI_INTENT_TTEST 3 /*! [C2, chap 27] Fisher F statistic (2 params): p1 = numerator DOF, p2 = denominator DOF. */ #define NIFTI_INTENT_FTEST 4 /*! [C1, chap 13] Standard normal (0 params): Density = N(0,1). */ #define NIFTI_INTENT_ZSCORE 5 /*! [C1, chap 18] Chi-squared (1 param): p1 = DOF. Density(x) proportional to exp(-x/2) * x^(p1/2-1). */ #define 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). */ #define 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. */ #define 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). */ #define 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,.... */ #define NIFTI_INTENT_POISSON 10 /*! [C1, chap 13] Normal distribution (2 params): p1 = mean, p2 = standard deviation. */ #define NIFTI_INTENT_NORMAL 11 /*! [C2, chap 30] Noncentral F statistic (3 params): p1 = numerator DOF, p2 = denominator DOF, p3 = numerator noncentrality parameter. */ #define NIFTI_INTENT_FTEST_NONC 12 /*! [C2, chap 29] Noncentral chi-squared statistic (2 params): p1 = DOF, p2 = noncentrality parameter. */ #define 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)). */ #define NIFTI_INTENT_LOGISTIC 14 /*! [C2, chap 24] Laplace distribution (2 params): p1 = location, p2 = scale. Density(x) proportional to exp(-abs(x-p1)/p2). */ #define NIFTI_INTENT_LAPLACE 15 /*! [C2, chap 26] Uniform distribution: p1 = lower end, p2 = upper end. */ #define NIFTI_INTENT_UNIFORM 16 /*! [C2, chap 31] Noncentral t statistic (2 params): p1 = DOF, p2 = noncentrality parameter. */ #define 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. */ #define 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. */ #define 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. */ #define NIFTI_INTENT_INVGAUSS 20 /*! [C2, chap 22] Extreme value type I (2 params): p1 = location, p2 = scale cdf(x) = exp(-exp(-(x-p1)/p2)). */ #define NIFTI_INTENT_EXTVAL 21 /*! Data is a 'p-value' (no params). */ #define 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). */ #define 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). */ #define NIFTI_INTENT_LOG10PVAL 24 /*! Smallest intent_code that indicates a statistic. */ #define NIFTI_FIRST_STATCODE 2 /*! Largest intent_code that indicates a statistic. */ #define 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. */ #define 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. */ #define 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. */ #define 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] */ #define 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 */ #define 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) */ #define NIFTI_INTENT_DISPVECT 1006 /* specifically for displacements */ #define 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"). */ #define 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. */ #define 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 */ #define NIFTI_INTENT_QUATERNION 1010 /*! Dimensionless value - no params - although, as in _ESTIMATE the name of the parameter may be stored in intent_name. */ #define 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). */ #define NIFTI_XFORM_UNKNOWN 0 /*! Scanner-based anatomical coordinates */ #define NIFTI_XFORM_SCANNER_ANAT 1 /*! Coordinates aligned to another file's, or to anatomical "truth". */ #define NIFTI_XFORM_ALIGNED_ANAT 2 /*! Coordinates aligned to Talairach- Tournoux Atlas; (0,0,0)=AC, etc. */ #define NIFTI_XFORM_TALAIRACH 3 /*! MNI 152 normalized coordinates. */ #define 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. */ #define NIFTI_UNITS_UNKNOWN 0 /** Space codes are multiples of 1. **/ /*! NIFTI code for meters. */ #define NIFTI_UNITS_METER 1 /*! NIFTI code for millimeters. */ #define NIFTI_UNITS_MM 2 /*! NIFTI code for micrometers. */ #define NIFTI_UNITS_MICRON 3 /** Time codes are multiples of 8. **/ /*! NIFTI code for seconds. */ #define NIFTI_UNITS_SEC 8 /*! NIFTI code for milliseconds. */ #define NIFTI_UNITS_MSEC 16 /*! NIFTI code for microseconds. */ #define NIFTI_UNITS_USEC 24 /*** These units are for spectral data: ***/ /*! NIFTI code for Hertz. */ #define NIFTI_UNITS_HZ 32 /*! NIFTI code for ppm. */ #define NIFTI_UNITS_PPM 40 /*! NIFTI code for radians per second. */ #define 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 @{ */ #define NIFTI_SLICE_UNKNOWN 0 #define NIFTI_SLICE_SEQ_INC 1 #define NIFTI_SLICE_SEQ_DEC 2 #define NIFTI_SLICE_ALT_INC 3 #define NIFTI_SLICE_ALT_DEC 4 #define NIFTI_SLICE_ALT_INC2 5 /* 05 May 2005: RWCox */ #define 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_ */ caret-5.6.4~dfsg.1.orig/caret_cifti/caret_cifti.pro0000664000175000017500000000136411572067322022037 0ustar michaelmichaelTARGET = CaretCifti CONFIG += staticlib INCLUDEPATH += . !vs:TEMPLATE = lib win32:vs:TEMPLATE=vclib include(../caret_qmake_include.pro) dll { CONFIG -= staticlib CONFIG += plugin } # Input SOURCES = CiftiFile.cxx \ CiftiFileException.cxx \ CiftiMatrix.cxx \ CiftiXMLReader.cxx \ CiftiXMLWriter.cxx \ CiftiXMLElements.cxx \ CiftiXML.cxx \ Nifti2Header.cxx HEADERS = CiftiFile.h \ CiftiFileException.h \ CiftiMatrix.h \ CiftiXMLReader.h \ CiftiXMLWriter.h \ CiftiXMLElements.h \ CiftiXML.h \ nifti1.h \ nifti2.h \ Nifti2Header.h caret-5.6.4~dfsg.1.orig/caret_cifti/Nifti2Header.h0000664000175000017500000000446011572067322021456 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2011 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __NIFTI_2_HEADER #define __NIFTI_2_HEADER #include #include "nifti2.h" #include "iostream" #include "CiftiFileException.h" #include "CiftiByteSwap.h" #include class Nifti2Header { public: Nifti2Header() throw (CiftiFileException); Nifti2Header(const QString &inputFileName) throw (CiftiFileException); Nifti2Header(QFile &inputFile) throw (CiftiFileException); Nifti2Header(const nifti_2_header &header) throw (CiftiFileException); ~Nifti2Header(); void readFile(const QString &inputFileName) throw (CiftiFileException); void readFile(QFile &inputFile) throw (CiftiFileException); void getHeaderStruct(nifti_2_header &header) const throw (CiftiFileException); void SetHeaderStuct(const nifti_2_header &header) throw (CiftiFileException); int getCiftiType(const nifti_2_header &header) const throw (CiftiFileException); int getCiftiType() const throw (CiftiFileException); void writeFile(QFile &outputFile) const throw (CiftiFileException); void writeFile(const QString &outputFileName) const throw (CiftiFileException); QString *getHeaderAsString(); void initHeaderStruct(nifti_2_header &header); void initHeaderStruct(); void initTimeSeriesHeaderStruct(nifti_2_header &header); void initTimeSeriesHeaderStruct(); bool getSwapNeeded(); void getCiftiDimensions(std::vector &dimensions); private: nifti_2_header m_header; bool m_swapNeeded; }; #endif //__NIFTI_2_HEADERcaret-5.6.4~dfsg.1.orig/caret_cifti/Nifti2Header.cxx0000664000175000017500000002726211572067322022036 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2011 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "Nifti2Header.h" #include Nifti2Header::Nifti2Header(const QString& inputFileName) throw (CiftiFileException) { readFile(inputFileName); } Nifti2Header::Nifti2Header(QFile &inputFile) throw (CiftiFileException) { readFile(inputFile); } void Nifti2Header::readFile(const QString& inputFileName) throw (CiftiFileException) { QFile inputFile; inputFile.setFileName(inputFileName); inputFile.open(QIODevice::ReadOnly); this->readFile(inputFile); inputFile.close(); } bool Nifti2Header::getSwapNeeded() { return m_swapNeeded; } void Nifti2Header::readFile(QFile &inputFile) throw (CiftiFileException) { int bytes_read = 0; m_swapNeeded=false; bytes_read = inputFile.read((char *)&m_header, NIFTI2_HEADER_SIZE); if(bytes_read < NIFTI2_HEADER_SIZE) { throw CiftiFileException("Error reading Cifti header, file is too short."); } if(NIFTI2_NEEDS_SWAP(m_header)) { m_swapNeeded = true; CiftiByteSwap::swapBytes(&(m_header.sizeof_hdr),1); CiftiByteSwap::swapBytes(&(m_header.datatype),1); CiftiByteSwap::swapBytes(&(m_header.bitpix),1); CiftiByteSwap::swapBytes(&(m_header.dim[0]),8); CiftiByteSwap::swapBytes(&(m_header.intent_p1),1); CiftiByteSwap::swapBytes(&(m_header.intent_p2),1); CiftiByteSwap::swapBytes(&(m_header.intent_p3),1); CiftiByteSwap::swapBytes(&(m_header.pixdim[0]),8); CiftiByteSwap::swapBytes(&(m_header.vox_offset),1); CiftiByteSwap::swapBytes(&(m_header.scl_slope),1); CiftiByteSwap::swapBytes(&(m_header.scl_inter),1); CiftiByteSwap::swapBytes(&(m_header.cal_max),1); CiftiByteSwap::swapBytes(&(m_header.cal_min),1); CiftiByteSwap::swapBytes(&(m_header.slice_duration),1); CiftiByteSwap::swapBytes(&(m_header.toffset),1); CiftiByteSwap::swapBytes(&(m_header.slice_start),1); CiftiByteSwap::swapBytes(&(m_header.slice_end),1); CiftiByteSwap::swapBytes(&(m_header.qform_code),1); CiftiByteSwap::swapBytes(&(m_header.sform_code),1); CiftiByteSwap::swapBytes(&(m_header.quatern_b),1); CiftiByteSwap::swapBytes(&(m_header.quatern_c),1); CiftiByteSwap::swapBytes(&(m_header.quatern_d),1); CiftiByteSwap::swapBytes(&(m_header.qoffset_x),1); CiftiByteSwap::swapBytes(&(m_header.qoffset_y),1); CiftiByteSwap::swapBytes(&(m_header.qoffset_z),1); CiftiByteSwap::swapBytes(&(m_header.srow_x[0]),4); CiftiByteSwap::swapBytes(&(m_header.srow_y[0]),4); CiftiByteSwap::swapBytes(&(m_header.srow_z[0]),4); CiftiByteSwap::swapBytes(&(m_header.slice_code),1); CiftiByteSwap::swapBytes(&(m_header.xyzt_units),1); CiftiByteSwap::swapBytes(&(m_header.intent_code),1); //throw CiftiFileException("The NIFTI standard only supports little-endian byte order."); std::cout <<"It is recommended that Cifti files are stored in little-endian byte order." << std::endl; } if((NIFTI2_VERSION(m_header))!=2) { throw CiftiFileException("This is not a valid Nifti2/Cifti File."); } } Nifti2Header::Nifti2Header(const nifti_2_header &header) throw (CiftiFileException) { memcpy((void *)&m_header,&header,sizeof(m_header)); } Nifti2Header::Nifti2Header() throw (CiftiFileException) { initHeaderStruct(m_header); } Nifti2Header::~Nifti2Header() { } QString *Nifti2Header::getHeaderAsString() { QString *string = new QString; *string += "header size: " + QString::number (m_header.sizeof_hdr) + "\n"; *string += "magic : " + QString::fromAscii(m_header.magic) + "\n"; *string += "Data Type: " + QString::number(m_header.datatype) + "\n"; *string += "bitpix: " + QString::number(m_header.bitpix) + "\n"; *string += "dim[0]: " + QString::number(m_header.dim[0]) + "\n"; *string += "intent_p1: " + QString::number(m_header.intent_p1) + "\n"; *string += "intent_p2: " + QString::number(m_header.intent_p2) + "\n"; *string += "intent_p3: " + QString::number(m_header.intent_p3) + "\n"; *string += "pixdim[0]: " + QString::number(m_header.pixdim[0] ) + "\n"; *string += "pixdim[1]: " + QString::number(m_header.pixdim[1]) + "\n"; *string += "pixdim[2]: " + QString::number(m_header.pixdim[2]) + "\n"; *string += "pixdim[3]: " + QString::number(m_header.pixdim[3]) + "\n"; *string += "pixdim[4]: " + QString::number(m_header.pixdim[4]) + "\n"; *string += "pixdim[5]: " + QString::number(m_header.pixdim[5]) + "\n"; *string += "pixdim[6]: " + QString::number(m_header.pixdim[6]) + "\n"; *string += "pixdim[7]: " + QString::number(m_header.pixdim[7]) + "\n"; *string += "vox_offset: " + QString::number(m_header.vox_offset) + "\n"; *string += "scl_scope: " + QString::number(m_header.scl_slope) + "\n"; *string += "scl_inter: " + QString::number(m_header.scl_inter) + "\n"; *string += "cal_max: " + QString::number(m_header.cal_max) + "\n"; *string += "cal_min: " + QString::number(m_header.cal_min) + "\n"; *string += "slice_duration: " + QString::number(m_header.slice_duration) + "\n"; *string += "toffset: " + QString::number(m_header.toffset) + "\n"; *string += "slice_start: " + QString::number(m_header.slice_start) + "\n"; *string += "slice_end: " + QString::number(m_header.slice_end) + "\n"; *string += "descrip: " + QString::fromAscii(m_header.descrip) + "\n"; *string += "aux_file: " + QString::fromAscii(m_header.aux_file) + "\n"; *string += "qform_code: " + QString::number(m_header.qform_code) + "\n"; *string += "sform_code: " + QString::number(m_header.sform_code) + "\n"; *string += "quatern_b: " + QString::number(m_header.quatern_b) + "\n"; *string += "quatern_c: " + QString::number(m_header.quatern_c) + "\n"; *string += "quatern_d: " + QString::number(m_header.quatern_d) + "\n"; *string += "qoffset_x: " + QString::number(m_header.qoffset_x) + "\n"; *string += "qoffset_y: " + QString::number(m_header.qoffset_y) + "\n"; *string += "qoffset_z: " + QString::number(m_header.qoffset_z) + "\n"; *string += "srow_x[0]: " + QString::number(m_header.srow_x[0]) + "\n"; *string += "srow_x[1]: " + QString::number(m_header.srow_x[1]) + "\n"; *string += "srow_x[2]: " + QString::number(m_header.srow_x[2]) + "\n"; *string += "srow_x[3]: " + QString::number(m_header.srow_x[3]) + "\n"; *string += "srow_y[0]: " + QString::number(m_header.srow_y[0]) + "\n"; *string += "srow_y[1]: " + QString::number(m_header.srow_y[1]) + "\n"; *string += "srow_y[2]: " + QString::number(m_header.srow_y[2]) + "\n"; *string += "srow_y[3]: " + QString::number(m_header.srow_y[3]) + "\n"; *string += "srow_z[0]: " + QString::number(m_header.srow_z[0]) + "\n"; *string += "srow_z[1]: " + QString::number(m_header.srow_z[1]) + "\n"; *string += "srow_z[2]: " + QString::number(m_header.srow_z[2]) + "\n"; *string += "srow_z[3]: " + QString::number(m_header.srow_z[3]) + "\n"; *string += "slice_code: " + QString::number(m_header.slice_code) + "\n"; *string += "xyzt_units: " + QString::number(m_header.xyzt_units) + "\n"; *string += "intent_code: " + QString::number(m_header.intent_code) + "\n"; *string += "intent_name: " + QString::fromAscii(m_header.intent_name) + "\n"; *string += "dim_info: " + QString::number(m_header.dim_info) + "\n"; //string + m_header.unused_str + "\n"; return string; } void Nifti2Header::getHeaderStruct(nifti_2_header &header) const throw (CiftiFileException) { memcpy(&header, &m_header, sizeof(m_header)); } void Nifti2Header::SetHeaderStuct(const nifti_2_header &header) throw (CiftiFileException) { memcpy(&m_header, &header, sizeof(m_header)); } int Nifti2Header::getCiftiType(const nifti_2_header &header) const throw (CiftiFileException) { return header.intent_code; } int Nifti2Header::getCiftiType() const throw (CiftiFileException) { return m_header.intent_code; } void Nifti2Header::writeFile(QFile &outputFile) const throw (CiftiFileException) { if(!outputFile.isOpen()) { if(!outputFile.open(QIODevice::WriteOnly)) { throw CiftiFileException("There was an error opening the file for writing."); } } if(outputFile.write((char *)&m_header,NIFTI2_HEADER_SIZE) != NIFTI2_HEADER_SIZE) { throw CiftiFileException("The was an error writing the header."); } //outputFile.close(); } void Nifti2Header::writeFile(const QString &outputFileName) const throw (CiftiFileException) { QFile outputFile; outputFile.setFileName(outputFileName); this->writeFile(outputFile); outputFile.close(); } void Nifti2Header::initHeaderStruct() { initHeaderStruct(this->m_header); } void Nifti2Header::initHeaderStruct(nifti_2_header &header) { header.sizeof_hdr = NIFTI2_HEADER_SIZE; memcpy(header.magic, "n+2\0\r\n\032\n",8); header.datatype = 0;//CIFTI_NONE; header.bitpix = 0;//TODO header.dim[0] = 0;//TODO header.intent_p1 = 0; header.intent_p2 = 0; header.intent_p3 = 0; header.pixdim[0] = 0.0;header.pixdim[1] = 1.0; header.pixdim[2] = 1.0;header.pixdim[3] = 1.0; header.pixdim[4] = 1.0;header.pixdim[5] = 1.0; header.pixdim[6] = 1.0;header.pixdim[7] = 1.0; header.vox_offset = 544;//TODO, currently set to minimum value header.scl_slope = 1; header.scl_inter = 0; header.cal_max = 0; header.cal_min = 0; header.slice_duration = 0; header.toffset = 0; header.slice_start = 0; header.slice_end = 0; memset(header.descrip,0x00,80); memset(header.aux_file,0x00,24); header.qform_code =0.0; header.sform_code =0.0; header.quatern_b = 0.0; header.quatern_c = 0.0; header.quatern_d = 0.0; header.qoffset_x = 0.0; header.qoffset_y = 0.0; header.qoffset_z = 0.0; header.srow_x[0] = 0.0; header.srow_x[1] = 0.0; header.srow_x[2] = 0.0; header.srow_x[3] = 0.0; header.srow_y[0] = 0.0; header.srow_y[1] = 0.0; header.srow_y[2] = 0.0; header.srow_y[3] = 0.0; header.srow_z[0] = 0.0; header.srow_z[1] = 0.0; header.srow_z[2] = 0.0; header.srow_z[3] = 0.0; header.slice_code = 0; header.xyzt_units = 0;//TODO header.intent_code = NIFTI_INTENT_NONE; memset(header.intent_name,0x00,16); header.dim_info = 0; memset(header.unused_str,0x00,15); } void Nifti2Header::initTimeSeriesHeaderStruct() { initTimeSeriesHeaderStruct(m_header); } void Nifti2Header::initTimeSeriesHeaderStruct(nifti_2_header &header) { initHeaderStruct(header); header.intent_code = NIFTI_INTENT_CONNECTIVITY_DENSE; header.datatype = NIFTI_TYPE_FLOAT32; header.dim[0] = 6;header.dim[1] = 1; header.dim[2] = 1;header.dim[3] = 1; header.dim[4] = 1;header.dim[5] = 0; header.dim[6] = 0;header.dim[7] = 1; header.bitpix = 32; strcpy(header.intent_name, "ConnDenseTime\0"); } void Nifti2Header::getCiftiDimensions(std::vector< int >& dimensions) { if(m_header.dim[5]!=1) dimensions.push_back(m_header.dim[5]); if(m_header.dim[6]!=1) dimensions.push_back(m_header.dim[6]); if(m_header.dim[7]!=1) dimensions.push_back(m_header.dim[7]); } caret-5.6.4~dfsg.1.orig/caret_cifti/CiftiXMLWriter.h0000664000175000017500000000403611572067322022025 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __CIFTI_XML_WRITER_H__ #define __CIFTI_XML_WRITER_H__ #include #include "CiftiXMLElements.h" void writeCiftiXML(QXmlStreamWriter &xml, CiftiRootElement &rootElement); void writeMatrixElement(QXmlStreamWriter &xml, CiftiMatrixElement &matrixElement); void writeMetaData(QXmlStreamWriter &xml, QHash &metaData); void writeMetaDataElement(QXmlStreamWriter &xml, const QString &name, const QString &value); void writeLabelTable(QXmlStreamWriter &xml, std::vector &labelElement); void writeLabel(QXmlStreamWriter &xml, CiftiLabelElement &label); void writeMatrixIndicesMap(QXmlStreamWriter &xml, CiftiMatrixIndicesMapElement &matrixIndicesMap); void writeBrainModel(QXmlStreamWriter &xml, CiftiBrainModelElement &brainModel); void writeVolume(QXmlStreamWriter &xml, CiftiVolume &volume); void writeTransformationMatrixVoxelIndicesIJKtoXYZ(QXmlStreamWriter &xml, TransformationMatrixVoxelIndicesIJKtoXYZ &transform); void getModelTypeString(int modelType, QString &modelTypeString); void getDataSpaceString(int dataSpace, QString &dataSpaceString); void getUnitsXYZString(int UnitsXYZ, QString &unitsXYZString); #endif //__CIFTI_XML_WRITER_H__caret-5.6.4~dfsg.1.orig/caret_cifti/CiftiXMLWriter.cxx0000664000175000017500000002433411572067322022403 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CiftiXMLWriter.h" #include "iostream" void writeCiftiXML(QXmlStreamWriter &xml, CiftiRootElement &rootElement) { xml.setAutoFormatting(true); xml.writeStartElement("CIFTI"); if(rootElement.m_version.length() >0) xml.writeAttribute("Version",rootElement.m_version); else xml.writeAttribute("Version","1.0"); xml.writeAttribute("NumberOfMatrices",QString::number(rootElement.m_numberOfMatrices)); for(unsigned int i = 0;i 0) writeMetaData(xml,matrixElement.m_userMetaData); 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"); QHash::Iterator i; for (i = metaData.begin(); i != metaData.end(); ++i) { writeMetaDataElement(xml,i.key(),i.value()); } xml.writeEndElement(); } void writeMetaDataElement(QXmlStreamWriter &xml, const QString &name, const QString &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 writeLabelTable(QXmlStreamWriter &xml, std::vector &labelElement) { xml.writeStartElement("LabelTable"); for(unsigned int i=0;i0) { QString str; xml.writeAttribute("TimeStep",str.sprintf("%.1f",matrixIndicesMap.m_timeStep)); 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 writeVolume(QXmlStreamWriter &xml, CiftiVolume &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 voxelIndices; QString s; for(int i = 0;i<15;i++) { voxelIndices.append(s.sprintf("%.1f ",transform.m_transform[i])); } voxelIndices.append(s.sprintf("%.1f", transform.m_transform[15])); xml.writeCharacters(voxelIndices); xml.writeEndElement(); } void 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 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 getUnitsXYZString(int unitsXYZ, QString &unitsXYZString) { if(unitsXYZ == NIFTI_UNITS_MM) unitsXYZString = "NIFTI_UNITS_MM"; else if(unitsXYZ == NIFTI_UNITS_MICRON) unitsXYZString = "NIFTI_UNITS_MICRON"; }caret-5.6.4~dfsg.1.orig/caret_cifti/CiftiXMLReader.h0000664000175000017500000000353311572067322021754 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __CIFTI_XML_READER_H__ #define __CIFTI_XML_READER_H__ #include "CiftiXMLElements.h" #include void parseCiftiXML(QXmlStreamReader &xml, CiftiRootElement &rootElement); void parseMatrixElement(QXmlStreamReader &xml, CiftiMatrixElement &matrixElement); void parseMetaData(QXmlStreamReader &xml, QHash &matrixElement); void parseMetaDataElement(QXmlStreamReader &xml, QHash &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 parseVolume(QXmlStreamReader &xml, CiftiVolume &volume); void parseTransformationMatrixVoxelIndicesIJKtoXYZ(QXmlStreamReader &xml, TransformationMatrixVoxelIndicesIJKtoXYZ &transform); #endif //__CIFTI_XML_READER_H__caret-5.6.4~dfsg.1.orig/caret_cifti/CiftiXMLReader.cxx0000664000175000017500000004467411572067322022342 0ustar michaelmichael#include #include #include "CiftiXMLElements.h" #include "iostream" #include "CiftiXMLReader.h" void 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 = attributes.value("Version").toString(); 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 std::cout << "unknown element: " << elementName.toAscii().data() << std::endl; } } if(xml.hasError()) { std::cout << "XML error: " << xml.errorString().toAscii().data() << std::endl; } else if(xml.atEnd()) { ;//std::cout << "Reached end, done" << std::endl; } } void 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(CiftiVolume()); parseVolume(xml,matrixElement.m_volume.back()); } else std::cout << "unknown element: " << elementName.toAscii().data() << std::endl; } } 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 parseMetaData(QXmlStreamReader &xml, QHash &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 std::cout << "unknown element: " << elementName.toAscii().data() << std::endl; } } //check for end element if(!xml.isEndElement() || (xml.name().toString() != "MetaData")) xml.raiseError("MetaData end tag not found."); } void parseMetaDataElement(QXmlStreamReader &xml, QHash &userMetaData) { QString name; QString value; QString test; 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(); 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(); xml.readNext(); if(!xml.isEndElement()) xml.raiseError("End element for meta data value tag not found."); } else std::cout << "unknown element: " << elementName.toAscii().data() << std::endl; } } userMetaData.insert(name,value); if(!xml.isEndElement() || (xml.name().toString() != "MD")) xml.raiseError("End element for MD tag not found"); } void 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 std::cout << "unknown element: " << elementName.toAscii().data() << std::endl; } } //check end element if(!xml.isEndElement() || (xml.name().toString() != "LabelTable")) { xml.raiseError("End element for label table not found."); } } void 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 parseMatrixIndicesMap(QXmlStreamReader &xml, CiftiMatrixIndicesMapElement &matrixIndicesMap) { QXmlStreamAttributes attributes = xml.attributes(); //get attribute values if(attributes.hasAttribute("AppliesToMatrixDimension")) { QStringList values = attributes.value("AppliesToMatrixDimension").toString().split(','); for(int i = 0;i #include #include "nifti2.h" /* Cifti Defines */ enum ModelType { CIFTI_MODEL_TYPE_SURFACE=1, CIFTI_MODEL_TYPE_VOXELS=2 }; enum IndicesMapToDataType { CIFTI_INDEX_TYPE_BRAIN_MODELS=1, CIFTI_INDEX_TYPE_FIBERS=2, CIFTI_INDEX_TYPE_PARCELS=3, CIFTI_INDEX_TYPE_TIME_POINTS=4 }; typedef unsigned long long voxelIndexType; class CiftiBrainModelElement { public: //CiftiBrainModelElement(); unsigned long long m_indexOffset; unsigned long long m_indexCount; ModelType m_modelType; QString m_brainStructure; unsigned long long m_surfaceNumberOfNodes; //children std::vector m_nodeIndices; std::vector m_voxelIndicesIJK; }; class CiftiMatrixIndicesMapElement { public: CiftiMatrixIndicesMapElement() { m_timeStep = -1.0; m_timeStepUnits = -1; } std::vector m_appliesToMatrixDimension; IndicesMapToDataType m_indicesMapToDataType; double m_timeStep; int m_timeStepUnits; std::vector m_brainModels; }; class CiftiLabelElement { public: CiftiLabelElement() { m_red = m_green = m_blue = m_alpha = m_x = m_y = m_z = 0.0; } unsigned long long m_key; float m_red; float m_green; float m_blue; float m_alpha; float m_x; float m_y; float m_z; QString m_text; }; class TransformationMatrixVoxelIndicesIJKtoXYZ { public: unsigned long m_dataSpace; unsigned long m_transformedSpace; unsigned long m_unitsXYZ; float m_transform[16]; }; class CiftiVolume { public: std::vector m_transformationMatrixVoxelIndicesIJKtoXYZ; unsigned int m_volumeDimensions[3]; }; class CiftiMatrixElement { public: std::vector m_labelTable;//TODO, this may be better as a hash QHash m_userMetaData; //user meta data std::vector m_matrixIndicesMap; std::vector m_volume; }; class CiftiRootElement { public: QString m_version; unsigned long m_numberOfMatrices; std::vector m_matrices; }; #endif //__CIFTI_ELEMENTScaret-5.6.4~dfsg.1.orig/caret_cifti/CiftiXMLElements.cxx0000664000175000017500000000162211572067322022676 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2011 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CiftiXMLElements.h" caret-5.6.4~dfsg.1.orig/caret_cifti/CiftiXML.h0000664000175000017500000000403211572067322020624 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2011 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __CIFTI_XML #define __CIFTI_XML #include "CiftiXMLElements.h" #include "CiftiXMLReader.h" #include "CiftiXMLWriter.h" #include class CiftiXML { public: //TODO create initializers for various types of XML meta data (Dense Connectivity, Dense Time Series, etc) CiftiXML() { } CiftiXML(CiftiRootElement &xml_root) { m_root = xml_root; } CiftiXML(const QByteArray &bytes) { readXML(bytes); } CiftiXML(const QString &xml_string) { readXML(xml_string); } CiftiXML(QXmlStreamReader &xml_stream) { readXML(xml_stream); } void readXML(const QByteArray &bytes) { QString text(bytes);readXML(text);} void readXML(const QString &text) {QXmlStreamReader xml(text); readXML(xml);} void readXML(QXmlStreamReader &xml_stream) { parseCiftiXML(xml_stream,m_root);} void writeXML(QString &text) { QXmlStreamWriter xml(&text); writeCiftiXML(xml,m_root);} void writeXML(QByteArray &bytes) { QXmlStreamWriter xml(&bytes); writeCiftiXML(xml,m_root);} void setXMLRoot (CiftiRootElement &xml_root) { m_root = xml_root; } void getXMLRoot (CiftiRootElement &xml_root) { xml_root = m_root; } protected: CiftiRootElement m_root; }; #endif//__CIFTI_XML caret-5.6.4~dfsg.1.orig/caret_cifti/CiftiXML.cxx0000664000175000017500000000156211572067322021204 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2011 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/caret-5.6.4~dfsg.1.orig/caret_cifti/CiftiMatrix.h0000664000175000017500000000507211572067322021435 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2011 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __CIFTI_MATRIX #define __CIFTI_MATRIX #include #include #include #include enum CACHE_LEVEL { IN_MEMORY, ON_DISK }; //warning!!! when using ON_DISK cache level, don't plan on using the file handle again, consider it gone, once handing it to a CiftiMatrix object. class CiftiMatrix { public: CiftiMatrix(QFile &file, std::vector &dimensions,CACHE_LEVEL clevel=IN_MEMORY) throw (CiftiFileException); CiftiMatrix(const QString &fileName, std::vector &dimensions, unsigned long long int offset, CACHE_LEVEL clevel=IN_MEMORY) throw (CiftiFileException); CiftiMatrix(const QString &fileName, std::vector &dimensions, CACHE_LEVEL clevel=IN_MEMORY) throw (CiftiFileException); CiftiMatrix() throw (CiftiFileException); ~CiftiMatrix(); void swapByteOrder(); void readMatrix(QFile &file, std::vector &dimensions); void readMatrix(const QString &fileName, std::vector &dimensions, unsigned long long offset); void readMatrix(const QString &fileName, std::vector &dimensions); void writeMatrix(QFile &file); void getMatrixData(float *&data, std::vector &dimensions);//gets the entire matrix, depending on the copy data preferences, //either copies all of the data void setMatrixData(float *data, std::vector &dimensions); void setCopyData(bool copyData); bool getCopyData(); protected: void freeMatrix(); void initMatrix(); void init(); void setDimensions(std::vector dimensions); float * m_matrix; unsigned long long m_length; std::vector m_dimensions; CACHE_LEVEL m_clevel; bool m_copyData; }; #endif //__CIFTI_MATRIXcaret-5.6.4~dfsg.1.orig/caret_cifti/CiftiMatrix.cxx0000664000175000017500000001145411572067322022011 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2011 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #ifdef Q_OS_WIN32 #include #else //not Q_OST_WIN32 #include #endif //ifdef Q_OS_WIN32 CiftiMatrix::CiftiMatrix(QFile &file, std::vector &dimensions,CACHE_LEVEL clevel) throw (CiftiFileException) { init(); m_clevel = clevel; readMatrix(file, dimensions); } CiftiMatrix::CiftiMatrix(const QString &fileName, std::vector &dimensions, unsigned long long offset, CACHE_LEVEL clevel) throw (CiftiFileException) { init(); m_clevel = clevel; readMatrix(fileName, dimensions, offset); } CiftiMatrix::CiftiMatrix(const QString &fileName, std::vector &dimensions, CACHE_LEVEL clevel) throw (CiftiFileException) { init(); m_clevel = clevel; readMatrix(fileName, dimensions); } CiftiMatrix::CiftiMatrix() throw (CiftiFileException) { init(); } CiftiMatrix::~CiftiMatrix() { freeMatrix(); } void CiftiMatrix::swapByteOrder() { CiftiByteSwap::swapBytes(m_matrix,m_length); } //gets the entire matrix, depending on the copy data preferences, //either copies all of the data void CiftiMatrix::getMatrixData(float *&matrix, std::vector &dimensions) { dimensions = m_dimensions; if(m_copyData) { matrix = new float [m_length]; memcpy((char *)matrix,(char *)m_matrix,m_length*4); } else { matrix = m_matrix; } } void CiftiMatrix::setMatrixData(float *data, std::vector &dimensions) { freeMatrix(); setDimensions(dimensions); if(m_copyData) { m_matrix = new float[m_length]; memcpy((char *)m_matrix,(char *)data, m_length*4); } else { m_matrix = data; } } void CiftiMatrix::setDimensions(std::vector dimensions) { m_dimensions = dimensions; m_length = m_dimensions[0]; for(unsigned int i =1;i &dimensions) { readMatrix(fileName, dimensions, 0); } void CiftiMatrix::readMatrix(const QString &fileName, std::vector &dimensions, unsigned long long offset) { QFile ciftiFile; ciftiFile.setFileName(fileName); if(m_clevel == IN_MEMORY) { ciftiFile.open(QIODevice::ReadOnly); if(offset) ciftiFile.seek(offset); readMatrix(ciftiFile,dimensions); } else if(m_clevel == ON_DISK) { CiftiFileException("ON_DISK file IO mode not yet implemented."); ciftiFile.open(QIODevice::ReadOnly); if(offset) ciftiFile.seek(offset); } } void CiftiMatrix::readMatrix(QFile &file, std::vector &dimensions) { freeMatrix(); setDimensions(dimensions); if(m_clevel == IN_MEMORY) { m_matrix = new float [m_length]; if(!m_matrix) CiftiFileException("Error allocating Cifti Matrix."); int fd = file.handle(); size_t bytes_read = 0; size_t bytes_needed = m_length * 4; char * position = (char *)m_matrix; while(bytes_read < bytes_needed) { position = (char *)m_matrix + bytes_read; bytes_read += read(fd, (void *)position, bytes_needed-bytes_read); } //unsigned long long bytes_read = file.readData((char *)(m_matrix),m_length); //bytes_read = file.read((char *)(m_matrix),1500000000); if(bytes_read != m_length*4) CiftiFileException("Error reading matrix from Cifti File."); } else if(m_clevel == ON_DISK) { CiftiFileException("ON_DISK file IO mode not yet implemented."); } } void CiftiMatrix::writeMatrix(QFile &file) { file.write((char *)m_matrix,m_length*4); }caret-5.6.4~dfsg.1.orig/caret_cifti/CiftiFileException.h0000664000175000017500000000333111572067322022723 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __CIFTI_FILE_EXCEPTION_H__ #define __CIFTI_FILE_EXCEPTION_H__ #include #include class StatisticException; /// Exception involving data files class CiftiFileException : public std::exception { public: // Constructor CiftiFileException(const QString& msg); /// Constructor CiftiFileException(const QString& filename, const QString& msg); /// Destructor virtual ~CiftiFileException() throw(); /// get description of exception virtual QString whatQString() const throw(); protected: /// Description of the exception QString exceptionDescription; private: /// get description of exception (private to prevent its use) virtual const char* what() const throw() { return ""; } }; #endif // __FILE_EXCEPTION_H__ caret-5.6.4~dfsg.1.orig/caret_cifti/CiftiFileException.cxx0000664000175000017500000000314311572067322023277 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CiftiFileException.h" CiftiFileException::CiftiFileException(const QString& msg) { exceptionDescription = msg; } /** * Constructor. */ CiftiFileException::CiftiFileException(const QString& filename, const QString& msg) { QString s("Error "); s.append(filename); s.append(": "); s.append(msg); exceptionDescription = s; } /** * Destructor. */ CiftiFileException::~CiftiFileException() throw() { } /** * Text message describing exception. */ /* const char* CiftiFileException::what() const throw() { return exceptionDescription.toAscii().constData(); } */ /** * Text message describing exception. */ QString CiftiFileException::whatQString() const throw() { return exceptionDescription; } caret-5.6.4~dfsg.1.orig/caret_cifti/CiftiFile.h0000664000175000017500000000600011572067322021040 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2011 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __CIFTI_FILE #define __CIFTI_FILE #include #include "nifti2.h" #include "iostream" #include "CiftiFileException.h" #include "Nifti2Header.h" #include "CiftiXML.h" #include "CiftiMatrix.h" class CiftiFile { public: CiftiFile(CACHE_LEVEL clevel = IN_MEMORY) throw (CiftiFileException); CiftiFile(const QString &fileName,CACHE_LEVEL clevel = IN_MEMORY) throw (CiftiFileException); virtual void openFile(const QString &fileName) throw (CiftiFileException); virtual void openFile(const QString &fileName, CACHE_LEVEL clevel) throw (CiftiFileException); virtual void writeFile(const QString &fileName) const throw (CiftiFileException); virtual void setHeader(const Nifti2Header &header) throw (CiftiFileException); virtual Nifti2Header * getHeader() throw (CiftiFileException); virtual void getHeader(Nifti2Header &header) throw (CiftiFileException); virtual void setCiftiXML(CiftiXML &ciftixml) throw (CiftiFileException); virtual CiftiXML * getCiftiXML() throw (CiftiFileException); virtual void getCiftiXML(CiftiXML &xml) throw (CiftiFileException); virtual void setCiftiMatrix(CiftiMatrix &matrix) throw (CiftiFileException); virtual CiftiMatrix * getCiftiMatrix() throw (CiftiFileException); virtual ~CiftiFile(); protected: virtual void init(); virtual void readHeader() throw (CiftiFileException); virtual void readCiftiMatrix() throw (CiftiFileException); bool m_copyMatrix;//determines whether matrix is copied, when retrieved or set. Avoiding a copy allows for memory usage to be halved, but has the caveats of allowing //other classes to access what should be private data //in the event that this flag is true, the internal pointer to the cifti matrix is set to null, and the file is read again upon access, so don't use this as a hack to meddle //with internal data. Doing will mean that each copy of the matrix that is retrieved will still be unique CACHE_LEVEL m_clevel; QFile m_inputFile; Nifti2Header *m_nifti2Header; CiftiMatrix *m_matrix; CiftiXML *m_xml; bool m_swapNeeded; }; #endif //__CIFTI_FILEcaret-5.6.4~dfsg.1.orig/caret_cifti/CiftiFile.cxx0000664000175000017500000001277311572067322021431 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2011 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CiftiFile.h" #include "CiftiXML.h" #include #include "CiftiXMLReader.h" #include "CiftiByteSwap.h" //CiftiFile CiftiFile::CiftiFile(CACHE_LEVEL clevel) throw (CiftiFileException) { init(); m_clevel = clevel; } CiftiFile::CiftiFile(const QString &fileName,CACHE_LEVEL clevel) throw (CiftiFileException) { init(); this->openFile(fileName, clevel); } void CiftiFile::init() { this->m_nifti2Header = NULL; this->m_clevel = IN_MEMORY; this->m_xml = NULL; this->m_matrix = NULL; this->m_swapNeeded = false; this->m_copyMatrix = false; } void CiftiFile::openFile(const QString &fileName) throw (CiftiFileException) { m_inputFile.setFileName(fileName); m_inputFile.open(QIODevice::ReadOnly); readHeader(); //read XML m_swapNeeded = m_nifti2Header->getSwapNeeded(); char extensions[4]; m_inputFile.read(extensions,4); unsigned int length; m_inputFile.read((char *)&length, 4); if(m_swapNeeded)CiftiByteSwap::swapBytes(&length,1); unsigned int ecode; m_inputFile.read((char *)&ecode,4); if(m_swapNeeded)CiftiByteSwap::swapBytes(&ecode,1); if(ecode != NIFTI_ECODE_CIFTI) throw CiftiFileException("Error reading extensions. Extension Code is not Cifti."); QByteArray bytes = m_inputFile.read(length-8);//we substract 8 since the length includes the ecode and length m_xml = new CiftiXML(bytes); //read Matrix readCiftiMatrix(); } void CiftiFile::openFile(const QString &fileName, CACHE_LEVEL clevel) throw (CiftiFileException) { m_clevel = clevel; this->openFile(fileName); } void CiftiFile::writeFile(const QString &fileName) const throw (CiftiFileException) { QFile outputFile(fileName); outputFile.open(QIODevice::WriteOnly); //Get XML string and length, which is needed to calculate the vox_offset stored in the Nifti Header QByteArray xmlBytes; m_xml->writeXML(xmlBytes); int length = 8 + xmlBytes.length(); int ecode = 32;//NIFTI_ECODE_CIFTI char bytes[4] = { 0x01, 0x00,0x00, 0x00}; nifti_2_header header; m_nifti2Header->getHeaderStruct(header); header.vox_offset = 544 + length; m_nifti2Header->SetHeaderStuct(header); //write out the file m_nifti2Header->writeFile(outputFile); outputFile.write(bytes,4); outputFile.write((char *)&length,4); outputFile.write((char *)&ecode,4); outputFile.write(xmlBytes); m_matrix->writeMatrix(outputFile); outputFile.close(); } CiftiFile::~CiftiFile() { if(m_nifti2Header) delete m_nifti2Header; } // Head IO void CiftiFile::setHeader(const Nifti2Header &header) throw (CiftiFileException) { if(m_nifti2Header) delete m_nifti2Header; m_nifti2Header = new Nifti2Header(header); } void CiftiFile::readHeader() throw (CiftiFileException) { if(m_nifti2Header != NULL) delete m_nifti2Header; m_nifti2Header = new Nifti2Header(m_inputFile); } Nifti2Header *CiftiFile::getHeader() throw (CiftiFileException) { if(m_nifti2Header == NULL) readHeader(); return new Nifti2Header(*m_nifti2Header); } void CiftiFile::getHeader(Nifti2Header &header) throw (CiftiFileException) { if(m_nifti2Header == NULL) readHeader(); header = *m_nifti2Header; } // Matrix IO void CiftiFile::setCiftiMatrix(CiftiMatrix & matrix) throw (CiftiFileException) { if(this->m_matrix) delete this->m_matrix; if(this->m_copyMatrix) { this->m_matrix = new CiftiMatrix(matrix); } else { this->m_matrix = &matrix; } } CiftiMatrix * CiftiFile::getCiftiMatrix() throw (CiftiFileException) { if(!this->m_matrix) readCiftiMatrix();//TODO check reset extension offset if needed if(this->m_copyMatrix) { return new CiftiMatrix(*m_matrix); } else { CiftiMatrix *temp = this->m_matrix; this->m_matrix = NULL; return temp; } } void CiftiFile::readCiftiMatrix() throw (CiftiFileException) { if(m_matrix != NULL) delete m_matrix; std::vector dimensions; m_nifti2Header->getCiftiDimensions(dimensions); m_matrix = new CiftiMatrix(m_inputFile, dimensions,m_clevel); m_matrix->setCopyData(m_copyMatrix); if(m_swapNeeded) m_matrix->swapByteOrder(); } // XML IO void CiftiFile::setCiftiXML(CiftiXML & xml) throw (CiftiFileException) { if(this->m_xml) delete this->m_xml; this->m_xml = new CiftiXML(xml); } CiftiXML * CiftiFile::getCiftiXML() throw (CiftiFileException) { if(!this->m_xml) return NULL;//readCiftiXML();//TODO check reset extension offset if needed return new CiftiXML(*m_xml); } void CiftiFile::getCiftiXML(CiftiXML &xml) throw (CiftiFileException) { if(!this->m_xml) return;//readCiftiXML();//TODO check reset extension offset if needed xml = *m_xml; } caret-5.6.4~dfsg.1.orig/caret_cifti/CiftiByteSwap.h0000664000175000017500000000503611572067322021727 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2011 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __CIFTI_BYTE_SWAP #define __CIFTI_BYTE_SWAP #include class CiftiByteSwap { public: /// byte swap the data static inline void swapBytes(char* n, int typeSize, unsigned long long numToSwap) { for(unsigned long long i = 0;i #include #include #include #include #include "CaretLinkedList.h" class TessEdge; class TessTriangle; class TessVertex; //*********************************************************************************** /// Class for a tessellation exception class TessellationException : public std::exception { public: /// Constructor TessellationException(const QString& s) { description = s; } /// Destructor virtual ~TessellationException() throw() { } /// get description of exception virtual const char* what() const throw() { return description.toAscii().constData(); } /// get description of exception QString whatQString() const throw() { return description; } protected: /// description of the exception QString description; }; //*********************************************************************************** /// Class for storing a dynamic (modifiable) tessellation class Tessellation { public: /// a vertex list typedef std::list VertexList; /// the vertex list iterator typedef std::list::iterator VertexListIterator; /// a vertex set typedef std::set VertexSet; /// the vertex set iterator typedef std::set::iterator VertexSetIterator; /// a vertex vector typedef std::vector VertexVector; /// the vertex vector iterator typedef std::vector::iterator VertexVectorIterator; /// an edge list typedef CaretLinkedList EdgeList; /// the edge list iterator //typedef std::list::iterator EdgeListIterator; /// an edge vector typedef std::vector EdgeVector; /// the edge vector iterator typedef std::vector::iterator EdgeVectorIterator; /// caret triangle list typedef CaretLinkedList CaretTriangleList; /// the triangle list typedef std::list TriangleList; /// the triangle list iterator typedef std::list::iterator TriangleListIterator; /// the triangle set typedef std::set TriangleSet; /// the triangle set iterator typedef std::set::iterator TriangleSetIterator; // Constructor Tessellation(); // Destructor ~Tessellation(); // clear the tessellation void clear(); // Add an edge to this tessellation. TessEdge* addEdge(TessVertex* tv1, TessVertex* tv2); // Remove an edge from the tessellation void removeEdge(TessEdge* te); // add a vertex to the tessellation void addVertex(TessVertex* tv); // add a triangle to the tessllation (vetices must be in tessellation) TessTriangle* addTriangle(TessVertex* tv1, TessVertex* tv2, TessVertex* tv3, EdgeVector& adjacentEdges); // find and edge with the two vertices TessEdge* findEdge(TessVertex* tv1, TessVertex* tv2, const bool edgeMustExist = true) throw (TessellationException); // remove a triangle from the tessellation void removeTriangle(TessTriangle* &tt); // Swap the edges of a triangle in the tessellation void swapTriangleEdges(TessTriangle* tt1, TessTriangle* tt2, TessTriangle* &newTriangle1, TessTriangle* &newTriangle2); /// get the vertices VertexVector* getVertexVector() { return &vertices; } /// get the edges EdgeList* getEdgeList() { return &edges; } /// get the triangles CaretTriangleList* getTriangleList() { return &triangles; } // Check the counts to verify that the tessellation is still correct. void getEulerCount(int& v, int& e, int& f, int& eulerCount) throw (TessellationException); // print counts of vertices, edges, triangles void printEulerCounts(const QString& message); protected: /// update an edge with a triangle void updateEdgeWithTriangle(TessTriangle* tt, TessVertex* tv1, TessVertex* tv2, std::vector& edgesToSearchFirst, const int edgeIndex); /// the vertices in the tessellation VertexVector vertices; /// the triangles in the tessellation CaretTriangleList triangles; /// the edges in the tessellation EdgeList edges; }; //*********************************************************************************** /// Class for storing a Tessellation vertex class TessVertex { public: // Constructor TessVertex(const int uniqueIDIn); // Destructor ~TessVertex(); // Add a triangle to the triangles that use this vertex void addTriangle(TessTriangle* tt); // Remove a triangle from the list of triangles that use this vertex void removeTriangle(TessTriangle* tt); /// get the unique ID int getUniqueID() const { return uniqueID; } /// get the triangles used Tessellation::TriangleList* getMyTriangles() { return &myTriangles; } // get a list of vertices that are neighbors of this vertex void getNeighborVertices(Tessellation::VertexList& vl); protected: /// Triangles used by this vertex Tessellation::TriangleList myTriangles; /// unique identification number int uniqueID; }; //*********************************************************************************** /// Class for storing a tessellation edge class TessEdge : public CaretLinkedList::Node { public: // Constructor TessEdge(TessVertex* tv1, TessVertex* tv2); // Constructor ~TessEdge(); // add a triangle to the list of two triangles that use this edge void addTriangle(TessTriangle* tt) throw (TessellationException); // get the number of triangles that use this edge int getNumberOfTrianglesUsingEdge() const; // Given a triangle, return the other triangle that uses this edge TessTriangle* getOtherTriangle(TessTriangle* tt); // remove a triangle from the list of two triangles that use this edge void removeTriangle(TessTriangle* tt) throw (TessellationException); protected: /// Vertices that are end points of this edge TessVertex* vertices[2]; /// Tiles using this edge TessTriangle* triangles[2]; /// Iterator for position of this edge in the EdgeList //Tessellation::EdgeListIterator edgeListPosition; friend class Tessellation; friend class TessTriangle; }; //*********************************************************************************** /// Class for storing a tessellation triangle class TessTriangle : public CaretLinkedList::Node { public: // Constructor TessTriangle(TessVertex* tv1, TessVertex* tv2, TessVertex* tv3); // Destructor ~TessTriangle(); // Disconnect this triangle from its edges and vertices (typically done before deleting this triangle) void disconnect(); // Given an adjacent triangle, find the edge that we share TessEdge* getCommonEdge(TessTriangle* tt) throw (TessellationException); // get vertex of triangle not part of the provided edge TessVertex* getVertexNotInEdge(TessEdge* te) throw (TessellationException); // get the vertex in the other triangle that is not used in this triangle TessVertex* getVertexNotInThisTriangle(TessTriangle* tt) throw (TessellationException); // get the edges in the triangle void getEdges(TessEdge* edgesOut[3]); // get the edges in the triangle but excluded edge (Note: edgesOut appended and not cleared) void getEdges(Tessellation::EdgeVector& edgesOut, TessEdge* excludeThisEdge); // get the edges in the triangle (Note: edgesOut appended and not cleared). void getEdges(Tessellation::EdgeVector& edgesOut); // get the vertices of the triangle void getVertices(TessVertex* &v1, TessVertex* &v2, TessVertex* &v3); // get the vertices of the triangle void getVertices(TessVertex* verticesOut[3]); // set the vertices of the triangle void setVertices(TessVertex* v1, TessVertex* v2, TessVertex* v3); // get the neighboring triangles adjacent to "me" void getNeighborTriangles(TessTriangle* neighbors[3]); protected: /// Vertices used by this triangle TessVertex* vertices[3]; /// Edges used by this triangle TessEdge* edges[3]; /// number of this triangle int triangleNumber; /// counter for triangles static int triangleCounter; /// Iterator for position of this triangle in the TriangleList Tessellation::TriangleListIterator triangleListPosition; friend class Tessellation; friend class TessEdge; friend class TessVertex; }; #ifdef __TESSELLATION_MAIN__ int TessTriangle::triangleCounter = 0; #endif // __TESSELLATION_MAIN__ #endif // __TESSELLATION_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/Tessellation.cxx0000664000175000017500000004156111572067322023106 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #define __TESSELLATION_MAIN__ #include "Tessellation.h" #undef __TESSELLATION_MAIN__ //********************************************************************************** //** TessVertex Methods //********************************************************************************** /** * Constructor. */ TessVertex::TessVertex(const int uniqueIDIn) { uniqueID = uniqueIDIn; } /** * Destructor. */ TessVertex::~TessVertex() { } /** * Add a triangle to the triangles that use this vertex. */ void TessVertex::addTriangle(TessTriangle* tt) { myTriangles.push_back(tt); } /** * Remove a triangle from the list of triangles that use this vertex. */ void TessVertex::removeTriangle(TessTriangle* tt) { /* if (std::find(myTriangles.begin(), myTriangles.end(), tt) == myTriangles.end()) { std::ostringstream str; str << "Trying to delete triangle " << tt->triangleNumber << " not associated with vertex " << uniqueID; throw TessellationException(str.str().c_str()); } */ myTriangles.remove(tt); } /** * get a list of vertices that are neighbors of this vertex. */ void TessVertex::getNeighborVertices(Tessellation::VertexList& vl) { // // Used to keep unique list of neighbor vertices // Tessellation::VertexSet vs; // // Loop through the triangles used by this vertex // for (Tessellation::TriangleListIterator tl = myTriangles.begin(); tl != myTriangles.end(); tl++) { TessTriangle* tt = *tl; // // Get the vertices in the triangle // TessVertex* tv[3]; tt->getVertices(tv); // // add vertices to the set // for (int i = 0; i < 3; i++) { if (tv[i] != this) { vs.insert(tv[i]); } } } // // update the output list // vl.clear(); vl.insert(vl.end(), vs.begin(), vs.end()); } //********************************************************************************** //** TessEdge Methods //********************************************************************************** /** * Constructor. */ TessEdge::TessEdge(TessVertex* tv1, TessVertex* tv2) { vertices[0] = tv1; vertices[1] = tv2; if (tv1 > tv2) { std::swap(vertices[0], vertices[1]); } triangles[0] = NULL; triangles[1] = NULL; } /** * Constructor. */ TessEdge::~TessEdge() { } /** * add a triangle to the list of two triangles that use this edge. */ void TessEdge::addTriangle(TessTriangle* tt) throw (TessellationException) { if (triangles[0] == NULL) { triangles[0] = tt; } else if (triangles[1] == NULL) { triangles[1] = tt; } else { std::ostringstream str; str << "TessEdge::addTriangle() Edge already has two triangles (" << triangles[0]->triangleNumber << ", " << triangles[1]->triangleNumber << ") while adding triangle " << tt->triangleNumber; throw TessellationException(str.str().c_str()); } if ((triangles[0] != NULL) && (triangles[1] != NULL)) { if (triangles[0] > triangles[1]) { std::swap(triangles[0], triangles[1]); } } } /** * get the number of triangles that use this edge. */ int TessEdge::getNumberOfTrianglesUsingEdge() const { int cnt = 0; if (triangles[0] != NULL) cnt++; if (triangles[1] != NULL) cnt++; return cnt; } /** * Given a triangle, return the other triangle that uses this edge. */ TessTriangle* TessEdge::getOtherTriangle(TessTriangle* tt) { if (triangles[0] == tt) { return triangles[1]; } else if (triangles[1] == tt) { return triangles[0]; } return NULL; } /** * remove a triangle from the list of two triangles that use this edge. */ void TessEdge::removeTriangle(TessTriangle* tt) throw (TessellationException) { if (triangles[0] == tt) { triangles[0] = triangles[1]; triangles[1] = NULL; } else if (triangles[1] == tt) { triangles[1] = NULL; } else { throw TessellationException("TessEdge::removeTriangle() failed."); } } //********************************************************************************** //** TessTriangle Methods //********************************************************************************** /** * Constructor. */ TessTriangle::TessTriangle(TessVertex* tv1, TessVertex* tv2, TessVertex* tv3) { vertices[0] = tv1; vertices[1] = tv2; vertices[2] = tv3; //std::sort(vertices, vertices + 3); edges[0] = NULL; edges[1] = NULL; edges[2] = NULL; triangleNumber = triangleCounter; triangleCounter++; //std::cout << "Creating triangle " << triangleNumber << std::endl; } /** * Destructor. */ TessTriangle::~TessTriangle() { //std::cout << "Deleting triangle " << triangleNumber << std::endl; } /** * Disconnect this triangle from its edges and vertices (typically done before deleting this triangle). */ void TessTriangle::disconnect() { // // Loop through the edges and vertices // for (int i = 0; i < 3; i++) { if (vertices[i] != NULL) { // // Remove "me" from the vertex // vertices[i]->removeTriangle(this); vertices[i] = NULL; } else { std::cout << "NULL vertex in TessTriangle::disconnect()" << std::endl; } if (edges[i] != NULL) { // // Remove "me" from the edge // edges[i]->removeTriangle(this); edges[i] = NULL; } else { std::cout << "NULL edge in TessTriangle::disconnect()" << std::endl; } } } /** * Given an adjacent triangle, find the edge that we share. */ TessEdge* TessTriangle::getCommonEdge(TessTriangle* tt) throw (TessellationException) { for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (edges[i] == tt->edges[j]) { return edges[i]; } } } throw TessellationException("TessTriangle::getCommonEdge() failed."); return NULL; } /** * get the neighboring triangles adjacent to "me". */ void TessTriangle::getNeighborTriangles(TessTriangle* neighbors[3]) { neighbors[0] = NULL; neighbors[1] = NULL; neighbors[2] = NULL; int cnt = 0; for (int i = 0; i < 3; i++) { TessTriangle* tt = edges[i]->getOtherTriangle(this); if (tt != NULL) { neighbors[cnt] = tt; cnt++; } } } /** * get the vertex in the other triangle that is not used in this triangle. */ TessVertex* TessTriangle::getVertexNotInThisTriangle(TessTriangle* tt) throw (TessellationException) { for (int i = 0; i < 3; i++) { bool found = false; TessVertex* tv = tt->vertices[i]; for (int j = 0; j < 3; j++) { if (tv == vertices[j]) { found = true; break; } } if (found == false) { return tv; } } // // The only way we should get here is if the two triangles are the SAME !!! // const QString msg("TessTriangle::getVertexNotInThisTriangle() failed.\n" "The two triangles (" + QString::number(triangleNumber) + " and " + QString::number(tt->triangleNumber) + " have the same vertices."); throw TessellationException(msg); } /** * get the vertices of the triangle. */ void TessTriangle::getVertices(TessVertex* &v1, TessVertex* &v2, TessVertex* &v3) { v1 = vertices[0]; v2 = vertices[1]; v3 = vertices[2]; } /** * get the vertices of the triangle. */ void TessTriangle::getVertices(TessVertex* verticesOut[3]) { verticesOut[0] = vertices[0]; verticesOut[1] = vertices[1]; verticesOut[2] = vertices[2]; } /** * set the vertices of the triangle. */ void TessTriangle::setVertices(TessVertex* v1, TessVertex* v2, TessVertex* v3) { vertices[0] = v1; vertices[1] = v2; vertices[2] = v3; } /** * get the edges in the triangle. */ void TessTriangle::getEdges(TessEdge* edgesOut[3]) { edgesOut[0] = edges[0]; edgesOut[1] = edges[1]; edgesOut[2] = edges[2]; } /** * get the edges in the triangle but excluded edge (Note: edgesOut appended and not cleared). */ void TessTriangle::getEdges(Tessellation::EdgeVector& edgesOut, TessEdge* excludeThisEdge) { for (int i = 0; i < 3; i++) { if ((edges[i] != NULL) && (edges[i] != excludeThisEdge)) { edgesOut.push_back(edges[i]); } } } /** * get the edges in the triangle (Note: edgesOut appended and not cleared). */ void TessTriangle::getEdges(Tessellation::EdgeVector& edgesOut) { for (int i = 0; i < 3; i++) { if (edges[i] != NULL) { edgesOut.push_back(edges[i]); } } } /** * get vertex of triangle not part of the provided edge. */ TessVertex* TessTriangle::getVertexNotInEdge(TessEdge* te) throw (TessellationException) { for (int i = 0; i < 3; i++) { if ((vertices[i] != NULL) && (vertices[i] != te->vertices[0]) && (vertices[i] != te->vertices[1])) { return vertices[i]; } } throw TessellationException("TessTriangle::getVertexNotInEdge() failed."); return NULL; } //********************************************************************************** //** Tessellation Methods //********************************************************************************** /** * Constructor. */ Tessellation::Tessellation() { clear(); } /** * Destructor. */ Tessellation::~Tessellation() { clear(); } /** * clear the tessellation. */ void Tessellation::clear() { TessTriangle::triangleCounter = 0; for (VertexVectorIterator iter = vertices.begin(); iter != vertices.end(); iter++) { delete *iter; } triangles.clear(); edges.clear(); } /** * add a vertex to the tessellation. */ void Tessellation::addVertex(TessVertex* tv) { vertices.push_back(tv); } /** * add a triangle to the tessllation. (vetices must be in tessellation) */ TessTriangle* Tessellation::addTriangle(TessVertex* tv1, TessVertex* tv2, TessVertex* tv3, EdgeVector& adjacentEdges) { // // Create a new triangle // TessTriangle* tt = new TessTriangle(tv1, tv2, tv3); // // Update vertices for this triangle // tv1->addTriangle(tt); tv2->addTriangle(tt); tv3->addTriangle(tt); // // Update the edges that use this triangle // updateEdgeWithTriangle(tt, tv1, tv2, adjacentEdges, 0); updateEdgeWithTriangle(tt, tv2, tv3, adjacentEdges, 1); updateEdgeWithTriangle(tt, tv3, tv1, adjacentEdges, 2); // // Add to the list of triangles // triangles.pushFront(tt); //tt->triangleListPosition = triangles.begin(); return tt; } /** * remove a triangle from the tessellation. */ void Tessellation::removeTriangle(TessTriangle* &tt) { tt->disconnect(); //triangles.erase(tt->triangleListPosition); triangles.remove(tt, true); //delete tt; //tt = NULL; } /** * Swap the edges of a triangle in the tessellation */ void Tessellation::swapTriangleEdges(TessTriangle* tt1, TessTriangle* tt2, TessTriangle* &newTriangle1, TessTriangle* &newTriangle2) { newTriangle1 = NULL; newTriangle2 = NULL; // // Get the edge shared by the two triangles // TessEdge* sharedEdge = tt1->getCommonEdge(tt2); // // Get vertices not in the shared edge // TessVertex* v1 = tt1->getVertexNotInEdge(sharedEdge); TessVertex* v2 = tt2->getVertexNotInEdge(sharedEdge); // // Get vertices of the shared edge // TessVertex* v3 = sharedEdge->vertices[0]; TessVertex* v4 = sharedEdge->vertices[1]; // // Get the edges other than the shared edge // EdgeVector adjacentEdges; tt1->getEdges(adjacentEdges, sharedEdge); tt2->getEdges(adjacentEdges, sharedEdge); // // Remove the two triangles from the tessellation // removeTriangle(tt1); removeTriangle(tt2); // // No longer need the edge // removeEdge(sharedEdge); // // Create the new edge from the vertices not in the shared edge // TessEdge* te = addEdge(v1, v2); adjacentEdges.push_back(te); // // Add the new triangles // newTriangle1 = addTriangle(v1, v2, v3, adjacentEdges); // 03/21/07 ***** newTriangle1->getEdges(adjacentEdges); newTriangle2 = addTriangle(v1, v2, v4, adjacentEdges); //int v, e, f, eulerCount; //getEulerCount(v, e, f, eulerCount); } /** * Add an edge to this tessellation. */ TessEdge* Tessellation::addEdge(TessVertex* tv1, TessVertex* tv2) { TessEdge* te = new TessEdge(tv1, tv2); edges.pushFront(te); //te->edgeListPosition = edges.begin(); return te; } /** * Remove an edge from the tessellation. The edge is also deleted. */ void Tessellation::removeEdge(TessEdge* te) { edges.remove(te, true); } /** * update an edge that uses a triangle. */ void Tessellation::updateEdgeWithTriangle(TessTriangle* tt, TessVertex* tv1, TessVertex* tv2, EdgeVector& edgesToSearchFirst, const int edgeIndex) { TessEdge* te = NULL; for (EdgeVectorIterator iter = edgesToSearchFirst.begin(); iter != edgesToSearchFirst.end(); iter++) { TessEdge* e = *iter; if (((e->vertices[0] == tv1) && (e->vertices[1] == tv2)) || ((e->vertices[0] == tv2) && (e->vertices[1] == tv1))) { te = e; break; } } if (te == NULL) { te = findEdge(tv1, tv2, false); //std::cout << "Searching all edges." << std::endl; } if (te == NULL) { te = addEdge(tv1, tv2); } te->addTriangle(tt); tt->edges[edgeIndex] = te; } /** * find and edge with the two vertices. */ TessEdge* Tessellation::findEdge(TessVertex* tv1a, TessVertex* tv2a, const bool edgeMustExist) throw (TessellationException) { // // Make tv1 the pointer with the smallest value // TessVertex* tv1 = tv1a; TessVertex* tv2 = tv2a; if (tv1 > tv2) { std::swap(tv1, tv2); } // // Find the edge - note: smallest vertex pointer in edge is in [0] // TessEdge* te = (TessEdge*)edges.getFront(); while (te != NULL) { if ((te->vertices[0] == tv2) && (te->vertices[1] == tv1)) { throw TessellationException("Edges out of order. in Tessellation::findEdge()"); } if ((te->vertices[0] == tv1) && (te->vertices[1] == tv2)) { return te; } te = (TessEdge*)te->getNext(); } if (edgeMustExist) { throw TessellationException("Tessellation::findEdge() failed."); } return NULL; } /** * Check the counts to verify that the tessellation is still correct. */ void Tessellation::getEulerCount(int& v, int& e, int& f, int& eulerCount) throw (TessellationException) { v = static_cast(vertices.size()); e = static_cast(edges.size()); f = static_cast(triangles.size()); eulerCount = v - e + f; if (eulerCount != 2) { std::ostringstream str; str << "Euler count invalid = " << eulerCount << " (V, E, F) = (" << v << ", " << e << ", " << f << ")"; throw TessellationException(str.str().c_str()); } } /** * print counts of vertices, edges, triangles. */ void Tessellation::printEulerCounts(const QString& message) { if (message.isEmpty() == false) { std::cout << message.toAscii().constData() << std::endl; } int V, E, F, eulerCount; getEulerCount(V, E, F, eulerCount); std::cout << "There are " << V << " vertices." << std::endl; std::cout << "There are " << E << " edges." << std::endl; std::cout << "There are " << F << " triangles." << std::endl; std::cout << "V - E + F = " << (V - E + F) << " should be 2" << std::endl; } caret-5.6.4~dfsg.1.orig/caret_brain_set/MetricsToRgbPaintConverter.h0000664000175000017500000000747311572067322025321 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_METRICS_TO_RGB_PAINT_CONVERTER_H__ #define __VE_METRICS_TO_RGB_PAINT_CONVERTER_H__ #include class MetricFile; class RgbPaintFile; /// Class that converts metrics to RGB Paint class MetricsToRgbPaintConverter { public: /// Constructor MetricsToRgbPaintConverter(); /// Destructor ~MetricsToRgbPaintConverter(); /// set rgb paint file info void setRgbPaintInfo(const int column, const QString& columnName, const QString& title); /// set red metric info void setRedMetric(const int column, const float negMax, const float posMax); /// set green metric info void setGreenMetric(const int column, const float negMax, const float posMax); /// set blue metric info void setBlueMetric(const int column, const float negMax, const float posMax); /// set red threshold info void setRedThresh(const int column, const float negMax, const float posMax); /// set green threshold info void setGreenThresh(const int column, const float negMax, const float posMax); /// set blue threshold info void setBlueThresh(const int column, const float negMax, const float posMax); /// convert metric to rgb paint (returns true if an error occurs) bool convert(const MetricFile* mf, RgbPaintFile* rgbPaintFile, QString& errorMessage); private: /// rgb paint column int rgbPaintColumn; /// rgb paint column name QString rgbPaintColumnName; /// rgb paint title QString rgbTitle; /// red metric column int redMetricColumn; /// green metric column int greenMetricColumn; /// blue metric column int blueMetricColumn; /// red metric negative max float redMetricNegMax; /// red metric positive max float redMetricPosMax; /// green metric negative max float greenMetricNegMax; /// green metric positive max float greenMetricPosMax; /// blue metric negative max float blueMetricNegMax; /// blue metric positive max float blueMetricPosMax; /// red threshold column int redThresholdColumn; /// green threshold column int greenThresholdColumn; /// blue threshold column int blueThresholdColumn; /// red threshold negative float redThresholdNeg; /// red threshold positive float redThresholdPos; /// green threshold negative float greenThresholdNeg; /// green threshold positive float greenThresholdPos; /// blue threshold negative float blueThresholdNeg; /// blue threshold positive float blueThresholdPos; }; #endif // __VE_METRICS_TO_RGB_PAINT_CONVERTER_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/MetricsToRgbPaintConverter.cxx0000664000175000017500000002145211572067322025665 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "MetricFile.h" #include "MetricsToRgbPaintConverter.h" #include "RgbPaintFile.h" /** * Constructor */ MetricsToRgbPaintConverter::MetricsToRgbPaintConverter() { } /** * Destructor */ MetricsToRgbPaintConverter::~MetricsToRgbPaintConverter() { } /** * set rgb paint file info. */ void MetricsToRgbPaintConverter::setRgbPaintInfo(const int column, const QString& columnName, const QString& title) { rgbPaintColumn = column; rgbPaintColumnName = columnName; rgbTitle = title; } /** * set red metric info. */ void MetricsToRgbPaintConverter::setRedMetric(const int column, const float negMax, const float posMax) { redMetricColumn = column; redMetricNegMax = negMax; redMetricPosMax = posMax; } /** * set green metric info. */ void MetricsToRgbPaintConverter::setGreenMetric(const int column, const float negMax, const float posMax) { greenMetricColumn = column; greenMetricNegMax = negMax; greenMetricPosMax = posMax; } /** * set blue metric info. */ void MetricsToRgbPaintConverter::setBlueMetric(const int column, const float negMax, const float posMax) { blueMetricColumn = column; blueMetricNegMax = negMax; blueMetricPosMax = posMax; } /** * set red threshold info. */ void MetricsToRgbPaintConverter::setRedThresh(const int column, const float neg, const float pos) { redThresholdColumn = column; redThresholdNeg = neg; redThresholdPos = pos; } /** * set green threshold info. */ void MetricsToRgbPaintConverter::setGreenThresh(const int column, const float neg, const float pos) { greenThresholdColumn = column; greenThresholdNeg = neg; greenThresholdPos = pos; } /** * set blue threshold info. */ void MetricsToRgbPaintConverter::setBlueThresh(const int column, const float neg, const float pos) { blueThresholdColumn = column; blueThresholdNeg = neg; blueThresholdPos = pos; } /** * convert the metric to rgb paint (returns true if an error occurs). */ bool MetricsToRgbPaintConverter::convert(const MetricFile* metricFile, RgbPaintFile* rgbPaintFile, QString& errorMessage) { bool errorFlag = false; errorMessage = ""; if ((redMetricColumn < 0) && (greenMetricColumn < 0) && (blueMetricColumn < 0)) { errorMessage = "You must select at least one metric column."; return true; } if (redMetricColumn >= 0) { if (redMetricNegMax > 0.0) { errorMessage.append("Red Neg Max must be less than or equal to zero.\n"); errorFlag = true; } if (redMetricPosMax < 0.0) { errorMessage.append("Red Pos Max must be greater than or equal to zero.\n"); errorFlag = true; } if (redThresholdColumn >= 0) { if (redThresholdNeg > 0.0) { errorMessage.append("Red Neg Threshold must be less than or equal to zero.\n"); errorFlag = true; } if (redThresholdPos < 0.0) { errorMessage.append("Red Pos Threshold must be greater than or equal to zero.\n"); errorFlag = true; } } } if (greenMetricColumn >= 0) { if (greenMetricNegMax > 0.0) { errorMessage.append("Green Neg Max must be less than or equal to zero.\n"); errorFlag = true; } if (greenMetricPosMax < 0.0) { errorMessage.append("Green Pos Max must be greater than or equal to zero.\n"); errorFlag = true; } if (greenThresholdColumn >= 0) { if (greenThresholdNeg > 0.0) { errorMessage.append("Green Neg Threshold must be less than or equal to zero.\n"); errorFlag = true; } if (greenThresholdPos < 0.0) { errorMessage.append("Green Pos Threshold must be greater than or equal to zero.\n"); errorFlag = true; } } } if (blueMetricColumn >= 0) { if (blueMetricNegMax > 0.0) { errorMessage.append("Blue Neg Max must be less than or equal to zero.\n"); errorFlag = true; } if (blueMetricPosMax < 0.0) { errorMessage.append("Blue Pos Max must be greater than or equal to zero.\n"); errorFlag = true; } if (blueThresholdColumn >= 0) { if (blueThresholdNeg > 0.0) { errorMessage.append("Blue Neg Threshold must be less than or equal to zero.\n"); errorFlag = true; } if (blueThresholdPos < 0.0) { errorMessage.append("Blue Pos Threshold must be greater than or equal to zero.\n"); errorFlag = true; } } } if (errorFlag) { return true; } // // Prepare the RGB Paint file // const int numNodes = metricFile->getNumberOfNodes(); if (rgbPaintColumn < 0) { if (rgbPaintFile->getNumberOfColumns() == 0) { rgbPaintFile->setNumberOfNodesAndColumns(numNodes, 1); rgbPaintColumn = 0; rgbPaintFile->setFileTitle(rgbTitle); } else { rgbPaintColumn = rgbPaintFile->getNumberOfColumns(); rgbPaintFile->addColumns(1); } } rgbPaintFile->setColumnName(rgbPaintColumn, rgbPaintColumnName); rgbPaintFile->setColumnComment(rgbPaintColumn, rgbTitle); // // Loop through nodes // for (int i = 0; i < numNodes; i++) { float r = 0, g = 0, b = 0; if (redMetricColumn >= 0) { r = metricFile->getValue(i, redMetricColumn); if (redThresholdColumn >= 0) { const float rt = metricFile->getValue(i, redThresholdColumn); if (rt >= 0.0) { if (rt < redThresholdPos) { r = 0.0; } } else { if (rt > redThresholdNeg) { r = 0.0; } } } } if (greenMetricColumn >= 0) { g = metricFile->getValue(i, greenMetricColumn); if (greenThresholdColumn >= 0) { const float gt = metricFile->getValue(i, greenThresholdColumn); if (gt >= 0.0) { if (gt < greenThresholdPos) { g = 0.0; } } else { if (gt > greenThresholdNeg) { g = 0.0; } } } } if (blueMetricColumn >= 0) { b = metricFile->getValue(i, blueMetricColumn); if (blueThresholdColumn >= 0) { const float bt = metricFile->getValue(i, blueThresholdColumn); if (bt >= 0.0) { if (bt < blueThresholdPos) { b = 0.0; } } else { if (bt > blueThresholdNeg) { b = 0.0; } } } } rgbPaintFile->setRgb(i, rgbPaintColumn, r, g, b); } if (redMetricColumn >= 0) { rgbPaintFile->setTitleRed(rgbPaintColumn, metricFile->getColumnName(redMetricColumn)); rgbPaintFile->setCommentRed(rgbPaintColumn, metricFile->getColumnComment(redMetricColumn)); rgbPaintFile->setScaleRed(rgbPaintColumn, redMetricNegMax, redMetricPosMax); } else { rgbPaintFile->setTitleRed(rgbPaintColumn, "Unused"); } if (greenMetricColumn >= 0) { rgbPaintFile->setTitleGreen(rgbPaintColumn, metricFile->getColumnName(greenMetricColumn)); rgbPaintFile->setCommentGreen(rgbPaintColumn, metricFile->getColumnComment(greenMetricColumn)); rgbPaintFile->setScaleGreen(rgbPaintColumn, greenMetricNegMax, greenMetricPosMax); } else { rgbPaintFile->setTitleGreen(rgbPaintColumn, "Unused"); } if (blueMetricColumn >= 0) { rgbPaintFile->setTitleBlue(rgbPaintColumn, metricFile->getColumnName(blueMetricColumn)); rgbPaintFile->setCommentBlue(rgbPaintColumn, metricFile->getColumnComment(blueMetricColumn)); rgbPaintFile->setScaleBlue(rgbPaintColumn, blueMetricNegMax, blueMetricPosMax); } else { rgbPaintFile->setTitleBlue(rgbPaintColumn, "Unused"); } return false; } caret-5.6.4~dfsg.1.orig/caret_brain_set/MetricAutoLoader.h0000664000175000017500000000031411572067322023257 0ustar michaelmichael/* * File: MetricAutoLoader.h * Author: john * * Created on August 5, 2009, 4:06 PM */ #ifndef __METRIC_AUTO_LOADER_H__ #define __METRIC_AUTO_LOADER_H__ #endif /* __METRIC_AUTO_LOADER_H__ */ caret-5.6.4~dfsg.1.orig/caret_brain_set/MapFmriAtlasSpecFileInfo.h0000664000175000017500000000651111572067322024630 0ustar michaelmichael #ifndef __GUI_MAP_FMRI_ATLAS_SPEC_FILE_INFO_H__ #define __GUI_MAP_FMRI_ATLAS_SPEC_FILE_INFO_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include class BrainSet; /// class for storage of atlas spec files and information class MapFmriAtlasSpecFileInfo { public: /// Constructor MapFmriAtlasSpecFileInfo(const QString& specFileNameIn); /// Destructor ~MapFmriAtlasSpecFileInfo(); /// read the atlases static void getAtlases(BrainSet* bs, std::vector& atlases); /// get the spec file path QString getSpecFilePath() const { return specFilePath; } /// get the spec file description QString getDescription() const { return description; } /// get the topology files QString getTopologyFile() const { return topoFile; } /// get the coordinate files std::vector getCoordinateFiles() const { return coordFiles; } /// get the average coordinate file QString getAverageCoordinateFile() const { return averageCoordinateFile; } /// get the validity of the data bool getDataValid() const { return dataValid; } /// get the species QString getSpecies() const { return species; } /// get the structure QString getStructure() const { return structure; } /// get the space QString getSpace() const { return space; } /// get the metric name hint QString getMetricNameHint() const { return metricNameHint; } /// comparison operator for sorting bool operator<(const MapFmriAtlasSpecFileInfo& asfi) const { return description < asfi.description; } protected: /// path of the spec file and its data files QString specFilePath; /// description from the spec file QString description; /// topology files for mapping QString topoFile; /// coordinate files for mapping std::vector coordFiles; /// spec file species QString species; /// spec file structure QString structure; /// spec file stereotaxic space QString space; /// metric name hint QString metricNameHint; /// average coordinate file QString averageCoordinateFile; /// data is valid bool dataValid; }; #endif // __GUI_MAP_FMRI_ATLAS_SPEC_FILE_INFO_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/MapFmriAtlasSpecFileInfo.cxx0000664000175000017500000001334211572067322025203 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainSet.h" #include "DebugControl.h" #include "FileUtilities.h" #include "MapFmriAtlasSpecFileInfo.h" #include "SpecFile.h" /** * Constructor. */ MapFmriAtlasSpecFileInfo::MapFmriAtlasSpecFileInfo(const QString& specFileNameIn) { dataValid = false; SpecFile sf; sf.setSorting(SpecFile::SORT_NAME); try { // // Get path to spec file and its data files // specFilePath = FileUtilities::dirname(specFileNameIn); // // Do not allow the spec file to be sorted // //sf.setSorting(SpecFile::SORT_NONE); // // Read the spec file // sf.readFile(specFileNameIn); // // Get the description from the spec file // description = sf.getHeaderTag("description"); if (description.isEmpty()) { description = FileUtilities::basename(specFileNameIn); } // // Get the fiducial coordinate files // coordFiles.clear(); for (int i = 0; i < sf.fiducialCoordFile.getNumberOfFiles(); i++) { coordFiles.push_back(sf.fiducialCoordFile.getFileName(i)); } // // get the average coordinate file // averageCoordinateFile = ""; if (sf.averageFiducialCoordFile.getNumberOfFiles() > 0) { averageCoordinateFile = sf.averageFiducialCoordFile.getFileName(0); } // // There should be only one topology file // if (sf.closedTopoFile.getNumberOfFiles() > 0) { topoFile = sf.closedTopoFile.getFileName(0); if (sf.closedTopoFile.getNumberOfFiles() > 1) { std::cout << "INFO: atlas spec file has more than one topology file. " << "First topology file used, others ignored: " << specFileNameIn.toAscii().constData() << std::endl; } } // // Get structure and species // structure = sf.getStructure().getTypeAsString(); species = sf.getSpecies().getName(); // // Get the space // space = sf.getSpace().getName(); if (space.isEmpty()) { space = "UNKNOWN"; } // // Get the metric name hint // metricNameHint = sf.getHeaderTag("metric_name_hint"); // // spec file is valid if it has both topo and coord files // if ((coordFiles.empty() == false) && (topoFile.isEmpty() == false)) { dataValid = true; } if (DebugControl::getDebugOn()) { QString msg; if (topoFile.isEmpty()) { msg += "\n has no closed topology file."; } if (averageCoordinateFile.isEmpty()) { msg += "\n has no average coordinate file."; } if (coordFiles.empty()) { msg += "\n has no fiducial coordinate files."; } if (msg.isEmpty() == false) { std::cout << "INFO: Atlas space \"" << space.toAscii().constData() << "\" structure \"" << structure.toAscii().constData() << "\"" << msg.toAscii().constData() << "\n from spec file " << FileUtilities::basename(specFileNameIn).toAscii().constData() << std::endl; } } } catch (FileException& e) { } } /** * Destructor. */ MapFmriAtlasSpecFileInfo::~MapFmriAtlasSpecFileInfo() { } /** * read the atlases. */ void MapFmriAtlasSpecFileInfo::getAtlases(BrainSet* bs, std::vector& atlases) { atlases.clear(); // // Look for atlas spec files in Caret installation directory. // QString atlasFilesDirectory = bs->getCaretHomeDirectory(); atlasFilesDirectory.append("/data_files/fmri_mapping_files"); std::vector files; QString fileExt("*"); fileExt.append(SpecFile::getSpecFileExtension()); FileUtilities::findFilesInDirectory(atlasFilesDirectory, QStringList(fileExt), files); // // Process each of the atlas spec files // for (int i = 0; i < static_cast(files.size()); i++) { // // Prepend path to name of atlas spec file // QString name(atlasFilesDirectory); name.append("/"); name.append(files[i]); // // See if spec files is valid // MapFmriAtlasSpecFileInfo asfi(name); if (asfi.getDataValid()) { atlases.push_back(asfi); } else { std::cout << "WARNING: invalid atlas spec file: " << name.toAscii().constData() << std::endl; } } // // Sort atlas spec file info // std::sort(atlases.begin(), atlases.end()); } caret-5.6.4~dfsg.1.orig/caret_brain_set/FociFileToPalsProjector.h0000664000175000017500000001523511572067322024557 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __FOCI_FILE_TO_PALS_PROJECTOR_H__ #define __FOCI_FILE_TO_PALS_PROJECTOR_H__ #include #include "BrainModelAlgorithm.h" #include "Structure.h" class CellProjection; class FociProjectionFile; class BrainModelSurfacePointProjector; class BrainSet; class MapFmriAtlasSpecFileInfo; class StudyMetaDataFile; /// This class is used to project a FocusFile to a BrainModelSurface and store the /// results in a cell projection file. class FociFileToPalsProjector : public BrainModelAlgorithm { public: /// Constructor FociFileToPalsProjector(BrainSet* brainSetIn, FociProjectionFile* fociProjectionFileIn, const StudyMetaDataFile* studyMetaDataFileIn, const int firstFocusIndexIn, const int lastFocusIndexIn, const float projectOntoSurfaceAboveDistanceIn, const bool projectOntoSurfaceFlagIn, const bool projectToCerebellumFlagIn, const float cerebralCutoffIn, const float cerebellumCutoffIn); /// Destructor ~FociFileToPalsProjector(); /// project the foci void execute() throw (BrainModelAlgorithmException); /// default cutoff for distance to cerebral cortex static float getDefaultCerebralCutoffDistance() { return 2.0; } /// default cutoff for distance to cerebellum static float getDefaultCerebellumCutoffDistance() { return 4.0; } /// set the index of the first focus to project void setFirstFocusIndex(const int firstFocusIndexIn, const int lastFocusIndexIn); protected: // // class for storing the point projectors // class PointProjector { public: /// constructor PointProjector(const QString& spaceNameIn, const Structure::STRUCTURE_TYPE structureTypeIn, BrainModelSurfacePointProjector* pointProjectorIn, BrainSet* bsIn, BrainModelSurface* bmsIn); /// destructor ~PointProjector(); /// get the space name QString getSpaceName() const { return spaceName; } /// get the structure Structure::STRUCTURE_TYPE getStructureType() const { return structureType; } /// equality operator bool operator==(const PointProjector& pp) const; /// brain set BrainSet* bs; /// surface used for projection BrainModelSurface* bms; /// original name of space QString originalSpaceName; /// name of space QString spaceName; /// structure Structure::STRUCTURE_TYPE structureType; /// the point projector BrainModelSurfacePointProjector* pointProjector; }; // project a single cell void projectFocus(CellProjection& cp, BrainModelSurface* bms, BrainModelSurfacePointProjector* pointProjector, const BrainModelSurface* searchSurface); // convert space names to identical spaces static void spaceNameConvert(QString& spaceName); // load the needed point projectors void loadNeededPointProjectors(const std::vector& projectorsNeeded) throw (BrainModelAlgorithmException); // find the surface for the specified space and structure BrainModelSurface* findSearchSurface(const QString& spaceName, const Structure::STRUCTURE_TYPE structure); // get distance of focus from a surface float getDistanceToSurface(const CellProjection* cp, const PointProjector* pp) const; // get point projector for space and structure PointProjector* getPointProjector(const QString& spaceName, const Structure::STRUCTURE_TYPE structure); // spaces currently loaded std::vector pointProjectors; // the file that is to be projected FociProjectionFile* fociProjectionFile; // the study metadata file const StudyMetaDataFile* studyMetaDataFile; // the first focus that is to be projected int firstFocusIndex; // the last focus that is to be projected (if -1 do all) int lastFocusIndex; // project onto surface distance const float projectOntoSurfaceAboveDistance; // project onto surface flag const bool projectOntoSurfaceFlag; /// project to cerebellum flag bool projectToCerebellumFlag; /// cerebral cortext cutoff float cerebralCutoff; /// cerebellum cutoff float cerebellumCutoff; /// atlases available for mapping foci std::vector availableAtlases; /// atlases need to be loaded flag bool atlasesDirectoryLoadedFlag; }; /* bool operator==(const FociFileToPalsProjector::PointProjector& pp1, const FociFileToPalsProjector::PointProjector& pp2) { const bool val = ((pp1.getSpaceName() == pp2.getSpaceName()) && (pp1.getStructureType() == pp2.getStructureType())); return val; } */ #endif // __FOCI_FILE_TO_PALS_PROJECTOR_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/FociFileToPalsProjector.cxx0000664000175000017500000012051211572067322025125 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #ifdef Q_OS_WIN32 #define NOMINMAX #endif #include #include #include #include #include #include #include "vtkLine.h" #include "vtkMath.h" #include "vtkPlane.h" #include "vtkTriangle.h" #include "BrainModelSurface.h" #include "BrainModelSurfacePointProjector.h" #include "BrainSet.h" #include "DebugControl.h" #include "FociFileToPalsProjector.h" #include "FociProjectionFile.h" #include "MapFmriAtlasSpecFileInfo.h" #include "MathUtilities.h" #include "StudyMetaDataFile.h" #include "TopologyFile.h" /** * Constructor. */ FociFileToPalsProjector::FociFileToPalsProjector(BrainSet* brainSetIn, FociProjectionFile* fociProjectionFileIn, const StudyMetaDataFile* studyMetaDataFileIn, const int firstFocusIndexIn, const int lastFocusIndexIn, const float projectOntoSurfaceAboveDistanceIn, const bool projectOntoSurfaceFlagIn, const bool projectToCerebellumFlagIn, const float cerebralCutoffIn, const float cerebellumCutoffIn) : BrainModelAlgorithm(brainSetIn), fociProjectionFile(fociProjectionFileIn), studyMetaDataFile(studyMetaDataFileIn), firstFocusIndex(firstFocusIndexIn), lastFocusIndex(lastFocusIndexIn), projectOntoSurfaceAboveDistance(projectOntoSurfaceAboveDistanceIn), projectOntoSurfaceFlag(projectOntoSurfaceFlagIn), projectToCerebellumFlag(projectToCerebellumFlagIn), cerebralCutoff(cerebralCutoffIn), cerebellumCutoff(cerebellumCutoffIn), atlasesDirectoryLoadedFlag(false) { } /** * Destructor. */ FociFileToPalsProjector::~FociFileToPalsProjector() { for (unsigned int i = 0; i < pointProjectors.size(); i++) { delete pointProjectors[i]; } pointProjectors.clear(); } /** * set the index of the first focus and last to project. */ void FociFileToPalsProjector::setFirstFocusIndex(const int firstFocusIndexIn, const int lastFocusIndexIn) { firstFocusIndex = firstFocusIndexIn; lastFocusIndex = lastFocusIndexIn; } /** * Project foci */ void FociFileToPalsProjector::execute() throw (BrainModelAlgorithmException) { try { if (atlasesDirectoryLoadedFlag == false) { atlasesDirectoryLoadedFlag = true; std::vector atlasList; MapFmriAtlasSpecFileInfo::getAtlases(brainSet, atlasList); if (atlasList.empty()) { throw BrainModelAlgorithmException("Unable to find PALS atlases. Is caret installed properly?"); } for (unsigned int i = 0; i < atlasList.size(); i++) { const MapFmriAtlasSpecFileInfo& mfi = atlasList[i]; if (mfi.getDataValid() && (mfi.getAverageCoordinateFile().isEmpty() == false) && (mfi.getTopologyFile().isEmpty() == false)) { availableAtlases.push_back(mfi); } } } if (fociProjectionFile == NULL) { throw BrainModelAlgorithmException("Invalid foci projection file for projecting."); } if (studyMetaDataFile == NULL) { throw BrainModelAlgorithmException("Invalid study metadata file for projecting."); } // // Remove all duplicates (cerebellar or cerebral) // if (lastFocusIndex < 0) { fociProjectionFile->deleteAllDuplicateCellProjections(); } const int numFoci = fociProjectionFile->getNumberOfCellProjections(); if ((numFoci <= 0) || (firstFocusIndex >= numFoci)) { throw BrainModelAlgorithmException("No foci for projecting."); } // // Find out the spaces that are needed for projecting the foci // QString fociWithoutSpaces; int spacesCount = 0; QString fociWithoutOriginalXYZ; int noXYZCount = 0; std::vector projectorsNeeded; std::vector focusSpace; if (numFoci > 0) { focusSpace.resize(numFoci, ""); } // // Always load the FLIRT atlas which is used for setting search XYZ // const QString flirtSpaceName("FLIRT"); { PointProjector pp1(flirtSpaceName, Structure::STRUCTURE_TYPE_CORTEX_LEFT, NULL, NULL, NULL); if (std::find(projectorsNeeded.begin(), projectorsNeeded.end(), pp1) == projectorsNeeded.end()) { projectorsNeeded.push_back(pp1); } PointProjector pp2(flirtSpaceName, Structure::STRUCTURE_TYPE_CORTEX_RIGHT, NULL, NULL, NULL); if (std::find(projectorsNeeded.begin(), projectorsNeeded.end(), pp2) == projectorsNeeded.end()) { projectorsNeeded.push_back(pp2); } if (projectToCerebellumFlag) { PointProjector pp3(flirtSpaceName, Structure::STRUCTURE_TYPE_CEREBELLUM, NULL, NULL, NULL); if (std::find(projectorsNeeded.begin(), projectorsNeeded.end(), pp3) == projectorsNeeded.end()) { projectorsNeeded.push_back(pp3); } } } // // Determine last focus to project // int lastFocusToProject = numFoci; if (lastFocusIndex >= 0) { lastFocusToProject = lastFocusIndex + 1; } // // Determine the needed stereotaxic spaces // for (int i = firstFocusIndex; i < lastFocusToProject; i++) { CellProjection* cp = fociProjectionFile->getCellProjection(i); const float* xyz = cp->getXYZ(); const StudyMetaDataLinkSet smdls = cp->getStudyMetaDataLinkSet(); const int numStudyMetaDataLinks = smdls.getNumberOfStudyMetaDataLinks(); if (numStudyMetaDataLinks > 0) { for (int m = 0; m < numStudyMetaDataLinks; m++) { const StudyMetaDataLink smdl = smdls.getStudyMetaDataLink(m); const int studyMetaDataIndex = studyMetaDataFile->getStudyIndexFromLink(smdl); if ((studyMetaDataIndex >= 0) && (studyMetaDataIndex < studyMetaDataFile->getNumberOfStudyMetaData())) { const StudyMetaData* smd = studyMetaDataFile->getStudyMetaData(studyMetaDataIndex); if (smd->getStereotaxicSpace().isEmpty() == false) { focusSpace[i] = smd->getStereotaxicSpace(); break; } } } } else { const int studyNumber = cp->getStudyNumber(); if ((studyNumber >= 0) && (studyNumber < fociProjectionFile->getNumberOfStudyInfo())) { const CellStudyInfo* csi = fociProjectionFile->getStudyInfo(studyNumber); focusSpace[i] = csi->getStereotaxicSpace(); } } if (focusSpace[i].isEmpty()) { fociWithoutSpaces += (QString::number(i) + " "); spacesCount++; if (spacesCount >= 10) { fociWithoutSpaces += "\n"; spacesCount = 0; } } else { /* 28 feb 2008 Structure::STRUCTURE_TYPE structure = Structure::STRUCTURE_TYPE_CORTEX_LEFT; if (xyz[0] > 0) { structure = Structure::STRUCTURE_TYPE_CORTEX_RIGHT; } cp->setCellStructure(structure); */ // // See if a new point projector is needed for left, right, and cerebellum // PointProjector pp1(focusSpace[i], Structure::STRUCTURE_TYPE_CORTEX_LEFT, NULL, NULL, NULL); if (std::find(projectorsNeeded.begin(), projectorsNeeded.end(), pp1) == projectorsNeeded.end()) { projectorsNeeded.push_back(pp1); } PointProjector pp2(focusSpace[i], Structure::STRUCTURE_TYPE_CORTEX_RIGHT, NULL, NULL, NULL); if (std::find(projectorsNeeded.begin(), projectorsNeeded.end(), pp2) == projectorsNeeded.end()) { projectorsNeeded.push_back(pp2); } if (projectToCerebellumFlag) { PointProjector pp3(focusSpace[i], Structure::STRUCTURE_TYPE_CEREBELLUM, NULL, NULL, NULL); if (std::find(projectorsNeeded.begin(), projectorsNeeded.end(), pp3) == projectorsNeeded.end()) { projectorsNeeded.push_back(pp3); } } } if ((xyz[0] == 0.0) && (xyz[1] == 0.0) && (xyz[2] == 0.0)) { fociWithoutOriginalXYZ += (QString::number(i) + " "); noXYZCount++; if (noXYZCount >= 10) { fociWithoutOriginalXYZ += "\n"; noXYZCount = 0; } } } // // Cannot project if spaces are missing // QString errorMessage; if (fociWithoutSpaces.isEmpty() == false) { errorMessage.append("These foci do not have associated sterotaxic spaces: \n"); errorMessage.append(fociWithoutSpaces); errorMessage.append("\n"); } if (fociWithoutOriginalXYZ.isEmpty() == false) { errorMessage.append("These foci are missing their original stereotaxic coordinates.\n" "They were probably loaded from an older version of the foci\n" "projection file that did not store the original foci coordinates.\n" "Indices of these foci: \n"); errorMessage.append(fociWithoutOriginalXYZ); errorMessage.append("\n"); } if (errorMessage.isEmpty() == false) { throw BrainModelAlgorithmException(errorMessage); } // // Number of foci to project // const int totalSteps = lastFocusToProject - firstFocusIndex + 1; // // Create the progress dialog // createProgressDialog("Map Foci to PALS Atlas", totalSteps, "mapFociToPalsProgressDialog"); // // load any needed point projectors // loadNeededPointProjectors(projectorsNeeded); // // Find the flirt surfaces for unprojection // BrainModelSurface* leftSearchSurface = findSearchSurface(flirtSpaceName, Structure::STRUCTURE_TYPE_CORTEX_LEFT); if (leftSearchSurface == NULL) { throw BrainModelAlgorithmException( "Unable to find left hemisphere search surface for " + flirtSpaceName); } BrainModelSurface* rightSearchSurface = findSearchSurface(flirtSpaceName, Structure::STRUCTURE_TYPE_CORTEX_RIGHT); if (rightSearchSurface == NULL) { throw BrainModelAlgorithmException( "Unable to find right hemisphere search surface for " + flirtSpaceName); } BrainModelSurface* cerebellumSearchSurface = NULL; if (projectToCerebellumFlag) { cerebellumSearchSurface = findSearchSurface(flirtSpaceName, Structure::STRUCTURE_TYPE_CEREBELLUM); if (cerebellumSearchSurface == NULL) { throw BrainModelAlgorithmException( "Unable to find cerebellum search surface for " + flirtSpaceName); } } // // Loop through the foci and project them // for (int i = firstFocusIndex; i < lastFocusToProject; i++) { updateProgressDialog("Mapping Focus " + QString::number(i), i + 1); CellProjection* cp = fociProjectionFile->getCellProjection(i); spaceNameConvert(focusSpace[i]); Structure::STRUCTURE_TYPE structure = cp->getCellStructure(); if (DebugControl::getDebugOn()) { std::cout << "Mapping " << i << " focus named " << cp->getName().toAscii().constData() << " with space " << focusSpace[i].toAscii().constData() << " structure " << Structure::convertTypeToString(structure).toAscii().constData() << std::endl; } // // Get Left, Right, and Cerebellum point projectors // const PointProjector* leftProjector = getPointProjector(focusSpace[i], Structure::STRUCTURE_TYPE_CORTEX_LEFT); if (leftProjector == NULL) { throw BrainModelAlgorithmException( "Unable to find left hemisphere point projector for " + focusSpace[i]); } const PointProjector* rightProjector = getPointProjector(focusSpace[i], Structure::STRUCTURE_TYPE_CORTEX_RIGHT); if (rightProjector == NULL) { throw BrainModelAlgorithmException( "Unable to find right hemisphere point projector for " + focusSpace[i]); } PointProjector* cerebellumProjector = NULL; if (projectToCerebellumFlag) { cerebellumProjector = getPointProjector(focusSpace[i], Structure::STRUCTURE_TYPE_CEREBELLUM); if (cerebellumProjector == NULL) { throw BrainModelAlgorithmException( "Unable to find cerebellum point projector for " + focusSpace[i]); } } // // Get distance to cerebellum and surface // float cerebellumDistance = 1000000.0; if (projectToCerebellumFlag) { cerebellumDistance = getDistanceToSurface(cp, cerebellumProjector); } float cerebralDistance = 10000000.0; float focusXYZ[3]; cp->getXYZ(focusXYZ); if (focusXYZ[0] > 0) { cerebralDistance = getDistanceToSurface(cp, rightProjector); } else { cerebralDistance = getDistanceToSurface(cp, leftProjector); } // // Determine to which structure foci should be projected // Structure::STRUCTURE_TYPE projectionStructure = Structure::STRUCTURE_TYPE_INVALID; Structure::STRUCTURE_TYPE cerebellumStructure = Structure::STRUCTURE_TYPE_INVALID; structure = Structure::STRUCTURE_TYPE_INVALID; if (projectToCerebellumFlag == false) { if (focusXYZ[0] < 0.0) { structure = Structure::STRUCTURE_TYPE_CORTEX_LEFT; } else { structure = Structure::STRUCTURE_TYPE_CORTEX_RIGHT; } projectionStructure = structure; } else { if (cerebellumDistance > 0.0) { // // Use ratios // const float focusRatio = cerebralDistance / cerebellumDistance; if (focusRatio <= cerebralCutoff) { if (focusXYZ[0] < 0.0) { structure = Structure::STRUCTURE_TYPE_CORTEX_LEFT; } else { structure = Structure::STRUCTURE_TYPE_CORTEX_RIGHT; } projectionStructure = structure; } else if (focusRatio > cerebellumCutoff) { structure = Structure::STRUCTURE_TYPE_CEREBELLUM; projectionStructure = structure; } else { if (focusXYZ[0] < 0.0) { structure = Structure::STRUCTURE_TYPE_CORTEX_LEFT_OR_CEREBELLUM; projectionStructure = Structure::STRUCTURE_TYPE_CORTEX_LEFT; cerebellumStructure = Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_LEFT; } else { structure = Structure::STRUCTURE_TYPE_CORTEX_RIGHT_OR_CEREBELLUM; projectionStructure = Structure::STRUCTURE_TYPE_CORTEX_RIGHT; cerebellumStructure = Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_RIGHT; } } } else { structure = Structure::STRUCTURE_TYPE_CEREBELLUM; } } cp->setCellStructure(structure); // // Set the search surface // BrainModelSurface* searchSurface = NULL; switch (projectionStructure) { case Structure::STRUCTURE_TYPE_CORTEX_LEFT: case Structure::STRUCTURE_TYPE_CORTEX_LEFT_OR_CEREBELLUM: searchSurface = leftSearchSurface; break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT: case Structure::STRUCTURE_TYPE_CORTEX_RIGHT_OR_CEREBELLUM: searchSurface = rightSearchSurface; break; case Structure::STRUCTURE_TYPE_CORTEX_BOTH: case Structure::STRUCTURE_TYPE_CEREBELLUM: case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_LEFT: case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_RIGHT: searchSurface = cerebellumSearchSurface; break; case Structure::STRUCTURE_TYPE_CEREBRUM_CEREBELLUM: case Structure::STRUCTURE_TYPE_SUBCORTICAL: case Structure::STRUCTURE_TYPE_ALL: case Structure::STRUCTURE_TYPE_INVALID: break; } // // Find the point projector // PointProjector *pp = NULL; PointProjector *cerebellumPP = NULL; for (unsigned int j = 0; j < pointProjectors.size(); j++) { if ((pointProjectors[j]->spaceName == focusSpace[i]) && (pointProjectors[j]->structureType == projectionStructure)) { pp = pointProjectors[j]; } if (cerebellumStructure != Structure::STRUCTURE_TYPE_INVALID) { if ((pointProjectors[j]->spaceName == focusSpace[i]) && (pointProjectors[j]->structureType == Structure::STRUCTURE_TYPE_CEREBELLUM)) { cerebellumPP = pointProjectors[j]; } } } if (pp == NULL) { QString msg("Unable to find point projector for focus "); msg.append(QString::number(i)); msg.append(" space "); msg.append(focusSpace[i]); throw BrainModelAlgorithmException(msg); } // // Project the focus // projectFocus(*cp, pp->bms, pp->pointProjector, searchSurface); // // If also projecting to the cerebellum // if (cerebellumPP != NULL) { // // Copy focus and add it to file // fociProjectionFile->addCellProjection(CellProjection(*cp)); CellProjection* cerebellumFocus = fociProjectionFile->getCellProjection( fociProjectionFile->getNumberOfCellProjections() - 1); // // Set the structure, duplicate flag, and project it // cerebellumFocus->setCellStructure(cerebellumStructure); cerebellumFocus->setDuplicateFlag(true); projectFocus(*cerebellumFocus, cerebellumPP->bms, cerebellumPP->pointProjector, cerebellumSearchSurface); } } } catch (BrainModelAlgorithmException& e) { removeProgressDialog(); throw BrainModelAlgorithmException(e); } removeProgressDialog(); } /** * get point projector for space and structure. */ FociFileToPalsProjector::PointProjector* FociFileToPalsProjector::getPointProjector(const QString& spaceName, const Structure::STRUCTURE_TYPE structure) { for (unsigned int m = 0; m < pointProjectors.size(); m++) { PointProjector* pp = pointProjectors[m]; if ((pp->structureType == structure) && (pp->spaceName == spaceName)) { return pp; } } return NULL; } /** * Find surface for space and structure. */ BrainModelSurface* FociFileToPalsProjector::findSearchSurface(const QString& spaceName, const Structure::STRUCTURE_TYPE structure) { for (unsigned int m = 0; m < pointProjectors.size(); m++) { PointProjector* pp = pointProjectors[m]; if ((pp->structureType == structure) && (pp->spaceName == spaceName)) { return pp->bms; } } return NULL; } /** * load the needed point projectors. */ void FociFileToPalsProjector::loadNeededPointProjectors(const std::vector& projectorsNeeded) throw (BrainModelAlgorithmException) { for (unsigned int i = 0; i < projectorsNeeded.size(); i++) { // // Does this point projector NOT exist ? // bool ppFound = false; for (unsigned int m = 0; m < pointProjectors.size(); m++) { if (*(pointProjectors[m]) == projectorsNeeded[i]) { ppFound = true; } } if (ppFound == false) { // // Find matching atlas // MapFmriAtlasSpecFileInfo* matchingAtlas = NULL; for (unsigned int j = 0; j < availableAtlases.size(); j++) { const Structure::STRUCTURE_TYPE atlasStructure = Structure::convertStringToType(availableAtlases[j].getStructure()); const QString atlasSpace = availableAtlases[j].getSpace(); if ((atlasStructure == projectorsNeeded[i].structureType) && (atlasSpace == projectorsNeeded[i].spaceName)) { matchingAtlas = &availableAtlases[j]; break; } } // // No atlas available ?? // if (matchingAtlas == NULL) { QString msg("Unable to find atlas in space \"" + projectorsNeeded[i].originalSpaceName + "\" for structure \"" + Structure::convertTypeToString(projectorsNeeded[i].structureType) + "\""); throw BrainModelAlgorithmException(msg); } updateProgressDialog("Loading atlas for " + matchingAtlas->getSpace() + " " + matchingAtlas->getStructure()); // // Save current directory // const QString savedDirectory = QDir::currentPath(); // // Set to atlas directory // QDir::setCurrent(matchingAtlas->getSpecFilePath()); // // Create surface for brain model // BrainSet* bs = new BrainSet(matchingAtlas->getTopologyFile(), matchingAtlas->getAverageCoordinateFile()); if (bs->getNumberOfBrainModels() == 0) { QString msg("Error loading atlas "); msg.append(matchingAtlas->getDescription()); delete bs; throw BrainModelAlgorithmException(msg); } BrainModelSurface* bms = bs->getBrainModelSurface(0); if (bms == NULL) { QString msg("Error loading atlas (no brain model surface) "); msg.append(matchingAtlas->getDescription()); delete bs; throw BrainModelAlgorithmException(msg); } TopologyFile* tf = bms->getTopologyFile(); if (tf == NULL) { QString msg("Error loading atlas (no topology file) "); msg.append(matchingAtlas->getDescription()); delete bs; throw BrainModelAlgorithmException(msg); } // // Create a point projector // BrainModelSurfacePointProjector* pointProjector = new BrainModelSurfacePointProjector(bms, BrainModelSurfacePointProjector::SURFACE_TYPE_HINT_OTHER, false); // // Load the brain model and point projectors for atlas // PointProjector* pp = new PointProjector(projectorsNeeded[i].spaceName, projectorsNeeded[i].structureType, pointProjector, bs, bms); pointProjectors.push_back(pp); // // Restore directory // QDir::setCurrent(savedDirectory); if (DebugControl::getDebugOn()) { std::cout << "Loaded PALS " << pp->spaceName.toAscii().constData() << " " << Structure::convertTypeToString(pp->structureType).toAscii().constData() << std::endl; } } } } /** * convert space names to identical spaces. */ void FociFileToPalsProjector::spaceNameConvert(QString& spaceName) { if (spaceName.startsWith("711-2") || spaceName.startsWith("7112")) { spaceName = "711-2C"; } else if (spaceName.startsWith("T88")) { spaceName = "AFNI"; } } /** * get distance of focus from a surface. */ float FociFileToPalsProjector::getDistanceToSurface(const CellProjection* cp, const PointProjector* pp) const { float distance = 0.0; // // Get the position of the focus // float xyz[3]; cp->getXYZ(xyz); // // Project to nearest node // const int nodeNum = pp->pointProjector->projectToNearestNode(xyz); if (nodeNum >= 0) { const CoordinateFile* cf = pp->bms->getCoordinateFile(); distance = cf->getDistanceToPoint(nodeNum, xyz); } return distance; } /** * Project a focus. Returns true if the focus was projected. */ void FociFileToPalsProjector::projectFocus(CellProjection& cp, BrainModelSurface* bms, BrainModelSurfacePointProjector* pointProjector, const BrainModelSurface* searchSurface) { CoordinateFile* coordinateFile = bms->getCoordinateFile(); TopologyFile* topologyFile = bms->getTopologyFile(); // // Initialize search position // cp.setSearchXYZ(0.0, 0.0, 0.0); // // Get the position of the focus // float xyz[3]; cp.getXYZ(xyz); // // Default to not projected // cp.projectionType = CellProjection::PROJECTION_TYPE_UNKNOWN; // // If position is unknown, cannot project focus // if ((xyz[0] == 0.0) && (xyz[1] == 0.0) && (xyz[2] == 0.0)) { return; } // // Set the fiducial position of the focus projection // cp.posFiducial[0] = xyz[0]; cp.posFiducial[1] = xyz[1]; cp.posFiducial[2] = xyz[2]; int nearestTileNumber, tileNodes[3]; float barycentricAreas[3], distance, distanceComponents[3], signedDistance; // // Project to the surface // const int result = pointProjector->projectBarycentricNearestTile(xyz, nearestTileNumber, tileNodes, barycentricAreas, signedDistance, distance, distanceComponents); // // Signed distance to surface // cp.setSignedDistanceAboveSurface(signedDistance); // // Did focus project inside a tile ? // if (result > 0) { cp.projectionType = CellProjection::PROJECTION_TYPE_INSIDE_TRIANGLE; cp.closestTileVertices[0] = tileNodes[2]; cp.closestTileVertices[1] = tileNodes[1]; cp.closestTileVertices[2] = tileNodes[0]; cp.closestTileAreas[0] = barycentricAreas[1]; cp.closestTileAreas[1] = barycentricAreas[0]; cp.closestTileAreas[2] = barycentricAreas[2]; cp.cdistance[0] = distanceComponents[0]; cp.cdistance[1] = distanceComponents[1]; cp.cdistance[2] = distanceComponents[2]; if (projectOntoSurfaceFlag) { float tileNormal[3]; MathUtilities::computeNormal((float*)coordinateFile->getCoordinate(tileNodes[0]), (float*)coordinateFile->getCoordinate(tileNodes[1]), (float*)coordinateFile->getCoordinate(tileNodes[2]), tileNormal); cp.cdistance[0] = tileNormal[0] * projectOntoSurfaceAboveDistance; cp.cdistance[1] = tileNormal[1] * projectOntoSurfaceAboveDistance; cp.cdistance[2] = tileNormal[2] * projectOntoSurfaceAboveDistance; cp.signedDistanceAboveSurface = projectOntoSurfaceAboveDistance; } } // // Is focus supposed to be projected onto the surface ? // else if (projectOntoSurfaceFlag) { const int nearestNode = pointProjector->projectToNearestNode(xyz); if (nearestNode >= 0) { cp.projectionType = CellProjection::PROJECTION_TYPE_INSIDE_TRIANGLE; cp.closestTileVertices[0] = nearestNode; cp.closestTileVertices[1] = nearestNode; cp.closestTileVertices[2] = nearestNode; cp.closestTileAreas[0] = 1.0; cp.closestTileAreas[1] = 1.0; cp.closestTileAreas[2] = 1.0; const float* normal = bms->getNormal(nearestNode); cp.cdistance[0] = normal[0] * projectOntoSurfaceAboveDistance; cp.cdistance[1] = normal[1] * projectOntoSurfaceAboveDistance; cp.cdistance[2] = normal[2] * projectOntoSurfaceAboveDistance; cp.signedDistanceAboveSurface = projectOntoSurfaceAboveDistance; } else { return; } } // // Did focus project outside a tile ? // else if (result < 0) { cp.projectionType = CellProjection::PROJECTION_TYPE_OUTSIDE_TRIANGLE; // // Vertices of closest tile // int v1, v2, v3; topologyFile->getTile(nearestTileNumber, v1, v2, v3); const float* p1 = coordinateFile->getCoordinate(v1); const float* p2 = coordinateFile->getCoordinate(v2); const float* p3 = coordinateFile->getCoordinate(v3); // // focus projected to plane of nearest tile // float planeNormal[3]; MathUtilities::computeNormal(p1, p2, p3, planeNormal); float cellProjectedToPlane[3]; #ifdef HAVE_VTK5 double xyzd[3] = { xyz[0], xyz[1], xyz[2] }; double p1d[3] = { p1[0], p1[1], p1[2] }; double dn[3] = { planeNormal[0], planeNormal[1], planeNormal[2] }; double cellProjD[3]; vtkPlane::ProjectPoint(xyzd, p1d, dn, cellProjD); cellProjectedToPlane[0] = cellProjD[0]; cellProjectedToPlane[1] = cellProjD[1]; cellProjectedToPlane[2] = cellProjD[2]; #else // HAVE_VTK5 vtkPlane::ProjectPoint((float*)xyz, (float*)p1, planeNormal, cellProjectedToPlane); #endif // HAVE_VTK5 // // Find vertices of edge closest to cell projected to plane // int closestVertices[2]; const float dist1 = MathUtilities::distancePointToLine3D(xyz, p1, p2); const float dist2 = MathUtilities::distancePointToLine3D(xyz, p2, p3); const float dist3 = MathUtilities::distancePointToLine3D(xyz, p3, p1); if ((dist1 < dist2) && (dist1 < dist3)) { closestVertices[0] = v1; closestVertices[1] = v2; } else if ((dist2 < dist1) && (dist2 < dist3)) { closestVertices[0] = v2; closestVertices[1] = v3; } else { closestVertices[0] = v3; closestVertices[1] = v1; } const int iR = closestVertices[0]; const int jR = closestVertices[1]; const int triA = nearestTileNumber; const int triB = topologyFile->getTileWithVertices(iR, jR, triA); float coordJR[3]; coordinateFile->getCoordinate(jR, coordJR); float coordIR[3]; coordinateFile->getCoordinate(iR, coordIR); float normalA[3]; if (triA >= 0){ int v1, v2, v3; topologyFile->getTile(triA, v1, v2, v3); const float* p1 = coordinateFile->getCoordinate(v1); const float* p2 = coordinateFile->getCoordinate(v2); const float* p3 = coordinateFile->getCoordinate(v3); MathUtilities::computeNormal((float*)p1, (float*)p2, (float*)p3, normalA); } float normalB[3]; if (triB >= 0){ int v1, v2, v3; topologyFile->getTile(triB, v1, v2, v3); const float* p1 = coordinateFile->getCoordinate(v1); const float* p2 = coordinateFile->getCoordinate(v2); const float* p3 = coordinateFile->getCoordinate(v3); MathUtilities::computeNormal((float*)p1, (float*)p2, (float*)p3, normalB); } else { cp.dR = std::sqrt(vtkMath::Distance2BetweenPoints(cellProjectedToPlane, xyz)); float v[3]; MathUtilities::subtractVectors(coordJR, coordIR, v); float t1[3]; MathUtilities::subtractVectors(xyz, coordIR, t1); float t2 = MathUtilities::dotProduct(v, v); float t3 = MathUtilities::dotProduct(t1, v); float QR[3]; for (int j = 0; j < 3; j++) QR[j] = coordIR[j] + ((t3/t2) * v[j]); MathUtilities::subtractVectors(coordJR, coordIR, v); t2 = MathUtilities::vectorLength(v); MathUtilities::subtractVectors(QR, coordIR, t1); t3 = MathUtilities::vectorLength(t1); if (t2 > 0.0) cp.fracRI = t3/t2; else cp.fracRI = 0.0; MathUtilities::subtractVectors(coordIR, coordJR, v); t2 = MathUtilities::vectorLength(v); MathUtilities::subtractVectors(QR, coordJR, t1); t3 = MathUtilities::vectorLength(t1); if (t2 > 0.0) cp.fracRJ = t3/t2; else cp.fracRI = 0.0; if (cp.fracRI > 1.0){ for (int j = 0; j < 3; j++) QR[j] = coordJR[j]; } if (cp.fracRJ > 1.0){ for (int j = 0; j < 3; j++) QR [j] = coordIR[j]; } MathUtilities::subtractVectors(xyz, cellProjectedToPlane, t1); t2 = MathUtilities::vectorLength(t1); if (t2 > 0){ for (int j = 0; j < 3; j++) t1[j] = t1[j]/t2; } t3 = MathUtilities::dotProduct(t1, normalA); for (int j = 0; j < 3; j++) xyz[j] = QR[j] + (cp.dR * t3 * normalA[j]); } float v[3]; MathUtilities::subtractVectors(coordJR, coordIR, v); float t1[3]; MathUtilities::subtractVectors(xyz, coordIR, t1); float t2 = MathUtilities::dotProduct(v, v); float t3 = MathUtilities::dotProduct(t1, v); float QR[3]; for (int j = 0; j < 3; j++) QR[j] = coordIR[j] + ((t3/t2) * v[j]); if ((triA >=0) && (triB >= 0)){ t2 = MathUtilities::dotProduct(normalA, normalB); t2 = std::min(t2, (float)1.0); // imit to 1.0 cp.phiR = std::acos(t2); } else cp.phiR = 0.0; MathUtilities::subtractVectors(xyz, QR, t1); t2 = MathUtilities::vectorLength(t1); if (t2 > 0.0){ for (int j = 0; j < 3; j++) t1[j] = t1[j]/t2; } t3 = MathUtilities::dotProduct(normalA, t1); // HAD 11.11.96 Added for H53 where t3 = 0 if (t3 > 0) cp.thetaR = std::acos(t3 * (t3/fabs (t3))); else cp.thetaR = 0.0; MathUtilities::subtractVectors(coordJR, coordIR, v); t2 = MathUtilities::vectorLength(v); MathUtilities::subtractVectors (QR, coordIR, t1); t3 = MathUtilities::vectorLength(t1); if (t2 > 0.0) cp.fracRI = t3/t2; else cp.fracRI = 0.0; MathUtilities::subtractVectors(coordIR, coordJR, v); t2 = MathUtilities::vectorLength(v); MathUtilities::subtractVectors(QR, coordJR, t1); t3 = MathUtilities::vectorLength(t1); if (t2 > 0.0) cp.fracRJ = t3/t2; else cp.fracRJ = 0.0; cp.dR = std::sqrt(vtkMath::Distance2BetweenPoints(QR, xyz)); topologyFile->getTile(triA, cp.triVertices[0]); topologyFile->getTile(triB, cp.triVertices[1]); std::swap(cp.triVertices[0][0], cp.triVertices[0][2]); coordinateFile->getCoordinate(cp.triVertices[0][0], cp.triFiducial[0][0]); coordinateFile->getCoordinate(cp.triVertices[0][1], cp.triFiducial[0][1]); coordinateFile->getCoordinate(cp.triVertices[0][2], cp.triFiducial[0][2]); if (triB >= 0) { std::swap(cp.triVertices[1][0], cp.triVertices[1][2]); coordinateFile->getCoordinate(cp.triVertices[1][0], cp.triFiducial[1][0]); coordinateFile->getCoordinate(cp.triVertices[1][1], cp.triFiducial[1][1]); coordinateFile->getCoordinate(cp.triVertices[1][2], cp.triFiducial[1][2]); } cp.vertexFiducial[0][0] = coordIR[0]; cp.vertexFiducial[0][1] = coordIR[1]; cp.vertexFiducial[0][2] = coordIR[2]; cp.vertexFiducial[1][0] = coordJR[0]; cp.vertexFiducial[1][1] = coordJR[1]; cp.vertexFiducial[1][2] = coordJR[2]; cp.vertex[0] = iR; cp.vertex[1] = jR; } // // Set the search position // if (searchSurface != NULL) { cp.getProjectedPosition(searchSurface->getCoordinateFile(), searchSurface->getTopologyFile(), true, false, false, cp.searchXYZ); } } //============================================================================== /** * constructor. */ FociFileToPalsProjector::PointProjector::PointProjector(const QString& spaceNameIn, const Structure::STRUCTURE_TYPE structureTypeIn, BrainModelSurfacePointProjector* pointProjectorIn, BrainSet* bsIn, BrainModelSurface* bmsIn) { originalSpaceName = spaceNameIn; spaceName = spaceNameIn; FociFileToPalsProjector::spaceNameConvert(spaceName); structureType = structureTypeIn; pointProjector = pointProjectorIn; bs = bsIn; bms = bmsIn; } /** * destructor. */ FociFileToPalsProjector::PointProjector::~PointProjector() { if (pointProjector != NULL) { delete pointProjector; pointProjector = NULL; } if (bms != NULL) { delete bms; bms = NULL; } } /** * equality operator. */ bool FociFileToPalsProjector::PointProjector::operator==(const FociFileToPalsProjector::PointProjector& pp) const { if ((spaceName == pp.spaceName) && (structureType == pp.structureType)) { return true; } return false; } caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsWustlRegion.h0000664000175000017500000001032511572067322025410 0ustar michaelmichael #ifndef __DISPLAY_SETTINGS_WUSTL_REGION_H__ #define __DISPLAY_SETTINGS_WUSTL_REGION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "DisplaySettings.h" /// class for controlling display of a wustl region file class DisplaySettingsWustlRegion : public DisplaySettings { public: /// graph mode enum GRAPH_MODE { GRAPH_MODE_AUTO_SCALE, GRAPH_MODE_USER_SCALE }; /// time course selection enum TIME_COURSE_SELECTION { TIME_COURSE_SELECTION_ALL, TIME_COURSE_SELECTION_SINGLE }; /// constructor DisplaySettingsWustlRegion(BrainSet* bsIn); /// destructor ~DisplaySettingsWustlRegion(); /// reinitialize all display settings virtual void reset(); /// update any selections due to changes with loaded data files virtual void update(); /// get popup graph enabled bool getPopupGraphEnabled() const { return popupGraphEnabled; } /// set popup graph enabled void setPopupGraphEnabled(const bool enabled) { popupGraphEnabled = enabled; } /// get the selected time course number int getSelectedTimeCourse() const { return selectedTimeCourse; } /// set the selected time course number void setSelectedTimeCourse(const int tc); /// get the selected case name QString getSelectedCaseName() const { return selectedCaseName; } /// set the selected case name void setSelectedCaseName(const QString& caseName) { selectedCaseName = caseName; } /// get the selected paint volume int getSelectedPaintVolume() const { return selectedPaintVolume; } /// set the selected paint volume void setSelectedPaintVolume(const int spv) { selectedPaintVolume = spv; } /// get the graph mode GRAPH_MODE getGraphMode() const { return graphMode; } /// set the graph mode void setGraphMode(const GRAPH_MODE gm) { graphMode = gm; } /// get the user scale void getUserScale(float& minScaleOut, float& maxScaleOut) const; /// set the user scale void setUserScale(const float minScaleIn, const float maxScaleIn); /// get the time course selection TIME_COURSE_SELECTION getTimeCourseSelection() const { return timeCourseSelection; } /// set the time course selection void setTimeCourseSelection(const TIME_COURSE_SELECTION tcs) { timeCourseSelection = tcs; } /// apply a scene (set display settings) virtual void showScene(const SceneFile::Scene& scene, QString& errorMessage) ; /// create a scene (read display settings) virtual void saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& errorMessage); protected: /// time course selection TIME_COURSE_SELECTION timeCourseSelection; /// popup graph enabled bool popupGraphEnabled; /// the selected time course int selectedTimeCourse; /// the selected case name QString selectedCaseName; /// the selected paint volume int selectedPaintVolume; /// the graph mode GRAPH_MODE graphMode; /// the user scale float userScale[2]; }; #endif // __DISPLAY_SETTINGS_WUSTL_REGION_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsWustlRegion.cxx0000664000175000017500000001343311572067322025766 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainSet.h" #include "DisplaySettingsWustlRegion.h" #include "WustlRegionFile.h" /** * constructor. */ DisplaySettingsWustlRegion::DisplaySettingsWustlRegion(BrainSet* bsIn) : DisplaySettings(bsIn) { popupGraphEnabled = false; userScale[0] = -10.0; userScale[1] = 10.0; graphMode = GRAPH_MODE_AUTO_SCALE; timeCourseSelection = TIME_COURSE_SELECTION_SINGLE; reset(); } /** * destructor. */ DisplaySettingsWustlRegion::~DisplaySettingsWustlRegion() { } /** * get the user scale. */ void DisplaySettingsWustlRegion::getUserScale(float& minScaleOut, float& maxScaleOut) const { minScaleOut = userScale[0]; maxScaleOut = userScale[1]; } /** * set the user scale. */ void DisplaySettingsWustlRegion::setUserScale(const float minScaleIn, const float maxScaleIn) { userScale[0] = minScaleIn; userScale[1] = maxScaleIn; } /** * set the selected time course number. */ void DisplaySettingsWustlRegion::setSelectedTimeCourse(const int tc) { selectedTimeCourse = tc; update(); } /** * reinitialize all display settings. */ void DisplaySettingsWustlRegion::reset() { selectedTimeCourse = -1; selectedCaseName = ""; selectedPaintVolume = -1; } /** * update any selections due to changes with loaded data files. */ void DisplaySettingsWustlRegion::update() { // // Update selected paint volume // const int numPaintVolumes = brainSet->getNumberOfVolumePaintFiles(); if (numPaintVolumes > 0) { if ((selectedPaintVolume < 0) || (selectedPaintVolume >= numPaintVolumes)) { selectedPaintVolume = 0; } } else { selectedPaintVolume = -1; } // // Update selected time course // const WustlRegionFile* wrf = brainSet->getWustlRegionFile(); const int numTimeCourses = wrf->getNumberOfTimeCourses(); if (numTimeCourses > 0) { if ((selectedTimeCourse < 0) || (selectedTimeCourse >= numTimeCourses)) { selectedTimeCourse = 0; } } else { selectedTimeCourse = -1; } // // Update for selected case name // if (selectedTimeCourse >= 0) { if (selectedCaseName.isEmpty()) { selectedCaseName = "average"; } const WustlRegionFile::TimeCourse* tc = wrf->getTimeCourse(selectedTimeCourse); std::vector caseNames; tc->getAllRegionCaseNames(caseNames); // // If current case name is not found, try to set it to first available case name // if (std::find(caseNames.begin(), caseNames.end(), selectedCaseName) == caseNames.end()) { selectedCaseName = ""; if (caseNames.empty() == false) { selectedCaseName = caseNames[0]; } } } else { selectedCaseName = ""; } } /** * apply a scene (set display settings). */ void DisplaySettingsWustlRegion::showScene(const SceneFile::Scene& scene, QString& /*errorMessage*/) { const int numClasses = scene.getNumberOfSceneClasses(); for (int nc = 0; nc < numClasses; nc++) { const SceneFile::SceneClass* sc = scene.getSceneClass(nc); if (sc->getName() == "DisplaySettingsWustlRegion") { const int num = sc->getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc->getSceneInfo(i); const QString infoName = si->getName(); if (infoName == "popupGraphEnabled") { si->getValue(popupGraphEnabled); } else if (infoName == "userScale0") { si->getValue(userScale[0]); } else if (infoName == "userScale1") { si->getValue(userScale[1]); } else if (infoName == "timeCourseSelection") { timeCourseSelection = static_cast(si->getValueAsInt()); } else if (infoName == "graphMode") { graphMode = static_cast(si->getValueAsInt()); } } } } } /** * create a scene (read display settings). */ void DisplaySettingsWustlRegion::saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& /*errorMessage*/) { const WustlRegionFile* wrf = brainSet->getWustlRegionFile(); if (onlyIfSelected) { if (popupGraphEnabled == false) { return; } if (wrf->empty()) { return; } } SceneFile::SceneClass sc("DisplaySettingsWustlRegion"); sc.addSceneInfo(SceneFile::SceneInfo("timeCourseSelection", timeCourseSelection)); sc.addSceneInfo(SceneFile::SceneInfo("popupGraphEnabled", popupGraphEnabled)); sc.addSceneInfo(SceneFile::SceneInfo("graphMode", graphMode)); sc.addSceneInfo(SceneFile::SceneInfo("userScale0", userScale[0])); sc.addSceneInfo(SceneFile::SceneInfo("userScale1", userScale[1])); scene.addSceneClass(sc); } caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsVolume.h0000664000175000017500000003727011572067322024405 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __DISPLAY_SETTINGS_VOLUME_H__ #define __DISPLAY_SETTINGS_VOLUME_H__ #include "DisplaySettings.h" class BrainModelSurface; class TransformationMatrix; class VolumeFile; /// Display settings for volumes class DisplaySettingsVolume : public DisplaySettings { public: /// anatomy coloring type enum ANATOMY_COLORING_TYPE { ANATOMY_COLORING_TYPE_0_255, ANATOMY_COLORING_TYPE_MIN_MAX, ANATOMY_COLORING_TYPE_2_98, }; /// segmentation draw type enum SEGMENTATION_DRAW_TYPE { SEGMENTATION_DRAW_TYPE_BLEND, SEGMENTATION_DRAW_TYPE_SOLID, SEGMENTATION_DRAW_TYPE_BOX, SEGMENTATION_DRAW_TYPE_CROSS }; /// coloring for surface outline enum SURFACE_OUTLINE_COLOR { SURFACE_OUTLINE_COLOR_BLACK, SURFACE_OUTLINE_COLOR_BLUE, SURFACE_OUTLINE_COLOR_GREEN, SURFACE_OUTLINE_COLOR_RED, SURFACE_OUTLINE_COLOR_WHITE }; /// misc values enum { /// maximum number of overlay surfaces MAXIMUM_OVERLAY_SURFACES = 9 }; /// Constructor DisplaySettingsVolume(BrainSet* bs); /// Destructor ~DisplaySettingsVolume(); /// Reinitialize all display settings virtual void reset(); /// Update any selections due to changes in loaded volumes virtual void update(); /// get the segmentation draw type SEGMENTATION_DRAW_TYPE getSegmentationDrawType() const { return segmentationDrawType; } /// set the segmentation draw type void setSegmentationDrawType(const SEGMENTATION_DRAW_TYPE sdt) { segmentationDrawType = sdt; } /// get the selected functional volume file for viewing int getSelectedFunctionalVolumeView() const { return selectedFunctionalVolumeView; } /// set the selected functional volume file for viewing void setSelectedFunctionalVolumeView(const int index) { selectedFunctionalVolumeView = index; } /// set the selected functional volume file for viewing void setSelectedFunctionalVolumeView(const QString& name); /// get the selected functional volume file for thresholding int getSelectedFunctionalVolumeThreshold() const { return selectedFunctionalVolumeThreshold; } /// set the selected functional volume file for thresholding void setSelectedFunctionalVolumeThreshold(const int index) { selectedFunctionalVolumeThreshold = index; } /// set the selected functional volume file for thresholding void setSelectedFunctionalVolumeThreshold(const QString& name); /// get the selected paint volume file int getSelectedPaintVolume() const { return selectedPaintVolume; } /// set the selected paint volume file void setSelectedPaintVolume(const int index) { selectedPaintVolume = index; } /// set the selected paint volume file void setSelectedPaintVolume(const QString& name); /// get the selected rgb volume file int getSelectedRgbVolume() const { return selectedRgbVolume; } /// set the selected rgb volume file void setSelectedRgbVolume(const int index) { selectedRgbVolume = index; } /// set the selected rgb volume file void setSelectedRgbVolume(const QString& name); /// get the selected segmentation volume file int getSelectedSegmentationVolume() const { return selectedSegmentationVolume; } /// set the selected segmentation volume file void setSelectedSegmentationVolume(const int index) { selectedSegmentationVolume = index; } /// set the selected segmentation volume file void setSelectedSegmentationVolume(const QString& name); /// get the selected anatomy volume file int getSelectedAnatomyVolume() const { return selectedAnatomyVolume; } /// set the selected anatomy volume file void setSelectedAnatomyVolume(const int index) { selectedAnatomyVolume = index; } /// set the selected anatomy volume file void setSelectedAnatomyVolume(const QString& name); /// get the anatomy volume brightness int getAnatomyVolumeBrightness() const { return anatomyVolumeBrightness; } /// get the anatomy volume contrast int getAnatomyVolumeContrast() const { return anatomyVolumeContrast; } /// set the anatomy volume brightness void setAnatomyVolumeBrightness(const int brightness) { anatomyVolumeBrightness = brightness; } /// set the anatomy volume contrast void setAnatomyVolumeContrast(const int contrast) { anatomyVolumeContrast = contrast; } /// get the selected vector volume file int getSelectedVectorVolume() const { return selectedVectorVolume; } /// set the selected vector volume file void setSelectedVectorVolume(const int index) { selectedVectorVolume = index; } /// set the selected vector volume file void setSelectedVectorVolume(const QString& name); /// get vector volume sparsity int getVectorVolumeSparsity() const { return vectorVolumeSparsity; } /// set vector volume sparsity void setVectorVolumeSparsity(const int vvs) { vectorVolumeSparsity = vvs; } /// get display the crosshair coordinates bool getDisplayCrosshairCoordinates() const { return displayCrosshairCoordinates; } /// set display the crosshair coordinates void setDisplayCrosshairCoordinates(const bool d) { displayCrosshairCoordinates = d; } /// get display the crosshairs bool getDisplayCrosshairs() const { return displayCrosshairs; } /// set display the crosshairss void setDisplayCrosshairs(const bool d) { displayCrosshairs = d; } /// get display the orientation labels bool getDisplayOrientationLabels() const { return displayOrientationLabels; } /// set display the orientation labels void setDisplayOrientationLabels(const bool d) { displayOrientationLabels = d; } /// get the anatomical volume coloring type ANATOMY_COLORING_TYPE getAnatomyVolumeColoringType() const { return anatomyColoringType; } /// set the anatomy volume coloring type void setAnatomyVolumeColoringType(const ANATOMY_COLORING_TYPE act) { anatomyColoringType = act; }; /// set the cropping slices valid void setCroppingSlicesValid(const bool b) { croppingSlicesValid = b; } /// get the cropping slices valid bool getCroppingSlicesValid() const { return croppingSlicesValid; } /// set the cropping slices void setCroppingSlices(const int slices[6]); /// get the cropping slices void getCroppingSlices(int slices[6]) const; /// get the anatomy thresholding valid bool getAnatomyThresholdValid() const { return anatomyThresholdValid; } /// set the anatomy thresholding valid void setAnatomyThresholdValid(const bool b) { anatomyThresholdValid = b; } /// get the anatomy threshold value void getAnatomyThreshold(float& minThresh, float& maxThresh) const; /// set the anatomy threshold value void setAnatomyThreshold(const float minThresh, const float maxThresh = 1.0e10); /// get the segmentation translucency float getSegmentationTranslucency() const { return segmentationTranslucency; } /// set the segmentation translucency void setSegmentationTranslucency(const float st) { segmentationTranslucency = st; } /// get montage view selected bool getMontageViewSelected() const { return montageViewSelected; } /// set montage view selected void setMontageViewSelected(const int b) { montageViewSelected = b; } /// get volume montage settings (returns true if montage on) void getMontageViewSettings(int& numRows, int& numSlices, int& sliceIncrement) const; /// set volume montage settings void setMontageViewSettings(const int numRows, const int numCols, const int sliceIncrement); /// apply a scene (set display settings) virtual void showScene(const SceneFile::Scene& scene, QString& errorMessage) ; /// create a scene (read display settings) virtual void saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& errorMessage); /// get the overlay opacity float getOverlayOpacity() const { return overlayOpacity; } /// set the overlay opacity void setOverlayOpacity(const float oo) { overlayOpacity = oo; } /// get show palette color bar bool getDisplayColorBar() const { return displayColorBar; } /// set show palette color bar void setDisplayColorBar(const bool showIt) { displayColorBar = showIt; } /// get the oblique slices transformation matrix TransformationMatrix* getObliqueSlicesTransformationMatrix() { return obliqueTransform; } /// set the oblique slices transformation matrix void setObliqueSlicesTransformationMatrix(TransformationMatrix* tm) { obliqueTransform = tm; } /// get the oblique slices sampling size float getObliqueSlicesSamplingSize() const { return obliqueSlicesSamplingSize; } /// set the oblique slices samping size void setObliqueSlicesSamplingSize(const float ss) { obliqueSlicesSamplingSize = ss; } /// Get one of the "overlay" surfaces. BrainModelSurface* getOverlaySurface(const int overlaySurfaceNumber); /// Set one of the "overlay" surfaces. void setOverlaySurface(const int overlaySurfaceNumber, BrainModelSurface* bms); /// get display overlay surface over the volume bool getDisplayOverlaySurfaceOutline(const int overlaySurfaceNumber) const { return displayOverlaySurfaceOutline[overlaySurfaceNumber]; } /// set display overlay surface over the volume void setDisplayOverlaySurfaceOutline(const int overlaySurfaceNumber, const bool dso) { displayOverlaySurfaceOutline[overlaySurfaceNumber] = dso; } /// get the overlay surface outline color SURFACE_OUTLINE_COLOR getOverlaySurfaceOutlineColor(const int overlaySurfaceNumber) const { return overlaySurfaceOutlineColor[overlaySurfaceNumber]; } /// set the overlay surface outline color void setOverlaySurfaceOutlineColor(const int overlaySurfaceNumber, const SURFACE_OUTLINE_COLOR soc) { overlaySurfaceOutlineColor[overlaySurfaceNumber] = soc; } /// get the overlay surface outline thickness float getOverlaySurfaceOutlineThickness(const int overlaySurfaceNumber) const { return overlaySurfaceOutlineThickness[overlaySurfaceNumber]; } /// set the overlay surface outline thickness void setOverlaySurfaceOutlineThickness(const int overlaySurfaceNumber, const float sot) { overlaySurfaceOutlineThickness[overlaySurfaceNumber] = sot; } private: /// file selection helper int fileSelectionHelper(const std::vector& files, const QString& fileName); /// help save volume file for scene void sceneSelectedVolumeHelper(SceneFile::SceneClass& sceneClass, const QString& infoName, const VolumeFile* vf); /// anatomy threshold valid bool anatomyThresholdValid; /// anatomy threshold float anatomyThreshold[2]; /// cropping slices are valid bool croppingSlicesValid; /// the cropping slices int croppingSlices[6]; /// update the selection index for a file type void updateFileType(const int numFiles, int& selectedIndex); /// selected functional volume file for viewing int selectedFunctionalVolumeView; /// selected functional volume file for thresholding int selectedFunctionalVolumeThreshold; /// selected paint volume file int selectedPaintVolume; /// selected rgb volume file int selectedRgbVolume; /// selected segmentation volume file int selectedSegmentationVolume; /// selected vector volume file int selectedVectorVolume; /// selected anatomy volume file int selectedAnatomyVolume; /// anatomy volume brightness int anatomyVolumeBrightness; /// anatomy volume contrast int anatomyVolumeContrast; /// display the crosshair coordinates bool displayCrosshairCoordinates; /// display the crosshairs bool displayCrosshairs; /// display the orientation labels bool displayOrientationLabels; /// anatomy coloring type ANATOMY_COLORING_TYPE anatomyColoringType; /// segmentation draw type SEGMENTATION_DRAW_TYPE segmentationDrawType; /// segmentation translucency float segmentationTranslucency; /// montage view selected bool montageViewSelected; /// montage view number of rows int montageViewNumberOfRows; /// montage view number of columns int montageViewNumberOfColumns; /// montage slice increment int montageSliceIncrement; /// overlay opacity float overlayOpacity; /// show color palette color bar bool displayColorBar; /// vector volume sparsity int vectorVolumeSparsity; /// oblique slices transform TransformationMatrix* obliqueTransform; /// oblique slices sampling size float obliqueSlicesSamplingSize; /// surface outlines overlayed on volume slices BrainModelSurface* overlaySurface[MAXIMUM_OVERLAY_SURFACES]; /// display overlay surface outline over the volume bool displayOverlaySurfaceOutline[MAXIMUM_OVERLAY_SURFACES]; /// surface overlay outline color SURFACE_OUTLINE_COLOR overlaySurfaceOutlineColor[MAXIMUM_OVERLAY_SURFACES]; /// surface overlay outline thickness float overlaySurfaceOutlineThickness[MAXIMUM_OVERLAY_SURFACES]; }; #endif // __DISPLAY_SETTINGS_VOLUME_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsVolume.cxx0000664000175000017500000005651011572067322024756 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "DisplaySettingsVolume.h" #include "BrainModelSurface.h" #include "BrainModelVolume.h" #include "BrainSet.h" #include "FileUtilities.h" #include "PreferencesFile.h" #include "VolumeFile.h" /** * Constructor. */ DisplaySettingsVolume::DisplaySettingsVolume(BrainSet* bs) : DisplaySettings(bs) { PreferencesFile* pf = BrainSet::getPreferencesFile(); anatomyVolumeBrightness = pf->getAnatomyVolumeBrightness(); anatomyVolumeContrast = pf->getAnatomyVolumeContrast(); anatomyColoringType = ANATOMY_COLORING_TYPE_2_98; segmentationDrawType = SEGMENTATION_DRAW_TYPE_BLEND; displayCrosshairCoordinates = true; displayCrosshairs = true; displayOrientationLabels = true; segmentationTranslucency = 0.5; for (int i = 0; i < MAXIMUM_OVERLAY_SURFACES; i++) { displayOverlaySurfaceOutline[i] = false; overlaySurfaceOutlineColor[i] = SURFACE_OUTLINE_COLOR_GREEN; if (i == 0) { overlaySurfaceOutlineColor[i] = SURFACE_OUTLINE_COLOR_GREEN; } else if (i == 1) { overlaySurfaceOutlineColor[i] = SURFACE_OUTLINE_COLOR_RED; } else if (i == 2) { overlaySurfaceOutlineColor[i] = SURFACE_OUTLINE_COLOR_BLUE; } else if (i == 3) { overlaySurfaceOutlineColor[i] = SURFACE_OUTLINE_COLOR_WHITE; } else if (i == 4) { overlaySurfaceOutlineColor[i] = SURFACE_OUTLINE_COLOR_BLACK; } overlaySurfaceOutlineThickness[i] = 0.8; } montageViewNumberOfRows = 3; montageViewNumberOfColumns = 3; montageSliceIncrement = 5; overlayOpacity = 1.0; displayColorBar = false; vectorVolumeSparsity = 1; obliqueSlicesSamplingSize = 1.0; reset(); } /** * Destructor. */ DisplaySettingsVolume::~DisplaySettingsVolume() { } /** * Reinitialize all display settings. */ void DisplaySettingsVolume::reset() { selectedAnatomyVolume = -1; selectedFunctionalVolumeView = -1; selectedFunctionalVolumeThreshold = -1; selectedPaintVolume = -1; selectedRgbVolume = -1; selectedSegmentationVolume = -1; selectedVectorVolume = -1; croppingSlicesValid = false; setAnatomyThreshold(256.0); anatomyThresholdValid = false; montageViewSelected = false; obliqueTransform = NULL; for (int i = 0; i < MAXIMUM_OVERLAY_SURFACES; i++) { overlaySurface[i] = NULL; } } /** * Update selections due to changes in loaded cells. */ void DisplaySettingsVolume::update() { updateFileType(brainSet->getNumberOfVolumeFunctionalFiles(), selectedFunctionalVolumeView); updateFileType(brainSet->getNumberOfVolumeFunctionalFiles(), selectedFunctionalVolumeThreshold); updateFileType(brainSet->getNumberOfVolumePaintFiles(), selectedPaintVolume); updateFileType(brainSet->getNumberOfVolumeRgbFiles(), selectedRgbVolume); updateFileType(brainSet->getNumberOfVolumeSegmentationFiles(), selectedSegmentationVolume); updateFileType(brainSet->getNumberOfVolumeAnatomyFiles(), selectedAnatomyVolume); updateFileType(brainSet->getNumberOfVolumeVectorFiles(), selectedVectorVolume); if (obliqueTransform != NULL) { TransformationMatrixFile* tmf = brainSet->getTransformationMatrixFile(); if (tmf->getMatrixValid(obliqueTransform) == false) { obliqueTransform = NULL; } } } /** * set the cropping slices. */ void DisplaySettingsVolume::setCroppingSlices(const int slices[6]) { for (int i = 0; i < 6; i++) { croppingSlices[i] = slices[i]; } } /** * get the cropping slices. */ void DisplaySettingsVolume::getCroppingSlices(int slices[6]) const { for (int i = 0; i < 6; i++) { slices[i] = croppingSlices[i]; } } /** * update the selected file based upon the number of files */ void DisplaySettingsVolume::updateFileType(const int numFiles, int& selectedIndex) { if (numFiles > 0) { if ((selectedIndex < 0) || (selectedIndex >= numFiles)) { selectedIndex = 0; } } else { selectedIndex = -1; } } /** * get volume montage settings (returns true if montage on). */ void DisplaySettingsVolume::getMontageViewSettings(int& numRows, int& numSlices, int& sliceIncrement) const { numRows = montageViewNumberOfRows; numSlices = montageViewNumberOfColumns; sliceIncrement = montageSliceIncrement; } /** * set volume montage settings. */ void DisplaySettingsVolume::setMontageViewSettings(const int numRows, const int numCols, const int sliceIncrement) { montageViewNumberOfRows = numRows; montageViewNumberOfColumns = numCols; montageSliceIncrement = sliceIncrement; } const QString volumeFileAnatomyID("volume-file-anatomy"); const QString volumeFileFunctionalViewID("volume-file-func-view"); const QString volumeFileFunctionalThreshID("volume-file-func-thresh"); const QString volumeFilePaintID("volume-file-paint"); const QString volumeFileRgbID("volume-file-rgb"); const QString volumeFileSegmentationID("volume-file-segmentation"); const QString volumeFileVectorID("volume-file-vector"); /** * apply a scene (set display settings). */ void DisplaySettingsVolume::showScene(const SceneFile::Scene& scene, QString& errorMessage) { const int numClasses = scene.getNumberOfSceneClasses(); for (int nc = 0; nc < numClasses; nc++) { const SceneFile::SceneClass* sc = scene.getSceneClass(nc); if (sc->getName() == "DisplaySettingsVolume") { const int num = sc->getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc->getSceneInfo(i); const QString infoName = si->getName(); if (infoName == volumeFileAnatomyID) { setSelectedAnatomyVolume(si->getValueAsString()); } else if (infoName == volumeFileFunctionalViewID) { setSelectedFunctionalVolumeView(si->getValueAsString()); } else if (infoName == volumeFileFunctionalThreshID) { setSelectedFunctionalVolumeThreshold(si->getValueAsString()); } else if (infoName == volumeFilePaintID) { setSelectedPaintVolume(si->getValueAsString()); } else if (infoName == volumeFileRgbID) { setSelectedRgbVolume(si->getValueAsString()); } else if (infoName == volumeFileSegmentationID) { setSelectedSegmentationVolume(si->getValueAsString()); } else if (infoName == volumeFileVectorID) { setSelectedVectorVolume(si->getValueAsString()); } else if (infoName == "anatomyVolumeBrightness") { si->getValue(anatomyVolumeBrightness); } else if (infoName == "anatomyVolumeContrast") { si->getValue(anatomyVolumeContrast); } else if (infoName == "displayCrosshairCoordinates") { si->getValue(displayCrosshairCoordinates); } else if (infoName == "displayOrientationLabels") { si->getValue(displayOrientationLabels); } else if (infoName == "displayCrosshairs") { si->getValue(displayCrosshairs); } else if (infoName == "anatomyColoringType") { int val; si->getValue(val); anatomyColoringType = static_cast(val); } else if (infoName == "segmentationDrawType") { int val; si->getValue(val); segmentationDrawType = static_cast(val); } else if (infoName == "segmentationTranslucency") { si->getValue(segmentationTranslucency); } else if ((infoName == "displaySurfaceOutline") || (infoName == "displayFiducialSurfaceOutline")){ si->getValue(displayOverlaySurfaceOutline[0]); } else if ((infoName == "surfaceOutlineColor") || (infoName == "overlaySurfaceOutlineColor")) { int val; si->getValue(val); overlaySurfaceOutlineColor[0] = static_cast(val); } else if ((infoName == "surfaceOutlineThickness") || (infoName == "fiducialSurfaceOutlineThickness")) { si->getValue(overlaySurfaceOutlineThickness[0]); } else if (infoName == "displayHullSurfaceOutline") { si->getValue(displayOverlaySurfaceOutline[1]); } else if (infoName == "hullSurfaceOutlineColor") { int val; si->getValue(val); overlaySurfaceOutlineColor[1] = static_cast(val); } else if (infoName == "hullSurfaceOutlineThickness") { si->getValue(overlaySurfaceOutlineThickness[1]); } else if (infoName == "overlaySurface") { const int modelNum = si->getModelName().toInt(); if ((modelNum >= 0) && (modelNum < MAXIMUM_OVERLAY_SURFACES)) { overlaySurface[modelNum] = NULL; if (si->getValueAsString() != "NULL") { bool foundSurface = false; for (int i = 0; i < brainSet->getNumberOfBrainModels(); i++) { BrainModelSurface* bms = brainSet->getBrainModelSurface(i); if (bms != NULL) { const QString coordName = FileUtilities::basename(bms->getCoordinateFile()->getFileName()); if (coordName == si->getValueAsString()) { overlaySurface[modelNum] = bms; foundSurface = true; break; } } } if (foundSurface == false) { errorMessage.append("Unable to find surface named "); errorMessage.append(si->getValueAsString()); errorMessage.append(" for volume overlay\n"); } } } } else if (infoName == "displayOverlaySurfaceOutline") { const int modelNum = si->getModelName().toInt(); if ((modelNum >= 0) && (modelNum < MAXIMUM_OVERLAY_SURFACES)) { si->getValue(displayOverlaySurfaceOutline[modelNum]); } } else if (infoName == "overlaySurfaceOutlineColor") { const int modelNum = si->getModelName().toInt(); if ((modelNum >= 0) && (modelNum < MAXIMUM_OVERLAY_SURFACES)) { int val; si->getValue(val); overlaySurfaceOutlineColor[modelNum] = static_cast(val); } } else if (infoName == "overlaySurfaceOutlineThickness") { const int modelNum = si->getModelName().toInt(); if ((modelNum >= 0) && (modelNum < MAXIMUM_OVERLAY_SURFACES)) { si->getValue(overlaySurfaceOutlineThickness[modelNum]); } } else if (infoName == "montageViewSelected") { si->getValue(montageViewSelected); } else if (infoName == "montageViewNumberOfRows") { si->getValue(montageViewNumberOfRows); } else if (infoName == "montageViewNumberOfColumns") { si->getValue(montageViewNumberOfColumns); } else if (infoName == "montageSliceIncrement") { si->getValue(montageSliceIncrement); } else if (infoName == "overlayOpacity") { si->getValue(overlayOpacity); } else if (infoName == "displayColorBar") { si->getValue(displayColorBar); } else if (infoName == "obliqueTransform") { TransformationMatrixFile* tmf = brainSet->getTransformationMatrixFile(); obliqueTransform = tmf->getTransformationMatrixWithName(si->getValueAsString()); } else if (infoName == "obliqueSlicesSamplingSize") { si->getValue(obliqueSlicesSamplingSize); } } } } } /// help save volume file for scene void DisplaySettingsVolume::sceneSelectedVolumeHelper(SceneFile::SceneClass& sceneClass, const QString& infoName, const VolumeFile* vf) { if (vf != NULL) { sceneClass.addSceneInfo(SceneFile::SceneInfo(infoName, vf->getDescriptiveLabel())); // FileUtilities::basename(vf->getFileName()))); } } /** * create a scene (read display settings). */ void DisplaySettingsVolume::saveScene(SceneFile::Scene& scene, const bool onlyIfSelectedFlag, QString& /*errorMessage*/) { if (onlyIfSelectedFlag) { const int numVolumes = brainSet->getNumberOfVolumeAnatomyFiles() + brainSet->getNumberOfVolumeFunctionalFiles() + brainSet->getNumberOfVolumePaintFiles() + brainSet->getNumberOfVolumeProbAtlasFiles() + brainSet->getNumberOfVolumeRgbFiles() + brainSet->getNumberOfVolumeSegmentationFiles() + brainSet->getNumberOfVolumeVectorFiles(); if (numVolumes <= 0) { return; } } SceneFile::SceneClass sc("DisplaySettingsVolume"); BrainModelVolume* bmv = brainSet->getBrainModelVolume(); if (bmv != NULL) { sceneSelectedVolumeHelper(sc, volumeFileAnatomyID, bmv->getSelectedVolumeAnatomyFile()); sceneSelectedVolumeHelper(sc, volumeFileFunctionalViewID, bmv->getSelectedVolumeFunctionalViewFile()); sceneSelectedVolumeHelper(sc, volumeFileFunctionalThreshID, bmv->getSelectedVolumeFunctionalThresholdFile()); sceneSelectedVolumeHelper(sc, volumeFilePaintID, bmv->getSelectedVolumePaintFile()); sceneSelectedVolumeHelper(sc, volumeFileRgbID, bmv->getSelectedVolumeRgbFile()); sceneSelectedVolumeHelper(sc, volumeFileSegmentationID, bmv->getSelectedVolumeSegmentationFile()); sceneSelectedVolumeHelper(sc, volumeFileVectorID, bmv->getSelectedVolumeVectorFile()); } sc.addSceneInfo(SceneFile::SceneInfo("anatomyVolumeBrightness", anatomyVolumeBrightness)); sc.addSceneInfo(SceneFile::SceneInfo("anatomyVolumeContrast", anatomyVolumeContrast)); sc.addSceneInfo(SceneFile::SceneInfo("displayCrosshairCoordinates", displayCrosshairCoordinates)); sc.addSceneInfo(SceneFile::SceneInfo("displayCrosshairs", displayCrosshairs)); sc.addSceneInfo(SceneFile::SceneInfo("displayOrientationLabels", displayOrientationLabels)); sc.addSceneInfo(SceneFile::SceneInfo("anatomyColoringType", static_cast(anatomyColoringType))); sc.addSceneInfo(SceneFile::SceneInfo("segmentationDrawType", static_cast(segmentationDrawType))); sc.addSceneInfo(SceneFile::SceneInfo("segmentationTranslucency", segmentationTranslucency)); for (int i = 0; i < MAXIMUM_OVERLAY_SURFACES; i++) { const QString modelNum(QString::number(i)); QString surfaceName("NULL"); if (overlaySurface[i] != NULL) { if (brainSet->getBrainModelIndex(overlaySurface[i]) >= 0) { surfaceName = FileUtilities::basename(overlaySurface[i]->getCoordinateFile()->getFileName()); } } sc.addSceneInfo(SceneFile::SceneInfo("overlaySurface", modelNum, surfaceName)); sc.addSceneInfo(SceneFile::SceneInfo("displayOverlaySurfaceOutline", modelNum, displayOverlaySurfaceOutline[i])); sc.addSceneInfo(SceneFile::SceneInfo("overlaySurfaceOutlineColor", modelNum, static_cast(overlaySurfaceOutlineColor[i]))); sc.addSceneInfo(SceneFile::SceneInfo("overlaySurfaceOutlineThickness", modelNum, overlaySurfaceOutlineThickness[i])); } sc.addSceneInfo(SceneFile::SceneInfo("montageViewSelected", montageViewSelected)); sc.addSceneInfo(SceneFile::SceneInfo("montageViewNumberOfRows", montageViewNumberOfRows)); sc.addSceneInfo(SceneFile::SceneInfo("montageViewNumberOfColumns", montageViewNumberOfColumns)); sc.addSceneInfo(SceneFile::SceneInfo("montageSliceIncrement", montageSliceIncrement)); sc.addSceneInfo(SceneFile::SceneInfo("overlayOpacity", overlayOpacity)); sc.addSceneInfo(SceneFile::SceneInfo("displayColorBar", displayColorBar)); if (obliqueTransform != NULL) { sc.addSceneInfo(SceneFile::SceneInfo("obliqueTransform", obliqueTransform->getMatrixName())); } sc.addSceneInfo(SceneFile::SceneInfo("obliqueSlicesSamplingSize", obliqueSlicesSamplingSize)); scene.addSceneClass(sc); } /** * set the selected anatomy volume file. */ void DisplaySettingsVolume::setSelectedAnatomyVolume(const QString& name) { std::vector files; brainSet->getVolumeAnatomyFiles(files); const int num = fileSelectionHelper(files, name); if (num >= 0) { setSelectedAnatomyVolume(num); } } /** * set the selected vector volume file. */ void DisplaySettingsVolume::setSelectedVectorVolume(const QString& name) { std::vector files; brainSet->getVolumeVectorFiles(files); const int num = fileSelectionHelper(files, name); if (num >= 0) { setSelectedVectorVolume(num); } } /** * set the selected segmentation volume file. */ void DisplaySettingsVolume::setSelectedSegmentationVolume(const QString& name) { std::vector files; brainSet->getVolumeSegmentationFiles(files); const int num = fileSelectionHelper(files, name); if (num >= 0) { setSelectedSegmentationVolume(num); } } /** * set the selected rgb volume file. */ void DisplaySettingsVolume::setSelectedRgbVolume(const QString& name) { std::vector files; brainSet->getVolumeRgbFiles(files); const int num = fileSelectionHelper(files, name); if (num >= 0) { setSelectedRgbVolume(num); } } /** * set the selected paint volume file. */ void DisplaySettingsVolume::setSelectedPaintVolume(const QString& name) { std::vector files; brainSet->getVolumePaintFiles(files); const int num = fileSelectionHelper(files, name); if (num >= 0) { setSelectedPaintVolume(num); } } /** * set the selected functional volume file for thresholding. */ void DisplaySettingsVolume::setSelectedFunctionalVolumeThreshold(const QString& name) { std::vector files; brainSet->getVolumeFunctionalFiles(files); const int num = fileSelectionHelper(files, name); if (num >= 0) { setSelectedFunctionalVolumeThreshold(num); } } /** * set the selected functional volume file for viewing. */ void DisplaySettingsVolume::setSelectedFunctionalVolumeView(const QString& name) { std::vector files; brainSet->getVolumeFunctionalFiles(files); const int num = fileSelectionHelper(files, name); if (num >= 0) { setSelectedFunctionalVolumeView(num); } } /** * file selection helper. */ int DisplaySettingsVolume::fileSelectionHelper(const std::vector& files, const QString& fileName) { const QString& name = FileUtilities::basename(fileName); for (unsigned int i = 0; i < files.size(); i++) { if (name == files[i]->getDescriptiveLabel()) { return i; } if (name == FileUtilities::basename(files[i]->getFileName())) { return i; } } return -1; } /** * Set one of the "overlay" surfaces. */ void DisplaySettingsVolume::setOverlaySurface(const int overlaySurfaceNumber, BrainModelSurface* bms) { overlaySurface[overlaySurfaceNumber] = bms; } /** * Get one of the "overlay" surfaces. */ BrainModelSurface* DisplaySettingsVolume::getOverlaySurface(const int overlaySurfaceNumber) { bool overlaySurfaceFound = false; // // 1st surface is always active fiducial to avoid breaking older scenes // if (overlaySurfaceNumber > 0) { // // Make sure overlay surface is still valid // if (overlaySurface[overlaySurfaceNumber] != NULL) { const int numBrains = brainSet->getNumberOfBrainModels(); for (int i = 0; i < numBrains; i++) { BrainModelSurface* bms = brainSet->getBrainModelSurface(i); if (bms != NULL) { if (bms == overlaySurface[overlaySurfaceNumber]) { overlaySurfaceFound = true; break; } } } } } // // Use the active fiducial surface to make the active surface // if (overlaySurfaceFound == false) { overlaySurface[overlaySurfaceNumber] = brainSet->getActiveFiducialSurface(); } return overlaySurface[overlaySurfaceNumber]; } /** * get the anatomy threshold value. */ void DisplaySettingsVolume::getAnatomyThreshold(float& minThresh, float& maxThresh) const { minThresh = anatomyThreshold[0]; maxThresh = anatomyThreshold[1]; } /** * set the anatomy threshold value. */ void DisplaySettingsVolume::setAnatomyThreshold(const float minThresh, const float maxThresh) { anatomyThreshold[0] = minThresh; anatomyThreshold[1] = maxThresh; } caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsVectors.h0000664000175000017500000002327211572067322024560 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __DISPLAY_SETTINGS_VECTORS_H__ #define __DISPLAY_SETTINGS_VECTORS_H__ #include #include "DisplaySettings.h" /// DisplaySettingsVectors is a class that maintains parameters for /// controlling the display of vector data. class DisplaySettingsVectors : public DisplaySettings { public: /// display mode types enum DISPLAY_MODE { /// show all vectors DISPLAY_MODE_ALL, /// show no vectors DISPLAY_MODE_NONE, /// show sparse (some) vectors DISPLAY_MODE_SPARSE }; /// type of vectors enum VECTOR_TYPE { /// bidirectional (two opposite) vectors VECTOR_TYPE_BIDIRECTIONAL, /// unidirectional (one direction) vectors VECTOR_TYPE_UNIDIRECTIONAL_ARROW, /// unidirectional (one direction) vectors VECTOR_TYPE_UNIDIRECTIONAL_CYLINDER }; /// SURFACE_SYMBOL { enum SURFACE_SYMBOL { /// 3D Symbol SURFACE_SYMBOL_3D, /// 2D Line SURFACE_SYMBOL_2D_LINE }; /// coloring mode enum COLOR_MODE { /// color using colors form file COLOR_MODE_VECTOR_COLORS, /// color using XYZ as RGB COLOR_MODE_XYZ_AS_RGB }; /// vector display orientation enum DISPLAY_ORIENTATION { /// vectors oriented along any axis DISPLAY_ORIENTATION_ANY, /// vectors oriented along left/right axis DISPLAY_ORIENTATION_LEFT_RIGHT, /// vectors oriented along posterior/anterior axis DISPLAY_ORIENTATION_POSTERIOR_ANTERIOR, /// vectors oriented along inferior/superior axis DISPLAY_ORIENTATION_INFERIOR_SUPERIOR }; /// Constructor DisplaySettingsVectors(BrainSet* bs); /// Destructor ~DisplaySettingsVectors(); /// get the vector type VECTOR_TYPE getVectorType() const { return vectorType; } /// set the vector type void setVectorType(const VECTOR_TYPE vt) { vectorType = vt; } /// get the surface symbol SURFACE_SYMBOL getSurfaceSymbol() const { return surfaceSymbol; } /// set the surface symbol void setSurfaceSymbol(const SURFACE_SYMBOL ss) { surfaceSymbol = ss; } /// get the display mode on surface DISPLAY_MODE getDisplayModeSurface() const { return displayModeSurface; } /// get the display mode on volume DISPLAY_MODE getDisplayModeVolume() const { return displayModeVolume; } /// set the display mode on surface void setDisplayModeSurface(const DISPLAY_MODE dm); /// set the display mode on volume void setDisplayModeVolume(const DISPLAY_MODE dm); // get the color mode COLOR_MODE getColorMode() const { return colorMode; } /// set the color mode void setColorMode(const COLOR_MODE colorModeIn); /// Reinitialize all display settings void reset(); /// Update any selections due to changes in loaded areal estimation file void update(); /// apply a scene (set display settings) virtual void showScene(const SceneFile::Scene& scene, QString& errorMessage) ; /// create a scene (read display settings) virtual void saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& errorMessage); /// get the sparse distance int getSparseDisplayDistance() const { return sparseDistance; } /// set the sparse distance void setSparseDisplayDistance(const int dist); /// get the length multiplier float getLengthMultiplier() const { return lengthMultiplier; } // set the length multiplier void setLengthMultiplier(const float len); /// get draw with magnitude bool getDrawWithMagnitude() const { return drawWithMagnitude; } // set draw with magnitude void setDrawWithMagnitude(const bool dwm); /// volume slice distance above limit float getVolumeSliceDistanceAboveLimit() const { return volumeSliceDistanceAboveLimit; } /// volume slice distance below limit float getVolumeSliceDistanceBelowLimit() const { return volumeSliceDistanceBelowLimit; } // set the volume slice above limit void setVolumeSliceDistanceAboveLimit(const float limit); // set the volume slice below limit void setVolumeSliceDistanceBelowLimit(const float limit); /// get the surface vector line width float getSurfaceVectorLineWidth() const { return surfaceVectorLineWidth; } // set the surface vector line width void setSurfaceVectorLineWidth(const float lineWidth); /// get the magnitude threshold float getMagnitudeThreshold() const { return magnitudeThreshold; } // set the magnitude threshold void setMagnitudeThreshold(const float magThresh); /// get enable segmentation masking volume bool getSegmentationMaskingVolumeEnabled() { return segmentationMaskingVolumeEnabled; } /// set enable segmentation masking volume void setSegmentationMaskingVolumeEnabled(bool enableIt); /// get the segmentation volume used for masking VolumeFile* getSegmentationMaskingVolumeFile(); // set the segmentation volume used for masking void setSegmentationMaskingVolumeFile(VolumeFile* vf); /// get enable functional masking volume bool getFunctionalMaskingVolumeEnabled() const { return functionalMaskingVolumeEnabled; } /// set enable functional masking volume void setFunctionalMaskingVolumeEnabled(bool enableIt); /// get the functional volume used for masking VolumeFile* getFunctionalMaskingVolumeFile(); // set the functional volume used for masking void setFunctionalMaskingVolumeFile(VolumeFile* vf); /// get the functional masking volume negative threshold float getFunctionalMaskingVolumeNegativeThreshold() const { return functionalMaskingVolumeNegativeThreshold; } /// set the functional masking volume negative threshold void setFunctionalMaskingVolumeNegativeThreshold(const float value); /// get the functional masking volume positive theshold float getFunctionalMaskingVolumePositiveThreshold() const { return functionalMaskingVolumePositiveThreshold; } /// set the functional masking volume positive theshold void setFunctionalMaskingVolumePositiveThreshold(const float value); /// get display a vector file bool getDisplayVectorFile(const int indx) const; /// set display a vector file void setDisplayVectorFile(const int indx, const bool dispFlag); /// get the display orientation DISPLAY_ORIENTATION getDisplayOrientation() const { return displayOrientation; } /// set the display orientation void setDisplayOrientation(const DISPLAY_ORIENTATION orient) { displayOrientation = orient; } /// get the display orientation angle float getDisplayOrientationAngle() const { return displayOrientationAngle; } /// set the display orientation angle void setDisplayOrientationAngle(const float angle) { displayOrientationAngle = angle; } private: /// surface symbol SURFACE_SYMBOL surfaceSymbol; /// vector type VECTOR_TYPE vectorType; /// the display mode on surface DISPLAY_MODE displayModeSurface; /// the display mode on volume DISPLAY_MODE displayModeVolume; /// the color mode COLOR_MODE colorMode; /// sparse distance (mm) int sparseDistance; /// tracks which vector files should be displayed mutable std::vector displayVectorFileFlag; /// vector length multiplier float lengthMultiplier; /// draw the vectors using the magnitude bool drawWithMagnitude; /// volume slice distance above limit float volumeSliceDistanceAboveLimit; /// volume slice distance below limit float volumeSliceDistanceBelowLimit; /// width for surface vectors drawn as lines float surfaceVectorLineWidth; /// threshold for magnitude float magnitudeThreshold; /// enable segmentation masking volume bool segmentationMaskingVolumeEnabled; /// segmentation volume used for masking VolumeFile* segmentationMaskingVolumeFile; /// enable functional volume masking bool functionalMaskingVolumeEnabled; /// functional volume used for masking VolumeFile* functionalMaskingVolumeFile; /// functional volume masking negative threshold float functionalMaskingVolumeNegativeThreshold; /// functional volume masking positive threshold float functionalMaskingVolumePositiveThreshold; /// the display orientation DISPLAY_ORIENTATION displayOrientation; /// the display orientation angle float displayOrientationAngle; }; #endif // __DISPLAY_SETTINGS_VECTORS_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsVectors.cxx0000664000175000017500000004570711572067322025142 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainSet.h" #include "DisplaySettingsVectors.h" #include "FileUtilities.h" #include "StringUtilities.h" #include "VectorFile.h" /** * The constructor. */ DisplaySettingsVectors::DisplaySettingsVectors(BrainSet* bs) : DisplaySettings(bs) { lengthMultiplier = 10.0; sparseDistance = 50; colorMode = DisplaySettingsVectors::COLOR_MODE_XYZ_AS_RGB; displayModeSurface = DisplaySettingsVectors::DISPLAY_MODE_NONE; displayModeVolume = DisplaySettingsVectors::DISPLAY_MODE_NONE; vectorType = DisplaySettingsVectors::VECTOR_TYPE_BIDIRECTIONAL; surfaceSymbol = DisplaySettingsVectors::SURFACE_SYMBOL_2D_LINE; drawWithMagnitude = true; magnitudeThreshold = 0.05; surfaceVectorLineWidth = 1.0; volumeSliceDistanceAboveLimit = 1.05; volumeSliceDistanceBelowLimit = -1.05; segmentationMaskingVolumeEnabled = false; functionalMaskingVolumeEnabled = false; functionalMaskingVolumePositiveThreshold = 5.0; functionalMaskingVolumeNegativeThreshold = -5.0; displayOrientation = DISPLAY_ORIENTATION_ANY; displayOrientationAngle = 45.0; reset(); } /** * The destructor. */ DisplaySettingsVectors::~DisplaySettingsVectors() { } /** * Reinitialize all display settings */ void DisplaySettingsVectors::reset() { segmentationMaskingVolumeFile = NULL; functionalMaskingVolumeFile = NULL; } /** * Update any selections due to changes in loaded areal estimation file */ void DisplaySettingsVectors::update() { } /** * set the length multiplier. */ void DisplaySettingsVectors::setLengthMultiplier(const float len) { lengthMultiplier = len; } /** * set the color mode. */ void DisplaySettingsVectors::setColorMode(const COLOR_MODE colorModeIn) { this->colorMode = colorModeIn; } /** * set draw with magnitude. */ void DisplaySettingsVectors::setDrawWithMagnitude(const bool dwm) { this->drawWithMagnitude = dwm; } /** * set the display mode. */ void DisplaySettingsVectors::setDisplayModeSurface(const DISPLAY_MODE dm) { displayModeSurface = dm; } /** * set the display mode. */ void DisplaySettingsVectors::setDisplayModeVolume(const DISPLAY_MODE dm) { displayModeVolume = dm; } /** * set the sparse distance. */ void DisplaySettingsVectors::setSparseDisplayDistance(const int dist) { sparseDistance = dist; } /** * Get display a vector file. */ bool DisplaySettingsVectors::getDisplayVectorFile(const int indx) const { displayVectorFileFlag.resize(brainSet->getNumberOfVectorFiles(), true); if ((indx >= 0) && (indx < static_cast(displayVectorFileFlag.size()))) { return displayVectorFileFlag[indx]; } return false; } /** * Set display a vector file. */ void DisplaySettingsVectors::setDisplayVectorFile(const int indx, const bool dispFlag) { displayVectorFileFlag.resize(brainSet->getNumberOfVectorFiles(), true); if ((indx >= 0) && (indx < static_cast(displayVectorFileFlag.size()))) { displayVectorFileFlag[indx] = dispFlag; } } static const QString surfaceVectorID("surface-vector-column"); /** * apply a scene (set display settings). */ void DisplaySettingsVectors::showScene(const SceneFile::Scene& scene, QString& /*errorMessage*/) { segmentationMaskingVolumeFile = NULL; int numVectorFiles = brainSet->getNumberOfVectorFiles(); for (int i = 0; i < numVectorFiles; i++) { this->setDisplayVectorFile(i, false); } surfaceSymbol = SURFACE_SYMBOL_2D_LINE; vectorType = VECTOR_TYPE_BIDIRECTIONAL; const int numClasses = scene.getNumberOfSceneClasses(); for (int nc = 0; nc < numClasses; nc++) { const SceneFile::SceneClass* sc = scene.getSceneClass(nc); if (sc->getName() == "DisplaySettingsVectors") { const int num = sc->getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc->getSceneInfo(i); const QString infoName = si->getName(); if (infoName == "colorMode") { colorMode = static_cast(si->getValueAsInt()); } else if (infoName == "surfaceSymbol") { const QString surfaceSymbolString = si->getValueAsString(); if (surfaceSymbolString == "SURFACE_SYMBOL_3D") { surfaceSymbol = SURFACE_SYMBOL_3D; } else if (surfaceSymbolString == "SURFACE_SYMBOL_2D_LINE") { surfaceSymbol = SURFACE_SYMBOL_2D_LINE; } } else if (infoName == "vectorType") { const QString vectorTypeString = si->getValueAsString(); if (vectorTypeString == "VECTOR_TYPE_BIDIRECTIONAL") { vectorType = VECTOR_TYPE_BIDIRECTIONAL; } else if ((vectorTypeString == "VECTOR_TYPE_UNIDIRECTIONAL") || (vectorTypeString == "VECTOR_TYPE_UNIDIRECTIONAL_ARROW")) { vectorType = VECTOR_TYPE_UNIDIRECTIONAL_ARROW; } else if (vectorTypeString == "VECTOR_TYPE_UNIDIRECTIONAL_CYLINDER") { vectorType = VECTOR_TYPE_UNIDIRECTIONAL_CYLINDER; } } else if (infoName == "drawMode") { switch (si->getValueAsInt()) { case 0: surfaceSymbol = SURFACE_SYMBOL_3D; vectorType = VECTOR_TYPE_UNIDIRECTIONAL_ARROW; break; case 1: surfaceSymbol = SURFACE_SYMBOL_3D; vectorType = VECTOR_TYPE_BIDIRECTIONAL; break; case 2: surfaceSymbol = SURFACE_SYMBOL_2D_LINE; vectorType = VECTOR_TYPE_BIDIRECTIONAL; break; case 3: surfaceSymbol = SURFACE_SYMBOL_2D_LINE; vectorType = VECTOR_TYPE_UNIDIRECTIONAL_ARROW; break; } } else if (infoName == "displayModeSurface") { displayModeSurface = static_cast(si->getValueAsInt()); } else if (infoName == "displayModeVolume") { displayModeVolume = static_cast(si->getValueAsInt()); } else if (infoName == "sparseDistance") { si->getValue(sparseDistance); } else if (infoName == "drawWithMagnitude") { si->getValue(drawWithMagnitude); } else if (infoName == "lengthMultiplier") { si->getValue(lengthMultiplier); } else if (infoName == "magnitudeThreshold") { si->getValue(magnitudeThreshold); } else if (infoName == "volumeSliceDistanceBelowLimit") { si->getValue(volumeSliceDistanceBelowLimit); } else if (infoName == "volumeSliceDistanceAboveLimit") { si->getValue(volumeSliceDistanceAboveLimit); } else if (infoName == "surfaceVectorLineWidth") { si->getValue(surfaceVectorLineWidth); } else if (infoName == "segmentationMaskingVolumeEnabled") { si->getValue(segmentationMaskingVolumeEnabled); } else if (infoName == "segmentationMaskingVolumeFile") { const QString name = si->getValueAsString(); for (int m = 0; m < brainSet->getNumberOfVolumeSegmentationFiles(); m++) { VolumeFile* vf = brainSet->getVolumeSegmentationFile(m); if (name == FileUtilities::basename(vf->getFileName())) { segmentationMaskingVolumeFile = vf; break; } } } else if (infoName == "functionalMaskingVolumeEnabled") { si->getValue(functionalMaskingVolumeEnabled); } else if (infoName == "functionalMaskingVolumeFile") { const QString name = si->getValueAsString(); for (int m = 0; m < brainSet->getNumberOfVolumeFunctionalFiles(); m++) { VolumeFile* vf = brainSet->getVolumeFunctionalFile(m); if (name == FileUtilities::basename(vf->getFileName())) { functionalMaskingVolumeFile = vf; break; } } } else if (infoName == "functionalMaskingVolumePositiveThreshold") { si->getValue(functionalMaskingVolumePositiveThreshold); } else if (infoName == "functionalMaskingVolumeNegativeThreshold") { si->getValue(functionalMaskingVolumeNegativeThreshold); } else if (infoName == "displayVectorFileFlag") { const QString fileName = si->getValueAsString(); for (int m = 0; m < numVectorFiles; m++) { VectorFile* vf = brainSet->getVectorFile(m); if (vf->getFileNameNoPath() == fileName) { this->setDisplayVectorFile(m, true); break; } } } else if (infoName == "displayOrientationAngle") { si->getValue(displayOrientationAngle); } else if (infoName == "displayOrientation") { QString orientString = si->getValueAsString(); DISPLAY_ORIENTATION orient = DISPLAY_ORIENTATION_ANY; if (orientString == "DISPLAY_ORIENTATION_ANY") { orient = DISPLAY_ORIENTATION_ANY; } else if (orientString == "DISPLAY_ORIENTATION_LEFT_RIGHT") { orient = DISPLAY_ORIENTATION_LEFT_RIGHT; } else if (orientString == "DISPLAY_ORIENTATION_POSTERIOR_ANTERIOR") { orient = DISPLAY_ORIENTATION_POSTERIOR_ANTERIOR; } else if (orientString == "DISPLAY_ORIENTATION_INFERIOR_SUPERIOR") { orient = DISPLAY_ORIENTATION_INFERIOR_SUPERIOR; } else { std::cout << "ERROR: Invalid display orientation for vectors: \"" << orientString.toAscii().constData() << std::endl; } setDisplayOrientation(orient); } } } } } /** * create a scene (read display settings). */ void DisplaySettingsVectors::saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& /*errorMessage*/) { int numVectorFiles = brainSet->getNumberOfVectorFiles(); if (onlyIfSelected) { if (numVectorFiles <= 0) { return; } } SceneFile::SceneClass sc("DisplaySettingsVectors"); sc.addSceneInfo(SceneFile::SceneInfo("colorMode", colorMode)); QString vectorTypeString; switch (vectorType) { case VECTOR_TYPE_BIDIRECTIONAL: vectorTypeString = "VECTOR_TYPE_BIDIRECTIONAL"; break; case VECTOR_TYPE_UNIDIRECTIONAL_ARROW: vectorTypeString = "VECTOR_TYPE_UNIDIRECTIONAL_ARROW"; break; case VECTOR_TYPE_UNIDIRECTIONAL_CYLINDER: vectorTypeString = "VECTOR_TYPE_UNIDIRECTIONAL_CYLINDER"; break; } sc.addSceneInfo(SceneFile::SceneInfo("vectorType", vectorTypeString)); QString surfaceSymbolString; switch (surfaceSymbol) { case SURFACE_SYMBOL_3D: surfaceSymbolString = "SURFACE_SYMBOL_3D"; break; case SURFACE_SYMBOL_2D_LINE: surfaceSymbolString = "SURFACE_SYMBOL_2D_LINE"; break; } sc.addSceneInfo(SceneFile::SceneInfo("surfaceSymbol", surfaceSymbolString)); sc.addSceneInfo(SceneFile::SceneInfo("displayModeSurface", displayModeSurface)); sc.addSceneInfo(SceneFile::SceneInfo("displayModeVolume", displayModeVolume)); sc.addSceneInfo(SceneFile::SceneInfo("sparseDistance", sparseDistance)); sc.addSceneInfo(SceneFile::SceneInfo("lengthMultiplier", lengthMultiplier)); sc.addSceneInfo(SceneFile::SceneInfo("drawWithMagnitude", drawWithMagnitude)); sc.addSceneInfo(SceneFile::SceneInfo("magnitudeThreshold", magnitudeThreshold)); sc.addSceneInfo(SceneFile::SceneInfo("volumeSliceDistanceAboveLimit", volumeSliceDistanceAboveLimit)); sc.addSceneInfo(SceneFile::SceneInfo("volumeSliceDistanceBelowLimit", volumeSliceDistanceBelowLimit)); sc.addSceneInfo(SceneFile::SceneInfo("surfaceVectorLineWidth", surfaceVectorLineWidth)); sc.addSceneInfo(SceneFile::SceneInfo("segmentationMaskingVolumeEnabled", segmentationMaskingVolumeEnabled)); if (getSegmentationMaskingVolumeFile() != NULL) { sc.addSceneInfo(SceneFile::SceneInfo("segmentationMaskingVolumeFile", FileUtilities::basename(getSegmentationMaskingVolumeFile()->getFileName()))); } sc.addSceneInfo(SceneFile::SceneInfo("functionalMaskingVolumeEnabled", functionalMaskingVolumeEnabled)); if (getFunctionalMaskingVolumeFile() != NULL) { sc.addSceneInfo(SceneFile::SceneInfo("functionalMaskingVolumeFile", FileUtilities::basename(getFunctionalMaskingVolumeFile()->getFileName()))); } sc.addSceneInfo(SceneFile::SceneInfo("functionalMaskingVolumePositiveThreshold", functionalMaskingVolumePositiveThreshold)); sc.addSceneInfo(SceneFile::SceneInfo("functionalMaskingVolumeNegativeThreshold", functionalMaskingVolumeNegativeThreshold)); for (int i = 0; i < numVectorFiles; i++) { if (this->getDisplayVectorFile(i)) { VectorFile* vf = brainSet->getVectorFile(i); sc.addSceneInfo(SceneFile::SceneInfo("displayVectorFileFlag", vf->getFileNameNoPath())); } } sc.addSceneInfo(SceneFile::SceneInfo("displayOrientationAngle", displayOrientationAngle)); QString orientString; switch (displayOrientation) { case DISPLAY_ORIENTATION_ANY: orientString = "DISPLAY_ORIENTATION_ANY"; break; case DISPLAY_ORIENTATION_LEFT_RIGHT: orientString = "DISPLAY_ORIENTATION_LEFT_RIGHT"; break; case DISPLAY_ORIENTATION_POSTERIOR_ANTERIOR: orientString = "DISPLAY_ORIENTATION_POSTERIOR_ANTERIOR"; break; case DISPLAY_ORIENTATION_INFERIOR_SUPERIOR: orientString = "DISPLAY_ORIENTATION_INFERIOR_SUPERIOR"; break; } sc.addSceneInfo(SceneFile::SceneInfo("displayOrientation", orientString)); scene.addSceneClass(sc); } /** * set the volume slice above limit. */ void DisplaySettingsVectors::setVolumeSliceDistanceAboveLimit(const float limit) { this->volumeSliceDistanceAboveLimit = limit; } /** * set the volume slice below limit. */ void DisplaySettingsVectors::setVolumeSliceDistanceBelowLimit(const float limit) { this->volumeSliceDistanceBelowLimit = limit; } /** * set the surface vector line width. */ void DisplaySettingsVectors::setSurfaceVectorLineWidth(const float lineWidth) { this->surfaceVectorLineWidth = lineWidth; } /** * set the magnitude threshold. */ void DisplaySettingsVectors::setMagnitudeThreshold(const float magThresh) { this->magnitudeThreshold = magThresh; } /** * set enable segmentation masking volume. */ void DisplaySettingsVectors::setSegmentationMaskingVolumeEnabled(bool enableIt) { this->segmentationMaskingVolumeEnabled = enableIt; } /** * get the segmentation volume used for masking. */ VolumeFile* DisplaySettingsVectors::getSegmentationMaskingVolumeFile() { bool found = false; for (int i = 0; i < brainSet->getNumberOfVolumeSegmentationFiles(); i++) { if (brainSet->getVolumeSegmentationFile(i) == this->segmentationMaskingVolumeFile) { found = true; break; } } if (found == false) { this->segmentationMaskingVolumeFile = NULL; } if (this->segmentationMaskingVolumeFile == NULL) { if (brainSet->getNumberOfVolumeSegmentationFiles() > 0) { this->segmentationMaskingVolumeFile = brainSet->getVolumeSegmentationFile(0); } } return segmentationMaskingVolumeFile; } /** * set the segmentation volume used for masking. */ void DisplaySettingsVectors::setSegmentationMaskingVolumeFile(VolumeFile* vf) { this->segmentationMaskingVolumeFile = vf; } /** * Set enable functional masking volume. */ void DisplaySettingsVectors::setFunctionalMaskingVolumeEnabled(bool enableIt) { functionalMaskingVolumeEnabled = enableIt; } /** * Get the functional volume used for masking. */ VolumeFile* DisplaySettingsVectors::getFunctionalMaskingVolumeFile() { bool found = false; for (int i = 0; i < brainSet->getNumberOfVolumeFunctionalFiles(); i++) { if (brainSet->getVolumeFunctionalFile(i) == this->functionalMaskingVolumeFile) { found = true; break; } } if (found == false) { this->functionalMaskingVolumeFile = NULL; } if (this->functionalMaskingVolumeFile == NULL) { const int numFunctionalVolumes = brainSet->getNumberOfVolumeFunctionalFiles(); if (numFunctionalVolumes > 0) { this->functionalMaskingVolumeFile = brainSet->getVolumeFunctionalFile(numFunctionalVolumes - 1); } } return functionalMaskingVolumeFile; } /** * set the functional volume used for masking. */ void DisplaySettingsVectors::setFunctionalMaskingVolumeFile(VolumeFile* vf) { functionalMaskingVolumeFile = vf; } /** * Set the functional masking volume positive theshold. */ void DisplaySettingsVectors::setFunctionalMaskingVolumePositiveThreshold(const float value) { functionalMaskingVolumePositiveThreshold = value; } /** * Set the functional masking volume negative. */ void DisplaySettingsVectors::setFunctionalMaskingVolumeNegativeThreshold(const float value) { functionalMaskingVolumeNegativeThreshold = value; } caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsTopography.h0000664000175000017500000000454211572067322025266 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_DISPLAY_SETTINGS_TOPOGRAPHY_H__ #define __VE_DISPLAY_SETTINGS_TOPOGRAPHY_H__ #include #include "DisplaySettingsNodeAttributeFile.h" /// DisplaySettingsTopography is a class that maintains parameters for controlling /// the display of Topography Files. class DisplaySettingsTopography : public DisplaySettingsNodeAttributeFile { public: /// Type of topography display enum TOPOGRAPHY_DISPLAY_TYPE { TOPOGRAPHY_DISPLAY_ECCENTRICITY, TOPOGRAPHY_DISPLAY_POLAR_ANGLE }; /// Constructor DisplaySettingsTopography(BrainSet* bs); /// Constructor ~DisplaySettingsTopography(); /// get the topography display type TOPOGRAPHY_DISPLAY_TYPE getDisplayType() const { return displayType; } /// set the topography display type void setDisplayType(const TOPOGRAPHY_DISPLAY_TYPE tdt) { displayType = tdt; } /// Reinitialize all display settings void reset(); /// Update any selections due to changes in loaded metric file void update(); /// apply a scene (set display settings) virtual void showScene(const SceneFile::Scene& scene, QString& errorMessage) ; /// create a scene (read display settings) virtual void saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& errorMessage); private: /// display type TOPOGRAPHY_DISPLAY_TYPE displayType; }; #endif caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsTopography.cxx0000664000175000017500000000763111572067322025643 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelSurfaceNodeColoring.h" #include "BrainSet.h" #include "DisplaySettingsTopography.h" #include "TopographyFile.h" /** * The constructor. */ DisplaySettingsTopography::DisplaySettingsTopography(BrainSet* bs) : DisplaySettingsNodeAttributeFile(bs, NULL, bs->getTopographyFile(), BrainModelSurfaceOverlay::OVERLAY_TOPOGRAPHY, true, false) { reset(); } /** * The destructor. */ DisplaySettingsTopography::~DisplaySettingsTopography() { } /** * Reinitialize all display settings. */ void DisplaySettingsTopography::reset() { DisplaySettingsNodeAttributeFile::reset(); displayType = TOPOGRAPHY_DISPLAY_ECCENTRICITY; } /** * Update selections due to changes in loaded topography files. */ void DisplaySettingsTopography::update() { DisplaySettingsNodeAttributeFile::update(); } static const QString topographyID("topography-column"); /** * apply a scene (set display settings). */ void DisplaySettingsTopography::showScene(const SceneFile::Scene& scene, QString& errorMessage) { DisplaySettingsNodeAttributeFile::showScene(scene, errorMessage); const int numClasses = scene.getNumberOfSceneClasses(); for (int nc = 0; nc < numClasses; nc++) { const SceneFile::SceneClass* sc = scene.getSceneClass(nc); if (sc->getName() == "DisplaySettingsTopography") { showSceneSelectedColumns(*sc, "Topograrphy File", topographyID, "", errorMessage); const int num = sc->getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc->getSceneInfo(i); const QString infoName = si->getName(); if (infoName == "topography-displayType") { int val; si->getValue(val); displayType = static_cast(val); } } } } } /** * create a scene (read display settings). */ void DisplaySettingsTopography::saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& errorMessage) { DisplaySettingsNodeAttributeFile::saveScene(scene, onlyIfSelected, errorMessage); TopographyFile* tf = brainSet->getTopographyFile(); if (onlyIfSelected) { if (tf->getNumberOfColumns() <= 0) { return; } if (brainSet->isASurfaceOverlayForAnySurface( BrainModelSurfaceOverlay::OVERLAY_TOPOGRAPHY) == false) { return; } } SceneFile::SceneClass sc("DisplaySettingsTopography"); saveSceneSelectedColumns(sc); sc.addSceneInfo(SceneFile::SceneInfo("topography-displayType", displayType)); scene.addSceneClass(sc); } caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsSurfaceShape.h0000664000175000017500000001017511572067322025502 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_DISPLAY_SETTINGS_SURFACE_SHAPE_H__ #define __VE_DISPLAY_SETTINGS_SURFACE_SHAPE_H__ #include #include "DisplaySettingsNodeAttributeFile.h" /// DisplaySettingsSurfaceShape is a class that maintains parameters for controlling /// the display of surface shape data files. class DisplaySettingsSurfaceShape : public DisplaySettingsNodeAttributeFile { public: /// color map for display enum SURFACE_SHAPE_COLOR_MAP { SURFACE_SHAPE_COLOR_MAP_GRAY, SURFACE_SHAPE_COLOR_MAP_ORANGE_YELLOW, SURFACE_SHAPE_COLOR_MAP_PALETTE }; /// Constructor DisplaySettingsSurfaceShape(BrainSet* bs); /// Destructor ~DisplaySettingsSurfaceShape(); /// Reinitialize all display settings void reset(); /// Update any selections due to changes in loaded surface shape file void update(); /// get the color map for display SURFACE_SHAPE_COLOR_MAP getColorMap() const { return colorMap; } /// set the color map for display void setColorMap(const SURFACE_SHAPE_COLOR_MAP cm) { colorMap = cm; } /// get display color bar bool getDisplayColorBar() const { return displayColorBar; } /// set display color bar void setDisplayColorBar(const bool dcb) { displayColorBar = dcb; } /// get node uncertainty column int getNodeUncertaintyColumn() const { return nodeUncertaintyColumn; } /// set the node undertainty column void setNodeUncertaintyColumn(const int col) { nodeUncertaintyColumn = col; } /// get node uncertainty enabled bool getNodeUncertaintyEnabled() const { return nodeUncertaintyEnabled; } /// set node uncertainty enabled void setNodeUncertaintyEnabled(const bool ne) { nodeUncertaintyEnabled = ne; } /// get the selected palette index int getSelectedPaletteIndex() const { return paletteIndex; } /// set the selected palette index void setSelectedPaletteIndex(const int pi) { paletteIndex = pi; } /// get interpolate palette colors flag bool getInterpolatePaletteColors() const { return interpolatePaletteColors; } /// set interpolate palette colors flag void setInterpolatePaletteColors(const int ic) { interpolatePaletteColors = ic; } /// apply a scene (set display settings) virtual void showScene(const SceneFile::Scene& scene, QString& errorMessage) ; /// create a scene (read display settings) virtual void saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& errorMessage); // get the columns for palette and color mapping (negative if invalid) int getShapeColumnForPaletteAndColorMapping() const; private: /// color map for display SURFACE_SHAPE_COLOR_MAP colorMap; /// display metric color bar bool displayColorBar; /// node uncertainty column int nodeUncertaintyColumn; /// node uncertainty enabled bool nodeUncertaintyEnabled; /// interpolate palette colors bool interpolatePaletteColors; /// selected palette index int paletteIndex; }; #endif caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsSurfaceShape.cxx0000664000175000017500000002001411572067322026046 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelSurface.h" #include "BrainModelSurfaceNodeColoring.h" #include "BrainSet.h" #include "DisplaySettingsSurfaceShape.h" #include "PaletteFile.h" #include "SurfaceShapeFile.h" /** * The constructor. */ DisplaySettingsSurfaceShape::DisplaySettingsSurfaceShape(BrainSet* bs) : DisplaySettingsNodeAttributeFile(bs, bs->getSurfaceShapeFile(), NULL, BrainModelSurfaceOverlay::OVERLAY_SURFACE_SHAPE, true, false) { reset(); } /** * The destructor. */ DisplaySettingsSurfaceShape::~DisplaySettingsSurfaceShape() { } /** * Reinitialize all display settings. */ void DisplaySettingsSurfaceShape::reset() { DisplaySettingsNodeAttributeFile::reset(); colorMap = SURFACE_SHAPE_COLOR_MAP_GRAY; displayColorBar = false; nodeUncertaintyColumn = 0; nodeUncertaintyEnabled = false; paletteIndex = 0; interpolatePaletteColors = false; } /** * Update any selections du to changes in loaded surface shape file. */ void DisplaySettingsSurfaceShape::update() { DisplaySettingsNodeAttributeFile::update(); if (nodeUncertaintyColumn >= 0) { const SurfaceShapeFile* ssf = brainSet->getSurfaceShapeFile(); if (nodeUncertaintyColumn >= ssf->getNumberOfColumns()) { nodeUncertaintyColumn = -3; // -3 is none in combo box on d/c } } if (paletteIndex >= brainSet->getPaletteFile()->getNumberOfPalettes()) { paletteIndex = 0; } } static const QString surfaceShapeViewID("surface-shape-column"); /** * apply a scene (set display settings). */ void DisplaySettingsSurfaceShape::showScene(const SceneFile::Scene& scene, QString& errorMessage) { DisplaySettingsNodeAttributeFile::showScene(scene, errorMessage); SurfaceShapeFile* ssf = brainSet->getSurfaceShapeFile(); const int numClasses = scene.getNumberOfSceneClasses(); for (int nc = 0; nc < numClasses; nc++) { const SceneFile::SceneClass* sc = scene.getSceneClass(nc); if (sc->getName() == "DisplaySettingsSurfaceShape") { showSceneSelectedColumns(*sc, "Surface Shape File", surfaceShapeViewID, "", errorMessage); const int num = sc->getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc->getSceneInfo(i); const QString infoName = si->getName(); if (infoName == "colorMap") { int val; si->getValue(val); colorMap = static_cast(val); } else if (infoName == "shapeDisplayColorBar") { si->getValue(displayColorBar); } else if (infoName == "nodeUncertaintyColumn") { const QString name = si->getValueAsString(); for (int j = 0; j < ssf->getNumberOfColumns(); j++) { if (name == ssf->getColumnName(j)) { nodeUncertaintyColumn = j; } } } else if (infoName == "nodeUncertaintyEnabled") { si->getValue(nodeUncertaintyEnabled); } else if (infoName == "interpolatePaletteColors") { si->getValue(interpolatePaletteColors); } else if (infoName == "shapePaletteIndex") { const QString paletteName = si->getValueAsString(); PaletteFile* pf = brainSet->getPaletteFile(); const int num = pf->getNumberOfPalettes(); bool found = false; for (int j = 0; j < num; j++) { const Palette* pal = pf->getPalette(j); if (paletteName == pal->getName()) { paletteIndex = j; found = true; break; } } if (found == false) { errorMessage.append("Unable to find palette named: "); errorMessage.append(paletteName); errorMessage.append("\n"); } } } } } } /** * create a scene (read display settings). */ void DisplaySettingsSurfaceShape::saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& errorMessage) { DisplaySettingsNodeAttributeFile::saveScene(scene, onlyIfSelected, errorMessage); SurfaceShapeFile* ssf = brainSet->getSurfaceShapeFile(); if (onlyIfSelected) { if (ssf->getNumberOfColumns() <= 0) { return; } if (brainSet->isASurfaceOverlayForAnySurface( BrainModelSurfaceOverlay::OVERLAY_SURFACE_SHAPE) == false) { // return; } } SceneFile::SceneClass sc("DisplaySettingsSurfaceShape"); saveSceneSelectedColumns(sc); sc.addSceneInfo(SceneFile::SceneInfo("colorMap", colorMap)); sc.addSceneInfo(SceneFile::SceneInfo("shapeDisplayColorBar", displayColorBar)); if ((nodeUncertaintyColumn >= 0) && (nodeUncertaintyColumn < ssf->getNumberOfColumns())) { sc.addSceneInfo(SceneFile::SceneInfo("nodeUncertaintyColumn", ssf->getColumnName(nodeUncertaintyColumn))); } sc.addSceneInfo(SceneFile::SceneInfo("nodeUncertaintyEnabled", nodeUncertaintyEnabled)); sc.addSceneInfo(SceneFile::SceneInfo("interpolatePaletteColors", interpolatePaletteColors)); PaletteFile* pf = brainSet->getPaletteFile(); if ((paletteIndex >= 0) && (paletteIndex < pf->getNumberOfPalettes())) { const Palette* pal = pf->getPalette(paletteIndex); sc.addSceneInfo(SceneFile::SceneInfo("shapePaletteIndex", pal->getName())); } scene.addSceneClass(sc); } /** * get the columns for palette and color mapping (negative if invalid). */ int DisplaySettingsSurfaceShape::getShapeColumnForPaletteAndColorMapping() const { int displayColumnOut = -1; // // Get the brain model surface in the main window // const int mainWindowBrainModelIndex = brainSet->getDisplayedModelIndexForWindow(BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW); const BrainModelSurface* bms = brainSet->getBrainModelSurface(mainWindowBrainModelIndex); if (bms == NULL) { return displayColumnOut; } // // See if surface has shape as an overlay // for (int i = 0; i < brainSet->getNumberOfSurfaceOverlays(); i++) { const BrainModelSurfaceOverlay* bmsOverlay = brainSet->getSurfaceOverlay(i); if (bmsOverlay->getOverlay(mainWindowBrainModelIndex) == BrainModelSurfaceOverlay::OVERLAY_SURFACE_SHAPE) { displayColumnOut = bmsOverlay->getDisplayColumnSelected(mainWindowBrainModelIndex); } } return displayColumnOut; } caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsSurface.h0000664000175000017500000002253611572067322024525 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_DISPLAY_SETTINGS_SURFACE_H__ #define __VE_DISPLAY_SETTINGS_SURFACE_H__ #include "DisplaySettings.h" class BrainModelSurface; class BrainSet; /// This class maintains parameters for display of surface. class DisplaySettingsSurface : public DisplaySettings { public: /// Surface drawing enums. enum DRAW_MODE { DRAW_MODE_NODES, DRAW_MODE_LINKS, DRAW_MODE_LINK_HIDDEN_LINE_REMOVAL, DRAW_MODE_LINKS_EDGES_ONLY, DRAW_MODE_NODES_AND_LINKS, DRAW_MODE_TILES, DRAW_MODE_TILES_WITH_LIGHT, DRAW_MODE_TILES_WITH_LIGHT_NO_BACK, DRAW_MODE_TILES_LINKS_NODES, DRAW_MODE_NONE }; /// the viewing projection enum VIEWING_PROJECTION { VIEWING_PROJECTION_ORTHOGRAPHIC, VIEWING_PROJECTION_PERSPECTIVE }; /// coloring for identify node symbols enum IDENTIFY_NODE_COLOR { IDENTIFY_NODE_COLOR_BLACK, IDENTIFY_NODE_COLOR_BLUE, IDENTIFY_NODE_COLOR_GREEN, IDENTIFY_NODE_COLOR_RED, IDENTIFY_NODE_COLOR_WHITE }; /// clipping plane axis enum CLIPPING_PLANE_AXIS { CLIPPING_PLANE_AXIS_X_NEGATIVE = 0, CLIPPING_PLANE_AXIS_X_POSITIVE = 1, CLIPPING_PLANE_AXIS_Y_NEGATIVE = 2, CLIPPING_PLANE_AXIS_Y_POSITIVE = 3, CLIPPING_PLANE_AXIS_Z_NEGATIVE = 4, CLIPPING_PLANE_AXIS_Z_POSITIVE = 5, CLIPPING_PLANE_AXIS_NUMBER_OF = 6 }; /// clipping plane application enum CLIPPING_PLANE_APPLICATION { CLIPPING_PLANE_APPLICATION_MAIN_WINDOW_ONLY, CLIPPING_PLANE_APPLICATION_FIDUCIAL_SURFACES_ONLY, CLIPPING_PLANE_APPLICATION_ALL_SURFACES, }; /// get the drawing mode DRAW_MODE getDrawMode() const { return drawMode; } /// set the drawing mode void setDrawMode(const DRAW_MODE dm); /// get the viewing projection VIEWING_PROJECTION getViewingProjection() const { return viewingProjection; } /// set the viewing projection void setViewingProjection(const VIEWING_PROJECTION vp) { viewingProjection = vp; } /// Constructor DisplaySettingsSurface(BrainSet* bs); /// Desstructor ~DisplaySettingsSurface(); /// get node brightness float getNodeBrightness() const { return nodeBrightness; } /// set node brightness void setNodeBrightness(const float bright) { nodeBrightness = bright; } /// get node contrast float getNodeContrast() const { return nodeContrast; } /// set node contrast void setNodeContrast(const float contrast) { nodeContrast = contrast; } /// get node size float getNodeSize() const { return nodeSize; } /// set node size void setNodeSize(const float size) { nodeSize = size; } /// get link size float getLinkSize() const { return linkSize; } /// set link size void setLinkSize(const float size) { linkSize = size; } /// get show normals bool getShowNormals() const { return showNormals; } /// set show normals void setShowNormals(const bool show) { showNormals = show; } /// get show morphing total forces bool getShowMorphingTotalForces() const { return showMorphingTotalForces; } /// set show morphing total forces void setShowMorphingTotalForces(const bool show) { showMorphingTotalForces = show; } /// get show morphing angular forces bool getShowMorphingAngularForces() const { return showMorphingAngularForces; } /// set show morphing angular forces void setShowMorphingAngularForces(const bool show) { showMorphingAngularForces = show; } /// get show morphing linear forces bool getShowMorphingLinearForces() const { return showMorphingLinearForces; } /// set show morphing linear forces void setShowMorphingLinearForces(const bool show) { showMorphingLinearForces = show; } /// get display length of force vector float getForceVectorDisplayLength() const { return forceVectorDisplayLength; } /// set the display length of the force vector void setForceVectorDisplayLength(const float length) { forceVectorDisplayLength = length; } /// Get show surface axes info void getSurfaceAxesInfo(bool& showAxes, bool& showLetters, bool& showHashMarks, float& axesLength, float axesOffset[3]) const; /// set show surface axes info void setSurfaceAxesInfo(const bool showAxes, const bool showLetters, const bool showHashMarks, const float axesLength, const float axesOffset[3]); /// get the identify node color IDENTIFY_NODE_COLOR getIdentifyNodeColor() const { return identifyNodeColor; } /// set the identify node color void setIdentifyNodeColor(const IDENTIFY_NODE_COLOR idc) { identifyNodeColor = idc; } /// get the opacity float getOpacity() const { return opacity; } /// set the opacity void setOpacity(const float opacityIn) { opacity = opacityIn; }; /// get a clipping plane coordinate float getClippingPlaneCoordinate(const CLIPPING_PLANE_AXIS planeAxis) const; /// set a clipping plane coordinate void setClippingPlaneCoordinate(const CLIPPING_PLANE_AXIS planeAxis, const float coordinateValue); /// get clipping plane enabled bool getClippingPlaneEnabled(const CLIPPING_PLANE_AXIS planeAxis) const; /// set a clipping plane coordinate void setClippingPlaneEnabled(const CLIPPING_PLANE_AXIS planeAxis, const bool enabled); /// get the clipping plane application CLIPPING_PLANE_APPLICATION getClippingPlaneApplication() const { return clippingPlaneApplication; } /// set the clipping plane application void setClippingPlaneApplication(const CLIPPING_PLANE_APPLICATION cpa) { clippingPlaneApplication = cpa; } /// Reinitialize all display settings void reset(); /// Update any selections due to changes in loaded surface shape file void update(); /// apply a scene (set display settings) virtual void showScene(const SceneFile::Scene& scene, QString& errorMessage) ; /// create a scene (read display settings) virtual void saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& errorMessage); private: /// the drawing mode DRAW_MODE drawMode; /// node brightness float nodeBrightness; /// node contrast float nodeContrast; /// node size float nodeSize; /// link size float linkSize; /// display length of a force vector float forceVectorDisplayLength; /// show normals bool showNormals; /// show morphing total forces bool showMorphingTotalForces; /// show morphing angular forces bool showMorphingAngularForces; /// show morphing linear forces bool showMorphingLinearForces; /// the viewing projection VIEWING_PROJECTION viewingProjection; /// show surface axes bool showSurfaceAxes; /// show surface axes letters on surface axes bool showSurfaceAxesLetters; /// show surface axes hash marks bool showSurfaceAxesHashMarks; /// surface axes length float surfaceAxesLength; /// surface axis offset float surfaceAxesOffset[3]; /// identify node color IDENTIFY_NODE_COLOR identifyNodeColor; /// surface opacity float opacity; /// clipping plane coordinate along each axis (negative and positive) float clippingPlaneCoordinate[CLIPPING_PLANE_AXIS_NUMBER_OF]; /// clipping plane enabled for each axis (negative and positive) bool clippingPlaneEnabled[CLIPPING_PLANE_AXIS_NUMBER_OF]; /// how the clipping planes are applied CLIPPING_PLANE_APPLICATION clippingPlaneApplication; }; #endif // __VE_DISPLAY_SETTINGS_SURFACE_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsSurface.cxx0000664000175000017500000004314111572067322025073 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurfaceNodeColoring.h" #include "BrainSet.h" #include "DisplaySettingsSection.h" #include "DisplaySettingsSurface.h" #include "StringUtilities.h" /** * The constructor. */ DisplaySettingsSurface::DisplaySettingsSurface(BrainSet* bs) : DisplaySettings(bs) { drawMode = DRAW_MODE_TILES_WITH_LIGHT; nodeBrightness = 0.0; nodeContrast = 1.0; nodeSize = 2; linkSize = 2; forceVectorDisplayLength = 10.0; opacity = 1.0; identifyNodeColor = IDENTIFY_NODE_COLOR_GREEN; showNormals = false; showMorphingTotalForces = false; showMorphingAngularForces = false; showMorphingLinearForces = false; viewingProjection = VIEWING_PROJECTION_ORTHOGRAPHIC; showSurfaceAxes = false; showSurfaceAxesLetters = true; showSurfaceAxesHashMarks = true; surfaceAxesLength = 110.0; surfaceAxesOffset[0] = 0.0; surfaceAxesOffset[1] = 0.0; surfaceAxesOffset[2] = 0.0; for (int i = 0; i < CLIPPING_PLANE_AXIS_NUMBER_OF; i++) { this->clippingPlaneEnabled[i] = false; } this->clippingPlaneCoordinate[0] = -100.0; this->clippingPlaneCoordinate[1] = 100.0; this->clippingPlaneCoordinate[2] = -100.0; this->clippingPlaneCoordinate[3] = 100.0; this->clippingPlaneCoordinate[4] = -100.0; this->clippingPlaneCoordinate[5] = 100.0; this->clippingPlaneApplication = CLIPPING_PLANE_APPLICATION_MAIN_WINDOW_ONLY; reset(); } /** * The destructor. */ DisplaySettingsSurface::~DisplaySettingsSurface() { } /** * Reinitialize all display settings. */ void DisplaySettingsSurface::reset() { } /** * Update any selections do to changes in loaded surface shape file. */ void DisplaySettingsSurface::update() { } /** * set the drawing mode. */ void DisplaySettingsSurface::setDrawMode(const DRAW_MODE dm) { drawMode = dm; bool lightOn = false; switch (drawMode) { case DRAW_MODE_NODES: break; case DRAW_MODE_LINKS: break; case DRAW_MODE_LINK_HIDDEN_LINE_REMOVAL: break; case DRAW_MODE_LINKS_EDGES_ONLY: break; case DRAW_MODE_NODES_AND_LINKS: break; case DRAW_MODE_TILES: break; case DRAW_MODE_TILES_WITH_LIGHT: lightOn = true; break; case DRAW_MODE_TILES_WITH_LIGHT_NO_BACK: lightOn = true; case DRAW_MODE_TILES_LINKS_NODES: lightOn = true; break; case DRAW_MODE_NONE: break; } } /** * Get show surface axes info. */ void DisplaySettingsSurface::getSurfaceAxesInfo(bool& showAxes, bool& showLetters, bool& showHashMarks, float& axesLength, float axesOffset[3]) const { showAxes = showSurfaceAxes; showLetters = showSurfaceAxesLetters; showHashMarks = showSurfaceAxesHashMarks; axesLength = surfaceAxesLength; for (int i = 0; i < 3; i++) { axesOffset[i] = surfaceAxesOffset[i]; } } /** * set show surface axes info. */ void DisplaySettingsSurface::setSurfaceAxesInfo(const bool showAxes, const bool showLetters, const bool showHashMarks, const float axesLength, const float axesOffset[3]) { showSurfaceAxes = showAxes; showSurfaceAxesLetters = showLetters; showSurfaceAxesHashMarks = showHashMarks; surfaceAxesLength = axesLength; for (int i = 0; i < 3; i++) { surfaceAxesOffset[i] = axesOffset[i]; } } static const QString DRAW_MODE_NODES_VALUE("DRAW_MODE_NODES"); static const QString DRAW_MODE_LINKS_VALUE("DRAW_MODE_LINKS"); static const QString DRAW_MODE_LINK_HIDDEN_LINE_REMOVAL_VALUE("DRAW_MODE_LINK_HIDDEN_LINE_REMOVAL"); static const QString DRAW_MODE_LINKS_EDGES_ONLY_VALUE("DRAW_MODE_LINKS_EDGES_ONLY"); static const QString DRAW_MODE_NODES_AND_LINKS_VALUE("DRAW_MODE_NODES_AND_LINKS"); static const QString DRAW_MODE_TILES_VALUE("DRAW_MODE_TILES"); static const QString DRAW_MODE_TILES_WITH_LIGHT_VALUE("DRAW_MODE_TILES_WITH_LIGHT"); static const QString DRAW_MODE_TILES_WITH_LIGHT_NO_BACK_VALUE("DRAW_MODE_TILES_WITH_LIGHT_NO_BACK"); static const QString DRAW_MODE_TILES_LINKS_NODES_VALUE("DRAW_MODE_TILES_LINKS_NODES"); static const QString DRAW_MODE_NONE_VALUE("DRAW_MODE_NONE"); /** * apply a scene (set display settings). */ void DisplaySettingsSurface::showScene(const SceneFile::Scene& scene, QString& /*errorMessage*/) { const int numClasses = scene.getNumberOfSceneClasses(); for (int nc = 0; nc < numClasses; nc++) { const SceneFile::SceneClass* sc = scene.getSceneClass(nc); if (sc->getName() == "DisplaySettingsSurface") { const int num = sc->getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc->getSceneInfo(i); const QString infoName = si->getName(); if (infoName == "surfaceDrawMode") { const QString drawModeValue = si->getValueAsString(); if (drawModeValue == DRAW_MODE_NODES_VALUE) { drawMode = DRAW_MODE_NODES; } else if (drawModeValue == DRAW_MODE_LINKS_VALUE) { drawMode = DRAW_MODE_LINKS; } else if (drawModeValue == DRAW_MODE_LINK_HIDDEN_LINE_REMOVAL_VALUE) { drawMode = DRAW_MODE_LINK_HIDDEN_LINE_REMOVAL; } else if (drawModeValue == DRAW_MODE_LINKS_EDGES_ONLY_VALUE) { drawMode = DRAW_MODE_LINKS_EDGES_ONLY; } else if (drawModeValue == DRAW_MODE_NODES_AND_LINKS_VALUE) { drawMode = DRAW_MODE_NODES_AND_LINKS; } else if (drawModeValue == DRAW_MODE_TILES_VALUE) { drawMode = DRAW_MODE_TILES; } else if (drawModeValue == DRAW_MODE_TILES_WITH_LIGHT_VALUE) { drawMode = DRAW_MODE_TILES_WITH_LIGHT; } else if (drawModeValue == DRAW_MODE_TILES_WITH_LIGHT_NO_BACK_VALUE) { drawMode = DRAW_MODE_TILES_WITH_LIGHT_NO_BACK; } else if (drawModeValue == DRAW_MODE_TILES_LINKS_NODES_VALUE) { drawMode = DRAW_MODE_TILES_LINKS_NODES; } else if (drawModeValue == DRAW_MODE_NONE_VALUE) { drawMode = DRAW_MODE_NONE; } } else if (infoName == "nodeBrightness") { si->getValue(nodeBrightness); } else if (infoName == "opacity") { si->getValue(opacity); } else if (infoName == "nodeContrast") { si->getValue(nodeContrast); } else if (infoName == "nodeSize") { si->getValue(nodeSize); } else if (infoName == "linkSize") { si->getValue(linkSize); } else if (infoName == "forceVectorDisplayLength") { si->getValue(forceVectorDisplayLength); } else if (infoName == "showNormals") { si->getValue(showNormals); } else if (infoName == "showMorphingTotalForces") { si->getValue(showMorphingTotalForces); } else if (infoName == "showMorphingAngularForces") { si->getValue(showMorphingAngularForces); } else if (infoName == "showMorphingLinearForces") { si->getValue(showMorphingLinearForces); } else if (infoName == "sectionToHighlight") { int sectionToHighlight; bool sectionHighlightEveryX; DisplaySettingsSection* dss = brainSet->getDisplaySettingsSection(); dss->getSectionHighlighting(sectionToHighlight, sectionHighlightEveryX); si->getValue(sectionToHighlight); dss->getSectionHighlighting(sectionToHighlight, sectionHighlightEveryX); } else if (infoName == "sectionHighlightEveryX") { int sectionToHighlight; bool sectionHighlightEveryX; DisplaySettingsSection* dss = brainSet->getDisplaySettingsSection(); dss->getSectionHighlighting(sectionToHighlight, sectionHighlightEveryX); si->getValue(sectionHighlightEveryX); dss->getSectionHighlighting(sectionToHighlight, sectionHighlightEveryX); } else if (infoName == "viewingProjection") { int val; si->getValue(val); viewingProjection = static_cast(val); } else if (infoName == "showSurfaceAxes") { si->getValue(showSurfaceAxes); } else if (infoName == "showSurfaceAxesLetters") { si->getValue(showSurfaceAxesLetters); } else if (infoName == "showSurfaceAxesHashMarks") { si->getValue(showSurfaceAxesHashMarks); } else if (infoName == "surfaceAxesLength") { si->getValue(surfaceAxesLength); } else if (infoName == "surfaceAxesOffset") { const QString val = si->getValueAsString(); std::vector tokens; StringUtilities::token(val, " ", tokens); if (tokens.size() >= 3) { surfaceAxesOffset[0] = tokens[0].toFloat(); surfaceAxesOffset[1] = tokens[1].toFloat(); surfaceAxesOffset[2] = tokens[2].toFloat(); } } else if (infoName == "identifyNodeColor") { identifyNodeColor = static_cast(si->getValueAsInt()); } else if (infoName == "clippingPlaneApplication") { clippingPlaneApplication = static_cast(si->getValueAsInt()); } else if (infoName == "clippingPlaneEnabled") { const QString val = si->getValueAsString(); std::vector tokens; StringUtilities::token(val, " ", tokens); if (tokens.size() >= CLIPPING_PLANE_AXIS_NUMBER_OF) { for (int i = 0; i < CLIPPING_PLANE_AXIS_NUMBER_OF; i++) { clippingPlaneEnabled[i] = tokens[i]; } } } else if (infoName == "clippingPlaneCoordinate") { const QString val = si->getValueAsString(); std::vector tokens; StringUtilities::token(val, " ", tokens); if (tokens.size() >= CLIPPING_PLANE_AXIS_NUMBER_OF) { for (int i = 0; i < CLIPPING_PLANE_AXIS_NUMBER_OF; i++) { clippingPlaneCoordinate[i] = tokens[i]; } } } } } } } /** * create a scene (read display settings). */ void DisplaySettingsSurface::saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& /*errorMessage*/) { if (onlyIfSelected) { const int num = brainSet->getNumberOfBrainModels(); bool haveSurfacesFlag = false; for (int i = 0; i < num; i++) { if (brainSet->getBrainModelSurface(i) != NULL) { haveSurfacesFlag = true; break; } } if (haveSurfacesFlag == false) { return; } } SceneFile::SceneClass sc("DisplaySettingsSurface"); QString drawModeValue(DRAW_MODE_NODES_VALUE); switch (drawMode) { case DRAW_MODE_NODES: drawModeValue = DRAW_MODE_NODES_VALUE; break; case DRAW_MODE_LINKS: drawModeValue = DRAW_MODE_LINKS_VALUE; break; case DRAW_MODE_LINK_HIDDEN_LINE_REMOVAL: drawModeValue = DRAW_MODE_LINK_HIDDEN_LINE_REMOVAL_VALUE; break; case DRAW_MODE_LINKS_EDGES_ONLY: drawModeValue = DRAW_MODE_LINKS_EDGES_ONLY_VALUE; break; case DRAW_MODE_NODES_AND_LINKS: drawModeValue = DRAW_MODE_NODES_AND_LINKS_VALUE; break; case DRAW_MODE_TILES: drawModeValue = DRAW_MODE_TILES_VALUE; break; case DRAW_MODE_TILES_WITH_LIGHT: drawModeValue = DRAW_MODE_TILES_WITH_LIGHT_VALUE; break; case DRAW_MODE_TILES_WITH_LIGHT_NO_BACK: drawModeValue = DRAW_MODE_TILES_WITH_LIGHT_NO_BACK_VALUE; break; case DRAW_MODE_TILES_LINKS_NODES: drawModeValue = DRAW_MODE_TILES_LINKS_NODES_VALUE; break; case DRAW_MODE_NONE: drawModeValue = DRAW_MODE_NONE_VALUE; break; } sc.addSceneInfo(SceneFile::SceneInfo("surfaceDrawMode", drawModeValue)); sc.addSceneInfo(SceneFile::SceneInfo("nodeBrightness", nodeBrightness)); sc.addSceneInfo(SceneFile::SceneInfo("nodeContrast", nodeContrast)); sc.addSceneInfo(SceneFile::SceneInfo("opacity", opacity)); sc.addSceneInfo(SceneFile::SceneInfo("nodeSize", nodeSize)); sc.addSceneInfo(SceneFile::SceneInfo("linkSize", linkSize)); sc.addSceneInfo(SceneFile::SceneInfo("forceVectorDisplayLength", forceVectorDisplayLength)); sc.addSceneInfo(SceneFile::SceneInfo("showNormals", showNormals)); sc.addSceneInfo(SceneFile::SceneInfo("showMorphingTotalForces", showMorphingTotalForces)); sc.addSceneInfo(SceneFile::SceneInfo("showMorphingAngularForces", showMorphingAngularForces)); sc.addSceneInfo(SceneFile::SceneInfo("showMorphingLinearForces", showMorphingLinearForces)); sc.addSceneInfo(SceneFile::SceneInfo("viewingProjection", viewingProjection)); sc.addSceneInfo(SceneFile::SceneInfo("showSurfaceAxes", showSurfaceAxes)); sc.addSceneInfo(SceneFile::SceneInfo("showSurfaceAxesLetters", showSurfaceAxesLetters)); sc.addSceneInfo(SceneFile::SceneInfo("showSurfaceAxesHashMarks", showSurfaceAxesHashMarks)); sc.addSceneInfo(SceneFile::SceneInfo("surfaceAxesLength", surfaceAxesLength)); sc.addSceneInfo(SceneFile::SceneInfo("identifyNodeColor", identifyNodeColor)); std::vector offsets; offsets.push_back(surfaceAxesOffset[0]); offsets.push_back(surfaceAxesOffset[1]); offsets.push_back(surfaceAxesOffset[2]); sc.addSceneInfo(SceneFile::SceneInfo("surfaceAxesOffset", StringUtilities::combine(offsets, " "))); std::vector planeEnabled; std::vector planeCoord; for (int i = 0; i < CLIPPING_PLANE_AXIS_NUMBER_OF; i++) { planeEnabled.push_back(clippingPlaneEnabled[i]); planeCoord.push_back(clippingPlaneCoordinate[i]); } sc.addSceneInfo(SceneFile::SceneInfo("clippingPlaneEnabled", StringUtilities::combine(planeEnabled, " "))); sc.addSceneInfo(SceneFile::SceneInfo("clippingPlaneCoordinate", StringUtilities::combine(planeCoord, " "))); sc.addSceneInfo(SceneFile::SceneInfo("clippingPlaneApplication", static_cast(clippingPlaneApplication))); scene.addSceneClass(sc); } /** * get a clipping plane coordinate. */ float DisplaySettingsSurface::getClippingPlaneCoordinate(const CLIPPING_PLANE_AXIS planeAxis) const { return this->clippingPlaneCoordinate[planeAxis]; } /** * set a clipping plane coordinate. */ void DisplaySettingsSurface::setClippingPlaneCoordinate(const CLIPPING_PLANE_AXIS planeAxis, const float coordinateValue) { this->clippingPlaneCoordinate[planeAxis] = coordinateValue; } /** * get clipping plane enabled. */ bool DisplaySettingsSurface::getClippingPlaneEnabled(const CLIPPING_PLANE_AXIS planeAxis) const { return this->clippingPlaneEnabled[planeAxis]; } /** * set a clipping plane coordinate. */ void DisplaySettingsSurface::setClippingPlaneEnabled(const CLIPPING_PLANE_AXIS planeAxis, const bool enabled) { this->clippingPlaneEnabled[planeAxis] = enabled; } caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsStudyMetaData.h0000664000175000017500000001246611572067322025647 0ustar michaelmichael #ifndef __DISPLAY_SETTINGS_STUDY_METADATA_H__ #define __DISPLAY_SETTINGS_STUDY_METADATA_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "DisplaySettings.h" class BrainSet; /// class for display settings of study meta data class DisplaySettingsStudyMetaData : public DisplaySettings { public: /// keyword status enum KEYWORD_STATUS { /// KEYWORD_STATUS_KEYWORD_SELECTED, /// KEYWORD_STATUS_KEYWORD_NOT_SELECTED, /// KEYWORD_STATUS_HAS_NO_KEYWORDS }; // Constructor DisplaySettingsStudyMetaData(BrainSet* bs); // Destructor virtual ~DisplaySettingsStudyMetaData(); // Reinitialize all display settings virtual void reset(); // Update any selections due to changes in loaded cells virtual void update(); // get keywords and number of foci using the keywords void getKeywordsAndUsageByFoci(std::vector& keywordsOut, std::vector& fociCountForKeywordOut) const; // get keyword indices sorted by name case insensitive void getKeywordIndicesSortedByName(std::vector& indicesSortedByNameOut, const bool reverseOrderFlag, const bool limitToDisplayedFociFlag) const; // update the keywords void updateKeywords(); /// get the number of keywords int getNumberOfKeywords() const { return keywords.size(); } // get index of a keyword int getKeywordIndexByName(const QString& name) const; // get a keyword from its index QString getKeywordNameByIndex(const int indx) const; // get a keyword's selection status bool getKeywordSelected(const int indx) const; // get a keyword's selection status bool getKeywordSelected(const QString& name) const; // set a keyword's selection status void setKeywordSelected(const int indx, const bool selFlag); // get subheaders and number of foci using the subheaders void getSubheadersAndUsageByFoci(std::vector& subheadersOut, std::vector& fociCountForSubheadersOut) const; // get subheader indices sorted by name case insensitive void getSubHeaderIndicesSortedByName(std::vector& indicesSortedByNameOut, const bool reverseOrderFlag, const bool limitToDisplayedFociFlag) const; // update the subheaders names void updateSubHeaderNames(); /// get the number of subheader names int getNumberOfSubHeaderNames() const { return subHeaderNames.size(); } // get index of a subheader name int getSubHeaderIndexByName(const QString& name) const; // get a subh header name by its index QString getSubHeaderNameByIndex(const int indx) const; // get a subheader name's selection status bool getSubHeaderNameSelected(const int indx) const; // get a sub header name's selection status bool getSubHeaderNameSelected(const QString& name) const; // set a sub header name's selection status void setSubHeaderNameSelected(const int indx, const bool selFlag); // update study metadata table subheader selection status void updateStudyMetaDataTableSubHeaderSelectionFlags() const; // apply a scene (set display settings) virtual void showScene(const SceneFile::Scene& scene, QString& errorMessage) ; // create a scene (read display settings) virtual void saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& errorMessage); // determine studies with selected keywords void getStudiesWithSelectedKeywords(std::vector& studyKeywordStatus) const; protected: // the keywords std::vector keywords; // the keyword selection status std::vector keywordsSelected; // the sub header names std::vector subHeaderNames; // the sub header selection status std::vector subHeaderNamesSelected; }; #endif // __DISPLAY_SETTINGS_STUDY_METADATA_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsStudyMetaData.cxx0000664000175000017500000005411211572067322026214 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainSet.h" #include "DisplaySettingsStudyMetaData.h" #include "FociProjectionFile.h" #include "NameIndexSort.h" #include "StudyMetaDataFile.h" /** * Constructor. */ DisplaySettingsStudyMetaData::DisplaySettingsStudyMetaData(BrainSet* bs) : DisplaySettings(bs) { reset(); } /** * Destructor. */ DisplaySettingsStudyMetaData::~DisplaySettingsStudyMetaData() { } /** * Reinitialize all display settings. */ void DisplaySettingsStudyMetaData::reset() { } /** * Update any selections due to changes in loaded cells. */ void DisplaySettingsStudyMetaData::update() { updateKeywords(); updateSubHeaderNames(); } class CaseInsensitiveStringCompare { public: bool operator() (const QString& s1, const QString& s2) const { return (s1.toLower() < s2.toLower()); } }; /** * get keywords and number of foci using the keywords. */ void DisplaySettingsStudyMetaData::getKeywordsAndUsageByFoci(std::vector& keywordsOut, std::vector& fociCountForKeywordOut) const { keywordsOut.clear(); fociCountForKeywordOut.clear(); const StudyMetaDataFile* smdf = brainSet->getStudyMetaDataFile(); const int numStudies = smdf->getNumberOfStudyMetaData(); if (numStudies <= 0) { return; } const FociProjectionFile* fpf = brainSet->getFociProjectionFile(); const int numFoci = fpf->getNumberOfCellProjections(); if (numFoci <= 0) { return; } // // Track number of foci using each study // std::vector numberOfFociLinkingToStudy(numStudies, 0); for (int j = 0; j < numFoci; j++) { const CellProjection* fp = fpf->getCellProjection(j); StudyMetaDataLinkSet smdls = fp->getStudyMetaDataLinkSet(); for (int j = 0; j < smdls.getNumberOfStudyMetaDataLinks(); j++) { StudyMetaDataLink smdl = smdls.getStudyMetaDataLink(j); const int studyIndex = smdf->getStudyIndexFromLink(smdl); if ((studyIndex >= 0) && (studyIndex < numStudies)) { numberOfFociLinkingToStudy[studyIndex]++; } } } // // Update count for each keyword // std::map keywordFociCount; for (int i= 0; i < smdf->getNumberOfStudyMetaData(); i++) { //if (numberOfFociLinkingToStudy[i] > 0) { // // Get keywords from study // const StudyMetaData* smd = smdf->getStudyMetaData(i); std::vector keywords; smd->getKeywords(keywords); const int numKeywords = static_cast(keywords.size()); if (numKeywords > 0) { // // Update the total keywords counts // for (int k = 0; k < numKeywords; k++) { const QString& kw = keywords[k]; std::map::iterator iter = keywordFociCount.find(kw); if (iter != keywordFociCount.end()) { keywordFociCount[kw] += numberOfFociLinkingToStudy[i]; } else { keywordFociCount[kw] = numberOfFociLinkingToStudy[i]; } } } //} } for (std::map::iterator iter = keywordFociCount.begin(); iter != keywordFociCount.end(); iter++) { keywordsOut.push_back(iter->first); fociCountForKeywordOut.push_back(iter->second); } } /* void DisplaySettingsStudyMetaData::getKeywordsAndUsageByFoci(std::vector& keywordsOut, std::vector& fociCountForKeywordOut) const { keywordsOut.clear(); fociCountForKeywordOut.clear(); const StudyMetaDataFile* smdf = brainSet->getStudyMetaDataFile(); const FociProjectionFile* fpf = brainSet->getFociProjectionFile(); const int numFoci = fpf->getNumberOfCellProjections(); // // Track foci using each keyword // std::map keywordFociCount; // // Check all studies // for (int i= 0; i < smdf->getNumberOfStudyMetaData(); i++) { // // Get keywords from study // const StudyMetaData* smd = smdf->getStudyMetaData(i); std::vector keywords; smd->getKeywords(keywords); const int numKeywords = static_cast(keywords.size()); if (numKeywords > 0) { // // Loop through all foci and count number of foci that // use these keywords // int numberOfFociUsingKeywords = 0; for (int j = 0; j < numFoci; j++) { const CellProjection* fp = fpf->getCellProjection(j); StudyMetaDataLinkSet smdls = fp->getStudyMetaDataLinkSet(); for (int j = 0; j < smdls.getNumberOfStudyMetaDataLinks(); j++) { StudyMetaDataLink smdl = smdls.getStudyMetaDataLink(j); const int studyIndex = smdf->getStudyIndexFromLink(smdl); if (studyIndex == i) { numberOfFociUsingKeywords++; } } } // // Update the total keywords counts // for (int k = 0; k < numKeywords; k++) { const QString& kw = keywords[k]; std::map::iterator iter = keywordFociCount.find(kw); if (iter != keywordFociCount.end()) { keywordFociCount[kw] += numberOfFociUsingKeywords; } else { keywordFociCount[kw] = numberOfFociUsingKeywords; } } } } for (std::map::iterator iter = keywordFociCount.begin(); iter != keywordFociCount.end(); iter++) { keywordsOut.push_back(iter->first); fociCountForKeywordOut.push_back(iter->second); } } */ /** * get keyword indices sorted by name case insensitive. */ void DisplaySettingsStudyMetaData::getKeywordIndicesSortedByName( std::vector& indicesSortedByNameOut, const bool reverseOrderFlag, const bool limitToDisplayedFociFlag) const { NameIndexSort nis; int numKeywords = 0; if (limitToDisplayedFociFlag) { std::vector subsetOfKeywords; brainSet->getStudyMetaDataFile()->getAllKeywordsUsedByDisplayedFoci( brainSet->getFociProjectionFile(), subsetOfKeywords); numKeywords = static_cast(subsetOfKeywords.size()); for (int i = 0; i < numKeywords; i++) { // // Need to use index of ALL keywords // nis.add(getKeywordIndexByName(subsetOfKeywords[i]), subsetOfKeywords[i]); } } else { numKeywords = getNumberOfKeywords(); for (int i = 0; i < numKeywords; i++) { nis.add(i, getKeywordNameByIndex(i)); } } nis.sortByNameCaseInsensitive(); indicesSortedByNameOut.resize(numKeywords, 0); for (int i = 0; i < numKeywords; i++) { indicesSortedByNameOut[i] = nis.getSortedIndex(i); } if (reverseOrderFlag) { std::reverse(indicesSortedByNameOut.begin(), indicesSortedByNameOut.end()); } } /** * update the keywords. */ void DisplaySettingsStudyMetaData::updateKeywords() { // // Save current selections and clear current // const std::vector oldKeywords = keywords; const std::vector oldKeywordsSelected = keywordsSelected; const int numOldKeywords = static_cast(oldKeywords.size()); keywords.clear(); keywordsSelected.clear(); // // get the updated keywords // const StudyMetaDataFile* smdf = brainSet->getStudyMetaDataFile(); smdf->getAllKeywords(keywords); // // Update current selection status with old selection status // const int numKeywords = getNumberOfKeywords(); if (numKeywords > 0) { keywordsSelected.resize(numKeywords); std::fill(keywordsSelected.begin(), keywordsSelected.end(), true); for (int i = 0; i < numOldKeywords; i++) { const int indx = getKeywordIndexByName(oldKeywords[i]); if (indx >= 0) { keywordsSelected[indx] = oldKeywordsSelected[i]; } } } } /** * get index of a keyword. */ int DisplaySettingsStudyMetaData::getKeywordIndexByName(const QString& name) const { const int num = keywords.size(); for (int i = 0; i < num; i++) { if (keywords[i] == name) { return i; } } return -1; } /** * get a keyword from its index */ QString DisplaySettingsStudyMetaData::getKeywordNameByIndex(const int indx) const { if (indx < getNumberOfKeywords()) { return keywords[indx]; } return ""; } /** * get a keyword's selection status. */ bool DisplaySettingsStudyMetaData::getKeywordSelected(const int indx) const { if (indx < getNumberOfKeywords()) { return keywordsSelected[indx]; } return false; } /** * get a keyword's selection status. Returns false if keyword does not exist. */ bool DisplaySettingsStudyMetaData::getKeywordSelected(const QString& name) const { const int indx = getKeywordIndexByName(name); if (indx >= 0) { return getKeywordSelected(indx); } return false; } /** * set a keyword's selection status. */ void DisplaySettingsStudyMetaData::setKeywordSelected(const int indx, const bool selFlag) { if (indx < getNumberOfKeywords()) { keywordsSelected[indx] = selFlag; } } /** * determine studies with selected keywords. */ void DisplaySettingsStudyMetaData::getStudiesWithSelectedKeywords( std::vector& studyKeywordStatus) const { studyKeywordStatus.clear(); // // get the updated keywords // const StudyMetaDataFile* smdf = brainSet->getStudyMetaDataFile(); const int num = smdf->getNumberOfStudyMetaData(); if (num > 0) { studyKeywordStatus.resize(num); for (int i = 0; i < num; i++) { std::vector studyKeywords; const StudyMetaData* smd = smdf->getStudyMetaData(i); smd->getKeywords(studyKeywords); const int numKeywords = static_cast(studyKeywords.size()); studyKeywordStatus[i] = KEYWORD_STATUS_HAS_NO_KEYWORDS; if (numKeywords > 0) { studyKeywordStatus[i] = KEYWORD_STATUS_KEYWORD_NOT_SELECTED; // // See if at least one keyword is selected // for (int j = 0; j < numKeywords; j++) { if (getKeywordSelected(studyKeywords[j])) { studyKeywordStatus[i] = KEYWORD_STATUS_KEYWORD_SELECTED; break; } } } } } } /** * get subheaders and number of foci using the subheaders. */ void DisplaySettingsStudyMetaData::getSubheadersAndUsageByFoci( std::vector& subheadersOut, std::vector& fociCountForSubheadersOut) const { subheadersOut.clear(); fociCountForSubheadersOut.clear(); const StudyMetaDataFile* smdf = brainSet->getStudyMetaDataFile(); const int numStudies = smdf->getNumberOfStudyMetaData(); if (numStudies <= 0) { return; } const FociProjectionFile* fpf = brainSet->getFociProjectionFile(); const int numFoci = fpf->getNumberOfCellProjections(); if (numFoci <= 0) { return; } // // Track number of foci using each study // std::vector numberOfFociLinkingToStudy(numStudies, 0); for (int j = 0; j < numFoci; j++) { const CellProjection* fp = fpf->getCellProjection(j); StudyMetaDataLinkSet smdls = fp->getStudyMetaDataLinkSet(); for (int j = 0; j < smdls.getNumberOfStudyMetaDataLinks(); j++) { StudyMetaDataLink smdl = smdls.getStudyMetaDataLink(j); const int studyIndex = smdf->getStudyIndexFromLink(smdl); if ((studyIndex >= 0) && (studyIndex < numStudies)) { numberOfFociLinkingToStudy[studyIndex]++; } } } // // Update count for each subheader // std::map subheaderFociCount; for (int i= 0; i < smdf->getNumberOfStudyMetaData(); i++) { //if (numberOfFociLinkingToStudy[i] > 0) { // // Get subheaders from study // const StudyMetaData* smd = smdf->getStudyMetaData(i); std::vector subheaders; smd->getAllTableSubHeaderShortNames(subheaders); const int numSubheaders = static_cast(subheaders.size()); if (numSubheaders > 0) { // // Update the total subheader counts // for (int k = 0; k < numSubheaders; k++) { const QString& sh = subheaders[k]; std::map::iterator iter = subheaderFociCount.find(sh); if (iter != subheaderFociCount.end()) { subheaderFociCount[sh] += numberOfFociLinkingToStudy[i]; } else { subheaderFociCount[sh] = numberOfFociLinkingToStudy[i]; } } } //} } for (std::map::iterator iter = subheaderFociCount.begin(); iter != subheaderFociCount.end(); iter++) { subheadersOut.push_back(iter->first); fociCountForSubheadersOut.push_back(iter->second); } } /** * get subheader indices sorted by name case insensitive. */ void DisplaySettingsStudyMetaData::getSubHeaderIndicesSortedByName(std::vector& indicesSortedByNameOut, const bool reverseOrderFlag, const bool limitToDisplayedFociFlag) const { NameIndexSort nis; int numSubHeaderNames = 0; if (limitToDisplayedFociFlag) { std::vector subsetOfSubHeaderNames; brainSet->getStudyMetaDataFile()->getAllTableSubHeaderShortNamesUsedByDisplayedFoci( brainSet->getFociProjectionFile(), subsetOfSubHeaderNames); numSubHeaderNames = static_cast(subsetOfSubHeaderNames.size()); for (int i = 0; i < numSubHeaderNames; i++) { // // Need to use index of ALL subheaders // nis.add(getSubHeaderIndexByName(subsetOfSubHeaderNames[i]), subsetOfSubHeaderNames[i]); } } else { numSubHeaderNames = getNumberOfSubHeaderNames(); for (int i = 0; i < numSubHeaderNames; i++) { nis.add(i, getSubHeaderNameByIndex(i)); } } nis.sortByNameCaseInsensitive(); indicesSortedByNameOut.resize(numSubHeaderNames, 0); for (int i = 0; i < numSubHeaderNames; i++) { indicesSortedByNameOut[i] = nis.getSortedIndex(i); } if (reverseOrderFlag) { std::reverse(indicesSortedByNameOut.begin(), indicesSortedByNameOut.end()); } } /** * update the subheaders names. */ void DisplaySettingsStudyMetaData::updateSubHeaderNames() { // // Save current selections and clear current // const std::vector oldSubHeaderNames = subHeaderNames; const std::vector oldSubHeaderNamesSelected = subHeaderNamesSelected; const int numOldSubHeaderNames = static_cast(oldSubHeaderNames.size()); subHeaderNames.clear(); subHeaderNamesSelected.clear(); // // Get the updated subheader names // const StudyMetaDataFile* smdf = brainSet->getStudyMetaDataFile(); smdf->getAllTableSubHeaderShortNames(subHeaderNames); // // Update current selections status with old selection status // const int numSubHeaderNames = getNumberOfSubHeaderNames(); if (numSubHeaderNames > 0) { subHeaderNamesSelected.resize(numSubHeaderNames); std::fill(subHeaderNamesSelected.begin(), subHeaderNamesSelected.end(), true); for (int i = 0; i < numOldSubHeaderNames; i++) { const int indx = getSubHeaderIndexByName(oldSubHeaderNames[i]); if (indx >= 0) { subHeaderNamesSelected[indx] = oldSubHeaderNamesSelected[i]; } } } } /** * get index of a subheader name. */ int DisplaySettingsStudyMetaData::getSubHeaderIndexByName(const QString& name) const { const int num = getNumberOfSubHeaderNames(); for (int i = 0; i < num; i++) { if (subHeaderNames[i] == name) { return i; } } return -1; } /** * get a subh header name by its index. */ QString DisplaySettingsStudyMetaData::getSubHeaderNameByIndex(const int indx) const { if (indx < getNumberOfSubHeaderNames()) { return subHeaderNames[indx]; } return ""; } /** * get a subheader name's selection status. */ bool DisplaySettingsStudyMetaData::getSubHeaderNameSelected(const int indx) const { if (indx < getNumberOfSubHeaderNames()) { return subHeaderNamesSelected[indx]; } return false; } /** * get a sub header name's selection status. */ bool DisplaySettingsStudyMetaData::getSubHeaderNameSelected(const QString& name) const { const int indx = getSubHeaderIndexByName(name); if (indx >= 0) { return getSubHeaderNameSelected(indx); } return false; } /** * set a sub header name's selection status. */ void DisplaySettingsStudyMetaData::setSubHeaderNameSelected(const int indx, const bool selFlag) { if (indx < getNumberOfSubHeaderNames()) { subHeaderNamesSelected[indx] = selFlag; } } /** * update study metadata table subheader selection status. */ void DisplaySettingsStudyMetaData::updateStudyMetaDataTableSubHeaderSelectionFlags() const { StudyMetaDataFile* smdf = brainSet->getStudyMetaDataFile(); const int numMetaData = smdf->getNumberOfStudyMetaData(); for (int i = 0; i < numMetaData; i++) { StudyMetaData* smd = smdf->getStudyMetaData(i); const int numTables = smd->getNumberOfTables(); for (int j = 0; j < numTables; j++) { StudyMetaData::Table* table = smd->getTable(j); const int numSubHeaders = table->getNumberOfSubHeaders(); for (int k = 0; k < numSubHeaders; k++) { StudyMetaData::SubHeader* sh = table->getSubHeader(k); bool selFlag = false; //true; const int indx = getSubHeaderIndexByName(sh->getShortName()); if (indx >= 0) { selFlag = getSubHeaderNameSelected(indx); } sh->setSelected(selFlag); } } } } /** * apply a scene (set display settings). */ void DisplaySettingsStudyMetaData::showScene(const SceneFile::Scene& scene, QString& errorMessage) { const int numClasses = scene.getNumberOfSceneClasses(); for (int nc = 0; nc < numClasses; nc++) { const SceneFile::SceneClass* sc = scene.getSceneClass(nc); if (sc->getName() == "DisplaySettingsStudyMetaData") { const int num = sc->getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc->getSceneInfo(i); const QString infoName = si->getName(); if (infoName == "keywords") { const QString name = si->getModelName(); const bool selFlag = si->getValueAsBool(); const int indx = getKeywordIndexByName(name); if (indx >= 0) { setKeywordSelected(indx, selFlag); } else { QString msg("study keyword \""); msg.append(name); msg.append("\" not loaded in memory.\n"); errorMessage.append(msg); } } else if (infoName == "subheaders") { const QString name = si->getModelName(); const bool selFlag = si->getValueAsBool(); const int indx = getSubHeaderIndexByName(name); if (indx >= 0) { setSubHeaderNameSelected(indx, selFlag); } else { QString msg("study subheader \""); msg.append(name); msg.append("\" not loaded in memory.\n"); errorMessage.append(msg); } } } } } } /** * create a scene (read display settings). */ void DisplaySettingsStudyMetaData::saveScene(SceneFile::Scene& scene, const bool /*onlyIfSelected*/, QString& /*errorMessage*/) { SceneFile::SceneClass sc("DisplaySettingsStudyMetaData"); const int num = getNumberOfKeywords(); for (int j = 0; j < num; j++) { sc.addSceneInfo(SceneFile::SceneInfo("keywords", getKeywordNameByIndex(j), getKeywordSelected(j))); } const int numSHN = getNumberOfSubHeaderNames(); for (int j = 0; j < numSHN; j++) { sc.addSceneInfo(SceneFile::SceneInfo("subheaders", getSubHeaderNameByIndex(j), getSubHeaderNameSelected(j))); } scene.addSceneClass(sc); } caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsSection.h0000664000175000017500000000672611572067322024544 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __DISPLAY_SETTINGS_SECTION_H__ #define __DISPLAY_SETTINGS_SECTION_H__ #include #include "DisplaySettingsNodeAttributeFile.h" /// DisplaySettingsSection is a class that maintains parameters for /// controlling the display of section data. class DisplaySettingsSection : public DisplaySettingsNodeAttributeFile { public: enum SELECTION_TYPE { SELECTION_TYPE_SINGLE, SELECTION_TYPE_MULTIPLE, SELECTION_TYPE_ALL }; /// Constructor DisplaySettingsSection(BrainSet* bs); /// Destructor ~DisplaySettingsSection(); /// Reinitialize all display settings void reset(); /// Update any selections due to changes in loaded areal estimation file void update(); /// get the section type SELECTION_TYPE getSelectionType() const; /// set the selection type void setSelectionType(SELECTION_TYPE type); /// get the minimum selected section int getMinimumSelectedSection() const; /// get the maximum selected section int getMaximumSelectedSection() const; /// set the minimum selected section void setMinimumSelectedSection(const int sect); /// set the maximum selected section void setMaximumSelectedSection(const int sect); /// get section highlighting void getSectionHighlighting(int& sectionToHighlightOut, bool& highlightEveryXOut) const; /// set section highlighting void setSectionHighlighting(const int sectionToHighlightIn, const bool highlightEveryXIn); /// apply a scene (set display settings) virtual void showScene(const SceneFile::Scene& scene, QString& errorMessage) ; /// create a scene (read display settings) virtual void saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& errorMessage); private: /// update section selections void updateSectionSelections() const; /// type of section selection SELECTION_TYPE selectionType; /// minimum selected section for each column mutable int minimumSelectedSection; /// maximum selected section for each column mutable int maximumSelectedSection; /// section highlighting int sectionToHighlight; /// highlight every X sections bool sectionHighlightEveryX; }; #endif // __DISPLAY_SETTINGS_SECTION_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsSection.cxx0000664000175000017500000001601011572067322025102 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainSet.h" #include "DisplaySettingsSection.h" #include "SectionFile.h" #include "FileUtilities.h" /** * The constructor. */ DisplaySettingsSection::DisplaySettingsSection(BrainSet* bs) : DisplaySettingsNodeAttributeFile(bs, NULL, bs->getSectionFile(), BrainModelSurfaceOverlay::OVERLAY_SECTIONS, false, false) { sectionToHighlight = 10; sectionHighlightEveryX = true; reset(); } /** * The destructor. */ DisplaySettingsSection::~DisplaySettingsSection() { } /** * Reinitialize all display settings */ void DisplaySettingsSection::reset() { DisplaySettingsNodeAttributeFile::reset(); selectionType = SELECTION_TYPE_ALL; updateSectionSelections(); } /** * get section highlighting. */ void DisplaySettingsSection::getSectionHighlighting(int& sectionToHighlightOut, bool& highlightEveryXOut) const { sectionToHighlightOut = sectionToHighlight; highlightEveryXOut = sectionHighlightEveryX; } /** * set section highlighting. */ void DisplaySettingsSection::setSectionHighlighting(const int sectionToHighlightIn, const bool highlightEveryXIn) { sectionToHighlight = sectionToHighlightIn; sectionHighlightEveryX = highlightEveryXIn; } /** * Update any selections due to changes in loaded areal estimation file */ void DisplaySettingsSection::update() { DisplaySettingsNodeAttributeFile::update(); updateSectionSelections(); } static const QString sectionID("section-column"); /** * apply a scene (set display settings). */ void DisplaySettingsSection::showScene(const SceneFile::Scene& scene, QString& errorMessage) { DisplaySettingsNodeAttributeFile::showScene(scene, errorMessage); const int numClasses = scene.getNumberOfSceneClasses(); for (int nc = 0; nc < numClasses; nc++) { const SceneFile::SceneClass* sc = scene.getSceneClass(nc); if (sc->getName() == "DisplaySettingsSection") { showSceneSelectedColumns(*sc, "Section File", sectionID, "", errorMessage); const int num = sc->getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc->getSceneInfo(i); const QString infoName = si->getName(); if (infoName == "selectionType") { selectionType = static_cast(si->getValueAsInt()); } else if (infoName == "minimumSelectedSection") { si->getValue(minimumSelectedSection); } else if (infoName == "maximumSelectedSection") { si->getValue(maximumSelectedSection); } else if (infoName == "sectionToHighlight") { si->getValue(sectionToHighlight); } else if (infoName == "sectionHighlightEveryX") { si->getValue(sectionHighlightEveryX); } } } } } /** * create a scene (read display settings). */ void DisplaySettingsSection::saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& errorMessage) { DisplaySettingsNodeAttributeFile::saveScene(scene, onlyIfSelected, errorMessage); SectionFile* sf = brainSet->getSectionFile(); if (onlyIfSelected) { if (sf->getNumberOfColumns() <= 0) { return; } } SceneFile::SceneClass sc("DisplaySettingsSection"); saveSceneSelectedColumns(sc);; sc.addSceneInfo(SceneFile::SceneInfo("selectionType", static_cast(selectionType))); sc.addSceneInfo(SceneFile::SceneInfo("minimumSelectedSection", minimumSelectedSection)); sc.addSceneInfo(SceneFile::SceneInfo("maximumSelectedSection", maximumSelectedSection)); sc.addSceneInfo(SceneFile::SceneInfo("sectionToHighlight", sectionToHighlight)); sc.addSceneInfo(SceneFile::SceneInfo("sectionHighlightEveryX", sectionHighlightEveryX)); scene.addSceneClass(sc); } /** * get the minimum selected section */ int DisplaySettingsSection::getMinimumSelectedSection() const { updateSectionSelections(); return minimumSelectedSection; } /** * get the maximum selected section */ int DisplaySettingsSection::getMaximumSelectedSection() const { updateSectionSelections(); return maximumSelectedSection; } /** * update section selections. */ void DisplaySettingsSection::updateSectionSelections() const { SectionFile* sf = brainSet->getSectionFile(); int selectedColumn = getSelectedDisplayColumn(-1, -1); if ((selectedColumn < 0) || (selectedColumn >= sf->getNumberOfColumns())) { selectedColumn = 0; } if (selectedColumn < sf->getNumberOfColumns()) { maximumSelectedSection = std::min(maximumSelectedSection, sf->getMaximumSection(selectedColumn)); maximumSelectedSection = std::max(maximumSelectedSection, sf->getMinimumSection(selectedColumn)); minimumSelectedSection = std::max(minimumSelectedSection, sf->getMinimumSection(selectedColumn)); minimumSelectedSection = std::min(minimumSelectedSection, sf->getMaximumSection(selectedColumn)); } } /** * set the minimum selected section */ void DisplaySettingsSection::setMinimumSelectedSection(const int sect) { minimumSelectedSection = sect; } /** * set the maximum selected section */ void DisplaySettingsSection::setMaximumSelectedSection(const int sect) { maximumSelectedSection = sect; } /** * get the section type */ DisplaySettingsSection::SELECTION_TYPE DisplaySettingsSection::getSelectionType() const { return selectionType; } /** * set the selection type */ void DisplaySettingsSection::setSelectionType(SELECTION_TYPE type) { selectionType = type; } caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsScene.h0000664000175000017500000000601011572067322024157 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __DISPLAY_SETTINGS_SCENE_H__ #define __DISPLAY_SETTINGS_SCENE_H__ #include "DisplaySettings.h" /// Display settings for scenes class DisplaySettingsScene : public DisplaySettings { public: /// type for window position enum WINDOW_POSITIONS { /// use all window positions from scene WINDOW_POSITIONS_USE_ALL, /// ignore main window position, make all others relative to scene WINDOW_POSITIONS_IGNORE_MAIN_OTHERS_RELATIVE, /// ignore all window positions WINDOW_POSITIONS_IGNORE_ALL }; /// Constructor DisplaySettingsScene(BrainSet* bsIn); /// Destructor ~DisplaySettingsScene(); /// reinitialize all display settings void reset(); /// update any selections due to changes with loaded data files void update(); /// apply a scene (set display settings) virtual void showScene(const SceneFile::Scene& scene, QString& errorMessage); /// create a scene (read display settings) virtual void saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& errorMessage); /// get the window position preference WINDOW_POSITIONS getWindowPositionPreference() const { return windowPositions; } /// set the window position preference void setWindowPositionPreference(const WINDOW_POSITIONS wpp) { windowPositions = wpp; } /// preserve foci, foci colors, and study metadata bool getPreserveFociAndFociColorsAndStudyMetaDataFlag() const { return preserveFociAndFociColorsAndStudyMetaDataFlag; } /// preserve foci, foci colors, and study metadata void setPreserveFociAndFociColorsAndStudyMetaDataFlag(const bool b) { preserveFociAndFociColorsAndStudyMetaDataFlag = b; } private: /// window positions (DO NOT SAVE TO SCENE) WINDOW_POSITIONS windowPositions; /// preserve foci, foci colors, and study metadata (DO NOT SAVE TO SCENE) bool preserveFociAndFociColorsAndStudyMetaDataFlag; }; #endif // __DISPLAY_SETTINGS_IMAGES_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsScene.cxx0000664000175000017500000000340611572067322024540 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "DisplaySettingsScene.h" /** * Constructor. */ DisplaySettingsScene::DisplaySettingsScene(BrainSet* bsIn) : DisplaySettings(bsIn) { windowPositions = WINDOW_POSITIONS_IGNORE_MAIN_OTHERS_RELATIVE; preserveFociAndFociColorsAndStudyMetaDataFlag = false; } /** * Destructor. */ DisplaySettingsScene::~DisplaySettingsScene() { } /** * reinitialize all display settings. */ void DisplaySettingsScene::reset() { } /** * update any selections due to changes with loaded data files. */ void DisplaySettingsScene::update() { } /** * apply a scene (set display settings). */ void DisplaySettingsScene::showScene(const SceneFile::Scene& /*scene*/, QString& /*errorMessage*/) { } /** * create a scene (read display settings). */ void DisplaySettingsScene::saveScene(SceneFile::Scene& /*scene*/, const bool /*onlyIfSelected*/, QString& /*errorMessage*/) { } caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsRgbPaint.h0000664000175000017500000000674711572067322024651 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_DISPLAY_SETTINGS_RGB_PAINT_H__ #define __VE_DISPLAY_SETTINGS_RGB_PAINT_H__ #include #include "DisplaySettingsNodeAttributeFile.h" /// DisplaySettingsRgbPaint is a class that maintains parameters for controlling /// the display of RGB Paint files. class DisplaySettingsRgbPaint : public DisplaySettingsNodeAttributeFile { public: /// Display Mode enum RGB_DISPLAY_MODE { RGB_DISPLAY_MODE_POSITIVE, RGB_DISPLAY_MODE_NEGATIVE }; /// Constructor DisplaySettingsRgbPaint(BrainSet* bs); /// Destructor ~DisplaySettingsRgbPaint(); /// Reinitialize all display settings void reset(); /// Update any selections due to changes in loaded rgb paint file void update(); /// Get the thresholds void getThresholds(float& redThresh, float& greenThresh, float& blueThresh) const; /// Set the thresholds void setThresholds(const float redThresh, const float greenThresh, const float blueThresh); /// get the display mode RGB_DISPLAY_MODE getDisplayMode() const { return displayMode; } /// set the display mode void setDisplayMode(const RGB_DISPLAY_MODE dm) { displayMode = dm; } /// red enabled for display bool getRedEnabled() const { return redEnabled; } /// set red enabled for display void setRedEnabled(const int re) { redEnabled = re; }; /// green enabled for display bool getGreenEnabled() const { return greenEnabled; } /// set red enabled for display void setGreenEnabled(const int ge) { greenEnabled = ge; }; /// blue enabled for display bool getBlueEnabled() const { return blueEnabled; } /// set blue enabled for display void setBlueEnabled(const int be) { blueEnabled = be; }; /// apply a scene (set display settings) virtual void showScene(const SceneFile::Scene& scene, QString& errorMessage) ; /// create a scene (read display settings) virtual void saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& errorMessage); private: /// red threshold float redThreshold; /// green threshold float greenThreshold; /// blue threshold float blueThreshold; /// display mode RGB_DISPLAY_MODE displayMode; /// red enabled for display bool redEnabled; /// green enabled for display bool greenEnabled; /// blue enabled for display bool blueEnabled; }; #endif caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsRgbPaint.cxx0000664000175000017500000001373411572067322025216 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelSurfaceNodeColoring.h" #include "BrainSet.h" #include "DisplaySettingsRgbPaint.h" #include "RgbPaintFile.h" /** * The constructor. */ DisplaySettingsRgbPaint::DisplaySettingsRgbPaint(BrainSet* bs) : DisplaySettingsNodeAttributeFile(bs, NULL, bs->getRgbPaintFile(), BrainModelSurfaceOverlay::OVERLAY_RGB_PAINT, true, false) { reset(); } /** * The destructor. */ DisplaySettingsRgbPaint::~DisplaySettingsRgbPaint() { } /** * Reinitialize all display settings. */ void DisplaySettingsRgbPaint::reset() { DisplaySettingsNodeAttributeFile::reset(); displayMode = RGB_DISPLAY_MODE_POSITIVE; redThreshold = 0.0; greenThreshold = 0.0; blueThreshold = 0.0; redEnabled = true; greenEnabled = true; blueEnabled = true; } /** * Update any selections due to changes in loaded rgb paint file. */ void DisplaySettingsRgbPaint::update() { DisplaySettingsNodeAttributeFile::update(); } /** * Get the red, green, and blue thresholds */ void DisplaySettingsRgbPaint::getThresholds(float& redThresh, float& greenThresh, float& blueThresh) const { redThresh = redThreshold; greenThresh = greenThreshold; blueThresh = blueThreshold; } /** * Get the red, green, and blue thresholds */ void DisplaySettingsRgbPaint::setThresholds(const float redThresh, const float greenThresh, const float blueThresh) { redThreshold = redThresh; greenThreshold = greenThresh; blueThreshold = blueThresh; } static const QString rgbPaintSurfaceID("surface-rgb-paint-column"); /** * apply a scene (set display settings). */ void DisplaySettingsRgbPaint::showScene(const SceneFile::Scene& scene, QString& errorMessage) { DisplaySettingsNodeAttributeFile::showScene(scene, errorMessage); const int numClasses = scene.getNumberOfSceneClasses(); for (int nc = 0; nc < numClasses; nc++) { const SceneFile::SceneClass* sc = scene.getSceneClass(nc); if (sc->getName() == "DisplaySettingsRgbPaint") { showSceneSelectedColumns(*sc, "RGB Paint File", rgbPaintSurfaceID, "", errorMessage); const int num = sc->getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc->getSceneInfo(i); const QString infoName = si->getName(); if (infoName == "rgb-displayMode") { int val; si->getValue(val); displayMode = static_cast(val); } else if (infoName == "redThreshold") { si->getValue(redThreshold); } else if (infoName == "greenThreshold") { si->getValue(greenThreshold); } else if (infoName == "blueThreshold") { si->getValue(blueThreshold); } else if (infoName == "redEnabled") { si->getValue(redEnabled); } else if (infoName == "greenEnabled") { si->getValue(greenEnabled); } else if (infoName == "blueEnabled") { si->getValue(blueEnabled); } } } } } /** * create a scene (read display settings). */ void DisplaySettingsRgbPaint::saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& errorMessage) { DisplaySettingsNodeAttributeFile::saveScene(scene, onlyIfSelected, errorMessage); RgbPaintFile* rpf = brainSet->getRgbPaintFile(); if (onlyIfSelected) { if (rpf->getNumberOfColumns() <= 0) { return; } if (brainSet->isASurfaceOverlayForAnySurface( BrainModelSurfaceOverlay::OVERLAY_RGB_PAINT) == false) { return; } } SceneFile::SceneClass sc("DisplaySettingsRgbPaint"); saveSceneSelectedColumns(sc); sc.addSceneInfo(SceneFile::SceneInfo("rgb-displayMode", displayMode)); sc.addSceneInfo(SceneFile::SceneInfo("redThreshold", redThreshold)); sc.addSceneInfo(SceneFile::SceneInfo("greenThreshold", greenThreshold)); sc.addSceneInfo(SceneFile::SceneInfo("blueThreshold", blueThreshold)); sc.addSceneInfo(SceneFile::SceneInfo("redEnabled", redEnabled)); sc.addSceneInfo(SceneFile::SceneInfo("greenEnabled", greenEnabled)); sc.addSceneInfo(SceneFile::SceneInfo("blueEnabled", blueEnabled)); scene.addSceneClass(sc); } caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsProbabilisticAtlas.h0000664000175000017500000001317611572067322026710 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_DISPLAY_SETTINGS_PROB_ATLAS_H__ #define __VE_DISPLAY_SETTINGS_PROB_ATLAS_H__ #include #include "DisplaySettings.h" class Structure; /// DisplaySettingsProbabilisticAtlas is a class that maintains parameters for controlling /// the display of Probabilistic Atlas Files. class DisplaySettingsProbabilisticAtlas : public DisplaySettings { public: /// Probabilistic type enum PROBABILISTIC_TYPE { PROBABILISTIC_TYPE_SURFACE, PROBABILISTIC_TYPE_VOLUME }; /// Type of topography display enum PROBABILISTIC_DISPLAY_TYPE { PROBABILISTIC_DISPLAY_TYPE_NORMAL, PROBABILISTIC_DISPLAY_TYPE_THRESHOLD }; /// Constructor DisplaySettingsProbabilisticAtlas(BrainSet* bs, const PROBABILISTIC_TYPE probTypeIn); /// Constructor ~DisplaySettingsProbabilisticAtlas(); /// get the number of channels selected int getNumberOfChannelsSelected() const; /// get channel selected bool getChannelSelected(const int index) const; /// get channel selected for structure set with updateSelectedChannelsForCurrentStructure() bool getChannelSelectedForStructure(const int index) const; /// set channel selected void setChannelSelected(const int index, const bool sel) { channelSelected[index] = sel; } /// set selections status of all channels void setAllChannelsSelectedStatus(const bool status); /// get area selected bool getAreaSelected(const int index) const { return areaSelected[index]; } /// set selections status of all areas void setAllAreasSelectedStatus(const bool status); /// set area selected void setAreaSelected(const int index, const bool sel) { areaSelected[index] = sel; } /// get the topography display type PROBABILISTIC_DISPLAY_TYPE getDisplayType() const { return displayType; } /// set the topography display type void setDisplayType(const PROBABILISTIC_DISPLAY_TYPE pdt) { displayType = pdt; } /// get treat color ??? as if it was Unassigned bool getTreatQuestColorAsUnassigned() const { return treatQuestColorAsUnassigned; } /// set treat color ??? as if it was Unassigned void setTreatQuestColorAsUnassigned(const bool tcu) { treatQuestColorAsUnassigned = tcu; } /// get thresholding display type ratio (0 = at least one to 1 = all) float getThresholdDisplayTypeRatio() const { return thresholdDisplayTypeRatio; } /// set thresholding display type ratio (0 = at least one to 1 = all) void setThresholdDisplayTypeRatio(const float ratio) { thresholdDisplayTypeRatio = ratio; } /// get apply to left and right structures flag bool getApplySelectionToLeftAndRightStructuresFlag() const { return applySelectionToLeftAndRightStructuresFlag; } /// set apply to left and right structures flag void setApplySelectionToLeftAndRightStructuresFlag(const bool b) { applySelectionToLeftAndRightStructuresFlag = b; } /// for node attribute files - all column selections for each surface are the same virtual bool columnSelectionsAreTheSame(const int bm1, const int bm2) const; /// Reinitialize all display settings void reset(); /// Update any selections due to changes in loaded metric file void update(); /// update structure associated with each channel void updateSelectedChannelsForCurrentStructure(const Structure& structure); /// apply a scene (set display settings) virtual void showScene(const SceneFile::Scene& scene, QString& errorMessage) ; /// create a scene (read display settings) virtual void saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& errorMessage); private: /// type of data PROBABILISTIC_TYPE probType; /// display type PROBABILISTIC_DISPLAY_TYPE displayType; /// channel selections std::vector channelSelected; /// channel selections for specific structures (do not need to save to scene) std::vector channelSelectedForStructure; /// areas (colors) selected std::vector areaSelected; /// threshold display type ratio float thresholdDisplayTypeRatio; /// treat the color ??? as if was the color Unassigned bool treatQuestColorAsUnassigned; /// apply coloring with corresponding structures bool applySelectionToLeftAndRightStructuresFlag; }; #endif caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsProbabilisticAtlas.cxx0000664000175000017500000004613311572067322027262 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelSurfaceNodeColoring.h" #include "BrainModelVolumeVoxelColoring.h" #include "BrainModelVolume.h" #include "BrainSet.h" #include "DisplaySettingsProbabilisticAtlas.h" #include "FileUtilities.h" #include "ProbabilisticAtlasFile.h" /** * Constructor. */ DisplaySettingsProbabilisticAtlas::DisplaySettingsProbabilisticAtlas(BrainSet* bs, const PROBABILISTIC_TYPE probTypeIn) : DisplaySettings(bs) { reset(); probType = probTypeIn; } /** * Destructor. */ DisplaySettingsProbabilisticAtlas::~DisplaySettingsProbabilisticAtlas() { } /** * Get the number of selected channels. */ int DisplaySettingsProbabilisticAtlas::getNumberOfChannelsSelected() const { if (applySelectionToLeftAndRightStructuresFlag) { return std::count(channelSelectedForStructure.begin(), channelSelectedForStructure.end(), true); } else { return std::count(channelSelected.begin(), channelSelected.end(), true); } } /** * update structure associated with each channel. */ void DisplaySettingsProbabilisticAtlas::updateSelectedChannelsForCurrentStructure(const Structure& structure) { switch (probType) { case PROBABILISTIC_TYPE_SURFACE: { ProbabilisticAtlasFile* pf = brainSet->getProbabilisticAtlasSurfaceFile(); const int numColumns = pf->getNumberOfColumns(); for (int i = 0; i < numColumns; i++) { // // Default channel off for structure // channelSelectedForStructure[i] = false; // // Is channel on? // if (channelSelected[i]) { switch (structure.getType()) { case Structure::STRUCTURE_TYPE_CORTEX_LEFT: if (pf->getColumnName(i).toLower().indexOf("left") >= 0) { channelSelectedForStructure[i] = true; } break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT: if (pf->getColumnName(i).toLower().indexOf("right") >= 0) { channelSelectedForStructure[i] = true; } break; case Structure::STRUCTURE_TYPE_CORTEX_BOTH: break; case Structure::STRUCTURE_TYPE_CEREBELLUM: break; case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_LEFT: break; case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_RIGHT: break; case Structure::STRUCTURE_TYPE_CORTEX_LEFT_OR_CEREBELLUM: break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT_OR_CEREBELLUM: break; case Structure::STRUCTURE_TYPE_CEREBRUM_CEREBELLUM: case Structure::STRUCTURE_TYPE_SUBCORTICAL: case Structure::STRUCTURE_TYPE_ALL: case Structure::STRUCTURE_TYPE_INVALID: break; } } } } break; case PROBABILISTIC_TYPE_VOLUME: break; } } /** * for node attribute files - all column selections for each surface are the same. */ bool DisplaySettingsProbabilisticAtlas::columnSelectionsAreTheSame(const int bm1, const int bm2) const { if (applySelectionToLeftAndRightStructuresFlag) { const BrainModelSurface* bms1 = brainSet->getBrainModelSurface(bm1); const BrainModelSurface* bms2 = brainSet->getBrainModelSurface(bm2); if ((bms1 != NULL) && (bms2 != NULL)) { if (bms1->getStructure().getType() != bms2->getStructure().getType()) { // // Different structures, probably left/right // return false; } } } return true; } /** * get channel selected. */ bool DisplaySettingsProbabilisticAtlas::getChannelSelected(const int indx) const { return channelSelected[indx]; } /** * get channel selected. */ bool DisplaySettingsProbabilisticAtlas::getChannelSelectedForStructure(const int indx) const { if (applySelectionToLeftAndRightStructuresFlag) { return channelSelectedForStructure[indx]; } else { return channelSelected[indx]; } } /** * Set the selection status of all channels */ void DisplaySettingsProbabilisticAtlas::setAllChannelsSelectedStatus(const bool status) { std::fill(channelSelected.begin(), channelSelected.end(), status); } /** * Set the selection status of all areas. */ void DisplaySettingsProbabilisticAtlas::setAllAreasSelectedStatus(const bool status) { std::fill(areaSelected.begin(), areaSelected.end(), status); } /** * Reset the settings. */ void DisplaySettingsProbabilisticAtlas::reset() { displayType = PROBABILISTIC_DISPLAY_TYPE_NORMAL; channelSelected.clear(); channelSelectedForStructure.clear(); areaSelected.clear(); treatQuestColorAsUnassigned = false; thresholdDisplayTypeRatio = 0.5; applySelectionToLeftAndRightStructuresFlag = false; } /** * Update as a result of new files being loaded. */ void DisplaySettingsProbabilisticAtlas::update() { switch (probType) { case PROBABILISTIC_TYPE_SURFACE: { ProbabilisticAtlasFile* pf = brainSet->getProbabilisticAtlasSurfaceFile(); const int numColumns = pf->getNumberOfColumns(); channelSelected.resize(numColumns); std::fill(channelSelected.begin(), channelSelected.end(), true); channelSelectedForStructure.resize(numColumns); const int numNames = pf->getNumberOfPaintNames(); areaSelected.resize(numNames); std::fill(areaSelected.begin(), areaSelected.end(), true); } break; case PROBABILISTIC_TYPE_VOLUME: { const int numChannels = brainSet->getNumberOfVolumeProbAtlasFiles(); channelSelected.resize(numChannels); std::fill(channelSelected.begin(), channelSelected.end(), true); channelSelectedForStructure.resize(numChannels); int numNames = 0; BrainModelVolume* bmv = brainSet->getBrainModelVolume(); if (bmv != NULL) { if (brainSet->getNumberOfVolumeProbAtlasFiles() > 0) { numNames = brainSet->getVolumeProbAtlasFile(0)->getNumberOfRegionNames(); } } areaSelected.resize(numNames); std::fill(areaSelected.begin(), areaSelected.end(), true); } break; } } /** * apply a scene (set display settings). */ void DisplaySettingsProbabilisticAtlas::showScene(const SceneFile::Scene& scene, QString& errorMessage) { applySelectionToLeftAndRightStructuresFlag = false; update(); std::fill(channelSelected.begin(), channelSelected.end(), false); std::fill(areaSelected.begin(), areaSelected.end(), false); const int numClasses = scene.getNumberOfSceneClasses(); for (int nc = 0; nc < numClasses; nc++) { const SceneFile::SceneClass* sc = scene.getSceneClass(nc); if (((sc->getName() == "DisplaySettingsProbabilisticAtlasSurface") && (probType == PROBABILISTIC_TYPE_SURFACE)) || ((sc->getName() == "DisplaySettingsProbabilisticAtlasVolume") && (probType == PROBABILISTIC_TYPE_VOLUME))) { const int num = sc->getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc->getSceneInfo(i); const QString infoName = si->getName(); if (sc->getName() == "DisplaySettingsProbabilisticAtlasSurface") { ProbabilisticAtlasFile* paf = brainSet->getProbabilisticAtlasSurfaceFile(); if (infoName == "surf-prob-atlas-displayType") { displayType = static_cast(si->getValueAsInt()); } else if (infoName == "surf-thresholdDisplayTypeRatio") { si->getValue(thresholdDisplayTypeRatio); } else if (infoName == "surf-treatQuestColorAsUnassigned") { si->getValue(treatQuestColorAsUnassigned); } else if (infoName == "surf-channelSelected") { const QString name = si->getModelName(); bool nameFound = false; for (int i = 0; i < paf->getNumberOfColumns(); i++) { if (paf->getColumnName(i) == name) { if (i < static_cast(channelSelected.size())) { channelSelected[i] = si->getValueAsBool(); nameFound = true; } } } if (nameFound == false) { QString msg("Unable to find prob atlas column named \""); msg.append(name); msg.append("\"\n"); errorMessage.append(msg); } } else if (infoName == "surf-areaSelected") { const QString name = si->getModelName(); bool nameFound = false; for (int i = 0; i < paf->getNumberOfPaintNames(); i++) { if (name == paf->getPaintNameFromIndex(i)) { if (i < static_cast(areaSelected.size())) { areaSelected[i] = si->getValueAsBool(); nameFound = true; } } } if (nameFound == false) { QString msg("Unable to find prob atlas area named \""); msg.append(name); msg.append("\"\n"); errorMessage.append(msg); } } else if (infoName == "surf-applySelectionToLeftAndRightStructuresFlag") { applySelectionToLeftAndRightStructuresFlag = si->getValueAsBool(); } } if (sc->getName() == "DisplaySettingsProbabilisticAtlasVolume") { if (infoName == "vol-prob-atlas-displayType") { displayType = static_cast(si->getValueAsInt());; } else if (infoName == "vol-thresholdDisplayTypeRatio") { si->getValue(thresholdDisplayTypeRatio); } else if (infoName == "vol-treatQuestColorAsUnassigned") { si->getValue(treatQuestColorAsUnassigned); } else if (infoName == "vol-channelSelected") { const QString name = si->getModelName(); bool nameFound = false; for (int i = 0; i < brainSet->getNumberOfVolumeProbAtlasFiles(); i++) { const QString volDescriptiveName = FileUtilities::basename(brainSet->getVolumeProbAtlasFile(i)->getDescriptiveLabel()); if (volDescriptiveName == name) { if (i < static_cast(channelSelected.size())) { channelSelected[i] = si->getValueAsBool(); nameFound = true; } } } if (nameFound == false) { QString msg("Unable to find prob atlas volume with label: \""); msg.append(name); msg.append("\"\n"); errorMessage.append(msg); } } else if (infoName == "vol-areaSelected") { BrainModelVolume* bmv = brainSet->getBrainModelVolume(); if (bmv != NULL) { if (brainSet->getNumberOfVolumeProbAtlasFiles() > 0) { const VolumeFile* vf = brainSet->getVolumeProbAtlasFile(0); const QString name = si->getModelName(); const int indx = vf->getRegionIndexFromName(name); if (indx >= 0) { areaSelected[indx] = si->getValueAsBool(); } else { QString msg("Unable to find prob atlas volume area named \""); msg.append(name); msg.append("\"\n"); errorMessage.append(msg); } } } } } } } } } /** * create a scene (read display settings). */ void DisplaySettingsProbabilisticAtlas::saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& errorMessage) { SceneFile::SceneClass sc("DisplaySettingsProbabilisticAtlas"); switch (probType) { case PROBABILISTIC_TYPE_SURFACE: { sc.setName("DisplaySettingsProbabilisticAtlasSurface"); ProbabilisticAtlasFile* paf = brainSet->getProbabilisticAtlasSurfaceFile(); if (onlyIfSelected) { if (paf->getNumberOfColumns() <= 0) { return; } if (brainSet->isASurfaceOverlayForAnySurface( BrainModelSurfaceOverlay::OVERLAY_PROBABILISTIC_ATLAS) == false) { return; } } sc.addSceneInfo(SceneFile::SceneInfo("surf-prob-atlas-displayType", displayType)); sc.addSceneInfo(SceneFile::SceneInfo("surf-thresholdDisplayTypeRatio", thresholdDisplayTypeRatio)); sc.addSceneInfo(SceneFile::SceneInfo("surf-treatQuestColorAsUnassigned", treatQuestColorAsUnassigned)); const int numChannels = std::min(paf->getNumberOfColumns(), static_cast(channelSelected.size())); for (int i = 0; i < numChannels; i++) { sc.addSceneInfo(SceneFile::SceneInfo("surf-channelSelected", paf->getColumnName(i), channelSelected[i])); } const int numNames = std::min(paf->getNumberOfPaintNames(), static_cast(areaSelected.size())); for (int i = 0; i < numNames; i++) { sc.addSceneInfo(SceneFile::SceneInfo("surf-areaSelected", paf->getPaintNameFromIndex(i), areaSelected[i])); } sc.addSceneInfo(SceneFile::SceneInfo("surf-applySelectionToLeftAndRightStructuresFlag", applySelectionToLeftAndRightStructuresFlag)); } break; case PROBABILISTIC_TYPE_VOLUME: { if (onlyIfSelected) { if (brainSet->getNumberOfVolumeProbAtlasFiles() <= 0) { return; } BrainModelVolumeVoxelColoring* bmvvc = brainSet->getVoxelColoring(); if (bmvvc->isUnderlayOrOverlay( BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_PROB_ATLAS) == false) { return; } } sc.setName("DisplaySettingsProbabilisticAtlasVolume"); sc.addSceneInfo(SceneFile::SceneInfo("vol-prob-atlas-displayType", displayType)); sc.addSceneInfo(SceneFile::SceneInfo("vol-thresholdDisplayTypeRatio", thresholdDisplayTypeRatio)); sc.addSceneInfo(SceneFile::SceneInfo("vol-treatQuestColorAsUnassigned", treatQuestColorAsUnassigned)); const int numChannels = std::min(brainSet->getNumberOfVolumeProbAtlasFiles(), static_cast(channelSelected.size())); bool duplicateVolumeLabelsFlag = false; for (int i = 0; i < numChannels; i++) { const VolumeFile* vf = brainSet->getVolumeProbAtlasFile(i); for (int j = 0; j < i; j++) { const VolumeFile* vfj = brainSet->getVolumeProbAtlasFile(j); if (vf->getDescriptiveLabel() == vfj->getDescriptiveLabel()) { duplicateVolumeLabelsFlag = true; } } sc.addSceneInfo(SceneFile::SceneInfo("vol-channelSelected", vf->getDescriptiveLabel(), channelSelected[i])); } if (duplicateVolumeLabelsFlag) { errorMessage += "The probabilistic atlas volumes have one or more " "identical labels. Each probabilistic volume must " "have a unqiue label."; } int numNames = 0; BrainModelVolume* bmv = brainSet->getBrainModelVolume(); if (bmv != NULL) { if (brainSet->getNumberOfVolumeProbAtlasFiles() > 0) { const VolumeFile* vf = brainSet->getVolumeProbAtlasFile(0); numNames = vf->getNumberOfRegionNames(); numNames = std::min(numNames, static_cast(areaSelected.size())); for (int i = 0; i < numNames; i++) { sc.addSceneInfo(SceneFile::SceneInfo("vol-areaSelected", vf->getRegionNameFromIndex(i), areaSelected[i])); } } } } break; } scene.addSceneClass(sc); } caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsPaint.h0000664000175000017500000000567211572067322024212 0ustar michaelmichael#ifndef __DISPLAY_SETTINGS_PAINT_H__ #define __DISPLAY_SETTINGS_PAINT_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "DisplaySettingsNodeAttributeFile.h" /// DisplaySettingsPaint is a class that maintains parameters for controlling /// the display of paint data files. class DisplaySettingsPaint : public DisplaySettingsNodeAttributeFile { public: /// Constructor DisplaySettingsPaint(BrainSet* bs); /// Destructor ~DisplaySettingsPaint(); /// Reinitialize all display settings void reset(); /// Update any selections due to changes in loaded paint file void update(); /// get the selected medial wall override column int getMedialWallOverrideColumn() const { return medialWallOverrideColumn; } /// set the medial wall override column void setMedialWallOverrideColumn(const int col) { medialWallOverrideColumn = col; } /// get the medial wall override column enabled bool getMedialWallOverrideColumnEnabled() const { return medialWallOverrideEnabled; } /// set the medial wall override column enabled void setMedialWallOverrideColumnEnabled(const bool b) { medialWallOverrideEnabled = b; } /// apply a scene (set display settings) virtual void showScene(const SceneFile::Scene& scene, QString& errorMessage) ; /// create a scene (read display settings) virtual void saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& errorMessage); /// get the geography blending float getGeographyBlending() const { return geographyBlending; } /// set the geography blending void setGeographyBlending(const float gb) { geographyBlending = gb; } private: /// geography blending float geographyBlending; /// selected medial wall override column int medialWallOverrideColumn; /// medial wall override column enabled bool medialWallOverrideEnabled; }; #endif // __DISPLAY_SETTINGS_PAINT_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsPaint.cxx0000664000175000017500000001166311572067322024562 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelSurfaceNodeColoring.h" #include "BrainSet.h" #include "DisplaySettingsPaint.h" #include "PaintFile.h" /** * The constructor. */ DisplaySettingsPaint::DisplaySettingsPaint(BrainSet* bs) : DisplaySettingsNodeAttributeFile(bs, bs->getPaintFile(), NULL, BrainModelSurfaceOverlay::OVERLAY_PAINT, true, false) { medialWallOverrideColumn = -1; medialWallOverrideEnabled = false; geographyBlending = 0.6; reset(); } /** * The destructor. */ DisplaySettingsPaint::~DisplaySettingsPaint() { } /** * Reinitialize all display settings. */ void DisplaySettingsPaint::reset() { DisplaySettingsNodeAttributeFile::reset(); } /** * Update any selections du to changes in loaded paint file. */ void DisplaySettingsPaint::update() { DisplaySettingsNodeAttributeFile::update(); updateSelectedColumnIndex(brainSet->getPaintFile(), medialWallOverrideColumn); } static const QString paintColumnID("paint-column"); static const QString paintMedWallColumnID("paint-med-wall-column"); /** * apply a scene (set display settings). */ void DisplaySettingsPaint::showScene(const SceneFile::Scene& scene, QString& errorMessage) { DisplaySettingsNodeAttributeFile::showScene(scene, errorMessage); PaintFile* pf = brainSet->getPaintFile(); const int numClasses = scene.getNumberOfSceneClasses(); for (int nc = 0; nc < numClasses; nc++) { const SceneFile::SceneClass* sc = scene.getSceneClass(nc); if (sc->getName() == "DisplaySettingsPaint") { showSceneSelectedColumns(*sc, "Paint File", paintColumnID, "", errorMessage); const int num = sc->getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc->getSceneInfo(i); const QString infoName = si->getName(); if (infoName == "medialWallOverrideEnabled") { si->getValue(medialWallOverrideEnabled); } else if (infoName == "geographyBlending") { si->getValue(geographyBlending); } else if (infoName == paintMedWallColumnID) { const QString columnName = si->getValueAsString(); for (int i = 0; i < pf->getNumberOfColumns(); i++) { if (columnName == pf->getColumnName(i)) { medialWallOverrideColumn = i; break; } } } } } } } /** * create a scene (read display settings). */ void DisplaySettingsPaint::saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& errorMessage) { DisplaySettingsNodeAttributeFile::saveScene(scene, onlyIfSelected, errorMessage); PaintFile* pf = brainSet->getPaintFile(); if (onlyIfSelected) { if (pf->getNumberOfColumns() <= 0) { return; } if (brainSet->isASurfaceOverlayForAnySurface( BrainModelSurfaceOverlay::OVERLAY_PAINT) == false) { return; } } SceneFile::SceneClass sc("DisplaySettingsPaint"); saveSceneSelectedColumns(sc); sc.addSceneInfo(SceneFile::SceneInfo("medialWallOverrideEnabled", medialWallOverrideEnabled)); sc.addSceneInfo(SceneFile::SceneInfo("geographyBlending", geographyBlending)); if ((medialWallOverrideColumn >= 0) && (medialWallOverrideColumn < pf->getNumberOfColumns())) { sc.addSceneInfo(SceneFile::SceneInfo(paintMedWallColumnID, pf->getColumnName(medialWallOverrideColumn))); } scene.addSceneClass(sc); } caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsNodeAttributeFile.h0000664000175000017500000001450011572067322026476 0ustar michaelmichael #ifndef __DISPLAY_SETTINGS_NODE_ATTRIBUTE_FILE_H__ #define __DISPLAY_SETTINGS_NODE_ATTRIBUTE_FILE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelSurfaceOverlay.h" #include "DisplaySettings.h" #include "SceneFile.h" class GiftiNodeDataFile; class NodeAttributeFile; /// class for node attribute file display settings class DisplaySettingsNodeAttributeFile : public DisplaySettings { public: // constructor DisplaySettingsNodeAttributeFile(BrainSet* bs, GiftiNodeDataFile* gafIn, NodeAttributeFile* nafIn, const BrainModelSurfaceOverlay::OVERLAY_SELECTIONS overlayTypeIn, const bool allowSurfaceUniqueColumnSelectionFlagIn, const bool thresholdColumnValidFlagIn); // destructor ~DisplaySettingsNodeAttributeFile(); /// reinitialize all display settings (be sure to call this from child) virtual void reset(); /// update any selections due to changes with loaded data files (be sure to call from child) virtual void update(); /// for node attribute files - all column selections for each surface are the same virtual bool columnSelectionsAreTheSame(const int bm1, const int bm2) const; /// get column selected for display int getSelectedDisplayColumn(const int modelNumber, const int overlayNumber) const; /// set column for display void setSelectedDisplayColumn(const int modelNumber, const int overlayNumber, const int columnNumber); /// get column selected for thresholding int getSelectedThresholdColumn(const int modelNumber, const int overlayNumber) const; /// set column for thresholding void setSelectedThresholdColumn(const int modelNumber, const int overlayNumber, const int columnNumber); /// get apply to left and right structures flag bool getApplySelectionToLeftAndRightStructuresFlag() const { return applySelectionToLeftAndRightStructuresFlag; } /// set apply to left and right structures flag void setApplySelectionToLeftAndRightStructuresFlag(const bool b) { applySelectionToLeftAndRightStructuresFlag = b; } /// for node attribute files - all column selections for each surface are the same //virtual bool displayColumnSelectionsAreTheSame(const int bm1, const int bm2) const; /// for node attribute files - all column selections for each surface are the same //virtual bool thresholdColumnSelectionsAreTheSame(const int bm1, const int bm2) const; // get flags to find out if any columns are selected as one of the overlays void getSelectedColumnFlags(const int brainModelIndex, std::vector& selectedColumnFlagsOut) const; // Get first selected column that is an overlay for the brain model (-1 if none) int getFirstSelectedColumnForBrainModel(const int brainModelIndex) const; /// apply a scene (set display settings) virtual void showScene(const SceneFile::Scene& scene, QString& errorMessage); /// create a scene (read display settings) virtual void saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& errorMessage); protected: /// get the number of columns for the file int getFileNumberOfColumns() const; /// get the names for file columns void getFileColumnNames(std::vector& columnNames) const; /// save scene for selected columns void saveSceneSelectedColumns(SceneFile::SceneClass& sc); /// show scene for selected columns void showSceneSelectedColumns(const SceneFile::SceneClass& sc, const QString& fileTypeName, const QString& legacyDisplayElementName, const QString& legacyThresholdElmentName, QString& errorMessage); /// Set the default value for selected column of any new surfaces void updateSelectedColumnIndices(std::vector& selCol); /// get the index for column selection int getColumnSelectionIndex(const int modelIndex, const int overlayNumber) const; private: /// the selected display column std::vector displayColumn; /// the threshold column std::vector thresholdColumn; /// gifti node attribute file for which this is setting the settings GiftiNodeDataFile* gaf; /// node attribute file for which this is setting the settings NodeAttributeFile* naf; /// type of overlay for this data type const BrainModelSurfaceOverlay::OVERLAY_SELECTIONS overlayType; /// threshold column is valid const bool thresholdColumnValidFlag; /// allow each surface to have its own column selection const bool allowSurfaceUniqueColumnSelectionFlag; /// apply coloring with corresponding structures bool applySelectionToLeftAndRightStructuresFlag; }; #endif // __DISPLAY_SETTINGS_NODE_ATTRIBUTE_FILE_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsNodeAttributeFile.cxx0000664000175000017500000010476711572067322027070 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurface.h" #include "BrainSet.h" #include "CoordinateFile.h" #include "DisplaySettingsNodeAttributeFile.h" #include "FileUtilities.h" #include "GiftiNodeDataFile.h" #include "NodeAttributeFile.h" // // Name of scene element // static const QString xmlOldDisplayElementName("ds-display-column"); static const QString xmlOldThresholdElementName("ds-display-column"); static const QString xmlDisplayElementName("DisplaySettingsDisplayColumn"); static const QString xmlThresholdElementName("DisplaySettingsThresholdColumn"); static const QString xmlNumberOfOverlaysName("DisplaySettingsNumberOfOverlays"); /** * constructor. */ DisplaySettingsNodeAttributeFile::DisplaySettingsNodeAttributeFile( BrainSet* bs, GiftiNodeDataFile* gafIn, NodeAttributeFile* nafIn, const BrainModelSurfaceOverlay::OVERLAY_SELECTIONS overlayTypeIn, const bool allowSurfaceUniqueColumnSelectionFlagIn, const bool thresholdColumnValidFlagIn) : DisplaySettings(bs), gaf(gafIn), naf(nafIn), overlayType(overlayTypeIn), thresholdColumnValidFlag(thresholdColumnValidFlagIn), allowSurfaceUniqueColumnSelectionFlag(allowSurfaceUniqueColumnSelectionFlagIn) { applySelectionToLeftAndRightStructuresFlag = false; } /** * destructor. */ DisplaySettingsNodeAttributeFile::~DisplaySettingsNodeAttributeFile() { } /** * reinitialize all display settings (be sure to call this from child). */ void DisplaySettingsNodeAttributeFile::reset() { displayColumn.clear(); thresholdColumn.clear(); } /** * update any selections due to changes with loaded data files (be sure to call from child). */ void DisplaySettingsNodeAttributeFile::update() { updateSelectedColumnIndices(displayColumn); updateSelectedColumnIndices(thresholdColumn); } /** * Set the default value for selected column of any new surfaces. */ void DisplaySettingsNodeAttributeFile::updateSelectedColumnIndices(std::vector& selCol) { if (allowSurfaceUniqueColumnSelectionFlag) { const int numCols = getFileNumberOfColumns(); const int numOverlays = brainSet->getNumberOfSurfaceOverlays(); std::vector defValue(numOverlays, 0); // // Determine default value for any new surfaces // const int numModels = brainSet->getNumberOfBrainModels(); if (selCol.empty() == false) { //defValue = selCol[0]; const int modelNum = brainSet->getFirstBrainModelSurfaceIndex(); if ((modelNum >= 0) && (modelNum < static_cast(selCol.size()))) { for (int i = 0; i < numOverlays; i++) { defValue[i] = selCol[getColumnSelectionIndex(modelNum, i)]; } } } // // Limit default columns to valid columns // for (int i = 0; i < numOverlays; i++) { if (defValue[i] >= numCols) { defValue[i] = 0; } else if (defValue[i] < 0) { if (numCols > 0) { defValue[i] = 0; } } } // // Resize to number of brain models and overlays // const int oldNumModels = selCol.size() / numOverlays; selCol.resize(numModels * numOverlays, 0); for (int i = oldNumModels; i < numModels; i++) { for (int j = 0; j < numOverlays; j++) { selCol[getColumnSelectionIndex(i, j)] = defValue[j]; } } // // Reset column indices for any surfaces that may have been deleted // for (int i = 0; i < numModels; i++) { for (int j = 0; j < numOverlays; j++) { if (selCol[getColumnSelectionIndex(i, j)] >= numCols) { selCol[getColumnSelectionIndex(i, j)] = defValue[j]; } else if (selCol[getColumnSelectionIndex(i, j)] < 0) { selCol[getColumnSelectionIndex(i, j)] = defValue[j]; } } } } else { if (selCol.empty()) { selCol.resize(1, 0); } } } /** * for node attribute files - all column selections for each surface are the same. */ bool DisplaySettingsNodeAttributeFile::columnSelectionsAreTheSame(const int bm1, const int bm2) const { const int numOverlays = brainSet->getNumberOfSurfaceOverlays(); for (int j = 0; j < numOverlays; j++) { if (displayColumn[getColumnSelectionIndex(bm1, j)] != displayColumn[getColumnSelectionIndex(bm2, j)]) { return false; } if (thresholdColumn[getColumnSelectionIndex(bm1, j)] != thresholdColumn[getColumnSelectionIndex(bm2, j)]) { return false; } } return true; } /** * get column selected for display. */ int DisplaySettingsNodeAttributeFile::getSelectedDisplayColumn(const int modelNumber, const int overlayNumber) const { if (displayColumn.empty()) { return -1; } if (allowSurfaceUniqueColumnSelectionFlag) { int model = modelNumber; if (model < 0) { model = 0; } return displayColumn[getColumnSelectionIndex(model, overlayNumber)]; } else { return displayColumn[0]; } } /** * set column for display. */ void DisplaySettingsNodeAttributeFile::setSelectedDisplayColumn(const int modelNumber, const int overlayNumber, const int columnNumber) { const int numOverlays = brainSet->getNumberOfSurfaceOverlays(); if (allowSurfaceUniqueColumnSelectionFlag) { const int numCols = getFileNumberOfColumns(); std::vector columnNames; getFileColumnNames(columnNames); bool madeSelectionsLeftRightFlag = false; if (applySelectionToLeftAndRightStructuresFlag) { if ((columnNumber >= 0) && (columnNumber < numCols)) { int leftCol = -1; int rightCol = -1; QString name = columnNames[columnNumber].toLower().trimmed(); if (name.indexOf("left") >= 0) { leftCol = columnNumber; const QString rightName = name.replace("left", "right"); for (int i = 0; i < numCols; i++) { if (columnNames[i].toLower().trimmed() == rightName) { rightCol = i; break; } } madeSelectionsLeftRightFlag = true; } else if (name.indexOf("right") >= 0) { rightCol = columnNumber; const QString leftName = name.replace("right", "left"); for (int i = 0; i < numCols; i++) { if (columnNames[i].toLower().trimmed() == leftName) { leftCol = i; break; } } madeSelectionsLeftRightFlag = true; } for (int i = 0; i < brainSet->getNumberOfBrainModels(); i++) { const BrainModelSurface* bms = brainSet->getBrainModelSurface(i); if (bms != NULL) { switch (bms->getStructure().getType()) { case Structure::STRUCTURE_TYPE_CORTEX_LEFT: if (leftCol >= 0) { if (overlayNumber < 0) { for (int nn = 0; nn < numOverlays; nn++) { displayColumn[getColumnSelectionIndex(i, nn)] = leftCol; } } else { displayColumn[getColumnSelectionIndex(i, overlayNumber)] = leftCol; } } break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT: if (rightCol >= 0) { if (overlayNumber < 0) { for (int nn = 0; nn < numOverlays; nn++) { displayColumn[getColumnSelectionIndex(i, nn)] = rightCol; } } else { displayColumn[getColumnSelectionIndex(i, overlayNumber)] = rightCol; } } break; case Structure::STRUCTURE_TYPE_CORTEX_BOTH: break; case Structure::STRUCTURE_TYPE_CEREBELLUM: break; case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_LEFT: break; case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_RIGHT: break; case Structure::STRUCTURE_TYPE_CORTEX_LEFT_OR_CEREBELLUM: break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT_OR_CEREBELLUM: break; case Structure::STRUCTURE_TYPE_CEREBRUM_CEREBELLUM: case Structure::STRUCTURE_TYPE_SUBCORTICAL: case Structure::STRUCTURE_TYPE_ALL: case Structure::STRUCTURE_TYPE_INVALID: break; } } } } } if (madeSelectionsLeftRightFlag == false) { if (modelNumber < 0) { for (int i = 0; i < brainSet->getNumberOfBrainModels(); i++) { if (overlayNumber < 0) { for (int nn = 0; nn < numOverlays; nn++) { displayColumn[getColumnSelectionIndex(i, nn)] = columnNumber; } } else { displayColumn[getColumnSelectionIndex(i, overlayNumber)] = columnNumber; } } } else { if (overlayNumber < 0) { for (int nn = 0; nn < numOverlays; nn++) { displayColumn[getColumnSelectionIndex(modelNumber, nn)] = columnNumber; } } else { displayColumn[getColumnSelectionIndex(modelNumber, overlayNumber)] = columnNumber; } } } } else { displayColumn[0] = columnNumber; } } /** * get column selected for thresholding. */ int DisplaySettingsNodeAttributeFile::getSelectedThresholdColumn(const int modelNumber, const int overlayNumber) const { if (allowSurfaceUniqueColumnSelectionFlag) { if (thresholdColumn.empty()) { return -1; } int model = modelNumber; if (model < 0) { model = 0; } return thresholdColumn[getColumnSelectionIndex(model, overlayNumber)]; } else { return thresholdColumn[0]; } } /** * set column for thresholding. */ void DisplaySettingsNodeAttributeFile::setSelectedThresholdColumn(const int modelNumber, const int overlayNumber, const int columnNumber) { const int numOverlays = brainSet->getNumberOfSurfaceOverlays(); if (allowSurfaceUniqueColumnSelectionFlag) { const int numCols = getFileNumberOfColumns(); std::vector columnNames; getFileColumnNames(columnNames); bool madeSelectionsLeftRightFlag = false; if (applySelectionToLeftAndRightStructuresFlag) { if ((columnNumber >= 0) && (columnNumber < numCols)) { int leftCol = -1; int rightCol = -1; QString name = columnNames[columnNumber].toLower().trimmed(); if (name.indexOf("left") >= 0) { leftCol = columnNumber; const QString rightName = name.replace("left", "right"); for (int i = 0; i < numCols; i++) { if (columnNames[i].toLower().trimmed() == rightName) { rightCol = i; break; } } madeSelectionsLeftRightFlag = true; } else if (name.indexOf("right") >= 0) { rightCol = columnNumber; const QString leftName = name.replace("right", "left"); for (int i = 0; i < numCols; i++) { if (columnNames[i].toLower().trimmed() == leftName) { leftCol = i; break; } } madeSelectionsLeftRightFlag = true; } for (int i = 0; i < brainSet->getNumberOfBrainModels(); i++) { const BrainModelSurface* bms = brainSet->getBrainModelSurface(i); if (bms != NULL) { switch (bms->getStructure().getType()) { case Structure::STRUCTURE_TYPE_CORTEX_LEFT: if (leftCol >= 0) { if (overlayNumber < 0) { for (int nn = 0; nn < numOverlays; nn++) { thresholdColumn[getColumnSelectionIndex(i, nn)] = leftCol; } } else { thresholdColumn[getColumnSelectionIndex(i, overlayNumber)] = leftCol; } } break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT: if (rightCol >= 0) { if (overlayNumber < 0) { for (int nn = 0; nn < numOverlays; nn++) { thresholdColumn[getColumnSelectionIndex(i, nn)] = rightCol; } } else { thresholdColumn[getColumnSelectionIndex(i, overlayNumber)] = rightCol; } } break; case Structure::STRUCTURE_TYPE_CORTEX_BOTH: break; case Structure::STRUCTURE_TYPE_CEREBELLUM: break; case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_LEFT: break; case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_RIGHT: break; case Structure::STRUCTURE_TYPE_CORTEX_LEFT_OR_CEREBELLUM: break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT_OR_CEREBELLUM: break; case Structure::STRUCTURE_TYPE_CEREBRUM_CEREBELLUM: case Structure::STRUCTURE_TYPE_SUBCORTICAL: case Structure::STRUCTURE_TYPE_ALL: case Structure::STRUCTURE_TYPE_INVALID: break; } } } } } if (madeSelectionsLeftRightFlag == false) { if (modelNumber < 0) { for (int i = 0; i < brainSet->getNumberOfBrainModels(); i++) { if (overlayNumber < 0) { for (int nn = 0; nn < numOverlays; nn++) { thresholdColumn[getColumnSelectionIndex(i, nn)] = columnNumber; } } else { thresholdColumn[getColumnSelectionIndex(i, overlayNumber)] = columnNumber; } } } else { if (overlayNumber < 0) { for (int nn = 0; nn < numOverlays; nn++) { thresholdColumn[getColumnSelectionIndex(modelNumber, nn)] = columnNumber; } } else { thresholdColumn[getColumnSelectionIndex(modelNumber, overlayNumber)] = columnNumber; } } } } else { thresholdColumn[0] = columnNumber; } } /** * get the number of columns for the file. */ int DisplaySettingsNodeAttributeFile::getFileNumberOfColumns() const { int numCols = 0; if (gaf != NULL) { numCols = gaf->getNumberOfColumns(); } if (naf != NULL) { numCols = naf->getNumberOfColumns(); } return numCols; } /** * get the names for file columns. */ void DisplaySettingsNodeAttributeFile::getFileColumnNames(std::vector& columnNames) const { columnNames.clear(); if (gaf != NULL) { const int numCols = gaf->getNumberOfColumns(); for (int i = 0; i < numCols; i++) { columnNames.push_back(gaf->getColumnName(i)); } } else if (naf != NULL) { const int numCols = naf->getNumberOfColumns(); for (int i = 0; i < numCols; i++) { columnNames.push_back(naf->getColumnName(i)); } } } /** * save scene for selected columns. */ void DisplaySettingsNodeAttributeFile::saveSceneSelectedColumns(SceneFile::SceneClass& sc) { // // Names of file columns // std::vector columnNames; getFileColumnNames(columnNames); if (columnNames.empty() == false) { // // Is each surface allowed its own column selection // if (allowSurfaceUniqueColumnSelectionFlag) { // // Check each brain model // const int numBrainModels = brainSet->getNumberOfBrainModels(); const int numOverlays = brainSet->getNumberOfSurfaceOverlays(); // // Add the number of overlays // SceneFile::SceneInfo sin(xmlNumberOfOverlaysName, numOverlays); sc.addSceneInfo(sin); // // Process each brain model // bool didDefaultFlag = false; for (int n = 0; n < numBrainModels; n++) { // // Is this a surface ? // const BrainModelSurface* bms = brainSet->getBrainModelSurface(n); if (bms != NULL) { // // Setup the default values // for (int j = 0; j < numOverlays; j++) { const int overlayNumber = j; const int colIndex = getColumnSelectionIndex(n, j); const int dispCol = displayColumn[colIndex]; const QString displayColumnName(columnNames[dispCol]); const int threshCol = thresholdColumn[colIndex]; QString thresholdColumnName; if (thresholdColumnValidFlag) { thresholdColumnName = columnNames[threshCol]; } if (displayColumnName.isEmpty() == false) { // // Do the Default first // if (didDefaultFlag == false) { SceneFile::SceneInfo si(xmlDisplayElementName, SceneFile::SceneInfo::getDefaultSurfacesName(), overlayNumber, displayColumnName); sc.addSceneInfo(si); if (thresholdColumnValidFlag) { SceneFile::SceneInfo sit(xmlThresholdElementName, SceneFile::SceneInfo::getDefaultSurfacesName(), overlayNumber, thresholdColumnName); sc.addSceneInfo(sit); } } } } didDefaultFlag = true; } // // // Process each overlay for the brain model // for (int j = 0; j < numOverlays; j++) { const int overlayNumber = j; // // Is this a surface ? // const BrainModelSurface* bms = brainSet->getBrainModelSurface(n); if (bms != NULL) { const QString displayColumnName( columnNames[displayColumn[getColumnSelectionIndex(n, j)]]); QString thresholdColumnName; if (thresholdColumnValidFlag) { thresholdColumnName = columnNames[thresholdColumn[getColumnSelectionIndex(n, j)]]; } if (displayColumnName.isEmpty() == false) { // // Get name of coordinate file // const CoordinateFile* cf = bms->getCoordinateFile(); QString surfaceName = FileUtilities::basename(cf->getFileName()); // // Create the scene info for this model // SceneFile::SceneInfo si(xmlDisplayElementName, surfaceName, overlayNumber, displayColumnName); sc.addSceneInfo(si); if (thresholdColumnValidFlag) { // // Create the scene info for this model // SceneFile::SceneInfo si(xmlThresholdElementName, surfaceName, overlayNumber, thresholdColumnName); sc.addSceneInfo(si); } } } } } } else { if ((displayColumn[0] >= 0) && (displayColumn[0] < getFileNumberOfColumns())) { sc.addSceneInfo(SceneFile::SceneInfo(xmlDisplayElementName, columnNames[displayColumn[0]])); } if (thresholdColumnValidFlag) { if ((thresholdColumn[0] >= 0) && (thresholdColumn[0] < getFileNumberOfColumns())) { sc.addSceneInfo(SceneFile::SceneInfo(xmlThresholdElementName, columnNames[thresholdColumn[0]])); } } } } sc.addSceneInfo(SceneFile::SceneInfo("applySelectionToLeftAndRightStructuresFlag", applySelectionToLeftAndRightStructuresFlag)); } /** * show scene for selected columns. */ void DisplaySettingsNodeAttributeFile::showSceneSelectedColumns(const SceneFile::SceneClass& sc, const QString& fileTypeName, const QString& legacyDisplayElementName, const QString& legacyThresholdElmentName, QString& errorMessage) { // // Names of file columns // std::vector columnNames; getFileColumnNames(columnNames); const int numColumns = static_cast(columnNames.size()); const int totalNumberOfOverlays = brainSet->getNumberOfSurfaceOverlays(); int numberOfOverlaysInScene = 1; if (allowSurfaceUniqueColumnSelectionFlag) { const int num = sc.getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc.getSceneInfo(i); const QString infoName = si->getName(); bool dispFlag = false; bool dispLegacyFlag = false; bool threshFlag = false; bool threshLegacyFlag = false; if (infoName == xmlNumberOfOverlaysName) { numberOfOverlaysInScene = si->getValueAsInt(); if (numberOfOverlaysInScene > totalNumberOfOverlays) { errorMessage = "The scene contains more overlays than Caret supports. " "Some data may not be displayed properly."; } } else if ((infoName == xmlDisplayElementName) || (infoName == xmlOldDisplayElementName)) { dispFlag = true; } else if (infoName == legacyDisplayElementName) { dispLegacyFlag = true; } else if ((infoName == xmlThresholdElementName) || (infoName == xmlOldThresholdElementName)) { threshFlag = true; } else if (infoName == legacyThresholdElmentName) { threshLegacyFlag = true; } if (dispFlag || dispLegacyFlag || threshFlag || threshLegacyFlag) { // // Handle all surfaces or a specific surface // const QString surfaceName = si->getModelName(); int startSurface = 0; int endSurface = brainSet->getNumberOfBrainModels(); // // Old scenes (before separate overlays) should set all overlays // int overlayStartNumber = 0; int overlayEndNumber = totalNumberOfOverlays; const int overlayNumberInSceneInfo = si->getOverlayNumber(); if (overlayNumberInSceneInfo >= 0) { overlayStartNumber = std::min(overlayNumberInSceneInfo, totalNumberOfOverlays); overlayEndNumber = std::min(overlayNumberInSceneInfo + 1, totalNumberOfOverlays); } // // Is this NOT the default surface // if (surfaceName != SceneFile::SceneInfo::getDefaultSurfacesName()) { endSurface = 0; const BrainModelSurface* bms = brainSet->getBrainModelSurfaceWithCoordinateFileName(surfaceName); if (bms != NULL) { startSurface = brainSet->getBrainModelIndex(bms); if (startSurface >= 0) { endSurface = startSurface + 1; } } else { QString msg("Surface named \""); msg.append(surfaceName); msg.append("\" not found.\n"); errorMessage.append(msg); } } // // Get the index of the data column // int columnNum = -1; const QString dataColumnName = si->getValueAsString(); for (int m = 0; m < numColumns; m++) { if (columnNames[m] == dataColumnName) { columnNum = m; break; } } if (columnNum >= 0) { // // Set the selected column // if (dispFlag || dispLegacyFlag) { //const int lastIndex = std::min(endSurface, // static_cast(displayColumn.size())); for (int k = startSurface; k < endSurface; k++) { for (int m = overlayStartNumber; m < overlayEndNumber; m++) { setSelectedDisplayColumn(k, m, columnNum); //displayColumn[k] = columnNum; } } } else if (threshFlag || threshLegacyFlag) { //const int lastIndex = std::min(endSurface, // static_cast(thresholdColumn.size())); for (int k = startSurface; k < endSurface; k++) { for (int m = overlayStartNumber; m < overlayEndNumber; m++) { setSelectedThresholdColumn(k, m, columnNum); //thresholdColumn[k] = columnNum; } } } } else { QString msg(fileTypeName); msg.append(" column named \""); msg.append(dataColumnName); msg.append("\" not found.\n"); errorMessage.append(msg); } } } } else { const int num = sc.getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc.getSceneInfo(i); const QString infoName = si->getName(); bool dispFlag = false; bool dispLegacyFlag = false; bool threshFlag = false; bool threshLegacyFlag = false; if ((infoName == xmlDisplayElementName) || (infoName == xmlOldDisplayElementName)) { dispFlag = true; } else if (infoName == legacyDisplayElementName) { dispLegacyFlag = true; } else if ((infoName == xmlThresholdElementName) || (infoName == xmlOldThresholdElementName)) { threshFlag = true; } else if (infoName == legacyThresholdElmentName) { threshLegacyFlag = true; } if (dispFlag || dispLegacyFlag || threshFlag || threshLegacyFlag) { const QString colName = si->getValueAsString(); for (int j = 0; j < numColumns; j++) { if (colName == columnNames[j]) { if (dispFlag || dispLegacyFlag) { displayColumn[0] = j; } else if (threshFlag || threshLegacyFlag) { thresholdColumn[0] = j; } return; } } QString msg(fileTypeName); msg.append(" column named \""); msg.append(colName); msg.append("\" not found.\n"); errorMessage.append(msg); } } } const int num = sc.getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc.getSceneInfo(i); const QString infoName = si->getName(); if (infoName == "applySelectionToLeftAndRightStructuresFlag") { applySelectionToLeftAndRightStructuresFlag = si->getValueAsBool(); } } } /** * get the index for column selection. */ int DisplaySettingsNodeAttributeFile::getColumnSelectionIndex(const int modelIndex, const int overlayNumber) const { const int indx = (modelIndex * brainSet->getNumberOfSurfaceOverlays()) + overlayNumber; return indx; } /** * for node attribute files - all column selections for each surface are the same. */ /* bool DisplaySettingsNodeAttributeFile::displayColumnSelectionsAreTheSame(const int bm1, const int bm2) const { return (displayColumn[bm1] == displayColumn[bm2]); } */ /** * for node attribute files - all column selections for each surface are the same. */ /* bool DisplaySettingsNodeAttributeFile::thresholdColumnSelectionsAreTheSame(const int bm1, const int bm2) const { return (thresholdColumn[bm1] == thresholdColumn[bm2]); } */ /** * get flags to find out if any columns are selected as one of the overlays. */ void DisplaySettingsNodeAttributeFile::getSelectedColumnFlags(const int brainModelIndex, std::vector& selectedColumnFlagsOut) const { // // Clear the selected column flags // selectedColumnFlagsOut.resize(getFileNumberOfColumns()); std::fill(selectedColumnFlagsOut.begin(), selectedColumnFlagsOut.end(), false); for (int i = 0; i < brainSet->getNumberOfSurfaceOverlays(); i++) { const BrainModelSurfaceOverlay* bmsOverlay = brainSet->getSurfaceOverlay(i); if (bmsOverlay->getOverlay(brainModelIndex) == overlayType) { selectedColumnFlagsOut[getSelectedDisplayColumn(brainModelIndex, i)] = true; } } } /** * Get the selected column for the first brain model that is an overla of this type. */ /* int DisplaySettingsNodeAttributeFile::getPrioritySelectedColumn() const { for (int i = 0; i < brainSet->getNumberOfSurfaceOverlays(); i++) { const BrainModelSurfaceOverlay* bmsOverlay = brainSet->getSurfaceOverlay(i); if (bmsOverlay->getOverlay() == overlayType) { for (int j = 0; j < brainSet->getNumberOfBrainModels(); j++) { const int col = getSelectedDisplayColumn(j, i); if (col >= 0) { return col; } } } } return -1; } */ /** * Get first selected column that is an overlay for the brain model (-1 if none) */ int DisplaySettingsNodeAttributeFile::getFirstSelectedColumnForBrainModel(const int brainModelIndex) const { std::vector selectedColumnFlags; getSelectedColumnFlags(brainModelIndex, selectedColumnFlags); for (unsigned int i = 0; i < selectedColumnFlags.size(); i++) { if (selectedColumnFlags[i]) { return i; } } return -1; } /** * apply a scene (set display settings). */ void DisplaySettingsNodeAttributeFile::showScene(const SceneFile::Scene& /*scene*/, QString& /*errorMessage*/) { applySelectionToLeftAndRightStructuresFlag = false; } /** * create a scene (read display settings). */ void DisplaySettingsNodeAttributeFile::saveScene(SceneFile::Scene& /*scene*/, const bool /*onlyIfSelected*/, QString& /*errorMessage*/) { } caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsModels.h0000664000175000017500000001035411572067322024353 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __DISPLAY_SETTINGS_MODELS_H__ #define __DISPLAY_SETTINGS_MODELS_H__ #include "DisplaySettings.h" /// Display settings for models class DisplaySettingsModels : public DisplaySettings { public: /// Constructor DisplaySettingsModels(BrainSet* bsIn); /// Destructor ~DisplaySettingsModels(); /// reinitialize all display settings void reset(); /// update any selections due to changes with loaded data files void update(); /// get line width float getLineWidth() const { return lineWidth; } /// set line width void setLineWidth(const float lw) { lineWidth = lw; } /// get vertex size float getVertexSize() const { return vertexSize; } /// set vertex size void setVertexSize(const float vs) { vertexSize = vs; } /// get light enabled for vertices bool getLightVerticesEnabled() const { return lightVertices; } /// set light enabled for vertices void setLightVerticesEnabled(const bool le) { lightVertices = le; } /// get light enabled for lines bool getLightLinesEnabled() const { return lightLines; } /// set light enabled for lines void setLightLinesEnabled(const bool le) { lightLines = le; } /// get light enabled for polygons bool getLightPolygonsEnabled() const { return lightPolygons; } /// set light enabled for polygons void setLightPolygonsEnabled(const bool le) { lightPolygons = le; } /// get the opacity float getOpacity() const { return opacity; } /// set the opacity void setOpacity(const float op) { opacity = op; } /// get show polygons bool getShowPolygons() const { return showPolygons; } /// set show polygons void setShowPolygons(const bool b) { showPolygons = b; } /// get show triangles bool getShowTriangles() const { return showTriangles; } /// set show triangles void setShowTriangles(const bool b) { showTriangles = b; } /// get show lines bool getShowLines() const { return showLines; } /// set show lines void setShowLines(const bool b) { showLines = b; } /// get show vertices bool getShowVertices() const { return showVertices; } /// set show vertices void setShowVertices(const bool b) { showVertices = b; } /// apply a scene (set display settings) virtual void showScene(const SceneFile::Scene& scene, QString& errorMessage) ; /// create a scene (read display settings) virtual void saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& errorMessage); private: /// opacity float opacity; /// line width float lineWidth; /// vertex size float vertexSize; /// light enable for bool lightVertices; /// light enable for bool lightLines; /// light enable for bool lightPolygons; /// show polygons bool showPolygons; /// show triangles bool showTriangles; /// show lines bool showLines; /// show vertices bool showVertices; }; #endif // __DISPLAY_SETTINGS_MODELS_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsModels.cxx0000664000175000017500000001705211572067322024730 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainSet.h" #include "DisplaySettingsModels.h" #include "FileUtilities.h" #include "TransformationMatrixFile.h" #include "VtkModelFile.h" /** * Constructor. */ DisplaySettingsModels::DisplaySettingsModels(BrainSet* bsIn) : DisplaySettings(bsIn) { opacity = 1.0; lineWidth = 2.0; vertexSize = 2.0; lightLines = false; lightVertices = true; lightPolygons = true; showPolygons = true; showTriangles = true; showLines = true; showVertices = false; } /** * Destructor. */ DisplaySettingsModels::~DisplaySettingsModels() { } /** * reinitialize all display settings. */ void DisplaySettingsModels::reset() { } /** * update any selections due to changes with loaded data files. */ void DisplaySettingsModels::update() { } /** * apply a scene (set display settings). */ void DisplaySettingsModels::showScene(const SceneFile::Scene& scene, QString& errorMessage) { TransformationMatrixFile* tmf = brainSet->getTransformationMatrixFile(); const int numClasses = scene.getNumberOfSceneClasses(); for (int nc = 0; nc < numClasses; nc++) { const SceneFile::SceneClass* sc = scene.getSceneClass(nc); if (sc->getName() == "DisplaySettingsModels") { const int num = sc->getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc->getSceneInfo(i); const QString infoName = si->getName(); if ((infoName == "model-display-status") || (infoName == "model-xform")) { const int num = brainSet->getNumberOfVtkModelFiles(); const QString name = si->getModelName(); bool modelFound = false; for (int i = 0; i < num; i++) { VtkModelFile* vmf = brainSet->getVtkModelFile(i); if (name == FileUtilities::basename(vmf->getFileName())) { if (infoName == "model-display-status") { vmf->setDisplayFlag(si->getValueAsBool()); } else if (name == "model-xform") { TransformationMatrix* tm = tmf->getTransformationMatrixWithName(si->getValueAsString()); if (tm != NULL) { vmf->setAssociatedTransformationMatrix(tm); } else { QString msg("Unable to find transformation matrix \""); msg.append(si->getValueAsString()); msg.append("\" for use by VTK model \""); msg.append(name); msg.append("\"\n"); errorMessage.append(msg); } } modelFound = true; } } if (modelFound == false) { QString msg("Vtk Model \""); msg.append(name); msg.append("\" not found.\n"); errorMessage.append(msg); } } else if (infoName == "model-opacity") { si->getValue(opacity); } else if (infoName == "model-lineWidth") { si->getValue(lineWidth); } else if (infoName == "model-vertexSize") { si->getValue(vertexSize); } else if (infoName == "model-lightVertices") { si->getValue(lightVertices); } else if (infoName == "model-lightLines") { si->getValue(lightLines); } else if (infoName == "model-lightPolygons") { si->getValue(lightPolygons); } else if (infoName == "showPolygons") { si->getValue(showPolygons); } else if (infoName == "showTriangles") { si->getValue(showTriangles); } else if (infoName == "showLines") { si->getValue(showLines); } else if (infoName == "showVertices") { si->getValue(showVertices); } } } } } /** * create a scene (read display settings). */ void DisplaySettingsModels::saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& /*errorMessage*/) { const int num = brainSet->getNumberOfVtkModelFiles(); if (onlyIfSelected) { bool haveModelsOn = false; for (int i = 0; i < num; i++) { const VtkModelFile* vmf = brainSet->getVtkModelFile(i); if (vmf->getDisplayFlag()) { haveModelsOn = true; } } if (haveModelsOn == false) { return; } } TransformationMatrixFile* tmf = brainSet->getTransformationMatrixFile(); SceneFile::SceneClass sc("DisplaySettingsModels"); for (int i = 0; i < num; i++) { const VtkModelFile* vmf = brainSet->getVtkModelFile(i); sc.addSceneInfo(SceneFile::SceneInfo("model-display-status", FileUtilities::basename(vmf->getFileName()), vmf->getDisplayFlag())); const TransformationMatrix* tm = vmf->getAssociatedTransformationMatrix(); if (tmf->getMatrixIndex(tm) >= 0) { sc.addSceneInfo(SceneFile::SceneInfo("model-xform", FileUtilities::basename(vmf->getFileName()), tm->getMatrixName())); } } sc.addSceneInfo(SceneFile::SceneInfo("model-opacity", opacity)); sc.addSceneInfo(SceneFile::SceneInfo("model-lineWidth", lineWidth)); sc.addSceneInfo(SceneFile::SceneInfo("model-vertexSize", vertexSize)); sc.addSceneInfo(SceneFile::SceneInfo("model-lightVertices", lightVertices)); sc.addSceneInfo(SceneFile::SceneInfo("model-lightLines", lightLines)); sc.addSceneInfo(SceneFile::SceneInfo("model-lightPolygons", lightPolygons)); sc.addSceneInfo(SceneFile::SceneInfo("showPolygons", showPolygons)); sc.addSceneInfo(SceneFile::SceneInfo("showTriangles", showTriangles)); sc.addSceneInfo(SceneFile::SceneInfo("showLines", showLines)); sc.addSceneInfo(SceneFile::SceneInfo("showVertices", showVertices)); scene.addSceneClass(sc); } caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsMetric.h0000664000175000017500000002535311572067322024360 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_DISPLAY_SETTINGS_METRIC_H__ #define __VE_DISPLAY_SETTINGS_METRIC_H__ #include #include "DisplaySettingsNodeAttributeFile.h" class BrainModelSurface; class BrainSet; class VolumeFile; /// DisplaySettingsMetric is a class that maintains parameters for controlling /// the display of metric data files. class DisplaySettingsMetric : public DisplaySettingsNodeAttributeFile { public: /// Metric graphing enum METRIC_DATA_PLOT { METRIC_DATA_PLOT_OFF, METRIC_DATA_PLOT_NODE, METRIC_DATA_PLOT_NODE_AND_NEIGHBORS }; /// Metric scaling for color mapping enum METRIC_OVERLAY_SCALE { /// auto scale metric column min/max METRIC_OVERLAY_SCALE_AUTO, /// auto scale metric column percentage min/max METRIC_OVERLAY_SCALE_AUTO_PERCENTAGE, /// auto scale using a specified metric column min/max METRIC_OVERLAY_SCALE_AUTO_SPECIFIED_COLUMN, /// auto scale using selection functional volume min/max METRIC_OVERLAY_SCALE_AUTO_FUNC_VOLUME, /// auto scale using user entered min/max METRIC_OVERLAY_SCALE_USER }; /// Positive/Negative Display enum METRIC_DISPLAY_MODE { METRIC_DISPLAY_MODE_POSITIVE_AND_NEGATIVE, METRIC_DISPLAY_MODE_POSITIVE_ONLY, METRIC_DISPLAY_MODE_NEGATIVE_ONLY }; /// type of thresholding enum METRIC_THRESHOLDING_TYPE { METRIC_THRESHOLDING_TYPE_FILE_COLUMN, METRIC_THRESHOLDING_TYPE_FILE_COLUMN_AVERAGE, METRIC_THRESHOLDING_TYPE_USER_VALUES, }; /// Constructor DisplaySettingsMetric(BrainSet* bs); /// Destructor ~DisplaySettingsMetric(); /// Reinitialize all display settings void reset(); /// Update any selections due to changes in loaded metric file void update(); /// get the column number for the overlay scale specified column int getOverlayScaleSpecifiedColumnNumber() const { return overlayScaleSpecifiedColumnNumber; } /// set the column number for the overlay scale specified column void setOverlayScaleSpecifiedColumnNumber(const int col) { overlayScaleSpecifiedColumnNumber = col; } /// get the type of metric thresholding METRIC_THRESHOLDING_TYPE getMetricThresholdingType() const { return thresholdType; } /// set the type of metric thresholding void setMetricThresholdingType(const METRIC_THRESHOLDING_TYPE mtt) { thresholdType = mtt; } /// get the user thresholding values void getUserThresholdingValues(float& negThresh, float& posThresh) const; /// set the user thresholding values void setUserThresholdingValues(const float negThresh, const float posThresh); /// get selected overlay scale METRIC_OVERLAY_SCALE getSelectedOverlayScale() const { return overlayScale; } /// set selected overlay scale void setSelectedOverlayScale(const METRIC_OVERLAY_SCALE mos) { overlayScale = mos; } /// get the user scale minimum and maximum void getUserScaleMinMax(float& posMinValue, float& posMaxValue, float& negMinValue, float& negMaxValue) const; /// set the user scale minimum and maximum void setUserScaleMinMax(const float posMinValue, const float posMaxValue, const float negMinValue, const float negMaxValue); /// get display color bar bool getDisplayColorBar() const { return displayColorBar; } /// set display color bar void setDisplayColorBar(const bool dcb) { displayColorBar = dcb; } /// get interpolate colors flag bool getInterpolateColors() const { return interpolateColors; } /// set interpolate colors flag void setInterpolateColors(const int ic) { interpolateColors = ic; } /// get the display mode METRIC_DISPLAY_MODE getDisplayMode() const { return displayMode; } /// set the display mode void setDisplayMode(const METRIC_DISPLAY_MODE mdm) { displayMode = mdm; } /// get the selected palette index int getSelectedPaletteIndex() const { return paletteIndex; } /// set the selected palette index void setSelectedPaletteIndex(const int pi) { paletteIndex = pi; } /// get popup plot of metric data when node identified METRIC_DATA_PLOT getMDataPlotOnNodeID() const { return metricDataPlot; } /// set popup plot of metric data when node identified void setDataPlotOnNodeID(const METRIC_DATA_PLOT dp) { metricDataPlot = dp; } /// get manual data plot scaling bool getDataPlotManualScaling(float& minPlot, float& maxPlot) const; /// set manual data plot scaling void setDataPlotManualScaling(const bool b, const float minPlot, const float maxPlot); /// get show special color for thresholded nodes bool getShowSpecialColorForThresholdedNodes() const { return showSpecialColorForThresholdedNodes; } /// set show special color for thresholded nodes void setShowSpecialColorForThresholdedNodes(const bool b) { showSpecialColorForThresholdedNodes = b; } /// get special color for thresholded nodes void getSpecialColorsForThresholdedNodes(unsigned char negThreshColor[3], unsigned char posThreshColor[3]) const; /// apply a scene (set display settings) virtual void showScene(const SceneFile::Scene& scene, QString& errorMessage) ; /// create a scene (read display settings) virtual void saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& errorMessage); // get the display and threshold columns for palette (negative if invalid) void getMetricsForColoringAndPalette(int& displayColumnOut, int& thresholdColumnOut, float& negMaxValue, float& negMinValue, float& posMinValue, float& posMaxValue, const bool volumeFlag = false) const; /// get the auto scale percentage negative minimum float getAutoScalePercentageNegativeMinimum() const { return autoScalePercentageNegativeMinimum; } /// set the auto scale percentage negative minimum void setAutoScalePercentageNegativeMinimum(const float nm) { autoScalePercentageNegativeMinimum = nm; } /// get the auto scale percentage negative maximum float getAutoScalePercentageNegativeMaximum() const { return autoScalePercentageNegativeMaximum; } /// set the auto scale percentage negative maximum void setAutoScalePercentageNegativeMaximum(const float nm) { autoScalePercentageNegativeMaximum = nm; } /// get the auto scale percentage positive minimum float getAutoScalePercentagePositiveMinimum() const { return autoScalePercentagePositiveMinimum; } /// set the auto scale percentage positive minimum void setAutoScalePercentagePositiveMinimum(const float pm) { autoScalePercentagePositiveMinimum = pm; } /// get the auto scale percentage positive maximum float getAutoScalePercentagePositiveMaximum() const { return autoScalePercentagePositiveMaximum; } /// set the auto scale percentage positive maximum void setAutoScalePercentagePositiveMaximum(const float pm) { autoScalePercentagePositiveMaximum = pm; } private: /// metric thresholding type METRIC_THRESHOLDING_TYPE thresholdType; /// user negative threshold float userNegativeThreshold; /// user positive threshold float userPositiveThreshold; /// overlay scale METRIC_OVERLAY_SCALE overlayScale; /// user scale positive minimum value float userScalePositiveMinimum; /// user scale positive maximum float userScalePositiveMaximum; /// user scale negative minimum value float userScaleNegativeMinimum; /// user scale negative maximum float userScaleNegativeMaximum; /// interpolate colors bool interpolateColors; /// display metric color bar bool displayColorBar; /// selected palette index int paletteIndex; /// positive / negative display mode METRIC_DISPLAY_MODE displayMode; /// type of data plot METRIC_DATA_PLOT metricDataPlot; /// metric data plot manual scale bool metricDataPlotManualScaleFlag; /// metric data plot manual scale minimum float metricDataPlotManualScaleMinimum; /// metric data plot manual scale maximum float metricDataPlotManualScaleMaximum; /// show thresholded nodes in special color bool showSpecialColorForThresholdedNodes; /// column number for the overlay scale specified column int overlayScaleSpecifiedColumnNumber; /// auto scale percentage negative minimum float autoScalePercentageNegativeMinimum; /// auto scale percentage negative maximum float autoScalePercentageNegativeMaximum; /// auto scale percentage positive minimum float autoScalePercentagePositiveMinimum; /// auto scale percentage positive maximum float autoScalePercentagePositiveMaximum; }; #endif caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsMetric.cxx0000664000175000017500000005427311572067322024736 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelSurface.h" #include "BrainModelSurfaceNodeColoring.h" #include "BrainModelVolume.h" #include "BrainModelVolumeVoxelColoring.h" #include "BrainSet.h" #include "DisplaySettingsMetric.h" #include "MetricFile.h" #include "PaletteFile.h" /** * The constructor. */ DisplaySettingsMetric::DisplaySettingsMetric(BrainSet* bs) : DisplaySettingsNodeAttributeFile(bs, bs->getMetricFile(), NULL, BrainModelSurfaceOverlay::OVERLAY_METRIC, true, true) { reset(); } /** * The destructor. */ DisplaySettingsMetric::~DisplaySettingsMetric() { } /** * Reinitialize all display settings. */ void DisplaySettingsMetric::reset() { DisplaySettingsNodeAttributeFile::reset(); overlayScale = METRIC_OVERLAY_SCALE_AUTO; userScaleNegativeMaximum = -1.0; userScaleNegativeMinimum = 0.0; userScalePositiveMinimum = 0.0; userScalePositiveMaximum = 1.0; interpolateColors = false; displayMode = METRIC_DISPLAY_MODE_POSITIVE_AND_NEGATIVE; paletteIndex = 0; displayColorBar = false; metricDataPlot = METRIC_DATA_PLOT_OFF; metricDataPlotManualScaleFlag = false; metricDataPlotManualScaleMinimum = 0.0; metricDataPlotManualScaleMaximum = 1000.0; showSpecialColorForThresholdedNodes = false; userNegativeThreshold = 0.0; userPositiveThreshold = 0.0; thresholdType = METRIC_THRESHOLDING_TYPE_USER_VALUES; overlayScaleSpecifiedColumnNumber = 0; autoScalePercentageNegativeMinimum = 2.0; autoScalePercentageNegativeMaximum = 98.0; autoScalePercentagePositiveMinimum = 2.0; autoScalePercentagePositiveMaximum = 98.0; } /** * get the display and threshold columns for palette (negative if invalid). */ void DisplaySettingsMetric::getMetricsForColoringAndPalette(int& displayColumnOut, int& thresholdColumnOut, float& negMaxValue, float& negMinValue, float& posMinValue, float& posMaxValue, const bool volumeFlag) const { displayColumnOut = -1; thresholdColumnOut = -1; negMaxValue = 0.0; negMinValue = 0.0; posMinValue = 0.0; posMaxValue = 0.0; bool doUpdateFlag = true; if (volumeFlag) { doUpdateFlag = false; } // // Find the first displayed surface with metric as an overlay // for (int iw = 0; iw < BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS; iw++) { const int brainModelIndex = brainSet->getDisplayedModelIndexForWindow( static_cast(iw)); if ((brainModelIndex >= 0) && (brainModelIndex < brainSet->getNumberOfBrainModels())) { const BrainModelSurface* bms = brainSet->getBrainModelSurface(brainModelIndex); if (bms != NULL) { for (int j = (brainSet->getNumberOfSurfaceOverlays() - 1); j >= 0; j--) { const BrainModelSurfaceOverlay* bmsOverlay = brainSet->getSurfaceOverlay(j); if (bmsOverlay->getOverlay(brainModelIndex, doUpdateFlag) == BrainModelSurfaceOverlay::OVERLAY_METRIC) { displayColumnOut = bmsOverlay->getDisplayColumnSelected(brainModelIndex); thresholdColumnOut = bmsOverlay->getThresholdColumnSelected(brainModelIndex); break; } } } } if (displayColumnOut >= 0) { break; } } MetricFile* mf = brainSet->getMetricFile(); /* * Use functional volume if there are no metric files. */ bool useFunctionalVolumeFlag = false; if (brainSet->getNumberOfVolumeFunctionalFiles() > 0) { useFunctionalVolumeFlag = true; if (mf->getNumberOfColumns() > 0) { if (displayColumnOut >= 0) { if (displayColumnOut < mf->getNumberOfColumns()) { useFunctionalVolumeFlag = false; } } } } switch (getSelectedOverlayScale()) { case METRIC_OVERLAY_SCALE_AUTO: if (displayColumnOut >= 0) { float minValue, maxValue; mf->getDataColumnMinMax(displayColumnOut, minValue, maxValue); if (minValue < 0.0) { negMaxValue = minValue; } if (maxValue > 0.0) { posMaxValue = maxValue; } } break; case METRIC_OVERLAY_SCALE_AUTO_PERCENTAGE: if (displayColumnOut >= 0) { mf->getMinMaxValuesFromPercentages(displayColumnOut, autoScalePercentageNegativeMaximum, autoScalePercentageNegativeMinimum, autoScalePercentagePositiveMinimum, autoScalePercentagePositiveMaximum, negMaxValue, negMinValue, posMinValue, posMaxValue); } break; case METRIC_OVERLAY_SCALE_AUTO_SPECIFIED_COLUMN: if (getOverlayScaleSpecifiedColumnNumber() >= 0) { float minValue, maxValue; mf->getDataColumnMinMax(getOverlayScaleSpecifiedColumnNumber(), minValue, maxValue); if (minValue < 0.0) { negMaxValue = minValue; } if (maxValue > 0.0) { posMaxValue = maxValue; } } break; case METRIC_OVERLAY_SCALE_AUTO_FUNC_VOLUME: useFunctionalVolumeFlag = true; break; case METRIC_OVERLAY_SCALE_USER: getUserScaleMinMax(posMinValue, posMaxValue, negMinValue, negMaxValue); useFunctionalVolumeFlag = false; // use the USER SCALE values break; } // // Use volume for min/max values if no metrics // //if (mf->getNumberOfColumns() <= 0) { // useFunctionalVolumeFlag = true; //} if (useFunctionalVolumeFlag) { BrainModelVolume* bmv = brainSet->getBrainModelVolume(); if (bmv != NULL) { VolumeFile* vf = bmv->getSelectedVolumeFunctionalViewFile(); if (vf != NULL) { float minValue, maxValue; vf->getMinMaxVoxelValues(minValue, maxValue); if (minValue < 0.0) { negMaxValue = minValue; } if (maxValue > 0.0) { posMaxValue = maxValue; } } } } } /** * get manual data plot scaling. */ bool DisplaySettingsMetric::getDataPlotManualScaling(float& minPlot, float& maxPlot) const { minPlot = metricDataPlotManualScaleMinimum; maxPlot = metricDataPlotManualScaleMaximum; return metricDataPlotManualScaleFlag; } /** * set manual data plot scaling. */ void DisplaySettingsMetric::setDataPlotManualScaling(const bool b, const float minPlot, const float maxPlot) { metricDataPlotManualScaleFlag = b; metricDataPlotManualScaleMinimum = minPlot; metricDataPlotManualScaleMaximum = maxPlot; } /** * Update any selections due to changes in loaded metric file. */ void DisplaySettingsMetric::update() { DisplaySettingsNodeAttributeFile::update(); if (paletteIndex >= brainSet->getPaletteFile()->getNumberOfPalettes()) { paletteIndex = 0; } updateSelectedColumnIndex(brainSet->getMetricFile(), overlayScaleSpecifiedColumnNumber); } /** * Get the user scale minimum and maximum values. */ void DisplaySettingsMetric::getUserScaleMinMax(float& posMinValue, float& posMaxValue, float& negMinValue, float& negMaxValue) const { posMinValue = userScalePositiveMinimum; posMaxValue = userScalePositiveMaximum; negMinValue = userScaleNegativeMinimum; negMaxValue = userScaleNegativeMaximum; } /** * Set the user scale minimum and maximum values. */ void DisplaySettingsMetric::setUserScaleMinMax(const float posMinValue, const float posMaxValue, const float negMinValue, const float negMaxValue) { userScalePositiveMinimum = posMinValue; userScalePositiveMaximum = posMaxValue; userScaleNegativeMinimum = negMinValue; userScaleNegativeMaximum = negMaxValue; } /** * get special color for thresholded nodes. */ void DisplaySettingsMetric::getSpecialColorsForThresholdedNodes(unsigned char negThreshColor[3], unsigned char posThreshColor[3]) const { negThreshColor[0] = 180; negThreshColor[1] = 255; negThreshColor[2] = 115; posThreshColor[0] = 115; posThreshColor[1] = 255; posThreshColor[2] = 180; } /** * get the user thresholding values. */ void DisplaySettingsMetric::getUserThresholdingValues(float& negThresh, float& posThresh) const { negThresh = userNegativeThreshold; posThresh = userPositiveThreshold; } /** * set the user thresholding values. */ void DisplaySettingsMetric::setUserThresholdingValues(const float negThresh, const float posThresh) { userNegativeThreshold = negThresh; userPositiveThreshold = posThresh; } static const QString metricViewID("metric-view-column"); static const QString metricThreshID("metric-thresh-column"); static const QString metricOverlayScaleAutoPriorityColumn("overlay-scale-priority-column"); static const QString metricOverlayScaleAutoPercentageColumn("overlay-scale-percentage-column"); static const QString metricOverlayScaleAutoSpecifiedColumn("overlay-scale-specified-column"); static const QString metricOverlayScaleAutoFunctionalVolume("overlay-scale-functional-volume"); static const QString metricOverlayScaleUser("overlay-scale-user"); /** * apply a scene (set display settings). */ void DisplaySettingsMetric::showScene(const SceneFile::Scene& scene, QString& errorMessage) { autoScalePercentageNegativeMinimum = 2.0; autoScalePercentageNegativeMaximum = 98.0; autoScalePercentagePositiveMinimum = 2.0; autoScalePercentagePositiveMaximum = 98.0; DisplaySettingsNodeAttributeFile::showScene(scene, errorMessage); const int numClasses = scene.getNumberOfSceneClasses(); for (int nc = 0; nc < numClasses; nc++) { const SceneFile::SceneClass* sc = scene.getSceneClass(nc); if (sc->getName() == "DisplaySettingsMetric") { showSceneSelectedColumns(*sc, "Metric File", metricViewID, metricThreshID, errorMessage); const int num = sc->getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc->getSceneInfo(i); const QString infoName = si->getName(); if (infoName == "thresholdType") { int val; si->getValue(val); thresholdType = static_cast(val); } else if (infoName == "userNegativeThreshold") { si->getValue(userNegativeThreshold); } else if (infoName == "userPositiveThreshold") { si->getValue(userPositiveThreshold); } else if (infoName == "overlayScale") { if (si->getValueAsString() == metricOverlayScaleAutoPriorityColumn) { overlayScale = METRIC_OVERLAY_SCALE_AUTO; } else if (si->getValueAsString() == metricOverlayScaleAutoPercentageColumn) { overlayScale = METRIC_OVERLAY_SCALE_AUTO_PERCENTAGE; } else if (si->getValueAsString() == metricOverlayScaleAutoSpecifiedColumn) { overlayScale = METRIC_OVERLAY_SCALE_AUTO_SPECIFIED_COLUMN; } else if (si->getValueAsString() == metricOverlayScaleAutoFunctionalVolume) { overlayScale = METRIC_OVERLAY_SCALE_AUTO_FUNC_VOLUME; } else if (si->getValueAsString() == metricOverlayScaleUser) { overlayScale = METRIC_OVERLAY_SCALE_USER; } else { overlayScale = METRIC_OVERLAY_SCALE_AUTO; // // Old scene had 3 types stored as int // const int val = si->getValueAsInt(); switch (val) { case 0: overlayScale = METRIC_OVERLAY_SCALE_AUTO; break; case 1: overlayScale = METRIC_OVERLAY_SCALE_AUTO_FUNC_VOLUME; break; case 2: overlayScale = METRIC_OVERLAY_SCALE_USER; break; } } } else if (infoName == "userScalePositiveMinimum") { si->getValue(userScalePositiveMinimum); } else if (infoName == "userScalePositiveMaximum") { si->getValue(userScalePositiveMaximum); } else if (infoName == "userScaleNegativeMinimum") { si->getValue(userScaleNegativeMinimum); } else if (infoName == "userScaleNegativeMaximum") { si->getValue(userScaleNegativeMaximum); } else if (infoName == "autoScalePercentageNegativeMinimum") { si->getValue(autoScalePercentageNegativeMinimum); } else if (infoName == "autoScalePercentageNegativeMaximum") { si->getValue(autoScalePercentageNegativeMaximum); } else if (infoName == "autoScalePercentagePositiveMinimum") { si->getValue(autoScalePercentagePositiveMinimum); } else if (infoName == "autoScalePercentagePositiveMaximum") { si->getValue(autoScalePercentagePositiveMaximum); } else if (infoName == "interpolateColors") { si->getValue(interpolateColors); } else if (infoName == "displayColorBar") { si->getValue(displayColorBar); } else if (infoName == "displayMode") { int val; si->getValue(val); displayMode = static_cast(val); } else if (infoName == "metricDataPlot") { int val; si->getValue(val); metricDataPlot = static_cast(val); } else if (infoName == "metricDataPlotManualScaleFlag") { si->getValue(metricDataPlotManualScaleFlag); } else if (infoName == "metricDataPlotManualScaleMinimum") { si->getValue(metricDataPlotManualScaleMinimum); } else if (infoName == "metricDataPlotManualScaleMaximum") { si->getValue(metricDataPlotManualScaleMaximum); } else if (infoName == "showSpecialColorForThresholdedNodes") { si->getValue(showSpecialColorForThresholdedNodes); } else if (infoName == "metricPaletteIndex") { const QString paletteName = si->getValueAsString(); PaletteFile* pf = brainSet->getPaletteFile(); const int num = pf->getNumberOfPalettes(); bool found = false; for (int j = 0; j < num; j++) { const Palette* pal = pf->getPalette(j); if (paletteName == pal->getName()) { paletteIndex = j; found = true; break; } } if (found == false) { errorMessage.append("Unable to find palette named: "); errorMessage.append(paletteName); errorMessage.append("\n"); } } } } } } /** * create a scene (read display settings). */ void DisplaySettingsMetric::saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& errorMessage) { DisplaySettingsNodeAttributeFile::saveScene(scene, onlyIfSelected, errorMessage); MetricFile* mf = brainSet->getMetricFile(); if (onlyIfSelected) { if (mf->getNumberOfColumns() <= 0) { return; } BrainModelVolumeVoxelColoring* bvvc = brainSet->getVoxelColoring(); if ((brainSet->isASurfaceOverlayForAnySurface( BrainModelSurfaceOverlay::OVERLAY_METRIC) == false) && (bvvc->isUnderlayOrOverlay(BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_FUNCTIONAL) == false)) { return; } } SceneFile::SceneClass sc("DisplaySettingsMetric"); saveSceneSelectedColumns(sc); sc.addSceneInfo(SceneFile::SceneInfo("thresholdType", thresholdType)); sc.addSceneInfo(SceneFile::SceneInfo("userNegativeThreshold", userNegativeThreshold)); sc.addSceneInfo(SceneFile::SceneInfo("userPositiveThreshold", userPositiveThreshold)); switch (overlayScale) { case METRIC_OVERLAY_SCALE_AUTO: sc.addSceneInfo(SceneFile::SceneInfo("overlayScale", metricOverlayScaleAutoPriorityColumn)); break; case METRIC_OVERLAY_SCALE_AUTO_PERCENTAGE: sc.addSceneInfo(SceneFile::SceneInfo("overlayScale", metricOverlayScaleAutoPercentageColumn)); break; case METRIC_OVERLAY_SCALE_AUTO_SPECIFIED_COLUMN: sc.addSceneInfo(SceneFile::SceneInfo("overlayScale", metricOverlayScaleAutoSpecifiedColumn)); break; case METRIC_OVERLAY_SCALE_AUTO_FUNC_VOLUME: sc.addSceneInfo(SceneFile::SceneInfo("overlayScale", metricOverlayScaleAutoFunctionalVolume)); break; case METRIC_OVERLAY_SCALE_USER: sc.addSceneInfo(SceneFile::SceneInfo("overlayScale", metricOverlayScaleUser)); break; } sc.addSceneInfo(SceneFile::SceneInfo("userScalePositiveMinimum", userScalePositiveMinimum)); sc.addSceneInfo(SceneFile::SceneInfo("userScalePositiveMaximum", userScalePositiveMaximum)); sc.addSceneInfo(SceneFile::SceneInfo("userScaleNegativeMinimum", userScaleNegativeMinimum)); sc.addSceneInfo(SceneFile::SceneInfo("userScaleNegativeMaximum", userScaleNegativeMaximum)); sc.addSceneInfo(SceneFile::SceneInfo("autoScalePercentageNegativeMinimum", autoScalePercentageNegativeMinimum)); sc.addSceneInfo(SceneFile::SceneInfo("autoScalePercentageNegativeMaximum", autoScalePercentageNegativeMaximum)); sc.addSceneInfo(SceneFile::SceneInfo("autoScalePercentagePositiveMinimum", autoScalePercentagePositiveMinimum)); sc.addSceneInfo(SceneFile::SceneInfo("autoScalePercentagePositiveMaximum", autoScalePercentagePositiveMaximum)); sc.addSceneInfo(SceneFile::SceneInfo("interpolateColors", interpolateColors)); sc.addSceneInfo(SceneFile::SceneInfo("displayColorBar", displayColorBar)); sc.addSceneInfo(SceneFile::SceneInfo("displayMode", displayMode)); sc.addSceneInfo(SceneFile::SceneInfo("metricDataPlot", metricDataPlot)); sc.addSceneInfo(SceneFile::SceneInfo("metricDataPlotManualScaleFlag", metricDataPlotManualScaleFlag)); sc.addSceneInfo(SceneFile::SceneInfo("metricDataPlotManualScaleMinimum", metricDataPlotManualScaleMinimum)); sc.addSceneInfo(SceneFile::SceneInfo("metricDataPlotManualScaleMaximum", metricDataPlotManualScaleMaximum)); sc.addSceneInfo(SceneFile::SceneInfo("showSpecialColorForThresholdedNodes", showSpecialColorForThresholdedNodes)); PaletteFile* pf = brainSet->getPaletteFile(); if ((paletteIndex >= 0) && (paletteIndex < pf->getNumberOfPalettes())) { const Palette* pal = pf->getPalette(paletteIndex); sc.addSceneInfo(SceneFile::SceneInfo("metricPaletteIndex", pal->getName())); } scene.addSceneClass(sc); } caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsImages.h0000664000175000017500000000634711572067322024344 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __DISPLAY_SETTINGS_IMAGES_H__ #define __DISPLAY_SETTINGS_IMAGES_H__ #include #include "DisplaySettings.h" /// Display settings for images class DisplaySettingsImages : public DisplaySettings { public: /// image position mode enum IMAGE_POSITION_MODE { /// place center of image in center of window IMAGE_POSITION_MODE_CENTER_OF_WINDOW, /// scale image to fit within the window IMAGE_POSITION_MODE_SCALE_TO_WINDOW }; /// Constructor DisplaySettingsImages(BrainSet* bsIn); /// Destructor ~DisplaySettingsImages(); /// reinitialize all display settings void reset(); /// update any selections due to changes with loaded data files void update(); /// get the main window image number int getMainWindowImageNumber() const { return mainWindowImageNumber; } /// set the main window image number void setMainWindowImageNumber(const int n); /// get the OpenGL image for the main window (returns NULL if invalid) QImage* getMainWindowImage(); /// get the show image in main window bool getShowImageInMainWindow() const { return showImageInMainWindowFlag; } /// set the show image in main window void setShowImageInMainWindow(const bool b) { showImageInMainWindowFlag = b; } /// apply a scene (set display settings) virtual void showScene(const SceneFile::Scene& scene, QString& errorMessage) ; /// create a scene (read display settings) virtual void saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& errorMessage); /// get the image position mode IMAGE_POSITION_MODE getImagePositionMode() const { return imagePositionMode; } /// set the image position mode void setImagePositionMode(const IMAGE_POSITION_MODE ipm) { imagePositionMode = ipm; } private: /// show image in main window flag bool showImageInMainWindowFlag; /// the main window image number int mainWindowImageNumber; /// the main window image formatted for OpenGL QImage openGLFormattedImage; /// the image position mode IMAGE_POSITION_MODE imagePositionMode; }; #endif // __DISPLAY_SETTINGS_IMAGES_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsImages.cxx0000664000175000017500000001164011572067322024707 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainSet.h" #include "DisplaySettingsImages.h" #include "FileUtilities.h" #include "ImageFile.h" /** * Constructor. */ DisplaySettingsImages::DisplaySettingsImages(BrainSet* bsIn) : DisplaySettings(bsIn) { setMainWindowImageNumber(-1); imagePositionMode = IMAGE_POSITION_MODE_CENTER_OF_WINDOW; //IMAGE_POSITION_MODE_SCALE_TO_WINDOW; } /** * Destructor. */ DisplaySettingsImages::~DisplaySettingsImages() { } /** * reinitialize all display settings. */ void DisplaySettingsImages::reset() { showImageInMainWindowFlag = false; setMainWindowImageNumber(-1); } /** * update any selections due to changes with loaded data files. */ void DisplaySettingsImages::update() { if (mainWindowImageNumber >= brainSet->getNumberOfImageFiles()) { mainWindowImageNumber = -1; } // // Need to make this call so that the opengl image is properly updated // setMainWindowImageNumber(mainWindowImageNumber); } /** * set the main window image number. */ void DisplaySettingsImages::setMainWindowImageNumber(const int n) { openGLFormattedImage = QImage(); mainWindowImageNumber = -1; if ((n >= 0) && (n < brainSet->getNumberOfImageFiles())) { ImageFile* img = brainSet->getImageFile(n); openGLFormattedImage = QGLWidget::convertToGLFormat(*(img->getImage())); mainWindowImageNumber = n; } } /** * apply a scene (set display settings). */ void DisplaySettingsImages::showScene(const SceneFile::Scene& scene, QString& errorMessage) { mainWindowImageNumber = -1; const int numClasses = scene.getNumberOfSceneClasses(); for (int nc = 0; nc < numClasses; nc++) { const SceneFile::SceneClass* sc = scene.getSceneClass(nc); if (sc->getName() == "DisplaySettingsImages") { const int num = sc->getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc->getSceneInfo(i); const QString infoName = si->getName(); if (infoName == "showImageInMainWindowFlag") { showImageInMainWindowFlag = si->getValueAsBool(); } else if (infoName == "mainWindowImageNumber") { const QString imageName = si->getValueAsString(); bool found = false; const int num = brainSet->getNumberOfImageFiles(); for (int m = 0; m < num; m++) { const ImageFile* img = brainSet->getImageFile(m); if (imageName == FileUtilities::basename(img->getFileName())) { setMainWindowImageNumber(m); found = true; break; } } if (found == false) { errorMessage.append("Image file named "); errorMessage.append(imageName); errorMessage.append(" not loaded"); } } } } } } /** * create a scene (read display settings). */ void DisplaySettingsImages::saveScene(SceneFile::Scene& scene, const bool /*onlyIfSelected*/, QString& /*errorMessage*/) { const int num = brainSet->getNumberOfImageFiles(); if ((mainWindowImageNumber >= 0) && (mainWindowImageNumber < num)) { SceneFile::SceneClass sc("DisplaySettingsImages"); const ImageFile* img = brainSet->getImageFile(mainWindowImageNumber); sc.addSceneInfo(SceneFile::SceneInfo("mainWindowImageNumber", FileUtilities::basename(img->getFileName()))); sc.addSceneInfo(SceneFile::SceneInfo("showImageInMainWindowFlag", showImageInMainWindowFlag)); scene.addSceneClass(sc); } } /** * get the OpenGL image for the main window (returns NULL if invalid). */ QImage* DisplaySettingsImages::getMainWindowImage() { if (openGLFormattedImage.width() <= 0) { return NULL; } return &openGLFormattedImage; } caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsGeodesicDistance.h0000664000175000017500000000637511572067322026335 0ustar michaelmichael #ifndef __DISPLAY_SETTINGS_GEODESIC_DISTANCE_H__ #define __DISPLAY_SETTINGS_GEODESIC_DISTANCE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "DisplaySettings.h" /// class for display control of geodesic distance class DisplaySettingsGeodesicDistance : public DisplaySettings { public: /// Constructor DisplaySettingsGeodesicDistance(BrainSet* bs); /// Destructor ~DisplaySettingsGeodesicDistance(); /// get the selected display column int getDisplayColumn() const { return displayColumn; } /// set the selected display column void setDisplayColumn(const int col) { displayColumn = col; } /// get geodesic path display enabled bool getPathDisplayEnabled() const { return pathDisplayEnabled; } /// set geodesic path display enabled void setPathDisplayEnabled(const bool de) { pathDisplayEnabled = de; } /// get the path display node number int getPathDisplayNodeNumber() const { return pathDisplayNodeNumber; } /// set the path display node number void setPathDisplayNodeNumber(const int dnn) { pathDisplayNodeNumber = dnn; } /// show the root node bool getShowRootNode() const { return showRootNode; } /// set show the root node void setShowRootNode(const bool b) { showRootNode = b; } /// get the path line width int getPathLineWidth() const { return lineWidth; } /// set the path line width void setPathLineWidth(const int w) { lineWidth = w; } /// reinitialize all display settings virtual void reset(); /// update any selections due to changes with loaded data files virtual void update(); /// apply a scene (set display settings) virtual void showScene(const SceneFile::Scene& scene, QString& errorMessage) ; /// create a scene (read display settings) virtual void saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& errorMessage); protected: /// selected display column int displayColumn; /// path display node number int pathDisplayNodeNumber; /// path display enabled bool pathDisplayEnabled; /// show the root node bool showRootNode; /// line width int lineWidth; }; #endif // __DISPLAY_SETTINGS_GEODESIC_DISTANCE_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsGeodesicDistance.cxx0000664000175000017500000001127611572067322026704 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurfaceNodeColoring.h" #include "BrainSet.h" #include "DisplaySettingsGeodesicDistance.h" #include "GeodesicDistanceFile.h" /** * Constructor. */ DisplaySettingsGeodesicDistance::DisplaySettingsGeodesicDistance(BrainSet* bs) : DisplaySettings(bs) { displayColumn = -1; pathDisplayEnabled = false; showRootNode = false; lineWidth = 3; reset(); } /** * Destructor. */ DisplaySettingsGeodesicDistance::~DisplaySettingsGeodesicDistance() { } /** * reinitialize all display settings. */ void DisplaySettingsGeodesicDistance::reset() { pathDisplayNodeNumber = -1; } /** * update any selections due to changes with loaded data files. */ void DisplaySettingsGeodesicDistance::update() { GeodesicDistanceFile* gdf = brainSet->getGeodesicDistanceFile(); const int numCols = gdf->getNumberOfColumns(); if (displayColumn >= numCols) { if (numCols > 0) { displayColumn = 0; } else { displayColumn = -1; } } else if ((numCols > 0) && (displayColumn < 0)) { displayColumn = 0; } if (pathDisplayNodeNumber >= brainSet->getNumberOfNodes()) { pathDisplayNodeNumber = -1; } } static const QString geodesicID("geodesic-column"); /** * apply a scene (set display settings). */ void DisplaySettingsGeodesicDistance::showScene(const SceneFile::Scene& scene, QString& errorMessage) { GeodesicDistanceFile* gdf = brainSet->getGeodesicDistanceFile(); const int numClasses = scene.getNumberOfSceneClasses(); for (int nc = 0; nc < numClasses; nc++) { const SceneFile::SceneClass* sc = scene.getSceneClass(nc); if (sc->getName() == "DisplaySettingsGeodesicDistance") { const int num = sc->getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc->getSceneInfo(i); const QString infoName = si->getName(); if (infoName == geodesicID) { showSceneNodeAttributeColumn(si, gdf, "Geodesic Distance File", displayColumn, errorMessage); } else if (infoName == "pathDisplayNodeNumber") { si->getValue(pathDisplayNodeNumber); } else if (infoName == "pathDisplayEnabled") { si->getValue(pathDisplayEnabled); } else if (infoName == "showRootNode") { si->getValue(showRootNode); } else if (infoName == "geolineWidth") { si->getValue(lineWidth); } } } } } /** * create a scene (read display settings). */ void DisplaySettingsGeodesicDistance::saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& /*errorMessage*/) { GeodesicDistanceFile* gdf = brainSet->getGeodesicDistanceFile(); if (onlyIfSelected) { if (gdf->getNumberOfColumns() <= 0) { return; } } SceneFile::SceneClass sc("DisplaySettingsGeodesicDistance"); saveSceneNodeAttributeColumn(sc, geodesicID, gdf, displayColumn); sc.addSceneInfo(SceneFile::SceneInfo("pathDisplayNodeNumber", pathDisplayNodeNumber)); sc.addSceneInfo(SceneFile::SceneInfo("pathDisplayEnabled", pathDisplayEnabled)); sc.addSceneInfo(SceneFile::SceneInfo("showRootNode", showRootNode)); sc.addSceneInfo(SceneFile::SceneInfo("geolineWidth", lineWidth)); scene.addSceneClass(sc); } caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsFoci.h0000664000175000017500000000346311572067322024013 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_DISPLAY_SETTINGS_FOCI_H__ #define __VE_DISPLAY_SETTINGS_FOCI_H__ #include "DisplaySettingsCells.h" class BrainSet; /// Display settings for foci and foci projections class DisplaySettingsFoci : public DisplaySettingsCells { public: /// Constructor DisplaySettingsFoci(BrainSet* bs); /// Destructor ~DisplaySettingsFoci(); /// Reinitialize all display settings void reset(); /// Update any selections due to changes in loaded foci void update(); /// Determine which foci are displayed void determineDisplayedFoci(); // apply a scene (set display settings) //virtual void showScene(const SceneFile::Scene& scene, QString& errorMessage) ; // create a scene (read display settings) //virtual void saveScene(SceneFile::Scene& scene, const bool onlyIfSelected); private: }; #endif caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsFoci.cxx0000664000175000017500000000417211572067322024364 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "DisplaySettingsFoci.h" #include "BrainSet.h" /** * Constructor. */ DisplaySettingsFoci::DisplaySettingsFoci(BrainSet* bs) : DisplaySettingsCells(bs) { reset(); } /** * Destructor. */ DisplaySettingsFoci::~DisplaySettingsFoci() { } /** * Reinitialize all display settings. */ void DisplaySettingsFoci::reset() { DisplaySettingsCells::reset(); } /** * Update selections due to changes in loaded foci. */ void DisplaySettingsFoci::update() { determineDisplayedFoci(); } /** * Determine the foci that are displayed. */ void DisplaySettingsFoci::determineDisplayedFoci() { DisplaySettingsCells::determineDisplayedCells(true); } /** * apply a scene (set display settings). */ /* void DisplaySettingsFoci::showScene(const SceneFile::Scene& scene, QString& errorMessage) { const int numClasses = scene.getNumberOfSceneClasses(); for (int nc = 0; nc < numClasses; nc++) { const SceneFile::SceneClass* sc = scene.getSceneClass(nc); if (sc->getName() == "DisplaySettingsFoci") { } } } */ /** * create a scene (read display settings). */ /* void DisplaySettingsFoci::saveScene(SceneFile::Scene& scene, const bool onlyIfSelected) { SceneFile::SceneClass sc("DisplaySettingsFoci"); scene.addSceneClass(sc); } */ caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsDeformationField.h0000664000175000017500000000772111572067322026347 0ustar michaelmichael #ifndef __VE_DISPLAY_SETTINGS_DEFORMATION_FIELD_H__ #define __VE_DISPLAY_SETTINGS_DEFORMATION_FIELD_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "DisplaySettings.h" class BrainSet; /// DisplaySettingsDeformationField is a class that maintains parameters for controlling /// the display of deformation field data files. class DisplaySettingsDeformationField : public DisplaySettings { public: /// display mode types enum DISPLAY_MODE { DISPLAY_MODE_ALL, DISPLAY_MODE_NONE, DISPLAY_MODE_SPARSE }; /// Constructor DisplaySettingsDeformationField(BrainSet* bs); /// Destructor ~DisplaySettingsDeformationField(); /// get the display mode DISPLAY_MODE getDisplayMode() const { return displayMode; } /// set the display mode void setDisplayMode(const DISPLAY_MODE dm); /// Reinitialize all display settings void reset(); /// Update any selections due to changes in loaded metric file void update(); /// get column selected for display int getSelectedDisplayColumn(); /// set column for display void setSelectedDisplayColumn(const int sdc) { displayColumn = sdc; } /// get the sparse distance int getSparseDisplayDistance() const { return sparseDistance; } /// set the sparse distance void setSparseDisplayDistance(const int dist) { sparseDistance = dist; } /// get display vectors on identified nodes bool getDisplayIdentifiedNodes() const { return displayIdentifiedNodes; } /// set display vector on identified nodes void setDisplayIdentifiedNodes(const bool b) { displayIdentifiedNodes = b; } /// get display vector for node bool getDisplayVectorForNode(const int nodeNum) const; /// set display vector for node void setDisplayVectorForNode(const int nodeNum, const bool status); /// show vectors unstretched on flat surface void getShowUnstretchedOnFlat(float& factor, bool& showIt); /// set show vectors unstretched on flat surface void setShowUnstretchedOnFlat(const float factor, const bool showIt); /// apply a scene (set display settings) virtual void showScene(const SceneFile::Scene& scene, QString& errorMessage) ; /// create a scene (read display settings) virtual void saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& errorMessage); private: /// selected column for dislay int displayColumn; /// the display mode DISPLAY_MODE displayMode; /// sparse distance (mm) int sparseDistance; /// display vectors on identified nodes bool displayIdentifiedNodes; /// display a vector for a node std::vector displayVectorForNode; /// show unstretched scale factor float unstretchedFactor; /// show unstretched vectors on flat bool showUnstretchedOnFlat; }; #endif // __VE_DISPLAY_SETTINGS_DEFORMATION_FIELD_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsDeformationField.cxx0000664000175000017500000001710611572067322026720 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainSet.h" #include "DisplaySettingsDeformationField.h" #include "DeformationFieldFile.h" /** * The constructor. */ DisplaySettingsDeformationField::DisplaySettingsDeformationField(BrainSet* bs) : DisplaySettings(bs) { displayMode = DISPLAY_MODE_NONE; sparseDistance = 50; displayIdentifiedNodes = false; showUnstretchedOnFlat = true; unstretchedFactor = 2.5; reset(); } /** * The destructor. */ DisplaySettingsDeformationField::~DisplaySettingsDeformationField() { } /** * show vectors unstretched on flat surface */ void DisplaySettingsDeformationField::getShowUnstretchedOnFlat(float& factor, bool& showIt) { factor = unstretchedFactor; showIt = showUnstretchedOnFlat; } /** * set show vectors unstretched on flat surface */ void DisplaySettingsDeformationField::setShowUnstretchedOnFlat(const float factor, const bool showIt) { unstretchedFactor = factor; showUnstretchedOnFlat = showIt; } /** * Reinitialize all display settings. */ void DisplaySettingsDeformationField::reset() { displayColumn = 0; displayVectorForNode.clear(); } /** * Update any selections due to changes in loaded metric file. */ void DisplaySettingsDeformationField::update() { const int numCol = brainSet->getDeformationFieldFile()->getNumberOfColumns(); if (displayColumn >= numCol) { displayColumn = 0; } bool defaultValue = false; switch (displayMode) { case DISPLAY_MODE_ALL: defaultValue = true; break; case DISPLAY_MODE_NONE: defaultValue = false; break; case DISPLAY_MODE_SPARSE: defaultValue = false; break; } const int numNodes = brainSet->getNumberOfNodes(); displayVectorForNode.resize(numNodes, defaultValue); } /** * set the display mode. */ void DisplaySettingsDeformationField::setDisplayMode(const DISPLAY_MODE dm) { displayMode = dm; const int numNodes = static_cast(displayVectorForNode.size()); switch (displayMode) { case DISPLAY_MODE_ALL: for (int i = 0; i < numNodes; i++) { displayVectorForNode[i] = true; } break; case DISPLAY_MODE_NONE: for (int i = 0; i < numNodes; i++) { displayVectorForNode[i] = false; } break; case DISPLAY_MODE_SPARSE: for (int i = 0; i < numNodes; i++) { displayVectorForNode[i] = false; } for (int i = 0; i < numNodes; i += sparseDistance) { displayVectorForNode[i] = true; } break; } } /** * Get the column selected for display. * Returns -1 if there are no metric columns available. */ int DisplaySettingsDeformationField::getSelectedDisplayColumn() { if (displayColumn >= brainSet->getDeformationFieldFile()->getNumberOfColumns()) { displayColumn = -1; } else if ((displayColumn < 0) && (brainSet->getDeformationFieldFile()->getNumberOfColumns() > 0)) { displayColumn = 0; } return displayColumn; } /** * get display vector for node. */ bool DisplaySettingsDeformationField::getDisplayVectorForNode(const int nodeNum) const { if (nodeNum < static_cast(displayVectorForNode.size())) { return displayVectorForNode[nodeNum]; } return false; } /** * set display vector for node. */ void DisplaySettingsDeformationField::setDisplayVectorForNode(const int nodeNum, const bool status) { if (nodeNum < static_cast(displayVectorForNode.size())) { displayVectorForNode[nodeNum] = status; } } static const QString deformationFieldID("deformation-field-column"); /** * apply a scene (set display settings). */ void DisplaySettingsDeformationField::showScene(const SceneFile::Scene& scene, QString& errorMessage) { DeformationFieldFile* dff = brainSet->getDeformationFieldFile(); setDisplayMode(DISPLAY_MODE_NONE); const int numClasses = scene.getNumberOfSceneClasses(); for (int nc = 0; nc < numClasses; nc++) { const SceneFile::SceneClass* sc = scene.getSceneClass(nc); if (sc->getName() == "DisplaySettingsDeformationField") { const int num = sc->getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc->getSceneInfo(i); const QString infoName = si->getName(); if (infoName == deformationFieldID) { showSceneNodeAttributeColumn(si, dff, "Deformation Field File", displayColumn, errorMessage); } else if (infoName == "deformation-field-displayMode") { setDisplayMode(static_cast(si->getValueAsInt())); } else if (infoName == "sparseDistance") { si->getValue(sparseDistance); } else if (infoName == "displayIdentifiedNodes") { si->getValue(displayIdentifiedNodes); } else if (infoName == "unstretchedFactor") { si->getValue(unstretchedFactor); } else if (infoName == "showUnstretchedOnFlat") { si->getValue(showUnstretchedOnFlat); } } } } } /** * create a scene (read display settings). */ void DisplaySettingsDeformationField::saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& /*errorMessage*/) { DeformationFieldFile* dff = brainSet->getDeformationFieldFile(); if (onlyIfSelected) { if (dff->getNumberOfColumns() <= 0) { return; } if (displayMode == DISPLAY_MODE_NONE) { return; } } SceneFile::SceneClass sc("DisplaySettingsDeformationField"); saveSceneNodeAttributeColumn(sc, deformationFieldID, dff, displayColumn); sc.addSceneInfo(SceneFile::SceneInfo("deformation-field-displayMode", displayMode)); sc.addSceneInfo(SceneFile::SceneInfo("sparseDistance", sparseDistance)); sc.addSceneInfo(SceneFile::SceneInfo("displayIdentifiedNodes", displayIdentifiedNodes)); sc.addSceneInfo(SceneFile::SceneInfo("unstretchedFactor", unstretchedFactor)); sc.addSceneInfo(SceneFile::SceneInfo("showUnstretchedOnFlat", showUnstretchedOnFlat)); scene.addSceneClass(sc); } caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsCuts.h0000664000175000017500000000376311572067322024054 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_DISPLAY_SETTINGS_CUTS_H__ #define __VE_DISPLAY_SETTINGS_CUTS_H__ #include "DisplaySettings.h" /// Display settings for cuts class DisplaySettingsCuts : public DisplaySettings { public: /// Constructor DisplaySettingsCuts(BrainSet* bs); /// Destructor ~DisplaySettingsCuts(); /// Reinitialize all display settings void reset(); /// Update any selections due to changes in loaded cuts void update(); /// get display cuts bool getDisplayCuts() const { return displayCuts; } /// set display cuts void setDisplayCuts(const bool dfc) { displayCuts = dfc; } /// apply a scene (set display settings) virtual void showScene(const SceneFile::Scene& scene, QString& errorMessage) ; /// create a scene (read display settings) virtual void saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& errorMessage); protected: /// display cuts bool displayCuts; }; #endif // __VE_DISPLAY_SETTINGS_CUTS_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsCuts.cxx0000664000175000017500000000503211572067322024416 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "DisplaySettingsCuts.h" #include "BrainSet.h" /** * Constructor. */ DisplaySettingsCuts::DisplaySettingsCuts(BrainSet* bs) : DisplaySettings(bs) { reset(); } /** * Destructor. */ DisplaySettingsCuts::~DisplaySettingsCuts() { } /** * Reinitialize all display settings. */ void DisplaySettingsCuts::reset() { displayCuts = false; } /** * Update selections due to changes in loaded cuts. */ void DisplaySettingsCuts::update() { } /** * apply a scene (set display settings). */ void DisplaySettingsCuts::showScene(const SceneFile::Scene& scene, QString& /*errorMessage*/) { const int numClasses = scene.getNumberOfSceneClasses(); for (int nc = 0; nc < numClasses; nc++) { const SceneFile::SceneClass* sc = scene.getSceneClass(nc); if (sc->getName() == "DisplaySettingsCuts") { const int num = sc->getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc->getSceneInfo(i); const QString infoName = si->getName(); if (infoName == "displayCuts") { si->getValue(displayCuts); } } } } } /** * create a scene (read display settings). */ void DisplaySettingsCuts::saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& /*errorMessage*/) { if (onlyIfSelected) { if (displayCuts == false) { return; } } SceneFile::SceneClass sc("DisplaySettingsCuts"); sc.addSceneInfo(SceneFile::SceneInfo("displayCuts", displayCuts)); scene.addSceneClass(sc); } caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsContours.h0000664000175000017500000001114711572067322024745 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __DISPLAY_SETTINGS_CONTOURS_H__ #define __DISPLAY_SETTINGS_CONTOURS_H__ #include "DisplaySettings.h" /// Display settings for contours class DisplaySettingsContours : public DisplaySettings { public: /// drawing mode for contours enum DRAW_MODE { /// draw as points DRAW_MODE_POINTS, /// draw as lines DRAW_MODE_LINES, /// draw as points and lines DRAW_MODE_POINTS_AND_LINES }; /// Constructor DisplaySettingsContours(BrainSet* bs); /// Destructor ~DisplaySettingsContours(); /// Reinitialize all display settings virtual void reset(); /// Update any selections due to changes in loaded cells virtual void update(); /// get draw mode DRAW_MODE getDrawMode() const { return drawMode; } /// set draw mode void setDrawMode(const DRAW_MODE dm) { drawMode = dm; } /// get show end points bool getShowEndPoints() const { return showEndPoints; } /// set show end points void setShowEndPoints(const bool sep) { showEndPoints = sep; } /// get line thickness float getLineThickness() const { return drawLineThickness; } /// set line thickness void setLineThickness(const float ds) { drawLineThickness = ds; } /// get point size float getPointSize() const { return drawPointSize; } /// set point size void setPointSize(const float ds) { drawPointSize = ds; } /// get show contour cells bool getDisplayContourCells() const { return showContourCells; } /// set show contour cells void setDisplayContourCells(const bool scc) { showContourCells = scc; } /// determine which contour cells should be displayed void determineDisplayedContourCells(); /// get contour cell size float getContourCellSize() const { return contourCellSize; } /// set contour cell size void setContourCellSize(const float cs) { contourCellSize = cs; } /// get alignment contour valid bool getAlignmentContourValid() const { return alignmentContourValid; } /// set alignment contour valid void setAlignmentContourValid(const bool b) { alignmentContourValid = b; } /// get alignment contour number int getAlignmentContourNumber() const { return alignmentContourNumber; } /// set alignment contour number void setAlignmentContourNumber(const int num) {alignmentContourNumber = num; } /// get display cross at origin bool getDisplayCrossAtOrigin() const { return displayCrossAtOrigin; } /// set display cross at origin void setDisplayCrossAtOrigin(const bool b) { displayCrossAtOrigin = b; } /// apply a scene (set display settings) virtual void showScene(const SceneFile::Scene& scene, QString& errorMessage) ; /// create a scene (read display settings) virtual void saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& errorMessage); private: /// draw as lines DRAW_MODE drawMode; /// show end points bool showEndPoints; /// drawing line thickness float drawLineThickness; /// drawing point size float drawPointSize; /// show contour cells bool showContourCells; /// contour cell size float contourCellSize; /// alignment contour valid bool alignmentContourValid; /// alignment contour number int alignmentContourNumber; /// display a cross at the origin bool displayCrossAtOrigin; }; #endif // __DISPLAY_SETTINGS_CONTOURS_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsContours.cxx0000664000175000017500000001474411572067322025326 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelContours.h" #include "BrainSet.h" #include "ContourCellFile.h" #include "ContourCellColorFile.h" #include "DisplaySettingsContours.h" /** * Constructor. */ DisplaySettingsContours::DisplaySettingsContours(BrainSet* bs) : DisplaySettings(bs) { reset(); } /** * Destructor. */ DisplaySettingsContours::~DisplaySettingsContours() { } /** * Reinitialize all display settings. */ void DisplaySettingsContours::reset() { drawMode = DRAW_MODE_POINTS_AND_LINES; showEndPoints = false; showContourCells = true; drawLineThickness = 1.0; drawPointSize = 2.0; contourCellSize = 4.0; alignmentContourValid = false; alignmentContourNumber = 0; displayCrossAtOrigin = true; } /** * Update selections due to changes in loaded cells. */ void DisplaySettingsContours::update() { determineDisplayedContourCells(); } /** * Determine which contour cells are displayed. */ void DisplaySettingsContours::determineDisplayedContourCells() { BrainModelContours* bmc = brainSet->getBrainModelContours(-1); if (bmc == NULL) { return; } //ContourFile* contourFile = bmc->getContourFile(); ContourCellColorFile* colorFile = brainSet->getContourCellColorFile(); const int numColors = colorFile->getNumberOfColors(); // // Only use class information in the fiducial foci or cell file // ContourCellFile* cellFile = brainSet->getContourCellFile(); // // Minimum and maximum displayed section // //const int minimumSection = contourFile->getMinimumSelectedSection(); //const int maximumSection = contourFile->getMaximumSelectedSection(); const int numCells = cellFile->getNumberOfCells(); for (int j = 0; j < numCells; j++) { CellData* cd = cellFile->getCell(j); cd->setDisplayFlag(false); // // Check color selected for display // bool colorDisplayFlag = true; const int colorIndex = cd->getColorIndex(); if ((colorIndex >= 0) && (colorIndex < numColors)) { colorDisplayFlag = colorFile->getSelected(colorIndex); } // // Check class selected // bool classDisplayFlag = true; if (cd->getClassIndex() >= 0) { classDisplayFlag = cellFile->getCellClassSelectedByIndex(cd->getClassIndex()); } // // Check section for cells // bool sectionDisplayFlag = true; //if ((cd->getSectionNumber() < minimumSection) || // (cd->getSectionNumber() > maximumSection)) { // sectionDisplayFlag = false; //} // // Set the cell's display flag. // cd->setDisplayFlag(colorDisplayFlag && classDisplayFlag && sectionDisplayFlag); } } /** * apply a scene (set display settings). */ void DisplaySettingsContours::showScene(const SceneFile::Scene& scene, QString& /*errorMessage*/) { const int numClasses = scene.getNumberOfSceneClasses(); for (int nc = 0; nc < numClasses; nc++) { const SceneFile::SceneClass* sc = scene.getSceneClass(nc); if (sc->getName() == "DisplaySettingsContours") { const int num = sc->getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc->getSceneInfo(i); const QString infoName = si->getName(); if (infoName == "drawMode") { drawMode = static_cast(si->getValueAsInt()); } else if (infoName == "contour-drawAsLines") { bool b; si->getValue(b); if (b) { drawMode = DRAW_MODE_LINES; } else { drawMode = DRAW_MODE_POINTS_AND_LINES; } } else if (infoName == "contour-showEndPoints") { si->getValue(showEndPoints); } else if (infoName == "contour-drawingSize") { si->getValue(drawPointSize); } else if (infoName == "drawLineThickness") { si->getValue(drawLineThickness); } else if (infoName == "drawPointSize") { si->getValue(drawPointSize); } else if (infoName == "showContourCells") { si->getValue(showContourCells); } else if (infoName == "contourCellSize") { si->getValue(contourCellSize); } } } } } /** * create a scene (read display settings). */ void DisplaySettingsContours::saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& /*errorMessage*/) { if (onlyIfSelected) { BrainModelContours* bmc = brainSet->getBrainModelContours(); if (bmc == NULL) { return; } } SceneFile::SceneClass sc("DisplaySettingsContours"); sc.addSceneInfo(SceneFile::SceneInfo("drawMode", static_cast(drawMode))); sc.addSceneInfo(SceneFile::SceneInfo("contour-showEndPoints", showEndPoints)); sc.addSceneInfo(SceneFile::SceneInfo("drawPointSize", drawPointSize)); sc.addSceneInfo(SceneFile::SceneInfo("drawLineThickness", drawLineThickness)); sc.addSceneInfo(SceneFile::SceneInfo("showContourCells", showContourCells)); sc.addSceneInfo(SceneFile::SceneInfo("contourCellSize", contourCellSize)); scene.addSceneClass(sc); } caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsCoCoMac.h0000664000175000017500000000670011572067322024374 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_DISPLAY_SETTINGS_COCOMAC_H__ #define __VE_DISPLAY_SETTINGS_COCOMAC_H__ #include "DisplaySettings.h" /// DisplaySettingsCoCoMac is a class that maintains parameters for controlling /// the display of CoCoMac Files. class DisplaySettingsCoCoMac : public DisplaySettings { public: /// Type of connection display enum CONNECTION_DISPLAY_TYPE { CONNECTION_DISPLAY_AFFERENT, CONNECTION_DISPLAY_EFFERENT, CONNECTION_DISPLAY_AFFERENT_AND_EFFERENT, CONNECTION_DISPLAY_AFFERENT_OR_EFFERENT }; /// Constructor DisplaySettingsCoCoMac(BrainSet* bs); /// Constructor ~DisplaySettingsCoCoMac(); /// get the connection display type CONNECTION_DISPLAY_TYPE getConnectionDisplayType() const { return connectionDisplayType; } /// set the connection display type void setConnectionDisplayType(const CONNECTION_DISPLAY_TYPE cdt) { connectionDisplayType = cdt; } /// get the selected paint column to use for area names int getSelectedPaintColumn() const { return selectedPaintColumn; } /// set the selected paint column to use for area names void setSelectedPaintColumn(const int col) { selectedPaintColumn = col; } /// get the selected node for cocomac info int getSelectedNode() const { return selectedNode; } /// set the selected node for cocomac info void setSelectedNode(const int node) { selectedNode = node; } /// get identification info produced when node coloring QString getIDInfo() { QString s(idInfo); idInfo = ""; return s; } /// set identification info produced when node coloring void setIDInfo(const QString& s) { idInfo = s; } /// Reinitialize all display settings void reset(); /// Update any selections due to changes in loaded metric file void update(); /// apply a scene (set display settings) virtual void showScene(const SceneFile::Scene& scene, QString& errorMessage) ; /// create a scene (read display settings) virtual void saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& errorMessage); private: /// connection display type CONNECTION_DISPLAY_TYPE connectionDisplayType; /// selected paint column for area names int selectedPaintColumn; /// selected node int selectedNode; /// id info produced by node coloring QString idInfo; }; #endif caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsCoCoMac.cxx0000664000175000017500000000773411572067322024757 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurfaceNodeColoring.h" #include "BrainSet.h" #include "DisplaySettingsCoCoMac.h" #include "PaintFile.h" /** * The constructor. */ DisplaySettingsCoCoMac::DisplaySettingsCoCoMac(BrainSet* bs) : DisplaySettings(bs) { reset(); } /** * The destructor. */ DisplaySettingsCoCoMac::~DisplaySettingsCoCoMac() { } /** * Reinitialize all display settings. */ void DisplaySettingsCoCoMac::reset() { selectedPaintColumn = 0; connectionDisplayType = CONNECTION_DISPLAY_AFFERENT; selectedNode = -1; } /** * Update selections due to changes in loaded topography files. */ void DisplaySettingsCoCoMac::update() { PaintFile* pf = brainSet->getPaintFile(); if (selectedPaintColumn >= pf->getNumberOfColumns()) { selectedPaintColumn = 0; } } static const QString cocomacPaintID("cocomac-paint-column"); /** * apply a scene (set display settings). */ void DisplaySettingsCoCoMac::showScene(const SceneFile::Scene& scene, QString& errorMessage) { const int numClasses = scene.getNumberOfSceneClasses(); for (int nc = 0; nc < numClasses; nc++) { const SceneFile::SceneClass* sc = scene.getSceneClass(nc); if (sc->getName() == "DisplaySettingsCoCoMac") { PaintFile* pf = brainSet->getPaintFile(); const int num = sc->getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc->getSceneInfo(i); const QString infoName = si->getName(); if (infoName == cocomacPaintID) { showSceneNodeAttributeColumn(si, pf, "Paint File", selectedPaintColumn, errorMessage); } else if (infoName == "connectionDisplayType") { int val; si->getValue(val); connectionDisplayType = static_cast(val); } else if (infoName == "selectedNode") { si->getValue(selectedNode); } } } } } /** * create a scene (read display settings). */ void DisplaySettingsCoCoMac::saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& /*errorMessage*/) { if (onlyIfSelected) { if (brainSet->isASurfaceOverlayForAnySurface( BrainModelSurfaceOverlay::OVERLAY_COCOMAC) == false) { return; } } SceneFile::SceneClass sc("DisplaySettingsCoCoMac"); PaintFile* pf = brainSet->getPaintFile(); saveSceneNodeAttributeColumn(sc, cocomacPaintID, pf, selectedPaintColumn); sc.addSceneInfo(SceneFile::SceneInfo("connectionDisplayType", connectionDisplayType)); sc.addSceneInfo(SceneFile::SceneInfo("selectedNode", selectedNode)); scene.addSceneClass(sc); } caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsCells.h0000664000175000017500000002125511572067322024174 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_DISPLAY_SETTINGS_CELLS_H__ #define __VE_DISPLAY_SETTINGS_CELLS_H__ #include "CellBase.h" #include "CellColorFile.h" #include "DisplaySettings.h" class BrainSet; class CellProjection; /// Display settings for cells and cell projections class DisplaySettingsCells : public DisplaySettings { public: /// Display Mode enum CELL_DISPLAY_MODE { CELL_DISPLAY_MODE_SHOW_ALL, CELL_DISPLAY_MODE_SHOW_DEEP_ONLY, CELL_DISPLAY_MODE_SHOW_SUPERFICIAL_ONLY }; /// Constructor DisplaySettingsCells(BrainSet* bs); /// Destructor virtual ~DisplaySettingsCells(); /// Reinitialize all display settings virtual void reset(); /// Update any selections due to changes in loaded cells virtual void update(); /// get display cells bool getDisplayCells() const { return displayCells; } /// set display cells void setDisplayCells(const bool dfc) { displayCells = dfc; } /// get display volume cells bool getDisplayVolumeCells() const { return displayVolumeCells; } /// set display volume cells void setDisplayVolumeCells(const bool dfc) { displayVolumeCells = dfc; } /// get display cell raised on flat surface bool getDisplayFlatCellsRaised() const { return displayFlatCellsRaised; } /// set dislay cells raised on flat surface void setDisplayFlatCellsRaised(const bool fsr) { displayFlatCellsRaised = fsr; } /// get display cells pasted onto 3D surfaces bool getDisplayPasteCellsOnto3D() const { return displayPasteCellsOnto3D; } /// set display cells pasted onto 3D surface void setDisplayPasteCellsOnto3D(const bool d3d) { displayPasteCellsOnto3D = d3d; } /// get the symbol override ColorFile::ColorStorage::SYMBOL getSymbolOverride() const { return symbolOverride; } /// set the symbol override void setSymbolOverride(const ColorFile::ColorStorage::SYMBOL so) { symbolOverride = so; } /// get cell draw size float getDrawSize() const { return cellSize; } /// set cell draw size void setDrawSize(const float ds) { cellSize = ds; } /// set display cells only on the correct hemisphere void setDisplayCellsOnCorrectHemisphereOnly(const bool b) { displayCellsOnCorrectHemisphereOnly = b; } /// ge display cells only on the correct hemisphere bool getDisplayCellsOnCorrectHemisphereOnly() const { return displayCellsOnCorrectHemisphereOnly; } /// get the distance to surface limit float getDistanceToSurfaceLimit() const { return distanceToSurfaceLimit; } /// set the distance to surface limit void setDistanceToSurfaceLimit(const float dist) { distanceToSurfaceLimit = dist; } /// get the border opacity float getOpacity() const { return opacity; } /// set the border opacity void setOpacity(const float o) { opacity = o; } /// get the display mode CELL_DISPLAY_MODE getDisplayMode() const { return cellDisplayMode; } /// set the display mode void setDisplayMode(const CELL_DISPLAY_MODE cdm) { cellDisplayMode = cdm; } /// determine which cells should be displayed (set's cell display flags) void determineDisplayedCells(const bool fociFlag = false); /// determine which volume cells should be displayed (set's cell display flags) void determineDisplayedVolumeCells(); /// apply a scene (set display settings) virtual void showScene(const SceneFile::Scene& scene, QString& errorMessage) ; /// create a scene (read display settings) virtual void saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& errorMessage); /// get the coloring mode CellBase::CELL_COLOR_MODE getColorMode() const { return cellColorMode; } /// set the coloring mode void setColorMode(const CellBase::CELL_COLOR_MODE ccm) { cellColorMode = ccm; } /// get display cells without class assignments bool getDisplayCellsWithoutClassAssignments() const { return displayCellsWithoutClassAssignments; } /// set display cells without class assignments void setDisplayCellsWithoutClassAssignments(const bool b) { displayCellsWithoutClassAssignments = b; } /// get display cells without matching color bool getDisplayCellsWithoutMatchingColor() const { return displayCellsWithoutMatchingColor; } /// set display cells without matching color void setDisplayCellsWithoutMatchingColor(const bool b) { displayCellsWithoutMatchingColor = b; } /// get display cells without a link to a study with keywords bool getDisplayCellsWithoutLinkToStudyWithKeywords() const { return displayCellsWithoutLinkToStudyWithKeywords; } /// set display cells without a link to a study with keywords void setDisplayCellsWithoutLinkToStudyWithKeywords(const bool b) { displayCellsWithoutLinkToStudyWithKeywords = b; } /// get display only keywords for displayed cells //bool getDisplayKeywordsForOnlyDisplayedCells() const // { return displayKeywordsForOnlyDisplayedCells; } /// set display only keywords for displayed cells //void setDisplayKeywordsForOnlyDisplayedCells(const bool b) // { displayKeywordsForOnlyDisplayedCells = b; } /// get display cells without a link to a table subheader bool getDisplayCellsWithoutLinkToStudyWithTableSubHeader() const { return displayCellsWithoutLinkToStudyWithTableSubHeader; } /// set display cells without a link to a table subheader void setDisplayCellsWithoutLinkToStudyWithTableSubHeader(const bool b) { displayCellsWithoutLinkToStudyWithTableSubHeader = b; } /// get only show cells that are in the search bool getDislayCellsOnlyIfInSearch() const { return displayCellsOnlyIfInSearch; } /// set only show cells that are in the search bool setDisplayCellsOnlyIfInSearch(const bool b) { return displayCellsOnlyIfInSearch = b; } protected: /// display cells bool displayCells; /// display volume cells bool displayVolumeCells; /// show cells raised on flat surface bool displayFlatCellsRaised; /// paste cells onto 3D surfaces bool displayPasteCellsOnto3D; /// symbol override ColorFile::ColorStorage::SYMBOL symbolOverride; /// draw size float cellSize; /// display cells only on the correct hemisphere bool displayCellsOnCorrectHemisphereOnly; /// limit display to cells within distance to surface float distanceToSurfaceLimit; /// cell display mode CELL_DISPLAY_MODE cellDisplayMode; /// cell coloring mode CellBase::CELL_COLOR_MODE cellColorMode; /// opacity float opacity; /// display cells without class assignments bool displayCellsWithoutClassAssignments; /// display cells without matching color bool displayCellsWithoutMatchingColor; /// display cells without a link to a study with keywords bool displayCellsWithoutLinkToStudyWithKeywords; /// display keywords for only cells that are displayed //bool displayKeywordsForOnlyDisplayedCells; /// display cells without a link to a table subheader bool displayCellsWithoutLinkToStudyWithTableSubHeader; // show only cells that are in the search bool displayCellsOnlyIfInSearch; }; #endif caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsCells.cxx0000664000175000017500000006723211572067322024554 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #ifdef Q_OS_WIN32 #define NOMINMAX // needed for min/max in algorithm & numeric_limits #endif #include #include #include #include "BrainSet.h" #include "CellFile.h" #include "CellColorFile.h" #include "DisplaySettingsCells.h" #include "DisplaySettingsFoci.h" #include "DisplaySettingsScene.h" #include "DisplaySettingsSection.h" #include "DisplaySettingsStudyMetaData.h" #include "FociColorFile.h" #include "FociFile.h" #include "FociProjectionFile.h" #include "SectionFile.h" #include "StudyMetaDataFile.h" /** * Constructor. */ DisplaySettingsCells::DisplaySettingsCells(BrainSet* bs) : DisplaySettings(bs) { displayCells = false; displayVolumeCells = false; displayFlatCellsRaised = true; displayPasteCellsOnto3D = false; cellSize = 4; symbolOverride = ColorFile::ColorStorage::SYMBOL_NONE; displayCellsOnCorrectHemisphereOnly = true; distanceToSurfaceLimit = 1000.0; cellDisplayMode = CELL_DISPLAY_MODE_SHOW_ALL; cellColorMode = CellBase::CELL_COLOR_MODE_NAME; opacity = 1.0; displayCellsWithoutClassAssignments = true; displayCellsWithoutMatchingColor = true; displayCellsWithoutLinkToStudyWithKeywords = true; displayCellsWithoutLinkToStudyWithTableSubHeader = true; displayCellsOnlyIfInSearch = true; //displayKeywordsForOnlyDisplayedCells = false; reset(); } /** * Destructor. */ DisplaySettingsCells::~DisplaySettingsCells() { } /** * Reinitialize all display settings. */ void DisplaySettingsCells::reset() { } /** * Update selections due to changes in loaded cells. */ void DisplaySettingsCells::update() { determineDisplayedCells(false); } /** * determine which volume cells should be displayed (set's cell display flags). */ void DisplaySettingsCells::determineDisplayedVolumeCells() { const ColorFile* colorFile = brainSet->getCellColorFile(); const int numColors = colorFile->getNumberOfColors(); CellFile* cf = brainSet->getVolumeCellFile(); const int numCells = cf->getNumberOfCells(); for (int j = 0; j < numCells; j++) { CellData* cd = cf->getCell(j); cd->setDisplayFlag(false); // // Check hemisphere // /* bool hemisphereDisplayFlag = false; switch(cd->getCellStructure()) { case Structure::STRUCTURE_TYPE_CORTEX_LEFT: hemisphereDisplayFlag = displayLeftHemisphereCells; break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT: hemisphereDisplayFlag = displayRightHemisphereCells; break; case Structure::STRUCTURE_TYPE_CORTEX_BOTH: case Structure::STRUCTURE_TYPE_CEREBELLUM: case Structure::STRUCTURE_TYPE_INVALID: hemisphereDisplayFlag = true; break; } */ // // Check color selected for display // bool colorDisplayFlag = true; const int colorIndex = cd->getColorIndex(); if ((colorIndex >= 0) && (colorIndex < numColors)) { colorDisplayFlag = colorFile->getSelected(colorIndex); } // // Check class selected // /* bool classDisplayFlag = true; if (fiducialDataFile != NULL) { const int classIndex = cd->getClassIndex(); classDisplayFlag = fiducialDataFile->getCellClassSelectedByIndex(classIndex); } */ // // Set the cell's display flag. // cd->setDisplayFlag( //hemisphereDisplayFlag && colorDisplayFlag //&& classDisplayFlag ); } } /** * Determine cells that are displayed. */ void DisplaySettingsCells::determineDisplayedCells(const bool fociFlag) { DisplaySettingsSection* dss = brainSet->getDisplaySettingsSection(); if (fociFlag == false) { determineDisplayedVolumeCells(); } ColorFile* colorFile = NULL; if (fociFlag) { colorFile = brainSet->getFociColorFile(); } else { colorFile = brainSet->getCellColorFile(); } const int numColors = colorFile->getNumberOfColors(); // // Only use class information in the fiducial foci or cell file // CellProjectionFile* projFile = NULL; if (fociFlag) { projFile = brainSet->getFociProjectionFile(); } else { projFile = brainSet->getCellProjectionFile(); } // // Minimum and maximum displayed section // int minimumSection = std::numeric_limits::min(); int maximumSection = std::numeric_limits::max(); if (fociFlag == false) { SectionFile* sectionFile = brainSet->getSectionFile(); if (sectionFile != NULL) { bool checkSections = false; const int col = dss->getSelectedDisplayColumn(-1, -1); if ((col >= 0) && (col < sectionFile->getNumberOfColumns())) { switch (dss->getSelectionType()) { case DisplaySettingsSection::SELECTION_TYPE_SINGLE: checkSections = true; break; case DisplaySettingsSection::SELECTION_TYPE_MULTIPLE: checkSections = true; break; case DisplaySettingsSection::SELECTION_TYPE_ALL: // // Ignore sections if all sections selected // break; } } if (checkSections) { if ((col >= 0) && (col < sectionFile->getNumberOfColumns())) { minimumSection = dss->getMinimumSelectedSection(); maximumSection = dss->getMaximumSelectedSection(); } } } } const int numCells = projFile->getNumberOfCellProjections(); // // For foci, determine if studies have selected keywords // const StudyMetaDataFile* smdf = brainSet->getStudyMetaDataFile(); std::vector studyKeywordStatus; if (fociFlag) { const DisplaySettingsStudyMetaData* dssmd = brainSet->getDisplaySettingsStudyMetaData(); dssmd->getStudiesWithSelectedKeywords(studyKeywordStatus); dssmd->updateStudyMetaDataTableSubHeaderSelectionFlags(); } for (int j = 0; j < numCells; j++) { CellProjection* cp = projFile->getCellProjection(j); cp->setDisplayFlag(false); // // Check hemisphere // /* bool hemisphereDisplayFlag = false; switch(cp->getCellStructure()) { case Structure::STRUCTURE_TYPE_CORTEX_LEFT: hemisphereDisplayFlag = displayLeftHemisphereCells; break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT: hemisphereDisplayFlag = displayRightHemisphereCells; break; case Structure::STRUCTURE_TYPE_CORTEX_BOTH: case Structure::STRUCTURE_TYPE_CEREBELLUM: case Structure::STRUCTURE_TYPE_INVALID: hemisphereDisplayFlag = true; break; } */ // // Check all/deep/superficial // bool allDeepSuperficialFlag = true; if (fociFlag == false) { switch(cellDisplayMode) { case DisplaySettingsCells::CELL_DISPLAY_MODE_SHOW_ALL: allDeepSuperficialFlag = true; break; case DisplaySettingsCells::CELL_DISPLAY_MODE_SHOW_DEEP_ONLY: if (cp->getSignedDistanceAboveSurface() > 0.0) { allDeepSuperficialFlag = false; } break; case DisplaySettingsCells::CELL_DISPLAY_MODE_SHOW_SUPERFICIAL_ONLY: if (cp->getSignedDistanceAboveSurface() < 0.0) { allDeepSuperficialFlag = false; } break; } } // // Check distance to surface // bool distanceToSurfaceFlag = false; if (fabs(cp->getSignedDistanceAboveSurface()) < distanceToSurfaceLimit) { distanceToSurfaceFlag = true; } // // Check color selected for display // bool colorDisplayFlag = true; if (fociFlag) { colorDisplayFlag = displayCellsWithoutMatchingColor; } const int colorIndex = cp->getColorIndex(); if ((colorIndex >= 0) && (colorIndex < numColors)) { colorDisplayFlag = colorFile->getSelected(colorIndex); } // // Check class selected // bool classDisplayFlag = true; if (fociFlag) { const int classIndex = cp->getClassIndex(); if ((classIndex >= 0) && (cp->getClassName().isEmpty() == false)) { classDisplayFlag = projFile->getCellClassSelectedByIndex(classIndex); } else { classDisplayFlag = displayCellsWithoutClassAssignments; } } // // Check name selected // bool nameDisplayFlag = true; if (fociFlag) { const int uniqueNameIndex = cp->getUniqueNameIndex(); if ((uniqueNameIndex >= 0) && (cp->getName().isEmpty() == false)) { nameDisplayFlag = projFile->getCellUniqueNameSelectedByIndex(uniqueNameIndex); } } // // Check section for cells // bool sectionDisplayFlag = true; if ((cp->getSectionNumber() < minimumSection) || (cp->getSectionNumber() > maximumSection)) { sectionDisplayFlag = false; } // // Check foci search // bool inSearchFlag = true; if (fociFlag) { if (displayCellsOnlyIfInSearch) { inSearchFlag = cp->getInSearchFlag(); } } // // Check foci keywords // bool keywordDisplayFlag = true; if (fociFlag) { // // Initially set as if study has not keywords // keywordDisplayFlag = displayCellsWithoutLinkToStudyWithKeywords; // // Get links // const StudyMetaDataLinkSet smdls = cp->getStudyMetaDataLinkSet(); bool done = false; for (int mm = 0; mm < smdls.getNumberOfStudyMetaDataLinks(); mm++) { const StudyMetaDataLink smdl = smdls.getStudyMetaDataLink(mm); const int smdIndex = smdf->getStudyIndexFromLink(smdl); if ((smdIndex >= 0) && (smdIndex < smdf->getNumberOfStudyMetaData())) { switch (studyKeywordStatus[smdIndex]) { case DisplaySettingsStudyMetaData::KEYWORD_STATUS_KEYWORD_SELECTED: keywordDisplayFlag = true; done = true; // show study break; case DisplaySettingsStudyMetaData::KEYWORD_STATUS_KEYWORD_NOT_SELECTED: keywordDisplayFlag = false; break; case DisplaySettingsStudyMetaData::KEYWORD_STATUS_HAS_NO_KEYWORDS: keywordDisplayFlag = displayCellsWithoutLinkToStudyWithKeywords; break; } } if (done) { break; } } } // // Check foci table subheaders // bool subHeaderDisplayFlag = true; if (fociFlag) { // // Initially set as if study has no table subheader // subHeaderDisplayFlag = displayCellsWithoutLinkToStudyWithTableSubHeader; const StudyMetaDataLinkSet smdls = cp->getStudyMetaDataLinkSet(); for (int mm = 0; mm < smdls.getNumberOfStudyMetaDataLinks(); mm++) { const StudyMetaDataLink smdl = smdls.getStudyMetaDataLink(mm); const int smdIndex = smdf->getStudyIndexFromLink(smdl); if ((smdIndex >= 0) && (smdIndex < smdf->getNumberOfStudyMetaData())) { const StudyMetaData* smd = smdf->getStudyMetaData(smdIndex); const QString tableNumber = smdl.getTableNumber(); const StudyMetaData::Table* table = smd->getTableByTableNumber(tableNumber); if (table != NULL) { const QString subHeaderNumber = smdl.getTableSubHeaderNumber(); const StudyMetaData::SubHeader* subHeader = table->getSubHeaderBySubHeaderNumber(subHeaderNumber); if (subHeader != NULL) { subHeaderDisplayFlag = subHeader->getSelected(); if (subHeaderDisplayFlag) { break; } } } } } } // // Set the cell's display flag. // cp->setDisplayFlag(//hemisphereDisplayFlag && allDeepSuperficialFlag && distanceToSurfaceFlag && colorDisplayFlag && classDisplayFlag && nameDisplayFlag && inSearchFlag && sectionDisplayFlag && keywordDisplayFlag && subHeaderDisplayFlag); } } /** * apply a scene (set display settings). */ void DisplaySettingsCells::showScene(const SceneFile::Scene& scene, QString& errorMessage) { const bool fociFlag = (dynamic_cast(this) != NULL); // // If preserving foci, do not alter scene settings // if (fociFlag) { DisplaySettingsScene* dss = brainSet->getDisplaySettingsScene(); if (dss->getPreserveFociAndFociColorsAndStudyMetaDataFlag()) { return; } } CellProjectionFile* fidCells = brainSet->getCellProjectionFile(); if (fociFlag) { fidCells = brainSet->getFociProjectionFile(); } const int numCellProj = fidCells->getNumberOfCellProjections(); for (int m = 0; m < numCellProj; m++) { CellProjection* cp = fidCells->getCellProjection(m); cp->setHighlightFlag(false); } const int numClasses = scene.getNumberOfSceneClasses(); for (int nc = 0; nc < numClasses; nc++) { const SceneFile::SceneClass* sc = scene.getSceneClass(nc); if (((sc->getName() == "DisplaySettingsCells") && (fociFlag == false)) || ((sc->getName() == "DisplaySettingsFoci") && fociFlag)) { const int num = sc->getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc->getSceneInfo(i); const QString infoName = si->getName(); if (infoName == "displayCells") { si->getValue(displayCells); } else if (infoName == "displayVolumeCells") { si->getValue(displayVolumeCells); } else if (infoName == "displayFlatCellsRaised") { si->getValue(displayFlatCellsRaised); } else if (infoName == "displayPasteCellsOnto3D") { si->getValue(displayPasteCellsOnto3D); } else if (infoName == "drawMode") { // obsolete const int drawMode = si->getValueAsInt(); if (drawMode == 0) { symbolOverride = ColorFile::ColorStorage::SYMBOL_NONE; } else if (drawMode == 1) { symbolOverride = ColorFile::ColorStorage::SYMBOL_OPENGL_POINT; } else if (drawMode == 2) { symbolOverride = ColorFile::ColorStorage::SYMBOL_SPHERE; } } else if (infoName == "cellColorMode") { cellColorMode = static_cast(si->getValueAsInt()); } else if (infoName == "cellSize") { si->getValue(cellSize); } /* else if (infoName == "displayLeftHemisphereCells") { si->getValue(displayLeftHemisphereCells); } else if (infoName == "displayRightHemisphereCells") { si->getValue(displayRightHemisphereCells); } */ else if (infoName == "displayCellsOnCorrectHemisphereOnly") { si->getValue(displayCellsOnCorrectHemisphereOnly); } else if (infoName == "distanceToSurfaceLimit") { si->getValue(distanceToSurfaceLimit); } else if (infoName == "cellDisplayMode") { cellDisplayMode = static_cast(si->getValueAsInt()); } else if (infoName == "symbolOverride") { symbolOverride = ColorFile::ColorStorage::textToSymbol(si->getValueAsString()); } else if (infoName == "displayCellsWithoutClassAssignments") { displayCellsWithoutClassAssignments = si->getValueAsBool(); } else if (infoName == "displayCellsWithoutMatchingColor") { displayCellsWithoutMatchingColor = si->getValueAsBool(); } else if (infoName == "displayCellsWithoutLinkToStudyWithKeywords") { displayCellsWithoutLinkToStudyWithKeywords = si->getValueAsBool(); } else if (infoName == "displayCellsWithoutLinkToStudyWithTableSubHeader") { displayCellsWithoutLinkToStudyWithTableSubHeader = si->getValueAsBool(); } else if (infoName == "displayCellsOnlyIfInSearch") { displayCellsOnlyIfInSearch = si->getValueAsBool(); } else if (infoName == "displayKeywordsForOnlyDisplayedCells") { //displayKeywordsForOnlyDisplayedCells = si->getValueAsBool(); } else if (infoName == "color") { if (fociFlag) { showSceneColorFile(*si, brainSet->getFociColorFile(), "Foci", errorMessage); } else { showSceneColorFile(*si, brainSet->getCellColorFile(), "Cell", errorMessage); } } else if (infoName == "class") { if (fidCells == NULL) { if (fociFlag) { errorMessage.append("No foci are loaded.\n"); } else { errorMessage.append("No cells are loaded.\n"); } } else { const QString name = si->getModelName(); const bool selFlag = si->getValueAsBool(); const int indx = fidCells->getCellClassIndexByName(name); if (indx >= 0) { fidCells->setCellClassSelectedByIndex(indx, selFlag); } else if (name.isEmpty() == false) { QString msg; if (fociFlag) { msg = "Foci "; } else { msg = "Cell "; } msg.append("class \""); msg.append(name); msg.append("\" not found.\n"); errorMessage.append(msg); } } } else if (infoName == "names") { if (fidCells == NULL) { if (fociFlag) { errorMessage.append("No foci are loaded.\n"); } else { errorMessage.append("No cells are loaded.\n"); } } else { const QString name = si->getModelName(); const bool selFlag = si->getValueAsBool(); const int indx = fidCells->getCellUniqueNameIndexByName(name); if (indx >= 0) { fidCells->setCellUniqueNameSelectedByIndex(indx, selFlag); } else if (name.isEmpty() == false) { QString msg; if (fociFlag) { msg = "Foci "; } else { msg = "Cell "; } msg.append("name \""); msg.append(name); msg.append("\" not found.\n"); errorMessage.append(msg); } } } else if (infoName == "HighlightName") { for (int m = 0; m < numCellProj; m++) { CellProjection* cp = fidCells->getCellProjection(m); if (cp->getName() == si->getModelName()) { cp->setHighlightFlag(true); } } } else if (infoName == "CellNumbersInSearch") { QString cellsInSearchString = si->getValueAsString(); QTextStream stream(&cellsInSearchString); int numCellsInSearch; stream >> numCellsInSearch; if (numCellsInSearch == numCellProj) { // // Initially, declare all cells NOT in search // for (int m = 0; m < numCellProj; m++) { CellProjection* cp = fidCells->getCellProjection(m); cp->setInSearchFlag(false); } // // Identify all cells in search // while (stream.atEnd() == false) { int cellNum = -1; stream >> cellNum; if (cellNum >= 0) { fidCells->getCellProjection(cellNum)->setInSearchFlag(true); } } } } } } } } /** * create a scene (read display settings). */ void DisplaySettingsCells::saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& /*errorMessage*/) { const bool fociFlag = (dynamic_cast(this) != NULL); CellProjectionFile* fidCells = brainSet->getCellProjectionFile(); if (fociFlag) { fidCells = brainSet->getFociProjectionFile(); } int numCells = fidCells->getNumberOfCellProjections(); if (onlyIfSelected) { if (numCells <= 0) { return; } } SceneFile::SceneClass sc("DisplaySettingsCells"); if (fociFlag) { sc.setName("DisplaySettingsFoci"); } sc.addSceneInfo(SceneFile::SceneInfo("displayCells", displayCells)); sc.addSceneInfo(SceneFile::SceneInfo("displayVolumeCells", displayVolumeCells)); sc.addSceneInfo(SceneFile::SceneInfo("displayFlatCellsRaised", displayFlatCellsRaised)); sc.addSceneInfo(SceneFile::SceneInfo("displayPasteCellsOnto3D", displayPasteCellsOnto3D)); sc.addSceneInfo(SceneFile::SceneInfo("symbolOverride", ColorFile::ColorStorage::symbolToText(symbolOverride))); sc.addSceneInfo(SceneFile::SceneInfo("cellSize", cellSize)); sc.addSceneInfo(SceneFile::SceneInfo("cellColorMode", static_cast(cellColorMode))); //sc.addSceneInfo(SceneFile::SceneInfo("displayLeftHemisphereCells", displayLeftHemisphereCells)); //sc.addSceneInfo(SceneFile::SceneInfo("displayRightHemisphereCells", displayRightHemisphereCells)); sc.addSceneInfo(SceneFile::SceneInfo("displayCellsOnCorrectHemisphereOnly", displayCellsOnCorrectHemisphereOnly)); sc.addSceneInfo(SceneFile::SceneInfo("distanceToSurfaceLimit", distanceToSurfaceLimit)); sc.addSceneInfo(SceneFile::SceneInfo("cellDisplayMode", cellDisplayMode)); sc.addSceneInfo(SceneFile::SceneInfo("displayCellsWithoutClassAssignments", displayCellsWithoutClassAssignments)); sc.addSceneInfo(SceneFile::SceneInfo("displayCellsWithoutMatchingColor", displayCellsWithoutMatchingColor)); sc.addSceneInfo(SceneFile::SceneInfo("displayCellsWithoutLinkToStudyWithKeywords", displayCellsWithoutLinkToStudyWithKeywords)); sc.addSceneInfo(SceneFile::SceneInfo("displayCellsWithoutLinkToStudyWithTableSubHeader", displayCellsWithoutLinkToStudyWithTableSubHeader)); sc.addSceneInfo(SceneFile::SceneInfo("displayCellsOnlyIfInSearch", displayCellsOnlyIfInSearch)); //sc.addSceneInfo(SceneFile::SceneInfo("displayKeywordsForOnlyDisplayedCells", displayKeywordsForOnlyDisplayedCells)); if (fociFlag) { saveSceneColorFile(sc, "color", brainSet->getFociColorFile()); } else { saveSceneColorFile(sc, "color", brainSet->getCellColorFile()); } // // Classes // if (fidCells != NULL) { const int num = fidCells->getNumberOfCellClasses(); for (int j = 0; j < num; j++) { sc.addSceneInfo(SceneFile::SceneInfo("class", fidCells->getCellClassNameByIndex(j), fidCells->getCellClassSelectedByIndex(j))); } } // // unique names // if (fidCells != NULL) { const int num = fidCells->getNumberOfCellUniqueNames(); for (int j = 0; j < num; j++) { sc.addSceneInfo(SceneFile::SceneInfo("names", fidCells->getCellUniqueNameByIndex(j), fidCells->getCellUniqueNameSelectedByIndex(j))); } } // // Cell highlighting // if (fidCells != NULL) { // // Get list of names of highlighted cells // std::set highlightedNames; const int num = fidCells->getNumberOfCellProjections(); for (int i = 0; i < num; i++) { const CellProjection* cellProj = fidCells->getCellProjection(i); if (cellProj->getHighlightFlag()) { highlightedNames.insert(cellProj->getName()); } } // // Add names to scene file // for (std::set::const_iterator iter = highlightedNames.begin(); iter != highlightedNames.end(); iter++) { sc.addSceneInfo(SceneFile::SceneInfo("HighlightName", *iter, *iter)); } } // // Cell in search flags // if (fociFlag && (fidCells != NULL)) { // // Only add to scene if there are cells that are NOT in the search // bool allInSearch = true; const int num = fidCells->getNumberOfCellProjections(); for (int i = 0; i < num; i++) { const CellProjection* cp = fidCells->getCellProjection(i); if (cp->getInSearchFlag() == false) { allInSearch = false; break; } } if (allInSearch == false) { // // Create a string containing the TOTAL number of cells followed // by a list of cell numbers in the search // QString s(QString::number(num)); for (int i = 0; i < num; i++) { const CellProjection* cp = fidCells->getCellProjection(i); if (cp->getInSearchFlag()) { s += (" " + QString::number(i)); } } sc.addSceneInfo(SceneFile::SceneInfo("CellNumbersInSearch", s)); } } scene.addSceneClass(sc); } caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsBorders.h0000664000175000017500000001254611572067322024535 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_DISPLAY_SETTINGS_BORDERS_H__ #define __VE_DISPLAY_SETTINGS_BORDERS_H__ class BrainSet; #include "ColorFile.h" #include "DisplaySettings.h" /// Display settings for all of the border types class DisplaySettingsBorders : public DisplaySettings { public: /// how to display the borders enum BORDER_DRAW_MODE { BORDER_DRAW_AS_SYMBOLS, BORDER_DRAW_AS_LINES, BORDER_DRAW_AS_SYMBOLS_AND_LINES, BORDER_DRAW_AS_UNSTRETCHED_LINES, BORDER_DRAW_AS_VARIABILITY, BORDER_DRAW_AS_VARIABILITY_AND_LINES }; /// Constructor DisplaySettingsBorders(BrainSet* bs); /// Destructor ~DisplaySettingsBorders(); /// Reinitialize all display settings void reset(); /// Update any selections due to changes in loaded borders void update(); /// get the draw mode BORDER_DRAW_MODE getDrawMode() const { return drawMode; } /// set the draw mode void setDrawMode(const BORDER_DRAW_MODE bdm) { drawMode = bdm; } /// get the border opacity float getOpacity() const { return opacity; } /// set the border opacity void setOpacity(const float o) { opacity = o; } /// get the symbol type ColorFile::ColorStorage::SYMBOL getSymbolType() const { return symbolType; } /// set the symbol type void setSymbolType(const ColorFile::ColorStorage::SYMBOL st) { symbolType = st; } /// get display borders bool getDisplayBorders() const { return displayBorders; } /// set display borders void setDisplayBorders(const bool db) { displayBorders = db; } /// get display raised flat borders bool getDisplayFlatBordersRaised() const { return displayFlatBordersRaised; } /// set display raised flat borders void setDisplayFlatBordersRaised(const bool dfr) { displayFlatBordersRaised = dfr; } /// get display first link in red bool getDisplayFirstLinkRed() const { return displayFirstLinkRed; } /// set display first link in red void setDisplayFirstLinkRed(const bool flr) { displayFirstLinkRed = flr; } /// get display uncertainty vectors (flat only) bool getDisplayUncertaintyVectors() const { return displayFlatUncertaintyVectors; } /// set display uncertainty vectors (flat only) void setDisplayUncertaintyVector(const bool duv) { displayFlatUncertaintyVectors = duv; } /// get the draw borders as stretch lines stretch factor float getDrawAsStretchedLinesStretchFactor() const { return stretchFactor; } /// set the draw borders as stretch lines stretch factor void setDrawAsStretchedLinesStretchFactor(const float sf) { stretchFactor = sf; } /// get border draw size float getDrawSize() const { return borderSize; } /// set border draw size void setDrawSize(const float ds) { borderSize = ds; } /// set border display flag void determineDisplayedBorders(); /// apply a scene (set display settings) virtual void showScene(const SceneFile::Scene& scene, QString& errorMessage) ; /// create a scene (read display settings) virtual void saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& errorMessage); /// get override border colors with area colors bool getOverrideBorderColorsWithAreaColors() const { return overrideBorderColorsWithAreaColors; } /// set override border colors with area colors void setOverrideBorderColorsWithAreaColors(const bool b) { overrideBorderColorsWithAreaColors = b; } private: /// border draw mode BORDER_DRAW_MODE drawMode; /// display borders bool displayBorders; /// show flat borders raised bool displayFlatBordersRaised; /// show first link in red bool displayFirstLinkRed; /// show flat uncertainty vectors bool displayFlatUncertaintyVectors; /// border draw size float borderSize; /// draw borders as stretch lines stretch factor float stretchFactor; /// override border colors with area colors bool overrideBorderColorsWithAreaColors; /// symbol type ColorFile::ColorStorage::SYMBOL symbolType; /// opacity float opacity; }; #endif caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsBorders.cxx0000664000175000017500000002371511572067322025110 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BorderColorFile.h" #include "BorderFile.h" #include "BrainSet.h" #include "BrainModelBorderSet.h" #include "DisplaySettingsBorders.h" /** * Constructor */ DisplaySettingsBorders::DisplaySettingsBorders(BrainSet* bs) : DisplaySettings(bs) { drawMode = BORDER_DRAW_AS_SYMBOLS; displayBorders = false; overrideBorderColorsWithAreaColors = false; displayFlatBordersRaised = true; displayFirstLinkRed = false; displayFlatUncertaintyVectors = false; borderSize = 2; stretchFactor = 10.0; symbolType = ColorFile::ColorStorage::SYMBOL_OPENGL_POINT; opacity = 1.0; reset(); } /** * Destructor */ DisplaySettingsBorders::~DisplaySettingsBorders() { } /** * Reset to default settings */ void DisplaySettingsBorders::reset() { } /** * Updates when files are loaded */ void DisplaySettingsBorders::update() { determineDisplayedBorders(); } /** * Determine which borders should be displayed in all border files. */ void DisplaySettingsBorders::determineDisplayedBorders() { const BorderColorFile* cf = brainSet->getBorderColorFile(); const int numColors = cf->getNumberOfColors(); BrainModelBorderSet* bmbs = brainSet->getBorderSet(); const int numBorders = bmbs->getNumberOfBorders(); for (int j = 0; j < numBorders; j++) { BrainModelBorder* b = bmbs->getBorder(j); bool colorDisplayed = true; const int colorIndex = b->getBorderColorFileIndex(); if ((colorIndex >= 0) && (colorIndex < numColors)) { colorDisplayed = cf->getSelected(colorIndex); } b->setDisplayFlag(displayBorders && colorDisplayed && b->getNameDisplayFlag()); } BorderFile* volumeBorders = bmbs->getVolumeBorders(); const int numVolumeBorders = volumeBorders->getNumberOfBorders(); for (int j = 0; j < numVolumeBorders; j++) { Border* b = volumeBorders->getBorder(j); bool colorDisplayed = true; const int colorIndex = b->getBorderColorIndex(); if ((colorIndex >= 0) && (colorIndex < numColors)) { colorDisplayed = cf->getSelected(colorIndex); } b->setDisplayFlag(displayBorders && colorDisplayed && b->getNameDisplayFlag()); } } /** * apply a scene (set display settings). */ void DisplaySettingsBorders::showScene(const SceneFile::Scene& scene, QString& errorMessage) { const int numClasses = scene.getNumberOfSceneClasses(); for (int nc = 0; nc < numClasses; nc++) { const SceneFile::SceneClass* sc = scene.getSceneClass(nc); if (sc->getName() == "DisplaySettingsBorders") { //BorderColorFile* cf = brainSet->getBorderColorFile(); //const int numColors = cf->getNumberOfColors(); BrainModelBorderSet* bmbs = brainSet->getBorderSet(); const int numBorders = bmbs->getNumberOfBorders(); BorderFile* volumeBorders = bmbs->getVolumeBorders(); const int numVolumeBorders = volumeBorders->getNumberOfBorders(); const int num = sc->getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc->getSceneInfo(i); const QString infoName = si->getName(); if (infoName == "drawMode") { drawMode = static_cast(si->getValueAsInt()); } else if (infoName == "displayBorders") { si->getValue(displayBorders); } else if (infoName == "displayFlatBordersRaised") { si->getValue(displayFlatBordersRaised); } else if (infoName == "displayFirstLinkRed") { si->getValue(displayFirstLinkRed); } else if (infoName == "displayFlatUncertaintyVectors") { si->getValue(displayFlatUncertaintyVectors); } else if (infoName == "overrideBorderColorsWithAreaColors") { si->getValue(overrideBorderColorsWithAreaColors); } else if (infoName == "borderSize") { si->getValue(borderSize); } else if (infoName == "stretchFactor") { si->getValue(stretchFactor); } else if (infoName == "symbolType") { symbolType = ColorFile::ColorStorage::textToSymbol(si->getValueAsString()); } else if (infoName == "color") { showSceneColorFile(*si, brainSet->getBorderColorFile(), "Border", errorMessage); /* const QString name = si->getModelName(); const bool selected = si->getValueAsBool(); bool colorFound = false; for (int j = 0; j < numColors; j++) { ColorFile::ColorStorage* cs = cf->getColor(j); if (cs->getName() == name) { cs->setSelected(selected); colorFound = true; } } if (colorFound == false) { QString msg("Border color \""); msg.append(name); msg.append("\" not found.\n"); errorMessage.append(msg); } */ } else if (infoName == "border-surf") { const QString name = si->getModelName(); const bool selected = si->getValueAsBool(); bool borderFound = false; for (int j = 0; j < numBorders; j++) { BrainModelBorder* b = bmbs->getBorder(j); if (b->getName() == name) { b->setNameDisplayFlag(selected); borderFound = true; } } if (borderFound == false) { QString msg("Surface Border named \""); msg.append(name); msg.append("\" not found.\n"); errorMessage.append(msg); } } else if (infoName == "border-vol") { const QString name = si->getModelName(); const bool selected = si->getValueAsBool(); bool borderFound = false; for (int j = 0; j < numVolumeBorders; j++) { Border* b = volumeBorders->getBorder(j); if (b->getName() == name) { b->setNameDisplayFlag(selected); borderFound = true; } } if (borderFound == false) { QString msg("Volume Border named \""); msg.append(name); msg.append("\" not found.\n"); errorMessage.append(msg); } } } } } } /** * create a scene (read display settings). */ void DisplaySettingsBorders::saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& /*errorMessage*/) { if (onlyIfSelected) { if (displayBorders == false) { return; } BrainModelBorderSet* bmbs = brainSet->getBorderSet(); if (bmbs->getNumberOfBorders() <= 0) { return; } } SceneFile::SceneClass sc("DisplaySettingsBorders"); sc.addSceneInfo(SceneFile::SceneInfo("drawMode", drawMode)); sc.addSceneInfo(SceneFile::SceneInfo("displayBorders", displayBorders)); sc.addSceneInfo(SceneFile::SceneInfo("displayFlatBordersRaised", displayFlatBordersRaised)); sc.addSceneInfo(SceneFile::SceneInfo("displayFirstLinkRed", displayFirstLinkRed)); sc.addSceneInfo(SceneFile::SceneInfo("displayFlatUncertaintyVectors", displayFlatUncertaintyVectors)); sc.addSceneInfo(SceneFile::SceneInfo("borderSize", borderSize)); sc.addSceneInfo(SceneFile::SceneInfo("stretchFactor", stretchFactor)); sc.addSceneInfo(SceneFile::SceneInfo("overrideBorderColorsWithAreaColors", overrideBorderColorsWithAreaColors)); sc.addSceneInfo(SceneFile::SceneInfo("symbolType", ColorFile::ColorStorage::symbolToText(symbolType))); /* const BorderColorFile* cf = brainSet->getBorderColorFile(); const int numColors = cf->getNumberOfColors(); for (int i = 0; i < numColors; i++) { const ColorFile::ColorStorage* cs = cf->getColor(i); sc.addSceneInfo(SceneFile::SceneInfo("color", cs->getName(), cs->getSelected())); } */ saveSceneColorFile(sc, "color", brainSet->getBorderColorFile()); BrainModelBorderSet* bmbs = brainSet->getBorderSet(); const int numBorders = bmbs->getNumberOfBorders(); for (int j = 0; j < numBorders; j++) { BrainModelBorder* b = bmbs->getBorder(j); SceneFile::SceneInfo si("border-surf", b->getName(), b->getNameDisplayFlag()); sc.addSceneInfo(si); } BorderFile* volumeBorders = bmbs->getVolumeBorders(); const int numVolumeBorders = volumeBorders->getNumberOfBorders(); for (int j = 0; j < numVolumeBorders; j++) { Border* b = volumeBorders->getBorder(j); sc.addSceneInfo(SceneFile::SceneInfo("border-vol", b->getName(), b->getNameDisplayFlag())); } scene.addSceneClass(sc); } caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsArealEstimation.h0000664000175000017500000000367111572067322026215 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_DISPLAY_SETTINGS_AREAL_ESTIMATION_H__ #define __VE_DISPLAY_SETTINGS_AREAL_ESTIMATION_H__ #include #include "DisplaySettingsNodeAttributeFile.h" /// DisplaySettingsArealEstimation is a class that maintains parameters for /// controlling the display of areal estimation data. class DisplaySettingsArealEstimation : public DisplaySettingsNodeAttributeFile { public: /// Constructor DisplaySettingsArealEstimation(BrainSet* bs); /// Destructor ~DisplaySettingsArealEstimation(); /// Reinitialize all display settings void reset(); /// Update any selections due to changes in loaded areal estimation file void update(); /// apply a scene (set display settings) virtual void showScene(const SceneFile::Scene& scene, QString& errorMessage) ; /// create a scene (read display settings) virtual void saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& errorMessage); private: }; #endif caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettingsArealEstimation.cxx0000664000175000017500000000663111572067322026567 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "ArealEstimationFile.h" #include "BrainModelSurfaceNodeColoring.h" #include "BrainSet.h" #include "DisplaySettingsArealEstimation.h" #include "FileUtilities.h" /** * The constructor. */ DisplaySettingsArealEstimation::DisplaySettingsArealEstimation(BrainSet* bs) : DisplaySettingsNodeAttributeFile(bs, NULL, bs->getArealEstimationFile(), BrainModelSurfaceOverlay::OVERLAY_AREAL_ESTIMATION, true, false) { reset(); } /** * The destructor. */ DisplaySettingsArealEstimation::~DisplaySettingsArealEstimation() { } /** * Reinitialize all display settings */ void DisplaySettingsArealEstimation::reset() { DisplaySettingsNodeAttributeFile::reset(); } /** * Update any selections due to changes in loaded areal estimation file */ void DisplaySettingsArealEstimation::update() { DisplaySettingsNodeAttributeFile::update(); } static const QString arealEstimationID("areal-estimation-column"); /** * apply a scene (set display settings). */ void DisplaySettingsArealEstimation::showScene(const SceneFile::Scene& scene, QString& errorMessage) { DisplaySettingsNodeAttributeFile::showScene(scene, errorMessage); const int numClasses = scene.getNumberOfSceneClasses(); for (int nc = 0; nc < numClasses; nc++) { const SceneFile::SceneClass* sc = scene.getSceneClass(nc); if (sc->getName() == "DisplaySettingsArealEstimation") { showSceneSelectedColumns(*sc, "Areal Estimation File", arealEstimationID, "", errorMessage); } } } /** * create a scene (read display settings). */ void DisplaySettingsArealEstimation::saveScene(SceneFile::Scene& scene, const bool onlyIfSelected, QString& errorMessage) { DisplaySettingsNodeAttributeFile::saveScene(scene, onlyIfSelected, errorMessage); ArealEstimationFile* aef = brainSet->getArealEstimationFile(); if (onlyIfSelected) { if (aef->getNumberOfColumns() <= 0) { return; } if (brainSet->isASurfaceOverlayForAnySurface( BrainModelSurfaceOverlay::OVERLAY_AREAL_ESTIMATION) == false) { return; } } SceneFile::SceneClass sc("DisplaySettingsArealEstimation"); saveSceneSelectedColumns(sc); scene.addSceneClass(sc); } caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettings.h0000664000175000017500000001460611572067322023213 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_DISPLAY_SETTINGS_H__ #define __VE_DISPLAY_SETTINGS_H__ #include #include "SceneFile.h" class BrainSet; class ColorFile; class GiftiNodeDataFile; class NodeAttributeFile; /// DisplaySettings is an abstract class for controlling the display /// of data files. class DisplaySettings { public: /// destructor virtual ~DisplaySettings(); /// reinitialize all display settings virtual void reset() = 0; /// update any selections due to changes with loaded data files virtual void update() = 0; /// apply a scene (set display settings) virtual void showScene(const SceneFile::Scene& scene, QString& errorMessage) = 0; /// create a scene (read display settings) virtual void saveScene(SceneFile::Scene& scene, const bool onlyIfSelectedFlag, QString& errorMessage) = 0; /// for node attribute files - all column selections for each surface are the same virtual bool columnSelectionsAreTheSame(const int bm1, const int bm2) const; protected: /// constructor DisplaySettings(BrainSet* bsIn); /// Set the default value for selected column of any new surfaces void updateSelectedColumnIndices(const NodeAttributeFile* naf, std::vector& selCol); /// Set the default value for selected column of any new surfaces void updateSelectedColumnIndices(const GiftiNodeDataFile* naf, std::vector& selCol); /// Set the default value for for a column void updateSelectedColumnIndex(const NodeAttributeFile* naf, int& selCol); /// Set the default value for for a column void updateSelectedColumnIndex(const GiftiNodeDataFile* naf, int& selCol); /// apply a scene for node attribute display settings void showSceneNodeAttribute(const SceneFile::SceneClass& sc, const QString& infoName, const NodeAttributeFile* naf, const QString& fileTypeName, std::vector& selectedColumn, QString& errorMessage); /// apply a scene for node attribute display settings void showSceneNodeAttribute(const SceneFile::SceneClass& sc, const QString& infoName, const GiftiNodeDataFile* naf, const QString& fileTypeName, std::vector& selectedColumn, QString& errorMessage); /// create a scene for node attribute display settings void saveSceneNodeAttribute(SceneFile::SceneClass& sc, const QString& infoName, const NodeAttributeFile* naf, const std::vector& selectedColumn); /// create a scene for node attribute display settings void saveSceneNodeAttribute(SceneFile::SceneClass& sc, const QString& infoName, const GiftiNodeDataFile* naf, const std::vector& selectedColumn); /// apply a scene for a node attribute column void showSceneNodeAttributeColumn(const SceneFile::SceneInfo* si, const NodeAttributeFile* naf, const QString& fileTypeName, int& displayColumn, QString& errorMessage); /// apply a scene for a node attribute column void showSceneNodeAttributeColumn(const SceneFile::SceneInfo* si, const GiftiNodeDataFile* naf, const QString& fileTypeName, int& displayColumn, QString& errorMessage); /// create a scene for node attribute display settings void saveSceneNodeAttributeColumn(SceneFile::SceneClass& sc, const QString& infoName, const NodeAttributeFile* naf, const int displayColumn); /// create a scene for node attribute display settings void saveSceneNodeAttributeColumn(SceneFile::SceneClass& sc, const QString& infoName, const GiftiNodeDataFile* naf, const int displayColumn); /// apply scene for a color file void showSceneColorFile(const SceneFile::SceneInfo& si, ColorFile* cf, const QString& errorName, QString& errorMessage); /// save color file settings void saveSceneColorFile(SceneFile::SceneClass& sc, const QString& sceneInfoName, const ColorFile* cf); /// the brain set BrainSet* brainSet; }; #endif caret-5.6.4~dfsg.1.orig/caret_brain_set/DisplaySettings.cxx0000664000175000017500000004355411572067322023572 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainSet.h" #include "ColorFile.h" #include "DisplaySettings.h" #include "FileUtilities.h" #include "GiftiNodeDataFile.h" #include "NodeAttributeFile.h" /** * constructor. */ DisplaySettings::DisplaySettings(BrainSet* bsIn) { brainSet = bsIn; } /** * destructor. */ DisplaySettings::~DisplaySettings() { } /** * Set the default value for selected column of any new surfaces */ void DisplaySettings::updateSelectedColumnIndices(const NodeAttributeFile* naf, std::vector& selCol) { int defValue = 0; // // Determine default value for any new surfaces // const int numModels = brainSet->getNumberOfBrainModels(); if (selCol.empty() == false) { defValue = selCol[0]; const int modelNum = brainSet->getFirstBrainModelSurfaceIndex(); if ((modelNum >= 0) && (modelNum < static_cast(selCol.size()))) { defValue = selCol[modelNum]; } } const int numCols = naf->getNumberOfColumns(); if (defValue >= numCols) { defValue = 0; } else if (defValue < 0) { if (numCols > 0) { defValue = 0; } } // // Resize to number of brain models // selCol.resize(numModels, defValue); // // Reset column indices for any surfaces that may have been deleted // for (int i = 0; i < numModels; i++) { if (selCol[i] >= numCols) { selCol[i] = defValue; } else if (selCol[i] < 0) { selCol[i] = defValue; } } } /** * Set the default value for selected column of any new surfaces */ void DisplaySettings::updateSelectedColumnIndices(const GiftiNodeDataFile* naf, std::vector& selCol) { int defValue = 0; // // Determine default value for any new surfaces // const int numModels = brainSet->getNumberOfBrainModels(); if (selCol.empty() == false) { defValue = selCol[0]; const int modelNum = brainSet->getFirstBrainModelSurfaceIndex(); if ((modelNum >= 0) && (modelNum < static_cast(selCol.size()))) { defValue = selCol[modelNum]; } } const int numCols = naf->getNumberOfColumns(); if (defValue >= numCols) { defValue = 0; } else if (defValue < 0) { if (numCols > 0) { defValue = 0; } } // // Resize to number of brain models // selCol.resize(numModels, defValue); // // Reset column indices for any surfaces that may have been deleted // for (int i = 0; i < numModels; i++) { if (selCol[i] >= numCols) { selCol[i] = defValue; } else if (selCol[i] < 0) { selCol[i] = defValue; } } } /** * Set the default value for for a column */ void DisplaySettings::updateSelectedColumnIndex(const NodeAttributeFile* naf, int& selCol) { // // Reset column indices for any surfaces that may have been deleted // const int numCols = naf->getNumberOfColumns(); if (selCol >= numCols) { selCol = 0; } else if (numCols > 0) { if (selCol < 0) { selCol = 0; } } if (numCols == 0) { selCol = -1; } } /** * Set the default value for for a column */ void DisplaySettings::updateSelectedColumnIndex(const GiftiNodeDataFile* naf, int& selCol) { // // Reset column indices for any surfaces that may have been deleted // const int numCols = naf->getNumberOfColumns(); if (selCol >= numCols) { selCol = 0; } else if (numCols > 0) { if (selCol < 0) { selCol = 0; } } if (numCols == 0) { selCol = -1; } } /** * for node attribute files - all column selections for each surface are the same. */ bool DisplaySettings::columnSelectionsAreTheSame(const int /*bm1*/, const int /*bm2*/) const { return true; } /** * apply a scene for node attribute display settings. */ void DisplaySettings::showSceneNodeAttribute(const SceneFile::SceneClass& sc, const QString& myInfoName, const NodeAttributeFile* naf, const QString& fileTypeName, std::vector& selectedColumn, QString& errorMessage) { const int num = sc.getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc.getSceneInfo(i); const QString infoName = si->getName(); if (infoName == myInfoName) { // // Handle all surfaces or a specific surface // const QString surfaceName = si->getModelName(); int startSurface = 0; int endSurface = brainSet->getNumberOfBrainModels(); if (surfaceName != SceneFile::SceneInfo::getDefaultSurfacesName()) { endSurface = 0; const BrainModelSurface* bms = brainSet->getBrainModelSurfaceWithCoordinateFileName(surfaceName); if (bms != NULL) { startSurface = brainSet->getBrainModelIndex(bms); if (startSurface >= 0) { endSurface = startSurface + 1; } } else { QString msg("Surface named \""); msg.append(surfaceName); msg.append("\" not found.\n"); errorMessage.append(msg); } } // // Get the index of the data column // int columnNum = -1; const QString dataColumnName = si->getValueAsString(); for (int m = 0; m < naf->getNumberOfColumns(); m++) { if (naf->getColumnName(m) == dataColumnName) { columnNum = m; break; } } if (columnNum >= 0) { // // Set the selected column // const int lastIndex = std::min(endSurface, static_cast(selectedColumn.size())); for (int k = startSurface; k < lastIndex; k++) { selectedColumn[k] = columnNum; } } else { QString msg(fileTypeName); msg.append(" column named \""); msg.append(dataColumnName); msg.append("\" not found.\n"); errorMessage.append(msg); } } } } /** * apply a scene for node attribute display settings. */ void DisplaySettings::showSceneNodeAttribute(const SceneFile::SceneClass& sc, const QString& myInfoName, const GiftiNodeDataFile* naf, const QString& fileTypeName, std::vector& selectedColumn, QString& errorMessage) { const int num = sc.getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc.getSceneInfo(i); const QString infoName = si->getName(); if (infoName == myInfoName) { // // Handle all surfaces or a specific surface // const QString surfaceName = si->getModelName(); int startSurface = 0; int endSurface = brainSet->getNumberOfBrainModels(); if (surfaceName != SceneFile::SceneInfo::getDefaultSurfacesName()) { endSurface = 0; const BrainModelSurface* bms = brainSet->getBrainModelSurfaceWithCoordinateFileName(surfaceName); if (bms != NULL) { startSurface = brainSet->getBrainModelIndex(bms); if (startSurface >= 0) { endSurface = startSurface + 1; } } else { QString msg("Surface named \""); msg.append(surfaceName); msg.append("\" not found.\n"); errorMessage.append(msg); } } // // Get the index of the data column // int columnNum = -1; const QString dataColumnName = si->getValueAsString(); for (int m = 0; m < naf->getNumberOfColumns(); m++) { if (naf->getColumnName(m) == dataColumnName) { columnNum = m; break; } } if (columnNum >= 0) { // // Set the selected column // const int lastIndex = std::min(endSurface, static_cast(selectedColumn.size())); for (int k = startSurface; k < lastIndex; k++) { selectedColumn[k] = columnNum; } } else { QString msg(fileTypeName); msg.append(" column named \""); msg.append(dataColumnName); msg.append("\" not found.\n"); errorMessage.append(msg); } } } } /** * create a scene for node attribute display settings. */ void DisplaySettings::saveSceneNodeAttribute(SceneFile::SceneClass& sc, const QString& infoName, const NodeAttributeFile* naf, const std::vector& selectedColumn) { // // Check each brain model // bool didDefaultFlag = false; /* const int num = std::min(brainSet->getNumberOfBrainModels(), std::min(naf->getNumberOfColumns(), static_cast(selectedColumn.size()))); */ const int num = std::min(brainSet->getNumberOfBrainModels(), static_cast(selectedColumn.size())); for (int n = 0; n < num; n++) { // // Is this a surface ? // const BrainModelSurface* bms = brainSet->getBrainModelSurface(n); if (bms != NULL) { const QString dataColumnName(naf->getColumnName(selectedColumn[n])); if (dataColumnName.isEmpty() == false) { // // Do the Default first // if (didDefaultFlag == false) { SceneFile::SceneInfo si(infoName, SceneFile::SceneInfo::getDefaultSurfacesName(), dataColumnName); sc.addSceneInfo(si); didDefaultFlag = true; } // // Get name of coordinate file // const CoordinateFile* cf = bms->getCoordinateFile(); QString surfaceName = FileUtilities::basename(cf->getFileName()); // // Create the scene info for this model // SceneFile::SceneInfo si(infoName, surfaceName, dataColumnName); sc.addSceneInfo(si); } } } } /** * create a scene for node attribute display settings. */ void DisplaySettings::saveSceneNodeAttribute(SceneFile::SceneClass& sc, const QString& infoName, const GiftiNodeDataFile* naf, const std::vector& selectedColumn) { // // Check each brain model // bool didDefaultFlag = false; const int num = std::min(brainSet->getNumberOfBrainModels(), static_cast(selectedColumn.size())); /* const int num = std::min(brainSet->getNumberOfBrainModels(), std::min(naf->getNumberOfColumns(), static_cast(selectedColumn.size()))); */ for (int n = 0; n < num; n++) { // // Is this a surface ? // const BrainModelSurface* bms = brainSet->getBrainModelSurface(n); if (bms != NULL) { const QString dataColumnName(naf->getColumnName(selectedColumn[n])); if (dataColumnName.isEmpty() == false) { // // Do the Default first // if (didDefaultFlag == false) { SceneFile::SceneInfo si(infoName, SceneFile::SceneInfo::getDefaultSurfacesName(), dataColumnName); sc.addSceneInfo(si); didDefaultFlag = true; } // // Get name of coordinate file // const CoordinateFile* cf = bms->getCoordinateFile(); QString surfaceName = FileUtilities::basename(cf->getFileName()); // // Create the scene info for this model // SceneFile::SceneInfo si(infoName, surfaceName, dataColumnName); sc.addSceneInfo(si); } } } } /** * apply a scene for a node attribute column. */ void DisplaySettings::showSceneNodeAttributeColumn(const SceneFile::SceneInfo* si, const NodeAttributeFile* naf, const QString& fileTypeName, int& displayColumn, QString& errorMessage) { const QString colName = si->getValueAsString(); for (int j = 0; j < naf->getNumberOfColumns(); j++) { if (colName == naf->getColumnName(j)) { displayColumn = j; return; } } QString msg(fileTypeName); msg.append(" column named \""); msg.append(colName); msg.append("\" not found.\n"); errorMessage.append(msg); } /** * apply a scene for a node attribute column. */ void DisplaySettings::showSceneNodeAttributeColumn(const SceneFile::SceneInfo* si, const GiftiNodeDataFile* naf, const QString& fileTypeName, int& displayColumn, QString& errorMessage) { const QString colName = si->getValueAsString(); for (int j = 0; j < naf->getNumberOfColumns(); j++) { if (colName == naf->getColumnName(j)) { displayColumn = j; return; } } QString msg(fileTypeName); msg.append(" column named \""); msg.append(colName); msg.append("\" not found.\n"); errorMessage.append(msg); } /** * create a scene for node attribute display settings. */ void DisplaySettings::saveSceneNodeAttributeColumn(SceneFile::SceneClass& sc, const QString& infoName, const NodeAttributeFile* naf, const int displayColumn) { if ((displayColumn >= 0) && (displayColumn < naf->getNumberOfColumns())) { sc.addSceneInfo(SceneFile::SceneInfo(infoName, naf->getColumnName(displayColumn))); } } /** * create a scene for node attribute display settings. */ void DisplaySettings::saveSceneNodeAttributeColumn(SceneFile::SceneClass& sc, const QString& infoName, const GiftiNodeDataFile* naf, const int displayColumn) { if ((displayColumn >= 0) && (displayColumn < naf->getNumberOfColumns())) { sc.addSceneInfo(SceneFile::SceneInfo(infoName, naf->getColumnName(displayColumn))); } } /** * apply scene for a color file. */ void DisplaySettings::showSceneColorFile(const SceneFile::SceneInfo& si, ColorFile* cf, const QString& errorName, QString& errorMessage) { const QString name = si.getModelName(); const bool selected = si.getValueAsBool(); const int numColors = cf->getNumberOfColors(); bool colorFound = false; for (int j = 0; j < numColors; j++) { ColorFile::ColorStorage* cs = cf->getColor(j); if (cs->getName() == name) { cs->setSelected(selected); colorFound = true; } } if (colorFound == false) { QString msg(errorName); msg.append(" color \""); msg.append(name); msg.append("\" not found.\n"); errorMessage.append(msg); } } /** * save color file settings. */ void DisplaySettings::saveSceneColorFile(SceneFile::SceneClass& sc, const QString& sceneInfoName, const ColorFile* cf) { const int numColors = cf->getNumberOfColors(); for (int i = 0; i < numColors; i++) { const ColorFile::ColorStorage* cs = cf->getColor(i); sc.addSceneInfo(SceneFile::SceneInfo(sceneInfoName, cs->getName(), cs->getSelected())); } } caret-5.6.4~dfsg.1.orig/caret_brain_set/CellProjectionUnprojector.h0000664000175000017500000000413211572067322025225 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_CELL_PROJECTION_UNPROJECTOR_H__ #define __VE_CELL_PROJECTION_UNPROJECTOR_H__ #include "CellFile.h" #include "CellProjectionFile.h" #include "BrainModelSurface.h" /// This class is used to unproject cell projections onto a surface class CellProjectionUnprojector { private: /// position of unprojected cell float xyz[3]; /// compute a projection point void computeProjectionPoint(CellProjection& cp, float projection[3]); /// Unproject an inside triangle projection void unprojectInsideTriangle(CellProjection& cp, const CoordinateFile& cf); /// Unproject an outside triangle projection void unprojectOutsideTriangle(CellProjection& cp, const CoordinateFile& cf); /// unproject a cell projection void unprojectCellProjection(CellProjection& cp, const CoordinateFile& s); public: /// Constructor CellProjectionUnprojector(); /// Destructor ~CellProjectionUnprojector(); /// Unproject the cell projections void unprojectCellProjections(CellProjectionFile& cpf, BrainModelSurface* s, CellFile& cf, const int startIndex); }; #endif caret-5.6.4~dfsg.1.orig/caret_brain_set/CellProjectionUnprojector.cxx0000664000175000017500000003321211572067322025601 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #ifdef Q_OS_WIN32 #define NOMINMAX #endif #include #include #include "CellProjectionUnprojector.h" #include "MathUtilities.h" #include "vtkMath.h" #include "vtkTriangle.h" //#include "gaussj.h" //#include "nrutil.h" /** * Constructor. */ CellProjectionUnprojector::CellProjectionUnprojector() { } /** * Destructor. */ CellProjectionUnprojector::~CellProjectionUnprojector() { } /** * Unproject an outside triangle projections. */ void CellProjectionUnprojector::unprojectOutsideTriangle(CellProjection& cp, const CoordinateFile& cf) { const int is = 0; const int js = 1; float v[3], v_t1[3]; MathUtilities::subtractVectors(cp.vertexFiducial[js], cp.vertexFiducial[is], v); MathUtilities::subtractVectors(cp.posFiducial, cp.vertexFiducial[is], v_t1); float s_t2 = MathUtilities::dotProduct(v, v); float s_t3 = MathUtilities::dotProduct(v_t1, v); float QR[3]; for (int j = 0; j < 3; j++) { QR[j] = cp.vertexFiducial[is][j] + ((s_t3/s_t2) * v[j]); } const int pis = cp.vertex[0]; const int pjs = cp.vertex[1]; const float* posPIS = cf.getCoordinate(pis); const float* posPJS = cf.getCoordinate(pjs); MathUtilities::subtractVectors(posPJS, posPIS, v); float QS[3]; if ((cp.fracRI <= 1.0) && (cp.fracRJ <= 1.0)) { for (int j = 0; j < 3; j++) { QS[j] = posPIS[j] + cp.fracRI * v[j]; } } else if ((cp.fracRI > 1.0) && (cp.fracRI > cp.fracRJ)) { MathUtilities::subtractVectors(QR, cp.vertexFiducial[js], v_t1); s_t2 = MathUtilities::vectorLength(v_t1); MathUtilities::subtractVectors(posPJS, posPIS, v); s_t3 = MathUtilities::vectorLength(v); for (int j = 0; j < 3; j++) { QS[j] = posPJS[j] + s_t2 * (v[j]/s_t3); } } else if ((cp.fracRJ > 1.0) && (cp.fracRJ > cp.fracRI)) { MathUtilities::subtractVectors(QR, cp.vertexFiducial[is], v_t1); s_t2 = MathUtilities::vectorLength(v_t1); MathUtilities::subtractVectors(posPIS, posPJS, v); s_t3 = MathUtilities::vectorLength(v); for (int j = 0; j < 3; j++) { QS[j] = posPIS[j] + s_t2 * (v[j]/s_t3); } } else { // printf("CellProjectionFile: Unrecognized case for fracRI and fracRJ: " // "%.2f %.2f\n", fracRI, fracRJ); return; } if ((cp.triVertices[0][0] < 0) || (cp.triVertices[1][0] < 0)) { xyz[0] = 0.0; xyz[1] = 0.0; xyz[2] = 0.0; return; } float normalB[3]; MathUtilities::computeNormal((float*)cf.getCoordinate(cp.triVertices[1][0]), (float*)cf.getCoordinate(cp.triVertices[1][1]), (float*)cf.getCoordinate(cp.triVertices[1][2]), normalB); float normalA[3]; MathUtilities::computeNormal((float*)cf.getCoordinate(cp.triVertices[0][0]), (float*)cf.getCoordinate(cp.triVertices[0][1]), (float*)cf.getCoordinate(cp.triVertices[0][2]), normalA); s_t2 = MathUtilities::dotProduct(normalA, normalB); s_t2 = std::min(s_t2, (float)1.0); // limit to <= 1.0 float phiS = std::acos(s_t2); float thetaS = 0.0; if (cp.phiR > 0.0) { thetaS = (cp.thetaR/cp.phiR) * phiS; } else { thetaS = 0.5 * phiS; } MathUtilities::subtractVectors(posPJS, posPIS, v); MathUtilities::normalize(v); float v_t3[3]; MathUtilities::crossProduct(normalA, v, v_t3); float projection[3] = { 0.0, 0.0, 0.0 }; computeProjectionPoint(cp, projection); MathUtilities::subtractVectors(projection, QR, v_t1); MathUtilities::normalize(v_t1); MathUtilities::subtractVectors(cp.vertexFiducial[js], cp.vertexFiducial[is], v); MathUtilities::normalize(v); float normalA_3D[3]; MathUtilities::computeNormal(cp.triFiducial[0][0], cp.triFiducial[0][1], cp.triFiducial[0][2], normalA_3D); float v_t2[3]; MathUtilities::crossProduct(normalA_3D, v, v_t2); s_t3 = MathUtilities::dotProduct(v_t1, v_t2); float TS[3]; for (int k = 0; k < 3; k++) { TS[k] = QS[k] + (s_t3 * (cp.dR * std::sin(thetaS)) * v_t2[k]); } MathUtilities::subtractVectors(cp.posFiducial, projection, v); MathUtilities::normalize(v); s_t3 = MathUtilities::dotProduct(normalA_3D, v); for (int i = 0; i < 3; i++) { xyz[i] = TS[i] + (cp.dR * s_t3 * std::cos(thetaS)) * normalA[i]; } } /** * Compute the projection point. */ void CellProjectionUnprojector::computeProjectionPoint(CellProjection& cp, float projection[3]) { float v[3], w[3], tnormal[3]; MathUtilities::subtractVectors(cp.triFiducial[0][1], cp.triFiducial[0][0], v); MathUtilities::subtractVectors(cp.triFiducial[0][1], cp.triFiducial[0][2], w); MathUtilities::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] = MathUtilities::dotProduct(v, cp.posFiducial); b[1] = MathUtilities::dotProduct(w, cp.posFiducial); b[2] = MathUtilities::dotProduct(tnormal, cp.triFiducial[0][2]); vtkMath::LinearSolve3x3(a, b, projection); /* float **ta = matrix(1, 3, 1, 3); float **tb = matrix(1, 3, 1, 1); for (int i = 0; i < 3; i++) { tb[i+1][1] = b[i]; for (int j = 0; j < 3; j++) { ta[i+1][j+1] = a[i][j]; } } gaussj(ta, 3, tb, 1); for (int m = 0; m < 3; m++) { projection[m] = tb[1][m+1]; } free_matrix(ta, 1, 3, 1, 1); free_matrix(tb, 1, 3, 1, 1); */ } /** * Unproject an inside triangle projection. */ void CellProjectionUnprojector::unprojectInsideTriangle(CellProjection& cp, const CoordinateFile& cf) { const float* v1 = cf.getCoordinate(cp.closestTileVertices[0]); const float* v2 = cf.getCoordinate(cp.closestTileVertices[1]); const float* v3 = cf.getCoordinate(cp.closestTileVertices[2]); float t1[3], t2[3], t3[3]; for (int i = 0; i < 3; i++) { t1[i] = cp.closestTileAreas[0] * v3[i]; t2[i] = cp.closestTileAreas[1] * v1[i]; t3[i] = cp.closestTileAreas[2] * v2[i]; } const float area = cp.closestTileAreas[0] + cp.closestTileAreas[1] + cp.closestTileAreas[2]; float projection[3] = { 0.0, 0.0, 0.0 }; if (area != 0) { for (int i = 0; i < 3; i++) { projection[i] = (t1[i] + t2[i] + t3[i]) / area; } } // // Note: that does caret4 style clockwise orientation // float tileNormal[3]; MathUtilities::computeNormal((float*)v3, (float*)v2, (float*)v1, tileNormal); for (int j = 0; j < 3; j++) { if (cp.signedDistanceAboveSurface != 0.0) { xyz[j] = projection[j] + tileNormal[j] * cp.signedDistanceAboveSurface; } else { xyz[j] = projection[j] + cp.cdistance[j]; } } } /** * Unproject a cell projection. */ void CellProjectionUnprojector::unprojectCellProjection(CellProjection& cp, const CoordinateFile& cf) { switch(cp.projectionType) { case CellProjection::PROJECTION_TYPE_INSIDE_TRIANGLE: unprojectInsideTriangle(cp, cf); break; case CellProjection::PROJECTION_TYPE_OUTSIDE_TRIANGLE: unprojectOutsideTriangle(cp, cf); break; case CellProjection::PROJECTION_TYPE_UNKNOWN: break; } } /** * Unproject a cell (or foci) projection file. */ void CellProjectionUnprojector::unprojectCellProjections(CellProjectionFile& cpf, BrainModelSurface* s, CellFile& cf, const int startIndex) { if (s == NULL) { return; } const int numProj = cpf.getNumberOfCellProjections(); // // Transfer study info from the cell proj file to the cell file but // only transfer those study info that need to be transferred. // std::vector cellProjFileToCellFileStudyInfoIndex; int numCellProjStudyInfo = cpf.getNumberOfStudyInfo(); if (numCellProjStudyInfo > 0) { // // cellProjFileToCellFileStudyInfoIndex converts cell proj file study info indices // into cell file study info indices // cellProjFileToCellFileStudyInfoIndex.resize(numCellProjStudyInfo, -1); for (int i = startIndex; i < numProj; i++) { // // Get the cell proj file study info index // const int cellProjStudyInfoIndex = cpf.getCellProjection(i)->getStudyNumber(); if (cellProjStudyInfoIndex >= 0) { // // If this cell proj study info index does not yet convert to a cell study info index // if (cellProjFileToCellFileStudyInfoIndex[cellProjStudyInfoIndex] < 0) { // // See if the study is already in the cell file // const int cellStudyInfoIndex = cf.getStudyInfoIndexFromValue((*cpf.getStudyInfo(cellProjStudyInfoIndex))); if (cellStudyInfoIndex >= 0) { // // convert cell proj file study index into existing cell file study index // cellProjFileToCellFileStudyInfoIndex[cellProjStudyInfoIndex] = cellStudyInfoIndex; } else { // // add study info to cell file and convert cell file proj study info index // into cell file study info index // cellProjFileToCellFileStudyInfoIndex[cellProjStudyInfoIndex] = cf.addStudyInfo((*cpf.getStudyInfo(cellProjStudyInfoIndex))); } } } } } for (int i = startIndex; i < numProj; i++) { CellProjection* cp = cpf.getCellProjection(i); xyz[0] = 0.0; xyz[1] = 0.0; xyz[2] = 0.0; if (cp->projectionType != CellProjection::PROJECTION_TYPE_UNKNOWN) { unprojectCellProjection(*cp, *(s->getCoordinateFile())); if (s->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FIDUCIAL) { if (cp->projectionType == CellProjection::PROJECTION_TYPE_OUTSIDE_TRIANGLE) { xyz[0] = cp->posFiducial[0]; xyz[1] = cp->posFiducial[1]; xyz[2] = cp->posFiducial[2]; } switch(cp->structure.getType()) { case Structure::STRUCTURE_TYPE_CORTEX_LEFT: if (xyz[0] > 0.0) xyz[0] = -xyz[0]; break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT: if (xyz[0] < 0.0) xyz[0] = -xyz[0]; break; case Structure::STRUCTURE_TYPE_CORTEX_BOTH: break; case Structure::STRUCTURE_TYPE_CEREBRUM_CEREBELLUM: case Structure::STRUCTURE_TYPE_SUBCORTICAL: case Structure::STRUCTURE_TYPE_ALL: case Structure::STRUCTURE_TYPE_INVALID: break; case Structure::STRUCTURE_TYPE_CEREBELLUM: break; case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_LEFT: break; case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_RIGHT: break; case Structure::STRUCTURE_TYPE_CORTEX_LEFT_OR_CEREBELLUM: break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT_OR_CEREBELLUM: break; } } } int studyNumber = cp->getStudyNumber(); if ((studyNumber >= 0) && (studyNumber < static_cast(cellProjFileToCellFileStudyInfoIndex.size()))) { studyNumber = cellProjFileToCellFileStudyInfoIndex[studyNumber]; } else { studyNumber = -1; } CellData cd(cp->getName(), xyz[0], xyz[1], xyz[2], cp->getSectionNumber(), cp->getClassName(), studyNumber, cp->getColorIndex()); cd.copyCellBaseData(*cp); cd.setClassName(cp->getClassName()); cd.setStudyNumber(studyNumber); cd.setXYZ(xyz); cd.setSignedDistanceAboveSurface(cp->getSignedDistanceAboveSurface()); cd.setCellStructure(cp->structure.getType()); /* switch(cp->hemisphere.getType()) { case Structure::STRUCTURE_TYPE_CORTEX_LEFT: cd.setCellHemisphere(CellData::CELL_IN_LEFT_HEMISPHERE); break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT: cd.setCellHemisphere(CellData::CELL_IN_RIGHT_HEMISPHERE); break; case Hemisphere::HEMISPHERE_UNKNOWN: cd.setCellHemisphere(CellData::CELL_IN_UNKNOWN_HEMISPHERE); break; } */ cf.addCell(cd); } } caret-5.6.4~dfsg.1.orig/caret_brain_set/CellFileProjector.h0000664000175000017500000000636211572067322023434 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_CELL_FILE_PROJECTOR_H__ #define __VE_CELL_FILE_PROJECTOR_H__ class QProgressDialog; class CellData; class CellProjection; class CellProjectionFile; class CoordinateFile; class TopologyFile; class BrainModelSurface; class BrainModelSurfacePointProjector; /// This class is used to project a CellFile to a BrainModelSurface and store the /// results in a cell projection file. class CellFileProjector { public: /// Type of hemisphere projection enum PROJECTION_TYPE { PROJECTION_TYPE_ALL, PROJECTION_TYPE_HEMISPHERE_ONLY, PROJECTION_TYPE_FLIP_TO_MATCH_HEMISPHERE }; /// Constructor CellFileProjector(const BrainModelSurface* bmsIn); /// Destructor ~CellFileProjector(); /// Project the cell projection file using the BrainModelSurface /// passed to the constructor. void projectFile(CellProjectionFile* cpf, const int startWithCell, const PROJECTION_TYPE projectionType, const float projectOntoSurfaceAboveDistance, const bool projectOntoSurface, QWidget* progressDialogParent); /// project a single cell void projectCell(CellProjection& cp, const PROJECTION_TYPE projectionType, const float projectOntoSurfaceAboveDistance, const bool projectOntoSurface); /// update cell number if projected to the cell projection file //int updateCellProjection(const CellFile* cf, const int cellNumber, // CellProjectionFile* cpf, // const PROJECTION_TYPE projectionType); private: /// used to project the cell points BrainModelSurfacePointProjector* pointProjector; /// hemisphere of brain model Structure hemisphere; /// coordinate file used for projecting const CoordinateFile* coordinateFile; /// topology file used for projecting const TopologyFile* topologyFile; /// the brain model surface const BrainModelSurface* bms; /// fiducial surface flag bool fiducialSurfaceFlag; }; #endif // __VE_CELL_FILE_PROJECTOR_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/CellFileProjector.cxx0000664000175000017500000004601511572067322024006 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #ifdef Q_OS_WIN32 #define NOMINMAX #endif #include #include #include #include #include #include "vtkLine.h" #include "vtkMath.h" #include "vtkPlane.h" #include "vtkTriangle.h" #include "BrainModelSurface.h" #include "BrainModelSurfacePointProjector.h" #include "CellFileProjector.h" #include "CellProjectionFile.h" #include "MathUtilities.h" #include "TopologyFile.h" /** * Constructor. */ CellFileProjector::CellFileProjector(const BrainModelSurface* bmsIn) : coordinateFile(bmsIn->getCoordinateFile()), // initialize const members topologyFile(bmsIn->getTopologyFile()), bms(bmsIn) { pointProjector = new BrainModelSurfacePointProjector(bmsIn, BrainModelSurfacePointProjector::SURFACE_TYPE_HINT_OTHER, false); hemisphere = bmsIn->getStructure(); // // Check for fiducial surface // fiducialSurfaceFlag = ((bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_RAW) || (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FIDUCIAL)); } /** * Destructor. */ CellFileProjector::~CellFileProjector() { } /** * Project cell projection file using the BrainModelSurface passed to * the constructor. If "progressDialogParent" is not NULL, a progress dialog will be * displayed while cells are being projected. */ void CellFileProjector::projectFile(CellProjectionFile* cpf, const int startIndex, const PROJECTION_TYPE projectionType, const float projectOntoSurfaceAboveDistance, const bool projectOntoSurface, QWidget* progressDialogParent) { const int numCells = cpf->getNumberOfCellProjections(); if (numCells > 0) { // // Create a progress dialog // QProgressDialog* progressDialog = NULL; if (progressDialogParent != NULL) { progressDialog = new QProgressDialog("Projecting", 0, 0, numCells + 1, progressDialogParent); progressDialog->setWindowTitle("Projecting"); progressDialog->setValue(0); progressDialog->show(); } // // loop through the cells // for (int i = startIndex; i < numCells; i++) { CellProjection* cp = cpf->getCellProjection(i); projectCell(*cp, projectionType, projectOntoSurfaceAboveDistance, projectOntoSurface); // // Set search position to projected position // float xyz[3]; if (cp->getProjectedPosition(coordinateFile, topologyFile, true, false, false, xyz)) { cp->setSearchXYZ(xyz); } if (progressDialog != NULL) { progressDialog->setValue(i + 1); } } // // Remove the progress dialog // if (progressDialog != NULL) { progressDialog->setValue(numCells + 1); delete progressDialog; } } } /** * update a cell projection and return number of cell projection */ /* int CellFileProjector::updateCellProjection(const CellFile* cf, const int cellNumber, CellProjectionFile* cpf, const PROJECTION_TYPE projectionType) { const CellData* cd = cf->getCell(cellNumber); int cellProjUniqueID = cd->getCellProjectionID(); int index = -1; for (int i = 0; i < cpf->getNumberOfCellProjections(); i++) { if (cpf->getCellProjection(i)->getUniqueID() == cellProjUniqueID) { index = i; break; } } if (index >= 0) { CellProjection* cp = cpf->getCellProjection(index); if (projectCell(*cd, *cp, projectionType, 0.0, false)) { const int cellStudyIndex = cd->getStudyNumber(); int cellProjStudyInfoNumber = -1; if (cellStudyIndex >= 0) { int cellProjStudyInfoNumber = cpf->getStudyInfoFromValue((*cf->getStudyInfo(cellStudyIndex))); if (cellProjStudyInfoNumber < 0) { cellProjStudyInfoNumber = cpf->addStudyInfo((*cf->getStudyInfo(cellStudyIndex))); } } cp->setStudyNumber(cellProjStudyInfoNumber); return index; } } return -1; } */ /** * Project a cell. Returns true if the cell was projected. */ void CellFileProjector::projectCell(CellProjection& cp, const PROJECTION_TYPE projectionType, const float projectOntoSurfaceAboveDistance, const bool projectOntoSurface) { // // Get the position of the cell // float xyz[3]; const bool validXYZ = cp.getProjectedPosition(coordinateFile, topologyFile, fiducialSurfaceFlag, false, false, xyz); // // Default to not projected // cp.projectionType = CellProjection::PROJECTION_TYPE_UNKNOWN; // // If position is unknown, cannot project cell // if (validXYZ == false) { return; } // // Set the fiducial position of the cell projection // cp.posFiducial[0] = xyz[0]; cp.posFiducial[1] = xyz[1]; cp.posFiducial[2] = xyz[2]; // // save original hemisphere // if (xyz[0] < 0.0) { cp.structure.setType(Structure::STRUCTURE_TYPE_CORTEX_LEFT); } else { cp.structure.setType(Structure::STRUCTURE_TYPE_CORTEX_RIGHT); } // // Modify position if forcing onto hemisphere // switch (projectionType) { case PROJECTION_TYPE_FLIP_TO_MATCH_HEMISPHERE: if (hemisphere == Structure::STRUCTURE_TYPE_CORTEX_LEFT) { if (xyz[0] > 0.0) xyz[0] = -xyz[0]; } else if (hemisphere == Structure::STRUCTURE_TYPE_CORTEX_RIGHT) { if (xyz[0] < 0.0) xyz[0] = -xyz[0]; } break; case PROJECTION_TYPE_HEMISPHERE_ONLY: if (hemisphere == Structure::STRUCTURE_TYPE_CORTEX_LEFT) { if (xyz[0] > 0.0) return; } else if (hemisphere == Structure::STRUCTURE_TYPE_CORTEX_RIGHT) { if (xyz[0] < 0.0) return; } break; case PROJECTION_TYPE_ALL: break; } int nearestTileNumber, tileNodes[3]; float barycentricAreas[3], distance, distanceComponents[3], signedDistance; // // Project to the surface // const int result = pointProjector->projectBarycentricNearestTile(xyz, nearestTileNumber, tileNodes, barycentricAreas, signedDistance, distance, distanceComponents); // // Signed distance to surface // cp.setSignedDistanceAboveSurface(signedDistance); // // Did cell project inside a tile ? // if (result > 0) { cp.projectionType = CellProjection::PROJECTION_TYPE_INSIDE_TRIANGLE; cp.closestTileVertices[0] = tileNodes[2]; cp.closestTileVertices[1] = tileNodes[1]; cp.closestTileVertices[2] = tileNodes[0]; cp.closestTileAreas[0] = barycentricAreas[1]; cp.closestTileAreas[1] = barycentricAreas[0]; cp.closestTileAreas[2] = barycentricAreas[2]; cp.cdistance[0] = distanceComponents[0]; cp.cdistance[1] = distanceComponents[1]; cp.cdistance[2] = distanceComponents[2]; if (projectOntoSurface) { float tileNormal[3]; MathUtilities::computeNormal((float*)coordinateFile->getCoordinate(tileNodes[0]), (float*)coordinateFile->getCoordinate(tileNodes[1]), (float*)coordinateFile->getCoordinate(tileNodes[2]), tileNormal); cp.cdistance[0] = tileNormal[0] * projectOntoSurfaceAboveDistance; cp.cdistance[1] = tileNormal[1] * projectOntoSurfaceAboveDistance; cp.cdistance[2] = tileNormal[2] * projectOntoSurfaceAboveDistance; cp.signedDistanceAboveSurface = projectOntoSurfaceAboveDistance; } } // // Is cell supposed to be projected onto the surface ? // else if (projectOntoSurface) { const int nearestNode = pointProjector->projectToNearestNode(xyz); if (nearestNode >= 0) { cp.projectionType = CellProjection::PROJECTION_TYPE_INSIDE_TRIANGLE; cp.closestTileVertices[0] = nearestNode; cp.closestTileVertices[1] = nearestNode; cp.closestTileVertices[2] = nearestNode; cp.closestTileAreas[0] = 1.0; cp.closestTileAreas[1] = 1.0; cp.closestTileAreas[2] = 1.0; const float* normal = bms->getNormal(nearestNode); cp.cdistance[0] = normal[0] * projectOntoSurfaceAboveDistance; cp.cdistance[1] = normal[1] * projectOntoSurfaceAboveDistance; cp.cdistance[2] = normal[2] * projectOntoSurfaceAboveDistance; cp.signedDistanceAboveSurface = projectOntoSurfaceAboveDistance; } else { return; } } // // Did cell project outside a tile ? // else if (result < 0) { cp.projectionType = CellProjection::PROJECTION_TYPE_OUTSIDE_TRIANGLE; // // Vertices of closest tile // int v1, v2, v3; topologyFile->getTile(nearestTileNumber, v1, v2, v3); const float* p1 = coordinateFile->getCoordinate(v1); const float* p2 = coordinateFile->getCoordinate(v2); const float* p3 = coordinateFile->getCoordinate(v3); // // cell projected to plane of nearest tile // float planeNormal[3]; MathUtilities::computeNormal(p1, p2, p3, planeNormal); float cellProjectedToPlane[3]; #ifdef HAVE_VTK5 double xyzd[3] = { xyz[0], xyz[1], xyz[2] }; double p1d[3] = { p1[0], p1[1], p1[2] }; double dn[3] = { planeNormal[0], planeNormal[1], planeNormal[2] }; double cellProjD[3]; vtkPlane::ProjectPoint(xyzd, p1d, dn, cellProjD); cellProjectedToPlane[0] = cellProjD[0]; cellProjectedToPlane[1] = cellProjD[1]; cellProjectedToPlane[2] = cellProjD[2]; #else // HAVE_VTK5 vtkPlane::ProjectPoint((float*)xyz, (float*)p1, planeNormal, cellProjectedToPlane); #endif // HAVE_VTK5 // // Find vertices of edge closest to cell projected to plane // int closestVertices[2]; /* VTK DistanceToLine appears to be incorrect. const float dist1 = vtkLine::DistanceToLine((float*)cellProjectedToPlane, (float*)p1, (float*)p2); const float dist2 = vtkLine::DistanceToLine((float*)cellProjectedToPlane, (float*)p2, (float*)p3); const float dist3 = vtkLine::DistanceToLine((float*)cellProjectedToPlane, (float*)p3, (float*)p1); */ const float dist1 = MathUtilities::distancePointToLine3D(xyz, p1, p2); const float dist2 = MathUtilities::distancePointToLine3D(xyz, p2, p3); const float dist3 = MathUtilities::distancePointToLine3D(xyz, p3, p1); if ((dist1 < dist2) && (dist1 < dist3)) { closestVertices[0] = v1; closestVertices[1] = v2; } else if ((dist2 < dist1) && (dist2 < dist3)) { closestVertices[0] = v2; closestVertices[1] = v3; } else { closestVertices[0] = v3; closestVertices[1] = v1; } /* if (vtkMath::Distance2BetweenPoints((float*)xyz, (float*)coordinateFile->getCoordinate(closestVertices[1])) < vtkMath::Distance2BetweenPoints((float*)xyz, (float*)coordinateFile->getCoordinate(closestVertices[0]))) { const int temp = closestVertices[0]; closestVertices[0] = closestVertices[1]; closestVertices[1] = temp; } */ const int iR = closestVertices[0]; const int jR = closestVertices[1]; const int triA = nearestTileNumber; const int triB = topologyFile->getTileWithVertices(iR, jR, triA); float coordJR[3]; coordinateFile->getCoordinate(jR, coordJR); float coordIR[3]; coordinateFile->getCoordinate(iR, coordIR); float normalA[3]; if (triA >= 0){ int v1, v2, v3; topologyFile->getTile(triA, v1, v2, v3); const float* p1 = coordinateFile->getCoordinate(v1); const float* p2 = coordinateFile->getCoordinate(v2); const float* p3 = coordinateFile->getCoordinate(v3); MathUtilities::computeNormal((float*)p1, (float*)p2, (float*)p3, normalA); } float normalB[3]; if (triB >= 0){ int v1, v2, v3; topologyFile->getTile(triB, v1, v2, v3); const float* p1 = coordinateFile->getCoordinate(v1); const float* p2 = coordinateFile->getCoordinate(v2); const float* p3 = coordinateFile->getCoordinate(v3); MathUtilities::computeNormal((float*)p1, (float*)p2, (float*)p3, normalB); } else { cp.dR = std::sqrt(vtkMath::Distance2BetweenPoints(cellProjectedToPlane, xyz)); float v[3]; MathUtilities::subtractVectors(coordJR, coordIR, v); float t1[3]; MathUtilities::subtractVectors(xyz, coordIR, t1); float t2 = MathUtilities::dotProduct(v, v); float t3 = MathUtilities::dotProduct(t1, v); float QR[3]; for (int j = 0; j < 3; j++) QR[j] = coordIR[j] + ((t3/t2) * v[j]); MathUtilities::subtractVectors(coordJR, coordIR, v); t2 = MathUtilities::vectorLength(v); MathUtilities::subtractVectors(QR, coordIR, t1); t3 = MathUtilities::vectorLength(t1); if (t2 > 0.0) cp.fracRI = t3/t2; else cp.fracRI = 0.0; MathUtilities::subtractVectors(coordIR, coordJR, v); t2 = MathUtilities::vectorLength(v); MathUtilities::subtractVectors(QR, coordJR, t1); t3 = MathUtilities::vectorLength(t1); if (t2 > 0.0) cp.fracRJ = t3/t2; else cp.fracRI = 0.0; if (cp.fracRI > 1.0){ for (int j = 0; j < 3; j++) QR[j] = coordJR[j]; } if (cp.fracRJ > 1.0){ for (int j = 0; j < 3; j++) QR [j] = coordIR[j]; } MathUtilities::subtractVectors(xyz, cellProjectedToPlane, t1); t2 = MathUtilities::vectorLength(t1); if (t2 > 0){ for (int j = 0; j < 3; j++) t1[j] = t1[j]/t2; } t3 = MathUtilities::dotProduct(t1, normalA); for (int j = 0; j < 3; j++) xyz[j] = QR[j] + (cp.dR * t3 * normalA[j]); } float v[3]; MathUtilities::subtractVectors(coordJR, coordIR, v); float t1[3]; MathUtilities::subtractVectors(xyz, coordIR, t1); float t2 = MathUtilities::dotProduct(v, v); float t3 = MathUtilities::dotProduct(t1, v); float QR[3]; for (int j = 0; j < 3; j++) QR[j] = coordIR[j] + ((t3/t2) * v[j]); if ((triA >=0) && (triB >= 0)){ t2 = MathUtilities::dotProduct(normalA, normalB); t2 = std::min(t2, (float)1.0); // imit to 1.0 cp.phiR = std::acos(t2); } else cp.phiR = 0.0; MathUtilities::subtractVectors(xyz, QR, t1); t2 = MathUtilities::vectorLength(t1); if (t2 > 0.0){ for (int j = 0; j < 3; j++) t1[j] = t1[j]/t2; } t3 = MathUtilities::dotProduct(normalA, t1); // HAD 11.11.96 Added for H53 where t3 = 0 if (t3 > 0) cp.thetaR = std::acos(t3 * (t3/fabs (t3))); else cp.thetaR = 0.0; MathUtilities::subtractVectors(coordJR, coordIR, v); t2 = MathUtilities::vectorLength(v); MathUtilities::subtractVectors (QR, coordIR, t1); t3 = MathUtilities::vectorLength(t1); if (t2 > 0.0) cp.fracRI = t3/t2; else cp.fracRI = 0.0; MathUtilities::subtractVectors(coordIR, coordJR, v); t2 = MathUtilities::vectorLength(v); MathUtilities::subtractVectors(QR, coordJR, t1); t3 = MathUtilities::vectorLength(t1); if (t2 > 0.0) cp.fracRJ = t3/t2; else cp.fracRJ = 0.0; cp.dR = std::sqrt(vtkMath::Distance2BetweenPoints(QR, xyz)); topologyFile->getTile(triA, cp.triVertices[0]); topologyFile->getTile(triB, cp.triVertices[1]); std::swap(cp.triVertices[0][0], cp.triVertices[0][2]); coordinateFile->getCoordinate(cp.triVertices[0][0], cp.triFiducial[0][0]); coordinateFile->getCoordinate(cp.triVertices[0][1], cp.triFiducial[0][1]); coordinateFile->getCoordinate(cp.triVertices[0][2], cp.triFiducial[0][2]); if (triB >= 0) { std::swap(cp.triVertices[1][0], cp.triVertices[1][2]); coordinateFile->getCoordinate(cp.triVertices[1][0], cp.triFiducial[1][0]); coordinateFile->getCoordinate(cp.triVertices[1][1], cp.triFiducial[1][1]); coordinateFile->getCoordinate(cp.triVertices[1][2], cp.triFiducial[1][2]); } cp.vertexFiducial[0][0] = coordIR[0]; cp.vertexFiducial[0][1] = coordIR[1]; cp.vertexFiducial[0][2] = coordIR[2]; cp.vertexFiducial[1][0] = coordJR[0]; cp.vertexFiducial[1][1] = coordJR[1]; cp.vertexFiducial[1][2] = coordJR[2]; cp.vertex[0] = iR; cp.vertex[1] = jR; } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainSetNodeAttribute.h0000664000175000017500000001207711572067322024266 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_BRAIN_SET_NODE_ATTRIBUTE_H__ #define __VE_BRAIN_SET_NODE_ATTRIBUTE_H__ /// class for node attributes that are common to all surfaces class BrainSetNodeAttribute { public: /// type for highlighting nodes enum HIGHLIGHT_NODE_TYPE { HIGHLIGHT_NODE_NONE, HIGHLIGHT_NODE_LOCAL, HIGHLIGHT_NODE_REMOTE, }; enum CLASSIFICATION_TYPE { CLASSIFICATION_TYPE_INTERIOR, CLASSIFICATION_TYPE_EDGE, CLASSIFICATION_TYPE_CORNER }; enum CROSSOVER_STATUS { CROSSOVER_YES, CROSSOVER_NO, CROSSOVER_DEGENERATE_EDGE }; /// Constructor BrainSetNodeAttribute(); /// Constructor BrainSetNodeAttribute(const int row, const int col, const int node); /// Destructor ~BrainSetNodeAttribute(); /// get flat morphing attributes void getFlatMorphAttributes(int& row, int& column, int& node) const; /// set flat morphing attributes void setFlatMorphAttributes(const int row, const int col, const int node); /// get the spherical morphing attributes void getSphericalMorphingAttributes(int &node, int& tile, int tileNodes[3], float tileAreas[3]) const; /// set the spherical morphing attributes void setSphericalMorphingAttributes(const int node, const int tile, const int tileNodes[3], const float tileAreas[3]); /// get morphing forces void getMorphingForces(float linear[3], float angular[3], float total[3]) const; /// set morphing forces void setMorphingForces(const float linear[3], const float angular[3], const float total[3]); /// set node highlighting void setHighlighting(const HIGHLIGHT_NODE_TYPE hl); /// get node highlighting HIGHLIGHT_NODE_TYPE getHighlighting() const { return highlight; } /// set the node classification void setClassification(const CLASSIFICATION_TYPE ct) { classification = ct; } /// get the node classification CLASSIFICATION_TYPE getClassification() const { return classification; } /// get crossover status CROSSOVER_STATUS getCrossover() const { return crossover; } /// set crossover status void setCrossover(const CROSSOVER_STATUS status) { crossover = status; } /// get visited flag bool getVisited() const { return visited; } /// set visited flag void setVisited(const bool value) { visited = value; } /// reset all parameters to default value void reset(); /// get display flag inline bool getDisplayFlag() const { return displayFlag; } /// set display flag void setDisplayFlag(const bool df) { displayFlag = df; } private: /// the display flag bool displayFlag; /// subsampled grid row (used in flat multiresolution morphing) int morphRow; /// subsampeld grid column (used in flat multiresolution morphing) int morphColumn; /// nearest node in the surface that was subsampled int morphNode; /// tile projected to (used in spherical multiresolution morphing) int morphTile; /// areas of tile projected to (used in spherical multiresolution morphing) float morphTileAreas[3]; /// nodes of tile projected to (used in spherical multiresolution morphing) int morphTileNodes[3]; /// linear morphing force float linearForce[3]; /// angular morphing force float angularForce[3]; /// total morphing force float totalForce[3]; /// node highlighting HIGHLIGHT_NODE_TYPE highlight; /// node classification CLASSIFICATION_TYPE classification; /// crossover status CROSSOVER_STATUS crossover; /// visited flag bool visited; friend class BrainSet; friend class BrainModelSurface; friend class BrainModelSurfaceMultiresolutionMorphing; }; #endif // __VE_BRAIN_MODEL_SURFACE_NODE_ATTRIBUTE_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainSetNodeAttribute.cxx0000664000175000017500000001047011572067322024634 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainSetNodeAttribute.h" /** * Constructor */ BrainSetNodeAttribute::BrainSetNodeAttribute() { reset(); } /** * Constructor */ BrainSetNodeAttribute::BrainSetNodeAttribute(const int row, const int col, const int node) { reset(); morphRow = row; morphColumn = col; morphNode = node; } /** * Destructor */ BrainSetNodeAttribute::~BrainSetNodeAttribute() { } /** * Reset all parameters */ void BrainSetNodeAttribute::reset() { displayFlag = true; morphRow = -1; morphColumn = -1; morphNode = -1; morphTile = -1; morphTileAreas[0] = 0.0; morphTileAreas[1] = 0.0; morphTileAreas[2] = 0.0; morphTileNodes[0] = 0; morphTileNodes[1] = 0; morphTileNodes[2] = 0; highlight = HIGHLIGHT_NODE_NONE; classification = CLASSIFICATION_TYPE_INTERIOR; crossover = CROSSOVER_NO; visited = false; for (int i = 0; i < 3; i++) { linearForce[i] = 0.0; angularForce[i] = 0.0; totalForce[i] = 0.0; } } /** * get flat morphing attributes */ void BrainSetNodeAttribute::getFlatMorphAttributes(int& row, int& col, int& node) const { row = morphRow; col = morphColumn; node = morphNode; } /** * set flat morphing attributes */ void BrainSetNodeAttribute::setFlatMorphAttributes(const int row, const int col, const int node) { morphRow = row; morphColumn = col; morphNode = node; } /** * get the spherical morphing attributes */ void BrainSetNodeAttribute::getSphericalMorphingAttributes(int& node, int& tile, int tileNodes[3], float tileAreas[3]) const { node = morphNode; tile = morphTile; tileNodes[0] = morphTileNodes[0]; tileNodes[1] = morphTileNodes[1]; tileNodes[2] = morphTileNodes[2]; tileAreas[0] = morphTileAreas[0]; tileAreas[1] = morphTileAreas[1]; tileAreas[2] = morphTileAreas[2]; } /** * set the spherical morphing attributes */ void BrainSetNodeAttribute::setSphericalMorphingAttributes(const int node, const int tile, const int tileNodes[3], const float tileAreas[3]) { morphNode = node; morphTile = tile; morphTileNodes[0] = tileNodes[0]; morphTileNodes[1] = tileNodes[1]; morphTileNodes[2] = tileNodes[2]; morphTileAreas[0] = tileAreas[0]; morphTileAreas[1] = tileAreas[1]; morphTileAreas[2] = tileAreas[2]; } /** * get morphing forces */ void BrainSetNodeAttribute::getMorphingForces(float linear[3], float angular[3], float total[3]) const { for (int i = 0; i < 3; i++) { linear[i] = linearForce[i]; angular[i] = angularForce[i]; total[i] = totalForce[i]; } } /** * set morphing forces */ void BrainSetNodeAttribute::setMorphingForces(const float linear[3], const float angular[3], const float total[3]) { for (int i = 0; i < 3; i++) { linearForce[i] = linear[i]; angularForce[i] = angular[i]; totalForce[i] = total[i]; } } /** * Set node highlighting */ void BrainSetNodeAttribute::setHighlighting(const HIGHLIGHT_NODE_TYPE hl) { // // If node already highlighted, clear its highlighting // if ((highlight != HIGHLIGHT_NODE_NONE)) { highlight = HIGHLIGHT_NODE_NONE; } else { highlight = hl; } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainSetMultiThreadedSpecFileReader.h0000664000175000017500000000465611572067322027012 0ustar michaelmichael #ifndef __BRAIN_SET_MULTI_THREADED_SPEC_FILE_READER_H__ #define __BRAIN_SET_MULTI_THREADED_SPEC_FILE_READER_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include "SpecFile.h" class BrainModelAlgorithm; class BrainSet; class QProgressDialog; /// class for multi-hreaded reading of spec file data files class BrainSetMultiThreadedSpecFileReader : public QObject { Q_OBJECT public: // constructor BrainSetMultiThreadedSpecFileReader(BrainSet* brainSetIn); // destructor ~BrainSetMultiThreadedSpecFileReader(); // read the files void readDataFiles(const int numberOfThreads, const SpecFile& specFile, QProgressDialog* progressDialog, std::vector& errorMessagesOut); protected slots: // update the progress dialog void updateProgressDialog(const QString& message); protected: // add data files to the algorithm void addDataFiles(const SpecFile::Entry& specFileEntry); // read files void readFiles(const int numberOfThreads, std::vector& errorMessagesOut); // clear the file readers void clearFileReaders(); // the brain set BrainSet* brainSet; // the file readers std::vector fileReaders; // the progress dialog QProgressDialog* progressDialog; }; #endif // __BRAIN_SET_MULTI_THREADED_SPEC_FILE_READER_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainSetMultiThreadedSpecFileReader.cxx0000664000175000017500000002057711572067322027365 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainModelAlgorithmMultiThreadExecutor.h" #include "BrainSet.h" #include "BrainSetDataFileReader.h" #include "BrainSetMultiThreadedSpecFileReader.h" #include "SpecFile.h" /** * constructor. */ BrainSetMultiThreadedSpecFileReader::BrainSetMultiThreadedSpecFileReader(BrainSet* brainSetIn) { brainSet = brainSetIn; } /** * destructor. */ BrainSetMultiThreadedSpecFileReader::~BrainSetMultiThreadedSpecFileReader() { clearFileReaders(); } /** * clear the file readers. */ void BrainSetMultiThreadedSpecFileReader::clearFileReaders() { for (unsigned int i = 0; i < fileReaders.size(); i++) { delete fileReaders[i]; fileReaders[i] = NULL; } fileReaders.clear(); } /** * add data files to the algorithm. */ void BrainSetMultiThreadedSpecFileReader::addDataFiles(const SpecFile::Entry& specFileEntry) { for (int i = (specFileEntry.getNumberOfFiles() - 1); i >= 0; i--) { if (specFileEntry.getSelected(i) == SpecFile::SPEC_TRUE) { fileReaders.push_back( new BrainSetDataFileReader(brainSet, specFileEntry.getSpecFileTag(), specFileEntry.getFileName(i))); } } } /** * update the progress dialog. */ void BrainSetMultiThreadedSpecFileReader::updateProgressDialog(const QString& message) { if (progressDialog != NULL) { if (message.isEmpty() == false) { QApplication::processEvents(); progressDialog->setValue(progressDialog->value() + 1); progressDialog->setLabelText(message); progressDialog->show(); QApplication::processEvents(); } } } /** * read files. */ void BrainSetMultiThreadedSpecFileReader::readFiles(const int numberOfThreads, std::vector& errorMessagesOut) { BrainModelAlgorithmMultiThreadExecutor executor(fileReaders, numberOfThreads, false); QObject::connect(&executor, SIGNAL(algorithmStartedDescription(const QString&)), this, SLOT(updateProgressDialog(const QString&))); executor.startExecution(); std::vector messages; executor.getExceptionMessages(messages); errorMessagesOut.insert(errorMessagesOut.end(), messages.begin(), messages.end()); clearFileReaders(); } /** * read the files. */ void BrainSetMultiThreadedSpecFileReader::readDataFiles(const int numberOfThreads, const SpecFile& specFile, QProgressDialog* progressDialogIn, std::vector& errorMessagesOut) { errorMessagesOut.clear(); progressDialog = progressDialogIn; // // Read Topology Files (must be read before coordinates) // addDataFiles(specFile.unknownTopoFile); addDataFiles(specFile.lobarCutTopoFile); addDataFiles(specFile.cutTopoFile); addDataFiles(specFile.openTopoFile); addDataFiles(specFile.closedTopoFile); readFiles(numberOfThreads, errorMessagesOut); brainSet->setSelectedTopologyFiles(); // // Read Anatomy volume and Coordinate files // anatomy volume is read here so that it is will be the underlay // addDataFiles(specFile.volumeAnatomyFile); addDataFiles(specFile.rawCoordFile); addDataFiles(specFile.fiducialCoordFile); addDataFiles(specFile.inflatedCoordFile); addDataFiles(specFile.veryInflatedCoordFile); addDataFiles(specFile.sphericalCoordFile); addDataFiles(specFile.ellipsoidCoordFile); addDataFiles(specFile.compressedCoordFile); addDataFiles(specFile.flatCoordFile); addDataFiles(specFile.lobarFlatCoordFile); addDataFiles(specFile.hullCoordFile); addDataFiles(specFile.unknownCoordFile); readFiles(numberOfThreads, errorMessagesOut); // // Read Surface files // addDataFiles(specFile.rawSurfaceFile); addDataFiles(specFile.fiducialSurfaceFile); addDataFiles(specFile.inflatedSurfaceFile); addDataFiles(specFile.veryInflatedSurfaceFile); addDataFiles(specFile.sphericalSurfaceFile); addDataFiles(specFile.ellipsoidSurfaceFile); addDataFiles(specFile.compressedSurfaceFile); addDataFiles(specFile.flatSurfaceFile); addDataFiles(specFile.lobarFlatSurfaceFile); addDataFiles(specFile.hullSurfaceFile); addDataFiles(specFile.unknownSurfaceFile); readFiles(numberOfThreads, errorMessagesOut); // // Read Volume Files except anatomy (do not read until after coordinates) // addDataFiles(specFile.volumeFunctionalFile); addDataFiles(specFile.volumePaintFile); addDataFiles(specFile.volumeProbAtlasFile); addDataFiles(specFile.volumeRgbFile); addDataFiles(specFile.volumeSegmentationFile); addDataFiles(specFile.volumeVectorFile); readFiles(numberOfThreads, errorMessagesOut); // // Read Contour files // addDataFiles(specFile.contourFile); readFiles(numberOfThreads, errorMessagesOut); // // Sort the brain models since their order will vary upon // which reading threads finish first // brainSet->sortBrainModels(); // // Read All other files (after all "BrainModel" files are read) // Read "larger" files first // addDataFiles(specFile.fociProjectionFile); addDataFiles(specFile.surfaceShapeFile); addDataFiles(specFile.metricFile); addDataFiles(specFile.arealEstimationFile); addDataFiles(specFile.borderProjectionFile); addDataFiles(specFile.paintFile); addDataFiles(specFile.atlasFile); addDataFiles(specFile.rgbPaintFile); addDataFiles(specFile.studyMetaDataFile); addDataFiles(specFile.areaColorFile); addDataFiles(specFile.vocabularyFile); addDataFiles(specFile.wustlRegionFile); addDataFiles(specFile.topographyFile); addDataFiles(specFile.geodesicDistanceFile); addDataFiles(specFile.latLonFile); addDataFiles(specFile.paramsFile); addDataFiles(specFile.sceneFile); addDataFiles(specFile.sectionFile); addDataFiles(specFile.deformationFieldFile); addDataFiles(specFile.volumeBorderFile); addDataFiles(specFile.imageFile); addDataFiles(specFile.vtkModelFile); addDataFiles(specFile.paletteFile); addDataFiles(specFile.vectorFile); addDataFiles(specFile.borderColorFile); addDataFiles(specFile.rawBorderFile); addDataFiles(specFile.fiducialBorderFile); addDataFiles(specFile.inflatedBorderFile); addDataFiles(specFile.veryInflatedBorderFile); addDataFiles(specFile.sphericalBorderFile); addDataFiles(specFile.ellipsoidBorderFile); addDataFiles(specFile.compressedBorderFile); addDataFiles(specFile.flatBorderFile); addDataFiles(specFile.lobarFlatBorderFile); addDataFiles(specFile.hullBorderFile); addDataFiles(specFile.unknownBorderFile); addDataFiles(specFile.cellColorFile); addDataFiles(specFile.cellFile); addDataFiles(specFile.volumeCellFile); addDataFiles(specFile.cellProjectionFile); addDataFiles(specFile.cocomacConnectivityFile); addDataFiles(specFile.contourCellFile); addDataFiles(specFile.contourCellColorFile); addDataFiles(specFile.cutsFile); addDataFiles(specFile.fociColorFile); addDataFiles(specFile.fociFile); addDataFiles(specFile.transformationMatrixFile); addDataFiles(specFile.transformationDataFile); addDataFiles(specFile.deformationMapFile); addDataFiles(specFile.cerebralHullFile); readFiles(numberOfThreads, errorMessagesOut); } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainSetDataFileReader.h0000664000175000017500000000332611572067322024306 0ustar michaelmichael #ifndef __BRAIN_SET_DATA_FILE_READER_H__ #define __BRAIN_SET_DATA_FILE_READER_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelAlgorithm.h" /// class for reading a data file class BrainSetDataFileReader : public BrainModelAlgorithm { public: // constructor BrainSetDataFileReader(BrainSet* bsIn, const QString& specFileTagIn, const QString& fileNameIn); // destructor ~BrainSetDataFileReader(); // execute the algorithm void execute() throw (BrainModelAlgorithmException); /// get a text description of algorithm virtual QString getTextDescription() const; protected: /// the spec file tag QString specFileTag; /// the file name QString fileName; }; #endif // __BRAIN_SET_DATA_FILE_READER_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainSetDataFileReader.cxx0000664000175000017500000005460211572067322024664 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurface.h" #include "BrainSet.h" #include "BrainSetDataFileReader.h" #include "FileUtilities.h" #include "SpecFile.h" #include "TopologyFile.h" /** * constructor. */ BrainSetDataFileReader::BrainSetDataFileReader(BrainSet* bsIn, const QString& specFileTagIn, const QString& fileNameIn) : BrainModelAlgorithm(bsIn) { specFileTag = specFileTagIn; fileName = fileNameIn; } /** * destructor. */ BrainSetDataFileReader::~BrainSetDataFileReader() { } /** * execute the algorithm. */ void BrainSetDataFileReader::execute() throw (BrainModelAlgorithmException) { try { if (specFileTag == SpecFile::getClosedTopoFileTag()) { brainSet->readTopologyFile(fileName, TopologyFile::TOPOLOGY_TYPE_CLOSED, true, true); } else if (specFileTag == SpecFile::getOpenTopoFileTag()) { brainSet->readTopologyFile(fileName, TopologyFile::TOPOLOGY_TYPE_OPEN, true, true); } else if (specFileTag == SpecFile::getCutTopoFileTag()) { brainSet->readTopologyFile(fileName, TopologyFile::TOPOLOGY_TYPE_CUT, true, true); } else if (specFileTag == SpecFile::getLobarCutTopoFileTag()) { brainSet->readTopologyFile(fileName, TopologyFile::TOPOLOGY_TYPE_LOBAR_CUT, true, true); } else if (specFileTag == SpecFile::getUnknownTopoFileMatchTag()) { brainSet->readTopologyFile(fileName, TopologyFile::TOPOLOGY_TYPE_UNKNOWN, true, true); } else if (specFileTag == SpecFile::getRawCoordFileTag()) { brainSet->readCoordinateFile(fileName, BrainModelSurface::SURFACE_TYPE_RAW, true, true, true); } else if (specFileTag == SpecFile::getFiducialCoordFileTag()) { brainSet->readCoordinateFile(fileName, BrainModelSurface::SURFACE_TYPE_FIDUCIAL, true, true, true); } else if (specFileTag == SpecFile::getInflatedCoordFileTag()) { brainSet->readCoordinateFile(fileName, BrainModelSurface::SURFACE_TYPE_INFLATED, true, true, true); } else if (specFileTag == SpecFile::getVeryInflatedCoordFileTag()) { brainSet->readCoordinateFile(fileName, BrainModelSurface::SURFACE_TYPE_VERY_INFLATED, true, true, true); } else if (specFileTag == SpecFile::getSphericalCoordFileTag()) { brainSet->readCoordinateFile(fileName, BrainModelSurface::SURFACE_TYPE_SPHERICAL, true, true, true); } else if (specFileTag == SpecFile::getEllipsoidCoordFileTag()) { brainSet->readCoordinateFile(fileName, BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL, true, true, true); } else if (specFileTag == SpecFile::getCompressedCoordFileTag()) { brainSet->readCoordinateFile(fileName, BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL, true, true, true); } else if (specFileTag == SpecFile::getFlatCoordFileTag()) { brainSet->readCoordinateFile(fileName, BrainModelSurface::SURFACE_TYPE_FLAT, true, true, true); } else if (specFileTag == SpecFile::getLobarFlatCoordFileTag()) { brainSet->readCoordinateFile(fileName, BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR, true, true, true); } else if (specFileTag == SpecFile::getHullCoordFileTag()) { brainSet->readCoordinateFile(fileName, BrainModelSurface::SURFACE_TYPE_HULL, true, true, true); } else if (specFileTag == SpecFile::getUnknownCoordFileMatchTag()) { brainSet->readCoordinateFile(fileName, BrainModelSurface::SURFACE_TYPE_UNKNOWN, true, true, true); } else if (specFileTag == SpecFile::getAverageFiducialCoordFileTag()) { // ignore } else if (specFileTag == SpecFile::getRawSurfaceFileTag()) { brainSet->readSurfaceFile(fileName, BrainModelSurface::SURFACE_TYPE_RAW, true, true, true); } else if (specFileTag == SpecFile::getFiducialSurfaceFileTag()) { brainSet->readSurfaceFile(fileName, BrainModelSurface::SURFACE_TYPE_FIDUCIAL, true, true, true); } else if (specFileTag == SpecFile::getInflatedSurfaceFileTag()) { brainSet->readSurfaceFile(fileName, BrainModelSurface::SURFACE_TYPE_INFLATED, true, true, true); } else if (specFileTag == SpecFile::getVeryInflatedSurfaceFileTag()) { brainSet->readSurfaceFile(fileName, BrainModelSurface::SURFACE_TYPE_VERY_INFLATED, true, true, true); } else if (specFileTag == SpecFile::getSphericalSurfaceFileTag()) { brainSet->readSurfaceFile(fileName, BrainModelSurface::SURFACE_TYPE_SPHERICAL, true, true, true); } else if (specFileTag == SpecFile::getEllipsoidSurfaceFileTag()) { brainSet->readSurfaceFile(fileName, BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL, true, true, true); } else if (specFileTag == SpecFile::getCompressedSurfaceFileTag()) { brainSet->readSurfaceFile(fileName, BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL, true, true, true); } else if (specFileTag == SpecFile::getFlatSurfaceFileTag()) { brainSet->readSurfaceFile(fileName, BrainModelSurface::SURFACE_TYPE_FLAT, true, true, true); } else if (specFileTag == SpecFile::getLobarFlatSurfaceFileTag()) { brainSet->readSurfaceFile(fileName, BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR, true, true, true); } else if (specFileTag == SpecFile::getHullSurfaceFileTag()) { brainSet->readSurfaceFile(fileName, BrainModelSurface::SURFACE_TYPE_HULL, true, true, true); } else if (specFileTag == SpecFile::getUnknownSurfaceFileMatchTag()) { brainSet->readSurfaceFile(fileName, BrainModelSurface::SURFACE_TYPE_UNKNOWN, true, true, true); } else if (specFileTag == SpecFile::getVolumeFunctionalFileTag()) { brainSet->readVolumeFile(fileName, VolumeFile::VOLUME_TYPE_FUNCTIONAL, true, true); } else if (specFileTag == SpecFile::getVolumePaintFileTag()) { brainSet->readVolumeFile(fileName, VolumeFile::VOLUME_TYPE_PAINT, true, true); } else if (specFileTag == SpecFile::getVolumeProbAtlasFileTag()) { brainSet->readVolumeFile(fileName, VolumeFile::VOLUME_TYPE_PROB_ATLAS, true, true); } else if (specFileTag == SpecFile::getVolumeRgbFileTag()) { brainSet->readVolumeFile(fileName, VolumeFile::VOLUME_TYPE_RGB, true, true); } else if (specFileTag == SpecFile::getVolumeSegmentationFileTag()) { brainSet->readVolumeFile(fileName, VolumeFile::VOLUME_TYPE_SEGMENTATION, true, true); } else if (specFileTag == SpecFile::getVolumeAnatomyFileTag()) { brainSet->readVolumeFile(fileName, VolumeFile::VOLUME_TYPE_ANATOMY, true, true); } else if (specFileTag == SpecFile::getVolumeVectorFileTag()) { brainSet->readVolumeFile(fileName, VolumeFile::VOLUME_TYPE_VECTOR, true, true); } else if (specFileTag == SpecFile::getTransformationMatrixFileTag()) { brainSet->readTransformationMatrixFile(fileName, true, true); } else if (specFileTag == SpecFile::getTransformationDataFileTag()) { brainSet->readTransformationDataFile(fileName, true, true); } else if (specFileTag == SpecFile::getLatLonFileTag()) { brainSet->readLatLonFile(fileName, true, true); } else if (specFileTag == SpecFile::getSectionFileTag()) { brainSet->readSectionFile(fileName, true, true); } else if (specFileTag == SpecFile::getPaintFileTag()) { brainSet->readPaintFile(fileName, true, true); } else if (specFileTag == SpecFile::getAreaColorFileTag()) { brainSet->readAreaColorFile(fileName, true, true); } else if (specFileTag == SpecFile::getRgbPaintFileTag()) { brainSet->readRgbPaintFile(fileName, true, true); } else if (specFileTag == SpecFile::getVectorFileTag()) { brainSet->readVectorFile(fileName, true, true); } else if (specFileTag == SpecFile::getRawBorderFileTag()) { brainSet->readBorderFile(fileName, BrainModelSurface::SURFACE_TYPE_RAW, true, true); } else if (specFileTag == SpecFile::getFiducialBorderFileTag()) { brainSet->readBorderFile(fileName, BrainModelSurface::SURFACE_TYPE_FIDUCIAL, true, true); } else if (specFileTag == SpecFile::getInflatedBorderFileTag()) { brainSet->readBorderFile(fileName, BrainModelSurface::SURFACE_TYPE_INFLATED, true, true); } else if (specFileTag == SpecFile::getVeryInflatedBorderFileTag()) { brainSet->readBorderFile(fileName, BrainModelSurface::SURFACE_TYPE_VERY_INFLATED, true, true); } else if (specFileTag == SpecFile::getSphericalBorderFileTag()) { brainSet->readBorderFile(fileName, BrainModelSurface::SURFACE_TYPE_SPHERICAL, true, true); } else if (specFileTag == SpecFile::getEllipsoidBorderFileTag()) { brainSet->readBorderFile(fileName, BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL, true, true); } else if (specFileTag == SpecFile::getCompressedBorderFileTag()) { brainSet->readBorderFile(fileName, BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL, true, true); } else if (specFileTag == SpecFile::getFlatBorderFileTag()) { brainSet->readBorderFile(fileName, BrainModelSurface::SURFACE_TYPE_FLAT, true, true); } else if (specFileTag == SpecFile::getLobarFlatBorderFileTag()) { brainSet->readBorderFile(fileName, BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR, true, true); } else if (specFileTag == SpecFile::getHullBorderFileTag()) { brainSet->readBorderFile(fileName, BrainModelSurface::SURFACE_TYPE_HULL, true, true); } else if (specFileTag == SpecFile::getUnknownBorderFileMatchTag()) { brainSet->readBorderFile(fileName, BrainModelSurface::SURFACE_TYPE_UNKNOWN, true, true); } else if (specFileTag == SpecFile::getVolumeBorderFileTag()) { brainSet->readVolumeBorderFile(fileName, true, true); } else if (specFileTag == SpecFile::getBorderColorFileTag()) { brainSet->readBorderColorFile(fileName, true, true); } else if (specFileTag == SpecFile::getBorderProjectionFileTag()) { brainSet->readBorderProjectionFile(fileName, true, true); } else if (specFileTag == SpecFile::getPaletteFileTag()) { brainSet->readPaletteFile(fileName, true, true); } else if (specFileTag == SpecFile::getTopographyFileTag()) { brainSet->readTopographyFile(fileName, true, true); } else if (specFileTag == SpecFile::getCellFileTag()) { brainSet->readCellFile(fileName, true, true); } else if (specFileTag == SpecFile::getCellColorFileTag()) { brainSet->readCellColorFile(fileName, true, true); } else if (specFileTag == SpecFile::getCellProjectionFileTag()) { brainSet->readCellProjectionFile(fileName, true, true); } else if (specFileTag == SpecFile::getVolumeCellFileTag()) { brainSet->readVolumeCellFile(fileName, true, true); } else if (specFileTag == SpecFile::getContourFileTag()) { brainSet->readContourFile(fileName, true, true); } else if (specFileTag == SpecFile::getContourCellFileTag()) { brainSet->readContourCellFile(fileName, true, true); } else if (specFileTag == SpecFile::getContourCellColorFileTag()) { brainSet->readContourCellColorFile(fileName, true, true); } else if (specFileTag == SpecFile::getAtlasFileTag()) { brainSet->readProbabilisticAtlasFile(fileName, true, true); } else if (specFileTag == SpecFile::getMetricFileTag()) { brainSet->readMetricFile(fileName, true, true); } else if (specFileTag == SpecFile::getSurfaceShapeFileTag()) { brainSet->readSurfaceShapeFile(fileName, true, true); } else if (specFileTag == SpecFile::getCocomacConnectivityFileTag()) { brainSet->readCocomacConnectivityFile(fileName, true, true); } else if (specFileTag == SpecFile::getArealEstimationFileTag()) { brainSet->readArealEstimationFile(fileName, true, true); } else if (specFileTag == SpecFile::getCutsFileTag()) { brainSet->readCutsFile(fileName, true, true); } else if (specFileTag == SpecFile::getFociFileTag()) { brainSet->readFociFile(fileName, true, true); } else if (specFileTag == SpecFile::getFociColorFileTag()) { brainSet->readFociColorFile(fileName, true, true); } else if (specFileTag == SpecFile::getFociProjectionFileTag()) { brainSet->readFociProjectionFile(fileName, true, true); } else if (specFileTag == SpecFile::getFociSearchFileTag()) { brainSet->readFociSearchFile(fileName, true, true); } else if (specFileTag == SpecFile::getParamsFileTag()) { brainSet->readParamsFile(fileName, true, true); } else if (specFileTag == SpecFile::getDeformationFieldFileTag()) { brainSet->readDeformationFieldFile(fileName, true, true); } else if (specFileTag == SpecFile::getVtkModelFileTag()) { brainSet->readVtkModelFile(fileName, true, true); } else if (specFileTag == SpecFile::getImageFileTag()) { brainSet->readImageFile(fileName, true, true); } else if (specFileTag == SpecFile::getSceneFileTag()) { brainSet->readSceneFile(fileName, true, true); } else if (specFileTag == SpecFile::getGeodesicDistanceFileTag()) { brainSet->readGeodesicDistanceFile(fileName, true, true); } else if (specFileTag == SpecFile::getStudyMetaDataFileTag()) { brainSet->readStudyMetaDataFile(fileName, true, true); } else if (specFileTag == SpecFile::getVocabularyFileTag()) { brainSet->readVocabularyFile(fileName, true, true); } else if (specFileTag == SpecFile::getWustlRegionFileTag()) { brainSet->readWustlRegionFile(fileName, true, true); } else { const QString msg("Unrecognized spec file tag \"" + specFileTag + "\" passed to BrainSetDataFileReader"); throw BrainModelAlgorithmException(msg); } } catch (FileException& e) { throw BrainModelAlgorithmException(e); } } /** * get a text description of algorithm. */ QString BrainSetDataFileReader::getTextDescription() const { const QString msg("Reading " + FileUtilities::basename(fileName)); return msg; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainSetAutoLoaderManager.h0000664000175000017500000000567611572067322025056 0ustar michaelmichael#ifndef __BRAIN_SET_AUTOLOADER_MANAGER_H__ #define __BRAIN_SET_AUTOLOADER_MANAGER_H__ #include "SceneFile.h" #include "VoxelIJK.h" class BrainSet; class BrainSetAutoLoaderFile; class BrainSetAutoLoaderFileFunctionalVolume; class BrainSetAutoLoaderFileMetric; class BrainSetAutoLoaderFileMetricByNode; class BrainSetAutoLoaderFilePaintCluster; /// processes automatic loading of data files class BrainSetAutoLoaderManager { public: /// number of metric auto loaders enum { NUMBER_OF_METRIC_AUTO_LOADERS = 4 }; /// number of metric node auto loaders enum { NUMBER_OF_METRIC_NODE_AUTO_LOADERS = 4 }; /// number of functional volume auto loaders enum { NUMBER_OF_FUNCTIONAL_VOLUME_AUTO_LOADERS = 1 }; /// number of cluster auto loaders enum { NUMBER_OF_CLUSTER_AUTO_LOADERS = 2 }; // constructor BrainSetAutoLoaderManager(BrainSet* bs); // destructor ~BrainSetAutoLoaderManager(); // process autoloading for a voxel. QString processAutoLoading(const float xyzIn[3]); // Process autoloading for a node. QString processAutoLoading(const int nodeNumber); /// get a metric autoloader BrainSetAutoLoaderFileMetric* getMetricAutoLoader(const int indx); /// get a metric by node autoloader BrainSetAutoLoaderFileMetricByNode* getMetricNodeAutoLoader(const int indx); /// get a functional volume auto loader BrainSetAutoLoaderFileFunctionalVolume* getFunctionalVolumeAutoLoader(const int indx); /// get a cluster auto loader BrainSetAutoLoaderFilePaintCluster* getClusterAutoLoader(const int indx); // see if any auto loaders are selected bool getAnyAutoLoaderSelected(); // reinitialize all display settings void reset(); // update any selections due to changes with loaded data files void update(); // apply a scene (set display settings) void showScene(const SceneFile::Scene& scene, QString& errorMessage); // create a scene (read display settings) void saveScene(SceneFile::Scene& scene, const bool onlyIfSelectedFlag, QString& errorMessage); protected: /// the brain set BrainSet* brainSet; /// metric auto loaders BrainSetAutoLoaderFileMetric* metricAutoLoaders[NUMBER_OF_METRIC_AUTO_LOADERS]; /// metric node auto loaders BrainSetAutoLoaderFileMetricByNode* metricNodeAutoLoaders[NUMBER_OF_METRIC_NODE_AUTO_LOADERS]; /// functional volume auto loaders BrainSetAutoLoaderFileFunctionalVolume* functionalVolumeAutoLoaders[NUMBER_OF_FUNCTIONAL_VOLUME_AUTO_LOADERS]; /// cluster auto loaders BrainSetAutoLoaderFilePaintCluster* clusterAutoLoaders[NUMBER_OF_CLUSTER_AUTO_LOADERS]; /// all of the auto loaders std::vector allFileAutoLoaders; }; #endif /* __BRAIN_SET_AUTOLOADER_MANAGER_H__ */ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainSetAutoLoaderManager.cxx0000664000175000017500000003011711572067322025415 0ustar michaelmichael #include #include "BrainModelSurface.h" #include "BrainModelSurfaceNodeColoring.h" #include "BrainModelSurfaceOverlay.h" #include "BrainSet.h" #include "BrainSetAutoLoaderManager.h" #include "BrainSetAutoLoaderFileFunctionalVolume.h" #include "BrainSetAutoLoaderFileMetric.h" #include "BrainSetAutoLoaderFileMetricByNode.h" #include "BrainSetAutoLoaderFilePaintCluster.h" #include "DebugControl.h" #include "MetricFile.h" #include "VolumeFile.h" /** * constructor. */ BrainSetAutoLoaderManager::BrainSetAutoLoaderManager(BrainSet* bs) { this->brainSet = bs; for (int i = 0; i < NUMBER_OF_METRIC_AUTO_LOADERS; i++) { metricAutoLoaders[i] = new BrainSetAutoLoaderFileMetric(bs, i); allFileAutoLoaders.push_back(metricAutoLoaders[i]); } for (int i = 0; i < NUMBER_OF_METRIC_NODE_AUTO_LOADERS; i++) { metricNodeAutoLoaders[i] = new BrainSetAutoLoaderFileMetricByNode(bs, i); allFileAutoLoaders.push_back(metricNodeAutoLoaders[i]); } for (int i = 0; i < NUMBER_OF_FUNCTIONAL_VOLUME_AUTO_LOADERS; i++) { functionalVolumeAutoLoaders[i] = new BrainSetAutoLoaderFileFunctionalVolume(bs, i); allFileAutoLoaders.push_back(functionalVolumeAutoLoaders[i]); } for (int i = 0; i < NUMBER_OF_CLUSTER_AUTO_LOADERS; i++) { clusterAutoLoaders[i] = new BrainSetAutoLoaderFilePaintCluster(bs, i); allFileAutoLoaders.push_back(clusterAutoLoaders[i]); } } /** * destructor. */ BrainSetAutoLoaderManager::~BrainSetAutoLoaderManager() { } /** * reinitialize all display settings. */ void BrainSetAutoLoaderManager::reset() { for (unsigned int i = 0; i < allFileAutoLoaders.size(); i++) { allFileAutoLoaders[i]->reset(); } } /** * update any selections due to changes with loaded data files. */ void BrainSetAutoLoaderManager::update() { for (unsigned int i = 0; i < allFileAutoLoaders.size(); i++) { allFileAutoLoaders[i]->update(); } } /** * apply a scene (set display settings). */ void BrainSetAutoLoaderManager::showScene(const SceneFile::Scene& scene, QString& errorMessage) { for (unsigned int i = 0; i < allFileAutoLoaders.size(); i++) { allFileAutoLoaders[i]->showScene(scene, errorMessage); } } /** * create a scene (read display settings). */ void BrainSetAutoLoaderManager::saveScene(SceneFile::Scene& scene, const bool onlyIfSelectedFlag, QString& errorMessageOut) { for (unsigned int i = 0; i < allFileAutoLoaders.size(); i++) { allFileAutoLoaders[i]->saveScene(scene, onlyIfSelectedFlag, errorMessageOut); } } /** * get a metric autoloader. */ BrainSetAutoLoaderFileMetric* BrainSetAutoLoaderManager::getMetricAutoLoader(const int indx) { return this->metricAutoLoaders[indx]; } /** * get a metric node autoloader. */ BrainSetAutoLoaderFileMetricByNode* BrainSetAutoLoaderManager::getMetricNodeAutoLoader(const int indx) { return this->metricNodeAutoLoaders[indx]; } /** * get a functional volume autoloader. */ BrainSetAutoLoaderFileFunctionalVolume* BrainSetAutoLoaderManager::getFunctionalVolumeAutoLoader(const int indx) { return this->functionalVolumeAutoLoaders[indx]; } /** * Get a cluster auto loader. */ BrainSetAutoLoaderFilePaintCluster* BrainSetAutoLoaderManager::getClusterAutoLoader(const int indx) { return this->clusterAutoLoaders[indx]; } /** * see if any auto loaders are selected. */ bool BrainSetAutoLoaderManager::getAnyAutoLoaderSelected() { for (unsigned int i = 0; i < allFileAutoLoaders.size(); i++) { if (allFileAutoLoaders[i]->getAutoLoadEnabled()) { return true; } } return false; } /** * Process autoloading for a voxel. */ QString BrainSetAutoLoaderManager::processAutoLoading(const float xyz[3]) { QString errorMessage = ""; for (int i = 0; i < BrainSetAutoLoaderManager::NUMBER_OF_METRIC_AUTO_LOADERS; i++) { const QString indexString = QString::number(i + 1); // // Auto load metric // //int modelIndex = this->getDisplayedBrainModelIndex(); BrainSetAutoLoaderFileMetric* alm = this->getMetricAutoLoader(i); //const int modelIndex = bs->getBrainModelIndex(alm->getAutoLoadMetricDisplaySurface()); if (alm->getAutoLoadEnabled()) { VoxelIJK voxelIJK; // // See if volume selected // VolumeFile* vf = alm->getAutoLoadAnatomyVolumeFile(); if (vf != NULL) { int ijk[3]; float pcoords[3]; if (vf->convertCoordinatesToVoxelIJK(xyz, ijk, pcoords)) { const QString msg = alm->loadFileForVoxel(VoxelIJK(ijk)); if (msg.isEmpty() == false) { errorMessage += msg; } else { voxelIJK.setIJK(ijk); } } } else { errorMessage += "Auto Load Metric " + indexString + " selected but no Anatomical Volume selected.\n"; } alm->setLastAutoLoadAnatomyVoxelIndices(voxelIJK); } } for (int i = 0; i < BrainSetAutoLoaderManager::NUMBER_OF_FUNCTIONAL_VOLUME_AUTO_LOADERS; i++) { const QString indexString = QString::number(i + 1); // // Auto load functional volume // BrainSetAutoLoaderFileFunctionalVolume* alf = this->getFunctionalVolumeAutoLoader(i); if (alf->getAutoLoadEnabled()) { VoxelIJK voxelIJK; // // See if volume selected // VolumeFile* vf = alf->getAutoLoadAnatomyVolumeFile(); if (vf != NULL) { int ijk[3]; float pcoords[3]; if (vf->convertCoordinatesToVoxelIJK(xyz, ijk, pcoords)) { const QString msg = alf->loadFileForVoxel(VoxelIJK(ijk)); if (msg.isEmpty() == false) { errorMessage += msg; } else { voxelIJK.setIJK(ijk); } } } else { errorMessage += "Auto Load functional volume " + indexString + " selected but no Anatomical Volume selected.\n"; } alf->setLastAutoLoadAnatomyVoxelIndices(voxelIJK); } } /* for (int i = 0; i < NUMBER_OF_CLUSTER_AUTO_LOADERS; i++) { BrainSetAutoLoaderFilePaintCluster* alc = this->getClusterAutoLoader(i); if (alc->getAutoLoadEnabled()) { int loadedNodeNumber = -1; const QString msg = alc->loadFileForNode(nodeNumber); if (msg.isEmpty() == false) { errorMessage += msg; } else { loadedNodeNumber = nodeNumber; } alc->setLastAutoLoadNodeNumber(loadedNodeNumber); } } */ return errorMessage; } /** * Process autoloading for a node. */ QString BrainSetAutoLoaderManager::processAutoLoading(const int nodeNumber) { QString errorMessage = ""; for (int i = 0; i < BrainSetAutoLoaderManager::NUMBER_OF_METRIC_NODE_AUTO_LOADERS; i++) { const QString indexString = QString::number(i + 1); // // Auto load metric // BrainSetAutoLoaderFileMetricByNode* alm = this->getMetricNodeAutoLoader(i); if (alm->getAutoLoadEnabled()) { VoxelIJK voxelIJK; if (nodeNumber >= 0) { errorMessage += alm->loadFileForNode(nodeNumber); } else { errorMessage += "No node selected for autoloading metric by node."; } } } for (int i = 0; i < BrainSetAutoLoaderManager::NUMBER_OF_METRIC_AUTO_LOADERS; i++) { const QString indexString = QString::number(i + 1); // // Auto load metric // //int modelIndex = this->getDisplayedBrainModelIndex(); BrainSetAutoLoaderFileMetric* alm = this->getMetricAutoLoader(i); //const int modelIndex = bs->getBrainModelIndex(alm->getAutoLoadMetricDisplaySurface()); if (alm->getAutoLoadEnabled()) { VoxelIJK voxelIJK; if (nodeNumber >= 0) { BrainModelSurface* intersectionSurface = alm->getAutoLoadVolumeIntersectionSurface(); if (intersectionSurface != NULL) { // // Get the node's position // CoordinateFile* cf = intersectionSurface->getCoordinateFile(); float xyz[3]; cf->getCoordinate(nodeNumber, xyz); // // See if volume selected // VolumeFile* vf = alm->getAutoLoadAnatomyVolumeFile(); if (vf != NULL) { int ijk[3]; float pcoords[3]; if (vf->convertCoordinatesToVoxelIJK(xyz, ijk, pcoords)) { const QString msg = alm->loadFileForVoxel(VoxelIJK(ijk)); if (msg.isEmpty() == false) { errorMessage += msg; } else { voxelIJK.setIJK(ijk); } } } else { errorMessage += "Auto Load Metric " + indexString + " selected but no Anatomical Volume selected.\n"; } } else { errorMessage += "Auto Load Metric " + indexString + " selected but no intersection Surface selected.\n"; } } else { errorMessage += "No node selected for autoloading metric."; } alm->setLastAutoLoadAnatomyVoxelIndices(voxelIJK); } } for (int i = 0; i < BrainSetAutoLoaderManager::NUMBER_OF_FUNCTIONAL_VOLUME_AUTO_LOADERS; i++) { const QString indexString = QString::number(i + 1); // // Auto load functional volume // BrainSetAutoLoaderFileFunctionalVolume* alf = this->getFunctionalVolumeAutoLoader(i); if (alf->getAutoLoadEnabled()) { VoxelIJK voxelIJK; if (nodeNumber >= 0) { BrainModelSurface* intersectionSurface = alf->getAutoLoadVolumeIntersectionSurface(); if (intersectionSurface != NULL) { // // Get the node's position // CoordinateFile* cf = intersectionSurface->getCoordinateFile(); float xyz[3]; cf->getCoordinate(nodeNumber, xyz); // // See if volume selected // VolumeFile* vf = alf->getAutoLoadAnatomyVolumeFile(); if (vf != NULL) { int ijk[3]; float pcoords[3]; if (vf->convertCoordinatesToVoxelIJK(xyz, ijk, pcoords)) { const QString msg = alf->loadFileForVoxel(VoxelIJK(ijk)); if (msg.isEmpty() == false) { errorMessage += msg; } else { voxelIJK.setIJK(ijk); } } } else { errorMessage += "Auto Load functional volume " + indexString + " selected but no Anatomical Volume selected.\n"; } } else { errorMessage += "Auto Load functional volume " + indexString + " selected but no intersection Surface selected.\n"; } } else { errorMessage += "No node selected for autoloading metric."; } alf->setLastAutoLoadAnatomyVoxelIndices(voxelIJK); } } for (int i = 0; i < NUMBER_OF_CLUSTER_AUTO_LOADERS; i++) { BrainSetAutoLoaderFilePaintCluster* alc = this->getClusterAutoLoader(i); if (alc->getAutoLoadEnabled()) { int loadedNodeNumber = -1; const QString msg = alc->loadFileForNode(nodeNumber); if (msg.isEmpty() == false) { errorMessage += msg; } else { loadedNodeNumber = nodeNumber; } alc->setLastAutoLoadNodeNumber(loadedNodeNumber); } } return errorMessage; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainSetAutoLoaderFilePaintCluster.h0000664000175000017500000000732411572067322026711 0ustar michaelmichael#ifndef __BRAIN_SET_AUTO_LOADER_FILE_PAINT_CLUSTER_H__ #define __BRAIN_SET_AUTO_LOADER_FILE_PAINT_CLUSTER_H__ #include "BrainSetAutoLoaderFile.h" #include "SceneFile.h" class BrainModelSurface; class VolumeFile; class BrainSetAutoLoaderFilePaintCluster : public BrainSetAutoLoaderFile { public: /// constructor BrainSetAutoLoaderFilePaintCluster(BrainSet* bsIn, const int autoLoaderIndexIn); /// destructor ~BrainSetAutoLoaderFilePaintCluster(); /// reinitialize all display settings void reset(); /// update any selections due to changes with loaded data files void update(); /// apply a scene (set display settings) void showScene(const SceneFile::Scene& scene, QString& errorMessage); /// create a scene (read display settings) void saveScene(SceneFile::Scene& scene, const bool onlyIfSelectedFlag, QString& errorMessage); /** get the auto load display surface */ BrainModelSurface* getAutoLoadDisplaySurface() { return this->autoLoadDisplaySurface; } /** set the auto load display surface */ void setAutoLoadDisplaySurface(BrainModelSurface* bms) { this->autoLoadDisplaySurface = bms; } /** * Get the last auto-loaded cluster metric column number. */ int getAutoLoadLastMetricColumnNumber() const { return this->autoLoadClusterLastMetricColumnNumber; } /** * Set the last auto-loaded paint cluster number. */ void setAutoLoadLastMetricColumnNumber(const int columnNumber) { this->autoLoadClusterLastMetricColumnNumber = columnNumber; } // auto load the metric and volume file for the specified node (return error message) QString loadFileForNode(const int nodeNumber); /** * Get the last auto-loaded functional volume. */ VolumeFile* getAutoLoadLastFunctionalVolume() { return this->autoLoadClusterLastFunctionalVolume; } /** * Set the last auto-loaded functional volume. */ void setAutoLoadLastFunctionalVolume(VolumeFile* vf) { this->autoLoadClusterLastFunctionalVolume = vf; } // Get the last auto load node number. int getLastAutoLoadNodeNumber() const; // Set the last auto load node number. void setLastAutoLoadNodeNumber(const int nodeNumber); /// get the selected paint column number int getPaintColumnNumber(); /// set the selected paint column number void setPaintColumnNumber(const int columnNumber); /// Auto load the metric file for the specified voxel (return error message). QString loadFileForVoxel(const VoxelIJK& /*voxel*/) { return ""; } // NOT USED protected: /// get the number of previously node numbers. */ int getNumberOfPreviouslyLoadedNodeNumbers() const { return previouslyLoadedNodeNumbers.size(); } /// get a previously node number (zero index is oldest). int getPreviouslyLoadedNodeNumber(const int indx) const { return previouslyLoadedNodeNumbers[indx]; } /// auto load cluster display surface BrainModelSurface* autoLoadDisplaySurface; /// column number of last auto-loaded metric (DO NOT SAVE TO SCENE) int autoLoadClusterLastMetricColumnNumber; /// last auto loaded functional volume (do not save to scene) VolumeFile* autoLoadClusterLastFunctionalVolume; /// previously loaded node numbers std::vector previouslyLoadedNodeNumbers; /// selected paint column number int paintColumnNumber; }; #endif /* __BRAIN_SET_AUTO_LOADER_FILE_PAINT_CLUSTER_H__ */ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainSetAutoLoaderFilePaintCluster.cxx0000664000175000017500000004036111572067322027262 0ustar michaelmichael#include #include #include #include #include "BrainModelSurface.h" #include "BrainModelSurfaceNodeColoring.h" #include "BrainModelSurfaceOverlay.h" #include "BrainModelVolumeVoxelColoring.h" #include "BrainSet.h" #include "BrainSetAutoLoaderFilePaintCluster.h" #include "DisplaySettingsMetric.h" #include "DisplaySettingsVolume.h" #include "DebugControl.h" #include "MetricFile.h" #include "PaintFile.h" #include "StringUtilities.h" #include "VolumeFile.h" #include "VoxelIJK.h" /** * constructor. */ BrainSetAutoLoaderFilePaintCluster::BrainSetAutoLoaderFilePaintCluster(BrainSet* bsIn, const int autoLoaderIndexIn) : BrainSetAutoLoaderFile(bsIn, autoLoaderIndexIn) { reset(); } /** * destructor. */ BrainSetAutoLoaderFilePaintCluster::~BrainSetAutoLoaderFilePaintCluster() { } /** * reinitialize all display settings. */ void BrainSetAutoLoaderFilePaintCluster::reset() { BrainSetAutoLoaderFile::reset(); autoLoadDisplaySurface = NULL; autoLoadClusterLastFunctionalVolume = NULL; autoLoadClusterLastMetricColumnNumber = -1; previouslyLoadedNodeNumbers.clear(); paintColumnNumber = -1; } /** * update any selections due to changes with loaded data files. */ void BrainSetAutoLoaderFilePaintCluster::update() { BrainSetAutoLoaderFile::update(); //validate volume, surface, etc //brainSet->getVolumeAnatomyFileByName(const QString& filename); //brainSet->getBrainModelSurfaceByCoordinateFileName(const QString& filename); } /** * apply a scene (set display settings). */ void BrainSetAutoLoaderFilePaintCluster::showScene(const SceneFile::Scene& scene, QString& /*errorMessage*/) { reset(); const int numClasses = scene.getNumberOfSceneClasses(); for (int nc = 0; nc < numClasses; nc++) { const SceneFile::SceneClass* sc = scene.getSceneClass(nc); if (sc->getName().startsWith("BrainSetAutoLoaderFilePaintCluster")) { std::vector tokens; StringUtilities::token(sc->getName(), ":", tokens); int indx = -1; if (tokens.size() > 1) { indx = tokens[1].toInt(); } if (indx == this->autoLoaderIndex) { const int num = sc->getNumberOfSceneInfo(); // // parent class data // showSceneHelper(*sc); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc->getSceneInfo(i); const QString infoName = si->getName(); if (infoName == "autoLoadDisplaySurface") { autoLoadDisplaySurface = brainSet->getBrainModelSurfaceWithCoordinateFileName(si->getValueAsString()); } else if (infoName == "previouslyLoadedNodeNumbers") { previouslyLoadedNodeNumbers.push_back(si->getValueAsInt()); } else if (infoName == "paintColumnNumber") { PaintFile* pf = brainSet->getPaintFile(); paintColumnNumber = pf->getColumnWithName(si->getValueAsString()); } } } } } // // Autoload any previously loaded voxels // int num = getNumberOfPreviouslyLoadedNodeNumbers(); for (int i = 0; i < num; i++) { if (this->autoLoadEnabledFlag) { this->loadFileForNode(this->getPreviouslyLoadedNodeNumber(i)); } } } /** * create a scene (read display settings). */ void BrainSetAutoLoaderFilePaintCluster::saveScene(SceneFile::Scene& scene, const bool /*onlyIfSelectedFlag*/, QString& /*errorMessage*/) { //MetricFile* mf = brainSet->getMetricFile(); SceneFile::SceneClass sc("BrainSetAutoLoaderFilePaintCluster:" + QString::number(this->autoLoaderIndex)); for (unsigned int i = 0; i < previouslyLoadedNodeNumbers.size(); i++) { sc.addSceneInfo(SceneFile::SceneInfo("previouslyLoadedNodeNumbers", previouslyLoadedNodeNumbers[i])); } PaintFile* pf = brainSet->getPaintFile(); if ((paintColumnNumber >= 0) && (paintColumnNumber < pf->getNumberOfColumns())) { sc.addSceneInfo(SceneFile::SceneInfo("paintColumnNumber", pf->getColumnName(paintColumnNumber))); } if (autoLoadDisplaySurface != NULL) { sc.addSceneInfo(SceneFile::SceneInfo("autoLoadDisplaySurface", autoLoadDisplaySurface->getCoordinateFile()->getFileName())); } saveSceneHelper(sc); // DO NOT add to scene //sc.addSceneInfo(SceneFile::SceneInfo("autoLoadMetricLastColumnNumber", // autoLoadMetricLastColumnNumber)); scene.addSceneClass(sc); } /** * Auto load the metric file for the specified node (return error message). */ QString BrainSetAutoLoaderFilePaintCluster::loadFileForNode(const int nodeNumber) { QString errorMessage = ""; if ((nodeNumber < 0) || (nodeNumber >= brainSet->getNumberOfNodes())) { return ""; } // // Clear node highlighting // brainSet->clearNodeHighlightSymbols(); // // Remove previously loaded metric column // MetricFile* mf = brainSet->getMetricFile(); int lastCol = this->getAutoLoadLastMetricColumnNumber(); if (this->getAutoLoadReplaceLastFileEnabled() && (lastCol >= 0) && (lastCol < mf->getNumberOfColumns())) { mf->removeColumn(lastCol); brainSet->getDisplaySettingsMetric()->update(); this->setAutoLoadLastMetricColumnNumber(-1); lastCol = -1; } // // Remove previously loaded functional volume // DisplaySettingsVolume* dsv = brainSet->getDisplaySettingsVolume(); VolumeFile* lastVolume = this->getAutoLoadLastFunctionalVolume(); if (this->getAutoLoadReplaceLastFileEnabled() && (lastVolume != NULL)) { brainSet->deleteVolumeFile(lastVolume); this->setAutoLoadLastFunctionalVolume(NULL); dsv->update(); lastVolume = NULL; } if (DebugControl::getDebugOn()) { std::cout << "Cluster Auto Load Node: " << nodeNumber << std::endl; } const QString metricDirectoryName = this->getAutoLoadDirectoryName(); const QString functionalVolumeDirectoryName = this->getAutoLoadSecondaryDirectoryName(); int loadedMetricColumn = -1; VolumeFile* loadedFunctionalVolume = NULL; if (metricDirectoryName.isEmpty() && functionalVolumeDirectoryName.isEmpty()) { errorMessage += "Both metric and functional volume directory names are empty."; } bool metricDirectoryNameValid = false; if (metricDirectoryName.isEmpty() == false) { if (QFile::exists(metricDirectoryName) == false) { errorMessage += "Auto Load Cluster selected but metric directory (" + metricDirectoryName + ") is invalid.\n"; } else { metricDirectoryNameValid = true; } } bool functionalVolumeDirectoryNameValidFlag = false; if (functionalVolumeDirectoryName.isEmpty() == false) { if (QFile::exists(functionalVolumeDirectoryName) == false) { errorMessage += "Auto Load Cluster selected but functional volume directory (" + functionalVolumeDirectoryName + ") is invalid.\n"; } else { functionalVolumeDirectoryNameValidFlag = true; } } PaintFile* pf = brainSet->getPaintFile(); const int paintIndex = pf->getPaint(nodeNumber, paintColumnNumber); if (paintIndex >= 0) { const QString paintName = pf->getPaintNameFromIndex(paintIndex); const int paintNameNumber = paintName.toInt(); //std::cout << "Paint Name: " << paintName.toAscii().constData() << std::endl; const QString reMetricString(".*_(.+)" + SpecFile::getMetricFileExtension()); QRegExp metricRE(reMetricString, Qt::CaseInsensitive); const QString reFunctionalVolumeString(".*(\\d+)" + SpecFile::getNiftiGzipVolumeFileExtension()); QRegExp functionalVolumeRE(reFunctionalVolumeString, Qt::CaseInsensitive); QString metricFileNameToLoad = ""; if (metricDirectoryNameValid) { QDir metricDir(metricDirectoryName); QStringList metricFileList = metricDir.entryList(QDir::Files); for (int ni = 0; ni < metricFileList.size(); ni++) { const QString fileName = metricFileList.at(ni); if (metricRE.exactMatch(fileName)) { QStringList matches = metricRE.capturedTexts(); if (matches.size() >= 2) { //std::cout << "Filename: " << fileName.toAscii().constData() << std::endl; //std::cout << "Match 0: " << matches.at(0).toAscii().constData() << std::endl; //std::cout << "Match 1: " << matches.at(1).toAscii().constData() << std::endl; // // Note: 1st capture is the entire string // //const int filePaintNumber = matches.at(1).toInt(); //if (paintNameNumber == filePaintNumber) { QString theMatch = matches.at(1); if (paintName == theMatch) { const QString fullPath = metricDirectoryName + "/" + fileName; metricFileNameToLoad = fullPath; break; } } } } } QString functionalVolumeFileNameToLoad = ""; if (functionalVolumeDirectoryNameValidFlag) { QDir functionalVolumeDir(functionalVolumeDirectoryName); QStringList functionalVolumeFileList = functionalVolumeDir.entryList(QDir::Files); for (int ni = 0; ni < functionalVolumeFileList.size(); ni++) { const QString fileName = functionalVolumeFileList.at(ni); if (functionalVolumeRE.exactMatch(fileName)) { QStringList matches = functionalVolumeRE.capturedTexts(); if (matches.size() >= 2) { // // Note: 1st capture is the entire string // const int filePaintNumber = matches.at(1).toInt(); if (paintNameNumber == filePaintNumber) { const QString fullPath = functionalVolumeDirectoryName + "/" + fileName; functionalVolumeFileNameToLoad = fullPath; break; } } } } } if (metricFileNameToLoad.isEmpty() == false) { if (DebugControl::getDebugOn()) { std::cout << "Load: " << metricFileNameToLoad.toAscii().constData() << std::endl; } try { brainSet->readMetricFile(metricFileNameToLoad, true, false); const int col = brainSet->getMetricFile()->getNumberOfColumns() - 1; BrainModelSurfaceOverlay* metricOverlay = NULL; int overlayIndex = 3 - this->autoLoaderIndex; if ((overlayIndex >= 0) && (overlayIndex < brainSet->getNumberOfSurfaceOverlays())) { metricOverlay = brainSet->getSurfaceOverlay(overlayIndex); } if (metricOverlay != NULL) { BrainModelSurface* displaySurface = this->getAutoLoadDisplaySurface(); if (displaySurface != NULL) { const int surfaceIndex = brainSet->getBrainModelIndex(displaySurface); metricOverlay->setOverlay(surfaceIndex, BrainModelSurfaceOverlay::OVERLAY_METRIC); metricOverlay->setDisplayColumnSelected(surfaceIndex, col); metricOverlay->setThresholdColumnSelected(surfaceIndex, col); } } loadedMetricColumn = col; int numNodes = brainSet->getNumberOfNodes(); for (int m = 0; m < numNodes; m++) { brainSet->getNodeAttributes(m)->setHighlighting( BrainSetNodeAttribute::HIGHLIGHT_NODE_NONE); if (pf->getPaint(m, paintColumnNumber) == paintIndex) { if (m == nodeNumber) { // // DO NOT highlight selected node as the identification // code will do this. // //brainSet->getNodeAttributes(m)->setHighlighting( // BrainSetNodeAttribute::HIGHLIGHT_NODE_LOCAL); } else { brainSet->getNodeAttributes(m)->setHighlighting( BrainSetNodeAttribute::HIGHLIGHT_NODE_REMOTE); } } } } catch (FileException e) { errorMessage += (e.whatQString() + "\n"); } } else if (metricDirectoryNameValid) { errorMessage += ("No metric file for cluster node " + QString::number(nodeNumber) + " for paint name: " + paintName + "\n"); } if (functionalVolumeFileNameToLoad.isEmpty() == false) { if (DebugControl::getDebugOn()) { std::cout << "Load: " << functionalVolumeFileNameToLoad.toAscii().constData() << std::endl; } try { brainSet->readVolumeFile(functionalVolumeFileNameToLoad, VolumeFile::VOLUME_TYPE_FUNCTIONAL, true, false); const int volumeIndex = brainSet->getNumberOfVolumeFunctionalFiles() - 1; if (volumeIndex >= 0) { dsv->setSelectedFunctionalVolumeView(volumeIndex); dsv->setSelectedFunctionalVolumeThreshold(volumeIndex); BrainModelVolumeVoxelColoring* vvc = brainSet->getVoxelColoring(); vvc->setPrimaryOverlay(BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_FUNCTIONAL); loadedFunctionalVolume = brainSet->getVolumeFunctionalFile(volumeIndex); } } catch (FileException e) { errorMessage += (e.whatQString() + "\n"); } } else if (functionalVolumeDirectoryNameValidFlag) { errorMessage += ("No functional volume file for cluster node " + QString::number(nodeNumber) + "\n"); } } else { errorMessage += ("No clusters for node with invalid paint index."); } this->setAutoLoadLastMetricColumnNumber(loadedMetricColumn); this->setAutoLoadLastFunctionalVolume(loadedFunctionalVolume); brainSet->getDisplaySettingsMetric()->update(); brainSet->getNodeColoring()->assignColors(); brainSet->clearAllDisplayLists(); return errorMessage; } /** * Get the last auto load node number. */ int BrainSetAutoLoaderFilePaintCluster::getLastAutoLoadNodeNumber() const { const int indx = getNumberOfPreviouslyLoadedNodeNumbers() - 1; if (indx >= 0) { return getPreviouslyLoadedNodeNumber(indx); } return -1; } /** * Set the last auto load node number. */ void BrainSetAutoLoaderFilePaintCluster::setLastAutoLoadNodeNumber(const int nodeNumber) { if (this->autoLoadReplaceLastFileFlag) { previouslyLoadedNodeNumbers.clear(); } previouslyLoadedNodeNumbers.push_back(nodeNumber); } /** * Get the selected paint column number. */ int BrainSetAutoLoaderFilePaintCluster::getPaintColumnNumber() { PaintFile* pf = brainSet->getPaintFile(); const int numColumns = pf->getNumberOfColumns(); if (paintColumnNumber >= numColumns) { paintColumnNumber = numColumns -1; } if (paintColumnNumber < 0) { if (numColumns > 0) { paintColumnNumber = 0; } } return paintColumnNumber; } /** * Set the selected paint column number. */ void BrainSetAutoLoaderFilePaintCluster::setPaintColumnNumber(const int columnNumber) { paintColumnNumber = columnNumber; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainSetAutoLoaderFileMetricByNode.h0000664000175000017500000000176411572067322026622 0ustar michaelmichael#ifndef __BRAIN_SET_AUTO_LOADER_FILE_METRIC_BY_NODE_H__ #define __BRAIN_SET_AUTO_LOADER_FILE_METRIC_BY_NODE_H__ #include "BrainSetAutoLoaderFileMetric.h" class BrainModelSurface; class VolumeFile; class BrainSetAutoLoaderFileMetricByNode : public BrainSetAutoLoaderFileMetric { public: /// constructor BrainSetAutoLoaderFileMetricByNode(BrainSet* bsIn, const int autoLoaderIndexIn); /// destructor virtual ~BrainSetAutoLoaderFileMetricByNode(); // auto load the metric file for the specified node number (return error message) virtual QString loadFileForNode(const int nodeNumber); // is auto loading metric file by node supported for this auto loader virtual bool isLoadFileForNodeSupported() const; // auto load the metric file for the specified voxel (return error message) virtual QString loadFileForVoxel(const VoxelIJK& voxel); protected: }; #endif // __BRAIN_SET_AUTO_LOADER_FILE_METRIC_BY_NODE_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainSetAutoLoaderFileMetricByNode.cxx0000664000175000017500000001436511572067322027176 0ustar michaelmichael #include #include #include #include #include #include "BrainModelSurface.h" #include "BrainModelSurfaceNodeColoring.h" #include "BrainModelSurfaceOverlay.h" #include "BrainSet.h" #include "BrainSetAutoLoaderFileMetricByNode.h" #include "DebugControl.h" #include "DisplaySettingsMetric.h" #include "MetricFile.h" #include "StringUtilities.h" #include "VolumeFile.h" #include "VoxelIJK.h" /** * constructor */ BrainSetAutoLoaderFileMetricByNode::BrainSetAutoLoaderFileMetricByNode(BrainSet* bsIn, const int autoLoaderIndexIn) : BrainSetAutoLoaderFileMetric(bsIn, autoLoaderIndexIn) { } /** * destructor. */ BrainSetAutoLoaderFileMetricByNode::~BrainSetAutoLoaderFileMetricByNode() { } /** * auto load the metric file for the specified node number (return error message). */ QString BrainSetAutoLoaderFileMetricByNode::loadFileForNode(const int nodeNumber) { QString errorMessage = ""; MetricFile* mf = brainSet->getMetricFile(); int lastCol = this->getAutoLoadLastMetricColumnNumber(); if (this->getAutoLoadReplaceLastFileEnabled() && (lastCol >= 0) && (lastCol < mf->getNumberOfColumns())) { mf->removeColumn(lastCol); this->setAutoLoadLastMetricColumnNumber(-1); lastCol = -1; } int autoLoadColumnNumber = -1; const QString directoryName = this->getAutoLoadDirectoryName(); if (QFile::exists(directoryName) == false) { errorMessage += "Auto Load Metric selected but directory (" + directoryName + ") is invalid.\n"; } else { const QString fileNamePrefix = QString::number(nodeNumber); const QString reString("(\\d+)_(.*)." + SpecFile::getMetricFileExtension()); QRegExp re(reString, Qt::CaseInsensitive); QString metricFileNameToLoad = ""; QDir dir(directoryName); QStringList fileList = dir.entryList(QDir::Files); int fileCounter = 0; for (int ni = 0; ni < fileList.size(); ni++) { const QString fileName = fileList.at(ni); if (re.exactMatch(fileName)) { QStringList matches = re.capturedTexts(); if (matches.size() >= 3) { // // Note: zero'th capture is the entire string // const int fileNodeNumber = matches.at(1).toInt(); if (nodeNumber == fileNodeNumber) { const QString fullPath = directoryName + "/" + fileName; metricFileNameToLoad = fullPath; break; } } } fileCounter++; } //std::cout << "Searched " << fileCounter << " files." << std::endl; QString columnName = ""; if (metricFileNameToLoad.isEmpty() == false) { if (DebugControl::getDebugOn()) { std::cout << "Load: " << metricFileNameToLoad.toAscii().constData() << std::endl; } try { int col = -1; int lastCol = this->getAutoLoadLastMetricColumnNumber(); if (this->getAutoLoadReplaceLastFileEnabled() && (lastCol >= 0) && (lastCol < brainSet->getMetricFile()->getNumberOfColumns())) { std::vector columnDestination; columnDestination.push_back(lastCol); std::vector columnNames; columnNames.push_back(""); brainSet->readMetricFile(metricFileNameToLoad, columnDestination, columnNames, AbstractFile::FILE_COMMENT_MODE_LEAVE_AS_IS, false); col = lastCol; } else { brainSet->readMetricFile(metricFileNameToLoad, true, false); col = brainSet->getMetricFile()->getNumberOfColumns() - 1; } BrainModelSurfaceOverlay* metricOverlay = NULL; int overlayIndex = 3 - this->autoLoaderIndex; if ((overlayIndex >= 0) && (overlayIndex < brainSet->getNumberOfSurfaceOverlays())) { metricOverlay = brainSet->getSurfaceOverlay(overlayIndex); } if (metricOverlay != NULL) { BrainModelSurface* displaySurface = this->getAutoLoadMetricDisplaySurface(); if (displaySurface != NULL) { const int surfaceIndex = brainSet->getBrainModelIndex(displaySurface); metricOverlay->setOverlay(surfaceIndex, BrainModelSurfaceOverlay::OVERLAY_METRIC); metricOverlay->setDisplayColumnSelected(surfaceIndex, col); metricOverlay->setThresholdColumnSelected(surfaceIndex, col); } } autoLoadColumnNumber = col; columnName = brainSet->getMetricFile()->getColumnName(col); } catch (FileException e) { errorMessage += (e.whatQString() + "\n"); } } else { errorMessage = ("No metric file for node " + QString::number(nodeNumber) + "\n"); } //if (DebugControl::getDebugOn()) { std::cout << "Node Number: " << nodeNumber << ", file: " << metricFileNameToLoad.toAscii().constData() << ", column-name: " << columnName.toAscii().constData() << std::endl; //} } if (autoLoadColumnNumber >= 0) { this->setAutoLoadLastMetricColumnNumber(autoLoadColumnNumber); } brainSet->getDisplaySettingsMetric()->update(); brainSet->getNodeColoring()->assignColors(); brainSet->clearAllDisplayLists(); return errorMessage; } /** * is auto loading metric file by node supported for this auto loader */ bool BrainSetAutoLoaderFileMetricByNode::isLoadFileForNodeSupported() const { return true; } /** * Auto load the metric file for the specified voxel (return error message). */ QString BrainSetAutoLoaderFileMetricByNode::loadFileForVoxel(const VoxelIJK& voxel) { return "Auto-Loading files by voxel not suppored."; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainSetAutoLoaderFileMetric.h0000664000175000017500000000417011572067322025513 0ustar michaelmichael#ifndef __BRAIN_SET_AUTO_LOADER_FILE_METRIC_H__ #define __BRAIN_SET_AUTO_LOADER_FILE_METRIC_H__ #include "BrainSetAutoLoaderFile.h" #include "SceneFile.h" class BrainModelSurface; class VolumeFile; class BrainSetAutoLoaderFileMetric : public BrainSetAutoLoaderFile { public: /// constructor BrainSetAutoLoaderFileMetric(BrainSet* bsIn, const int autoLoaderIndexIn); /// destructor ~BrainSetAutoLoaderFileMetric(); /// reinitialize all display settings void reset(); /// update any selections due to changes with loaded data files void update(); /// apply a scene (set display settings) void showScene(const SceneFile::Scene& scene, QString& errorMessage); /// create a scene (read display settings) void saveScene(SceneFile::Scene& scene, const bool onlyIfSelectedFlag, QString& errorMessage); /** get the auto load display surface */ BrainModelSurface* getAutoLoadMetricDisplaySurface() { return this->autoLoadDisplaySurface; } /** set the auto load display surface */ void setAutoLoadMetricDisplaySurface(BrainModelSurface* bms) { this->autoLoadDisplaySurface = bms; } /** * Get the last auto-loaded metric column number. */ int getAutoLoadLastMetricColumnNumber() const { return this->autoLoadMetricLastColumnNumber; } /** * Set the last auto-loaded metric column number. */ void setAutoLoadLastMetricColumnNumber(const int columnNumber) { this->autoLoadMetricLastColumnNumber = columnNumber; } // auto load the metric file for the specified voxel (return error message) virtual QString loadFileForVoxel(const VoxelIJK& voxel); protected: /// auto load metric display surface BrainModelSurface* autoLoadDisplaySurface; /// column number of last auto-loaded metric (DO NOT SAVE TO SCENE) int autoLoadMetricLastColumnNumber; }; #endif /* __BRAIN_SET_AUTO_LOADER_FILE_METRIC_H__ */ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainSetAutoLoaderFileMetric.cxx0000664000175000017500000002315311572067322026070 0ustar michaelmichael #include #include #include #include #include "BrainModelSurface.h" #include "BrainModelSurfaceNodeColoring.h" #include "BrainModelSurfaceOverlay.h" #include "BrainSet.h" #include "BrainSetAutoLoaderFileMetric.h" #include "DebugControl.h" #include "DisplaySettingsMetric.h" #include "MetricFile.h" #include "StringUtilities.h" #include "VolumeFile.h" #include "VoxelIJK.h" /** * constructor. */ BrainSetAutoLoaderFileMetric::BrainSetAutoLoaderFileMetric(BrainSet* bsIn, const int autoLoaderIndexIn) : BrainSetAutoLoaderFile(bsIn, autoLoaderIndexIn) { reset(); } /** * destructor. */ BrainSetAutoLoaderFileMetric::~BrainSetAutoLoaderFileMetric() { } /** * reinitialize all display settings. */ void BrainSetAutoLoaderFileMetric::reset() { BrainSetAutoLoaderFile::reset(); autoLoadDisplaySurface = NULL; autoLoadMetricLastColumnNumber = -1; } /** * update any selections due to changes with loaded data files. */ void BrainSetAutoLoaderFileMetric::update() { BrainSetAutoLoaderFile::update(); //validate volume, surface, etc //brainSet->getVolumeAnatomyFileByName(const QString& filename); //brainSet->getBrainModelSurfaceByCoordinateFileName(const QString& filename); } /** * apply a scene (set display settings). */ void BrainSetAutoLoaderFileMetric::showScene(const SceneFile::Scene& scene, QString& /*errorMessage*/) { reset(); const int numClasses = scene.getNumberOfSceneClasses(); for (int nc = 0; nc < numClasses; nc++) { const SceneFile::SceneClass* sc = scene.getSceneClass(nc); if (sc->getName().startsWith("BrainSetAutoLoaderFileMetric")) { std::vector tokens; StringUtilities::token(sc->getName(), ":", tokens); int indx = -1; if (tokens.size() > 1) { indx = tokens[1].toInt(); } if (indx == this->autoLoaderIndex) { const int num = sc->getNumberOfSceneInfo(); // // parent class data // showSceneHelper(*sc); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc->getSceneInfo(i); const QString infoName = si->getName(); if (infoName == "autoLoadDisplaySurface") { autoLoadDisplaySurface = brainSet->getBrainModelSurfaceWithCoordinateFileName(si->getValueAsString()); } } } } } // // Autoload any previously loaded voxels // int num = getNumberOfPreviouslyLoadedVoxels(); for (int i = 0; i < num; i++) { if (this->autoLoadEnabledFlag) { this->loadFileForVoxel(this->getPreviouslyLoadedVoxel(i)); } } } /** * create a scene (read display settings). */ void BrainSetAutoLoaderFileMetric::saveScene(SceneFile::Scene& scene, const bool /*onlyIfSelectedFlag*/, QString& /*errorMessage*/) { //MetricFile* mf = brainSet->getMetricFile(); SceneFile::SceneClass sc("BrainSetAutoLoaderFileMetric:" + QString::number(this->autoLoaderIndex)); if (autoLoadDisplaySurface != NULL) { sc.addSceneInfo(SceneFile::SceneInfo("autoLoadDisplaySurface", autoLoadDisplaySurface->getCoordinateFile()->getFileName())); } saveSceneHelper(sc); // DO NOT add to scene //sc.addSceneInfo(SceneFile::SceneInfo("autoLoadMetricLastColumnNumber", // autoLoadMetricLastColumnNumber)); scene.addSceneClass(sc); } /** * Auto load the metric file for the specified voxel (return error message). */ QString BrainSetAutoLoaderFileMetric::loadFileForVoxel(const VoxelIJK& voxel) { QString errorMessage = ""; int ijk[3]; voxel.getIJK(ijk); MetricFile* mf = brainSet->getMetricFile(); int lastCol = this->getAutoLoadLastMetricColumnNumber(); if (this->getAutoLoadReplaceLastFileEnabled() && (lastCol >= 0) && (lastCol < mf->getNumberOfColumns())) { mf->removeColumn(lastCol); this->setAutoLoadLastMetricColumnNumber(-1); lastCol = -1; } if (DebugControl::getDebugOn()) { std::cout << "Metric Auto Load Voxel IJK: " << ijk[0] << " " << ijk[1] << " " << ijk[2] << std::endl; } int autoLoadColumnNumber = -1; const QString directoryName = this->getAutoLoadDirectoryName(); if (QFile::exists(directoryName) == false) { errorMessage += "Auto Load Metric selected but directory (" + directoryName + ") is invalid.\n"; } else { const QString reString("(.*_)(\\d+)_(\\d+)_(\\d+)" + SpecFile::getMetricFileExtension()); QRegExp re(reString, Qt::CaseInsensitive); QString metricFileNameToLoad = ""; QDir dir(directoryName); QStringList fileList = dir.entryList(QDir::Files); int fileCounter = 0; bool firstMetricFound = false; for (int ni = 0; ni < fileList.size(); ni++) { const QString fileName = fileList.at(ni); if (re.exactMatch(fileName)) { QStringList matches = re.capturedTexts(); if (matches.size() >= 5) { // // Note: zero'th capture is the entire string // const int vi = matches.at(2).toInt(); const int vj = matches.at(3).toInt(); const int vk = matches.at(4).toInt(); if ((vi == ijk[0]) && (vj == ijk[1]) && (vk == ijk[2])) { const QString fullPath = directoryName + "/" + fileName; metricFileNameToLoad = fullPath; break; } if (firstMetricFound == false) { QString guessedFileName = directoryName + "/" + matches.at(1) + QString::number(ijk[0]) + "_" + QString::number(ijk[1]) + "_" + QString::number(ijk[2]) + SpecFile::getMetricFileExtension(); if (QFile::exists(guessedFileName)) { metricFileNameToLoad = guessedFileName; break; } firstMetricFound = true; } } } fileCounter++; } //std::cout << "Searched " << fileCounter << " files." << std::endl; if (metricFileNameToLoad.isEmpty() == false) { if (DebugControl::getDebugOn()) { std::cout << "Load: " << metricFileNameToLoad.toAscii().constData() << std::endl; } try { int col = -1; int lastCol = this->getAutoLoadLastMetricColumnNumber(); if (this->getAutoLoadReplaceLastFileEnabled() && (lastCol >= 0) && (lastCol < brainSet->getMetricFile()->getNumberOfColumns())) { std::vector columnDestination; columnDestination.push_back(lastCol); std::vector columnNames; columnNames.push_back(""); brainSet->readMetricFile(metricFileNameToLoad, columnDestination, columnNames, AbstractFile::FILE_COMMENT_MODE_LEAVE_AS_IS, false); col = lastCol; } else { brainSet->readMetricFile(metricFileNameToLoad, true, false); col = brainSet->getMetricFile()->getNumberOfColumns() - 1; } BrainModelSurfaceOverlay* metricOverlay = NULL; int overlayIndex = 3 - this->autoLoaderIndex; if ((overlayIndex >= 0) && (overlayIndex < brainSet->getNumberOfSurfaceOverlays())) { metricOverlay = brainSet->getSurfaceOverlay(overlayIndex); } if (metricOverlay != NULL) { BrainModelSurface* displaySurface = this->getAutoLoadMetricDisplaySurface(); if (displaySurface != NULL) { const int surfaceIndex = brainSet->getBrainModelIndex(displaySurface); metricOverlay->setOverlay(surfaceIndex, BrainModelSurfaceOverlay::OVERLAY_METRIC); metricOverlay->setDisplayColumnSelected(surfaceIndex, col); metricOverlay->setThresholdColumnSelected(surfaceIndex, col); } } autoLoadColumnNumber = col; } catch (FileException e) { errorMessage += (e.whatQString() + "\n"); } } else { errorMessage = ("No metric file for voxel (" + QString::number(ijk[0]) + ", " + QString::number(ijk[1]) + ", " + QString::number(ijk[2]) + ")\n"); } } if (autoLoadColumnNumber >= 0) { this->setAutoLoadLastMetricColumnNumber(autoLoadColumnNumber); } brainSet->getDisplaySettingsMetric()->update(); brainSet->getNodeColoring()->assignColors(); brainSet->clearAllDisplayLists(); return errorMessage; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainSetAutoLoaderFileFunctionalVolume.h0000664000175000017500000000353011572067322027561 0ustar michaelmichael/* * File: BrainSetAutoLoaderFileFunctionalVolume.h * Author: john * * Created on August 21, 2009, 10:38 AM */ #ifndef __BRAIN_SET_AUTO_LOADER_FILE_FUNCTIONAL_VOLUME_H__ #define __BRAIN_SET_AUTO_LOADER_FILE_FUNCTIONAL_VOLUME_H__ #include "BrainSetAutoLoaderFile.h" #include "SceneFile.h" class VolumeFile; class BrainSetAutoLoaderFileFunctionalVolume : public BrainSetAutoLoaderFile { public: /// constructor BrainSetAutoLoaderFileFunctionalVolume(BrainSet* bsIn, const int autoLoaderIndexIn); /// destructor ~BrainSetAutoLoaderFileFunctionalVolume(); /// reinitialize all display settings void reset(); /// update any selections due to changes with loaded data files void update(); /// apply a scene (set display settings) void showScene(const SceneFile::Scene& scene, QString& errorMessage); /// create a scene (read display settings) void saveScene(SceneFile::Scene& scene, const bool onlyIfSelectedFlag, QString& errorMessage); /** * Get the last auto-loaded functional volume. */ VolumeFile* getAutoLoadLastFunctionalVolume() { return this->autoLoadMetricLastFunctionalVolume; } /** * Set the last auto-loaded functional volume. */ void setAutoLoadLastFunctionalVolume(VolumeFile* vf) { this->autoLoadMetricLastFunctionalVolume = vf; } // auto load the metric file for the specified voxel (return error message) QString loadFileForVoxel(const VoxelIJK& voxel); protected: /// last auto loaded functional volume (do not save to scene) VolumeFile* autoLoadMetricLastFunctionalVolume; }; #endif /* __BRAIN_SET_AUTO_LOADER_FILE_FUNCTIONAL_VOLUME_H__ */ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainSetAutoLoaderFileFunctionalVolume.cxx0000664000175000017500000001645711572067322030150 0ustar michaelmichael #include #include #include #include #include "BrainModelVolumeVoxelColoring.h" #include "BrainSet.h" #include "BrainSetAutoLoaderFileFunctionalVolume.h" #include "DebugControl.h" #include "DisplaySettingsVolume.h" #include "StringUtilities.h" #include "VolumeFile.h" #include "VoxelIJK.h" /** * constructor. */ BrainSetAutoLoaderFileFunctionalVolume::BrainSetAutoLoaderFileFunctionalVolume(BrainSet* bsIn, const int autoLoaderIndexIn) : BrainSetAutoLoaderFile(bsIn, autoLoaderIndexIn) { reset(); } /** * destructor. */ BrainSetAutoLoaderFileFunctionalVolume::~BrainSetAutoLoaderFileFunctionalVolume() { } /** * reinitialize all display settings. */ void BrainSetAutoLoaderFileFunctionalVolume::reset() { BrainSetAutoLoaderFile::reset(); autoLoadMetricLastFunctionalVolume = NULL; } /** * update any selections due to changes with loaded data files. */ void BrainSetAutoLoaderFileFunctionalVolume::update() { BrainSetAutoLoaderFile::update(); //validate volume, surface, etc //brainSet->getVolumeAnatomyFileByName(const QString& filename); //brainSet->getBrainModelSurfaceByCoordinateFileName(const QString& filename); } /** * apply a scene (set display settings). */ void BrainSetAutoLoaderFileFunctionalVolume::showScene(const SceneFile::Scene& scene, QString& /*errorMessage*/) { reset(); const int numClasses = scene.getNumberOfSceneClasses(); for (int nc = 0; nc < numClasses; nc++) { const SceneFile::SceneClass* sc = scene.getSceneClass(nc); if (sc->getName().startsWith("BrainSetAutoLoaderFileFunctionalVolume")) { std::vector tokens; StringUtilities::token(sc->getName(), ":", tokens); int indx = -1; if (tokens.size() > 1) { indx = tokens[1].toInt(); } if (indx == this->autoLoaderIndex) { const int num = sc->getNumberOfSceneInfo(); // // parent class data // showSceneHelper(*sc); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc->getSceneInfo(i); const QString infoName = si->getName(); } } } } // // Autoload any previously loaded voxels // int num = getNumberOfPreviouslyLoadedVoxels(); for (int i = 0; i < num; i++) { if (this->autoLoadEnabledFlag) { this->loadFileForVoxel(this->getPreviouslyLoadedVoxel(i)); } } } /** * create a scene (read display settings). */ void BrainSetAutoLoaderFileFunctionalVolume::saveScene(SceneFile::Scene& scene, const bool /*onlyIfSelectedFlag*/, QString& /*errorMessage*/) { SceneFile::SceneClass sc("BrainSetAutoLoaderFileFunctionalVolume:" + QString::number(this->autoLoaderIndex)); saveSceneHelper(sc); // DO NOT add to scene //sc.addSceneInfo(SceneFile::SceneInfo("autoLoadMetricLastColumnNumber", // autoLoadMetricLastColumnNumber)); scene.addSceneClass(sc); } /** * Auto load the metric file for the specified voxel (return error message). */ QString BrainSetAutoLoaderFileFunctionalVolume::loadFileForVoxel(const VoxelIJK& voxel) { DisplaySettingsVolume* dsv = brainSet->getDisplaySettingsVolume(); VolumeFile* lastVolume = this->getAutoLoadLastFunctionalVolume(); if (this->getAutoLoadReplaceLastFileEnabled() && (lastVolume != NULL)) { brainSet->deleteVolumeFile(lastVolume); this->setAutoLoadLastFunctionalVolume(NULL); dsv->update(); lastVolume = NULL; } QString errorMessage = ""; int ijk[3]; voxel.getIJK(ijk); VolumeFile* autoLoadLastVolumeFile = NULL; if (DebugControl::getDebugOn()) { std::cout << "Functional Volume Auto Load Voxel IJK: " << ijk[0] << " " << ijk[1] << " " << ijk[2] << std::endl; } const QString directoryName = this->getAutoLoadDirectoryName(); if (QFile::exists(directoryName) == false) { errorMessage += "Auto Load Functional Volume selected but directory (" + directoryName + ") is invalid.\n"; } else { const QString reString(".*_(\\d+)_(\\d+)_(\\d+)" + SpecFile::getNiftiGzipVolumeFileExtension()); QRegExp re(reString, Qt::CaseInsensitive); QString functionalVolumeFileNameToLoad = ""; QDir dir(directoryName); QStringList fileList = dir.entryList(QDir::Files); for (int ni = 0; ni < fileList.size(); ni++) { const QString fileName = fileList.at(ni); if (re.exactMatch(fileName)) { QStringList matches = re.capturedTexts(); if (matches.size() >= 4) { // // Note: 1st capture is the entire string // const int vi = matches.at(1).toInt(); const int vj = matches.at(2).toInt(); const int vk = matches.at(3).toInt(); if ((vi == ijk[0]) && (vj == ijk[1]) && (vk == ijk[2])) { const QString fullPath = directoryName + "/" + fileName; functionalVolumeFileNameToLoad = fullPath; break; } } } } if (functionalVolumeFileNameToLoad.isEmpty() == false) { if (DebugControl::getDebugOn()) { std::cout << "Load: " << functionalVolumeFileNameToLoad.toAscii().constData() << std::endl; } try { VolumeFile* lastVolume = this->getAutoLoadLastFunctionalVolume(); if (this->getAutoLoadReplaceLastFileEnabled() && (lastVolume != NULL)) { brainSet->deleteVolumeFile(lastVolume); } brainSet->readVolumeFile(functionalVolumeFileNameToLoad, VolumeFile::VOLUME_TYPE_FUNCTIONAL, true, false); const int volumeIndex = brainSet->getNumberOfVolumeFunctionalFiles() - 1; if (volumeIndex >= 0) { dsv->setSelectedFunctionalVolumeView(volumeIndex); dsv->setSelectedFunctionalVolumeThreshold(volumeIndex); BrainModelVolumeVoxelColoring* vvc = brainSet->getVoxelColoring(); vvc->setPrimaryOverlay(BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_FUNCTIONAL); autoLoadLastVolumeFile = brainSet->getVolumeFunctionalFile(volumeIndex); } } catch (FileException e) { errorMessage += (e.whatQString() + "\n"); } } else { errorMessage = ("No functional volume file for voxel (" + QString::number(ijk[0]) + ", " + QString::number(ijk[1]) + ", " + QString::number(ijk[2]) + ")\n"); } } dsv->update(); brainSet->clearAllDisplayLists(); this->setAutoLoadLastFunctionalVolume(autoLoadLastVolumeFile); return errorMessage; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainSetAutoLoaderFile.h0000664000175000017500000001177011572067322024353 0ustar michaelmichael/* * File: BrainSetAutoLoaderFile.h * Author: john * * Created on August 20, 2009, 3:23 PM */ #ifndef __BRAIN_SET_AUTO_LOADER_FILE_H__ #define __BRAIN_SET_AUTO_LOADER_FILE_H__ #include "SceneFile.h" #include "VoxelIJK.h" class BrainModelSurface; class BrainSet; class VolumeFile; /// base class for file auto loaders class BrainSetAutoLoaderFile { public: /// constructor BrainSetAutoLoaderFile(BrainSet* bsIn, const int autoLoaderIndexIn); /// destructor virtual ~BrainSetAutoLoaderFile(); /// reinitialize all display settings virtual void reset(); /// update any selections due to changes with loaded data files virtual void update(); /// apply a scene (set display settings) virtual void showScene(const SceneFile::Scene& scene, QString& errorMessage) = 0; /// create a scene (read display settings) virtual void saveScene(SceneFile::Scene& scene, const bool onlyIfSelectedFlag, QString& errorMessage) = 0; /** get the auto load volume file */ VolumeFile* getAutoLoadAnatomyVolumeFile() { return this->autoLoadAnatomyVolumeFile; } /** set the auto load volume file */ void setAutoLoadAnatomyVolumeFile(VolumeFile* vf) { this->autoLoadAnatomyVolumeFile = vf; } /** set the auto load directory name */ QString getAutoLoadDirectoryName() const { return this->autoLoadDirectoryName; } /** Set the auto load directory name */ void setAutoLoadDirectoryName(const QString& name) { this->autoLoadDirectoryName = name; } /** set the auto load secondary directory name */ QString getAutoLoadSecondaryDirectoryName() const { return this->autoLoadSecondaryDirectoryName; } /** Set the auto load secondary directory name */ void setAutoLoadSecondaryDirectoryName(const QString& name) { this->autoLoadSecondaryDirectoryName = name; } /** get the auto load enabled */ bool getAutoLoadEnabled() const { return this->autoLoadEnabledFlag; } /** set the auto load enabled */ void setAutoLoadEnabled(bool b) { this->autoLoadEnabledFlag = b; } /** * Get replace last auto loaded file. */ bool getAutoLoadReplaceLastFileEnabled() const { return this->autoLoadReplaceLastFileFlag; } /** * Set replace last autoloaded last file. */ void setAutoLoadReplaceLastFileEnabled(const bool b) { this->autoLoadReplaceLastFileFlag = b; } // Get the last auto load anatomy volume indices. VoxelIJK getLastAutoLoadAnatomyVoxelIndices() const; // Set the last auto load anatomy volume indices. void setLastAutoLoadAnatomyVoxelIndices(const VoxelIJK& voxel); // auto load the metric file for the specified voxel (return error message) virtual QString loadFileForVoxel(const VoxelIJK& voxel) = 0; // auto load the metric file for the specified node number (return error message) virtual QString loadFileForNode(const int nodeNumber); // is auto loading metric file by node supported for this auto loader virtual bool isLoadFileForNodeSupported() const; /** get the auto load volume intersection surface */ BrainModelSurface* getAutoLoadVolumeIntersectionSurface() { return this->autoLoadVolumeIntersectionSurface; } /** set the auto load volume intersection surface */ void setAutoLoadVolumeIntersectionSurface(BrainModelSurface* bms) { this->autoLoadVolumeIntersectionSurface = bms; } protected: /// Help with applying a scene. void showSceneHelper(const SceneFile::SceneClass& sc); /// Help saving a scene. void saveSceneHelper(SceneFile::SceneClass& sc); /// the brain set BrainSet* brainSet; /// auto load anatomical volume file VolumeFile* autoLoadAnatomyVolumeFile; /// directory containing auto load files QString autoLoadDirectoryName; /// secondary directory containing auto load files QString autoLoadSecondaryDirectoryName; /// auto load file enabled bool autoLoadEnabledFlag; /// replace previous auto loaded file flag bool autoLoadReplaceLastFileFlag; /// index of this autoloader const int autoLoaderIndex; /// get the number of previously loaded voxels. */ int getNumberOfPreviouslyLoadedVoxels() const { return previouslyLoadedVoxels.size(); } /// get a previously loaded voxel (zero is oldest). VoxelIJK getPreviouslyLoadedVoxel(const int indx) { return previouslyLoadedVoxels[indx]; } private: /// previously loaded voxels std::vector previouslyLoadedVoxels; /// auto load volume intersection surface BrainModelSurface* autoLoadVolumeIntersectionSurface; }; #endif /* __BRAIN_SET_AUTO_LOADER_FILE_H__ */ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainSetAutoLoaderFile.cxx0000664000175000017500000001203411572067322024720 0ustar michaelmichael#include "BrainModelSurface.h" #include "BrainSet.h" #include "BrainSetAutoLoaderFile.h" #include "StringUtilities.h" #include "VolumeFile.h" /** * constructor. */ BrainSetAutoLoaderFile::BrainSetAutoLoaderFile(BrainSet* bsIn, const int autoLoaderIndexIn) : brainSet(bsIn), autoLoaderIndex(autoLoaderIndexIn) { reset(); } /** * destructor. */ BrainSetAutoLoaderFile::~BrainSetAutoLoaderFile() { } /** * reinitialize all display settings. */ void BrainSetAutoLoaderFile::reset() { autoLoadVolumeIntersectionSurface = NULL; autoLoadAnatomyVolumeFile = NULL; autoLoadDirectoryName = ""; autoLoadSecondaryDirectoryName = ""; autoLoadEnabledFlag = false; autoLoadReplaceLastFileFlag = false; previouslyLoadedVoxels.clear(); } /** * update any selections due to changes with loaded data files. */ void BrainSetAutoLoaderFile::update() { //validate volume, surface, etc //brainSet->getVolumeAnatomyFileByName(const QString& filename); //brainSet->getBrainModelSurfaceByCoordinateFileName(const QString& filename); } /** * Help with applying a scene. */ void BrainSetAutoLoaderFile::showSceneHelper(const SceneFile::SceneClass& sc) { const int num = sc.getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc.getSceneInfo(i); const QString infoName = si->getName(); if (infoName == "autoLoadVolumeIntersectionSurface") { autoLoadVolumeIntersectionSurface = brainSet->getBrainModelSurfaceWithCoordinateFileName(si->getValueAsString()); } else if (infoName == "autoLoadAnatomyVolumeFile") { autoLoadAnatomyVolumeFile = brainSet->getVolumeAnatomyFileWithName(si->getValueAsString()); } else if (infoName == "autoLoadDirectoryName") { si->getValue(autoLoadDirectoryName); } else if (infoName == "autoLoadSecondaryDirectoryName") { si->getValue(autoLoadSecondaryDirectoryName); } else if (infoName == "autoLoadEnabledFlag") { si->getValue(autoLoadEnabledFlag); } else if (infoName == "autoLoadReplaceLastFileFlag") { si->getValue(autoLoadReplaceLastFileFlag); } else if (infoName == "previouslyLoadedVoxels") { std::vector indices; StringUtilities::token(si->getValueAsString(), " ", indices); if (indices.size() >= 3) { VoxelIJK ijk(indices[0], indices[1], indices[2]); previouslyLoadedVoxels.push_back(ijk); } } } } /** * Help saving a scene. */ void BrainSetAutoLoaderFile::saveSceneHelper(SceneFile::SceneClass& sc) { if (autoLoadVolumeIntersectionSurface != NULL) { sc.addSceneInfo(SceneFile::SceneInfo("autoLoadVolumeIntersectionSurface", autoLoadVolumeIntersectionSurface->getCoordinateFile()->getFileNameNoPath())); } if (autoLoadAnatomyVolumeFile != NULL) { sc.addSceneInfo(SceneFile::SceneInfo("autoLoadAnatomyVolumeFile", autoLoadAnatomyVolumeFile->getFileNameNoPath())); } sc.addSceneInfo(SceneFile::SceneInfo("autoLoadDirectoryName", autoLoadDirectoryName)); sc.addSceneInfo(SceneFile::SceneInfo("autoLoadSecondaryDirectoryName", autoLoadSecondaryDirectoryName)); sc.addSceneInfo(SceneFile::SceneInfo("autoLoadEnabledFlag", autoLoadEnabledFlag)); sc.addSceneInfo(SceneFile::SceneInfo("autoLoadReplaceLastFileFlag", autoLoadReplaceLastFileFlag)); for (unsigned int i = 0; i < previouslyLoadedVoxels.size(); i++) { VoxelIJK voxel = previouslyLoadedVoxels[i]; std::vector indices; indices.push_back(voxel.getI()); indices.push_back(voxel.getJ()); indices.push_back(voxel.getK()); sc.addSceneInfo(SceneFile::SceneInfo("previouslyLoadedVoxels", StringUtilities::combine(indices, " "))); } } /** * Get the last auto load anatomy volume indices. */ VoxelIJK BrainSetAutoLoaderFile::getLastAutoLoadAnatomyVoxelIndices() const { VoxelIJK voxel; int num = static_cast(previouslyLoadedVoxels.size()); if (num > 0) { voxel = previouslyLoadedVoxels[num - 1]; } return voxel; } /** * Set the last auto load anatomy volume indices. */ void BrainSetAutoLoaderFile::setLastAutoLoadAnatomyVoxelIndices(const VoxelIJK& voxel) { if (this->autoLoadReplaceLastFileFlag) { previouslyLoadedVoxels.clear(); } previouslyLoadedVoxels.push_back(voxel); } /** * Auto load the metric file for the specified node number (return error message). */ QString BrainSetAutoLoaderFile::loadFileForNode(const int nodeNumber) { return "This auto loader does not load files by node number."; } /** * Is auto loading metric file by node supported for this auto loader. */ bool BrainSetAutoLoaderFile::isLoadFileForNodeSupported() const { return false; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainSet.h0000664000175000017500000030041111572067322021564 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __BRAIN_SET_H__ #define __BRAIN_SET_H__ #include #include #include #include #include #include #include "BrainModelAlgorithmException.h" #include "BrainModelBorderSet.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceOverlay.h" #include "BrainSetNodeAttribute.h" #include "Structure.h" #include "NodeAttributeFile.h" #include "PreferencesFile.h" #include "SceneFile.h" #include "SpecFile.h" #include "Species.h" #include "TopologyFile.h" #include "TransformationMatrixFile.h" #include "VolumeFile.h" // forward declarations avoid include files (fewer dependencies when compiling). class QProgressDialog; class QWidget; class AreaColorFile; class ArealEstimationFile; class BorderColorFile; class BorderFile; class BrainModelContours; class BrainModelSurfaceAndVolume; class BrainModelSurfaceNodeColoring; class BrainModelSurfaceROINodeSelection; class BrainModelVolumeVoxelColoring; class BrainModelVolume; class BrainModelVolumeRegionOfInterest; class BrainSetAutoLoaderManager; class CellColorFile; class CellFile; class CellProjectionFile; class CocomacConnectivityFile; class ContourCellFile; class ContourCellColorFile; class ContourFile; class CutsFile; class DeformationFieldFile; class DeformationMapFile; class DisplaySettingsArealEstimation; class DisplaySettingsBorders; class DisplaySettingsCells; class DisplaySettingsContours; class DisplaySettingsCuts; class DisplaySettingsCoCoMac; class DisplaySettingsDeformationField; class DisplaySettingsFoci; class DisplaySettingsGeodesicDistance; class DisplaySettingsImages; class DisplaySettingsMetric; class DisplaySettingsModels; class DisplaySettingsSection; class DisplaySettingsSurface; class DisplaySettingsPaint; class DisplaySettingsProbabilisticAtlas; class DisplaySettingsScene; class DisplaySettingsRgbPaint; class DisplaySettingsStudyMetaData; class DisplaySettingsSurfaceShape; class DisplaySettingsVectors; class DisplaySettingsTopography; class DisplaySettingsVolume; class DisplaySettingsWustlRegion; class FociColorFile; class FociFile; class FociProjectionFile; class FociSearchFile; class GeodesicDistanceFile; class ImageFile; class LatLonFile; class MetricFile; class MniObjSurfaceFile; class BrainModelIdentification; class NodeAttributeFile; class PaintFile; class PaletteFile; class ParamsFile; class PreferencesFile; class ProbabilisticAtlasFile; class QTimer; class RgbPaintFile; class SectionFile; class StudyCollectionFile; class StudyMetaDataFile; class SurfaceShapeFile; class TopographyFile; class VectorFile; class VocabularyFile; class VtkModelFile; class WustlRegionFile; /** * Brain Set contains all Surfaces (topology and coordinates) and all * attribute data (paint files, metric files, etc). */ class BrainSet : public QObject { Q_OBJECT public: /// spec file read mode enum SPEC_FILE_READ_MODE { SPEC_FILE_READ_MODE_NORMAL, SPEC_FILE_READ_MODE_APPEND }; /// Constructor (using only the caret main sets the primaryBrainSetFlagIn) BrainSet(const bool primaryBrainSetFlagIn = false); /// Read in the brain set contained in the spec file BrainSet(const QString& specFileNameIn, const bool readAllFilesInSpecFile, const bool primaryBrainSetFlagIn); /// Construct a brain set from a topology file and one or more coordinate files BrainSet(const QString& topoFileName, const QString& coordFileName1, const QString& coordFileName2 = "", const bool primaryBrainSetFlagIn = false); /// Construct a brain set from a vtk surface file BrainSet(const QString& vtkSurfaceFileName, const BrainModelSurface::SURFACE_TYPES surfaceType = BrainModelSurface::SURFACE_TYPE_UNKNOWN, const TopologyFile::TOPOLOGY_TYPES topologyType = TopologyFile::TOPOLOGY_TYPE_UNKNOWN); /// Destructor virtual ~BrainSet(); /// initialize static stuff such as Preferences File /// this is normally called from the BrainSet constructor static void initializeStaticStuff(); /// initialize data file static members static void initializeDataFileStaticMembers(); /// set the random seed static void setRandomSeed(unsigned int randomSeed); /// get the name of the bin directory static QString getBinDirectoryName(); /// get the web caret flag bool getWebCaretFlag() const { return webCaretFlag; } /// set the web caret flag void setWebCaretFlag(const bool flag) { webCaretFlag = flag; } /// get display cross for node int getDisplayCrossForNode() const { return displayCrossForNode; } /// get surface on which identification was made BrainModelSurface* getDisplayCrossSurface() const { return displayNoCrossForSurface; } /// set display cross for node void setDisplayCrossForNode(const int nodeNumber, BrainModelSurface* surface); /// add a brain model void addBrainModel(BrainModel* bm, const bool readingSpecFile = false); /// delete all brain models void deleteAllBrainModels(); /// delete a brain model void deleteBrainModel(const BrainModel* bm); /// add a topology file void addTopologyFile(TopologyFile* tf); /// delete topology file void deleteTopologyFile(TopologyFile* tf); /// add a volume file of the specified type void addVolumeFile(const VolumeFile::VOLUME_TYPE vt, VolumeFile* vf, const QString& name, const bool append, const bool updateSpec) throw (FileException); /// delete a volume file void deleteVolumeFile(const VolumeFile* vf); /// get the number of surface overlays int getNumberOfSurfaceOverlays() const { return numberOfSurfaceOverlays; } /// get the primary surface overlay BrainModelSurfaceOverlay* getPrimarySurfaceOverlay(); /// get the primary surface overlay (const method) const BrainModelSurfaceOverlay* getPrimarySurfaceOverlay() const; /// get the secondary surface overlay BrainModelSurfaceOverlay* getSecondarySurfaceOverlay(); /// get the secondary surface overlay (const method) const BrainModelSurfaceOverlay* getSecondarySurfaceOverlay() const; /// get the surface underlay BrainModelSurfaceOverlay* getSurfaceUnderlay(); /// get the surface underlay (const method) const BrainModelSurfaceOverlay* getSurfaceUnderlay() const; /// get a surface overlay BrainModelSurfaceOverlay* getSurfaceOverlay(const int overlayNumber) { return surfaceOverlays[overlayNumber]; } /// get a surface overlay (const method) const BrainModelSurfaceOverlay* getSurfaceOverlay(const int overlayNumber) const { return surfaceOverlays[overlayNumber]; } /// get something is an overlay bool isASurfaceOverlay(const int model, const BrainModelSurfaceOverlay::OVERLAY_SELECTIONS os) const; /// get something is an overlay for any model bool isASurfaceOverlayForAnySurface(const BrainModelSurfaceOverlay::OVERLAY_SELECTIONS os) const; /// update the surface overlays due to change in brain models void updateSurfaceOverlaysDueToChangeInBrainModels(); /// copy the overlay selections from specified surface to all other surfaces void copyOverlaysFromSurface(const int surfaceModelIndex); /// apply all projected files (foci, cells, borders) void applyAllProjectedFiles(); /// Assign border colors to border projections and borders void assignBorderColors(); /// Assign cell colors to cell and cell projection files void assignCellColors(); /// Assign contour cell colors to contour cells void assignContourCellColors(); /// Assign foci colors to foci and foci projection files void assignFociColors(); /// add nodes to all surfaces at the origin void addNodes(const int numNodesToAdd); /// Clear all display list. void clearAllDisplayLists(); /// classify the nodes as interior and edges void classifyNodes(TopologyFile* tf = NULL, const bool onlyDoClassificationIfNeeded = false); /// find out if nodes have been classified bool getNodesHaveBeenClassified() const { return nodesHaveBeenClassified; } /// get the number of brain models int getNumberOfBrainModels() const { return brainModels.size(); } /// get the index for a brain model int getBrainModelIndex(const BrainModel* bm) const; /// get a brain model BrainModel* getBrainModel(const int modelIndex) { return brainModels[modelIndex]; } /// get a brain model (constant method) const BrainModel* getBrainModel(const int modelIndex) const { return brainModels[modelIndex]; } /// get a brain model contours (if negative index first one found is returned) BrainModelContours* getBrainModelContours(const int modelIndex = -1); /// get a brain model contours (const method) (if negative index first one found is returned) const BrainModelContours* getBrainModelContours(const int modelIndex = -1) const; /// get a brain model surface BrainModelSurface* getBrainModelSurface(const int modelIndex); /// get a brain model surface (const method) const BrainModelSurface* getBrainModelSurface(const int modelIndex) const; /// get a brain model surface with the specified coordinate file name (NULL if not found) BrainModelSurface* getBrainModelSurfaceWithCoordinateFileName(const QString& fileName); /// get the index of the first brain model surface (returns -1 if not found) int getFirstBrainModelSurfaceIndex() const; /// set the "active" fiducial surface void setActiveFiducialSurface(BrainModelSurface* bms); /// get the "active" fiducial surface BrainModelSurface* getActiveFiducialSurface(); /// get the left fiducial volume interaction surface BrainModelSurface* getLeftFiducialVolumeInteractionSurface(); /// get the right fiducial volume interaction surface BrainModelSurface* getRightFiducialVolumeInteractionSurface(); /// get the cerebellum fiducial volume interaction surface BrainModelSurface* getCerebellumFiducialVolumeInteractionSurface(); /// set the left fiducial volume interaction surface void setLeftFiducialVolumeInteractionSurface(BrainModelSurface* bms); /// set the right fiducial volume interaction surface void setRightFiducialVolumeInteractionSurface(BrainModelSurface* bms); /// set the cerebellum fiducial volume interaction surface void setCerebellumFiducialVolumeInteractionSurface(BrainModelSurface* bms); /// delete a brain model surface void deleteBrainModelSurface(BrainModelSurface* bms); /// delete all brain model surfaces void deleteAllBrainModelSurfaces(); /// delete all topology files void deleteAllTopologyFiles(); /// get a brain model volume (if negative index first one found is returned) BrainModelVolume* getBrainModelVolume(const int modelIndex = -1); /// get a brain model volume (if negative index first one found is returned) CONST method const BrainModelVolume* getBrainModelVolume(const int modelIndex = -1) const; /// get a brain model surface and volume (if negative index first one found is returned) BrainModelSurfaceAndVolume* getBrainModelSurfaceAndVolume(const int modelIndex = -1); /// get a brain model surface and volume (if negative index first one found is returned) CONST method const BrainModelSurfaceAndVolume* getBrainModelSurfaceAndVolume(const int modelIndex = -1) const; /// get a brain model surface of the specified type BrainModelSurface* getBrainModelSurfaceOfType(const BrainModelSurface::SURFACE_TYPES st); /// get the number of nodes int getNumberOfNodes() const; /// find a node with the specified morph row and column (returns -1 if not found) int getNodeWithMorphRowColumn(const int row, const int column, const int startAtNode = 0) const; /// get the identification object BrainModelIdentification* getBrainModelIdentification() { return brainModelIdentification; } /// get the region of interest node selection object BrainModelSurfaceROINodeSelection* getBrainModelSurfaceRegionOfInterestNodeSelection() { return brainModelSurfaceRegionOfInterestNodeSelection; } /// get the region of interest node selection object const method const BrainModelSurfaceROINodeSelection* getBrainModelSurfaceRegionOfInterestNodeSelection() const { return brainModelSurfaceRegionOfInterestNodeSelection; } /// get access to node coloring BrainModelSurfaceNodeColoring* getNodeColoring() { return nodeColoring; } /// get access to the voxel coloring BrainModelVolumeVoxelColoring* getVoxelColoring() { return voxelColoring; } /// get the volume region of interest controller BrainModelVolumeRegionOfInterest* getVolumeRegionOfInterestController() { return brainModelVolumeRegionOfInterest; } /// get the stereotaxic space StereotaxicSpace getStereotaxicSpace() const { return stereotaxicSpace; } /// set the stereotaxic space (const method) void setStereotaxicSpace(const StereotaxicSpace& ss); /// get the subject QString getSubject() const { return subject; } /// set the subject void setSubject(const QString& s); /// get the species Species getSpecies() const { return species; } /// set the species void setSpecies(const Species& s); /// get the structure Structure getStructure() const { return structure; } /// set the structure void setStructure(const Structure::STRUCTURE_TYPE s); /// set the structure void setStructure(const Structure& s); /// guess subject, species, and structure if not specified void guessSubjectSpeciesStructureFromCoordTopoFileNames(); /// get the brain set auto loader manager BrainSetAutoLoaderManager* getAutoLoaderManager() { return brainSetAutoLoaderManager; } /// add a document file void addDocumentFile(const QString& documentFileName); /// get the areal estimation file ArealEstimationFile* getArealEstimationFile() { return arealEstimationFile; } /// get the cocomac file CocomacConnectivityFile* getCocomacFile() { return cocomacFile; } /// get the contour cell file ContourCellFile* getContourCellFile() { return contourCellFile; } /// get the contour cell color file ContourCellColorFile* getContourCellColorFile() { return contourCellColorFile; } /// get the cuts file CutsFile* getCutsFile() { return cutsFile; } /// get the name of the deformation map file QString getDeformationMapFileName() const { return deformationMapFileName; } /// set the deformation map file name void setDeformationMapFileName(const QString& name, const bool updateSpec); /// get the deformation field file DeformationFieldFile* getDeformationFieldFile() { return deformationFieldFile; } /// get the metric file MetricFile* getMetricFile() { return metricFile; } /// get the area color file AreaColorFile* getAreaColorFile() { return areaColorFile; } /// get the probabilistic atlas file ProbabilisticAtlasFile* getProbabilisticAtlasSurfaceFile() { return probabilisticAtlasSurfaceFile; } /// get the paint file PaintFile* getPaintFile() { return paintFile; } /// get the palette file PaletteFile* getPaletteFile() { return paletteFile; } /// get the parameters file ParamsFile* getParamsFile() { return paramsFile; } /// get the RGB Paint file RgbPaintFile* getRgbPaintFile() { return rgbPaintFile; } /// get the study collection file StudyCollectionFile* getStudyCollectionFile() { return studyCollectionFile; } /// get the study metadata file StudyMetaDataFile* getStudyMetaDataFile() { return studyMetaDataFile; } /// get the vocabulary file VocabularyFile* getVocabularyFile() { return vocabularyFile; } /// get the wustl region file WustlRegionFile* getWustlRegionFile() { return wustlRegionFile; } /// get the geodesic distance file GeodesicDistanceFile* getGeodesicDistanceFile() { return geodesicDistanceFile; } /// get the surface shape file SurfaceShapeFile* getSurfaceShapeFile() { return surfaceShapeFile; } /// get the number of vector files int getNumberOfVectorFiles() const{ return vectorFiles.size(); } /// get the vector file VectorFile* getVectorFile(const int indx) { return vectorFiles[indx]; } /// get the vector file (const method) const VectorFile* getVectorFile(const int indx) const { return vectorFiles[indx]; } /// add a vector file void addVectorFile(VectorFile* vf); /// remove a vector file void removeVectorFile(const int indx); /// remove a vector file void removeVectorFile(VectorFile* vf); /// get vector file's index int getVectorFileIndex(VectorFile* vf); /// get the number of topology files int getNumberOfTopologyFiles() const { return topologyFiles.size(); } /// get a topology file by its index TopologyFile* getTopologyFile(const int index) { return topologyFiles[index]; } /// get the topography file TopographyFile* getTopographyFile() { return topographyFile; } /// get the closed topology TopologyFile* getTopologyClosed() { return topologyClosed; } /// get the open topology TopologyFile* getTopologyOpen() { return topologyOpen; } /// get the cut topology TopologyFile* getTopologyCut() { return topologyCut; } /// get the lobar cut topology TopologyFile* getTopologyLobarCut() { return topologyLobarCut; } /// get the unknown topology TopologyFile* getTopologyUnknown() { return topologyUnknown; } /// get the transformation matrix file TransformationMatrixFile* getTransformationMatrixFile() { return transformationMatrixFile; } /// get the name of the cerebral hull file QString getCerebralHullFileName() const { return cerebralHullFileName; } /// generate the cerebral hull vtk file from the segmentation volume void generateCerebralHullVtkFile(const VolumeFile* segmentationVolume, const bool saveHullVolumeFileFlag) throw (BrainModelAlgorithmException); /// generate the cerebral hull vtk file /// caller must delete the output files (hull volume and VTK file) void generateCerebralHullVtkFile(const VolumeFile* segmentationVolumeIn, VolumeFile* &cerebralHullVolumeOut, vtkPolyData* &cerebralHullVtkPolyDataOut) throw (BrainModelAlgorithmException); /// get the areal estimation settings DisplaySettingsArealEstimation* getDisplaySettingsArealEstimation() { return displaySettingsArealEstimation; } /// get the border display settings DisplaySettingsBorders* getDisplaySettingsBorders() { return displaySettingsBorders; } /// get the cell display settings DisplaySettingsCells* getDisplaySettingsCells() { return displaySettingsCells; } /// get the contour display settings DisplaySettingsContours* getDisplaySettingsContours() { return displaySettingsContours; } /// get the cuts display settings DisplaySettingsCuts* getDisplaySettingsCuts() { return displaySettingsCuts; }; /// get the cocomac display settings DisplaySettingsCoCoMac* getDisplaySettingsCoCoMac() { return displaySettingsCoCoMac; } /// get the foci display settings DisplaySettingsFoci* getDisplaySettingsFoci() { return displaySettingsFoci; } /// get the deformation field display settings DisplaySettingsDeformationField* getDisplaySettingsDeformationField() { return displaySettingsDeformationField; } /// get the images display settings DisplaySettingsImages* getDisplaySettingsImages() { return displaySettingsImages; } /// get the metric display settings DisplaySettingsMetric* getDisplaySettingsMetric() { return displaySettingsMetric; } /// get the model display settings DisplaySettingsModels* getDisplaySettingsModels() { return displaySettingsModels; } /// get the node display settings DisplaySettingsSurface* getDisplaySettingsSurface() { return displaySettingsSurface; } /// get the section display settings DisplaySettingsSection* getDisplaySettingsSection() { return displaySettingsSection; } /// get the paint display settings DisplaySettingsPaint* getDisplaySettingsPaint() { return displaySettingsPaint; } /// get the prob atlas display settings DisplaySettingsProbabilisticAtlas* getDisplaySettingsProbabilisticAtlasSurface() { return displaySettingsProbabilisticAtlasSurface; } /// get the rgb paint display settings DisplaySettingsRgbPaint* getDisplaySettingsRgbPaint() { return displaySettingsRgbPaint; } /// get the scene display settings DisplaySettingsScene* getDisplaySettingsScene() { return displaySettingsScene; } /// get the surface shape display settings DisplaySettingsSurfaceShape* getDisplaySettingsSurfaceShape() { return displaySettingsSurfaceShape; } /// get the study metadata display settings DisplaySettingsStudyMetaData* getDisplaySettingsStudyMetaData() { return displaySettingsStudyMetaData; } /// get the surface display settings DisplaySettingsVectors* getDisplaySettingsVectors() { return displaySettingsVectors; }; /// get the topography file display settings DisplaySettingsTopography* getDisplaySettingsTopography() { return displaySettingsTopography; } /// get the volume display settings DisplaySettingsVolume* getDisplaySettingsVolume() { return displaySettingsVolume; } /// get the volume display settings (const method) const DisplaySettingsVolume* getDisplaySettingsVolume() const { return displaySettingsVolume; } /// get the volume prob atlas display settings DisplaySettingsProbabilisticAtlas* getDisplaySettingsProbabilisticAtlasVolume() { return displaySettingsProbabilisticAtlasVolume; } /// get the wustl region display settings DisplaySettingsWustlRegion* getDisplaySettingsWustlRegion() { return displaySettingsWustlRegion; } /// get the geodesic distance display settings DisplaySettingsGeodesicDistance* getDisplaySettingsGeodesicDistance() { return displaySettingsGeodesicDistance; } /// Set the default scaling for all surfaces void setDefaultScaling(const float orthoRight, const float orthoTop); /// reset the Brain Surfaces void reset(const bool keepSceneData = false); /// reset all data files void resetDataFiles(const bool keepSceneData, const bool keepFociAndFociColorsAndStudyMetaData); /// reset all node attribute files void resetNodeAttributeFiles(); /// create a spec file from all files in the selected scenes void createSpecFromScenes(const std::vector& sceneIndices, const QString& newSpecFileName, const QString& newSceneFileName, QString& errorMessageOut); /// add a tag and file pair to the spec file void addToSpecFile(const QString& specFileTag, const QString& fileName, const QString& fileName2 = ""); /// get the spec file that keeps track of loaded files SpecFile* getLoadedFilesSpecFile() { return &loadedFilesSpecFile; } /// get the spec file (const method) const SpecFile* getLoadedFilesSpecFile() const { return &loadedFilesSpecFile; } /// get the spec file name QString getSpecFileName() const { return specFileName; } /// set the spec file name void setSpecFileName(const QString& name, const bool readOldSpecFileFlag = true); /// get the time the spec file was loaded QDateTime getSpecFileTimeOfLoading() const { return specFileTimeOfLoading; } /// read the spec file (returns true if reading was aborted by user) bool readSpecFile(const SpecFile& specFileIn, const QString& specFileNameIn, QString& errorMessagesOut); /// read the spec file (returns true if reading was aborted by user) bool readSpecFile(const SPEC_FILE_READ_MODE specReadMode, const SpecFile& specFileIn, const QString& specFileNameIn, std::vector& errorMessagesOut, const TransformationMatrix* specTransformationMatrixIn, QProgressDialog* progressDialog); /// read the spec file (returns true if reading was aborted by user) bool readSpecFileMultiThreaded(const SPEC_FILE_READ_MODE specReadMode, const SpecFile& specFileIn, const QString& specFileNameIn, std::vector& errorMessagesOut, const TransformationMatrix* specTransformationMatrixIn, QProgressDialog* progressDialog); /// read the spec file (returns true if reading was aborted by user) bool readSpecFile(const SPEC_FILE_READ_MODE specReadMode, const SpecFile& specFileIn, const QString& specFileNameIn, QString& errorMessageOut, const TransformationMatrix* specTransformationMatrixIn, QProgressDialog* progressDialog); /// delete all borders void deleteAllBorders(); /// get the border color file BorderColorFile* getBorderColorFile() { return borderColorFile; } /// get the border set BrainModelBorderSet* getBorderSet() { return brainModelBorderSet; } /// get the volume borders BorderFile* getVolumeBorderFile() { return brainModelBorderSet->getVolumeBorders(); } /// convert volume borders to cells void convertVolumeBordersToFiducialCells(); /// get the volume borders const method const BorderFile* getVolumeBorderFile() const { return brainModelBorderSet->getVolumeBorders(); } /// cell color file CellColorFile* getCellColorFile() { return cellColorFile; } /// get the cell projection file CellProjectionFile* getCellProjectionFile() { return cellProjectionFile; } /// get the volume cell file CellFile* getVolumeCellFile() { return volumeCellFile; } /// get the volume cell file (const method) const CellFile* getVolumeCellFile() const { return volumeCellFile; } /// delete all cells and cell projections void deleteAllCells(const bool deleteCellProjections, const bool deleteVolumeCells); /// delete all cell projections (including those in cell files) void deleteAllCellProjections(); /// delete a cell void deleteCell(const int cellNumber); /// remove unlinked studies from study meta data file int removeUnlinkedStudiesFromStudyMetaDataFile(); /// move foci study info to the study meta data file void moveFociStudyInfoToStudyMetaDataFile(); /// get the foci color file FociColorFile* getFociColorFile() { return fociColorFile; } /// get the foci projection file FociProjectionFile* getFociProjectionFile() { return fociProjectionFile; } /// get the foci search file FociSearchFile* getFociSearchFile() { return fociSearchFile; } /// delete all foci projections (including those in foci files) void deleteAllFociProjections(); /// delete a focus void deleteFocus(const int focusNumber); /// get the lat/lon file LatLonFile* getLatLonFile() { return latLonFile; } /// get the section file SectionFile* getSectionFile() { return sectionFile; } /// get the scene file SceneFile* getSceneFile() { return sceneFile; }; /// get the preferences file static PreferencesFile* getPreferencesFile(); /// get the number of volume functional files int getNumberOfVolumeFunctionalFiles() const { return volumeFunctionalFiles.size(); } /// get the volume functional file VolumeFile* getVolumeFunctionalFile(const int index); /// get the volume functional file (const method) const VolumeFile* getVolumeFunctionalFile(const int index) const; /// get the functional volume file with the specified name (NULL if not found) VolumeFile* getVolumeFunctionalFileWithName(const QString& name); /// get the volume functional files void getVolumeFunctionalFiles(std::vector& files) { files = volumeFunctionalFiles; } /// get the number of paint volume files int getNumberOfVolumePaintFiles() const { return volumePaintFiles.size(); } /// get the volume paint file VolumeFile* getVolumePaintFile(const int index); /// get the volume paint file (const method) const VolumeFile* getVolumePaintFile(const int index) const; /// get the paint volume file with the specified name (NULL if not found) VolumeFile* getVolumePaintFileWithName(const QString& name); /// get the volume paint files void getVolumePaintFiles(std::vector& files) { files = volumePaintFiles; } /// get the volume prob atlas file VolumeFile* getVolumeProbAtlasFile(const int index); /// get the volume prob atlas file (const method) const VolumeFile* getVolumeProbAtlasFile(const int index) const; /// get the prob atlas volume file with the specified name (NULL if not found) VolumeFile* getVolumeProbAtlasFileWithName(const QString& name); /// get the volume prob atlas files void getVolumeProbAtlasFiles(std::vector& files) { files = volumeProbAtlasFiles; } /// get the number of prob atlas volume files int getNumberOfVolumeProbAtlasFiles() const { return volumeProbAtlasFiles.size(); } /// synchronize prob atlas volume region names void synchronizeProbAtlasVolumeRegionNames(); /// get the number of rgb volume files int getNumberOfVolumeRgbFiles() const { return volumeRgbFiles.size(); } /// get the volume rgb file VolumeFile* getVolumeRgbFile(const int index); /// get the volume rgb file (const method) const VolumeFile* getVolumeRgbFile(const int index) const; /// get the RGB volume file with the specified name (NULL if not found) VolumeFile* getVolumeRgbFileWithName(const QString& name); /// get the volume rgb files void getVolumeRgbFiles(std::vector& files) { files = volumeRgbFiles; } /// get the number of volume segmentation files int getNumberOfVolumeSegmentationFiles() const { return volumeSegmentationFiles.size(); } /// get the volume segmentation file VolumeFile* getVolumeSegmentationFile(const int index); /// get the volume segmentation file (const method) const VolumeFile* getVolumeSegmentationFile(const int index) const; /// get the segmentation volume file with the specified name (NULL if not found) VolumeFile* getVolumeSegmentationFileWithName(const QString& name); /// get the volume segmentation files void getVolumeSegmentationFiles(std::vector& files) { files = volumeSegmentationFiles; } /// get the number of volume anatomy files int getNumberOfVolumeAnatomyFiles() const { return volumeAnatomyFiles.size(); } /// get the volume anatomy file VolumeFile* getVolumeAnatomyFile(const int index); /// get the volume anatomy file (const method) const VolumeFile* getVolumeAnatomyFile(const int index) const; /// get the anatomy volume file with the specified name (NULL if not found) VolumeFile* getVolumeAnatomyFileWithName(const QString& name); /// get the volume anatomy files void getVolumeAnatomyFiles(std::vector& files) { files = volumeAnatomyFiles; } /// get the number of volume vector files int getNumberOfVolumeVectorFiles() const { return volumeVectorFiles.size(); } /// get the volume vector file VolumeFile* getVolumeVectorFile(const int index); /// get the volume vector file (const method) const VolumeFile* getVolumeVectorFile(const int index) const; /// get the vector volume file with the specified name (NULL if not found) VolumeFile* getVolumeVectorFileWithName(const QString& name); /// get the volume vector files void getVolumeVectorFiles(std::vector& files) { files = volumeVectorFiles; } /// delete all image files void deleteAllImageFiles(); /// delete an image file void deleteImageFile(ImageFile* img); /// add an image file void addImageFile(ImageFile* img); /// get number of image files int getNumberOfImageFiles() const { return imageFiles.size(); } /// get an image file ImageFile* getImageFile(const int fileNum); /// get an image file based upon the image's name ImageFile* getImageFile(const QString& filename); /// see if an image file is valid bool getImageFileValid(const ImageFile* img) const; /// delete all of the VTK model files void deleteAllVtkModelFiles(); /// delete a VTK model file void deleteVtkModelFile(VtkModelFile* vmf); /// add a VTK model file void addVtkModelFile(VtkModelFile* vmf); /// get the number of vtk model files int getNumberOfVtkModelFiles() const { return vtkModelFiles.size(); } /// get a vtk model file VtkModelFile* getVtkModelFile(const int modelNum); /// assign transformation data file colors void assignTransformationDataFileColors(); /// get the number of transformation data files int getNumberOfTransformationDataFiles() const { return transformationDataFiles.size(); } /// get a transformation data file AbstractFile* getTransformationDataFile(const int indx) { return transformationDataFiles[indx]; } /// get a transformation data file (const method) const AbstractFile* getTransformationDataFile(const int indx) const { return transformationDataFiles[indx]; } /// delete a transformation data file void deleteTransformationDataFile(const int fileIndex); /// delete a transformation data file void deleteTransformationDataFile(AbstractFile* af); /// get have transformation data cell files bool getHaveTransformationDataCellFiles() const; /// get have transformation data contour files bool getHaveTransformationDataContourFiles() const; /// get have transformation data contour cell files bool getHaveTransformationDataContourCellFiles() const; /// get have transformation data foci files bool getHaveTransformationDataFociFiles() const; /// get have transformation data vtk files bool getHaveTransformationDataVtkFiles() const; /// get caret's home directory static QString getCaretHomeDirectory(); /// get the common node attributes for a node BrainSetNodeAttribute* getNodeAttributes(const int nodeNum); /// get the common node attributes for a node (const method) const BrainSetNodeAttribute* getNodeAttributes(const int nodeNum) const { return &nodeAttributes[nodeNum]; } /// set the visited flag on all node attributes void setAllNodesVisited(const bool value); /// read the areal estimation data file void readArealEstimationFile(const QString& name, const bool append, const bool updateSpec) throw (FileException); /// read the areal estimation data file (only selected columns) void readArealEstimationFile(const QString& name, const std::vector& columnDestination, const std::vector& fileBeingReadColumnNames, const AbstractFile::FILE_COMMENT_MODE fcm, const bool updateSpec) throw (FileException); /// write the ArealEstimation data file void writeArealEstimationFile(const QString& name) throw (FileException); /// read a volume border file void readVolumeBorderFile(const QString& name, const bool append, const bool updateSpec) throw (FileException); /// write a volume border file void writeVolumeBorderFile(const QString& name, const bool removeDuplicates = false) throw (FileException); /// read the border data file void readBorderFile(const QString& name, const BrainModelSurface::SURFACE_TYPES st, const bool append, const bool updateSpec) throw (FileException); /// write the Border data file void writeBorderFile(const QString& name, const BrainModelSurface* bms, const BrainModelSurface::SURFACE_TYPES borderFileType, const QString& commentText, const QString& pubMedID, const bool removeDuplicates = false) throw (FileException); /// read the border color data file void readBorderColorFile(const QString& name, const bool append, const bool updateSpec) throw (FileException); /// write the BorderColor data file void writeBorderColorFile(const QString& name) throw (FileException); /// read the border projection data file void readBorderProjectionFile(const QString& name, const bool append, const bool updateSpec) throw (FileException); /// write the BorderProjection data file void writeBorderProjectionFile(const QString& name, const QString& commentText, const QString& pubMedID, const bool removeDuplicates = false) throw (FileException); /// read the cell data file void readCellFile(const QString& name, const bool append, const bool updateSpec) throw (FileException); /// read the volume cell data file void readVolumeCellFile(const QString& name, const bool append, const bool updateSpec) throw (FileException); /// write the Cell data file void writeCellFile(const QString& name, const BrainModelSurface* bms, const AbstractFile::FILE_FORMAT fileFormat, const QString& commentText) throw (FileException); /// write the Volume Cell data file void writeVolumeCellFile(const QString& name) throw (FileException); /// read the cell color data file void readCellColorFile(const QString& name, const bool append, const bool updateSpec) throw (FileException); /// write the CellColor data file void writeCellColorFile(const QString& name) throw (FileException); /// read the cell projection data file void readCellProjectionFile(const QString& name, const bool append, const bool updateSpec) throw (FileException); /// write the CellProjection data file void writeCellProjectionFile(const QString& name) throw (FileException); /// read the cocomac connectivity file void readCocomacConnectivityFile(const QString& name, const bool append, const bool updateSpec) throw (FileException); /// write the CocomacConnectivity data file void writeCocomacConnectivityFile(const QString& name) throw (FileException); /// read a contour file void readContourFile(const QString& name, const bool append, const bool updateSpec) throw (FileException); /// write the Contour data file void writeContourFile(const QString& name, ContourFile* cf) throw (FileException); /// read a contour cell file void readContourCellFile(const QString& name, const bool append, const bool updateSpec) throw (FileException); /// read a contour cell color file void readContourCellColorFile(const QString& name, const bool append, const bool updateSpec) throw (FileException); /// write the Contour Cell data file void writeContourCellFile(const QString& name) throw (FileException); /// write the Contour Cell Color data file void writeContourCellColorFile(const QString& name) throw (FileException); /// read the coordinate data file file void readCoordinateFile(const QString& name, const BrainModelSurface::SURFACE_TYPES st, const bool readingSpecFile, const bool append, const bool updateSpec) throw (FileException); /// write the coordinate data file void writeCoordinateFile(const QString& name, const BrainModelSurface::SURFACE_TYPES st, CoordinateFile* cf, const bool updateSpecFile = true) throw (FileException); /// read the surface data file file void readSurfaceFile(const QString& name, const BrainModelSurface::SURFACE_TYPES st, const bool readingSpecFile, const bool append, const bool updateSpec) throw (FileException); /// write the surface data file void writeSurfaceFile(const QString& name, const BrainModelSurface::SURFACE_TYPES st, BrainModelSurface* bms, const bool updateSpecFile = true, const AbstractFile::FILE_FORMAT fileFormat = AbstractFile::FILE_FORMAT_XML) throw (FileException); /// read the cuts file void readCutsFile(const QString& name, const bool append, const bool updateSpec) throw (FileException); /// write the Cuts data file void writeCutsFile(const QString& name) throw (FileException); /// read the foci data file file void readFociFile(const QString& name, const bool append, const bool updateSpec) throw (FileException); /// write the Foci data file void writeFociFile(const QString& name, const BrainModelSurface* leftBms, const BrainModelSurface* rightBms, const BrainModelSurface* cerebellumBMS, const AbstractFile::FILE_FORMAT fileFormat, const QString& commentText) throw (FileException); /// write the Foci data file void writeFociFileOriginalCoordinates(const QString& name, const AbstractFile::FILE_FORMAT fileFormat, const QString& commentText) throw (FileException); /// read the foci color data file file void readFociColorFile(const QString& name, const bool append, const bool updateSpec) throw (FileException); /// write the FociColor data file void writeFociColorFile(const QString& name) throw (FileException); /// read the foci projection data file file void readFociProjectionFile(const QString& name, const bool append, const bool updateSpec) throw (FileException); /// write the FociProjection data file void writeFociProjectionFile(const QString& name) throw (FileException); /// read the foci search file void readFociSearchFile(const QString& name, const bool append, const bool updateSpec) throw (FileException); /// write the foci search file void writeFociSearchFile(const QString& name) throw (FileException); /// read the geodesic distance data file file void readGeodesicDistanceFile(const QString& name, const bool append, const bool updateSpec) throw (FileException); /// read the geodesic distance data file file (only selected columns) void readGeodesicDistanceFile(const QString& name, const std::vector& columnDestination, const std::vector& fileBeingReadColumnNames, const AbstractFile::FILE_COMMENT_MODE fcm, const bool updateSpec) throw (FileException); /// write the geodesic distance data file void writeGeodesicDistanceFile(const QString& name) throw (FileException); /// read the lat lon data file file void readLatLonFile(const QString& name, const bool append, const bool updateSpec) throw (FileException); /// read the lat lon data file file (only selected columns) void readLatLonFile(const QString& name, const std::vector& columnDestination, const std::vector& fileBeingReadColumnNames, const AbstractFile::FILE_COMMENT_MODE fcm, const bool updateSpec) throw (FileException); /// write the LatLon data file void writeLatLonFile(const QString& name) throw (FileException); /// read the deformation field file void readDeformationFieldFile(const QString& name, const bool append, const bool updateSpec) throw (FileException); /// read the deformation field file (only selected columns) void readDeformationFieldFile(const QString& name, const std::vector& columnDestination, const std::vector& fileBeingReadColumnNames, const AbstractFile::FILE_COMMENT_MODE fcm, const bool updateSpec) throw (FileException); /// write the deformation field data file void writeDeformationFieldFile(const QString& name) throw (FileException); /// read the metric data file file void readMetricFile(const QString& name, const bool append, const bool updateSpec) throw (FileException); /// read the metric data file file (only selected columns) void readMetricFile(const QString& name, const std::vector& columnDestination, const std::vector& fileBeingReadColumnNames, const AbstractFile::FILE_COMMENT_MODE fcm, const bool updateSpec) throw (FileException); /// write the Metric data file void writeMetricFile(const QString& name) throw (FileException); /// read the area color data file file void readAreaColorFile(const QString& name, const bool append, const bool updateSpec) throw (FileException); /// write the NodeColor data file void writeAreaColorFile(const QString& name) throw (FileException); /// read the paint data file file (only selected columns) void readPaintFile(const QString& name, const std::vector& columnDestination, const std::vector& fileBeingReadColumnNames, const AbstractFile::FILE_COMMENT_MODE fcm, const bool updateSpec) throw (FileException); /// read the paint data file file void readPaintFile(const QString& name, const bool append, const bool updateSpec) throw (FileException); /// write the Paint data file void writePaintFile(const QString& name) throw (FileException); /// read the study collection file void readStudyCollectionFile(const QString& name, const bool append, const bool updateSpec) throw (FileException); /// write the study collection file void writeStudyCollectionFile(const QString& name) throw (FileException); /// read the study metadata file void readStudyMetaDataFile(const QString& name, const bool append, const bool updateSpec) throw (FileException); /// write the study metadata file void writeStudyMetaDataFile(const QString& name) throw (FileException); /// read the vocabulary file void readVocabularyFile(const QString& name, const bool append, const bool updateSpec) throw (FileException); /// write the vocabulary file void writeVocabularyFile(const QString& name) throw (FileException); /// read the wustl region file void readWustlRegionFile(const QString& name, const bool append, const bool updateSpec) throw (FileException); /// write the wustl region file void writeWustlRegionFile(const QString& name) throw (FileException); /// read the palette data file file void readPaletteFile(const QString& name, const bool append, const bool updateSpec) throw (FileException); /// write the Palette data file void writePaletteFile(const QString& name) throw (FileException); /// read the params data file file void readParamsFile(const QString& name, const bool append, const bool updateSpec) throw (FileException); /// write the Params data file void writeParamsFile(const QString& name) throw (FileException); /// read the prob atlas data file file void readProbabilisticAtlasFile(const QString& name, const bool append, const bool updateSpec) throw (FileException); /// write the ProbabilisticAtlas data file void writeProbabilisticAtlasFile(const QString& name) throw (FileException); /// read the rgb paint data file file void readRgbPaintFile(const QString& name, const bool append, const bool updateSpec) throw (FileException); /// write the RgbPaint data file void writeRgbPaintFile(const QString& name) throw (FileException); /// read the scene data file file void readSceneFile(const QString& name, const bool append, const bool updateSpec) throw (FileException); /// write the scene data file void writeSceneFile(const QString& name) throw (FileException); /// read the section data file file void readSectionFile(const QString& name, const bool append, const bool updateSpec) throw (FileException); /// write the Section data file void writeSectionFile(const QString& name) throw (FileException); /// read the image data file void readImageFile(const QString& name, const bool append, const bool updateSpec) throw (FileException); /// write the image data file void writeImageFile(const QString& name, ImageFile* img) throw (FileException); /// read the vtk model data file void readVtkModelFile(const QString& name, const bool append, const bool updateSpec) throw (FileException); /// write the vtk model data file void writeVtkModelFile(const QString& name, VtkModelFile* vmf) throw (FileException); /// read the surface shape data file file (only selected columns) void readSurfaceShapeFile(const QString& name, const std::vector& columnDestination, const std::vector& fileBeingReadColumnNames, const AbstractFile::FILE_COMMENT_MODE fcm, const bool updateSpec) throw (FileException); /// read the surface shape data file file void readSurfaceShapeFile(const QString& name, const bool append, const bool updateSpec) throw (FileException); /// write the SurfaceShape data file void writeSurfaceShapeFile(const QString& name) throw (FileException); /// read the vector data file file void readVectorFile(const QString& name, const bool append, const bool updateSpec) throw (FileException); /// write the Vector data file void writeVectorFile(VectorFile* vf, const QString& name) throw (FileException); /// read the topography data file file void readTopographyFile(const QString& name, const bool append, const bool updateSpec) throw (FileException); /// write the Topography data file void writeTopographyFile(const QString& name) throw (FileException); /// read the topology data file file void readTopologyFile(const QString& name, const TopologyFile::TOPOLOGY_TYPES tt, const bool append, const bool updateSpec) throw (FileException); /// write theTopology data file void writeTopologyFile(const QString& name, const TopologyFile::TOPOLOGY_TYPES tt, TopologyFile* tf) throw (FileException); /// read the transformation matrix file void readTransformationMatrixFile(const QString& name, const bool append, const bool updateSpec) throw (FileException); /// write the transformation matrix file void writeTransformationMatrixFile(const QString& name) throw (FileException); /// read the transformation data file void readTransformationDataFile(const QString& name, const bool append, const bool updateSpec) throw (FileException); /// read volume data file void readVolumeFile(const QString& name, const VolumeFile::VOLUME_TYPE vt, const bool append, const bool updateSpec) throw (FileException); /// write the volume data file void writeVolumeFile(const QString& name, const VolumeFile::FILE_READ_WRITE_TYPE writeFileType, const VolumeFile::VOLUME_TYPE volumeType, VolumeFile* vf, const VolumeFile::VOXEL_DATA_TYPE voxelDataTypeToWrite = VolumeFile::VOXEL_DATA_TYPE_UNKNOWN, const bool zipAfniVolumeFile = false) throw (FileException); /// Write the multi-volume file data. void writeMultiVolumeFile(const QString& name, const VolumeFile::VOLUME_TYPE volumeType, const QString& comment, std::vector& subVolumes, const VolumeFile::VOXEL_DATA_TYPE voxelDataTypeToWrite = VolumeFile::VOXEL_DATA_TYPE_UNKNOWN, const bool zipAfniVolumeFile = false) throw (FileException); /// reset node attributes (ensures number of attributes == num nodes) void resetNodeAttributes(); /// clear the node attributes void clearNodeAttributes(); /// clear all node highlight symbols void clearNodeHighlightSymbols(); /// disconnect the nodes for the specified topology file. All coordinate files using this /// topology will have disconnected nodes moved to the origin. void disconnectNodes(TopologyFile* tf, const std::vector& nodesToDisconnect); /// disconnect the nodes with the specified paint names in the specified paint column void disconnectNodes(TopologyFile* tf, const std::vector& paintNames, const int paintColumn); /// disconnect the nodes with the specified paint indices in the specified paint column void disconnectNodes(TopologyFile* tf, const std::vector& paintIndices, const int paintColumn); /// set the parent for progress dialogs (if this is called with a non-null value, progress /// dialogs will be displayed during "longish" operations. void setProgressDialogParent(QWidget* parent) { progressDialogParent = parent; } /// get the progress dialog parent QWidget* getProgressDialogParent() { return progressDialogParent; } /// import MD Plot file void importMDPlotFile(const QString& filename, const bool importPointsAsContourCells, const bool importLinesAsContours, const bool appendToExistingContours, const bool appendToExistingContourCells) throw (FileException); /// import Neurolucida file void importNeurolucidaFile(const QString& filename, const bool importMarkersAsCells, const bool importContours, const bool appendToExistingContours, const bool appendToExistingContourCells) throw (FileException); /// import brain voyager file void importBrainVoyagerFile(const QString& filename, const bool importCoordinates, const bool importTopology, const bool importColors, const BrainModelSurface::SURFACE_TYPES surfaceType = BrainModelSurface::SURFACE_TYPE_FIDUCIAL, const TopologyFile::TOPOLOGY_TYPES topologyType = TopologyFile::TOPOLOGY_TYPE_CLOSED) throw (FileException); /// import mni obj surface file void importMniObjSurfaceFile(const QString& filename, const bool importCoordinates, const bool importTopology, const bool importColors, const BrainModelSurface::SURFACE_TYPES surfaceType = BrainModelSurface::SURFACE_TYPE_FIDUCIAL, const TopologyFile::TOPOLOGY_TYPES topologyType = TopologyFile::TOPOLOGY_TYPE_CLOSED) throw (FileException); /// import byu surface file void importByuSurfaceFile(const QString& filename, const bool importCoordinates, const bool importTopology, const BrainModelSurface::SURFACE_TYPES surfaceType, const TopologyFile::TOPOLOGY_TYPES topologyType) throw (FileException); /// Export to a free surfer ascii surface file. void exportFreeSurferAsciiSurfaceFile(BrainModelSurface* bms, const QString& filename) throw (FileException); /// import a free surfer ascii surface file void importFreeSurferSurfaceFile(const QString& filename, const bool importCoordinates, const bool importTopology, const AbstractFile::FILE_FORMAT fileFormat = AbstractFile::FILE_FORMAT_ASCII, const BrainModelSurface::SURFACE_TYPES surfaceType = BrainModelSurface::SURFACE_TYPE_FIDUCIAL, const TopologyFile::TOPOLOGY_TYPES topologyType = TopologyFile::TOPOLOGY_TYPE_CLOSED) throw (FileException); /// import stl surface file void importStlSurfaceFile(const QString& filename, const bool importCoordinates, const bool importTopology, const BrainModelSurface::SURFACE_TYPES surfaceType, const TopologyFile::TOPOLOGY_TYPES topologyType) throw (FileException); /// import vtk surface file void importVtkSurfaceFile(const QString& filename, const bool importCoordinates, const bool importTopology, const bool importColors, const BrainModelSurface::SURFACE_TYPES surfaceType, const TopologyFile::TOPOLOGY_TYPES topologyType) throw (FileException); /// import vtk XML surface file void importVtkXmlSurfaceFile(const QString& filename, const bool importCoordinates, const bool importTopology, const bool importColors, const BrainModelSurface::SURFACE_TYPES surfaceType, const TopologyFile::TOPOLOGY_TYPES topologyType) throw (FileException); /// Import vtk type files (vtk, stl, byu) void importVtkTypeFileHelper(const QString& filename, vtkPolyData* polyData, const bool importCoordinates, const bool importTopology, const bool importColors, const BrainModelSurface::SURFACE_TYPES surfaceType, const TopologyFile::TOPOLOGY_TYPES topologyType) throw (FileException); /// Import Analyze volume file void importAnalyzeVolumeFile(const QString& filename, const VolumeFile::VOLUME_TYPE volumeType) throw (FileException); /// Export Analyze volume file void exportAnalyzeVolumeFile(VolumeFile* vf, const QString& filename) throw (FileException); /// Export MINC volume file void exportMincVolumeFile(VolumeFile* vf, const QString& filename) throw (FileException); /// Import Raw volume file void importRawVolumeFile(const QString& filename, const VolumeFile::VOLUME_TYPE volumeType, const int dimensions[3], const VolumeFile::VOXEL_DATA_TYPE voxelDataType, const bool byteSwap) throw (FileException); /// Import MINC volume file void importMincVolumeFile(const QString& filename, const VolumeFile::VOLUME_TYPE volumeType) throw (FileException); /// Import VTK structured points volume file void importVtkStructuredPointsVolumeFile(const QString& filename, const VolumeFile::VOLUME_TYPE volumeType) throw (FileException); /// Export VTK structured points volume file void exportVtkStructuredPointsVolumeFile(VolumeFile* vf, const QString& filename) throw (FileException); /// export byu surface file void exportByuSurfaceFile(const BrainModelSurface* bms, const QString& filename) throw (FileException); /// export inventor surface file void exportInventorSurfaceFile(const BrainModelSurface* bms, const QString& filename) throw (FileException); /// export stl surface file void exportStlSurfaceFile(const BrainModelSurface* bms, const QString& filename) throw (FileException); /// export 3dStudio ASE surface file void export3DStudioASESurfaceFile(const BrainModelSurface* bms, const QString& filename) throw (FileException); /// export vrml surface file void exportVrmlSurfaceFile(const BrainModelSurface* bms, const QString& filename) throw (FileException); /// export wavefront object surface file void exportWavefrontSurfaceFile(const BrainModelSurface* bms, const QString& filename) throw (FileException); /// Convert a BrainModelSurface to a vtkPolyData file with option of node colors vtkPolyData* convertToVtkPolyData(const BrainModelSurface* bms, const bool useNodeColors); /// export vtk surface file void exportVtkSurfaceFile(const BrainModelSurface* bms, const QString& filename, const bool exportColors) throw (FileException); /// export vtk XML surface file void exportVtkXmlSurfaceFile(const BrainModelSurface* bms, const QString& filename, const bool exportColors) throw (FileException); /// request that a brain model be displayed and drawn by the user of this brain set void drawBrainModel(const int brainModelIndex, const int currentAlgorithmIteration = -1); /// request that a brain model be displayed and drawn by the user of this brain set void drawBrainModel(const BrainModel* bm, const int currentAlgorithmIteration = -1); /// See if this iteration is one in which the brain model should be redrawn. bool isIterationUpdate(const int currentAlgorithmIteration) const; /// Simplify the surface (this also removed all other surfaces and volumes) void simplifySurface(const BrainModelSurface* bms, const int maxPolygons) throw (FileException); /// Initalize things after reading a spec file or initial surface into caret void postSpecFileReadInitializations(); /// get display splash image bool getDisplaySplashImage() const { return displaySplashImage; } /// set display splash image void setDisplaySplashImage(const bool b) { displaySplashImage = b; } /// get the splash image QImage* getSplashImage() { return &splashImage; } /// get the display all nodes flag bool getDisplayAllNodes() const { return displayAllNodesFlag; } /// set the display all nodes flag void setDisplayAllNodes(const bool dan) { displayAllNodesFlag = dan; } /// Set node display flags based upon sections and other criteria. void updateNodeDisplayFlags(); /// load identification filters from a scene void showSceneIdentificationFilters(const SceneFile::Scene* ss, QString& errorMessage); /// apply a scene (set display settings) void showScene(const SceneFile::Scene* ss, const bool checkSpecFlag, QString& errorMessage, QString& warningMessage); /// apply a scene (set display settings) void showScene(const int sceneIndex, QString& errorMessage, QString& warningMessage); /// Get the model for a window from a scene. BrainModel* showSceneGetBrainModel(const int sceneIndex, const int viewingWindowNumberIn, int geometryOut[4], int glWidthHeightOut[2], bool& yokeOut, QString& errorMessageOut); /// Get the model for a window from a scene. BrainModel* showSceneGetBrainModel(const SceneFile::Scene* scene, const int viewingWindowNumberIn, int geometryOut[4], int glWidthHeightOut[2], bool& yokeOut, QString& errorMessageOut); /// create a scene (read display settings) void saveScene(SceneFile* sf, const std::vector& mainWindowSceneClasses, const QString& sceneName, const bool onlyIfSelectedFlag, QString& errorMessageOut, QString& warningMessageOut); /// insert after scene (read display settings) void insertScene(SceneFile* sf, const int insertAfterIndex, const std::vector& mainWindowSceneClasses, const QString& sceneName, const bool onlyIfSelectedFlag, QString& errorMessageOut, QString& warningMessageOut); /// replace a scene (read display settings) void replaceScene(SceneFile* sf, const int sceneIndex, const std::vector& mainWindowSceneClasses, const QString& sceneName, const bool onlyIfSelectedFlag, QString& errorMessageOut, QString& warningMessageOut); /// Save the model for a window from a scene void saveSceneForBrainModelWindow(const int viewingWindowNumber, const int geometry[4], const int glWidthHeight[2], const BrainModel* bm, const bool yokeIn, SceneFile::SceneClass& sceneClass); /// convert displayed borders into a VTK model. void convertDisplayedBordersToVtkModel(const BrainModelSurface* bms); /// convert displayed cells into a VTK model. void convertDisplayedCellsToVtkModel(const BrainModelSurface* bms); /// convert displayed foci into a VTK model. void convertDisplayedFociToVtkModel(const BrainModelSurface* bms); /// get the displayed model index for a window int getDisplayedModelIndexForWindow(const BrainModel::BRAIN_MODEL_VIEW_NUMBER windowNumber) const; /// set the displayed model index for a window void setDisplayedModelIndexForWindow(const BrainModel::BRAIN_MODEL_VIEW_NUMBER windowNumber, const int modelIndex); /// update the default file naming prefix void updateDefaultFileNamePrefix(); /// set when reading coordinate files DO NOT use topology file in coord file header void setIgnoreTopologyFileInCoordinateFileHeaderFlag(const bool b) { ignoreTopologyFileInCoordinateFileHeaderFlag = b; } /// sort the brain models (raw, fiducial, ..., volume, surf&vol, contours) void sortBrainModels(); /// remove coordinate and topoology files from spec file void removeCoordAndTopoFromSpecFile(); /// Get the volume file name with the specified name (NULL if not found) VolumeFile* getVolumeFileWithName(const std::vector& files, const QString& fileName); public slots: /// clear the file void clearAreaColorFile(); /// clear the file void clearArealEstimationFile(); /// clear the file void clearBorderColorFile(); /// clear the file void clearCellColorFile(); /// clear the file void clearCocomacConnectivityFile(); /// clear the file void clearContourCellColorFile(); /// clear the file void clearContourCellFile(); /// clear the file void clearContourFile(const bool deleteBrainModelContoursFlag = true); /// clear the file void clearCutsFile(); /// clear the file void clearDeformationFieldFile(); /// clear the file void clearDeformationMapFile(); /// clear the file void clearFociColorFile(); /// clear the file void clearFociSearchFile(); /// clear the file void clearGeodesicDistanceFile(); /// clear the file void clearLatLonFile(); /// clear the file void clearMetricFile(); /// clear the file void clearPaintFile(); /// clear the file void clearPaletteFile(); /// clear the file void clearParamsFile(); /// clear the file void clearProbabilisticAtlasFile(); /// clear the file void clearRgbPaintFile(); /// clear the file void clearSceneFile(); /// clear the file void clearSectionFile(); /// clear the study collection file void clearStudyCollectionFile(); /// clear the study metadata file void clearStudyMetaDataFile(); /// clear the file void clearSurfaceShapeFile(); /// clear the file void clearVectorFiles(); /// clear the file void clearTopographyFile(); /// clear the file void clearTransformationMatrixFile(); /// clear the transformation data files void clearTransformationDataFiles(); /// clear the vocabulary file void clearVocabularyFile(); /// clear the file void clearWustlRegionFile(); /// clear the anatomy volume files void clearVolumeAnatomyFiles(); /// clear the functional volume files void clearVolumeFunctionalFiles(); /// clear the paint volume files void clearVolumePaintFiles(); /// clear the prob atlasvolume files void clearVolumeProbabilisticAtlasFiles(); /// clear the rgb volume files void clearVolumeRgbFiles(); /// clear the segmentation volume files void clearVolumeSegmentationFiles(); /// clear the vector volume files void clearVolumeVectorFiles(); signals: /// signal that requests a brain model be displayed and drawn void signalDisplayBrainModel(int brainModelIndex); /// signal that the brain set has changed void signalBrainSetChanged(); /// signal that graphics windows should be redrawn void signalGraphicsUpdate(BrainSet* bs); protected slots: // called when cross timer timesout void slotDisplayCrossTimerTimeout(); private: /// index of model in each window int displayedModelIndices[BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS]; /// reading a spec file flag (do not update the spec file) bool readingSpecFileFlag; /// the web caret flag bool webCaretFlag; /// splash image QImage splashImage; /// display splash image bool displaySplashImage; /// parent for progress dialogs QWidget* progressDialogParent; /// the overlays std::vector surfaceOverlays; /// the number of surface overlays int numberOfSurfaceOverlays; /// node std::vector nodeAttributes; /// the spec file that keeps track of loaded files for this brain set SpecFile loadedFilesSpecFile; /// name of the spec file QString specFileName; /// time of spec file loading QDateTime specFileTimeOfLoading; /// a transformation matrix that is applied to "fiducial" files while reading a spec file TransformationMatrix specDataFileTransformationMatrix; /// storage for all surfaces std::vector brainModels; /// the left fiducial volume interaction surface BrainModelSurface* leftFiducialVolumeInteractionSurface; /// the right fiducial volume interaction surface BrainModelSurface* rightFiducialVolumeInteractionSurface; /// the cerebellum fiducial volume interaction surface BrainModelSurface* cerebellumFiducialVolumeInteractionSurface; /// the active fiducial surface BrainModelSurface* activeFiducialSurface; /// the identification object BrainModelIdentification* brainModelIdentification; /// the auto loader manager BrainSetAutoLoaderManager* brainSetAutoLoaderManager; /// region of interest node selection object BrainModelSurfaceROINodeSelection* brainModelSurfaceRegionOfInterestNodeSelection; /// node coloring class BrainModelSurfaceNodeColoring* nodeColoring; /// voxel coloring class BrainModelVolumeVoxelColoring* voxelColoring; /// volume region of interest controller BrainModelVolumeRegionOfInterest* brainModelVolumeRegionOfInterest; /// areal estimation file ArealEstimationFile* arealEstimationFile; /// cocomac file CocomacConnectivityFile* cocomacFile; /// contour cell file ContourCellFile* contourCellFile; /// contour cell color file ContourCellColorFile* contourCellColorFile; /// cuts file (cuts are same as borders) CutsFile* cutsFile; /// name of deformation map file QString deformationMapFileName; /// deformation field file DeformationFieldFile* deformationFieldFile; /// lat/lon files LatLonFile* latLonFile; /// scene file SceneFile* sceneFile; /// section file SectionFile* sectionFile; /// metric file MetricFile* metricFile; /// area color file AreaColorFile* areaColorFile; //// probabilistic atlas file ProbabilisticAtlasFile* probabilisticAtlasSurfaceFile; /// paint file PaintFile* paintFile; /// Palette File PaletteFile* paletteFile; /// study collection file StudyCollectionFile* studyCollectionFile; /// study metadata file StudyMetaDataFile* studyMetaDataFile; /// vocabulary file VocabularyFile* vocabularyFile; /// wustl region file WustlRegionFile* wustlRegionFile; /// geodesic distance file GeodesicDistanceFile* geodesicDistanceFile; /// Params File ParamsFile* paramsFile; /// RGB Paint file RgbPaintFile* rgbPaintFile; /// Surface Shape file SurfaceShapeFile* surfaceShapeFile; /// vector file std::vector vectorFiles; /// Topography File TopographyFile* topographyFile; /// topology files std::vector topologyFiles; /// active closed topology file TopologyFile* topologyClosed; /// active open topology file TopologyFile* topologyOpen; /// active cut topology file TopologyFile* topologyCut; /// active lobar cut topology file TopologyFile* topologyLobarCut; /// active unknown topology file TopologyFile* topologyUnknown; /// functional volume files std::vector volumeFunctionalFiles; /// paint volume files std::vector volumePaintFiles; /// prob atlas volume files std::vector volumeProbAtlasFiles; /// rgb paint volume files std::vector volumeRgbFiles; /// segmentation volume files std::vector volumeSegmentationFiles; /// anatomy volume files std::vector volumeAnatomyFiles; /// vector volume files std::vector volumeVectorFiles; /// transformation matrix file TransformationMatrixFile* transformationMatrixFile; /// the species Species species; /// the subject QString subject; /// the stereotaxic space StereotaxicSpace stereotaxicSpace; /// hemisphere Structure structure; /// initialize static stuff flag static bool staticStuffInitialized; /// Areal Estimation display settings DisplaySettingsArealEstimation* displaySettingsArealEstimation; /// Border display settings DisplaySettingsBorders* displaySettingsBorders; /// Cell display settings DisplaySettingsCells* displaySettingsCells; /// CoCoMac display settings DisplaySettingsCoCoMac* displaySettingsCoCoMac; /// Contour display settings DisplaySettingsContours* displaySettingsContours; /// Cuts display settings DisplaySettingsCuts* displaySettingsCuts; /// Foci display settings DisplaySettingsFoci* displaySettingsFoci; /// node display settings DisplaySettingsSurface* displaySettingsSurface; /// section display settings DisplaySettingsSection* displaySettingsSection; /// deformation field display settings DisplaySettingsDeformationField* displaySettingsDeformationField; /// images display settings DisplaySettingsImages* displaySettingsImages; /// Metric display settings DisplaySettingsMetric* displaySettingsMetric; /// Models display settings DisplaySettingsModels* displaySettingsModels; /// Paint settings DisplaySettingsPaint* displaySettingsPaint; /// Probabilistic Atlas settings for surface DisplaySettingsProbabilisticAtlas* displaySettingsProbabilisticAtlasSurface; /// RGB Paint display settings DisplaySettingsRgbPaint* displaySettingsRgbPaint; /// Scene display settings DisplaySettingsScene* displaySettingsScene; /// study metadata display settings DisplaySettingsStudyMetaData* displaySettingsStudyMetaData; /// Surface shape display settings DisplaySettingsSurfaceShape* displaySettingsSurfaceShape; /// vector display settings DisplaySettingsVectors* displaySettingsVectors; /// Topography display settings DisplaySettingsTopography* displaySettingsTopography; /// Volume display settings DisplaySettingsVolume* displaySettingsVolume; /// Wustl Region Display Settings DisplaySettingsWustlRegion* displaySettingsWustlRegion; /// Geodesic distance file Display Settings DisplaySettingsGeodesicDistance* displaySettingsGeodesicDistance; /// Probabilistic Atlas settings for volume DisplaySettingsProbabilisticAtlas* displaySettingsProbabilisticAtlasVolume; /// Border color file BorderColorFile* borderColorFile; /// the border set BrainModelBorderSet* brainModelBorderSet; /// Cell color file CellColorFile* cellColorFile; /// Cell Projection File CellProjectionFile* cellProjectionFile; /// volume cell file CellFile* volumeCellFile; /// foci color file FociColorFile* fociColorFile; /// foci projection file FociProjectionFile* fociProjectionFile; /// foci search file FociSearchFile* fociSearchFile; /// the image files std::vector imageFiles; /// the vtk model files std::vector vtkModelFiles; /// the transformation matrix data files std::vector transformationDataFiles; /// number of nodes message when reading files QString numNodesMessage; /// name of cerebral hull file name QString cerebralHullFileName; /// nodes have been classified flag bool nodesHaveBeenClassified; /// display all nodes flag bool displayAllNodesFlag; /// primary brain set flag (allows setting of AbstractFile default names) bool primaryBrainSetFlag; /// when reading coordinate files DO NOT use topology file in coord file header bool ignoreTopologyFileInCoordinateFileHeaderFlag; /// display a cross for this node int displayCrossForNode; /// surface on which no cross should be shown BrainModelSurface* displayNoCrossForSurface; /// display cross timer QTimer* displayCrossTimer; /// mutex for add to spec file QMutex mutexAddToSpecFile; /// mutex for reading topology files QMutex mutexReadTopologyFile; /// mutex for reading coordinate files QMutex mutexReadCoordinateFile; /// mutex for reading surface files QMutex mutexReadSurfaceFile; /// mutex for adding brain model QMutex mutexAddBrainModel; /// mutex for creating surface and volume QMutex mutexCreateSurfaceAndVolume; /// mutex for reading area color file QMutex mutexAreaColorFile; /// mutex for reading areal estimation file QMutex mutexArealEstimationFile; /// mutex for reading volume border file QMutex mutexVolumeBorderFile; /// mutex for reading surface border and border projection files QMutex mutexBorderAndBorderProjectionFile; /// mutex for reading border color file QMutex mutexBorderColorFile; /// mutex for reading cell and cell projection file QMutex mutexCellAndCellProjectionFile; /// mutex for reading volume cell file QMutex mutexVolumeCellFile; /// mutex for reading cell color file QMutex mutexCellColorFile; /// mutex for reading cocomac file QMutex mutexCocomacFile; /// mutex for reading contour file QMutex mutexContourFile; /// mutex for reading contour cell file QMutex mutexContourCellFile; /// mutex for reading contour cell color file QMutex mutexContourCellColorFile; /// mutex for reading cuts file QMutex mutexCutsFile; /// mutex for adding volume file QMutex mutexAddVolumeFile; /// mutex for reading foci and foci projection file QMutex mutexFociAndFociProjectionFile; /// mutex for reading foci color file QMutex mutexFociColorFile; /// mutex for reading foci search file QMutex mutexFociSearchFile; /// mutex for reading geodesic distance file QMutex mutexGeodesicDistanceFile; /// mutex for reading lat lon file QMutex mutexLatLonFile; /// mutex for reading metric file QMutex mutexMetricFile; /// mutex for reading deformation field file QMutex mutexDeformationFieldFile; /// mutex for reading paint file QMutex mutexPaintFile; /// mutex for reading study collection file QMutex mutexStudyCollectionFile; /// mutex for reading study meta data file QMutex mutexStudyMetaDataFile; /// mutex for reading vocabulary file QMutex mutexVocabularyFile; /// mutex for reading wustl region file QMutex mutexWustlRegionFile; /// mutex for reading palette file QMutex mutexPaletteFile; /// mutex for reading params file QMutex mutexParamsFile; /// mutex for reading prob atlas file QMutex mutexProbAtlasFile; /// mutex for reading rgb paint file QMutex mutexRgbPaintFile; /// mutex for reading scene file QMutex mutexSceneFile; /// mutex for reading section file QMutex mutexSectionFile; /// mutex for reading surface shape file QMutex mutexSurfaceShapeFile; /// mutex for reading vector file QMutex mutexVectorFile; /// mutex for reading topography file QMutex mutexTopographyFile; /// mutex for reading transformation matrix file QMutex mutexTransformationMatrixFile; /// mutex for reading transformation data file QMutex mutexTransformationDataFile; /// mutex for reading image files QMutex mutexImageFile; /// mutex for reading vtk models QMutex mutexVtkModelFile; /// the preferences file (DO NOT USE THIS DIRECTLY, use getPreferencesFile()) static PreferencesFile* preferencesFile; /// update displayed model indices void updateDisplayedModelIndices(); /// save/replace scene helper void saveReplaceSceneHelper(SceneFile::Scene& scene, const std::vector& mainWindowSceneClasses, const bool onlyIfSelectedFlag, QString& errorMessageOut, QString& warningMessageOut); /// check node attribute columns for columns with same name void checkNodeAttributeFilesForDuplicateColumnNames(QString& errorMessageOut); /// check for duplicate column names in a mode attribute file void nodeAttribteDuplicateNamesHelper(const QString& fileTypeName, NodeAttributeFile* naf, QString& errorMessageOut) const; /// check for duplicate column names in a mode attribute file void niftiNodeDataFileDuplicateNamesHelper(const QString& fileTypeName, GiftiNodeDataFile* naf, QString& errorMessageOut) const; /// read an image (returns true if read successfully) bool readImage(const QString& filename, const QString& format, QImage& image); /// construct the brain set void constructBrainSet(); /// create a brain model surface and volume void createBrainModelSurfaceAndVolume(); /// delete surface that are of the specified type void deleteSurfacesOfType(const BrainModelSurface::SURFACE_TYPES st); /// Read in border files bool readBorderFiles(const SpecFile::Entry& borderFilesToRead, const BrainModelSurface::SURFACE_TYPES bt, std::vector& errorMessages, int& progressFileCounter, QProgressDialog* progressDialog); /// Read in coordinate file group bool readCoordinateFileGroup(const SpecFile::Entry& coordFile, const BrainModelSurface::SURFACE_TYPES surfaceType, std::vector& errorMessages, int& progressFileCounter, QProgressDialog* progressDialog); /// Read in surface file group bool readSurfaceFileGroup(const SpecFile::Entry& surfaceFile, const BrainModelSurface::SURFACE_TYPES surfaceType, std::vector& errorMessages, int& progressFileCounter, QProgressDialog* progressDialog); /// Update the file reading progress dialog bool updateFileReadProgressDialog(const QString& filename, int& progressFileCounter, QProgressDialog* progressDialog); /// set the selected topology files void setSelectedTopologyFiles(); /// if section file empty, look for sections in topology files void getSectionsFromTopology(); /// Update all display settings. void updateAllDisplaySettings(); friend class BrainSetMultiThreadedSpecFileReader; }; // initialize static members #ifdef __BRAIN_SET_MAIN__ bool BrainSet::staticStuffInitialized = false; PreferencesFile* BrainSet::preferencesFile = NULL; #endif // __BRAIN_SET_MAIN__ #endif // __BRAIN_SET_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainSet.cxx0000664000175000017500000142475011572067322022155 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "vtkActor.h" #include "vtkMath.h" #include "vtkPolyDataMapper.h" #include "vtkPointData.h" #include "vtkRenderer.h" #include "vtkRenderWindow.h" #include "vtkVRMLExporter.h" #define __BRAIN_SET_MAIN__ #include "BrainSet.h" #undef __BRAIN_SET_MAIN__ #include "AreaColorFile.h" #include "ArealEstimationFile.h" #include "AtlasSurfaceDirectoryFile.h" #include "BorderColorFile.h" #include "BorderFile.h" #include "BorderProjectionFile.h" #include "BorderProjectionUnprojector.h" #include "BrainModelBorderSet.h" #include "BrainModelContours.h" #include "BrainModelIdentification.h" #include "BrainModelSurfaceAndVolume.h" #include "BrainModelSurfaceCurvature.h" #include "BrainModelSurfaceNodeColoring.h" #include "BrainModelSurfaceROINodeSelection.h" #include "BrainModelSurfaceResection.h" #include "BrainModelVolume.h" #include "BrainModelVolumeToSurfaceConverter.h" #include "BrainModelVolumeVoxelColoring.h" #include "BrainModelVolumeRegionOfInterest.h" #include "BrainSetMultiThreadedSpecFileReader.h" #include "BrainSetAutoLoaderManager.h" #include "BrainVoyagerFile.h" #include "CellColorFile.h" #include "CellFile.h" #include "CellProjectionFile.h" #include "CellProjectionUnprojector.h" #include "CocomacConnectivityFile.h" #include "ColorFile.h" #include "ContourCellColorFile.h" #include "ContourCellFile.h" #include "ContourFile.h" #include "CutsFile.h" #include "DebugControl.h" #include "DeformationFieldFile.h" #include "DeformationMapFile.h" #include "DisplaySettingsArealEstimation.h" #include "DisplaySettingsBorders.h" #include "DisplaySettingsCells.h" #include "DisplaySettingsContours.h" #include "DisplaySettingsCuts.h" #include "DisplaySettingsCoCoMac.h" #include "DisplaySettingsDeformationField.h" #include "DisplaySettingsFoci.h" #include "DisplaySettingsGeodesicDistance.h" #include "DisplaySettingsImages.h" #include "DisplaySettingsMetric.h" #include "DisplaySettingsModels.h" #include "DisplaySettingsSection.h" #include "DisplaySettingsSurface.h" #include "DisplaySettingsPaint.h" #include "DisplaySettingsProbabilisticAtlas.h" #include "DisplaySettingsRgbPaint.h" #include "DisplaySettingsScene.h" #include "DisplaySettingsStudyMetaData.h" #include "DisplaySettingsSurfaceShape.h" #include "DisplaySettingsVectors.h" #include "DisplaySettingsTopography.h" #include "DisplaySettingsVolume.h" #include "DisplaySettingsWustlRegion.h" #include "FileUtilities.h" #include "FociColorFile.h" #include "FociFile.h" #include "FociProjectionFile.h" #include "FociSearchFile.h" #include "GeodesicDistanceFile.h" #include "ImageFile.h" #include "LatLonFile.h" #include "MDPlotFile.h" #include "MetricFile.h" #include "MniObjSurfaceFile.h" #include "NeurolucidaFile.h" #include "PaintFile.h" #include "PaletteFile.h" #include "ParamsFile.h" #include "ProbabilisticAtlasFile.h" #include "RgbPaintFile.h" #include "SceneFile.h" #include "SectionFile.h" #include "StatisticRandomNumber.h" #include "StringUtilities.h" #include "StudyCollectionFile.h" #include "StudyMetaDataFile.h" #include "SurfaceShapeFile.h" #include "TopographyFile.h" #include "TopologyFile.h" #include "TopologyHelper.h" #include "TransformationMatrixFile.h" #include "VectorFile.h" #include "VocabularyFile.h" #include "VtkModelFile.h" #include "WustlRegionFile.h" #include "vtkBYUReader.h" #include "vtkBYUWriter.h" #include "vtkFieldData.h" #include "vtkIVWriter.h" #include "vtkLight.h" #include "vtkOBJExporter.h" #include "vtkPolyDataNormals.h" #include "vtkPolyDataReader.h" #include "vtkPolyDataWriter.h" #include "vtkSTLReader.h" #include "vtkSTLWriter.h" #include "vtkUnsignedCharArray.h" #include "vtkXMLPolyDataReader.h" #include "vtkXMLPolyDataWriter.h" /** * The Constructor. */ BrainSet::BrainSet(const bool primaryBrainSetFlagIn) { constructBrainSet(); primaryBrainSetFlag = primaryBrainSetFlagIn; } /** * Construct a brain set from a vtk surface file. */ BrainSet::BrainSet(const QString& vtkSurfaceFileName, const BrainModelSurface::SURFACE_TYPES surfaceType, const TopologyFile::TOPOLOGY_TYPES topologyType) { constructBrainSet(); try { importVtkSurfaceFile(vtkSurfaceFileName, true, // import coords true, // import topology true, // import colors surfaceType, topologyType); } catch (FileException& e) { std::cout << "Error constructing brain set from VTK file: " << e.whatQString().toAscii().constData() << std::endl; } } /** * Construct a brain set from a topology file and a coordinate file. * For success, check to see if there is one brain model surface. */ BrainSet::BrainSet(const QString& topoFileName, const QString& coordFileName1, const QString& coordFileName2, const bool primaryBrainSetFlagIn) { constructBrainSet(); primaryBrainSetFlag = primaryBrainSetFlagIn; // // Create a spec file with the two files // SpecFile sf; std::vector coordFileNames; coordFileNames.push_back(coordFileName1); coordFileNames.push_back(coordFileName2); sf.setTopoAndCoordSelected(topoFileName, coordFileNames, getStructure()); // // Read the spec file // std::vector messages; readSpecFile(SPEC_FILE_READ_MODE_NORMAL, sf, "", messages, NULL, NULL); if (messages.empty() == false) { for (unsigned int i = 0; i < messages.size(); i++) { std::cout << "BrainSet construction error: " << messages[i].toAscii().constData() << std::endl; } } // // As a result of this call, the block of code below is probably unnecessary // setIgnoreTopologyFileInCoordinateFileHeaderFlag(true); // // Some coordinate files have a topology file name listed in the header // which causes the topology file to be loaded and assigned to the // coordinate file. So, force the topology file to the file passed to // this constructor. // if ((getNumberOfBrainModels() > 0) && (getNumberOfTopologyFiles() > 0)) { // // loop through topology files // for (int i = 0; i < getNumberOfTopologyFiles(); i++) { // // Get the topology file and its name // TopologyFile* topoFile = getTopologyFile(i); const QString topoName = topoFile->getFileName(); // // Is this the topology file that was passed to this constructor? // if (FileUtilities::basename(topoName) == FileUtilities::basename(topoFileName)) { // // Make all surfaces use the topology file // for (int j = 0; j < getNumberOfBrainModels(); j++) { BrainModelSurface* bms = getBrainModelSurface(j); if (bms != NULL) { bms->setTopologyFile(topoFile); } } break; } } } // // Structure needs to be set // for (int i = 0; i < getNumberOfBrainModels(); i++) { const BrainModelSurface* bms = getBrainModelSurface(i); if (bms != NULL) { if (bms->getStructure().getType() != Structure::STRUCTURE_TYPE_INVALID) { setStructure(bms->getStructure()); break; } } } updateDefaultFileNamePrefix(); } /** * Construct a brain set from all files in a spec file. * For success, check to see if there is one brain model surface. */ BrainSet::BrainSet(const QString& specFileNameIn, const bool readAllFilesInSpecFile, const bool primaryBrainSetFlagIn) { constructBrainSet(); primaryBrainSetFlag = primaryBrainSetFlagIn; // // Create and read spec file // SpecFile sf; try { sf.readFile(specFileNameIn); } catch (FileException&) { //return; } if (readAllFilesInSpecFile) { sf.setAllFileSelections(SpecFile::SPEC_TRUE); } else { sf.setAllFileSelections(SpecFile::SPEC_FALSE); } // // Read the spec file // std::vector messages; readSpecFile(SPEC_FILE_READ_MODE_NORMAL, sf, specFileNameIn, messages, NULL, NULL); } /** * construct the brain set. */ void BrainSet::constructBrainSet() { specFileTimeOfLoading = QDateTime::currentDateTime(); webCaretFlag = false; readingSpecFileFlag = false; ignoreTopologyFileInCoordinateFileHeaderFlag = false; numberOfSurfaceOverlays = 4; initializeStaticStuff(); primaryBrainSetFlag = false; progressDialogParent = NULL; numNodesMessage = "Contains different number of nodes than "; areaColorFile = new AreaColorFile; arealEstimationFile = new ArealEstimationFile; borderColorFile = new BorderColorFile; cellColorFile = new CellColorFile; cellProjectionFile = new CellProjectionFile; volumeCellFile = new CellFile; cocomacFile = new CocomacConnectivityFile; contourCellFile = new ContourCellFile; contourCellColorFile = new ContourCellColorFile; cutsFile = new CutsFile; deformationFieldFile = new DeformationFieldFile; fociColorFile = new FociColorFile; fociProjectionFile = new FociProjectionFile; fociSearchFile = new FociSearchFile; geodesicDistanceFile = new GeodesicDistanceFile; latLonFile = new LatLonFile; metricFile = new MetricFile; probabilisticAtlasSurfaceFile = new ProbabilisticAtlasFile; paintFile = new PaintFile; paletteFile = new PaletteFile; paramsFile = new ParamsFile; rgbPaintFile = new RgbPaintFile; sceneFile = new SceneFile; sectionFile = new SectionFile; studyCollectionFile = new StudyCollectionFile; studyMetaDataFile = new StudyMetaDataFile; surfaceShapeFile = new SurfaceShapeFile; topographyFile = new TopographyFile; transformationMatrixFile = new TransformationMatrixFile; vocabularyFile = new VocabularyFile; wustlRegionFile = new WustlRegionFile; brainModelBorderSet = new BrainModelBorderSet(this); brainModelIdentification = new BrainModelIdentification(this); brainSetAutoLoaderManager = new BrainSetAutoLoaderManager(this); nodeColoring = new BrainModelSurfaceNodeColoring(this); voxelColoring = new BrainModelVolumeVoxelColoring(this); brainModelSurfaceRegionOfInterestNodeSelection = new BrainModelSurfaceROINodeSelection(this); brainModelVolumeRegionOfInterest = new BrainModelVolumeRegionOfInterest(this); displaySettingsArealEstimation = new DisplaySettingsArealEstimation(this); displaySettingsBorders = new DisplaySettingsBorders(this); displaySettingsContours = new DisplaySettingsContours(this); displaySettingsDeformationField = new DisplaySettingsDeformationField(this); displaySettingsGeodesicDistance = new DisplaySettingsGeodesicDistance(this); displaySettingsImages = new DisplaySettingsImages(this); displaySettingsMetric = new DisplaySettingsMetric(this); displaySettingsModels = new DisplaySettingsModels(this); displaySettingsSection = new DisplaySettingsSection(this); displaySettingsSurface = new DisplaySettingsSurface(this); displaySettingsPaint = new DisplaySettingsPaint(this); displaySettingsProbabilisticAtlasSurface = new DisplaySettingsProbabilisticAtlas(this, DisplaySettingsProbabilisticAtlas::PROBABILISTIC_TYPE_SURFACE); displaySettingsRgbPaint = new DisplaySettingsRgbPaint(this); displaySettingsScene = new DisplaySettingsScene(this); displaySettingsStudyMetaData = new DisplaySettingsStudyMetaData(this); displaySettingsSurfaceShape = new DisplaySettingsSurfaceShape(this); displaySettingsVectors = new DisplaySettingsVectors(this); displaySettingsCells = new DisplaySettingsCells(this); displaySettingsCoCoMac = new DisplaySettingsCoCoMac(this); displaySettingsCuts = new DisplaySettingsCuts(this); displaySettingsFoci = new DisplaySettingsFoci(this); displaySettingsTopography = new DisplaySettingsTopography(this); displaySettingsVolume = new DisplaySettingsVolume(this); displaySettingsWustlRegion = new DisplaySettingsWustlRegion(this); displaySettingsProbabilisticAtlasVolume = new DisplaySettingsProbabilisticAtlas(this, DisplaySettingsProbabilisticAtlas::PROBABILISTIC_TYPE_VOLUME); for (int i = 0; i < getNumberOfSurfaceOverlays(); i++) { surfaceOverlays.push_back(new BrainModelSurfaceOverlay(this, i)); } reset(); // // load the splash image // QString imageName(getCaretHomeDirectory()); imageName.append(QDir::separator()); imageName.append("data_files"); imageName.append(QDir::separator()); imageName.append("images"); imageName.append(QDir::separator()); imageName.append("caret5"); QString jpegImageName(imageName); jpegImageName.append(".jpg"); displaySplashImage = readImage(jpegImageName, "JPEG", splashImage); if (displaySplashImage == false) { QString pngImageName(imageName); pngImageName.append(".png"); displaySplashImage = readImage(pngImageName, "PNG", splashImage); /* if (displaySplashImage == false) { QString msg("Unable to open splash image files "); msg.append(jpegImageName); msg.append(" or "); msg.append(pngImageName); msg.append(". CARET5_HOME may not be set correctly."); std::cerr << msg << std::endl; } */ } displayCrossTimer = new QTimer(this); QObject::connect(displayCrossTimer, SIGNAL(timeout()), this, SLOT(slotDisplayCrossTimerTimeout())); } /** * called when cross timer timesout. */ void BrainSet::slotDisplayCrossTimerTimeout() { setDisplayCrossForNode(-1, NULL); clearAllDisplayLists(); emit signalGraphicsUpdate(this); } /** * set display cross for node. */ void BrainSet::setDisplayCrossForNode(const int node, BrainModelSurface* surface) { displayCrossForNode = node; displayNoCrossForSurface = surface; if (displayCrossTimer->isActive()) { displayCrossTimer->stop(); } if (node >= 0) { displayCrossTimer->setSingleShot(true); displayCrossTimer->start(2000); } clearAllDisplayLists(); } /** * get the name of the bin directory. */ QString BrainSet::getBinDirectoryName() { QString binName("ERROR_BIN_DIRECTORY_IS_UNKNOWN"); QString program = qApp->applicationDirPath(); if (program.contains("macosx32")) { binName = "bin_macosx32"; } else if (program.contains("macosx64")) { binName = "bin_macosx64"; } else if (program.contains("windows32")) { binName = "bin_windows32"; } else if (program.contains("windows64")) { binName = "bin_windows64"; } else if (program.contains("linux32")) { binName = "bin_linux32"; } else if (program.contains("linux64")) { binName = "bin_linux64"; } else if (program.contains("linux_intel64")) { binName = "bin_linux_intel64"; } //#ifdef Q_OS_WIN32 // binName = "bin_windows"; //#endif //#ifdef Q_OS_FREEBSD // binName = "bin_freebsd"; //#endif //#ifdef Q_OS_UNIX // binName = "bin_linux"; //#endif //#ifdef Q_OS_MACX // binName = "bin_macosx"; //#endif return binName; } /** * set the random seed. */ void BrainSet::setRandomSeed(unsigned int randomSeed) { StatisticRandomNumber::setRandomSeed(randomSeed); } /** * get caret's home directory. */ QString BrainSet::getCaretHomeDirectory() { static QString caretHomeDirectory; if (caretHomeDirectory.isEmpty()) { const char* caretHome = getenv("CARET5_HOME"); if (caretHome != NULL) { caretHomeDirectory = caretHome; } else { caretHomeDirectory = qApp->applicationDirPath(); if (caretHomeDirectory.isEmpty() == false) { caretHomeDirectory = FileUtilities::dirname(caretHomeDirectory); #ifdef Q_OS_MACX const bool appFlag = (caretHomeDirectory.indexOf(".app/") > 0); if (appFlag) { caretHomeDirectory = FileUtilities::dirname(caretHomeDirectory); caretHomeDirectory = FileUtilities::dirname(caretHomeDirectory); caretHomeDirectory = FileUtilities::dirname(caretHomeDirectory); } #endif } } if (DebugControl::getDebugOn()) { std::cout << "Caret Home Directory: " << caretHomeDirectory.toAscii().constData() << std::endl; } } return caretHomeDirectory; } /** * get the preferences file. */ PreferencesFile* BrainSet::getPreferencesFile() { if (preferencesFile == NULL) { QString preferencesFileName = QDir::homePath(); if (preferencesFileName.isEmpty() == false) { preferencesFileName.append("/"); } preferencesFileName.append(".caret5_preferences"); preferencesFile = new PreferencesFile; try { preferencesFile->readFile(preferencesFileName); } catch (FileException) { } preferencesFile->setFileName(preferencesFileName); } return preferencesFile; } /** * Read the user's caret5 preferences file and intialize other things. */ void BrainSet::initializeStaticStuff() { if (staticStuffInitialized) { return; } staticStuffInitialized = true; // // Might be set at command line // const bool debugOn = DebugControl::getDebugOn(); try { AbstractFile::setTextFileDigitsRightOfDecimal( getPreferencesFile()->getTextFileDigitsRightOfDecimal()); AbstractFile::setPreferredWriteType( getPreferencesFile()->getPreferredWriteDataType()); } catch (FileException& /*e*/) { //std::cerr << "Warning: reading caret preferences file: " // << e.whatQString() << std::endl; } // // Random seed generator // if (getPreferencesFile()->getRandomSeedOverride()) { // // Use seed provided by user // setRandomSeed(getPreferencesFile()->getRandomSeedOverrideValue()); } else { // // Use number of seconds since 1970 // setRandomSeed(QDateTime::currentDateTime().toTime_t()); } if (debugOn) { DebugControl::setDebugOn(true); } } /** * The destructor. */ BrainSet::~BrainSet() { reset(); delete displayCrossTimer; displayCrossTimer = NULL; displayCrossForNode = -1; displayNoCrossForSurface = NULL; delete areaColorFile; delete arealEstimationFile; delete borderColorFile; delete cellColorFile; delete cellProjectionFile; delete volumeCellFile; delete cocomacFile; delete contourCellFile; delete contourCellColorFile; delete cutsFile; delete deformationFieldFile; delete fociColorFile; delete fociProjectionFile; delete geodesicDistanceFile; delete latLonFile; delete metricFile; delete probabilisticAtlasSurfaceFile; delete paintFile; delete paletteFile; delete paramsFile; delete rgbPaintFile; delete sceneFile; delete sectionFile; delete studyCollectionFile; delete studyMetaDataFile; delete surfaceShapeFile; delete topographyFile; delete transformationMatrixFile; delete vocabularyFile; delete wustlRegionFile; delete brainModelBorderSet; delete brainSetAutoLoaderManager; delete brainModelIdentification; delete nodeColoring; delete voxelColoring; delete brainModelVolumeRegionOfInterest; delete brainModelSurfaceRegionOfInterestNodeSelection; delete displaySettingsArealEstimation; delete displaySettingsBorders; delete displaySettingsDeformationField; delete displaySettingsGeodesicDistance; delete displaySettingsImages; delete displaySettingsMetric; delete displaySettingsModels; delete displaySettingsSection; delete displaySettingsSurface; delete displaySettingsPaint; delete displaySettingsProbabilisticAtlasSurface; delete displaySettingsRgbPaint; delete displaySettingsScene; delete displaySettingsStudyMetaData; delete displaySettingsSurfaceShape; delete displaySettingsVectors; delete displaySettingsCells; delete displaySettingsCoCoMac; delete displaySettingsContours; delete displaySettingsCuts; delete displaySettingsFoci; delete displaySettingsTopography; delete displaySettingsVolume; delete displaySettingsProbabilisticAtlasVolume; delete displaySettingsWustlRegion; } /** * get the primary surface overlay. */ BrainModelSurfaceOverlay* BrainSet::getPrimarySurfaceOverlay() { return getSurfaceOverlay(getNumberOfSurfaceOverlays() - 1); } /** * get the primary surface overlay (const method). */ const BrainModelSurfaceOverlay* BrainSet::getPrimarySurfaceOverlay() const { return getSurfaceOverlay(getNumberOfSurfaceOverlays() - 1); } /** * get the secondary surface overlay. */ BrainModelSurfaceOverlay* BrainSet::getSecondarySurfaceOverlay() { return getSurfaceOverlay(getNumberOfSurfaceOverlays() - 2); } /** * get the secondary surface overlay (const method). */ const BrainModelSurfaceOverlay* BrainSet::getSecondarySurfaceOverlay() const { return getSurfaceOverlay(getNumberOfSurfaceOverlays() - 2); } /** * get the surface underlay. */ BrainModelSurfaceOverlay* BrainSet::getSurfaceUnderlay() { return getSurfaceOverlay(0); } /** * get the surface underlay (const method). */ const BrainModelSurfaceOverlay* BrainSet::getSurfaceUnderlay() const { return getSurfaceOverlay(0); } /** * get something is an overlay for any model. */ bool BrainSet::isASurfaceOverlayForAnySurface(const BrainModelSurfaceOverlay::OVERLAY_SELECTIONS os) const { for (int i = 0; i < getNumberOfSurfaceOverlays(); i++) { for (int m = 0; m < getNumberOfBrainModels(); m++) { if (getBrainModelSurface(m) != NULL) { if (getSurfaceOverlay(i)->getOverlay(m) == os) { return true; } } } } return false; } /** * get something is an overlay. */ bool BrainSet::isASurfaceOverlay(const int modelIn, const BrainModelSurfaceOverlay::OVERLAY_SELECTIONS os) const { int model = modelIn; if (model < 0) { model = 0; } for (int i = 0; i < getNumberOfSurfaceOverlays(); i++) { if (getSurfaceOverlay(i)->getOverlay(model) == os) { return true; } } return false; } /** * copy the overlay selections from specified surface to all other surfaces. */ void BrainSet::copyOverlaysFromSurface(const int surfaceModelIndex) { for (int i = 0; i < getNumberOfSurfaceOverlays(); i++) { getSurfaceOverlay(i)->copyOverlaysFromSurface(surfaceModelIndex); } } /** * update the surface overlays due to change in brain models. */ void BrainSet::updateSurfaceOverlaysDueToChangeInBrainModels() { for (int i = 0; i < getNumberOfSurfaceOverlays(); i++) { getSurfaceOverlay(i)->update(); } } /** * apply all projected files (foci, cells, borders). */ void BrainSet::applyAllProjectedFiles() { // // Unproject all borders // brainModelBorderSet->unprojectBordersForAllSurfaces(); } /** * Clear all display list. */ void BrainSet::clearAllDisplayLists() { const int num = getNumberOfBrainModels(); // // Clear all surface display lists // for (int i = 0; i < num; i++) { BrainModelSurface* bms = getBrainModelSurface(i); if (bms != NULL) { CoordinateFile* cf = bms->getCoordinateFile(); cf->clearDisplayList(); } } // // Clear surface and volume voxel cloud display list // BrainModelSurfaceAndVolume* bmsv = getBrainModelSurfaceAndVolume(); if (bmsv != NULL) { CoordinateFile* cf = bmsv->getCoordinateFile(); cf->clearDisplayList(); bmsv->clearVoxelCloudDisplayList(); } for (int i = 0; i < getNumberOfTopologyFiles(); i++) { topologyFiles[i]->clearDisplayList(); } arealEstimationFile->clearDisplayList(); areaColorFile->clearDisplayList(); borderColorFile->clearDisplayList(); cellColorFile->clearDisplayList(); cellProjectionFile->clearDisplayList(); volumeCellFile->clearDisplayList(); fociColorFile->clearDisplayList(); fociProjectionFile->clearDisplayList(); fociSearchFile->clearDisplayList(); cocomacFile->clearDisplayList(); cutsFile->clearDisplayList(); deformationFieldFile->clearDisplayList(); geodesicDistanceFile->clearDisplayList(); for (int i = 0; i < getNumberOfImageFiles(); i++) { imageFiles[i]->clearDisplayList(); } latLonFile->clearDisplayList(); metricFile->clearDisplayList(); paintFile->clearDisplayList(); paletteFile->clearDisplayList(); paramsFile->clearDisplayList(); probabilisticAtlasSurfaceFile->clearDisplayList(); rgbPaintFile->clearDisplayList(); sectionFile->clearDisplayList(); studyCollectionFile->clearDisplayList(); studyMetaDataFile->clearDisplayList(); surfaceShapeFile->clearDisplayList(); topographyFile->clearDisplayList(); for (int i = 0; i < getNumberOfVtkModelFiles(); i++) { vtkModelFiles[i]->clearDisplayList(); } for (int i = 0; i < getNumberOfTransformationDataFiles(); i++) { transformationDataFiles[i]->clearDisplayList(); } vocabularyFile->clearDisplayList(); wustlRegionFile->clearDisplayList(); } /** * Delete all of the brain models */ void BrainSet::deleteAllBrainModels() { deleteAllTopologyFiles(); clearVolumeAnatomyFiles(); clearVolumeFunctionalFiles(); clearVolumePaintFiles(); clearVolumeProbabilisticAtlasFiles(); clearVolumeRgbFiles(); clearVolumeSegmentationFiles(); clearVolumeVectorFiles(); for (unsigned int i = 0; i < brainModels.size(); i++) { if (brainModels[i] != NULL) { delete brainModels[i]; brainModels[i] = NULL; } } brainModels.clear(); updateDisplayedModelIndices(); } /** * Reset the brain surface. Typically used prior to loading new files. */ void BrainSet::reset(const bool keepSceneData) { for (int i = 0; i < BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS; i++) { displayedModelIndices[i] = 0; } SpecFile::Entry savedSceneFile = loadedFilesSpecFile.sceneFile; loadedFilesSpecFile.clear(); specFileName = ""; specDataFileTransformationMatrix.identity(); stereotaxicSpace.reset(); species.reset(); setSubject(""); deleteAllBrainModels(); resetDataFiles(keepSceneData, false); if (keepSceneData) { loadedFilesSpecFile.sceneFile = savedSceneFile; } deleteAllBorders(); brainSetAutoLoaderManager->reset(); displaySettingsArealEstimation->reset(); displaySettingsBorders->reset(); displaySettingsDeformationField->reset(); displaySettingsGeodesicDistance->reset(); displaySettingsImages->reset(); displaySettingsMetric->reset(); displaySettingsModels->reset(); displaySettingsSection->reset(); displaySettingsSurface->reset(); displaySettingsPaint->reset(); displaySettingsProbabilisticAtlasSurface->reset(); displaySettingsRgbPaint->reset(); if (keepSceneData == false) { displaySettingsScene->reset(); } displaySettingsStudyMetaData->reset(); displaySettingsSurfaceShape->reset(); displaySettingsVectors->reset(); displaySettingsCells->reset(); displaySettingsCoCoMac->reset(); displaySettingsContours->reset(); displaySettingsCuts->reset(); displaySettingsFoci->reset(); displaySettingsTopography->reset(); displaySettingsVolume->reset(); displaySettingsProbabilisticAtlasVolume->reset(); displaySettingsWustlRegion->reset(); //resetNodeAttributeFiles(); resetNodeAttributes(); structure = Structure::STRUCTURE_TYPE_INVALID; activeFiducialSurface = NULL; leftFiducialVolumeInteractionSurface = NULL; rightFiducialVolumeInteractionSurface = NULL; cerebellumFiducialVolumeInteractionSurface = NULL; cerebralHullFileName = ""; deleteAllImageFiles(); deleteAllVtkModelFiles(); nodesHaveBeenClassified = false; displayAllNodesFlag = true; } /** * Reset data files. */ void BrainSet::resetDataFiles(const bool keepSceneData, const bool keepFociAndFociColorsAndStudyMetaData) { deleteAllBorders(); clearCocomacConnectivityFile(); clearContourCellFile(); clearContourCellColorFile(); clearCutsFile(); clearAreaColorFile(); clearParamsFile(); if (keepSceneData == false) { sceneFile->clear(); } clearPaletteFile(); paletteFile->addDefaultPalettes(); paletteFile->clearModified(); clearVectorFiles(); clearBorderColorFile(); clearCellColorFile(); deleteAllCells(true, true); if (keepFociAndFociColorsAndStudyMetaData == false) { clearFociColorFile(); deleteAllFociProjections(); clearFociSearchFile(); fociSearchFile->addDefaultSearch(); } if (keepFociAndFociColorsAndStudyMetaData == false) { clearStudyCollectionFile(); clearStudyMetaDataFile(); } clearVocabularyFile(); clearTransformationMatrixFile(); clearTransformationDataFiles(); deleteAllImageFiles(); deleteAllVtkModelFiles(); resetNodeAttributeFiles(); } /** * Reset node attribute files */ void BrainSet::resetNodeAttributeFiles() { clearArealEstimationFile(); arealEstimationFile->clearModified(); deformationMapFileName = ""; clearDeformationFieldFile(); deformationFieldFile->clearModified(); clearLatLonFile(); clearSectionFile(); clearMetricFile(); metricFile->clearModified(); clearProbabilisticAtlasFile(); probabilisticAtlasSurfaceFile->clearModified(); clearPaintFile(); paintFile->clearModified(); clearRgbPaintFile(); rgbPaintFile->clearModified(); clearSurfaceShapeFile(); surfaceShapeFile->clearModified(); clearTopographyFile(); topographyFile->clearModified(); } /** * initialize data file static members */ void BrainSet::initializeDataFileStaticMembers() { } /** * Get the model for a window from a scene. */ BrainModel* BrainSet::showSceneGetBrainModel(const int sceneIndex, const int viewingWindowNumberIn, int geometryOut[4], int glWidthHeightOut[2], bool& yokeOut, QString& errorMessageOut) { SceneFile* sf = getSceneFile(); if ((sceneIndex >= 0) && (sceneIndex < sf->getNumberOfScenes())) { return showSceneGetBrainModel(sf->getScene(sceneIndex), viewingWindowNumberIn, geometryOut, glWidthHeightOut, yokeOut, errorMessageOut); } return NULL; } /** * Get the model for a window from a scene. */ BrainModel* BrainSet::showSceneGetBrainModel(const SceneFile::Scene* scene, const int viewingWindowNumber, int geometryOut[4], int glWidthHeightOut[2], bool& yokeOut, QString& errorMessageOut) { geometryOut[0] = -1; geometryOut[1] = -1; geometryOut[2] = -1; geometryOut[3] = -1; glWidthHeightOut[0] = -1; glWidthHeightOut[1] = -1; yokeOut = false; errorMessageOut = ""; //SceneFile* sf = getSceneFile(); //if ((sceneIndex < 0) || (sceneIndex >= sf->getNumberOfScenes())) { // return NULL; //} if (viewingWindowNumber < 0) { return NULL; } QString windowName("GuiMainWindow"); if (viewingWindowNumber > 0) { std::ostringstream str; str << "ViewingWindow:" << (viewingWindowNumber + 1); windowName = str.str().c_str(); } //const SceneFile::Scene* scene = sf->getScene(sceneIndex); const int numModels = getNumberOfBrainModels(); BrainModel* brainModel = NULL; const int numClasses = scene->getNumberOfSceneClasses(); for (int nc = 0; nc < numClasses; nc++) { const SceneFile::SceneClass* sc = scene->getSceneClass(nc); const QString className(sc->getName()); if (className == windowName) { BrainModelVolume* bmv = NULL; BrainModelSurface* bms = NULL; const int num = sc->getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc->getSceneInfo(i); const QString infoName = si->getName(); if (infoName == "BrainModel") { const QString modelName = si->getModelName(); const QString value = si->getValueAsString(); brainModel = NULL; if (modelName == "BrainModelContours") { brainModel = getBrainModelContours(); bmv = NULL; } else if (modelName == "BrainModelSurface") { for (int j = 0; j < numModels; j++) { BrainModelSurface* bms1 = getBrainModelSurface(j); if (bms1 != NULL) { if (value == FileUtilities::basename(bms1->getCoordinateFile()->getFileName())) { brainModel = bms1; bms = bms1; break; } } } bmv = NULL; } else if (modelName == "BrainModelSurfaceAndVolume") { brainModel = getBrainModelSurfaceAndVolume(); bmv = NULL; } else if (modelName == "BrainModelVolume") { brainModel = getBrainModelVolume(); bmv = getBrainModelVolume(); } if (brainModel == NULL) { errorMessageOut.append("Unable to find brain model: "); errorMessageOut.append(modelName); errorMessageOut.append("\n"); return NULL; } } else if (infoName == "Transformation") { if (brainModel != NULL) { brainModel->setTransformationsAsString(viewingWindowNumber, si->getValueAsString()); } } else if (infoName == "Slices") { if (bmv != NULL) { std::vector tokens; StringUtilities::token(si->getValueAsString(), " ", tokens); if (tokens.size() >= 3) { const int slices[3] = { StringUtilities::toInt(tokens[0]), StringUtilities::toInt(tokens[1]), StringUtilities::toInt(tokens[2]) }; bmv->setSelectedOrthogonalSlices(viewingWindowNumber, slices); } } } else if (infoName == "viewStereotaxicCoordinatesFlag") { if (bmv != NULL) { bmv->setViewStereotaxicCoordinatesFlag(viewingWindowNumber, si->getValueAsBool()); } } else if (infoName == "Oblique-Trans") { if (bmv != NULL) { bmv->setObliqueTransformationsAsString(viewingWindowNumber, si->getValueAsString()); } } else if (infoName == "Oblique-Slices") { if (bmv != NULL) { std::vector tokens; StringUtilities::token(si->getValueAsString(), " ", tokens); if (tokens.size() >= 3) { const int slices[3] = { StringUtilities::toInt(tokens[0]), StringUtilities::toInt(tokens[1]), StringUtilities::toInt(tokens[2]) }; bmv->setSelectedObliqueSlices(slices); } } } else if (infoName == "Oblique-Slice-Offsets") { if (bmv != NULL) { std::vector tokens; StringUtilities::token(si->getValueAsString(), " ", tokens); if (tokens.size() >= 3) { const int slices[3] = { StringUtilities::toInt(tokens[0]), StringUtilities::toInt(tokens[1]), StringUtilities::toInt(tokens[2]) }; bmv->setSelectedObliqueSliceOffsets(viewingWindowNumber, slices); } } } else if (infoName == "Axis") { if (bmv != NULL) { bmv->setSelectedAxis(viewingWindowNumber, static_cast(si->getValueAsInt())); } } else if (infoName == "Topology") { const QString topoName(si->getValueAsString()); for (int mm = 0; mm < getNumberOfTopologyFiles(); mm++) { TopologyFile* tf = getTopologyFile(mm); if (tf != NULL) { if (FileUtilities::basename(tf->getFileName()) == topoName) { if (bms != NULL) { bms->setTopologyFile(tf); break; } } } } } else if (infoName == "Geometry") { std::vector tokens; StringUtilities::token(si->getValueAsString(), " ", tokens); if (tokens.size() >= 4) { geometryOut[0] = StringUtilities::toInt(tokens[0]); geometryOut[1] = StringUtilities::toInt(tokens[1]); geometryOut[2] = StringUtilities::toInt(tokens[2]); geometryOut[3] = StringUtilities::toInt(tokens[3]); } } else if (infoName == "GLWidgetSize") { std::vector tokens; StringUtilities::token(si->getValueAsString(), " ", tokens); if (tokens.size() >= 2) { glWidthHeightOut[0] = StringUtilities::toInt(tokens[0]); glWidthHeightOut[1] = StringUtilities::toInt(tokens[1]); } } else if (infoName == "Yoke") { yokeOut = si->getValueAsBool(); } } } } return brainModel; } /** * Save the model for a window from a scene */ void BrainSet::saveSceneForBrainModelWindow(const int viewingWindowNumber, const int geometry[4], const int glWidthHeight[2], const BrainModel* bm, const bool yokeIn, SceneFile::SceneClass& sceneClass) { if (viewingWindowNumber < 0) { return; } if (bm == NULL) { return; } QString windowName("GuiMainWindow"); if (viewingWindowNumber > 0) { std::ostringstream str; str << "ViewingWindow:" << (viewingWindowNumber + 1); windowName = str.str().c_str(); } QString modelName; QString modelValue; BrainModelSurface* bms = NULL; BrainModelVolume* bmv = NULL; if (getBrainModelContours() == bm) { modelName = "BrainModelContours"; modelValue = modelName; } else if (getBrainModelSurfaceAndVolume() == bm) { modelName = "BrainModelSurfaceAndVolume"; modelValue = modelName; } else if (getBrainModelVolume() == bm) { modelName = "BrainModelVolume"; modelValue = modelName; bmv = getBrainModelVolume(); } else { for (int i = 0; i < getNumberOfBrainModels(); i++) { if (getBrainModelSurface(i) == bm) { bms = getBrainModelSurface(i); modelName = "BrainModelSurface"; modelValue = FileUtilities::basename(bms->getCoordinateFile()->getFileName()); break; } } } if (modelName.isEmpty() == false) { sceneClass.setName(windowName); sceneClass.addSceneInfo(SceneFile::SceneInfo("BrainModel", modelName, modelValue)); if (bm != NULL) { sceneClass.addSceneInfo(SceneFile::SceneInfo("Transformation", bm->getTransformationsAsString(viewingWindowNumber))); } if (bms != NULL) { const TopologyFile* tf = bms->getTopologyFile(); if (tf != NULL) { sceneClass.addSceneInfo(SceneFile::SceneInfo("Topology", FileUtilities::basename(tf->getFileName()))); } } if (bmv != NULL) { int slices[3]; bmv->getSelectedOrthogonalSlices(viewingWindowNumber, slices); std::ostringstream str; str << slices[0] << " " << slices[1] << " " << slices[2]; sceneClass.addSceneInfo(SceneFile::SceneInfo("Slices", str.str().c_str())); sceneClass.addSceneInfo(SceneFile::SceneInfo("Axis", bmv->getSelectedAxis(viewingWindowNumber))); sceneClass.addSceneInfo(SceneFile::SceneInfo("Oblique-Trans", bmv->getObliqueTransformationsAsString(viewingWindowNumber))); sceneClass.addSceneInfo(SceneFile::SceneInfo("viewStereotaxicCoordinatesFlag", bmv->getViewStereotaxicCoordinatesFlag(viewingWindowNumber))); str.str(""); int obliqueSlices[3]; bmv->getSelectedObliqueSlices(obliqueSlices); str << obliqueSlices[0] << " " << obliqueSlices[1] << " " << obliqueSlices[2]; sceneClass.addSceneInfo(SceneFile::SceneInfo("Oblique-Slices", str.str().c_str())); str.str(""); int obliqueSliceOffsets[3]; bmv->getSelectedObliqueSliceOffsets(viewingWindowNumber, obliqueSliceOffsets); str << obliqueSliceOffsets[0] << " " << obliqueSliceOffsets[1] << " " << obliqueSliceOffsets[2]; sceneClass.addSceneInfo(SceneFile::SceneInfo("Oblique-Slice-Offsets", str.str().c_str())); } std::ostringstream str; str << geometry[0] << " " << geometry[1] << " " << geometry[2] << " " << geometry[3]; sceneClass.addSceneInfo(SceneFile::SceneInfo("Geometry", str.str().c_str())); str.str(""); str << glWidthHeight[0] << " " << glWidthHeight[1]; sceneClass.addSceneInfo(SceneFile::SceneInfo("GLWidgetSize", str.str().c_str())); sceneClass.addSceneInfo(SceneFile::SceneInfo("Yoke", yokeIn)); } } /** * apply a scene (set display settings). */ void BrainSet::showScene(const int sceneIndex, QString& errorMessage, QString& warningMessage) { SceneFile* sf = getSceneFile(); if ((sceneIndex >= 0) && (sceneIndex < sf->getNumberOfScenes())) { showScene(sf->getScene(sceneIndex), false, errorMessage, warningMessage); } } /** * load identification filters from a scene. */ void BrainSet::showSceneIdentificationFilters(const SceneFile::Scene* ss, QString& errorMessage) { errorMessage = ""; if (ss != NULL) { brainModelIdentification->showScene(*ss, errorMessage); } } /** * apply a scene (set display settings). */ void BrainSet::showScene(const SceneFile::Scene* ss, const bool checkSpecFlag, QString& errorMessage, QString& warningMessage) { errorMessage = ""; //const SceneFile::Scene* ss = sceneFile->getScene(sceneIndex); if (ss != NULL) { // // Find out which files are needed for this scene // SpecFile sf; sf.showScene(*ss, errorMessage); // // Should the spec file be checked // if (checkSpecFlag) { SpecFile userSpec; try { userSpec.readFile(getSpecFileName()); QString msg; if (sf.isSubsetOfOtherSpecFile(userSpec, msg) == false) { errorMessage.append("Spec File Errors for Spec File "); errorMessage.append(FileUtilities::basename(getSpecFileName())); errorMessage.append(": \n"); errorMessage.append(msg); } } catch (FileException&) { } } /* // // clear colors // clearAreaColorFile(); clearBorderColorFile(); clearCellColorFile(); clearContourCellColorFile(); clearFociColorFile(); // // Clear all borders, cells, cuts, and foci // deleteAllBorders(); deleteAllCells(true, true); deleteAllFociProjections(); clearCutsFile(); clearContourCellFile(); // // Clear cocomac // clearCocomacConnectivityFile(); // // Clear probabilistic atlas files // clearProbabilisticAtlasFile(); probabilisticAtlasSurfaceFile->clearModified(); */ // // Clear data files // resetDataFiles(true, displaySettingsScene->getPreserveFociAndFociColorsAndStudyMetaDataFlag()); // // Get rid of volume prob atlas files // this->clearVolumeAnatomyFiles(); this->clearVolumeFunctionalFiles(); this->clearVolumePaintFiles(); this->clearVolumeProbabilisticAtlasFiles(); this->clearVolumeRgbFiles(); this->clearVolumeSegmentationFiles(); this->clearVolumeVectorFiles(); // // Clear node identify symbols // clearNodeHighlightSymbols(); // // Do not load any files that are already loaded // sf.deselectFilesSelectedInOtherSpecFile(loadedFilesSpecFile); // // Read any files that are part of scene but not already loaded // QString specMsg; readSpecFile(SPEC_FILE_READ_MODE_APPEND, sf, "scene", specMsg, NULL, NULL); errorMessage.append(specMsg); paletteFile->clearModified(); // // Auto-Loaded Files // brainSetAutoLoaderManager->showScene(*ss, errorMessage); // // Update overlays // for (int i = 0; i < getNumberOfSurfaceOverlays(); i++) { getSurfaceOverlay(i)->showScene(*ss, errorMessage); } // // Update node/voxel coloring // brainModelIdentification->showScene(*ss, errorMessage); nodeColoring->showScene(*ss, errorMessage); voxelColoring->showScene(*ss, errorMessage); // // surface and volume settings // BrainModelSurfaceAndVolume* bmsv = getBrainModelSurfaceAndVolume(); if (bmsv != NULL) { bmsv->showScene(*ss, errorMessage); } // // transformation matrices // transformationMatrixFile->showScene(*ss, errorMessage); // // display settings // displaySettingsArealEstimation->showScene(*ss, errorMessage); displaySettingsBorders->showScene(*ss, errorMessage); displaySettingsCells->showScene(*ss, errorMessage); displaySettingsCoCoMac->showScene(*ss, errorMessage); displaySettingsContours->showScene(*ss, errorMessage); displaySettingsCuts->showScene(*ss, errorMessage); displaySettingsFoci->showScene(*ss, errorMessage); displaySettingsGeodesicDistance->showScene(*ss, errorMessage); displaySettingsDeformationField->showScene(*ss, errorMessage); displaySettingsImages->showScene(*ss, errorMessage); displaySettingsMetric->showScene(*ss, errorMessage); displaySettingsModels->showScene(*ss, errorMessage); displaySettingsPaint->showScene(*ss, errorMessage); displaySettingsProbabilisticAtlasSurface->showScene(*ss, errorMessage); displaySettingsProbabilisticAtlasVolume->showScene(*ss, errorMessage); displaySettingsRgbPaint->showScene(*ss, errorMessage); displaySettingsScene->showScene(*ss, errorMessage); displaySettingsSection->showScene(*ss, errorMessage); displaySettingsStudyMetaData->showScene(*ss, errorMessage); displaySettingsSurface->showScene(*ss, errorMessage); displaySettingsSurfaceShape->showScene(*ss, errorMessage); displaySettingsVectors->showScene(*ss, errorMessage); displaySettingsTopography->showScene(*ss, errorMessage); displaySettingsVolume->showScene(*ss, errorMessage); displaySettingsWustlRegion->showScene(*ss, errorMessage); assignBorderColors(); assignCellColors(); assignFociColors(); displaySettingsBorders->determineDisplayedBorders(); displaySettingsCells->determineDisplayedCells(); displaySettingsFoci->determineDisplayedCells(true); clearNodeHighlightSymbols(); const int numClasses = ss->getNumberOfSceneClasses(); for (int nc = 0; nc < numClasses; nc++) { const SceneFile::SceneClass* sc = ss->getSceneClass(nc); const int num = sc->getNumberOfSceneInfo(); // // Node highlighting // if (sc->getName() == "NodeHighlighting") { clearNodeHighlightSymbols(); const int numNodes = getNumberOfNodes(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc->getSceneInfo(i); const int nodeNum = StringUtilities::toInt(si->getModelName()); if (numNodes > 0) { BrainSetNodeAttribute* bna = getNodeAttributes(nodeNum); bna->setHighlighting( static_cast(si->getValueAsInt())); } } } else if ((sc->getName() == "BrainSet") || (sc->getName() == "BrainSet")) { for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc->getSceneInfo(i); if (si->getName() == "ActiveFiducial") { const QString activeFiducialName(si->getValueAsString()); bool found = false; const int numModels = getNumberOfBrainModels(); for (int i = 0; i < numModels; i++) { BrainModelSurface* bms = getBrainModelSurface(i); if (bms != NULL) { const CoordinateFile* cf = bms->getCoordinateFile(); const QString name(FileUtilities::basename(cf->getFileName())); if (name == activeFiducialName) { setActiveFiducialSurface(bms); found = true; break; } } } if (found == false) { errorMessage.append("Unable to set active fiducial surface to: "); errorMessage.append(activeFiducialName); errorMessage.append("\n"); } } else if (si->getName() == "LeftVolumeFiducialInteraction") { const QString fiducialName(si->getValueAsString()); bool found = false; const int numModels = getNumberOfBrainModels(); for (int i = 0; i < numModels; i++) { BrainModelSurface* bms = getBrainModelSurface(i); if (bms != NULL) { const CoordinateFile* cf = bms->getCoordinateFile(); const QString name(FileUtilities::basename(cf->getFileName())); if (name == fiducialName) { setLeftFiducialVolumeInteractionSurface(bms); found = true; break; } } } if (found == false) { errorMessage.append("Unable to set left fiducial volume interaction surface to: "); errorMessage.append(fiducialName); errorMessage.append("\n"); } } else if (si->getName() == "RightVolumeFiducialInteraction") { const QString fiducialName(si->getValueAsString()); bool found = false; const int numModels = getNumberOfBrainModels(); for (int i = 0; i < numModels; i++) { BrainModelSurface* bms = getBrainModelSurface(i); if (bms != NULL) { const CoordinateFile* cf = bms->getCoordinateFile(); const QString name(FileUtilities::basename(cf->getFileName())); if (name == fiducialName) { setRightFiducialVolumeInteractionSurface(bms); found = true; break; } } } if (found == false) { errorMessage.append("Unable to set right fiducial volume interaction surface to: "); errorMessage.append(fiducialName); errorMessage.append("\n"); } } else if (si->getName() == "CerebellumVolumeFiducialInteraction") { const QString fiducialName(si->getValueAsString()); bool found = false; const int numModels = getNumberOfBrainModels(); for (int i = 0; i < numModels; i++) { BrainModelSurface* bms = getBrainModelSurface(i); if (bms != NULL) { const CoordinateFile* cf = bms->getCoordinateFile(); const QString name(FileUtilities::basename(cf->getFileName())); if (name == fiducialName) { setCerebellumFiducialVolumeInteractionSurface(bms); found = true; break; } } } if (found == false) { errorMessage.append("Unable to set cerebellum fiducial volume interaction surface to: "); errorMessage.append(fiducialName); errorMessage.append("\n"); } } } } else if (sc->getName() == "TransformationDataFile") { TransformationMatrixFile* tmf = getTransformationMatrixFile(); const int numMatrices = tmf->getNumberOfMatrices(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc->getSceneInfo(i); const QString fileName = si->getName(); const QString matrixName = si->getValueAsString(); bool fileFound = false; for (int i = 0; i < getNumberOfTransformationDataFiles(); i++) { AbstractFile* af = getTransformationDataFile(i); const QString name = FileUtilities::basename(af->getFileName()); if (fileName == name) { fileFound = true; bool matrixFound = true; TransformationMatrix* tm = NULL; if (matrixName != "NULL") { matrixFound = false; for (int i = 0; i < numMatrices; i++) { TransformationMatrix* matrix = tmf->getTransformationMatrix(i); if (matrix->getMatrixName() == matrixName) { tm = matrix; matrixFound = true; break; } } } af->setAssociatedTransformationMatrix(tm); if (matrixFound == false) { errorMessage.append("Unable to find matrix for transformation data file "); errorMessage.append(fileName); errorMessage.append(", matrix "); errorMessage.append(matrixName); } fileFound = true; break; } } if (fileFound == false) { errorMessage.append("Transformation data file in scene but not loaded "); errorMessage.append(fileName); } } } } // // Assign node/voxel colors // nodeColoring->assignColors(); voxelColoring->setVolumeAllColoringInvalid(); } checkNodeAttributeFilesForDuplicateColumnNames(warningMessage); } /** * create a scene (read display settings). */ void BrainSet::saveScene(SceneFile* sf, const std::vector& mainWindowSceneClasses, const QString& sceneName, const bool onlyIfSelectedFlag, QString& errorMessageOut, QString& warningMessageOut) { SceneFile::Scene scene(sceneName); saveReplaceSceneHelper(scene, mainWindowSceneClasses, onlyIfSelectedFlag, errorMessageOut, warningMessageOut); if (errorMessageOut.isEmpty()) { sf->addScene(scene); } else { errorMessageOut.append("Scene HAS NOT been saved."); } } /** * insert after scene (read display settings). */ void BrainSet::insertScene(SceneFile* sf, const int insertAfterIndex, const std::vector& mainWindowSceneClasses, const QString& sceneName, const bool onlyIfSelectedFlag, QString& errorMessageOut, QString& warningMessageOut) { SceneFile::Scene scene(sceneName); saveReplaceSceneHelper(scene, mainWindowSceneClasses, onlyIfSelectedFlag, errorMessageOut, warningMessageOut); if (errorMessageOut.isEmpty()) { sf->insertScene(insertAfterIndex, scene); } else { errorMessageOut.append("Scene HAS NOT been saved."); } } /** * replace a scene (read display settings). */ void BrainSet::replaceScene(SceneFile* sf, const int sceneIndex, const std::vector& mainWindowSceneClasses, const QString& sceneName, const bool onlyIfSelectedFlag, QString& errorMessageOut, QString& warningMessageOut) { SceneFile::Scene scene(sceneName); saveReplaceSceneHelper(scene, mainWindowSceneClasses, onlyIfSelectedFlag, errorMessageOut, warningMessageOut); if (errorMessageOut.isEmpty()) { sf->replaceScene(sceneIndex, scene); } else { errorMessageOut.append("Scene HAS NOT been saved."); } } /** * save/replace scene helper. */ void BrainSet::saveReplaceSceneHelper(SceneFile::Scene& scene, const std::vector& mainWindowSceneClasses, const bool onlyIfSelectedFlag, QString& errorMessageOut, QString& warningMessageOut) { errorMessageOut = ""; warningMessageOut = ""; if (mainWindowSceneClasses.empty() == false) { for (unsigned int i = 0; i < mainWindowSceneClasses.size(); i++) { scene.addSceneClass(mainWindowSceneClasses[i]); } } // // Update overlays // for (int i = 0; i < getNumberOfSurfaceOverlays(); i++) { getSurfaceOverlay(i)->saveScene(scene, onlyIfSelectedFlag); } brainModelIdentification->saveScene(scene); nodeColoring->saveScene(scene, onlyIfSelectedFlag); voxelColoring->saveScene(scene, onlyIfSelectedFlag); BrainModelSurfaceAndVolume* bmsv = getBrainModelSurfaceAndVolume(); if (bmsv != NULL) { bmsv->saveScene(scene, false); } // // Transformation matrices // transformationMatrixFile->saveScene(scene, onlyIfSelectedFlag); // // Matrices associated with transform data files // SceneFile::SceneClass tsc("TransformationDataFile"); for (int i = 0; i < getNumberOfTransformationDataFiles(); i++) { const AbstractFile* af = getTransformationDataFile(i); const QString name = FileUtilities::basename(af->getFileName()); const TransformationMatrix* tm = af->getAssociatedTransformationMatrix(); QString matrixName("NULL"); if (tm != NULL) { matrixName = tm->getMatrixName(); } tsc.addSceneInfo(SceneFile::SceneInfo(name, matrixName)); } if (tsc.getNumberOfSceneInfo() > 0) { scene.addSceneClass(tsc); } // // display settings // displaySettingsArealEstimation->saveScene(scene, onlyIfSelectedFlag, errorMessageOut); displaySettingsBorders->saveScene(scene, onlyIfSelectedFlag, errorMessageOut); displaySettingsCells->saveScene(scene, onlyIfSelectedFlag, errorMessageOut); displaySettingsCoCoMac->saveScene(scene, onlyIfSelectedFlag, errorMessageOut); displaySettingsContours->saveScene(scene, onlyIfSelectedFlag, errorMessageOut); displaySettingsCuts->saveScene(scene, onlyIfSelectedFlag, errorMessageOut); displaySettingsFoci->saveScene(scene, onlyIfSelectedFlag, errorMessageOut); displaySettingsGeodesicDistance->saveScene(scene, onlyIfSelectedFlag, errorMessageOut); displaySettingsDeformationField->saveScene(scene, onlyIfSelectedFlag, errorMessageOut); displaySettingsImages->saveScene(scene, onlyIfSelectedFlag, errorMessageOut); displaySettingsMetric->saveScene(scene, onlyIfSelectedFlag, errorMessageOut); displaySettingsModels->saveScene(scene, onlyIfSelectedFlag, errorMessageOut); displaySettingsPaint->saveScene(scene, onlyIfSelectedFlag, errorMessageOut); displaySettingsProbabilisticAtlasSurface->saveScene(scene, onlyIfSelectedFlag, errorMessageOut); displaySettingsProbabilisticAtlasVolume->saveScene(scene, onlyIfSelectedFlag, errorMessageOut); displaySettingsRgbPaint->saveScene(scene, onlyIfSelectedFlag, errorMessageOut); displaySettingsScene->saveScene(scene, onlyIfSelectedFlag, errorMessageOut); displaySettingsSection->saveScene(scene, onlyIfSelectedFlag, errorMessageOut); displaySettingsStudyMetaData->saveScene(scene, onlyIfSelectedFlag, errorMessageOut); displaySettingsSurface->saveScene(scene, onlyIfSelectedFlag, errorMessageOut); displaySettingsSurfaceShape->saveScene(scene, onlyIfSelectedFlag, errorMessageOut); displaySettingsVectors->saveScene(scene, onlyIfSelectedFlag, errorMessageOut); displaySettingsTopography->saveScene(scene, onlyIfSelectedFlag, errorMessageOut); displaySettingsVolume->saveScene(scene, onlyIfSelectedFlag, errorMessageOut); displaySettingsWustlRegion->saveScene(scene, onlyIfSelectedFlag, errorMessageOut); brainSetAutoLoaderManager->saveScene(scene, onlyIfSelectedFlag, errorMessageOut); SceneFile::SceneClass sc("NodeHighlighting"); const int numNodes = getNumberOfNodes(); for (int n = 0; n < numNodes; n++) { const BrainSetNodeAttribute* bna = getNodeAttributes(n); const BrainSetNodeAttribute::HIGHLIGHT_NODE_TYPE hnt = bna->getHighlighting(); if (hnt != BrainSetNodeAttribute::HIGHLIGHT_NODE_NONE) { sc.addSceneInfo(SceneFile::SceneInfo("nh", StringUtilities::fromNumber(n), hnt)); } } if (sc.getNumberOfSceneInfo() > 0) { scene.addSceneClass(sc); } loadedFilesSpecFile.saveScene(scene, true); SceneFile::SceneClass sca("BrainSet"); const BrainModelSurface* bms = getActiveFiducialSurface(); if (bms != NULL) { const CoordinateFile* cf = bms->getCoordinateFile(); const QString name(FileUtilities::basename(cf->getFileName())); if (name.isEmpty() == false) { sca.addSceneInfo(SceneFile::SceneInfo("ActiveFiducial", name)); } } const BrainModelSurface* bmsLeft = getLeftFiducialVolumeInteractionSurface(); if (bmsLeft != NULL) { const CoordinateFile* cf = bmsLeft->getCoordinateFile(); const QString name(FileUtilities::basename(cf->getFileName())); if (name.isEmpty() == false) { sca.addSceneInfo(SceneFile::SceneInfo("LeftVolumeFiducialInteraction", name)); } } const BrainModelSurface* bmsRight = getRightFiducialVolumeInteractionSurface(); if (bmsRight != NULL) { const CoordinateFile* cf = bmsRight->getCoordinateFile(); const QString name(FileUtilities::basename(cf->getFileName())); if (name.isEmpty() == false) { sca.addSceneInfo(SceneFile::SceneInfo("RightVolumeFiducialInteraction", name)); } } const BrainModelSurface* bmsCerebellum = getCerebellumFiducialVolumeInteractionSurface(); if (bmsCerebellum != NULL) { const CoordinateFile* cf = bmsCerebellum->getCoordinateFile(); const QString name(FileUtilities::basename(cf->getFileName())); if (name.isEmpty() == false) { sca.addSceneInfo(SceneFile::SceneInfo("CerebellumVolumeFiducialInteraction", name)); } } if (sca.getNumberOfSceneInfo() > 0) { scene.addSceneClass(sca); } checkNodeAttributeFilesForDuplicateColumnNames(warningMessageOut); } /** * check node attribute columns for columns with same name. */ void BrainSet::checkNodeAttributeFilesForDuplicateColumnNames(QString& errorMessageOut) { nodeAttribteDuplicateNamesHelper("Areal Estimation File", arealEstimationFile, errorMessageOut); nodeAttribteDuplicateNamesHelper("Deformation Field File", deformationFieldFile, errorMessageOut); nodeAttribteDuplicateNamesHelper("Geodesic Distance File", geodesicDistanceFile, errorMessageOut); nodeAttribteDuplicateNamesHelper("Lat Lon File", latLonFile, errorMessageOut); niftiNodeDataFileDuplicateNamesHelper("Metric File", metricFile, errorMessageOut); niftiNodeDataFileDuplicateNamesHelper("Paint File", paintFile, errorMessageOut); nodeAttribteDuplicateNamesHelper("Rgb Paint File", rgbPaintFile, errorMessageOut); nodeAttribteDuplicateNamesHelper("Section File", sectionFile, errorMessageOut); niftiNodeDataFileDuplicateNamesHelper("Shape File", surfaceShapeFile, errorMessageOut); nodeAttribteDuplicateNamesHelper("Topography File", topographyFile, errorMessageOut); } /** * check for duplicate column names in a mode attribute file. */ void BrainSet::nodeAttribteDuplicateNamesHelper(const QString& fileTypeName, NodeAttributeFile* naf, QString& errorMessageOut) const { std::vector duplicateNames; if (naf->checkForColumnsWithSameName(duplicateNames)) { errorMessageOut.append(fileTypeName); errorMessageOut.append(" has the following duplicate column names:\n"); for (unsigned int i = 0; i < duplicateNames.size(); i++) { errorMessageOut.append(" "); errorMessageOut.append(duplicateNames[i]); errorMessageOut.append("\n"); } errorMessageOut.append("\n"); } } /** * check for duplicate column names in a mode attribute file. */ void BrainSet::niftiNodeDataFileDuplicateNamesHelper(const QString& fileTypeName, GiftiNodeDataFile* naf, QString& errorMessageOut) const { std::vector duplicateNames; if (naf->checkForColumnsWithSameName(duplicateNames)) { errorMessageOut.append(fileTypeName); errorMessageOut.append(" has the following duplicate column names:\n"); for (unsigned int i = 0; i < duplicateNames.size(); i++) { errorMessageOut.append(" "); errorMessageOut.append(duplicateNames[i]); errorMessageOut.append("\n"); } errorMessageOut.append("\n"); } } /** * Get rid of all topology files */ void BrainSet::deleteAllTopologyFiles() { for (unsigned int j= 0; j < topologyFiles.size(); j++) { if (topologyFiles[j] != NULL) { loadedFilesSpecFile.closedTopoFile.clearSelectionStatus(topologyFiles[j]->getFileName()); loadedFilesSpecFile.openTopoFile.clearSelectionStatus(topologyFiles[j]->getFileName()); loadedFilesSpecFile.cutTopoFile.clearSelectionStatus(topologyFiles[j]->getFileName()); loadedFilesSpecFile.lobarCutTopoFile.clearSelectionStatus(topologyFiles[j]->getFileName()); loadedFilesSpecFile.unknownTopoFile.clearSelectionStatus(topologyFiles[j]->getFileName()); delete topologyFiles[j]; topologyFiles[j] = NULL; } } topologyFiles.clear(); topologyClosed = NULL; topologyOpen = NULL; topologyCut = NULL; topologyLobarCut = NULL; topologyUnknown = NULL; } /** * Set the visited flag on all nodes */ void BrainSet::setAllNodesVisited(const bool value) { const int numNodes = getNumberOfNodes(); for (int i = 0; i < numNodes; i++) { nodeAttributes[i].visited = value; } } /** * Set the structure and update in the spec file. */ void BrainSet::setStructure(const Structure::STRUCTURE_TYPE hem) { structure.setType(hem); updateDefaultFileNamePrefix(); } /** * Set the structure and update in the spec file. */ void BrainSet::setStructure(const Structure& hem) { structure = hem; updateDefaultFileNamePrefix(); } /** * set the subject. */ void BrainSet::setSubject(const QString& s) { subject = s; updateDefaultFileNamePrefix(); } /** * set the stereotaxic space (const method). */ void BrainSet::setStereotaxicSpace(const StereotaxicSpace& ss) { stereotaxicSpace = ss; } /** * set the species. */ void BrainSet::setSpecies(const Species& s) { species = s; updateDefaultFileNamePrefix(); } /** * guess subject, species, and structure if not specified. */ void BrainSet::guessSubjectSpeciesStructureFromCoordTopoFileNames() { if ((species.getType() == Species::TYPE_UNKNOWN) || subject.isEmpty() || (structure.getType() == Structure::STRUCTURE_TYPE_INVALID)) { // // Get names of topo and coord files // std::vector fileNames; for (int i = 0; i < getNumberOfTopologyFiles(); i++) { fileNames.push_back(FileUtilities::basename(getTopologyFile(i)->getFileName())); } for (int i = 0; i < getNumberOfBrainModels(); i++) { const BrainModelSurface* bms = getBrainModelSurface(i); if (bms != NULL) { fileNames.push_back(FileUtilities::basename(bms->getCoordinateFile()->getFileName())); } } // // Loop through file names // for (int i = 0; i < static_cast(fileNames.size()); i++) { QString fDir, fSpecies, fCasename, fAnatomy, fHemisphere, fDescription, fDescriptionNoTypeName, fTheDate, fNumNodes, fExtension; // // Is this a valid caret data file name // if (FileUtilities::parseCaretDataFileName(fileNames[i], fDir, fSpecies, fCasename, fAnatomy, fHemisphere, fDescription, fDescriptionNoTypeName, fTheDate, fNumNodes, fExtension)) { // // Update data // if ((species.getType() == Species::TYPE_UNKNOWN) && (fSpecies != "")) { species.setUsingName(fSpecies); } if (subject.isEmpty() && (fCasename.isEmpty() == false)) { subject = fCasename; } if ((structure.getType() == Structure::STRUCTURE_TYPE_INVALID) && (fHemisphere.isEmpty() == false)) { const Structure s(fHemisphere); if (s.getType() != Structure::STRUCTURE_TYPE_INVALID) { structure = s; } } } // // See if done // if ((species.getType() != Species::TYPE_UNKNOWN) && (subject.isEmpty() == false) && (structure.getType() == Structure::STRUCTURE_TYPE_INVALID)) { break; } } } } /** * update the default file naming prefix. */ void BrainSet::updateDefaultFileNamePrefix() { if (primaryBrainSetFlag) { QString defaultFileNamePrefix; guessSubjectSpeciesStructureFromCoordTopoFileNames(); const QString hem = structure.getTypeAsAbbreviatedString(); if ((hem != "U") && (hem.isEmpty() == false) && (species.getType() != Species::TYPE_UNKNOWN) && (subject.isEmpty() == false)) { defaultFileNamePrefix.append(species.getName()); defaultFileNamePrefix.append("."); defaultFileNamePrefix.append(subject); defaultFileNamePrefix.append("."); defaultFileNamePrefix.append(hem); } AbstractFile::setDefaultFileNamePrefix(defaultFileNamePrefix, getNumberOfNodes()); } } /** * get a brain model contours (if negative index first one found is returned). */ BrainModelContours* BrainSet::getBrainModelContours(const int modelIndex) { if (modelIndex < 0) { for (int i = 0; i < getNumberOfBrainModels(); i++) { BrainModelContours* bmc = getBrainModelContours(i); if (bmc != NULL) { return bmc; } } } else if (modelIndex < getNumberOfBrainModels()) { return dynamic_cast(brainModels[modelIndex]); } return NULL; } /** * get a brain model contours (const method) (if negative index first one found is returned). */ const BrainModelContours* BrainSet::getBrainModelContours(const int modelIndex) const { if (modelIndex < 0) { for (int i = 0; i < getNumberOfBrainModels(); i++) { const BrainModelContours* bmc = getBrainModelContours(i); if (bmc != NULL) { return bmc; } } } else if (modelIndex < getNumberOfBrainModels()) { return dynamic_cast(brainModels[modelIndex]); } return NULL; } /** * Get a brain model volume (if negative index first one found is returned). */ BrainModelVolume* BrainSet::getBrainModelVolume(const int modelIndex) { if (modelIndex < 0) { for (int i = 0; i < getNumberOfBrainModels(); i++) { BrainModelVolume* bmv = getBrainModelVolume(i); if (bmv != NULL) { return bmv; } } } else if (modelIndex < getNumberOfBrainModels()) { return dynamic_cast(brainModels[modelIndex]); } return NULL; } /** * Get a brain model volume (if negative index first one found is returned) CONST method */ const BrainModelVolume* BrainSet::getBrainModelVolume(const int modelIndex) const { if (modelIndex < 0) { for (int i = 0; i < getNumberOfBrainModels(); i++) { const BrainModelVolume* bmv = getBrainModelVolume(i); if (bmv != NULL) { return bmv; } } } else if (modelIndex < getNumberOfBrainModels()) { return dynamic_cast(brainModels[modelIndex]); } return NULL; } /** * Get a brain model surface and volume (if negative index first one found is returned). */ BrainModelSurfaceAndVolume* BrainSet::getBrainModelSurfaceAndVolume(const int modelIndex) { if (modelIndex < 0) { for (int i = 0; i < getNumberOfBrainModels(); i++) { BrainModelSurfaceAndVolume* bmsv = getBrainModelSurfaceAndVolume(i); if (bmsv != NULL) { return bmsv; } } } else if (modelIndex < getNumberOfBrainModels()) { return dynamic_cast(brainModels[modelIndex]); } return NULL; } /** * Get a brain model surface and volume (if negative index first one found is returned) CONST method */ const BrainModelSurfaceAndVolume* BrainSet::getBrainModelSurfaceAndVolume(const int modelIndex) const { if (modelIndex < 0) { for (int i = 0; i < getNumberOfBrainModels(); i++) { const BrainModelSurfaceAndVolume* bmsv = getBrainModelSurfaceAndVolume(i); if (bmsv != NULL) { return bmsv; } } } else if (modelIndex < getNumberOfBrainModels()) { return dynamic_cast(brainModels[modelIndex]); } return NULL; } /** * add nodes to all surfaces at the origin */ void BrainSet::addNodes(const int numNodesToAdd) { const float origin[3] = { 0.0, 0.0, 0.0 }; // // Add nodes to all coordinate files // const int numModels = getNumberOfBrainModels(); for (int i = 0; i < numModels; i++) { BrainModelSurface* bms = getBrainModelSurface(i); if (bms != NULL) { CoordinateFile* cf = bms->getCoordinateFile(); for (int j = 0; j < numNodesToAdd; j++) { cf->addCoordinate(origin); } } } // // Update all topology files // const int numTopo = getNumberOfTopologyFiles(); for (int i = 0; i < numTopo; i++) { TopologyFile* tf = getTopologyFile(i); const int oldNumNodes = tf->getNumberOfNodes(); const int newNumNodes = oldNumNodes + numNodesToAdd; if (newNumNodes > oldNumNodes) { tf->setNumberOfNodes(newNumNodes); } } // // Update the display flags // updateNodeDisplayFlags(); // // Update the node attribute files // std::vector nodeAttributeFiles; nodeAttributeFiles.push_back(arealEstimationFile); nodeAttributeFiles.push_back(deformationFieldFile); nodeAttributeFiles.push_back(latLonFile); nodeAttributeFiles.push_back(rgbPaintFile); nodeAttributeFiles.push_back(sectionFile); nodeAttributeFiles.push_back(topographyFile); for (int i = 0; i < static_cast(nodeAttributeFiles.size()); i++) { NodeAttributeFile* naf = nodeAttributeFiles[i]; if (naf != NULL) { if ((naf->getNumberOfNodes() > 0) && (naf->getNumberOfColumns() > 0)) { naf->addNodes(numNodesToAdd); } } } std::vector niftiNodeDataFiles; niftiNodeDataFiles.push_back(metricFile); niftiNodeDataFiles.push_back(paintFile); niftiNodeDataFiles.push_back(surfaceShapeFile); for (int i = 0; i < static_cast(niftiNodeDataFiles.size()); i++) { GiftiNodeDataFile* naf = niftiNodeDataFiles[i]; if (naf != NULL) { if ((naf->getNumberOfNodes() > 0) && (naf->getNumberOfColumns() > 0)) { naf->addNodes(numNodesToAdd); } } } // // Assign node coloring // nodeColoring->assignColors(); } /** * Create a brain model surface and volume. */ void BrainSet::createBrainModelSurfaceAndVolume() { // // Prevent more than one thread from executing this code // QMutexLocker locker(&mutexCreateSurfaceAndVolume); BrainModelSurfaceAndVolume* bmsv = getBrainModelSurfaceAndVolume(); if (bmsv != NULL) { // // If no surface attached to surf&vol, add one // const CoordinateFile* cf = bmsv->getCoordinateFile(); if (cf->getNumberOfCoordinates() <= 0) { const BrainModelSurface* fiducialSurface = getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_FIDUCIAL); if (fiducialSurface != NULL) { bmsv->setSurface(); } } return; } if (getNumberOfVolumeAnatomyFiles() > 0) { BrainModelSurfaceAndVolume* bmsv = new BrainModelSurfaceAndVolume(this); bmsv->initializeSelectedSlices(); addBrainModel(bmsv); } } /** * get a brain model surface. */ BrainModelSurface* BrainSet::getBrainModelSurface(const int modelIndex) { if (modelIndex < getNumberOfBrainModels()) { if (brainModels[modelIndex]->getModelType() == BrainModel::BRAIN_MODEL_SURFACE) { return dynamic_cast(brainModels[modelIndex]); } } return NULL; } /** * get a brain model surface (const method). */ const BrainModelSurface* BrainSet::getBrainModelSurface(const int modelIndex) const { if (modelIndex < getNumberOfBrainModels()) { if (brainModels[modelIndex]->getModelType() == BrainModel::BRAIN_MODEL_SURFACE) { return dynamic_cast(brainModels[modelIndex]); } } return NULL; } /** * get the index of the first brain model surface (returns -1 if not found). */ int BrainSet::getFirstBrainModelSurfaceIndex() const { for (int i = 0; i < getNumberOfBrainModels(); i++) { if (getBrainModelSurface(i) != NULL) { return i; } } return -1; } /** * Set the name of the spec file. Also sets the current directory * to the directory of the spec file. If name is empty, the * spec file is cleared. */ void BrainSet::setSpecFileName(const QString& name, const bool readOldSpecFileFlag) { // // MUST read with the old spec file name and then // write with the new spec file name // const QString oldSpecFileName(specFileName); SpecFile sf; bool specValidFlag = false; if (readOldSpecFileFlag) { try { sf.readFile(specFileName); specValidFlag = true; } catch (FileException&) { } } specFileName = name; if (name.isEmpty() == false) { QDir::setCurrent(FileUtilities::dirname(name)); } if (specValidFlag) { try { sf.writeFile(specFileName); } catch (FileException&) { } } } /** * Classify the nodes as interior/edges. If the topology file is NULL * the most appropriate (cut) file will be used. */ void BrainSet::classifyNodes(TopologyFile* tfIn, const bool onlyDoClassificationIfNeeded) { if (onlyDoClassificationIfNeeded) { if (nodesHaveBeenClassified) { return; } } QTime timer; timer.start(); TopologyFile* tf = tfIn; if (tf == NULL) { // // Pick most appropriate topology file // if (topologyCut != NULL) { tf = topologyCut; } else if (topologyLobarCut != NULL) { tf = topologyLobarCut; } else if (topologyOpen != NULL) { tf = topologyOpen; } else if (topologyClosed != NULL) { tf = topologyClosed; } else if (topologyUnknown != NULL) { tf = topologyUnknown; } } if (tf != NULL) { // // Default to interior nodes // const int numNodes = getNumberOfNodes(); for (int i = 0; i < numNodes; i++) { nodeAttributes[i].classification = BrainSetNodeAttribute::CLASSIFICATION_TYPE_INTERIOR; } // // Any nodes used by an edge with only one tile is an edge node // const TopologyHelper* th = tf->getTopologyHelper(true, true, false); const std::set& edges = th->getEdgeInfo(); for (std::set::const_iterator iter = edges.begin(); iter != edges.end(); iter++) { int node1, node2; iter->getNodes(node1, node2); int tile1, tile2; iter->getTiles(tile1, tile2); if (tile2 < 0) { nodeAttributes[node1].classification = BrainSetNodeAttribute::CLASSIFICATION_TYPE_EDGE; nodeAttributes[node2].classification = BrainSetNodeAttribute::CLASSIFICATION_TYPE_EDGE; } } // // Corner have only two neighbors // for (int i = 0; i < numNodes; i++) { std::vector neighbors; th->getNodeNeighbors(i, neighbors); if (static_cast(neighbors.size()) == 2) { nodeAttributes[i].classification = BrainSetNodeAttribute::CLASSIFICATION_TYPE_CORNER; } } nodesHaveBeenClassified = true; } if (DebugControl::getDebugOn()) { std::cout << "Time to classify nodes: " << (static_cast(timer.elapsed()) / 1000.0) << std::endl; } updateSurfaceOverlaysDueToChangeInBrainModels(); clearAllDisplayLists(); } /** * Disconnect the specified nodes and move them to the origin. */ void BrainSet::disconnectNodes(TopologyFile* tf, const std::vector& nodesToDisconnect) { if (tf == NULL) { return; } tf->deleteTilesWithMarkedNodes(nodesToDisconnect); // // Move disconnected nodes to origin in all surfaces that use the topology file // const int numDisconnectNodes = static_cast(nodesToDisconnect.size()); const float origin[3] = { 0.0, 0.0, 0.0 }; for (int i = 0; i < getNumberOfBrainModels(); i++) { BrainModelSurface* bms = getBrainModelSurface(i); if (bms != NULL) { if (bms->getTopologyFile() == tf) { CoordinateFile* cf = bms->getCoordinateFile(); int numNodesInCoord = bms->getNumberOfNodes(); if (numNodesInCoord == numDisconnectNodes) { for (int j = 0; j < numNodesInCoord; j++) { if (nodesToDisconnect[j]) { cf->setCoordinate(j, origin); } } } } } } } /** * Disconnect the nodes with the specified paint names in the specified paint column. */ void BrainSet::disconnectNodes(TopologyFile* tf, const std::vector& paintNames, const int paintColumn) { // // Convert the paint names to paint indices // const PaintFile* pf = getPaintFile(); std::vector paintIndices; for (int i = 0; i < static_cast(paintNames.size()); i++) { const int paintIndex = pf->getPaintIndexFromName(paintNames[i]); if (paintIndex >= 0) { paintIndices.push_back(paintIndex); } } // // Disconnect nodes with the specified paint indices // if (paintIndices.empty() == false) { disconnectNodes(tf, paintIndices, paintColumn); } } /** * Disconnect the nodes with the specified paint indices in the specified paint column. */ void BrainSet::disconnectNodes(TopologyFile* tf, const std::vector& paintIndices, const int paintColumn) { // // Make sure there is something in the paint file // const PaintFile* pf = getPaintFile(); const int numNodes = pf->getNumberOfNodes(); if (numNodes == 0) { return; } // // Check for valid paint column // if ((paintColumn >= 0) && (paintColumn < pf->getNumberOfColumns())) { // // Find the nodes with the paintIndices that should be disconnected // std::vector nodesToDisconnect(numNodes, false); for (int i = 0; i < numNodes; i++) { if (std::find(paintIndices.begin(), paintIndices.end(), pf->getPaint(i, paintColumn)) != paintIndices.end()) { nodesToDisconnect[i] = true; } } // // Disconnect the nodes // disconnectNodes(tf, nodesToDisconnect); } } /** * convert volume borders to cells. */ void BrainSet::convertVolumeBordersToFiducialCells() { // // Get the border file // const BorderFile* bf = getVolumeBorderFile(); const int numBorders = bf->getNumberOfBorders(); // // Get the border and cell color files // const ColorFile* borderColors = getBorderColorFile(); ColorFile* cellColors = getCellColorFile(); // // Get the fiducial cell files // CellFile cf; // // Convert the border link points to cells // for (int i = 0; i < numBorders; i++) { // // Get the border and info // const Border* b = bf->getBorder(i); const QString borderName(b->getName()); const int numLinks = b->getNumberOfLinks(); // // Transfer color if needed // const int borderColorIndex = b->getBorderColorIndex(); if (borderColorIndex >= 0) { const QString colorName = borderColors->getColorNameByIndex(borderColorIndex); bool exactMatch = false; const int colorIndex = cellColors->getColorIndexByName(colorName, exactMatch); if (colorIndex < 0) { unsigned char r, g, b; borderColors->getColorByIndex(borderColorIndex, r, g, b); cellColors->addColor(borderName, r, g, b); } } // // Convert link points to cells // for (int j = 0; j < numLinks; j++) { const float* xyz = b->getLinkXYZ(j); CellData cd(borderName, xyz[0], xyz[1], xyz[2], 0); if (xyz[0] >= 0) { cd.setCellStructure(Structure::STRUCTURE_TYPE_CORTEX_RIGHT); } else { cd.setCellStructure(Structure::STRUCTURE_TYPE_CORTEX_LEFT); } cf.addCell(cd); } } // // Append to existing cells // cellProjectionFile->appendFiducialCellFile(cf); // // Update cell display settings // displaySettingsCells->update(); } /** * Set the selected topology files */ void BrainSet::setSelectedTopologyFiles() { topologyClosed = NULL; topologyOpen = NULL; topologyCut = NULL; topologyLobarCut = NULL; topologyUnknown = NULL; const int numTopo = getNumberOfTopologyFiles(); for (int i = 0; i < numTopo; i++) { TopologyFile* tf = getTopologyFile(i); switch(tf->getTopologyType()) { case TopologyFile::TOPOLOGY_TYPE_CLOSED: if (topologyClosed == NULL) { topologyClosed = tf; } break; case TopologyFile::TOPOLOGY_TYPE_OPEN: if (topologyOpen == NULL) { topologyOpen = tf; } break; case TopologyFile::TOPOLOGY_TYPE_CUT: if (topologyCut == NULL) { topologyCut = tf; } break; case TopologyFile::TOPOLOGY_TYPE_LOBAR_CUT: if (topologyLobarCut == NULL) { topologyLobarCut = tf; } break; case TopologyFile::TOPOLOGY_TYPE_UNKNOWN: case TopologyFile::TOPOLOGY_TYPE_UNSPECIFIED: if (topologyUnknown == NULL) { topologyUnknown = tf; } break; } } if (topologyClosed == NULL) { if (topologyOpen != NULL) { topologyClosed = topologyOpen; } else if (topologyCut != NULL) { topologyClosed = topologyCut; } else if (topologyLobarCut != NULL) { topologyClosed = topologyLobarCut; } else if (topologyUnknown != NULL) { topologyClosed = topologyUnknown; } } if (topologyOpen == NULL) { if (topologyClosed != NULL) { topologyOpen = topologyClosed; } else if (topologyCut != NULL) { topologyOpen = topologyCut; } else if (topologyLobarCut != NULL) { topologyOpen = topologyLobarCut; } else if (topologyUnknown != NULL) { topologyOpen = topologyUnknown; } } if (topologyCut == NULL) { if (topologyClosed != NULL) { topologyCut = topologyClosed; } else if (topologyOpen != NULL) { topologyCut = topologyOpen; } else if (topologyLobarCut != NULL) { topologyCut = topologyLobarCut; } else if (topologyUnknown != NULL) { topologyCut = topologyUnknown; } } if (topologyLobarCut == NULL) { if (topologyClosed != NULL) { topologyLobarCut = topologyClosed; } else if (topologyOpen != NULL) { topologyLobarCut = topologyOpen; } else if (topologyCut != NULL) { topologyLobarCut = topologyCut; } else if (topologyUnknown != NULL) { topologyLobarCut = topologyUnknown; } } if (topologyUnknown == NULL) { if (topologyClosed != NULL) { topologyUnknown = topologyClosed; } else if (topologyOpen != NULL) { topologyUnknown = topologyOpen; } else if (topologyCut != NULL) { topologyUnknown = topologyCut; } else if (topologyLobarCut != NULL) { topologyUnknown = topologyLobarCut; } } /* if (getNumberOfClosedTopologyFiles() > 0) { topologyClosed = topologyClosedFiles[0]; topologyOpen = topologyClosed; topologyCut = topologyClosed; topologyLobarCut = topologyClosed; } if (getNumberOfOpenTopologyFiles() > 0) { topologyOpen = topologyOpenFiles[0]; topologyCut = topologyOpen; topologyLobarCut = topologyOpen; if (topologyClosed == NULL) { topologyClosed = topologyOpen; } } if (getNumberOfCutTopologyFiles() > 0) { topologyCut = topologyCutFiles[0]; topologyLobarCut = topologyCut; if (topologyClosed == NULL) { topologyClosed = topologyCut; } if (topologyOpen == NULL) { topologyOpen = topologyCut; } } if (getNumberOfLobarCutTopologyFiles() > 0) { topologyLobarCut = topologyLobarCutFiles[0]; if (topologyClosed == NULL) { topologyClosed = topologyLobarCut; } if (topologyOpen == NULL) { topologyOpen = topologyLobarCut; } if (topologyCut == NULL) { topologyCut = topologyLobarCut; } } if (getNumberOfUnknownTopologyFiles() > 0) { if (topologyLobarCut == NULL) { topologyLobarCut = topologyUnknownFiles[0]; } if (topologyClosed == NULL) { topologyClosed = topologyUnknownFiles[0]; } if (topologyOpen == NULL) { topologyOpen = topologyUnknownFiles[0]; } if (topologyCut == NULL) { topologyCut = topologyUnknownFiles[0]; } } */ } /** * Update the file reading progress dialog. Returns true if the cancel button was pressed * and reading of files should terminate. */ bool BrainSet::updateFileReadProgressDialog(const QString& filename, int& progressFileCounter, QProgressDialog* progressDialog) { if (progressDialog != NULL) { if (progressDialog->wasCanceled()) { readingSpecFileFlag = false; return true; } QString s("Reading: "); s.append(FileUtilities::basename(filename)); progressDialog->setLabelText(s); progressFileCounter++; progressDialog->setValue(progressFileCounter); qApp->processEvents(); // note: qApp is global in QApplication } return false; } /** * create a spec file from all files in the selected scenes. */ void BrainSet::createSpecFromScenes(const std::vector& sceneIndices, const QString& newSpecFileName, const QString& newSceneFileName, QString& errorMessageOut) { // // The new scene file // SceneFile newSceneFile; // // Create a spec file // SpecFile newSpecFile; // // Set metadata // newSpecFile.setStructure(structure.getTypeAsString()); newSpecFile.setSpecies(species.getName()); newSpecFile.setSubject(subject); newSpecFile.setSpace(stereotaxicSpace); // // Loop through the scene file // const int numScenes = static_cast(sceneIndices.size()); for (int i = 0; i < numScenes; i++) { // // Get the scene // const SceneFile::Scene* scene = sceneFile->getScene(sceneIndices[i]); // // Add the scene to the new scene file // newSceneFile.addScene(*scene); // // Get the scenes spec file entries and add to new spec file // SpecFile sf; sf.showScene(*scene, errorMessageOut); newSpecFile.append(sf); } // // Write the new scene file // try { newSceneFile.writeFile(newSceneFileName); } catch (FileException& e) { errorMessageOut = e.whatQString(); return; } // // Add the scene to the spec file // newSpecFile.addToSpecFile(SpecFile::getSceneFileTag(), FileUtilities::basename(newSceneFileName), "", false); // // Write the new spec file // try { newSpecFile.writeFile(newSpecFileName); } catch (FileException& e) { errorMessageOut = e.whatQString(); return; } } /** * Add a tag and file to the spec file. */ void BrainSet::addToSpecFile(const QString& specFileTag, const QString& fileName, const QString& fileName2) { // // The remainder of this routine must not be run by more than one thread // QMutexLocker locker(&mutexAddToSpecFile); // // Do not call sf.setStructure() since Unknown screws things up. // switch (structure.getType()) { case Structure::STRUCTURE_TYPE_CEREBELLUM: loadedFilesSpecFile.setStructure(Structure::getCerebellumAsString()); break; case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_LEFT: loadedFilesSpecFile.setStructure(Structure::getCerebellumOrLeftCerebralAsString()); break; case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_RIGHT: loadedFilesSpecFile.setStructure(Structure::getCerebellumOrRightCerebralAsString()); break; case Structure::STRUCTURE_TYPE_CORTEX_LEFT: loadedFilesSpecFile.setStructure(Structure::getCortextLeftAsString()); break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT: loadedFilesSpecFile.setStructure(Structure::getCortexRightAsString()); break; case Structure::STRUCTURE_TYPE_CORTEX_BOTH: loadedFilesSpecFile.setStructure(Structure::getCortexBothAsString()); break; case Structure::STRUCTURE_TYPE_CORTEX_LEFT_OR_CEREBELLUM: loadedFilesSpecFile.setStructure(Structure::getLeftCerebralOrCerebellumAsString()); break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT_OR_CEREBELLUM: loadedFilesSpecFile.setStructure(Structure::getRightCerebralOrCerebellumAsString()); break; case Structure::STRUCTURE_TYPE_CEREBRUM_CEREBELLUM: loadedFilesSpecFile.setStructure(Structure::getCerebrumAndCerebellumAsString()); break; case Structure::STRUCTURE_TYPE_SUBCORTICAL: loadedFilesSpecFile.setStructure(Structure::getSubCorticalAsString()); break; case Structure::STRUCTURE_TYPE_ALL: loadedFilesSpecFile.setStructure(Structure::getAllAsString()); break; case Structure::STRUCTURE_TYPE_INVALID: // do not override if unknown break; } loadedFilesSpecFile.setSpecies(getSpecies().getName()); loadedFilesSpecFile.setSubject(getSubject()); //sf.setSpace(getSpace()); //sf.setCategory(getCategory()); // // add to spec file that keeps track of loaded files but do not write the spec file // loadedFilesSpecFile.addToSpecFile(specFileTag, fileName, fileName2, false); // // Update the spec file on the disk // if (readingSpecFileFlag == false) { if (specFileName.isEmpty() == false) { SpecFile sf; try { sf.readFile(specFileName); } catch (FileException& /*e*/) { // since file may not yet exist, ignore read error } sf.setFileName(specFileName); if (loadedFilesSpecFile.getStructure().isValid()) { sf.setStructure(loadedFilesSpecFile.getStructure()); } if (loadedFilesSpecFile.getSpecies().isValid()) { sf.setSpecies(loadedFilesSpecFile.getSpecies().getName()); } if (loadedFilesSpecFile.getSubject().isEmpty() == false) { sf.setSubject(loadedFilesSpecFile.getSubject()); } sf.addToSpecFile(specFileTag, fileName, fileName2, true); } } } /** * Write the node color file. */ void BrainSet::writeAreaColorFile(const QString& name) throw (FileException) { loadedFilesSpecFile.areaColorFile.setAllSelections(SpecFile::SPEC_FALSE); areaColorFile->writeFile(name); addToSpecFile(SpecFile::getAreaColorFileTag(), name); } /** * Read the area color data file file */ void BrainSet::readAreaColorFile(const QString& name, const bool append, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexAreaColorFile); if (append == false) { clearAreaColorFile(); } const unsigned long modified = areaColorFile->getModified(); if (areaColorFile->getNumberOfColors() == 0) { try { areaColorFile->readFile(name); } catch (FileException& e) { clearAreaColorFile(); throw FileException(FileUtilities::basename(name), e.whatQString()); } } else { // Append to existing AreaColorFile cf; cf.readFile(name); QString msg; areaColorFile->append(cf); } areaColorFile->setModifiedCounter(modified); paintFile->getLabelTable()->assignColors(*areaColorFile); if (updateSpec) { addToSpecFile(SpecFile::getAreaColorFileTag(), name); } } /** * add a document file. */ void BrainSet::addDocumentFile(const QString& documentFileName) { addToSpecFile(SpecFile::getDocumentFileTag(), documentFileName); } /** * Write the areal estimation data file. */ void BrainSet::writeArealEstimationFile(const QString& name) throw (FileException) { loadedFilesSpecFile.arealEstimationFile.setAllSelections(SpecFile::SPEC_FALSE); arealEstimationFile->writeFile(name); addToSpecFile(SpecFile::getArealEstimationFileTag(), name); } /** * Read the areal estimation data file file */ void BrainSet::readArealEstimationFile(const QString& name, const bool append, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexArealEstimationFile); if (append == false) { clearArealEstimationFile(); } const unsigned long modified = arealEstimationFile->getModified(); if (arealEstimationFile->getNumberOfColumns() == 0) { try { arealEstimationFile->readFile(name); if (arealEstimationFile->getNumberOfNodes() != getNumberOfNodes()) { throw FileException(FileUtilities::basename(name), numNodesMessage); } } catch (FileException& e) { clearArealEstimationFile(); throw FileException(FileUtilities::basename(name), e.whatQString()); } } else { // Append to existing areal estimations ArealEstimationFile aef; aef.readFile(name); if (aef.getNumberOfNodes() != getNumberOfNodes()) { throw FileException(FileUtilities::basename(name), numNodesMessage); } try { arealEstimationFile->append(aef); } catch (FileException& e) { throw FileException(FileUtilities::basename(name), e.whatQString()); } } arealEstimationFile->setModifiedCounter(modified); displaySettingsArealEstimation->update(); if (updateSpec) { addToSpecFile(SpecFile::getArealEstimationFileTag(), name); } } /** * read the areal estimation data file file (only selected columns). */ void BrainSet::readArealEstimationFile(const QString& name, const std::vector& columnDestination, const std::vector& fileBeingReadColumnNames, const AbstractFile::FILE_COMMENT_MODE fcm, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexArealEstimationFile); const bool arealEstimationFileEmpty = arealEstimationFile->empty(); ArealEstimationFile aef; aef.readFile(name); if (aef.getNumberOfNodes() != getNumberOfNodes()) { throw FileException(FileUtilities::basename(name), numNodesMessage); } try { for (int i = 0; i < aef.getNumberOfColumns(); i++) { if (i < static_cast(fileBeingReadColumnNames.size())) { aef.setColumnName(i, fileBeingReadColumnNames[i]); } } std::vector columnDestination2 = columnDestination; arealEstimationFile->append(aef, columnDestination2, fcm); } catch (FileException& e) { throw FileException(FileUtilities::basename(name), e.whatQString()); } if (arealEstimationFileEmpty) { arealEstimationFile->clearModified(); } else { arealEstimationFile->setModified(); } if (readingSpecFileFlag == false) { displaySettingsArealEstimation->update(); } if (updateSpec) { addToSpecFile(SpecFile::getArealEstimationFileTag(), name); } } /** * read a volume border file. */ void BrainSet::readVolumeBorderFile(const QString& name, const bool append, const bool updateSpec) throw (FileException) { BorderFile* borderFile = getVolumeBorderFile(); QMutexLocker locker(&mutexVolumeBorderFile); if (append || (borderFile->getNumberOfBorders() <= 0)) { borderFile->readFile(name); } else { BorderFile bf; bf.readFile(name); borderFile->append(bf); } if (updateSpec) { addToSpecFile(SpecFile::getVolumeBorderFileTag(), name); } } /** * write a volume border file. */ void BrainSet::writeVolumeBorderFile(const QString& name, const bool removeDuplicates) throw (FileException) { loadedFilesSpecFile.volumeBorderFile.setAllSelections(SpecFile::SPEC_FALSE); BorderFile* borderFile = getVolumeBorderFile(); if (removeDuplicates) { std::vector indices; borderFile->getDuplicateBorderIndices(indices); borderFile->removeBordersWithIndices(indices); } borderFile->setHeaderTag(AbstractFile::headerTagConfigurationID, "VOLUME"); borderFile->writeFile(name); addToSpecFile(SpecFile::getVolumeBorderFileTag(), name); } /** * Write the border data file. */ void BrainSet::writeBorderFile(const QString& name, const BrainModelSurface* bms, const BrainModelSurface::SURFACE_TYPES borderFileType, const QString& commentText, const QString& pubMedID, const bool removeDuplicates) throw (FileException) { // // Find borders that are used on the specified surface // BorderFile borderFile; borderFile.setFileComment(commentText); borderFile.setFilePubMedID(pubMedID); brainModelBorderSet->copyBordersToBorderFile(bms, borderFile); if (removeDuplicates) { std::vector indices; borderFile.getDuplicateBorderIndices(indices); borderFile.removeBordersWithIndices(indices); } borderFile.setHeaderTag(AbstractFile::headerTagConfigurationID, BrainModelSurface::getSurfaceConfigurationIDFromType(borderFileType)); if (borderFile.getNumberOfBorders() <= 0) { QString msg("There are no borders for surface "); msg.append(FileUtilities::basename(bms->getFileName())); throw FileException(name, msg); } QString tag; switch(borderFileType) { case BrainModelSurface::SURFACE_TYPE_RAW: tag = SpecFile::getRawBorderFileTag(); loadedFilesSpecFile.rawBorderFile.setAllSelections(SpecFile::SPEC_FALSE); break; case BrainModelSurface::SURFACE_TYPE_FIDUCIAL: tag = SpecFile::getFiducialBorderFileTag(); loadedFilesSpecFile.fiducialBorderFile.setAllSelections(SpecFile::SPEC_FALSE); break; case BrainModelSurface::SURFACE_TYPE_INFLATED: tag = SpecFile::getInflatedBorderFileTag(); loadedFilesSpecFile.inflatedBorderFile.setAllSelections(SpecFile::SPEC_FALSE); break; case BrainModelSurface::SURFACE_TYPE_VERY_INFLATED: tag = SpecFile::getVeryInflatedBorderFileTag(); loadedFilesSpecFile.veryInflatedBorderFile.setAllSelections(SpecFile::SPEC_FALSE); break; case BrainModelSurface::SURFACE_TYPE_SPHERICAL: tag = SpecFile::getSphericalBorderFileTag(); loadedFilesSpecFile.sphericalBorderFile.setAllSelections(SpecFile::SPEC_FALSE); break; case BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL: tag = SpecFile::getEllipsoidBorderFileTag(); loadedFilesSpecFile.ellipsoidBorderFile.setAllSelections(SpecFile::SPEC_FALSE); break; case BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL: tag = SpecFile::getCompressedBorderFileTag(); loadedFilesSpecFile.compressedBorderFile.setAllSelections(SpecFile::SPEC_FALSE); break; case BrainModelSurface::SURFACE_TYPE_FLAT: tag = SpecFile::getFlatBorderFileTag(); loadedFilesSpecFile.flatBorderFile.setAllSelections(SpecFile::SPEC_FALSE); break; case BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR: tag = SpecFile::getLobarFlatBorderFileTag(); loadedFilesSpecFile.lobarFlatBorderFile.setAllSelections(SpecFile::SPEC_FALSE); break; case BrainModelSurface::SURFACE_TYPE_HULL: tag = SpecFile::getHullCoordFileTag(); loadedFilesSpecFile.hullBorderFile.setAllSelections(SpecFile::SPEC_FALSE); break; case BrainModelSurface::SURFACE_TYPE_UNKNOWN: case BrainModelSurface::SURFACE_TYPE_UNSPECIFIED: default: tag = SpecFile::getUnknownBorderFileMatchTag(); loadedFilesSpecFile.unknownBorderFile.setAllSelections(SpecFile::SPEC_FALSE); break; } borderFile.setHeaderTag(AbstractFile::headerTagConfigurationID, BrainModelSurface::getSurfaceConfigurationIDFromType(bms->getSurfaceType())); borderFile.writeFile(name); addToSpecFile(tag, name); BrainModelBorderFileInfo* bmi = brainModelBorderSet->getBorderFileInfo(borderFileType); bmi->setFileName(name); bmi->setFileComment(commentText); bmi->setPubMedID(pubMedID); brainModelBorderSet->setSurfaceBordersModified(bms, false); } /** * Read the border data file file */ void BrainSet::readBorderFile(const QString& name, const BrainModelSurface::SURFACE_TYPES stin, const bool append, const bool updateSpec) throw (FileException) { BrainModelSurface::SURFACE_TYPES st = stin; if (st == BrainModelSurface::SURFACE_TYPE_UNSPECIFIED) { BorderFile b; b.readFileMetaDataOnly(name); const QString typeTag = b.getHeaderTag(AbstractFile::headerTagConfigurationID); if (typeTag.isEmpty() == false) { st = BrainModelSurface::getSurfaceTypeFromConfigurationID(typeTag); } } QString tag; switch(st) { case BrainModelSurface::SURFACE_TYPE_RAW: tag = SpecFile::getRawBorderFileTag(); break; case BrainModelSurface::SURFACE_TYPE_FIDUCIAL: tag = SpecFile::getFiducialBorderFileTag(); break; case BrainModelSurface::SURFACE_TYPE_INFLATED: tag = SpecFile::getInflatedBorderFileTag(); break; case BrainModelSurface::SURFACE_TYPE_VERY_INFLATED: tag = SpecFile::getVeryInflatedBorderFileTag(); break; case BrainModelSurface::SURFACE_TYPE_SPHERICAL: tag = SpecFile::getSphericalBorderFileTag(); break; case BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL: tag = SpecFile::getEllipsoidBorderFileTag(); break; case BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL: tag = SpecFile::getCompressedBorderFileTag(); break; case BrainModelSurface::SURFACE_TYPE_FLAT: tag = SpecFile::getFlatBorderFileTag(); break; case BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR: tag = SpecFile::getLobarFlatBorderFileTag(); break; case BrainModelSurface::SURFACE_TYPE_HULL: tag = SpecFile::getHullBorderFileTag(); break; case BrainModelSurface::SURFACE_TYPE_UNKNOWN: case BrainModelSurface::SURFACE_TYPE_UNSPECIFIED: tag = SpecFile::getUnknownBorderFileMatchTag(); break; } BorderFile borderFile; try { borderFile.readFile(name); } catch (FileException& e) { borderFile.clear(); throw FileException(FileUtilities::basename(name), e.whatQString()); } // // Update configuration ID in the border file // const QString configID = BrainModelSurface::getSurfaceConfigurationIDFromType(st); borderFile.setHeaderTag(AbstractFile::headerTagConfigurationID, configID); borderFile.clearModified(); // // If transformation matrix should be applied // if ((st == BrainModelSurface::SURFACE_TYPE_RAW) || (st == BrainModelSurface::SURFACE_TYPE_FIDUCIAL)) { if (specDataFileTransformationMatrix.isIdentity() == false) { borderFile.applyTransformationMatrix(specDataFileTransformationMatrix); borderFile.clearModified(); } } // // Add to current borders. // QMutexLocker locker(&mutexBorderAndBorderProjectionFile); if (append == false) { deleteAllBorders(); } brainModelBorderSet->copyBordersFromBorderFile(&borderFile, st); if (readingSpecFileFlag == false) { displaySettingsBorders->update(); } if (updateSpec) { addToSpecFile(tag, name); } } /** * Write the border color data file. */ void BrainSet::writeBorderColorFile(const QString& name) throw (FileException) { loadedFilesSpecFile.borderColorFile.setAllSelections(SpecFile::SPEC_FALSE); borderColorFile->writeFile(name); addToSpecFile(SpecFile::getBorderColorFileTag(), name); } /** * Read the border color data file file */ void BrainSet::readBorderColorFile(const QString& name, const bool append, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexBorderColorFile); if (append == false) { clearBorderColorFile(); } const unsigned long modified = borderColorFile->getModified(); if (borderColorFile->getNumberOfColors() == 0) { try { borderColorFile->readFile(name); } catch (FileException& e) { clearBorderColorFile(); throw FileException(FileUtilities::basename(name), e.whatQString()); } } else { // Append to existing BorderColorFile cf; cf.readFile(name); borderColorFile->append(cf); } borderColorFile->setModifiedCounter(modified); if (updateSpec) { addToSpecFile(SpecFile::getBorderColorFileTag(), name); } } /** * Write the border projection data file. */ void BrainSet::writeBorderProjectionFile(const QString& name, const QString& commentText, const QString& pubMedID, const bool removeDuplicates) throw (FileException) { loadedFilesSpecFile.borderProjectionFile.setAllSelections(SpecFile::SPEC_FALSE); BorderProjectionFile borderProjFile; brainModelBorderSet->copyBordersToBorderProjectionFile(borderProjFile); if (removeDuplicates) { std::vector indices; borderProjFile.getDuplicateBorderProjectionIndices(indices); borderProjFile.removeBordersWithIndices(indices); } borderProjFile.setFileComment(commentText); borderProjFile.setFilePubMedID(pubMedID); borderProjFile.writeFile(name); addToSpecFile(SpecFile::getBorderProjectionFileTag(), name); BrainModelBorderFileInfo* bmi = brainModelBorderSet->getBorderProjectionFileInfo(); bmi->setFileName(name); bmi->setFileComment(commentText); bmi->setPubMedID(pubMedID); brainModelBorderSet->setProjectionsModified(false); } /** * Read the border projection data file file */ void BrainSet::readBorderProjectionFile(const QString& name, const bool append, const bool updateSpec) throw (FileException) { BorderProjectionFile borderProjFile; try { borderProjFile.readFile(name); } catch (FileException& e) { throw FileException(FileUtilities::basename(name), e.whatQString()); } QMutexLocker locker(&mutexBorderAndBorderProjectionFile); if (append == false) { deleteAllBorders(); } bool modified = brainModelBorderSet->getProjectionsModified(); const bool hadBorders = (brainModelBorderSet->getNumberOfBorders() > 0); brainModelBorderSet->copyBordersFromBorderProjectionFile(&borderProjFile); brainModelBorderSet->setProjectionsModified(modified); if (readingSpecFileFlag == false) { displaySettingsBorders->update(); } if (hadBorders == false) { brainModelBorderSet->setAllBordersModifiedStatus(false); brainModelBorderSet->setProjectionsModified(false); } if (updateSpec) { addToSpecFile(SpecFile::getBorderProjectionFileTag(), name); } } /** * Write the cell data file. */ void BrainSet::writeCellFile(const QString& name, const BrainModelSurface* bms, const AbstractFile::FILE_FORMAT fileFormat, const QString& commentText) throw (FileException) { // // Check for fiducial surface // const bool fiducialSurfaceFlag = ((bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_RAW) || (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FIDUCIAL)); // // Get cells for surface // CellFile cf; cellProjectionFile->getCellFile(bms->getCoordinateFile(), bms->getTopologyFile(), fiducialSurfaceFlag, cf); if (cf.getNumberOfCells() <= 0) { throw FileException("There are no cells that project to the selected surface."); } cf.setFileComment(commentText); cf.setFileWriteType(fileFormat); cf.writeFile(name); addToSpecFile(SpecFile::getCellFileTag(), name); } /** * Read the cell data file file */ void BrainSet::readCellFile(const QString& name, const bool append, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexCellAndCellProjectionFile); if (append == false) { //deleteCellsOfType(st); deleteAllCells(true, true); } CellFile cellFile; try { cellFile.readFile(name); // // If transformation should be applied // if (specDataFileTransformationMatrix.isIdentity() == false) { cellFile.applyTransformationMatrix(std::numeric_limits::min(), std::numeric_limits::max(), specDataFileTransformationMatrix, false); } } catch (FileException& e) { throw FileException(FileUtilities::basename(name), e.whatQString()); } cellProjectionFile->appendFiducialCellFile(cellFile); if (updateSpec) { addToSpecFile(SpecFile::getCellFileTag(), name); } } /** * Write the cell data file. */ void BrainSet::writeVolumeCellFile(const QString& name) throw (FileException) { loadedFilesSpecFile.volumeCellFile.setAllSelections(SpecFile::SPEC_FALSE); CellFile* cf = getVolumeCellFile(); if (cf != NULL) { cf->writeFile(name); addToSpecFile(SpecFile::getVolumeCellFileTag(), name); } else { throw FileException("", "There is no volume cell file to write."); } } /** * Read the cell data file file */ void BrainSet::readVolumeCellFile(const QString& name, const bool append, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexVolumeCellFile); if (append == false) { deleteAllCells(false, true); } const unsigned long modified = volumeCellFile->getModified(); if (volumeCellFile->getNumberOfCells() == 0) { try { volumeCellFile->readFile(name); // // If transformation should be applied // if (specDataFileTransformationMatrix.isIdentity() == false) { volumeCellFile->applyTransformationMatrix(std::numeric_limits::min(), std::numeric_limits::max(), specDataFileTransformationMatrix, false); } } catch (FileException& e) { deleteAllCells(false, true); throw FileException(FileUtilities::basename(name), e.whatQString()); } } else { // Append to existing CellFile cf; cf.readFile(name); // // If transformation should be applied // if (specDataFileTransformationMatrix.isIdentity() == false) { cf.applyTransformationMatrix(std::numeric_limits::min(), std::numeric_limits::max(), specDataFileTransformationMatrix, false); } volumeCellFile->append(cf); } volumeCellFile->setModifiedCounter(modified); displaySettingsCells->update(); if (updateSpec) { addToSpecFile(SpecFile::getVolumeCellFileTag(), name); } } /** * Write the cell color data file. */ void BrainSet::writeCellColorFile(const QString& name) throw (FileException) { loadedFilesSpecFile.cellColorFile.setAllSelections(SpecFile::SPEC_FALSE); cellColorFile->writeFile(name); addToSpecFile(SpecFile::getCellColorFileTag(), name); } /** * Read the cell color data file file */ void BrainSet::readCellColorFile(const QString& name, const bool append, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexCellColorFile); if (append == false) { clearCellColorFile(); } const unsigned long modified = cellColorFile->getModified(); if (cellColorFile->getNumberOfColors() == 0) { try { cellColorFile->readFile(name); } catch (FileException& e) { clearCellColorFile(); throw FileException(FileUtilities::basename(name), e.whatQString()); } } else { // Append to existing CellColorFile cf; cf.readFile(name); //QString msg; cellColorFile->append(cf); } cellColorFile->setModifiedCounter(modified); if (updateSpec) { addToSpecFile(SpecFile::getCellColorFileTag(), name); } } /** * Write the cell projection data file. */ void BrainSet::writeCellProjectionFile(const QString& name) throw (FileException) { loadedFilesSpecFile.cellProjectionFile.setAllSelections(SpecFile::SPEC_FALSE); cellProjectionFile->writeFile(name); addToSpecFile(SpecFile::getCellProjectionFileTag(), name); } /** * Read the cell projection data file file */ void BrainSet::readCellProjectionFile(const QString& name, const bool append, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexCellAndCellProjectionFile); if (append == false) { deleteAllCellProjections(); } const unsigned long modified = cellProjectionFile->getModified(); if (cellProjectionFile->getNumberOfCellProjections() == 0) { try { cellProjectionFile->readFile(name); } catch (FileException& e) { deleteAllCellProjections(); throw FileException(FileUtilities::basename(name), e.whatQString()); } } else { // Append to existing CellProjectionFile cf; cf.readFile(name); QString msg; cellProjectionFile->append(cf); } cellProjectionFile->setModifiedCounter(modified); displaySettingsCells->update(); if (updateSpec) { addToSpecFile(SpecFile::getCellProjectionFileTag(), name); } } /** * Write the CocomacConnectivity data file. */ void BrainSet::writeCocomacConnectivityFile(const QString& name) throw (FileException) { loadedFilesSpecFile.cocomacConnectivityFile.setAllSelections(SpecFile::SPEC_FALSE); cocomacFile->writeFile(name); addToSpecFile(SpecFile::getCocomacConnectivityFileTag(), name); } /** * Read a Cocomac Connectivity file. */ void BrainSet::readCocomacConnectivityFile(const QString& name, const bool append, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexCocomacFile); if (append == false) { clearCocomacConnectivityFile(); } const unsigned long modified = cocomacFile->getModified(); if (cocomacFile->getNumberOfCocomacProjections() == 0) { try { cocomacFile->readFile(name); } catch (FileException& e) { clearCocomacConnectivityFile(); throw FileException(FileUtilities::basename(name), e.whatQString()); } } else { // Append to existing CocomacConnectivityFile cf; cf.readFile(name); QString msg; cocomacFile->append(cf, msg); if (msg.isEmpty() == false) { throw FileException(FileUtilities::basename(name), msg); } } cocomacFile->setModifiedCounter(modified); displaySettingsCoCoMac->update(); if (updateSpec) { addToSpecFile(SpecFile::getCocomacConnectivityFileTag(), name); } } /** * Write the contour data file. */ void BrainSet::writeContourFile(const QString& name, ContourFile* cf) throw (FileException) { loadedFilesSpecFile.contourFile.setAllSelections(SpecFile::SPEC_FALSE); cf->writeFile(name); addToSpecFile(SpecFile::getContourFileTag(), name); } /** * Read a Contour file. */ void BrainSet::readContourFile(const QString& name, const bool append, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexContourFile); if (append == false) { clearContourFile(false); } BrainModelContours* bmc = getBrainModelContours(-1); bool createdBrainModelContours = false; if (bmc == NULL) { bmc = new BrainModelContours(this); createdBrainModelContours = true; } try { bmc->readContourFile(name, append); if (createdBrainModelContours) { addBrainModel(bmc); } if (updateSpec) { addToSpecFile(SpecFile::getContourFileTag(), name); } } catch (FileException& e) { if (createdBrainModelContours) { delete bmc; } throw e; } displaySettingsContours->update(); } /** * Write the contour cell data file. */ void BrainSet::writeContourCellFile(const QString& name) throw (FileException) { loadedFilesSpecFile.contourCellFile.setAllSelections(SpecFile::SPEC_FALSE); contourCellFile->writeFile(name); addToSpecFile(SpecFile::getContourCellFileTag(), name); } /** * Read the contour cell data file */ void BrainSet::readContourCellFile(const QString& name, const bool append, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexContourCellFile); if (append == false) { clearContourCellFile(); } const unsigned long modified = contourCellFile->getModified(); if (contourCellFile->getNumberOfCells() == 0) { try { contourCellFile->readFile(name); } catch (FileException& e) { clearContourCellFile(); throw FileException(FileUtilities::basename(name), e.whatQString()); } } else { // Append to existing ContourCellFile cf; cf.readFile(name); contourCellFile->append(cf); } contourCellFile->setModifiedCounter(modified); displaySettingsCells->update(); if (updateSpec) { addToSpecFile(SpecFile::getContourCellFileTag(), name); } } /** * Write the contour cell color data file. */ void BrainSet::writeContourCellColorFile(const QString& name) throw (FileException) { loadedFilesSpecFile.contourCellColorFile.setAllSelections(SpecFile::SPEC_FALSE); contourCellColorFile->writeFile(name); addToSpecFile(SpecFile::getContourCellColorFileTag(), name); } /** * Read the contour cell color data file */ void BrainSet::readContourCellColorFile(const QString& name, const bool append, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexContourCellColorFile); if (append == false) { clearContourCellColorFile(); } const unsigned long modified = contourCellColorFile->getModified(); if (contourCellColorFile->getNumberOfColors() == 0) { try { contourCellColorFile->readFile(name); } catch (FileException& e) { clearContourCellColorFile(); throw FileException(FileUtilities::basename(name), e.whatQString()); } } else { // Append to existing ContourCellColorFile cf; cf.readFile(name); contourCellColorFile->append(cf); } contourCellColorFile->setModifiedCounter(modified); displaySettingsContours->update(); if (updateSpec) { addToSpecFile(SpecFile::getContourCellColorFileTag(), name); } } /** * Set the deformation map file name. */ void BrainSet::setDeformationMapFileName(const QString& name, const bool updateSpec) { deformationMapFileName = name; if (updateSpec) { addToSpecFile(SpecFile::getDeformationMapFileTag(), name); } } /** * Write the cuts data file. */ void BrainSet::writeCutsFile(const QString& name) throw (FileException) { loadedFilesSpecFile.cutsFile.setAllSelections(SpecFile::SPEC_FALSE); cutsFile->writeFile(name); addToSpecFile(SpecFile::getCutsFileTag(), name); } /** * Read a cuts file. */ void BrainSet::readCutsFile(const QString& name, const bool append, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexCutsFile); if (append == false) { clearCutsFile(); } const unsigned long modified = cutsFile->getModified(); if (cutsFile->getNumberOfBorders() == 0) { try { cutsFile->readFile(name); } catch (FileException& e) { clearCutsFile(); throw FileException(FileUtilities::basename(name), e.whatQString()); } } else { // Append to existing CutsFile cf; cf.readFile(name); QString msg; cutsFile->append(cf); if (msg.isEmpty() == false) { throw FileException(FileUtilities::basename(name), msg); } } cutsFile->setModifiedCounter(modified); displaySettingsCuts->update(); if (updateSpec) { addToSpecFile(SpecFile::getCutsFileTag(), name); } } /** * Remove any surfaces of the specified type from the brain models. */ void BrainSet::deleteSurfacesOfType(const BrainModelSurface::SURFACE_TYPES st) { std::vector modelsToDelete; for (int i = 0; i < getNumberOfBrainModels(); i++) { BrainModel* bm = getBrainModel(i); if (bm->getModelType() == BrainModel::BRAIN_MODEL_SURFACE) { BrainModelSurface* bms = dynamic_cast(bm); if (bms->getSurfaceType() != st) { modelsToDelete.push_back(bms); } } } for (unsigned int i = 0; i < modelsToDelete.size(); i++) { deleteBrainModelSurface(modelsToDelete[i]); } nodeColoring->assignColors(); clearAllDisplayLists(); } /** * write the surface data file. */ void BrainSet::writeSurfaceFile(const QString& name, const BrainModelSurface::SURFACE_TYPES st, BrainModelSurface* bms, const bool updateSpecFile, const AbstractFile::FILE_FORMAT fileFormat) throw (FileException) { QString oldFileName = FileUtilities::filenameWithoutExtension( bms->getCoordinateFile()->getFileName()); oldFileName.append(SpecFile::getGiftiSurfaceFileExtension()); const BrainModelSurface::SURFACE_TYPES st1 = bms->getSurfaceType(); switch (st1) { case BrainModelSurface::SURFACE_TYPE_RAW: loadedFilesSpecFile.rawSurfaceFile.clearSelectionStatus(oldFileName); break; case BrainModelSurface::SURFACE_TYPE_FIDUCIAL: loadedFilesSpecFile.fiducialSurfaceFile.clearSelectionStatus(oldFileName); break; case BrainModelSurface::SURFACE_TYPE_INFLATED: loadedFilesSpecFile.inflatedSurfaceFile.clearSelectionStatus(oldFileName); break; case BrainModelSurface::SURFACE_TYPE_VERY_INFLATED: loadedFilesSpecFile.veryInflatedSurfaceFile.clearSelectionStatus(oldFileName); break; case BrainModelSurface::SURFACE_TYPE_SPHERICAL: loadedFilesSpecFile.sphericalSurfaceFile.clearSelectionStatus(oldFileName); break; case BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL: loadedFilesSpecFile.ellipsoidSurfaceFile.clearSelectionStatus(oldFileName); break; case BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL: loadedFilesSpecFile.compressedSurfaceFile.clearSelectionStatus(oldFileName); break; case BrainModelSurface::SURFACE_TYPE_FLAT: loadedFilesSpecFile.flatSurfaceFile.clearSelectionStatus(oldFileName); break; case BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR: loadedFilesSpecFile.lobarFlatSurfaceFile.clearSelectionStatus(oldFileName); break; case BrainModelSurface::SURFACE_TYPE_HULL: loadedFilesSpecFile.hullSurfaceFile.clearSelectionStatus(oldFileName); break; case BrainModelSurface::SURFACE_TYPE_UNKNOWN: case BrainModelSurface::SURFACE_TYPE_UNSPECIFIED: loadedFilesSpecFile.unknownSurfaceFile.clearSelectionStatus(oldFileName); break; } // // Update surface to new type // bms->setSurfaceType(st); // // Write the surface file // bms->writeSurfaceFile(name, fileFormat); if (updateSpecFile) { addToSpecFile(BrainModelSurface::getSurfaceSpecFileTagFromSurfaceType(st), name); } } /** * Write the coordinate data file. */ void BrainSet::writeCoordinateFile(const QString& name, const BrainModelSurface::SURFACE_TYPES st, CoordinateFile* cf, const bool updateSpecFile) throw (FileException) { const QString typeTag = cf->getHeaderTag(AbstractFile::headerTagConfigurationID); if (typeTag.isEmpty() == false) { const BrainModelSurface::SURFACE_TYPES st1 = BrainModelSurface::getSurfaceTypeFromConfigurationID(typeTag); switch (st1) { case BrainModelSurface::SURFACE_TYPE_RAW: loadedFilesSpecFile.rawCoordFile.clearSelectionStatus(cf->getFileName()); break; case BrainModelSurface::SURFACE_TYPE_FIDUCIAL: loadedFilesSpecFile.fiducialCoordFile.clearSelectionStatus(cf->getFileName()); break; case BrainModelSurface::SURFACE_TYPE_INFLATED: loadedFilesSpecFile.inflatedCoordFile.clearSelectionStatus(cf->getFileName()); break; case BrainModelSurface::SURFACE_TYPE_VERY_INFLATED: loadedFilesSpecFile.veryInflatedCoordFile.clearSelectionStatus(cf->getFileName()); break; case BrainModelSurface::SURFACE_TYPE_SPHERICAL: loadedFilesSpecFile.sphericalCoordFile.clearSelectionStatus(cf->getFileName()); break; case BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL: loadedFilesSpecFile.ellipsoidCoordFile.clearSelectionStatus(cf->getFileName()); break; case BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL: loadedFilesSpecFile.compressedCoordFile.clearSelectionStatus(cf->getFileName()); break; case BrainModelSurface::SURFACE_TYPE_FLAT: loadedFilesSpecFile.flatCoordFile.clearSelectionStatus(cf->getFileName()); break; case BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR: loadedFilesSpecFile.lobarFlatCoordFile.clearSelectionStatus(cf->getFileName()); break; case BrainModelSurface::SURFACE_TYPE_HULL: loadedFilesSpecFile.hullCoordFile.clearSelectionStatus(cf->getFileName()); break; case BrainModelSurface::SURFACE_TYPE_UNKNOWN: case BrainModelSurface::SURFACE_TYPE_UNSPECIFIED: loadedFilesSpecFile.unknownCoordFile.clearSelectionStatus(cf->getFileName()); break; } } const QString configID = BrainModelSurface::getSurfaceConfigurationIDFromType(st); cf->setHeaderTag(AbstractFile::headerTagConfigurationID, configID); // // Update the surface type for the BrainModelSurface that uses // this coordinate file that is being saved. // for (int i = 0; i < getNumberOfBrainModels(); i++) { BrainModel* bm = getBrainModel(i); if (bm->getModelType() == BrainModel::BRAIN_MODEL_SURFACE) { BrainModelSurface* bms = dynamic_cast(bm); CoordinateFile* coordFile = bms->getCoordinateFile(); if (coordFile == cf) { // // Get the name of the topology file // QString topoFileName; const TopologyFile* tf = bms->getTopologyFile(); if (tf != NULL) { topoFileName = FileUtilities::basename(tf->getFileName()); if (topoFileName.length() < 5) { topoFileName = ""; } } cf->setHeaderTag(SpecFile::getUnknownTopoFileMatchTag(), topoFileName); const Structure::STRUCTURE_TYPE hem = bms->getStructure().getType(); if (hem != Structure::STRUCTURE_TYPE_INVALID) { cf->setHeaderTag(AbstractFile::headerTagStructure, Structure::convertTypeToString(hem)); } bms->setSurfaceType(st); } } } cf->writeFile(name); if (updateSpecFile) { addToSpecFile(BrainModelSurface::getCoordSpecFileTagFromSurfaceType(st), name); } } /** * Read the volume file data */ void BrainSet::readVolumeFile(const QString& name, const VolumeFile::VOLUME_TYPE vt, const bool appendIn, const bool updateSpecIn) throw (FileException) { bool updateSpec = updateSpecIn; bool append = appendIn; std::vector volumes; VolumeFile::readFile(name, VolumeFile::VOLUME_READ_SELECTION_ALL, volumes, false); for (unsigned int i = 0; i < volumes.size(); i++) { VolumeFile* vf = volumes[i]; // // Should a transformation matrix be applied ? // if (specDataFileTransformationMatrix.isIdentity() == false) { vf->applyTransformationMatrix(specDataFileTransformationMatrix); vf->clearModified(); } if (i > 0) { updateSpec = false; append = true; } addVolumeFile(vt, vf, name, append, updateSpec); } // // If not reading a spec file, reading prob atlas volumes, and // appending volumes, then region names need to be synchronized // if (readingSpecFileFlag == false) { if (vt == VolumeFile::VOLUME_TYPE_PROB_ATLAS) { if (volumes.size() < volumeProbAtlasFiles.size()) { synchronizeProbAtlasVolumeRegionNames(); } } } } /** * Add a volume file to this brain set and create a brain model volume if necessary. */ void BrainSet::addVolumeFile(const VolumeFile::VOLUME_TYPE vt, VolumeFile* vf, const QString& name, const bool append, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexAddVolumeFile); QString tag; // // Add the volume file to this brain set. // switch (vt) { case VolumeFile::VOLUME_TYPE_ANATOMY: if (append == false) { clearVolumeAnatomyFiles(); } volumeAnatomyFiles.push_back(vf); tag = SpecFile::getVolumeAnatomyFileTag(); break; case VolumeFile::VOLUME_TYPE_FUNCTIONAL: if (append == false) { clearVolumeFunctionalFiles(); } volumeFunctionalFiles.push_back(vf); tag = SpecFile::getVolumeFunctionalFileTag(); break; case VolumeFile::VOLUME_TYPE_PAINT: if (append == false) { clearVolumePaintFiles(); } volumePaintFiles.push_back(vf); tag = SpecFile::getVolumePaintFileTag(); break; case VolumeFile::VOLUME_TYPE_PROB_ATLAS: if (append == false) { clearVolumeProbabilisticAtlasFiles(); } else if (volumeProbAtlasFiles.size() > 0) { int dimOld[3]; volumeProbAtlasFiles[0]->getDimensions(dimOld); int dimNew[3]; vf->getDimensions(dimNew); if ((dimOld[0] != dimNew[0]) || (dimOld[1] != dimNew[1]) || (dimOld[2] != dimNew[2])) { throw FileException("Newly selected probabilistic atlas volume " "has different dimensions than previously " "loaded probabilistic atlas volume(s). All " "probabilistic atlas volumes must have the " "same dimensions."); } } volumeProbAtlasFiles.push_back(vf); //if (volumeProbAtlasFiles.size() > 1) { // volumeProbAtlasFiles[0]->setVoxelColoringInvalid(); //} tag = SpecFile::getVolumeProbAtlasFileTag(); displaySettingsProbabilisticAtlasVolume->update(); break; case VolumeFile::VOLUME_TYPE_RGB: if (append == false) { clearVolumeRgbFiles(); } volumeRgbFiles.push_back(vf); tag = SpecFile::getVolumeRgbFileTag(); break; case VolumeFile::VOLUME_TYPE_ROI: return; break; case VolumeFile::VOLUME_TYPE_SEGMENTATION: { if (append == false) { clearVolumeSegmentationFiles(); } const bool isModified = vf->getModified(); vf->makeSegmentationZeroTwoFiftyFive(); if (isModified == false) { vf->clearModified(); } volumeSegmentationFiles.push_back(vf); tag = SpecFile::getVolumeSegmentationFileTag(); } break; case VolumeFile::VOLUME_TYPE_VECTOR: { if (append == false) { clearVolumeVectorFiles(); } volumeVectorFiles.push_back(vf); tag = SpecFile::getVolumeVectorFileTag(); } break; case VolumeFile::VOLUME_TYPE_UNKNOWN: return; break; } // // Update the spec file // if (updateSpec) { if (name.isEmpty() == false) { addToSpecFile(tag, name, vf->getDataFileName()); } } // // Set the volume's type // vf->setVolumeType(vt); /* // // Adjust anatomy and segmentation volume ranges. // QTime timer; timer.start(); vf->scaleAnatomyAndSegmentationVolumesTo255(); if (DebugControl::getDebugOn()) { std::cout << "Time to read scale anatomy/segmentation volume " << FileUtilities::basename(vf->getFileName()) << " was " << (static_cast(timer.elapsed()) / 1000.0) << " seconds." << std::endl; } */ // // Create a brain model volume if there is not one // BrainModelVolume* bmv = NULL; for (int i = 0; i < getNumberOfBrainModels(); i++) { bmv = getBrainModelVolume(i); if (bmv != NULL) { break; } } bool createdBrainModelVolume = false; if (bmv == NULL) { createdBrainModelVolume = true; bmv = new BrainModelVolume(this); addBrainModel(bmv); voxelColoring->initializeUnderlay(); } switch (vt) { case VolumeFile::VOLUME_TYPE_ANATOMY: break; case VolumeFile::VOLUME_TYPE_FUNCTIONAL: break; case VolumeFile::VOLUME_TYPE_PAINT: break; case VolumeFile::VOLUME_TYPE_PROB_ATLAS: // // Update indices into name table // // if (readingSpecFileFlag == false) { // synchronizeProbAtlasVolumeRegionNames(); // } displaySettingsProbabilisticAtlasVolume->update(); break; case VolumeFile::VOLUME_TYPE_RGB: break; case VolumeFile::VOLUME_TYPE_ROI: break; case VolumeFile::VOLUME_TYPE_SEGMENTATION: break; case VolumeFile::VOLUME_TYPE_VECTOR: break; case VolumeFile::VOLUME_TYPE_UNKNOWN: return; break; } /* // // Color the voxels for this volume // QTime colorTime; colorTime.start(); voxelColoring->updateVolumeFileColoring(vf); if (DebugControl::getDebugOn()) { std::cout << "Time to color volume: " << vf->getFileName() << (static_cast(colorTime.elapsed()) / 1000.0) << " seconds." << std::endl; } */ if (readingSpecFileFlag == false) { displaySettingsVolume->update(); displaySettingsWustlRegion->update(); } if (createdBrainModelVolume) { bmv->initializeSelectedSlicesAllViews(true); } // // Possibly create a brain model surface and volume // createBrainModelSurfaceAndVolume(); } /** * delete a volume file. */ void BrainSet::deleteVolumeFile(const VolumeFile* vf) { if (vf == NULL) { return; } if (getNumberOfVolumeFunctionalFiles() > 0) { std::vector files; for (int i = 0; i < getNumberOfVolumeFunctionalFiles(); i++) { if (vf != getVolumeFunctionalFile(i)) { files.push_back(getVolumeFunctionalFile(i)); } } volumeFunctionalFiles = files; } if (getNumberOfVolumePaintFiles() > 0) { std::vector files; for (int i = 0; i < getNumberOfVolumePaintFiles(); i++) { if (vf != getVolumePaintFile(i)) { files.push_back(getVolumePaintFile(i)); } } volumePaintFiles = files; } if (getNumberOfVolumeProbAtlasFiles() > 0) { std::vector files; int indx = -1; for (int i = 0; i < getNumberOfVolumeProbAtlasFiles(); i++) { if (vf != getVolumeProbAtlasFile(i)) { files.push_back(getVolumeProbAtlasFile(i)); } else { indx = i; } } volumeProbAtlasFiles = files; } if (getNumberOfVolumeRgbFiles() > 0) { std::vector files; for (int i = 0; i < getNumberOfVolumeRgbFiles(); i++) { if (vf != getVolumeRgbFile(i)) { files.push_back(getVolumeRgbFile(i)); } } volumeRgbFiles = files; } if (getNumberOfVolumeSegmentationFiles() > 0) { std::vector files; for (int i = 0; i < getNumberOfVolumeSegmentationFiles(); i++) { if (vf != getVolumeSegmentationFile(i)) { files.push_back(getVolumeSegmentationFile(i)); } } volumeSegmentationFiles = files; } if (getNumberOfVolumeAnatomyFiles() > 0) { std::vector files; for (int i = 0; i < getNumberOfVolumeAnatomyFiles(); i++) { if (vf != getVolumeAnatomyFile(i)) { files.push_back(getVolumeAnatomyFile(i)); } } volumeAnatomyFiles = files; } if (getNumberOfVolumeVectorFiles() > 0) { std::vector files; for (int i = 0; i < getNumberOfVolumeVectorFiles(); i++) { if (vf != getVolumeVectorFile(i)) { files.push_back(getVolumeVectorFile(i)); } } volumeVectorFiles = files; } if ((getNumberOfVolumeFunctionalFiles() == 0) && (getNumberOfVolumeRgbFiles() == 0) && (getNumberOfVolumePaintFiles() == 0) && (getNumberOfVolumeSegmentationFiles() == 0) && (getNumberOfVolumeAnatomyFiles() == 0) && (getNumberOfVolumeVectorFiles() == 0)) { BrainModelVolume* bmv = getBrainModelVolume(); if (bmv != NULL) { deleteBrainModel(bmv); } BrainModelSurfaceAndVolume* bmsv = getBrainModelSurfaceAndVolume(); if (bmsv != NULL) { deleteBrainModel(bmsv); } } displaySettingsVolume->update(); displaySettingsWustlRegion->update(); loadedFilesSpecFile.volumeFunctionalFile.clearSelectionStatus(vf->getFileName()); loadedFilesSpecFile.volumePaintFile.clearSelectionStatus(vf->getFileName()); loadedFilesSpecFile.volumeProbAtlasFile.clearSelectionStatus(vf->getFileName()); loadedFilesSpecFile.volumeRgbFile.clearSelectionStatus(vf->getFileName()); loadedFilesSpecFile.volumeSegmentationFile.clearSelectionStatus(vf->getFileName()); loadedFilesSpecFile.volumeAnatomyFile.clearSelectionStatus(vf->getFileName()); loadedFilesSpecFile.volumeVectorFile.clearSelectionStatus(vf->getFileName()); delete vf; nodeColoring->assignColors(); clearAllDisplayLists(); } /** * Write the multi-volume file data. */ void BrainSet::writeMultiVolumeFile(const QString& name, const VolumeFile::VOLUME_TYPE volumeType, const QString& comment, std::vector& subVolumes, const VolumeFile::VOXEL_DATA_TYPE voxelDataTypeToWriteIn, const bool zipAfniVolumeFile) throw (FileException) { VolumeFile::VOXEL_DATA_TYPE voxelDataTypeToWrite = voxelDataTypeToWriteIn; if (voxelDataTypeToWrite == VolumeFile::VOXEL_DATA_TYPE_UNKNOWN) { if (subVolumes.empty() == false) { voxelDataTypeToWrite = subVolumes[0]->getVoxelDataType(); } } // // Set spec file tag // QString tag(SpecFile::getVolumeAnatomyFileTag()); switch (volumeType) { case VolumeFile::VOLUME_TYPE_ANATOMY: tag = SpecFile::getVolumeAnatomyFileTag(); break; case VolumeFile::VOLUME_TYPE_FUNCTIONAL: tag = SpecFile::getVolumeFunctionalFileTag(); break; case VolumeFile::VOLUME_TYPE_PAINT: tag = SpecFile::getVolumePaintFileTag(); break; case VolumeFile::VOLUME_TYPE_PROB_ATLAS: tag = SpecFile::getVolumeProbAtlasFileTag(); break; case VolumeFile::VOLUME_TYPE_RGB: tag = SpecFile::getVolumeRgbFileTag(); break; case VolumeFile::VOLUME_TYPE_ROI: throw FileException(FileUtilities::basename(name), "Unrecognized volume type"); break; case VolumeFile::VOLUME_TYPE_SEGMENTATION: tag = SpecFile::getVolumeSegmentationFileTag(); break; case VolumeFile::VOLUME_TYPE_VECTOR: tag = SpecFile::getVolumeVectorFileTag(); break; case VolumeFile::VOLUME_TYPE_UNKNOWN: throw FileException(FileUtilities::basename(name), "Unrecognized volume type"); break; } if (subVolumes.empty() == false) { subVolumes[0]->setFileComment(comment); VolumeFile::writeFile(name, volumeType, voxelDataTypeToWrite, subVolumes, zipAfniVolumeFile); addToSpecFile(tag, name, subVolumes[0]->getDataFileName()); } /* const QString dataFileName = VolumeFile::writeMultiVolumeFile(name, writeFileType, comment, subVolumes); */ } /** * Write the volume file data. */ void BrainSet::writeVolumeFile(const QString& nameIn, const VolumeFile::FILE_READ_WRITE_TYPE writeFileType, const VolumeFile::VOLUME_TYPE volumeType, VolumeFile* vf, const VolumeFile::VOXEL_DATA_TYPE voxelDataTypeToWriteIn, const bool zipAfniVolumeFile) throw (FileException) { VolumeFile::VOXEL_DATA_TYPE voxelDataTypeToWrite = voxelDataTypeToWriteIn; if (voxelDataTypeToWrite == VolumeFile::VOXEL_DATA_TYPE_UNKNOWN) { voxelDataTypeToWrite = vf->getVoxelDataType(); } QString name(nameIn); // // NIFTI GZIP // if (name.endsWith(SpecFile::getNiftiVolumeFileExtension()) && zipAfniVolumeFile) { name += ".gz"; } vf->setFileWriteType(writeFileType); // // Set spec file tag // QString tag(SpecFile::getVolumeAnatomyFileTag()); switch (volumeType) { case VolumeFile::VOLUME_TYPE_ANATOMY: tag = SpecFile::getVolumeAnatomyFileTag(); loadedFilesSpecFile.volumeAnatomyFile.clearSelectionStatus(vf->getFileName()); break; case VolumeFile::VOLUME_TYPE_FUNCTIONAL: tag = SpecFile::getVolumeFunctionalFileTag(); loadedFilesSpecFile.volumeFunctionalFile.clearSelectionStatus(vf->getFileName()); break; case VolumeFile::VOLUME_TYPE_PAINT: tag = SpecFile::getVolumePaintFileTag(); loadedFilesSpecFile.volumePaintFile.clearSelectionStatus(vf->getFileName()); break; case VolumeFile::VOLUME_TYPE_PROB_ATLAS: tag = SpecFile::getVolumeProbAtlasFileTag(); loadedFilesSpecFile.volumeProbAtlasFile.clearSelectionStatus(vf->getFileName()); break; case VolumeFile::VOLUME_TYPE_RGB: tag = SpecFile::getVolumeRgbFileTag(); loadedFilesSpecFile.volumeRgbFile.clearSelectionStatus(vf->getFileName()); break; case VolumeFile::VOLUME_TYPE_ROI: throw FileException(FileUtilities::basename(name), "Unrecognized volume type=ROI"); break; case VolumeFile::VOLUME_TYPE_SEGMENTATION: tag = SpecFile::getVolumeSegmentationFileTag(); loadedFilesSpecFile.volumeSegmentationFile.clearSelectionStatus(vf->getFileName()); break; case VolumeFile::VOLUME_TYPE_VECTOR: tag = SpecFile::getVolumeVectorFileTag(); loadedFilesSpecFile.volumeVectorFile.clearSelectionStatus(vf->getFileName()); break; case VolumeFile::VOLUME_TYPE_UNKNOWN: throw FileException(FileUtilities::basename(name), "Unrecognized volume type"); break; } std::vector volumesToWrite; volumesToWrite.push_back(vf); VolumeFile::writeFile(name, volumeType, voxelDataTypeToWrite, volumesToWrite, zipAfniVolumeFile); /* vf->writeFile(name); QString dataFileName(vf->getDataFileName()); if (vf->getWriteFileGzip()) { if (dataFileName.right(3) != ".gz") { dataFileName.append(".gz"); } if (writeFileType == VolumeFile::FILE_READ_WRITE_TYPE_NIFTI) { if (name.right(3) != ".gz") { name.append(".gz"); } } } */ addToSpecFile(tag, name, vf->getDataFileName()); } /** * read the surface data file file. */ void BrainSet::readSurfaceFile(const QString& name, const BrainModelSurface::SURFACE_TYPES surfaceTypeIn, const bool readingSpecFile, const bool append, const bool updateSpec) throw (FileException) { BrainModelSurface::SURFACE_TYPES surfaceType = surfaceTypeIn; BrainModelSurface* bms = new BrainModelSurface(this); bms->readSurfaceFile(name); if (surfaceType == BrainModelSurface::SURFACE_TYPE_UNKNOWN) { surfaceType = bms->getSurfaceType(); } QMutexLocker mutex(&mutexReadSurfaceFile); bool needToInitialize = false; if (readingSpecFile == false) { needToInitialize = true; for (int i = 0; i < getNumberOfBrainModels(); i++) { if (getBrainModelSurface(i) != NULL) { needToInitialize = false; } } } if (append == false) { deleteSurfacesOfType(surfaceType); } if (getNumberOfNodes() == 0) { if (bms->getNumberOfNodes() > 0) { numNodesMessage = " contains a different number of nodes than "; numNodesMessage.append(FileUtilities::basename(name)); } else { delete bms; bms = NULL; throw FileException(name, "Contains no nodes"); } } else if (getNumberOfNodes() != bms->getNumberOfNodes()) { delete bms; bms = NULL; throw FileException(FileUtilities::basename(name), numNodesMessage); } // // Get the coordinate file // CoordinateFile* cf = bms->getCoordinateFile(); QString tag; bool applyTransformFlag = false; switch(surfaceType) { case BrainModelSurface::SURFACE_TYPE_RAW: tag = SpecFile::getRawSurfaceFileTag(); applyTransformFlag = (specDataFileTransformationMatrix.isIdentity() == false); break; case BrainModelSurface::SURFACE_TYPE_FIDUCIAL: tag = SpecFile::getFiducialSurfaceFileTag(); applyTransformFlag = (specDataFileTransformationMatrix.isIdentity() == false); break; case BrainModelSurface::SURFACE_TYPE_INFLATED: tag = SpecFile::getInflatedSurfaceFileTag(); break; case BrainModelSurface::SURFACE_TYPE_VERY_INFLATED: tag = SpecFile::getVeryInflatedSurfaceFileTag(); break; case BrainModelSurface::SURFACE_TYPE_SPHERICAL: tag = SpecFile::getSphericalSurfaceFileTag(); break; case BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL: tag = SpecFile::getEllipsoidSurfaceFileTag(); break; case BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL: tag = SpecFile::getCompressedSurfaceFileTag(); break; case BrainModelSurface::SURFACE_TYPE_FLAT: tag = SpecFile::getFlatSurfaceFileTag(); break; case BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR: tag = SpecFile::getLobarFlatSurfaceFileTag(); break; case BrainModelSurface::SURFACE_TYPE_HULL: tag = SpecFile::getHullSurfaceFileTag(); break; case BrainModelSurface::SURFACE_TYPE_UNKNOWN: case BrainModelSurface::SURFACE_TYPE_UNSPECIFIED: tag = SpecFile::getUnknownSurfaceFileMatchTag(); break; default: throw FileException(FileUtilities::basename(name), "Unrecognized surface type"); break; } // // If transformation matrix should be applied // if (applyTransformFlag) { cf->applyTransformationMatrix(specDataFileTransformationMatrix); cf->clearModified(); } bms->computeNormals(); bms->setSurfaceType(surfaceType); // // Only set the structure for the surface if the structure is unknown // if (bms->getStructure() == Structure::STRUCTURE_TYPE_INVALID) { if (structure.getType() != Structure::STRUCTURE_TYPE_INVALID) { bms->setStructure(structure.getType()); } //cf->setHeaderTag(AbstractFile::headerTagHemisphere, ""); } cf->clearModified(); // setSurfaceType causes modified flat to be set addBrainModel(bms, readingSpecFile); setSelectedTopologyFiles(); if (updateSpec) { addToSpecFile(tag, name); } if (needToInitialize) { postSpecFileReadInitializations(); } // // Possibly create a brain model surface and volume // createBrainModelSurfaceAndVolume(); } /** * Read the coordinate data file file */ void BrainSet::readCoordinateFile(const QString& name, const BrainModelSurface::SURFACE_TYPES stin, const bool readingSpecFile, const bool append, const bool updateSpec) throw (FileException) { // // get type of surface from file, if needed // BrainModelSurface::SURFACE_TYPES st = stin; if ((st == BrainModelSurface::SURFACE_TYPE_UNSPECIFIED) || (st == BrainModelSurface::SURFACE_TYPE_UNKNOWN)) { CoordinateFile cf; cf.readFileMetaDataOnly(name); const QString typeTag = cf.getHeaderTag(AbstractFile::headerTagConfigurationID); if (typeTag.isEmpty() == false) { st = BrainModelSurface::getSurfaceTypeFromConfigurationID(typeTag); } } // // Read the coordinate file // BrainModelSurface* bms = new BrainModelSurface(this); bms->readCoordinateFile(name); // // The remainder of this routine must not be run by more than one thread // QMutexLocker locker(&mutexReadCoordinateFile); // // See if initialization needed // bool needToInitialize = false; if (readingSpecFile == false) { needToInitialize = true; for (int i = 0; i < getNumberOfBrainModels(); i++) { if ((getBrainModelSurface(i) != NULL) && (getBrainModelSurface(i) != bms)) { needToInitialize = false; } } } // // Check nodes // if (getNumberOfNodes() == 0) { if (bms->getNumberOfNodes() > 0) { numNodesMessage = " contains a different number of nodes than "; numNodesMessage.append(FileUtilities::basename(name)); } else { delete bms; bms = NULL; throw FileException(name, "Contains no nodes"); } } else if (getNumberOfNodes() != bms->getNumberOfNodes()) { delete bms; bms = NULL; throw FileException(FileUtilities::basename(name), numNodesMessage); } if (append == false) { deleteSurfacesOfType(st); } // // Get the coordinate file // CoordinateFile* cf = bms->getCoordinateFile(); // // May automatically set topology file // TopologyFile* useThisTopologyFile = NULL; /* if (readingSpecFile) { const QString topoFile = cf->getHeaderTag(SpecFile::UnknownTopoFileMatchTag); if (topoFile.empty() == false) { for (int i = 0; i < getNumberOfTopologyFiles(); i++) { if (FileUtilities::basename(topoFile) == FileUtilities::basename(getTopologyFile(i)->getFileName())) { useThisTopologyFile = getTopologyFile(i); break; } } } } else { */ // // Should topo file listed in coord file's header be used // if (ignoreTopologyFileInCoordinateFileHeaderFlag == false) { // // Load matching topo file if it is not already loaded // const QString topoFile = cf->getHeaderTag(SpecFile::getUnknownTopoFileMatchTag()); if (topoFile.isEmpty() == false) { bool loadIt = true; for (int i = 0; i < getNumberOfTopologyFiles(); i++) { if (FileUtilities::basename(topoFile) == FileUtilities::basename(getTopologyFile(i)->getFileName())) { loadIt = false; useThisTopologyFile = getTopologyFile(i); break; } } if (QFile::exists(topoFile) && loadIt) { try { // // Want to update spec file even if reading files from spec file // const bool readingSpecFileFlagCOPY = readingSpecFileFlag; readingSpecFileFlag = false; readTopologyFile(topoFile, TopologyFile::TOPOLOGY_TYPE_UNSPECIFIED, true, true); readingSpecFileFlag = readingSpecFileFlagCOPY; //const int topoIndex = getNumberOfTopologyFiles() - 1; //if ((topoIndex >= 0) && (topoIndex < getNumberOfTopologyFiles())) { // // Note that readTopologyFile() always places the just read topology // file as the first topology file // if (getNumberOfTopologyFiles() > 0) { useThisTopologyFile = getTopologyFile(0); } } catch (FileException& /*e*/) { } } } } /* } */ // // Update configuration ID in the coord file // const QString configID = BrainModelSurface::getSurfaceConfigurationIDFromType(st); cf->setHeaderTag(AbstractFile::headerTagConfigurationID, configID); cf->clearModified(); QString tag; bool applyTransformFlag = false; bool topoError = false; switch(st) { case BrainModelSurface::SURFACE_TYPE_RAW: topoError = bms->setTopologyFile(topologyClosed); tag = SpecFile::getRawCoordFileTag(); applyTransformFlag = (specDataFileTransformationMatrix.isIdentity() == false); break; case BrainModelSurface::SURFACE_TYPE_FIDUCIAL: topoError = bms->setTopologyFile(topologyClosed); tag = SpecFile::getFiducialCoordFileTag(); applyTransformFlag = (specDataFileTransformationMatrix.isIdentity() == false); break; case BrainModelSurface::SURFACE_TYPE_INFLATED: topoError = bms->setTopologyFile(topologyClosed); tag = SpecFile::getInflatedCoordFileTag(); break; case BrainModelSurface::SURFACE_TYPE_VERY_INFLATED: topoError = bms->setTopologyFile(topologyClosed); tag = SpecFile::getVeryInflatedCoordFileTag(); break; case BrainModelSurface::SURFACE_TYPE_SPHERICAL: topoError = bms->setTopologyFile(topologyClosed); tag = SpecFile::getSphericalCoordFileTag(); break; case BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL: topoError = bms->setTopologyFile(topologyClosed); tag = SpecFile::getEllipsoidCoordFileTag(); break; case BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL: topoError = bms->setTopologyFile(topologyClosed); tag = SpecFile::getCompressedCoordFileTag(); break; case BrainModelSurface::SURFACE_TYPE_FLAT: topoError = bms->setTopologyFile(topologyCut); tag = SpecFile::getFlatCoordFileTag(); break; case BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR: topoError = bms->setTopologyFile(topologyLobarCut); tag = SpecFile::getLobarFlatCoordFileTag(); break; case BrainModelSurface::SURFACE_TYPE_HULL: topoError = bms->setTopologyFile(topologyClosed); tag = SpecFile::getHullCoordFileTag(); break; case BrainModelSurface::SURFACE_TYPE_UNKNOWN: case BrainModelSurface::SURFACE_TYPE_UNSPECIFIED: topoError = bms->setTopologyFile(topologyClosed); tag = SpecFile::getUnknownCoordFileMatchTag(); break; default: throw FileException(FileUtilities::basename(name), "Unrecognized surface type"); break; } // // If transformation matrix should be applied // if (applyTransformFlag) { cf->applyTransformationMatrix(specDataFileTransformationMatrix); cf->clearModified(); } // // Use topology file coord file was using when it was saved // if (useThisTopologyFile != NULL) { topoError = bms->setTopologyFile(useThisTopologyFile); } if (topoError) { std::ostringstream str; str << "Topology File " << FileUtilities::basename(bms->getTopologyFile()->getFileName()).toAscii().constData() << "\n is not for use with coordinate file " << FileUtilities::basename(name).toAscii().constData() << ".\n Topo file has tiles with node numbers exceeding \n" << "the number of coordinates in the coordinate file."; delete bms; throw FileException(name, str.str().c_str()); } bms->computeNormals(); bms->setSurfaceType(st); // // Only set the structure for the surface if the structure is unknown // if (bms->getStructure() == Structure::STRUCTURE_TYPE_INVALID) { if (structure.getType() != Structure::STRUCTURE_TYPE_INVALID) { bms->setStructure(structure.getType()); } //cf->setHeaderTag(AbstractFile::headerTagHemisphere, ""); } cf->clearModified(); // setSurfaceType causes modified flat to be set addBrainModel(bms, readingSpecFile); if (updateSpec) { addToSpecFile(tag, name); } if (needToInitialize) { postSpecFileReadInitializations(); } // // Possibly create a brain model surface and volume // createBrainModelSurfaceAndVolume(); } /** * Add a brain model to this brain set */ void BrainSet::addBrainModel(BrainModel* bm, const bool readingSpecFile) { // // The remainder of this routine must not be run by more than one thread // QMutexLocker locker(&mutexAddBrainModel); brainModels.push_back(bm); brainModelBorderSet->addBrainModel(bm); updateDisplayedModelIndices(); updateSurfaceOverlaysDueToChangeInBrainModels(); updateAllDisplaySettings(); if (readingSpecFile == false) { if (dynamic_cast(bm) != NULL) { nodeColoring->assignColors(); } } } /** * get the index for a brain model. */ int BrainSet::getBrainModelIndex(const BrainModel* bm) const { const int numBrainModels = getNumberOfBrainModels(); for (int i = 0; i < numBrainModels; i++) { if (bm == getBrainModel(i)) { return i; } } return -1; } /** * Delete a brain model */ void BrainSet::deleteBrainModel(const BrainModel* bm) { std::vector models; const unsigned int num = brainModels.size(); for (unsigned int i = 0; i < num; i++) { if (brainModels[i] != bm) { models.push_back(brainModels[i]); } } brainModelBorderSet->deleteBrainModel(bm); brainModels = models; delete bm; updateDisplayedModelIndices(); updateSurfaceOverlaysDueToChangeInBrainModels(); updateAllDisplaySettings(); nodeColoring->assignColors(); clearAllDisplayLists(); } /** * Write the foci data file of the specified type. */ void BrainSet::writeFociFile(const QString& name, const BrainModelSurface* leftBMS, const BrainModelSurface* rightBMS, const BrainModelSurface* cerebellumBMS, const AbstractFile::FILE_FORMAT fileFormat, const QString& commentText) throw (FileException) { FociFile ff; const CoordinateFile* leftCF = ((leftBMS != NULL) ? leftBMS->getCoordinateFile() : NULL); const TopologyFile* leftTF = ((leftBMS != NULL) ? leftBMS->getTopologyFile() : NULL); const CoordinateFile* rightCF = ((rightBMS != NULL) ? rightBMS->getCoordinateFile() : NULL); const TopologyFile* rightTF = ((rightBMS != NULL) ? rightBMS->getTopologyFile() : NULL); const CoordinateFile* cerebellumCF = ((cerebellumBMS != NULL) ? cerebellumBMS->getCoordinateFile() : NULL); const TopologyFile* cerebellumTF = ((cerebellumBMS != NULL) ? cerebellumBMS->getTopologyFile() : NULL); fociProjectionFile->getCellFileForRightLeftFiducials(leftCF, leftTF, rightCF, rightTF, cerebellumCF, cerebellumTF, ff); // // Check for foci // if (ff.getNumberOfCells() <= 0) { throw FileException("There are no foci that project to the selected surface(s)."); } ff.setFileComment(commentText); ff.setFileWriteType(fileFormat); ff.writeFile(name); addToSpecFile(SpecFile::getFociFileTag(), name); } /** * write the Foci data file. */ void BrainSet::writeFociFileOriginalCoordinates(const QString& name, const AbstractFile::FILE_FORMAT fileFormat, const QString& commentText) throw (FileException) { FociFile ff; fociProjectionFile->getCellFileOriginalCoordinates(ff); ff.setFileComment(commentText); ff.setFileWriteType(fileFormat); ff.writeFile(name); addToSpecFile(SpecFile::getFociFileTag(), name); } /** * Read the foci data file file */ void BrainSet::readFociFile(const QString& name, const bool append, const bool updateSpec) throw (FileException) { FociFile fociFile; try { fociFile.readFile(name); // // If transformation should be applied // if (specDataFileTransformationMatrix.isIdentity() == false) { fociFile.applyTransformationMatrix(std::numeric_limits::min(), std::numeric_limits::max(), specDataFileTransformationMatrix, false); } } catch (FileException& e) { throw FileException(FileUtilities::basename(name), e.whatQString()); } QMutexLocker locker(&mutexFociAndFociProjectionFile); if (append == false) { deleteAllFociProjections(); } fociProjectionFile->appendFiducialCellFile(fociFile); if (updateSpec) { addToSpecFile(SpecFile::getFociFileTag(), name); } } /** * Write the foci color data file. */ void BrainSet::writeFociColorFile(const QString& name) throw (FileException) { loadedFilesSpecFile.fociColorFile.setAllSelections(SpecFile::SPEC_FALSE); fociColorFile->writeFile(name); addToSpecFile(SpecFile::getFociColorFileTag(), name); } /** * Read the foci color data file file */ void BrainSet::readFociColorFile(const QString& name, const bool append, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexFociColorFile); if (append == false) { clearFociColorFile(); } const unsigned long modified = fociColorFile->getModified(); if (fociColorFile->getNumberOfColors() == 0) { try { fociColorFile->readFile(name); } catch (FileException& e) { clearFociColorFile(); throw FileException(FileUtilities::basename(name), e.whatQString()); } } else { // Append to existing FociColorFile cf; cf.readFile(name); QString msg; fociColorFile->append(cf); } fociColorFile->setModifiedCounter(modified); if (updateSpec) { addToSpecFile(SpecFile::getFociColorFileTag(), name); } } /** * Write the Foci Projection data file. */ void BrainSet::writeFociProjectionFile(const QString& name) throw (FileException) { loadedFilesSpecFile.fociProjectionFile.setAllSelections(SpecFile::SPEC_FALSE); fociProjectionFile->writeFile(name); addToSpecFile(SpecFile::getFociProjectionFileTag(), name); } /** * Read the foci projection data file file */ void BrainSet::readFociProjectionFile(const QString& name, const bool append, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexFociAndFociProjectionFile); if (append == false) { deleteAllFociProjections(); } const unsigned long modified = fociProjectionFile->getModified(); if (fociProjectionFile->getNumberOfCellProjections() == 0) { try { fociProjectionFile->readFile(name); } catch (FileException& e) { deleteAllFociProjections(); throw FileException(FileUtilities::basename(name), e.whatQString()); } } else { // Append to existing FociProjectionFile cf; cf.readFile(name); QString msg; fociProjectionFile->append(cf); } fociProjectionFile->setModifiedCounter(modified); if (readingSpecFileFlag == false) { displaySettingsFoci->update(); } if (updateSpec) { addToSpecFile(SpecFile::getFociProjectionFileTag(), name); } } /** * Write the Foci Search data file. */ void BrainSet::writeFociSearchFile(const QString& name) throw (FileException) { loadedFilesSpecFile.fociSearchFile.setAllSelections(SpecFile::SPEC_FALSE); fociSearchFile->writeFile(name); addToSpecFile(SpecFile::getFociSearchFileTag(), name); } /** * Read the foci search data file file */ void BrainSet::readFociSearchFile(const QString& name, const bool append, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexFociSearchFile); if (append == false) { clearFociSearchFile(); } const unsigned long modified = fociSearchFile->getModified(); if (fociSearchFile->getNumberOfFociSearchSets() == 0) { try { fociSearchFile->readFile(name); } catch (FileException& e) { deleteAllFociProjections(); throw FileException(FileUtilities::basename(name), e.whatQString()); } } else { // Append to existing FociSearchFile fsf; fsf.readFile(name); QString msg; fociSearchFile->append(fsf); } fociSearchFile->setModifiedCounter(modified); if (readingSpecFileFlag == false) { displaySettingsFoci->update(); } if (updateSpec) { addToSpecFile(SpecFile::getFociSearchFileTag(), name); } } /** * Write the geodesic distance data file. */ void BrainSet::writeGeodesicDistanceFile(const QString& name) throw (FileException) { loadedFilesSpecFile.geodesicDistanceFile.setAllSelections(SpecFile::SPEC_FALSE); geodesicDistanceFile->writeFile(name); addToSpecFile(SpecFile::getGeodesicDistanceFileTag(), name); } /** * read the geodesic distance data file file (only selected columns). */ void BrainSet::readGeodesicDistanceFile(const QString& name, const std::vector& columnDestination, const std::vector& fileBeingReadColumnNames, const AbstractFile::FILE_COMMENT_MODE fcm, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexGeodesicDistanceFile); GeodesicDistanceFile gdf; gdf.readFile(name); if (gdf.getNumberOfNodes() != getNumberOfNodes()) { throw FileException(FileUtilities::basename(name), numNodesMessage); } try { for (int i = 0; i < gdf.getNumberOfColumns(); i++) { if (i < static_cast(fileBeingReadColumnNames.size())) { gdf.setColumnName(i, fileBeingReadColumnNames[i]); } } geodesicDistanceFile->append(gdf, columnDestination, fcm); } catch (FileException& e) { throw FileException(FileUtilities::basename(name), e.whatQString()); } geodesicDistanceFile->setModified(); displaySettingsGeodesicDistance->update(); if (updateSpec) { addToSpecFile(SpecFile::getGeodesicDistanceFileTag(), name); } } /** * Read the geodesic distance data file file */ void BrainSet::readGeodesicDistanceFile(const QString& name, const bool append, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexGeodesicDistanceFile); if (append == false) { clearGeodesicDistanceFile(); } const unsigned long modified = geodesicDistanceFile->getModified(); if (geodesicDistanceFile->getNumberOfColumns() == 0) { try { geodesicDistanceFile->readFile(name); if (geodesicDistanceFile->getNumberOfNodes() != getNumberOfNodes()) { throw FileException(FileUtilities::basename(name), numNodesMessage); } } catch (FileException& e) { clearGeodesicDistanceFile(); throw FileException(FileUtilities::basename(name), e.whatQString()); } } else { // Append to existing GeodesicDistanceFile gdf; gdf.readFile(name); if (gdf.getNumberOfNodes() != getNumberOfNodes()) { throw FileException(FileUtilities::basename(name), numNodesMessage); } try { geodesicDistanceFile->append(gdf); } catch (FileException& e) { throw FileException(FileUtilities::basename(name), e.whatQString()); } } geodesicDistanceFile->setModifiedCounter(modified); displaySettingsGeodesicDistance->update(); if (updateSpec) { addToSpecFile(SpecFile::getGeodesicDistanceFileTag(), name); } } /** * Write the lat lon data file. */ void BrainSet::writeLatLonFile(const QString& name) throw (FileException) { loadedFilesSpecFile.latLonFile.setAllSelections(SpecFile::SPEC_FALSE); latLonFile->writeFile(name); addToSpecFile(SpecFile::getLatLonFileTag(), name); } /** * read the lat lon data file file (only selected columns). */ void BrainSet::readLatLonFile(const QString& name, const std::vector& columnDestination, const std::vector& fileBeingReadColumnNames, const AbstractFile::FILE_COMMENT_MODE fcm, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexLatLonFile); LatLonFile llf; llf.readFile(name); if (llf.getNumberOfNodes() != getNumberOfNodes()) { throw FileException(FileUtilities::basename(name), numNodesMessage); } try { for (int i = 0; i < llf.getNumberOfColumns(); i++) { if (i < static_cast(fileBeingReadColumnNames.size())) { llf.setColumnName(i, fileBeingReadColumnNames[i]); } } latLonFile->append(llf, columnDestination, fcm); } catch (FileException& e) { throw FileException(FileUtilities::basename(name), e.whatQString()); } latLonFile->setModified(); if (updateSpec) { addToSpecFile(SpecFile::getLatLonFileTag(), name); } } /** * Read the lat lon data file file */ void BrainSet::readLatLonFile(const QString& name, const bool append, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexLatLonFile); if (append == false) { clearLatLonFile(); } const unsigned long modified = latLonFile->getModified(); if (latLonFile->getNumberOfColumns() == 0) { try { latLonFile->readFile(name); if (latLonFile->getNumberOfNodes() != getNumberOfNodes()) { throw FileException(FileUtilities::basename(name), numNodesMessage); } } catch (FileException& e) { clearLatLonFile(); throw FileException(FileUtilities::basename(name), e.whatQString()); } } else { // Append to existing LatLonFile llf; llf.readFile(name); if (llf.getNumberOfNodes() != getNumberOfNodes()) { throw FileException(FileUtilities::basename(name), numNodesMessage); } try { latLonFile->append(llf); } catch (FileException& e) { throw FileException(FileUtilities::basename(name), e.whatQString()); } } latLonFile->setModifiedCounter(modified); if (updateSpec) { addToSpecFile(SpecFile::getLatLonFileTag(), name); } } /** * Write the metric data file. */ void BrainSet::writeMetricFile(const QString& name) throw (FileException) { loadedFilesSpecFile.metricFile.setAllSelections(SpecFile::SPEC_FALSE); metricFile->writeFile(name); addToSpecFile(SpecFile::getMetricFileTag(), name); } /** * read the metric data file file (only selected columns). */ void BrainSet::readMetricFile(const QString& name, const std::vector& columnDestination, const std::vector& fileBeingReadColumnNames, const AbstractFile::FILE_COMMENT_MODE fcm, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexMetricFile); const bool metricFileEmpty = metricFile->empty(); MetricFile mf; mf.setNumberOfNodesForSparseNodeIndexFiles(getNumberOfNodes()); mf.readFile(name); if (mf.getNumberOfNodes() != getNumberOfNodes()) { throw FileException(FileUtilities::basename(name), numNodesMessage); } try { for (int i = 0; i < mf.getNumberOfColumns(); i++) { if (i < static_cast(fileBeingReadColumnNames.size())) { if (fileBeingReadColumnNames[i].isEmpty() == false) { mf.setColumnName(i, fileBeingReadColumnNames[i]); } } } std::vector columnDestination2 = columnDestination; metricFile->append(mf, columnDestination2, fcm); } catch (FileException& e) { throw FileException(FileUtilities::basename(name), e.whatQString()); } if (metricFileEmpty) { metricFile->clearModified(); } else { metricFile->setModified(); } if (readingSpecFileFlag == false) { displaySettingsMetric->update(); brainSetAutoLoaderManager->update(); } if (updateSpec) { addToSpecFile(SpecFile::getMetricFileTag(), name); } } /** * Read the metric data file file */ void BrainSet::readMetricFile(const QString& name, const bool append, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexMetricFile); if (append == false) { clearMetricFile(); } const unsigned long modified = metricFile->getModified(); if (metricFile->getNumberOfColumns() == 0) { try { metricFile->readFile(name); if (metricFile->getNumberOfNodes() != getNumberOfNodes()) { throw FileException(FileUtilities::basename(name), numNodesMessage); } } catch (FileException& e) { clearMetricFile(); throw FileException(FileUtilities::basename(name), e.whatQString()); } } else { // Append to existing MetricFile mf; mf.readFile(name); if (mf.getNumberOfNodes() != getNumberOfNodes()) { throw FileException(FileUtilities::basename(name), numNodesMessage); } try { metricFile->append(mf); } catch (FileException& e) { throw FileException(FileUtilities::basename(name), e.whatQString()); } } metricFile->setModifiedCounter(modified); if (readingSpecFileFlag == false) { displaySettingsMetric->update(); brainSetAutoLoaderManager->update(); } if (updateSpec) { addToSpecFile(SpecFile::getMetricFileTag(), name); } } /** * Write the deformation field data file. */ void BrainSet::writeDeformationFieldFile(const QString& name) throw (FileException) { loadedFilesSpecFile.deformationMapFile.setAllSelections(SpecFile::SPEC_FALSE); deformationFieldFile->writeFile(name); addToSpecFile(SpecFile::getDeformationFieldFileTag(), name); } /** * read the deformation field data file (only selected columns). */ void BrainSet::readDeformationFieldFile(const QString& name, const std::vector& columnDestination, const std::vector& fileBeingReadColumnNames, const AbstractFile::FILE_COMMENT_MODE fcm, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexDeformationFieldFile); DeformationFieldFile dff; dff.readFile(name); if (dff.getNumberOfNodes() != getNumberOfNodes()) { throw FileException(FileUtilities::basename(name), numNodesMessage); } try { for (int i = 0; i < dff.getNumberOfColumns(); i++) { if (i < static_cast(fileBeingReadColumnNames.size())) { dff.setColumnName(i, fileBeingReadColumnNames[i]); } } deformationFieldFile->append(dff, columnDestination, fcm); } catch (FileException& e) { throw FileException(FileUtilities::basename(name), e.whatQString()); } deformationFieldFile->setModified(); displaySettingsDeformationField->update(); if (updateSpec) { addToSpecFile(SpecFile::getDeformationFieldFileTag(), name); } } /** * Read the deformation field data file file */ void BrainSet::readDeformationFieldFile(const QString& name, const bool append, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexDeformationFieldFile); if (append == false) { clearDeformationFieldFile(); } const unsigned long modified = deformationFieldFile->getModified(); if (deformationFieldFile->getNumberOfColumns() == 0) { try { deformationFieldFile->readFile(name); if (deformationFieldFile->getNumberOfNodes() != getNumberOfNodes()) { throw FileException(FileUtilities::basename(name), numNodesMessage); } } catch (FileException& e) { clearDeformationFieldFile(); throw FileException(FileUtilities::basename(name), e.whatQString()); } } else { // Append to existing DeformationFieldFile dff; dff.readFile(name); if (dff.getNumberOfNodes() != getNumberOfNodes()) { throw FileException(FileUtilities::basename(name), numNodesMessage); } try { deformationFieldFile->append(dff); } catch (FileException& e) { throw FileException(FileUtilities::basename(name), e.whatQString()); } } deformationFieldFile->setModifiedCounter(modified); displaySettingsDeformationField->update(); if (updateSpec) { addToSpecFile(SpecFile::getDeformationFieldFileTag(), name); } } /** * Write the paint data file. */ void BrainSet::writePaintFile(const QString& name) throw (FileException) { paintFile->getLabelTable()->assignColors(*areaColorFile); loadedFilesSpecFile.paintFile.setAllSelections(SpecFile::SPEC_FALSE); paintFile->writeFile(name); addToSpecFile(SpecFile::getPaintFileTag(), name); } /** * read the paint data file file (only selected columns). */ void BrainSet::readPaintFile(const QString& name, const std::vector& columnDestination, const std::vector& fileBeingReadColumnNames, const AbstractFile::FILE_COMMENT_MODE fcm, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexPaintFile); const bool paintFileEmpty = paintFile->empty(); PaintFile pf; pf.readFile(name); if (pf.getNumberOfNodes() != getNumberOfNodes()) { throw FileException(FileUtilities::basename(name), numNodesMessage); } try { for (int i = 0; i < pf.getNumberOfColumns(); i++) { if (i < static_cast(fileBeingReadColumnNames.size())) { pf.setColumnName(i, fileBeingReadColumnNames[i]); } } std::vector columnDestination2 = columnDestination; if ((pf.getFileReadType() == AbstractFile::FILE_FORMAT_XML) || (pf.getFileReadType() == AbstractFile::FILE_FORMAT_XML_BASE64) || (pf.getFileReadType() == AbstractFile::FILE_FORMAT_XML_GZIP_BASE64)) { if (pf.getLabelTable()->getHadColorsWhenRead()) { // allow area colors to override label table colors pf.getLabelTable()->assignColors(*areaColorFile); pf.getLabelTable()->addColorsToColorFile(*areaColorFile); if (DebugControl::getDebugOn()) { std::cout << "After GIFTI Label File reading there are " << areaColorFile->getNumberOfColors() << " area colors." << std::endl; } } } paintFile->append(pf, columnDestination2, fcm); paintFile->getLabelTable()->assignColors(*areaColorFile); } catch (FileException& e) { throw FileException(FileUtilities::basename(name), e.whatQString()); } if (paintFileEmpty) { paintFile->clearModified(); } else { paintFile->setModified(); } if (readingSpecFileFlag == false) { displaySettingsPaint->update(); } if (updateSpec) { addToSpecFile(SpecFile::getPaintFileTag(), name); } } /** * Read the paint data file file */ void BrainSet::readPaintFile(const QString& name, const bool append, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexPaintFile); if (append == false) { clearPaintFile(); } const unsigned long modified = paintFile->getModified(); if (paintFile->getNumberOfColumns() == 0) { try { paintFile->readFile(name); if (paintFile->getNumberOfNodes() != getNumberOfNodes()) { throw FileException(FileUtilities::basename(name), numNodesMessage); } if ((paintFile->getFileReadType() == AbstractFile::FILE_FORMAT_XML) || (paintFile->getFileReadType() == AbstractFile::FILE_FORMAT_XML_BASE64) || (paintFile->getFileReadType() == AbstractFile::FILE_FORMAT_XML_GZIP_BASE64)) { if (paintFile->getLabelTable()->getHadColorsWhenRead()) { paintFile->getLabelTable()->assignColors(*areaColorFile); paintFile->getLabelTable()->addColorsToColorFile(*areaColorFile); if (DebugControl::getDebugOn()) { std::cout << "After GIFTI Label File reading there are " << areaColorFile->getNumberOfColors() << " colors." << std::endl; } } } } catch (FileException& e) { clearPaintFile(); throw FileException(FileUtilities::basename(name), e.whatQString()); } } else { // Append to existing PaintFile pf; pf.readFile(name); if (pf.getNumberOfNodes() != getNumberOfNodes()) { throw FileException(FileUtilities::basename(name), numNodesMessage); } try { paintFile->append(pf); if ((pf.getFileReadType() == AbstractFile::FILE_FORMAT_XML) || (pf.getFileReadType() == AbstractFile::FILE_FORMAT_XML_BASE64) || (pf.getFileReadType() == AbstractFile::FILE_FORMAT_XML_GZIP_BASE64)) { if (pf.getLabelTable()->getHadColorsWhenRead()) { pf.getLabelTable()->assignColors(*areaColorFile); pf.getLabelTable()->addColorsToColorFile(*areaColorFile); if (DebugControl::getDebugOn()) { std::cout << "After GIFTI Label File reading there are " << areaColorFile->getNumberOfColors() << " colors." << std::endl; } } } } catch (FileException& e) { throw FileException(FileUtilities::basename(name), e.whatQString()); } } paintFile->getLabelTable()->assignColors(*areaColorFile); paintFile->setModifiedCounter(modified); if (readingSpecFileFlag == false) { displaySettingsPaint->update(); } if (updateSpec) { addToSpecFile(SpecFile::getPaintFileTag(), name); } } /** * Read the study meta data file */ void BrainSet::readStudyMetaDataFile(const QString& name, const bool append, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexStudyMetaDataFile); if (append == false) { clearStudyMetaDataFile(); } const unsigned long modified = studyMetaDataFile->getModified(); if (studyMetaDataFile->empty()) { try { studyMetaDataFile->readFile(name); } catch (FileException& e) { clearStudyMetaDataFile(); throw e; } } else { StudyMetaDataFile smdf; smdf.readFile(name); studyMetaDataFile->append(smdf); } studyMetaDataFile->setModifiedCounter(modified); if (updateSpec) { addToSpecFile(SpecFile::getStudyMetaDataFileTag(), name); } if (readingSpecFileFlag == false) { displaySettingsStudyMetaData->update(); } } /** * Write the study meta data file. */ void BrainSet::writeStudyMetaDataFile(const QString& name) throw (FileException) { loadedFilesSpecFile.studyMetaDataFile.setAllSelections(SpecFile::SPEC_FALSE); studyMetaDataFile->writeFile(name); addToSpecFile(SpecFile::getStudyMetaDataFileTag(), name); } /** * Read the study collection file */ void BrainSet::readStudyCollectionFile(const QString& name, const bool append, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexStudyCollectionFile); if (append == false) { clearStudyCollectionFile(); } const unsigned long modified = studyCollectionFile->getModified(); if (studyCollectionFile->empty()) { try { studyCollectionFile->readFile(name); } catch (FileException& e) { clearStudyCollectionFile(); throw e; } } else { StudyCollectionFile scf; scf.readFile(name); studyCollectionFile->append(scf); } studyCollectionFile->setModifiedCounter(modified); if (updateSpec) { addToSpecFile(SpecFile::getStudyCollectionFileTag(), name); } if (readingSpecFileFlag == false) { /// displaySettingsStudyMetaData->update(); } } /** * Write the study collection file. */ void BrainSet::writeStudyCollectionFile(const QString& name) throw (FileException) { loadedFilesSpecFile.studyCollectionFile.setAllSelections(SpecFile::SPEC_FALSE); studyCollectionFile->writeFile(name); addToSpecFile(SpecFile::getStudyCollectionFileTag(), name); } /** * Read the vocabulary data file */ void BrainSet::readVocabularyFile(const QString& name, const bool append, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexVocabularyFile); if (append == false) { clearVocabularyFile(); } const unsigned long modified = vocabularyFile->getModified(); if (vocabularyFile->empty()) { try { vocabularyFile->readFile(name); } catch (FileException& e) { clearVocabularyFile(); throw e; } } else { VocabularyFile vf; vf.readFile(name); vocabularyFile->append(vf); } vocabularyFile->setModifiedCounter(modified); if (updateSpec) { addToSpecFile(SpecFile::getVocabularyFileTag(), name); } } /** * Write the vocabulary data file. */ void BrainSet::writeVocabularyFile(const QString& name) throw (FileException) { loadedFilesSpecFile.vocabularyFile.setAllSelections(SpecFile::SPEC_FALSE); vocabularyFile->writeFile(name); addToSpecFile(SpecFile::getVocabularyFileTag(), name); } /** * Read the wustl region data file */ void BrainSet::readWustlRegionFile(const QString& name, const bool append, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexWustlRegionFile); if (append == false) { clearWustlRegionFile(); } const unsigned long modified = wustlRegionFile->getModified(); if (wustlRegionFile->getNumberOfTimeCourses() == 0) { try { wustlRegionFile->readFile(name); } catch (FileException& e) { clearWustlRegionFile(); throw e; } } else { WustlRegionFile wrf; wrf.readFile(name); wustlRegionFile->append(wrf); } wustlRegionFile->setModifiedCounter(modified); displaySettingsWustlRegion->update(); if (updateSpec) { addToSpecFile(SpecFile::getWustlRegionFileTag(), name); } } /** * Write the wustl region data file. */ void BrainSet::writeWustlRegionFile(const QString& name) throw (FileException) { loadedFilesSpecFile.wustlRegionFile.setAllSelections(SpecFile::SPEC_FALSE); wustlRegionFile->writeFile(name); addToSpecFile(SpecFile::getWustlRegionFileTag(), name); } /** * Write the Palette data file. */ void BrainSet::writePaletteFile(const QString& name) throw (FileException) { loadedFilesSpecFile.paletteFile.setAllSelections(SpecFile::SPEC_FALSE); paletteFile->writeFile(name); addToSpecFile(SpecFile::getPaletteFileTag(), name); } /** * Read the palette data file file */ void BrainSet::readPaletteFile(const QString& name, const bool append, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexPaletteFile); if (append == false) { clearPaletteFile(); } const unsigned long modified = paletteFile->getModified(); if (paletteFile->getNumberOfPalettes() == 0) { try { paletteFile->readFile(name); } catch (FileException& e) { clearPaletteFile(); throw e; } } else { PaletteFile pf; pf.readFile(name); paletteFile->append(pf); } paletteFile->setModifiedCounter(modified); displaySettingsMetric->update(); displaySettingsSurfaceShape->update(); if (updateSpec) { addToSpecFile(SpecFile::getPaletteFileTag(), name); } } /** * Write the params data file. */ void BrainSet::writeParamsFile(const QString& name) throw (FileException) { loadedFilesSpecFile.paramsFile.setAllSelections(SpecFile::SPEC_FALSE); paramsFile->writeFile(name); addToSpecFile(SpecFile::getParamsFileTag(), name); } /** * Read the params data file file */ void BrainSet::readParamsFile(const QString& name, const bool append, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexParamsFile); if (append == false) { clearParamsFile(); } const unsigned long modified = paramsFile->getModified(); if (paramsFile->empty() == 0) { try { paramsFile->readFile(name); } catch (FileException& e) { clearParamsFile(); throw e; } } else { ParamsFile pf; pf.readFile(name); QString msg; paramsFile->append(pf, msg); if (msg.isEmpty() == false) { throw FileException(name, msg); } } paramsFile->setModifiedCounter(modified); if (updateSpec) { addToSpecFile(SpecFile::getParamsFileTag(), name); } } /** * Write the probabilistic atlas data file. */ void BrainSet::writeProbabilisticAtlasFile(const QString& name) throw (FileException) { loadedFilesSpecFile.atlasFile.setAllSelections(SpecFile::SPEC_FALSE); probabilisticAtlasSurfaceFile->writeFile(name); addToSpecFile(SpecFile::getAtlasFileTag(), name); } /** * Read the prob atlas data file file */ void BrainSet::readProbabilisticAtlasFile(const QString& name, const bool append, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexProbAtlasFile); if (append == false) { clearProbabilisticAtlasFile(); } const unsigned long modified = probabilisticAtlasSurfaceFile->getModified(); if (probabilisticAtlasSurfaceFile->getNumberOfColumns() == 0) { try { probabilisticAtlasSurfaceFile->readFile(name); if (probabilisticAtlasSurfaceFile->getNumberOfNodes() != getNumberOfNodes()) { throw FileException(FileUtilities::basename(name), numNodesMessage); } } catch (FileException& e) { clearProbabilisticAtlasFile(); throw FileException(FileUtilities::basename(name), e.whatQString()); } } else { // Append to existing ProbabilisticAtlasFile paf; paf.readFile(name); if (paf.getNumberOfNodes() != getNumberOfNodes()) { throw FileException(FileUtilities::basename(name), numNodesMessage); } try { probabilisticAtlasSurfaceFile->append(paf); } catch (FileException& e) { throw FileException(FileUtilities::basename(name), e.whatQString()); } } probabilisticAtlasSurfaceFile->setModifiedCounter(modified); displaySettingsProbabilisticAtlasSurface->update(); if (updateSpec) { addToSpecFile(SpecFile::getAtlasFileTag(), name); } } /** * Write the rgb paint data file. */ void BrainSet::writeRgbPaintFile(const QString& name) throw (FileException) { loadedFilesSpecFile.rgbPaintFile.setAllSelections(SpecFile::SPEC_FALSE); rgbPaintFile->writeFile(name); addToSpecFile(SpecFile::getRgbPaintFileTag(), name); } /** * Read the rgb paint data file file */ void BrainSet::readRgbPaintFile(const QString& name, const bool append, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexRgbPaintFile); if (append == false) { clearRgbPaintFile(); } const unsigned long modified = rgbPaintFile->getModified(); if (rgbPaintFile->getNumberOfColumns() == 0) { try { rgbPaintFile->readFile(name); if (rgbPaintFile->getNumberOfNodes() != getNumberOfNodes()) { throw FileException(FileUtilities::basename(name), numNodesMessage); } } catch (FileException& e) { clearRgbPaintFile(); throw FileException(FileUtilities::basename(name), e.whatQString()); } } else { // Append to existing RgbPaintFile rf; rf.readFile(name); if (rf.getNumberOfNodes() != getNumberOfNodes()) { throw FileException(FileUtilities::basename(name), numNodesMessage); } try { rgbPaintFile->append(rf); } catch (FileException& e) { throw FileException(FileUtilities::basename(name), e.whatQString()); } } rgbPaintFile->setModifiedCounter(modified); displaySettingsRgbPaint->update(); if (updateSpec) { addToSpecFile(SpecFile::getRgbPaintFileTag(), name); } } /** * Write the scene data file. */ void BrainSet::writeSceneFile(const QString& name) throw (FileException) { loadedFilesSpecFile.sceneFile.setAllSelections(SpecFile::SPEC_FALSE); sceneFile->writeFile(name); addToSpecFile(SpecFile::getSceneFileTag(), name); } /** * Read the scene data file file */ void BrainSet::readSceneFile(const QString& name, const bool append, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexSceneFile); if (append == false) { clearSceneFile(); } const unsigned long modified = sceneFile->getModified(); if (sceneFile->empty()) { sceneFile->readFile(name); // // Special processing for WebCaret. In SuMS, a spec file and its data files are // stored in a single directory. However, a scene file may still have relative paths // for data files loaded at the time of scene creation so strip the paths from the files // if (webCaretFlag) { sceneFile->removePathsFromAllSpecFileDataFileNames(); } } else { try { SceneFile sf; sf.readFile(name); // // Special processing for WebCaret. In SuMS, a spec file and its data files are // stored in a single directory. However, a scene file may still have relative paths // for data files loaded at the time of scene creation so strip the paths from the files // if (webCaretFlag) { sf.removePathsFromAllSpecFileDataFileNames(); } sceneFile->append(sf); } catch (FileException& e) { clearSceneFile(); throw e; } } sceneFile->setModifiedCounter(modified); displaySettingsScene->update(); if (updateSpec) { addToSpecFile(SpecFile::getSceneFileTag(), name); } } /** * Write the section data file. */ void BrainSet::writeSectionFile(const QString& name) throw (FileException) { loadedFilesSpecFile.sectionFile.setAllSelections(SpecFile::SPEC_FALSE); sectionFile->writeFile(name); addToSpecFile(SpecFile::getSectionFileTag(), name); } /** * Read the section data file file */ void BrainSet::readSectionFile(const QString& name, const bool append, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexSectionFile); if (append == false) { clearSectionFile(); } const unsigned long modified = sectionFile->getModified(); if (sectionFile->getNumberOfColumns() == 0) { try { sectionFile->readFile(name); if (sectionFile->getNumberOfNodes() != getNumberOfNodes()) { throw FileException(FileUtilities::basename(name), numNodesMessage); } } catch (FileException& e) { clearSectionFile(); throw FileException(FileUtilities::basename(name), e.whatQString()); } } else { // Append to existing SectionFile sf; sf.readFile(name); if (sf.getNumberOfNodes() != getNumberOfNodes()) { throw FileException(FileUtilities::basename(name), numNodesMessage); } try { sectionFile->append(sf); } catch (FileException& e) { throw FileException(FileUtilities::basename(name), e.whatQString()); } } sectionFile->setModifiedCounter(modified); if (updateSpec) { addToSpecFile(SpecFile::getSectionFileTag(), name); } displaySettingsSection->update(); } /** * Write the surface shape data file. */ void BrainSet::writeSurfaceShapeFile(const QString& name) throw (FileException) { loadedFilesSpecFile.surfaceShapeFile.setAllSelections(SpecFile::SPEC_FALSE); surfaceShapeFile->writeFile(name); addToSpecFile(SpecFile::getSurfaceShapeFileTag(), name); } /** * read the surface shape data file file (only selected columns). */ void BrainSet::readSurfaceShapeFile(const QString& name, const std::vector& columnDestination, const std::vector& fileBeingReadColumnNames, const AbstractFile::FILE_COMMENT_MODE fcm, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexSurfaceShapeFile); const bool shapeEmpty = surfaceShapeFile->empty(); SurfaceShapeFile ssf; ssf.setNumberOfNodesForSparseNodeIndexFiles(getNumberOfNodes()); ssf.readFile(name); if (ssf.getNumberOfNodes() != getNumberOfNodes()) { throw FileException(FileUtilities::basename(name), numNodesMessage); } try { for (int i = 0; i < ssf.getNumberOfColumns(); i++) { if (i < static_cast(fileBeingReadColumnNames.size())) { ssf.setColumnName(i, fileBeingReadColumnNames[i]); } } std::vector columnDestination2 = columnDestination; surfaceShapeFile->append(ssf, columnDestination2, fcm); } catch (FileException& e) { throw FileException(FileUtilities::basename(name), e.whatQString()); } if (shapeEmpty) { surfaceShapeFile->clearModified(); } else { surfaceShapeFile->setModified(); } if (readingSpecFileFlag == false) { displaySettingsSurfaceShape->update(); } if (updateSpec) { addToSpecFile(SpecFile::getSurfaceShapeFileTag(), name); } } /** * Read the surface shape data file file */ void BrainSet::readSurfaceShapeFile(const QString& name, const bool append, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexSurfaceShapeFile); if (append == false) { clearSurfaceShapeFile(); } const unsigned long modified = surfaceShapeFile->getModified(); if (surfaceShapeFile->getNumberOfColumns() == 0) { try { surfaceShapeFile->readFile(name); if (surfaceShapeFile->getNumberOfNodes() != getNumberOfNodes()) { throw FileException(FileUtilities::basename(name), numNodesMessage); } } catch (FileException& e) { clearSurfaceShapeFile(); throw FileException(FileUtilities::basename(name), e.whatQString()); } } else { // Append to existing SurfaceShapeFile ssf; ssf.readFile(name); if (ssf.getNumberOfNodes() != getNumberOfNodes()) { throw FileException(FileUtilities::basename(name), numNodesMessage); } try { surfaceShapeFile->append(ssf); } catch (FileException& e) { throw FileException(FileUtilities::basename(name), e.whatQString()); } } surfaceShapeFile->setModifiedCounter(modified); if (readingSpecFileFlag == false) { displaySettingsSurfaceShape->update(); } if (updateSpec) { addToSpecFile(SpecFile::getSurfaceShapeFileTag(), name); } } /** * Write the vector data file. */ void BrainSet::writeVectorFile(VectorFile* vf, const QString& name) throw (FileException) { loadedFilesSpecFile.vectorFile.clearSelectionStatus(vf->getFileName()); vf->writeFile(name); addToSpecFile(SpecFile::getVectorFileTag(), name); } /** * Read the vector data file file */ void BrainSet::readVectorFile(const QString& name, const bool append, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexVectorFile); if (append == false) { clearVectorFiles(); } VectorFile* vf = NULL; try { vf = new VectorFile(); vf->readFile(name); addVectorFile(vf); } catch (FileException& e) { if (vf != NULL) { delete vf; } throw FileException(FileUtilities::basename(name), e.whatQString()); } displaySettingsVectors->update(); if (updateSpec) { addToSpecFile(SpecFile::getVectorFileTag(), name); } clearAllDisplayLists(); } /** * Write the topography data file. */ void BrainSet::writeTopographyFile(const QString& name) throw (FileException) { loadedFilesSpecFile.topographyFile.setAllSelections(SpecFile::SPEC_FALSE); topographyFile->writeFile(name); addToSpecFile(SpecFile::getTopographyFileTag(), name); } /** *BrainSet::read the topography data file file */ void BrainSet::readTopographyFile(const QString& name, const bool append, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexTopographyFile); if (append == false) { clearTopographyFile(); } const unsigned long modified = topographyFile->getModified(); if (topographyFile->getNumberOfColumns() == 0) { try { topographyFile->setNumberOfNodesVersion0File(getNumberOfNodes()); topographyFile->readFile(name); if (topographyFile->getNumberOfNodes() != getNumberOfNodes()) { throw FileException(FileUtilities::basename(name), numNodesMessage); } } catch (FileException& e) { clearTopographyFile(); throw FileException(FileUtilities::basename(name), e.whatQString()); } } else { // Append to existing TopographyFile tf; tf.setNumberOfNodesVersion0File(getNumberOfNodes()); tf.readFile(name); if (tf.getNumberOfNodes() != getNumberOfNodes()) { throw FileException(FileUtilities::basename(name), numNodesMessage); } try { topographyFile->append(tf); } catch (FileException& e) { throw FileException(FileUtilities::basename(name), e.whatQString()); } } topographyFile->setModifiedCounter(modified); displaySettingsTopography->update(); if (updateSpec) { addToSpecFile(SpecFile::getTopographyFileTag(), name); } } /** * Write the transformation matrix data file. */ void BrainSet::writeTransformationMatrixFile(const QString& name) throw (FileException) { loadedFilesSpecFile.transformationMatrixFile.setAllSelections(SpecFile::SPEC_FALSE); transformationMatrixFile->writeFile(name); addToSpecFile(SpecFile::getTransformationMatrixFileTag(), name); } /** * read the transformation matrix file */ void BrainSet::readTransformationMatrixFile(const QString& name, const bool append, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexTransformationMatrixFile); if (append == false) { clearTransformationMatrixFile(); } const unsigned long modified = transformationMatrixFile->getModified(); if (transformationMatrixFile->getNumberOfMatrices() == 0) { try { transformationMatrixFile->readFile(name); } catch (FileException& e) { clearTransformationMatrixFile(); throw FileException(FileUtilities::basename(name), e.whatQString()); } } else { // Append to existing TransformationMatrixFile tf; tf.readFile(name); transformationMatrixFile->append(tf); } transformationMatrixFile->setModifiedCounter(modified); if (updateSpec) { addToSpecFile(SpecFile::getTransformationMatrixFileTag(), name); } } /** * read the transformation matrix data file */ void BrainSet::readTransformationDataFile(const QString& name, const bool append, const bool updateSpec) throw (FileException) { QMutexLocker locker(&mutexTransformationDataFile); if (append == false) { transformationDataFiles.clear(); } QString errorMessage; AbstractFile* ab = AbstractFile::readAnySubClassDataFile(name, false, errorMessage); if (ab == NULL) { throw FileException(FileUtilities::basename(name), errorMessage); } transformationDataFiles.push_back(ab); if (updateSpec) { addToSpecFile(SpecFile::getTransformationDataFileTag(), name); } } /** * Write the topology data file. */ void BrainSet::writeTopologyFile(const QString& name, const TopologyFile::TOPOLOGY_TYPES tt, TopologyFile* tf) throw (FileException) { switch(tf->getTopologyType()) { case TopologyFile::TOPOLOGY_TYPE_CLOSED: loadedFilesSpecFile.closedTopoFile.clearSelectionStatus(tf->getFileName()); break; case TopologyFile::TOPOLOGY_TYPE_OPEN: loadedFilesSpecFile.openTopoFile.clearSelectionStatus(tf->getFileName()); break; case TopologyFile::TOPOLOGY_TYPE_CUT: loadedFilesSpecFile.cutTopoFile.clearSelectionStatus(tf->getFileName()); break; case TopologyFile::TOPOLOGY_TYPE_LOBAR_CUT: loadedFilesSpecFile.lobarCutTopoFile.clearSelectionStatus(tf->getFileName()); break; case TopologyFile::TOPOLOGY_TYPE_UNKNOWN: case TopologyFile::TOPOLOGY_TYPE_UNSPECIFIED: loadedFilesSpecFile.unknownTopoFile.clearSelectionStatus(tf->getFileName()); break; } tf->setTopologyType(tt); QString tag; switch(tt) { case TopologyFile::TOPOLOGY_TYPE_CLOSED: tag = SpecFile::getClosedTopoFileTag(); break; case TopologyFile::TOPOLOGY_TYPE_OPEN: tag = SpecFile::getOpenTopoFileTag(); break; case TopologyFile::TOPOLOGY_TYPE_CUT: tag = SpecFile::getCutTopoFileTag(); break; case TopologyFile::TOPOLOGY_TYPE_LOBAR_CUT: tag = SpecFile::getLobarCutTopoFileTag(); break; case TopologyFile::TOPOLOGY_TYPE_UNKNOWN: case TopologyFile::TOPOLOGY_TYPE_UNSPECIFIED: tag = SpecFile::getUnknownTopoFileMatchTag(); break; } tf->writeFile(name); addToSpecFile(tag, name); } /** * Read the topology data file file. When reading spec file, new topology files are placed at * the end of the vector that holds them. When not reading a spec file, the user is opening * a topology file so make it the active one. */ void BrainSet::readTopologyFile(const QString& name, const TopologyFile::TOPOLOGY_TYPES ttin, const bool append, const bool updateSpec) throw (FileException) { TopologyFile::TOPOLOGY_TYPES tt = ttin; if ((tt == TopologyFile::TOPOLOGY_TYPE_UNSPECIFIED) || (tt == TopologyFile::TOPOLOGY_TYPE_UNKNOWN)) { TopologyFile tf; tf.readFileMetaDataOnly(name); const QString typeTag = tf.getHeaderTag(AbstractFile::headerTagPerimeterID); if (typeTag.isEmpty() == false) { tt = TopologyFile::getTopologyTypeFromPerimeterID(typeTag); } } TopologyFile* topoJustRead = new TopologyFile; try { topoJustRead->readFile(name); } catch (FileException& e) { delete topoJustRead; throw FileException(FileUtilities::basename(name), e.whatQString()); } QString tag; // // This keeps track of any topology files that are being deleted (because append == false). // This allows the new topology file to be applied to coordinate files. // std::vector replacedTopologyFiles; // // The remainder of this routine must not be run by more than one thread // QMutexLocker locker(&mutexReadTopologyFile); // // If not appending, remove any topology files that are the same type as // the topology file being read. The newest file is always placed in the // first spot. // if (append == false) { std::vector tempFiles; tempFiles.push_back(topoJustRead); const int numTopo = getNumberOfTopologyFiles(); for (int i = 0; i < numTopo; i++) { TopologyFile* tf = getTopologyFile(i); if (tt == tf->getTopologyType()) { replacedTopologyFiles.push_back(tf); delete tf; } else { tempFiles.push_back(tf); } } topologyFiles = tempFiles; } else { topologyFiles.insert(topologyFiles.begin(), topoJustRead); } // // Override topology type in the TopologyFile just read. // if (topoJustRead->getTopologyType() != tt) { topoJustRead->setTopologyType(tt); } switch(tt) { case TopologyFile::TOPOLOGY_TYPE_CLOSED: tag = SpecFile::getClosedTopoFileTag(); break; case TopologyFile::TOPOLOGY_TYPE_OPEN: tag = SpecFile::getOpenTopoFileTag(); break; case TopologyFile::TOPOLOGY_TYPE_CUT: tag = SpecFile::getCutTopoFileTag(); break; case TopologyFile::TOPOLOGY_TYPE_LOBAR_CUT: tag = SpecFile::getLobarCutTopoFileTag(); break; case TopologyFile::TOPOLOGY_TYPE_UNKNOWN: case TopologyFile::TOPOLOGY_TYPE_UNSPECIFIED: default: tag = SpecFile::getUnknownTopoFileMatchTag(); break; } if (updateSpec) { addToSpecFile(tag, name); } // // If any surface was using a deleted topology file, replace it with // the topology file that was just read. // if (replacedTopologyFiles.size() > 0) { for (int i = 0; i < getNumberOfBrainModels(); i++) { BrainModel* bm = getBrainModel(i); if (bm->getModelType() == BrainModel::BRAIN_MODEL_SURFACE) { BrainModelSurface* bms = dynamic_cast(bm); TopologyFile* stf = bms->getTopologyFile(); if (std::find(replacedTopologyFiles.begin(), replacedTopologyFiles.end(), stf) != replacedTopologyFiles.end()) { bms->setTopologyFile(topoJustRead); } } } } setSelectedTopologyFiles(); } /** * Add a topology file */ void BrainSet::addTopologyFile(TopologyFile* tf) { topologyFiles.push_back(tf); } /** * delete topology file. */ void BrainSet::deleteTopologyFile(TopologyFile* tf) { if (tf == NULL) { return; } loadedFilesSpecFile.closedTopoFile.clearSelectionStatus(tf->getFileName()); loadedFilesSpecFile.openTopoFile.clearSelectionStatus(tf->getFileName()); loadedFilesSpecFile.cutTopoFile.clearSelectionStatus(tf->getFileName()); loadedFilesSpecFile.lobarCutTopoFile.clearSelectionStatus(tf->getFileName()); loadedFilesSpecFile.unknownTopoFile.clearSelectionStatus(tf->getFileName()); int topoIndex = -1; std::vector savedTopologyFiles; for (int i = 0; i < getNumberOfTopologyFiles(); i++) { TopologyFile* topology = getTopologyFile(i); if (topology != tf) { savedTopologyFiles.push_back(topology); } else { topoIndex = i; } } topologyFiles = savedTopologyFiles; delete tf; setSelectedTopologyFiles(); // // If delete topology was used by a surface, give the surface a new topo file // if ((topoIndex < 0) || (topoIndex >= getNumberOfTopologyFiles())) { topoIndex = 0; } TopologyFile* newTF = NULL; if ((topoIndex >= 0) && (topoIndex < getNumberOfTopologyFiles())) { newTF = getTopologyFile(topoIndex); } for (int i = 0; i < getNumberOfBrainModels(); i++) { BrainModelSurface* bms = getBrainModelSurface(i); if (bms != NULL) { if (bms->getTopologyFile() == tf) { bms->setTopologyFile(newTF); } } } clearAllDisplayLists(); } /** * Read in surface file group. */ bool BrainSet::readSurfaceFileGroup(const SpecFile::Entry& surfaceFile, const BrainModelSurface::SURFACE_TYPES surfaceType, std::vector& errorMessages, int& progressFileCounter, QProgressDialog* progressDialog) { for (unsigned i = 0; i < surfaceFile.files.size(); i++) { if (surfaceFile.files[i].selected) { if (updateFileReadProgressDialog(surfaceFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readSurfaceFile(surfaceFile.files[i].filename, surfaceType, true, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } return false; } /** * Read some coordinate files. Returns true if file reading was aborted. */ bool BrainSet::readCoordinateFileGroup(const SpecFile::Entry& coordFile, const BrainModelSurface::SURFACE_TYPES surfaceType, std::vector& errorMessages, int& progressFileCounter, QProgressDialog* progressDialog) { for (unsigned i = 0; i < coordFile.files.size(); i++) { if (coordFile.files[i].selected) { if (updateFileReadProgressDialog(coordFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readCoordinateFile(coordFile.files[i].filename, surfaceType, true, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } return false; } /** * Read some border files. Returns true if file reading was aborted. */ bool BrainSet::readBorderFiles(const SpecFile::Entry& borderFilesToRead, const BrainModelSurface::SURFACE_TYPES bt, std::vector& errorMessages, int& progressFileCounter, QProgressDialog* progressDialog) { for (unsigned i = 0; i < borderFilesToRead.files.size(); i++) { if (borderFilesToRead.files[i].selected) { if (updateFileReadProgressDialog(borderFilesToRead.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readBorderFile(borderFilesToRead.files[i].filename, bt, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } return false; } /** * read the spec file (returns true if reading was aborted by user). */ bool BrainSet::readSpecFile(const SpecFile& specFileIn, const QString& specFileNameIn, QString& errorMessagesOut) { return readSpecFile(SPEC_FILE_READ_MODE_NORMAL, specFileIn, specFileNameIn, errorMessagesOut, NULL, NULL); } /** * Read the BrainSet data files. Any error message will be placed * into "errorMessageOut". If "errorMessageOut" is empty, then there * were no errors reading the spec file's data files. * * Returns "true" if the user aborted loading files with the progress dialog. */ bool BrainSet::readSpecFile(const SPEC_FILE_READ_MODE specReadMode, const SpecFile& specFileIn, const QString& specFileNameIn, QString& errorMessageOut, const TransformationMatrix* specTransformationMatrixIn, QProgressDialog* progressDialog) { errorMessageOut = ""; std::vector msg; const bool b = readSpecFile(specReadMode, specFileIn, specFileNameIn, msg, specTransformationMatrixIn, progressDialog); if (msg.empty() == false) { errorMessageOut = StringUtilities::combine(msg, "\n"); } return b; } /** * Read the BrainSet data files. Any error message will be placed * into "errorMessages". The size of errorMessages will correspond to * the number files that failed to read correctly. If the size of * errorMessages is 0, no file reading errors were encountered. * * Returns "true" if the user aborted loading files with the progress dialog. */ bool BrainSet::readSpecFile(const SPEC_FILE_READ_MODE specReadMode, const SpecFile& specFileIn, const QString& specFileNameIn, std::vector& errorMessages, const TransformationMatrix* specTransformationMatrixIn, QProgressDialog* progressDialog) { if (getPreferencesFile()->getNumberOfFileReadingThreads() > 1) { return readSpecFileMultiThreaded(specReadMode, specFileIn, specFileNameIn, errorMessages, specTransformationMatrixIn, progressDialog); } specFileTimeOfLoading = QDateTime::currentDateTime(); readingSpecFileFlag = true; switch (specReadMode) { case SPEC_FILE_READ_MODE_NORMAL: // // clear out "this" brain set // reset(); break; case SPEC_FILE_READ_MODE_APPEND: break; } if (specTransformationMatrixIn != NULL) { specDataFileTransformationMatrix = *specTransformationMatrixIn; } errorMessages.clear(); int progressFileCounter = 0; switch (specReadMode) { case SPEC_FILE_READ_MODE_NORMAL: // // Copy spec file passed and clear all selections in BrainSet::specFile // loadedFilesSpecFile = specFileIn; loadedFilesSpecFile.setAllFileSelections(SpecFile::SPEC_FALSE); //loadedFilesSpecFile.setFileName(specFileNameIn); loadedFilesSpecFile.setCurrentDirectoryToSpecFileDirectory(); specFileName = specFileNameIn; structure = specFileIn.getStructure(); /* hemisphere = Hemisphere::HEMISPHERE_UNKNOWN; if (specFileIn.getStructure() == "right") { hemisphere = BrainModelSurface::HEMISPHERE_RIGHT; } else if (specFileIn.getStructure() == "left") { hemisphere = BrainModelSurface::HEMISPHERE_LEFT; } else if (specFileIn.getStructure() == "both") { hemisphere = BrainModelSurface::HEMISPHERE_BOTH; } setStructure(hemisphere); */ setSpecies(loadedFilesSpecFile.getSpecies()); setSubject(loadedFilesSpecFile.getSubject()); stereotaxicSpace = loadedFilesSpecFile.getSpace(); resetDataFiles(false, false); break; case SPEC_FILE_READ_MODE_APPEND: break; } const int numTopoFilesBeforeLoading = getNumberOfTopologyFiles(); // // Note about reading topology files. "readTopologyFile()" always places the newest topology // file at the beginning of its storage in "topologyFiles". So, when we read the topology // files from the spec file, read them starting with the oldest unknown to the newest // closed topology file (the spec file sorts each file type by date). // // // Read the unknown topology files // for (int j = (specFileIn.unknownTopoFile.files.size() - 1); j >= 0; j--) { if (specFileIn.unknownTopoFile.files[j].selected) { if (updateFileReadProgressDialog(specFileIn.unknownTopoFile.files[j].filename, progressFileCounter, progressDialog)) { return true; } try { readTopologyFile(specFileIn.unknownTopoFile.files[j].filename, TopologyFile::TOPOLOGY_TYPE_UNKNOWN, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read the lobar cut topology files // for (int j = (specFileIn.lobarCutTopoFile.files.size() - 1); j >= 0; j--) { if (specFileIn.lobarCutTopoFile.files[j].selected) { if (updateFileReadProgressDialog(specFileIn.lobarCutTopoFile.files[j].filename, progressFileCounter, progressDialog)) { return true; } try { readTopologyFile(specFileIn.lobarCutTopoFile.files[j].filename, TopologyFile::TOPOLOGY_TYPE_LOBAR_CUT, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read the cut topology files // for (int j = (specFileIn.cutTopoFile.files.size() - 1); j >= 0; j--) { if (specFileIn.cutTopoFile.files[j].selected) { if (updateFileReadProgressDialog(specFileIn.cutTopoFile.files[j].filename, progressFileCounter, progressDialog)) { return true; } try { readTopologyFile(specFileIn.cutTopoFile.files[j].filename, TopologyFile::TOPOLOGY_TYPE_CUT, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read the open topology files // for (int j = (specFileIn.openTopoFile.files.size() - 1); j >= 0; j--) { if (specFileIn.openTopoFile.files[j].selected) { if (updateFileReadProgressDialog(specFileIn.openTopoFile.files[j].filename, progressFileCounter, progressDialog)) { return true; } try { readTopologyFile(specFileIn.openTopoFile.files[j].filename, TopologyFile::TOPOLOGY_TYPE_OPEN, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read the closed topology files // for (int j = (specFileIn.closedTopoFile.files.size() - 1); j >= 0; j--) { if (specFileIn.closedTopoFile.files[j].selected) { if (updateFileReadProgressDialog(specFileIn.closedTopoFile.files[j].filename, progressFileCounter, progressDialog)) { return true; } try { readTopologyFile(specFileIn.closedTopoFile.files[j].filename, TopologyFile::TOPOLOGY_TYPE_CLOSED, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } setSelectedTopologyFiles(); // // Read in the raw coordinate files // if (readCoordinateFileGroup(specFileIn.rawCoordFile, BrainModelSurface::SURFACE_TYPE_RAW, errorMessages, progressFileCounter, progressDialog)) return true; // // Read in the fiducial coordinate files // if (readCoordinateFileGroup(specFileIn.fiducialCoordFile, BrainModelSurface::SURFACE_TYPE_FIDUCIAL, errorMessages, progressFileCounter, progressDialog)) return true; // // Read in the inflated coordinate files // if (readCoordinateFileGroup(specFileIn.inflatedCoordFile, BrainModelSurface::SURFACE_TYPE_INFLATED, errorMessages, progressFileCounter, progressDialog)) return true; // // Read in the very inflated coordinate files // if (readCoordinateFileGroup(specFileIn.veryInflatedCoordFile, BrainModelSurface::SURFACE_TYPE_VERY_INFLATED, errorMessages, progressFileCounter, progressDialog)) return true; // // Read in the spherical coordinate files // if (readCoordinateFileGroup(specFileIn.sphericalCoordFile, BrainModelSurface::SURFACE_TYPE_SPHERICAL, errorMessages, progressFileCounter, progressDialog)) return true; // // Read in the ellipsoid coordinate files // if (readCoordinateFileGroup(specFileIn.ellipsoidCoordFile, BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL, errorMessages, progressFileCounter, progressDialog)) return true; // // Read in the compressed medial wall coordinate files // if (readCoordinateFileGroup(specFileIn.compressedCoordFile, BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL, errorMessages, progressFileCounter, progressDialog)) return true; // // // Read in the flat coordinate files // if (readCoordinateFileGroup(specFileIn.flatCoordFile, BrainModelSurface::SURFACE_TYPE_FLAT, errorMessages, progressFileCounter, progressDialog)) return true; // // Read in the lobar flat coordinate files // if (readCoordinateFileGroup(specFileIn.lobarFlatCoordFile, BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR, errorMessages, progressFileCounter, progressDialog)) return true; // // Read in the hull coordinate files // if (readCoordinateFileGroup(specFileIn.hullCoordFile, BrainModelSurface::SURFACE_TYPE_HULL, errorMessages, progressFileCounter, progressDialog)) return true; // // Read in the unknown coordinate files // if (readCoordinateFileGroup(specFileIn.unknownCoordFile, BrainModelSurface::SURFACE_TYPE_UNKNOWN, errorMessages, progressFileCounter, progressDialog)) return true; // // Read in the raw coordinate files // if (readSurfaceFileGroup(specFileIn.rawSurfaceFile, BrainModelSurface::SURFACE_TYPE_RAW, errorMessages, progressFileCounter, progressDialog)) return true; // // Read in the fiducial coordinate files // if (readSurfaceFileGroup(specFileIn.fiducialSurfaceFile, BrainModelSurface::SURFACE_TYPE_FIDUCIAL, errorMessages, progressFileCounter, progressDialog)) return true; // // Read in the inflated coordinate files // if (readSurfaceFileGroup(specFileIn.inflatedSurfaceFile, BrainModelSurface::SURFACE_TYPE_INFLATED, errorMessages, progressFileCounter, progressDialog)) return true; // // Read in the very inflated coordinate files // if (readSurfaceFileGroup(specFileIn.veryInflatedSurfaceFile, BrainModelSurface::SURFACE_TYPE_VERY_INFLATED, errorMessages, progressFileCounter, progressDialog)) return true; // // Read in the spherical coordinate files // if (readSurfaceFileGroup(specFileIn.sphericalSurfaceFile, BrainModelSurface::SURFACE_TYPE_SPHERICAL, errorMessages, progressFileCounter, progressDialog)) return true; // // Read in the ellipsoid coordinate files // if (readSurfaceFileGroup(specFileIn.ellipsoidSurfaceFile, BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL, errorMessages, progressFileCounter, progressDialog)) return true; // // Read in the compressed medial wall coordinate files // if (readSurfaceFileGroup(specFileIn.compressedSurfaceFile, BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL, errorMessages, progressFileCounter, progressDialog)) return true; // // // Read in the flat coordinate files // if (readSurfaceFileGroup(specFileIn.flatSurfaceFile, BrainModelSurface::SURFACE_TYPE_FLAT, errorMessages, progressFileCounter, progressDialog)) return true; // // Read in the lobar flat coordinate files // if (readSurfaceFileGroup(specFileIn.lobarFlatSurfaceFile, BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR, errorMessages, progressFileCounter, progressDialog)) return true; // // Read in the hull coordinate files // if (readSurfaceFileGroup(specFileIn.hullSurfaceFile, BrainModelSurface::SURFACE_TYPE_HULL, errorMessages, progressFileCounter, progressDialog)) return true; // // Read in the unknown coordinate files // if (readSurfaceFileGroup(specFileIn.unknownSurfaceFile, BrainModelSurface::SURFACE_TYPE_UNKNOWN, errorMessages, progressFileCounter, progressDialog)) return true; // // Read in the anatomy volume files // for (unsigned int i = 0; i < specFileIn.volumeAnatomyFile.files.size(); i++) { if (specFileIn.volumeAnatomyFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.volumeAnatomyFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readVolumeFile(specFileIn.volumeAnatomyFile.files[i].filename, VolumeFile::VOLUME_TYPE_ANATOMY, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read in the functional volume files // for (unsigned int i = 0; i < specFileIn.volumeFunctionalFile.files.size(); i++) { if (specFileIn.volumeFunctionalFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.volumeFunctionalFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readVolumeFile(specFileIn.volumeFunctionalFile.files[i].filename, VolumeFile::VOLUME_TYPE_FUNCTIONAL, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read in the paint volume files // for (unsigned int i = 0; i < specFileIn.volumePaintFile.files.size(); i++) { if (specFileIn.volumePaintFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.volumePaintFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readVolumeFile(specFileIn.volumePaintFile.files[i].filename, VolumeFile::VOLUME_TYPE_PAINT, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read in the prob atlas volume files // for (unsigned int i = 0; i < specFileIn.volumeProbAtlasFile.files.size(); i++) { if (specFileIn.volumeProbAtlasFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.volumeProbAtlasFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readVolumeFile(specFileIn.volumeProbAtlasFile.files[i].filename, VolumeFile::VOLUME_TYPE_PROB_ATLAS, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } if (specFileIn.volumeProbAtlasFile.files.size() > 1) { synchronizeProbAtlasVolumeRegionNames(); } // // Read in the rgb paint volume files // for (unsigned int i = 0; i < specFileIn.volumeRgbFile.files.size(); i++) { if (specFileIn.volumeRgbFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.volumeRgbFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readVolumeFile(specFileIn.volumeRgbFile.files[i].filename, VolumeFile::VOLUME_TYPE_RGB, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read in the segmentation volume files // for (unsigned int i = 0; i < specFileIn.volumeSegmentationFile.files.size(); i++) { if (specFileIn.volumeSegmentationFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.volumeSegmentationFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readVolumeFile(specFileIn.volumeSegmentationFile.files[i].filename, VolumeFile::VOLUME_TYPE_SEGMENTATION, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read in the vector volume files // for (unsigned int i = 0; i < specFileIn.volumeVectorFile.files.size(); i++) { if (specFileIn.volumeVectorFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.volumeVectorFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readVolumeFile(specFileIn.volumeVectorFile.files[i].filename, VolumeFile::VOLUME_TYPE_VECTOR, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read in the paint files // for (unsigned int i = 0; i < specFileIn.paintFile.files.size(); i++) { if (specFileIn.paintFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.paintFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readPaintFile(specFileIn.paintFile.files[i].filename, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read in the probabilistic atlas files // for (unsigned int i = 0; i < specFileIn.atlasFile.files.size(); i++) { if (specFileIn.atlasFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.atlasFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readProbabilisticAtlasFile(specFileIn.atlasFile.files[i].filename, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read in the area color file // for (unsigned int i = 0; i < specFileIn.areaColorFile.files.size(); i++) { if (specFileIn.areaColorFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.areaColorFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readAreaColorFile(specFileIn.areaColorFile.files[i].filename, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read the rgb paint files // for (unsigned int i = 0; i < specFileIn.rgbPaintFile.files.size(); i++) { if (specFileIn.rgbPaintFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.rgbPaintFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readRgbPaintFile(specFileIn.rgbPaintFile.files[i].filename, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read the study collection files // for (unsigned int i = 0; i < specFileIn.studyCollectionFile.files.size(); i++) { if (specFileIn.studyCollectionFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.studyCollectionFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readStudyCollectionFile(specFileIn.studyCollectionFile.files[i].filename, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read the study meta data files // for (unsigned int i = 0; i < specFileIn.studyMetaDataFile.files.size(); i++) { if (specFileIn.studyMetaDataFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.studyMetaDataFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readStudyMetaDataFile(specFileIn.studyMetaDataFile.files[i].filename, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read the vocabulary files // for (unsigned int i = 0; i < specFileIn.vocabularyFile.files.size(); i++) { if (specFileIn.vocabularyFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.vocabularyFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readVocabularyFile(specFileIn.vocabularyFile.files[i].filename, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read the wustl region files // for (unsigned int i = 0; i < specFileIn.wustlRegionFile.files.size(); i++) { if (specFileIn.wustlRegionFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.wustlRegionFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readWustlRegionFile(specFileIn.wustlRegionFile.files[i].filename, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read the areal estimation files // for (unsigned int i = 0; i < specFileIn.arealEstimationFile.files.size(); i++) { if (specFileIn.arealEstimationFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.arealEstimationFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readArealEstimationFile(specFileIn.arealEstimationFile.files[i].filename, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read the topography files // for (unsigned int i = 0; i < specFileIn.topographyFile.files.size(); i++) { if (specFileIn.topographyFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.topographyFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readTopographyFile(specFileIn.topographyFile.files[i].filename, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read the geodesic files // for (unsigned int i = 0; i < specFileIn.geodesicDistanceFile.files.size(); i++) { if (specFileIn.geodesicDistanceFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.geodesicDistanceFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readGeodesicDistanceFile(specFileIn.geodesicDistanceFile.files[i].filename, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read the lat/lon files // for (unsigned int i = 0; i < specFileIn.latLonFile.files.size(); i++) { if (specFileIn.latLonFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.latLonFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readLatLonFile(specFileIn.latLonFile.files[i].filename, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read the params files // for (unsigned int i = 0; i < specFileIn.paramsFile.files.size(); i++) { if (specFileIn.paramsFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.paramsFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readParamsFile(specFileIn.paramsFile.files[i].filename, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read the scene files // for (unsigned int i = 0; i < specFileIn.sceneFile.files.size(); i++) { if (specFileIn.sceneFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.sceneFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readSceneFile(specFileIn.sceneFile.files[i].filename, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read the section files // for (unsigned int i = 0; i < specFileIn.sectionFile.files.size(); i++) { if (specFileIn.sectionFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.sectionFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readSectionFile(specFileIn.sectionFile.files[i].filename, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read the deformation field files // for (unsigned int i = 0; i < specFileIn.deformationFieldFile.files.size(); i++) { if (specFileIn.deformationFieldFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.deformationFieldFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readDeformationFieldFile(specFileIn.deformationFieldFile.files[i].filename, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read the volume border files // for (unsigned int i = 0; i < specFileIn.volumeBorderFile.files.size(); i++) { if (specFileIn.volumeBorderFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.volumeBorderFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readVolumeBorderFile(specFileIn.volumeBorderFile.files[i].filename, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read the metric files // for (unsigned int i = 0; i < specFileIn.metricFile.files.size(); i++) { if (specFileIn.metricFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.metricFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readMetricFile(specFileIn.metricFile.files[i].filename, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read the image files // for (unsigned int i = 0; i < specFileIn.imageFile.files.size(); i++) { if (specFileIn.imageFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.imageFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readImageFile(specFileIn.imageFile.files[i].filename, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read the model files // for (unsigned int i = 0; i < specFileIn.vtkModelFile.files.size(); i++) { if (specFileIn.vtkModelFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.vtkModelFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readVtkModelFile(specFileIn.vtkModelFile.files[i].filename, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read the palette file // bool firstSelectedPaletteFile = true; for (unsigned int i = 0; i < specFileIn.paletteFile.files.size(); i++) { if (specFileIn.paletteFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.paletteFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { if (firstSelectedPaletteFile) { clearPaletteFile(); } firstSelectedPaletteFile = false; readPaletteFile(specFileIn.paletteFile.files[i].filename, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } switch (specReadMode) { case SPEC_FILE_READ_MODE_NORMAL: paletteFile->addDefaultPalettes(); paletteFile->clearModified(); break; case SPEC_FILE_READ_MODE_APPEND: break; } // // Read the surface shape files // for (unsigned int i = 0; i < specFileIn.surfaceShapeFile.files.size(); i++) { if (specFileIn.surfaceShapeFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.surfaceShapeFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readSurfaceShapeFile(specFileIn.surfaceShapeFile.files[i].filename, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read the vector files // for (unsigned int i = 0; i < specFileIn.vectorFile.files.size(); i++) { if (specFileIn.vectorFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.vectorFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readVectorFile(specFileIn.vectorFile.files[i].filename, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read in the border color file // for (unsigned int i = 0; i < specFileIn.borderColorFile.files.size(); i++) { if (specFileIn.borderColorFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.borderColorFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readBorderColorFile(specFileIn.borderColorFile.files[i].filename, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read in the raw borders // if (readBorderFiles(specFileIn.rawBorderFile, BrainModelSurface::SURFACE_TYPE_RAW, errorMessages, progressFileCounter, progressDialog)) return true; // // Read in the fiducial borders // if (readBorderFiles(specFileIn.fiducialBorderFile, BrainModelSurface::SURFACE_TYPE_FIDUCIAL, errorMessages, progressFileCounter, progressDialog)) return true; // // Read in the inflated borders // if (readBorderFiles(specFileIn.inflatedBorderFile, BrainModelSurface::SURFACE_TYPE_INFLATED, errorMessages, progressFileCounter, progressDialog)) return true; // // Read in the very inflated borders // if (readBorderFiles(specFileIn.veryInflatedBorderFile, BrainModelSurface::SURFACE_TYPE_VERY_INFLATED, errorMessages, progressFileCounter, progressDialog)) return true; // // Read in the spherical borders // if (readBorderFiles(specFileIn.sphericalBorderFile, BrainModelSurface::SURFACE_TYPE_SPHERICAL, errorMessages, progressFileCounter, progressDialog)) return true; // // Read in the ellipsoid borders // if (readBorderFiles(specFileIn.ellipsoidBorderFile, BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL, errorMessages, progressFileCounter, progressDialog)) return true; // // Read in the compressed medial wall borders // if (readBorderFiles(specFileIn.compressedBorderFile, BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL, errorMessages, progressFileCounter, progressDialog)) return true; // // Read in the flat borders // if (readBorderFiles(specFileIn.flatBorderFile, BrainModelSurface::SURFACE_TYPE_FLAT, errorMessages, progressFileCounter, progressDialog)) return true; // // Read in the lobar flat borders // if (readBorderFiles(specFileIn.lobarFlatBorderFile, BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR, errorMessages, progressFileCounter, progressDialog)) return true; // // Read in the hull borders // if (readBorderFiles(specFileIn.hullBorderFile, BrainModelSurface::SURFACE_TYPE_HULL, errorMessages, progressFileCounter, progressDialog)) return true; // // Read in the unknown borders // if (readBorderFiles(specFileIn.unknownBorderFile, BrainModelSurface::SURFACE_TYPE_UNKNOWN, errorMessages, progressFileCounter, progressDialog)) return true; // // Read the border projection files // for (unsigned int i = 0; i < specFileIn.borderProjectionFile.files.size(); i++) { if (specFileIn.borderProjectionFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.borderProjectionFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readBorderProjectionFile(specFileIn.borderProjectionFile.files[i].filename, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read in the cell color file // for (unsigned int i = 0; i < specFileIn.cellColorFile.files.size(); i++) { if (specFileIn.cellColorFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.cellColorFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readCellColorFile(specFileIn.cellColorFile.files[i].filename, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read the fiducial cell file // for (unsigned int i = 0; i < specFileIn.cellFile.files.size(); i++) { if (specFileIn.cellFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.cellFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readCellFile(specFileIn.cellFile.files[i].filename, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read the volume cell file // for (unsigned int i = 0; i < specFileIn.volumeCellFile.files.size(); i++) { if (specFileIn.volumeCellFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.volumeCellFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readVolumeCellFile(specFileIn.volumeCellFile.files[i].filename, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read the cell projection file // for (unsigned int i = 0; i < specFileIn.cellProjectionFile.files.size(); i++) { if (specFileIn.cellProjectionFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.cellProjectionFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readCellProjectionFile(specFileIn.cellProjectionFile.files[i].filename, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } cellProjectionFile->clearModified(); // // Read the cocomac connectivity file // for (unsigned int i = 0; i < specFileIn.cocomacConnectivityFile.files.size(); i++) { if (specFileIn.cocomacConnectivityFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.cocomacConnectivityFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readCocomacConnectivityFile(specFileIn.cocomacConnectivityFile.files[i].filename, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read the contour file // for (unsigned int i = 0; i < specFileIn.contourFile.files.size(); i++) { if (specFileIn.contourFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.contourFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readContourFile(specFileIn.contourFile.files[i].filename, true, true); BrainModelContours* bmc = getBrainModelContours(-1); if (bmc != NULL) { ContourFile* cf = bmc->getContourFile(); cf->clearModified(); } } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read the contour cell file // for (unsigned int i = 0; i < specFileIn.contourCellFile.files.size(); i++) { if (specFileIn.contourCellFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.contourCellFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readContourCellFile(specFileIn.contourCellFile.files[i].filename, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read the contour cell color file // for (unsigned int i = 0; i < specFileIn.contourCellColorFile.files.size(); i++) { if (specFileIn.contourCellColorFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.contourCellColorFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readContourCellColorFile(specFileIn.contourCellColorFile.files[i].filename, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read the cuts file // for (unsigned int i = 0; i < specFileIn.cutsFile.files.size(); i++) { if (specFileIn.cutsFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.cutsFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readCutsFile(specFileIn.cutsFile.files[i].filename, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read in the foci color file // for (unsigned int i = 0; i < specFileIn.fociColorFile.files.size(); i++) { if (specFileIn.fociColorFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.fociColorFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readFociColorFile(specFileIn.fociColorFile.files[i].filename, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read the fiducial foci file // for (unsigned int i = 0; i < specFileIn.fociFile.files.size(); i++) { if (specFileIn.fociFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.fociFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readFociFile(specFileIn.fociFile.files[i].filename, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read the foci projection file // for (unsigned int i = 0; i < specFileIn.fociProjectionFile.files.size(); i++) { if (specFileIn.fociProjectionFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.fociProjectionFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readFociProjectionFile(specFileIn.fociProjectionFile.files[i].filename, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } fociProjectionFile->clearModified(); // // Read the foci search file // for (unsigned int i = 0; i < specFileIn.fociSearchFile.files.size(); i++) { if (i == 0) { // // Remove default search // clearFociSearchFile(); } if (specFileIn.fociSearchFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.fociSearchFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readFociSearchFile(specFileIn.fociSearchFile.files[i].filename, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } fociSearchFile->clearModified(); // // Read the transformation matrix file // for (unsigned int i = 0; i < specFileIn.transformationMatrixFile.files.size(); i++) { if (specFileIn.transformationMatrixFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.transformationMatrixFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readTransformationMatrixFile(specFileIn.transformationMatrixFile.files[i].filename, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Read the transformation data file // for (unsigned int i = 0; i < specFileIn.transformationDataFile.files.size(); i++) { if (specFileIn.transformationDataFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.transformationDataFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } try { readTransformationDataFile(specFileIn.transformationDataFile.files[i].filename, true, true); } catch (FileException& e) { errorMessages.push_back(e.whatQString()); } } } // // Set the deformation map file name to the first one selected // for (unsigned int i = 0; i < specFileIn.deformationMapFile.files.size(); i++) { if (specFileIn.deformationMapFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.deformationMapFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } deformationMapFileName = specFileIn.deformationMapFile.files[i].filename; break; } } // // Set the cerebral hull file name to the first one selected // for (unsigned int i = 0; i < specFileIn.cerebralHullFile.files.size(); i++) { if (specFileIn.cerebralHullFile.files[i].selected) { if (updateFileReadProgressDialog(specFileIn.cerebralHullFile.files[i].filename, progressFileCounter, progressDialog)) { return true; } cerebralHullFileName = specFileIn.cerebralHullFile.files[i].filename; break; } } if (progressDialog != NULL) { if (progressDialog->wasCanceled()) { readingSpecFileFlag = false; return true; } progressDialog->setLabelText("Initializing Data"); progressFileCounter++; progressDialog->setValue(progressFileCounter); qApp->processEvents(); // note: qApp is global in QApplication } // // If no surface shape file was selected // if (surfaceShapeFile->getNumberOfColumns() == 0) { // // Compute curvature for a fiducial or raw surface // if (getNumberOfTopologyFiles() > 0) { BrainModelSurface* curvatureSurface = NULL; for (int i = 0; i < getNumberOfBrainModels(); i++) { BrainModelSurface* bms = getBrainModelSurface(i); if (bms != NULL) { if (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FIDUCIAL) { curvatureSurface = bms; break; } else if (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_RAW) { curvatureSurface = bms; } } } if (curvatureSurface != NULL) { BrainModelSurfaceCurvature bmsc(this, curvatureSurface, getSurfaceShapeFile(), BrainModelSurfaceCurvature::CURVATURE_COLUMN_CREATE_NEW, BrainModelSurfaceCurvature::CURVATURE_COLUMN_DO_NOT_GENERATE, "Folding (Mean Curvature)", ""); try { bmsc.execute(); getSurfaceShapeFile()->clearModified(); } catch (BrainModelAlgorithmException& /*e*/) { clearSurfaceShapeFile(); } } } } for (int ii = numTopoFilesBeforeLoading; ii < getNumberOfTopologyFiles(); ii++) { TopologyFile* tf = getTopologyFile(ii); tf->clearModified(); } postSpecFileReadInitializations(); resetNodeAttributes(); // // Emit the signal that this brain set has changed // emit signalBrainSetChanged(); readingSpecFileFlag = false; return false; } /** * Read the BrainSet data files. Any error message will be placed * into "errorMessages". The size of errorMessages will correspond to * the number files that failed to read correctly. If the size of * errorMessages is 0, no file reading errors were encountered. * * Returns "true" if the user aborted loading files with the progress dialog. */ bool BrainSet::readSpecFileMultiThreaded(const SPEC_FILE_READ_MODE specReadMode, const SpecFile& specFileIn, const QString& specFileNameIn, std::vector& errorMessages, const TransformationMatrix* specTransformationMatrixIn, QProgressDialog* progressDialogIn) { QProgressDialog* progressDialog = progressDialogIn; specFileTimeOfLoading = QDateTime::currentDateTime(); readingSpecFileFlag = true; switch (specReadMode) { case SPEC_FILE_READ_MODE_NORMAL: // // clear out "this" brain set // reset(); break; case SPEC_FILE_READ_MODE_APPEND: break; } if (specTransformationMatrixIn != NULL) { specDataFileTransformationMatrix = *specTransformationMatrixIn; } errorMessages.clear(); //int progressFileCounter = 0; switch (specReadMode) { case SPEC_FILE_READ_MODE_NORMAL: // // Copy spec file passed and clear all selections in BrainSet::specFile // loadedFilesSpecFile = specFileIn; loadedFilesSpecFile.setAllFileSelections(SpecFile::SPEC_FALSE); //loadedFilesSpecFile.setFileName(specFileNameIn); loadedFilesSpecFile.setCurrentDirectoryToSpecFileDirectory(); specFileName = specFileNameIn; structure = specFileIn.getStructure(); /* hemisphere = Hemisphere::HEMISPHERE_UNKNOWN; if (specFileIn.getStructure() == "right") { hemisphere = BrainModelSurface::HEMISPHERE_RIGHT; } else if (specFileIn.getStructure() == "left") { hemisphere = BrainModelSurface::HEMISPHERE_LEFT; } else if (specFileIn.getStructure() == "both") { hemisphere = BrainModelSurface::HEMISPHERE_BOTH; } setStructure(hemisphere); */ setSpecies(loadedFilesSpecFile.getSpecies()); setSubject(loadedFilesSpecFile.getSubject()); stereotaxicSpace = loadedFilesSpecFile.getSpace(); resetDataFiles(false, false); break; case SPEC_FILE_READ_MODE_APPEND: break; } const int numTopoFilesBeforeLoading = getNumberOfTopologyFiles(); // // Create the multi-threaded reader and read files // const int numThreads = getPreferencesFile()->getNumberOfFileReadingThreads(); BrainSetMultiThreadedSpecFileReader multiThreadReader(this); multiThreadReader.readDataFiles(numThreads, specFileIn, progressDialog, errorMessages); // // Add default palettes // switch (specReadMode) { case SPEC_FILE_READ_MODE_NORMAL: paletteFile->addDefaultPalettes(); paletteFile->clearModified(); break; case SPEC_FILE_READ_MODE_APPEND: break; } cellProjectionFile->clearModified(); fociProjectionFile->clearModified(); if (progressDialog != NULL) { if (progressDialog->wasCanceled()) { readingSpecFileFlag = false; return true; } progressDialog->setLabelText("Initializing Data"); progressDialog->setValue(progressDialog->value() + 1); qApp->processEvents(); // note: qApp is global in QApplication } // // If no surface shape file was selected // if (surfaceShapeFile->getNumberOfColumns() == 0) { // // Compute curvature for a fiducial or raw surface // if (getNumberOfTopologyFiles() > 0) { BrainModelSurface* curvatureSurface = NULL; for (int i = 0; i < getNumberOfBrainModels(); i++) { BrainModelSurface* bms = getBrainModelSurface(i); if (bms != NULL) { if (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FIDUCIAL) { curvatureSurface = bms; break; } else if (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_RAW) { curvatureSurface = bms; } } } if (curvatureSurface != NULL) { BrainModelSurfaceCurvature bmsc(this, curvatureSurface, getSurfaceShapeFile(), BrainModelSurfaceCurvature::CURVATURE_COLUMN_CREATE_NEW, BrainModelSurfaceCurvature::CURVATURE_COLUMN_DO_NOT_GENERATE, "Folding (Mean Curvature)", ""); try { bmsc.execute(); getSurfaceShapeFile()->clearModified(); } catch (BrainModelAlgorithmException& /*e*/) { clearSurfaceShapeFile(); } } } } for (int ii = numTopoFilesBeforeLoading; ii < getNumberOfTopologyFiles(); ii++) { TopologyFile* tf = getTopologyFile(ii); tf->clearModified(); } postSpecFileReadInitializations(); resetNodeAttributes(); // // Emit the signal that this brain set has changed // emit signalBrainSetChanged(); readingSpecFileFlag = false; return false; } /** * sort the brain models (raw, fiducial, ..., volume, surf&vol, contours). */ void BrainSet::sortBrainModels() { const int numModels = static_cast(brainModels.size()); if (numModels <= 0) { return; } // // Assign priority to the models // const int surfacePriority = 0; const int volumePriority = 20; const int surfaceAndVolumePriority = 21; const int contourPriority = 22; const int noPriority = 23; std::vector modelPriority(numModels, noPriority); for (int i = 0; i < numModels; i++) { int priority = noPriority; if (getBrainModelSurfaceAndVolume(i) != NULL) { priority = surfaceAndVolumePriority; } else if (getBrainModelSurface(i) != NULL) { const BrainModelSurface* bms = getBrainModelSurface(i); priority = surfacePriority + static_cast(bms->getSurfaceType()); } else if (getBrainModelVolume(i) != NULL) { priority = volumePriority; } else if (getBrainModelContours(i) != NULL) { priority = contourPriority; } modelPriority[i] = priority; } // // Replace the models in sorted order // std::vector sortedModels; for (int ip = 0; ip <= noPriority; ip++) { for (int j = 0; j < numModels; j++) { if (modelPriority[j] == ip) { sortedModels.push_back(brainModels[j]); } } } if (brainModels.size() == sortedModels.size()) { brainModels = sortedModels; } else { std::cout << "INFO: Sorting of brain models failed." << std::endl; } } /** * Update all display settings. */ void BrainSet::updateAllDisplaySettings() { brainSetAutoLoaderManager->update(); displaySettingsArealEstimation->update(); displaySettingsBorders->update(); displaySettingsCells->update(); displaySettingsCoCoMac->update(); displaySettingsContours->update(); displaySettingsCuts->update(); displaySettingsFoci->update(); displaySettingsDeformationField->update(); displaySettingsMetric->update(); displaySettingsPaint->update(); displaySettingsProbabilisticAtlasSurface->update(); displaySettingsRgbPaint->update(); displaySettingsScene->update(); displaySettingsSection->update(); displaySettingsStudyMetaData->update(); displaySettingsSurfaceShape->update(); displaySettingsVectors->update(); displaySettingsTopography->update(); displaySettingsVolume->update(); displaySettingsProbabilisticAtlasVolume->update(); displaySettingsWustlRegion->update(); } /** * Initalize things after reading a spec file or initial surface into caret */ void BrainSet::postSpecFileReadInitializations() { getSectionsFromTopology(); assignBorderColors(); assignCellColors(); assignContourCellColors(); assignFociColors(); updateAllDisplaySettings(); clearNodeAttributes(); brainModelBorderSet->setAllBordersModifiedStatus(false); brainModelBorderSet->setProjectionsModified(false); if (sectionFile->getNumberOfColumns() == 0) { BrainModelSurface* bms = getActiveFiducialSurface(); if (bms != NULL) { BrainModelSurfaceResection bmsr(this, bms, bms->getRotationTransformMatrix(0), BrainModelSurfaceResection::SECTION_AXIS_Y, BrainModelSurfaceResection::SECTION_TYPE_THICKNESS, sectionFile, -1, "Default Sections 1mm Y-axis", 1.0, 100); try { bmsr.execute(); } catch (BrainModelAlgorithmException) { } sectionFile->clearModified(); } } updateNodeDisplayFlags(); // // Default to surface shape if no overlays/underlays selected // if (getSurfaceUnderlay()->getOverlay(-1) == BrainModelSurfaceOverlay::OVERLAY_NONE) { if (getSurfaceShapeFile()->getNumberOfColumns() > 0) { getSurfaceUnderlay()->setOverlay(-1, BrainModelSurfaceOverlay::OVERLAY_SURFACE_SHAPE); } } nodeColoring->assignColors(); // // Create default transformation matrices // ParamsFile* paramsFile = getParamsFile(); float acX, acY, acZ; paramsFile->getParameter(ParamsFile::keyACx, acX); paramsFile->getParameter(ParamsFile::keyACy, acY); paramsFile->getParameter(ParamsFile::keyACz, acZ); if ((acX != 0.0) || (acY != 0.0) || (acZ != 0.0)) { TransformationMatrixFile* tmf = getTransformationMatrixFile(); // // Create matrix to transform from Native to AC-centered space. // QString name("Native To AC"); TransformationMatrix* tm = tmf->getTransformationMatrixWithName(name); if (tm == NULL) { TransformationMatrix nac; nac.setMatrixName(name); nac.setMatrixComment("Convert from Native to AC-centered space."); nac.translate(-acX, -acY, -acZ); tmf->addTransformationMatrix(nac); } // // Create matrix to transform from Native to AC-centered space. // name = "AC To Native"; tm = tmf->getTransformationMatrixWithName(name); if (tm == NULL) { TransformationMatrix acn; acn.setMatrixName(name); acn.setMatrixComment("Convert from AC-centered to Native space."); acn.translate(acX, acY, acZ); tmf->addTransformationMatrix(acn); } tmf->clearModified(); } paramsFile->getParameter(ParamsFile::keyWholeVolumeACx, acX); paramsFile->getParameter(ParamsFile::keyWholeVolumeACy, acY); paramsFile->getParameter(ParamsFile::keyWholeVolumeACz, acZ); if ((acX != 0.0) || (acY != 0.0) || (acZ != 0.0)) { TransformationMatrixFile* tmf = getTransformationMatrixFile(); // // Create matrix to transform from Native to whole volume AC-centered space. // QString name("Native To Whole Volume AC"); TransformationMatrix* tm = tmf->getTransformationMatrixWithName(name); if (tm == NULL) { TransformationMatrix nac; nac.setMatrixName(name); nac.setMatrixComment("Convert from Native to Whole Volume AC-centered space."); nac.translate(-acX, -acY, -acZ); tmf->addTransformationMatrix(nac); } // // Create matrix to transform from Native to whole volume AC-centered space. // name = "Whole Volume AC To Native"; tm = tmf->getTransformationMatrixWithName(name); if (tm == NULL) { TransformationMatrix acn; acn.setMatrixName(name); acn.setMatrixComment("Convert from Whole Volume AC-centered to Native space."); acn.translate(acX, acY, acZ); tmf->addTransformationMatrix(acn); } tmf->clearModified(); } updateDefaultFileNamePrefix(); } /** * delete a brain model surface. */ void BrainSet::deleteBrainModelSurface(BrainModelSurface* bms) { const QString name(bms->getCoordinateFile()->getFileName()); loadedFilesSpecFile.rawCoordFile.clearSelectionStatus(name); loadedFilesSpecFile.fiducialCoordFile.clearSelectionStatus(name); loadedFilesSpecFile.inflatedCoordFile.clearSelectionStatus(name); loadedFilesSpecFile.veryInflatedCoordFile.clearSelectionStatus(name); loadedFilesSpecFile.sphericalCoordFile.clearSelectionStatus(name); loadedFilesSpecFile.ellipsoidCoordFile.clearSelectionStatus(name); loadedFilesSpecFile.compressedCoordFile.clearSelectionStatus(name); loadedFilesSpecFile.flatCoordFile.clearSelectionStatus(name); loadedFilesSpecFile.lobarFlatCoordFile.clearSelectionStatus(name); loadedFilesSpecFile.unknownCoordFile.clearSelectionStatus(name); deleteBrainModel(bms); clearAllDisplayLists(); updateAllDisplaySettings(); nodeColoring->assignColors(); } /** * delete all brain model surfaces. */ void BrainSet::deleteAllBrainModelSurfaces() { std::vector modelsToDelete; const int num = static_cast(brainModels.size()); for (int i = (num - 1); i >= 0; i--) { switch (brainModels[i]->getModelType()) { case BrainModel::BRAIN_MODEL_SURFACE: { BrainModelSurface* bms = getBrainModelSurface(i); if (bms != NULL) { deleteBrainModelSurface(bms); } } break; case BrainModel::BRAIN_MODEL_SURFACE_AND_VOLUME: deleteBrainModel(brainModels[i]); break; case BrainModel::BRAIN_MODEL_VOLUME: break; case BrainModel::BRAIN_MODEL_CONTOURS: break; } } deleteAllTopologyFiles(); resetNodeAttributeFiles(); clearAllDisplayLists(); } /** * Get the "active" fiducial surface. */ void BrainSet::setActiveFiducialSurface(BrainModelSurface* bms) { activeFiducialSurface = bms; BrainModelSurfaceAndVolume* bmsv = getBrainModelSurfaceAndVolume(); if (bmsv != NULL) { bmsv->setSurface(); } for (int i = 0; i < getNumberOfVolumeFunctionalFiles(); i++) { getVolumeFunctionalFile(i)->setVoxelToSurfaceDistancesValid(false); } } /** * Get the "active" fiducial surface. */ BrainModelSurface* BrainSet::getActiveFiducialSurface() { // // Make sure fiducial surface is still valid // bool activeFiducialSurfaceFound = false; if (activeFiducialSurface != NULL) { const int numBrains = getNumberOfBrainModels(); for (int i = 0; i < numBrains; i++) { BrainModelSurface* bms = getBrainModelSurface(i); if (bms != NULL) { if (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FIDUCIAL) { if (bms == activeFiducialSurface) { activeFiducialSurfaceFound = true; } } } } } // // Find the fiducial surface to make the active surface // if (activeFiducialSurfaceFound == false) { activeFiducialSurface = NULL; const int numBrains = getNumberOfBrainModels(); for (int i = 0; i < numBrains; i++) { BrainModelSurface* bms = getBrainModelSurface(i); if (bms != NULL) { if (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FIDUCIAL) { activeFiducialSurface = bms; } } } } return activeFiducialSurface; } /** * get the left fiducial volume interaction surface. */ BrainModelSurface* BrainSet::getLeftFiducialVolumeInteractionSurface() { // // Does the surface still exist // int indx = getBrainModelIndex(leftFiducialVolumeInteractionSurface); if (indx >= 0) { BrainModelSurface* bms = getBrainModelSurface(indx); if (bms->getStructure().getType() != Structure::STRUCTURE_TYPE_CORTEX_LEFT) { indx = -1; } } if (indx < 0) { // // Find the first left fiducial surface // leftFiducialVolumeInteractionSurface = NULL; const int numBrains = getNumberOfBrainModels(); for (int i = 0; i < numBrains; i++) { BrainModelSurface* bms = getBrainModelSurface(i); if (bms != NULL) { if (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FIDUCIAL) { if (bms->getStructure().getType() == Structure::STRUCTURE_TYPE_CORTEX_LEFT) { leftFiducialVolumeInteractionSurface = bms; } } } } } return leftFiducialVolumeInteractionSurface; } /** * get the right fiducial volume interaction surface. */ BrainModelSurface* BrainSet::getRightFiducialVolumeInteractionSurface() { // // Does the surface still exist // int indx = getBrainModelIndex(rightFiducialVolumeInteractionSurface); if (indx >= 0) { BrainModelSurface* bms = getBrainModelSurface(indx); if (bms->getStructure().getType() != Structure::STRUCTURE_TYPE_CORTEX_RIGHT) { indx = -1; } } if (indx < 0) { // // Find the first right fiducial surface // rightFiducialVolumeInteractionSurface = NULL; const int numBrains = getNumberOfBrainModels(); for (int i = 0; i < numBrains; i++) { BrainModelSurface* bms = getBrainModelSurface(i); if (bms != NULL) { if (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FIDUCIAL) { if (bms->getStructure().getType() == Structure::STRUCTURE_TYPE_CORTEX_RIGHT) { rightFiducialVolumeInteractionSurface = bms; } } } } } return rightFiducialVolumeInteractionSurface; } /** * get the cerebellum fiducial volume interaction surface. */ BrainModelSurface* BrainSet::getCerebellumFiducialVolumeInteractionSurface() { // // Does the surface still exist // int indx = getBrainModelIndex(cerebellumFiducialVolumeInteractionSurface); if (indx >= 0) { BrainModelSurface* bms = getBrainModelSurface(indx); if (bms->getStructure().getType() != Structure::STRUCTURE_TYPE_CEREBELLUM) { indx = -1; } } if (indx < 0) { // // Find the first cerebellum fiducial surface // cerebellumFiducialVolumeInteractionSurface = NULL; const int numBrains = getNumberOfBrainModels(); for (int i = 0; i < numBrains; i++) { BrainModelSurface* bms = getBrainModelSurface(i); if (bms != NULL) { if (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FIDUCIAL) { if (bms->getStructure().getType() == Structure::STRUCTURE_TYPE_CEREBELLUM) { cerebellumFiducialVolumeInteractionSurface = bms; } } } } } return cerebellumFiducialVolumeInteractionSurface; } /** * set the left fiducial volume interaction surface. */ void BrainSet::setLeftFiducialVolumeInteractionSurface(BrainModelSurface* bms) { leftFiducialVolumeInteractionSurface = bms; } /** * set the right fiducial volume interaction surface. */ void BrainSet::setRightFiducialVolumeInteractionSurface(BrainModelSurface* bms) { rightFiducialVolumeInteractionSurface = bms; } /** * set the cerebellum fiducial volume interaction surface. */ void BrainSet::setCerebellumFiducialVolumeInteractionSurface(BrainModelSurface* bms) { cerebellumFiducialVolumeInteractionSurface = bms; } /** * Get a brain model surface of the specified type. */ BrainModelSurface* BrainSet::getBrainModelSurfaceOfType(const BrainModelSurface::SURFACE_TYPES st) { const int ns = getNumberOfBrainModels(); for (int i = (ns - 1); i >= 0; i--) { BrainModel* bm = getBrainModel(i); if (bm->getModelType() == BrainModel::BRAIN_MODEL_SURFACE) { BrainModelSurface* s = dynamic_cast(bm); if (s->getSurfaceType() == st) { return s; } } } return NULL; } /** * Get a brain model surface with the specified coordinate file name (NULL if not found). */ BrainModelSurface* BrainSet::getBrainModelSurfaceWithCoordinateFileName(const QString& fileNameIn) { const QString fileName(FileUtilities::basename(fileNameIn)); const int ns = getNumberOfBrainModels(); for (int i = (ns - 1); i >= 0; i--) { BrainModelSurface* bms = getBrainModelSurface(i); if (bms != NULL) { const CoordinateFile* cf = bms->getCoordinateFile(); if (cf != NULL) { const QString coordName = FileUtilities::basename(cf->getFileName()); if (fileName == coordName) { return bms; } } } } return NULL; } /** * generate the cerebral hull vtk file */ void BrainSet::generateCerebralHullVtkFile(const VolumeFile* segmentationVolume, const bool saveHullVolumeFileFlag) throw (BrainModelAlgorithmException) { cerebralHullFileName = ""; // // Create the cerebral hull volume // VolumeFile* hullVolume = new VolumeFile; segmentationVolume->createCerebralHullVolume(*hullVolume); /* QString name(hullVolume->getFileName()); const QString afniExt("+orig" + SpecFile::getAfniVolumeFileExtension()); if (name.endsWith(afniExt) == false) { if (name.endsWith(SpecFile::getAfniVolumeFileExtension())) { const int numChars = name.length() - SpecFile::getAfniVolumeFileExtension().length(); name = name.left(numChars); } name.append(afniExt); } hullVolume->setFileName(name); */ // // Add the cerbral hull file to the brain set // addVolumeFile(VolumeFile::VOLUME_TYPE_SEGMENTATION, hullVolume, hullVolume->getFileName(), true, true); if(saveHullVolumeFileFlag) { // // Save file // try { writeVolumeFile(hullVolume->getFileName(), hullVolume->getFileWriteType(), VolumeFile::VOLUME_TYPE_SEGMENTATION, hullVolume); } catch (FileException& e) { QString msg("Error saving cerebral hull volume: \n"); msg.append(e.whatQString()); throw BrainModelAlgorithmException(msg); } } // // Create a new brain set // BrainSet bs; // // Generate a surface from the cerebral hull volume // BrainModelVolumeToSurfaceConverter bmvsc(&bs, hullVolume, BrainModelVolumeToSurfaceConverter::RECONSTRUCTION_MODE_SUREFIT_SURFACE, true, false); try { bmvsc.execute(); } catch (BrainModelAlgorithmException& e) { QString msg("ERROR creating cerebral hull VTK file: \n"); msg.append(e.whatQString()); throw BrainModelAlgorithmException(msg); } // // Find the fiducial surface // BrainModelSurface* bms = bs.getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_FIDUCIAL); if (bms == NULL) { throw BrainModelAlgorithmException("Unable to find surface generated from cerebral hull volume."); } // // Name the VTK file // QString prefix; int numNodes; AbstractFile::getDefaultFileNamePrefix(prefix, numNodes); QString vtkName(prefix); if (prefix.isEmpty() == false) { vtkName.append("."); } vtkName.append("CerebralHull.vtk"); // // Export hull surface to VTK surface file. // try { bs.exportVtkSurfaceFile(bms, vtkName, false); } catch (FileException& e) { QString msg("Error saving cerebral hull as VTK file."); msg.append(e.whatQString()); throw BrainModelAlgorithmException(e.whatQString()); } // // Update spec file // addToSpecFile(SpecFile::getCerebralHullFileTag(), vtkName); // // Set name of cerebral null // cerebralHullFileName = vtkName; } /** * generate the cerebral hull vtk file * caller must delete the output files (hull volume and VTK file) */ void BrainSet::generateCerebralHullVtkFile(const VolumeFile* segmentationVolumeIn, VolumeFile* &cerebralHullVolumeOut, vtkPolyData* &cerebralHullVtkPolyDataOut) throw (BrainModelAlgorithmException) { // // Create the cerebral hull volume // cerebralHullVolumeOut = new VolumeFile; segmentationVolumeIn->createCerebralHullVolume(*cerebralHullVolumeOut); // // Create a new brain set // BrainSet bs; // // Generate a surface from the cerebral hull volume // BrainModelVolumeToSurfaceConverter bmvsc(&bs, cerebralHullVolumeOut, BrainModelVolumeToSurfaceConverter::RECONSTRUCTION_MODE_SUREFIT_SURFACE, true, false); try { bmvsc.execute(); } catch (BrainModelAlgorithmException& e) { QString msg("ERROR creating cerebral hull VTK file: \n"); msg.append(e.whatQString()); throw BrainModelAlgorithmException(msg); } // // Find the fiducial surface // BrainModelSurface* bms = bs.getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_FIDUCIAL); if (bms == NULL) { throw BrainModelAlgorithmException("Unable to find surface generated from cerebral hull volume."); } // // Get VTK poly data from surface // cerebralHullVtkPolyDataOut = bms->convertToVtkPolyData(); } /** * If no sections files, search through topology files for sections. */ void BrainSet::getSectionsFromTopology() { if (sectionFile->getNumberOfColumns() == 0) { const int numNodes = getNumberOfNodes(); if (numNodes <= 0) { return; } const int numFiles = getNumberOfTopologyFiles(); for (int i = 0; i < numFiles; i++) { TopologyFile* tf = getTopologyFile(i); std::vector sectionInfo; if (tf->getNodeSections(sectionInfo)) { int column = 0; if (sectionFile->getNumberOfNodes() == 0) { sectionFile->setNumberOfNodesAndColumns(numNodes, 1); column = 0; } else { column = sectionFile->getNumberOfColumns(); sectionFile->addColumns(1); } QString str("From topology file: "); str.append(tf->getFileName()); sectionFile->setColumnComment(column, str); sectionFile->setColumnName(column, FileUtilities::basename(tf->getFileName())); const int num = std::min(static_cast(sectionInfo.size()), numNodes); for (int j = 0; j < num; j++) { sectionFile->setSection(j, column, sectionInfo[j]); } } /* if (tf->getNumberOfTopologyNodes() == numNodes) { int column = 0; if (sectionFile->getNumberOfNodes() == 0) { sectionFile->setNumberOfNodesAndColumns(numNodes, 1); column = 0; } else { column = sectionFile->getNumberOfColumns(); sectionFile->addColumns(1); } QString str("From topology file: "); str.append(tf->getFileName()); sectionFile->setColumnComment(column, str); sectionFile->setColumnName(column, FileUtilities::basename(tf->getFileName())); for (int j = 0; j < numNodes; j++) { const TopologyNode* tn = tf->getTopologyNode(j); sectionFile->setSection(j, column, tn->getSectionNumber()); } sectionFile->setMaximumSelectedSection(column, sectionFile->getMaximumSection(column)); sectionFile->setMinimumSelectedSection(column, sectionFile->getMinimumSection(column)); } */ } sectionFile->clearModified(); } } /** * Returns the number of nodes in this surface */ int BrainSet::getNumberOfNodes() const { const int numModels = getNumberOfBrainModels(); for (int i = 0; i < numModels; i++) { const BrainModelSurface* bms = getBrainModelSurface(i); if (bms != NULL) { return bms->getNumberOfNodes(); } } return 0; } /** * Set the default scaling for all surfaces */ void BrainSet::setDefaultScaling(const float orthoRight, const float orthoTop) { const int ns = getNumberOfBrainModels(); for (int i = 0; i < ns; i++) { BrainModel* bm = getBrainModel(i); switch (bm->getModelType()) { case BrainModel::BRAIN_MODEL_CONTOURS: break; case BrainModel::BRAIN_MODEL_SURFACE: { BrainModelSurface* s = dynamic_cast(bm); s->setDefaultScaling(orthoRight, orthoTop); break; } case BrainModel::BRAIN_MODEL_SURFACE_AND_VOLUME: { BrainModelSurface* s = dynamic_cast(bm); s->setDefaultScaling(orthoRight, orthoTop); break; } case BrainModel::BRAIN_MODEL_VOLUME: break; } } } /** * Assign border colors to the border projection and border files */ void BrainSet::assignBorderColors() { brainModelBorderSet->assignColors(); } /** * Assign cell colors to cell and cell projection files */ void BrainSet::assignCellColors() { // // Cell Projection File // cellProjectionFile->assignColors(*cellColorFile, displaySettingsCells->getColorMode()); // // volume cell file // volumeCellFile->assignColors(*cellColorFile, displaySettingsCells->getColorMode()); // // Transform data files may contain cell files // assignTransformationDataFileColors(); } /** * Assign contour cell colors to contour cells */ void BrainSet::assignContourCellColors() { // // Contour Cell File // contourCellFile->assignColors(*contourCellColorFile, CellBase::CELL_COLOR_MODE_NAME); } /** * Assign foci colors to foci and foci projection files */ void BrainSet::assignFociColors() { // // Foci Projection File // fociProjectionFile->assignColors(*fociColorFile, displaySettingsFoci->getColorMode()); // // Transform data files may contain cell files // assignTransformationDataFileColors(); } /** * delete a transformation data file. */ void BrainSet::deleteTransformationDataFile(const int fileIndex) { if ((fileIndex >= 0) && (fileIndex < getNumberOfTransformationDataFiles())) { delete transformationDataFiles[fileIndex]; transformationDataFiles.erase(transformationDataFiles.begin() + fileIndex); } } /** * delete a transformation data file. */ void BrainSet::deleteTransformationDataFile(AbstractFile* af) { for (int i = 0; i < getNumberOfTransformationDataFiles(); i++) { if (getTransformationDataFile(i) == af) { deleteTransformationDataFile(i); break; } } } /** * get have transformation data cell files. */ bool BrainSet::getHaveTransformationDataCellFiles() const { for (int i = 0; i < getNumberOfTransformationDataFiles(); i++) { if (dynamic_cast(transformationDataFiles[i]) != NULL) { if (dynamic_cast(transformationDataFiles[i]) == NULL) { if (dynamic_cast(transformationDataFiles[i]) == NULL) { return true; } } } } return false; } /** * get have transformation data contour files. */ bool BrainSet::getHaveTransformationDataContourFiles() const { for (int i = 0; i < getNumberOfTransformationDataFiles(); i++) { if (dynamic_cast(transformationDataFiles[i]) != NULL) { return true; } } return false; } /** * get have transformation data contour cell files. */ bool BrainSet::getHaveTransformationDataContourCellFiles() const { for (int i = 0; i < getNumberOfTransformationDataFiles(); i++) { if (dynamic_cast(transformationDataFiles[i]) != NULL) { return true; } } return false; } /** * get have transformation data foci files. */ bool BrainSet::getHaveTransformationDataFociFiles() const { for (int i = 0; i < getNumberOfTransformationDataFiles(); i++) { if (dynamic_cast(transformationDataFiles[i]) != NULL) { return true; } } return false; } /** * get have transformation data vtk files. */ bool BrainSet::getHaveTransformationDataVtkFiles() const { for (int i = 0; i < getNumberOfTransformationDataFiles(); i++) { if (dynamic_cast(transformationDataFiles[i]) != NULL) { return true; } } return false; } /** * assign transformation data file colors. */ void BrainSet::assignTransformationDataFileColors() { const int num = getNumberOfTransformationDataFiles(); for (int i = 0; i < num; i++) { AbstractFile* af = getTransformationDataFile(i); FociFile* ff = dynamic_cast(af); if (ff != NULL) { ff->assignColors(*fociColorFile, CellBase::CELL_COLOR_MODE_NAME); } CellFile* cf = dynamic_cast(af); if ((ff == NULL) && (cf != NULL)) { cf->assignColors(*cellColorFile, CellBase::CELL_COLOR_MODE_NAME); } } } /** * remove unlinked studies from study meta data file. * Returns number of studies that are removed. */ int BrainSet::removeUnlinkedStudiesFromStudyMetaDataFile() { // // Used to track linked studies // const int numStudies = studyMetaDataFile->getNumberOfStudyMetaData(); if (numStudies <= 0) { return 0; } // // Get PubMed IDs of various data types // std::set pmidSet; std::vector pmids; arealEstimationFile->getPubMedIDsOfAllLinkedStudyMetaData(pmids); pmidSet.insert(pmids.begin(), pmids.end()); cellProjectionFile->getPubMedIDsOfAllLinkedStudyMetaData(pmids); pmidSet.insert(pmids.begin(), pmids.end()); deformationFieldFile->getPubMedIDsOfAllLinkedStudyMetaData(pmids); pmidSet.insert(pmids.begin(), pmids.end()); fociProjectionFile->getPubMedIDsOfAllLinkedStudyMetaData(pmids); pmidSet.insert(pmids.begin(), pmids.end()); geodesicDistanceFile->getPubMedIDsOfAllLinkedStudyMetaData(pmids); pmidSet.insert(pmids.begin(), pmids.end()); latLonFile->getPubMedIDsOfAllLinkedStudyMetaData(pmids); pmidSet.insert(pmids.begin(), pmids.end()); paintFile->getPubMedIDsOfAllLinkedStudyMetaData(pmids); pmidSet.insert(pmids.begin(), pmids.end()); rgbPaintFile->getPubMedIDsOfAllLinkedStudyMetaData(pmids); pmidSet.insert(pmids.begin(), pmids.end()); surfaceShapeFile->getPubMedIDsOfAllLinkedStudyMetaData(pmids); pmidSet.insert(pmids.begin(), pmids.end()); for (int i = 0; i < getNumberOfVectorFiles(); i++) { getVectorFile(i)->getPubMedIDsOfAllLinkedStudyMetaData(pmids); pmidSet.insert(pmids.begin(), pmids.end()); } topographyFile->getPubMedIDsOfAllLinkedStudyMetaData(pmids); pmidSet.insert(pmids.begin(), pmids.end()); vocabularyFile->getPubMedIDsOfAllLinkedStudyMetaData(pmids); pmidSet.insert(pmids.begin(), pmids.end()); // // Identify linked studies // std::vector studyUsageFlags(numStudies, 0); for (std::set::iterator iter = pmidSet.begin(); iter != pmidSet.end(); iter++) { const QString pmid(*iter); if (pmid.isEmpty() == false) { const int studyNumber = studyMetaDataFile->getStudyIndexFromPubMedID(pmid); if (studyNumber >= 0) { studyUsageFlags[studyNumber] = true; } } } // // Remove unused studies // int numUnusedStudies = 0; for (int i = (numStudies - 1); i >= 0; i--) { if (studyUsageFlags[i] == false) { studyMetaDataFile->deleteStudyMetaData(i); numUnusedStudies++; } } return numUnusedStudies; } /** * move foci study info to the study meta data file. */ void BrainSet::moveFociStudyInfoToStudyMetaDataFile() { StudyMetaDataFile* smdf = getStudyMetaDataFile(); FociProjectionFile* fpf = getFociProjectionFile(); smdf->append(*fpf); displaySettingsStudyMetaData->update(); displaySettingsFoci->update(); } /** * Delete all foci projections (including those in foci files). */ void BrainSet::deleteAllFociProjections() { fociProjectionFile->clear(); loadedFilesSpecFile.fociProjectionFile.setAllSelections(SpecFile::SPEC_FALSE); loadedFilesSpecFile.fociFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * Delete a focus. */ void BrainSet::deleteFocus(const int focusNumber) { fociProjectionFile->deleteCellProjection(focusNumber); } /** * Delete cell and cell projections. */ void BrainSet::deleteAllCells(const bool deleteCellProjections, const bool deleteVolumeCells) { if (deleteCellProjections) { deleteAllCellProjections(); } if (deleteVolumeCells) { volumeCellFile->clear(); loadedFilesSpecFile.volumeCellFile.setAllSelections(SpecFile::SPEC_FALSE); } } /** * Delete all cell projections (including those in cell files). */ void BrainSet::deleteAllCellProjections() { cellProjectionFile->clear(); loadedFilesSpecFile.cellProjectionFile.setAllSelections(SpecFile::SPEC_FALSE); loadedFilesSpecFile.cellFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * Delete a cell. */ void BrainSet::deleteCell(const int cellNumber) { cellProjectionFile->deleteCellProjection(cellNumber); } /** * delete all image files. */ void BrainSet::deleteAllImageFiles() { for (int i = 0; i < getNumberOfImageFiles(); i++) { delete imageFiles[i]; } imageFiles.clear(); loadedFilesSpecFile.imageFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * delete an image file. */ void BrainSet::deleteImageFile(ImageFile* img) { std::vector files; for (int i = 0; i < getNumberOfImageFiles(); i++) { if (imageFiles[i] == img) { loadedFilesSpecFile.imageFile.clearSelectionStatus(img->getFileName()); delete img; } else { files.push_back(imageFiles[i]); } } imageFiles = files; } /** * add an image file. */ void BrainSet::addImageFile(ImageFile* img) { imageFiles.push_back(img); displaySettingsImages->update(); } /** * see if an image file is valid. */ bool BrainSet::getImageFileValid(const ImageFile* img) const { const int num = getNumberOfImageFiles(); for (int i = 0; i < num; i++) { if (imageFiles[i] == img) { return true; } } return false; } /** * get an image file. */ ImageFile* BrainSet::getImageFile(const int fileNum) { if ((fileNum >= 0) && (fileNum < getNumberOfImageFiles())) { return imageFiles[fileNum]; } return NULL; } /** * get an image file based upon the image's file name. */ ImageFile* BrainSet::getImageFile(const QString& filename) { const int num = getNumberOfImageFiles(); for (int i = 0; i < num; i++) { ImageFile* img = getImageFile(i); if (img != NULL) { if (FileUtilities::basename(filename) == FileUtilities::basename(img->getFileName())) { return img; } } } return NULL; } /** * read the image data file. */ void BrainSet::readImageFile(const QString& name, const bool append, const bool updateSpec) throw (FileException) { ImageFile* img = new ImageFile; try { img->readFile(name); } catch (FileException& e) { delete img; throw(e); } QMutexLocker locker(&mutexImageFile); if (append == false) { deleteAllImageFiles(); } imageFiles.push_back(img); if (updateSpec) { addToSpecFile(SpecFile::getImageFileTag(), name); } displaySettingsImages->update(); } /** * write the image data file. */ void BrainSet::writeImageFile(const QString& name, ImageFile* img) throw (FileException) { loadedFilesSpecFile.imageFile.clearSelectionStatus(img->getFileName()); img->writeFile(name); addToSpecFile(SpecFile::getImageFileTag(), name); displaySettingsImages->update(); } /** * get a vtk model file. */ VtkModelFile* BrainSet::getVtkModelFile(const int modelNum) { if ((modelNum >= 0) && (modelNum < getNumberOfVtkModelFiles())) { return vtkModelFiles[modelNum]; } return NULL; } /** * Delete all VTK model files. */ void BrainSet::deleteAllVtkModelFiles() { for (int i = 0; i < getNumberOfVtkModelFiles(); i++) { delete vtkModelFiles[i]; } vtkModelFiles.clear(); loadedFilesSpecFile.vtkModelFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * add a VTK model file. */ void BrainSet::addVtkModelFile(VtkModelFile* vmf) { vtkModelFiles.push_back(vmf); displaySettingsModels->update(); } /** * delete a VTK model file. */ void BrainSet::deleteVtkModelFile(VtkModelFile* vmf) { std::vector files; for (int i = 0; i < getNumberOfVtkModelFiles(); i++) { if (vtkModelFiles[i] == vmf) { loadedFilesSpecFile.vtkModelFile.clearSelectionStatus(vmf->getFileName()); delete vmf; } else { files.push_back(vtkModelFiles[i]); } } vtkModelFiles = files; } /** * read the vtk model data file. */ void BrainSet::readVtkModelFile(const QString& name, const bool append, const bool updateSpec) throw (FileException) { VtkModelFile* vmf = new VtkModelFile(); try { vmf->readFile(name); } catch (FileException& e) { delete vmf; throw(e); } QMutexLocker locker(&mutexVtkModelFile); if (append == false) { deleteAllVtkModelFiles(); } vtkModelFiles.push_back(vmf); if (updateSpec) { addToSpecFile(SpecFile::getVtkModelFileTag(), name); } displaySettingsModels->update(); } /** * write the vtk model data file. */ void BrainSet::writeVtkModelFile(const QString& name, VtkModelFile* vmf) throw (FileException) { loadedFilesSpecFile.vtkModelFile.clearSelectionStatus(vmf->getFileName()); vmf->writeFile(name); addToSpecFile(SpecFile::getVtkModelFileTag(), name); } /** * Get the common node attributes for a node. */ BrainSetNodeAttribute* BrainSet::getNodeAttributes(const int nodeNum) { if (nodeNum >= static_cast(nodeAttributes.size())) { nodeAttributes.resize(nodeNum + 1); } return &nodeAttributes[nodeNum]; } /** * reset node attributes */ void BrainSet::resetNodeAttributes() { if (getNumberOfNodes() > static_cast(nodeAttributes.size())) { nodeAttributes.resize(getNumberOfNodes()); } brainModelSurfaceRegionOfInterestNodeSelection->update(); } /** * clear the node attributes */ void BrainSet::clearNodeAttributes() { resetNodeAttributes(); const int numNodes = getNumberOfNodes(); for (int i = 0; i < numNodes; i++) { nodeAttributes[i].reset(); } } /// find a node with the specified morph row and column (returns -1 if not found) int BrainSet::getNodeWithMorphRowColumn(const int row, const int column, const int startAtNode) const { const int numNodes = static_cast(nodeAttributes.size()); for (int i = startAtNode; i < numNodes; i++) { if ((nodeAttributes[i].morphRow == row) && (nodeAttributes[i].morphColumn == column)) { return i; } } return -1; } /** * export byu surface file. */ void BrainSet::exportByuSurfaceFile(const BrainModelSurface* bms, const QString& filename) throw (FileException) { if (bms != NULL) { vtkPolyData* polyData = bms->convertToVtkPolyData(); if (polyData != NULL) { vtkBYUWriter *writer = vtkBYUWriter::New(); writer->SetInput(polyData); writer->SetHeader("Written by Caret"); writer->SetGeometryFileName((char*)filename.toAscii().constData()); writer->Write(); writer->Delete(); polyData->Delete(); } } } /** * export inventor surface file. */ void BrainSet::exportInventorSurfaceFile(const BrainModelSurface* bms, const QString& filename) throw (FileException) { if (bms != NULL) { vtkPolyData* polyData = bms->convertToVtkPolyData(); if (polyData != NULL) { const int numNodes = getNumberOfNodes(); vtkUnsignedCharArray *colors = vtkUnsignedCharArray::New(); colors->SetNumberOfComponents(3); colors->SetNumberOfTuples(numNodes); BrainModelSurfaceNodeColoring* bsnc = getNodeColoring(); const int model = bms->getBrainModelIndex(); for (int i = 0; i < numNodes; i++) { const unsigned char* charRgb = bsnc->getNodeColor(model, i); float rgb[3]; rgb[0] = charRgb[0]; rgb[1] = charRgb[1]; rgb[2] = charRgb[2]; colors->InsertTuple(i, rgb); } polyData->GetPointData()->SetScalars(colors); colors->Delete(); vtkIVWriter *writer = vtkIVWriter::New(); writer->SetInput(polyData); writer->SetHeader("Written by Caret"); writer->SetFileName((char*)filename.toAscii().constData()); writer->Write(); writer->Delete(); polyData->Delete(); } } } /** * export stl surface file. */ void BrainSet::exportStlSurfaceFile(const BrainModelSurface* bms, const QString& filename) throw (FileException) { if (bms != NULL) { vtkPolyData* polyData = bms->convertToVtkPolyData(); if (polyData != NULL) { vtkSTLWriter *writer = vtkSTLWriter::New(); writer->SetInput(polyData); writer->SetHeader("Written by Caret"); writer->SetFileName((char*)filename.toAscii().constData()); writer->Write(); writer->Delete(); polyData->Delete(); } } } /** * export wavefront object surface file. */ void BrainSet::exportWavefrontSurfaceFile(const BrainModelSurface* /*bms*/, const QString& /*filename*/) throw (FileException) { throw FileException("Export to Wavefront not supported."); /* RENABLING WILL CAUSE LINK ERRORS!!! to Xt libs and others const QString fileExt = FileUtilities::filenameExtension(filename); QString filePrefix = filename; if (fileExt == ".obj") { filePrefix = FileUtilities::filenameWithoutExtension(filename); } if (bms != NULL) { vtkPolyData* polyData = convertToVtkPolyData(bms, true); if (polyData != NULL) { vtkPolyDataMapper* polyDataMapper = vtkPolyDataMapper::New(); polyDataMapper->SetInput(polyData); polyDataMapper->SetColorModeToDefault(); polyDataMapper->SetScalarModeToUsePointData(); vtkActor* actor = vtkActor::New(); actor->SetMapper(polyDataMapper); vtkRenderer* renderer = vtkRenderer::New(); renderer->AddActor(actor); renderer->SetBackground(0, 0, 0); vtkRenderWindow* window = vtkRenderWindow::New(); window->AddRenderer(renderer); window->SetSize(500, 500); vtkOBJExporter* obj = vtkOBJExporter::New(); obj->SetRenderWindow(window); obj->SetFilePrefix(filePrefix.toAscii().constData()); obj->Write(); obj->Delete(); window->Delete(); renderer->Delete(); actor->Delete(); polyDataMapper->Delete(); polyData->Delete(); } } */ } /** * export 3dStudio ASE surface file. */ void BrainSet::export3DStudioASESurfaceFile(const BrainModelSurface* bms, const QString& filename) throw (FileException) { if (bms != NULL) { QFile file(filename); if (file.open(QIODevice::WriteOnly)) { QTextStream stream(&file); stream.setRealNumberNotation(QTextStream::FixedNotation); stream.setRealNumberPrecision(6); stream << "*3DSMAX_ASCIIEXPORT 200\n"; stream << "*COMMENT \"cube.ase, created by IVCON.\"\n"; stream << "*COMMENT \"Original data in cube.iv\"\n"; stream << "*SCENE {\n"; stream << " *SCENE_FILENAME \"\"\n"; stream << " *SCENE_FIRSTFRAME 0\n"; stream << " *SCENE_LASTFRAME 100\n"; stream << " *SCENE_FRAMESPEED 30\n"; stream << " *SCENE_TICKSPERFRAME 160\n"; stream << " *SCENE_BACKGROUND_STATIC 0.0000 0.0000 0.0000\n"; stream << " *SCENE_AMBIENT_STATIC 0.0431 0.0431 0.0431\n"; stream << "}\n"; stream << "\n"; stream << "*MATERIAL_LIST {\n"; stream << " *MATERIAL_COUNT 1\n"; stream << " *MATERIAL 0 {\n"; stream << " *MATERIAL_NAME \"surface\"\n"; stream << " *MATERIAL_AMBIENT 0.7 0.7 0.7 \n"; stream << " *MATERIAL_DIFFUSE 0.8 0.8 0.8 \n"; stream << " *MATERIAL_SHADING phong\n"; stream << " *MATERIAL_SHINE 0.3\n"; stream << " }\n"; stream << "}\n"; stream << "\n"; stream << "*GEOMOBJECT {\n"; stream << " *NODE_NAME \"Object01\"\n"; stream << " *NODE_TM {\n"; stream << " *NODE_NAME \"Object01\"\n"; stream << " *INHERIT_POS 0 0 0\n"; stream << " *INHERIT_ROT 0 0 0\n"; stream << " *INHERIT_SCL 0 0 0\n"; stream << " *TM_ROW0 1.0000 0.0000 0.0000\n"; stream << " *TM_ROW1 0.0000 1.0000 0.0000\n"; stream << " *TM_ROW2 0.0000 0.0000 1.0000\n"; stream << " *TM_ROW3 0.0000 0.0000 0.0000\n"; stream << " *TM_POS 0.0000 0.0000 0.0000\n"; stream << " *TM_ROTAXIS 0.0000 0.0000 0.0000\n"; stream << " *TM_ROTANGLE 0.0000\n"; stream << " *TM_SCALE 1.0000 1.0000 1.0000\n"; stream << " *TM_SCALEAXIS 0.0000 0.0000 0.0000\n"; stream << " *TM_SCALEAXISANG 0.0000\n"; stream << " }\n"; stream << "\n"; const CoordinateFile* cf = bms->getCoordinateFile(); const int numNodes = cf->getNumberOfCoordinates(); const TopologyFile* tf = bms->getTopologyFile(); const int numTiles = tf->getNumberOfTiles(); stream << " *MESH {\n"; stream << " *TIMEVALUE 0\n"; stream << " *MESH_NUMVERTEX " << numNodes << "\n"; stream << " *MESH_NUMFACES " << numTiles << "\n"; stream << " *MESH_VERTEX_LIST {\n"; for (int i = 0; i < numNodes; i++) { const float* xyz = cf->getCoordinate(i); stream << " *MESH_VERTEX " << i << " " << xyz[0] << " " << xyz[1] << " " << xyz[2] << "\n"; } stream << " }\n"; stream << "\n"; stream << " *MESH_FACE_LIST {\n"; for (int i = 0; i < numTiles; i++) { const int* tileNodes = tf->getTile(i); stream << " *MESH_FACE " << i << ": " << "A: " << tileNodes[0] << " " << "B: " << tileNodes[1] << " " << "C: " << tileNodes[2] << " " << "AB: 1 BC: 1 CA: 1 *MESH_SMOOTHING 1 *MESH_MTLID 0" << "\n"; } stream << " }\n"; stream << "\n"; stream << " *MESH_NUMTVERTEX 0 \n"; stream << " *MESH_NUMCVERTEX " << numNodes << " \n"; stream << " *MESH_CVERTLIST {" << "\n"; BrainModelSurfaceNodeColoring* bsnc = getNodeColoring(); const int modelIndex = getBrainModelIndex(bms); for (int i = 0; i < numNodes; i++) { const unsigned char* color = bsnc->getNodeColor(modelIndex, i); const float rgb[3] = { color[0] / 255.0, color[1] / 255.0, color[2] / 255.0 }; stream << " *MESH_VERTCOL " << i << " " << rgb[0] << " " << rgb[1] << " " << rgb[2] << "\n"; } stream << " }\n"; stream << " *MESH_NORMALS {\n"; for (int i = 0; i < numNodes; i++) { const float* normal = bms->getNormal(i); stream << " *MESH_VERTEXNORMAL " << i << " " << normal[0] << " " << normal[1] << " " << normal[2] << "\n"; } stream << " }\n"; stream << "\n"; /* *MESH_FACENORMAL 6 0.000000 0.000000 1.000000 *MESH_VERTEXNORMAL 0 0.000000 0.000000 1.000000 *MESH_VERTEXNORMAL 1 0.000000 0.000000 1.000000 *MESH_VERTEXNORMAL 2 0.000000 0.000000 1.000000 *MESH_VERTEXNORMAL 3 0.000000 0.000000 1.000000 */ stream << " *PROP_MOTIONBLUR 0\n"; stream << " *PROP_CASTSHADOW 1\n"; stream << " *PROP_RECVSHADOW 1\n"; stream << " }\n"; stream << "}\n"; stream << "\n"; } else { throw FileException(filename, "Unable to open for writing"); } } } /** * export vrml surface file. */ void BrainSet::exportVrmlSurfaceFile(const BrainModelSurface* bms, const QString& filename) throw (FileException) { /* if (bms != NULL) { vtkPolyData* polyData = convertToVtkPolyData(bms, true); if (polyData != NULL) { vtkPolyDataMapper* polyDataMapper = vtkPolyDataMapper::New(); polyDataMapper->SetInput(polyData); polyDataMapper->SetColorModeToDefault(); polyDataMapper->SetScalarModeToUsePointData(); vtkActor* actor = vtkActor::New(); actor->SetMapper(polyDataMapper); vtkRenderer* renderer = vtkRenderer::New(); renderer->AddActor(actor); renderer->SetBackground(0, 0, 0); vtkRenderWindow* window = vtkRenderWindow::New(); window->AddRenderer(renderer); window->SetSize(500, 500); vtkVRMLExporter* vrml = vtkVRMLExporter::New(); vrml->SetRenderWindow(window); vrml->SetFileName(filename.toAscii().constData()); vrml->Write(); vrml->Delete(); window->Delete(); renderer->Delete(); actor->Delete(); polyDataMapper->Delete(); polyData->Delete(); } } */ if (bms == NULL) { return; } QFile file(filename); if (file.open(QIODevice::WriteOnly)) { QTextStream stream(&file); stream.setRealNumberNotation(QTextStream::FixedNotation); stream.setRealNumberPrecision(6); stream << "#VRML V2.0 utf8\n"; stream << "\n"; stream << "WorldInfo {\n"; stream << " title \"title\"\n"; stream << " info \"Written by Caret\"\n"; stream << "}\n"; stream << "\n"; stream << "NavigationInfo {\n"; stream << " headlight TRUE\n"; stream << " speed 20.0\n"; stream << " type [\"EXAMINE\", \"WALK\", \"FLY\",\"ANY\"]\n"; stream << "}\n\n"; //if (lightOn) { const float lightPos[3] = { 0.0, 0.0, 1000.0 }; stream << "PointLight {\n"; stream << " ambientIntensity 1.0\n"; stream << " attenuation 1.0 1.0 1.0\n"; stream << " color 1.0 1.0 1.0\n"; stream << " intensity 1.0\n"; stream << " location " << lightPos[0] << " " << lightPos[1] << " " << lightPos[2] << "\n"; stream << " on TRUE\n"; stream << " radius 10000.0\n"; stream << "}\n"; //} stream << "Shape {\n"; stream << " appearance Appearance {\n"; stream << " material Material {\n"; stream << " ambientIntensity 0\n"; stream << " diffuseColor 1 1 1\n"; stream << " specularColor 0 0 0\n"; stream << " shininess 0.0078125\n"; stream << " transparency 0\n"; stream << " }\n"; stream << " }\n"; stream << "\n"; stream << " geometry IndexedFaceSet {\n"; stream << " solid FALSE\n"; // // nodes // const CoordinateFile* cf = bms->getCoordinateFile(); const int numCoords = cf->getNumberOfCoordinates(); stream << " coord Coordinate {\n"; stream << " point [\n"; for (int i = 0; i < numCoords; i++) { const float* xyz = cf->getCoordinate(i); stream << " " << xyz[0] << " " << xyz[1] << " " << xyz[2]; if (i < (numCoords - 1)) { stream << ","; } stream << "\n"; } stream << " ]\n"; stream << " }\n"; // coordCoordinate stream << "\n"; // // Tiles // const TopologyFile* tf = bms->getTopologyFile(); const int numTiles = tf->getNumberOfTiles(); stream << " coordIndex [\n"; for (int i = 0; i < numTiles; i++) { const int* t = tf->getTile(i); stream << " " << t[0] << " " << t[1] << " " << t[2] << " -1"; if (i < (numTiles - 1)) { stream << ","; } stream << "\n"; } stream << " ]\n"; // coordIndex stream << "\n"; // // Node Normals // stream << " normal Normal {\n"; stream << " vector [\n"; for (int i = 0; i < numCoords; i++) { const float* n = bms->getNormal(i); stream << " " << n[0] << " " << n[1] << " " << n[2]; if (i < (numCoords - 1)) { stream << ","; } stream << "\n"; } stream << " ]\n"; stream << " }\n"; // normal Normal stream << "\n"; // // Node Colors // stream << " color Color {\n"; stream << " color [\n"; BrainModelSurfaceNodeColoring* bsnc = getNodeColoring(); const int model = bms->getBrainModelIndex(); for (int i = 0; i < numCoords; i++) { const unsigned char* charRgb = bsnc->getNodeColor(model, i); float rgb[3]; rgb[0] = charRgb[0]; rgb[1] = charRgb[1]; rgb[2] = charRgb[2]; stream << " " << rgb[0]/255.0 << " " << rgb[1]/255.0 << " " << rgb[2]/255.0; if (i < (numCoords - 1)) { stream << ","; } stream << "\n"; } stream << " ]\n"; stream << " }\n"; // color Color stream << "\n"; stream << " }\n"; // geometry IndexedFaceSet stream << "}\n"; // Shape file.close(); } else { throw FileException(filename, "Unable to open for writing"); } } /** * export vtk surface file */ void BrainSet::exportVtkSurfaceFile(const BrainModelSurface* bms, const QString& filename, const bool exportColors) throw (FileException) { if (bms != NULL) { vtkPolyData* polyData = convertToVtkPolyData(bms, exportColors); if (polyData != NULL) { vtkPolyDataWriter *writer = vtkPolyDataWriter::New(); writer->SetInput(polyData); writer->SetHeader("Written by Caret"); writer->SetFileName((char*)filename.toAscii().constData()); writer->Write(); writer->Delete(); polyData->Delete(); } } } /** * export vtk XML surface file */ void BrainSet::exportVtkXmlSurfaceFile(const BrainModelSurface* bms, const QString& filename, const bool exportColors) throw (FileException) { if (bms != NULL) { vtkPolyData* polyData = convertToVtkPolyData(bms, exportColors); if (polyData != NULL) { vtkXMLPolyDataWriter *writer = vtkXMLPolyDataWriter::New(); writer->SetInput(polyData); writer->SetDataModeToAscii(); writer->SetFileName((char*)filename.toAscii().constData()); writer->Write(); writer->Delete(); polyData->Delete(); } } } /** * Convert a BrainModelSurface to a vtkPolyData file with option of node colors */ vtkPolyData* BrainSet::convertToVtkPolyData(const BrainModelSurface* bms, const bool useNodeColors) { vtkPolyData* polyData = NULL; if (bms != NULL) { polyData = bms->convertToVtkPolyData(); if (polyData != NULL) { if (useNodeColors) { vtkUnsignedCharArray *colors = vtkUnsignedCharArray::New(); colors->SetNumberOfComponents(3); const int numNodes = getNumberOfNodes(); colors->SetNumberOfTuples(numNodes); BrainModelSurfaceNodeColoring* bsnc = getNodeColoring(); const int model = bms->getBrainModelIndex(); for (int i = 0; i < numNodes; i++) { const unsigned char* charRgb = bsnc->getNodeColor(model, i); float rgb[3]; rgb[0] = charRgb[0]; rgb[1] = charRgb[1]; rgb[2] = charRgb[2]; colors->InsertTuple(i, rgb); } polyData->GetPointData()->SetScalars(colors); colors->Delete(); } } } return polyData; } /** * Import Raw volume file. */ void BrainSet::importRawVolumeFile(const QString& filename, const VolumeFile::VOLUME_TYPE volumeType, const int dimensions[3], const VolumeFile::VOXEL_DATA_TYPE voxelDataType, const bool byteSwap) throw (FileException) { VolumeFile* vf = new VolumeFile; try { switch (volumeType) { case VolumeFile::VOLUME_TYPE_FUNCTIONAL: break; case VolumeFile::VOLUME_TYPE_PAINT: break; case VolumeFile::VOLUME_TYPE_PROB_ATLAS: break; case VolumeFile::VOLUME_TYPE_RGB: break; case VolumeFile::VOLUME_TYPE_ROI: throw FileException(FileUtilities::basename(filename), "ROI type not supported."); break; case VolumeFile::VOLUME_TYPE_SEGMENTATION: break; case VolumeFile::VOLUME_TYPE_ANATOMY: break; case VolumeFile::VOLUME_TYPE_VECTOR: break; case VolumeFile::VOLUME_TYPE_UNKNOWN: throw FileException(FileUtilities::basename(filename), "Unrecognized volume type"); break; } const VolumeFile::ORIENTATION orient[3] = { VolumeFile::ORIENTATION_UNKNOWN, VolumeFile::ORIENTATION_UNKNOWN, VolumeFile::ORIENTATION_UNKNOWN }; const float origin[3] = { 0.0, 0.0, 0.0 }; const float space[3] = { 1.0, 1.0, 1.0 }; vf->readFileVolumeRaw(filename, 0, voxelDataType, dimensions, orient, origin, space, byteSwap); addVolumeFile(volumeType, vf, filename, true, false); } catch (FileException& e) { delete vf; throw e; } } /** * Import MINC volume file. */ void BrainSet::importMincVolumeFile(const QString& filename, const VolumeFile::VOLUME_TYPE volumeType) throw (FileException) { VolumeFile* vf = new VolumeFile; try { switch (volumeType) { case VolumeFile::VOLUME_TYPE_FUNCTIONAL: break; case VolumeFile::VOLUME_TYPE_PAINT: break; case VolumeFile::VOLUME_TYPE_PROB_ATLAS: break; case VolumeFile::VOLUME_TYPE_RGB: break; case VolumeFile::VOLUME_TYPE_ROI: throw FileException(FileUtilities::basename(filename), "ROI volume type not supported."); break; case VolumeFile::VOLUME_TYPE_SEGMENTATION: break; case VolumeFile::VOLUME_TYPE_ANATOMY: break; case VolumeFile::VOLUME_TYPE_VECTOR: break; case VolumeFile::VOLUME_TYPE_UNKNOWN: throw FileException(FileUtilities::basename(filename), "Unrecognized volume type"); break; } vf->importMincVolume(filename); addVolumeFile(volumeType, vf, filename, true, false); } catch (FileException& e) { delete vf; throw e; } } /** * Import Analyze volume file. */ void BrainSet::importAnalyzeVolumeFile(const QString& filename, const VolumeFile::VOLUME_TYPE volumeType) throw (FileException) { VolumeFile* vf = new VolumeFile; try { switch (volumeType) { case VolumeFile::VOLUME_TYPE_FUNCTIONAL: break; case VolumeFile::VOLUME_TYPE_PAINT: break; case VolumeFile::VOLUME_TYPE_PROB_ATLAS: break; case VolumeFile::VOLUME_TYPE_RGB: break; case VolumeFile::VOLUME_TYPE_ROI: throw FileException(FileUtilities::basename(filename), "ROI volume type not supported."); break; case VolumeFile::VOLUME_TYPE_SEGMENTATION: break; case VolumeFile::VOLUME_TYPE_ANATOMY: break; case VolumeFile::VOLUME_TYPE_VECTOR: break; case VolumeFile::VOLUME_TYPE_UNKNOWN: throw FileException(FileUtilities::basename(filename), "Unrecognized volume type"); break; } vf->importAnalyzeVolume(filename); addVolumeFile(volumeType, vf, filename, true, false); } catch (FileException& e) { delete vf; throw e; } } /** * Import VTK Structured Points volume file. */ void BrainSet::importVtkStructuredPointsVolumeFile(const QString& filename, const VolumeFile::VOLUME_TYPE volumeType) throw (FileException) { VolumeFile* vf = new VolumeFile; try { switch (volumeType) { case VolumeFile::VOLUME_TYPE_FUNCTIONAL: break; case VolumeFile::VOLUME_TYPE_PAINT: break; case VolumeFile::VOLUME_TYPE_PROB_ATLAS: break; case VolumeFile::VOLUME_TYPE_RGB: break; case VolumeFile::VOLUME_TYPE_ROI: throw FileException(FileUtilities::basename(filename), "ROI volume type not supported."); break; case VolumeFile::VOLUME_TYPE_SEGMENTATION: break; case VolumeFile::VOLUME_TYPE_ANATOMY: break; case VolumeFile::VOLUME_TYPE_VECTOR: break; case VolumeFile::VOLUME_TYPE_UNKNOWN: throw FileException(FileUtilities::basename(filename), "Unrecognized volume type"); break; } vf->importVtkStructuredPointsVolume(filename); addVolumeFile(volumeType, vf, filename, true, false); } catch (FileException& e) { delete vf; throw e; } } /** * Export VTK Structured Points volume file. */ void BrainSet::exportVtkStructuredPointsVolumeFile(VolumeFile* vf, const QString& filename) throw (FileException) { vf->exportVtkStructuredPointsVolume(filename); } /** * Export Analyze volume file. */ void BrainSet::exportAnalyzeVolumeFile(VolumeFile* vf, const QString& filename) throw (FileException) { vf->exportAnalyzeVolume(filename); } /** * Export Minc volume file. */ void BrainSet::exportMincVolumeFile(VolumeFile* vf, const QString& filename) throw (FileException) { vf->exportMincVolume(filename); } /** * import byu surface file. */ void BrainSet::importByuSurfaceFile(const QString& filename, const bool importCoordinates, const bool importTopology, const BrainModelSurface::SURFACE_TYPES surfaceType, const TopologyFile::TOPOLOGY_TYPES topologyType) throw (FileException) { vtkBYUReader* reader = vtkBYUReader::New(); reader->SetGeometryFileName((char*)filename.toAscii().constData()); reader->ReadDisplacementOff(); reader->ReadScalarOff(); reader->ReadTextureOff(); reader->Update(); vtkPolyData* polyData = reader->GetOutput(); try { importVtkTypeFileHelper(filename, polyData, importCoordinates, importTopology, false, surfaceType, topologyType); } catch (FileException& e) { reader->Delete(); throw e; } // don't do this polyData->Delete(); reader->Delete(); } /** * import stl surface file. */ void BrainSet::importStlSurfaceFile(const QString& filename, const bool importCoordinates, const bool importTopology, const BrainModelSurface::SURFACE_TYPES surfaceType, const TopologyFile::TOPOLOGY_TYPES topologyType) throw (FileException) { vtkSTLReader* reader = vtkSTLReader::New(); reader->SetFileName((char*)filename.toAscii().constData()); reader->Update(); vtkPolyData* polyData = reader->GetOutput(); try { importVtkTypeFileHelper(filename, polyData, importCoordinates, importTopology, false, surfaceType, topologyType); } catch (FileException& e) { reader->Delete(); throw e; } // don't do this polyData->Delete(); reader->Delete(); } /** * import vtk file */ void BrainSet::importVtkSurfaceFile(const QString& filename, const bool importCoordinates, const bool importTopology, const bool importColors, const BrainModelSurface::SURFACE_TYPES surfaceType, const TopologyFile::TOPOLOGY_TYPES topologyType) throw (FileException) { vtkPolyDataReader* reader = vtkPolyDataReader::New(); reader->SetFileName((char*)filename.toAscii().constData()); reader->Update(); vtkPolyData* polyData = reader->GetOutput(); try { importVtkTypeFileHelper(filename, polyData, importCoordinates, importTopology, importColors, surfaceType, topologyType); } catch (FileException& e) { reader->Delete(); throw e; } // don't do this polyData->Delete(); reader->Delete(); } /** * import vtk XML file */ void BrainSet::importVtkXmlSurfaceFile(const QString& filename, const bool importCoordinates, const bool importTopology, const bool importColors, const BrainModelSurface::SURFACE_TYPES surfaceType, const TopologyFile::TOPOLOGY_TYPES topologyType) throw (FileException) { vtkXMLPolyDataReader* reader = vtkXMLPolyDataReader::New(); reader->SetFileName((char*)filename.toAscii().constData()); reader->Update(); vtkPolyData* polyData = reader->GetOutput(); try { importVtkTypeFileHelper(filename, polyData, importCoordinates, importTopology, importColors, surfaceType, topologyType); } catch (FileException& e) { reader->Delete(); throw e; } // don't do this polyData->Delete(); reader->Delete(); } /** * Simplify the surface (this also removed all other surfaces and volumes). */ void BrainSet::simplifySurface(const BrainModelSurface* bms, const int maxPolygons) throw (FileException) { // // Decimate the surface // vtkPolyData* polyData = bms->simplifySurface(maxPolygons); if (polyData != NULL) { // // Clear out the brain set // reset(); // // "Import" the decimated surface // TopologyFile::TOPOLOGY_TYPES tt = TopologyFile::TOPOLOGY_TYPE_UNKNOWN; const TopologyFile* tf = bms->getTopologyFile(); if (tf != NULL) { tt = tf->getTopologyType(); } importVtkTypeFileHelper("", polyData, true, true, false, bms->getSurfaceType(), tt); // // Free up memory // polyData->Delete(); } } /** * import vtk type file helper. */ void BrainSet::importVtkTypeFileHelper(const QString& filename, vtkPolyData* polyData, const bool importCoordinates, const bool importTopology, const bool importColors, const BrainModelSurface::SURFACE_TYPES surfaceType, const TopologyFile::TOPOLOGY_TYPES topologyType) throw (FileException) { if (polyData == NULL) { throw FileException(filename, "Unable to read file"); } int numNodes = getNumberOfNodes(); bool noNodesFlag = (numNodes == 0); const int numPolys = polyData->GetNumberOfPolys(); const int numPoints = polyData->GetNumberOfPoints(); if (numPoints <= 0) { throw FileException(filename, "File has no points"); } if (numPolys <= 0) { if (polyData->GetNumberOfStrips() <= 0) { throw FileException(filename, "File has no triangles or strips."); } } if (noNodesFlag == false) { if (numPoints != numNodes) { throw FileException(filename, "File has different number of nodes than current surfaces."); } } if (importTopology) { // // Get the topology // TopologyFile* vtkTopology = new TopologyFile; try { vtkTopology->importFromVtkFile(polyData); vtkTopology->setTopologyType(topologyType); addTopologyFile(vtkTopology); setSelectedTopologyFiles(); } catch (FileException& /*e*/) { delete vtkTopology; throw FileException(filename, "Error getting topology"); } } if (importCoordinates) { BrainModelSurface* bms = new BrainModelSurface(this); bms->importFromVtkFile(polyData, filename); if (numNodes == 0) { if (bms->getNumberOfNodes() > 0) { numNodesMessage = " contains a different number of nodes than "; numNodesMessage.append(FileUtilities::basename(filename)); } else { delete bms; bms = NULL; throw FileException(filename, "Contains no nodes"); } } else if (numNodes != bms->getNumberOfNodes()) { delete bms; bms = NULL; throw FileException(FileUtilities::basename(filename), numNodesMessage); } if (getNumberOfTopologyFiles() > 0) { bms->setTopologyFile(getTopologyFile(getNumberOfTopologyFiles() - 1)); } bms->orientTilesConsistently(); bms->computeNormals(); bms->orientNormalsOut(); bms->setSurfaceType(surfaceType); bms->setStructure(getStructure()); addBrainModel(bms); } if (importColors) { rgbPaintFile->importFromVtkFile(polyData); } if (noNodesFlag) { // // Reset node coloring // getPrimarySurfaceOverlay()->setOverlay(-1, BrainModelSurfaceOverlay::OVERLAY_NONE); getSecondarySurfaceOverlay()->setOverlay(-1, BrainModelSurfaceOverlay::OVERLAY_NONE); getSurfaceUnderlay()->setOverlay(-1, BrainModelSurfaceOverlay::OVERLAY_NONE); if (importColors) { if (rgbPaintFile->getNumberOfColumns() > 0) { getPrimarySurfaceOverlay()->setOverlay(-1, BrainModelSurfaceOverlay::OVERLAY_RGB_PAINT); } } postSpecFileReadInitializations(); } } /** * import Neurolucida file. */ void BrainSet::importNeurolucidaFile(const QString& filename, const bool importMarkersAsCells, const bool importContours, const bool appendToExistingContours, const bool appendToExistingContourCells) throw (FileException) { NeurolucidaFile nf; nf.readFile(filename); BrainModelContours* bmc = getBrainModelContours(-1); if (bmc == NULL) { bmc = new BrainModelContours(this); addBrainModel(bmc); } if (importContours) { try { if (appendToExistingContours == false) { clearContourFile(false); } bmc->importNeurolucidaFile(nf, appendToExistingContours); } catch (FileException& e) { throw e; } } if (importMarkersAsCells) { if (appendToExistingContourCells == false) { clearContourCellFile(); clearContourCellColorFile(); } try { contourCellFile->importNeurolucidaFile(nf); contourCellColorFile->importNeurolucidaFileColors(nf); } catch (FileException& e) { throw e; } } displaySettingsContours->update(); displaySettingsCells->update(); } /** * import MD Plot file. */ void BrainSet::importMDPlotFile(const QString& filename, const bool importPointsAsContourCells, const bool importLinesAsContours, const bool appendToExistingContours, const bool appendToExistingContourCells) throw (FileException) { MDPlotFile mdf; mdf.readFile(filename); BrainModelContours* bmc = getBrainModelContours(-1); if (bmc == NULL) { bmc = new BrainModelContours(this); addBrainModel(bmc); } if (importLinesAsContours) { try { if (appendToExistingContours == false) { clearContourFile(false); } bmc->importMDPlotFile(mdf, appendToExistingContours); } catch (FileException& e) { throw e; } } if (importPointsAsContourCells) { if (appendToExistingContourCells == false) { clearContourCellFile(); clearContourCellColorFile(); } try { contourCellFile->importMDPlotFile(mdf); contourCellColorFile->importMDPlotFileColors(); } catch (FileException& e) { throw e; } } displaySettingsContours->update(); displaySettingsCells->update(); } /** * import mni obj surface file. */ void BrainSet::importMniObjSurfaceFile(const QString& filename, const bool importCoordinates, const bool importTopology, const bool importColors, const BrainModelSurface::SURFACE_TYPES surfaceType, const TopologyFile::TOPOLOGY_TYPES topologyType) throw (FileException) { int numNodes = getNumberOfNodes(); bool noNodesFlag = (numNodes == 0); MniObjSurfaceFile mni; try { mni.readFile(filename); if (importTopology) { // // Get the topology // TopologyFile* mniTopology = new TopologyFile; try { mniTopology->importFromMniObjSurfaceFile(mni); mniTopology->setTopologyType(topologyType); addTopologyFile(mniTopology); setSelectedTopologyFiles(); } catch (FileException& /*e*/) { delete mniTopology; throw FileException(filename, "Error getting topology"); } } // // Get the coordinates // if (mni.getNumberOfPoints() > 0) { if (importCoordinates) { BrainModelSurface* bms = new BrainModelSurface(this); bms->importFromMniObjSurfaceFile(mni); if (numNodes == 0) { if (bms->getNumberOfNodes() > 0) { numNodesMessage = " contains a different number of nodes than "; numNodesMessage.append(FileUtilities::basename(filename)); } else { delete bms; bms = NULL; throw FileException(filename, "Contains no nodes"); } } else if (numNodes != bms->getNumberOfNodes()) { delete bms; bms = NULL; throw FileException(FileUtilities::basename(filename), numNodesMessage); } if (getNumberOfTopologyFiles() > 0) { bms->setTopologyFile(getTopologyFile(getNumberOfTopologyFiles() - 1)); } bms->orientTilesConsistently(); bms->computeNormals(); bms->setSurfaceType(surfaceType); bms->setStructure(getStructure()); addBrainModel(bms); } numNodes = getNumberOfNodes(); if (importColors && (numNodes > 0)) { // // Add new column or get the column in the rgb file // const QString rgbColumnName("MNI OBJ Surface"); int column = 0; if (rgbPaintFile->getNumberOfColumns() <= 0) { rgbPaintFile->setNumberOfNodesAndColumns(numNodes, 1); column = 0; } else { rgbPaintFile->addColumns(1); column = paintFile->getNumberOfColumns() - 1; } rgbPaintFile->setColumnName(0, rgbColumnName); // // Converts a brain voyager color index into a paint file index // for (int i = 0; i < numNodes; i++) { const unsigned char* rgba = mni.getColorRGBA(i); const float r = rgba[0]; const float g = rgba[1]; const float b = rgba[2]; rgbPaintFile->setRgb(i, column, r, g, b); } } } else { throw FileException(filename, "Has no coordinates"); } } catch (FileException& e) { throw e; } if (noNodesFlag) { postSpecFileReadInitializations(); } } /** * import brain voyager file */ void BrainSet::importBrainVoyagerFile(const QString& filename, const bool importCoordinates, const bool importTopology, const bool importColors, const BrainModelSurface::SURFACE_TYPES surfaceType, const TopologyFile::TOPOLOGY_TYPES topologyType) throw (FileException) { int numNodes = getNumberOfNodes(); bool noNodesFlag = (numNodes == 0); BrainVoyagerFile bvf; try { bvf.readFile(filename); if (importTopology) { // // Get the topology // TopologyFile* bvTopology = new TopologyFile; try { bvTopology->importFromBrainVoyagerFile(bvf); bvTopology->setTopologyType(topologyType); addTopologyFile(bvTopology); setSelectedTopologyFiles(); } catch (FileException& /*e*/) { delete bvTopology; throw FileException(filename, "Error getting topology"); } } // // Get the coordinates // if (bvf.getNumberOfVertices() > 0) { if (importCoordinates) { BrainModelSurface* bms = new BrainModelSurface(this); bms->importFromBrainVoyagerFile(bvf); if (numNodes == 0) { if (bms->getNumberOfNodes() > 0) { numNodesMessage = " contains a different number of nodes than "; numNodesMessage.append(FileUtilities::basename(filename)); } else { delete bms; bms = NULL; throw FileException(filename, "Contains no nodes"); } } else if (numNodes != bms->getNumberOfNodes()) { delete bms; bms = NULL; throw FileException(FileUtilities::basename(filename), numNodesMessage); } if (getNumberOfTopologyFiles() > 0) { bms->setTopologyFile(getTopologyFile(getNumberOfTopologyFiles() - 1)); } bms->orientTilesConsistently(); bms->computeNormals(); bms->setSurfaceType(surfaceType); bms->setStructure(getStructure()); addBrainModel(bms); } numNodes = getNumberOfNodes(); if (importColors && (numNodes > 0)) { // // Add new column or get the column in the paint file // const QString paintColumnName("Brain_Voyager"); int column = 0; if (paintFile->getNumberOfColumns() <= 0) { paintFile->setNumberOfNodesAndColumns(numNodes, 1); column = 0; } else { paintFile->addColumns(1); column = paintFile->getNumberOfColumns() - 1; } paintFile->setColumnName(0, paintColumnName); const int colorTableSize = bvf.getColorTableSize(); if (colorTableSize > 0) { // // Converts a brain voyager color index into a paint file index // int* colorTableToPaintIndices = new int[colorTableSize]; for (int i = 0; i < colorTableSize; i++) { const BrainVoyagerColorTableElement* te = bvf.getColorTableElement(i); colorTableToPaintIndices[i] = paintFile->addPaintName(te->getColorName()); // // Add color to area color file // unsigned char rgb[3]; te->getRgb(rgb); areaColorFile->addColor(te->getColorName(), rgb[0], rgb[1], rgb[2], 255, 2.0, 1.0); } // // Set the paint index for the vertex // for (int i = 0; i < numNodes; i++) { const int index = bvf.getVertexColorIndex(i); if (index < colorTableSize) { paintFile->setPaint(i, column, colorTableToPaintIndices[index]); } else { std::cout << "Brain Voyager Import Node: " << i << " has an invalid color table index = " << index << std::endl; } } delete[] colorTableToPaintIndices; } } } else { throw FileException(filename, "Has no coordinates"); } } catch (FileException& e) { throw e; } if (noNodesFlag) { postSpecFileReadInitializations(); } } /** * Export a brain model surface to a free surfer ascii surface file. */ void BrainSet::exportFreeSurferAsciiSurfaceFile(BrainModelSurface* bms, const QString& filename) throw (FileException) { FreeSurferSurfaceFile fssf; TopologyFile* tf = bms->getTopologyFile(); CoordinateFile* cf = bms->getCoordinateFile(); fssf.setNumberOfVerticesAndTriangles(cf->getNumberOfCoordinates(), tf->getNumberOfTiles()); tf->exportToFreeSurferSurfaceFile(fssf); cf->exportToFreeSurferSurfaceFile(fssf); fssf.writeFile(filename); } /** * Import a free surfer ascii surface file. */ void BrainSet::importFreeSurferSurfaceFile(const QString& filename, const bool importCoordinates, const bool importTopology, const AbstractFile::FILE_FORMAT fileFormat, const BrainModelSurface::SURFACE_TYPES surfaceType, const TopologyFile::TOPOLOGY_TYPES topologyType) throw (FileException) { int numNodes = getNumberOfNodes(); bool noNodesFlag = (numNodes == 0); FreeSurferSurfaceFile fssf; fssf.setFileReadType(fileFormat); fssf.readFile(filename); // // Create a new brain model surface and topology file // BrainModelSurface* bms = NULL; TopologyFile* tf = NULL; try { // // If importing topology, copy tiles to the topology file // if (importTopology) { TopologyFile* otherTopoFile = getTopologyClosed(); if (otherTopoFile == NULL) { otherTopoFile = getTopologyOpen(); } if (otherTopoFile == NULL) { otherTopoFile = getTopologyUnknown(); } tf = new TopologyFile; tf->importFromFreeSurferSurfaceFile(fssf, otherTopoFile); tf->setTopologyType(topologyType); } // // Add the new surface // if (importCoordinates) { // // Import the coordinates // bms = new BrainModelSurface(this); CoordinateFile* coords = bms->getCoordinateFile(); coords->importFromFreeSurferSurfaceFile(fssf, numNodes); if (importTopology) { bms->setTopologyFile(tf); } else { bms->setTopologyFile(getTopologyFile(getNumberOfTopologyFiles() - 1)); } bms->orientTilesConsistently(); bms->computeNormals(); bms->setSurfaceType(surfaceType); bms->setStructure(getStructure()); addBrainModel(bms); } // // need this in case topology importing throws an exception // if (importTopology) { addTopologyFile(tf); setSelectedTopologyFiles(); } } catch (FileException& e) { if (bms != NULL) { delete bms; } if (tf != NULL) { delete tf; } throw e; } if (noNodesFlag) { postSpecFileReadInitializations(); } } /** * See if this iteration is one in which the brain model should be redrawn. */ bool BrainSet::isIterationUpdate(const int currentAlgorithmIteration) const { if (currentAlgorithmIteration > 0) { if ((currentAlgorithmIteration % DebugControl::getIterativeUpdate()) != 0) { return false; } } return true; } /** * Request that a brain model be displayed and drawn by the user of this brain set. * If "currentAlgorithmIteration" is greater than zero, the display will only be updated * if "currentAlgorithmIteration" modulus iterativeDrawNumber is zero. */ void BrainSet::drawBrainModel(const int brainModelIndex, const int currentAlgorithmIteration) { if (isIterationUpdate(currentAlgorithmIteration)) { emit signalDisplayBrainModel(brainModelIndex); } } /** * Request that a brain model be displayed and drawn by the user of this brain set. */ void BrainSet::drawBrainModel(const BrainModel* bm, const int currentAlgorithmIteration) { const int numBrains = getNumberOfBrainModels(); for (int i = 0; i < numBrains; i++) { if (bm == brainModels[i]) { drawBrainModel(i, currentAlgorithmIteration); break; } } } /** * get the volume functional file. */ VolumeFile* BrainSet::getVolumeFunctionalFile(const int index) { if ((index >= 0) && (index < static_cast(volumeFunctionalFiles.size()))) { return volumeFunctionalFiles[index]; } else { return NULL; } } /** * get the volume functional file (const method) */ const VolumeFile* BrainSet::getVolumeFunctionalFile(const int index) const { if ((index >= 0) && (index < static_cast(volumeFunctionalFiles.size()))) { return volumeFunctionalFiles[index]; } else { return NULL; } } /** * get the volume paint file */ VolumeFile* BrainSet::getVolumePaintFile(const int index) { if ((index >= 0) && (index < static_cast(volumePaintFiles.size()))) { return volumePaintFiles[index]; } else { return NULL; } } /** * get the volume paint file (const method). */ const VolumeFile* BrainSet::getVolumePaintFile(const int index) const { if ((index >= 0) && (index < static_cast(volumePaintFiles.size()))) { return volumePaintFiles[index]; } else { return NULL; } } /** * get the volume prob atlas file */ VolumeFile* BrainSet::getVolumeProbAtlasFile(const int index) { if ((index >= 0) && (index < static_cast(volumeProbAtlasFiles.size()))) { return volumeProbAtlasFiles[index]; } else { return NULL; } } /** * get the volume prob atlas file (const method). */ const VolumeFile* BrainSet::getVolumeProbAtlasFile(const int index) const { if ((index >= 0) && (index < static_cast(volumeProbAtlasFiles.size()))) { return volumeProbAtlasFiles[index]; } else { return NULL; } } /** * synchronize prob atlas volume region names. */ void BrainSet::synchronizeProbAtlasVolumeRegionNames() { VolumeFile::synchronizeRegionNames(volumeProbAtlasFiles); } /** * get the volume rgb file */ VolumeFile* BrainSet::getVolumeRgbFile(const int index) { if ((index >= 0) && (index < static_cast(volumeRgbFiles.size()))) { return volumeRgbFiles[index]; } else { return NULL; } } /** * get the volume rgb file (const method). */ const VolumeFile* BrainSet::getVolumeRgbFile(const int index) const { if ((index >= 0) && (index < static_cast(volumeRgbFiles.size()))) { return volumeRgbFiles[index]; } else { return NULL; } } /** * get the volume segmentation file. */ VolumeFile* BrainSet::getVolumeSegmentationFile(const int index) { if ((index >= 0) && (index < static_cast(volumeSegmentationFiles.size()))) { return volumeSegmentationFiles[index]; } else { return NULL; } } /** * get the volume segmentation file (const method). */ const VolumeFile* BrainSet::getVolumeSegmentationFile(const int index) const { if ((index >= 0) && (index < static_cast(volumeSegmentationFiles.size()))) { return volumeSegmentationFiles[index]; } else { return NULL; } } /** * get the volume anatomy file. */ VolumeFile* BrainSet::getVolumeAnatomyFile(const int index) { if ((index >= 0) && (index < static_cast(volumeAnatomyFiles.size()))) { return volumeAnatomyFiles[index]; } else { return NULL; } } /** * get the volume anatomy file (const method). */ const VolumeFile* BrainSet::getVolumeAnatomyFile(const int index) const { if ((index >= 0) && (index < static_cast(volumeAnatomyFiles.size()))) { return volumeAnatomyFiles[index]; } else { return NULL; } } /** * get the volume vector file. */ VolumeFile* BrainSet::getVolumeVectorFile(const int index) { if ((index >= 0) && (index < static_cast(volumeVectorFiles.size()))) { return volumeVectorFiles[index]; } else { return NULL; } } /** * get the volume vector file (const method). */ const VolumeFile* BrainSet::getVolumeVectorFile(const int index) const { if ((index >= 0) && (index < static_cast(volumeVectorFiles.size()))) { return volumeVectorFiles[index]; } else { return NULL; } } /** * Get the paint volume file with the specified name (NULL if not found). */ VolumeFile* BrainSet::getVolumePaintFileWithName(const QString& name) { std::vector files; getVolumePaintFiles(files); return getVolumeFileWithName(files, name); } /** * Get the prob atlas volume file with the specified name (NULL if not found). */ VolumeFile* BrainSet::getVolumeProbAtlasFileWithName(const QString& name) { std::vector files; getVolumeProbAtlasFiles(files); return getVolumeFileWithName(files, name); } /** * Get the RGB volume file with the specified name (NULL if not found). */ VolumeFile* BrainSet::getVolumeRgbFileWithName(const QString& name) { std::vector files; getVolumeRgbFiles(files); return getVolumeFileWithName(files, name); } /** * Get the segmentation volume file with the specified name (NULL if not found). */ VolumeFile* BrainSet::getVolumeSegmentationFileWithName(const QString& name) { std::vector files; getVolumeSegmentationFiles(files); return getVolumeFileWithName(files, name); } /** * Get the anatomy volume file with the specified name (NULL if not found). */ VolumeFile* BrainSet::getVolumeAnatomyFileWithName(const QString& name) { std::vector files; getVolumeAnatomyFiles(files); return getVolumeFileWithName(files, name); } /** * Get the functional volume file with the specified name (NULL if not found). */ VolumeFile* BrainSet::getVolumeFunctionalFileWithName(const QString& name) { std::vector files; getVolumeFunctionalFiles(files); return getVolumeFileWithName(files, name); } /** * Get the vector volume file with the specified name (NULL if not found). */ VolumeFile* BrainSet::getVolumeVectorFileWithName(const QString& name) { std::vector files; getVolumeVectorFiles(files); return getVolumeFileWithName(files, name); } /** * Get the volume file name with the specified name (NULL if not found). */ VolumeFile* BrainSet::getVolumeFileWithName(const std::vector& files, const QString& fileName) { const QString name = FileUtilities::basename(fileName); for (unsigned int i = 0; i < files.size(); i++) { if (name == files[i]->getFileNameNoPath()) { return files[i]; } } return NULL; } /** * clear all node highlight symbols. */ void BrainSet::clearNodeHighlightSymbols() { const int numNodes = getNumberOfNodes(); for (int i = 0; i < numNodes; i++) { BrainSetNodeAttribute* bna = getNodeAttributes(i); bna->setHighlighting(BrainSetNodeAttribute::HIGHLIGHT_NODE_NONE); } clearAllDisplayLists(); } /** * read an image (returns true if read successfully). */ bool BrainSet::readImage(const QString& filename, const QString& format, QImage& image) { QImage tempImage; const bool valid = (tempImage.load(filename.toAscii().constData(), format.toAscii().constData())); if (valid) { image = QGLWidget::convertToGLFormat(tempImage); } return valid; } /** * Set node display flags based upon sections and other criteria. */ void BrainSet::updateNodeDisplayFlags() { resetNodeAttributes(); const int numNodes = getNumberOfNodes(); displayAllNodesFlag = true; bool checkNodes = true; DisplaySettingsSection* dss = getDisplaySettingsSection(); SectionFile* sf = getSectionFile(); const int column = dss->getSelectedDisplayColumn(-1, -1); if (sf->getNumberOfColumns() == 0) { checkNodes = false; } else { if (dss->getSelectionType() == DisplaySettingsSection::SELECTION_TYPE_ALL) { checkNodes = false; } } if (checkNodes == false) { for (int i = 0; i < numNodes; i++) { nodeAttributes[i].setDisplayFlag(true); } return; } const int minSection = dss->getMinimumSelectedSection(); const int maxSection = dss->getMaximumSelectedSection(); for (int i = 0; i < numNodes; i++) { bool displayIt = true; const int section = sf->getSection(i, column); if ((section < minSection) || (section > maxSection)) { displayAllNodesFlag = false; displayIt = false; } nodeAttributes[i].setDisplayFlag(displayIt); } } /** * remove coordinate and topoology files from spec file. */ void BrainSet::removeCoordAndTopoFromSpecFile() { loadedFilesSpecFile.rawCoordFile.clear(false); loadedFilesSpecFile.fiducialCoordFile.clear(false); loadedFilesSpecFile.inflatedCoordFile.clear(false); loadedFilesSpecFile.veryInflatedCoordFile.clear(false); loadedFilesSpecFile.sphericalCoordFile.clear(false); loadedFilesSpecFile.ellipsoidCoordFile.clear(false); loadedFilesSpecFile.compressedCoordFile.clear(false); loadedFilesSpecFile.flatCoordFile.clear(false); loadedFilesSpecFile.lobarFlatCoordFile.clear(false); loadedFilesSpecFile.hullCoordFile.clear(false); loadedFilesSpecFile.unknownCoordFile.clear(false); loadedFilesSpecFile.closedTopoFile.clear(false); loadedFilesSpecFile.openTopoFile.clear(false); loadedFilesSpecFile.cutTopoFile.clear(false); loadedFilesSpecFile.lobarCutTopoFile.clear(false); if (specFileName.isEmpty() == false) { try { SpecFile sf; sf.readFile(specFileName); sf.rawCoordFile.clear(false); sf.fiducialCoordFile.clear(false); sf.inflatedCoordFile.clear(false); sf.veryInflatedCoordFile.clear(false); sf.sphericalCoordFile.clear(false); sf.ellipsoidCoordFile.clear(false); sf.compressedCoordFile.clear(false); sf.flatCoordFile.clear(false); sf.lobarFlatCoordFile.clear(false); sf.hullCoordFile.clear(false); sf.unknownCoordFile.clear(false); sf.closedTopoFile.clear(false); sf.openTopoFile.clear(false); sf.cutTopoFile.clear(false); sf.lobarCutTopoFile.clear(false); sf.writeFile(specFileName); } catch (FileException) { // do nothing } } } /** * Delete all borders */ void BrainSet::deleteAllBorders() { brainModelBorderSet->deleteAllBorders(); loadedFilesSpecFile.borderProjectionFile.setAllSelections(SpecFile::SPEC_FALSE); loadedFilesSpecFile.rawBorderFile.setAllSelections(SpecFile::SPEC_FALSE); loadedFilesSpecFile.fiducialBorderFile.setAllSelections(SpecFile::SPEC_FALSE); loadedFilesSpecFile.inflatedBorderFile.setAllSelections(SpecFile::SPEC_FALSE); loadedFilesSpecFile.veryInflatedBorderFile.setAllSelections(SpecFile::SPEC_FALSE); loadedFilesSpecFile.sphericalBorderFile.setAllSelections(SpecFile::SPEC_FALSE); loadedFilesSpecFile.ellipsoidBorderFile.setAllSelections(SpecFile::SPEC_FALSE); loadedFilesSpecFile.compressedBorderFile.setAllSelections(SpecFile::SPEC_FALSE); loadedFilesSpecFile.flatBorderFile.setAllSelections(SpecFile::SPEC_FALSE); loadedFilesSpecFile.lobarFlatBorderFile.setAllSelections(SpecFile::SPEC_FALSE); loadedFilesSpecFile.hullBorderFile.setAllSelections(SpecFile::SPEC_FALSE); loadedFilesSpecFile.unknownBorderFile.setAllSelections(SpecFile::SPEC_FALSE); loadedFilesSpecFile.volumeBorderFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * clear the file */ void BrainSet::clearAreaColorFile() { areaColorFile->clear(); loadedFilesSpecFile.areaColorFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * clear the file */ void BrainSet::clearArealEstimationFile() { arealEstimationFile->clear(); loadedFilesSpecFile.arealEstimationFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * clear the file */ void BrainSet::clearBorderColorFile() { borderColorFile->clear(); loadedFilesSpecFile.borderColorFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * clear the file */ void BrainSet::clearCellColorFile() { cellColorFile->clear(); loadedFilesSpecFile.cellColorFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * clear the file */ void BrainSet::clearCocomacConnectivityFile() { cocomacFile->clear(); loadedFilesSpecFile.cocomacConnectivityFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * clear the file */ void BrainSet::clearContourCellColorFile() { contourCellColorFile->clear(); loadedFilesSpecFile.contourCellColorFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * clear the file */ void BrainSet::clearContourCellFile() { contourCellFile->clear(); loadedFilesSpecFile.contourCellFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * clear the file */ void BrainSet::clearContourFile(const bool deleteBrainModelContoursFlag) { if (deleteBrainModelContoursFlag) { BrainModelContours* bmc = getBrainModelContours(-1); if (bmc != NULL) { bmc->reset(); deleteBrainModel(bmc); bmc = NULL; } } loadedFilesSpecFile.contourFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * clear the file */ void BrainSet::clearCutsFile() { cutsFile->clear(); loadedFilesSpecFile.cutsFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * clear the file */ void BrainSet::clearDeformationFieldFile() { deformationFieldFile->clear(); loadedFilesSpecFile.deformationFieldFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * clear the file */ void BrainSet::clearDeformationMapFile() { deformationMapFileName = ""; loadedFilesSpecFile.deformationMapFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * clear the file */ void BrainSet::clearFociColorFile() { fociColorFile->clear(); loadedFilesSpecFile.fociColorFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * clear the file */ void BrainSet::clearFociSearchFile() { fociSearchFile->clear(); loadedFilesSpecFile.fociSearchFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * clear the file */ void BrainSet::clearGeodesicDistanceFile() { geodesicDistanceFile->clear(); loadedFilesSpecFile.geodesicDistanceFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * clear the file */ void BrainSet::clearLatLonFile() { latLonFile->clear(); loadedFilesSpecFile.latLonFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * clear the file */ void BrainSet::clearMetricFile() { metricFile->clear(); loadedFilesSpecFile.metricFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * clear the file */ void BrainSet::clearPaintFile() { paintFile->clear(); loadedFilesSpecFile.paintFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * clear the file */ void BrainSet::clearPaletteFile() { paletteFile->clear(); loadedFilesSpecFile.paletteFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * clear the file */ void BrainSet::clearParamsFile() { paramsFile->clear(); loadedFilesSpecFile.paramsFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * clear the file */ void BrainSet::clearProbabilisticAtlasFile() { probabilisticAtlasSurfaceFile->clear(); loadedFilesSpecFile.atlasFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * clear the file */ void BrainSet::clearRgbPaintFile() { rgbPaintFile->clear(); loadedFilesSpecFile.rgbPaintFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * clear the file */ void BrainSet::clearSceneFile() { sceneFile->clear(); loadedFilesSpecFile.sceneFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * clear the file */ void BrainSet::clearSectionFile() { sectionFile->clear(); loadedFilesSpecFile.sectionFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * clear the file */ void BrainSet::clearSurfaceShapeFile() { surfaceShapeFile->clear(); loadedFilesSpecFile.surfaceShapeFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * Add a vector file. */ void BrainSet::addVectorFile(VectorFile* vf) { vectorFiles.push_back(vf); } /** * Remove a vector file. */ void BrainSet::removeVectorFile(const int indx) { loadedFilesSpecFile.vectorFile.clearSelectionStatus(vectorFiles[indx]->getFileName()); vectorFiles.erase(vectorFiles.begin() + indx); } /** * Remove a vector file. */ void BrainSet::removeVectorFile(VectorFile* vf) { for (int i = 0; i < getNumberOfVectorFiles(); i++) { if (getVectorFile(i) == vf) { removeVectorFile(i); break; } } } /** * get vector file's index. */ int BrainSet::getVectorFileIndex(VectorFile* vf) { for (int i = 0; i < getNumberOfVectorFiles(); i++) { if (vectorFiles[i] == vf) { return i; } } return -1; } /** * clear the file */ void BrainSet::clearVectorFiles() { for (int i = 0; i < getNumberOfVectorFiles(); i++) { delete vectorFiles[i]; } vectorFiles.clear(); loadedFilesSpecFile.vectorFile.setAllSelections(SpecFile::SPEC_FALSE); clearAllDisplayLists(); } /** * clear the file */ void BrainSet::clearTopographyFile() { topographyFile->clear(); loadedFilesSpecFile.topographyFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * clear the file */ void BrainSet::clearTransformationMatrixFile() { transformationMatrixFile->clear(); loadedFilesSpecFile.transformationMatrixFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * clear the transformation data files. */ void BrainSet::clearTransformationDataFiles() { for (int i = 0; i < getNumberOfTransformationDataFiles(); i++) { delete transformationDataFiles[i]; } transformationDataFiles.clear(); loadedFilesSpecFile.transformationDataFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * clear the file */ void BrainSet::clearStudyMetaDataFile() { studyMetaDataFile->clear(); loadedFilesSpecFile.studyMetaDataFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * clear the file */ void BrainSet::clearStudyCollectionFile() { studyCollectionFile->clear(); loadedFilesSpecFile.studyCollectionFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * clear the file */ void BrainSet::clearWustlRegionFile() { wustlRegionFile->clear(); loadedFilesSpecFile.wustlRegionFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * clear the file */ void BrainSet::clearVocabularyFile() { vocabularyFile->clear(); loadedFilesSpecFile.vocabularyFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * clear the anatomy volume files. */ void BrainSet::clearVolumeAnatomyFiles() { for (unsigned int i = 0; i < volumeAnatomyFiles.size(); i++) { delete volumeAnatomyFiles[i]; } volumeAnatomyFiles.clear(); loadedFilesSpecFile.volumeAnatomyFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * clear the functional volume files. */ void BrainSet::clearVolumeFunctionalFiles() { for (unsigned int i = 0; i < volumeFunctionalFiles.size(); i++) { delete volumeFunctionalFiles[i]; } volumeFunctionalFiles.clear(); loadedFilesSpecFile.volumeFunctionalFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * clear the paint volume files. */ void BrainSet::clearVolumePaintFiles() { for (unsigned int i = 0; i < volumePaintFiles.size(); i++) { delete volumePaintFiles[i]; } volumePaintFiles.clear(); loadedFilesSpecFile.volumePaintFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * clear the prob atlasvolume files. */ void BrainSet::clearVolumeProbabilisticAtlasFiles() { for (unsigned int i = 0; i < volumeProbAtlasFiles.size(); i++) { delete volumeProbAtlasFiles[i]; } volumeProbAtlasFiles.clear(); loadedFilesSpecFile.volumeProbAtlasFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * clear the rgb volume files. */ void BrainSet::clearVolumeRgbFiles() { for (unsigned int i = 0; i < volumeRgbFiles.size(); i++) { delete volumeRgbFiles[i]; } volumeRgbFiles.clear(); loadedFilesSpecFile.volumeRgbFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * clear the segmentation volume files. */ void BrainSet::clearVolumeSegmentationFiles() { for (unsigned int i = 0; i < volumeSegmentationFiles.size(); i++) { delete volumeSegmentationFiles[i]; } volumeSegmentationFiles.clear(); loadedFilesSpecFile.volumeSegmentationFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * clear the vector volume files. */ void BrainSet::clearVolumeVectorFiles() { for (unsigned int i = 0; i < volumeVectorFiles.size(); i++) { delete volumeVectorFiles[i]; } volumeVectorFiles.clear(); loadedFilesSpecFile.volumeVectorFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * convert displayed borders into a VTK model. */ void BrainSet::convertDisplayedBordersToVtkModel(const BrainModelSurface* bms) { BrainModelBorderSet* bmbs = getBorderSet(); if (bmbs != NULL) { BorderFile bf; bmbs->copyBordersToBorderFile(bms, bf); BorderFile displayedBorders; const int num = bf.getNumberOfBorders(); for (int i = 0; i < num; i++) { const Border* b = bf.getBorder(i); if (b->getDisplayFlag()) { displayedBorders.addBorder(*b); } } if (displayedBorders.getNumberOfBorders() > 0) { VtkModelFile* vmf = new VtkModelFile(&displayedBorders, borderColorFile); addVtkModelFile(vmf); } } } /** * convert displayed cells into a VTK model. */ void BrainSet::convertDisplayedCellsToVtkModel(const BrainModelSurface* bms) { // // Check for fiducial surface // const bool fiducialSurfaceFlag = ((bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_RAW) || (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FIDUCIAL)); CellFile cf; cellProjectionFile->getCellFile(bms->getCoordinateFile(), bms->getTopologyFile(), fiducialSurfaceFlag, cf); const int numCells = cf.getNumberOfCells(); if (numCells > 0) { CellFile displayedCells; for (int i = 0; i < numCells; i++) { CellData* cd = cf.getCell(i); if (cd->getDisplayFlag()) { displayedCells.addCell(*cd); } } if (displayedCells.getNumberOfCells() > 0) { VtkModelFile* vmf = new VtkModelFile(&displayedCells, cellColorFile); addVtkModelFile(vmf); } } } /** * convert displayed foci into a VTK model. */ void BrainSet::convertDisplayedFociToVtkModel(const BrainModelSurface *bms) { // // Check for fiducial surface // const bool fiducialSurfaceFlag = ((bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_RAW) || (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FIDUCIAL)); FociFile ff; fociProjectionFile->getCellFile(bms->getCoordinateFile(), bms->getTopologyFile(), fiducialSurfaceFlag, ff); const int numCells = ff.getNumberOfCells(); if (numCells > 0) { FociFile displayedFoci; const int numFoci = ff.getNumberOfCells(); for (int i = 0; i < numFoci; i++) { CellData* cd = ff.getCell(i); if (cd->getDisplayFlag()) { displayedFoci.addCell(*cd); } } if (displayedFoci.getNumberOfCells() > 0) { VtkModelFile* vmf = new VtkModelFile(&displayedFoci, fociColorFile); addVtkModelFile(vmf); } } } /** * update displayed model indices. */ void BrainSet::updateDisplayedModelIndices() { for (int i = 0; i < BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS; i++) { if (displayedModelIndices[i] >= getNumberOfBrainModels()) { displayedModelIndices[i] = 0; } } } /** * get the displayed model index for a window. */ int BrainSet::getDisplayedModelIndexForWindow(const BrainModel::BRAIN_MODEL_VIEW_NUMBER windowNumber) const { if (displayedModelIndices[windowNumber] >= getNumberOfBrainModels()) { return 0; } return displayedModelIndices[windowNumber]; } /** * set the displayed model index for a window. */ void BrainSet::setDisplayedModelIndexForWindow(const BrainModel::BRAIN_MODEL_VIEW_NUMBER windowNumber, const int modelIndex) { displayedModelIndices[windowNumber] = modelIndex; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeVoxelColoring.h0000664000175000017500000001242211572067322025776 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __BRAIN_MODEL_VOLUME_VOXEL_COLORING_H__ #define __BRAIN_MODEL_VOLUME_VOXEL_COLORING_H__ #include "SceneFile.h" class BrainSet; class VolumeFile; /// class for coloring of volumes class BrainModelVolumeVoxelColoring { public: enum UNDERLAY_OVERLAY_TYPE { UNDERLAY_OVERLAY_NONE, UNDERLAY_OVERLAY_ANATOMY, UNDERLAY_OVERLAY_FUNCTIONAL, UNDERLAY_OVERLAY_PAINT, UNDERLAY_OVERLAY_PROB_ATLAS, UNDERLAY_OVERLAY_RGB, UNDERLAY_OVERLAY_SEGMENTATION, UNDERLAY_OVERLAY_VECTOR }; /// constructor BrainModelVolumeVoxelColoring(BrainSet* bs); /// destructor ~BrainModelVolumeVoxelColoring(); /// initialize the underlay to the first available volume void initializeUnderlay(); /// get the underlay UNDERLAY_OVERLAY_TYPE getUnderlay() const { return underlay; } /// set the underlay void setUnderlay(const UNDERLAY_OVERLAY_TYPE u) { underlay = u; } /// get the primary overlay UNDERLAY_OVERLAY_TYPE getPrimaryOverlay() const { return primaryOverlay; } /// set the primary overlay void setPrimaryOverlay(const UNDERLAY_OVERLAY_TYPE po) { primaryOverlay = po; } /// get the secondary overlay UNDERLAY_OVERLAY_TYPE getSecondaryOverlay() const { return secondaryOverlay; } /// set the secondary overlay void setSecondaryOverlay(const UNDERLAY_OVERLAY_TYPE so) { secondaryOverlay = so; } /// Color all of the volumes voxels void colorAllOfTheVolumesVoxels(VolumeFile* vf); /// Get a voxel's coloring. void getVoxelColoring(VolumeFile* vf, const int i, const int j, const int k, unsigned char rgb[4]); /// Set all functional volume coloring invalid void setVolumeFunctionalColoringInvalid(); /// Set all paint volume coloring invalid void setVolumePaintColoringInvalid(); /// Set all prob atlas volume coloring invalid void setVolumeProbAtlasColoringInvalid(); /// Set all functional volume coloring invalid void setVolumeAnatomyColoringInvalid(); /// Set all segmentation volume coloring invalid void setVolumeSegmentationColoringInvalid(); /// Set all rgb paint volume coloring invalid void setVolumeRgbPaintColoringInvalid(); /// Set all vector volume coloring invalid void setVolumeVectorColoringInvalid(); /// set all volume coloring invalid void setVolumeAllColoringInvalid(); /// Get the color for a segmentation voxel that is "on" static void getSegmentationVoxelOnColor(unsigned char rgbs[4]); /// Get the color for a segmentation voxel that is "off" static void getSegmentationVoxelOffColor(unsigned char rgbs[4]); /// apply a scene (set display settings) void showScene(const SceneFile::Scene& scene, QString& errorMessage) ; /// create a scene (read display settings) void saveScene(SceneFile::Scene& scene, const bool onlyIfSelectedFlag); /// see if an overlay or underlay is of a specific type bool isUnderlayOrOverlay(const UNDERLAY_OVERLAY_TYPE uo) const; private: /// Assign normal probabilistic coloring to a voxel void assignNormalProbAtlasColor(const int i, const int j, const int k, unsigned char rgb[4]); /// Assign threshold probabilistic coloring to a voxel void assignThresholdProbAtlasColor(const int i, const int j, const int k, unsigned char rgb[4]); /// the brain set this object is associated with BrainSet* brainSet; /// the underlay UNDERLAY_OVERLAY_TYPE underlay; /// the primary overlay UNDERLAY_OVERLAY_TYPE primaryOverlay; /// the secondary overlay UNDERLAY_OVERLAY_TYPE secondaryOverlay; }; #endif // __BRAIN_MODEL_VOLUME_VOXEL_COLORING_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeVoxelColoring.cxx0000664000175000017500000011223011572067322026347 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #ifdef Q_OS_WIN32 #define NOMINMAX #endif #include #include #include "AreaColorFile.h" #include "BrainSet.h" #include "BrainModelSurfaceNodeColoring.h" #include "BrainModelVolume.h" #include "BrainModelVolumeVoxelColoring.h" #include "DebugControl.h" #include "DisplaySettingsMetric.h" #include "DisplaySettingsProbabilisticAtlas.h" #include "DisplaySettingsVolume.h" #include "MetricFile.h" #include "PaletteFile.h" #include "VolumeFile.h" /** * constructor. */ BrainModelVolumeVoxelColoring::BrainModelVolumeVoxelColoring(BrainSet* bs) { brainSet = bs; underlay = UNDERLAY_OVERLAY_ANATOMY; primaryOverlay = UNDERLAY_OVERLAY_NONE; secondaryOverlay = UNDERLAY_OVERLAY_NONE; } /** * destructor. */ BrainModelVolumeVoxelColoring::~BrainModelVolumeVoxelColoring() { } /** * Initialize the underlay selection */ void BrainModelVolumeVoxelColoring::initializeUnderlay() { if (brainSet->getNumberOfVolumeAnatomyFiles() > 0) { underlay = UNDERLAY_OVERLAY_ANATOMY; } else if (brainSet->getNumberOfVolumeFunctionalFiles() > 0) { underlay = UNDERLAY_OVERLAY_FUNCTIONAL; } else if (brainSet->getNumberOfVolumePaintFiles() > 0) { underlay = UNDERLAY_OVERLAY_PAINT; } else if (brainSet->getNumberOfVolumeProbAtlasFiles() > 0) { underlay = UNDERLAY_OVERLAY_PROB_ATLAS; } else if (brainSet->getNumberOfVolumeRgbFiles() > 0) { underlay = UNDERLAY_OVERLAY_RGB; } else if (brainSet->getNumberOfVolumeSegmentationFiles() > 0) { underlay = UNDERLAY_OVERLAY_SEGMENTATION; } else if (brainSet->getNumberOfVolumeVectorFiles() > 0) { underlay = UNDERLAY_OVERLAY_VECTOR; } } /** * Set all functional volume file coloring invalid. */ void BrainModelVolumeVoxelColoring::setVolumeFunctionalColoringInvalid() { for (int i = 0; i < brainSet->getNumberOfVolumeFunctionalFiles(); i++) { VolumeFile* vf = brainSet->getVolumeFunctionalFile(i); vf->setVoxelColoringInvalid(); } } /** * Set all anatomy volume file coloring invalid. */ void BrainModelVolumeVoxelColoring::setVolumeAnatomyColoringInvalid() { for (int i = 0; i < brainSet->getNumberOfVolumeAnatomyFiles(); i++) { VolumeFile* vf = brainSet->getVolumeAnatomyFile(i); vf->setVoxelColoringInvalid(); } } /** * Set all paint volume file coloring invalid. */ void BrainModelVolumeVoxelColoring::setVolumePaintColoringInvalid() { for (int i = 0; i < brainSet->getNumberOfVolumePaintFiles(); i++) { VolumeFile* vf = brainSet->getVolumePaintFile(i); vf->setVoxelColoringInvalid(); } } /** * Set all prob atlas volume file coloring invalid. */ void BrainModelVolumeVoxelColoring::setVolumeProbAtlasColoringInvalid() { for (int i = 0; i < brainSet->getNumberOfVolumeProbAtlasFiles(); i++) { VolumeFile* vf = brainSet->getVolumeProbAtlasFile(i); vf->setVoxelColoringInvalid(); } } /** * Set all segmenatation volume file coloring invalid. */ void BrainModelVolumeVoxelColoring::setVolumeSegmentationColoringInvalid() { for (int i = 0; i < brainSet->getNumberOfVolumeSegmentationFiles(); i++) { VolumeFile* vf = brainSet->getVolumeSegmentationFile(i); vf->setVoxelColoringInvalid(); } } /** * Set all vector volume file coloring invalid. */ void BrainModelVolumeVoxelColoring::setVolumeVectorColoringInvalid() { for (int i = 0; i < brainSet->getNumberOfVolumeVectorFiles(); i++) { VolumeFile* vf = brainSet->getVolumeVectorFile(i); vf->setVoxelColoringInvalid(); } } /** * Set all rgb paint volume file coloring invalid. */ void BrainModelVolumeVoxelColoring::setVolumeRgbPaintColoringInvalid() { for (int i = 0; i < brainSet->getNumberOfVolumeRgbFiles(); i++) { VolumeFile* vf = brainSet->getVolumeRgbFile(i); vf->setVoxelColoringInvalid(); } } /** * set all volume coloring invalid. */ void BrainModelVolumeVoxelColoring::setVolumeAllColoringInvalid() { setVolumeAnatomyColoringInvalid(); setVolumeFunctionalColoringInvalid(); setVolumePaintColoringInvalid(); setVolumeProbAtlasColoringInvalid(); setVolumeRgbPaintColoringInvalid(); setVolumeSegmentationColoringInvalid(); setVolumeVectorColoringInvalid(); } /** * Color all of the volumes voxels. */ void BrainModelVolumeVoxelColoring::colorAllOfTheVolumesVoxels(VolumeFile* vf) { const unsigned char invalidColor[4] = { 0, 0, 0, VolumeFile::VOXEL_COLOR_STATUS_INVALID }; int dim[3] = { 0, 0, 0 }; vf->getDimensions(dim); for (int i = 0; i < dim[0]; i++) { for (int j = 0; j < dim[1]; j++) { for (int k = 0; k < dim[2]; k++) { vf->setVoxelColor(i, j, k, invalidColor); unsigned char rgb[4]; getVoxelColoring(vf, i, j, k, rgb); vf->setVoxelColor(i, j, k, rgb); } } } } /** * Get a voxel's coloring. */ void BrainModelVolumeVoxelColoring::getVoxelColoring(VolumeFile* vf, const int i, const int j, const int k, unsigned char rgb[4]) { // // If voxel color NOT invalid, we are done // vf->getVoxelColor(i, j, k, rgb); if (rgb[3] != VolumeFile::VOXEL_COLOR_STATUS_INVALID) { return; } float voxel = vf->getVoxel(i, j, k); const DisplaySettingsVolume* dsv = brainSet->getDisplaySettingsVolume(); switch(vf->getVolumeType()) { case VolumeFile::VOLUME_TYPE_ANATOMY: { float voxelOffset = 0.0; float voxelScale = 1.0; switch (dsv->getAnatomyVolumeColoringType()) { case DisplaySettingsVolume::ANATOMY_COLORING_TYPE_0_255: voxelOffset = 0.0; voxelScale = 1.0; break; case DisplaySettingsVolume::ANATOMY_COLORING_TYPE_MIN_MAX: { float minValue = 0.0, maxValue = 0.0; vf->getMinMaxVoxelValues(minValue, maxValue); const float range = maxValue - minValue; if (range != 0.0) { voxelOffset = -minValue; voxelScale = 255.0 / range; } } break; case DisplaySettingsVolume::ANATOMY_COLORING_TYPE_2_98: { float blackValue = 0.0, whiteValue = 0.0; vf->getTwoToNinetyEightPercentMinMaxVoxelValues(blackValue, whiteValue); // // Black/White range of the voxels // const float bwRange = whiteValue - blackValue; voxelOffset = -blackValue; voxelScale = 255.0 / bwRange; } } const float brightness = dsv->getAnatomyVolumeBrightness(); const float contrast = dsv->getAnatomyVolumeContrast(); const float shift = brightness - 128.0; const float scale = (100.0 + contrast) / (100.0 - contrast); voxel += voxelOffset; voxel *= voxelScale; float intensity = 128.0 + (voxel + shift) * scale; if (intensity > 255.0) { intensity = 255.0; } else if (intensity < 0.0) { intensity = 0.0; } rgb[0] = static_cast(intensity); rgb[1] = rgb[0]; rgb[2] = rgb[0]; rgb[3] = VolumeFile::VOXEL_COLOR_STATUS_VALID; vf->setVoxelColor(i, j, k, rgb); } break; case VolumeFile::VOLUME_TYPE_FUNCTIONAL: { // // Get the volume used for thresholding // VolumeFile* threshVolume = vf; const int threshIndex = dsv->getSelectedFunctionalVolumeThreshold(); if ((threshIndex >= 0) && (threshIndex < brainSet->getNumberOfVolumeFunctionalFiles())) { threshVolume = brainSet->getVolumeFunctionalFile(threshIndex); } // // Get the metric settings // MetricFile* mf = brainSet->getMetricFile(); DisplaySettingsMetric* dsm = brainSet->getDisplaySettingsMetric(); // // Get the palette file // const PaletteFile* pf = brainSet->getPaletteFile(); if (pf->getNumberOfPalettes() == 0) { std::cerr << "There are no palette files loaded, cannot color metrics." << std::endl; return; } const Palette* palette = pf->getPalette(dsm->getSelectedPaletteIndex()); // // Get the minimum and maximum metric // float posMinMetric = 0.0, posMaxMetric = 0.0, negMinMetric = 0.0, negMaxMetric = 0.0; int metricDisplayColumnNumber, metricThresholdColumnNumber; dsm->getMetricsForColoringAndPalette(metricDisplayColumnNumber, metricThresholdColumnNumber, negMaxMetric, negMinMetric, posMinMetric, posMaxMetric, true); // // Get thresholding // float thresholdNegativeValue = 0.0, thresholdPositiveValue = 0.0; dsm->getUserThresholdingValues(thresholdNegativeValue, thresholdPositiveValue); switch (dsm->getMetricThresholdingType()) { case DisplaySettingsMetric::METRIC_THRESHOLDING_TYPE_FILE_COLUMN: if ((metricThresholdColumnNumber >= 0) && (metricThresholdColumnNumber < mf->getNumberOfColumns())) { mf->getColumnThresholding(metricThresholdColumnNumber, thresholdNegativeValue, thresholdPositiveValue); } break; case DisplaySettingsMetric::METRIC_THRESHOLDING_TYPE_FILE_COLUMN_AVERAGE: if ((metricThresholdColumnNumber >= 0) && (metricThresholdColumnNumber < mf->getNumberOfColumns())) { mf->getColumnAverageThresholding(metricThresholdColumnNumber, thresholdNegativeValue, thresholdPositiveValue); } break; case DisplaySettingsMetric::METRIC_THRESHOLDING_TYPE_USER_VALUES: dsm->getUserThresholdingValues(thresholdNegativeValue, thresholdPositiveValue); break; } // // Always interpolate if the palette has only two colors // bool interpolateColor = dsm->getInterpolateColors(); if (palette->getNumberOfPaletteEntries() == 2) { interpolateColor = true; } rgb[3] = VolumeFile::VOXEL_COLOR_STATUS_VALID_DO_NOT_SHOW_VOXEL; //const float voxel = vf->getVoxelWithFlatIndex(i, 0); //const float threshVoxel = threshVolume->getVoxelWithFlatIndex(i); const float threshVoxel = threshVolume->getVoxel(i, j, k); unsigned char negThreshColor[3], posThreshColor[3]; dsm->getSpecialColorsForThresholdedNodes(negThreshColor, posThreshColor); const bool showThreshVoxels = dsm->getShowSpecialColorForThresholdedNodes(); // // when activation assignment dialog is active only display // those metrics that exceed the threshold value // enum DISPLAY_VOXEL { DISPLAY_VOXEL_NORMAL, DISPLAY_VOXEL_POS_THRESH_COLOR, DISPLAY_VOXEL_NEG_THRESH_COLOR, DISPLAY_VOXEL_DO_NOT }; DISPLAY_VOXEL displayVoxel = DISPLAY_VOXEL_NORMAL; if (threshVoxel >= 0.0) { if (threshVoxel < thresholdPositiveValue) { displayVoxel = DISPLAY_VOXEL_DO_NOT; if (showThreshVoxels) { if (threshVoxel != 0.0) { displayVoxel = DISPLAY_VOXEL_POS_THRESH_COLOR; } } } } if (threshVoxel <= 0.0) { if (threshVoxel > thresholdNegativeValue) { displayVoxel = DISPLAY_VOXEL_DO_NOT; if (showThreshVoxels) { if (threshVoxel != 0.0) { displayVoxel = DISPLAY_VOXEL_NEG_THRESH_COLOR; } } } } switch(dsm->getDisplayMode()) { case DisplaySettingsMetric::METRIC_DISPLAY_MODE_POSITIVE_AND_NEGATIVE: break; case DisplaySettingsMetric::METRIC_DISPLAY_MODE_NEGATIVE_ONLY: if (voxel >= 0.0) { displayVoxel = DISPLAY_VOXEL_DO_NOT; } break; case DisplaySettingsMetric::METRIC_DISPLAY_MODE_POSITIVE_ONLY: if (voxel <= 0.0) { displayVoxel = DISPLAY_VOXEL_DO_NOT; } break; } switch (displayVoxel) { case DISPLAY_VOXEL_NORMAL: { float normalized = 0.0; if ((palette->getNumberOfPaletteEntries() == 2) && interpolateColor) { // // Normalize between [0, 1.0] when two color palette interpolate // float diffMetric = posMaxMetric - negMaxMetric; if (diffMetric == 0.0) { diffMetric = 1.0; } normalized = (voxel - negMaxMetric) / diffMetric; } else { if (voxel >= posMinMetric) { const float numerator = voxel - posMinMetric; float denominator = posMaxMetric - posMinMetric; if (denominator == 0.0) { denominator = 1.0; } normalized = numerator / denominator; } else if (voxel <= negMinMetric) { const float numerator = voxel - negMinMetric; float denominator = negMaxMetric - negMinMetric; if (denominator == 0.0) { denominator = 1.0; } else if (denominator < 0.0) { denominator = -denominator; } normalized = numerator / denominator; // // allow a "Postive Only" palette with "Negative Only" displayed // if (palette->getPositiveOnly() && (dsm->getDisplayMode() == DisplaySettingsMetric::METRIC_DISPLAY_MODE_NEGATIVE_ONLY)) { normalized = -normalized; } } } bool isNoneColor = false; unsigned char colors[3]; palette->getColor(normalized, interpolateColor, isNoneColor, colors); if (isNoneColor == false) { rgb[0] = colors[0]; rgb[1] = colors[1]; rgb[2] = colors[2]; rgb[3] = VolumeFile::VOXEL_COLOR_STATUS_VALID; } } break; case DISPLAY_VOXEL_POS_THRESH_COLOR: rgb[0] = posThreshColor[0]; rgb[1] = posThreshColor[1]; rgb[2] = posThreshColor[2]; rgb[3] = VolumeFile::VOXEL_COLOR_STATUS_VALID; break; case DISPLAY_VOXEL_NEG_THRESH_COLOR: rgb[0] = negThreshColor[0]; rgb[1] = negThreshColor[1]; rgb[2] = negThreshColor[2]; rgb[3] = VolumeFile::VOXEL_COLOR_STATUS_VALID; break; case DISPLAY_VOXEL_DO_NOT: break; } // switch vf->setVoxelColor(i, j, k, rgb); } break; case VolumeFile::VOLUME_TYPE_PAINT: { const int numRegionNames = vf->getNumberOfRegionNames(); if (numRegionNames > 0) { AreaColorFile* cf = brainSet->getAreaColorFile(); // // Get first volume // VolumeFile* firstVolumeFile = brainSet->getVolumePaintFile(0); // // Assing colors to the voxels // rgb[3] = VolumeFile::VOXEL_COLOR_STATUS_VALID_DO_NOT_SHOW_VOXEL; if (voxel > 0) { const int paintIndex = static_cast(voxel); const QString name = vf->getRegionNameFromIndex(paintIndex); bool match; const int colorFileIndex = cf->getColorIndexByName(name, match); if (colorFileIndex >= 0) { cf->getColorByIndex(colorFileIndex, rgb[0], rgb[1], rgb[2]); if (firstVolumeFile->getHighlightRegionNameByIndex(paintIndex)) { rgb[0] = 0; rgb[1] = 255; rgb[2] = 0; } rgb[3] = VolumeFile::VOXEL_COLOR_STATUS_VALID; } } } else { rgb[3] = VolumeFile::VOXEL_COLOR_STATUS_VALID_DO_NOT_SHOW_VOXEL; } vf->setVoxelColor(i, j, k, rgb); } break; case VolumeFile::VOLUME_TYPE_PROB_ATLAS: { DisplaySettingsProbabilisticAtlas* dspa = brainSet->getDisplaySettingsProbabilisticAtlasVolume(); switch (dspa->getDisplayType()) { case DisplaySettingsProbabilisticAtlas::PROBABILISTIC_DISPLAY_TYPE_NORMAL: assignNormalProbAtlasColor(i, j, k, rgb); break; case DisplaySettingsProbabilisticAtlas::PROBABILISTIC_DISPLAY_TYPE_THRESHOLD: assignThresholdProbAtlasColor(i, j, k, rgb); break; } if ((rgb[0] > 0) || (rgb[1] > 0) || (rgb[2] > 0)) { rgb[3] = VolumeFile::VOXEL_COLOR_STATUS_VALID; } else { rgb[3] = VolumeFile::VOXEL_COLOR_STATUS_VALID_DO_NOT_SHOW_VOXEL; } vf->setVoxelColor(i, j, k, rgb); } break; case VolumeFile::VOLUME_TYPE_RGB: rgb[0] = static_cast(vf->getVoxel(i, j, k, 0)); rgb[1] = static_cast(vf->getVoxel(i, j, k, 1)); rgb[2] = static_cast(vf->getVoxel(i, j, k, 2)); if ((rgb[0] > 0) || (rgb[1] > 0) || (rgb[2] > 0)) { rgb[3] = VolumeFile::VOXEL_COLOR_STATUS_VALID; } else { rgb[3] = VolumeFile::VOXEL_COLOR_STATUS_VALID_DO_NOT_SHOW_VOXEL; } vf->setVoxelColor(i, j, k, rgb); break; case VolumeFile::VOLUME_TYPE_ROI: if (voxel != 0) { rgb[0] = 0; rgb[1] = 255; rgb[2] = 0; rgb[3] = VolumeFile::VOXEL_COLOR_STATUS_VALID; } else { rgb[3] = VolumeFile::VOXEL_COLOR_STATUS_VALID_DO_NOT_SHOW_VOXEL; } vf->setVoxelColor(i, j, k, rgb); break; case VolumeFile::VOLUME_TYPE_SEGMENTATION: { unsigned char onColor[4]; getSegmentationVoxelOnColor(onColor); if (voxel != 0) { rgb[0] = onColor[0]; rgb[1] = onColor[1]; rgb[2] = onColor[2]; rgb[3] = VolumeFile::VOXEL_COLOR_STATUS_VALID; } else { rgb[3] = VolumeFile::VOXEL_COLOR_STATUS_VALID_DO_NOT_SHOW_VOXEL; } vf->setVoxelColor(i, j, k, rgb); } break; case VolumeFile::VOLUME_TYPE_VECTOR: // // Do not use colors for voxels // rgb[3] = VolumeFile::VOXEL_COLOR_STATUS_VALID; vf->setVoxelColor(i, j, k, rgb); break; case VolumeFile::VOLUME_TYPE_UNKNOWN: break; } } /** * Assign normal probabilistic coloring to a voxel. */ void BrainModelVolumeVoxelColoring::assignNormalProbAtlasColor(const int iv, const int jv, const int kv, unsigned char rgb[4]) { DisplaySettingsProbabilisticAtlas* dspa = brainSet->getDisplaySettingsProbabilisticAtlasVolume(); AreaColorFile* cf = brainSet->getAreaColorFile(); const int numberOfVolumes = brainSet->getNumberOfVolumeProbAtlasFiles(); const int numSelectedChannels = dspa->getNumberOfChannelsSelected(); //BrainModelVolume* bmv = brainSet->getBrainModelVolume(); // // Initialize to background color // rgb[0] = 0; rgb[1] = 0; rgb[2] = 0; bool highlightFlag = false; if (numSelectedChannels > 0) { int* paintIndices = new int[numberOfVolumes]; int count = 0; VolumeFile* firstVolumeFile = NULL; for (int fileNum = 0; fileNum < numberOfVolumes; fileNum++) { VolumeFile* vf = brainSet->getVolumeProbAtlasFile(fileNum); if (fileNum == 0) { firstVolumeFile = vf; } if (dspa->getChannelSelected(fileNum)) { const int voxel = static_cast(vf->getVoxel(iv, jv, kv)); // // Convert voxel into its place in the prob atlas name table // const int paintIndex = voxel; //vf->getRegionNameFromIndex(voxel); // check > 0 since ??? is always first and is not a valid atlas index if ((paintIndex > 0) && (paintIndex < vf->getNumberOfRegionNames())) { if (dspa->getAreaSelected(paintIndex)) { paintIndices[count] = paintIndex; count++; } if (firstVolumeFile->getHighlightRegionNameByIndex(paintIndex)) { highlightFlag = true; } } } } if (count > 0) { const VolumeFile* firstVolumeFile = brainSet->getVolumeProbAtlasFile(0); // clear colors since we have probabilistic data for this voxel rgb[0] = 0; rgb[1] = 0; rgb[2] = 0; if (highlightFlag) { rgb[1] = 255; } else { for (int m = 0; m < count; m++) { QString colorName(firstVolumeFile->getRegionNameFromIndex(paintIndices[m])); if (dspa->getTreatQuestColorAsUnassigned()) { if (colorName == "???") { colorName = "Unassigned"; } } bool exactMatch; const int areaColorIndex = cf->getColorIndexByName(colorName, exactMatch); if (areaColorIndex >= 0) { unsigned char r, g, b; cf->getColorByIndex(areaColorIndex, r, g, b); rgb[0] += (unsigned char)((r / (float)(numSelectedChannels))); rgb[1] += (unsigned char)((g / (float)(numSelectedChannels))); rgb[2] += (unsigned char)((b / (float)(numSelectedChannels))); } } } } if (highlightFlag) { rgb[0] = 0; rgb[1] = 255; rgb[2] = 0; } delete[] paintIndices; } } /** * Assign threshold probabilistic coloring to a voxel. */ void BrainModelVolumeVoxelColoring::assignThresholdProbAtlasColor(const int iv, const int jv, const int kv, unsigned char rgb[4]) { rgb[0] = 0; rgb[1] = 0; rgb[2] = 0; DisplaySettingsProbabilisticAtlas* dspa = brainSet->getDisplaySettingsProbabilisticAtlasVolume(); AreaColorFile* cf = brainSet->getAreaColorFile(); //BrainModelVolume* bmv = brainSet->getBrainModelVolume(); const int numberOfVolumes = brainSet->getNumberOfVolumeProbAtlasFiles(); if (numberOfVolumes < 0) { return; } const VolumeFile* firstVolumeFile = brainSet->getVolumeProbAtlasFile(0); const int numSelectedChannels = dspa->getNumberOfChannelsSelected(); unsigned char anyAreaColor[3] = { 100, 100, 100 }; bool anyAreaColorValid = false; cf->getColorByName("ANYAREA", anyAreaColorValid, anyAreaColor[0], anyAreaColor[1], anyAreaColor[2]); if (numSelectedChannels > 0) { std::map indexCounterMap; const int numPaintNames = firstVolumeFile->getNumberOfRegionNames(); bool atLeastOneNonZero = false; for (int volNum = 0; volNum < numberOfVolumes; volNum++) { VolumeFile* vf = brainSet->getVolumeProbAtlasFile(volNum); if (volNum == 0) { firstVolumeFile = vf; } int cntIndex = 0; if (dspa->getChannelSelected(volNum)) { const int voxel = static_cast(vf->getVoxel(iv, jv, kv)); cntIndex = voxel; //bmv->getProbAtlasNameTableIndex(volNum, voxel); } if ((cntIndex > 0) && (cntIndex < numPaintNames)) { if (dspa->getAreaSelected(cntIndex) == false) { cntIndex = -1; } } if (cntIndex > 0) { // // Skip non-sulci // bool useIt = true; if ((vf->getRegionNameFromIndex(cntIndex) == "???") || (vf->getRegionNameFromIndex(cntIndex) == "GYRAL") || (vf->getRegionNameFromIndex(cntIndex) == "GYRUS")) { useIt = false; } if (useIt) { atLeastOneNonZero = true; std::map::iterator iter = indexCounterMap.find(cntIndex); if (iter != indexCounterMap.end()) { iter->second++; } else { indexCounterMap[cntIndex] = 1; } } } } int paintColIndex = -1; if (indexCounterMap.empty() == false) { int maxIndex = -1; int maxCount = -1; for (std::map::iterator iter = indexCounterMap.begin(); iter != indexCounterMap.end(); iter++) { if (iter->second > maxCount) { maxIndex = iter->first; maxCount = iter->second; } } if (maxCount >= 0) { const float percentSelected = static_cast(maxCount) / static_cast(numSelectedChannels); if (percentSelected >= dspa->getThresholdDisplayTypeRatio()) { paintColIndex = maxIndex; } } } if (paintColIndex >= 0) { const QString paintName = firstVolumeFile->getRegionNameFromIndex(paintColIndex); bool match = false; const int areaColorIndex = cf->getColorIndexByName(paintName, match); if (areaColorIndex >= 0) { unsigned char r, g, b; cf->getColorByIndex(areaColorIndex, r, g, b); rgb[0] = r; rgb[1] = g; rgb[2] = b; if (firstVolumeFile->getHighlightRegionNameByIndex(paintColIndex)) { rgb[0] = 0; rgb[1] = 255; rgb[2] = 0; } } else { rgb[0] = anyAreaColor[0]; rgb[1] = anyAreaColor[1]; rgb[2] = anyAreaColor[2]; } } else if (atLeastOneNonZero && anyAreaColorValid) { rgb[0] = anyAreaColor[0]; rgb[1] = anyAreaColor[1]; rgb[2] = anyAreaColor[2]; } } } /** * Get the colors for an "on" segmentation voxel */ void BrainModelVolumeVoxelColoring::getSegmentationVoxelOnColor(unsigned char rgbs[4]) { rgbs[0] = 255; rgbs[1] = 0; rgbs[2] = 0; rgbs[3] = VolumeFile::VOXEL_COLOR_STATUS_VALID; // causes voxel to display } /** * Get the colors for an "off" segmentation voxel */ void BrainModelVolumeVoxelColoring::getSegmentationVoxelOffColor(unsigned char rgbs[4]) { rgbs[0] = 0; rgbs[1] = 0; rgbs[2] = 0; rgbs[3] = VolumeFile::VOXEL_COLOR_STATUS_VALID_DO_NOT_SHOW_VOXEL; // causes voxel to NOT display } // // Strings for showing and saving scenes // static const QString underlayNameID("Volume-Underlay-Name"); static const QString secondaryOverlayNameID("Volume-Secondary-Overlay-Name"); static const QString primaryOverlayNameID("Volume-Primary-Overlay-Name"); static const QString ouNoneName("none"); static const QString ouAnatomyName("anatomy"); static const QString ouFunctionalName("functional"); static const QString ouPaintName("paint"); static const QString ouProbabilisticAtlasName("probabilistic-atlas"); static const QString ouRgbName("rgb"); static const QString ouSegmentationName("segmentation"); static const QString ouVectorName("vector"); /** * apply a scene (set display settings). */ void BrainModelVolumeVoxelColoring::showScene(const SceneFile::Scene& scene, QString& errorMessage) { const int numClasses = scene.getNumberOfSceneClasses(); for (int nc = 0; nc < numClasses; nc++) { const SceneFile::SceneClass* sc = scene.getSceneClass(nc); if (sc->getName() == "BrainModelVolumeVoxelColoring") { const int num = sc->getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc->getSceneInfo(i); const QString infoName = si->getName(); // // Is this for underlay or overlay ? // if ((infoName == underlayNameID) || (infoName == secondaryOverlayNameID) || (infoName == primaryOverlayNameID)) { UNDERLAY_OVERLAY_TYPE selection = UNDERLAY_OVERLAY_NONE; const QString value = si->getValueAsString(); if (value == ouAnatomyName) { selection = UNDERLAY_OVERLAY_ANATOMY; if (brainSet->getNumberOfVolumeAnatomyFiles() <= 0) { errorMessage.append("No anatomy volumes are loaded\n"); } } else if (value == ouFunctionalName) { selection = UNDERLAY_OVERLAY_FUNCTIONAL; if (brainSet->getNumberOfVolumeFunctionalFiles() <= 0) { errorMessage.append("No functional volumes are loaded\n"); } } else if (value == ouPaintName) { selection = UNDERLAY_OVERLAY_PAINT; if (brainSet->getNumberOfVolumePaintFiles() <= 0) { errorMessage.append("No paint volumes are loaded\n"); } } else if (value == ouProbabilisticAtlasName) { selection = UNDERLAY_OVERLAY_PROB_ATLAS; if (brainSet->getNumberOfVolumeProbAtlasFiles() <= 0) { errorMessage.append("No prob atlas volumes are loaded\n"); } } else if (value == ouRgbName) { selection = UNDERLAY_OVERLAY_RGB; if (brainSet->getNumberOfVolumeRgbFiles() <= 0) { errorMessage.append("No rgb volumes are loaded\n"); } } else if (value == ouSegmentationName) { selection = UNDERLAY_OVERLAY_SEGMENTATION; if (brainSet->getNumberOfVolumeSegmentationFiles() <= 0) { errorMessage.append("No segmentation volumes are loaded\n"); } } else if (value == ouVectorName) { selection = UNDERLAY_OVERLAY_VECTOR; if (brainSet->getNumberOfVolumeVectorFiles() <= 0) { errorMessage.append("No vector volumes are loaded\n"); } } // // Set the overlay or underlay // if (infoName == underlayNameID) { setUnderlay(selection); } else if (infoName == secondaryOverlayNameID) { setSecondaryOverlay(selection); } else if (infoName == primaryOverlayNameID) { setPrimaryOverlay(selection); } } } } } } /** * create a scene (read display settings). */ void BrainModelVolumeVoxelColoring::saveScene(SceneFile::Scene& scene, const bool /*onlyIfSelectedFlag*/) { //if (onlyIfSelectedFlag) { const int numVolumes = brainSet->getNumberOfVolumeAnatomyFiles() + brainSet->getNumberOfVolumeFunctionalFiles() + brainSet->getNumberOfVolumePaintFiles() + brainSet->getNumberOfVolumeProbAtlasFiles() + brainSet->getNumberOfVolumeRgbFiles() + brainSet->getNumberOfVolumeSegmentationFiles() + brainSet->getNumberOfVolumeVectorFiles(); if (numVolumes <= 0) { return; } //} SceneFile::SceneClass sc("BrainModelVolumeVoxelColoring"); // // Do underlay and both overlays // for (int i = 0; i < 3; i++) { QString ouName; QString ouValue; UNDERLAY_OVERLAY_TYPE selection = UNDERLAY_OVERLAY_NONE; switch (i) { case 0: ouName = underlayNameID; selection = getUnderlay(); break; case 1: ouName = secondaryOverlayNameID; selection = getSecondaryOverlay(); break; case 2: ouName = primaryOverlayNameID; selection = getPrimaryOverlay(); break; } switch(selection) { case UNDERLAY_OVERLAY_NONE: ouValue = ouNoneName; break; case UNDERLAY_OVERLAY_ANATOMY: ouValue = ouAnatomyName; break; case UNDERLAY_OVERLAY_FUNCTIONAL: ouValue = ouFunctionalName; break; case UNDERLAY_OVERLAY_PAINT: ouValue = ouPaintName; break; case UNDERLAY_OVERLAY_PROB_ATLAS: ouValue = ouProbabilisticAtlasName; break; case UNDERLAY_OVERLAY_RGB: ouValue = ouRgbName; break; case UNDERLAY_OVERLAY_SEGMENTATION: ouValue = ouSegmentationName; break; case UNDERLAY_OVERLAY_VECTOR: ouValue = ouVectorName; break; } SceneFile::SceneInfo si(ouName, ouValue); sc.addSceneInfo(si); } scene.addSceneClass(sc); } /** * see if an overlay or underlay is of a specific type. */ bool BrainModelVolumeVoxelColoring::isUnderlayOrOverlay(const UNDERLAY_OVERLAY_TYPE uo) const { if ((underlay == uo) || (secondaryOverlay == uo) || (primaryOverlay == uo)) { return true; } return false; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeTopologyGraphCorrector.h0000664000175000017500000001037011572067322027665 0ustar michaelmichael #ifndef __BRAIN_MODEL_VOLUME_TOPOLOGY_GRAPH_CORRECTOR_H__ #define __BRAIN_MODEL_VOLUME_TOPOLOGY_GRAPH_CORRECTOR_H__ #include "BrainModelAlgorithm.h" /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelVolumeTopologyGraph.h" class VolumeFile; /// class for correcting volume topology using a graph class BrainModelVolumeTopologyGraphCorrector : public BrainModelAlgorithm { public: /// correction mode enum CORRECTION_MODE { /// make minimal corrections needed to repair topology CORRECTION_MODE_MINIMAL, /// normal fill and remove handles CORRECTION_MODE_NORMAL }; // constructor BrainModelVolumeTopologyGraphCorrector(BrainSet* bsIn, const CORRECTION_MODE correctionModeIn, const VolumeFile* segmentationVolumeFileIn); // destructor ~BrainModelVolumeTopologyGraphCorrector(); // execute the algorithm void execute() throw (BrainModelAlgorithmException); /// get the number of voxels changed during the correction process int getNumberOfVoxelsChanged() const { return numberOfVoxelsChanged; } // get the corrected segmentation volume file const VolumeFile* getCorrectedSegmentationVolumeFile() const { return correctedSegmentationVolumeFile; } // get the paint volume file showing corrections const VolumeFile* getShowingCorrectionsPaintVolumeFile() const { return showingCorrectionsPaintVolumeFile; } protected: // add or remove voxels to/from a volume void addRemoveVoxels(VolumeFile* foregroundVolumeFile, VolumeFile* backgroundVolumeFile, const BrainModelVolumeTopologyGraph* graph, const BrainModelVolumeTopologyGraph::GraphCycle* cycle, const std::vector vertices, const bool addVoxelsFlag); // create the foreground and background graphs void createForegroundAndBackgroundGraphs( const VolumeFile* foregroundVolumeFile, const VolumeFile* backgroundVolumeFile, const BrainModelVolumeTopologyGraph::VOXEL_NEIGHBOR_CONNECTIVITY foregroundVoxelConnectivity, const BrainModelVolumeTopologyGraph::VOXEL_NEIGHBOR_CONNECTIVITY backgroundVoxelConnectivity, BrainModelVolumeTopologyGraph* graphsOut[6]) const throw (BrainModelAlgorithmException); /// correction mode CORRECTION_MODE correctionMode; /// segmentation volume that is to be corrected const VolumeFile* segmentationVolumeFile; /// corrected segmentation volume file VolumeFile* correctedSegmentationVolumeFile; /// number of voxels changed during correction process int numberOfVoxelsChanged; /// paint volume file containing corrections VolumeFile* showingCorrectionsPaintVolumeFile; /// index of voxels added in paint volume containing corrections int paintVoxelAddedIndex; /// index of voxels added in paint volume containing corrections int paintVoxelRemovedIndex; }; #endif // __BRAIN_MODEL_VOLUME_TOPOLOGY_GRAPH_CORRECTOR_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeTopologyGraphCorrector.cxx0000664000175000017500000004201511572067322030241 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainModelVolumeTopologyGraph.h" #include "BrainModelVolumeTopologyGraphCorrector.h" #include "VolumeFile.h" /** * constructor. */ BrainModelVolumeTopologyGraphCorrector::BrainModelVolumeTopologyGraphCorrector( BrainSet* bsIn, const CORRECTION_MODE correctionModeIn, const VolumeFile* segmentationVolumeFileIn) : BrainModelAlgorithm(bsIn), correctionMode(correctionModeIn), segmentationVolumeFile(segmentationVolumeFileIn) { correctedSegmentationVolumeFile = NULL; showingCorrectionsPaintVolumeFile = NULL; numberOfVoxelsChanged = 0; } /** * destructor. */ BrainModelVolumeTopologyGraphCorrector::~BrainModelVolumeTopologyGraphCorrector() { if (correctedSegmentationVolumeFile != NULL) { delete correctedSegmentationVolumeFile; correctedSegmentationVolumeFile = NULL; } if (showingCorrectionsPaintVolumeFile != NULL) { delete showingCorrectionsPaintVolumeFile; showingCorrectionsPaintVolumeFile = NULL; } } /** * execute the algorithm. */ void BrainModelVolumeTopologyGraphCorrector::execute() throw (BrainModelAlgorithmException) { if (segmentationVolumeFile == NULL) { throw BrainModelAlgorithmException("Input segmentation volume is invalid."); } // // Copy the input volume // correctedSegmentationVolumeFile = new VolumeFile(*segmentationVolumeFile); correctedSegmentationVolumeFile->makeSegmentationZeroTwoFiftyFive(); // // Copy of volume before correction // const VolumeFile uncorrectedVolumeFile(*correctedSegmentationVolumeFile); // // Create paint volume showing corrections // showingCorrectionsPaintVolumeFile = new VolumeFile(*segmentationVolumeFile); showingCorrectionsPaintVolumeFile->setVolumeType(VolumeFile::VOLUME_TYPE_PAINT); const int nonePaintIndex = showingCorrectionsPaintVolumeFile->addRegionName("???"); showingCorrectionsPaintVolumeFile->setAllVoxels(nonePaintIndex); paintVoxelAddedIndex = showingCorrectionsPaintVolumeFile->addRegionName("ADDED"); paintVoxelRemovedIndex = showingCorrectionsPaintVolumeFile->addRegionName("REMOVED"); // // Try each connectivity // for (int conn = 0; conn < 6; conn++) { std::cout << "Conn: " << conn << std::endl; // // Connectivity used for generating graphs // BrainModelVolumeTopologyGraph::VOXEL_NEIGHBOR_CONNECTIVITY foregroundVoxelConnectivity = BrainModelVolumeTopologyGraph::VOXEL_NEIGHBOR_CONNECTIVITY_26; switch (conn) { case 0: case 3: foregroundVoxelConnectivity = BrainModelVolumeTopologyGraph::VOXEL_NEIGHBOR_CONNECTIVITY_26; break; case 1: case 4: foregroundVoxelConnectivity = BrainModelVolumeTopologyGraph::VOXEL_NEIGHBOR_CONNECTIVITY_18; break; case 2: case 5: foregroundVoxelConnectivity = BrainModelVolumeTopologyGraph::VOXEL_NEIGHBOR_CONNECTIVITY_6; break; } BrainModelVolumeTopologyGraph::VOXEL_NEIGHBOR_CONNECTIVITY backgroundVoxelConnectivity = BrainModelVolumeTopologyGraph::VOXEL_NEIGHBOR_CONNECTIVITY_26; switch (foregroundVoxelConnectivity) { case BrainModelVolumeTopologyGraph::VOXEL_NEIGHBOR_CONNECTIVITY_6: backgroundVoxelConnectivity = BrainModelVolumeTopologyGraph::VOXEL_NEIGHBOR_CONNECTIVITY_18; break; case BrainModelVolumeTopologyGraph::VOXEL_NEIGHBOR_CONNECTIVITY_18: backgroundVoxelConnectivity = BrainModelVolumeTopologyGraph::VOXEL_NEIGHBOR_CONNECTIVITY_6; break; case BrainModelVolumeTopologyGraph::VOXEL_NEIGHBOR_CONNECTIVITY_26: backgroundVoxelConnectivity = BrainModelVolumeTopologyGraph::VOXEL_NEIGHBOR_CONNECTIVITY_6; break; } // // Do until done // VolumeFile backgroundVolumeFile; bool needToGenerateBackgroundVolumeFlag = true; //int ctr = 0; bool done = false; while (done == false) { //ctr++; //if (((ctr % 5) == 0) && (ctr > 0)) { // const QString name("graph_corrected_" // + QString::number(ctr) // + ".nii.gz"); // correctedSegmentationVolumeFile->writeFile(name); //} // // Create background volume // if (needToGenerateBackgroundVolumeFlag) { backgroundVolumeFile = (*correctedSegmentationVolumeFile); backgroundVolumeFile.invertSegmentationVoxels(); } // // Compute foreground and background graphs for each axis // 0-2 are foreground, 3-5 are background // const int numGraphs = 6; BrainModelVolumeTopologyGraph* graphs[numGraphs]; createForegroundAndBackgroundGraphs(correctedSegmentationVolumeFile, &backgroundVolumeFile, foregroundVoxelConnectivity, backgroundVoxelConnectivity, graphs); // // Loop through graphs and find smallest handle // int fewestVoxelsGraphGraphIndex = -1; int fewestVoxelsCycleIndex = -1; int fewestVoxelsNumberOfVoxels = std::numeric_limits::max(); std::vector fewestVoxelVertices; switch (correctionMode) { case CORRECTION_MODE_MINIMAL: { int fewestVoxelsVertexIndex = -1; for (int i = 0; i < 6; i++) { int cycleIndex; int vertexIndex; int numberOfVoxels; graphs[i]->getGraphCycleWithSmallestVertex(cycleIndex, vertexIndex, numberOfVoxels); if (cycleIndex >= 0) { if (numberOfVoxels <= fewestVoxelsNumberOfVoxels) { fewestVoxelsNumberOfVoxels = numberOfVoxels; fewestVoxelsCycleIndex = cycleIndex; fewestVoxelsVertexIndex = vertexIndex; fewestVoxelsGraphGraphIndex = i; } } } if (fewestVoxelsVertexIndex >= 0) { fewestVoxelVertices.push_back( graphs[fewestVoxelsGraphGraphIndex]->getGraphVertex(fewestVoxelsVertexIndex)); } } break; case CORRECTION_MODE_NORMAL: { std::vector fewestVertexIndices; for (int i = 0; i < 6; i++) { int cycleIndex; int numberOfVoxels; std::vector vertexIndices; graphs[i]->getGraphCycleWithSmallestHandle(cycleIndex, vertexIndices, numberOfVoxels); if (cycleIndex >= 0) { if (numberOfVoxels <= fewestVoxelsNumberOfVoxels) { fewestVoxelsNumberOfVoxels = numberOfVoxels; fewestVoxelsCycleIndex = cycleIndex; fewestVertexIndices = vertexIndices; fewestVoxelsGraphGraphIndex = i; } } } if (fewestVoxelsGraphGraphIndex >= 0) { const int num = static_cast(fewestVertexIndices.size()); for (int m = 0; m < num; m++) { fewestVoxelVertices.push_back( graphs[fewestVoxelsGraphGraphIndex]->getGraphVertex(fewestVertexIndices[m])); } } } break; } if (fewestVoxelsGraphGraphIndex >= 0) { const BrainModelVolumeTopologyGraph::GraphCycle* cycle = graphs[fewestVoxelsGraphGraphIndex]->getGraphCycle(fewestVoxelsCycleIndex); if ((fewestVoxelsGraphGraphIndex >= 0) && (fewestVoxelsGraphGraphIndex <= 2)) { // // If smallest handle is in foreground so // remove voxels from volume // addRemoveVoxels(correctedSegmentationVolumeFile, &backgroundVolumeFile, graphs[fewestVoxelsGraphGraphIndex], cycle, fewestVoxelVertices, false); } else if ((fewestVoxelsGraphGraphIndex >= 3) && (fewestVoxelsGraphGraphIndex <= 5)) { // // Smallest handle in background so use // it to fill in the foreground // addRemoveVoxels(correctedSegmentationVolumeFile, &backgroundVolumeFile, graphs[fewestVoxelsGraphGraphIndex], cycle, fewestVoxelVertices, true); } // // Remove any islands DO NOT FILL CAVITIES HERE // needToGenerateBackgroundVolumeFlag = correctedSegmentationVolumeFile->removeIslandsFromSegmentation(); if (needToGenerateBackgroundVolumeFlag) { std::cout << "Volume Topology Graph islands removed." << std::endl; } } else { // // No handles, so done // done = true; } // // Free the graphs // for (int i = 0; i < numGraphs; i++) { delete graphs[i]; graphs[i] = NULL; } } } // // Fill any cavities that may be present // correctedSegmentationVolumeFile->fillSegmentationCavities(); // // Count the number of voxels changed // int dimI, dimJ, dimK; uncorrectedVolumeFile.getDimensions(dimI, dimJ, dimK); for (int i = 0; i < dimI; i++) { for (int j = 0; j < dimJ; j++) { for (int k = 0; k < dimK; k++) { if (uncorrectedVolumeFile.getVoxel(i, j, k, 0) != correctedSegmentationVolumeFile->getVoxel(i, j, k, 0)) { numberOfVoxelsChanged++; } } } } correctedSegmentationVolumeFile->makeDefaultFileName("Segment_GraphErrorCorrected"); correctedSegmentationVolumeFile->setDescriptiveLabel("Segment_GraphErrorCorrected"); } /** * add or remove voxels to/from a volume. */ void BrainModelVolumeTopologyGraphCorrector::addRemoveVoxels( VolumeFile* foregroundVolumeFile, VolumeFile* backgroundVolumeFile, const BrainModelVolumeTopologyGraph* graph, const BrainModelVolumeTopologyGraph::GraphCycle* cycle, const std::vector vertices, const bool addVoxelsFlag) { std::cout << QString(70, '-').toAscii().constData() << std::endl; QString addRemoveString("Removing "); int newForegroundVoxelValue = 0; int newBackgroundVoxelValue = 255; int paintVolumeVoxelIndex = paintVoxelRemovedIndex; if (addVoxelsFlag) { newForegroundVoxelValue = 255; newBackgroundVoxelValue = 0; addRemoveString = "Adding "; paintVolumeVoxelIndex = paintVoxelAddedIndex; } QString axisText("Unknown"); switch (graph->getSearchAxis()) { case BrainModelVolumeTopologyGraph::SEARCH_AXIS_X: axisText = "X-Axis"; break; case BrainModelVolumeTopologyGraph::SEARCH_AXIS_Y: axisText = "Y-Axis"; break; case BrainModelVolumeTopologyGraph::SEARCH_AXIS_Z: axisText = "Z-Axis"; break; } const int numVertices = static_cast(vertices.size()); std::vector voxels; for (int i = 0; i < numVertices; i++) { const int numVoxelsInVertex = vertices[i]->getNumberOfVoxels(); for (int j = 0; j < numVoxelsInVertex; j++) { voxels.push_back(*vertices[i]->getVoxel(j)); } } const int numVoxels = static_cast(voxels.size()); std::cout << addRemoveString.toAscii().constData() << numVoxels << " voxels using vertices in slice "; for (int n = 0; n < numVertices; n++) { std::cout << vertices[n]->getSliceNumber() << " "; } std::cout << " along " << axisText.toAscii().constData() << std::endl; std::cout << " from cycle: "; const int numGraphVerticesInCycle = cycle->getNumberOfGraphVerticesInCycle(); for (int j = 0; j < numGraphVerticesInCycle; j++) { const int graphVertexIndex = cycle->getGraphVertexIndex(j); const BrainModelVolumeTopologyGraph::GraphVertex* vertex = graph->getGraphVertex(graphVertexIndex); std::cout << vertex->getSliceNumber() << "(" << vertex->getNumberOfVoxels() << ") "; } std::cout << std::endl; for (int i = 0; i < numVoxels; i++) { foregroundVolumeFile->setVoxel(voxels[i], 0, newForegroundVoxelValue); backgroundVolumeFile->setVoxel(voxels[i], 0, newBackgroundVoxelValue); showingCorrectionsPaintVolumeFile->setVoxel(voxels[i], 0, paintVolumeVoxelIndex); } } /** * create the foreground and background graphs. */ void BrainModelVolumeTopologyGraphCorrector::createForegroundAndBackgroundGraphs( const VolumeFile* foregroundVolumeFile, const VolumeFile* backgroundVolumeFile, const BrainModelVolumeTopologyGraph::VOXEL_NEIGHBOR_CONNECTIVITY foregroundVoxelConnectivity, const BrainModelVolumeTopologyGraph::VOXEL_NEIGHBOR_CONNECTIVITY backgroundVoxelConnectivity, BrainModelVolumeTopologyGraph* graphsOut[6]) const throw (BrainModelAlgorithmException) { // // Foreground graphs // graphsOut[0] = new BrainModelVolumeTopologyGraph(brainSet, foregroundVolumeFile, BrainModelVolumeTopologyGraph::SEARCH_AXIS_X, foregroundVoxelConnectivity); graphsOut[1] = new BrainModelVolumeTopologyGraph(brainSet, foregroundVolumeFile, BrainModelVolumeTopologyGraph::SEARCH_AXIS_Y, foregroundVoxelConnectivity); graphsOut[2] = new BrainModelVolumeTopologyGraph(brainSet, foregroundVolumeFile, BrainModelVolumeTopologyGraph::SEARCH_AXIS_Z, foregroundVoxelConnectivity); // // Background (inverted segmentation) graphs // graphsOut[3] = new BrainModelVolumeTopologyGraph(brainSet, backgroundVolumeFile, BrainModelVolumeTopologyGraph::SEARCH_AXIS_X, backgroundVoxelConnectivity); graphsOut[4] = new BrainModelVolumeTopologyGraph(brainSet, backgroundVolumeFile, BrainModelVolumeTopologyGraph::SEARCH_AXIS_Y, backgroundVoxelConnectivity); graphsOut[5] = new BrainModelVolumeTopologyGraph(brainSet, backgroundVolumeFile, BrainModelVolumeTopologyGraph::SEARCH_AXIS_Z, backgroundVoxelConnectivity); for (int i = 0; i < 6; i++) { graphsOut[i]->execute(); } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeTopologyGraph.h0000664000175000017500000003536211572067322026012 0ustar michaelmichael #ifndef __BRAIN_MODEL_VOLUME_TOPOLOGY_GRAPH_H__ #define __BRAIN_MODEL_VOLUME_TOPOLOGY_GRAPH_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include "BrainModelAlgorithm.h" #include "VoxelIJK.h" class VolumeFile; /// create graph of segmentation volume topology /// This algorithm is based off the paper "Automated Topology Correction /// for Human Brain Segmentation" by Lin Chen and Gudrun Wagenknecht, /// MICCAI 2006, LNCS 4191, pp. 316-323, 2006. Springer-Verlag. class BrainModelVolumeTopologyGraph : public BrainModelAlgorithm { public: // search axis enum SEARCH_AXIS { // search along X axis SEARCH_AXIS_X, // search along Y axis SEARCH_AXIS_Y, // search along Z axis SEARCH_AXIS_Z }; // voxel neighbor connectivity enum VOXEL_NEIGHBOR_CONNECTIVITY { // 6-connected VOXEL_NEIGHBOR_CONNECTIVITY_6, // 18-connected VOXEL_NEIGHBOR_CONNECTIVITY_18, // 26-connected VOXEL_NEIGHBOR_CONNECTIVITY_26 }; /// Edge in the graph class GraphEdge { public: // constructor GraphEdge(const int vertexNumberIn, const int strengthIn) { vertexNumber = vertexNumberIn; strength = strengthIn; } // destructor ~GraphEdge() { } // get the vertex number int getVertexNumber() const { return vertexNumber; } // get the strength int getStrength() const { return strength; } protected: // the vertex number int vertexNumber; // the strength int strength; }; /// Vertex in the graph class GraphVertex { public: // constructor GraphVertex(const int sliceNumberIn) { sliceNumber = sliceNumberIn; identifier = -1; } // destructor ~GraphVertex() { voxels.clear(); } /// add a voxel to the vertex void addVoxel(const VoxelIJK& v) { voxels.push_back(v); } /// add connected graph vertex index void addConnectedGraphVertex(const int vertexIndex, const int strength) { connectedGraphEdges.push_back(GraphEdge(vertexIndex, strength)); } /// get number of connected graph edges int getNumberOfConnectedGraphEdges() const { return connectedGraphEdges.size(); } /// get connected graph vertex index const GraphEdge* getConnectedGraphEdge(const int indx) const { return &connectedGraphEdges[indx]; } /// get the number of voxels in the vertex int getNumberOfVoxels() const { return voxels.size(); } /// get a voxel const VoxelIJK* getVoxel(const int indx) const { return &voxels[indx]; } /// get the slice number int getSliceNumber() const { return sliceNumber; } /// get the identifier int getIdentifier() const { return identifier; } /// set the identifier void setIdentifier(const int id) { identifier = id; } /// get a descriptive name (slice_number and identifier) QString getDescriptiveName() const { return ("S" + QString::number(sliceNumber) //+ "I" + QString::number(identifier) + "N" + QString::number(voxels.size())); } /// the slice number int sliceNumber; /// voxels in vertex std::vector voxels; /// connected graph edges std::vector connectedGraphEdges; /// identifier int identifier; }; /// cycle in the graph class GraphCycle { public: // constructor GraphCycle(); // destructor ~GraphCycle(); // clear the cycle void clear(); /// is cycle empty bool empty() const { return cycle.empty(); } // number of graph vertices in cycle int getNumberOfGraphVerticesInCycle() const { return cycle.size(); } // get index of graph vertex in cycle int getGraphVertexIndex(const int indx) const { return cycle[indx]; } // set the cycle void set(const std::vector& cycleVerticesIn, const std::vector& cycleSlicesIn); /// get the handle vertices std::vector getHandleVertices() const { return handleVertices; } /// get the number of voxels that make up the handle int getHandleSizeInVoxels() const { return numVoxelsInHandle; } // set the vertices that form the handle void setHandleVertices(const std::vector& handleVerticesIn, const int numVoxelsInHandleIn); // equality operator bool operator==(const GraphCycle& c) const; // comparison operator bool operator<(const GraphCycle& c) const; // get the cycle std::vector getCycle() const; protected: /// the cycle std::vector cycle; /// the cycle in sorted order (used for comparisons) std::vector cycleSorted; /// the vertices that form the handle in the cycle std::vector handleVertices; /// number of voxels in the handle int numVoxelsInHandle; }; // constructor BrainModelVolumeTopologyGraph(BrainSet* bsIn, const VolumeFile* segmentationVolumeFileIn, const SEARCH_AXIS searchAxisIn, const VOXEL_NEIGHBOR_CONNECTIVITY voxelConnectivityIn); // destructor ~BrainModelVolumeTopologyGraph(); // execute the algorithm void execute() throw (BrainModelAlgorithmException); /// get the number of vertices in the graph int getNumberOfGraphVertices() const { return graphVertices.size(); } /// get a vertex in the graph GraphVertex* getGraphVertex(const int indx) { return graphVertices[indx]; } /// get a vertex in the graph (const method) const GraphVertex* getGraphVertex(const int indx) const { return graphVertices[indx]; } /// get number of cycles in graph int getNumberOfGraphCycles() const { return graphCycles.size(); } /// get a cycle in the graph GraphCycle* getGraphCycle(const int indx) { return &graphCycles[indx]; } /// get a cycle in the graph (const method) const GraphCycle* getGraphCycle(const int indx) const { return &graphCycles[indx]; } /// get cycle with smallest vertex (vertex that contains fewest voxels) void getGraphCycleWithSmallestVertex(int &cycleIndexOut, int &vertexIndexOut, int &numberofVoxelsOut) const; /// get cycle with smallest handle (handle that contains fewest voxels) void getGraphCycleWithSmallestHandle(int &cycleIndexOut, std::vector& vertexIndicesOut, int &numberOfVoxelsOut) const; // print the results void printResults() const; // get the search axis SEARCH_AXIS getSearchAxis() const { return searchAxis; } // create an paint volume file containing the handles void createHandlesPaintVolumeFile(VolumeFile& handlesPaintVolumeFile); // write the graph to a paint volume file void writeGraphToPaintVolumeFile(const QString& paintVolumeFileName) const throw (BrainModelAlgorithmException); // write graph to graphviz file void writeGraphVizDotFile(const QString& dotFileName) const throw (BrainModelAlgorithmException); protected: /// slice neighbor connectivity enum SLICE_NEIGHBOR_CONNECTIVITY { /// 4-connected SLICE_NEIGHBOR_CONNECTIVITY_4, /// 8-connected SLICE_NEIGHBOR_CONNECTIVITY_8 }; /// vertex visited status enum VISITED_STATUS { NOT_VISITED = 0, VISITED = 1 }; /// A slice of a volume class VolumeSlice { public: // constructor VolumeSlice(const int dimIin, const int dimJin); // destructor ~VolumeSlice(); // get indices valid bool getIJValid(const int i, const int j) const; // get dimension I int getDimI() const { return dimI; } // get dimension J int getDimJ() const { return dimJ; } // set a voxel in the slice void setVoxel(const SEARCH_AXIS searchAxis, const VoxelIJK& v, const int value); // get a voxel in the slice float getVoxel(const SEARCH_AXIS searchAxis, const VoxelIJK& v) const; // set a voxel in the slice void setVoxel(const int horizIndex, const int vertIndex, const int value); // get a voxel in the slice float getVoxel(const int horizIndex, const int vertIndex) const; // set all voxels in the slice void setAllVoxels(const int value); protected: // get the index int getIndex(const SEARCH_AXIS searchAxis, const VoxelIJK& v) const; // get the index int getIndex(const int horizIndex, const int vertIndex) const; /// the voxels int* voxels; /// dimension I int dimI; /// dimension J int dimJ; }; // create the vertices in the graph void createGraphVertices() throw (BrainModelAlgorithmException); // create the edges (connections between vertices) in the graph void createGraphEdges() throw (BrainModelAlgorithmException); // search graph for cycles void searchGraphForCycles(); // determine the handles void determineHandles(); // perform breadth first search void breadthFirstSearchForCycles(const int startVertexIndex, const int searchForVertexIndex, GraphCycle& cycleOut); // get voxel slice neighbors void getVoxelSliceNeighbors(const VoxelIJK& v, const VolumeSlice& slice, const int searchForValue, std::vector& neighborsOut) const; // add a slice neighboring voxel if valid and not searched void addSliceNeighbor(const VolumeSlice& slice, const int i, const int j, const int k, const int searchForValue, std::vector& neighborsOut) const; // get graph vertex connected neighbors void getGraphVertexConnectedNeighbors(const VoxelIJK& v, const bool adjoiningSlicesOnlyFlag, std::map& graphVertexNeighborsInOut) const; // get graph vertex connected neighbors in next slice only void getGraphVertexConnectedNeighborsInNextSlice(const VoxelIJK& v, std::map& graphVertexNeighborsInOut) const; // add a graph vertex neighbor void addGraphVertexNeighbor(const int i, const int j, const int k, std::set& neighborsOut) const; // print vertices in the graph void printGraphVertices() const; // print cycles in the graph void printGraphCycles() const; /// adjust IJK for axis being processed void ijkForSlice(int& i, int& j, int& k) const; /// get IJK from loop void ijkFromLoop(const int horiz, const int vert, const int slice, int& i, int& j, int& k) const; /// Get voxel connects to voxels in another vertex. bool getVoxelConnectedToGraphVertex(const VoxelIJK& v1, const int otherGraphVertexIndex) const; /// input segmentation volume const VolumeFile* inputSegmentationVolumeFile; /// segmentation volume on which topology graph is built VolumeFile* segmentationVolumeFile; /// vertices in the graph std::vector graphVertices; /// cycles in the graph std::vector graphCycles; /// the search axis SEARCH_AXIS searchAxis; /// the voxel connectivity VOXEL_NEIGHBOR_CONNECTIVITY volumeConnectivity; /// the slice connectivity SLICE_NEIGHBOR_CONNECTIVITY sliceConnectivity; // volume where the voxel values are the index of the graph // vertex to which the voxel belongs VolumeFile* voxelGraphVertexIndexVolumeFile; }; #endif // __BRAIN_MODEL_VOLUME_TOPOLOGY_GRAPH_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeTopologyGraph.cxx0000664000175000017500000015405311572067322026364 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include "BrainModelVolumeTopologyGraph.h" #include "VolumeFile.h" /** * constructor. */ BrainModelVolumeTopologyGraph::BrainModelVolumeTopologyGraph( BrainSet* bsIn, const VolumeFile* segmentationVolumeFileIn, const SEARCH_AXIS searchAxisIn, const VOXEL_NEIGHBOR_CONNECTIVITY volumeConnectivityIn) : BrainModelAlgorithm(bsIn), inputSegmentationVolumeFile(segmentationVolumeFileIn), searchAxis(searchAxisIn), volumeConnectivity(volumeConnectivityIn) { segmentationVolumeFile = NULL; voxelGraphVertexIndexVolumeFile = NULL; } /** * destructor. */ BrainModelVolumeTopologyGraph::~BrainModelVolumeTopologyGraph() { const int num = getNumberOfGraphVertices(); for (int i = 0; i < num; i++) { delete graphVertices[i]; graphVertices[i] = NULL; } graphVertices.clear(); if (voxelGraphVertexIndexVolumeFile != NULL) { delete voxelGraphVertexIndexVolumeFile; voxelGraphVertexIndexVolumeFile = NULL; } if (segmentationVolumeFile != NULL) { delete segmentationVolumeFile; segmentationVolumeFile = NULL; } } /** * execute the algorithm. */ void BrainModelVolumeTopologyGraph::execute() throw (BrainModelAlgorithmException) { if (inputSegmentationVolumeFile == NULL) { throw BrainModelAlgorithmException("Segmentation Volume is invalid"); } // // Make a copy of the input segmentation volume file // segmentationVolumeFile = new VolumeFile(*inputSegmentationVolumeFile); // // Set slice connectivity based opon voxel connectivity // switch (volumeConnectivity) { case VOXEL_NEIGHBOR_CONNECTIVITY_6: sliceConnectivity = SLICE_NEIGHBOR_CONNECTIVITY_4; break; case VOXEL_NEIGHBOR_CONNECTIVITY_18: sliceConnectivity = SLICE_NEIGHBOR_CONNECTIVITY_8; break; case VOXEL_NEIGHBOR_CONNECTIVITY_26: sliceConnectivity = SLICE_NEIGHBOR_CONNECTIVITY_8; break; } // // Create a volume where the voxel values are the index of the graph // vertex to which the voxel belongs // voxelGraphVertexIndexVolumeFile = new VolumeFile(*segmentationVolumeFile); voxelGraphVertexIndexVolumeFile->setAllVoxels(-1.0); // // Create the vertices in the graph // createGraphVertices(); // // Create the graph edges (connections between vertices) // createGraphEdges(); // // Search for cycles (which are handles) // searchGraphForCycles(); // // Determine the voxels that form the handle part of the handle // determineHandles(); } /** * write the graph to a paint volume file. */ void BrainModelVolumeTopologyGraph::writeGraphToPaintVolumeFile(const QString& paintVolumeFileName) const throw (BrainModelAlgorithmException) { VolumeFile paintVolumeFile = *inputSegmentationVolumeFile; paintVolumeFile.setVolumeType(VolumeFile::VOLUME_TYPE_PAINT); const int backgroundValue = paintVolumeFile.addRegionName("???"); paintVolumeFile.setAllVoxels(backgroundValue); const int numGraphVertices = getNumberOfGraphVertices(); for (int i = 0; i < numGraphVertices; i++) { const GraphVertex* vertex = getGraphVertex(i); const int numVoxels = vertex->getNumberOfVoxels(); if (numVoxels > 0) { const int paintIndex = paintVolumeFile.addRegionName(vertex->getDescriptiveName()); for (int i = 0; i < numVoxels; i++) { const VoxelIJK* v = vertex->getVoxel(i); paintVolumeFile.setVoxel(*v, 0, paintIndex); } } } try { paintVolumeFile.writeFile(paintVolumeFileName); } catch (FileException& e) { throw BrainModelAlgorithmException(e); } } /** * write graph to graphvis file. */ void BrainModelVolumeTopologyGraph::writeGraphVizDotFile(const QString& dotFileName) const throw (BrainModelAlgorithmException) { QFile file(dotFileName); if (file.open(QFile::WriteOnly)) { QTextStream stream(&file); stream << "graph G {\n"; const int numGraphVertices = getNumberOfGraphVertices(); for (int i = 0; i < numGraphVertices; i++) { const GraphVertex* vertex = getGraphVertex(i); const int numConnections = vertex->getNumberOfConnectedGraphEdges(); for (int m = 0; m < numConnections; m++) { const GraphEdge* edge = vertex->getConnectedGraphEdge(m); if (i < edge->getVertexNumber()) { const GraphVertex* otherVertex = getGraphVertex(edge->getVertexNumber()); stream << " " << vertex->getDescriptiveName() << " -- " << otherVertex->getDescriptiveName() << ";\n"; } } } stream << "}\n"; file.close(); } else { throw BrainModelAlgorithmException("Unable to open file " + dotFileName + ": " + file.errorString()); } } /** * print the results. */ void BrainModelVolumeTopologyGraph::printResults() const { // // Print vertices in graph // printGraphVertices(); // // Print cycles in graph // printGraphCycles(); } /** * create the vertices in the graph. */ void BrainModelVolumeTopologyGraph::createGraphVertices() throw (BrainModelAlgorithmException) { // // Get dimensions of the volume // int dimensions[3]; segmentationVolumeFile->getDimensions(dimensions); if ((dimensions[0] <= 0) || (dimensions[1] <= 0) || (dimensions[2] <= 0)) { throw BrainModelAlgorithmException("At least one volume dimension is zero."); } int sliceLoopEnd = 0; int horizLoopEnd = 0; int vertLoopEnd = 0; switch (searchAxis) { case SEARCH_AXIS_X: sliceLoopEnd = dimensions[0]; horizLoopEnd = dimensions[1]; vertLoopEnd = dimensions[2]; break; case SEARCH_AXIS_Y: sliceLoopEnd = dimensions[1]; horizLoopEnd = dimensions[0]; vertLoopEnd = dimensions[2]; break; case SEARCH_AXIS_Z: sliceLoopEnd = dimensions[2]; horizLoopEnd = dimensions[0]; vertLoopEnd = dimensions[1]; break; default: throw BrainModelAlgorithmException("Invalid search axis none of X/Y/Z."); break; } // // Keep track of voxels in the slice that have been processed // VolumeSlice voxelsVisitedSlice(horizLoopEnd, vertLoopEnd); // // Loop through slices // for (int sliceLoop = 0; sliceLoop < sliceLoopEnd; sliceLoop++) { // // Initialize all segmentation voxels to unvisited // for (int horizLoop = 0; horizLoop < horizLoopEnd; horizLoop++) { for (int vertLoop = 0; vertLoop < vertLoopEnd; vertLoop++) { int i = 0, j = 0, k = 0; ijkFromLoop(horizLoop, vertLoop, sliceLoop, i, j, k); if (segmentationVolumeFile->getVoxel(i, j, k, 0) != 0) { voxelsVisitedSlice.setVoxel(horizLoop, vertLoop, NOT_VISITED); } else { voxelsVisitedSlice.setVoxel(horizLoop, vertLoop, VISITED); } } } // // Find connected components in slice, each becomes vertex in graph // for (int horizLoop = 0; horizLoop < horizLoopEnd; horizLoop++) { for (int vertLoop = 0; vertLoop < vertLoopEnd; vertLoop++) { int i = 0, j = 0, k = 0; ijkFromLoop(horizLoop, vertLoop, sliceLoop, i, j, k); if (voxelsVisitedSlice.getVoxel(horizLoop, vertLoop) == NOT_VISITED) { // // Create a vertex in the graph // GraphVertex* vertex = new GraphVertex(sliceLoop); // // Create a stack for finding connected components // std::stack stack; stack.push(VoxelIJK(i, j, k)); bool done = false; while (done == false) { // // Get next voxel to search // const VoxelIJK v = stack.top(); stack.pop(); // // Is voxel unvisited? // if (voxelsVisitedSlice.getVoxel(searchAxis, v) == NOT_VISITED) { // // Set visited // voxelsVisitedSlice.setVoxel(searchAxis, v, VISITED); // // Add voxel to graph vertex // vertex->addVoxel(v); // // Set graph vertex to which voxel belongs // voxelGraphVertexIndexVolumeFile->setVoxel(v, 0, graphVertices.size()); // // Search neighbors // std::vector neighbors; getVoxelSliceNeighbors(v, voxelsVisitedSlice, NOT_VISITED, neighbors); // // Add neighbors to stack // const int numNeigh = static_cast(neighbors.size()); for (int m = 0; m < numNeigh; m++) { stack.push(neighbors[m]); } } // // If no more vertices to search, then done // if (stack.empty()) { done = true; } } // // Add the vertex to the graph // const int graphVertexIndex = static_cast(graphVertices.size()); vertex->setIdentifier(graphVertexIndex); graphVertices.push_back(vertex); } } } } } /** * adjust IJK for axis being processed. */ void BrainModelVolumeTopologyGraph::ijkForSlice(int& i, int& j, int& k) const { int ii = i, jj = j, kk = k; switch (searchAxis) { case SEARCH_AXIS_X: i = jj; j = kk; k = ii; break; case SEARCH_AXIS_Y: i = ii; j = kk; k = jj; break; case SEARCH_AXIS_Z: i = ii; j = jj; k = kk; break; } } /** * get IJK from loop. */ void BrainModelVolumeTopologyGraph::ijkFromLoop(const int horiz, const int Vert, const int slice, int& i, int& j, int& k) const { switch (searchAxis) { case SEARCH_AXIS_X: i = slice; j = horiz; k = Vert; break; case SEARCH_AXIS_Y: i = horiz; j = slice; k = Vert; break; case SEARCH_AXIS_Z: i = horiz; j = Vert; k = slice; break; } } /** * create the edges (connections) in the graph. */ void BrainModelVolumeTopologyGraph::createGraphEdges() throw (BrainModelAlgorithmException) { const bool increasingSlicesOnlyFlag = true; // // Loop through the graph vertices // const int numGraphVertices = getNumberOfGraphVertices(); for (int m = 0; m < numGraphVertices; m++) { // // Get the vertex in the graph // GraphVertex* vertex = getGraphVertex(m); // // Graph vertices to which this graph vertex is connected // key is vertex number, value is strength // std::map connectedGraphVertexIndices; // // Loop through the voxels in the graph vertex // const int numVoxels = vertex->getNumberOfVoxels(); for (int n = 0; n < numVoxels; n++) { // // Get the voxel // const VoxelIJK* voxel = vertex->getVoxel(n); // // Get the connected neighbors // if (increasingSlicesOnlyFlag) { getGraphVertexConnectedNeighborsInNextSlice(*voxel, connectedGraphVertexIndices); } else { getGraphVertexConnectedNeighbors(*voxel, true, connectedGraphVertexIndices); } } // // Set the connections // for (std::map::const_iterator iter = connectedGraphVertexIndices.begin(); iter != connectedGraphVertexIndices.end(); iter++) { const int graphVertexNumber = iter->first; const int strength = iter->second; if (graphVertexNumber != m) { if (vertex->getSliceNumber() == getGraphVertex(graphVertexNumber)->getSliceNumber()) { throw BrainModelAlgorithmException( "BrainModelVolumeTopologyGraph ERROR: " "graph vertex connected to another in same slice " + vertex->getSliceNumber()); } vertex->addConnectedGraphVertex(graphVertexNumber, strength); if (increasingSlicesOnlyFlag) { getGraphVertex(graphVertexNumber)->addConnectedGraphVertex(m, strength); } } } } } /** * get graph vertex connected neighbors in next slice only */ void BrainModelVolumeTopologyGraph::getGraphVertexConnectedNeighborsInNextSlice(const VoxelIJK& v, std::map& graphVertexNeighborsInOut) const { const int i = v.getI(); const int j = v.getJ(); const int k = v.getK(); std::set uniqueNeighbors; switch (volumeConnectivity) { case VOXEL_NEIGHBOR_CONNECTIVITY_26: switch (searchAxis) { case SEARCH_AXIS_X: // // Add neighbors that share a corner // addGraphVertexNeighbor(i + 1, j - 1, k - 1, uniqueNeighbors); addGraphVertexNeighbor(i + 1, j + 1, k - 1, uniqueNeighbors); addGraphVertexNeighbor(i + 1, j - 1, k + 1, uniqueNeighbors); addGraphVertexNeighbor(i + 1, j + 1, k + 1, uniqueNeighbors); break; case SEARCH_AXIS_Y: // // Add neighbors that share a corner // addGraphVertexNeighbor(i + 1, j + 1, k - 1, uniqueNeighbors); addGraphVertexNeighbor(i - 1, j + 1, k - 1, uniqueNeighbors); addGraphVertexNeighbor(i + 1, j + 1, k + 1, uniqueNeighbors); addGraphVertexNeighbor(i - 1, j + 1, k + 1, uniqueNeighbors); break; case SEARCH_AXIS_Z: // // Add neighbors that share a corner // addGraphVertexNeighbor(i - 1, j - 1, k + 1, uniqueNeighbors); addGraphVertexNeighbor(i + 1, j - 1, k + 1, uniqueNeighbors); addGraphVertexNeighbor(i + 1, j + 1, k + 1, uniqueNeighbors); addGraphVertexNeighbor(i - 1, j + 1, k + 1, uniqueNeighbors); break; } // // NO "break" !!!!! // Intentionally fall through to next case to get remaining neighbors // case VOXEL_NEIGHBOR_CONNECTIVITY_18: // // Add neighbors that share an edge // switch (searchAxis) { case SEARCH_AXIS_X: // // // slice above addGraphVertexNeighbor(i + 1, j, k - 1, uniqueNeighbors); addGraphVertexNeighbor(i + 1, j, k + 1, uniqueNeighbors); addGraphVertexNeighbor(i + 1, j - 1, k, uniqueNeighbors); addGraphVertexNeighbor(i + 1, j + 1, k, uniqueNeighbors); break; case SEARCH_AXIS_Y: // // // slice above addGraphVertexNeighbor(i - 1, j + 1, k, uniqueNeighbors); addGraphVertexNeighbor(i + 1, j + 1, k, uniqueNeighbors); addGraphVertexNeighbor(i, j + 1, k - 1, uniqueNeighbors); addGraphVertexNeighbor(i, j + 1, k + 1, uniqueNeighbors); break; case SEARCH_AXIS_Z: // // slice above // addGraphVertexNeighbor(i - 1, j, k + 1, uniqueNeighbors); addGraphVertexNeighbor(i + 1, j, k + 1, uniqueNeighbors); addGraphVertexNeighbor(i, j - 1, k + 1, uniqueNeighbors); addGraphVertexNeighbor(i, j + 1, k + 1, uniqueNeighbors); break; } // // NO "break" !!!!! // Intentionally fall through to next case to get remaining neighbors // case VOXEL_NEIGHBOR_CONNECTIVITY_6: // // Add neighbors that share a face // switch (searchAxis) { case SEARCH_AXIS_X: // // slice next // addGraphVertexNeighbor(i + 1, j, k, uniqueNeighbors); break; case SEARCH_AXIS_Y: // // slice next // addGraphVertexNeighbor(i, j + 1, k, uniqueNeighbors); break; case SEARCH_AXIS_Z: // // slice next // addGraphVertexNeighbor(i, j, k + 1, uniqueNeighbors); break; } break; } for (std::set::const_iterator iter = uniqueNeighbors.begin(); iter != uniqueNeighbors.end(); iter++) { const int vertexNumber = *iter; if (graphVertexNeighborsInOut.find(vertexNumber) == graphVertexNeighborsInOut.end()) { graphVertexNeighborsInOut[vertexNumber] = 1; } else { graphVertexNeighborsInOut[vertexNumber]++; } } } /** * get graph vertex connected neighbors. */ void BrainModelVolumeTopologyGraph::getGraphVertexConnectedNeighbors(const VoxelIJK& v, const bool adjoiningSlicesOnlyFlag, std::map& graphVertexNeighborsInOut) const { const int i = v.getI(); const int j = v.getJ(); const int k = v.getK(); std::set uniqueNeighbors; switch (volumeConnectivity) { case VOXEL_NEIGHBOR_CONNECTIVITY_26: // // Add neighbors that share a corner // addGraphVertexNeighbor(i - 1, j - 1, k - 1, uniqueNeighbors); addGraphVertexNeighbor(i + 1, j - 1, k - 1, uniqueNeighbors); addGraphVertexNeighbor(i + 1, j + 1, k - 1, uniqueNeighbors); addGraphVertexNeighbor(i - 1, j + 1, k - 1, uniqueNeighbors); addGraphVertexNeighbor(i - 1, j - 1, k + 1, uniqueNeighbors); addGraphVertexNeighbor(i + 1, j - 1, k + 1, uniqueNeighbors); addGraphVertexNeighbor(i + 1, j + 1, k + 1, uniqueNeighbors); addGraphVertexNeighbor(i - 1, j + 1, k + 1, uniqueNeighbors); // // NO "break" !!!!! // Intentionally fall through to next case to get remaining neighbors // case VOXEL_NEIGHBOR_CONNECTIVITY_18: // // Add neighbors that share an edge // switch (searchAxis) { case SEARCH_AXIS_X: // // Same slice // if (adjoiningSlicesOnlyFlag == false) { addGraphVertexNeighbor(i, j - 1, k - 1, uniqueNeighbors); addGraphVertexNeighbor(i, j - 1, k + 1, uniqueNeighbors); addGraphVertexNeighbor(i, j + 1, k + 1, uniqueNeighbors); addGraphVertexNeighbor(i, j + 1, k - 1, uniqueNeighbors); } // // Slice below // addGraphVertexNeighbor(i - 1, j, k - 1, uniqueNeighbors); addGraphVertexNeighbor(i - 1, j, k + 1, uniqueNeighbors); addGraphVertexNeighbor(i - 1, j - 1, k, uniqueNeighbors); addGraphVertexNeighbor(i - 1, j + 1, k, uniqueNeighbors); // // // slice above addGraphVertexNeighbor(i + 1, j, k - 1, uniqueNeighbors); addGraphVertexNeighbor(i + 1, j, k + 1, uniqueNeighbors); addGraphVertexNeighbor(i + 1, j - 1, k, uniqueNeighbors); addGraphVertexNeighbor(i + 1, j + 1, k, uniqueNeighbors); break; case SEARCH_AXIS_Y: // // Same slice // if (adjoiningSlicesOnlyFlag == false) { addGraphVertexNeighbor(i - 1, j, k - 1, uniqueNeighbors); addGraphVertexNeighbor(i + 1, j, k - 1, uniqueNeighbors); addGraphVertexNeighbor(i + 1, j, k + 1, uniqueNeighbors); addGraphVertexNeighbor(i - 1, j, k + 1, uniqueNeighbors); } // // Slice below // addGraphVertexNeighbor(i - 1, j - 1, k, uniqueNeighbors); addGraphVertexNeighbor(i + 1, j - 1, k, uniqueNeighbors); addGraphVertexNeighbor(i, j - 1, k - 1, uniqueNeighbors); addGraphVertexNeighbor(i, j - 1, k + 1, uniqueNeighbors); // // // slice above addGraphVertexNeighbor(i - 1, j + 1, k, uniqueNeighbors); addGraphVertexNeighbor(i + 1, j + 1, k, uniqueNeighbors); addGraphVertexNeighbor(i, j + 1, k - 1, uniqueNeighbors); addGraphVertexNeighbor(i, j + 1, k + 1, uniqueNeighbors); break; case SEARCH_AXIS_Z: // // Same slice // if (adjoiningSlicesOnlyFlag == false) { addGraphVertexNeighbor(i - 1, j - 1, k, uniqueNeighbors); addGraphVertexNeighbor(i + 1, j - 1, k, uniqueNeighbors); addGraphVertexNeighbor(i + 1, j + 1, k, uniqueNeighbors); addGraphVertexNeighbor(i - 1, j + 1, k, uniqueNeighbors); } // // Slice below // addGraphVertexNeighbor(i - 1, j, k - 1, uniqueNeighbors); addGraphVertexNeighbor(i + 1, j, k - 1, uniqueNeighbors); addGraphVertexNeighbor(i, j - 1, k - 1, uniqueNeighbors); addGraphVertexNeighbor(i, j + 1, k - 1, uniqueNeighbors); // // slice above // addGraphVertexNeighbor(i - 1, j, k + 1, uniqueNeighbors); addGraphVertexNeighbor(i + 1, j, k + 1, uniqueNeighbors); addGraphVertexNeighbor(i, j - 1, k + 1, uniqueNeighbors); addGraphVertexNeighbor(i, j + 1, k + 1, uniqueNeighbors); break; } // // NO "break" !!!!! // Intentionally fall through to next case to get remaining neighbors // case VOXEL_NEIGHBOR_CONNECTIVITY_6: // // Add neighbors that share a face // switch (searchAxis) { case SEARCH_AXIS_X: if (adjoiningSlicesOnlyFlag == false) { // // left/right // addGraphVertexNeighbor(i, j - 1, k, uniqueNeighbors); addGraphVertexNeighbor(i, j + 1, k, uniqueNeighbors); // // down/up // addGraphVertexNeighbor(i, j, k - 1, uniqueNeighbors); addGraphVertexNeighbor(i, j, k + 1, uniqueNeighbors); } // // slice prev/next // addGraphVertexNeighbor(i - 1, j, k, uniqueNeighbors); addGraphVertexNeighbor(i + 1, j, k, uniqueNeighbors); break; case SEARCH_AXIS_Y: if (adjoiningSlicesOnlyFlag == false) { // // left/right // addGraphVertexNeighbor(i - 1, j, k, uniqueNeighbors); addGraphVertexNeighbor(i + 1, j, k, uniqueNeighbors); // // down/up // addGraphVertexNeighbor(i, j, k - 1, uniqueNeighbors); addGraphVertexNeighbor(i, j, k + 1, uniqueNeighbors); } // // slice prev/next // addGraphVertexNeighbor(i, j - 1, k, uniqueNeighbors); addGraphVertexNeighbor(i, j + 1, k, uniqueNeighbors); break; case SEARCH_AXIS_Z: if (adjoiningSlicesOnlyFlag == false) { // // left/right // addGraphVertexNeighbor(i - 1, j, k, uniqueNeighbors); addGraphVertexNeighbor(i + 1, j, k, uniqueNeighbors); // // down/up // addGraphVertexNeighbor(i, j - 1, k, uniqueNeighbors); addGraphVertexNeighbor(i, j + 1, k, uniqueNeighbors); } // // slice prev/next // addGraphVertexNeighbor(i, j, k - 1, uniqueNeighbors); addGraphVertexNeighbor(i, j, k + 1, uniqueNeighbors); break; } break; } for (std::set::const_iterator iter = uniqueNeighbors.begin(); iter != uniqueNeighbors.end(); iter++) { const int vertexNumber = *iter; if (graphVertexNeighborsInOut.find(vertexNumber) == graphVertexNeighborsInOut.end()) { graphVertexNeighborsInOut[vertexNumber] = 1; } else { graphVertexNeighborsInOut[vertexNumber]++; } } } /** * add a graph vertex neighbor. */ void BrainModelVolumeTopologyGraph::addGraphVertexNeighbor(const int i, const int j, const int k, std::set& neighborsOut) const { if (voxelGraphVertexIndexVolumeFile->getVoxelIndexValid(i, j, k)) { const int graphVertexNumber = static_cast(voxelGraphVertexIndexVolumeFile->getVoxel(i, j, k, 0)); if (graphVertexNumber >= 0) { neighborsOut.insert(graphVertexNumber); } } } /** * determine the handles. */ void BrainModelVolumeTopologyGraph::determineHandles() { const int numCycles = getNumberOfGraphCycles(); for (int i = 0; i < numCycles; i++) { GraphCycle* cycle = getGraphCycle(i); // // Get the vertices in the cycle // std::vector cycleVertices = cycle->getCycle(); const int numVertices = static_cast(cycleVertices.size()); if (numVertices >= 4) { // // Find a "handleSize" sequence of vertices that contains the // smallest number of voxels // const int handleSize = (numVertices - 2) / 2; int minHandleVoxels = std::numeric_limits::max(); std::vector handleVertices; for (int j = 0; j < numVertices; j++) { int ctr = 0; int indx = j; int numVoxels = 0; std::vector vertexSequence; while (ctr < handleSize) { int vertexIndex = cycleVertices[indx]; numVoxels += getGraphVertex(vertexIndex)->getNumberOfVoxels(); vertexSequence.push_back(vertexIndex); ctr++; indx++; if (indx >= numVertices) { indx = 0; } } if (numVoxels < minHandleVoxels) { handleVertices = vertexSequence; minHandleVoxels = numVoxels; } } cycle->setHandleVertices(handleVertices, minHandleVoxels); } } } /** * search graph for cycles. */ void BrainModelVolumeTopologyGraph::searchGraphForCycles() { graphCycles.clear(); // // Loop through the graph vertices // const int numGraphVertices = getNumberOfGraphVertices(); for (int m = 0; m < numGraphVertices; m++) { // // Get the vertex in the graph // const GraphVertex* vertex = getGraphVertex(m); const int mySliceNumber = vertex->getSliceNumber(); // // Only search using slices "above" this vertex // for (int n = 0; n < vertex->getNumberOfConnectedGraphEdges(); n++) { // // Get the connected edge // const GraphEdge* edge = vertex->getConnectedGraphEdge(n); const int neighborIndex = edge->getVertexNumber(); const GraphVertex* neighborVertex = getGraphVertex(neighborIndex); if (neighborVertex->getSliceNumber() > mySliceNumber) { GraphCycle cycle; breadthFirstSearchForCycles(neighborIndex, vertex->getIdentifier(), cycle); if (cycle.empty() == false) { graphCycles.push_back(cycle); /* std::cout << "Cycle (" << m << " " << vertex->getIdentifier() << " " << neighborIndex << ") "; const std::vector cycleVertexIndices = cycle.getCycle(); for (unsigned int p = 0; p < cycleVertexIndices.size(); p++) { std::cout << cycleVertexIndices[p] << " "; } std::cout << std::endl; */ } } } } // // Sort the cycles and remove duplicates // std::sort(graphCycles.begin(), graphCycles.end()); std::vector::iterator iter = std::unique(graphCycles.begin(), graphCycles.end()); graphCycles.erase(iter, graphCycles.end()); } /** * perform breadth first search for cycles in graph */ void BrainModelVolumeTopologyGraph::breadthFirstSearchForCycles(const int startVertexIndex, const int searchForVertexIndex, GraphCycle& cycleOut) { cycleOut.clear(); // // Track path // const int numGraphVertices = getNumberOfGraphVertices(); std::vector vertexParentIndex(numGraphVertices, -1); std::vector visited(numGraphVertices, 0); // // Indices of vertices that need to be searched // std::queue queue; // // Add start vertex to the queue // queue.push(startVertexIndex); vertexParentIndex[startVertexIndex] = searchForVertexIndex; // // While there are vertices to search // while (queue.empty() == false) { // // Get a vertex index from the queue // const int vertexIndex = queue.front(); queue.pop(); // // Mark vertex visited // visited[vertexIndex] = 1; // // Is this what we are looking for? // if (vertexIndex == searchForVertexIndex) { // // Found target // std::vector cycleVertexIndices; cycleVertexIndices.push_back(vertexIndex); int parentIndex = vertexParentIndex[vertexIndex]; while ((parentIndex >= 0) && (parentIndex != searchForVertexIndex)) { cycleVertexIndices.push_back(parentIndex); parentIndex = vertexParentIndex[parentIndex]; } std::vector sliceNumbers; for (unsigned int i = 0; i < cycleVertexIndices.size(); i++) { sliceNumbers.push_back(getGraphVertex(cycleVertexIndices[i])->getSliceNumber()); } cycleOut.set(cycleVertexIndices, sliceNumbers); return; } else { // // Get the vertex // const GraphVertex* graphVertex = getGraphVertex(vertexIndex); // // Get connection edges // const int numConnectedGraphEdges = graphVertex->getNumberOfConnectedGraphEdges(); for (int i = 0; i < numConnectedGraphEdges; i++) { // // Get index of a connected graph vertex // const GraphEdge* edge = graphVertex->getConnectedGraphEdge(i); const int connVertexIndex = edge->getVertexNumber(); // // If vertex has NOT been visited // if (visited[connVertexIndex] == 0) { // // We are working with the starting vertex, do not // move to its parent which is the search for vertex // bool useIt = true; if (vertexIndex == startVertexIndex) { if (connVertexIndex == searchForVertexIndex) { useIt = false; } } if (useIt) { // // Set the parent for the connected vertex and place it in queue // vertexParentIndex[connVertexIndex] = vertexIndex; queue.push(connVertexIndex); } } } } } } /** * get voxel neighbors. */ void BrainModelVolumeTopologyGraph::getVoxelSliceNeighbors(const VoxelIJK& v, const VolumeSlice& slice, const int searchForValue, std::vector& neighborsOut) const { neighborsOut.clear(); const int i = v.getI(); const int j = v.getJ(); const int k = v.getK(); switch (searchAxis) { case SEARCH_AXIS_X: switch (sliceConnectivity) { case SLICE_NEIGHBOR_CONNECTIVITY_8: // // Add neighbors that share a corner // addSliceNeighbor(slice, i, j + 1, k + 1, searchForValue, neighborsOut); addSliceNeighbor(slice, i, j + 1, k - 1, searchForValue, neighborsOut); addSliceNeighbor(slice, i, j - 1, k - 1, searchForValue, neighborsOut); addSliceNeighbor(slice, i, j - 1, k + 1, searchForValue, neighborsOut); // // Intentionally fall through to get the inclusive 4-connected neighbors // case SLICE_NEIGHBOR_CONNECTIVITY_4: // // Add neighbors that share an edge // addSliceNeighbor(slice, i, j, k + 1, searchForValue, neighborsOut); addSliceNeighbor(slice, i, j, k - 1, searchForValue, neighborsOut); addSliceNeighbor(slice, i, j + 1, k, searchForValue, neighborsOut); addSliceNeighbor(slice, i, j - 1, k, searchForValue, neighborsOut); break; } break; case SEARCH_AXIS_Y: switch (sliceConnectivity) { case SLICE_NEIGHBOR_CONNECTIVITY_8: // // Add neighbors that share a corner // addSliceNeighbor(slice, i + 1, j, k + 1, searchForValue, neighborsOut); addSliceNeighbor(slice, i - 1, j, k + 1, searchForValue, neighborsOut); addSliceNeighbor(slice, i - 1, j, k - 1, searchForValue, neighborsOut); addSliceNeighbor(slice, i + 1, j, k - 1, searchForValue, neighborsOut); // // Intentionally fall through to get the inclusive 4-connected neighbors // case SLICE_NEIGHBOR_CONNECTIVITY_4: // // Add neighbors that share an edge // addSliceNeighbor(slice, i + 1, j, k, searchForValue, neighborsOut); addSliceNeighbor(slice, i - 1, j, k, searchForValue, neighborsOut); addSliceNeighbor(slice, i, j, k + 1, searchForValue, neighborsOut); addSliceNeighbor(slice, i, j, k - 1, searchForValue, neighborsOut); break; } break; case SEARCH_AXIS_Z: switch (sliceConnectivity) { case SLICE_NEIGHBOR_CONNECTIVITY_8: // // Add neighbors that share a corner // addSliceNeighbor(slice, i + 1, j + 1, k, searchForValue, neighborsOut); addSliceNeighbor(slice, i - 1, j + 1, k, searchForValue, neighborsOut); addSliceNeighbor(slice, i - 1, j - 1, k, searchForValue, neighborsOut); addSliceNeighbor(slice, i + 1, j - 1, k, searchForValue, neighborsOut); // // Intentionally fall through to get the inclusive 4-connected neighbors // case SLICE_NEIGHBOR_CONNECTIVITY_4: // // Add neighbors that share an edge // addSliceNeighbor(slice, i + 1, j, k, searchForValue, neighborsOut); addSliceNeighbor(slice, i - 1, j, k, searchForValue, neighborsOut); addSliceNeighbor(slice, i, j + 1, k, searchForValue, neighborsOut); addSliceNeighbor(slice, i, j - 1, k, searchForValue, neighborsOut); break; } break; } } void BrainModelVolumeTopologyGraph::addSliceNeighbor(const VolumeSlice& slice, const int ii, const int jj, const int kk, const int searchForValue, std::vector& neighborsOut) const { int i = ii, j = jj, k = kk; ijkForSlice(i, j, k); if (slice.getIJValid(i, j)) { if (slice.getVoxel(i, j) == searchForValue) { neighborsOut.push_back(VoxelIJK(ii, jj, kk)); } } } /** * print vertices in the graph. */ void BrainModelVolumeTopologyGraph::printGraphVertices() const { const int numGraphVertices = getNumberOfGraphVertices(); std::cout << "There are " << numGraphVertices << " vertices in the graph." << std::endl; for (int i = 0; i < numGraphVertices; i++) { const GraphVertex* vertex = getGraphVertex(i); std::cout << "Vertex-Index/Slice/Num-Voxels: " << i << ", " << vertex->getSliceNumber() << ", " << vertex->getNumberOfVoxels() << std::endl; std::cout << " Connections: "; const int numConnections = vertex->getNumberOfConnectedGraphEdges(); for (int m = 0; m < numConnections; m++) { const GraphEdge* edge = vertex->getConnectedGraphEdge(m); std::cout << edge->getVertexNumber() << "(" << edge->getStrength() << ") "; } std::cout << std::endl; } } /** * print cycles in the graph. */ void BrainModelVolumeTopologyGraph::printGraphCycles() const { const int numGraphCycles = getNumberOfGraphCycles(); std::cout << "There are " << numGraphCycles << " cycles in the graph." << std::endl; for (int i = 0; i < numGraphCycles; i++) { const GraphCycle* cycle = getGraphCycle(i); std::cout << "Cycle " << i << " Slices: "; const int numGraphVerticesInCycle = cycle->getNumberOfGraphVerticesInCycle(); bool needNewlineFlag = false; for (int j = 0; j < numGraphVerticesInCycle; j++) { const int graphVertexIndex = cycle->getGraphVertexIndex(j); const GraphVertex* vertex = getGraphVertex(graphVertexIndex); std::cout << vertex->getSliceNumber() << "(" << vertex->getNumberOfVoxels() << ") "; if ((j > 0) && ((j % 7) == 0)) { std::cout << std::endl; if (j < (numGraphVerticesInCycle - 1)) { std::cout << " "; } needNewlineFlag = false; } else { needNewlineFlag = true; } } if (needNewlineFlag) { std::cout << std::endl; } const std::vector handleVertices = cycle->getHandleVertices(); const int numInHandle = static_cast(handleVertices.size()); if (numInHandle > 0) { std::cout << " Handle: "; for (int m = 0; m < numInHandle; m++) { const int graphVertexIndex = handleVertices[m]; const GraphVertex* vertex = getGraphVertex(graphVertexIndex); std::cout << vertex->getSliceNumber() << "(" << vertex->getNumberOfVoxels() << ") "; } std::cout << std::endl; } } } /** * get cycle with smallest handle (handle that contains fewest voxels). */ void BrainModelVolumeTopologyGraph::getGraphCycleWithSmallestHandle(int &cycleIndexOut, std::vector& vertexIndicesOut, int &numberOfVoxelsOut) const { cycleIndexOut = -1; vertexIndicesOut.clear(); numberOfVoxelsOut = std::numeric_limits::max(); const int numGraphCycles = getNumberOfGraphCycles(); for (int i = 0; i < numGraphCycles; i++) { const GraphCycle* cycle = getGraphCycle(i); if (cycle->getHandleSizeInVoxels() < numberOfVoxelsOut) { numberOfVoxelsOut = cycle->getHandleSizeInVoxels(); cycleIndexOut = i; vertexIndicesOut = cycle->getHandleVertices(); } } } /** * get cycle with smallest vertex (contains fewest voxels). */ void BrainModelVolumeTopologyGraph::getGraphCycleWithSmallestVertex(int &cycleIndexOut, int &vertexIndexOut, int &numberofVoxelsOut) const { cycleIndexOut = -1; vertexIndexOut = -1; numberofVoxelsOut = std::numeric_limits::max(); const int numGraphCycles = getNumberOfGraphCycles(); for (int i = 0; i < numGraphCycles; i++) { const GraphCycle* cycle = getGraphCycle(i); const int numGraphVerticesInCycle = cycle->getNumberOfGraphVerticesInCycle(); for (int j = 0; j < numGraphVerticesInCycle; j++) { const int graphVertexIndex = cycle->getGraphVertexIndex(j); const GraphVertex* vertex = getGraphVertex(graphVertexIndex); const int numVoxels = vertex->getNumberOfVoxels(); if (numVoxels < numberofVoxelsOut) { numberofVoxelsOut = numVoxels; cycleIndexOut = i; vertexIndexOut = graphVertexIndex; } } } } /** * create an paint volume file containing the handles. */ void BrainModelVolumeTopologyGraph::createHandlesPaintVolumeFile(VolumeFile& handlesPaintVolumeFile) { int dim[3]; segmentationVolumeFile->getDimensions(dim); float space[3], org[3]; segmentationVolumeFile->getSpacing(space); segmentationVolumeFile->getOrigin(org); VolumeFile::ORIENTATION orient[3]; segmentationVolumeFile->getOrientation(orient); handlesPaintVolumeFile.initialize(VolumeFile::VOXEL_DATA_TYPE_FLOAT, dim, orient, org, space, true, true); handlesPaintVolumeFile.setVolumeType(VolumeFile::VOLUME_TYPE_PAINT); handlesPaintVolumeFile.addRegionName("???"); const int numGraphCycles = getNumberOfGraphCycles(); for (int i = 0; i < numGraphCycles; i++) { const GraphCycle* cycle = getGraphCycle(i); const std::vector handlesVertices = cycle->getHandleVertices(); const int numGraphVerticesInHandle = static_cast(handlesVertices.size()); QString regionName("Handle_" + QString::number(i)); switch (searchAxis) { case SEARCH_AXIS_X: regionName += "_X_"; break; case SEARCH_AXIS_Y: regionName += "_Y_"; break; case SEARCH_AXIS_Z: regionName += "_Z_"; break; } int minSliceNumber = std::numeric_limits::max(); int maxSliceNumber = std::numeric_limits::min(); for (int j = 0; j < numGraphVerticesInHandle; j++) { const int graphVertexIndex = handlesVertices[j]; const GraphVertex* vertex = getGraphVertex(graphVertexIndex); minSliceNumber = std::min(minSliceNumber, vertex->getSliceNumber()); maxSliceNumber = std::max(maxSliceNumber, vertex->getSliceNumber()); } regionName += (QString::number(minSliceNumber) + "_" + QString::number(maxSliceNumber)); const int regionIndex = handlesPaintVolumeFile.addRegionName(regionName); // // Set paint voxels corresponding to handle // for (int j = 0; j < numGraphVerticesInHandle; j++) { const int graphVertexIndex = handlesVertices[j]; const GraphVertex* vertex = getGraphVertex(graphVertexIndex); const int numVoxels = vertex->getNumberOfVoxels(); for (int n = 0; n < numVoxels; n++) { const VoxelIJK* v = vertex->getVoxel(n); handlesPaintVolumeFile.setVoxel(*v, 0, regionIndex); } } } } /** * Get voxel connects to voxels in another vertex. */ bool BrainModelVolumeTopologyGraph::getVoxelConnectedToGraphVertex(const VoxelIJK& v1, const int otherGraphVertexIndex) const { const GraphVertex* vertex = getGraphVertex(otherGraphVertexIndex); const int numVoxels = vertex->getNumberOfVoxels(); for (int n = 0; n < numVoxels; n++) { const VoxelIJK* v2 = vertex->getVoxel(n); // // Voxels indices cannot differ by more than one if immediate neighbor // const int di = std::abs(v1.getI() - v2->getI()); if (di > 1) continue; const int dj = std::abs(v1.getJ() - v2->getJ()); if (dj > 1) continue; const int dk = std::abs(v1.getK() - v2->getK()); if (dk > 1) continue; const int dSum = di + dj + dk; switch (volumeConnectivity) { case VOXEL_NEIGHBOR_CONNECTIVITY_6: if (dSum == 1) return true; break; case VOXEL_NEIGHBOR_CONNECTIVITY_18: if (dSum <= 2) return true; break; case VOXEL_NEIGHBOR_CONNECTIVITY_26: if (dSum <= 3) return true; break; } } return false; } //========================================================================== //========================================================================== //========================================================================== // // Volume Slice Class // /** * constructor. */ BrainModelVolumeTopologyGraph::VolumeSlice::VolumeSlice(const int dimIin, const int dimJin) { dimI = dimIin; dimJ = dimJin; const int num = dimI * dimJ; voxels = new int[num]; } /** * destructor. */ BrainModelVolumeTopologyGraph::VolumeSlice::~VolumeSlice() { if (voxels != NULL) { delete[] voxels; voxels = NULL; } } /** * get indices valid. */ bool BrainModelVolumeTopologyGraph::VolumeSlice::getIJValid(const int i, const int j) const { if ((i >= 0) && (i < dimI) && (j >= 0) && (j < dimJ)) { return true; } return false; } /** * set a voxel in the slice. */ void BrainModelVolumeTopologyGraph::VolumeSlice::setVoxel(const SEARCH_AXIS searchAxis, const VoxelIJK& v, const int value) { const int indx = getIndex(searchAxis, v); voxels[indx] = value; } /** * get a voxel in the slice. */ float BrainModelVolumeTopologyGraph::VolumeSlice::getVoxel(const SEARCH_AXIS searchAxis, const VoxelIJK& v) const { const int indx = getIndex(searchAxis, v); return voxels[indx]; } /** * set all voxels in the slice. */ void BrainModelVolumeTopologyGraph::VolumeSlice::setAllVoxels(const int value) { const int num = dimI * dimJ; for (int i = 0; i < num; i++) { voxels[i] = value; } } /** * set a voxel in the slice. */ void BrainModelVolumeTopologyGraph::VolumeSlice::setVoxel(const int horizIndex, const int vertIndex, const int value) { const int indx = getIndex(horizIndex, vertIndex); voxels[indx] = value; } /** * get a voxel in the slice. */ float BrainModelVolumeTopologyGraph::VolumeSlice::getVoxel(const int horizIndex, const int vertIndex) const { const int indx = getIndex(horizIndex, vertIndex); return voxels[indx]; } /** * get the index. */ int BrainModelVolumeTopologyGraph::VolumeSlice::getIndex(const int horizIndex, const int vertIndex) const { const int indx = (dimI * vertIndex) + horizIndex; /* if ((indx < 0) || (indx >= (dimI * dimJ))) { std::cout << "VolumeSlice bad index: " << horizIndex << ", " << vertIndex << std::endl; } */ return indx; } /** * get the index. */ int BrainModelVolumeTopologyGraph::VolumeSlice::getIndex(const SEARCH_AXIS searchAxis, const VoxelIJK& v) const { int i = 0; int j = 0; switch (searchAxis) { case SEARCH_AXIS_X: i = v.getJ(); j = v.getK(); break; case SEARCH_AXIS_Y: i = v.getI(); j = v.getK(); break; case SEARCH_AXIS_Z: i = v.getI(); j = v.getJ(); break; } const int indx = (dimI * j) + i; /* if ((indx < 0) || (indx >= (dimI * dimJ))) { std::cout << "VolumeSlice bad index: " << i << ", " << j << std::endl; } */ return indx; } //========================================================================== //========================================================================== //========================================================================== // // Cycle class // /** * constructor. */ BrainModelVolumeTopologyGraph::GraphCycle::GraphCycle() { } /** * destructor. */ BrainModelVolumeTopologyGraph::GraphCycle::~GraphCycle() { } /** * clear the cycle. */ void BrainModelVolumeTopologyGraph::GraphCycle::clear() { cycle.clear(); cycleSorted.clear(); } /** * set the cycle. */ void BrainModelVolumeTopologyGraph::GraphCycle::set(const std::vector& cycleVerticesIn, const std::vector& cycleSlicesIn) { if (cycleVerticesIn.size() != cycleSlicesIn.size()) { std::cout << "PROGRAM ERROR: size vertices != size slices in " "BrainModelVolumeTopologyGraph::GraphCycle::set()" << std::endl; } cycle.clear(); cycleSorted.clear(); // // Sort so cycle starts with smallest SLICE number // int minSliceNumber = std::numeric_limits::max(); int minSliceIndex = -1; const int num = static_cast(cycleSlicesIn.size()); for (int i = 0; i < num; i++) { if (cycleSlicesIn[i] < minSliceNumber) { minSliceNumber = cycleSlicesIn[i]; minSliceIndex = i; } } for (int i = minSliceIndex; i < num; i++) { cycle.push_back(cycleVerticesIn[i]); } for (int i = 0; i < minSliceIndex; i++) { cycle.push_back(cycleVerticesIn[i]); } cycleSorted = cycleVerticesIn; std::sort(cycleSorted.begin(), cycleSorted.end()); } /** * set the vertices that form the handle. */ void BrainModelVolumeTopologyGraph::GraphCycle::setHandleVertices(const std::vector& handleVerticesIn, const int numVoxelsInHandleIn) { handleVertices = handleVerticesIn; numVoxelsInHandle = numVoxelsInHandleIn; } /** * equality operator. */ bool BrainModelVolumeTopologyGraph::GraphCycle::operator==(const GraphCycle& c) const { return std::equal(cycleSorted.begin(), cycleSorted.end(), c.cycleSorted.begin()); } /** * comparison operator (based upon number of elements. */ bool BrainModelVolumeTopologyGraph::GraphCycle::operator<(const GraphCycle& c) const { if (cycleSorted.size() == c.cycleSorted.size()) { return std::lexicographical_compare(cycleSorted.begin(), cycleSorted.end(), c.cycleSorted.begin(), c.cycleSorted.end()); } return (cycleSorted.size() < c.cycleSorted.size()); } /** * get the cycle. */ std::vector BrainModelVolumeTopologyGraph::GraphCycle::getCycle() const { return cycle; } //========================================================================== //========================================================================== //========================================================================== // // // caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeTopologicalError.h0000664000175000017500000000500511572067322026471 0ustar michaelmichael #ifndef __BRAIN_MODEL_VOLUME_TOPOLOGICAL_ERROR_H__ #define __BRAIN_MODEL_VOLUME_TOPOLOGICAL_ERROR_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "VolumeFile.h" /// stores information about a topological error (handle) class BrainModelVolumeTopologicalError { public: /// Constructor BrainModelVolumeTopologicalError(const int voxelIJKIn[3], const float voxelXYZIn[3], const int slicesIn[2], const std::vector& handleVoxelsIn, const int numVoxelsIn, const VolumeFile::VOLUME_AXIS axisIn); /// Constructor BrainModelVolumeTopologicalError(const int voxelIJKIn[3], const int numVoxelsIn); /// get the handle info void getInfo(int voxelIJKOut[3], float voxelXYZOut[3], int slicesOut[2], int& numVoxelsOut, VolumeFile::VOLUME_AXIS& axisOut) const; /// get the voxels that make up the handle (one dimensional indices) void getHandleVoxels(std::vector& handleVoxelsOut) const; protected: /// a voxel in the handle int voxelIJK[3]; /// stereotaxic coordinate of voxel in handle float voxelXYZ[3]; /// starting and ending slice of the handle int slices[2]; /// number of voxels in the handle int numVoxels; /// axis along which voxel was found VolumeFile::VOLUME_AXIS axis; /// indices to voxels that make up the handle std::vector handleVoxels; }; #endif // __BRAIN_MODEL_VOLUME_TOPOLOGICAL_ERROR_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeTopologicalError.cxx0000664000175000017500000000622011572067322027044 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelVolumeTopologicalError.h" /** * Constructor. */ BrainModelVolumeTopologicalError::BrainModelVolumeTopologicalError(const int voxelIJKIn[3], const float voxelXYZIn[3], const int slicesIn[2], const std::vector& handleVoxelsIn, const int numVoxelsIn, const VolumeFile::VOLUME_AXIS axisIn) { voxelIJK[0] = voxelIJKIn[0]; voxelIJK[1] = voxelIJKIn[1]; voxelIJK[2] = voxelIJKIn[2]; voxelXYZ[0] = voxelXYZIn[0]; voxelXYZ[1] = voxelXYZIn[1]; voxelXYZ[2] = voxelXYZIn[2]; slices[0] = slicesIn[0]; slices[1] = slicesIn[1]; handleVoxels = handleVoxelsIn; numVoxels = numVoxelsIn; axis = axisIn; } /** * Constructor. */ BrainModelVolumeTopologicalError::BrainModelVolumeTopologicalError(const int voxelIJKIn[3], const int numVoxelsIn) { voxelIJK[0] = voxelIJKIn[0]; voxelIJK[1] = voxelIJKIn[1]; voxelIJK[2] = voxelIJKIn[2]; slices[0] = -1; slices[1] = -1; handleVoxels.clear(); numVoxels = numVoxelsIn; axis = VolumeFile::VOLUME_AXIS_UNKNOWN; } /** * get the handle info. */ void BrainModelVolumeTopologicalError::getInfo(int voxelIJKOut[3], float voxelXYZOut[3], int slicesOut[2], int& numVoxelsOut, VolumeFile::VOLUME_AXIS& axisOut) const { voxelIJKOut[0] = voxelIJK[0]; voxelIJKOut[1] = voxelIJK[1]; voxelIJKOut[2] = voxelIJK[2]; voxelXYZOut[0] = voxelXYZ[0]; voxelXYZOut[1] = voxelXYZ[1]; voxelXYZOut[2] = voxelXYZ[2]; slicesOut[0] = slices[0]; slicesOut[1] = slices[1]; numVoxelsOut = numVoxels; axisOut = axis; } /** * get the voxels that make up the handle (one dimensional indices). */ void BrainModelVolumeTopologicalError::getHandleVoxels(std::vector& handleVoxelsOut) const { handleVoxelsOut = handleVoxels; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeToVtkSurfaceMapper.h0000664000175000017500000000402511572067322026731 0ustar michaelmichael #ifndef __BRAIN_MODEL_VOLUME_TO_VTK_SURFACE_MAPPER_H__ #define __BRAIN_MODEL_VOLUME_TO_VTK_SURFACE_MAPPER_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelAlgorithm.h" class PaletteFile; class VolumeFile; class VtkModelFile; /// class for mapping a volume to a VTK surface class BrainModelVolumeToVtkSurfaceMapper : public BrainModelAlgorithm { public: // constructor BrainModelVolumeToVtkSurfaceMapper(BrainSet* bs, VtkModelFile* vtkModelFileIn, const VolumeFile* volumeFileIn, const PaletteFile* paletteFileIn, const int paletteNumberIn); // destructor ~BrainModelVolumeToVtkSurfaceMapper(); // execute the algorithm void execute() throw (BrainModelAlgorithmException); protected: /// the VTK model file VtkModelFile* vtkModelFile; /// the volume that is to be mapped const VolumeFile* volumeFile; /// the palette file const PaletteFile* paletteFile; /// palette number const int paletteNumber; }; #endif // __BRAIN_MODEL_VOLUME_TO_VTK_SURFACE_MAPPER_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeToVtkSurfaceMapper.cxx0000664000175000017500000000730411572067322027307 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelVolumeToVtkSurfaceMapper.h" #include "PaletteFile.h" #include "VolumeFile.h" #include "VtkModelFile.h" /** * constructor. */ BrainModelVolumeToVtkSurfaceMapper::BrainModelVolumeToVtkSurfaceMapper( BrainSet* bs, VtkModelFile* vtkModelFileIn, const VolumeFile* volumeFileIn, const PaletteFile* paletteFileIn, const int paletteNumberIn) : BrainModelAlgorithm(bs), vtkModelFile(vtkModelFileIn), volumeFile(volumeFileIn), paletteFile(paletteFileIn), paletteNumber(paletteNumberIn) { } /** * destructor. */ BrainModelVolumeToVtkSurfaceMapper::~BrainModelVolumeToVtkSurfaceMapper() { } /** * execute the algorithm. */ void BrainModelVolumeToVtkSurfaceMapper::execute() throw (BrainModelAlgorithmException) { // // Check inputs // if (vtkModelFile == NULL) { throw BrainModelAlgorithmException("VTK model file is invalid."); } if (volumeFile == NULL) { throw BrainModelAlgorithmException("Volume file is invalid."); } if (paletteFile == NULL) { throw BrainModelAlgorithmException("Palette file is invalid."); } if ((paletteNumber < 0) || (paletteNumber >= paletteFile->getNumberOfPalettes())) { throw BrainModelAlgorithmException("Palette number is invalid."); } // // Get the palette // const Palette* palette = paletteFile->getPalette(paletteNumber); // // Get volume minimum and maximum values // float minValue, maxValue; VolumeFile mappingVolume(*volumeFile); mappingVolume.getMinMaxVoxelValues(minValue, maxValue); // // Loop through the coordinates of the model // const CoordinateFile* cf = vtkModelFile->getCoordinateFile(); const int numCoords = cf->getNumberOfCoordinates(); for (int i = 0; i < numCoords; i++) { const float* xyz = cf->getCoordinate(i); int ijk[3]; if (mappingVolume.convertCoordinatesToVoxelIJK(xyz, ijk)) { // // Normalize the data value // const float voxelValue = volumeFile->getVoxel(ijk, 0); float normalized = 0.0; if (voxelValue > 0.0) { normalized = voxelValue / maxValue; } else if (voxelValue < 0.0) { normalized = -std::fabs(voxelValue / minValue); } // // Get the coloring // const bool interpolateColor = false; bool isNoneColor = false; unsigned char colors[4]; palette->getColor(normalized, interpolateColor, isNoneColor, colors); colors[3] = 255; // // Set the point's color // vtkModelFile->setPointColor(i, colors); } } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeToSurfaceMapperPALS.h0000664000175000017500000000605111572067322026725 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelAlgorithm.h" #include "BrainModelVolumeToSurfaceMapperAlgorithmParameters.h" #include "Structure.h" class GiftiNodeDataFile; class VolumeFile; /// class for mapping a volume to the PALS atlas class BrainModelVolumeToSurfaceMapperPALS : public BrainModelAlgorithm { public: // constructor BrainModelVolumeToSurfaceMapperPALS(BrainSet* bsIn, VolumeFile* volumeFileIn, const QString& stereotaxicSpaceNameIn, const Structure& structureIn, const BrainModelVolumeToSurfaceMapperAlgorithmParameters& mappingParameters, GiftiNodeDataFile* dataFileIn); // destructor ~BrainModelVolumeToSurfaceMapperPALS(); // get the names of the supported stereotaxic spaces static void getSupportedStereotaxicSpaceName(std::vector& namesOut); // execute the algorithm void execute() throw (BrainModelAlgorithmException); protected: // map to average fiducial surface void mapAverageFiducial(const QString& topologyFileName, const QString& avgFidCoordFileName, const QString& structureName, GiftiNodeDataFile* nodeDataFile) throw (BrainModelAlgorithmException); // map all indiv cases void mapIndividualCases(const QString& topologyFileName, const std::vector& indivCoordFileNames, const QString& structureAbbreviation, GiftiNodeDataFile* nodeDataFile) throw (BrainModelAlgorithmException); /// the volume that is to be mapped VolumeFile* volumeFile; /// the structure that is being mapped Structure structure; /// the stereotaxic space that is being mapped QString stereotaxicSpaceName; /// the mapping algorithm parameters BrainModelVolumeToSurfaceMapperAlgorithmParameters mappingParameters; /// the output data file GiftiNodeDataFile* dataFile; }; caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeToSurfaceMapperPALS.cxx0000664000175000017500000004637411572067322027314 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainModelSurface.h" #include "BrainModelVolumeToSurfaceMapper.h" #include "BrainModelVolumeToSurfaceMapperPALS.h" #include "BrainSet.h" #include "FileUtilities.h" #include "MapFmriAtlasSpecFileInfo.h" #include "MetricFile.h" #include "PaintFile.h" #include "VolumeFile.h" /** * constructor. */ BrainModelVolumeToSurfaceMapperPALS::BrainModelVolumeToSurfaceMapperPALS(BrainSet* bsIn, VolumeFile* volumeFileIn, const QString& stereotaxicSpaceNameIn, const Structure& structureIn, const BrainModelVolumeToSurfaceMapperAlgorithmParameters& mappingParametersIn, GiftiNodeDataFile* dataFileIn) : BrainModelAlgorithm(bsIn) { volumeFile = volumeFileIn; stereotaxicSpaceName = stereotaxicSpaceNameIn; structure = structureIn; mappingParameters = mappingParametersIn; dataFile = dataFileIn; } /** * destructor. */ BrainModelVolumeToSurfaceMapperPALS::~BrainModelVolumeToSurfaceMapperPALS() { } /** * execute the algorithm. */ void BrainModelVolumeToSurfaceMapperPALS::execute() throw (BrainModelAlgorithmException) { if (volumeFile == NULL) { throw BrainModelAlgorithmException("Volume is invalid."); } if (dataFile == NULL) { throw BrainModelAlgorithmException("Data file is invalid."); } if (stereotaxicSpaceName.isEmpty()) { throw BrainModelAlgorithmException("Stereotaxic space name is empty."); } QString structureName; QString structureAbbreviation; switch (structure.getType()) { case Structure::STRUCTURE_TYPE_CORTEX_LEFT: structureName = "LEFT"; structureAbbreviation = "L"; break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT: structureName = "RIGHT"; structureAbbreviation = "R"; break; case Structure::STRUCTURE_TYPE_CORTEX_BOTH: case Structure::STRUCTURE_TYPE_CEREBELLUM: case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_LEFT: case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_RIGHT: case Structure::STRUCTURE_TYPE_CORTEX_LEFT_OR_CEREBELLUM: case Structure::STRUCTURE_TYPE_CORTEX_RIGHT_OR_CEREBELLUM: case Structure::STRUCTURE_TYPE_CEREBRUM_CEREBELLUM: case Structure::STRUCTURE_TYPE_SUBCORTICAL: case Structure::STRUCTURE_TYPE_ALL: case Structure::STRUCTURE_TYPE_INVALID: throw BrainModelAlgorithmException("Structure must be left or right."); break; } MetricFile* outputMetricFile = NULL; PaintFile* outputPaintFile = NULL; switch (mappingParameters.getAlgorithm()) { case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_METRIC_AVERAGE_NODES: case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_METRIC_AVERAGE_VOXEL: case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_METRIC_ENCLOSING_VOXEL: case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_METRIC_GAUSSIAN: case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_METRIC_INTERPOLATED_VOXEL: case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_METRIC_MAXIMUM_VOXEL: case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_METRIC_MCW_BRAINFISH: case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_METRIC_STRONGEST_VOXEL: outputMetricFile = dynamic_cast(dataFile); if (outputMetricFile == NULL) { throw BrainModelAlgorithmException("A metric mapping algorithm has been " "selected but the data file is not a " "metric file."); } break; case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_PAINT_ENCLOSING_VOXEL: outputPaintFile = dynamic_cast(dataFile); if (outputPaintFile == NULL) { throw BrainModelAlgorithmException("A paint mapping algorithm has been " "selected but the data file is not a " "paint file."); } break; } // // Get the atlases // std::vector atlases; MapFmriAtlasSpecFileInfo::getAtlases(brainSet, atlases); // // Find the correct atlas // MapFmriAtlasSpecFileInfo* mappingAtlas = NULL; for (unsigned int i = 0; i < atlases.size(); i++) { if (atlases[i].getDataValid()) { if (atlases[i].getSpace() == stereotaxicSpaceName) { if (atlases[i].getStructure().toUpper() == structureName) { mappingAtlas = &atlases[i]; } } } } if (mappingAtlas == NULL) { throw BrainModelAlgorithmException("Unable to find an atlas with stereotaxic " "space = \"" + stereotaxicSpaceName + "\" and structure = \"" + structureName + "\""); } // // Get the data file names from the atlas // const QString mappingFilesPath = mappingAtlas->getSpecFilePath(); const QString topologyFileName = mappingAtlas->getTopologyFile(); const QString averageCoordFileName = mappingAtlas->getAverageCoordinateFile(); const std::vector indivCoordFileNames = mappingAtlas->getCoordinateFiles(); const int numIndivCoordFiles = static_cast(indivCoordFileNames.size()); // // Save the current directory // const QString savedDirectory = QDir::currentPath(); // // Change directory to the directory containing the mapping files // QDir::setCurrent(mappingFilesPath); try { // // Maping to a metric file // if (outputMetricFile != NULL) { // // Map to average fiducial // if (mappingParameters.getPalsMetricAverageFiducialMappingEnabled()) { mapAverageFiducial(topologyFileName, averageCoordFileName, structureName, outputMetricFile); } // // Do metric multi-fiducial cases need to be mapped ? // if (mappingParameters.getPalsMetricMultiFiducialMappingEnabled() || mappingParameters.getPalsMetricMinimumEnabled() || mappingParameters.getPalsMetricMaximumEnabled() || mappingParameters.getPalsMetricStandardDeviationEnabled() || mappingParameters.getPalsMetricStandardErrorEnabled() || mappingParameters.getPalsMetricAllCasesEnabled()) { // // Map to each indiv coordinate file // MetricFile multiFidMetricFile; mapIndividualCases(topologyFileName, indivCoordFileNames, structureAbbreviation, &multiFidMetricFile); // // Set column names for statistics and MFM // QString averageColumnName; if (mappingParameters.getPalsMetricMultiFiducialMappingEnabled()) { averageColumnName = "MFM " + structureName + " - " + FileUtilities::basename(volumeFile->getFileName()); } QString standardDeviationColumnName; if (mappingParameters.getPalsMetricStandardDeviationEnabled()) { standardDeviationColumnName = "STANDARD DEVIATION (MFM) " + structureName + " - " + FileUtilities::basename(volumeFile->getFileName()); } QString standardErrorColumnName; if (mappingParameters.getPalsMetricStandardErrorEnabled()) { standardErrorColumnName = "STANDARD ERROR (MFM) " + structureName + " - " + FileUtilities::basename(volumeFile->getFileName()); } QString minimumAbsColumnName; if (mappingParameters.getPalsMetricMinimumEnabled()) { minimumAbsColumnName = "MINIMUM (MFM) " + structureName + " - " + FileUtilities::basename(volumeFile->getFileName()); } QString maximumAbsColumnName; if (mappingParameters.getPalsMetricMaximumEnabled()) { maximumAbsColumnName = "MAXIMUM (MFM) " + structureName + " - " + FileUtilities::basename(volumeFile->getFileName()); } // // Do any stats need to be computed // if ((averageColumnName.isEmpty() == false) || (standardDeviationColumnName.isEmpty() == false) || (standardErrorColumnName.isEmpty() == false) || (minimumAbsColumnName.isEmpty() == false) || (maximumAbsColumnName.isEmpty() == false)) { multiFidMetricFile.computeStatistics(averageColumnName, standardDeviationColumnName, standardErrorColumnName, minimumAbsColumnName, maximumAbsColumnName); // // Append stats // std::vector columnDestination(multiFidMetricFile.getNumberOfColumns(), MetricFile::APPEND_COLUMN_DO_NOT_LOAD); for (int i = numIndivCoordFiles; i < multiFidMetricFile.getNumberOfColumns(); i++) { columnDestination[i] = MetricFile::APPEND_COLUMN_NEW; } outputMetricFile->append(multiFidMetricFile, columnDestination, MetricFile::FILE_COMMENT_MODE_LEAVE_AS_IS); } // // Append indiv cases to output file // if (mappingParameters.getPalsMetricAllCasesEnabled()) { std::vector columnDestination(multiFidMetricFile.getNumberOfColumns(), MetricFile::APPEND_COLUMN_DO_NOT_LOAD); for (int i = 0; i < numIndivCoordFiles; i++) { columnDestination[i] = MetricFile::APPEND_COLUMN_NEW; } outputMetricFile->append(multiFidMetricFile, columnDestination, MetricFile::FILE_COMMENT_MODE_LEAVE_AS_IS); } } } if (outputPaintFile != NULL) { // // Map to average fiducial // if (mappingParameters.getPalsPaintAverageFiducialMappingEnabled()) { mapAverageFiducial(topologyFileName, averageCoordFileName, structureName, outputPaintFile); } // // Do paint multi-fiducial cases need to be mapped ? // if (mappingParameters.getPalsPaintMostCommonEnabled() || mappingParameters.getPalsPaintMostCommonExcludeUnidentifiedEnabled() || mappingParameters.getPalsPaintAllCasesEnabled()) { // // Map to each indiv coordinate file // PaintFile multiFidPaintFile; mapIndividualCases(topologyFileName, indivCoordFileNames, structureAbbreviation, &multiFidPaintFile); // // Set column names for statistics and MFM // QString mostCommonColumnName; if (mappingParameters.getPalsPaintMostCommonEnabled()) { mostCommonColumnName = "Most Common (MFM) " + structureName + " - " + FileUtilities::basename(volumeFile->getFileName()); } QString mostCommonNoIDColumnName; if (mappingParameters.getPalsPaintMostCommonExcludeUnidentifiedEnabled()) { mostCommonNoIDColumnName = "Most Common Exclude No ID (MFM) " + structureName + " - " + FileUtilities::basename(volumeFile->getFileName()); } // // Do any most common need to be computed // if ((mostCommonColumnName.isEmpty() == false) || (mostCommonNoIDColumnName.isEmpty() == false)) { multiFidPaintFile.appendMostCommon(mostCommonColumnName, mostCommonNoIDColumnName); // // Append most common // std::vector columnDestination(multiFidPaintFile.getNumberOfColumns(), PaintFile::APPEND_COLUMN_DO_NOT_LOAD); for (int i = numIndivCoordFiles; i < multiFidPaintFile.getNumberOfColumns(); i++) { columnDestination[i] = PaintFile::APPEND_COLUMN_NEW; } outputPaintFile->append(multiFidPaintFile, columnDestination, PaintFile::FILE_COMMENT_MODE_LEAVE_AS_IS); } // // Append indiv cases to output file // if (mappingParameters.getPalsPaintAllCasesEnabled()) { std::vector columnDestination(multiFidPaintFile.getNumberOfColumns(), PaintFile::APPEND_COLUMN_DO_NOT_LOAD); for (int i = 0; i < numIndivCoordFiles; i++) { columnDestination[i] = PaintFile::APPEND_COLUMN_NEW; } outputPaintFile->append(multiFidPaintFile, columnDestination, PaintFile::FILE_COMMENT_MODE_LEAVE_AS_IS); } } } } catch (BrainModelAlgorithmException& e) { // // Restore directory // QDir::setCurrent(savedDirectory); throw (e); } // // Restore directory // QDir::setCurrent(savedDirectory); } /** * map to average fiducial surface. */ void BrainModelVolumeToSurfaceMapperPALS::mapAverageFiducial(const QString& topologyFileName, const QString& avgFidCoordFileName, const QString& structureName, GiftiNodeDataFile* nodeDataFile) throw (BrainModelAlgorithmException) { // // Load the surface // BrainSet bs(topologyFileName, avgFidCoordFileName); BrainModelSurface* bms = bs.getBrainModelSurface(0); if (bms == NULL) { throw BrainModelAlgorithmException("Error loading mapping coord file " + avgFidCoordFileName); } // // Map the surface // QString columnName("AFM " + structureName + " - " + FileUtilities::basename(volumeFile->getFileName())); BrainModelVolumeToSurfaceMapper mapper(&bs, bms, volumeFile, nodeDataFile, mappingParameters, -1, // new column columnName); mapper.execute(); } /** * map all indiv cases. */ void BrainModelVolumeToSurfaceMapperPALS::mapIndividualCases(const QString& topologyFileName, const std::vector& indivCoordFileNames, const QString& structureAbbreviation, GiftiNodeDataFile* nodeDataFile) throw (BrainModelAlgorithmException) { const int numIndivCoordFiles = static_cast(indivCoordFileNames.size()); // // Map to each indiv coordinate file // for (int i = 0; i < numIndivCoordFiles; i++) { // // Load the surface // BrainSet bs(topologyFileName, indivCoordFileNames[i]); BrainModelSurface* bms = bs.getBrainModelSurface(0); if (bms == NULL) { throw BrainModelAlgorithmException("Error loading mapping coord file " + indivCoordFileNames[i]); } // // Map the surface // QString columnName("Map to Case" + QString::number(i + 1).rightJustified(2, '0') + "." + structureAbbreviation + " - " + FileUtilities::basename(volumeFile->getFileName())); BrainModelVolumeToSurfaceMapper mapper(&bs, bms, volumeFile, nodeDataFile, mappingParameters, -1, // new column columnName); mapper.execute(); } } /** * get the names of the supported stereotaxic spaces. */ void BrainModelVolumeToSurfaceMapperPALS::getSupportedStereotaxicSpaceName(std::vector& namesOut) { namesOut.clear(); // // read the atlases // BrainSet bsTemp; std::vector palsAtlases; MapFmriAtlasSpecFileInfo::getAtlases(&bsTemp, palsAtlases); std::set uniqueSpaceNamesSorted; for (unsigned int i = 0; i < palsAtlases.size(); i++) { uniqueSpaceNamesSorted.insert(palsAtlases[i].getSpace()); } namesOut.insert(namesOut.end(), uniqueSpaceNamesSorted.begin(), uniqueSpaceNamesSorted.end()); } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeToSurfaceMapperAlgorithmParameters.h0000664000175000017500000003106111572067322032137 0ustar michaelmichael #ifndef __BRAIN_MODEL_VOLUME_TO_SURFACE_MAPPER_ALGORITHM_PARAMETERS_H__ #define __BRAIN_MODEL_VOLUME_TO_SURFACE_MAPPER_ALGORITHM_PARAMETERS_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include class PreferencesFile; /// class for volume to surface algorithm parameters class BrainModelVolumeToSurfaceMapperAlgorithmParameters { public: /// mapping algorithm enum ALGORITHM { /// metric average nodes mapping algorithm ALGORITHM_METRIC_AVERAGE_NODES, /// metric average voxel mapping algorithm ALGORITHM_METRIC_AVERAGE_VOXEL, /// metric enclosing voxel mapping algorithm ALGORITHM_METRIC_ENCLOSING_VOXEL, /// metric gaussian mapping algorithm ALGORITHM_METRIC_GAUSSIAN, /// metric interpolated voxel mapping algorithm ALGORITHM_METRIC_INTERPOLATED_VOXEL, /// metric maximum voxel mapping algorithm ALGORITHM_METRIC_MAXIMUM_VOXEL, /// metric MCW brainfish mapping algorithm ALGORITHM_METRIC_MCW_BRAINFISH, /// metric strongest voxel mapping algorithm ALGORITHM_METRIC_STRONGEST_VOXEL, /// paint enclosing voxel mapping algorithm ALGORITHM_PAINT_ENCLOSING_VOXEL }; // constructor BrainModelVolumeToSurfaceMapperAlgorithmParameters(); // destructor ~BrainModelVolumeToSurfaceMapperAlgorithmParameters(); // transfer parameters from preferences file void transferParametersFromPreferencesFile(const PreferencesFile* pf); // transfer parameters to preferences file void transferParametersToPreferncesFile(PreferencesFile* pf, const bool writePreferencesFileFlag); // get algorithm ALGORITHM getAlgorithm() const; // set algorithm void setAlgorithm(const ALGORITHM alg); // get the algorithm names and values static void getAlgorithmNamesAndValues(std::vector& namesOut, std::vector& valuesOut); // get the algorithm name static QString getAlgorithmName(const ALGORITHM alg); // get algorithm from string static ALGORITHM getAlgorithmFromNameString(const QString& s); // get algorithm parameter as string for comment usage QString getAlgorithmParametersForComment() const; // get the algorithm parameters as a equal and semicolon separated string QString getAlgorithmParametersAsString() const; // set the algorithm parameters from a string void setAlgorithmParametersFromString(const QString& s); // get the average voxel parameters void getAlgorithmMetricAverageVoxelParameters(float& neighborsOut) const; // set the average voxel parameters void setAlgorithmMetricAverageVoxelParameters(const float neighborsIn); // get the maximum voxel parameters void getAlgorithmMetricMaximumVoxelParameters(float& neighborsOut) const; // set the maximum voxel parameters void setAlgorithmMetricMaximumVoxelParameters(const float neighborsIn); // get the strongest voxel parameters void getAlgorithmMetricStrongestVoxelParameters(float& neighborsOut) const; // set the strongest voxel parameters void setAlgorithmMetricStrongestVoxelParameters(const float neighborsIn); // set gaussian algorithm parameters void getAlgorithmMetricGaussianParameters(float& gaussianNeighborsOut, float& gaussianSigmaNormOut, float& gaussianSigmaTangOut, float& gaussianNormBelowCutoffOut, float& gaussianNormAboveCutoffOut, float& gaussianTangCutoffOut) const; // set gaussian algorithm parameters void setAlgorithmMetricGaussianParameters(const float gaussianNeighborsIn, const float gaussianSigmaNormIn, const float gaussianSigmaTangIn, const float gaussianNormBelowCutoffIn, const float gaussianNormAboveCutoffIn, const float gaussianTangCutoffIn); // get the mcw brainfish algorithm parameters void getAlgorithmMetricMcwBrainFishParameters(float& mcwBrainFishMaxDistanceOut, int& mcwBrainFishSplatFactorOut) const; // set the mcw brainfish algorithm parameters void setAlgorithmMetricMcwBrainFishParameters(const float mcwBrainFishMaxDistanceIn, const int mcwBrainFishSplatFactorIn); /// get PALS metric average fiducial mapping enabled bool getPalsMetricAverageFiducialMappingEnabled() const { return palsMetricAverageFiducialMappingEnabled; } /// get PALS metric multi fiducial mapping enabled bool getPalsMetricMultiFiducialMappingEnabled() const { return palsMetricMultiFiducialMappingEnabled; } /// get PALS metric minimum enabled bool getPalsMetricMinimumEnabled() const { return palsMetricMinimumEnabled; } /// get PALS metric maximum enabled bool getPalsMetricMaximumEnabled() const { return palsMetricMaximumEnabled; } /// get PALS metric standard deviation enabled bool getPalsMetricStandardDeviationEnabled() const { return palsMetricStandardDeviationEnabled; } /// get PALS metric standard error enabled bool getPalsMetricStandardErrorEnabled() const { return palsMetricStandardErrorEnabled; } /// get PALS metric all cases enabled bool getPalsMetricAllCasesEnabled() const { return palsMetricAllCasesEnabled; } /// get PALS paint average fiducial mapping enabled bool getPalsPaintAverageFiducialMappingEnabled() const { return palsPaintAverageFiducialMappingEnabled; } /// get PALS paint most common enabled bool getPalsPaintMostCommonEnabled() const { return palsPaintMostCommonEnabled; } /// get PALS paint most common exlude unidentified enabled bool getPalsPaintMostCommonExcludeUnidentifiedEnabled() const { return palsPaintMostCommonExcludeUnidentifiedEnabled; } /// get PALS paint all cases enabled bool getPalsPaintAllCasesEnabled() const { return palsPaintAllCasesEnabled; } /// PALS metric average fiducial mapping enabled void setPalsMetricAverageFiducialMappingEnabled(const bool b) { palsMetricAverageFiducialMappingEnabled = b; } /// PALS metric multi fiducial mapping enabled void setPalsMetricMultiFiducialMappingEnabled(const bool b) { palsMetricMultiFiducialMappingEnabled = b; } /// PALS metric minimum enabled void setPalsMetricMinimumEnabled(const bool b) { palsMetricMinimumEnabled = b; } /// PALS metric maximum enabled void setPalsMetricMaximumEnabled(const bool b) { palsMetricMaximumEnabled = b; } /// PALS metric standard deviation enabled void setPalsMetricStandardDeviationEnabled(const bool b) { palsMetricStandardDeviationEnabled = b; } /// PALS metric standard error enabled void setPalsMetricStandardErrorEnabled(const bool b) { palsMetricStandardErrorEnabled = b; } /// PALS metric all cases enabled void setPalsMetricAllCasesEnabled(const bool b) { palsMetricAllCasesEnabled = b; } /// PALS paint average fiducial mapping enabled void setPalsPaintAverageFiducialMappingEnabled(const bool b) { palsPaintAverageFiducialMappingEnabled = b; } /// PALS paint most common enabled void setPalsPaintMostCommonEnabled(const bool b) { palsPaintMostCommonEnabled = b; } /// PALS paint most common exlude unidentified enabled void setPalsPaintMostCommonExcludeUnidentifiedEnabled(const bool b) { palsPaintMostCommonExcludeUnidentifiedEnabled = b; } /// PALS paint all cases enabled void setPalsPaintAllCasesEnabled(const bool b) { palsPaintAllCasesEnabled = b; } /// get the metric average nodes algorithm name static QString getAlgorithmMetricAverageNodesName() { return "METRIC_AVERAGE_NODES"; } /// get the metric average voxel algorithm name static QString getAlgorithmMetricAverageVoxelName() { return "METRIC_AVERAGE_VOXEL"; } /// get the metric enclosing voxel algorithm name static QString getAlgorithmMetricEnclosingVoxelName() { return "METRIC_ENCLOSING_VOXEL"; } /// get the metric gaussian algorithm name static QString getAlgorithmMetricGaussianName() { return "METRIC_GAUSSIAN"; } /// get the metric interpolated voxel algorithm name static QString getAlgorithmMetricInterpolatedVoxelName() { return "METRIC_INTERPOLATED_VOXEL"; } /// get the metric maximum voxel algorithm name static QString getAlgorithmMetricMaximumVoxelName() { return "METRIC_MAXIMUM_VOXEL"; } /// get the metric mcw brainfish algorithm name static QString getAlgorithmMetricMcwBrainFishName() { return "METRIC_MCW_BRAIN_FISH"; } /// get the metric strongest voxel algorithm name static QString getAlgorithmMetricStrongestVoxelName() { return "METRIC_STRONGEST_VOXEL"; } /// get the paint enclosing voxel algorithm name static QString getAlgorithmPaintEnclosingVoxel() { return "PAINT_ENCLOSING_VOXEL"; } protected: /// algorithm used for mapping ALGORITHM algorithm; /// average voxel neighbors float averageVoxelNeighbors; /// maximum voxel neighbors float maximumVoxelNeighbors; /// strongest voxel neighbors float strongestVoxelNeighbors; /// gaussian neighbors float gaussianNeighbors; /// gaussian sigma norm float gaussianSigmaNorm; /// gaussian sigma tang float gaussianSigmaTang; /// gaussian norm below cutoff float gaussianNormBelowCutoff; /// gaussian norm above cutoff float gaussianNormAboveCutoff; /// gaussian tang cutoff float gaussianTangCutoff; /// mcw brain fish max distance float mcwBrainFishMaxDistance; /// mcw brain fish splat factor int mcwBrainFishSplatFactor; /// PALS metric average fiducial mapping enabled bool palsMetricAverageFiducialMappingEnabled; /// PALS metric multi fiducial mapping enabled bool palsMetricMultiFiducialMappingEnabled; /// PALS metric minimum enabled bool palsMetricMinimumEnabled; /// PALS metric maximum enabled bool palsMetricMaximumEnabled; /// PALS metric standard deviation enabled bool palsMetricStandardDeviationEnabled; /// PALS metric standard error enabled bool palsMetricStandardErrorEnabled; /// PALS metric all cases enabled bool palsMetricAllCasesEnabled; /// PALS paint average fiducial mapping enabled bool palsPaintAverageFiducialMappingEnabled; /// PALS paint most common enabled bool palsPaintMostCommonEnabled; /// PALS paint most common exlude unidentified enabled bool palsPaintMostCommonExcludeUnidentifiedEnabled; /// PALS paint all cases enabled bool palsPaintAllCasesEnabled; }; #endif // __BRAIN_MODEL_VOLUME_TO_SURFACE_MAPPER_ALGORITHM_PARAMETERS_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeToSurfaceMapperAlgorithmParameters.cxx0000664000175000017500000004323011572067322032513 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelVolumeToSurfaceMapperAlgorithmParameters.h" #include "BrainSet.h" #include "PreferencesFile.h" /** * constructor. */ BrainModelVolumeToSurfaceMapperAlgorithmParameters::BrainModelVolumeToSurfaceMapperAlgorithmParameters() { // // Create a brain set // BrainSet brainSet; // // Default the parameters // algorithm = ALGORITHM_METRIC_ENCLOSING_VOXEL; gaussianNeighbors = 6.0; averageVoxelNeighbors = 0.0; maximumVoxelNeighbors = 3.0; strongestVoxelNeighbors = 3.0; gaussianSigmaNorm = 2.0; gaussianSigmaTang = 1.0; gaussianNormBelowCutoff = 2.0; gaussianNormAboveCutoff = 2.0; gaussianTangCutoff = 3.0; mcwBrainFishMaxDistance = 1.0; mcwBrainFishSplatFactor = 1; palsMetricAverageFiducialMappingEnabled = false; palsMetricMultiFiducialMappingEnabled = false; palsMetricMinimumEnabled = false; palsMetricMaximumEnabled = false; palsMetricStandardDeviationEnabled = false; palsMetricStandardErrorEnabled = false; palsMetricAllCasesEnabled = false; palsPaintAverageFiducialMappingEnabled = false; palsPaintMostCommonEnabled = false; palsPaintMostCommonExcludeUnidentifiedEnabled = false; palsPaintAllCasesEnabled = false; // // Get the preferences file which is read as part of BrainSet constructor // PreferencesFile* pf = brainSet.getPreferencesFile(); transferParametersFromPreferencesFile(pf); } /** * destructor. */ BrainModelVolumeToSurfaceMapperAlgorithmParameters::~BrainModelVolumeToSurfaceMapperAlgorithmParameters() { } /** * transfer parameters from preferences file. */ void BrainModelVolumeToSurfaceMapperAlgorithmParameters::transferParametersFromPreferencesFile(const PreferencesFile* pf) { const QString paramString = pf->getFmriAlgorithmParameters(); setAlgorithmParametersFromString(paramString); } /** * transfer parameters to preferences file. */ void BrainModelVolumeToSurfaceMapperAlgorithmParameters::transferParametersToPreferncesFile( PreferencesFile* pf, const bool writePreferencesFileFlag) { pf->setFmriAlgorithmParameters(getAlgorithmParametersAsString()); if (writePreferencesFileFlag) { try { if (pf->getFileName().isEmpty() == false) { pf->writeFile(pf->getFileName()); } } catch (FileException&) { } } } /** * get the algorithm parameters as a equal and semicolon separated string. */ QString BrainModelVolumeToSurfaceMapperAlgorithmParameters::getAlgorithmParametersAsString() const { QStringList sl; sl << "algorithm" << "=" << getAlgorithmName(algorithm) << ";"; sl << "averageVoxelNeighbors" << "=" << QString::number(averageVoxelNeighbors, 'f', 3) << ";"; sl << "maximumVoxelNeighbors" << "=" << QString::number(maximumVoxelNeighbors, 'f', 3) << ";"; sl << "strongestVoxelNeighbors" << "=" << QString::number(strongestVoxelNeighbors, 'f', 3) << ";"; sl << "gaussianNeighbors" << "=" << QString::number(gaussianNeighbors, 'f', 3) << ";"; sl << "gaussianSigmaNorm" << "=" << QString::number(gaussianSigmaNorm, 'f', 3) << ";"; sl << "gaussianSigmaTang" << "=" << QString::number(gaussianSigmaTang, 'f', 3) << ";"; sl << "gaussianNormBelowCutoff" << "=" << QString::number(gaussianNormBelowCutoff, 'f', 3) << ";"; sl << "gaussianNormAboveCutoff" << "=" << QString::number(gaussianNormAboveCutoff, 'f', 3) << ";"; sl << "gaussianTangCutoff" << "=" << QString::number(gaussianTangCutoff, 'f', 3) << ";"; sl << "mcwBrainFishMaxDistance" << "=" << QString::number(mcwBrainFishMaxDistance, 'f', 3) << ";"; sl << "mcwBrainFishSplatFactor" << "=" << QString::number(mcwBrainFishSplatFactor) << ";"; const QString s = sl.join(""); return s; } /** * set the algorithm parameters from a string. */ void BrainModelVolumeToSurfaceMapperAlgorithmParameters::setAlgorithmParametersFromString(const QString& s) { const QStringList sl = s.split(';'); for (int i = 0; i < sl.count(); i++) { const QStringList paramSL = sl.at(i).split('='); if (paramSL.count() == 2) { const QString name = paramSL.at(0); const QString value = paramSL.at(1); if (name == "algorithm") { algorithm = getAlgorithmFromNameString(value); } else if (name == "averageVoxelNeighbors") { averageVoxelNeighbors = value.toFloat(); } else if (name == "maximumVoxelNeighbors") { maximumVoxelNeighbors = value.toFloat(); } else if (name == "strongestVoxelNeighbors") { strongestVoxelNeighbors = value.toFloat(); } else if (name == "gaussianNeighbors") { gaussianNeighbors = value.toFloat(); } else if (name == "gaussianSigmaNorm") { gaussianSigmaNorm = value.toFloat(); } else if (name == "gaussianSigmaTang") { gaussianSigmaTang = value.toFloat(); } else if (name == "gaussianNormBelowCutoff") { gaussianNormBelowCutoff = value.toFloat(); } else if (name == "gaussianNormAboveCutoff") { gaussianNormAboveCutoff = value.toFloat(); } else if (name == "gaussianTangCutoff") { gaussianTangCutoff = value.toFloat(); } else if (name == "mcwBrainFishMaxDistance") { mcwBrainFishMaxDistance = value.toFloat(); } else if (name == "mcwBrainFishSplatFactor") { mcwBrainFishSplatFactor = value.toInt(); } } } } /** * get algorithm parameters as string for comment usage. */ QString BrainModelVolumeToSurfaceMapperAlgorithmParameters::getAlgorithmParametersForComment() const { QString s; switch (algorithm) { case ALGORITHM_METRIC_AVERAGE_NODES: s.append("Algorithm: Metric Average Nodes\n"); break; case ALGORITHM_METRIC_AVERAGE_VOXEL: s.append("Algorithm: Metric Average Voxel\n"); s.append(" neighbors="); s.append(QString::number(averageVoxelNeighbors, 'f', 3)); s.append("mm\n"); break; case ALGORITHM_METRIC_ENCLOSING_VOXEL: s.append("Algorithm: Metric Enclosing Voxel\n"); break; case ALGORITHM_METRIC_GAUSSIAN: s.append("Algorithm: Metric Gaussian\n"); s.append(" neighbors="); s.append(QString::number(gaussianNeighbors, 'f', 3)); s.append("mm sigma-norm="); s.append(QString::number(gaussianSigmaNorm, 'f', 3)); s.append(" sigma-tang="); s.append(QString::number(gaussianSigmaTang, 'f', 3)); s.append(" norm-below-cutoff="); s.append(QString::number(gaussianNormBelowCutoff, 'f', 3)); s.append(" norm-above-cutoff="); s.append(QString::number(gaussianNormAboveCutoff, 'f', 3)); s.append(" tang-cutoff="); s.append(QString::number(gaussianTangCutoff, 'f', 3)); s.append("\n"); break; case ALGORITHM_METRIC_INTERPOLATED_VOXEL: s.append("Algorithm: Metric Interpolated Voxel\n"); break; case ALGORITHM_METRIC_MAXIMUM_VOXEL: s.append("Algorithm: Metric Maximum Voxel\n"); s.append(" neighbors="); s.append(QString::number(maximumVoxelNeighbors, 'f', 3)); s.append("mm\n"); break; case ALGORITHM_METRIC_MCW_BRAINFISH: s.append("Algorithm: Metric MCW Brain Fish\n"); s.append(" max-distance="); s.append(QString::number(mcwBrainFishMaxDistance, 'f', 3)); s.append(" splat-factor="); s.append(QString::number(mcwBrainFishSplatFactor)); s.append("\n"); break; case ALGORITHM_METRIC_STRONGEST_VOXEL: s.append("Algorithm: Metric Strongest Voxel\n"); s.append(" neighbors="); s.append(QString::number(strongestVoxelNeighbors, 'f', 3)); s.append("mm\n"); break; case ALGORITHM_PAINT_ENCLOSING_VOXEL: s.append("Algorithm: Paint Enclosing Voxel\n"); break; } return s; } /** * get algorithm. */ BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM BrainModelVolumeToSurfaceMapperAlgorithmParameters::getAlgorithm() const { return algorithm; } /** * set algorithm. */ void BrainModelVolumeToSurfaceMapperAlgorithmParameters::setAlgorithm(const ALGORITHM alg) { algorithm = alg; } /** * get the algorithm name. */ QString BrainModelVolumeToSurfaceMapperAlgorithmParameters::getAlgorithmName(const ALGORITHM alg) { QString s("Unknown"); switch (alg) { case ALGORITHM_METRIC_AVERAGE_NODES: s = getAlgorithmMetricAverageNodesName(); break; case ALGORITHM_METRIC_AVERAGE_VOXEL: s = getAlgorithmMetricAverageVoxelName(); break; case ALGORITHM_METRIC_ENCLOSING_VOXEL: s = getAlgorithmMetricEnclosingVoxelName(); break; case ALGORITHM_METRIC_GAUSSIAN: s = getAlgorithmMetricGaussianName(); break; case ALGORITHM_METRIC_INTERPOLATED_VOXEL: s = getAlgorithmMetricInterpolatedVoxelName(); break; case ALGORITHM_METRIC_MAXIMUM_VOXEL: s = getAlgorithmMetricMaximumVoxelName(); break; case ALGORITHM_METRIC_MCW_BRAINFISH: s = getAlgorithmMetricMcwBrainFishName(); break; case ALGORITHM_METRIC_STRONGEST_VOXEL: s = getAlgorithmMetricStrongestVoxelName(); break; case ALGORITHM_PAINT_ENCLOSING_VOXEL: s = getAlgorithmPaintEnclosingVoxel(); break; } return s; } /** * get algorithm from string. */ BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM BrainModelVolumeToSurfaceMapperAlgorithmParameters::getAlgorithmFromNameString(const QString& s) { ALGORITHM alg = ALGORITHM_METRIC_ENCLOSING_VOXEL; if (s == getAlgorithmMetricAverageNodesName()) { alg = ALGORITHM_METRIC_AVERAGE_NODES; } else if (s == getAlgorithmMetricAverageVoxelName()) { alg = ALGORITHM_METRIC_AVERAGE_VOXEL; } else if (s == getAlgorithmMetricEnclosingVoxelName()) { alg = ALGORITHM_METRIC_ENCLOSING_VOXEL; } else if (s == getAlgorithmMetricGaussianName()) { alg = ALGORITHM_METRIC_GAUSSIAN; } else if (s == getAlgorithmMetricInterpolatedVoxelName()) { alg = ALGORITHM_METRIC_INTERPOLATED_VOXEL; } else if (s == getAlgorithmMetricMaximumVoxelName()) { alg = ALGORITHM_METRIC_MAXIMUM_VOXEL; } else if (s == getAlgorithmMetricMcwBrainFishName()) { alg = ALGORITHM_METRIC_MCW_BRAINFISH; } else if (s == getAlgorithmMetricStrongestVoxelName()) { alg = ALGORITHM_METRIC_STRONGEST_VOXEL; } else if (s == getAlgorithmPaintEnclosingVoxel()) { alg = ALGORITHM_PAINT_ENCLOSING_VOXEL; } return alg; } /** * get the algorithm names and values. */ void BrainModelVolumeToSurfaceMapperAlgorithmParameters::getAlgorithmNamesAndValues( std::vector& namesOut, std::vector& valuesOut) { namesOut.clear(); valuesOut.clear(); namesOut.push_back(getAlgorithmMetricAverageNodesName()); valuesOut.push_back(ALGORITHM_METRIC_AVERAGE_NODES); namesOut.push_back(getAlgorithmMetricAverageVoxelName()); valuesOut.push_back(ALGORITHM_METRIC_AVERAGE_VOXEL); namesOut.push_back(getAlgorithmMetricEnclosingVoxelName()); valuesOut.push_back(ALGORITHM_METRIC_ENCLOSING_VOXEL); namesOut.push_back(getAlgorithmMetricGaussianName()); valuesOut.push_back(ALGORITHM_METRIC_GAUSSIAN); namesOut.push_back(getAlgorithmMetricInterpolatedVoxelName()); valuesOut.push_back(ALGORITHM_METRIC_INTERPOLATED_VOXEL); namesOut.push_back(getAlgorithmMetricMaximumVoxelName()); valuesOut.push_back(ALGORITHM_METRIC_MAXIMUM_VOXEL); namesOut.push_back(getAlgorithmMetricMcwBrainFishName()); valuesOut.push_back(ALGORITHM_METRIC_MCW_BRAINFISH); namesOut.push_back(getAlgorithmMetricStrongestVoxelName()); valuesOut.push_back(ALGORITHM_METRIC_STRONGEST_VOXEL); namesOut.push_back(getAlgorithmPaintEnclosingVoxel()); valuesOut.push_back(ALGORITHM_PAINT_ENCLOSING_VOXEL); } /** * get the average voxel parameters. */ void BrainModelVolumeToSurfaceMapperAlgorithmParameters::getAlgorithmMetricAverageVoxelParameters(float& neighborsOut) const { neighborsOut = averageVoxelNeighbors; } /** * set the average voxel parameters. */ void BrainModelVolumeToSurfaceMapperAlgorithmParameters::setAlgorithmMetricAverageVoxelParameters(const float neighborsIn) { averageVoxelNeighbors = neighborsIn; } /** * get the maximum voxel parameters. */ void BrainModelVolumeToSurfaceMapperAlgorithmParameters::getAlgorithmMetricMaximumVoxelParameters(float& neighborsOut) const { neighborsOut = maximumVoxelNeighbors; } /** * set the maximum voxel parameters. */ void BrainModelVolumeToSurfaceMapperAlgorithmParameters::setAlgorithmMetricMaximumVoxelParameters(const float neighborsIn) { maximumVoxelNeighbors = neighborsIn; } /** * get the strongest voxel parameters. */ void BrainModelVolumeToSurfaceMapperAlgorithmParameters::getAlgorithmMetricStrongestVoxelParameters(float& neighborsOut) const { neighborsOut = strongestVoxelNeighbors; } /** * set the maximum voxel parameters. */ void BrainModelVolumeToSurfaceMapperAlgorithmParameters::setAlgorithmMetricStrongestVoxelParameters(const float neighborsIn) { strongestVoxelNeighbors = neighborsIn; } /** * set gaussian algorithm parameters. */ void BrainModelVolumeToSurfaceMapperAlgorithmParameters::getAlgorithmMetricGaussianParameters( float& gaussianNeighborsOut, float& gaussianSigmaNormOut, float& gaussianSigmaTangOut, float& gaussianNormBelowCutoffOut, float& gaussianNormAboveCutoffOut, float& gaussianTangCutoffOut) const { gaussianNeighborsOut = gaussianNeighbors; gaussianSigmaNormOut = gaussianSigmaNorm; gaussianSigmaTangOut = gaussianSigmaTang; gaussianNormBelowCutoffOut = gaussianNormBelowCutoff; gaussianNormAboveCutoffOut = gaussianNormAboveCutoff; gaussianTangCutoffOut = gaussianTangCutoff; } /** * set gaussian algorithm parameters. */ void BrainModelVolumeToSurfaceMapperAlgorithmParameters::setAlgorithmMetricGaussianParameters( const float gaussianNeighborsIn, const float gaussianSigmaNormIn, const float gaussianSigmaTangIn, const float gaussianNormBelowCutoffIn, const float gaussianNormAboveCutoffIn, const float gaussianTangCutoffIn) { gaussianNeighbors = gaussianNeighborsIn; gaussianSigmaNorm = gaussianSigmaNormIn; gaussianSigmaTang = gaussianSigmaTangIn; gaussianNormBelowCutoff = gaussianNormBelowCutoffIn; gaussianNormAboveCutoff = gaussianNormAboveCutoffIn; gaussianTangCutoff = gaussianTangCutoffIn; } /** * get the mcw brainfish algorithm parameters. */ void BrainModelVolumeToSurfaceMapperAlgorithmParameters::getAlgorithmMetricMcwBrainFishParameters( float& mcwBrainFishMaxDistanceOut, int& mcwBrainFishSplatFactorOut) const { mcwBrainFishMaxDistanceOut = mcwBrainFishMaxDistance; mcwBrainFishSplatFactorOut = mcwBrainFishSplatFactor; } /** * set the mcw brainfish algorithm parameters. */ void BrainModelVolumeToSurfaceMapperAlgorithmParameters::setAlgorithmMetricMcwBrainFishParameters( const float mcwBrainFishMaxDistanceIn, const int mcwBrainFishSplatFactorIn) { mcwBrainFishMaxDistance = mcwBrainFishMaxDistanceIn; mcwBrainFishSplatFactor = mcwBrainFishSplatFactorIn; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeToSurfaceMapper.h0000664000175000017500000001320611572067322026245 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __BRAIN_MODEL_VOLUME_TO_SURFACE_MAPPER_H__ #define __BRAIN_MODEL_VOLUME_TO_SURFACE_MAPPER_H__ #include "BrainModelAlgorithm.h" #include "BrainModelVolumeToSurfaceMapperAlgorithmParameters.h" class BrainModelSurface; class GiftiNodeDataFile; class MetricFile; class PaintFile; class TopologyHelper; class VolumeFile; /// class that maps a volume (typically functional) to a surface's node attribute file class BrainModelVolumeToSurfaceMapper : public BrainModelAlgorithm { public: /// Constructor for a volume file in memory. BrainModelVolumeToSurfaceMapper(BrainSet* bs, BrainModelSurface* surfaceIn, VolumeFile* volumeFileIn, GiftiNodeDataFile* dataFileIn, const BrainModelVolumeToSurfaceMapperAlgorithmParameters algorithmIn, const int dataFileColumnIn, const QString& dataFileColumnNameIn); /// Constructor for a volume file that needs to be read. BrainModelVolumeToSurfaceMapper(BrainSet* bs, BrainModelSurface* surfaceIn, const QString& volumeFileNameIn, GiftiNodeDataFile* dataFileIn, const BrainModelVolumeToSurfaceMapperAlgorithmParameters algorithmIn, const int dataFileColumnIn, const QString& dataFileColumnNameIn); /// Destructor ~BrainModelVolumeToSurfaceMapper(); /// execute the algorithm virtual void execute() throw (BrainModelAlgorithmException); protected: /// Run the Metric Average Nodes algorithm void algorithmMetricAverageNodes(const float* allCoords); /// Run the Metric Average Voxel algorithm void algorithmMetricAverageVoxel(const float* allCoords); /// Run the Metric Enclosing Voxel algorithm void algorithmMetricEnclosingVoxel(const float* allCoords); /// Run the Metric Gaussian algorithm void algorithmMetricGaussian(const float* allCoords); /// Run the Metric Interpolated Voxel algorithm void algorithmMetricInterpolatedVoxel(const float* allCoords); /// Run the Metric Maximum Voxel algorithm void algorithmMetricMaximumVoxel(const float* allCoords); /// Run the Metric Strongest Voxel algorithm void algorithmMetricStrongestVoxel(const float* allCoords); /// Run the Metric MCW Brain Fish algorithm void algorithmMetricMcwBrainFish(const float* allCoords); /// Run the Paint Enclosing Voxel algorithm void algorithmPaintEnclosingVoxel(const float* allCoords); /// add paint names for paint indices without names void addPaintNamesForIndicesWithoutNames(); /// Get the valid subvolume for neighbor mapping algorithms. bool getNeighborsSubVolume(const float xyz[3], int& iMin, int& iMax, int& jMin, int& jMax, int& kMin, int& kMax, const float neighborsCubeSize) const; /// volume source type enum MODE_VOLUME { MODE_VOLUME_IN_MEMORY, MODE_VOLUME_ON_DISK }; /// the algorithm parameters BrainModelVolumeToSurfaceMapperAlgorithmParameters algorithmParameters; /// surface for mapping BrainModelSurface* surface; /// volume to map VolumeFile* volumeFile; /// the data file GiftiNodeDataFile* dataFile; /// metric file to update MetricFile* metricFile; /// paint file to update PaintFile* paintFile; /// the data file column int dataFileColumn; /// name for data column QString dataFileColumnName; /// volume type mode MODE_VOLUME volumeMode; /// volume file name QString volumeFileName; /// the topology helper TopologyHelper* topologyHelper; /// number of nodes in the surface int numberOfNodes; /// data file column number being updated int dataFileColumnNumber; /// volume dimensions int volumeDimensions[3]; /// volume origin float volumeOrigin[3]; /// volume voxel size float volumeVoxelSize[3]; /// index of ??? paint name int paintQuestionNameIndex; /// translates paint volume indices to paint file indices std::vector paintVolumeIndexToPaintFileNameIndex; }; #endif // __BRAIN_MODEL_VOLUME_TO_SURFACE_MAPPER_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeToSurfaceMapper.cxx0000664000175000017500000013314211572067322026622 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include "BrainModelSurface.h" #include "BrainModelSurfacePointLocator.h" #include "BrainModelVolumeToSurfaceMapper.h" #include "BrainSet.h" #include "CaretVersion.h" #include "DateAndTime.h" #include "FileUtilities.h" #include "GaussianComputation.h" #include "MathUtilities.h" #include "MetricFile.h" #include "PaintFile.h" #include "StringUtilities.h" #include "TopologyFile.h" #include "TopologyHelper.h" #include "VolumeFile.h" #include "vtkMath.h" /** * Constructor for a volume file in memory */ BrainModelVolumeToSurfaceMapper::BrainModelVolumeToSurfaceMapper( BrainSet* bs, BrainModelSurface* surfaceIn, VolumeFile* volumeFileIn, GiftiNodeDataFile* dataFileIn, const BrainModelVolumeToSurfaceMapperAlgorithmParameters algorithmIn, const int dataFileColumnIn, const QString& dataFileColumnNameIn) : BrainModelAlgorithm(bs) { metricFile = NULL; paintFile = NULL; volumeMode = MODE_VOLUME_IN_MEMORY; surface = surfaceIn; volumeFile = volumeFileIn; dataFile = dataFileIn; dataFileColumn = dataFileColumnIn; dataFileColumnName = dataFileColumnNameIn; algorithmParameters = algorithmIn; } /** * Constructor for a volume file that needs to be read. */ BrainModelVolumeToSurfaceMapper::BrainModelVolumeToSurfaceMapper( BrainSet* bs, BrainModelSurface* surfaceIn, const QString& volumeFileNameIn, GiftiNodeDataFile* dataFileIn, const BrainModelVolumeToSurfaceMapperAlgorithmParameters algorithmIn, const int dataFileColumnIn, const QString& dataFileColumnNameIn) : BrainModelAlgorithm(bs) { metricFile = NULL; paintFile = NULL; volumeFile = NULL; volumeMode = MODE_VOLUME_ON_DISK; surface = surfaceIn; volumeFileName = volumeFileNameIn; dataFile = dataFileIn; dataFileColumn = dataFileColumnIn; dataFileColumnName = dataFileColumnNameIn; algorithmParameters = algorithmIn; } /** * Destructor */ BrainModelVolumeToSurfaceMapper::~BrainModelVolumeToSurfaceMapper() { } /** * execute the algorithm */ void BrainModelVolumeToSurfaceMapper::execute() throw (BrainModelAlgorithmException) { // // Get surface stuff // if (surface == NULL) { throw BrainModelAlgorithmException("No surface provided."); } const CoordinateFile* cf = surface->getCoordinateFile(); numberOfNodes = cf->getNumberOfCoordinates(); if (numberOfNodes <= 0) { throw BrainModelAlgorithmException("Surface contains no nodes."); } const float* allCoords = cf->getCoordinate(0); // // Get the topology file // TopologyFile* tf = surface->getTopologyFile(); if (tf == NULL) { throw BrainModelAlgorithmException("Surface has no topology."); } // // Verify paint/metric // if (dataFile == NULL) { throw BrainModelAlgorithmException("Metric/Paint file is invalid."); } switch (algorithmParameters.getAlgorithm()) { case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_METRIC_AVERAGE_NODES: case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_METRIC_AVERAGE_VOXEL: case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_METRIC_ENCLOSING_VOXEL: case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_METRIC_GAUSSIAN: case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_METRIC_INTERPOLATED_VOXEL: case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_METRIC_MAXIMUM_VOXEL: case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_METRIC_MCW_BRAINFISH: case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_METRIC_STRONGEST_VOXEL: metricFile = dynamic_cast(dataFile); if (metricFile == NULL) { throw BrainModelAlgorithmException("A metric file must be provided for metric mapping."); } break; case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_PAINT_ENCLOSING_VOXEL: paintFile = dynamic_cast(dataFile); if (paintFile == NULL) { throw BrainModelAlgorithmException("A metric file must be provided for metric mapping."); } break; } // // Create topology helper so that only connected nodes are mapped // topologyHelper = (TopologyHelper*)tf->getTopologyHelper(false, true, false); // // Reset metric column if necessary // dataFileColumnNumber = 0; if ((dataFileColumn < 0) || (dataFileColumn >= dataFile->getNumberOfColumns())) { dataFileColumn = -1; } if (dataFileColumn >= 0) { dataFileColumnNumber = dataFileColumn; } int columnsToAdd = 0; // // Mapping using a file that needs to be read // VolumeFile volumeFileOnDisk; int numberOfSubVolumes = 1; switch (volumeMode) { case MODE_VOLUME_ON_DISK: // // Determine the number of sub volumes in the volume by reading the header // volumeFile = &volumeFileOnDisk; try { volumeFile->readFile(volumeFileName, VolumeFile::VOLUME_READ_HEADER_ONLY); numberOfSubVolumes = volumeFile->getNumberOfSubVolumes(); // // Determine the number of columns that need to be added to the metric file // if (dataFileColumn < 0) { columnsToAdd = numberOfSubVolumes; dataFileColumnNumber = dataFile->getNumberOfColumns(); } else { columnsToAdd = (dataFileColumn + numberOfSubVolumes) - dataFile->getNumberOfColumns(); dataFileColumnNumber = dataFileColumn; } } catch (FileException& e) { throw BrainModelAlgorithmException(e.whatQString()); } break; case MODE_VOLUME_IN_MEMORY: if (volumeFile == NULL) { throw BrainModelAlgorithmException("No volume provided."); } if (dataFileColumn < 0) { columnsToAdd = 1; dataFileColumnNumber = dataFile->getNumberOfColumns(); } break; } // // Paint file region names // if (paintFile != NULL) { paintQuestionNameIndex = paintFile->addPaintName("???"); // // Process the regions // paintVolumeIndexToPaintFileNameIndex.clear(); const int numRegionNames = volumeFile->getNumberOfRegionNames(); for (int i = 0; i < numRegionNames; i++) { QString name(volumeFile->getRegionNameFromIndex(i)); if (name.isEmpty()) { name = ("Unknown_name_" + QString::number(i)); } paintVolumeIndexToPaintFileNameIndex.push_back(paintFile->addPaintName(name)); } } // // Add space, if needed, to the metric file // if (columnsToAdd > 0) { // // Add a column onto the metric file // if (dataFile->getNumberOfColumns() == 0) { dataFile->setNumberOfNodesAndColumns(numberOfNodes, columnsToAdd); } else { dataFile->addColumns(columnsToAdd); } } // // Get volume information // volumeFile->getOrigin(volumeOrigin); volumeFile->getSpacing(volumeVoxelSize); volumeFile->getDimensions(volumeDimensions); for (int j = 0; j < numberOfSubVolumes; j++) { switch (volumeMode) { case MODE_VOLUME_ON_DISK: // // Read the sub volume // try { volumeFile->readFile(volumeFileName, j); } catch (FileException& e) { throw BrainModelAlgorithmException(e.whatQString()); } break; case MODE_VOLUME_IN_MEMORY: break; } int dim[3]; volumeFile->getDimensions(dim); if ((dim[0] <= 0) || (dim[1] <= 0) || (dim[2] <= 0)) { throw BrainModelAlgorithmException("Volume is empty - dimensions all zero."); } QString columnName(dataFileColumnName); if (volumeMode == MODE_VOLUME_ON_DISK) { if (columnName.isEmpty()) { std::vector subVolumeNames; if (j < static_cast(subVolumeNames.size())) { columnName = subVolumeNames[j]; } } if (columnName.isEmpty()) { std::ostringstream str; str << " #" << (j + 1); columnName.append(str.str().c_str()); } } dataFile->setColumnName(dataFileColumnNumber, columnName); // // Map the volume to the surface // switch (algorithmParameters.getAlgorithm()) { case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_METRIC_AVERAGE_NODES: algorithmMetricAverageNodes(allCoords); break; case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_METRIC_AVERAGE_VOXEL: algorithmMetricAverageVoxel(allCoords); break; case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_METRIC_ENCLOSING_VOXEL: algorithmMetricEnclosingVoxel(allCoords); break; case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_METRIC_GAUSSIAN: algorithmMetricGaussian(allCoords); break; case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_METRIC_INTERPOLATED_VOXEL: algorithmMetricInterpolatedVoxel(allCoords); break; case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_METRIC_MAXIMUM_VOXEL: algorithmMetricMaximumVoxel(allCoords); break; case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_METRIC_MCW_BRAINFISH: algorithmMetricMcwBrainFish(allCoords); break; case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_METRIC_STRONGEST_VOXEL: algorithmMetricStrongestVoxel(allCoords); break; case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_PAINT_ENCLOSING_VOXEL: algorithmPaintEnclosingVoxel(allCoords); break; } // // Set the metadata link // dataFile->setColumnStudyMetaDataLinkSet(dataFileColumnNumber, volumeFile->getStudyMetaDataLinkSet()); // // Set the comment // QString comment; comment.append("CARET v"); comment.append(CaretVersion::getCaretVersionAsString()); comment.append("\n"); comment.append("Mapped to surface: "); comment.append(FileUtilities::basename(cf->getFileName())); comment.append("\n"); comment.append("Mapped from volume: "); comment.append(FileUtilities::basename(volumeFile->getFileName())); comment.append("\n"); comment.append("Subvolume: "); comment.append(StringUtilities::fromNumber(j)); comment.append("\n"); comment.append(algorithmParameters.getAlgorithmParametersForComment()); // // Might have been a NIFTI file // GiftiMetaData* md = dataFile->getDataArray(dataFileColumnNumber)->getMetaData(); QString niftiIntentAndParamString; QString niftiIntentName; int intentCode; float intentParameter1, intentParameter2, intentParameter3; float niftiTR; volumeFile->getNiftiInfo(niftiIntentAndParamString, niftiIntentName, intentCode, intentParameter1, intentParameter2, intentParameter3, niftiTR); if (niftiIntentAndParamString.isEmpty() == false) { comment.append("intent: " + niftiIntentAndParamString + "\n"); md->set("intent", niftiIntentAndParamString); comment.append("intent_code: " + QString::number(intentCode) + "\n"); md->set("intent_code", QString::number(intentCode)); comment.append("intent_p1: " + QString::number(intentParameter1, 'f', 3) + "\n"); md->set("intent_p1", QString::number(intentParameter1, 'f', 3)); comment.append("intent_p2: " + QString::number(intentParameter2, 'f', 3) + "\n"); md->set("intent_p2", QString::number(intentParameter2, 'f', 3)); comment.append("intent_p3: " + QString::number(intentParameter3, 'f', 3) + "\n"); md->set("intent_p3", QString::number(intentParameter3, 'f', 3)); GiftiDataArray* gda = dataFile->getDataArray(dataFileColumnNumber); gda->setIntent(niftiIntentName); } if (niftiTR != 0.0) { comment.append("slice_duration: " + QString::number(niftiTR) + "\n"); md->set("TimeStep", niftiTR); } comment.append("\n"); comment.append("Date Mapped: "); comment.append(DateAndTime::getDateAndTimeAsString()); comment.append("\n"); dataFile->setColumnComment(dataFileColumnNumber, comment); // // Prepare for mapping next column // dataFileColumnNumber++; } // // Add paint names for anything that is missing // if (paintFile != NULL) { addPaintNamesForIndicesWithoutNames(); } // // Store algorithm parameters in preferences file // PreferencesFile* pf = brainSet->getPreferencesFile(); algorithmParameters.transferParametersToPreferncesFile(pf, true); } /** * Run the Metric Average Nodes algorithm. * The metric for each node is the average of the node and its neighbors voxel values. */ void BrainModelVolumeToSurfaceMapper::algorithmMetricAverageNodes(const float* allCoords) { for (int i = 0; i < numberOfNodes; i++) { float value = 0.0; if (topologyHelper->getNodeHasNeighbors(i)) { int ijk[3]; float pcoords[3]; if (volumeFile->convertCoordinatesToVoxelIJK((float*)&allCoords[i*3], ijk, pcoords)) { value = volumeFile->getVoxel(ijk, 0); float numContribute = 1.0; int numNeighbors = 0; const int* neighbors = topologyHelper->getNodeNeighbors(i, numNeighbors); for (int j = 0; j < numNeighbors; j++) { const int n = neighbors[j]; if (volumeFile->convertCoordinatesToVoxelIJK((float*)&allCoords[n*3], ijk, pcoords)) { value += volumeFile->getVoxel(ijk, 0); numContribute += 1.0; } } value /= numContribute; } } metricFile->setValue(i, dataFileColumnNumber, value); } } /** * Run the Metric Average Voxel algorithm */ void BrainModelVolumeToSurfaceMapper::algorithmMetricAverageVoxel(const float* allCoords) { float averageVoxelNeighbors = 1.0; algorithmParameters.getAlgorithmMetricAverageVoxelParameters(averageVoxelNeighbors); for (int i = 0; i < numberOfNodes; i++) { float value = 0.0; float numValueCounter = 0.0; if (topologyHelper->getNodeHasNeighbors(i)) { int iMin, iMax, jMin, jMax, kMin, kMax; if (getNeighborsSubVolume(&allCoords[i*3], iMin, iMax, jMin, jMax, kMin, kMax, averageVoxelNeighbors)) { for (int ii = iMin; ii <= iMax; ii++) { for (int jj = jMin; jj <= jMax; jj++) { for (int kk = kMin; kk <= kMax; kk++) { int ijk[3] = { ii, jj, kk }; value += volumeFile->getVoxel(ijk, 0); numValueCounter += 1.0; } } } } } if (numValueCounter > 0.0) { value /= numValueCounter; } metricFile->setValue(i, dataFileColumnNumber, value); } } /** * Run the Metric Enclosing Voxel algorithm */ void BrainModelVolumeToSurfaceMapper::algorithmMetricEnclosingVoxel(const float* allCoords) { for (int i = 0; i < numberOfNodes; i++) { float value = 0.0; if (topologyHelper->getNodeHasNeighbors(i)) { int ijk[3]; float pcoords[3]; if (volumeFile->convertCoordinatesToVoxelIJK((float*)&allCoords[i*3], ijk, pcoords)) { value = volumeFile->getVoxel(ijk, 0); } } metricFile->setValue(i, dataFileColumnNumber, value); } } /* SAVED void BrainModelVolumeToSurfaceMapper::algorithmGaussian(const float* allCoords) { const float halfVoxelX = volumeVoxelSize[0] * 0.5; const float halfVoxelY = volumeVoxelSize[1] * 0.5; const float halfVoxelZ = volumeVoxelSize[2] * 0.5; for (int i = 0; i < numberOfNodes; i++) { float value = 0.0; if (topologyHelper->getNodeHasNeighbors(i)) { float voxelSum = 0.0; float weightSum = 0.0; int iMin, iMax, jMin, jMax, kMin, kMax; if (getNeighborsSubVolume(&allCoords[i*3], iMin, iMax, jMin, jMax, kMin, kMax, gaussianNeighbors)) { const float* nodeNormal = surface->getNormal(i); for (int ii = iMin; ii <= iMax; ii++) { for (int jj = jMin; jj <= jMax; jj++) { for (int kk = kMin; kk <= kMax; kk++) { int ijk[3] = { ii, jj, kk }; vtkIdType pointID = structuredPointsVolume->ComputePointId(ijk); // // Voxel position - probably should add 1/2 voxel to get voxel center // const float voxelPos[3] = { (ii * volumeVoxelSize[0] + volumeOrigin[0]) + halfVoxelX, (jj * volumeVoxelSize[1] + volumeOrigin[1]) + halfVoxelY, (kk * volumeVoxelSize[2] + volumeOrigin[2]) + halfVoxelZ }; const float v = voxelDataArray->GetComponent(pointID, 0); //if (v != 0.0) { gaussian(&allCoords[i*3], nodeNormal, voxelPos, v, voxelSum, weightSum); //} } } } } if (weightSum != 0.0) { value = voxelSum / weightSum; } } metricFile->setValue(i, metricColumnNumber, value); } } */ /** * Run the Metric Gaussian algorithm */ void BrainModelVolumeToSurfaceMapper::algorithmMetricGaussian(const float* allCoords) { float gaussianNeighbors; float gaussianSigmaNorm; float gaussianSigmaTang; float gaussianNormBelowCutoff; float gaussianNormAboveCutoff; float gaussianTangCutoff; algorithmParameters.getAlgorithmMetricGaussianParameters(gaussianNeighbors, gaussianSigmaNorm, gaussianSigmaTang, gaussianNormBelowCutoff, gaussianNormAboveCutoff, gaussianTangCutoff); const float halfVoxelX = volumeVoxelSize[0] * 0.5; const float halfVoxelY = volumeVoxelSize[1] * 0.5; const float halfVoxelZ = volumeVoxelSize[2] * 0.5; for (int i = 0; i < numberOfNodes; i++) { float value = 0.0; if (topologyHelper->getNodeHasNeighbors(i)) { int iMin, iMax, jMin, jMax, kMin, kMax; if (getNeighborsSubVolume(&allCoords[i*3], iMin, iMax, jMin, jMax, kMin, kMax, gaussianNeighbors)) { std::vector gaussPoints; for (int ii = iMin; ii <= iMax; ii++) { for (int jj = jMin; jj <= jMax; jj++) { for (int kk = kMin; kk <= kMax; kk++) { int ijk[3] = { ii, jj, kk }; // // Voxel position - probably should add 1/2 voxel to get voxel center // const float voxelPos[3] = { (ii * volumeVoxelSize[0] + volumeOrigin[0]) + halfVoxelX, (jj * volumeVoxelSize[1] + volumeOrigin[1]) + halfVoxelY, (kk * volumeVoxelSize[2] + volumeOrigin[2]) + halfVoxelZ }; const float v = volumeFile->getVoxel(ijk, 0); gaussPoints.push_back(GaussianComputation::Point3D(voxelPos, v)); } } } GaussianComputation gauss(gaussianNormBelowCutoff, gaussianNormAboveCutoff, gaussianSigmaNorm, gaussianSigmaTang, gaussianTangCutoff); value = gauss.evaluate(&allCoords[i*3], surface->getNormal(i), gaussPoints); } } metricFile->setValue(i, dataFileColumnNumber, value); } } /** * Run the Metric Interpolated Voxel algorithm */ void BrainModelVolumeToSurfaceMapper::algorithmMetricInterpolatedVoxel(const float* allCoords) { for (int i = 0; i < numberOfNodes; i++) { float value = 0.0; if (topologyHelper->getNodeHasNeighbors(i)) { volumeFile->getInterpolatedVoxel(&allCoords[i*3], value); } metricFile->setValue(i, dataFileColumnNumber, value); } } /** * Run the Metric Maximum Voxel algorithm */ void BrainModelVolumeToSurfaceMapper::algorithmMetricMaximumVoxel(const float* allCoords) { float maximumVoxelNeighbors = 1.0; algorithmParameters.getAlgorithmMetricMaximumVoxelParameters(maximumVoxelNeighbors); for (int i = 0; i < numberOfNodes; i++) { float value = 0.0; if (topologyHelper->getNodeHasNeighbors(i)) { int iMin, iMax, jMin, jMax, kMin, kMax; if (getNeighborsSubVolume(&allCoords[i*3], iMin, iMax, jMin, jMax, kMin, kMax, maximumVoxelNeighbors)) { bool firstTime = true; for (int ii = iMin; ii <= iMax; ii++) { for (int jj = jMin; jj <= jMax; jj++) { for (int kk = kMin; kk <= kMax; kk++) { int ijk[3] = { ii, jj, kk }; const float v = volumeFile->getVoxel(ijk, 0); if (firstTime) { value = v; } else { value = std::max(v, value); } firstTime = false; } } } } } metricFile->setValue(i, dataFileColumnNumber, value); } } /** * Run the Metric Strongest Voxel algorithm */ void BrainModelVolumeToSurfaceMapper::algorithmMetricStrongestVoxel(const float* allCoords) { float strongestVoxelNeighbors = 1.0; algorithmParameters.getAlgorithmMetricStrongestVoxelParameters(strongestVoxelNeighbors); for (int i = 0; i < numberOfNodes; i++) { float absVoxel = 0.0; float signedVoxel = 0.0; if (topologyHelper->getNodeHasNeighbors(i)) { int iMin, iMax, jMin, jMax, kMin, kMax; if (getNeighborsSubVolume(&allCoords[i*3], iMin, iMax, jMin, jMax, kMin, kMax, strongestVoxelNeighbors)) { for (int ii = iMin; ii <= iMax; ii++) { for (int jj = jMin; jj <= jMax; jj++) { for (int kk = kMin; kk <= kMax; kk++) { int ijk[3] = { ii, jj, kk }; const float signedTemp = volumeFile->getVoxel(ijk, 0); const float absTemp = std::fabs(signedTemp); if (absTemp > absVoxel) { absVoxel = absTemp; signedVoxel = signedTemp; } } } } } } metricFile->setValue(i, dataFileColumnNumber, signedVoxel); } } /** * Run the Metric MCW Brain Fish algorithm */ void BrainModelVolumeToSurfaceMapper::algorithmMetricMcwBrainFish(const float* allCoords) { float mcwBrainFishMaxDistance; int mcwBrainFishSplatFactor; algorithmParameters.getAlgorithmMetricMcwBrainFishParameters(mcwBrainFishMaxDistance, mcwBrainFishSplatFactor); float surfaceBounds[6]; surface->getBounds(surfaceBounds); // // convert surface bounds into voxel indices // float voxelBounds[6]; voxelBounds[0] = floor((surfaceBounds[0] - volumeOrigin[0]) / volumeVoxelSize[0]); voxelBounds[1] = floor((surfaceBounds[1] - volumeOrigin[0]) / volumeVoxelSize[0]); voxelBounds[2] = floor((surfaceBounds[2] - volumeOrigin[1]) / volumeVoxelSize[1]); voxelBounds[3] = floor((surfaceBounds[3] - volumeOrigin[1]) / volumeVoxelSize[1]); voxelBounds[4] = floor((surfaceBounds[4] - volumeOrigin[2]) / volumeVoxelSize[2]); voxelBounds[5] = floor((surfaceBounds[5] - volumeOrigin[2]) / volumeVoxelSize[2]); // // Limit search of volume to voxels around surface's bounds // int xmin = static_cast(voxelBounds[0] - mcwBrainFishMaxDistance - 1); int xmax = static_cast(voxelBounds[1] + mcwBrainFishMaxDistance + 1); if (xmin < 0) xmin = 0; if (xmax >= volumeDimensions[0]) xmax = volumeDimensions[0] - 1; int ymin = static_cast(voxelBounds[2] - mcwBrainFishMaxDistance - 1); int ymax = static_cast(voxelBounds[3] + mcwBrainFishMaxDistance + 1); if (ymin < 0) ymin = 0; if (ymax >= volumeDimensions[1]) ymax = volumeDimensions[1] - 1; int zmin = static_cast(voxelBounds[4] - mcwBrainFishMaxDistance - 1); int zmax = static_cast(voxelBounds[5] + mcwBrainFishMaxDistance + 1); if (zmin < 0) zmin = 0; if (zmax >= volumeDimensions[2]) zmax = volumeDimensions[2] - 1; if (DebugControl::getDebugOn()) { //printf("ROI: xmin=%d; xmax=%d; ymin=%d; ymax=%d; zmin=%d; zmax=%d\n", // xmin, xmax, ymin, ymax, zmin, zmax); } float* activity = new float[numberOfNodes]; bool* assigned = new bool[numberOfNodes]; bool* assignedToo = new bool[numberOfNodes]; for (int m = 0; m < numberOfNodes; m++) { assigned[m] = false; assignedToo[m] = false; activity[m] = 0.0; } // // Use a point locator to speed nearby node queries // BrainModelSurfacePointLocator* pointLocator = new BrainModelSurfacePointLocator( surface, true); // // loop through the voxels // for (int k = zmin; k < zmax; k++) { for (int j = ymin; j < ymax; j++) { for (int i = xmin; i < xmax; i++) { int ijk[3] = { i, j, k }; // // voxel at (i, j, k) // const float voxel = volumeFile->getVoxel(ijk, 0); //printf("voxel (%d,%d,%d) = %f\n", i, j, k, voxel); // // Only do voxels that have some activity // if (voxel != 0.0) { int nearestNode = -1; // // Center of voxel // float voxelPos[3] = { volumeOrigin[0] + ijk[0] * volumeVoxelSize[0] + volumeVoxelSize[0] * 0.5, volumeOrigin[1] + ijk[1] * volumeVoxelSize[1] + volumeVoxelSize[1] * 0.5, volumeOrigin[2] + ijk[2] * volumeVoxelSize[2] + volumeVoxelSize[2] * 0.5 }; // // Find the node that is nearest to the voxel // const int nodeFound = pointLocator->getNearestPoint(voxelPos); if (nodeFound >= 0) { // // Make sure node is within the brain fish max distance // const float* xyz = &allCoords[nodeFound*3]; if ((xyz[0] > (voxelPos[0] - mcwBrainFishMaxDistance)) && (xyz[0] < (voxelPos[0] + mcwBrainFishMaxDistance))) { if ((xyz[1] > (voxelPos[1] - mcwBrainFishMaxDistance)) && (xyz[1] < (voxelPos[1] + mcwBrainFishMaxDistance))) { if ((xyz[2] > (voxelPos[2] - mcwBrainFishMaxDistance)) && (xyz[2] < (voxelPos[2] + mcwBrainFishMaxDistance))) { nearestNode = nodeFound; } } } } // // Allow positive activity to override negative activity // Negative only overrides "less negative" // if (nearestNode >= 0) { assigned[nearestNode] = true; const float nodeValue = activity[nearestNode]; if (voxel > 0.0) { if (voxel > nodeValue) { activity[nearestNode] = voxel; } } else if (nodeValue < 0.0) { if (voxel < nodeValue) { activity[nearestNode] = voxel; } } } } } } } // // Process the splat factor. For each node that is assigned, check any // of its neighbors that are not assigned. If the neighbor is not assigned, // assign the neighbor the average of its assigned neighbors. // if (mcwBrainFishSplatFactor > 0) { for (int m = 0; m < numberOfNodes; m++) { assignedToo[m] = assigned[m]; } // // Number of Splat levels // for (int k = 0; k < mcwBrainFishSplatFactor; k++) { for (int m = 0; m < numberOfNodes; m++) { // // Is this node assigned ? // if (assigned[m]) { // // Get this node's neighbors // std::vector neighbors; topologyHelper->getNodeNeighbors(m, neighbors); for (unsigned int j = 0; j < neighbors.size(); j++) { const int neighbor = neighbors[j]; // // Is neighbor unassigned ? // if (assigned[neighbor] == false) { float sum = 0.0; int cnt = 0; // // Get this neighbor's neighbors // std::vector neighbors2; topologyHelper->getNodeNeighbors(neighbor, neighbors2); for (unsigned int n = 0; n < neighbors2.size(); n++) { // // Is the neighbor's neighbor assigned ? // const int neighbor2 = neighbors2[n]; if (assigned[neighbor2]) { sum += activity[neighbor2]; cnt++; } } // // Set this neighbors activity, if any from its neighbors // if (cnt > 0) { activity[neighbor] = sum/cnt; assignedToo[neighbor] = true; } } } } } for (int mm = 0; mm < numberOfNodes; mm++) { assigned[mm] = assignedToo[mm]; } } } // // Update the metric file with the activity // for (int mm = 0; mm < numberOfNodes; mm++) { metricFile->setValue(mm, dataFileColumnNumber, activity[mm]); } delete[] assigned; delete[] assignedToo; delete[] activity; } /** * Get the valid subvolume for neighbor mapping algorithms. * Returns true if the neighbors subvolume is valid (within the volume) */ bool BrainModelVolumeToSurfaceMapper::getNeighborsSubVolume(const float xyz[3], int& iMin, int& iMax, int& jMin, int& jMax, int& kMin, int& kMax, const float neighborsCubeSize) const { int ijk[3]; if (volumeFile->convertCoordinatesToVoxelIJK(xyz, ijk) == false) { return false; } // // Half cube // const float halfCubeSize = neighborsCubeSize * 0.5; // // Min corner // const float minCorner[3] = { xyz[0] - halfCubeSize, xyz[1] - halfCubeSize, xyz[2] - halfCubeSize }; int ijkMin[3]; volumeFile->convertCoordinatesToVoxelIJK(minCorner, ijkMin); // // Max corner // const float maxCorner[3] = { xyz[0] + halfCubeSize, xyz[1] + halfCubeSize, xyz[2] + halfCubeSize }; int ijkMax[3]; volumeFile->convertCoordinatesToVoxelIJK(maxCorner, ijkMax); // // Limit dimensions // int dim[3]; volumeFile->getDimensions(dim); for (int i = 0; i < 3; i++) { ijkMin[i] = std::max(ijkMin[i], 0); ijkMax[i] = std::min(ijkMax[i], dim[i] - 1); } iMin = ijkMin[0]; jMin = ijkMin[1]; kMin = ijkMin[2]; iMax = ijkMax[0]; jMax = ijkMax[1]; kMax = ijkMax[2]; return true; } /** * Get the valid subvolume for neighbor mapping algorithms. * Returns true if the neighbors subvolume is valid (within the volume) * bool BrainModelVolumeToSurfaceMapper::getNeighborsSubVolume(const float xyz[3], int& iMin, int& iMax, int& jMin, int& jMax, int& kMin, int& kMax, const float neighborsCubeSize) const { // // See where the node is located inside the volume // int ijk[3]; float pcoords[3]; if (volumeFile->convertCoordinatesToVoxelIJK(xyz, ijk, pcoords)) { // // Default to the voxel containing the node // iMin = ijk[0]; iMax = ijk[0]; jMin = ijk[1]; jMax = ijk[1]; kMin = ijk[2]; kMax = ijk[2]; if (neighborsCubeSize > 0.0) { // // half of the neighbor cube // const float halfCube = neighborsCubeSize * 0.5; // // maximum voxel indices // const int maxDimI = volumeDimensions[0] - 1; const int maxDimJ = volumeDimensions[1] - 1; const int maxDimK = volumeDimensions[2] - 1; // // Half voxel sizes // //const float halfVoxelI = volumeVoxelSize[0] * 0.5; //const float halfVoxelJ = volumeVoxelSize[1] * 0.5; //const float halfVoxelK = volumeVoxelSize[2] * 0.5; // // Look for voxels in positive X // const float maxX = xyz[0] + halfCube; for (int i = ijk[0] + 1; i < maxDimI; i++) { float coord[3]; volumeFile->getVoxelCoordinate(i, ijk[1], ijk[2], coord); const float x = coord[0]; //const float x = i * volumeVoxelSize[0] + volumeOrigin[0] + halfVoxelI; if (x <= maxX) { iMax = i; } else { break; } } // // Look for voxels in negative X // const float minX = xyz[0] - halfCube; for (int i = ijk[0] - 1; i >= 0; i--) { float coord[3]; volumeFile->getVoxelCoordinate(i, ijk[1], ijk[2], coord); const float x = coord[0]; //const float x = i * volumeVoxelSize[0] + volumeOrigin[0] + halfVoxelI; if (x >= minX) { iMin = i; } else { break; } } // // Look for voxels in positive Y // const float maxY = xyz[1] + halfCube; for (int j = ijk[1] + 1; j < maxDimJ; j++) { float coord[3]; volumeFile->getVoxelCoordinate(ijk[0], j, ijk[2], coord); const float y = coord[1]; //const float y = j * volumeVoxelSize[1] + volumeOrigin[1] + halfVoxelJ; if (y <= maxY) { jMax = j; } else { break; } } // // Look for voxels in negative Y // const float minY = xyz[1] - halfCube; for (int j = ijk[1] - 1; j >= 0; j--) { float coord[3]; volumeFile->getVoxelCoordinate(ijk[0], j, ijk[2], coord); const float y = coord[1]; //const float y = j * volumeVoxelSize[1] + volumeOrigin[1] + halfVoxelJ; if (y >= minY) { jMin = j; } else { break; } } // // Look for voxels in positive Z // const float maxZ = xyz[2] + halfCube; for (int k = ijk[2] + 1; k < maxDimK; k++) { float coord[3]; volumeFile->getVoxelCoordinate(ijk[0], ijk[1], k, coord); const float z = coord[2]; //const float z = k * volumeVoxelSize[2] + volumeOrigin[2] + halfVoxelK; if (z <= maxZ) { kMax = k; } else { break; } } // // Look for voxels in negative Z // const float minZ = xyz[2] - halfCube; for (int k = ijk[2] - 1; k >= 0; k--) { float coord[3]; volumeFile->getVoxelCoordinate(ijk[0], ijk[1], k, coord); const float z = coord[2]; //const float z = k * volumeVoxelSize[2] + volumeOrigin[2] + halfVoxelK; if (z >= minZ) { kMin = k; } else { break; } } } return true; } return false; } */ /** * Run the Paint Enclosing Voxel algorithm */ void BrainModelVolumeToSurfaceMapper::algorithmPaintEnclosingVoxel(const float* allCoords) { const int numPaintIndices = static_cast(paintVolumeIndexToPaintFileNameIndex.size()); for (int i = 0; i < numberOfNodes; i++) { float value = 0.0; if (topologyHelper->getNodeHasNeighbors(i)) { int ijk[3]; float pcoords[3]; if (volumeFile->convertCoordinatesToVoxelIJK((float*)&allCoords[i*3], ijk, pcoords)) { value = volumeFile->getVoxel(ijk, 0); } } // // Convert the paint volume name index to a paint file name index // if the index is out of range a name is created for it by the // method named addPaintNamesForIndicesWithoutNames() // int paintIndex = static_cast(value); if (paintIndex < 0) { paintIndex = paintQuestionNameIndex; } else if (paintIndex < numPaintIndices) { paintIndex = paintVolumeIndexToPaintFileNameIndex[paintIndex]; } paintFile->setPaint(i, dataFileColumnNumber, paintIndex); } } /** * add paint names for paint indices without names. */ void BrainModelVolumeToSurfaceMapper::addPaintNamesForIndicesWithoutNames() { // // Find maximum paint index // const int numNodes = paintFile->getNumberOfNodes(); const int numCols = paintFile->getNumberOfColumns(); int maximumPaintIndex = -1; for (int i = 0; i < numNodes; i++) { for (int j = 0; j < numCols; j++) { maximumPaintIndex = std::max(paintFile->getPaint(i, j), maximumPaintIndex); } } // // Add paint names as needed // const int numPaintNames = paintFile->getNumberOfPaintNames(); if (maximumPaintIndex >= numPaintNames) { for (int i = numPaintNames; i <= maximumPaintIndex; i++) { paintFile->addPaintName("Unknown_name_" + QString::number(i)); } } } /* * Determine the gaussian for a node * Inputs: * nodeXYZ is the position of the node. * nodeNormal is the normal vector (magnitude = 1.0) for the node. * voxelXYZ is the position of the voxel (probably should be the center of the voxel. * voxelValue is the voxel whose metricSum and weightSum are being determined * void BrainModelVolumeToSurfaceMapper::gaussian(const float nodeXYZ[3], const float nodeNormal[3], const float voxelXYZ[3], const float voxelValue, float& metricSum, float& weightSum) const { // // "DistanceVector" is the offset vector of a voxel from the origin of the gaussian. // const float distanceVector[3] = { voxelXYZ[0] - nodeXYZ[0], voxelXYZ[1] - nodeXYZ[1], voxelXYZ[2] - nodeXYZ[2] }; // // "dNorm" is"distanceVector" projected onto the normal. // See "Computer Graphics" 2nd ed pages 1096-1097 // // nodeNormal // /|\ x // | // | dTang // ------# # = voxelXYZ // d || / // N || / // o || / distanceVector // r || / // m ||/ // * * = nodeXYZ // const float dNorm = MathUtilities::dotProduct((float*)nodeNormal, (float*)distanceVector); // // See if the voxel of interest is within the allowable distances along the normal vector. // float Wnorm = 0.0; if ((dNorm > -gaussianNormBelowCutoff) && (dNorm < gaussianNormAboveCutoff)) { // // Wnorm is the weighting for the distance along the normal vector. // The weighting is inversely related to the distance from the node. // Wnorm = exp (-(dNorm*dNorm)/(gaussianSigmaNorm*gaussianSigmaNorm)); } if (Wnorm > 0.0) { // // Tang is the distance vector components from the voxel // to the nearest point on infinitely long normal vector. // float Tang[3]; for (int i = 0; i < 3; i++) { Tang[i] = distanceVector[i] - dNorm*nodeNormal[i]; } // // dTang is the distance from the end of the voxel to the closest // point on the infinitely long normal vector. // const float dTang = std::sqrt(Tang[0]*Tang[0] + Tang[1]*Tang[1] + Tang[2]*Tang[2]); // // See if voxel distance tangentially is within the limits. // float Wtang = 0.0; if (dTang < gaussianTangCutoff) { // // Wtang is the weighting for the distance orthogonal to the // normal vector. The weighting is inversely related to the // distance from the origin. // Wtang = exp (-((dTang*dTang) / (gaussianSigmaTang * gaussianSigmaTang))); } if (Wtang > 0.0) { // // Combine the weights and update the metric and weight sums. // const float weight = Wnorm * Wtang; metricSum += voxelValue * weight; weightSum += weight; } } } */ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeToSurfaceConverter.h0000664000175000017500000000705511572067322026775 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __BRAIN_MODEL_VOLUME_TO_SURFACE_CONVERTER_H__ #define __BRAIN_MODEL_VOLUME_TO_SURFACE_CONVERTER_H__ #include "BrainModelAlgorithm.h" class VolumeFile; /// Class that converts a segmentation volume to a surface class BrainModelVolumeToSurfaceConverter : public BrainModelAlgorithm { public: /// reconstruction mode enum RECONSTRUCTION_MODE { /// generate a brain model surface like SureFit RECONSTRUCTION_MODE_SUREFIT_SURFACE, /// generate a brain model surface like SureFit with no polygon reduction RECONSTRUCTION_MODE_SUREFIT_SURFACE_MAXIMUM_POLYGONS, /// generate a VTK model surface RECONSTRUCTION_MODE_VTK_MODEL, /// generate a VTK model surface with no polygon reduction RECONSTRUCTION_MODE_VTK_MODEL_MAXIMUM_POLYGONS, /// generate a model that creates a point for every voxel RECONSTRUCTION_MODE_SOLID_STRUCTURE }; /// Constructor BrainModelVolumeToSurfaceConverter(BrainSet* bs, const VolumeFile* segmentationVolumeFileIn, const RECONSTRUCTION_MODE reconstructionModeIn, const bool rightHemisphereFlagIn, const bool leftHemisphereFlagIn, const bool createHypersmoothSurfaceFlagIn = false); /// Destructor ~BrainModelVolumeToSurfaceConverter(); /// execute the algorithm virtual void execute() throw (BrainModelAlgorithmException); private: /// generate the surefit surface void generateSureFitSurface(const bool maxPolygonsFlag) throw (BrainModelAlgorithmException); /// generate the surefit surface pro void generateSureFitSurfaceOld() throw (BrainModelAlgorithmException); /// generate the surface void generateSurface() throw (BrainModelAlgorithmException); /// generate a vtk model void generateVtkModel(const bool maxPolygonsFlag) throw (BrainModelAlgorithmException); /// generate a solid structure model void generateSolidStructure() throw (BrainModelAlgorithmException); /// the segmentation volume for converting to a surface VolumeFile* segmentationVolumeFile; /// right hemisphere flag bool rightHemisphereFlag; /// left hemisphere flag bool leftHemisphereFlag; /// the reconstruction mode RECONSTRUCTION_MODE reconstructionMode; /// create hypersmooth flag bool createHypersmoothSurfaceFlag; }; #endif // __BRAIN_MODEL_VOLUME_TO_SURFACE_CONVERTER_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeToSurfaceConverter.cxx0000664000175000017500000005505311572067322027351 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "vtkCellArray.h" #include "vtkCleanPolyData.h" #include "vtkClipPolyData.h" #include "vtkDecimatePro.h" #include "vtkImageGaussianSmooth.h" #include "vtkImageShrink3D.h" #include "vtkMarchingCubes.h" #include "vtkPlane.h" #include "vtkPolyDataNormals.h" #include "vtkPolyDataWriter.h" #include "vtkSmoothPolyDataFilter.h" #include "vtkStructuredPoints.h" #include "vtkTriangleFilter.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceNodeColoring.h" #include "BrainModelVolumeToSurfaceConverter.h" #include "BrainSet.h" #include "DebugControl.h" #include "VolumeFile.h" #include "VtkModelFile.h" /** * Constructor */ BrainModelVolumeToSurfaceConverter::BrainModelVolumeToSurfaceConverter( BrainSet* bs, const VolumeFile* segmentationVolumeFileIn, const RECONSTRUCTION_MODE reconstructionModeIn, const bool rightHemisphereFlagIn, const bool leftHemisphereFlagIn, const bool createHypersmoothSurfaceFlagIn) : BrainModelAlgorithm(bs) { segmentationVolumeFile = new VolumeFile(*segmentationVolumeFileIn); reconstructionMode = reconstructionModeIn; rightHemisphereFlag = rightHemisphereFlagIn; leftHemisphereFlag = leftHemisphereFlagIn; createHypersmoothSurfaceFlag = createHypersmoothSurfaceFlagIn; } /** * Destructor */ BrainModelVolumeToSurfaceConverter::~BrainModelVolumeToSurfaceConverter() { if (segmentationVolumeFile != NULL) { delete segmentationVolumeFile; segmentationVolumeFile = NULL; } } /** * Execute the algorithm. */ void BrainModelVolumeToSurfaceConverter::execute() throw (BrainModelAlgorithmException) { // // If there are any voxels around the edges that are part of the segmentation // they will result in a hole in the surface. So pad the volume by adding one // slice around all edges to prevent holes. // const int padAroundEdges[6] = { 1, 1, 1, 1, 1, 1 }; float origin[3]; segmentationVolumeFile->getOrigin(origin); if (DebugControl::getDebugOn()) { std::cout << "Origin before padding: " << origin[0] << " " << origin[1] << " " << origin[2] << std::endl; } // // Enlarge "this" volume // int dim[3]; segmentationVolumeFile->getDimensions(dim); const int dimMod[6] = { -padAroundEdges[0], dim[0] + padAroundEdges[1], -padAroundEdges[2], dim[1] + padAroundEdges[3], -padAroundEdges[4], dim[2] + padAroundEdges[5], }; segmentationVolumeFile->resize(dimMod); //segmentationVolumeFile->padSegmentation(padAroundEdges, false); segmentationVolumeFile->getOrigin(origin); if (DebugControl::getDebugOn()) { std::cout << "Origin after padding: " << origin[0] << " " << origin[1] << " " << origin[2] << std::endl; } int indices[6]; float bounds[6]; segmentationVolumeFile->getNonZeroVoxelExtent(indices, bounds); if (DebugControl::getDebugOn()) { std::cout << "Extent after padding: " << "(" << bounds[0] << ", " << bounds[1] << ") " << "(" << bounds[2] << ", " << bounds[3] << ") " << "(" << bounds[4] << ", " << bounds[5] << ") " << std::endl; } switch (reconstructionMode) { case RECONSTRUCTION_MODE_SUREFIT_SURFACE: generateSureFitSurface(false); break; case RECONSTRUCTION_MODE_SUREFIT_SURFACE_MAXIMUM_POLYGONS: generateSureFitSurface(true); break; case RECONSTRUCTION_MODE_VTK_MODEL: generateVtkModel(false); break; case RECONSTRUCTION_MODE_VTK_MODEL_MAXIMUM_POLYGONS: generateVtkModel(true); break; case RECONSTRUCTION_MODE_SOLID_STRUCTURE: generateSolidStructure(); break; } } /** * generate a solid structure model. */ void BrainModelVolumeToSurfaceConverter::generateSolidStructure() throw (BrainModelAlgorithmException) { // // Reconstruct as a VTK model // generateVtkModel(false); // // Find the reconstructed vtk model // const int numVtkModels = brainSet->getNumberOfVtkModelFiles(); if (numVtkModels <= 0) { throw BrainModelAlgorithmException("No VTK models were reconstructed."); } VtkModelFile* vtkModel = brainSet->getVtkModelFile(numVtkModels - 1); // // Copy the segmentation // VolumeFile segmentation(*segmentationVolumeFile); // // Erode the segmentation volume to remove the outer layer of voxels // segmentation.doVolMorphOps(0, 1); // // Get the dimensions of the volume // int dim[3]; segmentation.getDimensions(dim); // // Create a point for each non-zero voxel // for (int i = 0; i < dim[0]; i++) { for (int j = 0; j < dim[1]; j++) { for (int k = 0; k < dim[2]; k++) { if (segmentation.getVoxel(i, j, k, 0) != 0.0) { float xyz[3]; segmentation.getVoxelCoordinate(i, j, k, xyz); vtkModel->addCoordinate(xyz); } } } } } /** * Generate surface. */ void BrainModelVolumeToSurfaceConverter::generateSureFitSurface(const bool maxPolygonsFlag) throw (BrainModelAlgorithmException) { // // Convert to structured points // vtkStructuredPoints* sp = segmentationVolumeFile->convertToVtkStructuredPoints(); double bounds[6]; sp->GetBounds(bounds); if (DebugControl::getDebugOn()) { std::cout << "Segmentation input volume bounds: " << bounds[0] << " " << bounds[1] << " " << bounds[2] << " " << bounds[3] << " " << bounds[4] << " " << bounds[5] << std::endl; } // // Shrinker - does this actually do anything ? // vtkImageShrink3D* shrinker = vtkImageShrink3D::New(); shrinker->SetInput(sp); shrinker->SetShrinkFactors(1, 1, 1); shrinker->AveragingOn(); // // Gaussian smooth the volume // vtkImageGaussianSmooth* gaussian = vtkImageGaussianSmooth::New(); gaussian->SetDimensionality(3); gaussian->SetStandardDeviation(0); gaussian->SetInput(shrinker->GetOutput()); gaussian->Update(); vtkImageData* gaussOut = gaussian->GetOutput(); gaussOut->GetBounds(bounds); if (DebugControl::getDebugOn()) { std::cout << "Segmentation shrink/gauss volume bounds: " << bounds[0] << " " << bounds[1] << " " << bounds[2] << " " << bounds[3] << " " << bounds[4] << " " << bounds[5] << std::endl; } // // Marching cubes converts volume to a surface // vtkMarchingCubes* mc = vtkMarchingCubes::New(); mc->SetInput(gaussian->GetOutput()); //mc->SetValue(0, 511.5); mc->SetValue(0, 127.5); mc->ComputeScalarsOff(); mc->ComputeGradientsOff(); mc->ComputeNormalsOff(); // // Clean up surface created by marching cubes // vtkCleanPolyData* clean = vtkCleanPolyData::New(); clean->SetInput(mc->GetOutput()); // // Make sure mesh is only triangles // vtkTriangleFilter *triangleFilter = vtkTriangleFilter::New(); triangleFilter->SetInput(clean->GetOutput()); if (DebugControl::getDebugOn()) { triangleFilter->Update(); vtkPolyDataWriter* writer = vtkPolyDataWriter::New(); writer->SetInput(triangleFilter->GetOutput()); writer->SetFileName("surface_undecimated.vtk"); writer->Write(); writer->Delete(); } triangleFilter->Update(); vtkPolyData* boundsPolyData = triangleFilter->GetOutput(); boundsPolyData->GetBounds(bounds); if (DebugControl::getDebugOn()) { std::cout << "Surface bounds: " << bounds[0] << " " << bounds[1] << " " << bounds[2] << " " << bounds[3] << " " << bounds[4] << " " << bounds[5] << std::endl; } // // See if the surface should be decimated // vtkDecimatePro* decimater = NULL; if (maxPolygonsFlag == false) { decimater = vtkDecimatePro::New(); if (DebugControl::getDebugOn()) { decimater->DebugOn(); } double errorVal = 0.001; //if (maxPolygonsFlag) { // errorVal = 0.0; //} decimater->SetInput(triangleFilter->GetOutput()); decimater->SetTargetReduction(0.90); decimater->PreserveTopologyOn(); decimater->SetFeatureAngle(30.0); //45.0); //1); // orig == 30 decimater->SplittingOff(); decimater->PreSplitMeshOff(); decimater->SetMaximumError(errorVal); decimater->BoundaryVertexDeletionOff(); decimater->SetDegree(25); decimater->AccumulateErrorOn(); decimater->SetAbsoluteError(errorVal); decimater->SetErrorIsAbsolute(1); if (DebugControl::getDebugOn()) { decimater->PrintSelf(std::cout, static_cast(3)); decimater->Update(); decimater->PrintSelf(std::cout, static_cast(3)); vtkPolyDataWriter* writer = vtkPolyDataWriter::New(); writer->SetInput(decimater->GetOutput()); writer->SetFileName("surface_decimated.vtk"); writer->Write(); writer->Delete(); } } // // Clean again // vtkCleanPolyData* clean2 = vtkCleanPolyData::New(); if (decimater != NULL) { clean2->SetInput(decimater->GetOutput()); } else { clean2->SetInput(triangleFilter->GetOutput()); } // // Since reconstruction successful clear out any existing surfaces // brainSet->deleteAllBrainModelSurfaces(); // // Compute normals on the surface // vtkPolyDataNormals* rawNormals = vtkPolyDataNormals::New(); rawNormals->SetInput(clean2->GetOutput()); rawNormals->SplittingOff(); rawNormals->ConsistencyOn(); rawNormals->ComputePointNormalsOn(); rawNormals->NonManifoldTraversalOn(); // // Force vtk to execute // rawNormals->Update(); // // Get a pointer to the poly data // vtkPolyData* rawPolyDataSurface = rawNormals->GetOutput(); if (DebugControl::getDebugOn()) { vtkPolyDataWriter* writer = vtkPolyDataWriter::New(); writer->SetInput(rawPolyDataSurface); writer->SetFileName("raw.vtk"); writer->Write(); writer->Delete(); } // // Convert to vtk file to a brain model surface // try { brainSet->importVtkTypeFileHelper("raw.vtk", rawPolyDataSurface, true, true, false, BrainModelSurface::SURFACE_TYPE_FIDUCIAL, TopologyFile::TOPOLOGY_TYPE_CLOSED); } catch (FileException& e) { throw BrainModelAlgorithmException(e.whatQString()); } // // Use volume orientation for surface's orientation // VolumeFile::ORIENTATION orient[3]; segmentationVolumeFile->getOrientation(orient); QString orientString; for (int io = 0; io < 3; io++) { switch (orient[io]) { case VolumeFile::ORIENTATION_UNKNOWN: orientString.append("U"); break; case VolumeFile::ORIENTATION_RIGHT_TO_LEFT: orientString.append("R"); break; case VolumeFile::ORIENTATION_LEFT_TO_RIGHT: orientString.append("L"); break; case VolumeFile::ORIENTATION_POSTERIOR_TO_ANTERIOR: orientString.append("P"); break; case VolumeFile::ORIENTATION_ANTERIOR_TO_POSTERIOR: orientString.append("A"); break; case VolumeFile::ORIENTATION_INFERIOR_TO_SUPERIOR: orientString.append("I"); break; case VolumeFile::ORIENTATION_SUPERIOR_TO_INFERIOR: orientString.append("S"); break; } } // // Newest brain model should be the surface // BrainModelSurface* rawBms = brainSet->getBrainModelSurface(brainSet->getNumberOfBrainModels() - 1); if (rawBms != NULL) { rawBms->orientNormalsOut(); if (rightHemisphereFlag && leftHemisphereFlag) { rawBms->setStructure(Structure::STRUCTURE_TYPE_CEREBELLUM); } else if (rightHemisphereFlag) { rawBms->setStructure(Structure::STRUCTURE_TYPE_CORTEX_RIGHT); } else if (leftHemisphereFlag) { rawBms->setStructure(Structure::STRUCTURE_TYPE_CORTEX_LEFT); } rawBms->setSurfaceType(BrainModelSurface::SURFACE_TYPE_RAW); rawBms->appendToCoordinateFileComment("Generated from reconstruction of segmentation: "); rawBms->appendToCoordinateFileComment(segmentationVolumeFile->getFileName()); rawBms->appendToCoordinateFileComment("\n"); rawBms->appendToTopologyFileComment("Generated from reconstruction of segmentation: "); rawBms->appendToTopologyFileComment(segmentationVolumeFile->getFileName()); rawBms->appendToTopologyFileComment("\n"); TopologyFile* tf = rawBms->getTopologyFile(); if (tf != NULL) { const int numIslands = tf->disconnectIslands(); if (numIslands > 0) { rawBms->moveDisconnectedNodesToOrigin(); } if (DebugControl::getDebugOn()) { std::cout << numIslands << " islands were in reconstructed surface." << std::endl; } tf->setTopologyType(TopologyFile::TOPOLOGY_TYPE_CLOSED); } // // Default surface orientation to that of the volume // CoordinateFile* cf = rawBms->getCoordinateFile(); cf->setHeaderTag(AbstractFile::headerTagOrientation, orientString); // // Set the stereotaxic space in the coord frame id // cf->setHeaderTag(AbstractFile::headerTagCoordFrameID, brainSet->getStereotaxicSpace().getName()); } // // Smooth the surface // vtkSmoothPolyDataFilter* smooth = vtkSmoothPolyDataFilter::New(); smooth->SetInput(rawPolyDataSurface); smooth->SetNumberOfIterations(10); smooth->SetRelaxationFactor(0.2); smooth->SetFeatureAngle(180.0); smooth->FeatureEdgeSmoothingOff(); smooth->BoundarySmoothingOff(); smooth->SetConvergence(0); // // Compute normals on the surface // vtkPolyDataNormals* normals = vtkPolyDataNormals::New(); normals->SetInput(smooth->GetOutput()); normals->SplittingOff(); normals->ConsistencyOn(); normals->ComputePointNormalsOn(); normals->NonManifoldTraversalOn(); // // Force vtk to execute // normals->Update(); // // Get a pointer to the poly data // vtkPolyData* polyDataSurface = normals->GetOutput(); // // Test to clip a surface DO NOT USE THIS AS IT CHANGES TOPOLOGY // bool testFlag = false; if (testFlag) { vtkPlane* plane = vtkPlane::New(); plane->SetOrigin(37.0, -42.0, 59.0); plane->SetNormal(0.0, -1.0, 0.0); vtkClipPolyData* clipper = vtkClipPolyData::New(); clipper->SetClipFunction(plane); clipper->SetInput(polyDataSurface); clipper->Update(); vtkPolyDataWriter* writer = vtkPolyDataWriter::New(); writer->SetInput(clipper->GetOutput()); writer->SetFileName("surface_cut.vtk"); writer->Write(); writer->Delete(); clipper->Delete(); plane->Delete(); } // // Convert to vtk file to a brain model surface // try { brainSet->importVtkTypeFileHelper("fiducial.vtk", polyDataSurface, true, false, false, BrainModelSurface::SURFACE_TYPE_FIDUCIAL, TopologyFile::TOPOLOGY_TYPE_CLOSED); } catch (FileException& e) { throw BrainModelAlgorithmException(e.whatQString()); } // // Newest brain model should be the surface // BrainModelSurface* bms = brainSet->getBrainModelSurface(brainSet->getNumberOfBrainModels() - 1); if (bms != NULL) { bms->orientNormalsOut(); if (rightHemisphereFlag && leftHemisphereFlag) { bms->setStructure(Structure::STRUCTURE_TYPE_CEREBELLUM); } else if (rightHemisphereFlag) { bms->setStructure(Structure::STRUCTURE_TYPE_CORTEX_RIGHT); } else if (leftHemisphereFlag) { bms->setStructure(Structure::STRUCTURE_TYPE_CORTEX_LEFT); } bms->setSurfaceType(BrainModelSurface::SURFACE_TYPE_FIDUCIAL); bms->appendToCoordinateFileComment("Generated from reconstruction of segmentation: "); bms->appendToCoordinateFileComment(segmentationVolumeFile->getFileName()); bms->appendToCoordinateFileComment("\n"); // // Default surface orientation to that of the volume // CoordinateFile* cf = bms->getCoordinateFile(); cf->setHeaderTag(AbstractFile::headerTagOrientation, orientString); // // Set the stereotaxic space in the coord frame id // cf->setHeaderTag(AbstractFile::headerTagCoordFrameID, brainSet->getStereotaxicSpace().getName()); // // Does user want a hypersmoothed surface created // if (createHypersmoothSurfaceFlag) { bms->createInflatedAndEllipsoidFromFiducial(true, false, false, false, false, false, true, 1.0, NULL); /* // // Create the hypersmoothed surface // BrainModelSurface* hypersmoothSurface = new BrainModelSurface(*bms); hypersmoothSurface->arealSmoothing(1.0, 50, 0); hypersmoothSurface->setSurfaceType(BrainModelSurface::SURFACE_TYPE_INFLATED); brainSet->addBrainModel(hypersmoothSurface); */ } } brainSet->postSpecFileReadInitializations(); // // Assign colors to the surface // //brainSet->getNodeColoring()->assignColors(); rawNormals->Delete(); normals->Delete(); smooth->Delete(); if (decimater != NULL) { decimater->Delete(); } triangleFilter->Delete(); clean->Delete(); mc->Delete(); sp->Delete(); } /** * generate a vtk model. */ void BrainModelVolumeToSurfaceConverter::generateVtkModel(const bool maxPolygonsFlag) throw (BrainModelAlgorithmException) { // // Convert to structured points // vtkStructuredPoints* sp = segmentationVolumeFile->convertToVtkStructuredPoints(); // // Shrinker - does this actually do anything ? // vtkImageShrink3D* shrinker = vtkImageShrink3D::New(); shrinker->SetInput(sp); shrinker->SetShrinkFactors(1, 1, 1); shrinker->AveragingOn(); // // Gaussian smooth the volume // vtkImageGaussianSmooth* gaussian = vtkImageGaussianSmooth::New(); gaussian->SetDimensionality(3); gaussian->SetStandardDeviation(0); gaussian->SetInput(shrinker->GetOutput()); // // Marching cubes converts volume to a surface // vtkMarchingCubes* mc = vtkMarchingCubes::New(); mc->SetInput(gaussian->GetOutput()); //mc->SetValue(0, 511.5); mc->SetValue(0, 127.5); mc->ComputeScalarsOff(); mc->ComputeGradientsOff(); mc->ComputeNormalsOff(); // // Clean up surface created by marching cubes // vtkCleanPolyData* clean = vtkCleanPolyData::New(); clean->SetInput(mc->GetOutput()); // // Make sure mesh is only triangles // vtkTriangleFilter *triangleFilter = vtkTriangleFilter::New(); triangleFilter->SetInput(clean->GetOutput()); // // See if the surface should be decimated // vtkDecimatePro* decimater = NULL; if (maxPolygonsFlag == false) { decimater = vtkDecimatePro::New(); if (DebugControl::getDebugOn()) { decimater->DebugOn(); } const double errorVal = 0.001; decimater->SetInput(triangleFilter->GetOutput()); decimater->SetTargetReduction(0.90); decimater->PreserveTopologyOn(); decimater->SetFeatureAngle(30); decimater->SplittingOff(); decimater->PreSplitMeshOff(); decimater->SetMaximumError(errorVal); decimater->BoundaryVertexDeletionOff(); decimater->SetDegree(25); decimater->AccumulateErrorOn(); decimater->SetAbsoluteError(errorVal); decimater->SetErrorIsAbsolute(1); } // // Clean again // vtkCleanPolyData* clean2 = vtkCleanPolyData::New(); if (decimater != NULL) { clean2->SetInput(decimater->GetOutput()); } else { clean2->SetInput(triangleFilter->GetOutput()); } // // Smooth the surface // vtkSmoothPolyDataFilter* smooth = vtkSmoothPolyDataFilter::New(); smooth->SetInput(clean2->GetOutput()); smooth->SetNumberOfIterations(10); smooth->SetRelaxationFactor(0.2); smooth->SetFeatureAngle(180.0); smooth->FeatureEdgeSmoothingOff(); smooth->BoundarySmoothingOff(); smooth->SetConvergence(0); // // Compute normals on the surface // vtkPolyDataNormals* rawNormals = vtkPolyDataNormals::New(); rawNormals->SetInput(smooth->GetOutput()); rawNormals->SplittingOff(); rawNormals->ConsistencyOn(); rawNormals->ComputePointNormalsOn(); rawNormals->NonManifoldTraversalOn(); // // Force vtk to execute // rawNormals->Update(); // // Get a pointer to the poly data // vtkPolyData* rawPolyDataSurface = rawNormals->GetOutput(); // // Add vtk model file to brain set // VtkModelFile* vtkModelFile = new VtkModelFile(rawPolyDataSurface); brainSet->addVtkModelFile(vtkModelFile); vtkModelFile->setModified(); rawNormals->Delete(); smooth->Delete(); clean2->Delete(); if (decimater != NULL) { decimater->Delete(); } triangleFilter->Delete(); clean->Delete(); mc->Delete(); sp->Delete(); } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeThresholdSegmentation.h0000664000175000017500000000351011572067322027514 0ustar michaelmichael#ifndef __BRAIN_MODEL_VOLUME_THRESHOLD_SEGMENTATION_H__ #define __BRAIN_MODEL_VOLUME_THRESHOLD_SEGMENTATION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelAlgorithm.h" class VolumeFile; /// class for performing threshold segmentation class BrainModelVolumeThresholdSegmentation : public BrainModelAlgorithm { public: // Constructor BrainModelVolumeThresholdSegmentation(BrainSet* bs, VolumeFile* anatomyVolumeIn, const float thresholdIn[2]); // Destructor ~BrainModelVolumeThresholdSegmentation(); // execute the algorithm void execute() throw (BrainModelAlgorithmException); protected: /// the anatomy volume VolumeFile* anatomyVolume; /// the threshold to use float threshold[2]; }; #endif // __BRAIN_MODEL_VOLUME_THRESHOLD_SEGMENTATION_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeThresholdSegmentation.cxx0000664000175000017500000000525311572067322030075 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainModelVolumeThresholdSegmentation.h" #include "BrainSet.h" #include "VolumeFile.h" /** * Constructor. */ BrainModelVolumeThresholdSegmentation::BrainModelVolumeThresholdSegmentation(BrainSet* bs, VolumeFile* anatomyVolumeIn, const float thresholdIn[2]) : BrainModelAlgorithm(bs) { anatomyVolume = anatomyVolumeIn; threshold[0] = thresholdIn[0]; threshold[1] = thresholdIn[1]; } /** * Destructor. */ BrainModelVolumeThresholdSegmentation::~BrainModelVolumeThresholdSegmentation() { } /** * execute the algorithm. */ void BrainModelVolumeThresholdSegmentation::execute() throw (BrainModelAlgorithmException) { if (anatomyVolume == NULL) { throw BrainModelAlgorithmException("Anatomy volume is invalid (NULL)."); } // // Create the segmentation volume // VolumeFile* segVol = new VolumeFile(*anatomyVolume); segVol->setVolumeType(VolumeFile::VOLUME_TYPE_SEGMENTATION); // // Set file name and comments // std::ostringstream str; str << "Threshold_" << threshold; segVol->setFileName(str.str().c_str()); segVol->setDescriptiveLabel(""); str.str(""); str << "Thresholded with " << threshold << "\n"; segVol->appendToFileComment(str.str().c_str()); // // Threshold the volume // segVol->dualThresholdVolume(threshold[0], threshold[1]); // // Add volume to the brain set // brainSet->addVolumeFile(VolumeFile::VOLUME_TYPE_SEGMENTATION, segVol, segVol->getFileName(), true, false); } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeTFCE.h0000664000175000017500000000516211572067322023730 0ustar michaelmichael #ifndef __BRAIN_MODEL_VOLUME_TFCE_H__ #define __BRAIN_MODEL_VOLUME_TFCE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelAlgorithm.h" class VolumeFile; /// class for create a functional volume using a probabilistic volume class BrainModelVolumeTFCE : public BrainModelAlgorithm { public: /// Constructor BrainModelVolumeTFCE(BrainSet* bs, VolumeFile* inFuncVolumeIn, VolumeFile* outFuncVolumeIn, const QString& outVolumeNameIn, const QString& outVolumeLabelIn, const int numStepsIn = 50, const float EIn = 0.5f, const float HIn = 2.0f); /// Destructor ~BrainModelVolumeTFCE(); /// execute the algorithm void execute() throw (BrainModelAlgorithmException); ///default parameters static inline const int defaultNumSteps() { return 50; }; static inline const float defaultE() { return 0.5f; }; static inline const float defaultH() { return 2.0f; }; static inline int min(int a, int b) { return (a > b ? b : a); }; static inline int max(int a, int b) { return (a > b ? a : b); }; protected: /// segmentation volume, anatomy input volume VolumeFile* outFuncVolume; VolumeFile* inFuncVolume; /// segmentation volume name QString outVolumeName; /// segmentation volume label QString outVolumeLabel; /// parameter storage float H, E; int numSteps; }; #endif // __BRAIN_MODEL_VOLUME_TFCE_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeTFCE.cxx0000664000175000017500000001466111572067322024307 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelVolume.h" #include "BrainModelVolumeTFCE.h" #include "BrainSet.h" #include "VolumeFile.h" #include /** * Constructor. */ BrainModelVolumeTFCE::BrainModelVolumeTFCE(BrainSet* bs, VolumeFile* inFuncVolumeIn, VolumeFile* outFuncVolumeIn, const QString& outVolumeNameIn, const QString& outVolumeLabelIn, const int numStepsIn, const float EIn, const float HIn) : BrainModelAlgorithm(bs) { inFuncVolume = inFuncVolumeIn; outFuncVolume = outFuncVolumeIn; outVolumeName = outVolumeNameIn; outVolumeLabel = outVolumeLabelIn; numSteps = numStepsIn; E = EIn; H = HIn; } /** * Destructor. */ BrainModelVolumeTFCE::~BrainModelVolumeTFCE() { } /** * execute the algorithm. */ void BrainModelVolumeTFCE::execute() throw (BrainModelAlgorithmException) { // // Verify volumes exist // if (inFuncVolume == NULL) { throw BrainModelAlgorithmException("Invalid input volume."); } if (inFuncVolume->getNumberOfComponentsPerVoxel() != 1) { throw BrainModelAlgorithmException("Volume has multiple components."); } bool createdOutVolume = false; if (outFuncVolume == NULL) { outFuncVolume = new VolumeFile(*inFuncVolume); createdOutVolume = true; } outFuncVolume->setFileName(outVolumeName); outFuncVolume->setDescriptiveLabel(outVolumeLabel); // // Verify volumes have same dimensions // int aDim[3], sDim[3]; inFuncVolume->getDimensions(aDim); outFuncVolume->getDimensions(sDim); for (int i = 0; i < 3; i++) { if (aDim[i] != sDim[i]) { throw BrainModelAlgorithmException( "Input and Output Volumes are of different dimensions."); } } int i, j, k, ti, tj, tk, maxi, maxj, maxk, mini, minj, mink, temp, growingInd, growingCur, numVoxels = aDim[0] * aDim[1] * aDim[2]; float fmax = 0.0f, thresh, valToAdd; float* voxels = inFuncVolume->getVoxelData(), *outData = outFuncVolume->getVoxelData(); bool* flagUsed = new bool[numVoxels];//bitwise saves little space, due to other arrays, so make it simple short* growing = new short[numVoxels * 3];//excessive array for storing clusters, just in case (and in case indices range outside 0-255) for (temp = 0; temp < numVoxels; ++temp) { if (voxels[temp] > fmax) fmax = voxels[temp]; outData[temp] = 0.0f; } for (thresh = fmax / numSteps / 2.0; thresh < fmax; thresh += fmax / numSteps) { for (temp = 0; temp < numVoxels; ++temp) flagUsed[temp] = false; for (k = 0; k < aDim[2]; ++k) { for (j = 0; j < aDim[1]; ++j) { for (i = 0; i < aDim[0]; ++i) { temp = inFuncVolume->getVoxelDataIndex(i, j, k); if (!flagUsed[temp] && voxels[temp] >= thresh) { flagUsed[temp] = true; growingInd = 3; growingCur = 0; growing[0] = i; growing[1] = j; growing[2] = k; while (growingCur < growingInd) { maxi = min(aDim[0], growing[growingCur] + 2); maxj = min(aDim[1], growing[growingCur + 1] + 2); maxk = min(aDim[2], growing[growingCur + 2] + 2); mini = max(0, growing[growingCur] - 1); minj = max(0, growing[growingCur + 1] - 1); mink = max(0, growing[growingCur + 2] - 1); for (tk = mink; tk < maxk; ++tk) { for (tj = minj; tj < maxj; ++tj) { for (ti = mini; ti < maxi; ++ti) { temp = inFuncVolume->getVoxelDataIndex(ti, tj, tk); if (!flagUsed[temp] && voxels[temp] >= thresh) { flagUsed[temp] = true; growing[growingInd] = ti; growing[growingInd + 1] = tj; growing[growingInd + 2] = tk; growingInd += 3; } } } } growingCur += 3; } growingCur = 0; valToAdd = std::pow(growingInd / 3.0f, E) * std::pow(thresh, H) * fmax / numSteps;// e(h)^E * h^H * dh //NOTE: integral approximation can be improved using standard weighting techniques, currently uses center of piece method while (growingCur < growingInd) { outData[outFuncVolume->getVoxelDataIndex(growing[growingCur], growing[growingCur + 1], growing[growingCur + 2])] += valToAdd; growingCur += 3; } } } } } } if (createdOutVolume) { brainSet->addVolumeFile(VolumeFile::VOLUME_TYPE_SEGMENTATION, outFuncVolume, outFuncVolume->getFileName(), true, false); } outFuncVolume->setVoxelColoringInvalid(); delete[] flagUsed; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeSureFitSegmentation.h0000664000175000017500000004010311572067322027140 0ustar michaelmichael #ifndef __BRAIN_MODEL_VOLUME_SEGMENTATION_H__ #define __BRAIN_MODEL_VOLUME_SEGMENTATION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelAlgorithm.h" #include "BrainModelSurface.h" #include "SureFitVectorFile.h" #include "VolumeFile.h" class PaintFile; /// class for performing segmentation operations class BrainModelVolumeSureFitSegmentation : public BrainModelAlgorithm { public: /// error correction method enum ERROR_CORRECTION_METHOD { /// No Error Correction ERROR_CORRECTION_METHOD_NONE, /// Graph-Based Error Correction ERROR_CORRECTION_METHOD_GRAPH, /// SureFit Error Correction ERROR_CORRECTION_METHOD_SUREFIT, /// SureFit Error Correction followed by Graph Correction ERROR_CORRECTION_METHOD_SUREFIT_AND_GRAPH, /// Graph Error Correction followed by SureFit Error ERROR_CORRECTION_METHOD_GRAPH_AND_SUREFIT }; /// Constructor BrainModelVolumeSureFitSegmentation(BrainSet* bs, const VolumeFile* anatomyVolumeIn, const VolumeFile* segmentationVolumeIn, const VolumeFile::FILE_READ_WRITE_TYPE typeOfVolumeFilesToWriteIn, const int acIJKIn[3], const int paddingIn[6], const float wmPeakIn, const float gmPeakIn, const float midThreshOverrideIn, const Structure::STRUCTURE_TYPE structureIn, const bool disconnectEyeFlagIn, const bool disconnectHindBrainFlagIn, const bool disconnectHindBrainHiThreshFlagIn, const bool cutCorpusCallosumFlagIn, const bool segmentAnatomyFlagIn, const bool fillVentriclesFlagIn, const ERROR_CORRECTION_METHOD errorCorrectionMethodIn, const bool generateRawAndFidualSurfacesFlagIn, const bool maximumPolygonsFlagIn, const bool generateTopologicallyCorrectFiducialSurfaceFlagIn, const bool generateInflatedSurfaceFlagIn, const bool generateVeryInflatedSurfaceFlagIn, const bool generateEllipsoidSurfaceFlagIn, const bool generateSphericalSurfaceFlagIn, const bool generateCompressedMedialWallSurfaceFlagIn, const bool generateHullSurfaceFlagIn, const bool generateDepthCurvatureGeographyFlagIn, const bool identifyRegisterFlattenLandmarksFlagIn, const bool autoSaveFilesFlagIn); /// Constructor used for identifying sulci only. BrainModelVolumeSureFitSegmentation( BrainSet* bs, const Structure::STRUCTURE_TYPE structureIn, const VolumeFile::FILE_READ_WRITE_TYPE typeOfVolumeFilesToWriteIn, const bool generateHullSurfaceFlagIn); /// Destructor ~BrainModelVolumeSureFitSegmentation(); /// get error correction methods and names static void getErrorCorrectionMethodsAndNames(std::vector& namesOut, std::vector& methodsOut); /// set the volume mask applied prior to inner and outer boundary determination void setVolumeMask(const VolumeFile* volumeMaskIn); /// set white maximum (values larger than this are excluded prior to inner and outer boundary determination void setWhiteMatterMaximum(const float whiteMatterMaximumIn); /// execute the algorithm void execute() throw (BrainModelAlgorithmException); /// execute the algorithm for only identifying sulci void executeIdentifySulci() throw (BrainModelAlgorithmException); /// generate the corpus callosum slice (assumes AC at center) /// estimate white matter peak if invalid static void generateCorpusCallosumSlice(VolumeFile& anatomyVolumeFileIn, VolumeFile& corpusCallosumVolumeFileOut, const Structure& structure, const float grayMatterPeakIn, const float whiteMatterPeakIn, const bool looseMask = false) throw (BrainModelAlgorithmException); protected: /// apply volume mask and white matter maximum void applyVolumeMaskAndWhiteMatterMaximum() throw (BrainModelAlgorithmException); /// disconnect the eye void disconnectEye() throw (BrainModelAlgorithmException); /// disconnect the hind brain void disconnectHindBrain() throw (BrainModelAlgorithmException); /// cut the corpus callossum void cutCorpusCallossum() throw (BrainModelAlgorithmException); /// generate the inner boundary void generateInnerBoundary() throw (BrainModelAlgorithmException); /// generate the outer boundary void generateOuterBoundary() throw (BrainModelAlgorithmException); /// generate the segmentation void generateSegmentation() throw (BrainModelAlgorithmException); /// generate the raw and fiducial surfaces void generateRawAndFiducialSurfaces(VolumeFile* vf) throw (BrainModelAlgorithmException); /// create a fiducial surface that is topologically correct void generateTopologicallyCorrectFiducialSurface(); /// generate the inflated and ellipsoid surfaces void generateInflatedAndEllipsoidSurfaces() throw (BrainModelAlgorithmException); /// fill ventricles void fillVentricles() throw (BrainModelAlgorithmException); /// do graph-based automatic error correction VolumeFile* graphBasedErrorCorrection(VolumeFile* vf); /// do SureFit automatic error correction VolumeFile* sureFitAutomaticErrorCorrection(VolumeFile* vf); /// generate depth, curvature, and geography void generateDepthCurvatureGeography(const VolumeFile* vf); /// generate landmarks borders for flattening and registration void generateRegistrationFlatteningLandmarkBorders() throw (BrainModelAlgorithmException); /// generate default scenes void generateDefaultScenes() throw (BrainModelAlgorithmException); /// get parameters from the parameters file void getParameters() throw (BrainModelAlgorithmException); /// write the volume for debugging void writeDebugVolume(VolumeFile* vf, const QString& name) throw (BrainModelAlgorithmException); /// write the volume for debugging void writeDebugVolume(VolumeFile& vf, const QString& name) throw (BrainModelAlgorithmException); /// write the vector file for debugging void writeDebugVector(SureFitVectorFile& vf, const QString& name) throw (BrainModelAlgorithmException); /// Free a volume file. void freeVolumeInMemory(VolumeFile* &vf); /// Free a vector file. void freeVectorInMemory(SureFitVectorFile* &vf); /// free all volumes and vector files in memory. void freeAllFilesInMemory(); /// assign paint for padded CUT.FACE nodes void assignPaddedCutFaceNodePainting(const CoordinateFile* cf, const VolumeFile* segmentVol, PaintFile* pf, const int columnToAssign); /// the fiducial surface BrainModelSurface* fiducialSurface; /// the input volume VolumeFile* anatomyVolume; /// resulting segmentation volume VolumeFile* segmentationVolume; /// resulting segmentation with ventricles filled VolumeFile* segmentationVentriclesFilledVolume; /// white matter threshold no eye volume VolumeFile* whiteMatterThreshNoEyeVolume; /// white matter threshold no eye flood volume VolumeFile* whiteMatterThreshNoEyeFloodVolume; /// cerebral white matter no brain stem filled VolumeFile* cerebralWmNoBstemFill; /// the inner mask volume VolumeFile* innerMask1Volume; /// intensity gradient volume VolumeFile* gradIntensityVolume; /// eye fat sculpt volume VolumeFile* eyeFatSculptVolume; /// gray matter level volume VolumeFile* gmILevelVolume; /// outer mask VolumeFile* outerMaskVolume; /// hindbrain flood volume VolumeFile* hindbrainFloodVolume; /// volume VolumeFile* wmThreshFloodVolume; /// volume VolumeFile* inTotalVolume; /// wm volume VolumeFile* inTotalThinWMVolume; /// out total volume VolumeFile* outTotalVolume; /// wm near ventricle volume VolumeFile* thinWMOrNearVentricleHCMask; /// gradient blur VolumeFile* ventGradLevelBlurVolume; /// inner boundary blur VolumeFile* inTotalBlur1Volume; /// outer boundary blur VolumeFile* outTotalBlur1Volume; /// cerebral wm erode volume VolumeFile* cerebralWMErodeVolume; /// pia vector SureFitVectorFile* gradPiaLevelVec; /// the gradient thin white matter vector SureFitVectorFile* gradThinWMlevelVecFile; /// the intensity gradient file SureFitVectorFile* gradIntensityVecFile; /// total thin WM gradient file SureFitVectorFile* gradInTotalThinWMVecFile; /// gray/white gradient SureFitVectorFile* gradGWlevelVecFile; /// gradient pial vector SureFitVectorFile* outGradPialLevelGMGradOutITMagVecFile; /// optional mask used for removal of non-cortical material VolumeFile* volumeMask; /// optional value for excluding voxels larger than this value float whiteMatterMaximum; /// disconnect eye flag bool disconnectEyeFlag; /// disconnect the hind brain flag bool disconnectHindBrainFlag; /// disconnect hind brain using high thresholding flag bool disconnectHindBrainHiThreshFlag; /// cut the corpus callossum flag bool cutCorpusCallosumFlag; /// generate the inner boundary flag bool generateInnerBoundaryFlag; /// generate the outer boundary flag bool generateOuterBoundaryFlag; /// generate the segmentation flag bool generateSegmentationFlag; /// generate the surface flag bool generateRawAndFidualSurfacesFlag; /// generate a topologically correct fiducial surface bool generateTopologicallyCorrectFiducialSurfaceFlag; /// generate inflated surface bool generateInflatedSurfaceFlag; /// generate very inflated surface bool generateVeryInflatedSurfaceFlag; /// generate ellipsoid surfaces bool generateEllipsoidSurfaceFlag; /// generate spherical surface bool generateSphericalSurfaceFlag; /// generate compressed medial wall surface bool generateCompressedMedialWallSurfaceFlag; /// generate hull surface bool generateHullSurfaceFlag; /// fill ventricles flag bool fillVentriclesFlag; /// error correction method ERROR_CORRECTION_METHOD errorCorrectionMethod; /// generate depth, curvature, geography flag bool generateDepthCurvatureGeographyFlag; /// generate landmarks for registration and flattening bool identifyRegisterFlattenLandmarksFlag; /// auto-save files flag bool autoSaveFilesFlag; /// generate maximum polygons bool maximumPolygonsFlag; /// x dimensions of volume being segmented int xDim; /// y dimensions of volume being segmented int yDim; /// z dimensions of volume being segmented int zDim; /// Anterior Commissure voxel indices int acIJK[3]; /// x/y/z minimums //int xyzMin[3]; /// white matter peak float wmPeak; /// white matter threshold float wmThresh; /// float csfThresh; /// cgm peak float cgmPeak; /// float cgmLow; /// float cgmHigh; /// float cgmSignum; /// float inITPeak; /// float inITLow; /// float inITHigh; /// float inITSignum; /// float outITPeak; /// float outITLow; /// float outITHigh; /// float outITSignum; /// padding voxel indices //int paddingIJK[6]; /// structure Structure::STRUCTURE_TYPE structure; /// extract mask flag bool extractMaskFlag; /// 0=left, 1=right int Hem; /// ??? int Hem1; /// ??? int Hem2; /// ??? int HemDbl; /// ??? int Hem3; /// ??? int xAClow; /// ??? int xAChigh; /// ??? int xAC_1; /// ??? int xAC_1_low; /// ??? int xAC_1_high; /// ??? int xAC_10; /// ??? int xAC_15; /// ??? int xAC_20; /// ??? int xAC_20_low; /// ??? int xAC_20_high; /// ??? int xAC_40; /// ??? int xAC_15_40_low; /// ??? int xAC_15_40_high; /// ??? int xAC_50; /// ??? int xMedLimit_50_low; /// ??? int xMedLimit_50_high; /// ??? int xMedLimit_20_low; /// ??? int xMedLimit_20_high; /// ??? int xMedLimit_low; /// ??? int xMedLimit_high; /// Xmin from params file //int xMin; /// Ymin from params file //int yMin; /// Zmin from params file //int zMin; /// segmentation debug files sub directory QString segmentationDebugFilesSubDirectory; /// partial hemisphere padding int partialHemispherePadding[6]; /// type of volume files to write VolumeFile::FILE_READ_WRITE_TYPE typeOfVolumeFilesToWrite; }; #endif // __BRAIN_MODEL_VOLUME_SEGMENTATION_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeSureFitSegmentation.cxx0000664000175000017500000061413611572067322027530 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include "AreaColorFile.h" #include "BorderColorFile.h" #include "BorderProjectionFile.h" #include "BrainSet.h" #include "BrainModelOpenGL.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceBorderLandmarkIdentification.h" #include "BrainModelSurfaceCurvature.h" #include "BrainModelSurfaceOverlay.h" #include "BrainModelSurfaceSulcalDepthWithNormals.h" #include "BrainModelSurfaceTopologyCorrector.h" #include "BrainModelVolumeGradient.h" #include "BrainModelVolumeNearToPlane.h" #include "BrainModelVolumeSureFitErrorCorrection.h" #include "BrainModelVolumeSureFitSegmentation.h" #include "BrainModelVolumeToSurfaceConverter.h" #include "BrainModelVolumeTopologyGraphCorrector.h" #include "DebugControl.h" #include "DisplaySettingsBorders.h" #include "DisplaySettingsSurfaceShape.h" #include "PaintFile.h" #include "ParamsFile.h" #include "SceneFile.h" #include "StatisticHistogram.h" #include "SurfaceShapeFile.h" #include "TopologyFile.h" #include "VocabularyFile.h" /** * Constructor. Call execute() after this constructor. */ BrainModelVolumeSureFitSegmentation::BrainModelVolumeSureFitSegmentation(BrainSet* bs, const VolumeFile* anatomyVolumeIn, const VolumeFile* segmentationVolumeIn, const VolumeFile::FILE_READ_WRITE_TYPE typeOfVolumeFilesToWriteIn, const int acIJKIn[3], const int partialHemispherePaddingIn[6], const float wmPeakIn, const float gmPeakIn, const float midThreshOverrideIn, const Structure::STRUCTURE_TYPE structureIn, const bool disconnectEyeFlagIn, const bool disconnectHindBrainFlagIn, const bool disconnectHindBrainHiThreshFlagIn, const bool cutCorpusCallosumFlagIn, const bool segmentAnatomyFlagIn, const bool fillVentriclesFlagIn, const ERROR_CORRECTION_METHOD errorCorrectionMethodIn, const bool generateRawAndFidualSurfacesFlagIn, const bool maximumPolygonsFlagIn, const bool generateTopologicallyCorrectFiducialSurfaceFlagIn, const bool generateInflatedSurfaceFlagIn, const bool generateVeryInflatedSurfaceFlagIn, const bool generateEllipsoidSurfaceFlagIn, const bool generateSphericalSurfaceFlagIn, const bool generateCompressedMedialWallSurfaceFlagIn, const bool generateHullSurfaceFlagIn, const bool generateDepthCurvatureGeographyFlagIn, const bool identifyRegisterFlattenLandmarksFlagIn, const bool autoSaveFilesFlagIn) : BrainModelAlgorithm(bs) { typeOfVolumeFilesToWrite = typeOfVolumeFilesToWriteIn; disconnectEyeFlag = disconnectEyeFlagIn; disconnectHindBrainFlag = disconnectHindBrainFlagIn; disconnectHindBrainHiThreshFlag = disconnectHindBrainHiThreshFlagIn; cutCorpusCallosumFlag = cutCorpusCallosumFlagIn; if (segmentAnatomyFlagIn) { generateInnerBoundaryFlag = true; generateOuterBoundaryFlag = true; generateSegmentationFlag = true; } else { generateInnerBoundaryFlag = false; generateOuterBoundaryFlag = false; generateSegmentationFlag = false; } fillVentriclesFlag = fillVentriclesFlagIn; errorCorrectionMethod = errorCorrectionMethodIn; generateRawAndFidualSurfacesFlag = generateRawAndFidualSurfacesFlagIn; generateTopologicallyCorrectFiducialSurfaceFlag = generateTopologicallyCorrectFiducialSurfaceFlagIn; generateInflatedSurfaceFlag = generateInflatedSurfaceFlagIn; generateVeryInflatedSurfaceFlag = generateVeryInflatedSurfaceFlagIn; generateEllipsoidSurfaceFlag = generateEllipsoidSurfaceFlagIn; generateSphericalSurfaceFlag = generateSphericalSurfaceFlagIn; generateCompressedMedialWallSurfaceFlag = generateCompressedMedialWallSurfaceFlagIn; generateHullSurfaceFlag = generateHullSurfaceFlagIn; generateDepthCurvatureGeographyFlag = generateDepthCurvatureGeographyFlagIn; identifyRegisterFlattenLandmarksFlag = identifyRegisterFlattenLandmarksFlagIn; autoSaveFilesFlag = autoSaveFilesFlagIn; maximumPolygonsFlag = maximumPolygonsFlagIn; extractMaskFlag = true; anatomyVolume = NULL; if (anatomyVolumeIn != NULL) { anatomyVolume = new VolumeFile(*anatomyVolumeIn); anatomyVolume->setFileWriteType(typeOfVolumeFilesToWrite); } segmentationVolume = NULL; if (segmentationVolumeIn != NULL) { segmentationVolume = new VolumeFile(*segmentationVolumeIn); segmentationVolume->setFileWriteType(typeOfVolumeFilesToWrite); } segmentationVentriclesFilledVolume = NULL; whiteMatterThreshNoEyeVolume = NULL; whiteMatterThreshNoEyeFloodVolume = NULL; cerebralWmNoBstemFill = NULL; innerMask1Volume = NULL; gradIntensityVolume = NULL; eyeFatSculptVolume = NULL; gmILevelVolume = NULL; outerMaskVolume = NULL; wmThreshFloodVolume = NULL; inTotalVolume = NULL; inTotalThinWMVolume = NULL; outTotalVolume = NULL; thinWMOrNearVentricleHCMask = NULL; ventGradLevelBlurVolume = NULL; inTotalBlur1Volume = NULL; outTotalBlur1Volume = NULL; cerebralWMErodeVolume = NULL; hindbrainFloodVolume = NULL; fiducialSurface = NULL; gradPiaLevelVec = NULL; gradThinWMlevelVecFile = NULL; gradIntensityVecFile = NULL; gradInTotalThinWMVecFile = NULL; gradGWlevelVecFile = NULL; outGradPialLevelGMGradOutITMagVecFile = NULL; acIJK[0] = acIJKIn[0]; acIJK[1] = acIJKIn[1]; acIJK[2] = acIJKIn[2]; wmPeak = wmPeakIn; cgmPeak = gmPeakIn; wmThresh = (wmPeak + cgmPeak) * 0.5; if (midThreshOverrideIn > 0.0) { wmThresh = midThreshOverrideIn; } structure = structureIn; for (int i = 0; i < 6; i++) { partialHemispherePadding[i] = partialHemispherePaddingIn[i]; } volumeMask = NULL; whiteMatterMaximum = 0.0; } /** * Constructor used for identifying sulci only. * Call executeIdentifySulci() after this constructor. */ BrainModelVolumeSureFitSegmentation::BrainModelVolumeSureFitSegmentation(BrainSet* bs, const Structure::STRUCTURE_TYPE structureIn, const VolumeFile::FILE_READ_WRITE_TYPE typeOfVolumeFilesToWriteIn, const bool generateHullSurfaceFlagIn) : BrainModelAlgorithm(bs) { typeOfVolumeFilesToWrite = typeOfVolumeFilesToWriteIn; autoSaveFilesFlag = true; anatomyVolume = NULL; segmentationVentriclesFilledVolume = NULL; whiteMatterThreshNoEyeVolume = NULL; whiteMatterThreshNoEyeFloodVolume = NULL; cerebralWmNoBstemFill = NULL; innerMask1Volume = NULL; gradIntensityVolume = NULL; eyeFatSculptVolume = NULL; gmILevelVolume = NULL; outerMaskVolume = NULL; wmThreshFloodVolume = NULL; inTotalVolume = NULL; inTotalThinWMVolume = NULL; outTotalVolume = NULL; thinWMOrNearVentricleHCMask = NULL; ventGradLevelBlurVolume = NULL; inTotalBlur1Volume = NULL; outTotalBlur1Volume = NULL; cerebralWMErodeVolume = NULL; hindbrainFloodVolume = NULL; gradPiaLevelVec = NULL; gradThinWMlevelVecFile = NULL; gradIntensityVecFile = NULL; gradInTotalThinWMVecFile = NULL; gradGWlevelVecFile = NULL; outGradPialLevelGMGradOutITMagVecFile = NULL; generateHullSurfaceFlag = generateHullSurfaceFlagIn; if (bs->getNumberOfVolumeSegmentationFiles() <= 0) { throw BrainModelAlgorithmException("No segmentation volume is loaded in brain set."); } else if (bs->getNumberOfVolumeSegmentationFiles() > 1) { throw BrainModelAlgorithmException("More than one segmentation volumes are loaded in brain set."); } segmentationVolume = new VolumeFile(*(bs->getVolumeSegmentationFile(0))); fiducialSurface = bs->getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_FIDUCIAL); if (fiducialSurface == NULL) { throw BrainModelAlgorithmException("No fiducial surface is loaded in brain set."); } acIJK[0] = 0; acIJK[1] = 0; acIJK[2] = 0; structure = structureIn; for (int i = 0; i < 6; i++) { partialHemispherePadding[i] = 0; } volumeMask = NULL; whiteMatterMaximum = 0.0; } /** * Destructor. */ BrainModelVolumeSureFitSegmentation::~BrainModelVolumeSureFitSegmentation() { freeAllFilesInMemory(); if (DebugControl::getDebugOn() == false) { QDir dir; dir.rmdir(segmentationDebugFilesSubDirectory); } } /** * get error correction methods and names. */ void BrainModelVolumeSureFitSegmentation::getErrorCorrectionMethodsAndNames( std::vector& namesOut, std::vector& methodsOut) { namesOut.clear(); methodsOut.clear(); namesOut.push_back("NONE"); methodsOut.push_back(ERROR_CORRECTION_METHOD_NONE); namesOut.push_back("GRAPH"); methodsOut.push_back(ERROR_CORRECTION_METHOD_GRAPH); namesOut.push_back("SUREFIT"); methodsOut.push_back(ERROR_CORRECTION_METHOD_SUREFIT); namesOut.push_back("SUREFIT_THEN_GRAPH"); methodsOut.push_back(ERROR_CORRECTION_METHOD_SUREFIT_AND_GRAPH); namesOut.push_back("GRAPH_THEN_SUREFIT"); methodsOut.push_back(ERROR_CORRECTION_METHOD_GRAPH_AND_SUREFIT); } /** * set the volume mask applied prior to inner and outer boundary determination. */ void BrainModelVolumeSureFitSegmentation::setVolumeMask(const VolumeFile* volumeMaskIn) { volumeMask = new VolumeFile(*volumeMaskIn); } /** * set white maximum (values larger than this are excluded prior to inner and outer boundary determination. */ void BrainModelVolumeSureFitSegmentation::setWhiteMatterMaximum(const float whiteMatterMaximumIn) { whiteMatterMaximum = whiteMatterMaximumIn; } /** * Free all volumes and vector files in memory. */ void BrainModelVolumeSureFitSegmentation::freeAllFilesInMemory() { freeVolumeInMemory(anatomyVolume); freeVolumeInMemory(whiteMatterThreshNoEyeVolume); freeVolumeInMemory(whiteMatterThreshNoEyeFloodVolume); freeVolumeInMemory(cerebralWmNoBstemFill); freeVolumeInMemory(innerMask1Volume); freeVolumeInMemory(gradIntensityVolume); freeVolumeInMemory(eyeFatSculptVolume); freeVolumeInMemory(gmILevelVolume); freeVolumeInMemory(outerMaskVolume); freeVolumeInMemory(wmThreshFloodVolume); freeVolumeInMemory(inTotalVolume); freeVolumeInMemory(inTotalThinWMVolume); freeVolumeInMemory(outTotalVolume); freeVolumeInMemory(thinWMOrNearVentricleHCMask); freeVolumeInMemory(ventGradLevelBlurVolume); freeVolumeInMemory(inTotalBlur1Volume); freeVolumeInMemory(outTotalBlur1Volume); freeVolumeInMemory(cerebralWMErodeVolume); freeVolumeInMemory(segmentationVolume); freeVolumeInMemory(segmentationVentriclesFilledVolume); freeVolumeInMemory(hindbrainFloodVolume); freeVolumeInMemory(volumeMask); freeVectorInMemory(gradPiaLevelVec); freeVectorInMemory(gradThinWMlevelVecFile); freeVectorInMemory(gradIntensityVecFile); freeVectorInMemory(gradInTotalThinWMVecFile); freeVectorInMemory(gradGWlevelVecFile); freeVectorInMemory(outGradPialLevelGMGradOutITMagVecFile); } /** * free a volume file in memory. */ void BrainModelVolumeSureFitSegmentation::freeVolumeInMemory(VolumeFile* &vf) { if (vf != NULL) { delete vf; vf = NULL; } } /** * free a vector file in memory. */ void BrainModelVolumeSureFitSegmentation::freeVectorInMemory(SureFitVectorFile* &vf) { if (vf != NULL) { delete vf; vf = NULL; } } /** * execute the algorithm for only identifying sulci. */ void BrainModelVolumeSureFitSegmentation::executeIdentifySulci() throw (BrainModelAlgorithmException) { if (segmentationVolume == NULL) { throw BrainModelAlgorithmException("Segmentation volume is NULL"); } switch (structure) { case Structure::STRUCTURE_TYPE_CORTEX_LEFT: case Structure::STRUCTURE_TYPE_CORTEX_RIGHT: break; case Structure::STRUCTURE_TYPE_CORTEX_BOTH: case Structure::STRUCTURE_TYPE_CEREBELLUM: case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_LEFT: case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_RIGHT: case Structure::STRUCTURE_TYPE_CORTEX_LEFT_OR_CEREBELLUM: case Structure::STRUCTURE_TYPE_CORTEX_RIGHT_OR_CEREBELLUM: case Structure::STRUCTURE_TYPE_CEREBRUM_CEREBELLUM: case Structure::STRUCTURE_TYPE_SUBCORTICAL: case Structure::STRUCTURE_TYPE_ALL: case Structure::STRUCTURE_TYPE_INVALID: QString msg("Struture must be either \""); msg += Structure::convertTypeToString(Structure::STRUCTURE_TYPE_CORTEX_LEFT); msg += "\" or \""; msg += Structure::convertTypeToString(Structure::STRUCTURE_TYPE_CORTEX_RIGHT); msg += "\"."; throw BrainModelAlgorithmException(msg); break; } // // Create the segmentation debug files directory // segmentationDebugFilesSubDirectory = "SEGMENTATION_DEBUG_VOLUMES"; QDir debugDir(segmentationDebugFilesSubDirectory); if (debugDir.exists() == false) { QDir temp("."); temp.mkdir(segmentationDebugFilesSubDirectory); } // // Determine AC voxel // float zeros[3] = { 0.0, 0.0, 0.0 }; segmentationVolume->convertCoordinatesToVoxelIJK(zeros, acIJK); // // setup parameters for AC offsets and stuff // getParameters(); // // Generate depth, curvature, and geography // generateDepthCurvatureGeography(segmentationVolume); freeAllFilesInMemory(); } /** * execute the algorithm. */ void BrainModelVolumeSureFitSegmentation::execute() throw (BrainModelAlgorithmException) { if ((anatomyVolume == NULL) && (segmentationVolume == NULL)) { throw BrainModelAlgorithmException("No anatomy or segmentation volume available."); } QTime timer; timer.start(); if (DebugControl::getDebugOn()) { if (anatomyVolume != NULL) { float mins, maxs; anatomyVolume->getMinMaxVoxelValues(mins, maxs); std::cout << "Anatomy Volume min/max voxels: " << mins << ", " << maxs << std::endl; } } // // Create the segmentation debug files directory // segmentationDebugFilesSubDirectory = "SEGMENTATION_DEBUG_VOLUMES"; QDir debugDir(segmentationDebugFilesSubDirectory); if (debugDir.exists() == false) { QDir temp("."); temp.mkdir(segmentationDebugFilesSubDirectory); } try { // // Read parameters from paramters file // getParameters(); int PROGRESS_PROGRESS_DISCONNECT_EYE = -1; int PROGRESS_DISCONNECT_HIND_BRAIN = -1; int PROGRESS_CUT_CORPUS_CALLOSUM = -1; int PROGRESS_GENERATE_INNER_BOUNDARY = -1; int PROGRESS_GENERATE_OUTER_BOUNDARY = -1; int PROGRESS_GENERATE_LAYER_4 = -1; int PROGRESS_FILL_VENTRICLES = -1; int PROGRESS_AUTOMATIC_ERROR_CORRECTION = -1; int PROGRESS_GENERATE_SURFACE = -1; int PROGRESS_GENERATE_INFLATED_ELLIPSOID_SURFACE = -1; int PROGRESS_GENERATE_SULCAL_ID = -1; int PROCESS_GENERATE_REGISTER_FLATTEN_LANDMARKS = -1; int numSteps = 1; // // Check inputs // if (disconnectEyeFlag) { if (anatomyVolume == NULL) { throw BrainModelAlgorithmException("Cannot disconnect eye. No Anatomy Volume."); } PROGRESS_PROGRESS_DISCONNECT_EYE = numSteps; numSteps++; } if (disconnectHindBrainFlag) { if (anatomyVolume == NULL) { throw BrainModelAlgorithmException("Cannot hindbrain. No Anatomy Volume."); } PROGRESS_DISCONNECT_HIND_BRAIN = numSteps; numSteps++; } if (cutCorpusCallosumFlag) { if (anatomyVolume == NULL) { throw BrainModelAlgorithmException("Cannot cut corpus callosum. No Anatomy Volume."); } PROGRESS_CUT_CORPUS_CALLOSUM = numSteps; numSteps++; } if (anatomyVolume != NULL) { if (generateInnerBoundaryFlag) { PROGRESS_GENERATE_INNER_BOUNDARY = numSteps; numSteps++; } if (generateOuterBoundaryFlag) { PROGRESS_GENERATE_OUTER_BOUNDARY = numSteps; numSteps++; } if (generateSegmentationFlag) { PROGRESS_GENERATE_LAYER_4 = numSteps; numSteps++; } } if (fillVentriclesFlag) { PROGRESS_FILL_VENTRICLES = numSteps; numSteps++; } switch (errorCorrectionMethod) { case ERROR_CORRECTION_METHOD_NONE: break; case ERROR_CORRECTION_METHOD_GRAPH: case ERROR_CORRECTION_METHOD_SUREFIT: case ERROR_CORRECTION_METHOD_SUREFIT_AND_GRAPH: case ERROR_CORRECTION_METHOD_GRAPH_AND_SUREFIT: PROGRESS_AUTOMATIC_ERROR_CORRECTION = numSteps; numSteps++; break; } if (generateRawAndFidualSurfacesFlag) { PROGRESS_GENERATE_SURFACE = numSteps; numSteps++; } if (generateInflatedSurfaceFlag || generateVeryInflatedSurfaceFlag || generateEllipsoidSurfaceFlag || generateSphericalSurfaceFlag || generateCompressedMedialWallSurfaceFlag) { if (generateRawAndFidualSurfacesFlag == false) { throw BrainModelAlgorithmException("You must create raw and fiducial if you want " "inflated and/or ellipsoid surfaces."); } PROGRESS_GENERATE_INFLATED_ELLIPSOID_SURFACE = numSteps; numSteps++; } if (generateDepthCurvatureGeographyFlag) { if (generateRawAndFidualSurfacesFlag == false) { throw BrainModelAlgorithmException("You must create raw and fiducial if you want " "to generate depth, curvature, and geography."); } PROGRESS_GENERATE_SULCAL_ID = numSteps; numSteps++; } if (identifyRegisterFlattenLandmarksFlag) { if (generateInflatedSurfaceFlag == false) { throw BrainModelAlgorithmException("You must generate an inflated surface" " if you want to generate registration and flattening landmark borders."); } if (generateVeryInflatedSurfaceFlag == false) { throw BrainModelAlgorithmException("You must generate a very inflated surface" " if you want to generate registration and flattening landmark borders."); } if (generateEllipsoidSurfaceFlag == false) { throw BrainModelAlgorithmException("You must generate an ellipsoid surface" " if you want to generate registration and flattening landmark borders."); } //if (generateSphericalSurfaceFlag == false) { // throw BrainModelAlgorithmException("You must generate a spherical surface" // " if you want to generate registration and flattening landmarks borders."); //} if (generateDepthCurvatureGeographyFlag == false) { throw BrainModelAlgorithmException("You must generate depth, curvature, and geography" " if you want to generate registration and flattening landmark borders."); } PROCESS_GENERATE_REGISTER_FLATTEN_LANDMARKS = numSteps; numSteps++; } createProgressDialog("Segmentation Processing", numSteps, "segmentationProgressDialog"); // // descriptive name for segmentation volume (only set if segmentation is performed) // QString segmentationVolumeDescription; // // Should anatomy volume be processed // if (anatomyVolume != NULL) { // // make volume write float // anatomyVolume->setVoxelDataType(VolumeFile::VOXEL_DATA_TYPE_FLOAT); // // Disconnect the eye // if (disconnectEyeFlag) { updateProgressDialog("Disconnecting the eye.", PROGRESS_PROGRESS_DISCONNECT_EYE); disconnectEye(); if ((disconnectHindBrainFlag == false) && (cutCorpusCallosumFlag == false) && (generateInnerBoundaryFlag == false) && (generateOuterBoundaryFlag == false) && (generateSegmentationFlag == false)) { segmentationVolume = new VolumeFile(*whiteMatterThreshNoEyeVolume); segmentationVolumeDescription = "EyeAndSkullDisconnected"; } } // // Disconnect the hind brain // if (disconnectHindBrainFlag) { updateProgressDialog("Disconnecting the hind brain.", PROGRESS_DISCONNECT_HIND_BRAIN); disconnectHindBrain(); if ((cutCorpusCallosumFlag == false) && (generateInnerBoundaryFlag == false) && (generateOuterBoundaryFlag == false) && (generateSegmentationFlag == false)) { segmentationVolume = new VolumeFile(*cerebralWmNoBstemFill); segmentationVolumeDescription = "HindBrainDisconnected"; } } else { if (disconnectEyeFlag) { cerebralWmNoBstemFill = whiteMatterThreshNoEyeFloodVolume; } else { // // Needed if disconnecting hind brain skipped // //cerebralWmNoBstemFill = new VolumeFile(*anatomyVolume); //cerebralWmNoBstemFill->setAllVoxels(0.0); } } // // cut the corpus callosum // if (cutCorpusCallosumFlag) { updateProgressDialog("Cutting the corpus callosum.", PROGRESS_CUT_CORPUS_CALLOSUM); cutCorpusCallossum(); if ((generateInnerBoundaryFlag == false) && (generateOuterBoundaryFlag == false) && (generateSegmentationFlag == false)) { segmentationVolume = new VolumeFile(*cerebralWMErodeVolume); segmentationVolumeDescription = "CorpusCallossumCut"; } } // // Apply optional mask and white matter maximum // applyVolumeMaskAndWhiteMatterMaximum(); // // Update params file with gray/white peaks // ParamsFile* paramsFile = brainSet->getParamsFile(); if (paramsFile != NULL) { paramsFile->setParameter(ParamsFile::keyCGMpeak, cgmPeak); paramsFile->setParameter(ParamsFile::keyWMpeak, wmPeak); try { paramsFile->writeFile(paramsFile->getFileName()); } catch (FileException&) { } } // // generate the inner boundary // if (generateInnerBoundaryFlag) { updateProgressDialog("Determining the inner boundary.", PROGRESS_GENERATE_INNER_BOUNDARY); generateInnerBoundary(); } // // generate the outer boundary // if (generateOuterBoundaryFlag) { updateProgressDialog("Determining the outer boundary.", PROGRESS_GENERATE_OUTER_BOUNDARY); generateOuterBoundary(); } // // Generate the segmentation // if (generateSegmentationFlag) { updateProgressDialog("Determining layer 4.", PROGRESS_GENERATE_LAYER_4); generateSegmentation(); segmentationVolumeDescription = "Segmentation"; } } // // Was the segmentation volume created ? // if ((segmentationVolume != NULL) && (segmentationVolumeDescription.isEmpty() == false)) { // // make volume write float // segmentationVolume->setVoxelDataType(VolumeFile::VOXEL_DATA_TYPE_FLOAT); // // Add it to the brain set // VolumeFile* temp = new VolumeFile(*segmentationVolume); temp->setFileWriteType(typeOfVolumeFilesToWrite); temp->makeDefaultFileName(segmentationVolumeDescription); temp->setDescriptiveLabel(segmentationVolumeDescription); brainSet->addVolumeFile(VolumeFile::VOLUME_TYPE_SEGMENTATION, temp, "", true, false); // // Save the segmentation volume ? // if (autoSaveFilesFlag) { try { brainSet->writeVolumeFile(temp->getFileName(), temp->getFileWriteType(), VolumeFile::VOLUME_TYPE_SEGMENTATION, temp); } catch (FileException& e) { addToWarningMessages(e.whatQString()); } } } // // Is there a segmentation volume ? // if (segmentationVolume != NULL) { VolumeFile* segmentVolumeForProcessing = new VolumeFile(*segmentationVolume); // // make volume write float // segmentVolumeForProcessing->setVoxelDataType(VolumeFile::VOXEL_DATA_TYPE_FLOAT); // // If ventricles should be filled // if (fillVentriclesFlag) { updateProgressDialog("Filling the ventricles.", PROGRESS_FILL_VENTRICLES); // // Fill the ventricles // fillVentricles(); // // Were ventricles filled ? // if (segmentationVentriclesFilledVolume != NULL) { // // Add it to the brain set // VolumeFile* temp = new VolumeFile(*segmentationVentriclesFilledVolume); temp->setFileWriteType(typeOfVolumeFilesToWrite); temp->makeDefaultFileName("Segmentation_vent"); temp->setDescriptiveLabel("Segmentation_vent"); brainSet->addVolumeFile(VolumeFile::VOLUME_TYPE_SEGMENTATION, temp, "", true, false); delete segmentVolumeForProcessing; segmentVolumeForProcessing = new VolumeFile(*temp); // // Save the segmentation with ventricles filled volume ? // if (autoSaveFilesFlag) { try { brainSet->writeVolumeFile(temp->getFileName(), typeOfVolumeFilesToWrite, VolumeFile::VOLUME_TYPE_SEGMENTATION, temp); } catch (FileException& e) { addToWarningMessages(e.whatQString()); } } } } // // Should errors be automatically corrected // if (errorCorrectionMethod != ERROR_CORRECTION_METHOD_NONE) { // // If a segmentation was generated from the anatomy volume // if ((anatomyVolume != NULL) && generateSegmentationFlag) { // // Generate a surface so that the user can see it and determine if // there was a problem such failure to remove the skull // generateRawAndFiducialSurfaces(segmentVolumeForProcessing); // // Cause surface to be displayed // brainSet->drawBrainModel(brainSet->getNumberOfBrainModels() - 1, 0); allowEventsToProcess(); } updateProgressDialog("Automatic Error Correction.", PROGRESS_AUTOMATIC_ERROR_CORRECTION); // // Do error correction // VolumeFile* correctedVolume = NULL; QString defaultCorrectedName("Segment_ErrorCorrected"); switch (errorCorrectionMethod) { case ERROR_CORRECTION_METHOD_NONE: break; case ERROR_CORRECTION_METHOD_GRAPH: defaultCorrectedName = "Segment_GraphErrorCorrected"; correctedVolume = graphBasedErrorCorrection(segmentVolumeForProcessing); break; case ERROR_CORRECTION_METHOD_SUREFIT: defaultCorrectedName = "Segment_SureFitErrorCorrected"; correctedVolume = sureFitAutomaticErrorCorrection(segmentVolumeForProcessing); break; case ERROR_CORRECTION_METHOD_SUREFIT_AND_GRAPH: { correctedVolume = sureFitAutomaticErrorCorrection(segmentVolumeForProcessing); VolumeFile* volumeToDelete = correctedVolume; correctedVolume = graphBasedErrorCorrection(correctedVolume); defaultCorrectedName = "Segment_SureFit_GraphErrorCorrected"; if (volumeToDelete != NULL) { delete volumeToDelete; } } break; case ERROR_CORRECTION_METHOD_GRAPH_AND_SUREFIT: { correctedVolume = graphBasedErrorCorrection(segmentVolumeForProcessing); VolumeFile* volumeToDelete = correctedVolume; correctedVolume = sureFitAutomaticErrorCorrection(correctedVolume); defaultCorrectedName = "Segment_Graph_SureFitErrorCorrected"; if (volumeToDelete != NULL) { delete volumeToDelete; } } break; } if (correctedVolume != NULL) { correctedVolume->setFileWriteType(typeOfVolumeFilesToWrite); correctedVolume->makeDefaultFileName(defaultCorrectedName); correctedVolume->setDescriptiveLabel(defaultCorrectedName); // // Add the corrected volume to the brain set // brainSet->addVolumeFile(VolumeFile::VOLUME_TYPE_SEGMENTATION, correctedVolume, correctedVolume->getFileName(), true, true); // // Save the error corrected segmentation volume ? // if (autoSaveFilesFlag) { try { brainSet->writeVolumeFile(correctedVolume->getFileName(), typeOfVolumeFilesToWrite, VolumeFile::VOLUME_TYPE_SEGMENTATION, correctedVolume); } catch (FileException& e) { addToWarningMessages(e.whatQString()); } } delete segmentVolumeForProcessing; segmentVolumeForProcessing = new VolumeFile(*correctedVolume); } } // // If the surface should be generated // if (generateRawAndFidualSurfacesFlag) { updateProgressDialog("Generating the surface.", PROGRESS_GENERATE_SURFACE); // // Does the volume need to be padded for surface reconstruction // Only need to do this if generating an ellipsoid too // if (generateEllipsoidSurfaceFlag) { if ((partialHemispherePadding[0] != 0) || (partialHemispherePadding[1] != 0) || (partialHemispherePadding[2] != 0) || (partialHemispherePadding[3] != 0) || (partialHemispherePadding[4] != 0) || (partialHemispherePadding[5] != 0)) { // // Pad the segmentation // segmentVolumeForProcessing->padSegmentation(partialHemispherePadding, true); segmentVolumeForProcessing->clearModified(); // // Update volume dimensions // segmentVolumeForProcessing->getDimensions(xDim, yDim, zDim); } } // // Generate the raw and fiducial surfaces // updateProgressDialog("Generating the raw and fiducial surfaces.", PROGRESS_GENERATE_SURFACE); generateRawAndFiducialSurfaces(segmentVolumeForProcessing); // // If fiducial surface should be corrected // if (generateTopologicallyCorrectFiducialSurfaceFlag) { updateProgressDialog("Correcting fiducial surface topology.", PROGRESS_GENERATE_SURFACE); generateTopologicallyCorrectFiducialSurface(); } // // If inflated and ellipsoid surfaces should be generated // if (generateInflatedSurfaceFlag || generateVeryInflatedSurfaceFlag || generateEllipsoidSurfaceFlag || generateSphericalSurfaceFlag|| generateCompressedMedialWallSurfaceFlag) { updateProgressDialog("Generating the inflated, ellipsoid, and/or spherical surfaces.", PROGRESS_GENERATE_INFLATED_ELLIPSOID_SURFACE); // // Generate the inflated and ellipsoid surfaces // generateInflatedAndEllipsoidSurfaces(); } // // Auto save topology and coordinate files // if (autoSaveFilesFlag) { for (int i = 0; i < brainSet->getNumberOfTopologyFiles(); i++) { TopologyFile* tf = brainSet->getTopologyFile(i); try { brainSet->writeTopologyFile(tf->getFileName(), tf->getTopologyType(), tf); } catch (FileException& e) { addToWarningMessages(e.whatQString()); } } for (int i = 0; i < brainSet->getNumberOfBrainModels(); i++) { BrainModelSurface* bms = brainSet->getBrainModelSurface(i); if (bms != NULL) { CoordinateFile* cf = bms->getCoordinateFile(); try { brainSet->writeCoordinateFile(cf->getFileName(), bms->getSurfaceType(), cf, true); } catch (FileException& e) { addToWarningMessages(e.whatQString()); } } } } // // If sulci ID should be generated // if (generateDepthCurvatureGeographyFlag) { updateProgressDialog("Generating depth, curvature, and geography.", PROGRESS_GENERATE_SULCAL_ID); // // generate depth, curvature, and geography // generateDepthCurvatureGeography(segmentVolumeForProcessing); } // // If registration and flattening landmarks should be generated // if (identifyRegisterFlattenLandmarksFlag) { updateProgressDialog("Generating registration and flattening landmarks.", PROCESS_GENERATE_REGISTER_FLATTEN_LANDMARKS); generateRegistrationFlatteningLandmarkBorders(); } // // Generate default scenes // generateDefaultScenes(); } if (segmentVolumeForProcessing != NULL) { delete segmentVolumeForProcessing; segmentVolumeForProcessing = NULL; } } if (DebugControl::getDebugOn()) { std::cout << "Time to perform segmentation: " << (static_cast(timer.elapsed()) / 1000.0) << std::endl; } } catch (BrainModelAlgorithmException& e) { freeAllFilesInMemory(); removeProgressDialog(); throw BrainModelAlgorithmException(e.whatQString()); } catch (FileException& e) { freeAllFilesInMemory(); removeProgressDialog(); throw BrainModelAlgorithmException(e.whatQString()); } freeAllFilesInMemory(); removeProgressDialog(); } /** * apply volume mask and white matter maximum. */ void BrainModelVolumeSureFitSegmentation::applyVolumeMaskAndWhiteMatterMaximum() throw (BrainModelAlgorithmException) { if (volumeMask != NULL) { // // Exclude voxels that fall outside optional mask // cerebralWMErodeVolume->maskWithVolume(volumeMask); innerMask1Volume->maskWithVolume(volumeMask); outerMaskVolume->maskWithVolume(volumeMask); } if (whiteMatterMaximum > 0.0) { // // Turn off all voxels brighter than white matter maximum // int dim[3]; anatomyVolume->getDimensions(dim); for (int i = 0; i < dim[0]; i++) { for (int j = 0; j < dim[1]; j++) { for (int k = 0; k < dim[2]; k++) { if (anatomyVolume->getVoxel(i, j, k, 0) > whiteMatterMaximum) { cerebralWMErodeVolume->setVoxel(i, j, k, 0, 0.0); innerMask1Volume->setVoxel(i, j, k, 0, 0.0); outerMaskVolume->setVoxel(i, j, k, 0, 0.0); } } } } } } /** * do graph-based automatic error correction. */ VolumeFile* BrainModelVolumeSureFitSegmentation::graphBasedErrorCorrection(VolumeFile* vf) { BrainModelVolumeTopologyGraphCorrector corrector(brainSet, BrainModelVolumeTopologyGraphCorrector::CORRECTION_MODE_NORMAL, vf); try { corrector.execute(); } catch (BrainModelAlgorithmException& e) { throw e; } VolumeFile* volumeOut = NULL; if (corrector.getCorrectedSegmentationVolumeFile() != NULL) { volumeOut = new VolumeFile(*corrector.getCorrectedSegmentationVolumeFile()); } return volumeOut; } /** * do automatic error correction. */ VolumeFile* BrainModelVolumeSureFitSegmentation::sureFitAutomaticErrorCorrection(VolumeFile* vf) { VolumeFile *vol = new VolumeFile(*vf); // // Load the radial position map volume // VolumeFile radialPosVolume; try { switch (typeOfVolumeFilesToWrite) { case VolumeFile::FILE_READ_WRITE_TYPE_RAW: throw FileException("ERROR: RadioPositionMap wants to be read in RAW"); break; case VolumeFile::FILE_READ_WRITE_TYPE_AFNI: radialPosVolume.readFile("RadialPositionMap+orig.HEAD"); break; case VolumeFile::FILE_READ_WRITE_TYPE_ANALYZE: radialPosVolume.readFile("RadialPositionMap+orig.hdr"); break; case VolumeFile::FILE_READ_WRITE_TYPE_NIFTI: case VolumeFile::FILE_READ_WRITE_TYPE_NIFTI_GZIP: if (QFile::exists("RadialPositionMap+orig.nii.gz")) { radialPosVolume.readFile("RadialPositionMap+orig.nii.gz"); } else { radialPosVolume.readFile("RadialPositionMap+orig.nii"); } break; case VolumeFile::FILE_READ_WRITE_TYPE_SPM_OR_MEDX: radialPosVolume.readFile("RadialPositionMap+orig.hdr"); break; case VolumeFile::FILE_READ_WRITE_TYPE_WUNIL: radialPosVolume.readFile("RadialPositionMap+orig.ifh"); break; case VolumeFile::FILE_READ_WRITE_TYPE_UNKNOWN: throw FileException("ERROR: RadioPositionMap wants to be read in UNKNOWN"); break; } } catch (FileException& e) { throw BrainModelAlgorithmException("Unable to find volume file \"RadialPositionMap+orig.*\""); } // // Run error correction // BrainModelVolumeSureFitErrorCorrection sfec(brainSet, vol, &radialPosVolume, typeOfVolumeFilesToWrite, acIJK, (Hem == 0), DebugControl::getDebugOn()); try { sfec.execute(); } catch (BrainModelAlgorithmException& e) { throw e; } // // Get the error corrected volume // if (vol != NULL) { delete vol; } vol = NULL; if (sfec.getOutputVolume() != NULL) { vol = new VolumeFile(*sfec.getOutputVolume()); } return vol; } /** * Generate depth, curvature, and geography. */ void BrainModelVolumeSureFitSegmentation::generateDepthCurvatureGeography(const VolumeFile* segmentVolIn) { // // Expand around edges with empty slices // VolumeFile segmentVolumeExpanded(*segmentVolIn); int expDim[3]; segmentVolumeExpanded.getDimensions(expDim); const int expSlices = 7; const int resizeCrop[6] = { -expSlices, expDim[0] + expSlices, -expSlices, expDim[1] + expSlices, -expSlices, expDim[2] + expSlices }; segmentVolumeExpanded.resize(resizeCrop); writeDebugVolume(segmentVolumeExpanded, "SegmentExpandedForDepthCurveGeom"); // // Add area colors if needed // AreaColorFile* areaColorFile = brainSet->getAreaColorFile(); bool match = false; areaColorFile->getColorIndexByName("???", match); if (match == false) { areaColorFile->addColor("???", 170, 170, 170); } match = false; areaColorFile->getColorIndexByName("SUL", match); if (match == false) { areaColorFile->addColor("SUL", 130, 130, 130); } match = false; areaColorFile->getColorIndexByName("CENTRAL", match); if (match == false) { areaColorFile->addColor("CENTRAL", 255, 255, 0); } match = false; areaColorFile->getColorIndexByName("CALCARINE", match); if (match == false) { areaColorFile->addColor("CALCARINE", 255, 100, 0); } match = false; areaColorFile->getColorIndexByName("CUT.FACE", match); if (match == false) { areaColorFile->addColor("CUT.FACE", 255, 0, 0); } if (autoSaveFilesFlag) { if (areaColorFile->getModified()) { try { if (QFile::exists(areaColorFile->getFileName())) { brainSet->writeAreaColorFile(areaColorFile->getFileName()); } else { brainSet->writeAreaColorFile(areaColorFile->makeDefaultFileName("Initial")); } } catch (FileException& e) { addToWarningMessages(e.whatQString()); } } } // // Generate the hull volume and the cerebral hull VTK file // This creates the cerebral hull volume too. // brainSet->generateCerebralHullVtkFile(&segmentVolumeExpanded, false); VolumeFile* cerebralHullVolume = NULL; const int num = brainSet->getNumberOfVolumeSegmentationFiles() - 1; if (num >= 0) { // // Cerebral hull volume is newest segmentation volume // cerebralHullVolume = brainSet->getVolumeSegmentationFile(num); // // Should cerebral hull volume be saved // if (autoSaveFilesFlag) { try { cerebralHullVolume->setFileWriteType(typeOfVolumeFilesToWrite); cerebralHullVolume->makeDefaultFileName("CerebralHull"); cerebralHullVolume->setDescriptiveLabel("CerebralHull"); cerebralHullVolume->setFileWriteType(typeOfVolumeFilesToWrite); brainSet->writeVolumeFile(cerebralHullVolume->getFileName(), typeOfVolumeFilesToWrite, cerebralHullVolume->getVolumeType(), cerebralHullVolume); } catch (FileException& e) { addToWarningMessages(e.whatQString()); } } } // // cerebral hull surface BrainModelSurface* hullSurface = NULL; CoordinateFile* hullCoordFile = NULL; if (generateHullSurfaceFlag) { hullSurface = new BrainModelSurface(*fiducialSurface); hullCoordFile = hullSurface->getCoordinateFile(); hullCoordFile->makeDefaultFileName("CerebralHull"); brainSet->addBrainModel(hullSurface); } // // // Create the sulcal depth map in the surface shape file // const int hullSmoothingIterations = 5; const int depthSmoothingIterations = 100; SurfaceShapeFile* ssf = brainSet->getSurfaceShapeFile(); BrainModelSurfaceSulcalDepthWithNormals bmssd(brainSet, fiducialSurface, brainSet->getCerebralHullFileName(), ssf, hullSmoothingIterations, depthSmoothingIterations, BrainModelSurfaceSulcalDepthWithNormals::DEPTH_COLUMN_CREATE_NEW, BrainModelSurfaceSulcalDepthWithNormals::DEPTH_COLUMN_CREATE_NEW, "Depth", "Smoothed Depth", hullCoordFile); bmssd.execute(); // // Add curvature to the surface shape file // BrainModelSurfaceCurvature bmsc(brainSet, fiducialSurface, ssf, BrainModelSurfaceCurvature::CURVATURE_COLUMN_CREATE_NEW, BrainModelSurfaceCurvature::CURVATURE_COLUMN_CREATE_NEW, "Folding (Mean Curvature)", "Gaussian Curvature"); bmsc.execute(); // // Should files be saved // if (autoSaveFilesFlag) { try { if (QFile::exists(ssf->getFileName())) { brainSet->writeSurfaceShapeFile(ssf->getFileName()); } else { brainSet->writeSurfaceShapeFile(ssf->makeDefaultFileName("Initial")); } } catch (FileException& e) { addToWarningMessages(e.whatQString()); } // // Save hull surface too // if (hullSurface != NULL) { try { brainSet->writeCoordinateFile(hullCoordFile->getFileName(), BrainModelSurface::SURFACE_TYPE_HULL, hullCoordFile); } catch (FileException& e) { addToWarningMessages(e.whatQString()); } } } //#VolMorphOps.py 0 3 CerebralHull.mnc CerebralHull.erode.3 //SureFitOps.VolMorphOps (0, 3, data) //che3fname = "%s/%s" % (SulDirectory, "CerebralHull.erode.3.mnc") //WriteNetCDFFile (che3fname, data, xdim, ydim, zdim) VolumeFile data(*cerebralHullVolume); data.doVolMorphOps(0, 3); writeDebugVolume(data, "CerebralHull.erode.3"); VolumeFile cerebralHullErode3(data); //#VolMorphOps.py 0 1 CerebralHull.erode.3.mnc CerebralHull.erode.4 //SureFitOps.VolMorphOps (0, 1, data) //che4fname = "%s/%s" % (SulDirectory, "CerebralHull.erode.4.mnc") //WriteNetCDFFile (che4fname, data, xdim, ydim, zdim) data.doVolMorphOps(0, 1); writeDebugVolume(data, "CerebralHull.erode.4"); VolumeFile cerebralHullErode4(data); //#VolMorphOps.py 0 6 CerebralHull.erode.4.mnc CerebralHull.erode.10 //SureFitOps.VolMorphOps (0, 6, data) //che10fname = "%s/%s" % (SulDirectory, "CerebralHull.erode.10.mnc") //WriteNetCDFFile (che10fname, data, xdim, ydim, zdim) data.doVolMorphOps(0, 6); writeDebugVolume(data, "CerebralHull.erode.10"); VolumeFile cerebralHullErode10(data); //#CombineVols.py subrect CerebralHull.erode.3.mnc $Segment_file BuriedCortex.3deep //vol = volume.Volume (che3fname) //data = vol.VoxData3D //SureFitOps.CombineVols ("subrect", data, segdata, segdata) //bc3fname = "%s/%s.BuriedCortex.3deep.mnc" % // (SulDirectory, ReadParams.GetFilePrefix ()) //WriteNetCDFFile (bc3fname, data, xdim, ydim, zdim) VolumeFile segData(segmentVolumeExpanded); data = cerebralHullErode3; VolumeFile::performMathematicalOperation(VolumeFile::VOLUME_MATH_OPERATION_SUBTRACT_POSITIVE, &data, &segData, &segData, &data); data.stretchVoxelValues(); writeDebugVolume(data, "BuriedCortex.3deep"); VolumeFile bc3vol(data); //#VolMorphOps.py 1 0 BuriedCortex.3deep.mnc Sulci.3.dilate //SureFitOps.VolMorphOps (1, 0, data) //fname = "%s/%s" % (SulDirectory, "Sulci.3.dilate.mnc") //WriteNetCDFFile (fname, data, xdim, ydim, zdim) data.doVolMorphOps(1, 0); writeDebugVolume(data, "Sulci.3.dilate"); // #IntersectVolumeWithSurface.py $fname Sulci.3.dilate.mnc SUL 1 -0.5 -0.5 -0.5 // paintstring = "SUL" // col_number = 0 // xoffset = yoffset = zoffset = -0.5 // SureFitOps.IntersectVolumeWithSurface (specfname, data, paintstring, col_number, xoffset, yoffset, zoffset) // oldpaintfile = "%s.paint" % paintstring // os.rename (oldpaintfile, paintfile) // #2002-12: want this paint in both specific sulci and geography columns // paintstring = "SUL" // col_number = 1 // xoffset = yoffset = zoffset = -0.5 // SureFitOps.IntersectVolumeWithSurface (specfname, data, paintstring, col_number, xoffset, yoffset, zoffset) // oldpaintfile = "%s.paint" % paintstring // os.rename (oldpaintfile, paintfile) // // 27 Jan 2006 per DVE // To determine geography, use the cerebral hull eroded three times // const BrainModelSurface* rawBMS = brainSet->getBrainModelSurfaceOfType( BrainModelSurface::SURFACE_TYPE_RAW); if (rawBMS == NULL) { throw BrainModelAlgorithmException("Unable to find raw surface for sulci ID"); } const bool identifyCalcarineAndCentralFlag = false; int numPaintColumns = 0; int sulciIDColumnNumber = -1; if (identifyCalcarineAndCentralFlag) { sulciIDColumnNumber = numPaintColumns++; } const int geographyColumnNumber = numPaintColumns++; const CoordinateFile* rawCoordFile = rawBMS->getCoordinateFile(); PaintFile* pf = brainSet->getPaintFile(); pf->setNumberOfNodesAndColumns(brainSet->getNumberOfNodes(), numPaintColumns); if (sulciIDColumnNumber >= 0) { pf->setColumnName(sulciIDColumnNumber, "Sulci ID"); } pf->setColumnName(geographyColumnNumber, "Geography"); if (sulciIDColumnNumber >= 0) { pf->assignPaintColumnWithVolumeFile(&cerebralHullErode3, //&data, rawCoordFile, sulciIDColumnNumber, "SUL"); } pf->assignPaintColumnWithVolumeFile(&cerebralHullErode3, //&data, rawCoordFile, geographyColumnNumber, "SUL"); // // Set CUT.FACE paint ID for padded volumes // assignPaddedCutFaceNodePainting(rawCoordFile, &segmentVolumeExpanded, pf, geographyColumnNumber); if (identifyCalcarineAndCentralFlag) { // #CombineVols.py subrect CerebralHull.erode.4.mnc $Segment_file BuriedCortex.4deep // vol = volume.Volume (che4fname) // data = vol.VoxData3D // SureFitOps.CombineVols ("subrect", data, segdata, segdata) // bc4fname = "%s/%s" % (SulDirectory, "BuriedCortex.4deep.mnc") // WriteNetCDFFile (bc4fname, data, xdim, ydim, zdim) data = cerebralHullErode4; VolumeFile::performMathematicalOperation(VolumeFile::VOLUME_MATH_OPERATION_SUBTRACT_POSITIVE, &data, &segData, &segData, &data); data.stretchVoxelValues(); writeDebugVolume(data, "BuriedCortex.4deep"); VolumeFile buriedCortex4Deep(data); //if (acIJK[1] > (yDim - oldPadPosY)) { if (acIJK[1] > (yDim - partialHemispherePadding[3])) { if (DebugControl::getDebugOn()) { std::cout << "AC forward of anterior wall; skipping central sulcus." << std::endl; } } else { const int xAC_CeSlat = acIJK[0] + Hem3 * 40; const int xAC_CeSmed = acIJK[1] + Hem3 * 10; const int CeSxlow = xAC_CeSlat * Hem2 + xAC_CeSmed * Hem; const int CeSxhigh = xAC_CeSlat * Hem + xAC_CeSmed * Hem2; const int CeSymin = acIJK[1] - 40; const int CeSymax = acIJK[1] - 5; const int CeSzmin = acIJK[2] + 40; const int CeSzmax = acIJK[2] + 80; // #FillBiggestObject.py BuriedCortex.4deep.mnc CentralSulcus.4below $CeSxlow $CeSxhigh $CeSymin $CeSymax $CeSzmin $CeSzmax // x1 = CeSxlow // x2 = CeSxhigh // y1 = CeSymin // y2 = CeSymax // z1 = CeSzmin // z2 = CeSzmax // fboseed, data = FillBiggestObject (data, x1, x2, y1, y2, z1, z2) // fname = "%s/%s" % (SulDirectory, "CentralSulcus.4below.mnc") // WriteNetCDFFile (fname, data, xdim, ydim, zdim) data.fillBiggestObjectWithinMask(CeSxlow, CeSxhigh, CeSymin, CeSymax, CeSzmin, CeSzmax, 255, 255); writeDebugVolume(data, "CentralSulcus.4below"); // #Sculpt.py 0 5 0 $ncol 0 $nrow 0 $nslices CentralSulcus.4below.mnc BuriedCortex.3deep.mnc CentralSulcus // x1 = 0 // x2 = xdim // y1 = 0 // y2 = ydim // z1 = 0 // z2 = zdim // SureFitOps.Sculpt (0, 5, 0, 0, 0, x1, x2, y1, y2, z1, z2, data, bc3vol.VoxData3D) // fname = "%s/%s.CentralSulcus.mnc" % // (SulDirectory, ReadParams.GetFilePrefix ()) // WriteNetCDFFile (fname, data, xdim, ydim, zdim) // if refreshslice == 1: // SureSliceFcn.SetSecondVolume (data) int seed[3] = { 0, 0, 0 }; int extent[6] = { 0, xDim, 0, yDim, 0, zDim }; data.sculptVolume(0, &bc3vol, 5, seed, extent); writeDebugVolume(data, "CentralSulcus"); // #FindLimits.py CentralSulcus.mnc Limits.CeS // fname = "%s/%s.Limits.CeS" % // (SulDirectory, ReadParams.GetFilePrefix ()) // CesLim = SureFitOps.FindLimits (fname, data) data.findLimits("CentralSulculs.limits", extent); // #VolMorphOps.py 1 0 CentralSulcus.mnc CentralSulcus.dilate // SureFitOps.VolMorphOps (1, 0, data) // csdfname = "%s/%s.CentralSulcus.dilate.mnc" % // (SulDirectory, ReadParams.GetFilePrefix ()) // WriteNetCDFFile (csdfname, data, xdim, ydim, zdim) data.doVolMorphOps(1, 0); writeDebugVolume(data, "CentralSulcus.dilate"); // #IntersectVolumeWithSurface.py $fname CentralSulcus.dilate.mnc CENTRAL 1 -0.5 -0.5 -0.5 // paintstring = "CENTRAL" // col_number = 0 // SureFitOps.IntersectVolumeWithSurface (specfname, data, paintstring, col_number, xoffset, yoffset, zoffset) // oldpaintfile = "%s.paint" % paintstring // os.rename (oldpaintfile, paintfile) pf->assignPaintColumnWithVolumeFile(&data, rawCoordFile, sulciIDColumnNumber, "CENTRAL"); } // #CombineVols.py subrect CerebralHull.erode.10.mnc $Segment_file BuriedCortex.10deep // vol = volume.Volume (che10fname) // data = vol.VoxData3D // SureFitOps.CombineVols ("subrect", data, segdata, segdata) // bc10fname = "%s/%s.BuriedCortex.10deep.mnc" % // (SulDirectory, ReadParams.GetFilePrefix ()) // WriteNetCDFFile (bc10fname, data, xdim, ydim, zdim) data = cerebralHullErode10; VolumeFile::performMathematicalOperation(VolumeFile::VOLUME_MATH_OPERATION_SUBTRACT_POSITIVE, &data, &segData, &segData, &data); data.stretchVoxelValues(); writeDebugVolume(data, "BuriedCortex.10deep"); // #VolMorphOps.py 1 0 BuriedCortex.10deep.mnc Sulci.10.dilate // SureFitOps.VolMorphOps (1, 0, data) // s10dfname = "%s/%s" % (SulDirectory, "Sulci.10.dilate.mnc") // WriteNetCDFFile (s10dfname, data, xdim, ydim, zdim) data.doVolMorphOps(1, 0); writeDebugVolume(data, "Sulci.10.dilate"); // #MaskVol.py BuriedCortex.4deep.mnc BuriedCortex.4deep.CaSmask $CaSxlow $CaSxhigh $CaSymin $CaSymax $CaSzmin $CaSzmax // x1 = CaSxlow // x2 = CaSxhigh // y1 = CaSymin // y2 = CaSymax // z1 = CaSzmin // z2 = CaSzmax // vol = volume.Volume (bc4fname) // data = vol.VoxData3D // SureFitOps.MaskVol (x1, x2, y1, y2, z1, z2, data) // fname = "%s/%s" % (SulDirectory, "BuriedCortex.4deep.CaSmask.mnc") // WriteNetCDFFile (fname, data, xdim, ydim, zdim) const int xAC_CaSlat = acIJK[0] + Hem3 * 30; const int xAC_CaSmed = acIJK[0]; const int CaSxlow = xAC_CaSlat * Hem2 + xAC_CaSmed * Hem; const int CaSxhigh = xAC_CaSlat * Hem + xAC_CaSmed * Hem2; const int CaSymin = acIJK[1] - 100; const int CaSymax = acIJK[1] - 70; const int CaSzmin = acIJK[2]; const int CaSzmax = acIJK[2] + 30; data = buriedCortex4Deep; int extent[6]; extent[0] = CaSxlow; extent[1] = CaSxhigh; extent[2] = CaSymin; extent[3] = CaSymax; extent[4] = CaSzmin; extent[5] = CaSzmax; data.maskVolume(extent); writeDebugVolume(data, "BuriedCortex.4deep.CaSmask"); // #FillBiggestObject.py BuriedCortex.4deep.CaSmask.mnc CalcarineSulcus.4below $CaSxlow $CaSxhigh $CaSymin $CaSymax $CaSzmin $CaSzmax // fboseed, data = FillBiggestObject (data, x1, x2, y1, y2, z1, z2) // fname = "%s/%s" % (SulDirectory, "CalcarineSulcus.4below.mnc") // WriteNetCDFFile (fname, data, xdim, ydim, zdim) data.fillBiggestObjectWithinMask(extent, 255, 255); writeDebugVolume(data, "CalcarineSulcus.4below"); // #Sculpt.py 0 8 0 $ncol 0 $nrow 0 $nslices CalcarineSulcus.4below.mnc BuriedCortex.3deep.mnc CalcarineSulcus // x1 = 0 // x2 = xdim // y1 = 0 // y2 = ydim // z1 = 0 // z2 = zdim // SureFitOps.Sculpt (0, 8, 0, 0, 0, x1, x2, y1, y2, z1, z2, data, bc3vol.VoxData3D) // fname = "%s/%s.CalcarineSulcus.mnc" % // (SulDirectory, ReadParams.GetFilePrefix ()) // WriteNetCDFFile (fname, data, xdim, ydim, zdim) extent[0] = 0; extent[1] = xDim; extent[2] = 0; extent[3] = yDim; extent[4] = 0; extent[5] = zDim; int seed[3]; seed[0] = 0; seed[1] = 0; seed[2] = 0; //hghjhj data.sculptVolume(0, &bc3vol, 8, seed, extent); writeDebugVolume(data, "CalcarineSulcus"); // #FindLimits.py CalcarineSulcus.mnc Limits.CaS // fname = "%s/%s.Limits.CaS" % // (SulDirectory, ReadParams.GetFilePrefix ()) // CesLim = SureFitOps.FindLimits (fname, data) data.findLimits("Cas.Limits", extent); // #VolMorphOps.py 1 0 CalcarineSulcus.mnc CalcarineSulcus.dilate // SureFitOps.VolMorphOps (1, 0, data) // fname = "%s/%s.CalcarineSulcus.dilate.mnc" % // (SulDirectory, ReadParams.GetFilePrefix ()) // WriteNetCDFFile (fname, data, xdim, ydim, zdim) data.doVolMorphOps(1, 0); writeDebugVolume(data, "CalcarineSulcus.dilate"); // #IntersectVolumeWithSurface.py $fname CalcarineSulcus.dilate.mnc CALCARINE 1 -0.5 -0.5 -0.5 // paintstring = "CALCARINE" // col_number = 0 // SureFitOps.IntersectVolumeWithSurface (specfname, data, paintstring, col_number, xoffset, yoffset, zoffset) // oldpaintfile = "%s.paint" % paintstring // os.rename (oldpaintfile, paintfile) // geographyfname = re.sub(".Surface.", ".geography.", specfname) // geographyfname = re.sub(".spec", ".paint", geographyfname) // os.rename (paintfile, geographyfname) pf->assignPaintColumnWithVolumeFile(&data, rawCoordFile, sulciIDColumnNumber, "CALCARINE"); } // // Should the paint file be saved // if (autoSaveFilesFlag) { PaintFile* pf = brainSet->getPaintFile(); try { if (QFile::exists(pf->getFileName())) { brainSet->writePaintFile(pf->getFileName()); } else { brainSet->writePaintFile(pf->makeDefaultFileName("Initial")); } } catch (FileException& e) { addToWarningMessages(e.whatQString()); } } } /** * generate default scenes. */ void BrainModelVolumeSureFitSegmentation::generateDefaultScenes() throw (BrainModelAlgorithmException) { // // Update display settings and other things in brain set // brainSet->postSpecFileReadInitializations(); // // Set underlay to surface shape // BrainModelSurfaceOverlay* underlay = brainSet->getSurfaceUnderlay(); underlay->setOverlay(-1, BrainModelSurfaceOverlay::OVERLAY_SURFACE_SHAPE); DisplaySettingsSurfaceShape* dsss = brainSet->getDisplaySettingsSurfaceShape(); const SurfaceShapeFile* ssf = brainSet->getSurfaceShapeFile(); const int underlayOverlayNumber = underlay->getOverlayNumber(); if (ssf->getSulcalDepthColumnNumber() >= 0) { dsss->setSelectedDisplayColumn(-1, underlayOverlayNumber, ssf->getSulcalDepthColumnNumber()); } else if (ssf->getMeanCurvatureColumnNumber() >= 0) { dsss->setSelectedDisplayColumn(-1, underlayOverlayNumber, ssf->getMeanCurvatureColumnNumber()); } // // Turn on display of borders // brainSet->getDisplaySettingsBorders()->setDisplayBorders(true); // // For each window, main and viewing // std::vector windowSceneClasses; // // Lateral view of very inflated in Main Window // BrainModelSurface* veryInflatedSurface = brainSet->getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_VERY_INFLATED); if (veryInflatedSurface == NULL) { return; } // // Set the view // const int mainWindowGeometry[4] = { 50, 50, 600, 600 }; const int viewWindowGeometry[4] = { 600, 50, 400, 400 }; const int graphicsSizeX = 512; const int graphicsSizeY = 512; const int mainWindowGraphicsSize[2] = { -1, -1 }; const int viewWindowGraphicsSize[2] = { graphicsSizeX, graphicsSizeY }; if (brainSet->getProgressDialogParent() == NULL) { double orthoRight, orthoTop; BrainModelOpenGL::getDefaultOrthoRightAndTop(graphicsSizeX, graphicsSizeY, orthoRight, orthoTop); brainSet->setDefaultScaling(orthoRight, orthoTop); } // // create the lateral view in the main window // SceneFile::SceneClass mainWindowSceneClass(""); veryInflatedSurface->setToStandardView(BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW, BrainModel::VIEW_LATERAL); brainSet->saveSceneForBrainModelWindow(BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW, mainWindowGeometry, mainWindowGraphicsSize, veryInflatedSurface, false, mainWindowSceneClass); windowSceneClasses.push_back(mainWindowSceneClass); // // create the medial view in the view window // SceneFile::SceneClass viewWindowSceneClass(""); veryInflatedSurface->setToStandardView(BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_2, BrainModel::VIEW_MEDIAL); brainSet->saveSceneForBrainModelWindow(BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_2, viewWindowGeometry, viewWindowGraphicsSize, veryInflatedSurface, false, viewWindowSceneClass); windowSceneClasses.push_back(viewWindowSceneClass); QString errorMessage; QString warningMessage; brainSet->saveScene(brainSet->getSceneFile(), windowSceneClasses, "Lateral/Medial Views of Landmarks", false, errorMessage, warningMessage); errorMessage.append(warningMessage); if (errorMessage.isEmpty() == false) { throw BrainModelAlgorithmException(errorMessage); } // // Save scene file // if (autoSaveFilesFlag) { SceneFile* sf = brainSet->getSceneFile(); try { if (QFile::exists(sf->getFileName())) { brainSet->writeSceneFile(sf->getFileName()); } else { brainSet->writeSceneFile(sf->makeDefaultFileName("Initial")); } } catch (FileException& e) { addToWarningMessages(e.whatQString()); } } } /** * generate landmarks borders for flattening and registration. */ void BrainModelVolumeSureFitSegmentation::generateRegistrationFlatteningLandmarkBorders() throw (BrainModelAlgorithmException) { BorderProjectionFile borderProjectionFile; BrainModelSurfaceBorderLandmarkIdentification bmsbli(brainSet, brainSet->getStereotaxicSpace(), anatomyVolume, brainSet->getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_FIDUCIAL), brainSet->getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_INFLATED), brainSet->getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_VERY_INFLATED), brainSet->getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL), brainSet->getSurfaceShapeFile(), brainSet->getSurfaceShapeFile()->getSulcalDepthColumnNumber(), brainSet->getPaintFile(), brainSet->getPaintFile()->getGeographyColumnNumber(), brainSet->getAreaColorFile(), &borderProjectionFile, brainSet->getBorderColorFile(), brainSet->getVocabularyFile(), BrainModelSurfaceBorderLandmarkIdentification::OPERATION_ID_ALL); bmsbli.execute(); brainSet->getBorderSet()->copyBordersFromBorderProjectionFile(&borderProjectionFile); brainSet->getDisplaySettingsBorders()->setDisplayBorders(true); // // Save data files // if (autoSaveFilesFlag) { AreaColorFile* acf = brainSet->getAreaColorFile(); if (acf->getModified()) { try { if (QFile::exists(acf->getFileName())) { brainSet->writeAreaColorFile(acf->getFileName()); } else { brainSet->writeAreaColorFile(acf->makeDefaultFileName("Initial")); } } catch (FileException& e) { addToWarningMessages(e.whatQString()); } } PaintFile* pf = brainSet->getPaintFile(); try { if (QFile::exists(pf->getFileName())) { brainSet->writePaintFile(pf->getFileName()); } else { brainSet->writePaintFile(pf->makeDefaultFileName("Initial")); } } catch (FileException& e) { addToWarningMessages(e.whatQString()); } VocabularyFile* vocabularyFile = brainSet->getVocabularyFile(); if (vocabularyFile->getModified()) { try { if (QFile::exists(vocabularyFile->getFileName())) { brainSet->writeVocabularyFile(vocabularyFile->getFileName()); } else { brainSet->writeVocabularyFile(vocabularyFile->makeDefaultFileName("Initial")); } } catch (FileException& e) { addToWarningMessages(e.whatQString()); } } BorderColorFile* borderColorFile = brainSet->getBorderColorFile(); if (borderColorFile->getModified()) { try { if (QFile::exists(borderColorFile->getFileName())) { brainSet->writeBorderColorFile(borderColorFile->getFileName()); } else { brainSet->writeBorderColorFile(borderColorFile->makeDefaultFileName("Initial")); } } catch (FileException& e) { addToWarningMessages(e.whatQString()); } } if (brainSet->getBorderSet()->getNumberOfBorders() > 0) { BorderProjectionFile bpf; const QString name = bpf.makeDefaultFileName("LANDMARKS"); try { brainSet->writeBorderProjectionFile(name, "", ""); } catch (FileException& e) { addToWarningMessages(e.whatQString()); } } } } /** * assign paint for padded CUT.FACE nodes. */ void BrainModelVolumeSureFitSegmentation::assignPaddedCutFaceNodePainting(const CoordinateFile* cf, const VolumeFile* segmentVol, PaintFile* pf, const int columnToAssign) { if ((partialHemispherePadding[0] > 0) || (partialHemispherePadding[1] > 0) || (partialHemispherePadding[2] > 0) || (partialHemispherePadding[3] > 0) || (partialHemispherePadding[4] > 0) || (partialHemispherePadding[5] > 0)) { // // Make a copy of the segmentation volume // VolumeFile padVol(*segmentVol); // // Turn on all voxels (all padding) // padVol.setAllVoxels(1); // // Turn off voxels that are not in padding region // const int iStart = partialHemispherePadding[0]; const int iEnd = xDim - partialHemispherePadding[1]; const int jStart = partialHemispherePadding[2]; const int jEnd = yDim - partialHemispherePadding[3]; const int kStart = partialHemispherePadding[4]; const int kEnd = zDim - partialHemispherePadding[5]; for (int i = iStart; i < iEnd; i++) { for (int j = jStart; j < jEnd; j++) { for (int k = kStart; k < kEnd; k++) { padVol.setVoxel(i, j, k, 0, 0); } } } // // Intersect volume with coordinates to for CUT.FACE in geography column // pf->assignPaintColumnWithVolumeFile(&padVol, cf, columnToAssign, "CUT.FACE"); } } /** * generate the surfaces. */ void BrainModelVolumeSureFitSegmentation::generateRawAndFiducialSurfaces(VolumeFile* vf) throw (BrainModelAlgorithmException) { // // Clear surface files from the spec file // try { SpecFile sf; sf.readFile(brainSet->getSpecFileName()); sf.clearFiles(false, true, false, true); sf.writeFile(sf.getFileName()); } catch (FileException& e) { std::cout << "ERROR: clearing surface files from the spec file." << std::endl; } // // Set reconstruction mode // BrainModelVolumeToSurfaceConverter::RECONSTRUCTION_MODE reconMode = BrainModelVolumeToSurfaceConverter::RECONSTRUCTION_MODE_SUREFIT_SURFACE; if (maximumPolygonsFlag) { reconMode = BrainModelVolumeToSurfaceConverter::RECONSTRUCTION_MODE_SUREFIT_SURFACE_MAXIMUM_POLYGONS; } // // Generate the surface // BrainModelVolumeToSurfaceConverter bmvsc(brainSet, vf, reconMode, brainSet->getStructure() == (Structure::STRUCTURE_TYPE_CORTEX_RIGHT), brainSet->getStructure() == (Structure::STRUCTURE_TYPE_CORTEX_LEFT)); bmvsc.execute(); // // name surfaces // for (int i = 0; i < brainSet->getNumberOfBrainModels(); i++) { BrainModelSurface* bms = brainSet->getBrainModelSurface(i); if (bms != NULL) { CoordinateFile* cf = bms->getCoordinateFile(); cf->makeDefaultFileName(bms->getSurfaceTypeName()); if (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FIDUCIAL) { fiducialSurface = bms; } } } // // Name topology files // for (int i = 0; i < brainSet->getNumberOfTopologyFiles(); i++) { TopologyFile* tf = brainSet->getTopologyFile(i); tf->makeDefaultFileName(tf->getTopologyTypeName()); } if (fiducialSurface == NULL) { throw BrainModelAlgorithmException("Generation of fiducial surface failed."); } } /** * create a fiducial surface that is topologically correct. */ void BrainModelVolumeSureFitSegmentation::generateTopologicallyCorrectFiducialSurface() { if (fiducialSurface != NULL) { const TopologyFile* tf = fiducialSurface->getTopologyFile(); if (tf != NULL) { // // An Euler count of 2 means that there are no topological errors in the surface. // If that is the case, there is no need to do correction. // int faces, vertices, edges, eulerCount, holes, objects; tf->getEulerCount(false, faces, vertices, edges, eulerCount, holes, objects); if (eulerCount == 2) { return; } // // Correct the surface // BrainModelSurfaceTopologyCorrector bmstc(brainSet, fiducialSurface); try { bmstc.execute(); // // Use corrected fiducial surface for further processing // fiducialSurface = bmstc.getPointerToNewSurface(); } catch (BrainModelAlgorithmException& e) { // // Let user know correction failed but do not abort segmentation process // std::cout << "WARNING: surface topology correction failed." << std::endl; std::cout << " " << e.whatQString().toAscii().constData() << std::endl; return; } } } // be sure to set the member fiducialSurface !!!! } /** * generate the inflated and ellipsoid surfaces. */ void BrainModelVolumeSureFitSegmentation::generateInflatedAndEllipsoidSurfaces() throw (BrainModelAlgorithmException) { fiducialSurface->createInflatedAndEllipsoidFromFiducial(generateInflatedSurfaceFlag, generateVeryInflatedSurfaceFlag, generateEllipsoidSurfaceFlag, generateSphericalSurfaceFlag, generateCompressedMedialWallSurfaceFlag, true, true, 1.0, NULL); } /** * disconnect the eye. */ void BrainModelVolumeSureFitSegmentation::disconnectEye() throw (BrainModelAlgorithmException) { if (DebugControl::getDebugOn()) { std::cout << "#### DisconnectEye begin ####" << std::endl; } int seed[3]={0,0,0}; //int extent[6]={0,0,0,0,0,0}; //int ACx = acIJK[0]; int ACy = acIJK[1]; int ACz = acIJK[2]; // // Copy the input volume // VolumeFile* volume = new VolumeFile(*anatomyVolume); //DISCONNECT EYE SECTION: //5 if ACz > 0, enter loop: bool EyeFatDisconnectRound2 = true; bool EyeFound = true; if (( ACz > 0) && ( ACy < yDim )) { for (int i = 1 ; i < 9 ; i++) { const float WMhiThreshTemp = wmThresh + (10 * i); if ( WMhiThreshTemp > 255) { if (DebugControl::getDebugOn()) { std::cout << "REACHED THRESH LIMIT" << std::endl; } break; } // // Copy the input volume // delete volume; volume = new VolumeFile(*anatomyVolume); // // Threshold the input volume // volume->thresholdVolume(static_cast(WMhiThreshTemp)); // // Find the biggest object within the specified region // VoxelIJK vijk(seed); volume->findBiggestObjectWithinMask(xAC_15_40_low, xAC_15_40_high, acIJK[1] + 20, yDim, 0, acIJK[2] - 15, 255.0, 255.0, vijk); vijk.getIJK(seed); if ((seed[0] == -1) || (seed[1] == -1) || (seed[2] == -1)) { if (DebugControl::getDebugOn()) { std::cout << "NO EYE FOUND" << std::endl; } EyeFound = false; EyeFatDisconnectRound2 = false; writeDebugVolume(volume, "EyeFat.Flood"); break; } // // Fill the biggest object // volume->floodFillWithVTK(seed, 255, 255, 0); writeDebugVolume(volume, "EyeFat.TestFlood"); // // Find non-zero voxel extent // int extent[6]; volume->findLimits("EyeFat.TestFlood.limits", extent); if (extent[5] < (acIJK[2] + 20)) { if (DebugControl::getDebugOn()) { std::cout << "EYE DISCONNECTED FROM CEREBRUM" << std::endl; } writeDebugVolume(volume, "EyeFat.Flood"); EyeFatDisconnectRound2 = false; break; } } } // if (( ACz > 0) && ( ACy < ydim )) { else { if (DebugControl::getDebugOn()) { std::cout << "No need to disconnect eye (out of volume range)." << std::endl; } EyeFound = false; EyeFatDisconnectRound2 = false; } if (EyeFatDisconnectRound2) { //1/26/2001 EyeFatDisconnectRound2 if previous loop failed to disconnect eye // e.g., brl19_mpr_n4_111_t88_gfc_8bit.L.full.sMRI.mnc if (DebugControl::getDebugOn()) { std::cout << "EYE FAT NOT DISCONNECTED; TRYING SECOND PASS" << std::endl; } for (int i = 1; i < 9; i++) { const float WMhiThreshTemp = wmThresh + (10 * i); if ( WMhiThreshTemp > 255) { if (DebugControl::getDebugOn()) { std::cout << "REACHED THRESH LIMIT BEFORE EYE DISCONNECTED." << std::endl; } throw BrainModelAlgorithmException("REACHED THRESH LIMIT BEFORE EYE DISCONNECTED."); } // // Copy the input volume // delete volume; volume = new VolumeFile(*anatomyVolume); // // Threshold the volume // volume->thresholdVolume(static_cast(WMhiThreshTemp)); // // Set extent for masking the volume // int extent[6] = { xAClow, xAChigh, acIJK[1], acIJK[1] + 35, acIJK[2] - 30, acIJK[2] }; // // Mask the volume to within the extent // volume->maskVolume(extent); // // Stretch the volume values to full range of 0 - 255 // volume->stretchVoxelValues(); writeDebugVolume(volume, "WMhiThreshTemp"); // // Find the biggest object within the specified region // VoxelIJK voxelIJK(seed); volume->findBiggestObjectWithinMask(xAC_15_40_low, xAC_15_40_high, acIJK[1] + 20, yDim, 0, acIJK[2] - 15, 255, 255, voxelIJK); voxelIJK.getIJK(seed); if (( seed[0] == -1 ) || ( seed[1] == -1 ) || ( seed[2] == -1 )) { if (DebugControl::getDebugOn()) { std::cout << "NO EYE FOUND" << std::endl; } writeDebugVolume(volume, "EyeFat.Flood"); break; } // // Flood fille the volume // volume->floodFillWithVTK(seed, 255, 255, 0); writeDebugVolume(volume, "EyeFat.TestFlood"); // // Find non-zero voxel extent // volume->findLimits("EyeFat.TestFlood.limits", extent); if ( extent[5] < ACz-5 ) { if (DebugControl::getDebugOn()) { std::cout << "EYE DISCONNECTED FROM CEREBRUM" << std::endl; } writeDebugVolume(volume, "EyeFat.Flood"); break; } if ( i==8 ) { std::cout << "ERROR IN EYE FAT SEGMENTATION" << std::endl; throw BrainModelAlgorithmException("ERROR IN EYE FAT SEGMENTATION"); } } } if ( EyeFound ) { //SmearAxis.py EyeFat.Flood.mnc EyeFat.SmearVent 2 5 -1 1 //%doSmearAxis (2, 5, -1, 1, voxdataflat, xdim, ydim, zdim); volume->smearAxis(VolumeFile::VOLUME_AXIS_Z, 5, -1, 1); volume->stretchVoxelValues(); writeDebugVolume(volume, "EyeFat.SmearVent"); //%unsigned char* efsvdata=new unsigned char [num_voxels]; //%for ( i=0 ; ishiftAxis(VolumeFile::VOLUME_AXIS_Z, -10); //SmearAxis.py EyeFat.SlideVent.mnc EyeFat.SlideVent_SmearXpos 0 5 1 1 //%doSmearAxis (0, 5, 1, 1, voxdataflat, xdim, ydim, zdim); //%write_minc ("EyeFat.SlideVent_SmearXpos.mnc", voxdataflat, xdim, ydim, zdim); volume->smearAxis(VolumeFile::VOLUME_AXIS_X, 5, 1, 1); volume->stretchVoxelValues(); writeDebugVolume(volume, "EyeFat.SlideVent_SmearXpos"); //SmearAxis.py EyeFat.SlideVent_SmearXpos.mnc EyeFat.SlideVent_SmearXpos_Xneg 0 5 -1 1 //%doSmearAxis (0, 5, -1, 1, voxdataflat, xdim, ydim, zdim); //%write_minc ("EyeFat.SlideVent_SmearXpos_Xneg.mnc", voxdataflat, xdim, ydim, zdim); volume->smearAxis(VolumeFile::VOLUME_AXIS_X, 5, -1, 1); volume->stretchVoxelValues(); // 10/29 writeDebugVolume(volume, "EyeFat.SlideVent_SmearXpos_Xneg"); //CombineVols.py OR EyeFat.SmearVent.mnc EyeFat.SlideVent_SmearXpos_Xneg.mnc EyeFat.SmearVent_MedLat //%CombineVols ("OR", voxdataflat, efsvdata, efsvdata, xdim, ydim, zdim); //%write_minc ("EyeFat.SmearVent_MedLat.mnc", voxdataflat, xdim, ydim, zdim); //%delete [] efsvdata; VolumeFile::performMathematicalOperation(VolumeFile::VOLUME_MATH_OPERATION_OR, volume, &volumeCopy, NULL, volume); volume->stretchVoxelValues(); //10/29 writeDebugVolume(volume, "EyeFat.SmearVent_MedLat"); //3/24/2003: Added mask for Wieser's YL_tlrc.L.full.sMRI.mnc missing temporal pole int extent[6]; extent[0]=0; extent[1]=xDim; extent[2]=ACy+25; extent[3]=yDim; extent[4]=0; extent[5]=zDim; //%MaskVolume (voxdataflat, xdim, ydim, zdim, extent); volume->maskVolume(extent); volume->stretchVoxelValues(); // 10/29 //InvertThresh.py ../$fname CSF.thresh CSFThresh //%unsigned char* csftdata=new unsigned char [num_voxels]; //%for ( i=0 ; i(csfThresh)); writeDebugVolume(&volumeCSF, "CSF.thresh"); //8 Sculpt.py 2 2 xMedLimit_40_low xMedLimit_40_high ACy nrow 0 `expr ACz + 20` EyeFat.SmearVent_MedLat.mnc CSF.thresh.mnc EyeFat.sculpt seed[0] = 0; seed[1] = 0; seed[2] = 0; extent[0] = xMedLimit_50_low; extent[1] = xMedLimit_50_high; extent[2] = ACy; extent[3] = yDim; extent[4] = 0; extent[5] = ACz + 20; //%Sculpt (2, 2, seed, extent, voxdataflat, csftdata, xdim, ydim, zdim); //%write_minc ("EyeFat.sculpt.mnc", voxdataflat, xdim, ydim, zdim); volume->sculptVolume(2, &volumeCSF, 2, seed, extent); volume->stretchVoxelValues(); writeDebugVolume(volume, "EyeFat.sculpt"); //%delete [] csftdata; //Thresh.py ../fname WM.thresh.mnc WMThresh } else { //%for ( i=0 ; isetAllVoxels(0.0); writeDebugVolume(volume, "EyeFat.sculpt"); } // // Copy for use in hind brain removal // eyeFatSculptVolume = new VolumeFile(*volume); //Thresh.py ../$fname WM.thresh.mnc WMThresh //%ThresholdVolume (inputdata, int(WMThresh), xdim,ydim,zdim); //%write_minc ("WhiteMatter.Thresholded.mnc", inputdata, xdim, ydim, zdim); VolumeFile* inputVolume = new VolumeFile(*anatomyVolume); inputVolume->thresholdVolume(static_cast(wmThresh)); writeDebugVolume(inputVolume, "WhiteMatter.Thresholded"); //CombineVols.py subrect WM.thresh.mnc EyeFat.sculpt.mnc WM.thresh_noEye //%CombineVols ("subrect", inputdata, voxdataflat, voxdataflat, xdim, ydim, zdim); //%write_minc ("WM.thresh_noEye.mnc", inputdata, xdim, ydim, zdim); VolumeFile::performMathematicalOperation(VolumeFile::VOLUME_MATH_OPERATION_SUBTRACT_POSITIVE, inputVolume, volume, volume, inputVolume); inputVolume->stretchVoxelValues(); writeDebugVolume(inputVolume, "WM.thresh_noEye"); whiteMatterThreshNoEyeVolume = new VolumeFile(*inputVolume); //%FindBiggestObjectWithinMask (inputdata, xdim, ydim, zdim, //% 0, xdim, 0, ydim, 0, zdim, seed); //%vtkFloodFill (seed, inputdata, 255, 255, 0, xdim, ydim, zdim); //&write_minc ("WM.thresh_noEye.flood.mnc", inputdata, xdim, ydim, zdim); VolumeFile floodVolume(*inputVolume); VoxelIJK seedIJK(seed); floodVolume.findBiggestObjectWithinMask(0, xDim, 0, yDim, 0, zDim, 255.0, 255.0, seedIJK); if (seedIJK.getI() < 0) { throw BrainModelAlgorithmException( "findBiggestObjectWithinMask() failed to find biggest object when\n" "trying to create intermediate volume \"WM.thresh_noEye.flood\"."); } floodVolume.floodFillWithVTK(seedIJK, 255, 255, 0); writeDebugVolume(&floodVolume, "WM.thresh_noEye.flood"); whiteMatterThreshNoEyeFloodVolume = new VolumeFile(floodVolume); delete volume; if (DebugControl::getDebugOn()) { std::cout << "#### DisconnectEye done ####" << std::endl; } } /** * disconnect the hind brain. */ void BrainModelVolumeSureFitSegmentation::disconnectHindBrain() throw (BrainModelAlgorithmException) { if (DebugControl::getDebugOn()) { std::cout << "#### DisconnectHindbrain begin ####" << std::endl; } int ACx = acIJK[0]; int ACy = acIJK[1]; int ACz = acIJK[2]; //%float WMhiThreshTemp; // HINDBRAIN LOOP //%unsigned char* inputdata=new unsigned char [num_voxels]; //%unsigned char* voxdataflat=new unsigned char [num_voxels]; //%unsigned char* hbdata=new unsigned char [num_voxels]; //%unsigned char* wmtnedata=new unsigned char [num_voxels]; //%read_minc_file (mincfile, inputdata); //%if ( lp.skipeye ) {for ( i=0 ; i(wmThresh)); writeDebugVolume(wmtnedata, "WhiteMatter.Thresholded"); } VolumeFile hbdata(inputData); VolumeFile voxdataflat(wmtnedata); freeVolumeInMemory(whiteMatterThreshNoEyeFloodVolume); bool hbloopflag = false; bool hbnull = false; //%int seed[3] = { 0, 0, 0}; //%int extent[6] = { 0, 0, 0, 0, 0, 0 }; if (DebugControl::getDebugOn()) { std::cout << "ACz=" << ACz << " ; ACy=" << ACy << " ; ydim=" << yDim << std::endl; } if (ACz > 0) { hbloopflag = true; } if (yDim < (ACy-60)) { hbloopflag = false; } if ((yDim < (ACy-40)) && (zDim < 10)) { hbloopflag = false; } if ( hbloopflag ) { // PREPARE CUT PLANES //2 MakePlane.py Hem3 ACx 1 ACy 1 ACz -20 2 ../fname CutForHindbrain //%unsigned char* cutdata1=new unsigned char [num_voxels]; //%for ( i=0 ; i yDim) { ymax = yDim; } //%MakePlane (cutdata1, lp.Hem3, float (ACx), 1.0, //% ymax, 1.0, float (ACz), -20.0, 2.0, xdim,ydim,zdim); //%write_minc ("CutForHindbrain.mnc", cutdata1, xdim, ydim, zdim); VolumeFile cutdata1(wmtnedata); cutdata1.setAllVoxels(0.0); cutdata1.makePlane(Hem3, ACx, 1.0, ymax, 1.0, ACz, -20.0, 2.0); voxdataflat = cutdata1; // 10mar05 writeDebugVolume(&cutdata1, "CutForHindbrain"); // 10mar05 voxdataflat.setAllVoxels(0.0); //4 MaskVol.py CutForHindbrain.mnc CutForHindbrain.mask xMedLimit_20_low xMedLimit_20_high 0 nrow 0 `expr ACz + 10 int extent[6]; extent[0] = xMedLimit_20_low; extent[1] = xMedLimit_20_high; extent[2] = 0; extent[3] = yDim; extent[4] = 0; extent[5] = ACz + 10; cutdata1.maskVolume(extent); cutdata1.stretchVoxelValues(); //11/11/2002 - DVE: add lower, wider cut x2+10, z2=ACz extent[1] = xMedLimit_20_high + 10; extent[5] = ACz; voxdataflat.maskVolume(extent); voxdataflat.stretchVoxelValues(); //%CombineVols ("OR", cutdata1, voxdataflat, voxdataflat, xdim, ydim, zdim); //end 11/11/2002 additions //%write_minc ("CutForHindbrain.mask.mnc", cutdata1, xdim, ydim, zdim); VolumeFile::performMathematicalOperation(VolumeFile::VOLUME_MATH_OPERATION_OR, &cutdata1, &voxdataflat, &voxdataflat, &cutdata1); cutdata1.stretchVoxelValues(); writeDebugVolume(&cutdata1, "CutForHindbrain.mask"); //03/16/2001: DVE added next two steps, used later in hindbrain loop //MakePlane.py 0 0 0 0 1 ACz 0 10 ../fname HorizontalCut //%for ( i=0 ; i 255.0) { std::cout << "REACHED THRESH LIMIT BEFORE HINDBRAIN DISCONNECTED" << std::endl; throw BrainModelAlgorithmException("REACHED THRESH LIMIT BEFORE HINDBRAIN DISCONNECTED"); } //%for ( j=0 ; j(WMhiThreshTemp)); //CombineVols.py subrect WM.HiThreshTemp.mnc CutForHindbrain.mask.mnc WMthresh_HindbrainCut //%CombineVols ("subrect", voxdataflat, cutdata1, cutdata1, xdim, ydim, zdim); //%write_minc ("WMthresh_HindbrainCut.mnc", voxdataflat, xdim, ydim, zdim); VolumeFile::performMathematicalOperation(VolumeFile::VOLUME_MATH_OPERATION_SUBTRACT_POSITIVE, &voxdataflat, &cutdata1, &cutdata1, &voxdataflat); voxdataflat.stretchVoxelValues(); std::ostringstream str; str.str(""); str << "WMthresh_HindbrainCut" << i; writeDebugVolume(&voxdataflat, str.str().c_str()); //%for ( j=0 ; j(wmThresh)); writeDebugVolume(&voxdataflat, "WMthresh_HindbrainCut"); } //CombineVols.py subrect WMthresh_HindbrainCut.mnc EyeFat.sculpt.mnc WMHiThresh_noEye_noHB //%unsigned char* efsdata=new unsigned char [num_voxels]; //%if ( lp.skipeye ) {for ( i=0 ; isetAllVoxels(0.0); } // // Added on 8/9/05 per Donna's Au 8, 2005 2:45PM email // if (disconnectHindBrainHiThreshFlag) { VolumeFile::performMathematicalOperation(VolumeFile::VOLUME_MATH_OPERATION_SUBTRACT_POSITIVE, // 10mar2005 &voxdataflat, eyeFatSculptVolume, eyeFatSculptVolume, &voxdataflat); } else { if (disconnectEyeFlag) { VolumeFile::performMathematicalOperation(VolumeFile::VOLUME_MATH_OPERATION_SUBTRACT_POSITIVE, // 10mar2005 whiteMatterThreshNoEyeVolume, hindbrainFloodVolume, hindbrainFloodVolume, &voxdataflat); } else { VolumeFile::performMathematicalOperation(VolumeFile::VOLUME_MATH_OPERATION_SUBTRACT_POSITIVE, // 10mar2005 &wmtnedata, hindbrainFloodVolume, hindbrainFloodVolume, &voxdataflat); } } voxdataflat.stretchVoxelValues(); writeDebugVolume(&voxdataflat, "WMHiThresh_noEye_noHB"); freeVolumeInMemory(eyeFatSculptVolume); freeVolumeInMemory(hindbrainFloodVolume); freeVolumeInMemory(whiteMatterThreshNoEyeVolume); //FillBiggestObject.py WMHiThresh_noEye_noHB.mnc WMHiThresh_noEye_noHB.final xMedLimit_20_low xMedLimit_20_high `expr ACy - 20` `expr ACy + 40` ACz `expr ACz + 30 //12/8/2000 DVE: change y1 to `expr min[ACy, ymin] - 20` //%seed[0]=seed[1]=seed[2]=0; //%int lowy=ACy; //%if (lp.Ymin < ACy) lowy=lp.Ymin; //%FindBiggestObjectWithinMask (voxdataflat, xdim, ydim, zdim, lp.xMedLimit_20_low, lp.xMedLimit_20_high, lowy-20, ACy+40, ACz, ACz+30, seed); //%vtkFloodFill (seed, voxdataflat, 255, 255, 0, xdim, ydim, zdim); //%write_minc ("WMHiThresh_noEye_noHB.final.mnc", voxdataflat, xdim, ydim, zdim); VoxelIJK voxelSeed(0, 0, 0); int lowy = ACy; if (15 < ACy) { lowy = 15; } // if (yMin < ACy) { // lowy = yMin; // } voxdataflat.findBiggestObjectWithinMask(xMedLimit_20_low, xMedLimit_20_high, lowy-20, ACy+40, ACz, ACz+30, 255.0, 255.0, voxelSeed); if (voxelSeed.getI() < 0) { throw BrainModelAlgorithmException( "findBiggestObjectWithinMask() failed to find biggest object when\n" "trying to create intermediate volume \"WMHiThresh_noEye_noHB.final\"."); } voxdataflat.floodFillWithVTK(voxelSeed, 255, 255, 0); writeDebugVolume(&voxdataflat, "WMHiThresh_noEye_noHB.final"); //05/15/2001: Sculpt.py 0 3 $xAClow $xAChigh 0 $ydim 0 $zdim WMHiThresh_noEye_noHB.final.mnc WM.thresh_noEye.mnc CerebralWM_FirstSculpt.mnc int extent[6]; extent[0] = xAClow; extent[1] = xAChigh; extent[2] = 0; extent[3] = yDim; extent[4] = 0; extent[5] = zDim; //%unsigned char* cwmfsdata=new unsigned char [num_voxels]; //%for ( i=0 ; igetGrayWhitePeakEstimates(grayPeakBucketNumber, whitePeakBucketNumber, grayMinimumBucketNumber, whiteMaximumBucketNumber, grayWhiteBoundaryBucketNumber, csfPeakBucketNumber); if (grayMatterPeak <= 0) { grayMatterPeak = hist->getDataValueForBucket(grayPeakBucketNumber); } if (whiteMatterPeak <= 0) { whiteMatterPeak = hist->getDataValueForBucket(whitePeakBucketNumber); } delete hist; } int redoCounter = 0; float threshhold = (grayMatterPeak + whiteMatterPeak) * 0.5; do { redo = false; redoCounter++; if (DebugControl::getDebugOn()) { std::cout << "Redo " << redoCounter << ": Gray: " << grayMatterPeak << " White: " << whiteMatterPeak << " Threshold: " << threshhold << std::endl; } corpusCallosumVolumeFileOut = anatomyVolumeFileIn; corpusCallosumVolumeFileOut.thresholdVolume(threshhold); corpusCallosumVolumeFileOut.convertCoordinatesToVoxelIJK(acXYZ, acIJK); int Hem = 0; if (structure.getType() == Structure::STRUCTURE_TYPE_CORTEX_RIGHT) { Hem = 1; } const int Hem1 = Hem; const int Hem2 = 1 - Hem1; const int HemDbl = 2 * Hem1; const int Hem3 = HemDbl - 1; const int xAC_1 = acIJK[0] + Hem3 * 1; const int xAC_1_low = xAC_1 * Hem2 + acIJK[0] * Hem1; const int xAC_1_high = xAC_1 * Hem1 + acIJK[0] * Hem2; //MaskVol.py WM.thresh.mnc CC.slice xAC_1_low xAC_1_high `expr ACy - 50` `expr ACy + 40` ACz `expr ACz + 40 int extent[6]; extent[0] = xAC_1_low; extent[1] = xAC_1_high; extent[2] = acIJK[1] - 50; extent[3] = acIJK[1] + 40; extent[4] = acIJK[2]; extent[5] = acIJK[2] + 40; //%MaskVolume (ccdata, xdim, ydim, zdim, extent); //%write_minc ("CC.slice.mnc", ccdata, xdim, ydim, zdim); if (looseMask) {/* allow 711-2* origin to not be exactly on the AC */ extent[2] -= 10; extent[3] += 10; extent[4] -= 10; extent[5] += 10; } if (DebugControl::getDebugOn()) { try { QString name = "CC_BeforeMask_" + QString::number(redoCounter) + ".nii.gz"; corpusCallosumVolumeFileOut.setDescriptiveLabel(name); corpusCallosumVolumeFileOut.writeFile(name); } catch (FileException e) { } } corpusCallosumVolumeFileOut.maskVolume(extent); corpusCallosumVolumeFileOut.stretchVoxelValues(); if (DebugControl::getDebugOn()) { try { QString name = "CC_AfterMask_" + QString::number(redoCounter) + ".nii.gz"; corpusCallosumVolumeFileOut.setDescriptiveLabel(name); corpusCallosumVolumeFileOut.writeFile(name); } catch (FileException e) { } } //FillBiggestObject.py CC.slice.mnc CC.slice.fill.mnc xAC_1_low xAC_1_high `expr ACy - 50` `expr ACy + 40` ACz `expr ACz + 40 //%FindBiggestObjectWithinMask (ccdata, xdim, ydim, zdim, extent[0],extent[1],extent[2],extent[3],extent[4],extent[5], seed); //%vtkFloodFill (seed, ccdata, 255, 255, 0, xdim, ydim, zdim); //%write_minc ("CorpusCallosumSlice.mnc", ccdata, xdim, ydim, zdim); VoxelIJK voxelSeed(0, 0, 0); corpusCallosumVolumeFileOut.findBiggestObjectWithinMask(extent, 255, 255, voxelSeed); if (voxelSeed.getI() < 0) { if (grayMatterPeakIn > 0.0f && whiteMatterPeakIn > 0.0f) { throw BrainModelAlgorithmException( "findBiggestObjectWithinMask() failed to find biggest object when\n" "trying to create intermediate volume \"CorpusCallosumSlice\"."); } else { //cout << "threshhold " << threshhold << ": findBiggestObjectWithinMask() failed" << endl; voxMax = threshhold; redo = true; } } if (!redo) { corpusCallosumVolumeFileOut.floodFillWithVTK(voxelSeed, 255, 255, 0); if (DebugControl::getDebugOn()) { try { QString name = "CC_FloodFill_" + QString::number(redoCounter) + ".nii.gz"; corpusCallosumVolumeFileOut.setDescriptiveLabel(name); corpusCallosumVolumeFileOut.writeFile(name); } catch (FileException e) { } } corpusCallosumVolumeFileOut.setDescriptiveLabel("CorpusCallosumSlice"); // // Get extent of volume // corpusCallosumVolumeFileOut.getNonZeroVoxelExtent(dimExtent, coordExtent);//doesn't use normal "one-after" array size conventions if (dimExtent[0] == -1) { //cout << "threshhold " << threshhold << ": no nonzero extent found" << endl; voxMax = threshhold; redo = true; } } if (!redo && fabs(coordExtent[3] - coordExtent[2]) < 50.0f) { //cout << "threshhold " << threshhold << ": y coord extent too small" << endl; voxMax = threshhold; redo = true; } if (!redo && fabs((coordExtent[3] - coordExtent[2]) * (coordExtent[5] - coordExtent[4])) > 2900.0f) { //cout << "threshhold " << threshhold << ": yz extent too large" << endl; voxMin = threshhold; redo = true; } if (!redo && fabs(coordExtent[5] - coordExtent[4]) > 45.0f) {//can only be tripped when looseMask is true //cout << "threshhold " << threshhold << ": z coord extent too big" << endl; voxMin = threshhold; redo = true; } if (!redo) { i = (dimExtent[0] + dimExtent[1]) / 2;//only need to look at the middle slice count = 0; total = (dimExtent[3] - dimExtent[2] + 1) * (dimExtent[5] - dimExtent[4] + 1); for (j = dimExtent[2]; j <= dimExtent[3]; ++j) { for (k = dimExtent[4]; k <= dimExtent[5]; ++k) { if (corpusCallosumVolumeFileOut.getVoxel(i, j, k) > 0.0f) { ++count; } } } //cout << "threshhold " << threshhold << ": " << count << " / " << total; if (count < total * 0.25f) { //cout << ", too few voxels" << endl; voxMax = threshhold; redo = true; } else { if (count > total * 0.55f) { //cout << ", too many voxels" << endl; voxMin = threshhold; redo = true; } else { //cout << ", acceptable" << endl; } } } threshhold = (voxMin + voxMax + threshhold) / 3.0f;//its like bisection search, except it moves slower so it doesnt try crazy values if (redo && voxMax != 0.0f && voxMin / voxMax > 0.98f) {//warning: give up check expects voxels to have minimum of 0 //cout << "giving up" << endl; redo = false; } } while (grayMatterPeakIn <= 0 && whiteMatterPeakIn <= 0 && redo); } /** * cut the corpus callossum. */ void BrainModelVolumeSureFitSegmentation::cutCorpusCallossum() throw (BrainModelAlgorithmException) { //%printf("#### CutCorpusCallossum begin ####\n"); if (DebugControl::getDebugOn()) { std::cout << "#### CutCorpusCallossum begin ####" << std::endl; } //%int i, j; //%int seed[3]={0,0,0}; //%int extent[6]={0,0,0,0,0,0}; //%int xdim=lp.xdim; //%int ydim=lp.ydim; //%int zdim=lp.zdim; //%int num_voxels=xdim*ydim*zdim; //%int ACy=lp.ACy; //%int ACz=lp.ACz; //%float WMThresh=lp.WMThresh; //%unsigned char* ccdata=new unsigned char [num_voxels]; //%read_minc_file (mincfile, ccdata); //Thresh.py ../$fname WM.thresh.mnc WMThresh //%ThresholdVolume (ccdata, int(WMThresh), xdim,ydim,zdim); VolumeFile ccdata = *anatomyVolume; ccdata.thresholdVolume(static_cast(wmThresh)); // // Were both eye removal and hindbrain removal skipped ? // if ((disconnectEyeFlag == false) && (disconnectHindBrainFlag == false)) { cerebralWmNoBstemFill = new VolumeFile(ccdata); } //MaskVol.py WM.thresh.mnc CC.slice xAC_1_low xAC_1_high `expr ACy - 50` `expr ACy + 40` ACz `expr ACz + 40 int extent[6]; extent[0] = xAC_1_low; extent[1] = xAC_1_high; extent[2] = acIJK[1] - 50; extent[3] = acIJK[1] + 40; extent[4] = acIJK[2]; extent[5] = acIJK[2] + 40; if (DebugControl::getDebugOn()) { std::cout << "CC LIMITS: " << extent[0] << "-" << extent[1] << "-" << extent[2] << "-" << extent[3] << "-" << extent[4] << "-" << extent[5] << std::endl; } //%MaskVolume (ccdata, xdim, ydim, zdim, extent); //%write_minc ("CC.slice.mnc", ccdata, xdim, ydim, zdim); ccdata.maskVolume(extent); ccdata.stretchVoxelValues(); writeDebugVolume(&ccdata, "CC.slice"); //FillBiggestObject.py CC.slice.mnc CC.slice.fill.mnc xAC_1_low xAC_1_high `expr ACy - 50` `expr ACy + 40` ACz `expr ACz + 40 //%FindBiggestObjectWithinMask (ccdata, xdim, ydim, zdim, extent[0],extent[1],extent[2],extent[3],extent[4],extent[5], seed); //%vtkFloodFill (seed, ccdata, 255, 255, 0, xdim, ydim, zdim); //%write_minc ("CorpusCallosumSlice.mnc", ccdata, xdim, ydim, zdim); VoxelIJK voxelSeed(0, 0, 0); ccdata.findBiggestObjectWithinMask(extent, 255, 255, voxelSeed); if (voxelSeed.getI() < 0) { throw BrainModelAlgorithmException( "findBiggestObjectWithinMask() failed to find biggest object when\n" "trying to create intermediate volume \"CorpusCallosumSlice\"."); } ccdata.floodFillWithVTK(voxelSeed, 255, 255, 0); //writeDebugVolume(&ccdata, "CorpusCallosumSlice"); // // Now save the corpus callosum slice volume (30 July 2007) // which will be used for sulcal ID // { QString fileNameWritten, dataFileNameWritten; ccdata.setDescriptiveLabel("CorpusCallosumSlice"); VolumeFile::writeVolumeFile(&ccdata, typeOfVolumeFilesToWrite, "CorpusCallosumSlice", false, fileNameWritten, dataFileNameWritten); } //%FindLimits (xdim, ydim, zdim, ccdata, "CC.slice.fill.limits", extent); ccdata.findLimits("CC.slice.fill.limits", extent); // TO-DO: Write CC* values to params file int CCpost=extent[2]; int CCant=extent[3]; int CCvent=extent[4]; int CCdors=extent[5]; //%printf("CCpost=%d ; CCant=%d ; CCvent=%d ; CCdors=%d\n", CCpost, CCant, CCvent, Ccdors); if (DebugControl::getDebugOn()) { std::cout << "CCpost=" << CCpost << " ; " << "CCant=" << CCant << " ; " << "CCvent=" << CCvent << " ; " << "CCdors=" << CCdors << std::endl; } //24 VolMorphOps.py 3 0 CerebralWM_noBstem.fill.mnc CerebralWM_noBstem.dilate.mnc //%unsigned char* cwmnbsfdata=new unsigned char [num_voxels]; //%unsigned char* cwmnbsfdilatedata=new unsigned char [num_voxels]; //%read_minc_file ("CerebralWM_noBstem.fill.mnc", cwmnbsfdata); //%for ( i=0 ; i CCpost) { extent[2] = CCpost; extent[3] = CCant; } else { extent[2] = 0; extent[3] = yDim; } if ( CCdors > acIJK[2] ) { extent[4] = acIJK[2]; extent[5] = CCdors; } else { extent[4] = 0; extent[5] = zDim; } //%FindBiggestObjectWithinMask (cwmnbsfdata, xdim, ydim, zdim, extent[0],extent[1],extent[2],extent[3],extent[4],extent[5], seed); //%vtkFloodFill (seed, cwmnbsfdata, 255, 255, 0, xdim, ydim, zdim); //%unsigned char* cwmdata=new unsigned char [num_voxels]; //%for ( j=0 ; jgetSpecies().isHuman()) { dilerodes = 3; } cwmnbsfdata.makeShellVolume(dilerodes, dilerodes); //cwmnbsfdata.makeShellVolume(3, 3); cwmnbsfdata.stretchVoxelValues(); writeDebugVolume(cwmnbsfdata, "InnerMask.1"); innerMask1Volume = new VolumeFile(cwmnbsfdata); //33 MakeShell.py 6 1 CerebralWhiteMatter.mnc OuterMask.1 //%for ( j=0 ; jgetSpecies().isHuman()) { dilations = 6; } cwmnbsfdata.makeShellVolume(dilations, 1); cwmnbsfdata.stretchVoxelValues(); writeDebugVolume(cwmnbsfdata, "OuterMask.1"); outerMaskVolume = new VolumeFile(cwmnbsfdata); //%printf("#### CutCorpusCallossum done ####\n"); //%delete [] cwmdata; //%delete [] cwmnbsfdata; //%printf("#### CutCorpusCallossum end ####\n"); //%return 0; if (DebugControl::getDebugOn()) { std::cout << "#### CutCorpusCallossum done ####" << std::endl; std::cout << "#### CutCorpusCallossum end ####" << std::endl; } } /** * generate the inner boundary. */ void BrainModelVolumeSureFitSegmentation::generateInnerBoundary() throw (BrainModelAlgorithmException) { //%printf("#### GenerateInnerBoundary begin ####\n"); if (DebugControl::getDebugOn()) { std::cout << "#### GenerateInnerBoundary begin ####" << std::endl; } //%int i, extent[6]; //%int xdim=lp.xdim; //%int ydim=lp.ydim; //%int zdim=lp.zdim; //%int ACy=lp.ACy; //%int ACz=lp.ACz; //%int num_voxels=xdim*ydim*zdim; //%float WMpeak=lp.WMpeak; //%float CGMpeak=lp.CGMpeak; //%unsigned char* inputdata=new unsigned char [num_voxels]; //%read_minc_file (mincfile, inputdata); //1 //%unsigned char* voxdataflat=new unsigned char [num_voxels]; //%for ( i=0 ; iexecute(); delete bmvg; bmvg = NULL; voxdataflat.stretchVoxelValues(); gradIntensityVecFile = new SureFitVectorFile(vec); writeDebugVector(vec, "Intensity.grad"); //2 //%unsigned char* intgraddata=new unsigned char [num_voxels]; //%for ( i=0 ; i(vec.getMagnitudeWithFlatIndex(i)); voxdataflat.setVoxelWithFlatIndex(i, 0, value); intgraddata.setVoxelWithFlatIndex(i, 0, value); } writeDebugVolume(voxdataflat, "Intensity.grad"); gradIntensityVolume = new VolumeFile(voxdataflat); //3 //%float GWdiff=WMpeak-CGMpeak; //%float GWgradpeak=GWdiff/2; //%float GWgradlow=GWgradpeak/2; //%float GWgradhigh=GWgradpeak*2; //%float GWgradsignum=1.5; //%ClassifyIT (GWgradpeak, GWgradlow, GWgradhigh, GWgradsignum, voxdataflat, xdim, ydim, zdim); //%write_minc ("Grad.GWlevel.mnc", voxdataflat, xdim, ydim, zdim); const float gwDiff = wmPeak - cgmPeak; const float gwGradPeak = gwDiff / 2.0; const float gwGradLow = gwGradPeak / 2.0; const float gwGradHigh = gwGradPeak * 2.0; const float gwGradSignum = 1.5; voxdataflat.classifyIntensities(gwGradPeak, gwGradLow, gwGradHigh, gwGradSignum); voxdataflat.stretchVoxelValues(); writeDebugVolume(voxdataflat, "Grad.GWlevel"); //4 //%CombineVectorVolume ("replacemag", xdim, ydim, zdim, vec.X, vec.Y, vec.Z, vec.Mag, voxdataflat); //%vec.WriteRaw ("Grad.GWlevel.vec"); //NEW 2000-10-14 begin //%float ThinWMgradpeak=GWdiff/4.0; //%float ThinWMgradlow=ThinWMgradpeak/2.0; //%float ThinWMgradhigh=ThinWMgradpeak*2.0; //%for ( i=0 ; iexecute(); //{ // float vx, vy, vz; // vec.getVectorWithFlatIndex(30028, vx, vy, vz); // std::cout << "vec 30028 : " << vx << ", " << vy << ", " << vz << ", " // << vec.getMagnitudeWithFlatIndex(30028) << std::endl; //} delete bmvg; bmvg = NULL; voxdataflat.stretchVoxelValues(); writeDebugVector(vec, "GM.grad"); //8 //%for ( i=0 ; iexecute(); } catch (BrainModelAlgorithmException& e) { throw BrainModelAlgorithmException(e.whatQString()); } delete bmvntp; voxdataflat.stretchVoxelValues(); VolumeFile twmdata(voxdataflat); freeVectorInMemory(gradThinWMlevelVecFile); //14 //%BlurFil(voxdataflat, xdim, ydim, zdim); //%write_minc ("ThinWM.blur.mnc", voxdataflat, xdim, ydim, zdim); voxdataflat.blur(); voxdataflat.stretchVoxelValues(); writeDebugVolume(voxdataflat, "ThinWM.blur"); //15 This part extensively revised by DVE 6/5/2000 //%for ( i=0 ; igetSpecies().isHuman() == false) { voxdataflat = *inTotalVolume; } voxdataflat.blur(); voxdataflat.stretchVoxelValues(); writeDebugVolume(voxdataflat, "In.Total.blur1"); inTotalBlur1Volume = new VolumeFile(voxdataflat); //%delete [] voxdataflat; //%printf("#### GenerateInnerBoundary end ####\n"); //%return 0; if (DebugControl::getDebugOn()) { std::cout << "#### GenerateInnerBoundary end ####" << std::endl; } } /** * generate the outer boundary. */ void BrainModelVolumeSureFitSegmentation::generateOuterBoundary() throw (BrainModelAlgorithmException) { //%printf("#### GenerateOuterBoundary begin ####\n"); if (DebugControl::getDebugOn()) { std::cout << "#### GenerateOuterBoundary ####" << std::cout; } //%int i; //%int xdim=lp.xdim; //%int ydim=lp.ydim; //%int zdim=lp.zdim; //%int num_voxels=xdim*ydim*zdim; //%unsigned char* outitdata=new unsigned char [num_voxels]; //%read_minc_file (mincfile, outitdata); VolumeFile outitdata = *anatomyVolume; //1 //%ClassifyIT (lp.OutITpeak, lp.OutITlow, lp.OutIThigh, lp.OutITsignum, outitdata, xdim, ydim, zdim); //%write_minc ("OutIT.mnc", outitdata, xdim, ydim, zdim); outitdata.classifyIntensities(outITPeak, outITLow, outITHigh, outITSignum); outitdata.stretchVoxelValues(); writeDebugVolume(outitdata, "OutIT"); //2 //%float PiaGradpeak=lp.CGMpeak*2/3.0; //%float PiaGradlow=PiaGradpeak/2.0; //%float PiaGradhigh=PiaGradpeak*3/2.0; //%float PiaGradsignum=1.0; //%unsigned char* voxdataflat=new unsigned char [num_voxels]; //%read_minc_file ("Intensity.grad.mnc", voxdataflat); //%ClassifyIT (PiaGradpeak, PiaGradlow, PiaGradhigh, PiaGradsignum, //% voxdataflat, xdim, ydim, zdim); //%write_minc ("Grad.PiaLevel.mnc", voxdataflat, xdim, ydim, zdim); const float piaGradPeak = cgmPeak * 2.0 / 3.0; const float piaGradLow = piaGradPeak / 2.0; const float piaGradHigh = piaGradPeak * 3.0 / 2.0; const float piaGradSignum = 1.0; VolumeFile voxdataflat = *gradIntensityVolume; voxdataflat.classifyIntensities(piaGradPeak, piaGradLow, piaGradHigh, piaGradSignum); voxdataflat.stretchVoxelValues(); writeDebugVolume(voxdataflat, "Grad.PiaLevel"); freeVolumeInMemory(gradIntensityVolume); //3 //%Vector vec("Intensity.grad.vec", xdim, ydim, zdim); //%CombineVectorVolume ("replacemag", xdim, ydim, zdim, vec.X, vec.Y, vec.Z, vec.Mag, voxdataflat); //%vec.WriteRaw ("Grad.PiaLevel.vec"); SureFitVectorFile vec = *gradIntensityVecFile; vec.combineWithVolumeOperation(SureFitVectorFile::COMBINE_VOLUME_REPLACE_MAGNITUDE_WITH_VOLUME, &voxdataflat); writeDebugVector(vec, "Grad.PiaLevel"); gradPiaLevelVec = new SureFitVectorFile(vec); //4 //%unsigned char* soliddata=new unsigned char [num_voxels]; //%for ( i=0 ; iexecute(); } catch (BrainModelAlgorithmException& e) { throw BrainModelAlgorithmException(e.whatQString()); } writeDebugVector(vec, "InvertGM.grad"); delete bmvg; bmvg = NULL; soliddata.stretchVoxelValues(); //7 //%for ( i=0 ; iexecute(); delete bmvntp; bmvntp = NULL; voxdataflat.stretchVoxelValues(); writeDebugVolume(voxdataflat, "Out.Near2In"); freeVolumeInMemory(outerMaskVolume); freeVectorInMemory(gradInTotalThinWMVecFile); //%for ( i=0 ; igetSpecies().isHuman()) { maskdata = *thinWMOrNearVentricleHCMask; VolumeFile::performMathematicalOperation( VolumeFile::VOLUME_MATH_OPERATION_SUBTRACT_POSITIVE, &voxdataflat, &maskdata, &maskdata, &voxdataflat); voxdataflat.stretchVoxelValues(); } writeDebugVolume(voxdataflat, "Out.Near2In.sqrt_notThinWM.HCmask"); vec = *gradIntensityVecFile; vec.combineWithVolumeOperation(SureFitVectorFile::COMBINE_VOLUME_REPLACE_MAGNITUDE_WITH_VOLUME, &voxdataflat); writeDebugVector(vec, "Out.Near2In"); freeVolumeInMemory(thinWMOrNearVentricleHCMask); //16 //%maskflag=0; //%operation=2; //2vec //%for ( i=0 ; igetSpecies().isHuman()) { maskdata = *ventGradLevelBlurVolume; VolumeFile::performMathematicalOperation( VolumeFile::VOLUME_MATH_OPERATION_SUBTRACT_POSITIVE, &voxdataflat, &maskdata, &maskdata, &voxdataflat); voxdataflat.stretchVoxelValues(); } writeDebugVolume(voxdataflat, "Out.Total_notVentricle"); writeDebugVolume(voxdataflat, "OuterBoundary"); //18 //%BlurFil(voxdataflat, xdim, ydim, zdim); //%write_minc ("Out.Total.blur1.mnc", voxdataflat, xdim, ydim, zdim); voxdataflat.blur(); voxdataflat.stretchVoxelValues(); writeDebugVolume(voxdataflat, "Out.Total.blur1"); outTotalBlur1Volume = new VolumeFile(voxdataflat); // Clean up //%delete [] maskdata; //%delete [] voxdataflat; //%printf("#### GenerateOuterBoundary end ####\n"); //%return 0; if (DebugControl::getDebugOn()) { std::cout << "#### GenerateOuterBoundary end ####" << std::endl; } } /** * generate the segmentation. */ void BrainModelVolumeSureFitSegmentation::generateSegmentation() throw (BrainModelAlgorithmException) { //%printf("#### GenerateSegmentation begin ####\n"); if (DebugControl::getDebugOn()) { std::cout << "#### GenerateSegmentation begin ####" << std::endl; } //%int i, seed[3]; //%int xdim=lp.xdim; //%int ydim=lp.ydim; //%int zdim=lp.zdim; //%int num_voxels=xdim*ydim*zdim; //%float WMThresh=lp.WMThresh; //%unsigned char* voxdataflat=new unsigned char [num_voxels]; //%unsigned char* maskdata=new unsigned char [num_voxels]; VolumeFile voxdataflat(*anatomyVolume); VolumeFile maskdata(*anatomyVolume); //%if ( extractmaskflag == TRUE ) { //% read_minc_file ("In.Total.blur1.mnc", voxdataflat); //% read_minc_file ("InnerMask.1.mnc", maskdata); //% CombineVols ("mult", voxdataflat, maskdata, maskdata, xdim, ydim, zdim); //% write_minc ("In.Total.blur.mask.mnc", voxdataflat, xdim, ydim, zdim); //% read_minc_file ("CerebralWM.erode.mnc", maskdata); //%} //%else { //% //1 Thresh.py ../$fname WM.thresh.mnc WMThresh //% read_minc_file (mincfile, maskdata); //% ThresholdVolume (maskdata, int(WMThresh), xdim,ydim,zdim); //% write_minc ("WhiteMatter.Thresholded.mnc", maskdata, xdim, ydim, zdim); //% //2 FillBiggestObject.py WM.thresh.mnc WM.thresh.flood.mnc 0 ncol 0 nrow 0 nslices //% FindBiggestObjectWithinMask (voxdataflat, xdim, ydim, zdim, 0, xdim, 0, ydim, 0, zdim, seed); //% if (( seed[0] == -1 ) || ( seed[1] == -1 ) || ( seed[2] == -1 )) { //% printf("Exiting: Null volume\n"); //% return 1; //% } //% vtkFloodFill (seed, maskdata, 255, 255, 0, xdim, ydim, zdim); //% write_minc ("WM.thresh.flood.mnc", maskdata, xdim, ydim, zdim); //% //3 VolMorphOps.py 0 2 WM.thresh.flood.mnc WM.thresh.erode.mnc //% DoVolMorphOps (xdim, ydim, zdim, maskdata, 0, 2); //% write_minc ("WM.thresh.erode.mnc", maskdata, xdim, ydim, zdim); //% read_minc_file ("In.Total.blur1.mnc", voxdataflat); //%} if (extractMaskFlag) { voxdataflat = *inTotalBlur1Volume; maskdata = *innerMask1Volume; VolumeFile::performMathematicalOperation( VolumeFile::VOLUME_MATH_OPERATION_MULTIPLY, &voxdataflat, &maskdata, &maskdata, &voxdataflat); voxdataflat.stretchVoxelValues(); writeDebugVolume(voxdataflat, "In.Total.blur.mask"); maskdata = *cerebralWMErodeVolume; } else { maskdata = *anatomyVolume; maskdata.thresholdVolume(static_cast(wmThresh)); writeDebugVolume(maskdata, "WhiteMatter.Thresholded"); VoxelIJK voxelSeed(0, 0, 0); voxdataflat.findBiggestObjectWithinMask(0, xDim, 0, yDim, 0, zDim, 255.0, 255.0, voxelSeed); if (voxelSeed.getI() < 0) { throw BrainModelAlgorithmException( "findBiggestObjectWithinMask() failed to find biggest object when\n" "trying to create intermediate volume \"WM.thresh.flood\"."); } maskdata.floodFillWithVTK(voxelSeed, 255, 255, 0); writeDebugVolume(maskdata, "WM.thresh.flood"); wmThreshFloodVolume = new VolumeFile(maskdata); maskdata.doVolMorphOps(0, 2); writeDebugVolume(maskdata, "WM.thresh.erode"); voxdataflat = *inTotalBlur1Volume; } freeVolumeInMemory(innerMask1Volume); freeVolumeInMemory(inTotalBlur1Volume); //4 CombineVolsDiffRatio.py ../INNER.BOUNDARY/In.Total.blur1.mnc ../OUTER.BOUNDARY/Out.Total.blur1.mnc WM.thresh.erode.mnc InOutDiff.mag.mnc //%unsigned char* outtotalblurdata=new unsigned char [num_voxels]; //%read_minc_file ("Out.Total.blur1.mnc", outtotalblurdata); VolumeFile outtotalblurdata = *outTotalBlur1Volume; freeVolumeInMemory(outTotalBlur1Volume); //%CombineVols ("diffratio", voxdataflat, outtotalblurdata, maskdata, xdim, ydim, zdim); //%write_minc ("InOutDiff.mag.mnc", voxdataflat, xdim, ydim, zdim); //%write_minc ("RadialPositionMap.Initial.mnc", voxdataflat, xdim, ydim, zdim); //%delete [] outtotalblurdata; //%unsigned char* rpmdata=new unsigned char [num_voxels]; //%for ( i=0 ; i(inOutDiffThresh)); writeDebugVolume(voxdataflat, "InOutDiff.thresh"); VolumeFile inoutdiffthreshdata = voxdataflat; //6 FillBiggestObject.py InOutDiff.thresh.mnc InOutDiff.flood.mnc 0 ncol 0 nrow 0 nslices //%FindBiggestObjectWithinMask (voxdataflat, xdim, ydim, zdim, 0, xdim, 0, ydim, 0, zdim, seed); //%if (( seed[0] == -1 ) || ( seed[1] == -1 ) || ( seed[2] == -1 )) { //% printf("Exiting: Null volume\n"); //% return 1; //%} //%vtkFloodFill (seed, voxdataflat, 255, 255, 0, xdim, ydim, zdim); //%write_minc ("InOutDiff.flood.mnc", voxdataflat, xdim, ydim, zdim); VoxelIJK voxelSeed(0, 0, 0); voxdataflat.findBiggestObjectWithinMask(0, xDim, 0, yDim, 0, zDim, 255.0, 255.0, voxelSeed); if (voxelSeed.getI() < 0) { throw BrainModelAlgorithmException( "findBiggestObjectWithinMask() failed to find biggest object when\n" "trying to create intermediate volume \"InOutDiff.flood\"."); } voxdataflat.floodFillWithVTK(voxelSeed, 255, 255, 0); writeDebugVolume(voxdataflat, "InOutDiff.flood"); //7 Grad.py 1 InTotal.grad ../INNER.BOUNDARY/In.Total.mnc //%read_minc_file ("In.Total.mnc", voxdataflat); //%Vector vec("", xdim, ydim, zdim); //%Grad (1, "InTotal.grad", voxdataflat, vec.X, vec.Y, vec.Z, vec.Mag, xdim, ydim, zdim); //%for ( i=0 ; iexecute(); delete bmvg; bmvg = NULL; writeDebugVector(vec, "InTotal.grad"); SureFitVectorFile inTotalGradVector = vec; vec.copyMagnitudeToVolume(&voxdataflat); writeDebugVolume(voxdataflat, "InTotal.grad"); freeVolumeInMemory(inTotalVolume); //9 Grad.py 1 OutTotal.grad ../OUTER.BOUNDARY/Out.Total.mnc //%read_minc_file ("Out.Total.mnc", voxdataflat); //%Grad (1, "OutTotal.grad", voxdataflat, vec.X, vec.Y, vec.Z, vec.Mag, xdim, ydim, zdim); voxdataflat = *outTotalVolume; bmvg = new BrainModelVolumeGradient(brainSet, 1, true, false, &voxdataflat, &voxdataflat, &vec); bmvg->execute(); delete bmvg; bmvg = NULL; writeDebugVector(vec, "OutTotal.grad"); freeVolumeInMemory(outTotalVolume); //10 ViewVector.py OutTotal.grad.vec ../$fname OutTotal.grad //%for ( i=0 ; iexecute(); delete bmvntp; bmvntp = NULL; voxdataflat.stretchVoxelValues(); writeDebugVolume(voxdataflat, "PialTrough"); //15 VolMorphOps.py 1 0 CerebralWM.flood.mnc CerebralWM.flood.dilate.mnc //%if ( extractmaskflag == TRUE ) read_minc_file ("CerebralWM.erode.mnc", maskdata); //%else read_minc_file ("WM.thresh.flood.mnc", maskdata); //%DoVolMorphOps (xdim, ydim, zdim, maskdata, 1, 0); //%write_minc ("CerebralWM.flood.dilate.mnc", maskdata, xdim, ydim, zdim); if (extractMaskFlag) { maskdata = *cerebralWMErodeVolume; } else { maskdata = *wmThreshFloodVolume; } maskdata.doVolMorphOps(1, 0); writeDebugVolume(maskdata, "CerebralWM.flood.dilate"); freeVolumeInMemory(wmThreshFloodVolume); freeVolumeInMemory(cerebralWMErodeVolume); //16 CombineVols.py subrect PialTrough.mnc CerebralWM.flood.dilate.mnc PialTrough_noCerebralWM.mnc //%CombineVols ("subrect", voxdataflat, maskdata, maskdata, xdim, ydim, zdim); //%write_minc ("PialTrough_noCerebralWM.mnc", voxdataflat, xdim, ydim, zdim); // New step added 6/5/2000: //%read_minc_file ("VentGradLevel.blur.mask.mnc", maskdata); //%CombineVols ("subrect", voxdataflat, maskdata, maskdata, xdim, ydim, zdim); //%write_minc ("PialTrough_Trimmed.mnc", voxdataflat, xdim, ydim, zdim); //%delete [] maskdata; VolumeFile::performMathematicalOperation( VolumeFile::VOLUME_MATH_OPERATION_SUBTRACT_POSITIVE, &voxdataflat, &maskdata, &maskdata, &voxdataflat); voxdataflat.stretchVoxelValues(); writeDebugVolume(voxdataflat, "PialTrough_noCerebralWM"); // // 7/24/2008 DLD added species condition to reduce chimp occipital smearing // if (brainSet->getSpecies().isHuman()) { maskdata = *ventGradLevelBlurVolume; VolumeFile::performMathematicalOperation( VolumeFile::VOLUME_MATH_OPERATION_SUBTRACT_POSITIVE, &voxdataflat, &maskdata, &maskdata, &voxdataflat); voxdataflat.stretchVoxelValues(); } writeDebugVolume(voxdataflat, "PialTrough_Trimmed"); freeVolumeInMemory(ventGradLevelBlurVolume); //17 CombineVols.py subrect InOutDiff.mag.mnc PialTrough_Trimmed.mnc InOutDiff_noPialTrough.mnc //%CombineVols ("subrect", rpmdata, voxdataflat, voxdataflat, xdim, ydim, zdim); //%write_minc ("InOutDiff_noPialTrough.mnc", rpmdata, xdim, ydim, zdim); //%write_minc ("RadialPositionMap.mnc", rpmdata, xdim, ydim, zdim); //%delete [] voxdataflat; VolumeFile::performMathematicalOperation( VolumeFile::VOLUME_MATH_OPERATION_SUBTRACT_POSITIVE, &rpmdata, &voxdataflat, &voxdataflat, &rpmdata); rpmdata.stretchVoxelValues(); writeDebugVolume(&rpmdata, "InOutDiff_noPialTrough"); try { QString fileNameWritten, dataFileNameWritten; rpmdata.setDescriptiveLabel("RadialPositionMap"); VolumeFile::writeVolumeFile(&rpmdata, typeOfVolumeFilesToWrite, "RadialPositionMap", false, fileNameWritten, dataFileNameWritten); //rpmdata.writeFile("RadialPositionMap+orig.HEAD"); //brainSet->writeVolumeFile("RadialPositionMap+orig.HEAD", // VolumeFile::FILE_READ_WRITE_TYPE_AFNI, // VolumeFile::VOLUME_TYPE_FUNCTIONAL, // &rpmdata); } catch (FileException& e) { throw BrainModelAlgorithmException(e.whatQString()); } //18 Thresh.py InOutDiff_noPialTrough.mnc InOutDiff_noPialTrough.thresh.mnc InOutDiffThresh //%ThresholdVolume (rpmdata, InOutDiffThresh, xdim,ydim,zdim); //%write_minc ("InOutDiff_noPialTrough.thresh.mnc", rpmdata, xdim, ydim, zdim); rpmdata.thresholdVolume(static_cast(inOutDiffThresh)); writeDebugVolume(rpmdata, "InOutDiff_noPialTrough.thresh"); //19 FillBiggestObject.py InOutDiff_noPialTrough.thresh.mnc InOutDiff_final.mnc 0 ncol 0 nrow 0 nslices //%FindBiggestObjectWithinMask (rpmdata, xdim, ydim, zdim, 0, xdim, 0, ydim, 0, zdim, seed); //%if (( seed[0] == -1 ) || ( seed[1] == -1 ) || ( seed[2] == -1 )) { //% printf("Exiting: Null volume\n"); //% return 1; //%} //%vtkFloodFill (seed, rpmdata, 255, 255, 0, xdim, ydim, zdim); //%write_minc ("InOutDiff_final.mnc", rpmdata, xdim, ydim, zdim); // Added 10/13/2000: FillHoles.py InOutDiff_final.mnc InOutDiff_final.fill.mnc //%NewDoFillHoles (xdim, ydim, zdim, rpmdata); //%write_minc ("InOutDiff_final.fill.mnc", rpmdata, xdim, ydim, zdim); //%write_minc ("Segment.mnc", rpmdata, xdim, ydim, zdim); rpmdata.findBiggestObjectWithinMask(0, xDim, 0, yDim, 0, zDim, 255.0, 255.0, voxelSeed); if (voxelSeed.getI() < 0) { throw BrainModelAlgorithmException( "findBiggestObjectWithinMask() failed to find biggest object when\n" "trying to create intermediate volume \"InOutDiff_final\"."); } rpmdata.floodFillWithVTK(voxelSeed, 255, 255, 0); writeDebugVolume(rpmdata, "InOutDiff_final"); rpmdata.fillSegmentationCavities(); writeDebugVolume(rpmdata, "InOutDiff_final.fill"); writeDebugVolume(rpmdata, "Segment"); segmentationVolume = new VolumeFile(rpmdata); //TO-DO: volume.AddMincHeaderLine ("correction_cycle", "0", segfinalfname) //20 (moved/changed after 21 10/25/2000): //MakeShell.py 1 0 Segmentation.mnc Segmentation.shell.mnc //%MakeShell (rpmdata, xdim, ydim, zdim, 1, 0); //%write_minc ("Segmentation.shell.mnc", rpmdata, xdim, ydim, zdim); //%delete [] rpmdata; rpmdata.makeShellVolume(1, 0); rpmdata.stretchVoxelValues(); writeDebugVolume(rpmdata, "Segmentation.shell"); //TO-DO: GenerateVolumeSpecFile () //TO-DO: Clean up files //%printf("#### GenerateSegmentation end ####\n"); //%return 0; if (DebugControl::getDebugOn()) { std::cout << "#### GenerateSegmentation end ####" << std::endl; } } /** * fill ventricles. */ void BrainModelVolumeSureFitSegmentation::fillVentricles() throw (BrainModelAlgorithmException) { if (DebugControl::getDebugOn()) { std::cout << "#### FillVentricles begin ####" << std::endl; } //1 VentricleThreshTemp=$CSFThresh //%int VentricleThreshTemp=int(lp.CSFThresh)+15; int ventricleThreshTemp = static_cast(csfThresh) + 15; //2 MakePlane.py 1 $ACx 0 $ACy 0 $ACz 0 2 $Segment_file MidlineSlab //%int xdim=lp.xdim; //%int ydim=lp.ydim; //%int zdim=lp.zdim; //%int ACx=lp.ACx; //%int ACy=lp.ACy; //%int ACz=lp.ACz; //%int num_voxels=xdim*ydim*zdim; //%unsigned char* inputdata=new unsigned char [num_voxels]; //%unsigned char* voxdataflat=new unsigned char [num_voxels]; //%unsigned char* segdata=new unsigned char [num_voxels]; //%read_minc_file (mincfile, inputdata); //%read_minc_file (segfname, segdata); //%unsigned char* plane=new unsigned char [num_voxels]; //%MakePlane (plane, 1.0, float(ACx), 0.0, float(ACy), 0.0, //% float(ACz), 0.0, 2.0, xdim, ydim, zdim); //%write_minc ("MidlineSlab.mnc", plane, xdim, ydim, zdim); VolumeFile inputdata = *anatomyVolume; VolumeFile voxdataflat = inputdata; voxdataflat.setAllVoxels(0.0); VolumeFile segdata = *segmentationVolume; VolumeFile plane = inputdata; plane.setAllVoxels(0.0); plane.makePlane(1.0, acIJK[0], 0.0, acIJK[1], 0.0, acIJK[2], 0.0, 2.0); plane.stretchVoxelValues(); writeDebugVolume(plane, "MidlineSlab"); //3 MaskVol.py MidlineSlab.mnc MidlineSlab.mask $xAC_1_low $xAC_1_high `expr $ACy - 40` `expr $ACy + 30` 0 `expr $ACz + 30` //%int extent[6]; //%extent[0]=lp.xAC_1_low; //%extent[1]=lp.xAC_1_high; //%extent[2]=ACy-40; //%extent[3]=ACy+30; //%extent[4]=0; //%extent[5]=ACz+30; //%MaskVolume (plane, xdim, ydim, zdim, extent); //%write_minc ("MidlineSlab.mask.mnc", plane, xdim, ydim, zdim); int extent[6]; extent[0] = xAC_1_low; extent[1] = xAC_1_high; extent[2] = acIJK[1] - 40; extent[3] = acIJK[1] + 30; extent[4] = 0; extent[5] = acIJK[2] + 30; plane.maskVolume(extent); plane.stretchVoxelValues(); writeDebugVolume(plane, "MidlineSlab.mask"); //4 while [ $VentricleFoundFlag == 0 ] ; do // sh -x NEW.TEST_VENTRICLE_LIMITS.sh ; . Volume_ID_limits ; // done //%char filename[256]; //%int seed[3], i, VentricleFoundFlag=FALSE; //%while ( VentricleFoundFlag==FALSE ) { int seed[3] = { -1, -1, -1 }; bool ventricleFoundFlag = false; while (ventricleFoundFlag == false) { //%for ( i=0 ; i(ventricleThreshTemp)); std::ostringstream str; str << "Ventricle.Temp.Thresh" << ventricleThreshTemp; writeDebugVolume(voxdataflat, str.str().c_str()); //3 MaskVol.py Ventricle.Temp.Thresh.mnc Ventricle.Temp.Thresh.PadMask $PadNegX `expr $ncol - $PadPosX` $PadNegY `expr $nrow - $PadPosY` $PadNegZ `expr $nslices - $PadPosZ` //%extent[0]=lp.OldPadNegX; //%extent[1]=xdim-lp.OldPadPosX; //%extent[2]=lp.OldPadNegY; //%extent[3]=ydim-lp.OldPadPosY; //%extent[4]=lp.OldPadNegZ; //%extent[5]=zdim-lp.OldPadPosZ; //%MaskVolume (voxdataflat, xdim, ydim, zdim, extent); //%write_minc ("Ventricle.Temp.Thresh.PadMask.mnc", voxdataflat, xdim, ydim, zdim); //extent[0] = oldPadNegX; //extent[1] = xDim - oldPadPosX; //extent[2] = oldPadNegY; //extent[3] = yDim - oldPadPosY; //extent[4] = oldPadNegZ; //extent[5] = zDim - oldPadPosZ; extent[0] = partialHemispherePadding[0]; extent[1] = xDim - partialHemispherePadding[1]; extent[2] = partialHemispherePadding[2]; extent[3] = yDim - partialHemispherePadding[3]; extent[4] = partialHemispherePadding[4]; extent[5] = zDim - partialHemispherePadding[5]; voxdataflat.maskVolume(extent); voxdataflat.stretchVoxelValues(); writeDebugVolume(voxdataflat, "Ventricle.Temp.Thresh.PadMask"); //4 CombineVols.py subrect Ventricle.Temp.Thresh.PadMask.mnc MidlineSlab.mask.mnc Ventricle.Temp.Thresh_MidlineCut //%CombineVols ("subrect", voxdataflat, plane, plane, xdim, ydim, zdim); //%sprintf (filename, "Ventricle.Temp.Thresh%d_MidlineCut.mnc", VentricleThreshTemp); //TO-DO: push filename onto cleanup stack //%write_minc (filename, voxdataflat, xdim, ydim, zdim); VolumeFile::performMathematicalOperation(VolumeFile::VOLUME_MATH_OPERATION_SUBTRACT_POSITIVE, &voxdataflat, &plane, &plane, &voxdataflat); voxdataflat.stretchVoxelValues(); str.str(""); str << "Ventricle.Temp.Thresh" << ventricleThreshTemp << "_MidlineCut"; writeDebugVolume(voxdataflat, str.str().c_str()); //5 FillBiggestObject.py Ventricle.Temp.Thresh_MidlineCut.mnc Ventricle.TestFlood $xAC_20_low $xAC_20_high `expr $ACy - 20` `expr $ACy + 20` `expr $ACz + 20` `expr $ACz + 40` //%extent[0]=lp.xAC_20_low; //%extent[1]=lp.xAC_20_high; //%extent[2]=ACy-20; //%extent[3]=ACy+20; //%extent[4]=ACz+20; //%extent[5]=ACz+40; //%FindBiggestObjectWithinMask (voxdataflat, xdim, ydim, zdim, extent[0],extent[1],extent[2],extent[3],extent[4],extent[5], seed); //%if (( seed[0] == -1 ) || ( seed[1] == -1 ) || ( seed[2] == -1 )) { //% printf("Ventricle not found within limits; exiting FillVentricles\n"); //% break; //%} //%vtkFloodFill (seed, voxdataflat, 255, 255, 0, xdim, ydim, zdim); //%sprintf (filename, "Ventricle.TestFlood%d.mnc", VentricleThreshTemp); //TO-DO: push filename onto cleanup stack //%write_minc (filename, voxdataflat, xdim, ydim, zdim); extent[0] = xAC_20_low; extent[1] = xAC_20_high; extent[2] = acIJK[1] - 20; extent[3] = acIJK[1] + 20; extent[4] = acIJK[2] + 20; extent[5] = acIJK[2] + 40; VoxelIJK seedIJK(seed); voxdataflat.findBiggestObjectWithinMask(extent, 255, 255, seedIJK); seed[0] = seedIJK.getI(); seed[1] = seedIJK.getJ(); seed[2] = seedIJK.getK(); if ((seed[0] < 0) || (seed[1] < 0) || (seed[2] < 0)) { if (DebugControl::getDebugOn()) { std::cout << "Ventricle not found within limits; exiting FillVentricles" << std::endl; } break; } voxdataflat.floodFillWithVTK(seedIJK, 255, 255, 0); str.str(""); str << "Ventricle.TestFlood" << ventricleThreshTemp; writeDebugVolume(voxdataflat, str.str().c_str()); //6 FindLimits.py Ventricle.TestFlood.mnc Ventricle.limits //%FindLimits (xdim, ydim, zdim, voxdataflat, "Ventricle.limits", extent); voxdataflat.findLimits("Ventricle.limits", extent); //7 if [ $LimitZmin -gt `expr $ACz - 20` ] ; then echo "VENTRICLE DISCONNECTED FROM CSF" ; exit; fi //%if (extent [4] > (ACz-20)) {VentricleFoundFlag=TRUE;} //%else {printf("VENTRICLE NOT YET DISCONNECTED\n");} if (extent[4] > (acIJK[2] - 20)) { ventricleFoundFlag = true; } else { if (DebugControl::getDebugOn()) { std::cout << "VENTRICLE NOT YET DISCONNECTED" << std::endl; } } } if (ventricleFoundFlag == false) { //%printf("VENTRICLE FAILED TO DISCONNECT FROM CSF\n"); if (DebugControl::getDebugOn()) { std::cout << "VENTRICLE FAILED TO DISCONNECT FROM CSF" << std::endl; } } else { //%printf("VENTRICLE DISCONNECTED FROM CSF\n"); if (DebugControl::getDebugOn()) { std::cout << "VENTRICLE DISCONNECTED FROM CSF" << std::endl; } //5 cp Ventricle.TestFlood.mnc Ventricle.flood.mnc //%write_minc ("Ventricle.flood.mnc", voxdataflat, xdim, ydim, zdim); writeDebugVolume(voxdataflat, "Ventricle.flood"); //6 Sculpt.py 2 5 $xAClow $xAChigh 0 $nrow 0 $nslices Ventricle.flood.mnc Segment_file Ventricle_notSegmentation //%for ( i=0 ; i<3 ; i++ ) seed[i]=0; //%extent[0]=lp.xAClow; //%extent[1]=lp.xAChigh; //%extent[2]=0; //%extent[3]=ydim; //%extent[4]=0; //%extent[5]=zdim; //%Sculpt (2, 5, seed, extent, voxdataflat, segdata, xdim, ydim, zdim); //%write_minc ("Ventricle_notSegmentation.mnc", voxdataflat, xdim, ydim, zdim); seed[0] = 0; seed[1] = 0; seed[2] = 0; extent[0] = xAClow; extent[1] = xAChigh; extent[2] = 0; extent[3] = yDim; extent[4] = 0; extent[5] = zDim; voxdataflat.sculptVolume(2, &segdata, 5, seed, extent); voxdataflat.stretchVoxelValues(); writeDebugVolume(voxdataflat, "Ventricle_notSegmentation"); //7 CombineVols.py OR $Segment_file Ventricle_notSegmentation.mnc Segmentation_Ventricle //%CombineVols ("OR", segdata, voxdataflat, voxdataflat, xdim, ydim, zdim); //%QString segventfname=segfname; //%segventfname.replace (segventfname.find(".mnc"),4,"_vent.mnc"); //%write_minc ((char *)segventfname, segdata, xdim, ydim, zdim); VolumeFile::performMathematicalOperation(VolumeFile::VOLUME_MATH_OPERATION_OR, &segdata, &voxdataflat, &voxdataflat, &segdata); segdata.stretchVoxelValues(); writeDebugVolume(segdata, "Segment_vent"); segmentationVentriclesFilledVolume = new VolumeFile(segdata); } /* delete [] inputdata; delete [] voxdataflat; delete [] segdata; delete [] plane; */ if (DebugControl::getDebugOn()) { std::cout << "#### FillVentricles end ####" << std::endl; } } /** * write the vector file for debugging. */ void BrainModelVolumeSureFitSegmentation::writeDebugVector(SureFitVectorFile& vf, const QString& nameIn) throw (BrainModelAlgorithmException) { if (DebugControl::getDebugOn()) { try { QString name; QDir intermedDir(segmentationDebugFilesSubDirectory); if (intermedDir.exists()) { name.append(segmentationDebugFilesSubDirectory); name.append("/"); } name.append(nameIn); name.append(SpecFile::getSureFitVectorFileExtension()); vf.writeFile(name); std::cout << "Write Debug Vector File: " << name.toAscii().constData() << std::endl; } catch (FileException& e) { throw (BrainModelAlgorithmException(e.whatQString())); } } } /** * write the volume. */ void BrainModelVolumeSureFitSegmentation::writeDebugVolume(VolumeFile& vf, const QString& nameIn) throw (BrainModelAlgorithmException) { writeDebugVolume(&vf, nameIn); } /** * write the volume. */ void BrainModelVolumeSureFitSegmentation::writeDebugVolume(VolumeFile* vf, const QString& nameIn) throw (BrainModelAlgorithmException) { if (DebugControl::getDebugOn()) { try { vf->setDescriptiveLabel(nameIn); QString name; QDir intermedDir(segmentationDebugFilesSubDirectory); if (intermedDir.exists()) { name.append(segmentationDebugFilesSubDirectory); name.append("/"); } name.append(nameIn); QString fileNameWritten; QString dataFileNameWritten; VolumeFile::writeVolumeFile(vf, typeOfVolumeFilesToWrite, name, false, fileNameWritten, dataFileNameWritten); //name.append(SpecFile::getAfniVolumeFileExtension()); //vf->writeFile(name); std::cout << "Write Debug Volume File: " << fileNameWritten.toAscii().constData() << std::endl; } catch (FileException& e) { throw (BrainModelAlgorithmException(e.whatQString())); } } } /** * get parameters from the parameters file. */ void BrainModelVolumeSureFitSegmentation::getParameters() throw (BrainModelAlgorithmException) { QString msg; if (structure == Structure::STRUCTURE_TYPE_INVALID) { /* int hem; if (pf->getParameter(ParamsFile::keyHem, hem)) { if (hem == 0) { hemisphere = Structure::STRUCTURE_TYPE_CORTEX_LEFT; } else if(hem == 1) { hemisphere = Structure::STRUCTURE_TYPE_CORTEX_RIGHT; } } */ if (structure == Structure::STRUCTURE_TYPE_INVALID) { msg.append("Unable to determine structure.\n"); } } if (msg.isEmpty() == false) { throw BrainModelAlgorithmException(msg); } // // Get the volume's dimensions // if (anatomyVolume != NULL) { anatomyVolume->getDimensions(xDim, yDim, zDim); } else { segmentationVolume->getDimensions(xDim, yDim, zDim); } // // Some structure flags // Hem = 0; if (structure == Structure::STRUCTURE_TYPE_CORTEX_RIGHT) { Hem = 1; } Hem1 = Hem; Hem2 = 1 - Hem1; HemDbl = 2 * Hem1; Hem3 = HemDbl - 1; // // Some AC relationships // xAC_1 = acIJK[0] + Hem3 * 1; xAClow = acIJK[0] * Hem1; xAChigh = xDim * Hem1 + acIJK[0] * Hem2; xAC_10 = acIJK[0] + Hem3 * 10; xAC_15 = acIJK[0] + Hem3 * 15; xAC_20 = acIJK[0] + Hem3 * 20; xAC_40 = acIJK[0] + Hem3 * 40; xAC_1_low = xAC_1 * Hem2 + acIJK[0] * Hem1; xAC_1_high = xAC_1 * Hem1 + acIJK[0] * Hem2; xAC_15_40_low = xAC_40 * Hem2 + xAC_15 * Hem1; xAC_15_40_high = xAC_40 * Hem1 + xAC_15 * Hem2; xAC_20_low = xAC_20 * Hem2 + acIJK[0] * Hem1; xAC_20_high = xAC_20 * Hem1 + acIJK[0] * Hem2; xAC_50 = acIJK[0] + Hem3 * 50; xMedLimit_50_low = xAC_50 * Hem2; xMedLimit_50_high = xAC_50 * Hem1 + xDim * Hem2; xMedLimit_20_low = xAC_20 * Hem2; xMedLimit_20_high = xAC_20 * Hem1 + xDim * Hem2; xMedLimit_low = acIJK[0] * Hem2; xMedLimit_high = acIJK[0] * Hem1 + xDim * Hem2; inITPeak= (wmPeak + cgmPeak) / 2.0; inITLow = cgmPeak; inITHigh = wmPeak; inITSignum = 2.0; cgmLow = cgmPeak / 2.0; cgmHigh = inITPeak; cgmSignum = 1.3; csfThresh = cgmPeak / 2.0; outITPeak = cgmPeak / 2.0; outITLow = csfThresh * 0.5; outITHigh = cgmPeak; outITSignum = 2.0; if (DebugControl::getDebugOn()) { std::cout << "Hem: " << Hem << std::endl; std::cout << "Hem2: " << Hem2 << std::endl; std::cout << "HemDbl: " << HemDbl << std::endl; std::cout << "Hem3: " << Hem3 << std::endl; std::cout << "xAC_1: " << xAC_1 << std::endl; std::cout << "xAC_10: " << xAC_10 << std::endl; std::cout << "xAC_15: " << xAC_15 << std::endl; std::cout << "xAC_20: " << xAC_20 << std::endl; std::cout << "xAC_40: " << xAC_40 << std::endl; std::cout << "xAC_50: " << xAC_50 << std::endl; std::cout << "xAC_1_low: " << xAC_1_low << std::endl; std::cout << "xAC_1_high: " << xAC_1_high << std::endl; std::cout << "xAC_20_low: " << xAC_20_low << std::endl; std::cout << "xAC_20_high: " << xAC_20_high << std::endl; std::cout << "xAC_15_40_low: " << xAC_15_40_low << std::endl; std::cout << "xAC_15_40_high: " << xAC_15_40_high << std::endl; std::cout << "xMedLimit_20_low: " << xMedLimit_20_low << std::endl; std::cout << "xMedLimit_20_high: " << xMedLimit_20_high << std::endl; std::cout << "xMedLimit_50_low: " << xMedLimit_50_low << std::endl; std::cout << "xMedLimit_50_high: " << xMedLimit_50_high << std::endl; std::cout << "xAClow: " << xAClow << std::endl; std::cout << "xAChigh: " << xAChigh << std::endl; std::cout << "xMedLimit_low: " << xMedLimit_low << std::endl; std::cout << "xMedLimit_high: " << xMedLimit_high << std::endl; std::cout << "AC: " << acIJK[0] << ", " << acIJK[1] << ", " << acIJK[2] << std::endl; std::cout << "wmPeak: " << wmPeak << std::endl; std::cout << "cgmPeak: " << cgmPeak << std::endl; std::cout << "wmThresh: " << wmThresh << std::endl; } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeSureFitErrorCorrection.h0000664000175000017500000003207611572067322027636 0ustar michaelmichael #ifndef __BRAIN_MODEL_VOLUME_SUREFIT_ERROR_CORRECTION_H__ #define __BRAIN_MODEL_VOLUME_SUREFIT_ERROR_CORRECTION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainModelAlgorithm.h" #include "DebugControl.h" #include "VolumeFile.h" class BrainModelSurface; class MetricFile; /// class for correcting topological errors in segmentation volumes class BrainModelVolumeSureFitErrorCorrection : public BrainModelAlgorithm { public: // Constructor BrainModelVolumeSureFitErrorCorrection(BrainSet* bs, VolumeFile* segmentationVolumeIn, VolumeFile* radialPositionMapVolumeIn, const VolumeFile::FILE_READ_WRITE_TYPE typeOfVolumeFilesToWriteIn, const int acIJKIn[3], const bool leftHemFlagIn, const bool saveIntermediateFilesIn); // Destructor ~BrainModelVolumeSureFitErrorCorrection(); // get the output volume const VolumeFile* getOutputVolume() const { return outputVolume; } // execute the algorithm void execute() throw (BrainModelAlgorithmException); protected: /// class for storing error information class ErrorStats { public: ErrorStats () { StartingHandles=0; TestObjectNum=0; UncorrectedObjects=0; CurrentHandles=0; MaskHandlesBefore=0; MaskCavitiesBefore=0; RemainingObjectNum=0; CurrentTestNum=1; CumulativeTestNum=0; ObjectsPatched=0; CavitiesPatched=0; DisconnectFlag=0; } ~ErrorStats () { } int getStartingHandles() const { return StartingHandles; } int getTestObjectNum() const { return TestObjectNum; } int getUncorrectedObjects() const { return UncorrectedObjects; } int getCurrentHandles() const { return CurrentHandles; } int getMaskHandlesBefore() const { return MaskHandlesBefore; } int getMaskCavitiesBefore() const { return MaskCavitiesBefore; } int getRemainingObjectNum() const { return RemainingObjectNum; } int getCurrentTestNum() const { return CurrentTestNum; } int getCumulativeTestNum() const { return CumulativeTestNum; } int getObjectsPatched() const { return ObjectsPatched; } int getCavitiesPatched() const { return CavitiesPatched; } int getDisconnectFlag() const { return DisconnectFlag; } void setStartingHandles(int value) { this->StartingHandles=value; if (DebugControl::getDebugOn()) { std::cout << "StartingHandles = " << this->StartingHandles << std::endl; } } void setTestObjectNum(int value) { this->TestObjectNum=value; if (DebugControl::getDebugOn()) { std::cout << "TestObjectNum = " << this->TestObjectNum << std::endl; } } void setUncorrectedObjects(int value) { this->UncorrectedObjects=value; if (DebugControl::getDebugOn()) { std::cout << "UncorrectedObjects = " << this->UncorrectedObjects << std::endl; } } void setCurrentHandles(int value) { this->CurrentHandles=value; if (DebugControl::getDebugOn()) { std::cout << "CurrentHandles = " << this->CurrentHandles << std::endl; } } void setMaskHandlesBefore(int value) { this->MaskHandlesBefore=value; if (DebugControl::getDebugOn()) { std::cout << "MaskHandlesBefore = " << this->MaskHandlesBefore << std::endl; } } void setMaskCavitiesBefore(int value) { this->MaskCavitiesBefore=value; if (DebugControl::getDebugOn()) { std::cout << "MaskCavitiesBefore = " << this->MaskCavitiesBefore << std::endl; } } void setRemainingObjectNum(int value) { this->RemainingObjectNum=value; if (DebugControl::getDebugOn()) { std::cout << "RemainingObjectNum = " << this->RemainingObjectNum << std::endl; } } void setCurrentTestNum(int value) { this->CurrentTestNum=value; if (DebugControl::getDebugOn()) { std::cout << "CurrentTestNum = " << this->CurrentTestNum << std::endl; } } void setCumulativeTestNum(int value) { this->CumulativeTestNum=value; if (DebugControl::getDebugOn()) { std::cout << "CumulativeTestNum = " << this->CumulativeTestNum << std::endl; } } void setObjectsPatched(int value) { this->ObjectsPatched=value; if (DebugControl::getDebugOn()) { std::cout << "ObjectsPatched = " << this->ObjectsPatched << std::endl; } } void setCavitiesPatched(int value) { this->CavitiesPatched=value; if (DebugControl::getDebugOn()) { std::cout << "CavitiesPatched = " << this->CavitiesPatched << std::endl; } } void setDisconnectFlag(int value) { this->DisconnectFlag=value; if (DebugControl::getDebugOn()) { if ( this->DisconnectFlag > 0 ) { std::cout << "Handle patched" << std::endl; } } } void print () { std::cout << "StartingHandles = " << this->StartingHandles << std::endl; std::cout << "TestObjectNum = " << this->TestObjectNum << std::endl; std::cout << "UncorrectedObjects = " << this->UncorrectedObjects << std::endl; std::cout << "CurrentHandles = " << this->CurrentHandles << std::endl; std::cout << "MaskHandlesBefore = " << this->MaskHandlesBefore << std::endl; std::cout << "MaskCavitiesBefore = " << this->MaskCavitiesBefore << std::endl; std::cout << "RemainingObjectNum = " << this->RemainingObjectNum << std::endl; std::cout << "CurrentTestNum = " << this->CurrentTestNum << std::endl; std::cout << "CumulativeTestNum = " << this->CumulativeTestNum << std::endl; std::cout << "ObjectsPatched = " << this->ObjectsPatched << std::endl; std::cout << "CavitiesPatched = " << this->CavitiesPatched << std::endl; } protected: int StartingHandles; int TestObjectNum; int UncorrectedObjects; int CurrentHandles; int MaskHandlesBefore; int MaskCavitiesBefore; int RemainingObjectNum; int CurrentTestNum; int CumulativeTestNum; int ObjectsPatched; int CavitiesPatched; int DisconnectFlag; }; // Find the nearest node that is not a crossover and has a compressed void crossoverProjection(const BrainModelSurface* bms, const MetricFile* crossoversMetric, const int crossoverColumn, const MetricFile* compressedMetric, const int compressedMetricColumn, MetricFile* outputMetric, const int outputMetricColumn, const float thresholdValue) throw (BrainModelAlgorithmException); // Generate a surface from the specified volume. void generateSurfaceAndMeasurements(const VolumeFile* vf) throw (BrainModelAlgorithmException); // Correct errors in segmetation. int correctErrors() throw (BrainModelAlgorithmException); // void uncorrectedObject() throw (BrainModelAlgorithmException); // patch an object ErrorStats patchObjectBatch(VolumeFile& rodata, VolumeFile& sbpdata, const int CurrentHandles, const int TestObjectNum) throw (BrainModelAlgorithmException); // perform a cycle of patching void patchCycle(VolumeFile& ctodata, VolumeFile& errorsdata, VolumeFile& sbpdata, int ctoextent[6], int TestStats[3], ErrorStats es) throw (BrainModelAlgorithmException); // Patch an "endo" handle. void patchEndoHandle(VolumeFile& sbpdata, int ctoextent[6], int TestStats[3], ErrorStats es, const int endo_count) throw (BrainModelAlgorithmException); // patch an "Exo" handle. void patchExoHandle(VolumeFile& sbpdata, int ctoextent[6], int TestStats[3], ErrorStats es, const int exoCount) throw (BrainModelAlgorithmException); // Patch invaginations void patchInvagination(VolumeFile& sbpdata, int TestStats[3], ErrorStats es) throw (BrainModelAlgorithmException); // read an intermediate volume void readIntermediateVolume(VolumeFile* vf, const QString& nameIn) throw (BrainModelAlgorithmException); // read an intermediate volume void readIntermediateVolume(VolumeFile& vf, const QString& nameIn) throw (BrainModelAlgorithmException); // write an intermediate volume void writeIntermediateVolume(VolumeFile* vf, const QString& nameIn) throw (BrainModelAlgorithmException); // write an intermediate volume void writeIntermediateVolume(VolumeFile& vf, const QString& nameIn) throw (BrainModelAlgorithmException); // convert metric surface data into a volume VolumeFile* convertMetricToVolume(const BrainModelSurface* bms, const MetricFile* mf, const int metricColumn, const float scaling, const float voxelBoxSize); // the input segmentation volume VolumeFile* segmentationVolume; // the input radial position map volume VolumeFile* radialPositionMapVolume; // x dimensions of volume being segmented int xDim; // y dimensions of volume being segmented int yDim; // z dimensions of volume being segmented int zDim; // Anterior Commissure voxel indices int acIJK[3]; // hemisphere int leftHemFlag; // intermediate files subdirectory QString intermediateFilesSubDirectory; // save (do not delete) the intermediate files bool saveIntermediateFiles; // intermediate files generated by this algorithm std::vector intermediateFileNames; // intermediate volume files in memory std::map intermediateVolumeFilesInMemory; // keep intermediate files in memory flag bool keepIntermediateFilesInMemoryFlag; // the output volume VolumeFile* outputVolume; /// type of volume files to write VolumeFile::FILE_READ_WRITE_TYPE typeOfVolumeFilesToWrite; /// was error correction successful? bool errorCorrectionWasSuccessfulFlag; }; #endif // __BRAIN_MODEL_VOLUME_SUREFIT_ERROR_CORRECTION_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeSureFitErrorCorrection.cxx0000664000175000017500000040172011572067322030205 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include "BrainModelSurface.h" #include "BrainModelVolumeSureFitErrorCorrection.h" #include "BrainModelVolumeToSurfaceConverter.h" #include "BrainSet.h" #include "BrainSetNodeAttribute.h" #include "DebugControl.h" #include "FileUtilities.h" #include "MetricFile.h" #include "TopologyFile.h" #include "TopologyHelper.h" #include "VolumeFile.h" /** * Constructor. */ BrainModelVolumeSureFitErrorCorrection::BrainModelVolumeSureFitErrorCorrection( BrainSet* bs, VolumeFile* segmentationVolumeIn, VolumeFile* radialPositionMapVolumeIn, const VolumeFile::FILE_READ_WRITE_TYPE typeOfVolumeFilesToWriteIn, const int acIJKIn[3], const bool leftHemFlagIn, const bool saveIntermediateFilesIn) : BrainModelAlgorithm(bs) { // // Setting true will reduce runtime by about 5% but does // require plenty of memory // keepIntermediateFilesInMemoryFlag = false; // true; segmentationVolume = new VolumeFile(*segmentationVolumeIn); radialPositionMapVolume = new VolumeFile(*radialPositionMapVolumeIn); typeOfVolumeFilesToWrite = typeOfVolumeFilesToWriteIn; leftHemFlag = leftHemFlagIn; acIJK[0] = acIJKIn[0]; acIJK[1] = acIJKIn[1]; acIJK[2] = acIJKIn[2]; intermediateFilesSubDirectory = "ERROR_CORRECTION_INTERMEDIATES"; saveIntermediateFiles = saveIntermediateFilesIn; if (saveIntermediateFiles) { keepIntermediateFilesInMemoryFlag = false; } outputVolume = NULL; errorCorrectionWasSuccessfulFlag = false; } /** * Destructor. */ BrainModelVolumeSureFitErrorCorrection::~BrainModelVolumeSureFitErrorCorrection() { if (outputVolume != NULL) { delete outputVolume; outputVolume = NULL; } if (segmentationVolume != NULL) { delete segmentationVolume; segmentationVolume = NULL; } if (radialPositionMapVolume != NULL) { delete radialPositionMapVolume; radialPositionMapVolume = NULL; } if ((saveIntermediateFiles == false) && (errorCorrectionWasSuccessfulFlag)) { for (unsigned int i = 0; i < intermediateFileNames.size(); i++) { QFile::remove(intermediateFileNames[i]); } for (std::map::iterator iter = intermediateVolumeFilesInMemory.begin(); iter != intermediateVolumeFilesInMemory.end(); iter++) { delete iter->second; } QDir dir; dir.rmdir(intermediateFilesSubDirectory); } } /** * execute the algorithm */ void BrainModelVolumeSureFitErrorCorrection::execute() throw (BrainModelAlgorithmException) { if (segmentationVolume == NULL) { throw BrainModelAlgorithmException("Input segmentation is invalid"); } segmentationVolume->getDimensions(xDim, yDim, zDim); if ((xDim <= 0) || (yDim <= 0) || (zDim <= 0)) { throw BrainModelAlgorithmException("Input segmentation is invalid"); } if (radialPositionMapVolume == NULL) { throw BrainModelAlgorithmException("Input radial position map volume is invalid"); } int raddim[3]; radialPositionMapVolume->getDimensions(raddim); if ((raddim[0] != xDim) || (raddim[1] != yDim) || (raddim[2] != zDim)) { throw BrainModelAlgorithmException( "Input Radial Position Map Volume has different dimensions than segmentation volume."); } try { // // Create the intermediate files directory // QDir intermedDir(intermediateFilesSubDirectory); if (intermedDir.exists() == false) { QDir temp("."); if (temp.mkdir(intermediateFilesSubDirectory) == false) { throw BrainModelAlgorithmException( "Unable to create temporary directory named \"" + intermediateFilesSubDirectory + "\" in \"" + temp.absolutePath() + " for use by Automatic Error Correction."); } } // // Create measurements // QTime genTimer; genTimer.start(); generateSurfaceAndMeasurements(segmentationVolume); const float genTime = genTimer.elapsed() * 0.001; // // Correct the errors // QTime errorTimer; errorTimer.start(); correctErrors(); const float errorTime = errorTimer.elapsed() * 0.001; if (DebugControl::getDebugOn()) { std::cout << "Surface and measurements time: " << genTime << std::endl; std::cout << "Correct errors time: " << errorTime << std::endl; } errorCorrectionWasSuccessfulFlag = true; } catch (BrainModelAlgorithmException& e) { removeProgressDialog(); throw e; } removeProgressDialog(); } /** * Generate a surface from the specified volume. */ void BrainModelVolumeSureFitErrorCorrection::generateSurfaceAndMeasurements(const VolumeFile* vf) throw (BrainModelAlgorithmException) { // // Make a copy of the segmentation volume since it will be added to a temporary brain set // VolumeFile* segVol = new VolumeFile(*vf); // // Fill any holes in the segmentation and write it // segVol->fillSegmentationCavities(); writeIntermediateVolume(segVol, "Segment.BeforePatch"); // // Create a brain set and add the segmentation volume to it // BrainSet bs; bs.addVolumeFile(VolumeFile::VOLUME_TYPE_SEGMENTATION, segVol, "", false, false); // // convert the segmentation volume to a surface // BrainModelVolumeToSurfaceConverter bmvsc(&bs, segVol, BrainModelVolumeToSurfaceConverter::RECONSTRUCTION_MODE_SUREFIT_SURFACE, (leftHemFlag == false), leftHemFlag); bmvsc.execute(); // // Find the raw and fiducial surfaces // BrainModelSurface* rawSurface = bs.getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_RAW); if (rawSurface == NULL) { throw BrainModelAlgorithmException("Unable to find raw surface for surface measurements."); } BrainModelSurface* fiducialSurface = bs.getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_FIDUCIAL); if (fiducialSurface == NULL) { throw BrainModelAlgorithmException("Unable to find fiducial surface for surface measurements."); } // // Metric file for surface measurements // MetricFile metricMeasurements; // // Generate the elliposoid surface // fiducialSurface->createInflatedAndEllipsoidFromFiducial(false, // inflated false, // very inflated true, // ellipsoid false, // sphere false, // cmw true, // finger smoothing false, // scale to fiducial 1.0, // No iteration scaling &metricMeasurements); // // Output measurements for debugging // if (DebugControl::getDebugOn()) { try { metricMeasurements.writeFile("ErrorCorrectionMeasurements.metric"); } catch (FileException&) { } } // // Find the ellipsoid surface // BrainModelSurface* ellipsoidSurface = bs.getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL); if (ellipsoidSurface == NULL) { throw BrainModelAlgorithmException("Unable to find ellipsoid surface for surface measurements."); } // // Find the compressed or stretched column // const int compressedStretchedColumn = metricMeasurements.getColumnWithName("Ellipsoid_CompressedOrStretched"); if (compressedStretchedColumn < 0) { throw BrainModelAlgorithmException("Unable to find metric column named Ellipsoid_CompressedOrStretched"); } // // Create a volume containing the compressed/stretched for the ellipsoid surface // VolumeFile* compressStretchVolume = convertMetricToVolume(rawSurface, &metricMeasurements, compressedStretchedColumn, 1.0, 1.5); if(compressStretchVolume == NULL) { throw BrainModelAlgorithmException("Unable to create compress stretch ellipsoid volume."); } writeIntermediateVolume(compressStretchVolume, "Ellipsoid_CompressedOrStretched"); delete compressStretchVolume; // 7/18/2005 compressStretchVolume = NULL; // 7/18/2005 // // Do a crossover check on the ellipsoid surface // ellipsoidSurface->crossoverCheckSureFitEllipsoid(); // // Create a metric file containing the crossovers // const int numNodes = ellipsoidSurface->getNumberOfNodes(); MetricFile crossoversMetric; crossoversMetric.setNumberOfNodesAndColumns(numNodes, 1); const QString metricCrossoversColumnName("crossovers"); const int crossoversColumn = 0; crossoversMetric.setColumnName(crossoversColumn, metricCrossoversColumnName); for (int i = 0; i < numNodes; i++) { const BrainSetNodeAttribute* bna = bs.getNodeAttributes(i); if (bna->getCrossover() == BrainSetNodeAttribute::CROSSOVER_YES) { crossoversMetric.setValue(i, crossoversColumn, 1.0); } } // // Create a volume containing the crossovers and write it // VolumeFile* crossoversVolume = convertMetricToVolume(rawSurface, &crossoversMetric, crossoversColumn, 1.0, 1.5); if(crossoversVolume == NULL) { throw BrainModelAlgorithmException("Unable to create crossovers volume."); } writeIntermediateVolume(crossoversVolume, "Crossovers"); // // Metric file for near crossovers // MetricFile nearCrossoversMetric; nearCrossoversMetric.setNumberOfNodesAndColumns(numNodes, 1); const int nearCrossoversColumn = 0; nearCrossoversMetric.setColumnName(nearCrossoversColumn, "Near Crossovers"); // // Find the non-crossover nodes near the crossovers // crossoverProjection(ellipsoidSurface, &crossoversMetric, crossoversColumn, &metricMeasurements, compressedStretchedColumn, &nearCrossoversMetric, nearCrossoversColumn, 1.0); // // Create a volume containing the near crossovers and write it // VolumeFile* nearCrossoversVolume = convertMetricToVolume(rawSurface, &nearCrossoversMetric, nearCrossoversColumn, 1.0, 1.5); if(nearCrossoversVolume == NULL) { throw BrainModelAlgorithmException("Unable to create near crossovers volume."); } writeIntermediateVolume(nearCrossoversVolume, "NearCrossovers"); delete nearCrossoversVolume; // 7/18/2005 nearCrossoversVolume = NULL; // 7/18/2005 // // Find the gaussian neg for low smoothed surface column // const int gaussNegLowSmoothColumn = metricMeasurements.getColumnWithName("gaussian_neg.LowSmooth"); if (gaussNegLowSmoothColumn < 0) { throw BrainModelAlgorithmException("Unable to find metric column named gaussian_neg.LowSmooth"); } // // Create a volume containing the gaussian neg for low smoothed surface // VolumeFile* gaussNegLowSmoothVolume = convertMetricToVolume(rawSurface, &metricMeasurements, gaussNegLowSmoothColumn, 1.0, 1.5); if(gaussNegLowSmoothVolume == NULL) { throw BrainModelAlgorithmException("Unable to create gauss neg low smooth volume."); } writeIntermediateVolume(gaussNegLowSmoothVolume, "Gauss_neg"); delete gaussNegLowSmoothVolume; // 7/18/2005 gaussNegLowSmoothVolume = NULL; // 7/18/2005 // // Find the compressed for high smoothed surface column // const int compressHighSmoothColumn = metricMeasurements.getColumnWithName("compressed.HighSmooth"); if (compressHighSmoothColumn < 0) { throw BrainModelAlgorithmException("Unable to find metric column named compressed.HighSmooth"); } // // Create a volume containing the compressed for high smoothed surface // VolumeFile* compressHighSmoothVolume = convertMetricToVolume(rawSurface, &metricMeasurements, compressHighSmoothColumn, 1.0, 1.5); if(compressHighSmoothVolume == NULL) { throw BrainModelAlgorithmException("Unable to create gauss neg low smooth volume."); } writeIntermediateVolume(compressHighSmoothVolume, "Compression.HighSmooth"); delete compressHighSmoothVolume; // 7/18/2005 compressHighSmoothVolume = NULL; // 7/18/2005 // // // Create a thresholded volume of crossovers and write it // crossoversVolume->thresholdVolume(75); writeIntermediateVolume(crossoversVolume, "Crossovers.thresh"); delete crossoversVolume; // 7/18/2005 crossoversVolume = NULL; // 7/18/2005 } /** * Find the nearest node that is not a crossover and has a compressed * value less than the threshold. */ void BrainModelVolumeSureFitErrorCorrection::crossoverProjection(const BrainModelSurface* bms, const MetricFile* crossoversMetric, const int crossoverColumn, const MetricFile* compressedMetric, const int compressedColumn, MetricFile* outputMetric, const int outputColumn, const float thresholdValue) throw (BrainModelAlgorithmException) { // // Get coordinates // const CoordinateFile* cf = bms->getCoordinateFile(); const int numNodes = bms->getNumberOfNodes(); // // Get topology helper // const TopologyFile* tf = bms->getTopologyFile(); if (tf == NULL) { std::ostringstream str; str << "Surface " << FileUtilities::basename(bms->getCoordinateFile()->getFileName()).toAscii().constData() << " has no topology"; throw BrainModelAlgorithmException(str.str().c_str()); } const TopologyHelper* th = tf->getTopologyHelper(false, true, false); // // Clear output metric column // for (int i = 0; i < numNodes; i++) { outputMetric->setValue(i, outputColumn, 0.0); } // // find closest non-crossover and non-stretched node to each crossover node // for (int i = 0; i < numNodes; i++) { // // Is this node a crossover node // if (crossoversMetric->getValue(i, crossoverColumn) != 0) { // // Get this node's coordinates // float x, y, z; cf->getCoordinate(i, x, y, z); // // Find nearest node that is not a crossover and has compression below the threshold // float nearestDistSQ = -1.0; int nearestNode = -1; for (int j = 0; j < numNodes; j++) { if ((crossoversMetric->getValue(j, crossoverColumn) == 0.0) && (compressedMetric->getValue(j, compressedColumn) <= thresholdValue) && th->getNodeHasNeighbors(j)) { float nodeX, nodeY, nodeZ; cf->getCoordinate(j, nodeX, nodeY, nodeZ); const float dx = nodeX - x; const float dy = nodeY - y; const float dz = nodeZ - z; const float distSQ = dx*dx + dy*dy + dz*dz; if (nearestNode < 0) { nearestDistSQ = distSQ; nearestNode = j; } else if (distSQ < nearestDistSQ) { nearestDistSQ = distSQ; nearestNode = j; } } } if (nearestNode < 0) { std::cout << "ERROR: Cannot find nearest node to crossover node " << i << endl; } else { outputMetric->setValue(nearestNode, outputColumn, 1.0); } } } } /** * convert metric surface data into a volume. */ VolumeFile* BrainModelVolumeSureFitErrorCorrection::convertMetricToVolume( const BrainModelSurface* bms, const MetricFile* mf, const int metricColumn, const float scaling, const float voxelBoxSize) { // // Check inputs // if (bms == NULL) { return NULL; } const int numNodes = bms->getNumberOfNodes(); if (numNodes <= 0) { return NULL; } if ((metricColumn < 0) || (metricColumn >= mf->getNumberOfColumns())) { return NULL; } // // Get half of the voxel box size // const float halfVoxelSize = voxelBoxSize * 0.5; // // Get the surface's coordinate file // const CoordinateFile* cf = bms->getCoordinateFile(); // // Create the volume file and clear its voxels // VolumeFile* vf = new VolumeFile(*segmentationVolume); vf->makeDefaultFileName("metric-to-vol"); vf->setVolumeType(VolumeFile::VOLUME_TYPE_FUNCTIONAL); vf->setAllVoxels(-1.0); // // Process each node // for (int m = 0; m < numNodes; m++) { // // Get the metric value // const float metricValue = mf->getValue(m, metricColumn); // // Get coordinate of node // const float* xyz = cf->getCoordinate(m); // // Convert coordinate to voxel IJK index and set the value for this voxel // int ijk[3]; vf->convertCoordinatesToVoxelIJK(xyz, ijk); if (vf->getVoxelIndexValid(ijk)) { if (metricValue > vf->getVoxel(ijk)) { vf->setVoxel(ijk, 0, metricValue); } } // // Is the voxel being "fuzzed" // if (voxelBoxSize > 1.0) { for (float x = (xyz[0] - halfVoxelSize); x <= (xyz[0] + halfVoxelSize); x += 1.0) { for (float y = (xyz[1] - halfVoxelSize); y <= (xyz[1] + halfVoxelSize); y += 1.0) { for (float z = (xyz[2] - halfVoxelSize); z <= (xyz[2] + halfVoxelSize); z += 1.0) { const float tempxyz[3] = { x, y, z }; int ijk[3]; vf->convertCoordinatesToVoxelIJK(tempxyz, ijk); if (vf->getVoxelIndexValid(ijk)) { if (metricValue > vf->getVoxel(ijk)) { vf->setVoxel(ijk, 0, metricValue); } } } } } } } if (scaling == 1.0) { const int numVoxels = vf->getTotalNumberOfVoxels(); for (int i = 0; i < numVoxels; i++) { float voxel = vf->getVoxelWithFlatIndex(i); if (voxel < -1.0) { voxel = 0.0; } else if (voxel > 4.0) { voxel = 255.0; } else { voxel = 50.0 * (voxel + 1.0); } voxel = std::min(voxel, 255.0f); vf->setVoxelWithFlatIndex(i, 0, voxel); } } return vf; } /** * Correct errors in segmetation. */ int BrainModelVolumeSureFitErrorCorrection::correctErrors() throw (BrainModelAlgorithmException) { if (DebugControl::getDebugOn()) { std::cout << "#### CorrectErrors begin ####" << std::endl; } /*TO-DO: CheckRPM find RadialPositionMap_pad.mnc or RadialPositionMap.mnc make sure its dims match the segmentations */ /* TEMPORARY GenerateSurfaceInflateCrossoverCheck (segfname, ellipsoidvtkname, rawvtkfname, lp); */ //START FINGER PATCHING //%int i, seed[3]={0,0,0}, extent[6]; //%int xdim=lp.xdim; //%int ydim=lp.ydim; //%int zdim=lp.zdim; //%int num_voxels=xdim*ydim*zdim; //%unsigned char* voxdataflat=new unsigned char [num_voxels]; //%unsigned char* hidata=new unsigned char [num_voxels]; //%unsigned char* lodata=new unsigned char [num_voxels]; //%read_minc_file ("Compression.HighSmooth.mnc", hidata); //%for ( i=0 ; i 0 ) { //% ErrorStats es=PatchObjectBatch (ctdata, sbpdata, CurrentHandles, TestObjectNum, lp); //% es.Print(); //% CurrentHandles=es.CurrentHandles; //%} if ((StartingHandles + NumObjects) > 0) { ErrorStats es = patchObjectBatch(ctdata, sbpdata, CurrentHandles, TestObjectNum); if (DebugControl::getDebugOn()) { es.print(); } CurrentHandles = es.getCurrentHandles(); } //cp Segment.BeforePatch.mnc Segment_Corrected.mnc //%read_minc_file ("Segment.BeforePatch.mnc", sbpdata); //%write_minc ("Segment_Corrected.mnc", sbpdata, xdim, ydim, zdim); //%printf("STARTING HANDLES = %d\n", StartingHandles); //%printf("FINAL HANDLES = %d\n", CurrentHandles); //%if ( CurrentHandles == 0 ) printf("CurrentHandles=0; PATCHING COMPLETE.\n"); readIntermediateVolume(sbpdata, "Segment.BeforePatch"); writeIntermediateVolume(sbpdata, "Segment_Corrected"); if (DebugControl::getDebugOn()) { std::cout << "STARTING HANDLES = " << StartingHandles << std::endl; std::cout << "FINAL HANDLES = " << CurrentHandles << std::endl; if (CurrentHandles == 0) { std::cout << "CurrentHandles=0; PATCHING COMPLETE." << std::endl; } } // // Create the output volume // outputVolume = new VolumeFile(sbpdata); outputVolume->makeDefaultFileName("Segment_ErrorCorrected"); outputVolume->setDescriptiveLabel("Segment_ErrorCorrected"); // //Added 5/25/2001: //%CombineVols ("subrect", sbpdata, segdata, segdata, xdim, ydim, zdim); //%write_minc ("Segment_Corrected_Minus_InitialSegmentation.mnc.mnc", sbpdata, xdim, ydim, zdim); //%delete [] segdata; //%delete [] sbpdata; //%delete [] ctdata; VolumeFile::performMathematicalOperation(VolumeFile::VOLUME_MATH_OPERATION_SUBTRACT_POSITIVE, &sbpdata, &segdata, &segdata, &sbpdata); sbpdata.stretchVoxelValues(); writeIntermediateVolume(sbpdata, "Segment_Corrected_Minus_InitialSegmentation"); if (DebugControl::getDebugOn()) { std::cout << "#### CorrectErrors end ####" << std::endl; } return 0; } /** * Patch an object */ BrainModelVolumeSureFitErrorCorrection::ErrorStats BrainModelVolumeSureFitErrorCorrection::patchObjectBatch(VolumeFile& rodata, VolumeFile& sbpdata, const int CurrentHandles, const int TestObjectNum) throw (BrainModelAlgorithmException) { if (DebugControl::getDebugOn()) { std::cout << "#### PatchObjectBatch begin ####" << std::endl; } //START CYCLE ErrorStats es; es.setStartingHandles(CurrentHandles); es.setTestObjectNum(TestObjectNum); es.setCurrentHandles(CurrentHandles); es.setRemainingObjectNum(TestObjectNum); //if ( true ) return es; //%int NumObjects=0, NumCavities=0, NumHandles=0; //%int xdim=lp.xdim; //%int ydim=lp.ydim; //%int zdim=lp.zdim; //%int num_voxels=xdim*ydim*zdim; //%int i, seed[3]={0,0,0}; //%int extent[6]={0,xdim,0,ydim,0,zdim}, ctoextent[6]={0,0,0,0,0,0}; int NumObjects = 0; int NumCavities = 0; int NumHandles = 0; int seed[3] = { 0, 0, 0 }; int extent[6] = { 0, xDim, 0, yDim, 0, zDim }; int ctoextent[6] = { 0, 0, 0, 0, 0, 0 }; //cp TestObjects.mnc RemainingObjects.mnc //%write_minc ("RemainingObjects.mnc", rodata, xdim, ydim, zdim); writeIntermediateVolume(rodata, "RemainingObjects"); //EulerSubVolume.py RemainingObjects.mnc RemainingObjects.euler 0 $ncol 0 $nrow 0 $nslices //%NewEulerSubVolume (rodata, "RemainingObjects.euler", extent, xdim, ydim, zdim, &NumObjects, &NumCavities, &NumHandles); //%printf("PatchObjectBatch post-euler NumHandles=%d; NumObjects=%d\n", NumHandles, NumObjects); //%es.setRemainingObjectNum(NumObjects); //%printf("RemainingObjectNum=%d\n", es.RemainingObjectNum); //%printf("RemainingObjectNum=%d\n", NumObjects); int eulerCount; rodata.getEulerCountsForSegmentationSubVolume(NumObjects, NumCavities, NumHandles, eulerCount, extent); es.setRemainingObjectNum(NumObjects); if (DebugControl::getDebugOn()) { std::cout << "PatchObjectBatch post-euler NumHandles=" << NumHandles << "; NumObjects=" << NumObjects << std::endl; std::cout << "RemainingObjectNum=" << es.getRemainingObjectNum() << std::endl; std::cout << "RemainingObjectNum=" << NumObjects << std::endl; } //Sculpt.py 0 2 0 $ncol 0 $nrow 0 $nslices CompositeAllPatches.Dilate.mnc Crossovers.thresh.mnc CompositeAllPatches_CrossoverSculpt //%unsigned char* capddata=new unsigned char [num_voxels]; //%unsigned char* voxdataflat=new unsigned char [num_voxels]; //%read_minc_file ("CompositeAllPatches.Dilate.mnc", capddata); //%for ( i=0 ; i 0 and CurrentHandles > 0: //%FILE *errorlimfile; //%unsigned char* ctodata=new unsigned char [num_voxels]; //%errorlimfile=fopen ("ErrorLimits.xyz", "w"); const QString errorlimfileName("ErrorLimits.xyz"); std::ofstream errorlimfile(errorlimfileName.toAscii().constData()); if (! errorlimfile) { throw BrainModelAlgorithmException("Unable to open ErrorLimits.xyz for writing."); } VolumeFile ctodata; //resorted to this because couldn't es.set* in subroutines //%int TestStats[3]={es.DisconnectFlag,es.CurrentHandles,es.CavitiesPatched}; //%while ((es.RemainingObjectNum>0) && (es.CurrentHandles>0)) { int TestStats[3] = { es.getDisconnectFlag(), es.getCurrentHandles(), es.getCavitiesPatched() }; while ((es.getRemainingObjectNum() > 0) && (es.getCurrentHandles() > 0)) { allowEventsToProcess(); { std::ostringstream str; str << "Processing handle " << es.getCurrentTestNum() << " of " << es.getStartingHandles(); if (DebugControl::getDebugOn()) { std::cout << str.str() << std::endl; } } if (DebugControl::getDebugOn()) { std::cout << "Iteration: " << es.getCurrentTestNum() << std::endl; } //FillBiggestObject.py RemainingObjects.mnc CurrentTestObject 0 $ncol 0 $nrow 0 $nslices //%for ( i=0 ; i= es.MaskHandlesBefore ) { //% printf("EXO-HANDLE TEST %d: NO HANDLE REDUCTION\n", exo_count); //% delete [] toicdata; //% delete [] toesfdata; //% delete [] toesdata; //% delete [] maskdata; //% delete [] voxdataflat; //% return; //%} int NumObjects, NumCavities, NumHandles, eulerCount; voxdataflat.getEulerCountsForSegmentationSubVolume(NumObjects, NumCavities, NumHandles, eulerCount, ctoextent); int MaskHandlesAfter = NumHandles; if (DebugControl::getDebugOn()) { std::cout << "MaskHandlesBefore = " << es.getMaskHandlesBefore() << "; MaskHandlesAfter = " << MaskHandlesAfter << std::endl; } if (MaskHandlesAfter >= es.getMaskHandlesBefore()) { if (DebugControl::getDebugOn()) { std::cout << "EXO-HANDLE TEST " << exoCount << ": NO HANDLE REDUCTION" << std::endl; } return; } //FillBiggestObject.py Segment.AfterPatch.fill.mnc Segment.AfterPatch.flood 0 $ncol 0 $nrow 0 $nslices //%FindBiggestObjectWithinMask (voxdataflat, xdim, ydim, zdim, extent[0],extent[1],extent[2],extent[3],extent[4],extent[5], seed); //%vtkFloodFill (seed, voxdataflat, 255, 255, 0, xdim, ydim, zdim); //%write_minc ("Segment.AfterPatch.flood.mnc", voxdataflat, xdim, ydim, zdim); voxdataflat.findBiggestObjectWithinMask(extent, 255.0, 255.0, seed); voxdataflat.floodFillWithVTK(seed, 255, 255, 0); writeIntermediateVolume(voxdataflat, "Segment.AfterPatch.flood"); //NewEulerSubVolume.py Segment.AfterPatch.flood.mnc AfterPatch.euler 0 $ncol 0 $nrow 0 $nslices //%NewEulerSubVolume (voxdataflat, "AfterPatch.euler", extent, xdim, ydim, zdim, &NumObjects, &NumCavities, &NumHandles); //%if ( NumHandles >= es.CurrentHandles ) { //% printf("FALSE POSITIVE - HANDLES NOT DECREASED\n"); //% delete [] toicdata; //% delete [] toesfdata; //% delete [] toesdata; //% delete [] maskdata; //% delete [] voxdataflat; //% return; //%} voxdataflat.getEulerCountsForSegmentationSubVolume(NumObjects, NumCavities, NumHandles, eulerCount, extent); if (NumHandles >= es.getCurrentHandles()) { if (DebugControl::getDebugOn()) { std::cout << "FALSE POSITIVE - HANDLES NOT DECREASED" << std::endl; } return; } //cp Segment.AfterPatch.flood.mnc Segment.BeforePatch.mnc //%for ( i=0 ; i= es.MaskHandlesBefore ) { //% printf("ENDO-HANDLE TEST %d: NO HANDLE REDUCTION\n", endo_count); //% delete [] toesdata; //% delete [] maskdata; //% delete [] voxdataflat; //% return; //%} int NumObjects, NumCavities, NumHandles, eulerCount; voxdataflat.getEulerCountsForSegmentationSubVolume(NumObjects, NumCavities, NumHandles, eulerCount, ctoextent); const int MaskHandlesAfter = NumHandles; if (DebugControl::getDebugOn()) { std::cout << "MaskHandlesBefore = " << es.getMaskHandlesBefore() << "; MaskHandlesAfter = " << MaskHandlesAfter << std::endl; } if (MaskHandlesAfter >= es.getMaskHandlesBefore()) { if (DebugControl::getDebugOn()) { std::cout << "ENDO-HANDLE TEST " << endoCount << ": NO HANDLE REDUCTION" << std::endl; } return; } //FillBiggestObject.py Segment.AfterPatch.fill.mnc Segment.AfterPatch.flood 0 $ncol 0 $nrow 0 $nslices //%FindBiggestObjectWithinMask (voxdataflat, xdim, ydim, zdim, extent[0],extent[1],extent[2],extent[3],extent[4],extent[5], seed); //%vtkFloodFill (seed, voxdataflat, 255, 255, 0, xdim, ydim, zdim); //%write_minc ("Segment.AfterPatch.flood.mnc", voxdataflat, xdim, ydim, zdim); voxdataflat.findBiggestObjectWithinMask(extent, 255.0, 255.0, seed); voxdataflat.floodFillWithVTK(seed, 255, 255, 0); writeIntermediateVolume(voxdataflat, "Segment.AfterPatch.flood"); //EulerSubVolume.py Segment.AfterPatch.flood.mnc AfterPatch.euler 0 $ncol 0 $nrow 0 $nslices //%NewEulerSubVolume (voxdataflat, "AfterPatch.euler", extent, xdim, ydim, zdim, &NumObjects, &NumCavities, &NumHandles); //%if ( NumHandles >= es.CurrentHandles ) { //% printf("FALSE POSITIVE - HANDLES NOT DECREASED\n"); //% delete [] toesdata; //% delete [] maskdata; //% delete [] voxdataflat; //% return; //%} voxdataflat.getEulerCountsForSegmentationSubVolume(NumObjects, NumCavities, NumHandles, eulerCount, extent); if ( NumHandles >= es.getCurrentHandles() ) { if (DebugControl::getDebugOn()) { std::cout << "FALSE POSITIVE - HANDLES NOT DECREASED" << std::endl; } return; } //cp Segment.AfterPatch.flood.mnc Segment.BeforePatch.mnc //%for ( i=0 ; i::iterator iter = intermediateVolumeFilesInMemory.find(nameIn); if (iter == intermediateVolumeFilesInMemory.end()) { throw BrainModelAlgorithmException( "PROGRAM ERROR: Unable to find volume named " + nameIn + " in intermediate volume files in memory."); } // // copy the volume to output // vf = *(iter->second); return; } try { QString name; QDir intermedDir(intermediateFilesSubDirectory); if (intermedDir.exists()) { name.append(intermediateFilesSubDirectory); name.append("/"); } name.append(nameIn); name.append("+orig"); switch (typeOfVolumeFilesToWrite) { case VolumeFile::FILE_READ_WRITE_TYPE_RAW: throw FileException("ERROR: Intermediate volume wants to be read in RAW"); break; case VolumeFile::FILE_READ_WRITE_TYPE_AFNI: name.append(SpecFile::getAfniVolumeFileExtension()); break; case VolumeFile::FILE_READ_WRITE_TYPE_ANALYZE: name.append(SpecFile::getAnalyzeVolumeFileExtension()); break; case VolumeFile::FILE_READ_WRITE_TYPE_NIFTI: { name.append(SpecFile::getNiftiVolumeFileExtension()); const QString compressName = name + ".gz"; if (QFile::exists(compressName)) { name = compressName; } } break; case VolumeFile::FILE_READ_WRITE_TYPE_NIFTI_GZIP: { name.append(SpecFile::getNiftiVolumeFileExtension()); const QString compressName = name + ".gz"; if (QFile::exists(compressName)) { name = compressName; } } break; case VolumeFile::FILE_READ_WRITE_TYPE_SPM_OR_MEDX: name.append(SpecFile::getAnalyzeVolumeFileExtension()); break; case VolumeFile::FILE_READ_WRITE_TYPE_WUNIL: name.append(SpecFile::getWustlVolumeFileExtension()); break; case VolumeFile::FILE_READ_WRITE_TYPE_UNKNOWN: throw FileException("ERROR: Intermediate Volume wants to be read in UNKNOWN"); break; } vf.readFile(name); if (DebugControl::getDebugOn()) { std::cout << "Read Volume File: " << name.toAscii().constData() << std::endl; } } catch (FileException& e) { throw (BrainModelAlgorithmException(e.whatQString())); } } /** * Write a volume. */ void BrainModelVolumeSureFitErrorCorrection::writeIntermediateVolume(VolumeFile& vf, const QString& nameIn) throw (BrainModelAlgorithmException) { writeIntermediateVolume(&vf, nameIn); } /** * Write a volume. */ void BrainModelVolumeSureFitErrorCorrection::writeIntermediateVolume(VolumeFile* vf, const QString& nameIn) throw (BrainModelAlgorithmException) { if (keepIntermediateFilesInMemoryFlag) { // // If volume with name exists, free its memory and remove from map // std::map::iterator iter = intermediateVolumeFilesInMemory.find(nameIn); if (iter != intermediateVolumeFilesInMemory.end()) { delete iter->second; intermediateVolumeFilesInMemory.erase(iter); } // // Keep file in memory // intermediateVolumeFilesInMemory[nameIn] = new VolumeFile(*vf); return; } try { vf->setDescriptiveLabel(nameIn); QString name; QDir intermedDir(intermediateFilesSubDirectory); if (intermedDir.exists()) { name.append(intermediateFilesSubDirectory); name.append("/"); } name.append(nameIn); QString fileNameWritten, dataFileNameWritten; VolumeFile::writeVolumeFile(vf, typeOfVolumeFilesToWrite, name, false, fileNameWritten, dataFileNameWritten); /* name.append("+orig"); // so readable by AFNI QString brickName(name); brickName.append(".BRIK"); name.append(SpecFile::getAfniVolumeFileExtension()); vf->writeFile(name); */ if (DebugControl::getDebugOn()) { std::cout << "Write Volume File: " << fileNameWritten.toAscii().constData() << std::endl; } intermediateFileNames.push_back(fileNameWritten); if (dataFileNameWritten.isEmpty() == false) { intermediateFileNames.push_back(dataFileNameWritten); } } catch (FileException& e) { throw (BrainModelAlgorithmException(e.whatQString())); } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeSegmentationStereotaxic.h0000664000175000017500000000655311572067322030064 0ustar michaelmichael #ifndef __BRAIN_MODEL_VOLUME_SEGMENTATION_STEREOTAXIC_H__ #define __BRAIN_MODEL_VOLUME_SEGMENTATION_STEREOTAXIC_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelAlgorithm.h" #include "BrainModelVolumeSureFitSegmentation.h" #include "Structure.h" class VolumeFile; /// class for automatic segmentation of anatomical volume in know stereotaxic space class BrainModelVolumeSegmentationStereotaxic : public BrainModelAlgorithm { public: // constructor BrainModelVolumeSegmentationStereotaxic(BrainSet* brainSetIn, const VolumeFile* anatomicalVolumeFileIn, const int uniformityIterationsIn, const bool disconnectEyeFlagIn, const BrainModelVolumeSureFitSegmentation::ERROR_CORRECTION_METHOD errorCorrectVolumeMethodIn, const bool errorCorrectSurfaceFlagIn, const bool maxPolygonsFlagIn, const bool flatteningFilesFlagIn); // destructor ~BrainModelVolumeSegmentationStereotaxic(); // execute the algorithm void execute() throw (BrainModelAlgorithmException); /// get the default number of uniformity iterations static int getDefaultUniformityIterations() { return 0; } protected: /// generate the segmentation void generateSegmentation(const QString& maskVolumeFileName) throw (BrainModelAlgorithmException); /// get the segmentation mask volume file names void getSegmentationMaskVolumeFileNames(const QString& spaceName, const QString& structureName, QString& maskNameOut) throw (BrainModelAlgorithmException); /// write debugging volume void writeDebugVolume(VolumeFile& vf, const QString& fileName); /// name of anatomical volume const VolumeFile* anatomicalVolumeFile; /// error correct volume method BrainModelVolumeSureFitSegmentation::ERROR_CORRECTION_METHOD errorCorrectVolumeMethod; /// error correct surface bool errorCorrectSurfaceFlag; /// generate maximum polygons in surface bool maxPolygonsFlag; /// generate flattening files bool flatteningFilesFlag; /// number of uniformity iterations int uniformityIterations; /// disconnect the eye flag bool disconnectEyeFlag; }; #endif // __BRAIN_MODEL_VOLUME_SEGMENTATION_STEREOTAXIC_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeSegmentationStereotaxic.cxx0000664000175000017500000004225411572067322030435 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainModelVolumeSegmentationStereotaxic.h" #include "BrainSet.h" #include "CommaSeparatedValueFile.h" #include "FileUtilities.h" #include "SegmentationMaskListFile.h" #include "SpecFile.h" #include "StatisticHistogram.h" #include "StringTable.h" #include "Structure.h" #include "VolumeFile.h" /** * constructor. */ BrainModelVolumeSegmentationStereotaxic::BrainModelVolumeSegmentationStereotaxic( BrainSet* brainSetIn, const VolumeFile* anatomicalVolumeFileIn, const int uniformityIterationsIn, const bool disconnectEyeFlagIn, const BrainModelVolumeSureFitSegmentation::ERROR_CORRECTION_METHOD errorCorrectVolumeMethodIn, const bool errorCorrectSurfaceFlagIn, const bool maxPolygonsFlagIn, const bool flatteningFilesFlagIn) : BrainModelAlgorithm(brainSetIn), anatomicalVolumeFile(anatomicalVolumeFileIn) { disconnectEyeFlag = disconnectEyeFlagIn; uniformityIterations = uniformityIterationsIn; errorCorrectVolumeMethod = errorCorrectVolumeMethodIn; errorCorrectSurfaceFlag = errorCorrectSurfaceFlagIn; maxPolygonsFlag = maxPolygonsFlagIn; flatteningFilesFlag = flatteningFilesFlagIn; } /** * destructor. */ BrainModelVolumeSegmentationStereotaxic::~BrainModelVolumeSegmentationStereotaxic() { } /** * execute the algorithm. */ void BrainModelVolumeSegmentationStereotaxic::execute() throw (BrainModelAlgorithmException) { // // Check inputs // if (brainSet == NULL) { throw BrainModelAlgorithmException("BrainSet is NULL."); } if (anatomicalVolumeFile == NULL) { throw BrainModelAlgorithmException("Anatomical volume file is NULL."); } const QString& stereotaxicSpaceName = brainSet->getStereotaxicSpace().getName(); if (stereotaxicSpaceName.isEmpty()) { throw BrainModelAlgorithmException("SpecFile has no stereotaxic space."); } // // Only do left and right structures // const Structure::STRUCTURE_TYPE structure = brainSet->getStructure().getType(); QString structureName; switch (structure) { case Structure::STRUCTURE_TYPE_CORTEX_LEFT: structureName = "LEFT"; break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT: structureName = "RIGHT"; break; case Structure::STRUCTURE_TYPE_CORTEX_BOTH: throw BrainModelAlgorithmException("Structure BOTH not allowed, must be RIGHT or LEFT"); break; case Structure::STRUCTURE_TYPE_CEREBELLUM: throw BrainModelAlgorithmException("Structure CEREBELLUM not allowed, must be RIGHT or LEFT"); break; case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_LEFT: throw BrainModelAlgorithmException("Structure CEREBELLUM OR LEFT not allowed, must be RIGHT or LEFT"); break; case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_RIGHT: throw BrainModelAlgorithmException("Structure CEREBELLUM OR RIGHT not allowed, must be RIGHT or LEFT"); break; case Structure::STRUCTURE_TYPE_CORTEX_LEFT_OR_CEREBELLUM: throw BrainModelAlgorithmException("Structure LEFT CEREBELLUM not allowed, must be RIGHT or LEFT"); break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT_OR_CEREBELLUM: throw BrainModelAlgorithmException("Structure RIGHT CEREBELLUM not allowed, must be RIGHT or LEFT"); break; case Structure::STRUCTURE_TYPE_CEREBRUM_CEREBELLUM: throw BrainModelAlgorithmException("Structure CEREBRUM CEREBELLUM not allowed, must be RIGHT or LEFT"); break; case Structure::STRUCTURE_TYPE_SUBCORTICAL: throw BrainModelAlgorithmException("Structure SUBCORTICAL not allowed, must be RIGHT or LEFT"); break; case Structure::STRUCTURE_TYPE_ALL: throw BrainModelAlgorithmException("Structure ALL not allowed, must be RIGHT or LEFT"); break; case Structure::STRUCTURE_TYPE_INVALID: throw BrainModelAlgorithmException("Structure in SpecFile is invalid"); break; } // // Find the names of the mask volumes // QString maskVolumeName; getSegmentationMaskVolumeFileNames(stereotaxicSpaceName, structureName, maskVolumeName); // // Generate segmentation // generateSegmentation(maskVolumeName); } /** * generate the segmentation. */ void BrainModelVolumeSegmentationStereotaxic::generateSegmentation( const QString& maskVolumeFileName) throw (BrainModelAlgorithmException) { // // Read the mask volume // VolumeFile maskVolume; try { maskVolume.readFile(maskVolumeFileName); } catch (FileException& e) { throw BrainModelAlgorithmException(e); } // // Get extent of the non-zero voxels in the max volume // int maskExtent[6]; float coordExtent[6]; maskVolume.getNonZeroVoxelExtent(maskExtent, coordExtent); const int padExtent = 1; maskExtent[0] -= padExtent; maskExtent[1] += padExtent; maskExtent[2] -= padExtent; maskExtent[3] += padExtent; maskExtent[4] -= padExtent; maskExtent[5] += padExtent; // // Convert mask extent to stereotaxic coordinates // const int minMaskExtent[3] = { maskExtent[0], maskExtent[2], maskExtent[4] }; const int maxMaskExtent[3] = { maskExtent[1], maskExtent[3], maskExtent[5] }; float minExtentXYZ[3], maxExtentXYZ[3]; maskVolume.getVoxelCoordinate(minMaskExtent, minExtentXYZ); maskVolume.getVoxelCoordinate(maxMaskExtent, maxExtentXYZ); // // Add anatomical volume name to spec file // brainSet->addToSpecFile(SpecFile::getVolumeAnatomyFileTag(), anatomicalVolumeFile->getFileName()); // // Copy anatomical volume // VolumeFile volume(*anatomicalVolumeFile); // // Convert mask extent stereotaxic coordinates into input volume slices // int minCropping[3], maxCropping[3]; volume.convertCoordinatesToVoxelIJK(minExtentXYZ, minCropping); volume.convertCoordinatesToVoxelIJK(maxExtentXYZ, maxCropping); const int cropping[6] = { minCropping[0], maxCropping[0], minCropping[1], maxCropping[1], minCropping[2], maxCropping[2] }; // // Crop the input volume // volume.resize(cropping); writeDebugVolume(volume, "anatomy_cropped"); // // Mask the volume to extract the hemisphere // DO NOT DO THIS FOR NOW as it causes a problem with cutting the corpus callosum // //volume.maskWithVolume(&maskVolume); // // Stretch the voxels to 0 to 255 // volume.stretchVoxelValues(); writeDebugVolume(volume, "anatomy_0_255"); // // Get a histogram for the volume // StatisticHistogram uniformHistogram = *(volume.getHistogram()); // // get histogram measurements // int csfPeakBucketNumber; int grayPeakBucketNumber; int whitePeakBucketNumber; int grayMinimumBucketNumber; int whiteMaximumBucketNumber; int grayWhiteBoundaryBucketNumber; uniformHistogram.getGrayWhitePeakEstimates(grayPeakBucketNumber, whitePeakBucketNumber, grayMinimumBucketNumber, whiteMaximumBucketNumber, grayWhiteBoundaryBucketNumber, csfPeakBucketNumber); // // Perform non-uniformity correction on the volume // if (uniformityIterations > 0) { const float uniformGrayMin = uniformHistogram.getDataValueForBucket(grayMinimumBucketNumber); const float uniformWhiteMax = uniformHistogram.getDataValueForBucket(whiteMaximumBucketNumber); std::cout << "Bias correction Gray Min: " << uniformGrayMin << " White Max: " << uniformWhiteMax << std::endl; if ((uniformGrayMin > 0) && (uniformWhiteMax > 0)) { volume.biasCorrectionWithAFNI(static_cast(uniformGrayMin), static_cast(uniformWhiteMax), uniformityIterations); writeDebugVolume(volume, "bias_corrected"); } else { std::cout << "Uniformity correction skipped due to invalid gray/white." << std::endl; } } // // Get histogram for gray/white peaks // StatisticHistogram grayWhiteHistogram = *(volume.getHistogram()); grayWhiteHistogram.getGrayWhitePeakEstimates(grayPeakBucketNumber, whitePeakBucketNumber, grayMinimumBucketNumber, whiteMaximumBucketNumber, grayWhiteBoundaryBucketNumber, csfPeakBucketNumber); const float whiteMatterMaximum = grayWhiteHistogram.getDataValueForBucket(whiteMaximumBucketNumber); std::cout << "White matter maximum for segmentation: " << whiteMatterMaximum << std::endl; // // Get the peaks and adjust the gray peak a little bit low // const int grayOffset = 0; //-3; const float grayPeak = grayWhiteHistogram.getDataValueForBucket(grayPeakBucketNumber + grayOffset); const float whitePeak = grayWhiteHistogram.getDataValueForBucket(whitePeakBucketNumber); std::cout << "Gray Peak: " << grayPeak << " White Peak: " << whitePeak << std::endl; if ((grayPeak <= 0) || (whitePeak <= 0)) { throw BrainModelAlgorithmException("ERROR: Invalid gray or white peak."); } // // Get anterior commissure position // const float zeros[3] = { 0.0, 0.0, 0.0 }; int acIJK[3]; volume.convertCoordinatesToVoxelIJK(zeros, acIJK); // // Segment the volume // const int padding[6] = { 0, 0, 0, 0, 0, 0 }; BrainModelVolumeSureFitSegmentation sureFit(brainSet, &volume, NULL, VolumeFile::FILE_READ_WRITE_TYPE_NIFTI_GZIP, acIJK, padding, whitePeak, grayPeak, 0.0, brainSet->getStructure().getType(), disconnectEyeFlag, // eye true, // hindbrain true, // high thresh true, // cut corpus callosum true, // segment anatomy true, // fill ventricles errorCorrectVolumeMethod, // correct volume true, // generate surfaces maxPolygonsFlag, // max polygons errorCorrectSurfaceFlag, // correct surface true, // inflated flatteningFilesFlag, // very inflated flatteningFilesFlag, // ellipsoid flatteningFilesFlag, // sphere flatteningFilesFlag, // CMW flatteningFilesFlag, // hull, flatteningFilesFlag, // Depth, Curve, Geography false, // Landmarks true); // auto save sureFit.setVolumeMask(&maskVolume); //sureFit.setWhiteMatterMaximum(whiteMatterMaximum); sureFit.execute(); } /** * get the segmentation mask volume file names. */ void BrainModelVolumeSegmentationStereotaxic::getSegmentationMaskVolumeFileNames( const QString& spaceNameIn, const QString& structureNameIn, QString& maskNameOut) throw (BrainModelAlgorithmException) { maskNameOut = ""; // // Read in segmentation masks list file // const QString maskVolumesDirectory(BrainSet::getCaretHomeDirectory() + "/data_files/segmentation_masks/"); const QString maskVolumeListFileName(maskVolumesDirectory + "mask_list.txt.csv"); //CommaSeparatedValueFile maskVolumeListFile; SegmentationMaskListFile maskVolumeListFile; try { maskVolumeListFile.readFile(maskVolumeListFileName); } catch (FileException& e) { throw BrainModelAlgorithmException(e); } /* // // Get the Mask Volumes String Table // const QString maskTableName("MaskVolumes"); const StringTable* maskVolumesTable = maskVolumeListFile.getDataSectionByName(maskTableName); if (maskVolumesTable == NULL) { throw BrainModelAlgorithmException("Unable to find table named " + maskTableName + " in " + maskVolumeListFileName); } // // Find columns numbers of data // const int spaceCol = maskVolumesTable->getColumnIndexFromName("Space"); const int structureCol = maskVolumesTable->getColumnIndexFromName("Structure"); const int volumeCol = maskVolumesTable->getColumnIndexFromName("MaskVolume"); if ((spaceCol < 0) || (structureCol < 0) || (volumeCol < 0)) { throw BrainModelAlgorithmException("Missing required columns in " + maskVolumeListFileName); } // // find the mask volume names // const QString& spaceName(spaceNameIn.toLower()); const QString& structureName(structureNameIn.toLower()); const int numRows = maskVolumesTable->getNumberOfRows(); for (int i = 0; i < numRows; i++) { if (spaceName == maskVolumesTable->getElement(i, spaceCol).toLower()) { if (structureName == maskVolumesTable->getElement(i, structureCol).toLower()) { maskNameOut = maskVolumesDirectory + maskVolumesTable->getElement(i, volumeCol); } } } */ maskNameOut = maskVolumeListFile.getSegmentationMaskFileName(spaceNameIn, structureNameIn); if (maskNameOut.isEmpty()) { QString msg("Unable to find mask volume for space \"" + spaceNameIn + "\" and structure \"" + structureNameIn + "\".\n" + "Available masks are: \n" + maskVolumeListFile.getAvailableMasks(" ")); /* for (int i = 0; i < numRows; i++) { msg += (maskVolumesTable->getElement(i, spaceCol).toLower() + " " + maskVolumesTable->getElement(i, structureCol).toLower() + "\n"); } */ throw BrainModelAlgorithmException(msg); } if (QFile::exists(maskNameOut) == false) { throw BrainModelAlgorithmException("Mask Volume " + maskNameOut + " is missing."); } } /** * write debugging volume. */ void BrainModelVolumeSegmentationStereotaxic::writeDebugVolume(VolumeFile& vf, const QString& fileNameIn) { //if (DebugControl::getDebugOn()) { const QString name("seg_debug_" + fileNameIn + SpecFile::getNiftiGzipVolumeFileExtension()); try { vf.writeFile(name); } catch (FileException& e) { std::cout << "Writing debug volume: " << e.whatQString().toAscii().constData() << std::endl; } //} } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeRegionOfInterest.h0000664000175000017500000001343111572067322026433 0ustar michaelmichael #ifndef __BRAIN_MODEL_VOLUME_REGION_OF_INTEREST_H__ #define __BRAIN_MODEL_VOLUME_REGION_OF_INTEREST_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelAlgorithmException.h" class BrainSet; class VolumeFile; /// keeps track of the volume used interactively for region of interest operations /// and performs operations using the region of interest class BrainModelVolumeRegionOfInterest { public: // constructor BrainModelVolumeRegionOfInterest(BrainSet* brainSetIn); // destructor ~BrainModelVolumeRegionOfInterest(); // set the volume ROI to all voxels in volume void setVolumeROIToAllVoxels(const VolumeFile* vf); // set the volume ROI to all displayed voxels in volume void setVolumeROIToAllDisplayedVoxels(const VolumeFile* vf); // set the volume ROI to all voxels within a range in volume void setVolumeROIToVoxelsInRangeOfValues(const VolumeFile* vf, const float minValue, const float maxValue); // set the volume ROI to all paint voxels with the specified name void setVolumeROIToPaintIDVoxels(const VolumeFile* vf, const QString& paintName); /// get the display volume ROI in graphics windows flag bool getDisplayVolumeROI() const { return displayVolumeROI; } /// set display the volume ROI in graphics windows flag void setDisplayVolumeROI(const bool b) { displayVolumeROI = b; } // get the number of voxels in the ROI int getNumberOfVoxelsInROI() const; /// get the region of interest volume VolumeFile* getROIVolume() { return roiVolume; } // assign paint id to paint volume for ROI voxels void operationAssignPaintVolumeID(VolumeFile* paintVolume, const QString& paintName) const throw (BrainModelAlgorithmException); // assign function value to functional volume for ROI voxels void operationAssignFunctionalVolumeValue(VolumeFile* functionalVolume, const float value) const throw (BrainModelAlgorithmException); // paint region center of gravity report void operationPaintRegionCenterOfGravity(const VolumeFile* paintVolume, QString& reportTextOut) const throw (BrainModelAlgorithmException); // paint percentage report void operationPaintPercentageReport(const VolumeFile* paintVolume, QString& reportTextOut) const throw (BrainModelAlgorithmException); // probabilistic paint volume overlap analysis void operationPaintOverlapAnalysis(const std::vector& paintVolumes, QString& reportTextOut) const throw (BrainModelAlgorithmException); // segmentation region center of gravity report void operationSegmentationRegionCenterOfGravity(const VolumeFile *segmentVolume, QString& reportTextOut) const throw (BrainModelAlgorithmException); protected: // reset the ROI volume void resetROIVolume(const VolumeFile* vf, const bool colorTheVolumesVoxelsFlag); // see if a stereotaxic coordinate is inside the ROI bool insideVolumeROI(const float xyz[3]) const; // determine which voxels are within the ROI volume // use std::vector since std::vector packs the bools into bits int determineVoxelsWithinVolumeROI(const VolumeFile* volume, const float minValue, const float maxValue, std::vector& voxelInROI) const; // create the report QString createReport(const VolumeFile* operatingVolume, const QString& description, const QString& operationText, const int totalNumberOfVoxels, const int numVoxelsInROI) const; // create the report QString createReport(const std::vector operatingVolumes, const QString& description, const QString& operationText, const int totalNumberOfVoxels, const int numVoxelsInROI) const; /// the brain set using this ROI BrainSet* brainSet; /// the volume containing the region of interest VolumeFile* roiVolume; /// display the volume ROI bool displayVolumeROI; /// text containing information about the ROI selection QString reportROIVolumeInfoText; }; #endif // __BRAIN_MODEL_VOLUME_REGION_OF_INTEREST_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeRegionOfInterest.cxx0000664000175000017500000007751211572067322027020 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "BrainModelVolumeRegionOfInterest.h" #include "BrainModelVolumeVoxelColoring.h" #include "BrainSet.h" #include "FileUtilities.h" #include "VolumeFile.h" /** * constructor. */ BrainModelVolumeRegionOfInterest::BrainModelVolumeRegionOfInterest(BrainSet* brainSetIn) { brainSet = brainSetIn; roiVolume = new VolumeFile; displayVolumeROI = false; } /** * destructor. */ BrainModelVolumeRegionOfInterest::~BrainModelVolumeRegionOfInterest() { if (roiVolume != NULL) { delete roiVolume; roiVolume = NULL; } } /** * get the number of voxels in the ROI. */ int BrainModelVolumeRegionOfInterest::getNumberOfVoxelsInROI() const { const int numVoxels = roiVolume->getTotalNumberOfVoxelElements(); const float* voxels = roiVolume->getVoxelData(); int cnt = 0; for (int i = 0; i < numVoxels; i++) { if (voxels[i] != 0.0) { cnt++; } } return cnt; } /** * assign paint id to paint volume for ROI voxels. */ void BrainModelVolumeRegionOfInterest::operationAssignPaintVolumeID( VolumeFile* paintVolume, const QString& paintName) const throw (BrainModelAlgorithmException) { if (getNumberOfVoxelsInROI() <= 0) { throw BrainModelAlgorithmException("The region of interest contains no voxels."); } // // See which voxels are in the ROI // std::vector voxelInROI; const int numVoxelsInROI = determineVoxelsWithinVolumeROI(paintVolume, -std::numeric_limits::min(), std::numeric_limits::max(), voxelInROI); if (numVoxelsInROI <= 0) { throw BrainModelAlgorithmException("No voxels from the functional volume are within the ROI volume.\n" "Are the stereotaxic coordinates properly set?"); } // // Index of paint being assigned // const int paintIndex = paintVolume->addRegionName(paintName); // // Determine the COG of the voxels in the ROI // int dim[3]; paintVolume->getDimensions(dim); for (int i = 0; i < dim[0]; i++) { for (int j = 0; j < dim[1]; j++) { for (int k = 0; k < dim[2]; k++) { const int flatIndex = paintVolume->getVoxelDataIndex(i, j, k); if (voxelInROI[flatIndex]) { paintVolume->setVoxel(i, j, k, 0, paintIndex); } } } } } /** * assign function value to functional volume for ROI voxels. */ void BrainModelVolumeRegionOfInterest::operationAssignFunctionalVolumeValue( VolumeFile* functionalVolume, const float value) const throw (BrainModelAlgorithmException) { if (getNumberOfVoxelsInROI() <= 0) { throw BrainModelAlgorithmException("The region of interest contains no voxels."); } // // See which voxels are in the ROI // std::vector voxelInROI; const int numVoxelsInROI = determineVoxelsWithinVolumeROI(functionalVolume, -std::numeric_limits::min(), std::numeric_limits::max(), voxelInROI); if (numVoxelsInROI <= 0) { throw BrainModelAlgorithmException("No voxels from the functional volume are within the ROI volume.\n" "Are the stereotaxic coordinates properly set?"); } // // Determine the COG of the voxels in the ROI // int dim[3]; functionalVolume->getDimensions(dim); for (int i = 0; i < dim[0]; i++) { for (int j = 0; j < dim[1]; j++) { for (int k = 0; k < dim[2]; k++) { const int flatIndex = functionalVolume->getVoxelDataIndex(i, j, k); if (voxelInROI[flatIndex]) { functionalVolume->setVoxel(i, j, k, 0, value); } } } } } /** * paint region center of gravity report. */ void BrainModelVolumeRegionOfInterest::operationPaintRegionCenterOfGravity( const VolumeFile* paintVolume, QString& reportTextOut) const throw (BrainModelAlgorithmException) { reportTextOut = ""; if (getNumberOfVoxelsInROI() <= 0) { throw BrainModelAlgorithmException("The region of interest contains no voxels."); } // // See which voxels are in the ROI // std::vector voxelInROI; const int numVoxelsInROI = determineVoxelsWithinVolumeROI(paintVolume, 0, std::numeric_limits::max(), voxelInROI); if (numVoxelsInROI <= 0) { throw BrainModelAlgorithmException("No voxels from the paint volume are within the ROI volume.\n" "Are the stereotaxic coordinates properly set?"); } // // Get number of paint names // const int numPaintNames = paintVolume->getNumberOfRegionNames(); if (numPaintNames <= 0) { throw BrainModelAlgorithmException("There are no paint regions in the volume."); return; } const int totalSize = numPaintNames * 3; double* voxelCOG = new double[totalSize]; double* coordCOG = new double[totalSize]; double* counter = new double[numPaintNames]; for (int i = 0; i < totalSize; i++) { voxelCOG[i] = 0.0; coordCOG[i] = 0.0; if (i < numPaintNames) { counter[i] = 0.0; } } // // Determine the COG of the voxels in the ROI // int dim[3]; paintVolume->getDimensions(dim); for (int i = 0; i < dim[0]; i++) { for (int j = 0; j < dim[1]; j++) { for (int k = 0; k < dim[2]; k++) { const int flatIndex = paintVolume->getVoxelDataIndex(i, j, k); if (voxelInROI[flatIndex]) { const int paintIndex = static_cast(paintVolume->getVoxel(i, j, k)); const int paintIndex3 = paintIndex * 3; voxelCOG[paintIndex3 + 0] += i; voxelCOG[paintIndex3 + 1] += j; voxelCOG[paintIndex3 + 2] += k; float xyz[3]; paintVolume->getVoxelCoordinate(i, j, k, xyz); coordCOG[paintIndex3 + 0] += xyz[0]; coordCOG[paintIndex3 + 1] += xyz[1]; coordCOG[paintIndex3 + 2] += xyz[2]; counter[paintIndex] += 1.0; } } } } std::ostringstream str; str.precision(2); str.setf(std::ios::fixed); std::vector sortedInfo; for (int i = 0; i < numPaintNames; i++) { const int i3 = i * 3; str.str(""); const QString name(paintVolume->getRegionNameFromIndex(i)); const double count = counter[i]; str << name.toAscii().constData() << " has " << static_cast(count) << " matching voxels.\n"; if (count > 0) { str << " Voxel IJK C.O.G.: (" << voxelCOG[i3 + 0] / count << ", " << voxelCOG[i3 + 1] / count << ", " << voxelCOG[i3 + 2] / count << ")\n"; str << " Voxel Coordinate C.O.G.: (" << coordCOG[i3 + 0] / count << ", " << coordCOG[i3 + 1] / count << ", " << coordCOG[i3 + 2] / count << ")\n"; } str << "\n"; sortedInfo.push_back(str.str().c_str()); } std::sort(sortedInfo.begin(), sortedInfo.end()); QString operationText; for (int i = 0; i < static_cast(sortedInfo.size()); i++) { operationText += sortedInfo[i]; } delete[] voxelCOG; delete[] coordCOG; delete[] counter; const int totalNumberOfVoxels = dim[0] * dim[1] * dim[2]; reportTextOut = createReport(paintVolume, "Paint Identification Center of Gravity", operationText, totalNumberOfVoxels, numVoxelsInROI); } /** * paint percentage report. */ void BrainModelVolumeRegionOfInterest::operationPaintPercentageReport( const VolumeFile* paintVolume, QString& reportTextOut) const throw (BrainModelAlgorithmException) { reportTextOut = ""; if (getNumberOfVoxelsInROI() <= 0) { throw BrainModelAlgorithmException("The region of interest contains no voxels."); } // // Use first paint volume to determine voxels in ROI // std::vector voxelInROI; const int numVoxelsInROI = determineVoxelsWithinVolumeROI(paintVolume, 0, std::numeric_limits::max(), voxelInROI); if (numVoxelsInROI <= 0) { throw BrainModelAlgorithmException("No voxels from the paint volume are within the ROI volume.\n" "Are the stereotaxic coordinates properly set?"); } // // Get number of paint names // const int numPaintNames = paintVolume->getNumberOfRegionNames(); if (numPaintNames <= 0) { throw BrainModelAlgorithmException("There are no paint regions in the volume."); } double* counter = new double[numPaintNames]; for (int i = 0; i < numPaintNames; i++) { counter[i] = 0.0; } // // Determine the COG of the voxels in the ROI // int dim[3]; paintVolume->getDimensions(dim); for (int i = 0; i < dim[0]; i++) { for (int j = 0; j < dim[1]; j++) { for (int k = 0; k < dim[2]; k++) { const int flatIndex = paintVolume->getVoxelDataIndex(i, j, k); if (voxelInROI[flatIndex]) { const int paintIndex = static_cast(paintVolume->getVoxel(i, j, k)); counter[paintIndex] += 1.0; } } } } std::ostringstream str; str.precision(2); str.setf(std::ios::fixed); std::vector sortedInfo; for (int i = 0; i < numPaintNames; i++) { str.str(""); const double count = counter[i]; str << paintVolume->getRegionNameFromIndex(i).toAscii().constData() << "; " << static_cast(count) << "; " << (count / numVoxelsInROI) * 100.0 << "\n"; sortedInfo.push_back(str.str().c_str()); } std::sort(sortedInfo.begin(), sortedInfo.end()); QString operationText; operationText += "Name; Voxels; Percent\n"; for (int i = 0; i < static_cast(sortedInfo.size()); i++) { operationText += sortedInfo[i]; operationText += "\n"; } delete[] counter; const int totalNumberOfVoxels = dim[0] * dim[1] * dim[2]; reportTextOut = createReport(paintVolume, "Paint Percentage Report", operationText, totalNumberOfVoxels, numVoxelsInROI); } /** * probabilistic paint volume overlap analysis. */ void BrainModelVolumeRegionOfInterest::operationPaintOverlapAnalysis( const std::vector& paintVolumes, QString& reportTextOut) const throw (BrainModelAlgorithmException) { reportTextOut = ""; if (getNumberOfVoxelsInROI() <= 0) { throw BrainModelAlgorithmException("The region of interest contains no voxels."); } // // Make sure all volumes are of the same dimensions // const int numVolumes = static_cast(paintVolumes.size()); int dim[3]; for (int i = 0; i < numVolumes; i++) { const VolumeFile* vf = paintVolumes[i]; if (i == 0) { vf->getDimensions(dim); } else { int dim2[3]; vf->getDimensions(dim2); for (int j = 0; j < 3; j++) { if (dim[j] != dim2[j]) { VolumeFile* vf0 = paintVolumes[0]; std::ostringstream str; str << "All volumes must be the same dimensions.\n" << "Volume " << FileUtilities::basename(vf0->getFileName()).toAscii().constData() << " dimensions: " << "(" << dim[0] << ", " << dim[1] << ", " << dim[2] << ")\n" << "Volume " << FileUtilities::basename(vf->getFileName()).toAscii().constData() << " dimensions: " << "(" << dim2[0] << ", " << dim2[1] << ", " << dim2[2] << ").\n"; throw BrainModelAlgorithmException(QString(str.str().c_str())); } } } } // // Use first paint volume to determine voxels in ROI // std::vector voxelInROI; const int numVoxelsInROI = determineVoxelsWithinVolumeROI(paintVolumes[0], 0, std::numeric_limits::max(), voxelInROI); if (numVoxelsInROI <= 0) { throw BrainModelAlgorithmException("No voxels from the first paint volume are within the ROI volume.\n" "Are the stereotaxic coordinates properly set?"); } // // Get all paint names in sorted order // std::set paintNamesSorted; for (int i = 0; i < numVolumes; i++) { VolumeFile* vf = paintVolumes[i]; const int numNames = vf->getNumberOfRegionNames(); for (int j = 0; j < numNames; j++) { paintNamesSorted.insert(vf->getRegionNameFromIndex(j)); } } std::vector paintNames(paintNamesSorted.begin(), paintNamesSorted.end()); const int numPaintNames = static_cast(paintNames.size()); // // Counts for each paint index // const int numColumns = numVolumes + 1; const int totalCountSize = numPaintNames * numColumns; std::vector totalCounts(totalCountSize, 0); // // Get conversion from each paint volume index to all paint names // std::vector< std::vector > paintIndexToAllPaintNames; for (int i = 0; i < numVolumes; i++) { VolumeFile* vf = paintVolumes[i]; const int numNames = vf->getNumberOfRegionNames(); std::vector indexConversion; for (int j = 0; j < numNames; j++) { int indx = -1; const QString name(vf->getRegionNameFromIndex(j)); for (int k = 0; k < numPaintNames; k++) { if (name == paintNames[k]) { indx = k; } } if (indx == -1) { std::cout << "PROGRAM ERROR: Invalid paint index volume paint report" << std::endl; } indexConversion.push_back(indx); } paintIndexToAllPaintNames.push_back(indexConversion); } // // Get the number of voxels // const int numVoxels = paintVolumes[0]->getTotalNumberOfVoxels(); for (int i = 0; i < numVoxels; i++) { // // Is this voxel in the ROI // if (voxelInROI[i]) { // // Get the paint names used by this voxel in all volumes // std::vector indicesUsedByThisVoxel; for (int j = 0; j < numVolumes; j++) { std::vector& indexConversion = paintIndexToAllPaintNames[j]; indicesUsedByThisVoxel.push_back( indexConversion[static_cast( paintVolumes[j]->getVoxelWithFlatIndex(i))]); } std::sort(indicesUsedByThisVoxel.begin(), indicesUsedByThisVoxel.end()); // // Get unique list of paint indices used by this voxel in all volumes // std::set uniqueIndices(indicesUsedByThisVoxel.begin(), indicesUsedByThisVoxel.end()); // // Update counts // for (std::set::iterator iter = uniqueIndices.begin(); iter != uniqueIndices.end(); iter++) { const int n = *iter; int cnt = 0; for (int p = 0; p < numVolumes; p++) { if (n == indicesUsedByThisVoxel[p]) { cnt++; } } totalCounts[n * numColumns + cnt]++; } } } const QString separator(";"); QString operationText; // // Create the report for each paint name // for (int i = 0; i < numPaintNames; i++) { const int offset = i * numColumns; // // Determine number of zero entries // int numZero = numVoxelsInROI; for (int j = 1; j < numColumns; j++) { numZero -= totalCounts[offset + j]; } totalCounts[offset] = numZero; // // Print counts // std::ostringstream str; str << paintNames[i].toAscii().constData() << " - number of voxels with:\n"; for (int j = 0; j < numColumns; j++) { str << j << " entries" << separator.toAscii().constData(); } str << "\n"; for (int j = 0; j < numColumns; j++) { str << totalCounts[offset + j] << separator.toAscii().constData(); } str << "\n"; operationText += QString(str.str().c_str()); // // Print percentages // str.str(""); str.precision(2); str.setf(std::ios::fixed); str << paintNames[i].toAscii().constData() << " - percent of voxels with:\n"; for (int j = 0; j < numColumns; j++) { str << j << " entries" << separator.toAscii().constData(); } str << "\n"; for (int j = 0; j < numColumns; j++) { const float pct = (static_cast(totalCounts[offset + j]) / static_cast(numVoxelsInROI)) * 100.0; str << pct << separator.toAscii().constData(); } str << "\n"; operationText += QString(str.str().c_str()); } const int totalNumberOfVoxels = dim[0] * dim[1] * dim[2]; reportTextOut = createReport(paintVolumes, "Probabilistic Atlas Overlap Analysis", operationText, totalNumberOfVoxels, numVoxelsInROI); } /** * determine which voxels are in the ROI volume. */ int BrainModelVolumeRegionOfInterest::determineVoxelsWithinVolumeROI(const VolumeFile* volume, const float minValue, const float maxValue, std::vector& voxelInROI) const { voxelInROI.resize(volume->getTotalNumberOfVoxels()); std::fill(voxelInROI.begin(), voxelInROI.end(), false); int dim[3]; volume->getDimensions(dim); int ctr = 0; for (int i = 0; i < dim[0]; i++) { for (int j = 0; j < dim[1]; j++) { for (int k = 0; k < dim[2]; k++) { const float voxel = volume->getVoxel(i, j, k); if ((voxel >= minValue) && (voxel <= maxValue)) { // // Get stereotaxic coordinate of volume's voxel // float xyz[3]; volume->getVoxelCoordinate(i, j, k, xyz); // // See if voxel is in the ROI using the stereotaxic coordinate // if (insideVolumeROI(xyz)) { const int flatIndex = volume->getVoxelDataIndex(i, j, k); voxelInROI[flatIndex] = true; ctr++; } } } } } return ctr; } /** * segmentation region center of gravity report. */ void BrainModelVolumeRegionOfInterest::operationSegmentationRegionCenterOfGravity( const VolumeFile *segmentVolume, QString& reportTextOut) const throw (BrainModelAlgorithmException) { reportTextOut = ""; if (getNumberOfVoxelsInROI() <= 0) { throw BrainModelAlgorithmException("The region of interest contains no voxels."); } // // // Determine the COG of the voxels in the ROI // double voxelCOG[3] = { 0.0, 0.0, 0.0 }; double coordCOG[3] = { 0.0, 0.0, 0.0 }; double counter = 0; int dim[3]; segmentVolume->getDimensions(dim); for (int i = 0; i < dim[0]; i++) { for (int j = 0; j < dim[1]; j++) { for (int k = 0; k < dim[2]; k++) { const float voxel = segmentVolume->getVoxel(i, j, k); if (voxel != 0.0) { // // Get stereotaxic coordinate of segmentation voxel // float xyz[3]; segmentVolume->getVoxelCoordinate(i, j, k, xyz); // // See if voxel is in the ROI using the stereotaxic coordinate // if (insideVolumeROI(xyz)) { voxelCOG[0] += i; voxelCOG[1] += j; voxelCOG[2] += k; coordCOG[0] += xyz[0]; coordCOG[1] += xyz[1]; coordCOG[2] += xyz[2]; counter += 1.0; } } } } } QString operationText; if (counter > 0) { const QString s1 = ("Voxel IJK C.O.G.: (" + QString::number(voxelCOG[0] / counter, 'f', 0) + ", " + QString::number(voxelCOG[1] / counter, 'f', 0) + ", " + QString::number(voxelCOG[2] / counter, 'f', 0) + ")\n"); operationText += s1; const QString s2 = ("Voxel Coordinate C.O.G.: (" + QString::number(coordCOG[0] / counter, 'f', 3) + ", " + QString::number(coordCOG[1] / counter, 'f', 3) + ", " + QString::number(coordCOG[2] / counter, 'f', 3) + ")\n"); operationText += s2; } else { operationText += "There are no non-zero segmentation voxels in the ROI.\n"; } const int totalNumberOfVoxels = dim[0] * dim[1] * dim[2]; reportTextOut = createReport(segmentVolume, "Segmentation Center of Gravity", operationText, totalNumberOfVoxels, static_cast(counter)); } /** * see if a stereotaxic coordinate is inside the ROI. */ bool BrainModelVolumeRegionOfInterest::insideVolumeROI(const float xyz[3]) const { int ijk[3]; if (roiVolume->convertCoordinatesToVoxelIJK(xyz, ijk)) { if (roiVolume->getVoxel(ijk) != 0.0) { return true; } } return false; } /** * reset the ROI volume. */ void BrainModelVolumeRegionOfInterest::resetROIVolume(const VolumeFile* vf, const bool colorTheVolumesVoxelsFlag) { if (vf != NULL) { // // Delete existing volume // if (roiVolume != NULL) { delete roiVolume; roiVolume = NULL; } // // Copy the user's volume // roiVolume = new VolumeFile(*vf); // // If voxels should be colored // if (colorTheVolumesVoxelsFlag) { // // Color all voxels // BrainModelVolumeVoxelColoring* voxelColoring = brainSet->getVoxelColoring(); voxelColoring->colorAllOfTheVolumesVoxels(roiVolume); // // Change the volume type so that the volume gets colored in the ROI color // Need to do this so after coloring copied volume so that the voxel display flags // are set but before changing the type to ROI for ROI coloring // roiVolume->setVolumeType(VolumeFile::VOLUME_TYPE_ROI); // // If any voxels have color set the voxel value to 1.0 else 0.0 if voxel color invalid // and set voxel color invalid so that it will get colored with the proper ROI color // const unsigned char invalidColor[4] = { 0, 0, 0, VolumeFile::VOXEL_COLOR_STATUS_INVALID }; int dim[3] = { 0, 0, 0 }; roiVolume->getDimensions(dim); for (int i = 0; i < dim[0]; i++) { for (int j = 0; j < dim[1]; j++) { for (int k = 0; k < dim[2]; k++) { unsigned char rgb[4]; roiVolume->getVoxelColor(i, j, k, rgb); if (rgb[3] == VolumeFile::VOXEL_COLOR_STATUS_VALID) { roiVolume->setVoxel(i, j, k, 0, 1.0); } else { roiVolume->setVoxel(i, j, k, 0, 0.0); } roiVolume->setVoxelColor(i, j, k, invalidColor); } } } } } else { // // create an empty volume // int dim[3] = { 0, 0, 0 }; VolumeFile::ORIENTATION orient[3]; float origin[3] = { 0.0, 0.0, 0.0 }; float spacing[3] = { 1.0, 1.0, 1.0 }; roiVolume->initialize(VolumeFile::VOXEL_DATA_TYPE_FLOAT, dim, orient, origin, spacing, true, // clear the voxels, true); // allocate voxel data } // // Change the volume type so that the volume gets colored in the ROI color // roiVolume->setVolumeType(VolumeFile::VOLUME_TYPE_ROI); reportROIVolumeInfoText = ""; } /** * set the volume ROI to all voxels in volume. */ void BrainModelVolumeRegionOfInterest::setVolumeROIToAllVoxels(const VolumeFile* vf) { resetROIVolume(vf, false); if (vf == NULL) { return; } // // Set all voxels to one // int dim[3]; roiVolume->getDimensions(dim); for (int i = 0; i < dim[0]; i++) { for (int j = 0; j < dim[1]; j++) { for (int k = 0; k < dim[2]; k++) { roiVolume->setVoxel(i, j, k, 0, 1.0); } } } reportROIVolumeInfoText = "Selection Mode: All voxels within volume " + FileUtilities::basename(vf->getFileName()) + "\n"; } /** * set the volume ROI to all displayed voxels in volume. */ void BrainModelVolumeRegionOfInterest::setVolumeROIToAllDisplayedVoxels(const VolumeFile* vf) { resetROIVolume(vf, true); if (vf == NULL) { return; } reportROIVolumeInfoText = "Selection Mode: All displayed voxels within volume " + FileUtilities::basename(vf->getFileName()) + "\n"; } /** * set the volume ROI to all paint voxels with the specified name. */ void BrainModelVolumeRegionOfInterest::setVolumeROIToPaintIDVoxels(const VolumeFile* vf, const QString& paintName) { resetROIVolume(vf, false); if (vf == NULL) { return; } const int paintIndex = vf->getRegionIndexFromName(paintName); // // Set all voxels with proper paint ID to one // int dim[3]; vf->getDimensions(dim); for (int i = 0; i < dim[0]; i++) { for (int j = 0; j < dim[1]; j++) { for (int k = 0; k < dim[2]; k++) { const int value = static_cast(vf->getVoxel(i, j, k, 0)); if (value == paintIndex) { roiVolume->setVoxel(i, j, k, 0, 1.0); } else { roiVolume->setVoxel(i, j, k, 0, 0.0); } } } } reportROIVolumeInfoText = "Selection Mode: All voxels with label " + paintName + " in volume " + FileUtilities::basename(vf->getFileName()) + "\n"; } /** * set the volume ROI to all voxels within a range in volume. */ void BrainModelVolumeRegionOfInterest::setVolumeROIToVoxelsInRangeOfValues(const VolumeFile* vf, const float minValue, const float maxValue) { resetROIVolume(vf, false); if (vf == NULL) { return; } // // Set voxels within range to one, others to zero // int dim[3]; vf->getDimensions(dim); for (int i = 0; i < dim[0]; i++) { for (int j = 0; j < dim[1]; j++) { for (int k = 0; k < dim[2]; k++) { const float value = vf->getVoxel(i, j, k, 0); if ((value >= minValue) && (value <= maxValue)) { roiVolume->setVoxel(i, j, k, 0, 1.0); } else { roiVolume->setVoxel(i, j, k, 0, 0.0); } } } } reportROIVolumeInfoText = "Selection Mode: All voxels with value in range (" + QString::number(minValue, 'f', 3) + " , " + QString::number(maxValue, 'f', 3) + ") in volume " + FileUtilities::basename(vf->getFileName()) + "\n"; } /** * create the report. */ QString BrainModelVolumeRegionOfInterest::createReport(const VolumeFile* operatingVolume, const QString& description, const QString& operationText, const int totalNumberOfVoxels, const int numVoxelsInROI) const { std::vector volumeVector; volumeVector.push_back((VolumeFile*)operatingVolume); return createReport(volumeVector, description, operationText, totalNumberOfVoxels, numVoxelsInROI); } /** * create the report. */ QString BrainModelVolumeRegionOfInterest::createReport(const std::vector operatingVolumes, const QString& description, const QString& operationText, const int totalNumberOfVoxels, const int numVoxelsInROI) const { QString txt = "\n" + description + "\n\n" + reportROIVolumeInfoText; for (unsigned int i = 0; i < operatingVolumes.size(); i++) { + "Operating on volume: " + FileUtilities::basename(operatingVolumes[i]->getFileName()) + "\n" + " label: " + operatingVolumes[i]->getDescriptiveLabel() + "\n"; } txt += "\n" + QString::number(numVoxelsInROI) + " of " + QString::number(totalNumberOfVoxels) + " voxels are in the ROI." + "\n\n" + operationText; return txt; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeROISmoothing.h0000664000175000017500000000367111572067322025533 0ustar michaelmichael #ifndef __BRAIN_MODEL_VOLUME_ROI_SMOOTHING_H__ #define __BRAIN_MODEL_VOLUME_ROI_SMOOTHING_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelAlgorithm.h" #include "VolumeFile.h" // //class VolumeFile; /// class for for smoothing and resampling a volume region to a given ROI class BrainModelVolumeROISmoothing : public BrainModelAlgorithm { public: /// Constructor BrainModelVolumeROISmoothing(BrainSet* bs, VolumeFile* valuesIn, VolumeFile* regionIn, std::vector *smoothVolVecIn, float sigmaIn); /// Destructor ~BrainModelVolumeROISmoothing(); /// execute the algorithm void execute() throw (BrainModelAlgorithmException); private: VolumeFile* values, *region; std::vector *smoothVolVec; float sigma; }; #endif // __BRAIN_MODEL_VOLUME_ROI_ATLAS_SMOOTHING_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeROISmoothing.cxx0000664000175000017500000001557311572067322026112 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelVolumeROISmoothing.h" #include "VolumeFile.h" #include #include #include using namespace std; BrainModelVolumeROISmoothing::BrainModelVolumeROISmoothing(BrainSet* bs, VolumeFile* valuesIn, VolumeFile* regionIn, std::vector * smoothVolVecIn, float sigmaIn) : BrainModelAlgorithm(bs) { values = valuesIn; region = regionIn; smoothVolVec = smoothVolVecIn; sigma = sigmaIn; } BrainModelVolumeROISmoothing::~BrainModelVolumeROISmoothing() { } void BrainModelVolumeROISmoothing::execute() throw (BrainModelAlgorithmException) { int i, j, k, ki, kj, kk, dim[3], dim2[3]; float spacing[3], spacing2[3], origin[3], origin2[3]; float inputVal, smoothVal, weightVal; if (!values || !region || !smoothVolVec) { throw BrainModelAlgorithmException("Invalid volume."); } values->getSpacing(spacing); values->getOrigin(origin); values->getDimensions(dim); bool match = true; region->getSpacing(spacing2); region->getOrigin(origin2); region->getDimensions(dim2); for (i = 0; i < 3; ++i) { if (abs(spacing[i] - spacing2[i]) > 0.0001f) { match = false; } if (abs(origin[i] - origin2[i]) > 0.0001f) { match = false; } if (dim[i] != dim2[i]) { match = false; } } if (!match) { throw BrainModelAlgorithmException("Input volumes do not match."); } VolumeFile::ORIENTATION myorient[3];// = {VolumeFile::ORIENTATION_LEFT_TO_RIGHT, // VolumeFile::ORIENTATION_POSTERIOR_TO_ANTERIOR, // VolumeFile::ORIENTATION_INFERIOR_TO_SUPERIOR}; values->getOrientation(myorient); float frange = sigma * 6.0f; int irange[3]; irange[0] = (int)floor(frange / fabs(spacing[0])); irange[1] = (int)floor(frange / fabs(spacing[1])); irange[2] = (int)floor(frange / fabs(spacing[2])); if (!irange[0] || !irange[1] || !irange[2]) { throw BrainModelAlgorithmException("Kernel too small."); } float*** weights = new float**[2 * irange[0] + 1];//precompute sigma weights float tempf, tempf2; for (i = 0; i < 2 * irange[0] + 1; ++i) { weights[i] = new float*[2 * irange[1] + 1]; for (j = 0; j < 2 * irange[1] + 1; ++j) { weights[i][j] = new float[2 * irange[2] + 1]; for (k = 0; k < 2 * irange[2] + 1; ++k) { tempf = (i - irange[0]) * spacing[0]; tempf *= tempf; tempf2 = (j - irange[1]) * spacing[1]; tempf2 *= tempf2; tempf += tempf2; tempf2 = (k - irange[2]) * spacing[2]; tempf2 *= tempf2; tempf += tempf2;//square of euclidean distance tempf /= sigma * sigma; weights[i][j][k] = exp(-tempf / 2.0f); } } } int numSubVolumes = values->getNumberOfSubVolumes(); smoothVolVec->resize(numSubVolumes); for( int s = 0;sinitialize(VolumeFile::VOXEL_DATA_TYPE_FLOAT, dim, myorient, origin, spacing);//because setDimensions doesn't allocate... (*smoothVolVec)[s] = smoothSubVol; //get our input sub volume VolumeFile subVol; try { subVol.readFile(values->getFileName(), s); } catch(FileException e) { exit(1); // std::cout << "Exception caught while reading volume " << i << " of nifti file, " << values->getFileName() << std::endl; // std::cout << e.whatQString() << std::endl; throw BrainModelAlgorithmException("Error while reading Nifti Sub Volume."); } for (i = 0; i < dim[0]; ++i) {//all voxels for (j = 0; j < dim[1]; ++j) { for (k = 0; k < dim[2]; ++k) { if (region->getVoxel(i, j, k) > 0.0f) {//if selected float weightSum = 0.0f; smoothVal = 0.0f; for (ki = -irange[0]; ki <= irange[0]; ++ki) {//loop through kernel if (i + ki < 0 || i + ki >= dim[0]) { continue;//makes the indentation a bit less daunting } for (kj = -irange[1]; kj <= irange[1]; ++kj) { if (j + kj < 0 || j + kj >= dim[1]) { continue; } for (kk = -irange[2]; kk <= irange[2]; ++kk) { if (k + kk < 0 || k + kk >= dim[2])// || (ki == 0 && kj == 0 && kk == 0)) {//dont skip center point? continue; } if (region->getVoxel(i + ki, j + kj, k + kk) > 0.0f) { inputVal = subVol.getVoxel(i + ki, j + kj , k + kk); weightVal = weights[ki + irange[0]][kj + irange[1]][kk + irange[2]]; smoothVal += inputVal * weightVal; weightSum += weightVal; } } } } if (smoothVal != smoothVal) { smoothVal = 0.0f;//set NaNs to zero } else { smoothVal /= weightSum; } smoothSubVol->setVoxel(i, j, k, 0, smoothVal); } else { smoothSubVol->setVoxel(i, j, k, 0, 0.0f); } } } } } }caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeROIMinima.h0000664000175000017500000000343211572067322024771 0ustar michaelmichael #ifndef __BRAIN_MODEL_VOLUME_ROI_MINIMA_H__ #define __BRAIN_MODEL_VOLUME_ROI_MINIMA_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelAlgorithm.h" class VolumeFile; /// class for create a functional volume using a probabilistic volume class BrainModelVolumeROIMinima : public BrainModelAlgorithm { public: /// Constructor BrainModelVolumeROIMinima(BrainSet* bs, VolumeFile* valuesIn, VolumeFile* regionIn, VolumeFile* minimaOutIn, float distIn); /// Destructor ~BrainModelVolumeROIMinima(); /// execute the algorithm void execute() throw (BrainModelAlgorithmException); private: VolumeFile* values, *region, *minimaOut; float dist; }; #endif // __BRAIN_MODEL_VOLUME_ROI_MINIMA_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeROIMinima.cxx0000664000175000017500000001312411572067322025343 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelVolumeROIMinima.h" #include "VolumeFile.h" #include using namespace std; BrainModelVolumeROIMinima::BrainModelVolumeROIMinima(BrainSet* bs, VolumeFile* valuesIn, VolumeFile* regionIn, VolumeFile* minimaOutIn, float distIn) : BrainModelAlgorithm(bs) { values = valuesIn; region = regionIn; minimaOut = minimaOutIn; dist = distIn; } BrainModelVolumeROIMinima::~BrainModelVolumeROIMinima() { } void BrainModelVolumeROIMinima::execute() throw (BrainModelAlgorithmException) { int i, j, k, ki, kj, kk, dim[3], dim2[3]; float spacing[3], spacing2[3], origin[3], origin2[3]; float tempf, tempf2, tempf3; if (!values || !region || !minimaOut) { throw BrainModelAlgorithmException("Invalid volume."); } values->getSpacing(spacing); values->getOrigin(origin); values->getDimensions(dim); bool match = true; region->getSpacing(spacing2); region->getOrigin(origin2); region->getDimensions(dim2); for (i = 0; i < 3; ++i) { if (abs(spacing[i] - spacing2[i]) > 0.0001f) { match = false; } if (abs(origin[i] - origin2[i]) > 0.0001f) { match = false; } if (dim[i] != dim2[i]) { match = false; } } if (!match) { throw BrainModelAlgorithmException("Input volumes do not match."); } VolumeFile::ORIENTATION myorient[3] = {VolumeFile::ORIENTATION_LEFT_TO_RIGHT, VolumeFile::ORIENTATION_POSTERIOR_TO_ANTERIOR, VolumeFile::ORIENTATION_INFERIOR_TO_SUPERIOR}; minimaOut->initialize(VolumeFile::VOXEL_DATA_TYPE_FLOAT, dim, myorient, origin, spacing);//because setDimensions doesn't allocate... tempf3 = dist * dist; int irange[3]; irange[0] = (int)floor(dist / fabs(spacing[0])); irange[1] = (int)floor(dist / fabs(spacing[1])); irange[2] = (int)floor(dist / fabs(spacing[2])); if (!irange[0] || !irange[1] || !irange[2]) { throw BrainModelAlgorithmException("Distance too small."); } char*** mask = new char**[2 * irange[0] + 1];//precompute "sphere" of voxels for (i = 0; i < 2 * irange[0] + 1; ++i) { mask[i] = new char*[2 * irange[1] + 1]; for (j = 0; j < 2 * irange[1] + 1; ++j) { mask[i][j] = new char[2 * irange[2] + 1]; for (k = 0; k < 2 * irange[2] + 1; ++k) { tempf = (i - irange[0]) * spacing[0]; tempf *= tempf; tempf2 = (j - irange[1]) * spacing[1]; tempf2 *= tempf2; tempf += tempf2; tempf2 = (k - irange[2]) * spacing[2]; tempf2 *= tempf2; tempf += tempf2;//square of euclidean distance if (tempf <= tempf3) { mask[i][j][k] = 1; } else { mask[i][j][k] = 0; } } } } bool found; for (i = 0; i < dim[0]; ++i) {//all voxels for (j = 0; j < dim[1]; ++j) { for (k = 0; k < dim[2]; ++k) { if (region->getVoxel(i, j, k) > 0.0f) {//if selected tempf = values->getVoxel(i, j, k); found = false; for (ki = -irange[0]; !found && ki <= irange[0]; ++ki) {//loop through kernel if (i + ki < 0 || i + ki >= dim[0]) { continue;//makes the indentation a bit less daunting } for (kj = -irange[1]; !found && kj <= irange[1]; ++kj) { if (j + kj < 0 || j + kj >= dim[1]) { continue; } for (kk = -irange[2]; kk <= irange[2]; ++kk) { if (k + kk < 0 || k + kk >= dim[2] || (ki == 0 && kj == 0 && kk == 0)) { continue; } if (mask[ki + irange[0]][kj + irange[1]][kk + irange[2]] && region->getVoxel(i + ki, j + kj, k + kk) > 0.0f && values->getVoxel(i + ki, j + kj, k + kk) < tempf) { found = true; break; } } } } if (found) { minimaOut->setVoxel(i, j, k, 0, 0.0f); } else { minimaOut->setVoxel(i, j, k, 0, 255.0f); } } else { minimaOut->setVoxel(i, j, k, 0, 0.0f); } } } } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeROIGradient.h0000664000175000017500000000354611572067322025322 0ustar michaelmichael #ifndef __BRAIN_MODEL_VOLUME_ROI_GRADIENT_H__ #define __BRAIN_MODEL_VOLUME_ROI_GRADIENT_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelAlgorithm.h" class VolumeFile; /// class for create a functional volume using a probabilistic volume class BrainModelVolumeROIGradient : public BrainModelAlgorithm { public: /// Constructor BrainModelVolumeROIGradient(BrainSet* bs, VolumeFile* valuesIn, VolumeFile* regionIn, VolumeFile* gradMagOutIn, float kernelIn); /// Destructor ~BrainModelVolumeROIGradient(); /// execute the algorithm void execute() throw (BrainModelAlgorithmException); private: VolumeFile* values, *region, *gradMagOut; float kernel; void calcrref(float* matrix[], int rows, int cols); }; #endif // __BRAIN_MODEL_VOLUME_ROI_GRADIENT_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeROIGradient.cxx0000664000175000017500000002047411572067322025674 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelVolumeROIGradient.h" #include "VolumeFile.h" #include using namespace std; void BrainModelVolumeROIGradient::calcrref(float* matrix[], int rows, int cols) {//assumes more cols than rows int i, j, k, temp; float tempf, tempf2; for (i = 0; i < rows; ++i) { tempf = std::abs(matrix[i][i]);//search for pivot temp = i; for (j = i + 1; j < rows; ++j) { tempf2 = std::abs(matrix[j][i]); if (tempf2 > tempf) { tempf = tempf2; temp = j; } } if (i != temp) { for (j = i; j < cols; ++j) {//skip the waste that will end up 0's and 1's tempf = matrix[i][j]; matrix[i][j] = matrix[temp][j]; matrix[temp][j] = tempf; } } tempf = matrix[i][i];//pivot for (j = i + 1; j < cols; ++j) {//again, skip the 0's and 1's matrix[i][j] /= tempf; for (k = 0; k < i; ++k) { matrix[k][j] -= matrix[k][i] * matrix[i][j]; } for (++k; k < rows; ++k) { matrix[k][j] -= matrix[k][i] * matrix[i][j]; } } }//rref complete for all cols >= rows, just pretend rowsXrows is I } BrainModelVolumeROIGradient::BrainModelVolumeROIGradient(BrainSet* bs, VolumeFile* valuesIn, VolumeFile* regionIn, VolumeFile* gradMagOutIn, float kernelIn) : BrainModelAlgorithm(bs) { values = valuesIn; region = regionIn; gradMagOut = gradMagOutIn; kernel = kernelIn; } BrainModelVolumeROIGradient::~BrainModelVolumeROIGradient() { } void BrainModelVolumeROIGradient::execute() throw (BrainModelAlgorithmException) { int i, j, k, ki, kj, kk, dim[3], dim2[3]; float spacing[3], spacing2[3], origin[3], origin2[3]; float tempf, tempf2, tempf3, dx, dy, dz; if (!values || !region || !gradMagOut) { throw BrainModelAlgorithmException("Invalid volume."); } values->getSpacing(spacing); values->getOrigin(origin); values->getDimensions(dim); bool match = true; region->getSpacing(spacing2); region->getOrigin(origin2); region->getDimensions(dim2); for (i = 0; i < 3; ++i) { if (abs(spacing[i] - spacing2[i]) > 0.0001f) { match = false; } if (abs(origin[i] - origin2[i]) > 0.0001f) { match = false; } if (dim[i] != dim2[i]) { match = false; } } if (!match) { throw BrainModelAlgorithmException("Input volumes do not match."); } VolumeFile::ORIENTATION myorient[3] = {VolumeFile::ORIENTATION_LEFT_TO_RIGHT, VolumeFile::ORIENTATION_POSTERIOR_TO_ANTERIOR, VolumeFile::ORIENTATION_INFERIOR_TO_SUPERIOR}; gradMagOut->initialize(VolumeFile::VOXEL_DATA_TYPE_FLOAT, dim, myorient, origin, spacing);//because setDimensions doesn't allocate... float frange = kernel * 4.0f; int irange[3]; irange[0] = (int)floor(frange / fabs(spacing[0])); irange[1] = (int)floor(frange / fabs(spacing[1])); irange[2] = (int)floor(frange / fabs(spacing[2])); if (!irange[0] || !irange[1] || !irange[2]) { throw BrainModelAlgorithmException("Kernel too small."); } float*** weights = new float**[2 * irange[0] + 1];//precompute kernel weights for (i = 0; i < 2 * irange[0] + 1; ++i) { weights[i] = new float*[2 * irange[1] + 1]; for (j = 0; j < 2 * irange[1] + 1; ++j) { weights[i][j] = new float[2 * irange[2] + 1]; for (k = 0; k < 2 * irange[2] + 1; ++k) { tempf = (i - irange[0]) * spacing[0]; tempf *= tempf; tempf2 = (j - irange[1]) * spacing[1]; tempf2 *= tempf2; tempf += tempf2; tempf2 = (k - irange[2]) * spacing[2]; tempf2 *= tempf2; tempf += tempf2;//square of euclidean distance tempf /= kernel * kernel; weights[i][j][k] = exp(-tempf / 2.0f); } } } float* rref[4]; for (i = 0; i < 4; ++i) { rref[i] = new float[5]; } for (i = 0; i < dim[0]; ++i) {//all voxels for (j = 0; j < dim[1]; ++j) { for (k = 0; k < dim[2]; ++k) { if (region->getVoxel(i, j, k) > 0.0f) {//if selected for (ki = 0; ki < 4; ++ki) {//reset rref for (kj = 0; kj < 5; ++kj) { rref[ki][kj] = 0.0f; } } tempf = values->getVoxel(i, j, k); for (ki = -irange[0]; ki <= irange[0]; ++ki) {//loop through kernel if (i + ki < 0 || i + ki >= dim[0]) { continue;//makes the indentation a bit less daunting } for (kj = -irange[1]; kj <= irange[1]; ++kj) { if (j + kj < 0 || j + kj >= dim[1]) { continue; } for (kk = -irange[2]; kk <= irange[2]; ++kk) { if (k + kk < 0 || k + kk >= dim[2])// || (ki == 0 && kj == 0 && kk == 0)) {//dont skip center point? continue; } if (region->getVoxel(i + ki, j + kj, k + kk) > 0.0f) { dx = ki * spacing[0]; dy = kj * spacing[1]; dz = kk * spacing[2]; tempf2 = values->getVoxel(i + ki, j + kj, k + kk) - tempf; tempf3 = weights[ki + irange[0]][kj + irange[1]][kk + irange[2]]; rref[0][0] += dx * dx * tempf3; rref[0][1] += dx * dy * tempf3; rref[0][2] += dx * dz * tempf3; rref[0][3] += dx * tempf3; rref[0][4] += dx * tempf2 * tempf3; rref[1][1] += dy * dy * tempf3; rref[1][2] += dy * dz * tempf3; rref[1][3] += dy * tempf3; rref[1][4] += dy * tempf2 * tempf3; rref[2][2] += dz * dz * tempf3; rref[2][3] += dz * tempf3; rref[2][4] += dz * tempf2 * tempf3; rref[3][3] += tempf3; rref[3][4] += tempf2 * tempf3; } } } } rref[1][0] = rref[0][1]; rref[2][0] = rref[0][2]; rref[2][1] = rref[1][2]; rref[3][0] = rref[0][3]; rref[3][1] = rref[1][3]; rref[3][2] = rref[2][3]; calcrref(rref, 4, 5);//gradient vector is (rref[0][4], rref[1][4], rref[2][4]) tempf = sqrt(rref[0][4] * rref[0][4] + rref[1][4] * rref[1][4] + rref[2][4] * rref[2][4]); if (tempf != tempf) { tempf = 0.0f;//set NaNs to zero } gradMagOut->setVoxel(i, j, k, 0, tempf); } else { gradMagOut->setVoxel(i, j, k, 0, 0.0f); } } } } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeROIAtlasResamplingAndSmoothing.h0000664000175000017500000000411711572067322031161 0ustar michaelmichael #ifndef __BRAIN_MODEL_VOLUME_ROI_ATLAS_RESAMPLING_AND_SMOOTHING_H__ #define __BRAIN_MODEL_VOLUME_ROI_ATLAS_RESAMPLING_AND_SMOOTHING_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelAlgorithm.h" #include "vector" class VolumeFile; /// class for for smoothing and resampling a volume region to a given ROI class BrainModelVolumeROIAtlasResamplingAndSmoothing : public BrainModelAlgorithm { public: /// Constructor BrainModelVolumeROIAtlasResamplingAndSmoothing(BrainSet* bs, VolumeFile* valuesIn, VolumeFile* regionIn, VolumeFile* AtlasIn,//for pixdim and srow std::vector *smoothVolVecIn, float sigmaIn); /// Destructor ~BrainModelVolumeROIAtlasResamplingAndSmoothing(); /// execute the algorithm void execute() throw (BrainModelAlgorithmException); private: VolumeFile* values, *region, *atlas; std::vector *smoothVolVec; float sigma; }; #endif // __BRAIN_MODEL_VOLUME_ROI_ATLAS_RESAMPLING_AND_SMOOTHING_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeROIAtlasResamplingAndSmoothing.cxx0000664000175000017500000003163111572067322031535 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelVolumeROIAtlasResamplingAndSmoothing.h" #include "VolumeFile.h" #include #include #include #include using namespace std; BrainModelVolumeROIAtlasResamplingAndSmoothing::BrainModelVolumeROIAtlasResamplingAndSmoothing(BrainSet* bs, VolumeFile* valuesIn, VolumeFile* regionIn, VolumeFile* atlasIn, std::vector * smoothVolVecIn, float sigmaIn) : BrainModelAlgorithm(bs) { values = valuesIn; region = regionIn; atlas = atlasIn; smoothVolVec = smoothVolVecIn, sigma = sigmaIn; } BrainModelVolumeROIAtlasResamplingAndSmoothing::~BrainModelVolumeROIAtlasResamplingAndSmoothing() { } void BrainModelVolumeROIAtlasResamplingAndSmoothing::execute() throw (BrainModelAlgorithmException) { int i, j, k, ki, kj, kk, dim[3], dim2[3], dim3[3]; float spacing[3], spacing2[3], spacing3[3], origin[3], origin2[3], origin3[3]; float inputVal, atlasVal, smoothVal, dx, dy, dz; if (!values || !region || !smoothVolVec) { throw BrainModelAlgorithmException("Invalid volume."); } values->getSpacing(spacing); values->getOrigin(origin); values->getDimensions(dim); bool match = true; region->getSpacing(spacing2); region->getOrigin(origin2); region->getDimensions(dim2); atlas->getSpacing(spacing3); atlas->getOrigin(origin3); atlas->getDimensions(dim3); for (i = 0; i < 3; ++i) { if (abs(spacing[i] - spacing2[i]) > 0.0001f) { match = false; } if (abs(spacing[i] - spacing3[i]) > 0.0001f) { match = false; } if (abs(origin[i] - origin2[i]) > 0.0001f) { match = false; } if (abs(origin[i] - origin3[i]) > 0.0001f) { match = false; } if ((dim[i] != dim2[i]) ||(dim2[i] != dim3[i])) { match = false; } } if (!match) { throw BrainModelAlgorithmException("Input volumes do not match."); } VolumeFile::ORIENTATION myorient[3] = {VolumeFile::ORIENTATION_LEFT_TO_RIGHT, VolumeFile::ORIENTATION_POSTERIOR_TO_ANTERIOR, VolumeFile::ORIENTATION_INFERIOR_TO_SUPERIOR}; //note: for now, get the volume orientation from the input time series //need to ask John H how this relates coordinate space //values->getOrientation(myorient); float frange = sigma * 6.0f; int irange[3]; irange[0] = (int)floor(frange / fabs(spacing[0])); irange[1] = (int)floor(frange / fabs(spacing[1])); irange[2] = (int)floor(frange / fabs(spacing[2])); //timevol -> values //File -> region //AtlasFile -> atlas //Atlastc -> smoothValues //Dimension bug fixing?? float displacement[3]; float distance; float atlasCoord[3]; float indCoord[3]; float weight; int numSubVolumes = values->getNumberOfSubVolumes(); smoothVolVec->resize(numSubVolumes); for( int s = 0;sinitialize(VolumeFile::VOXEL_DATA_TYPE_FLOAT, dim, myorient, origin, spacing);//because setDimensions doesn't allocate... (*smoothVolVec)[s] = smoothSubVol; //get our input sub volume VolumeFile subVol; subVol.readFile(values->getFileName(), s); for (i = 0; i < dim[0]; ++i) {//all voxels for (j = 0; j < dim[1]; ++j) { for (k = 0; k < dim[2]; ++k) { if (atlas->getVoxel(i, j, k) > 0.0f) {//if selected atlasVal = atlas->getVoxel(i, j, k); atlas->getVoxelCoordinate(i,j,k,atlasCoord); float weightSum = 0.0f; smoothVal = 0.0f; for (ki = i-irange[0];ki <= i+irange[0]; ++ki) {//loop through kernel if (ki < 0 || ki >= dim[0]) continue; for (kj = j-irange[1]; kj <= j+irange[1]; ++kj) { if (kj < 0 || kj >= dim[1]) continue; for (kk = k-irange[2]; kk <= k+irange[2]; ++kk) { if (kk < 0 || kk >= dim[2]) continue; if (region->getVoxel(ki,kj,kk) > 0.0f) { inputVal = subVol.getVoxel(ki, kj, kk); region->getVoxelCoordinate(ki,kj,kk,indCoord); displacement[0] = indCoord[0] - atlasCoord[0]; displacement[1] = indCoord[1] - atlasCoord[1]; displacement[2] = indCoord[2] - atlasCoord[2]; distance = sqrt(displacement[0]*displacement[0]+displacement[1]*displacement[1]+displacement[2]*displacement[2]); if(distance >= frange) continue; //taking a square root and then squaring below, definitely room for optimization... weight = exp((double)(-distance*distance/(2.0 * sigma*sigma))); smoothVal += inputVal * weight; weightSum += weight; } } } } if (smoothVal != smoothVal) { smoothVal = 0.0f;//set NaNs to zero } else { if(weightSum) smoothVal /= weightSum; else smoothVal = 0.0f; } smoothSubVol->setVoxel(i, j, k, 0, smoothVal); } else { smoothSubVol->setVoxel(i, j, k, 0, 0.0f); } } } } } } //This is an optimized version of AtlasResamplingAndSmoothing that is based on Tim Coalson's ROI gradient algorithm, //which pre-computes gaussian weights before entering the main loop. /* void BrainModelVolumeROIAtlasResamplingAndSmoothing::execute_optimized() throw (BrainModelAlgorithmException) { int i, j, k, ki, kj, kk, dim[3], dim2[3], dim3[3]; float spacing[3], spacing2[3], spacing3[3], origin[3], origin2[3], origin3[3]; float inputVal, atlasVal, smoothVal, weightVal, dx, dy, dz; if (!values || !region || !smoothVolVec) { throw BrainModelAlgorithmException("Invalid volume."); } values->getSpacing(spacing); values->getOrigin(origin); values->getDimensions(dim); bool match = true; region->getSpacing(spacing2); region->getOrigin(origin2); region->getDimensions(dim2); atlas->getSpacing(spacing3); atlas->getOrigin(origin3); atlas->getDimensions(dim3); for (i = 0; i < 3; ++i) { if (abs(spacing[i] - spacing2[i]) > 0.0001f) { match = false; } if (abs(spacing[i] - spacing3[i]) > 0.0001f) { match = false; } if (abs(origin[i] - origin2[i]) > 0.0001f) { match = false; } if (abs(origin[i] - origin3[i]) > 0.0001f) { match = false; } if (dim[i] != dim2[i] != dim3[i]) { match = false; } } if (!match) { throw BrainModelAlgorithmException("Input volumes do not match."); } VolumeFile::ORIENTATION myorient[3] = {VolumeFile::ORIENTATION_LEFT_TO_RIGHT, VolumeFile::ORIENTATION_POSTERIOR_TO_ANTERIOR, VolumeFile::ORIENTATION_INFERIOR_TO_SUPERIOR}; float frange = sigma * 6.0f; int irange[3]; irange[0] = (int)floor(frange / fabs(spacing[0])); irange[1] = (int)floor(frange / fabs(spacing[1])); irange[2] = (int)floor(frange / fabs(spacing[2])); if (!irange[0] || !irange[1] || !irange[2]) { throw BrainModelAlgorithmException("Kernel too small."); } float*** weights = new float**[2 * irange[0] + 1];//precompute sigma weights float tempf, tempf2; for (i = 0; i < 2 * irange[0] + 1; ++i) { weights[i] = new float*[2 * irange[1] + 1]; for (j = 0; j < 2 * irange[1] + 1; ++j) { weights[i][j] = new float[2 * irange[2] + 1]; for (k = 0; k < 2 * irange[2] + 1; ++k) { tempf = (i - irange[0]) * spacing[0]; tempf *= tempf; tempf2 = (j - irange[1]) * spacing[1]; tempf2 *= tempf2; tempf += tempf2; tempf2 = (k - irange[2]) * spacing[2]; tempf2 *= tempf2; tempf += tempf2;//square of euclidean distance tempf /= sigma * sigma; weights[i][j][k] = exp(-tempf / 2.0f); } } } //timevol -> values //File -> region //AtlasFile -> atlas //Atlastc -> smoothValues //Dimension bug fixing?? int numSubVolumes = region->getNumberOfSubVolumes(); std::vector smoothSubVolVec; smoothSubVolVec.resize(numSubVolumes); for( int i = 0;iinitialize(VolumeFile::VOXEL_DATA_TYPE_FLOAT, dim, myorient, origin, spacing);//because setDimensions doesn't allocate... smoothSubVolVec[i] = smoothSubVol; //get our input sub volume VolumeFile subVol; try { subVol.readFile(values->getFileName(), i); } catch(FileException e) { // std::cout << "Exception caught while reading volume " << i << " of nifti file, " << values->getFileName() << std::endl; // std::cout << e.whatQString() << std::endl; throw BrainModelAlgorithmException("Error while reading Nifti Sub Volume."); } for (i = 0; i < dim[0]; ++i) {//all voxels for (j = 0; j < dim[1]; ++j) { for (k = 0; k < dim[2]; ++k) { if (region->getVoxel(i, j, k) > 0.0f) {//if selected inputVal = values->getVoxel(i, j, k); int numWeights = 0; smoothVal = 0.0f; for (ki = -irange[0]; ki <= irange[0]; ++ki) {//loop through kernel if (i + ki < 0 || i + ki >= dim[0]) { continue;//makes the indentation a bit less daunting } for (kj = -irange[1]; kj <= irange[1]; ++kj) { if (j + kj < 0 || j + kj >= dim[1]) { continue; } for (kk = -irange[2]; kk <= irange[2]; ++kk) { if (k + kk < 0 || k + kk >= dim[2])// || (ki == 0 && kj == 0 && kk == 0)) {//dont skip center point? continue; } if (region->getVoxel(i + ki, j + kj, k + kk) > 0.0f) { atlasVal = atlas->getVoxel(i + ki, j + kj, k + kk); weightVal = weights[ki + irange[0]][kj + irange[1]][kk + irange[2]]; smoothVal += inputVal * weightVal; numWeights++; } } } } if (smoothVal != smoothVal) { smoothVal = 0.0f;//set NaNs to zero } else { smoothVal /= numWeights; } smoothSubVol->setVoxel(i, j, k, 0, smoothVal); } else { smoothSubVol->setVoxel(i, j, k, 0, 0.0f); } } } } } }*/ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeProbAtlasToFunctional.h0000664000175000017500000000373711572067322027432 0ustar michaelmichael #ifndef __BRAIN_MODEL_VOLUME_PROB_ATLAS_TO_FUNCTIONAL_H__ #define __BRAIN_MODEL_VOLUME_PROB_ATLAS_TO_FUNCTIONAL_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelAlgorithm.h" class VolumeFile; /// class for create a functional volume using a probabilistic volume class BrainModelVolumeProbAtlasToFunctional : public BrainModelAlgorithm { public: /// Constructor BrainModelVolumeProbAtlasToFunctional(BrainSet* bs, VolumeFile* funcVolumeIn, const QString& funcVolumeNameIn, const QString& funcVolumeLabelIn); /// Destructor ~BrainModelVolumeProbAtlasToFunctional(); /// execute the algorithm void execute() throw (BrainModelAlgorithmException); protected: /// functional volume VolumeFile* funcVolume; /// functional volume name QString funcVolumeName; /// functional volume label QString funcVolumeLabel; }; #endif // __BRAIN_MODEL_VOLUME_PROB_ATLAS_TO_FUNCTIONAL_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeProbAtlasToFunctional.cxx0000664000175000017500000001254111572067322027776 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelVolume.h" #include "BrainModelVolumeProbAtlasToFunctional.h" #include "BrainSet.h" #include "DisplaySettingsProbabilisticAtlas.h" #include "VolumeFile.h" /** * Constructor. */ BrainModelVolumeProbAtlasToFunctional::BrainModelVolumeProbAtlasToFunctional( BrainSet* bs, VolumeFile* funcVolumeIn, const QString& funcVolumeNameIn, const QString& funcVolumeLabelIn) : BrainModelAlgorithm(bs) { funcVolume = funcVolumeIn; funcVolumeName = funcVolumeNameIn; funcVolumeLabel = funcVolumeLabelIn; } /** * Destructor. */ BrainModelVolumeProbAtlasToFunctional::~BrainModelVolumeProbAtlasToFunctional() { } /** * execute the algorithm. */ void BrainModelVolumeProbAtlasToFunctional::execute() throw (BrainModelAlgorithmException) { // // Verify volumes exist // const int numberOfVolumes = brainSet->getNumberOfVolumeProbAtlasFiles(); if (numberOfVolumes <= 0) { throw BrainModelAlgorithmException("There are no probabilistic atlas volumes."); } VolumeFile* probAtlasVolume = brainSet->getVolumeProbAtlasFile(0); if (probAtlasVolume == NULL) { throw BrainModelAlgorithmException("Invalid probabilistic atlas volume."); } bool createdFunctionalVolume = false; if (funcVolume == NULL) { funcVolume = new VolumeFile(*probAtlasVolume); funcVolume->setVolumeType(VolumeFile::VOLUME_TYPE_FUNCTIONAL); createdFunctionalVolume = true; } funcVolume->setFileName(funcVolumeName); funcVolume->setDescriptiveLabel(funcVolumeLabel); // // Verify volumes have same dimensions // int pDim[3], fDim[3]; probAtlasVolume->getDimensions(pDim); funcVolume->getDimensions(fDim); for (int i = 0; i < 3; i++) { if (pDim[i] != fDim[i]) { throw BrainModelAlgorithmException( "Prob Atlas and Functional Volumes are of different dimensions."); } } DisplaySettingsProbabilisticAtlas* dspa = brainSet->getDisplaySettingsProbabilisticAtlasVolume(); //BrainModelVolume* bmv = brainSet->getBrainModelVolume(); const int numPaintNames = probAtlasVolume->getNumberOfRegionNames(); // // indices that should be ignored // const int questIndex = probAtlasVolume->getRegionIndexFromName("???"); const int gyralIndex = probAtlasVolume->getRegionIndexFromName("GYRAL"); const int gyrusIndex = probAtlasVolume->getRegionIndexFromName("GYRUS"); // // Loop through voxels // for (int i = 0; i < pDim[0]; i++) { for (int j = 0; j < pDim[1]; j++) { for (int k = 0; k < pDim[2]; k++) { // // Count valid indices // int count = 0; for (int volNum = 0; volNum < numberOfVolumes; volNum++) { VolumeFile* vf = brainSet->getVolumeProbAtlasFile(volNum); int cntIndex = 0; if (dspa->getChannelSelected(volNum)) { const int voxel = static_cast(vf->getVoxel(i, j, k)); cntIndex = voxel; //vf->getProbAtlasNameTableIndex(volNum, voxel); } if ((cntIndex > 0) && (cntIndex < numPaintNames)) { if (dspa->getAreaSelected(cntIndex) == false) { cntIndex = -1; } } if (cntIndex > 0) { // // Skip non-sulci // bool useIt = true; if ((cntIndex == questIndex) || (cntIndex == gyralIndex) || (cntIndex == gyrusIndex)) { useIt = false; } if (useIt) { count++; } } } // for (int volNum... // // Set the functional voxel // funcVolume->setVoxel(i, j, k, 0, count); } } } // // Add new functional volume to brain set // if (createdFunctionalVolume) { brainSet->addVolumeFile(VolumeFile::VOLUME_TYPE_FUNCTIONAL, funcVolume, funcVolume->getFileName(), true, false); } funcVolume->setVoxelColoringInvalid(); } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeNearToPlane.h0000664000175000017500000001016411572067322025355 0ustar michaelmichael #ifndef __BRAIN_MODEL_VOLUME_NEAR_TO_PLANE_H__ #define __BRAIN_MODEL_VOLUME_NEAR_TO_PLANE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelAlgorithm.h" class SureFitVectorFile; class VolumeFile; /// class for volume near to planes calculation class BrainModelVolumeNearToPlane : public BrainModelAlgorithm { public: /// some constants enum { DIM = 3, NALPHA = 6, FILTSIZE = 7 }; /// Constructor BrainModelVolumeNearToPlane(BrainSet* bs, SureFitVectorFile* vecFileIn, const float sigmaNIn, const float sigmaWIn, const float offsetIn, const bool downflagIn, const int gradsignIn, const bool maskingFlagIn, VolumeFile* maskVolumeIn, VolumeFile* outputVolumeIn); /// Destructor ~BrainModelVolumeNearToPlane(); /// execute the algorithm void execute() throw (BrainModelAlgorithmException); protected: /// void generateCoefficientMatrix(float sigmax, float sigmay, float sigmaz); /// void generateEllipsoidFilter(const float sigmax, const float sigmay, const float sigmaz, const float delta, float filter[NALPHA][FILTSIZE][FILTSIZE][FILTSIZE]); /// void multMatrixRow(const float b[3], const float m[3][3], float out[3]); /// void rotateTheta (const float C[DIM][DIM], const int alpha, float Cout[DIM][DIM]); /// void rotatePhi(const float C[DIM][DIM], const int alpha, float Cout[DIM][DIM]); /// void multMatrixMatrix(const float A[DIM][DIM], const float B[DIM][DIM], float out[DIM][DIM]); /// float newVectorConvolve(const int x, const int y, const int z, const float filter[FILTSIZE][FILTSIZE][FILTSIZE], const int signflag, float *dotproduct, const int absflag); /// void computeDotProduct(const int alpha, float *VectorVolumeX, float *VectorVolumeY, float *VectorVolumeZ, float *dotproduct); /// float downVectorConvolve(const int alpha, const int x, const int y, const int z, const float filter[FILTSIZE][FILTSIZE][FILTSIZE], const int signflag, float *VectorVolume[3], const int absFlag); /// SureFitVectorFile* vecFile; /// float sigmaN; /// float sigmaW; /// float offset; /// bool downflag; /// int gradsign; /// bool maskingFlag; /// VolumeFile* maskVolume; /// VolumeFile* outputVolume; }; #endif // __BRAIN_MODEL_VOLUME_NEAR_TO_PLANE_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeNearToPlane.cxx0000664000175000017500000004400211572067322025726 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainModelVolumeNearToPlane.h" #include "DebugControl.h" #include "MathUtilities.h" #include "SureFitVectorFile.h" #include "VolumeFile.h" #include "vtkMath.h" static float Coeff[BrainModelVolumeNearToPlane::NALPHA][3][3]; static float Fnormal[BrainModelVolumeNearToPlane::NALPHA][3]; static float phis[6] = { 0.0, 0.0, 72.0, 144.0, 216.0, 288.0 }; static float thetas[6] = { 0.0, 63.59, 63.59, 63.59, 63.59, 63.59, }; /** * Constructor. */ BrainModelVolumeNearToPlane::BrainModelVolumeNearToPlane( BrainSet* bs, SureFitVectorFile* vecFileIn, const float sigmaNIn, const float sigmaWIn, const float offsetIn, const bool downflagIn, const int gradsignIn, const bool maskingFlagIn, VolumeFile* maskVolumeIn, VolumeFile* outputVolumeIn) : BrainModelAlgorithm(bs) { vecFile = vecFileIn; sigmaN = sigmaNIn; sigmaW = sigmaWIn; offset = offsetIn; downflag = downflagIn; gradsign = gradsignIn; maskingFlag = maskingFlagIn; maskVolume = maskVolumeIn; outputVolume = outputVolumeIn; } /** * Destructor. */ BrainModelVolumeNearToPlane::~BrainModelVolumeNearToPlane() { } /** * execute the algorithm. */ void BrainModelVolumeNearToPlane::execute() throw (BrainModelAlgorithmException) { const int cnt = maskVolume->getNumberOfNonZeroVoxels(); if (DebugControl::getDebugOn()) { std::cout << "\t\tNewNear2Planes " << maskingFlag << std::endl; std::cout << "\t\t\t" << cnt << " voxels turned on in mask" << std::endl; std::cout << "SIGMA: narrow " << sigmaN << ", wide " << sigmaW << std::endl; } //%printf ("%d %d %d; %f %f %f; %d %d\n", ncol, nrow, nslices, //% sigmaN, sigmaW, offset, downflag, gradsign); vecFile->multiplyXYZByMagnitude(); const int numVoxels = outputVolume->getTotalNumberOfVoxels(); outputVolume->setAllVoxels(0.0); float* Pmag = outputVolume->getVoxelData(); float filter1[NALPHA][FILTSIZE][FILTSIZE][FILTSIZE]; float filter2[NALPHA][FILTSIZE][FILTSIZE][FILTSIZE]; generateEllipsoidFilter(sigmaW, sigmaW, sigmaN, offset, filter1); generateEllipsoidFilter(sigmaW, sigmaW, sigmaN, -offset, filter2); int startidx = 0; //ComputeIndex (0, 0, 0, ncol, nrow); float* PMagInit = &Pmag[startidx]; float* OrientVector = new float[numVoxels]; float* OrientVectorForDeleting = OrientVector; float* OrientInit = &OrientVector[startidx]; float* maskVoxels = maskVolume->getVoxelData(); float* MaskInit = &maskVoxels[startidx]; float* dotproduct = new float[numVoxels]; float* dotproductForDeleting = dotproduct; float* dotinit = &dotproduct [startidx]; float* vectorX = vecFile->getWithFlatIndexValueX(0); float* vectorY = vecFile->getWithFlatIndexValueY(0); float* vectorZ = vecFile->getWithFlatIndexValueZ(0); float* vectorInit[3]; vectorInit[0] = &vectorX[startidx]; vectorInit[1] = &vectorY[startidx]; vectorInit[2] = &vectorZ[startidx]; int ncol, nrow, nslices; outputVolume->getDimensions(ncol, nrow, nslices); for (int alpha = 0; alpha < NALPHA; alpha++){ float* Pmag = PMagInit; OrientVector = OrientInit; maskVoxels = MaskInit; dotproduct = dotinit; vectorX = vectorInit [0]; vectorY = vectorInit [1]; vectorZ = vectorInit [2]; computeDotProduct(alpha, vectorX, vectorY, vectorZ, dotproduct); for (int k = 0; k < nslices; k++){ if (DebugControl::getDebugOn()) { if ((k % 10) == 0) { printf ("\tALPHA %d; CONVOLUTION: Slice %d..%d\n", alpha, k, nslices); } } for (int j = 0; j < nrow; j++) { for (int i = 0; i < ncol; i++) { if (((maskingFlag) && (*maskVoxels != 0)) || (maskingFlag == false)) { float nearAlphaPlus = 0.0; float nearAlphaMinus = 0.0; if (downflag == 0){ if (abs(gradsign) == 1) { nearAlphaPlus = MathUtilities::limitToPositive( newVectorConvolve(i, j, k, filter1[alpha], gradsign, dotproduct, 0)); nearAlphaMinus = MathUtilities::limitToPositive( newVectorConvolve(i, j, k, filter2[alpha], -gradsign, dotproduct, 0)); } else { nearAlphaPlus = newVectorConvolve(i, j, k, filter1[alpha], 1, dotproduct, 1); nearAlphaMinus = newVectorConvolve(i, j, k, filter2 [alpha], 1, dotproduct, 1); } } else if (downflag == 1) { if (abs (gradsign) == 1) { nearAlphaPlus = MathUtilities::limitToPositive( downVectorConvolve(alpha, i, j, k, filter1[alpha], gradsign, vectorInit, 0)); nearAlphaMinus = MathUtilities::limitToPositive( downVectorConvolve (alpha, i, j, k, filter2[alpha], -gradsign, vectorInit, 0)); } else { nearAlphaPlus = downVectorConvolve(alpha, i, j, k, filter1[alpha], 1, vectorInit, 1); nearAlphaMinus = downVectorConvolve(alpha, i, j, k, filter2[alpha], 1, vectorInit, 1); } } *OrientVector = std::sqrt(nearAlphaPlus*nearAlphaMinus); *Pmag += *OrientVector; } maskVoxels++; OrientVector++; Pmag++; } } } /* char nfile [256]; sprintf (nfile, "%s.raw.float.c%d", directory, alpha); printf ("Writing volume for alpha %d to %s\n", alpha, nfile); OrientVector = OrientInit; WriteFloatVolume (OrientVector, nfile, ncol, nrow, nslices); */ } Pmag = PMagInit; delete[] OrientVectorForDeleting; //OrientVector; delete[] dotproductForDeleting; //dotproduct; } void BrainModelVolumeNearToPlane::generateCoefficientMatrix (const float sigmax, const float sigmay, const float sigmaz) { for (int k = 0; k < NALPHA; k++) { for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { Coeff[k][i][j] = 0.0; } } } for (int k = 0; k < NALPHA; k++){ Coeff[k][0][0] = 1.0/(sigmax*sigmax); Coeff[k][1][1] = 1.0/(sigmay*sigmay); Coeff[k][2][2] = 1.0/(sigmaz*sigmaz); } for (int i = 0; i < NALPHA; i++){ float Ctheta[NALPHA][3][3]; rotateTheta(Coeff[i], i, Ctheta[i]); rotatePhi(Ctheta[i], i, Coeff[i]); if (DebugControl::getDebugOn()) { std::cout << "Coefficients of Matrix: theta " << thetas[i] << ", phi " << phis[i] << std::endl; for (int j = 0; j < 3; j++) { std::cout << "\t" << Coeff[i][j][0] << " " << Coeff[i][j][1] << " " << Coeff[i][j][2] << std::endl; } } } } /** * */ void BrainModelVolumeNearToPlane::generateEllipsoidFilter(const float sigmax, const float sigmay, const float sigmaz, const float delta, float filter[NALPHA][FILTSIZE][FILTSIZE][FILTSIZE]) { const float DEG2RAD = MathUtilities::degreesToRadians(); for (int i = 0; i < NALPHA; i++){ Fnormal[i][0] = std::sin(DEG2RAD*thetas[i]) * std::cos(DEG2RAD * phis[i]); Fnormal[i][1] = std::sin(DEG2RAD*thetas[i]) * std::sin(DEG2RAD * phis[i]); Fnormal[i][2] = std::cos(DEG2RAD*thetas[i]); if (DebugControl::getDebugOn()) { std::cout << "Normal for " << i << ": " << Fnormal[i][0] << " " << Fnormal[i][1] << " " << Fnormal[i][2] << std::endl; } } generateCoefficientMatrix(sigmax, sigmay, sigmaz); for (int alpha = 0; alpha < NALPHA; alpha++) { if (DebugControl::getDebugOn()) { std::cout << "Generate filter for nalpha " << alpha << " (" << thetas[alpha] << " " << phis[alpha] << ")" << std::endl; } for (int k = 0; k < FILTSIZE; k++) { for (int i = 0; i < FILTSIZE; i++) { for (int j = 0; j < FILTSIZE; j++) { float R[3], Rout[3]; R[0] = i - FILTSIZE/2 - (delta * Fnormal[alpha][0]); R[1] = j - FILTSIZE/2 - (delta * Fnormal[alpha][1]); R[2] = k - FILTSIZE/2 - (delta * Fnormal[alpha][2]); multMatrixRow(R, Coeff[alpha], Rout); const float answer = Rout[0] * R[0] + Rout[1] * R[1] + Rout[2] * R[2]; filter[alpha][i][j][k] = exp(-answer); } } } } } void BrainModelVolumeNearToPlane::multMatrixRow(const float b[3], const float m[3][3], float out[3]) { for (int i = 0; i < 3; i++) { out [i] = 0.0; } for (int i = 0; i < 3; i++){ for (int j = 0; j < 3; j++){ out [i] += b [j] * m [j][i]; } } } /** * */ void BrainModelVolumeNearToPlane::rotatePhi(const float C[DIM][DIM], const int alpha, float Cout[DIM][DIM]) { const float DEG2RAD = MathUtilities::degreesToRadians(); float t1[DIM][DIM], t2[DIM][DIM], t3[DIM][DIM]; for (int i = 0; i < 3; i++){ for (int j = 0; j < DIM; j++){ t1[i][j] = 0.0; t2[i][j] = 0.0; } } t1[0][0] = std::cos(DEG2RAD * phis[alpha]); t1[0][1] = -std::sin(DEG2RAD * phis[alpha]); t1[1][0] = std::sin(DEG2RAD * phis[alpha]); t1[1][1] = std::cos(DEG2RAD * phis[alpha]); t1[2][2] = 1.0; t2[0][0] = std::cos(DEG2RAD * phis[alpha]); t2[0][1] = std::sin(DEG2RAD * phis[alpha]); t2[1][0] = -std::sin(DEG2RAD * phis[alpha]); t2[1][1] = std::cos(DEG2RAD * phis[alpha]); t2[2][2] = 1.0; multMatrixMatrix(t1, C, t3); multMatrixMatrix(t3, t2, Cout); } /** * */ void BrainModelVolumeNearToPlane::rotateTheta(const float C[DIM][DIM], const int alpha, float Cout[DIM][DIM]) { const float DEG2RAD = MathUtilities::degreesToRadians(); float t1[DIM][DIM], t2[DIM][DIM], t3[DIM][DIM]; for (int i = 0; i < DIM; i++){ for (int j = 0; j < DIM; j++){ t1[i][j] = 0.0; t2[i][j] = 0.0; } } t1[0][0] = std::cos(DEG2RAD * thetas[alpha]); t1[0][2] = -std::sin(DEG2RAD * thetas[alpha]); t1[1][1] = 1.0; t1[2][0] = std::sin(DEG2RAD * thetas[alpha]); t1[2][2] = std::cos(DEG2RAD * thetas[alpha]); t2[0][0] = std::cos(DEG2RAD * thetas[alpha]); t2[0][2] = std::sin(DEG2RAD * thetas[alpha]); t2[1][1] = 1.0; t2[2][0] = -std::sin(DEG2RAD * thetas[alpha]); t2[2][2] = std::cos(DEG2RAD * thetas[alpha]); multMatrixMatrix(t1, C, t3); multMatrixMatrix(t3, t2, Cout); } /** * */ void BrainModelVolumeNearToPlane::multMatrixMatrix(const float A[DIM][DIM], const float B[DIM][DIM], float out[DIM][DIM]) { for (int i = 0; i < DIM; i++) { for (int j = 0; j < DIM; j++) { out[i][j] = 0.0; } } for (int i = 0; i < DIM; i++) { for (int j = 0; j < DIM; j++) { for (int k = 0; k < DIM; k++) { out[i][j] += A[i][k] * B[k][j]; } } } } /** * */ float BrainModelVolumeNearToPlane::newVectorConvolve(const int x, const int y, const int z, const float filter[FILTSIZE][FILTSIZE][FILTSIZE], const int signflag, float *dotproduct, const int absflag) { const int offset = FILTSIZE/2; float answer = 0.0; int ncol, nrow, nslices; outputVolume->getDimensions(ncol, nrow, nslices); int xx = x-offset; int starti = 0; if (xx < 0) starti = -xx; else starti = 0; xx = x+offset-ncol; int stopi = 0; if (xx >= 0) stopi = (FILTSIZE-1)-xx; else stopi = FILTSIZE; int yy = y-offset; int startj = 0; if (yy < 0) startj = -yy; else startj = 0; yy = y+offset-nrow; int stopj = 0; if (yy >= 0) stopj = (FILTSIZE-1)-yy; else stopj = FILTSIZE; int zz = z-offset; int startk = 0; if (zz < 0) startk = -zz; else startk = 0; zz = z+offset-nslices; int stopk = 0; if (zz >= 0) stopk = (FILTSIZE-1)-zz; else stopk = FILTSIZE; xx = x+starti-offset; yy = y+startj-offset; zz = z+startk-offset; const int idx = outputVolume->getVoxelDataIndex(xx, yy, zz); const int isize = ncol * nrow; float* startdot = &dotproduct[idx]; float* curdot = &dotproduct[idx]; float val = 0.0; for (int k = startk; k < stopk; k++) { for (int j = startj; j < stopj; j++) { for (int i = starti; i < stopi; i++) { if (absflag == 0) { val = *curdot*signflag; } else { val = fabs(*curdot); } const float filter_val = filter[i][j][k]; answer += val * filter_val; curdot++; } int valinc = (j+1)*ncol; curdot = startdot + valinc; } startdot = startdot + isize; curdot = startdot; } return (answer); } /** * */ void BrainModelVolumeNearToPlane::computeDotProduct(const int alpha, float *VectorVolumeX, float *VectorVolumeY, float *VectorVolumeZ, float *dotproduct) { int ncol, nrow, nslices; outputVolume->getDimensions(ncol, nrow, nslices); for (int k = 0; k < nslices; k++) { for (int j = 0; j < nrow; j++) { for (int i = 0; i < ncol; i++) { float vector[3]; vector[0] = *VectorVolumeX++; vector[1] = *VectorVolumeY++; vector[2] = *VectorVolumeZ++; *dotproduct++ = MathUtilities::dotProduct(Fnormal[alpha], vector); } } } } float BrainModelVolumeNearToPlane::downVectorConvolve(const int alpha, const int x, const int y, const int z, const float filter[FILTSIZE][FILTSIZE][FILTSIZE], const int signflag, float *VectorVolume[3], const int absFlag) { int ncol, nrow, nslices; outputVolume->getDimensions(ncol, nrow, nslices); float answer = 0.0; for (int k = 0; k < FILTSIZE; k++) { for (int j = 0; j < FILTSIZE; j++) { for (int i = 0; i < FILTSIZE; i++) { const float xx = x+(2*i)-(2*FILTSIZE/2); const float yy = y+(2*j)-(2*FILTSIZE/2); const float zz = z+(2*k)-(2*FILTSIZE/2); if ((xx >= 0) && (xx < ncol) && (yy >= 0) && (yy < nrow) && (zz >= 0) && (zz < nslices)) { const int idx = outputVolume->getVoxelDataIndex(static_cast(xx), static_cast(yy), static_cast(zz)); float vector[3]; vector[0] = VectorVolume[0][idx]; vector[1] = VectorVolume[1][idx]; vector[2] = VectorVolume[2][idx]; float val; if (absFlag == 0) { val = signflag*MathUtilities::dotProduct(Fnormal[alpha], vector); } else { val = fabs(MathUtilities::dotProduct(Fnormal[alpha], vector)); } const float filter_val = filter[i][j][k]; answer += val * filter_val; } } } } return (answer); } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeLigaseSegmentation.h0000664000175000017500000000644111572067322026772 0ustar michaelmichael #ifndef __BRAIN_MODEL_VOLUME_LIGASE_SEGMENTATION_H__ #define __BRAIN_MODEL_VOLUME_LIGASE_SEGMENTATION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelAlgorithm.h" class VolumeFile; /// class for create a functional volume using a probabilistic volume class BrainModelVolumeLigaseSegmentation : public BrainModelAlgorithm { public: /// Constructor BrainModelVolumeLigaseSegmentation(BrainSet* bs, VolumeFile* anatVolumeIn, VolumeFile* segVolumeIn, const QString& segVolumeNameIn, const QString& segVolumeLabelIn, const int xIn, const int yIn, const int zIn, const float whiteMinIn, const float whiteMeanIn, const float whiteMaxIn, const float diffBaseIn = 0.18f, const float gradBaseIn = 0.075f, const float highBiasIn = 0.20f, const float lowBiasIn = 0.20f); /// Destructor ~BrainModelVolumeLigaseSegmentation(); /// execute the algorithm void execute() throw (BrainModelAlgorithmException); ///default parameters static inline const float defaultDiff() { return 0.18f; }; static inline const float defaultGrad() { return 0.075f; }; static inline const float defaultHighBias() { return 0.20f; }; static inline const float defaultLowBias() { return 0.20f; }; protected: /// segmentation volume, anatomy input volume VolumeFile* segVolume; VolumeFile* anatVolume; /// segmentation volume name QString segVolumeName; /// segmentation volume label QString segVolumeLabel; /// parameter storage, linked list node definition float whiteMin, whiteMean, whiteMax, diffBase, gradBase, highBias, lowBias; int x_init, y_init, z_init; struct iterNode { iterNode* next; float* iter; }; }; #endif // __BRAIN_MODEL_VOLUME_LIGASE_SEGMENTATION_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeLigaseSegmentation.cxx0000664000175000017500000002250711572067322027346 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelVolume.h" #include "BrainModelVolumeLigaseSegmentation.h" #include "BrainSet.h" #include "VolumeFile.h" #include /** * Constructor. */ BrainModelVolumeLigaseSegmentation::BrainModelVolumeLigaseSegmentation( BrainSet* bs, VolumeFile* anatVolumeIn, VolumeFile* segVolumeOutIn, const QString& segVolumeNameIn, const QString& segVolumeLabelIn, const int xIn, const int yIn, const int zIn, const float whiteMinIn, const float whiteMeanIn, const float whiteMaxIn, const float diffBaseIn, const float gradBaseIn, const float highBiasIn, const float lowBiasIn) : BrainModelAlgorithm(bs) { anatVolume = anatVolumeIn; segVolume = segVolumeOutIn; segVolumeName = segVolumeNameIn; segVolumeLabel = segVolumeLabelIn; whiteMin = whiteMinIn; whiteMean = whiteMeanIn; whiteMax = whiteMaxIn; x_init = xIn; y_init = yIn; z_init = zIn; diffBase = diffBaseIn * (whiteMax - whiteMin); gradBase = gradBaseIn; highBias = highBiasIn; lowBias = lowBiasIn; } /** * Destructor. */ BrainModelVolumeLigaseSegmentation::~BrainModelVolumeLigaseSegmentation() { } /** * execute the algorithm. */ void BrainModelVolumeLigaseSegmentation::execute() throw (BrainModelAlgorithmException) { // // Verify volumes exist // if (anatVolume == NULL) { throw BrainModelAlgorithmException("Invalid anatomy volume."); } if (anatVolume->getNumberOfComponentsPerVoxel() != 1) { throw BrainModelAlgorithmException("Volume has multiple components."); } bool createdSegmentationVolume = false; if (segVolume == NULL) { segVolume = new VolumeFile(*anatVolume); segVolume->setVolumeType(VolumeFile::VOLUME_TYPE_SEGMENTATION); createdSegmentationVolume = true; } segVolume->setFileName(segVolumeName); segVolume->setDescriptiveLabel(segVolumeLabel); // // Verify volumes have same dimensions // int aDim[3], sDim[3]; anatVolume->getDimensions(aDim); segVolume->getDimensions(sDim); for (int i = 0; i < 3; i++) { if (aDim[i] != sDim[i]) { throw BrainModelAlgorithmException( "Anatomy and Segmentation Volumes are of different dimensions."); } } // // Calculate 3D gradient magnitude // int i, j, k, xstep = 1, ystep = aDim[0], zstep = aDim[0] * aDim[1]; float idist, jdist, kdist, xd, yd, zd, max = 0.0f, temp, tempa, tempb, cutoff, sig1 = whiteMean - whiteMin, sig2 = whiteMax - whiteMean; float* voxels = anatVolume->getVoxelData(), *end = voxels + aDim[0] * aDim[1] * aDim[2] - zstep; float* iter, *i_iter, *j_iter, *k_iter; float* grad_mag = new float[aDim[0] * aDim[1] * aDim[2]]; float spacing[3]; anatVolume->getSpacing(spacing); // // pointer math gradient // for (iter = voxels + zstep; iter < end; ++iter) { xd = (*(iter + xstep) - *(iter - xstep)) / spacing[0]; yd = (*(iter + ystep) - *(iter - ystep)) / spacing[1]; zd = (*(iter + zstep) - *(iter - zstep)) / spacing[2]; temp = sqrtf(xd * xd + yd * yd + zd * zd); *(grad_mag + (iter - voxels)) = temp; if (temp > max) { max = temp; } }//WARNING: edges wrap, assumed to be unimportant, first and last slices uninitialized if (max == 0.0f) { delete[] grad_mag; throw BrainModelAlgorithmException("Anatomy volume has no gradient!"); } // // scale from 0 to 1 // end = grad_mag + aDim[0] * aDim[1] * aDim[2]; for (iter = grad_mag; iter < end; ++iter) { *iter /= max; } float* seg = segVolume->getVoxelData(); end = seg + aDim[0] * aDim[1] * aDim[2]; // // zero segmentation volume // // change to make all nonzeros less than 254 so it adds to existing segmentation? // for (iter = seg; iter < end; ++iter) { *iter = 0.0f; } end = voxels + aDim[0] * aDim[1] * aDim[2]; // // set first point // iterNode* head = new iterNode(), *tempIter; head->next = NULL; head->iter = voxels + anatVolume->getVoxelDataIndex(x_init, y_init, z_init); *(seg + (head->iter - voxels)) = 255.0f; // // loop until seed list clears (no more expansion) // // pointer math is used mostly to avoid calls to getVoxelDataIndex and to avoid reshaping the voxel data // while (head) { iter = head->iter; tempIter = head; head = head->next; delete tempIter; // // loop through neighbors via pointer math // for (i = -1; i < 2; ++i) { i_iter = iter + i * xstep; // // check if its the same slice // if (~i || (i_iter - voxels) / ystep == (iter - voxels) / ystep) { idist = i * spacing[0]; idist = idist * idist; for (j = -1; j < 2; ++j) { j_iter = i_iter + j * ystep; if (~j || (j_iter - voxels) / zstep == (iter - voxels) / zstep) { jdist = j * spacing[1]; jdist = idist + jdist * jdist; for (k = -1; k < 2; ++k) { k_iter = j_iter + k * zstep; // // check that its not already visited // if ((~k || (k_iter >= voxels && k_iter < end)) && *(seg + (k_iter - voxels)) < 254.0f) { kdist = k * spacing[2]; // // incremental distance from parent voxel // kdist = sqrtf(jdist + kdist * kdist); // // probabilistic intensity classification used as cutoff modifier // if (*k_iter < whiteMean) { temp = (whiteMean - *k_iter) / sig1; } else { temp = (whiteMean - *k_iter) / sig2; } cutoff = expf(-temp * temp / 2); // // difference from parent and 3d gradient magnitude used as criteria // temp = (*iter - *k_iter); //if (temp < 0.0f) temp = -temp; // unneeded for elliptical cutoffs tempa = temp / kdist / diffBase / cutoff; tempb = *(grad_mag + (k_iter - voxels)) / gradBase / cutoff; // // if the ordered pair formed by criteria divided by their respective cutoffs has euclidean distance // of less than 1, it grows there // // think of an ellipse on the diff-gradient plane, size determined by intensity and shape by respective // cutoffs, if the values at the point lie inside, the point is used // if (tempa * tempa + tempb * tempb < 1.0f) { *(seg + (k_iter - voxels)) = 255.0f; tempIter = new iterNode(); tempIter->next = head; tempIter->iter = k_iter; head = tempIter; } } } } } } } } // // Add new segmentation volume to brain set // if (createdSegmentationVolume) { brainSet->addVolumeFile(VolumeFile::VOLUME_TYPE_SEGMENTATION, segVolume, segVolume->getFileName(), true, false); } delete[] grad_mag; segVolume->setVoxelColoringInvalid(); } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeHandleFinder.h0000664000175000017500000001303311572067322025526 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __BRAIN_MODEL_VOLUME_HANDLE_FINDER_H__ #define __BRAIN_MODEL_VOLUME_HANDLE_FINDER_H__ #include #include #include "BrainModelAlgorithm.h" #include "BrainModelVolumeTopologicalError.h" class BrainSet; #include "VolumeFile.h" /// class that finds handles in a binary volume class BrainModelVolumeHandleFinder : public BrainModelAlgorithm { public: /// Constructor BrainModelVolumeHandleFinder(BrainSet* bs, VolumeFile* segmentationIn, const bool addHandlesVolumeToBrainSetIn, const bool searchAxisXIn, const bool searchAxisYIn, const bool searchAxisZIn, const bool rgbPaintSurfaceHandlesIn); /// Destructor ~BrainModelVolumeHandleFinder(); /// execute the algorithm virtual void execute() throw (BrainModelAlgorithmException); /// get the number of handles found int getNumberOfHandles() const { return handlesFound.size(); } /// get the information about a handle const BrainModelVolumeTopologicalError* getHandleInfo(const int handleNumber) const { return &handlesFound[handleNumber]; } private: /// voxel values used while searching enum { VOXEL_CAVITY = 200, VOXEL_EXTERIOR = 100, VOXEL_HANDLE = 150, VOXEL_NOT_HANDLE = 175, VOXEL_SEGMENTATION = 255, VOXEL_UNSET = 0 }; /// Class for storing voxel indices used while searching a volume class VoxelIJK { public: /// Constructor VoxelIJK(const int i, const int j, const int k) { ijkv[0] = i; ijkv[1] = j; ijkv[2] = k; } /// Constructor VoxelIJK(const int ijkIn[3]) { ijkv[0] = ijkIn[0]; ijkv[1] = ijkIn[1]; ijkv[2] = ijkIn[2]; } /// get the voxel indices const int* getIJK() const { return &ijkv[0]; } /// get the voxel indices void getIJK(int& i, int& j, int& k) const { i = ijkv[0]; j = ijkv[1]; k = ijkv[2]; } private: /// the voxel indices int ijkv[3]; }; /// intialize the exterior voxels void initialVoxelAssignments(const VolumeFile::VOLUME_AXIS searchAxis); /// Flood fill in 2D all 4-connected neighbors orthogonal specified axis. void floodFill4Connected(const VolumeFile::VOLUME_AXIS searchAxis, const int x, const int y, const int z, const int replace, const int replaceWith); /// Find handles along the specified axis void findHandles(const VolumeFile::VOLUME_AXIS searchAxis); /// determine if VOXEL_UNSET voxels should be VOXEL_HANDLE void findHandleSearch(const VolumeFile::VOLUME_AXIS searchAxis, const int x, const int y, const int z); /// clear the visited voxel flags void clearVisitedVoxels(); /// highlight handles in the surface using RGB Paint void highlightHandlesInSurface(); /// brain volume for searching for handles VolumeFile* segmentationVolume; /// brain volume showing handles VolumeFile* handlesVolume; /// x dimensions of volume int volumeDimX; /// x dimensions of volume int volumeDimY; /// x dimensions of volume int volumeDimZ; /// points to voxels currently being searched (do not delete) unsigned char* voxels; /// total number of voxels int numVoxels; /// slice of external voxels found while searching for handles std::set externalVoxelSlice; /// visited voxel flag used while searching int* visitedVoxels; /// keeps track of handles that are found std::vector handlesFound; /// search along the x axis for handles bool searchAxisX; /// search along the y axis for handles bool searchAxisY; /// search along the z axis for handles bool searchAxisZ; /// create the handles volume bool addHandlesVolumeToBrainSet; /// paint nodes around handles with rgb paint file bool rgbPaintSurfaceHandles; }; #endif // __BRAIN_MODEL_VOLUME_HANDLE_FINDER_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeHandleFinder.cxx0000664000175000017500000006363211572067322026113 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainModelVolume.h" #include "BrainModelVolumeHandleFinder.h" #include "BrainSet.h" #include "DebugControl.h" #include "FileUtilities.h" #include "RgbPaintFile.h" #include "TopologyFile.h" #include "TopologyHelper.h" #include "VolumeFile.h" /** * Constructor. * If the "handlesVolumeIn" is NULL it will be created. Otherwise, its * contents will be overwritten. */ BrainModelVolumeHandleFinder::BrainModelVolumeHandleFinder(BrainSet* bs, VolumeFile* segmentationIn, const bool addHandlesVolumeToBrainSetIn, const bool searchAxisXIn, const bool searchAxisYIn, const bool searchAxisZIn, const bool rgbPaintSurfaceHandlesIn) : BrainModelAlgorithm(bs) { segmentationVolume = segmentationIn; handlesVolume = NULL; addHandlesVolumeToBrainSet = addHandlesVolumeToBrainSetIn; voxels = NULL; visitedVoxels = NULL; searchAxisX = searchAxisXIn; searchAxisY = searchAxisYIn; searchAxisZ = searchAxisZIn; rgbPaintSurfaceHandles = rgbPaintSurfaceHandlesIn; } /** * Destructor */ BrainModelVolumeHandleFinder::~BrainModelVolumeHandleFinder() { } /** * execute the algorithm */ void BrainModelVolumeHandleFinder::execute() throw (BrainModelAlgorithmException) { // // Get information about the input volume // int dim[3]; segmentationVolume->getDimensions(dim); float origin[3]; segmentationVolume->getOrigin(origin); float spacing[3]; segmentationVolume->getSpacing(spacing); VolumeFile::ORIENTATION orientation[3]; segmentationVolume->getOrientation(orientation); // // Dimensions of input volume // volumeDimX = dim[0]; volumeDimY = dim[1]; volumeDimZ = dim[2]; // // Get the number of voxels // numVoxels = segmentationVolume->getTotalNumberOfVoxels(); if (numVoxels <= 0) { throw BrainModelAlgorithmException("Segmentation volume is empty"); } if (numVoxels != (volumeDimX * volumeDimY * volumeDimZ)) { throw BrainModelAlgorithmException("Number of voxels does not match dimensions."); } // // Copy input voxels since input and output volumes may be the same. // Create volumes for searching along the three axis. // unsigned char* inputVoxels = new unsigned char[numVoxels]; unsigned char* voxelsX = new unsigned char[numVoxels]; unsigned char* voxelsY = new unsigned char[numVoxels]; unsigned char* voxelsZ = new unsigned char[numVoxels]; for (int ii = 0; ii < numVoxels; ii++) { // // All non-zero voxels are assumed part of the segmentation // int voxel = VOXEL_UNSET; if (segmentationVolume->getVoxelWithFlatIndex(ii) != 0.0) { voxel = VOXEL_SEGMENTATION; } inputVoxels[ii] = voxel; voxelsX[ii] = voxel; voxelsY[ii] = voxel; voxelsZ[ii] = voxel; } // // Keeps track of voxels while searching // visitedVoxels = new int[numVoxels]; // // Look for voxels along the Z axis // if (searchAxisZ) { voxels = voxelsZ; initialVoxelAssignments(VolumeFile::VOLUME_AXIS_Z); findHandles(VolumeFile::VOLUME_AXIS_Z); } // // Look for voxels along the Y axis // if (searchAxisY) { voxels = voxelsY; initialVoxelAssignments(VolumeFile::VOLUME_AXIS_Y); findHandles(VolumeFile::VOLUME_AXIS_Y); } // // Look for voxels along the X axis // if (searchAxisX) { voxels = voxelsX; initialVoxelAssignments(VolumeFile::VOLUME_AXIS_X); findHandles(VolumeFile::VOLUME_AXIS_X); } // // Create the handles volume // handlesVolume = new VolumeFile(); handlesVolume->initialize(VolumeFile::VOXEL_DATA_TYPE_RGB_VOXEL_INTERLEAVED, dim, orientation, origin, spacing); //vtkDataArray* handles = handlesVolume->getVolumeData()->GetPointData()->GetScalars(); // // copy the handles found along each axis into the handles volume // for (int k = 0; k < volumeDimZ; k++) { for (int i = 0; i < volumeDimX; i++) { for (int j = 0; j < volumeDimY; j++) { bool handleFlag = false; const int ijk[3] = { i, j, k }; const int voxelID = segmentationVolume->getVoxelNumber(ijk); //handlesVolume->setVoxel(voxelID, inputVoxels[voxelID]); const int xvoxel = voxelsX[voxelID]; if (xvoxel == VOXEL_HANDLE) { handleFlag = true; } const int yvoxel = voxelsY[voxelID]; if (yvoxel == VOXEL_HANDLE) { handleFlag = true; } const int zvoxel = voxelsZ[voxelID]; if (zvoxel == VOXEL_HANDLE) { handleFlag = true; } if (handleFlag) { handlesVolume->setVoxel(ijk, 0, 255.0); handlesVolume->setVoxel(ijk, 1, 0.0); handlesVolume->setVoxel(ijk, 2, 255.0); } else { handlesVolume->setVoxel(ijk, 0, 0.0); handlesVolume->setVoxel(ijk, 1, 0.0); handlesVolume->setVoxel(ijk, 2, 0.0); } //voxels[voxelID] = static_cast(handles->GetComponent(voxelID, 0)); } } } // // If surface should be painted around the handles with rgb paint // if (rgbPaintSurfaceHandles) { highlightHandlesInSurface(); } // // Add handles volume to brain set if requested // if (addHandlesVolumeToBrainSet && (brainSet != NULL) && (getNumberOfHandles() > 0)) { const QString directory = FileUtilities::dirname(segmentationVolume->getFileName()); const QString filename = FileUtilities::basename(segmentationVolume->getFileName()); if (filename.isEmpty() == false) { QString s(directory); if (s.isEmpty() == false) { s.append("/"); } s.append("handles_"); s.append(filename); handlesVolume->setFileName(s); } handlesVolume->clearModified(); brainSet->addVolumeFile(VolumeFile::VOLUME_TYPE_RGB, handlesVolume, handlesVolume->getFileName(), true, false); } else { delete handlesVolume; } // // Free memory // delete[] inputVoxels; delete[] voxelsX; delete[] voxelsY; delete[] voxelsZ; delete[] visitedVoxels; } /** * Highlight nodes in the surface around the handles. */ void BrainModelVolumeHandleFinder::highlightHandlesInSurface() { // // Find the active fiducial surface // BrainModelSurface* fiducialSurface = brainSet->getActiveFiducialSurface(); if (fiducialSurface == NULL) { return; } // // Get the Coordinate file // CoordinateFile* cf = fiducialSurface->getCoordinateFile(); const int numCoords = cf->getNumberOfCoordinates(); if (numCoords <= 0) { return; } // // Get pointer to voxels // int dim[3]; handlesVolume->getDimensions(dim); if ((dim[0] <= 0) || (dim[1] <= 0) || (dim[2] <= 0)) { return; } // // Get the RGB Paint File // RgbPaintFile* rgbFile = brainSet->getRgbPaintFile(); // // Find/Create Handles column // const QString columnName("Handles"); int columnNumber = rgbFile->getColumnWithName(columnName); if ((columnNumber < 0) || (columnNumber >= rgbFile->getNumberOfColumns())) { if (rgbFile->getNumberOfColumns() == 0) { rgbFile->setNumberOfNodesAndColumns(numCoords, 1); } else { rgbFile->addColumns(1); } columnNumber = rgbFile->getNumberOfColumns() - 1; } rgbFile->setColumnName(columnNumber, columnName); bool* handlesFlag = new bool[numCoords]; // // See if node is around a handle // for (int i = 0; i < numCoords; i++) { float xyz[3]; cf->getCoordinate(i, xyz); handlesFlag[i] = false; int ijk[3]; float pcoords[3]; if (handlesVolume->convertCoordinatesToVoxelIJK(xyz, ijk, pcoords)) { if (handlesVolume->getVoxel(ijk, 0) != 0.0) { handlesFlag[i] = true; } } } // // Get a topology helper for the fiducial surface to access neighbors // const TopologyFile* tf = fiducialSurface->getTopologyFile(); const TopologyHelper* th = tf->getTopologyHelper(false, true, false); // // Highlight nodes that are neighbors of nodes marked has handles // bool* handlesFlag2 = new bool[numCoords]; const int neighborDepth = 2; for (int k = 0; k < neighborDepth; k++) { for (int i = 0; i < numCoords; i++) { handlesFlag2[i] = handlesFlag[i]; } for (int i = 0; i < numCoords; i++) { if (handlesFlag[i]) { int numNeighbors = 0; const int* neighbors = th->getNodeNeighbors(i, numNeighbors); for (int j = 0; j < numNeighbors; j++) { handlesFlag2[neighbors[j]] = true; } } } for (int i = 0; i < numCoords; i++) { handlesFlag[i] = handlesFlag2[i]; } } for (int i = 0; i < numCoords; i++) { if (handlesFlag[i]) { rgbFile->setRgb(i, columnNumber, 255.0, 0.0, 255.0); } else { rgbFile->setRgb(i, columnNumber, 0.0, 0.0, 0.0); } } rgbFile->clearModified(); delete[] handlesFlag; delete[] handlesFlag2; } /** * Clear the visited voxels. */ void BrainModelVolumeHandleFinder::clearVisitedVoxels() { for (int i = 0; i < numVoxels; i++) { visitedVoxels[i] = 0; } } /** * Look for any voxels with value VOXEL_UNSET that are six connected * to a voxel with value VOXEL_EXTERIOR thus forming a handle. */ void BrainModelVolumeHandleFinder::findHandleSearch(const VolumeFile::VOLUME_AXIS searchAxis, const int ii, const int jj, const int kk) { std::stack st; st.push(VoxelIJK(ii, jj, kk)); while (st.empty() == false) { const VoxelIJK v = st.top(); st.pop(); int i, j, k; v.getIJK(i, j, k); if ((i >= 0) && (i < volumeDimX) && (j >= 0) && (j < volumeDimY) && (k >= 0) && (k < volumeDimZ)) { const int ijk[3] = { i, j, k }; const int voxelID = segmentationVolume->getVoxelNumber(ijk); const int voxel = voxels[voxelID]; if (voxel == VOXEL_UNSET) { if (visitedVoxels[voxelID] == 0) { visitedVoxels[voxelID] = 1; switch (searchAxis) { case VolumeFile::VOLUME_AXIS_X: if (i < (volumeDimX - 1)) { const int ijk2[3] = { i + 1, j, k }; const int voxelID2 = segmentationVolume->getVoxelNumber(ijk2); if (voxels[voxelID2] == VOXEL_EXTERIOR) { externalVoxelSlice.insert(i + 1); } } if (i > 0) { const int ijk2[3] = { i - 1, j, k }; const int voxelID2 = segmentationVolume->getVoxelNumber(ijk2); if (voxels[voxelID2] == VOXEL_EXTERIOR) { externalVoxelSlice.insert(i - 1); } } break; case VolumeFile::VOLUME_AXIS_Y: if (j < (volumeDimY - 1)) { const int ijk2[3] = { i, j + 1, k }; const int voxelID2 = segmentationVolume->getVoxelNumber(ijk2); if (voxels[voxelID2] == VOXEL_EXTERIOR) { externalVoxelSlice.insert(j + 1); } } if (j > 0) { const int ijk2[3] = { i, j - 1, k }; const int voxelID2 = segmentationVolume->getVoxelNumber(ijk2); if (voxels[voxelID2] == VOXEL_EXTERIOR) { externalVoxelSlice.insert(j - 1); } } break; case VolumeFile::VOLUME_AXIS_Z: if (k < (volumeDimZ - 1)) { const int ijk2[3] = { i, j, k + 1 }; const int voxelID2 = segmentationVolume->getVoxelNumber(ijk2); if (voxels[voxelID2] == VOXEL_EXTERIOR) { externalVoxelSlice.insert(k + 1); } } if (k > 0) { const int ijk2[3] = { i, j, k - 1 }; const int voxelID2 = segmentationVolume->getVoxelNumber(ijk2); if (voxels[voxelID2] == VOXEL_EXTERIOR) { externalVoxelSlice.insert(k - 1); } } break; case VolumeFile::VOLUME_AXIS_ALL: case VolumeFile::VOLUME_AXIS_OBLIQUE: case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } st.push(VoxelIJK(i - 1, j, k)); st.push(VoxelIJK(i + 1, j, k)); st.push(VoxelIJK(i, j - 1, k)); st.push(VoxelIJK(i, j + 1, k)); st.push(VoxelIJK(i, j, k - 1)); st.push(VoxelIJK(i, j, k + 1)); } } } } } /** * Find handles along the specified axis. */ void BrainModelVolumeHandleFinder::findHandles(const VolumeFile::VOLUME_AXIS searchAxis) { int loop1Start = 0; int loop1End = 0; int loop2Start = 0; int loop2End = 0; int loop3Start = 0; int loop3End = 0; switch (searchAxis) { case VolumeFile::VOLUME_AXIS_X: loop1Start = 1; loop1End = volumeDimX - 1; loop2Start = 0; loop2End = volumeDimY; loop3Start = 0; loop3End = volumeDimZ; break; case VolumeFile::VOLUME_AXIS_Y: loop1Start = 1; loop1End = volumeDimY - 1; loop2Start = 0; loop2End = volumeDimX; loop3Start = 0; loop3End = volumeDimZ; break; case VolumeFile::VOLUME_AXIS_Z: loop1Start = 1; loop1End = volumeDimZ - 1; loop2Start = 0; loop2End = volumeDimX; loop3Start = 0; loop3End = volumeDimY; break; case VolumeFile::VOLUME_AXIS_ALL: case VolumeFile::VOLUME_AXIS_OBLIQUE: case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } for (int loop1 = loop1Start; loop1 < loop1End; loop1++) { for (int loop2 = loop2Start; loop2 < loop2End; loop2++) { for (int loop3 = loop3Start; loop3 < loop3End; loop3++) { int x = 0; int y = 0; int z = 0; switch (searchAxis) { case VolumeFile::VOLUME_AXIS_X: x = loop1; y = loop2; z = loop3; break; case VolumeFile::VOLUME_AXIS_Y: x = loop2; y = loop1; z = loop3; break; case VolumeFile::VOLUME_AXIS_Z: x = loop2; y = loop3; z = loop1; break; case VolumeFile::VOLUME_AXIS_ALL: case VolumeFile::VOLUME_AXIS_OBLIQUE: case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } int ijk[3] = { x, y, z }; // // Get the value at the voxel indices // int voxelID = segmentationVolume->getVoxelNumber((int*)ijk); const int voxel = voxels[voxelID]; // // Is this a potential handle voxel ? // if (voxel == VOXEL_UNSET) { clearVisitedVoxels(); // // Search VOXEL_UNSET voxels finding any that are adjacent in the // search axis to VOXEL_EXTERIOR voxels. // findHandleSearch(searchAxis, x, y, z); int status = VOXEL_NOT_HANDLE; // // If two or VOXEL_EXTERIOR voxels with different slices along // the search axis were found, then these voxels are part of a handle // if (externalVoxelSlice.size() > 1) { status = VOXEL_HANDLE; } // // Voxels are full enclosed by VOXEL_SEGMENTATION voxels // else if (externalVoxelSlice.size() == 0) { status = VOXEL_CAVITY; } // // Make the voxels as not a handle, in a handle, or in a cavity // int numVoxelsInHandle = 0; for (int m = 0; m < numVoxels; m++) { if (visitedVoxels[m]) { voxels[m] = status; numVoxelsInHandle++; } } // // Are the voxels in a handle // if (externalVoxelSlice.size() > 1) { // // Get the range of the slices along the search axis // int firstSlice = -1; int lastSlice = -1; for (std::set::iterator is = externalVoxelSlice.begin(); is != externalVoxelSlice.end(); is++) { if (is == externalVoxelSlice.begin()) { firstSlice = *is + 1; } lastSlice = *is - 1; } if (DebugControl::getDebugOn()) { std::cout << "Handle at voxel (" << x << ", " << y << ", " << z << ") slices (" << firstSlice << ", " << lastSlice << ") involves " << numVoxelsInHandle << " voxels" << endl; } // // Save the handle information // const int slices[2] = { firstSlice, lastSlice }; std::vector handleVoxels; for (int m = 0; m < numVoxels; m++) { if (visitedVoxels[m]) { handleVoxels.push_back(m); } } float voxelXYZ[3]; segmentationVolume->getVoxelCoordinate(ijk, voxelXYZ); handlesFound.push_back(BrainModelVolumeTopologicalError(ijk, voxelXYZ, slices, handleVoxels, numVoxelsInHandle, searchAxis)); } externalVoxelSlice.clear(); } } } } } /** * Flood fill in 2D all 4-connected neighbors orthogonal specified axis. */ void BrainModelVolumeHandleFinder::floodFill4Connected(const VolumeFile::VOLUME_AXIS searchAxis, const int i1, const int j1, const int z1, const int replace, const int replaceWith) { std::stack st; st.push(VoxelIJK(i1, j1, z1)); while (st.empty() == false) { const VoxelIJK v = st.top(); st.pop(); int i, j, k; v.getIJK(i, j, k); if ((i >= 0) && (i < volumeDimX) && (j >= 0) && (j < volumeDimY) && (k >= 0) && (k < volumeDimZ)) { const int ijk[3] = { i, j, k }; const int voxelID = segmentationVolume->getVoxelNumber(ijk); const int voxel = voxels[voxelID]; if (voxel == replace) { int iDelta = 0; int jDelta = 0; int kDelta = 0; switch (searchAxis) { case VolumeFile::VOLUME_AXIS_X: iDelta = 0; jDelta = 1; kDelta = 1; break; case VolumeFile::VOLUME_AXIS_Y: iDelta = 1; jDelta = 0; kDelta = 1; break; case VolumeFile::VOLUME_AXIS_Z: iDelta = 1; jDelta = 1; kDelta = 0; break; case VolumeFile::VOLUME_AXIS_ALL: case VolumeFile::VOLUME_AXIS_OBLIQUE: case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } voxels[voxelID] = replaceWith; 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)); } } } } } /** * Move around edges of volume and set all "4 connected" neighbors as * VOXEL_EXTERIOR. Any voxels remaining with the value VOXEL_UNSET are * potential handles. */ void BrainModelVolumeHandleFinder::initialVoxelAssignments(const VolumeFile::VOLUME_AXIS searchAxis) { switch (searchAxis) { case VolumeFile::VOLUME_AXIS_X: for (int x = 0; x < volumeDimX; x++) { for (int y = 0; y < volumeDimY; y++) { floodFill4Connected(VolumeFile::VOLUME_AXIS_X, x, y, 0, VOXEL_UNSET, VOXEL_EXTERIOR); floodFill4Connected(VolumeFile::VOLUME_AXIS_X, x, y, volumeDimZ - 1, VOXEL_UNSET, VOXEL_EXTERIOR); } for (int z = 0; z < volumeDimZ; z++) { floodFill4Connected(VolumeFile::VOLUME_AXIS_X, x, 0, z, VOXEL_UNSET, VOXEL_EXTERIOR); floodFill4Connected(VolumeFile::VOLUME_AXIS_X, x, volumeDimY - 1, z, VOXEL_UNSET, VOXEL_EXTERIOR); } } break; case VolumeFile::VOLUME_AXIS_Y: for (int y = 0; y < volumeDimY; y++) { for (int x = 0; x < volumeDimX; x++) { floodFill4Connected(VolumeFile::VOLUME_AXIS_Y, x, y, 0, VOXEL_UNSET, VOXEL_EXTERIOR); floodFill4Connected(VolumeFile::VOLUME_AXIS_Y, x, y, volumeDimZ - 1, VOXEL_UNSET, VOXEL_EXTERIOR); } for (int z = 0; z < volumeDimZ; z++) { floodFill4Connected(VolumeFile::VOLUME_AXIS_Y, 0, y, z, VOXEL_UNSET, VOXEL_EXTERIOR); floodFill4Connected(VolumeFile::VOLUME_AXIS_Y, volumeDimX - 1, y, z, VOXEL_UNSET, VOXEL_EXTERIOR); } } break; case VolumeFile::VOLUME_AXIS_Z: for (int z = 0; z < volumeDimZ; z++) { for (int x = 0; x < volumeDimX; x++) { floodFill4Connected(VolumeFile::VOLUME_AXIS_Z, x, 0, z, VOXEL_UNSET, VOXEL_EXTERIOR); floodFill4Connected(VolumeFile::VOLUME_AXIS_Z, x, volumeDimY - 1, z, VOXEL_UNSET, VOXEL_EXTERIOR); } for (int y = 0; y < volumeDimY; y++) { floodFill4Connected(VolumeFile::VOLUME_AXIS_Z, 0, y, z, VOXEL_UNSET, VOXEL_EXTERIOR); floodFill4Connected(VolumeFile::VOLUME_AXIS_Z, volumeDimX - 1, y, z, VOXEL_UNSET, VOXEL_EXTERIOR); } } break; case VolumeFile::VOLUME_AXIS_ALL: case VolumeFile::VOLUME_AXIS_OBLIQUE: case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeGradient.h0000664000175000017500000000723011572067322024742 0ustar michaelmichael #ifndef __BRAIN_MODEL_VOLUME_GRADIENT_H__ #define __BRAIN_MODEL_VOLUME_GRADIENT_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelAlgorithm.h" class SureFitVectorFile; class VolumeFile; /// class for creating a gradient on a volume class BrainModelVolumeGradient : public BrainModelAlgorithm { public: /// Constructor BrainModelVolumeGradient(BrainSet* bs, const int lambdaIn, const bool gradFlagIn, const bool maskingFlag, VolumeFile* volumeFileIn, VolumeFile* wholeMaskVolumeIn, SureFitVectorFile* gradFileIn); /// Destructor ~BrainModelVolumeGradient(); /// execute the algorithm void execute() throw (BrainModelAlgorithmException); protected: /// lambda int lambda; /// grad flag bool gradFlag; /// masking flag bool maskingFlag; /// volume file VolumeFile* volumeFile; /// mask volume VolumeFile* wholeMaskVolume; /// gradient file SureFitVectorFile* gradFile; /// misc enums enum { NALPHA = 6 }; /// cosine table float* gradientCosTable[3]; /// sine table float* gradientSinTable[3]; /// compute wave vectors. void computeWaveVectors(float N[NALPHA][3], const float kmag, const float phi); /// gradient function void mod3d(float* voxels, float *Cos, float *Sin, const int ncol, const int nrow, const int nslices); /// gradient function void LPF_5(float* voxels, const int ncol, const int nrow, const int nslices, const float Wo); /// Compute some sin/cos tables void computeTables(const float *N, const int ncol, const int nrow, const int nslices); /// void demod3d(float *Cos, float *Sin, const int ncol, int const nrow, const int nslices); /// //static void seperableConvolve(int ncol, int nrow, int nslices, // float *volume, float *filter); /// //static void oneDimConvolve (float *voxel, float *tempResult, float *filter, // const int dim, const int inc, // const int ncol, const int nrow, const int nslices); /// void applyOddMatrix(int idx, const double R[NALPHA], float *Grad[4], const double Mx[NALPHA], const double My[NALPHA], const double Mz[NALPHA]); /// double multRow(const double R[NALPHA], const double M[NALPHA]); }; #endif // __BRAIN_MODEL_VOLUME_GRADIENT_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeGradient.cxx0000664000175000017500000010153711572067322025322 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include // needed for Q_OS_WIN32 #ifdef Q_OS_WIN32 // required for M_PI in #define _USE_MATH_DEFINES #define NOMINMAX #endif #include #include #include #include "BrainModelVolumeGradient.h" #include "DebugControl.h" #include "SureFitVectorFile.h" #include "VolumeFile.h" // // Stuff for gradient operations // #define FIVE_TAP #ifdef FIVE_TAP /* 5 tap kmag= 0.5 */ double M01[6] = { 0.2500, 0.2638, 0.2684, 0.2760, 0.2760, 0.2684}; double Mx1[6] = {0.0229, 0.9473, 0.2578, -0.7316, -0.7316, 0.2578}; double My1[6] = {-0.0000, -0.0000, 0.8901, 0.5082, -0.5082, -0.8901}; double Mz1[6] = {1.1201, 0.4535, 0.4461, 0.4370, 0.4370, 0.4461}; double Mxx1[6] = { 1.8665, 0.5017, 1.7378, 0.9013, 0.9013, 1.7378 }; double Myy1[6] = { 1.8525, 1.8471, 0.5788, 1.3642, 1.3642, 0.5788 }; double Mzz1[6] = { -0.1405, 1.1744, 1.1583, 1.1327, 1.1327, 1.1583 }; double Mxy1[6] = { -0.0000,-0.0000,-0.6869, 1.2031,-1.2031, 0.6869 }; double Mxz1[6] = { -0.3044,-1.4666,-0.5865, 0.8093, 0.8093,-0.5865 }; double Myz1[6] = { 0.0000, 0.0000,-1.1971,-0.7241, 0.7241, 1.1971 }; /* 5 tap kmag = 0.25 */ double M02[6] = { 0.7286, 0.7305, 0.7312, 0.7323, 0.7323, 0.7312}; double Mx2[6] = {0.0010, 0.7616, 0.2270, -0.6077, -0.6077, 0.2270}; double My2[6] = {-0.0000, -0.0000, 0.7216, 0.4361, -0.4361, -0.7216}; double Mz2[6] = {0.8607, 0.3706, 0.3703, 0.3699, 0.3699, 0.3703}; double Mxx2[6] = { 1.2048,-1.4741, 0.9749,-0.5593,-0.5593, 0.9749}; double Myy2[6] = { 1.2043, 1.2167,-1.2321, 0.3024, 0.3024,-1.2321}; double Mzz2[6] = { -2.1358, 0.5305, 0.5301, 0.5295, 0.5295, 0.5301}; double Mxy2[6] = { -0.0000, 0.0000,-1.2283, 2.0323,-2.0323, 1.2283}; double Mxz2[6] = { -0.0397,-2.1228,-0.6533, 1.7218, 1.7218,-0.6533}; double Myz2[6] = { -0.0000, 0.0000,-2.0216,-1.2480, 1.2480, 2.0216}; /* 5 tap kmag = 0.10 */ double M05[6] = { 0.9517, 0.9517, 0.9517, 0.9518, 0.9518, 0.9517 }; double Mx5[6] = {0.0000, 1.4907, 0.4579, -1.2033, -1.2033, 0.4579}; double My5[6] = {-0.0000, 0.0000, 1.4169, 0.8725, -0.8725, -1.4169}; double Mz5[6] = {1.6694, 0.7418, 0.7417, 0.7417, 0.7417, 0.7417}; double Mxx5[6] = { 1.2048,-1.4741, 0.9749,-0.5593,-0.5593, 0.9749}; double Myy5[6] = { 1.2043, 1.2167,-1.2321, 0.3024, 0.3024,-1.2321}; double Mzz5[6] = { -2.1358, 0.5305, 0.5301, 0.5295, 0.5295, 0.5301}; double Mxy5[6] = { -0.0000, 0.0000,-1.2283, 2.0323,-2.0323, 1.2283}; double Mxz5[6] = { -0.0397,-2.1228,-0.6533, 1.7218, 1.7218,-0.6533}; double Myz5[6] = { -0.0000, 0.0000,-2.0216,-1.2480, 1.2480, 2.0216}; #else // FIVE_TAP // Matrix values for 7-tap filters //kmag = 0.5 double M01[VolumeFile::NALPHA] = {0.1250, 0.1355, 0.1391, 0.1450, 0.1450, 0.1391}; double Mx1[VolumeFile::NALPHA] = {0.0460, 1.2072, 0.3367, -0.9407, -0.9407, 0.3367}; double My1[VolumeFile::NALPHA] = {0.0000, -0.0000, 1.1375, 0.6586, -0.6586, -1.1375}; double Mz1[VolumeFile::NALPHA] = {1.4419, 0.6148, 0.5990, 0.5789, 0.5789, 0.5990}; double Mxx1[VolumeFile::NALPHA] = {-0.4021, -1.4259, -0.4345, -1.0266, -1.0266, -0.4345}; double Myy1[VolumeFile::NALPHA] = {-0.3991, -0.3644, -1.3160, -0.6614, -0.6614, -1.3160}; double Mzz1[VolumeFile::NALPHA] = {-1.5336, -0.4476, -0.4376, -0.4220, -0.4220, -0.4376}; double Mxy1[VolumeFile::NALPHA] = {0.0000, 0.0000, -0.5893, 1.0177, -1.0177, 0.5893}; double Mxz1[VolumeFile::NALPHA] = {0.0729, -0.9400, -0.1813, 0.9950, 0.9950, -0.1813}; double Myz1[VolumeFile::NALPHA] = {0.0000, -0.0000, -1.0269, -0.6126, 0.6126, 1.0269}; //kmag = 0.25 double Mx2[VolumeFile::NALPHA] = {0.0012, 0.5935, 0.1771, -0.4738, -0.4738, 0.1771}; double My2[VolumeFile::NALPHA] = {-0.0000, -0.0000, 0.5623, 0.3401, -0.3401, -0.5623}; double Mz2[VolumeFile::NALPHA] = {0.6709, 0.2897, 0.2893, 0.2888, 0.2888, 0.2893}; double M02[VolumeFile::NALPHA] = {0.6219, 0.6244, 0.6252, 0.6266, 0.6266, 0.6252}; double Mxx2[VolumeFile::NALPHA] = {0.6046, -0.6499, 0.4959, -0.2216, -0.2216, 0.4959}; double Myy2[VolumeFile::NALPHA] = {0.6044, 0.6093, -0.5365, 0.1811, 0.1811, -0.5365}; double Mzz2[VolumeFile::NALPHA] = {-0.9634, 0.2857, 0.2854, 0.2848, 0.2848, 0.2854}; double Mxy2[VolumeFile::NALPHA] = {0.0000, 0.0000, -0.6384, 1.0555, -1.0555, 0.6384}; double Mxz2[VolumeFile::NALPHA] = {-0.0221, -1.1053, -0.3410, 0.8928, 0.8928, -0.3410}; double Myz2[VolumeFile::NALPHA] = {-0.0000, 0.0000, -1.0508, -0.6482, 0.6482, 1.0508}; //kmag = 0.1 double M05[VolumeFile::NALPHA] = {0.9284, 0.9285, 0.9285, 0.9285, 0.9285, 0.9285}; double Mx5[VolumeFile::NALPHA] = {0.0001, 1.0187, 0.3129, -0.8223, -0.8223, 0.3129}; double My5[VolumeFile::NALPHA] = {-0.0000, -0.0000, 0.9682, 0.5962, -0.5962, -0.9682}; double Mz5[VolumeFile::NALPHA] = {1.1408, 0.5069, 0.5069, 0.5069, 0.5069, 0.5069}; double Mxx5[VolumeFile::NALPHA] = {2.4273, -3.3025, 1.8895, -1.3265, -1.3265, 1.8895}; double Myy5[VolumeFile::NALPHA] = {2.4273, 2.4319, -2.7601, 0.4560, 0.4560, -2.7601}; double Mzz5[VolumeFile::NALPHA] = {-4.7297, 0.9955, 0.9954, 0.9954, 0.9954, 0.9954}; double Mxy5[VolumeFile::NALPHA] = {-0.0000, 0.0000, -2.8244, 4.5867, -4.5867, 2.8244}; double Mxz5[VolumeFile::NALPHA] = {-0.0134, -4.8158, -1.4865, 3.9001, 3.9001, -1.4865}; double Myz5[VolumeFile::NALPHA] = {-0.0000, 0.0000, -4.5823, -2.8319, 2.8319, 4.5823}; #endif // FIVE_TAP #ifdef FIVE_TAP #define FILTSIZE 5 #else #define FILTSIZE 7 #endif /** * Constructor. */ BrainModelVolumeGradient::BrainModelVolumeGradient(BrainSet* bs, const int lambdaIn, const bool gradFlagIn, const bool maskingFlagIn, VolumeFile* volumeFileIn, VolumeFile* wholeMaskVolumeIn, SureFitVectorFile* gradFileIn) : BrainModelAlgorithm(bs) { lambda = lambdaIn; gradFlag = gradFlagIn; maskingFlag = maskingFlagIn; volumeFile = new VolumeFile(*volumeFileIn); wholeMaskVolume = new VolumeFile(*wholeMaskVolumeIn); gradFile = gradFileIn; } /** * Destructor. */ BrainModelVolumeGradient::~BrainModelVolumeGradient() { } /** * execute the algorithm. */ void BrainModelVolumeGradient::execute() throw (BrainModelAlgorithmException) { /* float N[NALPHA][3]; int i, j, k; float pi = 4*std::atan(1.0); float phi = 2*pi/5.0; float *Grad[4]; float *wholevolume, *volume, kmag; double R[NALPHA]; float Wnot; int jj; int CHUNK; float *WholeSinVolume[NALPHA]; char file2[256]; int cnt = 0; */ int nncol, nnrow, nnslices; volumeFile->getDimensions(nncol, nnrow, nnslices); //kmag = 0.5 double WMx1[NALPHA], WMy1[NALPHA], WMz1[NALPHA]; double WMxx1[NALPHA], WMyy1[NALPHA], WMzz1[NALPHA]; double WMxy1[NALPHA], WMxz1[NALPHA], WMyz1[NALPHA]; //kmag = 0.25 double WMx2[NALPHA], WMy2[NALPHA], WMz2[NALPHA]; double WMxx2[NALPHA], WMyy2[NALPHA], WMzz2[NALPHA]; double WMxy2[NALPHA], WMxz2[NALPHA], WMyz2[NALPHA]; //kmag = 0.1 double WMx5[NALPHA], WMy5[NALPHA], WMz5[NALPHA]; double WMxx5[NALPHA], WMyy5[NALPHA], WMzz5[NALPHA]; double WMxy5[NALPHA], WMxz5[NALPHA], WMyz5[NALPHA]; for (int i = 0; i < NALPHA; i++) { WMx1[i] = Mx1[i]; WMx2[i] = Mx2[i]; WMx5[i] = Mx5[i]; WMxx1[i] = Mxx1[i]; WMxx2[i] = Mxx2[i]; WMxx5[i] = Mxx5[i]; WMxy1[i] = Mxy1[i]; WMxy2[i] = Mxy2[i]; WMxy5[i] = Mxy5[i]; WMxz1[i] = Mxz1[i]; WMxz2[i] = Mxz2[i]; WMxz5[i] = Mxz5[i]; WMy1[i] = My1[i]; WMy2[i] = My2[i]; WMy5[i] = My5[i]; WMyy1[i] = Myy1[i]; WMyy2[i] = Myy2[i]; WMyy5[i] = Myy5[i]; WMyz1[i] = Myz1[i]; WMyz2[i] = Myz2[i]; WMyz5[i] = Myz5[i]; WMz1[i] = Mz1[i]; WMz2[i] = Mz2[i]; WMz5[i] = Mz5[i]; WMzz1[i] = Mzz1[i]; WMzz2[i] = Mzz2[i]; WMzz5[i] = Mzz5[i]; } if (DebugControl::getDebugOn()) { std::cout << "\t\tGrad " << maskingFlag << std::endl; } const int numVoxels = nncol * nnrow * nnslices; int cnt = 0; for (int i = 0; i < numVoxels; i++) { if (wholeMaskVolume->getVoxelWithFlatIndex(i) != 0) { cnt++; } } if (DebugControl::getDebugOn()) { std::cout << "\t\t\t" << cnt << " voxels turned on in mask" << std::endl; } const float kmag = M_PI / (2.0*lambda); if ((lambda != 1) && (lambda != 2) && (lambda != 5)){ std::cout << "Unrecognized lambda " << lambda << std::endl; throw BrainModelAlgorithmException("Unrecognized lambda"); } float Wnot = 0.0; switch (lambda){ case 1: for (int i = 0; i < NALPHA; i++) { Wnot += M01[i]; } break; case 2: for (int i = 0; i < NALPHA; i++) { Wnot += M02[i]; } break; case 5: for (int i = 0; i < NALPHA; i++) { Wnot += M05[i]; } break; default: throw BrainModelAlgorithmException("Unrecognized lambda"); } Wnot = Wnot/(float)NALPHA; if (DebugControl::getDebugOn()) { std::cout << "lambda " << lambda << ", kmag " << kmag << ", Wnot " << Wnot << ", FILTER " << FILTSIZE << std::endl; } // Apply to matrices switch (lambda){ case 1: for (int i = 0; i < NALPHA; i++){ WMx1[i] *= Wnot; WMy1[i] *= Wnot; WMz1[i] *= Wnot; WMxx1[i] *= Wnot; WMyy1[i] *= Wnot; WMzz1[i] *= Wnot; WMxy1[i] *= Wnot; WMxz1[i] *= Wnot; WMyz1[i] *= Wnot; } break; case 2: for (int i = 0; i < NALPHA; i++){ WMx2[i] *= Wnot; WMy2[i] *= Wnot; WMz2[i] *= Wnot; WMxx2[i] *= Wnot; WMyy2[i] *= Wnot; WMzz2[i] *= Wnot; WMxy2[i] *= Wnot; WMxz2[i] *= Wnot; WMyz2[i] *= Wnot; } break; case 5: for (int i = 0; i < NALPHA; i++){ WMx5[i] *= Wnot; WMy5[i] *= Wnot; WMz5[i] *= Wnot; WMxx5[i] *= Wnot; WMyy5[i] *= Wnot; WMzz5[i] *= Wnot; WMxy5[i] *= Wnot; WMxz5[i] *= Wnot; WMyz5[i] *= Wnot; } break; default: throw BrainModelAlgorithmException("Invalid lambda in VolumeFile::performGradient"); } //look_idx = 417; const int look_idx = -1; if (DebugControl::getDebugOn()) { std::cout << "Looking for " << look_idx << " in " << numVoxels << std::endl; for (int k = 0; k < nnslices; k++){ for (int j = 0; j < nnrow; j++){ for (int i = 0; i < nncol; i++){ const int idx1 = volumeFile->getVoxelDataIndex(i, j, k); if (look_idx == idx1) { std::cout << "here it is: " << i << " " << j << " " << k << "; " << idx1 << std::endl; } } } } } VolumeFile wholeVolume(*volumeFile); float N[NALPHA][3]; float phi = 2.0 * M_PI / 5.0; computeWaveVectors(N, kmag, phi); float* wholeSinVolume[NALPHA]; for (int i = 0; i < NALPHA; i++) { wholeSinVolume[i] = new float[numVoxels]; for (int j = 0; j < numVoxels; j++) { wholeSinVolume[i][j] = 0.0; } } for (int CHUNK = 0; CHUNK < 7; CHUNK++) { float *SinVolume[NALPHA]; float *CosVolume[NALPHA]; //%unsigned char maskvolume; const int ncol = nncol; const int nrow = nnrow; #define CHUNKLIKE #ifdef CHUNKLIKE int slice_range[2] = { 0, 0 }; if (CHUNK == 0){ slice_range[0] = 0; slice_range[1] = (1*nnslices)/7+FILTSIZE/2; } else if (CHUNK == 1){ slice_range[0] = (1*nnslices)/7-FILTSIZE/2; slice_range[1] = (2*nnslices)/7+FILTSIZE/2; } else if (CHUNK == 2){ slice_range[0] = (2*nnslices)/7-FILTSIZE/2; slice_range[1] = (3*nnslices)/7+FILTSIZE/2; } else if (CHUNK == 3){ slice_range[0] = (3*nnslices)/7-FILTSIZE/2; slice_range[1] = (4*nnslices)/7+FILTSIZE/2; } else if (CHUNK == 4){ slice_range[0] = (4*nnslices)/7-FILTSIZE/2; slice_range[1] = (5*nnslices)/7+FILTSIZE/2; } else if (CHUNK == 5){ slice_range[0] = (5*nnslices)/7-FILTSIZE/2; slice_range[1] = (6*nnslices)/7+FILTSIZE/2; } else{ slice_range[0] = (6*nnslices)/7-FILTSIZE/2; slice_range[1] = nnslices; } if ((slice_range[0] < 0) || (slice_range[0] > nnslices) || (slice_range[1] < 0) || (slice_range[1] > nnslices)) { std::ostringstream str; str << "SLICE RANGE OUT OF WHACK! " << slice_range[0] << " " << slice_range[1] << std::endl; throw BrainModelAlgorithmException(str.str().c_str()); } #else // CHUNKLIKE slice_range[0] = 0; slice_range[1] = nnslices; #endif // CHUNKLIKE const int nslices = slice_range[1] - slice_range[0] + 1; //%volume = new float[ncol*nrow*nslices]; //%if (masking == 1) //% maskvolume = new unsigned char[ncol*nrow*nslices]; VolumeFile volume(*volumeFile); VolumeFile maskVolume(*volumeFile); if (DebugControl::getDebugOn()) { std::cout << "\n**** Analyzing " << CHUNK << ": " << 0 << " " << ncol << "; " << 0 << " " << nrow << "; " << slice_range[0] << " " << slice_range[1] << std::endl; } for (int k = slice_range[0]; k < slice_range[1]; k++) { for (int j = 0; j < nnrow; j++) { for (int i = 0; i < nncol; i++) { /* int idx1 = volume.getVoxelDataIndex(i, j, (k-slice_range[0])); int idx2 = wholeVolume.getVoxelDataIndex (i, j, k); volume.setVoxelWithFlatIndex(idx1, wholeVolume.getVoxelWithFlatIndex(idx2)); if (maskingFlag) { maskVolume.setVoxelWithFlatIndex(idx1, wholeMaskVolume->getVoxelWithFlatIndex(idx2)); } */ volume.setVoxel(i, j, (k - slice_range[0]), 0, wholeVolume.getVoxel(i, j, k)); if (maskingFlag) { maskVolume.setVoxel(i, j, (k - slice_range[0]), 0, wholeMaskVolume->getVoxel(i, j, k)); } } } } gradientCosTable[0] = new float[ncol]; gradientCosTable[1] = new float[nrow]; gradientCosTable[2] = new float[nslices]; gradientSinTable[0] = new float[ncol]; gradientSinTable[1] = new float[nrow]; gradientSinTable[2] = new float[nslices]; for (int i = 0; i < NALPHA; i++) { SinVolume[i] = new float[ncol*nrow*nslices]; CosVolume[i] = new float[ncol*nrow*nslices]; for (int j = 0; j < ncol*nrow*nslices; j++){ CosVolume[i][j] = 0.0; SinVolume[i][j] = 0.0; } } // compute vector convolution field (or apply filter bank) // output is 6 volumes for cos and 6 volumes for sin for (int i = 0; i < NALPHA; i++) { const float t1 = std::pow(Wnot, 0.3333f); if (DebugControl::getDebugOn()) { std::cout << "\tCompute dodecahedral filtering for alpha = " << i << std::endl; } computeTables(N[i], ncol, nrow, nslices); mod3d(volume.getVoxelData(), CosVolume[i], SinVolume[i], ncol, nrow, nslices); #ifdef FIVE_TAP LPF_5(CosVolume[i], ncol, nrow, nslices, t1); LPF_5(SinVolume[i], ncol, nrow, nslices, t1); //printf ("LPF_5 Cos %f; %f %f %f\n", CosVolume[i][look_idx], N[i][0], N[i][1], N[i][2]); //printf ("LPF_5 Sin %f\n", SinVolume[i][look_idx]); //exit (-1); #else NormLPF_7(CosVolume[i], ncol, nrow, nslices, t1); NormLPF_7(SinVolume[i], ncol, nrow, nslices, t1); #endif demod3d(CosVolume[i], SinVolume[i], ncol, nrow, nslices); } { int kstart, kend; #ifdef CHUNKLIKE if (CHUNK == 0){ kstart = 0; kend = (1*nnslices)/7; } else if (CHUNK == 1){ kstart = (1*nnslices)/7; kend = (2*nnslices)/7; } else if (CHUNK == 2){ kstart = (2*nnslices)/7; kend = (3*nnslices)/7; } else if (CHUNK == 3){ kstart = (3*nnslices)/7; kend = (4*nnslices)/7; } else if (CHUNK == 4){ kstart = (4*nnslices)/7; kend = (5*nnslices)/7; } else if (CHUNK == 5){ kstart = (5*nnslices)/7; kend = (6*nnslices)/7; } else{ kstart = (6*nnslices)/7; kend = nnslices; } #else // CHUNKLIKE kstart = 0; kend = nnslices; #endif // CHUNKLIKE if (DebugControl::getDebugOn()) { std::cout << "Copy slab sine volume back into large volume: " << kstart << " to " << kend << "..." << std::endl; } for (int k = kstart; k < kend; k++) { if (DebugControl::getDebugOn()) { if ((k % 10) == 0) { std::cout << "\t" << k << " of " << slice_range[1] << std::endl; } } for (int j = 0; j < nnrow; j++) { for(int i = 0; i < nncol; i++) { for (int jj = 0; jj < NALPHA; jj++) { const int idx1 = volumeFile->getVoxelDataIndex(i, j, (k-slice_range[0])); const int idx2 = volumeFile->getVoxelDataIndex(i, j, k); wholeSinVolume[jj][idx2] = SinVolume[jj][idx1]; if (DebugControl::getDebugOn()) { if (idx2 == look_idx) { std::cout << "\t\there " << jj << " " << idx2 << ": " << i << " " << j << " " << k << " gets " << idx1 << " " << i << " " << j << " " << (k - slice_range[0]) << SinVolume[jj][idx1] << std::endl; } } } } } } } for (int i = 0; i < 3; i++){ delete[] gradientCosTable[i]; delete[] gradientSinTable[i]; } for (int i = 0; i < NALPHA; i++){ delete[] SinVolume[i]; delete[] CosVolume[i]; } //%if (masking == 1) //% delete[] maskvolume; //%delete[] volume; } // CHUNK //%delete[] wholevolume; if (gradFlag) { if (DebugControl::getDebugOn()) { std::cout << "Compute GRADIENT..." << std::endl; } const int numVox = nncol*nnrow*nnslices; for (int j = 0; j < numVox; j++) { gradFile->setVectorWithFlatIndex(j, 0.0, 0.0, 0.0); gradFile->setMagnitudeWithFlatIndex(j, 0.0); //%GradX[j] = 0.0; //%GradY[j] = 0.0; //%GradZ[j] = 0.0; //%GradMag[j] = 0.0; } float* Grad[4]; for (int i = 0; i < 3; i++){ Grad[i] = new float[numVox]; for (int j = 0; j < numVox; j++) { Grad[i][j] = 0.0; } } for (int i = 0; i < numVox; i++) { if (DebugControl::getDebugOn()) { if ((i % 500000) == 0) { std::cout << "\tGradient for node " << i << " of " << numVox << "; " << 100.0*((float)i/(float)(numVox)) << std::endl; } } if (((maskingFlag) && (wholeMaskVolume->getVoxelWithFlatIndex(i) != 0)) || (maskingFlag == false)) { double R[NALPHA]; for (int jj = 0; jj < NALPHA; jj++) { R[jj] = wholeSinVolume[jj][i]; } switch (lambda){ case 1: applyOddMatrix(i, R, Grad, WMx1, WMy1, WMz1); break; case 2: applyOddMatrix(i, R, Grad, WMx2, WMy2, WMz2); break; case 5: applyOddMatrix(i, R, Grad, WMx5, WMy5, WMz5); break; default: throw BrainModelAlgorithmException("Invalid lambda value."); } } // masking } for (int i = 0; i < NALPHA; i++) { delete[] wholeSinVolume[i]; } Grad[3] = new float[numVox]; for (int i = 0; i < numVox; i++) { float mag = Grad[0][i]*Grad[0][i] + Grad[1][i]*Grad[1][i] + Grad[2][i]*Grad[2][i]; if (mag > 0.0) { Grad[3][i] = std::sqrt(mag); for (int k = 0; k < 3; k++) { Grad[k][i] = Grad[k][i]/Grad[3][i]; } } else { Grad[3][i] = 0.0; } } //sprintf (file2, "%s.grad.vec", rootfile); //%sprintf (file2, "%s.vec", outfile); //%printf ("Write data to %s\n", file2); //%WriteRawVectorData (file2, Grad[0], Grad[1], Grad[2], //% Grad[3], nncol, nnrow, nnslices); for (int i = 0; i < numVox; i++) { gradFile->setVectorWithFlatIndex(i, Grad[0][i], Grad[1][i], Grad[2][i]); gradFile->setMagnitudeWithFlatIndex(i, Grad[3][i]); //%GradX[i] = Grad[0][i]; //%GradY[i] = Grad[1][i]; //%GradZ[i] = Grad[2][i]; //%GradMag[i] = Grad[3][i]; } for (int i = 0; i < 4; i++) { delete[] Grad[i]; } } // (grad_flag == 1) if (DebugControl::getDebugOn()) { std::cout << "Grad done..." << std::endl; } } /** * compute wave vectors. */ void BrainModelVolumeGradient::computeWaveVectors(float N[NALPHA][3], const float kmag, const float phi) { N[0][0] = 0.0; N[0][1] = 0.0; N[0][2] = kmag; for (int i = 0; i < 5; i++) { N[i+1][0] = 2*kmag* std::cos(i*phi)/ std::sqrt (5.0); N[i+1][1] = 2*kmag* std::sin(i*phi)/ std::sqrt (5.0); N[i+1][2] = kmag/std::sqrt (5.0); } if (DebugControl::getDebugOn()) { for (int i = 0; i < NALPHA; i++) { std::cout << "Direction cosine " << i << ": " << N[i][0] << " " << N[i][1] << " " << N[i][2] << std::endl; } } } /** * Compute some sin/cos tables */ void BrainModelVolumeGradient::computeTables(const float *N, const int ncol, const int nrow, const int nslices) { for (int i = 0; i < ncol; i++){ gradientCosTable[0][i] = std::cos(i*N[0]); gradientSinTable[0][i] = std::sin(i*N[0]); } for (int j = 0; j < nrow; j++){ gradientCosTable[1][j] = std::cos(j*N[1]); gradientSinTable[1][j] = std::sin(j*N[1]); } for (int k = 0; k < nslices; k++){ gradientCosTable[2][k] = std::cos(k*N[2]); //printf 2"TZ %d %f\n", k, cos (k*N[2])); gradientSinTable[2][k] = std::sin(k*N[2]); } } /** * Gradient function */ void BrainModelVolumeGradient::mod3d(float* voxels, float *Cos, float *Sin, const int ncol, const int nrow, const int nslices) { for (int k = 0; k < nslices; k++){ const float cz = gradientCosTable[2][k]; const float sz = gradientSinTable[2][k]; for (int j = 0; j < nrow; j++){ const float cy = gradientCosTable[1][j]; const float sy = gradientSinTable[1][j]; const float cyz = cy*cz - sy*sz; const float syz = sy*cz + cy*sz; for (int i = 0; i < ncol; i++){ const float cx = gradientCosTable[0][i]; const float sx = gradientSinTable[0][i]; const float cxyz = cx*cyz - sx*syz; const float sxyz = sx*cyz + cx*syz; const int idx = (j*ncol)+i+(k*ncol*nrow); Cos[idx] = cxyz * voxels[idx]; Sin[idx] = sxyz * voxels[idx]; /* if (idx == look_idx) printf ("idx %d: cxyz %f, sxyz %f, cos %f, sin %f, vol %f\n", idx, cxyz, sxyz, Cos[idx], Sin[idx], volume[idx]); */ } } } } /** * */ void BrainModelVolumeGradient::LPF_5(float* voxels, const int ncol, const int nrow, const int nslices, const float Wo) { float lpf_filter[5]; lpf_filter[0] = 1.0/16.0; lpf_filter[1] = 1.0/4.0; lpf_filter[2] = 3.0/8.0; lpf_filter[3] = 1.0/4.0; lpf_filter[4] = 1.0/16.0; for (int i = 0; i < 5; i++) { //printf ("Filter %d %f\n", i, lpf_filter[i]); lpf_filter[i] = lpf_filter[i] / Wo; //printf ("Filter %d %f\n", i, lpf_filter[i]); } //printf ("before lpf %f %f\n", volume[417], Wo); VolumeFile::seperableConvolve(ncol, nrow, nslices, voxels, lpf_filter); //printf ("after lpf %f %f\n", volume[417], Wo); } /** * */ /* void BrainModelVolumeGradient::seperableConvolve(int ncol, int nrow, int nslices, float *volume, float *filter) { int isize = ncol*nrow; //printf ("\tSeperableConvolve filtersize=%d\n", FSIZE); float* Result = new float[ncol*nrow*nslices]; float* TempSpace = new float[ncol*nrow*nslices]; float* voxel = volume; float* tempResult = Result; oneDimConvolve (voxel, tempResult, filter, 0, 1, ncol, nrow, nslices); //printf ("%d %f %f\n", idx, voxel[idx], tempResult[idx]); voxel = Result; tempResult = TempSpace; oneDimConvolve (voxel, tempResult, filter, 1, ncol, ncol, nrow, nslices); //printf ("%d %f %f\n", idx, voxel[idx], tempResult[idx]); voxel = TempSpace; tempResult = volume; oneDimConvolve (voxel, tempResult, filter, 2, isize, ncol, nrow, nslices); //printf ("%d %f %f\n", idx, voxel[idx], tempResult[idx]); delete[] Result; delete[] TempSpace; return; } */ /** * */ /* void BrainModelVolumeGradient::oneDimConvolve (float *voxel, float *tempResult, float *filter, const int dim, const int inc, const int ncol, const int nrow, const int nslices) { float p[FILTSIZE]; int cnt = 0; for (int k = 0; k < nslices; k++){ for (int j = 0; j < nrow; j++){ for (int i = 0; i < ncol; i++){ float* ip = voxel; if (dim == 0){ if (i == 0){ p[0] = *ip; p[1] = *ip; p[2] = *ip; p[3] = *(ip+inc); p[4] = *(ip+inc+inc); } else if (i == 1) { p[0] = *(ip-inc); p[1] = *(ip-inc); p[2] = *ip; p[3] = *(ip+inc); p[4] = *(ip+inc+inc); } else if (i == ncol-2) { p[0] = *(ip-inc-inc); p[1] = *(ip-inc); p[2] = *ip; p[3] = *(ip+inc); p[4] = *(ip+inc); } else if (i == ncol-1) { p[0] = *(ip-inc-inc); p[1] = *(ip-inc); p[2] = *ip; p[3] = *ip; p[4] = *ip; } else { p[0] = *(ip-inc-inc); p[1] = *(ip-inc); p[2] = *ip; p[3] = *(ip+inc); p[4] = *(ip+inc+inc); } } else if (dim == 1) { if (j == 0){ p[0] = *ip; p[1] = *ip; p[2] = *ip; p[3] = *(ip+inc); p[4] = *(ip+inc+inc); } else if (j == 1) { p[0] = *(ip-inc); p[1] = *(ip-inc); p[2] = *ip; p[3] = *(ip+inc); p[4] = *(ip+inc+inc); } else if (j == nrow-2) { p[0] = *(ip-inc-inc); p[1] = *(ip-inc); p[2] = *ip; p[3] = *(ip+inc); p[4] = *(ip+inc); } else if (j == nrow-1) { p[0] = *(ip-inc-inc); p[1] = *(ip-inc); p[2] = *ip; p[3] = *ip; p[4] = *ip; } else { p[0] = *(ip-inc-inc); p[1] = *(ip-inc); p[2] = *ip; p[3] = *(ip+inc); p[4] = *(ip+inc+inc); } } else if (dim == 2) { if (k == 0){ p[0] = *ip; p[1] = *ip; p[2] = *ip; p[3] = *(ip+inc); p[4] = *(ip+inc+inc); } else if (k == 1) { p[0] = *(ip-inc); p[1] = *(ip-inc); p[2] = *ip; p[3] = *(ip+inc); p[4] = *(ip+inc+inc); } else if (k == nslices-2) { p[0] = *(ip-inc-inc); p[1] = *(ip-inc); p[2] = *ip; p[3] = *(ip+inc); p[4] = *(ip+inc); } else if (k == nslices-1) { p[0] = *(ip-inc-inc); p[1] = *(ip-inc); p[2] = *ip; p[3] = *ip; p[4] = *ip; } else { p[0] = *(ip-inc-inc); p[1] = *(ip-inc); p[2] = *ip; p[3] = *(ip+inc); p[4] = *(ip+inc+inc); } } *tempResult = 0; for (int n = 0; n < FILTSIZE; n++){ *tempResult += filter[n]*p[n]; } tempResult++; voxel++; cnt++; } } } } */ /** * */ void BrainModelVolumeGradient::demod3d(float *Cos, float *Sin, const int ncol, int const nrow, const int nslices) { //%int i, j, k, idx; //%float cx, cy, cz; //%float sx, sy, sz; //%float cyz, syz, cxyz, sxyz; //%float rval, ival; //printf ("\t\tdemod3d %d %d %d\n", ncol, nrow, nslices); for (int k = 0; k < nslices; k++){ const float cz = gradientCosTable[2][k]; const float sz = gradientSinTable[2][k]; for (int j = 0; j < nrow; j++){ const float cy = gradientCosTable[1][j]; const float sy = gradientSinTable[1][j]; const float cyz = cy*cz - sy*sz; const float syz = sy*cz + cy*sz; for (int i = 0; i < ncol; i++){ const float cx = gradientCosTable[0][i]; const float sx = gradientSinTable[0][i]; const float cxyz = cx*cyz - sx*syz; const float sxyz = sx*cyz + cx*syz; const int idx = (j*ncol)+i+(k*ncol*nrow); const float rval = Cos[idx]; const float ival = Sin[idx]; Cos[idx] = (cxyz*rval) + (sxyz*ival); Sin[idx] = (-sxyz*rval) + (cxyz*ival); } } } } /** * */ void BrainModelVolumeGradient::applyOddMatrix(int idx, const double R[NALPHA], float *Grad[4], const double Mx[NALPHA], const double My[NALPHA], const double Mz[NALPHA]) { Grad[0][idx] = multRow(R, Mx); Grad[1][idx] = multRow(R, My); Grad[2][idx] = multRow(R, Mz); /*if (idx == 777534) printf ("%d: %f %f %f, %f %f %f %f %f %f\n", idx, Grad [0][idx], Grad [1][idx], Grad [2][idx], R [0], R [1], R [2], R [3], R [4], R [5]);*/ } /** * */ double BrainModelVolumeGradient::multRow(const double R[NALPHA], const double M[NALPHA]) { double ans = 0.0; for (int i = 0; i < NALPHA; i++) { ans += R[i] * M[i]; } return (ans); } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeFociUnprojector.h0000664000175000017500000000420211572067322026314 0ustar michaelmichael #ifndef __BRAIN_MODEL_VOLUME_FOCI_UNPROJECTOR_H__ #define __BRAIN_MODEL_VOLUME_FOCI_UNPROJECTOR_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelAlgorithm.h" class BrainModelSurface; class FociProjectionFile; /// class for setting the volume coordinates for foci class BrainModelVolumeFociUnprojector : public BrainModelAlgorithm { public: // constructor BrainModelVolumeFociUnprojector(BrainSet* bsIn, BrainModelSurface* leftSurfaceIn, BrainModelSurface* rightSurfaceIn, BrainModelSurface* cerebellumSurfaceIn, FociProjectionFile* fociProjectionFileIn); // destructor ~BrainModelVolumeFociUnprojector(); // execute the algorithm void execute() throw (BrainModelAlgorithmException); protected: /// the left surface BrainModelSurface* leftSurface; /// the right surface BrainModelSurface* rightSurface; /// the cerebellum surface BrainModelSurface* cerebellumSurface; /// the foci projection file FociProjectionFile* fociProjectionFile; }; #endif // __BRAIN_MODEL_VOLUME_FOCI_UNPROJECTOR_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeFociUnprojector.cxx0000664000175000017500000001335111572067322026674 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurface.h" #include "BrainModelVolumeFociUnprojector.h" #include "FociProjectionFile.h" /** * constructor. */ BrainModelVolumeFociUnprojector::BrainModelVolumeFociUnprojector(BrainSet* bsIn, BrainModelSurface* leftSurfaceIn, BrainModelSurface* rightSurfaceIn, BrainModelSurface* cerebellumSurfaceIn, FociProjectionFile* fociProjectionFileIn) : BrainModelAlgorithm(bsIn) { leftSurface = leftSurfaceIn; rightSurface = rightSurfaceIn; cerebellumSurface = cerebellumSurfaceIn; fociProjectionFile = fociProjectionFileIn; } /** * destructor. */ BrainModelVolumeFociUnprojector::~BrainModelVolumeFociUnprojector() { } /** * execute the algorithm. */ void BrainModelVolumeFociUnprojector::execute() throw (BrainModelAlgorithmException) { if ((leftSurface == NULL) && (rightSurface == NULL)) { throw BrainModelAlgorithmException("Both surfaces are invalid."); } if (fociProjectionFile == NULL) { throw BrainModelAlgorithmException("The foci projection file is invalid."); } const int numFoci = fociProjectionFile->getNumberOfCellProjections(); if (numFoci <= 0) { throw BrainModelAlgorithmException("The foci projection file contains no foci."); } // // Loop through the foci // for (int i = 0; i < numFoci; i++) { // // Get the focus // CellProjection* focus = fociProjectionFile->getCellProjection(i); // // Get the original position of the focus // float xyz[3]; focus->getXYZ(xyz); // // Determine which surface to use // bool leftFlag = false; bool rightFlag = false; bool cerebellumFlag = false; switch (focus->getCellStructure()) { case Structure::STRUCTURE_TYPE_CORTEX_LEFT: leftFlag = true; break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT: rightFlag = true; break; case Structure::STRUCTURE_TYPE_CEREBELLUM: cerebellumFlag = true; case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_LEFT: break; case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_RIGHT: break; case Structure::STRUCTURE_TYPE_CORTEX_LEFT_OR_CEREBELLUM: leftFlag = true; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT_OR_CEREBELLUM: rightFlag = true; break; case Structure::STRUCTURE_TYPE_CORTEX_BOTH: case Structure::STRUCTURE_TYPE_CEREBRUM_CEREBELLUM: case Structure::STRUCTURE_TYPE_SUBCORTICAL: case Structure::STRUCTURE_TYPE_ALL: case Structure::STRUCTURE_TYPE_INVALID: if (xyz[0] > 0.0) { rightFlag = true; } else if (xyz[0] < 0.0) { leftFlag = true; } break; } // // get projected position using appropriate surface // if (leftFlag && (leftSurface != NULL)) { float leftXYZ[3]; if (focus->getProjectedPosition(leftSurface->getCoordinateFile(), leftSurface->getTopologyFile(), leftSurface->getIsFiducialSurface(), leftSurface->getIsFlatSurface(), false, leftXYZ)) { xyz[0] = leftXYZ[0]; xyz[1] = leftXYZ[1]; xyz[2] = leftXYZ[2]; } } else if (rightFlag && (rightSurface != NULL)) { float rightXYZ[3]; if (focus->getProjectedPosition(rightSurface->getCoordinateFile(), rightSurface->getTopologyFile(), rightSurface->getIsFiducialSurface(), rightSurface->getIsFlatSurface(), false, rightXYZ)) { xyz[0] = rightXYZ[0]; xyz[1] = rightXYZ[1]; xyz[2] = rightXYZ[2]; } } else if (cerebellumFlag && (cerebellumSurface != NULL)) { if (focus->getProjectedPosition(cerebellumSurface->getCoordinateFile(), cerebellumSurface->getTopologyFile(), cerebellumSurface->getIsFiducialSurface(), cerebellumSurface->getIsFlatSurface(), false, xyz)) { } } // // Set the position of the focus in the volume // focus->setVolumeXYZ(xyz); } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeFociDensity.h0000664000175000017500000000443111572067322025425 0ustar michaelmichael #ifndef __BRAIN_MODEL_VOLUME_FOCI_DENSITY_H__ #define __BRAIN_MODEL_VOLUME_FOCI_DENSITY_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelAlgorithm.h" class FociProjectionFile; class VolumeFile; /// class for generating volume foci density class BrainModelVolumeFociDensity : public BrainModelAlgorithm { public: // type of density units enum DENSITY_UNITS { /// foci per cubic centimeter DENSITY_UNITS_FOCI_PER_CUBIC_CENTIMETER, /// foci per cubic millimeter DENSITY_UNITS_FOCI_PER_CUBIC_MILLIMETER }; // constructor BrainModelVolumeFociDensity(BrainSet* bsIn, const FociProjectionFile* fociProjectionFileIn, const float regionCubeSizeIn, const DENSITY_UNITS densityUnitsIn, VolumeFile* outputVolumeFileIn); // destructor ~BrainModelVolumeFociDensity(); // execute the algorithm void execute() throw (BrainModelAlgorithmException); protected: /// the foci projection file const FociProjectionFile* fociProjectionFile; /// the region cube size const float regionCubeSize; /// the density units const DENSITY_UNITS densityUnits; /// the output volume file VolumeFile* outputVolumeFile; }; #endif // __BRAIN_MODEL_VOLUME_FOCI_DENSITY_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeFociDensity.cxx0000664000175000017500000001450311572067322026001 0ustar michaelmichael #include "BrainModelVolumeFociDensity.h" #include "FociProjectionFile.h" #include "VolumeFile.h" /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelVolumeFociDensity.h" #include "FociProjectionFile.h" #include "VolumeFile.h" /** * constructor. */ BrainModelVolumeFociDensity::BrainModelVolumeFociDensity(BrainSet* bsIn, const FociProjectionFile* fociProjectionFileIn, const float regionCubeSizeIn, const DENSITY_UNITS densityUnitsIn, VolumeFile* outputVolumeFileIn) : BrainModelAlgorithm(bsIn), fociProjectionFile(fociProjectionFileIn), regionCubeSize(regionCubeSizeIn), densityUnits(densityUnitsIn), outputVolumeFile(outputVolumeFileIn) { } /** * destructor. */ BrainModelVolumeFociDensity::~BrainModelVolumeFociDensity() { } /** * execute the algorithm. */ void BrainModelVolumeFociDensity::execute() throw (BrainModelAlgorithmException) { // // Check dimensions // if (outputVolumeFile == NULL) { throw BrainModelAlgorithmException("The volume file is invalid"); } if (outputVolumeFile->getTotalNumberOfVoxels() <= 0) { throw BrainModelAlgorithmException("The volume contains no voxels."); } if (fociProjectionFile == NULL) { throw BrainModelAlgorithmException("The foci projection file is invalid"); } const int numFoci = fociProjectionFile->getNumberOfCellProjections(); if (numFoci <= 0) { throw BrainModelAlgorithmException("The foci projection file contains no foci."); } if (regionCubeSize <= 0.0) { throw BrainModelAlgorithmException("Region cube size is less than or equal to zero."); } // // Half the cube size // const float halfRegionCubeSize = regionCubeSize * 0.5; // // Set all voxels to zero // outputVolumeFile->setAllVoxels(0.0); // // Add units to comment // switch (densityUnits) { case DENSITY_UNITS_FOCI_PER_CUBIC_CENTIMETER: outputVolumeFile->appendToFileComment("\nUnits are number of foci per cubic centimeter."); break; case DENSITY_UNITS_FOCI_PER_CUBIC_MILLIMETER: outputVolumeFile->appendToFileComment("\nUnits are number of foci per cubic millimeter."); break; } // // Create progress dialog // createProgressDialog("Volume Foci Density", numFoci, "volumeFociDensity"); // // Loop through the foci // for (int n = 0; n < numFoci; n++) { // // Update progress dialog // const float pctComplete = (static_cast(n) / numFoci) * 100.0; const QString pctString(QString::number(pctComplete, 'f', 1) + "% complete."); updateProgressDialog(pctString); // // Get the stereotaxic coordinate // float focusXYZ[3]; fociProjectionFile->getCellProjection(n)->getVolumeXYZ(focusXYZ); if ((focusXYZ[0] != 0.0) || (focusXYZ[1] != 0.0) || (focusXYZ[2] != 0.0)) { // // place the ROI box at the focus and find its corners // const float minCornerXYZ[3] = { focusXYZ[0] - halfRegionCubeSize, focusXYZ[1] - halfRegionCubeSize, focusXYZ[2] - halfRegionCubeSize }; const float maxCornerXYZ[3] = { focusXYZ[0] + halfRegionCubeSize, focusXYZ[1] + halfRegionCubeSize, focusXYZ[2] + halfRegionCubeSize }; // // Get voxel indices containing corners // int minIJK[3], maxIJK[3]; outputVolumeFile->convertCoordinatesToVoxelIJK(minCornerXYZ, minIJK); outputVolumeFile->convertCoordinatesToVoxelIJK(maxCornerXYZ, maxIJK); // // Limit to valid indices // outputVolumeFile->clampVoxelIndex(minIJK); outputVolumeFile->clampVoxelIndex(maxIJK); // // Increment the voxels // for (int i = minIJK[0]; i <= maxIJK[0]; i++) { for (int j = minIJK[1]; j <= maxIJK[1]; j++) { for (int k = minIJK[2]; k <= maxIJK[2]; k++) { outputVolumeFile->setVoxel(i, j, k, 0, (outputVolumeFile->getVoxel(i, j, k) + 1)); } } } } } // // Scale to foci per mm^3 // int dim[3]; outputVolumeFile->getDimensions(dim); float voxelSize[3]; outputVolumeFile->getSpacing(voxelSize); float voxelVolume = voxelSize[0] * voxelSize[1] * voxelSize[2]; float regionCubeVolume = regionCubeSize * regionCubeSize * regionCubeSize; switch (densityUnits) { case DENSITY_UNITS_FOCI_PER_CUBIC_CENTIMETER: voxelVolume = voxelSize[0]/10.0 * voxelSize[1]/10.0 * voxelSize[2]/10.0; //regionCubeVolume = regionCubeSize/10.0 * regionCubeSize/10.0 * regionCubeSize/10.0; break; case DENSITY_UNITS_FOCI_PER_CUBIC_MILLIMETER: break; } float mm3voxel = regionCubeVolume * voxelVolume; for (int i = 0; i < dim[0]; i++) { for (int j = 0; j < dim[1]; j++) { for (int k = 0; k < dim[2]; k++) { outputVolumeFile->setVoxel(i, j, k, 0, (outputVolumeFile->getVoxel(i, j, k) / mm3voxel)); } } } removeProgressDialog(); } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeCrossoverHandleFinder.h0000664000175000017500000000652411572067322027443 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __BRAIN_MODEL_VOLUME_CROSSOVER_HANDLE_FINDER_H__ #define __BRAIN_MODEL_VOLUME_CROSSOVER_HANDLE_FINDER_H__ #include #include #include "BrainModelAlgorithm.h" #include "BrainModelVolumeTopologicalError.h" class BrainSet; #include "VolumeFile.h" /// class that finds handles in a binary volume class BrainModelVolumeCrossoverHandleFinder : public BrainModelAlgorithm { public: /// status result enum STATUS { /// no handles STATUS_NO_HANDLES, /// has handles STATUS_HAS_HANDLES }; /// Constructor BrainModelVolumeCrossoverHandleFinder(BrainSet* bs, const VolumeFile* segmentationIn, const bool addHandlesVolumeToBrainSetIn, const bool rgbPaintSurfaceHandlesIn); /// Destructor ~BrainModelVolumeCrossoverHandleFinder(); /// execute the algorithm virtual void execute() throw (BrainModelAlgorithmException); /// get the result status STATUS getResultStatus() const { return status; } /// get the number of handles found int getNumberOfHandles() const { return handlesFound.size(); } /// get the information about a handle const BrainModelVolumeTopologicalError* getHandleInfo(const int handleNumber) const { return &handlesFound[handleNumber]; } private: /// highlight handles in the surface using RGB Paint void highlightHandlesInSurface(); /// create a list of the handles in voxel IJK void createVoxelHandleList(); /// result status STATUS status; /// brain volume for searching for handles VolumeFile* segmentationVolume; /// crossovers volume VolumeFile* crossoversVolume; /// brain volume showing handles VolumeFile* handlesRgbVolume; /// x dimensions of volume int volumeDimX; /// x dimensions of volume int volumeDimY; /// x dimensions of volume int volumeDimZ; /// keeps track of handles that are found std::vector handlesFound; /// create the handles volume bool addHandlesVolumeToBrainSet; /// paint nodes around handles with rgb paint file bool rgbPaintSurfaceHandles; }; #endif // __BRAIN_MODEL_VOLUME_CROSSOVER_HANDLE_FINDER_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeCrossoverHandleFinder.cxx0000664000175000017500000003202511572067322030011 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainModelSurface.h" #include "BrainModelVolume.h" #include "BrainModelVolumeCrossoverHandleFinder.h" #include "BrainModelVolumeToSurfaceConverter.h" #include "BrainSetNodeAttribute.h" #include "BrainSet.h" #include "DebugControl.h" #include "FileUtilities.h" #include "RgbPaintFile.h" #include "TopologyFile.h" #include "TopologyHelper.h" #include "VolumeFile.h" /** * Constructor. */ BrainModelVolumeCrossoverHandleFinder::BrainModelVolumeCrossoverHandleFinder(BrainSet* bs, const VolumeFile* segmentationIn, const bool addHandlesVolumeToBrainSetIn, const bool rgbPaintSurfaceHandlesIn) : BrainModelAlgorithm(bs) { segmentationVolume = new VolumeFile(*segmentationIn); handlesRgbVolume = NULL; crossoversVolume = NULL; addHandlesVolumeToBrainSet = addHandlesVolumeToBrainSetIn; rgbPaintSurfaceHandles = rgbPaintSurfaceHandlesIn; } /** * Destructor */ BrainModelVolumeCrossoverHandleFinder::~BrainModelVolumeCrossoverHandleFinder() { if (crossoversVolume != NULL) { delete crossoversVolume; crossoversVolume = NULL; } if (segmentationVolume != NULL) { delete segmentationVolume; segmentationVolume = NULL; } } /** * execute the algorithm */ void BrainModelVolumeCrossoverHandleFinder::execute() throw (BrainModelAlgorithmException) { handlesFound.clear(); status = STATUS_HAS_HANDLES; // // Remove any islands in the segmentation // segmentationVolume->removeIslandsFromSegmentation(); // // Generate a surface // BrainSet bs; BrainModelVolumeToSurfaceConverter bmvsc(&bs, segmentationVolume, BrainModelVolumeToSurfaceConverter::RECONSTRUCTION_MODE_SUREFIT_SURFACE, false, true, false); try { bmvsc.execute(); } catch (BrainModelAlgorithmException& e) { throw BrainModelAlgorithmException("ERROR: Unable to generate a temporary surface\n" + e.whatQString()); } // // Find the fiducial surface created by surface generation // BrainModelSurface* fiducialBMS = bs.getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_FIDUCIAL); if (fiducialBMS == NULL) { throw BrainModelAlgorithmException("ERROR: unable to find the temporary fiducial surface."); } // // Get the topology file // TopologyFile* fiducialTF = fiducialBMS->getTopologyFile(); if (fiducialTF == NULL) { throw BrainModelAlgorithmException("ERROR: unable to find the temporary topology file."); } // // Remove islands // fiducialTF->disconnectIslands(); // // Generate an euler count // int faces, vertices, edges, eulerCount, numHoles, numObjects; fiducialTF->getEulerCount(false, faces, vertices, edges, eulerCount, numHoles, numObjects); // // Euler count is 2 for a topologically correct closed surface // if (eulerCount == 2) { status = STATUS_NO_HANDLES; return; } // // Smooth into a sphere DO NOT DELETE SINCE PART OF BRAIN SET // BrainModelSurface* sphereSurface = new BrainModelSurface(*fiducialBMS); bs.addBrainModel(sphereSurface); sphereSurface->translateToCenterOfMass(); sphereSurface->convertToSphereWithSurfaceArea(); sphereSurface->arealSmoothing(1.0, 1000, 0, NULL, 10); if (DebugControl::getDebugOn()) { try { sphereSurface->getCoordinateFile()->writeFile("crossover_sphere.coord"); sphereSurface->getTopologyFile()->writeFile("crossover_sphere.topo"); } catch (FileException&) { } } // // Do crossover check // int tileCrossovers = 0; int nodeCrossovers = 0; sphereSurface->crossoverCheck(tileCrossovers, nodeCrossovers, BrainModelSurface::SURFACE_TYPE_SPHERICAL); if (nodeCrossovers == 0) { status = STATUS_NO_HANDLES; return; } // // Create the crossovers volume // crossoversVolume = new VolumeFile(*segmentationVolume); crossoversVolume->setAllVoxels(0.0); crossoversVolume->setFileComment("Crossovers"); // // Set voxels that contain a crossover using fiducial surface // const int numNodes = fiducialBMS->getNumberOfNodes(); const CoordinateFile* fiducialCoords = fiducialBMS->getCoordinateFile(); for (int i = 0; i < numNodes; i++) { BrainSetNodeAttribute* bna = bs.getNodeAttributes(i); if (bna->getCrossover() == BrainSetNodeAttribute::CROSSOVER_YES) { const float* xyz = fiducialCoords->getCoordinate(i); int ijk[3]; if (crossoversVolume->convertCoordinatesToVoxelIJK(xyz, ijk)) { crossoversVolume->setVoxel(ijk, 0, 255.0); } } } if (DebugControl::getDebugOn()) { try { crossoversVolume->writeFile("crossovers_volume.nii"); } catch (FileException&) { } } // // If surface should be painted around the handles with rgb paint // if (rgbPaintSurfaceHandles) { highlightHandlesInSurface(); } // // Dilate the crossovers volume a little bit // crossoversVolume->doVolMorphOps(1, 0); // // Find objects in crossovers volume (the approximate handles) // createVoxelHandleList(); // // Add handles volume to brain set if requested // if (addHandlesVolumeToBrainSet && (brainSet != NULL)) { // // Get information about the input volume // int dim[3]; segmentationVolume->getDimensions(dim); float origin[3]; segmentationVolume->getOrigin(origin); float spacing[3]; segmentationVolume->getSpacing(spacing); VolumeFile::ORIENTATION orientation[3]; segmentationVolume->getOrientation(orientation); // // Create the handles volume // handlesRgbVolume = new VolumeFile; handlesRgbVolume->initialize(VolumeFile::VOXEL_DATA_TYPE_RGB_VOXEL_INTERLEAVED, dim, orientation, origin, spacing); // // Dimensions of input volume // volumeDimX = dim[0]; volumeDimY = dim[1]; volumeDimZ = dim[2]; // // copy the handles found along each axis into the handles volume // for (int k = 0; k < volumeDimZ; k++) { for (int i = 0; i < volumeDimX; i++) { for (int j = 0; j < volumeDimY; j++) { const int ijk[3] = { i, j, k }; if (crossoversVolume->getVoxel(ijk) != 0.0) { handlesRgbVolume->setVoxel(ijk, 0, 255.0); handlesRgbVolume->setVoxel(ijk, 1, 0.0); handlesRgbVolume->setVoxel(ijk, 2, 255.0); } else { handlesRgbVolume->setVoxel(ijk, 0, 0.0); handlesRgbVolume->setVoxel(ijk, 1, 0.0); handlesRgbVolume->setVoxel(ijk, 2, 0.0); } } } } const QString directory = FileUtilities::dirname(segmentationVolume->getFileName()); const QString filename = FileUtilities::basename(segmentationVolume->getFileName()); if (filename.isEmpty() == false) { QString s(directory); if (s.isEmpty() == false) { s.append("/"); } s.append("handles_"); s.append(filename); handlesRgbVolume->setFileName(s); } handlesRgbVolume->clearModified(); brainSet->addVolumeFile(VolumeFile::VOLUME_TYPE_RGB, handlesRgbVolume, handlesRgbVolume->getFileName(), true, false); } } /** * create a list of the handles in voxel IJK. */ void BrainModelVolumeCrossoverHandleFinder::createVoxelHandleList() { // // Find the objects in the crossovers volume // std::vector crossoverHandles; crossoversVolume->findObjectsWithinSegmentationVolume(crossoverHandles); // // Loop through the objects in the crossovers volume // const int num = static_cast(crossoverHandles.size()); for (int i = 0; i < num; i++) { const VolumeFile::VoxelGroup& vg = crossoverHandles[i]; const int numVoxels = vg.getNumberOfVoxels(); // // Find center of gravity of voxel IJKs // int ii = 0, jj = 0, kk = 0; for (int j = 0; j < numVoxels; j++) { const VoxelIJK voxelIJK = vg.getVoxel(j); ii += voxelIJK.getI(); jj += voxelIJK.getJ(); kk += voxelIJK.getK(); } ii /= numVoxels; jj /= numVoxels; kk /= numVoxels; const int ijk[3] = { ii, jj, kk }; BrainModelVolumeTopologicalError h(ijk, numVoxels); handlesFound.push_back(h); } } /** * Highlight nodes in the surface around the handles. */ void BrainModelVolumeCrossoverHandleFinder::highlightHandlesInSurface() { // // Find the active fiducial surface // BrainModelSurface* fiducialSurface = brainSet->getActiveFiducialSurface(); if (fiducialSurface == NULL) { return; } // // Get the Coordinate file // CoordinateFile* cf = fiducialSurface->getCoordinateFile(); const int numCoords = cf->getNumberOfCoordinates(); if (numCoords <= 0) { return; } // // Get pointer to voxels // int dim[3]; crossoversVolume->getDimensions(dim); if ((dim[0] <= 0) || (dim[1] <= 0) || (dim[2] <= 0)) { return; } // // Get the RGB Paint File // RgbPaintFile* rgbFile = brainSet->getRgbPaintFile(); // // Find/Create Handles column // const QString columnName("Handles"); int columnNumber = rgbFile->getColumnWithName(columnName); if ((columnNumber < 0) || (columnNumber >= rgbFile->getNumberOfColumns())) { if (rgbFile->getNumberOfColumns() == 0) { rgbFile->setNumberOfNodesAndColumns(numCoords, 1); } else { rgbFile->addColumns(1); } columnNumber = rgbFile->getNumberOfColumns() - 1; } rgbFile->setColumnName(columnNumber, columnName); bool* handlesFlag = new bool[numCoords]; // // See if node is around a handle // for (int i = 0; i < numCoords; i++) { float xyz[3]; cf->getCoordinate(i, xyz); handlesFlag[i] = false; int ijk[3]; float pcoords[3]; if (crossoversVolume->convertCoordinatesToVoxelIJK(xyz, ijk, pcoords)) { if (crossoversVolume->getVoxel(ijk, 0) != 0.0) { handlesFlag[i] = true; } } } // // Get a topology helper for the fiducial surface to access neighbors // const TopologyFile* tf = fiducialSurface->getTopologyFile(); const TopologyHelper* th = tf->getTopologyHelper(false, true, false); // // Highlight nodes that are neighbors of nodes marked has handles // bool* handlesFlag2 = new bool[numCoords]; const int neighborDepth = 2; for (int k = 0; k < neighborDepth; k++) { for (int i = 0; i < numCoords; i++) { handlesFlag2[i] = handlesFlag[i]; } for (int i = 0; i < numCoords; i++) { if (handlesFlag[i]) { int numNeighbors = 0; const int* neighbors = th->getNodeNeighbors(i, numNeighbors); for (int j = 0; j < numNeighbors; j++) { handlesFlag2[neighbors[j]] = true; } } } for (int i = 0; i < numCoords; i++) { handlesFlag[i] = handlesFlag2[i]; } } for (int i = 0; i < numCoords; i++) { if (handlesFlag[i]) { rgbFile->setRgb(i, columnNumber, 255.0, 0.0, 255.0); } else { rgbFile->setRgb(i, columnNumber, 0.0, 0.0, 0.0); } } rgbFile->clearModified(); delete[] handlesFlag; delete[] handlesFlag2; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeBiasCorrection.h0000664000175000017500000000552511572067322026120 0ustar michaelmichael #ifndef __BRAIN_MODEL_VOLUME_BIAS_CORRECTION_H__ #define __BRAIN_MODEL_VOLUME_BIAS_CORRECTION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifdef HAVE_ITK #include "itkArray.h" #endif // HAVE_ITK #include "BrainModelAlgorithm.h" #include "VolumeITKImage.h" class VolumeFile; /// class for performing bias correction on a volume file class BrainModelVolumeBiasCorrection : public BrainModelAlgorithm { public: // constructor BrainModelVolumeBiasCorrection(VolumeFile* vf, const float grayWhiteValuesIn[4], const float lowerUpperThresholdsIn[2], const int axisIterationsIn[3]); // destructor ~BrainModelVolumeBiasCorrection(); // execute the algorithm void execute() throw (BrainModelAlgorithmException); protected: #ifdef HAVE_ITK // perform the bias correction void biasCorrection(VolumeITKImage::ImagePointer& input, VolumeITKImage::ImagePointer& output, const int sliceDirection, const bool useLog); /// determine means and variance void meansVariance(const bool useLog); /// energy function computation void energyFunctions() const; /// remove edges void remove_edges(VolumeITKImage::ImagePointer input, VolumeITKImage::ImagePointer& NoEdgeImage); /// means of gray and white itk::Array classMeans; /// variance of gray and white itk::Array classSigmas; #endif // HAVE_ITK /// the volume VolumeFile* volumeFile; /// gray and white ranges float grayWhiteValues[4]; /// iterations for each axis int axisIterations[3]; /// lower and upper thresholds float lowerUpperThresholds[2]; }; #endif // __BRAIN_MODEL_VOLUME_BIAS_CORRECTION_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolumeBiasCorrection.cxx0000664000175000017500000003552511572067322026476 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ /*========================================================================= Program: Insight Segmentation & Registration Toolkit Module: $RCSfile: BrainModelVolumeBiasCorrection.cxx,v $ Language: C++ Date: $Date: 2009/04/09 15:50:54 $ Version: $Revision: 1.1.1.1 $ Copyright (c) 2002 Insight Consortium. All rights reserved. See ITKCopyright.txt or http://www.itk.org/HTML/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 notices for more information. =========================================================================*/ // // This code adapted from the ITK Application "BiasCorrector.cxx". // #include #include #include #include #include #include "BrainModelVolumeBiasCorrection.h" #include "DebugControl.h" #include "StatisticDataGroup.h" #include "StatisticMeanAndDeviation.h" #include "VolumeFile.h" #ifdef HAVE_ITK #include "itkCompositeValleyFunction.h" #include "itkMRIBiasFieldCorrectionFilter.h" #include "itkMinimumMaximumImageCalculator.h" #include "itkBinaryThresholdImageFilter.h" #include "itkImageRegionIterator.h" #include "itkZeroCrossingBasedEdgeDetectionImageFilter.h" #include "itkBinaryBallStructuringElement.h" #include "itkBinaryCrossStructuringElement.h" #include "itkBinaryDilateImageFilter.h" #include "itkMaskImageFilter.h" #include "itkCastImageFilter.h" #include "itkIndent.h" #include "itkHistogram.h" #include "vnl/vnl_math.h" typedef unsigned char MaskPixelType; typedef itk::Image MaskType; typedef MaskType::Pointer MaskPointer; typedef itk::MRIBiasFieldCorrectionFilter Corrector ; #endif // HAVE_ITK /** * constructor. */ BrainModelVolumeBiasCorrection::BrainModelVolumeBiasCorrection(VolumeFile* vf, const float grayWhiteValuesIn[4], const float lowerUpperThresholdsIn[2], const int axisIterationsIn[3]) : BrainModelAlgorithm(NULL) { volumeFile = vf; grayWhiteValues[0] = grayWhiteValuesIn[0]; grayWhiteValues[1] = grayWhiteValuesIn[1]; grayWhiteValues[2] = grayWhiteValuesIn[2]; grayWhiteValues[3] = grayWhiteValuesIn[3]; lowerUpperThresholds[0] = lowerUpperThresholdsIn[0]; lowerUpperThresholds[1] = lowerUpperThresholdsIn[1]; axisIterations[0] = axisIterationsIn[0]; axisIterations[1] = axisIterationsIn[1]; axisIterations[2] = axisIterationsIn[2]; } /** * destructor. */ BrainModelVolumeBiasCorrection::~BrainModelVolumeBiasCorrection() { } #ifdef HAVE_ITK void BrainModelVolumeBiasCorrection::remove_edges(VolumeITKImage::ImagePointer input, VolumeITKImage::ImagePointer& NoEdgeImage) { const int Dimension = 3; typedef itk::ZeroCrossingBasedEdgeDetectionImageFilter zeroCrossFilterType; typedef itk::CastImageFilter< VolumeITKImage::ImageTypeFloat3, MaskType> castFilterType; typedef itk::MaskImageFilter< VolumeITKImage::ImageTypeFloat3,MaskType, VolumeITKImage::ImageTypeFloat3 > maskFilterType; //typedef itk::BinaryBallStructuringElement StructuringElementType; typedef itk::BinaryCrossStructuringElement StructuringElementType; typedef itk::BinaryDilateImageFilter dilateFilterType; typedef itk::BinaryThresholdImageFilter< MaskType, MaskType> BinaryThresholdType; double variance[3]; variance[0] = 2.5; variance[1] = 2.5; variance[2] = 2.5; //std::cout << " edge detection" << std::endl; zeroCrossFilterType::Pointer edgeFilter = zeroCrossFilterType::New(); edgeFilter->SetInput(input); edgeFilter->SetVariance(variance); edgeFilter->Update(); castFilterType::Pointer convFilter = castFilterType::New(); convFilter->SetInput(edgeFilter->GetOutput()); convFilter->Update(); StructuringElementType structuringElement; int ballSize = 1; structuringElement.SetRadius( ballSize ); structuringElement.CreateStructuringElement( ); // //std::cout << "dilate edge image" << std::endl; dilateFilterType::Pointer dilateFilter = dilateFilterType::New(); dilateFilter->SetInput(convFilter->GetOutput()); dilateFilter->SetDilateValue (1); dilateFilter->SetKernel( structuringElement ); dilateFilter->Update(); const int MaskValue = 1; const int NoMaskValue = 0; //std::cout << "invert edge image" << std::endl; // Not Operation on Image -> select places where there is NO Edge BinaryThresholdType::Pointer NotFilter = BinaryThresholdType::New(); //NotFilter->SetInput(convFilter->GetOutput()); NotFilter->SetInput(dilateFilter->GetOutput()); NotFilter->SetOutsideValue(MaskValue); NotFilter->SetInsideValue(NoMaskValue); NotFilter->SetUpperThreshold(255); NotFilter->SetLowerThreshold(1); NotFilter->Update(); //std::cout << "mask with inverted edge image" << std::endl; /** masking of the input image with the inverted&dilated edge image */ maskFilterType::Pointer maskFilter = maskFilterType::New(); maskFilter->SetInput1(input); maskFilter->SetInput2(NotFilter->GetOutput()); maskFilter->Update(); NoEdgeImage = maskFilter->GetOutput(); } #endif // HAVE_ITK #ifdef HAVE_ITK void BrainModelVolumeBiasCorrection::biasCorrection(VolumeITKImage::ImagePointer& input, VolumeITKImage::ImagePointer& output, const int sliceDirection, const bool useLog) { // load images MaskPointer inputMask ; MaskPointer outputMask ; typedef itk::BinaryThresholdImageFilter< VolumeITKImage::ImageTypeFloat3, MaskType> threshFilterType; static const int TRESH_VAL = 1; static const int BG_VAL = 0; int degree = 3; std::vector InclassMeans ; std::vector InclassSigmas ; int volumeMaximumIteration = axisIterations[sliceDirection]; // jwh 200; int interSliceMaximumIteration = 200; // jwh 200; double initialRadius = 1.01; double growth = 1.05; double shrink = pow(growth, -0.25); bool usingSlabIdentification = false; bool useIntersliceCorrection = false; // // Bias corrector filter // Corrector::Pointer filter = Corrector::New() ; filter->SetInput(input) ; // // Create Output Mask // threshFilterType::Pointer threshFilter1 = threshFilterType::New(); threshFilter1->SetInput(input); threshFilter1->SetUpperThreshold(lowerUpperThresholds[1]); // 32000); threshFilter1->SetLowerThreshold(lowerUpperThresholds[0]); // percVal + 1); threshFilter1->SetOutsideValue( BG_VAL ); threshFilter1->SetInsideValue( TRESH_VAL ); threshFilter1->Update(); outputMask = threshFilter1->GetOutput() ; // // Create input mask // VolumeITKImage::ImagePointer NoEdgeImage ; remove_edges(input, NoEdgeImage); threshFilterType::Pointer threshFilter = threshFilterType::New(); threshFilter->SetInput(NoEdgeImage); threshFilter->SetUpperThreshold(lowerUpperThresholds[1]); // 32000 ); threshFilter->SetLowerThreshold(lowerUpperThresholds[0]); // percVal + 1 ); threshFilter->SetOutsideValue( BG_VAL ); threshFilter->SetInsideValue( TRESH_VAL ); threshFilter->Update(); inputMask = threshFilter->GetOutput() ; // // Set intputs and run the filter // if (DebugControl::getDebugOn()) { filter->DebugOn() ; } filter->SetOutputMask(outputMask) ; filter->SetInputMask(inputMask) ; filter->IsBiasFieldMultiplicative(useLog) ; filter->SetTissueClassStatistics(classMeans, classSigmas) ; filter->SetOptimizerGrowthFactor(growth) ; filter->SetOptimizerShrinkFactor(shrink) ; filter->SetVolumeCorrectionMaximumIteration(volumeMaximumIteration) ; filter->SetInterSliceCorrectionMaximumIteration(interSliceMaximumIteration) ; filter->SetOptimizerInitialRadius(initialRadius) ; filter->SetBiasFieldDegree(degree) ; filter->SetUsingSlabIdentification(usingSlabIdentification) ; filter->SetUsingInterSliceIntensityCorrection(useIntersliceCorrection) ; filter->SetSlicingDirection(sliceDirection) ; filter->SetUsingBiasFieldCorrection(true) ; filter->SetGeneratingOutput(true) ; filter->Update() ; // // Get output of filter // output = filter->GetOutput(); if (DebugControl::getDebugOn()) { std::cout << " coefficients :" ; Corrector::BiasFieldType::CoefficientArrayType coefficients = filter->GetEstimatedBiasFieldCoefficients() ; Corrector::BiasFieldType::CoefficientArrayType::iterator iter = coefficients.begin() ; while (iter != coefficients.end()) { std::cout << *iter << " " ; iter++ ; } std::cout << std::endl ; } } #endif // HAVE_ITK #ifdef HAVE_ITK /** * Do energy function */ void BrainModelVolumeBiasCorrection::energyFunctions() const { if (DebugControl::getDebugOn()) { typedef itk::CompositeValleyFunction EnergyFunction ; int interval = 100; EnergyFunction energy(classMeans, classSigmas) ; double higher = energy.GetUpperBound() ; double lower = energy.GetLowerBound() ; long noOfSamples = energy.GetNumberOfSamples() ; double TableInc = (double) ((higher - lower) / (noOfSamples - 1)); std::ofstream fout("energy.txt"); double d = lower; std::cout << "intensity\tenergy" << std::endl ; int i = 0 ; while(i < noOfSamples) { std::cout << d << "\t" << energy(d) << std::endl ; fout << d << "," << energy(d) << std::endl ; i += interval ; d += TableInc * interval ; } fout.close(); } } #endif // HAVE_ITK #ifdef HAVE_ITK /** * determine means and variance. */ void BrainModelVolumeBiasCorrection::meansVariance(const bool useLog) { std::vector grayVoxels, whiteVoxels; const int numVoxels = volumeFile->getTotalNumberOfVoxels(); for (int m = 0; m < numVoxels; m++) { const float v = volumeFile->getVoxelWithFlatIndex(m); if ((v >= grayWhiteValues[0]) && (v <= grayWhiteValues[1])) { grayVoxels.push_back(v); } if ((v >= grayWhiteValues[2]) && (v <= grayWhiteValues[3])) { whiteVoxels.push_back(v); } } // // Mean and deviation of gray // StatisticDataGroup sdgGray(&grayVoxels, StatisticDataGroup::DATA_STORAGE_MODE_POINT); StatisticMeanAndDeviation smdGray; smdGray.addDataGroup(&sdgGray); try { smdGray.execute(); } catch (StatisticException&) { } const float grayMean = smdGray.getMean(); const float grayVar = smdGray.getStandardDeviation(); // // Mean and deviation of white // StatisticDataGroup sdgWhite(&whiteVoxels, StatisticDataGroup::DATA_STORAGE_MODE_POINT); StatisticMeanAndDeviation smdWhite; smdWhite.addDataGroup(&sdgWhite); try { smdWhite.execute(); } catch (StatisticException&) { } const float whiteMean = smdWhite.getMean(); const float whiteVar = smdWhite.getStandardDeviation(); if (DebugControl::getDebugOn()) { std::cout << "Gray (mean, var): " << grayMean << ", " << grayVar << std::endl; std::cout << "White (mean, var): " << whiteMean << ", " << whiteVar << std::endl; } classMeans.SetSize(2); classSigmas.SetSize(2); classMeans[0] = grayMean; classMeans[1] = whiteMean; classSigmas[0] = grayVar; classSigmas[1] = whiteVar; if (useLog) { for (unsigned int i = 0 ; i < classMeans.size() ; i++) { classSigmas[i] = log(1.0 + classSigmas[i] / (classMeans[i] + 1.0)) ; classMeans[i] = log(classMeans[i] + 1.0) ; } } } #endif // HAVE_ITK /** * execute the algorithm. */ void BrainModelVolumeBiasCorrection::execute() throw (BrainModelAlgorithmException) { #ifdef HAVE_ITK if (volumeFile == NULL) { throw BrainModelAlgorithmException("Input volume is invalid (NULL)."); } try { const bool useLog = false; meansVariance(useLog); energyFunctions(); VolumeITKImage image; volumeFile->convertToITKImage(image); if (axisIterations[2] > 0) { VolumeITKImage imageOut; biasCorrection(image.image, imageOut.image, 2, useLog); image.image = imageOut.image; } if (axisIterations[0] > 0) { VolumeITKImage imageOut; biasCorrection(image.image, imageOut.image, 0, useLog); image.image = imageOut.image; } if (axisIterations[1] > 0) { VolumeITKImage imageOut; biasCorrection(image.image, imageOut.image, 1, useLog); image.image = imageOut.image; } volumeFile->convertFromITKImage(image); volumeFile->stretchVoxelValues(); std::ostringstream str; str << "\n" << "Bias Correction:\n" << " Iterations (X, Y, Z): " << axisIterations[0] << ", " << axisIterations[1] << ", " << axisIterations[2] << "\n" << " Thresholds (Low, High): " << lowerUpperThresholds[0] << ", " << lowerUpperThresholds[1] << "\n" << " Gray Range: " << grayWhiteValues[0] << ", " << grayWhiteValues[1] << "\n" << " White Range: " << grayWhiteValues[2] << ", " << grayWhiteValues[3] << "\n" << "\n"; volumeFile->appendToFileComment(str.str().c_str()); } catch (itk::ExceptionObject& e) { throw BrainModelAlgorithmException(e.what()); } #else // HAVE_ITK throw FileException("Bias Correction unavailable. ITK library not available at compile time."); #endif // HAVE_ITK } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolume.h0000664000175000017500000002044711572067322023271 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_BRAIN_MODEL_VOLUME_H__ #define __VE_BRAIN_MODEL_VOLUME_H__ #include "BrainModel.h" #include "VolumeFile.h" /// BrainModelVolume stores a single volume class BrainModelVolume : public BrainModel { public: /// Constructor BrainModelVolume(BrainSet* bs); /// Destructor ~BrainModelVolume(); /// Initialize the selected slices for all views. void initializeSelectedSlicesAllViews(const bool initializeAxis); /// initialize the selected slices for a single view void initializeSelectedSlices(const int viewNumber, const bool initializeAxis); /// Get a descriptive name of the model QString getDescriptiveName() const; /// get the selected slices for orthogonal views void getSelectedOrthogonalSlices(const int volumeViewNumber, int slices[3]); /// set the selected slices for orthogonal views void setSelectedOrthogonalSlices(const int volumeViewNumber, const int slices[3]); /// get the selected slices for oblique view void getSelectedObliqueSlices(int slices[3]); /// set the selected slices for oblique view void setSelectedObliqueSlices(const int slices[3]); /// get the selected oblique slice offsets void getSelectedObliqueSliceOffsets(const int volumeViewNumber, int slices[3]); /// set the selected oblique slice offsets void setSelectedObliqueSliceOffsets(const int volumeViewNumber, const int slices[3]); /// get the selected axis VolumeFile::VOLUME_AXIS getSelectedAxis(const int volumeViewNumber) const { return selectedAxis[volumeViewNumber]; } /// set the selected axis void setSelectedAxis(const int volumeViewNumber, const VolumeFile::VOLUME_AXIS axis); /// reset the volume void reset(); /// reset the viewing transform void resetViewingTransform(const int viewNumber); /// get the volume is an underlay or an overlay bool getVolumeIsAnUnderlayOrAnOverlay(const VolumeFile* vf) const; /// get the "bottom-most" selected volume file VolumeFile* getMasterVolumeFile(); /// get the "bottom-most" selected volume file (const method) const VolumeFile* getMasterVolumeFile() const; /// get the underlay volume file VolumeFile* getUnderlayVolumeFile(); /// get the underlay volume file (const method) const VolumeFile* getUnderlayVolumeFile() const; /// get the secondary overlay volume file VolumeFile* getOverlaySecondaryVolumeFile(); /// get the secondary overlay volume file (const method) const VolumeFile* getOverlaySecondaryVolumeFile() const; /// get the primary overlay volume file VolumeFile* getOverlayPrimaryVolumeFile(); /// get the primary overlay volume file (const method) const VolumeFile* getOverlayPrimaryVolumeFile() const; /// get the selected anatomy volume file (const method) const VolumeFile* getSelectedVolumeAnatomyFile() const; /// get the selected anatomy volume file VolumeFile* getSelectedVolumeAnatomyFile(); /// get the selected functional view volume file VolumeFile* getSelectedVolumeFunctionalViewFile(); /// get the selected functional view volume file (const method) const VolumeFile* getSelectedVolumeFunctionalViewFile() const; /// get the selected functional threshold volume file VolumeFile* getSelectedVolumeFunctionalThresholdFile(); /// get the selected functional threshold volume file (const method) const VolumeFile* getSelectedVolumeFunctionalThresholdFile() const; /// get the selected paint volume file VolumeFile* getSelectedVolumePaintFile(); /// get the selected paint volume file (const method) const VolumeFile* getSelectedVolumePaintFile() const; /// get the selected rgb volume file VolumeFile* getSelectedVolumeRgbFile(); /// get the selected rgb volume file (const method) const VolumeFile* getSelectedVolumeRgbFile() const; /// get the selected segmentation volume file VolumeFile* getSelectedVolumeSegmentationFile(); /// get the selected segmentation volume file (const method) const VolumeFile* getSelectedVolumeSegmentationFile() const; /// get the selected vector volume file VolumeFile* getSelectedVolumeVectorFile(); /// get the selected vector volume file (const method) const VolumeFile* getSelectedVolumeVectorFile() const; /// get the display rotation float getDisplayRotation(const int volumeViewNumber) const; /// set the display rotation void setDisplayRotation(const int volumeViewNumber, const float dr); /// add to the display rotation void addToDisplayRotation(const int volumeViewNumber, const float delta); /// get the oblique rotation matrix vtkTransform* getObliqueRotationMatrix() { return obliqueRotationMatrix; } /// get the oblique rotation matrix (const method) const vtkTransform* getObliqueRotationMatrix() const{ return obliqueRotationMatrix; } /// get the oblique rotation matrix (const method) void getObliqueRotationMatrix(float matrix[16]) const; /// set the oblique rotation matrix void setObliqueRotationMatrix(const float matrix[16]); /// get oblique transformations as string (16 rot, 1 scale) QString getObliqueTransformationsAsString(const int viewNumber) const; /// set oblique transformations from string (16 rot, 1 scale) void setObliqueTransformationsAsString(const int viewNumber, const QString s); /// set to a standard view virtual void setToStandardView(const int viewNumber, const STANDARD_VIEWS view); /// view stereotaxic coordinates flag bool getViewStereotaxicCoordinatesFlag(const int viewNumber) const; /// view stereotaxic coordinates flag void setViewStereotaxicCoordinatesFlag(const int viewNumber, const bool b); // get show underlay only in window bool getShowUnderlayOnlyInWindow(const int viewNumber) const; // set show underlay only in window void setShowUnderlayOnlyInWindow(const int viewNumber, const bool underlayOnlyFlag); protected: /// the selected ortogonal view slices int selectedOrthogonalSlices[NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS][3]; /// the selected oblique view slices int selectedObliqueSlices[3]; /// the oblique selected slice offsets int selectedObliqueSliceOffsets[NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS][3]; /// the selected axis VolumeFile::VOLUME_AXIS selectedAxis[NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS]; /// the display rotation float displayRotation[NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS]; /// show underlay only float showUnderlayOnly[NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS]; /// oblique view rotation matrix vtkTransform* obliqueRotationMatrix; /// view stereotaxic coordinates flag bool viewStereotaxicCoordinatesFlag[NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS]; }; #endif caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelVolume.cxx0000664000175000017500000011177311572067322023647 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "vtkTransform.h" #include "BrainModelVolume.h" #include "BrainModelVolumeVoxelColoring.h" #include "BrainSet.h" #include "DisplaySettingsVolume.h" #include "FileUtilities.h" /** * Constructor */ BrainModelVolume::BrainModelVolume(BrainSet* bs) : BrainModel(bs, BrainModel::BRAIN_MODEL_VOLUME) { obliqueRotationMatrix = vtkTransform::New(); reset(); } /** * Destructor */ BrainModelVolume::~BrainModelVolume() { reset(); obliqueRotationMatrix->Delete(); } /** * Get a descriptive name of the model. */ QString BrainModelVolume::getDescriptiveName() const { QString name("VOLUME"); const VolumeFile* vf = getMasterVolumeFile(); if (vf != NULL) { name.append(" - "); name.append(vf->getDescriptiveLabel()); } return name; } /** * Reset the volume. */ void BrainModelVolume::reset() { for (int i = 0; i < NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS; i++) { selectedOrthogonalSlices[i][0] = 0; selectedOrthogonalSlices[i][1] = 0; selectedOrthogonalSlices[i][2] = 0; selectedObliqueSliceOffsets[i][0] = 0; selectedObliqueSliceOffsets[i][1] = 0; selectedObliqueSliceOffsets[i][2] = 0; selectedAxis[i] = VolumeFile::VOLUME_AXIS_Z; displayRotation[i] = 0.0; viewStereotaxicCoordinatesFlag[i] = false; showUnderlayOnly[i] = false; } selectedObliqueSlices[0] = 0; selectedObliqueSlices[1] = 0; selectedObliqueSlices[2] = 0; obliqueRotationMatrix->Identity(); } /** * view stereotaxic coordinates flag. */ bool BrainModelVolume::getViewStereotaxicCoordinatesFlag(const int viewNumber) const { return viewStereotaxicCoordinatesFlag[viewNumber]; } /** * view stereotaxic coordinates flag. */ void BrainModelVolume::setViewStereotaxicCoordinatesFlag(const int viewNumber, const bool b) { viewStereotaxicCoordinatesFlag[viewNumber] = b; } /** * Initialize the selected slices for all views. */ void BrainModelVolume::initializeSelectedSlicesAllViews(const bool initializeAxis) { for (int i = 0; i < NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS; i++) { initializeSelectedSlices(i, initializeAxis); } } /** * Initialize the selected slices. If the origin is non-zero, the selected slices * are set to the voxel containing the coordinate (0, 0, 0). Otherwise, the selected * slices are set to the middle slices (dims / 2). */ void BrainModelVolume::initializeSelectedSlices(const int viewNumber, const bool initializeAxis) { int defaultIJK[3] = { 0, 0, 0 }; VolumeFile* vf = getMasterVolumeFile(); if (vf != NULL) { // // AC should be at stereotaxic coordinate (0, 0, 0) // float origin[3]; vf->getOrigin(origin); float xyz[3] = { 0.0, 0.0, 0.0 }; int ijk[3]; float p[3]; const bool insideVolumeFlag = vf->convertCoordinatesToVoxelIJK(xyz, ijk, p); if (insideVolumeFlag) { // // Initialize slices to the coordinate (0, 0, 0) which should be the AC // defaultIJK[0] = ijk[0]; defaultIJK[1] = ijk[1]; defaultIJK[2] = ijk[2]; } else { // // Origin not valid or (0, 0, 0) coordinate not in the volume so // initialize to "middle" slices // int voxelDimensions[3]; vf->getDimensions(voxelDimensions); defaultIJK[0] = voxelDimensions[0] / 2; defaultIJK[1] = voxelDimensions[1] / 2; defaultIJK[2] = voxelDimensions[2] / 2; } } if (initializeAxis) { selectedAxis[viewNumber] = VolumeFile::VOLUME_AXIS_Z; selectedOrthogonalSlices[viewNumber][0] = defaultIJK[0]; selectedOrthogonalSlices[viewNumber][1] = defaultIJK[1]; selectedOrthogonalSlices[viewNumber][2] = defaultIJK[2]; selectedObliqueSlices[0] = defaultIJK[0]; selectedObliqueSlices[1] = defaultIJK[1]; selectedObliqueSlices[2] = defaultIJK[2]; selectedObliqueSliceOffsets[viewNumber][0] = 0; selectedObliqueSliceOffsets[viewNumber][1] = 0; selectedObliqueSliceOffsets[viewNumber][2] = 0; } else { switch (selectedAxis[viewNumber]) { case VolumeFile::VOLUME_AXIS_X: case VolumeFile::VOLUME_AXIS_Y: case VolumeFile::VOLUME_AXIS_Z: case VolumeFile::VOLUME_AXIS_ALL: selectedOrthogonalSlices[viewNumber][0] = defaultIJK[0]; selectedOrthogonalSlices[viewNumber][1] = defaultIJK[1]; selectedOrthogonalSlices[viewNumber][2] = defaultIJK[2]; break; case VolumeFile::VOLUME_AXIS_OBLIQUE: selectedObliqueSlices[0] = defaultIJK[0]; selectedObliqueSlices[1] = defaultIJK[1]; selectedObliqueSlices[2] = defaultIJK[2]; break; case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: selectedObliqueSliceOffsets[viewNumber][0] = 0; selectedObliqueSliceOffsets[viewNumber][1] = 0; selectedObliqueSliceOffsets[viewNumber][2] = 0; break; case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } } } /** * Get the selected slices. */ void BrainModelVolume::getSelectedOrthogonalSlices(const int volumeViewNumber, int slices[3]) { slices[0] = selectedOrthogonalSlices[volumeViewNumber][0]; slices[1] = selectedOrthogonalSlices[volumeViewNumber][1]; slices[2] = selectedOrthogonalSlices[volumeViewNumber][2]; VolumeFile* vf = getMasterVolumeFile(); if (vf != NULL) { int dim[3]; vf->getDimensions(dim); if ((slices[0] >= dim[0]) || (slices[1] >= dim[1]) || (slices[2] >= dim[2])) { initializeSelectedSlicesAllViews(false); slices[0] = selectedOrthogonalSlices[volumeViewNumber][0]; slices[1] = selectedOrthogonalSlices[volumeViewNumber][1]; slices[2] = selectedOrthogonalSlices[volumeViewNumber][2]; } } } /** * get the selected slices for oblique view. */ void BrainModelVolume::getSelectedObliqueSlices(int slices[3]) { slices[0] = selectedObliqueSlices[0]; slices[1] = selectedObliqueSlices[1]; slices[2] = selectedObliqueSlices[2]; } /** * set the selected slices for oblique view. */ void BrainModelVolume::setSelectedObliqueSlices(const int slices[3]) { selectedObliqueSlices[0] = slices[0]; selectedObliqueSlices[1] = slices[1]; selectedObliqueSlices[2] = slices[2]; } /** * get the selected oblique slice offsets. */ void BrainModelVolume::getSelectedObliqueSliceOffsets(const int volumeViewNumber, int slices[3]) { slices[0] = selectedObliqueSliceOffsets[volumeViewNumber][0]; slices[1] = selectedObliqueSliceOffsets[volumeViewNumber][1]; slices[2] = selectedObliqueSliceOffsets[volumeViewNumber][2]; } /** * set the selected oblique slice offsets. */ void BrainModelVolume::setSelectedObliqueSliceOffsets(const int volumeViewNumber, const int slices[3]) { selectedObliqueSliceOffsets[volumeViewNumber][0] = slices[0]; selectedObliqueSliceOffsets[volumeViewNumber][1] = slices[1]; selectedObliqueSliceOffsets[volumeViewNumber][2] = slices[2]; } /** * Set the selected slices. */ void BrainModelVolume::setSelectedOrthogonalSlices(const int volumeViewNumber, const int slices[3]) { selectedOrthogonalSlices[volumeViewNumber][0] = slices[0]; selectedOrthogonalSlices[volumeViewNumber][1] = slices[1]; selectedOrthogonalSlices[volumeViewNumber][2] = slices[2]; } /** * reset the viewing transform. */ void BrainModelVolume::resetViewingTransform(const int viewNumber) { float m[16]; m[0] = 1.0; m[1] = 0.0; m[2] = 0.0; m[3] = 0.0; m[4] = 0.0; m[5] = 1.0; m[6] = 0.0; m[7] = 0.0; m[8] = 0.0; m[9] = 0.0; m[10] = 1.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; scaling[viewNumber][0] = 1.0; scaling[viewNumber][1] = 1.0; scaling[viewNumber][2] = 1.0; translation[viewNumber][0] = 0.0; translation[viewNumber][1] = 0.0; translation[viewNumber][2] = 0.0; setRotationMatrix(viewNumber, m); //initializeSelectedSlicesAllViews(false); displayRotation[viewNumber] = 0.0; if (getSelectedAxis(viewNumber) == VolumeFile::VOLUME_AXIS_OBLIQUE) { obliqueRotationMatrix->Identity(); } } /** * Set the volume to a standard view. * This should only be called for volumes when in viewing the "oblique" axis. */ void BrainModelVolume::setToStandardView(const int viewNumber, const STANDARD_VIEWS view) { float m[16]; bool valid = true; const Structure structure = brainSet->getStructure(); switch(view) { case VIEW_LATERAL: if (structure.getType() != Structure::STRUCTURE_TYPE_CORTEX_RIGHT) { m[0] = 0.0; m[1] = 0.0; m[2] = -1.0; m[3] = 0.0; m[4] = -1.0; m[5] = 0.0; m[6] = 0.0; m[7] = 0.0; m[8] = 0.0; m[9] = 1.0; m[10] = 0.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; } else { m[0] = 0.0; m[1] = 0.0; m[2] = 1.0; m[3] = 0.0; m[4] = 1.0; m[5] = 0.0; m[6] = 0.0; m[7] = 0.0; m[8] = 0.0; m[9] = 1.0; m[10] = 0.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; } break; case VIEW_MEDIAL: if (structure.getType() != Structure::STRUCTURE_TYPE_CORTEX_RIGHT) { m[0] = 0.0; m[1] = 0.0; m[2] = 1.0; m[3] = 0.0; m[4] = 1.0; m[5] = 0.0; m[6] = 0.0; m[7] = 0.0; m[8] = 0.0; m[9] = 1.0; m[10] = 0.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; } else { m[0] = 0.0; m[1] = 0.0; m[2] = -1.0; m[3] = 0.0; m[4] = -1.0; m[5] = 0.0; m[6] = 0.0; m[7] = 0.0; m[8] = 0.0; m[9] = 1.0; m[10] = 0.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; } break; case VIEW_POSTERIOR: if (structure.getType() != Structure::STRUCTURE_TYPE_CORTEX_RIGHT) { m[0] = 1.0; m[1] = 0.0; m[2] = 0.0; m[3] = 0.0; m[4] = 0.0; m[5] = 0.0; m[6] = -1.0; m[7] = 0.0; m[8] = 0.0; m[9] = 1.0; m[10] = 0.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; } else { m[0] = 1.0; m[1] = 0.0; m[2] = 0.0; m[3] = 0.0; m[4] = 0.0; m[5] = 0.0; m[6] = -1.0; m[7] = 0.0; m[8] = 0.0; m[9] = 1.0; m[10] = 0.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; } break; case VIEW_ANTERIOR: if (structure.getType() != Structure::STRUCTURE_TYPE_CORTEX_RIGHT) { m[0] = -1.0; m[1] = 0.0; m[2] = 0.0; m[3] = 0.0; m[4] = 0.0; m[5] = 0.0; m[6] = 1.0; m[7] = 0.0; m[8] = 0.0; m[9] = 1.0; m[10] = 0.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; } else { m[0] = -1.0; m[1] = 0.0; m[2] = 0.0; m[3] = 0.0; m[4] = 0.0; m[5] = 0.0; m[6] = 1.0; m[7] = 0.0; m[8] = 0.0; m[9] = 1.0; m[10] = 0.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; } break; case VIEW_VENTRAL: if (structure.getType() != Structure::STRUCTURE_TYPE_CORTEX_RIGHT) { m[0] = -1.0; m[1] = 0.0; m[2] = 0.0; m[3] = 0.0; m[4] = 0.0; m[5] = 1.0; m[6] = 0.0; m[7] = 0.0; m[8] = 0.0; m[9] = 0.0; m[10] = -1.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; } else { m[0] = -1.0; m[1] = 0.0; m[2] = 0.0; m[3] = 0.0; m[4] = 0.0; m[5] = 1.0; m[6] = 0.0; m[7] = 0.0; m[8] = 0.0; m[9] = 0.0; m[10] = -1.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; } break; case VIEW_DORSAL: if (structure.getType() != Structure::STRUCTURE_TYPE_CORTEX_RIGHT) { m[0] = 1.0; m[1] = 0.0; m[2] = 0.0; m[3] = 0.0; m[4] = 0.0; m[5] = 1.0; m[6] = 0.0; m[7] = 0.0; m[8] = 0.0; m[9] = 0.0; m[10] = 1.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; } else { m[0] = 1.0; m[1] = 0.0; m[2] = 0.0; m[3] = 0.0; m[4] = 0.0; m[5] = 1.0; m[6] = 0.0; m[7] = 0.0; m[8] = 0.0; m[9] = 0.0; m[10] = 1.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; } break; case VIEW_RESET: m[0] = 1.0; m[1] = 0.0; m[2] = 0.0; m[3] = 0.0; m[4] = 0.0; m[5] = 1.0; m[6] = 0.0; m[7] = 0.0; m[8] = 0.0; m[9] = 0.0; m[10] = 1.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; perspectiveZooming[viewNumber] = 100.0; //defaultPerspectiveZooming; scaling[viewNumber][0] = 1.0; scaling[viewNumber][1] = 1.0; scaling[viewNumber][2] = 1.0; translation[viewNumber][0] = 0.0; translation[viewNumber][1] = 0.0; translation[viewNumber][2] = 0.0; setRotationMatrix(viewNumber, m); initializeSelectedSlicesAllViews(false); displayRotation[viewNumber] = 0.0; if(getSelectedAxis(viewNumber) == VolumeFile::VOLUME_AXIS_OBLIQUE) { obliqueRotationMatrix->Identity(); } break; case VIEW_ROTATE_X_90: if(getSelectedAxis(viewNumber) == VolumeFile::VOLUME_AXIS_OBLIQUE) { obliqueRotationMatrix->RotateX(90.0); } valid = false; break; case VIEW_ROTATE_Y_90: if(getSelectedAxis(viewNumber) == VolumeFile::VOLUME_AXIS_OBLIQUE) { obliqueRotationMatrix->RotateY(90.0); } valid = false; break; case VIEW_ROTATE_Z_90: if(getSelectedAxis(viewNumber) == VolumeFile::VOLUME_AXIS_OBLIQUE) { obliqueRotationMatrix->RotateZ(-90.0); } valid = false; break; case VIEW_NONE: default: valid = false; break; } if (valid) { if(getSelectedAxis(viewNumber) == VolumeFile::VOLUME_AXIS_OBLIQUE) { setObliqueRotationMatrix(m); } } } /** * get the volume is an underlay or an overlay. */ bool BrainModelVolume::getVolumeIsAnUnderlayOrAnOverlay(const VolumeFile* vf) const { if (vf != NULL) { if ((vf == getUnderlayVolumeFile()) || (vf == getOverlaySecondaryVolumeFile()) || (vf == getOverlayPrimaryVolumeFile())) { return true; } } return false; } /** * get the "bottom-most" selected volume file for volume display sizing and control. */ VolumeFile* BrainModelVolume::getMasterVolumeFile() { VolumeFile *vf = getUnderlayVolumeFile(); if (vf != NULL) { return vf; } vf = getOverlaySecondaryVolumeFile(); if (vf != NULL) { return vf; } vf = getOverlayPrimaryVolumeFile(); return vf; } /** * get the "bottom-most" selected volume file for volume display sizing and control (const). */ const VolumeFile* BrainModelVolume::getMasterVolumeFile() const { if (getUnderlayVolumeFile() != NULL) { return getUnderlayVolumeFile(); } if (getOverlaySecondaryVolumeFile() != NULL) { return getOverlaySecondaryVolumeFile(); } return getOverlayPrimaryVolumeFile(); } /** * get the underlay volume file. */ VolumeFile* BrainModelVolume::getUnderlayVolumeFile() { BrainModelVolumeVoxelColoring* vvc = brainSet->getVoxelColoring(); switch (vvc->getUnderlay()) { case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_ANATOMY: return getSelectedVolumeAnatomyFile(); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_FUNCTIONAL: return getSelectedVolumeFunctionalViewFile(); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_PAINT: return getSelectedVolumePaintFile(); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_PROB_ATLAS: if (brainSet->getNumberOfVolumeProbAtlasFiles() > 0) { return brainSet->getVolumeProbAtlasFile(0); } break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_RGB: return getSelectedVolumeRgbFile(); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_SEGMENTATION: return getSelectedVolumeSegmentationFile(); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_VECTOR: return getSelectedVolumeVectorFile(); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_NONE: break; } return NULL; } /** * get the underlay volume file (const method). */ const VolumeFile* BrainModelVolume::getUnderlayVolumeFile() const { BrainModelVolumeVoxelColoring* vvc = brainSet->getVoxelColoring(); switch (vvc->getUnderlay()) { case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_ANATOMY: return getSelectedVolumeAnatomyFile(); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_FUNCTIONAL: return getSelectedVolumeFunctionalViewFile(); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_PAINT: return getSelectedVolumePaintFile(); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_PROB_ATLAS: if (brainSet->getNumberOfVolumeProbAtlasFiles() > 0) { return brainSet->getVolumeProbAtlasFile(0); } break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_RGB: return getSelectedVolumeRgbFile(); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_SEGMENTATION: return getSelectedVolumeSegmentationFile(); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_VECTOR: return getSelectedVolumeVectorFile(); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_NONE: break; } return NULL; } /** * get the secondary overlay volume file. */ VolumeFile* BrainModelVolume::getOverlaySecondaryVolumeFile() { BrainModelVolumeVoxelColoring* vvc = brainSet->getVoxelColoring(); switch (vvc->getSecondaryOverlay()) { case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_ANATOMY: return getSelectedVolumeAnatomyFile(); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_FUNCTIONAL: return getSelectedVolumeFunctionalViewFile(); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_PAINT: return getSelectedVolumePaintFile(); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_PROB_ATLAS: if (brainSet->getNumberOfVolumeProbAtlasFiles() > 0) { return brainSet->getVolumeProbAtlasFile(0); } break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_RGB: return getSelectedVolumeRgbFile(); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_SEGMENTATION: return getSelectedVolumeSegmentationFile(); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_VECTOR: return getSelectedVolumeVectorFile(); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_NONE: break; } return NULL; } /** * get the secondary overlay volume file (const method). */ const VolumeFile* BrainModelVolume::getOverlaySecondaryVolumeFile() const { BrainModelVolumeVoxelColoring* vvc = brainSet->getVoxelColoring(); switch (vvc->getSecondaryOverlay()) { case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_ANATOMY: return getSelectedVolumeAnatomyFile(); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_FUNCTIONAL: return getSelectedVolumeFunctionalViewFile(); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_PAINT: return getSelectedVolumePaintFile(); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_PROB_ATLAS: if (brainSet->getNumberOfVolumeProbAtlasFiles() > 0) { return brainSet->getVolumeProbAtlasFile(0); } break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_RGB: return getSelectedVolumeRgbFile(); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_SEGMENTATION: return getSelectedVolumeSegmentationFile(); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_VECTOR: return getSelectedVolumeVectorFile(); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_NONE: break; } return NULL; } /** * get the primary overlay volume file. */ VolumeFile* BrainModelVolume::getOverlayPrimaryVolumeFile() { BrainModelVolumeVoxelColoring* vvc = brainSet->getVoxelColoring(); switch (vvc->getPrimaryOverlay()) { case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_ANATOMY: return getSelectedVolumeAnatomyFile(); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_FUNCTIONAL: return getSelectedVolumeFunctionalViewFile(); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_PAINT: return getSelectedVolumePaintFile(); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_PROB_ATLAS: if (brainSet->getNumberOfVolumeProbAtlasFiles() > 0) { return brainSet->getVolumeProbAtlasFile(0); } break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_RGB: return getSelectedVolumeRgbFile(); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_SEGMENTATION: return getSelectedVolumeSegmentationFile(); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_VECTOR: return getSelectedVolumeVectorFile(); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_NONE: break; } return NULL; } /** * get the primary overlay volume file (const method). */ const VolumeFile* BrainModelVolume::getOverlayPrimaryVolumeFile() const { BrainModelVolumeVoxelColoring* vvc = brainSet->getVoxelColoring(); switch (vvc->getPrimaryOverlay()) { case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_ANATOMY: return getSelectedVolumeAnatomyFile(); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_FUNCTIONAL: return getSelectedVolumeFunctionalViewFile(); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_PAINT: return getSelectedVolumePaintFile(); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_PROB_ATLAS: if (brainSet->getNumberOfVolumeProbAtlasFiles() > 0) { return brainSet->getVolumeProbAtlasFile(0); } break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_RGB: return getSelectedVolumeRgbFile(); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_SEGMENTATION: return getSelectedVolumeSegmentationFile(); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_VECTOR: return getSelectedVolumeVectorFile(); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_NONE: break; } return NULL; } /** * Get the selected anatomy volume file. */ VolumeFile* BrainModelVolume::getSelectedVolumeAnatomyFile() { DisplaySettingsVolume* dsv = brainSet->getDisplaySettingsVolume(); VolumeFile* anatomyVolumeFile = NULL; if ((dsv->getSelectedAnatomyVolume() >= 0) && (dsv->getSelectedAnatomyVolume() < brainSet->getNumberOfVolumeAnatomyFiles())) { anatomyVolumeFile = brainSet->getVolumeAnatomyFile(dsv->getSelectedAnatomyVolume()); } return anatomyVolumeFile; } /** * Get the selected anatomy volume file (const method). */ const VolumeFile* BrainModelVolume::getSelectedVolumeAnatomyFile() const { DisplaySettingsVolume* dsv = brainSet->getDisplaySettingsVolume(); VolumeFile* anatomyVolumeFile = NULL; if ((dsv->getSelectedAnatomyVolume() >= 0) && (dsv->getSelectedAnatomyVolume() < brainSet->getNumberOfVolumeAnatomyFiles())) { anatomyVolumeFile = brainSet->getVolumeAnatomyFile(dsv->getSelectedAnatomyVolume()); } return anatomyVolumeFile; } /** * Get the selected functional volume file. */ VolumeFile* BrainModelVolume::getSelectedVolumeFunctionalViewFile() { DisplaySettingsVolume* dsv = brainSet->getDisplaySettingsVolume(); VolumeFile* functionalVolumeFile = NULL; if ((dsv->getSelectedFunctionalVolumeView() >= 0) && (dsv->getSelectedFunctionalVolumeView() < brainSet->getNumberOfVolumeFunctionalFiles())) { functionalVolumeFile = brainSet->getVolumeFunctionalFile(dsv->getSelectedFunctionalVolumeView()); } return functionalVolumeFile; } /** * Get the selected functional volume file (const method). */ const VolumeFile* BrainModelVolume::getSelectedVolumeFunctionalViewFile() const { DisplaySettingsVolume* dsv = brainSet->getDisplaySettingsVolume(); VolumeFile* functionalVolumeFile = NULL; if ((dsv->getSelectedFunctionalVolumeView() >= 0) && (dsv->getSelectedFunctionalVolumeView() < brainSet->getNumberOfVolumeFunctionalFiles())) { functionalVolumeFile = brainSet->getVolumeFunctionalFile(dsv->getSelectedFunctionalVolumeView()); } return functionalVolumeFile; } /** * Get the selected functional volume file (const method). */ const VolumeFile* BrainModelVolume::getSelectedVolumeFunctionalThresholdFile() const { DisplaySettingsVolume* dsv = brainSet->getDisplaySettingsVolume(); VolumeFile* functionalVolumeFile = NULL; if ((dsv->getSelectedFunctionalVolumeThreshold() >= 0) && (dsv->getSelectedFunctionalVolumeThreshold() < brainSet->getNumberOfVolumeFunctionalFiles())) { functionalVolumeFile = brainSet->getVolumeFunctionalFile(dsv->getSelectedFunctionalVolumeThreshold()); } return functionalVolumeFile; } /** * Get the selected functional volume file. */ VolumeFile* BrainModelVolume::getSelectedVolumeFunctionalThresholdFile() { DisplaySettingsVolume* dsv = brainSet->getDisplaySettingsVolume(); VolumeFile* functionalVolumeFile = NULL; if ((dsv->getSelectedFunctionalVolumeThreshold() >= 0) && (dsv->getSelectedFunctionalVolumeThreshold() < brainSet->getNumberOfVolumeFunctionalFiles())) { functionalVolumeFile = brainSet->getVolumeFunctionalFile(dsv->getSelectedFunctionalVolumeThreshold()); } return functionalVolumeFile; } /** * Get the selected paint volume file. */ VolumeFile* BrainModelVolume::getSelectedVolumePaintFile() { DisplaySettingsVolume* dsv = brainSet->getDisplaySettingsVolume(); VolumeFile* paintVolumeFile = NULL; if ((dsv->getSelectedPaintVolume() >= 0) && (dsv->getSelectedPaintVolume() < brainSet->getNumberOfVolumePaintFiles())) { paintVolumeFile = brainSet->getVolumePaintFile(dsv->getSelectedPaintVolume()); } return paintVolumeFile; } /** * Get the selected paint volume file (const method). */ const VolumeFile* BrainModelVolume::getSelectedVolumePaintFile() const { DisplaySettingsVolume* dsv = brainSet->getDisplaySettingsVolume(); VolumeFile* paintVolumeFile = NULL; if ((dsv->getSelectedPaintVolume() >= 0) && (dsv->getSelectedPaintVolume() < brainSet->getNumberOfVolumePaintFiles())) { paintVolumeFile = brainSet->getVolumePaintFile(dsv->getSelectedPaintVolume()); } return paintVolumeFile; } /** * Get the selected RGB volume file. */ VolumeFile* BrainModelVolume::getSelectedVolumeRgbFile() { DisplaySettingsVolume* dsv = brainSet->getDisplaySettingsVolume(); VolumeFile* rgbVolumeFile = NULL; if ((dsv->getSelectedRgbVolume() >= 0) && (dsv->getSelectedRgbVolume() < brainSet->getNumberOfVolumeRgbFiles())) { rgbVolumeFile = brainSet->getVolumeRgbFile(dsv->getSelectedRgbVolume()); } return rgbVolumeFile; } /** * Get the selected RGB volume file (const method). */ const VolumeFile* BrainModelVolume::getSelectedVolumeRgbFile() const { DisplaySettingsVolume* dsv = brainSet->getDisplaySettingsVolume(); VolumeFile* rgbVolumeFile = NULL; if ((dsv->getSelectedRgbVolume() >= 0) && (dsv->getSelectedRgbVolume() < brainSet->getNumberOfVolumeRgbFiles())) { rgbVolumeFile = brainSet->getVolumeRgbFile(dsv->getSelectedRgbVolume()); } return rgbVolumeFile; } /** * Get the selected segmenation volume file. */ VolumeFile* BrainModelVolume::getSelectedVolumeSegmentationFile() { DisplaySettingsVolume* dsv = brainSet->getDisplaySettingsVolume(); VolumeFile* segmentationVolumeFile = NULL; if ((dsv->getSelectedSegmentationVolume() >= 0) && (dsv->getSelectedSegmentationVolume() < brainSet->getNumberOfVolumeSegmentationFiles())) { segmentationVolumeFile = brainSet->getVolumeSegmentationFile(dsv->getSelectedSegmentationVolume()); } return segmentationVolumeFile; } /** * Get the selected segmenation volume file (const method). */ const VolumeFile* BrainModelVolume::getSelectedVolumeSegmentationFile() const { DisplaySettingsVolume* dsv = brainSet->getDisplaySettingsVolume(); VolumeFile* segmentationVolumeFile = NULL; if ((dsv->getSelectedSegmentationVolume() >= 0) && (dsv->getSelectedSegmentationVolume() < brainSet->getNumberOfVolumeSegmentationFiles())) { segmentationVolumeFile = brainSet->getVolumeSegmentationFile(dsv->getSelectedSegmentationVolume()); } return segmentationVolumeFile; } /** * Get the selected vector volume file. */ VolumeFile* BrainModelVolume::getSelectedVolumeVectorFile() { DisplaySettingsVolume* dsv = brainSet->getDisplaySettingsVolume(); VolumeFile* vectorVolumeFile = NULL; if ((dsv->getSelectedVectorVolume() >= 0) && (dsv->getSelectedVectorVolume() < brainSet->getNumberOfVolumeVectorFiles())) { vectorVolumeFile = brainSet->getVolumeVectorFile(dsv->getSelectedVectorVolume()); } return vectorVolumeFile; } /** * Get the selected vector volume file (const method). */ const VolumeFile* BrainModelVolume::getSelectedVolumeVectorFile() const { DisplaySettingsVolume* dsv = brainSet->getDisplaySettingsVolume(); VolumeFile* vectorVolumeFile = NULL; if ((dsv->getSelectedVectorVolume() >= 0) && (dsv->getSelectedVectorVolume() < brainSet->getNumberOfVolumeVectorFiles())) { vectorVolumeFile = brainSet->getVolumeVectorFile(dsv->getSelectedVectorVolume()); } return vectorVolumeFile; } /** * get the display rotation. */ float BrainModelVolume::getDisplayRotation(const int volumeViewNumber) const { return displayRotation[volumeViewNumber]; } /** * set the display rotation. */ void BrainModelVolume::setDisplayRotation(const int volumeViewNumber, const float dr) { displayRotation[volumeViewNumber] = dr; } /** * add to the display rotation. */ void BrainModelVolume::addToDisplayRotation(const int volumeViewNumber, const float delta) { displayRotation[volumeViewNumber] += delta; if ((displayRotation[volumeViewNumber] >= 360.0) || (displayRotation[volumeViewNumber] <= -360.0)) { displayRotation[volumeViewNumber] = fmod(displayRotation[volumeViewNumber],360.0f); } if (displayRotation[volumeViewNumber] > 180.0) { displayRotation[volumeViewNumber] = -360.0 + displayRotation[volumeViewNumber]; } if (displayRotation[volumeViewNumber] < -180.0) { displayRotation[volumeViewNumber] = 360.0 + displayRotation[volumeViewNumber]; } } /** * set the selected axis. */ void BrainModelVolume::setSelectedAxis(const int volumeViewNumber, const VolumeFile::VOLUME_AXIS axis) { selectedAxis[volumeViewNumber] = axis; displayRotation[volumeViewNumber] = 0.0; } /** * get oblique transformations as string (16 rot, 1 scale). */ QString BrainModelVolume::getObliqueTransformationsAsString(const int viewNumber) const { std::ostringstream str; str.precision(2); str.setf(std::ios::fixed); /* const vtkTransform* obliqueTrans = getObliqueRotationMatrix(viewNumber); TransformationMatrix tm; tm.setMatrix(obliqueTrans); float mat[16]; tm.getMatrix(mat); */ float mat[16]; getObliqueRotationMatrix(mat); for (int i = 0; i < 16; i++) { str << mat[i] << " "; } float scale[3]; getScaling(viewNumber, scale); str << scale[0] << " " << scale[1] << " " << scale[2]; const QString s(str.str().c_str()); return s; } /** * set oblique transformations from string (16 rot, 1 scale). */ void BrainModelVolume::setObliqueTransformationsAsString(const int viewNumber, const QString s) { QString s2(s); QTextStream textStream(&s2, QIODevice::ReadOnly); float mat[16]; for (int i = 0; i < 16; i++) { textStream >> mat[i]; } setObliqueRotationMatrix(mat); /* TransformationMatrix tm; tm.setMatrix(mat); vtkTransform* obliqueTrans = getObliqueRotationMatrix(viewNumber); tm.getMatrix(obliqueTrans); */ float scale[3]; textStream >> scale[0] >> scale[1] >> scale[2]; setScaling(viewNumber, scale); } /** * get the oblique rotation matrix. */ void BrainModelVolume::getObliqueRotationMatrix(float matrix[16]) const { vtkTransform* obliqueRot = (vtkTransform*)getObliqueRotationMatrix(); vtkMatrix4x4* m = vtkMatrix4x4::New(); obliqueRot->GetMatrix(m); int cnt = 0; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { matrix[cnt] = m->GetElement(i, j); cnt++; } } m->Delete(); } /** * set the oblique rotation matrix. */ void BrainModelVolume::setObliqueRotationMatrix(const float matrix[16]) { vtkTransform* obliqueRot = getObliqueRotationMatrix(); vtkMatrix4x4* m = vtkMatrix4x4::New(); obliqueRot->GetMatrix(m); int cnt = 0; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { m->SetElement(i, j, matrix[cnt]); cnt++; } } obliqueRot->SetMatrix(m); m->Delete(); } /** * get show underlay only in window. */ bool BrainModelVolume::getShowUnderlayOnlyInWindow(const int viewNumber) const { return showUnderlayOnly[viewNumber]; } /** * set show underlay only in window. */ void BrainModelVolume::setShowUnderlayOnlyInWindow(const int viewNumber, const bool underlayOnlyFlag) { showUnderlayOnly[viewNumber] = underlayOnlyFlag; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceTopologyCorrector.h0000664000175000017500000001013311572067322027021 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_TOPOLOGY_CORRECTOR_H__ #define __BRAIN_MODEL_SURFACE_TOPOLOGY_CORRECTOR_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainModelAlgorithm.h" #include "Tessellation.h" class QTime; class BrainModelSurface; class BrainModelSurfaceROINodeSelection; class CoordinateFile; class PointLocator; class TopologyFile; /// Class that corrects topological errors in a surface class BrainModelSurfaceTopologyCorrector : public BrainModelAlgorithm { public: // Constructor BrainModelSurfaceTopologyCorrector(BrainSet* bsIn, const BrainModelSurface* fiducialSurfaceIn, const int numberOfSmoothingCyclesIn = 30, const bool removeHighlyCompressedNodesIn = true, const float compressedNodesArealDistortionThresholdIn = -7.0); // Destructor ~BrainModelSurfaceTopologyCorrector(); /// skip corrected surface generation (just determine nodes that are removed) void setSkipCorrectedSurfaceGeneration(const bool skipIt) { skipCorrectedSurfaceGeneration = skipIt; } // execute the algorithm void execute() throw (BrainModelAlgorithmException); /// get a pointer to the new surface BrainModelSurface* getPointerToNewSurface() { return fiducialSurface; } // get a list of node numbers that were removed void getListOfNodesThatWereRemoved(std::vector& nodesRemoved) const; // get a list of node numbers that were removed void getListOfNodesThatWereRemoved(BrainModelSurfaceROINodeSelection& nodesRemovedROI) const; protected: /// smooth around removed nodes void smoothAroundRemovedNodes(); /// Flag nodes in highly compressed tiles as unavailable void removeNodesInHighlyCompressedTilesFromAvailableNodes() throw (BrainModelAlgorithmException); /// Flag the crossover nodes as unavailable void removeCrossoverNodesFromAvailableNodes(); /// retessellate the sphere BrainModelSurface* retessellateTheSphericalSurface() throw (BrainModelAlgorithmException); /// Smooth the spherical surface. void smoothSphericalSurfaceToMinimizeCrossovers() throw (BrainModelAlgorithmException); /// the fiducial surface DO NOT DELETE BrainModelSurface* fiducialSurface; /// the spherical surface DO NOT DELETE BrainModelSurface* sphericalSurface; /// number of nodes int numNodes; /// copy of the original input topology file TopologyFile* copyOfOriginalTopologyFile; /// topology file used to maintain connected nodes TopologyFile* workingTopologyFile; /// number of smoothing cycles to find crossovers int numberOfSmoothingCycles; /// remove highly compressed nodes bool removeHighlyCompressedNodes; /// highly compressed nodes have areal distortion less than this float compressedNodesArealDistortionThreshold; /// skip generation of corrected surfaces bool skipCorrectedSurfaceGeneration; }; #endif // __BRAIN_MODEL_SURFACE_TOPOLOGY_CORRECTOR_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceTopologyCorrector.cxx0000664000175000017500000003450511572067322027405 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include "vtkTriangle.h" #include "vtkPointLocator.h" #include "vtkPoints.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceDistortion.h" #include "BrainModelSurfaceROINodeSelection.h" #include "BrainModelSurfaceSmoothing.h" #include "BrainModelSurfaceSphericalTessellator.h" #include "BrainModelSurfaceTopologyCorrector.h" #include "BrainSet.h" #include "DebugControl.h" #include "MathUtilities.h" #include "PointLocator.h" #include "SurfaceShapeFile.h" #include "TopologyFile.h" #include "TopologyHelper.h" /** * Constructor. */ BrainModelSurfaceTopologyCorrector::BrainModelSurfaceTopologyCorrector( BrainSet* bsIn, const BrainModelSurface* fiducialSurfaceIn, const int numberOfSmoothingCyclesIn, const bool removeHighlyCompressedNodesIn, const float compressedNodesArealDistortionThresholdIn) : BrainModelAlgorithm(bsIn) { fiducialSurface = new BrainModelSurface(*fiducialSurfaceIn); sphericalSurface = new BrainModelSurface(*fiducialSurfaceIn); numberOfSmoothingCycles = numberOfSmoothingCyclesIn; removeHighlyCompressedNodes = removeHighlyCompressedNodesIn; compressedNodesArealDistortionThreshold = compressedNodesArealDistortionThresholdIn; numNodes = 0; copyOfOriginalTopologyFile = NULL; workingTopologyFile = NULL; skipCorrectedSurfaceGeneration = false; } /** * Destructor. */ BrainModelSurfaceTopologyCorrector::~BrainModelSurfaceTopologyCorrector() { if (copyOfOriginalTopologyFile != NULL) { delete copyOfOriginalTopologyFile; copyOfOriginalTopologyFile = NULL; } if (workingTopologyFile != NULL) { delete workingTopologyFile; workingTopologyFile = NULL; } } /** * Smooth the spherical surface. */ void BrainModelSurfaceTopologyCorrector::smoothSphericalSurfaceToMinimizeCrossovers() throw (BrainModelAlgorithmException) { int cycleNumber = 0; while (cycleNumber < numberOfSmoothingCycles) { // // Translate to center of mass // sphericalSurface->translateToCenterOfMass(); // // Do spherical smoothing // const int smoothingIterations = 100; BrainModelSurfaceSmoothing smoothing(brainSet, sphericalSurface, BrainModelSurfaceSmoothing::SMOOTHING_TYPE_LINEAR, 1.0, smoothingIterations, 0, 0, NULL, NULL, 10, 0); smoothing.execute(); // // Do a crossover check // int numNodeCrossovers, numTileCrossovers; sphericalSurface->crossoverCheck(numNodeCrossovers, numTileCrossovers, BrainModelSurface::SURFACE_TYPE_SPHERICAL); int crossoverCount = 0; for (int j = 0; j < numNodes; j++) { BrainSetNodeAttribute* bna = brainSet->getNodeAttributes(j); if (bna->getCrossover() == BrainSetNodeAttribute::CROSSOVER_YES) { crossoverCount++; } } if (DebugControl::getDebugOn()) { std::cout << "Crossovers at smoothing cycle " << cycleNumber << ": " << crossoverCount << std::endl; } if (crossoverCount <= 0) { break; } cycleNumber++; } } /** * Flag nodes in highly compressed tiles as unavailable. */ void BrainModelSurfaceTopologyCorrector::removeNodesInHighlyCompressedTilesFromAvailableNodes() throw (BrainModelAlgorithmException) { // // Calculate areal distortion // SurfaceShapeFile ssf; BrainModelSurfaceDistortion bmsd(brainSet, sphericalSurface, fiducialSurface, fiducialSurface->getTopologyFile(), &ssf, BrainModelSurfaceDistortion::DISTORTION_COLUMN_CREATE_NEW, BrainModelSurfaceDistortion::DISTORTION_COLUMN_DO_NOT_GENERATE, "Areal", ""); bmsd.execute(); if (ssf.getNumberOfColumns() != 1) { throw BrainModelAlgorithmException("Calculation of areal distortion failed."); } // // Get a topology helper for finding connected nodes to use in tessellation // const TopologyHelper* th = workingTopologyFile->getTopologyHelper(false, true, false); // // Mark nodes that exceed areal distortion threshold // std::vector distortedNodes(numNodes, false); for (int i = 0; i < numNodes; i++) { if (ssf.getValue(i, 0) < compressedNodesArealDistortionThreshold) { if (th->getNodeHasNeighbors(i)) { distortedNodes[i] = true; } } } // // Delete tiles using distorted nodes // workingTopologyFile->deleteTilesWithMarkedNodes(distortedNodes); } /** * Flag the crossover nodes as unavailable. */ void BrainModelSurfaceTopologyCorrector::removeCrossoverNodesFromAvailableNodes() { // // Do a crossover check // int numNodeCrossovers, numTileCrossovers; sphericalSurface->crossoverCheck(numNodeCrossovers, numTileCrossovers, BrainModelSurface::SURFACE_TYPE_SPHERICAL); // // Mark crossovers // std::vector nodeIsCrossover(numNodes, false); for (int j = 0; j < numNodes; j++) { BrainSetNodeAttribute* bna = brainSet->getNodeAttributes(j); if (bna->getCrossover() == BrainSetNodeAttribute::CROSSOVER_YES) { nodeIsCrossover[j] = true; } } // // Delete tiles using crossover nodes // workingTopologyFile->deleteTilesWithMarkedNodes(nodeIsCrossover); } /** * retessellate the sphere. */ BrainModelSurface* BrainModelSurfaceTopologyCorrector::retessellateTheSphericalSurface() throw (BrainModelAlgorithmException) { // // Get a topology helper for finding connected nodes to use in tessellation // const TopologyHelper* th = workingTopologyFile->getTopologyHelper(false, true, false); // // nodes that are to be added to the sphere // std::vector nodeAvailableFlags(numNodes, false); for (int i = 0; i < numNodes; i++) { if (th->getNodeHasNeighbors(i)) { nodeAvailableFlags[i] = true; } } // // Tessllate the available nodes // BrainModelSurfaceSphericalTessellator tess(brainSet, sphericalSurface, nodeAvailableFlags); tess.execute(); return tess.getPointerToNewSphericalSurface(); } /** * get a list of node numbers that were removed. */ void BrainModelSurfaceTopologyCorrector::getListOfNodesThatWereRemoved(std::vector& nodesRemoved) const { nodesRemoved.clear(); // // Get a topology helper for finding connected nodes to use in tessellation // const TopologyHelper* origTH = copyOfOriginalTopologyFile->getTopologyHelper(false, true, false); const TopologyHelper* correctedTH = workingTopologyFile->getTopologyHelper(false, true, false); // // Determine which nodes were disconnected // for (int i = 0; i < numNodes; i++) { if ((origTH->getNodeHasNeighbors(i)) && (correctedTH->getNodeHasNeighbors(i) == false)) { nodesRemoved.push_back(i); } } } /** * get a list of node numbers that were removed. */ void BrainModelSurfaceTopologyCorrector::getListOfNodesThatWereRemoved( BrainModelSurfaceROINodeSelection& nodesRemovedROI) const { nodesRemovedROI.update(); nodesRemovedROI.deselectAllNodes(); std::vector nodesRemoved; getListOfNodesThatWereRemoved(nodesRemoved); const int num = static_cast(nodesRemoved.size()); for (int i = 0; i < num; i++) { nodesRemovedROI.setNodeSelected(nodesRemoved[i], true); } } /** * smooth around removed nodes. */ void BrainModelSurfaceTopologyCorrector::smoothAroundRemovedNodes() { // // Get nodes that were removed // std::vector removedNodeNumbers; getListOfNodesThatWereRemoved(removedNodeNumbers); const int numRemovedNodes = static_cast(removedNodeNumbers.size()); // // Use the original topology file to find nodes for smoothing // const int neighborDepth = 3; std::vector smoothThisNode(numNodes, false); const TopologyHelper* th = copyOfOriginalTopologyFile->getTopologyHelper(false, true, false); for (int i = 0; i < numRemovedNodes; i++) { const int nodeNum = removedNodeNumbers[i]; std::vector neighbors; th->getNodeNeighborsToDepth(nodeNum, neighborDepth, neighbors); const int numNeighbors = static_cast(neighbors.size()); for (int j = 0; j < numNeighbors; j++) { smoothThisNode[neighbors[j]] = true; } } // // copy the corrected fiducial surface // BrainModelSurface* smoothedFiducialSurface = new BrainModelSurface(*fiducialSurface); // // Smooth the surface // const int numSmoothingIterations = 10; BrainModelSurfaceSmoothing bmss(brainSet, smoothedFiducialSurface, BrainModelSurfaceSmoothing::SMOOTHING_TYPE_AREAL, 1.0, numSmoothingIterations, 0, 0, &smoothThisNode, NULL, 0, 0); bmss.execute(); // // Rename and add to brain set // smoothedFiducialSurface->getCoordinateFile()->replaceFileNameDescription("FIDUCIAL_CORRECTED_SMOOTHED"); brainSet->addBrainModel(smoothedFiducialSurface); } /** * execute the algorithm. */ void BrainModelSurfaceTopologyCorrector::execute() throw (BrainModelAlgorithmException) { QTime timer; timer.start(); // // Get the number of nodes // numNodes = sphericalSurface->getNumberOfNodes(); sphericalSurface->setSurfaceType(BrainModelSurface::SURFACE_TYPE_SPHERICAL); // // Make a copy of the topology file which will be used to maintain connected nodes // copyOfOriginalTopologyFile = new TopologyFile(*(sphericalSurface->getTopologyFile())); workingTopologyFile = new TopologyFile(*(sphericalSurface->getTopologyFile())); try { // // Smooth the sphere to unfold it // smoothSphericalSurfaceToMinimizeCrossovers(); // // Remove crossover nodes from the available nodes // removeCrossoverNodesFromAvailableNodes(); // // Remove nodes that are part of tiles that become highly compressed due to smoothing // if (removeHighlyCompressedNodes) { removeNodesInHighlyCompressedTilesFromAvailableNodes(); } // // Remove any islands from the working topology file that were caused by node/tile deletion // workingTopologyFile->disconnectIslands(); // // Should corrected surfaces be generated // BrainModelSurface* retessellatedSphereSurface = NULL; if (skipCorrectedSurfaceGeneration == false) { // // Create a newly tessellated sphere // retessellatedSphereSurface = retessellateTheSphericalSurface(); // // Apply the spherical surface's new topology to the fiducial surface // fiducialSurface->setTopologyFile(retessellatedSphereSurface->getTopologyFile()); // // Rename the fiducial to FiducialCorrected // fiducialSurface->getCoordinateFile()->replaceFileNameDescription("FIDUCIAL_CORRECTED"); // // Add the fiducial to the brain set // brainSet->addBrainModel(fiducialSurface); // // Create a second fiducial smoothed around removed nodes // //smoothAroundRemovedNodes(); } if (DebugControl::getDebugOn()) { sphericalSurface->getCoordinateFile()->replaceFileNameDescription("SPHERE_SMOOTHED_UNCORRECTED"); brainSet->addBrainModel(sphericalSurface); std::cout << "Time to correct surface: " << timer.elapsed() * 0.001 << std::endl; } else { // // Delete the smoothed sphere // delete sphericalSurface; sphericalSurface = NULL; // // Delete the retessellated sphere // if (retessellatedSphereSurface != NULL) { brainSet->deleteBrainModel(retessellatedSphereSurface); } } } catch (TessellationException& te) { throw BrainModelAlgorithmException(te.whatQString()); } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceToVolumeSegmentationConverter.h0000664000175000017500000000434211572067322031347 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_TO_VOLUME_SEGMENTATION_CONVERTER_H__ #define __BRAIN_MODEL_SURFACE_TO_VOLUME_SEGMENTATION_CONVERTER_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelAlgorithm.h" class BrainModelSurface; class VolumeFile; /// create a segmentation volume from a surface class BrainModelSurfaceToVolumeSegmentationConverter : public BrainModelAlgorithm { public: // constructor BrainModelSurfaceToVolumeSegmentationConverter(BrainSet* bs, BrainModelSurface* inputSurfaceIn, VolumeFile* outputSegmentationVolumeIn, const bool fillCavitiesFlagIn, const bool fillHandlesFlagIn); // destructor ~BrainModelSurfaceToVolumeSegmentationConverter(); // execute the algorithm void execute() throw (BrainModelAlgorithmException); protected: /// the input surface BrainModelSurface* inputSurface; /// the segmentation volume VolumeFile* outputSegmentationVolume; /// fill any cavities in the segmentation bool fillCavitiesFlag; /// fill any detected handles in the segmentation bool fillHandlesFlag; }; #endif // __BRAIN_MODEL_SURFACE_TO_VOLUME_SEGMENTATION_CONVERTER_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceToVolumeSegmentationConverter.cxx0000664000175000017500000001211311572067322031715 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurface.h" #include "BrainModelSurfaceToVolumeConverter.h" #include "BrainModelSurfaceToVolumeSegmentationConverter.h" #include "BrainModelVolumeHandleFinder.h" #include "VolumeFile.h" /** * constructor. */ BrainModelSurfaceToVolumeSegmentationConverter::BrainModelSurfaceToVolumeSegmentationConverter( BrainSet* bs, BrainModelSurface* inputSurfaceIn, VolumeFile* outputSegmentationVolumeIn, const bool fillCavitiesFlagIn, const bool fillHandlesFlagIn) : BrainModelAlgorithm(bs) { inputSurface = inputSurfaceIn; outputSegmentationVolume = outputSegmentationVolumeIn; fillCavitiesFlag = fillCavitiesFlagIn; fillHandlesFlag = fillHandlesFlagIn; } /** * destructor. */ BrainModelSurfaceToVolumeSegmentationConverter::~BrainModelSurfaceToVolumeSegmentationConverter() { } /** * execute the algorithm. */ void BrainModelSurfaceToVolumeSegmentationConverter::execute() throw (BrainModelAlgorithmException) { if (inputSurface == NULL) { throw BrainModelAlgorithmException("Input surface is NULL."); } if (outputSegmentationVolume == NULL) { throw BrainModelAlgorithmException("Output volume is NULL"); } // // Get volume information // int dimensions[3]; outputSegmentationVolume->getDimensions(dimensions); float spacing[3]; outputSegmentationVolume->getSpacing(spacing); float origin[3]; outputSegmentationVolume->getOrigin(origin); // // Convert the surface to a segmentation volume // const float surfaceOffset[3] = { 0.0, 0.0, 0.0 }; BrainModelSurfaceToVolumeConverter bmsv(brainSet, inputSurface, StereotaxicSpace::SPACE_UNKNOWN, surfaceOffset, dimensions, spacing, origin, -1.5, 0.0, 0.5, BrainModelSurfaceToVolumeConverter::CONVERT_TO_SEGMENTATION_VOLUME_USING_NODES); bmsv.execute(); // // copy the resulting segmentation volume // VolumeFile* vf = bmsv.getOutputVolume(); if (vf == NULL) { throw BrainModelAlgorithmException("Unable to find volume created by intersecting with surface."); } const QString filename = outputSegmentationVolume->getFileName(); const VolumeFile::FILE_READ_WRITE_TYPE fileWriteType = outputSegmentationVolume->getFileWriteType(); *outputSegmentationVolume = *vf; outputSegmentationVolume->setFileWriteType(fileWriteType); outputSegmentationVolume->setFileName(filename); // // Remove islands in volume // outputSegmentationVolume->removeIslandsFromSegmentation(); // // Fill cavities if requested // if (fillCavitiesFlag) { outputSegmentationVolume->fillSegmentationCavities(); } // // If handles should be filled // if (fillHandlesFlag) { // // Find handles // BrainModelVolumeHandleFinder bmvh(brainSet, outputSegmentationVolume, false, true, true, true, false); bmvh.execute(); // // Fill small handles // const int numberOfVoxelsInSmallHandle = 6; for (int i = 0; i < bmvh.getNumberOfHandles(); i++) { const BrainModelVolumeTopologicalError* handle = bmvh.getHandleInfo(i); std::vector handleVoxels; handle->getHandleVoxels(handleVoxels); if (static_cast(handleVoxels.size()) <= numberOfVoxelsInSmallHandle) { if (handleVoxels.size() > 0) { outputSegmentationVolume->setVoxel(handleVoxels, 255.0); } } } } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceToVolumeConverter.h0000664000175000017500000001671511572067322027000 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __BRAIN_MODEL_SURFACE_TO_VOLUME_CONVERTER_H__ #define __BRAIN_MODEL_SURFACE_TO_VOLUME_CONVERTER_H__ #include #include #include "BrainModelAlgorithm.h" #include "StereotaxicSpace.h" #include "VolumeFile.h" class BrainModelSurface; class BrainSet; class BrainModelSurfaceNodeColoring; class CoordinateFile; class vtkTriangle; /// class that determines how a node maps to voxel class NodeToVoxelMapping { public: /// constructor NodeToVoxelMapping(const int node, const int ijk[3]) { nodeNumber = node; voxelIJK[0] = ijk[0]; voxelIJK[1] = ijk[1]; voxelIJK[2] = ijk[2]; } /// the node number int nodeNumber; /// voxel intersected by node int voxelIJK[3]; /// equality operator bool operator==(const NodeToVoxelMapping& n) const { return ((nodeNumber == n.nodeNumber) && (voxelIJK[0] == n.voxelIJK[0]) && (voxelIJK[1] == n.voxelIJK[1]) && (voxelIJK[2] == n.voxelIJK[2])); } /// less than operator bool operator<(const NodeToVoxelMapping& n) const { if (nodeNumber < n.nodeNumber) { return true; } else if (nodeNumber == n.nodeNumber) { if (voxelIJK[0] < n.voxelIJK[0]) { return true; } else if (voxelIJK[0] == n.voxelIJK[0]) { if (voxelIJK[1] < n.voxelIJK[1]) { return true; } else if (voxelIJK[1] == n.voxelIJK[1]) { if (voxelIJK[2] < n.voxelIJK[2]) { return true; } } } } return false; } }; /// Convert a brain model surface into a volume class BrainModelSurfaceToVolumeConverter : public BrainModelAlgorithm { public: /// conversion mode enum CONVERSION_MODE { CONVERT_TO_RGB_VOLUME_USING_NODE_COLORING, CONVERT_TO_ROI_VOLUME_USING_ROI_NODES, CONVERT_TO_ROI_VOLUME_USING_PAINT, CONVERT_TO_ROI_VOLUME_USING_METRIC_INTERPOLATE, CONVERT_TO_ROI_VOLUME_USING_METRIC_NO_INTERPOLATE, CONVERT_TO_ROI_VOLUME_USING_SURFACE_SHAPE, CONVERT_TO_SEGMENTATION_VOLUME_USING_NODES }; /// Constructor BrainModelSurfaceToVolumeConverter(BrainSet* bs, BrainModelSurface* surfaceIn, const StereotaxicSpace volumeSpaceHintIn, const float surfaceOffsetIn[3], const int volumeDimensionsIn[3], const float voxelSizeIn[3], const float volumeOriginIn[3], const float innerBoundaryIn, const float outerBoundaryIn, const float thicknessStepIn, const CONVERSION_MODE convertModeIn); /// Destructor ~BrainModelSurfaceToVolumeConverter(); /// set the node attribute (paint/metric/shape) column for ROI void setNodeAttributeColumn(const int column) { nodeAttributeColumn = column; } /// get the region of interest voxel value float getRegionOfInterestVoxelValue() const { return roiVoxelValue; } /// set the region of interest voxel value void setRegionOfInterestVoxelValue(const float val) { roiVoxelValue = val; } /// get node to voxel mapping enabled and file name void getNodeToVoxelMappingEnabled(bool& enabled, QString& fileName) const; /// set node to voxel mapping enabled and file name void setNodeToVoxelMappingEnabled(const bool enabled, const QString& fileName); /// execute the algorithm virtual void execute() throw (BrainModelAlgorithmException); /// get the volume that was created VolumeFile* getOutputVolume() { return volume; } private: /// perform conversion by intersecting tiles and voxels void conversionIntersectTilesAndVoxels() throw (BrainModelAlgorithmException); /// get the average rgb colors of three nodes void getTilesRgbColor(const int n1, const int n2, const int n3, float rgbFloat[3]); /// determine if a voxel index is valid bool getVoxelIndexValid(const int i, const int j, const int k) const; /// see if a triangle and a boxel intersect bool intersectTriangleWithVoxel(vtkTriangle* tri, float t1[3], float t2[3], float t3[3], const int ijk[3]); /// Resample the volume to a standard space. void resampleVolumeToStandardSpace(); /// surface being converted BrainModelSurface* surface; /// output volume VolumeFile* volume; /// volume standard space StereotaxicSpace volumeSpaceHint; /// coloring of surface's nodes BrainModelSurfaceNodeColoring* bsnc; /// surface's coordinate file CoordinateFile* cf; /// surface offset to place it into volume float surfaceOffset[3]; /// dimensions of output volume int volumeDimensions[3]; /// type of conversion CONVERSION_MODE conversionMode; /// flag to check is a voxel already has a value std::vector voxelSet; /// size of voxels float voxelSize[3]; /// origin of volume float volumeOrigin[3]; /// value for a region of interest voxel float roiVoxelValue; /// surface inner boundary float innerBoundary; /// surface outer boundary float outerBoundary; /// step when filling "thick" surface float thicknessStep; /// node attribute (metric/paint/shape) column for ROI int nodeAttributeColumn; /// total number of steps for progress dialog int progressDialogTotalSteps; /// current number of steps for progress dialog int progressDialogCurrentSteps; /// mapping of nodes to voxels std::set nodeToVoxelMapping; /// node to voxel mapping enabled bool nodeToVoxelMappingEnabled; /// node to voxel mapping file name QString nodeToVoxelMappingFileName; }; #endif // __BRAIN_MODEL_SURFACE_TO_VOLUME_CONVERTER_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceToVolumeConverter.cxx0000664000175000017500000016767511572067322027367 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #ifdef Q_OS_WIN32 #define NOMINMAX #endif #include #include #include #include #include #include #include "BrainModelSurface.h" #include "BrainModelSurfacePointProjector.h" #include "BrainModelSurfaceROINodeSelection.h" #include "BrainModelSurfaceToVolumeConverter.h" #include "BrainSet.h" #include "BrainModelSurfaceNodeColoring.h" #include "DebugControl.h" #include "MetricFile.h" #include "PaintFile.h" #include "SurfaceShapeFile.h" #include "vtkPolygon.h" #include "vtkTriangle.h" /** * Constructor. */ BrainModelSurfaceToVolumeConverter::BrainModelSurfaceToVolumeConverter( BrainSet* bs, BrainModelSurface* surfaceIn, const StereotaxicSpace volumeSpaceHintIn, const float surfaceOffsetIn[3], const int volumeDimensionsIn[3], const float voxelSizeIn[3], const float volumeOriginIn[3], const float innerBoundaryIn, const float outerBoundaryIn, const float thicknessStepIn, const CONVERSION_MODE convertModeIn) : BrainModelAlgorithm(bs) { progressDialogTotalSteps = 0; progressDialogCurrentSteps = 0; nodeToVoxelMappingEnabled = false; volumeSpaceHint = volumeSpaceHintIn; nodeAttributeColumn = 0; surface = surfaceIn; surfaceOffset[0] = surfaceOffsetIn[0]; surfaceOffset[1] = surfaceOffsetIn[1]; surfaceOffset[2] = surfaceOffsetIn[2]; volumeDimensions[0] = volumeDimensionsIn[0]; volumeDimensions[1] = volumeDimensionsIn[1]; volumeDimensions[2] = volumeDimensionsIn[2]; voxelSize[0] = voxelSizeIn[0]; voxelSize[1] = voxelSizeIn[1]; voxelSize[2] = voxelSizeIn[2]; volumeOrigin[0] = volumeOriginIn[0]; volumeOrigin[1] = volumeOriginIn[1]; volumeOrigin[2] = volumeOriginIn[2]; innerBoundary = innerBoundaryIn; outerBoundary = outerBoundaryIn; thicknessStep = thicknessStepIn; conversionMode = convertModeIn; roiVoxelValue = 255.0; // // set voxel dimensions and sizes for volumes that will // be resampled later. // switch(volumeSpaceHint.getSpace()) { case StereotaxicSpace::SPACE_UNKNOWN: break; case StereotaxicSpace::SPACE_OTHER: break; case StereotaxicSpace::SPACE_AFNI_TALAIRACH: break; case StereotaxicSpace::SPACE_FLIRT: break; case StereotaxicSpace::SPACE_FLIRT_222: break; case StereotaxicSpace::SPACE_MACAQUE_F6: break; case StereotaxicSpace::SPACE_MACAQUE_F99: break; case StereotaxicSpace::SPACE_MRITOTAL: break; case StereotaxicSpace::SPACE_SPM_99: break; case StereotaxicSpace::SPACE_SPM: break; case StereotaxicSpace::SPACE_SPM_95: break; case StereotaxicSpace::SPACE_SPM_96: break; case StereotaxicSpace::SPACE_SPM_2: break; case StereotaxicSpace::SPACE_SPM_5: break; case StereotaxicSpace::SPACE_T88: break; case StereotaxicSpace::SPACE_WU_7112B: case StereotaxicSpace::SPACE_WU_7112B_111: break; case StereotaxicSpace::SPACE_WU_7112B_222: volumeDimensions[0] = 256; volumeDimensions[1] = 256; volumeDimensions[2] = 150; voxelSize[0] = 1.0; voxelSize[1] = 1.0; voxelSize[2] = 1.0; break; case StereotaxicSpace::SPACE_WU_7112B_333: volumeDimensions[0] = 144; volumeDimensions[1] = 192; volumeDimensions[2] = 144; voxelSize[0] = 1.0; voxelSize[1] = 1.0; voxelSize[2] = 1.0; break; case StereotaxicSpace::SPACE_WU_7112C: case StereotaxicSpace::SPACE_WU_7112C_111: break; case StereotaxicSpace::SPACE_WU_7112C_222: volumeDimensions[0] = 256; volumeDimensions[1] = 256; volumeDimensions[2] = 150; voxelSize[0] = 1.0; voxelSize[1] = 1.0; voxelSize[2] = 1.0; break; case StereotaxicSpace::SPACE_WU_7112C_333: volumeDimensions[0] = 144; volumeDimensions[1] = 192; volumeDimensions[2] = 144; voxelSize[0] = 1.0; voxelSize[1] = 1.0; voxelSize[2] = 1.0; break; case StereotaxicSpace::SPACE_WU_7112O: case StereotaxicSpace::SPACE_WU_7112O_111: break; case StereotaxicSpace::SPACE_WU_7112O_222: volumeDimensions[0] = 256; volumeDimensions[1] = 256; volumeDimensions[2] = 150; voxelSize[0] = 1.0; voxelSize[1] = 1.0; voxelSize[2] = 1.0; break; case StereotaxicSpace::SPACE_WU_7112O_333: volumeDimensions[0] = 144; volumeDimensions[1] = 192; volumeDimensions[2] = 144; voxelSize[0] = 1.0; voxelSize[1] = 1.0; voxelSize[2] = 1.0; break; case StereotaxicSpace::SPACE_WU_7112Y: case StereotaxicSpace::SPACE_WU_7112Y_111: break; case StereotaxicSpace::SPACE_WU_7112Y_222: volumeDimensions[0] = 256; volumeDimensions[1] = 256; volumeDimensions[2] = 150; voxelSize[0] = 1.0; voxelSize[1] = 1.0; voxelSize[2] = 1.0; break; case StereotaxicSpace::SPACE_WU_7112Y_333: volumeDimensions[0] = 144; volumeDimensions[1] = 192; volumeDimensions[2] = 144; voxelSize[0] = 1.0; voxelSize[1] = 1.0; voxelSize[2] = 1.0; break; case StereotaxicSpace::SPACE_NUMBER_OF_SPACES: break; } } /** * Destructor. */ BrainModelSurfaceToVolumeConverter::~BrainModelSurfaceToVolumeConverter() { } /** * Execute. */ void BrainModelSurfaceToVolumeConverter::execute() throw (BrainModelAlgorithmException) { if ((volumeDimensions[0] <= 0) || (volumeDimensions[1] <= 0) || (volumeDimensions[2] <= 0)) { throw BrainModelAlgorithmException("Volume dimensions must be greater than zero."); } if ((voxelSize[0] <= 0.0) || (voxelSize[1] <= 0.0) || (voxelSize[2] <= 0.0)) { throw BrainModelAlgorithmException("Voxel sizes must be greater than zero."); } if (innerBoundary > outerBoundary) { throw BrainModelAlgorithmException("Inner boundary must be less than outer boundary."); } nodeToVoxelMapping.clear(); if (DebugControl::getDebugOn()) { std::cout << "Surface to Volume Converter:" << std::endl; std::cout << " Space: " << volumeSpaceHint.getName().toAscii().constData() << std::endl; std::cout << " Surface Offset: " << surfaceOffset[0] << ", " << surfaceOffset[1] << ", " << surfaceOffset[2] << std::endl; std::cout << " Volume Origin: " << volumeDimensions[0] << ", " << volumeDimensions[1] << ", " << volumeDimensions[2] << std::endl; std::cout << " Voxel Size: " << voxelSize[0] << ", " << voxelSize[1] << ", " << voxelSize[2] << std::endl; std::cout << " Origin: " << volumeOrigin[0] << ", " << volumeOrigin[1] << ", " << volumeOrigin[2] << std::endl; std::cout << " Inner Boundary: " << innerBoundary << std::endl; std::cout << " Outer Boundary: " << outerBoundary << std::endl; std::cout << " Thickness Step: " << thicknessStep << std::endl; } QTime timer; timer.start(); // // See if a progress dialog should be created // createProgressDialog("Converting Surface to Volume", 10, "surfaceToVolumeProgressDialog"); // // Create a volume // volume = new VolumeFile; // // the study meta data link // StudyMetaDataLinkSet studyMetaDataLinkSet; // // Set the type of volume and voxels // bool createSegmentationFlag = false; VolumeFile::VOXEL_DATA_TYPE voxelDataType = VolumeFile::VOXEL_DATA_TYPE_UNKNOWN; VolumeFile::VOLUME_TYPE volumeType = VolumeFile::VOLUME_TYPE_UNKNOWN; switch(conversionMode) { case CONVERT_TO_RGB_VOLUME_USING_NODE_COLORING: volumeType = VolumeFile::VOLUME_TYPE_RGB; voxelDataType = VolumeFile::VOXEL_DATA_TYPE_RGB_VOXEL_INTERLEAVED; break; case CONVERT_TO_ROI_VOLUME_USING_PAINT: volumeType = VolumeFile::VOLUME_TYPE_PAINT; voxelDataType = VolumeFile::VOXEL_DATA_TYPE_FLOAT; { PaintFile* pf = brainSet->getPaintFile(); if ((nodeAttributeColumn < 0) || (nodeAttributeColumn >= pf->getNumberOfColumns())) { removeProgressDialog(); throw BrainModelAlgorithmException("Invalid paint column"); } studyMetaDataLinkSet = pf->getColumnStudyMetaDataLinkSet(nodeAttributeColumn); } break; case CONVERT_TO_ROI_VOLUME_USING_METRIC_INTERPOLATE: case CONVERT_TO_ROI_VOLUME_USING_METRIC_NO_INTERPOLATE: volumeType = VolumeFile::VOLUME_TYPE_FUNCTIONAL; voxelDataType = VolumeFile::VOXEL_DATA_TYPE_FLOAT; { MetricFile* mf = brainSet->getMetricFile(); if ((nodeAttributeColumn < 0) || (nodeAttributeColumn >= mf->getNumberOfColumns())) { removeProgressDialog(); throw BrainModelAlgorithmException("Invalid metric column"); } studyMetaDataLinkSet = mf->getColumnStudyMetaDataLinkSet(nodeAttributeColumn); } break; case CONVERT_TO_ROI_VOLUME_USING_SURFACE_SHAPE: volumeType = VolumeFile::VOLUME_TYPE_FUNCTIONAL; voxelDataType = VolumeFile::VOXEL_DATA_TYPE_FLOAT; { SurfaceShapeFile* ssf = brainSet->getSurfaceShapeFile(); if ((nodeAttributeColumn < 0) || (nodeAttributeColumn >= ssf->getNumberOfColumns())) { removeProgressDialog(); throw BrainModelAlgorithmException("Invalid surface shape column"); } studyMetaDataLinkSet = ssf->getColumnStudyMetaDataLinkSet(nodeAttributeColumn); } break; case CONVERT_TO_ROI_VOLUME_USING_ROI_NODES: volumeType = VolumeFile::VOLUME_TYPE_SEGMENTATION; voxelDataType = VolumeFile::VOXEL_DATA_TYPE_FLOAT; break; case CONVERT_TO_SEGMENTATION_VOLUME_USING_NODES: volumeType = VolumeFile::VOLUME_TYPE_SEGMENTATION; voxelDataType = VolumeFile::VOXEL_DATA_TYPE_FLOAT; createSegmentationFlag = true; break; } // // Update/Create the volume // VolumeFile::ORIENTATION orient[3] = { VolumeFile::ORIENTATION_LEFT_TO_RIGHT, VolumeFile::ORIENTATION_POSTERIOR_TO_ANTERIOR, VolumeFile::ORIENTATION_INFERIOR_TO_SUPERIOR }; volume->initialize(voxelDataType, volumeDimensions, orient, volumeOrigin, voxelSize, false, true); volume->setVolumeType(volumeType); volume->setStudyMetaDataLinkSet(studyMetaDataLinkSet); const int numberOfVoxels = volume->getTotalNumberOfVoxels(); voxelSet.resize(numberOfVoxels, false); bsnc = brainSet->getNodeColoring(); const TopologyFile* tf = surface->getTopologyFile(); const int numTiles = tf->getNumberOfTiles(); const QString surfaceFileName(surface->getFileName()); try { // // Determing thickness of surfaces // const float thickness = outerBoundary - innerBoundary; // // Copy the user's surface since we don't want to modify it // BrainModelSurface thickSurface(*surface); surface = &thickSurface; cf = surface->getCoordinateFile(); // // Translate by half voxel // JWH Jun 14 // //TransformationMatrix tm; //tm.setTranslation(voxelSize[0] * 0.5, // voxelSize[1] * 0.5, // voxelSize[2] * 0.5); //thickSurface.applyTransformationMatrix(tm); // // Creating a segmentation volume ? if (createSegmentationFlag) { /* MOVE UP to 375 // // Copy the user's surface since we don't want to modify it // BrainModelSurface thickSurface(*surface); surface = &thickSurface; cf = surface->getCoordinateFile(); */ // // See if surface in native space // float bounds[6]; surface->getBounds(bounds); // // Guess at location inside surface // const float middleOfSurface[3] = { (bounds[0] + bounds[1]) * 0.5, (bounds[2] + bounds[3]) * 0.5, (bounds[4] + bounds[5]) * 0.5 }; // // Get the middle voxel // int middleIJK[3]; //volume->convertCoordinatesToVoxelIJK(insideSurface, middleIJK); volume->convertCoordinatesToVoxelIJK(middleOfSurface, middleIJK); // // Get the X voxel start and stop used to find interior voxel // int dim[3]; volume->getDimensions(dim); int startX = 0; int endX = dim[0] - 1; int deltaX = 1; switch (surface->getStructure().getType()) { case Structure::STRUCTURE_TYPE_CORTEX_LEFT: startX = dim[0] - 1; endX = 0; deltaX = -1; break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT: break; case Structure::STRUCTURE_TYPE_CORTEX_BOTH: case Structure::STRUCTURE_TYPE_CEREBELLUM: case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_LEFT: case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_RIGHT: case Structure::STRUCTURE_TYPE_CORTEX_LEFT_OR_CEREBELLUM: case Structure::STRUCTURE_TYPE_CORTEX_RIGHT_OR_CEREBELLUM: case Structure::STRUCTURE_TYPE_CEREBRUM_CEREBELLUM: case Structure::STRUCTURE_TYPE_SUBCORTICAL: case Structure::STRUCTURE_TYPE_ALL: case Structure::STRUCTURE_TYPE_INVALID: throw BrainModelAlgorithmException( "Coordinate/Surface \"" + surfaceFileName + " MUST have its structure set to " + "\"left\" or \"right\""); break; } // // Start at original surface and shrink until surface is closed // const float nodeDelta = -0.5; progressDialogTotalSteps = 3 * numTiles; for (int i = 1; i <= 20; i++) { // // Intersect volume with surface // conversionIntersectTilesAndVoxels(); // // Wait until few iterations until checking for a closed boundary // if (i >= 3) { // // Make a copy of the volume // VolumeFile volumeCopy(*volume); // // Find a voxel inside the volume // bool found = false; int seedVoxel[3] = { middleIJK[0], middleIJK[1], middleIJK[2], }; float lastVoxel = 0.0; for (int k = startX; k != endX; k += deltaX) { int ijk[3] = { k, middleIJK[1], middleIJK[2] }; const float newVoxel = volumeCopy.getVoxel(ijk); if (k == startX) { lastVoxel = newVoxel; } if ((newVoxel == 0.0) && (lastVoxel != 0.0)) { seedVoxel[0] = ijk[0]; seedVoxel[1] = ijk[1]; seedVoxel[2] = ijk[2]; found = true; break; } lastVoxel = newVoxel; } if (DebugControl::getDebugOn()) { std::cout << "Surface to Volume Inside volume seed: " << seedVoxel[0] << ", " << seedVoxel[1] << ", " << seedVoxel[2] << std::endl; } // // flood fill interior // //volumeCopy.convertCoordinatesToVoxelIJK(insideSurface, seedVoxel); const unsigned char red[4] = { 255, 0, 0, 1 }; volumeCopy.performSegmentationOperation(VolumeFile::SEGMENTATION_OPERATION_FLOOD_FILL_3D, VolumeFile::VOLUME_AXIS_Z, true, seedVoxel, seedVoxel, 255.0, red); // // If corner voxel not set, then surface outline in volume must be closed // if (volumeCopy.getVoxel(0, 0, 0) == 0) { volumeCopy.fillSegmentationCavities(); for (int j = 0; j < volume->getTotalNumberOfVoxelElements(); j++) { volume->setVoxelWithFlatIndex(j, 0, volumeCopy.getVoxelWithFlatIndex(j)); } break; } } surface->expandSurface(nodeDelta); } } else { if (thickness > 0.0) { /* MOVE UP to 375 // // Copy the user's surface since we don't want to modify it // BrainModelSurface thickSurface(*surface); surface = &thickSurface; cf = surface->getCoordinateFile(); */ // // Shrink nodes "inward" by half of thickness then // intersect and expand surface // float nodeDelta = innerBoundary; //-(thickness * 0.5); surface->expandSurface(nodeDelta); const int steps = static_cast(thickness / thicknessStep); progressDialogTotalSteps = (steps + 1) * numTiles; for (int i = 0; i <= steps; i++) { conversionIntersectTilesAndVoxels(); if (i < steps) { surface->expandSurface(thicknessStep); } } } else { progressDialogTotalSteps = numTiles; cf = surface->getCoordinateFile(); conversionIntersectTilesAndVoxels(); } } } catch (BrainModelAlgorithmException& e) { removeProgressDialog(); throw e; } switch(conversionMode) { case CONVERT_TO_RGB_VOLUME_USING_NODE_COLORING: break; case CONVERT_TO_ROI_VOLUME_USING_ROI_NODES: break; case CONVERT_TO_SEGMENTATION_VOLUME_USING_NODES: break; case CONVERT_TO_ROI_VOLUME_USING_PAINT: { // // Find out which paint names were used and add them to the ROI names // PaintFile* pf = brainSet->getPaintFile(); std::vector paintNamesUsed(pf->getNumberOfPaintNames(), 0); for (int i = 0; i < numberOfVoxels; i++) { const int index = static_cast(volume->getVoxelWithFlatIndex(i)); if (index > 0) { if (paintNamesUsed[index] == 0) { paintNamesUsed[index] = volume->addRegionName(pf->getPaintNameFromIndex(index)); } } } // // Update voxel values for updated region indices // for (int i = 0; i < numberOfVoxels; i++) { const int index = static_cast(volume->getVoxelWithFlatIndex(i)); if (index > 0) { volume->setVoxelWithFlatIndex(i, 0, static_cast(paintNamesUsed[index])); } } } break; case CONVERT_TO_ROI_VOLUME_USING_METRIC_INTERPOLATE: break; case CONVERT_TO_ROI_VOLUME_USING_METRIC_NO_INTERPOLATE: break; case CONVERT_TO_ROI_VOLUME_USING_SURFACE_SHAPE: break; } //if (DebugControl::getDebugOn()) { std::cout << "Time to create volume was " << (static_cast(timer.elapsed()) / 1000.0) << " seconds." << std::endl; //} switch(volumeSpaceHint.getSpace()) { case StereotaxicSpace::SPACE_UNKNOWN: break; case StereotaxicSpace::SPACE_OTHER: break; case StereotaxicSpace::SPACE_AFNI_TALAIRACH: break; case StereotaxicSpace::SPACE_FLIRT: break; case StereotaxicSpace::SPACE_FLIRT_222: break; case StereotaxicSpace::SPACE_MACAQUE_F6: break; case StereotaxicSpace::SPACE_MACAQUE_F99: break; case StereotaxicSpace::SPACE_MRITOTAL: break; case StereotaxicSpace::SPACE_SPM_99: break; case StereotaxicSpace::SPACE_SPM_2: break; case StereotaxicSpace::SPACE_SPM: break; case StereotaxicSpace::SPACE_SPM_95: break; case StereotaxicSpace::SPACE_SPM_96: break; case StereotaxicSpace::SPACE_SPM_5: break; case StereotaxicSpace::SPACE_T88: break; case StereotaxicSpace::SPACE_WU_7112B: case StereotaxicSpace::SPACE_WU_7112B_111: break; case StereotaxicSpace::SPACE_WU_7112B_222: resampleVolumeToStandardSpace(); break; case StereotaxicSpace::SPACE_WU_7112B_333: resampleVolumeToStandardSpace(); break; case StereotaxicSpace::SPACE_WU_7112C: case StereotaxicSpace::SPACE_WU_7112C_111: break; case StereotaxicSpace::SPACE_WU_7112C_222: resampleVolumeToStandardSpace(); break; case StereotaxicSpace::SPACE_WU_7112C_333: resampleVolumeToStandardSpace(); break; case StereotaxicSpace::SPACE_WU_7112O: case StereotaxicSpace::SPACE_WU_7112O_111: break; case StereotaxicSpace::SPACE_WU_7112O_222: resampleVolumeToStandardSpace(); break; case StereotaxicSpace::SPACE_WU_7112O_333: resampleVolumeToStandardSpace(); break; case StereotaxicSpace::SPACE_WU_7112Y: case StereotaxicSpace::SPACE_WU_7112Y_111: break; case StereotaxicSpace::SPACE_WU_7112Y_222: resampleVolumeToStandardSpace(); break; case StereotaxicSpace::SPACE_WU_7112Y_333: resampleVolumeToStandardSpace(); break; case StereotaxicSpace::SPACE_NUMBER_OF_SPACES: break; } QString comm("Volume intersected with surface: "); comm.append(surfaceFileName); comm.append("\n"); volume->appendToFileComment(comm); brainSet->addVolumeFile(volume->getVolumeType(), volume, "", true, false); if (volume->getVolumeType() == VolumeFile::VOLUME_TYPE_PROB_ATLAS) { brainSet->synchronizeProbAtlasVolumeRegionNames(); } if (nodeToVoxelMappingEnabled) { if (nodeToVoxelMappingFileName.isEmpty()) { nodeToVoxelMappingFileName = "node_to_voxel_mapping.txt"; } QFile file(nodeToVoxelMappingFileName); if (file.open(QIODevice::WriteOnly)) { QTextStream stream(&file); for (std::set::iterator iter = nodeToVoxelMapping.begin(); iter != nodeToVoxelMapping.end(); iter++) { const NodeToVoxelMapping nvm = *iter; stream << nvm.nodeNumber << " (" << nvm.voxelIJK[0] << ", " << nvm.voxelIJK[1] << ", " << nvm.voxelIJK[2] << ")" << "\n"; } file.close(); } } removeProgressDialog(); } /** * Resample the volume to a standard space. */ void BrainModelSurfaceToVolumeConverter::resampleVolumeToStandardSpace() { int voxelStep = 0; switch(volumeSpaceHint.getSpace()) { case StereotaxicSpace::SPACE_UNKNOWN: break; case StereotaxicSpace::SPACE_OTHER: break; case StereotaxicSpace::SPACE_AFNI_TALAIRACH: break; case StereotaxicSpace::SPACE_FLIRT: break; case StereotaxicSpace::SPACE_FLIRT_222: break; case StereotaxicSpace::SPACE_MACAQUE_F6: break; case StereotaxicSpace::SPACE_MACAQUE_F99: break; case StereotaxicSpace::SPACE_MRITOTAL: break; case StereotaxicSpace::SPACE_SPM_99: break; case StereotaxicSpace::SPACE_SPM_2: break; case StereotaxicSpace::SPACE_SPM: break; case StereotaxicSpace::SPACE_SPM_95: break; case StereotaxicSpace::SPACE_SPM_96: break; case StereotaxicSpace::SPACE_SPM_5: break; case StereotaxicSpace::SPACE_T88: break; case StereotaxicSpace::SPACE_WU_7112B: case StereotaxicSpace::SPACE_WU_7112B_111: break; case StereotaxicSpace::SPACE_WU_7112B_222: voxelStep = 2; break; case StereotaxicSpace::SPACE_WU_7112B_333: voxelStep = 3; break; case StereotaxicSpace::SPACE_WU_7112C: case StereotaxicSpace::SPACE_WU_7112C_111: break; case StereotaxicSpace::SPACE_WU_7112C_222: voxelStep = 2; break; case StereotaxicSpace::SPACE_WU_7112C_333: voxelStep = 3; break; case StereotaxicSpace::SPACE_WU_7112O: case StereotaxicSpace::SPACE_WU_7112O_111: break; case StereotaxicSpace::SPACE_WU_7112O_222: voxelStep = 2; break; case StereotaxicSpace::SPACE_WU_7112O_333: voxelStep = 3; break; case StereotaxicSpace::SPACE_WU_7112Y: case StereotaxicSpace::SPACE_WU_7112Y_111: break; case StereotaxicSpace::SPACE_WU_7112Y_222: voxelStep = 2; break; case StereotaxicSpace::SPACE_WU_7112Y_333: voxelStep = 3; break; case StereotaxicSpace::SPACE_NUMBER_OF_SPACES: break; } if (voxelStep <= 0) { return; } // // Half the number of voxels in the 111 surface when convert to new voxel size // const float halfVoxelCube = std::pow(static_cast(voxelStep), 3.0) * 0.5; // // Save current volume and create a new volume // VolumeFile* oldVolume = volume; volume = new VolumeFile(*volume); // // Set the new volumes parameters // float origin[3]; StereotaxicSpace theSpace(volumeSpaceHint); const QString name = theSpace.getName(); theSpace.getDimensions(volumeDimensions); theSpace.getOrigin(origin); theSpace.getVoxelSize(voxelSize); VolumeFile::ORIENTATION orient[3]; oldVolume->getOrientation(orient); volume->initialize(oldVolume->getVoxelDataType(), volumeDimensions, orient, origin, voxelSize); volume->setVolumeType(oldVolume->getVolumeType()); // // Copy the region names // volume->deleteAllRegionNames(); for (int i = 0; i < oldVolume->getNumberOfRegionNames(); i++) { volume->addRegionName(oldVolume->getRegionNameFromIndex(i)); } // // Get access to old voxels // const int oldNumberOfScalars = oldVolume->getTotalNumberOfVoxels(); if (oldNumberOfScalars == 0) { return; } // // loop through dimensions of new volume // for (int i = 0; i < volumeDimensions[0]; i++) { for (int j = 0; j < volumeDimensions[1]; j++) { for (int k = 0; k < volumeDimensions[2]; k++) { float voxelCount = 0.0; float sumRed = 0.0; float sumGreen = 0.0; float sumBlue = 0.0; std::map usedPaints; float sumMetric = 0.0; float sumSurfaceShape = 0.0; for (int ii = (i * voxelStep); ii < (i * voxelStep + voxelStep); ii++) { for (int jj = (j * voxelStep); jj < (j * voxelStep + voxelStep); jj++) { for (int kk = (k * voxelStep); kk < (k * voxelStep + voxelStep); kk++) { switch(conversionMode) { case CONVERT_TO_RGB_VOLUME_USING_NODE_COLORING: { const float red = oldVolume->getVoxel(ii, jj, kk, 0); const float green = oldVolume->getVoxel(ii, jj, kk, 1); const float blue = oldVolume->getVoxel(ii, jj, kk, 2); if ((red > 0.0) || (green > 0.0) || (blue > 0.0)) { sumRed += red; sumGreen += green; sumBlue += blue; voxelCount += 1.0; } } break; case CONVERT_TO_ROI_VOLUME_USING_PAINT: { const int paintIndex = static_cast(oldVolume->getVoxel(ii, jj, kk)); if (paintIndex > 0) { usedPaints[paintIndex]++; voxelCount += 1.0; } } break; case CONVERT_TO_ROI_VOLUME_USING_METRIC_INTERPOLATE: { const float value = oldVolume->getVoxel(ii, jj, kk); if (value != 0.0) { sumMetric += value; voxelCount += 1.0; } } break; case CONVERT_TO_ROI_VOLUME_USING_METRIC_NO_INTERPOLATE: { const float value = oldVolume->getVoxel(ii, jj, kk); if (value != 0.0) { if (value > sumMetric) { sumMetric = value; voxelCount = 1.0; // NOT INTERPOLATING } } } break; case CONVERT_TO_ROI_VOLUME_USING_SURFACE_SHAPE: { const float value = oldVolume->getVoxel(ii, jj, kk); if (value != 0.0) { sumSurfaceShape += value; voxelCount += 1.0; } } break; case CONVERT_TO_ROI_VOLUME_USING_ROI_NODES: if (oldVolume->getVoxel(ii, jj, kk) > 0) { voxelCount += 1.0; } break; case CONVERT_TO_SEGMENTATION_VOLUME_USING_NODES: if (oldVolume->getVoxel(ii, jj, kk) > 0) { voxelCount += 1.0; } break; } } // kk } // jj } // ii // // Are enough voxels set ? // switch(conversionMode) { case CONVERT_TO_RGB_VOLUME_USING_NODE_COLORING: if (voxelCount >= halfVoxelCube) { volume->setVoxel(i, j, k, 0, (sumRed / voxelCount)); volume->setVoxel(i, j, k, 1, (sumGreen / voxelCount)); volume->setVoxel(i, j, k, 2, (sumBlue / voxelCount)); } else { volume->setVoxel(i, j, k, 0, 0.0); volume->setVoxel(i, j, k, 1, 0.0); volume->setVoxel(i, j, k, 2, 0.0); } break; case CONVERT_TO_ROI_VOLUME_USING_PAINT: if (voxelCount >= halfVoxelCube) { int mostUsedIndex = -1; int mostUsedQuantity = 0; for (std::map::iterator iter = usedPaints.begin(); iter != usedPaints.end(); iter++) { if (iter->second > mostUsedQuantity) { mostUsedQuantity = iter->second; mostUsedIndex = iter->first; } } volume->setVoxel(i, j, k, 0, mostUsedIndex); } else { volume->setVoxel(i, j, k, 0, 0.0); } break; case CONVERT_TO_ROI_VOLUME_USING_ROI_NODES: if (voxelCount >= halfVoxelCube) { volume->setVoxel(i, j, k, 0, roiVoxelValue); } else { volume->setVoxel(i, j, k, 0, 0.0); } break; case CONVERT_TO_SEGMENTATION_VOLUME_USING_NODES: if (voxelCount >= halfVoxelCube) { volume->setVoxel(i, j, k, 0, roiVoxelValue); } else { volume->setVoxel(i, j, k, 0, 0.0); } break; case CONVERT_TO_ROI_VOLUME_USING_METRIC_INTERPOLATE: if (voxelCount >= halfVoxelCube) { volume->setVoxel(i, j, k, 0, sumMetric / voxelCount); } else { volume->setVoxel(i, j, k, 0, 0.0); } break; case CONVERT_TO_ROI_VOLUME_USING_METRIC_NO_INTERPOLATE: if (voxelCount > 0) { volume->setVoxel(i, j, k, 0, sumMetric / voxelCount); } else { volume->setVoxel(i, j, k, 0, 0.0); } break; case CONVERT_TO_ROI_VOLUME_USING_SURFACE_SHAPE: if (voxelCount >= halfVoxelCube) { volume->setVoxel(i, j, k, 0, sumSurfaceShape / voxelCount); } else { volume->setVoxel(i, j, k, 0, 0.0); } break; } } // k } // j } // i // // Get rid of the old volume // delete oldVolume; } /** * Perform conversion by intersecting voxels and tiles. */ void BrainModelSurfaceToVolumeConverter::conversionIntersectTilesAndVoxels() throw (BrainModelAlgorithmException) { const TopologyFile* tf = surface->getTopologyFile(); const int numTiles = tf->getNumberOfTiles(); PaintFile* paintFile = brainSet->getPaintFile(); MetricFile* metricFile = brainSet->getMetricFile(); SurfaceShapeFile* surfaceShapeFile = brainSet->getSurfaceShapeFile(); const BrainModelSurfaceROINodeSelection* surfaceROI = brainSet->getBrainModelSurfaceRegionOfInterestNodeSelection(); for (int m = 0; m < numTiles; m++) { // // Get the nodes in the tiles // int n1, n2, n3; tf->getTile(m, n1, n2, n3); bool useTile = false; float rgbFloat[3] = { 0.0, 0.0, 0.0 }; int paintIndex = 0; float metricValue = 0.0; float surfaceShapeValue = 0.0; switch(conversionMode) { case CONVERT_TO_RGB_VOLUME_USING_NODE_COLORING: // // If converting to RGB, get color for tile // getTilesRgbColor(n1, n2, n3, rgbFloat); useTile = true; break; case CONVERT_TO_ROI_VOLUME_USING_ROI_NODES: // // See if any of the tile's nodes are part of the query // { if (surfaceROI->getNodeSelected(n1) || surfaceROI->getNodeSelected(n2) || surfaceROI->getNodeSelected(n3)) { useTile = true; } } break; case CONVERT_TO_SEGMENTATION_VOLUME_USING_NODES: // // Use all tiles // useTile = true; break; case CONVERT_TO_ROI_VOLUME_USING_PAINT: { // // Get paint indices for the nodes of the tile // const int p1 = paintFile->getPaint(n1, nodeAttributeColumn); const int p2 = paintFile->getPaint(n2, nodeAttributeColumn); const int p3 = paintFile->getPaint(n3, nodeAttributeColumn); // // Do any of the nodes have valid paint indices // if ((p1 > 0) || (p2 > 0) || (p3 > 0)) { // // Use the tile and find a paint index to use for the tile // useTile = true; if (p1 == p2) { paintIndex = p1; } else if (p1 == p3) { paintIndex = p1; } else if (p2 == p3) { paintIndex = p2; } else if (p1 > 0) { paintIndex = p1; } else if (p2 > 0) { paintIndex = p2; } else if (p3 > 0) { paintIndex = p3; } else { useTile = false; } } } break; case CONVERT_TO_ROI_VOLUME_USING_METRIC_INTERPOLATE: metricValue = (metricFile->getValue(n1, nodeAttributeColumn) + metricFile->getValue(n2, nodeAttributeColumn) + metricFile->getValue(n3, nodeAttributeColumn)) / 3.0; useTile = true; break; case CONVERT_TO_ROI_VOLUME_USING_METRIC_NO_INTERPOLATE: metricValue = std::max(metricFile->getValue(n1, nodeAttributeColumn), std::max(metricFile->getValue(n2, nodeAttributeColumn), metricFile->getValue(n3, nodeAttributeColumn))); useTile = true; break; case CONVERT_TO_ROI_VOLUME_USING_SURFACE_SHAPE: surfaceShapeValue = (surfaceShapeFile->getValue(n1, nodeAttributeColumn) + surfaceShapeFile->getValue(n2, nodeAttributeColumn) + surfaceShapeFile->getValue(n3, nodeAttributeColumn)) / 3.0; useTile = true; break; } if (useTile) { // // Get the coordinates of the tile's nodes // float v1[3], v2[3], v3[3]; cf->getCoordinate(n1, v1); cf->getCoordinate(n2, v2); cf->getCoordinate(n3, v3); // // Add the offsets to each node // for (int j = 0; j < 3; j++) { v1[j] += surfaceOffset[j]; v2[j] += surfaceOffset[j]; v3[j] += surfaceOffset[j]; } // // Min and Max of coordinates // float minCoord[3]; minCoord[0] = std::min(v1[0], std::min(v2[0], v3[0])); minCoord[1] = std::min(v1[1], std::min(v2[1], v3[1])); minCoord[2] = std::min(v1[2], std::min(v2[2], v3[2])); float maxCoord[3]; maxCoord[0] = std::max(v1[0], std::max(v2[0], v3[0])); maxCoord[1] = std::max(v1[1], std::max(v2[1], v3[1])); maxCoord[2] = std::max(v1[2], std::max(v2[2], v3[2])); // // Convert the min & max of the coordinates into voxel indices // ComputeStructuredCoordinates returns 0 if not in the volume // int minIJK[3]; int maxIJK[3]; float pcoords[3]; if ((volume->convertCoordinatesToVoxelIJK(minCoord, minIJK, pcoords) != 0) && (volume->convertCoordinatesToVoxelIJK(maxCoord, maxIJK, pcoords) != 0)) { const int minX = minIJK[0]; const int minY = minIJK[1]; const int minZ = minIJK[2]; const int maxX = maxIJK[0]; const int maxY = maxIJK[1]; const int maxZ = maxIJK[2]; // // All nodes withing the same voxel ? // if ((minX == maxX) && (minY == maxY) && (minZ == maxZ)) { int ijk[3] = { minX, minY, minZ }; // // Keep track of node voxel assignments // if (nodeToVoxelMappingEnabled) { nodeToVoxelMapping.insert(NodeToVoxelMapping(n1, ijk)); nodeToVoxelMapping.insert(NodeToVoxelMapping(n2, ijk)); nodeToVoxelMapping.insert(NodeToVoxelMapping(n3, ijk)); } const int voxNum = volume->getVoxelNumber(ijk); if (voxelSet[voxNum] == false) { voxelSet[voxNum] = true; switch(conversionMode) { case CONVERT_TO_RGB_VOLUME_USING_NODE_COLORING: volume->setVoxel(ijk, 0, rgbFloat[0]); volume->setVoxel(ijk, 1, rgbFloat[1]); volume->setVoxel(ijk, 2, rgbFloat[2]); break; case CONVERT_TO_ROI_VOLUME_USING_ROI_NODES: volume->setVoxel(ijk, 0, roiVoxelValue); break; case CONVERT_TO_SEGMENTATION_VOLUME_USING_NODES: volume->setVoxel(ijk, 0, roiVoxelValue); break; case CONVERT_TO_ROI_VOLUME_USING_PAINT: volume->setVoxel(ijk, 0, paintIndex); break; case CONVERT_TO_ROI_VOLUME_USING_METRIC_INTERPOLATE: volume->setVoxel(ijk, 0, metricValue); break; case CONVERT_TO_ROI_VOLUME_USING_METRIC_NO_INTERPOLATE: volume->setVoxel(ijk, 0, metricValue); break; case CONVERT_TO_ROI_VOLUME_USING_SURFACE_SHAPE: volume->setVoxel(ijk, 0, surfaceShapeValue); break; } } } else { // // First, set the voxel that each of the nodes falls within // for (int j = 0; j < 3; j++) { float* xyz = NULL; switch(j) { case 0: xyz = v1; break; case 1: xyz = v2; break; case 2: xyz = v3; break; } if (xyz != NULL) { int ijk[3]; float pcoords[3]; if (volume->convertCoordinatesToVoxelIJK(xyz, ijk, pcoords) != 0) { // // Keep track of node voxel assignments // if (nodeToVoxelMappingEnabled) { nodeToVoxelMapping.insert(NodeToVoxelMapping(n1, ijk)); nodeToVoxelMapping.insert(NodeToVoxelMapping(n2, ijk)); nodeToVoxelMapping.insert(NodeToVoxelMapping(n3, ijk)); } const int voxNum = volume->getVoxelNumber(ijk); if (voxelSet[voxNum] == false) { voxelSet[voxNum] = true; switch(conversionMode) { case CONVERT_TO_RGB_VOLUME_USING_NODE_COLORING: volume->setVoxel(ijk, 0, rgbFloat[0]); volume->setVoxel(ijk, 1, rgbFloat[1]); volume->setVoxel(ijk, 2, rgbFloat[2]); break; case CONVERT_TO_ROI_VOLUME_USING_ROI_NODES: volume->setVoxel(ijk, 0, roiVoxelValue); break; case CONVERT_TO_SEGMENTATION_VOLUME_USING_NODES: volume->setVoxel(ijk, 0, roiVoxelValue); break; case CONVERT_TO_ROI_VOLUME_USING_PAINT: volume->setVoxel(ijk, 0, paintIndex); break; case CONVERT_TO_ROI_VOLUME_USING_METRIC_INTERPOLATE: volume->setVoxel(ijk, 0, metricValue); break; case CONVERT_TO_ROI_VOLUME_USING_METRIC_NO_INTERPOLATE: volume->setVoxel(ijk, 0, metricValue); break; case CONVERT_TO_ROI_VOLUME_USING_SURFACE_SHAPE: volume->setVoxel(ijk, 0, surfaceShapeValue); break; } } } } } // // Create a vtkTriangle and see if voxel edges pass through it // vtkPoints* pts = vtkPoints::New(); pts->SetNumberOfPoints(3); pts->InsertPoint(0, v1); pts->InsertPoint(1, v2); pts->InsertPoint(2, v3); vtkIdType ids[3] = { 0, 1, 2 }; vtkTriangle* triangle = vtkTriangle::New(); triangle->Initialize(3, ids, pts); for (int k = minZ; k <= maxZ; k++) { for (int j = minY; j <= maxY; j++) { for (int i = minX; i <= maxX; i++) { int ijk[3] = { i, j, k }; const int voxNum = volume->getVoxelNumber(i, j, k); if (voxelSet[voxNum] == false) { if (intersectTriangleWithVoxel(triangle, v1, v2, v3, ijk)) { voxelSet[voxNum] = true; switch(conversionMode) { case CONVERT_TO_RGB_VOLUME_USING_NODE_COLORING: volume->setVoxel(ijk, 0, rgbFloat[0]); volume->setVoxel(ijk, 1, rgbFloat[1]); volume->setVoxel(ijk, 2, rgbFloat[2]); break; case CONVERT_TO_ROI_VOLUME_USING_ROI_NODES: volume->setVoxel(ijk, 0, roiVoxelValue); break; case CONVERT_TO_SEGMENTATION_VOLUME_USING_NODES: volume->setVoxel(ijk, 0, roiVoxelValue); break; case CONVERT_TO_ROI_VOLUME_USING_PAINT: volume->setVoxel(ijk, 0, paintIndex); break; case CONVERT_TO_ROI_VOLUME_USING_METRIC_INTERPOLATE: volume->setVoxel(ijk, 0, metricValue); break; case CONVERT_TO_ROI_VOLUME_USING_METRIC_NO_INTERPOLATE: volume->setVoxel(ijk, 0, metricValue); break; case CONVERT_TO_ROI_VOLUME_USING_SURFACE_SHAPE: volume->setVoxel(ijk, 0, surfaceShapeValue); break; } // // Keep track of node voxel assignments // if (nodeToVoxelMappingEnabled) { nodeToVoxelMapping.insert(NodeToVoxelMapping(n1, ijk)); nodeToVoxelMapping.insert(NodeToVoxelMapping(n2, ijk)); nodeToVoxelMapping.insert(NodeToVoxelMapping(n3, ijk)); } } } else { // if (voxelSet[pointID]) // // Keep track of node voxel assignments. // Note: Voxel has already been set so its check is skipped above // but just see if the tile also intersects this voxel. // if (nodeToVoxelMappingEnabled) { if (intersectTriangleWithVoxel(triangle, v1, v2, v3, ijk)) { nodeToVoxelMapping.insert(NodeToVoxelMapping(n1, ijk)); nodeToVoxelMapping.insert(NodeToVoxelMapping(n2, ijk)); nodeToVoxelMapping.insert(NodeToVoxelMapping(n3, ijk)); } } } } } } triangle->Delete(); pts->Delete(); } } // ComputeStructuredCoordinates } // if (useTile) // // Update progress dialog // if (m > 0) { const int stepInterval = 1000; if ((m % stepInterval) == 0) { progressDialogCurrentSteps += stepInterval; int percent = static_cast( 100.0 * (static_cast(progressDialogCurrentSteps) / static_cast(progressDialogTotalSteps))); if (percent > 99) { percent = 99; } QString text = QString("%1% Complete.").arg(percent); updateProgressDialog(text, progressDialogCurrentSteps, progressDialogTotalSteps); } } } // for } /** * See if a triangle and a voxel intersect. */ bool BrainModelSurfaceToVolumeConverter::intersectTriangleWithVoxel(vtkTriangle* triangle, float t1In[3], float t2In[3], float t3In[3], const int ijk[3]) { #ifdef HAVE_VTK5 double t1[3] = { t1In[0], t1In[1], t1In[2] }; double t2[3] = { t2In[0], t2In[1], t2In[2] }; double t3[3] = { t3In[0], t3In[1], t3In[2] }; #else // HAVE_VTK5 float t1[3] = { t1In[0], t1In[1], t1In[2] }; float t2[3] = { t2In[0], t2In[1], t2In[2] }; float t3[3] = { t3In[0], t3In[1], t3In[2] }; #endif // HAVE_VTK5 const float tolerance = 0.01; // // Voxel sizes // const float dx = voxelSize[0]; const float dy = voxelSize[1]; const float dz = voxelSize[2]; // // Convert the volume index into a coordinate // coordinate returned is center of voxel so adjust to get corner // float xyzCenter[3]; volume->getVoxelCoordinate(ijk, xyzCenter); const float xyz[3] = { xyzCenter[0] - (dx * 0.5), xyzCenter[1] - (dy * 0.5), xyzCenter[2] - (dz * 0.5) }; // // Vertices of the voxel, Lower and Upper // float al[] = { xyz[0], xyz[1], xyz[2] }; float bl[] = { xyz[0] + dx, xyz[1], xyz[2] }; float cl[] = { xyz[0] + dx, xyz[1] + dy, xyz[2] }; float dl[] = { xyz[0], xyz[1] + dy, xyz[2] }; float au[] = { xyz[0], xyz[1], xyz[2] + dz }; float bu[] = { xyz[0] + dx, xyz[1], xyz[2] + dz }; float cu[] = { xyz[0] + dx, xyz[1] + dy, xyz[2] + dz }; float du[] = { xyz[0], xyz[1] + dy, xyz[2] + dz }; // // Test all 12 voxel edges for intersection with the triangle // for (int i = 0; i < 12; i++) { float *p1 = NULL, *p2 = NULL; switch(i) { case 0: p1 = al; p2 = bl; break; case 1: p1 = bl; p2 = cl; break; case 2: p1 = cl; p2 = dl; break; case 3: p1 = dl; p2 = al; break; case 4: p1 = au; p2 = bu; break; case 5: p1 = bu; p2 = cu; break; case 6: p1 = cu; p2 = du; break; case 7: p1 = du; p2 = au; break; case 8: p1 = al; p2 = au; break; case 9: p1 = bl; p2 = bu; break; case 10: p1 = cl; p2 = cu; break; case 11: p1 = dl; p2 = du; break; } int subid; #ifdef HAVE_VTK5 double t, x[3], pcoords[3]; double p1d[3] = { p1[0], p1[1], p1[2] }; double p2d[3] = { p2[0], p2[1], p2[2] }; double toleranced = tolerance; if (triangle->IntersectWithLine(p1d, p2d, toleranced, t, x, pcoords, subid) != 0) { #else // HAVE_VTK5 float t, x[3], pcoords[3]; if (triangle->IntersectWithLine(p1, p2, tolerance, t, x, pcoords, subid) != 0) { #endif // HAVE_VTK5 if ((t >= 0.0) && (t <= 1.0)) { return true; } } } // // Test triangle edges for intersection with voxel faces // for (int i = 0; i < 6; i++) { float *p1 = NULL, *p2 = NULL, *p3 = NULL, *p4 = NULL; switch(i) { case 0: p1 = al; p2 = bl; p3 = cl; p4 = dl; break; case 1: p1 = au; p2 = bu; p3 = cu; p4 = du; break; case 2: p1 = al; p2 = bl; p3 = bu; p4 = au; break; case 3: p1 = bl; p2 = cl; p3 = cu; p4 = bu; break; case 4: p1 = cl; p2 = dl; p3 = du; p4 = cu; break; case 5: p1 = dl; p2 = al; p3 = au; p4 = du; break; } // // Create a vtkPolygon of voxel face and see if triangle edges pass through it // vtkPoints* pts = vtkPoints::New(); pts->SetNumberOfPoints(4); pts->InsertPoint(0, p1); pts->InsertPoint(1, p2); pts->InsertPoint(2, p3); pts->InsertPoint(3, p4); vtkIdType ids[4] = { 0, 1, 2, 3 }; vtkPolygon* polygon = vtkPolygon::New(); polygon->Initialize(4, ids, pts); #ifdef HAVE_VTK5 double t, x[3], pcoords[3]; #else // HAVE_VTK5 float t, x[3], pcoords[3]; #endif // HAVE_VTK5 int subid; bool found = false; double toleranced = tolerance; if (polygon->IntersectWithLine(t1, t2, toleranced, t, x, pcoords, subid) != 0) { if ((t >= 0.0) && (t <= 1.0)) { found = true; } } if (found == false) { if (polygon->IntersectWithLine(t2, t3, toleranced, t, x, pcoords, subid) != 0) { if ((t >= 0.0) && (t <= 1.0)) { found = true; } } if (found == false) { if (polygon->IntersectWithLine(t3, t1, toleranced, t, x, pcoords, subid) != 0) { if ((t >= 0.0) && (t <= 1.0)) { found = true; } } } } polygon->Delete(); pts->Delete(); if (found) { return true; } } return false; } /** * Determine if a voxel index is valid */ bool BrainModelSurfaceToVolumeConverter::getVoxelIndexValid(const int i, const int j, const int k) const { if ((i >= 0) && (i < volumeDimensions[0]) && (j >= 0) && (j < volumeDimensions[1]) && (k >= 0) && (k < volumeDimensions[2])) { return true; } return false; } /** * Get the RGB average of a tile's nodes. */ void BrainModelSurfaceToVolumeConverter::getTilesRgbColor(const int n1, const int n2, const int n3, float rgbFloat[3]) { const float float255 = 255.0; // // Average the RGB values from the three nodes of the tile // const int modelNumber = surface->getBrainModelIndex(); const unsigned char* rgb1 = bsnc->getNodeColor(modelNumber, n1); const unsigned char* rgb2 = bsnc->getNodeColor(modelNumber, n2); const unsigned char* rgb3 = bsnc->getNodeColor(modelNumber, n3); rgbFloat[0] = (static_cast(rgb1[0]) + static_cast(rgb2[0]) + static_cast(rgb3[0])) / 3.0; rgbFloat[1] = (static_cast(rgb1[1]) + static_cast(rgb2[1]) + static_cast(rgb3[1])) / 3.0; rgbFloat[2] = (static_cast(rgb1[2]) + static_cast(rgb2[2]) + static_cast(rgb3[2])) / 3.0; rgbFloat[0] = std::min(rgbFloat[0], float255); rgbFloat[1] = std::min(rgbFloat[1], float255); rgbFloat[2] = std::min(rgbFloat[2], float255); } /** * get node to voxel mapping enabled and file name. */ void BrainModelSurfaceToVolumeConverter::getNodeToVoxelMappingEnabled(bool& enabled, QString& fileName) const { enabled = nodeToVoxelMappingEnabled; fileName = nodeToVoxelMappingFileName; } /** * set node to voxel mapping enabled and file name. */ void BrainModelSurfaceToVolumeConverter::setNodeToVoxelMappingEnabled(const bool enabled, const QString& fileName) { nodeToVoxelMappingEnabled = enabled; nodeToVoxelMappingFileName = fileName; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceSulcalIdentificationProbabilistic.h0000664000175000017500000002017111572067322032131 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_SULCAL_IDENTIFICATION_PROBABILISTIC_H__ #define __BRAIN_MODEL_SURFACE_SULCAL_IDENTIFICATION_PROBABILISTIC_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelAlgorithm.h" class AreaColorFile; class BrainModelSurface; class MetricFile; class PaintFile; class SurfaceShapeFile; class VocabularyFile; /// class for identifying sulci class BrainModelSurfaceSulcalIdentificationProbabilistic : public BrainModelAlgorithm { public: // constructor BrainModelSurfaceSulcalIdentificationProbabilistic(BrainSet* bs, const BrainModelSurface* fiducialSurfaceIn, const BrainModelSurface* inflatedSurfaceIn, const BrainModelSurface* veryInflatedSurfaceIn, const PaintFile* inputPaintFileIn, const int paintFileGeographyColumnNumberIn, const SurfaceShapeFile* surfaceShapeFileIn, const int surfaceShapeFileDepthColumnNumberIn, const QString& probabilisticDepthVolumeCSVFileNameIn, const float postCentralSulcusOffsetIn = 25.0, const float postCentralSulcusStdDevSquareIn = 100.0, const float postCentralSulcusSplitIn = 5.0); // destructor ~BrainModelSurfaceSulcalIdentificationProbabilistic(); // execute the algorithm void execute() throw (BrainModelAlgorithmException); // get the output paint file (will be delete'd by this algorithm, so copy if needed) const PaintFile* getOutputPaintFile() const { return outputPaintFile; } // get the output area color file const AreaColorFile* getOutputAreaColorFile() const { return outputAreaColorFile; } // get the output metric file containing probabilistic mappings const MetricFile* getOutputMetricFile() const { return probabilisticMetricFile; } // get the output vocabulary file const VocabularyFile* getOutputVocabularyFile() const { return outputVocabularyFile; } /// get the name of the Sulcus ID paint column static QString getSulcusIdPaintColumnName() { return "Sulcal Identification"; } protected: /// class for sulcal names and matching volume file class SulcalNameAndVolume { public: /// constructor SulcalNameAndVolume(const QString& sulcusNameIn, const float& depthThresholdIn, const QString& volumeNameIn, const int maximumClustersIn) { sulcusName = sulcusNameIn; depthThreshold = depthThresholdIn; volumeName = volumeNameIn; maximumClusters = maximumClustersIn; } /// get name of sulcus QString getSulcusName() const { return sulcusName; } /// get the depth threshold float getDepthThreshold() const { return depthThreshold; } /// get name of volume QString getVolumeName() const { return volumeName; } /// get the maximum number of clusters int getMaximumClusters() const { return maximumClusters; } protected: /// name of sulcus QString sulcusName; /// depth threshold float depthThreshold; /// name of volume QString volumeName; /// maximum clusters int maximumClusters; }; /// add an area color void addAreaColor(const QString& colorName); // load the colors void loadColors(); // load vocabulary void loadVocabulary(); // add casename to name QString addCaseNameToName(const QString& name) const; // add vocabulary void addVocabulary(const QString& name); // map the probabilistic functional volumes to the metric file void mapProbabilisticFunctionalVolumes() throw (BrainModelAlgorithmException); // create the initial sulcal identification void createInitialSulcalIdentification(const int paintColumn) throw (BrainModelAlgorithmException); // dilate the sulcal identification void dilateSulcalIdentification(const int paintColumn) throw (BrainModelAlgorithmException); // read the probabilistic volume file list void readProbabilisticVolumeFileList() throw (BrainModelAlgorithmException); // multiply probabilistic volumes by depth void multiplyProbabilisticFunctionalDataByDepth() throw (BrainModelAlgorithmException); // rotate the very inflated surface void rotateVeryInflatedSurface() throw (BrainModelAlgorithmException); // special process for the hippocampal fissure void specialProcessingForHippocampalFissure(MetricFile* metricFile, const int metricFileColumnNumber); /// sulcal names and volumes std::vector sulcalNamesAndVolumes; /// the fiducial surface const BrainModelSurface* fiducialSurface; /// the inflated surface const BrainModelSurface* inflatedSurface; /// the very inflated surface const BrainModelSurface* veryInflatedSurface; /// the rotated very inflated surface BrainModelSurface* rotatedVeryInflatedSurface; /// the input paint file const PaintFile* inputPaintFile; /// the output paint file PaintFile* outputPaintFile; /// the metric file for mapping functional probabilistic volumes MetricFile* probabilisticMetricFile; /// the paint file geography column number int paintFileGeographyColumnNumber; /// the output area color file AreaColorFile* outputAreaColorFile; /// the default area colors AreaColorFile* defaultAreaColorFile; /// the surface shape file const SurfaceShapeFile* surfaceShapeFile; /// the surface shape file depth column number int surfaceShapeFileDepthColumnNumber; /// output vocabulary file VocabularyFile* outputVocabularyFile; /// default vocabulary file VocabularyFile* defaultVocabularyFile; /// name of file listing sulcal names, depth thresholds, and volume file names const QString probabilisticDepthVolumeCSVFileName; /// post central sulcus offset from central sulcus const float postCentralSulcusOffset; /// post central sulcus offset from central sulcus std dev squared const float postCentralSulcusStdDevSquare; /// post central sulcus split between two largest post central sulci const float postCentralSulcusSplit; /// flag to add some default colors bool addingFirstColorFlag; }; #endif // __BRAIN_MODEL_SURFACE_SULCAL_IDENTIFICATION_PROBABILISTIC_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceSulcalIdentificationProbabilistic.cxx0000664000175000017500000013337011572067322032512 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include "AreaColorFile.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceMetricClustering.h" #include "BrainModelSurfaceROINodeSelection.h" #include "BrainModelSurfaceSulcalIdentificationProbabilistic.h" #include "BrainModelVolumeToSurfaceMapperAlgorithmParameters.h" #include "BrainModelVolumeToSurfaceMapper.h" #include "BrainSet.h" #include "CommaSeparatedValueFile.h" #include "DebugControl.h" #include "FileUtilities.h" #include "MathUtilities.h" #include "MetricFile.h" #include "PaintFile.h" #include "StringTable.h" #include "SurfaceShapeFile.h" #include "ValueIndexSort.h" #include "VocabularyFile.h" /** * constructor. */ BrainModelSurfaceSulcalIdentificationProbabilistic::BrainModelSurfaceSulcalIdentificationProbabilistic( BrainSet* bs, const BrainModelSurface* fiducialSurfaceIn, const BrainModelSurface* inflatedSurfaceIn, const BrainModelSurface* veryInflatedSurfaceIn, const PaintFile* inputPaintFileIn, const int paintFileGeographyColumnNumberIn, const SurfaceShapeFile* surfaceShapeFileIn, const int surfaceShapeFileDepthColumnNumberIn, const QString& probabilisticDepthVolumeCSVFileNameIn, const float postCentralSulcusOffsetIn, const float postCentralSulcusStdDevSquareIn, const float postCentralSulcusSplitIn) : BrainModelAlgorithm(bs), fiducialSurface(fiducialSurfaceIn), inflatedSurface(inflatedSurfaceIn), veryInflatedSurface(veryInflatedSurfaceIn), inputPaintFile(inputPaintFileIn), paintFileGeographyColumnNumber(paintFileGeographyColumnNumberIn), surfaceShapeFile(surfaceShapeFileIn), surfaceShapeFileDepthColumnNumber(surfaceShapeFileDepthColumnNumberIn), probabilisticDepthVolumeCSVFileName(probabilisticDepthVolumeCSVFileNameIn), postCentralSulcusOffset(postCentralSulcusOffsetIn), postCentralSulcusStdDevSquare(postCentralSulcusStdDevSquareIn), postCentralSulcusSplit(postCentralSulcusSplitIn) { defaultAreaColorFile = NULL; outputAreaColorFile = NULL; outputPaintFile = NULL; defaultVocabularyFile = NULL; outputVocabularyFile = NULL; probabilisticMetricFile = NULL; rotatedVeryInflatedSurface = NULL; addingFirstColorFlag = true; loadColors(); loadVocabulary(); } /** * destructor. */ BrainModelSurfaceSulcalIdentificationProbabilistic::~BrainModelSurfaceSulcalIdentificationProbabilistic() { if (defaultAreaColorFile != NULL) { delete defaultAreaColorFile; defaultAreaColorFile = NULL; } if (outputPaintFile != NULL) { delete outputPaintFile; outputPaintFile = NULL; } if (outputAreaColorFile != NULL) { delete outputAreaColorFile; outputAreaColorFile = NULL; } if (defaultVocabularyFile != NULL) { delete defaultVocabularyFile; defaultVocabularyFile = NULL; } if (outputVocabularyFile != NULL) { delete outputVocabularyFile; outputVocabularyFile = NULL; } if (probabilisticMetricFile != NULL) { delete probabilisticMetricFile; probabilisticMetricFile = NULL; } if (rotatedVeryInflatedSurface != NULL) { delete rotatedVeryInflatedSurface; rotatedVeryInflatedSurface = NULL; } } /** * execute the algorithm. */ void BrainModelSurfaceSulcalIdentificationProbabilistic::execute() throw (BrainModelAlgorithmException) { // // Check inputs // if (fiducialSurface == NULL) { throw BrainModelAlgorithmException("Fiducial surface is invalid."); } if (veryInflatedSurface == NULL) { throw BrainModelAlgorithmException("Very inflated surface is invalid."); } if (inputPaintFile == NULL) { throw BrainModelAlgorithmException("Paint file is invalid."); } if (surfaceShapeFile == NULL) { throw BrainModelAlgorithmException("Surface shape file is invalid."); } if ((paintFileGeographyColumnNumber < 0) || (paintFileGeographyColumnNumber >= inputPaintFile->getNumberOfColumns())) { throw BrainModelAlgorithmException("Paint file column number is invalid."); } if ((surfaceShapeFileDepthColumnNumber < 0) || (surfaceShapeFileDepthColumnNumber >= surfaceShapeFile->getNumberOfColumns())) { throw BrainModelAlgorithmException("Surface shape file column number is invalid."); } // // Apply a rotation to the very inflated surface // rotateVeryInflatedSurface(); // // Get a list of the probabilistic volumes // readProbabilisticVolumeFileList(); // // Copy the input paint file to the output paint file // outputPaintFile = new PaintFile; const int numOldPaints = inputPaintFile->getNumberOfPaintNames(); for (int i = 0; i < numOldPaints; i++) { outputPaintFile->addPaintName(inputPaintFile->getPaintNameFromIndex(i)); } outputPaintFile->setFileName(outputPaintFile->makeDefaultFileName("TEST_Sulcal_ID")); // // Map the probabilistic volumes to metric file // mapProbabilisticFunctionalVolumes(); // // multiply probabilistic functional data by depth // multiplyProbabilisticFunctionalDataByDepth(); // // Create the new initial sulcus ID paint column // const QString initialSulcusIdName("Initial Sulcus ID"); const int oldInitSulcusIdColumn = outputPaintFile->getColumnWithName(initialSulcusIdName); if (oldInitSulcusIdColumn >= 0) { outputPaintFile->removeColumn(oldInitSulcusIdColumn); } outputPaintFile->copyColumns(inputPaintFile, paintFileGeographyColumnNumber, -1, // create new column initialSulcusIdName); const int paintInitialSulciIDColumn = outputPaintFile->getNumberOfColumns() - 1; // // Make initial sulcal identification // createInitialSulcalIdentification(paintInitialSulciIDColumn); //if (DebugControl::getDebugOn()) { // try { // outputPaintFile->writeFile(outputPaintFile->getFileName()); // } // catch (FileException&) { // } //} // // Copy the initial sulcus ID to sulcus ID // const QString sulcusIdName(getSulcusIdPaintColumnName()); const int sulcusIdColumn = outputPaintFile->getColumnWithName(sulcusIdName); if (sulcusIdColumn >= 0) { outputPaintFile->removeColumn(sulcusIdColumn); } outputPaintFile->copyColumns(outputPaintFile, paintInitialSulciIDColumn, -1, // create new column sulcusIdName); //addCaseNameToName("Sulcus ID")); const int paintSulciIDColumn = outputPaintFile->getNumberOfColumns() - 1; // // Dilate the sulcal identification // dilateSulcalIdentification(paintSulciIDColumn); // // Remove the initial sulci id column // if (DebugControl::getDebugOn() == false) { outputPaintFile->removeColumn(paintInitialSulciIDColumn); } } /** * multiply probabilistic volumes by depth. */ void BrainModelSurfaceSulcalIdentificationProbabilistic::multiplyProbabilisticFunctionalDataByDepth() throw (BrainModelAlgorithmException) { const int numColumns = probabilisticMetricFile->getNumberOfColumns(); const int numNodes = probabilisticMetricFile->getNumberOfNodes(); for (int i = 0; i < numNodes; i++) { // // Get depth value for node // const float depthValue = surfaceShapeFile->getValue(i, surfaceShapeFileDepthColumnNumber); // // Multiply metric values by depth // for (int j = 0; j < numColumns; j++) { probabilisticMetricFile->setValue(i, j, (probabilisticMetricFile->getValue(i, j) * depthValue)); } } // // Name columns // for (int j = 0; j < numColumns; j++) { const QString name(brainSet->getSubject() + " Probabilistic " + sulcalNamesAndVolumes[j].getSulcusName() + " X Depth"); probabilisticMetricFile->setColumnName(j, name); } // // Write the metric file // if (DebugControl::getDebugOn()) { try { const QString filename = probabilisticMetricFile->makeDefaultFileName("ProbabilisticSulcal_Sulcus_X_Depth"); probabilisticMetricFile->writeFile(filename); //std::cout << "Wrote Prob Metric: " // << filename.toAscii().constData() // << std::endl; } catch (FileException&) { } } } /** * read the probabilistic volume file list. */ void BrainModelSurfaceSulcalIdentificationProbabilistic::readProbabilisticVolumeFileList() throw (BrainModelAlgorithmException) { // // Read the file containing the list of sulci, thresholds, and volume files // CommaSeparatedValueFile csvf; try { csvf.readFile(probabilisticDepthVolumeCSVFileName); } catch (FileException& e) { throw BrainModelAlgorithmException(e); } // // Directory name of CSV file // const QString csvDirectoryName = FileUtilities::dirname(probabilisticDepthVolumeCSVFileName); // // Find the needed table in the file // const QString tableName("ProbInfo"); const StringTable* st = csvf.getDataSectionByName(tableName); if (st == NULL) { const QString msg = QString("Unable to find data section named ") + tableName + QString(" in ") + FileUtilities::basename(probabilisticDepthVolumeCSVFileName); throw BrainModelAlgorithmException(msg); } // // Find the needed columns in the file // const QString sulcusNameColumnName("Sulcus Name"); const QString depthThresholdColumnName("Depth Threshold"); const QString volumeFileNameColumnName("Volume Name"); const QString maximumClustersColumnName("Maximum Clusters"); const int sulcusNameColumnNumber = st->getColumnIndexFromName(sulcusNameColumnName); const int depthThresholdColumnNumber = st->getColumnIndexFromName(depthThresholdColumnName); const int volumeNameColumnNumber = st->getColumnIndexFromName(volumeFileNameColumnName); const int maximumClustersColumnNumber = st->getColumnIndexFromName(maximumClustersColumnName); QString missingColumnsMessage; if (sulcusNameColumnNumber < 0) { missingColumnsMessage += (sulcusNameColumnName + "\n"); } if (depthThresholdColumnNumber < 0) { missingColumnsMessage += (depthThresholdColumnName + "\n"); } if (volumeNameColumnNumber < 0) { missingColumnsMessage += (volumeFileNameColumnName + "\n"); } if (maximumClustersColumnNumber < 0) { missingColumnsMessage += (maximumClustersColumnName + "\n"); } if (missingColumnsMessage.isEmpty() == false) { missingColumnsMessage.insert(0, QString("Required column titles not found in ") + FileUtilities::basename(probabilisticDepthVolumeCSVFileName) + "\n"); throw BrainModelAlgorithmException(missingColumnsMessage); } // // Read from the table // for (int i = 0; i < st->getNumberOfRows(); i++) { // // Prepend directory name onto volume name, if needed // QString volumeName = st->getElement(i, volumeNameColumnNumber); QFileInfo fi(volumeName); if (fi.isAbsolute() == false) { volumeName = csvDirectoryName + "/" //QDir::separator() + volumeName; } //std::cout << "BEFORE: " << volumeName.toAscii().constData() << std::endl; volumeName = volumeName.replace("\\", "/"); //std::cout << "AFTER: " << volumeName.toAscii().constData() << std::endl; SulcalNameAndVolume snav(st->getElement(i, sulcusNameColumnNumber), st->getElementAsFloat(i, depthThresholdColumnNumber), volumeName, st->getElementAsInt(i, maximumClustersColumnNumber)); sulcalNamesAndVolumes.push_back(snav); } if (sulcalNamesAndVolumes.empty()) { throw BrainModelAlgorithmException(QString("No volumes listed in ") + probabilisticDepthVolumeCSVFileName); } } /** * dilate the sulcal identification. */ void BrainModelSurfaceSulcalIdentificationProbabilistic::dilateSulcalIdentification(const int paintColumn) throw (BrainModelAlgorithmException) { // // Get paint indices for sulcal names // std::vector paintIndices; for (unsigned int i = 0; i < sulcalNamesAndVolumes.size(); i++) { paintIndices.push_back(outputPaintFile->getPaintIndexFromName( sulcalNamesAndVolumes[i].getSulcusName())); } const int numPaintIndices = static_cast(paintIndices.size()); if (numPaintIndices <= 0) { return; } // // Find index for paint "SUL" // const int sulIndex = outputPaintFile->getPaintIndexFromName("SUL"); if (sulIndex < 0) { throw BrainModelAlgorithmException("ERROR: Unable to find paint name \"SUL\"."); } // // Find calcarine paint // const int casIndex = outputPaintFile->getPaintIndexFromName("SUL.CaS"); const float casMaxZ = 13.0; const float casMaxY = -53.0; // // Find index for hippocampal fissure // const int hfIndex = outputPaintFile->getPaintIndexFromName("SUL.HF"); const float hfMaxZ = 5.0; // // Dilate the paints until not more dilations can be performed // bool done = false; std::vector paintFullyDilated(numPaintIndices, 0); while (done == false) { int numDilationsPerformed = 0; for (int i = 0; i < numPaintIndices; i++) { if (paintFullyDilated[i] == 0) { // // Limit extent of dilation for some cases // float maxExtent[6] = { -std::numeric_limits::max(), std::numeric_limits::max(), -std::numeric_limits::max(), std::numeric_limits::max(), -std::numeric_limits::max(), std::numeric_limits::max(), }; if (paintIndices[i] == hfIndex) { maxExtent[5] = hfMaxZ; } if (paintIndices[i] == casIndex) { maxExtent[5] = casMaxZ; maxExtent[3] = casMaxY; } const int dilateCount = outputPaintFile->dilatePaintID( fiducialSurface->getTopologyFile(), fiducialSurface->getCoordinateFile(), paintColumn, 1, paintIndices[i], sulIndex, maxExtent); if (dilateCount <= 0) { paintFullyDilated[i] = 1; } numDilationsPerformed += dilateCount; } } if (numDilationsPerformed <= 0) { done = true; } } } /** * add casename to name. */ QString BrainModelSurfaceSulcalIdentificationProbabilistic::addCaseNameToName(const QString& name) const { QString nameOut = name; if (brainSet->getSubject().isEmpty() == false) { nameOut += ("." + brainSet->getSubject()); if (brainSet->getStructure().getTypeAsAbbreviatedString().isEmpty() == false) { nameOut += ("." + brainSet->getStructure().getTypeAsAbbreviatedString()); } } return nameOut; } /** * find clusters using sulcal depth. */ void BrainModelSurfaceSulcalIdentificationProbabilistic::createInitialSulcalIdentification(const int paintColumn) throw (BrainModelAlgorithmException) { const QString centralSulcusName("SUL.CeS"); float centralSulcusCOG[3] = { 0.0, 0.0, 0.0 }; const QString postCentralSulcusName("SUL.PoCeS"); const QString superiorTemporalSulcusName("SUL.STS"); std::vector allowRelaxedDepthNames; const QString hippocampalFissureName("SUL.HF"); allowRelaxedDepthNames.push_back(hippocampalFissureName); const int numColumns = probabilisticMetricFile->getNumberOfColumns(); for (int j = 0; j < numColumns; j++) { BrainModelSurfaceMetricClustering* bmsmc = NULL; const bool hippocampalFissureFlag = (sulcalNamesAndVolumes[j].getSulcusName() == hippocampalFissureName); // // Some depths may be too deep, so if no clusters found, relax depth // and try again // float depthTestValue = sulcalNamesAndVolumes[j].getDepthThreshold(); const int numTries = 10; for (int mm = 0; mm < numTries; mm++) { // // Find the clusters with specified depth range // if (bmsmc != NULL) { delete bmsmc; bmsmc = NULL; } bmsmc = new BrainModelSurfaceMetricClustering(brainSet, (BrainModelSurface*)fiducialSurface, probabilisticMetricFile, BrainModelSurfaceMetricClustering::CLUSTER_ALGORITHM_MINIMUM_NUMBER_OF_NODES, j, // column number -1, // output column "Clusters", // output column name 1, // min number nodes 0.001, // min surface area depthTestValue, // neg min -100000000.0,// neg max 5.0, // pos min 4.0, // pos max false); // only clusters with min nodes or more try { bmsmc->execute(); // // Should depth be relaxed // if ((bmsmc->getNumberOfClusters() <= 0) && (std::find(allowRelaxedDepthNames.begin(), allowRelaxedDepthNames.end(), sulcalNamesAndVolumes[j].getSulcusName()) != allowRelaxedDepthNames.end())) { depthTestValue += 5.0; } else { mm = numTries; // get out of loop } } catch (BrainModelAlgorithmException& e) { throw BrainModelAlgorithmException("Finding clusters: " + e.whatQString()); } } const int numClusters = bmsmc->getNumberOfClusters(); // // Sum the total values of probabilistic times depth for each cluster // and sort indices // ValueIndexSort vis; for (int i = 0; i < numClusters; i++) { // // Look at the nodes in each cluster // double sum = 0.0; BrainModelSurfaceMetricClustering::Cluster* cluster = bmsmc->getCluster(i); const int numClusterNodes = cluster->getNumberOfNodesInCluster(); for (int k = 0; k < numClusterNodes; k++) { const int node = cluster->getNodeInCluster(k); sum += probabilisticMetricFile->getValue(node, j); } if (hippocampalFissureFlag) { float cog[3]; cluster->getCenterOfGravityForSurface(fiducialSurface, cog); if (DebugControl::getDebugOn()) { std::cout << hippocampalFissureName.toAscii().constData() << " cluster[" << i << "]" << " area=" << cluster->getArea() << " num-nodes=" << cluster->getNumberOfNodesInCluster() << " sum=" << sum << " cog=(" << cog[0] << "," << cog[1] << "," << cog[2] << ")" << std::endl; } // // Too far posterior ? // //if (cog[1] < -34.0) { // continue; //} } // // Special processing for post-central sulcus // bias in favor of clusters about 10mm posterior to CeS // if (sulcalNamesAndVolumes[j].getSulcusName() == postCentralSulcusName) { if (centralSulcusCOG[0] != 0.0) { float clusterCOG[3]; if (DebugControl::getDebugOn()) { cluster->getCenterOfGravity(clusterCOG); std::cout << "PoCeS Cluster Fiducial COG: " << clusterCOG[0] << ", " << clusterCOG[1] << ", " << clusterCOG[2] << std::endl; } cluster->getCenterOfGravityForSurface(rotatedVeryInflatedSurface, clusterCOG); cluster->setCenterOfGravity(clusterCOG); const float diff = (postCentralSulcusOffset + clusterCOG[1] - centralSulcusCOG[1]); const float bias = std::exp(-((diff*diff) / postCentralSulcusStdDevSquare)); const float sumBefore = sum; sum *= bias; if (DebugControl::getDebugOn()) { std::cout << "PoCeS Cluster Very Inflated COG: " << clusterCOG[0] << ", " << clusterCOG[1] << ", " << clusterCOG[2] << std::endl; std::cout << " Number of Nodes: " << numClusterNodes << std::endl; std::cout << " Sum: " << sumBefore << std::endl; std::cout << " Bias: " << bias << std::endl; std::cout << " Sum*Bias" << sum << std::endl; std::cout << std::endl; } } } vis.addValueIndexPair(i, std::fabs(sum)); // use abs since negative sums } // for (i = 0; i < numClusters... // // Sort the items // vis.sort(); int numSortedItems = vis.getNumberOfItems(); if (DebugControl::getDebugOn()) { if (sulcalNamesAndVolumes[j].getSulcusName() == postCentralSulcusName) { std::cout << "CeS Cluster Very Inflated COG: " << centralSulcusCOG[0] << ", " << centralSulcusCOG[1] << ", " << centralSulcusCOG[2] << std::endl; const int iStop = std::max(numSortedItems - 2, 0); for (int i = (numSortedItems - 1); i >= iStop; i--) { int indx; float value; vis.getValueAndIndex(i, indx, value); // // Set paint for nodes in cluster // const BrainModelSurfaceMetricClustering::Cluster* cluster = bmsmc->getCluster(indx); float clusterCOG[3]; cluster->getCenterOfGravity(clusterCOG); std::cout << "PoCeS Cluster Very Inflated COG: " << clusterCOG[0] << ", " << clusterCOG[1] << ", " << clusterCOG[2] << std::endl; std::cout << " Summed Depth: " << value << std::endl; } } /* std::cout << sulcalNamesAndVolumes[j].getSulcusName().toAscii().constData() << " clusters" << std::endl; for (int i = (vis.getNumberOfItems() - 1); i >= 0; i--) { int indx; float value; vis.getValueAndIndex(i, indx, value); std::cout << " " << indx << ": " << value << std::endl; } */ } // if (DebugControl... // // Set the paint index // const int paintIndex = outputPaintFile->addPaintName(sulcalNamesAndVolumes[j].getSulcusName()); // // Need to start at end of sorted data and find the // maximum number of clusters items // int stopIndex = numSortedItems - sulcalNamesAndVolumes[j].getMaximumClusters(); // // Special processing for hippocampal fissure // if (hippocampalFissureFlag) { if (numSortedItems > 1) { int indx1, indx2; float value1, value2; vis.getValueAndIndex(numSortedItems - 1, indx1, value1); vis.getValueAndIndex(numSortedItems - 2, indx2, value2); float cog1[3], cog2[3]; bmsmc->getCluster(indx1)->getCenterOfGravity(cog1); bmsmc->getCluster(indx2)->getCenterOfGravity(cog2); // // If 1st cluster is too far posterior, skip it and // use the 2nd cluster // const float posteriorLimitHF = -34.0; if (cog1[1] < posteriorLimitHF) { if (cog2[1] > posteriorLimitHF) { numSortedItems--; stopIndex--; std::cout << "SULCAL ID INFO: " << "HF cluster Y=" << cog1[1] << " skipped." << std::endl; } } } } // // Special processing for post-central sulcus // if (sulcalNamesAndVolumes[j].getSulcusName() == postCentralSulcusName) { if (numSortedItems > 1) { int indx1, indx2; float value1, value2; vis.getValueAndIndex(numSortedItems - 1, indx1, value1); vis.getValueAndIndex(numSortedItems - 2, indx2, value2); float cog1[3], cog2[3]; bmsmc->getCluster(indx1)->getCenterOfGravity(cog1); bmsmc->getCluster(indx2)->getCenterOfGravity(cog2); const float dist = std::fabs(cog1[1] - cog2[1]); // // If the first and second clusters are within 5mm of each other in Y, use both // if (dist <= postCentralSulcusSplit) { stopIndex = numSortedItems - 2; //std::cout << "INFO: using second PoCeS cluster." << std::endl; } } } // // Special processing for superior temporal sulcus // if (sulcalNamesAndVolumes[j].getSulcusName() == superiorTemporalSulcusName) { if (numSortedItems > 1) { int indx1, indx2; float value1, value2; vis.getValueAndIndex(numSortedItems - 1, indx1, value1); vis.getValueAndIndex(numSortedItems - 2, indx2, value2); const float y1 = bmsmc->getCluster(indx1)->getMaximumY(fiducialSurface); const float y2 = bmsmc->getCluster(indx2)->getMaximumY(fiducialSurface); // // If largest cluster is far posterior and the second cluster // is in front of it, use both clusters // if ((y1 < -25.0) && (y2 > y1)) { stopIndex = numSortedItems - 2; } } } // // Make sure stop index is valid // stopIndex = std::max(stopIndex, 0); // // Find the cluster nodes starting at end since we want the largest // for (int i = (numSortedItems - 1); i >= stopIndex; i--) { int indx; float value; vis.getValueAndIndex(i, indx, value); // // Set paint for nodes in cluster // const BrainModelSurfaceMetricClustering::Cluster* cluster = bmsmc->getCluster(indx); const int numClusterNodes = cluster->getNumberOfNodesInCluster(); for (int k = 0; k < numClusterNodes; k++) { const int node = cluster->getNodeInCluster(k); outputPaintFile->setPaint(node, paintColumn, paintIndex); } // // Save central sulcus center of gravity // if (sulcalNamesAndVolumes[j].getSulcusName() == centralSulcusName) { cluster->getCenterOfGravityForSurface(rotatedVeryInflatedSurface, centralSulcusCOG); } } // // Free memory // if (bmsmc != NULL) { delete bmsmc; bmsmc = NULL; } } } /** * map the probabilistic functional volumes to the metric file. */ void BrainModelSurfaceSulcalIdentificationProbabilistic::mapProbabilisticFunctionalVolumes() throw (BrainModelAlgorithmException) { // // Names of functional probabilistic volumes // const int numVolumes = static_cast(sulcalNamesAndVolumes.size()); // // Create the probabilistic metric file // if (probabilisticMetricFile != NULL) { delete probabilisticMetricFile; probabilisticMetricFile = NULL; } probabilisticMetricFile = new MetricFile; // // Use enclosing voxel algorithm for mapping // BrainModelVolumeToSurfaceMapperAlgorithmParameters mappingParameters; mappingParameters.setAlgorithm( BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_METRIC_ENCLOSING_VOXEL); // // Map the functional probabilistic volumes to the surface // for (int i = 0; i < numVolumes; i++) { // Use Sulcus Name only for area colors //const QString name(brainSet->getSubject() // + " " // + sulcalNamesAndVolumes[i].getSulcusName()); const QString name(sulcalNamesAndVolumes[i].getSulcusName()); BrainModelVolumeToSurfaceMapper mapper(brainSet, (BrainModelSurface*)fiducialSurface, sulcalNamesAndVolumes[i].getVolumeName(), probabilisticMetricFile, mappingParameters, -1, name); try { mapper.execute(); if (name.endsWith("SUL.HF")) { specialProcessingForHippocampalFissure(probabilisticMetricFile, probabilisticMetricFile->getNumberOfColumns() - 1); } addAreaColor(name); addVocabulary(name); } catch (BrainModelAlgorithmException& e) { const QString msg = "Mapping " + sulcalNamesAndVolumes[i].getVolumeName() + " failed: " + e.whatQString(); throw BrainModelAlgorithmException(msg); } } // // Set metrics to zero for any nodes that are not labeled as SUL in paint // const int numNodes = probabilisticMetricFile->getNumberOfNodes(); if (numNodes == inputPaintFile->getNumberOfNodes()) { const int numMetricColumns = probabilisticMetricFile->getNumberOfColumns(); const int paintIndex = inputPaintFile->getPaintIndexFromName("SUL"); if (paintIndex >= 0) { for (int i = 0; i < numNodes; i++) { if (inputPaintFile->getPaint(i, paintFileGeographyColumnNumber) != paintIndex) { for (int j = 0; j < numMetricColumns; j++) { probabilisticMetricFile->setValue(i, j, 0.0); } } } } } // // Write the metric file // if (DebugControl::getDebugOn()) { try { const QString filename = probabilisticMetricFile->makeDefaultFileName("ProbabilisticSulcal_ALL"); probabilisticMetricFile->writeFile(filename); } catch (FileException&) { } } } /** * rotate the very inflated surface. */ void BrainModelSurfaceSulcalIdentificationProbabilistic::rotateVeryInflatedSurface() throw (BrainModelAlgorithmException) { // // Set the rotation // double rotation = 0.0; if (veryInflatedSurface->getStructure() == Structure::STRUCTURE_TYPE_CORTEX_LEFT) { rotation = 35.0; } else if (veryInflatedSurface->getStructure() == Structure::STRUCTURE_TYPE_CORTEX_RIGHT) { rotation = -35.0; } else if (brainSet->getStructure() == Structure::STRUCTURE_TYPE_CORTEX_LEFT) { rotation = 35.0; } else if (brainSet->getStructure() == Structure::STRUCTURE_TYPE_CORTEX_RIGHT) { rotation = -35.0; } else { throw BrainModelAlgorithmException("Unable to determine hemisphere from very inflated " "surface header or fiducial coord's file name"); } // // Create a transformation matrix containing the rotation // TransformationMatrix tm; tm.rotateZ(rotation); // // Apply the rotation to the very inflated surface // rotatedVeryInflatedSurface = new BrainModelSurface(*veryInflatedSurface); rotatedVeryInflatedSurface->applyTransformationMatrix(tm); if (DebugControl::getDebugOn()) { try { CoordinateFile* cf = rotatedVeryInflatedSurface->getCoordinateFile(); cf->writeFile("Sulcal_ID_Very_Inflated_Surface_Rotated.coord"); } catch (FileException&) { } } } /** * special process for the hippocampal fissure. */ void BrainModelSurfaceSulcalIdentificationProbabilistic::specialProcessingForHippocampalFissure( MetricFile* metricFile, const int metricFileColumnNumber) { //std::cout << "Processing special Hippocampal features." << std::endl; // // Clear metric for any nodes whose normal vector's Z is not positive // const int numNodes = metricFile->getNumberOfNodes(); for (int i = 0; i < numNodes; i++) { const float* normalVector = inflatedSurface->getNormal(i); if (normalVector[2] <= 0.0) { metricFile->setValue(i, metricFileColumnNumber, 0.0); } } } /** * load the colors. */ void BrainModelSurfaceSulcalIdentificationProbabilistic::loadColors() { defaultAreaColorFile = new AreaColorFile; defaultAreaColorFile->addColor("SUL",130,130,130,255); defaultAreaColorFile->addColor("SUL.AOS",217,0,205,255); defaultAreaColorFile->addColor("SUL.AS",0,85,104,255); defaultAreaColorFile->addColor("SUL.CaS",255,0,104,255); defaultAreaColorFile->addColor("SUL.CaSd",120,0,0,255); defaultAreaColorFile->addColor("SUL.CaSv",166,0,0,255); defaultAreaColorFile->addColor("SUL.CeS",162,143,0,255); defaultAreaColorFile->addColor("SUL.CiS",8,54,255,255); defaultAreaColorFile->addColor("SUL.CiSmr",97,0,104,255); defaultAreaColorFile->addColor("SUL.CoS",178,58,58,255); defaultAreaColorFile->addColor("SUL.FMS",62,46,0,255); defaultAreaColorFile->addColor("SUL.FOS",112,46,12,255); defaultAreaColorFile->addColor("SUL.HF",255,0,0,255); defaultAreaColorFile->addColor("SUL.IFS",120,73,0,255); defaultAreaColorFile->addColor("SUL.ILS",152,31,87,255); defaultAreaColorFile->addColor("SUL.IOS",0,120,0,255); defaultAreaColorFile->addColor("SUL.IPS",104,255,0,255); defaultAreaColorFile->addColor("SUL.IPrCeS",161,88,29,255); defaultAreaColorFile->addColor("SUL.IRS",81,0,0,255); defaultAreaColorFile->addColor("SUL.ISS",255,0,0,255); defaultAreaColorFile->addColor("SUL.ITS",0,41,141,255); defaultAreaColorFile->addColor("SUL.LOS",141,47,0,255); defaultAreaColorFile->addColor("SUL.LS",131,0,0,255); defaultAreaColorFile->addColor("SUL.LiS",166,81,66,255); defaultAreaColorFile->addColor("SUL.LuS",236,195,1,255); defaultAreaColorFile->addColor("SUL.MFS",81,39,54,255); defaultAreaColorFile->addColor("SUL.MPrCeS",112,70,73,255); defaultAreaColorFile->addColor("SUL.OTS",85,43,0,255); defaultAreaColorFile->addColor("SUL.OlfS",100,0,66,255); defaultAreaColorFile->addColor("SUL.OrbS",85,39,23,255); defaultAreaColorFile->addColor("SUL.POS",93,0,209,255); defaultAreaColorFile->addColor("SUL.PS",46,139,46,255); defaultAreaColorFile->addColor("SUL.PaCeS",139,27,81,255); defaultAreaColorFile->addColor("SUL.PoCeS",27,112,0,255); defaultAreaColorFile->addColor("SUL.PoSubCeS",0,178,132,255); defaultAreaColorFile->addColor("SUL.RhS",46,0,39,255); defaultAreaColorFile->addColor("SUL.SF",0,0,77,255); defaultAreaColorFile->addColor("SUL.SFS",100,62,0,255); defaultAreaColorFile->addColor("SUL.SPS",67,0,56,255); defaultAreaColorFile->addColor("SUL.SPrCeS",155,110,0,255); defaultAreaColorFile->addColor("SUL.SRS",103,35,50,255); defaultAreaColorFile->addColor("SUL.SSS",100,0,0,255); defaultAreaColorFile->addColor("SUL.STS",46,0,0,255); defaultAreaColorFile->addColor("SUL.SubPS",67,0,56,255); defaultAreaColorFile->addColor("SUL.SupPS",96,33,126,255); defaultAreaColorFile->addColor("SUL.TOS",213,77,0,255); defaultAreaColorFile->addColor("SUL.TOrbS",62,31,23,255); defaultAreaColorFile->addColor("SUL.intFS",117,94,0,255); defaultAreaColorFile->addColor("SUL.pITS",81,39,120,255); } /** * load vocabulary. */ void BrainModelSurfaceSulcalIdentificationProbabilistic::loadVocabulary() { defaultVocabularyFile = new VocabularyFile; defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("GYRAL", "Gyral cortex")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("MEDIAL.WALL", "Non-cortical portions of surface along the medial wall")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL", "Sulcal (buried) cortex")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.AOS", "Anterior Occipital Sulcus")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.AS", "Angular Sulcus")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.CaS", "Calcarine Sulcus")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.CaSd", "Calcarine Sulcus (dorsal)")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.CaSv", "Calcarine Sulcus (ventral)")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.CeS", "Central Sulcus")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.CiS", "Cingulate Sulcus")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.CiSmr", "Cingulate Sulcus marginal ramus")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.CoS", "Collateral Sulcus")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.FMS", "Fronto-Marginal Sulcus")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.FOS", "Fronto-Orbital Sulcus")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.HF", "Hippocampal Fissure")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.IFS", "Inferior Frontal Sulcus")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.ILS", "Intra-Lingual Sulcus")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.intFS", "intermediate Frontal Sulcus")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.IPrCeS", "Inferior Pre-Central Sulcus")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.IPS", "Inferior Parietal Sulcus")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.IRS", "Inferior Rostral Sulcus")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.ISS", "Inferior Sagittal Sulcus")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.ITS", "Inferior Temporal Sulcus")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.LOS", "Lateral Occipital Sulcus")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.LuS", "Lunate Sulcus")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.MFS", "Middle Frontal Sulcus")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.MPrCeS", "Medial Pre-Central Sulcus")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.OlfS", "Olfactory Sulcus")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.OrbS", "Orbital Sulcus")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.OTS", "Occipito-Temporal Sulcus")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.PaCeS", "Para-Central Sulcus")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.pITS", "posterior Inferior Temporal Sulcus")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.PoCeS", "Postcentral Sulcus")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.POS", "Parieto-Occipital Sulcus")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.PoSubCeS", "Posterior Sub-Central Sulcus")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.RhS", "Rhinal Sulcus")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.SF", "Sylvian Fissure")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.SFS", "Superior Frontal Sulcus")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.SPrCeS", "Superior Pre-Central Sulcus")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.SRS", "Superior Rostral Sulcus")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.SSS", "Superior Sagittal Sulcus")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.STS", "Superior Temporal Sulcus")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.SubPS", "Sub-Parietal Sulcus")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.SupPS", "Superior Parietal Sulcus")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.TOrbS", "Transverse Orbital Sulcus")); defaultVocabularyFile->addVocabularyEntry(VocabularyFile::VocabularyEntry("SUL.TOS", "Transverse Occipital Sulcus")); } /** * add vocabulary. */ void BrainModelSurfaceSulcalIdentificationProbabilistic::addVocabulary(const QString& name) { // // Create output area color file, if needed // if (outputVocabularyFile == NULL) { outputVocabularyFile = new VocabularyFile; } const VocabularyFile::VocabularyEntry* ve = defaultVocabularyFile->getVocabularyEntryByName(name); if (ve != NULL) { outputVocabularyFile->addVocabularyEntry(*ve); } else { std::cout << "WARNING: No vocabular entry found when identifying sulci probabilistically: " << name.toAscii().constData() << std::endl; } } /** * add an area color. */ void BrainModelSurfaceSulcalIdentificationProbabilistic::addAreaColor(const QString& colorName) { // // Create output area color file, if needed // if (outputAreaColorFile == NULL) { outputAreaColorFile = new AreaColorFile; } // // If first time adding a color // if (addingFirstColorFlag) { addingFirstColorFlag = false; defaultAreaColorFile->addColor("???",170,170,170,255); defaultAreaColorFile->addColor("SUL",130,130,130,255); } // // See if color is available in default colors // bool exactMatch = false; const int indx = defaultAreaColorFile->getColorIndexByName(colorName, exactMatch); if ((indx >= 0) && (exactMatch)) { // // Add the color to the user's color file // unsigned char r, g, b, a; defaultAreaColorFile->getColorByIndex(indx, r, g, b, a); outputAreaColorFile->addColor(colorName, r, g, b, a); } else { std::cout << "INFO: BrainModelSurfaceSulcalIdentificationProbabilistic " << "color not found " << colorName.toAscii().constData(); } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceSulcalDepthWithNormals.h0000664000175000017500000000752611572067322027736 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_BRAIN_MODEL_SURFACE_SULCAL_DEPTH_WITH_NORMALS_H__ #define __GUI_BRAIN_MODEL_SURFACE_SULCAL_DEPTH_WITH_NORMALS_H__ #include #include "BrainModelAlgorithm.h" class BrainModelSurface; class CoordinateFile; class SurfaceShapeFile; class vtkPolyData; /// Class to generate a sulcal depth map for a surface class BrainModelSurfaceSulcalDepthWithNormals : public BrainModelAlgorithm { public: enum DEPTH_COLUMNS { DEPTH_COLUMN_CREATE_NEW = -1, DEPTH_COLUMN_DO_NOT_GENERATE = -2 }; /// Constructor BrainModelSurfaceSulcalDepthWithNormals(BrainSet* bs, BrainModelSurface* surfaceIn, const QString& hullVtkFilenNameIn, SurfaceShapeFile* shapeFileIn, const int hullSmoothingIterationsIn, const int depthSmoothingIterationsIn, const int depthColumnIn, const int smoothedDepthColumnIn, const QString& depthNameIn, const QString& smoothedDepthNameIn, CoordinateFile* outputHullCoordFileIn); /// Destructor ~BrainModelSurfaceSulcalDepthWithNormals(); /// execute the algorithm virtual void execute() throw (BrainModelAlgorithmException); private: // normal check for node (surface/hull normals oriented in similar direction) bool normalCheck(const int surfaceNode, const int hullNode); // determine greatest neighbor distance from each node void determineGreatestNeighborDistance(const BrainModelSurface* bms, std::vector& greatestDistance) const; /// surface for depth computation BrainModelSurface* surface; /// inflated surface for depth computation BrainModelSurface* inflatedSurface; /// inflated hull surface BrainModelSurface* inflatedHullSurface; /// less inflated hull surface BrainModelSurface* lowlySmoothedHullSurface; /// the hull vtk file name QString hullVtkFileName; /// surface shape file for storage of depth SurfaceShapeFile* shapeFile; /// column for depth int depthColumn; /// column for smoothed depth int smoothedDepthColumn; /// name for depth column QString depthName; /// name for smoothed depth column QString smoothedDepthName; /// hull smoothing interations int hullSmoothingIterations; /// depth smoothing interations int depthSmoothingIterations; /// hull coord file with same number of nodes as input surface CoordinateFile* outputHullCoordFile; }; #endif // __GUI_BRAIN_MODEL_SURFACE_SULCAL_DEPTH_WITH_NORMALS_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceSulcalDepthWithNormals.cxx0000664000175000017500000004733111572067322030307 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include "vtkMath.h" #include "BrainModelSurface.h" #include "BrainModelSurfacePointLocator.h" #include "BrainModelSurfaceSulcalDepthWithNormals.h" #include "BrainSet.h" #include "MathUtilities.h" #include "SurfaceShapeFile.h" #include "TopologyFile.h" #include "TopologyHelper.h" /** * Constructor. */ BrainModelSurfaceSulcalDepthWithNormals::BrainModelSurfaceSulcalDepthWithNormals( BrainSet* bs, BrainModelSurface* surfaceIn, const QString& hullVtkFileNameIn, SurfaceShapeFile* shapeFileIn, const int hullSmoothingIterationsIn, const int depthSmoothingIterationsIn, const int depthColumnIn, const int smoothedDepthColumnIn, const QString& depthNameIn, const QString& smoothedDepthNameIn, CoordinateFile* outputHullCoordFileIn) : BrainModelAlgorithm(bs) { surface = surfaceIn; shapeFile = shapeFileIn; depthColumn = depthColumnIn; smoothedDepthColumn = smoothedDepthColumnIn; hullSmoothingIterations = hullSmoothingIterationsIn; depthSmoothingIterations = depthSmoothingIterationsIn; hullVtkFileName = hullVtkFileNameIn; depthName = depthNameIn; smoothedDepthName = smoothedDepthNameIn; outputHullCoordFile = outputHullCoordFileIn; } /** * Destructor. */ BrainModelSurfaceSulcalDepthWithNormals::~BrainModelSurfaceSulcalDepthWithNormals() { } /** * execute the algorithm */ void BrainModelSurfaceSulcalDepthWithNormals::execute() throw (BrainModelAlgorithmException) { //std::cout << "Running David/Donna sulcal depth" << std::endl; // // check surface // if (surface == NULL) { throw BrainModelAlgorithmException("Surface is invalid."); } if (surface->getNumberOfNodes() <= 0) { throw BrainModelAlgorithmException("Surface has no nodes."); } // // create the inflated surface // inflatedSurface = new BrainModelSurface(*surface); inflatedSurface->inflateSurfaceAndSmoothFingers(surface, 6, 1.0, 200, 1.1, 1.0, 1.0, 0, NULL); bool needToDeleteInflatedSurface = true; if (DebugControl::getDebugOn()) { CoordinateFile* cf = inflatedSurface->getCoordinateFile(); if (cf != NULL) { cf->makeDefaultFileName("DebugSulcalDepthHyperInflated"); inflatedSurface->setSurfaceType(BrainModelSurface::SURFACE_TYPE_VERY_INFLATED); brainSet->addBrainModel(inflatedSurface); needToDeleteInflatedSurface = false; } } // // Create surface shape columns if needed // if (depthColumn == DEPTH_COLUMN_CREATE_NEW) { if (shapeFile->getNumberOfColumns() == 0) { shapeFile->setNumberOfNodesAndColumns(surface->getNumberOfNodes(), 1); } else { shapeFile->addColumns(1); } depthColumn = shapeFile->getNumberOfColumns() - 1; } if (smoothedDepthColumn == DEPTH_COLUMN_CREATE_NEW) { if (shapeFile->getNumberOfColumns() == 0) { shapeFile->setNumberOfNodesAndColumns(surface->getNumberOfNodes(), 1); } else { shapeFile->addColumns(1); } smoothedDepthColumn = shapeFile->getNumberOfColumns() - 1; } // // Set column names // if (depthColumn >= 0) { shapeFile->setColumnName(depthColumn, depthName); shapeFile->setColumnColorMappingMinMax(depthColumn, -30.0, 10.0); } if (smoothedDepthColumn >= 0) { shapeFile->setColumnName(smoothedDepthColumn, smoothedDepthName); shapeFile->setColumnColorMappingMinMax(smoothedDepthColumn, -30.0, 10.0); } // // Convert the hull to a brain model surface // BrainSet hullBrainSet; try { hullBrainSet.importVtkSurfaceFile(hullVtkFileName, true, true, false, BrainModelSurface::SURFACE_TYPE_FIDUCIAL, TopologyFile::TOPOLOGY_TYPE_CLOSED); } catch (FileException& e) { throw BrainModelAlgorithmException(e.whatQString()); } // // Hull should be first brain model // BrainModelSurface* hullSurface = hullBrainSet.getBrainModelSurface(0); if (hullSurface == NULL) { throw BrainModelAlgorithmException("Hull surface is missing."); } TopologyFile* hullTopologyFile = hullSurface->getTopologyFile(); const int numIslands = hullTopologyFile->disconnectIslands(); if (numIslands > 0) { hullSurface->moveDisconnectedNodesToOrigin(); } // // Save hull prior to smoothing // const BrainModelSurface* unsmoothedHullSurface = new BrainModelSurface(*hullSurface); const CoordinateFile* unsmoothedHullCoords = unsmoothedHullSurface->getCoordinateFile(); // // Create the inflated hull surface // inflatedHullSurface = new BrainModelSurface(*unsmoothedHullSurface); hullBrainSet.addBrainModel(inflatedHullSurface); lowlySmoothedHullSurface = new BrainModelSurface(*unsmoothedHullSurface); hullBrainSet.addBrainModel(lowlySmoothedHullSurface); // // First, just smooth a little, and save normal for distance to plane check // lowlySmoothedHullSurface->inflateSurfaceAndSmoothFingers(unsmoothedHullSurface, 1, 1.0, 30, 1.0, 1.0, 1.0, 0, NULL); // // Now, smooth more for "normalcheck" (i.e., part that keeps sylvian // from pairing with medial wall hull nodes) // inflatedHullSurface->inflateSurfaceAndSmoothFingers(unsmoothedHullSurface, 6, 1.0, 50, 1.1, 3.0, 1.0, 60, NULL); // // If desired, smooth hull // if (hullSmoothingIterations > 0) { // // Smooth the hull // hullSurface->arealSmoothing(1.0, hullSmoothingIterations, 0); } // // Make sure hull's normals point outward // hullSurface->orientNormalsOut(); // // determine greatest distance to each neighbor of each hull node // std::vector hullGreatestNeighborDistance; determineGreatestNeighborDistance(hullSurface, hullGreatestNeighborDistance); // // Create a point locator for the hull surface // BrainModelSurfacePointLocator hullLocator(hullSurface, true); // // Make sure inflated hull's normals point outward // inflatedHullSurface->computeNormals(); inflatedHullSurface->orientNormalsOut(); lowlySmoothedHullSurface->computeNormals(); lowlySmoothedHullSurface->orientNormalsOut(); // // Get surface and hull coordinates // const CoordinateFile* surfaceCoords = surface->getCoordinateFile(); const int numSurfaceNodes = surfaceCoords->getNumberOfCoordinates(); const CoordinateFile* hullCoords = hullSurface->getCoordinateFile(); // // TopologyHelper for surface // const TopologyFile* surfaceTopologyFile = surface->getTopologyFile(); const TopologyHelper* surfaceTopologyHelper = surfaceTopologyFile->getTopologyHelper(false, true, false); // // TopologyHelper for hull // const TopologyHelper* hullTopologyHelper = hullTopologyFile->getTopologyHelper(false, true, false); // // initialize hull coord file // if ((numSurfaceNodes > 0) && (outputHullCoordFile != NULL)) { outputHullCoordFile->setNumberOfCoordinates(numSurfaceNodes); } // // Determine depth values for surface nodes // int numHullNodes = hullSurface->getNumberOfNodes(); for (int i = 0; i < numSurfaceNodes; i++) { // // initially set the depth to zero // if (depthColumn >= 0) { shapeFile->setValue(i, depthColumn, 0.0); } if (smoothedDepthColumn >= 0) { shapeFile->setValue(i, smoothedDepthColumn, 0.0); } // // Make sure surface node has neighbors // if (surfaceTopologyHelper->getNodeHasNeighbors(i) == false) { continue; } // // coordinate of surface node // const float* surfaceXYZ = surfaceCoords->getCoordinate(i); // // Find node in hull that is nearest this surface node // int hullNode = hullLocator.getNearestPoint(surfaceXYZ); // // If nearest node found in hull // if (hullNode >= 0) { // // Do the normals fail to match in orientation ? // if (normalCheck(i, hullNode) == false) { float nearestHullNodeDistance = std::numeric_limits::max(); hullNode = -1; // // Find closest hull node with similar normal orientation // for (int m = 0; m < numHullNodes; m++) { // // Does hull node have neighbors and how far away is it // if (hullTopologyHelper->getNodeHasNeighbors(m) ) { float distSQ = hullCoords->getDistanceToPointSquared(m, surfaceXYZ); if (distSQ < nearestHullNodeDistance) { // // Are normals oriented in a similar direction ? // if (normalCheck(i, m) > 0.0) { // // Could be nearest node // hullNode = m; nearestHullNodeDistance = distSQ; } } } } } } // // If nearest node found in hull // if (hullNode >= 0) { // // Get the coordinate of the hull nearest node // const float* hullXYZ = hullCoords->getCoordinate(hullNode); // // Get normal of hull node // const float* hullNormal = hullSurface->getNormal(hullNode); const float* inflatedHullXYZ = inflatedHullSurface->getCoordinateFile()->getCoordinate(hullNode); const float* inflatedHullNormal = inflatedHullSurface->getNormal(hullNode); const float* lowSmoothNormal = lowlySmoothedHullSurface->getNormal(hullNode); // // Compute signed distance from surface not to point on plane from hull normal // const float distanceFromPlane = MathUtilities::signedDistanceToPlane(lowSmoothNormal, hullXYZ, surfaceXYZ); // // Distance between surface and hull point // float distance = MathUtilities::distance3D(hullXYZ, surfaceXYZ); // // Is surface node closer than hull node's nearest neighbor? // if (distance < hullGreatestNeighborDistance[hullNode]) { const float dxyz[3] = { surfaceXYZ[0] - hullXYZ[0], surfaceXYZ[1] - hullXYZ[1], surfaceXYZ[2] - hullXYZ[2] }; // // determine distance // distance = MathUtilities::dotProduct(dxyz, hullNormal); } else { // // "distance" is an absolute value // So, apply the sign of "distanceFromPlane" // if (distanceFromPlane < 0.0) { distance = -distance; } } if (DebugControl::getDebugOn()) { if (i == DebugControl::getDebugNodeNumber()) { const float* surfaceNormalXYZ = surface->getNormal(i); const float* inflatedXYZ = inflatedSurface->getCoordinateFile()->getCoordinate(i); const float* sn = inflatedSurface->getNormal(i); std::cout << "surface node: " << i << std::endl; std::cout << " hull node: " << hullNode << std::endl; std::cout << " surface node: " << surfaceXYZ[0] << ", " << surfaceXYZ[1] << ", " << surfaceXYZ[2] << std::endl; std::cout << " surface normal: " << surfaceNormalXYZ[0] << ", " << surfaceNormalXYZ[1] << ", " << surfaceNormalXYZ[2] << std::endl; std::cout << " dot: " << MathUtilities::dotProduct(sn, inflatedHullNormal) << std::endl; std::cout << " inflated surface XYZ: " << inflatedXYZ[0] << ", " << inflatedXYZ[1] << ", " << inflatedXYZ[2] << std::endl; std::cout << " inflated surface normal: " << sn[0] << ", " << sn[1] << ", " << sn[2] << std::endl; std::cout << " hull node: " << hullXYZ[0] << ", " << hullXYZ[1] << ", " << hullXYZ[2] << std::endl; std::cout << " hull normal: " << hullNormal[0] << ", " << hullNormal[1] << ", " << hullNormal[2] << std::endl; std::cout << " inflated hull XYZ: " << inflatedHullXYZ[0] << ", " << inflatedHullXYZ[1] << ", " << inflatedHullXYZ[2] << std::endl; std::cout << " inflated hull normal: " << inflatedHullNormal[0] << ", " << inflatedHullNormal[1] << ", " << inflatedHullNormal[2] << std::endl; std::cout << " lowly smoothed hull normal: " << lowSmoothNormal[0] << ", " << lowSmoothNormal[1] << ", " << lowSmoothNormal[2] << std::endl; std::cout << " distance: " << distance << std::endl; std::cout << " distance/plane: " << distanceFromPlane << std::endl; std::cout << " hull neigh dist:" << hullGreatestNeighborDistance[hullNode] << std::endl; } } // // Insert into the surface shape file // if (depthColumn >= 0) { shapeFile->setValue(i, depthColumn, distance); } if (smoothedDepthColumn >= 0) { shapeFile->setValue(i, smoothedDepthColumn, distance); } // // output hull coord file // if (outputHullCoordFile != NULL) { outputHullCoordFile->setCoordinate(i, unsmoothedHullCoords->getCoordinate(hullNode)); } } else { // // output hull coord file // if (outputHullCoordFile != NULL) { outputHullCoordFile->setCoordinate(i, 0.0, 0.0, 0.0); } } } // // if creating smoothed depth, smooth it // if ((smoothedDepthColumn >= 0) && (depthSmoothingIterations > 0)) { shapeFile->smoothAverageNeighbors(smoothedDepthColumn, smoothedDepthColumn, shapeFile->getColumnName(smoothedDepthColumn), 1.0, depthSmoothingIterations, surface->getTopologyFile()); } // // Free memory // delete unsmoothedHullSurface; unsmoothedHullSurface = NULL; if (needToDeleteInflatedSurface) { delete inflatedSurface; inflatedSurface = NULL; } } /** * normal check for node (surface/hull normals oriented in similar direction). */ bool BrainModelSurfaceSulcalDepthWithNormals::normalCheck(const int surfaceNode, const int hullNode) { // // Get the inflated hull surface normal // const float* inflatedHullNormal = inflatedHullSurface->getNormal(hullNode); // // Get the inflated surface normal // const float* inflatedSurfaceNormal = inflatedSurface->getNormal(surfaceNode); if (DebugControl::getDebugOn()) { } // // Get dot product which is angles between vectors // const float dot = vtkMath::Dot(inflatedHullNormal, inflatedSurfaceNormal); if (DebugControl::getDebugOn()) { if (surfaceNode == DebugControl::getDebugNodeNumber()) { std::cout << "Sulcal Depth node: " << surfaceNode << " hull node: " << hullNode << " dot: " << dot << std::endl; } } // // In similar direction // if (dot > 0.0) { return true; } return false; } /** * determine greatest neighbor distance from each node. */ void BrainModelSurfaceSulcalDepthWithNormals::determineGreatestNeighborDistance( const BrainModelSurface* bms, std::vector& greatestDistance) const { // // Initialize output distances // const int numNodes = bms->getNumberOfNodes(); greatestDistance.resize(numNodes); std::fill(greatestDistance.begin(), greatestDistance.end(), 0.0); // // Get a topology helper // const CoordinateFile* cf = bms->getCoordinateFile(); const TopologyFile* tf = bms->getTopologyFile(); if (tf != NULL) { const TopologyHelper* th = tf->getTopologyHelper(false, true, false); // // Determine distance for each node // for (int i = 0; i < numNodes; i++) { float maxDist = 0.0; int numNeighbors = 0; const int* neighbors = th->getNodeNeighbors(i, numNeighbors); for (int j = 0; j < numNeighbors; j++) { const float d = cf->getDistanceBetweenCoordinatesSquared(i, neighbors[j]); maxDist = std::max(maxDist, d); } greatestDistance[i] = sqrt(maxDist); } } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceSulcalDepth.h0000664000175000017500000000613611572067322025542 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_BRAIN_MODEL_SURFACE_SULCAL_DEPTH_H__ #define __GUI_BRAIN_MODEL_SURFACE_SULCAL_DEPTH_H__ #include "BrainModelAlgorithm.h" class BrainModelSurface; class CoordinateFile; class SurfaceShapeFile; class vtkPolyData; /// Class to generate a sulcal depth map for a surface class BrainModelSurfaceSulcalDepth : public BrainModelAlgorithm { public: enum DEPTH_COLUMNS { DEPTH_COLUMN_CREATE_NEW = -1, DEPTH_COLUMN_DO_NOT_GENERATE = -2 }; /// Constructor BrainModelSurfaceSulcalDepth(BrainSet* bs, BrainModelSurface* surfaceIn, const QString& hullVtkFilenNameIn, SurfaceShapeFile* shapeFileIn, const int hullSmoothingIterationsIn, const int depthSmoothingIterationsIn, const int depthColumnIn, const int smoothedDepthColumnIn, const QString& depthNameIn, const QString& smoothedDepthNameIn, CoordinateFile* outputHullCoordFileIn); /// Destructor ~BrainModelSurfaceSulcalDepth(); /// execute the algorithm virtual void execute() throw (BrainModelAlgorithmException); private: /// surface for depth computation BrainModelSurface* surface; /// the hull vtk file name QString hullVtkFileName; /// surface shape file for storage of depth SurfaceShapeFile* shapeFile; /// column for depth int depthColumn; /// column for smoothed depth int smoothedDepthColumn; /// name for depth column QString depthName; /// name for smoothed depth column QString smoothedDepthName; /// hull smoothing interations int hullSmoothingIterations; /// depth smoothing interations int depthSmoothingIterations; /// hull coord file with same number of nodes as input surface CoordinateFile* outputHullCoordFile; }; #endif // __GUI_BRAIN_MODEL_SURFACE_SULCAL_DEPTH_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceSulcalDepth.cxx0000664000175000017500000002444611572067322026121 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurface.h" #include "BrainModelSurfacePointLocator.h" #include "BrainModelSurfaceSulcalDepth.h" #include "BrainSet.h" #include "DebugControl.h" #include "MathUtilities.h" #include "SurfaceShapeFile.h" #include "TopologyFile.h" #include "TopologyHelper.h" /** * Constructor. */ BrainModelSurfaceSulcalDepth::BrainModelSurfaceSulcalDepth( BrainSet* bs, BrainModelSurface* surfaceIn, const QString& hullVtkFileNameIn, SurfaceShapeFile* shapeFileIn, const int hullSmoothingIterationsIn, const int depthSmoothingIterationsIn, const int depthColumnIn, const int smoothedDepthColumnIn, const QString& depthNameIn, const QString& smoothedDepthNameIn, CoordinateFile* outputHullCoordFileIn) : BrainModelAlgorithm(bs) { surface = surfaceIn; shapeFile = shapeFileIn; depthColumn = depthColumnIn; smoothedDepthColumn = smoothedDepthColumnIn; hullSmoothingIterations = hullSmoothingIterationsIn; depthSmoothingIterations = depthSmoothingIterationsIn; hullVtkFileName = hullVtkFileNameIn; depthName = depthNameIn; smoothedDepthName = smoothedDepthNameIn; outputHullCoordFile = outputHullCoordFileIn; } /** * Destructor. */ BrainModelSurfaceSulcalDepth::~BrainModelSurfaceSulcalDepth() { } /** * execute the algorithm */ void BrainModelSurfaceSulcalDepth::execute() throw (BrainModelAlgorithmException) { // // Create surface shape columns if needed // if (depthColumn == DEPTH_COLUMN_CREATE_NEW) { if (shapeFile->getNumberOfColumns() == 0) { shapeFile->setNumberOfNodesAndColumns(surface->getNumberOfNodes(), 1); } else { shapeFile->addColumns(1); } depthColumn = shapeFile->getNumberOfColumns() - 1; } if (smoothedDepthColumn == DEPTH_COLUMN_CREATE_NEW) { if (shapeFile->getNumberOfColumns() == 0) { shapeFile->setNumberOfNodesAndColumns(surface->getNumberOfNodes(), 1); } else { shapeFile->addColumns(1); } smoothedDepthColumn = shapeFile->getNumberOfColumns() - 1; } // // Set column names // if (depthColumn >= 0) { shapeFile->setColumnName(depthColumn, depthName); shapeFile->setColumnColorMappingMinMax(depthColumn, -30.0, 10.0); } if (smoothedDepthColumn >= 0) { shapeFile->setColumnName(smoothedDepthColumn, smoothedDepthName); shapeFile->setColumnColorMappingMinMax(smoothedDepthColumn, -30.0, 10.0); } // // Convert the hull to a brain model surface // BrainSet hullBrainSet; try { hullBrainSet.importVtkSurfaceFile(hullVtkFileName, true, true, false, BrainModelSurface::SURFACE_TYPE_FIDUCIAL, TopologyFile::TOPOLOGY_TYPE_CLOSED); } catch (FileException& e) { throw BrainModelAlgorithmException(e.whatQString()); } // // Hull should be first brain model // BrainModelSurface* hullSurface = hullBrainSet.getBrainModelSurface(0); if (hullSurface == NULL) { throw BrainModelAlgorithmException("Hull surface is missing."); } // // Save hull prior to smoothing // const BrainModelSurface* unsmoothedHullSurface = new BrainModelSurface(*hullSurface); const CoordinateFile* unsmoothedHullCoords = unsmoothedHullSurface->getCoordinateFile(); if (hullSmoothingIterations > 0) { // // Smooth the hull // hullSurface->arealSmoothing(1.0, hullSmoothingIterations, 0); } // // Make sure hull's normals point outward // hullSurface->orientNormalsOut(); // // Create a point locator for the hull surface // BrainModelSurfacePointLocator hullLocator(hullSurface, true); // // Get surface and hull coordinates // const CoordinateFile* surfaceCoords = surface->getCoordinateFile(); const int numSurfaceNodes = surfaceCoords->getNumberOfCoordinates(); const CoordinateFile* hullCoords = hullSurface->getCoordinateFile(); // // TopologyHelper for surface // const TopologyFile* surfaceTopologyFile = surface->getTopologyFile(); const TopologyHelper* surfaceTopologyHelper = surfaceTopologyFile->getTopologyHelper(false, true, false); // // initialize hull coord file // if ((numSurfaceNodes > 0) && (outputHullCoordFile != NULL)) { outputHullCoordFile->setNumberOfCoordinates(numSurfaceNodes); } // // Determine depth values for surface nodes // for (int i = 0; i < numSurfaceNodes; i++) { // // initially set the depth to zero // if (depthColumn >= 0) { shapeFile->setValue(i, depthColumn, 0.0); } if (smoothedDepthColumn >= 0) { shapeFile->setValue(i, smoothedDepthColumn, 0.0); } // // Make sure surface node has neighbors // if (surfaceTopologyHelper->getNodeHasNeighbors(i) == false) { continue; } // // coordinate of surface node // const float* surfaceXYZ = surfaceCoords->getCoordinate(i); // // Find node in hull that is nearest this surface node // const int nearestNode = hullLocator.getNearestPoint(surfaceXYZ); // // If nearest node found in hull // if (nearestNode >= 0) { // // Get the coordinate of the hull nearest node // const float* hullXYZ = hullCoords->getCoordinate(nearestNode); // // Get normal of hull node // const float* hullNormal = hullSurface->getNormal(nearestNode); // // Compute signed distance from surface not to point on plane from hull normal // const float distanceFromPlane = MathUtilities::signedDistanceToPlane(hullNormal, hullXYZ, surfaceXYZ); // // Distance between surface and hull point // float distance = MathUtilities::distance3D(hullXYZ, surfaceXYZ); // // Set the sign for inside or outside the hull // if (distanceFromPlane < 0.0) { distance = -distance; } if (DebugControl::getDebugOn()) { if (i == DebugControl::getDebugNodeNumber()) { const float* sn = surface->getNormal(i); std::cout << "surface node: " << i << std::endl; std::cout << " hull node: " << nearestNode << std::endl; std::cout << " surface node: " << surfaceXYZ[0] << ", " << surfaceXYZ[1] << ", " << surfaceXYZ[2] << std::endl; std::cout << " dot: " << MathUtilities::dotProduct(sn, hullNormal) << std::endl; std::cout << " surface normal: " << sn[0] << ", " << sn[1] << ", " << sn[2] << std::endl; std::cout << " hull node: " << hullXYZ[0] << ", " << hullXYZ[1] << ", " << hullXYZ[2] << std::endl; std::cout << " hull normal: " << hullNormal[0] << ", " << hullNormal[1] << ", " << hullNormal[2] << std::endl; std::cout << " distance: " << distance << std::endl; std::cout << " distance/plane: " << distanceFromPlane << std::endl; } } // // Insert into the surface shape file // if (depthColumn >= 0) { shapeFile->setValue(i, depthColumn, distance); } if (smoothedDepthColumn >= 0) { shapeFile->setValue(i, smoothedDepthColumn, distance); } // // output hull coord file // if (outputHullCoordFile != NULL) { outputHullCoordFile->setCoordinate(i, unsmoothedHullCoords->getCoordinate(nearestNode)); } } else { // // output hull coord file // if (outputHullCoordFile != NULL) { outputHullCoordFile->setCoordinate(i, 0.0, 0.0, 0.0); } } } // // if creating smoothed depth, smooth it // if ((smoothedDepthColumn >= 0) && (depthSmoothingIterations > 0)) { shapeFile->smoothAverageNeighbors(smoothedDepthColumn, smoothedDepthColumn, shapeFile->getColumnName(smoothedDepthColumn), 1.0, depthSmoothingIterations, surface->getTopologyFile()); } // // Free memory // delete unsmoothedHullSurface; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceStandardSphere.h0000664000175000017500000000351411572067322026236 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_STANDARD_SPHERE_H__ #define __BRAIN_MODEL_SURFACE_STANDARD_SPHERE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelAlgorithm.h" /// Read a standard sphere into a brain set class BrainModelSurfaceStandardSphere : public BrainModelAlgorithm { public: /// Constructor BrainModelSurfaceStandardSphere(BrainSet* bs, const int numberOfNodesIn); /// Destructor ~BrainModelSurfaceStandardSphere(); /// execute the algorithm void execute() throw (BrainModelAlgorithmException); /// get available number of nodes and triangles static void getNumberOfNodesAndTriangles( std::vector& numNodesOut, std::vector& numTrianglesOut); protected: /// number of nodse in surface const int numberOfNodes; }; #endif // __BRAIN_MODEL_SURFACE_STANDARD_SPHERE_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceStandardSphere.cxx0000664000175000017500000001010411572067322026602 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurfaceStandardSphere.h" #include "BrainModelSurface.h" #include "BrainSet.h" #include "SpecFile.h" /** * Constructor. */ BrainModelSurfaceStandardSphere::BrainModelSurfaceStandardSphere( BrainSet* bs, const int numberOfNodesIn) : BrainModelAlgorithm(bs), numberOfNodes(numberOfNodesIn) { } /** * Destructor. */ BrainModelSurfaceStandardSphere::~BrainModelSurfaceStandardSphere() { } /** * get number of nodes and triangles from the number of iterations. */ void BrainModelSurfaceStandardSphere::getNumberOfNodesAndTriangles( std::vector& numNodesOut, std::vector& numTrianglesOut) { numNodesOut.clear(); numTrianglesOut.clear(); // // sphere.v5.1.spec // numNodesOut.push_back(74); numTrianglesOut.push_back(144); // // sphere.v5.2.spec // numNodesOut.push_back(290); numTrianglesOut.push_back(576); // // sphere.v5.3.spec // numNodesOut.push_back(1154); numTrianglesOut.push_back(2304); // // sphere.v5.4.spec // numNodesOut.push_back(4610); numTrianglesOut.push_back(9216); // // sphere.v5.5.spec // numNodesOut.push_back(18434); numTrianglesOut.push_back(36864); // // sphere.v5.6.spec // numNodesOut.push_back(73730); numTrianglesOut.push_back(147456); } /** * execute the algorithm. */ void BrainModelSurfaceStandardSphere::execute() throw (BrainModelAlgorithmException) { // // Read in the standard sphere // QString standardSphereSpecName(brainSet->getCaretHomeDirectory()); switch(numberOfNodes) { case 74: standardSphereSpecName.append("/data_files/REGISTER.SPHERE/sphere.v5.1.spec"); break; case 290: standardSphereSpecName.append("/data_files/REGISTER.SPHERE/sphere.v5.2.spec"); break; case 1154: standardSphereSpecName.append("/data_files/REGISTER.SPHERE/sphere.v5.3.spec"); break; case 4610: standardSphereSpecName.append("/data_files/REGISTER.SPHERE/sphere.v5.4.spec"); break; case 18434: standardSphereSpecName.append("/data_files/REGISTER.SPHERE/sphere.v5.5.spec"); break; case 73730: standardSphereSpecName.append("/data_files/REGISTER.SPHERE/sphere.v5.6.spec"); break; } // // Read in the standard sphere spec file // try { SpecFile sf; sf.readFile(standardSphereSpecName); sf.setAllFileSelections(SpecFile::SPEC_TRUE); QString errorMessage; brainSet->readSpecFile(sf, standardSphereSpecName, errorMessage); if (errorMessage.isEmpty() == false) { throw BrainModelAlgorithmException(errorMessage); } // // Get the standard spherical surface // BrainModelSurface* standardSphere = brainSet->getBrainModelSurface(0); if (standardSphere == NULL) { throw BrainModelAlgorithmException( "Unable to find standard sphere after reading it"); } } catch (FileException e) { throw BrainModelAlgorithmException(e.whatQString()); } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceSphericalTessellator.h0000664000175000017500000001051111572067322027456 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_SPHERICAL_TESSELLATOR_H__ #define __BRAIN_MODEL_SURFACE_SPHERICAL_TESSELLATOR_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainModelAlgorithm.h" #include "Tessellation.h" class BrainModelSurface; class CoordinateFile; class PointLocator; class TopologyFile; /// Class that retessellates a sphere class BrainModelSurfaceSphericalTessellator : public BrainModelAlgorithm { public: /// Constructor BrainModelSurfaceSphericalTessellator(BrainSet* bsIn, BrainModelSurface* sphereSurfaceIn, const std::vector& includeNodeInTessellationFlagsIn); /// Destructor ~BrainModelSurfaceSphericalTessellator(); /// execute the algorithm void execute() throw (BrainModelAlgorithmException); /// get a pointer to the new spherical surface BrainModelSurface* getPointerToNewSphericalSurface() { return newSphericalSurface; } protected: /// clear the tessellation process void clear(); /// execute the tessellation algorithm void executeTessellation() throw (BrainModelAlgorithmException); /// create the initial sphere void createInitialSphere() throw (BrainModelAlgorithmException); /// create a sphere from the tessellation void createSphereFromTessellation() throw (BrainModelAlgorithmException); /// Find the tessellation triangle containing the new point TessTriangle* findContainingTriangle(const double xyz[3], TessVertex* tv); /// Find the nearest node in the tessellation. TessVertex* getNearestNodeInTessellation(const double* xyz, double& distanceSquared); /// get a triangles circumcenter and radius void getCircumcenterAndRadius(TessTriangle* tt, double center[3], double& radius); /// insert nodes into the sphere void insertNodesIntoSphere(const int callNum) throw (TessellationException); /// process all of the suspect triangles who made need their edges flipped void processSuspectTriangles(Tessellation::TriangleSet& suspectTriangles) throw (TessellationException); /// orient the triangle so that the normal points out void orientTriangleVertices(TessTriangle* tt); /// Create the point locator void createPointLocator(); /// the new spherical surface that is created BrainModelSurface* newSphericalSurface; /// the original spherical surface const BrainModelSurface* originalSphereSurface; /// number of nodes int numNodes; /// the suspect triangles who may require an edge flip //Tessellation::TriangleSet suspectTriangles; /// the tessellation Tessellation* tess; /// the point locator PointLocator* pointLocator; /// the coordinates double* pointXYZ; /// flags that indicate if node should be included in the tessellation std::vector includeNodeInTessellationFlags; /// original flags that indicate if node should be included in the tessellation const std::vector originalIncludeNodeInTessellationFlags; }; #endif // __BRAIN_MODEL_SURFACE_SPHERICAL_TESSELLATOR_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceSphericalTessellator.cxx0000664000175000017500000007006111572067322030037 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include "vtkTriangle.h" #include "vtkPointLocator.h" #include "vtkPoints.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceSphericalTessellator.h" #include "BrainSet.h" #include "DebugControl.h" #include "MathUtilities.h" #include "PointLocator.h" #include "TopologyFile.h" #include "TopologyHelper.h" /** * Constructor. */ BrainModelSurfaceSphericalTessellator::BrainModelSurfaceSphericalTessellator( BrainSet* bsIn, BrainModelSurface* sphereSurfaceIn, const std::vector& includeNodeInTessellationFlagsIn) : BrainModelAlgorithm(bsIn), originalSphereSurface(sphereSurfaceIn), originalIncludeNodeInTessellationFlags(includeNodeInTessellationFlagsIn) { pointLocator = NULL; pointXYZ = NULL; newSphericalSurface = NULL; tess = NULL; } /** * Destructor. */ BrainModelSurfaceSphericalTessellator::~BrainModelSurfaceSphericalTessellator() { clear(); } /** * reset the tessellation process. */ void BrainModelSurfaceSphericalTessellator::clear() { if (pointLocator != NULL) { delete pointLocator; pointLocator = NULL; } if (pointXYZ != NULL) { delete[] pointXYZ; } if (tess != NULL) { delete tess; tess = NULL; } } /** * execute the algorithm. */ void BrainModelSurfaceSphericalTessellator::execute() throw (BrainModelAlgorithmException) { QTime timer; timer.start(); // // Sometimes the tessellation algorithm fails. Since it randomizes the node // insertion order try it several times before giving up // QString errorMessage; const int maxTries = 10; for (int i = 0; i < maxTries; i++) { clear(); newSphericalSurface = NULL; numNodes = 0; includeNodeInTessellationFlags = originalIncludeNodeInTessellationFlags; try { executeTessellation(); return; } catch (BrainModelAlgorithmException& e) { errorMessage += (e.whatQString() + "\n"); std::cout << "INFO: spherical tessellation failed but trying it again." << std::endl; } } if (DebugControl::getDebugOn()) { std::cout << "Time to tessellate: " << timer.elapsed() * 0.001 << std::endl; } throw BrainModelAlgorithmException(errorMessage); } /** * create the initial sphere. */ void BrainModelSurfaceSphericalTessellator::createInitialSphere() throw (BrainModelAlgorithmException) { // // nodes with minimum and maximum xyz // double minmax[6] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; int nodes[6] = { -1, -1, -1, -1, -1, -1 }; // // Find the extreme nodes // for (int i = 0; i < numNodes; i++) { if (includeNodeInTessellationFlags[i]) { const double x = pointXYZ[i*3]; if (x < minmax[0]) { minmax[0] = x; nodes[0] = i; } if (x > minmax[1]) { minmax[1] = x; nodes[1] = i; } const double y = pointXYZ[i*3+1]; if (y < minmax[2]) { minmax[2] = y; nodes[2] = i; } if (y > minmax[3]) { minmax[3] = y; nodes[3] = i; } const double z = pointXYZ[i*3+2]; if (z < minmax[4]) { minmax[4] = z; nodes[4] = i; } if (z > minmax[5]) { minmax[5] = z; nodes[5] = i; } } } // // Make sure extreme coords are unique // std::set uniqueTest; for (int i = 0; i < 6; i++) { if (nodes[i] >= 0) { uniqueTest.insert(nodes[i]); } else { throw BrainModelAlgorithmException("Could not find extreme nodes"); } } if (uniqueTest.size() != 6) { throw BrainModelAlgorithmException("Could not find unique extreme nodes"); } // // Mark extreme nodes no longer available // for (int i = 0; i < 6; i++) { includeNodeInTessellationFlags[nodes[i]] = false; } // // Create tessellation vertices // TessVertex* v1 = new TessVertex(nodes[0]); TessVertex* v2 = new TessVertex(nodes[1]); TessVertex* v3 = new TessVertex(nodes[2]); TessVertex* v4 = new TessVertex(nodes[3]); TessVertex* v5 = new TessVertex(nodes[4]); TessVertex* v6 = new TessVertex(nodes[5]); // // Add vertices to the tessellation // tess->addVertex(v1); tess->addVertex(v2); tess->addVertex(v3); tess->addVertex(v4); tess->addVertex(v5); tess->addVertex(v6); // // Add to the point locator // if (pointLocator != NULL) { const CoordinateFile* coordFile = originalSphereSurface->getCoordinateFile(); for (int m = 0; m < 6; m++) { pointLocator->addPoint(coordFile->getCoordinate(nodes[m]), -1); } } // // Add triangles to the tessellation // Tessellation::EdgeVector noEdges; tess->addTriangle(v1, v4, v6, noEdges); tess->addTriangle(v4, v2, v6, noEdges); tess->addTriangle(v2, v3, v6, noEdges); tess->addTriangle(v3, v1, v6, noEdges); tess->addTriangle(v1, v4, v5, noEdges); tess->addTriangle(v4, v2, v5, noEdges); tess->addTriangle(v2, v3, v5, noEdges); tess->addTriangle(v3, v1, v5, noEdges); } /** * Find the nearest node in the tessellation. */ TessVertex* BrainModelSurfaceSphericalTessellator::getNearestNodeInTessellation(const double* xyz, double& distanceSquared) { distanceSquared = std::numeric_limits::max(); TessVertex* vertexOut = NULL; Tessellation::VertexVector* vertices = tess->getVertexVector(); const float p[3] = { xyz[0], xyz[1], xyz[2] }; if (pointLocator != NULL) { const int plNode = pointLocator->getNearestPoint(p); vertexOut = (*vertices)[plNode]; } if (vertexOut == NULL) { const CoordinateFile* coordFile = originalSphereSurface->getCoordinateFile(); for (Tessellation::VertexVectorIterator vi = vertices->begin(); vi != vertices->end(); vi++) { TessVertex* tv = *vi; const int nodeNumber = tv->getUniqueID(); const double distSQ = coordFile->getDistanceToPointSquared(nodeNumber, p); if (distSQ < distanceSquared) { distanceSquared = distSQ; vertexOut = tv; } } } return vertexOut; } /** * Find the tessellation triangle containing the new point. */ TessTriangle* BrainModelSurfaceSphericalTessellator::findContainingTriangle(const double xyz[3], TessVertex* tv) { for (int loop = 0; loop < 2; loop++) { // // Get the vertex's triangles // Tessellation::TriangleList triangles = *(tv->getMyTriangles()); // // Should we check triangles used by neighbors // if (loop == 1) { // // Set for unique triangles // Tessellation::TriangleSet ts; // // Get the neighboring vertices // Tessellation::VertexList vl; tv->getNeighborVertices(vl); // // Loop through neighboring vertices // for (Tessellation::VertexListIterator vli = vl.begin(); vli != vl.end(); vli++) { // // Get the triangles from the vertex // TessVertex* tv = *vli; Tessellation::TriangleList* vertexTriangles = tv->getMyTriangles(); // // Loop through triangles // for (Tessellation::TriangleListIterator tli = vertexTriangles->begin(); tli != vertexTriangles->end(); tli++) { // // Get the triangle // TessTriangle* tvt = *tli; // // If triangle not previously searched // if (std::find(triangles.begin(), triangles.end(), tvt) == triangles.end()) { // // Add to search list // ts.insert(tvt); } } } // // Set the new triangles that are to be searched // triangles.clear(); triangles.insert(triangles.begin(), ts.begin(), ts.end()); if (DebugControl::getDebugOn()) { std::cout << "Checking neighbor triangles." << std::endl; } } // if (loop == 1) // // Iterate through the triangles // for (Tessellation::TriangleListIterator ti = triangles.begin(); ti != triangles.end(); ti++) { TessTriangle* tt = *ti; // // Get the triangles vertices // TessVertex *tv1, *tv2, *tv3; tt->getVertices(tv1, tv2, tv3); // // Get the node number of the triangle's vertices // const int n1 = tv1->getUniqueID(); const int n2 = tv2->getUniqueID(); const int n3 = tv3->getUniqueID(); // // Get coordinates of triangle's vertices // double* p1 = &pointXYZ[n1*3]; double* p2 = &pointXYZ[n2*3]; double* p3 = &pointXYZ[n3*3]; // // Find out where ray from origin to query point intersects plane of triangle. // Returns false if ray is parallel to plane. // const double origin[3] = { 0.0, 0.0, 0.0 }; double pointOnPlane[3]; if (MathUtilities::rayIntersectPlane(p1, p2, p3, origin, xyz, pointOnPlane)) { // // Normal of tile // double normal[3]; MathUtilities::computeNormal((double*)p1, (double*)p2, (double*)p3, normal); // // Compute areas of triangles formed by triangle vertices and point on plane // const double area1 = MathUtilities::signedTriangleArea3D(normal, p1, p2, pointOnPlane); if (area1 > 0.0) { const double area2 = MathUtilities::signedTriangleArea3D(normal, p2, p3, pointOnPlane); if (area2 > 0.0) { const double area3 = MathUtilities::signedTriangleArea3D(normal, p3, p1, pointOnPlane); if (area3 > 0.0) { return tt; } } } } } } return NULL; } /** * insert nodes into the sphere. */ void BrainModelSurfaceSphericalTessellator::insertNodesIntoSphere( const int callNum) throw (TessellationException) { const double nodeToleranceSquared = 0.1 * 0.1; int cnt = 0; // // Randomly sort the nodes // std::vector randomized(numNodes); for (int k = 0; k < numNodes; k++) { randomized[k] = k; } std::random_shuffle(randomized.begin(), randomized.end()); // // Loop through the nodes // for (int j = 0; j < numNodes; j++) { const int nodeNum = randomized[j]; // // If this node is not yet in the sphere // if (includeNodeInTessellationFlags[nodeNum]) { // // Mark it as no longer available // includeNodeInTessellationFlags[nodeNum] = false; // // Get the node's coordinates // double xyz[3] = { pointXYZ[nodeNum*3], pointXYZ[nodeNum*3+1], pointXYZ[nodeNum*3+2] }; if (callNum > 0) { const float delta = 0.00001; xyz[0] += delta * callNum; xyz[1] += delta * callNum; xyz[2] += delta * callNum; } // // Find the nearest vertex in the tessellation // double distSQ = 0.0; TessVertex* nearestVertex = getNearestNodeInTessellation(xyz, distSQ); if (nearestVertex == NULL) { throw BrainModelAlgorithmException("No nearest node found."); } // // If distance to nearest node is less than tolerance, then skip node // if (distSQ < nodeToleranceSquared) { if (DebugControl::getDebugOn()) { std::cout << "INFO: Node " << nodeNum << " within tolerance so not added to tessellation." << std::endl; } } else { // // Find the tile that contains the node // TessTriangle* tt = findContainingTriangle(xyz, nearestVertex); // // Was a containing triangle found // if (tt != NULL) { if (DebugControl::getDebugOn()) { std::cout << "Inserting node: " << nodeNum << std::endl; } else if ((j % 1000) == 0) { } // // Get the triangle's neighbors // TessTriangle* neighbors[3]; tt->getNeighborTriangles(neighbors); // // Create a new vertex and add to tessellation // TessVertex* tv = new TessVertex(nodeNum); tess->addVertex(tv); // // Add to the point locator // if (pointLocator != NULL) { float xyzfloat[3] = { xyz[0], xyz[1], xyz[2] }; pointLocator->addPoint(xyzfloat, -1); } // // Get the vertices of the triangle // TessVertex *tv1, *tv2, *tv3; tt->getVertices(tv1, tv2, tv3); // // Get the edges of the triangle // Tessellation::EdgeVector adjacentEdges; tt->getEdges(adjacentEdges, NULL); // // Delete the triangle that contained the node // tess->removeTriangle(tt); // // Create the three new edges // adjacentEdges.push_back(tess->addEdge(tv1, tv)); adjacentEdges.push_back(tess->addEdge(tv2, tv)); adjacentEdges.push_back(tess->addEdge(tv3, tv)); // // Create three new triangles // TessTriangle* tt1 = tess->addTriangle(tv1, tv2, tv, adjacentEdges); TessTriangle* tt2 = tess->addTriangle(tv2, tv3, tv, adjacentEdges); TessTriangle* tt3 = tess->addTriangle(tv3, tv1, tv, adjacentEdges); // // Orient the triangle vertices so normal points out // orientTriangleVertices(tt1); orientTriangleVertices(tt2); orientTriangleVertices(tt3); // // Mark the triangles neighbors as suspect // Tessellation::TriangleSet suspectTriangles; for (int k = 0; k < 3; k++) { if (neighbors[k] != NULL) { suspectTriangles.insert(neighbors[k]); } } // // process all of the suspect triangles // processSuspectTriangles(suspectTriangles); //tess->getEulerCount(v, e, f, euler); cnt++; if (cnt > 50) { //break; } } // (tt != NULL) else { if (DebugControl::getDebugOn()) { std::cout << "No containing triangle found for node " << nodeNum << std::endl; } // // Mark it as available since it did not get inserted (try later) // includeNodeInTessellationFlags[nodeNum] = true; } } } } } /** * get a triangles circumcenter and radius. */ void BrainModelSurfaceSphericalTessellator::getCircumcenterAndRadius(TessTriangle* tt, double center[3], double& radius) { // // Get the triangles vertices // TessVertex *tv1, *tv2, *tv3; tt->getVertices(tv1, tv2, tv3); // // Get the node number of the triangle's vertices // const int n1 = tv1->getUniqueID(); const int n2 = tv2->getUniqueID(); const int n3 = tv3->getUniqueID(); // // Get circumcenter and radius // double* p1 = &pointXYZ[n1*3]; double* p2 = &pointXYZ[n2*3]; double* p3 = &pointXYZ[n3*3]; MathUtilities::triangleCircumcenter3D(p1, p2, p3, center, radius); } /** * process all of the suspect triangles who made need their edges flipped. */ void BrainModelSurfaceSphericalTessellator::processSuspectTriangles(Tessellation::TriangleSet& suspectTriangles) throw (TessellationException) { // // While there are suspect triangles // while (suspectTriangles.empty() == false) { // // Get and remove the triangle from the suspect list // Tessellation::TriangleSetIterator iter = suspectTriangles.begin(); TessTriangle* tt = *iter; suspectTriangles.erase(tt); // // Determine triangles circumcenter and radius // double center[3], radius; getCircumcenterAndRadius(tt, center, radius); // // Shrink the radius a little to avoid precision problems // radius *= 0.98; // // Get neighboring triangles // TessTriangle* triangleNeighbors[3]; tt->getNeighborTriangles(triangleNeighbors); // // loop through neighboring triangles // for (int i = 0; i < 3; i++) { // // Is triangle valid // if (triangleNeighbors[i] != NULL) { // // Get the non-shared vertex // TessVertex* tv = tt->getVertexNotInThisTriangle(triangleNeighbors[i]); if (tv != NULL) { // // Get the coordinate of the vertex // const int uniqueID = tv->getUniqueID(); double* xyz = &pointXYZ[uniqueID*3]; // // Get distance between new vertex and circumcenter // const double dist = MathUtilities::distance3D(xyz, center); // // if vertex is within the circumcircle // if (dist < radius) { // // Remove other triangle from the suspect list // suspectTriangles.erase(triangleNeighbors[i]); // // Create new triangles by swapping the shared edge // TessTriangle *new1, *new2; tess->swapTriangleEdges(tt, triangleNeighbors[i], new1, new2); // // Orient the new triangle so normal points out // orientTriangleVertices(new1); orientTriangleVertices(new2); // // mark new triangle neighbors as suspect // TessTriangle* neighbors[3]; new1->getNeighborTriangles(neighbors); for (int k = 0; k < 3; k++) { if (neighbors[k] != NULL) { if (neighbors[k] != new2) { suspectTriangles.insert(neighbors[k]); } } } new2->getNeighborTriangles(neighbors); for (int k = 0; k < 3; k++) { if (neighbors[k] != NULL) { if (neighbors[k] != new1) { suspectTriangles.insert(neighbors[k]); } } } // // Get out of neighboring triangles loop // i = 3; } // (dist < radius) } // (tv != NULL) else { // // Remove other triangle from the suspect list // suspectTriangles.erase(triangleNeighbors[i]); } } } } } /** * create a sphere from the tessellation. */ void BrainModelSurfaceSphericalTessellator::createSphereFromTessellation() throw (BrainModelAlgorithmException) { // // Get the triangles in the tessellation // Tessellation::CaretTriangleList* triangles = tess->getTriangleList(); if (triangles->empty()) { throw BrainModelAlgorithmException("Tessellation produced no triangles."); } // // Create a spherical brain model // newSphericalSurface = new BrainModelSurface(brainSet); newSphericalSurface->setSurfaceType(BrainModelSurface::SURFACE_TYPE_SPHERICAL); // // Get the coordinate file // CoordinateFile* cf = newSphericalSurface->getCoordinateFile(); // // Copy the coordinate file from the input surface // const CoordinateFile* coordFile = originalSphereSurface->getCoordinateFile(); *cf = *coordFile; cf->appendToFileComment("\nCreated by tessellating sphere."); //cf->setFileName("new_sphere_tessellation.coord"); cf->setModified(); // // Create a new topology file // TopologyFile* topoFile = new TopologyFile; QString topoFileName = topoFile->getFileName(); const TopologyFile* inputTopoFile = originalSphereSurface->getTopologyFile(); if (inputTopoFile != NULL) { topoFileName = inputTopoFile->getFileName(); } topoFile->setFileName(topoFileName); topoFile->replaceFileNameDescription("CLOSED_CORRECTED"); topoFile->setTopologyType(TopologyFile::TOPOLOGY_TYPE_CLOSED); topoFile->setFileComment("Created by spherical tessellator."); // // Add the topology file to the brain set // brainSet->addTopologyFile(topoFile); // // Copy the triangles from the tessellation // TessTriangle* tt = (TessTriangle*)triangles->getFront(); while (tt != NULL) { // // Get the vertices of the triangle // TessVertex* v1; TessVertex* v2; TessVertex* v3; tt->getVertices(v1, v2, v3); // // Add new triangle to topology // topoFile->addTile(v1->getUniqueID(), v2->getUniqueID(), v3->getUniqueID()); tt = (TessTriangle*)tt->getNext(); } // // Add the topology file to the surface // newSphericalSurface->setTopologyFile(topoFile); // // Orient the tiles so that they point correctly // newSphericalSurface->orientTilesOutward(BrainModelSurface::SURFACE_TYPE_SPHERICAL); newSphericalSurface->computeNormals(); // // Rename the spherical to SphericalCorrected // newSphericalSurface->getCoordinateFile()->replaceFileNameDescription("SPHERICAL_RETESSELLATED"); // // Add the surface to the brain set // brainSet->addBrainModel(newSphericalSurface); } /** * orient the triangle so that the normal points out. */ void BrainModelSurfaceSphericalTessellator::orientTriangleVertices(TessTriangle* tt) { // // Get the triangles vertices // TessVertex *v1, *v2, *v3; tt->getVertices(v1, v2, v3); // // Get the coordinates of the nodes // const double* c1 = &pointXYZ[v1->getUniqueID()*3]; const double* c2 = &pointXYZ[v2->getUniqueID()*3]; const double* c3 = &pointXYZ[v3->getUniqueID()*3]; // // Compute the tiles normal // double normal[3]; MathUtilities::computeNormal((double*)c1, (double*)c2, (double*)c3, normal); // // Use average of the three nodes as normal // Assumes sphere is centered at origin // double avg[3] = { (c1[0] + c2[0] + c3[0]) / 3.0, (c1[1] + c2[1] + c3[1]) / 3.0, (c1[2] + c2[2] + c3[2]) / 3.0 }; MathUtilities::normalize(avg); // // Does normal point into the sphere // if (MathUtilities::dotProduct(normal, avg) < 0.0) { tt->setVertices(v3, v2, v1); } } /** * Create the point locator. */ void BrainModelSurfaceSphericalTessellator::createPointLocator() { const CoordinateFile* coordFile = originalSphereSurface->getCoordinateFile(); float bounds[6]; coordFile->getBounds(bounds); const float smallNumber = 0.01; bounds[0] -= smallNumber; bounds[1] += smallNumber; bounds[2] -= smallNumber; bounds[3] += smallNumber; bounds[4] -= smallNumber; bounds[5] += smallNumber; int dims[3] = { 20, 20, 20 }; //{ 10, 10, 10 }; pointLocator = new PointLocator(bounds, dims); } /** * execute the tessellationalgorithm. */ void BrainModelSurfaceSphericalTessellator::executeTessellation() throw (BrainModelAlgorithmException) { if (originalSphereSurface == NULL) { throw BrainModelAlgorithmException("Input sphere surface is NULL."); } // // Create the tessellation object // tess = new Tessellation; // // Get the number of nodes // numNodes = originalSphereSurface->getNumberOfNodes(); try { // // Get the coordinate file // const CoordinateFile* coordFile = originalSphereSurface->getCoordinateFile(); // // Get the points // pointXYZ = new double[numNodes*3]; for (int i = 0; i < numNodes; i++) { const float* xyz = coordFile->getCoordinate(i); pointXYZ[i*3] = xyz[0]; pointXYZ[i*3+1] = xyz[1]; pointXYZ[i*3+2] = xyz[2]; } // // Create the point locator // createPointLocator(); // // Create the initial sphere // createInitialSphere(); if (DebugControl::getDebugOn()) { tess->printEulerCounts("Initial sphere: "); } // // Insert the remaining nodes into the sphere // for (int m = 0; m < 5; m++) { //std::cout << "Insertion iteration: " << m << std::endl; insertNodesIntoSphere(m); } // // Create a new sphere from the tessellation // createSphereFromTessellation(); if (DebugControl::getDebugOn()) { tess->printEulerCounts("Final sphere: "); std::cout << "Total nodes input: " << numNodes << std::endl; } } catch (TessellationException& te) { throw BrainModelAlgorithmException(te.whatQString()); } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceSmoothing.h0000664000175000017500000001510611572067322025276 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __BRAIN_MODEL_SURFACE_SMOOTHING_H__ #define __BRAIN_MODEL_SURFACE_SMOOTHING_H__ #include #include #include "BrainModelAlgorithmMultiThreaded.h" class BrainModelSurface; class QWaitCondition; class TopologyHelper; /// class for smoothing a brain model surface, multiple threads optional class BrainModelSurfaceSmoothing : public BrainModelAlgorithmMultiThreaded { public: /// Types of smoothing enum SMOOTHING_TYPE { SMOOTHING_TYPE_AREAL, SMOOTHING_TYPE_LINEAR, SMOOTHING_TYPE_LANDMARK_CONSTRAINED, SMOOTHING_TYPE_LANDMARK_NEIGHBOR_CONSTRAINED }; /// constructor BrainModelSurfaceSmoothing(BrainSet* bs, BrainModelSurface* surfaceIn, const SMOOTHING_TYPE smoothingTypeIn, const float strengthIn, const int iterationsIn, const int edgeIterationsIn, const int landmarkNeighborIterationsIn, const std::vector* smoothOnlyTheseNodesIn, const std::vector* landmarkNodeFlagsIn, const int projectToSphereEveryXIterationsIn, const int numberOfThreadsIn); /// Destructor ~BrainModelSurfaceSmoothing(); /// execute the algorithm void execute() throw (BrainModelAlgorithmException); protected: /// class stores information about each node class NodeInfo { public: /// constructor NodeInfo(); /// node types enum NODE_TYPE { NODE_TYPE_DO_NOT_SMOOTH, NODE_TYPE_NORMAL, NODE_TYPE_LANDMARK, NODE_TYPE_LANDMARK_NEIGHBOR }; /// type of node NODE_TYPE nodeType; /// edge node flag int edgeNodeFlag; /// number of landmark neighbors int numLandmarkNeighbors; /// offset of a landmark node from average of its neighbors float offset[3]; }; /// Constructor (protected) used to created threaded executions. BrainModelSurfaceSmoothing(BrainSet* bs, const SMOOTHING_TYPE smoothingTypeIn, const float strengthIn, const float landmarkScaleIn, NodeInfo* nodeInfoIn, TopologyHelper* topologyHelperIn, const int startNodeIndexIn, const int endNodeIndexIn, BrainModelSurfaceSmoothing* parentOfThisThreadIn, const int threadNumberIn); /// Initialize member variables. void initialize(); /// smooths for an iteration (required by QThread) void run(); /// set smooth edges this iteration void setSmoothEdgesThisIteration(const bool smooth) { smoothEdgesThisIteration = smooth; } /// set smooth landmark neighbors this iteration void setSmoothLandmarkNeighborsThisIteration(const bool smooth) { smoothLandmarkNeighborsThisIteration = smooth; } /// set the indices of the nodes that are to be smoothed (inclusive) void setIndicesOfNodesToSmooth(const int startNodeIndexIn, const int endNodeIndexIn); /// set the input and output coords void setInputAndOutputCoords(float* inCoords, float* outCoords); /// surface that is smoothed (DO NOT DELETE) BrainModelSurface* surface; /// smoothing type SMOOTHING_TYPE smoothingType; /// smoothing strength; float strength; /// inverse of strength (1.0 - strength) float inverseStrength; /// smoothing iterations int iterations; /// smoothing edge iterations int edgeIterations; /// smoothing landmark neighbors iterations int landmarkNeighborIterations; /// number of nodes int numberOfNodes; /// topology helper used to get node neighbors TopologyHelper* topologyHelper; /// array for holding coordinates (inputCoords and outputCoords point to this) float* coordsArray1; /// array for holding coordinates (inputCoords and outputCoords point to this) float* coordsArray2; /// pointers for input coordinates (do not delete) float* inputCoords; /// pointers for output coordinates (do not delete) float* outputCoords; /// smooth edges this iteration bool smoothEdgesThisIteration; /// index of first node to smooth int startNodeIndex; /// index of last node to smooth int endNodeIndex; /// threads when running multi-threaded. std::vector threads; /// project to sphere every X iterations int projectToSphereEveryXIterations; /// information about each node NodeInfo* nodeInfo; /// scale for landmark nodes float landmarkScale; /// smooth landmark neighbors this iteration bool smoothLandmarkNeighborsThisIteration; }; #ifdef __BRAIN_MODEL_SURFACE_SMOOTHING_MAIN_H__ #endif // __BRAIN_MODEL_SURFACE_SMOOTHING_MAIN_H__ #endif // __BRAIN_MODEL_SURFACE_SMOOTHING_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceSmoothing.cxx0000664000175000017500000010015711572067322025652 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include "vtkTriangle.h" #define __BRAIN_MODEL_SURFACE_SMOOTHING_MAIN_H__ #include "BrainModelSurfaceSmoothing.h" #undef __BRAIN_MODEL_SURFACE_SMOOTHING_MAIN_H__ #include "BrainModelSurface.h" #include "BrainSet.h" #include "BrainSetNodeAttribute.h" #include "DebugControl.h" #include "MathUtilities.h" #include "StringUtilities.h" #include "TopologyFile.h" #include "TopologyHelper.h" static const int SLEEP_TIME = 1; static const int SLEEP_TIME_MICROSECONDS = 250; /** * Constructor for the main controller of smoothing. */ BrainModelSurfaceSmoothing::BrainModelSurfaceSmoothing( BrainSet* bs, BrainModelSurface* surfaceIn, const SMOOTHING_TYPE smoothingTypeIn, const float strengthIn, const int iterationsIn, const int edgeIterationsIn, const int landmarkNeighborIterationsIn, const std::vector* smoothOnlyTheseNodesIn, const std::vector* landmarkNodeFlagsIn, const int projectToSphereEveryXIterationsIn, const int numberOfThreadsIn) : BrainModelAlgorithmMultiThreaded(bs, NULL, -1, false) { initialize(); surface = surfaceIn; smoothingType = smoothingTypeIn; strength = strengthIn; iterations = iterationsIn; edgeIterations = edgeIterationsIn; landmarkNeighborIterations = landmarkNeighborIterationsIn; const int numNodes = surfaceIn->getNumberOfNodes(); if (numNodes > 0) { nodeInfo = new NodeInfo[numNodes]; } if (smoothOnlyTheseNodesIn != NULL) { const int smoothOnlyTheseNodesCount = static_cast(smoothOnlyTheseNodesIn->size()); if (smoothOnlyTheseNodesCount > 0) { for (int i = 0; i < smoothOnlyTheseNodesCount; i++) { if ((*smoothOnlyTheseNodesIn)[i] == false) { nodeInfo[i].nodeType = NodeInfo::NODE_TYPE_DO_NOT_SMOOTH; } } } } // // Process landmarks and determine landmark neighbors // if (landmarkNodeFlagsIn != NULL) { const int nodeCount = static_cast(landmarkNodeFlagsIn->size()); CoordinateFile* cf = surface->getCoordinateFile(); const float* coords = cf->getCoordinate(0); const TopologyFile* topology = surface->getTopologyFile(); const TopologyHelper* th = topology->getTopologyHelper(false, true, true); //const TopologyHelper th(topology, false, true, true); if (nodeCount > 0) { bool haveLandmarkScale = false; for (int i = 0; i < nodeCount; i++) { // // Get the neighbors for this node // int numNeighbors = 0; const int* neighbors = th->getNodeNeighbors(i, numNeighbors); // // Is this a landmark node ? // if ((*landmarkNodeFlagsIn)[i]) { nodeInfo[i].nodeType = NodeInfo::NODE_TYPE_LANDMARK; if (smoothingType == SMOOTHING_TYPE_LANDMARK_NEIGHBOR_CONSTRAINED) { // // Determine offset of this landmark from its neighbors // float neighborSum[3] = { 0.0, 0.0, 0.0 }; for (int j = 0; j < numNeighbors; j++) { const int n = neighbors[j]; neighborSum[0] += coords[n*3]; neighborSum[1] += coords[n*3+1]; neighborSum[2] += coords[n*3+2]; } const float floatNeighbors = numNeighbors; nodeInfo[i].offset[0] = coords[i*3] - (neighborSum[0] / floatNeighbors); nodeInfo[i].offset[1] = coords[i*3+1] - (neighborSum[1] / floatNeighbors); nodeInfo[i].offset[2] = coords[i*3+2] - (neighborSum[2] / floatNeighbors); } } else { // // // see if any of its neighbors are landmark nodes for (int j = 0; j < numNeighbors; j++) { const int n = neighbors[j]; if ((*landmarkNodeFlagsIn)[n]) { nodeInfo[i].numLandmarkNeighbors++; } else { if (haveLandmarkScale == false) { haveLandmarkScale = true; landmarkScale = MathUtilities::distance3D(cf->getCoordinate(i), cf->getCoordinate(n)) / std::sqrt(3.0); } } } if (nodeInfo[i].numLandmarkNeighbors > 0) { nodeInfo[i].nodeType = NodeInfo::NODE_TYPE_LANDMARK_NEIGHBOR; } } } } //std::cout << "LandmarkScale=" << landmarkScale << std::endl; // // Special stuff for landmark neighbor constrained smoothing // if (smoothingType == SMOOTHING_TYPE_LANDMARK_NEIGHBOR_CONSTRAINED) { for (int i = 0; i < numNodes; i++) { // // Is this a landmark neighbor // if (nodeInfo[i].nodeType == NodeInfo::NODE_TYPE_LANDMARK_NEIGHBOR) { // // Get the neighbors for this node // int numNeighbors = 0; const int* neighbors = th->getNodeNeighbors(i, numNeighbors); // // Get average of landmark neighbor offsets // float avg[3] = { 0.0, 0.0, 0.0 }; for (int j = 0; j < numNeighbors; j++) { const int n = neighbors[j]; if (nodeInfo[n].nodeType == NodeInfo::NODE_TYPE_LANDMARK) { avg[0] += nodeInfo[n].offset[0]; avg[1] += nodeInfo[n].offset[1]; avg[2] += nodeInfo[n].offset[2]; } } // // Offset this landmark neighbor // const float floatNumLandmarkNeighbors = nodeInfo[i].numLandmarkNeighbors; float xyz[3]; cf->getCoordinate(i, xyz); xyz[0] += (avg[0] / floatNumLandmarkNeighbors); xyz[1] += (avg[1] / floatNumLandmarkNeighbors); xyz[2] += (avg[2] / floatNumLandmarkNeighbors); cf->setCoordinate(i, xyz); } } } } // if (landmarkNodeFlagsIn != NULL) projectToSphereEveryXIterations = projectToSphereEveryXIterationsIn; setNumberOfThreadsToRun(numberOfThreadsIn); } /** * Constructor (protected) used to created threaded executions. */ BrainModelSurfaceSmoothing::BrainModelSurfaceSmoothing(BrainSet* bs, const SMOOTHING_TYPE smoothingTypeIn, const float strengthIn, const float landmarkScaleIn, NodeInfo* nodeInfoIn, TopologyHelper* topologyHelperIn, const int startNodeIndexIn, const int endNodeIndexIn, BrainModelSurfaceSmoothing* parentOfThisThreadIn, const int threadNumberIn) : BrainModelAlgorithmMultiThreaded(bs, parentOfThisThreadIn, threadNumberIn, true) { initialize(); smoothingType = smoothingTypeIn; strength = strengthIn; inverseStrength = 1.0 - strength; nodeInfo = nodeInfoIn; topologyHelper = topologyHelperIn; startNodeIndex = startNodeIndexIn; endNodeIndex = endNodeIndexIn; landmarkScale = landmarkScaleIn; } /** * Destructor. */ BrainModelSurfaceSmoothing::~BrainModelSurfaceSmoothing() { if (getImAThread() == false) { if (coordsArray1 != NULL) { delete[] coordsArray1; } if (coordsArray2 != NULL) { delete[] coordsArray2; } if (topologyHelper != NULL) { // delete topologyHelper; } if (nodeInfo != NULL) { delete[] nodeInfo; } for (unsigned int i = 0; i < threads.size(); i++) { if (threads[i] != NULL) { delete threads[i]; } } } } /** * Initialize member variables. */ void BrainModelSurfaceSmoothing::initialize() { coordsArray1 = NULL; coordsArray2 = NULL; topologyHelper = NULL; nodeInfo = NULL; landmarkScale = 1.0; } /** * Execute the algorithm. */ void BrainModelSurfaceSmoothing::execute() throw (BrainModelAlgorithmException) { if (surface == NULL) { throw BrainModelAlgorithmException("Surfaced is invalid (NULL)."); } numberOfNodes = surface->getNumberOfNodes(); if (numberOfNodes <= 0) { throw BrainModelAlgorithmException("Surface has no nodes to smooth."); } // // No need to do anything if iterations is zero // if (iterations <= 0) { return; } // // Update node classification // TopologyFile* topology = surface->getTopologyFile(); brainSet->classifyNodes(topology, true); inverseStrength = 1.0 - strength; if (numberOfNodes <= 0) { throw BrainModelAlgorithmException("Surface has no nodes"); } // // Timer to time entire operation // QTime timer; timer.start(); /* switch(smoothingType) { case SMOOTHING_TYPE_AREAL: surface->appendToCoordinateFileComment("Areal "); break; case SMOOTHING_TYPE_LINEAR: surface->appendToCoordinateFileComment("Linear "); break; } surface->appendToCoordinateFileComment(" Smoothing: "); surface->appendToCoordinateFileComment(StringUtilities::fromNumber(strength)); surface->appendToCoordinateFileComment(" "); surface->appendToCoordinateFileComment(StringUtilities::fromNumber(iterations)); surface->appendToCoordinateFileComment(" "); surface->appendToCoordinateFileComment(StringUtilities::fromNumber(edgeIterations)); surface->appendToCoordinateFileComment("\n"); */ // // Get radius in event it is a sphere // const float sphereRadius = surface->getSphericalSurfaceRadius(); // // Topology helper for node neighbors // //topologyHelper = new TopologyHelper(topology, false, true, true); topologyHelper = (TopologyHelper*)topology->getTopologyHelper(false, true, true); if (DebugControl::getDebugOn()) { std::cout << "Topology Helper time: " << (static_cast(timer.elapsed()) / 1000.0) << std::endl; } // // Flag for interior/edge nodes // for (int i = 0; i < numberOfNodes; i++) { const BrainSetNodeAttribute* bna = brainSet->getNodeAttributes(i); nodeInfo[i].edgeNodeFlag = ! (bna->getClassification() == BrainSetNodeAttribute::CLASSIFICATION_TYPE_INTERIOR); } // // Get the coordinates and load them into arrays // float* coordsArray1 = new float[numberOfNodes * 3]; float* coordsArray2 = new float[numberOfNodes * 3]; CoordinateFile* coordFile = surface->getCoordinateFile(); for (int i = 0; i < numberOfNodes; i++) { coordFile->getCoordinate(i, &coordsArray1[i*3]); } // // Set the input and output coord pointers // inputCoords = coordsArray1; outputCoords = coordsArray2; int smoothNeighborCounter = 1; // // See if threads are being used, and if so, create them. // const int numberOfThreads = getNumberOfThreadsToRun(); if (numberOfThreads > 1) { // // Number of nodes each thread should smooth // const int numNodesPerThread = numberOfNodes / numberOfThreads; int startNode = 0; int endNode = numNodesPerThread; for (int i = 0; i < numberOfThreads; i++) { // // Limit ending node for last thread // if (i == (numberOfThreads - 1)) { endNode = numberOfNodes - 1; } if (DebugControl::getDebugOn()) { std::cout << "Smoothing thread " << i << " nodes " << startNode << " " << endNode << std::endl; } // // Create the threads // BrainModelSurfaceSmoothing* bmss = new BrainModelSurfaceSmoothing( brainSet, smoothingType, strength, landmarkScale, nodeInfo, topologyHelper, startNode, endNode, this, i); threads.push_back(bmss); // // Determine node indices which each thread should smooth // startNode = endNode + 1; endNode += numNodesPerThread; } } // // Smooth the specified number of iterations // for (int i = 1; i <= iterations; i++) { const bool firstIterationFlag = (i == 1); const bool lastIterationFlag = (i == iterations); // // See if edges should be smoothed this iteration // smoothEdgesThisIteration = false; if (edgeIterations > 0) { if ((i % edgeIterations) == 0) { smoothEdgesThisIteration = true; } } // // See if landmark neighbors should be smoothed this iteration // smoothLandmarkNeighborsThisIteration = false; if (smoothNeighborCounter == landmarkNeighborIterations) { smoothLandmarkNeighborsThisIteration = true; smoothNeighborCounter = 1; } else { smoothNeighborCounter++; } // // If running threads // if (numberOfThreads > 1) { for (int j = 0; j < numberOfThreads; j++) { // // Run each thread for an iteration of smoothing // threads[j]->setInputAndOutputCoords(inputCoords, outputCoords); threads[j]->setSmoothEdgesThisIteration(smoothEdgesThisIteration); threads[j]->setSmoothLandmarkNeighborsThisIteration(smoothLandmarkNeighborsThisIteration); // // Clear the number of child threads done // resetNumChildThreadDone(); // // Start the threads if this is the first iteration // if (firstIterationFlag) { threads[j]->setThreadKeepLoopingFlag(true); threads[j]->setThreadedIterationDoneFlag(true); threads[j]->start(QThread::TimeCriticalPriority); } /* // // if the last iteration clear the keep looping flag // if (lastIterationFlag ) { threads[j]->setThreadKeepLoopingFlag(false); } */ } // // Wait until all threads have started and in their loop. // This is need for the case that there is only one iteration. // while (getNumChildThreadStarted() < numberOfThreads) { //msleep(SLEEP_TIME); usleep(SLEEP_TIME_MICROSECONDS); } for (int j = 0; j < numberOfThreads; j++) { // // if the last iteration, clear the keep looping flag for the thread // if (lastIterationFlag ) { threads[j]->setThreadKeepLoopingFlag(false); } // // wake the thread so that it executes an iteration // if (DebugControl::getDebugOn()) { std::cout << "Allowing smoothing thread " << j << " to run." << std::endl; } threads[j]->setThreadedIterationDoneFlag(false); } // // Wait until all of the threads finish // while (getNumChildThreadDone() < numberOfThreads) { //msleep(SLEEP_TIME); usleep(SLEEP_TIME_MICROSECONDS); } if (DebugControl::getDebugOn()) { std::cout << "All smoothing threads completed iteration." << std::endl; } } else { // // // Smooth for one iteration // setIndicesOfNodesToSmooth(0, numberOfNodes - 1); run(); } // // If the surface should be projected to a sphere // if (projectToSphereEveryXIterations > 0) { if ((i % projectToSphereEveryXIterations) == 0) { for (int j = 0; j < numberOfNodes; j++) { MathUtilities::setVectorLength(&outputCoords[j*3], sphereRadius); } } } // // If NOT the last iteration // if (lastIterationFlag == false) { // // Update the displayed brain model // if (brainSet->isIterationUpdate(i)) { for (int j = 0; j < numberOfNodes; j++) { coordFile->setCoordinate(j, &outputCoords[j*3]); } brainSet->drawBrainModel(surface, i); } // // swap input and output coordinate pointers // std::swap(inputCoords, outputCoords); } } // // copy the smoothed coordinates back to the surface // for (int i = 0; i < numberOfNodes; i++) { coordFile->setCoordinate(i, &outputCoords[i*3]); } if (DebugControl::getDebugOn()) { std::cout << "Total smoothing time: " << (static_cast(timer.elapsed()) / 1000.0) << std::endl; } } /** * smooths for an iteration (required by QThread). */ void BrainModelSurfaceSmoothing::run() { const int maxNeighbors = topologyHelper->getMaximumNumberOfNeighbors(); if (maxNeighbors <= 0) { return; } float* tileAreas = new float[maxNeighbors]; float* tileCenters = new float[maxNeighbors * 3]; // // set looping flag for non-threaded execution so that we do an iteration // if (getImAThread() == false) { setThreadKeepLoopingFlag(true); } // // The threaded execution will stay in the loop since run only gets called once // while (getThreadKeepLoopingFlag()) { // // Is this a threaded instance // if (getImAThread()) { // // let parent know that this thread has started // getParentOfThisThread()->incrementNumChildThreadStarted(); // // Wait until parent says it is okay to go // while (getThreadedIterationDoneFlag()) { //msleep(SLEEP_TIME); usleep(SLEEP_TIME_MICROSECONDS); } if (DebugControl::getDebugOn()) { std::cout << "Smoothing Thread " << getThreadNumber() << " now executing." << std::endl; } } for (int i = startNodeIndex; i <= endNodeIndex; i++) { const int ix = i * 3; const int iy = ix + 1; const int iz = iy + 1; outputCoords[ix] = inputCoords[ix]; outputCoords[iy] = inputCoords[iy]; outputCoords[iz] = inputCoords[iz]; // // Determine if this node should be smoothed // bool smoothIt = true; if (nodeInfo[i].edgeNodeFlag) { smoothIt = smoothEdgesThisIteration; } // // Special cases of smoothing // switch (nodeInfo[i].nodeType) { case NodeInfo::NODE_TYPE_DO_NOT_SMOOTH: smoothIt = false; break; case NodeInfo::NODE_TYPE_NORMAL: break; case NodeInfo::NODE_TYPE_LANDMARK: smoothIt = false; break; case NodeInfo::NODE_TYPE_LANDMARK_NEIGHBOR: if (smoothingType == SMOOTHING_TYPE_LANDMARK_NEIGHBOR_CONSTRAINED) { smoothIt = smoothLandmarkNeighborsThisIteration; } if (smoothingType == SMOOTHING_TYPE_LANDMARK_CONSTRAINED) { smoothIt = false; // // Get the neighbors for this node // int numNeighbors = 0; const int* neighbors = topologyHelper->getNodeNeighbors(i, numNeighbors); if (numNeighbors > 2) { // // Determine average of neighbor coordinates // float neighAvg[3] = { 0.0, 0.0, 0.0 }; for (int j = 0; j < numNeighbors; j++) { const int n = neighbors[j]; neighAvg[0] += inputCoords[n*3]; neighAvg[1] += inputCoords[n*3+1]; neighAvg[2] += inputCoords[n*3+2]; } const float floatNumNeigh = numNeighbors; neighAvg[0] /= floatNumNeigh; neighAvg[1] /= floatNumNeigh; neighAvg[2] /= floatNumNeigh; // // Check each neighbor // for (int k = 0; k < numNeighbors; k++) { // // Is the neighbor a landmark // const int neigh = neighbors[k]; if (nodeInfo[neigh].nodeType == NodeInfo::NODE_TYPE_LANDMARK) { // // Get next and previous neighbors // int prevNeighIndex = k - 1; if (prevNeighIndex < 0) { prevNeighIndex = numNeighbors - 1; } const int neighA = neighbors[prevNeighIndex]; int nextNeighIndex = k + 1; if (nextNeighIndex >= numNeighbors) { nextNeighIndex = 0; } const int neighB = neighbors[nextNeighIndex]; // // Get coordinates of the neighbors // const float* ai = &inputCoords[neighA * 3]; const float* bi = &inputCoords[neighB * 3]; const float* li = &inputCoords[neigh * 3]; // // Adjust position of neighbor average // float p[3] = { 2 * li[0] - ai[0] - bi[0], 2 * li[1] - ai[1] - bi[1], 2 * li[2] - ai[2] - bi[2] }; const float len = std::sqrt(p[0]*p[0] + p[1]*p[1] + p[2]*p[2]); p[0] /= len; p[1] /= len; p[2] /= len; neighAvg[0] += li[0] + landmarkScale * p[0]; neighAvg[1] += li[1] + landmarkScale * p[1]; neighAvg[2] += li[2] + landmarkScale * p[2]; //std::cout << "Node " // << i // << ": p[" // << p[0] // << "," // << p[1] // << "," // << p[2] // << "]" // << std::endl; } } const float neighPlusOne = nodeInfo[i].numLandmarkNeighbors + 1; neighAvg[0] /= neighPlusOne; neighAvg[1] /= neighPlusOne; neighAvg[2] /= neighPlusOne; outputCoords[ix] = inverseStrength * inputCoords[ix] + strength * neighAvg[0]; outputCoords[iy] = inverseStrength * inputCoords[iy] + strength * neighAvg[1]; outputCoords[iz] = inverseStrength * inputCoords[iz] + strength * neighAvg[2]; } } break; } if (smoothIt) { // // Get the neighbors for this node // int numNeighbors = 0; const int* neighbors = topologyHelper->getNodeNeighbors(i, numNeighbors); bool arealSmoothIt = false; bool linearSmoothIt = false; switch (smoothingType) { case SMOOTHING_TYPE_LANDMARK_NEIGHBOR_CONSTRAINED: linearSmoothIt = true; break; case SMOOTHING_TYPE_LANDMARK_CONSTRAINED: linearSmoothIt = true; break; case SMOOTHING_TYPE_AREAL: arealSmoothIt = true; break; case SMOOTHING_TYPE_LINEAR: linearSmoothIt = true; break; } if (arealSmoothIt) { if (numNeighbors > 1) { float totalArea = 0.0; for (int j = 0; j < numNeighbors; j++) { // // get 2 consecutive neighbors of this node // const int n1 = neighbors[j]; int next = j + 1; if (next >= numNeighbors) { next = 0; } const int n2 = neighbors[next]; // // Area of the triangle // const float area = MathUtilities::triangleArea(&inputCoords[ix], &inputCoords[n1*3], &inputCoords[n2*3]); tileAreas[j] = area; totalArea += area; // // Save center of this tile // for (int k = 0; k < 3; k++) { float p = (inputCoords[ix+k] + inputCoords[n1*3+k] + inputCoords[n2*3+k]) / 3.0; tileCenters[j*3+k] = p; } } // // Total area is zero when this node and all of its neighbors // have the exact same XYZ coordinate // if (totalArea > 0.0) { // // Compute the influence of the neighboring nodes // float xa = 0.0; float ya = 0.0; float za = 0.0; for (int j = 0; j < numNeighbors; j++) { if (tileAreas[j] > 0.0) { const float weight = tileAreas[j] / totalArea; xa += weight * tileCenters[j*3]; ya += weight * tileCenters[j*3+1]; za += weight * tileCenters[j*3+2]; } } // // Update the nodes position // outputCoords[ix] = inputCoords[ix] * inverseStrength + xa * strength; outputCoords[iy] = inputCoords[iy] * inverseStrength + ya * strength; outputCoords[iz] = inputCoords[iz] * inverseStrength + za * strength; } } } if (linearSmoothIt) { if (numNeighbors > 1) { float neighXYZ[3] = { 0.0, 0.0, 0.0 }; for (int j = 0; j < numNeighbors; j++) { const int n = neighbors[j]; neighXYZ[0] += inputCoords[n*3]; neighXYZ[1] += inputCoords[n*3+1]; neighXYZ[2] += inputCoords[n*3+2]; } const float floatNumNeigh = numNeighbors; neighXYZ[0] /= floatNumNeigh; neighXYZ[1] /= floatNumNeigh; neighXYZ[2] /= floatNumNeigh; outputCoords[ix] = inputCoords[ix] * inverseStrength + neighXYZ[0] * strength; outputCoords[iy] = inputCoords[iy] * inverseStrength + neighXYZ[1] * strength; outputCoords[iz] = inputCoords[iz] * inverseStrength + neighXYZ[2] * strength; } } } } if (getImAThread()) { if (DebugControl::getDebugOn()) { std::cout << "Smoothing Thread " << getThreadNumber() << " finished iteration." << std::endl; } // // A threaded instance needs to tell that it has completed an iteration // setThreadedIterationDoneFlag(true); getParentOfThisThread()->incrementNumChildThreadDone(); } else { // // A non-threaded instance needs to return // setThreadKeepLoopingFlag(false); } } // while (keepLooping) delete[] tileAreas; delete[] tileCenters; } /** * Set the indices of the nodes that are to be smoothed (inclusive). */ void BrainModelSurfaceSmoothing::setIndicesOfNodesToSmooth(const int startNodeIndexIn, const int endNodeIndexIn) { startNodeIndex = startNodeIndexIn; endNodeIndex = endNodeIndexIn; } /** * Set the input and output coords */ void BrainModelSurfaceSmoothing::setInputAndOutputCoords(float* inCoords, float* outCoords) { inputCoords = inCoords; outputCoords = outCoords; } // //****************************************************************************************** // /** * Constructor */ BrainModelSurfaceSmoothing::NodeInfo::NodeInfo() { nodeType = NODE_TYPE_NORMAL; numLandmarkNeighbors = 0; offset[0] = 0.0; offset[1] = 0.0; offset[2] = 0.0; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceResection.h0000664000175000017500000000570511572067322025266 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __BRAIN_MODEL_SURFACE_RESECTION_H__ #define __BRAIN_MODEL_SURFACE_RESECTION_H__ #include "BrainModelAlgorithm.h" class BrainModelSurface; class SectionFile; class vtkTransform; /// Class for resectioning a surface class BrainModelSurfaceResection : public BrainModelAlgorithm { public: /// sectioning axis enum SECTION_AXIS { SECTION_AXIS_X, SECTION_AXIS_Y, SECTION_AXIS_Z, SECTION_AXIS_Z_WITH_ROTATION_MATRIX }; /// sectioning type enum SECTION_TYPE { SECTION_TYPE_THICKNESS, SECTION_TYPE_NUM_SECTIONS }; /// constructor BrainModelSurfaceResection(BrainSet* brainSetIn, BrainModelSurface* bmsIn, vtkTransform* rotationMatrixIn, const SECTION_AXIS sectionAxisIn, const SECTION_TYPE sectionTypeIn, SectionFile* sectionFileIn, const int columnNumberIn, const QString& columnNameIn, const float thicknessIn, const int numSectionsIn); /// destructor ~BrainModelSurfaceResection(); /// execute the algorithm virtual void execute() throw (BrainModelAlgorithmException); private: /// the surface for to use for sectioning BrainModelSurface* bms; /// the rotation matrix vtkTransform* rotationMatrix; /// the section axis SECTION_AXIS sectionAxis; /// the section type SECTION_TYPE sectionType; /// the section file SectionFile* sectionFile; /// the column in the section file int columnNumber; /// the name for the column QString columnName; /// the thickness for sectioning float thickness; /// the desired number of sections int numSections; }; #endif // __BRAIN_MODEL_SURFACE_RESECTION_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceResection.cxx0000664000175000017500000001232611572067322025636 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #ifdef Q_OS_WIN32 #define NOMINMAX #endif #include #include #include "BrainModelSurface.h" #include "BrainModelSurfaceResection.h" #include "SectionFile.h" #include "TopologyFile.h" #include "TopologyHelper.h" #include "vtkTransform.h" /** * Constructor */ BrainModelSurfaceResection::BrainModelSurfaceResection( BrainSet* brainSetIn, BrainModelSurface* bmsIn, vtkTransform* rotationMatrixIn, const SECTION_AXIS sectionAxisIn, const SECTION_TYPE sectionTypeIn, SectionFile* sectionFileIn, const int columnNumberIn, const QString& columnNameIn, const float thicknessIn, const int numSectionsIn) : BrainModelAlgorithm(brainSetIn) { bms = bmsIn; rotationMatrix = rotationMatrixIn; sectionAxis = sectionAxisIn; sectionType = sectionTypeIn; sectionFile = sectionFileIn; columnNumber = columnNumberIn; thickness = thicknessIn; numSections = numSectionsIn; columnName = columnNameIn; } /** * destructor. */ BrainModelSurfaceResection::~BrainModelSurfaceResection() { } /** * execute the algorithm */ void BrainModelSurfaceResection::execute() throw (BrainModelAlgorithmException) { // // Get a topology helper const TopologyFile* tf = bms->getTopologyFile(); if (tf == NULL) { throw BrainModelAlgorithmException("Surface has no topology file."); } const TopologyHelper* th = tf->getTopologyHelper(false, true, false); vtkMatrix4x4* matrix = vtkMatrix4x4::New(); if (rotationMatrix != NULL) { rotationMatrix->GetMatrix(matrix); //matrix->Transpose(); } // // // Coordinate component based upon the axis being used and // get min and max points // float ptMin = std::numeric_limits::max(); float ptMax = std::numeric_limits::min(); const int numNodes = bms->getNumberOfNodes(); const CoordinateFile* coords = bms->getCoordinateFile(); std::vector ptXYZ(numNodes); for (int i = 0; i < numNodes; i++) { float xyzw[4]; coords->getCoordinate(i, xyzw); switch (sectionAxis) { case SECTION_AXIS_X: ptXYZ[i] = xyzw[0]; break; case SECTION_AXIS_Y: ptXYZ[i] = xyzw[1]; break; case SECTION_AXIS_Z: ptXYZ[i] = xyzw[2]; break; case SECTION_AXIS_Z_WITH_ROTATION_MATRIX: { float pt[4]; xyzw[3] = 1.0; matrix->MultiplyPoint(xyzw, pt); ptXYZ[i] = pt[2]; } break; } // // Update min and max // ptMin = std::min(ptMin, ptXYZ[i]); ptMax = std::max(ptMax, ptXYZ[i]); } matrix->Delete(); // // If computing sections based upon thickness // convert to number of sections // switch (sectionType) { case SECTION_TYPE_THICKNESS: numSections = static_cast(((ptMax - ptMin) / thickness) + 0.5); break; case SECTION_TYPE_NUM_SECTIONS: break; } // // Add space to the section file if needed and set column name // if ((columnNumber < 0) || (columnNumber >= sectionFile->getNumberOfColumns())) { if (sectionFile->getNumberOfColumns() <= 0) { sectionFile->setNumberOfNodesAndColumns(numNodes, 1); } else { sectionFile->addColumns(1); } columnNumber = sectionFile->getNumberOfColumns() - 1; } sectionFile->setColumnName(columnNumber, columnName); // // determine the sections // const float scale = static_cast(numSections) / (ptMax - ptMin); for (int i = 0; i < numNodes; i++) { int sectionNumber = 0; if (th->getNodeHasNeighbors(i)) { sectionNumber = static_cast(scale * (ptXYZ[i] - ptMin)); } sectionFile->setSection(i, columnNumber, sectionNumber); } // // Update minimum and maximum sections // sectionFile->postColumnCreation(columnNumber); } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceROITextReport.h0000664000175000017500000000760311572067322026024 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_ROI_TEXT_REPORT_H__ #define __BRAIN_MODEL_SURFACE_ROI_TEXT_REPORT_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelSurfaceROIOperation.h" class CoordinateFile; class LatLonFile; class MetricFile; class PaintFile; class SurfaceShapeFile; class TopologyFile; /// class for performing region of interest operations on a surface class BrainModelSurfaceROITextReport : public BrainModelSurfaceROIOperation { public: // constructor BrainModelSurfaceROITextReport(BrainSet* bs, const BrainModelSurface* bmsIn, const BrainModelSurfaceROINodeSelection* surfaceROIIn, MetricFile* metricFileIn, const std::vector& selectedMetricColumnsForReportIn, MetricFile* shapeFileIn, const std::vector& selectedShapeColumnsForReportIn, PaintFile* paintFileIn, const std::vector& selectedPaintColumnsForReportIn, LatLonFile* latLonFileIn, const int latLonFileColumnIn, const QString& headerTextIn, MetricFile* metricCorrectionFileIn, const int metricCorrectionColumnIn, const bool tabSeparateReportFlagIn); // destructor ~BrainModelSurfaceROITextReport(); protected: // execute the operation void executeOperation() throw (BrainModelAlgorithmException); // create the text report void createTextReport() throw (BrainModelAlgorithmException); // Peform Metric and Surface Shape Report. void metricAndSurfaceShapeReport(const bool metricFlag); // perform paint report void paintReport(const float roiArea); /// selected metric columns std::vector selectedMetricColumnsForReport; /// selected surface shape columns std::vector selectedShapeColumnsForReport; /// selected paint columns std::vector selectedPaintColumnsForReport; /// lat lon file for report LatLonFile* reportLatLonFile; /// column for report lat lon file int reportLatLonFileColumn; /// metric file for report MetricFile* reportMetricFile; /// shape file for report MetricFile* reportShapeFile; /// paint file for report PaintFile* reportPaintFile; /// metric correction file for report MetricFile* reportMetricCorrectionFile; /// the metric correction column int metricCorrectionColumn; /// tab separate the report bool tabSeparateReportFlag; }; #endif // __BRAIN_MODEL_SURFACE_ROI_TEXT_REPORT_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceROITextReport.cxx0000664000175000017500000005647111572067322026406 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include "BrainModelSurface.h" #include "BrainModelSurfaceROINodeSelection.h" #include "BrainModelSurfaceROITextReport.h" #include "BrainSet.h" #include "CoordinateFile.h" #include "DebugControl.h" #include "FileUtilities.h" #include "LatLonFile.h" #include "MetricFile.h" #include "PaintFile.h" #include "StatisticsUtilities.h" #include "StringUtilities.h" #include "SurfaceShapeFile.h" #include "TopologyFile.h" /** * constructor. */ BrainModelSurfaceROITextReport::BrainModelSurfaceROITextReport(BrainSet* bs, const BrainModelSurface* bmsIn, const BrainModelSurfaceROINodeSelection* surfaceROIIn, MetricFile* metricFileIn, const std::vector& selectedMetricColumnsForReportIn, MetricFile* shapeFileIn, const std::vector& selectedShapeColumnsForReportIn, PaintFile* paintFileIn, const std::vector& selectedPaintColumnsForReportIn, LatLonFile* latLonFileIn, const int latLonFileColumnIn, const QString& headerTextIn, MetricFile* metricCorrectionFileIn, const int metricCorrectionColumnIn, const bool tabSeparateReportFlagIn) : BrainModelSurfaceROIOperation(bs, bmsIn, surfaceROIIn) { reportLatLonFile = NULL; reportMetricFile = NULL; reportShapeFile = NULL; reportPaintFile = NULL; reportMetricCorrectionFile = NULL; reportMetricFile = metricFileIn; selectedMetricColumnsForReport = selectedMetricColumnsForReportIn; reportShapeFile = shapeFileIn; selectedShapeColumnsForReport = selectedShapeColumnsForReportIn; reportPaintFile = paintFileIn; selectedPaintColumnsForReport = selectedPaintColumnsForReportIn; reportLatLonFile = latLonFileIn; reportLatLonFileColumn = latLonFileColumnIn; setHeaderText(headerTextIn); reportMetricCorrectionFile = metricCorrectionFileIn; metricCorrectionColumn = metricCorrectionColumnIn; tabSeparateReportFlag = tabSeparateReportFlagIn; } /** * destructor. */ BrainModelSurfaceROITextReport::~BrainModelSurfaceROITextReport() { } /** * execute the operation. */ void BrainModelSurfaceROITextReport::executeOperation() throw (BrainModelAlgorithmException) { reportText = ""; createTextReport(); } /** * create the text report. */ void BrainModelSurfaceROITextReport::createTextReport() throw (BrainModelAlgorithmException) { float roiArea = 0.0; createReportHeader(roiArea); // // ROI for metrics // if (reportMetricFile != NULL) { if (std::count(selectedMetricColumnsForReport.begin(), selectedMetricColumnsForReport.end(), true) > 0) { metricAndSurfaceShapeReport(true); } } // // ROI for surface shape // if (reportShapeFile != NULL) { if (std::count(selectedShapeColumnsForReport.begin(), selectedShapeColumnsForReport.end(), true) > 0) { metricAndSurfaceShapeReport(false); } } // // ROI for paint // if (reportPaintFile != NULL) { if (std::count(selectedPaintColumnsForReport.begin(), selectedPaintColumnsForReport.end(), true) > 0) { paintReport(roiArea); } } reportText.append("\n"); } /** * perform paint report. */ void BrainModelSurfaceROITextReport::paintReport(const float roiArea) { const CoordinateFile* cf = bms->getCoordinateFile(); const TopologyFile* tf = bms->getTopologyFile(); const int numTiles = tf->getNumberOfTiles(); const int numPaintNames = reportPaintFile->getNumberOfPaintNames(); bool latLonValid = false; if (reportLatLonFile != NULL) { if ((reportLatLonFileColumn >= 0) && (reportLatLonFileColumn < reportLatLonFile->getNumberOfColumns() > 0)) { latLonValid = true; } } // // Find longest paint name use in the ROI // int longestPaintNameLength = 11; for (int m = 0; m < numPaintNames; m++) { longestPaintNameLength = std::max(static_cast(reportPaintFile->getPaintNameFromIndex(m).length()), longestPaintNameLength); } longestPaintNameLength += 3; const int numberSize = 16; // // surface area for each paint name // std::vector paintNameAreas(numPaintNames, 0.0); std::vector paintNameAreasCorrected(numPaintNames, 0.0); std::vector paintNameAreasCogX(numPaintNames, 0.0); std::vector paintNameAreasCogY(numPaintNames, 0.0); std::vector paintNameAreasCogZ(numPaintNames, 0.0); std::vector paintNameAreasLat(numPaintNames, 0.0); std::vector paintNameAreasLon(numPaintNames, 0.0); std::vector paintNameNodeCounts(numPaintNames, 0); const int numPaintColumns = reportPaintFile->getNumberOfColumns(); for (int j = 0; j < numPaintColumns; j++) { if (selectedPaintColumnsForReport[j]) { // // Reset surface area for each paint name, COG, Lat/Lon // std::fill(paintNameAreas.begin(), paintNameAreas.end(), 0.0); std::fill(paintNameAreasCorrected.begin(), paintNameAreasCorrected.end(), 0.0); for (int i = 0; i < numTiles; i++) { // // Is tile in the ROI ? // if (tileInROI[i]) { int tileNodes[3]; tf->getTile(i, tileNodes); for (int k = 0; k < 3; k++) { // // Is this node in the ROI // if (operationSurfaceROI->getNodeSelected(tileNodes[k])) { const int node = tileNodes[k]; // // Update area node's paint // const int paintNameIndex = reportPaintFile->getPaint(node, j); float nodeArea = tileArea[i] / 3.0; paintNameAreas[paintNameIndex] += nodeArea; float areaDistCorrect = nodeArea; if ((reportMetricCorrectionFile != NULL) && (metricCorrectionColumn >= 0)) { const double metric = reportMetricCorrectionFile->getValue(node, metricCorrectionColumn); areaDistCorrect *= std::pow(2.0, metric); } paintNameAreasCorrected[paintNameIndex] += areaDistCorrect; } } } } std::fill(paintNameAreasCogX.begin(), paintNameAreasCogX.end(), 0.0); std::fill(paintNameAreasCogY.begin(), paintNameAreasCogY.end(), 0.0); std::fill(paintNameAreasCogZ.begin(), paintNameAreasCogZ.end(), 0.0); std::fill(paintNameAreasLat.begin(), paintNameAreasLat.end(), 0.0); std::fill(paintNameAreasLon.begin(), paintNameAreasLon.end(), 0.0); std::fill(paintNameNodeCounts.begin(), paintNameNodeCounts.end(), 0); const int numNodes = bms->getNumberOfNodes(); for (int i = 0; i < numNodes; i++) { if (operationSurfaceROI->getNodeSelected(i)) { const int paintNameIndex = reportPaintFile->getPaint(i, j); // // Update COG // const float* xyz = cf->getCoordinate(i); paintNameAreasCogX[paintNameIndex] += xyz[0]; paintNameAreasCogY[paintNameIndex] += xyz[1]; paintNameAreasCogZ[paintNameIndex] += xyz[2]; paintNameNodeCounts[paintNameIndex]++; // // Update Lat/Lon // if (latLonValid) { float lat, lon; reportLatLonFile->getLatLon(i, reportLatLonFileColumn, lat, lon); paintNameAreasLat[paintNameIndex] += lat; paintNameAreasLon[paintNameIndex] += lon; } } } // // See which paint names are used by the ROI // bool headerWritten = false; for (int m = 0; m < numPaintNames; m++) { if (paintNameAreas[m] > 0.0) { const QString indent(" "); if (headerWritten == false) { // // Write the header for this paint column // headerWritten = true; reportText.append("\n\n"); QString line; line.append("Paint Column "); line.append(QString::number(j)); line.append(" "); line.append(reportPaintFile->getColumnName(j)); reportText.append(line); reportText.append("\n"); line = ""; line.append(indent); if (tabSeparateReportFlag) line.append(getSeparatorCharacter()); line.append(StringUtilities::leftJustify("Paint Name", longestPaintNameLength)); if (tabSeparateReportFlag) line.append(getSeparatorCharacter()); line.append(StringUtilities::rightJustify("Area", numberSize)); if (tabSeparateReportFlag) line.append(getSeparatorCharacter()); line.append(StringUtilities::rightJustify("Percent Area", numberSize)); if (tabSeparateReportFlag) line.append(getSeparatorCharacter()); if (metricCorrectionColumn >= 0) { line.append(StringUtilities::rightJustify("Area-Corr", numberSize)); if (tabSeparateReportFlag) line.append(getSeparatorCharacter()); } line.append(StringUtilities::rightJustify("COG - X", numberSize)); if (tabSeparateReportFlag) line.append(getSeparatorCharacter()); line.append(StringUtilities::rightJustify("COG - Y", numberSize)); if (tabSeparateReportFlag) line.append(getSeparatorCharacter()); line.append(StringUtilities::rightJustify("COG - Z", numberSize)); if (tabSeparateReportFlag) line.append(getSeparatorCharacter()); line.append(StringUtilities::rightJustify("Latitude", numberSize)); if (tabSeparateReportFlag) line.append(getSeparatorCharacter()); line.append(StringUtilities::rightJustify("Longitude", numberSize)); reportText.append(line); reportText.append("\n"); } // // Write the area for this paint name // QString stats; stats.append(indent); if (tabSeparateReportFlag) stats.append(getSeparatorCharacter()); stats.append(StringUtilities::leftJustify(reportPaintFile->getPaintNameFromIndex(m), longestPaintNameLength)); if (tabSeparateReportFlag) stats.append(getSeparatorCharacter()); stats.append(StringUtilities::rightJustify(QString::number(paintNameAreas[m], 'f', 3), numberSize)); if (tabSeparateReportFlag) stats.append(getSeparatorCharacter()); const double percent = (paintNameAreas[m] / roiArea) * 100.0; stats.append(StringUtilities::rightJustify(QString::number(percent, 'f', 3), numberSize)); if (tabSeparateReportFlag) stats.append(getSeparatorCharacter()); if (metricCorrectionColumn >= 0) { stats.append(StringUtilities::rightJustify(QString::number(paintNameAreasCorrected[m], 'f', 3), numberSize)); if (tabSeparateReportFlag) stats.append(getSeparatorCharacter()); } const double numNodesForPaint = paintNameNodeCounts[m]; double cogX = 0.0; if (numNodesForPaint > 0) { cogX = paintNameAreasCogX[m] / numNodesForPaint; } stats.append(StringUtilities::rightJustify(QString::number(cogX, 'f', 3), numberSize)); if (tabSeparateReportFlag) stats.append(getSeparatorCharacter()); double cogY = 0.0; if (numNodesForPaint > 0) { cogY = paintNameAreasCogY[m] / numNodesForPaint; } stats.append(StringUtilities::rightJustify(QString::number(cogY, 'f', 3), numberSize)); if (tabSeparateReportFlag) stats.append(getSeparatorCharacter()); double cogZ = 0.0; if (numNodesForPaint > 0) { cogZ = paintNameAreasCogZ[m] / numNodesForPaint; } stats.append(StringUtilities::rightJustify(QString::number(cogZ, 'f', 3), numberSize)); if (tabSeparateReportFlag) stats.append(getSeparatorCharacter()); double cogLat = 0.0; if (numNodesForPaint > 0) { cogLat = paintNameAreasLat[m] / numNodesForPaint; } stats.append(StringUtilities::rightJustify(QString::number(cogLat, 'f', 3), numberSize)); if (tabSeparateReportFlag) stats.append(getSeparatorCharacter()); double cogLon = 0.0; if (numNodesForPaint > 0) { cogLon = paintNameAreasLon[m] / numNodesForPaint; } stats.append(StringUtilities::rightJustify(QString::number(cogLon, 'f', 3), numberSize)); reportText.append(stats); reportText.append("\n"); } } } } } /** * Peform Metric and Surface Shape Report. */ void BrainModelSurfaceROITextReport::metricAndSurfaceShapeReport(const bool metricFlag) { MetricFile* mf = NULL; if (metricFlag) { mf = reportMetricFile; } else { mf = reportShapeFile; } const int numNodes = mf->getNumberOfNodes(); const int numCols = mf->getNumberOfColumns(); if ((numNodes <= 0) || (numCols <= 0)) { return; } bool firstWrite = true; int longestColumnNameLength = 10; for (int j = 0; j < numCols; j++) { longestColumnNameLength = std::max(longestColumnNameLength, static_cast(mf->getColumnName(j).length())); } longestColumnNameLength += 5; const int columnNumberLength = 10; const int numberSize = 16; for (int j = 0; j < numCols; j++) { bool doIt = false; if (metricFlag) { doIt = selectedMetricColumnsForReport[j]; } else { doIt = selectedShapeColumnsForReport[j]; } if (doIt) { std::vector values; for (int i = 0; i < numNodes; i++) { if (operationSurfaceROI->getNodeSelected(i)) { values.push_back(mf->getValue(i, j)); } } if (values.size() > 0) { StatisticsUtilities::DescriptiveStatistics statistics; StatisticsUtilities::computeStatistics(values, true, statistics); if (firstWrite) { if (metricFlag) { reportText.append("\nMetrics for Region Of Interest\n"); reportText.append("\n"); } else { reportText.append("\nSurface Shape for Region of Interest\n"); reportText.append("\n"); } QString str; str.append(StringUtilities::rightJustify("Column", columnNumberLength)); str.append(" "); if (tabSeparateReportFlag) str.append(getSeparatorCharacter()); str.append(StringUtilities::leftJustify("Name", longestColumnNameLength)); if (tabSeparateReportFlag) str.append(getSeparatorCharacter()); str.append(StringUtilities::rightJustify("Average", numberSize)); if (tabSeparateReportFlag) str.append(getSeparatorCharacter()); str.append(StringUtilities::rightJustify("Sample Deviation", numberSize)); if (tabSeparateReportFlag) str.append(getSeparatorCharacter()); str.append(StringUtilities::rightJustify("Abs-Average", numberSize)); if (tabSeparateReportFlag) str.append(getSeparatorCharacter()); str.append(StringUtilities::rightJustify("Sample Abs-Deviation", numberSize)); if (tabSeparateReportFlag) str.append(getSeparatorCharacter()); str.append(StringUtilities::rightJustify("Minimum", numberSize)); if (tabSeparateReportFlag) str.append(getSeparatorCharacter()); str.append(StringUtilities::rightJustify("Maximum", numberSize)); if (tabSeparateReportFlag) str.append(getSeparatorCharacter()); str.append(StringUtilities::rightJustify("Range", numberSize)); if (tabSeparateReportFlag) str.append(getSeparatorCharacter()); str.append(StringUtilities::rightJustify("Median", numberSize)); if (tabSeparateReportFlag) str.append(getSeparatorCharacter()); str.append(StringUtilities::rightJustify("Abs-Median", numberSize)); reportText.append(str); reportText.append("\n"); firstWrite = false; } QString stats; stats.append(StringUtilities::rightJustify(QString::number(j), columnNumberLength)); stats.append(" "); if (tabSeparateReportFlag) stats.append(getSeparatorCharacter()); stats.append(StringUtilities::leftJustify(mf->getColumnName(j), longestColumnNameLength)); if (tabSeparateReportFlag) stats.append(getSeparatorCharacter()); stats.append(StringUtilities::rightJustify(QString::number(statistics.average, 'f', 6), numberSize)); if (tabSeparateReportFlag) stats.append(getSeparatorCharacter()); stats.append(StringUtilities::rightJustify(QString::number(statistics.standardDeviation, 'f', 6), numberSize)); if (tabSeparateReportFlag) stats.append(getSeparatorCharacter()); stats.append(StringUtilities::rightJustify(QString::number(statistics.absAverage, 'f', 6), numberSize)); if (tabSeparateReportFlag) stats.append(getSeparatorCharacter()); stats.append(StringUtilities::rightJustify(QString::number(statistics.absStandardDeviation, 'f', 6), numberSize)); if (tabSeparateReportFlag) stats.append(getSeparatorCharacter()); stats.append(StringUtilities::rightJustify(QString::number(statistics.minValue, 'f', 6), numberSize)); if (tabSeparateReportFlag) stats.append(getSeparatorCharacter()); stats.append(StringUtilities::rightJustify(QString::number(statistics.maxValue, 'f', 6), numberSize)); if (tabSeparateReportFlag) stats.append(getSeparatorCharacter()); stats.append(StringUtilities::rightJustify(QString::number(statistics.range, 'f', 6), numberSize)); if (tabSeparateReportFlag) stats.append(getSeparatorCharacter()); stats.append(StringUtilities::rightJustify(QString::number(statistics.median, 'f', 6), numberSize)); if (tabSeparateReportFlag) stats.append(getSeparatorCharacter()); stats.append(StringUtilities::rightJustify(QString::number(statistics.absMedian, 'f', 6), numberSize)); reportText.append(stats); reportText.append("\n"); } } } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceROISurfaceXYZMeansReport.h0000664000175000017500000000433211572067322030063 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_ROI_SURFACE_XYZ_MEANS_REPORT_H__ #define __BRAIN_MODEL_SURFACE_ROI_SURFACE_XYZ_MEANS_REPORT_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BorderFile.h" #include "BrainModelSurfaceROIOperation.h" class CoordinateFile; class LatLonFile; class MetricFile; class PaintFile; class SurfaceShapeFile; class TopologyFile; /// class for performing region of interest surface xyz means report class BrainModelSurfaceROISurfaceXYZMeansReport : public BrainModelSurfaceROIOperation { public: // constructor BrainModelSurfaceROISurfaceXYZMeansReport(BrainSet* bs, BrainModelSurface* bmsIn, BrainModelSurfaceROINodeSelection* surfaceROIIn, std::vector& coordFilesIn); // destructor ~BrainModelSurfaceROISurfaceXYZMeansReport(); // execute the operation void executeOperation() throw (BrainModelAlgorithmException); protected: // create the surface means text report void createSurfaceMeansTextReport() throw (BrainModelAlgorithmException); /// coord files for surface means std::vector surfaceMeansCoordFiles; }; #endif // __BRAIN_MODEL_SURFACE_ROI_SURFACE_XYZ_MEANS_REPORT_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceROISurfaceXYZMeansReport.cxx0000664000175000017500000000614611572067322030443 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainModelSurface.h" #include "BrainModelSurfaceROINodeSelection.h" #include "BrainModelSurfaceROISurfaceXYZMeansReport.h" #include "BrainSet.h" #include "CoordinateFile.h" #include "FileUtilities.h" /** * constructor. */ BrainModelSurfaceROISurfaceXYZMeansReport::BrainModelSurfaceROISurfaceXYZMeansReport(BrainSet* bs, BrainModelSurface* bmsIn, BrainModelSurfaceROINodeSelection* surfaceROIIn, std::vector& coordFilesIn) : BrainModelSurfaceROIOperation(bs, bmsIn, surfaceROIIn) { surfaceMeansCoordFiles = coordFilesIn; } /** * destructor. */ BrainModelSurfaceROISurfaceXYZMeansReport::~BrainModelSurfaceROISurfaceXYZMeansReport() { } /** * execute the operation. */ void BrainModelSurfaceROISurfaceXYZMeansReport::executeOperation() throw (BrainModelAlgorithmException) { const int numCoordFiles = static_cast(surfaceMeansCoordFiles.size()); if (numCoordFiles <= 0) { throw BrainModelAlgorithmException("ERROR: There are no coord files."); } // // Determine surface means // const int numNodes = brainSet->getNumberOfNodes(); for (int j = 0; j < numCoordFiles; j++) { double meanX = 0.0; double meanY = 0.0; double meanZ = 0.0; double nodeCount = 0.0; const CoordinateFile* coordFile = surfaceMeansCoordFiles[j]; for (int i = 0; i < numNodes; i++) { if (operationSurfaceROI->getNodeSelected(i)) { float xyz[3]; coordFile->getCoordinate(i, xyz); meanX += xyz[0]; meanY += xyz[1]; meanZ += xyz[2]; nodeCount += 1.0; } } meanX /= nodeCount; meanY /= nodeCount; meanZ /= nodeCount; const QString s = (FileUtilities::basename(coordFile->getFileName()) + " " + QString::number(meanX, 'f', 6) + " " + QString::number(meanY, 'f', 6) + " " + QString::number(meanZ, 'f', 6) + "\n"); reportText.append(s); } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceROIShapeCorrelationReport.h0000664000175000017500000000430011572067322030331 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_ROI_SHAPE_CORRELATION_REPORT_H__ #define __BRAIN_MODEL_SURFACE_ROI_SHAPE_CORRELATION_REPORT_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurfaceROIOperation.h" class SurfaceShapeFile; /// class for shape correlation report class BrainModelSurfaceROIShapeCorrelationReport : public BrainModelSurfaceROIOperation { public: // constructor BrainModelSurfaceROIShapeCorrelationReport(BrainSet* bs, BrainModelSurface* bmsIn, BrainModelSurfaceROINodeSelection* surfaceROIIn, SurfaceShapeFile* shapeFileIn, const int shapeReferenceColumnNumberIn, const bool separateWithSemicolonsFlagIn); // destructor ~BrainModelSurfaceROIShapeCorrelationReport(); protected: // execute the operation virtual void executeOperation() throw (BrainModelAlgorithmException); /// the surface shape file SurfaceShapeFile* shapeFile; /// shape column number int shapeReferenceColumnNumber; /// separate with semicolons flag bool separateWithSemicolonsFlag; }; #endif // __BRAIN_MODEL_SURFACE_ROI_SHAPE_CORRELATION_REPORT_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceROIShapeCorrelationReport.cxx0000664000175000017500000001040511572067322030707 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurface.h" #include "BrainModelSurfaceROINodeSelection.h" #include "BrainModelSurfaceROIShapeCorrelationReport.h" #include "SurfaceShapeFile.h" /** * Constructor. */ BrainModelSurfaceROIShapeCorrelationReport::BrainModelSurfaceROIShapeCorrelationReport( BrainSet* bs, BrainModelSurface* bmsIn, BrainModelSurfaceROINodeSelection* surfaceROIIn, SurfaceShapeFile* shapeFileIn, const int shapeReferenceColumnNumberIn, const bool separateWithSemicolonsFlagIn) : BrainModelSurfaceROIOperation(bs, bmsIn, surfaceROIIn) { shapeFile = shapeFileIn; shapeReferenceColumnNumber = shapeReferenceColumnNumberIn; separateWithSemicolonsFlag = separateWithSemicolonsFlagIn; } /** * destructor. */ BrainModelSurfaceROIShapeCorrelationReport::~BrainModelSurfaceROIShapeCorrelationReport() { } /** * execute the operation. */ void BrainModelSurfaceROIShapeCorrelationReport::executeOperation() throw (BrainModelAlgorithmException) { reportText = ""; setHeaderText("Shape Correlation Report"); const int numColumns = shapeFile->getNumberOfColumns(); if (numColumns <= 0) { throw BrainModelAlgorithmException("No surface shape file contains no data."); } QString separator(" "); if (separateWithSemicolonsFlag) { separator = ";"; } float roiArea = 0.0; createReportHeader(roiArea); std::vector nodesAreInROI; operationSurfaceROI->getNodesInROI(nodesAreInROI); std::vector coefficients; if (shapeReferenceColumnNumber < 0) { const int lastColumn = shapeFile->getNumberOfColumns() - 1; QString str; for (int j = 0; j < shapeFile->getNumberOfColumns(); j++) { str += (shapeFile->getColumnName(j)); if (j != lastColumn) { str += separator; } } str += "\n"; reportText.append(str); for (int j = 0; j < shapeFile->getNumberOfColumns(); j++) { shapeFile->correlationCoefficient(j, coefficients, &nodesAreInROI); QString str; for (int i = 0; i < shapeFile->getNumberOfColumns(); i++) { str += QString::number(coefficients[i],'f', 5); if (i != lastColumn) { str += separator; } } str += "\n"; reportText.append(str); } } else { shapeFile->correlationCoefficient(shapeReferenceColumnNumber, coefficients, &nodesAreInROI); QString str; str += ("\n" "Correlation for " + shapeFile->getColumnName(shapeReferenceColumnNumber) + "\n"); reportText.append(str); for (int i = 0; i < shapeFile->getNumberOfColumns(); i++) { str = ""; str += (QString::number(i + 1) + separator + shapeFile->getColumnName(i) + separator + QString::number(coefficients[i], 'f', 5) + "\n"); reportText.append(str); } } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceROIProbAtlasOverlapReport.h0000664000175000017500000000404311572067322030313 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_ROI_PROB_ATLAS_OVERLAP_REPORT_H__ #define __BRAIN_MODEL_SURFACE_ROI_PROB_ATLAS_OVERLAP_REPORT_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurfaceROIOperation.h" class ProbabilisticAtlasFile; /// class for computing integrated folding index class BrainModelSurfaceROIProbAtlasOverlapReport : public BrainModelSurfaceROIOperation { public: // constructor BrainModelSurfaceROIProbAtlasOverlapReport(BrainSet* bs, BrainModelSurface* bmsIn, BrainModelSurfaceROINodeSelection* inputSurfaceROIIn, ProbabilisticAtlasFile* probAtlasFileIn, const QString& headerTextIn, const bool tabSeparateReportFlagIn); // destructor ~BrainModelSurfaceROIProbAtlasOverlapReport(); protected: // execute the operation virtual void executeOperation() throw (BrainModelAlgorithmException); /// the surface shape file ProbabilisticAtlasFile* probAtlasFile; /// semicolon separate the report bool semicolonSeparateReportFlag; }; #endif // __BRAIN_MODEL_SURFACE_ROI_PROB_ATLAS_OVERLAP_REPORT_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceROIProbAtlasOverlapReport.cxx0000664000175000017500000002021111572067322030661 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainModelSurface.h" #include "BrainModelSurfaceROIProbAtlasOverlapReport.h" #include "BrainModelSurfaceROINodeSelection.h" #include "NameIndexSort.h" #include "ProbabilisticAtlasFile.h" #include "StringUtilities.h" #include "TopologyFile.h" /** * constructor. */ BrainModelSurfaceROIProbAtlasOverlapReport::BrainModelSurfaceROIProbAtlasOverlapReport( BrainSet* bs, BrainModelSurface* bmsIn, BrainModelSurfaceROINodeSelection* inputSurfaceROIIn, ProbabilisticAtlasFile* probAtlasFileIn, const QString& headerTextIn, const bool semicolonSeparateReportFlagIn) : BrainModelSurfaceROIOperation(bs, bmsIn, inputSurfaceROIIn) { probAtlasFile = probAtlasFileIn; semicolonSeparateReportFlag = semicolonSeparateReportFlagIn; setHeaderText(headerTextIn); } /** * destructor. */ BrainModelSurfaceROIProbAtlasOverlapReport::~BrainModelSurfaceROIProbAtlasOverlapReport() { } /** * execute the operation. */ void BrainModelSurfaceROIProbAtlasOverlapReport::executeOperation() throw (BrainModelAlgorithmException) { const int numNodes = probAtlasFile->getNumberOfNodes(); const int numCols = probAtlasFile->getNumberOfColumns(); if ((numNodes <= 0) || (numCols <= 0)) { throw BrainModelAlgorithmException("The Probabilistic Atlas File is Empty."); } const int numNames = probAtlasFile->getNumberOfPaintNames(); if (numNames <= 0) { throw BrainModelAlgorithmException("No names in Probabilistic Atlas File."); } float roiArea = 0.0; createReportHeader(roiArea); QString separator(" "); if (semicolonSeparateReportFlag) { separator = ";"; } const int numNodesSelected = operationSurfaceROI->getNumberOfNodesSelected(); const int countCols = numCols + 1; int* counts = new int[countCols]; // // Sort the paint names // std::vector indices; std::vector names; for (int i = 0; i < numNames; i++) { indices.push_back(i); names.push_back(probAtlasFile->getPaintNameFromIndex(i)); } NameIndexSort sortNames(indices, names); if (semicolonSeparateReportFlag) { QString str; str += "Name "; for (int j = 0; j < countCols; j++) { str += (separator + QString::number(j)); } str += "\n"; reportText.append(str); } // // Loop through paint names // for (int m = 0; m < numNames; m++) { // // Get the paint name and index // int indx = -1; QString name; sortNames.getSortedNameAndIndex(m, indx, name); // // Clear counts // for (int j = 0; j < countCols; j++) { counts[j] = 0; } // // Find nodes using paint // for (int i = 0; i < numNodes; i++) { if (operationSurfaceROI->getNodeSelected(i)) { int cnt = 0; for (int j = 0; j < numCols; j++) { if (probAtlasFile->getPaint(i, j) == indx) { cnt++; } } counts[cnt]++; } } QString str; if (semicolonSeparateReportFlag) { str += name + "\n"; for (int j = 0; j < countCols; j++) { if (j > 0) { str += separator; } str += QString::number(counts[j]); } } else { str += name + "\n"; for (int j = 0; j < countCols; j++) { str += (QString::number(counts[j]) + " with " + QString::number(j) + " entries "); } } str += "\n"; reportText.append(str); if (semicolonSeparateReportFlag) { str = " "; for (int j = 0; j < countCols; j++) { const float pct = (static_cast(counts[j]) / static_cast(numNodesSelected)) * 100.0; if (j > 0) { str += separator; } str += QString::number(pct, 'f', 3); } str += "\n"; } else { str = " "; for (int j = 0; j < countCols; j++) { const float pct = (static_cast(counts[j]) / static_cast(numNodesSelected)) * 100.0; str += (QString::number(pct, 'f', 3) + "% with " + QString::number(j) + " entries "); } str += "\n\n"; } reportText.append(str); reportText.append(" "); } delete[] counts; /* TopologyFile* tf = bms->getTopologyFile(); if (tf != NULL) { std::vector areaTimesFoldingSum(numColumns, 0.0); const int numTriangles = tf->getNumberOfTiles(); for (int i = 0; i < numTriangles; i++) { if (tileInROI[i]) { int n1, n2, n3; tf->getTile(i, n1, n2, n3); for (int j = 0; j < numColumns; j++) { // // Average folding index is: // SUM(Ai * Abs(Fi)) / SUM(Ai); // // Ai = area of triangle (less if not all nodes in ROI) // Fi = average shape value of triangle's three nodes // SUM(Ai) is the same as the ROI's area // float shapeSum = 0.0; float numInROI = 0.0; if (operationSurfaceROI->getNodeSelected(n1)) { shapeSum += surfaceShapeFile->getValue(n1, j); numInROI += 1.0; } if (operationSurfaceROI->getNodeSelected(n2)) { shapeSum += surfaceShapeFile->getValue(n2, j); numInROI += 1.0; } if (operationSurfaceROI->getNodeSelected(n3)) { shapeSum += surfaceShapeFile->getValue(n3, j); numInROI += 1.0; } if (numInROI > 0.0) { const float averageShape = std::fabs(shapeSum) / numInROI; areaTimesFoldingSum[j] += averageShape * tileArea[i]; } } } } int longestColumnNameLength = 10; for (int j = 0; j < numColumns; j++) { longestColumnNameLength = std::max(longestColumnNameLength, static_cast(surfaceShapeFile->getColumnName(j).length())); } longestColumnNameLength += 5; QString s = StringUtilities::leftJustify("Name", longestColumnNameLength) + StringUtilities::rightJustify("IFI", 12) + "\n"; reportText.append(s); for (int j = 0; j < numColumns; j++) { const float integratedFloatingIndex = areaTimesFoldingSum[j] / roiArea; QString s = StringUtilities::leftJustify(surfaceShapeFile->getColumnName(j), longestColumnNameLength) + StringUtilities::rightJustify(QString::number(integratedFloatingIndex, 'f', 6), 12) + "\n"; reportText.append(s); } } */ } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceROIPaintReport.h0000664000175000017500000000723611572067322026155 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_ROI_PAINT_REPORT_H__ #define __BRAIN_MODEL_SURFACE_ROI_PAINT_REPORT_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelSurfaceROIOperation.h" class LatLonFile; class MetricFile; class PaintFile; class SurfaceShapeFile; /// class for performing paint region of interest operations on a surface class BrainModelSurfaceROIPaintReport : public BrainModelSurfaceROIOperation { public: // constructor BrainModelSurfaceROIPaintReport(BrainSet* bs, BrainModelSurface* bmsIn, BrainModelSurfaceROINodeSelection* surfaceROIIn, MetricFile* metricFileIn, const std::vector& selectedMetricColumnsForReportIn, MetricFile* shapeFileIn, const std::vector& selectedShapeColumnsForReportIn, PaintFile* paintFileIn, const std::vector& selectedPaintColumnsForReportIn, const int paintRegionColumnNumberIn, LatLonFile* latLonFileIn, const int latLonFileColumnIn, MetricFile* metricCorrectionFileIn, const int metricCorrectionColumnIn, const bool semicolonSeparateReportFlagIn); // destructor ~BrainModelSurfaceROIPaintReport(); protected: // execute the operation void executeOperation() throw (BrainModelAlgorithmException); /// selected metric columns std::vector selectedMetricColumnsForReport; /// selected surface shape columns std::vector selectedShapeColumnsForReport; /// selected paint columns std::vector selectedPaintColumnsForReport; /// lat lon file for report LatLonFile* reportLatLonFile; /// column for report lat lon file int reportLatLonFileColumn; /// metric file for report MetricFile* reportMetricFile; /// shape file for report MetricFile* reportShapeFile; /// paint file for report PaintFile* reportPaintFile; /// paint column for paint region report int paintRegionColumnNumber; /// metric correction file for report MetricFile* reportMetricCorrectionFile; /// the metric correction column int metricCorrectionColumn; /// semicolon separate the report bool semicolonSeparateReportFlag; }; #endif // __BRAIN_MODEL_SURFACE_ROI_PAINT_REPORT_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceROIPaintReport.cxx0000664000175000017500000001551411572067322026526 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainModelSurface.h" #include "BrainModelSurfaceROINodeSelection.h" #include "BrainModelSurfaceROIPaintReport.h" #include "BrainModelSurfaceROITextReport.h" #include "BrainSet.h" #include "FileUtilities.h" #include "LatLonFile.h" #include "MetricFile.h" #include "PaintFile.h" #include "SurfaceShapeFile.h" /** * constructor. */ BrainModelSurfaceROIPaintReport::BrainModelSurfaceROIPaintReport(BrainSet* bs, BrainModelSurface* bmsIn, BrainModelSurfaceROINodeSelection* surfaceROIIn, MetricFile* metricFileIn, const std::vector& selectedMetricColumnsForReportIn, MetricFile* shapeFileIn, const std::vector& selectedShapeColumnsForReportIn, PaintFile* paintFileIn, const std::vector& selectedPaintColumnsForReportIn, const int paintRegionColumnNumberIn, LatLonFile* latLonFileIn, const int latLonFileColumnIn, MetricFile* metricCorrectionFileIn, const int metricCorrectionColumnIn, const bool semicolonSeparateReportFlagIn) : BrainModelSurfaceROIOperation(bs, bmsIn, surfaceROIIn) { reportLatLonFile = NULL; reportMetricFile = NULL; reportShapeFile = NULL; reportPaintFile = NULL; reportMetricCorrectionFile = NULL; reportMetricFile = metricFileIn; selectedMetricColumnsForReport = selectedMetricColumnsForReportIn; reportShapeFile = shapeFileIn; selectedShapeColumnsForReport = selectedShapeColumnsForReportIn; reportPaintFile = paintFileIn; selectedPaintColumnsForReport = selectedPaintColumnsForReportIn; paintRegionColumnNumber = paintRegionColumnNumberIn; reportLatLonFile = latLonFileIn; reportLatLonFileColumn = latLonFileColumnIn; setHeaderText("Paint Region Report"); reportMetricCorrectionFile = metricCorrectionFileIn; metricCorrectionColumn = metricCorrectionColumnIn; semicolonSeparateReportFlag = semicolonSeparateReportFlagIn; } /** * destructor. */ BrainModelSurfaceROIPaintReport::~BrainModelSurfaceROIPaintReport() { } /** * execute the operation. */ void BrainModelSurfaceROIPaintReport::executeOperation() throw (BrainModelAlgorithmException) { reportText = ""; if (reportPaintFile->getNumberOfColumns() <= 0) { throw BrainModelAlgorithmException("Paint file is empty."); } if ((paintRegionColumnNumber < 0) || (paintRegionColumnNumber >= reportPaintFile->getNumberOfColumns())) { throw BrainModelAlgorithmException("Region paint column is invalid."); } QString paintReportText; // // Get all of the paint names for the column // std::vector paintIndices; reportPaintFile->getPaintNamesForColumn(paintRegionColumnNumber, paintIndices); // // process each paint index // const int numPaintIndices = static_cast(paintIndices.size()); for (int i = 0; i < numPaintIndices; i++) { // // Get the index // const int paintIndex = paintIndices[i]; // // Save the selected nodes // const int numNodes = reportPaintFile->getNumberOfNodes(); std::vector savedNodeInROI(numNodes, 0); // // Limit nodes in ROI to those with valid paint column // for (int j = 0; j < numNodes; j++) { savedNodeInROI[j] = operationSurfaceROI->getNodeSelected(j); if (operationSurfaceROI->getNodeSelected(j)) { operationSurfaceROI->setNodeSelected(j, false); if (reportPaintFile->getPaint(j, paintRegionColumnNumber) == paintIndex) { operationSurfaceROI->setNodeSelected(j, true); } } } // // Run the report for this paint // const QString str = ("Paint Subregion Name: " + reportPaintFile->getPaintNameFromIndex(paintIndex)); if (operationSurfaceROI->getNumberOfNodesSelected() > 0) { reportText = ""; BrainModelSurfaceROITextReport roiReport(brainSet, bms, operationSurfaceROI, reportMetricFile, selectedMetricColumnsForReport, reportShapeFile, selectedShapeColumnsForReport, reportPaintFile, selectedPaintColumnsForReport, reportLatLonFile, 0, str, reportMetricFile, metricCorrectionColumn, semicolonSeparateReportFlag); try { roiReport.execute(); paintReportText += roiReport.getReportText(); } catch (BrainModelAlgorithmException& e) { throw BrainModelAlgorithmException(e.whatQString()); } } else { QString s = str; s += "\n No nodes in ROI\n\n"; paintReportText += s; } // // Restore the selected nodes // for (int j = 0; j < numNodes; j++) { operationSurfaceROI->setNodeSelected(j, (savedNodeInROI[j] != 0)); } } reportText = paintReportText; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceROIOperation.h0000664000175000017500000000566411572067322025651 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_ROI_H__ #define __BRAIN_MODEL_SURFACE_ROI_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BorderFile.h" #include "BrainModelAlgorithm.h" class BrainModelSurface; class BrainModelSurfaceROINodeSelection; class TopologyHelper; /// base class for performing region of interest operations on a surface class BrainModelSurfaceROIOperation : public BrainModelAlgorithm { public: // constructor BrainModelSurfaceROIOperation(BrainSet* bs, const BrainModelSurface* bmsIn, const BrainModelSurfaceROINodeSelection* inputSurfaceROIIn); // destructor ~BrainModelSurfaceROIOperation(); // execute the operation void execute() throw (BrainModelAlgorithmException); /// get the text report QString getReportText() const { return reportText; } protected: // execute the operation virtual void executeOperation() throw (BrainModelAlgorithmException) = 0; // get the topology helper const TopologyHelper* getTopologyHelper() const; /// get the separator character static QString getSeparatorCharacter() { return ";"; } // Create the report header void createReportHeader(float& roiAreaOut); // set the header text void setHeaderText(const QString& headerTextIn); /// surface on which to perform operation const BrainModelSurface* bms; /// the ROI selection BrainModelSurfaceROINodeSelection* operationSurfaceROI; /// report text QString reportText; /// area of each tile std::vector tileArea; /// tile in ROI flags std::vector tileInROI; /// the separator character static const QString separatorCharacter; private: /// the header text QString headerText; /// the input region of interest const BrainModelSurfaceROINodeSelection* inputSurfaceROI; }; #endif // __BRAIN_MODEL_SURFACE_ROI_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceROIOperation.cxx0000664000175000017500000001737711572067322026230 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainModelSurface.h" #include "BrainModelSurfaceROINodeSelection.h" #include "BrainModelSurfaceROIOperation.h" #include "BrainSet.h" #include "CoordinateFile.h" #include "DebugControl.h" #include "FileUtilities.h" #include "MathUtilities.h" #include "StringUtilities.h" #include "TopologyFile.h" #include "TopologyHelper.h" /** * constructor. */ BrainModelSurfaceROIOperation::BrainModelSurfaceROIOperation(BrainSet* bs, const BrainModelSurface* bmsIn, const BrainModelSurfaceROINodeSelection* inputSurfaceROIIn) : BrainModelAlgorithm(bs), bms(bmsIn), inputSurfaceROI(inputSurfaceROIIn) { operationSurfaceROI = NULL; } /** * destructor. */ BrainModelSurfaceROIOperation::~BrainModelSurfaceROIOperation() { if (operationSurfaceROI != NULL) { delete operationSurfaceROI; operationSurfaceROI = NULL; } } /** * execute the operation. */ void BrainModelSurfaceROIOperation::execute() throw (BrainModelAlgorithmException) { if (bms == NULL) { throw BrainModelAlgorithmException("Surface is invalid (NULL)."); } if (bms->getTopologyFile() == NULL) { throw BrainModelAlgorithmException("Surface has no topology."); } const int numNodes = bms->getNumberOfNodes(); if (numNodes <= 0) { throw BrainModelAlgorithmException("Surface contains no nodes."); } if (inputSurfaceROI == NULL) { throw BrainModelAlgorithmException("The input ROI is invalid."); } if (inputSurfaceROI->getNumberOfNodes() != numNodes) { throw BrainModelAlgorithmException("The surface and the ROI contain a different number of nodes."); } const int numberOfSelectedNodes = inputSurfaceROI->getNumberOfNodesSelected(); if (numberOfSelectedNodes <= 0) { throw BrainModelAlgorithmException("No nodes are selected in the ROI."); } reportText = ""; // // Copy the input ROI to the operation ROI // operationSurfaceROI = new BrainModelSurfaceROINodeSelection(*inputSurfaceROI); // // Remove any nodes from the operation ROI if they are not connected // const TopologyHelper* th = getTopologyHelper(); if (th == NULL) { throw BrainModelAlgorithmException("Operation surface topology invalid."); } for (int i = 0; i < numNodes; i++) { if (th->getNodeHasNeighbors(i) == false) { operationSurfaceROI->setNodeSelected(i, false); } } executeOperation(); } /** * Create the report header. */ void BrainModelSurfaceROIOperation::createReportHeader(float& roiAreaOut) { // // Add the header describing the node selection // reportText.append("Node Selection: " + inputSurfaceROI->getSelectionDescription()); reportText.append("\n\n"); const TopologyFile* tf = bms->getTopologyFile(); const int numNodes = bms->getNumberOfNodes(); // // Determine total area and selected area. // const CoordinateFile* cf = bms->getCoordinateFile(); double totalArea = 0.0; roiAreaOut = 0.0; const int numTiles = tf->getNumberOfTiles(); tileArea.resize(numTiles); std::fill(tileArea.begin(), tileArea.end(), 0.0); tileInROI.resize(numTiles); std::fill(tileInROI.begin(), tileInROI.end(), false); double centerOfGravity[3] = { 0.0, 0.0, 0.0 }; for (int i = 0; i < numTiles; i++) { int nodes[3]; tf->getTile(i, nodes); tileArea[i] = MathUtilities::triangleArea(cf->getCoordinate(nodes[0]), cf->getCoordinate(nodes[1]), cf->getCoordinate(nodes[2])); totalArea += tileArea[i]; double numMarked = 0.0; if (operationSurfaceROI->getNodeSelected(nodes[0])) numMarked += 1.0; if (operationSurfaceROI->getNodeSelected(nodes[1])) numMarked += 1.0; if (operationSurfaceROI->getNodeSelected(nodes[2])) numMarked += 1.0; if (tileArea[i] > 0.0) { roiAreaOut += (numMarked / 3.0) * tileArea[i]; } tileInROI[i] = (numMarked > 0.0); } for (int m = 0; m < numNodes; m++) { if (operationSurfaceROI->getNodeSelected(m)) { const float* xyz = cf->getCoordinate(m); centerOfGravity[0] += xyz[0]; centerOfGravity[1] += xyz[1]; centerOfGravity[2] += xyz[2]; } } if (headerText.isEmpty() == false) { reportText.append(headerText); reportText.append("\n\n"); } QString surf("Surface: "); surf.append(bms->getDescriptiveName()); surf.append("\n"); reportText.append(surf); reportText.append("\n"); QString topo("Topology: "); topo.append(tf->getDescriptiveName()); topo.append("\n"); reportText.append(topo); reportText.append("\n"); reportText.append("\n"); const int count = operationSurfaceROI->getNumberOfNodesSelected(); QStringList sl; sl << QString::number(count) << " of " << QString::number(numNodes) << " nodes in region of interest\n"; reportText.append(sl.join("")); reportText.append("\n"); sl.clear(); sl << "Total Surface Area: " << QString::number(totalArea, 'f', 1); reportText.append(sl.join("")); reportText.append("\n"); sl.clear(); sl << "Region of Interest Surface Area: " << QString::number(roiAreaOut, 'f', 1); reportText.append(sl.join("")); reportText.append("\n"); centerOfGravity[0] = centerOfGravity[0] / static_cast(count); centerOfGravity[1] = centerOfGravity[1] / static_cast(count); centerOfGravity[2] = centerOfGravity[2] / static_cast(count); sl.clear(); sl << "Region of Interest Center of Gravity: " << QString::number(centerOfGravity[0], 'f', 4) << " " << QString::number(centerOfGravity[1], 'f', 4) << " " << QString::number(centerOfGravity[2], 'f', 4); reportText.append(sl.join("")); reportText.append("\n"); float meanDistance, minDist, maxDist; bms->getMeanDistanceBetweenNodes(operationSurfaceROI, meanDistance, minDist, maxDist); sl.clear(); sl << "Region Mean Distance Between Nodes: " // << QString::number(bms->getMeanDistanceBetweenNodes(operationSurfaceROI), 'f', 5); << QString::number(meanDistance, 'f', 5); reportText.append(sl.join("")); reportText.append("\n"); reportText.append(" \n"); } /** * set the header text. */ void BrainModelSurfaceROIOperation::setHeaderText(const QString& headerTextIn) { headerText = headerTextIn; } /** * get the topology helper. */ const TopologyHelper* BrainModelSurfaceROIOperation::getTopologyHelper() const { if (bms == NULL) { return NULL; } const TopologyFile* tf = bms->getTopologyFile(); if (tf == NULL) { return NULL; } const TopologyHelper* th = tf->getTopologyHelper(false, true, false); return th; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceROINodeSelection.h0000664000175000017500000004445111572067322026441 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_ROI_NODE_SELECTION_H__ #define __BRAIN_MODEL_SURFACE_ROI_NODE_SELECTION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "FileException.h" class Border; class BorderProjection; class BrainModelBorderSet; class BrainModelSurface; class BrainSet; class LatLonFile; class MetricFile; class NodeRegionOfInterestFile; class PaintFile; class SurfaceShapeFile; class TopologyHelper; /// class for selecting nodes in a region of interest class BrainModelSurfaceROINodeSelection { public: /// logical selection (and, or, etc) enum SELECTION_LOGIC { /// normal selection (all existing selections are reset) SELECTION_LOGIC_NORMAL, /// logically AND (intersection) new and existing selections SELECTION_LOGIC_AND, /// logically OR (union) new and existing selections SELECTION_LOGIC_OR, /// new selections are AND'ed with opposite of existing selections SELECTION_LOGIC_AND_NOT }; // constructor BrainModelSurfaceROINodeSelection(BrainSet* brainSetIn); // copy constructor BrainModelSurfaceROINodeSelection(const BrainModelSurfaceROINodeSelection& roi); // Assignment operator. BrainModelSurfaceROINodeSelection& operator=(const BrainModelSurfaceROINodeSelection& roi); // destructor ~BrainModelSurfaceROINodeSelection(); // see if any nodes are selected bool anyNodesSelected() const; // get the selection status of a node bool getNodeSelected(const int nodeNumber) const; // set the selection status of a node void setNodeSelected(const int nodeNumber, const bool nodeSelectedFlag); // get the number of nodes selected int getNumberOfNodesSelected() const; // get the number of nodes (count of all nodes regardless of selection status) int getNumberOfNodes() const { return nodeSelectedFlags.size(); } // get node in ROI flags void getNodesInROI(std::vector& nodesAreInROI) const; // set the ROI selection into file void setRegionOfInterestIntoFile(NodeRegionOfInterestFile& nroi) const; // get the ROI selection from file void getRegionOfInterestFromFile(const NodeRegionOfInterestFile& nroi) throw (FileException); // get the tiles that have at least one node in the ROI void getTilesInRegionOfInterest(const BrainModelSurface* bms, std::vector& tilesInROI) const; // get the nodes selection types and names static void getNodeSelectionTypesAndNames(std::vector& typesOut, std::vector& namesOut); // get display selected nodes bool getDisplaySelectedNodes() const { return displaySelectedNodes; } // set display selected nodes void setDisplaySelectedNodes(const bool b) { displaySelectedNodes = b; } // deselect all nodes void deselectAllNodes(); // invert selected nodes QString invertSelectedNodes(const BrainModelSurface* selectionSurface); // get the extent of the selection void getExtentOfSelectedNodes(const BrainModelSurface* bms, float extentOut[6]) const; // get the center of gravity of the selection void getCenterOfGravityOfSelectedNodes(const BrainModelSurface* bms, float cogOut[3]) const; // get the nodes that have min/max x/y/z values void getNodesWithMinMaxXYZValues(const BrainModelSurface* bms, int& xMostMedial, int& xMostLateral, int& minXNode, int& maxXNode, int& minYNode, int& maxYNode, int& minZNode, int& maxZNode, int& absMinXNode, int& absMaxXNode, int& absMinYNode, int& absMaxYNode, int& absMinZNode, int& absMaxZNode) const; // get node with most lateral X Coordinate int getNodeWithMostLateralXCoordinate(const BrainModelSurface* surface) const; // get node with most medial X Coordinate int getNodeWithMostMedialXCoordinate(const BrainModelSurface* surface) const; // get node with minimum X Coordinate int getNodeWithMinimumXCoordinate(const BrainModelSurface* surface) const; // get node with maximum X Coordinate int getNodeWithMaximumXCoordinate(const BrainModelSurface* surface) const; // get node with minimum Y Coordinate int getNodeWithMinimumYCoordinate(const BrainModelSurface* surface) const; // get node with maximum Y Coordinate int getNodeWithMaximumYCoordinate(const BrainModelSurface* surface) const; // get node with minimum Z Coordinate int getNodeWithMinimumZCoordinate(const BrainModelSurface* surface) const; // get node with maximum Z Coordinate int getNodeWithMaximumZCoordinate(const BrainModelSurface* surface) const; // boundary only (keeps nodes in ROI that have at least one neighbor NOT in ROI) void boundaryOnly(const BrainModelSurface* bms); // dilate the selected nodes void dilate(const BrainModelSurface* selectionSurface, int numberOfIterations); // dilate around the node (adds node's neighbors to ROI) void dilateAroundNode(const BrainModelSurface* selectionSurface, const int nodeNumber); // dilate but only add nodes with selected paint void dilatePaintConstrained(const BrainModelSurface* selectionSurface, const PaintFile* paintFile, const int paintColumnNumber, const QString& paintName, const int numberOfIterations); // discard islands keeps the largest contiguous piece (returns number of islands removed) int discardIslands(const BrainModelSurface* selectionSurface); // discard islands with islands that have fewer than specified number of nodes int discardIslands(const BrainModelSurface* selectionSurface, const int minimumNumberOfNodesInIslandsKept); // find islands (number of disjoint groups of nodes). int findIslands(const BrainModelSurface* selectionSurface, std::vector& islandRootNode, std::vector& islandNumNodes, std::vector& nodeRootNeighbor); // find islands and place each in an ROI std::vector findIslands(const BrainModelSurface* selectionSurface); // erode the selected nodes void erode(const BrainModelSurface* selectionSurface, int numberOfIterations); // erode the selected nodes but maintain a connection between two nodes void erodeButMaintainNodeConnection(const BrainModelSurface* selectionSurface, int numberOfIterations, const int node1, const int node2); // erode the selected nodes but maintain a connection between two nodes void erodeButMaintainNodeConnection(const BrainModelSurface* selectionSurface, const std::vector& doNotErodeNodeFlags, int numberOfIterations, const int node1, const int node2); // expand the ROI so that these nodes are within the ROI and connected void expandSoNodesAreWithinAndConnected(const BrainModelSurface* selectionSurface, const int node1, const int node2); // find node int ROI nearest the XYZ int getNearestNodeInROI(const BrainModelSurface* selectionSurface, const float x, const float y, const float z) const; // find node int ROI nearest the XYZ int getNearestNodeInROI(const BrainModelSurface* selectionSurface, const float xyz[3]) const; // get the surface area of the ROI float getSurfaceAreaOfROI(const BrainModelSurface* surface) const; // limit the extent of the ROI void limitExtent(const BrainModelSurface* selectionSurface, const float extent[6]); // exclude nodes in a region void excludeNodesInRegion(const BrainModelSurface* selectionSurface, const float regionExtent[6]); // logically and this roi with another roi (returns error message) QString logicallyAND(const BrainModelSurfaceROINodeSelection* otherROI); // logically or this roi with another roi (returns error message) QString logicallyOR(const BrainModelSurfaceROINodeSelection* otherROI); // select all nodes (returns error message) QString selectAllNodes(const BrainModelSurface* selectionSurface); // select nodes that are edges QString selectNodesThatAreEdges(const SELECTION_LOGIC selectionLogic, const BrainModelSurface* selectionSurface); // select nodes within geodesic distance QString selectNodesWithinGeodesicDistance(const SELECTION_LOGIC selectionLogic, const BrainModelSurface* selectionSurface, const int nodeNumber, const float geodesicDistance); // select nodes with paint (returns error message) QString selectNodesWithPaint(const SELECTION_LOGIC selectionLogic, const BrainModelSurface* selectionSurface, const PaintFile* pf, const int paintFileColumnNumber, const QString& paintName); // select nodes within border (returns error message) QString selectNodesWithinBorder(const SELECTION_LOGIC selectionLogic, const BrainModelSurface* selectionSurface, const BrainModelSurface* flatSurface, const BrainModelBorderSet* bmbs, const QString& borderName); // select nodes within border (returns error message) QString selectNodesWithinBorderOnSphere(const SELECTION_LOGIC selectionLogic, const BrainModelSurface* sphericalSurface, const BorderProjection* borderProjection); // select nodes within border (returns error message) QString selectNodesWithinBorder(const SELECTION_LOGIC selectionLogic, const BrainModelSurface* selectionSurface, const Border* border, const bool surface3DFlag, const float zMinimum = 0.0); // select nodes within lat/long range (returns error message) QString selectNodesWithLatLong(const SELECTION_LOGIC selectionLogic, const BrainModelSurface* selectionSurface, const LatLonFile* latLonFile, const int latLonFileColumnNumber, const float minimumLatitude, const float maximumLatitude, const float minimumLongitude, const float maximumLongitude); // select nodes within metric range (returns error message) QString selectNodesWithMetric(const SELECTION_LOGIC selectionLogic, const BrainModelSurface* selectionSurface, const MetricFile* metricFile, const int metricFileColumnNumber, const float minimumMetricValue, const float maximumMetricValue); // select nodes within metric range and connected to specified node (returns error message) QString selectConnectedNodesWithMetric(const SELECTION_LOGIC selectionLogic, const BrainModelSurface* selectionSurface, const MetricFile* metricFile, const int metricFileColumnNumber, const float minimumMetricValue, const float maximumMetricValue, const int connectedToNodeNumber); // select nodes within surface shape range (returns error message) QString selectNodesWithSurfaceShape(const SELECTION_LOGIC selectionLogic, const BrainModelSurface* selectionSurface, const SurfaceShapeFile* surfaceShapeFile, const int surfaceShapeFileColumnNumber, const float minimumShapeValue, const float maximumShapeValue); // select nodes within surface shape range and connected to specified node (returns error message) QString selectConnectedNodesWithSurfaceShape(const SELECTION_LOGIC selectionLogic, const BrainModelSurface* selectionSurface, const SurfaceShapeFile* surfaceShapeFile, const int surfaceShapeFileColumnNumber, const float minimumShapeValue, const float maximumShapeValue, const int connectedToNodeNumber); // select nodes that are crossovers (returns error message) QString selectNodesThatAreCrossovers(const SELECTION_LOGIC selectionLogic, const BrainModelSurface* selectionSurface); // update (usually called if number of nodes changes) void update(); // get the selection description QString getSelectionDescription() const { return selectionDescription; } protected: // see if two nodes are connected in the ROI bool areNodesConnected(const BrainModelSurface* bms, const std::vector& connectionFlags, const int node1, const int node2); // get the topolgy helper for selection surface (returns NULL if unavailable) const TopologyHelper* getSelectionSurfaceTopologyHelper(const BrainModelSurface* selectionSurface, QString& errorMessageOut) const; // process the new node selections (returns error message) QString processNewNodeSelections(const SELECTION_LOGIC selectionLogic, const BrainModelSurface* selectionSurface, std::vector& newNodeSelections, const QString& description); // add to the selection description void addToSelectionDescription(const QString& selectionLogicText, const QString& descriptionIn); // copy helper used by copy constructor and assignment operator void copyHelper(const BrainModelSurfaceROINodeSelection& roi); /// the brain set BrainSet* brainSet; /// the node selection flags (ints should be faster than bools since bools packed into bits) std::vector nodeSelectedFlags; /// display selected nodes bool displaySelectedNodes; /// selection description QString selectionDescription; // IF NEW MEMBERS ARE ADDED BE SURE TO UPDATE "coypHelper()" }; #endif // __BRAIN_MODEL_SURFACE_ROI_NODE_SELECTION_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceROINodeSelection.cxx0000664000175000017500000025104211572067322027010 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "BorderFile.h" #include "BorderProjectionFile.h" #include "BrainModelBorderSet.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceConnectedSearchMetric.h" #include "BrainModelSurfaceGeodesic.h" #include "BrainModelSurfaceROINodeSelection.h" #include "BrainSet.h" #include "BrainSetNodeAttribute.h" #include "DebugControl.h" #include "GeodesicDistanceFile.h" #include "LatLonFile.h" #include "MathUtilities.h" #include "MetricFile.h" #include "NodeRegionOfInterestFile.h" #include "PaintFile.h" #include "StringUtilities.h" #include "SurfaceShapeFile.h" #include "TopologyFile.h" #include "TopologyHelper.h" /** * constructor. */ BrainModelSurfaceROINodeSelection::BrainModelSurfaceROINodeSelection(BrainSet* brainSetIn) { brainSet = brainSetIn; displaySelectedNodes = true; update(); } /** * copy constructor. */ BrainModelSurfaceROINodeSelection::BrainModelSurfaceROINodeSelection( const BrainModelSurfaceROINodeSelection& roi) { copyHelper(roi); } /** * Assignment operator. */ BrainModelSurfaceROINodeSelection& BrainModelSurfaceROINodeSelection::operator=(const BrainModelSurfaceROINodeSelection& roi) { if (this != &roi) { copyHelper(roi); } return *this; } /** * copy helper used by copy constructor and assignment operator. */ void BrainModelSurfaceROINodeSelection::copyHelper(const BrainModelSurfaceROINodeSelection& roi) { brainSet = roi.brainSet; nodeSelectedFlags = roi.nodeSelectedFlags; displaySelectedNodes = roi.displaySelectedNodes; selectionDescription = roi.selectionDescription; } /** * destructor. */ BrainModelSurfaceROINodeSelection::~BrainModelSurfaceROINodeSelection() { } /** * get the nodes selection types and names. */ void BrainModelSurfaceROINodeSelection::getNodeSelectionTypesAndNames( std::vector& typesOut, std::vector& namesOut) { typesOut.clear(); namesOut.clear(); typesOut.push_back(SELECTION_LOGIC_NORMAL); namesOut.push_back("Normal Selection"); typesOut.push_back(SELECTION_LOGIC_AND); namesOut.push_back("And Selection (Intersection)"); typesOut.push_back(SELECTION_LOGIC_OR); namesOut.push_back("Or Selection (Union)"); typesOut.push_back(SELECTION_LOGIC_AND_NOT); namesOut.push_back("And-Not Selection"); } /** * deselect all nodes. */ void BrainModelSurfaceROINodeSelection::deselectAllNodes() { update(); std::fill(nodeSelectedFlags.begin(), nodeSelectedFlags.end(), 0); selectionDescription = ""; } /** * select all nodes (returns error message). */ QString BrainModelSurfaceROINodeSelection::selectAllNodes(const BrainModelSurface* selectionSurface) { update(); const unsigned int numNodes = nodeSelectedFlags.size(); std::vector nodeFlags(numNodes, 1); return processNewNodeSelections(SELECTION_LOGIC_NORMAL, selectionSurface, nodeFlags, "All Nodes"); } /** * select nodes that are edges. */ QString BrainModelSurfaceROINodeSelection::selectNodesThatAreEdges(const SELECTION_LOGIC selectionLogic, const BrainModelSurface* selectionSurface) { update(); brainSet->classifyNodes(selectionSurface->getTopologyFile()); const unsigned int numNodes = nodeSelectedFlags.size(); std::vector nodeFlags(numNodes, 0); bool thereAreEdgeNodesFlag = false; for (unsigned int i = 0; i < numNodes; i++) { const BrainSetNodeAttribute* bna = brainSet->getNodeAttributes(i); if (bna->getClassification() == BrainSetNodeAttribute::CLASSIFICATION_TYPE_EDGE) { nodeFlags[i] = 1; thereAreEdgeNodesFlag = true; } } if (thereAreEdgeNodesFlag == false) { return "There are no edges in the surface."; } return processNewNodeSelections(selectionLogic, selectionSurface, nodeFlags, "Edge Nodes"); } /** * update (usually called if number of nodes changes). */ void BrainModelSurfaceROINodeSelection::update() { const unsigned int numNodes = brainSet->getNumberOfNodes(); if (numNodes != nodeSelectedFlags.size()) { nodeSelectedFlags.resize(numNodes, false); } } /** * see if any nodes are selected. */ bool BrainModelSurfaceROINodeSelection::anyNodesSelected() const { const unsigned int numNodes = nodeSelectedFlags.size(); for (unsigned int i = 0; i < numNodes; i++) { if (nodeSelectedFlags[i] != 0) { return true; } } return false; } /** * get the selection status of a node. */ bool BrainModelSurfaceROINodeSelection::getNodeSelected(const int nodeNumber) const { return (nodeSelectedFlags[nodeNumber] != 0); } /** * get the number of nodes selected. */ int BrainModelSurfaceROINodeSelection::getNumberOfNodesSelected() const { const unsigned int numNodes = nodeSelectedFlags.size(); int cnt = 0; for (unsigned int i = 0; i < numNodes; i++) { if (nodeSelectedFlags[i]) { cnt++; } } return cnt; } /** * set the selection status of a node. */ void BrainModelSurfaceROINodeSelection::setNodeSelected(const int nodeNumber, const bool nodeSelectedFlag) { nodeSelectedFlags[nodeNumber] = nodeSelectedFlag; } /** * get node in ROI flags. */ void BrainModelSurfaceROINodeSelection::getNodesInROI(std::vector& nodesAreInROI) const { const unsigned int num = nodeSelectedFlags.size(); nodesAreInROI.resize(num); for (unsigned int i = 0; i < num; i++) { nodesAreInROI[i] = (nodeSelectedFlags[i] != 0); } } /** * get the tiles that have at least one node in the ROI. */ void BrainModelSurfaceROINodeSelection::getTilesInRegionOfInterest( const BrainModelSurface* bms, std::vector& tilesInROI) const { tilesInROI.clear(); if (bms == NULL) { return; } const TopologyFile* tf = bms->getTopologyFile(); if (tf == NULL) { return; } const int numTiles = tf->getNumberOfTiles(); tilesInROI.resize(numTiles, 0); for (int i = 0; i < numTiles; i++) { int n1, n2, n3; tf->getTile(i, n1, n2, n3); if (nodeSelectedFlags[n1] || nodeSelectedFlags[n2] || nodeSelectedFlags[n3]) { tilesInROI[i] = 1; } } } /** * invert selected nodes. */ QString BrainModelSurfaceROINodeSelection::invertSelectedNodes(const BrainModelSurface* selectionSurface) { const unsigned int numNodes = nodeSelectedFlags.size(); std::vector newNodeSelections(numNodes, 0); for (unsigned int i = 0; i < numNodes; i++) { if (nodeSelectedFlags[i] == 0) { newNodeSelections[i] = 1; } } const QString descriptionSaved = selectionDescription; const QString msg = processNewNodeSelections(SELECTION_LOGIC_NORMAL, selectionSurface, newNodeSelections, "Invert Selection"); selectionDescription = descriptionSaved; addToSelectionDescription("", "Invert Selection"); return msg; } /** * select nodes within geodesic distance. */ QString BrainModelSurfaceROINodeSelection::selectNodesWithinGeodesicDistance( const SELECTION_LOGIC selectionLogic, const BrainModelSurface* selectionSurface, const int nodeNumber, const float geodesicDistance) { const int numNodes = selectionSurface->getNumberOfNodes(); if ((nodeNumber < 0) || (nodeNumber >= numNodes)) { return "Invalid node number for selecting nodes with geodesic."; } GeodesicDistanceFile geodesicDistanceFile; BrainModelSurfaceGeodesic geodesic(brainSet, (BrainModelSurface*)selectionSurface, NULL, -1, "", &geodesicDistanceFile, -1, "GeoDist", nodeNumber, NULL); try { geodesic.execute(); } catch (BrainModelAlgorithmException&) { return ("Selecting nodes with geodesic failed for node number " + QString::number(nodeNumber)); } if ((geodesicDistanceFile.getNumberOfNodes() == numNodes) && (geodesicDistanceFile.getNumberOfColumns() >= 1)) { std::vector newNodeSelections(numNodes, 0); for (int i = 0; i < numNodes; i++) { if (geodesicDistanceFile.getNodeParentDistance(i, 0) < geodesicDistance) { newNodeSelections[i] = 1; } } newNodeSelections[nodeNumber] = 1; const QString& description = ("Nodes within " + QString::number(geodesicDistance, 'f', 3) + " geodesic distance of node number " + QString::number(nodeNumber)); return processNewNodeSelections(selectionLogic, selectionSurface, newNodeSelections, description); } return ("Selecting nodes with geodesic failed for node number " + QString::number(nodeNumber)); } /** * select nodes with paint (returns error message). */ QString BrainModelSurfaceROINodeSelection::selectNodesWithPaint( const SELECTION_LOGIC selectionLogic, const BrainModelSurface* selectionSurface, const PaintFile* pf, const int paintFileColumnNumber, const QString& paintName) { if (pf == NULL) { return "ERROR: Paint File is invalid."; } if ((paintFileColumnNumber < 0) || (paintFileColumnNumber > pf->getNumberOfColumns())) { return "ERROR: Paint File Column is invalid."; } const int paintIndex = pf->getPaintIndexFromName(paintName); if (paintIndex < 0) { return "ERROR: Paint name " + paintName + "not found in paint file."; } const int numNodes = pf->getNumberOfNodes(); std::vector newNodeSelections(numNodes, 0); for (int i = 0; i < numNodes; i++) { if (pf->getPaint(i, paintFileColumnNumber) == paintIndex) { newNodeSelections[i] = 1; } } const QString& description = ("Nodes assigned the name " + paintName + " in column named " + pf->getColumnName(paintFileColumnNumber)); return processNewNodeSelections(selectionLogic, selectionSurface, newNodeSelections, description); } /** * select nodes within border (returns error message). */ QString BrainModelSurfaceROINodeSelection::selectNodesWithinBorder( const SELECTION_LOGIC selectionLogic, const BrainModelSurface* selectionSurface, const BrainModelSurface* flatSurface, const BrainModelBorderSet* bmbs, const QString& borderName) { if (flatSurface == NULL) { return "ERROR: Flat surface is invalid."; } const TopologyFile* tf = flatSurface->getTopologyFile(); if (tf == NULL) { return "ERROR: Flat Surface has no topology."; } if (bmbs == NULL) { return "ERROR: Borders are invalid."; } const CoordinateFile* cf = flatSurface->getCoordinateFile(); const float* coords = cf->getCoordinate(0); // // Get the border file for the surface type // BorderFile bf; bmbs->copyBordersToBorderFile(flatSurface, bf); const int numBorders = bf.getNumberOfBorders(); if (bf.getNumberOfBorders() <= 0) { return "ERROR: Flat surface has no borders."; } const int numNodes = brainSet->getNumberOfNodes(); std::vector newNodeSelections(numNodes, 0); const TopologyHelper* th = tf->getTopologyHelper(false, true, false); // // Need to check all borders since there may be more than one // with the same name. // for (int i = 0; i < numBorders; i++) { Border* b = bf.getBorder(i); if (b->getName() == borderName) { std::vector insideFlags; b->pointsInsideBorder2D(coords, numNodes, insideFlags); for (int j = 0; j < numNodes; j++) { if (th->getNodeHasNeighbors(j)) { if (insideFlags[j]) { newNodeSelections[j] = 1; } } } } } return processNewNodeSelections(selectionLogic, selectionSurface, newNodeSelections, "Nodes within borders named " + borderName); } /** * select nodes within lat/long range (returns error message). */ QString BrainModelSurfaceROINodeSelection::selectNodesWithLatLong( const SELECTION_LOGIC selectionLogic, const BrainModelSurface* selectionSurface, const LatLonFile* latLonFile, const int latLonFileColumnNumber, const float minimumLatitude, const float maximumLatitude, const float minimumLongitude, const float maximumLongitude) { if (latLonFile == NULL) { return "ERROR: Lat/Long file is invalid."; } if ((latLonFileColumnNumber < 0) || (latLonFileColumnNumber >= latLonFile->getNumberOfColumns())) { return "ERROR: Lat/Long file column number is invalid."; } const int numNodes = latLonFile->getNumberOfNodes(); std::vector newNodeSelections(numNodes, 0); for (int i = 0; i < numNodes; i++) { float lat, lon; latLonFile->getLatLon(i, latLonFileColumnNumber, lat, lon); if ((lat >= minimumLatitude) && (lat <= maximumLatitude) && (lon >= minimumLongitude) && (lon <= maximumLongitude)) { newNodeSelections[i] = 1; } } const QString description = ("Node with latitude range (" + QString::number(minimumLatitude, 'f', 4) + ", " + QString::number(maximumLatitude, 'f', 4) + ") and longitude range (" + QString::number(minimumLongitude, 'f', 4) + ", " + QString::number(maximumLongitude, 'f', 4) + ")"); return processNewNodeSelections(selectionLogic, selectionSurface, newNodeSelections, description); } /** * select nodes within metric range (returns error message). */ QString BrainModelSurfaceROINodeSelection::selectNodesWithMetric( const SELECTION_LOGIC selectionLogic, const BrainModelSurface* selectionSurface, const MetricFile* metricFile, const int metricFileColumnNumber, const float minimumMetricValue, const float maximumMetricValue) { QString fileType("Metric"); if (dynamic_cast(metricFile) != NULL) { fileType = "Shape"; } if (metricFile == NULL) { return "ERROR: " + fileType + " file is invalid."; } if ((metricFileColumnNumber < 0) || (metricFileColumnNumber >= metricFile->getNumberOfColumns())) { return "ERROR: " + fileType + " file column number is invalid."; } const int numNodes = metricFile->getNumberOfNodes(); std::vector newNodeSelections(numNodes, 0); for (int i = 0; i < numNodes; i++) { const float value = metricFile->getValue(i, metricFileColumnNumber); if ((value >= minimumMetricValue) && (value <= maximumMetricValue)) { newNodeSelections[i] = 1; } } const QString description = ("Nodes in range (" + QString::number(minimumMetricValue, 'f', 3) + ", " + QString::number(maximumMetricValue, 'f', 3) + ") in " + fileType + " column named " + metricFile->getColumnName(metricFileColumnNumber)); return processNewNodeSelections(selectionLogic, selectionSurface, newNodeSelections, description); } /** * select nodes within metric range and connected to specified node (returns error message). */ QString BrainModelSurfaceROINodeSelection::selectConnectedNodesWithMetric( const SELECTION_LOGIC selectionLogic, const BrainModelSurface* selectionSurface, const MetricFile* metricFile, const int metricFileColumnNumber, const float minimumMetricValue, const float maximumMetricValue, const int connectedToNodeNumber) { QString fileType("Metric"); if (dynamic_cast(metricFile) != NULL) { fileType = "Shape"; } if (metricFile == NULL) { return "ERROR: " + fileType + " file is invalid."; } if ((metricFileColumnNumber < 0) || (metricFileColumnNumber >= metricFile->getNumberOfColumns())) { return "ERROR: " + fileType + " file column number is invalid."; } const int numNodes = metricFile->getNumberOfNodes(); if ((connectedToNodeNumber < 0) || (connectedToNodeNumber >= numNodes)) { return "ERROR: selected node number is invalid."; } // // Find metrics connected to selected node that are within metric threshold values // std::vector newNodeSelections(numNodes, 0); BrainModelSurfaceConnectedSearchMetric metricSearch(brainSet, (BrainModelSurface*)selectionSurface, connectedToNodeNumber, metricFile, metricFileColumnNumber, minimumMetricValue, maximumMetricValue); try { metricSearch.execute(); for (int i = 0; i < numNodes; i++) { if (metricSearch.getNodeConnected(i)) { newNodeSelections[i] = 1; } } } catch (BrainModelAlgorithmException& bmae) { return bmae.whatQString(); } const QString description = ("Nodes in range (" + QString::number(minimumMetricValue, 'f', 3) + ", " + QString::number(maximumMetricValue, 'f', 3) + ") in " + fileType + " column named " + metricFile->getColumnName(metricFileColumnNumber) + " connected to node " + QString::number(connectedToNodeNumber)); return processNewNodeSelections(selectionLogic, selectionSurface, newNodeSelections, description); } /** * select nodes within surface shape range (returns error message). */ QString BrainModelSurfaceROINodeSelection::selectNodesWithSurfaceShape( const SELECTION_LOGIC selectionLogic, const BrainModelSurface* selectionSurface, const SurfaceShapeFile* surfaceShapeFile, const int surfaceShapeFileColumnNumber, const float minimumShapeValue, const float maximumShapeValue) { // // Shape is derived from Metric // return selectNodesWithMetric(selectionLogic, selectionSurface, surfaceShapeFile, surfaceShapeFileColumnNumber, minimumShapeValue, maximumShapeValue); } /** * select nodes within surface shape range and connected to specified node (returns error message). */ QString BrainModelSurfaceROINodeSelection::selectConnectedNodesWithSurfaceShape( const SELECTION_LOGIC selectionLogic, const BrainModelSurface* selectionSurface, const SurfaceShapeFile* surfaceShapeFile, const int surfaceShapeFileColumnNumber, const float minimumShapeValue, const float maximumShapeValue, const int connectedToNodeNumber) { // // Shape is derived from Metric // return selectConnectedNodesWithMetric(selectionLogic, selectionSurface, surfaceShapeFile, surfaceShapeFileColumnNumber, minimumShapeValue, maximumShapeValue, connectedToNodeNumber); } /** * select nodes that are crossovers (returns error message). */ QString BrainModelSurfaceROINodeSelection::selectNodesThatAreCrossovers( const SELECTION_LOGIC selectionLogic, const BrainModelSurface* selectionSurface) { const BrainSetNodeAttribute* nodeAttributes = brainSet->getNodeAttributes(0); const int numNodes = brainSet->getNumberOfNodes(); std::vector newNodeSelections(numNodes, 0); for (int i = 0; i < numNodes; i++) { if (nodeAttributes[i].getCrossover() == BrainSetNodeAttribute::CROSSOVER_YES) { newNodeSelections[i] = 1; } } return processNewNodeSelections(selectionLogic, selectionSurface, newNodeSelections, "Nodes identified as crossovers"); } /** * dilate the selected nodes. */ void BrainModelSurfaceROINodeSelection::dilate(const BrainModelSurface* selectionSurface, int numberOfIterations) { QString topologyHelperErrorMessage; const TopologyHelper* th = getSelectionSurfaceTopologyHelper(selectionSurface, topologyHelperErrorMessage); if (th == NULL) { return; } update(); const int numNodes = static_cast(nodeSelectedFlags.size()); // // For specified number of dilation iterations // for (int iter = 0; iter < numberOfIterations; iter++) { // // Output for dilation // std::vector nodesDilated = nodeSelectedFlags; // // Check each node // for (int i = 0; i < numNodes; i++) { // // Is this node in the ROI // if (nodeSelectedFlags[i]) { // // Get node's neighbors // int numNeighbors = 0; const int* neighbors = th->getNodeNeighbors(i, numNeighbors); // // Add neighbors to the ROI // for (int j = 0; j < numNeighbors; j++) { nodesDilated[neighbors[j]] = 1; } } } // // Output dilation // nodeSelectedFlags = nodesDilated; } addToSelectionDescription("", ("Dilated " + QString::number(numberOfIterations) + " iterations")); } /** * dilate around the node (adds node's neighbors to ROI). */ void BrainModelSurfaceROINodeSelection::dilateAroundNode(const BrainModelSurface* selectionSurface, const int nodeNumber) { QString topologyHelperErrorMessage; const TopologyHelper* th = getSelectionSurfaceTopologyHelper(selectionSurface, topologyHelperErrorMessage); if (th == NULL) { return; } update(); // // Put node's neighbors into the ROI // int numNeighbors = 0; const int* neighbors = th->getNodeNeighbors(nodeNumber, numNeighbors); // // Add neighbors to the ROI // for (int j = 0; j < numNeighbors; j++) { nodeSelectedFlags[neighbors[j]] = 1; } } /** * dilate but only add nodes with selected paint. */ void BrainModelSurfaceROINodeSelection::dilatePaintConstrained(const BrainModelSurface* selectionSurface, const PaintFile* paintFile, const int paintColumnNumber, const QString& paintName, const int numberOfIterations) { update(); const int numNodes = static_cast(nodeSelectedFlags.size()); if ((paintColumnNumber < 0) || (paintColumnNumber > paintFile->getNumberOfColumns()) || (paintFile->getNumberOfNodes() != numNodes)) { return; } const int paintNameIndex = paintFile->getPaintIndexFromName(paintName); QString topologyHelperErrorMessage; const TopologyHelper* th = getSelectionSurfaceTopologyHelper(selectionSurface, topologyHelperErrorMessage); if (th == NULL) { return; } // // Identify nodes that may be dilated // std::vector nodeMayBeDilated(numNodes, 0); for (int i = 0; i < numNodes; i++) { if (paintFile->getPaint(i, paintColumnNumber) == paintNameIndex) { nodeMayBeDilated[i] = 1; } } // // For specified number of dilation iterations // for (int iter = 0; iter < numberOfIterations; iter++) { // // Output for dilation // std::vector nodesDilated = nodeSelectedFlags; // // Check each node // for (int i = 0; i < numNodes; i++) { // // Is this node in the ROI // if (nodeSelectedFlags[i]) { // // Get node's neighbors // int numNeighbors = 0; const int* neighbors = th->getNodeNeighbors(i, numNeighbors); // // Add neighbors to the ROI // for (int j = 0; j < numNeighbors; j++) { const int nodeNum = neighbors[j]; if (nodeMayBeDilated[nodeNum] != 0) { nodesDilated[nodeNum] = 1; } } } } // // Output dilation // nodeSelectedFlags = nodesDilated; } const QString description = ("Dilated " + QString::number(numberOfIterations) + " iterations nodes with paint name " + paintName + " in paint column " + paintFile->getColumnName(paintColumnNumber)); addToSelectionDescription("", description); } /** * boundary only (keeps nodes in ROI that have at least one neighbor NOT in ROI). */ void BrainModelSurfaceROINodeSelection::boundaryOnly(const BrainModelSurface* bms) { QString topologyHelperErrorMessage; const TopologyHelper* th = getSelectionSurfaceTopologyHelper(bms, topologyHelperErrorMessage); if (th == NULL) { return; } update(); const int numNodes = static_cast(nodeSelectedFlags.size()); // // Output for boundary // std::vector boundaryNodes(numNodes, 0); // // Check each node // for (int i = 0; i < numNodes; i++) { // // Is this node in the ROI // if (nodeSelectedFlags[i]) { // // Get node's neighbors // int numNeighbors = 0; const int* neighbors = th->getNodeNeighbors(i, numNeighbors); // // If a neighbor is not in the ROI, this is a boundary node ROI // for (int j = 0; j < numNeighbors; j++) { if (nodeSelectedFlags[neighbors[j]] == 0) { boundaryNodes[i] = 1; break; } } } } // // Output boundary // nodeSelectedFlags = boundaryNodes; addToSelectionDescription("", "Boundary nodes only"); } /** * erode the selected nodes. */ void BrainModelSurfaceROINodeSelection::erode(const BrainModelSurface* selectionSurface, int numberOfIterations) { QString topologyHelperErrorMessage; const TopologyHelper* th = getSelectionSurfaceTopologyHelper(selectionSurface, topologyHelperErrorMessage); if (th == NULL) { return; } update(); const int numNodes = static_cast(nodeSelectedFlags.size()); // // For specified number of erosion iterations // for (int iter = 0; iter < numberOfIterations; iter++) { // // Output for eroding // std::vector nodesEroded = nodeSelectedFlags; // // Check each node // for (int i = 0; i < numNodes; i++) { // // Is this node in the ROI // if (nodeSelectedFlags[i]) { // // Get node's neighbors // int numNeighbors = 0; const int* neighbors = th->getNodeNeighbors(i, numNeighbors); // // If a neighbor is not in the ROI, take "this" node out of ROI // for (int j = 0; j < numNeighbors; j++) { if (nodeSelectedFlags[neighbors[j]] == 0) { nodesEroded[i] = 0; break; } } } } // // Output erosion // nodeSelectedFlags = nodesEroded; } addToSelectionDescription("", ("Eroded " + QString::number(numberOfIterations) + " iterations")); } /** * exclude nodes in a region. */ void BrainModelSurfaceROINodeSelection::excludeNodesInRegion( const BrainModelSurface* selectionSurface, const float regionExtent[6]) { update(); const int numNodes = static_cast(nodeSelectedFlags.size()); const CoordinateFile* cf = selectionSurface->getCoordinateFile(); for (int i = 0; i < numNodes; i++) { if (nodeSelectedFlags[i] != 0) { const float* xyz = cf->getCoordinate(i); if ((xyz[0] > regionExtent[0]) && (xyz[0] < regionExtent[1]) && (xyz[1] > regionExtent[2]) && (xyz[1] < regionExtent[3]) && (xyz[2] > regionExtent[4]) && (xyz[2] < regionExtent[5])) { nodeSelectedFlags[i] = 0; } } } const QString description = ("Excluded in region extent " "(" + QString::number(regionExtent[0], 'f', 3) + ", " + QString::number(regionExtent[1], 'f', 3) + ") " "(" + QString::number(regionExtent[2], 'f', 3) + ", " + QString::number(regionExtent[3], 'f', 3) + ") " "(" + QString::number(regionExtent[4], 'f', 3) + ", " + QString::number(regionExtent[5], 'f', 3) + ") "); addToSelectionDescription("", description); } /** * limit the extent of the ROI. */ void BrainModelSurfaceROINodeSelection::limitExtent(const BrainModelSurface* selectionSurface, const float extent[6]) { update(); const int numNodes = static_cast(nodeSelectedFlags.size()); const CoordinateFile* cf = selectionSurface->getCoordinateFile(); for (int i = 0; i < numNodes; i++) { if (nodeSelectedFlags[i] != 0) { const float* xyz = cf->getCoordinate(i); if ((xyz[0] < extent[0]) || (xyz[0] > extent[1]) || (xyz[1] < extent[2]) || (xyz[1] > extent[3]) || (xyz[2] < extent[4]) || (xyz[2] > extent[5])) { nodeSelectedFlags[i] = 0; } } } const QString description = ("Limit extent " "(" + QString::number(extent[0], 'f', 3) + ", " + QString::number(extent[1], 'f', 3) + ") " "(" + QString::number(extent[2], 'f', 3) + ", " + QString::number(extent[3], 'f', 3) + ") " "(" + QString::number(extent[4], 'f', 3) + ", " + QString::number(extent[5], 'f', 3) + ") "); addToSelectionDescription("", description); } /** * process the new node selections. */ QString BrainModelSurfaceROINodeSelection::processNewNodeSelections( const SELECTION_LOGIC selectionLogic, const BrainModelSurface* selectionSurface, std::vector& newNodeSelections, const QString& description) { QString topologyHelperErrorMessage; const TopologyHelper* th = getSelectionSurfaceTopologyHelper(selectionSurface, topologyHelperErrorMessage); if (th == NULL) { return topologyHelperErrorMessage; } update(); const unsigned int numNodes = nodeSelectedFlags.size(); newNodeSelections.resize(numNodes, 0); for (unsigned int i = 0; i < numNodes; i++) { if (th->getNodeHasNeighbors(i)) { switch (selectionLogic) { case SELECTION_LOGIC_NORMAL: nodeSelectedFlags[i] = newNodeSelections[i]; break; case SELECTION_LOGIC_AND: if (nodeSelectedFlags[i] && newNodeSelections[i]) { nodeSelectedFlags[i] = 1; } else { nodeSelectedFlags[i] = 0; } break; case SELECTION_LOGIC_OR: if (nodeSelectedFlags[i] || newNodeSelections[i]) { nodeSelectedFlags[i] = 1; } else { nodeSelectedFlags[i] = 0; } break; case SELECTION_LOGIC_AND_NOT: if (nodeSelectedFlags[i] && (newNodeSelections[i] == 0)) { nodeSelectedFlags[i] = 1; } else { nodeSelectedFlags[i] = 0; } break; } } else { nodeSelectedFlags[i] = 0; // not in topology } } // // Update description of selection // QString logicText; switch (selectionLogic) { case SELECTION_LOGIC_NORMAL: logicText = ""; selectionDescription = ""; break; case SELECTION_LOGIC_AND: logicText = "AND"; break; case SELECTION_LOGIC_OR: logicText = "OR"; break; case SELECTION_LOGIC_AND_NOT: logicText = "AND-NOT"; break; } addToSelectionDescription(logicText, description); return ""; } /** * add to the selection description. */ void BrainModelSurfaceROINodeSelection::addToSelectionDescription(const QString& selectionLogicText, const QString& descriptionIn) { QString description = descriptionIn; StringUtilities::lineWrapString(70, description); if (selectionDescription.isEmpty() == false) { selectionDescription += "\n"; } selectionDescription += (selectionLogicText + " " + description); if (DebugControl::getDebugOn()) { std::cout << "ROI: " << selectionDescription.toAscii().constData() << std::endl << std::endl; } } /** * get the topolgy helper for selection surface (returns NULL if unavailable). */ const TopologyHelper* BrainModelSurfaceROINodeSelection::getSelectionSurfaceTopologyHelper( const BrainModelSurface* selectionSurface, QString& errorMessageOut) const { errorMessageOut = ""; if (selectionSurface == NULL) { errorMessageOut = "ERROR: Selection surface is invalid."; return NULL; } const TopologyFile* tf = selectionSurface->getTopologyFile(); if (tf == NULL) { errorMessageOut = "ERROR: Selection Surface has no topology."; return NULL; } const TopologyHelper* th = tf->getTopologyHelper(false, true, false); if (th == NULL) { errorMessageOut = "ERROR: Failed to create topology helper."; } return th; } /** * get the center of gravity of the selection. */ void BrainModelSurfaceROINodeSelection::getCenterOfGravityOfSelectedNodes( const BrainModelSurface* bms, float cogOut[3]) const { cogOut[0] = 0.0; cogOut[1] = 0.0; cogOut[2] = 0.0; if (bms == NULL) { return; } const int numNodes = bms->getNumberOfNodes(); if (numNodes != static_cast(nodeSelectedFlags.size())) { return; } double sum[3] = { 0.0, 0.0, 0.0 }; const CoordinateFile* cf = bms->getCoordinateFile(); float numSelected = 0.0; for (int i = 0; i < numNodes; i++) { if (nodeSelectedFlags[i] != 0) { const float* xyz = cf->getCoordinate(i); sum[0] += xyz[0]; sum[1] += xyz[1]; sum[2] += xyz[2]; numSelected += 1.0; } } if (numSelected >= 1.0) { cogOut[0] = sum[0] / numSelected; cogOut[1] = sum[1] / numSelected; cogOut[2] = sum[2] / numSelected; } } /** * get the extent of the selection. */ void BrainModelSurfaceROINodeSelection::getExtentOfSelectedNodes( const BrainModelSurface* bms, float extentOut[6]) const { extentOut[0] = std::numeric_limits::max(); extentOut[1] = -std::numeric_limits::max(); extentOut[2] = std::numeric_limits::max(); extentOut[3] = -std::numeric_limits::max(); extentOut[4] = std::numeric_limits::max(); extentOut[5] = -std::numeric_limits::max(); if (bms == NULL) { return; } const int numNodes = bms->getNumberOfNodes(); if (numNodes != static_cast(nodeSelectedFlags.size())) { return; } const CoordinateFile* cf = bms->getCoordinateFile(); for (int i = 0; i < numNodes; i++) { if (nodeSelectedFlags[i] != 0) { const float* xyz = cf->getCoordinate(i); extentOut[0] = std::min(extentOut[0], xyz[0]); extentOut[1] = std::max(extentOut[1], xyz[0]); extentOut[2] = std::min(extentOut[2], xyz[1]); extentOut[3] = std::max(extentOut[3], xyz[1]); extentOut[4] = std::min(extentOut[4], xyz[2]); extentOut[5] = std::max(extentOut[5], xyz[2]); } } } /** * get node with most lateral X Coordinate. */ int BrainModelSurfaceROINodeSelection::getNodeWithMostLateralXCoordinate(const BrainModelSurface* surface) const { int minXNode, maxXNode, minYNode, maxYNode, minZNode, maxZNode; int mostMedialXNode, mostLateralXNode; int absMinXNode, absMaxXNode, absMinYNode, absMaxYNode, absMinZNode, absMaxZNode; getNodesWithMinMaxXYZValues(surface, mostMedialXNode, mostLateralXNode, minXNode, maxXNode, minYNode, maxYNode, minZNode, maxZNode, absMinXNode, absMaxXNode, absMinYNode, absMaxYNode, absMinZNode, absMaxZNode); return mostLateralXNode; } /** * get node with most medial X Coordinate. */ int BrainModelSurfaceROINodeSelection::getNodeWithMostMedialXCoordinate(const BrainModelSurface* surface) const { int minXNode, maxXNode, minYNode, maxYNode, minZNode, maxZNode; int mostMedialXNode, mostLateralXNode; int absMinXNode, absMaxXNode, absMinYNode, absMaxYNode, absMinZNode, absMaxZNode; getNodesWithMinMaxXYZValues(surface, mostMedialXNode, mostLateralXNode, minXNode, maxXNode, minYNode, maxYNode, minZNode, maxZNode, absMinXNode, absMaxXNode, absMinYNode, absMaxYNode, absMinZNode, absMaxZNode); return mostMedialXNode; } /** * get node with minimum X Coordinate. */ int BrainModelSurfaceROINodeSelection::getNodeWithMinimumXCoordinate(const BrainModelSurface* surface) const { int minXNode, maxXNode, minYNode, maxYNode, minZNode, maxZNode; int mostMedialXNode, mostLateralXNode; int absMinXNode, absMaxXNode, absMinYNode, absMaxYNode, absMinZNode, absMaxZNode; getNodesWithMinMaxXYZValues(surface, mostMedialXNode, mostLateralXNode, minXNode, maxXNode, minYNode, maxYNode, minZNode, maxZNode, absMinXNode, absMaxXNode, absMinYNode, absMaxYNode, absMinZNode, absMaxZNode); return minXNode; } /** * get node with maximum X Coordinate. */ int BrainModelSurfaceROINodeSelection::getNodeWithMaximumXCoordinate(const BrainModelSurface* surface) const { int minXNode, maxXNode, minYNode, maxYNode, minZNode, maxZNode; int mostMedialXNode, mostLateralXNode; int absMinXNode, absMaxXNode, absMinYNode, absMaxYNode, absMinZNode, absMaxZNode; getNodesWithMinMaxXYZValues(surface, mostMedialXNode, mostLateralXNode, minXNode, maxXNode, minYNode, maxYNode, minZNode, maxZNode, absMinXNode, absMaxXNode, absMinYNode, absMaxYNode, absMinZNode, absMaxZNode); return maxXNode; } /** * get node with minimum Y Coordinate. */ int BrainModelSurfaceROINodeSelection::getNodeWithMinimumYCoordinate(const BrainModelSurface* surface) const { int minXNode, maxXNode, minYNode, maxYNode, minZNode, maxZNode; int mostMedialXNode, mostLateralXNode; int absMinXNode, absMaxXNode, absMinYNode, absMaxYNode, absMinZNode, absMaxZNode; getNodesWithMinMaxXYZValues(surface, mostMedialXNode, mostLateralXNode, minXNode, maxXNode, minYNode, maxYNode, minZNode, maxZNode, absMinXNode, absMaxXNode, absMinYNode, absMaxYNode, absMinZNode, absMaxZNode); return minYNode; } /** * get node with maximum Y Coordinate. */ int BrainModelSurfaceROINodeSelection::getNodeWithMaximumYCoordinate(const BrainModelSurface* surface) const { int minXNode, maxXNode, minYNode, maxYNode, minZNode, maxZNode; int mostMedialXNode, mostLateralXNode; int absMinXNode, absMaxXNode, absMinYNode, absMaxYNode, absMinZNode, absMaxZNode; getNodesWithMinMaxXYZValues(surface, mostMedialXNode, mostLateralXNode, minXNode, maxXNode, minYNode, maxYNode, minZNode, maxZNode, absMinXNode, absMaxXNode, absMinYNode, absMaxYNode, absMinZNode, absMaxZNode); return maxYNode; } /** * get node with minimum Z Coordinate. */ int BrainModelSurfaceROINodeSelection::getNodeWithMinimumZCoordinate(const BrainModelSurface* surface) const { int minXNode, maxXNode, minYNode, maxYNode, minZNode, maxZNode; int mostMedialXNode, mostLateralXNode; int absMinXNode, absMaxXNode, absMinYNode, absMaxYNode, absMinZNode, absMaxZNode; getNodesWithMinMaxXYZValues(surface, mostMedialXNode, mostLateralXNode, minXNode, maxXNode, minYNode, maxYNode, minZNode, maxZNode, absMinXNode, absMaxXNode, absMinYNode, absMaxYNode, absMinZNode, absMaxZNode); return minZNode; } /** * get node with maximum Z Coordinate. */ int BrainModelSurfaceROINodeSelection::getNodeWithMaximumZCoordinate(const BrainModelSurface* surface) const { int minXNode, maxXNode, minYNode, maxYNode, minZNode, maxZNode; int mostMedialXNode, mostLateralXNode; int absMinXNode, absMaxXNode, absMinYNode, absMaxYNode, absMinZNode, absMaxZNode; getNodesWithMinMaxXYZValues(surface, mostMedialXNode, mostLateralXNode, minXNode, maxXNode, minYNode, maxYNode, minZNode, maxZNode, absMinXNode, absMaxXNode, absMinYNode, absMaxYNode, absMinZNode, absMaxZNode); return maxZNode; } /** * get the nodes that have min/max x/y/z values. * If structure is invalid medial/lateral nodes will too be invalid (-1) */ void BrainModelSurfaceROINodeSelection::getNodesWithMinMaxXYZValues( const BrainModelSurface* bms, int& xMostMedial, int& xMostLateral, int& minXNode, int& maxXNode, int& minYNode, int& maxYNode, int& minZNode, int& maxZNode, int& absMinXNode, int& absMaxXNode, int& absMinYNode, int& absMaxYNode, int& absMinZNode, int& absMaxZNode) const { xMostMedial = -1; xMostLateral = -1; minXNode = -1; maxXNode = -1; minYNode = -1; maxYNode = -1; minZNode = -1; maxZNode = -1; absMinXNode = -1; absMaxXNode = -1; absMinYNode = -1; absMaxYNode = -1; absMinZNode = -1; absMaxZNode = -1; float minX = std::numeric_limits::max(); float maxX = -std::numeric_limits::max(); float minY = std::numeric_limits::max(); float maxY = -std::numeric_limits::max(); float minZ = std::numeric_limits::max(); float maxZ = -std::numeric_limits::max(); float absMinX = std::numeric_limits::max(); float absMaxX = -std::numeric_limits::max(); float absMinY = std::numeric_limits::max(); float absMaxY = -std::numeric_limits::max(); float absMinZ = std::numeric_limits::max(); float absMaxZ = -std::numeric_limits::max(); if (bms == NULL) { return; } const int numNodes = bms->getNumberOfNodes(); if (numNodes != static_cast(nodeSelectedFlags.size())) { return; } const CoordinateFile* cf = bms->getCoordinateFile(); for (int i = 0; i < numNodes; i++) { if (nodeSelectedFlags[i] != 0) { float x, y, z; cf->getCoordinate(i, x, y, z); if (x < minX) { minX = x; minXNode = i; } if (x >= maxX) { maxX = x; maxXNode = i; } if (y < minY) { minY = y; minYNode = i; } if (y >= maxY) { maxY = y; maxYNode = i; } if (z < minZ) { minZ = z; minZNode = i; } if (z >= maxZ) { maxZ = z; maxZNode = i; } // // Do abs values // x = std::fabs(x); y = std::fabs(y); z = std::fabs(z); if (x < absMinX) { absMinX = x; absMinXNode = i; } if (x > absMaxX) { absMaxX = x; absMaxXNode = i; } if (y < absMinY) { absMinY = y; absMinYNode = i; } if (y > absMaxY) { absMaxY = y; absMaxYNode = i; } if (z < absMinZ) { absMinZ = z; absMinZNode = i; } if (z > absMaxZ) { absMaxZ = z; absMaxZNode = i; } } } // // Only set X medial and lateral if structure is valid // if (bms->getStructure().getType() == Structure::STRUCTURE_TYPE_CORTEX_LEFT) { xMostMedial = maxXNode; xMostLateral = minXNode; } else if (bms->getStructure().getType() == Structure::STRUCTURE_TYPE_CORTEX_RIGHT) { xMostMedial = minXNode; xMostLateral = maxXNode; } } /** * get the surface area of the ROI. */ float BrainModelSurfaceROINodeSelection::getSurfaceAreaOfROI(const BrainModelSurface* surface) const { float surfaceArea = 0.0; const TopologyFile* tf = surface->getTopologyFile(); const CoordinateFile* cf = surface->getCoordinateFile(); const int numTiles = tf->getNumberOfTiles(); for (int i = 0; i < numTiles; i++) { int n1, n2, n3; tf->getTile(i, n1, n2, n3); const float tileArea = MathUtilities::triangleArea(cf->getCoordinate(n1), cf->getCoordinate(n2), cf->getCoordinate(n3)); double numMarked = 0.0; if (nodeSelectedFlags[n1]) numMarked += 1.0; if (nodeSelectedFlags[n2]) numMarked += 1.0; if (nodeSelectedFlags[n3]) numMarked += 1.0; if (tileArea > 0.0) { surfaceArea += (numMarked / 3.0) * tileArea; } } return surfaceArea; } /** * set the ROI selection into file. */ void BrainModelSurfaceROINodeSelection::setRegionOfInterestIntoFile(NodeRegionOfInterestFile& nroi) const { const int numNodes = static_cast(nodeSelectedFlags.size()); nroi.setNumberOfNodes(numNodes); for (int i = 0; i < numNodes; i++) { nroi.setNodeSelected(i, (nodeSelectedFlags[i] != 0)); } nroi.setRegionOfInterestDescription(selectionDescription); } /** * get the ROI selection from file. */ void BrainModelSurfaceROINodeSelection::getRegionOfInterestFromFile(const NodeRegionOfInterestFile& nroi) throw (FileException) { const int numNodes = static_cast(nodeSelectedFlags.size()); if (numNodes == 0) { nodeSelectedFlags.resize(numNodes, false); } else if (numNodes != nroi.getNumberOfNodes()) { throw FileException("ROI and ROI-File have a different number of nodes."); } for (int i = 0; i < numNodes; i++) { if (nroi.getNodeSelected(i)) { nodeSelectedFlags[i] = 1; } else { nodeSelectedFlags[i] = 0; } } selectionDescription = nroi.getRegionOfInterestDescription(); } /** * expand the ROI so that these nodes are within the ROI and connected. */ void BrainModelSurfaceROINodeSelection::expandSoNodesAreWithinAndConnected(const BrainModelSurface* selectionSurface, const int node1, const int node2) { update(); // // If the ROI is empty, start with the two nodes // if (getNumberOfNodesSelected() <= 0) { nodeSelectedFlags[node1] = 1; nodeSelectedFlags[node2] = 1; } const std::vector nodesThatMayNotBeErodedFlags = nodeSelectedFlags; // // Dilate the ROI until node1 and node2 are both in the ROI // int dilateCounterGetNodesIntoROI = 0; while ((nodeSelectedFlags[node1] == 0) || (nodeSelectedFlags[node2] == 0)) { dilate(selectionSurface, 1); dilateCounterGetNodesIntoROI++; } if (DebugControl::getDebugOn()) { std::cout << dilateCounterGetNodesIntoROI << " iterations needed to get nodes " << node1 << " and " << node2 << " into the ROI" << std::endl; } // // do until the two nodes are connected // bool nodesConnected = false; int dilateCounterConnectNodes = 0; while (nodesConnected == false) { // // Are the nodes connected? // if (areNodesConnected(selectionSurface, nodeSelectedFlags, node1, node2)) { // // Done searching! // nodesConnected = true; } else { // // Dilate one iteration // dilate(selectionSurface, 1); dilateCounterConnectNodes++; } } if (DebugControl::getDebugOn()) { std::cout << dilateCounterConnectNodes << " iterations needed to connect nodes " << node1 << " and " << node2 << " in the ROI" << std::endl; } // // Was the ROI dilated in order to get the nodes into the ROI // or connect the nodes // const int numberOfErodeIterations = dilateCounterGetNodesIntoROI + dilateCounterConnectNodes; if (numberOfErodeIterations > 0) { // // Erode an equal number of iterations which essentially make this a // closing operation (dilation followed by erosion) // for (int i = 0; i < numberOfErodeIterations; i++) { // // Save selected nodes // const std::vector savedSelection = nodeSelectedFlags; // // Erode one itereation // erodeButMaintainNodeConnection(selectionSurface, nodesThatMayNotBeErodedFlags, 1, node1, node2); /* erode(selectionSurface, 1); // // Erosion could cause nodes to be disconnected // if (areNodesConnected(selectionSurface, nodeSelectedFlags, node1, node2) == false) { // // restore nodes selected and stop eroding // nodeSelectedFlags = savedSelection; break; } */ } } if (DebugControl::getDebugOn()) { std::cout << numberOfErodeIterations << " erosion iterations were performed " << std::endl; } } /** * see if two nodes are connected in the ROI. */ bool BrainModelSurfaceROINodeSelection::areNodesConnected(const BrainModelSurface* bms, const std::vector& connectionFlags, const int node1, const int node2) { // // Find nodes connected to first node // BrainModelSurfaceConnectedSearch connectedSearch(brainSet, (BrainModelSurface*)bms, node1, &connectionFlags); try { connectedSearch.execute(); } catch (BrainModelAlgorithmException&) { } // // Are the nodes connected? // if (connectedSearch.getNodeConnected(node2)) { // // Done searching! // return true; } return false; } /** * erode the selected nodes but maintain a connection between two nodes. */ void BrainModelSurfaceROINodeSelection::erodeButMaintainNodeConnection(const BrainModelSurface* selectionSurface, int numberOfIterations, const int node1, const int node2) { QString topologyHelperErrorMessage; const TopologyHelper* th = getSelectionSurfaceTopologyHelper(selectionSurface, topologyHelperErrorMessage); if (th == NULL) { return; } update(); const int numNodes = static_cast(nodeSelectedFlags.size()); // // Keeps track of nodes that cannot be eroded without breaking the connection // std::vector nodesThatMayNotBeEroded(numNodes, 0); nodesThatMayNotBeEroded[node1] = 1; nodesThatMayNotBeEroded[node2] = 1; // // For specified number of dilation iterations // for (int iter = 0; iter < numberOfIterations; iter++) { // // Output for eroding // std::vector nodesSelectedThisIteration = nodeSelectedFlags; // // Keeps track of nodes that were eroded this iteration // std::vector nodesErodedThisIteration; // // Check each node // for (int i = 0; i < numNodes; i++) { // // Is this node in the ROI // if (nodeSelectedFlags[i]) { // // Get node's neighbors // int numNeighbors = 0; const int* neighbors = th->getNodeNeighbors(i, numNeighbors); // // If a neighbor is not in the ROI, take "this" node out of ROI // for (int j = 0; j < numNeighbors; j++) { if (nodeSelectedFlags[neighbors[j]] == 0) { // // Make sure node can be eroded // if (nodesThatMayNotBeEroded[i] == 0) { nodesSelectedThisIteration[i] = 0; nodesErodedThisIteration.push_back(i); break; } } } } } // // See if nodes are NOT connected // if (areNodesConnected(selectionSurface, nodesSelectedThisIteration, node1, node2) == false) { // // Reset to status before this iterations erosion // nodesSelectedThisIteration = nodeSelectedFlags; // // Examine each node that was eroded this pass to see if it caused the // break in the connection // const int num = static_cast(nodesErodedThisIteration.size()); for (int m = 0; m < num; m++) { // // Get node that was eroded // const int nodeNum = nodesErodedThisIteration[m]; // // Can this node be eroded // if (nodesThatMayNotBeEroded[nodeNum] == 0) { // // Remove the node from the ROI // nodesSelectedThisIteration[nodeNum] = 0; // // See if nodes are NOT connected // if (areNodesConnected(selectionSurface, nodesSelectedThisIteration, node1, node2) == false) { // // Put node back in ROI and do not allow node to be eroded // nodesSelectedThisIteration[nodeNum] = 1; nodesThatMayNotBeEroded[nodeNum] = 1; } } } } // // Output erosion // nodeSelectedFlags = nodesSelectedThisIteration; } } /** * erode the selected nodes but maintain a connection between two nodes. */ void BrainModelSurfaceROINodeSelection::erodeButMaintainNodeConnection(const BrainModelSurface* selectionSurface, const std::vector& nodesThatMayNotBeErodedIn, int numberOfIterations, const int node1, const int node2) { QString topologyHelperErrorMessage; const TopologyHelper* th = getSelectionSurfaceTopologyHelper(selectionSurface, topologyHelperErrorMessage); if (th == NULL) { return; } update(); const int numNodes = static_cast(nodeSelectedFlags.size()); // // Keeps track of nodes that cannot be eroded without breaking the connection // std::vector nodesThatMayNotBeEroded = nodesThatMayNotBeErodedIn; nodesThatMayNotBeEroded.resize(numNodes, 0); nodesThatMayNotBeEroded[node1] = 1; nodesThatMayNotBeEroded[node2] = 1; // // For specified number of dilation iterations // for (int iter = 0; iter < numberOfIterations; iter++) { // // Output for eroding // std::vector nodesSelectedThisIteration = nodeSelectedFlags; // // Keeps track of nodes that were eroded this iteration // std::vector nodesErodedThisIteration; // // Check each node // for (int i = 0; i < numNodes; i++) { // // Is this node in the ROI // if (nodeSelectedFlags[i]) { // // Get node's neighbors // int numNeighbors = 0; const int* neighbors = th->getNodeNeighbors(i, numNeighbors); // // If a neighbor is not in the ROI, take "this" node out of ROI // for (int j = 0; j < numNeighbors; j++) { if (nodeSelectedFlags[neighbors[j]] == 0) { // // Make sure node can be eroded // if (nodesThatMayNotBeEroded[i] == 0) { nodesSelectedThisIteration[i] = 0; nodesErodedThisIteration.push_back(i); break; } } } } } // // See if nodes are NOT connected // if (areNodesConnected(selectionSurface, nodesSelectedThisIteration, node1, node2) == false) { // // Reset to status before this iterations erosion // nodesSelectedThisIteration = nodeSelectedFlags; // // Examine each node that was eroded this pass to see if it caused the // break in the connection // const int num = static_cast(nodesErodedThisIteration.size()); for (int m = 0; m < num; m++) { // // Get node that was eroded // const int nodeNum = nodesErodedThisIteration[m]; // // Can this node be eroded // if (nodesThatMayNotBeEroded[nodeNum] == 0) { // // Remove the node from the ROI // nodesSelectedThisIteration[nodeNum] = 0; // // See if nodes are NOT connected // if (areNodesConnected(selectionSurface, nodesSelectedThisIteration, node1, node2) == false) { // // Put node back in ROI and do not allow node to be eroded // nodesSelectedThisIteration[nodeNum] = 1; nodesThatMayNotBeEroded[nodeNum] = 1; } } } } // // Output erosion // nodeSelectedFlags = nodesSelectedThisIteration; } } /** * select nodes within border (returns error message). */ QString BrainModelSurfaceROINodeSelection::selectNodesWithinBorder( const SELECTION_LOGIC selectionLogic, const BrainModelSurface* selectionSurface, const Border* borderIn, const bool surface3DFlag, const float zMinimum) { // // Make all border Z zero // Border border = *borderIn; const int numLinks = border.getNumberOfLinks(); for (int i = 0; i < numLinks; i++) { float xyz[3]; border.getLinkXYZ(i, xyz); xyz[2] = 0.0; border.setLinkXYZ(i, xyz); } // // Test nodes within border // const int numNodes = selectionSurface->getNumberOfNodes(); std::vector insideBorderFlags(numNodes); border.pointsInsideBorder2D(selectionSurface->getCoordinateFile()->getCoordinate(0), numNodes, insideBorderFlags, surface3DFlag, zMinimum); // // Get nodes within border // std::vector nodeFlags(numNodes, 0); for (int i = 0; i < numNodes; i++) { if (insideBorderFlags[i]) { nodeFlags[i] = 1; } } // // Update the selected nodes // return processNewNodeSelections(selectionLogic, selectionSurface, nodeFlags, "Within Border Named " + border.getName()); } /** * select nodes within border (returns error message). */ QString BrainModelSurfaceROINodeSelection::selectNodesWithinBorderOnSphere( const SELECTION_LOGIC selectionLogic, const BrainModelSurface* sphericalSurface, const BorderProjection* borderProjection) { // // Copy sphere and orient so COG on positive Z-Axis // BrainModelSurface surface(*sphericalSurface); // // Create topology helper // const TopologyHelper* th = surface.getTopologyFile()->getTopologyHelper(false, true, false); // // Get the center of gravity of the border projection // float cog[3]; borderProjection->getCenterOfGravity(surface.getCoordinateFile(), th, cog); // // Copy sphere and orient so COG on positive Z-Axis // surface.orientPointToPositiveZAxis(cog); // // Unproject the border // Border border; borderProjection->unprojectBorderProjection(surface.getCoordinateFile(), th, border); // // Select the nodes // const QString message = selectNodesWithinBorder(selectionLogic, &surface, &border, true, 1.0); if (DebugControl::getDebugOn()) { try { CoordinateFile cf = *surface.getCoordinateFile(); cf.writeFile("Sphere_Orient_For_Border_Inclusion.coord"); BorderProjectionFile bpf; bpf.addBorderProjection(*borderProjection); bpf.writeFile("Sphere_Orient_For_Border_Inclusion.borderproj"); NodeRegionOfInterestFile roiFile; setRegionOfInterestIntoFile(roiFile); roiFile.writeFile("Sphere_Orient_For_Border_Inclusion.roi"); } catch (FileException&) { } } return message; } /** * discard islands with islands that have fewer than specified number of nodes. */ int BrainModelSurfaceROINodeSelection::discardIslands(const BrainModelSurface* selectionSurface, const int minimumNumberOfNodesInIslandsKept) { std::vector islandRootNode; std::vector islandNumNodes; std::vector nodeRootNeighbor; const int numPieces = findIslands(selectionSurface, islandRootNode, islandNumNodes, nodeRootNeighbor); // // See if there are any islands // if (numPieces <= 1) { return 0; } const int numNodes = selectionSurface->getNumberOfNodes(); // // Deselect all nodes that are not // connected to the node with the most connected neighbors // for (int i = 0; i < numNodes; i++) { for (int j = 0; j < numPieces; j++) { if (islandRootNode[j] == nodeRootNeighbor[i]) { if (islandNumNodes[j] < minimumNumberOfNodesInIslandsKept) { nodeSelectedFlags[i] = false; } break; } } } addToSelectionDescription("", ("Removed " + QString::number(numPieces - 1) + " islands containing less than " + QString::number(minimumNumberOfNodesInIslandsKept) + " nodes.")); return numPieces - 1; } /** * discard islands keeps the largest contiguous piece (returns number of islands removed). */ int BrainModelSurfaceROINodeSelection::discardIslands(const BrainModelSurface* selectionSurface) { std::vector islandRootNode; std::vector islandNumNodes; std::vector nodeRootNeighbor; const int numPieces = findIslands(selectionSurface, islandRootNode, islandNumNodes, nodeRootNeighbor); // // See if there are any islands // if (numPieces <= 1) { return 0; } const int numNodes = selectionSurface->getNumberOfNodes(); // // find node with most connected neighbors // int mostNeighborsNode = -1; int mostNeighbors = 0; for (int j = 0; j < numPieces; j++) { if (islandNumNodes[j] > 0) { if (DebugControl::getDebugOn()) { std::cout << islandRootNode[j] << " is connected to " << islandNumNodes[j] << " nodes." << std::endl; } } if (islandNumNodes[j] > mostNeighbors) { mostNeighborsNode = islandRootNode[j]; mostNeighbors = islandNumNodes[j]; } } if (DebugControl::getDebugOn()) { std::cout << mostNeighborsNode << " has the most neighbors = " << mostNeighbors << std::endl; } // // Deselect all nodes that are not // connected to the node with the most connected neighbors // if (mostNeighborsNode >= 0) { for (int i = 0; i < numNodes; i++) { if (nodeRootNeighbor[i] != mostNeighborsNode) { nodeSelectedFlags[i] = false; } } } addToSelectionDescription("", ("Removed " + QString::number(numPieces - 1) + " islands.")); return numPieces - 1; } /** * find islands (number of disjoint groups of nodes). * Returns number disjoint connected pieces of surface. * Return value of 1 indicates no islands (one connected piece of surface). * Return value of 0 indicates no topology. * Return value greater than 1 indicates islands. * * islandRootNode - contains a node in the piece of surface and the number of * elements is the number returned by this method. * islandNumNodes - is the number of nodes in the piece of surface and the * number of elements is the number returned by this method. * nodeRootNeighbor - is the "islandRootNode" for the node "i" and the number * of elements is the number of nodes in the surface. */ int BrainModelSurfaceROINodeSelection::findIslands(const BrainModelSurface* selectionSurface, std::vector& islandRootNode, std::vector& islandNumNodes, std::vector& nodeRootNeighbor) { update(); islandRootNode.clear(); islandNumNodes.clear(); nodeRootNeighbor.clear(); // // Get this topology file's topology helper (DO NOT DELETE IT) // QString topologyHelperErrorMessage; const TopologyHelper* topologyHelper = getSelectionSurfaceTopologyHelper(selectionSurface, topologyHelperErrorMessage); const int numNodes = topologyHelper->getNumberOfNodes(); if (numNodes == 0) { return 0; } if (numNodes == 1) { for (int i = 0; i < numNodes; i++) { if (nodeSelectedFlags[i]) { if (topologyHelper->getNodeHasNeighbors(i)) { islandRootNode.push_back(i); islandNumNodes.push_back(1); nodeRootNeighbor.push_back(i); break; } } } return static_cast(islandRootNode.size()); } nodeRootNeighbor.resize(numNodes); std::fill(nodeRootNeighbor.begin(), nodeRootNeighbor.end(), -1); std::vector numConnectedNeighbors(numNodes, 0); std::vector visited(numNodes, 0); // // Mark all nodes without neighbors or NOT in ROI as visited // for (int i = 0; i < numNodes; i++) { if ((topologyHelper->getNodeHasNeighbors(i) == false) || (nodeSelectedFlags[i] == 0)) { visited[i] = 1; } } // // Search the surface marking all connected nodes. // for (int n = 0; n < numNodes; n++) { if (visited[n] == 0) { const int nodeNumberIn = n; const int origNeighbor = n; std::stack st; st.push(nodeNumberIn); while(!st.empty()) { const int nodeNumber = st.top(); st.pop(); if (visited[nodeNumber] == 0) { visited[nodeNumber] = 1; nodeRootNeighbor[nodeNumber] = origNeighbor; numConnectedNeighbors[origNeighbor]++; std::vector neighbors; topologyHelper->getNodeNeighbors(nodeNumber, neighbors); for (int i = 0; i < static_cast(neighbors.size()); i++) { const int node = neighbors[i]; if (visited[node] == 0) { st.push(node); } } } } } } // // set the islands // for (int j = 0; j < numNodes; j++) { if (numConnectedNeighbors[j] > 0) { islandRootNode.push_back(j); islandNumNodes.push_back(numConnectedNeighbors[j]); if (DebugControl::getDebugOn()) { std::cout << j << " is connected to " << numConnectedNeighbors[j] << " nodes." << std::endl; } } } return static_cast(islandRootNode.size()); } /** * find islands and place each in an ROI. */ std::vector BrainModelSurfaceROINodeSelection::findIslands(const BrainModelSurface* selectionSurface) { std::vector islandsOut; // // Determine islands // std::vector islandRootNode, islandNumNodes, nodeRootNeighbor; const int numIslands = findIslands(selectionSurface, islandRootNode, islandNumNodes, nodeRootNeighbor); if (numIslands > 0) { const int numNodes = selectionSurface->getNumberOfNodes(); // // Contains mapping of Root node to ROI index // std::vector rootNodeToRoiIndex(numNodes, -1); // // Create new ROIs for each island // for (int i = 0; i < numIslands; i++) { rootNodeToRoiIndex[islandRootNode[i]] = i; islandsOut.push_back(new BrainModelSurfaceROINodeSelection(brainSet)); } // // Loop through nodes // for (int i = 0; i < numNodes; i++) { // // Assign node to proper ROI // const int roiNodeNumber = nodeRootNeighbor[i]; if (roiNodeNumber >= 0) { const int roiIndex = rootNodeToRoiIndex[roiNodeNumber]; islandsOut[roiIndex]->setNodeSelected(i, true); } } /* for (int i = 0; i < numIslands; i++) { const int rootNode = islandRootNode[i]; // // Create an ROI containing nodes in the island // BrainModelSurfaceROINodeSelection* island = new BrainModelSurfaceROINodeSelection(brainSet); for (int j = 0; j < numNodes; j++) { if (nodeRootNeighbor[j] == rootNode) { island->setNodeSelected(j, true); } } islandsOut.push_back(island); } */ } return islandsOut; } /** * find node int ROI nearest the XYZ. */ int BrainModelSurfaceROINodeSelection::getNearestNodeInROI( const BrainModelSurface* selectionSurface, const float xyz[3]) const { //update(); const CoordinateFile* cf = selectionSurface->getCoordinateFile(); int nearestNodeNumber = -1; float nearestNodeDistanceSquared = std::numeric_limits::max(); const int numNodes = selectionSurface->getNumberOfNodes(); for (int i = 0; i < numNodes; i++) { if (nodeSelectedFlags[i]) { const float distSQ = cf->getDistanceToPointSquared(i, xyz); if (distSQ < nearestNodeDistanceSquared) { nearestNodeNumber = i; nearestNodeDistanceSquared = distSQ; } } } return nearestNodeNumber; } /** * find node int ROI nearest the XYZ. */ int BrainModelSurfaceROINodeSelection::getNearestNodeInROI( const BrainModelSurface* selectionSurface, const float x, const float y, const float z) const { const float xyz[3] = { x, y, z }; return getNearestNodeInROI(selectionSurface, xyz); } /** * logically and this roi with another roi (returns error message). */ QString BrainModelSurfaceROINodeSelection::logicallyAND(const BrainModelSurfaceROINodeSelection* otherROI) { update(); const int numNodes = getNumberOfNodes(); if (numNodes != otherROI->getNumberOfNodes()) { return "Unable to AND ROIs because they have a different number of nodes."; } for (int i = 0; i < numNodes; i++) { if (nodeSelectedFlags[i] && otherROI->nodeSelectedFlags[i]) { nodeSelectedFlags[i] = true; } else { nodeSelectedFlags[i] = false; } } selectionDescription = "[" + selectionDescription + "] AND [" + otherROI->selectionDescription + "]"; return ""; } /** * logically or this roi with another roi (returns error message). */ QString BrainModelSurfaceROINodeSelection::logicallyOR(const BrainModelSurfaceROINodeSelection* otherROI) { update(); const int numNodes = getNumberOfNodes(); if (numNodes != otherROI->getNumberOfNodes()) { return "Unable to AND ROIs because they have a different number of nodes."; } for (int i = 0; i < numNodes; i++) { if (nodeSelectedFlags[i] || otherROI->nodeSelectedFlags[i]) { nodeSelectedFlags[i] = true; } else { nodeSelectedFlags[i] = false; } } selectionDescription = "[" + selectionDescription + "] AND [" + otherROI->selectionDescription + "]"; return ""; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceROIMetricSmoothing.h0000664000175000017500000001327411572067322027020 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_ROI_METRIC_SMOOTHING_H__ #define __BRAIN_MODEL_SURFACE_ROI_METRIC_SMOOTHING_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelAlgorithm.h" class BrainModelSurface; class CoordinateFile; class MetricFile; /// Class for smoothing metric data class BrainModelSurfaceROIMetricSmoothing : public BrainModelAlgorithm { public: /// Constructor BrainModelSurfaceROIMetricSmoothing(BrainSet* bs, BrainModelSurface* fiducialSurfaceIn, MetricFile* metricFileIn, MetricFile* roiFileIn, const int columnIn, const int outputColumnIn, const QString& outputColumnNameIn, const float strengthIn, const int iterationsIn, const float gaussNormBelowCutoffIn, const float gaussNormAboveCutoffIn, const float gaussSigmaNormIn, const float gaussSigmaTangIn, const float gaussTangentCutoffIn, const float geodesicGaussSigmaIn); // = 2.0f); /// Parallel Smoothing Constructor BrainModelSurfaceROIMetricSmoothing(BrainSet* bs, BrainModelSurface* fiducialSurfaceIn, MetricFile* metricFileIn, MetricFile* roiFileIn, const float strengthIn, const int iterationsIn, const float gaussNormBelowCutoffIn, const float gaussNormAboveCutoffIn, const float gaussSigmaNormIn, const float gaussSigmaTangIn, const float gaussTangentCutoffIn, const float geodesicGaussSigmaIn,//=2.0f const bool parallelSmoothingFlagIn=true); /// Destructor ~BrainModelSurfaceROIMetricSmoothing(); /// execute the algorithm void execute() throw (BrainModelAlgorithmException); void smoothSingleColumn(const QString& columnDescription, const int inputColumn, const int outputColumn); protected: /// determine neighbors for each node void determineNeighbors(); /// class for neighbor information class NeighborInfo { public: /// Constructor NeighborInfo(const std::vector& neighborsIn, const std::vector* distances, const float* roiValuesIn); /// Destructor ~NeighborInfo(); /// the neighbors std::vector neighbors; /// distance to neighbor std::vector distanceToNeighbor; /// number of neighbors int numNeighbors; }; /// neighbors for each node std::vector nodeNeighbors; /// number of nodes int numberOfNodes; /// fiducial surface used for smoothing BrainModelSurface* fiducialSurface; /// the metric file MetricFile* metricFile; /// the roi file MetricFile* roiFile; /// column number for input to smoothing int column; /// column number for output of smoothing int outputColumn; /// name of output column QString outputColumnName; /// smoothing strength float strength; /// number of smoothing iterations int iterations; /// gaussian norm below cutoff float gaussNormBelowCutoff; /// gaussian norma above cutoff float gaussNormAboveCutoff; /// gaussian sigma norm float gaussSigmaNorm; /// gaussian sigma tang float gaussSigmaTang; /// gaussian tangent cutoff float gaussTangentCutoff; /// parameter for geodesic gaussian float geodesicGaussSigma; /// roiValues for all nodes float *roiValues; /// smoothing all columns bool smoothAllColumnsFlag; /// parallelSmoothing bool runParallelFlag; }; #endif // __BRAIN_MODEL_SURFACE_METRIC_SMOOTHING_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceROIMetricSmoothing.cxx0000664000175000017500000003523311572067322027372 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include "BrainModelSurface.h" #include "BrainModelSurfaceROIMetricSmoothing.h" #include "DebugControl.h" #include "GeodesicHelper.h" #include "MetricFile.h" #include "StringUtilities.h" #include "TopologyFile.h" #include "TopologyHelper.h" #ifdef _OPENMP #include #endif /** * Constructor. */ BrainModelSurfaceROIMetricSmoothing::BrainModelSurfaceROIMetricSmoothing( BrainSet* bs, BrainModelSurface* fiducialSurfaceIn, MetricFile* metricFileIn, MetricFile* roiFileIn, const int columnIn, const int outputColumnIn, const QString& outputColumnNameIn, const float strengthIn, const int iterationsIn, const float gaussNormBelowCutoffIn, const float gaussNormAboveCutoffIn, const float gaussSigmaNormIn, const float gaussSigmaTangIn, const float gaussTangentCutoffIn, const float geodesicGaussSigmaIn) : BrainModelAlgorithm(bs) { fiducialSurface = fiducialSurfaceIn; metricFile = metricFileIn; roiFile = roiFileIn; column = columnIn; outputColumn = outputColumnIn; outputColumnName = outputColumnNameIn; strength = strengthIn; iterations = iterationsIn; gaussNormBelowCutoff = gaussNormBelowCutoffIn; gaussNormAboveCutoff = gaussNormAboveCutoffIn; gaussSigmaNorm = gaussSigmaNormIn; gaussSigmaTang = gaussSigmaTangIn; gaussTangentCutoff = gaussTangentCutoffIn; geodesicGaussSigma = geodesicGaussSigmaIn; smoothAllColumnsFlag = false; runParallelFlag = false; } /** * Constructor for all column smoothing */ BrainModelSurfaceROIMetricSmoothing::BrainModelSurfaceROIMetricSmoothing( BrainSet* bs, BrainModelSurface* fiducialSurfaceIn, MetricFile* metricFileIn, MetricFile* roiFileIn, const float strengthIn, const int iterationsIn, const float gaussNormBelowCutoffIn, const float gaussNormAboveCutoffIn, const float gaussSigmaNormIn, const float gaussSigmaTangIn, const float gaussTangentCutoffIn, const float geodesicGaussSigmaIn, const bool parallelSmoothingFlagIn) : BrainModelAlgorithm(bs) { fiducialSurface = fiducialSurfaceIn; metricFile = metricFileIn; roiFile = roiFileIn; strength = strengthIn; iterations = iterationsIn; gaussNormBelowCutoff = gaussNormBelowCutoffIn; gaussNormAboveCutoff = gaussNormAboveCutoffIn; gaussSigmaNorm = gaussSigmaNormIn; gaussSigmaTang = gaussSigmaTangIn; gaussTangentCutoff = gaussTangentCutoffIn; geodesicGaussSigma = geodesicGaussSigmaIn; runParallelFlag = parallelSmoothingFlagIn; smoothAllColumnsFlag = true; //initialize to avoid errors column = 0; outputColumn = 0; } /** * Destructor. */ BrainModelSurfaceROIMetricSmoothing::~BrainModelSurfaceROIMetricSmoothing() { } /** * execute the algorithm. */ void BrainModelSurfaceROIMetricSmoothing::execute() throw (BrainModelAlgorithmException) { numberOfNodes = fiducialSurface->getNumberOfNodes(); // // Check for valid input column // if ((metricFile->getNumberOfColumns() <= 0) || (metricFile->getNumberOfNodes() <= 0)) { throw BrainModelAlgorithmException("Metric file contains no data."); } if ((roiFile->getNumberOfColumns() <= 0) ) { throw BrainModelAlgorithmException("ROI file contains no data."); } if (!smoothAllColumnsFlag && ((column < 0) || (column >= metricFile->getNumberOfColumns()))) { throw BrainModelAlgorithmException("Input metric column is invalid."); } // // Create a new column if needed. // if (!smoothAllColumnsFlag && ((outputColumn < 0) || (outputColumn >= metricFile->getNumberOfColumns()))){ metricFile->addColumns(1); outputColumn = metricFile->getNumberOfColumns() - 1; } if(!outputColumnName.isEmpty())metricFile->setColumnName(outputColumn, outputColumnName); // // Copy the input column to the output column // if (column != outputColumn) { std::vector values; metricFile->getColumnForAllNodes(column, values); metricFile->setColumnForAllNodes(outputColumn, values); } // // Get array of ROI values for all nodes // roiValues = new float[numberOfNodes]; roiFile->getColumnForAllNodes(0,roiValues); // // Determine the neighbors for each node // determineNeighbors(); QString smoothComment; smoothComment.append("Geodesic Gaussian Smoothing: \n"); smoothComment.append(" Sigma: "); smoothComment.append(StringUtilities::fromNumber(geodesicGaussSigma)); smoothComment.append("\n"); smoothComment.append(" Stength/Iterations: "); smoothComment.append(StringUtilities::fromNumber(strength)); smoothComment.append(" "); smoothComment.append(StringUtilities::fromNumber(iterations)); smoothComment.append("\n"); bool debugOpenMpFlag = false; if (this->smoothAllColumnsFlag) { int numColumns = this->metricFile->getNumberOfColumns(); if (this->runParallelFlag) { #pragma omp parallel for for (int i = 0; i < numColumns; i++) { if (debugOpenMpFlag) { std::cout << "Start Smoothing Column: " << i << std::endl; } this->smoothSingleColumn(smoothComment, i, i); if (debugOpenMpFlag) { std::cout << "Finished Smoothing Column: " << i << std::endl; } } } else { for (int i = 0; i < numColumns; i++) { if (debugOpenMpFlag) { std::cout << "Smoothing Column " << i << std::endl; } this->smoothSingleColumn(smoothComment, i, i); } } } else { this->smoothSingleColumn(smoothComment, column, outputColumn); } delete[] roiValues; } /** * smooth a column in the metric file. */ void BrainModelSurfaceROIMetricSmoothing::smoothSingleColumn(const QString& columnDescription, const int inputColumn, const int outputColumn) { // // Allocate arrays for storing data of column being smoothed // int numberOfNodes = metricFile->getNumberOfNodes(); float* inputValues = new float[numberOfNodes]; float* outputValues = new float[numberOfNodes]; metricFile->getColumnForAllNodes(inputColumn, inputValues); if (inputColumn != outputColumn) { metricFile->setColumnForAllNodes(outputColumn, inputValues); } int smoothColumn = outputColumn; // // Prepare for smoothing // for (int iter = 0; iter < iterations; iter++) { bool stopSmoothingFlag = false; // // Should smoothing be stopped ??? // if (stopSmoothingFlag) { break; } // // load arrays for smoothing data // metricFile->getColumnForAllNodes(smoothColumn, inputValues); // // smooth all of the nodes // for (int i = 0; i < numberOfNodes; i++) { // // copy input to output in event this node is not smoothed // outputValues[i] = inputValues[i]; //Here is where we filter out center nodes that aren't in the ROI if(roiValues[i] == 0.0) //make sure round-off errors don't affect this { outputValues[i] = 0.0; continue; } const NeighborInfo& neighInfo = nodeNeighbors[i]; // // Does this node have neighbors // if (neighInfo.numNeighbors > 0) { float neighborSum = 0.0; bool setOutputValueFlag = true; //distance to neighbor is geodesic, not euclidean, check determineNeighbors int j, end = neighInfo.numNeighbors; float totalWeight = 0.0f, weight, tempf; for (j = 0; j < end; ++j) {//weighted average, using gaussian of geodesic distance as weight tempf = neighInfo.distanceToNeighbor[j] / geodesicGaussSigma; weight = std::exp((double)(-tempf * tempf * 0.5f));//the gaussian function totalWeight += weight; neighborSum += weight * inputValues[neighInfo.neighbors[j]]; } neighborSum /= totalWeight; // // Apply smoothing to the node // if (setOutputValueFlag) { if (DebugControl::getDebugOn()) { if (DebugControl::getDebugNodeNumber() == i) { std::cout << "Smoothing node " << i << " iteration " << iter << " node neighbor sum " << neighborSum << std::endl; } } outputValues[i] = neighborSum;//WARNING: used for geodesic gaussian, if this is changed, make geogauss gives the same result (ignore strength) } } } // // Copy the smoothed values to the output column // metricFile->setColumnForAllNodes(smoothColumn, outputValues); } // for +iterations delete[] inputValues; delete[] outputValues; QString smoothComment(metricFile->getColumnComment(smoothColumn)); if (smoothComment.isEmpty() == false) { smoothComment.append("\n"); } smoothComment.append(columnDescription); metricFile->setColumnComment(smoothColumn, smoothComment); } /** * determine neighbors for each node. */ void BrainModelSurfaceROIMetricSmoothing::determineNeighbors() { // // Clear the neighbors // nodeNeighbors.clear(); // // Get the topology helper // const TopologyFile* topologyFile = fiducialSurface->getTopologyFile(); const TopologyHelper* topologyHelper = topologyFile->getTopologyHelper(false, true, false); // // Coordinate file and maximum distance cutoff // CoordinateFile* cf = fiducialSurface->getCoordinateFile(); GeodesicHelper* gh = NULL; float geoCutoff = 4.0f * geodesicGaussSigma; std::vector* distance = NULL; cf = fiducialSurface->getCoordinateFile(); gh = new GeodesicHelper(cf, topologyFile); distance = new std::vector; // // Loop through the nodes // QTime timer; timer.start(); for (int i = 0; i < numberOfNodes; i++) { std::vector neighbors; int NumberofNeighborsInROI = 0; gh->getNodesToGeoDist(i, geoCutoff, neighbors, *distance, true); for(unsigned int j = 0;jgetNodeNeighbors(i, neighbors); neighbors.push_back(i);//for geogauss, we want the center node in the list gh->getGeoToTheseNodes(i, neighbors, *distance, true); } // // add to all neighbors // nodeNeighbors.push_back(NeighborInfo(neighbors,distance,roiValues)); } if (gh) delete gh; if (distance) delete distance; const float elapsedTime = timer.elapsed() * 0.001; if (DebugControl::getDebugOn()) { std::cout << "Time to determine neighbors: " << elapsedTime << " seconds." << std::endl; } } //*************************************************************************************** /** * Constructor. */ BrainModelSurfaceROIMetricSmoothing::NeighborInfo::NeighborInfo(const std::vector& neighborsIn, const std::vector* distances, const float * roiValuesIn) { const int numNeighborsIn = static_cast(neighborsIn.size()); for (int i = 0; i < numNeighborsIn; i++) { const int node = neighborsIn[i]; // here is where we filter out neighbors that aren't in the ROI if(roiValuesIn[neighborsIn[i]] == 0.0) continue; //make sure round-off errors don't affect this neighbors.push_back(node); distanceToNeighbor.push_back((*distances)[i]); } numNeighbors = static_cast(neighbors.size()); } /** * Destructor. */ BrainModelSurfaceROIMetricSmoothing::NeighborInfo::~NeighborInfo() { } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceROIMetricGradient.h0000664000175000017500000000776511572067322026616 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_METRIC_GRADIENT_H__ #define __BRAIN_MODEL_SURFACE_METRIC_GRADIENT_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelAlgorithm.h" class CoordinateFile; class MetricFile; class VectorFile; class TopologyHelper; /// class for create a functional volume using a probabilistic volume class BrainModelSurfaceROIMetricGradient : public BrainModelAlgorithm { public: /// Constructor for execution on single column BrainModelSurfaceROIMetricGradient(BrainSet* bs, int bsIndexIn, MetricFile* roiIn, MetricFile* valuesIn, int metricIndexIn, VectorFile* gradOutIn, MetricFile* gradMagOutIn, int magOutIndexIn, bool avgNormalsIn = false); /// Constructor for execution of all columns BrainModelSurfaceROIMetricGradient(BrainSet* bs, int bsIndexIn, MetricFile* roiIn, MetricFile* valuesIn, bool avgNormalsIn, bool parallelFlagIn); /// Destructor ~BrainModelSurfaceROIMetricGradient(); /// execute the algorithm void execute() throw (BrainModelAlgorithmException); private: /// execute on single metric column void executeSingleColumn() throw (BrainModelAlgorithmException); void executeAllColumns() throw (BrainModelAlgorithmException); void processSingleColumn(const TopologyHelper* myhelper, const float* allnormals, const float* sourceData, const float* roiValues, const int columnIndex, const int numNodes) throw (BrainModelAlgorithmException); void initialize(); bool allColumnsFlag; bool parallelFlag; int setIndex, metricIndex, magOutIndex, depth; MetricFile* values, *roi, *gradMagOut; VectorFile* gradOut; bool avgNormals; void crossProd(const float in1[3], const double in2[3], double out[3]); void crossProd(const double in1[3], const double in2[3], double out[3]); double dotProd(const double in1[3], const double in2[3]); double dotProd(const float in1[3], const double in2[3]); void normalize(double in[3]); void coordDiff(const float* coord1, const float* coord2, double out[3]); void calcrref(double* matrix[], int rows, int cols); double det3(double* matrix[], int column); bool haveWarned; bool haveFailed; }; #endif // __BRAIN_MODEL_SURFACE_METRIC_GRADIENT_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceROIMetricGradient.cxx0000664000175000017500000007466611572067322027175 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurfaceROIMetricGradient.h" #include "BrainSet.h" #include "BrainModelSurface.h" #include "CoordinateFile.h" #include "TopologyFile.h" #include "TopologyHelper.h" #include "VectorFile.h" #include "MetricFile.h" #include #include #ifdef _OPENMP #include #endif void BrainModelSurfaceROIMetricGradient::crossProd(const float in1[3], const double in2[3], double out[3]) {//avoid loops for speed out[0] = in1[1] * in2[2] - in1[2] * in2[1]; out[1] = in1[2] * in2[0] - in1[0] * in2[2]; out[2] = in1[0] * in2[1] - in1[1] * in2[0]; } void BrainModelSurfaceROIMetricGradient::crossProd(const double in1[3], const double in2[3], double out[3]) {//avoid loops for speed out[0] = in1[1] * in2[2] - in1[2] * in2[1]; out[1] = in1[2] * in2[0] - in1[0] * in2[2]; out[2] = in1[0] * in2[1] - in1[1] * in2[0]; } double BrainModelSurfaceROIMetricGradient::dotProd(const double in1[3], const double in2[3]) { return in1[0] * in2[0] + in1[1] * in2[1] + in1[2] * in2[2]; } double BrainModelSurfaceROIMetricGradient::dotProd(const float in1[3], const double in2[3]) { return in1[0] * in2[0] + in1[1] * in2[1] + in1[2] * in2[2]; } void BrainModelSurfaceROIMetricGradient::normalize(double in[3]) { double mag = sqrt(in[0] * in[0] + in[1] * in[1] + in[2] * in[2]); in[0] /= mag; in[1] /= mag; in[2] /= mag; } void BrainModelSurfaceROIMetricGradient::coordDiff(const float* coord1, const float* coord2, double out[3]) { out[0] = coord1[0] - coord2[0]; out[1] = coord1[1] - coord2[1]; out[2] = coord1[2] - coord2[2]; } void BrainModelSurfaceROIMetricGradient::calcrref(double* matrix[], int rows, int cols) {//assumes more cols than rows int i, j, k, temp; double tempd, tempd2; for (i = 0; i < rows; ++i) { tempd = std::abs(matrix[i][i]);//search for pivot temp = i; for (j = i + 1; j < rows; ++j) { tempd2 = std::abs(matrix[j][i]); if (tempd2 > tempd) { tempd = tempd2; temp = j; } } if (i != temp) { for (j = i; j < cols; ++j) {//skip the waste that will end up 0's and 1's tempd = matrix[i][j]; matrix[i][j] = matrix[temp][j]; matrix[temp][j] = tempd; } } tempd = matrix[i][i];//pivot for (j = i + 1; j < cols; ++j) {//again, skip the 0's and 1's matrix[i][j] /= tempd; for (k = 0; k < i; ++k) { matrix[k][j] -= matrix[k][i] * matrix[i][j]; } for (++k; k < rows; ++k) { matrix[k][j] -= matrix[k][i] * matrix[i][j]; } } }//rref complete for all cols >= rows, just pretend rowsXrows is I } /** * Constructor. */ BrainModelSurfaceROIMetricGradient::BrainModelSurfaceROIMetricGradient( BrainSet* bs, int bsIndexIn, MetricFile* roiIn, MetricFile* valuesIn, int metricIndexIn, VectorFile* gradOutIn, MetricFile* gradMagOutIn, int magOutIndexIn, bool avgNormalsIn) : BrainModelAlgorithm(bs) { initialize(); setIndex = bsIndexIn; values = valuesIn; roi = roiIn; metricIndex = metricIndexIn; gradOut = gradOutIn; gradMagOut = gradMagOutIn; magOutIndex = magOutIndexIn; avgNormals = avgNormalsIn; } /** * Constructor for execution of all columns. */ BrainModelSurfaceROIMetricGradient::BrainModelSurfaceROIMetricGradient(BrainSet* bs, int bsIndexIn, MetricFile* roiIn, MetricFile* valuesIn, bool avgNormalsIn, bool parallelFlagIn) : BrainModelAlgorithm(bs) { initialize(); setIndex = bsIndexIn; roi = roiIn; values = valuesIn; gradMagOut = valuesIn; avgNormals = avgNormalsIn; allColumnsFlag = true; parallelFlag = parallelFlagIn; } /** * Destructor. */ BrainModelSurfaceROIMetricGradient::~BrainModelSurfaceROIMetricGradient() { } void BrainModelSurfaceROIMetricGradient::initialize() { allColumnsFlag = false; parallelFlag = false; haveWarned = false; haveFailed = false; } /** * execute the algorithm. */ void BrainModelSurfaceROIMetricGradient::execute() throw (BrainModelAlgorithmException) { if (allColumnsFlag) { executeAllColumns(); } else { executeSingleColumn(); } } /** * execute all the metric columns */ void BrainModelSurfaceROIMetricGradient::executeAllColumns() throw (BrainModelAlgorithmException) { // // Verify files exist, are valid, etc. // BrainModelSurface* mysurf = brainSet->getBrainModelSurface(setIndex);//reference CoordinateFile* source = mysurf->getCoordinateFile();//reference TopologyFile* topo = mysurf->getTopologyFile(); const TopologyHelper* myhelper = topo->getTopologyHelper(false, true, false); mysurf->computeNormals(); mysurf->orientNormalsOut(); if (source == NULL) { throw BrainModelAlgorithmException("Invalid coordinate file."); } if (values == NULL) { throw BrainModelAlgorithmException("Invalid metric file."); } if (roi == NULL) { throw BrainModelAlgorithmException("Invalid roi file."); } if (source->getNumberOfCoordinates() < 1) { throw BrainModelAlgorithmException("Not enough nodes in coordinate file."); } if (source->getNumberOfCoordinates() != values->getNumberOfNodes()) { throw BrainModelAlgorithmException("Coordinate file contains different number of nodes than metric file."); } if (source->getNumberOfCoordinates() != roi->getNumberOfNodes()) { throw BrainModelAlgorithmException("Coordinate file contains different number of nodes than ROI file."); } int numNodes = source->getNumberOfCoordinates(); int i, j, k, numNeigh; float* sourceData = new float[numNodes * 3]; source->getAllCoordinates(sourceData); float* roiValues = new float[numNodes]; float* magData = NULL; std::vector neighbors; magData = new float[numNodes]; roi->getColumnForAllNodes(0,roiValues); float* allnormals = new float[numNodes * 3]; for (i = 0; i < numNodes; ++i) { j = i * 3; const float* mynormal = mysurf->getNormal(i); allnormals[j] = mynormal[0]; allnormals[j + 1] = mynormal[1]; allnormals[j + 2] = mynormal[2]; } if (avgNormals) {//assume normals have identical length for (i = 0; i < numNodes; ++i) { const float* mynormal = mysurf->getNormal(i); if(roiValues[i] == 0.0f) continue; //should these be filtered or not?, I'm thinking for now that //normals should not be filtered myhelper->getNodeNeighbors(i, neighbors); numNeigh = neighbors.size(); for (j = 0; j < numNeigh; ++j) { k = neighbors[j] * 3; allnormals[k] += mynormal[0]; allnormals[k + 1] += mynormal[1]; allnormals[k + 2] += mynormal[2]; } } }//WARNING: normals are not normalized, nor identical length - below algorithm normalizes after every use of a normal though int numColumns = values->getNumberOfColumns(); if (parallelFlag) { #pragma omp parallel for for (int i = 0; i < numColumns; i++) { processSingleColumn(myhelper, allnormals, sourceData, roiValues, i, numNodes); } } else { for (int i = 0; i < numColumns; i++) { processSingleColumn(myhelper, allnormals, sourceData, roiValues, i, numNodes); } } delete[] allnormals; delete[] roiValues; delete[] sourceData; } /** * process single column. */ void BrainModelSurfaceROIMetricGradient::processSingleColumn(const TopologyHelper* myhelper, const float* allnormals, const float* sourceData, const float* roiValues, const int columnIndex, const int numNodes) throw (BrainModelAlgorithmException) { int i, j, k, numNeigh, whichnode; double xhat[3], yhat[3], somevec[3]; float nodemetric; double xmag, ymag,tempd, sanity; double* rrefb[3]; double *savedVec = new double[numNodes * 3]; float* metricData = new float[numNodes]; float* magData = new float[numNodes]; std::vector neighbors; values->getColumnForAllNodes(columnIndex, metricData); rrefb[0] = new double[4]; rrefb[1] = new double[4]; rrefb[2] = new double[4]; //std::vector RejectedNodes; //Nodes that for whatever reason were throw out of the calculation (too few neighbors, etc.) for (i = 0; i < numNodes; ++i) { if(roiValues[i] == 0.0f) { savedVec[i*3]=0.0; savedVec[i*3+1]=0.0; savedVec[i*3+2]=0.0; magData[i] = 0.0f; continue; } const float* mynormal = allnormals + i * 3; 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; } crossProd(mynormal, somevec, xhat); normalize(xhat);//use cross products to generate a 2d coordinate system orthogonal to normal crossProd(mynormal, xhat, yhat); normalize(yhat);//xhat, yhat are orthogonal unit vectors describing the coord system with k = surface normal for (j = 0; j < 4; ++j) { rrefb[0][j] = 0.0; rrefb[1][j] = 0.0; rrefb[2][j] = 0.0; } nodemetric = metricData[i];//uses metric difference for 2 reasons: makes rref cumulate smaller values, and makes root node not matter to calculation //use function below to filter node neighbors based on ROI myhelper->getNodeNeighborsInROI(i, neighbors,roiValues);//intelligently detects depth == 1 (and invalid depth) //TODO: need to check if neighbors.size is zero numNeigh = neighbors.size(); /*unsigned int MinimumNeighbors = 3;//let fallback handle this by calculating gradient vectors to neighbors and averaging if(neighbors.size() < MinimumNeighbors) { //cout << "node number is " << i << endl; //cout << "neighbor count is " << neighbors.size() << endl; RejectedNodes.push_back(i); continue; }*/ if (numNeigh >= 2)//dont attempt regression if the system is underdetermined { for (j = 0; j < numNeigh; ++j) { whichnode = neighbors[j]; tempd = metricData[whichnode] - nodemetric;//metric difference coordDiff(&sourceData[whichnode * 3], &sourceData[i * 3], somevec);//position delta vector xmag = dotProd(xhat, somevec);//project to 2d plane tangent to surface ymag = dotProd(yhat, somevec); rrefb[0][0] += xmag * xmag;//gather A'A and A'b sums for regression rrefb[0][1] += xmag * ymag; rrefb[0][2] += xmag; rrefb[1][1] += ymag * ymag; rrefb[1][2] += ymag; rrefb[2][2] += 1.0f; rrefb[0][3] += xmag * tempd; rrefb[1][3] += ymag * tempd; rrefb[2][3] += tempd; } rrefb[1][0] = rrefb[0][1];//complete the symmetric elements rrefb[2][0] = rrefb[0][2]; rrefb[2][1] = rrefb[1][2]; rrefb[2][2] += 1.0f;//include center (metric and coord differences will be zero, so this is all that is needed) calcrref(rrefb, 3, 4); somevec[0] = xhat[0] * rrefb[0][3] + yhat[0] * rrefb[1][3]; somevec[1] = xhat[1] * rrefb[0][3] + yhat[1] * rrefb[1][3]; somevec[2] = xhat[2] * rrefb[0][3] + yhat[2] * rrefb[1][3];//somevec is now our surface gradient sanity = (float)(somevec[0] + somevec[1] + somevec[2]); } if (numNeigh < 2 || !(sanity == sanity)) { //expect this to happen with ROI gradient //if (!haveWarned) std::cerr << "WARNING: gradient calculation found a NaN/inf with regression method" << endl; //haveWarned = true; if (numNeigh != 0) { somevec[0] = 0.0; somevec[1] = 0.0; somevec[2] = 0.0; for (j = 0; j < numNeigh; ++j) { whichnode = neighbors[j]; coordDiff(&sourceData[whichnode * 3], &sourceData[i * 3], xhat);//xhat repurposed as a temp variable for (k = 0; k < 3; ++k) yhat[k] = xhat[k]; normalize(xhat); tempd = (metricData[whichnode] - nodemetric) / sqrt(yhat[0] * yhat[0] + yhat[1] * yhat[1] + yhat[2] * yhat[2]);//difference over distance gives gradient magnitude for (k = 0; k < 3; ++k) somevec[k] += tempd * xhat[k];//magnitude times unit vector parallel to distance vector gives crude estimate } for (j = 0; j < 3; ++j) { somevec[j] /= numNeigh;//now we have the 3d gradient, time to subtract the dot product with normal xhat[j] = mynormal[j]; } normalize(xhat);//for sanity, in case your normals aren't unit vectors somehow tempd = dotProd(somevec, xhat); sanity = 0.0; for (j = 0; j < 3; ++j) sanity += (float)((somevec[j] -= tempd * xhat[j])); } if (numNeigh == 0 || !(sanity == sanity)) { if (!haveFailed) { std::cerr << "WARNING: gradient calculation found a NaN/inf with fallback method, outputting ZERO" << endl; std::cerr << "check your coordinate/topo files for isolated nodes and nodes with identical coords" << endl; } haveFailed = true; somevec[0] = 0.0; somevec[1] = 0.0; somevec[2] = 0.0; } } //saveVec savedVec[i*3]=somevec[0]; savedVec[i*3+1]=somevec[1]; savedVec[i*3+2]=somevec[2]; magData[i] = (float)sqrt(somevec[0] * somevec[0] + somevec[1] * somevec[1] + somevec[2] * somevec[2]); } //For nodes that have less than 3 neighbors, we calculate the average gradient vector of that node's neighbors //This gives us a crude estimate of what that node's gradient vector should be. /*for(unsigned int i = 0;igetNodeNeighborsInROI(Node, neighbors,roiValues); double averageVec[3] = { 0.0, 0.0, 0.0 }; //calculate average Vector if (neighbors.size() > 0) { for(unsigned int j = 0;jsetColumnForAllNodes(columnIndex, magData); gradMagOut->setColumnName(columnIndex, "surface gradient"); delete[] magData; delete[] metricData; delete[] rrefb[0]; delete[] rrefb[1]; delete[] rrefb[2]; } /** * execute the algorithm on a single metric column. */ void BrainModelSurfaceROIMetricGradient::executeSingleColumn() throw (BrainModelAlgorithmException) { // // Verify files exist, are valid, etc. // BrainModelSurface* mysurf = brainSet->getBrainModelSurface(setIndex);//reference CoordinateFile* source = mysurf->getCoordinateFile();//reference TopologyFile* topo = mysurf->getTopologyFile(); const TopologyHelper* myhelper = topo->getTopologyHelper(false, true, false); mysurf->computeNormals(); mysurf->orientNormalsOut(); if (source == NULL) { throw BrainModelAlgorithmException("Invalid coordinate file."); } if (values == NULL) { throw BrainModelAlgorithmException("Invalid metric file."); } if (roi == NULL) { throw BrainModelAlgorithmException("Invalid roi file."); } if (source->getNumberOfCoordinates() < 1) { throw BrainModelAlgorithmException("Not enough nodes in coordinate file."); } if (source->getNumberOfCoordinates() != values->getNumberOfNodes()) { throw BrainModelAlgorithmException("Coordinate file contains different number of nodes than metric file."); } if (source->getNumberOfCoordinates() != roi->getNumberOfNodes()) { throw BrainModelAlgorithmException("Coordinate file contains different number of nodes than ROI file."); } // // Check output files exist // bool saveMag = true, saveVec = true; if (gradMagOut == NULL) { saveMag = false; } else { if (source->getNumberOfCoordinates() != gradMagOut->getNumberOfNodes()) { gradMagOut->setNumberOfNodesAndColumns(source->getNumberOfCoordinates(), 1);//clear existing data because node numbers don't match magOutIndex = 0; } if (magOutIndex < 0 || magOutIndex >= gradMagOut->getNumberOfColumns()) { magOutIndex = gradMagOut->getNumberOfColumns(); gradMagOut->addColumns(1); } gradMagOut->setColumnName(magOutIndex, "surface gradient"); } if (gradOut == NULL) { saveVec = false; gradOut = new VectorFile();//need to create one anyway as a place to store vectors gradOut->setNumberOfVectors(source->getNumberOfCoordinates()); } else { if (source->getNumberOfCoordinates() != gradOut->getNumberOfVectors()) { gradOut->setNumberOfVectors(source->getNumberOfCoordinates()); } } if (!saveMag && !saveVec) { throw BrainModelAlgorithmException("No valid output file."); } int numNodes = source->getNumberOfCoordinates(); int i, j, k, numNeigh, whichnode; double xhat[3], yhat[3], somevec[3]; float nodemetric, somevecf[3]; double xmag, ymag,tempd, sanity; double* rrefb[3]; float* sourceData = new float[numNodes * 3]; source->getAllCoordinates(sourceData); float* metricData = new float[numNodes]; float* roiValues = new float[numNodes]; float* magData = NULL; std::vector neighbors; if (saveMag) { magData = new float[numNodes]; } values->getColumnForAllNodes(metricIndex, metricData); roi->getColumnForAllNodes(0,roiValues); rrefb[0] = new double[4]; rrefb[1] = new double[4]; rrefb[2] = new double[4]; float* allnormals = new float[numNodes * 3]; for (i = 0; i < numNodes; ++i) { j = i * 3; const float* mynormal = mysurf->getNormal(i); allnormals[j] = mynormal[0]; allnormals[j + 1] = mynormal[1]; allnormals[j + 2] = mynormal[2]; } if (avgNormals) {//assume normals have identical length for (i = 0; i < numNodes; ++i) { const float* mynormal = mysurf->getNormal(i); if(roiValues[i] == 0.0f) continue; //should these be filtered or not?, I'm thinking for now that //normals should not be filtered myhelper->getNodeNeighbors(i, neighbors); numNeigh = neighbors.size(); for (j = 0; j < numNeigh; ++j) { k = neighbors[j] * 3; allnormals[k] += mynormal[0]; allnormals[k + 1] += mynormal[1]; allnormals[k + 2] += mynormal[2]; } } }//WARNING: normals are not normalized, nor identical length - below algorithm normalizes after every use of a normal though std::vector RejectedNodes; //Nodes that for whatever reason were throw out of the calculation (too few neighbors, etc.) for (i = 0; i < numNodes; ++i) { if(roiValues[i] == 0.0f) { //saveVec gradOut->setVectorOrigin(i, &sourceData[i * 3]); const float xyzVectorIn[3] = {0.0f,0.0f, 0.0f}; gradOut->setVectorUnitComponents(i, xyzVectorIn);//gradient complete! if (saveMag) { magData[i] = 0.0f; } continue; } float* mynormal = allnormals + i * 3; 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; } crossProd(mynormal, somevec, xhat); normalize(xhat);//use cross products to generate a 2d coordinate system orthogonal to normal crossProd(mynormal, xhat, yhat); normalize(yhat);//xhat, yhat are orthogonal unit vectors describing the coord system with k = surface normal for (j = 0; j < 4; ++j) { rrefb[0][j] = 0.0; rrefb[1][j] = 0.0; rrefb[2][j] = 0.0; } nodemetric = metricData[i];//uses metric difference for 2 reasons: makes rref cumulate smaller values, and makes root node not matter to calculation //use function below to filter node neighbors based on ROI myhelper->getNodeNeighborsInROI(i, neighbors,roiValues);//intelligently detects depth == 1 (and invalid depth) //TODO: need to check if neighbors.size is zero numNeigh = neighbors.size(); /*unsigned int MinimumNeighbors = 3;//let fallback handle this by calculating gradient vectors to neighbors and averaging if(neighbors.size() < MinimumNeighbors) { //cout << "node number is " << i << endl; //cout << "neighbor count is " << neighbors.size() << endl; RejectedNodes.push_back(i); continue; }*/ if (numNeigh >= 2)//dont attempt regression if the system is underdetermined { for (j = 0; j < numNeigh; ++j) { whichnode = neighbors[j]; tempd = metricData[whichnode] - nodemetric;//metric difference coordDiff(&sourceData[whichnode * 3], &sourceData[i * 3], somevec);//position delta vector xmag = dotProd(xhat, somevec);//project to 2d plane tangent to surface ymag = dotProd(yhat, somevec); rrefb[0][0] += xmag * xmag;//gather A'A and A'b sums for regression rrefb[0][1] += xmag * ymag; rrefb[0][2] += xmag; rrefb[1][1] += ymag * ymag; rrefb[1][2] += ymag; rrefb[2][2] += 1.0f; rrefb[0][3] += xmag * tempd; rrefb[1][3] += ymag * tempd; rrefb[2][3] += tempd; } rrefb[1][0] = rrefb[0][1];//complete the symmetric elements rrefb[2][0] = rrefb[0][2]; rrefb[2][1] = rrefb[1][2]; rrefb[2][2] += 1.0f;//include center (metric and coord differences will be zero, so this is all that is needed) calcrref(rrefb, 3, 4); somevecf[0] = (float)(somevec[0] = xhat[0] * rrefb[0][3] + yhat[0] * rrefb[1][3]); somevecf[1] = (float)(somevec[1] = xhat[1] * rrefb[0][3] + yhat[1] * rrefb[1][3]); somevecf[2] = (float)(somevec[2] = xhat[2] * rrefb[0][3] + yhat[2] * rrefb[1][3]);//somevec is now our surface gradient sanity = somevec[0] + somevec[1] + somevec[2]; } if (numNeigh < 2 || !(sanity == sanity)) { //expect this to happen with ROI gradient //if (!haveWarned) std::cerr << "WARNING: gradient calculation found a NaN/inf with regression method" << endl; //haveWarned = true; if (numNeigh != 0) { somevecf[0] = 0.0f; somevecf[1] = 0.0f; somevecf[2] = 0.0f; somevec[0] = 0.0; somevec[1] = 0.0; somevec[2] = 0.0; for (j = 0; j < numNeigh; ++j) { whichnode = neighbors[j]; coordDiff(&sourceData[whichnode * 3], &sourceData[i * 3], xhat);//xhat repurposed as a temp variable for (k = 0; k < 3; ++k) yhat[k] = xhat[k]; normalize(xhat); tempd = (metricData[whichnode] - nodemetric) / sqrt(yhat[0] * yhat[0] + yhat[1] * yhat[1] + yhat[2] * yhat[2]);//difference over distance gives gradient magnitude for (k = 0; k < 3; ++k) somevec[k] += tempd * xhat[k];//magnitude times unit vector parallel to distance vector gives crude estimate } for (j = 0; j < 3; ++j) { somevec[j] /= numNeigh;//now we have the 3d gradient, time to subtract the dot product with normal xhat[j] = mynormal[j]; } normalize(xhat);//for sanity, in case your normals aren't unit vectors somehow tempd = dotProd(somevec, xhat); sanity = 0.0; for (j = 0; j < 3; ++j) sanity += (somevecf[j] = (float)(somevec[j] -= tempd * xhat[j])); } if (numNeigh == 0 || !(sanity == sanity)) { if (!haveFailed) { std::cerr << "WARNING: gradient calculation found a NaN/inf with fallback method, outputting ZERO" << endl; std::cerr << "check your coordinate/topo files for isolated nodes and nodes with identical coords" << endl; } haveFailed = true; somevecf[0] = 0.0f; somevecf[1] = 0.0f; somevecf[2] = 0.0f; somevec[0] = 0.0; somevec[1] = 0.0; somevec[2] = 0.0; } } //saveVec gradOut->setVectorOrigin(i, &sourceData[i * 3]); gradOut->setVectorUnitComponents(i, somevecf);//gradient complete! if (saveMag) { magData[i] = (float)sqrt(somevec[0] * somevec[0] + somevec[1] * somevec[1] + somevec[2] * somevec[2]); } } //For nodes that have less than 3 neighbors, we calculate the average gradient vector of that node's neighbors //This gives us a crude estimate of what that node's gradient vector should be. /*for(unsigned int i = 0;igetNodeNeighborsInROI(Node, neighbors,roiValues); double averageVec[3] = { 0.0, 0.0, 0.0 }; //calculate average Vector if (neighbors.size() > 0) { for(unsigned int j = 0;jsetColumnForAllNodes(magOutIndex, magData); delete[] magData; } if(!saveVec) delete gradOut; delete[] sourceData; delete[] metricData; delete[] rrefb[0]; delete[] rrefb[1]; delete[] rrefb[2]; delete[] allnormals; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceROIMetricClusterReport.h0000664000175000017500000000520211572067322027656 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_ROI_METRIC_CLUSTER_REPORT_H__ #define __BRAIN_MODEL_SURFACE_ROI_METRIC_CLUSTER_REPORT_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurfaceROIOperation.h" class MetricFile; /// class for metric cluster report class BrainModelSurfaceROIMetricClusterReport : public BrainModelSurfaceROIOperation { public: // constructor BrainModelSurfaceROIMetricClusterReport(BrainSet* bs, BrainModelSurface* bmsIn, BrainModelSurfaceROINodeSelection* surfaceROIIn, MetricFile* metricOrShapeFileIn, const std::vector& columnSelectedFlags, MetricFile* distortionMetricFileIn, const int distortionMetricFileColumnIn, const float metricThresholdValueIn, const bool separateWithSemicolonsFlagIn); // destructor ~BrainModelSurfaceROIMetricClusterReport(); protected: // execute the operation virtual void executeOperation() throw (BrainModelAlgorithmException); /// the metric file MetricFile* metricFile; /// column selected flag std::vector columnSelectedFlags; /// the metric distortion file MetricFile* distortionMetricFile; /// metric threshold column number int distortionMetricFileColumn; /// metric threshold value float metricThresholdValue; /// separate with semicolons flag bool separateWithSemicolonsFlag; }; #endif // __BRAIN_MODEL_SURFACE_ROI_METRIC_CLUSTER_REPORT_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceROIMetricClusterReport.cxx0000664000175000017500000001651111572067322030236 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainModelSurface.h" #include "BrainModelSurfaceMetricClustering.h" #include "BrainModelSurfaceROINodeSelection.h" #include "BrainModelSurfaceROIMetricClusterReport.h" #include "MetricFile.h" #include "SurfaceShapeFile.h" /** * Constructor. */ BrainModelSurfaceROIMetricClusterReport::BrainModelSurfaceROIMetricClusterReport( BrainSet* bs, BrainModelSurface* bmsIn, BrainModelSurfaceROINodeSelection* surfaceROIIn, MetricFile* metricOrShapeFileIn, const std::vector& columnSelectedFlagsIn, MetricFile* distortionMetricFileIn, const int distortionMetricFileColumnIn, const float metricThresholdValueIn, const bool separateWithSemicolonsFlagIn) : BrainModelSurfaceROIOperation(bs, bmsIn, surfaceROIIn) { metricFile = metricOrShapeFileIn; columnSelectedFlags = columnSelectedFlagsIn; distortionMetricFile = distortionMetricFileIn; distortionMetricFileColumn = distortionMetricFileColumnIn; metricThresholdValue = metricThresholdValueIn; separateWithSemicolonsFlag = separateWithSemicolonsFlagIn; } /** * destructor. */ BrainModelSurfaceROIMetricClusterReport::~BrainModelSurfaceROIMetricClusterReport() { } /** * execute the operation. */ void BrainModelSurfaceROIMetricClusterReport::executeOperation() throw (BrainModelAlgorithmException) { reportText = ""; QString fileTypeName("Metric"); if (dynamic_cast(metricFile) != NULL) { fileTypeName = "Shape"; } setHeaderText(fileTypeName + " Cluster Report"); const int numColumns = metricFile->getNumberOfColumns(); if (numColumns <= 0) { throw BrainModelAlgorithmException(fileTypeName + " file contains no data."); } QString separator(" "); if (separateWithSemicolonsFlag) { separator = ";"; } float roiArea = 0.0; createReportHeader(roiArea); const int numNodes = bms->getNumberOfNodes(); // // Report header // QString str = ("Threshold" + separator + "Column" + separator + "Num-Nodes" + separator + "Area " + separator + "Area Corrected" + separator + "COG-X" + separator + "COG-Y" + separator + "COG-Z" + "\n"); reportText.append(str); float posMin = 0.0; float posMax = 0.0; float negMin = 0.0; float negMax = 0.0; if (metricThresholdValue >= 0.0) { posMin = metricThresholdValue; posMax = std::numeric_limits::max(); negMin = -1.0; negMax = 0.0; } else { posMin = 1.0; posMax = 0.0; negMin = metricThresholdValue; negMax = -std::numeric_limits::max(); } // // Process each column // for (int i = 0; i < numColumns; i++) { // // Ignore deselected shape columns // if (columnSelectedFlags[i] == false) { continue; } // // Create a shape file containing just the single column // MetricFile tempMetricFile; tempMetricFile.setNumberOfNodesAndColumns(numNodes, 1); std::vector nodeValues; metricFile->getColumnForAllNodes(i, nodeValues); tempMetricFile.setColumnForAllNodes(0, nodeValues); // // Find the clusters // BrainModelSurfaceMetricClustering bmsmc(brainSet, bms, &tempMetricFile, BrainModelSurfaceMetricClustering::CLUSTER_ALGORITHM_MINIMUM_SURFACE_AREA, 0, 0, "cluster", 1, 0.001, negMin, negMax, posMin, posMax, true); try { bmsmc.execute(); } catch (BrainModelAlgorithmException& e) { throw BrainModelAlgorithmException(e.whatQString()); } // // Node areas // std::vector nodeAreas; bms->getAreaOfAllNodes(nodeAreas); // // Process the clusters // const int numClusters = bmsmc.getNumberOfClusters(); for (int j = 0; j < numClusters; j++) { const BrainModelSurfaceMetricClustering::Cluster* cluster = bmsmc.getCluster(j); const int numNodesInCluster = cluster->getNumberOfNodesInCluster(); // // Corrected area is sum of each node's area multiplied by // 2 to the power of the selected metric column for the node // float correctedArea = 0.0; if ((distortionMetricFileColumn >= 0) && (distortionMetricFile != NULL)) { for (int k = 0; k < numNodesInCluster; k++) { const int nodeNum = cluster->getNodeInCluster(k); float nodeArea = nodeAreas[nodeNum]; const double metric = distortionMetricFile->getValue(nodeNum, distortionMetricFileColumn); correctedArea += (nodeArea * std::pow(2.0, metric)); } } else { correctedArea = cluster->getArea(); } // // Add to the report // float cog[3]; cluster->getCenterOfGravity(cog); QString str = (QString::number(metricThresholdValue, 'f', 5) + separator + QString::number(i + 1) + separator + QString::number(numNodesInCluster) + separator + QString::number(cluster->getArea(), 'f', 5) + separator + QString::number(correctedArea, 'f', 5) + separator + QString::number(cog[0], 'f', 5) + separator + QString::number(cog[1], 'f', 5) + separator + QString::number(cog[2], 'f', 5) + "\n"); reportText.append(str); } } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceROIIntegratedFoldingIndexReport.h0000664000175000017500000000410111572067322031447 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_ROI_INTEGRATED_FOLDING_INDEX_REPORT_H__ #define __BRAIN_MODEL_SURFACE_ROI_INTEGRATED_FOLDING_INDEX_REPORT_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurfaceROIOperation.h" class SurfaceShapeFile; /// class for computing integrated folding index class BrainModelSurfaceROIIntegratedFoldingIndexReport : public BrainModelSurfaceROIOperation { public: // constructor BrainModelSurfaceROIIntegratedFoldingIndexReport(BrainSet* bs, BrainModelSurface* bmsIn, BrainModelSurfaceROINodeSelection* inputSurfaceROIIn, SurfaceShapeFile* surfaceShapeFileIn, const QString& headerTextIn, const bool semicolonSeparateReportFlagIn); // destructor ~BrainModelSurfaceROIIntegratedFoldingIndexReport(); protected: // execute the operation virtual void executeOperation() throw (BrainModelAlgorithmException); /// the surface shape file SurfaceShapeFile* surfaceShapeFile; /// semicolon separate the report bool semicolonSeparateReportFlag; }; #endif // __BRAIN_MODEL_SURFACE_ROI_INTEGRATED_FOLDING_INDEX_REPORT_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceROIIntegratedFoldingIndexReport.cxx0000664000175000017500000001210511572067322032025 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainModelSurface.h" #include "BrainModelSurfaceROIIntegratedFoldingIndexReport.h" #include "BrainModelSurfaceROINodeSelection.h" #include "StringUtilities.h" #include "SurfaceShapeFile.h" #include "TopologyFile.h" /** * constructor. */ BrainModelSurfaceROIIntegratedFoldingIndexReport::BrainModelSurfaceROIIntegratedFoldingIndexReport( BrainSet* bs, BrainModelSurface* bmsIn, BrainModelSurfaceROINodeSelection* inputSurfaceROIIn, SurfaceShapeFile* surfaceShapeFileIn, const QString& headerTextIn, const bool semicolonSeparateReportFlagIn) : BrainModelSurfaceROIOperation(bs, bmsIn, inputSurfaceROIIn) { surfaceShapeFile = surfaceShapeFileIn; semicolonSeparateReportFlag = semicolonSeparateReportFlagIn; setHeaderText(headerTextIn); } /** * destructor. */ BrainModelSurfaceROIIntegratedFoldingIndexReport::~BrainModelSurfaceROIIntegratedFoldingIndexReport() { } /** * execute the operation. */ void BrainModelSurfaceROIIntegratedFoldingIndexReport::executeOperation() throw (BrainModelAlgorithmException) { const int numColumns = surfaceShapeFile->getNumberOfColumns(); if (numColumns <= 0) { throw BrainModelAlgorithmException("No surface shape file contains no data."); } QString separator(""); if (semicolonSeparateReportFlag) { separator = ";"; } float roiArea = 0.0; createReportHeader(roiArea); TopologyFile* tf = bms->getTopologyFile(); if (tf != NULL) { std::vector areaTimesFoldingSum(numColumns, 0.0); const int numTriangles = tf->getNumberOfTiles(); for (int i = 0; i < numTriangles; i++) { if (tileInROI[i]) { int n1, n2, n3; tf->getTile(i, n1, n2, n3); for (int j = 0; j < numColumns; j++) { // // Average folding index is: // SUM(Ai * Abs(Fi)) / SUM(Ai); // // Ai = area of triangle (less if not all nodes in ROI) // Fi = average shape value of triangle's three nodes // SUM(Ai) is the same as the ROI's area // float shapeSum = 0.0; float numInROI = 0.0; if (operationSurfaceROI->getNodeSelected(n1)) { shapeSum += surfaceShapeFile->getValue(n1, j); numInROI += 1.0; } if (operationSurfaceROI->getNodeSelected(n2)) { shapeSum += surfaceShapeFile->getValue(n2, j); numInROI += 1.0; } if (operationSurfaceROI->getNodeSelected(n3)) { shapeSum += surfaceShapeFile->getValue(n3, j); numInROI += 1.0; } if (numInROI > 0.0) { const float averageShape = std::fabs(shapeSum) / numInROI; areaTimesFoldingSum[j] += averageShape * tileArea[i]; } } } } int longestColumnNameLength = 10; for (int j = 0; j < numColumns; j++) { longestColumnNameLength = std::max(longestColumnNameLength, static_cast(surfaceShapeFile->getColumnName(j).length())); } longestColumnNameLength += 5; QString s = StringUtilities::leftJustify("Name", longestColumnNameLength) + separator + StringUtilities::rightJustify("IFI", 12) + "\n"; reportText.append(s); for (int j = 0; j < numColumns; j++) { const float integratedFloatingIndex = areaTimesFoldingSum[j] / roiArea; QString s = StringUtilities::leftJustify(surfaceShapeFile->getColumnName(j), longestColumnNameLength) + separator + StringUtilities::rightJustify(QString::number(integratedFloatingIndex, 'f', 6), 12) + "\n"; reportText.append(s); } } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceROIFoldingMeasurementReport.h0000664000175000017500000001525011572067322030665 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_ROI_FOLDING_MEASUREMENT_REPORT_H__ #define __BRAIN_MODEL_SURFACE_ROI_FOLDING_MEASUREMENT_REPORT_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurfaceROIOperation.h" class BrainModelSurface; /// class for measuring folding on the surface class BrainModelSurfaceROIFoldingMeasurementReport : public BrainModelSurfaceROIOperation { public: // constructor BrainModelSurfaceROIFoldingMeasurementReport(BrainSet* bs, const BrainModelSurface* surfaceIn, const BrainModelSurfaceROINodeSelection* roiIn, const QString& headerTextIn, const bool semicolonSeparateReportFlagIn, const BrainModelSurface* hullSurfaceIn, const QString& metricFoldingMeasurementsFileNameIn); // destructor ~BrainModelSurfaceROIFoldingMeasurementReport(); // execute the operation void executeOperation() throw (BrainModelAlgorithmException); protected: /// curvatures measures on each node class NodeCurvatureMeasure { public: // constructor NodeCurvatureMeasure(); // destructor ~NodeCurvatureMeasure(); // set the measurements void setMeasurements(const float k1In, const float k2In); /// primary principal curvature float k1; /// secondary principal curvature float k2; /// mean curvature float H; /// gaussian curvature float K; /// positive mean curvature float Hplus; /// negative mean curvature float Hminus; /// positive gaussian curvature float Kplus; /// negative gaussian curvature float Kminus; /// surface area measure of positive mean curvature float HplusAreaMeasure; /// surface area measure of negative mean curvature float HminusAreaMeasure; /// surface area measure of positive gaussian curvature float KplusAreaMeasure; /// surface area measure of negative gaussian curvature float KminusAreaMeasure; /// curvedness index float ci; /// shape index float si; /// folding index float fi; }; /// Folding Measurements class FoldingMeasurements { public: // constructor FoldingMeasurements(); // destructor ~FoldingMeasurements(); // add folding measurements for a tile void addTileFolding(const BrainModelSurfaceROINodeSelection* roi, const float tileFullArea, const int tileNodes[3], const std::vector& nodeCurvatures); // finalize the measurements void finalizeMeasurements(const float roiSurfaceArea); // Intrinsic Curvature Index float ICI; // Negative Intrinsic Curvature Index float NICI; // Gaussian L2 Norm float GLN; // Absolute ICI float AICI; // Mean Curvature Index float MCI; // Negative Mean Curavture Index float NMCI; // Mean L2 Norm float MLN; // Absolute Mean Curvature Index float AMCI; // Folding Index float FI; // Curvedness Index float CI; // Shape Index float SI; // Area Fraction of Intrinsic Curvature Index float FICI; // Area Fraction of Negative Intrinsic Curvature Index float FNICI; // Area Fraction of Mean Curvature Index float FMCI; // Area Fraction of Negative Mean Curvature Index float FNMCI; // SH2SH float SH2SH; // SK2SK float SK2SK; // total area of the ROI float roiTotalArea; }; // compute the node curvature measurements void computeNodeCurvatureMeasurements(std::vector& cm) throw (BrainModelAlgorithmException); // create a metric file containing the folding measurements per node void computeMetricFoldingMeasurementsFile(const std::vector& cm, const BrainModelSurfaceROINodeSelection* roi) throw (BrainModelAlgorithmException); /// the cerebral hull surface const BrainModelSurface* hullSurface; /// semicolon separate the report bool semicolonSeparateReportFlag; /// If not empty, create a metric file with folding measurements per node QString metricFoldingMeasurementsFileName; }; #endif // __BRAIN_MODEL_SURFACE_ROI_FOLDING_MEASUREMENT_REPORT_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceROIFoldingMeasurementReport.cxx0000664000175000017500000005563411572067322031252 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelSurface.h" #include "BrainModelSurfaceCurvature.h" #include "BrainModelSurfaceROIFoldingMeasurementReport.h" #include "BrainModelSurfaceROINodeSelection.h" #include "StringUtilities.h" #include "SurfaceShapeFile.h" #include "TopologyFile.h" /** * constructor. */ BrainModelSurfaceROIFoldingMeasurementReport::BrainModelSurfaceROIFoldingMeasurementReport( BrainSet* bs, const BrainModelSurface* surfaceIn, const BrainModelSurfaceROINodeSelection* roiIn, const QString& headerTextIn, const bool semicolonSeparateReportFlagIn, const BrainModelSurface* hullSurfaceIn, const QString& metricFoldingMeasurementsFileNameIn) : BrainModelSurfaceROIOperation(bs, surfaceIn, roiIn), hullSurface(hullSurfaceIn), semicolonSeparateReportFlag(semicolonSeparateReportFlagIn), metricFoldingMeasurementsFileName(metricFoldingMeasurementsFileNameIn) { setHeaderText(headerTextIn); } /** * destructor. */ BrainModelSurfaceROIFoldingMeasurementReport::~BrainModelSurfaceROIFoldingMeasurementReport() { } /** * execute the operation. */ void BrainModelSurfaceROIFoldingMeasurementReport::executeOperation() throw (BrainModelAlgorithmException) { // // Compute the numerous curvatures measurements for each node // std::vector cm; computeNodeCurvatureMeasurements(cm); // // Start creating the report // QString separator(""); if (semicolonSeparateReportFlag) { separator = ";"; } float roiArea = 0.0; createReportHeader(roiArea); // // Start creating the surface's folding measurements // FoldingMeasurements surfaceFoldingMeasurements; // // Loop through the triangles // TopologyFile* tf = bms->getTopologyFile(); const int numTriangles = tf->getNumberOfTiles(); for (int i = 0; i < numTriangles; i++) { // // Is the triangle in the ROI ? // if (tileInROI[i]) { // // Get the nodes in the triangle // int n[3]; tf->getTile(i, n); // // Compute and add tiles measurements to the surface's folding measurements // surfaceFoldingMeasurements.addTileFolding(operationSurfaceROI, tileArea[i], n, cm); } } // // Finish the surface measurements // surfaceFoldingMeasurements.finalizeMeasurements(roiArea); const int textLen = 45; const int numLen = 14; // // Create the remainder of the report // reportText.append(QString("Intrinsic Curvature Index (ICI)").leftJustified(textLen, ' ') + QString::number(surfaceFoldingMeasurements.ICI, 'f', 5).rightJustified( numLen, ' ') + "\n"); reportText.append(QString("Negative Intrinsic Curvature Index (NICI)").leftJustified(textLen, ' ') + QString::number(surfaceFoldingMeasurements.NICI, 'f', 5).rightJustified( numLen, ' ') + "\n"); reportText.append(QString("Gaussian L2 Norm (GLN)").leftJustified(textLen, ' ') + QString::number(surfaceFoldingMeasurements.GLN, 'f', 5).rightJustified( numLen, ' ') + "\n"); reportText.append(QString("Absolute Intrinsic Curvature Index (AICI)").leftJustified(textLen, ' ') + QString::number(surfaceFoldingMeasurements.AICI, 'f', 5).rightJustified( numLen, ' ') + "\n"); reportText.append(QString("Mean Curvature Index (MCI)").leftJustified(textLen, ' ') + QString::number(surfaceFoldingMeasurements.MCI, 'f', 5).rightJustified( numLen, ' ') + "\n"); reportText.append(QString("Negative Mean Curvature Index (NMCI)").leftJustified(textLen, ' ') + QString::number(surfaceFoldingMeasurements.NMCI, 'f', 5).rightJustified( numLen, ' ') + "\n"); reportText.append(QString("Mean L2 Form (MLN)").leftJustified(textLen, ' ') + QString::number(surfaceFoldingMeasurements.MLN, 'f', 5).rightJustified( numLen, ' ') + "\n"); reportText.append(QString("Absolute Mean Curvature Index (AMCI)").leftJustified(textLen, ' ') + QString::number(surfaceFoldingMeasurements.AMCI, 'f', 5).rightJustified( numLen, ' ') + "\n"); reportText.append(QString("Folding Index (FI)").leftJustified(textLen, ' ') + QString::number(surfaceFoldingMeasurements.FI, 'f', 5).rightJustified( numLen, ' ') + "\n"); reportText.append(QString("Curvedness Index (CI)").leftJustified(textLen, ' ') + QString::number(surfaceFoldingMeasurements.CI, 'f', 5).rightJustified( numLen, ' ') + "\n"); reportText.append(QString("Shape Index (SI)").leftJustified(textLen, ' ') + QString::number(surfaceFoldingMeasurements.SI, 'f', 5).rightJustified( numLen, ' ') + "\n"); reportText.append(QString("Area Fraction of ICI (FICI)").leftJustified(textLen, ' ') + QString::number(surfaceFoldingMeasurements.FICI, 'f', 5).rightJustified( numLen, ' ') + "\n"); reportText.append(QString("Area Fraction Negative ICI (FICI)").leftJustified(textLen, ' ') + QString::number(surfaceFoldingMeasurements.FNICI, 'f', 5).rightJustified( numLen, ' ') + "\n"); reportText.append(QString("Area Fraction of MCI (FMCI)").leftJustified(textLen, ' ') + QString::number(surfaceFoldingMeasurements.FMCI, 'f', 5).rightJustified( numLen, ' ') + "\n"); reportText.append(QString("Area Fraction of Neg MCI (FNMCI)").leftJustified(textLen, ' ') + QString::number(surfaceFoldingMeasurements.FNMCI, 'f', 5).rightJustified( numLen, ' ') + "\n"); reportText.append(QString("SH2SH").leftJustified(textLen, ' ') + QString::number(surfaceFoldingMeasurements.SH2SH, 'f', 5).rightJustified( numLen, ' ') + "\n"); reportText.append(QString("SK2SK").leftJustified(textLen, ' ') + QString::number(surfaceFoldingMeasurements.SK2SK, 'f', 5).rightJustified( numLen, ' ') + "\n"); /* reportText.append(QString("").leftJustified(textLen, ' ') + QString::number(surfaceFoldingMeasurements., 'f', 5).leftJustified( numLen, ' ') + "\n"); int longestColumnNameLength = 10; for (int j = 0; j < numColumns; j++) { longestColumnNameLength = std::max(longestColumnNameLength, static_cast(surfaceShapeFile->getColumnName(j).length())); } longestColumnNameLength += 5; QString s = StringUtilities::leftJustify("Name", longestColumnNameLength) + separator + StringUtilities::rightJustify("IFI", 12) + "\n"; reportText.append(s); for (int j = 0; j < numColumns; j++) { const float integratedFloatingIndex = areaTimesFoldingSum[j] / roiArea; QString s = StringUtilities::leftJustify(surfaceShapeFile->getColumnName(j), longestColumnNameLength) + separator + StringUtilities::rightJustify(QString::number(integratedFloatingIndex, 'f', 6), 12) + "\n"; reportText.append(s); } */ computeMetricFoldingMeasurementsFile(cm, operationSurfaceROI); } /* * compute the node curvature measurements. */ void BrainModelSurfaceROIFoldingMeasurementReport::computeNodeCurvatureMeasurements(std::vector& cm) throw (BrainModelAlgorithmException) { // // Get principal curvatures // SurfaceShapeFile curvatureShapeFile; BrainModelSurfaceCurvature curvatures(brainSet, bms, &curvatureShapeFile, -1, -1, SurfaceShapeFile::meanCurvatureColumnName, SurfaceShapeFile::gaussianCurvatureColumnName, true); curvatures.execute(); const int k1ShapeColumn = curvatures.getKMaxColumnNumber(); const int k2ShapeColumn = curvatures.getKMinColumnNumber(); if (k1ShapeColumn < 0) { throw new BrainModelAlgorithmException("K1 Curvature failed."); } if (k2ShapeColumn < 0) { throw new BrainModelAlgorithmException("K2 Curvature failed."); } // // Set the curvature measurements for each node // const int numNodes = curvatureShapeFile.getNumberOfNodes(); cm.resize(numNodes); for (int i = 0; i < numNodes; i++) { cm[i].setMeasurements(curvatureShapeFile.getValue(i, k1ShapeColumn), curvatureShapeFile.getValue(i, k2ShapeColumn)); } } void BrainModelSurfaceROIFoldingMeasurementReport::computeMetricFoldingMeasurementsFile( const std::vector& cm, const BrainModelSurfaceROINodeSelection* roi) throw (BrainModelAlgorithmException) { if (metricFoldingMeasurementsFileName.isEmpty()) { return; } int numNodes = this->bms->getNumberOfNodes(); int numColumns = 0; const int COLUMN_K1 = numColumns++; const int COLUMN_K2 = numColumns++; const int COLUMN_MEAN = numColumns++; const int COLUMN_GAUSS = numColumns++; const int COLUMN_ICI = numColumns++; const int COLUMN_NICI = numColumns++; const int COLUMN_GLN = numColumns++; const int COLUMN_AICI = numColumns++; const int COLUMN_MCI = numColumns++; const int COLUMN_NMCI = numColumns++; const int COLUMN_MLN = numColumns++; const int COLUMN_AMCI = numColumns++; const int COLUMN_FI = numColumns++; const int COLUMN_CI = numColumns++; const int COLUMN_SI = numColumns++; const int COLUMN_FICI = numColumns++; const int COLUMN_FNICI = numColumns++; const int COLUMN_FMCI = numColumns++; const int COLUMN_FNMCI = numColumns++; const int COLUMN_SH2SH = numColumns++; const int COLUMN_SK2SK = numColumns++; const int COLUMN_SURFACE_AREA = numColumns++; MetricFile mf; mf.setNumberOfNodesAndColumns(numNodes, numColumns); mf.setColumnName(COLUMN_K1, "K1"); mf.setColumnComment(COLUMN_K1, ""); mf.setColumnName(COLUMN_K2, "K2"); mf.setColumnComment(COLUMN_K2, ""); mf.setColumnName(COLUMN_MEAN, "Mean"); mf.setColumnComment(COLUMN_MEAN, ""); mf.setColumnName(COLUMN_GAUSS, "GAUSS"); mf.setColumnComment(COLUMN_GAUSS, ""); mf.setColumnName(COLUMN_ICI, "ICI (Intrinsic Curvature Index)"); mf.setColumnComment(COLUMN_ICI, ""); mf.setColumnName(COLUMN_NICI, "NICI (Negative Intrinsic Curvature Index)"); mf.setColumnComment(COLUMN_NICI, ""); mf.setColumnName(COLUMN_GLN, "GLN (Gaussian L2 Norm)"); mf.setColumnComment(COLUMN_GLN, ""); mf.setColumnName(COLUMN_AICI, "AICI (Absolute Intrinsic Curvature Index)"); mf.setColumnComment(COLUMN_AICI, ""); mf.setColumnName(COLUMN_MCI, "MCI (Mean Curvature Index)"); mf.setColumnComment(COLUMN_MCI, ""); mf.setColumnName(COLUMN_NMCI, "NMCI (Negative Mean Curvature Index)"); mf.setColumnComment(COLUMN_NMCI, ""); mf.setColumnName(COLUMN_MLN, "MLN (Mean L2 Form)"); mf.setColumnComment(COLUMN_MLN, ""); mf.setColumnName(COLUMN_AMCI, "AMCI (Absolute Mean Curvature Index)"); mf.setColumnComment(COLUMN_AMCI, ""); mf.setColumnName(COLUMN_FI, "FI (Folding Index)"); mf.setColumnComment(COLUMN_FI, ""); mf.setColumnName(COLUMN_CI, "CI (Curvedness Index)"); mf.setColumnComment(COLUMN_CI, ""); mf.setColumnName(COLUMN_SI, "SI (Shape Index)"); mf.setColumnComment(COLUMN_SI, ""); mf.setColumnName(COLUMN_FICI, "FICI (Area Fraction of ICI)"); mf.setColumnComment(COLUMN_FICI, ""); mf.setColumnName(COLUMN_FNICI, "FNICI (Area Fraction of Negative ICI)"); mf.setColumnComment(COLUMN_FNICI, ""); mf.setColumnName(COLUMN_FMCI, "FMCI (Area Fraction of MCI)"); mf.setColumnComment(COLUMN_FMCI, ""); mf.setColumnName(COLUMN_FNMCI, "FNMCI (Area Fraction of Negative MCI)"); mf.setColumnComment(COLUMN_FNMCI, ""); mf.setColumnName(COLUMN_SH2SH, "SH2SH"); mf.setColumnComment(COLUMN_SH2SH, ""); mf.setColumnName(COLUMN_SK2SK, "SK2SK"); mf.setColumnComment(COLUMN_SK2SK, ""); mf.setColumnName(COLUMN_SURFACE_AREA, "Surface Area"); mf.setColumnComment(COLUMN_SURFACE_AREA, ""); std::vector nodeAreas; this->bms->getAreaOfAllNodes(nodeAreas); for (int i = 0; i < numNodes; i++) { if (roi->getNodeSelected(i)) { // // Add in partial amounts // const NodeCurvatureMeasure ncm = cm[i]; float ici = ncm.Kplus; float nici = ncm.Kminus; float gln = (ncm.K * ncm.K); float aici = std::fabs(ncm.K); float mci = ncm.Hplus; float nmci = ncm.Hminus; float mln = (ncm.H * ncm.H); float amci = std::fabs(ncm.H); float fi = ncm.fi; float ci = ncm.ci; float si = std::fabs(ncm.si); float fici = ncm.KplusAreaMeasure; float fnici = ncm.KminusAreaMeasure; float fmci = ncm.HplusAreaMeasure; float fnmci = ncm.HminusAreaMeasure; float sh2sh = 0.0; if (amci != 0.0) { sh2sh = mln / amci; } float sk2sk = 0.0; if (aici != 0.0) { sk2sk = gln / aici; } mf.setValue(i, COLUMN_K1, ncm.k1); mf.setValue(i, COLUMN_K2, ncm.k2); mf.setValue(i, COLUMN_MEAN, ncm.H); mf.setValue(i, COLUMN_GAUSS, ncm.K); mf.setValue(i, COLUMN_ICI, ici); mf.setValue(i, COLUMN_NICI, nici); mf.setValue(i, COLUMN_GLN, gln); mf.setValue(i, COLUMN_AICI, aici); mf.setValue(i, COLUMN_MCI, mci); mf.setValue(i, COLUMN_NMCI, nmci); mf.setValue(i, COLUMN_MLN, mln); mf.setValue(i, COLUMN_AMCI, amci); mf.setValue(i, COLUMN_FI, fi); mf.setValue(i, COLUMN_CI, ci); mf.setValue(i, COLUMN_SI, si); mf.setValue(i, COLUMN_FICI, fici); mf.setValue(i, COLUMN_FNICI,fnici); mf.setValue(i, COLUMN_FMCI, fmci); mf.setValue(i, COLUMN_FNMCI, fnmci); mf.setValue(i, COLUMN_SH2SH, sh2sh); mf.setValue(i, COLUMN_SK2SK, sk2sk); mf.setValue(i, COLUMN_SURFACE_AREA, nodeAreas[i]); } } for (int i = 0; i < numColumns; i++) { float minValue, maxValue; mf.getDataColumnMinMax(i, minValue, maxValue); //ssf.setColumnColorMappingMinMax(i, minValue, maxValue); } try { mf.writeFile(metricFoldingMeasurementsFileName); } catch (FileException& e) { throw BrainModelAlgorithmException("Writing Metric Folding Indices File: " + e.whatQString()); } } // //============================================================================== //============================================================================== //============================================================================== // /** * constructor. */ BrainModelSurfaceROIFoldingMeasurementReport::NodeCurvatureMeasure::NodeCurvatureMeasure() { } /** * destructor. */ BrainModelSurfaceROIFoldingMeasurementReport::NodeCurvatureMeasure::~NodeCurvatureMeasure() { } /** * Set the measurements. */ void BrainModelSurfaceROIFoldingMeasurementReport::NodeCurvatureMeasure::setMeasurements( const float k1In, const float k2In) { k1 = k1In; k2 = k2In; H = (k1 + k2) / 2.0; K = (k1 * k2); Hplus = ((H > 0.0) ? H : 0.0); Hminus = ((H < 0.0) ? H : 0.0); Kplus = ((K > 0.0) ? K : 0.0); Kminus = ((K < 0.0) ? K : 0.0); HplusAreaMeasure = ((H > 0.0) ? 1.0 : 0.0); HminusAreaMeasure = ((H < 0.0) ? 1.0 : 0.0); KplusAreaMeasure = ((K > 0.0) ? 1.0 : 0.0); KminusAreaMeasure = ((K < 0.0) ? 1.0 : 0.0); ci = std::sqrt((k1*k1 + k2*k2) / 2.0); si = (2.0 / M_PI) * std::atan2((k1 + k2), (k1 - k2)); fi = std::fabs(k1) * (std::fabs(k1) - std::fabs(k2)); } // //============================================================================== //============================================================================== //============================================================================== // /** * constructor. */ BrainModelSurfaceROIFoldingMeasurementReport::FoldingMeasurements::FoldingMeasurements() { ICI = 0.0; NICI = 0.0; GLN = 0.0; AICI = 0.0; MCI = 0.0; NMCI = 0.0; MLN = 0.0; AMCI = 0.0; FI = 0.0; CI = 0.0; SI = 0.0; FICI = 0.0; FNICI = 0.0; FMCI = 0.0; FNMCI = 0.0; SH2SH = 0.0; SK2SK = 0.0; roiTotalArea = 0.0; } /** * destructor. */ BrainModelSurfaceROIFoldingMeasurementReport::FoldingMeasurements::~FoldingMeasurements() { } /** * add folding measurements for a tile. */ void BrainModelSurfaceROIFoldingMeasurementReport::FoldingMeasurements::addTileFolding( const BrainModelSurfaceROINodeSelection* roi, const float tileFullArea, const int tileNodes[3], const std::vector& nodeCurvatures) { const float oneThird = 1.0 / 3.0; float ici = 0.0; float nici = 0.0; float gln = 0.0; float aici = 0.0; float mci = 0.0; float nmci = 0.0; float mln = 0.0; float amci = 0.0; float fi = 0.0; float ci = 0.0; float si = 0.0; float fici = 0.0; float fnici = 0.0; float fmci = 0.0; float fnmci = 0.0; float oneThirdTileArea = tileFullArea * oneThird; float tileAreaUsed = 0.0; // // Loop through nodes of tile // bool nodeUsedFlag = false; for (int n = 0; n < 3; n++) { const int nodeNumber = tileNodes[n]; if (roi->getNodeSelected(nodeNumber)) { // // Add in partial amounts // const NodeCurvatureMeasure ncm = nodeCurvatures[nodeNumber]; ici += ncm.Kplus * oneThird; nici += ncm.Kminus * oneThird; gln += (ncm.K * ncm.K) * oneThird; aici += std::fabs(ncm.K) * oneThird; mci += ncm.Hplus * oneThird; nmci += ncm.Hminus * oneThird; mln += (ncm.H * ncm.H) * oneThird; amci += std::fabs(ncm.H) * oneThird; fi += ncm.fi * oneThird; ci += ncm.ci * oneThird; si += std::fabs(ncm.si) * oneThird; fici += ncm.KplusAreaMeasure * oneThird; fnici += ncm.KminusAreaMeasure * oneThird; fmci += ncm.HplusAreaMeasure * oneThird; fnmci += ncm.HminusAreaMeasure * oneThird; // // Each node uses approximately one third of the tile // tileAreaUsed += oneThirdTileArea; nodeUsedFlag = true; } } // // Was the tile in the ROI // if (nodeUsedFlag) { ICI += ici * tileAreaUsed; NICI += nici * tileAreaUsed; GLN += gln * tileAreaUsed; AICI += aici * tileAreaUsed; MCI += mci * tileAreaUsed; NMCI += nmci * tileAreaUsed; MLN += mln * tileAreaUsed; AMCI += amci * tileAreaUsed; FI += fi * tileAreaUsed; CI += ci * tileAreaUsed; SI += si * tileAreaUsed; FICI += fici * tileAreaUsed; FNICI += fnici * tileAreaUsed; FMCI += fmci * tileAreaUsed; FNMCI += fnmci * tileAreaUsed; roiTotalArea += tileAreaUsed; } } /** * finalize the measurements. */ void BrainModelSurfaceROIFoldingMeasurementReport::FoldingMeasurements::finalizeMeasurements( const float roiSurfaceArea) { ICI /= roiSurfaceArea; NICI /= roiSurfaceArea; GLN /= roiSurfaceArea; AICI /= roiSurfaceArea; MCI /= roiSurfaceArea; NMCI /= roiSurfaceArea; MLN /= roiSurfaceArea; AMCI /= roiSurfaceArea; FI /= roiSurfaceArea; CI /= roiSurfaceArea; SI /= roiSurfaceArea; FICI /= roiSurfaceArea; FNICI /= roiSurfaceArea; FMCI /= roiSurfaceArea; FNMCI /= roiSurfaceArea; if (AMCI != 0.0) { SH2SH = MLN / AMCI; } if (AICI != 0.0) { SK2SK = GLN/AICI; } //std::cout << "ROI area: " << roiTotalArea << std::endl; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceROICreateBorderUsingMetricShape.h0000664000175000017500000000630111572067322031372 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_ROI_CREATE_BORDER_USING_METRIC_SHAPE_H__ #define __BRAIN_MODEL_SURFACE_ROI_CREATE_BORDER_USING_METRIC_SHAPE_H__ #include "BrainModelAlgorithm.h" /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BorderFile.h" #include "BrainModelSurfaceROIOperation.h" class BrainModelSurface; class BrainModelSurfaceROINodeSelection; class MetricFile; /// class for drawing roughly linear borders along nods with metric or shape values class BrainModelSurfaceROICreateBorderUsingMetricShape : public BrainModelSurfaceROIOperation { public: /// mode enum MODE { /// follow nodes with most negative values MODE_FOLLOW_MOST_NEGATIVE, /// follow nodes with most positive values MODE_FOLLOW_MOST_POSITIVE }; // constructor BrainModelSurfaceROICreateBorderUsingMetricShape(BrainSet* bs, const BrainModelSurface* bmsIn, const BrainModelSurfaceROINodeSelection* surfaceROIIn, const MODE modeIn, const MetricFile* metricFileIn, const int metricColumnNumberIn, const QString& borderNameIn, const int startNodeIn, const int endNodeIn, const float samplingDensityIn); // destructor ~BrainModelSurfaceROICreateBorderUsingMetricShape(); // execute the operation void executeOperation() throw (BrainModelAlgorithmException); // get the border that was created by create border mode Border getBorder() const; protected: /// mode for search const MODE mode; /// metric file const MetricFile* metricFile; /// metric column number const int metricColumnNumber; /// name for border const QString borderName; /// border start node const int borderStartNode; /// border end node const int borderEndNode; /// border sampling density const float borderSamplingDensity; /// border created Border border; }; #endif // __BRAIN_MODEL_SURFACE_ROI_CREATE_BORDER_USING_METRIC_SHAPE_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceROICreateBorderUsingMetricShape.cxx0000664000175000017500000004331511572067322031753 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include "BrainModelSurface.h" #include "BrainModelSurfaceROICreateBorderUsingMetricShape.h" #include "BrainModelSurfaceROINodeSelection.h" #include "BrainSet.h" #include "CoordinateFile.h" #include "DebugControl.h" #include "FileUtilities.h" #include "MathUtilities.h" #include "MetricFile.h" #include "TopologyFile.h" #include "TopologyHelper.h" /** * constructor. It is best to use a "lightly folded" surface such as a * very inflated surface or and ellipsoid surface. When finding the path, * the distance from the next node to the end node must be less than the * distance from the current node to the end node. When the surface is * highly folded, it may be necessary to move away from the end node * which will cause the algorithm to fail. */ BrainModelSurfaceROICreateBorderUsingMetricShape::BrainModelSurfaceROICreateBorderUsingMetricShape( BrainSet* bs, const BrainModelSurface* bmsIn, const BrainModelSurfaceROINodeSelection* surfaceROIIn, const MODE modeIn, const MetricFile* metricFileIn, const int metricColumnNumberIn, const QString& borderNameIn, const int startNodeIn, const int endNodeIn, const float samplingDensityIn) : BrainModelSurfaceROIOperation(bs, bmsIn, surfaceROIIn), mode(modeIn), metricFile(metricFileIn), metricColumnNumber(metricColumnNumberIn), borderName(borderNameIn), borderStartNode(startNodeIn), borderEndNode(endNodeIn), borderSamplingDensity(samplingDensityIn) { } /** * destructor. */ BrainModelSurfaceROICreateBorderUsingMetricShape::~BrainModelSurfaceROICreateBorderUsingMetricShape() { } /** * execute the operation. */ void BrainModelSurfaceROICreateBorderUsingMetricShape::executeOperation() throw (BrainModelAlgorithmException) { if (borderName.isEmpty()) { throw BrainModelAlgorithmException("Name for border is empty."); } BrainModelSurfaceROINodeSelection theROI(*operationSurfaceROI); const int numNodesInROI = theROI.getNumberOfNodesSelected(); if (numNodesInROI == 1) { throw BrainModelAlgorithmException("There is only one node, the starting node, in the ROI " " for border named " + borderName); } const int numNodes = bms->getNumberOfNodes(); const CoordinateFile* cf = bms->getCoordinateFile(); border.clearLinks(); // // Check Inputs // if (metricFile == NULL) { throw BrainModelAlgorithmException("Metric/Shape file is invalid for border named " + borderName); } if ((metricColumnNumber < 0) || (metricColumnNumber >= metricFile->getNumberOfColumns())) { throw BrainModelAlgorithmException("Metric/Shape file column number is invalid for border named " + borderName); } if ((borderStartNode < 0) || (borderStartNode >= numNodes)) { throw BrainModelAlgorithmException("Starting node is invalid for border named " + borderName); } if ((borderEndNode < 0) || (borderEndNode >= numNodes)) { throw BrainModelAlgorithmException("Ending node is invalid for border named " + borderName); } if (borderStartNode == borderEndNode) { throw BrainModelAlgorithmException("Starting and ending node are the same for border named " + borderName); } if (theROI.getNodeSelected(borderStartNode) == false) { throw BrainModelAlgorithmException("Starting node is not in the ROI for border named " + borderName); } if (theROI.getNodeSelected(borderEndNode) == false) { throw BrainModelAlgorithmException("Ending node is not in the ROI for border named " + borderName); } // // Get a topology helper // const TopologyFile* tf = bms->getTopologyFile(); const TopologyHelper* th = tf->getTopologyHelper(false, true, false); // // Use a deque (double ended queue) for tracking nodes in path // std::deque borderPathNodes; borderPathNodes.push_back(borderStartNode); // // Keep track of nodes added to ROI (used for fast indexing) // std::vector nodeVisitedFlags(numNodes, 0); nodeVisitedFlags[borderStartNode] = 1; // // Coordinate of ending node // const float* endXYZ = cf->getCoordinate(borderEndNode); // // Loop until path from starting to ending nodes is found // int currentNode = borderStartNode; int lastDilatedNode = -1; bool done = false; while (done == false) { // // Get neighbors of current node // int numNeighbors = 0; const int* neighbors = th->getNodeNeighbors(currentNode, numNeighbors); // // see if any neighbor is the ending node // for (int i = 0; i < numNeighbors; i++) { if (neighbors[i] == borderEndNode) { borderPathNodes.push_back(borderEndNode); done = true; break; } } // // Need to search neighbors // if (done == false) { // // Find distance from current node to ending node // const float currentNodeDistanceToEndingNode = MathUtilities::distanceSquared3D(cf->getCoordinate(currentNode), endXYZ); // // Next node for border // int nextNode = -1; float nextNodeMetricValue = 0.0; switch (mode) { case MODE_FOLLOW_MOST_NEGATIVE: nextNodeMetricValue = std::numeric_limits::max(); break; case MODE_FOLLOW_MOST_POSITIVE: nextNodeMetricValue = -std::numeric_limits::max(); break; } // // Loop through neighbors // for (int i = 0; i < numNeighbors; i++) { const int neighborNode = neighbors[i]; // // Is node in the ROI // if (theROI.getNodeSelected(neighborNode) && (nodeVisitedFlags[neighborNode] == 0)) { // // Is distance from neighbor to end node closer than distance // form current node to end node // const float distance = MathUtilities::distanceSquared3D(cf->getCoordinate(neighborNode), endXYZ); if (distance < currentNodeDistanceToEndingNode) { // // Is metric value the most positive or negative // const float metricValue = metricFile->getValue(neighborNode, metricColumnNumber); if (nextNode < 0) { nextNode = neighborNode; nextNodeMetricValue = metricValue; } else { switch (mode) { case MODE_FOLLOW_MOST_NEGATIVE: if (metricValue < nextNodeMetricValue) { nextNode = neighborNode; nextNodeMetricValue = metricValue; } break; case MODE_FOLLOW_MOST_POSITIVE: if (metricValue > nextNodeMetricValue) { nextNode = neighborNode; nextNodeMetricValue = metricValue; } break; } } } // if } } // for // // If no neighbor in ROI is closer to end node than current node // if (nextNode < 0) { // // Move to neighbor that is closest to end node even if that // means moving away from the end // float nearestDistance = std::numeric_limits::max(); for (int i = 0; i < numNeighbors; i++) { const int neighborNode = neighbors[i]; // // Is node in the ROI // if (theROI.getNodeSelected(neighborNode) && (nodeVisitedFlags[neighborNode] == 0)) { // // Is distance from neighbor than other neighbors // const float distance = MathUtilities::distanceSquared3D(cf->getCoordinate(neighborNode), endXYZ); if (distance < nearestDistance) { nearestDistance = distance; nextNode = neighborNode; } } } } if (nextNode >= 0) { currentNode = nextNode; borderPathNodes.push_back(currentNode); lastDilatedNode = -1; nodeVisitedFlags[currentNode] = 1; } /* else if (borderPathNodes.size() > 1) { // // Since cannot move closer to end, back up one node // and remove current node from ROI // theROI.setNodeSelected(currentNode, false); if (currentNode != borderPathNodes.back()) { std::cout << "ERROR back() is not current node." << std::endl; } borderPathNodes.pop_back(); currentNode = borderPathNodes.back(); } */ else if (currentNode != lastDilatedNode) { // // Put neighbors in ROI and try again // theROI.dilateAroundNode(bms, currentNode); lastDilatedNode = currentNode; } else { throw BrainModelAlgorithmException( "Create Metric/Shape Border: unable to complete path from node " + QString::number(borderStartNode) + " to node " + QString::number(borderEndNode) + ". Stuck at node " + QString::number(currentNode) + " for border named " + borderName); } } } // // Name and add nodes to the border // border.clearLinks(); const int numNodesInPath = static_cast(borderPathNodes.size()); for (int j = 0; j < numNodesInPath; j++) { border.addBorderLink(cf->getCoordinate(borderPathNodes[j])); } border.setName(borderName); } /* 18apr2008 void BrainModelSurfaceROICreateBorderUsingMetricShape::executeOperation() throw (BrainModelAlgorithmException) { if (borderName.isEmpty()) { throw BrainModelAlgorithmException("Name for border is empty."); } const int numNodesInROI = theROI->getNumberOfNodesSelected(); if (numNodesInROI == 1) { throw BrainModelAlgorithmException("There is only one node, the starting node, in the ROI " " for border named " + borderName); } const int numNodes = bms->getNumberOfNodes(); const CoordinateFile* cf = bms->getCoordinateFile(); border.clearLinks(); // // Check Inputs // if (metricFile == NULL) { throw BrainModelAlgorithmException("Metric/Shape file is invalid for border named " + borderName); } if ((metricColumnNumber < 0) || (metricColumnNumber >= metricFile->getNumberOfColumns())) { throw BrainModelAlgorithmException("Metric/Shape file column number is invalid for border named " + borderName); } if ((borderStartNode < 0) || (borderStartNode >= numNodes)) { throw BrainModelAlgorithmException("Starting node is invalid for border named " + borderName); } if ((borderEndNode < 0) || (borderEndNode >= numNodes)) { throw BrainModelAlgorithmException("Ending node is invalid for border named " + borderName); } if (borderStartNode == borderEndNode) { throw BrainModelAlgorithmException("Starting and ending node are the same for border named " + borderName); } if (operationSurfaceROI->getNodeSelected(borderStartNode) == false) { throw BrainModelAlgorithmException("Starting node is not in the ROI for border named " + borderName); } if (operationSurfaceROI->getNodeSelected(borderEndNode) == false) { throw BrainModelAlgorithmException("Ending node is not in the ROI for border named " + borderName); } // // Get a topology helper // const TopologyFile* tf = bms->getTopologyFile(); const TopologyHelper* th = tf->getTopologyHelper(false, true, false); // // Beginning of border // border.addBorderLink(cf->getCoordinate(borderStartNode)); // // Coordinate of ending node // const float* endXYZ = cf->getCoordinate(borderEndNode); // // Loop until path from starting to ending nodes is found // int currentNode = borderStartNode; bool done = false; while (done == false) { // // Get neighbors of current node // int numNeighbors = 0; const int* neighbors = th->getNodeNeighbors(currentNode, numNeighbors); // // see if any neighbors is the ending node // for (int i = 0; i < numNeighbors; i++) { if (neighbors[i] == borderEndNode) { border.addBorderLink(endXYZ); done = true; break; } } // // Need to search neighbors // if (done == false) { // // Find distance from current node to ending node // const float currentNodeDistanceToEndingNode = MathUtilities::distanceSquared3D(cf->getCoordinate(currentNode), endXYZ); // // Next node for border // int nextNode = -1; float nextNodeMetricValue = 0.0; switch (mode) { case MODE_FOLLOW_MOST_NEGATIVE: nextNodeMetricValue = std::numeric_limits::max(); break; case MODE_FOLLOW_MOST_POSITIVE: nextNodeMetricValue = -std::numeric_limits::max(); break; } // // Loop through neighbors // for (int i = 0; i < numNeighbors; i++) { const int neighborNode = neighbors[i]; // // Is node in the ROI // if (operationSurfaceROI->getNodeSelected(neighborNode)) { // // Is distance from neighbor to end node closer than distance // form current node to end node // const float distance = MathUtilities::distanceSquared3D(cf->getCoordinate(neighborNode), endXYZ); if (distance < currentNodeDistanceToEndingNode) { // // Is metric value the most positive or negative // const float metricValue = metricFile->getValue(neighborNode, metricColumnNumber); if (nextNode < 0) { nextNode = neighborNode; nextNodeMetricValue = metricValue; } else { switch (mode) { case MODE_FOLLOW_MOST_NEGATIVE: if (metricValue < nextNodeMetricValue) { nextNode = neighborNode; nextNodeMetricValue = metricValue; } break; case MODE_FOLLOW_MOST_POSITIVE: if (metricValue > nextNodeMetricValue) { nextNode = neighborNode; nextNodeMetricValue = metricValue; } break; } } } // if } } // for if (nextNode >= 0) { border.addBorderLink(cf->getCoordinate(nextNode)); currentNode = nextNode; } else { throw BrainModelAlgorithmException( "Create Border: unable to complete path from node " + QString::number(borderStartNode) + " to node " + QString::number(borderEndNode) + ". Stuck at node " + QString::number(currentNode) + " for border named " + borderName); } } } // // Name the border // border.setName(borderName); } */ /** * get the border that was created by create border mode. */ Border BrainModelSurfaceROICreateBorderUsingMetricShape::getBorder() const { return border; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceROICreateBorderUsingGeodesic.h0000664000175000017500000000473311572067322030717 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_ROI_CREATE_BORDER_USING_GEODESIC_H__ #define __BRAIN_MODEL_SURFACE_ROI_CREATE_BORDER_USING_GEODESIC_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BorderFile.h" #include "BrainModelSurfaceROIOperation.h" class BrainModelSurface; class BrainModelSurfaceROINodeSelection; /// class for performing creating a borders using geodesic distances class BrainModelSurfaceROICreateBorderUsingGeodesic : public BrainModelSurfaceROIOperation { public: // constructor BrainModelSurfaceROICreateBorderUsingGeodesic(BrainSet* bs, BrainModelSurface* bmsIn, BrainModelSurfaceROINodeSelection* surfaceROIIn, const QString& borderNameIn, const int startNodeIn, const int endNodeIn, const float samplingDensityIn); // destructor ~BrainModelSurfaceROICreateBorderUsingGeodesic(); // execute the operation void executeOperation() throw (BrainModelAlgorithmException); // get the border that was created by create border mode Border getBorder() const; protected: /// name for border QString borderName; /// border created Border border; /// border start node int borderStartNode; /// border end node int borderEndNode; /// border sampling density float borderSamplingDensity; }; #endif // __BRAIN_MODEL_SURFACE_ROI_CREATE_BORDER_USING_GEODESIC_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceROICreateBorderUsingGeodesic.cxx0000664000175000017500000002266311572067322031274 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainModelSurface.h" #include "BrainModelSurfaceGeodesic.h" #include "BrainModelSurfaceROINodeSelection.h" #include "BrainModelSurfaceROICreateBorderUsingGeodesic.h" #include "BrainSet.h" #include "CoordinateFile.h" #include "DebugControl.h" #include "FileUtilities.h" #include "GeodesicDistanceFile.h" #include "MathUtilities.h" #include "TopologyFile.h" /** * constructor. */ BrainModelSurfaceROICreateBorderUsingGeodesic::BrainModelSurfaceROICreateBorderUsingGeodesic(BrainSet* bs, BrainModelSurface* bmsIn, BrainModelSurfaceROINodeSelection* surfaceROIIn, const QString& borderNameIn, const int startNodeIn, const int endNodeIn, const float samplingDensityIn) : BrainModelSurfaceROIOperation(bs, bmsIn, surfaceROIIn) { borderName = borderNameIn; borderStartNode = startNodeIn; borderEndNode = endNodeIn; borderSamplingDensity = samplingDensityIn; } /** * destructor. */ BrainModelSurfaceROICreateBorderUsingGeodesic::~BrainModelSurfaceROICreateBorderUsingGeodesic() { } /** * execute the operation. */ void BrainModelSurfaceROICreateBorderUsingGeodesic::executeOperation() throw (BrainModelAlgorithmException) { // // Check Inputs // if (borderName.isEmpty()) { throw BrainModelAlgorithmException("Name for border is empty."); } const int numNodesInROI = operationSurfaceROI->getNumberOfNodesSelected(); if (numNodesInROI == 1) { throw BrainModelAlgorithmException("There is only one node, the starting node, in the ROI " " border named " + borderName); } const int numNodes = bms->getNumberOfNodes(); border.clearLinks(); if (borderStartNode >= 0) { if (borderStartNode >= numNodes) { throw BrainModelAlgorithmException("Starting node is invalid for " + borderName + "."); } if (operationSurfaceROI->getNodeSelected(borderStartNode) == false) { throw BrainModelAlgorithmException("Starting node is not in the ROI for " + borderName + "."); } } if (borderEndNode >= 0) { if (borderEndNode >= numNodes) { throw BrainModelAlgorithmException("Ending node is invalid for " + borderName + "."); } if (operationSurfaceROI->getNodeSelected(borderEndNode) == false) { throw BrainModelAlgorithmException("Ending node is not in the ROI for " + borderName + "."); } if (borderStartNode < 0) { throw BrainModelAlgorithmException("If the end node is specified, the start node must also be specified for " + borderName + "."); } if (borderStartNode == borderEndNode) { throw BrainModelAlgorithmException("Starting and ending node are the same for " + borderName + "."); } } // // If starting node is not specified // int iterStart = 2; if (borderStartNode < 0) { // // First iteration will find the starting node // iterStart = 1; // // Just pick the first selected node to use as the starting node // for (int i = 0; i < numNodes; i++) { if (operationSurfaceROI->getNodeSelected(i)) { borderStartNode = i; break; } } } // // (Iter == 1) is only performed if a starting node was not specified. In this // iteration, find the node that is furthest from the first selected node which // should be at one end of the sulcus. Use this node as the start node. // // (Iter == 2) performs the geodesic calculation from the start node. If the // end node was not specified, just pick the node furthest from the starting // node as the end node. // for (int iter = iterStart; iter <= 2; iter++) { // // Determine the geodesic distances // GeodesicDistanceFile geodesicFile; BrainModelSurfaceGeodesic geodesic(brainSet, bms, NULL, -2, "metric-column-name", &geodesicFile, -2, "geodesic-column-name", borderStartNode, operationSurfaceROI); geodesic.execute(); // // Verify geodesic file // if ((geodesicFile.getNumberOfNodes() != numNodes) || (geodesicFile.getNumberOfColumns() != 1)) { throw BrainModelAlgorithmException("PROGRAM ERROR: Geodesic distance file was not properly created for " + borderName + "."); } // // Find node furthest from start node for this iteration // int furthestNode = -1; float furthestNodeDistance = 0.0; for (int i = 0; i < numNodes; i++) { const float dist = geodesicFile.getNodeParentDistance(i, 0); if (dist > furthestNodeDistance) { furthestNodeDistance = dist; furthestNode = i; } } // // If searching for the starting node // if (iter == 1) { borderStartNode = furthestNode; if (borderStartNode < 0) { throw BrainModelAlgorithmException("Unable to determine starting node for " + borderName + "."); } if (DebugControl::getDebugOn()) { std::cout << "Starting node is " << borderStartNode << std::endl; } } // // If finding geodesic path and possibly the end node // if (iter == 2) { // // Was end node NOT specified // if (borderEndNode < 0) { borderEndNode = furthestNode; if (borderEndNode < 0) { throw BrainModelAlgorithmException("Unable to determine the ending node for " + borderName + "."); } if (DebugControl::getDebugOn()) { std::cout << "Ending node is " << borderEndNode << std::endl; } } // // Make sure end node is connected in geodesic to start node // if (geodesicFile.getNodeParent(borderEndNode, 0) < 0) { throw BrainModelAlgorithmException( "CREATE BORDER ERROR: Start and end nodes are not " "connected in the ROI for " + borderName + "."); } // // Set border name // border.setName(borderName); // // Find path for border // bool done = false; int nodeNum = borderEndNode; const CoordinateFile* coordFile = bms->getCoordinateFile(); while (done == false) { // // Add on to border // float xyz[3]; coordFile->getCoordinate(nodeNum, xyz); border.addBorderLink(xyz); // // Next node in geodesic path // nodeNum = geodesicFile.getNodeParent(nodeNum, 0); if ((nodeNum == borderStartNode) || (nodeNum < 0)) { done = true; } } } // if (iter == 2... } // for (iter... // // resample the border // if (borderSamplingDensity >= 0) { int dummyUnused; border.resampleBorderToDensity(borderSamplingDensity, 2, dummyUnused); } // // Need to reverse the links since we start from the end node in the geodesic path // border.reverseBorderLinks(); } /** * get the border that was created by create border mode. */ Border BrainModelSurfaceROICreateBorderUsingGeodesic::getBorder() const { return border; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceROIAssignShape.h0000664000175000017500000000447211572067322026112 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_ROI_ASSIGN_SHAPE_H__ #define __BRAIN_MODEL_SURFACE_ROI_ASSIGN_SHAPE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurfaceROIOperation.h" class SurfaceShapeFile; /// class for assigning surface shape using an ROI class BrainModelSurfaceROIAssignShape : public BrainModelSurfaceROIOperation { public: // constructor BrainModelSurfaceROIAssignShape(BrainSet* bs, BrainModelSurface* bmsIn, BrainModelSurfaceROINodeSelection* surfaceROIIn, SurfaceShapeFile* shapeFileIn, const int shapeColumnNumberIn, const QString& shapeColumnNameIn, const float valueIn); // destructor ~BrainModelSurfaceROIAssignShape(); // get assigned shape column int getAssignedShapeColumn() const { return shapeColumnNumber; }; protected: // execute the operation virtual void executeOperation() throw (BrainModelAlgorithmException); /// the surface shape file SurfaceShapeFile* shapeFile; /// shape column number int shapeColumnNumber; /// name for shape column QString shapeColumnName; /// value to assign float value; }; #endif // __BRAIN_MODEL_SURFACE_ROI_ASSIGN_SHAPE_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceROIAssignShape.cxx0000664000175000017500000000543611572067322026466 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurface.h" #include "BrainModelSurfaceROINodeSelection.h" #include "BrainModelSurfaceROIAssignShape.h" #include "SurfaceShapeFile.h" #include "TopologyHelper.h" /** * Constructor. */ BrainModelSurfaceROIAssignShape::BrainModelSurfaceROIAssignShape(BrainSet* bs, BrainModelSurface* bmsIn, BrainModelSurfaceROINodeSelection* surfaceROIIn, SurfaceShapeFile* shapeFileIn, const int shapeColumnNumberIn, const QString& shapeColumnNameIn, const float valueIn) : BrainModelSurfaceROIOperation(bs, bmsIn, surfaceROIIn) { shapeFile = shapeFileIn; shapeColumnNumber = shapeColumnNumberIn; shapeColumnName = shapeColumnNameIn; value = valueIn; } /** * destructor. */ BrainModelSurfaceROIAssignShape::~BrainModelSurfaceROIAssignShape() { } /** * execute the operation. */ void BrainModelSurfaceROIAssignShape::executeOperation() throw (BrainModelAlgorithmException) { const int numNodes = bms->getNumberOfNodes(); if (shapeFile->getNumberOfColumns() == 0) { shapeFile->setNumberOfNodesAndColumns(numNodes, 1); shapeColumnNumber = shapeFile->getNumberOfColumns() - 1; } else if ((shapeColumnNumber < 0) || (shapeColumnNumber >= shapeFile->getNumberOfColumns())) { shapeFile->addColumns(1); shapeColumnNumber = shapeFile->getNumberOfColumns() - 1; } // // Set column name // shapeFile->setColumnName(shapeColumnNumber, shapeColumnName); // // Assign the shape index to the nodes // for (int i = 0; i < numNodes; i++) { if (operationSurfaceROI->getNodeSelected(i)) { shapeFile->setValue(i, shapeColumnNumber, value); } } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceROIAssignPaint.h0000664000175000017500000000445011572067322026121 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_ROI_ASSIGN_PAINT_H__ #define __BRAIN_MODEL_SURFACE_ROI_ASSIGN_PAINT_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurfaceROIOperation.h" class PaintFile; /// class for assigning paints using an ROI class BrainModelSurfaceROIAssignPaint : public BrainModelSurfaceROIOperation { public: // constructor BrainModelSurfaceROIAssignPaint(BrainSet* bs, BrainModelSurface* bmsIn, BrainModelSurfaceROINodeSelection* surfaceROIIn, PaintFile* paintFileIn, const int paintColumnNumberIn, const QString& paintColumnNameIn, const QString& paintNameIn); // destructor ~BrainModelSurfaceROIAssignPaint(); // get assigned paint column int getAssignedPaintColumn() const { return paintColumnNumber; }; protected: // execute the operation virtual void executeOperation() throw (BrainModelAlgorithmException); /// the paint file PaintFile* paintFile; /// paint column number int paintColumnNumber; /// name for paint column QString paintColumnName; /// paint name to assign QString paintName; }; #endif // __BRAIN_MODEL_SURFACE_ROI_ASSIGN_PAINT_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceROIAssignPaint.cxx0000664000175000017500000000600111572067322026466 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurface.h" #include "BrainModelSurfaceROINodeSelection.h" #include "BrainModelSurfaceROIAssignPaint.h" #include "PaintFile.h" #include "TopologyHelper.h" /** * Constructor. */ BrainModelSurfaceROIAssignPaint::BrainModelSurfaceROIAssignPaint(BrainSet* bs, BrainModelSurface* bmsIn, BrainModelSurfaceROINodeSelection* surfaceROIIn, PaintFile* paintFileIn, const int paintColumnNumberIn, const QString& paintColumnNameIn, const QString& paintNameIn) : BrainModelSurfaceROIOperation(bs, bmsIn, surfaceROIIn) { paintFile = paintFileIn; paintColumnNumber = paintColumnNumberIn; paintColumnName = paintColumnNameIn; paintName = paintNameIn; } /** * destructor. */ BrainModelSurfaceROIAssignPaint::~BrainModelSurfaceROIAssignPaint() { } /** * execute the operation. */ void BrainModelSurfaceROIAssignPaint::executeOperation() throw (BrainModelAlgorithmException) { if (paintName.isEmpty()) { throw BrainModelAlgorithmException("Paint name is empty."); } const int numNodes = bms->getNumberOfNodes(); if (paintFile->getNumberOfColumns() == 0) { paintFile->setNumberOfNodesAndColumns(numNodes, 1); paintColumnNumber = paintFile->getNumberOfColumns() - 1; } else if ((paintColumnNumber < 0) || (paintColumnNumber >= paintFile->getNumberOfColumns())) { paintFile->addColumns(1); paintColumnNumber = paintFile->getNumberOfColumns() - 1; } // // Set column name // paintFile->setColumnName(paintColumnNumber, paintColumnName); // // Get the index of the paint name // const int paintIndex = paintFile->addPaintName(paintName); // // Assign the paint index to the nodes // for (int i = 0; i < numNodes; i++) { if (operationSurfaceROI->getNodeSelected(i)) { paintFile->setPaint(i, paintColumnNumber, paintIndex); } } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceROIAssignMetricNodeArea.h0000664000175000017500000000462411572067322027673 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_ROI_ASSIGN_METRIC_NODE_AREA_H__ #define __BRAIN_MODEL_SURFACE_ROI_ASSIGN_METRIC_NODE_AREA_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurfaceROIOperation.h" class MetricFile; /// class for assigning metrics using an ROI class BrainModelSurfaceROIAssignMetricNodeArea : public BrainModelSurfaceROIOperation { public: // constructor BrainModelSurfaceROIAssignMetricNodeArea(BrainSet* bs, BrainModelSurface* bmsIn, BrainModelSurfaceROINodeSelection* surfaceROIIn, MetricFile* metricFileIn, const int metricColumnNumberIn, const QString& metricColumnNameIn, const bool percentageAreaFlagIn); // destructor ~BrainModelSurfaceROIAssignMetricNodeArea(); // get assigned metric column int getAssignedMetricColumn() const { return metricColumnNumber; }; protected: // execute the operation virtual void executeOperation() throw (BrainModelAlgorithmException); /// the metric file MetricFile* metricFile; /// metric column number int metricColumnNumber; /// name for metric column const QString metricColumnName; /// do percentage of surface area const bool percentageAreaFlag; }; #endif // __BRAIN_MODEL_SURFACE_ROI_ASSIGN_METRIC_NODE_AREA_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceROIAssignMetricNodeArea.cxx0000664000175000017500000000670111572067322030244 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurface.h" #include "BrainModelSurfaceROINodeSelection.h" #include "BrainModelSurfaceROIAssignMetricNodeArea.h" #include "MetricFile.h" #include "TopologyHelper.h" /** * Constructor. */ BrainModelSurfaceROIAssignMetricNodeArea::BrainModelSurfaceROIAssignMetricNodeArea(BrainSet* bs, BrainModelSurface* bmsIn, BrainModelSurfaceROINodeSelection* surfaceROIIn, MetricFile* metricFileIn, const int metricColumnNumberIn, const QString& metricColumnNameIn, const bool percentageAreaFlagIn) : BrainModelSurfaceROIOperation(bs, bmsIn, surfaceROIIn), metricFile(metricFileIn), metricColumnNumber(metricColumnNumberIn), metricColumnName(metricColumnNameIn), percentageAreaFlag(percentageAreaFlagIn) { } /** * destructor. */ BrainModelSurfaceROIAssignMetricNodeArea::~BrainModelSurfaceROIAssignMetricNodeArea() { } /** * execute the operation. */ void BrainModelSurfaceROIAssignMetricNodeArea::executeOperation() throw (BrainModelAlgorithmException) { const int numNodes = bms->getNumberOfNodes(); if (metricFile->getNumberOfColumns() == 0) { metricFile->setNumberOfNodesAndColumns(numNodes, 1); metricColumnNumber = metricFile->getNumberOfColumns() - 1; } else if ((metricColumnNumber < 0) || (metricColumnNumber >= metricFile->getNumberOfColumns())) { metricFile->addColumns(1); metricColumnNumber = metricFile->getNumberOfColumns() - 1; } // // Set column name // metricFile->setColumnName(metricColumnNumber, metricColumnName); // // Compute the node areas // std::vector nodeAreas; bms->getAreaOfAllNodes(nodeAreas); // // Do percentage of area? // if (percentageAreaFlag) { const float surfaceArea = bms->getSurfaceArea(); if (surfaceArea > 0.0) { const int numNodes = static_cast(nodeAreas.size()); for (int i = 0; i < numNodes; i++) { nodeAreas[i] = (nodeAreas[i] / surfaceArea) * 100.0; } } } // // Assign the metric index to the nodes // for (int i = 0; i < numNodes; i++) { if (operationSurfaceROI->getNodeSelected(i)) { metricFile->setValue(i, metricColumnNumber, nodeAreas[i]); } else { metricFile->setValue(i, metricColumnNumber, 0); } } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceROIAssignMetric.h0000664000175000017500000000445411572067322026275 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_ROI_ASSIGN_METRIC_H__ #define __BRAIN_MODEL_SURFACE_ROI_ASSIGN_METRIC_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurfaceROIOperation.h" class MetricFile; /// class for assigning metrics using an ROI class BrainModelSurfaceROIAssignMetric : public BrainModelSurfaceROIOperation { public: // constructor BrainModelSurfaceROIAssignMetric(BrainSet* bs, BrainModelSurface* bmsIn, BrainModelSurfaceROINodeSelection* surfaceROIIn, MetricFile* metricFileIn, const int metricColumnNumberIn, const QString& metricColumnNameIn, const float valueIn); // destructor ~BrainModelSurfaceROIAssignMetric(); // get assigned metric column int getAssignedMetricColumn() const { return metricColumnNumber; }; protected: // execute the operation virtual void executeOperation() throw (BrainModelAlgorithmException); /// the metric file MetricFile* metricFile; /// metric column number int metricColumnNumber; /// name for metric column QString metricColumnName; /// value to assign float value; }; #endif // __BRAIN_MODEL_SURFACE_ROI_ASSIGN_METRIC_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceROIAssignMetric.cxx0000664000175000017500000000546111572067322026647 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurface.h" #include "BrainModelSurfaceROINodeSelection.h" #include "BrainModelSurfaceROIAssignMetric.h" #include "MetricFile.h" #include "TopologyHelper.h" /** * Constructor. */ BrainModelSurfaceROIAssignMetric::BrainModelSurfaceROIAssignMetric(BrainSet* bs, BrainModelSurface* bmsIn, BrainModelSurfaceROINodeSelection* surfaceROIIn, MetricFile* metricFileIn, const int metricColumnNumberIn, const QString& metricColumnNameIn, const float valueIn) : BrainModelSurfaceROIOperation(bs, bmsIn, surfaceROIIn) { metricFile = metricFileIn; metricColumnNumber = metricColumnNumberIn; metricColumnName = metricColumnNameIn; value = valueIn; } /** * destructor. */ BrainModelSurfaceROIAssignMetric::~BrainModelSurfaceROIAssignMetric() { } /** * execute the operation. */ void BrainModelSurfaceROIAssignMetric::executeOperation() throw (BrainModelAlgorithmException) { const int numNodes = bms->getNumberOfNodes(); if (metricFile->getNumberOfColumns() == 0) { metricFile->setNumberOfNodesAndColumns(numNodes, 1); metricColumnNumber = metricFile->getNumberOfColumns() - 1; } else if ((metricColumnNumber < 0) || (metricColumnNumber >= metricFile->getNumberOfColumns())) { metricFile->addColumns(1); metricColumnNumber = metricFile->getNumberOfColumns() - 1; } // // Set column name // metricFile->setColumnName(metricColumnNumber, metricColumnName); // // Assign the metric index to the nodes // for (int i = 0; i < numNodes; i++) { if (operationSurfaceROI->getNodeSelected(i)) { metricFile->setValue(i, metricColumnNumber, value); } } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfacePolyhedronNew.h0000664000175000017500000000575611572067322026136 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __BRAIN_MODEL_SURFACE_POLYAHEDRON_NEW_H__ #define __BRAIN_MODEL_SURFACE_POLYAHEDRON_NEW_H__ #include "BrainModelAlgorithm.h" #include class BrainModelSurface; /// class that generates a tetrahedron surface class BrainModelSurfacePolyhedronNew : public BrainModelAlgorithm { public: // constructor BrainModelSurfacePolyhedronNew(BrainSet* bs, const int numberOfDivisions); // destructor ~BrainModelSurfacePolyhedronNew(); // execute the algorithm void execute() throw (BrainModelAlgorithmException); // get number of nodes and triangles from the number of iterations static void getNumberOfNodesAndTrianglesFromDivisions( int divisions, int& numNodesOut, int& numTrianglesOut); protected: enum POLYHEDRA { POLYHEDRA_TETRAHEDRON, POLYHEDRA_OCTAHEDRON, POLYHEDRA_ICOSAHEDRON }; /// make the surface a sphere void makeSphere(); ///interpolate a face node void interp3(float coord1[3], float coord2[3], float coord3[3], int row, int col, float out[3]); ///get edge nodes, generating if needed void getEdge(int node1, int node2, int* out); ///edge node info std::vector > > edgenodes;//yes, really /// the surface created BrainModelSurface* surface; /// the topology file created TopologyFile* topologyFile; CoordinateFile* coordinateFile; /// number of iterations int numberOfDivisions; int curNodes, curTiles; /// type of polyhedra produced static const POLYHEDRA polyhedra; }; /*//this goes in .cxx, so we don't need to use compiler directives #ifdef __BRAIN_MODEL_SURFACE_POLYAHEDRON_MAIN__ const BrainModelSurfacePolyhedronNew::POLYHEDRA BrainModelSurfacePolyhedronNew::polyhedra = BrainModelSurfacePolyhedronNew::POLYHEDRA_ICOSAHEDRON; #endif // __BRAIN_MODEL_SURFACE_POLYAHEDRON_MAIN__ //*/ #endif // __BRAIN_MODEL_SURFACE_POLYAHEDRON_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfacePolyhedronNew.cxx0000664000175000017500000003522511572067322026503 0ustar michaelmichael /*LICENSE_START*/ #include "BrainSet.h" /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelSurface.h" //#define __BRAIN_MODEL_SURFACE_POLYAHEDRON_MAIN__ #include "BrainModelSurfacePolyhedronNew.h" //#undef __BRAIN_MODEL_SURFACE_POLYAHEDRON_MAIN__ #include "CoordinateFile.h" #include "TopologyFile.h" #include "TopologyHelper.h" //define polyhedron type const BrainModelSurfacePolyhedronNew::POLYHEDRA BrainModelSurfacePolyhedronNew::polyhedra = BrainModelSurfacePolyhedronNew::POLYHEDRA_ICOSAHEDRON; /** * constructor. */ BrainModelSurfacePolyhedronNew::BrainModelSurfacePolyhedronNew(BrainSet* bs, const int numberOfDivisionsIn) : BrainModelAlgorithm(bs), numberOfDivisions(numberOfDivisionsIn) { if (numberOfDivisions < 1) numberOfDivisions = 1; surface = NULL; } /** * destructor. */ BrainModelSurfacePolyhedronNew::~BrainModelSurfacePolyhedronNew() { } /** * get number of nodes and triangles from the number of iterations. */ void BrainModelSurfacePolyhedronNew::getNumberOfNodesAndTrianglesFromDivisions( int divisions, int& numNodesOut, int& numTrianglesOut) { // // Initial number of triangles for initial tetrahedron // int numTriangles = 0; switch (polyhedra) { case POLYHEDRA_TETRAHEDRON: numTriangles = 4; break; case POLYHEDRA_OCTAHEDRON: numTriangles = 8; break; case POLYHEDRA_ICOSAHEDRON: numTriangles = 20; break; } // // Calculate number of nodes using the Euler Characteristic // // V - E + F = 2 // V = 2 + E - F // 3 edges per triangle with each edge shared // V = 2 + ((F * 3) / 2) - F // V = 2 + 1.5 * F - F // V = 2 + (1.5 - 1) * F // V = 2 + 0.5 * F // V = 2 + (F / 2) // numTrianglesOut = numTriangles * divisions * divisions;//yes, its really that simple, the sum of the two triangulars is square numNodesOut = 2 + (numTrianglesOut / 2); } /** * execute the algorithm. */ void BrainModelSurfacePolyhedronNew::execute() throw (BrainModelAlgorithmException) { // // Create a surface // this->surface = new BrainModelSurface(brainSet); this->surface->setSurfaceType(BrainModelSurface::SURFACE_TYPE_SPHERICAL); this->brainSet->addBrainModel(surface); // // Set the initial coordinates // coordinateFile = surface->getCoordinateFile(); // // Create and set the initial topology // TopologyFile* initTopo = new TopologyFile(); topologyFile = new TopologyFile(); initTopo->setTopologyType(TopologyFile::TOPOLOGY_TYPE_CLOSED); topologyFile->setTopologyType(TopologyFile::TOPOLOGY_TYPE_CLOSED); this->brainSet->addTopologyFile(topologyFile); this->surface->setTopologyFile(this->topologyFile); // // Get needed sizes of files // int totalTiles, totalNodes; getNumberOfNodesAndTrianglesFromDivisions(numberOfDivisions, totalNodes, totalTiles); coordinateFile->setNumberOfCoordinates(totalNodes); topologyFile->setNumberOfTiles(totalTiles); curTiles = 0; // // Create the initial polyhedra // switch (this->polyhedra) { case POLYHEDRA_TETRAHEDRON: curNodes = 4; coordinateFile->setCoordinate(0, 1.0, 1.0, 1.0); coordinateFile->setCoordinate(1, -1.0, -1.0, 1.0); coordinateFile->setCoordinate(2, -1.0, 1.0, -1.0); coordinateFile->setCoordinate(3, 1.0, -1.0, -1.0); initTopo->setNumberOfTiles(4); initTopo->setTile(0, 1, 0, 2); initTopo->setTile(1, 1, 3, 0); initTopo->setTile(2, 2, 3, 0); initTopo->setTile(3, 3, 2, 1); break; case POLYHEDRA_OCTAHEDRON: curNodes = 6; coordinateFile->setCoordinate(0, -1.0, -1.0, 0.0); coordinateFile->setCoordinate(1, 1.0, -1.0, 0.0); coordinateFile->setCoordinate(2, 1.0, 1.0, 0.0); coordinateFile->setCoordinate(3, -1.0, 1.0, 0.0); coordinateFile->setCoordinate(4, 0.0, 0.0, -1.0); coordinateFile->setCoordinate(5, 0.0, 0.0, 1.0); initTopo->setNumberOfTiles(8); initTopo->setTile(0, 0, 1, 5); initTopo->setTile(1, 1, 2, 5); initTopo->setTile(2, 2, 3, 5); initTopo->setTile(3, 3, 0, 5); initTopo->setTile(4, 0, 1, 4); initTopo->setTile(5, 1, 2, 4); initTopo->setTile(6, 2, 3, 4); initTopo->setTile(7, 3, 0, 4); break; case POLYHEDRA_ICOSAHEDRON: { const double phi = (1.0 + std::sqrt(5.0)) / 2.0; curNodes = 12; coordinateFile->setCoordinate(0, -phi, 0.0, 1.0); coordinateFile->setCoordinate(1, 0, -1.0, phi); coordinateFile->setCoordinate(2, phi, 0.0, 1.0); coordinateFile->setCoordinate(3, 0, 1.0, phi); coordinateFile->setCoordinate(4, -1.0, -phi, 0.0); coordinateFile->setCoordinate(5, 1.0, -phi, 0.0); coordinateFile->setCoordinate(6, 1.0, phi, 0.0); coordinateFile->setCoordinate(7, -1.0, phi, 0.0); coordinateFile->setCoordinate(8, -phi, 0.0, -1.0); coordinateFile->setCoordinate(9, 0, -1.0, -phi); coordinateFile->setCoordinate(10, phi, 0.0, -1.0); coordinateFile->setCoordinate(11, 0, 1.0, -phi); initTopo->setNumberOfTiles(20); initTopo->setTile(0, 0, 7, 8); initTopo->setTile(1, 0, 3, 7); initTopo->setTile(2, 0, 1, 3); initTopo->setTile(3, 1, 2, 3); initTopo->setTile(4, 1, 5, 2); initTopo->setTile(5, 5, 9, 10); initTopo->setTile(6, 10, 11, 6); initTopo->setTile(7, 4, 1, 0); initTopo->setTile(8, 4, 5, 1); initTopo->setTile(9, 4, 9, 5); initTopo->setTile(10, 5, 10, 2); initTopo->setTile(11, 10, 6, 2); initTopo->setTile(12, 6, 11, 7); initTopo->setTile(13, 11, 9, 8); initTopo->setTile(14, 9, 4, 8); initTopo->setTile(15, 8, 4, 0); initTopo->setTile(16, 11, 8, 7); initTopo->setTile(17, 6, 7, 3); initTopo->setTile(18, 6, 3, 2); initTopo->setTile(19, 11, 10, 9); } break; } // Note: if further refinement is required (unlikely), use a dodecahedron, divide each face into 5 triangles, keep track of which vertex is in the // center, and always pass that vertex as the first vertex to interp3. Then, make two separate polynomials to interpolate weights, one for the first // vertex and one for the other two. Then, optimize with a genetic algorithm for both variance of triangle area, and some regularization term to keep // the shape of the triangles consistent. This means the triangles, once projected to the sphere, will each be identical, and have smaller area, // causing the polynomial that modifies the linear weights closer to linear, therefore with less edge effects. - Tim C // // Begin triangle division code - does not rely on spherical, preserves tile orientation // edgenodes.resize(curNodes - 1);//stores by low node # int edgesize = numberOfDivisions + 1; int i, j, k, numTiles = initTopo->getNumberOfTiles(), intRows = numberOfDivisions - 1, intCols; float tempcoord[3], coord1[3], coord2[3], coord3[3]; int* edge1 = new int[edgesize], *edge2 = new int[edgesize], *edge3 = new int[edgesize]; int** facenodes = new int*[edgesize]; for (i = 0; i < edgesize; ++i) {// first index is row from bottom, second index is column from left facenodes[i] = new int[edgesize - i]; } // // Loop through tiles // for (i = 0; i < numTiles; i++) { // // Get the tile's nodes // int node1, node2, node3; initTopo->getTile(i, node1, node2, node3); //convention for visualization: node 1 is bottom left, node 2 is bottom right, node 3 is top //tile generation also follows this convention, with the consequence that tile orientation is preserved // // Get or generate edge nodes // getEdge(node1, node2, edge1);//bottom edge, left to right getEdge(node1, node3, edge2);//left edge, bottom to top getEdge(node2, node3, edge3);//right edge, bottom to top // // Get coords for interpolating // coordinateFile->getCoordinate(node1, coord1);//only 20 times, doesn't matter if we use a local coord aray coordinateFile->getCoordinate(node2, coord2); coordinateFile->getCoordinate(node3, coord3); // // Copy edge nodes into the face array // for (j = 0; j < edgesize; ++j) { facenodes[0][j] = edge1[j]; facenodes[j][0] = edge2[j]; facenodes[j][numberOfDivisions - j] = edge3[j]; } // // Time intensive code start (assuming large numberOfDivisions) // // // Generate interior coordinates // for (j = 1; j < intRows; ++j) { intCols = numberOfDivisions - j; for (k = 1; k < intCols; ++k) { interp3(coord1, coord2, coord3, j, k, tempcoord); coordinateFile->setCoordinate(curNodes, tempcoord); facenodes[j][k] = curNodes; ++curNodes; } } // // Generate tiles // for (j = 0; j < numberOfDivisions; ++j) {//lets inner loop short circuit on top row for (k = 0; k < numberOfDivisions - j - 1; ++k) {//pairs for trapezoidal pieces topologyFile->setTile(curTiles, facenodes[j][k], facenodes[j][k + 1], facenodes[j + 1][k]); topologyFile->setTile(curTiles + 1, facenodes[j + 1][k], facenodes[j][k + 1], facenodes[j + 1][k + 1]); curTiles += 2; }//and one more topologyFile->setTile(curTiles, facenodes[j][numberOfDivisions - j - 1], facenodes[j][numberOfDivisions - j], facenodes[j + 1][numberOfDivisions - j - 1]); ++curTiles; } // // Time intensive code end // } // // End triangle division code // this->makeSphere(); this->surface->convertToSphereWithRadius(100.0); delete initTopo; for (i = 0; i < edgesize; ++i) delete[] facenodes[i]; delete[] facenodes; delete[] edge1; delete[] edge2; delete[] edge3; } /** * Make the surface a sphere. */ void BrainModelSurfacePolyhedronNew::makeSphere() { this->surface->orientTilesOutward(surface->getSurfaceType()); this->surface->computeNormals(); this->surface->translateToCenterOfMass(); this->surface->convertToSphereWithRadius(10000.0); } void BrainModelSurfacePolyhedronNew::getEdge(int node1, int node2, int* out) {//function is called relatively few times, assuming large numberOfDivisions bool reverse = false; int i, index, edgesize = numberOfDivisions + 1; if (node1 > node2) { reverse = true; i = node1; node1 = node2; node2 = i; } bool found = false; for (i = 0; i < (int)edgenodes[node1].size(); ++i) { if (edgenodes[node1][i][numberOfDivisions] == node2) { found = true; index = i; break; } } if (!found) { float tempcoord[3], coord1[3], coord2[3], coord3[3] = {0.0f, 0.0f, 0.0f}; coordinateFile->getCoordinate(node1, coord1);//this function isn't called a lot, so who cares if it uses a local coord array coordinateFile->getCoordinate(node2, coord2); std::vector tempvec; tempvec.resize(edgesize); tempvec[0] = node1; tempvec[numberOfDivisions] = node2; for (i = 1; i < numberOfDivisions; ++i) { interp3(coord1, coord2, coord3, 0, i, tempcoord);//use 0 as dummy node, with row 0 it is unused tempvec[i] = curNodes; coordinateFile->setCoordinate(curNodes, tempcoord); ++curNodes; } index = edgenodes[node1].size(); edgenodes[node1].push_back(tempvec); } if (reverse) { for (i = 0; i < edgesize; ++i) { out[i] = edgenodes[node1][index][edgesize - i - 1]; } } else { for (i = 0; i < edgesize; ++i) { out[i] = edgenodes[node1][index][i]; } } } void BrainModelSurfacePolyhedronNew::interp3(float coord1[3], float coord2[3], float coord3[3], int row, int col, float out[3]) {//this is the function to change if you want different spacing float weight2 = ((float)col) / numberOfDivisions;//start with flat interpolation weights float weight3 = ((float)row) / numberOfDivisions; 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; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfacePolyhedron.h0000664000175000017500000000477511572067322025464 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __BRAIN_MODEL_SURFACE_POLYAHEDRON_H__ #define __BRAIN_MODEL_SURFACE_POLYAHEDRON_H__ #include "BrainModelAlgorithm.h" class BrainModelSurface; /// class that generates a tetrahedron surface class BrainModelSurfacePolyhedron : public BrainModelAlgorithm { public: // constructor BrainModelSurfacePolyhedron(BrainSet* bs, const int numberOfIterations); // destructor ~BrainModelSurfacePolyhedron(); // execute the algorithm void execute() throw (BrainModelAlgorithmException); // get number of nodes and triangles from the number of iterations static void getNumberOfNodesAndTrianglesFromIterations( std::vector& iterationsOut, std::vector& numNodesOut, std::vector& numTrianglesOut); protected: enum POLYHEDRA { POLYHEDRA_TETRAHEDRON, POLYHEDRA_OCTAHEDRON, POLYHEDRA_ICOSAHEDRON }; /// make the surface a sphere void makeSphere(); /// the surface created BrainModelSurface* surface; /// the topology file created TopologyFile* topologyFile; /// number of iterations const int numberOfIterations; /// type of polyhedra produced static const POLYHEDRA polyhedra; }; #ifdef __BRAIN_MODEL_SURFACE_POLYAHEDRON_MAIN__ const BrainModelSurfacePolyhedron::POLYHEDRA BrainModelSurfacePolyhedron::polyhedra = BrainModelSurfacePolyhedron::POLYHEDRA_ICOSAHEDRON; #endif // __BRAIN_MODEL_SURFACE_POLYAHEDRON_MAIN__ #endif // __BRAIN_MODEL_SURFACE_POLYAHEDRON_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfacePolyhedron.cxx0000664000175000017500000003176411572067322026035 0ustar michaelmichael /*LICENSE_START*/ #include #include "BrainSet.h" /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelSurface.h" #define __BRAIN_MODEL_SURFACE_POLYAHEDRON_MAIN__ #include "BrainModelSurfacePolyhedron.h" #undef __BRAIN_MODEL_SURFACE_POLYAHEDRON_MAIN__ #include "CoordinateFile.h" #include "TopologyFile.h" #include "TopologyHelper.h" #include "BrainModelSurfaceDeformDataFile.h" /** * constructor. */ BrainModelSurfacePolyhedron::BrainModelSurfacePolyhedron(BrainSet* bs, const int numberOfIterationsIn) : BrainModelAlgorithm(bs), numberOfIterations(numberOfIterationsIn) { surface = NULL; } /** * destructor. */ BrainModelSurfacePolyhedron::~BrainModelSurfacePolyhedron() { } /** * get number of nodes and triangles from the number of iterations. */ void BrainModelSurfacePolyhedron::getNumberOfNodesAndTrianglesFromIterations( std::vector& iterationsOut, std::vector& numNodesOut, std::vector& numTrianglesOut) { iterationsOut.clear(); numNodesOut.clear(); numTrianglesOut.clear(); // // Initial number of triangles for initial tetrahedron // int numTriangles = 0; switch (polyhedra) { case POLYHEDRA_TETRAHEDRON: numTriangles = 4; break; case POLYHEDRA_OCTAHEDRON: numTriangles = 8; break; case POLYHEDRA_ICOSAHEDRON: numTriangles = 20; break; } for (int iter = 0; iter < 8; iter++) { // // Calculate number of nodes using the Euler Characteristic // // V - E + F = 2 // V = 2 + E - F // 3 edges per triangle with each edge shared // V = 2 + ((F * 3) / 2) - F // V = 2 + 1.5 * F - F // V = 2 + (1.5 - 1) * F // V = 2 + 0.5 * F // V = 2 + (F / 2) // const int numNodes = 2 + (numTriangles / 2); iterationsOut.push_back(iter); numNodesOut.push_back(numNodes); numTrianglesOut.push_back(numTriangles); // // Each triangle subdivides into four triangles // numTriangles *= 4; } } /** * execute the algorithm. */ void BrainModelSurfacePolyhedron::execute() throw (BrainModelAlgorithmException) { // // Create a surface // this->surface = new BrainModelSurface(brainSet); this->surface->setSurfaceType(BrainModelSurface::SURFACE_TYPE_SPHERICAL); this->brainSet->addBrainModel(surface); // // Set the initial coordinates // CoordinateFile* coordinateFile = surface->getCoordinateFile(); // // Create and set the initial topology // this->topologyFile = new TopologyFile(); this->topologyFile->setTopologyType(TopologyFile::TOPOLOGY_TYPE_CLOSED); this->brainSet->addTopologyFile(topologyFile); this->surface->setTopologyFile(this->topologyFile); // // Create the initial polyhedra // switch (this->polyhedra) { case POLYHEDRA_TETRAHEDRON: coordinateFile->setNumberOfCoordinates(4); coordinateFile->setCoordinate(0, 1.0, 1.0, 1.0); coordinateFile->setCoordinate(1, -1.0, -1.0, 1.0); coordinateFile->setCoordinate(2, -1.0, 1.0, -1.0); coordinateFile->setCoordinate(3, 1.0, -1.0, -1.0); this->topologyFile->setNumberOfTiles(4); this->topologyFile->setTile(0, 1, 0, 2); this->topologyFile->setTile(1, 1, 3, 0); this->topologyFile->setTile(2, 2, 3, 0); this->topologyFile->setTile(3, 3, 2, 1); break; case POLYHEDRA_OCTAHEDRON: coordinateFile->setNumberOfCoordinates(6); coordinateFile->setCoordinate(0, -1.0, -1.0, 0.0); coordinateFile->setCoordinate(1, 1.0, -1.0, 0.0); coordinateFile->setCoordinate(2, 1.0, 1.0, 0.0); coordinateFile->setCoordinate(3, -1.0, 1.0, 0.0); coordinateFile->setCoordinate(4, 0.0, 0.0, -1.0); coordinateFile->setCoordinate(5, 0.0, 0.0, 1.0); this->topologyFile->setNumberOfTiles(8); this->topologyFile->setTile(0, 0, 1, 5); this->topologyFile->setTile(1, 1, 2, 5); this->topologyFile->setTile(2, 2, 3, 5); this->topologyFile->setTile(3, 3, 0, 5); this->topologyFile->setTile(4, 0, 1, 4); this->topologyFile->setTile(5, 1, 2, 4); this->topologyFile->setTile(6, 2, 3, 4); this->topologyFile->setTile(7, 3, 0, 4); break; case POLYHEDRA_ICOSAHEDRON: { const double phi = (1.0 + std::sqrt(5.0)) / 2.0; coordinateFile->setNumberOfCoordinates(12); coordinateFile->setCoordinate(0, -phi, 0.0, 1.0); coordinateFile->setCoordinate(1, 0, -1.0, phi); coordinateFile->setCoordinate(2, phi, 0.0, 1.0); coordinateFile->setCoordinate(3, 0, 1.0, phi); coordinateFile->setCoordinate(4, -1.0, -phi, 0.0); coordinateFile->setCoordinate(5, 1.0, -phi, 0.0); coordinateFile->setCoordinate(6, 1.0, phi, 0.0); coordinateFile->setCoordinate(7, -1.0, phi, 0.0); coordinateFile->setCoordinate(8, -phi, 0.0, -1.0); coordinateFile->setCoordinate(9, 0, -1.0, -phi); coordinateFile->setCoordinate(10, phi, 0.0, -1.0); coordinateFile->setCoordinate(11, 0, 1.0, -phi); /* this->topologyFile->setNumberOfTiles(coordinateFile->getNumberOfCoordinates() + 20); for (int i = 0; i < coordinateFile->getNumberOfCoordinates(); i++) { this->topologyFile->setTile(i, i, i, i); } */ this->topologyFile->setNumberOfTiles(20); this->topologyFile->setTile(0, 0, 7, 8); this->topologyFile->setTile(1, 0, 3, 7); this->topologyFile->setTile(2, 0, 1, 3); this->topologyFile->setTile(3, 1, 2, 3); this->topologyFile->setTile(4, 1, 5, 2); this->topologyFile->setTile(5, 5, 9, 10); this->topologyFile->setTile(6, 10, 11, 6); this->topologyFile->setTile(7, 4, 1, 0); this->topologyFile->setTile(8, 4, 5, 1); this->topologyFile->setTile(9, 4, 9, 5); this->topologyFile->setTile(10, 5, 10, 2); this->topologyFile->setTile(11, 10, 6, 2); this->topologyFile->setTile(12, 6, 11, 7); this->topologyFile->setTile(13, 11, 9, 8); this->topologyFile->setTile(14, 9, 4, 8); this->topologyFile->setTile(15, 8, 4, 0); this->topologyFile->setTile(16, 11, 8, 7); this->topologyFile->setTile(17, 6, 7, 3); this->topologyFile->setTile(18, 6, 3, 2); this->topologyFile->setTile(19, 11, 10, 9); } break; } // // Scale the surface // TransformationMatrix tm; tm.scale(100.0, 100.0, 100.0); this->surface->applyTransformationMatrix(tm); this->makeSphere(); // // Subdivide for the specified number of iterations // for (int iterations = 0; iterations < this->numberOfIterations; iterations++) { // // Create a topology helper // const TopologyHelper* th = this->topologyFile->getTopologyHelper(true, true, true); // // Make a copy of the coordinate file // CoordinateFile newCoords; int numOldCoords = coordinateFile->getNumberOfCoordinates(); newCoords.setNumberOfCoordinates(numOldCoords); for (int i = 0; i < numOldCoords; i++) { newCoords.setCoordinate(i, coordinateFile->getCoordinate(i)); } // // Get the edges and place them in a vector // const std::set edgesSet = th->getEdgeInfo(); std::vector edges; for (std::set::const_iterator iter = edgesSet.begin(); iter != edgesSet.end(); iter++) { edges.push_back(*iter); } // // Index of new node for edge // std::vector edgeMidpointNodeIndex; // // Add a vertex at the midpoint of each edge // int numEdges = static_cast(edges.size()); for (int i = 0; i < numEdges; i++) { // // Get the edge's nodes // int node1, node2; edges[i].getNodes(node1, node2); // // Get the midpoint of the nodes // const float* xyz1 = coordinateFile->getCoordinate(node1); const float* xyz2 = coordinateFile->getCoordinate(node2); const float midpoint[3] = { (xyz1[0] + xyz2[0]) * 0.5, (xyz1[1] + xyz2[1]) * 0.5, (xyz1[2] + xyz2[2]) * 0.5 }; // // Add midpoint as new coordinate // newCoords.addCoordinate(midpoint); edgeMidpointNodeIndex.push_back(newCoords.getNumberOfCoordinates() - 1); } // // Copy new coordinates to the surface's coordinates // const int numCoords = newCoords.getNumberOfCoordinates(); coordinateFile->setNumberOfCoordinates(numCoords); for (int i = 0; i < numCoords; i++) { coordinateFile->setCoordinate(i, newCoords.getCoordinate(i)); } // // Create a new topology file // TopologyFile newTopology; // // Loop through the old topology file // int numOldTriangles = this->topologyFile->getNumberOfTiles(); for (int i = 0; i < numOldTriangles; i++) { const int* triangle = this->topologyFile->getTile(i); // // Find the edges used by this triangle // int newNodes[3] = { -1, -1, -1 }; for (int k = 0; k < numEdges; k++) { TopologyEdgeInfo& tei = edges[k]; if ((tei.tile1 == i) || (tei.tile2 == i)) { if ((tei.node1 == triangle[0]) && (tei.node2 == triangle[1])) { newNodes[0] = edgeMidpointNodeIndex[k]; } else if ((tei.node1 == triangle[1]) && (tei.node2 == triangle[0])) { newNodes[0] = edgeMidpointNodeIndex[k]; } else if ((tei.node1 == triangle[1]) && (tei.node2 == triangle[2])) { newNodes[1] = edgeMidpointNodeIndex[k]; } else if ((tei.node1 == triangle[2]) && (tei.node2 == triangle[1])) { newNodes[1] = edgeMidpointNodeIndex[k]; } else if ((tei.node1 == triangle[0]) && (tei.node2 == triangle[2])) { newNodes[2] = edgeMidpointNodeIndex[k]; } else if ((tei.node1 == triangle[2]) && (tei.node2 == triangle[0])) { newNodes[2] = edgeMidpointNodeIndex[k]; } } } // // Check for errors // for (int j = 0; j < 3; j++) { if (newNodes[j] < 0) { throw BrainModelAlgorithmException("ALGORITHM ERROR: " "failed to find edges for a triangle."); } } // // Create new tiles // newTopology.addTile(triangle[0], newNodes[0], newNodes[2]); newTopology.addTile(triangle[1], newNodes[1], newNodes[0]); newTopology.addTile(triangle[2], newNodes[2], newNodes[1]); newTopology.addTile(newNodes[0], newNodes[1], newNodes[2]); } // // Copy new topology to surface's topology // const int numNewTriangles = newTopology.getNumberOfTiles(); this->topologyFile->setNumberOfTiles(numNewTriangles); for (int j = 0; j < numNewTriangles; j++) { this->topologyFile->setTile(j, newTopology.getTile(j)); } this->makeSphere(); } // for (iterations... this->makeSphere(); this->surface->convertToSphereWithRadius(100.0); } /** * Make the surface a sphere. */ void BrainModelSurfacePolyhedron::makeSphere() { this->surface->orientTilesOutward(surface->getSurfaceType()); this->surface->computeNormals(); this->surface->translateToCenterOfMass(); this->surface->convertToSphereWithRadius(10000.0); }caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfacePointProjector.h0000664000175000017500000001226011572067322026306 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_BRAIN_MODEL_SURFACE_POINT_PROJECTOR_H__ #define __VE_BRAIN_MODEL_SURFACE_POINT_PROJECTOR_H__ #include class BrainModelSurface; class BrainModelSurfacePointLocator; class CoordinateFile; class TopologyFile; class TopologyHelper; /// This class is used to project points onto a BrainModelSurface. It can project to /// the nearest node or to a barycentric position in a tile. class BrainModelSurfacePointProjector { public: /// Surface type hint passed to constructor enum SURFACE_TYPE_HINT { SURFACE_TYPE_HINT_FLAT, SURFACE_TYPE_HINT_SPHERE, SURFACE_TYPE_HINT_OTHER }; /// Constructor BrainModelSurfacePointProjector(const BrainModelSurface* bmsIn, const SURFACE_TYPE_HINT surfaceTypeHintIn, const bool surfaceMayHaveNodesAddedToIt); /// Destructor ~BrainModelSurfacePointProjector(); /// project to nearest node int projectToNearestNode(const float xyz[3]); /// barycentric projection (returns tile node projects to else negative) int projectBarycentric(const float xyz[3], int& nearestNodeNumberOut, int tileNodesOut[3], float barycentricOut[3], const bool checkNeighbors = true); /// barycentric projection to nearest tile but may not be within the tile int projectBarycentricNearestTile(const float xyz[3], int& nearestTileNumberOut, int tileNodesOut[3], float barycentricOut[3], float& signedDistanceOut, float& distanceToTile, float distanceComponents[3]); /// barycentric projection to the "best" tile (2D only) int projectBarycentricBestTile2D(const float xyz[3], int& nearestTileNumberOut, int tileNodesOut[3], float barycentricOut[3]); /// unproject using the specified coordinate file static void unprojectPoint(const int tileNodes[3], const float tileAreas[3], const CoordinateFile* cf, float xyzOut[3]); private: /// Status of the search (degenerate is on an edge, vertex, or "just" outside the tile) enum SEARCH_STATUS { TILE_NOT_FOUND, TILE_FOUND, TILE_FOUND_DEGENERATE }; /// see if a point is in any of the files used by a node. void checkPointInNodesTiles(const TopologyHelper* topologyHelper, const int nodeNumber); /// see if the point "xyz" is within the tile "tileNumber" void checkPointInTile(const int tileNumber); /// compute areas formed by assuming xyz is within the triangle formed by p1, p2, p3 int triangleAreas(const float* p1, const float* p2, const float* p3, const float* normal, const float* xyz, float& area1, float& area2, float& area3); /// point locator for BrainModelSurface BrainModelSurfacePointLocator* pointLocator; /// coordinate file const CoordinateFile* coordinateFile; /// topology file const TopologyFile* topologyFile; /// the surface type hint SURFACE_TYPE_HINT surfaceTypeHint; /// inside triangle tolerance float tileAreaTolerance; /// "on" the node tolerance float nearestNodeToleranceSquared; /// tiles that have been searched in barycentric mode std::set barycentricSearchedTiles; /// the search status (used in barycentric searching) SEARCH_STATUS barycentricSearchStatus; /// tile found in barycentric mode int barycentricTile; /// nodes of tile found in barycentric mode int barycentricNodes[3]; /// barycentric areas of tile found in barycentric mode float barycentricAreas[3]; /// the query point for barycentric mode float barycentricQueryPoint[3]; }; #endif // __VE_BRAIN_MODEL_SURFACE_POINT_PROJECTOR_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfacePointProjector.cxx0000664000175000017500000005612111572067322026665 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include // needed for Q_OS_WIN32 #ifdef Q_OS_WIN32 // required for M_PI in #define NOMINMAX #endif #include #include #include #include "BrainModelSurface.h" #include "BrainModelSurfacePointLocator.h" #include "BrainModelSurfacePointProjector.h" #include "MathUtilities.h" #include "TopologyFile.h" #include "TopologyHelper.h" #include "vtkMath.h" #include "vtkPlane.h" #include "vtkTriangle.h" /** * Constructor. * Set "surfaceMayHaveNodesAddedToIt" if the surface will have nodes added to it * after constructing this object. */ BrainModelSurfacePointProjector::BrainModelSurfacePointProjector( const BrainModelSurface* bmsIn, const SURFACE_TYPE_HINT surfaceTypeHintIn, const bool surfaceMayHaveNodesAddedToIt) : coordinateFile(bmsIn->getCoordinateFile()), // initialize const members topologyFile(bmsIn->getTopologyFile()) { surfaceTypeHint = surfaceTypeHintIn; // // Create a point locator for connected nodes // pointLocator = new BrainModelSurfacePointLocator(bmsIn, true, surfaceMayHaveNodesAddedToIt); nearestNodeToleranceSquared = 0.01 * 0.01; tileAreaTolerance = -0.01; switch (surfaceTypeHint) { case SURFACE_TYPE_HINT_FLAT: case SURFACE_TYPE_HINT_SPHERE: break; case SURFACE_TYPE_HINT_OTHER: { // // see if coordinate file is flat to speed up queries // const int numCoords = coordinateFile->getNumberOfCoordinates(); bool isFlat = true; for (int i = 0; i < numCoords; i++) { const float* xyz = coordinateFile->getCoordinate(i); if (xyz[2] != 0.0) { isFlat = false; break; } } if (isFlat) { surfaceTypeHint = SURFACE_TYPE_HINT_FLAT; } } } } /** * Destructor. */ BrainModelSurfacePointProjector::~BrainModelSurfacePointProjector() { if (pointLocator != NULL) delete pointLocator; pointLocator = NULL; } /** * Project to nearest node. Returns nearest node number of negative if surface * had no nodes. */ int BrainModelSurfacePointProjector::projectToNearestNode(const float xyz[3]) { return pointLocator->getNearestPoint(xyz); } /** * Project to the nearest tile. First, a barycentric projection is performed. If the query * point projects into a tile, a positive number is returned. If the query point does not project * into a tile, the tile nearest to the query point will be determined and a negative number * is returned. If there are no tiles, zero is returned. */ int BrainModelSurfacePointProjector::projectBarycentricNearestTile(const float xyz[3], int& nearestTileNumberOut, int tileNodesOut[3], float barycentricOut[3], float& signedDistanceOut, float& distanceToTileOut, float distanceToTileComponentsOut[3]) { int nearestNodeNumber = -1; nearestTileNumberOut = -1; // // Try a normal barycentric mode projection first // nearestTileNumberOut = projectBarycentric(xyz, nearestNodeNumber, tileNodesOut, barycentricOut, true); // // Did query point project successfully to a tile // if (nearestTileNumberOut >= 0) { // // Coordinates of tile // const float* p1 = coordinateFile->getCoordinate(tileNodesOut[0]); const float* p2 = coordinateFile->getCoordinate(tileNodesOut[1]); const float* p3 = coordinateFile->getCoordinate(tileNodesOut[2]); // // Tile's normal // float normal[3]; MathUtilities::computeNormal((float*)p1, (float*)p2, (float*)p3, normal); /* // // Project query point onto tile's plane // float projectedOntoTile[3]; vtkPlane::ProjectPoint((float*)xyz, (float*)p1, normal, projectedOntoTile); // // Distance from query point to tile // distanceToTileOut = vtkPlane::DistanceToPlane((float*)xyz, normal, projectedOntoTile); const float dx = normal[0] * (xyz[0] - projectedOntoTile[0]); const float dy = normal[1] * (xyz[1] - projectedOntoTile[1]); const float dz = normal[2] * (xyz[2] - projectedOntoTile[2]); const float signedDistance = dx + dy + dz; std::cout << "distance: " << distanceToTileOut << " signed: " << signedDistance << std::endl; */ // // get signed distance to plane from query point // signedDistanceOut = MathUtilities::signedDistanceToPlane(normal, p1, xyz); distanceToTileOut = fabs(signedDistanceOut); // // Determine distance and components from query point to tile // distanceToTileComponentsOut[0] = normal[0] * signedDistanceOut; distanceToTileComponentsOut[1] = normal[1] * signedDistanceOut; distanceToTileComponentsOut[2] = normal[2] * signedDistanceOut; return 1; } else { // // Look through searched tiles to find the one closest to the query point // for (std::set::iterator iter = barycentricSearchedTiles.begin(); iter != barycentricSearchedTiles.end(); iter++) { const int tileNumber = *iter; // // Determine components magnitude of distance and from query point to tile // int v1, v2, v3; topologyFile->getTile(tileNumber, v1, v2, v3); const float* p1 = coordinateFile->getCoordinate(v1); const float* p2 = coordinateFile->getCoordinate(v2); const float* p3 = coordinateFile->getCoordinate(v3); // // Tile's normal // float normal[3]; MathUtilities::computeNormal((float*)p1, (float*)p2, (float*)p3, normal); /* // // Project query point onto tile's plane // float projectedOntoTile[3]; vtkPlane::ProjectPoint((float*)xyz, (float*)p1, normal, projectedOntoTile); // // Distance from query point to tile // const float distance = vtkPlane::DistanceToPlane((float*)xyz, normal, projectedOntoTile); */ // // get signed distance to plane from query point // signedDistanceOut = MathUtilities::signedDistanceToPlane(normal, p1, xyz); const float distance = fabs(signedDistanceOut); // // Determine distance and components from query point to tile // float distComponents[3]; distComponents[0] = normal[0] * signedDistanceOut; distComponents[1] = normal[1] * signedDistanceOut; distComponents[2] = normal[2] * signedDistanceOut; if ((nearestTileNumberOut < 0) || (distance < distanceToTileOut)) { nearestTileNumberOut = tileNumber; distanceToTileOut = distance; distanceToTileComponentsOut[0] = distComponents[0]; distanceToTileComponentsOut[1] = distComponents[1]; distanceToTileComponentsOut[2] = distComponents[2]; } } if (nearestTileNumberOut >= 0) { return -1; } } // // Should never get here unless there are no tiles // return 0; } /** * Project barycentric to "best" tile (must have passed barycentricMode = true to constructor). * First, finds the nearest node to the query point. Next, for each tile used by the nearest * node, the total distances to the three nodes of the tile are determined. The tile with the * smallest of these distances is the "best" tile. This is used by flat multiresolution * morphing and this method may only be appropriate for flat surfaces. Returns negative * if there are no tiles or greater than or equal to zero upon success. * * This is essentially "interpolate_surface" from caret4. */ int BrainModelSurfacePointProjector::projectBarycentricBestTile2D(const float xyz[3], int& nearestTileNumberOut, int tileNodesOut[3], float barycentricOut[3]) { nearestTileNumberOut = -1; tileNodesOut[0] = -1; tileNodesOut[1] = -1; tileNodesOut[2] = -1; barycentricOut[0] = 0.0; barycentricOut[1] = 0.0; barycentricOut[2] = 0.0; // // generate topology info for node without sorting. // const TopologyHelper* topologyHelper = topologyFile->getTopologyHelper(false, true, false); // // Find node closest to the point // const int nearestNodeNumberOut = pointLocator->getNearestPoint(xyz); if (nearestNodeNumberOut >= 0) { // // Find tiles used by this node // std::vector nodesTiles; topologyHelper->getNodeTiles(nearestNodeNumberOut, nodesTiles); nearestTileNumberOut = -1; float closestDistance = std::numeric_limits::max(); // // Check each tile // for (int tileIndex = 0; tileIndex < static_cast(nodesTiles.size()); tileIndex++) { // // Get the nodes of the tile // const int tile = nodesTiles[tileIndex]; int n1, n2, n3; topologyFile->getTile(tile, n1, n2, n3); // // Distance squared to each of the tile's nodes // const float d1 = coordinateFile->getDistanceToPointSquared(n1, xyz); const float d2 = coordinateFile->getDistanceToPointSquared(n2, xyz); const float d3 = coordinateFile->getDistanceToPointSquared(n3, xyz); // // "Mean" distance to the three nodes // const float dist = std::sqrt(d1*d1 + d2*d2 + d3*d3); // // Check to see if this tile is "better" // if ((nearestTileNumberOut < 0) || (dist < closestDistance)) { nearestTileNumberOut = tile; closestDistance = dist; } } // // If a tile was found // if (nearestTileNumberOut >= 0) { // // Get the coordinate of the nodes of the best tile // topologyFile->getTile(nearestTileNumberOut, tileNodesOut); const float* p1 = coordinateFile->getCoordinate(tileNodesOut[0]); const float* p2 = coordinateFile->getCoordinate(tileNodesOut[1]); const float* p3 = coordinateFile->getCoordinate(tileNodesOut[2]); // // Determine barycentric areas // barycentricOut[0] = (MathUtilities::signedTriangleArea2D(p1, xyz, p2)); barycentricOut[1] = (MathUtilities::signedTriangleArea2D(p2, xyz, p3)); barycentricOut[2] = (MathUtilities::signedTriangleArea2D(p3, xyz, p1)); return nearestNodeNumberOut; } } // // Tile not found // return -1; } /** * Barycentric projection to tile (must have passed barycentricMode = true to constructor). * Returns the index of the tile the points projects to or negative if the point does not * project to a tile. */ int BrainModelSurfacePointProjector::projectBarycentric(const float xyz[3], int& nearestNodeNumberOut, int tileNodesOut[3], float barycentricOut[3], const bool checkNeighbors) { // // generate topology info for node without sorting. // const TopologyHelper* topologyHelper = topologyFile->getTopologyHelper(false, true, false); barycentricQueryPoint[0] = xyz[0]; barycentricQueryPoint[1] = xyz[1]; barycentricQueryPoint[2] = xyz[2]; barycentricTile = -1; barycentricNodes[0] = -1; barycentricNodes[1] = -1; barycentricNodes[2] = -1; barycentricAreas[0] = 0.0; barycentricAreas[1] = 0.0; barycentricAreas[2] = 0.0; // // reset tiles that have been searched // barycentricSearchedTiles.clear(); // // Find node closest to the point // nearestNodeNumberOut = pointLocator->getNearestPoint(xyz); // // Reset the search status // barycentricSearchStatus = TILE_NOT_FOUND; // // Search the tiles used by the nearest node first. // checkPointInNodesTiles(topologyHelper, nearestNodeNumberOut); // // If projection point not found in tiles using node closest to query point or // found degenerately, keep searching // if ((barycentricSearchStatus != TILE_FOUND) && (checkNeighbors)) { if (barycentricSearchStatus == TILE_FOUND_DEGENERATE) { //std::cout << "Query point degenerately in nearest node's neighboring tiles." << std::endl; } else { //std::cout << "Query point not found in nearest node's neighboring tiles." << std::endl; } // // Check neighboring nodes of node nearest to query point // std::vector neighbors; topologyHelper->getNodeNeighbors(nearestNodeNumberOut, neighbors); const int numNeighbors = static_cast(neighbors.size()); for (int i = 0; i < numNeighbors; i++) { checkPointInNodesTiles(topologyHelper, neighbors[i]); if (barycentricSearchStatus == TILE_FOUND) { break; } } } // // Might be "on" the nearest node // if (barycentricSearchStatus == TILE_NOT_FOUND) { if (vtkMath::Distance2BetweenPoints(barycentricQueryPoint, (float*)coordinateFile->getCoordinate(nearestNodeNumberOut)) <= nearestNodeToleranceSquared) { barycentricSearchStatus = TILE_FOUND; barycentricNodes[0] = nearestNodeNumberOut; barycentricNodes[1] = nearestNodeNumberOut; barycentricNodes[2] = nearestNodeNumberOut; barycentricAreas[0] = 0.0; barycentricAreas[1] = 1.0; barycentricAreas[2] = 0.0; std::cout << "Point is on nearest node." << std::endl; } } // // Should not need to search remaining tiles // if (barycentricSearchStatus == TILE_NOT_FOUND) { //std::cout << "IMPLEMENT: Query point not found in neighboring nodes' tiles." << std::endl; // // Find nodes that are within X distance of the node // // // Search all remaining tiles // } tileNodesOut[0] = barycentricNodes[0]; tileNodesOut[1] = barycentricNodes[1]; tileNodesOut[2] = barycentricNodes[2]; barycentricOut[0] = barycentricAreas[0]; barycentricOut[1] = barycentricAreas[1]; barycentricOut[2] = barycentricAreas[2]; return barycentricTile; } /** * See if a point is in the tiles used by this node. */ void BrainModelSurfacePointProjector::checkPointInNodesTiles(const TopologyHelper* topologyHelper, const int nodeNumber) { // // Get the tiles used by the closest node // std::vector tiles; topologyHelper->getNodeTiles(nodeNumber, tiles); const int numTiles = static_cast(tiles.size()); for (int i = 0; i < numTiles; i++) { checkPointInTile(tiles[i]); // // If all areas positive, terminate search. // if (barycentricSearchStatus == TILE_FOUND) { break; } } } /** * See if the point "xyz" is within tile "tileNumber". */ void BrainModelSurfacePointProjector::checkPointInTile(const int tileNumber) { // // See if this tile has been searched before. // if (barycentricSearchedTiles.find(tileNumber) != barycentricSearchedTiles.end()) { return; } barycentricSearchedTiles.insert(tileNumber); // // Get the vertices of the triangle // int v1, v2, v3; topologyFile->getTile(tileNumber, v1, v2, v3); const float* p1 = coordinateFile->getCoordinate(v1); const float* p2 = coordinateFile->getCoordinate(v2); const float* p3 = coordinateFile->getCoordinate(v3); float normal[3]; float queryPoint[3]; switch (surfaceTypeHint) { case SURFACE_TYPE_HINT_FLAT: normal[0] = 0.0; normal[1] = 0.0; normal[2] = 1.0; queryPoint[0] = barycentricQueryPoint[0]; queryPoint[1] = barycentricQueryPoint[1]; queryPoint[2] = barycentricQueryPoint[2]; break; case SURFACE_TYPE_HINT_SPHERE: { // // See if a ray from the origin to the query point intersects // the plane of the triangle, and, if so, where // float origin[3] = { 0.0, 0.0, 0.0 }; if (MathUtilities::rayIntersectPlane(p1, p2, p3, origin, barycentricQueryPoint, queryPoint) == false) { // // Ray from origin to query point is parallel to the plane // return; } // // Normal of tile // MathUtilities::computeNormal((float*)p1, (float*)p2, (float*)p3, normal); } break; case SURFACE_TYPE_HINT_OTHER: // // Project point onto the plane of the tile // MathUtilities::computeNormal((float*)p1, (float*)p2, (float*)p3, normal); #ifdef HAVE_VTK5 { double dn[3] = { normal[0], normal[1], normal[2] }; double db[3] = { barycentricQueryPoint[0], barycentricQueryPoint[1], barycentricQueryPoint[2] }; double dp[3] = { p1[0], p1[1], p1[2] }; double dq[3]; vtkPlane::ProjectPoint(db, dp, dn, dq); queryPoint[0] = dq[0]; queryPoint[1] = dq[1]; queryPoint[2] = dq[2]; } #else // HAVE_VTK5 vtkPlane::ProjectPoint((float*)barycentricQueryPoint, (float*)p1, normal, queryPoint); #endif // HAVE_VTK5 break; } float area1, area2, area3; // // 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. // const int result = triangleAreas(p1, p2, p3, normal, queryPoint, area1, area2, area3); if (result != 0) { if (result > 0) { barycentricSearchStatus = TILE_FOUND; } else { barycentricSearchStatus = TILE_FOUND_DEGENERATE; } barycentricTile = tileNumber; barycentricNodes[0] = v1; barycentricNodes[1] = v2; barycentricNodes[2] = v3; barycentricAreas[0] = area1; barycentricAreas[1] = area2; barycentricAreas[2] = area3; } } /** * 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. * * Returns 1 if all areas are positive (point inside the triangle). * Returns -1 if all areas are greater than the tolerance (point may be on edge or vertex) * Returns 0 if not in the triangle. */ int BrainModelSurfacePointProjector::triangleAreas(const float* p1, const float* p2, const float* p3, const float* normal, const float* xyz, float& area1, float& area2, float& area3) { int result = 0; float triangleArea = 0.0; bool inside = false; switch (surfaceTypeHint) { case SURFACE_TYPE_HINT_FLAT: area1 = MathUtilities::signedTriangleArea2D(p1, p2, xyz); if (area1 > tileAreaTolerance) { area2 = MathUtilities::signedTriangleArea2D(p2, p3, xyz); if (area2 > tileAreaTolerance) { area3 = MathUtilities::signedTriangleArea2D(p3, p1, xyz); if (area3 > tileAreaTolerance) { inside = true; triangleArea = MathUtilities::signedTriangleArea2D(p1, p2, p3); } } } break; case SURFACE_TYPE_HINT_SPHERE: case SURFACE_TYPE_HINT_OTHER: area1 = MathUtilities::signedTriangleArea3D(normal, p1, p2, xyz); if (area1 >= tileAreaTolerance) { area2 = MathUtilities::signedTriangleArea3D(normal, p2, p3, xyz); if (area2 >= tileAreaTolerance) { area3 = MathUtilities::signedTriangleArea3D(normal, p3, p1, xyz); if (area3 >= tileAreaTolerance) { inside = true; triangleArea = MathUtilities::triangleArea((float*)p1, (float*)p2, (float*)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.0; area2 = 0.0; area3 = 0.0; } } return result; } void BrainModelSurfacePointProjector::unprojectPoint(const int tileNodes[3], const float tileAreas[3], const CoordinateFile* cf, float xyzOut[3]) { const float* v1 = cf->getCoordinate(tileNodes[0]); const float* v2 = cf->getCoordinate(tileNodes[1]); const float* v3 = cf->getCoordinate(tileNodes[2]); const float totalArea = tileAreas[0] + tileAreas[1] + tileAreas[2]; if (totalArea != 0.0) { xyzOut[0] = (v1[0] * tileAreas[1] + v2[0] * tileAreas[2] + v3[0] * tileAreas[0]) / totalArea; xyzOut[1] = (v1[1] * tileAreas[1] + v2[1] * tileAreas[2] + v3[1] * tileAreas[0]) / totalArea; xyzOut[2] = (v1[2] * tileAreas[1] + v2[2] * tileAreas[2] + v3[2] * tileAreas[0]) / totalArea; } else { xyzOut[0] = v1[0]; xyzOut[1] = v1[1]; xyzOut[2] = v1[2]; } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfacePointLocator.h0000664000175000017500000000560211572067322025744 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_BRAIN_MODEL_SURFACE_POINT_LOCATOR_H__ #define __VE_BRAIN_MODEL_SURFACE_POINT_LOCATOR_H__ #include class BrainModelSurface; class CoordinateFile; class vtkPointLocator; class vtkPoints; class vtkPolyData; /// This class is used to quickly find the nearest point (node) in a BrainModelSurface. It /// should be used when multiple queries will be made. class BrainModelSurfacePointLocator { public: /// Constructor BrainModelSurfacePointLocator(const BrainModelSurface* bmsin, const bool limitToConnectedNodes, const bool nodesMayBeAddedToSurfaceIn = false, const std::vector* limitToTheseNodes = NULL); /// Destructor ~BrainModelSurfacePointLocator(); /// find point nearest to location (returns negative BrainModelSurface is empty) int getNearestPoint(const float xyz[3]); /// find points within the specified radius of the location void getPointsWithinRadius(const float xyz[3], const float radius, std::vector& nearbyPointsOut); private: /// the point locator vtkPointLocator* locator; /// the points vtkPoints* points; /// data set for the points vtkPolyData* polyData; /// If we are limited to connected nodes, only connected nodes will be placed into the /// point locator. "pointIndexToNodeIndex" keeps track of this relationship. std::vector pointIndexToNodeIndex; /// nodes may be added to the surface after this object is constructed bool nodesMayBeAddedToSurface; /// number of nodes in object passed to constructor int originalNumberOfNodes; /// the surface's coordinate file (DO NOT DELETE IN DESTRUCTOR) const CoordinateFile* coordFile; }; #endif // __VE_BRAIN_MODEL_SURFACE_POINT_LOCATOR_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfacePointLocator.cxx0000664000175000017500000001713511572067322026323 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurface.h" #include "BrainModelSurfacePointLocator.h" #include "TopologyFile.h" #include "vtkIdList.h" #include "vtkMath.h" #include "vtkPointLocator.h" /** * Constructor. * * If "limitToConnectedNodes" is set, only those nodes who are used in the * BrainModelSurface's tiles will be searched. * * If "limitToTheseNodes" is not NULL and has the same number of elements as * there are nodes in the BrainModelSurface, nodes with limitToTheseNodes[] * equal to false will not be searched. * * "nodesMayBeAddedToSurfaceIn" should be set if nodes will be added to the * surface after this object is constructed. */ BrainModelSurfacePointLocator::BrainModelSurfacePointLocator(const BrainModelSurface* bms, const bool limitToConnectedNodes, const bool nodesMayBeAddedToSurfaceIn, const std::vector* limitToTheseNodes) : coordFile(bms->getCoordinateFile()) { locator = NULL; points = NULL; polyData = NULL; //const CoordinateFile* coordFile = bms->getCoordinateFile(); const int numPoints = coordFile->getNumberOfCoordinates(); if (numPoints <= 0) { return; } // // Find out if surface will have nodes added to it after this object is constructed // nodesMayBeAddedToSurface = nodesMayBeAddedToSurfaceIn; originalNumberOfNodes = numPoints; // // If necessary, keep track of which nodes are connected // std::vector useThisNode(numPoints, false); if (limitToConnectedNodes) { const TopologyFile* topoFile = bms->getTopologyFile(); const int numTiles = topoFile->getNumberOfTiles(); for (int i = 0; i < numTiles; i++) { int v1, v2, v3; topoFile->getTile(i, v1, v2, v3); useThisNode[v1] = true; useThisNode[v2] = true; useThisNode[v3] = true; } } else { std::fill(useThisNode.begin(), useThisNode.end(), true); } // // if additional node restrictions // if (limitToTheseNodes != NULL) { if (static_cast(limitToTheseNodes->size()) == numPoints) { for (int i = 0; i < numPoints; i++) { if ((*limitToTheseNodes)[i] == false) { useThisNode[i] = false; } } } } // // Add the nodes to the point locator // int counter = 0; points = vtkPoints::New(); for (int i = 0; i < numPoints; i++) { if (useThisNode[i]) { float xyz[3]; coordFile->getCoordinate(i, xyz); points->InsertPoint(counter, xyz); counter++; pointIndexToNodeIndex.push_back(i); } } polyData = vtkPolyData::New(); polyData->SetPoints(points); locator = vtkPointLocator::New(); locator->Initialize(); locator->SetDataSet(polyData); locator->BuildLocator(); } /* * Destructor */ BrainModelSurfacePointLocator::~BrainModelSurfacePointLocator() { if (locator != NULL) { locator->Delete(); locator = NULL; } if (polyData != NULL) { polyData->Delete(); polyData = NULL; } if (points != NULL) { points->Delete(); points = NULL; } } /** * find point nearest to location (returns negative BrainModelSurface is empty) */ int BrainModelSurfacePointLocator::getNearestPoint(const float xyz[3]) { int closestNodeIndex = -1; if (locator != NULL) { #ifdef HAVE_VTK5 double d[3] = { xyz[0], xyz[1], xyz[2] }; const int num = locator->FindClosestPoint(d); #else // HAVE_VTK5 const int num = locator->FindClosestPoint((float*)xyz); #endif // HAVE_VTK5 if (num >= 0) { closestNodeIndex = pointIndexToNodeIndex[num]; } } // // Is is possible that nodes have been added to the surface // if (nodesMayBeAddedToSurface) { // // Have nodes been added to the surface // if (originalNumberOfNodes < coordFile->getNumberOfCoordinates()) { // // Use coordinate file to find nearest node in the nodes that have been added // const int closestNewNodeIndex = coordFile->getCoordinateIndexClosestToPoint(xyz[0], xyz[1], xyz[2], originalNumberOfNodes); // // Figure out which closest node to use // if (closestNewNodeIndex >= 0) { if (closestNodeIndex < 0) { closestNodeIndex = closestNewNodeIndex; } else { const float newCoordDist = vtkMath::Distance2BetweenPoints(xyz, coordFile->getCoordinate(closestNewNodeIndex)); const float oldCoordDist = vtkMath::Distance2BetweenPoints(xyz, coordFile->getCoordinate(closestNodeIndex)); if (newCoordDist < oldCoordDist) { closestNodeIndex = closestNewNodeIndex; } } } } } return closestNodeIndex; } /** * Find points within a specified radius of the location. */ void BrainModelSurfacePointLocator::getPointsWithinRadius(const float xyz[3], const float radius, std::vector& nearbyPointsOut) { nearbyPointsOut.clear(); vtkIdList* idList = vtkIdList::New(); // // Find nearby points with the vtk locator // #ifdef HAVE_VTK5 double xyzD[3] = { xyz[0], xyz[1], xyz[2] }; locator->FindPointsWithinRadius(radius, xyzD, idList); #else // HAVE_VTK5 locator->FindPointsWithinRadius(radius, xyz, idList); #endif // HAVE_VTK5 const int numIDs = idList->GetNumberOfIds(); if (numIDs > 0) { for (int i = 0; i < numIDs; i++) { nearbyPointsOut.push_back(pointIndexToNodeIndex[idList->GetId(i)]); } } // Is is possible that nodes have been added to the surface // if (nodesMayBeAddedToSurface) { // // Have nodes been added to the surface // const int newNumberOfNodes = coordFile->getNumberOfCoordinates(); if (originalNumberOfNodes < newNumberOfNodes) { const float radiusSquared = radius * radius; // // Examine nodes that have been added to the surface // for (int i = originalNumberOfNodes; i < newNumberOfNodes; i++) { const float* coordXYZ = coordFile->getCoordinate(i); const float distSquared = vtkMath::Distance2BetweenPoints(xyz, coordXYZ); if (distSquared < radiusSquared) { nearbyPointsOut.push_back(i); } } } } if (idList != NULL) idList->Delete(); } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfacePaintToBorderConverter.h0000664000175000017500000000403411572067322027731 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_PAINT_TO_BORDER_CONVERTER_H__ #define __BRAIN_MODEL_SURFACE_PAINT_TO_BORDER_CONVERTER_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelAlgorithm.h" class BrainModelSurface; class PaintFile; /// algorithm that creates borders around each paint region class BrainModelSurfacePaintToBorderConverter : public BrainModelAlgorithm { public: // constructor BrainModelSurfacePaintToBorderConverter(BrainSet* brainSetIn, BrainModelSurface* bmsIn, PaintFile* paintFileIn, const int paintFileColumnIn); // destructor ~BrainModelSurfacePaintToBorderConverter(); // execute the algorithm void execute() throw (BrainModelAlgorithmException); protected: // the surface BrainModelSurface* bms; // the paint file PaintFile* paintFile; // the paint file column int paintFileColumn; // the border file BorderFile* borderFile; }; #endif // __BRAIN_MODEL_SURFACE_PAINT_TO_BORDER_CONVERTER_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfacePaintToBorderConverter.cxx0000664000175000017500000002012711572067322030305 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "AreaColorFile.h" #include "BorderColorFile.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceClusterToBorderConverter.h" #include "BrainModelSurfaceConnectedSearchPaint.h" #include "BrainModelSurfacePaintToBorderConverter.h" #include "BrainModelSurfaceROINodeSelection.h" #include "BrainSet.h" #include "PaintFile.h" /** * constructor. */ BrainModelSurfacePaintToBorderConverter::BrainModelSurfacePaintToBorderConverter( BrainSet* brainSetIn, BrainModelSurface* bmsIn, PaintFile* paintFileIn, const int paintFileColumnIn) : BrainModelAlgorithm(brainSetIn) { bms = bmsIn; paintFile = paintFileIn; paintFileColumn = paintFileColumnIn; } /** * destructor. */ BrainModelSurfacePaintToBorderConverter::~BrainModelSurfacePaintToBorderConverter() { } /** * execute the algorithm. */ void BrainModelSurfacePaintToBorderConverter::execute() throw (BrainModelAlgorithmException) { // // Check inputs // if (bms == NULL) { throw BrainModelAlgorithmException("ERROR: No surface provided."); } const int numNodes = bms->getNumberOfNodes(); if (numNodes <= 0) { throw BrainModelAlgorithmException("ERROR: The surface contains no nodes."); } TopologyFile* topologyFile = bms->getTopologyFile(); if (topologyFile == NULL) { throw BrainModelAlgorithmException("ERROR: Surface has no topology."); } if (paintFile == NULL) { throw BrainModelAlgorithmException("ERROR: No Paint file provided."); } if ((paintFileColumn < 0) || (paintFileColumn >= paintFile->getNumberOfColumns())) { throw BrainModelAlgorithmException("ERROR: Invalid paint file column."); } // // Keep track of nodes that have been searched // std::vector nodeHasBeenSearched(numNodes, false); // // Loop through the nodes to find the paints that are to be searched // exclude ??? // const int questionIndex = paintFile->getPaintIndexFromName("???"); std::set paintIndicesForSearching; for (int i = 0; i < numNodes; i++) { const int indx = paintFile->getPaint(i, paintFileColumn); if (indx != questionIndex) { paintIndicesForSearching.insert(indx); } } // // Will keep track of border colors that are needed // std::set borderColorsNeeded; // // Loop through the paint indices // for (std::set::iterator iter = paintIndicesForSearching.begin(); iter != paintIndicesForSearching.end(); iter++) { // // Index of paint for which we will search // const int paintIndex = *iter; // // Loop through the nodes // for (int i = 0; i < numNodes; i++) { // // Has this node NOT been checked // if (nodeHasBeenSearched[i] == false) { // // Does it have the paint index we are seeking // if (paintFile->getPaint(i, paintFileColumn) == paintIndex) { // // Mark this node searched // nodeHasBeenSearched[i] = true; // // Do a connected search // BrainModelSurfaceConnectedSearchPaint paintSearch(brainSet, bms, i, paintFile, paintFileColumn, paintIndex); paintSearch.execute(); // // Get the connected nodes found // BrainModelSurfaceROINodeSelection paintROI(brainSet); paintROI.update(); paintROI.deselectAllNodes(); bool atLeastOneNodeInCluster = false; for (int j = 0; j < numNodes; j++) { if (paintSearch.getNodeConnected(j)) { // // Have at least on node in the cluster // atLeastOneNodeInCluster = true; // // Mark node has been searched // nodeHasBeenSearched[j] = true; // // Mark node in the cluster // paintROI.setNodeSelected(j, 1); } } // // If nodes are found // if (atLeastOneNodeInCluster) { // // Create a border around the cluster // BrainModelSurfaceClusterToBorderConverter borderGenerator(brainSet, bms, topologyFile, paintFile->getPaintNameFromIndex(paintIndex), &paintROI, false); borderGenerator.execute(); // // Will need a border colors // borderColorsNeeded.insert(paintFile->getPaintNameFromIndex(paintIndex)); } } } } } // // Add any needed border colors // AreaColorFile* acf = brainSet->getAreaColorFile(); BorderColorFile* bcf = brainSet->getBorderColorFile(); for (std::set::iterator iter = borderColorsNeeded.begin(); iter != borderColorsNeeded.end(); iter++) { const QString colorName(*iter); // // Find area color // bool areaColorMatch = false; const int areaColorIndex = acf->getColorIndexByName(colorName, areaColorMatch); // // Find border color // bool borderColorMatch = false; const int borderColorIndex = bcf->getColorIndexByName(colorName, borderColorMatch); // // If border color does not exist // if ((borderColorIndex < 0) || (borderColorMatch == false)) { // // If there is an area color // if (areaColorIndex >= 0) { // // Transfer the area color to the border color // float pointSize, lineSize; acf->getPointLineSizeByIndex(areaColorIndex, pointSize, lineSize); unsigned char r, g, b, a; acf->getColorByIndex(areaColorIndex, r, g, b, a); bcf->addColor(colorName, r, g, b, a, pointSize, lineSize); } } } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfacePaintSulcalIdentification.h0000664000175000017500000000756111572067322030426 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_PAINT_SULCAL_IDENTIFICATION_H__ #define __BRAIN_MODEL_SURFACE_PAINT_SULCAL_IDENTIFICATION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelAlgorithm.h" class AreaColorFile; class BrainModelSurface; class MetricFile; class PaintFile; class SurfaceShapeFile; class VocabularyFile; class VolumeFile; /// generate paint sulcal identication class BrainModelSurfacePaintSulcalIdentification : public BrainModelAlgorithm { public: // constructor BrainModelSurfacePaintSulcalIdentification(BrainSet* bs, const BrainModelSurface* fiducialSurfaceIn, const BrainModelSurface* inflatedSurfaceIn, const BrainModelSurface* veryInflatedSurfaceIn, PaintFile* paintFileInOut, const int paintFileGeographyColumnNumberIn, AreaColorFile* areaColorFileInOut, const SurfaceShapeFile* depthSurfaceShapeFileIn, const int depthSurfaceShapeFileColumnNumberIn, VocabularyFile* vocabularyFileOut); // destructor ~BrainModelSurfacePaintSulcalIdentification(); // execute the algorithm void execute() throw (BrainModelAlgorithmException); /// get probabilistic metric file of sulci locations const MetricFile* getMetricFile() const { return metricFile; } /// get paint file containing the sulcal identification const PaintFile* getPaintFile() const { return paintFile; } /// get area color file containing paint sulcal identification const AreaColorFile* getAreaColorFile() const { return areaColorFile; } // get the name of the Sulcus ID paint column static QString getSulcusIdPaintColumnName(); protected: /// fiducila surface const BrainModelSurface* fiducialSurface; /// inflated surface const BrainModelSurface* inflatedSurface; /// very inflated surface const BrainModelSurface* veryInflatedSurface; /// input paint file containing geography paint column PaintFile* paintFile; /// column number of geography in paint file const int paintFileGeographyColumnNumber; /// area color file AreaColorFile* areaColorFile; /// surface shape file containing depth information const SurfaceShapeFile* depthSurfaceShapeFile; /// surface shape file depth column number const int depthSurfaceShapeFileColumnNumber; /// vocabulary file VocabularyFile* vocabularyFile; /// probabilistic metric file MetricFile* metricFile; /// left hemisphere flag bool leftHemisphereFlag; }; #endif // __BRAIN_MODEL_SURFACE_PAINT_SULCAL_IDENTIFICATION_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfacePaintSulcalIdentification.cxx0000664000175000017500000001546511572067322031003 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "AreaColorFile.h" #include "BorderColorFile.h" #include "BorderProjectionFile.h" #include "BrainModelSurface.h" #include "BrainModelSurfacePaintSulcalIdentification.h" #include "BrainModelSurfaceSulcalIdentificationProbabilistic.h" #include "BrainSet.h" #include "FociColorFile.h" #include "FociProjectionFile.h" #include "MetricFile.h" #include "PaintFile.h" #include "SurfaceShapeFile.h" #include "VocabularyFile.h" #include "VolumeFile.h" /** * constructor. */ BrainModelSurfacePaintSulcalIdentification::BrainModelSurfacePaintSulcalIdentification( BrainSet* bs, const BrainModelSurface* fiducialSurfaceIn, const BrainModelSurface* inflatedSurfaceIn, const BrainModelSurface* veryInflatedSurfaceIn, PaintFile* paintFileInOut, const int paintFileGeographyColumnNumberIn, AreaColorFile* areaColorFileInOut, const SurfaceShapeFile* depthSurfaceShapeFileIn, const int depthSurfaceShapeFileColumnNumberIn, VocabularyFile* vocabularyFileOut) : BrainModelAlgorithm(bs), fiducialSurface(fiducialSurfaceIn), inflatedSurface(inflatedSurfaceIn), veryInflatedSurface(veryInflatedSurfaceIn), paintFile(paintFileInOut), paintFileGeographyColumnNumber(paintFileGeographyColumnNumberIn), areaColorFile(areaColorFileInOut), depthSurfaceShapeFile(depthSurfaceShapeFileIn), depthSurfaceShapeFileColumnNumber(depthSurfaceShapeFileColumnNumberIn), vocabularyFile(vocabularyFileOut) { metricFile = NULL; } /** * destructor. */ BrainModelSurfacePaintSulcalIdentification::~BrainModelSurfacePaintSulcalIdentification() { if (metricFile != NULL) { delete metricFile; metricFile = NULL; } } /** * get the name of the Sulcus ID paint column. */ QString BrainModelSurfacePaintSulcalIdentification::getSulcusIdPaintColumnName() { return BrainModelSurfaceSulcalIdentificationProbabilistic::getSulcusIdPaintColumnName(); } /** * execute the algorithm. */ void BrainModelSurfacePaintSulcalIdentification::execute() throw (BrainModelAlgorithmException) { if (fiducialSurface == NULL) { throw BrainModelAlgorithmException("The fiducial surface is invalid."); } if (inflatedSurface == NULL) { throw BrainModelAlgorithmException("The inflated surface is invalid."); } if (veryInflatedSurface == NULL) { throw BrainModelAlgorithmException("The very inflated is invalid."); } if (depthSurfaceShapeFile == NULL) { throw BrainModelAlgorithmException("The surfac shape file is invalid."); } if ((depthSurfaceShapeFileColumnNumber < 0) || (depthSurfaceShapeFileColumnNumber >= depthSurfaceShapeFile->getNumberOfColumns())) { throw BrainModelAlgorithmException("Surface Shape File Depth column is invalid."); } // // Verify left or right only // leftHemisphereFlag = false; switch (fiducialSurface->getStructure().getType()) { case Structure::STRUCTURE_TYPE_CORTEX_LEFT: leftHemisphereFlag = true; break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT: leftHemisphereFlag = false; break; case Structure::STRUCTURE_TYPE_CORTEX_BOTH: case Structure::STRUCTURE_TYPE_CEREBELLUM: case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_LEFT: case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_RIGHT: case Structure::STRUCTURE_TYPE_CORTEX_LEFT_OR_CEREBELLUM: case Structure::STRUCTURE_TYPE_CORTEX_RIGHT_OR_CEREBELLUM: case Structure::STRUCTURE_TYPE_CEREBRUM_CEREBELLUM: case Structure::STRUCTURE_TYPE_SUBCORTICAL: case Structure::STRUCTURE_TYPE_ALL: case Structure::STRUCTURE_TYPE_INVALID: throw ("Structure must be left or right hemisphere."); break; } // // Validate geography paint column // if (paintFile == NULL) { throw BrainModelAlgorithmException("Geography Paint File is invalid."); } if ((paintFileGeographyColumnNumber < 0) || (paintFileGeographyColumnNumber >= paintFile->getNumberOfColumns())) { throw BrainModelAlgorithmException("Geography Paint File column is invalid."); } const QString probabilisticDirectoryFileName = (leftHemisphereFlag ? "left/PALS_B12.LEFT.PROBABILISTIC.FILE_DIRECTORY.csv" : "right/PALS_B12.RIGHT.PROBABILISTIC.FILE_DIRECTORY.csv"); const QString probabilisticSulciVolumeDirectoryFilePath = (brainSet->getCaretHomeDirectory() + "/data_files/sulcal_identification/" + probabilisticDirectoryFileName); // // Generate the probabilistic identification // BrainModelSurfaceSulcalIdentificationProbabilistic sid(brainSet, fiducialSurface, inflatedSurface, veryInflatedSurface, paintFile, paintFileGeographyColumnNumber, depthSurfaceShapeFile, depthSurfaceShapeFileColumnNumber, probabilisticSulciVolumeDirectoryFilePath); sid.execute(); // // Remove any paints from input paint that have Sulcal ID column names // const PaintFile* sulcalIdPaintFile = sid.getOutputPaintFile(); for (int i = 0; i < sulcalIdPaintFile->getNumberOfColumns(); i++) { const QString columnName = sulcalIdPaintFile->getColumnName(i); const int indx = paintFile->getColumnWithName(columnName); if (columnName >= 0) { paintFile->removeColumn(indx); } } // // Get the output files of the probabilistic identification // metricFile = new MetricFile(*sid.getOutputMetricFile()); paintFile->append(*sulcalIdPaintFile); areaColorFile->append(*sid.getOutputAreaColorFile()); vocabularyFile->append(*sid.getOutputVocabularyFile()); } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfacePaintAssignRelativeToLine.h0000664000175000017500000000637211572067322030363 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_PAINT_ASSIGN_RELATIVE_TO_LINE_H__ #define __BRAIN_MODEL_SURFACE_PAINT_ASSIGN_RELATIVE_TO_LINE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelAlgorithm.h" class BrainModelSurface; class PaintFile; /// class for assigning paint nodes relative to a line class BrainModelSurfacePaintAssignRelativeToLine : public BrainModelAlgorithm { public: // constructor BrainModelSurfacePaintAssignRelativeToLine(BrainSet* brainSetIn, BrainModelSurface * bmsIn, PaintFile* paintFileIn, const int paintFileColumnNumberIn, const int augmentPaintRegionNameIndexIn, const int newPaintNameIndexIn, const float lineStartXYZIn[3], const float lineEndXYZIn[3], const float minimumDistanceToLineIn, const float maximumDistanceToLineIn, const std::vector& limitToPaintIndicesIn, const float nodeExtentLimitIn[6]); // destructor ~BrainModelSurfacePaintAssignRelativeToLine(); // execute the algorithm void execute() throw (BrainModelAlgorithmException); protected: /// the surface BrainModelSurface * bms; /// the paint file PaintFile* paintFile; /// number of paint column int paintFileColumnNumber; /// name of region for augmenting int augmentPaintRegionNameIndex; /// index for new paint assignment int newPaintNameIndex; /// start of line float lineStartXYZ[3]; /// end of line float lineEndXYZ[3]; /// minimum distance to line float minimumDistanceToLine; /// maximum distance to line float maximumDistanceToLine; /// limit assignments to these paint indices std::vector limitToPaintIndices; /// absolute node XYZ limits float nodeExtentLimit[6]; }; #endif // __BRAIN_MODEL_SURFACE_PAINT_ASSIGN_RELATIVE_TO_LINE_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfacePaintAssignRelativeToLine.cxx0000664000175000017500000002222211572067322030726 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurface.h" #include "BrainModelSurfacePaintAssignRelativeToLine.h" #include "CoordinateFile.h" #include "MathUtilities.h" #include "PaintFile.h" #include "TopologyFile.h" #include "TopologyHelper.h" /** * constructor. */ BrainModelSurfacePaintAssignRelativeToLine::BrainModelSurfacePaintAssignRelativeToLine( BrainSet* brainSetIn, BrainModelSurface * bmsIn, PaintFile* paintFileIn, const int paintFileColumnNumberIn, const int augmentPaintRegionNameIndexIn, const int newPaintNameIndexIn, const float lineStartXYZIn[3], const float lineEndXYZIn[3], const float minimumDistanceToLineIn, const float maximumDistanceToLineIn, const std::vector& limitToPaintIndicesIn, const float nodeExtentLimitIn[6]) : BrainModelAlgorithm(brainSetIn) { bms = bmsIn; paintFile = paintFileIn; paintFileColumnNumber = paintFileColumnNumberIn; augmentPaintRegionNameIndex = augmentPaintRegionNameIndexIn; newPaintNameIndex = newPaintNameIndexIn; lineStartXYZ[0] = lineStartXYZIn[0]; lineStartXYZ[1] = lineStartXYZIn[1]; lineStartXYZ[2] = lineStartXYZIn[2]; lineEndXYZ[0] = lineEndXYZIn[0]; lineEndXYZ[1] = lineEndXYZIn[1]; lineEndXYZ[2] = lineEndXYZIn[2]; minimumDistanceToLine = minimumDistanceToLineIn; maximumDistanceToLine = maximumDistanceToLineIn; limitToPaintIndices = limitToPaintIndicesIn; nodeExtentLimit[0] = nodeExtentLimitIn[0]; nodeExtentLimit[1] = nodeExtentLimitIn[1]; nodeExtentLimit[2] = nodeExtentLimitIn[2]; nodeExtentLimit[3] = nodeExtentLimitIn[3]; nodeExtentLimit[4] = nodeExtentLimitIn[4]; nodeExtentLimit[5] = nodeExtentLimitIn[5]; } /** * destructor. */ BrainModelSurfacePaintAssignRelativeToLine::~BrainModelSurfacePaintAssignRelativeToLine() { } /** * execute the algorithm. */ void BrainModelSurfacePaintAssignRelativeToLine::execute() throw (BrainModelAlgorithmException) { throw BrainModelAlgorithmException("BrainModelSurfacePaintAssignRelativeToLine NOT FUNCTIONING YET."); if (bms == NULL) { throw BrainModelAlgorithmException("Surface is invalid."); } if (paintFile == NULL) { throw BrainModelAlgorithmException("Paint file is invalid."); } // // Get coordinates and topology // const int numNodes = bms->getNumberOfNodes(); const CoordinateFile* cf = bms->getCoordinateFile(); const TopologyFile* tf = bms->getTopologyFile(); // // Get the topology helper // const TopologyHelper* th = tf->getTopologyHelper(false, true, false); const int numExistingPaintNames = static_cast(limitToPaintIndices.size()); // // Copy the region paint indices // std::vector regionPaintIndices(numNodes); for (int i = 0; i < numNodes; i++) { regionPaintIndices[i] = paintFile->getPaint(i, paintFileColumnNumber); } // // Loop until done // bool done = false; while (done == false) { // // Keep track of nodes that get paint changed // int numNodesChanged = 0; // // loop through nodes // for (int i = 0; i < numNodes; i++) { // // If node is not new paint or region paint // const int nodePaintIndex = paintFile->getPaint(i, paintFileColumnNumber); if ((regionPaintIndices[i] != augmentPaintRegionNameIndex) && (nodePaintIndex != newPaintNameIndex)) { // // Get neighbors // int numNeighbors = 0; const int* neighbors = th->getNodeNeighbors(i, numNeighbors); // // Loop through neighbors // bool testNode = false; for (int j = 0; j < numNeighbors; j++) { const int neighborNode = neighbors[j]; // // Is its neighbor part of the augment region? // if (regionPaintIndices[neighborNode] == augmentPaintRegionNameIndex) { // // Test this node // testNode = true; break; } } // // Is the paints that can be overwritten limited // if (numExistingPaintNames > 0) { // // May not want to test this node // testNode = false; // // Is it one of the existing paint names that can be overwritten // for (int j = 0; j < numExistingPaintNames; j++) { if (paintFile->getPaint(i, paintFileColumnNumber) == limitToPaintIndices[j]) { testNode = true; break; } } } // // If this node should be tested // const float* nodeXYZ = cf->getCoordinate(i); if (testNode) { // // See if within abs limits // testNode = false; if ((nodeXYZ[0] >= nodeExtentLimit[0]) && (nodeXYZ[0] <= nodeExtentLimit[1]) && (nodeXYZ[1] >= nodeExtentLimit[2]) && (nodeXYZ[1] <= nodeExtentLimit[3]) && (nodeXYZ[2] >= nodeExtentLimit[4]) && (nodeXYZ[2] <= nodeExtentLimit[5])) { testNode = true; } } if (testNode) { // // Get distance to line // const float distanceToLine = MathUtilities::distancePointToLine3D(nodeXYZ, lineStartXYZ, lineEndXYZ); // // Is distance within limit // testNode = false; if ((distanceToLine >= minimumDistanceToLine) && (distanceToLine <= maximumDistanceToLine)) { testNode = true; } } } } // // If no nodes where changed // if (numNodesChanged <= 0) { done = true; } else { // // add a layer around augment paints // for (int i = 0; i < numNodes; i++) { // // Is this the paint that is to be augmented // if (regionPaintIndices[i] == augmentPaintRegionNameIndex) { // // Get the neighbors // int numNeighbors = 0; const int* neighbors = th->getNodeNeighbors(i, numNeighbors); for (int j = 0; j < numNeighbors; j++) { // // Add node to region // bool addNodeToRegion = true; const int node = neighbors[j]; if (numExistingPaintNames > 0) { // // Is it one of the existing paint names that can be overwritten // addNodeToRegion = false; for (int j = 0; j < numExistingPaintNames; j++) { if (paintFile->getPaint(node, paintFileColumnNumber) == limitToPaintIndices[j]) { addNodeToRegion = true; break; } } } if (addNodeToRegion) { regionPaintIndices[node] = augmentPaintRegionNameIndex; } } } } } } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceOverlay.h0000664000175000017500000001244011572067322024746 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_OVERLAY_H__ #define __BRAIN_MODEL_SURFACE_OVERLAY_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include "SceneFile.h" class BrainSet; class DisplaySettingsNodeAttributeFile; /// class for an overlays settings class BrainModelSurfaceOverlay { public: /// Primary Overlay Underlay Selections enum OVERLAY_SELECTIONS { OVERLAY_NONE, OVERLAY_AREAL_ESTIMATION, OVERLAY_COCOMAC, OVERLAY_METRIC, OVERLAY_PAINT, OVERLAY_PROBABILISTIC_ATLAS, OVERLAY_RGB_PAINT, OVERLAY_SECTIONS, OVERLAY_SHOW_CROSSOVERS, OVERLAY_SHOW_EDGES, OVERLAY_SURFACE_SHAPE, OVERLAY_TOPOGRAPHY, OVERLAY_GEOGRAPHY_BLENDING }; // constructor BrainModelSurfaceOverlay(BrainSet* brainSetIn, const int overlayNumberIn); // destructor ~BrainModelSurfaceOverlay(); // reset the overlay void reset(); /// get the overlay OVERLAY_SELECTIONS getOverlay(const int modelNumber, const bool doUpdateFlag = true) const; /// set the overlay void setOverlay(const int modelNumber, const OVERLAY_SELECTIONS os); // get data types and names for selection void getDataTypesAndNames(std::vector& typesOut, std::vector& namesOut) const; // get the display column valid bool getDisplayColumnValid(const int modelNumber) const; // get the display column names QStringList getDisplayColumnNames(const int modelNumber) const; // get the selected display column int getDisplayColumnSelected(const int modelNumber) const; // set the selected display column void setDisplayColumnSelected(const int modelNumber, const int columnNumber); // get the threshold column names QStringList getThresholdColumnNames(const int modelNumber) const; // get the threshold column valid bool getThresholdColumnValid(const int modelNumber) const; // get the selected threshold column int getThresholdColumnSelected(const int modelNumber) const; // set the selected threshold column void setThresholdColumnSelected(const int modelNumber, const int columnNumber); /// get lighting enabled bool getLightingEnabled() const { return lightingEnabled; } /// set lighting enabled void setLightingEnabled(const bool le) { lightingEnabled = le; } /// get the opacity float getOpacity() const { return opacity; } /// set the opacity void setOpacity(const float op) { opacity = op; } /// get the overlay number int getOverlayNumber() const { return overlayNumber; } /// apply a scene (set display settings) void showScene(const SceneFile::Scene& scene, QString& errorMessage); /// create a scene (read display settings) void saveScene(SceneFile::Scene& scene, const bool onlyIfSelected); /// update the overlay due to brain model being loaded/unloaded or files changing void update() const; /// copy the overlay selections from specified surface to all other surfaces void copyOverlaysFromSurface(const int surfaceModelIndex); /// get name of the overlay QString getName() const { return name; } // get the name of the data type QString getDataTypeName(const int modelNumber) const; protected: /// copy the overlay selections from specified surface to all other surfaces void copyOverlaysFromSurfaceHelper(DisplaySettingsNodeAttributeFile* dsna, const int surfaceModelIndex); /// the overlay selected mutable std::vector overlay; /// the opacity float opacity; /// lighting bool lightingEnabled; /// brain set using this overlay BrainSet* brainSet; /// the overlay number int overlayNumber; /// the name of the overlay QString name; }; #endif // __BRAIN_MODEL_SURFACE_OVERLAY_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceOverlay.cxx0000664000175000017500000007257511572067322025340 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "ArealEstimationFile.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceOverlay.h" #include "BrainSet.h" #include "BrainSetNodeAttribute.h" #include "CocomacConnectivityFile.h" #include "DisplaySettingsArealEstimation.h" #include "DisplaySettingsMetric.h" #include "DisplaySettingsPaint.h" #include "DisplaySettingsRgbPaint.h" #include "DisplaySettingsSection.h" #include "DisplaySettingsSurfaceShape.h" #include "DisplaySettingsTopography.h" #include "FileUtilities.h" #include "MetricFile.h" #include "PaintFile.h" #include "ProbabilisticAtlasFile.h" #include "RgbPaintFile.h" #include "SectionFile.h" #include "SurfaceShapeFile.h" #include "TopographyFile.h" // // For scenes // static const QString overlayNoneName("none"); static const QString overlayArealEstimationName("areal-estimation"); static const QString overlayCocomacName("cocomac"); static const QString overlayMetricName("metric"); static const QString overlayPaintName("paint"); static const QString overlayProbabilisticAtlasName("probabilistic-atlas"); static const QString overlayRgbPaintName("rgb-paint"); static const QString overlaySectionsName("sections"); static const QString overlayShowCrossoversName("show-crossovers"); static const QString overlayShowEdgesName("show-edges"); static const QString overlaySurfaceShapeName("surface-shape"); static const QString overlayTopographyName("topography"); static const QString overlayGeographyBlendingName("geography-blending"); /** * constructor. */ BrainModelSurfaceOverlay::BrainModelSurfaceOverlay(BrainSet* brainSetIn, const int overlayNumberIn) { brainSet = brainSetIn; overlayNumber = overlayNumberIn; const int numberOfOverlays = brainSet->getNumberOfSurfaceOverlays(); if (overlayNumber == 0) { name = "Underlay"; } else if (overlayNumber == (numberOfOverlays - 1)) { name = "Primary Overlay"; } else if (overlayNumber == (numberOfOverlays - 2)) { name = "Secondary Overlay"; } else if (overlayNumber == (numberOfOverlays - 3)) { name = "Tertiary Overlay"; } else if (overlayNumber == (numberOfOverlays - 4)) { name = "Quaternary Overlay"; } else if (overlayNumber == (numberOfOverlays - 5)) { name = "Quinary Overlay"; } else if (overlayNumber == (numberOfOverlays - 6)) { name = "Senary Overlay"; } else if (overlayNumber == (numberOfOverlays - 7)) { name = "Septenary Overlay"; } else if (overlayNumber == (numberOfOverlays - 8)) { name = "Octonary Overlay"; } else if (overlayNumber == (numberOfOverlays - 9)) { name = "Nonary Overlay"; } else if (overlayNumber == (numberOfOverlays - 10)) { name = "Denary Overlay"; } else { name = QString::number(overlayNumber + 1) + " Overlay"; } reset(); } /** * destructor. */ BrainModelSurfaceOverlay::~BrainModelSurfaceOverlay() { } /** * reset the overlay. */ void BrainModelSurfaceOverlay::reset() { opacity = 1.0; lightingEnabled = true; update(); } /** * update the overlay due to brain model being loaded/unloaded or files changing. */ void BrainModelSurfaceOverlay::update() const { // // Get default selection // OVERLAY_SELECTIONS defaultSelection = OVERLAY_NONE; if (overlay.empty() == false) { defaultSelection = overlay[0]; } // // Size up for number of brain models // const int numBrainModels = brainSet->getNumberOfBrainModels(); overlay.resize(numBrainModels, defaultSelection); // // get valid types and names // std::vector dataTypes; std::vector dataTypeNames; getDataTypesAndNames(dataTypes, dataTypeNames); // // reset any overlays that are invalid // for (int i = 0; i < numBrainModels; i++) { if (std::find(dataTypes.begin(), dataTypes.end(), overlay[i]) == dataTypes.end()) { overlay[i] = OVERLAY_NONE; } } } /** * get the overlay. */ BrainModelSurfaceOverlay::OVERLAY_SELECTIONS BrainModelSurfaceOverlay::getOverlay(const int modelNumberIn, const bool doUpdateFlag) const { int modelNumber = modelNumberIn; if (doUpdateFlag) { update(); } if (modelNumber < 0) { modelNumber = 0; } else if (modelNumber >= static_cast(overlay.size())) { modelNumber = 0; } if (overlay.empty()) { return OVERLAY_NONE; } return overlay[modelNumber]; } /** * set the overlay. */ void BrainModelSurfaceOverlay::setOverlay(const int modelNumberIn, const OVERLAY_SELECTIONS os) { int modelNumber = modelNumberIn; update(); if (modelNumber < 0) { std::fill(overlay.begin(), overlay.end(), os); } else if ((modelNumber >= 0) && (modelNumber < static_cast(overlay.size()))) { overlay[modelNumber] = os; } } /** * get data types and names for selection. */ void BrainModelSurfaceOverlay::getDataTypesAndNames(std::vector& typesOut, std::vector& namesOut) const { typesOut.clear(); namesOut.clear(); const int numNodes = brainSet->getNumberOfNodes(); bool haveCrossovers = false; bool haveEdges = false; for (int i = 0; i < numNodes; i++) { const BrainSetNodeAttribute* bna = brainSet->getNodeAttributes(i); if (bna != NULL) { if (bna->getCrossover() != BrainSetNodeAttribute::CROSSOVER_NO) { haveCrossovers = true; } if (bna->getClassification() == BrainSetNodeAttribute::CLASSIFICATION_TYPE_EDGE) { haveEdges = true; } } } typesOut.push_back(OVERLAY_NONE); namesOut.push_back("None"); if (brainSet->getArealEstimationFile()->empty() == false) { typesOut.push_back(OVERLAY_AREAL_ESTIMATION); namesOut.push_back("Areal Estimation"); } if (brainSet->getCocomacFile()->empty() == false) { typesOut.push_back(OVERLAY_COCOMAC); namesOut.push_back("CoCoMac"); } if (haveCrossovers) { typesOut.push_back(OVERLAY_SHOW_CROSSOVERS); namesOut.push_back("Crossovers"); } if (haveEdges) { typesOut.push_back(OVERLAY_SHOW_EDGES); namesOut.push_back("Edges"); } if (brainSet->getPaintFile()->empty() == false) { if (brainSet->getPaintFile()->getGeographyColumnNumber() >= 0) { typesOut.push_back(OVERLAY_GEOGRAPHY_BLENDING); namesOut.push_back("Geography Blending"); } } if (brainSet->getMetricFile()->empty() == false) { typesOut.push_back(OVERLAY_METRIC); namesOut.push_back("Metric"); } if (brainSet->getPaintFile()->empty() == false) { typesOut.push_back(OVERLAY_PAINT); namesOut.push_back("Paint"); } if (brainSet->getProbabilisticAtlasSurfaceFile()->empty() == false) { typesOut.push_back(OVERLAY_PROBABILISTIC_ATLAS); namesOut.push_back("Probabilistic Atlas"); } if (brainSet->getRgbPaintFile()->empty() == false) { typesOut.push_back(OVERLAY_RGB_PAINT); namesOut.push_back("RGB Paint"); } if (brainSet->getSectionFile()->empty() == false) { typesOut.push_back(OVERLAY_SECTIONS); namesOut.push_back("Sections"); } if (brainSet->getSurfaceShapeFile()->empty() == false) { typesOut.push_back(OVERLAY_SURFACE_SHAPE); namesOut.push_back("Shape"); } if (brainSet->getTopographyFile()->empty() == false) { typesOut.push_back(OVERLAY_TOPOGRAPHY); namesOut.push_back("Topography"); } } /** * get the display column valid. */ bool BrainModelSurfaceOverlay::getDisplayColumnValid(const int modelNumber) const { return (getDisplayColumnNames(modelNumber).isEmpty() == false); } /** * get the display column names. */ QStringList BrainModelSurfaceOverlay::getDisplayColumnNames(const int modelNumberIn) const { int modelNumber = modelNumberIn; if (modelNumber < 0) { modelNumber = 0; } GiftiNodeDataFile* gnf = NULL; NodeAttributeFile* naf = NULL; switch (overlay[modelNumber]) { case OVERLAY_NONE: break; case OVERLAY_AREAL_ESTIMATION: naf = brainSet->getArealEstimationFile(); break; case OVERLAY_COCOMAC: break; case OVERLAY_METRIC: gnf = brainSet->getMetricFile(); break; case OVERLAY_PAINT: gnf = brainSet->getPaintFile(); break; case OVERLAY_PROBABILISTIC_ATLAS: break; case OVERLAY_RGB_PAINT: naf = brainSet->getRgbPaintFile(); break; case OVERLAY_SECTIONS: break; case OVERLAY_SHOW_CROSSOVERS: break; case OVERLAY_SHOW_EDGES: break; case OVERLAY_SURFACE_SHAPE: gnf = brainSet->getSurfaceShapeFile(); break; case OVERLAY_TOPOGRAPHY: naf = brainSet->getTopographyFile(); break; case OVERLAY_GEOGRAPHY_BLENDING: break; } QStringList names; if (gnf != NULL) { for (int i = 0; i < gnf->getNumberOfColumns(); i++) { names << gnf->getColumnName(i); } } if (naf != NULL) { for (int i = 0; i < naf->getNumberOfColumns(); i++) { names << naf->getColumnName(i); } } return names; } /** * get the threshold column names. */ QStringList BrainModelSurfaceOverlay::getThresholdColumnNames(const int modelNumberIn) const { int modelNumber = modelNumberIn; if (modelNumber < 0) { modelNumber = 0; } bool thresholdValid = false; switch (overlay[modelNumber]) { case OVERLAY_NONE: break; case OVERLAY_AREAL_ESTIMATION: break; case OVERLAY_COCOMAC: break; case OVERLAY_METRIC: thresholdValid = true; break; case OVERLAY_PAINT: break; case OVERLAY_PROBABILISTIC_ATLAS: break; case OVERLAY_RGB_PAINT: break; case OVERLAY_SECTIONS: break; case OVERLAY_SHOW_CROSSOVERS: break; case OVERLAY_SHOW_EDGES: break; case OVERLAY_SURFACE_SHAPE: break; case OVERLAY_TOPOGRAPHY: break; case OVERLAY_GEOGRAPHY_BLENDING: break; } QStringList names; if (thresholdValid) { names = getDisplayColumnNames(modelNumber); } return names; } /** * get the threshold column valid. */ bool BrainModelSurfaceOverlay::getThresholdColumnValid(const int modelNumber) const { return (getThresholdColumnNames(modelNumber).isEmpty() == false); } /** * get the selected display column. */ int BrainModelSurfaceOverlay::getDisplayColumnSelected(const int modelNumberIn) const { int modelNumber = modelNumberIn; if (modelNumber < 0) { modelNumber = 0; } DisplaySettingsNodeAttributeFile* dsna = NULL; switch (overlay[modelNumber]) { case OVERLAY_NONE: break; case OVERLAY_AREAL_ESTIMATION: dsna = brainSet->getDisplaySettingsArealEstimation(); break; case OVERLAY_COCOMAC: break; case OVERLAY_METRIC: dsna = brainSet->getDisplaySettingsMetric(); break; case OVERLAY_PAINT: dsna = brainSet->getDisplaySettingsPaint(); break; case OVERLAY_PROBABILISTIC_ATLAS: break; case OVERLAY_RGB_PAINT: dsna = brainSet->getDisplaySettingsRgbPaint(); break; case OVERLAY_SECTIONS: dsna = brainSet->getDisplaySettingsSection(); break; case OVERLAY_SHOW_CROSSOVERS: break; case OVERLAY_SHOW_EDGES: break; case OVERLAY_SURFACE_SHAPE: dsna = brainSet->getDisplaySettingsSurfaceShape(); break; case OVERLAY_TOPOGRAPHY: dsna = brainSet->getDisplaySettingsTopography(); break; case OVERLAY_GEOGRAPHY_BLENDING: break; } int columnNumber = -1; if (dsna != NULL) { columnNumber = dsna->getSelectedDisplayColumn(modelNumber, overlayNumber); } return columnNumber; } /** * set the selected display column. */ void BrainModelSurfaceOverlay::setDisplayColumnSelected(const int modelNumberIn, const int columnNumber) { int modelNumber = modelNumberIn; if (modelNumber < 0) { modelNumber = 0; } DisplaySettingsNodeAttributeFile* dsna = NULL; switch (overlay[modelNumber]) { case OVERLAY_NONE: break; case OVERLAY_AREAL_ESTIMATION: dsna = brainSet->getDisplaySettingsArealEstimation(); break; case OVERLAY_COCOMAC: break; case OVERLAY_METRIC: dsna = brainSet->getDisplaySettingsMetric(); break; case OVERLAY_PAINT: dsna = brainSet->getDisplaySettingsPaint(); break; case OVERLAY_PROBABILISTIC_ATLAS: break; case OVERLAY_RGB_PAINT: dsna = brainSet->getDisplaySettingsRgbPaint(); break; case OVERLAY_SECTIONS: dsna = brainSet->getDisplaySettingsSection(); break; case OVERLAY_SHOW_CROSSOVERS: break; case OVERLAY_SHOW_EDGES: break; case OVERLAY_SURFACE_SHAPE: dsna = brainSet->getDisplaySettingsSurfaceShape(); break; case OVERLAY_TOPOGRAPHY: dsna = brainSet->getDisplaySettingsTopography(); break; case OVERLAY_GEOGRAPHY_BLENDING: break; } if (dsna != NULL) { dsna->setSelectedDisplayColumn(modelNumberIn, overlayNumber, columnNumber); } } /** * get the selected threshold column. */ int BrainModelSurfaceOverlay::getThresholdColumnSelected(const int modelNumberIn) const { int modelNumber = modelNumberIn; if (modelNumber < 0) { modelNumber = 0; } DisplaySettingsNodeAttributeFile* dsna = NULL; switch (overlay[modelNumber]) { case OVERLAY_NONE: break; case OVERLAY_AREAL_ESTIMATION: dsna = brainSet->getDisplaySettingsArealEstimation(); break; case OVERLAY_COCOMAC: break; case OVERLAY_METRIC: dsna = brainSet->getDisplaySettingsMetric(); break; case OVERLAY_PAINT: dsna = brainSet->getDisplaySettingsPaint(); break; case OVERLAY_PROBABILISTIC_ATLAS: break; case OVERLAY_RGB_PAINT: dsna = brainSet->getDisplaySettingsRgbPaint(); break; case OVERLAY_SECTIONS: dsna = brainSet->getDisplaySettingsSection(); break; case OVERLAY_SHOW_CROSSOVERS: break; case OVERLAY_SHOW_EDGES: break; case OVERLAY_SURFACE_SHAPE: dsna = brainSet->getDisplaySettingsSurfaceShape(); break; case OVERLAY_TOPOGRAPHY: dsna = brainSet->getDisplaySettingsTopography(); break; case OVERLAY_GEOGRAPHY_BLENDING: break; } int columnNumber = -1; if (dsna != NULL) { columnNumber = dsna->getSelectedThresholdColumn(modelNumber, overlayNumber); } return columnNumber; } /** * set the selected threshold column. */ void BrainModelSurfaceOverlay::setThresholdColumnSelected(const int modelNumberIn, const int columnNumber) { int modelNumber = modelNumberIn; if (modelNumber < 0) { modelNumber = 0; } DisplaySettingsNodeAttributeFile* dsna = NULL; switch (overlay[modelNumber]) { case OVERLAY_NONE: break; case OVERLAY_AREAL_ESTIMATION: dsna = brainSet->getDisplaySettingsArealEstimation(); break; case OVERLAY_COCOMAC: break; case OVERLAY_METRIC: dsna = brainSet->getDisplaySettingsMetric(); break; case OVERLAY_PAINT: dsna = brainSet->getDisplaySettingsPaint(); break; case OVERLAY_PROBABILISTIC_ATLAS: break; case OVERLAY_RGB_PAINT: dsna = brainSet->getDisplaySettingsRgbPaint(); break; case OVERLAY_SECTIONS: dsna = brainSet->getDisplaySettingsSection(); break; case OVERLAY_SHOW_CROSSOVERS: break; case OVERLAY_SHOW_EDGES: break; case OVERLAY_SURFACE_SHAPE: dsna = brainSet->getDisplaySettingsSurfaceShape(); break; case OVERLAY_TOPOGRAPHY: dsna = brainSet->getDisplaySettingsTopography(); break; case OVERLAY_GEOGRAPHY_BLENDING: break; } if (dsna != NULL) { dsna->setSelectedThresholdColumn(modelNumberIn, overlayNumber, columnNumber); } } /** * apply a scene (set display settings). */ void BrainModelSurfaceOverlay::showScene(const SceneFile::Scene& scene, QString& errorMessage) { const int numClasses = scene.getNumberOfSceneClasses(); for (int nc = 0; nc < numClasses; nc++) { const SceneFile::SceneClass* sc = scene.getSceneClass(nc); if (sc->getName().startsWith("BrainModelSurfaceOverlay")) { const QStringList sl = sc->getName().split(':'); if (sl.count() == 2) { const int num = sl.at(1).toInt(); if (num != overlayNumber) { continue; } } else { continue; } const int num = sc->getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc->getSceneInfo(i); const QString infoName = si->getName(); const QString value = si->getValueAsString(); if (infoName == "opacity") { setOpacity(si->getValueAsFloat()); } else if (infoName == "lightingEnabled") { setLightingEnabled(si->getValueAsBool()); } // // Do overlay // if (infoName == "overlay") { OVERLAY_SELECTIONS overlay = OVERLAY_NONE; const QString surfaceName = si->getModelName(); if (value == overlayArealEstimationName) { overlay = OVERLAY_AREAL_ESTIMATION; if (brainSet->getArealEstimationFile()->getNumberOfColumns() <= 0) { errorMessage.append("Areal Estimation File is overlay/underlay but no Areal Estimation File is loaded.\n"); } } else if (value == overlayCocomacName) { overlay = OVERLAY_COCOMAC; const CocomacConnectivityFile* coco = brainSet->getCocomacFile(); if (coco->empty()) { errorMessage.append("CoCoMac File is overlay/underlay but no CoCoMac File is loaded.\n"); } } else if (value == overlayMetricName) { overlay = OVERLAY_METRIC; if (brainSet->getMetricFile()->empty()) { errorMessage.append("Metric File is overlay/underlay but no Metric File is loaded.\n"); } } else if (value == overlayPaintName) { overlay = OVERLAY_PAINT; if (brainSet->getPaintFile()->empty()) { errorMessage.append("Paint File is overlay/underlay but no Paint File is loaded.\n"); } } else if (value == overlayProbabilisticAtlasName) { overlay = OVERLAY_PROBABILISTIC_ATLAS; if (brainSet->getProbabilisticAtlasSurfaceFile()->empty()) { errorMessage.append("Prob Atlas File is overlay/underlay but no Prob Atlas File is loaded.\n"); } } else if (value == overlayRgbPaintName) { overlay = OVERLAY_RGB_PAINT; if (brainSet->getRgbPaintFile()->empty()) { errorMessage.append("RGB Paint File is overlay/underlay but no RGB Paint File is loaded.\n"); } } else if (value == overlaySectionsName) { overlay = OVERLAY_SECTIONS; } else if (value == overlayShowCrossoversName) { overlay = OVERLAY_SHOW_CROSSOVERS; } else if (value == overlayShowEdgesName) { overlay = OVERLAY_SHOW_EDGES; } else if (value == overlaySurfaceShapeName) { overlay = OVERLAY_SURFACE_SHAPE; if (brainSet->getSurfaceShapeFile()->empty()) { errorMessage.append("Surface Shape File is overlay/underlay but no Surface Shape File is loaded.\n"); } } else if (value == overlayTopographyName) { overlay = OVERLAY_TOPOGRAPHY; if (brainSet->getTopographyFile()->empty()) { errorMessage.append("Topography File is overlay/underlay but no Topography File is loaded.\n"); } } else if (value == overlayGeographyBlendingName) { overlay = OVERLAY_GEOGRAPHY_BLENDING; PaintFile* pf = brainSet->getPaintFile(); if (pf->empty()) { errorMessage.append("Geography Blending is overlay/underlay but no Paint File is loaded.\n"); } else if (pf->getGeographyColumnNumber() < 0) { errorMessage.append("Geography Blending is overlay/underlay but no Geography Column in Paint File.\n"); } } // // Handle all surfaces or a specific surface // int startSurface = 0; int endSurface = brainSet->getNumberOfBrainModels(); if (surfaceName != SceneFile::SceneInfo::getDefaultSurfacesName()) { endSurface = 0; const BrainModelSurface* bms = brainSet->getBrainModelSurfaceWithCoordinateFileName(surfaceName); if (bms != NULL) { startSurface = brainSet->getBrainModelIndex(bms); if (startSurface >= 0) { endSurface = startSurface + 1; } } } // // Set the overlay // for (int k = startSurface; k < endSurface; k++) { setOverlay(k, overlay); } } } } } } /** * create a scene (read display settings). */ void BrainModelSurfaceOverlay::saveScene(SceneFile::Scene& scene, const bool onlyIfSelected) { if (onlyIfSelected) { const int num = brainSet->getNumberOfBrainModels(); bool haveSurfacesFlag = false; for (int i = 0; i < num; i++) { if (brainSet->getBrainModelSurface(i) != NULL) { haveSurfacesFlag = true; break; } } if (haveSurfacesFlag == false) { return; } } SceneFile::SceneClass sc("BrainModelSurfaceOverlay:" + QString::number(overlayNumber)); sc.addSceneInfo(SceneFile::SceneInfo("overlayNumber", getOverlayNumber())); sc.addSceneInfo(SceneFile::SceneInfo("opacity", getOpacity())); sc.addSceneInfo(SceneFile::SceneInfo("lightingEnabled", getLightingEnabled())); bool didDefaultFlag = false; // // Check each brain model // const int num = brainSet->getNumberOfBrainModels(); for (int n = 0; n < num; n++) { // // Is this a surface ? // const BrainModelSurface* bms = brainSet->getBrainModelSurface(n); if (bms != NULL) { // // Surface index but use zero index if doing all // int surfaceIndex = n; // // Get name of coordinate file // const CoordinateFile* cf = bms->getCoordinateFile(); QString surfaceName = FileUtilities::basename(cf->getFileName()); QString ouValue; switch(getOverlay(surfaceIndex)) { case OVERLAY_NONE: ouValue = overlayNoneName; break; case OVERLAY_AREAL_ESTIMATION: ouValue = overlayArealEstimationName; break; case OVERLAY_COCOMAC: ouValue = overlayCocomacName; break; case OVERLAY_METRIC: ouValue = overlayMetricName; break; case OVERLAY_PAINT: ouValue = overlayPaintName; break; case OVERLAY_PROBABILISTIC_ATLAS: ouValue = overlayProbabilisticAtlasName; break; case OVERLAY_RGB_PAINT: ouValue = overlayRgbPaintName; break; case OVERLAY_SECTIONS: ouValue = overlaySectionsName; break; case OVERLAY_SHOW_CROSSOVERS: ouValue = overlayShowCrossoversName; break; case OVERLAY_SHOW_EDGES: ouValue = overlayShowEdgesName; break; case OVERLAY_SURFACE_SHAPE: ouValue = overlaySurfaceShapeName; break; case OVERLAY_TOPOGRAPHY: ouValue = overlayTopographyName; break; case OVERLAY_GEOGRAPHY_BLENDING: ouValue = overlayGeographyBlendingName; break; } // // Do default first // if (didDefaultFlag == false) { SceneFile::SceneInfo si("overlay", SceneFile::SceneInfo::getDefaultSurfacesName(), ouValue); sc.addSceneInfo(si); didDefaultFlag = true; } // // Create the scene info for this overlay/underlay // SceneFile::SceneInfo si("overlay", surfaceName, ouValue); sc.addSceneInfo(si); } // if (bms != NULL) } // for n scene.addSceneClass(sc); } /** * copy the overlay selections from specified surface to all other surfaces. */ void BrainModelSurfaceOverlay::copyOverlaysFromSurface(const int surfaceModelIndex) { if ((surfaceModelIndex >= 0) && (surfaceModelIndex < static_cast(overlay.size()))) { // // Set the overlay // const OVERLAY_SELECTIONS selectedOverlay = overlay[surfaceModelIndex]; std::fill(overlay.begin(), overlay.end(), selectedOverlay); copyOverlaysFromSurfaceHelper(brainSet->getDisplaySettingsArealEstimation(), surfaceModelIndex); copyOverlaysFromSurfaceHelper(brainSet->getDisplaySettingsMetric(), surfaceModelIndex); copyOverlaysFromSurfaceHelper(brainSet->getDisplaySettingsPaint(), surfaceModelIndex); copyOverlaysFromSurfaceHelper(brainSet->getDisplaySettingsRgbPaint(), surfaceModelIndex); copyOverlaysFromSurfaceHelper(brainSet->getDisplaySettingsSection(), surfaceModelIndex); copyOverlaysFromSurfaceHelper(brainSet->getDisplaySettingsSurfaceShape(), surfaceModelIndex); copyOverlaysFromSurfaceHelper(brainSet->getDisplaySettingsTopography(), surfaceModelIndex); } } /** * copy the overlay selections from specified surface to all other surfaces. */ void BrainModelSurfaceOverlay::copyOverlaysFromSurfaceHelper(DisplaySettingsNodeAttributeFile* dsna, const int surfaceModelIndex) { for (int m = 0; m < overlayNumber; m++) { dsna->setSelectedDisplayColumn(-1, overlayNumber, dsna->getSelectedDisplayColumn(surfaceModelIndex, overlayNumber)); } } /** * get the name of the data type. */ QString BrainModelSurfaceOverlay::getDataTypeName(const int modelNumber) const { QString s; std::vector types; std::vector names; getDataTypesAndNames(types, names); const int num = static_cast(types.size()); for (int i = 0; i < num; i++) { if (getOverlay(modelNumber) == types[i]) { s = names[i]; break; } } return s; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceNodeColoring.h0000664000175000017500000001667311572067322025723 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_BRAIN_SURFACE_NODE_COLORING_H__ #define __VE_BRAIN_SURFACE_NODE_COLORING_H__ #include #include #include #include "SceneFile.h" class BrainModelSurface; class BrainSet; class PaintFile; #include "PaletteFile.h" /// Class for coloring nodes in a "BrainModelSurface" class BrainModelSurfaceNodeColoring { public: /// coloring mode enum COLORING_MODE { /// coloring mode normal COLORING_MODE_NORMAL, /// coloring mode blend overlays COLORING_MODE_OVERLAY_BLENDING }; /// Constructor BrainModelSurfaceNodeColoring(BrainSet* bs); /// Destructor ~BrainModelSurfaceNodeColoring(); /// Assign colors to the Brain Surfaces Nodes void assignColors(); /// get the coloring mode COLORING_MODE getColoringMode() const { return coloringMode; } /// set the coloring mode void setColoringMode(const COLORING_MODE mode) { coloringMode = mode; } /// get the colors for a node const unsigned char* getNodeColor(const int model, const int index) const; /// set the colors for a node void setNodeColor(const int model, const int index, const unsigned char rgb[3], const unsigned char alpha = 255); /// get the color source for a node int getNodeColorSource(const int model, const int index) const; /// match paint file names to node colors static void matchPaintNamesToNodeColorFile(BrainSet* bs, int paintsNodeColorIndex[], std::vector& paintNames); /// Get the shape look up table void getShapeLookupTable(unsigned char lutOut[256][3]) const; /// add prob atlas thresholding to paint file /// the paint column must exist. void addProbAtlasThresholdingToPaintFile(PaintFile* paintFileIn, const int paintColumn); /// apply a scene (set display settings) void showScene(const SceneFile::Scene& scene, QString& errorMessage); /// create a scene (read display settings) void saveScene(SceneFile::Scene& scene, const bool onlyIfSelected); private: /// class for storing colors associated with a node class NodeColor { public: int r; int g; int b; int a; NodeColor() { reset(); } void reset() { r = g = b = -1; a = 1.0; } inline bool isValid() const { return ((r >= 0) || (g >= 0) || (b >= 0)); } }; /// the coloring mode COLORING_MODE coloringMode; /// used to help apply colors to nodes std::vector nodeColors; /// brain set being colored (DO NOT "delete" IT !) BrainSet* brainSet; /// default color name QString defaultColorName; /// default color unsigned char defaultColor[3]; /// node colors std::vector nodeColoring; /// node color source std::vector nodeColorSource; /// paint file for saving prob atlas paint assignment PaintFile* probAtlasThreshPaintFile; /// paint file column for saving prob atlas paint assignment int probAtlasThreshPaintColumn; /// color palette for topography polar angle PaletteFile polarAngleTopographyPaletteFile; /// color palette for topography eccentricity PaletteFile eccentricityTopographyPaletteFile; /// question ??? color index int questionColorIndex; /// number of brain models last time int numBrainModelsLastTime; /// number of nodes last iteration to avoid frequent resizing int numNodesLastTime; /// brain model number for which coloring is being set int modelNumber; /// paint indices with no area color std::set paintIndicesWithNoAreaColor; /// assign medial wall override coloring void assignMedialWallOverrideColoring(const int colorOffset, const int sourceOffset); /// Assign areal estimation coloring void assignArealEstimationColoring(const int overlayNumber); /// Assign cocomac coloring void assignCocomacColoring(); /// Assign crossover coloring void assignCrossoverColoring(); /// Assign blend geography coloring void assignBlendGeographyColoring(const int offset, const int sourceOffset); /// Assign edges coloring void assignEdgesColoring(); /// Assign metric coloring void assignMetricColoring(const int overlayNumber); /// Assign none coloring void assignNoneColoring(const int nodeColoringOffset, const int nodeColorSourceOffset); /// assign paint coloring void assignPaintColoring(const int overlayNumber); /// Assign probabilistic coloring to a node. void assignProbabilisticColorToNode(const int n, const int paintsAreaColorIndex[]); /// Assign probabilistic coloring void assignProbabilisticNormalColoring(); /// Assign Threshold Probabilistic coloring void assignProbabilisticThresholdColoring(); /// Assign Probabilistic coloring void assignProbabilisticColoring(const BrainModelSurface* bms); /// Assign RGB Paint coloring void assignRgbPaintColoring(const int overlayNumber, const bool underlayFlag); /// Assign section coloring void assignSectionColoring(const int overlayNumber); /// Surface shape coloring void assignSurfaceShapeColoring(const int overlayNumber); /// Assign topography coloring void assignTopographyColoring(const int overlayNumber); /// Assign topography polar angle coloring palette void assignTopographyPolarAnglePalette(); /// Assign topography eccentricity coloring palette void assignTopographyEccentricityPalette(); /// clamp a float to int [0, 255] int clamp0255(const float v) const; /// get the LUT index for a value unsigned char getLutIndex(const float value, const float dmin, const float dmax) const; /// set the default color void setDefaultColor(); }; #endif caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceNodeColoring.cxx0000664000175000017500000030012611572067322026263 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "AreaColorFile.h" #include "ArealEstimationFile.h" #include "BrainModelSurfaceOverlay.h" #include "BrainModelVolume.h" #include "CocomacConnectivityFile.h" #include "ColorFile.h" #include "DebugControl.h" #include "DisplaySettingsArealEstimation.h" #include "DisplaySettingsCoCoMac.h" #include "DisplaySettingsMetric.h" #include "DisplaySettingsPaint.h" #include "DisplaySettingsSurface.h" #include "DisplaySettingsProbabilisticAtlas.h" #include "DisplaySettingsRgbPaint.h" #include "DisplaySettingsSection.h" #include "DisplaySettingsSurface.h" #include "DisplaySettingsSurfaceShape.h" #include "DisplaySettingsTopography.h" #include "FileUtilities.h" #include "MetricFile.h" #include "PaintFile.h" #include "ProbabilisticAtlasFile.h" #include "RgbPaintFile.h" #include "SectionFile.h" #include "StringUtilities.h" #include "SurfaceShapeFile.h" #include "TopographyFile.h" #include "VolumeFile.h" #include "vtkPiecewiseFunction.h" #include "BrainModelSurfaceNodeColoring.h" #include "BrainSet.h" //--------------------------------------------------------------------------- static unsigned char lutOrangeYellow[256][3] = { { 0, 0, 0 }, { 2, 0, 0 }, { 4, 0, 0 }, { 6, 0, 0 }, { 8, 0, 0 }, { 10, 0, 0 }, { 12, 0, 0 }, { 14, 0, 0 }, { 16, 0, 0 }, { 18, 0, 0 }, { 20, 0, 0 }, { 22, 0, 0 }, { 24, 0, 0 }, { 26, 0, 0 }, { 28, 0, 0 }, { 30, 0, 0 }, { 32, 0, 0 }, { 34, 0, 0 }, { 36, 0, 0 }, { 38, 0, 0 }, { 40, 0, 0 }, { 42, 0, 0 }, { 44, 0, 0 }, { 46, 0, 0 }, { 48, 0, 0 }, { 50, 0, 0 }, { 52, 0, 0 }, { 54, 0, 0 }, { 56, 0, 0 }, { 58, 0, 0 }, { 60, 0, 0 }, { 62, 0, 0 }, { 64, 0, 0 }, { 66, 0, 0 }, { 68, 0, 0 }, { 70, 0, 0 }, { 72, 0, 0 }, { 74, 0, 0 }, { 76, 0, 0 }, { 78, 0, 0 }, { 80, 0, 0 }, { 82, 0, 0 }, { 84, 0, 0 }, { 86, 0, 0 }, { 88, 0, 0 }, { 90, 0, 0 }, { 92, 0, 0 }, { 94, 0, 0 }, { 96, 0, 0 }, { 98, 0, 0 }, { 100, 0, 0 }, { 102, 0, 0 }, { 104, 0, 0 }, { 106, 0, 0 }, { 108, 0, 0 }, { 110, 0, 0 }, { 112, 0, 0 }, { 114, 0, 0 }, { 116, 0, 0 }, { 118, 0, 0 }, { 120, 0, 0 }, { 122, 0, 0 }, { 124, 0, 0 }, { 126, 0, 0 }, { 128, 0, 0 }, { 130, 2, 0 }, { 132, 4, 0 }, { 134, 6, 0 }, { 136, 8, 0 }, { 138, 10, 0 }, { 140, 12, 0 }, { 142, 14, 0 }, { 144, 16, 0 }, { 146, 18, 0 }, { 148, 20, 0 }, { 150, 22, 0 }, { 152, 24, 0 }, { 154, 26, 0 }, { 156, 28, 0 }, { 158, 30, 0 }, { 160, 32, 0 }, { 162, 34, 0 }, { 164, 36, 0 }, { 166, 38, 0 }, { 168, 40, 0 }, { 170, 42, 0 }, { 172, 44, 0 }, { 174, 46, 0 }, { 176, 48, 0 }, { 178, 50, 0 }, { 180, 52, 0 }, { 182, 54, 0 }, { 184, 56, 0 }, { 186, 58, 0 }, { 188, 60, 0 }, { 190, 62, 0 }, { 192, 64, 0 }, { 194, 66, 0 }, { 196, 68, 0 }, { 198, 70, 0 }, { 200, 72, 0 }, { 202, 74, 0 }, { 204, 76, 0 }, { 206, 78, 0 }, { 208, 80, 0 }, { 210, 82, 0 }, { 212, 84, 0 }, { 214, 86, 0 }, { 216, 88, 0 }, { 218, 90, 0 }, { 220, 92, 0 }, { 222, 94, 0 }, { 224, 96, 0 }, { 226, 98, 0 }, { 228, 100, 0 }, { 230, 102, 0 }, { 232, 104, 0 }, { 234, 106, 0 }, { 236, 108, 0 }, { 238, 110, 0 }, { 240, 112, 0 }, { 242, 114, 0 }, { 244, 116, 0 }, { 246, 118, 0 }, { 248, 120, 0 }, { 250, 122, 0 }, { 252, 124, 0 }, { 254, 126, 0 }, { 254, 128, 0 }, { 254, 130, 2 }, { 254, 132, 4 }, { 254, 134, 6 }, { 254, 136, 8 }, { 254, 138, 10 }, { 254, 140, 12 }, { 254, 142, 14 }, { 254, 144, 16 }, { 254, 146, 18 }, { 254, 148, 20 }, { 254, 150, 22 }, { 254, 152, 24 }, { 254, 154, 26 }, { 254, 156, 28 }, { 254, 158, 30 }, { 254, 160, 32 }, { 254, 162, 34 }, { 254, 164, 36 }, { 254, 166, 38 }, { 254, 168, 40 }, { 254, 170, 42 }, { 254, 172, 44 }, { 254, 174, 46 }, { 254, 176, 48 }, { 254, 178, 50 }, { 254, 180, 52 }, { 254, 182, 54 }, { 254, 184, 56 }, { 254, 186, 58 }, { 254, 188, 60 }, { 254, 190, 62 }, { 254, 192, 64 }, { 254, 194, 66 }, { 254, 196, 68 }, { 254, 198, 70 }, { 254, 200, 72 }, { 254, 202, 74 }, { 254, 204, 76 }, { 254, 206, 78 }, { 254, 208, 80 }, { 254, 210, 82 }, { 254, 212, 84 }, { 254, 214, 86 }, { 254, 216, 88 }, { 254, 218, 90 }, { 254, 220, 92 }, { 254, 222, 94 }, { 254, 224, 96 }, { 254, 226, 98 }, { 254, 228, 100 }, { 254, 230, 102 }, { 254, 232, 104 }, { 254, 234, 106 }, { 254, 236, 108 }, { 254, 238, 110 }, { 254, 240, 112 }, { 254, 242, 114 }, { 254, 244, 116 }, { 254, 246, 118 }, { 254, 248, 120 }, { 254, 250, 122 }, { 254, 252, 124 }, { 254, 254, 126 }, { 254, 254, 128 }, { 254, 254, 130 }, { 254, 254, 132 }, { 254, 254, 134 }, { 254, 254, 136 }, { 254, 254, 138 }, { 254, 254, 140 }, { 254, 254, 142 }, { 254, 254, 144 }, { 254, 254, 146 }, { 254, 254, 148 }, { 254, 254, 150 }, { 254, 254, 152 }, { 254, 254, 154 }, { 254, 254, 156 }, { 254, 254, 158 }, { 254, 254, 160 }, { 254, 254, 162 }, { 254, 254, 164 }, { 254, 254, 166 }, { 254, 254, 168 }, { 254, 254, 170 }, { 254, 254, 172 }, { 254, 254, 174 }, { 254, 254, 176 }, { 254, 254, 178 }, { 254, 254, 180 }, { 254, 254, 182 }, { 254, 254, 184 }, { 254, 254, 186 }, { 254, 254, 188 }, { 254, 254, 190 }, { 254, 254, 192 }, { 254, 254, 194 }, { 254, 254, 196 }, { 254, 254, 198 }, { 254, 254, 200 }, { 254, 254, 202 }, { 254, 254, 204 }, { 254, 254, 206 }, { 254, 254, 208 }, { 254, 254, 210 }, { 254, 254, 212 }, { 254, 254, 214 }, { 254, 254, 216 }, { 254, 254, 218 }, { 254, 254, 220 }, { 254, 254, 222 }, { 254, 254, 224 }, { 254, 254, 226 }, { 254, 254, 228 }, { 254, 254, 230 }, { 254, 254, 232 }, { 254, 254, 234 }, { 254, 254, 236 }, { 254, 254, 238 }, { 254, 254, 240 }, { 254, 254, 242 }, { 254, 254, 244 }, { 254, 254, 246 }, { 254, 254, 248 }, { 254, 254, 250 }, { 254, 254, 252 }, { 254, 254, 254 } }; /** * The constructor */ BrainModelSurfaceNodeColoring::BrainModelSurfaceNodeColoring(BrainSet* bs) { brainSet = bs; defaultColor[0] = 100; defaultColor[1] = 100; defaultColor[2] = 100; defaultColorName = "???"; numNodesLastTime = -1; numBrainModelsLastTime = -1; probAtlasThreshPaintFile = NULL; coloringMode = COLORING_MODE_NORMAL; assignTopographyEccentricityPalette(); assignTopographyPolarAnglePalette(); } /** * The destructor. */ BrainModelSurfaceNodeColoring::~BrainModelSurfaceNodeColoring() { } /** * Get the shape look up table */ void BrainModelSurfaceNodeColoring::getShapeLookupTable(unsigned char lutOut[256][3]) const { for (int i = 0; i < 256; i++) { for (int j = 0; j < 3; j++) { lutOut[i][j] = lutOrangeYellow[i][j]; } } } /** * find color for ??? */ void BrainModelSurfaceNodeColoring::setDefaultColor() { const AreaColorFile* cf = brainSet->getAreaColorFile(); // // avoid search if default color index has not changed // bool match; unsigned char r, g, b; questionColorIndex = cf->getColorByName(defaultColorName, match, r, g, b); if (questionColorIndex >= 0) { defaultColor[0] = r; defaultColor[1] = g; defaultColor[2] = b; } else { defaultColor[0] = 100; defaultColor[1] = 100; defaultColor[2] = 100; } } /** * get the colors for a node. */ const unsigned char* BrainModelSurfaceNodeColoring::getNodeColor(const int modelIn, const int indexIn) const { // // Model might be "-1" which for display purposes means all models. // In this case, use the first model. // const int model = (modelIn < 0) ? 0 : modelIn; const int index = (model * numNodesLastTime * 4) + (indexIn * 4); return &nodeColoring[index]; } /** * get the color source for a node. */ int BrainModelSurfaceNodeColoring::getNodeColorSource(const int modelIn, const int indexIn) const { // // Model might be "-1" which for display purposes means all models. // In this case, use the first model. // const int model = (modelIn < 0) ? 0 : modelIn; const int index = (model * numNodesLastTime) + indexIn; return nodeColorSource[index]; } /** * Set the colors for a node. */ void BrainModelSurfaceNodeColoring::setNodeColor(const int modelIn, const int index, const unsigned char rgb[3], const unsigned char alpha) { // // Model might be "-1" which for display purposes means all models. // In this case, use the first model. // const int model = (modelIn < 0) ? 0 : modelIn; const int numNodes = brainSet->getNumberOfNodes(); nodeColoring[model * numNodes * 4 + index * 4] = rgb[0]; nodeColoring[model * numNodes * 4 + index * 4 + 1] = rgb[1]; nodeColoring[model * numNodes * 4 + index * 4 + 2] = rgb[2]; nodeColoring[model * numNodes * 4 + index * 4 + 3] = alpha; } /** * Get the lookup table index for a value between (dmin, dmax) */ unsigned char BrainModelSurfaceNodeColoring::getLutIndex(const float value, const float dmin, const float dmax) const { if (value < dmin) return 0; if (value > dmax) return 255; const float lutScale = 255.0/(dmax-dmin); int colorIndex = (int)(lutScale * (value - dmin)); if (colorIndex < 0) colorIndex = 0; if (colorIndex > 255) colorIndex = 255; return (unsigned char)colorIndex; } /** * Assign surface painting for NONE */ void BrainModelSurfaceNodeColoring::assignNoneColoring(const int nodeColoringOffset, const int nodeColorSourceOffset) { const int numNodes = brainSet->getNumberOfNodes(); for (register int i = 0; i < numNodes; i++) { nodeColoring[nodeColoringOffset + i*4] = defaultColor[0]; nodeColoring[nodeColoringOffset + i*4+1] = defaultColor[1]; nodeColoring[nodeColoringOffset + i*4+2] = defaultColor[2]; nodeColoring[nodeColoringOffset + i*4+3] = 255; nodeColorSource[nodeColorSourceOffset + i] = -1; } } /** * Assign RGB Paint Coloring. */ void BrainModelSurfaceNodeColoring::assignRgbPaintColoring(const int overlayNumber, const bool underlayFlag) { DisplaySettingsRgbPaint* dsrp = brainSet->getDisplaySettingsRgbPaint(); RgbPaintFile* rgbPaintFile = brainSet->getRgbPaintFile(); if (rgbPaintFile->getNumberOfColumns() == 0) { return; } const int numNodes = rgbPaintFile->getNumberOfNodes(); if (numNodes == 0) { return; } if (numNodes != brainSet->getNumberOfNodes()) { std::cerr << "RGB Paint has different number of nodes than surface." << std::endl; return; } const int column = dsrp->getSelectedDisplayColumn(modelNumber, overlayNumber); if ((column < 0) || (column >= rgbPaintFile->getNumberOfColumns())) { std::cout << "Invalid RGB Paint column selected." << std::endl; return; } // // Note: Threshold values are always in the range 0 to 255. // float redThresh, greenThresh, blueThresh; dsrp->getThresholds(redThresh, greenThresh, blueThresh); const bool positiveDisplay = (dsrp->getDisplayMode() == DisplaySettingsRgbPaint::RGB_DISPLAY_MODE_POSITIVE); float redMaxValue, redMinValue; rgbPaintFile->getScaleRed(column, redMinValue, redMaxValue); vtkPiecewiseFunction* redPF = vtkPiecewiseFunction::New(); if (positiveDisplay) { redPF->AddSegment(0.0, 0, redMaxValue, 255); } else { redPF->AddSegment(0.0, 0, redMinValue, 255); } redPF->ClampingOn(); float greenMaxValue, greenMinValue; rgbPaintFile->getScaleGreen(column, greenMinValue, greenMaxValue); vtkPiecewiseFunction* greenPF = vtkPiecewiseFunction::New(); if (positiveDisplay) { greenPF->AddSegment(0.0, 0, greenMaxValue, 255); } else { greenPF->AddSegment(0.0, 0, greenMinValue, 255); } greenPF->ClampingOn(); float blueMaxValue, blueMinValue; rgbPaintFile->getScaleBlue(column, blueMinValue, blueMaxValue); vtkPiecewiseFunction* bluePF = vtkPiecewiseFunction::New(); if (positiveDisplay) { bluePF->AddSegment(0.0, 0, blueMaxValue, 255); } else { bluePF->AddSegment(0.0, 0, blueMinValue, 255); } bluePF->ClampingOn(); for (register int i = 0; i < numNodes; i++) { float r, g, b; rgbPaintFile->getRgb(i, column, r, g, b); if ((r == 0.0) && (g == 0.0) && (b == 0.0)) { // no RGB so do nothing } else if (positiveDisplay) { if (underlayFlag) { redThresh = -1.0; greenThresh = -1.0; blueThresh = -1.0; } if (dsrp->getRedEnabled()) { if (r >= 0.0) { if (r > redThresh) { nodeColors[i].r = (unsigned char)redPF->GetValue(r); } } } if (dsrp->getGreenEnabled()) { if (g >= 0.0) { if (g > greenThresh) { nodeColors[i].g = (unsigned char)greenPF->GetValue(g); } } } if (dsrp->getBlueEnabled()) { if (b >= 0.0) { if (b > blueThresh) { nodeColors[i].b = (unsigned char)bluePF->GetValue(b); } } } } else { if (underlayFlag) { redThresh = -1.0; greenThresh = -1.0; blueThresh = -1.0; } if (dsrp->getRedEnabled()) { if (r <= 0.0) { if (r < redThresh) { nodeColors[i].r = (unsigned char)redPF->GetValue(r); } } } if (dsrp->getGreenEnabled()) { if (g <= 0.0) { if (g < greenThresh) { nodeColors[i].g = (unsigned char)greenPF->GetValue(g); } } } if (dsrp->getBlueEnabled()) { if (b <= 0.0) { if (b < blueThresh) { nodeColors[i].b = (unsigned char)bluePF->GetValue(b); } } } } // // If any component is set, make sure any unset components are set // to zero (all components are -1 upon entry to this function). // if ((nodeColors[i].r >= 0) || (nodeColors[i].g >= 0) || (nodeColors[i].b >= 0)) { if (nodeColors[i].r < 0) { nodeColors[i].r = 0; } if (nodeColors[i].g < 0) { nodeColors[i].g = 0; } if (nodeColors[i].b < 0) { nodeColors[i].b = 0; } } } redPF->Delete(); greenPF->Delete(); bluePF->Delete(); } /** * Assign areal estimation coloring. */ void BrainModelSurfaceNodeColoring::assignArealEstimationColoring(const int overlayNumber) { DisplaySettingsArealEstimation* dsae = brainSet->getDisplaySettingsArealEstimation(); const int columnNumber = dsae->getSelectedDisplayColumn(modelNumber, overlayNumber); ArealEstimationFile* aef = brainSet->getArealEstimationFile(); const int numNodes = brainSet->getNumberOfNodes(); if ((aef->getNumberOfNodes() == 0) || (aef->getNumberOfColumns() == 0)) { return; } if (aef->getNumberOfNodes() != numNodes) { std::cerr << "Number of node in areal estimation files does not match surface" << std::endl; return; } // // For each name in the ArealEstimationFile assign it an index into the // Area Colors // int* areaColorIndex = new int[aef->getNumberOfAreaNames()]; AreaColorFile* cf = brainSet->getAreaColorFile(); for (int j = 0; j < aef->getNumberOfAreaNames(); j++) { bool m; areaColorIndex[j] = cf->getColorIndexByName(aef->getAreaName(j), m); } for (register int i = 0; i < numNodes; i++) { float r = 0, g = 0, b = 0; int nameIndx[4]; float prob[4]; aef->getNodeData(i, columnNumber, nameIndx, prob); for (int j = 0; j < 4; j++) { const int indx = areaColorIndex[nameIndx[j]]; unsigned char red, green, blue; if (indx >= 0) { cf->getColorByIndex(indx, red, green, blue); } else { paintIndicesWithNoAreaColor.insert(nameIndx[j]); red = defaultColor[0]; green = defaultColor[1]; blue = defaultColor[2]; } r += prob[j] * red; g += prob[j] * green; b += prob[j] * blue; } if (r > 255.0) r = 255.0; if (r < 0.0) r = 0.0; if (g > 255.0) g = 255.0; if (g < 0.0) g = 0.0; if (b > 255.0) b = 255.0; if (b < 0.0) b = 0.0; nodeColors[i].r = static_cast(r); nodeColors[i].g = static_cast(g); nodeColors[i].b = static_cast(b); } delete[] areaColorIndex; } /** * Match paint names to names in area color file which produces an index for * each paint name into the area color file. It finds the exact match or * the "longest" where the area color name is a prefix of the paint name. */ void BrainModelSurfaceNodeColoring::matchPaintNamesToNodeColorFile(BrainSet* bs, int paintIndexToColorFile[], std::vector& paintNames) { AreaColorFile* cf = bs->getAreaColorFile(); const int numNames = static_cast(paintNames.size()); for (int j = 0; j < numNames; j++) { bool exactMatch = false; unsigned char r = 0, g = 0, b = 0; paintIndexToColorFile[j] = cf->getColorByName(paintNames[j], exactMatch, r, g, b); } } /** * Assign paint coloring to nodes. */ void BrainModelSurfaceNodeColoring::assignPaintColoring(const int overlayNumber) { PaintFile* pf = brainSet->getPaintFile(); const int numNodes = pf->getNumberOfNodes(); if (numNodes == 0) { return; } if (numNodes != brainSet->getNumberOfNodes()) { std::cerr << "Number of nodes in Paint File does not match surface." << std::endl; return; } DisplaySettingsPaint* dsp = brainSet->getDisplaySettingsPaint(); const int column = dsp->getSelectedDisplayColumn(modelNumber, overlayNumber); if (column < 0) { //std::cerr << "No column of paint file selected." << std::endl; return; } // // Assign colors to the paint names // AreaColorFile* cf = brainSet->getAreaColorFile(); pf->assignColors(*cf); // // The label table inside the paint file // GiftiLabelTable* labelTable = pf->getLabelTable(); // // Assign the colors to the nodes // for (int i = 0; i < numNodes; i++) { const int p = pf->getPaint(i, column); if (pf->getPaintNameEnabled(p)) { const int colorFileIndex = labelTable->getColorFileIndex(p); if (colorFileIndex >= 0) { if (colorFileIndex != questionColorIndex) { unsigned char r = 0, g = 0, b = 0, a = 0; cf->getColorByIndex(colorFileIndex, r, g, b, a); if (a > 0) { nodeColors[i].r = r; nodeColors[i].g = g; nodeColors[i].b = b; } } } else { paintIndicesWithNoAreaColor.insert(p); } } } } /** * Assign probabilistic coloring to a node. */ void BrainModelSurfaceNodeColoring::assignProbabilisticColorToNode( const int n, const int paintsAreaColorIndex[]) { DisplaySettingsProbabilisticAtlas* dspa = brainSet->getDisplaySettingsProbabilisticAtlasSurface(); ProbabilisticAtlasFile* paf = brainSet->getProbabilisticAtlasSurfaceFile(); AreaColorFile* cf = brainSet->getAreaColorFile(); const int numberOfColumns = paf->getNumberOfColumns(); const int numSelectedChannels = dspa->getNumberOfChannelsSelected(); if (numSelectedChannels > 0) { int* areaColorIndices = new int[numberOfColumns]; int* paintIndices = new int[numberOfColumns]; bool haveColors = false; for (int c = 0; c < numberOfColumns; c++) { if (dspa->getChannelSelectedForStructure(c)) { const int paintIndex = paf->getPaint(n, c); areaColorIndices[c] = paintsAreaColorIndex[paintIndex]; paintIndices[c] = paintIndex; // check > 0 since ??? is always first and is not a valid atlas index if (paintIndex > 0) { if (dspa->getAreaSelected(paintIndex)) { haveColors = true; } } } } if (haveColors) { // clear colors since we have probabilistic data for this node nodeColors[n].r = 0; nodeColors[n].g = 0; nodeColors[n].b = 0; for (int color = 0; color < numberOfColumns; color++) { if (dspa->getChannelSelectedForStructure(color)) { const int areaColorIndex = areaColorIndices[color]; const int paintIndex = paintIndices[color]; if (areaColorIndex >= 0) { if (dspa->getAreaSelected(paintIndex)) { //nodeWasColored = 1; unsigned char r, g, b; cf->getColorByIndex(areaColorIndex, r, g, b); nodeColors[n].r += (unsigned char)( (r / (float)(numSelectedChannels))); nodeColors[n].g += (unsigned char)( (g / (float)(numSelectedChannels))); nodeColors[n].b += (unsigned char)( (b / (float)(numSelectedChannels))); } } else if (areaColorIndex < 0) { paintIndicesWithNoAreaColor.insert(areaColorIndex); } } } } delete[] areaColorIndices; delete[] paintIndices; } } /** * Normal Probabilistic coloring. */ void BrainModelSurfaceNodeColoring::assignProbabilisticNormalColoring() { DisplaySettingsProbabilisticAtlas* dspa = brainSet->getDisplaySettingsProbabilisticAtlasSurface(); PaintFile* paf = brainSet->getProbabilisticAtlasSurfaceFile(); const int numberOfNodes = paf->getNumberOfNodes(); const int numberOfColumns = paf->getNumberOfColumns(); if (numberOfColumns <= 0) { return; } if (numberOfNodes != brainSet->getNumberOfNodes()) { std::cerr << "Probabilistic Atlas file has different number of nodes " << numberOfNodes << " than surface " << brainSet->getNumberOfNodes() << "." << std::endl; return; } const int numPaintNames = paf->getNumberOfPaintNames(); if (numPaintNames <= 0) { std::cerr << "Probabilistic Atlas file contains no paint names." << std::endl; return; } const QString question3 = "???"; std::vector paintNames; for (int j = 0; j < numPaintNames; j++) { QString name(paf->getPaintNameFromIndex(j)); if (dspa->getTreatQuestColorAsUnassigned()) { if (name == question3) { name = "Unassigned"; } } paintNames.push_back(name); } int* paintsAreaColorIndex = new int[numPaintNames]; matchPaintNamesToNodeColorFile(brainSet, paintsAreaColorIndex, paintNames); int* probIndices = new int[numberOfColumns]; for (int j = 0; j < numberOfNodes; j++){ paf->getPaints(j, probIndices); bool haveNonQuestion = false; for (int k = 0; k < numberOfColumns; k++) { if (probIndices[k] < numPaintNames) { if (paintNames[probIndices[k]].left(3) != question3) { haveNonQuestion = true; break; } } } nodeColors[j].r = defaultColor[0]; nodeColors[j].g = defaultColor[1]; nodeColors[j].b = defaultColor[2]; if (haveNonQuestion) { assignProbabilisticColorToNode(j, paintsAreaColorIndex); } } delete[] probIndices; delete[] paintsAreaColorIndex; } /** * Threshold probabilistic coloring. */ void BrainModelSurfaceNodeColoring::assignProbabilisticThresholdColoring() { DisplaySettingsProbabilisticAtlas* dspa = brainSet->getDisplaySettingsProbabilisticAtlasSurface(); ProbabilisticAtlasFile* paf = brainSet->getProbabilisticAtlasSurfaceFile(); const int numberOfNodes = paf->getNumberOfNodes(); const int numberOfColumns = paf->getNumberOfColumns(); if (numberOfNodes != brainSet->getNumberOfNodes()) { std::cerr << "Probabilistic Atlas file has different number of nodes than surface." << std::endl; return; } if (numberOfColumns <= 0) { return; } const int numPaintNames = paf->getNumberOfPaintNames(); if (numPaintNames <= 0) { std::cerr << "Probabilistic Atlas file contains no paint names." << std::endl; return; } int questionIndex = -1; int gyralIndex = -1; int gyrusIndex = -1; std::vector paintNames; for (int j = 0; j < numPaintNames; j++) { QString name(paf->getPaintNameFromIndex(j)); if (dspa->getTreatQuestColorAsUnassigned()) { if (name == "???") { name = "Unassigned"; } } if (name == "???") { questionIndex = static_cast(paintNames.size()); } if (name == "GYRUS") { gyrusIndex = static_cast(paintNames.size()); } if (name == "GYRAL") { gyralIndex = static_cast(paintNames.size()); } paintNames.push_back(name); } int* paintsAreaColorIndex = new int[numPaintNames]; matchPaintNamesToNodeColorFile(brainSet, paintsAreaColorIndex, paintNames); const int numSelectedChannels = dspa->getNumberOfChannelsSelected(); // see if there is a color for "ANYAREA" which is used when at least one paint column is // non-zero but there is not a majority of the columns the same. AreaColorFile* cf = brainSet->getAreaColorFile(); unsigned char anyAreaColor[3] = { defaultColor[0], defaultColor[1], defaultColor[2] }; bool anyAreaColorValid = false; cf->getColorByName("ANYAREA", anyAreaColorValid, anyAreaColor[0], anyAreaColor[1], anyAreaColor[2]); // // Number of columns that must match // const float ratio = dspa->getThresholdDisplayTypeRatio(); for (int j = 0; j < numberOfNodes; j++){ nodeColors[j].r = defaultColor[0]; nodeColors[j].g = defaultColor[1]; nodeColors[j].b = defaultColor[2]; std::map indexCounterMap; bool atLeastOneNonZero = false; for (int k = 0; k < numberOfColumns; k++) { int cntIndex = 0; if (dspa->getChannelSelectedForStructure(k)) { cntIndex = paf->getPaint(j, k); } if ((cntIndex > 0) && (cntIndex < numPaintNames)) { if (dspa->getAreaSelected(cntIndex) == false) { cntIndex = -1; } } if (cntIndex > 0) { // // Skip non-sulci // bool useIt = true; if ((cntIndex == questionIndex) || (cntIndex == gyralIndex) || (cntIndex == gyrusIndex)) { useIt = false; } if (useIt) { atLeastOneNonZero = true; std::map::iterator iter = indexCounterMap.find(cntIndex); if (iter != indexCounterMap.end()) { iter->second++; } else { indexCounterMap[cntIndex] = 1; } } } } int paintColIndex = -1; if (indexCounterMap.empty() == false) { int maxIndex = -1; int maxCount = -1; for (std::map::iterator iter = indexCounterMap.begin(); iter != indexCounterMap.end(); iter++) { if (iter->second > maxCount) { maxIndex = iter->first; maxCount = iter->second; } } if (maxCount >= 0) { const float percentSelected = static_cast(maxCount) / static_cast(numSelectedChannels); if (percentSelected >= ratio) { paintColIndex = maxIndex; } } } if (probAtlasThreshPaintFile != NULL) { probAtlasThreshPaintFile->setPaint(j, probAtlasThreshPaintColumn, 0); } if (paintColIndex >= 0) { const int areaColorIndex = paintsAreaColorIndex[paintColIndex]; if (areaColorIndex >= 0) { unsigned char r, g, b; cf->getColorByIndex(areaColorIndex, r, g, b); nodeColors[j].r = r; nodeColors[j].g = g; nodeColors[j].b = b; if (probAtlasThreshPaintFile != NULL) { const int indx = probAtlasThreshPaintFile->addPaintName( paf->getPaintNameFromIndex(paintColIndex)); probAtlasThreshPaintFile->setPaint(j, probAtlasThreshPaintColumn, indx); } } else { nodeColors[j].r = anyAreaColor[0]; nodeColors[j].g = anyAreaColor[1]; nodeColors[j].b = anyAreaColor[2]; paintIndicesWithNoAreaColor.insert(areaColorIndex); } } else if (atLeastOneNonZero && anyAreaColorValid) { nodeColors[j].r = anyAreaColor[0]; nodeColors[j].g = anyAreaColor[1]; nodeColors[j].b = anyAreaColor[2]; } } if (paintsAreaColorIndex != NULL) delete[] paintsAreaColorIndex; } /** * add prob atlas thresholding to paint file * the paint column must exist. */ void BrainModelSurfaceNodeColoring::addProbAtlasThresholdingToPaintFile(PaintFile* paintFileIn, const int paintColumn) { probAtlasThreshPaintFile = paintFileIn; probAtlasThreshPaintColumn = paintColumn; assignColors(); probAtlasThreshPaintFile = NULL; } void BrainModelSurfaceNodeColoring::assignProbabilisticColoring(const BrainModelSurface* bms) { DisplaySettingsProbabilisticAtlas* dspa = brainSet->getDisplaySettingsProbabilisticAtlasSurface(); if (bms != NULL) { dspa->updateSelectedChannelsForCurrentStructure(bms->getStructure()); } if (dspa->getDisplayType() == DisplaySettingsProbabilisticAtlas::PROBABILISTIC_DISPLAY_TYPE_NORMAL) { assignProbabilisticNormalColoring(); } else { assignProbabilisticThresholdColoring(); } } //--------------------------------------------------------------------------- void BrainModelSurfaceNodeColoring::assignBlendGeographyColoring(const int offset, const int /*sourceOffset*/) { PaintFile* pf = brainSet->getPaintFile(); const int geoColumn = pf->getGeographyColumnNumber(); if (geoColumn < 0) { return; } // find all paints that begin with "SUL" const int numPaints = pf->getNumberOfPaintNames(); if (numPaints <= 0) { return; } int* geoPaint = new int[numPaints]; for (int i = 0; i < numPaints; i++) { const QString name = pf->getPaintNameFromIndex(i); if (name.left(3) == "SUL") { geoPaint[i] = 1; } else { geoPaint[i] = 0; } } DisplaySettingsPaint* dsp = brainSet->getDisplaySettingsPaint(); const float geographyBlending = dsp->getGeographyBlending(); const int numNodes = brainSet->getNumberOfNodes(); for (int j = 0; j < numNodes; j++) { const int paintIndex = pf->getPaint(j, geoColumn); if (geoPaint[paintIndex]) { const int indx = offset + (j * 4); nodeColoring[indx] = static_cast(nodeColoring[indx] * geographyBlending); nodeColoring[indx + 1] = static_cast(nodeColoring[indx + 1] * geographyBlending); nodeColoring[indx + 2] = static_cast(nodeColoring[indx + 2] * geographyBlending); } } delete geoPaint; } /** * Crossover coloring. */ void BrainModelSurfaceNodeColoring::assignCrossoverColoring() { const int numNodes = brainSet->getNumberOfNodes(); for (register int i = 0; i < numNodes; i++) { BrainSetNodeAttribute* bna = brainSet->getNodeAttributes(i); if (bna->getCrossover() != BrainSetNodeAttribute::CROSSOVER_NO) { nodeColors[i].r = 255; nodeColors[i].g = 0; nodeColors[i].b = 0; } } } /** * Sections coloring */ void BrainModelSurfaceNodeColoring::assignSectionColoring(const int overlayNumber) { SectionFile* sf = brainSet->getSectionFile(); const int numNodes = sf->getNumberOfNodes(); if (numNodes != brainSet->getNumberOfNodes()) { std::cout << "ERROR: Section file has different number of nodes than surfaces." << std::endl; return; } const DisplaySettingsSection* dss = brainSet->getDisplaySettingsSection(); int selectedSection = -100000; bool sectionEveryX = false; dss->getSectionHighlighting(selectedSection, sectionEveryX); DisplaySettingsSection* ds = brainSet->getDisplaySettingsSection(); const int sectionSetNumber = ds->getSelectedDisplayColumn(-1, overlayNumber); if ((sectionSetNumber >= 0) && (sectionSetNumber < sf->getNumberOfColumns())) { for (int i = 0; i < numNodes; i++) { bool colorIt = false; const int section = sf->getSection(i, sectionSetNumber); if (sectionEveryX) { if (selectedSection == 0) { colorIt = true; } else if ((section % selectedSection) == 0) { colorIt = true; } } else { if (section == selectedSection) { colorIt = true; } } if (colorIt) { nodeColors[i].r = 0; nodeColors[i].g = 0; nodeColors[i].b = 255; } } } } /** * Edges coloring */ void BrainModelSurfaceNodeColoring::assignEdgesColoring() { const int numNodes = brainSet->getNumberOfNodes(); for (register int i = 0; i < numNodes; i++) { BrainSetNodeAttribute* bna = brainSet->getNodeAttributes(i); if (bna->getClassification() == BrainSetNodeAttribute::CLASSIFICATION_TYPE_EDGE) { nodeColors[i].r = 0; nodeColors[i].g = 0; nodeColors[i].b = 255; } } } /** * Surface Shape coloring. */ void BrainModelSurfaceNodeColoring::assignSurfaceShapeColoring(const int overlayNumber) { const SurfaceShapeFile* ssf = brainSet->getSurfaceShapeFile(); const DisplaySettingsSurfaceShape* dsss = brainSet->getDisplaySettingsSurfaceShape(); const int column = dsss->getSelectedDisplayColumn(modelNumber, overlayNumber); if (column < 0) { return; } const int numNodes = ssf->getNumberOfNodes(); if (numNodes <= 0) { return; } if (numNodes != brainSet->getNumberOfNodes()) { std::cerr << "Surface shape file has different number of nodes than surface." << std::endl; return; } float minValue, maxValue; ssf->getColumnColorMappingMinMax(column, minValue, maxValue); float diffMinMax = maxValue - minValue; if (diffMinMax == 0.0) { diffMinMax = 1.0; } // // For palette coloring // PaletteFile* pf = brainSet->getPaletteFile(); const Palette* palette = pf->getPalette(dsss->getSelectedPaletteIndex()); // // Always interpolate if the palette has only two colors // bool interpolatePaletteColor = dsss->getInterpolatePaletteColors(); if (palette->getNumberOfPaletteEntries() == 2) { interpolatePaletteColor = true; } for (int j = 0; j < numNodes; j++) { const float shape = ssf->getValue(j, column); const int gray = getLutIndex(shape, minValue, maxValue); switch(dsss->getColorMap()) { case DisplaySettingsSurfaceShape::SURFACE_SHAPE_COLOR_MAP_GRAY: nodeColors[j].r = gray; nodeColors[j].g = gray; nodeColors[j].b = gray; break; case DisplaySettingsSurfaceShape::SURFACE_SHAPE_COLOR_MAP_ORANGE_YELLOW: nodeColors[j].r = lutOrangeYellow[gray][0]; nodeColors[j].g = lutOrangeYellow[gray][1]; nodeColors[j].b = lutOrangeYellow[gray][2]; break; case DisplaySettingsSurfaceShape::SURFACE_SHAPE_COLOR_MAP_PALETTE: { float normalized = 0.0; if ((palette->getNumberOfPaletteEntries() == 2) && interpolatePaletteColor) { // // Normalize between [0, 1.0] when two color palette interpolate // normalized = (1.0 / diffMinMax) * (shape - minValue); } else { if (shape >= 0.0) { if (maxValue != 0.0) { normalized = shape / maxValue; } } else { if (minValue != 0.0) { normalized = -(shape / minValue); } } } bool isNoneColor = false; unsigned char colors[3]; palette->getColor(normalized, interpolatePaletteColor, isNoneColor, colors); if (isNoneColor == false) { nodeColors[j].r = colors[0]; nodeColors[j].g = colors[1]; nodeColors[j].b = colors[2]; } } break; } } } /** * Assign CoCoMac coloring. */ void BrainModelSurfaceNodeColoring::assignCocomacColoring() { DisplaySettingsCoCoMac* dsc = brainSet->getDisplaySettingsCoCoMac(); CocomacConnectivityFile* ccf = brainSet->getCocomacFile(); const int numProj = ccf->getNumberOfCocomacProjections(); const int node = dsc->getSelectedNode(); QString idInfo; if ((numProj >= 0) && (node >= 0) && (node < brainSet->getNumberOfNodes())) { // // Ensure valid paint column selected for cocomac // const int paintColumn = dsc->getSelectedPaintColumn(); PaintFile* pf = brainSet->getPaintFile(); if ((paintColumn >= 0) && (paintColumn < pf->getNumberOfColumns())) { // // Get the name of the paint // const int selectedPaintIndex = pf->getPaint(node, paintColumn); if ((selectedPaintIndex >= 0) && (selectedPaintIndex < pf->getNumberOfPaintNames())) { const QString paintName(pf->getPaintNameFromIndex(selectedPaintIndex)); std::set paintsOfInterest; for (int i = 0; i < numProj; i++) { CocomacProjection* cp = ccf->getCocomacProjection(i); switch(dsc->getConnectionDisplayType()) { case DisplaySettingsCoCoMac::CONNECTION_DISPLAY_AFFERENT: case DisplaySettingsCoCoMac::CONNECTION_DISPLAY_AFFERENT_OR_EFFERENT: if (paintName == cp->getTargetSite()) { const int sourcePaintIndex = pf->getPaintIndexFromName(cp->getSourceSite()); QString s(" "); s.append(cp->getTargetSite()); s.append(" has afferent connection from "); s.append(cp->getSourceSite()); s.append(" density "); s.append(cp->getDensity()); s.append("\n"); idInfo.append(s); if (sourcePaintIndex >= 0) { paintsOfInterest.insert(sourcePaintIndex); } } if (dsc->getConnectionDisplayType() == DisplaySettingsCoCoMac::CONNECTION_DISPLAY_AFFERENT) { break; } // // no "break;" here. Fall through to show efferent connections if "OR". // case DisplaySettingsCoCoMac::CONNECTION_DISPLAY_EFFERENT: if (paintName == cp->getSourceSite()) { const int targetPaintIndex = pf->getPaintIndexFromName(cp->getTargetSite()); QString s(" "); s.append(cp->getSourceSite()); s.append(" has efferent connection to "); s.append(cp->getTargetSite()); s.append(" density "); s.append(cp->getDensity()); s.append("\n"); idInfo.append(s); if (targetPaintIndex) { paintsOfInterest.insert(targetPaintIndex); } } break; case DisplaySettingsCoCoMac::CONNECTION_DISPLAY_AFFERENT_AND_EFFERENT: if (paintName == cp->getSourceSite()) { const QString targetName(cp->getTargetSite()); QString afferentDensity; bool connectsBothWays = false; for (int j = 0; j < numProj; j++) { CocomacProjection* ocp = ccf->getCocomacProjection(j); if ((ocp->getSourceSite() == targetName) && (ocp->getTargetSite() == paintName)) { connectsBothWays = true; afferentDensity = ocp->getDensity(); break; } } if (connectsBothWays) { const int targetPaintIndex = pf->getPaintIndexFromName(targetName); QString s(" "); s.append(cp->getSourceSite()); s.append(" has afferent and efferent connection with "); s.append(cp->getTargetSite()); s.append(" afferent density "); s.append(afferentDensity); s.append(" efferent density "); s.append(cp->getDensity()); s.append("\n"); idInfo.append(s); if (targetPaintIndex >= 0) { paintsOfInterest.insert(targetPaintIndex); } } } break; } } const int numNodes = brainSet->getNumberOfNodes(); for (int i = 0; i < numNodes; i++) { int rgb[3] = { 0, 0, 0 }; bool applyColorsToNode = false; const int nodePaintIndex = pf->getPaint(i, paintColumn); if (nodePaintIndex == selectedPaintIndex) { rgb[0] = 255; rgb[1] = 0; rgb[2] = 0; applyColorsToNode = true; } else { if (paintsOfInterest.find(nodePaintIndex) != paintsOfInterest.end()) { rgb[0] = 0; rgb[1] = 255; rgb[2] = 0; applyColorsToNode = true; } } if (applyColorsToNode) { nodeColors[i].r = rgb[0]; nodeColors[i].g = rgb[1]; nodeColors[i].b = rgb[2]; } } } } } dsc->setIDInfo(idInfo); } /** * Assign metric coloring. */ void BrainModelSurfaceNodeColoring::assignMetricColoring(const int overlayNumber) { QTime timer; timer.start(); MetricFile* mf = brainSet->getMetricFile(); DisplaySettingsMetric* dsm = brainSet->getDisplaySettingsMetric(); const int viewIndex = dsm->getSelectedDisplayColumn(modelNumber, overlayNumber); if (viewIndex < 0) { return; } const int numNodes = mf->getNumberOfNodes(); if (numNodes != brainSet->getNumberOfNodes()) { std::cerr << "Metric file has different number of nodes than the surface." << std::endl; return; } const PaletteFile* pf = brainSet->getPaletteFile(); if (pf->getNumberOfPalettes() == 0) { std::cerr << "There are no palette files loaded, cannot color metrics." << std::endl; return; } const Palette* palette = pf->getPalette(dsm->getSelectedPaletteIndex()); const bool positiveOnlyPalette = palette->getPositiveOnly(); VolumeFile* funcVolume = NULL; BrainModelVolume* bmv = brainSet->getBrainModelVolume(); if (bmv != NULL) { funcVolume = bmv->getSelectedVolumeFunctionalViewFile(); } float posMinMetric = 0.0, posMaxMetric = 0.0, negMinMetric = 0.0, negMaxMetric = 0.0; DisplaySettingsMetric::METRIC_OVERLAY_SCALE overlayScale = dsm->getSelectedOverlayScale(); if (overlayScale == DisplaySettingsMetric::METRIC_OVERLAY_SCALE_AUTO_FUNC_VOLUME) { if (funcVolume == NULL) { overlayScale = DisplaySettingsMetric::METRIC_OVERLAY_SCALE_AUTO; } } bool userScaleFlag = false; switch (overlayScale) { case DisplaySettingsMetric::METRIC_OVERLAY_SCALE_AUTO: mf->getDataColumnMinMax(dsm->getSelectedDisplayColumn(modelNumber, overlayNumber), //dsm->getFirstSelectedColumnForBrainModel(modelNumber), negMaxMetric, posMaxMetric); break; case DisplaySettingsMetric::METRIC_OVERLAY_SCALE_AUTO_PERCENTAGE: mf->getMinMaxValuesFromPercentages(dsm->getSelectedDisplayColumn(modelNumber, overlayNumber), dsm->getAutoScalePercentageNegativeMaximum(), dsm->getAutoScalePercentageNegativeMinimum(), dsm->getAutoScalePercentagePositiveMinimum(), dsm->getAutoScalePercentagePositiveMaximum(), negMaxMetric, negMinMetric, posMinMetric, posMaxMetric); break; case DisplaySettingsMetric::METRIC_OVERLAY_SCALE_AUTO_SPECIFIED_COLUMN: mf->getDataColumnMinMax(dsm->getOverlayScaleSpecifiedColumnNumber(), negMaxMetric, posMaxMetric); break; case DisplaySettingsMetric::METRIC_OVERLAY_SCALE_AUTO_FUNC_VOLUME: funcVolume->getMinMaxVoxelValues(negMaxMetric, posMaxMetric); break; case DisplaySettingsMetric::METRIC_OVERLAY_SCALE_USER: userScaleFlag = true; dsm->getUserScaleMinMax(posMinMetric, posMaxMetric, negMinMetric, negMaxMetric); break; } //setColorbarMinMaxZero(minMetric, maxMetric, 0.0); const int thresholdIndex = dsm->getSelectedThresholdColumn(modelNumber, overlayNumber); float thresholdNegativeValue = 0.0, thresholdPositiveValue = 0.0; dsm->getUserThresholdingValues(thresholdNegativeValue, thresholdPositiveValue); switch (dsm->getMetricThresholdingType()) { case DisplaySettingsMetric::METRIC_THRESHOLDING_TYPE_FILE_COLUMN: if ((thresholdIndex >= 0) && (thresholdIndex < mf->getNumberOfColumns())) { mf->getColumnThresholding(thresholdIndex, thresholdNegativeValue, thresholdPositiveValue); } break; case DisplaySettingsMetric::METRIC_THRESHOLDING_TYPE_FILE_COLUMN_AVERAGE: if ((thresholdIndex >= 0) && (thresholdIndex < mf->getNumberOfColumns())) { mf->getColumnAverageThresholding(thresholdIndex, thresholdNegativeValue, thresholdPositiveValue); } break; case DisplaySettingsMetric::METRIC_THRESHOLDING_TYPE_USER_VALUES: dsm->getUserThresholdingValues(thresholdNegativeValue, thresholdPositiveValue); break; } // // Always interpolate if the palette has only two colors // bool interpolateColor = dsm->getInterpolateColors(); if (palette->getNumberOfPaletteEntries() == 2) { interpolateColor = true; } unsigned char negThreshColor[3], posThreshColor[3]; dsm->getSpecialColorsForThresholdedNodes(negThreshColor, posThreshColor); const bool showThreshNodes = dsm->getShowSpecialColorForThresholdedNodes(); enum DISPLAY_NODE { DISPLAY_NODE_NORMAL, DISPLAY_NODE_POS_THRESH_COLOR, DISPLAY_NODE_NEG_THRESH_COLOR, DISPLAY_NODE_DO_NOT }; for (int j = 0; j < numNodes; j++) { // // when activation assignment dialog is active only display // those metrics that exceed the threshold value // DISPLAY_NODE displayNode = DISPLAY_NODE_NORMAL; const float thresh = mf->getValue(j, thresholdIndex); if (thresh >= 0.0) { if (thresh < thresholdPositiveValue) { displayNode = DISPLAY_NODE_DO_NOT; if (showThreshNodes) { if (thresh != 0.0) { displayNode = DISPLAY_NODE_POS_THRESH_COLOR; } } } } if (thresh <= 0.0) { if (thresh > thresholdNegativeValue) { displayNode = DISPLAY_NODE_DO_NOT; if (showThreshNodes) { if (thresh != 0.0) { displayNode = DISPLAY_NODE_NEG_THRESH_COLOR; } } } } const float metric = mf->getValue(j, viewIndex); switch(dsm->getDisplayMode()) { case DisplaySettingsMetric::METRIC_DISPLAY_MODE_POSITIVE_AND_NEGATIVE: break; case DisplaySettingsMetric::METRIC_DISPLAY_MODE_NEGATIVE_ONLY: if (metric >= 0.0) { displayNode = DISPLAY_NODE_DO_NOT; } break; case DisplaySettingsMetric::METRIC_DISPLAY_MODE_POSITIVE_ONLY: if (metric <= 0.0) { displayNode = DISPLAY_NODE_DO_NOT; } break; } if (positiveOnlyPalette) { if (dsm->getDisplayMode() == DisplaySettingsMetric::METRIC_DISPLAY_MODE_POSITIVE_AND_NEGATIVE) { if (metric <= 0.0) { displayNode = DISPLAY_NODE_DO_NOT; } } } // // Do not color nodes that are not within user scale // if (userScaleFlag) { if ((metric > negMinMetric) && (metric < posMinMetric)) { displayNode = DISPLAY_NODE_DO_NOT; } } switch (displayNode) { case DISPLAY_NODE_NORMAL: { float normalized = 0.0; if ((palette->getNumberOfPaletteEntries() == 2) && interpolateColor) { // // Normalize between [0, 1.0] when two color palette interpolate // float diffMetric = posMaxMetric - negMaxMetric; if (diffMetric == 0.0) { diffMetric = 1.0; } normalized = (metric - negMaxMetric) / diffMetric; } else { if (metric >= posMinMetric) { const float numerator = metric - posMinMetric; float denominator = posMaxMetric - posMinMetric; if (denominator == 0.0) { denominator = 1.0; } normalized = numerator / denominator; } else if (metric <= negMinMetric) { const float numerator = metric - negMinMetric; float denominator = negMaxMetric - negMinMetric; if (denominator == 0.0) { denominator = 1.0; } else if (denominator < 0.0) { denominator = -denominator; } normalized = numerator / denominator; // // allow a "Postive Only" palette with "Negative Only" displayed // if (positiveOnlyPalette && (dsm->getDisplayMode() == DisplaySettingsMetric::METRIC_DISPLAY_MODE_NEGATIVE_ONLY)) { normalized = -normalized; } } } bool isNoneColor = false; unsigned char colors[3]; palette->getColor(normalized, interpolateColor, isNoneColor, colors); if (isNoneColor == false) { nodeColors[j].r = colors[0]; nodeColors[j].g = colors[1]; nodeColors[j].b = colors[2]; } } break; case DISPLAY_NODE_POS_THRESH_COLOR: nodeColors[j].r = posThreshColor[0]; nodeColors[j].g = posThreshColor[1]; nodeColors[j].b = posThreshColor[2]; break; case DISPLAY_NODE_NEG_THRESH_COLOR: nodeColors[j].r = negThreshColor[0]; nodeColors[j].g = negThreshColor[1]; nodeColors[j].b = negThreshColor[2]; break; case DISPLAY_NODE_DO_NOT: break; } } if (DebugControl::getDebugOn()) { std::cout << "Time to assign metric colors: " << (static_cast(timer.elapsed()) / 1000.0) << std::endl; } } //--------------------------------------------------------------------------- // ***COLORS // dk-blue = #0000ff // blue = #0044ff // lt-blue1 = #0069ff // lt-blue2 = #0099ff // blue-cyan = #00ccff // cyan = #00ffff // green = #00ff00 // limegreen = #10b010 // yellow = #ffff00 // orange = #ff6900 // oran-red = #ff4400 // red = #ff0000 // purple = #66004c // ***PALETTES [13] // 1.000000 -> dk-blue // 0.640000 -> blue // 0.460000 -> lt-blue1 // 0.320000 -> lt-blue2 // 0.230000 -> blue-cyan // 0.160000 -> cyan // 0.112000 -> green // 0.080000 -> limegreen // 0.056000 -> yellow // 0.040000 -> orange // 0.028000 -> oran-red // 0.020000 -> red // 0.000000 -> purple void BrainModelSurfaceNodeColoring::assignTopographyEccentricityPalette() { unsigned char rgb[3]; eccentricityTopographyPaletteFile.clear(); Palette palette(&eccentricityTopographyPaletteFile); palette.setPositiveOnly(false); palette.setName("Eccentricity"); rgb[0] = 0x00; rgb[1] = 0x00; rgb[2] = 0xff; PaletteColor dkBlue("dk-blue", rgb); eccentricityTopographyPaletteFile.addPaletteColor(dkBlue); palette.addPaletteEntry(1.0, dkBlue.getName()); rgb[0] = 0x00; rgb[1] = 0x44; rgb[2] = 0xff; PaletteColor blue("blue", rgb); eccentricityTopographyPaletteFile.addPaletteColor(blue); palette.addPaletteEntry(0.64, blue.getName()); rgb[0] = 0x00; rgb[1] = 0x69; rgb[2] = 0xff; PaletteColor ltBlue1("lt-blue1", rgb); eccentricityTopographyPaletteFile.addPaletteColor(ltBlue1); palette.addPaletteEntry(0.46, ltBlue1.getName()); rgb[0] = 0x00; rgb[1] = 0x99; rgb[2] = 0xff; PaletteColor ltBlue2("lt-blue2", rgb); eccentricityTopographyPaletteFile.addPaletteColor(ltBlue2); palette.addPaletteEntry(0.32, ltBlue2.getName()); rgb[0] = 0x00; rgb[1] = 0xcc; rgb[2] = 0xff; PaletteColor blueCyan("blue-cyan", rgb); eccentricityTopographyPaletteFile.addPaletteColor(blueCyan); palette.addPaletteEntry(0.23, blueCyan.getName()); rgb[0] = 0x00; rgb[1] = 0xff; rgb[2] = 0xff; PaletteColor cyan("cyan", rgb); eccentricityTopographyPaletteFile.addPaletteColor(cyan); palette.addPaletteEntry(0.16, cyan.getName()); rgb[0] = 0x00; rgb[1] = 0xff; rgb[2] = 0x00; PaletteColor green("green", rgb); eccentricityTopographyPaletteFile.addPaletteColor(green); palette.addPaletteEntry(0.112, green.getName()); rgb[0] = 0x10; rgb[1] = 0xb0; rgb[2] = 0x10; PaletteColor limeGreen("limegreen", rgb); eccentricityTopographyPaletteFile.addPaletteColor(limeGreen); palette.addPaletteEntry(0.08, limeGreen.getName()); rgb[0] = 0xff; rgb[1] = 0xff; rgb[2] = 0x00; PaletteColor yellow("yellow", rgb); eccentricityTopographyPaletteFile.addPaletteColor(yellow); palette.addPaletteEntry(0.056, yellow.getName()); rgb[0] = 0xff; rgb[1] = 0x69; rgb[2] = 0x00; PaletteColor orange("orange", rgb); eccentricityTopographyPaletteFile.addPaletteColor(orange); palette.addPaletteEntry(0.04, orange.getName()); rgb[0] = 0xff; rgb[1] = 0x44; rgb[2] = 0x00; PaletteColor oranRed("oran-red", rgb); eccentricityTopographyPaletteFile.addPaletteColor(oranRed); palette.addPaletteEntry(0.028, oranRed.getName()); rgb[0] = 0xff; rgb[1] = 0x00; rgb[2] = 0x00; PaletteColor red("red", rgb); eccentricityTopographyPaletteFile.addPaletteColor(red); palette.addPaletteEntry(0.02, red.getName()); rgb[0] = 0x66; rgb[1] = 0x00; rgb[2] = 0x4c; PaletteColor purple("purple", rgb); eccentricityTopographyPaletteFile.addPaletteColor(purple); palette.addPaletteEntry(0.00, purple.getName()); eccentricityTopographyPaletteFile.addPalette(palette); } //--------------------------------------------------------------------------- // ***COLORS // red = #ff0000 // yellow = #ffff00 // green = #00ff00 // cyan = #00ffff // blue = #0044ff // ***PALETTES [5] // 1.000000 -> red // 0.50000 -> yellow // 0.00000 -> green // -.50000 -> cyan // -1.00 -> blue /** * Assign topography polar angle coloring */ void BrainModelSurfaceNodeColoring::assignTopographyPolarAnglePalette() { unsigned char rgb[3]; polarAngleTopographyPaletteFile.clear(); Palette palette(&polarAngleTopographyPaletteFile); palette.setPositiveOnly(false); palette.setName("Polar Angle"); rgb[0] = 0xff; rgb[1] = 0x00; rgb[2] = 0x00; PaletteColor red("red", rgb); polarAngleTopographyPaletteFile.addPaletteColor(red); palette.addPaletteEntry(1.0, red.getName()); rgb[0] = 0xff; rgb[1] = 0xff; rgb[2] = 0x00; PaletteColor yellow("yellow", rgb); polarAngleTopographyPaletteFile.addPaletteColor(yellow); palette.addPaletteEntry(0.5, yellow.getName()); rgb[0] = 0x00; rgb[1] = 0xff; rgb[2] = 0x00; PaletteColor green("green", rgb); polarAngleTopographyPaletteFile.addPaletteColor(green); palette.addPaletteEntry(0.0, green.getName()); rgb[0] = 0x00; rgb[1] = 0xff; rgb[2] = 0xff; PaletteColor cyan("cyan", rgb); polarAngleTopographyPaletteFile.addPaletteColor(cyan); palette.addPaletteEntry(-0.5, cyan.getName()); rgb[0] = 0x00; rgb[1] = 0x44; rgb[2] = 0xff; PaletteColor blue("blue", rgb); polarAngleTopographyPaletteFile.addPaletteColor(blue); palette.addPaletteEntry(-1.0, blue.getName()); polarAngleTopographyPaletteFile.addPalette(palette); } /** * Assign from topography */ void BrainModelSurfaceNodeColoring::assignTopographyColoring(const int overlayNumber) { TopographyFile* tf = brainSet->getTopographyFile(); if ((tf->getNumberOfNodes() == 0) || (tf->getNumberOfColumns() == 0)) { return; } DisplaySettingsTopography* dst = brainSet->getDisplaySettingsTopography(); const int column = dst->getSelectedDisplayColumn(modelNumber, overlayNumber); const bool showEccentricity = (dst->getDisplayType() == DisplaySettingsTopography::TOPOGRAPHY_DISPLAY_ECCENTRICITY); const int numNodes = brainSet->getNumberOfNodes(); if (numNodes != tf->getNumberOfNodes()) { std::cerr << "Topography has different number of nodes than surface." << std::endl; return; } #ifdef Q_OS_WIN32 float minScalar = 10000000000.0; float maxScalar = -minScalar; #else float minScalar = std::numeric_limits::max(); float maxScalar = -std::numeric_limits::max(); #endif bool* topographyValid = new bool[numNodes]; float* topographyScalar = new float[numNodes]; for (int h = 0; h < numNodes; h++) { topographyValid[h] = false; } for (int i = 0; i < numNodes; i++) { const NodeTopography nt = tf->getNodeTopography(i, column); float eMean, eLow, eHigh, pMean, pLow, pHigh; QString areaName; nt.getData(eMean, eLow, eHigh, pMean, pLow, pHigh, areaName); if (areaName.isEmpty() == false) { topographyValid[i] = true; if (showEccentricity) { topographyScalar[i] = eMean; } else { topographyScalar[i] = pMean; } if (topographyScalar[i] > maxScalar) { maxScalar = topographyScalar[i]; } if (topographyScalar[i] < minScalar) { minScalar = topographyScalar[i]; } } } for (int j = 0; j < numNodes; j++) { if (topographyValid[j]) { float normalized = 0.0; if (topographyScalar[j] >= 0.0) { normalized = topographyScalar[j] / maxScalar; } else { normalized = -(topographyScalar[j] / minScalar); } bool noneColorFlag = false; unsigned char colors[3]; if (showEccentricity) { const Palette* pal = eccentricityTopographyPaletteFile.getPalette(0); pal->getColor(normalized, false, noneColorFlag, colors); } else { const Palette* pal = polarAngleTopographyPaletteFile.getPalette(0); pal->getColor(normalized, false, noneColorFlag, colors); } nodeColors[j].r = colors[0]; nodeColors[j].g = colors[1]; nodeColors[j].b = colors[2]; } } delete[] topographyValid; delete[] topographyScalar; } /** * Clamp a float value to an int in [0, 255] */ int BrainModelSurfaceNodeColoring::clamp0255(const float v) const { int value = static_cast(v + 0.5); if (value > 255) value = 255; if (value < 0) value = 0; return value; } /** * Assign surface coloring to the brain surface's nodes. */ void BrainModelSurfaceNodeColoring::assignColors() { QTime timer; timer.start(); paintIndicesWithNoAreaColor.clear(); brainSet->clearAllDisplayLists(); const int numNodes = brainSet->getNumberOfNodes(); if (numNodes < 0) { return; } const int numBrainModels = brainSet->getNumberOfBrainModels(); if (numBrainModels < 0) { return; } const int numberOfSurfaceOverlays = brainSet->getNumberOfSurfaceOverlays(); if ((numNodesLastTime < 0) || (numNodesLastTime != numNodes) || (numBrainModelsLastTime < 0) || (numBrainModelsLastTime != numBrainModels)) { nodeColors.resize(numNodes); nodeColoring.resize(numNodes * 4 * numBrainModels); nodeColorSource.resize(numNodes * numBrainModels); numNodesLastTime = numNodes; numBrainModelsLastTime = numBrainModels; } setDefaultColor(); for (modelNumber = 0; modelNumber < numBrainModels; modelNumber++) { // // offsets into nodeColoring and nodeColorSource // const int nodeColorSourceOffset = modelNumber * numNodes; const int nodeColoringOffset = nodeColorSourceOffset * 4; // // If this is not the first model number // if (modelNumber > 0) { // // If this model has the same coloring as the first model // bool copySurfaceColorsFlag = true; for (int i = 0; i < numberOfSurfaceOverlays; i++) { // // Are the two overlays set the same ? // BrainModelSurfaceOverlay* bmsOverlay = brainSet->getSurfaceOverlay(i); if (bmsOverlay->getOverlay(modelNumber) == bmsOverlay->getOverlay(0)) { DisplaySettingsNodeAttributeFile* dsnaf = NULL; switch(bmsOverlay->getOverlay(modelNumber)) { case BrainModelSurfaceOverlay::OVERLAY_NONE: break; case BrainModelSurfaceOverlay::OVERLAY_AREAL_ESTIMATION: dsnaf = brainSet->getDisplaySettingsArealEstimation(); break; case BrainModelSurfaceOverlay::OVERLAY_COCOMAC: //dsnaf = brainSet->getDisplaySettingsCoCoMac(); break; case BrainModelSurfaceOverlay::OVERLAY_METRIC: dsnaf = brainSet->getDisplaySettingsMetric(); break; case BrainModelSurfaceOverlay::OVERLAY_PAINT: dsnaf = brainSet->getDisplaySettingsPaint(); break; case BrainModelSurfaceOverlay::OVERLAY_PROBABILISTIC_ATLAS: //dsnaf = brainSet->getDisplaySettingsProbabilisticAtlasSurface(); break; case BrainModelSurfaceOverlay::OVERLAY_RGB_PAINT: dsnaf = brainSet->getDisplaySettingsRgbPaint(); break; case BrainModelSurfaceOverlay::OVERLAY_SECTIONS: break; case BrainModelSurfaceOverlay::OVERLAY_SHOW_CROSSOVERS: break; case BrainModelSurfaceOverlay::OVERLAY_SHOW_EDGES: break; case BrainModelSurfaceOverlay::OVERLAY_SURFACE_SHAPE: dsnaf = brainSet->getDisplaySettingsSurfaceShape(); break; case BrainModelSurfaceOverlay::OVERLAY_TOPOGRAPHY: dsnaf = brainSet->getDisplaySettingsTopography(); break; case BrainModelSurfaceOverlay::OVERLAY_GEOGRAPHY_BLENDING: break; } if (dsnaf != NULL) { if (dsnaf->columnSelectionsAreTheSame(modelNumber, 0) == false) { copySurfaceColorsFlag = false; } } } else { copySurfaceColorsFlag = false; break; } } if (copySurfaceColorsFlag) { // // Copy coloring // for (int i = 0; i < numNodes; i++) { nodeColoring[nodeColoringOffset + i*4] = nodeColoring[i*4]; nodeColoring[nodeColoringOffset + i*4+1] = nodeColoring[i*4+1]; nodeColoring[nodeColoringOffset + i*4+2] = nodeColoring[i*4+2]; nodeColoring[nodeColoringOffset + i*4+3] = nodeColoring[i*4+3]; nodeColorSource[nodeColorSourceOffset + i] = nodeColorSource[i]; } // // Go to the next model // continue; } } // // initialize nodes to default color // assignNoneColoring(nodeColoringOffset, nodeColorSourceOffset); // // Use selected coloring mode // switch (coloringMode) { case COLORING_MODE_NORMAL: { // // Loop through the overlays and assign the colors // for (int iso = 0; iso < numberOfSurfaceOverlays; iso++) { // // Reset the colors // for (int i = 0; i < numNodes; i++) { nodeColors[i].reset(); } // // Get the surface overlay // const BrainModelSurfaceOverlay* bmsOverlay = brainSet->getSurfaceOverlay(iso); // // Color using the overlay // switch (bmsOverlay->getOverlay(modelNumber)) { case BrainModelSurfaceOverlay::OVERLAY_NONE: break; case BrainModelSurfaceOverlay::OVERLAY_AREAL_ESTIMATION: assignArealEstimationColoring(iso); break; case BrainModelSurfaceOverlay::OVERLAY_COCOMAC: assignCocomacColoring(); break; case BrainModelSurfaceOverlay::OVERLAY_METRIC: assignMetricColoring(iso); break; case BrainModelSurfaceOverlay::OVERLAY_PAINT: assignPaintColoring(iso); break; case BrainModelSurfaceOverlay::OVERLAY_PROBABILISTIC_ATLAS: assignProbabilisticColoring(brainSet->getBrainModelSurface(modelNumber)); break; case BrainModelSurfaceOverlay::OVERLAY_RGB_PAINT: assignRgbPaintColoring(iso, false); break; case BrainModelSurfaceOverlay::OVERLAY_SECTIONS: assignSectionColoring(iso); break; case BrainModelSurfaceOverlay::OVERLAY_SHOW_CROSSOVERS: assignCrossoverColoring(); break; case BrainModelSurfaceOverlay::OVERLAY_SHOW_EDGES: assignEdgesColoring(); break; case BrainModelSurfaceOverlay::OVERLAY_SURFACE_SHAPE: assignSurfaceShapeColoring(iso); break; case BrainModelSurfaceOverlay::OVERLAY_TOPOGRAPHY: assignTopographyColoring(iso); break; case BrainModelSurfaceOverlay::OVERLAY_GEOGRAPHY_BLENDING: // handled later in this method break; } // // Get opacity for blending overlays // const float overlayOpacity = bmsOverlay->getOpacity(); const float oneMinusOverlayOpacity = 1.0 - overlayOpacity; // // Apply coloring to nodes // for (int i = 0; i < numNodes; i++) { // // Was color applied to the node for this overlay // if ((nodeColors[i].r >= 0) || (nodeColors[i].g >= 0) || (nodeColors[i].b >= 0)) { float r = nodeColors[i].r * overlayOpacity + nodeColoring[nodeColoringOffset + i*4] * oneMinusOverlayOpacity; float g = nodeColors[i].g * overlayOpacity + nodeColoring[nodeColoringOffset + i*4+1] * oneMinusOverlayOpacity; float b = nodeColors[i].b * overlayOpacity + nodeColoring[nodeColoringOffset + i*4+2] * oneMinusOverlayOpacity; nodeColoring[nodeColoringOffset + i*4] = clamp0255(r); nodeColoring[nodeColoringOffset + i*4+1] = clamp0255(g); nodeColoring[nodeColoringOffset + i*4+2] = clamp0255(b); nodeColoring[nodeColoringOffset + i*4+3] = 255; nodeColorSource[nodeColorSourceOffset + i] = iso; } } // // Special case for geography blending do if previous overlay was // geography blending // if (iso > 0) { if (brainSet->getSurfaceOverlay(iso - 1)->getOverlay(modelNumber) == BrainModelSurfaceOverlay::OVERLAY_GEOGRAPHY_BLENDING) { assignBlendGeographyColoring(nodeColoringOffset, nodeColorSourceOffset); } } } } break; case COLORING_MODE_OVERLAY_BLENDING: { // // Node coloring for the three most primary overlays and the underlay // std::vector primaryOverlayColors; std::vector secondaryOverlayColors; std::vector tertiaryOverlayColors; std::vector underlayColors; // // Indices of overlays // const int primaryOverlayIndex = numberOfSurfaceOverlays - 1; const int secondaryOverlayIndex = numberOfSurfaceOverlays - 2; const int tertiaryOverlayIndex = numberOfSurfaceOverlays - 3; // // Loop through the overlays and assign the colors // for (int iso = 0; iso < numberOfSurfaceOverlays; iso++) { // // Reset the colors // for (int i = 0; i < numNodes; i++) { nodeColors[i].reset(); } // // Get the surface overlay // const BrainModelSurfaceOverlay* bmsOverlay = brainSet->getSurfaceOverlay(iso); // // Color using the overlay // switch (bmsOverlay->getOverlay(modelNumber)) { case BrainModelSurfaceOverlay::OVERLAY_NONE: break; case BrainModelSurfaceOverlay::OVERLAY_AREAL_ESTIMATION: assignArealEstimationColoring(iso); break; case BrainModelSurfaceOverlay::OVERLAY_COCOMAC: assignCocomacColoring(); break; case BrainModelSurfaceOverlay::OVERLAY_METRIC: assignMetricColoring(iso); break; case BrainModelSurfaceOverlay::OVERLAY_PAINT: assignPaintColoring(iso); break; case BrainModelSurfaceOverlay::OVERLAY_PROBABILISTIC_ATLAS: assignProbabilisticColoring(brainSet->getBrainModelSurface(modelNumber)); break; case BrainModelSurfaceOverlay::OVERLAY_RGB_PAINT: assignRgbPaintColoring(iso, false); break; case BrainModelSurfaceOverlay::OVERLAY_SECTIONS: assignSectionColoring(iso); break; case BrainModelSurfaceOverlay::OVERLAY_SHOW_CROSSOVERS: assignCrossoverColoring(); break; case BrainModelSurfaceOverlay::OVERLAY_SHOW_EDGES: assignEdgesColoring(); break; case BrainModelSurfaceOverlay::OVERLAY_SURFACE_SHAPE: assignSurfaceShapeColoring(iso); break; case BrainModelSurfaceOverlay::OVERLAY_TOPOGRAPHY: assignTopographyColoring(iso); break; case BrainModelSurfaceOverlay::OVERLAY_GEOGRAPHY_BLENDING: // handled later in this method break; } // // Assign the colors to the proper underlay/overlay // if (iso == 0) { underlayColors = nodeColors; } else if (iso == primaryOverlayIndex) { primaryOverlayColors = nodeColors; } else if (iso == secondaryOverlayIndex) { secondaryOverlayColors = nodeColors; } else if (iso == tertiaryOverlayIndex) { tertiaryOverlayColors = nodeColors; } } // // Blend the colors // for (int i = 0; i < numNodes; i++) { // // Was color applied to the node for this overlay // if (primaryOverlayColors[i].isValid() || secondaryOverlayColors[i].isValid() || tertiaryOverlayColors[i].isValid()) { float r = 0.0, g = 0.0, b = 0.0; float sum = 0.0; float maxBefore = 0.0; int overlayColorSource = 0; if (tertiaryOverlayColors[i].isValid()) { r += tertiaryOverlayColors[i].r; g += tertiaryOverlayColors[i].g; b += tertiaryOverlayColors[i].b; overlayColorSource = primaryOverlayIndex; sum += 1.0; maxBefore = std::max(tertiaryOverlayColors[i].r, std::max(tertiaryOverlayColors[i].g, tertiaryOverlayColors[i].b)); } if (secondaryOverlayColors[i].isValid()) { r += secondaryOverlayColors[i].r; g += secondaryOverlayColors[i].g; b += secondaryOverlayColors[i].b; overlayColorSource = secondaryOverlayIndex; sum += 1.0; maxBefore = std::max(secondaryOverlayColors[i].r, std::max(secondaryOverlayColors[i].g, secondaryOverlayColors[i].b)); } if (primaryOverlayColors[i].isValid()) { r += primaryOverlayColors[i].r; g += primaryOverlayColors[i].g; b += primaryOverlayColors[i].b; overlayColorSource = tertiaryOverlayIndex; sum += 1.0; maxBefore = std::max(primaryOverlayColors[i].r, std::max(primaryOverlayColors[i].g, primaryOverlayColors[i].b)); } if (sum > 0.0) { const float maxAfter = std::max(r, std::max(g, b)); const float scale = maxBefore / maxAfter; sum = 1.0; nodeColoring[nodeColoringOffset + i*4] = clamp0255(r / sum); nodeColoring[nodeColoringOffset + i*4+1] = clamp0255(g / sum); nodeColoring[nodeColoringOffset + i*4+2] = clamp0255(b / sum); nodeColoring[nodeColoringOffset + i*4] = clamp0255(r * scale); nodeColoring[nodeColoringOffset + i*4+1] = clamp0255(g * scale); nodeColoring[nodeColoringOffset + i*4+2] = clamp0255(b * scale); nodeColoring[nodeColoringOffset + i*4+3] = 255; nodeColorSource[nodeColorSourceOffset + i] = overlayColorSource; } } else if (underlayColors[i].isValid()) { nodeColoring[nodeColoringOffset + i*4] = clamp0255(underlayColors[i].r); nodeColoring[nodeColoringOffset + i*4+1] = clamp0255(underlayColors[i].g); nodeColoring[nodeColoringOffset + i*4+2] = clamp0255(underlayColors[i].b); nodeColoring[nodeColoringOffset + i*4+3] = 255; nodeColorSource[nodeColorSourceOffset + i] = 0; } } } break; } // // Apply contrast and brightness // DisplaySettingsSurface* dsn = brainSet->getDisplaySettingsSurface(); const float brightness = dsn->getNodeBrightness(); const float contrast = dsn->getNodeContrast(); if ((brightness != 0.0) || (contrast != 1.0)) { for (int i = 0; i < numNodes; i++) { float r = nodeColoring[nodeColoringOffset + i*4]; float g = nodeColoring[nodeColoringOffset + i*4+1]; float b = nodeColoring[nodeColoringOffset + i*4+2]; // // Brightness is added // r += brightness; g += brightness; b += brightness; // // Contrast is multiplied // r *= contrast; g *= contrast; b *= contrast; // // color components may become greater than 255 in which case all of the components should // be scaled to the range [0 255] to maintain the proper hue. // float maxValue = r; if (g > maxValue) maxValue = g; if (b > maxValue) maxValue = b; float scale = 1.0; if (maxValue > 255.0) { scale = 255.0 / maxValue; } nodeColoring[nodeColoringOffset + i*4] = clamp0255(r * scale); nodeColoring[nodeColoringOffset + i*4+1] = clamp0255(g * scale); nodeColoring[nodeColoringOffset + i*4+2] = clamp0255(b * scale); } } // // Apply opacity // const float surfaceOpacity = dsn->getOpacity(); for (int i = 0; i < numNodes; i++) { nodeColoring[nodeColoringOffset + i*4+3] = clamp0255(surfaceOpacity * 255.0); } assignMedialWallOverrideColoring(nodeColoringOffset, nodeColorSourceOffset); } if (paintIndicesWithNoAreaColor.empty() == false) { PaintFile* pf = brainSet->getPaintFile(); std::cout << "WARNING: Paint names with no corresponding area colors:" << std::endl; for (std::set::iterator iter = paintIndicesWithNoAreaColor.begin(); iter != paintIndicesWithNoAreaColor.end(); iter++) { QString name = pf->getPaintNameFromIndex(*iter); if (name.isEmpty()) { name = "<...empty name for index=" + QString::number(*iter) + ">"; } std::cout << " " << name.toAscii().constData() << std::endl; } std::cout << std::endl; paintIndicesWithNoAreaColor.clear(); } if (DebugControl::getDebugOn()) { std::cout << "Time to assign colors to surface nodes was " << (static_cast(timer.elapsed()) / 1000.0) << std::endl; } } /** * assign medial wall override coloring. */ void BrainModelSurfaceNodeColoring::assignMedialWallOverrideColoring(const int colorOffset, const int sourceOffset) { PaintFile* pf = brainSet->getPaintFile(); DisplaySettingsPaint* dsp = brainSet->getDisplaySettingsPaint(); if (dsp->getMedialWallOverrideColumnEnabled()) { const int paintColumn = dsp->getMedialWallOverrideColumn(); if ((paintColumn >= 0) && (paintColumn < pf->getNumberOfColumns())) { const int medWallIndex = pf->getPaintIndexFromName("MEDIAL.WALL"); if (medWallIndex > 0) { const int numNodes = pf->getNumberOfNodes(); if (numNodes == 0) { return; } if (numNodes != brainSet->getNumberOfNodes()) { std::cerr << "Number of nodes in Paint File does not match surface." << std::endl; return; } AreaColorFile* cf = brainSet->getAreaColorFile(); bool match = false; const int colorIndex = cf->getColorIndexByName("MEDIAL.WALL", match); if ((colorIndex >= 0) && match) { unsigned char r, g, b; cf->getColorByIndex(colorIndex, r, g, b); for (int i = 0; i < numNodes; i++) { if (pf->getPaint(i, paintColumn) == medWallIndex) { nodeColoring[colorOffset + i*4] = r; nodeColoring[colorOffset + i*4+1] = g; nodeColoring[colorOffset + i*4+2] = b; nodeColorSource[sourceOffset + i] = -1; } } } } } } } // // Strings for showing and saving scenes // static const QString underlayNameID("Surface-Underlay-Name"); static const QString secondaryOverlayNameID("Surface-Secondary-Overlay-Name"); static const QString primaryOverlayNameID("Surface-Primary-Overlay-Name"); static const QString ouNoneName("none"); static const QString ouArealEstimationName("areal-estimation"); static const QString ouCocomacName("cocomac"); static const QString ouMetricName("metric"); static const QString ouPaintName("paint"); static const QString ouProbabilisticAtlasName("probabilistic-atlas"); static const QString ouRgbPaintName("rgb-paint"); static const QString ouSectionsName("sections"); static const QString ouShowCrossoversName("show-crossovers"); static const QString ouShowEdgesName("show-edges"); static const QString ouSurfaceShapeName("surface-shape"); static const QString ouTopographyName("topography"); static const QString ouGeographyBlendingName("geography-blending"); static const QString ouGeographyBlending("geographyBlending"); static const QString ouOpacity("opacity"); static const QString ouLighting("lightingOn"); static const QString ouPrimaryLighting("primaryOverlayLightingOn"); static const QString ouSecondaryLighting("secondaryOverlayLightingOn"); static const QString ouUnderlayLighting("underlayLightingOn"); /** * apply a scene (set display settings). */ void BrainModelSurfaceNodeColoring::showScene(const SceneFile::Scene& scene, QString& errorMessage) { coloringMode = COLORING_MODE_NORMAL; const int numOverlays = brainSet->getNumberOfSurfaceOverlays(); const int primaryOverlayNumber = numOverlays - 1; const int secondaryOverlayNumber = numOverlays - 2; const int underlayNumber = 0; DisplaySettingsPaint* dsp = brainSet->getDisplaySettingsPaint(); const int numClasses = scene.getNumberOfSceneClasses(); for (int nc = 0; nc < numClasses; nc++) { const SceneFile::SceneClass* sc = scene.getSceneClass(nc); if (sc->getName() == "BrainModelSurfaceNodeColoring") { const int num = sc->getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc->getSceneInfo(i); const QString infoName = si->getName(); const QString value = si->getValueAsString(); if (infoName == "coloringMode") { if (value == "NORMAL") { coloringMode = COLORING_MODE_NORMAL; break; } else if (value == "BLENDING") { coloringMode = COLORING_MODE_OVERLAY_BLENDING; break; } } // // NOTE: ALL OF THESE SCENE ITEMS SUPPORT SCENES MADE PRIOR TO // THE NEW OVERLAY SYSTEM // if (infoName == ouGeographyBlending) { dsp->setGeographyBlending(si->getValueAsFloat()); } else if (infoName == ouOpacity) { for (int i = 0; i < numOverlays; i++) { brainSet->getSurfaceOverlay(i)->setOpacity(si->getValueAsFloat()); } } else if (infoName == ouLighting) { //setLightingOn(si->getValueAsBool()); } else if (infoName == ouPrimaryLighting) { brainSet->getSurfaceOverlay(primaryOverlayNumber)->setLightingEnabled(si->getValueAsBool()); } else if (infoName == ouSecondaryLighting) { brainSet->getSurfaceOverlay(secondaryOverlayNumber)->setLightingEnabled(si->getValueAsBool()); } else if (infoName == ouUnderlayLighting) { brainSet->getSurfaceOverlay(underlayNumber)->setLightingEnabled(si->getValueAsBool()); } // // Is this for underlay or overlay ? // if ((infoName == underlayNameID) || (infoName == secondaryOverlayNameID) || (infoName == primaryOverlayNameID)) { BrainModelSurfaceOverlay::OVERLAY_SELECTIONS overlay = BrainModelSurfaceOverlay::OVERLAY_NONE; const QString surfaceName = si->getModelName(); if (value == ouArealEstimationName) { overlay = BrainModelSurfaceOverlay::OVERLAY_AREAL_ESTIMATION; if (brainSet->getArealEstimationFile()->getNumberOfColumns() <= 0) { errorMessage.append("Areal Estimation File is overlay/underlay but no Areal Estimation File is loaded.\n"); } } else if (value == ouCocomacName) { overlay = BrainModelSurfaceOverlay::OVERLAY_COCOMAC; const CocomacConnectivityFile* coco = brainSet->getCocomacFile(); if (coco->empty()) { errorMessage.append("CoCoMac File is overlay/underlay but no CoCoMac File is loaded.\n"); } } else if (value == ouMetricName) { overlay = BrainModelSurfaceOverlay::OVERLAY_METRIC; if (brainSet->getMetricFile()->empty()) { errorMessage.append("Metric File is overlay/underlay but no Metric File is loaded.\n"); } } else if (value == ouPaintName) { overlay = BrainModelSurfaceOverlay::OVERLAY_PAINT; if (brainSet->getPaintFile()->empty()) { errorMessage.append("Paint File is overlay/underlay but no Paint File is loaded.\n"); } } else if (value == ouProbabilisticAtlasName) { overlay = BrainModelSurfaceOverlay::OVERLAY_PROBABILISTIC_ATLAS; if (brainSet->getProbabilisticAtlasSurfaceFile()->empty()) { errorMessage.append("Prob Atlas File is overlay/underlay but no Prob Atlas File is loaded.\n"); } } else if (value == ouRgbPaintName) { overlay = BrainModelSurfaceOverlay::OVERLAY_RGB_PAINT; if (brainSet->getRgbPaintFile()->empty()) { errorMessage.append("RGB Paint File is overlay/underlay but no RGB Paint File is loaded.\n"); } } else if (value == ouSectionsName) { overlay = BrainModelSurfaceOverlay::OVERLAY_SECTIONS; } else if (value == ouShowCrossoversName) { overlay = BrainModelSurfaceOverlay::OVERLAY_SHOW_CROSSOVERS; } else if (value == ouShowEdgesName) { overlay = BrainModelSurfaceOverlay::OVERLAY_SHOW_EDGES; } else if (value == ouSurfaceShapeName) { overlay = BrainModelSurfaceOverlay::OVERLAY_SURFACE_SHAPE; if (brainSet->getSurfaceShapeFile()->empty()) { errorMessage.append("Surface Shape File is overlay/underlay but no Surface Shape File is loaded.\n"); } } else if (value == ouTopographyName) { overlay = BrainModelSurfaceOverlay::OVERLAY_TOPOGRAPHY; if (brainSet->getTopographyFile()->empty()) { errorMessage.append("Topography File is overlay/underlay but no Topography File is loaded.\n"); } } else if (value == ouGeographyBlendingName) { overlay = BrainModelSurfaceOverlay::OVERLAY_GEOGRAPHY_BLENDING; PaintFile* pf = brainSet->getPaintFile(); if (pf->empty()) { errorMessage.append("Geography Blending is overlay/underlay but no Paint File is loaded.\n"); } else if (pf->getGeographyColumnNumber() < 0) { errorMessage.append("Geography Blending is overlay/underlay but no Geography Column in Paint File.\n"); } } // // Handle all surfaces or a specific surface // int startSurface = 0; int endSurface = brainSet->getNumberOfBrainModels(); if (surfaceName != SceneFile::SceneInfo::getDefaultSurfacesName()) { endSurface = 0; const BrainModelSurface* bms = brainSet->getBrainModelSurfaceWithCoordinateFileName(surfaceName); if (bms != NULL) { startSurface = brainSet->getBrainModelIndex(bms); if (startSurface >= 0) { endSurface = startSurface + 1; } } } // // Set the overlay or underlay // for (int k = startSurface; k < endSurface; k++) { if (infoName == underlayNameID) { brainSet->getSurfaceOverlay(underlayNumber)->setOverlay(k, overlay); } else if (infoName == secondaryOverlayNameID) { brainSet->getSurfaceOverlay(secondaryOverlayNumber)->setOverlay(k, overlay); } else if (infoName == primaryOverlayNameID) { brainSet->getSurfaceOverlay(primaryOverlayNumber)->setOverlay(k, overlay); } } } } } } } /** * create a scene (read display settings). */ void BrainModelSurfaceNodeColoring::saveScene(SceneFile::Scene& scene, const bool /*onlyIfSelected*/) { SceneFile::SceneClass sc("BrainModelSurfaceNodeColoring"); switch (coloringMode) { case COLORING_MODE_NORMAL: sc.addSceneInfo(SceneFile::SceneInfo("coloringMode", "NORMAL")); break; case COLORING_MODE_OVERLAY_BLENDING: sc.addSceneInfo(SceneFile::SceneInfo("coloringMode", "BLENDING")); break; } scene.addSceneClass(sc); } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceMultiresolutionMorphing.h0000664000175000017500000002214611572067322030253 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_BRAIN_SURFACE_MULTIRESOLUTION_MORPHING_H__ #define __VE_BRAIN_SURFACE_MULTIRESOLUTION_MORPHING_H__ #include #include #include "BrainSetNodeAttribute.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceMorphing.h" #include "MultiResMorphFile.h" #include "StatisticsUtilities.h" #include "SurfaceShapeFile.h" class BorderProjection; class BrainModelSurface; class CoordinateFile; class TopologyFile; /// class for measurements take while multiresolution morphing class MorphingMeasurements { public: /// constructor MorphingMeasurements(const QString& nameIn, const StatisticsUtilities::DescriptiveStatistics& arealDistortionStatisticsIn, const StatisticsUtilities::DescriptiveStatistics& linearDistortionStatisticsIn, const int numberOfNodeCrossoversIn, const int numberOfTileCrossoversIn, const float elapsedTimeIn); /// get the measurements void get(QString& nameOut, StatisticsUtilities::DescriptiveStatistics& arealDistortionStatisticsOut, StatisticsUtilities::DescriptiveStatistics& linearDistortionStatisticsOut, int& numberOfNodeCrossoversOut, int& numberOfTileCrossoversOut, float& elapsedTimeOut) const; private: /// name for this measurement QString name; /// areal distortion measurements StatisticsUtilities::DescriptiveStatistics arealDistortionStatistics; /// linear distortion measurements StatisticsUtilities::DescriptiveStatistics linearDistortionStatistics; /// number of node crossovers int numberOfNodeCrossovers; /// number of tile crossovers int numberOfTileCrossovers; /// time of cycle float elapsedTime; }; /// Class that performs multiresolution morphing on a brain surface class BrainModelSurfaceMultiresolutionMorphing : public BrainModelAlgorithm { public: /// Constructor BrainModelSurfaceMultiresolutionMorphing(BrainSet* brainSetIn, BrainModelSurface* referenceSurfaceIn, BrainModelSurface* morphingSurfaceIn, const BrainModelSurfaceMorphing::MORPHING_SURFACE_TYPE morphingSurfaceTypeIn, const BorderProjection* centralSulcusBorderProjectionIn = NULL); /// Destructor virtual ~BrainModelSurfaceMultiresolutionMorphing(); /// run the multiresolution morphing virtual void execute() throw (BrainModelAlgorithmException); /// copy the parameters to this morphing object void copyParameters(const BrainModelSurfaceMultiresolutionMorphing& bmsm); BrainModelSurfaceMorphing::MORPHING_SURFACE_TYPE getMorphingSurfaceType() const { return morphingSurfaceType; } /// get the surface measurements taken while morphing void getMorphingMeasurements(std::vector& mm) const { mm = measurements; } /// get automatically save all created files bool getAutoSaveAllFiles() const { return autoSaveFilesFlag; } /// set automatically save all created files void setAutoSaveAllFiles(const bool b) { autoSaveFilesFlag = b; } /// get multi-res morph file that contains parameters for editing MultiResMorphFile* getMultiResMorphParametersFile() { return &this->multiResMorphFile; } /// get multi-res morph file that contains parameters for reading const MultiResMorphFile* getMultiResMorphParametersFile() const { return &this->multiResMorphFile; } protected: enum { SURFACE_FIDUCIAL_INDEX = 0, SURFACE_MORPHED_INDEX = 1, SURFACE_NOT_MORPHED_INDEX = 2 }; /// void constructTemplateSpheres(std::vector& brains) throw (BrainModelAlgorithmException); /// create the equilateral grid topology file TopologyFile* createEquilateralGridTopology(BrainSet* brain, BrainModelSurface* surface); void createSphereDownsampleMapping(std::vector& brains) throw (BrainModelAlgorithmException); /// downsample an equilateral grid surface BrainSet* downsampleEquilateralGridSurface(BrainSet* brainIn); /// measure surface distortions void measureSurface(const int cycleNumber, const float elapsedTime); /// create downsampled surface(s) void multiresolutionDownsample(std::vector& brains); /// perform the multi-resolution morphing void multiresolutionMorph(std::vector& brains); /// upsample fro a lower resolution to a higher resolution brain (spherical surface) void sphericalUpsample(std::vector& brains, const int targetBrainIndex) throw (BrainModelAlgorithmException); /// write the multi-resolution surfaces void writeMultiresolutionSurfaces(std::vector& brains); /// upsample from a lower resolution to higher resolution brain (float surface) void flatUpsample(BrainSet* fromBrain, BrainSet* toBrain, BrainModelSurface* toSurface, const bool backsampleFlag); /// smooth to eliminate crossovers void smoothOutCrossovers(BrainModelSurface* bms, const float sphereRadius); /// setup file naming prefix and suffix void setUpOutputFileNaming(); /// the reference surface BrainModelSurface* referenceSurface; /// the morphing surface BrainModelSurface* morphingSurface; /// type of surface being morphed const BrainModelSurfaceMorphing::MORPHING_SURFACE_TYPE morphingSurfaceType; /// central sulcus border projection for alignment const BorderProjection* centralSulcusBorderProjection; /// surface shape file used for distortion measurements SurfaceShapeFile shapeMeasurementsFile; /// intermediate files std::vector intermediateFiles; /// prefix of intermediate files names QString intermediateFileNamePrefix[MultiResolutionMorphingCycle::MAXIMUM_NUMBER_OF_LEVELS]; /// prefix of intermediate coord files being morphed QString intermediateCoordFileNamePrefix[MultiResolutionMorphingCycle::MAXIMUM_NUMBER_OF_LEVELS]; /// name of intermediate spec files QString intermediateSpecFileNames[MultiResolutionMorphingCycle::MAXIMUM_NUMBER_OF_LEVELS]; /// name of original morphing surface coord file QString origCoordFileName; /// measurements take while morphing std::vector measurements; /// output filename's prefix QString outputFileNamePrefix; /// output filename's suffix QString outputFileNameSuffix; /// the hemisphere being morphed Structure::STRUCTURE_TYPE brainStruct; /// surface type for crossover checks BrainModelSurface::SURFACE_TYPES brainModelSurfaceType; /// cycle currently being iterated int currentCycle; /// crossover smoothing strength float crossoverSmoothStrength; /// crossover smoothing cycles int crossoverSmoothCycles; /// crossover smoothing iterations per cycle int crossoverSmoothIterations; /// crossover smoothing edges every X iterations int crossoverSmoothEdgeIterations; /// crossover smoothing project to sphere every X iterations int crossoverSmoothProjectToSphereIterations; /// crossover smoothing neighbor depth int crossoverSmoothNeighborDepth; /// auto save all created files bool autoSaveFilesFlag; /// multi-res morph file contains parameters MultiResMorphFile multiResMorphFile; }; #endif // __VE_BRAIN_SURFACE_MULTIRESOLUTION_MORPHING_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceMultiresolutionMorphing.cxx0000664000175000017500000024031011572067322030621 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #ifdef Q_OS_WIN32 // required for M_PI in #define _USE_MATH_DEFINES #define NOMINMAX #endif #include #include #include #include #include #include #include #include #include #include "BorderFile.h" #include "BorderProjectionFile.h" #include "BrainModelBorderSet.h" #include "BrainModelSurfaceDistortion.h" #include "BrainModelSurfaceFlatHexagonalSubsample.h" #include "BrainModelSurfaceMultiresolutionMorphing.h" #include "BrainModelSurfacePointProjector.h" #include "BrainSet.h" #include "DebugControl.h" #include "FileUtilities.h" #include "StatisticDataGroup.h" #include "StringUtilities.h" #include "TopologyHelper.h" #include "TransformationMatrixFile.h" #include "vtkMath.h" #include "vtkTriangle.h" /** * Constructor */ BrainModelSurfaceMultiresolutionMorphing::BrainModelSurfaceMultiresolutionMorphing( BrainSet* brainSetIn, BrainModelSurface* referenceSurfaceIn, BrainModelSurface* morphingSurfaceIn, const BrainModelSurfaceMorphing::MORPHING_SURFACE_TYPE morphingSurfaceTypeIn, const BorderProjection* centralSulcusBorderProjectionIn) : BrainModelAlgorithm(brainSetIn), referenceSurface(referenceSurfaceIn), morphingSurface(morphingSurfaceIn), morphingSurfaceType(morphingSurfaceTypeIn), centralSulcusBorderProjection(centralSulcusBorderProjectionIn) { autoSaveFilesFlag = true; currentCycle = std::numeric_limits::max(); brainModelSurfaceType = BrainModelSurface::SURFACE_TYPE_UNKNOWN; switch (morphingSurfaceType) { case BrainModelSurfaceMorphing::MORPHING_SURFACE_FLAT: brainModelSurfaceType = BrainModelSurface::SURFACE_TYPE_FLAT; this->multiResMorphFile.initializeParametersFlat(); crossoverSmoothStrength = 1.0; crossoverSmoothCycles = 10; crossoverSmoothIterations = 50; crossoverSmoothEdgeIterations = 10; crossoverSmoothProjectToSphereIterations = 0; crossoverSmoothNeighborDepth = 5; break; case BrainModelSurfaceMorphing::MORPHING_SURFACE_SPHERICAL: brainModelSurfaceType = BrainModelSurface::SURFACE_TYPE_SPHERICAL; this->multiResMorphFile.initializeParametersSpherical(); crossoverSmoothStrength = 1.0; crossoverSmoothCycles = 10; crossoverSmoothIterations = 10; crossoverSmoothEdgeIterations = 0; crossoverSmoothProjectToSphereIterations = 10; crossoverSmoothNeighborDepth = 30; break; } outputFileNamePrefix = ""; outputFileNameSuffix = ""; intermediateFiles.clear(); // // Get name of original coordinate file // if (morphingSurface != NULL) { const CoordinateFile* origCoord = morphingSurface->getCoordinateFile(); origCoordFileName = origCoord->getFileName(); } } /** * Destructor */ BrainModelSurfaceMultiresolutionMorphing::~BrainModelSurfaceMultiresolutionMorphing() { } /** * Copy parameters from another object */ void BrainModelSurfaceMultiresolutionMorphing::copyParameters( const BrainModelSurfaceMultiresolutionMorphing& bmsm) { this->multiResMorphFile = bmsm.multiResMorphFile; } /** * Setup the the output file name prefix and suffix */ void BrainModelSurfaceMultiresolutionMorphing::setUpOutputFileNaming() { outputFileNamePrefix = ""; outputFileNameSuffix = ""; // // Get the name of the input coordinate file // const CoordinateFile* cf = morphingSurface->getCoordinateFile(); QString morphFileName(cf->getFileName()); if (morphFileName.isEmpty()) { const TopologyFile* tf = morphingSurface->getTopologyFile(); morphFileName = tf->getFileName(); } if (morphFileName.isEmpty()) { morphFileName = brainSet->getSpecFileName(); } if (morphFileName.isEmpty()) { outputFileNamePrefix = "morphing_output"; outputFileNameSuffix = SpecFile::getCoordinateFileExtension(); } else { // // Parse the file name // QString directory, species, casename, anatomy, hemisphere, description, descriptionNoType; QString theDate, numNodes, extension; if (FileUtilities::parseCaretDataFileName(morphFileName, directory, species, casename, anatomy, hemisphere, description, descriptionNoType, theDate, numNodes, extension)) { if (species.isEmpty() == false) { outputFileNamePrefix.append(species); outputFileNamePrefix.append("."); } if (casename.isEmpty() == false) { outputFileNamePrefix.append(casename); outputFileNamePrefix.append("."); } if (anatomy.isEmpty() == false) { outputFileNamePrefix.append(anatomy); outputFileNamePrefix.append("."); } if (hemisphere.isEmpty() == false) { outputFileNamePrefix.append(hemisphere); outputFileNamePrefix.append("."); } if (descriptionNoType.isEmpty() == false) { outputFileNamePrefix.append(descriptionNoType); outputFileNamePrefix.append("."); } if (theDate.isEmpty() == false) { outputFileNameSuffix.append(theDate); outputFileNameSuffix.append("."); } if (numNodes.isEmpty() == false) { outputFileNameSuffix.append(numNodes); } // extension has period at beginning if (outputFileNameSuffix.isEmpty()) { // outputFileNameSuffix.append("."); //} outputFileNameSuffix.append(SpecFile::getCoordinateFileExtension()); } else { outputFileNamePrefix = FileUtilities::filenameWithoutExtension(morphFileName); if (StringUtilities::endsWith(outputFileNamePrefix, ".") == false) { outputFileNamePrefix.append("."); } outputFileNameSuffix = FileUtilities::filenameExtension(morphFileName); } } if (outputFileNameSuffix.startsWith('.') == false) { outputFileNameSuffix.insert(0, '.'); } } /** * run the multiresolution morphing */ void BrainModelSurfaceMultiresolutionMorphing::execute() throw (BrainModelAlgorithmException) { QString morphTypeString; switch (morphingSurfaceType) { case BrainModelSurfaceMorphing::MORPHING_SURFACE_FLAT: morphTypeString = "Flat "; break; case BrainModelSurfaceMorphing::MORPHING_SURFACE_SPHERICAL: morphTypeString = "Spherical "; break; } std::ostringstream str; str << "\n" << "Multiresolution Morphing " << morphTypeString.toAscii().constData() << ": " << " reference surface=" << FileUtilities::basename(referenceSurface->getFileName()).toAscii().constData() << "\n" << " morphing surface=" << FileUtilities::basename(morphingSurface->getFileName()).toAscii().constData() << "\n"; int numberOfCycles = this->multiResMorphFile.getNumberOfCycles(); for (int j = 0; j < numberOfCycles; j++) { MultiResolutionMorphingCycle* cycle = this->getMultiResMorphParametersFile()->getCycle(j); str << "cycle " << j << ":" << " iterations="; int iterationsPerLevel[MultiResolutionMorphingCycle::MAXIMUM_NUMBER_OF_LEVELS]; cycle->getIterationsAll(iterationsPerLevel); for (int i = 0; i < MultiResolutionMorphingCycle::MAXIMUM_NUMBER_OF_LEVELS; i++) { str << iterationsPerLevel[i] << " "; } str << "\n" << " linear force=" << cycle->getLinearForce() << " angular force=" << cycle->getAngularForce() << " step size=" << cycle->getStepSize() << "\n" << "smoothing strength=" << cycle->getSmoothingStrength() << " iterations=" << cycle->getSmoothingIterations() << " edge iterations=" << cycle->getSmoothingIterationEdges() << "\n"; } const QString fileComment(str.str().c_str()); // // Surfaces that will be scaled after the process is finished // std::vector surfacesToScale; // // Get modified status of existing brain models // std::vector brainModelModified; for (int i = 0; i < brainSet->getNumberOfBrainModels(); i++) { BrainModelSurface* bms = brainSet->getBrainModelSurface(i); if (bms != NULL) { CoordinateFile* cf = bms->getCoordinateFile(); brainModelModified.push_back(cf->getModified()); } else { brainModelModified.push_back(0); } } // // Check for stragglers // std::vector cornerTiles; morphingSurface->getTopologyFile()->findCornerTiles(2, cornerTiles); if (cornerTiles.empty() == false) { throw BrainModelAlgorithmException( "Straggler tile(s) were found (tiles that have two nodes that are\n" "only used by a single tile). These tiles will cause problems\n" "with Multi-resolution Morphing. Use the Surface:Topology:\n" "Remove Corner and Straggler Tiles menu item with \"Delete Stragglers\n" "Only\" to eliminate them. After doing so, save both the Topology \n" "and Coordinate files."); } int numberOfLevels = this->multiResMorphFile.getNumberOfLevels(); // // Create the progress dialog // QString title("Flat Multiresolution Morphing"); if (morphingSurfaceType == BrainModelSurfaceMorphing::MORPHING_SURFACE_SPHERICAL) { title = "Spherical Multiresolution Morphing"; } createProgressDialog(title, numberOfCycles + 1, "multiresMorphProgressDialog"); try { // // Setup filename prefix and suffix for output file naming // setUpOutputFileNaming(); // // Save the original topology file for spherical morphing since it might get modified // TopologyFile* originalTopologyFile = NULL; TopologyFile* newTopologyFile = NULL; switch (morphingSurfaceType) { case BrainModelSurfaceMorphing::MORPHING_SURFACE_FLAT: break; case BrainModelSurfaceMorphing::MORPHING_SURFACE_SPHERICAL: if (this->multiResMorphFile.isPointSphericalTrianglesOutward()) { originalTopologyFile = morphingSurface->getTopologyFile(); newTopologyFile = new TopologyFile(*originalTopologyFile); morphingSurface->setTopologyFile(newTopologyFile); } break; } // // Use the morphing surface's topology file // TopologyFile* topologyFile = morphingSurface->getTopologyFile(); // // Classify the nodes using the morphing surface's topology file // brainSet->clearNodeAttributes(); brainSet->classifyNodes(topologyFile); const int numTiles = topologyFile->getNumberOfTiles(); std::vector dummy1, dummy2, dummy3; const int numPiecesOfSurface = topologyFile->findIslands(dummy1, dummy2, dummy3); if (numPiecesOfSurface > 1) { throw BrainModelAlgorithmException( "There are multiple pieces of surface. Use Surface: Topology: Remove Islands\n" "to remove them and verify that the surface remains correct."); } // // Set the references surface area // const float referenceSurfaceArea = referenceSurface->getSurfaceArea(topologyFile); switch (morphingSurfaceType) { case BrainModelSurfaceMorphing::MORPHING_SURFACE_FLAT: break; case BrainModelSurfaceMorphing::MORPHING_SURFACE_SPHERICAL: // // Scale surface of sphere 02/26/2004 // morphingSurface->convertToSphereWithSurfaceArea(referenceSurfaceArea); break; } // // Get the radius of the spherical morphing surface // const float sphericalRadius = morphingSurface->getSphericalSurfaceRadius(); // // Measure the surface // measureSurface(-1, 0.0); // // Get the hemisphere being morphed // brainStruct = brainSet->getStructure().getType(); if (DebugControl::getDebugOn()) { try { BrainModelSurface tempr(*referenceSurface); tempr.getCoordinateFile()->writeFile("debug_morph_input_refererence.coord"); BrainModelSurface tempm(*morphingSurface); tempm.getCoordinateFile()->writeFile("debug_morph_input_morphing.coord"); TopologyFile tempt(*topologyFile); tempt.writeFile("debug_morph_input_topology.topo"); SpecFile sp; sp.addToSpecFile(SpecFile::getFiducialCoordFileTag(), tempr.getCoordinateFile()->getFileName(), "", false); switch (morphingSurfaceType) { case BrainModelSurfaceMorphing::MORPHING_SURFACE_FLAT: sp.addToSpecFile(SpecFile::getFlatCoordFileTag(), tempm.getCoordinateFile()->getFileName(), "", false); sp.addToSpecFile(SpecFile::getCutTopoFileTag(), tempt.getFileName(), "", false); break; case BrainModelSurfaceMorphing::MORPHING_SURFACE_SPHERICAL: sp.addToSpecFile(SpecFile::getSphericalCoordFileTag(), tempm.getCoordinateFile()->getFileName(), "", false); sp.addToSpecFile(SpecFile::getClosedTopoFileTag(), tempt.getFileName(), "", false); break; } sp.writeFile("debug_morph_input.spec"); } catch (FileException&) { } } // // Loop number of cycles // for (currentCycle = 0; currentCycle < numberOfCycles; currentCycle++) { const bool lastCycleFlag = (currentCycle == (numberOfCycles - 1)); // // Set progress dialog // { std::ostringstream str; QString typeString("Flat"); if (morphingSurfaceType == BrainModelSurfaceMorphing::MORPHING_SURFACE_SPHERICAL) { typeString = "Spherical"; } str << "Running " << typeString.toAscii().constData() << " Cycle " << (currentCycle + 1) << " of " << numberOfCycles; updateProgressDialog(str.str().c_str(), currentCycle + 1); } // // Start a timer // QTime timer; timer.start(); // // set the prefix for naming intermediate files and spec file naming // QString morphTypeString("none"); switch (morphingSurfaceType) { case BrainModelSurfaceMorphing::MORPHING_SURFACE_FLAT: morphTypeString = "flatmorph"; break; case BrainModelSurfaceMorphing::MORPHING_SURFACE_SPHERICAL: morphTypeString = "spheremorph"; break; } QString cycleNumberString = QString::number(currentCycle + 1); for (int i = 0; i < numberOfLevels; i++) { std::ostringstream ostr; ostr << morphTypeString.toAscii().constData() << ".cycle" << (currentCycle + 1) << ".level" << (i + 1); intermediateFileNamePrefix[i] = ostr.str().c_str(); intermediateCoordFileNamePrefix[i] = intermediateFileNamePrefix[i]; switch(morphingSurfaceType) { case BrainModelSurfaceMorphing::MORPHING_SURFACE_FLAT: intermediateCoordFileNamePrefix[i].append(".flat"); break; case BrainModelSurfaceMorphing::MORPHING_SURFACE_SPHERICAL: intermediateCoordFileNamePrefix[i].append(".sphere"); break; } intermediateSpecFileNames[i] = intermediateFileNamePrefix[i]; intermediateSpecFileNames[i].append(".spec"); intermediateFiles.push_back(intermediateSpecFileNames[i]); } std::vector brains; brains.push_back(brainSet); // one passed to this objects constructor switch (morphingSurfaceType) { case BrainModelSurfaceMorphing::MORPHING_SURFACE_FLAT: { // // Set resampling number of tiles // const int numberOfResamplingTiles = static_cast(numTiles * 0.3); // // Create a flat hexagonal subsampled surface // BrainModelSurfaceFlatHexagonalSubsample hexSubSample(brainSet, referenceSurface, morphingSurface, numberOfResamplingTiles); hexSubSample.execute(); BrainSet* subSampledBrainSet = hexSubSample.getSubsampledBrainSet(); if (subSampledBrainSet != NULL) { subSampledBrainSet->setSpecFileName("InitialFlatHex_Cycle" + cycleNumberString + ".spec"); BrainModelSurface* flatHexSurface = subSampledBrainSet->getBrainModelSurface(1); subSampledBrainSet->writeCoordinateFile("InitialFlatHex_Cycle" + cycleNumberString + ".coord", BrainModelSurface::SURFACE_TYPE_FLAT, flatHexSurface->getCoordinateFile(), true); subSampledBrainSet->writeTopologyFile("InitialFlatHex_Cycle" + cycleNumberString + ".topo", TopologyFile::TOPOLOGY_TYPE_CUT, flatHexSurface->getTopologyFile()); intermediateFiles.push_back(flatHexSurface->getCoordinateFile()->getFileName()); intermediateFiles.push_back(flatHexSurface->getTopologyFile()->getFileName()); BrainModelSurface* fiducialHexSurface = subSampledBrainSet->getBrainModelSurface(0); subSampledBrainSet->writeCoordinateFile("InitialFiducialHex_Cycle" + cycleNumberString + ".coord", BrainModelSurface::SURFACE_TYPE_FIDUCIAL, fiducialHexSurface->getCoordinateFile(), true); intermediateFiles.push_back(fiducialHexSurface->getCoordinateFile()->getFileName()); // // Create the non-morphed surface // BrainModelSurface* bms = subSampledBrainSet->getBrainModelSurface(1); subSampledBrainSet->setStructure(brainStruct); subSampledBrainSet->addBrainModel(new BrainModelSurface(*bms)); } if (subSampledBrainSet == NULL) { throw BrainModelAlgorithmException("Failed to create equilateral grid surface"); } brains.push_back(subSampledBrainSet); // // multiresolution downsample the surface // multiresolutionDownsample(brains); // // Write the multiresolution surfaces // writeMultiresolutionSurfaces(brains); // // Morph the surfaces // multiresolutionMorph(brains); // // smooth to eliminate crossovers // smoothOutCrossovers(morphingSurface, 0.0); // // Update surface normals // morphingSurface->computeNormals(); // // Translate to center of mass and scale to fit the window // morphingSurface->translateToCenterOfMass(); morphingSurface->updateForDefaultScaling(); } break; case BrainModelSurfaceMorphing::MORPHING_SURFACE_SPHERICAL: { // // Create the multiresolution spheres and mappings between them // constructTemplateSpheres(brains); createSphereDownsampleMapping(brains); // // Write the multiresolution surfaces // writeMultiresolutionSurfaces(brains); // // Morph the surfaces // multiresolutionMorph(brains); // // smooth to eliminate crossovers // smoothOutCrossovers(morphingSurface, sphericalRadius); // // Update surface normals // morphingSurface->computeNormals(); } break; } // switch(morphingSurfaceType) // // Free memory of multiresolution surfaces. Note that index 0 is // the brain passed to this objects constructor so do not delete it. // for (int i = 1; i < static_cast(brains.size()); i++) { delete brains[i]; } // // if flat surface // if (morphingSurfaceType == BrainModelSurfaceMorphing::MORPHING_SURFACE_FLAT) { // // Save the coordinates // morphingSurface->pushCoordinates(); // // scale to match reference surface area // morphingSurface->scaleSurfaceToArea(referenceSurfaceArea, true); // // Add to surfaces that should be scaled // surfacesToScale.push_back(morphingSurface); } // // If spherical surface // if (morphingSurfaceType == BrainModelSurfaceMorphing::MORPHING_SURFACE_SPHERICAL) { morphingSurface->convertToSphereWithRadius(sphericalRadius); } // // Measure the surface // measureSurface(currentCycle, (timer.elapsed() * 0.001)); if (currentCycle == 0) { CoordinateFile* cf = morphingSurface->getCoordinateFile(); cf->appendToFileComment(fileComment); cf->appendSoftwareVersionToFileComment("Multiresolution Morphing with"); } // // Write the morphed coordinate file (but do not add to spec file just yet) // QString cycleType("FLAT_CYCLE"); if (morphingSurfaceType == BrainModelSurfaceMorphing::MORPHING_SURFACE_SPHERICAL) { cycleType = "SPHERE_CYCLE"; } std::ostringstream str; str << outputFileNamePrefix.toAscii().constData() << cycleType.toAscii().constData() << (currentCycle + 1) //<< "." << outputFileNameSuffix.toAscii().constData() << std::ends; if (autoSaveFilesFlag) { try { CoordinateFile* cf = morphingSurface->getCoordinateFile(); brainSet->writeCoordinateFile(str.str().c_str(), morphingSurface->getSurfaceType(), cf, true); } catch (FileException& e) { throw BrainModelAlgorithmException(e.whatQString()); } } else { CoordinateFile* cf = morphingSurface->getCoordinateFile(); cf->setFileName(str.str().c_str()); } // if flat surface // if (morphingSurfaceType == BrainModelSurfaceMorphing::MORPHING_SURFACE_FLAT) { // // Restore the coordinates // morphingSurface->popCoordinates(); } // // If doing flat registration and smoothing of flat surface overlap // enabled and doing the last cycle // if ((morphingSurfaceType == BrainModelSurfaceMorphing::MORPHING_SURFACE_FLAT) && this->multiResMorphFile.isSmoothOutFlatSurfaceOverlap() && lastCycleFlag) { // // Copy the morphing surface // BrainModelSurface* smoothingSurface = new BrainModelSurface(*morphingSurface); // // If there was smoothing of overlapped areas // if (smoothingSurface->smoothOutFlatSurfaceOverlap()) { // // Save the coordinates // smoothingSurface->pushCoordinates(); // // scale to match reference surface area // smoothingSurface->scaleSurfaceToArea(referenceSurfaceArea, true); // // Add to surfaces that should be scaled // surfacesToScale.push_back(smoothingSurface); // // Write the smoothed out overlap surface // morphingSurface = smoothingSurface; brainSet->addBrainModel(morphingSurface); CoordinateFile* cf = morphingSurface->getCoordinateFile(); std::ostringstream str; str << outputFileNamePrefix.toAscii().constData() << "FLAT_CYCLE" << (currentCycle + 1) << "_OVERLAP_SMOOTH" //<< "." << outputFileNameSuffix.toAscii().constData() << std::ends; if (autoSaveFilesFlag) { try { brainSet->writeCoordinateFile(str.str().c_str(), morphingSurface->getSurfaceType(), cf, false); } catch (FileException& e) { throw BrainModelAlgorithmException(e.whatQString()); } } else { cf->setFileName(str.str().c_str()); } // // Measure the overlap smoothed surface // measureSurface(1000, (timer.elapsed() * 0.001)); // // if flat surface // if (morphingSurfaceType == BrainModelSurfaceMorphing::MORPHING_SURFACE_FLAT) { // // Restore the coordinates // smoothingSurface->popCoordinates(); } } else { delete smoothingSurface; } } // // if this is the last cycle // if (lastCycleFlag) { // // Add the coordinate file to the spec file // if (autoSaveFilesFlag) { brainSet->addToSpecFile( BrainModelSurface::getCoordSpecFileTagFromSurfaceType(morphingSurface->getSurfaceType()), morphingSurface->getFileName()); } // // If surface should be aligned // if (centralSulcusBorderProjection != NULL) { if (centralSulcusBorderProjection->getNumberOfLinks() > 1) { const bool flatFlag = (morphingSurfaceType == BrainModelSurfaceMorphing::MORPHING_SURFACE_FLAT); BrainModelSurface* alignmentSurface = new BrainModelSurface(*morphingSurface); alignmentSurface->alignToStandardOrientation(referenceSurface, centralSulcusBorderProjection, false, false); brainSet->addBrainModel(alignmentSurface); if (flatFlag) { alignmentSurface->scaleSurfaceToArea(referenceSurfaceArea, true); } const QString alignmentComment = "\nAligned to Standard Orientation using " + centralSulcusBorderProjection->getName() + " from " + brainSet->getBorderSet()->getBorderProjectionFileInfo()->getFileName() + ".\n"; CoordinateFile* cf = alignmentSurface->getCoordinateFile(); cf->appendToFileComment(alignmentComment); const QString name( outputFileNamePrefix + (flatFlag ? "FLAT_ALIGNED" : "SPHERE_ALIGNED") + outputFileNameSuffix); if (autoSaveFilesFlag) { try { brainSet->writeCoordinateFile(name, alignmentSurface->getSurfaceType(), cf, true); } catch (FileException& e) { throw BrainModelAlgorithmException(e.whatQString()); } } else { cf->setFileName(name); } morphingSurface = alignmentSurface; // // Measure the overlap smoothed surface // measureSurface(2000, (timer.elapsed() * 0.001)); } } } // // Update the displayed brain model // brainSet->drawBrainModel(morphingSurface); } // // If original topology file was saved, restore it to the surfaces. // This is used in spherical morphing since the topology may be modified // if ((originalTopologyFile != NULL) && (newTopologyFile != NULL)) { // // Restore the topology file // const int numBrainModels = brainSet->getNumberOfBrainModels(); for (int i = 0; i < numBrainModels; i++) { BrainModelSurface* bms = brainSet->getBrainModelSurface(i); if (bms != NULL) { if (bms->getTopologyFile() == newTopologyFile) { bms->setTopologyFile(originalTopologyFile); } } } delete newTopologyFile; } // // Delete intermediate files is user wants them deleted // if (this->multiResMorphFile.isDeleteTemporaryFiles()) { for (int i = 0; i < static_cast(intermediateFiles.size()); i++) { QFile::remove(intermediateFiles[i]); } } // // Retain modified status of existing brain models // for (int i = 0; i < brainSet->getNumberOfBrainModels(); i++) { BrainModelSurface* bms = brainSet->getBrainModelSurface(i); if (bms != NULL) { if (morphingSurfaceType == BrainModelSurfaceMorphing::MORPHING_SURFACE_FLAT) { if (std::find(surfacesToScale.begin(), surfacesToScale.end(), bms) != surfacesToScale.end()) { bms->scaleSurfaceToArea(referenceSurfaceArea, true); if (autoSaveFilesFlag) { CoordinateFile* cf = bms->getCoordinateFile(); brainSet->writeCoordinateFile(cf->getFileName(), bms->getSurfaceType(), cf); } } } CoordinateFile* cf = bms->getCoordinateFile(); if (i < static_cast(brainModelModified.size())) { cf->setModifiedCounter(brainModelModified[i]); } //else { // cf->clearModified(); //} } } } catch (BrainModelAlgorithmException& e) { removeProgressDialog(); throw e; } removeProgressDialog(); } /** * Make measurements of surface */ void BrainModelSurfaceMultiresolutionMorphing::measureSurface(const int cycleNumber, const float elapsedTime) { // // Set the names of the distortion measurements // QString arealDistortName("Areal Distortion "); QString linearDistortName("Linear Distortion "); QString cycleName; if (cycleNumber == -1) { arealDistortName.append("Before Morphing"); linearDistortName.append("Before Morphing"); cycleName = "Before Morphing"; } else { std::ostringstream str; if (cycleNumber == 2000) { str << "Aligned"; } else if (cycleNumber == 1000) { str << "Overlap Smoothed"; } else { str << " Cycle " << (cycleNumber + 1); } arealDistortName.append(str.str().c_str()); linearDistortName.append(str.str().c_str()); cycleName = str.str().c_str(); } // // Make the distortion measurements // BrainModelSurfaceDistortion bmsd(brainSet, morphingSurface, referenceSurface, morphingSurface->getTopologyFile(), &shapeMeasurementsFile, BrainModelSurfaceDistortion::DISTORTION_COLUMN_CREATE_NEW, BrainModelSurfaceDistortion::DISTORTION_COLUMN_CREATE_NEW, arealDistortName, linearDistortName); bmsd.execute(); // // Save the distortion measurements file. // QString filename; switch(morphingSurfaceType) { case BrainModelSurfaceMorphing::MORPHING_SURFACE_FLAT: filename = "flat_morph_distortion"; break; case BrainModelSurfaceMorphing::MORPHING_SURFACE_SPHERICAL: filename = "spherical_morph_distortion"; break; } if (filename.isEmpty() == false) { filename.append(SpecFile::getSurfaceShapeFileExtension()); try { shapeMeasurementsFile.writeFile(filename); } catch (FileException& e) { throw BrainModelAlgorithmException(e.whatQString()); } if (cycleNumber < 0) { //brainSet->addToSpecFile(SpecFile::surfaceShapeFileTag, filename); } } // // Get columns in surface shape file // const int arealDistortColumn = shapeMeasurementsFile.getColumnWithName(arealDistortName); const int linearDistortColumn = shapeMeasurementsFile.getColumnWithName(linearDistortName); if (arealDistortColumn < 0) { std::cout << "PROGRAM ERROR: invalid areal distortion column at " << __LINE__ << " in " << __FILE__ << std::endl; return; } if (linearDistortColumn < 0) { std::cout << "PROGRAM ERROR: invalid linear distortion column at " << __LINE__ << " in " << __FILE__ << std::endl; return; } const int numNodes = morphingSurface->getNumberOfNodes(); std::vector linearDistortion(numNodes); std::vector arealDistortion(numNodes); for (int i = 0; i < numNodes; i++) { arealDistortion[i] = shapeMeasurementsFile.getValue(i, arealDistortColumn); linearDistortion[i] = shapeMeasurementsFile.getValue(i, linearDistortColumn); } // // Statistics for areal distortion // StatisticsUtilities::DescriptiveStatistics arealDistortionStats; StatisticsUtilities::computeStatistics(arealDistortion, true, arealDistortionStats); /* StatisticDataGroup arealGroup(&arealDistortion, StatisticDataGroup::DATA_STORAGE_MODE_POINT); StatisticsUtilities arealDS(StatisticDescriptiveStatistics::DATA_TYPE_SAMPLE); arealDS.addDataGroup(&arealGroup); try { arealDS.execute(); } catch (StatisticException&) { } const StatisticDescriptiveStatistics::DescriptiveStatistics arealDistortionStats = arealDS.getDescriptiveStatistics(); */ // // Statistics for linear distortion // StatisticsUtilities::DescriptiveStatistics linearDistortionStats; StatisticsUtilities::computeStatistics(linearDistortion, true, linearDistortionStats); /* StatisticDataGroup linearGroup(&linearDistortion, StatisticDataGroup::DATA_STORAGE_MODE_POINT); StatisticDescriptiveStatistics linearDS(StatisticDescriptiveStatistics::DATA_TYPE_SAMPLE); linearDS.addDataGroup(&linearGroup); try { linearDS.execute(); } catch (StatisticException&) { } const StatisticDescriptiveStatistics::DescriptiveStatistics linearDistortionStats = linearDS.getDescriptiveStatistics(); */ int numTileCrossovers, numNodeCrossovers; morphingSurface->crossoverCheck(numTileCrossovers, numNodeCrossovers, brainModelSurfaceType); MorphingMeasurements mm(cycleName, arealDistortionStats, linearDistortionStats, numNodeCrossovers, numTileCrossovers, elapsedTime); measurements.push_back(mm); } /** * Smooth to eliminate crossovers. */ void BrainModelSurfaceMultiresolutionMorphing::smoothOutCrossovers(BrainModelSurface* bms, const float sphereRadius) { if (DebugControl::getDebugOn()) { try { BrainModelSurface temp(*bms); temp.getCoordinateFile()->writeFile("debug_morph_before_any_smoothing.coord"); } catch (FileException&) { } } int numNodeCrossovers = 10; MultiResolutionMorphingCycle* cycle = this->multiResMorphFile.getCycle(currentCycle); int smoothingIterations = cycle->getSmoothingIterations(); float smoothingStrength = cycle->getSmoothingStrength(); int smoothingEdgesIterations = cycle->getSmoothingIterationEdges(); int iterCount = 0; while ((numNodeCrossovers > 2) && (iterCount < smoothingIterations)) { int numIters = 10; if ((smoothingIterations - iterCount) < numIters) { numIters = (smoothingIterations - iterCount); } if (numIters > 0) { bms->arealSmoothing(smoothingStrength, numIters, smoothingEdgesIterations); iterCount += numIters; } else { break; } // // Push nodes on spherical surface back to the sphere // if (morphingSurfaceType == BrainModelSurfaceMorphing::MORPHING_SURFACE_SPHERICAL) { bms->convertToSphereWithRadius(sphereRadius); // // If normals should be pointed outward // if (this->multiResMorphFile.isPointSphericalTrianglesOutward()) { bms->orientTilesOutward(BrainModelSurface::SURFACE_TYPE_SPHERICAL); } } int numTileCrossovers; bms->crossoverCheck(numTileCrossovers, numNodeCrossovers, brainModelSurfaceType); } if (DebugControl::getDebugOn()) { try { BrainModelSurface temp2(*bms); temp2.getCoordinateFile()->writeFile("debug_morph_after_general_smoothing.coord"); } catch (FileException&) { } } if (this->multiResMorphFile.isSmoothOutCrossovers()) { // // Set project back to sphere if sphere // int projToSphereEveryIter = -1; switch (morphingSurfaceType) { case BrainModelSurfaceMorphing::MORPHING_SURFACE_FLAT: projToSphereEveryIter = -1; break; case BrainModelSurfaceMorphing::MORPHING_SURFACE_SPHERICAL: projToSphereEveryIter = 5; break; } // // Smooth out crossovers // // bms->smoothOutSurfaceCrossovers(1.0, 10, 50, 10, projToSphereEveryIter, 3); bms->smoothOutSurfaceCrossovers(crossoverSmoothStrength, crossoverSmoothCycles, crossoverSmoothIterations, crossoverSmoothEdgeIterations, crossoverSmoothProjectToSphereIterations, crossoverSmoothNeighborDepth, brainModelSurfaceType); // // Project back to sphere // switch (morphingSurfaceType) { case BrainModelSurfaceMorphing::MORPHING_SURFACE_FLAT: break; case BrainModelSurfaceMorphing::MORPHING_SURFACE_SPHERICAL: bms->convertToSphereWithRadius(sphereRadius); break; } int numTileCrossovers; bms->crossoverCheck(numTileCrossovers, numNodeCrossovers, brainModelSurfaceType); } if (DebugControl::getDebugOn()) { try { BrainModelSurface temp3(*bms); temp3.getCoordinateFile()->writeFile("debug_morph_crossover_smoothing.coord"); } catch (FileException&) { } } if (DebugControl::getDebugOn()) { if (numNodeCrossovers > 0) { std::cout << "At end of smoothing there are " << numNodeCrossovers << " node crossovers." << std::endl; } } } /** * Write multiresolution surfaces. Note that spec file is written automatically any * time a data file is saved. */ void BrainModelSurfaceMultiresolutionMorphing::writeMultiresolutionSurfaces(std::vector& brains) { // // surface with index 0 is surface being morphed and do not need to write it // const int numBrainSets = static_cast(brains.size()); for (int i = (numBrainSets - 1); i > 0; i--) { BrainSet* bs = brains[i]; bs->setSpecFileName(intermediateSpecFileNames[i]); try { // // Write the topology file // QString topoName(intermediateFileNamePrefix[i]); topoName.append(SpecFile::getTopoFileExtension()); TopologyFile* tf = bs->getTopologyFile(0); try { bs->writeTopologyFile(topoName, tf->getTopologyType(), tf); } catch (FileException& e) { throw BrainModelAlgorithmException(e.whatQString()); } intermediateFiles.push_back(topoName); // // Write the fidicual coordinate file // QString fiducialName(intermediateFileNamePrefix[i]); fiducialName.append(".fiducial"); fiducialName.append(SpecFile::getCoordinateFileExtension()); BrainModelSurface* bms = bs->getBrainModelSurface(SURFACE_FIDUCIAL_INDEX); CoordinateFile* cf = bms->getCoordinateFile(); try { bs->writeCoordinateFile(fiducialName, bms->getSurfaceType(), cf); } catch (FileException& e) { throw BrainModelAlgorithmException(e.whatQString()); } intermediateFiles.push_back(fiducialName); // // Write the flat/spherical coordinate file // QString flatName(intermediateCoordFileNamePrefix[i]); flatName.append(SpecFile::getCoordinateFileExtension()); bms = bs->getBrainModelSurface(SURFACE_MORPHED_INDEX); cf = bms->getCoordinateFile(); try { bs->writeCoordinateFile(flatName, bms->getSurfaceType(), cf); } catch (FileException& e) { throw BrainModelAlgorithmException(e.whatQString()); } intermediateFiles.push_back(flatName); // // Convert the surface to a border file to facilitate overlaying surface // on the original high resolution surface // { QString borderFileName(intermediateCoordFileNamePrefix[i]); borderFileName.append(SpecFile::getBorderFileExtension()); BorderFile bf(bms->getTopologyFile(), bms->getCoordinateFile()); switch(morphingSurfaceType) { case BrainModelSurfaceMorphing::MORPHING_SURFACE_FLAT: bf.setHeaderTag(AbstractFile::headerTagConfigurationID, SpecFile::getFlatBorderFileTagName()); bs->addToSpecFile(SpecFile::getFlatBorderFileTag(), borderFileName); break; case BrainModelSurfaceMorphing::MORPHING_SURFACE_SPHERICAL: bf.setHeaderTag(AbstractFile::headerTagConfigurationID, SpecFile::getSphericalBorderFileTagName()); bs->addToSpecFile(SpecFile::getSphericalBorderFileTag(), borderFileName); break; } bf.writeFile(borderFileName); intermediateFiles.push_back(borderFileName); } } catch (FileException& e) { std::cerr << "File Write Error: " << e.whatQString().toAscii().constData() << std::endl; } } } /** * Create downsampled multiresolution surface(s). */ void BrainModelSurfaceMultiresolutionMorphing::multiresolutionDownsample( std::vector& brains) { int numNodes = 1000; // // create subsampled surfaces until number of nodes is less than or equal to 100 // while (numNodes > 100) { const int brainIndex = brains.size() - 1; const int prevNumNodes = brains[brainIndex]->getNumberOfNodes(); BrainSet* bs = downsampleEquilateralGridSurface(brains[brainIndex]); if (bs != NULL) { brains.push_back(bs); numNodes = bs->getNumberOfNodes(); if (DebugControl::getDebugOn()) { std::cout << "Downsampled surface " << brainIndex << " to " << (brainIndex + 1) << " nodes reduced from " << prevNumNodes << " to " << numNodes << std::endl; } } else { throw BrainModelAlgorithmException("Failed to downsample surface"); } // // limit to maximum number of levels // if (brains.size() == MultiResolutionMorphingCycle::MAXIMUM_NUMBER_OF_LEVELS) { break; } } } /** * Downsample an equilateral grid surface by selecting every other node in each row and column. */ BrainSet* BrainModelSurfaceMultiresolutionMorphing::downsampleEquilateralGridSurface(BrainSet* brainIn) { // // Surfaces and coordinate files of input brain // BrainModelSurface* fiducialSurfaceIn = brainIn->getBrainModelSurface(SURFACE_FIDUCIAL_INDEX); CoordinateFile* fiducialCoordIn = fiducialSurfaceIn->getCoordinateFile(); BrainModelSurface* flatSurfaceIn = brainIn->getBrainModelSurface(SURFACE_MORPHED_INDEX); CoordinateFile* flatCoordIn = flatSurfaceIn->getCoordinateFile(); // // Output brain set // BrainSet* brainOut = new BrainSet; brainOut->setStructure(brainStruct); // // Output brain surfaces (fiducial, flat, and a flat that does not get modified) // BrainModelSurface* fiducialSurfaceOut = new BrainModelSurface(brainOut); fiducialSurfaceOut->setSurfaceType(BrainModelSurface::SURFACE_TYPE_FIDUCIAL); fiducialSurfaceOut->setStructure(brainStruct); BrainModelSurface* flatSurfaceOut = new BrainModelSurface(brainOut); flatSurfaceOut->setSurfaceType(BrainModelSurface::SURFACE_TYPE_FLAT); fiducialSurfaceOut->setStructure(brainStruct); BrainModelSurface* flatNotMorphSurfaceOut = new BrainModelSurface(brainOut); flatNotMorphSurfaceOut->setSurfaceType(BrainModelSurface::SURFACE_TYPE_FLAT); flatNotMorphSurfaceOut->setStructure(brainStruct); // // Add brain surfaces to brain // brainOut->addBrainModel(fiducialSurfaceOut); brainOut->addBrainModel(flatSurfaceOut); brainOut->addBrainModel(flatNotMorphSurfaceOut); // // Loop through node of input flat surface for subsampling // const int numNodes = flatSurfaceIn->getNumberOfNodes(); for (int nm = 0; nm < numNodes; nm++) { const BrainSetNodeAttribute* bna = brainIn->getNodeAttributes(nm); int row, column, node; bna->getFlatMorphAttributes(row, column, node); // // Use node in every other row and column // if ( ((row % 2) == 0) && ((column %2) == 0) ) { flatSurfaceOut->addNode(flatCoordIn->getCoordinate(nm)); flatNotMorphSurfaceOut->addNode(flatCoordIn->getCoordinate(nm)); fiducialSurfaceOut->addNode(fiducialCoordIn->getCoordinate(nm)); brainOut->resetNodeAttributes(); BrainSetNodeAttribute* bna = brainOut->getNodeAttributes(flatSurfaceOut->getNumberOfNodes() - 1); bna->setFlatMorphAttributes((row/2), (column/2), nm); } } // // Unable to subsample ? // if (flatSurfaceOut->getNumberOfNodes() <= 0) { delete fiducialSurfaceOut; delete flatSurfaceOut; delete flatNotMorphSurfaceOut; return NULL; } // // Create the topology // TopologyFile* topology = createEquilateralGridTopology(brainOut, flatSurfaceOut); if (topology != NULL) { fiducialSurfaceOut->setTopologyFile(topology); flatSurfaceOut->setTopologyFile(topology); flatNotMorphSurfaceOut->setTopologyFile(topology); brainOut->addTopologyFile(topology); } return brainOut; } /** * Create the topology for an equilateral grid. */ TopologyFile* BrainModelSurfaceMultiresolutionMorphing::createEquilateralGridTopology(BrainSet* brain, BrainModelSurface* surface) { const int numNodes = surface->getNumberOfNodes(); TopologyFile *topology = new TopologyFile(); topology->setTopologyType(TopologyFile::TOPOLOGY_TYPE_CUT); for (int i = 0; i < numNodes; i++) { BrainSetNodeAttribute* bna = brain->getNodeAttributes(i); int row, col, node; bna->getFlatMorphAttributes(row, col, node); const int n1 = brain->getNodeWithMorphRowColumn(row, col + 1, i); const int n2 = brain->getNodeWithMorphRowColumn(row + 1, col, i); const int n3 = brain->getNodeWithMorphRowColumn(row + 1, col - 1, i); if ((n1 >= 0) && (n2 >= 0)) { topology->addTile(i, n1, n2); } if ((n2 >= 0) && (n3 >= 0)) { topology->addTile(i, n2, n3); } } if (topology->getNumberOfTiles() <= 0) { delete topology; throw BrainModelAlgorithmException("Failed to create topology"); } return topology; } /** * Peform the multi-resolution morphing */ void BrainModelSurfaceMultiresolutionMorphing::multiresolutionMorph(std::vector& brains) { const int numBrains = static_cast(brains.size()); // // Limit to available levels // int startNum = numBrains - 1; if (startNum >= MultiResolutionMorphingCycle::MAXIMUM_NUMBER_OF_LEVELS) { startNum = MultiResolutionMorphingCycle::MAXIMUM_NUMBER_OF_LEVELS - 1; } // // Start with the lowest resolution surface // for (int bi = startNum; bi > 0; bi--) { // // Get the flat and fiducial surfaces // BrainSet* bs = brains[bi]; BrainModelSurface* fiducialSurface = bs->getBrainModelSurface(SURFACE_FIDUCIAL_INDEX); BrainModelSurface* flatSurface = bs->getBrainModelSurface(SURFACE_MORPHED_INDEX); // // Update normals on the flat and fiducial surfaces // fiducialSurface->computeNormals(); flatSurface->computeNormals(); MultiResolutionMorphingCycle* morphCycle = this->multiResMorphFile.getCycle(currentCycle); int iterationsPerLevel[MultiResolutionMorphingCycle::MAXIMUM_NUMBER_OF_LEVELS]; morphCycle->getIterationsAll(iterationsPerLevel); if (DebugControl::getDebugOn()) { std::cout << std::endl << "*** Morphing Level surface " << bi << ": nodes " << bs->getNumberOfNodes() << ", iterations " << iterationsPerLevel[bi] << std::endl; } // // Morph the surface for the specified iterations // BrainModelSurfaceMorphing bsm(bs, fiducialSurface, flatSurface, morphingSurfaceType); MultiResolutionMorphingCycle* cycle = this->multiResMorphFile.getCycle(this->currentCycle); bsm.setMorphingParameters(iterationsPerLevel[bi], cycle->getLinearForce(), cycle->getAngularForce(), cycle->getStepSize()); bsm.execute(); // // Write the morphed file // std::ostringstream str; str << intermediateCoordFileNamePrefix[bi].toAscii().constData() << ".Morph" << iterationsPerLevel[bi]; intermediateCoordFileNamePrefix[bi] = str.str().c_str(); QString coordName(intermediateCoordFileNamePrefix[bi]); coordName.append(SpecFile::getCoordinateFileExtension()); try { bs->writeCoordinateFile(coordName, flatSurface->getSurfaceType(), flatSurface->getCoordinateFile()); } catch (FileException& e) { throw BrainModelAlgorithmException(e.whatQString()); } intermediateFiles.push_back(coordName); // // Convert the morphed surface to a border file for help in debugging // { QString borderFileName(coordName); borderFileName.append(SpecFile::getBorderFileExtension()); BorderFile bf(flatSurface->getTopologyFile(), flatSurface->getCoordinateFile()); if (morphingSurfaceType == BrainModelSurfaceMorphing::MORPHING_SURFACE_FLAT) { bf.setHeaderTag(AbstractFile::headerTagConfigurationID, SpecFile::getFlatBorderFileTagName()); } else { bf.setHeaderTag(AbstractFile::headerTagConfigurationID, SpecFile::getSphericalBorderFileTagName()); } bf.writeFile(borderFileName); intermediateFiles.push_back(borderFileName); } if (morphingSurfaceType == BrainModelSurfaceMorphing::MORPHING_SURFACE_SPHERICAL) { // // If upsampling to original surface, we want sphericalUpsample to update // a copy of the morphing surface since morphingSurface is initially the // input surface that should no longer be modified. // if (bi == 1) { // // Make a copy of the input surface (do not want to modify it) // BrainModelSurface* bms = new BrainModelSurface(*morphingSurface); brains[0]->addBrainModel(bms); morphingSurface = bms; } else { // // smooth crossovers // const int numNodes = bs->getNumberOfNodes(); int iters = 0; int depth = 0; if (numNodes < 100) { iters = 1; depth = 1; } else if (numNodes < 1000) { iters = 3; depth = 2; } else if (numNodes < 2000) { iters = 5; depth = 2; } else if (numNodes < 5000) { iters = 10; depth = 3; } else { iters = 20; depth = 3; } if (iters > 0) { // flatSurface->smoothOutSurfaceCrossovers(1.0, 1, iters, 0, iters, depth); } } // // upsample to next sphere // sphericalUpsample(brains, bi - 1); // // Write the upsampled coordinate file // std::ostringstream str; str << intermediateCoordFileNamePrefix[bi-1].toAscii().constData() << ".Morph.Up"; intermediateCoordFileNamePrefix[bi-1] = str.str().c_str(); QString coordName(intermediateCoordFileNamePrefix[bi-1]); coordName.append(SpecFile::getCoordinateFileExtension()); BrainModelSurface* surf = brains[bi-1]->getBrainModelSurface(SURFACE_MORPHED_INDEX); if (bi != 1) { try { brains[bi-1]->writeCoordinateFile(coordName, surf->getSurfaceType(), surf->getCoordinateFile()); // // Convert the morphed surface to a border file for help in debugging // { QString borderFileName(coordName); borderFileName.append(SpecFile::getBorderFileExtension()); BorderFile bf(flatSurface->getTopologyFile(), flatSurface->getCoordinateFile()); if (morphingSurfaceType == BrainModelSurfaceMorphing::MORPHING_SURFACE_FLAT) { bf.setHeaderTag(AbstractFile::headerTagConfigurationID, SpecFile::getFlatBorderFileTagName()); } else { bf.setHeaderTag(AbstractFile::headerTagConfigurationID, SpecFile::getSphericalBorderFileTagName()); } bf.writeFile(borderFileName); intermediateFiles.push_back(borderFileName); } } catch (FileException& e) { throw BrainModelAlgorithmException(e.whatQString()); } } intermediateFiles.push_back(coordName); // // morph final surface // if (bi == 1) { // // Morph the surface for the specified iterations // BrainModelSurfaceMorphing bsm(brains[0] /*bs*/, referenceSurface, morphingSurface, morphingSurfaceType); bsm.setMorphingParameters(iterationsPerLevel[0], cycle->getLinearForce(), cycle->getAngularForce(), cycle->getStepSize()); bsm.execute(); } } else { // flat morphing if (bi > 1) { // // Upsample one resolution to another // flatUpsample(brains[bi], brains[bi - 1], brains[bi - 1]->getBrainModelSurface(SURFACE_MORPHED_INDEX), false); intermediateCoordFileNamePrefix[bi - 1].append(".U"); QString coordName(intermediateCoordFileNamePrefix[bi - 1]); coordName.append(SpecFile::getCoordinateFileExtension()); BrainModelSurface* bms = brains[bi - 1]->getBrainModelSurface(SURFACE_MORPHED_INDEX); try { brains[bi - 1]->writeCoordinateFile(coordName, bms->getSurfaceType(), bms->getCoordinateFile()); } catch (FileException& e) { throw BrainModelAlgorithmException(e.whatQString()); } intermediateFiles.push_back(coordName); } else if (bi == 1) { // // Make a copy of the input surface (do not want to modify it) // BrainModelSurface* bms = new BrainModelSurface(*morphingSurface); brains[0]->addBrainModel(bms); morphingSurface = bms; // // Backsample into original surface // flatUpsample(brains[bi], brains[0], morphingSurface, true); // // Morph the surface for the specified iterations // BrainModelSurfaceMorphing bsm(brains[0] /*bs*/, referenceSurface, morphingSurface, morphingSurfaceType); bsm.setMorphingParameters(iterationsPerLevel[0], cycle->getLinearForce(), cycle->getAngularForce(), cycle->getStepSize()); bsm.execute(); } } } // for (int bi = ... } /** * Upsample from one flat brain surface to another */ void BrainModelSurfaceMultiresolutionMorphing::flatUpsample(BrainSet* fromBrain, BrainSet* toBrain, BrainModelSurface* toSurface, const bool backsampleFlag) { // // "from" brain's surface and coordinate files // const BrainModelSurface* fromSurface = fromBrain->getBrainModelSurface(SURFACE_MORPHED_INDEX); const CoordinateFile* fromCoords = fromSurface->getCoordinateFile(); const BrainModelSurface* fromNotMorphedSurface = fromBrain->getBrainModelSurface(SURFACE_NOT_MORPHED_INDEX); const int numFromNodes = fromNotMorphedSurface->getNumberOfNodes(); // // Topology for "from" surface // const TopologyHelper* fromTopology = fromNotMorphedSurface->getTopologyFile()->getTopologyHelper(false, true, false); // // "to" brain's coordinate file // CoordinateFile* toCoords = toSurface->getCoordinateFile(); const int numToNodes = toSurface->getNumberOfNodes(); // // Mark all of "to" surface's nodes as unvisited // toBrain->setAllNodesVisited(false); if (backsampleFlag == false) { // // In the "fromSurface" the morphNode contains the node number in the "toSurface" from // which this node was downsampled // for (int i = 0; i < numFromNodes; i++) { if (fromTopology->getNodeHasNeighbors(i)) { // // Transfer the coordinates from the morphed "from" surface // BrainSetNodeAttribute* bna = fromBrain->getNodeAttributes(i); const float* xyz = fromCoords->getCoordinate(i); toCoords->setCoordinate(bna->morphNode, xyz); // // Use the visited flag to mark this node as being updated // BrainSetNodeAttribute* hiResAttr = toBrain->getNodeAttributes(bna->morphNode); hiResAttr->setVisited(true); } } } // // Point Projector to project new surface points into original surface // BrainModelSurfacePointProjector* bspp = new BrainModelSurfacePointProjector(fromNotMorphedSurface, BrainModelSurfacePointProjector::SURFACE_TYPE_HINT_FLAT, false); // // process all nodes in the "to" surface that were not downsampled // for (int i = 0; i < numToNodes; i++) { // // Was node NOT downsampled ? // if (toBrain->getNodeAttributes(i)->getVisited() == false) { // // project using non-morphed "from" surface // int nearestTile = -1; int tileNodes[3]; float tileAreas[3]; const int node = bspp->projectBarycentricBestTile2D(toCoords->getCoordinate(i), nearestTile, tileNodes, tileAreas); if (node >= 0) { float xyz[3]; BrainModelSurfacePointProjector::unprojectPoint(tileNodes, tileAreas, fromCoords, xyz); toCoords->setCoordinate(i, xyz); } else if (node >= 0) { std::cout << "WARNING: Using nearest node when upsampling for " << i << std::endl; toCoords->setCoordinate(i, fromCoords->getCoordinate(node)); } } } } /** * Read in the standard spheres and then construct a fiducial surface for each of them. */ void BrainModelSurfaceMultiresolutionMorphing::constructTemplateSpheres( std::vector& brains) throw (BrainModelAlgorithmException) { // // Get radius of the morphing surface // const float morphingSurfaceRadius = morphingSurface->getSphericalSurfaceRadius(); // // Create a point projector for the morphing surface // BrainModelSurfacePointProjector mspp(morphingSurface, BrainModelSurfacePointProjector::SURFACE_TYPE_HINT_SPHERE, false); // // Get the center of gravity of the reference surface // float referenceCOG[3]; referenceSurface->getCenterOfMass(referenceCOG); // // User's reference surface coordinate file // const CoordinateFile* referenceCoordinateFile = referenceSurface->getCoordinateFile(); // // Do for each level // int numberOfLevels = this->multiResMorphFile.getNumberOfLevels(); for (int lvl = (numberOfLevels - 1); lvl > 0; lvl--) { // // Create name of standard sphere spec file // std::ostringstream ostr; ostr << brainSet->getCaretHomeDirectory().toAscii().constData() << "/data_files/CONSTRUCT.SPHERE/" << "sphere.v5." << lvl << ".spec"; const QString specFileName(ostr.str().c_str()); // // Save name of current directory since reading a spec file sets the // current path to the spec file's directory. // const QString savedPath(QDir::currentPath()); // // Read the spec file and select all files in the spec file // SpecFile sf; try { sf.readFile(specFileName); sf.setAllFileSelections(SpecFile::SPEC_TRUE); } catch (FileException& /*e*/) { std::ostringstream msg; msg << "Unable to read file: " << specFileName.toAscii().constData() << std::endl; throw BrainModelAlgorithmException(msg.str().c_str()); } // // Create a new brain set and load the files listed in the spec file // BrainSet* sphereBrain = new BrainSet; std::vector errorMessages; sphereBrain->readSpecFile(BrainSet::SPEC_FILE_READ_MODE_NORMAL, sf, specFileName, errorMessages, NULL, NULL); if (errorMessages.size() > 0) { QString msg("Error reading data files listed in spec file: "); msg.append(specFileName); msg.append("\n"); for (unsigned int i = 0; i < errorMessages.size(); i++) { msg.append(errorMessages[i]); msg.append("\n"); } throw BrainModelAlgorithmException(msg); } else if (sphereBrain->getNumberOfBrainModels() < 2) { QString msg(specFileName); msg.append(" contains\nless than two surface. Should have fiducial and spherical"); throw BrainModelAlgorithmException(msg); } // // Restore the current directory // QDir::setCurrent(savedPath); // // Get the standard sphere fiducial surface // BrainModelSurface* sphereFiducialSurface = sphereBrain->getBrainModelSurface(0); if (sphereFiducialSurface == NULL) { QString msg("Spec file: "); msg.append(specFileName); msg.append("\nDoes not contains any surfaces."); throw BrainModelAlgorithmException(msg); } CoordinateFile* sphereFiducialCoords = sphereFiducialSurface->getCoordinateFile(); // // Get the standard sphere surface // BrainModelSurface* sphereSurface = sphereBrain->getBrainModelSurface(1); if (sphereSurface == NULL) { QString msg("Spec file: "); msg.append(specFileName); msg.append("\nDoes not contains less than 1 surface."); throw BrainModelAlgorithmException(msg); } // // Set the view of this standard sphere surface so that it is the // same as the surface being morphed (04/27/2009). // sphereSurface->copyTransformations(this->morphingSurface, BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW, BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW); // // Set the sphere to have the same area as the reference surface // sphereSurface->convertToSphereWithRadius(morphingSurfaceRadius); // // Rotate the sphere just a little. Higher resolution spheres have points directly // on edges of the lower resolution sphere which creates a degenerate condition // when mapping. // TransformationMatrix tm; tm.rotate(TransformationMatrix::ROTATE_X_AXIS, 0.25 * lvl); tm.rotate(TransformationMatrix::ROTATE_Y_AXIS, 0.25 * lvl); tm.rotate(TransformationMatrix::ROTATE_Z_AXIS, 0.25 * lvl); sphereSurface->applyTransformationMatrix(tm); // // Project nodes in sphere surface onto morphing surface // const int numSphereNodes = sphereSurface->getNumberOfNodes(); if (numSphereNodes != sphereFiducialCoords->getNumberOfCoordinates()) { QString msg(specFileName); msg.append("\nfiducial and sphere have a different number of coordinates.\n"); msg.append("Sphere Fiducial number of coordinates: "); msg.append(StringUtilities::fromNumber(sphereFiducialCoords->getNumberOfCoordinates())); msg.append("\nSphere number of coordinates: "); msg.append(StringUtilities::fromNumber(numSphereNodes)); throw BrainModelAlgorithmException(msg); } CoordinateFile* sphereCoords = sphereSurface->getCoordinateFile(); std::vector nodeNotProjected(numSphereNodes, false); bool haveNotProjectedNodes = false; for (int i = 0; i < numSphereNodes; i++) { float xyz[3]; sphereCoords->getCoordinate(i, xyz); // // Project point to input surface // int nearestNode = -1; int tileNodes[3]; float tileAreas[3]; const int tile = mspp.projectBarycentric(xyz, nearestNode, tileNodes, tileAreas, true); // // Did point project into the surface // if (tile >= 0) { // // Set the sphere's reference surface coordinate // float refXYZ[3]; BrainModelSurfacePointProjector::unprojectPoint(tileNodes, tileAreas, referenceCoordinateFile, refXYZ); sphereFiducialCoords->setCoordinate(i, refXYZ); } else { // // Medial wall may be missing from user's reference sphere so mark nodes // as not projected and place them at the origin // nodeNotProjected[i] = true; haveNotProjectedNodes = true; sphereFiducialCoords->setCoordinate(i, referenceCOG); } } // for (i = 0; i < numSphereNodes... // // If there are nodes that were not projected. Typically these nodes are in // the medial wall so smoothing them pulls them from the origin. // if (haveNotProjectedNodes) { sphereFiducialSurface->linearSmoothing(1.0, 300, 0, &nodeNotProjected); } // // save this sphere brain // brains.push_back(sphereBrain); } // for (lvl... } /** * Map each brain to brain + 1 */ void BrainModelSurfaceMultiresolutionMorphing::createSphereDownsampleMapping( std::vector& brains) throw (BrainModelAlgorithmException) { const int numBrains = static_cast(brains.size()); // // Map each brain to the next brain // for (int i = 0; i < (numBrains - 1); i++) { // // Get the brains // BrainSet* currentBrain = brains[i]; BrainSet* nextBrain = brains[i + 1]; // // Get the current sphere's surface and coordinate file // BrainModelSurface* currentSphereSurface = NULL; if (i == 0) { currentSphereSurface = morphingSurface; } else { currentSphereSurface = currentBrain->getBrainModelSurface(SURFACE_MORPHED_INDEX); } const CoordinateFile* currentSphereCoords = currentSphereSurface->getCoordinateFile(); const int numCoords = currentSphereCoords->getNumberOfCoordinates(); // // Topology helper for current surface // const TopologyHelper* currentSphereTopologyHelper = new TopologyHelper( currentSphereSurface->getTopologyFile(), false, true, false); // // Get the next sphere's surface // BrainModelSurface* nextSphereSurface = nextBrain->getBrainModelSurface(SURFACE_MORPHED_INDEX); // // Create a point projector for the next sphere surface // BrainModelSurfacePointProjector sspp(nextSphereSurface, BrainModelSurfacePointProjector::SURFACE_TYPE_HINT_SPHERE, false); // // Project each node from current sphere to next sphere // for (int i = 0; i < numCoords; i++) { float xyz[3]; currentSphereCoords->getCoordinate(i, xyz); // // Project point to original surface // int nearestNode = -1; int tileNodes[3]; float tileAreas[3]; int tile = -1; // // Only try to project if node has neighbors // if (currentSphereTopologyHelper->getNodeHasNeighbors(i)) { // // Project current sphere node to next sphere // tile = sspp.projectBarycentric(xyz, nearestNode, tileNodes, tileAreas, true); } BrainSetNodeAttribute* bna = currentBrain->getNodeAttributes(i); bna->setSphericalMorphingAttributes(nearestNode, tile, tileNodes, tileAreas); } } } /** * Upsample brain + 1 to brain */ void BrainModelSurfaceMultiresolutionMorphing::sphericalUpsample(std::vector& brains, const int targetBrainIndex) throw (BrainModelAlgorithmException) { // // Get the brains // BrainSet* currentBrain = brains[targetBrainIndex]; BrainSet* nextBrain = brains[targetBrainIndex + 1]; // // Get the current sphere's surface and coordinate file // BrainModelSurface* currentSphereSurface = NULL; if (targetBrainIndex == 0) { currentSphereSurface = morphingSurface; } else { currentSphereSurface = currentBrain->getBrainModelSurface(SURFACE_MORPHED_INDEX); } CoordinateFile* currentSphereCoords = currentSphereSurface->getCoordinateFile(); const int numCoords = currentSphereCoords->getNumberOfCoordinates(); // // Get the radius of the sphere // const float sphereRadius = currentSphereSurface->getSphericalSurfaceRadius(); // // Get the next sphere's surface // BrainModelSurface* nextSphereSurface = nextBrain->getBrainModelSurface(SURFACE_MORPHED_INDEX); const CoordinateFile* nextSphereCoords = nextSphereSurface->getCoordinateFile(); // // Make the next sphere the same radius as the current one // nextSphereSurface->convertToSphereWithRadius(sphereRadius); // // Update the position of each target coordinate // for (int i = 0; i < numCoords; i++) { // // get the node's morphing information int nearestNode = -1; int tileNodes[3]; float tileAreas[3]; int tile = -1; BrainSetNodeAttribute* bna = currentBrain->getNodeAttributes(i); bna->getSphericalMorphingAttributes(nearestNode, tile, tileNodes, tileAreas); if (tile >= 0) { // // Unproject using tile information // float xyz[3]; BrainModelSurfacePointProjector::unprojectPoint(tileNodes, tileAreas, nextSphereCoords, xyz); currentSphereCoords->setCoordinate(i, xyz); } else if (nearestNode >= 0) { // // unproject to nearest node's position // currentSphereCoords->setCoordinate(i, nextSphereCoords->getCoordinate(nearestNode)); } } // // Force nodes to be on the sphere // currentSphereSurface->convertToSphereWithRadius(sphereRadius); } /** * constructor */ MorphingMeasurements::MorphingMeasurements(const QString& nameIn, const StatisticsUtilities::DescriptiveStatistics& arealDistortionStatisticsIn, const StatisticsUtilities::DescriptiveStatistics& linearDistortionStatisticsIn, const int numberOfNodeCrossoversIn, const int numberOfTileCrossoversIn, const float elapsedTimeIn) { arealDistortionStatistics = arealDistortionStatisticsIn; linearDistortionStatistics = linearDistortionStatisticsIn; name = nameIn; numberOfNodeCrossovers = numberOfNodeCrossoversIn; numberOfTileCrossovers = numberOfTileCrossoversIn; elapsedTime = elapsedTimeIn; } /** * get the measurements */ void MorphingMeasurements::get(QString& nameOut, StatisticsUtilities::DescriptiveStatistics& arealDistortionStatisticsOut, StatisticsUtilities::DescriptiveStatistics& linearDistortionStatisticsOut, int& numberOfNodeCrossoversOut, int& numberOfTileCrossoversOut, float& elapsedTimeOut) const { nameOut = name; arealDistortionStatisticsOut = arealDistortionStatistics; linearDistortionStatisticsOut = linearDistortionStatistics; numberOfNodeCrossoversOut = numberOfNodeCrossovers; numberOfTileCrossoversOut = numberOfTileCrossovers; elapsedTimeOut = elapsedTime; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceMorphing.h0000664000175000017500000002505111572067322025112 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_BRAIN_SURFACE_MORPHING_H__ #define __VE_BRAIN_SURFACE_MORPHING_H__ #include #include #include "BrainModelAlgorithmMultiThreaded.h" #include "BrainModelSurface.h" #include "BrainSetNodeAttribute.h" class BrainModelSurface; class CoordinateFile; class QFile; class SurfaceShapeFile; /// This class morphs a surface class BrainModelSurfaceMorphing : public BrainModelAlgorithmMultiThreaded { public: /// type of surface morphing enum MORPHING_SURFACE_TYPE { MORPHING_SURFACE_FLAT, MORPHING_SURFACE_SPHERICAL }; //class NeighborInformation; /// Constructor BrainModelSurfaceMorphing(BrainSet* brainSetIn, BrainModelSurface* referenceSurfaceIn, BrainModelSurface* morphingSurfaceIn, const MORPHING_SURFACE_TYPE morphingSurfaceTypeIn, const int numberOfThreasIn = -1); /// Destructor virtual ~BrainModelSurfaceMorphing(); /// execute the morphing for the number of iterations virtual void execute() throw (BrainModelAlgorithmException); /// get morphing parameters void getMorphingParameters(int& iterationsOut, float& linearForceOut, float& angularForceOut, float& stepSizeOut) const; /// set morphing parameters void setMorphingParameters(const int iterationIn, const float linearForceIn, const float angularForceIn, const float stepSizeIn); /// set the nodes that should be morphred void setNodesThatShouldBeMorphed(const std::vector& nodesThatShouldBeMorphed, const float noMorphStepSizeIn); /// set the fiducial sphere distortion corrections void setFiducialSphereDistortionCorrections(const std::vector& fiducialSphereRatiosIn, const float sphereFiducialDistortionFractionIn); /// get do statistics each pass and save to file bool getDoStatisticsEachPass() const { return doStatisticsEachPass; } /// set do statistics each pass and save to file void setDoStatisticsEachPass(const bool b) { doStatisticsEachPass = b; } protected: /// This class is used to sort nodes class NodeSort { public: /// the node number int nodeNumber; /// its sort value float sortValue; /// constructor NodeSort(const int node, const float value) { nodeNumber = node; sortValue = value; } /// less than method bool operator<(const NodeSort& ns) const { return (sortValue < ns.sortValue); } }; /// This class contains information about relationships to neighboring nodes class NeighborInformation { public: /// Constructor NeighborInformation(); /// Desstructor ~NeighborInformation(); /// initialize the neighbor information void initialize(const float* coords, const int nodeNumberIn, const BrainSetNodeAttribute* nodeAttribute, const int* neighborsIn, const int numNeighborsIn); /// set forces to zero void resetForces(); /// the neighbors sorted int* neighbors; /// the distance to each neighbor float* neighborDistance; /// the angle between neighbors float* angle1; /// the angle between neighbors float* angle2; /// total force on the node (3D) float totalForce[3]; /// angular force on the node (3D) float angularForce[3]; /// linear force on the node (3D) float linearForce[3]; /// number of this node int nodeNumber; /// number of neighbors int numNeighbors; /// node classification BrainSetNodeAttribute::CLASSIFICATION_TYPE classification; }; /// Constructor for a thread instance. BrainModelSurfaceMorphing(BrainSet* brainSetIn, BrainModelSurface* referenceSurfaceIn, BrainModelSurface* morphingSurfaceIn, const MORPHING_SURFACE_TYPE morphingSurfaceTypeIn, NeighborInformation* morphNodeInfoIn, int* nodeShouldBeMorphedIn, const float noMorphStepSizeIn, const int startNodeIndexIn, const int endNodeIndexIn, const float sphericalSurfaceRadiusIn, BrainModelSurfaceMorphing* parentOfThisThreadIn, const int threadNumberIn); /// morph for one iteration void run(int iteration); /// Compute the angular force on a node by its neighbor. void computeAngularForce(const float* coords, const NeighborInformation& nodeInfo, const int neighborIndex, float forcesOut[3]); /// compute the linear force on a node void computeLinearForce(const float* coords, const NeighborInformation& nodeInfo, const int nodeNum, const int neighNodeNum, const int nodeInfoNeighIndex, float force[3]); /// generate the neighbor information for a node void generateNeighborInformation(); /// initialize variables for this instance void initialize(); /// Map forces to a plane (used in spherical morphing). void mapForcesToPlane(const float nodeXYZ[3], float force[3]); /// project node back to the sphere void projectNodeBackToSphere(const int nodeNumber); /// set the forces on nodes that are NOT being morphed void setForcesOnNoMorphNodes(); /// Update the statistics file used for testing void updateStatsFile(QFile& statsFile, CoordinateFile* morphCoordFile, SurfaceShapeFile& measurementsShapeFile, BrainModelSurface::SURFACE_TYPES surfaceTypeHint, const int iterationNumber, const bool firstIterationFlag); /// set the indices of the nodes that are to be morphed (inclusive) void setIndicesOfNodesToMorph(const int startNodeIndexIn, const int endNodeIndexIn); /// set the input and output coords void setInputAndOutputCoords(float* inCoords, float* outCoords); /// check for not a number (true if any data are NaN) bool checkNaN(float* data, int numberOfData) const; /// the reference surface BrainModelSurface* referenceSurface; /// the morphing surface BrainModelSurface* morphingSurface; /// type of surface being morphed MORPHING_SURFACE_TYPE morphingSurfaceType; /// neighboring node information NeighborInformation* morphNodeInfo; /// flat that denotes nodes that should be morphed (int faster than bool) int* nodeShouldBeMorphed; /// ratios of fiducial to spherical surface std::vector fiducialSphereRatios; /// the distortion fraction float sphereFiducialDistortionFraction; /// linear force float linearForce; /// angular force float angularForce; /// step size float stepSize; /// step size for inverse of forces when neighbors are not morphred float noMorphNeighborStepSize; /// number of iterations to morph int iterations; /// array for holding coordinates (inputCoords and outputCoords point to this) float* coordsArray1; /// array for holding coordinates (inputCoords and outputCoords point to this) float* coordsArray2; /// pointers for input coordinates (do not delete) float* inputCoords; /// pointers for output coordinates (do not delete) float* outputCoords; /// number of nodes in the surfaces int numberOfNodes; /// radius of the spherical surface float sphericalSurfaceRadius; /// index of first node to smooth int startNodeIndex; /// index of last node to smooth int endNodeIndex; /// do statistics each pass and save to file bool doStatisticsEachPass; /// all nodes being morphed flag bool allNodesBeingMorphed; /// threads when running multi-threaded. std::vector threads; }; #endif // __VE_BRAIN_SURFACE_MORPHING_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceMorphing.cxx0000664000175000017500000015131211572067322025465 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include // needed for Q_OS_WIN32 #ifdef Q_OS_WIN32 // required for M_PI in #define NOMINMAX #define _USE_MATH_DEFINES #endif #include #include #include #include #include #include #include #include "BrainModelSurfaceDistortion.h" #include "BrainSetNodeAttribute.h" #include "BrainSet.h" #include "BrainModelSurfaceMorphing.h" #include "DebugControl.h" #include "FileUtilities.h" #include "MathUtilities.h" #include "StatisticsUtilities.h" #include "StringUtilities.h" #include "SurfaceShapeFile.h" #include "TopologyHelper.h" #include "vtkMath.h" #include "vtkTriangle.h" /** * Constructor */ BrainModelSurfaceMorphing::BrainModelSurfaceMorphing(BrainSet* brainSetIn, BrainModelSurface* referenceSurfaceIn, BrainModelSurface* morphingSurfaceIn, const MORPHING_SURFACE_TYPE morphingSurfaceTypeIn, const int numberOfThreadsIn) : BrainModelAlgorithmMultiThreaded(brainSetIn, NULL, -1, false) { initialize(); referenceSurface = referenceSurfaceIn; morphingSurface = morphingSurfaceIn; morphingSurfaceType = morphingSurfaceTypeIn; numberOfNodes = 0; if (morphingSurface != NULL) { numberOfNodes = morphingSurface->getNumberOfNodes(); nodeShouldBeMorphed = new int[numberOfNodes]; for (int i = 0; i < numberOfNodes; i++) { nodeShouldBeMorphed[i] = true; } } PreferencesFile* pf = brainSet->getPreferencesFile(); int numThreads = pf->getMaximumNumberOfThreads(); if (numThreads <= 0) { numThreads = 1; } if (numberOfThreadsIn > 0) { numThreads = numberOfThreadsIn; } setNumberOfThreadsToRun(numThreads); } /** * Constructor for a thread instance. */ BrainModelSurfaceMorphing::BrainModelSurfaceMorphing(BrainSet* brainSetIn, BrainModelSurface* referenceSurfaceIn, BrainModelSurface* morphingSurfaceIn, const MORPHING_SURFACE_TYPE morphingSurfaceTypeIn, NeighborInformation* morphNodeInfoIn, int* nodeShouldBeMorphedIn, const float noMorphStepSizeIn, const int startNodeIndexIn, const int endNodeIndexIn, const float sphericalSurfaceRadiusIn, BrainModelSurfaceMorphing* parentOfThisThreadIn, const int threadNumberIn) : BrainModelAlgorithmMultiThreaded(brainSetIn, parentOfThisThreadIn, threadNumberIn, true) { referenceSurface = referenceSurfaceIn; morphingSurface = morphingSurfaceIn; morphingSurfaceType = morphingSurfaceTypeIn; morphNodeInfo = morphNodeInfoIn; nodeShouldBeMorphed = nodeShouldBeMorphedIn; noMorphNeighborStepSize = noMorphStepSizeIn; startNodeIndex = startNodeIndexIn; endNodeIndex = endNodeIndexIn; sphericalSurfaceRadius = sphericalSurfaceRadiusIn; } /** * Initialize variables for this instance. */ void BrainModelSurfaceMorphing::initialize() { doStatisticsEachPass = false; coordsArray1 = NULL; coordsArray2 = NULL; morphNodeInfo = NULL; referenceSurface = NULL; morphingSurface = NULL; iterations = 1; linearForce = 0.50; angularForce = 0.30; stepSize = 0.5; noMorphNeighborStepSize = 0.5; nodeShouldBeMorphed = NULL; numberOfNodes = 0; allNodesBeingMorphed = true; setNumberOfThreadsToRun(1); } /** * Destructor */ BrainModelSurfaceMorphing::~BrainModelSurfaceMorphing() { if (getImAThread() == false) { if (coordsArray1 != NULL) { delete[] coordsArray1; } if (coordsArray2 != NULL) { delete[] coordsArray2; } if (morphNodeInfo != NULL) { delete[] morphNodeInfo; } if (nodeShouldBeMorphed != NULL) { delete[] nodeShouldBeMorphed; } for (unsigned int i = 0; i < threads.size(); i++) { if (threads[i] != NULL) { delete threads[i]; } } } } /** * get morphing parameters */ void BrainModelSurfaceMorphing::getMorphingParameters(int& iterationsOut, float& linearForceOut, float& angularForceOut, float& stepSizeOut) const { iterationsOut = iterations; linearForceOut = linearForce; angularForceOut = angularForce; stepSizeOut = stepSize; } /** * set morphing parameters */ void BrainModelSurfaceMorphing::setMorphingParameters(const int iterationsIn, const float linearForceIn, const float angularForceIn, const float stepSizeIn) { iterations = iterationsIn; linearForce = linearForceIn; angularForce = angularForceIn; stepSize = stepSizeIn; } /** * execute the morphing */ void BrainModelSurfaceMorphing::execute() throw (BrainModelAlgorithmException) { BrainModelSurface::SURFACE_TYPES surfaceTypeHint = BrainModelSurface::SURFACE_TYPE_UNKNOWN; switch (morphingSurfaceType) { case MORPHING_SURFACE_FLAT: surfaceTypeHint = BrainModelSurface::SURFACE_TYPE_FLAT; break; case MORPHING_SURFACE_SPHERICAL: surfaceTypeHint = BrainModelSurface::SURFACE_TYPE_SPHERICAL; break; default: break; } if (numberOfNodes <= 0) { throw BrainModelAlgorithmException("Morphing surface has no nodes."); } if (numberOfNodes != referenceSurface->getNumberOfNodes()) { throw BrainModelAlgorithmException( "Reference and Morphing surfaces have a different number of nodes."); } // // Morphing surface coordinate file // CoordinateFile* morphCoordFile = morphingSurface->getCoordinateFile(); // // Get the coordinates and load them into arrays // float* coordsArray1 = new float[numberOfNodes * 3]; float* coordsArray2 = new float[numberOfNodes * 3]; for (int i = 0; i < numberOfNodes; i++) { morphCoordFile->getCoordinate(i, &coordsArray1[i*3]); } // // Set the input and output coord pointers // inputCoords = coordsArray1; outputCoords = coordsArray2; // // Generate neighbors, lengths, and angles for reference surface // generateNeighborInformation(); // // Save radius of morphing surface in case it is a sphere // sphericalSurfaceRadius = morphingSurface->getSphericalSurfaceRadius(); // // If no iterations (just calculating forces) // bool forcesOnlyFlag = false; if (iterations == 0) { forcesOnlyFlag = true; iterations = 1; } // // If measuring at each iteration // QFile statsFile("morph_stats.txt"); bool statsFileValid = false; if (doStatisticsEachPass) { if (statsFile.open(QIODevice::WriteOnly)) { statsFileValid = true; } } // // Surface shape file for measurements // SurfaceShapeFile measurementsShapeFile; // // See if threads are being used, and if so, create them. // const int numberOfThreads = getNumberOfThreadsToRun(); if (numberOfThreads > 1) { // // Number of nodes each thread should smooth // const int numNodesPerThread = numberOfNodes / numberOfThreads; int startNode = 0; int endNode = numNodesPerThread; for (int i = 0; i < numberOfThreads; i++) { // // Limit ending node for last thread // if (i == (numberOfThreads - 1)) { endNode = numberOfNodes - 1; } if (DebugControl::getDebugOn()) { std::cout << "Morphing thread " << i << " nodes " << startNode << " " << endNode << std::endl; } // // Create the threads // BrainModelSurfaceMorphing* bmsm = new BrainModelSurfaceMorphing( brainSet, referenceSurface, morphingSurface, morphingSurfaceType, morphNodeInfo, nodeShouldBeMorphed, noMorphNeighborStepSize, startNode, endNode, sphericalSurfaceRadius, this, i); bmsm->setMorphingParameters(iterations, linearForce, angularForce, stepSize); threads.push_back(bmsm); // // Determine node indices which each thread should smooth // startNode = endNode + 1; endNode += numNodesPerThread; } } // // morph for the surface // for (int i = 1; i <= iterations; i++) { const bool firstIterationFlag = (i == 1); const bool lastIterationFlag = (i == iterations); // // Update surface normals // //for (int j = 0; j < numberOfNodes; j++) { // morphCoordFile->setCoordinate(j, &inputCoords[j*3]); //} //morphingSurface->computeNormals(); morphingSurface->computeNormals(inputCoords); // // Set the forces on nodes that are NOT being morphed // if (allNodesBeingMorphed == false) { setForcesOnNoMorphNodes(); } // // If running threads // if (numberOfThreads > 1) { for (int j = 0; j < numberOfThreads; j++) { // // Run each thread for an iteration of smoothing // threads[j]->setInputAndOutputCoords(inputCoords, outputCoords); // // Clear the number of child threads done // resetNumChildThreadDone(); // // Start the threads if this is the first iteration // if (firstIterationFlag) { threads[j]->setThreadKeepLoopingFlag(true); threads[j]->setThreadedIterationDoneFlag(true); threads[j]->start(QThread::TimeCriticalPriority); } } // // Wait until all threads have started and in their loop. // This is need for the case that there is only one iteration. // while (getNumChildThreadStarted() < numberOfThreads) { msleep(1); } for (int j = 0; j < numberOfThreads; j++) { // // if the last iteration, clear the keep looping flag for the thread // if (lastIterationFlag ) { threads[j]->setThreadKeepLoopingFlag(false); } // // wake the thread so that it executes an iteration // if (DebugControl::getDebugOn()) { std::cout << "Allowing morphing thread " << j << " to run." << std::endl; } threads[j]->setThreadedIterationDoneFlag(false); } // // Wait until all of the threads finish // while (getNumChildThreadDone() < numberOfThreads) { msleep(1); } if (DebugControl::getDebugOn()) { std::cout << "All morphing threads completed iteration." << std::endl; } } else { // // Smooth for one iteration // setIndicesOfNodesToMorph(0, numberOfNodes - 1); run(i); } // // morph one iteration // //run(i); if (DebugControl::getDebugOn()) { if ((DebugControl::getDebugNodeNumber() >= 0) && (DebugControl::getDebugNodeNumber() < numberOfNodes)) { const int node = DebugControl::getDebugNodeNumber(); std::cout << "DEBUG iter " << i << " NODE " << node << " coords: " << outputCoords[node*3] << " " << outputCoords[node*3+1] << " " << outputCoords[node*3+2] << std::endl; } } bool coordFileUpdated = false; // // If NOT the last iteration // if (lastIterationFlag == false) { // // Update the displayed brain model // if (brainSet->isIterationUpdate(i)) { for (int j = 0; j < numberOfNodes; j++) { morphCoordFile->setCoordinate(j, &outputCoords[j*3]); } brainSet->drawBrainModel(morphingSurface, i); coordFileUpdated = true; } // // swap input and output coordinate pointers // std::swap(inputCoords, outputCoords); } // // If just calculating forces, reset iterations // if (forcesOnlyFlag) { iterations = 0; } // // If measuring at each iteration // if (statsFileValid) { // // If not just doing forces // if (forcesOnlyFlag == false) { updateStatsFile(statsFile, morphCoordFile, measurementsShapeFile, surfaceTypeHint, i, firstIterationFlag); } } } // // // if (statsFileValid) { statsFile.close(); } // // Copy the coordinates back to the morphing surface // if (forcesOnlyFlag == false) { for (int j = 0; j < numberOfNodes; j++) { morphCoordFile->setCoordinate(j, &outputCoords[j*3]); } } // // Copy the force vectors // BrainSetNodeAttribute* attributes = brainSet->getNodeAttributes(0); for (int i = 0; i < numberOfNodes; i++) { attributes[i].setMorphingForces(morphNodeInfo[i].linearForce, morphNodeInfo[i].angularForce, morphNodeInfo[i].totalForce); } if (DebugControl::getDebugOn()) { const int node = DebugControl::getDebugNodeNumber(); if (node >= 0) { int start = node - 5; int end = node + 5; if (start < 0) { start = start - start; end = start + 10; } if (end >= numberOfNodes) { end = numberOfNodes - 1; } for (int j = start; j < end; j++) { std::cout << j << ": Forces (L, A): " << morphNodeInfo[j].linearForce[0] << " " << morphNodeInfo[j].linearForce[1] << " " << morphNodeInfo[j].linearForce[2] << " " << morphNodeInfo[j].angularForce[0] << " " << morphNodeInfo[j].angularForce[1] << " " << morphNodeInfo[j].angularForce[2] << " " << std::endl; } } } } /** * Update the statistics file used for testing */ void BrainModelSurfaceMorphing::updateStatsFile(QFile& statsFile, CoordinateFile* morphCoordFile, SurfaceShapeFile& measurementsShapeFile, BrainModelSurface::SURFACE_TYPES surfaceTypeHint, const int iterationNumber, const bool firstIterationFlag) { // // Add columns to surface shape file if first time // if (measurementsShapeFile.getNumberOfColumns() <= 1) { measurementsShapeFile.setNumberOfNodesAndColumns(numberOfNodes, 2); } // // Update coordinates since stats taken on surface // for (int j = 0; j < numberOfNodes; j++) { morphCoordFile->setCoordinate(j, &outputCoords[j*3]); } // // Determine distortion // BrainModelSurfaceDistortion bmsd(brainSet, morphingSurface, referenceSurface, morphingSurface->getTopologyFile(), &measurementsShapeFile, BrainModelSurfaceDistortion::DISTORTION_COLUMN_CREATE_NEW, BrainModelSurfaceDistortion::DISTORTION_COLUMN_CREATE_NEW, "areal-dist", "linear-dist"); try { // // Generate distortion // bmsd.execute(); // // Get areal and linear distortion statistics // StatisticsUtilities::DescriptiveStatistics arealStats, linearStats; bmsd.getArealDistortionStatistics(arealStats); bmsd.getLinearDistortionStatistics(linearStats); // // Do a crossover check // int numTileCrossovers, numNodeCrossovers; morphingSurface->crossoverCheck(numTileCrossovers, numNodeCrossovers, surfaceTypeHint); // // Set textstream for file // QTextStream stream(&statsFile); stream.setRealNumberNotation(QTextStream::FixedNotation); if (firstIterationFlag) { stream << "" << "\t" << "Number of" << "\t" << "Areal" << "\t" << "Areal" << "\t" << "Linear" << "\t" << "Linear" << "\n"; stream << "Iteration" << "\t" << "Tile" << "\t" << "Distortion" << "\t" << "Distortion" << "\t" << "Distortion" << "\t" << "Distortion" << "\n"; stream << "Number" << "\t" << "Crossovers" << "\t" << "Average" << "\t" << "Deviation" << "\t" << "Average" << "\t" << "Deviation" << "\n"; } stream << iterationNumber << "\t" << numTileCrossovers << "\t" << arealStats.average << "\t" << arealStats.standardDeviation << "\t" << linearStats.average << "\t" << linearStats.standardDeviation << "\n"; } catch (BrainModelAlgorithmException&) { } } /** * Project nodes back to the sphere. */ void BrainModelSurfaceMorphing::projectNodeBackToSphere(const int nodeNumber) { // // scale to sphere // if (morphNodeInfo[nodeNumber].numNeighbors > 0) { const int i3 = nodeNumber * 3; const float prad = std::sqrt(outputCoords[i3] * outputCoords[i3] + outputCoords[i3+1] * outputCoords[i3+1] + outputCoords[i3+2] * outputCoords[i3+2]); if (prad > 0.0) { const float scale = sphericalSurfaceRadius / prad; outputCoords[i3] *= scale; outputCoords[i3+1] *= scale; outputCoords[i3+2] *= scale; } } } /** * Calculate forces on nodes that are NOT BEING MORPHED. * This cannot be done inside the threaded execution since these * node's forces are needed by other nodes. */ void BrainModelSurfaceMorphing::setForcesOnNoMorphNodes() { // // Calculate forces on nodes that are NOT BEING MORPHED // This is needed for some "inverse force" calculations needed below // for (int j = 0; j < numberOfNodes; j++) { if (nodeShouldBeMorphed[j] == false) { // // Info for this node and reset forces // NeighborInformation& nodeInfo = morphNodeInfo[j]; nodeInfo.resetForces(); if (nodeInfo.numNeighbors > 1) { const float floatNumNeighbors = static_cast(nodeInfo.numNeighbors); // // Determine linear forces for node // if (linearForce > 0.0) { for (int k = 0; k < nodeInfo.numNeighbors; k++) { const int n = nodeInfo.neighbors[k]; float linearForceComponents[3]; computeLinearForce(inputCoords, nodeInfo, j, n, k, linearForceComponents); for (int i = 0; i < 3; i++) { nodeInfo.totalForce[i] += linearForceComponents[i] / floatNumNeighbors; nodeInfo.linearForce [i] += linearForceComponents[i] / floatNumNeighbors; } } } // Apply angular forces to node // if (angularForce > 0.0) { if (nodeInfo.classification == BrainSetNodeAttribute::CLASSIFICATION_TYPE_CORNER) { float angularForceComponents[3]; computeAngularForce(inputCoords, nodeInfo, 0, angularForceComponents); for (int i = 0; i < 3; i++){ nodeInfo.totalForce[i] += angularForceComponents[i] / (floatNumNeighbors - 1.0); nodeInfo.angularForce[i] += angularForceComponents[i] / (floatNumNeighbors - 1.0); } } else { for (int k = 0; k < nodeInfo.numNeighbors; k++){ float angularForceComponents[3]; computeAngularForce(inputCoords, nodeInfo, k, angularForceComponents); for (int i = 0; i < 3; i++){ nodeInfo.totalForce[i] += angularForceComponents[i] / floatNumNeighbors; nodeInfo.angularForce[i] += angularForceComponents[i] / floatNumNeighbors; } } } } // if (angularForce > 0.0) } } } } /** * Morph the surface */ void BrainModelSurfaceMorphing::run(int iteration) { QTime timer; timer.start(); // // set looping flag for non-threaded execution so that we do an iteration // if (getImAThread() == false) { setThreadKeepLoopingFlag(true); } // // The threaded execution will stay in the loop since run only gets called once // while (getThreadKeepLoopingFlag()) { // // Is this a threaded instance // if (getImAThread()) { // // let parent know that this thread has started // getParentOfThisThread()->incrementNumChildThreadStarted(); // // Wait until parent says it is okay to go // while (getThreadedIterationDoneFlag()) { msleep(1); } if (DebugControl::getDebugOn()) { std::cout << "Morphing Thread " << getThreadNumber() << " now executing." << std::endl; } } // // morph each node that should be morphed // for (int j = startNodeIndex; j <= endNodeIndex; j++) { // // Save node position // float nodePos[3] = { inputCoords[j*3], inputCoords[j*3+1], inputCoords[j*3+2] }; outputCoords[j*3] = nodePos[0]; outputCoords[j*3+1] = nodePos[1]; outputCoords[j*3+2] = nodePos[2]; // // Info for this node // NeighborInformation& nodeInfo = morphNodeInfo[j]; // // If this node has neighbors and should be morphed // if ((nodeInfo.numNeighbors > 1) && nodeShouldBeMorphed[j]) { // // Initialize forces to zero // nodeInfo.resetForces(); float linearForceComponents[3]; float angularForceComponents[3]; const float floatNumNeighbors = static_cast(nodeInfo.numNeighbors); // // Apply linear forces to node // if (linearForce > 0.0) { for (int k = 0; k < nodeInfo.numNeighbors; k++) { const int n = nodeInfo.neighbors[k]; computeLinearForce(inputCoords, nodeInfo, j, n, k, linearForceComponents); for (int i = 0; i < 3; i++) { nodeInfo.totalForce[i] += linearForceComponents[i] / floatNumNeighbors; nodeInfo.linearForce[i] += linearForceComponents[i] / floatNumNeighbors; // // If this neighbor is not a morphable node // if (nodeShouldBeMorphed[n] == false) { // // Add the inverse of the neighbor's linear force // nodeInfo.totalForce[i] -= (noMorphNeighborStepSize * morphNodeInfo[n].linearForce[i]) / floatNumNeighbors; nodeInfo.linearForce[i] -= (noMorphNeighborStepSize * morphNodeInfo[n].linearForce[i]) / floatNumNeighbors; } } } if (DebugControl::getDebugOn()) { if (DebugControl::getDebugNodeNumber() == j) { std::cout << std::endl; std::cout << "Total Linear Force for node: " << j << "(" << nodeInfo.linearForce[0] << ", " << nodeInfo.linearForce[1] << ", " << nodeInfo.linearForce[2] << ")" << std::endl; std::cout << std::endl; } } } // // Apply angular forces to node // if (angularForce > 0.0) { if (nodeInfo.classification == BrainSetNodeAttribute::CLASSIFICATION_TYPE_CORNER) { computeAngularForce(inputCoords, nodeInfo, 0, angularForceComponents); for (int i = 0; i < 3; i++){ nodeInfo.totalForce[i] += angularForceComponents[i] / (floatNumNeighbors - 1.0); nodeInfo.angularForce[i] += angularForceComponents[i] / (floatNumNeighbors - 1.0); } } else { for (int k = 0; k < nodeInfo.numNeighbors; k++){ const int n = nodeInfo.neighbors[k]; computeAngularForce(inputCoords, nodeInfo, k, angularForceComponents); for (int i = 0; i < 3; i++){ nodeInfo.totalForce[i] += angularForceComponents[i] / floatNumNeighbors; nodeInfo.angularForce[i] += angularForceComponents[i] / floatNumNeighbors; // // If this neighbor is not a morphable node // if (nodeShouldBeMorphed[n] == false) { // // Add the inverse of the neighbor's linear force // nodeInfo.totalForce[i] -= (noMorphNeighborStepSize * morphNodeInfo[n].angularForce[i]) / floatNumNeighbors; nodeInfo.angularForce[i] -= (noMorphNeighborStepSize * morphNodeInfo[n].angularForce[i]) / floatNumNeighbors; } } } } } // if (angularForce > 0.0) // // Adjust forces during spherical morphing // if (morphingSurfaceType == MORPHING_SURFACE_SPHERICAL) { mapForcesToPlane(nodePos, nodeInfo.totalForce); mapForcesToPlane(nodePos, nodeInfo.angularForce); mapForcesToPlane(nodePos, nodeInfo.linearForce); } // // Add forces and store in temporary node positions // outputCoords[j*3] = nodePos[0] + stepSize * nodeInfo.totalForce[0]; outputCoords[j*3+1] = nodePos[1] + stepSize * nodeInfo.totalForce[1]; outputCoords[j*3+2] = nodePos[2] + stepSize * nodeInfo.totalForce[2]; if (DebugControl::getDebugOn()) { if (checkNaN(&outputCoords[j*3], 3)) { QString s = "PROGRAM ERROR: NaN detected for coordinate " + QString::number(j) + " iteration " + QString::number(iteration) + " in " + FileUtilities::basename(morphingSurface->getCoordinateFile()->getFileName()); throw BrainModelAlgorithmException(s); } } } // if (nodeInfo.numNeighbors > 1) // // Project back to sphere if morphing a sphere // switch (morphingSurfaceType) { case MORPHING_SURFACE_FLAT: break; case MORPHING_SURFACE_SPHERICAL: projectNodeBackToSphere(j); break; } } // for (j = 0... if (getImAThread()) { if (DebugControl::getDebugOn()) { std::cout << "Morphing Thread " << getThreadNumber() << " finished iteration." << std::endl; } // // A threaded instance needs to tell that it has completed an iteration // setThreadedIterationDoneFlag(true); getParentOfThisThread()->incrementNumChildThreadDone(); } else { // // A non-threaded instance needs to return // setThreadKeepLoopingFlag(false); } } // while (keepLooping) if (DebugControl::getDebugOn()) { std::cout << " iteration" << iteration << " time: " << (static_cast(timer.elapsed()) / 1000.0) << std::endl; } } /** * check for not a number (true if any data are NaN). */ bool BrainModelSurfaceMorphing::checkNaN(float* data, int numberOfData) const { for (int i = 0; i < numberOfData; i++) { if (MathUtilities::isNaN(data[i])) { return true; } } return false; } /** * Map forces to a plane (used in spherical morphing). */ void BrainModelSurfaceMorphing::mapForcesToPlane(const float nodeXYZ[3], float force[3]) { // // Compute the node's normal // float nodeNormal[3] = { nodeXYZ[0], nodeXYZ[1], nodeXYZ[2] }; MathUtilities::normalize(nodeNormal); // // angle between normal and force // const float dot = MathUtilities::dotProduct(nodeNormal, force); // // Adjust force // force[0] = force[0] - (dot * nodeNormal[0]); force[1] = force[1] - (dot * nodeNormal[1]); force[2] = force[2] - (dot * nodeNormal[2]); } /** * Compute the angular force on a node by its neighbor. */ void BrainModelSurfaceMorphing::computeAngularForce(const float* coords, const NeighborInformation& nodeInfo, const int neighborIndex, float forceOut[3]) { // // Clear forces // forceOut[0] = 0.0; forceOut[1] = 0.0; forceOut[2] = 0.0; if (nodeInfo.numNeighbors < 1) { return; } // // Indices of neighboring nodes // const int neighborNodeNumber = nodeInfo.neighbors[neighborIndex]; int nextNeighborIndex = neighborIndex + 1; if (nextNeighborIndex >= nodeInfo.numNeighbors) nextNeighborIndex = 0; const int nextNeighborNodeNumber = nodeInfo.neighbors[nextNeighborIndex]; // // coordinates of this node and the neighbors // const float* nodeCoords = &coords[nodeInfo.nodeNumber * 3]; const float* neighborCoords = &coords[neighborNodeNumber * 3]; const float* nextNeighborCoords = &coords[nextNeighborNodeNumber * 3]; // // Compute the normal for the triangle // float triangleNormal[3]; MathUtilities::computeNormal((float*)nodeCoords, (float*)neighborCoords, (float*)nextNeighborCoords, triangleNormal); // // Check for crossovers // bool crossover = false; switch (morphingSurfaceType) { case MORPHING_SURFACE_FLAT: if (triangleNormal[2] < 0.0) { crossover = true; } break; case MORPHING_SURFACE_SPHERICAL: { float avgNormal[3] = { (nodeCoords[0] + neighborCoords[0] + nextNeighborCoords[0]) / 3.0, (nodeCoords[1] + neighborCoords[1] + nextNeighborCoords[1]) / 3.0, (nodeCoords[2] + neighborCoords[2] + nextNeighborCoords[2]) / 3.0 }; if (MathUtilities::normalize(avgNormal) > 0.0) { const float dot = MathUtilities::dotProduct(avgNormal, triangleNormal); if (dot < 0.0) { crossover = true; } } } break; } crossover = false; //********************************************************* if (crossover) { triangleNormal[0] = -triangleNormal[0]; triangleNormal[1] = -triangleNormal[1]; triangleNormal[2] = -triangleNormal[2]; } // // Angle at neighbor // const float angle1 = MathUtilities::angle(nodeCoords, neighborCoords, nextNeighborCoords); // // angle difference // float angleDiff1 = nodeInfo.angle1[neighborIndex] - angle1; if (crossover) { angleDiff1 = nodeInfo.angle1[neighborIndex] + angle1; } // // distance components and distance to neighbor // float distanceComponents1[3]; MathUtilities::subtractVectors(neighborCoords, nodeCoords, distanceComponents1); const float distance1 = MathUtilities::vectorLength(distanceComponents1); // // Amount (magnitude) node should be moved // const float mag1 = distance1 * std::sin(angleDiff1); // // Determine vector of node movement // float direction1[3]; // // Determine a vector that points orthogonally from the plane defined // by the tile's normal vector and the tiles edge (vector perpendicular to // edge pointing outside the tringle but in the triangle's plane). // MathUtilities::normalizedCrossProduct(distanceComponents1, triangleNormal, direction1); if (MathUtilities::vectorLength(direction1) > 0.0) { float force[3]; force[0] = angularForce * mag1 * direction1[0]; force[1] = angularForce * mag1 * direction1[1]; force[2] = angularForce * mag1 * direction1[2]; if (DebugControl::getDebugOn()) { if (checkNaN(force, 3)) { QString s = "PROGRAM ERROR: NaN detected for angular force node " + QString::number(nodeInfo.nodeNumber) + " in " + FileUtilities::basename(morphingSurface->getCoordinateFile()->getFileName()); throw BrainModelAlgorithmException(s); } } if (crossover) { force[0] = -force[0]; force[1] = -force[1]; force[2] = -force[2]; } forceOut[0] += force[0]; forceOut[1] += force[1]; forceOut[2] += force[2]; if (DebugControl::getDebugOn()) { const int node = DebugControl::getDebugNodeNumber(); if (node == nodeInfo.nodeNumber) { std::cout << "Morphing Debugging Node: " << node << std::endl; std::cout << "Neighbor: " << neighborNodeNumber << std::endl; std::cout << "Angle1 (Fiducial, surface): " << (nodeInfo.angle1[neighborIndex] * MathUtilities::radiansToDegrees()) << " " << (angle1 * MathUtilities::radiansToDegrees()) << std::endl; std::cout << "Force: " << force[0] << ", " << force[1] << ", " << force[2] << std::endl; } } } //--------------------------------------------------------------------------------------- // // Angle at neighbor // const float angle2 = MathUtilities::angle(neighborCoords, nextNeighborCoords, nodeCoords); // // angle difference // float angleDiff2 = nodeInfo.angle2[neighborIndex] - angle2; if (crossover) { angleDiff2 = nodeInfo.angle2[neighborIndex] + angle2; } // // distance components and distance to neighbor // float distanceComponents2[3]; MathUtilities::subtractVectors(nextNeighborCoords, nodeCoords, distanceComponents2); const float distance2 = MathUtilities::vectorLength(distanceComponents2); // // Amount (magnitude) node should be moved // const float mag2 = distance2 * std::sin(angleDiff2); // // Determine vector of node movement // float direction2[3]; // // Determine a vector that points orthogonally from the plane defined // by the tile's normal vector and the tiles edge (vector perpendicular to // edge pointing outside the tringle but in the triangle's plane). // MathUtilities::normalizedCrossProduct(triangleNormal, distanceComponents2, direction2); if (MathUtilities::vectorLength(direction2) > 0.0) { float force[3]; force[0] = angularForce * mag2 * direction2[0]; force[1] = angularForce * mag2 * direction2[1]; force[2] = angularForce * mag2 * direction2[2]; if (DebugControl::getDebugOn()) { if (checkNaN(force, 3)) { QString s = "PROGRAM ERROR: NaN detected for angular force node " + QString::number(nodeInfo.nodeNumber) + " in " + FileUtilities::basename(morphingSurface->getCoordinateFile()->getFileName()); throw BrainModelAlgorithmException(s); } } if (crossover) { force[0] = -force[0]; force[1] = -force[1]; force[2] = -force[2]; } forceOut[0] += force[0]; forceOut[1] += force[1]; forceOut[2] += force[2]; if (DebugControl::getDebugOn()) { const int node = DebugControl::getDebugNodeNumber(); if (node == nodeInfo.nodeNumber) { std::cout << "Morphing Debugging Node: " << node << std::endl; std::cout << "Neighbor: " << nextNeighborNodeNumber << std::endl; std::cout << "Angle2 (Fiducial, surface): " << (nodeInfo.angle2[neighborIndex] * MathUtilities::radiansToDegrees()) << " " << (angle2 * MathUtilities::radiansToDegrees()) << std::endl; std::cout << "Force: " << force[0] << ", " << force[1] << ", " << force[2] << std::endl; } } } } /** * Compute linear force on a node from a neighbor */ void BrainModelSurfaceMorphing::computeLinearForce(const float* coords, const NeighborInformation& nodeInfo, const int nodeNum, const int neighNodeNum, const int nodeInfoNeighIndex, float force[3]) { // // Clear forces // force[0] = 0.0; force[1] = 0.0; force[2] = 0.0; // // positions of node and neighbor // const float* nodePos = &coords[nodeNum * 3]; const float* neighPos = &coords[neighNodeNum * 3]; // // Distance between node and its neighbor in the surface that is being morphed // const float neighborDistance = MathUtilities::distance3D(nodePos, neighPos); // // If neighbor is very close do not update forces // Added back, 01 April 2009 as node and neighbor had // identical position resulting in NaN // if (neighborDistance <= 0.000001) { return; } // // distance to neighbor in fiducial surface // const float neighborFiducialDistance = nodeInfo.neighborDistance[nodeInfoNeighIndex]; // // Difference between node & neighbor in the fiducial and morphing surface (the "error") // float errorDistance = neighborFiducialDistance - neighborDistance; // // ratio of distances in morphing and fiducial surfaces // float errorDistRatio = 0.0; if (neighborFiducialDistance != 0.0) { errorDistRatio = neighborDistance / neighborFiducialDistance; } // // if compressed, double error // if (errorDistRatio < 0.50) { errorDistance *= 2.0; } // // apply linear force strength // errorDistance *= linearForce; // // get distance between node and neighbor in X, Y, and Z // Note: want to push "this" node in relation to its neighbor // float errorComponents[3]; MathUtilities::subtractVectors(nodePos, neighPos, errorComponents); // // Determine the linear force components // force[0] = errorDistance * errorComponents[0] / neighborDistance; force[1] = errorDistance * errorComponents[1] / neighborDistance; force[2] = errorDistance * errorComponents[2] / neighborDistance; if (DebugControl::getDebugOn()) { if (checkNaN(force, 3)) { QString s = "PROGRAM ERROR: NaN detected for linear force node and neighbor " + QString::number(nodeNum) + " & " + QString::number(neighNodeNum) + " in " + FileUtilities::basename(morphingSurface->getCoordinateFile()->getFileName()); throw BrainModelAlgorithmException(s); } } if (DebugControl::getDebugOn()) { if (DebugControl::getDebugNodeNumber() == nodeNum) { std::cout << std::endl; std::cout << "Linear Force Calculation" << std::endl; std::cout << "Node " << nodeNum << " (" << nodePos[0] << ", " << nodePos[1] << ", " << nodePos[2] << ")" << std::endl; std::cout << "Neighbor " << neighNodeNum << " (" << neighPos[0] << ", " << neighPos[1] << ", " << neighPos[2] << ")" << std::endl; std::cout << "Fiducial Distance: " << neighborFiducialDistance << std::endl; std::cout << "Distance: " << neighborDistance << std::endl; std::cout << "Error Distance: " << errorDistance << std::endl; std::cout << "Linear Force: (" << force[0] << ", " << force[1] << ", " << force[2] << ")" << std::endl; } } } /** * Set the indices of the nodes that are to be morphed (inclusive). */ void BrainModelSurfaceMorphing::setIndicesOfNodesToMorph(const int startNodeIndexIn, const int endNodeIndexIn) { startNodeIndex = startNodeIndexIn; endNodeIndex = endNodeIndexIn; } /** * Set the input and output coords */ void BrainModelSurfaceMorphing::setInputAndOutputCoords(float* inCoords, float* outCoords) { inputCoords = inCoords; outputCoords = outCoords; } /** * Generate neighbor information */ void BrainModelSurfaceMorphing::generateNeighborInformation() { // // Use topology from morphing surface // TopologyFile* tf = morphingSurface->getTopologyFile(); // // Classify the nodes as interior or exterior // BrainSet* bs = morphingSurface->getBrainSet(); bs->classifyNodes(tf); // // Get the coordinates from the reference surface // const CoordinateFile* cf = referenceSurface->getCoordinateFile(); const float* firstCoord = cf->getCoordinate(0); // // Create a topology helper to get node neighbors // const TopologyHelper* th = tf->getTopologyHelper(true, true, true); // // See if fiducial sphere ratios should be used // const bool useFiducialSphereRatios = (numberOfNodes == static_cast(fiducialSphereRatios.size())); const float inverseDistortionFraction = 1.0 - sphereFiducialDistortionFraction; // // Get the surface's brain set and see if this node is interior or edge // const BrainSetNodeAttribute* allNodeAttributes = brainSet->getNodeAttributes(0); // // Generate neighbors, lengths, and angles for reference surface // morphNodeInfo = new NeighborInformation[numberOfNodes]; for (int i = 0; i < numberOfNodes; i++) { int numNeighbors; const int* neighbors = th->getNodeNeighbors(i, numNeighbors); morphNodeInfo[i].initialize(firstCoord, i, &allNodeAttributes[i], neighbors, numNeighbors); // // If fiducial sphere ratios should be used // if (useFiducialSphereRatios) { const float myRatio = fiducialSphereRatios[i]; // // Scale neighbor distances by David's magic formula // for (int j = 0; j < morphNodeInfo[i].numNeighbors; j++) { const int neigh = morphNodeInfo[i].neighbors[j]; const float neighRatio = fiducialSphereRatios[neigh]; morphNodeInfo[i].neighborDistance[j] = inverseDistortionFraction + (sphereFiducialDistortionFraction * ((myRatio + neighRatio) * 0.5) * morphNodeInfo[i].neighborDistance[j]); } } } } /** * set the nodes that should be morphred. */ void BrainModelSurfaceMorphing::setNodesThatShouldBeMorphed(const std::vector& nodesThatShouldBeMorphedIn, const float noMorphStepSizeIn) { allNodesBeingMorphed = true; const int num = static_cast(nodesThatShouldBeMorphedIn.size()); for (int i = 0; i < numberOfNodes; i++) { nodeShouldBeMorphed[i] = false; if (i < num) { nodeShouldBeMorphed[i] = nodesThatShouldBeMorphedIn[i]; } if (nodeShouldBeMorphed[i] == false) { allNodesBeingMorphed = false; } } noMorphNeighborStepSize = noMorphStepSizeIn; } /** * set the fiducial sphere distortion corrections. */ void BrainModelSurfaceMorphing::setFiducialSphereDistortionCorrections( const std::vector& fiducialSphereRatiosIn, const float sphereFiducialDistortionFractionIn) { fiducialSphereRatios = fiducialSphereRatiosIn; sphereFiducialDistortionFraction = sphereFiducialDistortionFractionIn; } //-------------------------------------------------------------------------------- /** * Constructor. */ BrainModelSurfaceMorphing::NeighborInformation::NeighborInformation() { numNeighbors = 0; neighbors = NULL; neighborDistance = NULL; angle1 = NULL; angle2 = NULL; } /** * Destructor. */ BrainModelSurfaceMorphing::NeighborInformation::~NeighborInformation() { if (neighbors != NULL) { delete neighbors; } if (neighborDistance != NULL) { delete neighborDistance; } if (angle1 != NULL) { delete angle1; } if (angle2 != NULL) { delete angle2; } } /** * Initialize neighbor information */ void BrainModelSurfaceMorphing::NeighborInformation::initialize(const float* coords, const int nodeNumberIn, const BrainSetNodeAttribute* nodeAttribute, const int* neighborsIn, const int numNeighborsIn) { // // Index of this node // nodeNumber = nodeNumberIn; // // Set this nodes interior flag // classification = nodeAttribute->getClassification(); // // Allocate items to number of neighbors // numNeighbors = numNeighborsIn; if (numNeighbors > 0) { neighbors = new int[numNeighbors]; for (int i = 0; i < numNeighbors; i++) { neighbors[i] = neighborsIn[i]; } neighborDistance = new float[numNeighbors]; angle1 = new float[numNeighbors]; angle2 = new float[numNeighbors]; const float* myCoord = &coords[nodeNumber * 3]; if (numNeighbors > 1) { // // Compute distances and angles to neighbors // for (int i = 0; i < numNeighbors; i++) { // // length to neighbor // neighborDistance[i] = MathUtilities::distance3D(myCoord, &coords[neighbors[i] * 3]); // // indices for next and previous neighbors // int nextIndex = i + 1; if (nextIndex >= numNeighbors) nextIndex = 0; // // Coordinates of current and previous neighbor // const float* currNeighborCoord = &coords[neighbors[i] * 3]; const float* nextNeighborCoord = &coords[neighbors[nextIndex] * 3]; // // Compute angles // if (classification == BrainSetNodeAttribute::CLASSIFICATION_TYPE_CORNER) { // // Only compute for first neighbor // if (i == 0) { angle1[0] = MathUtilities::angle(myCoord, currNeighborCoord, nextNeighborCoord); angle2[0] = MathUtilities::angle(currNeighborCoord, nextNeighborCoord, myCoord); angle1[1] = 0.0; angle2[1] = 0.0; } } else { // // Angle at current neighbor // angle1[i] = MathUtilities::angle(myCoord, currNeighborCoord, nextNeighborCoord); // // Angle at next neighbor // angle2[i] = MathUtilities::angle(currNeighborCoord, nextNeighborCoord, myCoord); } } if (DebugControl::getDebugOn()) { if (nodeNumber == DebugControl::getDebugNodeNumber()) { std::cout << "\nNode Number : " << nodeNumber << std::endl; for (int i = 0; i < numNeighbors; i++) { std::cout << "Neighbor[" << i << "] " << neighbors[i] << " angle1 (radians, degrees): " << angle1[i] << " " << angle1[i] * MathUtilities::radiansToDegrees() << std::endl << " angle2 (radians, degrees): " << angle2[i] << " " << angle2[i] * MathUtilities::radiansToDegrees() << std::endl; } } } } } } /** * Initialize neighbor information */ void BrainModelSurfaceMorphing::NeighborInformation::resetForces() { totalForce[0] = 0.0; totalForce[1] = 0.0; totalForce[2] = 0.0; linearForce[0] = 0.0; linearForce[1] = 0.0; linearForce[2] = 0.0; angularForce[0] = 0.0; angularForce[1] = 0.0; angularForce[2] = 0.0; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceMetricTwoSampleTTest.h0000664000175000017500000001232611572067322027373 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_SHAPE_TWO_SAMPLE_H__ #define __BRAIN_MODEL_SURFACE_SHAPE_TWO_SAMPLE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainModelSurfaceMetricFindClustersBase.h" class BrainModelSurface; class MetricFile; class QTextStream; /// find significant clusters in surface shape files using a two sampled T-Test class BrainModelSurfaceMetricTwoSampleTTest : public BrainModelSurfaceMetricFindClustersBase { public: /// data transform mode enum DATA_TRANSFORM_MODE { /// no transformation of data DATA_TRANSFORM_NONE, /// Wilcoxon Rank Sum input data then two-sample T-Test DATA_TRANSFORM_WILCOXON_RANK_SUM_THEN_TWO_SAMPLE_T_TEST }; /// variance mode enum VARIANCE_MODE { /// use Donna's sigma VARIANCE_MODE_SIGMA, /// use pooled variance VARIANCE_MODE_POOLED, /// use unpooled variance VARIANCE_MODE_UNPOOLED }; // constructor BrainModelSurfaceMetricTwoSampleTTest(BrainSet* bs, const DATA_TRANSFORM_MODE dataTransformModeIn, const VARIANCE_MODE varianceModeIn, const QString& shapeFileANameIn, const QString& shapeFileBNameIn, const QString& fiducialCoordFileNameIn, const QString& openTopoFileNameIn, const QString& distortionShapeFileNameIn, const QString& tMapFileNameIn, const QString& shuffledTMapFileNameIn, const QString& clustersPaintFileNameIn, const QString& clustersMetricFileNameIn, const QString& reportFileNameIn, const int distortionShapeFileColumnIn, const int iterationsIn, const float negativeThreshIn, const float positiveThreshIn, const float pValueIn, const int tVarianceSmoothingIterationsIn, const float tVarianceSmoothingStrengthIn, const bool doTMapDOF, const bool doTMapPValue, const int numberOfThreadsIn); // destructor ~BrainModelSurfaceMetricTwoSampleTTest(); protected: /// must be implemented by subclasses void executeClusterSearch() throw (BrainModelAlgorithmException); // free memory void cleanUp(); // create donna's sigma t-map MetricFile* createDonnasSigmaTMap(const MetricFile& mfA, const MetricFile& mfB, const bool addMeanValues) throw (BrainModelAlgorithmException); // create donna's shuffled sigma t-map MetricFile* createDonnasShuffledSigmaTMap(const MetricFile& mfA, const MetricFile& mfB) throw (BrainModelAlgorithmException); // finish donna's sigma processing void finishDonnasSigmaTMap(MetricFile& tMapFile, MetricFile& shuffledTMapFile) throw (BrainModelAlgorithmException); // transform the input data into rank-sum data void transformToRankSum(MetricFile& fileA, MetricFile& fileB) throw (BrainModelAlgorithmException); /// name of shape file A QString shapeFileAName; /// name of shape file B QString shapeFileBName; /// iterations for shuffled T-Map int iterations; /// data transform mode DATA_TRANSFORM_MODE dataTransformMode; /// the variance mode VARIANCE_MODE varianceMode; }; #endif // __BRAIN_MODEL_SURFACE_SHAPE_TWO_SAMPLE_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceMetricTwoSampleTTest.cxx0000664000175000017500000006515311572067322027754 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "BrainModelSurface.h" #include "BrainModelSurfaceMetricTwoSampleTTest.h" #include "BrainSet.h" #include "CoordinateFile.h" #include "DateAndTime.h" #include "DebugControl.h" #include "FileUtilities.h" #include "PaintFile.h" #include "MetricFile.h" #include "StatisticDataGroup.h" #include "StatisticMeanAndDeviation.h" #include "StatisticRankTransformation.h" #include "TopologyFile.h" /** * constructor. */ BrainModelSurfaceMetricTwoSampleTTest::BrainModelSurfaceMetricTwoSampleTTest( BrainSet* bs, const DATA_TRANSFORM_MODE dataTransformModeIn, const VARIANCE_MODE varianceModeIn, const QString& shapeFileANameIn, const QString& shapeFileBNameIn, const QString& fiducialCoordFileNameIn, const QString& openTopoFileNameIn, const QString& areaCorrectionShapeFileNameIn, const QString& tMapFileNameIn, const QString& shuffledTMapFileNameIn, const QString& clustersPaintFileNameIn, const QString& clustersMetricFileNameIn, const QString& reportFileNameIn, const int areaCorrectionShapeFileColumnIn, const int iterationsIn, const float negativeThreshIn, const float positiveThreshIn, const float pValueIn, const int tVarianceSmoothingIterationsIn, const float tVarianceSmoothingStrengthIn, const bool doTMapDOFIn, const bool doTMapPValueIn, const int numberOfThreadsIn) : BrainModelSurfaceMetricFindClustersBase(bs, fiducialCoordFileNameIn, openTopoFileNameIn, areaCorrectionShapeFileNameIn, tMapFileNameIn, shuffledTMapFileNameIn, clustersPaintFileNameIn, clustersMetricFileNameIn, reportFileNameIn, areaCorrectionShapeFileColumnIn, negativeThreshIn, positiveThreshIn, pValueIn, tVarianceSmoothingIterationsIn, tVarianceSmoothingStrengthIn, doTMapDOFIn, doTMapPValueIn, numberOfThreadsIn) { dataTransformMode = dataTransformModeIn; varianceMode = varianceModeIn; shapeFileAName = shapeFileANameIn; shapeFileBName = shapeFileBNameIn; iterations = iterationsIn; } /** * destructor. */ BrainModelSurfaceMetricTwoSampleTTest::~BrainModelSurfaceMetricTwoSampleTTest() { cleanUp(); } /** * execute the algorithm. */ void BrainModelSurfaceMetricTwoSampleTTest::executeClusterSearch() throw (BrainModelAlgorithmException) { // // Steps in algorithm // enum { ALG_STEP_CHECKING_INPUT, ALG_STEP_TMAP, ALG_STEP_SHUFFLED_TMAP, ALG_STEP_FINDING_CLUSTERS_T_MAP, ALG_STEP_FINDING_CLUSTERS_SHUFFLE_T_MAP, ALG_NUM_STEPS }; // // Update progress // QString title; switch (dataTransformMode) { case DATA_TRANSFORM_NONE: title = "Two Sample T-Test"; break; case DATA_TRANSFORM_WILCOXON_RANK_SUM_THEN_TWO_SAMPLE_T_TEST: title = "Wilcoxon Rank-Sum Applied to Input Data"; break; } bool pooledVarianceFlag = false; switch (varianceMode) { case VARIANCE_MODE_SIGMA: title += " donna's sigma"; break; case VARIANCE_MODE_POOLED: pooledVarianceFlag = true; title += " pooled variance"; break; case VARIANCE_MODE_UNPOOLED: title += " unpooled variance"; break; } createProgressDialog(title, ALG_NUM_STEPS, "sifClustDialog"); updateProgressDialog("Verifying Input", ALG_STEP_CHECKING_INPUT, ALG_NUM_STEPS); // // check iterations // if (iterations < 0) { throw BrainModelAlgorithmException("Iterations must be positive."); } // // Read the surface shape A file // MetricFile ssfA; try { ssfA.readFile(shapeFileAName); } catch (FileException &e) { std::ostringstream str; str << "Unable to read surface shape file A: " << FileUtilities::basename(shapeFileAName).toAscii().constData(); throw BrainModelAlgorithmException(str.str().c_str()); } // // Read the surface shape B file // MetricFile ssfB; try { ssfB.readFile(shapeFileBName); } catch (FileException &e) { std::ostringstream str; str << "Unable to read surface shape file B: " << FileUtilities::basename(shapeFileBName).toAscii().constData(); throw BrainModelAlgorithmException(str.str().c_str()); } // // Number of nodes in surface // const int numberOfNodes = bms->getNumberOfNodes(); // // Check file compatibilities // if (numberOfNodes != ssfA.getNumberOfNodes()) { throw BrainModelAlgorithmException("First shape file has different number of nodes" "than the coordinate file."); } if (numberOfNodes != ssfB.getNumberOfNodes()) { throw BrainModelAlgorithmException("Second shape file has different number of nodes" "than the coordinate file."); } if (numberOfNodes != areaCorrectionShapeFile->getNumberOfNodes()) { throw BrainModelAlgorithmException("Area correction shape file has different number of nodes" "than the coordinate file."); } // // data transform mode specific operations // switch (dataTransformMode) { case DATA_TRANSFORM_NONE: break; case DATA_TRANSFORM_WILCOXON_RANK_SUM_THEN_TWO_SAMPLE_T_TEST: // // Transform the input data into rank-sum data // transformToRankSum(ssfA, ssfB); break; } // // Update progress // updateProgressDialog("Doing T-Map", ALG_STEP_TMAP, ALG_NUM_STEPS); int tMapColumn = 2; switch (varianceMode) { case VARIANCE_MODE_SIGMA: tMapColumn = 0; statisticalMapShapeFile = createDonnasSigmaTMap(ssfA, ssfB, true); break; case VARIANCE_MODE_POOLED: // NOTE: Same processing for pooled and unpooled case VARIANCE_MODE_UNPOOLED: // // Create T-Map // tMapColumn = 2; try { statisticalMapShapeFile = MetricFile::computeStatisticalTMap(&ssfA, &ssfB, brain->getTopologyFile(0), tVarianceSmoothingIterations, tVarianceSmoothingStrength, pooledVarianceFlag, 0.05, false, doStatisticalMapDOF, doStatisticalMapPValue); } catch (FileException& e) { std::ostringstream str; str << "T-Map failure: " << e.whatQString().toAscii().constData(); cleanUp(); throw BrainModelAlgorithmException(str.str().c_str()); } break; } // // Write T-Map file // try { statisticalMapShapeFile->writeFile(statisticalMapFileName); } catch (FileException& e) { std::ostringstream str; str << "Unable to write T-Map: " << FileUtilities::basename(statisticalMapFileName).toAscii().constData(); cleanUp(); throw BrainModelAlgorithmException(str.str().c_str()); } // // Update progress // updateProgressDialog("Doing Shuffled T-Map", ALG_STEP_SHUFFLED_TMAP, ALG_NUM_STEPS); switch (varianceMode) { case VARIANCE_MODE_SIGMA: tMapColumn = 0; // // Create the shuffled sigma t-map // shuffleStatisticalMapShapeFile = createDonnasShuffledSigmaTMap(ssfA, ssfB); // // Determine sigma for each node and apply to both t-map and shuffled t-map // finishDonnasSigmaTMap(*statisticalMapShapeFile, *shuffleStatisticalMapShapeFile); // // Write T-Map file again since it was changed when applying sigma // try { statisticalMapShapeFile->writeFile(statisticalMapFileName); } catch (FileException& e) { std::ostringstream str; str << "Unable to write T-Map: " << FileUtilities::basename(statisticalMapFileName).toAscii().constData(); cleanUp(); throw BrainModelAlgorithmException(str.str().c_str()); } break; case VARIANCE_MODE_POOLED: // NOTE: same processing for pooled and unpooled case VARIANCE_MODE_UNPOOLED: { // // Combine input shape for shuffled T-Map // MetricFile allShape = ssfA; allShape.append(ssfB); // // Do shuffled T-Map // try { shuffleStatisticalMapShapeFile = allShape.computeStatisticalShuffledTMap(iterations, ssfA.getNumberOfColumns(), brain->getTopologyFile(0), tVarianceSmoothingIterations, tVarianceSmoothingStrength, pooledVarianceFlag); } catch (FileException& e) { std::ostringstream str; str << "Shuffled T-Map failure: " << e.whatQString().toAscii().constData(); cleanUp(); throw BrainModelAlgorithmException(str.str().c_str()); } }; break; } // // Write Shuffled T-Map file // try { shuffleStatisticalMapShapeFile->writeFile(shuffledStatisticalMapFileName); } catch (FileException& e) { std::ostringstream str; str << "Unable to write Shuffled T-Map: " << FileUtilities::basename(shuffledStatisticalMapFileName).toAscii().constData(); cleanUp(); throw BrainModelAlgorithmException(str.str().c_str()); } // // Update progress // updateProgressDialog("Finding clusters in T-Map", ALG_STEP_FINDING_CLUSTERS_T_MAP, ALG_NUM_STEPS); // // find the clusters in T-Map // std::vector tMapClusters; findClusters(statisticalMapShapeFile, tMapClusters, "Finding Clusters in T-Map", tMapColumn, false); // // Update progress // updateProgressDialog("Finding Clusters in Shuffled T-Map", ALG_STEP_FINDING_CLUSTERS_SHUFFLE_T_MAP, ALG_NUM_STEPS); // // find the clusters in Shuffled T-Map // Note: Only use largest cluster from each column // std::vector shuffleTMapClusters; findClusters(shuffleStatisticalMapShapeFile, shuffleTMapClusters, "Finding Clusters in Shuffled T-Map", -1, true); // // Set pValue for shuffled T-Map // setRandomizedClusterPValues(*shuffleStatisticalMapShapeFile, shuffleTMapClusters); // // Find area of the "P-Value" cluster in the shuffled T-Map // float significantCorrectedArea = std::numeric_limits::max(); int pValueClusterIndex = -1; if (shuffleTMapClusters.empty() == false) { pValueClusterIndex = std::min(static_cast(pValue * iterations) - 1, static_cast(shuffleTMapClusters.size())); pValueClusterIndex = std::max(pValueClusterIndex, 0); } if (pValueClusterIndex >= 0) { significantCorrectedArea = shuffleTMapClusters[pValueClusterIndex].areaCorrected; } // // Find P-Value for significant clusters in T-Map // for (unsigned int i = 0; i < tMapClusters.size(); i++) { Cluster& tMapCluster = tMapClusters[i]; int cnt = shuffleTMapClusters.size() - 1; if (shuffleTMapClusters.empty() == false) { if (tMapCluster.areaCorrected > shuffleTMapClusters[0].areaCorrected) { cnt = 1; } else { for (unsigned int j = 0; j < shuffleTMapClusters.size() - 1; j++) { if ((tMapCluster.areaCorrected < shuffleTMapClusters[j].areaCorrected) && (tMapCluster.areaCorrected >= shuffleTMapClusters[j+1].areaCorrected)) { cnt = j + 2; } } } } cnt = std::min(cnt, iterations); tMapCluster.pValue = static_cast(cnt) / static_cast(iterations); } // // So only do column 3 in T-Map when searching for T-Map clusters // // // For each T-Map that has area corrected that exceeds significant area // Find its rank in shuffled tmap // P-value = rank / iterations // // Option for paint file to show the clusters // // Open the report file // QFile reportFile(reportFileName); if (reportFile.open(QIODevice::WriteOnly) == false) { std::ostringstream str; str << "Unable to open report file for writing: " << FileUtilities::basename(reportFileName).toAscii().constData(); cleanUp(); throw BrainModelAlgorithmException(str.str().c_str()); } // // Create the text stream // QTextStream reportStream(&reportFile); // // Show area and thresholds // reportStream << "Type of T-Test: " << title << "\n"; reportStream << "Date/Time: " << DateAndTime::getDateAndTimeAsString() << "\n"; //QDateTime::currentDateTime().toString("MMM d, yyyy hh:mm:ss") << "\n"; reportStream << "Shape File A: " << shapeFileAName << "\n"; reportStream << "Shape File B: " << shapeFileBName << "\n"; reportStream << "Fiducial Coord File: " << fiducialCoordFileName << "\n"; reportStream << "Open Topo File: " << openTopoFileName << "\n"; if ((areaCorrectionShapeFile != NULL) || (areaCorrectionShapeFileColumn >= 0)) { reportStream << "Area Correct File: " << areaCorrectionShapeFileName << "\n"; reportStream << "Area Correct Column: " << areaCorrectionShapeFile->getColumnName(areaCorrectionShapeFileColumn) << "\n"; } reportStream << "Negative Threshold: " << negativeThresh << "\n"; reportStream << "Positive Threshold: " << positiveThresh << "\n"; reportStream << "Iterations: " << iterations << "\n"; reportStream << "P-Value: " << pValue << "\n"; reportStream << "Significant Area: " << significantCorrectedArea << "\n"; reportStream << "\n"; // // Add significant clusters to report file // reportStream << "Shuffled TMap" << "\n"; reportStream << "-------------" << "\n"; printClusters(reportStream, shuffleTMapClusters, significantCorrectedArea); reportStream << "\n\n\n"; reportStream << "TMap" << "\n"; reportStream << "----" << "\n"; printClusters(reportStream, tMapClusters, significantCorrectedArea); reportStream << "\n\n\n"; // // Add all clusters to report file // reportStream << "Shuffled TMap" << "\n"; reportStream << "-------------" << "\n"; printClusters(reportStream, shuffleTMapClusters); reportStream << "\n\n\n"; reportStream << "TMap" << "\n"; reportStream << "----" << "\n"; printClusters(reportStream, tMapClusters); // // Close the report file // reportFile.close(); // // Do the paint file // createClustersPaintFile(tMapClusters, significantCorrectedArea, numberOfNodes); // // Do the clusters metric file // createClustersMetricFile(tMapClusters, tMapColumn, numberOfNodes); // // Do cluster reports // createMetricShapeClustersReportFile(tMapClusters, shapeFileAName); createMetricShapeClustersReportFile(tMapClusters, shapeFileBName); } /** * finish donna's sigma processing. */ void BrainModelSurfaceMetricTwoSampleTTest::finishDonnasSigmaTMap(MetricFile& tMapFile, MetricFile& shuffledTMapFile) throw (BrainModelAlgorithmException) { const int numNodes = shuffledTMapFile.getNumberOfNodes(); const int numColumns = shuffledTMapFile.getNumberOfColumns(); if (numColumns <= 0) { return; } // // Compute the deviation for nodes in shuffled sigma t-map // float* data = new float[numColumns]; StatisticDataGroup sdg(data, numColumns, StatisticDataGroup::DATA_STORAGE_MODE_POINT); for (int i = 0; i < numNodes; i++) { // // Get the data for a node in the shuffled file // for (int j = 0; j < numColumns; j++) { data[j] = shuffledTMapFile.getValue(i, j); } // // compute statistics, note "sdg" maintains pointer to "data[]" // StatisticMeanAndDeviation smd; smd.addDataGroup(&sdg); try { smd.execute(); } catch (StatisticException& e) { throw BrainModelAlgorithmException(e); } // // divide t-map and shuffled t-map by sigma // const float sigma = smd.getStandardDeviation(); if (sigma != 0) { tMapFile.setValue(i, 0, (tMapFile.getValue(i, 0) / sigma)); for (int j = 0; j < numColumns; j++) { shuffledTMapFile.setValue(i, j, (shuffledTMapFile.getValue(i, j) / sigma)); } } } delete[] data; } /** * create donna's shuffled sigma t-map. */ MetricFile* BrainModelSurfaceMetricTwoSampleTTest::createDonnasShuffledSigmaTMap( const MetricFile& mfA, const MetricFile& mfB) throw (BrainModelAlgorithmException) { MetricFile* mf = NULL; try { const int numberOfNodes = bms->getNumberOfNodes(); // // Copy the input metric files and shuffle them and create output files for shuffling // std::vector shuffleFilesIn; shuffleFilesIn.push_back((MetricFile*)&mfA); shuffleFilesIn.push_back((MetricFile*)&mfB); MetricFile ma = mfA; MetricFile mb = mfB; std::vector shuffleFilesOut; shuffleFilesOut.push_back(&ma); shuffleFilesOut.push_back(&mb); // // Create the shuffled metric file // mf = new MetricFile; mf->setNumberOfNodesAndColumns(numberOfNodes, iterations); for (int j = 0; j < iterations; j++) { // // Set the name of the column // mf->setColumnName(j, "Iteration " + QString::number(j + 1)); // // Shuffle the input files into the output files // MetricFile::shuffle(shuffleFilesIn, shuffleFilesOut); // // Create the Sigma T-Map // MetricFile* mfT = createDonnasSigmaTMap(ma, mb, false); // // Add Sigma T-Map to shuffled file // for (int i = 0; i < numberOfNodes; i++) { mf->setValue(i, j, mfT->getValue(i, 0)); } delete mfT; } } catch (FileException& e) { if (mf != NULL) { delete mf; mf = NULL; } throw BrainModelAlgorithmException(e); } return mf; } /** * create donna's sigma t-map. */ MetricFile* BrainModelSurfaceMetricTwoSampleTTest::createDonnasSigmaTMap(const MetricFile& mfA, const MetricFile& mfB, const bool addMeanValues) throw (BrainModelAlgorithmException) { const int numberOfNodes = bms->getNumberOfNodes(); // // Create the metric file // MetricFile* mf = new MetricFile; int numberOfColumns = 0; const int tSigmaColumn = numberOfColumns++; int meanGroupAColumn = -1; int meanGroupBColumn = -1; if (addMeanValues) { meanGroupAColumn = numberOfColumns++; meanGroupBColumn = numberOfColumns++; } mf->setNumberOfNodesAndColumns(numberOfNodes, numberOfColumns); if (addMeanValues) { mf->setColumnName(meanGroupAColumn, "Group A Mean"); mf->setColumnName(meanGroupBColumn, "Group B Mean"); } mf->setColumnName(tSigmaColumn, "T-Sigma"); mf->setFileComment("T-Sigma Map from " + FileUtilities::basename(shapeFileAName) + " and " + FileUtilities::basename(shapeFileBName)); // // Compute A's, B's mean, and abs difference // const int numColumnsA = mfA.getNumberOfColumns(); const int numColumnsB = mfB.getNumberOfColumns(); for (int i = 0; i < numberOfNodes; i++) { double sumA = 0.0; for (int j = 0; j < numColumnsA; j++) { sumA += mfA.getValue(i, j); } const float meanA = sumA / static_cast(numColumnsA); double sumB = 0.0; for (int j = 0; j < numColumnsB; j++) { sumB += mfB.getValue(i, j); } const float meanB = sumB / static_cast(numColumnsB); if (addMeanValues) { mf->setValue(i, meanGroupAColumn, meanA); mf->setValue(i, meanGroupBColumn, meanB); } mf->setValue(i, tSigmaColumn, std::fabs(meanA - meanB)); } return mf; } /** * transform the input data into rank-sum data. */ void BrainModelSurfaceMetricTwoSampleTTest::transformToRankSum(MetricFile& fileA, MetricFile& fileB) throw (BrainModelAlgorithmException) { const int numColA = fileA.getNumberOfColumns(); const int numColB = fileB.getNumberOfColumns(); const int numNodes = fileA.getNumberOfNodes(); float* dataA = NULL; if (numColA > 0) { dataA = new float[numColA]; } float* dataB = NULL; if (numColB > 0) { dataB = new float[numColB]; } // // Convert data to rank-sum indices // for (int i = 0; i < numNodes; i++) { // // Get the data for each node // fileA.getAllColumnValuesForNode(i, dataA); fileB.getAllColumnValuesForNode(i, dataB); // // Transform the data // StatisticRankTransformation rt; StatisticDataGroup dga(dataA, numColA, StatisticDataGroup::DATA_STORAGE_MODE_POINT); StatisticDataGroup dgb(dataB, numColB, StatisticDataGroup::DATA_STORAGE_MODE_POINT); rt.addDataGroup(&dga); rt.addDataGroup(&dgb); try { rt.execute(); if (rt.getNumberOfOutputDataGroups() != 2) { const QString msg = "StatisticRankTransform failed. Number of data output data groups should be 2 but is " + QString::number(rt.getNumberOfOutputDataGroups()); throw BrainModelAlgorithmException(msg); } } catch (StatisticException& e) { throw BrainModelAlgorithmException(e); } // // set the data for each node // const StatisticDataGroup* sdgRankA = rt.getOutputDataGroupContainingRankValues(0); fileA.setAllColumnValuesForNode(i, sdgRankA->getPointerToData()); const StatisticDataGroup* sdgRankB = rt.getOutputDataGroupContainingRankValues(1); fileB.setAllColumnValuesForNode(i, sdgRankB->getPointerToData()); } // // Free memory // if (dataA != NULL) { delete[] dataA; dataA = NULL; } if (dataB != NULL) { delete[] dataB; dataB = NULL; } // // write rank-sum files if debugging is on // if (DebugControl::getDebugOn()) { try { fileA.writeFile("rank_sum_A.metric"); fileB.writeFile("rank_sum_B.metric"); } catch (FileException&) { } } } /** * Free memory. */ void BrainModelSurfaceMetricTwoSampleTTest::cleanUp() { BrainModelSurfaceMetricFindClustersBase::cleanUp(); } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceMetricTwinComparison.h0000664000175000017500000000367611572067322027460 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_METRIC_TWIN_COMPARISON_H__ #define __BRAIN_MODEL_SURFACE_METRIC_TWIN_COMPARISON_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelAlgorithm.h" /// class for generating comparisons between twin subjects class BrainModelSurfaceMetricTwinComparison : public BrainModelAlgorithm { public: // constructor BrainModelSurfaceMetricTwinComparison(BrainSet* bs, const QString& metricShapeTwinAFileNameIn, const QString& metricShapeTwinBFileNameIn, const QString& outputMetricShapeFileNameIn); // destructor ~BrainModelSurfaceMetricTwinComparison(); // execute the algorithm void execute() throw (BrainModelAlgorithmException); protected: /// file name QString metricShapeTwinAFileName; /// file name QString metricShapeTwinBFileName; /// file name QString outputMetricShapeFileName; }; #endif // __BRAIN_MODEL_SURFACE_METRIC_TWIN_COMPARISON_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceMetricTwinComparison.cxx0000664000175000017500000002123011572067322030015 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelSurfaceMetricTwinComparison.h" #include "DebugControl.h" #include "FileUtilities.h" #include "MetricFile.h" /** * constructor. */ BrainModelSurfaceMetricTwinComparison::BrainModelSurfaceMetricTwinComparison( BrainSet* bs, const QString& metricShapeTwinAFileNameIn, const QString& metricShapeTwinBFileNameIn, const QString& outputMetricShapeFileNameIn) : BrainModelAlgorithm(bs) { metricShapeTwinAFileName = metricShapeTwinAFileNameIn; metricShapeTwinBFileName = metricShapeTwinBFileNameIn; outputMetricShapeFileName = outputMetricShapeFileNameIn; } /** * destructor. */ BrainModelSurfaceMetricTwinComparison::~BrainModelSurfaceMetricTwinComparison() { } /** * execute the algorithm. */ void BrainModelSurfaceMetricTwinComparison::execute() throw (BrainModelAlgorithmException) { // // Make sure file names are specified // if (metricShapeTwinAFileName.isEmpty()) { throw BrainModelAlgorithmException("Twin File A filename is empty."); } if (metricShapeTwinBFileName.isEmpty()) { throw BrainModelAlgorithmException("Twin File B filename is empty."); } if (outputMetricShapeFileName.isEmpty()) { throw BrainModelAlgorithmException("Output filename is empty."); } // // Read in the input files // MetricFile metricFileA, metricFileB; try { metricFileA.readFile(metricShapeTwinAFileName); metricFileB.readFile(metricShapeTwinBFileName); } catch (FileException& e) { throw BrainModelAlgorithmException(e); } // // Examine data files // const int numNodes = metricFileA.getNumberOfNodes(); const int numCols = metricFileA.getNumberOfColumns(); if ((numNodes <= 0) || (numCols <= 0)) { const QString msg = FileUtilities::basename(metricShapeTwinAFileName) + " contains no data."; throw BrainModelAlgorithmException(msg); } if (numNodes != metricFileB.getNumberOfNodes()) { throw BrainModelAlgorithmException("The input files contain a different number of nodes."); } if (numCols != metricFileB.getNumberOfColumns()) { throw BrainModelAlgorithmException("The input files contain a different number of columns."); } // // Create the output metric file // int numOutputColumns = 0; const int twinVarianceColumn = numOutputColumns++; const int nonTwinVarianceColumn = numOutputColumns++; const int differenceColumn = numOutputColumns++; MetricFile outputMetricFile; outputMetricFile.setNumberOfNodesAndColumns(numNodes, numOutputColumns); // // Set column names // outputMetricFile.setColumnName(twinVarianceColumn, "Twin Expected Variance"); outputMetricFile.setColumnName(nonTwinVarianceColumn, "Non-Twin Expected Variance"); outputMetricFile.setColumnName(differenceColumn, "Twin minus Non-Twin"); // // Do twin differences // for (int i = 0; i < numNodes; i++) { // // Compute "expected variance" at each node // double nodeSum = 0.0; for (int j = 0; j < numCols; j++) { if ((i == 0) && DebugControl::getDebugOn()) { std::cout << "Twin comparison File A Column " << j << ", File B Column " << j << std::endl; } const float valA = metricFileA.getValue(i, j); const float valB = metricFileB.getValue(i, j); const float d = valA - valB; const float d2 = d * d; nodeSum += d2; } const float expectedVariance = nodeSum / static_cast(numCols); outputMetricFile.setValue(i, twinVarianceColumn, expectedVariance); } // // Do Non-Twin pairs by pairing each twin to everyone but its twin // Sort of a "upper triangular matrix" comparison to avoid multiple comparisons // for (int i = 0; i < numNodes; i++) { // // Non-Twin comparisons within file A // double nodeSum = 0.0; int comparisonCount = 0; for (int j = 0; j < (numCols - 1); j++) { const float valA1 = metricFileA.getValue(i, j); for (int k = j + 1; k < numCols; k++) { // // Compare to subject in file A // const float valA2 = metricFileA.getValue(i, k); const float da = valA1 - valA2; const float da2 = da * da; nodeSum += da2; comparisonCount++; if ((i == 0) && DebugControl::getDebugOn()) { std::cout << "Non-Twin comparison File A Column " << j << ", File A Column " << k << std::endl; } } // for K } // for J // // Non-Twin comparisons between files A & B // for (int j = 0; j < numCols; j++) { const float valA = metricFileA.getValue(i, j); for (int k = 0; k < numCols; k++) { // // Only do non-twins // if (j != k) { // // Compare to subject in file B // const float valB = metricFileB.getValue(i, k); const float db = valA - valB; const float db2 = db * db; nodeSum += db2; comparisonCount++; if ((i == 0) && DebugControl::getDebugOn()) { std::cout << "Non-Twin comparison File A Column " << j << ", File B Column " << k << std::endl; } } } // for K } // for J // // Non-Twin comparisons withing file B // for (int j = 0; j < (numCols - 1); j++) { const float valB1 = metricFileB.getValue(i, j); for (int k = j + 1; k < numCols; k++) { // // Compare to subject in file B // const float valB2 = metricFileB.getValue(i, k); const float db = valB1 - valB2; const float db2 = db * db; nodeSum += db2; comparisonCount++; if ((i == 0) && DebugControl::getDebugOn()) { std::cout << "Non-Twin comparison File B Column " << j << ", File B Column " << k << std::endl; } } // for K } // for J const float expectedVariance = nodeSum / static_cast(comparisonCount); outputMetricFile.setValue(i, nonTwinVarianceColumn, expectedVariance); if (i == 0) { std::cout << "Non-Twin Comparision count: " << comparisonCount << std::endl; } } // for I try { // // Compute differences in the twin vs non-twin expected variances // outputMetricFile.performBinaryOperation(MetricFile::BINARY_OPERATION_SUBTRACT, twinVarianceColumn, nonTwinVarianceColumn, differenceColumn, outputMetricFile.getColumnName(differenceColumn)); // // Set color mapping // outputMetricFile.setColorMappingToColumnMinMax(); // // Write the metric file // outputMetricFile.writeFile(outputMetricShapeFileName); } catch (FileException& e) { throw BrainModelAlgorithmException(e); } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceMetricSmoothingAll.h0000664000175000017500000001617511572067322027102 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_METRIC_SMOOTHING_ALL_H__ #define __BRAIN_MODEL_SURFACE_METRIC_SMOOTHING_ALL_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelAlgorithm.h" class BrainModelSurface; class CoordinateFile; class GaussianComputation; class MetricFile; /// Class for smoothing metric data class BrainModelSurfaceMetricSmoothingAll : public BrainModelAlgorithm { public: /// smoothing algorithms enum SMOOTH_ALGORITHM { SMOOTH_ALGORITHM_AVERAGE_NEIGHBORS, SMOOTH_ALGORITHM_DILATE, SMOOTH_ALGORITHM_FULL_WIDTH_HALF_MAXIMUM, SMOOTH_ALGORITHM_SURFACE_NORMAL_GAUSSIAN, SMOOTH_ALGORITHM_GEODESIC_GAUSSIAN, SMOOTH_ALGORITHM_WEIGHTED_AVERAGE_NEIGHBORS, SMOOTH_ALGORITHM_NONE }; /// Constructor to smooth a single column BrainModelSurfaceMetricSmoothingAll(BrainSet* bs, BrainModelSurface* fiducialSurfaceIn, BrainModelSurface* gaussianSphericalSurfaceIn, MetricFile* metricFileIn, const SMOOTH_ALGORITHM algorithmIn, const int columnIn, const int outputColumnIn, const QString& outputColumnNameIn, const float strengthIn, const int iterationsIn, const float desiredFullWidthHalfMaximumIn, const float gaussNormBelowCutoffIn, const float gaussNormAboveCutoffIn, const float gaussSigmaNormIn, const float gaussSigmaTangIn, const float gaussTangentCutoffIn, const float geodesicGaussSigmaIn); // = 2.0f); /// Constructor to smooth all columns BrainModelSurfaceMetricSmoothingAll(BrainSet* bs, BrainModelSurface* fiducialSurfaceIn, BrainModelSurface* gaussianSphericalSurfaceIn, MetricFile* metricFileIn, const SMOOTH_ALGORITHM algorithmIn, const float strengthIn, const int iterationsIn, const float desiredFullWidthHalfMaximumIn, const float gaussNormBelowCutoffIn, const float gaussNormAboveCutoffIn, const float gaussSigmaNormIn, const float gaussSigmaTangIn, const float gaussTangentCutoffIn, const float geodesicGaussSigmaIn, // = 2.0f); const bool runParallelFlagIn); /// Destructor ~BrainModelSurfaceMetricSmoothingAll(); /// execute the algorithm void execute() throw (BrainModelAlgorithmException); /// get the full width half maximum smoothing results description QString getFullWidthHalfMaximumSmoothingResultsDescription() const { return fullWidthHalfMaximumSmoothingResultsDescription; } protected: // smooth a column in the metric file void smoothSingleColumn(const QString& columnDescription, const int inputColumn, const int outputColumn, const GaussianComputation& gauss); /// determine neighbors for each node void determineNeighbors(); /// class for neighbor information class NeighborInfo { public: /// Constructor NeighborInfo(const CoordinateFile* cf, const int myNodeNumber, const std::vector& neighborsIn, const float maxDistanceCutoff, const std::vector* distances = NULL); /// Destructor ~NeighborInfo(); /// the neighbors std::vector neighbors; /// distance to neighbor std::vector distanceToNeighbor; /// number of neighbors int numNeighbors; }; /// neighbors for each node std::vector nodeNeighbors; /// number of nodes int numberOfNodes; /// fiducial surface used for smoothing BrainModelSurface* fiducialSurface; /// spherical surface used for overall distance cutoff when gaussian smoothing BrainModelSurface* gaussianSphericalSurface; /// the metric file MetricFile* metricFile; /// the smoothing algorithm SMOOTH_ALGORITHM algorithm; /// column number for input to smoothing int column; /// column number for output of smoothing int outputColumn; /// name of output column QString outputColumnName; /// smoothing strength float strength; /// number of smoothing iterations int iterations; /// gaussian norm below cutoff float gaussNormBelowCutoff; /// gaussian norma above cutoff float gaussNormAboveCutoff; /// gaussian sigma norm float gaussSigmaNorm; /// gaussian sigma tang float gaussSigmaTang; /// gaussian tangent cutoff float gaussTangentCutoff; /// desired full width half maximum float desiredFullWidthHalfMaximum; /// parameter for geodesic gaussian float geodesicGaussSigma; /// full width half maximum smoothing results description QString fullWidthHalfMaximumSmoothingResultsDescription; bool smoothAllColumnsFlag; bool runParallelFlag; }; #endif // __BRAIN_MODEL_SURFACE_METRIC_SMOOTHING_ALL_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceMetricSmoothingAll.cxx0000664000175000017500000007264011572067322027454 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "BrainModelSurface.h" #include "BrainModelSurfaceMetricFullWidthHalfMaximum.h" #include "BrainModelSurfaceMetricSmoothingAll.h" #include "DebugControl.h" #include "GaussianComputation.h" #include "GeodesicHelper.h" #include "MetricFile.h" #include "StringUtilities.h" #include "TopologyFile.h" #include "TopologyHelper.h" #ifdef _OPENMP #include #endif /** * Constructor to smooth all columns. */ BrainModelSurfaceMetricSmoothingAll::BrainModelSurfaceMetricSmoothingAll( BrainSet* bs, BrainModelSurface* fiducialSurfaceIn, BrainModelSurface* gaussianSphericalSurfaceIn, MetricFile* metricFileIn, const SMOOTH_ALGORITHM algorithmIn, const float strengthIn, const int iterationsIn, const float desiredFullWidthHalfMaximumIn, const float gaussNormBelowCutoffIn, const float gaussNormAboveCutoffIn, const float gaussSigmaNormIn, const float gaussSigmaTangIn, const float gaussTangentCutoffIn, const float geodesicGaussSigmaIn, const bool runParallelFlagIn) // = 2.0f); : BrainModelAlgorithm(bs) { fiducialSurface = fiducialSurfaceIn; gaussianSphericalSurface = gaussianSphericalSurfaceIn; if (gaussianSphericalSurface == NULL) { gaussianSphericalSurface = fiducialSurface; } metricFile = metricFileIn; algorithm = algorithmIn; column = -1; outputColumn = -1; outputColumnName = ""; strength = strengthIn; iterations = iterationsIn; desiredFullWidthHalfMaximum = desiredFullWidthHalfMaximumIn; gaussNormBelowCutoff = gaussNormBelowCutoffIn; gaussNormAboveCutoff = gaussNormAboveCutoffIn; gaussSigmaNorm = gaussSigmaNormIn; gaussSigmaTang = gaussSigmaTangIn; gaussTangentCutoff = gaussTangentCutoffIn; geodesicGaussSigma = geodesicGaussSigmaIn; this->smoothAllColumnsFlag = true; this->runParallelFlag = runParallelFlagIn; } /** * Constructor to smooth a single column. */ BrainModelSurfaceMetricSmoothingAll::BrainModelSurfaceMetricSmoothingAll( BrainSet* bs, BrainModelSurface* fiducialSurfaceIn, BrainModelSurface* gaussianSphericalSurfaceIn, MetricFile* metricFileIn, const SMOOTH_ALGORITHM algorithmIn, const int columnIn, const int outputColumnIn, const QString& outputColumnNameIn, const float strengthIn, const int iterationsIn, const float desiredFullWidthHalfMaximumIn, const float gaussNormBelowCutoffIn, const float gaussNormAboveCutoffIn, const float gaussSigmaNormIn, const float gaussSigmaTangIn, const float gaussTangentCutoffIn, const float geodesicGaussSigmaIn) : BrainModelAlgorithm(bs) { fiducialSurface = fiducialSurfaceIn; gaussianSphericalSurface = gaussianSphericalSurfaceIn; if (gaussianSphericalSurface == NULL) { gaussianSphericalSurface = fiducialSurface; } metricFile = metricFileIn; algorithm = algorithmIn; column = columnIn; outputColumn = outputColumnIn; outputColumnName = outputColumnNameIn; strength = strengthIn; iterations = iterationsIn; desiredFullWidthHalfMaximum = desiredFullWidthHalfMaximumIn; gaussNormBelowCutoff = gaussNormBelowCutoffIn; gaussNormAboveCutoff = gaussNormAboveCutoffIn; gaussSigmaNorm = gaussSigmaNormIn; gaussSigmaTang = gaussSigmaTangIn; gaussTangentCutoff = gaussTangentCutoffIn; geodesicGaussSigma = geodesicGaussSigmaIn; this->smoothAllColumnsFlag = false; this->runParallelFlag = false; } /** * Destructor. */ BrainModelSurfaceMetricSmoothingAll::~BrainModelSurfaceMetricSmoothingAll() { } /** * execute the algorithm. */ void BrainModelSurfaceMetricSmoothingAll::execute() throw (BrainModelAlgorithmException) { fullWidthHalfMaximumSmoothingResultsDescription = ""; numberOfNodes = fiducialSurface->getNumberOfNodes(); // // Check for valid input column // if ((metricFile->getNumberOfColumns() <= 0) || (metricFile->getNumberOfNodes() <= 0)) { throw BrainModelAlgorithmException("Metric file contains no data."); } // // Create a new column if needed. // if (this->smoothAllColumnsFlag == false) { if ((column < 0) || (column >= metricFile->getNumberOfColumns())) { throw BrainModelAlgorithmException("Input metric column is invalid."); } if ((outputColumn < 0) || (outputColumn >= metricFile->getNumberOfColumns())){ metricFile->addColumns(1); outputColumn = metricFile->getNumberOfColumns() - 1; } metricFile->setColumnName(outputColumn, outputColumnName); } // // Used if gaussian smoothing is being performed // GaussianComputation gauss(gaussNormBelowCutoff, gaussNormAboveCutoff, gaussSigmaNorm, gaussSigmaTang, gaussTangentCutoff); // // Determine the neighbors for each node // determineNeighbors(); // // Add comments describing smoothing // QString smoothComment; switch (algorithm) { case SMOOTH_ALGORITHM_NONE: smoothComment.append("Invalid smoothing algorithm: \n"); break; case SMOOTH_ALGORITHM_AVERAGE_NEIGHBORS: smoothComment.append("Average Neighbors Smoothing: \n"); break; case SMOOTH_ALGORITHM_DILATE: smoothComment.append("Dilation"); break; case SMOOTH_ALGORITHM_FULL_WIDTH_HALF_MAXIMUM: break; case SMOOTH_ALGORITHM_SURFACE_NORMAL_GAUSSIAN: smoothComment.append("Gaussian (Surface Normal) Smoothing: \n"); smoothComment.append(" Norm Below Cutoff: "); smoothComment.append(StringUtilities::fromNumber(gaussNormBelowCutoff)); smoothComment.append("\n"); smoothComment.append(" Norm Above Cutoff: "); smoothComment.append(StringUtilities::fromNumber(gaussNormAboveCutoff)); smoothComment.append("\n"); smoothComment.append(" Sigma Norm: "); smoothComment.append(StringUtilities::fromNumber(gaussSigmaNorm)); smoothComment.append("\n"); smoothComment.append(" Sigma Tang: "); smoothComment.append(StringUtilities::fromNumber(gaussSigmaTang)); smoothComment.append("\n"); smoothComment.append(" Tangend Cutoff: "); smoothComment.append(StringUtilities::fromNumber(gaussTangentCutoff)); smoothComment.append("\n"); break; case SMOOTH_ALGORITHM_WEIGHTED_AVERAGE_NEIGHBORS: smoothComment.append("Weighted Average Neighbors Smoothing: \n"); break; case SMOOTH_ALGORITHM_GEODESIC_GAUSSIAN: smoothComment.append("Geodesic Gaussian Smoothing: \n"); smoothComment.append(" Sigma: "); smoothComment.append(StringUtilities::fromNumber(geodesicGaussSigma)); smoothComment.append("\n"); break; } smoothComment.append(" Stength/Iterations: "); smoothComment.append(StringUtilities::fromNumber(strength)); smoothComment.append(" "); smoothComment.append(StringUtilities::fromNumber(iterations)); smoothComment.append("\n"); bool debugOpenMpFlag = false; #ifdef _OPENMP if (debugOpenMpFlag) { std::cout << "OPEN MP SUPPORTED" << std::endl; if (this->runParallelFlag) { std::cout << "OpenMP Maximum Threads: " << omp_get_max_threads() << std::endl; } } #else this->runParallelFlag = false; #endif if (this->smoothAllColumnsFlag) { int numColumns = this->metricFile->getNumberOfColumns(); if (this->runParallelFlag) { #pragma omp parallel for for (int i = 0; i < numColumns; i++) { if (debugOpenMpFlag) { std::cout << "Start Smoothing Column: " << i << std::endl; } this->smoothSingleColumn(smoothComment, i, i, gauss); if (debugOpenMpFlag) { std::cout << "Finished Smoothing Column: " << i << std::endl; } } } else { for (int i = 0; i < numColumns; i++) { if (debugOpenMpFlag) { std::cout << "Smoothing Column " << i << std::endl; } this->smoothSingleColumn(smoothComment, i, i, gauss); } } } else { this->smoothSingleColumn(smoothComment, column, outputColumn, gauss); } } /** * smooth a column in the metric file. */ void BrainModelSurfaceMetricSmoothingAll::smoothSingleColumn(const QString& columnDescription, const int inputColumn, const int outputColumn, const GaussianComputation& gauss) { const CoordinateFile* coordinateFile = fiducialSurface->getCoordinateFile(); // // Inverse of strength is applied to the node's current metric value // const float oneMinusStrength = 1.0 - strength; // // Allocate arrays for storing data of column being smoothed // int numberOfNodes = metricFile->getNumberOfNodes(); float* inputValues = new float[numberOfNodes]; float* outputValues = new float[numberOfNodes]; // // Full width half maximum measurements // float fullWidthHalfMaximum = 0.0; int fullWidthHalfMaximumNumberOfIterations = 0; metricFile->getColumnForAllNodes(inputColumn, inputValues); if (inputColumn != outputColumn) { metricFile->setColumnForAllNodes(outputColumn, inputValues); } int smoothColumn = outputColumn; // // Prepate for smoothing // for (int iter = 0; iter < iterations; iter++) { bool stopSmoothingFlag = false; switch (algorithm) { case SMOOTH_ALGORITHM_AVERAGE_NEIGHBORS: break; case SMOOTH_ALGORITHM_DILATE: break; case SMOOTH_ALGORITHM_FULL_WIDTH_HALF_MAXIMUM: { // // Determine Full Width Half Maximum // BrainModelSurfaceMetricFullWidthHalfMaximum fwhm(brainSet, fiducialSurface, metricFile, smoothColumn); fwhm.execute(); fullWidthHalfMaximum = fwhm.getFullWidthHalfMaximum(); if (DebugControl::getDebugOn()) { std::cout << "Smoothing Full Width Half Maximum before iteration " << iter << " is " << fullWidthHalfMaximum << std::endl; } fullWidthHalfMaximumSmoothingResultsDescription += ("Before Iteration " + QString::number(iter) + " Estimated FWHM: " + QString::number(fullWidthHalfMaximum, 'f', 3) + "\n"); // // if FWHM achieved, stop smoothing // if (fullWidthHalfMaximum >= desiredFullWidthHalfMaximum) { stopSmoothingFlag = true; } } break; case SMOOTH_ALGORITHM_SURFACE_NORMAL_GAUSSIAN: case SMOOTH_ALGORITHM_WEIGHTED_AVERAGE_NEIGHBORS: case SMOOTH_ALGORITHM_GEODESIC_GAUSSIAN: case SMOOTH_ALGORITHM_NONE: break; } // // Should smoothing be stopped ??? // if (stopSmoothingFlag) { break; } // // load arrays for smoothing data // //std::vector columnValues(numberOfNodes); //getColumnForAllNodes(outputColumn, columnValues); metricFile->getColumnForAllNodes(smoothColumn, inputValues); // // smooth all of the nodes // for (int i = 0; i < numberOfNodes; i++) { // // copy input to output in event this node is not smoothed // outputValues[i] = inputValues[i]; const NeighborInfo& neighInfo = nodeNeighbors[i]; // // Does this node have neighbors // if (neighInfo.numNeighbors > 0) { float neighborSum = 0.0; bool setOutputValueFlag = true; bool dilateModeFlag = false; switch (algorithm) { case SMOOTH_ALGORITHM_NONE: break; case SMOOTH_ALGORITHM_AVERAGE_NEIGHBORS: { // // smooth metric data for this node // for (int j = 0; j < neighInfo.numNeighbors; j++) { // // Note: outputColumn has output from last iteration of smoothing // neighborSum += inputValues[neighInfo.neighbors[j]]; } neighborSum = neighborSum / static_cast(neighInfo.numNeighbors); }; break; case SMOOTH_ALGORITHM_DILATE: { if (inputValues[i] != 0.0) { // // Do not process nodes with non-zero values // setOutputValueFlag = false; } else { // // Average of non-zero neighbors // int numNonZeroNeighbors = 0; for (int j = 0; j < neighInfo.numNeighbors; j++) { // // Note: outputColumn has output from last iteration of smoothing // float neighborValue = inputValues[neighInfo.neighbors[j]]; if (neighborValue != 0.0) { neighborSum += neighborValue; numNonZeroNeighbors++; } } if (numNonZeroNeighbors > 0) { neighborSum = neighborSum / static_cast(numNonZeroNeighbors); dilateModeFlag = true; } } }; break; case SMOOTH_ALGORITHM_FULL_WIDTH_HALF_MAXIMUM: { // // smooth metric data for this node // for (int j = 0; j < neighInfo.numNeighbors; j++) { // // Note: outputColumn has output from last iteration of smoothing // neighborSum += inputValues[neighInfo.neighbors[j]]; } //neighborSum = neighborSum / static_cast(neighInfo.numNeighbors); // // Ignore strength so set output value here // FWHM paper does average of node and its neighbors // neighborSum += inputValues[i]; outputValues[i] = neighborSum / static_cast(neighInfo.numNeighbors + 1); setOutputValueFlag = false; }; break; case SMOOTH_ALGORITHM_SURFACE_NORMAL_GAUSSIAN: { // // Get neighbor information for gaussian smoothing // std::vector points; for (int j = 0; j < neighInfo.numNeighbors; j++) { const int neigh = neighInfo.neighbors[j]; points.push_back(GaussianComputation::Point3D( coordinateFile->getCoordinate(neigh), inputValues[neigh])); } if (DebugControl::getDebugOn()) { if (iter == 0) { if (DebugControl::getDebugNodeNumber() == i) { std::set sortedNeighbors; for (int j = 0; j < neighInfo.numNeighbors; j++) { sortedNeighbors.insert(neighInfo.neighbors[j]); } std::cout << "Neighbors (" << neighInfo.numNeighbors << ") of " << i << ": "; for (std::set::iterator it = sortedNeighbors.begin(); it != sortedNeighbors.end(); it++) { std::cout << *it << " "; } std::cout << std::endl; } } } // // Evaluate the gaussian for the node and its neighbors // neighborSum = gauss.evaluate(coordinateFile->getCoordinate(i), fiducialSurface->getNormal(i), points); } break; case SMOOTH_ALGORITHM_WEIGHTED_AVERAGE_NEIGHBORS: { // // Distances to each neighbor // std::vector neighborDistance(neighInfo.numNeighbors); float totalDistance = 0.0; for (int j = 0; j < neighInfo.numNeighbors; j++) { totalDistance += neighInfo.distanceToNeighbor[j]; } if (totalDistance == 0.0) { totalDistance = 1.0; } // // compute neighbor weighted average // std::vector neighborWeights(neighInfo.numNeighbors); float totalWeight = 0.0; for (int j = 0; j < neighInfo.numNeighbors; j++) { neighborWeights[j] = 1.0 - (neighInfo.distanceToNeighbor[j] / totalDistance); totalWeight += neighborWeights[j]; } if (totalWeight == 0.0) { totalWeight = 1.0; } // // compute neighbor weighted average // for (int j = 0; j < neighInfo.numNeighbors; j++) { const float weight = neighborWeights[j] / totalWeight; neighborSum += inputValues[neighInfo.neighbors[j]] * weight; } } break; case SMOOTH_ALGORITHM_GEODESIC_GAUSSIAN: { //distance to neighbor is geodesic, not euclidean, check determineNeighbors int j, end = neighInfo.numNeighbors; float totalWeight = 0.0f, weight, tempf; for (j = 0; j < end; ++j) {//weighted average, using gaussian of geodesic distance as weight tempf = neighInfo.distanceToNeighbor[j] / geodesicGaussSigma; /* * Performance of std::exp(float) takes five times as long as * std::exp(double) on 64-bit Linux. */ double d = -tempf * tempf * 0.5f; weight = std::exp(d); //weight = std::exp(-tempf * tempf * 0.5f);//the gaussian function totalWeight += weight; neighborSum += weight * inputValues[neighInfo.neighbors[j]]; } neighborSum /= totalWeight; dilateModeFlag = true;//HACK: makes it use the gaussian computation, with no extra precedence for center node //this is equivalent to strength = 1; oneMinusStrength = 0;, but with less computation //IF DILATE IS EVER CHANGED, MAKE SURE TO USE ONLY NEIGHBORSUM IF MODE IS GEODESIC_GAUSSIAN } break; } // // Apply smoothing to the node // if (setOutputValueFlag) { if (DebugControl::getDebugOn()) { if (DebugControl::getDebugNodeNumber() == i) { std::cout << "Smoothing node " << i << " iteration " << iter << " node neighbor sum " << neighborSum << std::endl; } } if (dilateModeFlag) { outputValues[i] = neighborSum;//WARNING: used for geodesic gaussian, if this is changed, make geogauss gives the same result (ignore strength) } else { outputValues[i] = (inputValues[i] * oneMinusStrength) + (neighborSum * strength); } } } } // // Copy the smoothed values to the output column // metricFile->setColumnForAllNodes(smoothColumn, outputValues); // // Keep track of iterations // fullWidthHalfMaximumNumberOfIterations++; } // for +iterations delete[] inputValues; delete[] outputValues; QString smoothComment(metricFile->getColumnComment(smoothColumn)); if (smoothComment.isEmpty() == false) { smoothComment.append("\n"); } if (algorithm == SMOOTH_ALGORITHM_FULL_WIDTH_HALF_MAXIMUM) { smoothComment.append("Full Width Half Maximum Algorithm: \n" " Desired Full Width Half Maximum: " + QString::number(desiredFullWidthHalfMaximum, 'f', 3) + "\n" + " Full Width Half Maximum achieved: " + QString::number(fullWidthHalfMaximum, 'f', 3) + "\n" + " Number of Iterations to achieve FWHM " + QString::number(fullWidthHalfMaximumNumberOfIterations) + "\n"); } smoothComment.append(columnDescription); metricFile->setColumnComment(smoothColumn, smoothComment); } /** * determine neighbors for each node. */ void BrainModelSurfaceMetricSmoothingAll::determineNeighbors() { // // Clear the neighbors // nodeNeighbors.clear(); // // Get the topology helper // const TopologyFile* topologyFile = fiducialSurface->getTopologyFile(); const TopologyHelper* topologyHelper = topologyFile->getTopologyHelper(false, true, false); // // Coordinate file and maximum distance cutoff // CoordinateFile* cf = fiducialSurface->getCoordinateFile(); GeodesicHelper* gh = NULL; float maxDistanceCutoff = std::numeric_limits::max(); float geoCutoff = 4.0f * geodesicGaussSigma; std::vector* distance = NULL; switch (algorithm) { case SMOOTH_ALGORITHM_AVERAGE_NEIGHBORS: break; case SMOOTH_ALGORITHM_DILATE: break; case SMOOTH_ALGORITHM_FULL_WIDTH_HALF_MAXIMUM: break; case SMOOTH_ALGORITHM_WEIGHTED_AVERAGE_NEIGHBORS: break; case SMOOTH_ALGORITHM_SURFACE_NORMAL_GAUSSIAN: cf = gaussianSphericalSurface->getCoordinateFile(); maxDistanceCutoff = std::max(std::max(gaussNormBelowCutoff, gaussNormAboveCutoff), gaussTangentCutoff); break; case SMOOTH_ALGORITHM_GEODESIC_GAUSSIAN: cf = fiducialSurface->getCoordinateFile(); gh = new GeodesicHelper(cf, topologyFile); distance = new std::vector; break; case SMOOTH_ALGORITHM_NONE: break; } // // Loop through the nodes // //QTime timer; //timer.start(); for (int i = 0; i < numberOfNodes; i++) { std::vector neighbors; switch (algorithm) { case SMOOTH_ALGORITHM_AVERAGE_NEIGHBORS: case SMOOTH_ALGORITHM_DILATE: case SMOOTH_ALGORITHM_FULL_WIDTH_HALF_MAXIMUM: case SMOOTH_ALGORITHM_WEIGHTED_AVERAGE_NEIGHBORS: { // // Get the neighbors for the node // topologyHelper->getNodeNeighbors(i, neighbors); } break; case SMOOTH_ALGORITHM_SURFACE_NORMAL_GAUSSIAN: { // // Get the neighbors for the node to the specified depth // topologyHelper->getNodeNeighborsToDepth(i, 5, neighbors); } break; case SMOOTH_ALGORITHM_GEODESIC_GAUSSIAN: gh->getNodesToGeoDist(i, geoCutoff, neighbors, *distance, true); if (neighbors.size() < 6) {//in case a really small kernel is specified topologyHelper->getNodeNeighbors(i, neighbors); neighbors.push_back(i);//for geogauss, we want the center node in the list gh->getGeoToTheseNodes(i, neighbors, *distance, true); } break; case SMOOTH_ALGORITHM_NONE: break; } // // add to all neighbors // nodeNeighbors.push_back(NeighborInfo(cf, i, neighbors, maxDistanceCutoff, distance)); } if (gh) delete gh; if (distance) delete distance; //const float elapsedTime = timer.elapsed() * 0.001; //if (DebugControl::getDebugOn()) { // std::cout << "Time to determine neighbors: " << elapsedTime << " seconds." << std::endl; //} } //*************************************************************************************** /** * Constructor. */ BrainModelSurfaceMetricSmoothingAll::NeighborInfo::NeighborInfo(const CoordinateFile* cf, const int myNodeNumber, const std::vector& neighborsIn, const float maxDistanceCutoff, const std::vector* distances) { const int numNeighborsIn = static_cast(neighborsIn.size()); if (distances) {//use STL vector copy operator, don't need to exclude anything distanceToNeighbor = *distances; neighbors = neighborsIn; } else { for (int i = 0; i < numNeighborsIn; i++) { const int node = neighborsIn[i]; const float dist = cf->getDistanceBetweenCoordinates(myNodeNumber, node); if (dist <= maxDistanceCutoff) { neighbors.push_back(node); distanceToNeighbor.push_back(dist); } } } numNeighbors = static_cast(neighbors.size()); } /** * Destructor. */ BrainModelSurfaceMetricSmoothingAll::NeighborInfo::~NeighborInfo() { } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceMetricSmoothing.h0000664000175000017500000001307711572067322026447 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_METRIC_SMOOTHING_H__ #define __BRAIN_MODEL_SURFACE_METRIC_SMOOTHING_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelAlgorithm.h" class BrainModelSurface; class CoordinateFile; class MetricFile; /// Class for smoothing metric data class BrainModelSurfaceMetricSmoothing : public BrainModelAlgorithm { public: /// smoothing algorithms enum SMOOTH_ALGORITHM { SMOOTH_ALGORITHM_AVERAGE_NEIGHBORS, SMOOTH_ALGORITHM_DILATE, SMOOTH_ALGORITHM_FULL_WIDTH_HALF_MAXIMUM, SMOOTH_ALGORITHM_SURFACE_NORMAL_GAUSSIAN, SMOOTH_ALGORITHM_GEODESIC_GAUSSIAN, SMOOTH_ALGORITHM_WEIGHTED_AVERAGE_NEIGHBORS, SMOOTH_ALGORITHM_NONE }; /// Constructor BrainModelSurfaceMetricSmoothing(BrainSet* bs, BrainModelSurface* fiducialSurfaceIn, BrainModelSurface* gaussianSphericalSurfaceIn, MetricFile* metricFileIn, const SMOOTH_ALGORITHM algorithmIn, const int columnIn, const int outputColumnIn, const QString& outputColumnNameIn, const float strengthIn, const int iterationsIn, const float desiredFullWidthHalfMaximumIn, const float gaussNormBelowCutoffIn, const float gaussNormAboveCutoffIn, const float gaussSigmaNormIn, const float gaussSigmaTangIn, const float gaussTangentCutoffIn, const float geodesicGaussSigmaIn); // = 2.0f); /// Destructor ~BrainModelSurfaceMetricSmoothing(); /// execute the algorithm void execute() throw (BrainModelAlgorithmException); /// get the full width half maximum smoothing results description QString getFullWidthHalfMaximumSmoothingResultsDescription() const { return fullWidthHalfMaximumSmoothingResultsDescription; } protected: /// determine neighbors for each node void determineNeighbors(); /// class for neighbor information class NeighborInfo { public: /// Constructor NeighborInfo(const CoordinateFile* cf, const int myNodeNumber, const std::vector& neighborsIn, const float maxDistanceCutoff, const std::vector* distances = NULL); /// Destructor ~NeighborInfo(); /// the neighbors std::vector neighbors; /// distance to neighbor std::vector distanceToNeighbor; /// number of neighbors int numNeighbors; }; /// neighbors for each node std::vector nodeNeighbors; /// number of nodes int numberOfNodes; /// fiducial surface used for smoothing BrainModelSurface* fiducialSurface; /// spherical surface used for overall distance cutoff when gaussian smoothing BrainModelSurface* gaussianSphericalSurface; /// the metric file MetricFile* metricFile; /// the smoothing algorithm SMOOTH_ALGORITHM algorithm; /// column number for input to smoothing int column; /// column number for output of smoothing int outputColumn; /// name of output column QString outputColumnName; /// smoothing strength float strength; /// number of smoothing iterations int iterations; /// gaussian norm below cutoff float gaussNormBelowCutoff; /// gaussian norma above cutoff float gaussNormAboveCutoff; /// gaussian sigma norm float gaussSigmaNorm; /// gaussian sigma tang float gaussSigmaTang; /// gaussian tangent cutoff float gaussTangentCutoff; /// desired full width half maximum float desiredFullWidthHalfMaximum; /// parameter for geodesic gaussian float geodesicGaussSigma; /// full width half maximum smoothing results description QString fullWidthHalfMaximumSmoothingResultsDescription; }; #endif // __BRAIN_MODEL_SURFACE_METRIC_SMOOTHING_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceMetricSmoothing.cxx0000664000175000017500000006237711572067322027031 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include "BrainModelSurface.h" #include "BrainModelSurfaceMetricFullWidthHalfMaximum.h" #include "BrainModelSurfaceMetricSmoothing.h" #include "DebugControl.h" #include "GaussianComputation.h" #include "GeodesicHelper.h" #include "MetricFile.h" #include "StringUtilities.h" #include "TopologyFile.h" #include "TopologyHelper.h" /** * Constructor. */ BrainModelSurfaceMetricSmoothing::BrainModelSurfaceMetricSmoothing( BrainSet* bs, BrainModelSurface* fiducialSurfaceIn, BrainModelSurface* gaussianSphericalSurfaceIn, MetricFile* metricFileIn, const SMOOTH_ALGORITHM algorithmIn, const int columnIn, const int outputColumnIn, const QString& outputColumnNameIn, const float strengthIn, const int iterationsIn, const float desiredFullWidthHalfMaximumIn, const float gaussNormBelowCutoffIn, const float gaussNormAboveCutoffIn, const float gaussSigmaNormIn, const float gaussSigmaTangIn, const float gaussTangentCutoffIn, const float geodesicGaussSigmaIn) : BrainModelAlgorithm(bs) { fiducialSurface = fiducialSurfaceIn; gaussianSphericalSurface = gaussianSphericalSurfaceIn; if (gaussianSphericalSurface == NULL) { gaussianSphericalSurface = fiducialSurface; } metricFile = metricFileIn; algorithm = algorithmIn; column = columnIn; outputColumn = outputColumnIn; outputColumnName = outputColumnNameIn; strength = strengthIn; iterations = iterationsIn; desiredFullWidthHalfMaximum = desiredFullWidthHalfMaximumIn; gaussNormBelowCutoff = gaussNormBelowCutoffIn; gaussNormAboveCutoff = gaussNormAboveCutoffIn; gaussSigmaNorm = gaussSigmaNormIn; gaussSigmaTang = gaussSigmaTangIn; gaussTangentCutoff = gaussTangentCutoffIn; geodesicGaussSigma = geodesicGaussSigmaIn; } /** * Destructor. */ BrainModelSurfaceMetricSmoothing::~BrainModelSurfaceMetricSmoothing() { } /** * execute the algorithm. */ void BrainModelSurfaceMetricSmoothing::execute() throw (BrainModelAlgorithmException) { fullWidthHalfMaximumSmoothingResultsDescription = ""; numberOfNodes = fiducialSurface->getNumberOfNodes(); // // Check for valid input column // if ((metricFile->getNumberOfColumns() <= 0) || (metricFile->getNumberOfNodes() <= 0)) { throw BrainModelAlgorithmException("Metric file contains no data."); } if ((column < 0) || (column >= metricFile->getNumberOfColumns())) { throw BrainModelAlgorithmException("Input metric column is invalid."); } // // Inverse of strength is applied to the node's current metric value // const float oneMinusStrength = 1.0 - strength; // // Create a new column if needed. // if ((outputColumn < 0) || (outputColumn >= metricFile->getNumberOfColumns())){ metricFile->addColumns(1); outputColumn = metricFile->getNumberOfColumns() - 1; } metricFile->setColumnName(outputColumn, outputColumnName); // // Copy the input column to the output column // if (column != outputColumn) { std::vector values; metricFile->getColumnForAllNodes(column, values); metricFile->setColumnForAllNodes(outputColumn, values); } // // column now being smoothed // const int smoothColumn = outputColumn; // // Allocate arrays for storing data of column being smoothed // float* inputValues = new float[numberOfNodes]; float* outputValues = new float[numberOfNodes]; // // Coordinates of all nodes // const CoordinateFile* coordinateFile = fiducialSurface->getCoordinateFile(); // // Used if gaussian smoothing is being performed // GaussianComputation gauss(gaussNormBelowCutoff, gaussNormAboveCutoff, gaussSigmaNorm, gaussSigmaTang, gaussTangentCutoff); // // Determine the neighbors for each node // determineNeighbors(); // // Full width half maximum measurements // float fullWidthHalfMaximum = 0.0; int fullWidthHalfMaximumNumberOfIterations = 0; // // Prepate for smoothing // for (int iter = 0; iter < iterations; iter++) { bool stopSmoothingFlag = false; switch (algorithm) { case SMOOTH_ALGORITHM_AVERAGE_NEIGHBORS: break; case SMOOTH_ALGORITHM_DILATE: break; case SMOOTH_ALGORITHM_FULL_WIDTH_HALF_MAXIMUM: { // // Determine Full Width Half Maximum // BrainModelSurfaceMetricFullWidthHalfMaximum fwhm(brainSet, fiducialSurface, metricFile, smoothColumn); fwhm.execute(); fullWidthHalfMaximum = fwhm.getFullWidthHalfMaximum(); if (DebugControl::getDebugOn()) { std::cout << "Smoothing Full Width Half Maximum before iteration " << iter << " is " << fullWidthHalfMaximum << std::endl; } fullWidthHalfMaximumSmoothingResultsDescription += ("Before Iteration " + QString::number(iter) + " Estimated FWHM: " + QString::number(fullWidthHalfMaximum, 'f', 3) + "\n"); // // if FWHM achieved, stop smoothing // if (fullWidthHalfMaximum >= desiredFullWidthHalfMaximum) { stopSmoothingFlag = true; } } break; case SMOOTH_ALGORITHM_SURFACE_NORMAL_GAUSSIAN: case SMOOTH_ALGORITHM_WEIGHTED_AVERAGE_NEIGHBORS: case SMOOTH_ALGORITHM_GEODESIC_GAUSSIAN: case SMOOTH_ALGORITHM_NONE: break; } // // Should smoothing be stopped ??? // if (stopSmoothingFlag) { break; } // // load arrays for smoothing data // //std::vector columnValues(numberOfNodes); //getColumnForAllNodes(outputColumn, columnValues); metricFile->getColumnForAllNodes(smoothColumn, inputValues); // // smooth all of the nodes // for (int i = 0; i < numberOfNodes; i++) { // // copy input to output in event this node is not smoothed // outputValues[i] = inputValues[i]; const NeighborInfo& neighInfo = nodeNeighbors[i]; // // Does this node have neighbors // if (neighInfo.numNeighbors > 0) { float neighborSum = 0.0; bool setOutputValueFlag = true; bool dilateModeFlag = false; switch (algorithm) { case SMOOTH_ALGORITHM_NONE: break; case SMOOTH_ALGORITHM_AVERAGE_NEIGHBORS: { // // smooth metric data for this node // for (int j = 0; j < neighInfo.numNeighbors; j++) { // // Note: outputColumn has output from last iteration of smoothing // neighborSum += inputValues[neighInfo.neighbors[j]]; } neighborSum = neighborSum / static_cast(neighInfo.numNeighbors); }; break; case SMOOTH_ALGORITHM_DILATE: { if (inputValues[i] != 0.0) { // // Do not process nodes with non-zero values // setOutputValueFlag = false; } else { // // Average of non-zero neighbors // int numNonZeroNeighbors = 0; for (int j = 0; j < neighInfo.numNeighbors; j++) { // // Note: outputColumn has output from last iteration of smoothing // float neighborValue = inputValues[neighInfo.neighbors[j]]; if (neighborValue != 0.0) { neighborSum += neighborValue; numNonZeroNeighbors++; } } if (numNonZeroNeighbors > 0) { neighborSum = neighborSum / static_cast(numNonZeroNeighbors); dilateModeFlag = true; } } }; break; case SMOOTH_ALGORITHM_FULL_WIDTH_HALF_MAXIMUM: { // // smooth metric data for this node // for (int j = 0; j < neighInfo.numNeighbors; j++) { // // Note: outputColumn has output from last iteration of smoothing // neighborSum += inputValues[neighInfo.neighbors[j]]; } //neighborSum = neighborSum / static_cast(neighInfo.numNeighbors); // // Ignore strength so set output value here // FWHM paper does average of node and its neighbors // neighborSum += inputValues[i]; outputValues[i] = neighborSum / static_cast(neighInfo.numNeighbors + 1); setOutputValueFlag = false; }; break; case SMOOTH_ALGORITHM_SURFACE_NORMAL_GAUSSIAN: { // // Get neighbor information for gaussian smoothing // std::vector points; for (int j = 0; j < neighInfo.numNeighbors; j++) { const int neigh = neighInfo.neighbors[j]; points.push_back(GaussianComputation::Point3D( coordinateFile->getCoordinate(neigh), inputValues[neigh])); } if (DebugControl::getDebugOn()) { if (iter == 0) { if (DebugControl::getDebugNodeNumber() == i) { std::set sortedNeighbors; for (int j = 0; j < neighInfo.numNeighbors; j++) { sortedNeighbors.insert(neighInfo.neighbors[j]); } std::cout << "Neighbors (" << neighInfo.numNeighbors << ") of " << i << ": "; for (std::set::iterator it = sortedNeighbors.begin(); it != sortedNeighbors.end(); it++) { std::cout << *it << " "; } std::cout << std::endl; } } } // // Evaluate the gaussian for the node and its neighbors // neighborSum = gauss.evaluate(coordinateFile->getCoordinate(i), fiducialSurface->getNormal(i), points); } break; case SMOOTH_ALGORITHM_WEIGHTED_AVERAGE_NEIGHBORS: { // // Distances to each neighbor // std::vector neighborDistance(neighInfo.numNeighbors); float totalDistance = 0.0; for (int j = 0; j < neighInfo.numNeighbors; j++) { totalDistance += neighInfo.distanceToNeighbor[j]; } if (totalDistance == 0.0) { totalDistance = 1.0; } // // compute neighbor weighted average // std::vector neighborWeights(neighInfo.numNeighbors); float totalWeight = 0.0; for (int j = 0; j < neighInfo.numNeighbors; j++) { neighborWeights[j] = 1.0 - (neighInfo.distanceToNeighbor[j] / totalDistance); totalWeight += neighborWeights[j]; } if (totalWeight == 0.0) { totalWeight = 1.0; } // // compute neighbor weighted average // for (int j = 0; j < neighInfo.numNeighbors; j++) { const float weight = neighborWeights[j] / totalWeight; neighborSum += inputValues[neighInfo.neighbors[j]] * weight; } } break; case SMOOTH_ALGORITHM_GEODESIC_GAUSSIAN: {//distance to neighbor is geodesic, not euclidean, check determineNeighbors int j, end = neighInfo.numNeighbors; float totalWeight = 0.0f, weight, tempf; for (j = 0; j < end; ++j) {//weighted average, using gaussian of geodesic distance as weight tempf = neighInfo.distanceToNeighbor[j] / geodesicGaussSigma; weight = std::exp(-tempf * tempf * 0.5f);//the gaussian function totalWeight += weight; neighborSum += weight * inputValues[neighInfo.neighbors[j]]; } neighborSum /= totalWeight; dilateModeFlag = true;//HACK: makes it use the gaussian computation, with no extra precedence for center node //this is equivalent to strength = 1; oneMinusStrength = 0;, but with less computation //IF DILATE IS EVER CHANGED, MAKE SURE TO USE ONLY NEIGHBORSUM IF MODE IS GEODESIC_GAUSSIAN } break; } // // Apply smoothing to the node // if (setOutputValueFlag) { if (DebugControl::getDebugOn()) { if (DebugControl::getDebugNodeNumber() == i) { std::cout << "Smoothing node " << i << " iteration " << iter << " node neighbor sum " << neighborSum << std::endl; } } if (dilateModeFlag) { outputValues[i] = neighborSum;//WARNING: used for geodesic gaussian, if this is changed, make geogauss gives the same result (ignore strength) } else { outputValues[i] = (inputValues[i] * oneMinusStrength) + (neighborSum * strength); } } } } // // Copy the smoothed values to the output column // metricFile->setColumnForAllNodes(smoothColumn, outputValues); // // Keep track of iterations // fullWidthHalfMaximumNumberOfIterations++; } // for +iterations // // Add comments describing smoothing // QString smoothComment(metricFile->getColumnComment(smoothColumn)); if (smoothComment.isEmpty() == false) { smoothComment.append("\n"); } switch (algorithm) { case SMOOTH_ALGORITHM_NONE: smoothComment.append("Invalid smoothing algorithm: \n"); break; case SMOOTH_ALGORITHM_AVERAGE_NEIGHBORS: smoothComment.append("Average Neighbors Smoothing: \n"); break; case SMOOTH_ALGORITHM_DILATE: smoothComment.append("Dilation"); break; case SMOOTH_ALGORITHM_FULL_WIDTH_HALF_MAXIMUM: smoothComment.append("Full Width Half Maximum Algorithm: \n" " Desired Full Width Half Maximum: " + QString::number(desiredFullWidthHalfMaximum, 'f', 3) + "\n" + " Full Width Half Maximum achieved: " + QString::number(fullWidthHalfMaximum, 'f', 3) + "\n" + " Number of Iterations to achieve FWHM " + QString::number(fullWidthHalfMaximumNumberOfIterations) + "\n"); break; case SMOOTH_ALGORITHM_SURFACE_NORMAL_GAUSSIAN: smoothComment.append("Gaussian (Surface Normal) Smoothing: \n"); smoothComment.append(" Norm Below Cutoff: "); smoothComment.append(StringUtilities::fromNumber(gaussNormBelowCutoff)); smoothComment.append("\n"); smoothComment.append(" Norm Above Cutoff: "); smoothComment.append(StringUtilities::fromNumber(gaussNormAboveCutoff)); smoothComment.append("\n"); smoothComment.append(" Sigma Norm: "); smoothComment.append(StringUtilities::fromNumber(gaussSigmaNorm)); smoothComment.append("\n"); smoothComment.append(" Sigma Tang: "); smoothComment.append(StringUtilities::fromNumber(gaussSigmaTang)); smoothComment.append("\n"); smoothComment.append(" Tangend Cutoff: "); smoothComment.append(StringUtilities::fromNumber(gaussTangentCutoff)); smoothComment.append("\n"); break; case SMOOTH_ALGORITHM_WEIGHTED_AVERAGE_NEIGHBORS: smoothComment.append("Weighted Average Neighbors Smoothing: \n"); break; case SMOOTH_ALGORITHM_GEODESIC_GAUSSIAN: smoothComment.append("Geodesic Gaussian Smoothing: \n"); smoothComment.append(" Sigma: "); smoothComment.append(StringUtilities::fromNumber(geodesicGaussSigma)); smoothComment.append("\n"); break; } smoothComment.append(" Stength/Iterations: "); smoothComment.append(StringUtilities::fromNumber(strength)); smoothComment.append(" "); smoothComment.append(StringUtilities::fromNumber(iterations)); smoothComment.append("\n"); metricFile->setColumnComment(smoothColumn, smoothComment); delete[] inputValues; delete[] outputValues; } /** * determine neighbors for each node. */ void BrainModelSurfaceMetricSmoothing::determineNeighbors() { // // Clear the neighbors // nodeNeighbors.clear(); // // Get the topology helper // const TopologyFile* topologyFile = fiducialSurface->getTopologyFile(); const TopologyHelper* topologyHelper = topologyFile->getTopologyHelper(false, true, false); // // Coordinate file and maximum distance cutoff // CoordinateFile* cf = fiducialSurface->getCoordinateFile(); GeodesicHelper* gh = NULL; float maxDistanceCutoff = std::numeric_limits::max(); float geoCutoff = 4.0f * geodesicGaussSigma; std::vector* distance = NULL; switch (algorithm) { case SMOOTH_ALGORITHM_AVERAGE_NEIGHBORS: break; case SMOOTH_ALGORITHM_DILATE: break; case SMOOTH_ALGORITHM_FULL_WIDTH_HALF_MAXIMUM: break; case SMOOTH_ALGORITHM_WEIGHTED_AVERAGE_NEIGHBORS: break; case SMOOTH_ALGORITHM_SURFACE_NORMAL_GAUSSIAN: cf = gaussianSphericalSurface->getCoordinateFile(); maxDistanceCutoff = std::max(std::max(gaussNormBelowCutoff, gaussNormAboveCutoff), gaussTangentCutoff); break; case SMOOTH_ALGORITHM_GEODESIC_GAUSSIAN: cf = fiducialSurface->getCoordinateFile(); gh = new GeodesicHelper(cf, topologyFile); distance = new std::vector; break; case SMOOTH_ALGORITHM_NONE: break; } // // Loop through the nodes // QTime timer; timer.start(); for (int i = 0; i < numberOfNodes; i++) { std::vector neighbors; switch (algorithm) { case SMOOTH_ALGORITHM_AVERAGE_NEIGHBORS: case SMOOTH_ALGORITHM_DILATE: case SMOOTH_ALGORITHM_FULL_WIDTH_HALF_MAXIMUM: case SMOOTH_ALGORITHM_WEIGHTED_AVERAGE_NEIGHBORS: { // // Get the neighbors for the node // topologyHelper->getNodeNeighbors(i, neighbors); } break; case SMOOTH_ALGORITHM_SURFACE_NORMAL_GAUSSIAN: { // // Get the neighbors for the node to the specified depth // topologyHelper->getNodeNeighborsToDepth(i, 5, neighbors); } break; case SMOOTH_ALGORITHM_GEODESIC_GAUSSIAN: gh->getNodesToGeoDist(i, geoCutoff, neighbors, *distance, true); if (neighbors.size() < 6) {//in case a really small kernel is specified topologyHelper->getNodeNeighbors(i, neighbors); neighbors.push_back(i);//for geogauss, we want the center node in the list gh->getGeoToTheseNodes(i, neighbors, *distance, true); } break; case SMOOTH_ALGORITHM_NONE: break; } // // add to all neighbors // nodeNeighbors.push_back(NeighborInfo(cf, i, neighbors, maxDistanceCutoff, distance)); } if (gh) delete gh; if (distance) delete distance; const float elapsedTime = timer.elapsed() * 0.001; if (DebugControl::getDebugOn()) { std::cout << "Time to determine neighbors: " << elapsedTime << " seconds." << std::endl; } } //*************************************************************************************** /** * Constructor. */ BrainModelSurfaceMetricSmoothing::NeighborInfo::NeighborInfo(const CoordinateFile* cf, const int myNodeNumber, const std::vector& neighborsIn, const float maxDistanceCutoff, const std::vector* distances) { const int numNeighborsIn = static_cast(neighborsIn.size()); if (distances) {//use STL vector copy operator, don't need to exclude anything distanceToNeighbor = *distances; neighbors = neighborsIn; } else { for (int i = 0; i < numNeighborsIn; i++) { const int node = neighborsIn[i]; const float dist = cf->getDistanceBetweenCoordinates(myNodeNumber, node); if (dist <= maxDistanceCutoff) { neighbors.push_back(node); distanceToNeighbor.push_back(dist); } } } numNeighbors = static_cast(neighbors.size()); } /** * Destructor. */ BrainModelSurfaceMetricSmoothing::NeighborInfo::~NeighborInfo() { } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceMetricOneAndPairedTTest.h0000664000175000017500000000733611572067322027756 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_ONE_SAMPLE_T_TEST_H #define __BRAIN_MODEL_SURFACE_ONE_SAMPLE_T_TEST_H /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurfaceMetricFindClustersBase.h" /// class for performing a one sample T-Test on a metric file class BrainModelSurfaceMetricOneAndPairedTTest : public BrainModelSurfaceMetricFindClustersBase { public: // // T-Test mode // enum T_TEST_MODE { T_TEST_MODE_ONE_SAMPLE, T_TEST_MODE_PAIRED }; // constructor BrainModelSurfaceMetricOneAndPairedTTest(BrainSet* bs, const T_TEST_MODE tTestModeIn, const std::vector& metricFileNamesIn, const QString& fiducialCoordFileNameIn, const QString& openTopoFileNameIn, const QString& areaCorrectionMetricFileNameIn, const QString& tMapFileNameIn, const QString& permutedTMapFileNameIn, const QString& clustersPaintFileNameIn, const QString& clustersMetricFileNameIn, const QString& reportFileNameIn, const int areaCorrectionMetricFileColumnIn, const float negativeThreshIn, const float positiveThreshIn, const float pValueIn, const int tVarianceSmoothingIterationsIn, const float tVarianceSmoothingStrengthIn, const int permutationIterationsIn, const float tTestConstantIn, const int numberOfThreadsIn); // destructor ~BrainModelSurfaceMetricOneAndPairedTTest(); protected: // execute the search virtual void executeClusterSearch() throw (BrainModelAlgorithmException); // free memory virtual void cleanUp(); // create the metric file for one-sample T-Test processing void oneSampleTTestProcessing(MetricFile& metricFileOut) throw (BrainModelAlgorithmException); // create the metric file for paired T-Test processing void pairedTTestProcessing(MetricFile& metricFileOut) throw (BrainModelAlgorithmException); /// name of input metric file std::vector metricFileNames; /// constant to perform T-Test against float tTestConstant; /// permutation interations int permutationIterations; /// t-test mode T_TEST_MODE tTestMode; }; #endif // __BRAIN_MODEL_SURFACE_ONE_SAMPLE_T_TEST_H caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceMetricOneAndPairedTTest.cxx0000664000175000017500000004237511572067322030333 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "BrainModelSurface.h" #include "BrainModelSurfaceMetricOneAndPairedTTest.h" #include "BrainSet.h" #include "CoordinateFile.h" #include "DateAndTime.h" #include "DebugControl.h" #include "FileUtilities.h" #include "PaintFile.h" #include "MetricFile.h" #include "TopologyFile.h" /** * constructor. */ BrainModelSurfaceMetricOneAndPairedTTest::BrainModelSurfaceMetricOneAndPairedTTest(BrainSet* bs, const T_TEST_MODE tTestModeIn, const std::vector& metricFileNamesIn, const QString& fiducialCoordFileNameIn, const QString& openTopoFileNameIn, const QString& areaCorrectionMetricFileNameIn, const QString& tMapFileNameIn, const QString& permutedTMapFileNameIn, const QString& clustersPaintFileNameIn, const QString& clustersMetricFileNameIn, const QString& reportFileNameIn, const int areaCorrectionMetricFileColumnIn, const float negativeThreshIn, const float positiveThreshIn, const float pValueIn, const int tVarianceSmoothingIterationsIn, const float tVarianceSmoothingStrengthIn, const int permutationIterationsIn, const float tTestConstantIn, const int numberOfThreadsIn) : BrainModelSurfaceMetricFindClustersBase(bs, fiducialCoordFileNameIn, openTopoFileNameIn, areaCorrectionMetricFileNameIn, tMapFileNameIn, permutedTMapFileNameIn, clustersPaintFileNameIn, clustersMetricFileNameIn, reportFileNameIn, areaCorrectionMetricFileColumnIn, negativeThreshIn, positiveThreshIn, pValueIn, tVarianceSmoothingIterationsIn, tVarianceSmoothingStrengthIn, false, false, numberOfThreadsIn) { tTestMode = tTestModeIn; metricFileNames = metricFileNamesIn; tTestConstant = tTestConstantIn; permutationIterations = permutationIterationsIn; } /** * destructor. */ BrainModelSurfaceMetricOneAndPairedTTest::~BrainModelSurfaceMetricOneAndPairedTTest() { } /** * must be implemented by subclasses. */ void BrainModelSurfaceMetricOneAndPairedTTest::executeClusterSearch() throw (BrainModelAlgorithmException) { // // Steps in algorithm // enum { ALG_STEP_CHECKING_INPUT, ALG_STEP_TMAP, ALG_STEP_PERMUTED_TMAP, ALG_STEP_FINDING_CLUSTERS_T_MAP, ALG_STEP_FINDING_CLUSTERS_PERMUTED_T_MAP, ALG_NUM_STEPS }; // // Update progress // createProgressDialog("Metric/Shape One Sample T-Test", ALG_NUM_STEPS, "oneSampProgress"); updateProgressDialog("Verifying Input", ALG_STEP_CHECKING_INPUT, ALG_NUM_STEPS); // // check iterations // if (permutationIterations < 0) { throw BrainModelAlgorithmException("Permutation iterations must be positive."); } // // Metric file used for processing // MetricFile metricFile; // // Check the mode // switch (tTestMode) { case T_TEST_MODE_ONE_SAMPLE: oneSampleTTestProcessing(metricFile); break; case T_TEST_MODE_PAIRED: pairedTTestProcessing(metricFile); break; } // // Get number of columns and limit iterations to 2**numCols // const int numCols = metricFile.getNumberOfColumns(); int maxIters = std::numeric_limits::max(); const double maxItersDouble = std::pow(2.0, numCols); if (maxItersDouble < static_cast(maxIters)) { maxIters = static_cast(maxItersDouble); } permutationIterations = std::min(permutationIterations, maxIters); // // Number of nodes in surface // const int numberOfNodes = bms->getNumberOfNodes(); // // Check file compatibilities // if (numberOfNodes != metricFile.getNumberOfNodes()) { throw BrainModelAlgorithmException("Metric/shape file has different number of nodes" "than the coordinate file."); } if (numberOfNodes != areaCorrectionShapeFile->getNumberOfNodes()) { throw BrainModelAlgorithmException("Area correction shape file has different number of nodes" "than the coordinate file."); } // // Update progress // updateProgressDialog("Doing T-Map", ALG_STEP_TMAP, ALG_NUM_STEPS); // // Create T-Map // try { statisticalMapShapeFile = metricFile.computeTValues(tTestConstant, brain->getTopologyFile(0), tVarianceSmoothingIterations, tVarianceSmoothingStrength); } catch (FileException& e) { std::ostringstream str; str << "T-Value failure: " << e.whatQString().toAscii().constData(); cleanUp(); throw BrainModelAlgorithmException(str.str().c_str()); } // // Write T-Map file // try { statisticalMapShapeFile->writeFile(statisticalMapFileName); } catch (FileException& e) { std::ostringstream str; str << "Unable to write T-Map: " << FileUtilities::basename(statisticalMapFileName).toAscii().constData(); cleanUp(); throw BrainModelAlgorithmException(str.str().c_str()); } // // Update progress // updateProgressDialog("Doing Permuted T-Map", ALG_STEP_PERMUTED_TMAP, ALG_NUM_STEPS); // // Do shuffled T-Map // try { shuffleStatisticalMapShapeFile = metricFile.computePermutedTValues(tTestConstant, permutationIterations, brain->getTopologyFile(0), tVarianceSmoothingIterations, tVarianceSmoothingStrength); } catch (FileException& e) { std::ostringstream str; str << "Permuted T-Map failure: " << e.whatQString().toAscii().constData(); cleanUp(); throw BrainModelAlgorithmException(str.str().c_str()); } // // Write Shuffled T-Map file // try { shuffleStatisticalMapShapeFile->writeFile(shuffledStatisticalMapFileName); } catch (FileException& e) { std::ostringstream str; str << "Unable to write Permuted T-Map: " << FileUtilities::basename(shuffledStatisticalMapFileName).toAscii().constData(); cleanUp(); throw BrainModelAlgorithmException(str.str().c_str()); } // // Update progress // updateProgressDialog("Finding clusters in T-Map", ALG_STEP_FINDING_CLUSTERS_T_MAP, ALG_NUM_STEPS); // // find the clusters in T-Map // Note: column 0 is the T-Map // std::vector tMapClusters; findClusters(statisticalMapShapeFile, tMapClusters, "Finding Clusters in T-Map", 0, false); // // Update progress // updateProgressDialog("Finding Clusters in Permuted T-Map", ALG_STEP_FINDING_CLUSTERS_PERMUTED_T_MAP, ALG_NUM_STEPS); // // find the clusters in Shuffled T-Map // Note: Only use largest cluster from each column // std::vector shuffleTMapClusters; findClusters(shuffleStatisticalMapShapeFile, shuffleTMapClusters, "Finding Clusters in Permuted T-Map", -1, true); // // Set pValue for shuffled T-Map // setRandomizedClusterPValues(*shuffleStatisticalMapShapeFile, shuffleTMapClusters); // // Find area of the "P-Value" cluster in the permuted T-Map // float significantCorrectedArea = std::numeric_limits::max(); int pValueClusterIndex = -1; if (shuffleTMapClusters.empty() == false) { pValueClusterIndex = std::min(static_cast(pValue * permutationIterations) - 1, static_cast(shuffleTMapClusters.size())); pValueClusterIndex = std::max(pValueClusterIndex, 0); } if (pValueClusterIndex >= 0) { significantCorrectedArea = shuffleTMapClusters[pValueClusterIndex].areaCorrected; } // // Find P-Value for significant clusters in T-Map // for (unsigned int i = 0; i < tMapClusters.size(); i++) { Cluster& tMapCluster = tMapClusters[i]; int cnt = shuffleTMapClusters.size() - 1; if (shuffleTMapClusters.empty() == false) { if (tMapCluster.areaCorrected > shuffleTMapClusters[0].areaCorrected) { cnt = 1; } else { for (unsigned int j = 0; j < shuffleTMapClusters.size() - 1; j++) { if ((tMapCluster.areaCorrected < shuffleTMapClusters[j].areaCorrected) && (tMapCluster.areaCorrected >= shuffleTMapClusters[j+1].areaCorrected)) { cnt = j + 2; } } } } cnt = std::min(cnt, permutationIterations); tMapCluster.pValue = static_cast(cnt) / static_cast(permutationIterations); } // // So only do column 0 in T-Map when searching for T-Map clusters // // // For each T-Map that has area corrected that exceeds significant area // Find its rank in shuffled tmap // P-value = rank / iterations // // Option for paint file to show the clusters // // Open the report file // QFile reportFile(reportFileName); if (reportFile.open(QIODevice::WriteOnly) == false) { std::ostringstream str; str << "Unable to open report file for writing: " << FileUtilities::basename(reportFileName).toAscii().constData(); cleanUp(); throw BrainModelAlgorithmException(str.str().c_str()); } // // Create the text stream // QTextStream reportStream(&reportFile); // // Show area and thresholds // reportStream << "Date/Time: " << DateAndTime::getDateAndTimeAsString() << "\n"; //QDateTime::currentDateTime().toString("MMM d, yyyy hh:mm:ss") << "\n"; reportStream << "Metric/Shape: " << metricFileNames[0] << "\n"; switch (tTestMode) { case T_TEST_MODE_ONE_SAMPLE: break; case T_TEST_MODE_PAIRED: reportStream << "Metric/Shape Two: " << metricFileNames[1] << "\n"; break; } reportStream << "Fiducial Coord File: " << fiducialCoordFileName << "\n"; reportStream << "Open Topo File: " << openTopoFileName << "\n"; if ((areaCorrectionShapeFile != NULL) || (areaCorrectionShapeFileColumn >= 0)) { reportStream << "Area Correct File: " << areaCorrectionShapeFileName << "\n"; reportStream << "Area Correct Column: " << areaCorrectionShapeFile->getColumnName(areaCorrectionShapeFileColumn) << "\n"; } reportStream << "Negative Threshold: " << negativeThresh << "\n"; reportStream << "Positive Threshold: " << positiveThresh << "\n"; reportStream << "Permutation Iterations: " << permutationIterations << "\n"; reportStream << "P-Value: " << pValue << "\n"; reportStream << "Significant Area: " << significantCorrectedArea << "\n"; reportStream << "\n"; // // Add significant clusters to report file // reportStream << "Permuted TMap" << "\n"; reportStream << "-------------" << "\n"; printClusters(reportStream, shuffleTMapClusters, significantCorrectedArea); reportStream << "\n\n\n"; reportStream << "TMap" << "\n"; reportStream << "----" << "\n"; printClusters(reportStream, tMapClusters, significantCorrectedArea); reportStream << "\n\n\n"; // // Add all clusters to report file // reportStream << "Permuted TMap" << "\n"; reportStream << "-------------" << "\n"; printClusters(reportStream, shuffleTMapClusters); reportStream << "\n\n\n"; reportStream << "TMap" << "\n"; reportStream << "----" << "\n"; printClusters(reportStream, tMapClusters); // // Close the report file // reportFile.close(); // // Do the paint file // createClustersPaintFile(tMapClusters, significantCorrectedArea, numberOfNodes); // // Do the clusters metric file // const int tValueColumn = 0; createClustersMetricFile(tMapClusters, tValueColumn, numberOfNodes); // // Do cluster reports // for (unsigned int i = 0; i < metricFileNames.size(); i++) { createMetricShapeClustersReportFile(tMapClusters, metricFileNames[i]); } } /** * create the metric file for one-sample T-Test processing. */ void BrainModelSurfaceMetricOneAndPairedTTest::oneSampleTTestProcessing(MetricFile& metricFileOut) throw (BrainModelAlgorithmException) { // // Verify metric files are present // if (metricFileNames.size() < 1) { throw BrainModelAlgorithmException("One metric/shape file must be provided."); } // // Read the single metric file // try { metricFileOut.readFile(metricFileNames[0]); } catch (FileException &e) { std::ostringstream str; str << "Unable to read metric/shape file: " << FileUtilities::basename(metricFileNames[0]).toAscii().constData(); throw BrainModelAlgorithmException(str.str().c_str()); } } /** * create the metric file for two-sample T-Test processing. */ void BrainModelSurfaceMetricOneAndPairedTTest::pairedTTestProcessing(MetricFile& metricFileOut) throw (BrainModelAlgorithmException) { // // Verifty metric files are present // if (metricFileNames.size() < 2) { throw BrainModelAlgorithmException("Two metric/shape files must be provided."); } // // Read the two metric files // MetricFile mf1, mf2; try { mf1.readFile(metricFileNames[0]); mf2.readFile(metricFileNames[1]); } catch (FileException &e) { throw BrainModelAlgorithmException(e.whatQString()); } if (mf1.getNumberOfColumns() != mf2.getNumberOfColumns()) { throw BrainModelAlgorithmException("The two input metric/shape files have a different number of columns."); } if (mf1.getNumberOfNodes() != mf2.getNumberOfNodes()) { throw BrainModelAlgorithmException("The two input metric/shape files have a different number of nodes."); } // // Load the metricFile with the subtraction of the two input metric files // const int numCols = mf1.getNumberOfColumns(); const int numNodes = mf1.getNumberOfNodes(); metricFileOut.setNumberOfNodesAndColumns(numNodes, numCols); metricFileOut.setFileComment("Subtraction of " + FileUtilities::basename(mf1.getFileName()) + " minus " + FileUtilities::basename(mf2.getFileName())); for (int j = 0; j < numCols; j++) { metricFileOut.setColumnName(j, mf1.getColumnName(j)); } for (int i = 0; i < numNodes; i++) { for (int j = 0; j < numCols; j++) { metricFileOut.setValue(i, j, (mf1.getValue(i, j) - mf2.getValue(i, j))); } } } /** * free memory. */ void BrainModelSurfaceMetricOneAndPairedTTest::cleanUp() { BrainModelSurfaceMetricFindClustersBase::cleanUp(); } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceMetricKruskalWallisRankTest.h0000664000175000017500000000713311572067322030740 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_METRIC_KRUSKAL_WALLIS_RANK_TEST_H__ #define __BRAIN_MODEL_SURFACE_METRIC_KRUSKAL_WALLIS_RANK_TEST_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurfaceMetricFindClustersBase.h" class MetricFile; /// class for performing a krusk-wallis (non-parametric ANOVA) on metric files class BrainModelSurfaceMetricKruskalWallisRankTest : public BrainModelSurfaceMetricFindClustersBase { public: // constructor BrainModelSurfaceMetricKruskalWallisRankTest(BrainSet* bs, const std::vector& inputMetricFileNamesIn, const QString& fiducialCoordFileNameIn, const QString& openTopoFileNameIn, const QString& areaCorrectionShapeFileNameIn, const QString& fMapFileNameIn, const QString& shuffledFMapFileNameIn, const QString& clustersPaintFileNameIn, const QString& clustersMetricFileNameIn, const QString& reportFileNameIn, const int areaCorrectionShapeFileColumnIn, const int iterationsIn, const float positiveThreshIn, const float pValueIn, const bool doFMapDOFIn, const bool doFMapPValueIn, const int numberOfThreadsIn); // destructor ~BrainModelSurfaceMetricKruskalWallisRankTest(); protected: /// must be implemented by subclasses void executeClusterSearch() throw (BrainModelAlgorithmException); /// perform an F-Test on a set of metric files void performFTest(const std::vector& metricFiles, MetricFile* outputMetricFile, const int fStatisticColumn, const int dofColumn, const int pValueColumn) throw (BrainModelAlgorithmException); /// the input metric file names std::vector inputMetricFileNames; /// the input metric files std::vector inputMetricFiles; /// metric files that are output of shuffling std::vector shuffledMetricFiles; /// interations for generating shuffled F-Map file int iterations; }; #endif // __BRAIN_MODEL_SURFACE_METRIC_KRUSKAL_WALLIS_RANK_TEST_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceMetricKruskalWallisRankTest.cxx0000664000175000017500000004406311572067322031316 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainModelSurface.h" #include "BrainModelSurfaceMetricKruskalWallisRankTest.h" #include "DateAndTime.h" #include "FileUtilities.h" #include "MetricFile.h" #include "StatisticKruskalWallis.h" #include "StatisticDataGroup.h" /** * constructor. */ BrainModelSurfaceMetricKruskalWallisRankTest::BrainModelSurfaceMetricKruskalWallisRankTest(BrainSet* bs, const std::vector& inputMetricFileNamesIn, const QString& fiducialCoordFileNameIn, const QString& openTopoFileNameIn, const QString& areaCorrectionShapeFileNameIn, const QString& fMapFileNameIn, const QString& shuffledFMapFileNameIn, const QString& clustersPaintFileNameIn, const QString& clustersMetricFileNameIn, const QString& reportFileNameIn, const int areaCorrectionShapeFileColumnIn, const int iterationsIn, const float positiveThreshIn, const float pValueIn, const bool doFMapDOFIn, const bool doFMapPValueIn, const int numberOfThreadsIn) : BrainModelSurfaceMetricFindClustersBase(bs, fiducialCoordFileNameIn, openTopoFileNameIn, areaCorrectionShapeFileNameIn, fMapFileNameIn, shuffledFMapFileNameIn, clustersPaintFileNameIn, clustersMetricFileNameIn, reportFileNameIn, areaCorrectionShapeFileColumnIn, -std::numeric_limits::max(), // no neg positiveThreshIn, pValueIn, 0, 0.0, doFMapDOFIn, doFMapPValueIn, numberOfThreadsIn) { inputMetricFileNames = inputMetricFileNamesIn; iterations = iterationsIn; } /** * destructor. */ BrainModelSurfaceMetricKruskalWallisRankTest::~BrainModelSurfaceMetricKruskalWallisRankTest() { for (unsigned int i = 0; i < inputMetricFiles.size(); i++) { delete inputMetricFiles[i]; inputMetricFiles[i] = NULL; } inputMetricFiles.clear(); for (unsigned int i = 0; i < shuffledMetricFiles.size(); i++) { delete shuffledMetricFiles[i]; shuffledMetricFiles[i] = NULL; } shuffledMetricFiles.clear(); } /** * must be implemented by subclasses. */ void BrainModelSurfaceMetricKruskalWallisRankTest::executeClusterSearch() throw (BrainModelAlgorithmException) { // // Steps in algorithm // enum { ALG_STEP_CHECKING_INPUT, ALG_STEP_F_MAP, ALG_STEP_SHUFFLED_F_MAP, ALG_STEP_FINDING_CLUSTERS_F_MAP, ALG_STEP_FINDING_CLUSTERS_SHUFFLED_F_MAP, ALG_NUM_STEPS }; // // Initialize the progress dialog // createProgressDialog("Kruskal-Wallis", ALG_NUM_STEPS, "BrainModelSurfaceMetricAnovaOneWay"); updateProgressDialog("Verifying Input", ALG_STEP_CHECKING_INPUT, ALG_NUM_STEPS); // // Read the input files // const int numInputFiles = static_cast(inputMetricFileNames.size()); if (numInputFiles < 2) { throw BrainModelAlgorithmException("There must be at least two input metric files."); } inputMetricFiles.resize(numInputFiles); for (int i = 0; i < numInputFiles; i++) { inputMetricFiles[i] = new MetricFile; try { inputMetricFiles[i]->readFile(inputMetricFileNames[i]); } catch (FileException& e) { throw BrainModelAlgorithmException(e); } } // // Verify number of nodes and columns // const int numberOfNodes = bms->getNumberOfNodes(); std::vector numberOfColumns(numInputFiles, 0); for (int i = 0; i < numInputFiles; i++) { if (inputMetricFiles[i]->getNumberOfNodes() != numberOfNodes) { const QString msg("Files have different number of nodes: \n" + FileUtilities::basename(inputMetricFileNames[0]) + " AND " + FileUtilities::basename(inputMetricFileNames[i])); throw BrainModelAlgorithmException(msg); } const int numCols = inputMetricFiles[i]->getNumberOfColumns(); if (numCols <= 0) { const QString msg(FileUtilities::basename(inputMetricFileNames[i]) + " contains no data columns."); throw BrainModelAlgorithmException(msg); } numberOfColumns[i] = numCols; } if (numberOfNodes != areaCorrectionShapeFile->getNumberOfNodes()) { throw BrainModelAlgorithmException("Area correction shape file has different number of nodes" "than the coordinate file."); } // // check iterations // if (iterations < 0) { throw BrainModelAlgorithmException("Iterations must be positive."); } // // Update progress // updateProgressDialog("Doing F-Map", ALG_STEP_F_MAP, ALG_NUM_STEPS); // // Create the F-Map Metric (output) File // int numOutputColumns = 0; const int fStatisticColumn = numOutputColumns++; int dofColumn = -1; if (doStatisticalMapDOF) { dofColumn = numOutputColumns++; } int pValueColumn = -1; if (doStatisticalMapPValue) { pValueColumn = numOutputColumns++; } statisticalMapShapeFile = new MetricFile; statisticalMapShapeFile->setNumberOfNodesAndColumns(numberOfNodes, numOutputColumns); // // Set the file comment // QString fileComment("Kruskal-Wallis for files: \n"); for (int i = 0; i < numInputFiles; i++) { fileComment += (" " + FileUtilities::basename(inputMetricFiles[i]->getFileName()) + "\n"); } statisticalMapShapeFile->setFileComment(fileComment); // // Create the F-Statistic Metric file // performFTest(inputMetricFiles, statisticalMapShapeFile, fStatisticColumn, dofColumn, pValueColumn); // // Write the F-Statistic metric file // try { statisticalMapShapeFile->writeFile(statisticalMapFileName); } catch (FileException& e) { throw BrainModelAlgorithmException(e); } // // Should a shuffled Statstical Map be created // if (iterations > 0) { // // Update progress // updateProgressDialog("Doing Shuffled F-Map", ALG_STEP_SHUFFLED_F_MAP, ALG_NUM_STEPS); // // Create shuffled statistical map metric file // shuffleStatisticalMapShapeFile = new MetricFile; shuffleStatisticalMapShapeFile->setNumberOfNodesAndColumns(numberOfNodes, iterations); // // Create metric files that will be the output of the shuffle process // for (int i = 0; i < numInputFiles; i++) { shuffledMetricFiles.push_back(new MetricFile(*inputMetricFiles[i])); } // // Perform for specified number of iterations // for (int i = 0; i < iterations; i++) { // // Shuffle the input files // try { MetricFile::shuffle(inputMetricFiles, shuffledMetricFiles); } catch (FileException& e) { throw BrainModelAlgorithmException(e); } // // Create the F-Statistic // performFTest(shuffledMetricFiles, shuffleStatisticalMapShapeFile, i, -1, -1); } // // Write the shuffled F-Statistic metric file // try { shuffleStatisticalMapShapeFile->writeFile(shuffledStatisticalMapFileName); } catch (FileException& e) { throw BrainModelAlgorithmException(e); } // // Update progress // updateProgressDialog("Finding Clusters in F-Map", ALG_STEP_FINDING_CLUSTERS_F_MAP, ALG_NUM_STEPS); // // find the clusters in F-Map // Note: column 2 is the F-Map // std::vector fMapClusters; findClusters(statisticalMapShapeFile, fMapClusters, "Finding Clusters in F-Map", fStatisticColumn, false); // // Update progress // updateProgressDialog("Finding Clusters in Shuffled F-Map", ALG_STEP_FINDING_CLUSTERS_SHUFFLED_F_MAP, ALG_NUM_STEPS); // // find the clusters in Shuffled F-Map // Note: Only use largest cluster from each column // std::vector shuffleFMapClusters; findClusters(shuffleStatisticalMapShapeFile, shuffleFMapClusters, "Finding Clusters in Shuffled F-Map", -1, true); // // Set pValue for shuffled T-Map // setRandomizedClusterPValues(*shuffleStatisticalMapShapeFile, shuffleFMapClusters); // // Find area of the "P-Value" cluster in the shuffled F-Map // float significantCorrectedArea = std::numeric_limits::max(); int pValueClusterIndex = -1; if (shuffleFMapClusters.empty() == false) { pValueClusterIndex = std::min(static_cast(pValue * iterations) - 1, static_cast(shuffleFMapClusters.size())); pValueClusterIndex = std::max(pValueClusterIndex, 0); } if (pValueClusterIndex >= 0) { significantCorrectedArea = shuffleFMapClusters[pValueClusterIndex].areaCorrected; } // // Find P-Value for significant clusters in T-Map // for (unsigned int i = 0; i < fMapClusters.size(); i++) { Cluster& fMapCluster = fMapClusters[i]; int cnt = shuffleFMapClusters.size() - 1; if (shuffleFMapClusters.empty() == false) { if (fMapCluster.areaCorrected > shuffleFMapClusters[0].areaCorrected) { cnt = 1; } else { for (unsigned int j = 0; j < shuffleFMapClusters.size() - 1; j++) { if ((fMapCluster.areaCorrected < shuffleFMapClusters[j].areaCorrected) && (fMapCluster.areaCorrected >= shuffleFMapClusters[j+1].areaCorrected)) { cnt = j + 2; } } } } cnt = std::min(cnt, iterations); fMapCluster.pValue = static_cast(cnt) / static_cast(iterations); } // // For each F-Map that has area corrected that exceeds significant area // Find its rank in shuffled tmap // P-value = rank / iterations // // Option for paint file to show the clusters // // Open the report file // QFile reportFile(reportFileName); if (reportFile.open(QIODevice::WriteOnly) == false) { std::ostringstream str; str << "Unable to open report file for writing: " << FileUtilities::basename(reportFileName).toAscii().constData(); cleanUp(); throw BrainModelAlgorithmException(str.str().c_str()); } // // Create the text stream // QTextStream reportStream(&reportFile); // // Show area and thresholds // reportStream << "Date/Time: " << DateAndTime::getDateAndTimeAsString() << "\n"; //QDateTime::currentDateTime().toString("MMM d, yyyy hh:mm:ss") << "\n"; for (int m = 0; m < numInputFiles; m++) { reportStream << "Shape File : " << inputMetricFileNames[m] << "\n"; } reportStream << "Fiducial Coord File: " << fiducialCoordFileName << "\n"; reportStream << "Open Topo File: " << openTopoFileName << "\n"; if ((areaCorrectionShapeFile != NULL) || (areaCorrectionShapeFileColumn >= 0)) { reportStream << "Area Correct File: " << areaCorrectionShapeFileName << "\n"; reportStream << "Area Correct Column: " << areaCorrectionShapeFile->getColumnName(areaCorrectionShapeFileColumn) << "\n"; } reportStream << "Positive Threshold: " << positiveThresh << "\n"; reportStream << "Iterations: " << iterations << "\n"; reportStream << "P-Value: " << pValue << "\n"; reportStream << "Significant Area: " << significantCorrectedArea << "\n"; reportStream << "\n"; // // Add significant clusters to report file // reportStream << "Shuffled FMap" << "\n"; reportStream << "-------------" << "\n"; printClusters(reportStream, shuffleFMapClusters, significantCorrectedArea); reportStream << "\n\n\n"; reportStream << "TMap" << "\n"; reportStream << "----" << "\n"; printClusters(reportStream, fMapClusters, significantCorrectedArea); reportStream << "\n\n\n"; // // Add all clusters to report file // reportStream << "Shuffled FMap" << "\n"; reportStream << "-------------" << "\n"; printClusters(reportStream, shuffleFMapClusters); reportStream << "\n\n\n"; reportStream << "FMap" << "\n"; reportStream << "----" << "\n"; printClusters(reportStream, fMapClusters); // // Close the report file // reportFile.close(); // // Do the clusters paint file // createClustersPaintFile(fMapClusters, significantCorrectedArea, numberOfNodes); // // Do the clusters metric file // createClustersMetricFile(fMapClusters, fStatisticColumn, numberOfNodes); // // Do cluster reports // for (unsigned int i = 0; i < inputMetricFileNames.size(); i++) { createMetricShapeClustersReportFile(fMapClusters, inputMetricFileNames[i]); } } // if (iterations > 0 } /** * perform an F-Test on a set of metric files. */ void BrainModelSurfaceMetricKruskalWallisRankTest::performFTest(const std::vector& metricFiles, MetricFile* outputMetricFile, const int fStatisticColumn, const int dofColumn, const int pValueColumn) throw (BrainModelAlgorithmException) { const int numberOfNodes = metricFiles[0]->getNumberOfNodes(); const int numInputFiles = static_cast(metricFiles.size()); // // Set column names // outputMetricFile->setColumnName(fStatisticColumn, "F-Statistic"); if (dofColumn >= 0) { outputMetricFile->setColumnName(dofColumn, "DOF"); } if (pValueColumn >= 0) { outputMetricFile->setColumnName(pValueColumn, "P-Value"); } // // Loop through the nodes and create the F-Statistic for each node // for (int i = 0; i < numberOfNodes; i++) { StatisticKruskalWallis kw; // // Create the data groups and add them to the algorithm // for (int j = 0; j < numInputFiles; j++) { // // Note, the kruskal-wallis algorithm will take care of deleting everything // const int numData = metricFiles[j]->getNumberOfColumns(); float* data = new float[numData]; metricFiles[j]->getAllColumnValuesForNode(i, data); StatisticDataGroup* sdg = new StatisticDataGroup(data, numData, StatisticDataGroup::DATA_STORAGE_MODE_TAKE_OWNERSHIP); kw.addDataGroup(sdg, true); } // // Execute the kruskal-wallis algorithm // try { kw.execute(); } catch (StatisticException& e) { throw BrainModelAlgorithmException(e); } // // Get the outputs of the kruskal-wallis algorithm // outputMetricFile->setValue(i, fStatisticColumn, kw.getFStatistic()); if (dofColumn >= 0) { outputMetricFile->setValue(i, dofColumn, kw.getDegreesOfFreedomTotal()); } if (pValueColumn >= 0) { outputMetricFile->setValue(i, pValueColumn, kw.getPValue()); } } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceMetricInterHemClusters.h0000664000175000017500000001176611572067322027743 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_SHAPE_INTER_HEM_CLUSTERS_H__ #define __BRAIN_MODEL_SURFACE_SHAPE_INTER_HEM_CLUSTERS_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainModelSurfaceMetricFindClustersBase.h" class BrainModelSurface; class MetricFile; class QTextStream; /// find significant clusters between hemisphere surface shape files class BrainModelSurfaceMetricInterHemClusters : public BrainModelSurfaceMetricFindClustersBase { public: // constructor BrainModelSurfaceMetricInterHemClusters(BrainSet* bs, const QString& shapeFileRightANameIn, const QString& shapeFileRightBNameIn, const QString& shapeFileLeftANameIn, const QString& shapeFileLeftBNameIn, const QString& fiducialCoordFileNameIn, const QString& openTopoFileNameIn, const QString& areaCorrectionShapeFileNameIn, const QString& rightTMapFileNameIn, const QString& leftTMapFileNameIn, const QString& rightShuffledTMapFileNameIn, const QString& leftShuffledTMapFileNameIn, const QString& tMapFileNameIn, const QString& shuffledTMapFileNameIn, const QString& clustersPaintFileNameIn, const QString& clustersMetricFileNameIn, const QString& reportFileNameIn, const int areaCorrectionShapeFileColumnIn, const int iterationsShuffledTMapIn, const int iterationsRightLeftShuffledTMapIn, const float negativeThreshIn, const float positiveThreshIn, const float pValueIn, const int tVarianceSmoothingIterationsIn, const float tVarianceSmoothingStrengthIn, const bool doTMapDOFIn, const bool doTMapPValueIn, const int numberOfThreadsIn); // destructor ~BrainModelSurfaceMetricInterHemClusters(); protected: /// must be implemented by subclasses void executeClusterSearch() throw (BrainModelAlgorithmException); // free memory void cleanUp(); /// name of shape file Right A QString shapeFileRightAName; /// name of shape file Right B QString shapeFileRightBName; /// name of shape file Left A QString shapeFileLeftAName; /// name of shape file Left B QString shapeFileLeftBName; /// name of right hem tmap file QString rightTMapFileName; /// name of left hem tmap file QString leftTMapFileName; /// name of right hem shuffled tmap file QString rightShuffledTMapFileName; /// name of left hem shuffled tmap file QString leftShuffledTMapFileName; /// iterations for shuffled T-Map int iterationsShuffledTMap; /// iterations for shuffled right/left T-Maps int iterationsRightLeftShuffledTMap; /// left T-Map shape file MetricFile* leftTMapShapeFile; /// right T-Map shape file MetricFile* rightTMapShapeFile; /// left shuffled T-Map shape file MetricFile* leftShuffledTMapShapeFile; /// right shuffled T-Map shape file MetricFile* rightShuffledTMapShapeFile; }; #endif // __BRAIN_MODEL_SURFACE_SHAPE_INTER_HEM_CLUSTERS_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceMetricInterHemClusters.cxx0000664000175000017500000006327111572067322030314 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "BrainModelSurfaceMetricInterHemClusters.h" #include "BrainSet.h" #include "DateAndTime.h" #include "DebugControl.h" #include "FileUtilities.h" #include "MetricFile.h" #include "StatisticRandomNumber.h" /** * constructor. */ BrainModelSurfaceMetricInterHemClusters::BrainModelSurfaceMetricInterHemClusters( BrainSet* bs, const QString& shapeFileRightANameIn, const QString& shapeFileRightBNameIn, const QString& shapeFileLeftANameIn, const QString& shapeFileLeftBNameIn, const QString& fiducialCoordFileNameIn, const QString& openTopoFileNameIn, const QString& areaCorrectionShapeFileNameIn, const QString& rightTMapFileNameIn, const QString& leftTMapFileNameIn, const QString& rightShuffledTMapFileNameIn, const QString& leftShuffledTMapFileNameIn, const QString& tMapFileNameIn, const QString& shuffledTMapFileNameIn, const QString& clustersPaintFileNameIn, const QString& clustersMetricFileNameIn, const QString& reportFileNameIn, const int areaCorrectionShapeFileColumnIn, const int iterationsShuffledTMapIn, const int iterationsRightLeftShuffledTMapIn, const float negativeThreshIn, const float positiveThreshIn, const float pValueIn, const int tVarianceSmoothingIterationsIn, const float tVarianceSmoothingStrengthIn, const bool doTMapDOFIn, const bool doTMapPValueIn, const int numberOfThreadsIn) : BrainModelSurfaceMetricFindClustersBase(bs, fiducialCoordFileNameIn, openTopoFileNameIn, areaCorrectionShapeFileNameIn, tMapFileNameIn, shuffledTMapFileNameIn, clustersPaintFileNameIn, clustersMetricFileNameIn, reportFileNameIn, areaCorrectionShapeFileColumnIn, negativeThreshIn, positiveThreshIn, pValueIn, tVarianceSmoothingIterationsIn, tVarianceSmoothingStrengthIn, doTMapDOFIn, doTMapPValueIn, numberOfThreadsIn) { shapeFileRightAName = shapeFileRightANameIn; shapeFileRightBName = shapeFileRightBNameIn; shapeFileLeftAName = shapeFileLeftANameIn; shapeFileLeftBName = shapeFileLeftBNameIn; rightTMapFileName = rightTMapFileNameIn; leftTMapFileName = leftTMapFileNameIn; rightShuffledTMapFileName = rightShuffledTMapFileNameIn; leftShuffledTMapFileName = leftShuffledTMapFileNameIn; iterationsShuffledTMap = iterationsShuffledTMapIn; iterationsRightLeftShuffledTMap = iterationsRightLeftShuffledTMapIn; leftTMapShapeFile = NULL; rightTMapShapeFile = NULL; leftShuffledTMapShapeFile = NULL; rightShuffledTMapShapeFile = NULL; } /** * destructor. */ BrainModelSurfaceMetricInterHemClusters::~BrainModelSurfaceMetricInterHemClusters() { cleanUp(); } /** * execute the algorithm. */ void BrainModelSurfaceMetricInterHemClusters::executeClusterSearch() throw (BrainModelAlgorithmException) { // // Steps in algorithm // enum { ALG_STEP_CHECKING_INPUT, ALG_STEP_TMAP_LEFT, ALG_STEP_TMAP_RIGHT, ALG_STEP_TMAP_PRODUCT, ALG_STEP_SHUFFLED_TMAP_LEFT, ALG_STEP_SHUFFLED_TMAP_RIGHT, ALG_STEP_SHUFFLED_TMAP_PRODUCT, ALG_STEP_FINDING_CLUSTERS_T_MAP, ALG_STEP_FINDING_CLUSTERS_SHUFFLE_T_MAP, ALG_NUM_STEPS }; // // Update progress // createProgressDialog("Surface Shape Interhemispheric Clusters", ALG_NUM_STEPS, "sifClustDialog"); updateProgressDialog("Verifying Input", ALG_STEP_CHECKING_INPUT, ALG_NUM_STEPS); // // check iterations // if (iterationsShuffledTMap < 0) { throw BrainModelAlgorithmException("Iterations for shuffled T-Map product be positive."); } if (iterationsRightLeftShuffledTMap < 0) { throw BrainModelAlgorithmException("Iterations for left/right shuffled T-Map be positive."); } // // Read the surface shape right A file // MetricFile ssfRightA; try { ssfRightA.readFile(shapeFileRightAName); } catch (FileException &e) { std::ostringstream str; str << "Unable to read surface shape file Right A: " << FileUtilities::basename(shapeFileRightAName).toAscii().constData(); throw BrainModelAlgorithmException(str.str().c_str()); } // // Read the surface shape right B file // MetricFile ssfRightB; try { ssfRightB.readFile(shapeFileRightBName); } catch (FileException &e) { std::ostringstream str; str << "Unable to read surface shape file Right B: " << FileUtilities::basename(shapeFileRightBName).toAscii().constData(); throw BrainModelAlgorithmException(str.str().c_str()); } // // Read the surface shape left A file // MetricFile ssfLeftA; try { ssfLeftA.readFile(shapeFileLeftAName); } catch (FileException &e) { std::ostringstream str; str << "Unable to read surface shape file Left A: " << FileUtilities::basename(shapeFileLeftAName).toAscii().constData(); throw BrainModelAlgorithmException(str.str().c_str()); } // // Read the surface shape left B file // MetricFile ssfLeftB; try { ssfLeftB.readFile(shapeFileLeftBName); } catch (FileException &e) { std::ostringstream str; str << "Unable to read surface shape file Left B: " << FileUtilities::basename(shapeFileLeftBName).toAscii().constData(); throw BrainModelAlgorithmException(str.str().c_str()); } // // Number of nodes in surface // const int numberOfNodes = bms->getNumberOfNodes(); // // Check file compatibilities // if (numberOfNodes != ssfRightA.getNumberOfNodes()) { throw BrainModelAlgorithmException("Right shape file A has different number of nodes" "than the coordinate file."); } if (numberOfNodes != ssfRightB.getNumberOfNodes()) { throw BrainModelAlgorithmException("Right shape file B has different number of nodes" "than the coordinate file."); } if (numberOfNodes != ssfLeftA.getNumberOfNodes()) { throw BrainModelAlgorithmException("Left shape file A has different number of nodes" "than the coordinate file."); } if (numberOfNodes != ssfLeftB.getNumberOfNodes()) { throw BrainModelAlgorithmException("Left shape file B has different number of nodes" "than the coordinate file."); } if (numberOfNodes != areaCorrectionShapeFile->getNumberOfNodes()) { throw BrainModelAlgorithmException("Area correction shape file has different number of nodes" "than the coordinate file."); } // // Update progress // updateProgressDialog("Doing Left T-Map", ALG_STEP_TMAP_LEFT, ALG_NUM_STEPS); // // Create Left T-Map // try { leftTMapShapeFile = MetricFile::computeStatisticalTMap(&ssfLeftA, &ssfLeftB, brain->getTopologyFile(0), tVarianceSmoothingIterations, tVarianceSmoothingStrength, false, 0.05, false, doStatisticalMapDOF, doStatisticalMapPValue); } catch (FileException& e) { std::ostringstream str; str << "Left T-Map failure: " << e.whatQString().toAscii().constData(); cleanUp(); throw BrainModelAlgorithmException(str.str().c_str()); } // // Write Left T-Map file // try { leftTMapShapeFile->writeFile(leftTMapFileName); } catch (FileException& e) { std::ostringstream str; str << "Unable to write T-Map: " << FileUtilities::basename(leftTMapFileName).toAscii().constData(); cleanUp(); throw BrainModelAlgorithmException(str.str().c_str()); } // // Update progress // updateProgressDialog("Doing Right T-Map", ALG_STEP_TMAP_RIGHT, ALG_NUM_STEPS); // // Create Right T-Map // try { rightTMapShapeFile = MetricFile::computeStatisticalTMap(&ssfRightA, &ssfRightB, brain->getTopologyFile(0), tVarianceSmoothingIterations, tVarianceSmoothingStrength, false, 0.05, false, doStatisticalMapDOF, doStatisticalMapPValue); } catch (FileException& e) { std::ostringstream str; str << "Right T-Map failure: " << e.whatQString().toAscii().constData(); cleanUp(); throw BrainModelAlgorithmException(str.str().c_str()); } // // Write Right T-Map file // try { rightTMapShapeFile->writeFile(rightTMapFileName); } catch (FileException& e) { std::ostringstream str; str << "Unable to write T-Map: " << FileUtilities::basename(rightTMapFileName).toAscii().constData(); cleanUp(); throw BrainModelAlgorithmException(str.str().c_str()); } // // Update progress // updateProgressDialog("Creating Left/Right T-Map Product", ALG_STEP_TMAP_PRODUCT, ALG_NUM_STEPS); // // Do Left/Right T-Map product // statisticalMapShapeFile = new MetricFile; statisticalMapShapeFile->setNumberOfNodesAndColumns(numberOfNodes, 3); statisticalMapShapeFile->setColumnName(0, "Unused"); statisticalMapShapeFile->setColumnName(1, "Unused"); statisticalMapShapeFile->setColumnName(2, "T-Map"); QString tMapCom("T-Map Product of "); tMapCom.append(FileUtilities::basename(leftTMapFileName)); tMapCom.append(" and "); tMapCom.append(FileUtilities::basename(rightTMapFileName)); statisticalMapShapeFile->setFileComment(tMapCom); for (int i = 0; i < numberOfNodes; i++) { statisticalMapShapeFile->setValue(i, 2, leftTMapShapeFile->getValue(i, 2) * rightTMapShapeFile->getValue(i, 2)); } // // Write T-Map file // try { statisticalMapShapeFile->writeFile(statisticalMapFileName); } catch (FileException& e) { std::ostringstream str; str << "Unable to write T-Map: " << FileUtilities::basename(statisticalMapFileName).toAscii().constData(); cleanUp(); throw BrainModelAlgorithmException(str.str().c_str()); } // // Update progress // updateProgressDialog("Doing Left Shuffled T-Map", ALG_STEP_SHUFFLED_TMAP_LEFT, ALG_NUM_STEPS); // // Combine input shape for shuffled T-Map // MetricFile allShapeLeft = ssfLeftA; allShapeLeft.append(ssfLeftB); // // Do shuffled T-Map // try { leftShuffledTMapShapeFile = allShapeLeft.computeStatisticalShuffledTMap(iterationsRightLeftShuffledTMap, ssfLeftA.getNumberOfColumns(), brain->getTopologyFile(0), tVarianceSmoothingIterations, tVarianceSmoothingStrength, false); } catch (FileException& e) { std::ostringstream str; str << "Left Shuffled T-Map failure: " << e.whatQString().toAscii().constData(); cleanUp(); throw BrainModelAlgorithmException(str.str().c_str()); } // // Write Left Shuffled T-Map file // try { leftShuffledTMapShapeFile->writeFile(leftShuffledTMapFileName); } catch (FileException& e) { std::ostringstream str; str << "Unable to write Left Shuffled T-Map: " << FileUtilities::basename(leftShuffledTMapFileName).toAscii().constData(); cleanUp(); throw BrainModelAlgorithmException(str.str().c_str()); } // // Update progress // updateProgressDialog("Doing Right Shuffled T-Map", ALG_STEP_SHUFFLED_TMAP_RIGHT, ALG_NUM_STEPS); // // Combine input shape for shuffled T-Map // MetricFile allShapeRight = ssfRightA; allShapeRight.append(ssfRightB); // // Do Right shuffled T-Map // try { rightShuffledTMapShapeFile = allShapeRight.computeStatisticalShuffledTMap(iterationsRightLeftShuffledTMap, ssfRightA.getNumberOfColumns(), brain->getTopologyFile(0), tVarianceSmoothingIterations, tVarianceSmoothingStrength, false); } catch (FileException& e) { std::ostringstream str; str << "Right Shuffled T-Map failure: " << e.whatQString().toAscii().constData(); cleanUp(); throw BrainModelAlgorithmException(str.str().c_str()); } // // Write Right Shuffled T-Map file // try { rightShuffledTMapShapeFile->writeFile(rightShuffledTMapFileName); } catch (FileException& e) { std::ostringstream str; str << "Unable to write right Shuffled T-Map: " << FileUtilities::basename(rightShuffledTMapFileName).toAscii().constData(); cleanUp(); throw BrainModelAlgorithmException(str.str().c_str()); } // // Update progress // updateProgressDialog("Creating Shuffled T-Map Product", ALG_STEP_SHUFFLED_TMAP_PRODUCT, ALG_NUM_STEPS); // // Create shuffled T-Map product file // shuffleStatisticalMapShapeFile = new MetricFile; shuffleStatisticalMapShapeFile->setNumberOfNodesAndColumns(numberOfNodes, iterationsShuffledTMap); QString stMapCom("Shuffled T-Map Product of "); stMapCom.append(FileUtilities::basename(leftShuffledTMapFileName)); stMapCom.append(" and "); stMapCom.append(FileUtilities::basename(rightShuffledTMapFileName)); statisticalMapShapeFile->setFileComment(stMapCom); for (int j = 0; j < iterationsShuffledTMap; j++) { const int leftCol = StatisticRandomNumber::randomInteger(0, leftShuffledTMapShapeFile->getNumberOfColumns() - 1); const int rightCol = StatisticRandomNumber::randomInteger(0, rightShuffledTMapShapeFile->getNumberOfColumns() - 1); std::ostringstream str; str << "Left=" << leftCol << " " << "Right=" << rightCol; shuffleStatisticalMapShapeFile->setColumnComment(j, str.str().c_str()); for (int i = 0; i < numberOfNodes; i++) { shuffleStatisticalMapShapeFile->setValue(i, j, leftShuffledTMapShapeFile->getValue(i, leftCol) * rightShuffledTMapShapeFile->getValue(i, rightCol)); } } // // Write Right Shuffled T-Map product file // try { shuffleStatisticalMapShapeFile->writeFile(shuffledStatisticalMapFileName); } catch (FileException& e) { std::ostringstream str; str << "Unable to write right Shuffled T-Map: " << FileUtilities::basename(shuffledStatisticalMapFileName).toAscii().constData(); cleanUp(); throw BrainModelAlgorithmException(str.str().c_str()); } // // Update progress // updateProgressDialog("Finding clusters in T-Map", ALG_STEP_FINDING_CLUSTERS_T_MAP, ALG_NUM_STEPS); // // find the clusters in T-Map // Note: column 2 is the T-Map // const int tMapColumn = 2; std::vector tMapClusters; findClusters(statisticalMapShapeFile, tMapClusters, "Finding clusters in T-Map", tMapColumn, false); // // Update progress // updateProgressDialog("Finding clusters in Shuffled T-Map", ALG_STEP_FINDING_CLUSTERS_SHUFFLE_T_MAP, ALG_NUM_STEPS); // // find the clusters in Shuffled T-Map // Note: Only use largest cluster from each column // std::vector shuffleTMapClusters; findClusters(shuffleStatisticalMapShapeFile, shuffleTMapClusters, "Finding clusters in Shuffled T-Map", -1, true); // // Set pValue for shuffled T-Map // setRandomizedClusterPValues(*shuffleStatisticalMapShapeFile, shuffleTMapClusters); // // Find area of the "P-Value" cluster in the shuffled T-Map // float significantCorrectedArea = std::numeric_limits::max(); int pValueClusterIndex = -1; if (shuffleTMapClusters.empty() == false) { pValueClusterIndex = std::min(static_cast(pValue * iterationsShuffledTMap) - 1, static_cast(shuffleTMapClusters.size())); pValueClusterIndex = std::max(pValueClusterIndex, 0); } if (pValueClusterIndex >= 0) { significantCorrectedArea = shuffleTMapClusters[pValueClusterIndex].areaCorrected; } // // Find P-Value for significant clusters in T-Map // for (unsigned int i = 0; i < tMapClusters.size(); i++) { Cluster& tMapCluster = tMapClusters[i]; int cnt = shuffleTMapClusters.size() - 1; if (shuffleTMapClusters.empty() == false) { if (tMapCluster.areaCorrected > shuffleTMapClusters[0].areaCorrected) { cnt = 1; } else { for (unsigned int j = 0; j < shuffleTMapClusters.size() - 1; j++) { if ((tMapCluster.areaCorrected < shuffleTMapClusters[j].areaCorrected) && (tMapCluster.areaCorrected >= shuffleTMapClusters[j+1].areaCorrected)) { cnt = j + 2; } } } } cnt = std::min(cnt, iterationsShuffledTMap); tMapCluster.pValue = static_cast(cnt) / static_cast(iterationsShuffledTMap); } // // So only do column 3 in T-Map when searching for T-Map clusters // // // For each T-Map that has area corrected that exceeds significant area // Find its rank in shuffled tmap // P-value = rank / iterations // // Option for paint file to show the clusters // // Open the report file // QFile reportFile(reportFileName); if (reportFile.open(QIODevice::WriteOnly) == false) { std::ostringstream str; str << "Unable to open report file for writing: " << FileUtilities::basename(reportFileName).toAscii().constData(); cleanUp(); throw BrainModelAlgorithmException(str.str().c_str()); } // // Create the text stream // QTextStream reportStream(&reportFile); // // Show area and thresholds // reportStream << "Date/Time: " << DateAndTime::getDateAndTimeAsString() << "\n"; //QDateTime::currentDateTime().toString("MMM d, yyyy hh:mm:ss") << "\n"; reportStream << "Shape File Left A: " << shapeFileLeftAName << "\n"; reportStream << "Shape File Left B: " << shapeFileLeftBName << "\n"; reportStream << "Shape File Left A: " << shapeFileRightAName << "\n"; reportStream << "Shape File Left B: " << shapeFileRightBName << "\n"; reportStream << "Fiducial Coord File: " << fiducialCoordFileName << "\n"; reportStream << "Open Topo File: " << openTopoFileName << "\n"; if ((areaCorrectionShapeFile != NULL) || (areaCorrectionShapeFileColumn >= 0)) { reportStream << "Area Correct File: " << areaCorrectionShapeFileName << "\n"; reportStream << "Area Correct Column: " << areaCorrectionShapeFile->getColumnName(areaCorrectionShapeFileColumn) << "\n"; } reportStream << "Negative Threshold: " << negativeThresh << "\n"; reportStream << "Positive Threshold: " << positiveThresh << "\n"; reportStream << "Right/LeftIterations: " << iterationsRightLeftShuffledTMap << "\n"; reportStream << "Shuffled T-Map Iterations: " << iterationsShuffledTMap << "\n"; reportStream << "P-Value: " << pValue << "\n"; reportStream << "Significant Area: " << significantCorrectedArea << "\n"; reportStream << "\n"; // // Add significant clusters to report file // reportStream << "Shuffled TMap" << "\n"; reportStream << "-------------" << "\n"; printClusters(reportStream, shuffleTMapClusters, significantCorrectedArea); reportStream << "\n\n\n"; reportStream << "TMap" << "\n"; reportStream << "----" << "\n"; printClusters(reportStream, tMapClusters, significantCorrectedArea); reportStream << "\n\n\n"; // // Add all clusters to report file // reportStream << "Shuffled TMap" << "\n"; reportStream << "-------------" << "\n"; printClusters(reportStream, shuffleTMapClusters); reportStream << "\n\n\n"; reportStream << "TMap" << "\n"; reportStream << "----" << "\n"; printClusters(reportStream, tMapClusters); // // Close the report file // reportFile.close(); // // Do the paint file // createClustersPaintFile(tMapClusters, significantCorrectedArea, numberOfNodes); // // Do the clusters metric file // createClustersMetricFile(tMapClusters, tMapColumn, numberOfNodes); // // Do cluster reports // createMetricShapeClustersReportFile(tMapClusters, shapeFileRightAName); createMetricShapeClustersReportFile(tMapClusters, shapeFileRightBName); createMetricShapeClustersReportFile(tMapClusters, shapeFileLeftAName); createMetricShapeClustersReportFile(tMapClusters, shapeFileLeftBName); } /** * Free memory. */ void BrainModelSurfaceMetricInterHemClusters::cleanUp() { BrainModelSurfaceMetricFindClustersBase::cleanUp(); if (leftTMapShapeFile != NULL) { delete leftTMapShapeFile; leftTMapShapeFile = NULL; } if (rightTMapShapeFile != NULL) { delete rightTMapShapeFile; rightTMapShapeFile = NULL; } if (leftShuffledTMapShapeFile != NULL) { delete leftShuffledTMapShapeFile; leftShuffledTMapShapeFile = NULL; } if (rightShuffledTMapShapeFile != NULL) { delete rightShuffledTMapShapeFile; rightShuffledTMapShapeFile = NULL; } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceMetricInGroupDifference.h0000664000175000017500000000375311572067322030036 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_METRIC_IN_GROUP_DIFFERENCE_H__ #define __BRAIN_MODEL_SURFACE_METRIC_IN_GROUP_DIFFERENCE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelAlgorithm.h" /// class for generating differences between all possible pairs of subjects class BrainModelSurfaceMetricInGroupDifference : public BrainModelAlgorithm { public: // constructor BrainModelSurfaceMetricInGroupDifference(BrainSet* bs, const QString& inputMetricShapeFileNameIn, const QString& outputMetricShapeFileNameIn, const bool absoluteValueFlagIn); // destructor ~BrainModelSurfaceMetricInGroupDifference(); // execute the algorithm void execute() throw (BrainModelAlgorithmException); protected: /// input metric file name QString inputMetricShapeFileName; /// output file name QString outputMetricShapeFileName; /// output absolute values flag bool absoluteValueFlag; }; #endif // __BRAIN_MODEL_SURFACE_METRIC_IN_GROUP_DIFFERENCE_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceMetricInGroupDifference.cxx0000664000175000017500000001212511572067322030402 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelSurfaceMetricInGroupDifference.h" #include "DebugControl.h" #include "FileUtilities.h" #include "MathUtilities.h" #include "MetricFile.h" /** * constructor. */ BrainModelSurfaceMetricInGroupDifference::BrainModelSurfaceMetricInGroupDifference( BrainSet* bs, const QString& inputMetricShapeFileNameIn, const QString& outputMetricShapeFileNameIn, const bool absoluteValueFlagIn) : BrainModelAlgorithm(bs) { inputMetricShapeFileName = inputMetricShapeFileNameIn; outputMetricShapeFileName = outputMetricShapeFileNameIn; absoluteValueFlag = absoluteValueFlagIn; } /** * destructor. */ BrainModelSurfaceMetricInGroupDifference::~BrainModelSurfaceMetricInGroupDifference() { } /** * execute the algorithm. */ void BrainModelSurfaceMetricInGroupDifference::execute() throw (BrainModelAlgorithmException) { // // Make sure file names are specified // if (inputMetricShapeFileName.isEmpty()) { throw BrainModelAlgorithmException("Input filename is empty."); } if (outputMetricShapeFileName.isEmpty()) { throw BrainModelAlgorithmException("Output filename is empty."); } // // Read in the input files // MetricFile inputMetricFile; try { inputMetricFile.readFile(inputMetricShapeFileName); } catch (FileException& e) { throw BrainModelAlgorithmException(e); } // // Examine data files // const int numNodes = inputMetricFile.getNumberOfNodes(); const int numCols = inputMetricFile.getNumberOfColumns(); if ((numNodes <= 0) || (numCols <= 0)) { const QString msg = FileUtilities::basename(inputMetricShapeFileName) + " contains no data."; throw BrainModelAlgorithmException(msg); } if (numCols < 2) { throw BrainModelAlgorithmException("The input metric file must contain at least two columns."); } // // Get the number of combinations which will be the number of columns in the output files // const int numOutputColumns = MathUtilities::combinations(numCols, 2); // // Create the output metric file // MetricFile outputMetricFile; outputMetricFile.setNumberOfNodesAndColumns(numNodes, numOutputColumns); // // Pair up each possible combination of nodes // int currentColumn = 0; for (int j = 0; j < (numCols - 1); j++) { for (int k = (j + 1); k < numCols; k++) { if (currentColumn >= numOutputColumns) { const QString msg = "Compute number of column combinations " + QString::number(numOutputColumns) + "\n" + "has been exceeded when combining columns \n" + QString::number(j) + " and " + QString::number(k); throw BrainModelAlgorithmException(msg); } // // Set the column name // const QString columnName = "Columns " + QString::number(j) + " and " + QString::number(k); outputMetricFile.setColumnName(currentColumn, columnName); // // Set column comment // const QString columnComment = inputMetricFile.getColumnName(j) + " AND " + inputMetricFile.getColumnName(k); outputMetricFile.setColumnComment(currentColumn, columnComment); // // Compute the differences for each node // for (int i = 0; i < numNodes; i++) { float diff = inputMetricFile.getValue(i, j) - inputMetricFile.getValue(i, k); if (absoluteValueFlag) { if (diff < 0) { diff = -diff; } } outputMetricFile.setValue(i, currentColumn, diff); } // // Next output column // currentColumn++; } } try { // // Write the metric file // outputMetricFile.writeFile(outputMetricShapeFileName); } catch (FileException& e) { throw BrainModelAlgorithmException(e); } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceMetricGradient.h0000664000175000017500000000753311572067322026235 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_METRIC_GRADIENT_H__ #define __BRAIN_MODEL_SURFACE_METRIC_GRADIENT_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelAlgorithm.h" class CoordinateFile; class MetricFile; class VectorFile; class TopologyHelper; /// class for create a functional volume using a probabilistic volume class BrainModelSurfaceMetricGradient : public BrainModelAlgorithm { public: /// Constructor for execution on single column BrainModelSurfaceMetricGradient(BrainSet* bs, int bsIndexIn, MetricFile* valuesIn, int metricIndexIn, VectorFile* gradOutIn, MetricFile* gradMagOutIn, int magOutIndexIn, bool avgNormalsIn = false); /// Constructor for execution of all columns BrainModelSurfaceMetricGradient(BrainSet* bs, int bsIndexIn, MetricFile* valuesIn, MetricFile* gradMagOutIn, bool avgNormalsIn, bool parallelFlagIn); /// Destructor ~BrainModelSurfaceMetricGradient(); /// execute the algorithm void execute() throw (BrainModelAlgorithmException); private: /// execute on single metric column void executeSingleColumn() throw (BrainModelAlgorithmException); /// execute the all metric columns void executeAllColumns() throw (BrainModelAlgorithmException); /// process single column void processSingleColumn(const TopologyHelper* topoHelper, const float* allnormals, const float* sourceData, const int columnIndex, const int numNodes) throw (BrainModelAlgorithmException); void initialize(); bool allColumnsFlag; bool parallelFlag; int setIndex, metricIndex, magOutIndex, depth; MetricFile* values, *gradMagOut; VectorFile* gradOut; bool avgNormals; void crossProd(const float in1[3], const double in2[3], double out[3]); void crossProd(const double in1[3], const double in2[3], double out[3]); double dotProd(const double in1[3], const double in2[3]); double dotProd(const float in1[3], const double in2[3]); void normalize(double in[3]); void coordDiff(const float* coord1, const float* coord2, double out[3]); void calcrref(double* matrix[], int rows, int cols); double det3(double* matrix[], int column); bool haveWarned; bool haveFailed; }; #endif // __BRAIN_MODEL_SURFACE_METRIC_GRADIENT_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceMetricGradient.cxx0000664000175000017500000005713011572067322026606 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurfaceMetricGradient.h" #include "BrainSet.h" #include "BrainModelSurface.h" #include "CoordinateFile.h" #include "TopologyFile.h" #include "TopologyHelper.h" #include "VectorFile.h" #include "MetricFile.h" #include #include #ifdef _OPENMP #include #endif void BrainModelSurfaceMetricGradient::crossProd(const float in1[3], const double in2[3], double out[3]) {//avoid loops for speed out[0] = in1[1] * in2[2] - in1[2] * in2[1]; out[1] = in1[2] * in2[0] - in1[0] * in2[2]; out[2] = in1[0] * in2[1] - in1[1] * in2[0]; } void BrainModelSurfaceMetricGradient::crossProd(const double in1[3], const double in2[3], double out[3]) {//avoid loops for speed out[0] = in1[1] * in2[2] - in1[2] * in2[1]; out[1] = in1[2] * in2[0] - in1[0] * in2[2]; out[2] = in1[0] * in2[1] - in1[1] * in2[0]; } double BrainModelSurfaceMetricGradient::dotProd(const double in1[3], const double in2[3]) { return in1[0] * in2[0] + in1[1] * in2[1] + in1[2] * in2[2]; } double BrainModelSurfaceMetricGradient::dotProd(const float in1[3], const double in2[3]) { return in1[0] * in2[0] + in1[1] * in2[1] + in1[2] * in2[2]; } void BrainModelSurfaceMetricGradient::normalize(double in[3]) { double mag = sqrt(in[0] * in[0] + in[1] * in[1] + in[2] * in[2]); in[0] /= mag; in[1] /= mag; in[2] /= mag; } void BrainModelSurfaceMetricGradient::coordDiff(const float* coord1, const float* coord2, double out[3]) { out[0] = coord1[0] - coord2[0]; out[1] = coord1[1] - coord2[1]; out[2] = coord1[2] - coord2[2]; } void BrainModelSurfaceMetricGradient::calcrref(double* matrix[], int rows, int cols) {//assumes more cols than rows int i, j, k, temp; double tempd, tempd2; for (i = 0; i < rows; ++i) { tempd = std::abs(matrix[i][i]);//search for pivot temp = i; for (j = i + 1; j < rows; ++j) { tempd2 = std::abs(matrix[j][i]); if (tempd2 > tempd) { tempd = tempd2; temp = j; } } if (i != temp) { for (j = i; j < cols; ++j) {//skip the waste that will end up 0's and 1's tempd = matrix[i][j]; matrix[i][j] = matrix[temp][j]; matrix[temp][j] = tempd; } } tempd = matrix[i][i];//pivot for (j = i + 1; j < cols; ++j) {//again, skip the 0's and 1's matrix[i][j] /= tempd; for (k = 0; k < i; ++k) { matrix[k][j] -= matrix[k][i] * matrix[i][j]; } for (++k; k < rows; ++k) { matrix[k][j] -= matrix[k][i] * matrix[i][j]; } } }//rref complete for all cols >= rows, just pretend rowsXrows is I } double BrainModelSurfaceMetricGradient::det3(double* matrix[], int column) {//diagonals trick for 3x3, unrolled int column1 = column + 1, column2 = column + 2; double ret = matrix[0][column] * matrix[1][column1] * matrix[2][column2]; ret += matrix[1][column] * matrix[2][column1] * matrix[0][column2]; ret += matrix[2][column] * matrix[0][column1] * matrix[1][column2]; ret -= matrix[2][column] * matrix[1][column1] * matrix[0][column2]; ret -= matrix[1][column] * matrix[0][column1] * matrix[2][column2]; ret -= matrix[0][column] * matrix[2][column1] * matrix[1][column2]; return ret; } /** * Constructor. */ BrainModelSurfaceMetricGradient::BrainModelSurfaceMetricGradient( BrainSet* bs, int bsIndexIn, MetricFile* valuesIn, int metricIndexIn, VectorFile* gradOutIn, MetricFile* gradMagOutIn, int magOutIndexIn, bool avgNormalsIn) : BrainModelAlgorithm(bs) { initialize(); setIndex = bsIndexIn; values = valuesIn; metricIndex = metricIndexIn; gradOut = gradOutIn; gradMagOut = gradMagOutIn; magOutIndex = magOutIndexIn; avgNormals = avgNormalsIn; } /** * Constructor for execution of all columns. */ BrainModelSurfaceMetricGradient::BrainModelSurfaceMetricGradient(BrainSet* bs, int bsIndexIn, MetricFile* valuesIn, MetricFile* gradMagOutIn, bool avgNormalsIn, bool parallelFlagIn) : BrainModelAlgorithm(bs) { initialize(); setIndex = bsIndexIn; values = valuesIn; gradMagOut = gradMagOutIn; avgNormals = avgNormalsIn; allColumnsFlag = true; parallelFlag = parallelFlagIn; } /** * Destructor. */ BrainModelSurfaceMetricGradient::~BrainModelSurfaceMetricGradient() { } void BrainModelSurfaceMetricGradient::initialize() { allColumnsFlag = false; parallelFlag = false; haveWarned = false; haveFailed = false; } /** * execute the algorithm. */ void BrainModelSurfaceMetricGradient::execute() throw (BrainModelAlgorithmException) { if (allColumnsFlag) { executeAllColumns(); } else { executeSingleColumn(); } } /** * execute the algorithm on a single metric column. */ void BrainModelSurfaceMetricGradient::executeSingleColumn() throw (BrainModelAlgorithmException) { // // Verify files exist, are valid, etc. // BrainModelSurface* mysurf = brainSet->getBrainModelSurface(setIndex);//reference CoordinateFile* source = mysurf->getCoordinateFile();//reference TopologyFile* topo = mysurf->getTopologyFile(); const TopologyHelper* myhelper = topo->getTopologyHelper(false, true, false); mysurf->computeNormals(); mysurf->orientNormalsOut(); if (source == NULL) { throw BrainModelAlgorithmException("Invalid coordinate file."); } if (values == NULL) { throw BrainModelAlgorithmException("Invalid metric file."); } if (source->getNumberOfCoordinates() < 1) { throw BrainModelAlgorithmException("Not enough nodes in coordinate file."); } if (source->getNumberOfCoordinates() != values->getNumberOfNodes()) { throw BrainModelAlgorithmException("Node numbers do not match."); } // // Check output files exist // bool saveMag = true, saveVec = true; if (gradMagOut == NULL) { saveMag = false; } else { if (source->getNumberOfCoordinates() != gradMagOut->getNumberOfNodes()) { gradMagOut->setNumberOfNodesAndColumns(source->getNumberOfCoordinates(), 1);//clear existing data because node numbers don't match magOutIndex = 0; } if (magOutIndex < 0 || magOutIndex >= gradMagOut->getNumberOfColumns()) { magOutIndex = gradMagOut->getNumberOfColumns(); gradMagOut->addColumns(1); } gradMagOut->setColumnName(magOutIndex, "surface gradient"); } if (gradOut == NULL) { saveVec = false; } else { if (source->getNumberOfCoordinates() != gradOut->getNumberOfVectors()) { gradOut->setNumberOfVectors(source->getNumberOfCoordinates()); } } if (!saveMag && !saveVec) { throw BrainModelAlgorithmException("No valid output file."); } int numNodes = source->getNumberOfCoordinates(); int i, j, k, numNeigh, whichnode; double xhat[3], yhat[3], somevec[3]; float nodemetric, somevecf[3]; double xmag, ymag,tempd, sanity; double* rrefb[3]; float* sourceData = new float[numNodes * 3]; source->getAllCoordinates(sourceData); float* metricData = new float[numNodes]; float* magData = NULL; std::vector neighbors; if (saveMag) { magData = new float[numNodes]; } values->getColumnForAllNodes(metricIndex, metricData); rrefb[0] = new double[4]; rrefb[1] = new double[4]; rrefb[2] = new double[4]; float* allnormals = new float[numNodes * 3]; for (i = 0; i < numNodes; ++i) { j = i * 3; const float* mynormal = mysurf->getNormal(i); allnormals[j] = mynormal[0]; allnormals[j + 1] = mynormal[1]; allnormals[j + 2] = mynormal[2]; } if (avgNormals) {//assume normals have identical length for (i = 0; i < numNodes; ++i) { const float* mynormal = mysurf->getNormal(i); myhelper->getNodeNeighbors(i, neighbors); numNeigh = neighbors.size(); for (j = 0; j < numNeigh; ++j) { k = neighbors[j] * 3; allnormals[k] += mynormal[0]; allnormals[k + 1] += mynormal[1]; allnormals[k + 2] += mynormal[2]; } } }//WARNING: normals are not normalized, nor identical length - below algorithm normalizes after every use of a normal though for (i = 0; i < numNodes; ++i) { float* mynormal = allnormals + i * 3; 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; } crossProd(mynormal, somevec, xhat); normalize(xhat);//use cross products to generate a 2d coordinate system orthogonal to normal crossProd(mynormal, xhat, yhat); normalize(yhat);//xhat, yhat are orthogonal unit vectors describing the coord system with k = surface normal for (j = 0; j < 4; ++j) { rrefb[0][j] = 0.0; rrefb[1][j] = 0.0; rrefb[2][j] = 0.0; } nodemetric = metricData[i];//uses metric difference for 2 reasons: makes rref cumulate smaller values, and makes root node not matter to calculation myhelper->getNodeNeighbors(i, neighbors);//intelligently detects depth == 1 (and invalid depth) numNeigh = neighbors.size(); if (numNeigh >= 2)//dont attempt regression if the system is underdetermined { for (j = 0; j < numNeigh; ++j) { whichnode = neighbors[j]; tempd = metricData[whichnode] - nodemetric;//metric difference coordDiff(&sourceData[whichnode * 3], &sourceData[i * 3], somevec);//position delta vector xmag = dotProd(xhat, somevec);//project to 2d plane tangent to surface ymag = dotProd(yhat, somevec); rrefb[0][0] += xmag * xmag;//gather A'A and A'b sums for regression rrefb[0][1] += xmag * ymag; rrefb[0][2] += xmag; rrefb[1][1] += ymag * ymag; rrefb[1][2] += ymag; rrefb[2][2] += 1.0f; rrefb[0][3] += xmag * tempd; rrefb[1][3] += ymag * tempd; rrefb[2][3] += tempd; } rrefb[1][0] = rrefb[0][1];//complete the symmetric elements rrefb[2][0] = rrefb[0][2]; rrefb[2][1] = rrefb[1][2]; rrefb[2][2] += 1.0f;//include center (metric and coord differences will be zero, so this is all that is needed) calcrref(rrefb, 3, 4); somevecf[0] = (float)(somevec[0] = xhat[0] * rrefb[0][3] + yhat[0] * rrefb[1][3]); somevecf[1] = (float)(somevec[1] = xhat[1] * rrefb[0][3] + yhat[1] * rrefb[1][3]); somevecf[2] = (float)(somevec[2] = xhat[2] * rrefb[0][3] + yhat[2] * rrefb[1][3]);//somevec is now our surface gradient sanity = somevec[0] + somevec[1] + somevec[2]; } if (numNeigh < 2 || !(sanity == sanity)) { if (!haveWarned) std::cerr << "WARNING: gradient calculation found a NaN/inf with regression method" << endl; haveWarned = true; if (numNeigh != 0) { somevecf[0] = 0.0f; somevecf[1] = 0.0f; somevecf[2] = 0.0f; somevec[0] = 0.0; somevec[1] = 0.0; somevec[2] = 0.0; for (j = 0; j < numNeigh; ++j) { whichnode = neighbors[j]; coordDiff(&sourceData[whichnode * 3], &sourceData[i * 3], xhat);//xhat repurposed as a temp variable for (k = 0; k < 3; ++k) yhat[k] = xhat[k]; normalize(xhat); tempd = (metricData[whichnode] - nodemetric) / sqrt(yhat[0] * yhat[0] + yhat[1] * yhat[1] + yhat[2] * yhat[2]);//difference over distance gives gradient magnitude for (k = 0; k < 3; ++k) somevec[k] += tempd * xhat[k];//magnitude times unit vector parallel to distance vector gives crude estimate } for (j = 0; j < 3; ++j) { somevec[j] /= numNeigh;//now we have the 3d gradient, time to subtract the dot product with normal xhat[j] = mynormal[j]; } normalize(xhat);//for sanity, in case your normals aren't unit vectors somehow tempd = dotProd(somevec, xhat); sanity = 0.0; for (j = 0; j < 3; ++j) sanity += (somevecf[j] = (float)(somevec[j] -= tempd * xhat[j])); } if (numNeigh == 0 || !(sanity == sanity)) { if (!haveFailed) { std::cerr << "WARNING: gradient calculation found a NaN/inf with fallback method, outputting ZERO" << endl; std::cerr << "check your coordinate/topo files for isolated nodes and nodes with identical coords" << endl; } haveFailed = true; somevecf[0] = 0.0f; somevecf[1] = 0.0f; somevecf[2] = 0.0f; somevec[0] = 0.0; somevec[1] = 0.0; somevec[2] = 0.0; } } if (saveVec) { gradOut->setVectorOrigin(i, &sourceData[i * 3]); gradOut->setVectorUnitComponents(i, somevecf);//gradient complete! } if (saveMag) { magData[i] = (float)sqrt(somevec[0] * somevec[0] + somevec[1] * somevec[1] + somevec[2] * somevec[2]); } } if (saveMag) { gradMagOut->setColumnForAllNodes(magOutIndex, magData); delete[] magData; } delete[] sourceData; delete[] metricData; delete[] rrefb[0]; delete[] rrefb[1]; delete[] rrefb[2]; delete[] allnormals; } /** * execute the all metric columns. */ void BrainModelSurfaceMetricGradient::executeAllColumns() throw (BrainModelAlgorithmException) { // // Verify files exist, are valid, etc. // BrainModelSurface* mysurf = brainSet->getBrainModelSurface(setIndex);//reference CoordinateFile* source = mysurf->getCoordinateFile();//reference TopologyFile* topo = mysurf->getTopologyFile(); const TopologyHelper* myhelper = topo->getTopologyHelper(false, true, false); mysurf->computeNormals(); mysurf->orientNormalsOut(); if (source == NULL) { throw BrainModelAlgorithmException("Invalid coordinate file."); } if (values == NULL) { throw BrainModelAlgorithmException("Invalid metric file."); } if (source->getNumberOfCoordinates() < 1) { throw BrainModelAlgorithmException("Not enough nodes in coordinate file."); } if (source->getNumberOfCoordinates() != values->getNumberOfNodes()) { throw BrainModelAlgorithmException("Node numbers do not match."); } int numNodes = source->getNumberOfCoordinates(); int numColumns = values->getNumberOfColumns(); float* allnormals = new float[numNodes * 3]; for (int i = 0; i < numNodes; ++i) { int j = i * 3; const float* mynormal = mysurf->getNormal(i); allnormals[j] = mynormal[0]; allnormals[j + 1] = mynormal[1]; allnormals[j + 2] = mynormal[2]; } std::vector neighbors; if (avgNormals) {//assume normals have identical length for (int i = 0; i < numNodes; ++i) { const float* mynormal = mysurf->getNormal(i); myhelper->getNodeNeighbors(i, neighbors); const int numNeigh = neighbors.size(); for (int j = 0; j < numNeigh; ++j) { int k = neighbors[j] * 3; allnormals[k] += mynormal[0]; allnormals[k + 1] += mynormal[1]; allnormals[k + 2] += mynormal[2]; } } }//WARNING: normals are not normalized, nor identical length - below algorithm normalizes after every use of a normal though float* sourceData = new float[numNodes * 3]; source->getAllCoordinates(sourceData); if (parallelFlag) { #pragma omp parallel for for (int i = 0; i < numColumns; i++) { processSingleColumn(myhelper, allnormals, sourceData, i, numNodes); } } else { for (int i = 0; i < numColumns; i++) { processSingleColumn(myhelper, allnormals, sourceData, i, numNodes); } } delete[] allnormals; delete[] sourceData; } /** * process single column. */ void BrainModelSurfaceMetricGradient::processSingleColumn(const TopologyHelper* myhelper, const float* allnormals, const float* sourceData, const int columnIndex, const int numNodes) throw (BrainModelAlgorithmException) { double xhat[3], yhat[3], somevec[3]; float nodemetric, somevecf[3]; double xmag, ymag,tempd, sanity; double* rrefb[3]; float* metricData = new float[numNodes]; float* magData = new float[numNodes]; rrefb[0] = new double[4]; rrefb[1] = new double[4]; rrefb[2] = new double[4]; std::vector neighbors; values->getColumnForAllNodes(columnIndex, metricData); for (int i = 0; i < numNodes; ++i) { const float* mynormal = allnormals + i * 3; 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; } crossProd(mynormal, somevec, xhat); normalize(xhat);//use cross products to generate a 2d coordinate system orthogonal to normal crossProd(mynormal, xhat, yhat); normalize(yhat);//xhat, yhat are orthogonal unit vectors describing the coord system with k = surface normal for (int j = 0; j < 4; ++j) { rrefb[0][j] = 0.0; rrefb[1][j] = 0.0; rrefb[2][j] = 0.0; } nodemetric = metricData[i];//uses metric difference for 2 reasons: makes rref cumulate smaller values, and makes root node not matter to calculation myhelper->getNodeNeighbors(i, neighbors);//intelligently detects depth == 1 (and invalid depth) const int numNeigh = neighbors.size(); if (numNeigh >= 2)//dont attempt regression if the system is underdetermined { for (int j = 0; j < numNeigh; ++j) { const int whichnode = neighbors[j]; tempd = metricData[whichnode] - nodemetric;//metric difference coordDiff(&sourceData[whichnode * 3], &sourceData[i * 3], somevec);//position delta vector xmag = dotProd(xhat, somevec);//project to 2d plane tangent to surface ymag = dotProd(yhat, somevec); rrefb[0][0] += xmag * xmag;//gather A'A and A'b sums for regression rrefb[0][1] += xmag * ymag; rrefb[0][2] += xmag; rrefb[1][1] += ymag * ymag; rrefb[1][2] += ymag; rrefb[2][2] += 1.0f; rrefb[0][3] += xmag * tempd; rrefb[1][3] += ymag * tempd; rrefb[2][3] += tempd; } rrefb[1][0] = rrefb[0][1];//complete the symmetric elements rrefb[2][0] = rrefb[0][2]; rrefb[2][1] = rrefb[1][2]; rrefb[2][2] += 1.0f;//include center (metric and coord differences will be zero, so this is all that is needed) calcrref(rrefb, 3, 4); somevecf[0] = (float)(somevec[0] = xhat[0] * rrefb[0][3] + yhat[0] * rrefb[1][3]); somevecf[1] = (float)(somevec[1] = xhat[1] * rrefb[0][3] + yhat[1] * rrefb[1][3]); somevecf[2] = (float)(somevec[2] = xhat[2] * rrefb[0][3] + yhat[2] * rrefb[1][3]);//somevec is now our surface gradient sanity = somevec[0] + somevec[1] + somevec[2]; } if (numNeigh < 2 || !(sanity == sanity)) { if (!haveWarned) std::cerr << "WARNING: gradient calculation found a NaN/inf with regression method" << endl; haveWarned = true; if (numNeigh != 0) { somevecf[0] = 0.0f; somevecf[1] = 0.0f; somevecf[2] = 0.0f; somevec[0] = 0.0; somevec[1] = 0.0; somevec[2] = 0.0; for (int j = 0; j < numNeigh; ++j) { const int whichnode = neighbors[j]; coordDiff(&sourceData[whichnode * 3], &sourceData[i * 3], xhat);//xhat repurposed as a temp variable for (int k = 0; k < 3; ++k) yhat[k] = xhat[k]; normalize(xhat); tempd = (metricData[whichnode] - nodemetric) / sqrt(yhat[0] * yhat[0] + yhat[1] * yhat[1] + yhat[2] * yhat[2]);//difference over distance gives gradient magnitude for (int k = 0; k < 3; ++k) somevec[k] += tempd * xhat[k];//magnitude times unit vector parallel to distance vector gives crude estimate } for (int j = 0; j < 3; ++j) { somevec[j] /= numNeigh;//now we have the 3d gradient, time to subtract the dot product with normal xhat[j] = mynormal[j]; } normalize(xhat);//for sanity, in case your normals aren't unit vectors somehow tempd = dotProd(somevec, xhat); sanity = 0.0; for (int j = 0; j < 3; ++j) sanity += (somevecf[j] = (float)(somevec[j] -= tempd * xhat[j])); } if (numNeigh == 0 || !(sanity == sanity)) { if (!haveFailed) { std::cerr << "WARNING: gradient calculation found a NaN/inf with fallback method, outputting ZERO" << endl; std::cerr << "check your coordinate/topo files for isolated nodes and nodes with identical coords" << endl; } haveFailed = true; somevecf[0] = 0.0f; somevecf[1] = 0.0f; somevecf[2] = 0.0f; somevec[0] = 0.0; somevec[1] = 0.0; somevec[2] = 0.0; } } magData[i] = (float)sqrt(somevec[0] * somevec[0] + somevec[1] * somevec[1] + somevec[2] * somevec[2]); } gradMagOut->setColumnForAllNodes(columnIndex, magData); gradMagOut->setColumnName(columnIndex, "surface gradient"); delete[] magData; delete[] metricData; delete[] rrefb[0]; delete[] rrefb[1]; delete[] rrefb[2]; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceMetricFullWidthHalfMaximum.h0000664000175000017500000000435111572067322030526 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_METRIC_FULL_WIDTH_HALF_MAXIMUM_H__ #define __BRAIN_MODEL_SURFACE_METRIC_FULL_WIDTH_HALF_MAXIMUM_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelAlgorithm.h" class BrainModelSurface; class MetricFile; /// determine the full width half maximum for a metric column class BrainModelSurfaceMetricFullWidthHalfMaximum : public BrainModelAlgorithm { public: // constructor BrainModelSurfaceMetricFullWidthHalfMaximum(BrainSet* bs, BrainModelSurface* brainModelSurfaceIn, MetricFile* metricFileIn, const int metricColumnIn); // destructor ~BrainModelSurfaceMetricFullWidthHalfMaximum(); // execute the algorithm void execute() throw (BrainModelAlgorithmException); // get the resulting full width half maximum measurement float getFullWidthHalfMaximum() const { return fullWidthHalfMaximum; } protected: // the surface on which to smooth BrainModelSurface* brainModelSurface; // the metric file to smooth MetricFile* metricFile; // metric column int metricColumn; // the full width half maximum float fullWidthHalfMaximum; }; #endif // __BRAIN_MODEL_SURFACE_METRIC_FULL_WIDTH_HALF_MAXIMUM_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceMetricFullWidthHalfMaximum.cxx0000664000175000017500000001755111572067322031107 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainModelSurface.h" #include "BrainModelSurfaceMetricFullWidthHalfMaximum.h" #include "CoordinateFile.h" #include "MathUtilities.h" #include "MetricFile.h" #include "StatisticMeanAndDeviation.h" #include "TopologyFile.h" #include "TopologyHelper.h" /** * constructor. */ BrainModelSurfaceMetricFullWidthHalfMaximum::BrainModelSurfaceMetricFullWidthHalfMaximum( BrainSet* bs, BrainModelSurface* brainModelSurfaceIn, MetricFile* metricFileIn, const int metricColumnIn) : BrainModelAlgorithm(bs) { fullWidthHalfMaximum = 0.0; brainModelSurface = brainModelSurfaceIn; metricFile = metricFileIn; metricColumn = metricColumnIn; } /** * destructor. */ BrainModelSurfaceMetricFullWidthHalfMaximum::~BrainModelSurfaceMetricFullWidthHalfMaximum() { } /** * Execute the algorithm. * * This algorithm is from: * Smoothing and cluster thresholding for cortical surface-based group analysis of fMRI data * Donald J. Hagler Jr., Ayse Pinar Saygin, and Martin I. Sereno * NeuroImage 33 (2006) 1093-1103 * * Full Width Half Maximum (FWHM) is computed using formula 2 * on page 1094 of the above paper. */ void BrainModelSurfaceMetricFullWidthHalfMaximum::execute() throw (BrainModelAlgorithmException) { fullWidthHalfMaximum = 0.0; // // Check inputs // if (brainModelSurface == NULL) { throw BrainModelAlgorithmException("Surface is NULL."); } if (metricFile == NULL) { throw BrainModelAlgorithmException("Surface is NULL."); } const int numNodes = brainModelSurface->getNumberOfNodes(); if (numNodes <= 0) { throw BrainModelAlgorithmException("Surface contains no nodes."); } if (metricFile->getNumberOfNodes() != numNodes) { throw BrainModelAlgorithmException("Surface and metric file contain a different number of nodes."); } if ((metricColumn < 0) || (metricColumn >= metricFile->getNumberOfColumns())) { throw BrainModelAlgorithmException("Metric column is invalid."); } // // Get topology file and topology helper // const TopologyFile* tf = brainModelSurface->getTopologyFile(); if (tf == NULL) { throw BrainModelAlgorithmException("Surface has no topology."); } const TopologyHelper* th = tf->getTopologyHelper(false, true, false); // // Get distance between each node and its neighbors // and the metric differences // USE ABSOLUTE VALUE FOR METRIC DIFFERENCES??? // const CoordinateFile*cf = brainModelSurface->getCoordinateFile(); std::vector nodeToNeighborEuclideanDistances; std::vector nodeToNeighborMetricDifferences; std::vector nodeMetricValues; for (int myNodeNumber = 0; myNodeNumber < numNodes; myNodeNumber++) { int numNeighbors = 0; const int* neighbors = th->getNodeNeighbors(myNodeNumber, numNeighbors); // // Node is connected?? // if (numNeighbors > 0) { const float* myXYZ = cf->getCoordinate(myNodeNumber); const float myMetric = metricFile->getValue(myNodeNumber, metricColumn); nodeMetricValues.push_back(myMetric); for (int neighborIndex = 0; neighborIndex < numNeighbors; neighborIndex++) { const int neighborNodeNumber = neighbors[neighborIndex]; if (myNodeNumber < neighborNodeNumber) { // avoid counting distance twice // // Inter neighbor distances // nodeToNeighborEuclideanDistances.push_back( MathUtilities::distance3D(myXYZ, cf->getCoordinate(neighborNodeNumber))); // // Inter neighbor metric differences // float metricDiff = myMetric - metricFile->getValue(neighborNodeNumber, metricColumn); //metricDiff = std::fabs(metricDiff); nodeToNeighborMetricDifferences.push_back(metricDiff); } } } } // // Mean and Sample Variance for node to neighbor euclidean distances // StatisticMeanAndDeviation interNeighborMeanAndDeviation; interNeighborMeanAndDeviation.addDataArray(&nodeToNeighborEuclideanDistances[0], static_cast(nodeToNeighborEuclideanDistances.size())); try { interNeighborMeanAndDeviation.execute(); } catch (StatisticException& e) { throw BrainModelAlgorithmException(e); } // // "dv" is average neighbor inter-distance // const double dv = interNeighborMeanAndDeviation.getMean(); // // Mean and Sample Variance for node to neighbor metric differences // StatisticMeanAndDeviation metricDifferenceMeanAndDeviation; metricDifferenceMeanAndDeviation.addDataArray(&nodeToNeighborMetricDifferences[0], static_cast(nodeToNeighborMetricDifferences.size())); try { metricDifferenceMeanAndDeviation.execute(); } catch (StatisticException& e) { throw BrainModelAlgorithmException(e); } // // "varDS" is the variance of the metric inter-neighbor differences // const double varDS = metricDifferenceMeanAndDeviation.getPopulationSampleVariance(); // // Sample Variance for node metric values // StatisticMeanAndDeviation metricMeanAndDeviation; metricMeanAndDeviation.addDataArray(&nodeMetricValues[0], static_cast(nodeMetricValues.size())); try { metricMeanAndDeviation.execute(); } catch (StatisticException& e) { throw BrainModelAlgorithmException(e); } // // "varS" is the variance of the all nodes' metric values // const double varS = metricMeanAndDeviation.getPopulationSampleVariance(); // // Equation from code MRISgaussFWHM // Same results as code that duplicates equation in paper // /* if (varS != 0) { double varratio = -std::log(1.0 - 0.5 * (varDS / varS)); if (varratio <= 0.0) { varratio = 0.5 * (varDS / varS); } if (varratio <= 0.0) { fullWidthHalfMaximum = 0.0; } else { fullWidthHalfMaximum = std::sqrt(2.0 * std::log(2) / varratio) * dv; } } */ // // Calculate FWHM // Exactly as in equation in paper // if (varS != 0.0) { const double denom = std::log((double)(1.0 - (varDS / (2.0 * varS)))); if (denom != 0.0) { const double val = (-2.0 * std::log(2.0)) / denom; if (val >= 0.0) { fullWidthHalfMaximum = dv * std::sqrt(val); //std::cout << "Paper Equation: " << XXXfullWidthHalfMaximum // << " Hagler Code: " << fullWidthHalfMaximum << std::endl; } } } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceMetricFindClustersBase.h0000664000175000017500000002202111572067322027665 0ustar michaelmichael#ifndef __BRAIN_MODEL_SURFACE_SHAPE_FIND_CLUSTERS_BASE_H__ #define __BRAIN_MODEL_SURFACE_SHAPE_FIND_CLUSTERS_BASE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainModelAlgorithm.h" class BrainModelSurface; class BrainModelSurfaceMetricClustering; class MetricFile; class QTextStream; /// base class for finding clusters in surface shape files class BrainModelSurfaceMetricFindClustersBase : public BrainModelAlgorithm { public: // constructor BrainModelSurfaceMetricFindClustersBase(BrainSet* bs, const QString& fiducialCoordFileNameIn, const QString& openTopoFileNameIn, const QString& distortionShapeFileNameIn, const QString& statisticalMapFileNameIn, const QString& shuffledStatisticalMapFileNameIn, const QString& clustersPaintFileNameIn, const QString& clustersMetricFileNameIn, const QString& reportFileNameIn, const int distortionShapeFileColumnIn, const float negativeThreshIn, const float positiveThreshIn, const float pValueIn, const int tVarianceSmoothingIterationsIn, const float tVarianceSmoothingStrengthIn, const bool doStatisticalMapDOFIn, const bool doStatisticalMapPValueIn, const int numberOfThreadsIn); // destructor ~BrainModelSurfaceMetricFindClustersBase(); // execute the algorithm void execute() throw (BrainModelAlgorithmException); protected: /// class for cluster thresholding class Cluster { public: QString name; int column; int numberOfNodes; std::vector nodes; float area; float areaCorrected; float cogX; float cogY; float cogZ; float pValue; float threshMin; float threshMax; /// constructor Cluster() { name = ""; column = -1; numberOfNodes = 0; area = 0.0; areaCorrected = 0.0; cogX = 0.0; cogY = 0.0; cogZ = 0.0; pValue = -1.0; threshMin = 0.0; threshMax = 0.0; nodes.clear(); } /// comparison operator using area corrected bool operator<(const Cluster& c) const { return (areaCorrected < c.areaCorrected); } /// set the name of a cluster void setName() { name = ""; if (threshMax < 0.0) { name += "minus_"; } else { name += "plus_"; } name += "cluster_area_"; name += QString::number(areaCorrected, 'f', 1); name += "_nodes_"; name += QString::number(numberOfNodes); } }; /// must be implemented by subclasses virtual void executeClusterSearch() throw (BrainModelAlgorithmException) = 0; // free memory virtual void cleanUp(); // find clusters in shape file void findClusters(MetricFile* mf, std::vector& clustersOut, const QString& progressMessage, const int limitToColumn, const bool useLargestClusterPerColumnFlag) throw (BrainModelAlgorithmException); // find clusters void findClustersSingleThread(MetricFile* mf, std::vector& clustersOut, const QString& progressMessage, const int limitToColumn, const bool useLargestClusterPerColumnFlag) throw (BrainModelAlgorithmException); // find clusters in shape file using multiple threads void findClustersMultiThread(MetricFile* mf, std::vector& clustersOut, const QString& progressMessage, const int limitToColumn, const bool useLargestClusterPerColumnFlag, const int numberOfThreads) throw (BrainModelAlgorithmException); /// Get the clusters after the cluster finding algorithm has finished void saveClusters(BrainModelSurfaceMetricClustering* bmsmc, std::vector& clustersOut, const int columnNumber, const bool useLargestClusterPerColumnFlag); // set randomized cluster p-values void setRandomizedClusterPValues(const MetricFile& randomFile, std::vector& randomClusters); // print the clusters void printClusters(QTextStream& stream, const std::vector& clusters, const float sigArea = -1.0); /// create the clusters paint file void createClustersPaintFile(const std::vector& clusters, const float sigArea, const int numNodes); /// create the clusters metric file void createClustersMetricFile(const std::vector& clusters, const int statisticalMapColumn, const int numNodes); /// set names of all clusters void setNamesForClusters(std::vector& clusters); /// create the clusters report file void createMetricShapeClustersReportFile(const std::vector& clusters, const QString& metricShapeFileName); /// name of fiducial coord file QString fiducialCoordFileName; /// name of open topo file QString openTopoFileName; /// name of area correction shape file QString areaCorrectionShapeFileName; /// name of Statistical Map file QString statisticalMapFileName; /// name of shuffled Statistical map file QString shuffledStatisticalMapFileName; /// name of clusters paint file QString clustersPaintFileName; /// name of clusters metric file name QString clustersMetricFileName; /// name of report file QString reportFileName; /// area correction shape file column int areaCorrectionShapeFileColumn; /// negative threshold float negativeThresh; /// positive threshold float positiveThresh; /// P-Value float pValue; /// brain set used by this algorithm BrainSet* brain; /// surface used by this algorithm BrainModelSurface* bms; // area correction shape file MetricFile* areaCorrectionShapeFile; /// shuffled statistical map file MetricFile* shuffleStatisticalMapShapeFile; /// statistical map shape fie MetricFile* statisticalMapShapeFile; /// t-map variance smoothing iterations int tVarianceSmoothingIterations; /// t-map variance smoothing strength float tVarianceSmoothingStrength; /// compute degrees of freedom for statistical map bool doStatisticalMapDOF; /// compute p-value for statistical map bool doStatisticalMapPValue; /// number of threads for cluster search int numberOfThreads; }; #endif // __BRAIN_MODEL_SURFACE_SHAPE_FIND_CLUSTERS_BASE_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceMetricFindClustersBase.cxx0000664000175000017500000012437011572067322030252 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include "BrainModelAlgorithmRunAsThread.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceMetricClustering.h" #include "BrainModelSurfaceMetricFindClustersBase.h" #include "BrainModelSurfaceROINodeSelection.h" #include "BrainModelSurfaceROITextReport.h" #include "BrainSet.h" #include "CoordinateFile.h" #include "DebugControl.h" #include "FileUtilities.h" #include "LatLonFile.h" #include "MetricFile.h" #include "PaintFile.h" #include "SpecFile.h" #include "SurfaceShapeFile.h" #include "TextFile.h" #include "TopologyFile.h" /** * constructor. */ BrainModelSurfaceMetricFindClustersBase::BrainModelSurfaceMetricFindClustersBase( BrainSet* bs, const QString& fiducialCoordFileNameIn, const QString& openTopoFileNameIn, const QString& areaCorrectionShapeFileNameIn, const QString& statisticalMapFileNameIn, const QString& shuffledStatisticalMapFileNameIn, const QString& clustersPaintFileNameIn, const QString& clustersMetricFileNameIn, const QString& reportFileNameIn, const int areaCorrectionShapeFileColumnIn, const float negativeThreshIn, const float positiveThreshIn, const float pValueIn, const int tVarianceSmoothingIterationsIn, const float tVarianceSmoothingStrengthIn, const bool doStatisticalMapDOFIn, const bool doStatisticalMapPValueIn, const int numberOfThreadsIn) : BrainModelAlgorithm(bs) { areaCorrectionShapeFile = NULL; bms = NULL; brain = NULL; shuffleStatisticalMapShapeFile = NULL; statisticalMapShapeFile = NULL; fiducialCoordFileName = fiducialCoordFileNameIn; openTopoFileName = openTopoFileNameIn; areaCorrectionShapeFileName = areaCorrectionShapeFileNameIn; statisticalMapFileName = statisticalMapFileNameIn; shuffledStatisticalMapFileName = shuffledStatisticalMapFileNameIn; clustersPaintFileName = clustersPaintFileNameIn; clustersMetricFileName = clustersMetricFileNameIn; reportFileName = reportFileNameIn; areaCorrectionShapeFileColumn = areaCorrectionShapeFileColumnIn; negativeThresh = negativeThreshIn; positiveThresh = positiveThreshIn; pValue = pValueIn; tVarianceSmoothingIterations = tVarianceSmoothingIterationsIn; tVarianceSmoothingStrength = tVarianceSmoothingStrengthIn; doStatisticalMapDOF = doStatisticalMapDOFIn; doStatisticalMapPValue = doStatisticalMapPValueIn; numberOfThreads = numberOfThreadsIn; } /** * destructor. */ BrainModelSurfaceMetricFindClustersBase::~BrainModelSurfaceMetricFindClustersBase() { cleanUp(); } /** * execute the algorithm. */ void BrainModelSurfaceMetricFindClustersBase::execute() throw (BrainModelAlgorithmException) { // // check negative threshold // if (negativeThresh > 0.0) { throw BrainModelAlgorithmException("Negative threshold cannot be positive."); } // // check positive threshold // if (positiveThresh < 0.0) { throw BrainModelAlgorithmException("Positive threshold cannot be negative."); } // // check p-value // if ((pValue < 0.0) || (pValue > 1.0)) { throw BrainModelAlgorithmException("P-Value must be between 0.0 and 1.0."); } // // check Statistical file name // if (statisticalMapFileName.isEmpty()) { throw BrainModelAlgorithmException("Statistical Map file name is empty."); } // // check Shuffled TMap file name // if (shuffledStatisticalMapFileName.isEmpty()) { throw BrainModelAlgorithmException("Shuffled T-Map file name is empty."); } // // check Report file name // if (reportFileName.isEmpty()) { throw BrainModelAlgorithmException("Report file name is empty."); } // // Read the area correction file // areaCorrectionShapeFile = new MetricFile; try { areaCorrectionShapeFile->readFile(areaCorrectionShapeFileName); } catch (FileException &e) { std::ostringstream str; str << "Unable to read area correction shape file: " << FileUtilities::basename(areaCorrectionShapeFileName).toAscii().constData(); throw BrainModelAlgorithmException(str.str().c_str()); } if ((areaCorrectionShapeFileColumn < 0) || (areaCorrectionShapeFileColumn >= areaCorrectionShapeFile->getNumberOfColumns())) { QString msg("Invalid distortion correction column=" + QString::number(areaCorrectionShapeFileColumn)); throw BrainModelAlgorithmException(msg); } // // Create a brain set with the fiducial surface and the topology file // brain = new BrainSet(openTopoFileName, fiducialCoordFileName); if (brain == NULL) { throw BrainModelAlgorithmException("Unable to create brain set."); } if (brain->getNumberOfBrainModels() <= 0) { throw BrainModelAlgorithmException("Problem with coordinate or topology file."); } bms = brain->getBrainModelSurface(0); if (bms == NULL) { throw BrainModelAlgorithmException("Problem with coordinate or topology file."); } if (bms->getTopologyFile() == NULL) { throw BrainModelAlgorithmException("Problem with topology file."); } if (bms->getTopologyFile()->getNumberOfTiles() <= 0) { throw BrainModelAlgorithmException("Topology file has no tiles."); } const int numberOfNodes = bms->getNumberOfNodes(); if (numberOfNodes <= 0) { throw BrainModelAlgorithmException("Coordinate file has no nodes."); } // // Execute subclasses search // executeClusterSearch(); cleanUp(); } /** * find clusters. * * If limitToColumn is greater than or equal to zero, only that column of the * file will be searched for clusters. * If useOneClusterPerColumnFlag is set, only the largest cluster from each * column will be used. */ void BrainModelSurfaceMetricFindClustersBase::findClusters(MetricFile* mf, std::vector& clustersOut, const QString& progressMessage, const int limitToColumn, const bool useLargestClusterPerColumnFlag) throw (BrainModelAlgorithmException) { QTime timer; timer.start(); if(numberOfThreads <= 1) { findClustersSingleThread(mf, clustersOut, progressMessage, limitToColumn, useLargestClusterPerColumnFlag); } else { findClustersMultiThread(mf, clustersOut, progressMessage, limitToColumn, useLargestClusterPerColumnFlag, numberOfThreads); } setNamesForClusters(clustersOut); std::cout << "Cluster search with " << numberOfThreads << " threads: " << (static_cast(timer.elapsed()) / 1000.0) << " seconds." << std::endl; } /** * find clusters */ void BrainModelSurfaceMetricFindClustersBase::findClustersSingleThread(MetricFile* mf, std::vector& clustersOut, const QString& progressMessage, const int limitToColumn, const bool useLargestClusterPerColumnFlag) throw (BrainModelAlgorithmException) { float posMin = positiveThresh; float posMax = std::numeric_limits::max(); float negMin = negativeThresh; float negMax = -std::numeric_limits::max(); // // Determine columns for finding clusters // int startColumn = 0; int endColumn = mf->getNumberOfColumns() - 1; if (limitToColumn >= 0) { if (limitToColumn >= mf->getNumberOfColumns()) { std::ostringstream str; str << "Invalid column: " << limitToColumn << " for file " << FileUtilities::basename(mf->getFileName()).toAscii().constData(); throw BrainModelAlgorithmException(str.str().c_str()); } startColumn = limitToColumn; endColumn = limitToColumn; } // // Process each column // int progressCounter = 0; const int numProgress = endColumn - startColumn + 1; for (int i = startColumn; i <= endColumn; i++) { if (DebugControl::getDebugOn()) { std::cout << "Cluster analysis for column: " << i << std::endl; } progressCounter++; if (progressMessage.isEmpty() == false) { std::ostringstream str; str << progressMessage.toAscii().constData() << ": " << progressCounter << " of " << numProgress; updateProgressDialog(str.str().c_str(), -1, -1); } // // Create a shape file containing just the single column // MetricFile tempShapeFile; tempShapeFile.setNumberOfNodesAndColumns(mf->getNumberOfNodes(), 1); std::vector nodeValues; mf->getColumnForAllNodes(i, nodeValues); tempShapeFile.setColumnForAllNodes(0, nodeValues); // // Find the clusters // BrainModelSurfaceMetricClustering bmsmc(brain, bms, &tempShapeFile, BrainModelSurfaceMetricClustering::CLUSTER_ALGORITHM_MINIMUM_SURFACE_AREA, 0, 0, "cluster", 1, 0.1, negMin, negMax, posMin, posMax, true); try { bmsmc.execute(); } catch (BrainModelAlgorithmException& e) { cleanUp(); throw e; } // // Storage for the clusters // std::vector clusters; // // Node areas // std::vector nodeAreas; bms->getAreaOfAllNodes(nodeAreas); // // Process the clusters // const int numClusters = bmsmc.getNumberOfClusters(); for (int j = 0; j < numClusters; j++) { const BrainModelSurfaceMetricClustering::Cluster* cluster = bmsmc.getCluster(j); const int numNodesInCluster = cluster->getNumberOfNodesInCluster(); // // Corrected area is sum of each node's area multiplied by // 2 to the power of the selected metric column for the node // float correctedArea = 0.0; if ((areaCorrectionShapeFile != NULL) || (areaCorrectionShapeFileColumn >= 0)) { for (int k = 0; k < numNodesInCluster; k++) { const int nodeNum = cluster->getNodeInCluster(k); float nodeArea = nodeAreas[nodeNum]; const double metric = areaCorrectionShapeFile->getValue(nodeNum, areaCorrectionShapeFileColumn); correctedArea += (nodeArea * std::pow(2.0, metric)); } } // // Save the cluster information // float cog[3]; cluster->getCenterOfGravity(cog); Cluster c; c.column = i + 1; c.numberOfNodes = cluster->getNumberOfNodesInCluster(); c.nodes = cluster->getNodesInCluster(); c.area = cluster->getArea(); c.areaCorrected = correctedArea; c.cogX = cog[0]; c.cogY = cog[1]; c.cogZ = cog[2]; float threshMin, threshMax; cluster->getThresholds(threshMin, threshMax); c.threshMin = threshMin; c.threshMax = threshMax; clusters.push_back(c); } // // Should only largest cluster be used // if (useLargestClusterPerColumnFlag) { if (clusters.empty() == false) { std::sort(clusters.begin(), clusters.end()); const int largestClusterIndex = static_cast(clusters.size() - 1); clustersOut.push_back(clusters[largestClusterIndex]); } } else { clustersOut.insert(clustersOut.end(), clusters.begin(), clusters.end()); } } // // Sort clusters so biggest elements first // std::sort(clustersOut.begin(), clustersOut.end()); std::reverse(clustersOut.begin(), clustersOut.end()); } /** * Get the clusters after the cluster finding algorithm has finished */ void BrainModelSurfaceMetricFindClustersBase::saveClusters(BrainModelSurfaceMetricClustering* bmsmc, std::vector& clustersOut, const int columnNumber, const bool useLargestClusterPerColumnFlag) { // // Storage for the clusters // std::vector clusters; // // Node areas // std::vector nodeAreas; bms->getAreaOfAllNodes(nodeAreas); // // Process the clusters // const int numClusters = bmsmc->getNumberOfClusters(); for (int j = 0; j < numClusters; j++) { const BrainModelSurfaceMetricClustering::Cluster* cluster = bmsmc->getCluster(j); const int numNodesInCluster = cluster->getNumberOfNodesInCluster(); // // Corrected area is sum of each node's area multiplied by // 2 to the power of the selected metric column for the node // float correctedArea = 0.0; if ((areaCorrectionShapeFile != NULL) || (areaCorrectionShapeFileColumn >= 0)) { for (int k = 0; k < numNodesInCluster; k++) { const int nodeNum = cluster->getNodeInCluster(k); float nodeArea = nodeAreas[nodeNum]; const double metric = areaCorrectionShapeFile->getValue(nodeNum, areaCorrectionShapeFileColumn); correctedArea += (nodeArea * std::pow(2.0, metric)); } } // // Save the cluster information // float cog[3]; cluster->getCenterOfGravity(cog); Cluster c; c.column = columnNumber; c.numberOfNodes = cluster->getNumberOfNodesInCluster(); c.nodes = cluster->getNodesInCluster(); c.area = cluster->getArea(); c.areaCorrected = correctedArea; c.cogX = cog[0]; c.cogY = cog[1]; c.cogZ = cog[2]; float threshMin, threshMax; cluster->getThresholds(threshMin, threshMax); c.threshMin = threshMin; c.threshMax = threshMax; clusters.push_back(c); } // for (int j = 0; j < numClusters // // Should only largest cluster be used // if (useLargestClusterPerColumnFlag) { if (clusters.empty() == false) { std::sort(clusters.begin(), clusters.end()); const int largestClusterIndex = static_cast(clusters.size() - 1); clustersOut.push_back(clusters[largestClusterIndex]); } } else { clustersOut.insert(clustersOut.end(), clusters.begin(), clusters.end()); } } /** * find clusters */ void BrainModelSurfaceMetricFindClustersBase::findClustersMultiThread(MetricFile* mf, std::vector& clustersOut, const QString& progressMessage, const int limitToColumn, const bool useLargestClusterPerColumnFlag, const int numberOfThreads) throw (BrainModelAlgorithmException) { float posMin = positiveThresh; float posMax = std::numeric_limits::max(); float negMin = negativeThresh; float negMax = -std::numeric_limits::max(); // // Determine columns for finding clusters // int startColumn = 0; int endColumn = mf->getNumberOfColumns() - 1; if (limitToColumn >= 0) { if (limitToColumn >= mf->getNumberOfColumns()) { std::ostringstream str; str << "Invalid column: " << limitToColumn << " for file " << FileUtilities::basename(mf->getFileName()).toAscii().constData(); throw BrainModelAlgorithmException(str.str().c_str()); } startColumn = limitToColumn; endColumn = limitToColumn; } // // Next column that is to be processed // int nextColumnToProcess = startColumn; // // Time to wait for threads in milliseconds // const unsigned long totalWaitTime = 1000; // 1000 milliseconds == 1 second const unsigned long threadWaitTime = totalWaitTime / numberOfThreads; // // Pointers for algorithm threads // std::vector algorithmThreads(numberOfThreads); for (int i = 0; i < numberOfThreads; i++) { algorithmThreads[i] = NULL; } // // Column number on which thread is operating // std::vector threadColumnNumber(numberOfThreads, -1); // // One metric column per thread // std::vector metricFilesForThreads(numberOfThreads); // // Progress data // int progressCounter = 0; const int numProgress = endColumn - startColumn + 1; // // Find clusters in all selected columns // bool done = false; while (done == false) { // // Loop through the threads to see if any are done and create new threads // for (int iThread = 0; iThread < numberOfThreads; iThread++) { // // Is thread valid // if (algorithmThreads[iThread] != NULL) { // // Wait on the thread // algorithmThreads[iThread]->wait(threadWaitTime); // // Is the thread finished // if (algorithmThreads[iThread]->isFinished()) { // // Get the algorithm // BrainModelSurfaceMetricClustering* bmsmc = dynamic_cast(algorithmThreads[iThread]->getBrainModelAlgorithm()); // // Save the clusters // saveClusters(bmsmc, clustersOut, threadColumnNumber[iThread], useLargestClusterPerColumnFlag); // // delete the thread (which also deletes the algorithm) // delete algorithmThreads[iThread]; algorithmThreads[iThread] = NULL; } } // // Is the thread available ? // if (algorithmThreads[iThread] == NULL) { // // Are there still columns of data to process // if (nextColumnToProcess <= endColumn) { // // Update progress // progressCounter++; if (progressMessage.isEmpty() == false) { std::ostringstream str; str << progressMessage.toAscii().constData() << ": " << progressCounter << " of " << numProgress; updateProgressDialog(str.str().c_str(), -1, -1); } // // Set column being processed by thread (columns in report start at one) // threadColumnNumber[iThread] = nextColumnToProcess + 1; // // Copy data to the thread's metric file // metricFilesForThreads[iThread].setNumberOfNodesAndColumns(mf->getNumberOfNodes(), 1); std::vector nodeValues; mf->getColumnForAllNodes(nextColumnToProcess, nodeValues); metricFilesForThreads[iThread].setColumnForAllNodes(0, nodeValues); // // Create a new cluster finding algorithm // BrainModelSurfaceMetricClustering* clusterAlgorithm = new BrainModelSurfaceMetricClustering (brain, bms, &metricFilesForThreads[iThread], BrainModelSurfaceMetricClustering::CLUSTER_ALGORITHM_MINIMUM_SURFACE_AREA, 0, 0, "cluster", 1, 0.1, negMin, negMax, posMin, posMax, true); // // Create a new thread to run the algorithm and take ownership of cluster algorithm // algorithmThreads[iThread] = new BrainModelAlgorithmRunAsThread(clusterAlgorithm, true); algorithmThreads[iThread]->start(QThread::HighestPriority); //if (DebugControl::getDebugOn()) { std::cout << "Started thread " << iThread << " for column " << nextColumnToProcess << std::endl; //} // // Move on to next metric column // nextColumnToProcess++; } // if (nextColumnToProcess <= endColumn) } // if (algorithmThreads[iThread] == NULL) } // for (int iThread // // Loop through the threads to see if any are still valid and if time to stop // done = true; for (int iThread = 0; iThread < numberOfThreads; iThread++) { if (algorithmThreads[iThread] != NULL) { done = false; } } // // Allow other events to process // allowEventsToProcess(); } // while (done == false) // // Sort clusters so biggest elements first // std::sort(clustersOut.begin(), clustersOut.end()); std::reverse(clustersOut.begin(), clustersOut.end()); } /* void BrainModelSurfaceMetricFindClustersBase::findClustersMultiThread(MetricFile* mf, std::vector& clustersOut, const QString& progressMessage, const int limitToColumn, const bool useLargestClusterPerColumnFlag, const int numberOfThreads) throw (BrainModelAlgorithmException) { float posMin = positiveThresh; float posMax = std::numeric_limits::max(); float negMin = negativeThresh; float negMax = -std::numeric_limits::max(); // // Determine columns for finding clusters // int startColumn = 0; int endColumn = mf->getNumberOfColumns() - 1; if (limitToColumn >= 0) { if (limitToColumn >= mf->getNumberOfColumns()) { std::ostringstream str; str << "Invalid column: " << limitToColumn << " for file " << FileUtilities::basename(mf->getFileName()).toAscii().constData(); throw BrainModelAlgorithmException(str.str().c_str()); } startColumn = limitToColumn; endColumn = limitToColumn; } // // Process each column group with the size being the number of threads // int progressCounter = 0; const int numProgress = endColumn - startColumn + 1; for (int i = startColumn; i <= endColumn; i += numberOfThreads) { if (DebugControl::getDebugOn()) { std::cout << "Cluster analysis for column: " << i << std::endl; } progressCounter++; if (progressMessage.isEmpty() == false) { std::ostringstream str; str << progressMessage.toAscii().constData() << ": " << progressCounter << " of " << numProgress; updateProgressDialog(str.str().c_str(), -1, -1); } // // Create shape files for each of the threads // std::vector tempShapeFile(numberOfThreads); // // Create storage for the algorithms and the threads // std::vector clusterAlgorithms(numberOfThreads); std::vector algorithmThreads(numberOfThreads); // // Allow other events to process // allowEventsToProcess(); // // Create and start each of the threads // for (int iThread = 0; iThread < numberOfThreads; iThread++) { // // Column number being processed // const int columnNumber = i + iThread; algorithmThreads[iThread] = NULL; clusterAlgorithms[iThread] = NULL; if (columnNumber <= endColumn) { // // Create a shape file containing just the single column // tempShapeFile[iThread].setNumberOfNodesAndColumns(mf->getNumberOfNodes(), 1); std::vector nodeValues; mf->getColumnForAllNodes(columnNumber, nodeValues); tempShapeFile[iThread].setColumnForAllNodes(0, nodeValues); // // Create the cluster algorithm // clusterAlgorithms[iThread] = new BrainModelSurfaceMetricClustering (brain, bms, &tempShapeFile[iThread], BrainModelSurfaceMetricClustering::CLUSTER_ALGORITHM_MINIMUM_SURFACE_AREA, 0, 0, "cluster", 1, 0.1, negMin, negMax, posMin, posMax); // // Create the thread to run the algorithm and start it // algorithmThreads[iThread] = new BrainModelAlgorithmRunAsThread(clusterAlgorithms[iThread]); algorithmThreads[iThread]->start(); algorithmThreads[iThread]->setPriority(QThread::HighestPriority); if (DebugControl::getDebugOn()) { std::cout << "Started thread " << iThread << " for column " << columnNumber << std::endl; } } // if (columnNumber <= endColumn) } // for (int iThread // // Allow other events to process // allowEventsToProcess(); // // Wait for all of the threads to finish // for (int iThread = 0; iThread < numberOfThreads; iThread++) { if (algorithmThreads[iThread] != NULL) { algorithmThreads[iThread]->wait(); if (DebugControl::getDebugOn()) { std::cout << "Thread finished " << iThread << std::endl; } } } // for (int iThread // // Process the outputs of the cluster algorithms // for (int iThread = 0; iThread < numberOfThreads; iThread++) { if (algorithmThreads[iThread] != NULL) { // // Pointer to the cluster algorithm // BrainModelSurfaceMetricClustering* bmsmc = clusterAlgorithms[iThread]; // // Storage for the clusters // std::vector clusters; // // Process the clusters // const int numClusters = bmsmc->getNumberOfClusters(); for (int j = 0; j < numClusters; j++) { const BrainModelSurfaceMetricClustering::Cluster* cluster = bmsmc->getCluster(j); const int numNodesInCluster = cluster->getNumberOfNodesInCluster(); // // Corrected area is sum of each node's area multiplied by // 2 to the power of the selected metric column for the node // float correctedArea = 0.0; if ((areaCorrectionShapeFile != NULL) || (areaCorrectionShapeFileColumn >= 0)) { for (int k = 0; k < numNodesInCluster; k++) { const int nodeNum = cluster->getNodeInCluster(k); float nodeArea = bmsmc->getNodeArea(nodeNum); const double metric = areaCorrectionShapeFile->getValue(nodeNum, areaCorrectionShapeFileColumn); correctedArea += (nodeArea * std::pow(2.0, metric)); } } // // Save the cluster information // float cog[3]; cluster->getCenterOfGravity(cog); Cluster c; c.column = i + iThread + 1; c.numberOfNodes = cluster->getNumberOfNodesInCluster(); c.nodes = cluster->getNodesInCluster(); c.area = cluster->getArea(); c.areaCorrected = correctedArea; c.cogX = cog[0]; c.cogY = cog[1]; c.cogZ = cog[2]; float threshMin, threshMax; cluster->getThresholds(threshMin, threshMax); c.threshMin = threshMin; c.threshMax = threshMax; clusters.push_back(c); } // for (int j = 0; j < numClusters // // Should only largest cluster be used // if (useLargestClusterPerColumnFlag) { if (clusters.empty() == false) { std::sort(clusters.begin(), clusters.end()); const int largestClusterIndex = static_cast(clusters.size() - 1); clustersOut.push_back(clusters[largestClusterIndex]); } } else { clustersOut.insert(clustersOut.end(), clusters.begin(), clusters.end()); } } // if (algorithmThreads[iThread] // // Free up memory // if (algorithmThreads[iThread] != NULL) { delete algorithmThreads[iThread]; algorithmThreads[iThread] = NULL; } if (clusterAlgorithms[iThread] != NULL) { delete clusterAlgorithms[iThread]; clusterAlgorithms[iThread] = NULL; } } // for (int iThread } // for (int i = startColumn // // Sort clusters so biggest elements first // std::sort(clustersOut.begin(), clustersOut.end()); std::reverse(clustersOut.begin(), clustersOut.end()); } */ /** * Set randomized cluster p-values. */ void BrainModelSurfaceMetricFindClustersBase::setRandomizedClusterPValues( const MetricFile& randomFile, std::vector& randomClusters) { const float numberOfIterations = randomFile.getNumberOfColumns(); if (numberOfIterations <= 0.0) { return; } int numClusters = static_cast(randomClusters.size()); for (int i = 0; i < numClusters; i++) { const float pValue = (i + 1) / numberOfIterations; Cluster& cluster = randomClusters[i]; cluster.pValue = pValue; } } /** * print the clusters */ void BrainModelSurfaceMetricFindClustersBase::printClusters(QTextStream& stream, const std::vector& clusters, const float sigArea) { // 1 2 3 4 5 6 7 8 9 100 110 // 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 stream << "Column Thresh Num-Nodes Area Area-Corrected COG-X COG-Y COG-Z P-Value" << "\n"; for (std::vector::const_iterator it = clusters.begin(); it != clusters.end(); it++) { const Cluster& c = *it; if (c.areaCorrected >= sigArea) { float thresh = c.threshMin; if (thresh < 0.0) { thresh = c.threshMax; } QString str = QString("%1 %2 %3 %4 %5 %6 %7 %8") .arg(c.column, 6) .arg(thresh, 8, 'f', 3) .arg(c.numberOfNodes, 9) .arg(c.area, 12, 'f', 6) .arg(c.areaCorrected, 14, 'f', 6) .arg(c.cogX, 8, 'f', 3) .arg(c.cogY, 8, 'f', 3) .arg(c.cogZ, 8, 'f', 3); stream << str; if (c.pValue >= 0.0) { stream << QString(" %1").arg(c.pValue, 8, 'f', 6); } stream << "\n"; } } } /** * create the clusters metric file. */ void BrainModelSurfaceMetricFindClustersBase::createClustersMetricFile(const std::vector& clusters, const int statisticalMapColumn, const int numNodes) { if (clustersMetricFileName.isEmpty()) { return; } MetricFile metricFile; metricFile.setNumberOfNodesAndColumns(numNodes, 2); metricFile.setColumnName(0, statisticalMapShapeFile->getColumnName(statisticalMapColumn)); metricFile.setColumnName(1, "1 - P"); for (std::vector::const_iterator it = clusters.begin(); it != clusters.end(); it++) { const Cluster& c = *it; if (c.areaCorrected > 0) { for (int n = 0; n < c.numberOfNodes; n++) { const float q = 1.0 - c.pValue; const int nodeNum = c.nodes[n]; metricFile.setValue(nodeNum, 0, statisticalMapShapeFile->getValue(nodeNum, statisticalMapColumn)); metricFile.setValue(nodeNum, 1, q); } } } try { metricFile.writeFile(clustersMetricFileName); } catch (FileException&) { } } /** * create the clusters paint file. */ void BrainModelSurfaceMetricFindClustersBase::createClustersPaintFile(const std::vector& clusters, const float sigArea, const int numNodes) { if (clustersPaintFileName.isEmpty()) { return; } PaintFile paintFile; paintFile.setNumberOfNodesAndColumns(numNodes, 1); paintFile.setColumnName(0, "Clusters"); for (std::vector::const_iterator it = clusters.begin(); it != clusters.end(); it++) { const Cluster& c = *it; if (c.areaCorrected >= sigArea) { /* std::ostringstream str; if (c.threshMax < 0.0) { str << "minus_"; } else { str << "plus_"; } str << "cluster_area_" << c.areaCorrected << "_nodes_" << c.numberOfNodes; const int paintIndex = paintFile.addPaintName(str.str().c_str()); */ const int paintIndex = paintFile.addPaintName(c.name); for (int n = 0; n < c.numberOfNodes; n++) { paintFile.setPaint(c.nodes[n], 0, paintIndex); } } } try { paintFile.writeFile(clustersPaintFileName); } catch (FileException&) { } } /** * set names of all clusters. */ void BrainModelSurfaceMetricFindClustersBase::setNamesForClusters(std::vector& clusters) { for (std::vector::iterator it = clusters.begin(); it != clusters.end(); it++) { Cluster& c = *it; c.setName(); } } /** * create the clusters report file. */ void BrainModelSurfaceMetricFindClustersBase::createMetricShapeClustersReportFile( const std::vector& clusters, const QString& metricShapeFileName) { // // Text file for ROI report // TextFile textFile; // // Read the metric file // MetricFile inputMetricFile; try { inputMetricFile.readFile(metricShapeFileName); } catch (FileException& e) { textFile.appendLine(e.whatQString()); } // // loop through the clusters // for (std::vector::const_iterator it = clusters.begin(); it != clusters.end(); it++) { const Cluster& c = *it; // // Set nodes in ROI to nodes in cluster // BrainModelSurfaceROINodeSelection surfaceROI(brain); surfaceROI.deselectAllNodes(); for (int i = 0; i < c.numberOfNodes; i++) { surfaceROI.setNodeSelected(c.nodes[i], 1); } // // Files for input to ROI operation // MetricFile* mf = NULL; std::vector selectedMetricColumns; MetricFile* ssf = NULL; std::vector selectedShapeColumns; PaintFile* pf = NULL; std::vector selectedPaintColumns; LatLonFile* llf = NULL; int latLonFileColumn = 0; if (metricShapeFileName.endsWith(SpecFile::getSurfaceShapeFileExtension())) { ssf = &inputMetricFile; const int numCols = ssf->getNumberOfColumns(); selectedShapeColumns.resize(numCols, true); } else { mf = &inputMetricFile; const int numCols = mf->getNumberOfColumns(); selectedMetricColumns.resize(numCols, true); } if (brain->getLatLonFile()->getNumberOfColumns() > 0) { llf = brain->getLatLonFile(); } // // Perform the ROI operation // BrainModelSurfaceROITextReport bmsri(brain, bms, &surfaceROI, mf, selectedMetricColumns, ssf, selectedShapeColumns, pf, selectedPaintColumns, llf, latLonFileColumn, c.name, areaCorrectionShapeFile, areaCorrectionShapeFileColumn, false); try { bmsri.execute(); textFile.appendLine(bmsri.getReportText()); } catch (BrainModelAlgorithmException& e) { textFile.appendLine(e.whatQString()); } } // // Write the text file containing the clusters ROI report // try { const QString textFileName(FileUtilities::basename(metricShapeFileName) + ".ClusterROI_report" + SpecFile::getTextFileExtension()); textFile.writeFile(textFileName); } catch (FileException& e) { std::cout << e.whatQString().toAscii().constData() << std::endl; } } /** * Free memory. */ void BrainModelSurfaceMetricFindClustersBase::cleanUp() { if (areaCorrectionShapeFile != NULL) { delete areaCorrectionShapeFile; areaCorrectionShapeFile = NULL; } if (statisticalMapShapeFile != NULL) { delete statisticalMapShapeFile; statisticalMapShapeFile = NULL; } if (shuffleStatisticalMapShapeFile != NULL) { delete shuffleStatisticalMapShapeFile; shuffleStatisticalMapShapeFile = NULL; } if (brain != NULL) { delete brain; brain = NULL; } // // Do not delete: // // bms - it is owned by "brain" } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceMetricExtrema.h0000664000175000017500000000370011572067322026075 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_METRIC_EXTREMA_H__ #define __BRAIN_MODEL_SURFACE_METRIC_EXTREMA_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelAlgorithm.h" class MetricFile; /// class for create a functional volume using a probabilistic volume class BrainModelSurfaceMetricExtrema : public BrainModelAlgorithm { public: /// Constructor BrainModelSurfaceMetricExtrema(BrainSet* bs, int bsIndexIn, MetricFile* valuesIn, int metricIndexIn, MetricFile* extremaOutIn, int exOutIndexIn, int depthIn); /// Destructor ~BrainModelSurfaceMetricExtrema(); /// execute the algorithm void execute() throw (BrainModelAlgorithmException); private: int setIndex, metricIndex, exOutIndex, depth; MetricFile* values, *extremaOut; }; #endif // __BRAIN_MODEL_SURFACE_METRIC_EXTREMA_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceMetricExtrema.cxx0000664000175000017500000001227511572067322026457 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelVolume.h" #include "BrainModelSurfaceMetricExtrema.h" #include "BrainSet.h" #include "BrainModelSurface.h" #include "CoordinateFile.h" #include "TopologyFile.h" #include "TopologyHelper.h" #include "MetricFile.h" #include #include /** * Constructor. */ BrainModelSurfaceMetricExtrema::BrainModelSurfaceMetricExtrema( BrainSet* bs, int bsIndexIn, MetricFile* valuesIn, int metricIndexIn, MetricFile* extremaOutIn, int exOutIndexIn, int depthIn) : BrainModelAlgorithm(bs) { setIndex = bsIndexIn; values = valuesIn; metricIndex = metricIndexIn; extremaOut = extremaOutIn; exOutIndex = exOutIndexIn; depth = depthIn; } /** * Destructor. */ BrainModelSurfaceMetricExtrema::~BrainModelSurfaceMetricExtrema() { } /** * execute the algorithm. */ void BrainModelSurfaceMetricExtrema::execute() throw (BrainModelAlgorithmException) { // // Verify files exist, are valid, etc. // BrainModelSurface* mysurf = brainSet->getBrainModelSurface(setIndex);//reference CoordinateFile* source = mysurf->getCoordinateFile();//reference TopologyFile* topo = mysurf->getTopologyFile(); const TopologyHelper* myhelper = topo->getTopologyHelper(false, true, false); if (depth < 1) { depth = 1; } if (source == NULL) { throw BrainModelAlgorithmException("Invalid coordinate file."); } if (values == NULL) { throw BrainModelAlgorithmException("Invalid metric file."); } if (source->getNumberOfCoordinates() < 1) { throw BrainModelAlgorithmException("Not enough nodes in coordinate file."); } if (source->getNumberOfCoordinates() != values->getNumberOfNodes()) { throw BrainModelAlgorithmException("Node numbers do not match."); } // // Check output files exist // if (extremaOut == NULL) { throw BrainModelAlgorithmException("No valid output file."); } if (extremaOut->getNumberOfNodes() != source->getNumberOfCoordinates()) { extremaOut->setNumberOfNodesAndColumns(source->getNumberOfCoordinates(), 1); exOutIndex = 0; } if (exOutIndex < 0 || exOutIndex >= extremaOut->getNumberOfColumns()) { exOutIndex = extremaOut->getNumberOfColumns(); extremaOut->addColumns(1); } extremaOut->setColumnName(exOutIndex, QString("extrema depth=") + QString::number(depth)); int numNodes = source->getNumberOfCoordinates(); int i, j, numNeigh, whichnode; float nodemetric; float* sourceData = new float[numNodes * 3]; source->getAllCoordinates(sourceData); float* metricData = new float[numNodes]; values->getColumnForAllNodes(metricIndex, metricData); std::vector neighbors; float* exData = new float[numNodes]; int* markmax = new int[numNodes], *markmin = new int[numNodes]; for (i = 0; i < numNodes; ++i) { exData[i] = 0.0f; markmax[i] = 0; markmin[i] = 0; } bool isMax, isMin; for (i = 0; i < numNodes; ++i) { isMax = !markmax[i];//skip previously compared nodes for extra speed isMin = !markmin[i];//also allows it to not request neighbors, even more speed if (isMax || isMin) { nodemetric = metricData[i]; myhelper->getNodeNeighborsToDepth(i, depth, neighbors); numNeigh = neighbors.size(); for (j = 0; (isMax || isMin) && j < numNeigh; ++j) { whichnode = neighbors[j]; if (nodemetric < metricData[whichnode]) { isMax = false; markmin[whichnode] = 1; } if (nodemetric > metricData[whichnode]) { isMin = false; markmax[whichnode] = 1; } } if (isMin) { exData[i] = -1.0f; } if (isMax) { exData[i] = 1.0f; } } } extremaOut->setColumnForAllNodes(exOutIndex, exData); delete[] exData; delete[] sourceData; delete[] metricData; delete[] markmax; delete[] markmin; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceMetricCorrelationMatrix.h0000664000175000017500000001006611572067322030141 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_METRIC_CORRELATION_MATRIX_H__ #define __BRAIN_MODEL_SURFACE_METRIC_CORRELATION_MATRIX_H__ #include #include "BrainModelAlgorithm.h" #include "GiftiDataArrayReadListener.h" class GiftiDataArray; class GiftiDataArrayFile; class MetricFile; /** * Compute correlation of each metric column with all other metric columns. */ class BrainModelSurfaceMetricCorrelationMatrix : public BrainModelAlgorithm, GiftiDataArrayReadListener { public: // constructor for files that have already been read BrainModelSurfaceMetricCorrelationMatrix( BrainSet* bs, MetricFile* inputMetricFileIn, const bool applyFisherZTransformFlagIn, const bool outputGiftiFlagIn, const bool parallelFlagIn); // create instance for processing that reads and writes files incrementally // in order to minimize memory usage BrainModelSurfaceMetricCorrelationMatrix( const QString& inputMetricFileName, const QString& outputMetricFileName, const bool applyFisherZTransformFlagIn, const bool outputGiftiFlagIn, const bool parallelFlagIn); // destructor ~BrainModelSurfaceMetricCorrelationMatrix(); // execute the algorithm void execute() throw (BrainModelAlgorithmException); // get the output metric file (if called caller is reponsible for DELETING // returned metric file. MetricFile* getOutputMetricFile(); // get the output gifti file (if called caller is reponsible for DELETING // returned gifti file. GiftiDataArrayFile* getOutputGiftiFile(); /// called for incremental reads QString dataArrayWasRead(GiftiDataArray* gda, const int dataArrayIndex, const int numberOfDataArrays); private: // constructor for i enum Mode { MODE_FILES_IN_MEMORY, MODE_METRIC_INCREMENTAL }; // initialize variables void initialize(); // load the data values void loadDataValues(); // load the data values by incrementally reading the input metric file void loadDataValuesMetricIncremental() throw (BrainModelAlgorithmException); // create output metric file void createOutputMetricFile(); // create output gifti file void createOutputGiftiFile(); // compute the means void computeMeans(); // compute the sum-squared void computeSumSquared(); // compute the correlations void computeCorrelations(const Mode currentMode); // compute correlations for rows until there are no more rows to process void computeCorrelationsForRows(); // compute correlations for rows until there are no more rows to process void computeCorrelationsForRowsMetricIncremental(FILE* file); const Mode mode; QString inputMetricFileName; MetricFile* inputMetricFile; GiftiDataArrayFile* outputGiftiFile; QString outputMetricFileName; MetricFile* outputMetricFile; float** outputDataArrayColumns; long inputNumRows; long inputNumColumns; long outputDimension; // All values in one-dim array float* dataValues; // mean of all column values for each row float* rowMeans; // sum-squared of all column values for each row double* rowSumSquared; const bool applyFisherZTransformFlag; bool deleteOutputMetricFlag; bool deleteOutputGiftiFlag; long nextRowToProcess; const bool outputGiftiFlag; const bool parallelFlag; }; #endif // __BRAIN_MODEL_SURFACE_METRIC_CORRELATION_MATRIX_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceMetricCorrelationMatrix.cxx0000664000175000017500000005420511572067322030517 0ustar michaelmichael/* * BrainModelSurfaceMetricCorrelationMatrix.cxx * caret_brain_set * * Created by John Harwell on 12/30/10. * Copyright 2010 Washington University School of Medicine. All rights reserved. * */ #include #include #include #include #include #include #include #include #include "BrainModelSurfaceMetricCorrelationMatrix.h" #include "GiftiDataArray.h" #include "GiftiDataArrayFile.h" #include "GiftiDataArrayFileStreamReader.h" #include "MetricFile.h" #ifdef _OPENMP #include #endif static const bool timingFlag = true; /** * constructor. */ BrainModelSurfaceMetricCorrelationMatrix::BrainModelSurfaceMetricCorrelationMatrix( BrainSet* bs, MetricFile* inputMetricFileIn, const bool applyFisherZTransformFlagIn, const bool outputGiftiFlagIn, const bool parallelFlagIn) : BrainModelAlgorithm(bs), GiftiDataArrayReadListener(), mode(MODE_FILES_IN_MEMORY), inputMetricFile(inputMetricFileIn), applyFisherZTransformFlag(applyFisherZTransformFlagIn), outputGiftiFlag(outputGiftiFlagIn), parallelFlag(parallelFlagIn) { this->initialize(); } // create instance for processing that reads and writes files incrementally // in order to minimize memory usage BrainModelSurfaceMetricCorrelationMatrix::BrainModelSurfaceMetricCorrelationMatrix( const QString& inputMetricFileName, const QString& outputMetricFileName, const bool applyFisherZTransformFlagIn, const bool outputGiftiFlagIn, const bool parallelFlagIn) : BrainModelAlgorithm(NULL), GiftiDataArrayReadListener(), mode(MODE_METRIC_INCREMENTAL), inputMetricFile(NULL), applyFisherZTransformFlag(applyFisherZTransformFlagIn), outputGiftiFlag(outputGiftiFlagIn), parallelFlag(parallelFlagIn) { this->initialize(); this->inputMetricFileName = inputMetricFileName; this->outputMetricFileName = outputMetricFileName; } /** * destructor. */ BrainModelSurfaceMetricCorrelationMatrix::~BrainModelSurfaceMetricCorrelationMatrix() { if (this->deleteOutputMetricFlag) { if (this->outputMetricFile != NULL) { delete this->outputMetricFile; } } if (this->deleteOutputGiftiFlag) { if (this->outputGiftiFile != NULL) { delete this->outputGiftiFile; } } if (this->dataValues != NULL) { delete[] this->dataValues; } if (this->rowMeans != NULL) { delete[] this->rowMeans; } if (this->rowSumSquared != NULL) { delete[] this->rowSumSquared; } } /** * initialize variables. */ void BrainModelSurfaceMetricCorrelationMatrix::initialize() { this->deleteOutputMetricFlag = true; this->outputMetricFile = NULL; this->deleteOutputGiftiFlag = true; this->outputGiftiFile = NULL; this->dataValues = NULL; this->rowMeans = NULL; this->rowSumSquared = NULL; this->nextRowToProcess = -1; } /** * execute the algorithm. */ void BrainModelSurfaceMetricCorrelationMatrix::execute() throw (BrainModelAlgorithmException) { QTime loadTimer; loadTimer.start(); switch (this->mode) { case MODE_FILES_IN_MEMORY: this->inputNumRows = this->inputMetricFile->getNumberOfNodes(); this->inputNumColumns = this->inputMetricFile->getNumberOfColumns(); if ((this->inputNumRows <= 0) || (this->inputNumColumns <= 0)) { throw BrainModelAlgorithmException( "Input metric file is empty: " + this->inputMetricFile->getFileName()); } this->loadDataValues(); break; case MODE_METRIC_INCREMENTAL: if (this->inputMetricFileName.isEmpty()) { throw BrainModelAlgorithmException("Input metric file name is empty."); } if (this->outputMetricFileName.isEmpty()) { throw BrainModelAlgorithmException("Output metric file name is empty."); } this->loadDataValuesMetricIncremental(); break; } if (timingFlag) { std::cout << "Loaded data values in " << (loadTimer.elapsed() * 0.001) << " seconds." << std::endl; } /* * Compute the means */ QTime meanTimer; meanTimer.start(); this->computeMeans(); if (timingFlag) { std::cout << "Computed means in " << (meanTimer.elapsed() * 0.001) << " seconds." << std::endl; } /* * Compute the sumSquared */ QTime ssTimer; ssTimer.start(); this->computeSumSquared(); if (timingFlag) { std::cout << "Computed sum-squareds in " << (ssTimer.elapsed() * 0.001) << " seconds." << std::endl; } /* * Set output dimension output */ this->outputDimension = this->inputNumRows; /* * Create the output metric file */ QTime createMetricTimer; createMetricTimer.start(); if (this->outputGiftiFlag) { this->createOutputGiftiFile(); } else { this->createOutputMetricFile(); } if (timingFlag) { std::cout << "Create output file in " << (createMetricTimer.elapsed() * 0.001) << " seconds." << std::endl; } /* * Comute the correlations */ QTime corrTimer; corrTimer.start(); this->computeCorrelations(MODE_FILES_IN_MEMORY); // SEE NOTE this->computeCorrelations(this->mode); // Use when CIFTI file is available if (timingFlag) { std::cout << "Computed correlations in " << (corrTimer.elapsed() * 0.001) << " seconds." << std::endl; } /* * Write output file. */ switch (this->mode) { case MODE_FILES_IN_MEMORY: break; case MODE_METRIC_INCREMENTAL: try { QTime writeTimer; writeTimer.start(); if (this->outputGiftiFlag) { AbstractFile::FILE_FORMAT format = AbstractFile::getPreferredMetricWriteTypeCaretCommand(); this->outputGiftiFile->setFileWriteType(format); this->outputGiftiFile->writeFile(this->outputMetricFileName); } else { this->outputMetricFile->writeFile(this->outputMetricFileName); } if (timingFlag) { std::cout << "Write output file in " << (writeTimer.elapsed() * 0.001) << " seconds." << std::endl; } } catch (FileException e) { throw BrainModelAlgorithmException(e.whatQString()); } break; } } /** * load the data values. */ void BrainModelSurfaceMetricCorrelationMatrix::loadDataValues() { /* * Create and load the data values. */ const long numRows = this->inputNumRows; const long numCols = this->inputNumColumns; const long numElements = numRows * numCols; this->dataValues = new float[numElements]; for (long jCol = 0; jCol < numCols; jCol++) { GiftiDataArray* gda = this->inputMetricFile->getDataArray(jCol); const float* giftiData = gda->getDataPointerFloat(); for (long iRow = 0; iRow < numRows; iRow++) { const long indx = (iRow * numCols) + jCol; this->dataValues[indx] = giftiData[iRow]; } } } /** * called for incremental reads. */ QString BrainModelSurfaceMetricCorrelationMatrix::dataArrayWasRead( GiftiDataArray* gda, const int dataArrayIndex, const int numberOfDataArrays) { /* * Data array should be one-dimensional with the number of * elements being the number of rows (nodes). */ bool twoDimFlag = false; long numRows = -1; long dataArrayNumberOfColumns = -1; if (gda->getNumberOfDimensions() == 1) { numRows = gda->getDimension(0); } else if (gda->getNumberOfDimensions() == 2) { if (gda->getDimension(1) == 1) { numRows = gda->getDimension(0); } else if (gda->getDimension(1) > 1) { if (numberOfDataArrays > 1) { return "Data file may contain only one two-dimensional data array."; } numRows = gda->getDimension(0); dataArrayNumberOfColumns = gda->getDimension(1); twoDimFlag = true; } } if (numRows <= 0) { return "Data arrays must be one-dimensional for incremental reading"; } if (dataArrayIndex == 0) { this->inputNumRows = numRows; if (twoDimFlag) { this->inputNumColumns = dataArrayNumberOfColumns; /* * Use the data, as is, and DO NOT delete the data array. */ this->dataValues = (float*)gda->getDataPointerFloat(); } else { this->inputNumColumns = numberOfDataArrays; const long numElements = this->inputNumRows * this->inputNumColumns; this->dataValues = new float[numElements]; } } else { if (numRows != this->inputNumRows) { return "Data arrays must all have the same dimensions"; } } if (twoDimFlag == false) { const int numCols = this->inputNumColumns; const float* giftiData = gda->getDataPointerFloat(); for (long iRow = 0; iRow < numRows; iRow++) { const long indx = (iRow * numCols) + dataArrayIndex; this->dataValues[indx] = giftiData[iRow]; } /* * Delete the data array since the data was copied. */ delete gda; } return ""; } /** * load the data values by incrementally reading the input metric file. */ void BrainModelSurfaceMetricCorrelationMatrix::loadDataValuesMetricIncremental() throw (BrainModelAlgorithmException) { try { GiftiDataArrayFileStreamReader::readFileAndReportDataArraysAsTheyAreRead( this->inputMetricFileName, this); } catch (FileException e) { throw BrainModelAlgorithmException(e); } } /** * get the output metric file (if called, caller is reponsible for DELETING * returned metric file). */ MetricFile* BrainModelSurfaceMetricCorrelationMatrix::getOutputMetricFile() { this->deleteOutputMetricFlag = false; return this->outputMetricFile; } /** * get the output gifti file (if called, caller is reponsible for DELETING * returned gifti file). */ GiftiDataArrayFile* BrainModelSurfaceMetricCorrelationMatrix::getOutputGiftiFile() { this->deleteOutputGiftiFlag = false; return this->outputGiftiFile; } /** * compute the means. */ void BrainModelSurfaceMetricCorrelationMatrix::computeMeans() { this->rowMeans = new float[this->inputNumRows]; const long numRows = this->inputNumRows; const long numCols = this->inputNumColumns; if (this->parallelFlag) { #pragma omp parallel for for (long iRow = 0; iRow < numRows; iRow++) { double sum = 0.0; for (long j = 0; j < numCols; j++) { const long indx = iRow * numCols + j; sum += this->dataValues[indx]; } this->rowMeans[iRow] = sum / numCols; } } else { for (long iRow = 0; iRow < numRows; iRow++) { double sum = 0.0; for (long j = 0; j < numCols; j++) { const long indx = iRow * numCols + j; sum += this->dataValues[indx]; } this->rowMeans[iRow] = sum / numCols; } } } /** * compute the sum squared. After this, the dataValues array * will contain the value after the mean has been subtracted. */ void BrainModelSurfaceMetricCorrelationMatrix::computeSumSquared() { const long numRows = this->inputNumRows; const long numCols = this->inputNumColumns; this->rowSumSquared = new double[numRows]; if (this->parallelFlag) { #pragma omp parallel for for (long iRow = 0; iRow < numRows; iRow++) { double ss = 0.0; double mean = this->rowMeans[iRow]; for (long jCol = 0; jCol < numCols; jCol++) { const long indx = iRow * numCols + jCol; float f = this->dataValues[indx] - mean; ss += (f * f); /* * Save difference of node from for use during correlation calculation */ this->dataValues[indx] = f; } this->rowSumSquared[iRow] = ss; } } else { for (long iRow = 0; iRow < numRows; iRow++) { double ss = 0.0; double mean = this->rowMeans[iRow]; for (long jCol = 0; jCol < numCols; jCol++) { const long indx = iRow * numCols + jCol; float f = this->dataValues[indx] - mean; ss += (f * f); /* * Save difference of node from for use during correlation calculation */ this->dataValues[indx] = f; } this->rowSumSquared[iRow] = ss; } } } /** * compute the correlations. */ void BrainModelSurfaceMetricCorrelationMatrix::computeCorrelations(const Mode currentMode) { this->nextRowToProcess = -1; switch (currentMode) { case MODE_FILES_IN_MEMORY: #ifdef _OPENMP if (this->parallelFlag) { long numThreads = omp_get_max_threads(); if (numThreads > 1) { #pragma omp parallel for for (long i = 0; i < numThreads; i++) { this->computeCorrelationsForRows(); } } else { this->computeCorrelationsForRows(); } } else { this->computeCorrelationsForRows(); } #else this->computeCorrelationsForRows(); #endif break; case MODE_METRIC_INCREMENTAL: { FILE* file = fopen("DataFile.dat", "w+"); if (file == NULL) { throw BrainModelAlgorithmException("Failed to open output file for writing."); } #ifdef _OPENMP if (this->parallelFlag) { long numThreads = omp_get_max_threads(); if (numThreads > 1) { #pragma omp parallel for for (long i = 0; i < numThreads; i++) { this->computeCorrelationsForRowsMetricIncremental(file); } } else { this->computeCorrelationsForRowsMetricIncremental(file); } } else { this->computeCorrelationsForRowsMetricIncremental(file); } #else this->computeCorrelationsForRowsMetricIncremental(file); #endif fclose(file); } break; } } /** * Sompute correlations for rows until there are no more rows to process. * Since the correlation matrix is symmetric, we only need to calculate * the lower half and can then copy the result to the upper half. */ void BrainModelSurfaceMetricCorrelationMatrix::computeCorrelationsForRows() { const double tinyValue = 1.0e-20; const long numJ = this->outputDimension; const long numCols = this->inputNumColumns; while (true) { long iRow = -1; // // Only one thread may execute this block at any time // #pragma omp critical { this->nextRowToProcess++; iRow = this->nextRowToProcess; if (timingFlag) { if ((iRow % 1000) == 0) { std::cout << "Processing row " << iRow << std::endl; } } } if (iRow >= this->outputDimension) { break; } // // Compare with remaining rows // for (long jRow = iRow; jRow < numJ; jRow++) { // // // diff of mean from col I multiplied by diff of mean from column J // double sumSquaredBothColumns = 0.0; for (long jCol = 0; jCol < numCols; jCol++) { const long indxI = iRow * numCols + jCol; const long indxJ = jRow * numCols + jCol; sumSquaredBothColumns += (this->dataValues[indxI] * this->dataValues[indxJ]); } // // Compute correlation coefficient // const double denominator = this->rowSumSquared[iRow] * this->rowSumSquared[jRow]; float r = 0.0; if (denominator != 0.0) { double sd = std::sqrt(denominator); r = sumSquaredBothColumns / sd; } else { r = sumSquaredBothColumns / tinyValue; } /* * Apply the Fisher Z-Transform? */ if (this->applyFisherZTransformFlag) { float denom = (1.0 - r); if (denom != 0.0) { r = 0.5 * std::log((1.0 + r) / denom); } else { r = 0.5 * std::log((1.0 + r) / tinyValue); } } // // Matrix is symmetric !!!! // //this->outputMetricFile->setValue(iRow, jRow, r); //this->outputMetricFile->setValue(jRow, iRow, r); *(this->outputDataArrayColumns[iRow] + jRow) = r; *(this->outputDataArrayColumns[jRow] + iRow) = r; } } } /** * Sompute correlations for rows until there are no more rows to process. * Since the correlation matrix is symmetric, we only need to calculate * the lower half and can then copy the result to the upper half. * * THIS is NOT functioning correctly. Except for first part of output file, * the remainder appears to be zeros. */ void BrainModelSurfaceMetricCorrelationMatrix::computeCorrelationsForRowsMetricIncremental(FILE* file) { const double tinyValue = 1.0e-20; const long numJ = this->outputDimension; const long numCols = this->inputNumColumns; float* dataRow = new float[this->outputDimension]; while (true) { long iRow = -1; // // Only one thread may execute this block at any time // #pragma omp critical { this->nextRowToProcess++; iRow = this->nextRowToProcess; } if (iRow >= this->outputDimension) { break; } // // Compare with ALL rows // for (long jRow = 0; jRow < numJ; jRow++) { // // // diff of mean from col I multiplied by diff of mean from column J // double sumSquaredBothColumns = 0.0; for (long jCol = 0; jCol < numCols; jCol++) { const long indxI = iRow * numCols + jCol; const long indxJ = jRow * numCols + jCol; sumSquaredBothColumns += (this->dataValues[indxI] * this->dataValues[indxJ]); } // // Compute correlation coefficient // const double denominator = this->rowSumSquared[iRow] * this->rowSumSquared[jRow]; float r = 0.0; if (denominator != 0.0) { double sd = std::sqrt(denominator); r = sumSquaredBothColumns / sd; } else { r = sumSquaredBothColumns / tinyValue; } /* * Apply the Fisher Z-Transform? */ if (this->applyFisherZTransformFlag) { float denom = (1.0 - r); if (denom != 0.0) { r = 0.5 * std::log((1.0 + r) / denom); } else { r = 0.5 * std::log((1.0 + r) / tinyValue); } } dataRow[jRow] = r; // // // // Matrix is symmetric !!!! // // // //this->outputMetricFile->setValue(iRow, jRow, r); // //this->outputMetricFile->setValue(jRow, iRow, r); // if (this->outputGiftiFlag) { // const long indx1 = iRow * numJ + jRow; // this->outputGiftiArrayData[indx1] = r; // const long indx2 = jRow * numJ + iRow; // this->outputGiftiArrayData[indx2] = r; // } // else { // *(this->outputMetricArrayColumns[iRow] + jRow) = r; // *(this->outputMetricArrayColumns[jRow] + iRow) = r; // } } // // Only one thread may execute this block at any time // #pragma omp critical { long offset = iRow * this->outputDimension * 4; unsigned long numToWrite = this->outputDimension * 4; if (fseek(file, offset, SEEK_SET) != 0) { throw BrainModelAlgorithmException("Seek into output file failed."); } if (fwrite((void*)dataRow, 1, numToWrite, file) != numToWrite) { throw BrainModelAlgorithmException("Failed to write bytes to output file."); } } } delete[] dataRow; } /** * create output gifti file. */ void BrainModelSurfaceMetricCorrelationMatrix::createOutputGiftiFile() { this->outputDimension = this->inputNumRows; this->outputGiftiFile = new GiftiDataArrayFile(); std::vector dims; dims.push_back(this->outputDimension); dims.push_back(this->outputDimension); GiftiDataArray* gda = new GiftiDataArray(this->outputGiftiFile, "NIFTI_INTENT_NONE", GiftiDataArray::DATA_TYPE_FLOAT32, dims, GiftiDataArray::ENCODING_EXTERNAL_FILE_BINARY); this->outputGiftiFile->addDataArray(gda); float* giftiData = gda->getDataPointerFloat(); this->outputDataArrayColumns = new float*[this->outputDimension]; for (long i = 0; i < this->outputDimension; i++) { long offset = i * this->outputDimension; this->outputDataArrayColumns[i] = (giftiData + offset); } } /** * create output metric file. */ void BrainModelSurfaceMetricCorrelationMatrix::createOutputMetricFile() { this->outputDimension = this->inputNumRows; this->outputMetricFile = new MetricFile(); this->outputMetricFile->setNumberOfNodesAndColumns(this->outputDimension, this->outputDimension); this->outputDataArrayColumns = new float*[this->outputDimension]; for (long i = 0; i < this->outputDimension; i++) { GiftiDataArray* gda = this->outputMetricFile->getDataArray(i); this->outputDataArrayColumns[i] = gda->getDataPointerFloat(); } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceMetricCoordinateDifference.h0000664000175000017500000001045011572067322030532 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_METRIC_COORDINATE_DIFFERENCE_H__ #define __BRAIN_MODEL_SURFACE_METRIC_COORDINATE_DIFFERENCE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainModelSurfaceMetricFindClustersBase.h" class BrainModelSurface; class CoordinateFile; class MetricFile; class QTextStream; /// find significant clusters in metric files that contain coordinate differences class BrainModelSurfaceMetricCoordinateDifference : public BrainModelSurfaceMetricFindClustersBase { public: /// the mode of the algorithm enum MODE { /// coordinate difference mode MODE_COORDINATE_DIFFERENCE, /// t-map difference mode MODE_TMAP_DIFFERENCE }; // constructor BrainModelSurfaceMetricCoordinateDifference(BrainSet* bs, const MODE modeIn, const std::vector& coordFileGroupAIn, const std::vector& coordFileGroupBIn, const QString& fiducialCoordFileNameIn, const QString& openTopoFileNameIn, const QString& distortionShapeFileNameIn, const QString& distanceMetricFileNameIn, const QString& shuffledDistanceMetricFileNameIn, const QString& clustersPaintFileNameIn, const QString& clustersMetricFileNameIn, const QString& reportFileNameIn, const int distortionShapeFileColumnIn, const int iterationsIn, const float thresholdIn, const float pValueIn, const int numberOfThreadsIn); // destructor ~BrainModelSurfaceMetricCoordinateDifference(); protected: /// must be implemented by subclasses void executeClusterSearch() throw (BrainModelAlgorithmException); // free memory void cleanUp(); /// compute coordinate deviation void computeCoordinateDeviation(const std::vector& coordFiles, const CoordinateFile& averageCoordFile, MetricFile& deviationFile); /// mode of the algorithm MODE mode; /// names of coordinate files for group A std::vector coordFileNameGroupA; /// names of coordinate files for group B std::vector coordFileNameGroupB; /// group A coordinate files std::vector coordGroupA; /// group B coordinate files std::vector coordGroupB; /// iterations for shuffling average coord files int iterations; /// name of distance metric file //QString& distanceMetricFileName; /// name of shuffled distance metric file //QString& shuffledDistanceMetricFileName; }; #endif // __BRAIN_MODEL_SURFACE_METRIC_COORDINATE_DIFFERENCE_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceMetricCoordinateDifference.cxx0000664000175000017500000005453311572067322031117 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "BrainModelSurface.h" #include "BrainModelSurfaceMetricCoordinateDifference.h" #include "BrainSet.h" #include "CoordinateFile.h" #include "DateAndTime.h" #include "DebugControl.h" #include "FileUtilities.h" #include "PaintFile.h" #include "MathUtilities.h" #include "MetricFile.h" #include "StatisticDataGroup.h" #include "TopologyFile.h" /** * constructor. */ BrainModelSurfaceMetricCoordinateDifference::BrainModelSurfaceMetricCoordinateDifference( BrainSet* bs, const MODE modeIn, const std::vector& coordFileNameGroupAIn, const std::vector& coordFileNameGroupBIn, const QString& fiducialCoordFileNameIn, const QString& openTopoFileNameIn, const QString& distortionShapeFileNameIn, const QString& distanceMetricFileNameIn, const QString& shuffledDistanceMetricFileNameIn, const QString& clustersPaintFileNameIn, const QString& clustersMetricFileNameIn, const QString& reportFileNameIn, const int distortionShapeFileColumnIn, const int iterationsIn, const float thresholdIn, const float pValueIn, const int numberOfThreadsIn) : BrainModelSurfaceMetricFindClustersBase(bs, fiducialCoordFileNameIn, openTopoFileNameIn, distortionShapeFileNameIn, distanceMetricFileNameIn, //tMapFileNameIn, shuffledDistanceMetricFileNameIn, //shuffledTMapFileNameIn, clustersPaintFileNameIn, clustersMetricFileNameIn, reportFileNameIn, distortionShapeFileColumnIn, 0.0, // negative threshold thresholdIn, pValueIn, 0, // variance smoothing iterations 0.0, // variance smoothing strength false, // do DOF false, // do P-Value numberOfThreadsIn) { mode = modeIn; coordFileNameGroupA = coordFileNameGroupAIn; coordFileNameGroupB = coordFileNameGroupBIn; iterations = iterationsIn; } /** * destructor. */ BrainModelSurfaceMetricCoordinateDifference::~BrainModelSurfaceMetricCoordinateDifference() { for (unsigned int i = 0; i < coordGroupA.size(); i++) { delete coordGroupA[i]; } coordGroupA.clear(); for (unsigned int i = 0; i < coordGroupB.size(); i++) { delete coordGroupB[i]; } coordGroupB.clear(); cleanUp(); } /** * execute the algorithm. */ void BrainModelSurfaceMetricCoordinateDifference::executeClusterSearch() throw (BrainModelAlgorithmException) { try { // // Steps in algorithm // enum { ALG_STEP_CHECKING_INPUT, ALG_STEP_TMAP, ALG_STEP_SHUFFLED_TMAP, ALG_STEP_FINDING_CLUSTERS_T_MAP, ALG_STEP_FINDING_CLUSTERS_SHUFFLE_T_MAP, ALG_NUM_STEPS }; // // Update progress // //createProgressDialog("Coordinate Distance Test", // ALG_NUM_STEPS, // "sifClustDialog"); updateProgressDialog("Verifying Input", ALG_STEP_CHECKING_INPUT, ALG_NUM_STEPS); // // check iterations // if (iterations < 0) { throw BrainModelAlgorithmException("Iterations must be positive."); } // // Read the group A coordinate files // for (unsigned int i = 0; i < coordFileNameGroupA.size(); i++) { CoordinateFile* cf = new CoordinateFile; cf->readFile(coordFileNameGroupA[i]); coordGroupA.push_back(cf); } // // Read the group B coordinate files // for (unsigned int i = 0; i < coordFileNameGroupB.size(); i++) { CoordinateFile* cf = new CoordinateFile; cf->readFile(coordFileNameGroupB[i]); coordGroupB.push_back(cf); } // // Check input files // if (coordGroupA.empty()) { throw BrainModelAlgorithmException("No coordinate files in Group A"); } if (coordGroupB.empty()) { throw BrainModelAlgorithmException("No coordinate files in Group B"); } // // Number of nodes in surface // const int numberOfNodes = coordGroupA[0]->getNumberOfCoordinates(); // // Create average coordinate files for group A // CoordinateFile coordAverageGroupA; CoordinateFile::createAverageCoordinateFile(coordGroupA, coordAverageGroupA); // // Create average coordinate files for group B // CoordinateFile coordAverageGroupB; CoordinateFile::createAverageCoordinateFile(coordGroupB, coordAverageGroupB); // // Compute the deviations // MetricFile deviationGroupA; computeCoordinateDeviation(coordGroupA, coordAverageGroupA, deviationGroupA); MetricFile deviationGroupB; computeCoordinateDeviation(coordGroupB, coordAverageGroupB, deviationGroupB); // // Check file compatibilities // if (numberOfNodes != bms->getNumberOfNodes()) { throw BrainModelAlgorithmException("Fiducial Coord has different number of nodes than coord file group."); } if (numberOfNodes != areaCorrectionShapeFile->getNumberOfNodes()) { throw BrainModelAlgorithmException("Area correction shape file has different number of nodes" "than the coordinate file."); } // // Update progress // updateProgressDialog("Doing Real Distance File", ALG_STEP_TMAP, ALG_NUM_STEPS); // // Create Distance File // statisticalMapShapeFile = new MetricFile; switch (mode) { case MODE_COORDINATE_DIFFERENCE: statisticalMapShapeFile->setNumberOfNodesAndColumns(numberOfNodes, 4); statisticalMapShapeFile->addColumnOfCoordinateDifference( MetricFile::COORDINATE_DIFFERENCE_MODE_ABSOLUTE, &coordAverageGroupA, &coordAverageGroupB, bms->getTopologyFile(), 0, "Coord Difference", "Difference of two average coord files", 1, 2, 3); break; case MODE_TMAP_DIFFERENCE: statisticalMapShapeFile->setNumberOfNodesAndColumns(numberOfNodes, 1); statisticalMapShapeFile->addColumnOfCoordinateDifferenceTMap( &coordAverageGroupA, &coordAverageGroupB, bms->getTopologyFile(), 0, "T-Map Coord Difference", "T-Map of Difference of two average coord files", &deviationGroupA, 0, &deviationGroupB, 0, true); try { coordAverageGroupA.writeFile("A_AverageFiducial.coord"); coordAverageGroupB.writeFile("B_AverageFiducial.coord"); deviationGroupA.writeFile("A_3D_VARIABILITY.surface_shape"); deviationGroupB.writeFile("B_3D_VARIABILITY.surface_shape"); } catch (FileException& e) { throw BrainModelAlgorithmException(e.whatQString()); } break; } // // Write Distance file // try { statisticalMapShapeFile->writeFile(statisticalMapFileName); } catch (FileException& e) { std::ostringstream str; str << "Unable to write Distance File: " << FileUtilities::basename(statisticalMapFileName).toAscii().constData(); cleanUp(); throw BrainModelAlgorithmException(str.str().c_str()); } // // Update progress // updateProgressDialog("Doing Shuffled Distance File", ALG_STEP_SHUFFLED_TMAP, ALG_NUM_STEPS); // // Get all coords in one group // std::vector allCoords; allCoords.insert(allCoords.end(), coordGroupA.begin(), coordGroupA.end()); allCoords.insert(allCoords.end(), coordGroupB.begin(), coordGroupB.end()); const int totalNumCoords = static_cast(allCoords.size()); if (totalNumCoords < 2) { throw BrainModelAlgorithmException("There must be at least two coord files."); } // // Do shuffled Distance File // shuffleStatisticalMapShapeFile = new MetricFile; shuffleStatisticalMapShapeFile->setNumberOfNodesAndColumns(numberOfNodes, iterations); for (int i = 0; i < iterations; i++) { CoordinateFile c1, c2; CoordinateFile::createShuffledAverageCoordinatesFiles(allCoords, -1, c1, c2); switch (mode) { case MODE_COORDINATE_DIFFERENCE: shuffleStatisticalMapShapeFile->addColumnOfCoordinateDifference( MetricFile::COORDINATE_DIFFERENCE_MODE_ABSOLUTE, &c1, &c2, bms->getTopologyFile(), i, "Coord Difference", "Difference of two average coord files"); break; case MODE_TMAP_DIFFERENCE: shuffleStatisticalMapShapeFile->addColumnOfCoordinateDifferenceTMap(&c1, &c2, bms->getTopologyFile(), i, "T-Map Coord Difference", "T-Map of Difference of two average coord files", &deviationGroupA, 0, &deviationGroupB, 0, false); break; } } // // Write Shuffled Distance file // try { shuffleStatisticalMapShapeFile->writeFile(shuffledStatisticalMapFileName); } catch (FileException& e) { std::ostringstream str; str << "Unable to write Shuffled Distance File: " << FileUtilities::basename(shuffledStatisticalMapFileName).toAscii().constData(); cleanUp(); throw BrainModelAlgorithmException(str.str().c_str()); } // // Update progress // updateProgressDialog("Finding clusters in Real Distance File", ALG_STEP_FINDING_CLUSTERS_T_MAP, ALG_NUM_STEPS); // // find the clusters in Distance File // Note: column 0 is the Distance column // std::vector tMapClusters; findClusters(statisticalMapShapeFile, tMapClusters, "Finding Clusters in Real Distance File", 0, false); // // Update progress // updateProgressDialog("Finding Clusters in Shuffled Distance File", ALG_STEP_FINDING_CLUSTERS_SHUFFLE_T_MAP, ALG_NUM_STEPS); // // find the clusters in Shuffled Distance File // Note: Only use largest cluster from each column // std::vector shuffleTMapClusters; findClusters(shuffleStatisticalMapShapeFile, shuffleTMapClusters, "Finding Clusters in Shuffled Distance File", -1, true); // // Set pValue for shuffled T-Map // setRandomizedClusterPValues(*shuffleStatisticalMapShapeFile, shuffleTMapClusters); // // Find area of the "P-Value" cluster in the shuffled Distance File // float significantCorrectedArea = std::numeric_limits::max(); int pValueClusterIndex = -1; if (shuffleTMapClusters.empty() == false) { pValueClusterIndex = std::min(static_cast(pValue * iterations) - 1, static_cast(shuffleTMapClusters.size())); pValueClusterIndex = std::max(pValueClusterIndex, 0); } if (pValueClusterIndex >= 0) { significantCorrectedArea = shuffleTMapClusters[pValueClusterIndex].areaCorrected; } // // Find P-Value for significant clusters in Distance File // for (unsigned int i = 0; i < tMapClusters.size(); i++) { Cluster& tMapCluster = tMapClusters[i]; int cnt = shuffleTMapClusters.size() - 1; if (shuffleTMapClusters.empty() == false) { if (tMapCluster.areaCorrected > shuffleTMapClusters[0].areaCorrected) { cnt = 1; } else { for (unsigned int j = 0; j < shuffleTMapClusters.size() - 1; j++) { if ((tMapCluster.areaCorrected < shuffleTMapClusters[j].areaCorrected) && (tMapCluster.areaCorrected >= shuffleTMapClusters[j+1].areaCorrected)) { cnt = j + 2; } } } } cnt = std::min(cnt, iterations); tMapCluster.pValue = static_cast(cnt) / static_cast(iterations); } // // For each distance that has area corrected that exceeds significant area // Find its rank in shuffled tmap // P-value = rank / iterations // // Open the report file // QFile reportFile(reportFileName); if (reportFile.open(QIODevice::WriteOnly) == false) { std::ostringstream str; str << "Unable to open report file for writing: " << FileUtilities::basename(reportFileName).toAscii().constData(); cleanUp(); throw BrainModelAlgorithmException(str.str().c_str()); } // // Create the text stream // QTextStream reportStream(&reportFile); // // Show area and thresholds // reportStream << "Date/Time: " << DateAndTime::getDateAndTimeAsString() << "\n"; //QDateTime::currentDateTime().toString("MMM d, yyyy hh:mm:ss") << "\n"; for (unsigned int j = 0; j < coordFileNameGroupA.size(); j++) { reportStream << "Coord File Group A: " << coordFileNameGroupA[j] << "\n"; } for (unsigned int j = 0; j < coordFileNameGroupB.size(); j++) { reportStream << "Coord File Group B: " << coordFileNameGroupB[j] << "\n"; } reportStream << "Fiducial Coord File: " << fiducialCoordFileName << "\n"; reportStream << "Open Topo File: " << openTopoFileName << "\n"; if ((areaCorrectionShapeFile != NULL) || (areaCorrectionShapeFileColumn >= 0)) { reportStream << "Area Correct File: " << areaCorrectionShapeFileName << "\n"; reportStream << "Area Correct Column: " << areaCorrectionShapeFile->getColumnName(areaCorrectionShapeFileColumn) << "\n"; } //reportStream << "Negative Threshold: " << negativeThresh << "\n"; reportStream << " Threshold: " << positiveThresh << "\n"; reportStream << "Iterations: " << iterations << "\n"; reportStream << "P-Value: " << pValue << "\n"; reportStream << "Significant Area: " << significantCorrectedArea << "\n"; reportStream << "\n"; // // Add significant clusters to report file // reportStream << "Shuffled Distance File" << "\n"; reportStream << "-------------" << "\n"; printClusters(reportStream, shuffleTMapClusters, significantCorrectedArea); reportStream << "\n\n\n"; reportStream << "Real Distance File" << "\n"; reportStream << "----" << "\n"; printClusters(reportStream, tMapClusters, significantCorrectedArea); reportStream << "\n\n\n"; // // Add all clusters to report file // reportStream << "Shuffled Distance File" << "\n"; reportStream << "-------------" << "\n"; printClusters(reportStream, shuffleTMapClusters); reportStream << "\n\n\n"; reportStream << "Real Distance File" << "\n"; reportStream << "----" << "\n"; printClusters(reportStream, tMapClusters); // // Close the report file // reportFile.close(); // // Do the paint file // createClustersPaintFile(tMapClusters, significantCorrectedArea, numberOfNodes); // // Do the clusters metric file // createClustersMetricFile(tMapClusters, 0, numberOfNodes); } catch (FileException& e) { throw BrainModelAlgorithmException(e.whatQString()); } } /** * compute coordinate deviation. Assume mean is zero and distance * between a coord and average is the value being measured. */ void BrainModelSurfaceMetricCoordinateDifference::computeCoordinateDeviation(const std::vector& coordFiles, const CoordinateFile& averageCoordFile, MetricFile& deviationFile) { float minVal = std::numeric_limits::max(); float maxVal = -std::numeric_limits::max(); const int numCoordFiles = static_cast(coordFiles.size()); const float denominator = numCoordFiles - 1; const int numNodes = averageCoordFile.getNumberOfCoordinates(); deviationFile.setNumberOfNodesAndColumns(numNodes, 1); for (int i = 0; i < numNodes; i++) { float sumSquared = 0.0; for (int j = 0; j < numCoordFiles; j++) { const float delta = MathUtilities::distance3D(coordFiles[j]->getCoordinate(i), averageCoordFile.getCoordinate(i)); sumSquared += (delta * delta); // note: mean is always zero } if (denominator > 0.0) { sumSquared = std::sqrt(sumSquared / denominator); } deviationFile.setValue(i, 0, sumSquared); minVal = std::min(minVal, sumSquared); maxVal = std::max(maxVal, sumSquared); } deviationFile.setColumnColorMappingMinMax(0, minVal, maxVal); } /** * Free memory. */ void BrainModelSurfaceMetricCoordinateDifference::cleanUp() { BrainModelSurfaceMetricFindClustersBase::cleanUp(); } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceMetricClustering.h0000664000175000017500000001600611572067322026612 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __BRAIN_MODEL_SURFACE_METRIC_CLUSTERING_H__ #define __BRAIN_MODEL_SURFACE_METRIC_CLUSTERING_H__ #include #include #include "BrainModelAlgorithm.h" class BrainModelSurface; class MetricFile; /// class for performing clustering of a metric file column class BrainModelSurfaceMetricClustering : public BrainModelAlgorithm { public: /// cluster of nodes class Cluster { public: /// Constructor Cluster(const float threshMinIn, const float threshMaxIn); /// Destructor ~Cluster() {} /// get number of nodes in cluster int getNumberOfNodesInCluster() const { return nodeIndices.size(); } /// get a node that is in the cluster int getNodeInCluster(const int indx) const { return nodeIndices[indx]; } /// get all nodes in the cluster std::vector getNodesInCluster() const { return nodeIndices; } /// add a node to the cluster void addNodeToCluster(const int index) { nodeIndices.push_back(index); } /// set the area of the cluster void setArea(const float area) { clusterArea = area; } /// get the cluster area float getArea() const { return clusterArea; } /// get the center of gravity void getCenterOfGravity(float cog[3]) const; /// set the center of gravity void setCenterOfGravity(const float cog[3]); /// get thresholds void getThresholds(float& threshMinOut, float& threshMaxOut) const; /// get the maximum Y-Value float getMaximumY(const BrainModelSurface* bms) const; /// get the center of gravity using the surface (does not overwrite cluster's cog) void getCenterOfGravityForSurface(const BrainModelSurface* bms, float cog[3]) const; protected: /// nodes in the cluster std::vector nodeIndices; /// area of the cluster float clusterArea; /// cluster center of gravity float centerOfGravity[3]; /// cluster threshold minimum float threshMin; /// cluster threshold maximum float threshMax; friend class BrainModelSurfaceMetricClustering; }; /// clustering algorithm enum CLUSTER_ALGORITHM { CLUSTER_ALGORITHM_NONE, CLUSTER_ALGORITHM_ANY_SIZE, CLUSTER_ALGORITHM_MINIMUM_NUMBER_OF_NODES, CLUSTER_ALGORITHM_MINIMUM_SURFACE_AREA, }; /// Constructor BrainModelSurfaceMetricClustering(BrainSet* bs, const BrainModelSurface* bmsIn, MetricFile* metricFileIn, const CLUSTER_ALGORITHM algorithmIn, const int columnIn, const int outputColumnIn, const QString& outputColumnNameIn, const int minimumNumberOfNodesIn, const float minimumSurfaceAreaIn, const float clusterNegativeMinimumThresholdIn, const float clusterNegativeMaximumThresholdIn, const float clusterPositiveMinimumThresholdIn, const float clusterPositiveMaximumThresholdIn, const bool outputAllClustersFlagIn); /// Destructor ~BrainModelSurfaceMetricClustering(); /// execute the algorithm virtual void execute() throw (BrainModelAlgorithmException); /// get the number of clusters int getNumberOfClusters() const { return clusters.size(); } /// get a cluster Cluster* getCluster(const int indx) { return &clusters[indx]; } /// get a cluster (const method) const Cluster* getCluster(const int indx) const { return &clusters[indx]; } /// get clusters indices sorted by number of nodes in cluster void getClusterIndicesSortedByNumberOfNodesInCluster(std::vector& indices) const; protected: /// find the clusters void findClusters() throw (BrainModelAlgorithmException); /// set clusters center of gravity and area void setClustersCenterOfGravityAndArea() throw (BrainModelAlgorithmException); /// surface for clustering const BrainModelSurface* bms; /// metric file being clustered MetricFile* metricFile; /// clustering algorithm CLUSTER_ALGORITHM algorithm; /// input column int inputColumn; /// output column int outputColumn; /// output column name QString outputColumnName; /// minimum number of nodes for number of nodes algorithm int minimumNumberOfNodes; /// minimum surface area for minimum surface area algorithm float minimumSurfaceArea; /// cluster negative minimum threshold float clusterNegativeMinimumThreshold; /// cluster negative maximum threshold float clusterNegativeMaximumThreshold; /// cluster positive minimum threshold float clusterPositiveMinimumThreshold; /// cluster positive maximum threshold float clusterPositiveMaximumThreshold; /// output all clusters including those that do not meet cluster area/number of nodes bool outputAllClustersFlag; /// marks nodes whose metric is within the threshold values std::vector nodeWithinThresholds; /// the clusters std::vector clusters; }; #endif // __BRAIN_MODEL_SURFACE_METRIC_CLUSTERING_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceMetricClustering.cxx0000664000175000017500000004031211572067322027162 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include "BrainModelSurface.h" #include "BrainModelSurfaceConnectedSearchMetric.h" #include "BrainModelSurfaceMetricClustering.h" #include "DebugControl.h" #include "MathUtilities.h" #include "MetricFile.h" #include "TopologyFile.h" #include "TopologyHelper.h" #include "ValueIndexSort.h" /** * Constructor. */ BrainModelSurfaceMetricClustering::BrainModelSurfaceMetricClustering(BrainSet* bs, const BrainModelSurface* bmsIn, MetricFile* metricFileIn, const CLUSTER_ALGORITHM algorithmIn, const int inputColumnIn, const int outputColumnIn, const QString& outputColumnNameIn, const int minimumNumberOfNodesIn, const float minimumSurfaceAreaIn, const float clusterNegativeMinimumThresholdIn, const float clusterNegativeMaximumThresholdIn, const float clusterPositiveMinimumThresholdIn, const float clusterPositiveMaximumThresholdIn, const bool outputAllClustersFlagIn) : BrainModelAlgorithm(bs), bms(bmsIn), metricFile(metricFileIn), algorithm (algorithmIn), inputColumn(inputColumnIn), outputColumn(outputColumnIn), outputColumnName(outputColumnNameIn), minimumNumberOfNodes(minimumNumberOfNodesIn), minimumSurfaceArea(minimumSurfaceAreaIn), clusterNegativeMinimumThreshold(clusterNegativeMinimumThresholdIn), clusterNegativeMaximumThreshold(clusterNegativeMaximumThresholdIn), clusterPositiveMinimumThreshold(clusterPositiveMinimumThresholdIn), clusterPositiveMaximumThreshold(clusterPositiveMaximumThresholdIn), outputAllClustersFlag(outputAllClustersFlagIn) { } /** * Destructor. */ BrainModelSurfaceMetricClustering::~BrainModelSurfaceMetricClustering() { clusters.clear(); } /** * execute the algorithm. */ void BrainModelSurfaceMetricClustering::execute() throw (BrainModelAlgorithmException) { // // Check for valid input column // if ((metricFile->getNumberOfColumns() <= 0) || (metricFile->getNumberOfNodes() <= 0)) { throw BrainModelAlgorithmException("Metric file has no data"); } if ((inputColumn < 0) || (inputColumn >= metricFile->getNumberOfColumns())) { throw BrainModelAlgorithmException("Invalid input column number"); } // // Create a new column if needed. // if ((outputColumn < 0) || (outputColumn >= metricFile->getNumberOfColumns())){ metricFile->addColumns(1); outputColumn = metricFile->getNumberOfColumns() - 1; } metricFile->setColumnName(outputColumn, outputColumnName); // // Copy the input column to the output column // if (inputColumn != outputColumn) { std::vector values; metricFile->getColumnForAllNodes(inputColumn, values); metricFile->setColumnForAllNodes(outputColumn, values); } // // Node within threshold flags // const int numNodes = bms->getNumberOfNodes(); nodeWithinThresholds.resize(numNodes); // // Get a toplogy helper // const TopologyFile* tf = bms->getTopologyFile(); const TopologyHelper* th = tf->getTopologyHelper(false, true, false); // // Find nodes that are within thresholds // for (int i = 0; i < numNodes; i++) { nodeWithinThresholds[i] = false; if (th->getNodeHasNeighbors(i)) { float v = metricFile->getValue(i, outputColumn); if ((v >= clusterPositiveMinimumThreshold) && (v <= clusterPositiveMaximumThreshold)) { nodeWithinThresholds[i] = true; } if ((v <= clusterNegativeMinimumThreshold) && (v >= clusterNegativeMaximumThreshold)) { nodeWithinThresholds[i] = true; } } } switch (algorithm) { case CLUSTER_ALGORITHM_NONE: throw BrainModelAlgorithmException("Invalid clustering algorithm = NONE"); break; case CLUSTER_ALGORITHM_ANY_SIZE: break; case CLUSTER_ALGORITHM_MINIMUM_NUMBER_OF_NODES: case CLUSTER_ALGORITHM_MINIMUM_SURFACE_AREA: // // Find the clusters // Note find clusters will make sure that a cluster contains just positive nodes // or just negative nodes. // findClusters(); setClustersCenterOfGravityAndArea(); break; } // // Nodes that are to remain after clustering // std::vector validClusterNodes(numNodes, false); std::vector clustersOut; const int numClusters = static_cast(clusters.size()); // // Determine which clusters are good // switch (algorithm) { case CLUSTER_ALGORITHM_NONE: break; case CLUSTER_ALGORITHM_ANY_SIZE: // // Any nodes within the thresholds are in the cluster // for (int i = 0; i < numNodes; i++) { validClusterNodes[i] = nodeWithinThresholds[i]; } break; case CLUSTER_ALGORITHM_MINIMUM_NUMBER_OF_NODES: // // Keep nodes that are in clusters with sufficient number of nodes // for (int i = 0; i < numClusters; i++) { Cluster& c = clusters[i]; const int numNodesInCluster = c.getNumberOfNodesInCluster(); if (numNodesInCluster >= minimumNumberOfNodes) { for (int j = 0; j < numNodesInCluster; j++) { validClusterNodes[c.nodeIndices[j]] = true; } clustersOut.push_back(c); } else { if (outputAllClustersFlag) { clustersOut.push_back(c); } } } break; case CLUSTER_ALGORITHM_MINIMUM_SURFACE_AREA: // // Keep nodes that are in clusters with minimum area // for (int i = 0; i < numClusters; i++) { Cluster& c = clusters[i]; if (c.getArea() >= minimumSurfaceArea) { const int numNodesInCluster = c.getNumberOfNodesInCluster(); for (int j = 0; j < numNodesInCluster; j++) { validClusterNodes[c.nodeIndices[j]] = true; } clustersOut.push_back(c); } else { if (outputAllClustersFlag) { clustersOut.push_back(c); } } } break; } // // output the clusters // clusters = clustersOut; // // Any nodes within the thresholds are in the cluster // for (int i = 0; i < numNodes; i++) { if (validClusterNodes[i] == false) { metricFile->setValue(i, outputColumn, 0.0); } } } /** * Find the clusters */ void BrainModelSurfaceMetricClustering::findClusters() throw (BrainModelAlgorithmException) { clusters.clear(); QTime timer; timer.start(); // // Search positive values // const int numNodes = metricFile->getNumberOfNodes(); for (int i = 0; i < numNodes; i++) { if (nodeWithinThresholds[i]) { float minVal = 0.0; float maxVal = 0.0; bool doIt = false; if ((metricFile->getValue(i, outputColumn) >= clusterPositiveMinimumThreshold) && (metricFile->getValue(i, outputColumn) <= clusterPositiveMaximumThreshold)) { minVal = clusterPositiveMinimumThreshold; maxVal = clusterPositiveMaximumThreshold; doIt = true; } else if ((metricFile->getValue(i, outputColumn) >= clusterNegativeMaximumThreshold) && (metricFile->getValue(i, outputColumn) <= clusterNegativeMinimumThreshold)) { minVal = clusterNegativeMaximumThreshold; maxVal = clusterNegativeMinimumThreshold; doIt = true; } if (doIt) { // // allow other events to process // allowEventsToProcess(); BrainModelSurfaceConnectedSearchMetric bmscsm(brainSet, bms, i, metricFile, outputColumn, minVal, maxVal, &nodeWithinThresholds); try { bmscsm.execute(); } catch (BrainModelAlgorithmException& e) { throw e; } // // Create a new cluster // Cluster c(minVal, maxVal); // // See which nodes should be added to the cluster // for (int j = i; j < numNodes; j++) { // // Is node part of the cluster ? // if (bmscsm.getNodeConnected(j)) { // // add to the cluster // c.addNodeToCluster(j); // // do not need to look at this node again // nodeWithinThresholds[j] = false; } } // // If the cluster has nodes, add it to the clusters // if (c.getNumberOfNodesInCluster() > 0) { clusters.push_back(c); if (DebugControl::getDebugOn()) { std::cout << "Cluster starting at node " << i << " contains " << c.getNumberOfNodesInCluster() << " nodes." << std::endl; } } } // // This node no longer needs to be examined // nodeWithinThresholds[i] = false; } } if (DebugControl::getDebugOn()) { std::cout << "Time to find clusters: " << (static_cast(timer.elapsed()) / 1000.0) << std::endl; } } /** * set clusters center of gravity and area. */ void BrainModelSurfaceMetricClustering::setClustersCenterOfGravityAndArea() throw (BrainModelAlgorithmException) { const int numClusters = static_cast(clusters.size()); if (numClusters > 0) { // // Get the area of all nodes // std::vector nodeAreas; bms->getAreaOfAllNodes(nodeAreas); const CoordinateFile* cf = bms->getCoordinateFile(); // // process each cluster // for (int i = 0; i < numClusters; i++) { Cluster& c = clusters[i]; const int numNodesInCluster = c.getNumberOfNodesInCluster(); if (numNodesInCluster > 0) { double area = 0.0; double cogSum[3] = { 0.0, 0.0, 0.0 }; for (int j = 0; j < numNodesInCluster; j++) { const int nodeNumber = c.nodeIndices[j]; area += nodeAreas[nodeNumber]; const float* xyz = cf->getCoordinate(nodeNumber); cogSum[0] += xyz[0]; cogSum[1] += xyz[1]; cogSum[2] += xyz[2]; } // // Note: Area of nodes is just summed, no need to divide by zero // c.setArea(area); const float cog[3] = { cogSum[0] / static_cast(numNodesInCluster), cogSum[1] / static_cast(numNodesInCluster), cogSum[2] / static_cast(numNodesInCluster) }; c.setCenterOfGravity(cog); } } } } /** * get clusters indices sorted by number of nodes in cluster. */ void BrainModelSurfaceMetricClustering::getClusterIndicesSortedByNumberOfNodesInCluster(std::vector& indices) const { indices.clear(); // // Sort the indices by number of nodes in clusters // ValueIndexSort vis; const int num = getNumberOfClusters(); for (int i = 0; i < num; i++) { const Cluster* c = getCluster(i); vis.addValueIndexPair(i, c->getNumberOfNodesInCluster()); } vis.sort(); // // Set output indices // const int numItems = vis.getNumberOfItems(); for (int i = 0; i < numItems; i++) { int indx; float value; vis.getValueAndIndex(i, indx, value); indices.push_back(indx); } } //***************************************************************************************** // // Cluster methods // /** * Constructor */ BrainModelSurfaceMetricClustering::Cluster::Cluster(const float threshMinIn, const float threshMaxIn) { clusterArea = 0.0; centerOfGravity[0] = 0.0; centerOfGravity[1] = 0.0; centerOfGravity[2] = 0.0; threshMin = threshMinIn; threshMax = threshMaxIn; } /** * get thresholds. */ void BrainModelSurfaceMetricClustering::Cluster::getThresholds(float& threshMinOut, float& threshMaxOut) const { threshMinOut = threshMin; threshMaxOut = threshMax; } /** * get the center of gravity. */ void BrainModelSurfaceMetricClustering::Cluster::getCenterOfGravity(float cog[3]) const { cog[0] = centerOfGravity[0]; cog[1] = centerOfGravity[1]; cog[2] = centerOfGravity[2]; } /** * set the center of gravity. */ void BrainModelSurfaceMetricClustering::Cluster::setCenterOfGravity(const float cog[3]) { centerOfGravity[0] = cog[0]; centerOfGravity[1] = cog[1]; centerOfGravity[2] = cog[2]; } /** * get the maximum Y-Value. */ float BrainModelSurfaceMetricClustering::Cluster::getMaximumY(const BrainModelSurface* bms) const { float maxY = 0.0; const int numClusterNodes = getNumberOfNodesInCluster(); if (numClusterNodes > 0) { const CoordinateFile* cf = bms->getCoordinateFile(); maxY = -std::numeric_limits::max(); for (int i = 0; i < numClusterNodes; i++) { const float* xyz = cf->getCoordinate(nodeIndices[i]); maxY = std::max(maxY, xyz[1]); } } return maxY; } /** * get the center of gravity using the surface (does not overwrite cluster's cog). */ void BrainModelSurfaceMetricClustering::Cluster::getCenterOfGravityForSurface(const BrainModelSurface* bms, float cog[3]) const { double cogSum[3] = { 0.0, 0.0, 0.0 }; const int numClusterNodes = getNumberOfNodesInCluster(); if (numClusterNodes > 0) { const CoordinateFile* cf = bms->getCoordinateFile(); for (int i = 0; i < numClusterNodes; i++) { const float* xyz = cf->getCoordinate(nodeIndices[i]); cogSum[0] += xyz[0]; cogSum[1] += xyz[1]; cogSum[2] += xyz[2]; } cogSum[0] /= static_cast(numClusterNodes); cogSum[1] /= static_cast(numClusterNodes); cogSum[2] /= static_cast(numClusterNodes); } cog[0] = cogSum[0]; cog[1] = cogSum[1]; cog[2] = cogSum[2]; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceMetricAnovaTwoWay.h0000664000175000017500000001122511572067322026710 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_METRIC_ANOVA_TWO_WAY_H__ #define __BRAIN_MODEL_SURFACE_METRIC_ANOVA_TWO_WAY_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurfaceMetricFindClustersBase.h" class MetricFile; /// class for performing a two-way anova on metric files class BrainModelSurfaceMetricAnovaTwoWay : public BrainModelSurfaceMetricFindClustersBase { public: /// anova model type enum ANOVA_MODEL_TYPE { /// invalid type ANOVA_MODEL_TYPE_INVALID, /// fixed effect ANOVA_MODEL_TYPE_FIXED_EFFECT, /// random effect ANOVA_MODEL_TYPE_RANDOM_EFFECT, /// mixed effect (A=fixed, B=random) ANOVA_MODEL_TYPE_ROWS_FIXED_EFFECT_COLUMN_RANDOM_EFFECT }; // constructor BrainModelSurfaceMetricAnovaTwoWay(BrainSet* bs, const ANOVA_MODEL_TYPE anovaModelTypeIn, const int numberOfRowsIn, const int numberOfColumnsIn, const QString& fiducialCoordFileNameIn, const QString& openTopoFileNameIn, const QString& areaCorrectionShapeFileNameIn, const QString& fMapFileNameIn, const QString& shuffledFMapFileNameIn, const QString& clustersPaintFileNameIn, const QString& clustersMetricFileNameIn, const QString& reportFileNameIn, const int areaCorrectionShapeFileColumnIn, const int iterationsIn, const float positiveThreshIn, const float pValueIn, const bool doFMapDOFIn, const bool doFMapPValueIn, const int numberOfThreadsIn); // destructor ~BrainModelSurfaceMetricAnovaTwoWay(); // set metric/shape file for a row and column void setMetricShapeFileName(const int row, const int column, const QString& metricFileName) throw (BrainModelAlgorithmException); protected: // must be implemented by subclasses void executeClusterSearch() throw (BrainModelAlgorithmException); // perform an F-Test on a set of metric files void performFTest(const std::vector& metricFiles, MetricFile* outputMetricFile, const int fStatisticColumn, const int dofColumn, const int pValueColumn) throw (BrainModelAlgorithmException); // get the index into one dimensional array of files or names int getFileIndex(const int rowNumber, const int columnNumber) const; /// type of ANOVA ANOVA_MODEL_TYPE anovaModelType; /// the input metric file names std::vector inputMetricFileNames; /// the input metric files std::vector inputMetricFiles; /// metric files that are output of shuffling std::vector shuffledMetricFiles; /// interations for generating shuffled F-Map file int iterations; /// number of rows of data int numberOfRows; /// number of columns of data int numberOfColumns; }; #endif // __BRAIN_MODEL_SURFACE_METRIC_ANOVA_TWO_WAY_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceMetricAnovaTwoWay.cxx0000664000175000017500000005050411572067322027266 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainModelSurface.h" #include "BrainModelSurfaceMetricAnovaTwoWay.h" #include "DateAndTime.h" #include "FileUtilities.h" #include "MetricFile.h" #include "StatisticAnovaTwoWay.h" #include "StatisticDataGroup.h" /** * constructor. */ BrainModelSurfaceMetricAnovaTwoWay::BrainModelSurfaceMetricAnovaTwoWay( BrainSet* bs, const ANOVA_MODEL_TYPE anovaModelTypeIn, const int numberOfRowsIn, const int numberOfColumnsIn, const QString& fiducialCoordFileNameIn, const QString& openTopoFileNameIn, const QString& areaCorrectionShapeFileNameIn, const QString& fMapFileNameIn, const QString& shuffledFMapFileNameIn, const QString& clustersPaintFileNameIn, const QString& clustersMetricFileNameIn, const QString& reportFileNameIn, const int areaCorrectionShapeFileColumnIn, const int iterationsIn, const float positiveThreshIn, const float pValueIn, const bool doFMapDOFIn, const bool doFMapPValueIn, const int numberOfThreadsIn) : BrainModelSurfaceMetricFindClustersBase(bs, fiducialCoordFileNameIn, openTopoFileNameIn, areaCorrectionShapeFileNameIn, fMapFileNameIn, shuffledFMapFileNameIn, clustersPaintFileNameIn, clustersMetricFileNameIn, reportFileNameIn, areaCorrectionShapeFileColumnIn, -std::numeric_limits::max(), // no neg positiveThreshIn, pValueIn, 0, 0.0, doFMapDOFIn, doFMapPValueIn, numberOfThreadsIn) { anovaModelType = anovaModelTypeIn; numberOfRows = numberOfRowsIn; numberOfColumns = numberOfColumnsIn; const int numFiles = numberOfRows * numberOfColumns; inputMetricFiles.resize(numFiles); inputMetricFileNames.resize(numFiles); iterations = iterationsIn; } /** * destructor. */ BrainModelSurfaceMetricAnovaTwoWay::~BrainModelSurfaceMetricAnovaTwoWay() { for (unsigned int i = 0; i < inputMetricFiles.size(); i++) { delete inputMetricFiles[i]; inputMetricFiles[i] = NULL; } inputMetricFiles.clear(); for (unsigned int i = 0; i < shuffledMetricFiles.size(); i++) { delete shuffledMetricFiles[i]; shuffledMetricFiles[i] = NULL; } shuffledMetricFiles.clear(); } /** * set metric/shape file for a row and column. */ void BrainModelSurfaceMetricAnovaTwoWay::setMetricShapeFileName(const int row, const int column, const QString& metricFileName) throw (BrainModelAlgorithmException) { const int indx = getFileIndex(row, column); if (indx >= 0) { inputMetricFileNames[indx] = metricFileName; } else { throw BrainModelAlgorithmException("Invalid indices."); } } /** * get the index into one dimensional array of files or names. */ int BrainModelSurfaceMetricAnovaTwoWay::getFileIndex(const int rowNumber, const int columnNumber) const { const int indx = (rowNumber * numberOfColumns) + columnNumber; const int maxFiles = (numberOfRows * numberOfColumns); if ((indx < 0) || (indx >= maxFiles)) { return -1; } return indx; } /** * must be implemented by subclasses. */ void BrainModelSurfaceMetricAnovaTwoWay::executeClusterSearch() throw (BrainModelAlgorithmException) { // // Steps in algorithm // enum { ALG_STEP_CHECKING_INPUT, ALG_STEP_F_MAP, ALG_STEP_SHUFFLED_F_MAP, ALG_STEP_FINDING_CLUSTERS_F_MAP, ALG_STEP_FINDING_CLUSTERS_SHUFFLED_F_MAP, ALG_NUM_STEPS }; // // Initialize the progress dialog // createProgressDialog("Two-Way ANOVA", ALG_NUM_STEPS, "BrainModelSurfaceMetricAnovaTwoWay"); updateProgressDialog("Verifying Input", ALG_STEP_CHECKING_INPUT, ALG_NUM_STEPS); // // Read the input files // const int numInputFiles = static_cast(inputMetricFileNames.size()); if (numInputFiles < 2) { throw BrainModelAlgorithmException("There must be at least two input metric files."); } inputMetricFiles.resize(numInputFiles); for (int i = 0; i < numInputFiles; i++) { if (inputMetricFileNames[i].isEmpty()) { throw BrainModelAlgorithmException("Metric file names have not been specified " "for all rows and columns."); } inputMetricFiles[i] = new MetricFile; try { inputMetricFiles[i]->readFile(inputMetricFileNames[i]); } catch (FileException& e) { throw BrainModelAlgorithmException(e); } } // // Verify number of nodes and columns // const int numberOfNodes = bms->getNumberOfNodes(); std::vector numberOfColumns(numInputFiles, 0); for (int i = 0; i < numInputFiles; i++) { if (inputMetricFiles[i]->getNumberOfNodes() != numberOfNodes) { const QString msg("Files have different number of nodes: \n" + FileUtilities::basename(inputMetricFileNames[0]) + " AND " + FileUtilities::basename(inputMetricFileNames[i])); throw BrainModelAlgorithmException(msg); } const int numCols = inputMetricFiles[i]->getNumberOfColumns(); if (numCols <= 0) { const QString msg(FileUtilities::basename(inputMetricFileNames[i]) + " contains no data columns."); throw BrainModelAlgorithmException(msg); } numberOfColumns[i] = numCols; } if (numberOfNodes != areaCorrectionShapeFile->getNumberOfNodes()) { throw BrainModelAlgorithmException("Area correction shape file has different number of nodes" "than the coordinate file."); } // // check iterations // if (iterations < 0) { throw BrainModelAlgorithmException("Iterations must be positive."); } // // Update progress // updateProgressDialog("Doing F-Map", ALG_STEP_F_MAP, ALG_NUM_STEPS); // // Create the F-Map Metric (output) File // int numOutputColumns = 0; const int fStatisticColumn = numOutputColumns++; int dofColumn = -1; if (doStatisticalMapDOF) { dofColumn = numOutputColumns++; } int pValueColumn = -1; if (doStatisticalMapPValue) { pValueColumn = numOutputColumns++; } statisticalMapShapeFile = new MetricFile; statisticalMapShapeFile->setNumberOfNodesAndColumns(numberOfNodes, numOutputColumns); // // Set the file comment // QString fileComment("Two way ANOVA for files: \n"); for (int i = 0; i < numInputFiles; i++) { fileComment += (" " + FileUtilities::basename(inputMetricFiles[i]->getFileName()) + "\n"); } statisticalMapShapeFile->setFileComment(fileComment); // // Create the F-Statistic Metric file // performFTest(inputMetricFiles, statisticalMapShapeFile, fStatisticColumn, dofColumn, pValueColumn); // // Write the F-Statistic metric file // try { statisticalMapShapeFile->writeFile(statisticalMapFileName); } catch (FileException& e) { throw BrainModelAlgorithmException(e); } // // Should a shuffled Statistical Map be created // if (iterations > 0) { // // Update progress // updateProgressDialog("Doing Shuffled F-Map", ALG_STEP_SHUFFLED_F_MAP, ALG_NUM_STEPS); // // Create shuffled statistical map metric file // shuffleStatisticalMapShapeFile = new MetricFile; shuffleStatisticalMapShapeFile->setNumberOfNodesAndColumns(numberOfNodes, iterations); // // Create metric files that will be the output of the shuffle process // for (int i = 0; i < numInputFiles; i++) { shuffledMetricFiles.push_back(new MetricFile(*inputMetricFiles[i])); } // // Perform for specified number of iterations // for (int i = 0; i < iterations; i++) { // // Shuffle the input files // try { MetricFile::shuffle(inputMetricFiles, shuffledMetricFiles); } catch (FileException& e) { throw BrainModelAlgorithmException(e); } // // Create the F-Statistic // performFTest(shuffledMetricFiles, shuffleStatisticalMapShapeFile, i, -1, -1); } // // Write the shuffled F-Statistic metric file // try { shuffleStatisticalMapShapeFile->writeFile(shuffledStatisticalMapFileName); } catch (FileException& e) { throw BrainModelAlgorithmException(e); } // // Update progress // updateProgressDialog("Finding Clusters in F-Map", ALG_STEP_FINDING_CLUSTERS_F_MAP, ALG_NUM_STEPS); // // find the clusters in F-Map // Note: column 2 is the F-Map // std::vector fMapClusters; findClusters(statisticalMapShapeFile, fMapClusters, "Finding Clusters in F-Map", fStatisticColumn, false); // // Update progress // updateProgressDialog("Finding Clusters in Shuffled F-Map", ALG_STEP_FINDING_CLUSTERS_SHUFFLED_F_MAP, ALG_NUM_STEPS); // // find the clusters in Shuffled F-Map // Note: Only use largest cluster from each column // std::vector shuffleFMapClusters; findClusters(shuffleStatisticalMapShapeFile, shuffleFMapClusters, "Finding Clusters in Shuffled F-Map", -1, true); // // Set pValue for shuffled T-Map // setRandomizedClusterPValues(*shuffleStatisticalMapShapeFile, shuffleFMapClusters); // // Find area of the "P-Value" cluster in the shuffled F-Map // float significantCorrectedArea = std::numeric_limits::max(); int pValueClusterIndex = -1; if (shuffleFMapClusters.empty() == false) { pValueClusterIndex = std::min(static_cast(pValue * iterations) - 1, static_cast(shuffleFMapClusters.size())); pValueClusterIndex = std::max(pValueClusterIndex, 0); } if (pValueClusterIndex >= 0) { significantCorrectedArea = shuffleFMapClusters[pValueClusterIndex].areaCorrected; } // // Find P-Value for significant clusters in T-Map // for (unsigned int i = 0; i < fMapClusters.size(); i++) { Cluster& fMapCluster = fMapClusters[i]; int cnt = shuffleFMapClusters.size() - 1; if (shuffleFMapClusters.empty() == false) { if (fMapCluster.areaCorrected > shuffleFMapClusters[0].areaCorrected) { cnt = 1; } else { for (unsigned int j = 0; j < shuffleFMapClusters.size() - 1; j++) { if ((fMapCluster.areaCorrected < shuffleFMapClusters[j].areaCorrected) && (fMapCluster.areaCorrected >= shuffleFMapClusters[j+1].areaCorrected)) { cnt = j + 2; } } } } cnt = std::min(cnt, iterations); fMapCluster.pValue = static_cast(cnt) / static_cast(iterations); } // // For each F-Map that has area corrected that exceeds significant area // Find its rank in shuffled tmap // P-value = rank / iterations // // Option for paint file to show the clusters // // Open the report file // QFile reportFile(reportFileName); if (reportFile.open(QIODevice::WriteOnly) == false) { std::ostringstream str; str << "Unable to open report file for writing: " << FileUtilities::basename(reportFileName).toAscii().constData(); cleanUp(); throw BrainModelAlgorithmException(str.str().c_str()); } // // Create the text stream // QTextStream reportStream(&reportFile); // // Show area and thresholds // reportStream << "Date/Time: " << DateAndTime::getDateAndTimeAsString() << "\n"; //QDateTime::currentDateTime().toString("MMM d, yyyy hh:mm:ss") << "\n"; for (int m = 0; m < numInputFiles; m++) { reportStream << "Shape File : " << inputMetricFileNames[m] << "\n"; } reportStream << "Fiducial Coord File: " << fiducialCoordFileName << "\n"; reportStream << "Open Topo File: " << openTopoFileName << "\n"; if ((areaCorrectionShapeFile != NULL) || (areaCorrectionShapeFileColumn >= 0)) { reportStream << "Area Correct File: " << areaCorrectionShapeFileName << "\n"; reportStream << "Area Correct Column: " << areaCorrectionShapeFile->getColumnName(areaCorrectionShapeFileColumn) << "\n"; } reportStream << "Positive Threshold: " << positiveThresh << "\n"; reportStream << "Iterations: " << iterations << "\n"; reportStream << "P-Value: " << pValue << "\n"; reportStream << "Significant Area: " << significantCorrectedArea << "\n"; reportStream << "\n"; // // Add significant clusters to report file // reportStream << "Shuffled FMap" << "\n"; reportStream << "-------------" << "\n"; printClusters(reportStream, shuffleFMapClusters, significantCorrectedArea); reportStream << "\n\n\n"; reportStream << "TMap" << "\n"; reportStream << "----" << "\n"; printClusters(reportStream, fMapClusters, significantCorrectedArea); reportStream << "\n\n\n"; // // Add all clusters to report file // reportStream << "Shuffled FMap" << "\n"; reportStream << "-------------" << "\n"; printClusters(reportStream, shuffleFMapClusters); reportStream << "\n\n\n"; reportStream << "FMap" << "\n"; reportStream << "----" << "\n"; printClusters(reportStream, fMapClusters); // // Close the report file // reportFile.close(); // // Do the clusters paint file // createClustersPaintFile(fMapClusters, significantCorrectedArea, numberOfNodes); // // Do the clusters metric file // createClustersMetricFile(fMapClusters, fStatisticColumn, numberOfNodes); // // Do cluster reports // for (unsigned int i = 0; i < inputMetricFileNames.size(); i++) { createMetricShapeClustersReportFile(fMapClusters, inputMetricFileNames[i]); } } // if (iterations > 0 } void BrainModelSurfaceMetricAnovaTwoWay::performFTest(const std::vector& metricFiles, MetricFile* outputMetricFile, const int fStatisticColumn, const int dofColumn, const int pValueColumn) throw (BrainModelAlgorithmException) { StatisticAnovaTwoWay::ANOVA_MODEL_TYPE statisticAnovaModel = StatisticAnovaTwoWay::ANOVA_MODEL_TYPE_INVALID; switch (anovaModelType) { case ANOVA_MODEL_TYPE_INVALID: throw BrainModelAlgorithmException("ANOVA model type is invalid"); break; case ANOVA_MODEL_TYPE_FIXED_EFFECT: statisticAnovaModel = StatisticAnovaTwoWay::ANOVA_MODEL_TYPE_FIXED_EFFECT; break; case ANOVA_MODEL_TYPE_RANDOM_EFFECT: statisticAnovaModel = StatisticAnovaTwoWay::ANOVA_MODEL_TYPE_RANDOM_EFFECT; break; case ANOVA_MODEL_TYPE_ROWS_FIXED_EFFECT_COLUMN_RANDOM_EFFECT: statisticAnovaModel = StatisticAnovaTwoWay::ANOVA_MODEL_TYPE_MIXED_EFFECT; break; } const int numberOfNodes = metricFiles[0]->getNumberOfNodes(); //const int numInputFiles = static_cast(metricFiles.size()); // // Set column names // outputMetricFile->setColumnName(fStatisticColumn, "F-Statistic"); if (dofColumn >= 0) { outputMetricFile->setColumnName(dofColumn, "DOF"); } if (pValueColumn >= 0) { outputMetricFile->setColumnName(pValueColumn, "P-Value"); } // // Loop through the nodes and create the F-Statistic for each node // for (int i = 0; i < numberOfNodes; i++) { StatisticAnovaTwoWay anova; anova.setNumberOfFactorLevels(numberOfRows, numberOfColumns); anova.setAnovaModelType(statisticAnovaModel); // // Create the data groups and add them to the algorithm // for (int m = 0; m < numberOfRows; m++) { for (int n = 0; n < numberOfColumns; n++) { // // Note, the anova algorithm will take care of deleting everything // const int indx = getFileIndex(m, n); const int numData = metricFiles[indx]->getNumberOfColumns(); float* data = new float[numData]; metricFiles[indx]->getAllColumnValuesForNode(i, data); anova.setDataArray(m, n, data, numData, true); } } // // Execute the two-way anova algorithm // try { anova.execute(); } catch (StatisticException& e) { throw BrainModelAlgorithmException(e); } // // Get the outputs of the anova algorithm // outputMetricFile->setValue(i, fStatisticColumn, anova.getfStatisticInteraction()); if (dofColumn >= 0) { outputMetricFile->setValue(i, dofColumn, anova.getDegreesOfFreedomInteractions()); } if (pValueColumn >= 0) { outputMetricFile->setValue(i, pValueColumn, anova.getPValueInteraction()); } } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceMetricAnovaOneWay.h0000664000175000017500000000700611572067322026662 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_METRIC_ANOVA_ONE_WAY_H__ #define __BRAIN_MODEL_SURFACE_METRIC_ANOVA_ONE_WAY_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurfaceMetricFindClustersBase.h" class MetricFile; /// class for performing a one-way anova on metric files class BrainModelSurfaceMetricAnovaOneWay : public BrainModelSurfaceMetricFindClustersBase { public: // constructor BrainModelSurfaceMetricAnovaOneWay(BrainSet* bs, const std::vector& inputMetricFileNamesIn, const QString& fiducialCoordFileNameIn, const QString& openTopoFileNameIn, const QString& areaCorrectionShapeFileNameIn, const QString& fMapFileNameIn, const QString& shuffledFMapFileNameIn, const QString& clustersPaintFileNameIn, const QString& clustersMetricFileNameIn, const QString& reportFileNameIn, const int areaCorrectionShapeFileColumnIn, const int iterationsIn, const float positiveThreshIn, const float pValueIn, const bool doFMapDOFIn, const bool doFMapPValueIn, const int numberOfThreadsIn); // destructor ~BrainModelSurfaceMetricAnovaOneWay(); protected: /// must be implemented by subclasses void executeClusterSearch() throw (BrainModelAlgorithmException); /// perform an F-Test on a set of metric files void performFTest(const std::vector& metricFiles, MetricFile* outputMetricFile, const int fStatisticColumn, const int dofColumn, const int pValueColumn) throw (BrainModelAlgorithmException); /// the input metric file names std::vector inputMetricFileNames; /// the input metric files std::vector inputMetricFiles; /// metric files that are output of shuffling std::vector shuffledMetricFiles; /// interations for generating shuffled F-Map file int iterations; }; #endif // __BRAIN_MODEL_SURFACE_METRIC_ANOVA_ONE_WAY_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceMetricAnovaOneWay.cxx0000664000175000017500000004354511572067322027245 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include "BrainModelSurface.h" #include "BrainModelSurfaceMetricAnovaOneWay.h" #include "DateAndTime.h" #include "FileUtilities.h" #include "MetricFile.h" #include "StatisticAnovaOneWay.h" #include "StatisticDataGroup.h" /** * constructor. */ BrainModelSurfaceMetricAnovaOneWay::BrainModelSurfaceMetricAnovaOneWay(BrainSet* bs, const std::vector& inputMetricFileNamesIn, const QString& fiducialCoordFileNameIn, const QString& openTopoFileNameIn, const QString& areaCorrectionShapeFileNameIn, const QString& fMapFileNameIn, const QString& shuffledFMapFileNameIn, const QString& clustersPaintFileNameIn, const QString& clustersMetricFileNameIn, const QString& reportFileNameIn, const int areaCorrectionShapeFileColumnIn, const int iterationsIn, const float positiveThreshIn, const float pValueIn, const bool doFMapDOFIn, const bool doFMapPValueIn, const int numberOfThreadsIn) : BrainModelSurfaceMetricFindClustersBase(bs, fiducialCoordFileNameIn, openTopoFileNameIn, areaCorrectionShapeFileNameIn, fMapFileNameIn, shuffledFMapFileNameIn, clustersPaintFileNameIn, clustersMetricFileNameIn, reportFileNameIn, areaCorrectionShapeFileColumnIn, -std::numeric_limits::max(), // no neg positiveThreshIn, pValueIn, 0, 0.0, doFMapDOFIn, doFMapPValueIn, numberOfThreadsIn) { inputMetricFileNames = inputMetricFileNamesIn; iterations = iterationsIn; } /** * destructor. */ BrainModelSurfaceMetricAnovaOneWay::~BrainModelSurfaceMetricAnovaOneWay() { for (unsigned int i = 0; i < inputMetricFiles.size(); i++) { delete inputMetricFiles[i]; inputMetricFiles[i] = NULL; } inputMetricFiles.clear(); for (unsigned int i = 0; i < shuffledMetricFiles.size(); i++) { delete shuffledMetricFiles[i]; shuffledMetricFiles[i] = NULL; } shuffledMetricFiles.clear(); } /** * must be implemented by subclasses. */ void BrainModelSurfaceMetricAnovaOneWay::executeClusterSearch() throw (BrainModelAlgorithmException) { // // Steps in algorithm // enum { ALG_STEP_CHECKING_INPUT, ALG_STEP_F_MAP, ALG_STEP_SHUFFLED_F_MAP, ALG_STEP_FINDING_CLUSTERS_F_MAP, ALG_STEP_FINDING_CLUSTERS_SHUFFLED_F_MAP, ALG_NUM_STEPS }; // // Initialize the progress dialog // createProgressDialog("One-Way ANOVA", ALG_NUM_STEPS, "BrainModelSurfaceMetricAnovaOneWay"); updateProgressDialog("Verifying Input", ALG_STEP_CHECKING_INPUT, ALG_NUM_STEPS); // // Read the input files // const int numInputFiles = static_cast(inputMetricFileNames.size()); if (numInputFiles < 2) { throw BrainModelAlgorithmException("There must be at least two input metric files."); } inputMetricFiles.resize(numInputFiles); for (int i = 0; i < numInputFiles; i++) { inputMetricFiles[i] = new MetricFile; try { inputMetricFiles[i]->readFile(inputMetricFileNames[i]); } catch (FileException& e) { throw BrainModelAlgorithmException(e); } } // // Verify number of nodes and columns // const int numberOfNodes = bms->getNumberOfNodes(); std::vector numberOfColumns(numInputFiles, 0); for (int i = 0; i < numInputFiles; i++) { if (inputMetricFiles[i]->getNumberOfNodes() != numberOfNodes) { const QString msg("Files have different number of nodes: \n" + FileUtilities::basename(inputMetricFileNames[0]) + " AND " + FileUtilities::basename(inputMetricFileNames[i])); throw BrainModelAlgorithmException(msg); } const int numCols = inputMetricFiles[i]->getNumberOfColumns(); if (numCols <= 0) { const QString msg(FileUtilities::basename(inputMetricFileNames[i]) + " contains no data columns."); throw BrainModelAlgorithmException(msg); } numberOfColumns[i] = numCols; } if (numberOfNodes != areaCorrectionShapeFile->getNumberOfNodes()) { throw BrainModelAlgorithmException("Area correction shape file has different number of nodes" "than the coordinate file."); } // // check iterations // if (iterations < 0) { throw BrainModelAlgorithmException("Iterations must be positive."); } // // Update progress // updateProgressDialog("Doing F-Map", ALG_STEP_F_MAP, ALG_NUM_STEPS); // // Create the F-Map Metric (output) File // int numOutputColumns = 0; const int fStatisticColumn = numOutputColumns++; int dofColumn = -1; if (doStatisticalMapDOF) { dofColumn = numOutputColumns++; } int pValueColumn = -1; if (doStatisticalMapPValue) { pValueColumn = numOutputColumns++; } statisticalMapShapeFile = new MetricFile; statisticalMapShapeFile->setNumberOfNodesAndColumns(numberOfNodes, numOutputColumns); // // Set the file comment // QString fileComment("One way ANOVA for files: \n"); for (int i = 0; i < numInputFiles; i++) { fileComment += (" " + FileUtilities::basename(inputMetricFiles[i]->getFileName()) + "\n"); } statisticalMapShapeFile->setFileComment(fileComment); // // Create the F-Statistic Metric file // performFTest(inputMetricFiles, statisticalMapShapeFile, fStatisticColumn, dofColumn, pValueColumn); // // Write the F-Statistic metric file // try { statisticalMapShapeFile->writeFile(statisticalMapFileName); } catch (FileException& e) { throw BrainModelAlgorithmException(e); } // // Should a shuffled Statstical Map be created // if (iterations > 0) { // // Update progress // updateProgressDialog("Doing Shuffled F-Map", ALG_STEP_SHUFFLED_F_MAP, ALG_NUM_STEPS); // // Create shuffled statistical map metric file // shuffleStatisticalMapShapeFile = new MetricFile; shuffleStatisticalMapShapeFile->setNumberOfNodesAndColumns(numberOfNodes, iterations); // // Create metric files that will be the output of the shuffle process // for (int i = 0; i < numInputFiles; i++) { shuffledMetricFiles.push_back(new MetricFile(*inputMetricFiles[i])); } // // Perform for specified number of iterations // for (int i = 0; i < iterations; i++) { // // Shuffle the input files // try { MetricFile::shuffle(inputMetricFiles, shuffledMetricFiles); } catch (FileException& e) { throw BrainModelAlgorithmException(e); } // // Create the F-Statistic // performFTest(shuffledMetricFiles, shuffleStatisticalMapShapeFile, i, -1, -1); } // // Write the shuffled F-Statistic metric file // try { shuffleStatisticalMapShapeFile->writeFile(shuffledStatisticalMapFileName); } catch (FileException& e) { throw BrainModelAlgorithmException(e); } // // Update progress // updateProgressDialog("Finding Clusters in F-Map", ALG_STEP_FINDING_CLUSTERS_F_MAP, ALG_NUM_STEPS); // // find the clusters in F-Map // Note: column 2 is the F-Map // std::vector fMapClusters; findClusters(statisticalMapShapeFile, fMapClusters, "Finding Clusters in F-Map", fStatisticColumn, false); // // Update progress // updateProgressDialog("Finding Clusters in Shuffled F-Map", ALG_STEP_FINDING_CLUSTERS_SHUFFLED_F_MAP, ALG_NUM_STEPS); // // find the clusters in Shuffled F-Map // Note: Only use largest cluster from each column // std::vector shuffleFMapClusters; findClusters(shuffleStatisticalMapShapeFile, shuffleFMapClusters, "Finding Clusters in Shuffled F-Map", -1, true); // // Set pValue for shuffled T-Map // setRandomizedClusterPValues(*shuffleStatisticalMapShapeFile, shuffleFMapClusters); // // Find area of the "P-Value" cluster in the shuffled F-Map // float significantCorrectedArea = std::numeric_limits::max(); int pValueClusterIndex = -1; if (shuffleFMapClusters.empty() == false) { pValueClusterIndex = std::min(static_cast(pValue * iterations) - 1, static_cast(shuffleFMapClusters.size())); pValueClusterIndex = std::max(pValueClusterIndex, 0); } if (pValueClusterIndex >= 0) { significantCorrectedArea = shuffleFMapClusters[pValueClusterIndex].areaCorrected; } // // Find P-Value for significant clusters in T-Map // for (unsigned int i = 0; i < fMapClusters.size(); i++) { Cluster& fMapCluster = fMapClusters[i]; int cnt = shuffleFMapClusters.size() - 1; if (shuffleFMapClusters.empty() == false) { if (fMapCluster.areaCorrected > shuffleFMapClusters[0].areaCorrected) { cnt = 1; } else { for (unsigned int j = 0; j < shuffleFMapClusters.size() - 1; j++) { if ((fMapCluster.areaCorrected < shuffleFMapClusters[j].areaCorrected) && (fMapCluster.areaCorrected >= shuffleFMapClusters[j+1].areaCorrected)) { cnt = j + 2; } } } } cnt = std::min(cnt, iterations); fMapCluster.pValue = static_cast(cnt) / static_cast(iterations); } // // For each F-Map that has area corrected that exceeds significant area // Find its rank in shuffled tmap // P-value = rank / iterations // // Option for paint file to show the clusters // // Open the report file // QFile reportFile(reportFileName); if (reportFile.open(QIODevice::WriteOnly) == false) { std::ostringstream str; str << "Unable to open report file for writing: " << FileUtilities::basename(reportFileName).toAscii().constData(); cleanUp(); throw BrainModelAlgorithmException(str.str().c_str()); } // // Create the text stream // QTextStream reportStream(&reportFile); // // Show area and thresholds // reportStream << "Date/Time: " << DateAndTime::getDateAndTimeAsString() << "\n"; for (int m = 0; m < numInputFiles; m++) { reportStream << "Shape File : " << inputMetricFileNames[m] << "\n"; } reportStream << "Fiducial Coord File: " << fiducialCoordFileName << "\n"; reportStream << "Open Topo File: " << openTopoFileName << "\n"; if ((areaCorrectionShapeFile != NULL) || (areaCorrectionShapeFileColumn >= 0)) { reportStream << "Area Correct File: " << areaCorrectionShapeFileName << "\n"; reportStream << "Area Correct Column: " << areaCorrectionShapeFile->getColumnName(areaCorrectionShapeFileColumn) << "\n"; } reportStream << "Positive Threshold: " << positiveThresh << "\n"; reportStream << "Iterations: " << iterations << "\n"; reportStream << "P-Value: " << pValue << "\n"; reportStream << "Significant Area: " << significantCorrectedArea << "\n"; reportStream << "\n"; // // Add significant clusters to report file // reportStream << "Shuffled FMap" << "\n"; reportStream << "-------------" << "\n"; printClusters(reportStream, shuffleFMapClusters, significantCorrectedArea); reportStream << "\n\n\n"; reportStream << "TMap" << "\n"; reportStream << "----" << "\n"; printClusters(reportStream, fMapClusters, significantCorrectedArea); reportStream << "\n\n\n"; // // Add all clusters to report file // reportStream << "Shuffled FMap" << "\n"; reportStream << "-------------" << "\n"; printClusters(reportStream, shuffleFMapClusters); reportStream << "\n\n\n"; reportStream << "FMap" << "\n"; reportStream << "----" << "\n"; printClusters(reportStream, fMapClusters); // // Close the report file // reportFile.close(); // // Do the clusters paint file // createClustersPaintFile(fMapClusters, significantCorrectedArea, numberOfNodes); // // Do the clusters metric file // createClustersMetricFile(fMapClusters, fStatisticColumn, numberOfNodes); // // Do cluster reports // for (unsigned int i = 0; i < inputMetricFileNames.size(); i++) { createMetricShapeClustersReportFile(fMapClusters, inputMetricFileNames[i]); } } // if (iterations > 0 } void BrainModelSurfaceMetricAnovaOneWay::performFTest(const std::vector& metricFiles, MetricFile* outputMetricFile, const int fStatisticColumn, const int dofColumn, const int pValueColumn) throw (BrainModelAlgorithmException) { const int numberOfNodes = metricFiles[0]->getNumberOfNodes(); const int numInputFiles = static_cast(metricFiles.size()); // // Set column names // outputMetricFile->setColumnName(fStatisticColumn, "F-Statistic"); if (dofColumn >= 0) { outputMetricFile->setColumnName(dofColumn, "DOF"); } if (pValueColumn >= 0) { outputMetricFile->setColumnName(pValueColumn, "P-Value"); } // // Loop through the nodes and create the F-Statistic for each node // for (int i = 0; i < numberOfNodes; i++) { StatisticAnovaOneWay anova; // // Create the data groups and add them to the algorithm // for (int j = 0; j < numInputFiles; j++) { // // Note, the anova algorithm will take care of deleting everything // const int numData = metricFiles[j]->getNumberOfColumns(); float* data = new float[numData]; metricFiles[j]->getAllColumnValuesForNode(i, data); StatisticDataGroup* sdg = new StatisticDataGroup(data, numData, StatisticDataGroup::DATA_STORAGE_MODE_TAKE_OWNERSHIP); anova.addDataGroup(sdg, true); } // // Execute the one-way anova algorithm // try { anova.execute(); } catch (StatisticException& e) { throw BrainModelAlgorithmException(e); } // // Get the outputs of the anova algorithm // outputMetricFile->setValue(i, fStatisticColumn, anova.getFStatistic()); if (dofColumn >= 0) { outputMetricFile->setValue(i, dofColumn, anova.getDegreesOfFreedomTotal()); } if (pValueColumn >= 0) { outputMetricFile->setValue(i, pValueColumn, anova.getPValue()); } } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceGeodesic.h0000664000175000017500000001413011572067322025045 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __BRAIN_MODEL_GEODESIC_H__ #define __BRAIN_MODEL_GEODESIC_H__ #include #include #include "BrainModelAlgorithm.h" class BrainModelSurface; class BrainModelSurfaceROINodeSelection; class GeodesicDistanceFile; class MetricFile; /// Class for surface geodesic distance computation. This is performed using /// Dijkstra's Shortest Path Algorithm with the surface nodes and links. /// A root node is provided and for all other nodes in the region of interest, /// its geodesic distance from the root node and its "parent neighbor" are /// added to a geodesic distance file. The "parent neighbors" can be followed to get /// the path to the root node. class BrainModelSurfaceGeodesic : public BrainModelAlgorithm { public: /// Constructor BrainModelSurfaceGeodesic(BrainSet* bs, const BrainModelSurface* surfaceIn, MetricFile* metricFileIn, const int metricFileColumnIn, const QString& metricColumnNameIn, GeodesicDistanceFile* geodesicDistanceFileIn, const int geodesicDistanceFileColumnIn, const QString& geodesicDistanceColumnName, const int rootNodeNumberIn, const BrainModelSurfaceROINodeSelection* surfaceROIIn = NULL); /// Destructor ~BrainModelSurfaceGeodesic(); /// execute the algorithm virtual void execute() throw (BrainModelAlgorithmException); protected: /// class for storing vertex information class Vertex { public: enum VERTEX_LOCATION { VERTEX_LOCATION_UNKNOWN, VERTEX_LOCATION_ACTIVE_LIST, VERTEX_LOCATION_TREE, VERTEX_LOCATION_UNVISITED }; /// Constructor Vertex(const int nodeNumberIn); /// less than operator bool operator<(const Vertex& v) const { return (distance < v.distance); } /// node node number int nodeNumber; /// neighbors std::vector neighbors; /// distances to neighbors; std::vector neighborDistance; /// number of neighbors int numNeighbors; /// distance from start node to this node float distance; /// previous node in path from start node int pathNode; /// location of this vertex VERTEX_LOCATION location; }; /// class for sorting vertices by "distance". class SortedVertex { public: /// Constructor SortedVertex(Vertex* vin) { v = vin; } /// less than operator bool operator<(const SortedVertex& sv) const { return (v->distance < sv.v->distance); } /// pointer to the vertex Vertex* v; }; typedef std::multiset::iterator SortedVertexIterator; /// place vertex in active list void addToActiveVertices(const int vertexNumber); /// place vertex in tree void addToTreeVertices(const int vertexNumber); /// place vertex in unvisited list void addToUnvisitedVertices(const int vertexNumber); /// remove a vertex from the unvisited list void removeFromUnvisitedVertices(const int vertexNumber); /// remove a vertex from the tree list void removeFromTreeVertices(const int vertexNumber); /// remove a vertex from the active list void removeFromActiveVertices(const int vertexNumber) throw (BrainModelAlgorithmException); /// surface for geodesic const BrainModelSurface* surface; /// metric file for storing geodesic info MetricFile* metricFile; /// column in metric file int metricFileColumn; /// metric column name QString metricColumnName; /// the geodesic distance file GeodesicDistanceFile* geodesicDistanceFile; /// column in geodesic distance file int geodesicDistanceFileColumn; /// name of geodesic distance column name QString geodesicDistanceColumnName; /// starting node number for geodesic distances int rootNodeNumber; /// nodes that are used for geodesic computation std::vector nodeInROI; /// nodes not yet visited std::set unvisitedVertices; /// nodes whose parent is in the tree. Use multiset since it is possible /// that nodes may be the same distance from root (distance is the /// sorting criterion. std::multiset activeVertices; /// nodes that are almost done or done std::set treeVertices; /// all of the node indexed by node number std::vector allVertices; }; #endif // __BRAIN_MODEL_GEODESIC_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceGeodesic.cxx0000664000175000017500000003710411572067322025426 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #ifdef Q_OS_WIN32 #define NOMINMAX #endif #include #include #include #include #include "BrainModelSurface.h" #include "BrainModelSurfaceGeodesic.h" #include "BrainModelSurfaceROINodeSelection.h" #include "BrainSet.h" #include "DebugControl.h" #include "DisplaySettingsGeodesicDistance.h" #include "GeodesicDistanceFile.h" #include "MetricFile.h" #include "StringUtilities.h" #include "TopologyFile.h" #include "TopologyHelper.h" /** * Constructor. If "nodeInROIIn" is NULL, then all nodes are used. * If a column number is "-3", that column is not created. * If a column number is "-2" a new column is created. */ BrainModelSurfaceGeodesic::BrainModelSurfaceGeodesic( BrainSet* bs, const BrainModelSurface* surfaceIn, MetricFile* metricFileIn, const int metricFileColumnIn, const QString& metricColumnNameIn, GeodesicDistanceFile* geodesicDistanceFileIn, const int geodesicDistanceFileColumnIn, const QString& geodesicDistanceColumnNameIn, const int rootNodeNumberIn, const BrainModelSurfaceROINodeSelection* surfaceROIIn) : BrainModelAlgorithm(bs), surface(surfaceIn), metricFile(metricFileIn), metricFileColumn(metricFileColumnIn), metricColumnName(metricColumnNameIn), geodesicDistanceFile(geodesicDistanceFileIn), geodesicDistanceFileColumn(geodesicDistanceFileColumnIn), geodesicDistanceColumnName(geodesicDistanceColumnNameIn), rootNodeNumber(rootNodeNumberIn) { const int numNodes = surface->getNumberOfNodes(); nodeInROI.resize(surface->getNumberOfNodes(), false); if (surfaceROIIn != NULL) { for (int i = 0; i < numNodes; i++) { if (surfaceROIIn->getNodeSelected(i)) { nodeInROI[i] = true; } } } else { std::fill(nodeInROI.begin(), nodeInROI.end(), true); } } /** * Destructor. */ BrainModelSurfaceGeodesic::~BrainModelSurfaceGeodesic() { } /** * execute the algorithm. */ void BrainModelSurfaceGeodesic::execute() throw (BrainModelAlgorithmException) { QTime timer; timer.start(); // // Check Inputs // if (surface == NULL) { throw BrainModelAlgorithmException("Invalid surface."); } if (geodesicDistanceFile == NULL) { throw BrainModelAlgorithmException("Invalid geodesic distance file."); } const int numNodes = surface->getNumberOfNodes(); if ((rootNodeNumber < 0) || (rootNodeNumber >= numNodes)) { throw BrainModelAlgorithmException("Invalid starting node number."); } const TopologyFile* tf = surface->getTopologyFile(); if (tf == NULL) { throw BrainModelAlgorithmException("Surface has no topology."); } // // Get the coordinate file // const CoordinateFile* cf = surface->getCoordinateFile(); // // Get the topology helper for node neighbors // const TopologyHelper* th = tf->getTopologyHelper(false, true, false); // // Reserve space to avoid reallocations // allVertices.reserve(numNodes); // // Create the vertex and edge information // for (int i = 0; i < numNodes; i++) { allVertices.push_back(Vertex(i)); Vertex& v = allVertices[i]; // // Make sure node is in region of interest // if (nodeInROI[i]) { // // Only consider node if it has neighbors // const int numNeighs = th->getNodeNumberOfNeighbors(i); if (numNeighs > 0) { // // Determine distance to each of node's neighbors // std::vector neighs; th->getNodeNeighbors(i, neighs); for (int j = 0; j < numNeighs; j++) { if (nodeInROI[neighs[j]]) { v.neighbors.push_back(neighs[j]); v.neighborDistance.push_back(cf->getDistanceBetweenCoordinates(i, neighs[j])); } } // // Only use node if it has neighbors // if (v.neighbors.empty() == false) { v.numNeighbors = static_cast(v.neighbors.size()); if (i == rootNodeNumber) { // // Root node goes into the tree // addToTreeVertices(i); } else { // // All other nodes go into unvisited list // addToUnvisitedVertices(i); } } else if (i == rootNodeNumber) { throw BrainModelAlgorithmException("Root node has no neighbors"); } } } else { // // Node not in ROI // v.distance = -1; } } // // Initialize the tree with the root node and put the roots neighbors in the active set // Vertex& rootVertex = allVertices[rootNodeNumber]; rootVertex.distance = 0; rootVertex.pathNode = rootNodeNumber; for (int i = 0; i < rootVertex.numNeighbors; i++) { const int n = rootVertex.neighbors[i]; Vertex& v = allVertices[n]; v.pathNode = rootNodeNumber; v.distance = rootVertex.neighborDistance[i]; removeFromUnvisitedVertices(n); addToActiveVertices(n); } // // Do until no active nodes // while (activeVertices.empty() == false) { // // Get the active node closest to the root node // SortedVertexIterator iter = activeVertices.begin(); SortedVertex sv = *iter; Vertex* v = sv.v; // // Keeps track of nodes that need to be moved to the active list // std::vector moveToActiveVertices; // // Check the node's neighbors // for (int i = 0; i < v->numNeighbors; i++) { // // Distance from root to active node to neighbor // const float dist = v->distance + v->neighborDistance[i]; // // Is this a shorter path than neighbor's current path distance // const int neighNodeNumber = v->neighbors[i]; Vertex& neighborVertex = allVertices[neighNodeNumber]; if (dist < neighborVertex.distance) { // // Update neighbors distance and path and move it to the active list // neighborVertex.distance = dist; neighborVertex.pathNode = v->nodeNumber; moveToActiveVertices.push_back(neighNodeNumber); } } // // Remove active node from active list and move to the tree // removeFromActiveVertices(v->nodeNumber); addToTreeVertices(v->nodeNumber); // // Move modified nodes to active list // for (int i = 0; i < static_cast(moveToActiveVertices.size()); i++) { const int vn = moveToActiveVertices[i]; Vertex& v = allVertices[vn]; const int vertexNumber = v.nodeNumber; switch (v.location) { case Vertex::VERTEX_LOCATION_UNKNOWN: throw BrainModelAlgorithmException("PROGRAM ERROR: VERTEX_LOCATION_UNKNOWN"); break; case Vertex::VERTEX_LOCATION_ACTIVE_LIST: removeFromActiveVertices(vertexNumber); break; case Vertex::VERTEX_LOCATION_TREE: removeFromTreeVertices(vertexNumber); break; case Vertex::VERTEX_LOCATION_UNVISITED: removeFromUnvisitedVertices(vertexNumber); break; } addToActiveVertices(vertexNumber); } } // // column comment // QString columnComment("Geodesic for node: "); columnComment.append(StringUtilities::fromNumber(rootNodeNumber)); // // Add column onto the metric file if needed // if (metricFile != NULL) { if (metricFileColumn >= -2) { if (metricFile->getNumberOfColumns() == 0) { metricFile->setNumberOfNodesAndColumns(numNodes, 1); metricFileColumn = 0; } else if ((metricFileColumn == -2) || (metricFileColumn >= metricFile->getNumberOfColumns())) { metricFile->addColumns(1); metricFileColumn = metricFile->getNumberOfColumns() - 1; } } } // // Add column onto the geodesic distance file if needed // if (geodesicDistanceFileColumn >= -2) { if (geodesicDistanceFile->getNumberOfColumns() == 0) { geodesicDistanceFile->setNumberOfNodesAndColumns(numNodes, 1); geodesicDistanceFileColumn = 0; } else if ((geodesicDistanceFileColumn == -2) || (geodesicDistanceFileColumn >= geodesicDistanceFile->getNumberOfColumns())) { geodesicDistanceFile->addColumns(1); geodesicDistanceFileColumn = geodesicDistanceFile->getNumberOfColumns() - 1; } // // Set root node number // geodesicDistanceFile->setRootNode(geodesicDistanceFileColumn, rootNodeNumber); } // // Name the metric column // if (metricFile != NULL) { if (metricFileColumn >= 0) { if (metricColumnName.isEmpty()) { std::ostringstream str1; str1 << "Geo Dist Node: " << rootNodeNumber; metricColumnName = str1.str().c_str(); } metricFile->setColumnName(metricFileColumn, metricColumnName); metricFile->setColumnComment(metricFileColumn, columnComment); } } // // Name the geodesic column // if (geodesicDistanceFileColumn >= 0) { if (geodesicDistanceColumnName.isEmpty()) { std::ostringstream str1; str1 << "Geo Dist Node: " << rootNodeNumber; geodesicDistanceColumnName = str1.str().c_str(); } geodesicDistanceFile->setColumnName(geodesicDistanceFileColumn, geodesicDistanceColumnName); geodesicDistanceFile->setColumnComment(geodesicDistanceFileColumn, columnComment); } // // Copy the geodesic distances and nodes to the metric file columns // for (int i = 0; i < numNodes; i++) { if (metricFile != NULL) { if (metricFileColumn >= 0) { metricFile->setValue(i, metricFileColumn, allVertices[i].distance); } } if (geodesicDistanceFileColumn >= 0) { geodesicDistanceFile->setNodeParent(i, geodesicDistanceFileColumn, allVertices[i].pathNode); geodesicDistanceFile->setNodeParentDistance(i, geodesicDistanceFileColumn, allVertices[i].distance); } } brainSet->getDisplaySettingsGeodesicDistance()->update(); if (DebugControl::getDebugOn()) { std::cout << "Time to compute geodesic was: " << timer.elapsed() * 0.001 << std::endl; } } /** * place vertex in active list. */ void BrainModelSurfaceGeodesic::addToActiveVertices(const int vertexNumber) { allVertices[vertexNumber].location = Vertex::VERTEX_LOCATION_ACTIVE_LIST; activeVertices.insert(SortedVertex(&allVertices[vertexNumber])); if (DebugControl::getDebugOn()) { if (vertexNumber == DebugControl::getDebugNodeNumber()) { std::cout << "Added " << vertexNumber << " to active vertices." << std::endl; } } } /** * remove a vertex from the active list */ void BrainModelSurfaceGeodesic::removeFromActiveVertices(const int vertexNumber) throw (BrainModelAlgorithmException) { bool found = false; for (SortedVertexIterator iter = activeVertices.begin(); iter != activeVertices.end(); iter++) { if (iter->v->nodeNumber == vertexNumber) { activeVertices.erase(iter); found = true; if (DebugControl::getDebugOn()) { if (vertexNumber == DebugControl::getDebugNodeNumber()) { std::cout << "Removed " << vertexNumber << " from active vertices." << std::endl; } } break; } } if (found == false) { if (DebugControl::getDebugOn()) { std::cout << "Active list at time of failure: "; for (SortedVertexIterator iter = activeVertices.begin(); iter != activeVertices.end(); iter++) { std::cout << " " << iter->v->nodeNumber; } std::cout << std::endl; } throw BrainModelAlgorithmException( "PROGRAM ERROR: Failed to remove from activeVertices"); } } /** * place vertex in tree. */ void BrainModelSurfaceGeodesic::addToTreeVertices(const int vertexNumber) { allVertices[vertexNumber].location = Vertex::VERTEX_LOCATION_TREE; treeVertices.insert(vertexNumber); if (DebugControl::getDebugOn()) { if (vertexNumber == DebugControl::getDebugNodeNumber()) { std::cout << "Added " << vertexNumber << " to tree vertices." << std::endl; } } } /** * remove vertex from tree. */ void BrainModelSurfaceGeodesic::removeFromTreeVertices(const int vertexNumber) { treeVertices.erase(vertexNumber); if (DebugControl::getDebugOn()) { if (vertexNumber == DebugControl::getDebugNodeNumber()) { std::cout << "Removed " << vertexNumber << " from tree vertices." << std::endl; } } } /** * place vertex in unvisited list. */ void BrainModelSurfaceGeodesic::addToUnvisitedVertices(const int vertexNumber) { allVertices[vertexNumber].location = Vertex::VERTEX_LOCATION_UNVISITED; unvisitedVertices.insert(vertexNumber); if (DebugControl::getDebugOn()) { if (vertexNumber == DebugControl::getDebugNodeNumber()) { std::cout << "Added " << vertexNumber << " to unvisited vertices." << std::endl; } } } /** * remove vertex from unvisited. */ void BrainModelSurfaceGeodesic::removeFromUnvisitedVertices(const int vertexNumber) { unvisitedVertices.erase(vertexNumber); if (DebugControl::getDebugOn()) { if (vertexNumber == DebugControl::getDebugNodeNumber()) { std::cout << "Removed " << vertexNumber << " from unvisited vertices." << std::endl; } } } //-------------------------------------------------------------------------------------- /** * Constructor. */ BrainModelSurfaceGeodesic::Vertex::Vertex(const int nodeNumberIn) { nodeNumber = nodeNumberIn; numNeighbors = 0; distance = std::numeric_limits::max(); pathNode = -1; location = VERTEX_LOCATION_UNKNOWN; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceFociUncertaintyToRgbPaint.h0000664000175000017500000001005111572067322030361 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_FOCI_UNCERTAINTY_TO_RGB_PAINT_H__ #define __BRAIN_MODEL_SURFACE_FOCI_UNCERTAINTY_TO_RGB_PAINT_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelAlgorithm.h" class BrainModelSurface; class FociProjectionFile; class FociColorFile; class RgbPaintFile; /// Class that converts foci uncertainty into an RGB Paint file. class BrainModelSurfaceFociUncertaintyToRgbPaint : public BrainModelAlgorithm { public: /// Constructor BrainModelSurfaceFociUncertaintyToRgbPaint( BrainSet* bsIn, const BrainModelSurface* leftSurfaceIn, const BrainModelSurface* rightSurfaceIn, RgbPaintFile* rgbPaintFileIn, const int leftRgbPaintFileColumnIn, const QString& leftRgbPaintFileColumnNameIn, const int rightRgbPaintFileColumnIn, const QString& rightRgbPaintFileColumnNameIn, const FociProjectionFile* fociProjectionFileIn, const FociColorFile* fociColorFileIn, const float lowerLimitIn, const float middleLimitIn, const float upperLimitIn); /// Destructor ~BrainModelSurfaceFociUncertaintyToRgbPaint(); /// execute the algorithm void execute() throw (BrainModelAlgorithmException); protected: /// Convert foci uncertainty to rgb paint (returns true if successful). void generateLimits(const BrainModelSurface* bms, const int rgbPaintColumnIn, const QString& rgbPaintColumnNewName, int& progressSteps) throw (BrainModelAlgorithmException); /// Convert foci uncertainty to rgb paint (returns true if successful). void generateLimitsOLD(const BrainModelSurface* bms, const int rgbPaintColumnIn, const QString& rgbPaintColumnNewName) throw (BrainModelAlgorithmException); /// the left surface const BrainModelSurface* leftSurface; /// the right surface const BrainModelSurface* rightSurface; /// the rgb paint file RgbPaintFile* rgbPaintFile; /// column to set for left surface data int leftRgbPaintFileColumn; /// name of column for left surface data QString leftRgbPaintFileColumnName; /// column to set for right surface data int rightRgbPaintFileColumn; /// name of column for right surface data QString rightRgbPaintFileColumnName; /// the foci projection file const FociProjectionFile* fociProjectionFile; /// the foci color file const FociColorFile* fociColorFile; /// the lower limit float lowerLimit; /// the middle limit float middleLimit; /// the upper limit float upperLimit; }; #endif // __BRAIN_MODEL_SURFACE_FOCI_UNCERTAINTY_TO_RGB_PAINT_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceFociUncertaintyToRgbPaint.cxx0000664000175000017500000005522711572067322030752 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include "BrainModelSurface.h" #include "BrainModelSurfaceFociUncertaintyToRgbPaint.h" #include "BrainSet.h" #include "FociProjectionFile.h" #include "FociColorFile.h" #include "MathUtilities.h" #include "PreferencesFile.h" #include "RgbPaintFile.h" #include "vtkMath.h" /** * Constructor. */ BrainModelSurfaceFociUncertaintyToRgbPaint::BrainModelSurfaceFociUncertaintyToRgbPaint( BrainSet* bsIn, const BrainModelSurface* leftSurfaceIn, const BrainModelSurface* rightSurfaceIn, RgbPaintFile* rgbPaintFileIn, const int leftRgbPaintFileColumnIn, const QString& leftRgbPaintFileColumnNameIn, const int rightRgbPaintFileColumnIn, const QString& rightRgbPaintFileColumnNameIn, const FociProjectionFile* fociProjectionFileIn, const FociColorFile* fociColorFileIn, const float lowerLimitIn, const float middleLimitIn, const float upperLimitIn) : BrainModelAlgorithm(bsIn), leftSurface(leftSurfaceIn), rightSurface(rightSurfaceIn), rgbPaintFile(rgbPaintFileIn), leftRgbPaintFileColumn(leftRgbPaintFileColumnIn), leftRgbPaintFileColumnName(leftRgbPaintFileColumnNameIn), rightRgbPaintFileColumn(rightRgbPaintFileColumnIn), rightRgbPaintFileColumnName(rightRgbPaintFileColumnNameIn), fociProjectionFile(fociProjectionFileIn), fociColorFile(fociColorFileIn), lowerLimit(lowerLimitIn), middleLimit(middleLimitIn), upperLimit(upperLimitIn) { } /** * Destructor. */ BrainModelSurfaceFociUncertaintyToRgbPaint::~BrainModelSurfaceFociUncertaintyToRgbPaint() { } /** * execute the algorithm. */ void BrainModelSurfaceFociUncertaintyToRgbPaint::execute() throw (BrainModelAlgorithmException) { if ((leftSurface == NULL) && (rightSurface == NULL)) { throw BrainModelAlgorithmException("Both surfaces are invalid."); } if (rgbPaintFile == NULL) { throw BrainModelAlgorithmException("The RGB Paint File is invalid."); } if (fociProjectionFile == NULL) { throw BrainModelAlgorithmException("The Foci Projection File is invalid."); } if (fociColorFile == NULL) { throw BrainModelAlgorithmException("The Foci Color File is invalid."); } if (fociProjectionFile->getNumberOfCellProjections() <= 0) { throw BrainModelAlgorithmException("The Foci Projection File contains no foci."); } if (fociProjectionFile->getNumberOfCellClasses() <= 0) { throw BrainModelAlgorithmException("There are no foci classes."); } int numNodes = 0; if (leftSurface != NULL) { numNodes += leftSurface->getNumberOfNodes(); } if (rightSurface != NULL) { numNodes += rightSurface->getNumberOfNodes(); } createProgressDialog("Determining Foci Uncertainty", numNodes, "fociUncertainty"); int progressSteps = 0; try { if (leftSurface != NULL) { generateLimits(leftSurface, leftRgbPaintFileColumn, leftRgbPaintFileColumnName, progressSteps); } if (rightSurface != NULL) { generateLimits(rightSurface, rightRgbPaintFileColumn, rightRgbPaintFileColumnName, progressSteps); } } catch (BrainModelAlgorithmException& e) { removeProgressDialog(); throw e; } removeProgressDialog(); } /** * Convert foci uncertainty to rgb paint (returns true if successful). */ void BrainModelSurfaceFociUncertaintyToRgbPaint::generateLimits(const BrainModelSurface* bms, const int rgbPaintColumnIn, const QString& rgbPaintColumnNewName, int& progressSteps) throw (BrainModelAlgorithmException) { // const float upperLimitSquared = upperLimit*upperLimit; // // Get number of foci classes // const int numClasses = fociProjectionFile->getNumberOfCellClasses(); const int numFoci = fociProjectionFile->getNumberOfCellProjections(); const TopologyFile* tf = bms->getTopologyFile(); const CoordinateFile* cf = bms->getCoordinateFile(); const int numCoords = cf->getNumberOfCoordinates(); if (numCoords <= 0) { throw BrainModelAlgorithmException("The surface has no coordinates."); } if (tf == NULL) { throw BrainModelAlgorithmException("The surface has no topology."); } if (tf->getNumberOfTiles() <= 0) { throw BrainModelAlgorithmException("The surface's topology contains no triangles."); } // // Storage for number of nodes in each class // std::vector nodeCount(numClasses, 0); // // Initialize color to foreground color // unsigned char foregroundColor[3]; PreferencesFile* pref = brainSet->getPreferencesFile(); pref->getSurfaceForegroundColor(foregroundColor[0], foregroundColor[1], foregroundColor[2]); // // Add a column to the rgb paint file // int rgbPaintColumn = rgbPaintColumnIn; if (rgbPaintFile->getNumberOfNodes() == 0) { rgbPaintFile->setNumberOfNodesAndColumns(bms->getNumberOfNodes(), 1); rgbPaintColumn = 0; } else if ((rgbPaintColumn < 0) || (rgbPaintColumn >= rgbPaintFile->getNumberOfColumns())) { rgbPaintColumn = rgbPaintFile->getNumberOfColumns(); rgbPaintFile->addColumns(1); } rgbPaintFile->setColumnName(rgbPaintColumn, rgbPaintColumnNewName); rgbPaintFile->setScaleRed(rgbPaintColumn, 0, 255.0); rgbPaintFile->setScaleGreen(rgbPaintColumn, 0, 255.0); rgbPaintFile->setScaleBlue(rgbPaintColumn, 0, 255.0); rgbPaintFile->setColumnComment(rgbPaintColumn, "Created from foci uncertainty"); const bool fiducialSurfaceFlag = bms->getIsFiducialSurface(); const bool flatSurfaceFlag = bms->getIsFlatSurface(); const Structure::STRUCTURE_TYPE surfaceStructureType = bms->getStructure().getType(); // // Loop through fiducial coordinates // for (int i = 0; i < numCoords; i++) { // // Update progress // if (progressDialog != NULL) { const float pctComplete = (static_cast(progressSteps) / progressDialog->maximum()) * 100.0; const QString pctString(QString::number(pctComplete, 'f', 1) + "% complete."); updateProgressDialog(pctString, progressSteps); } else { updateProgressDialog("Determining Uncertainty", progressSteps); } progressSteps++; // // Keep track of nodes in the various classes nearest to this node. // std::vector focusNearestNode(numClasses, -1); std::vector focusDistanceToNode(numClasses, std::numeric_limits::max()); // // Get the position of the node // const float* nodePos = cf->getCoordinate(i); // // Loop through foci // for (int k = 0; k < numFoci; k++) { // // Get the foci's and see if it is displayed // const CellProjection* focus = fociProjectionFile->getCellProjection(k); if (focus->getDisplayFlag()) { // // Get the foci's class and see if it matches the current foci class // const int classNumber = focus->getClassIndex(); if (classNumber >= 0) { // // Get the foci's position and adjust for hemisphere // bool useFocus = false; float fociPos[3]; if (focus->getProjectedPosition(cf, tf, fiducialSurfaceFlag, flatSurfaceFlag, false, fociPos)) { if (focus->getCellStructure() == surfaceStructureType) { useFocus = true; } } if (useFocus) { // // See how close this focus is to coordinate // const float distSQ = MathUtilities::distanceSquared3D(fociPos, nodePos); if ((distSQ < upperLimitSquared) && (distSQ < focusDistanceToNode[classNumber])) { focusNearestNode[classNumber] = k; focusDistanceToNode[classNumber] = distSQ; } } } } } for (int m = 0; m < numClasses; m++) { focusDistanceToNode[m] = std::sqrt(focusDistanceToNode[m]); } // // Node coloring // float nodeColor[3] = { -1.0, -1.0, -1.0 }; std::vector nearbyFoci; std::vector nearbyFociDistances; // // Loop through foci classes // for (int j = 0; j < numClasses; j++) { if (focusNearestNode[j] >= 0) { if ((focusDistanceToNode[j] >= lowerLimit) && (focusDistanceToNode[j] <= upperLimit)) { nearbyFoci.push_back(focusNearestNode[j]); nearbyFociDistances.push_back(focusDistanceToNode[j]); } } } const int nearbyFociCount = static_cast(nearbyFoci.size()); if (nearbyFociCount > 2) { // // Paint node gray // nodeColor[0] = 50.0; nodeColor[1] = 50.0; nodeColor[2] = 50.0; } else if (nearbyFociCount == 2) { // // Get color of foci nearest the node // int colorIndex = fociProjectionFile->getCellProjection(nearbyFoci[0])->getColorIndex(); unsigned char r, g, b; if (colorIndex >= 0) { fociColorFile->getColorByIndex(colorIndex, r, g, b); } else { // // Use foreground color // r = foregroundColor[0]; g = foregroundColor[1]; b = foregroundColor[2]; } const float r1 = r; const float g1 = g; const float b1 = b; // // Get color of foci second nearest the node // colorIndex = fociProjectionFile->getCellProjection(nearbyFoci[1])->getColorIndex(); if (colorIndex >= 0) { fociColorFile->getColorByIndex(colorIndex, r, g, b); } else { // // Use foreground color // r = foregroundColor[0]; g = foregroundColor[1]; b = foregroundColor[2]; } const float r2 = r; const float g2 = g; const float b2 = b; const float m = std::max(r1+r2, std::max(g1+g2, b1+b2)); nodeColor[0] = 255.0 * (r1 + r2) / m; nodeColor[1] = 255.0 * (g1 + g2) / m; nodeColor[2] = 255.0 * (b1 + b2) / m; } else if (nearbyFociCount == 1) { // // Use the foci's color // const int colorIndex = fociProjectionFile->getCellProjection(nearbyFoci[0])->getColorIndex(); if (colorIndex >= 0) { unsigned char r, g, b; fociColorFile->getColorByIndex(colorIndex, r, g, b); nodeColor[0] = r; nodeColor[1] = g; nodeColor[2] = b; } else { // // Use foreground color // nodeColor[0] = foregroundColor[0]; nodeColor[1] = foregroundColor[1]; nodeColor[2] = foregroundColor[2]; } // // If within middle limit, whiten the node to produce a halo effect // if (nearbyFociDistances[0] < middleLimit) { nodeColor[0] = 127.5 + 0.5 * nodeColor[0]; nodeColor[1] = 127.5 + 0.5 * nodeColor[1]; nodeColor[2] = 127.5 + 0.5 * nodeColor[2]; } } // // Add to rgb paint file // const float max255 = 255.0; nodeColor[0] = std::min(nodeColor[0], max255); nodeColor[1] = std::min(nodeColor[1], max255); nodeColor[2] = std::min(nodeColor[2], max255); rgbPaintFile->setRgb(i, rgbPaintColumn, nodeColor[0], nodeColor[1], nodeColor[2]); } } /** * Convert foci uncertainty to rgb paint (returns true if successful). */ void BrainModelSurfaceFociUncertaintyToRgbPaint::generateLimitsOLD(const BrainModelSurface* bms, const int rgbPaintColumnIn, const QString& rgbPaintColumnNewName) throw (BrainModelAlgorithmException) { // const float upperLimitSquared = upperLimit*upperLimit; // // Get number of foci classes // const int numClasses = fociProjectionFile->getNumberOfCellClasses(); const int numFoci = fociProjectionFile->getNumberOfCellProjections(); const TopologyFile* tf = bms->getTopologyFile(); const CoordinateFile* cf = bms->getCoordinateFile(); const int numCoords = cf->getNumberOfCoordinates(); if (numCoords <= 0) { throw BrainModelAlgorithmException("There surface has no coordinates."); } if (tf == NULL) { throw BrainModelAlgorithmException("There surface has no topology."); } if (tf->getNumberOfTiles() <= 0) { throw BrainModelAlgorithmException("There surface's topology contains no triangles."); } // // Storage for number of nodes in each class // std::vector nodeCount(numClasses, 0); // // Initialize color to foreground color // unsigned char foregroundColor[3]; PreferencesFile* pref = brainSet->getPreferencesFile(); pref->getSurfaceForegroundColor(foregroundColor[0], foregroundColor[1], foregroundColor[2]); // // Add a column to the rgb paint file // int rgbPaintColumn = rgbPaintColumnIn; if (rgbPaintFile->getNumberOfNodes() == 0) { rgbPaintFile->setNumberOfNodesAndColumns(bms->getNumberOfNodes(), 1); rgbPaintColumn = 0; } else if ((rgbPaintColumn < 0) || (rgbPaintColumn >= rgbPaintFile->getNumberOfColumns())) { rgbPaintColumn = rgbPaintFile->getNumberOfColumns(); rgbPaintFile->addColumns(1); } rgbPaintFile->setColumnName(rgbPaintColumn, rgbPaintColumnNewName); rgbPaintFile->setScaleRed(rgbPaintColumn, 0, 255.0); rgbPaintFile->setScaleGreen(rgbPaintColumn, 0, 255.0); rgbPaintFile->setScaleBlue(rgbPaintColumn, 0, 255.0); rgbPaintFile->setColumnComment(rgbPaintColumn, "Created from foci uncertainty"); const bool fiducialSurfaceFlag = bms->getIsFiducialSurface(); const bool flatSurfaceFlag = bms->getIsFlatSurface(); const Structure::STRUCTURE_TYPE surfaceStructureType = bms->getStructure().getType(); // // Loop through fiducial coordinates // for (int i = 0; i < numCoords; i++) { // // Keep track of nodes in the various classes nearest to this node. // std::vector focusNearestNode(numClasses, -1); std::vector focusDistanceToNode(numClasses, 0.0); // // Get the position of the node // const float* nodePos = cf->getCoordinate(i); // // Loop through foci classes // for (int fociClass = 0; fociClass < numClasses; fociClass++) { int closestFocus = -1; float closestFocusDistance = std::numeric_limits::max(); // // Loop through foci // for (int k = 0; k < numFoci; k++) { // // Get the foci's and see if it is displayed // const CellProjection* focus = fociProjectionFile->getCellProjection(k); if (focus->getDisplayFlag()) { // // Get the foci's class and see if it matches the current foci class // const int classNumber = focus->getClassIndex(); if (classNumber == fociClass) { // // Get the foci's position and adjust for hemisphere // bool useFocus = false; float fociPos[3]; if (focus->getProjectedPosition(cf, tf, fiducialSurfaceFlag, flatSurfaceFlag, false, fociPos)) { if (focus->getCellStructure() == surfaceStructureType) { useFocus = true; } } if (useFocus) { // // See how close this focus is to coordinate // const float distSquared = vtkMath::Distance2BetweenPoints(fociPos, nodePos); if ((distSquared < upperLimitSquared) && (distSquared < closestFocusDistance)) { closestFocus = k; closestFocusDistance = distSquared; } } } } } if (closestFocus >= 0) { focusNearestNode[fociClass] = closestFocus; focusDistanceToNode[fociClass] = std::sqrt(closestFocusDistance); } } // // Node coloring // float nodeColor[3] = { 0.0, 0.0, 0.0 }; std::vector nearbyFoci; std::vector nearbyFociDistances; // // Loop through foci classes // for (int j = 0; j < numClasses; j++) { if (focusNearestNode[j] >= 0) { if ((focusDistanceToNode[j] >= lowerLimit) && (focusDistanceToNode[j] <= upperLimit)) { nearbyFoci.push_back(focusNearestNode[j]); nearbyFociDistances.push_back(focusDistanceToNode[j]); } } } const int nearbyFociCount = static_cast(nearbyFoci.size()); if (nearbyFociCount > 2) { // // Paint node gray // nodeColor[0] = 50.0; nodeColor[1] = 50.0; nodeColor[2] = 50.0; } else if (nearbyFociCount == 2) { // // Get color of foci nearest the node // int colorIndex = fociProjectionFile->getCellProjection(nearbyFoci[0])->getColorIndex(); unsigned char r, g, b; if (colorIndex >= 0) { fociColorFile->getColorByIndex(colorIndex, r, g, b); } else { // // Use foreground color // r = foregroundColor[0]; g = foregroundColor[1]; b = foregroundColor[2]; } const float r1 = r; const float g1 = g; const float b1 = b; // // Get color of foci second nearest the node // colorIndex = fociProjectionFile->getCellProjection(nearbyFoci[1])->getColorIndex(); if (colorIndex >= 0) { fociColorFile->getColorByIndex(colorIndex, r, g, b); } else { // // Use foreground color // r = foregroundColor[0]; g = foregroundColor[1]; b = foregroundColor[2]; } const float r2 = r; const float g2 = g; const float b2 = b; const float m = std::max(r1+r2, std::max(g1+g2, b1+b2)); nodeColor[0] = 255.0 * (r1 + r2) / m; nodeColor[1] = 255.0 * (g1 + g2) / m; nodeColor[2] = 255.0 * (b1 + b2) / m; } else if (nearbyFociCount == 1) { // // Use the foci's color // const int colorIndex = fociProjectionFile->getCellProjection(nearbyFoci[0])->getColorIndex(); if (colorIndex >= 0) { unsigned char r, g, b; fociColorFile->getColorByIndex(colorIndex, r, g, b); nodeColor[0] = r; nodeColor[1] = g; nodeColor[2] = b; } else { // // Use foreground color // nodeColor[0] = foregroundColor[0]; nodeColor[1] = foregroundColor[1]; nodeColor[2] = foregroundColor[2]; } // // If within middle limit, whiten the node to produce a halo effect // if (nearbyFociDistances[0] < middleLimit) { nodeColor[0] = 127.5 + 0.5 * nodeColor[0]; nodeColor[1] = 127.5 + 0.5 * nodeColor[1]; nodeColor[2] = 127.5 + 0.5 * nodeColor[2]; } } // // Add to rgb paint file // const float max255 = 255.0; nodeColor[0] = std::min(nodeColor[0], max255); nodeColor[1] = std::min(nodeColor[1], max255); nodeColor[2] = std::min(nodeColor[2], max255); rgbPaintFile->setRgb(i, rgbPaintColumn, nodeColor[0], nodeColor[1], nodeColor[2]); } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceFociSearch.h0000664000175000017500000000772011572067322025340 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_FOCI_SEARCH_H__ #define __BRAIN_MODEL_SURFACE_FOCI_SEARCH_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelAlgorithm.h" #include "FociSearchFile.h" class CellProjection; class FociProjectionFile; class StudyMetaData; class StudyMetaDataFile; /// class for searching foci class BrainModelSurfaceFociSearch : public BrainModelAlgorithm { public: /// search mode enum SEARCH_MODE { /// search all foci SEARCH_MODE_ALL_FOCI, /// search only those marked as searched SEARCH_MODE_DISPLAYED_FOCI }; // constructor BrainModelSurfaceFociSearch(BrainSet* bsIn, const StudyMetaDataFile* studyMetaDataFileIn, FociProjectionFile* fociProjectionFileIn, const FociSearchSet* fociSearchSetIn, const SEARCH_MODE searchModeIn, const bool selectAllFociInMatchingStudiesFlagIn); // destructor ~BrainModelSurfaceFociSearch(); // execute the algorithm void execute() throw (BrainModelAlgorithmException); /// get the number of foci meeting search parameters int getNumberOfMatchingFoci() const { return numberOfFociInSearch; } /// get the number of foci from matching studies int getNumberOfFociFromMatchingStudies() const { return numberOfFociFromMatchingStudies; } /// number of studies from which matched foci originate int getNumberOfStudiesUsedByMatchingFoci() const { return numberOfStudiesUsedByMatchingFoci; } protected: // apply the search to a focus bool applySearchToFocus(const FociSearch* fociSearch, const CellProjection* focus, const float* spatialXYZRange); // include foci in matching studies into search void includeFociInMatchingStudiesIntoSearch(const std::set& matchingStudiesPubMedIDs); // get the text for the attribute QString getAttributeText(const FociSearch::ATTRIBUTE attribute, const CellProjection* focus, std::vector studies) const; /// the study meta data file const StudyMetaDataFile* studyMetaDataFile; /// the foci projection file FociProjectionFile* fociProjectionFile; /// the foci search set const FociSearchSet* fociSearchSet; /// the search mode const SEARCH_MODE searchMode; /// also select foci in matching studies const bool selectAllFociInMatchingStudiesFlag; /// number of foci meeting search parameters int numberOfFociInSearch; /// number of foci from matching studies int numberOfFociFromMatchingStudies; /// number of studies from which matched foci originate int numberOfStudiesUsedByMatchingFoci; }; #endif // __BRAIN_MODEL_SURFACE_FOCI_SEARCH_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceFociSearch.cxx0000664000175000017500000005373211572067322025717 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelSurfaceFociSearch.h" #include "FociProjectionFile.h" #include "MathUtilities.h" #include "Structure.h" #include "StudyMetaDataFile.h" /** * constructor. */ BrainModelSurfaceFociSearch::BrainModelSurfaceFociSearch(BrainSet* bsIn, const StudyMetaDataFile* studyMetaDataFileIn, FociProjectionFile* fociProjectionFileIn, const FociSearchSet* fociSearchSetIn, const SEARCH_MODE searchModeIn, const bool selectAllFociInMatchingStudiesFlagIn) : BrainModelAlgorithm(bsIn), studyMetaDataFile(studyMetaDataFileIn), fociProjectionFile(fociProjectionFileIn), fociSearchSet(fociSearchSetIn), searchMode(searchModeIn), selectAllFociInMatchingStudiesFlag(selectAllFociInMatchingStudiesFlagIn) { numberOfFociInSearch = 0; numberOfFociFromMatchingStudies = 0; numberOfStudiesUsedByMatchingFoci = 0; } /** * destructor. */ BrainModelSurfaceFociSearch::~BrainModelSurfaceFociSearch() { } /** * execute the algorithm. */ void BrainModelSurfaceFociSearch::execute() throw (BrainModelAlgorithmException) { numberOfFociInSearch = 0; numberOfFociFromMatchingStudies = 0; numberOfStudiesUsedByMatchingFoci = 0; // // Make sure there are search parameters // const int numSearchParameters = fociSearchSet->getNumberOfFociSearches(); if (numSearchParameters <= 0) { throw BrainModelAlgorithmException("The search contains no search parameters."); } // // Spatial search coordinates and range // std::vector spatialSearchXYZRange(numSearchParameters * 4, 0); // // Check search parameters // QString msg; for (int i = 0; i < numSearchParameters; i++) { const FociSearch* fs = fociSearchSet->getFociSearch(i); if (fs->getSearchText().isEmpty()) { msg += ("Search parameter " + QString::number(i + 1) + " text is empty\n"); } // // Check spatial searches // if (fs->getAttribute() == FociSearch::ATTRIBUTE_FOCUS_SPATIAL) { const QString regExpText("(\\s|,|;)+"); const QStringList sl = fs->getSearchText().split(QRegExp(regExpText), QString::SkipEmptyParts); if (sl.size() == 4) { const int i4 = i * 4; spatialSearchXYZRange[i4] = sl.at(0).toDouble(); spatialSearchXYZRange[i4+1] = sl.at(1).toDouble(); spatialSearchXYZRange[i4+2] = sl.at(2).toDouble(); spatialSearchXYZRange[i4+3] = sl.at(3).toDouble(); } else { msg += ("ERROR: " + fs->getSearchText() + " must be 4 floating point numbers (x, y, z, range).\n"); } } } if (msg.isEmpty() == false) { throw BrainModelAlgorithmException(msg); } // // Check foci file // const int numFoci = fociProjectionFile->getNumberOfCellProjections(); if (numFoci <= 0) { throw BrainModelAlgorithmException("The Foci Projection File contains no foci."); } // // PubMed IDs of studies from the matching foci // std::set matchingStudiesPubMedIDs; // // Checking only displayed foci // bool displayedFociOnlyFlag = false; switch (searchMode) { case SEARCH_MODE_ALL_FOCI: displayedFociOnlyFlag = false; break; case SEARCH_MODE_DISPLAYED_FOCI: displayedFociOnlyFlag = true; break; } // // Loop through the foci // for (int i = 0; i < numFoci; i++) { CellProjection* focus = fociProjectionFile->getCellProjection(i); // // Should this foci be checked // bool useIt = false; if (displayedFociOnlyFlag) { if (focus->getDisplayFlag()) { useIt = true; } } else { useIt = true; } if (useIt) { // // Loop through the search parameters // std::vector searchResult(numSearchParameters); for (int j = 0; j < numSearchParameters; j++) { // // Get the search parameters // const FociSearch* search = fociSearchSet->getFociSearch(j); searchResult[j] = applySearchToFocus(search, focus, &spatialSearchXYZRange[j*4]); } // // Perform boolean logic to determine final result // Initialize using the current in search status // bool result = focus->getInSearchFlag(); for (int j = 0; j < numSearchParameters; j++) { const FociSearch* search = fociSearchSet->getFociSearch(j); switch (search->getLogic()) { case FociSearch::LOGIC_UNION: result = result || searchResult[j]; break; case FociSearch::LOGIC_INTERSECTION: result = result && searchResult[j]; break; } } // // Set focus' in search flag // focus->setInSearchFlag(result); // // Update number matching // if (result) { numberOfFociInSearch++; // // Keep track studies from foci in search // const StudyMetaDataLinkSet smdls = focus->getStudyMetaDataLinkSet(); const int numLinks = smdls.getNumberOfStudyMetaDataLinks(); for (int i = 0; i < numLinks; i++) { const StudyMetaDataLink smdl = smdls.getStudyMetaDataLink(i); const int studyIndex = studyMetaDataFile->getStudyIndexFromLink(smdl); if (studyIndex >= 0) { const StudyMetaData* smd = studyMetaDataFile->getStudyMetaData(studyIndex); matchingStudiesPubMedIDs.insert(smd->getPubMedID()); } } } } } // // Should foci from matching studies be added to the search results? // if (selectAllFociInMatchingStudiesFlag) { includeFociInMatchingStudiesIntoSearch(matchingStudiesPubMedIDs); } numberOfStudiesUsedByMatchingFoci = matchingStudiesPubMedIDs.size(); } /** * include foci in matching studies into search. */ void BrainModelSurfaceFociSearch::includeFociInMatchingStudiesIntoSearch(const std::set& matchingStudiesPubMedIDs) { // // Loop through the foci // const int numFoci = fociProjectionFile->getNumberOfCellProjections(); for (int i = 0; i < numFoci; i++) { CellProjection* focus = fociProjectionFile->getCellProjection(i); // // If focus is NOT already in search // if (focus->getInSearchFlag() == false) { // // Loop through studies used by focus // const StudyMetaDataLinkSet smdls = focus->getStudyMetaDataLinkSet(); const int numLinks = smdls.getNumberOfStudyMetaDataLinks(); for (int i = 0; i < numLinks; i++) { const StudyMetaDataLink smdl = smdls.getStudyMetaDataLink(i); const int studyIndex = studyMetaDataFile->getStudyIndexFromLink(smdl); if (studyIndex >= 0) { const StudyMetaData* smd = studyMetaDataFile->getStudyMetaData(studyIndex); const QString focusPubMedID = smd->getPubMedID(); // // Loop through studies that should be displayed // for (std::set::const_iterator iter = matchingStudiesPubMedIDs.begin(); iter != matchingStudiesPubMedIDs.end(); iter++) { // // Do PubMedIDs match?? // if (focusPubMedID == *iter) { focus->setInSearchFlag(true); numberOfFociFromMatchingStudies++; } } } } } } } /** * apply the search to a focus. */ bool BrainModelSurfaceFociSearch::applySearchToFocus(const FociSearch* fociSearch, const CellProjection* focus, const float* spatialXYZRange) { // // Get the studies associated with the focus // std::vector studies; const StudyMetaDataLinkSet smdls = focus->getStudyMetaDataLinkSet(); const int numLinks = smdls.getNumberOfStudyMetaDataLinks(); for (int i = 0; i < numLinks; i++) { const StudyMetaDataLink smdl = smdls.getStudyMetaDataLink(i); const int studyIndex = studyMetaDataFile->getStudyIndexFromLink(smdl); if (studyIndex >= 0) { const StudyMetaData* smd = studyMetaDataFile->getStudyMetaData(studyIndex); studies.push_back(smd); } } // // Split on whitespace, comma, or semi-colon // const QString regExpText("(\\s|,|;)+"); const QString itemSeparator(";"); // // Get the text of the attribute // QString attributeText; switch (fociSearch->getAttribute()) { case FociSearch::ATTRIBUTE_ALL: for (int i = FociSearch::ATTRIBUTE_FOCUS_AREA; i < FociSearch::ATTRIBUTE_NUMBER_OF; i++) { const FociSearch::ATTRIBUTE attributeValue = static_cast(i); if (attributeValue != FociSearch::ATTRIBUTE_FOCUS_SPATIAL) { const QString s = getAttributeText(attributeValue, focus, studies); if (s.isEmpty() == false) { if (attributeText.isEmpty() == false) { attributeText += itemSeparator; } attributeText += s; } } } break; case FociSearch::ATTRIBUTE_FOCUS_SPATIAL: { float focusSearchXYZ[3]; focus->getSearchXYZ(focusSearchXYZ); if ((focusSearchXYZ[0] != 0.0) || (focusSearchXYZ[1] != 0.0) || (focusSearchXYZ[2] != 0.0)) { // // Note: elements in spatialXYZRange[] are X, Y, Z, and MAX RANGE // const float maxRange = spatialXYZRange[3]; const float distSQ = MathUtilities::distanceSquared3D(spatialXYZRange, focusSearchXYZ); if (distSQ < (maxRange * maxRange)) { return true; } return false; } } break; case FociSearch::ATTRIBUTE_FOCUS_AREA: case FociSearch::ATTRIBUTE_FOCUS_CLASS: case FociSearch::ATTRIBUTE_FOCUS_COMMENT: case FociSearch::ATTRIBUTE_FOCUS_GEOGRAPHY: case FociSearch::ATTRIBUTE_FOCUS_ROI: case FociSearch::ATTRIBUTE_FOCUS_STRUCTURE: case FociSearch::ATTRIBUTE_STUDY_AUTHORS: case FociSearch::ATTRIBUTE_STUDY_CITATION: case FociSearch::ATTRIBUTE_STUDY_COMMENT: case FociSearch::ATTRIBUTE_STUDY_DATA_FORMAT: case FociSearch::ATTRIBUTE_STUDY_DATA_TYPE: case FociSearch::ATTRIBUTE_STUDY_KEYWORDS: case FociSearch::ATTRIBUTE_STUDY_MESH_TERMS: case FociSearch::ATTRIBUTE_STUDY_NAME: case FociSearch::ATTRIBUTE_STUDY_SPECIES: case FociSearch::ATTRIBUTE_STUDY_STEREOTAXIC_SPACE: case FociSearch::ATTRIBUTE_STUDY_TABLE_HEADER: case FociSearch::ATTRIBUTE_STUDY_TABLE_SUBHEADER: case FociSearch::ATTRIBUTE_STUDY_TITLE: attributeText = getAttributeText(fociSearch->getAttribute(), focus, studies); break; case FociSearch::ATTRIBUTE_NUMBER_OF: break; } // // Get attribute // attributeText = attributeText.trimmed(); // // Process matching // switch (fociSearch->getMatching()) { case FociSearch::MATCHING_ANY_OF: { // // If empty, NOT a match // if (attributeText.isEmpty()) { return false; } // // split search terms into a list // const QStringList searchList = fociSearch->getSearchText().split(itemSeparator, QString::SkipEmptyParts); const int numInList = searchList.count(); // // See if any search term is in the attribute's text // for (int i = 0; i < numInList; i++) { if (attributeText.contains(searchList.at(i).trimmed(), Qt::CaseInsensitive)) { return true; } } } break; case FociSearch::MATCHING_ALL_OF: { // // If empty, NOT a match // if (attributeText.isEmpty()) { return false; } // // split search terms into a list // const QStringList searchList = fociSearch->getSearchText().split(itemSeparator, QString::SkipEmptyParts); const int numInList = searchList.count(); // // See if any search term is NOT in the attribute's text // for (int i = 0; i < numInList; i++) { if (attributeText.contains(searchList.at(i).trimmed(), Qt::CaseInsensitive) == false) { return false; } } // // If we are here, all must have matched // return true; } break; case FociSearch::MATCHING_NONE_OF: { // // If empty, IS a match // if (attributeText.isEmpty()) { return true; } // // split search terms into a list // const QStringList searchList = fociSearch->getSearchText().split(itemSeparator, QString::SkipEmptyParts); const int numInList = searchList.count(); // // See if any search term is in the attribute's text // for (int i = 0; i < numInList; i++) { if (attributeText.contains(searchList.at(i).trimmed(), Qt::CaseInsensitive)) { return false; } } // // If we are here, all must NOT have matched // return true; } break; case FociSearch::MATCHING_EXACT_PHRASE: { // // If empty, NOT a match // if (attributeText.isEmpty()) { return false; } if (attributeText.contains(fociSearch->getSearchText(), Qt::CaseInsensitive)) { return true; } } break; } return false; } /** * get the text for the attribute. */ QString BrainModelSurfaceFociSearch::getAttributeText(const FociSearch::ATTRIBUTE attribute, const CellProjection* focus, std::vector studies) const { const QString itemSeparator(";"); const int numStudies = static_cast(studies.size()); QString attributeText; switch (attribute) { case FociSearch::ATTRIBUTE_ALL: break; case FociSearch::ATTRIBUTE_FOCUS_AREA: attributeText = focus->getArea(); break; case FociSearch::ATTRIBUTE_FOCUS_CLASS: attributeText = focus->getClassName(); break; case FociSearch::ATTRIBUTE_FOCUS_COMMENT: attributeText = focus->getComment(); break; case FociSearch::ATTRIBUTE_FOCUS_GEOGRAPHY: attributeText = focus->getGeography(); break; case FociSearch::ATTRIBUTE_FOCUS_ROI: attributeText = focus->getRegionOfInterest(); break; case FociSearch::ATTRIBUTE_FOCUS_SPATIAL: break; case FociSearch::ATTRIBUTE_FOCUS_STRUCTURE: attributeText = Structure::convertTypeToString(focus->getCellStructure()); break; case FociSearch::ATTRIBUTE_STUDY_AUTHORS: for (int i = 0; i < numStudies; i++) { if (attributeText.isEmpty() == false) { attributeText += itemSeparator; } attributeText += studies[i]->getAuthors(); } break; case FociSearch::ATTRIBUTE_STUDY_CITATION: for (int i = 0; i < numStudies; i++) { if (attributeText.isEmpty() == false) { attributeText += itemSeparator; } attributeText += studies[i]->getCitation(); } break; case FociSearch::ATTRIBUTE_STUDY_COMMENT: for (int i = 0; i < numStudies; i++) { if (attributeText.isEmpty() == false) { attributeText += itemSeparator; } attributeText += studies[i]->getComment(); } break; case FociSearch::ATTRIBUTE_STUDY_DATA_FORMAT: for (int i = 0; i < numStudies; i++) { if (attributeText.isEmpty() == false) { attributeText += itemSeparator; } attributeText += studies[i]->getStudyDataFormat(); } break; case FociSearch::ATTRIBUTE_STUDY_DATA_TYPE: for (int i = 0; i < numStudies; i++) { if (attributeText.isEmpty() == false) { attributeText += itemSeparator; } attributeText += studies[i]->getStudyDataType(); } break; case FociSearch::ATTRIBUTE_STUDY_KEYWORDS: for (int i = 0; i < numStudies; i++) { if (attributeText.isEmpty() == false) { attributeText += itemSeparator; } attributeText += studies[i]->getKeywords(); } break; case FociSearch::ATTRIBUTE_STUDY_MESH_TERMS: for (int i = 0; i < numStudies; i++) { if (attributeText.isEmpty() == false) { attributeText += itemSeparator; } attributeText += studies[i]->getMedicalSubjectHeadings(); } break; case FociSearch::ATTRIBUTE_STUDY_NAME: for (int i = 0; i < numStudies; i++) { if (attributeText.isEmpty() == false) { attributeText += itemSeparator; } attributeText += studies[i]->getName(); } break; case FociSearch::ATTRIBUTE_STUDY_SPECIES: for (int i = 0; i < numStudies; i++) { if (attributeText.isEmpty() == false) { attributeText += itemSeparator; } attributeText += studies[i]->getSpecies(); } break; case FociSearch::ATTRIBUTE_STUDY_STEREOTAXIC_SPACE: for (int i = 0; i < numStudies; i++) { if (attributeText.isEmpty() == false) { attributeText += itemSeparator; } attributeText += studies[i]->getStereotaxicSpace(); } break; case FociSearch::ATTRIBUTE_STUDY_TABLE_HEADER: for (int i = 0; i < numStudies; i++) { const int numTables = studies[i]->getNumberOfTables(); for (int j = 0; j < numTables; j++) { if (attributeText.isEmpty() == false) { attributeText += itemSeparator; } const StudyMetaData::Table* table = studies[i]->getTable(j); attributeText += table->getHeader(); } } break; case FociSearch::ATTRIBUTE_STUDY_TABLE_SUBHEADER: for (int i = 0; i < numStudies; i++) { const int numTables = studies[i]->getNumberOfTables(); for (int j = 0; j < numTables; j++) { const StudyMetaData::Table* table = studies[i]->getTable(j); const int numSubHeaders = table->getNumberOfSubHeaders(); for (int k = 0; k < numSubHeaders; k++) { if (attributeText.isEmpty() == false) { attributeText += itemSeparator; } const StudyMetaData::SubHeader* sh = table->getSubHeader(k); attributeText += sh->getShortName(); } } } break; case FociSearch::ATTRIBUTE_STUDY_TITLE: for (int i = 0; i < numStudies; i++) { if (attributeText.isEmpty() == false) { attributeText += itemSeparator; } attributeText += studies[i]->getTitle(); } break; case FociSearch::ATTRIBUTE_NUMBER_OF: break; } return attributeText; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceFlattenPartialHemisphere.h0000664000175000017500000000242211572067322030250 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_FLATTEN_PARTIAL_HEMISPHERE_H__ #define __BRAIN_MODEL_SURFACE_FLATTEN_PARTIAL_HEMISPHERE_H__ #include "BrainModelAlgorithm.h" class BrainModelSurface; /// This class flattens a partial hemisphere class BrainModelSurfaceFlattenPartialHemisphere : public BrainModelAlgorithm { public: /// type of surface being flattened enum FLATTEN_TYPE { FLATTEN_TYPE_ELLIPSOID, FLATTEN_TYPE_FIDUCIAL }; /// Constructor BrainModelSurfaceFlattenPartialHemisphere(BrainModelSurface* fiducialSurfaceIn, BrainModelSurface* partialHemisphereSurfaceIn, const FLATTEN_TYPE flattenSurfaceTypeIn); /// Destructor ~BrainModelSurfaceFlattenPartialHemisphere(); /// Execute the flattening virtual void execute() throw (BrainModelAlgorithmException); protected: /// fiducial surface BrainModelSurface* fiducialSurface; /// partial hemisphere surface being flattened BrainModelSurface* partialHemisphereSurface; /// type of surface being flattened FLATTEN_TYPE flattenSurfaceType; }; #endif // __BRAIN_MODEL_SURFACE_FLATTEN_PARTIAL_HEMISPHERE_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceFlattenPartialHemisphere.cxx0000664000175000017500000002502011572067322030622 0ustar michaelmichael #include #include #include // needed on windows for TRUE and FALSE #include #include "BrainModelSurface.h" #include "BrainModelSurfaceFlattenPartialHemisphere.h" #include "BrainSet.h" #include "DebugControl.h" #include "FileUtilities.h" #include "PaintFile.h" /** * Constructor */ BrainModelSurfaceFlattenPartialHemisphere::BrainModelSurfaceFlattenPartialHemisphere( BrainModelSurface* fiducialSurfaceIn, BrainModelSurface* partialHemisphereSurfaceIn, const FLATTEN_TYPE flattenSurfaceTypeIn) : BrainModelAlgorithm(partialHemisphereSurfaceIn->getBrainSet()) { fiducialSurface = fiducialSurfaceIn; partialHemisphereSurface = partialHemisphereSurfaceIn; flattenSurfaceType = flattenSurfaceTypeIn; } /** * Destructor */ BrainModelSurfaceFlattenPartialHemisphere::~BrainModelSurfaceFlattenPartialHemisphere() { } /** * Execute the flattening */ void BrainModelSurfaceFlattenPartialHemisphere::execute() throw (BrainModelAlgorithmException) { const TopologyFile* topologyFile = partialHemisphereSurface->getTopologyFile(); std::vector dummy1, dummy2, dummy3; const int numPiecesOfSurface = topologyFile->findIslands(dummy1, dummy2, dummy3); if (numPiecesOfSurface > 1) { throw BrainModelAlgorithmException( "There are multiple pieces of surface. Use Surface: Topology: Remove Islands\n" "to remove them and verify that the surface remains correct."); } // // find the geography paint column // const PaintFile* pf = brainSet->getPaintFile(); const int geographyColumn = pf->getGeographyColumnNumber(); if (geographyColumn < 0) { throw BrainModelAlgorithmException( "There is no geography paint column which is needed for flattening the\n" "partial hemisphere. The geography paint column contains the \"CUT.FACE\"\n" "nodes which are needed to properly orient the partial hemisphere for\n" "flattening."); } // // original caret coord file and topology file names // QString originalCoordFileName(partialHemisphereSurface->getFileName()); if (originalCoordFileName.isEmpty()) { originalCoordFileName = "species.case.hem.descrip.num_nodes.coord"; } QString originalTopoFileName(partialHemisphereSurface->getTopologyFile()->getFileName()); if (originalTopoFileName.isEmpty()) { originalTopoFileName = "species.case.hem.descrip.num_nodes.topo"; } // // Make a copy of the surface // partialHemisphereSurface = new BrainModelSurface(*partialHemisphereSurface); brainSet->addBrainModel(partialHemisphereSurface); if (flattenSurfaceType == FLATTEN_TYPE_FIDUCIAL) { // // Get the surfaced area of the surface // const float fiducialSurfaceArea = partialHemisphereSurface->getSurfaceArea(); // // Convert the surface into a ellipse // partialHemisphereSurface->convertToEllipsoid(); // // Convert the ellipse into a sphere // partialHemisphereSurface->convertEllipsoidToSphereWithSurfaceArea(fiducialSurfaceArea); // // update the surface's normals // partialHemisphereSurface->computeNormals(); // // Get the number of crossovers // int numTileCrossovers, numNodeCrossovers; partialHemisphereSurface->crossoverCheck(numTileCrossovers, numNodeCrossovers, BrainModelSurface::SURFACE_TYPE_SPHERICAL); // // Parameters for smoothing the surface // const int smoothingCycles = 20; const int smoothingIterations = 100; const int smoothingEdgeIterations = 10; const float smoothingStrength = 1.0; // // Smooth, reproject to a sphere, update normals, crossover check, and show in main window // int numCycles = 0; while ((numCycles < smoothingCycles) && (numNodeCrossovers > 2)) { partialHemisphereSurface->linearSmoothing(smoothingStrength, smoothingIterations, smoothingEdgeIterations); partialHemisphereSurface->convertToSphereWithSurfaceArea(fiducialSurfaceArea); partialHemisphereSurface->computeNormals(); partialHemisphereSurface->crossoverCheck(numTileCrossovers, numNodeCrossovers, BrainModelSurface::SURFACE_TYPE_SPHERICAL); brainSet->drawBrainModel(partialHemisphereSurface); if (DebugControl::getDebugOn()) { std::cout << "Flatten Part Hem: smoothing cycle " << numCycles << " tile crossovers " << numTileCrossovers << " node crossovers " << numNodeCrossovers << std::endl; } numCycles++; } // // If there are crossovers and running in interactive environment, // allow user to decide whether or not to continue. // if (numNodeCrossovers > 2) { QWidget* parent = brainSet->getProgressDialogParent(); if (parent != NULL) { std::ostringstream msg; msg << "There are " << numNodeCrossovers << " node crossovers.\n" << "Continue flattening ?"; if (QMessageBox::warning(parent, "Crossovers Warning", msg.str().c_str(), "Yes", "No") != 0) { return; } } else { if (DebugControl::getDebugOn()) { std::cout << "INFO: partial hemisphere has " << numNodeCrossovers << " node crossovers." << std::endl; } } } } else if (flattenSurfaceType == FLATTEN_TYPE_ELLIPSOID) { // // Translate the surface to its center of mass // partialHemisphereSurface->translateToCenterOfMass(); // // Convert the ellipsoid into a sphere whose surface area is that of the fiducial surface // const float surfaceArea = fiducialSurface->getSurfaceArea(); partialHemisphereSurface->convertEllipsoidToSphereWithSurfaceArea(surfaceArea); } // // Save the spherical surface // const QString sphereCoordName = FileUtilities::changeCaretDataFileDescriptionType(originalCoordFileName, "SPHERE"); try { brainSet->writeCoordinateFile(sphereCoordName, BrainModelSurface::SURFACE_TYPE_SPHERICAL, partialHemisphereSurface->getCoordinateFile()); } catch (FileException& e) { throw BrainModelAlgorithmException(e.whatQString()); } // // Copy the surface // partialHemisphereSurface = new BrainModelSurface(*partialHemisphereSurface); brainSet->addBrainModel(partialHemisphereSurface); partialHemisphereSurface->appendToCoordinateFileComment("Flattening partial hemisphere\n"); // // Orient the sphere so that "CUT.FACE" nodes are on the negative Z axis // std::vector paintNames; paintNames.push_back("CUT.FACE"); QString errorMessage; if (partialHemisphereSurface->orientPaintedNodesToNegativeZAxis(brainSet->getPaintFile(), paintNames, geographyColumn, errorMessage)) { throw BrainModelAlgorithmException(errorMessage); } // // Copy topology file and set its type to OPEN // const TopologyFile* oldTopology = partialHemisphereSurface->getTopologyFile(); TopologyFile* topology = new TopologyFile(*oldTopology); topology->setTopologyType(TopologyFile::TOPOLOGY_TYPE_OPEN); brainSet->addTopologyFile(topology); partialHemisphereSurface->setTopologyFile(topology); // // Disconnect any nodes with names CUT.FACE or MEDIAL.WALL // std::vector disconnectNames; disconnectNames.push_back("CUT.FACE"); disconnectNames.push_back("MEDIAL.WALL"); brainSet->disconnectNodes(topology, disconnectNames, geographyColumn); // // Remove any stragglers (tiles that are connected to other tiles only at a single node) // partialHemisphereSurface->getTopologyFile()->removeCornerTiles(2); partialHemisphereSurface->moveDisconnectedNodesToOrigin(); // // Classify the nodes // brainSet->classifyNodes(topology); // // Save the open topology file // const QString openTopoName = FileUtilities::changeCaretDataFileDescriptionType(originalTopoFileName, "OPEN"); try { brainSet->writeTopologyFile(openTopoName, TopologyFile::TOPOLOGY_TYPE_OPEN, topology); } catch (FileException& e) { throw BrainModelAlgorithmException(e.whatQString()); } // // Project the surface flat // partialHemisphereSurface->convertSphereToFlat(); // // Smooth just a little bit // partialHemisphereSurface->arealSmoothing(1.0, 5, 0); // // Update normals // partialHemisphereSurface->computeNormals(); // // Scale the surface to 10x the fiducial area // partialHemisphereSurface->scaleSurfaceToArea(10.0 * fiducialSurface->getSurfaceArea(), false); // // Translate to center of mass and scale to fit the window // partialHemisphereSurface->translateToCenterOfMass(); partialHemisphereSurface->updateForDefaultScaling(); // // Determine crossovers // int numTileCrossovers, numNodeCrossovers; partialHemisphereSurface->crossoverCheck(numTileCrossovers, numNodeCrossovers, BrainModelSurface::SURFACE_TYPE_FLAT); // // Save the flat surface // const QString flatCoordName = FileUtilities::changeCaretDataFileDescriptionType(originalCoordFileName, "InitialFlat"); try { brainSet->writeCoordinateFile(flatCoordName, BrainModelSurface::SURFACE_TYPE_FLAT, partialHemisphereSurface->getCoordinateFile()); } catch (FileException& e) { throw BrainModelAlgorithmException(e.whatQString()); } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceFlattenHemisphere.h0000664000175000017500000001143211572067322026734 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_FLATTEN_HEMISPHERE_H__ #define __BRAIN_MODEL_SURFACE_FLATTEN_HEMISPHERE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BorderProjectionFile.h" #include "BrainModelAlgorithm.h" class AreaColorFile; class BrainModelSurface; class PaintFile; /// class for flattening a hemisphere class BrainModelSurfaceFlattenHemisphere : public BrainModelAlgorithm { public: /// constructor BrainModelSurfaceFlattenHemisphere(BrainSet* bsIn, const BrainModelSurface* fiducialSurfaceIn, const BrainModelSurface* ellipsoidOrSphericalSurfaceIn, const BorderProjectionFile* flattenBorderProjectionFileIn, PaintFile* paintFileInOut, AreaColorFile* areaColorFileInOut, const bool createFiducialWithSmoothedMedialWallFlagIn, const bool autoSaveFilesFlag); /// destructor ~BrainModelSurfaceFlattenHemisphere(); /// execute the algorithm void execute() throw (BrainModelAlgorithmException); /// get the spherical surface that was added to the brain set (NULL if input was sphere) BrainModelSurface* getSphericalSurface() const { return outputSphericalSurface; } /// get the flat surface that was added to the brain set BrainModelSurface* getInitialFlatSurface() const { return outputInitialFlatSurface; } /// get the open topology file that was added to the brain set TopologyFile* getOpenTopologyFile() const { return outputOpenTopologyFile; } /// get the cut topology file that was added to the brain set TopologyFile* getCutTopologyFile() const { return outputCutTopologyFile; } /// get the fiducial with smoothed medial wall added to brain set BrainModelSurface* getFiducialSurfaceWithSmoothedMedialWall() const { return outputFiducialSurfaceWithSmoothedMedialWall; } protected: /// find the flattening borders void findFlatteningBorders() throw (BrainModelAlgorithmException); /// create the spherical surface void createSphericalSurface() throw (BrainModelAlgorithmException); /// create the initial flat surface void createInitialFlatSurface() throw (BrainModelAlgorithmException); /// remove medial wall assignments from paint file void removeMedialWallAssignmentsFromPaintFile(); /// the input fiducial surface const BrainModelSurface* inputFiducialSurface; /// the input spherical surface const BrainModelSurface* inputSphericalSurface; /// the flatten border projection file const BorderProjectionFile* inputFlattenBorderProjectionFile; /// the output spherical surface BrainModelSurface* outputSphericalSurface; /// the output initial flat surface BrainModelSurface* outputInitialFlatSurface; /// the output open topology file TopologyFile* outputOpenTopologyFile; /// the output cut stopology file TopologyFile* outputCutTopologyFile; /// the medial wall border BorderProjection medialWallBorderProjection; /// borders that are applied as cuts BorderProjectionFile cutBorderProjectionFile; /// paint file PaintFile* paintFile; /// area color file AreaColorFile* areaColorFile; /// fiducial surface with smoothed medial wall BrainModelSurface* outputFiducialSurfaceWithSmoothedMedialWall; /// the create fiducial surface with smoothed medial wall flag const bool createFiducialWithSmoothedMedialWallFlag; /// automatically save files flag const bool autoSaveFilesFlag; }; #endif // __BRAIN_MODEL_SURFACE_FLATTEN_HEMISPHERE_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceFlattenHemisphere.cxx0000664000175000017500000004650411572067322027317 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "AreaColorFile.h" #include "BorderFile.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceBorderCutter.h" #include "BrainModelSurfaceBorderLandmarkIdentification.h" #include "BrainModelSurfaceFlattenHemisphere.h" #include "BrainModelSurfaceSulcalIdentificationProbabilistic.h" #include "BrainSet.h" #include "DebugControl.h" #include "FileUtilities.h" #include "PaintFile.h" #include "SpecFile.h" #include "TopologyFile.h" #include "TransformationMatrixFile.h" const QString medialWallName("MEDIAL.WALL"); /** * constructor. */ BrainModelSurfaceFlattenHemisphere::BrainModelSurfaceFlattenHemisphere( BrainSet* bsIn, const BrainModelSurface* fiducialSurfaceIn, const BrainModelSurface* ellipsoidOrSphericalSurfaceIn, const BorderProjectionFile* flattenBorderProjectionFileIn, PaintFile* paintFileInOut, AreaColorFile* areaColorFileInOut, const bool createFiducialWithSmoothedMedialWallFlagIn, const bool autoSaveFilesFlagIn) : BrainModelAlgorithm(bsIn), inputFiducialSurface(fiducialSurfaceIn), inputSphericalSurface(ellipsoidOrSphericalSurfaceIn), inputFlattenBorderProjectionFile(flattenBorderProjectionFileIn), paintFile(paintFileInOut), areaColorFile(areaColorFileInOut), createFiducialWithSmoothedMedialWallFlag(createFiducialWithSmoothedMedialWallFlagIn), autoSaveFilesFlag(autoSaveFilesFlagIn) { outputSphericalSurface = NULL; outputInitialFlatSurface = NULL; outputOpenTopologyFile = NULL; outputCutTopologyFile = NULL; outputFiducialSurfaceWithSmoothedMedialWall = NULL; } /** * destructor. */ BrainModelSurfaceFlattenHemisphere::~BrainModelSurfaceFlattenHemisphere() { } /** * execute the algorithm. */ void BrainModelSurfaceFlattenHemisphere::execute() throw (BrainModelAlgorithmException) { // // Check inputs // if (inputFiducialSurface == NULL) { throw BrainModelAlgorithmException("Fiducial surface is invalid."); } if (inputSphericalSurface == NULL) { throw BrainModelAlgorithmException("Ellipsoid/Sphere surface is invalid."); } if (inputFlattenBorderProjectionFile == NULL) { throw BrainModelAlgorithmException("Border projection is invalid."); } // // Make sure there are no islands in the surface // const TopologyFile* topologyFile = inputSphericalSurface->getTopologyFile(); std::vector dummy1, dummy2, dummy3; const int numPiecesOfSurface = topologyFile->findIslands(dummy1, dummy2, dummy3); if (numPiecesOfSurface > 1) { throw BrainModelAlgorithmException( "There are multiple pieces of surface. Use Surface: Topology: Remove Islands\n" "to remove them and verify that the surface remains correct."); } // // Veryify left or right hemisphere switch (inputSphericalSurface->getStructure().getType()) { case Structure::STRUCTURE_TYPE_CORTEX_LEFT: case Structure::STRUCTURE_TYPE_CORTEX_RIGHT: break; case Structure::STRUCTURE_TYPE_CORTEX_BOTH: case Structure::STRUCTURE_TYPE_CEREBELLUM: case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_LEFT: case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_RIGHT: case Structure::STRUCTURE_TYPE_CORTEX_LEFT_OR_CEREBELLUM: case Structure::STRUCTURE_TYPE_CORTEX_RIGHT_OR_CEREBELLUM: case Structure::STRUCTURE_TYPE_CEREBRUM_CEREBELLUM: case Structure::STRUCTURE_TYPE_SUBCORTICAL: case Structure::STRUCTURE_TYPE_ALL: case Structure::STRUCTURE_TYPE_INVALID: throw BrainModelAlgorithmException( "The ellipsoid/spherical surface's structure is neither " "left nor right which is required for flattening."); break; } // // Cleanup paint file // removeMedialWallAssignmentsFromPaintFile(); // // // Make sure the sphere is of the correct size and a sphere // createSphericalSurface(); // // Find the borders used during flattening // findFlatteningBorders(); // // Create the initial flat surface // createInitialFlatSurface(); } /** * create the spherical surface. */ void BrainModelSurfaceFlattenHemisphere::createSphericalSurface() throw (BrainModelAlgorithmException) { if (inputSphericalSurface->getSurfaceType() != BrainModelSurface::SURFACE_TYPE_SPHERICAL) { outputSphericalSurface = new BrainModelSurface(*inputSphericalSurface); outputSphericalSurface->convertToSphereWithSurfaceArea(inputFiducialSurface->getSurfaceArea()); outputSphericalSurface->getCoordinateFile()->setFileName( outputSphericalSurface->getCoordinateFile()->makeDefaultFileName("Spherical")); brainSet->addBrainModel(outputSphericalSurface); if (autoSaveFilesFlag) { try { CoordinateFile* cf = outputSphericalSurface->getCoordinateFile(); brainSet->writeCoordinateFile(cf->getFileName(), BrainModelSurface::SURFACE_TYPE_SPHERICAL, cf, true); } catch (FileException& e) { throw BrainModelAlgorithmException(e); } } } } /** * create the initial flat surface. */ void BrainModelSurfaceFlattenHemisphere::createInitialFlatSurface() throw (BrainModelAlgorithmException) { // // Get the node at the anterior commissure node number // const int anteriorCommissureNodeNumber = inputFiducialSurface->getCoordinateFile()->getCoordinateIndexClosestToPoint(0,0,0); if (anteriorCommissureNodeNumber < 0) { throw BrainModelAlgorithmException("Unable to find node near (0, 0, 0) in the fiducial surface."); } // // Copy the spherical surface // BrainModelSurface flattenSurface(*inputSphericalSurface); if (outputSphericalSurface != NULL) { flattenSurface = BrainModelSurface(*outputSphericalSurface); } // // Translate the surface to its center of mass // flattenSurface.translateToCenterOfMass(); // // Orient the sphere so that the middle of the medial wall is on the positive Z axix // const CoordinateFile* flattenCoordinates = flattenSurface.getCoordinateFile(); const float* sphericalAnteriorCommissureXYZ = flattenCoordinates->getCoordinate(anteriorCommissureNodeNumber); flattenSurface.orientPointToNegativeZAxis(sphericalAnteriorCommissureXYZ); // // Rotate the surface so that the medial wall faces the user // TransformationMatrix tm; tm.rotate(TransformationMatrix::ROTATE_Y_AXIS, 180.0); if (flattenSurface.getStructure() == Structure::STRUCTURE_TYPE_CORTEX_LEFT) { tm.rotate(TransformationMatrix::ROTATE_Z_AXIS, 90.0); } else { tm.rotate(TransformationMatrix::ROTATE_Z_AXIS, -90.0); } flattenSurface.applyTransformationMatrix(tm); if (DebugControl::getDebugOn()) { CoordinateFile cf(*flattenSurface.getCoordinateFile()); try { cf.writeFile("sphere_oriented_to_show_medial_wall" + SpecFile::getCoordinateFileExtension()); } catch (FileException&) { } } // // Copy the surface for in order to determine nodes inside the medial wall // and project the nodes with positive Z to the plane // BrainModelSurface surfaceForBorderInclusion(flattenSurface); surfaceForBorderInclusion.projectCoordinatesToPlane( BrainModelSurface::COORDINATE_PLANE_MOVE_POSITIVE_Z_TO_ZERO); // // Unproject the medial wall border // Border medialWallBorder; medialWallBorderProjection.unprojectBorderProjection( surfaceForBorderInclusion.getCoordinateFile(), medialWallBorder); // // Determine nodes in medial wall border // const int numNodes = surfaceForBorderInclusion.getNumberOfNodes(); std::vector nodesInsideMedialWallBorder(numNodes, false); medialWallBorder.pointsInsideBorder2D( surfaceForBorderInclusion.getCoordinateFile()->getCoordinate(0), numNodes, nodesInsideMedialWallBorder, true); // // Update paint identification // int medialWallColumnNumber = -1; int sulcusIdPaintColumnNumber = paintFile->getColumnWithName( BrainModelSurfaceSulcalIdentificationProbabilistic::getSulcusIdPaintColumnName()); int geographyPaintColumnNumber = paintFile->getColumnWithName("Geography"); if ((sulcusIdPaintColumnNumber < 0) && (geographyPaintColumnNumber < 0)) { if (paintFile->getNumberOfNodes() == 0) { paintFile->setNumberOfNodesAndColumns(inputFiducialSurface->getNumberOfNodes(), 1); } else { paintFile->addColumns(1); } geographyPaintColumnNumber = paintFile->getNumberOfColumns() - 1; paintFile->setColumnName(geographyPaintColumnNumber, "Geography"); } if (sulcusIdPaintColumnNumber > 0) { medialWallColumnNumber = sulcusIdPaintColumnNumber; } else if (geographyPaintColumnNumber > 0) { medialWallColumnNumber = geographyPaintColumnNumber; } const int medialWallPaintNumber = paintFile->addPaintName(medialWallName); for (int i = 0; i < numNodes; i++) { if (nodesInsideMedialWallBorder[i]) { if (sulcusIdPaintColumnNumber >= 0) { paintFile->setPaint(i, sulcusIdPaintColumnNumber, medialWallPaintNumber); } if (geographyPaintColumnNumber >= 0) { paintFile->setPaint(i, geographyPaintColumnNumber, medialWallPaintNumber); } } } // // Add area color // bool matchFlag = false; areaColorFile->getColorIndexByName(medialWallName, matchFlag); if (matchFlag == false) { areaColorFile->addColor(medialWallName, 0, 255, 0); if (autoSaveFilesFlag) { try { brainSet->writeAreaColorFile(areaColorFile->getFileName()); } catch (FileException& e) { throw BrainModelAlgorithmException(e); } } } // // Orient the sphere so that the medial wall is on the negative Z axis // which is necessary for flattening // std::vector paintNames; paintNames.push_back(medialWallName); QString errorMessage; if (flattenSurface.orientPaintedNodesToNegativeZAxis(paintFile, paintNames, medialWallColumnNumber, errorMessage)) { throw BrainModelAlgorithmException(errorMessage); } // // Compress the fronat face // flattenSurface.compressFrontFace(0.5, 0); // // Get pointer to closed topology // const TopologyFile* closedTopologyFile = flattenSurface.getTopologyFile(); // // Create new open topology by removing the medial wall and any stragglers // outputOpenTopologyFile = new TopologyFile(*closedTopologyFile); outputOpenTopologyFile->makeDefaultFileName("OPEN"); brainSet->addTopologyFile(outputOpenTopologyFile); brainSet->disconnectNodes(outputOpenTopologyFile, nodesInsideMedialWallBorder); outputOpenTopologyFile->setTopologyType(TopologyFile::TOPOLOGY_TYPE_OPEN); outputOpenTopologyFile->removeCornerTiles(2); if (autoSaveFilesFlag) { try { brainSet->writeTopologyFile(outputOpenTopologyFile->getFileName(), outputOpenTopologyFile->getTopologyType(), outputOpenTopologyFile); } catch (FileException& e) { throw BrainModelAlgorithmException(e); } } if (DebugControl::getDebugOn()) { CoordinateFile cf2(*flattenSurface.getCoordinateFile()); try { const QString topoFileName = FileUtilities::basename( flattenSurface.getTopologyFile()->getFileName()); if (topoFileName.isEmpty() == false) { cf2.setHeaderTag(SpecFile::getUnknownTopoFileMatchTag(), topoFileName); } cf2.writeFile("sphere_oriented_compressed_for_cuts" + SpecFile::getCoordinateFileExtension()); } catch (FileException&) { } } // // Create the cut toplogy file and flat surface // outputCutTopologyFile = new TopologyFile(*outputOpenTopologyFile); outputCutTopologyFile->makeDefaultFileName("CUT"); brainSet->addTopologyFile(outputCutTopologyFile); outputInitialFlatSurface = new BrainModelSurface(flattenSurface); outputInitialFlatSurface->getCoordinateFile()->makeDefaultFileName("InitialFlat"); outputInitialFlatSurface->setTopologyFile(outputCutTopologyFile); // // Project the sphere flat // outputInitialFlatSurface->convertSphereToFlat(); // // Smooth just a little bit // outputInitialFlatSurface->arealSmoothing(1.0, 5, 0); // // update the normals // outputInitialFlatSurface->computeNormals(); if (DebugControl::getDebugOn()) { CoordinateFile cf3(*outputInitialFlatSurface->getCoordinateFile()); try { cf3.writeFile("initial_flat_before_cuts_applied" + SpecFile::getCoordinateFileExtension()); } catch (FileException&) { } } // // Need to do before removing medial wall otherwise a cut may fail // near the medial wall // BrainModelSurfaceBorderCutter cutter(brainSet, outputInitialFlatSurface, &cutBorderProjectionFile, BrainModelSurfaceBorderCutter::CUTTING_MODE_FLAT_SURFACE, true); cutter.execute(); // // Scale the surface to 10x the fiducial area // outputInitialFlatSurface->scaleSurfaceToArea(10.0 * inputFiducialSurface->getSurfaceArea(), false); // // Translate to center of mass and scale to fit the window // outputInitialFlatSurface->translateToCenterOfMass(); outputInitialFlatSurface->updateForDefaultScaling(); // // Eliminate any islands or stragglers // outputCutTopologyFile->disconnectIslands(); outputCutTopologyFile->removeCornerTiles(1); outputInitialFlatSurface->moveDisconnectedNodesToOrigin(); // // Should a fiducial surface with a smoothed medial wall be produced // if (createFiducialWithSmoothedMedialWallFlag) { const float strength = 1.0; const int iterations = 500; const int smoothEdgesIterations = 0; BrainModelSurface* bms = new BrainModelSurface(*inputFiducialSurface); bms->arealSmoothing(strength, iterations, smoothEdgesIterations, &nodesInsideMedialWallBorder); bms->getCoordinateFile()->makeDefaultFileName("FiducialSmoothedMedialWall"); brainSet->addBrainModel(bms); outputFiducialSurfaceWithSmoothedMedialWall = bms; if (autoSaveFilesFlag) { try { CoordinateFile* cf = bms->getCoordinateFile(); brainSet->writeCoordinateFile(cf->getFileName(), bms->getSurfaceType(), cf, true); } catch (FileException& e) { throw BrainModelAlgorithmException(e); } } } // // Add the initial flat surface to the brain set // brainSet->addBrainModel(outputInitialFlatSurface); if (autoSaveFilesFlag) { try { CoordinateFile* cf = outputInitialFlatSurface->getCoordinateFile(); brainSet->writeCoordinateFile(cf->getFileName(), outputInitialFlatSurface->getSurfaceType(), cf, true); TopologyFile* tf = outputInitialFlatSurface->getTopologyFile(); brainSet->writeTopologyFile(tf->getFileName(), tf->getTopologyType(), tf); } catch (FileException& e) { throw BrainModelAlgorithmException(e); } if (paintFile->getModified()) { brainSet->writePaintFile(paintFile->getFileName()); } } } /** * remove medial wall assignments from paint file. */ void BrainModelSurfaceFlattenHemisphere::removeMedialWallAssignmentsFromPaintFile() { const int medialWallPaintIndex = paintFile->getPaintIndexFromName(medialWallName); if (medialWallPaintIndex >= 0) { const int questionIndex = paintFile->addPaintName("???"); const int numNodes = paintFile->getNumberOfNodes(); const int numCols = paintFile->getNumberOfColumns(); for (int i = 0; i < numNodes; i++) { for (int j = 0; j < numCols; j++) { if (paintFile->getPaint(i, j) == medialWallPaintIndex) { paintFile->setPaint(i, j, questionIndex); } } } } } /** * find the flattening borders. */ void BrainModelSurfaceFlattenHemisphere::findFlatteningBorders() throw (BrainModelAlgorithmException) { const int numBorderProjections = inputFlattenBorderProjectionFile->getNumberOfBorderProjections(); for (int i = 0; i < numBorderProjections; i++) { const BorderProjection* bp = inputFlattenBorderProjectionFile->getBorderProjection(i); const QString name = bp->getName(); if (name == BrainModelSurfaceBorderLandmarkIdentification::getFlattenMedialWallBorderName()) { medialWallBorderProjection = *bp; } else if (name.startsWith( BrainModelSurfaceBorderLandmarkIdentification::getFlattenStandardCutsBorderNamePrefix())) { cutBorderProjectionFile.addBorderProjection(*bp); } } // // Unable to find medial wall in input borders ? // if (medialWallBorderProjection.getNumberOfLinks() <= 0) { throw BrainModelAlgorithmException("Unable to find border named \"" + BrainModelSurfaceBorderLandmarkIdentification::getFlattenMedialWallBorderName() + "\" in input border projection file."); } // // Unable to find cuts ? // if (cutBorderProjectionFile.getNumberOfBorderProjections() <= 0) { throw BrainModelAlgorithmException("Unable to find cuts beginning with \"" + BrainModelSurfaceBorderLandmarkIdentification::getFlattenStandardCutsBorderNamePrefix() + "\" in input border projection file."); } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceFlattenFullHemisphere.h0000664000175000017500000000654111572067322027564 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __BRAIN_MODEL_SURFACE_FLATTEN_FULL_HEMISPHERE_H__ #define __BRAIN_MODEL_SURFACE_FLATTEN_FULL_HEMISPHERE_H__ #include "BrainModelAlgorithm.h" class BorderFile; class BrainModelSurface; class PaintFile; /// class for flattening a full hemisphere class BrainModelSurfaceFlattenFullHemisphere : public BrainModelAlgorithm { public: /// Constructor BrainModelSurfaceFlattenFullHemisphere(BrainModelSurface* fiducialSurfaceIn, BrainModelSurface* ellipsoidSurfaceIn, BorderFile* borderFileIn, const float acPositionIn[3], const float acOffsetIn[3], const bool smoothFiducialMedialWallFlagIn); /// Destructor ~BrainModelSurfaceFlattenFullHemisphere(); /// Execute the flattening virtual void execute() throw (BrainModelAlgorithmException); /// Execute the second half of the flattening virtual void executePart2() throw (BrainModelAlgorithmException); protected: /// save the borders for creating landmark borders void saveBordersForLandmarks(BorderFile* bf); /// create the landarks for deformation void createDeformationBorders(PaintFile* pf); /// fiducial surface BrainModelSurface* fiducialSurface; /// partial hemisphere surface being flattened BrainModelSurface* flattenSurface; /// position of anterior commissure float acPosition[3]; /// offset from anterior commissure float acOffset[3]; /// template border file name BorderFile* borderFile; /// the geography column number int geographyColumnNumber; /// medial wall paint file index int medialWallPaintFileIndex; /// hemisphere string for file naming QString hemStr; /// original topology file name QString originalTopoFileName; /// original coordinate file name QString originalCoordFileName; /// landmarks for deformation BorderFile landmarksForDeformation; /// paint file was empty at start of procedure bool paintFileEmptyAtStart; /// smooth the fiducial surface's medial wall during flattening bool smoothFiducialMedialWallFlag; }; #endif // __BRAIN_MODEL_SURFACE_FLATTEN_FULL_HEMISPHERE_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceFlattenFullHemisphere.cxx0000664000175000017500000011046511572067322030140 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include "AreaColorFile.h" #include "BorderColorFile.h" #include "BorderFile.h" #include "BorderFileProjector.h" #include "BorderProjectionFile.h" #include "BrainModelBorderSet.h" #include "BrainModelSurfaceNodeColoring.h" #include "BrainModelSurfacePointLocator.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceCutter.h" #include "BrainModelSurfaceFlattenFullHemisphere.h" #include "BrainSet.h" #include "DebugControl.h" #include "DisplaySettingsBorders.h" #include "FileUtilities.h" #include "PaintFile.h" #include "SpecFile.h" #include "SurfaceShapeFile.h" #include "TransformationMatrixFile.h" // // File globals // static const QString medialWallName("MEDIAL.WALL"); static const QString calcarineCutName("CalcarineCut"); static const QString frontalCutName("FrontalCut"); static const QString medialWallDorsalLandmark("LANDMARK.MedWall.DORSAL"); static const QString medialWallVentralLandmark("LANDMARK.MedWall.VENTRAL"); static const QString calcarineLandmark("LANDMARK.CalcarineSulcus"); /** * Constructor. */ BrainModelSurfaceFlattenFullHemisphere::BrainModelSurfaceFlattenFullHemisphere( BrainModelSurface* fiducialSurfaceIn, BrainModelSurface* ellipsoidSurfaceIn, BorderFile* borderFileIn, const float acPositionIn[3], const float acOffsetIn[3], const bool smoothFiducialMedialWallFlagIn) : BrainModelAlgorithm(ellipsoidSurfaceIn->getBrainSet()) { fiducialSurface = fiducialSurfaceIn; flattenSurface = ellipsoidSurfaceIn; borderFile = borderFileIn; acPosition[0] = acPositionIn[0]; acPosition[1] = acPositionIn[1]; acPosition[2] = acPositionIn[2]; acOffset[0] = acOffsetIn[0]; acOffset[1] = acOffsetIn[1]; acOffset[2] = acOffsetIn[2]; smoothFiducialMedialWallFlag = smoothFiducialMedialWallFlagIn; } /** * Destructor. */ BrainModelSurfaceFlattenFullHemisphere::~BrainModelSurfaceFlattenFullHemisphere() { } /** * Execute the flattening. */ void BrainModelSurfaceFlattenFullHemisphere::execute() throw (BrainModelAlgorithmException) { DisplaySettingsBorders* dsb = brainSet->getDisplaySettingsBorders(); dsb->setDisplayBorders(true); const TopologyFile* topologyFile = flattenSurface->getTopologyFile(); std::vector dummy1, dummy2, dummy3; const int numPiecesOfSurface = topologyFile->findIslands(dummy1, dummy2, dummy3); if (numPiecesOfSurface > 1) { throw BrainModelAlgorithmException( "There are multiple pieces of surface. Use Surface: Topology: Remove Islands\n" "to remove them and verify that the surface remains correct."); } if (borderFile == NULL) { throw BrainModelAlgorithmException("Border File not provided."); } else if (borderFile->getNumberOfBorders() == 0) { throw BrainModelAlgorithmException("Border File contains no borders."); } const int numNodes = flattenSurface->getNumberOfNodes(); // // Structure naming // hemStr = flattenSurface->getStructure().getTypeAsAbbreviatedString(); /* switch(flattenSurface->getStructure()) { case BrainModelSurface::HEMISPHERE_LEFT: hemStr = "L"); break; case BrainModelSurface::HEMISPHERE_RIGHT: hemStr = "R"); break; case BrainModelSurface::HEMISPHERE_BOTH: hemStr = "LR"); break; case BrainModelSurface::HEMISPHERE_UNKNOWN: hemStr = "U"); break; } */ // // original caret coord file and topology file names // originalCoordFileName = flattenSurface->getFileName(); if (originalCoordFileName.isEmpty()) { std::ostringstream str; str << "species.case." << hemStr.toAscii().constData() << ".descrip." << numNodes << SpecFile::getCoordinateFileExtension().toAscii().constData(); originalCoordFileName = str.str().c_str(); } originalTopoFileName = flattenSurface->getTopologyFile()->getFileName(); if (originalTopoFileName.isEmpty()) { std::ostringstream str; str << "species.case." << hemStr.toAscii().constData() << ".descrip." << numNodes << SpecFile::getTopoFileExtension().toAscii().constData(); originalTopoFileName = str.str().c_str(); } // // Change any nodes named medial wall in geography column to gyral. // Create the geography column if it does not exist. // PaintFile* paintFile = brainSet->getPaintFile(); paintFileEmptyAtStart = (paintFile->getNumberOfColumns() == 0); geographyColumnNumber = paintFile->getGeographyColumnNumber(); if (geographyColumnNumber < 0) { if (paintFile->getNumberOfColumns() == 0) { paintFile->setNumberOfNodesAndColumns(numNodes, 1); geographyColumnNumber = 0; } else { paintFile->addColumns(1); geographyColumnNumber = paintFile->getNumberOfColumns() - 1; } paintFile->setColumnName(geographyColumnNumber, PaintFile::columnNameGeography); } // // Change any nodes named MEDIAL.WALL to GYRAL // medialWallPaintFileIndex = paintFile->addPaintName(medialWallName); const int gyrusIndex = paintFile->addPaintName("GYRAL"); for (int i = 0; i < numNodes; i++) { if (paintFile->getPaint(i, geographyColumnNumber) == medialWallPaintFileIndex) { paintFile->setPaint(i, geographyColumnNumber, gyrusIndex); } } // // Add the GYRAL and MEDIAL.WALL colors if necessary // bool addedAreaColor = false; AreaColorFile* nodeColors = brainSet->getAreaColorFile(); bool exactMatch = false; nodeColors->getColorIndexByName("GYRAL", exactMatch); if (exactMatch == false) { nodeColors->addColor("GYRAL", 170, 170, 170, 1, 2); addedAreaColor = true; } exactMatch = false; nodeColors->getColorIndexByName(medialWallName, exactMatch); if (exactMatch == false) { nodeColors->addColor(medialWallName, 255, 0, 0, 1, 2); addedAreaColor = true; } // // Save the node color file if colors were added // if (addedAreaColor) { QString nodeColorFileName(nodeColors->getFileName()); // // Create the node color file name if there is not one // if (nodeColorFileName.isEmpty() || paintFileEmptyAtStart) { QString directory, species, casename, anatomy, hemisphere, description; QString descriptionNoType, theDate, numNodes, extension; if (FileUtilities::parseCaretDataFileName(originalTopoFileName, directory, species, casename, anatomy, hemisphere, description, descriptionNoType, theDate, numNodes, extension)) { nodeColorFileName = FileUtilities::reassembleCaretDataFileName(directory, species, casename, anatomy, hemisphere, "colors", theDate, numNodes, SpecFile::getAreaColorFileExtension()); } else { std::ostringstream str; str << "species.case." << hemStr.toAscii().constData() << ".colors." << numNodes.toAscii().constData() << SpecFile::getAreaColorFileExtension().toAscii().constData(); nodeColorFileName = str.str().c_str(); } } // // write the node color file // brainSet->writeAreaColorFile(nodeColorFileName); } // // Make a copy of the surface // flattenSurface = new BrainModelSurface(*flattenSurface); brainSet->addBrainModel(flattenSurface); flattenSurface->appendToCoordinateFileComment("Flattening full hemisphere\n"); // // Translate the surface to its center of mass // flattenSurface->translateToCenterOfMass(); // // Convert the ellipsoid into a sphere whose surface area is that of the fiducial surface // const float surfaceArea = fiducialSurface->getSurfaceArea(); flattenSurface->convertEllipsoidToSphereWithSurfaceArea(surfaceArea); // // Save the spherical surface // const QString sphereCoordName = FileUtilities::changeCaretDataFileDescriptionType(originalCoordFileName, "SPHERE"); try { brainSet->writeCoordinateFile(sphereCoordName, BrainModelSurface::SURFACE_TYPE_SPHERICAL, flattenSurface->getCoordinateFile()); } catch (FileException& e) { throw BrainModelAlgorithmException(e.whatQString()); } // // Copy the surface // flattenSurface = new BrainModelSurface(*flattenSurface); brainSet->addBrainModel(flattenSurface); // // Get the radius of spherical surface // const float sphereRadius = flattenSurface->getSphericalSurfaceRadius(); // // Set the radius of spherical borders to the radius of the surface // borderFile->setSphericalBorderRadius(sphereRadius); // // Approximate middle of medial wall with AC and offset // const float middleMedialWallPosFiducial[3] = { acPosition[0] + acOffset[0], acPosition[1] + acOffset[1], acPosition[2] + acOffset[2] }; // // Find node closest to middle of medial wall in fiducial surface // BrainModelSurfacePointLocator fiducialLocator(fiducialSurface, true); const int middleMedialWallNodeIndex = fiducialLocator.getNearestPoint( middleMedialWallPosFiducial); if (middleMedialWallNodeIndex < 0) { throw BrainModelAlgorithmException( "Unable to find node on fiducial surface nearest middle of medial wall"); } // // The borders projected to the spherical surface // //BorderProjectionFile borderProjectionFile = brainSet->getBorderProjectionFile(); // // Delete any existing borders and copy the border file to the surface // BrainModelBorderSet* bmbs = brainSet->getBorderSet(); brainSet->deleteAllBorders(); bmbs->copyBordersFromBorderFile(flattenSurface, borderFile); // // Color the borders // bmbs->assignColors(); // // Project the borders onto the spherical surface // bmbs->projectBorders(flattenSurface); // // Orient the sphere so that the middle of the medial wall is on the positive Z axix // CoordinateFile* flattenCoordinates = flattenSurface->getCoordinateFile(); const float* middleMedialWallSphereCoord = flattenCoordinates->getCoordinate(middleMedialWallNodeIndex); flattenSurface->orientPointToNegativeZAxis(middleMedialWallSphereCoord); // // Compress the medial wall // flattenSurface->convertSphereToCompressedMedialWall(0.5); // // Rotate the surface so that the medial wall faces the user // TransformationMatrix tm; tm.rotate(TransformationMatrix::ROTATE_Y_AXIS, 180.0); if (flattenSurface->getStructure() == Structure::STRUCTURE_TYPE_CORTEX_LEFT) { tm.rotate(TransformationMatrix::ROTATE_Z_AXIS, 90.0); } else { tm.rotate(TransformationMatrix::ROTATE_Z_AXIS, -90.0); } flattenSurface->applyTransformationMatrix(tm); // // Save the compressed medial wall coordinates and move all with positive Z // to the X-Y plane // flattenSurface->pushCoordinates(); flattenSurface->projectCoordinatesToPlane( BrainModelSurface::COORDINATE_PLANE_MOVE_POSITIVE_Z_TO_ZERO); // // Update the surface's normals // flattenSurface->computeNormals(); // // Save the compressed medial wall surface // const QString cmwCoordName = FileUtilities::changeCaretDataFileDescriptionType(originalCoordFileName, "CMW"); try { brainSet->writeCoordinateFile(cmwCoordName, BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL, flattenSurface->getCoordinateFile()); } catch (FileException& e) { throw BrainModelAlgorithmException(e.whatQString()); } // // Copy the surface // //moved to executePart2() 11/07/06 //flattenSurface = new BrainModelSurface(*flattenSurface); //brainSet->addBrainModel(flattenSurface); // // Apply the border projection file to the all surfaces // bmbs->unprojectBordersForAllSurfaces(); // // clear the border projection file // //borderProjectionFile->clear(); // // Make sure there is some sort of coloring // SurfaceShapeFile* ssf = brainSet->getSurfaceShapeFile(); if (ssf->getNumberOfColumns() > 0) { brainSet->getSurfaceUnderlay()->setOverlay(-1, BrainModelSurfaceOverlay::OVERLAY_SURFACE_SHAPE); } else { PaintFile* pf = brainSet->getPaintFile(); if (pf->getNumberOfColumns() > 0) { brainSet->getSurfaceUnderlay()->setOverlay(-1, BrainModelSurfaceOverlay::OVERLAY_PAINT); } } } /// Execute the second part of the flattening void BrainModelSurfaceFlattenFullHemisphere::executePart2() throw (BrainModelAlgorithmException) { const int numNodes = flattenSurface->getNumberOfNodes(); // // Get the compressed medial wall border file // BrainModelBorderSet* bmbs = brainSet->getBorderSet(); BorderFile* cmwBorder = bmbs->copyBordersOfSpecifiedType( BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL); if (cmwBorder == NULL) { throw BrainModelAlgorithmException("Unable to find compressed medial wall border."); } // // Copy the surface // //moved here 11/7/06 flattenSurface = new BrainModelSurface(*flattenSurface); brainSet->addBrainModel(flattenSurface); // // Copy the topology file // const TopologyFile* oldTopology = flattenSurface->getTopologyFile(); TopologyFile* topology = new TopologyFile(*oldTopology); topology->setTopologyType(TopologyFile::TOPOLOGY_TYPE_OPEN); brainSet->addTopologyFile(topology); flattenSurface->setTopologyFile(topology); // // Save the cmw border // QString templateCutsBorderFileName; { QString directory, species, casename, anatomy, hemisphere, description; QString descriptionNoType, theDate, numNodes, extension; if (FileUtilities::parseCaretDataFileName(originalTopoFileName, directory, species, casename, anatomy, hemisphere, description, descriptionNoType, theDate, numNodes, extension)) { templateCutsBorderFileName = FileUtilities::reassembleCaretDataFileName(directory, species, casename, anatomy, hemisphere, "TemplateCuts", theDate, numNodes, SpecFile::getBorderFileExtension()); } else { std::ostringstream str; str << "species.case." << hemStr.toAscii().constData() << ".TemplateCuts." << numNodes.toAscii().constData() << SpecFile::getBorderFileExtension().toAscii().constData(); templateCutsBorderFileName = str.str().c_str(); } } brainSet->writeBorderFile(templateCutsBorderFileName, flattenSurface, BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL, "", ""); // // Find the border named medial wall // const int medialWallBorderIndex = cmwBorder->getBorderIndexByName(medialWallName); if (medialWallBorderIndex < 0) { throw BrainModelAlgorithmException("Unable to find MEDIAL.WALL border."); } Border* medialWallBorder = cmwBorder->getBorder(medialWallBorderIndex); // // Find all nodes within the medial wall // CoordinateFile* flattenCoordinates = flattenSurface->getCoordinateFile(); std::vector nodesInsideMedialWallBorder(numNodes, false); medialWallBorder->pointsInsideBorder2D(flattenCoordinates->getCoordinate(0), numNodes, nodesInsideMedialWallBorder, true); // // Set geography for all nodes within the medial wall to MEDIAL.WALL // PaintFile* paintFile = brainSet->getPaintFile(); for (int i = 0; i < numNodes; i++) { if (nodesInsideMedialWallBorder[i]) { paintFile->setPaint(i, geographyColumnNumber, medialWallPaintFileIndex); } } // // Save the paint file // QString paintFileName(paintFile->getFileName()); if (paintFileName.isEmpty() || paintFileEmptyAtStart) { QString directory, species, casename, anatomy, hemisphere, description; QString descriptionNoType, theDate, numNodes, extension; if (FileUtilities::parseCaretDataFileName(originalTopoFileName, directory, species, casename, anatomy, hemisphere, description, descriptionNoType, theDate, numNodes, extension)) { paintFileName = FileUtilities::reassembleCaretDataFileName(directory, species, casename, anatomy, hemisphere, "geography", theDate, numNodes, SpecFile::getAreaColorFileExtension()); } else { std::ostringstream str; str << "species.case." << hemStr.toAscii().constData() << ".geography." << numNodes.toAscii().constData() << SpecFile::getPaintFileExtension().toAscii().constData(); paintFileName = str.str().c_str(); } } brainSet->writePaintFile(paintFileName); // // Should the fiducial surface have its medial wall smoothed ? // if (smoothFiducialMedialWallFlag) { // // Smooth the medial wall of the fiducial surface // fiducialSurface->arealSmoothing(1.0, 500, 0, &nodesInsideMedialWallBorder); fiducialSurface->computeNormals(); // // Write the fiducial coord file // try { CoordinateFile* cf = fiducialSurface->getCoordinateFile(); cf->writeFile(cf->getFileName()); } catch (FileException& e) { std::cout << "ERROR: Unable to write fiducial coordinate file after " << "smoothing the medial wall: " << e.whatQString().toAscii().constData() << std::endl; } } // // Save the geography since applying cuts may modify it // std::vector savedGeography(numNodes); for (int i = 0; i < numNodes; i++) { savedGeography[i] = paintFile->getPaint(i, geographyColumnNumber); } // // Save the medial wall, calcarine cut, and the frontal cut borders // saveBordersForLandmarks(cmwBorder); // // Remove the medial wall border from all borders // std::vector namesToDelete; namesToDelete.push_back(medialWallName); bmbs->deleteBordersWithNames(namesToDelete); // // Apply all of the cuts // BrainModelSurfaceCutter cutter(flattenSurface, cmwBorder, BrainModelSurfaceCutter::CUTTING_MODE_NON_NEGATIVE_Z_ONLY); try { cutter.execute(); } catch (BrainModelAlgorithmException& e) { throw e; } // // Restore the geography // for (int i = 0; i < numNodes; i++) { paintFile->setPaint(i, geographyColumnNumber, savedGeography[i]); } paintFile->clearModified(); // // Create the landmark borders for deformation // createDeformationBorders(paintFile); // // Restore the coordinates that were saved when positives projected flat // flattenSurface->popCoordinates(); // // update the normals // flattenSurface->computeNormals(); // // Orient the sphere so that the medial wall is on the negative Z axis // std::vector paintNames; paintNames.push_back(medialWallName); QString errorMessage; if (flattenSurface->orientPaintedNodesToNegativeZAxis(brainSet->getPaintFile(), paintNames, geographyColumnNumber, errorMessage)) { throw BrainModelAlgorithmException(errorMessage); } // // Remove the medial wall // brainSet->disconnectNodes(topology, nodesInsideMedialWallBorder); // // Remove any stragglers (tiles that are connected to other tiles only at a single node) // flattenSurface->getTopologyFile()->removeCornerTiles(2); flattenSurface->moveDisconnectedNodesToOrigin(); // // Project the sphere flat // flattenSurface->convertSphereToFlat(); // // Smooth just a little bit // flattenSurface->arealSmoothing(1.0, 5, 0); // // update the normals // flattenSurface->computeNormals(); // // Scale the surface to 10x the fiducial area // flattenSurface->scaleSurfaceToArea(10.0 * fiducialSurface->getSurfaceArea(), false); // // Translate to center of mass and scale to fit the window // flattenSurface->translateToCenterOfMass(); flattenSurface->updateForDefaultScaling(); // // Remove any stragglers (tiles that are connected to other tiles only at a single node) // // flattenSurface->getTopologyFile()->removeCornerTiles(2); // flattenSurface->moveDisconnectedNodesToOrigin(); // // Classify the nodes // brainSet->classifyNodes(topology); // // Save the topology file // const QString cutTopoName = FileUtilities::changeCaretDataFileDescriptionType(originalTopoFileName, "CUT"); try { brainSet->writeTopologyFile(cutTopoName, TopologyFile::TOPOLOGY_TYPE_CUT, topology); } catch (FileException& e) { throw BrainModelAlgorithmException(e.whatQString()); } // // Save the flat coordinate file // const QString flatCoordName = FileUtilities::changeCaretDataFileDescriptionType(originalCoordFileName, "InitialFlat"); try { brainSet->writeCoordinateFile(flatCoordName, BrainModelSurface::SURFACE_TYPE_FLAT, flattenSurface->getCoordinateFile()); } catch (FileException& e) { throw BrainModelAlgorithmException(e.whatQString()); } // // Set all borders as unmodified // bmbs->setAllBordersModifiedStatus(false); bmbs->setProjectionsModified(false); } /** * Finds and save the borders for creating landmark borders. The dorsal and ventral * portions of the medial wall border are determined and the part of the calcarine * cut that is outside the medial wall. */ void BrainModelSurfaceFlattenFullHemisphere::saveBordersForLandmarks(BorderFile* bf) { landmarksForDeformation.clear(); int medialWallIndex = -1; int calcarineCutIndex = -1; int frontalCutIndex = -1; // // Find the MEDIAL.WALL, CalcarineCut, and FrontalCut borders. // const int numBorders = bf->getNumberOfBorders(); for (int i = 0; i < numBorders; i++) { Border* b = bf->getBorder(i); if (b->getNumberOfLinks() > 0) { if (b->getName() == medialWallName) { //landmarksForDeformation.addBorder(*b); medialWallIndex = i; } else if (b->getName() == calcarineCutName) { //landmarksForDeformation.addBorder(*b); calcarineCutIndex = i; } else if (b->getName() == frontalCutName) { //landmarksForDeformation.addBorder(*b); frontalCutIndex = i; } } } // // If borders missing, print error messages // if (medialWallIndex < 0) { std::cout << "Missing " << medialWallName.toAscii().constData() << " border for deformation landmarks." << std::endl; } if (calcarineCutIndex < 0) { std::cout << "Missing " << calcarineCutName.toAscii().constData() << " border for deformation landmarks." << std::endl; } if (frontalCutIndex < 0) { std::cout << "Missing " << frontalCutName.toAscii().constData() << " border for deformation landmarks." << std::endl; } // // If borders found // if ((medialWallIndex >= 0) && (calcarineCutIndex >= 0) && (frontalCutIndex >= 0)) { // // Find out where medial wall border intersects calcarine and frontal // Border* medialWallBorder = bf->getBorder(medialWallIndex); Border* calcarineCutBorder = bf->getBorder(calcarineCutIndex); Border* frontalCutBorder = bf->getBorder(frontalCutIndex); // // NOTE: When viewing the compressed medial wall surface, the surface is presented in // the X-Y plane. // // End of calcarine cut border should be most negative X for left, most positive X for right // float calc0[3], calcLast[3]; calcarineCutBorder->getLinkXYZ(0, calc0); calcarineCutBorder->getLinkXYZ(calcarineCutBorder->getNumberOfLinks() - 1, calcLast); if (flattenSurface->getStructure() == Structure::STRUCTURE_TYPE_CORTEX_LEFT) { if (calc0[0] > calcLast[0]) { calcarineCutBorder->reverseBorderLinks(); } } else { if (calc0[0] < calcLast[0]) { calcarineCutBorder->reverseBorderLinks(); } } // // Indices to border links where borders intersect // int medialWallCalcarineIntersect = -1; int medialWallFrontalIntersect = -1; int calcarineMedialWallIntersect = -1; int frontalMedialWallIntersect = -1; // // Find intersections // const bool medialWallCalcarineIntersectionValid = medialWallBorder->intersection2D(calcarineCutBorder, true, false, medialWallCalcarineIntersect, calcarineMedialWallIntersect); const bool medialWallFrontalIntersectionValid = medialWallBorder->intersection2D(frontalCutBorder, true, false, medialWallFrontalIntersect, frontalMedialWallIntersect); if (medialWallCalcarineIntersectionValid == false) { std::cout << "Unable to find medial wall calacarine cut intersection." << std::endl; } if (medialWallFrontalIntersectionValid == false) { std::cout << "Unable to find medial wall frontal cut intersection." << std::endl; } if (medialWallCalcarineIntersectionValid && medialWallFrontalIntersectionValid) { if (DebugControl::getDebugOn()) { std::cout << "Found medial wall intersections with both the calcarine and " << "frontal cuts." << std::endl; } // // Get the two pieces of the medial wall border // Border* dorsalMedialWall = medialWallBorder->getSubSet(medialWallCalcarineIntersect, medialWallFrontalIntersect); if (dorsalMedialWall == NULL) { std::cout << "Calcarine to Frontal section of medial wall border is empty" << std::endl; } Border* ventralMedialWall = medialWallBorder->getSubSet(medialWallFrontalIntersect, medialWallCalcarineIntersect); if (ventralMedialWall == NULL) { std::cout << "Frontal to Calcarine section of medial wall border is empty" << std::endl; if (dorsalMedialWall != NULL) { delete dorsalMedialWall; } } if ((dorsalMedialWall != NULL) && (ventralMedialWall != NULL)) { // // Find out which one is dorsal (biggest Y) and ventral (smallest Y) // float dorsalBounds[6], ventralBounds[6]; dorsalMedialWall->getBounds(dorsalBounds); ventralMedialWall->getBounds(ventralBounds); if (dorsalBounds[3] < ventralBounds[3]) { // // Switch the pointers // std::swap(dorsalMedialWall, ventralMedialWall); } // // Set the names of the borders // dorsalMedialWall->setName(medialWallDorsalLandmark); ventralMedialWall->setName(medialWallVentralLandmark); // // Reverse links of dorsal border if necessary // Most positive X should be at beginning of border for left, most negative for right // float dorsal0[3], dorsalLast[3]; dorsalMedialWall->getLinkXYZ(0, dorsal0); dorsalMedialWall->getLinkXYZ(dorsalMedialWall->getNumberOfLinks() - 1, dorsalLast); if (flattenSurface->getStructure() == Structure::STRUCTURE_TYPE_CORTEX_LEFT) { if (dorsal0[0] < dorsalLast[0]) { dorsalMedialWall->reverseBorderLinks(); } } else { if (dorsal0[0] > dorsalLast[0]) { dorsalMedialWall->reverseBorderLinks(); } } // // Reverse links of ventral border if necessary // Most negative X should be at beginning of border for left, most positive for right // float ventral0[3], ventralLast[3]; ventralMedialWall->getLinkXYZ(0, ventral0); ventralMedialWall->getLinkXYZ(ventralMedialWall->getNumberOfLinks() - 1, ventralLast); if (flattenSurface->getStructure() == Structure::STRUCTURE_TYPE_CORTEX_LEFT) { if (ventral0[0] > ventralLast[0]) { ventralMedialWall->reverseBorderLinks(); } } else { if (ventral0[0] < ventralLast[0]) { ventralMedialWall->reverseBorderLinks(); } } // // Get the calcarine piece from its start to the medial wall // Border* calcarinePiece = calcarineCutBorder->getSubSet(0, calcarineMedialWallIntersect - 1); calcarinePiece->setName(calcarineLandmark); // // save the borders // landmarksForDeformation.addBorder(*dorsalMedialWall); landmarksForDeformation.addBorder(*ventralMedialWall); landmarksForDeformation.addBorder(*calcarinePiece); // // free up memory // delete dorsalMedialWall; delete ventralMedialWall; delete calcarinePiece; } } } } /** * create the landarks for deformation */ void BrainModelSurfaceFlattenFullHemisphere::createDeformationBorders(PaintFile* pf) { const int numNodes = flattenSurface->getNumberOfNodes(); // // Find the medial wall nodes // std::vector nonMedialWallNodes(numNodes, true); for (int i = 0; i < numNodes; i++) { if (pf->getPaint(i, geographyColumnNumber) == medialWallPaintFileIndex) { nonMedialWallNodes[i] = false; } } // // Create a point locator // BrainModelSurfacePointLocator locator(flattenSurface, true, false, &nonMedialWallNodes); // // Initialize a border projection file // BorderProjectionFile bpf; // // Convert the landmarks to a border projection file by dragging each border // link to the nearest node. // for (int m = 0; m < landmarksForDeformation.getNumberOfBorders(); m++) { const Border* b = landmarksForDeformation.getBorder(m); // // Create the border projection with the borders attributes // QString name; float center[3], sampling, variance, topographyValue, arealUncertainty; b->getData(name, center, sampling, variance, topographyValue, arealUncertainty); BorderProjection bp(b->getName(), center, sampling, variance, topographyValue, arealUncertainty); // // Project each border link to the nearest node and save as a border projection link // int previousNode = -1; for (int i = 0; i < b->getNumberOfLinks(); i++) { const int nearestNode = locator.getNearestPoint(b->getLinkXYZ(i)); if (nearestNode != previousNode) { const int vertices[3] = { nearestNode, nearestNode, nearestNode }; const float areas[3] = { 1.0, 0.0, 0.0 }; BorderProjectionLink bpl(b->getLinkSectionNumber(i), vertices, areas, b->getLinkRadius(i)); bp.addBorderProjectionLink(bpl); } previousNode = nearestNode; } // // If this projection is not empty // if (bp.getNumberOfLinks() > 0) { // // If this is a medial wall border // if ((bp.getName() == medialWallDorsalLandmark) || (bp.getName() == medialWallVentralLandmark)) { // // Remove is last link // bp.removeLastBorderProjectionLink(); } // // Add the border projection to the file // bpf.addBorderProjection(bp); } } // // Save the landmarks in a border projection file // if (bpf.getNumberOfBorderProjections()) { QString borderProjectionFileName; QString directory, species, casename, anatomy, hemisphere, description; QString descriptionNoType, theDate, numNodes, extension; if (FileUtilities::parseCaretDataFileName(originalTopoFileName, directory, species, casename, anatomy, hemisphere, description, descriptionNoType, theDate, numNodes, extension)) { borderProjectionFileName = FileUtilities::reassembleCaretDataFileName(directory, species, casename, anatomy, hemisphere, "LANDMARKS.FromFlattening", theDate, numNodes, SpecFile::getBorderProjectionFileExtension()); } else { std::ostringstream str; str << "species.case." << hemStr.toAscii().constData() << ".LANDMARKS.FromFlattening." << numNodes.toAscii().constData() << SpecFile::getBorderProjectionFileExtension().toAscii().constData(); borderProjectionFileName = str.str().c_str(); } bpf.writeFile(borderProjectionFileName); brainSet->addToSpecFile(SpecFile::getBorderProjectionFileTag(), borderProjectionFileName); } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceFlatHexagonalSubsample.h0000664000175000017500000000304311572067322027715 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_FLAT_HEXAGONAL_SUBSAMPLE_H__ #define __BRAIN_MODEL_SURFACE_FLAT_HEXAGONAL_SUBSAMPLE_H__ #include "BrainModelAlgorithm.h" class BrainModelSurface; /// Class that creates a hexagonal subsample of the flat surface class BrainModelSurfaceFlatHexagonalSubsample : public BrainModelAlgorithm { public: /// Constructor BrainModelSurfaceFlatHexagonalSubsample(BrainSet* brainSetIn, BrainModelSurface* fiducialSurfaceIn, BrainModelSurface* flatSurfaceIn, const int numberOfResamplingTiles = -1); /// Destructor ~BrainModelSurfaceFlatHexagonalSubsample(); /// create the sub sampled surface void execute() throw (BrainModelAlgorithmException); /// get the subsampled brain set BrainSet* getSubsampledBrainSet(); protected: /// fiducial of surface that is to be resampled BrainModelSurface* fiducialSurfaceForResampling; /// flat surface that is to be resampled BrainModelSurface* flatSurfaceForResampling; /// the subsampled brain set BrainSet* subSampBrainSet; /// number of resampling tiles goal int numberOfResamplingTiles; /// user retrieved the create brain set so destructor does not need to delete it bool brainSetRetrieved; }; #endif // __BRAIN_MODEL_SURFACE_FLAT_HEXAGONAL_SUBSAMPLE_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceFlatHexagonalSubsample.cxx0000664000175000017500000004117711572067322030302 0ustar michaelmichael #include #include "BorderFile.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceFlatHexagonalSubsample.h" #include "BrainModelSurfacePointProjector.h" #include "BrainSet.h" #include "DebugControl.h" #include "MathUtilities.h" /// used to create hexagonal surface class HexagonalNode { public: float xyz[3]; int indexX; int indexY; int nn; int mm; int tile; int tileNodes[3]; float tileAreas[3]; int nearestNode; bool isUsed; int nodeIndex; HexagonalNode(const float xyzIn[3], const int indexXIn, const int indexYIn, const int nnIn, const int mmIn, const int tileIn, const int tileNodesIn[3], const float tileAreasIn[3], const int nearestNodeIn) { xyz[0] = xyzIn[0]; xyz[1] = xyzIn[1]; xyz[2] = xyzIn[2]; indexX = indexXIn; indexY = indexYIn; nn = nnIn; mm = mmIn; tile = tileIn; tileNodes[0] = tileNodesIn[0]; tileNodes[1] = tileNodesIn[1]; tileNodes[2] = tileNodesIn[2]; tileAreas[0] = tileAreasIn[0]; tileAreas[1] = tileAreasIn[1]; tileAreas[2] = tileAreasIn[2]; nearestNode = nearestNodeIn; isUsed = false; nodeIndex = -1; } }; /** * Constructor. */ BrainModelSurfaceFlatHexagonalSubsample::BrainModelSurfaceFlatHexagonalSubsample( BrainSet* brainSetIn, BrainModelSurface* fiducialSurfaceIn, BrainModelSurface* flatSurfaceIn, const int numberOfResamplingTilesIn) : BrainModelAlgorithm(brainSetIn) { fiducialSurfaceForResampling = fiducialSurfaceIn; flatSurfaceForResampling = flatSurfaceIn; numberOfResamplingTiles = numberOfResamplingTilesIn; subSampBrainSet = NULL; brainSetRetrieved = false; } /** * Destructor */ BrainModelSurfaceFlatHexagonalSubsample::~BrainModelSurfaceFlatHexagonalSubsample() { if (brainSetRetrieved == false) { delete subSampBrainSet; } } /** * Create the subsampled surface. * * This creates a hexagonal grid that overlays the flat surface. * Initially, each row in the grid has the same number of nodes. The next row up is shifted * by one half the distance between nodes. This results in the nodes forming a parellelogram. * After the nodes have been created, the topology is created. If any of the tile's nodes are * inside the original surface provided by the user all three of the nodes and the tile are * retained. Once the topology has been determined, nodes that are not part of the topology * are discarded. */ void BrainModelSurfaceFlatHexagonalSubsample::execute() throw (BrainModelAlgorithmException) { if (flatSurfaceForResampling == NULL) { throw BrainModelAlgorithmException("No flat surface was provided."); } if (fiducialSurfaceForResampling == NULL) { throw BrainModelAlgorithmException("No fiducial surface was provided."); } // // Set number of tiles if user has not provided number // TopologyFile* topologyForResampling = flatSurfaceForResampling->getTopologyFile(); if (numberOfResamplingTiles < 0) { if (topologyForResampling == NULL) { throw BrainModelAlgorithmException("Flat surface has no topology."); } if (topologyForResampling->getNumberOfTiles() <= 0) { throw BrainModelAlgorithmException("Flat surface has no tiles"); } numberOfResamplingTiles = static_cast(topologyForResampling->getNumberOfTiles() * 0.3); } // // Get the bounds of the flat surface // CoordinateFile* fiducialCoords = fiducialSurfaceForResampling->getCoordinateFile(); CoordinateFile* flatCoords = flatSurfaceForResampling->getCoordinateFile(); float bounds[6]; flatCoords->getBounds(bounds); if (DebugControl::getDebugOn()) { try { BrainModelSurface tempf(*fiducialSurfaceForResampling); tempf.getCoordinateFile()->writeFile("debug_hex_subsamp_fiducial.coord"); BrainModelSurface tempf2(*flatSurfaceForResampling); tempf2.getCoordinateFile()->writeFile("debug_hex_subsamp_flat.coord"); } catch (FileException&) { } } // // Average distance between each linked pair of nodes in flat surface // float meanDistance, minDist, maxDist; flatSurfaceForResampling->getMeanDistanceBetweenNodes(NULL, meanDistance, minDist, maxDist); //const float meanDistance = flatSurfaceForResampling->getMeanDistanceBetweenNodes(); // // Area of flat surface // const float totalArea = flatSurfaceForResampling->getSurfaceArea(); if (DebugControl::getDebugOn()) { std::cout << "Mean Distance between nodes: " << meanDistance << std::endl; std::cout << "Total surface area: " << totalArea << std::endl; std::cout << "Resample to " << numberOfResamplingTiles << " tiles." << std::endl; } // // Determine spacing between resampled nodes // const float t1 = 4.0 * totalArea; const float sqrtOf3 = 1.7320508075; const float t2 = sqrtOf3 * numberOfResamplingTiles; const float spaceBetweenNodes = sqrt (t1/t2); if (DebugControl::getDebugOn()) { std::cout << "Spacing between resampled nodes: " << spaceBetweenNodes << std::endl; } // // 1/2 of surface height // const float dist = (bounds[3] - bounds[2])/2.0; // // Determine bounds of parallelogram overlaying input brain model surface // const int Nmin = static_cast(((bounds[0] - fabs(dist*0.57735))/spaceBetweenNodes) - 20.0); const int Nmax = static_cast(((bounds[1] + fabs(dist*0.57735))/spaceBetweenNodes) + 20.0); const int Mmin = static_cast(((bounds[2] *(2.0/sqrtOf3))/spaceBetweenNodes) - 2.0); const int Mmax = static_cast(((bounds[3]*(2.0/sqrtOf3))/spaceBetweenNodes) + 2.0); const int Nstop = Nmax - Nmin; const int Mstop = Mmax - Mmin; if (DebugControl::getDebugOn()) { std::cout << "New Surface Extent N " << Nmin << " " << Nmax << " M " << Mmin << " " << Mmax << std::endl; std::cout << "New dimensions: " << Nstop << " " << Mstop << std::endl; } // // Point Projector to project new surface points into original surface // BrainModelSurfacePointProjector bspp(flatSurfaceForResampling, BrainModelSurfacePointProjector::SURFACE_TYPE_HINT_FLAT, false); // // Create the new brain set // subSampBrainSet = new BrainSet; subSampBrainSet->setStructure(fiducialSurfaceForResampling->getStructure()); // // Create a new BrainModelSurface (both fiducial and flat and a flat that does not get morphed) // BrainModelSurface* fiducialSubSampSurface = new BrainModelSurface(subSampBrainSet); fiducialSubSampSurface->setSurfaceType(BrainModelSurface::SURFACE_TYPE_FIDUCIAL); fiducialSubSampSurface->setStructure(fiducialSurfaceForResampling->getStructure()); BrainModelSurface* flatSubSampSurface = new BrainModelSurface(subSampBrainSet); flatSubSampSurface->setSurfaceType(BrainModelSurface::SURFACE_TYPE_FLAT); flatSubSampSurface->setStructure(flatSurfaceForResampling->getStructure()); // // add surfaces to brain set // subSampBrainSet->addBrainModel(fiducialSubSampSurface); subSampBrainSet->addBrainModel(flatSubSampSurface); // // height of an equilateral triangle with base = 1.0 // const float triangleHeight = sqrtOf3 / 2.0; Border border("nodes"); // // Keep track of coordinates and which nodes are used // std::vector hexNodes; // // Subsample the current surface // // This loop iterates through a "parallelogram" that overlaps the surface. // for (int mm = Mmin; mm < Mmax; mm++) { for (int nn = Nmin; nn < Nmax; nn++) { const float p[3] = { (nn + mm/2.0) * spaceBetweenNodes, triangleHeight * mm * spaceBetweenNodes, 0.0 }; // // Indices that start at zero for X & Y // const int indexX = nn - Nmin; const int indexY = mm - Mmin; // // Project point to original surface // int nearestNode = -1; int tileNodes[3]; float areas[3]; const int tile = bspp.projectBarycentric(p, nearestNode, tileNodes, areas, true); HexagonalNode hexNode(p, indexX, indexY, nn, mm, tile, tileNodes, areas, nearestNode); hexNodes.push_back(hexNode); } } // // Create topology for the subsampled surface // TopologyFile* subSampTopology = new TopologyFile; subSampTopology->setTopologyType(topologyForResampling->getTopologyType()); subSampBrainSet->addTopologyFile(subSampTopology); for (int j = 0; j < (Mstop - 1); j++) { for (int i = 0; i < Nstop; i++) { const int hexNodeIndex = (j * Nstop) + i; HexagonalNode& hexNode = hexNodes[hexNodeIndex]; if (i > 0) { // // Triangle with neighbor above and left, and other neighbor above and right // const int neighAboveIndex = hexNodeIndex + Nstop; const int neighAboveLeftIndex = neighAboveIndex - 1; HexagonalNode& neighAboveHexNode = hexNodes[neighAboveIndex]; HexagonalNode& neighAboveLeftHexNode = hexNodes[neighAboveLeftIndex]; // // If any of the nodes projected to the surface, use the triangle // if ((hexNode.tile >= 0) || (neighAboveHexNode.tile >= 0) || (neighAboveLeftHexNode.tile >= 0)) { hexNode.isUsed = true; neighAboveHexNode.isUsed = true; neighAboveLeftHexNode.isUsed = true; subSampTopology->addTile(hexNodeIndex, neighAboveIndex, neighAboveLeftIndex); } } if (i < (Nstop - 1)) { // // Triangle with neighbor to the right and other neighbor above and right // const int neighRightIndex = hexNodeIndex + 1; const int neighAboveIndex = hexNodeIndex + Nstop; HexagonalNode& neighRightHexNode = hexNodes[neighRightIndex]; HexagonalNode& neighAboveHexNode = hexNodes[neighAboveIndex]; // // If any of the nodes projected to the surface, use the triangle // if ((hexNode.tile >= 0) || (neighRightHexNode.tile >= 0) || (neighAboveHexNode.tile >= 0)) { hexNode.isUsed = true; neighRightHexNode.isUsed = true; neighAboveHexNode.isUsed = true; subSampTopology->addTile(hexNodeIndex, neighRightIndex, neighAboveIndex); } } } } // // Find the resample points that are actually used // const int numHexNodes = static_cast(hexNodes.size()); for (int i = 0; i < numHexNodes; i++) { HexagonalNode& hexNode = hexNodes[i]; // // Was this node marked for use // if (hexNode.isUsed) { // // Get the corresponding position in the Fiducial coord // float fiducialXYZ[3] = { 0.0, 0.0, 0.0 }; if (hexNode.tile >= 0) { BrainModelSurfacePointProjector::unprojectPoint(hexNode.tileNodes, hexNode.tileAreas, fiducialCoords, fiducialXYZ); } else { fiducialCoords->getCoordinate(hexNode.nearestNode, fiducialXYZ); } fiducialSubSampSurface->addNode(fiducialXYZ); // // Add to the flat coordinate // flatSubSampSurface->addNode(hexNode.xyz); // // Set the new index for this point // hexNode.nodeIndex = flatSubSampSurface->getNumberOfNodes() - 1; if (DebugControl::getDebugOn()) { if (DebugControl::getDebugNodeNumber() == hexNode.nodeIndex) { int n1 = hexNode.tileNodes[0]; int n2 = hexNode.tileNodes[1]; int n3 = hexNode.tileNodes[2]; std::cout << "Hexagonal SubSample Output Node: " << hexNode.nodeIndex << "\n"; std::cout << " HexNode NearestNode: " << hexNode.nearestNode << "\n"; std::cout << " HexNode Triangle: " << hexNode.tile << "\n"; std::cout << " HexNode Triangle Nodes: " << hexNode.tileNodes[0] << ", " << hexNode.tileNodes[1] << ", " << hexNode.tileNodes[2] << "\n"; std::cout << " HexNode Triangle Areas: " << hexNode.tileAreas[0] << ", " << hexNode.tileAreas[1] << ", " << hexNode.tileAreas[2] << "\n"; std::cout << " HexNode Anatomical: " << fiducialXYZ[0] << ", " << fiducialXYZ[1] << ", " << fiducialXYZ[2] << "\n"; std::cout << " HexNode Flat: " << hexNode.xyz[0] << ", " << hexNode.xyz[1] << ", " << hexNode.xyz[2] << "\n"; float* f1 = fiducialCoords->getCoordinate(n1); std::cout << " Anat Node " << n1 << " " << f1[0] << ", " << f1[1] << ", " << f1[2] << "\n"; float* f2 = fiducialCoords->getCoordinate(n2); std::cout << " Anat Node " << n2 << " " << f2[0] << ", " << f2[1] << ", " << f2[2] << "\n"; float* f3 = fiducialCoords->getCoordinate(n3); std::cout << " Anat Node " << n3 << " " << f3[0] << ", " << f3[1] << ", " << f3[2] << "\n"; } } subSampBrainSet->resetNodeAttributes(); BrainSetNodeAttribute* bna = subSampBrainSet->getNodeAttributes(hexNode.nodeIndex); bna->setFlatMorphAttributes(hexNode.mm, hexNode.nn, hexNode.nearestNode); } } // // Update the topology file for new node indices // const int numTiles = subSampTopology->getNumberOfTiles(); for (int i = 0; i < numTiles; i++) { int v1, v2, v3; subSampTopology->getTile(i, v1, v2, v3); v1 = hexNodes[v1].nodeIndex; v2 = hexNodes[v2].nodeIndex; v3 = hexNodes[v3].nodeIndex; subSampTopology->setTile(i, v1, v2, v3); } // // Assign the topology file to both fiducial and flat surfaces // fiducialSubSampSurface->setTopologyFile(subSampTopology); flatSubSampSurface->setTopologyFile(subSampTopology); // // Make sure suffient nodes // const int numSubSampNodes = flatSubSampSurface->getNumberOfNodes(); if (numSubSampNodes <= 3) { //delete flatSubSampSurface; //delete fiducialSubSampSurface; //delete subSampTopology; delete subSampBrainSet; throw BrainModelAlgorithmException("Subsampled surface has no tiles."); } float resampBounds[6]; flatSubSampSurface->getCoordinateFile()->getBounds(resampBounds); if (DebugControl::getDebugOn()) { std::cout << "Resamp Bounds: " << resampBounds[0] << " " << resampBounds[1] << " " << resampBounds[2] << " " << resampBounds[3] << std::endl; } BorderFile bf(subSampTopology, flatSubSampSurface->getCoordinateFile()); bf.setHeaderTag(AbstractFile::headerTagConfigurationID, SpecFile::getFlatBorderFileTagName()); bf.writeFile("coords_as_border.border"); } /** * get the subsampled surface */ BrainSet* BrainModelSurfaceFlatHexagonalSubsample::getSubsampledBrainSet() { brainSetRetrieved = true; return subSampBrainSet; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceFindExtremum.h0000664000175000017500000001537111572067322025742 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_FIND_EXTREMUM_H__ #define __BRAIN_MODEL_SURFACE_FIND_EXTREMUM_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelAlgorithm.h" class BrainModelSurface; class BrainModelSurfaceROINodeSelection; class PaintFile; /// class for starting at a node, moving as far as possible in specified direction along mesh class BrainModelSurfaceFindExtremum : public BrainModelAlgorithm { public: /// direction for search enum DIRECTION { /// invalid direction DIRECTION_INVALID, /// move laterally DIRECTION_LATERAL, /// move medially DIRECTION_MEDIAL, /// move negative X DIRECTION_X_NEGATIVE, /// move positive X DIRECTION_X_POSITIVE, /// move negative Y DIRECTION_Y_NEGATIVE, /// move positive Y DIRECTION_Y_POSITIVE, /// move negative Z DIRECTION_Z_NEGATIVE, /// move positive Z DIRECTION_Z_POSITIVE, }; /// paint operation enum PAINT_OPERATION { /// no paint operation PAINT_OPERATION_NONE, /// move until paint identity changes PAINT_OPERATION_STOP_WHEN_PAINT_ID_CHANGES }; /// normal restriction enum NORMAL_RESTRICTION { /// no restriction NORMAL_RESTRICTION_NONE, /// restrict to negative normals NORMAL_RESTRICTION_NEGATIVE, /// restrict to positive normals NORMAL_RESTRICTION_POSITIVE }; // constructor BrainModelSurfaceFindExtremum(BrainSet* brainSetIn, BrainModelSurface* bmsIn, const DIRECTION searchDirectionIn, const int startNodeNumberIn, const float maximumMovementXIn, const float maximumMovementYIn, const float maximumMovementZIn); // constructor BrainModelSurfaceFindExtremum(BrainSet* brainSetIn, BrainModelSurface* bmsIn, const DIRECTION searchDirectionIn, const float startXYZ[3], const float maximumMovementXIn, const float maximumMovementYIn, const float maximumMovementZIn); // constructor BrainModelSurfaceFindExtremum(BrainSet* brainSetIn, BrainModelSurface* bmsIn, const DIRECTION searchDirectionIn, const int startNodeNumberIn, const float maximumMovementXIn, const float maximumMovementYIn, const float maximumMovementZIn, const PaintFile* paintFileIn, const int paintColumnNumberIn, const int paintIndexIn, const PAINT_OPERATION paintOperationIn); // destructor ~BrainModelSurfaceFindExtremum(); // restrict nodes to those in the roi void setNodeRestrictionWithROI(const BrainModelSurfaceROINodeSelection* restrictToROIIn); // restrict nodes to those with normals of specified signs void setNodeNormalRestriction(const NORMAL_RESTRICTION xNormalRestrictionIn, const NORMAL_RESTRICTION yNormalRestrictionIn, const NORMAL_RESTRICTION zNormalRestrictionIn); // get the extremum node that was found (-1 if invalid) int getExtremumNode() const { return extremumNode; } // get nodes in path to extremum including extremum void getNodeInPathToExtremum(std::vector& nodesInPathToExtremumOut) const; // set a region of interest to nodes in path void setRegionOfInterestToNodesInPath(BrainModelSurfaceROINodeSelection& roi) const; // execute the algorithm void execute() throw (BrainModelAlgorithmException); protected: /// see if a node is within maximum movement allowance bool withinMovementAllowance(const float x, const float y, const float z) const; /// check the node's normal bool checkNodeNormal(const float* normalVector) const; /// the surface BrainModelSurface* bms; /// starting node number int startNodeNumber; /// starting XYZ float startXYZ[3]; /// direction to search DIRECTION searchDirection; /// the extremum node that was found int extremumNode; /// maximum movement allowed in X direction when searching for extremum float maximumMovementX; /// maximum movement allowed in Y direction when searching for extremum float maximumMovementY; /// maximum movement allowed in Z direction when searching for extremum float maximumMovementZ; /// nodes in path to extremum std::vector nodesInPathToExtremum; /// paint operation PAINT_OPERATION paintOperation; /// paint file PaintFile* paintFile; /// paint column number int paintColumnNumber; /// paint index int paintIndex; /// normal restrictions NORMAL_RESTRICTION normalRestriction[3]; /// search ROI restriction BrainModelSurfaceROINodeSelection* restrictToROI; }; #endif // __BRAIN_MODEL_SURFACE_FIND_EXTREMUM_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceFindExtremum.cxx0000664000175000017500000003556211572067322026321 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelSurface.h" #include "BrainModelSurfaceFindExtremum.h" #include "BrainModelSurfaceROINodeSelection.h" #include "PaintFile.h" #include "TopologyFile.h" #include "TopologyHelper.h" /** * constructor. */ BrainModelSurfaceFindExtremum::BrainModelSurfaceFindExtremum(BrainSet* brainSetIn, BrainModelSurface* bmsIn, const DIRECTION searchDirectionIn, const int startNodeNumberIn, const float maximumMovementXIn, const float maximumMovementYIn, const float maximumMovementZIn) : BrainModelAlgorithm(brainSetIn) { bms = bmsIn; startNodeNumber = startNodeNumberIn; searchDirection = searchDirectionIn; startXYZ[0] = 0.0; startXYZ[1] = 0.0; startXYZ[2] = 0.0; extremumNode = -1; maximumMovementX = maximumMovementXIn; maximumMovementY = maximumMovementYIn; maximumMovementZ = maximumMovementZIn; paintOperation = PAINT_OPERATION_NONE; normalRestriction[0] = NORMAL_RESTRICTION_NONE; normalRestriction[1] = NORMAL_RESTRICTION_NONE; normalRestriction[2] = NORMAL_RESTRICTION_NONE; restrictToROI = NULL; } /** * constructor. */ BrainModelSurfaceFindExtremum::BrainModelSurfaceFindExtremum(BrainSet* brainSetIn, BrainModelSurface* bmsIn, const DIRECTION searchDirectionIn, const float startXYZIn[3], const float maximumMovementXIn, const float maximumMovementYIn, const float maximumMovementZIn) : BrainModelAlgorithm(brainSetIn) { bms = bmsIn; startNodeNumber = -1; searchDirection = searchDirectionIn; startXYZ[0] = startXYZIn[0]; startXYZ[1] = startXYZIn[1]; startXYZ[2] = startXYZIn[2]; extremumNode = -1; maximumMovementX = maximumMovementXIn; maximumMovementY = maximumMovementYIn; maximumMovementZ = maximumMovementZIn; paintOperation = PAINT_OPERATION_NONE; normalRestriction[0] = NORMAL_RESTRICTION_NONE; normalRestriction[1] = NORMAL_RESTRICTION_NONE; normalRestriction[2] = NORMAL_RESTRICTION_NONE; restrictToROI = NULL; } /** * constructor. */ BrainModelSurfaceFindExtremum::BrainModelSurfaceFindExtremum( BrainSet* brainSetIn, BrainModelSurface* bmsIn, const DIRECTION searchDirectionIn, const int startNodeNumberIn, const float maximumMovementXIn, const float maximumMovementYIn, const float maximumMovementZIn, const PaintFile* paintFileIn, const int paintColumnNumberIn, const int paintIndexIn, const PAINT_OPERATION paintOperationIn) : BrainModelAlgorithm(brainSetIn) { bms = bmsIn; startNodeNumber = startNodeNumberIn; searchDirection = searchDirectionIn; startXYZ[0] = 0.0; startXYZ[1] = 0.0; startXYZ[2] = 0.0; extremumNode = -1; maximumMovementX = maximumMovementXIn; maximumMovementY = maximumMovementYIn; maximumMovementZ = maximumMovementZIn; paintFile = (PaintFile*)paintFileIn; paintColumnNumber = paintColumnNumberIn; paintIndex = paintIndexIn; paintOperation = paintOperationIn; normalRestriction[0] = NORMAL_RESTRICTION_NONE; normalRestriction[1] = NORMAL_RESTRICTION_NONE; normalRestriction[2] = NORMAL_RESTRICTION_NONE; restrictToROI = NULL; } /** * destructor. */ BrainModelSurfaceFindExtremum::~BrainModelSurfaceFindExtremum() { } /** * execute the algorithm. */ void BrainModelSurfaceFindExtremum::execute() throw (BrainModelAlgorithmException) { nodesInPathToExtremum.clear(); if (searchDirection == DIRECTION_INVALID) { throw BrainModelAlgorithmException("Search direction is invalid."); } if (bms == NULL) { throw BrainModelAlgorithmException("Surface is invalid."); } const CoordinateFile* cf = bms->getCoordinateFile(); const int numNodes = bms->getNumberOfNodes(); if (numNodes <= 0) { throw BrainModelAlgorithmException("Surface contains no nodes."); } const TopologyFile* tf = bms->getTopologyFile(); if (tf == NULL) { throw BrainModelAlgorithmException("Surface has no topology."); } const TopologyHelper* th = tf->getTopologyHelper(false, true, false); switch (paintOperation) { case PAINT_OPERATION_NONE: break; case PAINT_OPERATION_STOP_WHEN_PAINT_ID_CHANGES: if (paintFile == NULL) { throw BrainModelAlgorithmException("Paint file is invalid."); } if ((paintColumnNumber < 0) || (paintColumnNumber >= paintFile->getNumberOfColumns())) { throw BrainModelAlgorithmException("Paint column number is invalid."); } break; } // // Convert lateral/medial search to negative or positive X search // if (searchDirection == DIRECTION_LATERAL) { if (bms->getStructure().getType() == Structure::STRUCTURE_TYPE_CORTEX_LEFT) { searchDirection = DIRECTION_X_NEGATIVE; } else if (bms->getStructure().getType() == Structure::STRUCTURE_TYPE_CORTEX_RIGHT) { searchDirection = DIRECTION_X_POSITIVE; } else { throw BrainModelAlgorithmException( "Surface has invalid structure need to for lateral search."); } } else if (searchDirection == DIRECTION_MEDIAL) { if (bms->getStructure().getType() == Structure::STRUCTURE_TYPE_CORTEX_LEFT) { searchDirection = DIRECTION_X_POSITIVE; } else if (bms->getStructure().getType() == Structure::STRUCTURE_TYPE_CORTEX_RIGHT) { searchDirection = DIRECTION_X_NEGATIVE; } else { throw BrainModelAlgorithmException( "Surface has invalid structure need to for lateral search."); } } // // If extremum node was not set, find node closest to start XYZ // if (startNodeNumber < 0) { startNodeNumber = bms->getNodeClosestToPoint(startXYZ); } else { cf->getCoordinate(startNodeNumber, startXYZ); } extremumNode = startNodeNumber; if (extremumNode < 0) { throw BrainModelAlgorithmException("Unable to determine starting node from XYZ."); } // // add nodes to path // nodesInPathToExtremum.push_back(extremumNode); // // Search surface until unable to proceed any further // bool done = false; while (done == false) { // // node's XYZ // float x, y, z; cf->getCoordinate(extremumNode, x, y, z); // // Get the neighbors of the current node // int numNeighbors = 0; const int* neighbors = th->getNodeNeighbors(extremumNode, numNeighbors); // // next node and value for searching // int nextNode = -1; float nextValue = 0.0; // // Loop through neighbors // for (int j = 0; j < numNeighbors; j++) { const int neighborNode = neighbors[j]; float nx, ny, nz; cf->getCoordinate(neighborNode, nx, ny, nz); if (restrictToROI != NULL) { if (restrictToROI->getNodeSelected(neighborNode) == false) { continue; } } if (checkNodeNormal(bms->getNormal(neighborNode))) { switch (searchDirection) { case DIRECTION_INVALID: break; case DIRECTION_LATERAL: break; case DIRECTION_MEDIAL: break; case DIRECTION_X_NEGATIVE: if (nx < x) { if ((nextNode < 0) || (nx < nextValue)) { if (withinMovementAllowance(nx, ny, nz)) { nextNode = neighborNode; nextValue = nx; } } } break; case DIRECTION_X_POSITIVE: if (nx > x) { if ((nextNode < 0) || (nx > nextValue)) { if (withinMovementAllowance(nx, ny, nz)) { nextNode = neighborNode; nextValue = nx; } } } break; case DIRECTION_Y_NEGATIVE: if (ny < y) { if ((nextNode < 0) || (ny < nextValue)) { if (withinMovementAllowance(nx, ny, nz)) { nextNode = neighborNode; nextValue = ny; } } } break; case DIRECTION_Y_POSITIVE: if (ny > y) { if ((nextNode < 0) || (ny > nextValue)) { if (withinMovementAllowance(nx, ny, nz)) { nextNode = neighborNode; nextValue = ny; } } } break; case DIRECTION_Z_NEGATIVE: if (nz < z) { if ((nextNode < 0) || (nz < nextValue)) { if (withinMovementAllowance(nx, ny, nz)) { nextNode = neighborNode; nextValue = nz; } } } break; case DIRECTION_Z_POSITIVE: if (nz > z) { if ((nextNode < 0) || (nz > nextValue)) { if (withinMovementAllowance(nx, ny, nz)) { nextNode = neighborNode; nextValue = nz; } } } break; } } } // // Was next node found ? // if (nextNode >= 0) { // // Check paint ? // switch (paintOperation) { case PAINT_OPERATION_NONE: break; case PAINT_OPERATION_STOP_WHEN_PAINT_ID_CHANGES: // // Did paint change? // if (paintFile->getPaint(nextNode, paintColumnNumber) != paintIndex) { done = true; } break; } if (done == false) { // // move to next node // extremumNode = nextNode; // // add nodes to path // nodesInPathToExtremum.push_back(extremumNode); } } else { // // done // done = true; } } } /** * see if a node is within maximum movement allowance. */ bool BrainModelSurfaceFindExtremum::withinMovementAllowance(const float x, const float y, const float z) const { const float dx = std::fabs(x - startXYZ[0]); const float dy = std::fabs(y - startXYZ[1]); const float dz = std::fabs(z - startXYZ[2]); //std::cout << "y: " << y // << " dy: " << dy // << " maximumMovementY: " << maximumMovementY // << std::endl; if ((dx < maximumMovementX) && (dy < maximumMovementY) && (dz < maximumMovementZ)) { return true; } return false; } /** * check the node's normal. */ bool BrainModelSurfaceFindExtremum::checkNodeNormal(const float* normalVector) const { for (int i = 0; i < 3; i++) { switch (normalRestriction[i]) { case NORMAL_RESTRICTION_NONE: break; case NORMAL_RESTRICTION_NEGATIVE: if (normalVector[i] >= 0.0) { return false; } case NORMAL_RESTRICTION_POSITIVE: if (normalVector[i] <= 0.0) { return false; } } } return true; } /** * get nodes in path to extremum including extremum. */ void BrainModelSurfaceFindExtremum::getNodeInPathToExtremum(std::vector& nodesInPathToExtremumOut) const { nodesInPathToExtremumOut = nodesInPathToExtremum; } /** * set a region of interest to nodes in path. */ void BrainModelSurfaceFindExtremum::setRegionOfInterestToNodesInPath(BrainModelSurfaceROINodeSelection& roi) const { roi.update(); roi.deselectAllNodes(); const int num = nodesInPathToExtremum.size(); for (int i = 0; i < num; i++) { roi.setNodeSelected(nodesInPathToExtremum[i], 1); } } /** * restrict nodes to those with normals of specified signs. */ void BrainModelSurfaceFindExtremum::setNodeNormalRestriction( const NORMAL_RESTRICTION xNormalRestrictionIn, const NORMAL_RESTRICTION yNormalRestrictionIn, const NORMAL_RESTRICTION zNormalRestrictionIn) { normalRestriction[0] = xNormalRestrictionIn; normalRestriction[1] = yNormalRestrictionIn; normalRestriction[2] = zNormalRestrictionIn; } /** * restrict nodes to those in the roi. */ void BrainModelSurfaceFindExtremum::setNodeRestrictionWithROI( const BrainModelSurfaceROINodeSelection* restrictToROIIn) { restrictToROI = (BrainModelSurfaceROINodeSelection*)restrictToROIIn; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceDistortion.h0000664000175000017500000000660111572067322025465 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_BRAIN_SURFACE_DISTORTION_H__ #define __VE_BRAIN_SURFACE_DISTORTION_H__ #include #include "BrainModelAlgorithm.h" #include "StatisticsUtilities.h" class BrainModelSurface; class SurfaceShapeFile; class TopologyFile; /// Class to compute distortion between two surfaces class BrainModelSurfaceDistortion : public BrainModelAlgorithm { public: enum DISTORTION_COLUMNS { DISTORTION_COLUMN_CREATE_NEW = -1, DISTORTION_COLUMN_DO_NOT_GENERATE = -2 }; /// Constructor BrainModelSurfaceDistortion(BrainSet* brainSetIn, BrainModelSurface* surfaceIn, BrainModelSurface* referenceSurfaceIn, TopologyFile* topologyFileIn, SurfaceShapeFile* surfaceShapeFileIn, const int arealDistortionColumnIn, const int linearDistortionColumnIn, const QString& arealDistortionNameIn, const QString& linearDistortionNameIn); /// Destructor ~BrainModelSurfaceDistortion(); /// add/update the distortions in the surface shape file virtual void execute() throw (BrainModelAlgorithmException); /// Get statistical measurements for areal distortion void getArealDistortionStatistics(StatisticsUtilities::DescriptiveStatistics& stats) const; /// Get statistical measurements for linear distortion void getLinearDistortionStatistics(StatisticsUtilities::DescriptiveStatistics& stats) const; private: /// surface BrainModelSurface* surface; /// reference surface BrainModelSurface* referenceSurface; /// topology file TopologyFile* topologyFile; /// surface shape file SurfaceShapeFile* surfaceShapeFile; /// name for areal distorition QString arealDistortionName; /// name for linear distortion QString linearDistortionName; /// linear distortion saved for statistical calculation std::vector linearDistortionForStatistics; /// areal distortion saved for statistical calculation std::vector arealDistortionForStatistics; /// areal distortion column number int arealDistortionColumn; /// linear distortion column number int linearDistortionColumn; }; #endif // __VE_BRAIN_SURFACE_DISTORTION_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceDistortion.cxx0000664000175000017500000002235111572067322026040 0ustar michaelmichael#include #include #include "BrainModelSurface.h" #include "BrainModelSurfaceDistortion.h" #include "FileUtilities.h" #include "MathUtilities.h" #include "StatisticDataGroup.h" #include "SurfaceShapeFile.h" #include "TopologyFile.h" #include "TopologyHelper.h" #include "vtkTriangle.h" /** * Constructor */ BrainModelSurfaceDistortion::BrainModelSurfaceDistortion(BrainSet* brainSetIn, BrainModelSurface* surfaceIn, BrainModelSurface* referenceSurfaceIn, TopologyFile* topologyFileIn, SurfaceShapeFile* surfaceShapeFileIn, const int arealDistortionColumnIn, const int linearDistortionColumnIn, const QString& arealDistortionNameIn, const QString& linearDistortionNameIn) : BrainModelAlgorithm(brainSetIn) { surface = surfaceIn; referenceSurface = referenceSurfaceIn; topologyFile = topologyFileIn; surfaceShapeFile = surfaceShapeFileIn; arealDistortionColumn = arealDistortionColumnIn; linearDistortionColumn = linearDistortionColumnIn; arealDistortionName = arealDistortionNameIn; linearDistortionName = linearDistortionNameIn; } /** * Destructor */ BrainModelSurfaceDistortion::~BrainModelSurfaceDistortion() { } /** * add/update the distortions in the surface shape file */ void BrainModelSurfaceDistortion::execute() throw (BrainModelAlgorithmException) { // // Coordinate files of both surfaces // const CoordinateFile* referenceCoords = referenceSurface->getCoordinateFile(); const CoordinateFile* coords = surface->getCoordinateFile(); // // Get number of nodes // const int numNodes = referenceCoords->getNumberOfCoordinates(); // // Use topology helper to find tiles for each node // const TopologyHelper th(topologyFile, false, true, false); // // Create comment info about surface used in distortion // QString commentInfo("Reference Surface: "); commentInfo.append(FileUtilities::basename(referenceSurface->getFileName())); commentInfo.append("\nSurface:"); commentInfo.append(FileUtilities::basename(surface->getFileName())); // // Create surface shape file columns if needed // if (arealDistortionColumn == DISTORTION_COLUMN_CREATE_NEW) { if (surfaceShapeFile->getNumberOfColumns() == 0) { surfaceShapeFile->setNumberOfNodesAndColumns(surface->getNumberOfNodes(), 1); } else { surfaceShapeFile->addColumns(1); } arealDistortionColumn = surfaceShapeFile->getNumberOfColumns() - 1; } if (linearDistortionColumn == DISTORTION_COLUMN_CREATE_NEW) { if (surfaceShapeFile->getNumberOfColumns() == 0) { surfaceShapeFile->setNumberOfNodesAndColumns(surface->getNumberOfNodes(), 1); } else { surfaceShapeFile->addColumns(1); } linearDistortionColumn = surfaceShapeFile->getNumberOfColumns() - 1; } // // Set column names // if (arealDistortionColumn >= 0) { surfaceShapeFile->setColumnName(arealDistortionColumn, arealDistortionName); surfaceShapeFile->setColumnColorMappingMinMax(arealDistortionColumn, -1.0, 1.0); surfaceShapeFile->setColumnComment(arealDistortionColumn, commentInfo); } if (linearDistortionColumn >= 0) { surfaceShapeFile->setColumnName(linearDistortionColumn, linearDistortionName); surfaceShapeFile->setColumnColorMappingMinMax(linearDistortionColumn, 0.0, 2.0); surfaceShapeFile->setColumnComment(linearDistortionColumn, commentInfo); } // // If areal distortion should be created // if (arealDistortionColumn >= 0) { // // Allocate areal distortion for statistics // arealDistortionForStatistics.resize(numNodes, 0); // // log(2.0) to avoid recomputation each iteration // const double log2 = log(2.0); // // Compute distortion for each tile // const int numTiles = topologyFile->getNumberOfTiles(); std::vector tileDistortion; for (int i = 0; i < numTiles; i++) { const int* v = topologyFile->getTile(i); const float tileAreaReference = MathUtilities::triangleArea( (float*)referenceCoords->getCoordinate(v[0]), (float*)referenceCoords->getCoordinate(v[1]), (float*)referenceCoords->getCoordinate(v[2])); const float tileArea = MathUtilities::triangleArea( (float*)coords->getCoordinate(v[0]), (float*)coords->getCoordinate(v[1]), (float*)coords->getCoordinate(v[2])); double distortion = 0.0; if (tileAreaReference != 0.0) { distortion = tileArea / tileAreaReference; } else { if (tileArea != 0.0) { distortion = 10000.0; // big distortion since denominator is zero } else { distortion = 1.0; // if both zero then same area } } // // zero will cause -inf // if (distortion < 0.00000001) { distortion = 0.00000001; } tileDistortion.push_back(log(distortion) / log2); } // // Compute areal distortion for all nodes // for (int i = 0; i < numNodes; i++) { float distortion = 1.0; const float numberOfNeighbors = th.getNodeNumberOfNeighbors(i); if (numberOfNeighbors >= 1.0) { distortion = 0.0; std::vector tiles; th.getNodeTiles(i, tiles); for (int j = 0; j < static_cast(tiles.size()); j++) { distortion += tileDistortion[tiles[j]]; } distortion /= numberOfNeighbors; } surfaceShapeFile->setValue(i, arealDistortionColumn, distortion); arealDistortionForStatistics[i] = distortion; } } // // If linear distortion should be created // if (linearDistortionColumn >= 0) { // // Allocate linear distortion for statistics // linearDistortionForStatistics.resize(numNodes, 0); // // Compute linear distortion for all nodes // for (int i = 0; i < numNodes; i++) { float distortion = 0.0; std::vector neighbors; th.getNodeNeighbors(i, neighbors); const int numberOfNeighbors = neighbors.size(); if (numberOfNeighbors >= 1) { const float* me = coords->getCoordinate(i); const float* ref = referenceCoords->getCoordinate(i); float distort = 0.0; for (int j = 0; j < numberOfNeighbors; j++) { const float dist = MathUtilities::distance3D(me, coords->getCoordinate(neighbors[j])); const float distRef = MathUtilities::distance3D(ref, referenceCoords->getCoordinate(neighbors[j])); if (distRef != 0.0) { distort += (dist / distRef); } else { if (dist != 0.0) { distort += 10000.0; // big number since denominator is zero } else { distort += 1.0; // both are zero } } } distortion = distort / static_cast(numberOfNeighbors); } surfaceShapeFile->setValue(i, linearDistortionColumn, distortion); linearDistortionForStatistics[i] = distortion; } } } /** * Get statistical measurements for areal distortion */ void BrainModelSurfaceDistortion::getArealDistortionStatistics(StatisticsUtilities::DescriptiveStatistics& stats) const { stats.reset(); StatisticsUtilities::computeStatistics(arealDistortionForStatistics, true, stats); /* StatisticDescriptiveStatistics sds(StatisticDescriptiveStatistics::DATA_TYPE_SAMPLE); StatisticDataGroup sdg(&arealDistortionForStatistics); sds.addDataGroup(&sdg); try { sds.execute(); } catch (StatisticException&) { } stats = sds.getDescriptiveStatistics(); */ } /** * Get statistical measurements for linear distortion */ void BrainModelSurfaceDistortion::getLinearDistortionStatistics(StatisticsUtilities::DescriptiveStatistics& stats) const { stats.reset(); StatisticsUtilities::computeStatistics(linearDistortionForStatistics, true, stats); /* StatisticDescriptiveStatistics sds(StatisticDescriptiveStatistics::DATA_TYPE_SAMPLE); StatisticDataGroup sdg(&linearDistortionForStatistics); sds.addDataGroup(&sdg); try { sds.execute(); } catch (StatisticException&) { } stats = sds.getDescriptiveStatistics(); */ } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceDeformationSphericalVector.h0000664000175000017500000001326611572067322030621 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __BRAIN_MODEL_SURFACE_DEFORMATION_SPHERICAL_VECTOR_H__ #define __BRAIN_MODEL_SURFACE_DEFORMATION_SPHERICAL_VECTOR_H__ #include "BrainModelSurfaceDeformation.h" #include "SurfaceShapeFile.h" /// this class performs a spherical vector deformation class BrainModelSurfaceDeformationSphericalVector : public BrainModelSurfaceDeformation { public: /// Constructor BrainModelSurfaceDeformationSphericalVector(BrainSet* brainSetIn, DeformationMapFile* DeformationMapFileIn); /// Destructor ~BrainModelSurfaceDeformationSphericalVector(); protected: /// Execute the deformation void executeDeformation() throw (BrainModelAlgorithmException); // Perform landmark constrained morphing on the sphere with source landmarks void landmarkMorphContrainedSource(BrainModelSurface* referenceDeformationSphere, const int cycleNumber) throw (BrainModelAlgorithmException); /// Perform landmark neighbor constrained smoothing on the sphere with source landmarks void landmarkNeighborConstrainedSmoothSource(const int cycleNumber); /// Get a regularly tessellated sphere and set its radius. BrainModelSurface* getRegularSphere(BrainSet* bs, float radius) throw (BrainModelAlgorithmException); /// tessellate the target border into the target deformation sphere void tessellateTargetBordersIntoDeformationSphere() throw (BrainModelAlgorithmException); /// tessellate the source border into the source deformation sphere void tessellateSourceBordersIntoDeformationSphere() throw (BrainModelAlgorithmException); /// create the deformed coordinate file at the end of each cycle void createDeformedCoordinateFile(BrainModelSurface* sourceDeformationSphere, BrainModelSurface* registeredDeformationSourceSphere, const int cycleNumber); /// write a border file containing the deformed landmarks void writeSourceBorderLandmarkFile(BrainModelSurface* surface, const int cycleNumber); /// write coords without the landmarks void writeCoordinatesWithoutLandmarks(BrainModelSurface* surface, const int cycleNumber); /// create the surface shape file containing the XYZ differences SurfaceShapeFile* createDifferenceShapeFile(int iterations); /// determine the fiducial sphere distortion void determineFiducialSphereDistortion(); /// update the fiducial sphere distortion void updateSphereFiducialDistortion(const int cycle, BrainModelSurface* morphedSourceDeformationSphere); /// Determine distortion ratio of fiducial vs spherical tile areas. void determineSphericalDistortion(const BrainModelSurface* fiducialSurface, const BrainModelSurface* sphericalSurface, std::vector& tileDistortion); /// move the landmark nodes to the average of their neighboring nodes void moveLandmarksToAverageOfNeighbors(BrainModelSurface* bms); /// the target deformation sphere BrainModelSurface* targetDeformationSphere; /// the source deformation sphere BrainModelSurface* sourceDeformationSphere; /// the reference source deformation sphere BrainModelSurface* referenceSourceDeformationSphere; /// the number of nodes in the regularly tessellated sphere prior to inserting landmarks int originalNumberOfNodes; /// keeps track of borders that are tessellated into the deformation sphere std::vector > usedBorderLinks; /// target file naming prefix for debugging QString debugTargetFileNamePrefix; /// source file naming prefix for debugging QString debugSourceFileNamePrefix; /// radius of the deformation sphere float deformationSphereRadius; /// keeps track of landmark nodes std::vector landmarkNodeFlags; /// keeps track of crossovers in each cycle std::vector crossoverCount; /// the target brain set BrainSet* targetDeformationBrainSet; /// Keep track of distortion SurfaceShapeFile fiducialSphereDistortion; /// ratio of target fiducial and spherical tile areas std::vector targetTileDistortion; /// ratio of source fiducial and spherical tile areas std::vector sourceTileDistortion; /// shape file containing border variances for the landmark nodes SurfaceShapeFile borderVarianceValuesShapeFile; }; #endif // __BRAIN_MODEL_SURFACE_DEFORMATION_SPHERICAL_VECTOR_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceDeformationSphericalVector.cxx0000664000175000017500000017771611572067322031207 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include "AreaColorFile.h" #include "BorderFile.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceDeformationSphericalVector.h" #include "BrainModelSurfaceMetricSmoothing.h" #include "BrainModelSurfaceMorphing.h" #include "BrainModelSurfaceNodeColoring.h" #include "BrainModelSurfacePointProjector.h" #include "BrainSet.h" #include "ColorFile.h" #include "DebugControl.h" #include "DeformationMapFile.h" #include "FileUtilities.h" #include "MathUtilities.h" #include "PaintFile.h" #include "StringUtilities.h" #include "TopologyHelper.h" //static const int morphAngleForceAlgorithm = 1; /** * Constructor. */ BrainModelSurfaceDeformationSphericalVector::BrainModelSurfaceDeformationSphericalVector( BrainSet* brainSetIn, DeformationMapFile* deformationMapFileIn) : BrainModelSurfaceDeformation(brainSetIn, deformationMapFileIn) { targetDeformationBrainSet = NULL; } /** * Destructor. */ BrainModelSurfaceDeformationSphericalVector::~BrainModelSurfaceDeformationSphericalVector() { if (targetDeformationBrainSet != NULL) { delete targetDeformationBrainSet; targetDeformationBrainSet = NULL; } } /** * Determine distortion ratio of fiducial vs spherical tile areas. */ void BrainModelSurfaceDeformationSphericalVector::determineSphericalDistortion( const BrainModelSurface* fiducialSurface, const BrainModelSurface* sphericalSurface, std::vector& tileDistortion) { // // Get topology file and number of tiles // const TopologyFile* tf = sphericalSurface->getTopologyFile(); const int numTiles = tf->getNumberOfTiles(); tileDistortion.resize(numTiles); // // Get the coordinate files // const CoordinateFile* fiducialCoords = fiducialSurface->getCoordinateFile(); const CoordinateFile* sphericalCoords = sphericalSurface->getCoordinateFile(); // // Determine fiducial/spherical area ratio of tiles // for (int i = 0; i < numTiles; i++) { int v1, v2, v3; tf->getTile(i, v1, v2, v3); const float sphereArea = MathUtilities::triangleArea((float*)sphericalCoords->getCoordinate(v1), (float*)sphericalCoords->getCoordinate(v2), (float*)sphericalCoords->getCoordinate(v3)); tileDistortion[i] = 1.0; if (sphereArea != 0.0) { const float fidArea = MathUtilities::triangleArea((float*)fiducialCoords->getCoordinate(v1), (float*)fiducialCoords->getCoordinate(v2), (float*)fiducialCoords->getCoordinate(v3)); tileDistortion[i] = fidArea / sphereArea; } } } /** * Determine the fiducial sphere distortion. */ void BrainModelSurfaceDeformationSphericalVector::determineFiducialSphereDistortion() { // // Create a point projector for projecting the deformation sphere nodes // onto the target surface // BrainModelSurfacePointProjector bspp(targetSurface, BrainModelSurfacePointProjector::SURFACE_TYPE_HINT_SPHERE, false); const int numTargetTiles = static_cast(targetTileDistortion.size()); // // Project each node in the deformation sphere // const int numNodes = targetDeformationSphere->getNumberOfNodes(); const CoordinateFile* targetDeformationCoords = targetDeformationSphere->getCoordinateFile(); for (int i = 0; i < numNodes; i++) { float xyz[3]; targetDeformationCoords->getCoordinate(i, xyz); // // Project target node onto source deformed surface // int nearestNode = -1; int tileNodes[3]; float tileAreas[3]; const int tile = bspp.projectBarycentric(xyz, nearestNode, tileNodes, tileAreas, true); // // Did it project ? // if ((tile >= 0) && (tile < numTargetTiles)) { fiducialSphereDistortion.setValue(i, 0, targetTileDistortion[tile]); } else { fiducialSphereDistortion.setValue(i, 0, 1.0); } } } /** * Update the fiducial sphere distortion. */ void BrainModelSurfaceDeformationSphericalVector::updateSphereFiducialDistortion( const int cycleIndex, BrainModelSurface* morphedSourceDeformationSphere) { // // Create a point projector for projecting the source deformation sphere // nodes to the original source surface // BrainModelSurfacePointProjector bspp(sourceSurface, BrainModelSurfacePointProjector::SURFACE_TYPE_HINT_SPHERE, false); // // Project deformation sphere nodes onto original source surface // const int numNodes = morphedSourceDeformationSphere->getNumberOfNodes(); const CoordinateFile* coords = morphedSourceDeformationSphere->getCoordinateFile(); const int numSourceTiles = static_cast(sourceTileDistortion.size()); for (int i = 0; i < numNodes; i++) { float xyz[3]; coords->getCoordinate(i, xyz); // // Project target node onto source deformed surface // int nearestNode = -1; int tileNodes[3]; float tileAreas[3]; const int tile = bspp.projectBarycentric(xyz, nearestNode, tileNodes, tileAreas, true); // // Did it project ? // if ((tile >= 0) && (tile < numSourceTiles)) { fiducialSphereDistortion.setValue(i, 1, sourceTileDistortion[tile]); } else { fiducialSphereDistortion.setValue(i, 1, 1.0); } fiducialSphereDistortion.setValue(i, 2, std::sqrt(fiducialSphereDistortion.getValue(i, 1) / fiducialSphereDistortion.getValue(i, 0))); } // // Save the surface shape file // std::ostringstream str; str << "targetFiducialSphereDistortion" << "_cycle_" << cycleIndex + 1 << SpecFile::getSurfaceShapeFileExtension().toAscii().constData(); fiducialSphereDistortion.writeFile(str.str().c_str()); //brainSet->addToSpecFile(SpecFile::getSurfaceShapeFileTag(), str.str().c_str()); intermediateFiles.push_back(str.str().c_str()); } /** * Load the regularly tessellated sphere and set its radius. */ BrainModelSurface* BrainModelSurfaceDeformationSphericalVector::getRegularSphere(BrainSet* bs, float radius) throw (BrainModelAlgorithmException) { // // Construct the regular sphere file name // QString specFileName(bs->getCaretHomeDirectory()); specFileName.append("/"); specFileName.append("data_files/REGISTER.SPHERE"); specFileName.append("/"); switch(deformationMapFile->getSphereResolution(0)) { case 20: specFileName.append("sphere.v5.0.spec"); break; case 74: specFileName.append("sphere.v5.1.spec"); break; case 290: specFileName.append("sphere.v5.2.spec"); break; case 1154: specFileName.append("sphere.v5.3.spec"); break; case 4610: specFileName.append("sphere.v5.4.spec"); break; case 18434: specFileName.append("sphere.v5.5.spec"); break; case 73730: specFileName.append("sphere.v5.6.spec"); break; default: { std::ostringstream str; str << "Invalid sphere resolution: " << deformationMapFile->getSphereResolution(0); throw BrainModelAlgorithmException(str.str().c_str()); } break; } // // Read the spec file // SpecFile sf; try { sf.readFile(specFileName); } catch (FileException& e) { throw BrainModelAlgorithmException(e.whatQString()); } sf.setAllFileSelections(SpecFile::SPEC_TRUE); // // Read the spec file into "this" brain set (use APPEND for source sphere) // std::vector errorMessages; bs->readSpecFile(BrainSet::SPEC_FILE_READ_MODE_NORMAL, sf, specFileName, errorMessages, NULL, NULL); if (errorMessages.empty() == false) { QString msg("Error reading data files for "); msg.append(specFileName); msg.append("\n"); msg.append(StringUtilities::combine(errorMessages, "\n")); throw BrainModelAlgorithmException(msg); } // // Get the spherical surface and set its radius // BrainModelSurface* sphereSurface = bs->getBrainModelSurface(0); if (sphereSurface == NULL) { throw BrainModelAlgorithmException("Regular sphere spec contained no coord file."); } sphereSurface->convertToSphereWithRadius(radius); sphereSurface->updateForDefaultScaling(); updateViewingTransformation(bs); return sphereSurface; } /** * Tessellate the target border into the target deformation sphere */ void BrainModelSurfaceDeformationSphericalVector::tessellateTargetBordersIntoDeformationSphere() throw (BrainModelAlgorithmException) { // // empty contents of the used and ignored border links // usedBorderLinks.clear(); // // Create a Point Projector with nodes to be added for the deformation sphere. // BrainModelSurfacePointProjector bspp(targetDeformationSphere, BrainModelSurfacePointProjector::SURFACE_TYPE_HINT_SPHERE, true); TopologyFile* tf = targetDeformationSphere->getTopologyFile(); // // Project each border link into the deformation sphere // const int numBorders = targetBorderFile->getNumberOfBorders(); for (int i = 0; i < numBorders; i++) { const Border* b = targetBorderFile->getBorder(i); const int numLinks = b->getNumberOfLinks(); for (int j = 0; j < numLinks; j++) { const float* xyz = b->getLinkXYZ(j); // // Project target node onto source deformed surface // int nearestNode = -1; int tileNodes[3]; float tileAreas[3]; const int tile = bspp.projectBarycentric(xyz, nearestNode, tileNodes, tileAreas, true); const int newNodeNumber = targetDeformationSphere->getNumberOfNodes(); // // Unproject using the deformed source coordinate file // if (tile >= 0) { // // Get the tile // int v1, v2, v3; tf->getTile(tile, v1, v2, v3); // // Create two new tiles // const int tn1[3] = { v1, v2, newNodeNumber }; const int tn2[3] = { v2, v3, newNodeNumber }; const int tn3[3] = { v3, v1, newNodeNumber }; // // Replace the original tile and create two new ones // tf->setTile(tile, tn1); tf->addTile(tn2); tf->addTile(tn3); // // Add the node to the surface // targetDeformationSphere->addNode(xyz); // // Keep track of border link assignments // usedBorderLinks.push_back(std::make_pair(i, j)); } else { if (nearestNode >= 0) { std::cout << "Border link with closest node ignored: " << i << " " << j << std::endl; } else { std::cout << "Border link without closest node ignored: " << i << " " << j << std::endl; } } } } const int numNodes = targetDeformationSphere->getNumberOfNodes(); if (numNodes == originalNumberOfNodes) { throw BrainModelAlgorithmException("Tessellating in border nodes failed."); } // // Make sure all nodes are on the sphere // targetDeformationSphere->convertToSphereWithRadius(deformationSphereRadius); // // Update the surface's normals and update node attributes for changes in nodes. // targetDeformationSphere->computeNormals(); targetDeformationBrainSet->resetNodeAttributes(); QString targetNamePrefix("target_withLandmarks.LVD"); // // Create the spec file name // QString specFileName = targetNamePrefix + SpecFile::getSpecFileExtension(); targetDeformationBrainSet->setSpecFileName(specFileName); intermediateFiles.push_back(specFileName); targetDeformationBrainSet->removeCoordAndTopoFromSpecFile(); // // Setup the paint file that shows the landmark nodes // PaintFile* pf = targetDeformationBrainSet->getPaintFile(); pf->setNumberOfNodesAndColumns(numNodes, 1); pf->setColumnName(0, "Landmarks"); const int nonLandmarkPaintIndex = pf->addPaintName("???"); const int landmarkPaintIndex = pf->addPaintName("Landmark"); for (int i = 0; i < numNodes; i++) { if (i < originalNumberOfNodes) { pf->setPaint(i, 0, nonLandmarkPaintIndex); } else { pf->setPaint(i, 0, landmarkPaintIndex); } } QString paintFileName(targetNamePrefix + SpecFile::getPaintFileExtension()); targetDeformationBrainSet->writePaintFile(paintFileName); intermediateFiles.push_back(paintFileName); // // Setup the node color file // AreaColorFile* cf = targetDeformationBrainSet->getAreaColorFile(); cf->addColor("Landmark", 255, 0, 0, 2, 1); cf->addColor("???", 170, 170, 170, 2, 1); QString nodeColorFileName(targetNamePrefix + SpecFile::getAreaColorFileExtension()); targetDeformationBrainSet->writeAreaColorFile(nodeColorFileName); intermediateFiles.push_back(nodeColorFileName); // // Write the topology file // QString topoFileName(targetNamePrefix + SpecFile::getTopoFileExtension()); targetDeformationBrainSet->writeTopologyFile(topoFileName, TopologyFile::TOPOLOGY_TYPE_CLOSED, tf); intermediateFiles.push_back(topoFileName); // // Set node coloring overlay to paint // BrainModelSurfaceNodeColoring* bsnc = targetDeformationBrainSet->getNodeColoring(); targetDeformationBrainSet->getPrimarySurfaceOverlay()->setOverlay(-1, BrainModelSurfaceOverlay::OVERLAY_PAINT); bsnc->assignColors(); // // Update the displayed surface // targetDeformationSphere->orientTilesConsistently(); targetDeformationSphere->computeNormals(); this->updateViewingTransformation(targetDeformationBrainSet); targetDeformationSphere->updateForDefaultScaling(); targetDeformationBrainSet->drawBrainModel(targetDeformationSphere); // // Write the sphere with target landmarks // QString coordFileName(targetNamePrefix + SpecFile::getCoordinateFileExtension()); targetDeformationBrainSet->writeCoordinateFile(coordFileName, BrainModelSurface::SURFACE_TYPE_SPHERICAL, targetDeformationSphere->getCoordinateFile()); intermediateFiles.push_back(coordFileName); } /** * Tessellate the source border into the target deformation sphere */ void BrainModelSurfaceDeformationSphericalVector::tessellateSourceBordersIntoDeformationSphere() throw (BrainModelAlgorithmException) { int numNodeCrossovers = 0; int numTileCrossovers = 0; sourceDeformationSphere->crossoverCheck(numTileCrossovers, numNodeCrossovers, BrainModelSurface::SURFACE_TYPE_SPHERICAL); if (numNodeCrossovers > 0) { std::cout << "WARNING: Source deformation sphere contains crossovers " "PRIOR to insertion of landmarks." << std::endl; } // // Create the surface shape file containing the border variances // Use target BrainSet for number of nodes since it has landmarks // inserted so that number of nodes is correct. // borderVarianceValuesShapeFile.setNumberOfNodesAndColumns(targetBrainSet->getNumberOfNodes(), 1); borderVarianceValuesShapeFile.setColumnName(0, "Border Variances"); // // Create a Point Projector with nodes to be added for the deformation sphere. // BrainModelSurfacePointProjector bspp(sourceDeformationSphere, BrainModelSurfacePointProjector::SURFACE_TYPE_HINT_SPHERE, true); TopologyFile* tf = sourceDeformationSphere->getTopologyFile(); // // Project each border link into the deformation sphere // const int numBorderLinks = static_cast(usedBorderLinks.size()); for (int i = 0; i < numBorderLinks; i++) { std::pair borderLinkNums = usedBorderLinks[i]; const int borderNumber = borderLinkNums.first; const int linkNumber = borderLinkNums.second; const Border* targetBorder = targetBorderFile->getBorder(borderNumber); const QString borderName = targetBorder->getName(); const Border* sourceBorder = sourceBorderFile->getBorderByName(borderName); if (sourceBorder == NULL) { throw BrainModelAlgorithmException( "Unable to find source border named \"" + borderName + "\""); } bool projectedFlag = false; // // Source border coordinate // float xyz[3]; sourceBorder->getLinkXYZ(linkNumber, xyz); // // Projecting may fail in some cases so perturb when there is a failure // const int iTestMaximum = 10; for (int iTest = 0; iTest < iTestMaximum; iTest++) { // // Project target node onto source deformed surface // int nearestNode = -1; int tileNodes[3]; float tileAreas[3]; // // perturb if problems projecting // if (iTest > 0) { std::cout << "Moving source border point due to projection failure: " << borderName.toAscii().constData() << " link " << linkNumber << " (" << xyz[0] << "," << xyz[1] << "," << xyz[2] << ")" << std::endl; xyz[0] += 0.001; xyz[1] += 0.001; xyz[2] += 0.001; } const int tile = bspp.projectBarycentric(xyz, nearestNode, tileNodes, tileAreas, true); const int newNodeNumber = sourceDeformationSphere->getNumberOfNodes(); // // Unproject using the deformed source coordinate file // if (tile >= 0) { // // Get the tile // int v1, v2, v3; tf->getTile(tile, v1, v2, v3); // // Create two new tiles and replace the file node is within // const int tn1[3] = { v1, v2, newNodeNumber }; const int tn2[3] = { v2, v3, newNodeNumber }; const int tn3[3] = { v3, v1, newNodeNumber }; // // Replace the original tile and create two new ones // tf->setTile(tile, tn1); tf->addTile(tn2); tf->addTile(tn3); // // Add the node to the surface // sourceDeformationSphere->addNode(xyz); // // Update the border variance shape file // int nodeNum = sourceDeformationSphere->getNumberOfNodes() - 1; this->borderVarianceValuesShapeFile.setValue(nodeNum, 0, targetBorder->getVariance()); if (DebugControl::getDebugOn()) { std::cout << targetBorder->getName().toAscii().constData() << " variance: " << targetBorder->getVariance() << std::endl; } projectedFlag = true; // // Get out of loop // iTest = iTestMaximum + 1; } } if (projectedFlag == false) { throw BrainModelAlgorithmException( "Unable to tessellate border " + borderName + " link " + linkNumber + " into source surface."); } } // // Make sure all nodes are on the sphere // sourceDeformationSphere->convertToSphereWithRadius(deformationSphereRadius); // // Update the surface's normals and update node attributes for changes in nodes. // sourceDeformationSphere->orientNormalsOut(); sourceDeformationSphere->computeNormals(); brainSet->resetNodeAttributes(); // // Smooth a tiny bit as some landmark nodes may be essentially on an edge // sourceDeformationSphere->arealSmoothing(0.5, 1, 0); sourceDeformationSphere->convertToSphereWithRadius(deformationSphereRadius); sourceDeformationSphere->crossoverCheck(numTileCrossovers, numNodeCrossovers, BrainModelSurface::SURFACE_TYPE_SPHERICAL); if (numNodeCrossovers > 0) { std::cout << "WARNING: Source deformation sphere contains crossovers " "AFTER insertion of landmarks." << std::endl; } QString sourceNamePrefix("source_withLandmarks.LVD"); // // Create the spec file name // QString specFileName = sourceNamePrefix + SpecFile::getSpecFileExtension(); brainSet->setSpecFileName(specFileName); intermediateFiles.push_back(specFileName); brainSet->removeCoordAndTopoFromSpecFile(); // // Setup the paint file that shows the landmark nodes // int numNodes = brainSet->getNumberOfNodes(); PaintFile* pf = brainSet->getPaintFile(); pf->setNumberOfNodesAndColumns(numNodes, 1); pf->setColumnName(0, "Landmarks"); const int nonLandmarkPaintIndex = pf->addPaintName("???"); const int landmarkPaintIndex = pf->addPaintName("Landmark"); for (int i = 0; i < numNodes; i++) { if (i < originalNumberOfNodes) { pf->setPaint(i, 0, nonLandmarkPaintIndex); } else { pf->setPaint(i, 0, landmarkPaintIndex); } } QString paintFileName(sourceNamePrefix + SpecFile::getPaintFileExtension()); brainSet->writePaintFile(paintFileName); intermediateFiles.push_back(paintFileName); // // Setup the node color file // AreaColorFile* cf = brainSet->getAreaColorFile(); cf->addColor("Landmark", 255, 0, 0, 2, 1); cf->addColor("???", 170, 170, 170, 2, 1); QString nodeColorFileName(sourceNamePrefix + SpecFile::getAreaColorFileExtension()); brainSet->writeAreaColorFile(nodeColorFileName); intermediateFiles.push_back(nodeColorFileName); // // Write the topology file // QString topoFileName(sourceNamePrefix + SpecFile::getTopoFileExtension()); brainSet->writeTopologyFile(topoFileName, TopologyFile::TOPOLOGY_TYPE_CLOSED, tf); intermediateFiles.push_back(topoFileName); // // Write the sphere with target landmarks // QString coordFileName(sourceNamePrefix + SpecFile::getCoordinateFileExtension()); brainSet->writeCoordinateFile(coordFileName, BrainModelSurface::SURFACE_TYPE_SPHERICAL, sourceDeformationSphere->getCoordinateFile()); intermediateFiles.push_back(coordFileName); // // Update the displayed surface // sourceDeformationSphere->orientTilesConsistently(); sourceDeformationSphere->computeNormals(); this->updateViewingTransformation(brainSet); sourceDeformationSphere->updateForDefaultScaling(); brainSet->drawBrainModel(sourceDeformationSphere); sourceDeformationSphere = new BrainModelSurface(*sourceDeformationSphere); brainSet->addBrainModel(sourceDeformationSphere); // // Save the border variance shape file // const QString shapeFileName("source_withLandmarksBorderVariance" + SpecFile::getSurfaceShapeFileExtension()); borderVarianceValuesShapeFile.writeFile(shapeFileName); intermediateFiles.push_back(shapeFileName); brainSet->addToSpecFile(SpecFile::getSurfaceShapeFileTag(), shapeFileName); } /** * move the landmark nodes to the average of their neighboring nodes. */ void BrainModelSurfaceDeformationSphericalVector::moveLandmarksToAverageOfNeighbors(BrainModelSurface* bms) { const TopologyHelper* th = bms->getTopologyFile()->getTopologyHelper(false, true, false); CoordinateFile* cf = bms->getCoordinateFile(); int numNodes = bms->getNumberOfNodes(); for (int i = originalNumberOfNodes; i < numNodes; i++) { int numNeighbors = 0; const int* neighbors = th->getNodeNeighbors(i, numNeighbors); float sumXYZ[3] = { 0.0, 0.0, 0.0 }; for (int j = 0; j < numNeighbors; j++) { const float* xyz = cf->getCoordinate(neighbors[j]); sumXYZ[0] += xyz[0]; sumXYZ[1] += xyz[1]; sumXYZ[2] += xyz[2]; } const float avgXYZ[3] = { sumXYZ[0] / numNeighbors, sumXYZ[1] / numNeighbors, sumXYZ[2] / numNeighbors }; cf->setCoordinate(i, avgXYZ); } bms->convertToSphereWithRadius(deformationSphereRadius); } /** * create the surface shape file containing the XYZ differences of the * nodes in the target and source surfaces. Note that only the landmark * nodes have their differences set; the original nodes have a difference * of zero. */ SurfaceShapeFile* BrainModelSurfaceDeformationSphericalVector::createDifferenceShapeFile(int iterations) { int numNodes = targetDeformationSphere->getNumberOfNodes(); SurfaceShapeFile* ssf = brainSet->getSurfaceShapeFile(); ssf->clear(); ssf->setNumberOfNodesAndColumns(numNodes, 6); ssf->setColumnName(0, "dX"); ssf->setColumnName(1, "dY"); ssf->setColumnName(2, "dZ"); ssf->setColumnName(3, "dX Smoothed"); ssf->setColumnName(4, "dY Smoothed"); ssf->setColumnName(5, "dZ Smoothed"); const CoordinateFile* sourceCoords = sourceDeformationSphere->getCoordinateFile(); const CoordinateFile* targetCoords = targetDeformationSphere->getCoordinateFile(); for (int i = originalNumberOfNodes; i < numNodes; i++) { const float* sxyz = sourceCoords->getCoordinate(i); const float* txyz = targetCoords->getCoordinate(i); float dxyz[3] = { txyz[0] - sxyz[0], txyz[1] - sxyz[1], txyz[2] - sxyz[2] }; // // Modify displacement using border variance // const float borderVariance = this->borderVarianceValuesShapeFile.getValue(i, 0); if (borderVariance != 0.0) { dxyz[0] *= borderVariance; dxyz[1] *= borderVariance; dxyz[2] *= borderVariance; } ssf->setValue(i, 0, dxyz[0]); ssf->setValue(i, 1, dxyz[1]); ssf->setValue(i, 2, dxyz[2]); // // If no smoothing iterations, set smoothed values to actual displacement // if (iterations <= 0) { ssf->setValue(i, 3, dxyz[0]); ssf->setValue(i, 4, dxyz[1]); ssf->setValue(i, 5, dxyz[2]); } } // // Smooth the columns // if (iterations > 0) { float strength = 0.5; for (int j = 0; j < 3; j++) { BrainModelSurfaceMetricSmoothing bmsms(brainSet, sourceDeformationSphere, sourceDeformationSphere, ssf, BrainModelSurfaceMetricSmoothing::SMOOTH_ALGORITHM_AVERAGE_NEIGHBORS, j, j + 3, (ssf->getColumnName(j) + " Smoothed"), strength, iterations, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.0); bmsms.execute(); } } return ssf; } /** * Perform landmark neighbor constrained smoothing on the sphere with source landmarks. */ void BrainModelSurfaceDeformationSphericalVector::landmarkNeighborConstrainedSmoothSource(const int cycleIndex) { // // Get smoothing parameters for this cycle // float strength; int numCycles, numIterations, neighborIterations, numFinalIterations; deformationMapFile->getSmoothingParameters(0, cycleIndex, strength, numCycles, numIterations, neighborIterations, numFinalIterations); if (numCycles <= 0) { return; } // // perform number of smoothing cycles // for (int i = 0; i < numCycles; i++) { // // Perform the landmark constrained smoothing // updateViewingTransformation(sourceDeformationSphere); sourceDeformationSphere->landmarkNeighborConstrainedSmoothing(strength, numIterations, landmarkNodeFlags, neighborIterations, 0); // // push non-landmark nodes back onto the sphere // sourceDeformationSphere->convertToSphereWithRadius(deformationSphereRadius, 0, originalNumberOfNodes); } // // Perform final smoothing // sourceDeformationSphere->arealSmoothing(strength, numFinalIterations, 0); // // push all nodes back onto the sphere // sourceDeformationSphere->convertToSphereWithRadius(deformationSphereRadius); sourceDeformationSphere->updateForDefaultScaling(); updateViewingTransformation(sourceDeformationSphere); } /** * Perform landmark constrained morphing on the sphere with source landmarks */ void BrainModelSurfaceDeformationSphericalVector::landmarkMorphContrainedSource( BrainModelSurface* referenceDeformationSphere, const int cycleIndex) throw (BrainModelAlgorithmException) { if (DebugControl::getDebugOn()) { std::cout << "Landmark Constrained Morphing Cycle " << (cycleIndex + 1) << std::endl; std::cout << " REF: " << referenceDeformationSphere->getCoordinateFile()->getFileNameNoPath().toAscii().constData() << std::endl; } // // Get smoothing parameters for this cycle (just need strength) // float strength; int numCycles, numIterations, neighborIterations, numFinalIterations; deformationMapFile->getSmoothingParameters(0, cycleIndex, strength, numCycles, numIterations, neighborIterations, numFinalIterations); // // Get the morphing paramters for this cycle // float linearForce, angularForce, stepSize, landmarkStepSize; int numMorphCycles, iterations, smoothIterations; deformationMapFile->getMorphingParameters(0, cycleIndex, numMorphCycles, linearForce, angularForce, stepSize, landmarkStepSize, iterations, smoothIterations); // // If morphing should be performed // if (numMorphCycles > 0) { // // NON-landmark nodes are morphed // const int numNodes = sourceDeformationSphere->getNumberOfNodes(); std::vector morphNodeFlag(numNodes); for (int i = 0; i < numNodes; i++) { morphNodeFlag[i] = ( ! landmarkNodeFlags[i]); } // // Get fiducial sphere ratio settings // bool useFiducialSphereRatios = false; float fiducialSphereRatioStrength = 0.5; deformationMapFile->getSphereFiducialRatio(useFiducialSphereRatios, fiducialSphereRatioStrength); std::vector fiducialSphereRatios; if (useFiducialSphereRatios) { // // Use fiducial/sphere distortion except on first cycle // if (cycleIndex > 0) { const int numNodes = fiducialSphereDistortion.getNumberOfNodes(); fiducialSphereRatios.resize(numNodes); for (int i = 0; i < numNodes; i++) { fiducialSphereRatios[i] = fiducialSphereDistortion.getValue(i, 2); } } } // // Morph for the specified number of cycles // for (int morphCycle = 0; morphCycle < numMorphCycles; morphCycle++) { // // Create the morphing object and set parameters // BrainModelSurfaceMorphing bmsm(brainSet, referenceDeformationSphere, sourceDeformationSphere, BrainModelSurfaceMorphing::MORPHING_SURFACE_SPHERICAL); bmsm.setMorphingParameters(iterations, linearForce, angularForce, stepSize); bmsm.setNodesThatShouldBeMorphed(morphNodeFlag, landmarkStepSize); if (fiducialSphereRatios.size() > 0) { if (useFiducialSphereRatios) { bmsm.setFiducialSphereDistortionCorrections(fiducialSphereRatios, fiducialSphereRatioStrength); } } // // execute the morphing // bmsm.execute(); // // Perform a little bit of normal smoothing // sourceDeformationSphere->arealSmoothing(strength, smoothIterations, 0); // // Move landmarks to average of neighbors 5/20/09 // this->moveLandmarksToAverageOfNeighbors(sourceDeformationSphere); // // Push nodes back to sphere and draw // sourceDeformationSphere->convertToSphereWithRadius(deformationSphereRadius); // // Draw the surface // sourceDeformationSphere->orientTilesConsistently(); sourceDeformationSphere->computeNormals(); sourceDeformationSphere->updateForDefaultScaling(); updateViewingTransformation(brainSet); brainSet->drawBrainModel(sourceDeformationSphere); } // // Save the surface // //QString coordFileName(debugSourceFileNamePrefix); //coordFileName.append("_withLandmarks_morphed"); //coordFileName.append(SpecFile::getCoordinateFileExtension()); //brainSet->writeCoordinateFile(coordFileName, BrainModelSurface::SURFACE_TYPE_SPHERICAL, // sourceDeformationSphere->getCoordinateFile()); //intermediateFiles.push_back(coordFileName); // // Draw the surface // sourceDeformationSphere->orientTilesConsistently(); sourceDeformationSphere->computeNormals(); sourceDeformationSphere->updateForDefaultScaling(); this->updateViewingTransformation(brainSet); brainSet->drawBrainModel(sourceDeformationSphere); } } /** * Deform the source sphere using the source and target deformation spheres */ void BrainModelSurfaceDeformationSphericalVector::createDeformedCoordinateFile( BrainModelSurface* originalSourceDeformationSphere, BrainModelSurface* registeredDeformationSourceSphere, const int cycleNumber) { try { bool lastCycleFlag = (cycleNumber >= this->deformationMapFile->getSphericalNumberOfCycles(0)); if (lastCycleFlag) { // // Check for crossovers in source deformation sphere // int sourceTileCrossoversCount = 0; int sourceNodeCrossoversCount = 0; originalSourceDeformationSphere->crossoverCheck(sourceTileCrossoversCount, sourceNodeCrossoversCount, BrainModelSurface::SURFACE_TYPE_SPHERICAL); if (sourceNodeCrossoversCount > 0) { std::cout << "WARNING: Original source deformation sphere has " << sourceNodeCrossoversCount << " crossovers when creating deformed coordinate file." << std::endl; } // // Check for crossovers in source in target deformation // int targetTileCrossoversCount = 0; int targetNodeCrossoversCount = 0; registeredDeformationSourceSphere->crossoverCheck(targetTileCrossoversCount, targetNodeCrossoversCount, BrainModelSurface::SURFACE_TYPE_SPHERICAL); if (targetNodeCrossoversCount > 0) { std::cout << "WARNING: Final deformation sphere has " << targetNodeCrossoversCount << " crossovers when creating deformed coordinate file." << std::endl; } // // Check for crossovers in user's source surface // int userTileCrossoversCount = 0; int userNodeCrossoversCount = 0; sourceSurface->crossoverCheck(userTileCrossoversCount, userNodeCrossoversCount, BrainModelSurface::SURFACE_TYPE_SPHERICAL); if (userNodeCrossoversCount > 0) { std::cout << "WARNING: User's individual sphere has " << userNodeCrossoversCount << " crossovers when creating deformed coordinate file." << std::endl; } } // // Copy the user's input surface to a new deformed surface // deformedSourceSurface = new BrainModelSurface(*sourceSurface); sourceBrainSet->addBrainModel(deformedSourceSurface); updateViewingTransformation(sourceBrainSet); // // Make sure source surface is same radius as deformation sphere // sourceSurface->convertToSphereWithRadius(deformationSphereRadius); // // Get the coordinate files for the user's surface and its // new deformed surface. // CoordinateFile* sourceCoords = sourceSurface->getCoordinateFile(); CoordinateFile* deformedSourceCoords = deformedSourceSurface->getCoordinateFile(); const int numCoords = sourceCoords->getNumberOfCoordinates(); // // See if X coordinate will need to be flipped (first cycle only !!!) // bool diffHemFlag = false; if (cycleNumber == 1) { diffHemFlag = (sourceBrainSet->getStructure() != targetBrainSet->getStructure()); if (diffHemFlag) { std::cout << "Different Hemispheres" << std::endl; } } // // Create a Point Projector for the source deformation sphere // BrainModelSurfacePointProjector bspp(originalSourceDeformationSphere, //targetDeformationSphere); BrainModelSurfacePointProjector::SURFACE_TYPE_HINT_SPHERE, false); // // Coord file of registered deformation source sphere // const CoordinateFile* deformSphereRegisteredCoords = registeredDeformationSourceSphere->getCoordinateFile(); // // Project each point in the users input surface to its deformed surface // for (int i = 0; i < numCoords; i++) { float xyz[3]; sourceCoords->getCoordinate(i, xyz); if (diffHemFlag) { xyz[0] = -xyz[0]; sourceCoords->setCoordinate(i, xyz); // needed for projecting borders } // // Project source node onto subsampled surface // int nearestNode = -1; int tileNodes[3]; float tileAreas[3]; const int tile = bspp.projectBarycentric(xyz, nearestNode, tileNodes, tileAreas, true); // // Unproject using the deformation sphere coordinate file // if (tile >= 0) { BrainModelSurfacePointProjector::unprojectPoint(tileNodes, tileAreas, deformSphereRegisteredCoords, xyz); } else if (nearestNode >= 0) { // JWH 08/08/03 2:15pm deformedSourceCoords->getCoordinate(nearestNode, xyz); //deformationMorphedSphereCoords->getCoordinate(nearestNode, xyz); deformSphereRegisteredCoords->getCoordinate(nearestNode, xyz); } deformedSourceCoords->setCoordinate(i, xyz); } deformedSourceSurface->orientTilesConsistently(); deformedSourceSurface->computeNormals(); if (lastCycleFlag) { // // Check for crossovers in user's source surface // int userDeformedTileCrossoversCount = 0; int userDeformedNodeCrossoversCount = 0; deformedSourceSurface->crossoverCheck(userDeformedTileCrossoversCount, userDeformedNodeCrossoversCount, BrainModelSurface::SURFACE_TYPE_SPHERICAL); if (userDeformedNodeCrossoversCount > 0) { std::cout << "WARNING: User's DEFORMED individual sphere has " << userDeformedNodeCrossoversCount << " after its creation." << std::endl; } } // // Write the source deformed coordinates // QDir::setCurrent(sourceDirectory); QString defCoordName(deformationMapFile->getDeformedFileNamePrefix()); QString dn(FileUtilities::dirname(sourceCoords->getFileName())); if ((dn != ".") && (dn.length() > 0)) { QString fn(FileUtilities::basename(sourceCoords->getFileName())); QString s(dn); s += QDir::separator(); s += deformationMapFile->getDeformedFileNamePrefix(); s += fn; defCoordName = s; } else { defCoordName.append(sourceCoords->getFileName()); } deformationMapFile->setSourceDeformedSphericalCoordFileName(defCoordName); deformedSourceCoords->appendToFileComment("\nDeformation Map File: "); deformedSourceCoords->appendToFileComment( FileUtilities::basename(sourceToTargetDeformationMapFileName)); if (cycleNumber == deformationMapFile->getSphericalNumberOfCycles(0)) { //deformedSourceCoords->writeFile(defCoordName); } else { QString cycleName = deformationMapFile->getDeformedFileNamePrefix() + "sphere_cycle_" + QString::number(cycleNumber) + SpecFile::getCoordinateFileExtension(); defCoordName = cycleName; } deformedSourceCoords->writeFile(defCoordName); QString descriptionMessage("Projecting " + sourceCoords->getFileName() + " to " + originalSourceDeformationSphere->getCoordinateFile()->getFileName() + " and unprojecting to " + registeredDeformationSourceSphere->getCoordinateFile()->getFileName() + " creating the file " + defCoordName); std::cout << descriptionMessage.toAscii().constData() << std::endl; QDir::setCurrent(originalDirectory); } catch (FileException& e) { throw BrainModelAlgorithmException(e.whatQString()); } } /** * write a border file containing the deformed landmarks. */ void BrainModelSurfaceDeformationSphericalVector::writeSourceBorderLandmarkFile(BrainModelSurface* surface, const int cycleNumber) { const CoordinateFile* cf = surface->getCoordinateFile(); const int numNodes = cf->getNumberOfCoordinates(); BorderFile bf; Border border; int lastBorderNumber = -1; for (int i = this->originalNumberOfNodes; i < numNodes; i++) { int usedIndex = i - this->originalNumberOfNodes; std::pair borderInfo = usedBorderLinks[usedIndex]; int borderNumber = borderInfo.first; //int linkNumber = borderInfo.second; if (borderNumber != lastBorderNumber) { if (border.getNumberOfLinks() > 0) { bf.addBorder(border); border.clearLinks(); } border.setName(targetBorderFile->getBorder(borderNumber)->getName()); lastBorderNumber = borderNumber; } border.addBorderLink(cf->getCoordinate(i)); } if (border.getNumberOfLinks() > 0) { bf.addBorder(border); } bf.setHeaderTag(AbstractFile::headerTagConfigurationID, BrainModelSurface::getSurfaceConfigurationIDFromType(BrainModelSurface::SURFACE_TYPE_SPHERICAL)); QString borderFileName("source_after_resample_cycle_" + QString::number(cycleNumber) + SpecFile::getBorderFileExtension()); bf.writeFile(borderFileName); intermediateFiles.push_back(borderFileName); brainSet->addToSpecFile(SpecFile::getSphericalBorderFileTag(), borderFileName); } /** * write coords without the landmarks. */ void BrainModelSurfaceDeformationSphericalVector::writeCoordinatesWithoutLandmarks(BrainModelSurface* surface, const int cycleNumber) { CoordinateFile cf; cf.setNumberOfCoordinates(this->originalNumberOfNodes); for (int i = 0; i < this->originalNumberOfNodes; i++) { cf.setCoordinate(i, surface->getCoordinateFile()->getCoordinate(i)); } QString coordFileName("source_withoutLandmarks.LVD.cycle_" + QString::number(cycleNumber) + SpecFile::getCoordinateFileExtension()); cf.writeFile(coordFileName); intermediateFiles.push_back(coordFileName); } /** * Execute the deformation. */ void BrainModelSurfaceDeformationSphericalVector::executeDeformation() throw (BrainModelAlgorithmException) { // // Validate vector smoothing iterations // QString vectorIterationsErrorMessage = ""; for (int ci = 0; ci < deformationMapFile->getSphericalNumberOfCycles(0); ci++) { // // Get vector-landmark parameters // int iterations = 0; float displacementFactor = 1.0; this->deformationMapFile->getLandmarkVectorParameters(0, ci, iterations, displacementFactor); if (iterations <= 0) { if (vectorIterationsErrorMessage.isEmpty()) { vectorIterationsErrorMessage = "Each cycle must have at least one iteration of vector smoothing.\n" "These cycles have zero iterations:"; } vectorIterationsErrorMessage += (" " + QString::number(ci + 1)); } } if (vectorIterationsErrorMessage.isEmpty() == false) { throw BrainModelAlgorithmException(vectorIterationsErrorMessage); } // // Get radius of target sphere // deformationSphereRadius = targetSurface->getSphericalSurfaceRadius(); // // Make source surface the same radius as the target surface // sourceSurface->convertToSphereWithRadius(deformationSphereRadius); // // control of sphere fiducial distortion // bool useFiducialSphereRatios = false; float fiducialSphereRatioStrength = 0.5; deformationMapFile->getSphereFiducialRatio(useFiducialSphereRatios, fiducialSphereRatioStrength); // // Determing the ratio of the source fiducial and spherical tile areas // if (useFiducialSphereRatios) { if (DebugControl::getDebugOn()) { std::cout << " " << std::endl; } updateProgressDialog("Determining Spherical Distortion"); determineSphericalDistortion(sourceFiducialSurface, sourceSurface, sourceTileDistortion); // // Determing the ratio of the target fiducial and spherical tile areas // determineSphericalDistortion(targetFiducialSurface, targetSurface, targetTileDistortion); } // // Resample the border files // if (DebugControl::getDebugOn()) { std::cout << "Resampling borders." << std::endl; } updateProgressDialog("Resampling borders."); resampleBorderFiles(-1, -1, deformationSphereRadius); // // Create the target brain set // targetDeformationBrainSet = new BrainSet(); // // Load the regularly tessellated sphere and make it same radius as target surface // QString currentDirectory(QDir::currentPath()); targetDeformationSphere = getRegularSphere(targetDeformationBrainSet, deformationSphereRadius); targetDeformationSphere->orientTilesConsistently(); targetDeformationSphere->computeNormals(); targetDeformationSphere->updateForDefaultScaling(); this->updateViewingTransformation(targetDeformationSphere); targetDeformationBrainSet->drawBrainModel(targetDeformationSphere); QDir::setCurrent(currentDirectory); // // Save the number of nodes before tessellating in the borders // originalNumberOfNodes = targetDeformationSphere->getNumberOfNodes(); // // tessellate the target borders into the target deformation sphere // if (DebugControl::getDebugOn()) { std::cout << "Tessellating borders into target." << std::endl; } updateProgressDialog("Tessellating Borders into Target"); tessellateTargetBordersIntoDeformationSphere(); // // Load the regularly tessellated sphere and make it same radius as target surface // currentDirectory = QDir::currentPath(); sourceDeformationSphere = getRegularSphere(brainSet, deformationSphereRadius); sourceDeformationSphere->orientTilesConsistently(); sourceDeformationSphere->computeNormals(); sourceDeformationSphere->updateForDefaultScaling(); this->updateViewingTransformation(sourceDeformationSphere); brainSet->drawBrainModel(sourceDeformationSphere); QDir::setCurrent(currentDirectory); // // tessellate the source borders into the source deformation sphere // if (DebugControl::getDebugOn()) { std::cout << "Tessellating borders into source." << std::endl; } updateProgressDialog("Tessellating Borders into Source"); tessellateSourceBordersIntoDeformationSphere(); // // Place copy of target into the brain set // QString targetCoordName = targetDeformationSphere->getCoordinateFile()->getFileName(); brainSet->readCoordinateFile(targetCoordName, BrainModelSurface::SURFACE_TYPE_SPHERICAL, false, true, true); brainSet->getBrainModelSurface(brainSet->getNumberOfBrainModels() - 1)->updateForDefaultScaling(); // // Mark the landmark nodes // //const int numNodes = targetDeformationSphere->getNumberOfNodes(); int numNodes = sourceDeformationSphere->getNumberOfNodes(); landmarkNodeFlags.resize(numNodes); for (int i = 0; i < numNodes; i++) { landmarkNodeFlags[i] = (i >= originalNumberOfNodes); } // // Create the source reference surface // referenceSourceDeformationSphere = new BrainModelSurface(*sourceDeformationSphere); moveLandmarksToAverageOfNeighbors(referenceSourceDeformationSphere); referenceSourceDeformationSphere->computeNormals(); referenceSourceDeformationSphere->updateForDefaultScaling(); brainSet->addBrainModel(referenceSourceDeformationSphere); this->updateViewingTransformation(referenceSourceDeformationSphere); brainSet->writeCoordinateFile("source_withLandmarks.LVD.REF.coord", BrainModelSurface::SURFACE_TYPE_SPHERICAL, referenceSourceDeformationSphere->getCoordinateFile(), true); intermediateFiles.push_back("source_withLandmarks.LVD.REF.coord"); // // Copy of source deformation sphere // BrainModelSurface originalSourceDeformationSphere(*referenceSourceDeformationSphere); originalSourceDeformationSphere.getCoordinateFile()->setFileName( "CopyOf_" + referenceSourceDeformationSphere->getCoordinateFile()->getFileName()); // // Perform the requested number of cycles // for (int cycleIndex = 0; cycleIndex < deformationMapFile->getSphericalNumberOfCycles(0); cycleIndex++) { const int cycleNumber = cycleIndex + 1; const QString cycleString("Cycle " + QString::number(cycleNumber) + " "); // // Get vector-landmark parameters // int iterations = 0; float displacementFactor = 1.0; this->deformationMapFile->getLandmarkVectorParameters(0, cycleIndex, iterations, displacementFactor); // // Create the surface shape coordinate differences // if (DebugControl::getDebugOn()) { std::cout << "Cycle " << cycleNumber << " smoothing landmarks in source." << std::endl; } updateProgressDialog(cycleString + "Smoothing Landmarks in Source"); SurfaceShapeFile* shapeDiffFile = this->createDifferenceShapeFile(iterations); // // Save the shape file // const QString shapeFileName("source_withLandmarks.LVD.cycle_" + QString::number(cycleNumber) + SpecFile::getSurfaceShapeFileExtension()); brainSet->writeSurfaceShapeFile(shapeFileName); intermediateFiles.push_back(shapeFileName); // // Displace sphere nodes by smoothed shape data // CoordinateFile* sourceCoords = sourceDeformationSphere->getCoordinateFile(); for (int j = 0; j < numNodes; j++) { float* xyz = sourceCoords->getCoordinate(j); xyz[0] += (shapeDiffFile->getValue(j, 3) * displacementFactor); xyz[1] += (shapeDiffFile->getValue(j, 4) * displacementFactor); xyz[2] += (shapeDiffFile->getValue(j, 5) * displacementFactor); sourceCoords->setCoordinate(j, xyz); } moveLandmarksToAverageOfNeighbors(sourceDeformationSphere); sourceDeformationSphere->convertToSphereWithRadius(this->deformationSphereRadius); const QString smoothedCoordName("source_withLandmarksDisplaced.LVD.cycle_" + QString::number(cycleNumber) + SpecFile::getCoordinateFileExtension()); brainSet->writeCoordinateFile(smoothedCoordName, BrainModelSurface::SURFACE_TYPE_SPHERICAL, sourceDeformationSphere->getCoordinateFile(), true); intermediateFiles.push_back(smoothedCoordName); updateViewingTransformation(brainSet); sourceDeformationSphere->orientTilesConsistently(); sourceDeformationSphere->computeNormals(); sourceDeformationSphere->updateForDefaultScaling(); this->updateViewingTransformation(sourceDeformationSphere); brainSet->drawBrainModel(sourceDeformationSphere); sourceDeformationSphere = new BrainModelSurface(*sourceDeformationSphere); brainSet->addBrainModel(sourceDeformationSphere); this->updateViewingTransformation(sourceDeformationSphere); // // Perform landmark neighbor constrained smoothing on the sphere with source landmarks // if (DebugControl::getDebugOn()) { std::cout << "Cycle " << cycleNumber << " landmark neighbor constrained smoothing." << std::endl; } updateProgressDialog(cycleString + "Landmark Neighbor Constrained Smoothing of Source"); landmarkNeighborConstrainedSmoothSource(cycleIndex); const QString smoothedLandmarkCoordName("source_withLandmarksSmoothed.LVD.cycle_" + QString::number(cycleNumber) + SpecFile::getCoordinateFileExtension()); brainSet->writeCoordinateFile(smoothedLandmarkCoordName, BrainModelSurface::SURFACE_TYPE_SPHERICAL, sourceDeformationSphere->getCoordinateFile(), true); intermediateFiles.push_back(smoothedLandmarkCoordName); updateViewingTransformation(brainSet); sourceDeformationSphere->orientTilesConsistently(); sourceDeformationSphere->computeNormals(); sourceDeformationSphere->updateForDefaultScaling(); this->updateViewingTransformation(sourceDeformationSphere); brainSet->drawBrainModel(sourceDeformationSphere); sourceDeformationSphere = new BrainModelSurface(*sourceDeformationSphere); this->updateViewingTransformation(sourceDeformationSphere); brainSet->addBrainModel(sourceDeformationSphere); // // During first cycle, allocate the fiducial sphere distortion surface shape file // if (useFiducialSphereRatios) { fiducialSphereDistortion.setNumberOfNodesAndColumns( targetDeformationSphere->getNumberOfNodes(), 3); fiducialSphereDistortion.setColumnName(0, "Target Distortion"); fiducialSphereDistortion.setColumnName(1, "Source Distortion"); fiducialSphereDistortion.setColumnName(2, "sqrt(Target/Source)"); // // determine the fiducial sphere distortion // determineFiducialSphereDistortion(); // // Update fiducial/sphere with deformed surface // updateSphereFiducialDistortion(cycleIndex, sourceDeformationSphere); } // // Perform landmark neighbor constrained morphing on the sphere with source landmarks // if (DebugControl::getDebugOn()) { std::cout << "Cycle " << cycleNumber << " landmark neighbor constrained morphing." << std::endl; } updateProgressDialog(cycleString + "Landmark Neighbor Constrained Morphing of Source"); landmarkMorphContrainedSource(referenceSourceDeformationSphere, cycleIndex); const QString morphedLandmarkCoordName("source_withLandmarksMorphed.LVD.cycle_" + QString::number(cycleNumber) + SpecFile::getCoordinateFileExtension()); intermediateFiles.push_back(morphedLandmarkCoordName); updateViewingTransformation(brainSet); sourceDeformationSphere->orientTilesConsistently(); sourceDeformationSphere->computeNormals(); sourceDeformationSphere->updateForDefaultScaling(); brainSet->drawBrainModel(sourceDeformationSphere); brainSet->writeCoordinateFile(morphedLandmarkCoordName, BrainModelSurface::SURFACE_TYPE_SPHERICAL, sourceDeformationSphere->getCoordinateFile(), true); // // Use morphed as REFERENCE for next cycle // referenceSourceDeformationSphere = sourceDeformationSphere; // // Check for crossovers // updateProgressDialog(cycleString + "Checking for Crossovers"); int numNodeCrossovers = 0, numTileCrossovers = 0; sourceDeformationSphere->crossoverCheck(numTileCrossovers, numNodeCrossovers, BrainModelSurface::SURFACE_TYPE_SPHERICAL); crossoverCount.push_back(numNodeCrossovers); // // Project the user's sphere from the original source deformation sphere to // the target deformation sphere // updateProgressDialog(cycleString + "Creating Deformed Coordinate File"); createDeformedCoordinateFile(&originalSourceDeformationSphere, sourceDeformationSphere, cycleNumber); // // Create a new sphere for the next cycle // if (cycleNumber < deformationMapFile->getSphericalNumberOfCycles(0)) { sourceDeformationSphere = new BrainModelSurface(*sourceDeformationSphere); this->updateViewingTransformation(sourceDeformationSphere); brainSet->addBrainModel(sourceDeformationSphere); } // // Create border file containing the deformed landmarks // writeSourceBorderLandmarkFile(sourceDeformationSphere, cycleNumber); // // Write deformation sphere without landmarks // writeCoordinatesWithoutLandmarks(sourceDeformationSphere, cycleNumber); } // // If the last cycle alert user if there are crossovers // bool anyCrossoversFlag = false; for (unsigned int i = 0; i < crossoverCount.size(); i++) { if (crossoverCount[i] > 0) { anyCrossoversFlag = true; break; } } if (anyCrossoversFlag > 0) { QWidget* parent = brainSet->getProgressDialogParent(); if (parent != NULL) { QString msg; for (int i = (crossoverCount.size() - 1); i >= 0; i--) { std::ostringstream str; str << "Cycle " << (i + 1) << " had " << crossoverCount[i] << " crossovers.\n"; msg.append(str.str().c_str()); } msg.append("\nContinue Deformation ?"); QApplication::restoreOverrideCursor(); QApplication::beep(); if (QMessageBox::warning(parent, "Crossover Alert", msg, "Yes", "No") != 0) { throw BrainModelAlgorithmException("Deformation terminated by user."); } //will not compile on mac - don't know why QApplication::setOverrideCursor(waitCursor); } } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceDeformationSphericalSlits.h0000664000175000017500000000646511572067322030460 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_DEFORMATION_SPHERICAL_SLITS_H__ #define __BRAIN_MODEL_SURFACE_DEFORMATION_SPHERICAL_SLITS_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelAlgorithm.h" class BorderProjectionFile; class BrainModelSurface; /// class for registering surfaces where the source surface does not have /// cortical areas that exist in the target class BrainModelSurfaceDeformationSphericalSlits : public BrainModelAlgorithm { public: // constructor BrainModelSurfaceDeformationSphericalSlits( BrainSet* brainSetIn, const BrainModelSurface* sphericalSurfaceIn, const BorderProjectionFile* slitLandmarkBorderProjectionFileIn); // destructor ~BrainModelSurfaceDeformationSphericalSlits(); // execute the algorithm void execute() throw (BrainModelAlgorithmException); // get the cut spherical surface that was added to the brain set BrainModelSurface* getCutSphericalSurface() { return cutSphericalSurface; } // get the cut topology file that was added to the brain set TopologyFile* getCutSphericalSurfaceTopologyFile() { return cutSphericalSurfaceTopologyFile; } // the smoothed closed spherical surface BrainModelSurface* getSmoothedClosedSphericalSurface() { return smoothedClosedSphericalSurface; } // get the closed topology file for the smoothed cut spherical surface TopologyFile* getSmoothedClosedSphericalSurfaceTopologyFile() { return smoothedClosedSphericalSurfaceTopologyFile; } // get the prefix for slit borders static QString getSlitLandmarkBorderNamePrefix() { return "LANDMARK.SLIT"; } protected: /// the input spherical surface const BrainModelSurface* inputSphericalSurface; /// the input slit landmark projections const BorderProjectionFile* inputSlitLandmarkBorderProjectionFile; // the cut spherical surface BrainModelSurface* cutSphericalSurface; // the smoothed closed spherical surface BrainModelSurface* smoothedClosedSphericalSurface; // the cut spherical surface topology file TopologyFile* cutSphericalSurfaceTopologyFile; // the closed topology file for the smoothed spherical surface TopologyFile* smoothedClosedSphericalSurfaceTopologyFile; }; #endif // __BRAIN_MODEL_SURFACE_DEFORMATION_SPHERICAL_SLITS_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceDeformationSphericalSlits.cxx0000664000175000017500000002675011572067322031032 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BorderProjectionFile.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceBorderCutter.h" #include "BrainModelSurfaceClusterToBorderConverter.h" #include "BrainModelSurfaceDeformation.h" #include "BrainModelSurfaceDeformDataFile.h" #include "BrainModelSurfaceDeformationMapCreate.h" #include "BrainModelSurfaceDeformationSphericalSlits.h" #include "BrainModelSurfaceROINodeSelection.h" #include "BrainModelSurfaceSphericalTessellator.h" #include "BrainSet.h" #include "BrainSetNodeAttribute.h" #include "DeformationMapFile.h" #include "FileUtilities.h" #include "MathUtilities.h" #include "PaintFile.h" #include "TopologyFile.h" #include "TopologyHelper.h" /** * constructor. */ BrainModelSurfaceDeformationSphericalSlits::BrainModelSurfaceDeformationSphericalSlits( BrainSet* brainSetIn, const BrainModelSurface* sphericalSurfaceIn, const BorderProjectionFile* slitLandmarkBorderProjectionFileIn) : BrainModelAlgorithm(brainSetIn), inputSphericalSurface(sphericalSurfaceIn), inputSlitLandmarkBorderProjectionFile(slitLandmarkBorderProjectionFileIn) { cutSphericalSurface = NULL; cutSphericalSurfaceTopologyFile = NULL; smoothedClosedSphericalSurface = NULL; smoothedClosedSphericalSurfaceTopologyFile = NULL; } /** * destructor. */ BrainModelSurfaceDeformationSphericalSlits::~BrainModelSurfaceDeformationSphericalSlits() { } /** * execute the algorithm. */ void BrainModelSurfaceDeformationSphericalSlits::execute() throw (BrainModelAlgorithmException) { // // Check inputs // if (inputSphericalSurface == NULL) { throw BrainModelAlgorithmException("Input spherical surface is invalid."); } if (inputSlitLandmarkBorderProjectionFile == NULL) { throw BrainModelAlgorithmException("Input border projections are invalid."); } // // Find the border projections that are slits // BorderProjectionFile slitBorderProjections; for (int i = 0; i < inputSlitLandmarkBorderProjectionFile->getNumberOfBorderProjections(); i++) { const BorderProjection* bp = inputSlitLandmarkBorderProjectionFile->getBorderProjection(i); if (bp->getName().startsWith(getSlitLandmarkBorderNamePrefix())) { slitBorderProjections.addBorderProjection(*bp); } } if (slitBorderProjections.getNumberOfBorderProjections() <= 0) { throw BrainModelAlgorithmException("No borders with name prefix " + getSlitLandmarkBorderNamePrefix() + " were found."); } // // Surface/Topology that will be cut and add to brain set // TopologyFile* closedTopologyFile = inputSphericalSurface->getTopologyFile(); cutSphericalSurface = new BrainModelSurface(*inputSphericalSurface); cutSphericalSurfaceTopologyFile = new TopologyFile(*closedTopologyFile); cutSphericalSurface->setTopologyFile(cutSphericalSurfaceTopologyFile); brainSet->addTopologyFile(cutSphericalSurfaceTopologyFile); brainSet->addBrainModel(cutSphericalSurface); // // Make the cuts // BrainModelSurfaceBorderCutter cutter(brainSet, cutSphericalSurface, &slitBorderProjections, BrainModelSurfaceBorderCutter::CUTTING_MODE_SPHERICAL_SURFACE, false); cutter.execute(); // // Classify nodes // brainSet->classifyNodes(cutSphericalSurfaceTopologyFile, false); // // Create an ROI from the edge nodes // BrainModelSurfaceROINodeSelection roi(brainSet); roi.selectNodesThatAreEdges(BrainModelSurfaceROINodeSelection::SELECTION_LOGIC_NORMAL, cutSphericalSurface); // // Convert the ROIs to borders // const QString borderAroundSlitName("SLIT.ENCLOSING.BORDER"); BrainModelSurfaceClusterToBorderConverter bmscbc(brainSet, cutSphericalSurface, cutSphericalSurfaceTopologyFile, borderAroundSlitName, &roi, true); bmscbc.execute(); // // Get ALL of the borders on the sphere // BrainModelBorderSet* bmbs = brainSet->getBorderSet(); BorderProjectionFile slitEnclosingBorderProjectionFile; bmbs->copyBordersToBorderProjectionFile(slitEnclosingBorderProjectionFile); // // Track names of borders that will be deleted later // std::vector borderNamesToDelete; borderNamesToDelete.push_back(borderAroundSlitName); // // Loop through the slit borders that were input by the user // for (int i = 0; i < slitBorderProjections.getNumberOfBorderProjections(); i++) { // // Get XYZ of first link using INPUT CLOSED SPHERE // const BorderProjection* slitBP = slitBorderProjections.getBorderProjection(i); if (slitBP->getNumberOfLinks() > 1) { // // Get XYZ of first and last links // const BorderProjectionLink* slitStartBPL = slitBP->getBorderProjectionLink(0); float firstLinkXYZ[3]; slitStartBPL->unprojectLink(inputSphericalSurface->getCoordinateFile(), firstLinkXYZ); const BorderProjectionLink* slitEndBPL = slitBP->getBorderProjectionLink(slitBP->getNumberOfLinks() - 1); float lastLinkXYZ[3]; slitEndBPL->unprojectLink(inputSphericalSurface->getCoordinateFile(), lastLinkXYZ); // // Find enclosing slit that corresponds // int nearestEnclosingSlitBorderIndex = -1; int nearestEnclosingSlitBorderLinkNumber = -1; float nearestEnclosingSlitBorderDistance = std::numeric_limits::max(); for (int j = 0; j < slitEnclosingBorderProjectionFile.getNumberOfBorderProjections(); j++) { const BorderProjection* bp = slitEnclosingBorderProjectionFile.getBorderProjection(j); if (bp->getName() == borderAroundSlitName) { const int linkNum = bp->getLinkNumberNearestToCoordinate( cutSphericalSurface->getCoordinateFile(), firstLinkXYZ); if (linkNum >= 0) { const BorderProjectionLink* bpl = bp->getBorderProjectionLink(linkNum); float linkXYZ[3]; bpl->unprojectLink(cutSphericalSurface->getCoordinateFile(), linkXYZ); const float distSQ = MathUtilities::distanceSquared3D(firstLinkXYZ, linkXYZ); if (distSQ < nearestEnclosingSlitBorderDistance) { nearestEnclosingSlitBorderDistance = distSQ; nearestEnclosingSlitBorderIndex = j; nearestEnclosingSlitBorderLinkNumber = linkNum; } } } } // // Was the corresponding border that encloses the slit found? // if (nearestEnclosingSlitBorderIndex >= 0) { BorderProjection* bp = slitEnclosingBorderProjectionFile.getBorderProjection(nearestEnclosingSlitBorderIndex); const int lastLinkNumber = bp->getLinkNumberNearestToCoordinate( cutSphericalSurface->getCoordinateFile(), lastLinkXYZ); // // Split it into two border projections // BorderProjection bp1, bp2; bp->splitClosedBorderProjection(cutSphericalSurface->getCoordinateFile(), nearestEnclosingSlitBorderLinkNumber, (slitBP->getName() + ".Patch"), bp1, bp2, lastLinkNumber); bp1.setName(slitBP->getName() + ".PatchA"); bp2.setName(slitBP->getName() + ".PatchB"); bp2.reverseOrderOfBorderProjectionLinks(); BorderProjectionFile tempBP; tempBP.addBorderProjection(bp1); tempBP.addBorderProjection(bp2); bmbs->copyBordersFromBorderProjectionFile(&tempBP); bmbs->projectBorders(cutSphericalSurface); borderNamesToDelete.push_back(slitBP->getName()); // // Update name of the enclosing slit border name // bp->setName(slitBP->getName() + ".Patch"); } } } // // Remove the enclosing borders // bmbs->deleteBordersWithNames(borderNamesToDelete); // // Classify nodes // brainSet->classifyNodes(cutSphericalSurfaceTopologyFile, false); // // Create the smoothed spherical coordinate file that will receive closed topology // BrainModelSurface* smoothedSphericalSurface = new BrainModelSurface(*cutSphericalSurface); brainSet->addBrainModel(smoothedSphericalSurface); // // Smooth the sphere // smoothedSphericalSurface->arealSmoothing(1.0, 1000, 10, NULL, 10); smoothedSphericalSurface->arealSmoothing(1.0, 1000, 0, NULL, 10); // // Close the sphere by retessellating it // const int numNodes = smoothedSphericalSurface->getNumberOfNodes(); const TopologyHelper* th = cutSphericalSurfaceTopologyFile->getTopologyHelper(false, true, false); std::vector useNodeInTessellationFlag(numNodes); for (int i = 0; i < numNodes; i++) { useNodeInTessellationFlag[i] = th->getNodeHasNeighbors(i); } BrainModelSurfaceSphericalTessellator bmsst(brainSet, smoothedSphericalSurface, useNodeInTessellationFlag); bmsst.execute(); // // Get newly tessellated closed spherical surface and topology file // smoothedClosedSphericalSurface = bmsst.getPointerToNewSphericalSurface(); smoothedClosedSphericalSurfaceTopologyFile = smoothedClosedSphericalSurface->getTopologyFile(); // // Remove the smoothed cut sphere from the brain set // brainSet->deleteBrainModel(smoothedSphericalSurface); smoothedSphericalSurface = NULL; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceDeformationSpherical.h0000664000175000017500000001170411572067322027431 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __BRAIN_MODEL_SURFACE_DEFORMATION_SPHERICAL_H__ #define __BRAIN_MODEL_SURFACE_DEFORMATION_SPHERICAL_H__ #include "BrainModelSurfaceDeformation.h" #include "SurfaceShapeFile.h" /// this class performs a spherical deformation class BrainModelSurfaceDeformationSpherical : public BrainModelSurfaceDeformation { public: /// Constructor BrainModelSurfaceDeformationSpherical(BrainSet* brainSetIn, DeformationMapFile* DeformationMapFileIn); /// Destructor ~BrainModelSurfaceDeformationSpherical(); protected: /// Execute the deformation void executeDeformation() throw (BrainModelAlgorithmException); /// determine the fiducial sphere distortion void determineFiducialSphereDistortion(); /// update the fiducial sphere distortion void updateSphereFiducialDistortion(const int cycle); /// Determine distortion ratio of fiducial vs spherical tile areas. void determineSphericalDistortion(const BrainModelSurface* fiducialSurface, const BrainModelSurface* sphericalSurface, std::vector& tileDistortion); /// Perform landmark constrained smoothing on the target deformation sphere void landmarkConstrainedSmoothTarget(); // Perform landmark constrained morphing on the sphere with source landmarks void landmarkMorphContrainedSource(const int cycleNumber) throw (BrainModelAlgorithmException); /// Perform landmark neighbor constrained smoothing on the sphere with source landmarks void landmarkNeighborConstrainedSmoothSource(const int cycleNumber); /// Load the regularly tessellated sphere and set its radius. void loadRegularSphere() throw (BrainModelAlgorithmException); /// Replace the target landmarks in the deformation sphere with the source landmarks void replaceTargetLandmarksWithSourceLandmarks(); /// tessellate the target border into the target deformation sphere void tessellateTargetBordersIntoDeformationSphere() throw (BrainModelAlgorithmException); /// create the deformed coordinate file at the end of each cycle void createDeformedCoordinateFile(const int cycle); /// update the deformed source borders for the next cycle void updateSourceBordersForNextCycle() throw (BrainModelAlgorithmException); /// the target deformation sphere BrainModelSurface* targetDeformationSphere; /// the unsmoothed target deformation sphere BrainModelSurface* unsmoothedTargetDeformationSphere; /// the unsmoothed source deformation sphere BrainModelSurface* unsmoothedSourceDeformationSphere; /// the smoothed source deformation sphere BrainModelSurface* smoothedSourceDeformationSphere; /// the morphed source deformation sphere BrainModelSurface* morphedSourceDeformationSphere; /// the number of nodes in the regularly tessellated sphere prior to inserting landmarks int originalNumberOfNodes; /// keeps track of borders that are tessellated into the deformation sphere std::vector > usedBorderLinks; /// target file naming prefix for debugging QString debugTargetFileNamePrefix; /// source file naming prefix for debugging QString debugSourceFileNamePrefix; /// radius of the deformation sphere float deformationSphereRadius; /// Keep track of distortion SurfaceShapeFile fiducialSphereDistortion; /// ratio of target fiducial and spherical tile areas std::vector targetTileDistortion; /// ratio of source fiducial and spherical tile areas std::vector sourceTileDistortion; /// keeps track of landmark nodes std::vector landmarkNodeFlags; /// keeps track of crossovers in each cycle std::vector crossoverCount; }; #endif // __BRAIN_MODEL_SURFACE_DEFORMATION_SPHERICAL_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceDeformationSpherical.cxx0000664000175000017500000013077011572067322030011 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include "AreaColorFile.h" #include "BorderFile.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceDeformationSpherical.h" #include "BrainModelSurfaceMorphing.h" #include "BrainModelSurfaceNodeColoring.h" #include "BrainModelSurfacePointProjector.h" #include "BrainSet.h" #include "ColorFile.h" #include "DebugControl.h" #include "DeformationMapFile.h" #include "FileUtilities.h" #include "MathUtilities.h" #include "PaintFile.h" #include "StringUtilities.h" //static const int morphAngleForceAlgorithm = 1; /** * Constructor. */ BrainModelSurfaceDeformationSpherical::BrainModelSurfaceDeformationSpherical( BrainSet* brainSetIn, DeformationMapFile* deformationMapFileIn) : BrainModelSurfaceDeformation(brainSetIn, deformationMapFileIn) { } /** * Destructor. */ BrainModelSurfaceDeformationSpherical::~BrainModelSurfaceDeformationSpherical() { } /** * Determine distortion ratio of fiducial vs spherical tile areas. */ void BrainModelSurfaceDeformationSpherical::determineSphericalDistortion( const BrainModelSurface* fiducialSurface, const BrainModelSurface* sphericalSurface, std::vector& tileDistortion) { // // Get topology file and number of tiles // const TopologyFile* tf = sphericalSurface->getTopologyFile(); const int numTiles = tf->getNumberOfTiles(); tileDistortion.resize(numTiles); // // Get the coordinate files // const CoordinateFile* fiducialCoords = fiducialSurface->getCoordinateFile(); const CoordinateFile* sphericalCoords = sphericalSurface->getCoordinateFile(); // // Determine fiducial/spherical area ratio of tiles // for (int i = 0; i < numTiles; i++) { int v1, v2, v3; tf->getTile(i, v1, v2, v3); const float sphereArea = MathUtilities::triangleArea((float*)sphericalCoords->getCoordinate(v1), (float*)sphericalCoords->getCoordinate(v2), (float*)sphericalCoords->getCoordinate(v3)); tileDistortion[i] = 1.0; if (sphereArea != 0.0) { const float fidArea = MathUtilities::triangleArea((float*)fiducialCoords->getCoordinate(v1), (float*)fiducialCoords->getCoordinate(v2), (float*)fiducialCoords->getCoordinate(v3)); tileDistortion[i] = fidArea / sphereArea; } } } /** * Load the regularly tessellated sphere and set its radius. */ void BrainModelSurfaceDeformationSpherical::loadRegularSphere() throw (BrainModelAlgorithmException) { // // Construct the regular sphere file name // QString specFileName(brainSet->getCaretHomeDirectory()); specFileName.append("/"); specFileName.append("data_files/REGISTER.SPHERE"); specFileName.append("/"); switch(deformationMapFile->getSphereResolution(0)) { case 20: specFileName.append("sphere.v5.0.spec"); break; case 74: specFileName.append("sphere.v5.1.spec"); break; case 290: specFileName.append("sphere.v5.2.spec"); break; case 1154: specFileName.append("sphere.v5.3.spec"); break; case 4610: specFileName.append("sphere.v5.4.spec"); break; case 18434: specFileName.append("sphere.v5.5.spec"); break; case 73730: specFileName.append("sphere.v5.6.spec"); break; default: { std::ostringstream str; str << "Invalid sphere resolution: " << deformationMapFile->getSphereResolution(0); throw BrainModelAlgorithmException(str.str().c_str()); } break; } // // Read the spec file // SpecFile sf; try { sf.readFile(specFileName); } catch (FileException& e) { throw BrainModelAlgorithmException(e.whatQString()); } sf.setAllFileSelections(SpecFile::SPEC_TRUE); // // Read the spec file into "this" brain set // std::vector errorMessages; brainSet->readSpecFile(BrainSet::SPEC_FILE_READ_MODE_NORMAL, sf, specFileName, errorMessages, NULL, NULL); if (errorMessages.empty() == false) { QString msg("Error reading data files for "); msg.append(specFileName); msg.append("\n"); msg.append(StringUtilities::combine(errorMessages, "\n")); throw BrainModelAlgorithmException(msg); } // // Get the spherical surface and set its radius // targetDeformationSphere = brainSet->getBrainModelSurface(0); if (targetDeformationSphere == NULL) { throw BrainModelAlgorithmException("Regular sphere spec contained no coord file."); } targetDeformationSphere->convertToSphereWithRadius(deformationSphereRadius); targetDeformationSphere->updateForDefaultScaling(); updateViewingTransformation(brainSet); brainSet->drawBrainModel(targetDeformationSphere); } /** * Tessellate the target border into the target deformation sphere */ void BrainModelSurfaceDeformationSpherical::tessellateTargetBordersIntoDeformationSphere() throw (BrainModelAlgorithmException) { // // empty contents of the used and ignored border links // usedBorderLinks.clear(); // // Create a Point Projector with nodes to be added for the deformation sphere. // BrainModelSurfacePointProjector bspp(targetDeformationSphere, BrainModelSurfacePointProjector::SURFACE_TYPE_HINT_SPHERE, true); TopologyFile* tf = targetDeformationSphere->getTopologyFile(); // // Project each border link into the deformation sphere // const int numBorders = targetBorderFile->getNumberOfBorders(); for (int i = 0; i < numBorders; i++) { const Border* b = targetBorderFile->getBorder(i); const int numLinks = b->getNumberOfLinks(); for (int j = 0; j < numLinks; j++) { const float* xyz = b->getLinkXYZ(j); // // Project target node onto source deformed surface // int nearestNode = -1; int tileNodes[3]; float tileAreas[3]; const int tile = bspp.projectBarycentric(xyz, nearestNode, tileNodes, tileAreas, true); const int newNodeNumber = targetDeformationSphere->getNumberOfNodes(); // // Unproject using the deformed source coordinate file // if (tile >= 0) { // // Get the tile // int v1, v2, v3; tf->getTile(tile, v1, v2, v3); // // Create two new tiles // const int tn1[3] = { v1, v2, newNodeNumber }; const int tn2[3] = { v2, v3, newNodeNumber }; const int tn3[3] = { v3, v1, newNodeNumber }; // // Replace the original tile and create two new ones // tf->setTile(tile, tn1); tf->addTile(tn2); tf->addTile(tn3); // // Add the node to the surface // targetDeformationSphere->addNode(xyz); // // Keep track of border link assignments // usedBorderLinks.push_back(std::make_pair(i, j)); } else { if (nearestNode >= 0) { std::cout << "Border link with closest node ignored: " << i << " " << j << std::endl; } else { std::cout << "Border link without closest node ignored: " << i << " " << j << std::endl; } } } } const int numNodes = targetDeformationSphere->getNumberOfNodes(); if (numNodes == originalNumberOfNodes) { throw BrainModelAlgorithmException("Tessellating in border nodes failed."); } // // Make sure all nodes are on the sphere // targetDeformationSphere->convertToSphereWithRadius(deformationSphereRadius); // // Update the surface's normals and update node attributes for changes in nodes. // targetDeformationSphere->computeNormals(); brainSet->resetNodeAttributes(); // // Create the spec file name // QString specFileName(debugTargetFileNamePrefix); specFileName.append("_withLandmarks.spec"); brainSet->setSpecFileName(specFileName); intermediateFiles.push_back(specFileName); // // Setup the paint file that shows the landmark nodes // PaintFile* pf = brainSet->getPaintFile(); pf->setNumberOfNodesAndColumns(numNodes, 1); pf->setColumnName(0, "Landmarks"); const int nonLandmarkPaintIndex = pf->addPaintName("???"); const int landmarkPaintIndex = pf->addPaintName("Landmark"); for (int i = 0; i < numNodes; i++) { if (i < originalNumberOfNodes) { pf->setPaint(i, 0, nonLandmarkPaintIndex); } else { pf->setPaint(i, 0, landmarkPaintIndex); } } QString paintFileName(debugTargetFileNamePrefix); paintFileName.append("_withLandmarks"); paintFileName.append(SpecFile::getPaintFileExtension()); brainSet->writePaintFile(paintFileName); intermediateFiles.push_back(paintFileName); // // Setup the node color file // AreaColorFile* cf = brainSet->getAreaColorFile(); cf->addColor("Landmark", 0, 255, 0, 2, 1); cf->addColor("???", 170, 170, 170, 2, 1); QString nodeColorFileName(debugTargetFileNamePrefix); nodeColorFileName.append("_withLandmarks"); nodeColorFileName.append(SpecFile::getAreaColorFileExtension()); brainSet->writeAreaColorFile(nodeColorFileName); intermediateFiles.push_back(nodeColorFileName); // // Write the topology file // QString topoFileName(debugTargetFileNamePrefix); topoFileName.append("_withLandmarks"); topoFileName.append(SpecFile::getTopoFileExtension()); brainSet->writeTopologyFile(topoFileName, TopologyFile::TOPOLOGY_TYPE_CLOSED, tf); intermediateFiles.push_back(topoFileName); // // Write the sphere with target landmarks // QString coordFileName(debugTargetFileNamePrefix); coordFileName.append("_withLandmarks"); coordFileName.append(SpecFile::getCoordinateFileExtension()); brainSet->writeCoordinateFile(coordFileName, BrainModelSurface::SURFACE_TYPE_SPHERICAL, targetDeformationSphere->getCoordinateFile()); intermediateFiles.push_back(coordFileName); // // Set node coloring overlay to paint // BrainModelSurfaceNodeColoring* bsnc = brainSet->getNodeColoring(); brainSet->getPrimarySurfaceOverlay()->setOverlay(-1, BrainModelSurfaceOverlay::OVERLAY_PAINT); bsnc->assignColors(); // // Update the displayed surface // this->updateViewingTransformation(brainSet); brainSet->drawBrainModel(targetDeformationSphere); } // // Perform landmark constrained smoothing on the target deformation sphere // void BrainModelSurfaceDeformationSpherical::landmarkConstrainedSmoothTarget() { // // Perform the landmark constrained smoothing // targetDeformationSphere->landmarkConstrainedSmoothing(0.5, 20, landmarkNodeFlags, 0); // // Push the nodes back onto the sphere // targetDeformationSphere->convertToSphereWithRadius(deformationSphereRadius); // // Save the coordinate file // QString coordFileName(debugTargetFileNamePrefix); coordFileName.append("_withLandmarks_smoothed"); coordFileName.append(SpecFile::getCoordinateFileExtension()); brainSet->writeCoordinateFile(coordFileName, BrainModelSurface::SURFACE_TYPE_SPHERICAL, targetDeformationSphere->getCoordinateFile()); intermediateFiles.push_back(coordFileName); // // Update scaling and display surface // targetDeformationSphere->updateForDefaultScaling(); updateViewingTransformation(brainSet); brainSet->drawBrainModel(targetDeformationSphere); } /** * Determine the fiducial sphere distortion. */ void BrainModelSurfaceDeformationSpherical::determineFiducialSphereDistortion() { // // Create a point projector for projecting the deformation sphere nodes // onto the target surface // BrainModelSurfacePointProjector bspp(targetSurface, BrainModelSurfacePointProjector::SURFACE_TYPE_HINT_SPHERE, false); const int numTargetTiles = static_cast(targetTileDistortion.size()); // // Project each node in the deformation sphere // const int numNodes = targetDeformationSphere->getNumberOfNodes(); const CoordinateFile* targetDeformationCoords = targetDeformationSphere->getCoordinateFile(); for (int i = 0; i < numNodes; i++) { float xyz[3]; targetDeformationCoords->getCoordinate(i, xyz); // // Project target node onto source deformed surface // int nearestNode = -1; int tileNodes[3]; float tileAreas[3]; const int tile = bspp.projectBarycentric(xyz, nearestNode, tileNodes, tileAreas, true); // // Did it project ? // if ((tile >= 0) && (tile < numTargetTiles)) { fiducialSphereDistortion.setValue(i, 0, targetTileDistortion[tile]); } else { fiducialSphereDistortion.setValue(i, 0, 1.0); } } } /** * Update the fiducial sphere distortion. */ void BrainModelSurfaceDeformationSpherical::updateSphereFiducialDistortion(const int /*cycle*/) { // // Create a point projector for projecting the source deformation sphere // nodes to the original source surface // BrainModelSurfacePointProjector bspp(sourceSurface, BrainModelSurfacePointProjector::SURFACE_TYPE_HINT_SPHERE, false); // // Project deformation sphere nodes onto original source surface // const int numNodes = morphedSourceDeformationSphere->getNumberOfNodes(); const CoordinateFile* coords = morphedSourceDeformationSphere->getCoordinateFile(); const int numSourceTiles = static_cast(sourceTileDistortion.size()); for (int i = 0; i < numNodes; i++) { float xyz[3]; coords->getCoordinate(i, xyz); // // Project target node onto source deformed surface // int nearestNode = -1; int tileNodes[3]; float tileAreas[3]; const int tile = bspp.projectBarycentric(xyz, nearestNode, tileNodes, tileAreas, true); // // Did it project ? // if ((tile >= 0) && (tile < numSourceTiles)) { fiducialSphereDistortion.setValue(i, 1, sourceTileDistortion[tile]); } else { fiducialSphereDistortion.setValue(i, 1, 1.0); } fiducialSphereDistortion.setValue(i, 2, std::sqrt(fiducialSphereDistortion.getValue(i, 1) / fiducialSphereDistortion.getValue(i, 0))); } // // Save the surface shape file // std::ostringstream str; str << debugTargetFileNamePrefix.toAscii().constData() << SpecFile::getSurfaceShapeFileExtension().toAscii().constData(); fiducialSphereDistortion.writeFile(str.str().c_str()); brainSet->addToSpecFile(SpecFile::getSurfaceShapeFileTag(), str.str().c_str()); intermediateFiles.push_back(str.str().c_str()); } /** * Replace the target landmarks in the deformation sphere with the source landmarks */ void BrainModelSurfaceDeformationSpherical::replaceTargetLandmarksWithSourceLandmarks() { // // Copy the surface // unsmoothedSourceDeformationSphere = new BrainModelSurface(*targetDeformationSphere); brainSet->addBrainModel(unsmoothedSourceDeformationSphere); updateViewingTransformation(brainSet); // // Replace target landmark nodes in deformation sphere with source landmark coordinates // const int numNodes = unsmoothedSourceDeformationSphere->getNumberOfNodes(); CoordinateFile* sourceCoords = unsmoothedSourceDeformationSphere->getCoordinateFile(); int borderCounter = 0; for (int i = originalNumberOfNodes; i < numNodes; i++) { const int borderNumber = usedBorderLinks[borderCounter].first; const int linkNumber = usedBorderLinks[borderCounter].second; const Border* sourceBorder = sourceBorderFile->getBorder(borderNumber); const float* xyz = sourceBorder->getLinkXYZ(linkNumber); sourceCoords->setCoordinate(i, xyz); borderCounter++; } // // Make sure all nodes are on the sphere // unsmoothedSourceDeformationSphere->convertToSphereWithRadius(deformationSphereRadius); // // Save the coordinate file // QString coordFileName(debugSourceFileNamePrefix); coordFileName.append("_withLandmarks_initial"); coordFileName.append(SpecFile::getCoordinateFileExtension()); brainSet->writeCoordinateFile(coordFileName, BrainModelSurface::SURFACE_TYPE_SPHERICAL, unsmoothedSourceDeformationSphere->getCoordinateFile()); intermediateFiles.push_back(coordFileName); unsmoothedSourceDeformationSphere->updateForDefaultScaling(); this->updateViewingTransformation(brainSet); brainSet->drawBrainModel(unsmoothedSourceDeformationSphere); } /** * Perform landmark neighbor constrained smoothing on the sphere with source landmarks. */ void BrainModelSurfaceDeformationSpherical::landmarkNeighborConstrainedSmoothSource(const int cycleNumber) { // // Copy the surface // smoothedSourceDeformationSphere = new BrainModelSurface(*unsmoothedSourceDeformationSphere); brainSet->addBrainModel(smoothedSourceDeformationSphere); updateViewingTransformation(brainSet); // // Get smoothing parameters for this cycle // float strength; int numCycles, numIterations, neighborIterations, numFinalIterations; deformationMapFile->getSmoothingParameters(0, cycleNumber - 1, strength, numCycles, numIterations, neighborIterations, numFinalIterations); smoothedSourceDeformationSphere->updateForDefaultScaling(); // // perform number of smoothing cycles // for (int i = 0; i < numCycles; i++) { // // Perform the landmark constrained smoothing // updateViewingTransformation(smoothedSourceDeformationSphere); smoothedSourceDeformationSphere->landmarkNeighborConstrainedSmoothing(strength, numIterations, landmarkNodeFlags, neighborIterations, 0); // // push non-landmark nodes back onto the sphere // smoothedSourceDeformationSphere->convertToSphereWithRadius(deformationSphereRadius, 0, originalNumberOfNodes); } // // Perform final smoothing // smoothedSourceDeformationSphere->arealSmoothing(strength, numFinalIterations, 0); // // push all nodes back onto the sphere // smoothedSourceDeformationSphere->convertToSphereWithRadius(deformationSphereRadius); smoothedSourceDeformationSphere->updateForDefaultScaling(); updateViewingTransformation(smoothedSourceDeformationSphere); // // Save the coordinate file // QString coordFileName(debugSourceFileNamePrefix); coordFileName.append("_withLandmarks_smoothed"); coordFileName.append(SpecFile::getCoordinateFileExtension()); brainSet->writeCoordinateFile(coordFileName, BrainModelSurface::SURFACE_TYPE_SPHERICAL, smoothedSourceDeformationSphere->getCoordinateFile()); intermediateFiles.push_back(coordFileName); smoothedSourceDeformationSphere->updateForDefaultScaling(); updateViewingTransformation(brainSet); brainSet->drawBrainModel(smoothedSourceDeformationSphere); } /** * Perform landmark constrained morphing on the sphere with source landmarks */ void BrainModelSurfaceDeformationSpherical::landmarkMorphContrainedSource(const int cycleNumber) throw (BrainModelAlgorithmException) { // // Get smoothing parameters for this cycle (just need strength) // float strength; int numCycles, numIterations, neighborIterations, numFinalIterations; deformationMapFile->getSmoothingParameters(0, cycleNumber - 1, strength, numCycles, numIterations, neighborIterations, numFinalIterations); // // Get the morphing paramters for this cycle // float linearForce, angularForce, stepSize, landmarkStepSize; int numMorphCycles, iterations, smoothIterations; deformationMapFile->getMorphingParameters(0, cycleNumber - 1, numMorphCycles, linearForce, angularForce, stepSize, landmarkStepSize, iterations, smoothIterations); morphedSourceDeformationSphere = NULL; // // If morphing should be performed // if (numMorphCycles > 0) { // // Copy the surface // morphedSourceDeformationSphere = new BrainModelSurface(*smoothedSourceDeformationSphere); brainSet->addBrainModel(morphedSourceDeformationSphere); updateViewingTransformation(brainSet); // // NON-landmark nodes are morphed // const int numNodes = morphedSourceDeformationSphere->getNumberOfNodes(); std::vector morphNodeFlag(numNodes); for (int i = 0; i < numNodes; i++) { morphNodeFlag[i] = ( ! landmarkNodeFlags[i]); } // // Get fiducial sphere ratio settings // bool useFiducialSphereRatios = false; float fiducialSphereRatioStrength = 0.5; deformationMapFile->getSphereFiducialRatio(useFiducialSphereRatios, fiducialSphereRatioStrength); std::vector fiducialSphereRatios; if (useFiducialSphereRatios) { // // Use fiducial/sphere distortion except on first cycle // if (cycleNumber > 1) { const int numNodes = fiducialSphereDistortion.getNumberOfNodes(); fiducialSphereRatios.resize(numNodes); for (int i = 0; i < numNodes; i++) { fiducialSphereRatios[i] = fiducialSphereDistortion.getValue(i, 2); } } } // // Morph for the specified number of cycles // for (int morphCycle = 0; morphCycle < numMorphCycles; morphCycle++) { // // Create the morphing object and set parameters // BrainModelSurfaceMorphing bmsm(brainSet, targetDeformationSphere, morphedSourceDeformationSphere, BrainModelSurfaceMorphing::MORPHING_SURFACE_SPHERICAL); bmsm.setMorphingParameters(iterations, linearForce, angularForce, stepSize); bmsm.setNodesThatShouldBeMorphed(morphNodeFlag, landmarkStepSize); if (fiducialSphereRatios.size() > 0) { if (useFiducialSphereRatios) { bmsm.setFiducialSphereDistortionCorrections(fiducialSphereRatios, fiducialSphereRatioStrength); } } // // execute the morphing // bmsm.execute(); // // Perform a little bit of normal smoothing // morphedSourceDeformationSphere->arealSmoothing(strength, smoothIterations, 0); // // Push nodes back to sphere and draw // morphedSourceDeformationSphere->convertToSphereWithRadius(deformationSphereRadius); // // Draw the surface // morphedSourceDeformationSphere->updateForDefaultScaling(); updateViewingTransformation(brainSet); brainSet->drawBrainModel(morphedSourceDeformationSphere); } // // Save the surface // QString coordFileName(debugSourceFileNamePrefix); coordFileName.append("_withLandmarks_morphed"); coordFileName.append(SpecFile::getCoordinateFileExtension()); brainSet->writeCoordinateFile(coordFileName, BrainModelSurface::SURFACE_TYPE_SPHERICAL, morphedSourceDeformationSphere->getCoordinateFile()); intermediateFiles.push_back(coordFileName); // // Draw the surface // morphedSourceDeformationSphere->updateForDefaultScaling(); this->updateViewingTransformation(brainSet); brainSet->drawBrainModel(morphedSourceDeformationSphere); } else { morphedSourceDeformationSphere = smoothedSourceDeformationSphere; } } /** * Deform the source sphere using the source and target deformation spheres */ void BrainModelSurfaceDeformationSpherical::createDeformedCoordinateFile(const int cycle) { try { // // Copy the user's input surface to a new deformed surface // deformedSourceSurface = new BrainModelSurface(*sourceSurface); sourceBrainSet->addBrainModel(deformedSourceSurface); updateViewingTransformation(sourceBrainSet); // // Make sure source surface is same radius as deformation sphere // sourceSurface->convertToSphereWithRadius(deformationSphereRadius); // // Coordinates of the morphed source deformation sphere // //const CoordinateFile* deformationMorphedSphereCoords = // morphedSourceDeformationSphere->getCoordinateFile(); // // Coordinates of the original unsmoothed target deformation sphere // const CoordinateFile* targetDeformationSphereCoords = unsmoothedTargetDeformationSphere->getCoordinateFile(); // // Get the coordinate files for the user's surface and its // new deformed surface. // CoordinateFile* sourceCoords = sourceSurface->getCoordinateFile(); CoordinateFile* deformedSourceCoords = deformedSourceSurface->getCoordinateFile(); const int numCoords = sourceCoords->getNumberOfCoordinates(); // // See if X coordinate will need to be flipped (first cycle only !!!) // bool diffHemFlag = false; if (cycle == 1) { diffHemFlag = (sourceBrainSet->getStructure() != targetBrainSet->getStructure()); } // // Create a Point Projector for the flat subsampled surface. // BrainModelSurfacePointProjector bspp(morphedSourceDeformationSphere, //targetDeformationSphere); BrainModelSurfacePointProjector::SURFACE_TYPE_HINT_SPHERE, false); // // Project each point in the users input surface to its deformed surface // for (int i = 0; i < numCoords; i++) { float xyz[3]; sourceCoords->getCoordinate(i, xyz); if (diffHemFlag) { xyz[0] = -xyz[0]; sourceCoords->setCoordinate(i, xyz); // needed for projecting borders } // // Project source node onto subsampled surface // int nearestNode = -1; int tileNodes[3]; float tileAreas[3]; const int tile = bspp.projectBarycentric(xyz, nearestNode, tileNodes, tileAreas, true); // // Unproject using the deformed source sphere coordinate file // if (tile >= 0) { BrainModelSurfacePointProjector::unprojectPoint(tileNodes, tileAreas, targetDeformationSphereCoords, //deformationMorphedSphereCoords, xyz); } else if (nearestNode >= 0) { // JWH 08/08/03 2:15pm deformedSourceCoords->getCoordinate(nearestNode, xyz); //deformationMorphedSphereCoords->getCoordinate(nearestNode, xyz); targetDeformationSphereCoords->getCoordinate(nearestNode, xyz); } deformedSourceCoords->setCoordinate(i, xyz); } // // Write the source deformed coordinates // QDir::setCurrent(sourceDirectory); QString defCoordName(deformationMapFile->getDeformedFileNamePrefix()); if (cycle == deformationMapFile->getSphericalNumberOfCycles(0)) { QString dn(FileUtilities::dirname(sourceCoords->getFileName())); if ((dn != ".") && (dn.length() > 0)) { QString fn(FileUtilities::basename(sourceCoords->getFileName())); QString s(dn); s += QDir::separator(); s += deformationMapFile->getDeformedFileNamePrefix(); s += fn; defCoordName = s; } else { defCoordName.append(sourceCoords->getFileName()); } } else { std::ostringstream str; str << "_sphere_cycle_" << cycle << SpecFile::getCoordinateFileExtension().toAscii().constData(); defCoordName.append(str.str().c_str()); } deformationMapFile->setSourceDeformedSphericalCoordFileName(defCoordName); deformedSourceCoords->appendToFileComment("\nDeformation Map File: "); deformedSourceCoords->appendToFileComment( FileUtilities::basename(sourceToTargetDeformationMapFileName)); deformedSourceCoords->writeFile(defCoordName); QDir::setCurrent(originalDirectory); } catch (FileException& e) { throw BrainModelAlgorithmException(e.whatQString()); } } /** * Update the source borders for the next cycle. */ void BrainModelSurfaceDeformationSpherical::updateSourceBordersForNextCycle() throw (BrainModelAlgorithmException) { // // Get the deformed source surface coordinates // const CoordinateFile* deformedCoords = deformedSourceSurface->getCoordinateFile(); // // Create a Point Projector for the source surface. // BrainModelSurfacePointProjector bspp(sourceSurface, BrainModelSurfacePointProjector::SURFACE_TYPE_HINT_SPHERE, false); // // Project each point in the source borders // const int numBorders = sourceBorderFile->getNumberOfBorders(); for (int i = 0; i < numBorders; i++) { Border* border = sourceBorderFile->getBorder(i); const int numLinks = border->getNumberOfLinks(); for (int j = 0; j < numLinks; j++) { float xyz[3]; border->getLinkXYZ(j, xyz); // // Project border point onto source surface // int nearestNode = -1; int tileNodes[3]; float tileAreas[3]; const int tile = bspp.projectBarycentric(xyz, nearestNode, tileNodes, tileAreas, true); // // Unproject using the deformed source surface // if (tile >= 0) { BrainModelSurfacePointProjector::unprojectPoint(tileNodes, tileAreas, deformedCoords, xyz); } else if (nearestNode >= 0) { deformedCoords->getCoordinate(nearestNode, xyz); } // // Update border link position // border->setLinkXYZ(j, xyz); } } } /* void BrainModelSurfaceDeformationSpherical::updateSourceBordersForNextCycle() throw (BrainModelAlgorithmException) { BorderFile* updatedBorders = new BorderFile; // // The border nodes were tessellated in as nodes and added to the original deformation sphere // const int numNodes = morphedSourceDeformationSphere->getNumberOfNodes(); const CoordinateFile* morphSourceCoords = morphedSourceDeformationSphere->getCoordinateFile(); // // For new borders that are created // Border* border = NULL; int lastBorderNumber = -1; // // Check nodes that were border links tessellated into the deformation sphere // for (int i = originalNumberOfNodes; i < numNodes; i++) { // // For morphed deformation sphere, get the border link that created this node // const int index = i - originalNumberOfNodes; const int borderNumber = usedBorderLinks[index].first; // // Has border changed ? // if (borderNumber != lastBorderNumber) { if (border != NULL) { updatedBorders->addBorder(*border); } const Border* sourceBorder = sourceBorderFile->getBorder(borderNumber); border = new Border(sourceBorder->getName()); } lastBorderNumber = borderNumber; // // Add the border's link // border->addBorderLink(morphSourceCoords->getCoordinate(i)); } if (border != NULL) { updatedBorders->addBorder(*border); } if (updatedBorders->getNumberOfBorders() != sourceBorderFile->getNumberOfBorders()) { throw BrainModelAlgorithmException("Number of borders changed when moving source " "border links for next cycle."); } delete sourceBorderFile; sourceBorderFile = updatedBorders; } */ /** * Execute the deformation. */ void BrainModelSurfaceDeformationSpherical::executeDeformation() throw (BrainModelAlgorithmException) { // // Get radius of target sphere // deformationSphereRadius = targetSurface->getSphericalSurfaceRadius(); // // Make source surface the same radius as the target surface // sourceSurface->convertToSphereWithRadius(deformationSphereRadius); // // control of sphere fiducial distortion // bool useFiducialSphereRatios = false; float fiducialSphereRatioStrength = 0.5; deformationMapFile->getSphereFiducialRatio(useFiducialSphereRatios, fiducialSphereRatioStrength); // // Determing the ratio of the source fiducial and spherical tile areas // if (useFiducialSphereRatios) { if (DebugControl::getDebugOn()) { std::cout << " " << std::endl; } updateProgressDialog("Determining Spherical Distortion"); determineSphericalDistortion(sourceFiducialSurface, sourceSurface, sourceTileDistortion); // // Determing the ratio of the target fiducial and spherical tile areas // determineSphericalDistortion(targetFiducialSurface, targetSurface, targetTileDistortion); } // // Perform the requested number of cycles // for (int cycle = 1; cycle <= deformationMapFile->getSphericalNumberOfCycles(0); cycle++) { // // Debug file name prefixes // std::ostringstream strT; strT << "ia_target_cycle" << cycle; debugTargetFileNamePrefix = strT.str().c_str(); std::ostringstream strS; strS << "ia_source_cycle" << cycle; debugSourceFileNamePrefix = strS.str().c_str(); // // Resample the border files // if (DebugControl::getDebugOn()) { std::cout << "Cycle " << cycle << " resampling borders." << std::endl; } updateProgressDialog("Cycle " + QString::number(cycle) + " resampling borders."); resampleBorderFiles(-1, cycle, deformationSphereRadius); // // Set the radius of the source/target border file to the radius of the target surface // sourceBorderFile->setSphericalBorderRadius(deformationSphereRadius); targetBorderFile->setSphericalBorderRadius(deformationSphereRadius); // // Load the regularly tessellated sphere and make it same radius as target surface // QString currentDirectory(QDir::currentPath()); loadRegularSphere(); QDir::setCurrent(currentDirectory); // // Save the number of nodes before tessellating in the borders // originalNumberOfNodes = targetDeformationSphere->getNumberOfNodes(); // // tessellate the target borders into the target deformation sphere // if (DebugControl::getDebugOn()) { std::cout << "Cycle " << cycle << " tessellating borders into target." << std::endl; } updateProgressDialog("Tessellating Borders into Target"); tessellateTargetBordersIntoDeformationSphere(); // // Copy the target deformed sphere making the current sphere the unsmoothed // unsmoothedTargetDeformationSphere = targetDeformationSphere; targetDeformationSphere = new BrainModelSurface(*unsmoothedTargetDeformationSphere); brainSet->addBrainModel(targetDeformationSphere); updateViewingTransformation(brainSet); // // Mark the landmark nodes // const int numNodes = targetDeformationSphere->getNumberOfNodes(); landmarkNodeFlags.resize(numNodes); for (int i = 0; i < numNodes; i++) { landmarkNodeFlags[i] = (i >= originalNumberOfNodes); } // // Perform landmark constrained smoothing. Only the coordinate nodes are // smoothed // if (DebugControl::getDebugOn()) { std::cout << "Cycle " << cycle << " landmark constrained smoothing of target." << std::endl; } updateProgressDialog("Landmark Constrianed Smoothing of Target"); landmarkConstrainedSmoothTarget(); // // During first cycle, allocate the fiducial sphere distortion surface shape file // // Update each cycle since number of nodes might vary by a couple due to projection problems //if (cycle == 1) { if (useFiducialSphereRatios) { fiducialSphereDistortion.setNumberOfNodesAndColumns( targetDeformationSphere->getNumberOfNodes(), 3); } //} if (useFiducialSphereRatios) { // // determine the fiducial sphere distortion // determineFiducialSphereDistortion(); } // // Replace the target landmarks in the deformation sphere with the source landmarks // updateProgressDialog("Replacing Target Landmarks with Source Landmarks"); replaceTargetLandmarksWithSourceLandmarks(); // // Perform landmark neighbor constrained smoothing on the sphere with source landmarks // if (DebugControl::getDebugOn()) { std::cout << "Cycle " << cycle << " landmark neighbor constrained smoothing." << std::endl; } updateProgressDialog("Landmark Neighbor Constrained Smoothing of Source"); landmarkNeighborConstrainedSmoothSource(cycle); // // Perform landmark constrained morphing on the sphere with source landmarks // if (DebugControl::getDebugOn()) { std::cout << "Cycle " << cycle << " landmark constrained morphing." << std::endl; } updateProgressDialog("Landmark Morphing Constrained Source"); landmarkMorphContrainedSource(cycle); // // Update fiducial/sphere with deformed surface // if (useFiducialSphereRatios) { updateSphereFiducialDistortion(cycle); } // // make sure normals point out on source sphere // morphedSourceDeformationSphere->orientNormalsOut(); // // Check for crossovers // updateProgressDialog("Checking for Crossovers"); int numNodeCrossovers, numTileCrossovers; morphedSourceDeformationSphere->crossoverCheck(numTileCrossovers, numNodeCrossovers, BrainModelSurface::SURFACE_TYPE_SPHERICAL); crossoverCount.push_back(numNodeCrossovers); // // If the last cycle alert user if there are crossovers // if (cycle == deformationMapFile->getSphericalNumberOfCycles(0)) { bool anyCrossoversFlag = false; for (unsigned int i = 0; i < crossoverCount.size(); i++) { if (crossoverCount[i] > 0) { anyCrossoversFlag = true; break; } } if (anyCrossoversFlag > 0) { QWidget* parent = brainSet->getProgressDialogParent(); if (parent != NULL) { QString msg; for (int i = (crossoverCount.size() - 1); i >= 0; i--) { std::ostringstream str; str << "Cycle " << (i + 1) << " had " << crossoverCount[i] << " crossovers.\n"; msg.append(str.str().c_str()); } msg.append("\nContinue Deformation ?"); QApplication::restoreOverrideCursor(); QApplication::beep(); if (QMessageBox::warning(parent, "Crossover Alert", msg, "Yes", "No") != 0) { throw BrainModelAlgorithmException("Deformation terminated by user."); } //will not compile on mac - don't know why QApplication::setOverrideCursor(waitCursor); } } } // // Project the user's sphere from the original source deformation sphere to // the target deformation sphere // updateProgressDialog("Creating Deformed Coordinate File"); createDeformedCoordinateFile(cycle); // // If this is not the last cycle // if (cycle < deformationMapFile->getSphericalNumberOfCycles(0)) { // // Update the source borders for the next cycle // updateProgressDialog("Updating Borders for Next Cycle"); updateSourceBordersForNextCycle(); // // Make input spherical coordinate file the one that was just deformed // const QString coordName = sourceSurface->getCoordinateFile()->getFileName(); sourceSurface = deformedSourceSurface; sourceSurface->getCoordinateFile()->setFileName(coordName); } } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceDeformationMultiStageSphericalVector.h0000664000175000017500000001455611572067322032623 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef _BRAIN_MODEL_SURFACE_DEFORMATION_MULTI_STAGE_SPHERICAL_VECTOR_H #define _BRAIN_MODEL_SURFACE_DEFORMATION_MULTI_STAGE_SPHERICAL_VECTOR_H #include "BrainModelSurfaceDeformation.h" #include "SurfaceShapeFile.h" class BrainModelSurface; class DeformationMapFile; class BrainModelSurfaceDeformationMultiStageSphericalVector : public BrainModelSurfaceDeformation { public: /// Constructor BrainModelSurfaceDeformationMultiStageSphericalVector(BrainSet* brainSetIn, DeformationMapFile* DeformationMapFileIn); /// Destructor ~BrainModelSurfaceDeformationMultiStageSphericalVector(); protected: /// Execute the deformation void executeDeformation() throw (BrainModelAlgorithmException); // Perform landmark constrained morphing on the sphere with source landmarks void landmarkMorphContrainedSource(BrainModelSurface* referenceDeformationSphere, const int stageNumber, const int cycleIndex) throw (BrainModelAlgorithmException); /// Perform landmark neighbor constrained smoothing on the sphere with source landmarks void landmarkNeighborConstrainedSmoothSource(const int stageIndex, const int cycleNumber); /// Get a regularly tessellated sphere and set its radius. BrainModelSurface* getRegularSphere(BrainSet* bs, const int stageIndex, const float radius) throw (BrainModelAlgorithmException); /// tessellate the target border into the target deformation sphere void tessellateTargetBordersIntoDeformationSphere(const int stageIndex) throw (BrainModelAlgorithmException); /// tessellate the source border into the source deformation sphere void tessellateSourceBordersIntoDeformationSphere(const int stageIndex) throw (BrainModelAlgorithmException); /// create the deformed coordinate file at the end of each cycle BrainModelSurface* createDeformedCoordinateFile(BrainModelSurface* sourceDeformationSphere, BrainModelSurface* registeredDeformationSourceSphere, const int stageIndex, const int cycleNumber, const QString& usersSourceCoordFileName); /// write a border file containing the deformed landmarks BorderFile* writeSourceBorderLandmarkFile(BrainModelSurface* surface, const int stageIndex, const int cycleNumber); /// write coords without the landmarks void writeCoordinatesWithoutLandmarks(BrainModelSurface* surface, const int stageIndex, const int cycleNumber); /// create the surface shape file containing the XYZ differences SurfaceShapeFile* createDifferenceShapeFile(int iterations); /// determine the fiducial sphere distortion void determineFiducialSphereDistortion(); /// update the fiducial sphere distortion void updateSphereFiducialDistortion(const int stageIndex, const int cycle, BrainModelSurface* morphedSourceDeformationSphere); /// Determine distortion ratio of fiducial vs spherical tile areas. void determineSphericalDistortion(const BrainModelSurface* fiducialSurface, const BrainModelSurface* sphericalSurface, std::vector& tileDistortion); /// move the landmark nodes to the average of their neighboring nodes void moveLandmarksToAverageOfNeighbors(BrainModelSurface* bms); /// the target deformation sphere BrainModelSurface* targetDeformationSphere; /// the source deformation sphere BrainModelSurface* sourceDeformationSphere; /// the reference source deformation sphere BrainModelSurface* referenceSourceDeformationSphere; /// the source surface operated on in this type of deformation BrainModelSurface* workingSourceSurface; /// the number of nodes in the regularly tessellated sphere prior to inserting landmarks int originalNumberOfNodes; /// keeps track of borders that are tessellated into the deformation sphere std::vector > usedBorderLinks; /// target file naming prefix for debugging QString debugTargetFileNamePrefix; /// source file naming prefix for debugging QString debugSourceFileNamePrefix; /// radius of the deformation sphere float deformationSphereRadius; /// keeps track of landmark nodes std::vector landmarkNodeFlags; /// the target brain set BrainSet* targetDeformationBrainSet; /// Keep track of distortion SurfaceShapeFile fiducialSphereDistortion; /// ratio of target fiducial and spherical tile areas std::vector targetTileDistortion; /// ratio of source fiducial and spherical tile areas std::vector sourceTileDistortion; /// shape file containing border variances for the landmark nodes SurfaceShapeFile borderVarianceValuesShapeFile; }; #endif // _BRAIN_MODEL_SURFACE_DEFORMATION_MULTI_STAGE_SPHERICAL_VECTOR_H caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceDeformationMultiStageSphericalVector.cxx0000664000175000017500000022625611572067322033200 0ustar michaelmichael#include #include "BrainModelSurfaceDeformDataFile.h" #include #include #include #include #include #include "AreaColorFile.h" #include "BorderFile.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceDeformationMultiStageSphericalVector.h" #include "BrainModelSurfaceMetricSmoothing.h" #include "BrainModelSurfaceMorphing.h" #include "BrainModelSurfaceNodeColoring.h" #include "BrainModelSurfacePointProjector.h" #include "BrainSet.h" #include "ColorFile.h" #include "DebugControl.h" #include "DeformationMapFile.h" #include "FileUtilities.h" #include "MathUtilities.h" #include "PaintFile.h" #include "StringUtilities.h" #include "TopologyHelper.h" //static const int morphAngleForceAlgorithm = 1; /** * Constructor. */ BrainModelSurfaceDeformationMultiStageSphericalVector::BrainModelSurfaceDeformationMultiStageSphericalVector( BrainSet* brainSetIn, DeformationMapFile* deformationMapFileIn) : BrainModelSurfaceDeformation(brainSetIn, deformationMapFileIn) { targetDeformationBrainSet = NULL; workingSourceSurface = NULL; } /** * Destructor. */ BrainModelSurfaceDeformationMultiStageSphericalVector::~BrainModelSurfaceDeformationMultiStageSphericalVector() { if (targetDeformationBrainSet != NULL) { delete targetDeformationBrainSet; targetDeformationBrainSet = NULL; } //if (workingSourceSurface != NULL) { // delete workingSourceSurface; // workingSourceSurface = NULL; //} } /** * Determine distortion ratio of fiducial vs spherical tile areas. */ void BrainModelSurfaceDeformationMultiStageSphericalVector::determineSphericalDistortion( const BrainModelSurface* fiducialSurface, const BrainModelSurface* sphericalSurface, std::vector& tileDistortion) { // // Get topology file and number of tiles // const TopologyFile* tf = sphericalSurface->getTopologyFile(); const int numTiles = tf->getNumberOfTiles(); tileDistortion.resize(numTiles); // // Get the coordinate files // const CoordinateFile* fiducialCoords = fiducialSurface->getCoordinateFile(); const CoordinateFile* sphericalCoords = sphericalSurface->getCoordinateFile(); // // Determine fiducial/spherical area ratio of tiles // for (int i = 0; i < numTiles; i++) { int v1, v2, v3; tf->getTile(i, v1, v2, v3); const float sphereArea = MathUtilities::triangleArea((float*)sphericalCoords->getCoordinate(v1), (float*)sphericalCoords->getCoordinate(v2), (float*)sphericalCoords->getCoordinate(v3)); tileDistortion[i] = 1.0; if (sphereArea != 0.0) { const float fidArea = MathUtilities::triangleArea((float*)fiducialCoords->getCoordinate(v1), (float*)fiducialCoords->getCoordinate(v2), (float*)fiducialCoords->getCoordinate(v3)); tileDistortion[i] = fidArea / sphereArea; } } } /** * Determine the fiducial sphere distortion. */ void BrainModelSurfaceDeformationMultiStageSphericalVector::determineFiducialSphereDistortion() { // // Create a point projector for projecting the deformation sphere nodes // onto the target surface // BrainModelSurfacePointProjector bspp(targetSurface, BrainModelSurfacePointProjector::SURFACE_TYPE_HINT_SPHERE, false); const int numTargetTiles = static_cast(targetTileDistortion.size()); // // Project each node in the deformation sphere // const int numNodes = targetDeformationSphere->getNumberOfNodes(); const CoordinateFile* targetDeformationCoords = targetDeformationSphere->getCoordinateFile(); for (int i = 0; i < numNodes; i++) { float xyz[3]; targetDeformationCoords->getCoordinate(i, xyz); // // Project target node onto source deformed surface // int nearestNode = -1; int tileNodes[3]; float tileAreas[3]; const int tile = bspp.projectBarycentric(xyz, nearestNode, tileNodes, tileAreas, true); // // Did it project ? // if ((tile >= 0) && (tile < numTargetTiles)) { fiducialSphereDistortion.setValue(i, 0, targetTileDistortion[tile]); } else { fiducialSphereDistortion.setValue(i, 0, 1.0); } } } /** * Update the fiducial sphere distortion. */ void BrainModelSurfaceDeformationMultiStageSphericalVector::updateSphereFiducialDistortion( const int stageIndex, const int cycleIndex, BrainModelSurface* morphedSourceDeformationSphere) { // // Create a point projector for projecting the source deformation sphere // nodes to the original source surface // BrainModelSurfacePointProjector bspp(workingSourceSurface, BrainModelSurfacePointProjector::SURFACE_TYPE_HINT_SPHERE, false); // // Project deformation sphere nodes onto original source surface // const int numNodes = morphedSourceDeformationSphere->getNumberOfNodes(); const CoordinateFile* coords = morphedSourceDeformationSphere->getCoordinateFile(); const int numSourceTiles = static_cast(sourceTileDistortion.size()); for (int i = 0; i < numNodes; i++) { float xyz[3]; coords->getCoordinate(i, xyz); // // Project target node onto source deformed surface // int nearestNode = -1; int tileNodes[3]; float tileAreas[3]; const int tile = bspp.projectBarycentric(xyz, nearestNode, tileNodes, tileAreas, true); // // Did it project ? // if ((tile >= 0) && (tile < numSourceTiles)) { fiducialSphereDistortion.setValue(i, 1, sourceTileDistortion[tile]); } else { fiducialSphereDistortion.setValue(i, 1, 1.0); } fiducialSphereDistortion.setValue(i, 2, std::sqrt(fiducialSphereDistortion.getValue(i, 1) / fiducialSphereDistortion.getValue(i, 0))); } // // Save the surface shape file // std::ostringstream str; str << "targetFiducialSphereDistortion" << "_stage_" << stageIndex + 1 << "_cycle_" << cycleIndex + 1 << SpecFile::getSurfaceShapeFileExtension().toAscii().constData(); fiducialSphereDistortion.writeFile(str.str().c_str()); //brainSet->addToSpecFile(SpecFile::getSurfaceShapeFileTag(), str.str().c_str()); intermediateFiles.push_back(str.str().c_str()); } /** * Load the regularly tessellated sphere and set its radius. */ BrainModelSurface* BrainModelSurfaceDeformationMultiStageSphericalVector::getRegularSphere(BrainSet* bs, const int stageIndex, const float radius) throw (BrainModelAlgorithmException) { // // Construct the regular sphere file name // QString specFileName(bs->getCaretHomeDirectory()); specFileName.append("/"); specFileName.append("data_files/REGISTER.LVD.SPHERE"); specFileName.append("/"); switch(deformationMapFile->getSphereResolution(stageIndex)) { case 20: throw BrainModelAlgorithmException( "Resolution 20 not available for Multi-Stage Vector Deformation"); break; case 74: specFileName.append("sphere.1.LVD.74.spec"); break; case 290: specFileName.append("sphere.2.LVD.290.spec"); break; case 1154: specFileName.append("sphere.3.LVD.1154.spec"); break; case 4610: specFileName.append("sphere.4.LVD.4610.spec"); break; case 18434: specFileName.append("sphere.5.LVD.18434.spec"); break; case 73730: specFileName.append("sphere.6.LVD.73730.spec"); break; default: { std::ostringstream str; str << "Invalid sphere resolution: " << deformationMapFile->getSphereResolution(stageIndex); throw BrainModelAlgorithmException(str.str().c_str()); } break; } // // Read the spec file // SpecFile sf; try { sf.readFile(specFileName); } catch (FileException& e) { throw BrainModelAlgorithmException(e.whatQString()); } sf.setAllFileSelections(SpecFile::SPEC_TRUE); // // Read the spec file into "this" brain set (use APPEND for source sphere) // std::vector errorMessages; bs->readSpecFile(BrainSet::SPEC_FILE_READ_MODE_NORMAL, sf, specFileName, errorMessages, NULL, NULL); if (errorMessages.empty() == false) { QString msg("Error reading data files for "); msg.append(specFileName); msg.append("\n"); msg.append(StringUtilities::combine(errorMessages, "\n")); throw BrainModelAlgorithmException(msg); } // // Get the spherical surface and set its radius // BrainModelSurface* sphereSurface = bs->getBrainModelSurface(0); if (sphereSurface == NULL) { throw BrainModelAlgorithmException("Regular sphere spec contained no coord file."); } sphereSurface->convertToSphereWithRadius(radius); sphereSurface->updateForDefaultScaling(); updateViewingTransformation(bs); return sphereSurface; } /** * Tessellate the target border into the target deformation sphere */ void BrainModelSurfaceDeformationMultiStageSphericalVector::tessellateTargetBordersIntoDeformationSphere( const int stageIndex) throw (BrainModelAlgorithmException) { // // empty contents of the used and ignored border links // usedBorderLinks.clear(); // // Create a Point Projector with nodes to be added for the deformation sphere. // BrainModelSurfacePointProjector bspp(targetDeformationSphere, BrainModelSurfacePointProjector::SURFACE_TYPE_HINT_SPHERE, true); TopologyFile* tf = targetDeformationSphere->getTopologyFile(); // // Project each border link into the deformation sphere // const int numBorders = targetBorderFile->getNumberOfBorders(); for (int i = 0; i < numBorders; i++) { const Border* b = targetBorderFile->getBorder(i); const int numLinks = b->getNumberOfLinks(); for (int j = 0; j < numLinks; j++) { const float* xyz = b->getLinkXYZ(j); // // Project target node onto source deformed surface // int nearestNode = -1; int tileNodes[3]; float tileAreas[3]; const int tile = bspp.projectBarycentric(xyz, nearestNode, tileNodes, tileAreas, true); const int newNodeNumber = targetDeformationSphere->getNumberOfNodes(); // // Unproject using the deformed source coordinate file // if (tile >= 0) { // // Get the tile // int v1, v2, v3; tf->getTile(tile, v1, v2, v3); // // Create two new tiles // const int tn1[3] = { v1, v2, newNodeNumber }; const int tn2[3] = { v2, v3, newNodeNumber }; const int tn3[3] = { v3, v1, newNodeNumber }; // // Replace the original tile and create two new ones // tf->setTile(tile, tn1); tf->addTile(tn2); tf->addTile(tn3); // // Add the node to the surface // targetDeformationSphere->addNode(xyz); // // Keep track of border link assignments // usedBorderLinks.push_back(std::make_pair(i, j)); } else { if (nearestNode >= 0) { std::cout << "Border link with closest node ignored: " << i << " " << j << std::endl; } else { std::cout << "Border link without closest node ignored: " << i << " " << j << std::endl; } } } } const int numNodes = targetDeformationSphere->getNumberOfNodes(); if (numNodes == originalNumberOfNodes) { throw BrainModelAlgorithmException("Tessellating in border nodes failed."); } // // Make sure all nodes are on the sphere // targetDeformationSphere->convertToSphereWithRadius(deformationSphereRadius); // // Update the surface's normals and update node attributes for changes in nodes. // targetDeformationSphere->computeNormals(); targetDeformationBrainSet->resetNodeAttributes(); QString targetNamePrefix("target_withLandmarks_stage" + QString::number(stageIndex + 1) + ".LVD"); // // Create the spec file name // QString specFileName = targetNamePrefix + SpecFile::getSpecFileExtension(); targetDeformationBrainSet->setSpecFileName(specFileName); intermediateFiles.push_back(specFileName); targetDeformationBrainSet->removeCoordAndTopoFromSpecFile(); // // Setup the paint file that shows the landmark nodes // PaintFile* pf = targetDeformationBrainSet->getPaintFile(); pf->setNumberOfNodesAndColumns(numNodes, 1); pf->setColumnName(0, "Landmarks"); const int nonLandmarkPaintIndex = pf->addPaintName("???"); const int landmarkPaintIndex = pf->addPaintName("Landmark"); for (int i = 0; i < numNodes; i++) { if (i < originalNumberOfNodes) { pf->setPaint(i, 0, nonLandmarkPaintIndex); } else { pf->setPaint(i, 0, landmarkPaintIndex); } } QString paintFileName(targetNamePrefix + SpecFile::getPaintFileExtension()); targetDeformationBrainSet->writePaintFile(paintFileName); intermediateFiles.push_back(paintFileName); // // Setup the node color file // AreaColorFile* cf = targetDeformationBrainSet->getAreaColorFile(); cf->addColor("Landmark", 255, 0, 0, 2, 1); cf->addColor("???", 170, 170, 170, 2, 1); QString nodeColorFileName(targetNamePrefix + SpecFile::getAreaColorFileExtension()); targetDeformationBrainSet->writeAreaColorFile(nodeColorFileName); intermediateFiles.push_back(nodeColorFileName); // // Write the topology file // QString topoFileName(targetNamePrefix + SpecFile::getTopoFileExtension()); targetDeformationBrainSet->writeTopologyFile(topoFileName, TopologyFile::TOPOLOGY_TYPE_CLOSED, tf); intermediateFiles.push_back(topoFileName); // // Set node coloring overlay to paint // BrainModelSurfaceNodeColoring* bsnc = targetDeformationBrainSet->getNodeColoring(); targetDeformationBrainSet->getPrimarySurfaceOverlay()->setOverlay(-1, BrainModelSurfaceOverlay::OVERLAY_PAINT); bsnc->assignColors(); // // Update the displayed surface // targetDeformationSphere->orientTilesConsistently(); targetDeformationSphere->computeNormals(); this->updateViewingTransformation(targetDeformationBrainSet); targetDeformationSphere->updateForDefaultScaling(); targetDeformationBrainSet->drawBrainModel(targetDeformationSphere); // // Write the sphere with target landmarks // QString coordFileName(targetNamePrefix + SpecFile::getCoordinateFileExtension()); targetDeformationBrainSet->writeCoordinateFile(coordFileName, BrainModelSurface::SURFACE_TYPE_SPHERICAL, targetDeformationSphere->getCoordinateFile()); intermediateFiles.push_back(coordFileName); } /** * Tessellate the source border into the target deformation sphere */ void BrainModelSurfaceDeformationMultiStageSphericalVector::tessellateSourceBordersIntoDeformationSphere( const int stageIndex) throw (BrainModelAlgorithmException) { int numNodeCrossovers = 0; int numTileCrossovers = 0; sourceDeformationSphere->crossoverCheck(numTileCrossovers, numNodeCrossovers, BrainModelSurface::SURFACE_TYPE_SPHERICAL); if (numNodeCrossovers > 0) { std::cout << "WARNING: Source deformation sphere contains crossovers " "PRIOR to insertion of landmarks." << std::endl; } // // Create the surface shape file containing the border variances // Use target BrainSet for number of nodes since it has landmarks // inserted so that number of nodes is correct. // borderVarianceValuesShapeFile.setNumberOfNodesAndColumns(targetBrainSet->getNumberOfNodes(), 1); borderVarianceValuesShapeFile.setColumnName(0, "Border Variances"); float endpointFactor = 1.0; this->deformationMapFile->getLandmarkVectorStageParameters(stageIndex, endpointFactor); // // Create a Point Projector with nodes to be added for the deformation sphere. // BrainModelSurfacePointProjector bspp(sourceDeformationSphere, BrainModelSurfacePointProjector::SURFACE_TYPE_HINT_SPHERE, true); TopologyFile* tf = sourceDeformationSphere->getTopologyFile(); // // Project each border link into the deformation sphere // const int numBorderLinks = static_cast(usedBorderLinks.size()); for (int i = 0; i < numBorderLinks; i++) { std::pair borderLinkNums = usedBorderLinks[i]; const int borderNumber = borderLinkNums.first; const int linkNumber = borderLinkNums.second; const Border* targetBorder = targetBorderFile->getBorder(borderNumber); const QString borderName = targetBorder->getName(); const Border* sourceBorder = sourceBorderFile->getBorderByName(borderName); if (sourceBorder == NULL) { throw BrainModelAlgorithmException( "Unable to find source border named \"" + borderName + "\""); } bool projectedFlag = false; // // Source border coordinate // float xyz[3]; sourceBorder->getLinkXYZ(linkNumber, xyz); // // Identify first and last links in borders // bool endPointFlag = false; const int iPrevious = i - 1; if (iPrevious >= 0) { // // If the previous border number is different, this is the first link // const int bnum = usedBorderLinks[iPrevious].first; if (bnum != borderNumber) { endPointFlag = true; } } else { // // No previous border, then this is first link in first border // endPointFlag = true; } const int iNext = i + 1; if (iNext < numBorderLinks) { // // If the next border number is different, this is the last link // const int bnum = usedBorderLinks[iNext].first; if (bnum != borderNumber) { endPointFlag = true; } } else { // // No next border, then this is the last link in the last border // endPointFlag = true; } //if (endPointFlag) { // std::cout << "Border " // << borderNumber // << " link " // << linkNumber // << " is an endpoint." // << std::endl; //} // // Projecting may fail in some cases so perturb when there is a failure // const int iTestMaximum = 10; for (int iTest = 0; iTest < iTestMaximum; iTest++) { // // Project target node onto source deformed surface // int nearestNode = -1; int tileNodes[3]; float tileAreas[3]; // // perturb if problems projecting // if (iTest > 0) { std::cout << "Moving source border point due to projection failure: " << borderName.toAscii().constData() << " link " << linkNumber << " (" << xyz[0] << "," << xyz[1] << "," << xyz[2] << ")" << std::endl; xyz[0] += 0.001; xyz[1] += 0.001; xyz[2] += 0.001; } const int tile = bspp.projectBarycentric(xyz, nearestNode, tileNodes, tileAreas, true); const int newNodeNumber = sourceDeformationSphere->getNumberOfNodes(); // // Unproject using the deformed source coordinate file // if (tile >= 0) { // // Get the tile // int v1, v2, v3; tf->getTile(tile, v1, v2, v3); // // Create two new tiles and replace the file node is within // const int tn1[3] = { v1, v2, newNodeNumber }; const int tn2[3] = { v2, v3, newNodeNumber }; const int tn3[3] = { v3, v1, newNodeNumber }; // // Replace the original tile and create two new ones // tf->setTile(tile, tn1); tf->addTile(tn2); tf->addTile(tn3); // // Add the node to the surface // sourceDeformationSphere->addNode(xyz); // // Update the border variance shape file // int nodeNum = sourceDeformationSphere->getNumberOfNodes() - 1; float variance = targetBorder->getVariance(); if (endPointFlag) { variance *= endpointFactor; } this->borderVarianceValuesShapeFile.setValue(nodeNum, 0, variance); if (DebugControl::getDebugOn()) { std::cout << targetBorder->getName().toAscii().constData() << " variance: " << targetBorder->getVariance() << std::endl; } projectedFlag = true; // // Get out of loop // iTest = iTestMaximum + 1; } } if (projectedFlag == false) { throw BrainModelAlgorithmException( "Unable to tessellate border " + borderName + " link " + linkNumber + " into source surface."); } } // // Make sure all nodes are on the sphere // sourceDeformationSphere->convertToSphereWithRadius(deformationSphereRadius); // // Update the surface's normals and update node attributes for changes in nodes. // sourceDeformationSphere->orientNormalsOut(); sourceDeformationSphere->computeNormals(); brainSet->resetNodeAttributes(); // // Smooth a tiny bit as some landmark nodes may be essentially on an edge // sourceDeformationSphere->arealSmoothing(0.5, 1, 0); sourceDeformationSphere->convertToSphereWithRadius(deformationSphereRadius); sourceDeformationSphere->crossoverCheck(numTileCrossovers, numNodeCrossovers, BrainModelSurface::SURFACE_TYPE_SPHERICAL); if (numNodeCrossovers > 0) { std::cout << "WARNING: Source deformation sphere contains crossovers " "AFTER insertion of landmarks." << std::endl; } QString sourceNamePrefix("source_withLandmarks_Stage_" + QString::number(stageIndex + 1) + ".LVD"); // // Create the spec file name // QString specFileName = sourceNamePrefix + SpecFile::getSpecFileExtension(); brainSet->setSpecFileName(specFileName); intermediateFiles.push_back(specFileName); brainSet->removeCoordAndTopoFromSpecFile(); // // Setup the paint file that shows the landmark nodes // int numNodes = brainSet->getNumberOfNodes(); PaintFile* pf = brainSet->getPaintFile(); pf->setNumberOfNodesAndColumns(numNodes, 1); pf->setColumnName(0, "Landmarks"); const int nonLandmarkPaintIndex = pf->addPaintName("???"); const int landmarkPaintIndex = pf->addPaintName("Landmark"); for (int i = 0; i < numNodes; i++) { if (i < originalNumberOfNodes) { pf->setPaint(i, 0, nonLandmarkPaintIndex); } else { pf->setPaint(i, 0, landmarkPaintIndex); } } QString paintFileName(sourceNamePrefix + SpecFile::getPaintFileExtension()); brainSet->writePaintFile(paintFileName); intermediateFiles.push_back(paintFileName); // // Setup the node color file // AreaColorFile* cf = brainSet->getAreaColorFile(); cf->addColor("Landmark", 255, 0, 0, 2, 1); cf->addColor("???", 170, 170, 170, 2, 1); QString nodeColorFileName(sourceNamePrefix + SpecFile::getAreaColorFileExtension()); brainSet->writeAreaColorFile(nodeColorFileName); intermediateFiles.push_back(nodeColorFileName); // // Write the topology file // QString topoFileName(sourceNamePrefix + SpecFile::getTopoFileExtension()); brainSet->writeTopologyFile(topoFileName, TopologyFile::TOPOLOGY_TYPE_CLOSED, tf); intermediateFiles.push_back(topoFileName); // // Write the sphere with target landmarks // QString coordFileName(sourceNamePrefix + SpecFile::getCoordinateFileExtension()); brainSet->writeCoordinateFile(coordFileName, BrainModelSurface::SURFACE_TYPE_SPHERICAL, sourceDeformationSphere->getCoordinateFile()); intermediateFiles.push_back(coordFileName); // // Update the displayed surface // sourceDeformationSphere->orientTilesConsistently(); sourceDeformationSphere->computeNormals(); this->updateViewingTransformation(brainSet); sourceDeformationSphere->updateForDefaultScaling(); brainSet->drawBrainModel(sourceDeformationSphere); sourceDeformationSphere = new BrainModelSurface(*sourceDeformationSphere); brainSet->addBrainModel(sourceDeformationSphere); // // Save the border variance shape file // const QString shapeFileName("source_withLandmarksBorderVariance_stage" + QString::number(stageIndex + 1) + SpecFile::getSurfaceShapeFileExtension()); borderVarianceValuesShapeFile.writeFile(shapeFileName); intermediateFiles.push_back(shapeFileName); brainSet->addToSpecFile(SpecFile::getSurfaceShapeFileTag(), shapeFileName); } /** * move the landmark nodes to the average of their neighboring nodes. */ void BrainModelSurfaceDeformationMultiStageSphericalVector::moveLandmarksToAverageOfNeighbors(BrainModelSurface* bms) { const TopologyHelper* th = bms->getTopologyFile()->getTopologyHelper(false, true, false); CoordinateFile* cf = bms->getCoordinateFile(); int numNodes = bms->getNumberOfNodes(); for (int i = originalNumberOfNodes; i < numNodes; i++) { int numNeighbors = 0; const int* neighbors = th->getNodeNeighbors(i, numNeighbors); float sumXYZ[3] = { 0.0, 0.0, 0.0 }; for (int j = 0; j < numNeighbors; j++) { const float* xyz = cf->getCoordinate(neighbors[j]); sumXYZ[0] += xyz[0]; sumXYZ[1] += xyz[1]; sumXYZ[2] += xyz[2]; } const float avgXYZ[3] = { sumXYZ[0] / numNeighbors, sumXYZ[1] / numNeighbors, sumXYZ[2] / numNeighbors }; cf->setCoordinate(i, avgXYZ); } bms->convertToSphereWithRadius(deformationSphereRadius); } /** * create the surface shape file containing the XYZ differences of the * nodes in the target and source surfaces. Note that only the landmark * nodes have their differences set; the original nodes have a difference * of zero. */ SurfaceShapeFile* BrainModelSurfaceDeformationMultiStageSphericalVector::createDifferenceShapeFile(int iterations) { int numNodes = targetDeformationSphere->getNumberOfNodes(); SurfaceShapeFile* ssf = brainSet->getSurfaceShapeFile(); ssf->clear(); ssf->setNumberOfNodesAndColumns(numNodes, 9); ssf->setColumnName(0, "dX"); ssf->setColumnName(1, "dY"); ssf->setColumnName(2, "dZ"); ssf->setColumnName(3, "dX * Border Variance"); ssf->setColumnName(4, "dY * Border Variance"); ssf->setColumnName(5, "dZ * Border Variance"); ssf->setColumnName(6, "dX Smoothed"); ssf->setColumnName(7, "dY Smoothed"); ssf->setColumnName(8, "dZ Smoothed"); const CoordinateFile* sourceCoords = sourceDeformationSphere->getCoordinateFile(); const CoordinateFile* targetCoords = targetDeformationSphere->getCoordinateFile(); for (int i = originalNumberOfNodes; i < numNodes; i++) { const float* sxyz = sourceCoords->getCoordinate(i); const float* txyz = targetCoords->getCoordinate(i); float dxyz[3] = { txyz[0] - sxyz[0], txyz[1] - sxyz[1], txyz[2] - sxyz[2] }; // // Displacement // ssf->setValue(i, 0, dxyz[0]); ssf->setValue(i, 1, dxyz[1]); ssf->setValue(i, 2, dxyz[2]); // // Modify displacement using border variance // const float borderVariance = this->borderVarianceValuesShapeFile.getValue(i, 0); if (borderVariance != 0.0) { dxyz[0] *= borderVariance; dxyz[1] *= borderVariance; dxyz[2] *= borderVariance; } // // Displacement multiplied by variance // ssf->setValue(i, 3, dxyz[0]); ssf->setValue(i, 4, dxyz[1]); ssf->setValue(i, 5, dxyz[2]); // // If no smoothing iterations, set smoothed values // if (iterations <= 0) { ssf->setValue(i, 6, dxyz[0]); ssf->setValue(i, 7, dxyz[1]); ssf->setValue(i, 8, dxyz[2]); } } // // Smooth the columns // if (iterations > 0) { float strength = 0.5; for (int j = 3; j < 6; j++) { BrainModelSurfaceMetricSmoothing bmsms(brainSet, sourceDeformationSphere, sourceDeformationSphere, ssf, BrainModelSurfaceMetricSmoothing::SMOOTH_ALGORITHM_AVERAGE_NEIGHBORS, j, j + 3, (ssf->getColumnName(j) + " Smoothed"), strength, iterations, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.0); bmsms.execute(); } } return ssf; } /** * Perform landmark neighbor constrained smoothing on the sphere with source landmarks. */ void BrainModelSurfaceDeformationMultiStageSphericalVector::landmarkNeighborConstrainedSmoothSource( const int stageIndex, const int cycleIndex) { // // Get smoothing parameters for this cycle // float strength; int numCycles, numIterations, neighborIterations, numFinalIterations; deformationMapFile->getSmoothingParameters(stageIndex, cycleIndex, strength, numCycles, numIterations, neighborIterations, numFinalIterations); if (numCycles <= 0) { return; } // // perform number of smoothing cycles // for (int i = 0; i < numCycles; i++) { // // Perform the landmark constrained smoothing // updateViewingTransformation(sourceDeformationSphere); sourceDeformationSphere->landmarkNeighborConstrainedSmoothing(strength, numIterations, landmarkNodeFlags, neighborIterations, 0); // // push non-landmark nodes back onto the sphere // sourceDeformationSphere->convertToSphereWithRadius(deformationSphereRadius, 0, originalNumberOfNodes); } // // Perform final smoothing // sourceDeformationSphere->arealSmoothing(strength, numFinalIterations, 0); // // push all nodes back onto the sphere // sourceDeformationSphere->convertToSphereWithRadius(deformationSphereRadius); sourceDeformationSphere->updateForDefaultScaling(); updateViewingTransformation(sourceDeformationSphere); } /** * Perform landmark constrained morphing on the sphere with source landmarks */ void BrainModelSurfaceDeformationMultiStageSphericalVector::landmarkMorphContrainedSource( BrainModelSurface* referenceDeformationSphere, const int stageIndex, const int cycleIndex) throw (BrainModelAlgorithmException) { if (DebugControl::getDebugOn()) { std::cout << "Landmark Constrained Morphing Cycle " << (cycleIndex + 1) << std::endl; std::cout << " REF: " << referenceDeformationSphere->getCoordinateFile()->getFileNameNoPath().toAscii().constData() << std::endl; } // // Get smoothing parameters for this cycle (just need strength) // float strength; int numCycles, numIterations, neighborIterations, numFinalIterations; deformationMapFile->getSmoothingParameters(stageIndex, cycleIndex, strength, numCycles, numIterations, neighborIterations, numFinalIterations); // // Get the morphing paramters for this cycle // float linearForce, angularForce, stepSize, landmarkStepSize; int numMorphCycles, iterations, smoothIterations; deformationMapFile->getMorphingParameters(stageIndex, cycleIndex, numMorphCycles, linearForce, angularForce, stepSize, landmarkStepSize, iterations, smoothIterations); // // If morphing should be performed // if (numMorphCycles > 0) { // // NON-landmark nodes are morphed // const int numNodes = sourceDeformationSphere->getNumberOfNodes(); std::vector morphNodeFlag(numNodes); for (int i = 0; i < numNodes; i++) { morphNodeFlag[i] = ( ! landmarkNodeFlags[i]); } // // Get fiducial sphere ratio settings // bool useFiducialSphereRatios = false; float fiducialSphereRatioStrength = 0.5; deformationMapFile->getSphereFiducialRatio(useFiducialSphereRatios, fiducialSphereRatioStrength); std::vector fiducialSphereRatios; if (useFiducialSphereRatios) { // // Use fiducial/sphere distortion except on first cycle // if (cycleIndex > 0) { const int numNodes = fiducialSphereDistortion.getNumberOfNodes(); fiducialSphereRatios.resize(numNodes); for (int i = 0; i < numNodes; i++) { fiducialSphereRatios[i] = fiducialSphereDistortion.getValue(i, 2); } } } // // Morph for the specified number of cycles // for (int morphCycle = 0; morphCycle < numMorphCycles; morphCycle++) { // // Create the morphing object and set parameters // BrainModelSurfaceMorphing bmsm(brainSet, referenceDeformationSphere, sourceDeformationSphere, BrainModelSurfaceMorphing::MORPHING_SURFACE_SPHERICAL); bmsm.setMorphingParameters(iterations, linearForce, angularForce, stepSize); bmsm.setNodesThatShouldBeMorphed(morphNodeFlag, landmarkStepSize); if (fiducialSphereRatios.size() > 0) { if (useFiducialSphereRatios) { bmsm.setFiducialSphereDistortionCorrections(fiducialSphereRatios, fiducialSphereRatioStrength); } } // // execute the morphing // bmsm.execute(); // // Perform a little bit of normal smoothing // sourceDeformationSphere->arealSmoothing(strength, smoothIterations, 0); // // Move landmarks to average of neighbors 5/20/09 // this->moveLandmarksToAverageOfNeighbors(sourceDeformationSphere); // // Push nodes back to sphere and draw // sourceDeformationSphere->convertToSphereWithRadius(deformationSphereRadius); // // Draw the surface // sourceDeformationSphere->orientTilesConsistently(); sourceDeformationSphere->computeNormals(); sourceDeformationSphere->updateForDefaultScaling(); updateViewingTransformation(brainSet); brainSet->drawBrainModel(sourceDeformationSphere); } // // Save the surface // //QString coordFileName(debugSourceFileNamePrefix); //coordFileName.append("_withLandmarks_morphed"); //coordFileName.append(SpecFile::getCoordinateFileExtension()); //brainSet->writeCoordinateFile(coordFileName, BrainModelSurface::SURFACE_TYPE_SPHERICAL, // sourceDeformationSphere->getCoordinateFile()); //intermediateFiles.push_back(coordFileName); // // Draw the surface // sourceDeformationSphere->orientTilesConsistently(); sourceDeformationSphere->computeNormals(); sourceDeformationSphere->updateForDefaultScaling(); this->updateViewingTransformation(brainSet); brainSet->drawBrainModel(sourceDeformationSphere); } } /** * Deform the source sphere using the source and target deformation spheres * Returns the deformed surface */ BrainModelSurface* BrainModelSurfaceDeformationMultiStageSphericalVector::createDeformedCoordinateFile( BrainModelSurface* originalSourceDeformationSphere, BrainModelSurface* registeredDeformationSourceSphere, const int stageIndex, const int cycleNumber, const QString& usersSourceCoordFileName) { try { const int stageNumber = stageIndex + 1; bool lastCycleFlag = (cycleNumber >= this->deformationMapFile->getSphericalNumberOfCycles(stageIndex)); //bool lastStageFlag = // (stageNumber >= this->deformationMapFile->getSphericalNumberOfStages()); BrainModelSurface* usersSourceSurface = workingSourceSurface; // 17jun2009 if (lastCycleFlag) { usersSourceSurface = sourceSurface; //} if (lastCycleFlag) { // // Check for crossovers in source deformation sphere // int sourceTileCrossoversCount = 0; int sourceNodeCrossoversCount = 0; originalSourceDeformationSphere->crossoverCheck(sourceTileCrossoversCount, sourceNodeCrossoversCount, BrainModelSurface::SURFACE_TYPE_SPHERICAL); if (sourceNodeCrossoversCount > 0) { std::cout << "WARNING: Original source deformation sphere has " << sourceNodeCrossoversCount << " crossovers when creating deformed coordinate file." << std::endl; } // // Check for crossovers in source in target deformation // int targetTileCrossoversCount = 0; int targetNodeCrossoversCount = 0; registeredDeformationSourceSphere->crossoverCheck(targetTileCrossoversCount, targetNodeCrossoversCount, BrainModelSurface::SURFACE_TYPE_SPHERICAL); if (targetNodeCrossoversCount > 0) { std::cout << "WARNING: Final deformation sphere has " << targetNodeCrossoversCount << " crossovers when creating deformed coordinate file." << std::endl; } // // Check for crossovers in user's source surface // int userTileCrossoversCount = 0; int userNodeCrossoversCount = 0; usersSourceSurface->crossoverCheck(userTileCrossoversCount, userNodeCrossoversCount, BrainModelSurface::SURFACE_TYPE_SPHERICAL); if (userNodeCrossoversCount > 0) { std::cout << "WARNING: User's individual sphere has " << userNodeCrossoversCount << " crossovers when creating deformed coordinate file." << std::endl; } } // // Copy the user's input surface to a new deformed surface // deformedSourceSurface = new BrainModelSurface(*usersSourceSurface); sourceBrainSet->addBrainModel(deformedSourceSurface); updateViewingTransformation(sourceBrainSet); // // Make sure source surface is same radius as deformation sphere // usersSourceSurface->convertToSphereWithRadius(deformationSphereRadius); // // Get the coordinate files for the user's surface and its // new deformed surface. // CoordinateFile* sourceCoords = usersSourceSurface->getCoordinateFile(); CoordinateFile* deformedSourceCoords = deformedSourceSurface->getCoordinateFile(); const int numCoords = sourceCoords->getNumberOfCoordinates(); // // See if X coordinate will need to be flipped (first cycle only !!!) // bool diffHemFlag = false; if (stageNumber == 1) { if (cycleNumber == 1) { diffHemFlag = (sourceBrainSet->getStructure() != targetBrainSet->getStructure()); if (diffHemFlag) { std::cout << "Different Hemispheres for Create Deformed Source Coordinates" << std::endl; } } } // // Create a Point Projector for the source deformation sphere // BrainModelSurfacePointProjector bspp(originalSourceDeformationSphere, //targetDeformationSphere); BrainModelSurfacePointProjector::SURFACE_TYPE_HINT_SPHERE, false); // // Coord file of registered deformation source sphere // const CoordinateFile* deformSphereRegisteredCoords = registeredDeformationSourceSphere->getCoordinateFile(); // // Project each point in the users input surface to its deformed surface // for (int i = 0; i < numCoords; i++) { float xyz[3]; sourceCoords->getCoordinate(i, xyz); if (diffHemFlag) { xyz[0] = -xyz[0]; sourceCoords->setCoordinate(i, xyz); // needed for projecting borders } // // Project source node onto subsampled surface // int nearestNode = -1; int tileNodes[3]; float tileAreas[3]; const int tile = bspp.projectBarycentric(xyz, nearestNode, tileNodes, tileAreas, true); // // Unproject using the deformation sphere coordinate file // if (tile >= 0) { BrainModelSurfacePointProjector::unprojectPoint(tileNodes, tileAreas, deformSphereRegisteredCoords, xyz); } else if (nearestNode >= 0) { // JWH 08/08/03 2:15pm deformedSourceCoords->getCoordinate(nearestNode, xyz); //deformationMorphedSphereCoords->getCoordinate(nearestNode, xyz); deformSphereRegisteredCoords->getCoordinate(nearestNode, xyz); } deformedSourceCoords->setCoordinate(i, xyz); } deformedSourceSurface->orientTilesConsistently(); deformedSourceSurface->computeNormals(); if (lastCycleFlag) { // // Check for crossovers in user's source surface // int userDeformedTileCrossoversCount = 0; int userDeformedNodeCrossoversCount = 0; deformedSourceSurface->crossoverCheck(userDeformedTileCrossoversCount, userDeformedNodeCrossoversCount, BrainModelSurface::SURFACE_TYPE_SPHERICAL); if (userDeformedNodeCrossoversCount > 0) { std::cout << "WARNING: User's DEFORMED individual sphere has " << userDeformedNodeCrossoversCount << " after its creation." << std::endl; } } // // Write the source deformed coordinates // /* QDir::setCurrent(sourceDirectory); QString defCoordName(deformationMapFile->getDeformedFileNamePrefix()); QString dn(FileUtilities::dirname(sourceCoords->getFileName())); if ((dn != ".") && (dn.length() > 0)) { QString fn(FileUtilities::basename(sourceCoords->getFileName())); QString s(dn); s += QDir::separator(); s += deformationMapFile->getDeformedFileNamePrefix(); s += fn; defCoordName = s; } else { defCoordName.append(sourceCoords->getFileName()); } */ // // Set name of deformed coordinate file and write it. // QDir::setCurrent(sourceDirectory); QString defCoordName; deformedSourceCoords->appendToFileComment("\nDeformation Map File: "); deformedSourceCoords->appendToFileComment( FileUtilities::basename(sourceToTargetDeformationMapFileName)); if ((stageNumber >= deformationMapFile->getSphericalNumberOfStages()) && (cycleNumber >= deformationMapFile->getSphericalNumberOfCycles(stageIndex))) { defCoordName = deformationMapFile->getDeformedFileNamePrefix() + FileUtilities::basename(usersSourceCoordFileName); deformationMapFile->setSourceDeformedSphericalCoordFileName(defCoordName); } else { defCoordName = deformationMapFile->getDeformedFileNamePrefix() + "sphere_stage_" + QString::number(stageNumber) + "_cycle_" + QString::number(cycleNumber) + SpecFile::getCoordinateFileExtension(); } QString descriptionMessage("Projecting " + sourceCoords->getFileName() + " to " + originalSourceDeformationSphere->getCoordinateFile()->getFileName() + " and unprojecting to " + registeredDeformationSourceSphere->getCoordinateFile()->getFileName() + " creating the file " + defCoordName); deformedSourceCoords->writeFile(defCoordName); QDir::setCurrent(originalDirectory); std::cout << "CREATE DEFORMED: " << descriptionMessage.toAscii().constData() << std::endl; return deformedSourceSurface; } catch (FileException& e) { throw BrainModelAlgorithmException(e.whatQString()); } } /** * write a border file containing the deformed landmarks. */ BorderFile* BrainModelSurfaceDeformationMultiStageSphericalVector::writeSourceBorderLandmarkFile(BrainModelSurface* surface, const int stageIndex, const int cycleNumber) { const CoordinateFile* cf = surface->getCoordinateFile(); const int numNodes = cf->getNumberOfCoordinates(); BorderFile* bf = new BorderFile; Border border; int lastBorderNumber = -1; for (int i = this->originalNumberOfNodes; i < numNodes; i++) { int usedIndex = i - this->originalNumberOfNodes; std::pair borderInfo = usedBorderLinks[usedIndex]; int borderNumber = borderInfo.first; //int linkNumber = borderInfo.second; if (borderNumber != lastBorderNumber) { if (border.getNumberOfLinks() > 0) { bf->addBorder(border); border.clearLinks(); } border.setName(targetBorderFile->getBorder(borderNumber)->getName()); lastBorderNumber = borderNumber; } border.addBorderLink(cf->getCoordinate(i)); } if (border.getNumberOfLinks() > 0) { bf->addBorder(border); } bf->setHeaderTag(AbstractFile::headerTagConfigurationID, BrainModelSurface::getSurfaceConfigurationIDFromType(BrainModelSurface::SURFACE_TYPE_SPHERICAL)); QString borderFileName("source_after_resample_stage_" + QString::number(stageIndex + 1) + "_cycle_" + QString::number(cycleNumber) + SpecFile::getBorderFileExtension()); bf->writeFile(borderFileName); intermediateFiles.push_back(borderFileName); brainSet->addToSpecFile(SpecFile::getSphericalBorderFileTag(), borderFileName); return bf; } /** * write coords without the landmarks. */ void BrainModelSurfaceDeformationMultiStageSphericalVector::writeCoordinatesWithoutLandmarks(BrainModelSurface* surface, const int stageIndex, const int cycleNumber) { CoordinateFile cf; cf.setNumberOfCoordinates(this->originalNumberOfNodes); for (int i = 0; i < this->originalNumberOfNodes; i++) { cf.setCoordinate(i, surface->getCoordinateFile()->getCoordinate(i)); } QString coordFileName("source_withoutLandmarks.LVD.stage_" + QString::number(stageIndex + 1) + "_cycle_" + QString::number(cycleNumber) + SpecFile::getCoordinateFileExtension()); cf.writeFile(coordFileName); intermediateFiles.push_back(coordFileName); } /** * Execute the deformation. */ void BrainModelSurfaceDeformationMultiStageSphericalVector::executeDeformation() throw (BrainModelAlgorithmException) { // // Validate vector smoothing iterations // QString vectorIterationsErrorMessage = ""; for (int si = 0; si < deformationMapFile->getSphericalNumberOfStages(); si++) { for (int ci = 0; ci < deformationMapFile->getSphericalNumberOfCycles(si); ci++) { // // Get vector-landmark parameters // int iterations = 0; float displacementFactor = 1.0; this->deformationMapFile->getLandmarkVectorParameters(si, ci, iterations, displacementFactor); if (iterations <= 0) { if (vectorIterationsErrorMessage.isEmpty()) { vectorIterationsErrorMessage = "Each cycle must have at least one iteration of vector smoothing.\n" "These stages/cycles have zero iterations:"; } vectorIterationsErrorMessage += (" (" + QString::number(si + 1) + "," + QString::number(ci + 1) + ")"); } } } if (vectorIterationsErrorMessage.isEmpty() == false) { throw BrainModelAlgorithmException(vectorIterationsErrorMessage); } // // Get radius of target sphere // deformationSphereRadius = targetSurface->getSphericalSurfaceRadius(); const QString sourceSurfaceCoordFileName = sourceSurface->getCoordinateFile()->getFileName(); // // Make a copy of the source surface so that it is not modified // workingSourceSurface = new BrainModelSurface(*sourceSurface); /// keeps track of crossovers in each cycle std::vector crossoverCount; std::vector crossoverStage; std::vector crossoverCycle; // // Loop through stages // for (int stageIndex = 0; stageIndex < deformationMapFile->getSphericalNumberOfStages(); stageIndex++) { const bool lastStageFlag = ((stageIndex + 1) >= deformationMapFile->getSphericalNumberOfStages()); QString progressPrefixString = "Stage " + QString::number(stageIndex + 1) + " "; // // If not the first stage // if (stageIndex > 0) { // // Read in the target brain set with the border file appropriate // for this stage. // delete targetBrainSet; readTargetBrainSet(stageIndex); } // // Make source surface the same radius as the target surface // workingSourceSurface->convertToSphereWithRadius(deformationSphereRadius); // // control of sphere fiducial distortion // bool useFiducialSphereRatios = false; float fiducialSphereRatioStrength = 0.5; deformationMapFile->getSphereFiducialRatio(useFiducialSphereRatios, fiducialSphereRatioStrength); // // Determing the ratio of the source fiducial and spherical tile areas // if (useFiducialSphereRatios) { if (DebugControl::getDebugOn()) { std::cout << " " << std::endl; } updateProgressDialog(progressPrefixString + "Determining Spherical Distortion"); determineSphericalDistortion(sourceFiducialSurface, workingSourceSurface, sourceTileDistortion); // // Determing the ratio of the target fiducial and spherical tile areas // determineSphericalDistortion(targetFiducialSurface, targetSurface, targetTileDistortion); } // // Resample the border files // if (DebugControl::getDebugOn()) { std::cout << "Resampling borders." << std::endl; } updateProgressDialog(progressPrefixString + "Resampling borders."); resampleBorderFiles(stageIndex, -1, deformationSphereRadius); // // Create the target brain set // targetDeformationBrainSet = new BrainSet(); // // Load the regularly tessellated sphere and make it same radius as target surface // QString currentDirectory(QDir::currentPath()); targetDeformationSphere = getRegularSphere(targetDeformationBrainSet, stageIndex, deformationSphereRadius); targetDeformationSphere->orientTilesConsistently(); targetDeformationSphere->computeNormals(); targetDeformationSphere->updateForDefaultScaling(); this->updateViewingTransformation(targetDeformationSphere); targetDeformationBrainSet->drawBrainModel(targetDeformationSphere); QDir::setCurrent(currentDirectory); // // Save the number of nodes before tessellating in the borders // originalNumberOfNodes = targetDeformationSphere->getNumberOfNodes(); // // tessellate the target borders into the target deformation sphere // if (DebugControl::getDebugOn()) { std::cout << "Tessellating borders into target." << std::endl; } updateProgressDialog(progressPrefixString + "Tessellating Borders into Target"); tessellateTargetBordersIntoDeformationSphere(stageIndex); // // Load the regularly tessellated sphere and make it same radius as target surface // currentDirectory = QDir::currentPath(); sourceDeformationSphere = getRegularSphere(brainSet, stageIndex, deformationSphereRadius); sourceDeformationSphere->orientTilesConsistently(); sourceDeformationSphere->computeNormals(); sourceDeformationSphere->updateForDefaultScaling(); this->updateViewingTransformation(sourceDeformationSphere); brainSet->drawBrainModel(sourceDeformationSphere); QDir::setCurrent(currentDirectory); // // tessellate the source borders into the source deformation sphere // if (DebugControl::getDebugOn()) { std::cout << "Tessellating borders into source." << std::endl; } updateProgressDialog(progressPrefixString + "Tessellating Borders into Source"); tessellateSourceBordersIntoDeformationSphere(stageIndex); // // Place copy of target into the brain set // QString targetCoordName = targetDeformationSphere->getCoordinateFile()->getFileName(); brainSet->readCoordinateFile(targetCoordName, BrainModelSurface::SURFACE_TYPE_SPHERICAL, false, true, true); brainSet->getBrainModelSurface( brainSet->getNumberOfBrainModels() - 1)->updateForDefaultScaling(); // // Mark the landmark nodes // //const int numNodes = targetDeformationSphere->getNumberOfNodes(); int numNodes = sourceDeformationSphere->getNumberOfNodes(); landmarkNodeFlags.resize(numNodes); for (int i = 0; i < numNodes; i++) { landmarkNodeFlags[i] = (i >= originalNumberOfNodes); } // // Create the source reference surface // referenceSourceDeformationSphere = new BrainModelSurface(*sourceDeformationSphere); moveLandmarksToAverageOfNeighbors(referenceSourceDeformationSphere); referenceSourceDeformationSphere->computeNormals(); referenceSourceDeformationSphere->updateForDefaultScaling(); brainSet->addBrainModel(referenceSourceDeformationSphere); this->updateViewingTransformation(referenceSourceDeformationSphere); const QString sourceRefName("source_withLandmarks_stage_" + QString::number(stageIndex + 1) + ".LVD.REF" + SpecFile::getCoordinateFileExtension()); brainSet->writeCoordinateFile(sourceRefName, BrainModelSurface::SURFACE_TYPE_SPHERICAL, referenceSourceDeformationSphere->getCoordinateFile(), true); intermediateFiles.push_back(sourceRefName); // // Copy of source deformation sphere // BrainModelSurface originalSourceDeformationSphere(*referenceSourceDeformationSphere); originalSourceDeformationSphere.getCoordinateFile()->setFileName( "CopyOf_" + referenceSourceDeformationSphere->getCoordinateFile()->getFileName()); // // Perform the requested number of cycles // for (int cycleIndex = 0; cycleIndex < deformationMapFile->getSphericalNumberOfCycles(stageIndex); cycleIndex++) { const int cycleNumber = cycleIndex + 1; const QString cycleString(progressPrefixString + "Cycle " + QString::number(cycleNumber) + " "); bool lastCycleFlag = (cycleNumber >= deformationMapFile->getSphericalNumberOfCycles(stageIndex)); // // Get vector-landmark parameters // int iterations = 0; float displacementFactor = 1.0; this->deformationMapFile->getLandmarkVectorParameters(stageIndex, cycleIndex, iterations, displacementFactor); // // Create the surface shape coordinate differences // if (DebugControl::getDebugOn()) { std::cout << "Cycle " << cycleNumber << " smoothing landmarks in source." << std::endl; } updateProgressDialog(cycleString + "Smoothing Landmarks in Source"); SurfaceShapeFile* shapeDiffFile = this->createDifferenceShapeFile(iterations); // // Save the shape file // const QString shapeFileName("source_withLandmarks.LVD.stage_" + QString::number(stageIndex + 1) + "_cycle_" + QString::number(cycleNumber) + SpecFile::getSurfaceShapeFileExtension()); brainSet->writeSurfaceShapeFile(shapeFileName); intermediateFiles.push_back(shapeFileName); // // Displace sphere nodes by smoothed shape data // CoordinateFile* sourceCoords = sourceDeformationSphere->getCoordinateFile(); for (int j = 0; j < numNodes; j++) { float* xyz = sourceCoords->getCoordinate(j); xyz[0] += (shapeDiffFile->getValue(j, 6) * displacementFactor); xyz[1] += (shapeDiffFile->getValue(j, 7) * displacementFactor); xyz[2] += (shapeDiffFile->getValue(j, 8) * displacementFactor); sourceCoords->setCoordinate(j, xyz); } const QString displacedCoordName("source_withLandmarksDisplaced.LVD.stage_" + QString::number(stageIndex + 1) + "_cycle_" + QString::number(cycleNumber) + SpecFile::getCoordinateFileExtension()); brainSet->writeCoordinateFile(displacedCoordName, BrainModelSurface::SURFACE_TYPE_SPHERICAL, sourceDeformationSphere->getCoordinateFile(), true); intermediateFiles.push_back(displacedCoordName); moveLandmarksToAverageOfNeighbors(sourceDeformationSphere); sourceDeformationSphere->convertToSphereWithRadius( this->deformationSphereRadius); const QString displayedSphereCoordName("source_withLandmarksDisplacedBackToSphere.LVD.stage_" + QString::number(stageIndex + 1) + "_cycle_" + QString::number(cycleNumber) + SpecFile::getCoordinateFileExtension()); brainSet->writeCoordinateFile(displayedSphereCoordName, BrainModelSurface::SURFACE_TYPE_SPHERICAL, sourceDeformationSphere->getCoordinateFile(), true); intermediateFiles.push_back(displayedSphereCoordName); updateViewingTransformation(brainSet); sourceDeformationSphere->orientTilesConsistently(); sourceDeformationSphere->computeNormals(); sourceDeformationSphere->updateForDefaultScaling(); this->updateViewingTransformation(sourceDeformationSphere); brainSet->drawBrainModel(sourceDeformationSphere); sourceDeformationSphere = new BrainModelSurface(*sourceDeformationSphere); brainSet->addBrainModel(sourceDeformationSphere); this->updateViewingTransformation(sourceDeformationSphere); // // Perform landmark neighbor constrained smoothing on the sphere // with source landmarks // if (DebugControl::getDebugOn()) { std::cout << "Cycle " << cycleNumber << " landmark neighbor constrained smoothing." << std::endl; } updateProgressDialog(cycleString + "Landmark Neighbor Constrained Smoothing of Source"); landmarkNeighborConstrainedSmoothSource(stageIndex, cycleIndex); const QString smoothedLandmarkCoordName( "source_withLandmarksSmoothed.LVD.stage_" + QString::number(stageIndex + 1) + "_cycle_" + QString::number(cycleNumber) + SpecFile::getCoordinateFileExtension()); brainSet->writeCoordinateFile(smoothedLandmarkCoordName, BrainModelSurface::SURFACE_TYPE_SPHERICAL, sourceDeformationSphere->getCoordinateFile(), true); intermediateFiles.push_back(smoothedLandmarkCoordName); updateViewingTransformation(brainSet); sourceDeformationSphere->orientTilesConsistently(); sourceDeformationSphere->computeNormals(); sourceDeformationSphere->updateForDefaultScaling(); this->updateViewingTransformation(sourceDeformationSphere); brainSet->drawBrainModel(sourceDeformationSphere); sourceDeformationSphere = new BrainModelSurface(*sourceDeformationSphere); this->updateViewingTransformation(sourceDeformationSphere); brainSet->addBrainModel(sourceDeformationSphere); // // During first cycle, allocate the fiducial sphere distortion // surface shape file // if (useFiducialSphereRatios) { fiducialSphereDistortion.setNumberOfNodesAndColumns( targetDeformationSphere->getNumberOfNodes(), 3); fiducialSphereDistortion.setColumnName(0, "Target Distortion"); fiducialSphereDistortion.setColumnName(1, "Source Distortion"); fiducialSphereDistortion.setColumnName(2, "sqrt(Target/Source)"); // // determine the fiducial sphere distortion // determineFiducialSphereDistortion(); // // Update fiducial/sphere with deformed surface // updateSphereFiducialDistortion(stageIndex, cycleIndex, sourceDeformationSphere); } // // Perform landmark neighbor constrained morphing on the sphere // with source landmarks // if (DebugControl::getDebugOn()) { std::cout << "Cycle " << cycleNumber << " landmark neighbor constrained morphing." << std::endl; } updateProgressDialog(cycleString + "Landmark Neighbor Constrained Morphing of Source"); landmarkMorphContrainedSource(referenceSourceDeformationSphere, stageIndex, cycleIndex); const QString morphedLandmarkCoordName( "source_withLandmarksMorphed.LVD.stage_" + QString::number(stageIndex + 1) + "_cycle_" + QString::number(cycleNumber) + SpecFile::getCoordinateFileExtension()); intermediateFiles.push_back(morphedLandmarkCoordName); updateViewingTransformation(brainSet); sourceDeformationSphere->orientTilesConsistently(); sourceDeformationSphere->computeNormals(); sourceDeformationSphere->updateForDefaultScaling(); brainSet->drawBrainModel(sourceDeformationSphere); brainSet->writeCoordinateFile(morphedLandmarkCoordName, BrainModelSurface::SURFACE_TYPE_SPHERICAL, sourceDeformationSphere->getCoordinateFile(), true); // // Use morphed as REFERENCE for next cycle // referenceSourceDeformationSphere = sourceDeformationSphere; // // Check for crossovers // updateProgressDialog(cycleString + "Checking for Crossovers"); int numNodeCrossovers = 0, numTileCrossovers = 0; sourceDeformationSphere->crossoverCheck(numTileCrossovers, numNodeCrossovers, BrainModelSurface::SURFACE_TYPE_SPHERICAL); crossoverCount.push_back(numNodeCrossovers); crossoverStage.push_back(stageIndex + 1); crossoverCycle.push_back(cycleNumber); if (deformationMapFile->getPauseForCrossoversConfirmation()) { if (brainSet->getProgressDialogParent() != NULL) { if (numNodeCrossovers > 0) { QString msg = "At stage " + QString::number(stageIndex + 1) + " cycle " + QString::number(cycleNumber) + " there are " + QString::number(numNodeCrossovers) + " crossovers." + "\nDo you want to continue?"; if (QMessageBox::question(brainSet->getProgressDialogParent(), "Crossovers Warning", msg, (QMessageBox::Yes | QMessageBox::No), QMessageBox::Yes) == QMessageBox::No) { throw BrainModelAlgorithmException("Deformation cancelled by user."); } } } } // // Project the user's sphere from the original source deformation sphere to // the original deformation sphere // updateProgressDialog(cycleString + "Creating Deformed Coordinate File"); BrainModelSurface* newDeformedSurface = createDeformedCoordinateFile(&originalSourceDeformationSphere, sourceDeformationSphere, stageIndex, cycleNumber, sourceSurfaceCoordFileName); // // Create a new sphere for the next cycle // if (lastCycleFlag == false) { sourceDeformationSphere = new BrainModelSurface(*sourceDeformationSphere); this->updateViewingTransformation(sourceDeformationSphere); brainSet->addBrainModel(sourceDeformationSphere); } // // Set surface for next stage // workingSourceSurface = deformedSourceSurface; // // Create border file containing the deformed landmarks and use // it as the border file for the next stage // BorderFile* defBorderFile = writeSourceBorderLandmarkFile(sourceDeformationSphere, stageIndex, cycleNumber); // // Write deformation sphere without landmarks // writeCoordinatesWithoutLandmarks(sourceDeformationSphere, stageIndex, cycleNumber); if (lastCycleFlag) { // // Set borders for next stage // sourceBorderFile = defBorderFile; if (lastStageFlag == false) { // // Use deformed source surface as input source surface // for next stage // sourceSurface = newDeformedSurface; } } } // cycle index } // stage index // // If the last cycle alert user if there are crossovers // bool anyCrossoversFlag = false; for (unsigned int i = 0; i < crossoverCount.size(); i++) { if (crossoverCount[i] > 0) { anyCrossoversFlag = true; break; } } if (anyCrossoversFlag > 0) { QWidget* parent = brainSet->getProgressDialogParent(); if (parent != NULL) { QString msg; for (int i = 0; i < static_cast(crossoverCount.size()); i++) { QString s = "Stage " + QString::number(crossoverStage[i]) + " Cycle " + QString::number(crossoverCycle[i]) + " had " + QString::number(crossoverCount[i]) + " crossovers.\n"; msg += s; } /* for (int i = 0; i < this->deformationMapFile->getSphericalNumberOfStages(); i++) { for (int j = 0; j < this->deformationMapFile->getSphericalNumberOfCycles(i); j++) { const int index = (i * this->deformationMapFile->getSphericalNumberOfCycles(i)) + j; std::ostringstream str; str << "Stage " << (i + 1) << " Cycle " << (j + 1) << " had " << crossoverCount[index] << " crossovers.\n"; msg.append(str.str().c_str()); } } */ msg.append("\nContinue Deformation ?"); QApplication::restoreOverrideCursor(); QApplication::beep(); if (QMessageBox::warning(parent, "Crossover Alert", msg, "Yes", "No") != 0) { throw BrainModelAlgorithmException("Deformation terminated by user."); } //will not compile on mac - don't know why QApplication::setOverrideCursor(waitCursor); } } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceDeformationMeasurement.h0000664000175000017500000000426211572067322030005 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __BRAIN_MODEL_SURFACE_DEFORMATION_MEASUREMENT_H__ #define __BRAIN_MODEL_SURFACE_DEFORMATION_MEASUREMENT_H__ #include "BrainModelAlgorithm.h" class BorderFile; class BrainModelSurface; class MetricFile; /// class for performing a deformation measurement class BrainModelSurfaceDeformationMeasurement : public BrainModelAlgorithm { public: /// constructor BrainModelSurfaceDeformationMeasurement(BrainSet* bs, BrainModelSurface* bmsIn, BorderFile* borderFileIn, MetricFile* metricFileIn, const int sphereNumberIn); /// Destructor ~BrainModelSurfaceDeformationMeasurement(); /// execute the algorithm void execute() throw (BrainModelAlgorithmException); protected: /// the surface being examined BrainModelSurface* bms; /// the borders used for measurement BorderFile* borderFile; /// the metric file into which the measurements should be placed MetricFile* userMetricFile; /// sphere resolution int sphereNumber; }; #endif // __BRAIN_MODEL_SURFACE_DEFORMATION_MEASUREMENT_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceDeformationMeasurement.cxx0000664000175000017500000003157311572067322030365 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifdef Q_OS_WIN32 #define NOMINMAX #endif #include #include #include #include #include #include #include "BorderFile.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceDeformationMeasurement.h" #include "BrainModelSurfaceGeodesic.h" #include "BrainModelSurfacePointLocator.h" #include "BrainSet.h" #include "CoordinateFile.h" #include "DebugControl.h" #include "GeodesicDistanceFile.h" #include "MathUtilities.h" #include "MetricFile.h" #include "TopologyFile.h" #include "TopologyHelper.h" /** * Constructor. */ BrainModelSurfaceDeformationMeasurement::BrainModelSurfaceDeformationMeasurement(BrainSet* bs, BrainModelSurface* bmsIn, BorderFile* borderFileIn, MetricFile* metricFileIn, const int sphereNumberIn) : BrainModelAlgorithm(bs) { bms = bmsIn; borderFile = borderFileIn; userMetricFile = metricFileIn; sphereNumber = sphereNumberIn; } /** * Destructor. */ BrainModelSurfaceDeformationMeasurement::~BrainModelSurfaceDeformationMeasurement() { } /** * execute the algorithm. */ void BrainModelSurfaceDeformationMeasurement::execute() throw (BrainModelAlgorithmException) { if (bms == NULL) { throw BrainModelAlgorithmException("The surface is invalid."); } if (bms->getNumberOfNodes() <= 0) { throw BrainModelAlgorithmException("The surface has no nodes."); } if (bms->getTopologyFile() == NULL) { throw BrainModelAlgorithmException("The surface has no topology."); } if (borderFile == NULL) { throw BrainModelAlgorithmException("The border file is invalid."); } if (borderFile->getNumberOfBorders() == 0) { throw BrainModelAlgorithmException("The border file contains no borders."); } if (userMetricFile == NULL) { throw BrainModelAlgorithmException("The metric file is invalid."); } // // Set up user's metric file // const int numNodes = bms->getNumberOfNodes(); int metricColumn = 0; if (userMetricFile->getNumberOfNodes() <= 0) { userMetricFile->setNumberOfNodesAndColumns(numNodes, 1); } else { userMetricFile->addColumns(1); metricColumn = userMetricFile->getNumberOfColumns() - 1; } userMetricFile->setColumnName(metricColumn, "Nearest Spherical Border Distance"); // // Create a topology helper so that only nodes with neighbors are used // const TopologyHelper* th = bms->getTopologyFile()->getTopologyHelper(false, true, false); CoordinateFile* cf = bms->getCoordinateFile(); const float radius = bms->getSphericalSurfaceRadius(); // // Loop through all of the nodes // for (int i = 0; i < numNodes; i++) { userMetricFile->setValue(i, metricColumn, 0.0); // // Only do nodes with neighbors // if (th->getNodeHasNeighbors(i)) { // // This node's XYZ // float nodeXYZ[3]; cf->getCoordinate(i, nodeXYZ); MathUtilities::normalize(nodeXYZ); // // Find the nearest border point // float nearestGreatCircleDistance = std::numeric_limits::max(); const int numBorders = borderFile->getNumberOfBorders(); for (int j = 0; j < numBorders; j++) { const Border* b = borderFile->getBorder(j); const int numLinks = b->getNumberOfLinks(); for (int k = 0; k < numLinks; k++) { float linkXYZ[3]; b->getLinkXYZ(k, linkXYZ); MathUtilities::normalize(linkXYZ); const float dotProduct = MathUtilities::dotProduct(nodeXYZ, linkXYZ); const float theta = std::acos(dotProduct); const float greatCircleDistance = theta * radius; nearestGreatCircleDistance = std::min(nearestGreatCircleDistance, greatCircleDistance); } } if (nearestGreatCircleDistance <= 0.0) { nearestGreatCircleDistance = 0.0001; } userMetricFile->setValue(i, metricColumn, nearestGreatCircleDistance); } if ((i % 100) == 0) { //std::cout << i << " of " << numNodes << std::endl; } } // // Write the user's metric file // try { // brainSet->writeMetricFile(userMetricFile->getFileName()); } catch (FileException& e) { throw BrainModelAlgorithmException(e.whatQString()); } } /* * This does geodesic distance. void BrainModelSurfaceDeformationMeasurement::execute() throw (BrainModelAlgorithmException) { if (bms == NULL) { throw BrainModelAlgorithmException("The surface is invalid."); } if (bms->getNumberOfNodes() <= 0) { throw BrainModelAlgorithmException("The surface has no nodes."); } if (bms->getTopologyFile() == NULL) { throw BrainModelAlgorithmException("The surface has no topology."); } if (borderFile == NULL) { throw BrainModelAlgorithmException("The border file is invalid."); } if (borderFile->getNumberOfBorders() == 0) { throw BrainModelAlgorithmException("The border file contains no borders."); } if (userMetricFile == NULL) { throw BrainModelAlgorithmException("The metric file is invalid."); } // // Load the standard sphere // QString currentPath = QDir::currentPath(); std::ostringstream str; str << brainSet->getCaretHomeDirectory() << "/" << "data_files/REGISTER.SPHERE" << "/" << "sphere.v5." << sphereNumber << ".spec"; BrainSet sphereBrainSet(str.str().c_str()); if (sphereBrainSet.getNumberOfBrainModels() <= 0) { QString msg("Unable to read standard sphere spec file "); msg.append(str.str().c_str()); throw BrainModelAlgorithmException(msg); } BrainModelSurface* sphereSurface = sphereBrainSet.getBrainModelSurface(0); if (sphereSurface == NULL) { QString msg("Unable to read standard sphere from"); msg.append(str.str().c_str()); throw BrainModelAlgorithmException(msg); } QDir::setCurrent(currentPath); // // Get the radius of the border file // float sphereRadius = 1.0; const int numBorders = borderFile->getNumberOfBorders(); for (int i = 0; i < numBorders; i++) { const Border* border = borderFile->getBorder(i); const int numLinks = border->getNumberOfLinks(); for (int j = 0; j < numLinks; j++) { const float* xyz = border->getLinkXYZ(j); sphereRadius = std::sqrt(xyz[0]*xyz[0] + xyz[1]*xyz[1] + xyz[2]*xyz[2]); break; } } // // Set the radius of the spherical surface // sphereSurface->convertToSphereWithRadius(sphereRadius); // // Find the nearest node for each borders point // std::set nodesNearBordersSet; BrainModelSurfacePointLocator sphereNodeLocator(sphereSurface, true); for (int i = 0; i < numBorders; i++) { const Border* border = borderFile->getBorder(i); const int numLinks = border->getNumberOfLinks(); for (int j = 0; j < numLinks; j++) { const int node = sphereNodeLocator.getNearestPoint(border->getLinkXYZ(j)); if (node >= 0) { nodesNearBordersSet.insert(node); if (DebugControl::getDebugOn()) { std::cout << border->getName().toAscii().constData() << " link " << j << " is closest to node " << node << std::endl; } } else { std::cout << "Unable to find node nearest to border " << border->getName().toAscii().constData() << "link " << j << std::endl; } } } // // Put the nodes near borders in a array for faster access // const int numNodesNearBorders = static_cast(nodesNearBordersSet.size()); if (numNodesNearBorders <= 0) { throw BrainModelAlgorithmException("No nodes near borders were found."); } int* nodesNearBorders = new int[numNodesNearBorders]; int cnt = 0; for (std::set::iterator iter = nodesNearBordersSet.begin(); iter != nodesNearBordersSet.end(); iter++) { nodesNearBorders[cnt] = *iter; cnt++; } // // Create a topology helper so that only nodes with neighbors are used // const TopologyHelper* th = sphereSurface->getTopologyFile()->getTopologyHelper(false, true, false); const int sphereNumNodes = sphereSurface->getNumberOfNodes(); CoordinateFile* cf = sphereSurface->getCoordinateFile(); // // Create a geodesic distance file with one column // GeodesicDistanceFile geoDistFile; geoDistFile.setNumberOfNodesAndColumns(sphereNumNodes, 1); // // Set up metric file // MetricFile sphereMetricFile; sphereMetricFile.setNumberOfNodesAndColumns(sphereNumNodes, 1); const int sphereMetricColumn = 0; // // Loop through all of the nodes // for (int i = 0; i < sphereNumNodes; i++) { sphereMetricFile.setValue(i, sphereMetricColumn, 0.0); // // Only do nodes with neighbors // if (th->getNodeHasNeighbors(i)) { // // Determine the geodesic distances for the node // BrainModelSurfaceGeodesic bmsg(&sphereBrainSet, sphereSurface, NULL, -3, "", &geoDistFile, 0, "node", i, NULL); try { bmsg.execute(); } catch (BrainModelAlgorithmException& e) { throw e; } // // Find the closest node in the node's nearest to the borders // float minDistSQ = std::numeric_limits::max(); const float* myXYZ = cf->getCoordinate(i); for (int j = 0; j < numNodesNearBorders; j++) { const int node = nodesNearBorders[j]; const float* nodeXYZ = cf->getCoordinate(node); const float dx = myXYZ[0] - nodeXYZ[0]; const float dy = myXYZ[1] - nodeXYZ[1]; const float dz = myXYZ[2] - nodeXYZ[2]; const float distSQ = dx*dx + dy*dy + dz*dz; minDistSQ = std::min(minDistSQ, distSQ); } const float dist = std::max(std::sqrt(minDistSQ), 0.001); sphereMetricFile.setValue(i, sphereMetricColumn, dist); } if ((i % 100) == 0) { std::cout << i << " of " << sphereNumNodes << std::endl; } } delete[] nodesNearBorders; // // Set up user's metric file // const int numNodes = bms->getNumberOfNodes(); int metricColumn = 0; if (userMetricFile->getNumberOfNodes() <= 0) { userMetricFile->setNumberOfNodesAndColumns(numNodes, 1); } else { userMetricFile->addColumns(1); metricColumn = userMetricFile->getNumberOfColumns() - 1; } userMetricFile->setColumnName(metricColumn, "Deform Distance"); // // Set distances for the users sphere // const CoordinateFile* userCoordFile = bms->getCoordinateFile(); for (int i = 0; i < numNodes; i++) { const int sphereNode = sphereNodeLocator.getNearestPoint(userCoordFile->getCoordinate(i)); userMetricFile->setValue(i, metricColumn, sphereMetricFile.getValue(sphereNode, sphereMetricColumn)); } // // Write the user's metric file // try { brainSet->writeMetricFile(userMetricFile->getFileName()); } catch (FileException& e) { throw BrainModelAlgorithmException(e.whatQString()); } } */ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceDeformationMapCreate.h0000664000175000017500000000514211572067322027357 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_DEFORMATION_MAP_CREATE_H__ #define __BRAIN_MODEL_SURFACE_DEFORMATION_MAP_CREATE_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelAlgorithm.h" class BrainModelSurface; class DeformationMapFile; /// class for create a deformation map from two surfaces class BrainModelSurfaceDeformationMapCreate : public BrainModelAlgorithm { public: /// deformation surface type enum DEFORMATION_SURFACE_TYPE { /// spherical surface DEFORMATION_SURFACE_TYPE_SPHERE }; // constructor BrainModelSurfaceDeformationMapCreate(BrainSet* bs, const BrainModelSurface* sourceSurfaceIn, const BrainModelSurface* targetSurfaceIn, DeformationMapFile* deformationMapFileIn, const DEFORMATION_SURFACE_TYPE deformationSurfaceTypeIn); // destructor ~BrainModelSurfaceDeformationMapCreate(); // execute the algorithm void execute() throw (BrainModelAlgorithmException); protected: // create the spherical deformation map void createSphericalDeformationMap(); /// source surface BrainModelSurface* sourceSurface; /// target surface BrainModelSurface* targetSurface; /// source surface const BrainModelSurface* sourceSurfaceIn; /// target surface const BrainModelSurface* targetSurfaceIn; /// deformation map DeformationMapFile* deformationMapFile; /// deformation surface type DEFORMATION_SURFACE_TYPE deformationSurfaceType; }; #endif // __BRAIN_MODEL_SURFACE_DEFORMATION_MAP_CREATE_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceDeformationMapCreate.cxx0000664000175000017500000001733211572067322027736 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelSurface.h" #include "BrainModelSurfaceDeformationMapCreate.h" #include "BrainModelSurfacePointProjector.h" #include "DeformationMapFile.h" #include "FileUtilities.h" #include "TopologyFile.h" /** * constructor. */ BrainModelSurfaceDeformationMapCreate::BrainModelSurfaceDeformationMapCreate( BrainSet* bs, const BrainModelSurface* sourceSurfaceIn, const BrainModelSurface* targetSurfaceIn, DeformationMapFile* deformationMapFileIn, const DEFORMATION_SURFACE_TYPE deformationSurfaceTypeIn) : BrainModelAlgorithm(bs), sourceSurfaceIn(sourceSurfaceIn), targetSurfaceIn(targetSurfaceIn) { deformationMapFile = deformationMapFileIn; deformationSurfaceType = deformationSurfaceTypeIn; } /** * destructor. */ BrainModelSurfaceDeformationMapCreate::~BrainModelSurfaceDeformationMapCreate() { if (this->sourceSurface != NULL) { delete this->sourceSurface; this->sourceSurface = NULL; } if (this->targetSurface != NULL) { delete this->targetSurface; this->targetSurface = NULL; } } /** * execute the algorithm. */ void BrainModelSurfaceDeformationMapCreate::execute() throw (BrainModelAlgorithmException) { // // Check inputs // if (sourceSurfaceIn == NULL) { throw BrainModelAlgorithmException("Source surface is invalid."); } if (targetSurfaceIn == NULL) { throw BrainModelAlgorithmException("Target surface is invalid."); } if (deformationMapFile == NULL) { throw BrainModelAlgorithmException("Deformation Map is invalid."); } if (sourceSurfaceIn->getNumberOfNodes() <= 0) { throw BrainModelAlgorithmException("Source surface contains no nodes."); } if (targetSurfaceIn->getNumberOfNodes() <= 0) { throw BrainModelAlgorithmException("Target surface contains no nodes."); } // // Verify there is topology // const TopologyFile* sourceTopologyFile = sourceSurfaceIn->getTopologyFile(); if (sourceTopologyFile == NULL) { throw BrainModelAlgorithmException("Source surface contains no topology."); } const TopologyFile* targetTopologyFile = targetSurfaceIn->getTopologyFile(); if (targetTopologyFile == NULL) { throw BrainModelAlgorithmException("Target surface contains no topology."); } // // Copy the source and target surfaces so that they can be modified // this->sourceSurface = new BrainModelSurface(*(this->sourceSurfaceIn)); this->targetSurface = new BrainModelSurface(*(this->targetSurfaceIn)); this->sourceSurface->getCoordinateFile()->setFileName( this->sourceSurfaceIn->getCoordinateFile()->getFileName()); this->targetSurface->getCoordinateFile()->setFileName( this->targetSurfaceIn->getCoordinateFile()->getFileName()); // // Clear the deformation map // deformationMapFile->clear(); // // Create the deformation map // switch (deformationSurfaceType) { case DEFORMATION_SURFACE_TYPE_SPHERE: createSphericalDeformationMap(); break; } // // File names for deformation map // const CoordinateFile* sourceCoord = sourceSurface->getCoordinateFile(); QString sourceDirName = FileUtilities::dirname(sourceCoord->getFileName()); if (sourceDirName == ".") { sourceDirName = QDir::currentPath(); } deformationMapFile->setSourceDirectory(sourceDirName); const CoordinateFile* targetCoord = targetSurface->getCoordinateFile(); QString targetDirName = FileUtilities::dirname(targetCoord->getFileName()); if (targetDirName == ".") { targetDirName = QDir::currentPath(); } deformationMapFile->setTargetDirectory(targetDirName); switch (deformationSurfaceType) { case DEFORMATION_SURFACE_TYPE_SPHERE: deformationMapFile->setSourceSphericalCoordFileName( FileUtilities::basename(sourceCoord->getFileName())); deformationMapFile->setSourceDeformedSphericalCoordFileName( FileUtilities::basename(sourceCoord->getFileName())); deformationMapFile->setSourceClosedTopoFileName( FileUtilities::basename(sourceTopologyFile->getFileName())); deformationMapFile->setTargetSphericalCoordFileName( FileUtilities::basename(targetCoord->getFileName())); deformationMapFile->setTargetClosedTopoFileName( FileUtilities::basename(targetTopologyFile->getFileName())); break; } } /** * create the spherical deformation map. */ void BrainModelSurfaceDeformationMapCreate::createSphericalDeformationMap() { // // Make sure source surface is same radius as target sphere // and at origin // //this->sourceSurface->translateToCenterOfMass(); //this->targetSurface->translateToCenterOfMass(); this->sourceSurface->translateMidpointToOrigin(); this->targetSurface->translateMidpointToOrigin(); float radius = targetSurface->getSphericalSurfaceRadius(); this->sourceSurface->convertToSphereWithRadius(radius); // // Get the coordinate files for the surfaces // const CoordinateFile* targetCoords = targetSurface->getCoordinateFile(); const int numCoords = targetCoords->getNumberOfCoordinates(); // // Create a Point Projector source surface. // BrainModelSurfacePointProjector bspp(sourceSurface, BrainModelSurfacePointProjector::SURFACE_TYPE_HINT_SPHERE, false); // // Set number of nodes in deformation map file // deformationMapFile->setNumberOfNodes(numCoords); // // Project each point from target onto source // for (int i = 0; i < numCoords; i++) { // // Get a target coordinate // float xyz[3]; targetCoords->getCoordinate(i, xyz); // // Project target node onto source surface // int nearestNode = -1; int tileNodes[3]; float tileAreas[3]; const int tile = bspp.projectBarycentric(xyz, nearestNode, tileNodes, tileAreas, true); // // Projected to tile? // if (tile >= 0) { deformationMapFile->setDeformDataForNode(i, tileNodes, tileAreas); } else if (nearestNode >= 0) { tileNodes[0] = nearestNode; tileNodes[1] = nearestNode; tileNodes[2] = nearestNode; tileAreas[0] = 0.33; tileAreas[1] = 0.33; tileAreas[2] = 0.33; deformationMapFile->setDeformDataForNode(i, tileNodes, tileAreas); } } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceDeformationFlat.h0000664000175000017500000000361311572067322026405 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __BRAIN_MODEL_SURFACE_DEFORMATION_FLAT_H__ #define __BRAIN_MODEL_SURFACE_DEFORMATION_FLAT_H__ #include "BrainModelSurfaceDeformation.h" /// this class performs a flat deformation class BrainModelSurfaceDeformationFlat : public BrainModelSurfaceDeformation { public: // Constructor BrainModelSurfaceDeformationFlat(BrainSet* brainSetIn, DeformationMapFile* DeformationMapFileIn); // Destructor ~BrainModelSurfaceDeformationFlat(); /// get output of flat fluid QString getFlatFluidOutput() const { return outputOfFlatFluid; } protected: // Execute the deformation void executeDeformation() throw (BrainModelAlgorithmException); // Check the borders to make sure the names are valid. void checkBorderNames(const QString& borderFileName) throw (BrainModelAlgorithmException); /// output of flat fluid program QString outputOfFlatFluid; }; #endif // __BRAIN_MODEL_SURFACE_DEFORMATION_FLAT_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceDeformationFlat.cxx0000664000175000017500000002763111572067322026766 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BorderFile.h" #include "BrainModelRunExternalProgram.h" #include "BrainModelSurfaceDeformationFlat.h" #include "BrainModelSurfaceFlatHexagonalSubsample.h" #include "BrainModelSurfacePointProjector.h" #include "BrainSet.h" #include "DebugControl.h" #include "DeformationMapFile.h" /** * Constructor. */ BrainModelSurfaceDeformationFlat::BrainModelSurfaceDeformationFlat( BrainSet* brainSetIn, DeformationMapFile* deformationMapFileIn) : BrainModelSurfaceDeformation(brainSetIn, deformationMapFileIn) { } /** * Destructor. */ BrainModelSurfaceDeformationFlat::~BrainModelSurfaceDeformationFlat() { } /** * Check the borders to make sure the names are valid. */ void BrainModelSurfaceDeformationFlat::checkBorderNames(const QString& borderFileName) throw (BrainModelAlgorithmException) { BorderFile bf; try { bf.readFile(borderFileName); const int num = bf.getNumberOfBorders(); for (int i = 0; i < num; i++) { const Border* b = bf.getBorder(i); const QString name(b->getName()); // // Is this a valid border name ? // if ((name.left(6) == "morph.") || (name.left(6) == "MORPH.") || (name.left(8) == "LANDMARK") || (name.left(8) == "landmark")) { return; } } QString msg("ERROR: at least one of the border files has no borders beginning with:\n"); msg.append(" \"morph.\"\n"); msg.append(" \"MORPH.\"\n"); msg.append(" \"LANDMARK\"\n"); msg.append(" \"landmark\"\n"); throw BrainModelAlgorithmException(msg); } catch (FileException& e) { QString msg("ERROR checking border names for validity\n"); msg.append(e.whatQString()); throw BrainModelAlgorithmException(msg); } } /** * Execute the deformation. */ void BrainModelSurfaceDeformationFlat::executeDeformation() throw (BrainModelAlgorithmException) { // // Get the flat parameters // int subSampleTiles = 900; int numberOfIterations = 0; float beta = 0.0; float varMult = 0.0; deformationMapFile->getFlatParameters(subSampleTiles, beta, varMult, numberOfIterations); // // Create a subsampled hexagaonal grid surface // BrainModelSurfaceFlatHexagonalSubsample fhs(sourceBrainSet, sourceFiducialSurface, sourceSurface, subSampleTiles); fhs.execute(); // // Get the output (subsampled brain set) from the hexagonal surface generator // BrainSet* subSampledBrainSet = fhs.getSubsampledBrainSet(); BrainModelSurface* fiducialSubSampledSurface = subSampledBrainSet->getBrainModelSurface(0); BrainModelSurface* flatSubSampledSurface = subSampledBrainSet->getBrainModelSurface(1); CoordinateFile* fiducialCoords = fiducialSubSampledSurface->getCoordinateFile(); CoordinateFile* flatCoords = flatSubSampledSurface->getCoordinateFile(); TopologyFile* flatTopology = flatSubSampledSurface->getTopologyFile(); // // Add resampled file names to deformation map file // deformationMapFile->setSourceResampledCutTopoFileName("flat_deform_resampled.topo"); deformationMapFile->setSourceResampledFlatCoordFileName("flat_deform_resampled.FLAT.coord"); deformationMapFile->setSourceResampledDeformedFlatCoordFileName("deformed_flat_deform_resampled.FLAT.coord"); // // Write the subsampled brain set // subSampledBrainSet->setSpecFileName("flat_deform_resampled.spec"); intermediateFiles.push_back("flat_deform_resampled.spec"); subSampledBrainSet->writeTopologyFile(deformationMapFile->getSourceResampledCutTopoFileName(), flatTopology->getTopologyType(), flatTopology); intermediateFiles.push_back(deformationMapFile->getSourceResampledCutTopoFileName()); subSampledBrainSet->writeCoordinateFile("flat_deform_resampled.FIDUCIAL.coord", fiducialSubSampledSurface->getSurfaceType(), fiducialCoords); intermediateFiles.push_back("flat_deform_resampled.FIDUCIAL.coord"); subSampledBrainSet->writeCoordinateFile(deformationMapFile->getSourceResampledFlatCoordFileName(), flatSubSampledSurface->getSurfaceType(), flatCoords); intermediateFiles.push_back(deformationMapFile->getSourceResampledFlatCoordFileName()); // // Convert the subsampled flat coord file into a border file since // flat_fluid operates on a border file. // const QString coordsAsBorderFileName("resampled_coords_as_border.border"); const int maxLinksPerBorder = 100; BorderFile coordsAsBorder(flatCoords, maxLinksPerBorder); coordsAsBorder.writeFile(coordsAsBorderFileName); intermediateFiles.push_back(coordsAsBorderFileName); checkBorderNames(targetBorderResampledName); checkBorderNames(sourceBorderResampledName); // // Assemble arguments for flat_fluid program // QStringList str; str << targetBorderResampledName << sourceBorderResampledName << coordsAsBorderFileName << QString::number(beta, 'f', 6) << QString::number(varMult, 'f', 6) << QString::number(numberOfIterations) << "junk.image" << QString::number(0) << QString::number(0); if (DebugControl::getDebugOn()) { std::cout << std::endl; std::cout << "flat_fluid will be executed with the parameters: " << std::endl; std::cout << " " << str.join(" ").toAscii().constData() << std::endl; std::cout << std::endl; } // // Execute flat_fluid // BrainModelRunExternalProgram cup("flat_fluid", str, true); cup.execute(); outputOfFlatFluid = cup.getOutputText(); // // Keep track of files created by flat fluid // intermediateFiles.push_back("arch.deform.dat"); intermediateFiles.push_back("arch.orig.dat"); intermediateFiles.push_back("iter.dat"); intermediateFiles.push_back("source.dat"); intermediateFiles.push_back("source.deform.dat"); intermediateFiles.push_back("source.orig.dat"); intermediateFiles.push_back("source.points.deform.dat"); intermediateFiles.push_back("target.dat"); intermediateFiles.push_back("target.deform.dat"); intermediateFiles.push_back("target.orig.dat"); intermediateFiles.push_back("target.points.deform.dat"); // // Read the deformed border // BorderFile deformedCoordsAsBorder; try { deformedCoordsAsBorder.readFile("arch.deform.dat"); } catch (FileException& e) { QString msg("Unable to read \"arch.deform.dat\", which is the output of flat_fluid.\n"); msg += e.whatQString(); throw BrainModelAlgorithmException(msg); } if (deformedCoordsAsBorder.getTotalNumberOfLinks() <= 0) { QString msg("The output of flat_fluid, \"arch.deform.dat\", contains no links.\n" "This means that flat_fluid was unable to deform the input data."); throw BrainModelAlgorithmException(msg); } // // Convert the deformed border links to a BrainModelSurface // BrainModelSurface* deformedFlatSubSampledSurface = new BrainModelSurface(subSampledBrainSet); deformedFlatSubSampledSurface->setSurfaceType(flatSubSampledSurface->getSurfaceType()); CoordinateFile* deformedFlatCoords = deformedFlatSubSampledSurface->getCoordinateFile(); deformedCoordsAsBorder.copyLinksToCoordinateFile(deformedFlatCoords); deformedFlatSubSampledSurface->setTopologyFile(flatTopology); subSampledBrainSet->addBrainModel(deformedFlatSubSampledSurface); // // Write the deformed subsampled coordinates // subSampledBrainSet->writeCoordinateFile(deformationMapFile->getSourceResampledDeformedFlatCoordFileName(), deformedFlatSubSampledSurface->getSurfaceType(), deformedFlatCoords); intermediateFiles.push_back(deformationMapFile->getSourceResampledDeformedFlatCoordFileName()); // // Copy the user's input surface to a new deformed surface // deformedSourceSurface = new BrainModelSurface(*sourceSurface); sourceBrainSet->addBrainModel(deformedSourceSurface); // // Create a Point Projector for the flat subsampled surface. // BrainModelSurfacePointProjector bspp(flatSubSampledSurface, BrainModelSurfacePointProjector::SURFACE_TYPE_HINT_OTHER, false); // // Get the coordinate files for the user's surface and its // new deformed surface. // CoordinateFile* sourceCoords = sourceSurface->getCoordinateFile(); CoordinateFile* deformedSourceCoords = deformedSourceSurface->getCoordinateFile(); const int numCoords = sourceCoords->getNumberOfCoordinates(); // // See if X coordinate will need to be flipped // const bool diffHemFlag = (sourceBrainSet->getStructure() != targetBrainSet->getStructure()); // // Project each point in the users input surface to its deformed surface // for (int i = 0; i < numCoords; i++) { float xyz[3]; sourceCoords->getCoordinate(i, xyz); if (diffHemFlag) { xyz[0] = -xyz[0]; } // // Project source node onto subsampled surface // int nearestNode = -1; int tileNodes[3]; float tileAreas[3]; const int tile = bspp.projectBarycentric(xyz, nearestNode, tileNodes, tileAreas, true); // // Unproject using the deformed subsampled coordinate file // if (tile >= 0) { BrainModelSurfacePointProjector::unprojectPoint(tileNodes, tileAreas, deformedFlatCoords, xyz); } else if (nearestNode >= 0) { // JWH 08/08/03 2:15pm deformedSourceCoords->getCoordinate(nearestNode, xyz); deformedFlatCoords->getCoordinate(nearestNode, xyz); } deformedSourceCoords->setCoordinate(i, xyz); } // // Write the source deformed coordinates // QDir::setCurrent(sourceDirectory); QString defCoordName(deformationMapFile->getDeformedFileNamePrefix()); defCoordName.append(sourceCoords->getFileName()); deformationMapFile->setSourceDeformedFlatCoordFileName(defCoordName); deformedSourceCoords->writeFile(defCoordName); //sourceBrainSet->writeCoordinateFile(defCoordName, // deformedSourceSurface->getSurfaceType(), // deformedSourceCoords); QDir::setCurrent(originalDirectory); } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceDeformation.h0000664000175000017500000002640511572067322025602 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __BRAIN_MODEL_SURFACE_DEFORMATION_H__ #define __BRAIN_MODEL_SURFACE_DEFORMATION_H__ #include "BrainModelAlgorithm.h" #include "BrainModelSurface.h" class DeformationMapFile; /// class for deforming a surface to another surface class BrainModelSurfaceDeformation : public BrainModelAlgorithm { public: /// Constructor BrainModelSurfaceDeformation(BrainSet* brainSetIn, DeformationMapFile* deformationMapFileIn); /// Destructor virtual ~BrainModelSurfaceDeformation(); /// Execute the deformation virtual void execute() throw (BrainModelAlgorithmException); /// get deform source fiducial coord files bool getDeformSourceFiducialCoordFiles() const { return deformSourceFiducialCoordFiles; } /// set deform source fiducial coord files void setDeformSourceFiducialCoordFiles(const bool b) { deformSourceFiducialCoordFiles = b; } /// get deform source inflated coord files bool getDeformSourceInflatedCoordFiles() const { return deformSourceInflatedCoordFiles; } /// set deform source inflated coord files void setDeformSourceInflatedCoordFiles(const bool b) { deformSourceInflatedCoordFiles = b; } /// get deform source very inflated coord files bool getDeformSourceVeryInflatedCoordFiles() const { return deformSourceVeryInflatedCoordFiles; } /// set deform source very inflated coord files void setDeformSourceVeryInflatedCoordFiles(const bool b) { deformSourceVeryInflatedCoordFiles = b; } /// get deform source spherical coord files bool getDeformSourceSphericalCoordFiles() const { return deformSourceSphericalCoordFiles; } /// set deform source spherical coord files void setDeformSourceSphericalCoordFiles(const bool b) { deformSourceSphericalCoordFiles = b; } /// get deform source flat coord files bool getDeformSourceFlatCoordFiles() const { return deformSourceFlatCoordFiles; } /// set deform source flat coord files void setDeformSourceFlatCoordFiles(const bool b) { deformSourceFlatCoordFiles = b; } // get deform source flat lobar coord files //bool getDeformSourceFlatLobarCoordFiles() const { return deformSourceFlatLobarCoordFiles; } // set deform source flat lobar coord files //void setDeformSourceFlatLobarCoordFiles(const bool b) { deformSourceFlatLobarCoordFiles = b; } /// get the source to target deform data file errors message QString getSourceToTargetDeformDataFileErrors() const { return sourceToTargetDeformDataFileErrors; } /// get the target to source deform data file errors message QString getTargetToSourceDeformDataFileErrors() const { return targetToSourceDeformDataFileErrors; } /// deform the data files static void deformDataFiles(BrainSet* sourceBrain, BrainSet* targetBrain, const QString& sourceSpecName, const DeformationMapFile* dmf, const bool sourceToTargetFlag, const bool deformSourceFiducialCoordFilesIn, const bool deformSourceInflatedCoordFilesIn, const bool deformSourceVeryInflatedCoordFilesIn, const bool deformSourceSphericalCoordFilesIn, const bool deformSourceFlatCoordFilesIn, QString& deformErrorsMessage) throw (BrainModelAlgorithmException); /// set the surface that has viewing transformations that should be used void setsurfaceWithViewingTransformations(BrainModelSurface* bms); /// set the deforomation map file names (overrides defaults) void setDeformationMapFileNames(const QString& indivToAtlasDefMapFileName, const QString& atlasToIndivDefMapFileName); /// get the source brain set BrainSet* getSourceBrainSet() { return this->sourceBrainSet; } /// get the target brain set BrainSet* getTargetBrainSet() { return this->targetBrainSet; } /// get should data files be deformed bool getDeformDataFilesStatus() { return deformDataFilesFlag; } /// set data files be deformed void setDeformDataFilesStatus(bool status) { deformDataFilesFlag = status; } protected: /// Execute the subclass' deformation virtual void executeDeformation() throw (BrainModelAlgorithmException) = 0; /// update the viewing transformation for surface void updateViewingTransformation(BrainModelSurface* bms); /// update the viewing transformation for surfaces in brain set void updateViewingTransformation(BrainSet* bs); /// Create the deformation that maps target surface nodes into the deformed source surface. void createNodeDeformation(const BrainModelSurface* theSourceSurfaceDeformed, const BrainModelSurface* theTargetSurface, DeformationMapFile* theDeformationMap); /// Check a border file to see if it might be screwed up void checkSphericalBorder(const BrainModelSurface* bms, const BorderFile* bf, const QString indivTargetName) const; /// Create the indiv-to-atlas deformation field void createIndivAtlasDeformationFieldFile(const BrainModelSurface* surface, const BrainModelSurface* deformedSurface); /// Create the atlas-to-indiv deformation field void createAtlasIndivDeformationFieldFile( const BrainModelSurface* atlasSphereSurface, const BrainModelSurface* surface, const BrainModelSurface* deformedSurface); /// create the output spec and deformation file names void createOutputSpecAndDeformationFileNames(); /// resample the border files void resampleBorderFiles(const int stageNumber, const int cycleNumber, float sphericalRadius) throw (BrainModelAlgorithmException); /// project the border file for the brain set to create other types of border files void projectBorderFile(BrainSet* theBrainSet, const BrainModelSurface::SURFACE_TYPES borderType, const QString& sourceTargetString) throw (BrainModelAlgorithmException); /// read the source brain set void readSourceBrainSet() throw (BrainModelAlgorithmException); /// read the target brain set void readTargetBrainSet(int stageIndex) throw (BrainModelAlgorithmException); /// the deformation map file (do not delete) DeformationMapFile* deformationMapFile; /// directory deformation run from QString originalDirectory; /// the source brain set BrainSet* sourceBrainSet; /// the target brain set BrainSet* targetBrainSet; /// source fiducial coord file (do not delete) BrainModelSurface* sourceFiducialSurface; /// source coordinate file (do not delete) BrainModelSurface* sourceSurface; /// deformed source coordinate file (do not delete) BrainModelSurface* deformedSourceSurface; /// source topology file (do not delete) TopologyFile* sourceTopologyFile; /// source border file (do not delete) BorderFile* sourceBorderFile; /// directory containing source files QString sourceDirectory; /// name of source resampled border file QString sourceBorderResampledName; /// source to target deformation spec file name QString sourceToTargetSpecFileName; /// source to target deformation map file name QString sourceToTargetDeformationMapFileName; /// target fiducial coord file (do not delete) BrainModelSurface* targetFiducialSurface; /// target coordinate file (do not delete) BrainModelSurface* targetSurface; /// target topology file (do not delete) TopologyFile* targetTopologyFile; /// target border file (do not delete) BorderFile* targetBorderFile; /// directory containing target files QString targetDirectory; /// name of target resampled border file QString targetBorderResampledName; /// target to source deformation spec file name QString targetToSourceSpecFileName; /// target to source deformation map file name QString targetToSourceDeformationMapFileName; /// keeps track of intermediate files std::vector intermediateFiles; /// keeps source border from being flipped multiple times bool sourceBorderFlippedForDifferentHemispheres; /// deform source fiducial coord files bool deformSourceFiducialCoordFiles; /// deform source inflated coord files bool deformSourceInflatedCoordFiles; /// deform source very inflated coord files bool deformSourceVeryInflatedCoordFiles; /// deform source spherical coord files bool deformSourceSphericalCoordFiles; /// deform source flat coord files bool deformSourceFlatCoordFiles; // deform source flat lobar coord files //bool deformSourceFlatLobarCoordFiles; /// source to target deform data file errors message QString sourceToTargetDeformDataFileErrors; /// target to source deform data file errors message QString targetToSourceDeformDataFileErrors; /// translation for default view float defaultViewTranslation[3]; /// scaling for default view float defaultViewScaling[3]; /// rotation for default view float defaultViewRotation[16]; /// default view valid bool defaultViewValid; /// should data files be deformed bool deformDataFilesFlag; }; #endif // __BRAIN_MODEL_SURFACE_DEFORMATION_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceDeformation.cxx0000664000175000017500000016616311572067322026163 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include "vtkMath.h" #include "BorderFile.h" #include "BorderFileProjector.h" #include "BorderProjectionFile.h" #include "BrainModelBorderSet.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceDeformation.h" #include "BrainModelSurfaceDeformDataFile.h" #include "BrainModelSurfacePointProjector.h" #include "BrainSet.h" #include "DebugControl.h" #include "DeformationFieldFile.h" #include "DeformationMapFile.h" #include "FileUtilities.h" #include "MathUtilities.h" #include "SpecFile.h" #include "StringUtilities.h" #include "TransformationMatrixFile.h" /** * Constructor */ BrainModelSurfaceDeformation::BrainModelSurfaceDeformation(BrainSet* brainSetIn, DeformationMapFile* deformationMapFileIn) : BrainModelAlgorithm(brainSetIn) { deformationMapFile = deformationMapFileIn; sourceBrainSet = NULL; targetBrainSet = NULL; sourceBorderFlippedForDifferentHemispheres = false; deformSourceFiducialCoordFiles = true; deformSourceInflatedCoordFiles = true; deformSourceVeryInflatedCoordFiles = true; deformSourceSphericalCoordFiles = true; deformSourceFlatCoordFiles = true; //deformSourceFlatLobarCoordFiles = true; defaultViewValid = false; deformDataFilesFlag = true; } /** * Destructor */ BrainModelSurfaceDeformation::~BrainModelSurfaceDeformation() { if (sourceBrainSet != NULL) { delete sourceBrainSet; sourceBrainSet = NULL; } if (targetBrainSet != NULL) { delete targetBrainSet; targetBrainSet = NULL; } } /** * set the surface that has viewing transformations that should be used. */ void BrainModelSurfaceDeformation::setsurfaceWithViewingTransformations(BrainModelSurface* bms) { this->defaultViewValid = false; if (bms != NULL) { this->defaultViewValid = true; bms->getTranslation(0, this->defaultViewTranslation); bms->getScaling(0, this->defaultViewScaling); bms->getRotationMatrix(0, this->defaultViewRotation); } } /** * update the viewing transformation for surface. */ void BrainModelSurfaceDeformation::updateViewingTransformation(BrainModelSurface* bms) { if (defaultViewValid) { bms->setTranslation(0, this->defaultViewTranslation); bms->setScaling(0, this->defaultViewScaling); bms->setRotationMatrix(0, this->defaultViewRotation); } } /** * update the viewing transformation for surfaces in brain set. */ void BrainModelSurfaceDeformation::updateViewingTransformation(BrainSet* bs) { for (int i = 0; i < bs->getNumberOfBrainModels(); i++) { BrainModelSurface* bms = bs->getBrainModelSurface(i); if (bms != NULL) { this->updateViewingTransformation(bms); } } } /** * Read in the source spec file and create a BrainSet for it. */ void BrainModelSurfaceDeformation::readSourceBrainSet() throw (BrainModelAlgorithmException) { // // Get the source spec file name. // const QString specFileName(deformationMapFile->getSourceSpecFileName()); // // Create the new brain set // sourceBrainSet = new BrainSet; // // Read in the source spec file and select the deformation files // SpecFile sf; QString borderName; DeformationMapFile::BORDER_FILE_TYPE borderType; deformationMapFile->getSourceBorderFileName(borderName, borderType); try { sf.readFile(specFileName); } catch(FileException& /*e*/) { QString msg("Error reading spec file "); msg.append(specFileName); } sf.setDeformationSelectedFiles(deformationMapFile->getSourceClosedTopoFileName(), deformationMapFile->getSourceCutTopoFileName(), deformationMapFile->getSourceFiducialCoordFileName(), deformationMapFile->getSourceSphericalCoordFileName(), deformationMapFile->getSourceFlatCoordFileName(), borderName, false, sf.getStructure()); // // Read in the data files for the source brain set. // Note: BrainSet::readSpecFile() will change the current directory so restore // current directory after files are read. // QString currentDirectory(QDir::currentPath()); std::vector errorMessages; sourceBrainSet->readSpecFile(BrainSet::SPEC_FILE_READ_MODE_NORMAL, sf, specFileName, errorMessages, NULL, NULL); sourceDirectory = QDir::currentPath(); QDir::setCurrent(currentDirectory); if (errorMessages.empty() == false) { const QString msg(StringUtilities::combine(errorMessages, "\n")); throw BrainModelAlgorithmException(msg); } // // See if border file needs to be projected // switch(deformationMapFile->getFlatOrSphereSelection()) { case DeformationMapFile::DEFORMATION_TYPE_FLAT: switch (borderType) { case DeformationMapFile::BORDER_FILE_UNKNOWN: throw BrainModelAlgorithmException("Source border file is of unknown type."); break; case DeformationMapFile::BORDER_FILE_FLAT: break; case DeformationMapFile::BORDER_FILE_FLAT_LOBAR: break; case DeformationMapFile::BORDER_FILE_SPHERICAL: // // Project spherical border to create flat border // projectBorderFile(sourceBrainSet, BrainModelSurface::SURFACE_TYPE_SPHERICAL, "source"); break; case DeformationMapFile::BORDER_FILE_PROJECTION: break; } break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: switch (borderType) { case DeformationMapFile::BORDER_FILE_UNKNOWN: throw BrainModelAlgorithmException("Source border file is of unknown type."); break; case DeformationMapFile::BORDER_FILE_FLAT: // // Project flat border to create spherical border // projectBorderFile(sourceBrainSet, BrainModelSurface::SURFACE_TYPE_FLAT, "source"); break; case DeformationMapFile::BORDER_FILE_FLAT_LOBAR: // // Project flat border to create spherical border // projectBorderFile(sourceBrainSet, BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR, "source"); break; case DeformationMapFile::BORDER_FILE_SPHERICAL: break; case DeformationMapFile::BORDER_FILE_PROJECTION: break; } break; } // // Set file pointers for source // sourceFiducialSurface = sourceBrainSet->getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_FIDUCIAL); if (sourceFiducialSurface == NULL) { throw BrainModelAlgorithmException("Unablet to find source fiducial coordinate file."); } switch(deformationMapFile->getFlatOrSphereSelection()) { case DeformationMapFile::DEFORMATION_TYPE_FLAT: sourceSurface = sourceBrainSet->getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_FLAT); sourceBorderFile = sourceBrainSet->getBorderSet()->copyBordersOfSpecifiedType(BrainModelSurface::SURFACE_TYPE_FLAT); if (sourceSurface == NULL) { sourceSurface = sourceBrainSet->getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR); sourceBorderFile = sourceBrainSet->getBorderSet()->copyBordersOfSpecifiedType(BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR); } break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: sourceSurface = sourceBrainSet->getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_SPHERICAL); sourceBorderFile = sourceBrainSet->getBorderSet()->copyBordersOfSpecifiedType(BrainModelSurface::SURFACE_TYPE_SPHERICAL); checkSphericalBorder(sourceSurface, sourceBorderFile, "Individual"); break; } if (sourceSurface == NULL) { throw BrainModelAlgorithmException("Unable to find source coordinate file."); } sourceTopologyFile = sourceSurface->getTopologyFile(); if (sourceTopologyFile == NULL) { throw BrainModelAlgorithmException("Unable to find source topology file."); } if (sourceBorderFile == NULL) { throw BrainModelAlgorithmException("Unable to find source border file."); } else if (sourceBorderFile->getNumberOfBorders() <= 0) { throw BrainModelAlgorithmException("Source border file (" + borderName + ") contains no borders, was not found, or is not in the spec file."); } } /** * Check a border file to see if it might be screwed up */ void BrainModelSurfaceDeformation::checkSphericalBorder(const BrainModelSurface* bms, const BorderFile* bf, const QString indivTargetName) const { const float halfRadius = bms->getSphericalSurfaceRadius() * 0.5; bool warnFlag = false; const int numBorders = bf->getNumberOfBorders(); for (int i = 0; i < numBorders; i++) { const Border* b = bf->getBorder(i); const int numLinks = b->getNumberOfLinks(); for (int i = 0; i < (numLinks - 1); i++) { const float* b1 = b->getLinkXYZ(i); const float* b2 = b->getLinkXYZ(i + 1); const float dist = MathUtilities::distance3D(b1, b2); if (dist > halfRadius) { warnFlag = true; break; } } if (warnFlag) { break; } } if (warnFlag) { QString msg("Warning: Border file for "); msg.append(indivTargetName); msg.append(" has abnormally large spacing.\n"); msg.append("Do you want to continue ?\n"); msg.append("\n"); msg.append("If you choose to cancel the deformation then\n"); msg.append(" 1) launch Caret5 in the approprate directory.\n"); msg.append(" 2) View the landmark borders on the spherical surface \n"); msg.append(" with Display Control: Borders: Draw Borders as Points and Lines.\n"); msg.append(" 3) Look for misprojected border points (probably at the origin)"); msg.append(" using Display Control: Surface Miscellaneous: Drawing Mode: Hide Surface.\n"); msg.append(" 4) Delete the misprojected border points with Layers: Borders\n"); msg.append(" Delete Border Point With Mouse.\n"); msg.append(" 5) Save the modified border projection file.\n"); QWidget* parentWidget = brainSet->getProgressDialogParent(); if (parentWidget != NULL) { if (QMessageBox::warning(parentWidget, "Warning", msg, "Continue", "Cancel") == 1) { throw BrainModelAlgorithmException("Canceled by user"); } } } } /** * Read in the target spec file and create a BrainSet for it. */ void BrainModelSurfaceDeformation::readTargetBrainSet(int stageIndex) throw (BrainModelAlgorithmException) { // // Get the target spec file name. // const QString specFileName(deformationMapFile->getTargetSpecFileName()); // // Create the new brain set // targetBrainSet = new BrainSet; // // Read in the target spec file and select the deformation files // SpecFile sf; QString borderName; DeformationMapFile::BORDER_FILE_TYPE borderType; deformationMapFile->getTargetBorderFileName(stageIndex, borderName, borderType); try { sf.readFile(specFileName); } catch(FileException& /*e*/) { QString msg("Error reading spec file "); msg.append(specFileName); } sf.setDeformationSelectedFiles(deformationMapFile->getTargetClosedTopoFileName(), deformationMapFile->getTargetCutTopoFileName(), deformationMapFile->getTargetFiducialCoordFileName(), deformationMapFile->getTargetSphericalCoordFileName(), deformationMapFile->getTargetFlatCoordFileName(), borderName, false, sf.getStructure()); // // Read in the data files for the target brain set. // Note: BrainSet::readSpecFile() will change the current directory so restore // current directory after files are read. // QString currentDirectory(QDir::currentPath()); std::vector errorMessages; targetBrainSet->readSpecFile(BrainSet::SPEC_FILE_READ_MODE_NORMAL, sf, specFileName, errorMessages, NULL, NULL); targetDirectory = QDir::currentPath(); QDir::setCurrent(currentDirectory); if (errorMessages.empty() == false) { const QString msg(StringUtilities::combine(errorMessages, "\n")); throw BrainModelAlgorithmException(msg); } // // See if border file needs to be projected // switch(deformationMapFile->getFlatOrSphereSelection()) { case DeformationMapFile::DEFORMATION_TYPE_FLAT: switch (borderType) { case DeformationMapFile::BORDER_FILE_UNKNOWN: throw BrainModelAlgorithmException("Target border file is of unknown type."); break; case DeformationMapFile::BORDER_FILE_FLAT: break; case DeformationMapFile::BORDER_FILE_FLAT_LOBAR: break; case DeformationMapFile::BORDER_FILE_SPHERICAL: // // Project spherical border to create flat border // projectBorderFile(targetBrainSet, BrainModelSurface::SURFACE_TYPE_SPHERICAL, "target"); break; case DeformationMapFile::BORDER_FILE_PROJECTION: break; } break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: switch (borderType) { case DeformationMapFile::BORDER_FILE_UNKNOWN: throw BrainModelAlgorithmException("Target border file is of unknown type."); break; case DeformationMapFile::BORDER_FILE_FLAT: // // Project flat border to create spherical border // projectBorderFile(targetBrainSet, BrainModelSurface::SURFACE_TYPE_FLAT, "target"); break; case DeformationMapFile::BORDER_FILE_FLAT_LOBAR: // // Project flat border to create spherical border // projectBorderFile(targetBrainSet, BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR, "target"); break; case DeformationMapFile::BORDER_FILE_SPHERICAL: break; case DeformationMapFile::BORDER_FILE_PROJECTION: break; } break; } // // Set file pointers for target // targetFiducialSurface = targetBrainSet->getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_FIDUCIAL); if (targetFiducialSurface == NULL) { throw BrainModelAlgorithmException("Unablet to find target fiducial coordinate file."); } switch(deformationMapFile->getFlatOrSphereSelection()) { case DeformationMapFile::DEFORMATION_TYPE_FLAT: targetSurface = targetBrainSet->getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_FLAT); targetBorderFile = targetBrainSet->getBorderSet()->copyBordersOfSpecifiedType(BrainModelSurface::SURFACE_TYPE_FLAT); if (targetSurface == NULL) { targetSurface = targetBrainSet->getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR); targetBorderFile = targetBrainSet->getBorderSet()->copyBordersOfSpecifiedType(BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR); } break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: targetSurface = targetBrainSet->getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_SPHERICAL); targetBorderFile = targetBrainSet->getBorderSet()->copyBordersOfSpecifiedType(BrainModelSurface::SURFACE_TYPE_SPHERICAL); checkSphericalBorder(targetSurface, targetBorderFile, "Target"); break; } if (targetSurface == NULL) { throw BrainModelAlgorithmException("Unable to find target coordinate file."); } targetTopologyFile = targetSurface->getTopologyFile(); if (targetTopologyFile == NULL) { throw BrainModelAlgorithmException("Unable to find target topology file."); } if (targetBorderFile == NULL) { throw BrainModelAlgorithmException("Unable to find target border file."); } else if (targetBorderFile->getNumberOfBorders() <= 0) { throw BrainModelAlgorithmException("Target border file (" + borderName + ") contains no borders, was not found, or is not in the spec file."); } } /** * Project the border file */ void BrainModelSurfaceDeformation::projectBorderFile(BrainSet* theBrainSet, const BrainModelSurface::SURFACE_TYPES borderType, const QString& sourceTargetString) throw (BrainModelAlgorithmException) { // // Get the border file and make sure it has borders // BorderFile* bf = theBrainSet->getBorderSet()->copyBordersOfSpecifiedType(borderType); if (bf == NULL) { QString s("Unable to find "); s.append(sourceTargetString); s.append(" border file."); throw BrainModelAlgorithmException(s); } else if (bf->getNumberOfBorders() == 0) { QString s(sourceTargetString); s.append(" border file is empty."); throw BrainModelAlgorithmException(s); } // // Get the surface for projection // BrainModelSurface* bms = theBrainSet->getBrainModelSurfaceOfType(borderType); if (bms == NULL) { QString s("Unable to find surface for projecting the "); s.append(sourceTargetString); s.append(" border file."); throw BrainModelAlgorithmException(s); } // // Create a border file projector // BorderFileProjector projector(bms, true); // // Get and clear the border projection file // BorderProjectionFile bpf; // // Project the border file // projector.projectBorderFile(bf, &bpf, NULL); // // Clear the border files // theBrainSet->deleteAllBorders(); // // Apply the border projection file to all surfaces // theBrainSet->getBorderSet()->copyBordersFromBorderProjectionFile(&bpf); } /** * Resample border files as needed. */ void BrainModelSurfaceDeformation::resampleBorderFiles(const int stageNumber, const int cycleNumber, float sphericalRadius) throw (BrainModelAlgorithmException) { // // Make sure source and target border files have same number of borders // if (sourceBorderFile->getNumberOfBorders() != targetBorderFile->getNumberOfBorders()) { throw BrainModelAlgorithmException( "Source and target border files have different numbers of borders."); } // // Get the type of resampling // DeformationMapFile::BORDER_RESAMPLING_TYPE resampleType; float resampleValue; deformationMapFile->getBorderResampling(resampleType, resampleValue); switch(resampleType) { case DeformationMapFile::BORDER_RESAMPLING_NONE: break; case DeformationMapFile::BORDER_RESAMPLING_FROM_BORDER_FILE: case DeformationMapFile::BORDER_RESAMPLING_VALUE: { // // Resample the borders // const int numBorders = sourceBorderFile->getNumberOfBorders(); for (int i = 0; i < numBorders; i++) { Border* sourceBorder = sourceBorderFile->getBorder(i); const int sourceBorderNumLinks = sourceBorder->getNumberOfLinks(); if (sourceBorderNumLinks > 1) { // for (int j = 0; j < sourceBorderNumLinks; j++) { // // Get the sampling density // float resampling = resampleValue; switch(resampleType) { case DeformationMapFile::BORDER_RESAMPLING_NONE: break; case DeformationMapFile::BORDER_RESAMPLING_FROM_BORDER_FILE: resampling = sourceBorder->getSamplingDensity(); break; case DeformationMapFile::BORDER_RESAMPLING_VALUE: break; } // // Resample the source border // int newNumLinks = 2; sourceBorder->resampleBorderToDensity(resampling, 2, newNumLinks); // // Get the name of the border // const QString borderName = sourceBorder->getName(); // // Find target border with same name // Border* targetBorder = targetBorderFile->getBorderByName(borderName); if (targetBorder == NULL) { QString msg("Border named "); msg.append(borderName); msg.append(" not found in target borders."); throw BrainModelAlgorithmException(msg); } // // Resample target border to match source border // targetBorder->resampleBorderToNumberOfLinks(newNumLinks); // } } } } break; } // // Make target borders have the same order as the source borders // BorderFile* tempBorderFile = new BorderFile; const int numBorders = sourceBorderFile->getNumberOfBorders(); for (int i = 0; i < numBorders; i++) { const Border* sb = sourceBorderFile->getBorder(i); const QString name = sb->getName(); Border* tb = targetBorderFile->getBorderByName(name); if (tb == NULL) { QString msg("Border named "); msg.append(name); msg.append(" not found in target borders."); throw BrainModelAlgorithmException(msg); } tempBorderFile->addBorder(*tb); } delete targetBorderFile; targetBorderFile = tempBorderFile; // // If source and target hemispheres are different, flip X coord of source border file // if (stageNumber <= 1) { if (sourceBrainSet->getStructure() != targetBrainSet->getStructure()) { if (sourceBorderFlippedForDifferentHemispheres == false) { sourceBorderFlippedForDifferentHemispheres = true; TransformationMatrix tm; tm.scale(-1.0, 1.0, 1.0); sourceBorderFile->applyTransformationMatrix(tm); std::cout << "Src/Tgt Different Hemispheres" << std::endl; } } } // // set the resampled border types // switch(deformationMapFile->getFlatOrSphereSelection()) { case DeformationMapFile::DEFORMATION_TYPE_FLAT: targetBorderFile->setHeaderTag(AbstractFile::headerTagConfigurationID, "FLAT"); sourceBorderFile->setHeaderTag(AbstractFile::headerTagConfigurationID, "FLAT"); break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: targetBorderFile->setHeaderTag(AbstractFile::headerTagConfigurationID, "SPHERICAL"); sourceBorderFile->setHeaderTag(AbstractFile::headerTagConfigurationID, "SPHERICAL"); break; } // // Apply spherical radius // if (sphericalRadius > 0.0) { sourceBorderFile->setSphericalBorderRadius(sphericalRadius); targetBorderFile->setSphericalBorderRadius(sphericalRadius); } // // Save the resampled source and target border files // sourceBorderResampledName = "source_after_resample_"; if (stageNumber >= 0) { sourceBorderResampledName += ("stage_" + QString::number(stageNumber)); } if (cycleNumber >= 0) { sourceBorderResampledName += ("_cycle_" + QString::number(cycleNumber)); } sourceBorderResampledName += ".border"; targetBorderResampledName = "target_after_resample_"; if (stageNumber >= 0) { targetBorderResampledName += ("stage_" + QString::number(stageNumber)); } if (cycleNumber >= 0) { targetBorderResampledName += ("_cycle_" + QString::number(cycleNumber)); } targetBorderResampledName += ".border"; sourceBorderFile->writeFile(sourceBorderResampledName); targetBorderFile->writeFile(targetBorderResampledName); intermediateFiles.push_back(sourceBorderResampledName); intermediateFiles.push_back(targetBorderResampledName); } /** * Create the output spec and deformation file names. */ void BrainModelSurfaceDeformation::createOutputSpecAndDeformationFileNames() { sourceToTargetSpecFileName = BrainModelSurfaceDeformDataFile::createDeformedFileName( deformationMapFile->getSourceSpecFileName(), deformationMapFile->getTargetSpecFileName(), deformationMapFile->getDeformedFileNamePrefix(), deformationMapFile->getNumberOfNodes(), false); if (sourceToTargetDeformationMapFileName.isEmpty()) { sourceToTargetDeformationMapFileName = BrainModelSurfaceDeformDataFile::createDeformedSpecFileName( deformationMapFile->getDeformedFileNamePrefix(), deformationMapFile->getSourceSpecFileName(), deformationMapFile->getTargetSpecFileName()); //sourceToTargetDeformationMapFileName = // BrainModelSurfaceDeformDataFile::createDeformedFileName( // deformationMapFile->getSourceSpecFileName(), // deformationMapFile->getTargetSpecFileName(), // deformationMapFile->getDeformedFileNamePrefix(), // deformationMapFile->getNumberOfNodes(), // true); } targetToSourceSpecFileName = BrainModelSurfaceDeformDataFile::createDeformedFileName( deformationMapFile->getTargetSpecFileName(), deformationMapFile->getSourceSpecFileName(), deformationMapFile->getDeformedFileNamePrefix(), deformationMapFile->getNumberOfNodes(), false); if (targetToSourceDeformationMapFileName.isEmpty()) { targetToSourceDeformationMapFileName = BrainModelSurfaceDeformDataFile::createDeformedSpecFileName( deformationMapFile->getDeformedFileNamePrefix(), deformationMapFile->getTargetSpecFileName(), deformationMapFile->getSourceSpecFileName()); //targetToSourceDeformationMapFileName = // BrainModelSurfaceDeformDataFile::createDeformedFileName( // deformationMapFile->getTargetSpecFileName(), // deformationMapFile->getSourceSpecFileName(), // deformationMapFile->getDeformedFileNamePrefix(), // deformationMapFile->getNumberOfNodes(), // true); } } /** * set the deforomation map file names (overrides defaults). */ void BrainModelSurfaceDeformation::setDeformationMapFileNames( const QString& indivToAtlasDefMapFileName, const QString& atlasToIndivDefMapFileName) { sourceToTargetDeformationMapFileName = indivToAtlasDefMapFileName; targetToSourceDeformationMapFileName = atlasToIndivDefMapFileName; } /** * Create the deformation that maps target surface nodes into the deformed source surface. */ void BrainModelSurfaceDeformation::createNodeDeformation(const BrainModelSurface* theSourceSurfaceDeformed, const BrainModelSurface* theTargetSurface, DeformationMapFile* theDeformationMap) { // // Create a Point Projector for the deformed surface. // BrainModelSurfacePointProjector::SURFACE_TYPE_HINT surfaceTypeHint = BrainModelSurfacePointProjector::SURFACE_TYPE_HINT_FLAT; switch (deformationMapFile->getFlatOrSphereSelection()) { case DeformationMapFile::DEFORMATION_TYPE_FLAT: break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: surfaceTypeHint = BrainModelSurfacePointProjector::SURFACE_TYPE_HINT_SPHERE; break; } BrainModelSurfacePointProjector bspp(theSourceSurfaceDeformed, surfaceTypeHint, false); // // Check for spherical deformation // float deformedRadius = 1.0; bool sphericalDeformationFlag = false; switch (deformationMapFile->getFlatOrSphereSelection()) { case DeformationMapFile::DEFORMATION_TYPE_FLAT: break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: sphericalDeformationFlag = true; deformedRadius = theSourceSurfaceDeformed->getSphericalSurfaceRadius(); break; } // // Get the source coordinates // const CoordinateFile* theSourceCoords = theSourceSurfaceDeformed->getCoordinateFile(); // // Get the target coordinates // const CoordinateFile* coords = theTargetSurface->getCoordinateFile(); const int numCoords = coords->getNumberOfCoordinates(); // // Set the number of nodes in the deformation file // theDeformationMap->setNumberOfNodes(numCoords); // // Project each target node into the source deformed surface // for (int i = 0; i < numCoords; i++) { float xyz[3]; coords->getCoordinate(i, xyz); // // Push nodes onto sphere if spherical deformation // if (sphericalDeformationFlag) { const float radius = MathUtilities::vectorLength(xyz); if (radius != 0.0) { const float scale = deformedRadius / radius; xyz[0] *= scale; xyz[1] *= scale; xyz[2] *= scale; } } // // Project target node onto source deformed surface // int nearestNode = -1; int tileNodes[3]; float tileAreas[3]; const int tile = bspp.projectBarycentric(xyz, nearestNode, tileNodes, tileAreas, true); // // Unproject using the deformed source coordinate file // if (tile >= 0) { // // First node should be closest one // const float distToNode[3] = { vtkMath::Distance2BetweenPoints(xyz, (float*)theSourceCoords->getCoordinate(tileNodes[0])), vtkMath::Distance2BetweenPoints(xyz, (float*)theSourceCoords->getCoordinate(tileNodes[1])), vtkMath::Distance2BetweenPoints(xyz, (float*)theSourceCoords->getCoordinate(tileNodes[2])) }; /* if ((distToNode[1] < distToNode[0]) && (distToNode[1] < distToNode[2])) { std::swap(tileNodes[0], tileNodes[1]); std::swap(tileAreas[0], tileAreas[1]); } else if ((distToNode[2] < distToNode[0]) && (distToNode[2] < distToNode[1])) { std::swap(tileNodes[0], tileNodes[2]); std::swap(tileAreas[0], tileAreas[2]); } */ // // Note: nodes and areas do not correspond by index due to an incorrect, early // implementation in caret // See BrainModelSurfacePointProjector for implementation // Node Area // Index Index // 0 1 // 1 2 // 2 0 // if ((distToNode[1] < distToNode[0]) && (distToNode[1] < distToNode[2])) { std::swap(tileNodes[0], tileNodes[1]); std::swap(tileAreas[2], tileAreas[1]); // this is correct } else if ((distToNode[2] < distToNode[0]) && (distToNode[2] < distToNode[1])) { std::swap(tileNodes[0], tileNodes[2]); std::swap(tileAreas[0], tileAreas[1]); // this is correct } } else if (nearestNode >= 0) { tileNodes[0] = nearestNode; tileNodes[1] = nearestNode; tileNodes[2] = nearestNode; tileAreas[0] = 1.0; tileAreas[1] = 0.0; tileAreas[2] = 0.0; } else { tileNodes[0] = -1; tileNodes[1] = -1; tileNodes[2] = -1; tileAreas[0] = 0.0; tileAreas[1] = 0.0; tileAreas[2] = 0.0; } // // Set the node for the deformation file // theDeformationMap->setDeformDataForNode(i, tileNodes, tileAreas); } } /** * Deform the data files. */ void BrainModelSurfaceDeformation::deformDataFiles(BrainSet* sourceBrain, BrainSet* targetBrain, const QString& sourceSpecName, const DeformationMapFile* dmf, const bool sourceToTargetFlag, const bool deformSourceFiducialCoordFilesIn, const bool deformSourceInflatedCoordFilesIn, const bool deformSourceVeryInflatedCoordFilesIn, const bool deformSourceSphericalCoordFilesIn, const bool deformSourceFlatCoordFilesIn, QString& deformErrorsMessage) throw (BrainModelAlgorithmException) { // // Read in the source spec file // SpecFile sf; try { sf.readFile(sourceSpecName); } catch (FileException& e) { throw BrainModelAlgorithmException(e.whatQString()); } // // deform areal estimation files // BrainModelSurfaceDeformDataFile::deformNodeAttributeFiles( dmf, BrainModelSurfaceDeformDataFile::DATA_FILE_AREAL_ESTIMATION, sf.arealEstimationFile, deformErrorsMessage); // // deform atlas files // BrainModelSurfaceDeformDataFile::deformGiftiNodeDataFiles( dmf, BrainModelSurfaceDeformDataFile::DATA_FILE_ATLAS, sf.atlasFile, deformErrorsMessage); // lat lon files // // BrainModelSurfaceDeformDataFile::deformNodeAttributeFiles( dmf, BrainModelSurfaceDeformDataFile::DATA_FILE_LAT_LON, sf.latLonFile, deformErrorsMessage); // // deform metric files // BrainModelSurfaceDeformDataFile::deformGiftiNodeDataFiles( dmf, BrainModelSurfaceDeformDataFile::DATA_FILE_METRIC, sf.metricFile, deformErrorsMessage); // // deform paint files // BrainModelSurfaceDeformDataFile::deformGiftiNodeDataFiles( dmf, BrainModelSurfaceDeformDataFile::DATA_FILE_PAINT, sf.paintFile, deformErrorsMessage); // // deform rgb paint files // BrainModelSurfaceDeformDataFile::deformGiftiNodeDataFiles( dmf, BrainModelSurfaceDeformDataFile::DATA_FILE_RGB_PAINT, sf.rgbPaintFile, deformErrorsMessage); // // deform surface shape files // BrainModelSurfaceDeformDataFile::deformGiftiNodeDataFiles( dmf, BrainModelSurfaceDeformDataFile::DATA_FILE_SHAPE, sf.surfaceShapeFile, deformErrorsMessage); // // deform topography files // BrainModelSurfaceDeformDataFile::deformNodeAttributeFiles( dmf, BrainModelSurfaceDeformDataFile::DATA_FILE_TOPOGRAPHY, sf.topographyFile, deformErrorsMessage); // // deform border files // BrainModelSurfaceDeformDataFile::deformBorderFiles( sourceBrain, targetBrain, dmf, BrainModelSurfaceDeformDataFile::DATA_FILE_BORDER_FLAT, sf.flatBorderFile, deformErrorsMessage); // // deform border files // BrainModelSurfaceDeformDataFile::deformBorderFiles( sourceBrain, targetBrain, dmf, BrainModelSurfaceDeformDataFile::DATA_FILE_BORDER_SPHERICAL, sf.sphericalBorderFile, deformErrorsMessage); // // deform border files // BrainModelSurfaceDeformDataFile::deformBorderFiles( sourceBrain, targetBrain, dmf, BrainModelSurfaceDeformDataFile::DATA_FILE_BORDER_PROJECTION, sf.borderProjectionFile, deformErrorsMessage); // // deform cell files // BrainModelSurfaceDeformDataFile::deformCellOrFociFiles( sourceBrain, targetBrain, dmf, sf.cellFile, false, deformErrorsMessage); // // deform cell files // BrainModelSurfaceDeformDataFile::deformCellOrFociProjectionFiles( sourceBrain, targetBrain, dmf, sf.cellProjectionFile, false, deformErrorsMessage); // // deform foci files // BrainModelSurfaceDeformDataFile::deformCellOrFociFiles( sourceBrain, targetBrain, dmf, sf.fociFile, true, deformErrorsMessage); // // deform foci files // BrainModelSurfaceDeformDataFile::deformCellOrFociProjectionFiles( sourceBrain, targetBrain, dmf, sf.fociProjectionFile, true, deformErrorsMessage); // // Determine which colors files are needed // const bool linkAreaColorFiles = (sf.arealEstimationFile.files.size() > 0) || (sf.atlasFile.files.size() > 0) || (sf.paintFile.files.size() > 0) || (sf.topographyFile.files.size() > 0); const bool linkBorderColorFiles = (sf.flatBorderFile.files.size() > 0) || (sf.sphericalBorderFile.files.size() > 0) || (sf.borderProjectionFile.files.size() > 0); const bool linkCellColorFiles = ((sf.cellFile.files.size() > 0) || (sf.cellProjectionFile.files.size() > 0)); const bool linkFociColorFiles = ((sf.fociFile.files.size() > 0) || (sf.fociProjectionFile.files.size() > 0)); // // link the needed color files // BrainModelSurfaceDeformDataFile::linkColorFiles(dmf, linkAreaColorFiles, linkBorderColorFiles, linkCellColorFiles, linkFociColorFiles, deformErrorsMessage); // // Only spherical deformation deforms coord files // bool doCoordFiles = false; switch(dmf->getFlatOrSphereSelection()) { case DeformationMapFile::DEFORMATION_TYPE_FLAT: break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: doCoordFiles = true; break; } // // If deforming source files // if (sourceToTargetFlag && doCoordFiles) { // // If fiducial coord files should be deformed // if (deformSourceFiducialCoordFilesIn) { BrainModelSurfaceDeformDataFile::deformCoordinateFiles(dmf, sf.fiducialCoordFile, deformErrorsMessage); } // // If inflated coord files should be deformed // if (deformSourceInflatedCoordFilesIn) { BrainModelSurfaceDeformDataFile::deformCoordinateFiles(dmf, sf.inflatedCoordFile, deformErrorsMessage); } // // If very inflated coord files should be deformed // if (deformSourceVeryInflatedCoordFilesIn) { BrainModelSurfaceDeformDataFile::deformCoordinateFiles(dmf, sf.veryInflatedCoordFile, deformErrorsMessage); } // // If spherical coord files should be deformed // if (deformSourceSphericalCoordFilesIn) { BrainModelSurfaceDeformDataFile::deformCoordinateFiles(dmf, sf.sphericalCoordFile, deformErrorsMessage); } // // If flat coord files should be deformed // if (deformSourceFlatCoordFilesIn) { BrainModelSurfaceDeformDataFile::deformFlatCoordinateFiles(dmf, sf.flatCoordFile, deformErrorsMessage); } } } /** * Create the indiv to atlas deformation field */ void BrainModelSurfaceDeformation::createIndivAtlasDeformationFieldFile(const BrainModelSurface* sphereSurface, const BrainModelSurface* deformedSphereSurfaceIn) { DeformationFieldFile dff; sphereSurface->createDeformationField(deformedSphereSurfaceIn, -1, "Spherical Deformation", dff); // // Write the deformation field file // QDir::setCurrent(sourceDirectory); const CoordinateFile* defCoordsIn = deformedSphereSurfaceIn->getCoordinateFile(); QString name(FileUtilities::filenameWithoutExtension(defCoordsIn->getFileName())); name.append(SpecFile::getDeformationFieldFileExtension()); try { dff.writeFile(name); } catch (FileException& e) { QDir::setCurrent(originalDirectory); std::cout << "ERROR writing: " << e.whatQString().toAscii().constData() << std::endl; } QDir::setCurrent(originalDirectory); } /** * Create the deformation field */ void BrainModelSurfaceDeformation::createAtlasIndivDeformationFieldFile( const BrainModelSurface* atlasSphereSurface, const BrainModelSurface* sphereSurface, const BrainModelSurface* deformedSphereSurfaceIn) { DeformationFieldFile dff; atlasSphereSurface->createDeformationField(sphereSurface, deformedSphereSurfaceIn, -1, "Spherical Deformation", dff); // // Write the deformation field file // QDir::setCurrent(targetDirectory); const CoordinateFile* coords = atlasSphereSurface->getCoordinateFile(); QString name(FileUtilities::filenameWithoutExtension(coords->getFileName())); name.append(SpecFile::getDeformationFieldFileExtension()); try { dff.writeFile(name); } catch (FileException& e) { QDir::setCurrent(originalDirectory); std::cout << "ERROR writing: " << e.whatQString().toAscii().constData() << std::endl; } QDir::setCurrent(originalDirectory); } /** * Execute the deformation */ void BrainModelSurfaceDeformation::execute() throw (BrainModelAlgorithmException) { const QString originalPath(QDir::currentPath()); enum { PROGRESS_READING_DATA_FILES = 0, PROGRESS_RUNNING_DEFORMATION, PROGRESS_CREATING_DEFORMAION_MAP, PROGRESS_DEFORMING_SOURCE_TO_TARGET, PROGRESS_DEFORMING_TARGET_TO_SOURCE, PROGRESS_TOTAL_STEPS }; createProgressDialog("Deformation", PROGRESS_TOTAL_STEPS, "deformationProgressDialog"); try { originalDirectory = QDir::currentPath(); // // Update progress // updateProgressDialog("Reading Data Files.", PROGRESS_READING_DATA_FILES); // // Read the source data files in // readSourceBrainSet(); // // Read the target data files in // readTargetBrainSet(0); // // Resample border files as needed so that they match. // resampleBorderFiles(-1, -1, -1.0); // // Create the spec and deformation map file names // createOutputSpecAndDeformationFileNames(); // // Set the source and target paths // deformationMapFile->setSourceDirectory(sourceDirectory); deformationMapFile->setTargetDirectory(targetDirectory); // // Create the deformed spec file name for the source data deformed to the target // deformationMapFile->setOutputSpecFileName(sourceToTargetSpecFileName); // // Update progress // updateProgressDialog("Running the Deformation.", PROGRESS_RUNNING_DEFORMATION); // // Execute the subclass' deformation // executeDeformation(); // // Update progress // updateProgressDialog("Creating the Deformation Map", PROGRESS_CREATING_DEFORMAION_MAP); // // Add software version to deformation map file // deformationMapFile->appendSoftwareVersionToFileComment("Deformed with"); // // set the inverse deformation flag for source to target // deformationMapFile->setInverseDeformationFlag(false); // // Create the node deformation part of the deformation map // createNodeDeformation(deformedSourceSurface, targetSurface, deformationMapFile); switch (deformationMapFile->getFlatOrSphereSelection()) { case DeformationMapFile::DEFORMATION_TYPE_FLAT: break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: // // Create the deformation field // createIndivAtlasDeformationFieldFile(sourceSurface, deformedSourceSurface); break; } // // Copy and set the name of the source to target spec file // SpecFile deformedToTargetSpecFile; QDir::setCurrent(targetDirectory); try { deformedToTargetSpecFile.readFile(deformationMapFile->getTargetSpecFileName()); } catch (FileException& /*e*/) { throw BrainModelAlgorithmException( "Error reading target spec file for creating deformed version."); } try { deformedToTargetSpecFile.writeFile(sourceToTargetSpecFileName); } catch (FileException& /*e*/) { throw BrainModelAlgorithmException( "Error writing target spec file for creating deformed version."); } targetBrainSet->setSpecFileName(sourceToTargetSpecFileName); QDir::setCurrent(originalDirectory); // // Add to recent spec files // PreferencesFile* pf = brainSet->getPreferencesFile(); pf->addToRecentSpecFiles(sourceToTargetSpecFileName, true); // // Write the deformation map file // QDir::setCurrent(targetDirectory); deformationMapFile->writeFile(sourceToTargetDeformationMapFileName); targetBrainSet->setDeformationMapFileName(sourceToTargetDeformationMapFileName, true); QDir::setCurrent(originalDirectory); // // Should data files be deformed? // if (deformDataFilesFlag) { // // Update progress // updateProgressDialog("Deforming Individual Files to Atlas.", PROGRESS_DEFORMING_SOURCE_TO_TARGET); // // Deform the source data files to the target // deformDataFiles(sourceBrainSet, targetBrainSet, deformationMapFile->getSourceSpecFileName(), deformationMapFile, true, deformSourceFiducialCoordFiles, deformSourceInflatedCoordFiles, deformSourceVeryInflatedCoordFiles, deformSourceSphericalCoordFiles, deformSourceFlatCoordFiles, sourceToTargetDeformDataFileErrors); // // Update progress // updateProgressDialog("Deforming Atlas Files to Individual.", PROGRESS_DEFORMING_TARGET_TO_SOURCE); // // if also deforming target to source // if (deformationMapFile->getDeformBothWays()) { // // set the inverse deformation flag for target to source // deformationMapFile->setInverseDeformationFlag(true); // // Create the deformed spec file for the target data deformed to the source // deformationMapFile->setOutputSpecFileName(targetToSourceSpecFileName); // // Create the node deformation part of the deformation map // createNodeDeformation(targetSurface, deformedSourceSurface, deformationMapFile); switch (deformationMapFile->getFlatOrSphereSelection()) { case DeformationMapFile::DEFORMATION_TYPE_FLAT: break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: // // Create the deformation field // createAtlasIndivDeformationFieldFile(targetSurface, sourceSurface, deformedSourceSurface); break; } // // Copy and set the name of the target to source spec file // SpecFile deformedToSourceSpecFile; QDir::setCurrent(sourceDirectory); try { deformedToSourceSpecFile.readFile(deformationMapFile->getSourceSpecFileName()); } catch (FileException& /*e*/) { throw BrainModelAlgorithmException( "Error reading source spec file for creating deformed version."); } try { deformedToSourceSpecFile.writeFile(targetToSourceSpecFileName); } catch (FileException& /*e*/) { throw BrainModelAlgorithmException( "Error writing source spec file for creating deformed version."); } sourceBrainSet->setSpecFileName(targetToSourceSpecFileName); QDir::setCurrent(originalDirectory); // // Add the deformed source coordinate file to the spec file // switch(deformationMapFile->getFlatOrSphereSelection()) { case DeformationMapFile::DEFORMATION_TYPE_FLAT: deformedToSourceSpecFile.addToSpecFile( SpecFile::getFlatCoordFileTag(), deformationMapFile->getSourceDeformedFlatCoordFileName(), "", true); break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: deformedToSourceSpecFile.addToSpecFile( SpecFile::getSphericalCoordFileTag(), deformationMapFile->getSourceDeformedSphericalCoordFileName(), "", true); break; } // // Swap source and target in deformation map file since now doing target to source // deformationMapFile->swapSourceAndTargetFiles(); // // Write the deformation map file // QDir::setCurrent(sourceDirectory); deformationMapFile->writeFile(targetToSourceDeformationMapFileName); sourceBrainSet->setDeformationMapFileName(targetToSourceDeformationMapFileName, true); QDir::setCurrent(originalDirectory); // // Add to recent spec files // PreferencesFile* pf = brainSet->getPreferencesFile(); pf->addToRecentSpecFiles(targetToSourceSpecFileName, true); // // Deform the target data files to the source // deformDataFiles(targetBrainSet, sourceBrainSet, deformationMapFile->getSourceSpecFileName(), // have source since deformationMapFile, // swapSourceAndTarget was called false, deformSourceFiducialCoordFiles, deformSourceInflatedCoordFiles, deformSourceVeryInflatedCoordFiles, deformSourceSphericalCoordFiles, deformSourceFlatCoordFiles, targetToSourceDeformDataFileErrors); } } // // Delete the intermediate files // if (DebugControl::getDebugOn()) { std::cout << "Current directory: " << QDir::currentPath().toAscii().constData() << std::endl; } QDir::setCurrent(originalPath); if (deformationMapFile->getDeleteIntermediateFiles()) { for (int i = 0; i < static_cast(intermediateFiles.size()); i++) { QFile::remove(intermediateFiles[i]); } } // // Remove the progress dialog // removeProgressDialog(); } catch (BrainModelAlgorithmException& e) { // // Remove the progress dialog // removeProgressDialog(); throw e; } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceDeformDataFile.h0000664000175000017500000002434311572067322026140 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_DEFORM_DATA_FILE_H__ #define __BRAIN_MODEL_SURFACE_DEFORM_DATA_FILE_H__ #include #include #include "BrainModelAlgorithmException.h" #include "SpecFile.h" class AbstractFile; class BrainSet; class DeformationMapFile; /// This class is used to deform surface data files using a deformation map file class BrainModelSurfaceDeformDataFile { public: /// data file types that are deformed enum DATA_FILE_TYPE { DATA_FILE_AREAL_ESTIMATION, DATA_FILE_ATLAS, DATA_FILE_BORDER_FLAT, DATA_FILE_BORDER_SPHERICAL, DATA_FILE_BORDER_PROJECTION, DATA_FILE_CELL, DATA_FILE_CELL_PROJECTION, DATA_FILE_COORDINATE, DATA_FILE_COORDINATE_FLAT, DATA_FILE_FOCI, DATA_FILE_FOCI_PROJECTION, DATA_FILE_LAT_LON, DATA_FILE_METRIC, DATA_FILE_PAINT, DATA_FILE_RGB_PAINT, DATA_FILE_SHAPE, DATA_FILE_TOPOGRAPHY }; /// link color files to target from source static void linkColorFiles(const DeformationMapFile* dmf, const bool linkAreaColorFiles, const bool linkBorderColorFiles, const bool linkCellColorFiles, const bool linkFociColorFiles, QString& deformErrorsMessage) throw (BrainModelAlgorithmException); /// create a deformed spec file name static QString createDeformedSpecFileName(const QString& deformedFileNamePrefix, const QString& sourceSpecFileName, const QString& targetSpecFileName); /// create a deformed data file name static QString createDeformedFileName( const QString& deformingFromFileName, const QString& mySpecFileName, const QString& deformedFilePrefix, const int numberOfNodes, const bool deformationMapFileNameFlag); /// deform a border file static void deformBorderFile(BrainSet* sourceBrainSet, BrainSet* targetBrainSet, const DeformationMapFile* dmf, const bool useSourceTargetPathsFlag, const DATA_FILE_TYPE dataFileType, const QString& dataFileName, const QString& outputFileNameIn = "") throw (BrainModelAlgorithmException); /// deform border files static void deformBorderFiles(BrainSet* sourceBrainSet, BrainSet* targetBrainSet, const DeformationMapFile* dmf, const DATA_FILE_TYPE dataFileType, const SpecFile::Entry& dataFiles, QString& deformErrorsMessage) throw (BrainModelAlgorithmException); /// deform coordinate files static void deformCoordinateFiles(const DeformationMapFile* dmf, const SpecFile::Entry& dataFiles, QString& deformErrorsMessage) throw (BrainModelAlgorithmException); /// deform a coordinate file static void deformCoordinateFile(const DeformationMapFile* dmf, const QString& dataFileName, QString& outputFileNameInOut, const bool smoothCoordFileOneIteration, const bool useSourceTargetPathsFlag) throw (BrainModelAlgorithmException); /// deform flat coordinate files static void deformFlatCoordinateFiles(const DeformationMapFile* dmf, const SpecFile::Entry& dataFiles, QString& deformErrorsMessage) throw (BrainModelAlgorithmException); /// deform a flat coordinate file static void deformFlatCoordinateFile(const DeformationMapFile* dmf, const QString& atlasTopoFileName, const bool useSourceTargetPathsFlag, const QString& coordFileName, const QString& topoFileName, const QString& outputCoordFileNameIn = "", const QString& outputTopoFileName = "", const float maxLength = 10.0) throw (BrainModelAlgorithmException); /// deform a cell or foci file static void deformCellOrFociFile(BrainSet* sourceBrainSet, BrainSet* targetBrainSet, const DeformationMapFile* dmf, const bool useSourceTargetPathsFlag, const QString& dataFileName, const bool fociFileFlag, const QString& outputFileNameIn = "") throw (BrainModelAlgorithmException); /// deform cell or foci files static void deformCellOrFociFiles(BrainSet* sourceBrainSet, BrainSet* targetBrainSet, const DeformationMapFile* dmf, const SpecFile::Entry& dataFiles, const bool fociFileFlag, QString& deformErrorsMessage) throw (BrainModelAlgorithmException); /// deform a cell or foci projection file static void deformCellOrFociProjectionFile(BrainSet* sourceBrainSet, BrainSet* targetBrainSet, const DeformationMapFile* dmf, const bool useSourceTargetPathsFlag, const QString& dataFileName, const bool fociFileFlag, const QString& outputFileNameIn = "") throw (BrainModelAlgorithmException); /// deform cell or foci projection files static void deformCellOrFociProjectionFiles(BrainSet* sourceBrainSet, BrainSet* targetBrainSet, const DeformationMapFile* dmf, const SpecFile::Entry& dataFiles, const bool fociFileFlag, QString& deformErrorsMessage) throw (BrainModelAlgorithmException); /// deform a node attribute data file static void deformNodeAttributeFile(const DeformationMapFile* dmf, const DATA_FILE_TYPE dataFileType, const bool useSourceTargetPathsFlag, const QString& dataFileName, const QString& outputFileNameIn = "") throw (BrainModelAlgorithmException); /// deform a nifti node data file static void deformGiftiNodeDataFile(const DeformationMapFile* dmf, const DATA_FILE_TYPE dataFileType, const bool useSourceTargetPathsFlag, const QString& dataFileName, const QString& outputFileNameIn = "") throw (BrainModelAlgorithmException); /// deform node attribute data files static void deformNodeAttributeFiles(const DeformationMapFile* dmf, const DATA_FILE_TYPE dataFileType, const SpecFile::Entry& dataFiles, QString& deformErrorsMessage) throw (BrainModelAlgorithmException); /// deform node attribute data files static void deformGiftiNodeDataFiles(const DeformationMapFile* dmf, const DATA_FILE_TYPE dataFileType, const SpecFile::Entry& dataFiles, QString& deformErrorsMessage) throw (BrainModelAlgorithmException); /// Add comment information about deformation. static void addCommentAboutDeformation(const DeformationMapFile& dmf, const AbstractFile* inputFile, AbstractFile* outputFile); protected: /// Help out with linking one type of color files. static void linkColorFileHelper(const SpecFile::Entry& colorFiles, const QString& sourceSpecFilePath, SpecFile& outputSpecFile); /// get a string containing names of surfaces loaded. static QString getLoadedSurfaces(BrainSet* bs); }; #endif // __BRAIN_MODEL_SURFACE_DEFORM_DATA_FILE_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceDeformDataFile.cxx0000664000175000017500000025573611572067322026527 0ustar michaelmichael#include #include "ArealEstimationFile.h" #include "BorderFileProjector.h" #include "BorderProjectionUnprojector.h" #include "BrainSet.h" #include "BrainModelSurfaceDeformDataFile.h" #include "BrainModelSurfacePointProjector.h" #include "CellFile.h" #include "CellFileProjector.h" #include "CellProjectionFile.h" #include "CellProjectionUnprojector.h" #include "CoordinateFile.h" #include "DateAndTime.h" #include "DeformationMapFile.h" #include "FociFile.h" #include "FociProjectionFile.h" #include "LatLonFile.h" #include "FileUtilities.h" #include "MetricFile.h" #include "PaintFile.h" #include "ProbabilisticAtlasFile.h" #include "RgbPaintFile.h" #include "StringUtilities.h" #include "SurfaceShapeFile.h" #include "TopographyFile.h" #include "TopologyFile.h" /* #include "SpecFile.h" */ /** * create a deformed spec file name */ QString BrainModelSurfaceDeformDataFile::createDeformedSpecFileName( const QString& deformedFileNamePrefix, const QString& srcSpecFileName, const QString& tgtSpecFileName) { QString outputName; QString srcDirectory, srcSpecies, srcCasename, srcAnatomy, srcHemisphere, srcDescription, srcDescriptionNoType, srcTheDate, srcNumNodes, srcExtension; // // Parse the source spec file name // bool srcSpecFileNameValid = false; if (srcSpecFileName.isEmpty() == false) { srcSpecFileNameValid = FileUtilities::parseCaretDataFileName(srcSpecFileName, srcDirectory, srcSpecies, srcCasename, srcAnatomy, srcHemisphere, srcDescription, srcDescriptionNoType, srcTheDate, srcNumNodes, srcExtension); } QString tgtDirectory, tgtSpecies, tgtCasename, tgtAnatomy, tgtHemisphere, tgtDescription, tgtDescriptionNoType, tgtTheDate, tgtNumNodes, tgtExtension; // // Parse the target spec file name // bool tgtSpecFileNameValid = false; if (tgtSpecFileName.isEmpty() == false) { tgtSpecFileNameValid = FileUtilities::parseCaretDataFileName(tgtSpecFileName, tgtDirectory, tgtSpecies, tgtCasename, tgtAnatomy, tgtHemisphere, tgtDescription, tgtDescriptionNoType, tgtTheDate, tgtNumNodes, tgtExtension); } // // If both files are parsed successfully // if (srcSpecFileNameValid && tgtSpecFileNameValid) { // // Assemble the spec file name // std::vector nameComponents; nameComponents.push_back(deformedFileNamePrefix); nameComponents.push_back(srcSpecies); nameComponents.push_back(srcCasename); nameComponents.push_back(srcAnatomy); nameComponents.push_back(srcHemisphere); nameComponents.push_back(srcDescription); nameComponents.push_back(tgtNumNodes); nameComponents.push_back(SpecFile::getDeformationMapFileExtension()); outputName = ""; if (tgtDirectory.isEmpty() == false) { //outputName.append(tgtDirectory); //outputName.append("/"); } for (unsigned int i = 0; i < nameComponents.size(); i++) { QString s = nameComponents[i]; if (s.isEmpty() == false) { if (s.startsWith(".") == false) { if (outputName.isEmpty() == false) { if (i == 1) { if (outputName.endsWith("_") == false) { outputName.append("."); } } else { outputName.append("."); } } } outputName.append(s); } } } else { // // just prepend destination directory and deformed file prefix // outputName = ""; //outputName = FileUtilities::dirname(tgtSpecFileName); //if (outputName.isEmpty() == false) { // outputName.append("/"); //} outputName.append(deformedFileNamePrefix); if (srcSpecFileName.isEmpty() == false) { QString specName = FileUtilities::basename(srcSpecFileName); if (specName.endsWith(SpecFile::getSpecFileExtension())) { outputName.append(specName.left(specName.length() - SpecFile::getSpecFileExtension().length())); } else { outputName.append(srcSpecFileName); } } outputName.append(SpecFile::getDeformationMapFileExtension()); } return outputName; } /** * Create the deformation map file name. */ QString BrainModelSurfaceDeformDataFile::createDeformedFileName(const QString& deformingFromFileName, const QString& mySpecFileName, const QString& deformedFilePrefix, const int numberOfNodes, const bool deformationMapFileNameFlag) { QString outputName; QString directory, species, casename, anatomy, hemisphere, description, descriptionNoType, theDate, numNodes, extension; // // Parse the deforming from file // const bool deformingFromFileNameValid = FileUtilities::parseCaretDataFileName(deformingFromFileName, directory, species, casename, anatomy, hemisphere, description, descriptionNoType, theDate, numNodes, extension); QString myDirectory, mySpecies, myCasename, myAnatomy, myHemisphere, myDescription, myDescriptionNoType, myTheDate, myNumNodes, myExtension; // // Parse the deforming to spec file // const bool mySpecFileNameValid = FileUtilities::parseCaretDataFileName(mySpecFileName, myDirectory, mySpecies, myCasename, myAnatomy, myHemisphere, myDescription, myDescriptionNoType, myTheDate, myNumNodes, myExtension); // // Sometimes the output spec file does not contain the number of nodes // if (myNumNodes.isEmpty()) { myNumNodes = QString::number(numberOfNodes); } // // If both files are parsed successfully // if (deformingFromFileNameValid && mySpecFileNameValid) { // // Deformation Map File get todays date and time // QString dateString; if (deformationMapFileNameFlag) { //dateString = QDateTime::currentDateTime().toString("yyyy_MM_dd_hh_mm"); dateString = DateAndTime::getDateAndTimeForNaming(); extension = SpecFile::getDeformationMapFileExtension(); } else { dateString = theDate; } // // Prepend the deformed file prefix to the species // QString prefixAndSpecies(deformedFilePrefix); prefixAndSpecies.append(species); // // Reassemble the file name // outputName = FileUtilities::reassembleCaretDataFileName(myDirectory, prefixAndSpecies, casename, anatomy, hemisphere, description, dateString, myNumNodes, extension); } else { // // just prepend destination directory and deformed file prefix // outputName = FileUtilities::dirname(mySpecFileName); if (outputName.isEmpty() == false) { outputName.append("/"); } outputName.append(deformedFilePrefix); outputName.append(FileUtilities::basename(deformingFromFileName)); //outputName.append(SpecFile::getDeformationMapFileExtension()); if (deformationMapFileNameFlag) { outputName.append(SpecFile::getDeformationMapFileExtension()); } } return outputName; } /** * deform node attribute data files */ void BrainModelSurfaceDeformDataFile::deformNodeAttributeFiles(const DeformationMapFile* dmf, const DATA_FILE_TYPE dataFileType, const SpecFile::Entry& dataFiles, QString& deformErrorsMessage) throw (BrainModelAlgorithmException) { for (unsigned int i = 0; i < dataFiles.files.size(); i++) { try { deformNodeAttributeFile(dmf, dataFileType, true, dataFiles.files[i].filename); } catch (BrainModelAlgorithmException& e) { deformErrorsMessage.append(e.whatQString()); deformErrorsMessage.append("\n"); } } } /** * deform node attribute data files */ void BrainModelSurfaceDeformDataFile::deformGiftiNodeDataFiles(const DeformationMapFile* dmf, const DATA_FILE_TYPE dataFileType, const SpecFile::Entry& dataFiles, QString& deformErrorsMessage) throw (BrainModelAlgorithmException) { for (unsigned int i = 0; i < dataFiles.files.size(); i++) { try { deformGiftiNodeDataFile(dmf, dataFileType, true, dataFiles.files[i].filename); } catch (BrainModelAlgorithmException& e) { deformErrorsMessage.append(e.whatQString()); deformErrorsMessage.append("\n"); } } } /** * deform border files */ void BrainModelSurfaceDeformDataFile::deformBorderFiles(BrainSet* sourceBrainSet, BrainSet* targetBrainSet, const DeformationMapFile* dmf, const DATA_FILE_TYPE dataFileType, const SpecFile::Entry& dataFiles, QString& deformErrorsMessage) throw (BrainModelAlgorithmException) { for (unsigned int i = 0; i < dataFiles.files.size(); i++) { try { deformBorderFile(sourceBrainSet, targetBrainSet, dmf, true, dataFileType, dataFiles.files[i].filename); } catch (BrainModelAlgorithmException& e) { deformErrorsMessage.append(e.whatQString()); deformErrorsMessage.append("\n"); } } } /** * Add comment information about deformation. */ void BrainModelSurfaceDeformDataFile::addCommentAboutDeformation(const DeformationMapFile& dmf, const AbstractFile* inputFile, AbstractFile* outputFile) { if ((inputFile != NULL) && (outputFile != NULL)) { outputFile->setFileTitle(inputFile->getFileTitle()); QString comment("Deformed from: "); comment.append(FileUtilities::basename(inputFile->getFileName())); comment.append("\n"); comment.append("Deformed with: "); comment.append(FileUtilities::basename(dmf.getFileName())); comment.append("\n"); comment.append(inputFile->getFileComment()); outputFile->setFileComment(comment); } } /** * Get a string containing names of surfaces loaded. */ QString BrainModelSurfaceDeformDataFile::getLoadedSurfaces(BrainSet* bs) { QString namesOut; int numModels = bs->getNumberOfBrainModels(); for (int i = 0; i < numModels; i++) { BrainModelSurface* bms = bs->getBrainModelSurface(i); if (bms != NULL) { if (namesOut.isEmpty()) { namesOut += "\nSurfaces Loaded: "; } else { namesOut += "\n"; } namesOut += bms->getCoordinateFile()->getFileName(); } } return namesOut; } /** * deform a border file */ void BrainModelSurfaceDeformDataFile::deformBorderFile(BrainSet* sourceBrainSet, BrainSet* targetBrainSet, const DeformationMapFile* dmf, const bool useSourceTargetPathsFlag, const DATA_FILE_TYPE dataFileType, const QString& dataFileName, const QString& outputFileNameIn) throw (BrainModelAlgorithmException) { AbstractFile* inputFile = NULL; // // Save current directory // const QString savedDirectory(QDir::currentPath()); // // Set to source directory // if (useSourceTargetPathsFlag) { if (dmf->getSourceDirectory().isEmpty() == false) { QDir::setCurrent(dmf->getSourceDirectory()); } else if (dmf->getSourceSpecFileName().isEmpty() == false) { QFileInfo fi(dmf->getSourceSpecFileName()); if (fi.isFile()) { QDir::setCurrent(FileUtilities::dirname(dmf->getSourceSpecFileName())); } } } // // Find the source surface's // BrainModelSurface* sourceFlatSurface = sourceBrainSet->getBrainModelSurfaceWithCoordinateFileName( dmf->getSourceFlatCoordFileName()); BrainModelSurface* sourceSphericalSurface = sourceBrainSet->getBrainModelSurfaceWithCoordinateFileName( dmf->getSourceSphericalCoordFileName()); //if (sourceSurface == NULL) { // throw BrainModelAlgorithmException("Unable to find source surface for deforming border file."); //} // // Read in the border or border projection file that is to be deformed. // BorderFile sourceBorderFile; BorderProjectionFile sourceBorderProjectionFile; BrainModelSurface* sourceBorderSurface = NULL; bool haveBorderFile = false; bool haveBorderProjectionFile = false; try { switch(dataFileType) { case DATA_FILE_AREAL_ESTIMATION: break; case DATA_FILE_ATLAS: break; case DATA_FILE_BORDER_FLAT: sourceBorderFile.readFile(dataFileName); sourceBorderSurface = sourceFlatSurface; haveBorderFile = true; inputFile = &sourceBorderFile; break; case DATA_FILE_BORDER_SPHERICAL: sourceBorderFile.readFile(dataFileName); sourceBorderSurface = sourceSphericalSurface; haveBorderFile = true; inputFile = &sourceBorderFile; break; case DATA_FILE_BORDER_PROJECTION: sourceBorderProjectionFile.readFile(dataFileName); haveBorderProjectionFile = true; inputFile = &sourceBorderProjectionFile; break; case DATA_FILE_CELL: break; case DATA_FILE_CELL_PROJECTION: break; case DATA_FILE_COORDINATE: break; case DATA_FILE_COORDINATE_FLAT: break; case DATA_FILE_FOCI: break; case DATA_FILE_FOCI_PROJECTION: break; case DATA_FILE_LAT_LON: break; case DATA_FILE_METRIC: break; case DATA_FILE_SHAPE: break; case DATA_FILE_PAINT: break; case DATA_FILE_RGB_PAINT: break; case DATA_FILE_TOPOGRAPHY: break; } } catch (FileException& e) { throw BrainModelAlgorithmException(e.whatQString()); } const QString sourceSurfaceNames = getLoadedSurfaces(sourceBrainSet); const QString targetSurfaceNames = getLoadedSurfaces(targetBrainSet); // // If the input file is a border file, make it into a border projection file // if (haveBorderFile) { if (sourceBorderSurface == NULL) { if (dataFileType == DATA_FILE_BORDER_FLAT) { QString msg("Unable to find flat surface for flat border file "); msg.append(dmf->getSourceFlatCoordFileName()); throw BrainModelAlgorithmException(msg); } else { QString msg("Unable to find spherical surface for spherical border file "); msg.append(dmf->getSourceSphericalCoordFileName()); throw BrainModelAlgorithmException(msg); } } // // Create a border file projector and project the border file // BorderFileProjector bfp(sourceBorderSurface, true); bfp.projectBorderFile(&sourceBorderFile, &sourceBorderProjectionFile, NULL); } else if (haveBorderProjectionFile == false) { throw BrainModelAlgorithmException("Unsupported file type for border file deformation."); } // // Find the deformed source surface which will exist if this was an indvidual to atlas deformation // QString unprojectSourceSurfaceName; BrainModelSurface* unprojectSourceSurface = NULL; if (dmf->getInverseDeformationFlag() == false) { switch (dmf->getFlatOrSphereSelection()) { case DeformationMapFile::DEFORMATION_TYPE_FLAT: unprojectSourceSurfaceName = dmf->getSourceDeformedFlatCoordFileName(); unprojectSourceSurface = sourceBrainSet->getBrainModelSurfaceWithCoordinateFileName (dmf->getSourceDeformedFlatCoordFileName()); break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: unprojectSourceSurfaceName = dmf->getSourceDeformedSphericalCoordFileName(); unprojectSourceSurface = sourceBrainSet->getBrainModelSurfaceWithCoordinateFileName( dmf->getSourceDeformedSphericalCoordFileName()); break; } } else { switch (dmf->getFlatOrSphereSelection()) { case DeformationMapFile::DEFORMATION_TYPE_FLAT: unprojectSourceSurfaceName = dmf->getSourceFlatCoordFileName(); unprojectSourceSurface = sourceFlatSurface; break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: unprojectSourceSurfaceName = dmf->getSourceSphericalCoordFileName(); unprojectSourceSurface = sourceSphericalSurface; break; } } if (unprojectSourceSurface == NULL) { QString msg("Missing source surface for border file deformation unprojection: "); msg.append(unprojectSourceSurfaceName); msg.append(sourceSurfaceNames); throw BrainModelAlgorithmException(msg); } // // Unproject source border projection file onto the flat or spherical source surface // sourceBorderFile.clear(); BorderProjectionUnprojector sbfu; sbfu.unprojectBorderProjections(*(unprojectSourceSurface->getCoordinateFile()), sourceBorderProjectionFile, sourceBorderFile); // // Target's border projection file // BorderProjectionFile targetBorderProjectionFile; // // if Atlas to Individual deformation // BrainModelSurface* targetProjectSurface = NULL; QString targetProjectSurfaceName; QString msg1 = ""; if (dmf->getInverseDeformationFlag()) { // // Use the deformed surface for projection // switch (dmf->getFlatOrSphereSelection()) { case DeformationMapFile::DEFORMATION_TYPE_FLAT: targetProjectSurfaceName = dmf->getSourceDeformedFlatCoordFileName(); targetProjectSurface = targetBrainSet->getBrainModelSurfaceWithCoordinateFileName (dmf->getSourceDeformedFlatCoordFileName()); break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: targetProjectSurfaceName = dmf->getSourceDeformedSphericalCoordFileName(); targetProjectSurface = targetBrainSet->getBrainModelSurfaceWithCoordinateFileName( dmf->getSourceDeformedSphericalCoordFileName()); break; } msg1 = sourceSurfaceNames; } else { // // Use the non-deformed surface for projection // switch (dmf->getFlatOrSphereSelection()) { case DeformationMapFile::DEFORMATION_TYPE_FLAT: targetProjectSurfaceName = dmf->getTargetFlatCoordFileName(); targetProjectSurface = targetBrainSet->getBrainModelSurfaceWithCoordinateFileName (dmf->getTargetFlatCoordFileName()); break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: targetProjectSurfaceName = dmf->getTargetSphericalCoordFileName(); targetProjectSurface = targetBrainSet->getBrainModelSurfaceWithCoordinateFileName( dmf->getTargetSphericalCoordFileName()); break; } msg1 = targetSurfaceNames; } if (targetProjectSurface == NULL) { QString msg("Unable to find target surface for projection of borders: "); msg.append(targetProjectSurfaceName); msg.append(msg1); throw BrainModelAlgorithmException(msg); } // // Project the border onto the target surface // BorderFileProjector bfp(targetProjectSurface, true); bfp.projectBorderFile(&sourceBorderFile, &targetBorderProjectionFile, NULL); // // Set to the target directory // if (useSourceTargetPathsFlag) { if (dmf->getTargetDirectory().isEmpty() == false) { QDir::setCurrent(dmf->getTargetDirectory()); } else if (dmf->getOutputSpecFileName().isEmpty() == false) { QFileInfo fi(dmf->getOutputSpecFileName()); if (fi.isFile()) { QDir::setCurrent(FileUtilities::dirname(dmf->getOutputSpecFileName())); } } } // // Create the deformed file name // QString outputFileName; if (outputFileNameIn.isEmpty()) { outputFileName = FileUtilities::basename( createDeformedFileName(dataFileName, dmf->getOutputSpecFileName(), dmf->getDeformedFileNamePrefix(), dmf->getNumberOfNodes(), false)); } else { outputFileName = outputFileNameIn; } // // Use the border projection file as needed // QString specFileTag; switch(dataFileType) { case DATA_FILE_AREAL_ESTIMATION: break; case DATA_FILE_ATLAS: break; case DATA_FILE_BORDER_FLAT: { // // Unproject onto the flat surface // BrainModelSurface* bms = targetBrainSet->getBrainModelSurfaceWithCoordinateFileName( dmf->getTargetFlatCoordFileName()); if (bms == NULL) { QString msg("Unable to find target flat coord file for border unprojection: "); msg.append(dmf->getTargetFlatCoordFileName()); msg.append(targetSurfaceNames); throw BrainModelAlgorithmException(msg); } BorderProjectionUnprojector tbfu; BorderFile targetFlatBorderFile; sbfu.unprojectBorderProjections(*(bms->getCoordinateFile()), targetBorderProjectionFile, targetFlatBorderFile); addCommentAboutDeformation(*dmf, inputFile, &targetFlatBorderFile); targetFlatBorderFile.writeFile(outputFileName); specFileTag = SpecFile::getFlatBorderFileTag(); } break; case DATA_FILE_BORDER_SPHERICAL: { // // Unproject onto the spherical surface // BrainModelSurface* bms = targetBrainSet->getBrainModelSurfaceWithCoordinateFileName( dmf->getTargetSphericalCoordFileName()); if (bms == NULL) { QString msg("Unable to find target spherical coord file for border unprojection: "); msg.append(dmf->getTargetSphericalCoordFileName()); msg.append(targetSurfaceNames); throw BrainModelAlgorithmException(msg); } BorderProjectionUnprojector tbfu; BorderFile targetSphericalBorderFile; sbfu.unprojectBorderProjections(*(bms->getCoordinateFile()), targetBorderProjectionFile, targetSphericalBorderFile); addCommentAboutDeformation(*dmf, inputFile, &targetSphericalBorderFile); targetSphericalBorderFile.writeFile(outputFileName); specFileTag = SpecFile::getSphericalBorderFileTag(); } break; case DATA_FILE_BORDER_PROJECTION: // // Use the projection file as it is // addCommentAboutDeformation(*dmf, inputFile, &targetBorderProjectionFile); targetBorderProjectionFile.writeFile(outputFileName); specFileTag = SpecFile::getBorderProjectionFileTag(); break; case DATA_FILE_CELL: break; case DATA_FILE_CELL_PROJECTION: break; case DATA_FILE_COORDINATE: break; case DATA_FILE_COORDINATE_FLAT: break; case DATA_FILE_FOCI: break; case DATA_FILE_FOCI_PROJECTION: break; case DATA_FILE_LAT_LON: break; case DATA_FILE_METRIC: break; case DATA_FILE_SHAPE: break; case DATA_FILE_PAINT: break; case DATA_FILE_RGB_PAINT: break; case DATA_FILE_TOPOGRAPHY: break; } if (useSourceTargetPathsFlag) { if (specFileTag.isEmpty() == false) { // // Update the target spec file // QFileInfo specFileInfo(dmf->getOutputSpecFileName()); if (specFileInfo.isFile()) { SpecFile sf; try { sf.readFile(dmf->getOutputSpecFileName()); // // file will be written if file is new to spec file // sf.addToSpecFile(specFileTag, outputFileName, "", true); } catch(FileException& e) { QDir::setCurrent(savedDirectory); QString msg("File successfully deformed. However, unable to update spec file:\n"); msg.append(dmf->getOutputSpecFileName()); throw BrainModelAlgorithmException(msg); } } } } // // Reset to the original directory // QDir::setCurrent(savedDirectory); } /** * deform a node attribute data file */ void BrainModelSurfaceDeformDataFile::deformNodeAttributeFile(const DeformationMapFile* dmf, const DATA_FILE_TYPE dataFileType, const bool useSourceTargetPathsFlag, const QString& dataFileName, const QString& outputFileNameIn) throw (BrainModelAlgorithmException) { // // Save current directory // const QString savedDirectory(QDir::currentPath()); // // Set to source directory // if (useSourceTargetPathsFlag) { if (dmf->getSourceDirectory().isEmpty() == false) { QDir::setCurrent(dmf->getSourceDirectory()); } else if (dmf->getSourceSpecFileName().isEmpty() == false) { QFileInfo fi(dmf->getSourceSpecFileName()); if (fi.isFile()) { QDir::setCurrent(FileUtilities::dirname(dmf->getSourceSpecFileName())); } } } // // Default deformation type to nearest node // NodeAttributeFile::DEFORM_TYPE dt = NodeAttributeFile::DEFORM_NEAREST_NODE; // // Read input file and create output file // NodeAttributeFile* inputFile = NULL; NodeAttributeFile* outputFile = NULL; QString specFileTag; switch(dataFileType) { case DATA_FILE_AREAL_ESTIMATION: inputFile = new ArealEstimationFile; outputFile = new ArealEstimationFile; specFileTag = SpecFile::getArealEstimationFileTag(); break; case DATA_FILE_ATLAS: break; case DATA_FILE_BORDER_FLAT: break; case DATA_FILE_BORDER_SPHERICAL: break; case DATA_FILE_BORDER_PROJECTION: break; case DATA_FILE_CELL: break; case DATA_FILE_CELL_PROJECTION: break; case DATA_FILE_COORDINATE: break; case DATA_FILE_COORDINATE_FLAT: break; case DATA_FILE_FOCI: break; case DATA_FILE_FOCI_PROJECTION: break; case DATA_FILE_LAT_LON: inputFile = new LatLonFile; outputFile = new LatLonFile; specFileTag = SpecFile::getLatLonFileTag(); break; case DATA_FILE_METRIC: break; case DATA_FILE_SHAPE: break; case DATA_FILE_PAINT: break; case DATA_FILE_RGB_PAINT: inputFile = new RgbPaintFile; outputFile = new RgbPaintFile; specFileTag = SpecFile::getRgbPaintFileTag(); break; case DATA_FILE_TOPOGRAPHY: inputFile = new TopographyFile; outputFile = new TopographyFile; specFileTag = SpecFile::getTopographyFileTag(); break; } if ((inputFile != NULL) && (outputFile != NULL)) { try { inputFile->readFile(dataFileName); } catch (FileException& e) { if (inputFile != NULL) delete inputFile; if (outputFile != NULL) delete outputFile; QDir::setCurrent(savedDirectory); throw BrainModelAlgorithmException(e.whatQString()); } } else { if (inputFile != NULL) delete inputFile; if (outputFile != NULL) delete outputFile; QDir::setCurrent(savedDirectory); QString msg("Data file type not supported for node deformation for file "); msg.append(dataFileName); throw BrainModelAlgorithmException(msg); } // // Deform the data file // try { inputFile->deform(*dmf, *outputFile, dt); } catch (FileException& e) { if (inputFile != NULL) delete inputFile; if (outputFile != NULL) delete outputFile; QDir::setCurrent(savedDirectory); throw BrainModelAlgorithmException(e.whatQString()); } // // Update file comments // addCommentAboutDeformation(*dmf, inputFile, outputFile); // // Set to the target directory // if (useSourceTargetPathsFlag) { if (dmf->getTargetDirectory().isEmpty() == false) { QDir::setCurrent(dmf->getTargetDirectory()); } else if (dmf->getOutputSpecFileName().isEmpty() == false) { QFileInfo fi(dmf->getOutputSpecFileName()); if (fi.isFile()) { QDir::setCurrent(FileUtilities::dirname(dmf->getOutputSpecFileName())); } } } // // Create the deformed file name // QString outputFileName; if (outputFileNameIn.isEmpty()) { outputFileName = FileUtilities::basename( createDeformedFileName(dataFileName, dmf->getOutputSpecFileName(), dmf->getDeformedFileNamePrefix(), dmf->getNumberOfNodes(), false)); } else { outputFileName = outputFileNameIn; } // // Write the data file // try { outputFile->writeFile(outputFileName); } catch(FileException& e) { if (inputFile != NULL) delete inputFile; if (outputFile != NULL) delete outputFile; QDir::setCurrent(savedDirectory); throw BrainModelAlgorithmException(e.whatQString()); } // // Update the target spec file // if (useSourceTargetPathsFlag) { QFileInfo specFileInfo(dmf->getOutputSpecFileName()); if (specFileInfo.isFile()) { SpecFile sf; try { sf.readFile(dmf->getOutputSpecFileName()); // // file will be written if file is new to spec file // sf.addToSpecFile(specFileTag, outputFileName, "", true); } catch(FileException& e) { if (inputFile != NULL) delete inputFile; if (outputFile != NULL) delete outputFile; QDir::setCurrent(savedDirectory); QString msg("File successfully deformed. However, unable to update spec file:\n"); msg.append(dmf->getOutputSpecFileName()); throw BrainModelAlgorithmException(msg); } } } // // Free memory // if (inputFile != NULL) delete inputFile; if (outputFile != NULL) delete outputFile; // // Reset to the original directory // QDir::setCurrent(savedDirectory); } /** * deform a nifti node data file */ void BrainModelSurfaceDeformDataFile::deformGiftiNodeDataFile(const DeformationMapFile* dmf, const DATA_FILE_TYPE dataFileType, const bool useSourceTargetPathsFlag, const QString& dataFileName, const QString& outputFileNameIn) throw (BrainModelAlgorithmException) { // // Save current directory // const QString savedDirectory(QDir::currentPath()); // // Set to source directory // if (useSourceTargetPathsFlag) { if (dmf->getSourceDirectory().isEmpty() == false) { QDir::setCurrent(dmf->getSourceDirectory()); } else if (dmf->getSourceSpecFileName().isEmpty() == false) { QFileInfo fi(dmf->getSourceSpecFileName()); if (fi.isFile()) { QDir::setCurrent(FileUtilities::dirname(dmf->getSourceSpecFileName())); } } } // // Default deformation type to nearest node // GiftiNodeDataFile::DEFORM_TYPE dt = GiftiNodeDataFile::DEFORM_NEAREST_NODE; // // Read input file and create output file // GiftiNodeDataFile* inputFile = NULL; GiftiNodeDataFile* outputFile = NULL; QString specFileTag; switch(dataFileType) { case DATA_FILE_AREAL_ESTIMATION: break; case DATA_FILE_ATLAS: inputFile = new ProbabilisticAtlasFile; outputFile = new ProbabilisticAtlasFile; specFileTag = SpecFile::getAtlasFileTag(); break; case DATA_FILE_BORDER_FLAT: break; case DATA_FILE_BORDER_SPHERICAL: break; case DATA_FILE_BORDER_PROJECTION: break; case DATA_FILE_CELL: break; case DATA_FILE_CELL_PROJECTION: break; case DATA_FILE_COORDINATE: break; case DATA_FILE_COORDINATE_FLAT: break; case DATA_FILE_FOCI: break; case DATA_FILE_FOCI_PROJECTION: break; case DATA_FILE_LAT_LON: break; case DATA_FILE_METRIC: inputFile = new MetricFile; outputFile = new MetricFile; specFileTag = SpecFile::getMetricFileTag(); switch(dmf->getMetricDeformationType()) { case DeformationMapFile::METRIC_DEFORM_NEAREST_NODE: dt = GiftiNodeDataFile::DEFORM_NEAREST_NODE; break; case DeformationMapFile::METRIC_DEFORM_AVERAGE_TILE_NODES: dt = GiftiNodeDataFile::DEFORM_TILE_AVERAGE; break; } break; case DATA_FILE_SHAPE: inputFile = new SurfaceShapeFile; outputFile = new SurfaceShapeFile; specFileTag = SpecFile::getSurfaceShapeFileTag(); break; case DATA_FILE_PAINT: inputFile = new PaintFile; outputFile = new PaintFile; specFileTag = SpecFile::getPaintFileTag(); break; case DATA_FILE_RGB_PAINT: break; case DATA_FILE_TOPOGRAPHY: break; } if ((inputFile != NULL) && (outputFile != NULL)) { try { inputFile->readFile(dataFileName); } catch (FileException& e) { if (inputFile != NULL) delete inputFile; if (outputFile != NULL) delete outputFile; QDir::setCurrent(savedDirectory); throw BrainModelAlgorithmException(e.whatQString()); } } else { if (inputFile != NULL) delete inputFile; if (outputFile != NULL) delete outputFile; QDir::setCurrent(savedDirectory); QString msg("Data file type not supported for node deformation for file "); msg.append(dataFileName); throw BrainModelAlgorithmException(msg); } // // Deform the data file // try { inputFile->deform(*dmf, *outputFile, dt); } catch (FileException& e) { if (inputFile != NULL) delete inputFile; if (outputFile != NULL) delete outputFile; QDir::setCurrent(savedDirectory); throw BrainModelAlgorithmException(e.whatQString()); } // // Update file comments // addCommentAboutDeformation(*dmf, inputFile, outputFile); // // Set to the target directory // if (useSourceTargetPathsFlag) { if (dmf->getTargetDirectory().isEmpty() == false) { QDir::setCurrent(dmf->getTargetDirectory()); } else if (dmf->getOutputSpecFileName().isEmpty() == false) { QFileInfo fi(dmf->getOutputSpecFileName()); if (fi.isFile()) { QDir::setCurrent(FileUtilities::dirname(dmf->getOutputSpecFileName())); } } } // // Create the deformed file name // QString outputFileName; if (outputFileNameIn.isEmpty()) { outputFileName = FileUtilities::basename( createDeformedFileName(dataFileName, dmf->getOutputSpecFileName(), dmf->getDeformedFileNamePrefix(), dmf->getNumberOfNodes(), false)); } else { outputFileName = outputFileNameIn; } // // Write the data file // try { outputFile->writeFile(outputFileName); } catch(FileException& e) { if (inputFile != NULL) delete inputFile; if (outputFile != NULL) delete outputFile; QDir::setCurrent(savedDirectory); throw BrainModelAlgorithmException(e.whatQString()); } // // Update the target spec file // if (useSourceTargetPathsFlag) { QFileInfo specFileInfo(dmf->getOutputSpecFileName()); if (specFileInfo.isFile()) { SpecFile sf; try { sf.readFile(dmf->getOutputSpecFileName()); // // file will be written if file is new to spec file // sf.addToSpecFile(specFileTag, outputFileName, "", true); } catch(FileException& e) { if (inputFile != NULL) delete inputFile; if (outputFile != NULL) delete outputFile; QDir::setCurrent(savedDirectory); QString msg("File successfully deformed. However, unable to update spec file:\n"); msg.append(dmf->getOutputSpecFileName()); throw BrainModelAlgorithmException(msg); } } } // // Free memory // if (inputFile != NULL) delete inputFile; if (outputFile != NULL) delete outputFile; // // Reset to the original directory // QDir::setCurrent(savedDirectory); } /** * deform cell or foci files */ void BrainModelSurfaceDeformDataFile::deformCellOrFociFiles(BrainSet* sourceBrainSet, BrainSet* targetBrainSet, const DeformationMapFile* dmf, const SpecFile::Entry& dataFiles, const bool fociFileFlag, QString& deformErrorsMessage) throw (BrainModelAlgorithmException) { for (unsigned int i = 0; i < dataFiles.files.size(); i++) { try { deformCellOrFociFile(sourceBrainSet, targetBrainSet, dmf, true, dataFiles.files[i].filename, fociFileFlag); } catch (BrainModelAlgorithmException& e) { deformErrorsMessage.append(e.whatQString()); deformErrorsMessage.append("\n"); } } } /** * deform a cell or foci file */ void BrainModelSurfaceDeformDataFile::deformCellOrFociFile(BrainSet* sourceBrainSet, BrainSet* targetBrainSet, const DeformationMapFile* dmf, const bool useSourceTargetPathsFlag, const QString& dataFileName, const bool fociFileFlag, const QString& outputFileNameIn) throw (BrainModelAlgorithmException) { // // Save current directory // const QString savedDirectory(QDir::currentPath()); // // Set to source directory // if (useSourceTargetPathsFlag) { if (dmf->getSourceDirectory().isEmpty() == false) { QDir::setCurrent(dmf->getSourceDirectory()); } else if (dmf->getSourceSpecFileName().isEmpty() == false) { QFileInfo fi(dmf->getSourceSpecFileName()); if (fi.isFile()) { QDir::setCurrent(FileUtilities::dirname(dmf->getSourceSpecFileName())); } } } // // Find the source surface's // BrainModelSurface* sourceFiducialSurface = sourceBrainSet->getBrainModelSurfaceWithCoordinateFileName( dmf->getSourceFiducialCoordFileName()); if (sourceFiducialSurface == NULL) { QDir::setCurrent(savedDirectory); throw BrainModelAlgorithmException("Unable to find source fiducial surface for cell deformation."); } BrainModelSurface* sourceFlatSurface = sourceBrainSet->getBrainModelSurfaceWithCoordinateFileName( dmf->getSourceFlatCoordFileName()); BrainModelSurface* sourceSphericalSurface = sourceBrainSet->getBrainModelSurfaceWithCoordinateFileName( dmf->getSourceSphericalCoordFileName()); // // Read in the cell file // CellFile* sourceCellFile = NULL; if (fociFileFlag) { sourceCellFile = new FociFile; } else { sourceCellFile = new CellFile; } try { sourceCellFile->readFile(dataFileName); } catch (FileException& e) { throw BrainModelAlgorithmException(e); } // // Project the cell file using the fiducial surface // CellProjectionFile sourceCellsProjected; sourceCellsProjected.appendFiducialCellFile(*sourceCellFile); CellFileProjector cfp(sourceFiducialSurface); cfp.projectFile(&sourceCellsProjected, 0, CellFileProjector::PROJECTION_TYPE_ALL, 0.0, true, NULL); // // Find the deformed source surface which will exist if this was an indvidual to atlas deformation // BrainModelSurface* unprojectSourceSurface = NULL; if (dmf->getInverseDeformationFlag() == false) { switch (dmf->getFlatOrSphereSelection()) { case DeformationMapFile::DEFORMATION_TYPE_FLAT: unprojectSourceSurface = sourceBrainSet->getBrainModelSurfaceWithCoordinateFileName (dmf->getSourceDeformedFlatCoordFileName()); break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: unprojectSourceSurface = sourceBrainSet->getBrainModelSurfaceWithCoordinateFileName( dmf->getSourceDeformedSphericalCoordFileName()); break; } } else { switch (dmf->getFlatOrSphereSelection()) { case DeformationMapFile::DEFORMATION_TYPE_FLAT: unprojectSourceSurface = sourceFlatSurface; break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: unprojectSourceSurface = sourceSphericalSurface; break; } } if (unprojectSourceSurface == NULL) { throw BrainModelAlgorithmException("Missing source surface for cell file deformation unprojection."); } // // Unproject source cell projection file onto the flat or spherical source surface // sourceCellFile->clear(); CellProjectionUnprojector scpu; scpu.unprojectCellProjections(sourceCellsProjected, unprojectSourceSurface, *sourceCellFile, 0); // // Target's cell projection file // CellProjectionFile targetCellProjectionFile; // // if Atlas to Individual deformation // BrainModelSurface* targetProjectSurface = NULL; if (dmf->getInverseDeformationFlag()) { // // Use the deformed surface for projection // switch (dmf->getFlatOrSphereSelection()) { case DeformationMapFile::DEFORMATION_TYPE_FLAT: targetProjectSurface = targetBrainSet->getBrainModelSurfaceWithCoordinateFileName (dmf->getSourceDeformedFlatCoordFileName()); break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: targetProjectSurface = targetBrainSet->getBrainModelSurfaceWithCoordinateFileName( dmf->getSourceDeformedSphericalCoordFileName()); break; } } else { // // Use the non-deformed surface for projection // switch (dmf->getFlatOrSphereSelection()) { case DeformationMapFile::DEFORMATION_TYPE_FLAT: targetProjectSurface = targetBrainSet->getBrainModelSurfaceWithCoordinateFileName (dmf->getTargetFlatCoordFileName()); break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: targetProjectSurface = targetBrainSet->getBrainModelSurfaceWithCoordinateFileName( dmf->getTargetSphericalCoordFileName()); break; } } if (targetProjectSurface == NULL) { throw BrainModelAlgorithmException("Unable to find target's deformed surface for cell deformation."); } // // Get the target fiducial surface // const BrainModelSurface* targetFiducialSurface = targetBrainSet->getBrainModelSurfaceWithCoordinateFileName( dmf->getTargetFiducialCoordFileName()); if (targetFiducialSurface == NULL) { throw BrainModelAlgorithmException("Unable to find target fiducial coord file for cell deformation."); } const CoordinateFile* targetFiducialCoordinateFile = targetFiducialSurface->getCoordinateFile(); // // Project the cells onto the target surface CANNOT USE CELL PROJECTOR // BrainModelSurfacePointProjector tdspp(targetProjectSurface, BrainModelSurfacePointProjector::SURFACE_TYPE_HINT_OTHER, false); for (int i = 0; i < sourceCellFile->getNumberOfCells(); i++) { CellData* cd = sourceCellFile->getCell(i); float xyz[3]; cd->getXYZ(xyz); int nearestNode, tileNodes[3]; float tileAreas[3]; const int tile = tdspp.projectBarycentric(xyz, nearestNode, tileNodes, tileAreas); // // Unproject onto target fiducial surface // if (tile >= 0) { BrainModelSurfacePointProjector::unprojectPoint(tileNodes, tileAreas, targetFiducialCoordinateFile, xyz); } else if (nearestNode >= 0) { targetFiducialCoordinateFile->getCoordinate(nearestNode, xyz); } else { xyz[0] = 0.0; xyz[1] = 0.0; xyz[2] = 0.0; } cd->setXYZ(xyz); } // // Set to the target directory // if (useSourceTargetPathsFlag) { if (dmf->getTargetDirectory().isEmpty() == false) { QDir::setCurrent(dmf->getTargetDirectory()); } else if (dmf->getOutputSpecFileName().isEmpty() == false) { QFileInfo fi(dmf->getOutputSpecFileName()); if (fi.isFile()) { QDir::setCurrent(FileUtilities::dirname(dmf->getOutputSpecFileName())); } } } // // Create the deformed file name // QString outputFileName; if (outputFileNameIn.isEmpty()) { outputFileName = FileUtilities::basename( createDeformedFileName(dataFileName, dmf->getOutputSpecFileName(), dmf->getDeformedFileNamePrefix(), dmf->getNumberOfNodes(), false)); } else { outputFileName = outputFileNameIn; } // // Write the target cell files // // Note: sourceCellFile is used for both source and output addCommentAboutDeformation(*dmf, sourceCellFile, sourceCellFile); try { sourceCellFile->writeFile(outputFileName); } catch (FileException& e) { throw BrainModelAlgorithmException(e.whatQString()); } // // Update the target spec file // if (useSourceTargetPathsFlag) { QFileInfo specFileInfo(dmf->getOutputSpecFileName()); if (specFileInfo.isFile()) { SpecFile sf; try { sf.readFile(dmf->getOutputSpecFileName()); // // file will be written if file is new to spec file // if (fociFileFlag) { sf.addToSpecFile(SpecFile::getFociFileTag(), outputFileName, "", true); } else { sf.addToSpecFile(SpecFile::getCellFileTag(), outputFileName, "", true); } } catch(FileException& e) { QDir::setCurrent(savedDirectory); QString msg("File was successfully deformed. However, unable to " "update Spec File: \n"); msg.append(dmf->getOutputSpecFileName()); throw BrainModelAlgorithmException(msg); } } } // // Reset to the original directory // QDir::setCurrent(savedDirectory); delete sourceCellFile; } /** * deform cell or foci files */ void BrainModelSurfaceDeformDataFile::deformCellOrFociProjectionFiles(BrainSet* sourceBrainSet, BrainSet* targetBrainSet, const DeformationMapFile* dmf, const SpecFile::Entry& dataFiles, const bool fociFileFlag, QString& deformErrorsMessage) throw (BrainModelAlgorithmException) { for (unsigned int i = 0; i < dataFiles.files.size(); i++) { try { deformCellOrFociProjectionFile(sourceBrainSet, targetBrainSet, dmf, true, dataFiles.files[i].filename, fociFileFlag); } catch (BrainModelAlgorithmException& e) { deformErrorsMessage.append(e.whatQString()); deformErrorsMessage.append("\n"); } } } /** * deform a cell or foci projection file */ void BrainModelSurfaceDeformDataFile::deformCellOrFociProjectionFile(BrainSet* sourceBrainSet, BrainSet* targetBrainSet, const DeformationMapFile* dmf, const bool useSourceTargetPathsFlag, const QString& dataFileName, const bool fociFileFlag, const QString& outputFileNameIn) throw (BrainModelAlgorithmException) { // // Save current directory // const QString savedDirectory(QDir::currentPath()); // // Set to source directory // if (useSourceTargetPathsFlag) { if (dmf->getSourceDirectory().isEmpty() == false) { QDir::setCurrent(dmf->getSourceDirectory()); } else if (dmf->getSourceSpecFileName().isEmpty() == false) { QFileInfo fi(dmf->getSourceSpecFileName()); if (fi.isFile()) { QDir::setCurrent(FileUtilities::dirname(dmf->getSourceSpecFileName())); } } } // // Find the source surface's // BrainModelSurface* sourceFiducialSurface = sourceBrainSet->getBrainModelSurfaceWithCoordinateFileName( dmf->getSourceFiducialCoordFileName()); if (sourceFiducialSurface == NULL) { QDir::setCurrent(savedDirectory); throw BrainModelAlgorithmException("Unable to find source fiducial surface for cell deformation."); } BrainModelSurface* sourceFlatSurface = sourceBrainSet->getBrainModelSurfaceWithCoordinateFileName( dmf->getSourceFlatCoordFileName()); BrainModelSurface* sourceSphericalSurface = sourceBrainSet->getBrainModelSurfaceWithCoordinateFileName( dmf->getSourceSphericalCoordFileName()); // // Read in the cell projection file // CellProjectionFile* sourceCellProjectionFile = NULL; CellFile* sourceCellFile = NULL; if (fociFileFlag) { sourceCellFile = new FociFile; sourceCellProjectionFile = new FociProjectionFile; } else { sourceCellFile = new CellFile; sourceCellProjectionFile = new CellProjectionFile; } try { sourceCellProjectionFile->readFile(dataFileName); } catch (FileException& e) { throw BrainModelAlgorithmException(e); } // // Find the deformed source surface which will exist if this was an indvidual to atlas deformation // BrainModelSurface* unprojectSourceSurface = NULL; if (dmf->getInverseDeformationFlag() == false) { switch (dmf->getFlatOrSphereSelection()) { case DeformationMapFile::DEFORMATION_TYPE_FLAT: unprojectSourceSurface = sourceBrainSet->getBrainModelSurfaceWithCoordinateFileName (dmf->getSourceDeformedFlatCoordFileName()); break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: unprojectSourceSurface = sourceBrainSet->getBrainModelSurfaceWithCoordinateFileName( dmf->getSourceDeformedSphericalCoordFileName()); break; } } else { switch (dmf->getFlatOrSphereSelection()) { case DeformationMapFile::DEFORMATION_TYPE_FLAT: unprojectSourceSurface = sourceFlatSurface; break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: unprojectSourceSurface = sourceSphericalSurface; break; } } if (unprojectSourceSurface == NULL) { throw BrainModelAlgorithmException("Missing source surface for cell file deformation unprojection."); } // // Unproject source cell projection file onto the flat or spherical source surface // sourceCellFile->clear(); CellProjectionUnprojector scpu; scpu.unprojectCellProjections(*sourceCellProjectionFile, unprojectSourceSurface, *sourceCellFile, 0); // // Target's cell projection file // CellProjectionFile targetCellProjectionFile; // // if Atlas to Individual deformation // BrainModelSurface* targetProjectSurface = NULL; if (dmf->getInverseDeformationFlag()) { // // Use the deformed surface for projection // switch (dmf->getFlatOrSphereSelection()) { case DeformationMapFile::DEFORMATION_TYPE_FLAT: targetProjectSurface = targetBrainSet->getBrainModelSurfaceWithCoordinateFileName (dmf->getSourceDeformedFlatCoordFileName()); break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: targetProjectSurface = targetBrainSet->getBrainModelSurfaceWithCoordinateFileName( dmf->getSourceDeformedSphericalCoordFileName()); break; } } else { // // Use the non-deformed surface for projection // switch (dmf->getFlatOrSphereSelection()) { case DeformationMapFile::DEFORMATION_TYPE_FLAT: targetProjectSurface = targetBrainSet->getBrainModelSurfaceWithCoordinateFileName (dmf->getTargetFlatCoordFileName()); break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: targetProjectSurface = targetBrainSet->getBrainModelSurfaceWithCoordinateFileName( dmf->getTargetSphericalCoordFileName()); break; } } if (targetProjectSurface == NULL) { throw BrainModelAlgorithmException("Unable to find target's deformed surface for cell deformation."); } // // Get the target fiducial surface // const BrainModelSurface* targetFiducialSurface = targetBrainSet->getBrainModelSurfaceWithCoordinateFileName( dmf->getTargetFiducialCoordFileName()); if (targetFiducialSurface == NULL) { throw BrainModelAlgorithmException("Unable to find target fiducial coord file for cell deformation."); } const CoordinateFile* targetFiducialCoordinateFile = targetFiducialSurface->getCoordinateFile(); // // Project the cells onto the target surface CANNOT USE CELL PROJECTOR // BrainModelSurfacePointProjector tdspp(targetProjectSurface, BrainModelSurfacePointProjector::SURFACE_TYPE_HINT_OTHER, false); for (int i = 0; i < sourceCellFile->getNumberOfCells(); i++) { CellData* cd = sourceCellFile->getCell(i); float xyz[3]; cd->getXYZ(xyz); int nearestNode, tileNodes[3]; float tileAreas[3]; const int tile = tdspp.projectBarycentric(xyz, nearestNode, tileNodes, tileAreas); // // Unproject onto target fiducial surface // if (tile >= 0) { BrainModelSurfacePointProjector::unprojectPoint(tileNodes, tileAreas, targetFiducialCoordinateFile, xyz); } else if (nearestNode >= 0) { targetFiducialCoordinateFile->getCoordinate(nearestNode, xyz); } else { xyz[0] = 0.0; xyz[1] = 0.0; xyz[2] = 0.0; } cd->setXYZ(xyz); } // // Replace cell projections with cells // sourceCellProjectionFile->clear(); sourceCellProjectionFile->appendFiducialCellFile(*sourceCellFile); // // Project cells to target fiducial surface // CellFileProjector cellProj(targetFiducialSurface); cellProj.projectFile(sourceCellProjectionFile, 0, CellFileProjector::PROJECTION_TYPE_ALL, 0.0, false, NULL); // // Set to the target directory // if (useSourceTargetPathsFlag) { if (dmf->getTargetDirectory().isEmpty() == false) { QDir::setCurrent(dmf->getTargetDirectory()); } else if (dmf->getOutputSpecFileName().isEmpty() == false) { QFileInfo fi(dmf->getOutputSpecFileName()); if (fi.isFile()) { QDir::setCurrent(FileUtilities::dirname(dmf->getOutputSpecFileName())); } } } // // Create the deformed file name // QString outputFileName; if (outputFileNameIn.isEmpty()) { outputFileName = FileUtilities::basename( createDeformedFileName(dataFileName, dmf->getOutputSpecFileName(), dmf->getDeformedFileNamePrefix(), dmf->getNumberOfNodes(), false)); } else { outputFileName = outputFileNameIn; } // // Write the target cell files // // Note: sourceCellFile is used for both source and output addCommentAboutDeformation(*dmf, sourceCellProjectionFile, sourceCellProjectionFile); try { sourceCellProjectionFile->writeFile(outputFileName); } catch (FileException& e) { throw BrainModelAlgorithmException(e.whatQString()); } // // Update the target spec file // if (useSourceTargetPathsFlag) { QFileInfo specFileInfo(dmf->getOutputSpecFileName()); if (specFileInfo.isFile()) { SpecFile sf; try { sf.readFile(dmf->getOutputSpecFileName()); // // file will be written if file is new to spec file // if (fociFileFlag) { sf.addToSpecFile(SpecFile::getFociProjectionFileTag(), outputFileName, "", true); } else { sf.addToSpecFile(SpecFile::getCellProjectionFileTag(), outputFileName, "", true); } } catch(FileException& e) { QDir::setCurrent(savedDirectory); QString msg("File was successfully deformed. However, unable to " "update Spec File: \n"); msg.append(dmf->getOutputSpecFileName()); throw BrainModelAlgorithmException(msg); } } } // // Reset to the original directory // QDir::setCurrent(savedDirectory); delete sourceCellFile; delete sourceCellProjectionFile; } /** * Link color files to target from source. */ void BrainModelSurfaceDeformDataFile::linkColorFiles(const DeformationMapFile* dmf, const bool linkAreaColorFiles, const bool linkBorderColorFiles, const bool linkCellColorFiles, const bool linkFociColorFiles, QString& deformErrorsMessage) throw (BrainModelAlgorithmException) { // // Read in the source spec file // SpecFile sourceSpecFile; try { sourceSpecFile.readFile(dmf->getSourceSpecFileName()); } catch (FileException& e) { deformErrorsMessage.append(e.whatQString()); deformErrorsMessage.append("\n"); return; } // // Get the path of the source spec file // const QString sourceSpecFilePath(FileUtilities::dirname(dmf->getSourceSpecFileName())); // // Read in the output spec file // SpecFile outputSpecFile; try { outputSpecFile.readFile(dmf->getOutputSpecFileName()); } catch (FileException& e) { deformErrorsMessage.append(e.whatQString()); deformErrorsMessage.append("\n"); return; } // // Do area color files // if (linkAreaColorFiles) { linkColorFileHelper(sourceSpecFile.areaColorFile, sourceSpecFilePath, outputSpecFile); } // // Do border color files // if (linkBorderColorFiles) { linkColorFileHelper(sourceSpecFile.borderColorFile, sourceSpecFilePath, outputSpecFile); } // // Do cell color files // if (linkCellColorFiles) { linkColorFileHelper(sourceSpecFile.cellColorFile, sourceSpecFilePath, outputSpecFile); } // // Do foci color files // if (linkFociColorFiles) { linkColorFileHelper(sourceSpecFile.fociColorFile, sourceSpecFilePath, outputSpecFile); } } /** * Help out with linking one type of color files. */ void BrainModelSurfaceDeformDataFile::linkColorFileHelper(const SpecFile::Entry& colorFiles, const QString& sourceSpecFilePath, SpecFile& outputSpecFile) { for (unsigned int i = 0; i < colorFiles.files.size(); i++) { QString filename(colorFiles.files[i].filename); if (filename.isEmpty() == false) { // // See if file does NOT have an absolute path // if (filename[0] != '/') { // // Prepend with the sourc spec file's path // QString s(sourceSpecFilePath); if (s.isEmpty() == false) { s.append("/"); } s.append(filename); filename = s; } // // Add to output spec file which will convert to a relative // path and write the spec file too. // outputSpecFile.addToSpecFile(colorFiles.specFileTag, filename, "", true); } } } /** * deform flat coordinate files. */ void BrainModelSurfaceDeformDataFile::deformFlatCoordinateFiles(const DeformationMapFile* dmf, const SpecFile::Entry& dataFiles, QString& deformErrorsMessage) throw (BrainModelAlgorithmException) { for (int i = 0; i < static_cast(dataFiles.files.size()); i++) { try { deformFlatCoordinateFile(dmf, dmf->getTargetClosedTopoFileName(), true, dataFiles.files[i].filename, dmf->getSourceCutTopoFileName(), "" ""); } catch (BrainModelAlgorithmException& e) { deformErrorsMessage.append(e.whatQString()); deformErrorsMessage.append("\n"); } } } /** * deform a flat coordinate file. */ void BrainModelSurfaceDeformDataFile::deformFlatCoordinateFile(const DeformationMapFile* dmf, const QString& atlasTopoFileName, const bool useSourceTargetPathsFlag, const QString& coordFileNameIn, const QString& topoFileName, const QString& outputCoordFileNameIn, const QString& outputTopoFileNameIn, const float maxLength) throw (BrainModelAlgorithmException) { // // Deform the coordinate file // QString deformedCoordFileName(outputCoordFileNameIn); deformCoordinateFile(dmf, coordFileNameIn, deformedCoordFileName, false, useSourceTargetPathsFlag); // // Save current directory // const QString savedDirectory(QDir::currentPath()); // // Set to the source directory // if (useSourceTargetPathsFlag) { if (dmf->getSourceDirectory().isEmpty() == false) { QDir::setCurrent(dmf->getSourceDirectory()); } else if (dmf->getSourceSpecFileName().isEmpty() == false) { QFileInfo fi(dmf->getSourceSpecFileName()); if (fi.isFile()) { QDir::setCurrent(FileUtilities::dirname(dmf->getSourceSpecFileName())); } } } // // Create a brain set // BrainSet brainSet; // // Create a spec file consisting of coord and topo of individual // SpecFile sf; sf.setTopoAndCoordSelected(topoFileName, coordFileNameIn, brainSet.getStructure()); // // Load the data files // std::vector errorMessages; brainSet.readSpecFile(BrainSet::SPEC_FILE_READ_MODE_NORMAL, sf, "spec file", errorMessages, NULL, NULL); if (errorMessages.empty() == false) { throw BrainModelAlgorithmException(StringUtilities::combine(errorMessages, "\n")); } // // Make sure needed files present // if (brainSet.getNumberOfBrainModels() < 1) { throw BrainModelAlgorithmException("Unable to find brain model of indiv topo and coord for flat coord deformation"); } const BrainModelSurface* bms = brainSet.getBrainModelSurface(0); if (bms == NULL) { throw BrainModelAlgorithmException("Unable to find brain model surface of indiv topo and coord for flat coord deformation"); } // // Create a point projector // BrainModelSurfacePointProjector bspp(bms, BrainModelSurfacePointProjector::SURFACE_TYPE_HINT_FLAT, false); // // Set to the target directory // if (useSourceTargetPathsFlag) { if (dmf->getTargetDirectory().isEmpty() == false) { QDir::setCurrent(dmf->getTargetDirectory()); } else if (dmf->getOutputSpecFileName().isEmpty() == false) { QFileInfo fi(dmf->getOutputSpecFileName()); if (fi.isFile()) { QDir::setCurrent(FileUtilities::dirname(dmf->getOutputSpecFileName())); } } } // // Read the deformed coordinate file // CoordinateFile cf; try { cf.readFile(deformedCoordFileName); } catch (FileException&) { throw BrainModelAlgorithmException("Unable to read deformed coordinate file for flat coord deformation."); } // // Flags nodes that are to be removed from topology // const int numCoords = cf.getNumberOfCoordinates(); std::vector nodesToRemoveFromTopology(numCoords, false); // // Find any node's in deformed coord that are at the origin // for (int i = 0; i < numCoords; i++) { const float* xyz = cf.getCoordinate(i); if ((xyz[0] == 0.0) && (xyz[1] == 0.0) && (xyz[2] == 0.0)) { nodesToRemoveFromTopology[i] = true; } } // // See if nodes in deformed coordinate file project to original // const float* coords = cf.getCoordinate(0); for (int i = 0; i < numCoords; i++) { int nearestNode; int tileNodes[3]; float barycentricCoords[3]; const int tile = bspp.projectBarycentric(&coords[i*3], nearestNode, tileNodes, barycentricCoords); // // does deformed node FAIL to project to original surface ? // if (tile < 0) { nodesToRemoveFromTopology[i] = true; } } // // Get individiuals topology file information // TopologyFile* tf = bms->getTopologyFile(); TopologyFile::TOPOLOGY_TYPES topoType = tf->getTopologyType(); if ((topoType == TopologyFile::TOPOLOGY_TYPE_UNKNOWN) || (topoType == TopologyFile::TOPOLOGY_TYPE_UNSPECIFIED)) { topoType = TopologyFile::TOPOLOGY_TYPE_CUT; } const QString specFileTag(TopologyFile::getSpecFileTagFromTopologyType(topoType)); // // Read the atlas topo file // TopologyFile newTopoFile; try { newTopoFile.readFile(atlasTopoFileName); newTopoFile.setTopologyType(topoType); } catch (FileException& e) { throw BrainModelAlgorithmException("Unable to read atlas topo file for flat coord deformation."); } // // Remove unneeded nodes // //newTopoFile.deleteTilesWithMarkedNodes(nodesToRemoveFromTopology); // // Find and disconnect long edges // const int numTiles = newTopoFile.getNumberOfTiles(); for (int i = 0; i < numTiles; i++) { const int* n = newTopoFile.getTile(i); if ((cf.getDistanceBetweenCoordinates(n[0], n[1]) > maxLength) || (cf.getDistanceBetweenCoordinates(n[1], n[2]) > maxLength) || (cf.getDistanceBetweenCoordinates(n[2], n[0]) > maxLength)) { nodesToRemoveFromTopology[n[0]] = true; nodesToRemoveFromTopology[n[1]] = true; nodesToRemoveFromTopology[n[2]] = true; } } // // Remove unneeded nodes // newTopoFile.deleteTilesWithMarkedNodes(nodesToRemoveFromTopology); // // Move disconnected nodes to origin // for (int i = 0; i < numCoords; i++) { if (nodesToRemoveFromTopology[i]) { cf.setCoordinate(i, 0.0, 0.0, 0.0); } } // // Rewrite deformed coord file since nodes moved to origin // try { cf.writeFile(cf.getFileName()); } catch (FileException& e) { QString msg("Unable to rewrite deformed coord file for flat coord deformation.\n"); msg.append(e.whatQString()); throw BrainModelAlgorithmException(msg); } // // Create output topo file name (if needed) // QString outputTopoFileName(outputTopoFileNameIn); if (outputTopoFileName.isEmpty()) { outputTopoFileName = FileUtilities::filenameWithoutExtension(deformedCoordFileName); outputTopoFileName.append(SpecFile::getTopoFileExtension()); } // // Write the output topo file // try { newTopoFile.writeFile(outputTopoFileName); } catch (FileException& e) { QString msg("Unable to write output topo file for flat coord deformation\n"); msg.append(e.whatQString()); throw BrainModelAlgorithmException(msg); } // // Update the target spec file // if (useSourceTargetPathsFlag) { QFileInfo specFileInfo(dmf->getOutputSpecFileName()); if (specFileInfo.isFile()) { SpecFile sfOut; const QString outputSpecFileName(dmf->getOutputSpecFileName()); try { sfOut.readFile(outputSpecFileName); // // file will be written if file is new to spec file // sfOut.addToSpecFile(specFileTag, outputTopoFileName, "", true); } catch(FileException& e) { QDir::setCurrent(savedDirectory); QString msg("File successfully deformed. However, unable to update spec file:\n"); msg.append(outputSpecFileName); throw BrainModelAlgorithmException(msg); } } } // // // Reset to the original directory // QDir::setCurrent(savedDirectory); } /** * deform coordinate files */ void BrainModelSurfaceDeformDataFile::deformCoordinateFiles(const DeformationMapFile* dmf, const SpecFile::Entry& dataFiles, QString& deformErrorsMessage) throw (BrainModelAlgorithmException) { for (int i = 0; i < static_cast(dataFiles.files.size()); i++) { try { QString emptyString; deformCoordinateFile(dmf, dataFiles.files[i].filename, emptyString, dmf->getSmoothDeformedSurfacesFlag(), true); } catch (BrainModelAlgorithmException& e) { deformErrorsMessage.append(e.whatQString()); deformErrorsMessage.append("\n"); } } } /** * deform a coordinate file. */ void BrainModelSurfaceDeformDataFile::deformCoordinateFile(const DeformationMapFile* dmf, const QString& dataFileName, QString& outputFileNameInOut, const bool smoothCoordFileOneIteration, const bool useSourceTargetPathsFlag) throw (BrainModelAlgorithmException) { // // Save current directory // const QString savedDirectory(QDir::currentPath()); // // Set to source directory // if (useSourceTargetPathsFlag) { if (dmf->getSourceDirectory().isEmpty() == false) { QDir::setCurrent(dmf->getSourceDirectory()); } else if (dmf->getSourceSpecFileName().isEmpty() == false) { QFileInfo fi(dmf->getSourceSpecFileName()); if (fi.isFile()) { QDir::setCurrent(FileUtilities::dirname(dmf->getSourceSpecFileName())); } } } // // Read input file // CoordinateFile inputFile; try { inputFile.readFile(dataFileName); } catch (FileException& e) { throw BrainModelAlgorithmException(e.whatQString()); } // // Base spec file tag upon input file's configuration ID // const QString specFileTag = BrainModelSurface::getCoordSpecFileTagFromSurfaceType( BrainModelSurface::getSurfaceTypeFromConfigurationID( inputFile.getHeaderTag(AbstractFile::headerTagConfigurationID))); // // Get the number of nodes // const int numNodes = dmf->getNumberOfNodes(); // // Create the output file // CoordinateFile outputFile; outputFile.setNumberOfCoordinates(numNodes); // // Process each node // for (int i = 0; i < numNodes; i++) { int tileNodes[3]; float tileAreas[3]; dmf->getDeformDataForNode(i, tileNodes, tileAreas); float xyz[3] = { 0.0, 0.0, 0.0 }; if (tileNodes[0] >= 0) { // // Unproject to input coordinate file // BrainModelSurfacePointProjector::unprojectPoint(tileNodes, tileAreas, &inputFile, xyz); } outputFile.setCoordinate(i, xyz); } // // Copy some of the input file's coordinate metadata // IF TAGS ADDED ALSO ADD THEM AFTER SMOOTHING LATER IN THIS METHOD // const QString configID = inputFile.getHeaderTag(CoordinateFile::headerTagConfigurationID); outputFile.setHeaderTag(CoordinateFile::headerTagConfigurationID, configID); outputFile.setHeaderTag(CoordinateFile::headerTagCoordFrameID, inputFile.getHeaderTag(CoordinateFile::headerTagCoordFrameID)); outputFile.setHeaderTag(CoordinateFile::headerTagOrientation, inputFile.getHeaderTag(CoordinateFile::headerTagOrientation)); outputFile.setHeaderTag(CoordinateFile::headerTagStructure, inputFile.getHeaderTag(CoordinateFile::headerTagStructure)); // // Update file comments // addCommentAboutDeformation(*dmf, &inputFile, &outputFile); // // Set to the target directory // if (useSourceTargetPathsFlag) { if (dmf->getTargetDirectory().isEmpty() == false) { QDir::setCurrent(dmf->getTargetDirectory()); } else if (dmf->getOutputSpecFileName().isEmpty() == false) { QFileInfo fi(dmf->getOutputSpecFileName()); if (fi.isFile()) { QDir::setCurrent(FileUtilities::dirname(dmf->getOutputSpecFileName())); } } } // // Create the deformed file name // if (outputFileNameInOut.isEmpty()) { outputFileNameInOut = FileUtilities::basename( createDeformedFileName(dataFileName, dmf->getOutputSpecFileName(), dmf->getDeformedFileNamePrefix(), dmf->getNumberOfNodes(), false)); } // // Write the data file // try { outputFile.writeFile(outputFileNameInOut); } catch(FileException& e) { QDir::setCurrent(savedDirectory); throw BrainModelAlgorithmException(e.whatQString()); } // // If the coord file should be smoothed // if (smoothCoordFileOneIteration) { QString topoFileName(dmf->getTargetClosedTopoFileName()); if (FileUtilities::isAbsolutePath(topoFileName) == false) { topoFileName = dmf->getTargetDirectory(); if (topoFileName.isEmpty() == false) { topoFileName.append("/"); } topoFileName.append(dmf->getTargetClosedTopoFileName()); } BrainSet bs(topoFileName, outputFileNameInOut); if (bs.getNumberOfBrainModels() > 0) { BrainModelSurface* bms = bs.getBrainModelSurface(0); if (bms != NULL) { bms->arealSmoothing(1.0, 1, 0); int numNodeCrossovers = 0; int numTileCrossovers = 0; bms->crossoverCheck(numTileCrossovers, numNodeCrossovers, bms->getSurfaceType()); if (numNodeCrossovers > 0) { std::cout << "WARNING: coordinate file " << outputFileNameInOut.toAscii().constData() << " has " << numNodeCrossovers << " crossovers after deformation." << std::endl; } CoordinateFile* cf = bms->getCoordinateFile(); // // Copy some of the input file's coordinate metadata // cf->setHeaderTag(CoordinateFile::headerTagConfigurationID, configID); cf->setHeaderTag(CoordinateFile::headerTagCoordFrameID, inputFile.getHeaderTag(CoordinateFile::headerTagCoordFrameID)); cf->setHeaderTag(CoordinateFile::headerTagOrientation, inputFile.getHeaderTag(CoordinateFile::headerTagOrientation)); cf->setHeaderTag(CoordinateFile::headerTagStructure, inputFile.getHeaderTag(CoordinateFile::headerTagStructure)); try { cf->writeFile(outputFileNameInOut); } catch(FileException& e) { QDir::setCurrent(savedDirectory); QString msg("Error writing smoothed coord file.\n"); msg.append(e.whatQString()); throw BrainModelAlgorithmException(msg); } } } } // // Update the target spec file // if (useSourceTargetPathsFlag) { QFileInfo specFileInfo(dmf->getOutputSpecFileName()); if (specFileInfo.isFile()) { SpecFile sf; try { sf.readFile(dmf->getOutputSpecFileName()); // // file will be written if file is new to spec file // sf.addToSpecFile(specFileTag, outputFileNameInOut, "", true); } catch(FileException& e) { QDir::setCurrent(savedDirectory); QString msg("File successfully deformed. However, unable to update spec file:\n"); msg.append(dmf->getOutputSpecFileName()); throw BrainModelAlgorithmException(msg); } } } // // Reset to the original directory // QDir::setCurrent(savedDirectory); } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceCutter.h0000664000175000017500000000205211572067322024571 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_CUTTER_H__ #define __BRAIN_MODEL_SURFACE_CUTTER_H__ #include "BrainModelAlgorithm.h" class BrainModelSurface; class BorderFile; /// This class applies cuts to a surface class BrainModelSurfaceCutter : public BrainModelAlgorithm { public: /// mode of cutting enum CUTTING_MODE { CUTTING_MODE_NORMAL, CUTTING_MODE_NON_NEGATIVE_Z_ONLY }; /// Constructor BrainModelSurfaceCutter(BrainModelSurface* cuttingSurfaceIn, BorderFile* cutsFileIn, const CUTTING_MODE cuttingModeIn); /// Destructor ~BrainModelSurfaceCutter(); /// Execute the flattening virtual void execute() throw (BrainModelAlgorithmException); protected: /// surface to which cuts are applied BrainModelSurface* cuttingSurface; /// the cuts file BorderFile* theCuts; /// cutting mode CUTTING_MODE cuttingMode; }; #endif // __BRAIN_MODEL_SURFACE_CUTTER_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceCutter.cxx0000664000175000017500000001321611572067322025150 0ustar michaelmichael#include #include #include #include #include "vtkLine.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceCutter.h" #include "BorderFile.h" #include "DebugControl.h" #include "MathUtilities.h" #include "TopologyFile.h" /** * Constructor. */ BrainModelSurfaceCutter::BrainModelSurfaceCutter(BrainModelSurface* cuttingSurfaceIn, BorderFile* cutsFileIn, const CUTTING_MODE cuttingModeIn) : BrainModelAlgorithm(cuttingSurfaceIn->getBrainSet()) { cuttingSurface = cuttingSurfaceIn; theCuts = cutsFileIn; cuttingMode = cuttingModeIn; } /** * Destructor. */ BrainModelSurfaceCutter::~BrainModelSurfaceCutter() { } /** * Execute the flattening. */ void BrainModelSurfaceCutter::execute() throw (BrainModelAlgorithmException) { QTime timer; timer.start(); // // NOTE: We could save some time and use a topology helper. But, if the topology is messed // up and more than two tiles use an edge, not all tiles would be removed. So, just // test all tiles. // // // Get the topolgoy file // TopologyFile* topology = cuttingSurface->getTopologyFile(); // // Get the coordinate file // const CoordinateFile* coords = cuttingSurface->getCoordinateFile(); const float* coordXYZ = coords->getCoordinate(0); // // Keep track of tiles that need to be deleted. // const int numTiles = topology->getNumberOfTiles(); std::vector deleteTheTile(numTiles, false); // // Apply all of the cuts // const int numCuts = theCuts->getNumberOfBorders(); for (int cti = 0; cti < numCuts; cti++) { // // only do cuts with at least two links // const Border* cut = theCuts->getBorder(cti); const int numCutPoints = cut->getNumberOfLinks(); if (numCutPoints > 1) { // // test each segment in the cut // for (int cpi = 0; cpi < (numCutPoints - 1); cpi++) { float c1[3], c2[3]; cut->getLinkXYZ(cpi, c1); cut->getLinkXYZ(cpi + 1, c2); c1[2] = 0.0; c2[2] = 0.0; // // Test this cut segment agains all tiles // for (int tile = 0; tile < numTiles; tile++) { // // If tile has not already been marked for deletion // if (deleteTheTile[tile] == false) { // // Get the vertices of the tile // int v1, v2, v3; topology->getTile(tile, v1, v2, v3); //float p1[3], p2[3], p3[3]; //coords->getCoordinate(v1, p1); //coords->getCoordinate(v2, p2); //coords->getCoordinate(v3, p3); const float* p1 = &coordXYZ[v1*3]; const float* p2 = &coordXYZ[v2*3]; const float* p3 = &coordXYZ[v3*3]; bool doCutCheck = true; switch(cuttingMode) { case CUTTING_MODE_NORMAL: break; case CUTTING_MODE_NON_NEGATIVE_Z_ONLY: if ((p1[2] < 0.0) || (p2[2] < 0.0) || (p3[2] < 0.0)) { doCutCheck = false; } break; } if (doCutCheck) { //p1[2] = 0.0; //p2[2] = 0.0; //p3[2] = 0.0; // // Check the cut segment against each tile edge // float intersection[2]; if (MathUtilities::lineIntersection2D(c1, c2, p1, p2, intersection)) { deleteTheTile[tile] = true; } else if (MathUtilities::lineIntersection2D(c1, c2, p2, p3, intersection)) { deleteTheTile[tile] = true; } else if (MathUtilities::lineIntersection2D(c1, c2, p3, p1, intersection)) { deleteTheTile[tile] = true; } } } } } } } // // If cuts were made // if (std::find(deleteTheTile.begin(), deleteTheTile.end(), true) != deleteTheTile.end()) { // // Remove the cut tiles // if (DebugControl::getDebugOn()) { std::cout << "deleting tiles "; } int cnt = 0; std::vector tilesToDelete; for (int i = 0; i < numTiles; i++) { if (deleteTheTile[i]) { tilesToDelete.push_back(i); if (DebugControl::getDebugOn()) { std::cout << " " << i; } cnt++; } } if (DebugControl::getDebugOn()) { std::cout << std::endl; std::cout << "Deleting " << cnt << " tiles." << std::endl; } const int numTilesBeforeDelete = topology->getNumberOfTiles(); topology->deleteTiles(tilesToDelete); if (DebugControl::getDebugOn()) { std::cout << "Tiles before applying cuts: " << numTilesBeforeDelete << std::endl; std::cout << "Tiles after applying cuts: " << topology->getNumberOfTiles() << std::endl; } // // Set topolgy file type to cut // topology->setTopologyType(TopologyFile::TOPOLOGY_TYPE_CUT); } //std::cout << "Total time: " << timer.elapsed() / 1000 << " seconds." << std::endl; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceCurvature.h0000664000175000017500000001035511572067322025310 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __BRAIN_MODEL_SURFACE_CURVATURE_H__ #define __BRAIN_MODEL_SURFACE_CURVATURE_H__ #include #include #include "BrainModelAlgorithm.h" class BrainModelSurface; class SurfaceShapeFile; /// Class to generate curvature for a surface class BrainModelSurfaceCurvature : public BrainModelAlgorithm { public: enum CURVATUE_COLUMNS { CURVATURE_COLUMN_CREATE_NEW = -1, CURVATURE_COLUMN_DO_NOT_GENERATE = -2 }; /// Constructor BrainModelSurfaceCurvature(BrainSet* bs, const BrainModelSurface* surfaceIn, SurfaceShapeFile* shapeFileIn, const int meanCurvatureColumnIn, const int gaussianCurvatureColumnIn, const QString& meanCurvatureNameIn, const QString& gaussianCurvatureNameIn, const bool computePrincipalCurvatures = false); /// Destructor ~BrainModelSurfaceCurvature(); /// execute the algorithm virtual void execute() throw (BrainModelAlgorithmException); /// get the mean curvature column (0..N-1) int getMeanCurvatureColumnNumber() const { return meanCurvatureColumn; } /// get the mean curvature column (0..N-1) int getGaussianCurvatureColumnNumber() const { return gaussianCurvatureColumn; } /// get the k-max (k1, first principal curvature) column (0..N-1) int getKMaxColumnNumber() const { return kMaxColumn; } /// get the k-min (k2, second principal curvature) column (0..N-1) int getKMinColumnNumber() const { return kMinColumn; } protected: /// point (xyz) used when computing surface curvature class CurvePoint3D { public: float xyz[3]; }; /// determine the curvatures void determineCurvature(const int num, const std::vector& dc, const std::vector& dn, float& gauss, float& mean, float& kmax, float& kmin); /// project to a plane? void projectToPlane(const float projected[3], const float basis[2][3], float xyz[3]); /// project something? void projection(const float vector[3], const float normal[3], float xyz[3]); /// surface for curvature computation BrainModelSurface* surface; /// surface shape file for storage of curvature SurfaceShapeFile* shapeFile; /// column for mean curvature int meanCurvatureColumn; /// column for gaussian curvature int gaussianCurvatureColumn; /// name for mean curvature column QString meanCurvatureName; /// name for gaussian curvature column QString gaussianCurvatureName; /// k-max (k1, first principal curvature) column int kMaxColumn; /// k-min (k2, second principal curvature) column int kMinColumn; /// compute the principal curvatures bool computePrincipalCurvatures; }; #endif // __BRAIN_MODEL_SURFACE_CURVATURE_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceCurvature.cxx0000664000175000017500000002503011572067322025657 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelSurface.h" #include "BrainModelSurfaceCurvature.h" #include "BrainSet.h" #include "FileUtilities.h" #include "MathUtilities.h" #include "SurfaceShapeFile.h" #include "TopologyHelper.h" #include "vtkMath.h" /** * Constructor. */ BrainModelSurfaceCurvature::BrainModelSurfaceCurvature( BrainSet* bs, const BrainModelSurface* surfaceIn, SurfaceShapeFile* shapeFileIn, const int meanCurvatureColumnIn, const int gaussianCurvatureColumnIn, const QString& meanCurvatureNameIn, const QString& gaussianCurvatureNameIn, const bool computePrincipalCurvaturesIn) : BrainModelAlgorithm(bs) { surface = NULL; if (surfaceIn != NULL) { surface = new BrainModelSurface(*surfaceIn); } shapeFile = shapeFileIn; meanCurvatureColumn = meanCurvatureColumnIn; gaussianCurvatureColumn = gaussianCurvatureColumnIn; meanCurvatureName = meanCurvatureNameIn; gaussianCurvatureName = gaussianCurvatureNameIn; computePrincipalCurvatures = computePrincipalCurvaturesIn; kMinColumn = -1; kMaxColumn = -1; } /** * Destructor. */ BrainModelSurfaceCurvature::~BrainModelSurfaceCurvature() { if (surface != NULL) { delete surface; surface = NULL; } } /** * Execute the algorithm. */ void BrainModelSurfaceCurvature::execute() throw (BrainModelAlgorithmException) { // // Update the surface's normals // surface->computeNormals(); // // Get the topology helper for the surface // const TopologyFile* tf = surface->getTopologyFile(); const TopologyHelper* th = tf->getTopologyHelper(false, true, true); const CoordinateFile* cf = surface->getCoordinateFile(); // // Create surface shape file columns if needed // if (meanCurvatureColumn == CURVATURE_COLUMN_CREATE_NEW) { if (shapeFile->getNumberOfColumns() == 0) { shapeFile->setNumberOfNodesAndColumns(surface->getNumberOfNodes(), 1); } else { shapeFile->addColumns(1); } meanCurvatureColumn = shapeFile->getNumberOfColumns() - 1; } if (gaussianCurvatureColumn == CURVATURE_COLUMN_CREATE_NEW) { if (shapeFile->getNumberOfColumns() == 0) { shapeFile->setNumberOfNodesAndColumns(surface->getNumberOfNodes(), 1); } else { shapeFile->addColumns(1); } gaussianCurvatureColumn = shapeFile->getNumberOfColumns() - 1; } // // Set column names // if (meanCurvatureColumn >= 0) { shapeFile->setColumnName(meanCurvatureColumn, meanCurvatureName); shapeFile->setColumnColorMappingMinMax(meanCurvatureColumn, -1.5, 1.5); } if (gaussianCurvatureColumn >= 0) { shapeFile->setColumnName(gaussianCurvatureColumn, gaussianCurvatureName); shapeFile->setColumnColorMappingMinMax(gaussianCurvatureColumn, -1.5, 1.5); } // // Do principle curvatures? // if (computePrincipalCurvatures) { if (shapeFile->getNumberOfColumns() == 0) { shapeFile->setNumberOfNodesAndColumns(surface->getNumberOfNodes(), 2); } else { shapeFile->addColumns(2); } kMaxColumn = shapeFile->getNumberOfColumns() - 2; kMinColumn = shapeFile->getNumberOfColumns() - 1; shapeFile->setColumnName(kMaxColumn, "k1 (kmajor, first principal curvature)"); shapeFile->setColumnColorMappingMinMax(kMaxColumn, -1.5, 1.5); shapeFile->setColumnName(kMinColumn, "k2 (kminor, second principal curvature)"); shapeFile->setColumnColorMappingMinMax(kMinColumn, -1.5, 1.5); } // // Compute curvature for each node // const int numNodes = surface->getNumberOfNodes(); for (int i = 0; i < numNodes; i++) { float gauss = 0.0; float mean = 0.0; float kmax = 0.0; float kmin = 0.0; std::vector neighbors; th->getNodeNeighbors(i, neighbors); const int numNeighbors = static_cast(neighbors.size()); if (numNeighbors > 0) { // // Position and normal for node // const float* nodeCoord = cf->getCoordinate(i); const float* nodeNormal = surface->getNormal(i); // // Find differences between node's and its neighbors' coordinates and normals // std::vector deltaNormal(numNeighbors); std::vector deltaCoord(numNeighbors); for (int j = 0; j < numNeighbors; j++) { const int neighbor = neighbors[j]; const float* neighCoord = cf->getCoordinate(neighbor); const float* neighNormal = surface->getNormal(neighbor); for (int k = 0; k < 3; k++) { deltaNormal[j].xyz[k] = neighNormal[k] - nodeNormal[k]; deltaCoord[j].xyz[k] = neighCoord[k] - nodeCoord[k]; } } // // Compute basis functions // float basis[2][3]; float t1[3]; projection(deltaCoord[0].xyz, nodeNormal, basis[0]); MathUtilities::normalize(basis[0]); for (int k = 0; k < 3; k++) { t1[k] = -basis[0][k]; } MathUtilities::normalizedCrossProduct(t1, nodeNormal, basis[1]); MathUtilities::normalize(basis[1]); std::vector dn(numNeighbors); std::vector dc(numNeighbors); for (int j = 0; j < numNeighbors; j++) { float projected[3]; projection(deltaNormal[j].xyz, nodeNormal, projected); projectToPlane(projected, basis, dn[j].xyz); projection(deltaCoord[j].xyz, nodeNormal, projected); projectToPlane(projected, basis, dc[j].xyz); } determineCurvature(numNeighbors, dc, dn, gauss, mean, kmax, kmin); } if (meanCurvatureColumn != CURVATURE_COLUMN_DO_NOT_GENERATE) { shapeFile->setValue(i, meanCurvatureColumn, mean); } if (gaussianCurvatureColumn != CURVATURE_COLUMN_DO_NOT_GENERATE) { shapeFile->setValue(i, gaussianCurvatureColumn, gauss); } if (kMaxColumn >= 0) { shapeFile->setValue(i, kMaxColumn, kmax); } if (kMinColumn >= 0) { shapeFile->setValue(i, kMinColumn, kmin); } } // // Create comment info about surface used in distortion // QString commentInfo("Surface: "); commentInfo.append(FileUtilities::basename(surface->getFileName())); if (meanCurvatureColumn != CURVATURE_COLUMN_DO_NOT_GENERATE) { shapeFile->setColumnComment(meanCurvatureColumn, commentInfo); } if (gaussianCurvatureColumn != CURVATURE_COLUMN_DO_NOT_GENERATE) { shapeFile->setColumnComment(gaussianCurvatureColumn, commentInfo); } } /** * */ void BrainModelSurfaceCurvature::projectToPlane(const float projected[3], const float basis[2][3], float xyz[3]) { xyz[0] = MathUtilities::dotProduct(projected, basis[0]); xyz[1] = MathUtilities::dotProduct(projected, basis[1]); xyz[2] = 0.0; } /** * */ void BrainModelSurfaceCurvature::projection(const float vector[3], const float normal[3], float xyz[3]) { const float t2 = MathUtilities::dotProduct(vector, normal); for (int i = 0; i < 3; i++) { xyz[i] = vector[i] - (t2 * normal[i]); } } /** * Determine the curvatures */ void BrainModelSurfaceCurvature::determineCurvature(const int num, const std::vector& dc, const std::vector& dn, float& gauss, float& mean, float& kmax, float& kmin) { float sum1 = 0.0; float sum2 = 0.0; float sum3 = 0.0; float wx = 0.0; float wy = 0.0; float wxy = 0.0; for (int i = 0; i < num; i++) { sum1 += (dc[i].xyz[0] * dn[i].xyz[0]); sum2 += ((dc[i].xyz[0] * dn[i].xyz[1]) + (dc[i].xyz[1] * dn[i].xyz[0])); sum3 += (dc[i].xyz[1] * dn[i].xyz[1]); wx += (dc[i].xyz[0] * dc[i].xyz[0]); wy += (dc[i].xyz[1] * dc[i].xyz[1]); wxy += (dc[i].xyz[0] * dc[i].xyz[1]); } const float wx2 = wx * wx; const float wy2 = wy * wy; const float wxy2 = wxy * wxy; float a = 0.0; float b = 0.0; float c = 0.0; const float t1 = (wx + wy) * (-wxy2 + wx * wy); if (t1 > 0.0) { a = (sum3 * wxy2 - sum2 * wxy * wy + sum1 * (-wxy2 + wx * wy + wy2)) / t1; b = (-(sum3 * wx * wxy) + sum2 * wx * wy - sum1 * wxy * wy) / t1; c = (-(sum2 * wx * wxy) + sum1 * wxy2 + sum3 * (wx2 - wxy2 + wx * wy)) / t1; } const float trC = a + c; const float detC = a * c - b * b; const float temp = trC * trC - 4 * detC; float k1 = 0.0; float k2 = 0.0; if (temp > 0.0) { const float deltaPlus = std::sqrt(temp); const float deltaMinus = -deltaPlus; k1 = (trC + deltaPlus) / 2.0; k2 = (trC + deltaMinus) / 2.0; } gauss = k1 * k2; mean = (k1 + k2) / 2.0; // // For KMAX and KMIN, is the largest of the two absolute values // if (std::abs(k1) > std::abs(k2)) { kmax = k1; kmin = k2; } else { kmax = k2; kmin = k1; } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceConnectedSearchPaint.h0000664000175000017500000000235411572067322027354 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_CONNECTED_PAINT_SEARCH_H__ #define __BRAIN_MODEL_SURFACE_CONNECTED_PAINT_SEARCH_H__ #include "BrainModelSurfaceConnectedSearch.h" class PaintFile; /// Class that searches for connected nodes with a paint values class BrainModelSurfaceConnectedSearchPaint : public BrainModelSurfaceConnectedSearch { public: /// Constructor BrainModelSurfaceConnectedSearchPaint(BrainSet* bs, BrainModelSurface* bmsIn, const int startNodeIn, const PaintFile* paintFileIn, const int paintColumnIn, const int paintIndexIn, const std::vector* limitToTheseNodesIn = NULL); /// Destructor virtual ~BrainModelSurfaceConnectedSearchPaint(); protected: /// accept a node virtual bool acceptNode(const int nodeNumber); /// paint file being searched const PaintFile* paintFile; /// paint column for connection search int paintColumn; /// paint index for search int paintIndex; }; #endif // __BRAIN_MODEL_SURFACE_CONNECTED_PAINT_SEARCH_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceConnectedSearchPaint.cxx0000664000175000017500000000234111572067322027723 0ustar michaelmichael #include "BrainModelSurfaceConnectedSearchPaint.h" #include "BrainSet.h" #include "PaintFile.h" /** * Constructor */ BrainModelSurfaceConnectedSearchPaint::BrainModelSurfaceConnectedSearchPaint( BrainSet* bs, BrainModelSurface* bmsIn, const int startNodeIn, const PaintFile* paintFileIn, const int paintColumnIn, const int paintIndexIn, const std::vector* limitToTheseNodesIn) : BrainModelSurfaceConnectedSearch(bs, bmsIn, startNodeIn, limitToTheseNodesIn) , paintFile(paintFileIn) { paintColumn = paintColumnIn; paintIndex = paintIndexIn; } /** * Destructor */ BrainModelSurfaceConnectedSearchPaint::~BrainModelSurfaceConnectedSearchPaint() { } /** * See if nodes paint matches the correct index */ bool BrainModelSurfaceConnectedSearchPaint::acceptNode(const int nodeNumber) { const float indx = paintFile->getPaint(nodeNumber, paintColumn); if (paintIndex == indx) { return true; } return false; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceConnectedSearchMetric.h0000664000175000017500000000265711572067322027532 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_CONNECTED_METRIC_SEARCH_H__ #define __BRAIN_MODEL_SURFACE_CONNECTED_METRIC_SEARCH_H__ #include "BrainModelSurfaceConnectedSearch.h" class MetricFile; /// Class that searches for connected nodes within a range of metric values class BrainModelSurfaceConnectedSearchMetric : public BrainModelSurfaceConnectedSearch { public: /// Constructor BrainModelSurfaceConnectedSearchMetric(BrainSet* bs, const BrainModelSurface* bmsIn, const int startNodeIn, const MetricFile* metricFileIn, const int metricColumnIn, const float metricMinimumIn, const float metricMaximumIn, const std::vector* limitToTheseNodesIn = NULL); /// Destructor virtual ~BrainModelSurfaceConnectedSearchMetric(); protected: /// accept a node virtual bool acceptNode(const int nodeNumber); /// metric file being searched const MetricFile* metricFile; /// metric column for connection search const int metricColumn; /// minimum value for search const float metricMinimum; /// maximum value for search const float metricMaximum; }; #endif // __BRAIN_MODEL_SURFACE_CONNECTED_METRIC_SEARCH_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceConnectedSearchMetric.cxx0000664000175000017500000000263511572067322030101 0ustar michaelmichael #include "BrainModelSurfaceConnectedSearchMetric.h" #include "BrainSet.h" #include "MetricFile.h" /** * Constructor */ BrainModelSurfaceConnectedSearchMetric::BrainModelSurfaceConnectedSearchMetric( BrainSet* bs, const BrainModelSurface* bmsIn, const int startNodeIn, const MetricFile* metricFileIn, const int metricColumnIn, const float metricMinimumIn, const float metricMaximumIn, const std::vector* limitToTheseNodesIn) : BrainModelSurfaceConnectedSearch(bs, bmsIn, startNodeIn, limitToTheseNodesIn), metricFile(metricFileIn), metricColumn(metricColumnIn), metricMinimum(metricMinimumIn), metricMaximum(metricMaximumIn) { } /** * Destructor */ BrainModelSurfaceConnectedSearchMetric::~BrainModelSurfaceConnectedSearchMetric() { } /** * See if nodes metric value is within the search values */ bool BrainModelSurfaceConnectedSearchMetric::acceptNode(const int nodeNumber) { const float metric = metricFile->getValue(nodeNumber, metricColumn); if ((metric >= metricMinimum) && (metric <= metricMaximum)) { return true; } return false; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceConnectedSearch.h0000664000175000017500000000321211572067322026352 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_CONNECTED_SEARCH_H__ #define __BRAIN_MODEL_SURFACE_CONNECTED_SEARCH_H__ #include #include "BrainModelAlgorithm.h" class BrainModelSurface; /// class that searches and identifies topologically connected nodes class BrainModelSurfaceConnectedSearch : public BrainModelAlgorithm { public: /// Constructor BrainModelSurfaceConnectedSearch(BrainSet* bs, const BrainModelSurface* bmsIn, const int startNodeIn, const std::vector* limitToTheseNodesIn = NULL); /// Destructor virtual ~BrainModelSurfaceConnectedSearch(); /// execute the search virtual void execute() throw (BrainModelAlgorithmException); /// see if a node is connected to the start node bool getNodeConnected(const int nodeNumber) const; protected: /// accept a node (override this to accept/reject nodes during the connected search) virtual bool acceptNode(const int nodeNumber); /// the brain model surface for searching const BrainModelSurface* bms; /// starting node for search int startNode; /// limit the search to these nodes const std::vector* limitToTheseNodes; /// number of nodes in the surface int numNodes; /// node visited flag used during search std::vector visited; /// node connected flag queried by user after search std::vector nodeConnected; }; #endif // __BRAIN_MODEL_SURFACE_CONNECTED_SEARCH_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceConnectedSearch.cxx0000664000175000017500000000710411572067322026731 0ustar michaelmichael #include #include #include "BrainModelSurface.h" #include "BrainModelSurfaceConnectedSearch.h" #include "TopologyFile.h" #include "TopologyHelper.h" /** * Constructor. */ BrainModelSurfaceConnectedSearch::BrainModelSurfaceConnectedSearch(BrainSet* bs, const BrainModelSurface* bmsIn, const int startNodeIn, const std::vector* limitToTheseNodesIn) : BrainModelAlgorithm(bs), bms(bmsIn), startNode(startNodeIn), limitToTheseNodes(limitToTheseNodesIn), numNodes(0) { } /** * Destructor. */ BrainModelSurfaceConnectedSearch::~BrainModelSurfaceConnectedSearch() { visited.clear(); nodeConnected.clear(); } /** * execute the search. */ void BrainModelSurfaceConnectedSearch::execute() throw (BrainModelAlgorithmException) { numNodes = bms->getNumberOfNodes(); if (numNodes <= 0) { return; } visited.resize(numNodes); nodeConnected.resize(numNodes); for (int i = 0; i < numNodes; i++) { visited[i] = false; nodeConnected[i] = false; } // // See if search is limited to a subset of nodes // if (limitToTheseNodes != NULL) { // // Mark nodes that are not to be searched as already visited // const int numLimitNodes = static_cast(limitToTheseNodes->size()); for (int i = 0; i < numLimitNodes; i++) { if (i < numNodes) { if ((*limitToTheseNodes)[i] == false) { visited[i] = true; } } } } // // Use a topology helper to get node neighbor information // const TopologyFile* tf = bms->getTopologyFile(); //TopologyHelper th(tf, false, true, false); const TopologyHelper* th = tf->getTopologyHelper(false, true, false); // // Mark the starting node as connected. // nodeConnected[startNode] = true; // // Use a stack to help with connected node search. // std::stack st; st.push(startNode); while(!st.empty()) { const int nodeNumber = st.top(); st.pop(); // // Is node unvisited ? // if (visited[nodeNumber] == false) { visited[nodeNumber] = true; // // Does node meet criteria for acceptance // bool useNode = false; if (nodeNumber == startNode) { useNode = true; } else if (acceptNode(nodeNumber)) { useNode = true; } if (useNode) { nodeConnected[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]; if (visited[neighborNode] == false) { st.push(neighborNode); } } } } } } /** * accept/reject a node for continued searching. */ bool BrainModelSurfaceConnectedSearch::acceptNode(const int nodeNumber) { if (nodeNumber >= 0) { return true; } return false; } /** * Find out if a node is connected. Call after "execute()". */ bool BrainModelSurfaceConnectedSearch::getNodeConnected(const int nodeNumber) const { if (nodeNumber < numNodes) { return nodeConnected[nodeNumber]; } return false; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceClusterToBorderConverter.h0000664000175000017500000000702311572067322030300 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_CLUSTER_TO_BORDER_CONVERTER_H__ #define __BRAIN_MODEL_SURFACE_CLUSTER_TO_BORDER_CONVERTER_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelAlgorithm.h" class BrainModelSurface; class BrainModelSurfaceROINodeSelection; class TopologyFile; class TopologyHelper; /// class for creating borders around clusters of nodes class BrainModelSurfaceClusterToBorderConverter : public BrainModelAlgorithm { public: // constructor BrainModelSurfaceClusterToBorderConverter(BrainSet* bs, BrainModelSurface* bms, TopologyFile* tfIn, const QString& borderName, BrainModelSurfaceROINodeSelection *surfaceROIIn, const bool projectTheBordersFlagIn); // destructor ~BrainModelSurfaceClusterToBorderConverter(); // execute the algorithm void execute() throw (BrainModelAlgorithmException); /// get the number of borders created int getNumberOfBordersCreated() const { return numberOfBordersCreated; } protected: /// node status enum STATUS { /// node is outside of a cluster STATUS_OUTSIDE, /// node is inside the cluster STATUS_INSIDE, /// node is on the boundary of a cluster STATUS_BOUNDARY, /// node was on the boundary of a cluster STATUS_WAS_BOUNDARY }; // execute original algorithm that misses some clusters void executeOriginal() throw (BrainModelAlgorithmException); // execute new algorithm void executeNew() throw (BrainModelAlgorithmException); // get the boundary neighor count for a node int getBoundaryNeighborCount(const int nodeNumber) const; // cleanup cluster nodes such as those with one or zero neighbors void cleanupClusterNodes(); /// the surface BrainModelSurface* bms; /// the border name for new borders QString borderName; /// the topology file TopologyFile* topologyFile; /// the topology helper TopologyHelper* topologyHelper; /// node status std::vector nodeStatus; /// number of borders created int numberOfBordersCreated; /// surface region of interest node selection BrainModelSurfaceROINodeSelection* surfaceROI; /// project the borders flag bool projectTheBordersFlag; }; #endif // __BRAIN_MODEL_SURFACE_CLUSTER_TO_BORDER_CONVERTER_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceClusterToBorderConverter.cxx0000664000175000017500000006006311572067322030656 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BorderFile.h" #include "BrainModelBorderSet.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceClusterToBorderConverter.h" #include "BrainModelSurfaceROINodeSelection.h" #include "BrainSet.h" #include "BrainSetNodeAttribute.h" #include "DebugControl.h" #include "TopologyFile.h" #include "TopologyHelper.h" /** * constructor. */ BrainModelSurfaceClusterToBorderConverter::BrainModelSurfaceClusterToBorderConverter( BrainSet* bs, BrainModelSurface* bmsIn, TopologyFile* tfIn, const QString& borderNameIn, BrainModelSurfaceROINodeSelection* surfaceROIIn, const bool projectTheBordersFlagIn) : BrainModelAlgorithm(bs) { bms = bmsIn; topologyFile = tfIn; borderName = borderNameIn; numberOfBordersCreated = 0; surfaceROI = surfaceROIIn; projectTheBordersFlag = projectTheBordersFlagIn; } /** * destructor. */ BrainModelSurfaceClusterToBorderConverter::~BrainModelSurfaceClusterToBorderConverter() { } /** * execute the algorithm. */ void BrainModelSurfaceClusterToBorderConverter::execute() throw (BrainModelAlgorithmException) { //executeOriginal(); executeNew(); } /** * execute original algorithm that misses some clusters. */ void BrainModelSurfaceClusterToBorderConverter::executeOriginal() throw (BrainModelAlgorithmException) { // // Make sure nodes are selected // if (surfaceROI->getNumberOfNodesSelected() <= 0) { throw BrainModelAlgorithmException("No nodes are selected.h"); } surfaceROI->update(); // // Check inputs // if (bms == NULL) { throw BrainModelAlgorithmException("Surface is invalid (NULL)."); } // // Check surface for nodes // const int numNodes = bms->getNumberOfNodes(); if (numNodes <= 0) { throw BrainModelAlgorithmException("Surface has no nodes."); } // // Check surface for topology // if (topologyFile == NULL) { topologyFile = bms->getTopologyFile(); if (topologyFile == NULL) { throw BrainModelAlgorithmException("Surface has no topology.h"); } } const int numTriangles = topologyFile->getNumberOfTiles(); // // Index of surface const int modelIndex = bms->getBrainModelIndex(); if (modelIndex < 0) { throw BrainModelAlgorithmException("Surface has invalid brain model index."); } // // Get the topology helper with node info sorted // topologyHelper = (TopologyHelper*)topologyFile->getTopologyHelper(false, true, true); // // Keep track of each node's status // nodeStatus.resize(numNodes); std::fill(nodeStatus.begin(), nodeStatus.end(), STATUS_OUTSIDE); // // Find nodes of interest (are metric but have neighbors not metric - boundary of cluster) // for (int i = 0; i < numNodes; i++) { // // Is node potentially in a cluster // if (surfaceROI->getNodeSelected(i)) { // // Flag as inside the cluster // nodeStatus[i] = STATUS_INSIDE; // // Get neighbors // int numNeighbors = 0; const int* neighbors = topologyHelper->getNodeNeighbors(i, numNeighbors); for (int j = 0; j < numNeighbors; j++) { // // Is it on the boundary of a cluster // if (surfaceROI->getNodeSelected(neighbors[j]) == false) { nodeStatus[i] = STATUS_BOUNDARY; break; } } } } /* // // Highlight nodes // brainSet->clearNodeHighlightSymbols(); for (int i = 0; i < numNodes; i++) { if (nodeStatus[i] == STATUS_BOUNDARY) { BrainSetNodeAttribute* bna = brainSet->getNodeAttributes(i); //if (i == startingNode) { // bna->setHighlighting(BrainSetNodeAttribute::HIGHLIGHT_NODE_REMOTE); //} //else { bna->setHighlighting(BrainSetNodeAttribute::HIGHLIGHT_NODE_LOCAL); //} } } */ for (int startNode = 0; startNode < numNodes; startNode++) { // // Clean up cluster nodes with zero or one neighbor // cleanupClusterNodes(); // // Find a starting node (3 consecutive nodes that each have two boundary neighbors) // int startingNode = -1; int firstNode = -1; int secondNode = -1; for (int i = startNode; i < numNodes; i++) { startNode = i; if (nodeStatus[i] == STATUS_BOUNDARY) { // // Has only two neighbors ? // if (getBoundaryNeighborCount(i) == 2) { if (DebugControl::getDebugOn()) { std::cout << "Examining Node: " << i << std::endl; } // // Each of these two neighbors has only two neighbors // bool valid = true; int numNeighbors = 0; const int* neighbors = topologyHelper->getNodeNeighbors(i, numNeighbors); for (int j = 0; j < numNeighbors; j++) { if (nodeStatus[neighbors[j]] == STATUS_BOUNDARY) { if (getBoundaryNeighborCount(neighbors[j]) != 2) { valid = false; break; } else { if (firstNode < 0) { firstNode = neighbors[j]; } else if (secondNode < 0) { secondNode = neighbors[j]; } } } } if (valid) { startingNode = i; break; } else { firstNode = -1; // 5/29/07 secondNode = -1; // 5/29/07 } } } } // // If no nodes found find a triangle with 3 nodes that are boundary nodes // This code added 5/30/2007 // if (secondNode < 0) { for (int i = 0; i < numTriangles; i++) { const int* nodes = topologyFile->getTile(i); if ((nodeStatus[nodes[0]] == STATUS_BOUNDARY) && (nodeStatus[nodes[1]] == STATUS_BOUNDARY) && (nodeStatus[nodes[2]] == STATUS_BOUNDARY)) { startingNode = nodes[0]; firstNode = nodes[1]; secondNode = nodes[2]; break; } } if (secondNode < 0) { for (int i = 0; i < numTriangles; i++) { const int* nodes = topologyFile->getTile(i); if ((nodeStatus[nodes[0]] == STATUS_BOUNDARY) && (nodeStatus[nodes[1]] == STATUS_BOUNDARY)) { startingNode = nodes[0]; firstNode = nodes[1]; secondNode = firstNode; break; } if ((nodeStatus[nodes[1]] == STATUS_BOUNDARY) && (nodeStatus[nodes[2]] == STATUS_BOUNDARY)) { startingNode = nodes[1]; firstNode = nodes[2]; secondNode = firstNode; break; } if ((nodeStatus[nodes[0]] == STATUS_BOUNDARY) && (nodeStatus[nodes[2]] == STATUS_BOUNDARY)) { startingNode = nodes[2]; firstNode = nodes[0]; secondNode = firstNode; break; } } } } // // For searching // int node = -1; int previousNode = -1; if ((firstNode >= 0) && (secondNode >= 0)) { // // Get neighors for first node // int numNeighbors = 0; const int* neighbors = topologyHelper->getNodeNeighbors(firstNode, numNeighbors); // // Neighbors should be CCW // for (int i = 0; i < numNeighbors; i++) { // // Find the starting node // if (neighbors[i] == startingNode) { // // Get next neighbor after starting node // int next = i + 1; if (next >= numNeighbors) { next = 0; } const int nextNeighbor = neighbors[next]; if (nodeStatus[nextNeighbor] == STATUS_OUTSIDE) { previousNode = firstNode; node = startingNode; } else { previousNode = startingNode; node = firstNode; } break; } } } if (DebugControl::getDebugOn()) { std::cout << "Start Node: " << previousNode << std::endl; std::cout << "2nd Node: " << node << std::endl; } // // Want to move clockwise around the boundary, note that nodes sorted counter-clockwise // if ((previousNode >= 0) && (node >= 0)) { const int originalNode = previousNode; std::vector borderNodes; borderNodes.push_back(previousNode); while ((node != originalNode) && (node >= 0)) { borderNodes.push_back(node); // // Get neighbors for first node // int numNeighbors = 0; const int* neighbors = topologyHelper->getNodeNeighbors(node, numNeighbors); bool foundNextNode = false; for (int j = 0; j < numNeighbors; j++) { // // Found previous node that is part of border // if (neighbors[j] == previousNode) { // // Find next clockwise neighbor that is a boundary node // int prev = j - 1; for (int iters = 0; iters < numNeighbors; iters++) { if (prev < 0) { prev = numNeighbors - 1; } // // Is this neighbor a boundary node? // if (nodeStatus[neighbors[prev]] == STATUS_BOUNDARY) { // // Use it and continue // previousNode = node; node = neighbors[prev]; foundNextNode = true; break; // get out of for (int iters... loop } else { prev--; } } break; // get out of (for int j... loop } } // // Failure to find next node ? // if (foundNextNode == false) { node = -1; } } // // Were node's found // if (borderNodes.size() > 2) { // // If last node is connected to first, add first node so border closes. // const int lastNode = borderNodes[borderNodes.size() - 1]; int numNeighbors = 0; const int* neighbors = topologyHelper->getNodeNeighbors(borderNodes[0], numNeighbors); for (int nn = 0; nn < numNeighbors; nn++) { if (neighbors[nn] == lastNode) { borderNodes.push_back(borderNodes[0]); } } // // Create a border // CoordinateFile* cf = bms->getCoordinateFile(); Border border; border.setName(borderName); if (DebugControl::getDebugOn()) { std::cout << "Border Nodes: " << std::endl; } for (unsigned int m = 0; m < borderNodes.size(); m++) { nodeStatus[borderNodes[m]] = STATUS_WAS_BOUNDARY; if (DebugControl::getDebugOn()) { std::cout << " " << borderNodes[m] << std::endl; } const float* xyz = cf->getCoordinate(borderNodes[m]); border.addBorderLink(xyz); } if (DebugControl::getDebugOn()) { std::cout << std::endl; } // // Get the border set // BrainModelBorderSet* bmbs = brainSet->getBorderSet(); // // Add the border to the border set // BorderFile bf; bf.addBorder(border); bmbs->copyBordersFromBorderFile(bms, &bf); numberOfBordersCreated++; } // if (borderNodes.empty()... } } // for (int startNode = 0... if (DebugControl::getDebugOn()) { std::cout << "Borders Created: " << numberOfBordersCreated << std::endl; } } /** * execute new algorithm. */ void BrainModelSurfaceClusterToBorderConverter::executeNew() throw (BrainModelAlgorithmException) { // // Make sure nodes are selected // if (surfaceROI->anyNodesSelected() == false) { throw BrainModelAlgorithmException("No nodes are selected.h"); } surfaceROI->update(); // // Check inputs // if (bms == NULL) { throw BrainModelAlgorithmException("Surface is invalid (NULL)."); } // // Check surface for nodes // const int numNodes = bms->getNumberOfNodes(); if (numNodes <= 0) { throw BrainModelAlgorithmException("Surface has no nodes."); } // // Check surface for topology // if (topologyFile == NULL) { topologyFile = bms->getTopologyFile(); if (topologyFile == NULL) { throw BrainModelAlgorithmException("Surface has no topology.h"); } } const int numTriangles = topologyFile->getNumberOfTiles(); // // Index of surface //const int modelIndex = bms->getBrainModelIndex(); //if (modelIndex < 0) { // throw BrainModelAlgorithmException("Surface has invalid brain model index."); //} // // Get the topology helper with node info sorted // topologyHelper = (TopologyHelper*)topologyFile->getTopologyHelper(false, true, true); // // Keep track of each node's status // nodeStatus.resize(numNodes); std::fill(nodeStatus.begin(), nodeStatus.end(), STATUS_OUTSIDE); // // Find nodes of interest (are metric but have neighbors not metric - boundary of cluster) // for (int i = 0; i < numNodes; i++) { // // Is node potentially in a cluster // if (surfaceROI->getNodeSelected(i)) { // // Flag as inside the cluster // nodeStatus[i] = STATUS_INSIDE; // // Get neighbors // int numNeighbors = 0; const int* neighbors = topologyHelper->getNodeNeighbors(i, numNeighbors); for (int j = 0; j < numNeighbors; j++) { // // Is it on the boundary of a cluster // if (surfaceROI->getNodeSelected(neighbors[j]) == false) { nodeStatus[i] = STATUS_BOUNDARY; break; } } } } /* // // Highlight nodes // brainSet->clearNodeHighlightSymbols(); for (int i = 0; i < numNodes; i++) { if (nodeStatus[i] == STATUS_BOUNDARY) { BrainSetNodeAttribute* bna = brainSet->getNodeAttributes(i); //if (i == startingNode) { // bna->setHighlighting(BrainSetNodeAttribute::HIGHLIGHT_NODE_REMOTE); //} //else { bna->setHighlighting(BrainSetNodeAttribute::HIGHLIGHT_NODE_LOCAL); //} } } */ // // Get the border set and number of borders before creating new borders // BrainModelBorderSet* bmbs = brainSet->getBorderSet(); const int originalNumberOfBorders = bmbs->getNumberOfBorders(); int startingTriangleNumber = 0; bool doneSearching = false; while (doneSearching == false) { // // Clean up cluster nodes with zero or one neighbor // cleanupClusterNodes(); int previousNode = -1; int node = -1; for (int i = startingTriangleNumber; i < numTriangles; i++) { const int* nodes = topologyFile->getTile(i); if ((nodeStatus[nodes[0]] == STATUS_BOUNDARY) && (nodeStatus[nodes[1]] == STATUS_BOUNDARY)) { previousNode = nodes[0]; node = nodes[1]; startingTriangleNumber = i; break; } if ((nodeStatus[nodes[1]] == STATUS_BOUNDARY) && (nodeStatus[nodes[2]] == STATUS_BOUNDARY)) { previousNode = nodes[1]; node = nodes[2]; startingTriangleNumber = i; break; } if ((nodeStatus[nodes[0]] == STATUS_BOUNDARY) && (nodeStatus[nodes[2]] == STATUS_BOUNDARY)) { previousNode = nodes[2]; node = nodes[0]; startingTriangleNumber = i; break; } } if (DebugControl::getDebugOn()) { std::cout << "Start Node: " << previousNode << std::endl; std::cout << "2nd Node: " << node << std::endl; } // // Want to move clockwise around the boundary, note that nodes sorted counter-clockwise // doneSearching = true; if ((previousNode >= 0) && (node >= 0)) { doneSearching = false; const int originalNode = previousNode; std::vector borderNodes; borderNodes.push_back(previousNode); while ((node != originalNode) && (node >= 0)) { borderNodes.push_back(node); // // Get neighbors for first node // int numNeighbors = 0; const int* neighbors = topologyHelper->getNodeNeighbors(node, numNeighbors); bool foundNextNode = false; for (int j = 0; j < numNeighbors; j++) { // // Found previous node that is part of border // if (neighbors[j] == previousNode) { // // Find next clockwise neighbor that is a boundary node // int prev = j - 1; for (int iters = 0; iters < numNeighbors; iters++) { if (prev < 0) { prev = numNeighbors - 1; } // // Is this neighbor a boundary node? // if (nodeStatus[neighbors[prev]] == STATUS_BOUNDARY) { // // Use it and continue // previousNode = node; node = neighbors[prev]; foundNextNode = true; break; // get out of for (int iters... loop } else { prev--; } } break; // get out of (for int j... loop } } // // Failure to find next node ? // if (foundNextNode == false) { node = -1; } } // // Were node's found // if (borderNodes.size() > 2) { // // If last node is connected to first, add first node so border closes. // const int lastNode = borderNodes[borderNodes.size() - 1]; int numNeighbors = 0; const int* neighbors = topologyHelper->getNodeNeighbors(borderNodes[0], numNeighbors); for (int nn = 0; nn < numNeighbors; nn++) { if (neighbors[nn] == lastNode) { borderNodes.push_back(borderNodes[0]); } } // // Create a border // CoordinateFile* cf = bms->getCoordinateFile(); Border border; border.setName(borderName); if (DebugControl::getDebugOn()) { std::cout << "Border Nodes: " << std::endl; } for (unsigned int m = 0; m < borderNodes.size(); m++) { nodeStatus[borderNodes[m]] = STATUS_WAS_BOUNDARY; if (DebugControl::getDebugOn()) { std::cout << " " << borderNodes[m] << std::endl; } const float* xyz = cf->getCoordinate(borderNodes[m]); border.addBorderLink(xyz); } if (DebugControl::getDebugOn()) { std::cout << std::endl; } // // Add the border to the border set // BorderFile bf; bf.addBorder(border); bmbs->copyBordersFromBorderFile(bms, &bf); numberOfBordersCreated++; } // if (borderNodes.empty()... } } // while (doneSearching == false... // // Optionally project the newly created borders // if (projectTheBordersFlag) { bmbs->projectBorders(bms, false, // NOT barycentric so project to nearest node originalNumberOfBorders); // first border to project } if (DebugControl::getDebugOn()) { std::cout << "Borders Created: " << numberOfBordersCreated << std::endl; } } /** * cleanup cluster nodes such as those with one or zero neighbors. */ void BrainModelSurfaceClusterToBorderConverter::cleanupClusterNodes() { const int numNodes = bms->getNumberOfNodes(); // // Check for nodes that might be in cluster but should be ignored. // May need to check multiple times if nodes are removed. // bool checkAgain = true; while (checkAgain) { checkAgain = false; for (int i = 0; i < numNodes; i++) { if (nodeStatus[i] == STATUS_BOUNDARY) { // // Count its neighbors that are part of cluster boundary // const int validCount = getBoundaryNeighborCount(i); // // If node has 0 or 1 neighbors in cluster, do not use it // if (validCount <= 1) { nodeStatus[i] = STATUS_OUTSIDE; checkAgain = true; } } } } } /** * get the boundary neighor count for a node. */ int BrainModelSurfaceClusterToBorderConverter::getBoundaryNeighborCount(const int nodeNumber) const { int validCount = 0; int numNeighbors = 0; const int* neighbors = topologyHelper->getNodeNeighbors(nodeNumber, numNeighbors); for (int j = 0; j < numNeighbors; j++) { if (nodeStatus[neighbors[j]] == STATUS_BOUNDARY) { validCount++; } } return validCount; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceCellDensityToMetric.h0000664000175000017500000000441411572067322027215 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __BRAIN_MODEL_SURFACE_CELL_DENSITY_TO_METRIC_H__ #define __BRAIN_MODEL_SURFACE_CELL_DENSITY_TO_METRIC_H__ #include "BrainModelAlgorithm.h" class BrainModelSurface; class CellProjectionFile; class MetricFile; /// This class convert cell densities into metric columns class BrainModelSurfaceCellDensityToMetric : public BrainModelAlgorithm { public: /// Constructor BrainModelSurfaceCellDensityToMetric(BrainSet* bsIn, BrainModelSurface* flatSurfaceIn, CellProjectionFile* cellProjectionFileIn, MetricFile* metricFileIn, const float gridSpacingIn, const bool displayedCellsOnlyFlagIn); /// Constructor ~BrainModelSurfaceCellDensityToMetric(); // execute the algorithm void execute() throw (BrainModelAlgorithmException); private: /// the flat surface BrainModelSurface* flatSurface; /// the grid spacing float gridSpacing; /// the cell projection file CellProjectionFile* cellProjectionFile; /// the metric file MetricFile* metricFile; /// displayed cells only bool displayedCellsOnlyFlag; }; #endif // __BRAIN_MODEL_SURFACE_CELL_DENSITY_TO_METRIC_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceCellDensityToMetric.cxx0000664000175000017500000002104211572067322027564 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelSurface.h" #include "BrainModelSurfaceCellDensityToMetric.h" #include "BrainSet.h" #include "CellFile.h" #include "CellProjectionFile.h" #include "MetricFile.h" /** * Constructor. */ BrainModelSurfaceCellDensityToMetric::BrainModelSurfaceCellDensityToMetric( BrainSet* bsIn, BrainModelSurface* flatSurfaceIn, CellProjectionFile* cellProjectionFileIn, MetricFile* metricFileIn, const float gridSpacingIn, const bool displayedCellsOnlyFlagIn) : BrainModelAlgorithm(bsIn) { flatSurface = flatSurfaceIn; cellProjectionFile = cellProjectionFileIn; metricFile = metricFileIn; gridSpacing = gridSpacingIn; displayedCellsOnlyFlag = displayedCellsOnlyFlagIn; } /** * Constructor. */ BrainModelSurfaceCellDensityToMetric::~BrainModelSurfaceCellDensityToMetric() { } /** * execute the algorithm. */ void BrainModelSurfaceCellDensityToMetric::execute() throw (BrainModelAlgorithmException) { // // Check inputs // if (flatSurface == NULL) { throw BrainModelAlgorithmException("The flat surface is invalid."); } if (cellProjectionFile == NULL) { throw BrainModelAlgorithmException("Cell Projection File is invalid."); } if (metricFile == NULL) { throw BrainModelAlgorithmException("Metric File is invalid."); } if (gridSpacing <= 0.0) { throw BrainModelAlgorithmException("Grid spacing is invalid."); } // // Get the coordinate file for the flat surface // const CoordinateFile* coordFile = flatSurface->getCoordinateFile(); // // Get the flat cell file // CellFile cellFile; cellProjectionFile->getCellFile(flatSurface->getCoordinateFile(), flatSurface->getTopologyFile(), false, cellFile); if (cellFile.getNumberOfCells() <= 0) { throw BrainModelAlgorithmException( "No cells on flat surface. Do you need to project cells?"); } // // Get the bounds of the coordinate file // float bounds[6]; coordFile->getBounds(bounds); const float xmin = bounds[0] - 1.0; const float xmax = bounds[1] + 1.0; const float ymin = bounds[2] - 1.0; const float ymax = bounds[3] + 1.0; // // Compute the grid dimensions // const int numGridX = static_cast( ((xmax - xmin) / gridSpacing) + 1.0); const int numGridY = static_cast( ((ymax - ymin) / gridSpacing) + 1.0); const int arraySize = numGridX * numGridY; if (arraySize <= 0) { throw BrainModelAlgorithmException("Grid is two small. Is there a flat surface?"); } int* cellTotal = new int[arraySize]; int* cellDeep = new int[arraySize]; int* cellSuperficial = new int[arraySize]; for (int k = 0; k < arraySize; k++) { cellTotal[k] = 0; cellDeep[k] = 0; cellSuperficial[k] = 0; } // // Loop through the cells // const int numCells = cellFile.getNumberOfCells(); int num = 0; for (int i = 0; i < numCells; i++) { const CellData* cd = cellFile.getCell(i); bool useIt = true; if (displayedCellsOnlyFlag) { useIt = cd->getDisplayFlag(); } if (useIt) { // // Determine grid coordinate // const float* cellPos = cd->getXYZ(); const int xi = static_cast((cellPos[0] - xmin) / gridSpacing); const int yi = static_cast((cellPos[1] - ymin) / gridSpacing); if (xi >= numGridX) { std::cerr << "Invalid x grid index "<< xi << " for cell " << i << std::endl; } else if (yi >= numGridY) { std::cerr << "Invalid x grid index "<< yi << " for cell " << i << std::endl; } else { const int index = (numGridX * yi) + xi; if (index >= arraySize) { std::cerr << "Invalid index " << index << " greater than last " << arraySize << std::endl; } else { cellTotal[index]++; if (cellPos[2] < 0.0) { //if (cd->getSignedDistanceToSurface() < 0.0) { cellDeep[index]++; } else { cellSuperficial[index]++; } num++; } } } } // // Find/Add columns to metric file // int allColumn = -1; int deepColumn = -1; int superficialColumn = -1; const QString allColumnName("All Cells"); const QString deepColumnName("Deep Layers"); const QString superficialColumnName("Superficial Layers"); if (metricFile->getNumberOfColumns() == 0) { metricFile->setNumberOfNodesAndColumns(flatSurface->getNumberOfNodes(), 3); metricFile->setFileTitle("Cell Density"); allColumn = 0; deepColumn = 1; superficialColumn = 2; } else { allColumn = metricFile->getColumnWithName(allColumnName); if (allColumn < 0) { allColumn = metricFile->getNumberOfColumns(); metricFile->addColumns(1); } deepColumn = metricFile->getColumnWithName(deepColumnName); if (deepColumn < 0) { deepColumn = metricFile->getNumberOfColumns(); metricFile->addColumns(1); } superficialColumn = metricFile->getColumnWithName(superficialColumnName); if (superficialColumn < 0) { superficialColumn = metricFile->getNumberOfColumns(); metricFile->addColumns(1); } } metricFile->setColumnName(allColumn, allColumnName); metricFile->setColumnName(deepColumn, deepColumnName); metricFile->setColumnName(superficialColumn, superficialColumnName); // // Loop through nodes // const int numCoords = coordFile->getNumberOfCoordinates(); for (int j = 0; j < numCoords; j++) { // // Get grid coordinate of node // const float* coordPos = coordFile->getCoordinate(j); const int xi = static_cast((coordPos[0] - xmin) / gridSpacing); const int yi = static_cast((coordPos[1] - ymin) / gridSpacing); if (xi >= numGridX) { std::cerr << "Invalid x grid index "<< xi << " for node " << j << std::endl; } else if (yi >= numGridY) { std::cerr << "Invalid y grid index "<< yi << " for node " << j << std::endl; } else { const int index = (numGridX * yi) + xi; if (index >= arraySize) { std::cerr << "Invalid index " << index << " greater than last " << arraySize << std::endl; } else { // // Set the metrics for the node // float metric[3]; metric[0] = 0.0; //static_cast(cellTotal[index]); metric[1] = 0.0; //static_cast(cellDeep[index]); metric[2] = 0.0; //static_cast(cellSuperficial[index]); if (cellTotal[index] > 0.0) { metric[0] = log(static_cast(cellTotal[index])); } if (cellDeep[index] > 0.0) { metric[1] = log(static_cast(cellDeep[index])); } if (cellSuperficial[index] > 0.0) { metric[2] = log(static_cast(cellSuperficial[index])); } metricFile->setValue(j, allColumn, metric[0]); metricFile->setValue(j, deepColumn, metric[1]); metricFile->setValue(j, superficialColumn, metric[2]); } } } delete[] cellTotal; delete[] cellDeep; delete[] cellSuperficial; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceCellAttributeAssignment.h0000664000175000017500000000725611572067322030132 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_CELL_ATTRIBUTE_ASSIGNMENT_H__ #define __BRAIN_MODEL_SURFACE_CELL_ATTRIBUTE_ASSIGNMENT_H__ #include #include "BrainModelAlgorithm.h" class BrainModelSurface; class BrainModelSurfacePointLocator; class CellProjectionFile; class PaintFile; /// class for assigning cell attributes class BrainModelSurfaceCellAttributeAssignment : public BrainModelAlgorithm { public: /// attribute that is to be assigned enum ASSIGN_ATTRIBUTE { /// assign area attribute ASSIGN_ATTRIBUTE_AREA, /// assign geography attribute ASSIGN_ATTRIBUTE_GEOGRAPHY, /// assign region of interest attribute ASSIGN_ATTRIBUTE_REGION_OF_INTEREST }; /// assignment method enum ASSIGNMENT_METHOD { /// assign append ASSIGNMENT_METHOD_APPEND, /// assign clear ASSIGNMENT_METHOD_CLEAR, /// assign replace ASSIGNMENT_METHOD_REPLACE }; // constructor BrainModelSurfaceCellAttributeAssignment(BrainSet* brainSetIn, const BrainModelSurface* leftSurfaceIn, const BrainModelSurface* rightSurfaceIn, const BrainModelSurface* cerebellumSurfaceIn, CellProjectionFile* cellProjectionFileIn, const PaintFile* paintFileIn, const std::vector& paintColumnsSelectedIn, const float maximumDistanceFromSurfaceIn, const ASSIGN_ATTRIBUTE assignAttributeIn, const ASSIGNMENT_METHOD assignmentMethodIn, const QString attributeIDIn, const bool optionIgnoreUnknownValuesFlagIn); // destructor ~BrainModelSurfaceCellAttributeAssignment(); // execute the algorithm void execute() throw (BrainModelAlgorithmException); // get attribute names and values static void getAttributeNamesAndValues(std::vector& namesOut, std::vector& valuesOut); // get assignment names and values static void getAssignmentNamesAndValues(std::vector& namesOut, std::vector& valuesOut); protected: /// left surface const BrainModelSurface* leftSurface; /// right surface const BrainModelSurface* rightSurface; /// cerebellum surface const BrainModelSurface* cerebellumSurface; /// cell projection file CellProjectionFile* cellProjectionFile; /// paint file const PaintFile* paintFile; /// paint columns selected for assignment const std::vector& paintColumnsSelected; /// maximum distance from surface const float maximumDistanceFromSurface; /// attribute being assigned const ASSIGN_ATTRIBUTE assignAttribute; /// method of assignment const ASSIGNMENT_METHOD assignmentMethod; /// attribute id QString attributeID; /// ignore ??? values option const bool optionIgnoreUnknownValuesFlag; /// left surface point locator BrainModelSurfacePointLocator* leftPointLocator; /// right surface point locator BrainModelSurfacePointLocator* rightPointLocator; /// cerebellum surface point locator BrainModelSurfacePointLocator* cerebellumPointLocator; }; #endif // __BRAIN_MODEL_SURFACE_CELL_ATTRIBUTE_ASSIGNMENT_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceCellAttributeAssignment.cxx0000664000175000017500000003112311572067322030473 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelSurface.h" #include "BrainModelSurfaceCellAttributeAssignment.h" #include "BrainModelSurfacePointLocator.h" #include "CellProjectionFile.h" #include "MathUtilities.h" #include "PaintFile.h" /** * constructor. */ BrainModelSurfaceCellAttributeAssignment::BrainModelSurfaceCellAttributeAssignment( BrainSet* brainSetIn, const BrainModelSurface* leftSurfaceIn, const BrainModelSurface* rightSurfaceIn, const BrainModelSurface* cerebellumSurfaceIn, CellProjectionFile* cellProjectionFileIn, const PaintFile* paintFileIn, const std::vector& paintColumnsSelectedIn, const float maximumDistanceFromSurfaceIn, const ASSIGN_ATTRIBUTE assignAttributeIn, const ASSIGNMENT_METHOD assignmentMethodIn, const QString attributeIDIn, const bool optionIgnoreUnknownValuesFlagIn) : BrainModelAlgorithm(brainSetIn), leftSurface(leftSurfaceIn), rightSurface(rightSurfaceIn), cerebellumSurface(cerebellumSurfaceIn), cellProjectionFile(cellProjectionFileIn), paintFile(paintFileIn), paintColumnsSelected(paintColumnsSelectedIn), maximumDistanceFromSurface(maximumDistanceFromSurfaceIn), assignAttribute(assignAttributeIn), assignmentMethod(assignmentMethodIn), attributeID(attributeIDIn), optionIgnoreUnknownValuesFlag(optionIgnoreUnknownValuesFlagIn) { leftPointLocator = NULL; rightPointLocator = NULL; cerebellumPointLocator = NULL; } /** * destructor. */ BrainModelSurfaceCellAttributeAssignment::~BrainModelSurfaceCellAttributeAssignment() { if (leftPointLocator != NULL) { delete leftPointLocator; leftPointLocator = NULL; } if (rightPointLocator != NULL) { delete rightPointLocator; rightPointLocator = NULL; } if (cerebellumPointLocator != NULL) { delete cerebellumPointLocator; cerebellumPointLocator = NULL; } } /** * execute the algorithm. */ void BrainModelSurfaceCellAttributeAssignment::execute() throw (BrainModelAlgorithmException) { if ((leftSurface == NULL) && (rightSurface == NULL) && (cerebellumSurface == NULL)) { throw BrainModelAlgorithmException("Attribute Assignment: All surfaces are invalid."); } if (cellProjectionFile == NULL) { throw BrainModelAlgorithmException("Attribute Assignment: Cell/Foci file is invalid."); } const int numCells = cellProjectionFile->getNumberOfCellProjections(); if (numCells <= 0) { throw BrainModelAlgorithmException("Attribute Assignment: There are no cells/foci."); } // // See if paints are selected // int numPaintCols = 0; if (paintFile != NULL) { numPaintCols = paintFile->getNumberOfColumns(); } if (assignmentMethod != ASSIGNMENT_METHOD_CLEAR) { if ((paintFile == NULL) || (numPaintCols <= 0)) { throw BrainModelAlgorithmException("There are no paint columns."); } else if (std::count(paintColumnsSelected.begin(), paintColumnsSelected.end(), true) <= 0) { throw BrainModelAlgorithmException("There are no paint columns selected."); } } // // Determine node nearest to each cell // std::vector cellsNearestLeftNodeDistance(numCells, -1.0); std::vector cellsNearestRightNodeDistance(numCells, -1.0); std::vector cellsNearestCerebellumNodeDistance(numCells, -1.0); std::vector cellsNearestLeftNode(numCells, -1); std::vector cellsNearestRightNode(numCells, -1); std::vector cellsNearestCerebellumNode(numCells, -1); if (leftSurface != NULL) { leftPointLocator = new BrainModelSurfacePointLocator(leftSurface, true); } if (rightSurface != NULL) { rightPointLocator = new BrainModelSurfacePointLocator(rightSurface, true); } if (cerebellumSurface != NULL) { cerebellumPointLocator = new BrainModelSurfacePointLocator(cerebellumSurface, true); } for (int i = 0; i < numCells; i++) { CellProjection* cp = cellProjectionFile->getCellProjection(i); float xyz[3]; cp->getXYZ(xyz); switch (cp->getCellStructure()) { case Structure::STRUCTURE_TYPE_CORTEX_LEFT: case Structure::STRUCTURE_TYPE_CORTEX_LEFT_OR_CEREBELLUM: if (leftSurface != NULL) { if (cp->getProjectedPosition(leftSurface->getCoordinateFile(), leftSurface->getTopologyFile(), leftSurface->getIsFiducialSurface(), leftSurface->getIsFlatSurface(), false, xyz)) { cellsNearestLeftNode[i] = leftPointLocator->getNearestPoint(xyz); cellsNearestLeftNodeDistance[i] = MathUtilities::distance3D(xyz, leftSurface->getCoordinateFile()->getCoordinate(cellsNearestLeftNode[i])); } } break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT: case Structure::STRUCTURE_TYPE_CORTEX_RIGHT_OR_CEREBELLUM: if (rightSurface != NULL) { if (cp->getProjectedPosition(rightSurface->getCoordinateFile(), rightSurface->getTopologyFile(), rightSurface->getIsFiducialSurface(), rightSurface->getIsFlatSurface(), false, xyz)) { cellsNearestRightNode[i] = rightPointLocator->getNearestPoint(xyz); cellsNearestRightNodeDistance[i] = MathUtilities::distance3D(xyz, rightSurface->getCoordinateFile()->getCoordinate(cellsNearestRightNode[i])); } } break; case Structure::STRUCTURE_TYPE_CORTEX_BOTH: case Structure::STRUCTURE_TYPE_CEREBELLUM: case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_LEFT: case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_RIGHT: if (cerebellumSurface != NULL) { if (cp->getProjectedPosition(cerebellumSurface->getCoordinateFile(), cerebellumSurface->getTopologyFile(), cerebellumSurface->getIsFiducialSurface(), cerebellumSurface->getIsFlatSurface(), false, xyz)) { cellsNearestCerebellumNode[i] = cerebellumPointLocator->getNearestPoint(xyz); cellsNearestCerebellumNodeDistance[i] = MathUtilities::distance3D(xyz, cerebellumSurface->getCoordinateFile()->getCoordinate(cellsNearestCerebellumNode[i])); } } break; case Structure::STRUCTURE_TYPE_CEREBRUM_CEREBELLUM: case Structure::STRUCTURE_TYPE_SUBCORTICAL: case Structure::STRUCTURE_TYPE_ALL: case Structure::STRUCTURE_TYPE_INVALID: break; } } // // Process the cells // for (int i = 0; i < numCells; i++) { // // Load cell data into the table // CellProjection* cd = cellProjectionFile->getCellProjection(i); // // Load paint into the table // int node = -1; float distance = 100000000.0; if (cellsNearestLeftNode[i] >= 0) { node = cellsNearestLeftNode[i]; distance = cellsNearestLeftNodeDistance[i]; } else if (cellsNearestRightNode[i] >= 0) { node = cellsNearestRightNode[i]; distance = cellsNearestRightNodeDistance[i]; } else if (cellsNearestCerebellumNode[i] >= 0) { node = cellsNearestCerebellumNode[i]; distance = cellsNearestCerebellumNodeDistance[i]; } if ((node >= 0) && (distance <= maximumDistanceFromSurface)) { QString valueString; switch (assignAttribute) { case ASSIGN_ATTRIBUTE_AREA: valueString = cd->getArea(); break; case ASSIGN_ATTRIBUTE_GEOGRAPHY: valueString = cd->getGeography(); break; case ASSIGN_ATTRIBUTE_REGION_OF_INTEREST: valueString = cd->getRegionOfInterest(); break; } bool doAssignmentFlag = false; switch (assignmentMethod) { case ASSIGNMENT_METHOD_APPEND: doAssignmentFlag = true; break; case ASSIGNMENT_METHOD_CLEAR: valueString = ""; break; case ASSIGNMENT_METHOD_REPLACE: doAssignmentFlag = true; valueString = ""; break; } if (doAssignmentFlag) { for (int j = 0; j < numPaintCols; j++) { if (paintColumnsSelected[j]) { const int paintIndex = paintFile->getPaint(node, j); QString paintName = paintFile->getPaintNameFromIndex(paintIndex); if (valueString.isEmpty() == false) { valueString += "; "; } if (optionIgnoreUnknownValuesFlag) { if (paintName.startsWith("?")) { paintName = " "; } } valueString += paintName; } } } switch (assignAttribute) { case ASSIGN_ATTRIBUTE_AREA: cd->setArea(valueString); break; case ASSIGN_ATTRIBUTE_GEOGRAPHY: cd->setGeography(valueString); break; case ASSIGN_ATTRIBUTE_REGION_OF_INTEREST: cd->setRegionOfInterest(valueString); break; } cd->setAttributeID(attributeID); } // surface found } // for (i = 0; i < numCells... } /** * get attribute names and values. */ void BrainModelSurfaceCellAttributeAssignment::getAttributeNamesAndValues( std::vector& namesOut, std::vector& valuesOut) { namesOut.clear(); valuesOut.clear(); namesOut.push_back("Area"); valuesOut.push_back(ASSIGN_ATTRIBUTE_AREA); namesOut.push_back("Geography"); valuesOut.push_back(ASSIGN_ATTRIBUTE_GEOGRAPHY); namesOut.push_back("RegionOfInterest"); valuesOut.push_back(ASSIGN_ATTRIBUTE_REGION_OF_INTEREST); } /** * get assignment names and values. */ void BrainModelSurfaceCellAttributeAssignment::getAssignmentNamesAndValues( std::vector& namesOut, std::vector& valuesOut) { namesOut.clear(); valuesOut.clear(); namesOut.push_back("Append"); valuesOut.push_back(ASSIGNMENT_METHOD_APPEND); namesOut.push_back("Clear"); valuesOut.push_back(ASSIGNMENT_METHOD_CLEAR); namesOut.push_back("Replace"); valuesOut.push_back(ASSIGNMENT_METHOD_REPLACE); } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceBorderToPaintConverter.h0000664000175000017500000000252011572067322027727 0ustar michaelmichael#ifndef __BRAIN_MODEL_SURFACE_BORDER_TO_PAINT_CONVERTER_H__ #define __BRAIN_MODEL_SURFACE_BORDER_TO_PAINT_CONVERTER_H__ #include #include class BrainModelSurface; class BorderProjectionFile; class PaintFile; class BrainModelSurfaceBorderToPaintConverter : public BrainModelAlgorithm { public: // constructor BrainModelSurfaceBorderToPaintConverter( BrainSet* bs, BrainModelSurface* surfaceIn, BorderProjectionFile* borderProjectionFileIn, PaintFile* paintFileIn, int paintColumnNumberIn, QString paintColumnNameIn); // destructor ~BrainModelSurfaceBorderToPaintConverter(); // execute the algorithm void execute() throw (BrainModelAlgorithmException); protected: /// the surface BrainModelSurface* surface; /// the border projection file BorderProjectionFile* borderProjectionFile; /// the paint file PaintFile* paintFile; /// the paint column number int paintColumnNumber; /// the name of the paint column QString paintColumnName; }; #endif /* __BRAIN_MODEL_SURFACE_BORDER_TO_PAINT_CONVERTER_H__ */ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceBorderToPaintConverter.cxx0000664000175000017500000001167611572067322030316 0ustar michaelmichael#include #include "BorderProjectionFile.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceBorderToPaintConverter.h" #include "DebugControl.h" #include "PaintFile.h" #include "TopologyFile.h" #include "TopologyHelper.h" // constructor BrainModelSurfaceBorderToPaintConverter::BrainModelSurfaceBorderToPaintConverter( BrainSet* bs, BrainModelSurface* surfaceIn, BorderProjectionFile* borderProjectionFileIn, PaintFile* paintFileIn, int paintColumnNumberIn, QString paintColumnNameIn) : BrainModelAlgorithm(bs), surface(surfaceIn), borderProjectionFile(borderProjectionFileIn), paintFile(paintFileIn), paintColumnNumber(paintColumnNumberIn), paintColumnName(paintColumnNameIn) { } // destructor BrainModelSurfaceBorderToPaintConverter::~BrainModelSurfaceBorderToPaintConverter() { } // execute the algorithm void BrainModelSurfaceBorderToPaintConverter::execute() throw (BrainModelAlgorithmException) { // // Verify inputs // if (surface == NULL) { throw BrainModelAlgorithmException("Surface is invalid."); } const int numNodes = surface->getNumberOfNodes(); if (numNodes <= 0) { throw BrainModelAlgorithmException("Surface contains no nodes."); } const CoordinateFile* cf = surface->getCoordinateFile(); const TopologyFile* topologyFile = surface->getTopologyFile(); if (topologyFile == NULL) { throw BrainModelAlgorithmException("Topology is invalid."); } const TopologyHelper* th = topologyFile->getTopologyHelper(false, true, false); if (borderProjectionFile == NULL) { throw BrainModelAlgorithmException("Border Projection File is invalid."); } const int numBorders = borderProjectionFile->getNumberOfBorderProjections(); if (numBorders <= 0) { throw BrainModelAlgorithmException( "Border Projection File contains no borders."); } if (paintFile == NULL) { throw BrainModelAlgorithmException("Paint File is invalid."); } // // Create a new paint column, if needed // if ((paintColumnNumber < 0) || (paintColumnNumber >= paintFile->getNumberOfColumns())) { if (paintFile->getNumberOfColumns() <= 0) { paintFile->setNumberOfNodesAndColumns(numNodes, 1); } else { paintFile->addColumns(1); } paintColumnNumber = paintFile->getNumberOfColumns() - 1; } paintFile->setColumnName(paintColumnNumber, paintColumnName); // // Debugging info // int debugNode = -1; if (DebugControl::getDebugOn()) { if ((DebugControl::getDebugNodeNumber() >= 0) && (DebugControl::getDebugNodeNumber() < paintFile->getNumberOfNodes())) { debugNode = DebugControl::getDebugNodeNumber(); } } // // Distance from node to nearest border point // std::vector nodeToBorderDistance(numNodes, std::numeric_limits::max()); std::vector nodePaintName(numNodes, ""); // // Loop through the border projections // for (int i = 0; i < numBorders; i++) { const BorderProjection* bp = borderProjectionFile->getBorderProjection(i); QString name; float center[3], samplingDensity, variance, topography, arealUncertainty; bp->getData(name, center, samplingDensity, variance, topography, arealUncertainty); const int numLinks = bp->getNumberOfLinks(); for (int j = 0; j < numLinks; j++) { const BorderProjectionLink* bpl = bp->getBorderProjectionLink(j); int section, nodeIndices[3]; float nodeAreas[3], radius; bpl->getData(section, nodeIndices, nodeAreas, radius); const int n1 = nodeIndices[0]; const int n2 = nodeIndices[1]; const int n3 = nodeIndices[2]; if (th->getNodeHasNeighbors(n1) && th->getNodeHasNeighbors(n2) && th->getNodeHasNeighbors(n3)) { float borderPointXYZ[3]; bpl->unprojectLink(cf, borderPointXYZ); // // Find nodes closest to border point // for (int m = 0; m < 3; m++) { const int node = nodeIndices[m]; const float distSQ = cf->getDistanceToPointSquared(node, borderPointXYZ); if (distSQ < nodeToBorderDistance[node]) { nodePaintName[node] = name; nodeToBorderDistance[node] = distSQ; } } } } } // // Assign the paint names to the nodes // for (int i = 0; i < numNodes; i++) { if (nodePaintName[i].isEmpty() == false) { const int paintIndex = this->paintFile->addPaintName(nodePaintName[i]); this->paintFile->setPaint(i, paintColumnNumber, paintIndex); } } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceBorderToMetricConverter.h0000664000175000017500000000254511572067322030106 0ustar michaelmichael#ifndef __BRAIN_MODEL_SURFACE_BORDER_TO_METRIC_CONVERTER_H__ #define __BRAIN_MODEL_SURFACE_BORDER_TO_METRIC_CONVERTER_H__ #include #include class BrainModelSurface; class BorderProjectionFile; class MetricFile; class BrainModelSurfaceBorderToMetricConverter : public BrainModelAlgorithm { public: // constructor BrainModelSurfaceBorderToMetricConverter( BrainSet* bs, BrainModelSurface* surfaceIn, BorderProjectionFile* borderProjectionFileIn, MetricFile* metricFileIn, int metricColumnNumberIn, QString metricColumnNameIn); // destructor ~BrainModelSurfaceBorderToMetricConverter(); // execute the algorithm void execute() throw (BrainModelAlgorithmException); protected: /// the surface BrainModelSurface* surface; /// the border projection file BorderProjectionFile* borderProjectionFile; /// the metric file MetricFile* metricFile; /// the metric column number int metricColumnNumber; /// the name of the metric column QString metricColumnName; }; #endif /* __BRAIN_MODEL_SURFACE_BORDER_TO_METRIC_CONVERTER_H__ */ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceBorderToMetricConverter.cxx0000664000175000017500000001327311572067322030461 0ustar michaelmichael #include "BorderProjectionFile.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceBorderToMetricConverter.h" #include "DebugControl.h" #include "MetricFile.h" #include "TopologyFile.h" #include "TopologyHelper.h" // constructor BrainModelSurfaceBorderToMetricConverter::BrainModelSurfaceBorderToMetricConverter( BrainSet* bs, BrainModelSurface* surfaceIn, BorderProjectionFile* borderProjectionFileIn, MetricFile* metricFileIn, int metricColumnNumberIn, QString metricColumnNameIn) : BrainModelAlgorithm(bs), surface(surfaceIn), borderProjectionFile(borderProjectionFileIn), metricFile(metricFileIn), metricColumnNumber(metricColumnNumberIn), metricColumnName(metricColumnNameIn) { } // destructor BrainModelSurfaceBorderToMetricConverter::~BrainModelSurfaceBorderToMetricConverter() { } // execute the algorithm void BrainModelSurfaceBorderToMetricConverter::execute() throw (BrainModelAlgorithmException) { // // Verify inputs // if (surface == NULL) { throw BrainModelAlgorithmException("Surface is invalid."); } const int numNodes = surface->getNumberOfNodes(); if (numNodes <= 0) { throw BrainModelAlgorithmException("Surface contains no nodes."); } const TopologyFile* topologyFile = surface->getTopologyFile(); if (topologyFile == NULL) { throw BrainModelAlgorithmException("Topology is invalid."); } const TopologyHelper* th = topologyFile->getTopologyHelper(false, true, false); if (borderProjectionFile == NULL) { throw BrainModelAlgorithmException("Border Projection File is invalid."); } const int numBorders = borderProjectionFile->getNumberOfBorderProjections(); if (numBorders <= 0) { throw BrainModelAlgorithmException( "Border Projection File contains no borders."); } if (metricFile == NULL) { throw BrainModelAlgorithmException("Metric File is invalid."); } // // Create a new metric column, if needed // if ((metricColumnNumber < 0) || (metricColumnNumber >= metricFile->getNumberOfColumns())) { if (metricFile->getNumberOfColumns() <= 0) { metricFile->setNumberOfNodesAndColumns(surface->getNumberOfNodes(), 1); } else { metricFile->addColumns(1); } metricColumnNumber = metricFile->getNumberOfColumns() - 1; } metricFile->setColumnName(metricColumnNumber, metricColumnName); // // Debugging info // int debugNode = -1; if (DebugControl::getDebugOn()) { if ((DebugControl::getDebugNodeNumber() >= 0) && (DebugControl::getDebugNodeNumber() < metricFile->getNumberOfNodes())) { debugNode = DebugControl::getDebugNodeNumber(); } } // // Sums of border variances for each node // std::vector nodeSum(numNodes, 0.0); std::vector nodeWeight(numNodes, 0.0); std::vector nodeCount(numNodes, 0.0); // // Loop through the border projections // for (int i = 0; i < numBorders; i++) { const BorderProjection* bp = borderProjectionFile->getBorderProjection(i); QString name; float center[3], samplingDensity, variance, topography, arealUncertainty; bp->getData(name, center, samplingDensity, variance, topography, arealUncertainty); const int numLinks = bp->getNumberOfLinks(); for (int j = 0; j < numLinks; j++) { const BorderProjectionLink* bpl = bp->getBorderProjectionLink(j); int section, nodeIndices[3]; float nodeAreas[3], radius; bpl->getData(section, nodeIndices, nodeAreas, radius); const int n1 = nodeIndices[0]; const int n2 = nodeIndices[1]; const int n3 = nodeIndices[2]; if (th->getNodeHasNeighbors(n1) && th->getNodeHasNeighbors(n2) && th->getNodeHasNeighbors(n3)) { // // Indices in border projection are out of sequence // const float areas[3] = { nodeAreas[1], nodeAreas[2], nodeAreas[0], }; float totalArea = (areas[0] + areas[1] + areas[2]); if (totalArea > 0.0) { const float weights[3] = { areas[0] / totalArea, areas[1] / totalArea, areas[2] / totalArea }; nodeSum[n1] += (weights[0] * variance); nodeSum[n2] += (weights[1] * variance); nodeSum[n3] += (weights[2] * variance); nodeWeight[n1] += weights[0]; //1.0; nodeWeight[n2] += weights[1]; //1.0; nodeWeight[n3] += weights[2]; //1.0; nodeCount[n1] += 1.0; nodeCount[n2] += 1.0; nodeCount[n3] += 1.0; } } } } // // Assign the metrics // for (int i = 0; i < numNodes; i++) { if (i == debugNode) { if (nodeCount[i] > 1.0) { std::cout << "Border to Metric node " << i << ", sum " << nodeSum[i] << ", weight " << nodeWeight[i] << ", count " << nodeCount[i] << std::endl; } } float value = 0.0; if (nodeWeight[i] > 0.0) { value = nodeSum[i] / nodeWeight[i]; } metricFile->setValue(i, metricColumnNumber, value); } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceBorderLandmarkIdentification.h0000664000175000017500000006470011572067322031074 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_BORDER_LANDMARK_IDENTIFICATION_H__ #define __BRAIN_MODEL_SURFACE_BORDER_LANDMARK_IDENTIFICATION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelAlgorithm.h" #include "BrainModelSurfaceFindExtremum.h" #include "BrainModelSurfaceROICreateBorderUsingMetricShape.h" #include "StereotaxicSpace.h" #include "Structure.h" class AreaColorFile; class BorderColorFile; class BorderProjection; class BorderProjectionFile; class BrainModelSurface; class BrainModelSurfaceROINodeSelection; class FociColorFile; class FociProjectionFile; class MetricFile; class PaintFile; class SurfaceShapeFile; class VocabularyFile; class VolumeFile; /// generate border landmarks for flattening and registration class BrainModelSurfaceBorderLandmarkIdentification : public BrainModelAlgorithm { public: /// operations to perform enum OPERATION { OPERATION_ID_REGISTRATION_LANDMARKS = 1, OPERATION_ID_FLATTENING_LANDMARKS = 2, OPERATION_ID_ALL = 0xffffffff }; // constructor BrainModelSurfaceBorderLandmarkIdentification(BrainSet* bs, const StereotaxicSpace& stereotaxicSpaceIn, VolumeFile* anatomicalVolumeFileIn, const BrainModelSurface* fiducialSurfaceIn, const BrainModelSurface* inflatedSurfaceIn, const BrainModelSurface* veryInflatedSurfaceIn, const BrainModelSurface* ellipsoidSurfaceIn, const SurfaceShapeFile* depthSurfaceShapeFileIn, const int depthSurfaceShapeFileColumnNumberIn, PaintFile* paintFileInOut, const int paintFileGeographyColumnNumberIn, AreaColorFile* areaColorFileInOut, BorderProjectionFile* borderProjectionFileInOut, BorderColorFile* borderColorFileInOut, VocabularyFile* vocabularyFileInOut, const int operationSelectionMaskIn = OPERATION_ID_ALL); // destructor ~BrainModelSurfaceBorderLandmarkIdentification(); // execute the algorithm void execute() throw (BrainModelAlgorithmException); // space supported for landmark identification? static bool isStereotaxicSpaceSupported(const StereotaxicSpace& stereotaxicSpaceIn); /// get probabilistic metric file of sulci locations const MetricFile* getMetricFile() const { return metricFile; } /// get foci projection file containing foci created during landmark determination const FociProjectionFile* getFociProjectionFile() const { return fociProjectionFile; } /// get foci color file containing colors for foci created during landmark creation const FociColorFile* getFociColorFile() const { return fociColorFile; } /// get supported stereotaxic spaces static void getSupportedStereotaxicSpaces(std::vector& spacesOut); /// get the name of the medial wall for flattening static QString getFlattenMedialWallBorderName() { return "FLATTEN.HOLE.MedialWall"; } /// get the name prefix for flattening standard cuts static QString getFlattenStandardCutsBorderNamePrefix() { return "FLATTEN.CUT.Std."; } /// get the name of central sulcus registration landmark static QString getCentralSulcusRegistrationLandmarkName() { return "LANDMARK.CentralSulcus"; } protected: // identify the sulci void paintSulcalIdentification() throw (BrainModelAlgorithmException); // identify the central sulcus void identifyCentralSulcus() throw (BrainModelAlgorithmException); // identify the sylvian fissure void identifySylvianFissure() throw (BrainModelAlgorithmException); // identify the superior temporal gyrus void identifySuperiorTemporalGyrus() throw (BrainModelAlgorithmException); // identify the calcarine sulcus void identifyCalcarineSulcus() throw (BrainModelAlgorithmException); // extend the calcarine sulcus to the medial wall void extendCalcarineSulcusToMedialWall() throw (BrainModelAlgorithmException); // identify the medial wall void identifyMedialWall() throw (BrainModelAlgorithmException); // create medial wall dorsal and ventral borders void createMedialWallDorsalAndVentralLandmarks() throw (BrainModelAlgorithmException); // identify the dorsal medial wall NEW void identifyDorsalMedialWallNew() throw (BrainModelAlgorithmException); // identify the dorsal medial wall void identifyDorsalMedialWallOld() throw (BrainModelAlgorithmException); // identify the ventral medial wall void identifyVentralMedialWall() throw (BrainModelAlgorithmException); // identify the cuts void identifyCuts() throw (BrainModelAlgorithmException); // identify the cut calcarine void identifyCutCalcarine(const int medialWallCogNodeNumber) throw (BrainModelAlgorithmException); // identify the cut cingulate void identifyCutCingulate(const int medialWallCogNodeNumber) throw (BrainModelAlgorithmException); // identify the cut frontal void identifyCutFrontal(const int medialWallCogNodeNumber) throw (BrainModelAlgorithmException); // identify the cut sylvian void identifyCutSylvian(const int medialWallCogNodeNumber) throw (BrainModelAlgorithmException); // identify the cut temporal void identifyCutTemporal(const int medialWallCogNodeNumber) throw (BrainModelAlgorithmException); // generate surface curvatures void generateSurfaceCurvatures() throw (BrainModelAlgorithmException); // get node nearby that has the value closest to the target value int getNearbyNodeWithShapeValue(const BrainModelSurface* surface, const SurfaceShapeFile* shapeFile, const int shapeColumnNumber, const float targetValue, const int startNodeNumber, const float maxDistance, const BrainModelSurfaceROINodeSelection* limitToWithinROI = NULL, const float* limitToExtent = NULL) const; // create a file name QString createFileName(const QString& description, const QString& extension) const; // add a focus at a border link void addFocusAtBorderLink(const BorderProjection* bp, const int borderLinkNumber, const QString& focusName); // add a focus at a node void addFocusAtNode(const QString& focusName, const int placeAtNodeNumber) throw (BrainModelAlgorithmException); // add a focus at a location void addFocusAtXYZ(const QString& focusName, const float xyz[3]); // add a focus at a location void addFocusAtXYZ(const BrainModelSurface* focusSurface, const QString& focusName, const float xyz[3]); // add a focus at the node nearest the XYZ int addFocusAtNodeNearestXYZ(const BrainModelSurface* surface, const QString& focusName, const float xyz[3]); // add focus at extremum int addFocusAtExtremum(const BrainModelSurface* extremumSurface, const int startingNodeNumber, const BrainModelSurfaceFindExtremum::DIRECTION searchDirection, const float xMaximumMovement, const float yMaximumMovement, const float zMaximumMovement, const QString& focusName, BrainModelSurfaceROINodeSelection* roiAlongPath = NULL, const BrainModelSurfaceFindExtremum::NORMAL_RESTRICTION xr = BrainModelSurfaceFindExtremum::NORMAL_RESTRICTION_NONE, const BrainModelSurfaceFindExtremum::NORMAL_RESTRICTION yr = BrainModelSurfaceFindExtremum::NORMAL_RESTRICTION_NONE, const BrainModelSurfaceFindExtremum::NORMAL_RESTRICTION zr = BrainModelSurfaceFindExtremum::NORMAL_RESTRICTION_NONE) throw (BrainModelAlgorithmException); /// add focus color void addFocusColor(const QString& colorName, const unsigned char red, const unsigned char green, const unsigned char blue); /// border nibble within modes enum BORDER_NIBBLE_MODE_DISTANCE { BORDER_NIBBLE_MODE_DISTANCE_X, BORDER_NIBBLE_MODE_DISTANCE_Y, BORDER_NIBBLE_MODE_DISTANCE_Z, BORDER_NIBBLE_MODE_DISTANCE_LINEAR }; // nibble border within distance void nibbleBorderWithinDistance(const BrainModelSurface* surface, const QString& borderName, const int nodeNumber, const BORDER_NIBBLE_MODE_DISTANCE nibbleMode, const float nibbleDistance) throw (BrainModelAlgorithmException); // nibble border within distance void nibbleBorderWithinDistance(const BrainModelSurface* surface, const QString& borderName, const float nibbleFromHereXYZ[3], const BORDER_NIBBLE_MODE_DISTANCE nibbleMode, const float nibbleDistance) throw (BrainModelAlgorithmException); // nibble border beyond distance void nibbleBorderBeyondDistance(const BrainModelSurface* surface, const QString& borderName, const float nibbleFromHereXYZ[3], const BORDER_NIBBLE_MODE_DISTANCE nibbleMode, const float nibbleDistance) throw (BrainModelAlgorithmException); /// border nibble within modes enum BORDER_NIBBLE_MODE_OFFSET { BORDER_NIBBLE_MODE_OFFSET_GREATER_THAN_X, BORDER_NIBBLE_MODE_OFFSET_GREATER_THAN_Y, BORDER_NIBBLE_MODE_OFFSET_GREATER_THAN_Z, BORDER_NIBBLE_MODE_OFFSET_LESS_THAN_X, BORDER_NIBBLE_MODE_OFFSET_LESS_THAN_Y, BORDER_NIBBLE_MODE_OFFSET_LESS_THAN_Z }; // nibble border with offset void nibbleBorderWithinOffset(const BrainModelSurface* surface, const QString& borderName, const float xyz[3], const BORDER_NIBBLE_MODE_OFFSET nibbleMode, const float nibbleOffset) throw (BrainModelAlgorithmException); // resample a border void resampleBorder(const BrainModelSurface* surface, const QString& borderName, const float samplingDistance, const bool projectToTilesFlag = true) throw (BrainModelAlgorithmException); // remove loops from a border void removeLoopsFromBorder(const BrainModelSurface* surface, const QString& borderName, const char axisChar) throw (BrainModelAlgorithmException); // project the foci void projectFoci(); // draw a border moving along the "most-lateral" nodes /** DOES NOT WORK void drawBorderMostLateral( const BrainModelSurface* borderSurface, const BrainModelSurfaceROINodeSelection* roiIn, const QString borderName, const std::vector& nodeNumbers, const float samplingDistance) throw (BrainModelAlgorithmException); */ // draw a border using geodesic method void drawBorderGeodesic(const BrainModelSurface* borderSurface, const BrainModelSurfaceROINodeSelection* roi, const QString borderName, const int startNodeNumber, const int endNodeNumber, const float samplingDistance) throw (BrainModelAlgorithmException); // draw a border using geodesic method connecting a group of nodes void drawBorderGeodesic(const BrainModelSurface* borderSurface, const BrainModelSurfaceROINodeSelection* roi, const QString borderName, const std::vector& nodeNumbers, const float samplingDistance) throw (BrainModelAlgorithmException); // draw a border using heuristic geodesic method connecting a group of nodes void drawBorderTargetedGeodesic(const BrainModelSurface* borderSurface, const BrainModelSurfaceROINodeSelection* roi, const QString borderName, const std::vector& nodeNumbers, const float samplingDistance, float target[3], float targetweight) throw (BrainModelAlgorithmException); // draw a border using heuristic geodesic method connecting a group of nodes void drawBorderMetricGeodesic(const BrainModelSurface* borderSurface, const BrainModelSurfaceROINodeSelection* roi, const QString borderName, const std::vector& nodeNumbers, const float samplingDistance, MetricFile* nodeCost, int metricColumn, float metricWeight) throw (BrainModelAlgorithmException); // Find node along geodesic path between nodes int findNodeAlongGeodesicPathBetweenNodes( const BrainModelSurface* surface, const int startNodeNumber, const int endNodeNumber, const float distanceFromStartNode, const BrainModelSurfaceROINodeSelection* roi = NULL) throw (BrainModelAlgorithmException); // draw a border using metric method void drawBorderMetric(const BrainModelSurface* borderSurface, const BrainModelSurfaceROICreateBorderUsingMetricShape::MODE drawMode, const MetricFile* metricShapeFile, const int metricShapeFileColumn, const QString borderName, const int startNodeNumber, const int endNodeNumber, const float samplingDistance, const BrainModelSurfaceROINodeSelection* optionalROI = NULL) throw (BrainModelAlgorithmException); // save an ROI to a file void saveRoiToFile(const BrainModelSurfaceROINodeSelection& roi, const QString& roiFileName) throw (BrainModelAlgorithmException); // merge borders (returned border was added to border projection file) BorderProjection* mergeBorders(const QString& outputBorderName, const QString& border1Name, const QString& border2Name, const bool deleteInputBordersFlag, const bool closeBorderFlag, const BrainModelSurface* smoothingSurface, const int smoothingIterations, const int smoothingNeighbors) throw (BrainModelAlgorithmException); // merge borders (returned border was added to border projection file) BorderProjection* mergeBorders(const QString& outputBorderName, const std::vector& borderNames, const bool deleteInputBordersFlag, const bool closeBorderFlag, const BrainModelSurface* smoothingSurface, const int smoothingIterations, const int smoothingNeighbors) throw (BrainModelAlgorithmException); // get intersection of two borders (returns true if intersection valid) bool getBorderIntersection(const BrainModelSurface* borderSurface, const QString& border1Name, const QString& border2Name, const QString& intersectionFocusName, const float intersectionTolerance, float* itersectionXYZOut = NULL, int* border1IntersectionLinkNumberOut = NULL, int* border2IntersectionLinkNumberOut = NULL) throw (BrainModelAlgorithmException); // get intersection of two borders (returns true if intersection valid) bool getBorderIntersection(const BrainModelSurface* borderSurface, const QString& border1Name, const QString& border2Name, const QString& intersectionFocusName, const float intersectionToleranceMinimum, const float intersectionToleranceMaximum, const float intersectionToleranceStep, float itersectionXYZOut[3]) throw (BrainModelAlgorithmException); // create a fiducial surface that is approximately scaled to 711-2* space void createAndScaleFiducialSurface() throw (BrainModelAlgorithmException); // get scaling for stereotaxic space (returns true if supported space) static bool getScalingForStereotaxicSpace(const StereotaxicSpace& space, float scalingOutLeft[3], float scalingOutRight[3]); /// delete the debug files directory and the files within it void deleteDebugFilesDirectoryAndContents(); /// get the node that is most lateral in the extent int getMostLateralNodeInExtent(const BrainModelSurface* surface, const float startXYZ[6], const float extent[6], const float maxGeodesicDistance) const; /// get the node that is most lateral in the extent int getClosestNodeInExtent(const BrainModelSurface* surface, const float startXYZ[6], const float extent[6], const float maxGeodesicDistance, const float target[3]) const; /// node type for heuristic search struct searchNode { float cost, heur; int node, prev; }; /// TSC: yes, these methods are overloaded, so sue me /// connect nodes via graph search, favoring nodes closer to the target point Border drawHeuristic(const BrainModelSurface* borderSurface, BrainModelSurfaceROINodeSelection* roi, int startNodeNumber, int endNodeNumber, float target[], float targetWeight) throw (BrainModelAlgorithmException); /// connect nodes via graph search, favoring nodes closer to the target point Border drawHeuristic(const BrainModelSurface* borderSurface, BrainModelSurfaceROINodeSelection* roi, int startNodeNumber, int endNodeNumber, MetricFile* nodeCost, int metricColumn, float metricWeight) throw (BrainModelAlgorithmException); /// stereotaxic space const StereotaxicSpace stereotaxicSpace; /// anatomical volume file VolumeFile* anatomicalVolumeFile; /// the input fiducial surface const BrainModelSurface* inputFiducialSurface; /// fiducial surface BrainModelSurface* fiducialSurface; /// inflated surface const BrainModelSurface* inflatedSurface; /// very inflated surface const BrainModelSurface* veryInflatedSurface; /// ellipsoid surface const BrainModelSurface* ellipsoidSurface; /// surface shape file containing depth information const SurfaceShapeFile* depthSurfaceShapeFile; /// surface shape file depth column number const int depthSurfaceShapeFileColumnNumber; /// paint file PaintFile* paintFile; /// column number of geography in paint file const int paintFileGeographyColumnNumber; /// area color file AreaColorFile* areaColorFile; /// border projection file BorderProjectionFile* borderProjectionFile; /// border color file BorderColorFile* borderColorFile; /// probabilistic metric file MetricFile* metricFile; /// foci projection file FociProjectionFile* fociProjectionFile; /// foci color file FociColorFile* fociColorFile; /// vocabulary file VocabularyFile* vocabularyFile; /// curvature shape file SurfaceShapeFile* curvatureShapeFile; /// fiducial curvature shape column number int curvatureFiducialMeanColumnNumber; /// smoothed fiducial curvature shape column number int curvatureFiducialSmoothedMeanColumnNumber; /// inflated curvature shape column number int curvatureInflatedMeanColumnNumber; /// paint file's Sulcus ID column name QString paintFileSulcusIdColumnName; /// paint file's Sulcus ID column number int paintFileSulcusIdColumnNumber; /// inflated surface coordinate of central sulcus ventral tip float inflatedSurfaceCentralSulcusVentralTipXYZ[3]; /// fiducial coordinate of the temporal pole float fiducialSurfaceTemporalPoleXYZ[3]; /// inflated coordinate of the temporal pole float inflatedSurfaceTemporalPoleXYZ[3]; /// node at temporal pole int temporalPoleNodeNumber; /// left hemisphere flag bool leftHemisphereFlag; /// the structure Structure::STRUCTURE_TYPE surfaceStructure; /// operation mask const int operationSelectionMask; /// node at anterior or calcarine sulcus int calcarineAnteriorNodeNumber; /// name of flatten frontal cut QString flattenCutFrontalName; /// name of calcarine cut QString flattenCutCalcarineName; /// name of dorsal section of medial wall QString medialWallDorsalSectionName; /// name of ventral part of medial wall QString medialWallVentralSectionName; /// medial node of central sulcus int cesMedialNodeNumber; /// calcarine posterior extreme node number int calcarinePosteriorExtremeNodeNumber; /// corpus callosum genu beginning node number int ccGenuBeginningNodeNumber; /// corpus callosum splenium limit node number int ccSpleniumLimitNodeNumber; /// corpus callosum splenium end node number int ccSpleniumEndNodeNumber; /// start node for medial wall int medialWallStartNodeNumber; /// node at ventral/frontal end of sylvian fissure inferior branch int sfInferiorBranchBeginNodeNumber; /// node at sylvian fissure ventral/frontal region int sfVentralFrontalNodeNumber; /// name of landmark QString calcarineSulcusLandmarkName; /// name of border file for debugging QString borderDebugFileName; /// name of foci projection file for debugging QString fociProjectionDebugFileName; /// name of foci color file for debugging QString fociColorDebugFileName; /// surface scale factors for "rough" transformation to 711-2 space float surfaceSpaceScaling[3]; /// name of directory containing debug files QString debugFilesDirectoryName; /// save all intermediate files bool saveIntermediateFilesFlag; /// all landmarks were sucessfully created bool allLandmarksSuccessfulFlag; }; #endif // __BRAIN_MODEL_SURFACE_BORDER_LANDMARK_IDENTIFICATION_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceBorderLandmarkIdentification.cxx0000664000175000017500000075310411572067322031452 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "AreaColorFile.h" #include "BorderColorFile.h" #include "BorderFile.h" #include "BorderFileProjector.h" #include "BorderProjectionFile.h" #include "BorderProjectionUnprojector.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceBorderLandmarkIdentification.h" #include "BrainModelSurfaceCurvature.h" #include "BrainModelSurfaceClusterToBorderConverter.h" #include "BrainModelSurfaceFindExtremum.h" #include "BrainModelSurfaceGeodesic.h" #include "BrainModelSurfacePaintSulcalIdentification.h" #include "BrainModelSurfaceROICreateBorderUsingGeodesic.h" #include "BrainModelSurfaceROINodeSelection.h" #include "BrainModelVolumeSureFitSegmentation.h" #include "BrainSet.h" #include "CellFileProjector.h" #include "DebugControl.h" #include "FociColorFile.h" #include "FociProjectionFile.h" #include "GeodesicDistanceFile.h" #include "MetricFile.h" #include "NodeRegionOfInterestFile.h" #include "PaintFile.h" #include "StatisticHistogram.h" #include "SurfaceShapeFile.h" #include "TopologyFile.h" #include "TopologyHelper.h" #include "VocabularyFile.h" #include "VolumeFile.h" /** * constructor. * * Note: Anatomical volume is used only for generation of corpus callosum. * If desired, an anatomical volume containing just the corpus callosum may * be used, and, if so, its filename must contain the case-insensitive * words "corpus" and "callosum". */ BrainModelSurfaceBorderLandmarkIdentification::BrainModelSurfaceBorderLandmarkIdentification( BrainSet* bs, const StereotaxicSpace& stereotaxicSpaceIn, VolumeFile* anatomicalVolumeFileIn, const BrainModelSurface* fiducialSurfaceIn, const BrainModelSurface* inflatedSurfaceIn, const BrainModelSurface* veryInflatedSurfaceIn, const BrainModelSurface* ellipsoidSurfaceIn, const SurfaceShapeFile* depthSurfaceShapeFileIn, const int depthSurfaceShapeFileColumnNumberIn, PaintFile* paintFileInOut, const int paintFileGeographyColumnNumberIn, AreaColorFile* areaColorFileInOut, BorderProjectionFile* borderProjectionFileInOut, BorderColorFile* borderColorFileInOut, VocabularyFile* vocabularyFileInOut, const int operationSelectionMaskIn) : BrainModelAlgorithm(bs), stereotaxicSpace(stereotaxicSpaceIn), anatomicalVolumeFile(anatomicalVolumeFileIn), inputFiducialSurface(fiducialSurfaceIn), inflatedSurface(inflatedSurfaceIn), veryInflatedSurface(veryInflatedSurfaceIn), ellipsoidSurface(ellipsoidSurfaceIn), depthSurfaceShapeFile(depthSurfaceShapeFileIn), depthSurfaceShapeFileColumnNumber(depthSurfaceShapeFileColumnNumberIn), paintFile(paintFileInOut), paintFileGeographyColumnNumber(paintFileGeographyColumnNumberIn), areaColorFile(areaColorFileInOut), borderProjectionFile(borderProjectionFileInOut), borderColorFile(borderColorFileInOut), vocabularyFile(vocabularyFileInOut), operationSelectionMask(operationSelectionMaskIn) { saveIntermediateFilesFlag = true; if (DebugControl::getDebugOn()) { saveIntermediateFilesFlag = true; } fiducialSurface = NULL; curvatureFiducialMeanColumnNumber = -1; curvatureInflatedMeanColumnNumber = -1; curvatureShapeFile = NULL; fociProjectionFile = NULL; fociColorFile = NULL; metricFile = NULL; paintFileSulcusIdColumnName = ""; paintFileSulcusIdColumnNumber = -1; calcarineAnteriorNodeNumber = -1; calcarinePosteriorExtremeNodeNumber = -1; ccGenuBeginningNodeNumber = -1; ccSpleniumEndNodeNumber = -1; cesMedialNodeNumber = -1; medialWallStartNodeNumber = -1; sfInferiorBranchBeginNodeNumber = -1; sfVentralFrontalNodeNumber = -1; temporalPoleNodeNumber = -1; calcarineSulcusLandmarkName = "LANDMARK.CalcarineSulcus"; allLandmarksSuccessfulFlag = false; } /** * destructor. */ BrainModelSurfaceBorderLandmarkIdentification::~BrainModelSurfaceBorderLandmarkIdentification() { if (fiducialSurface != NULL) { brainSet->deleteBrainModel(fiducialSurface); fiducialSurface = NULL; } if (curvatureShapeFile != NULL) { delete curvatureShapeFile; curvatureShapeFile = NULL; } if (metricFile != NULL) { delete metricFile; metricFile = NULL; } if (fociProjectionFile != NULL) { delete fociProjectionFile; fociProjectionFile = NULL; } if (fociColorFile != NULL) { delete fociColorFile; fociColorFile = NULL; } // // delete debug files only if debugging off and all landmarks okay // if (saveIntermediateFilesFlag == false) { if (allLandmarksSuccessfulFlag) { deleteDebugFilesDirectoryAndContents(); } } } /** * delete the debug files directory and the files within it. */ void BrainModelSurfaceBorderLandmarkIdentification::deleteDebugFilesDirectoryAndContents() { if (debugFilesDirectoryName.isEmpty() == false) { QDir debugDir(debugFilesDirectoryName); if (debugDir.exists()) { // // Delete all files // QDirIterator dit(debugDir); while (dit.hasNext()) { const QString name(dit.next()); QFileInfo fi(name); if (fi.isFile()) { //std::cout << "Deleting: " // << name.toAscii().constData() // << std::endl; QFile::remove(name); } } // // Delete the directory // debugDir.cdUp(); debugDir.rmdir(debugFilesDirectoryName); } } } /** * execute the algorithm. */ void BrainModelSurfaceBorderLandmarkIdentification::execute() throw (BrainModelAlgorithmException) { allLandmarksSuccessfulFlag = false; if (anatomicalVolumeFile == NULL) { throw BrainModelAlgorithmException("The anatomical volume is invalid."); } if (inputFiducialSurface == NULL) { throw BrainModelAlgorithmException("The fiducial surface is invalid."); } if (inflatedSurface == NULL) { throw BrainModelAlgorithmException("The inflated surface is invalid."); } if (veryInflatedSurface == NULL) { throw BrainModelAlgorithmException("The very inflated surface is invalid."); } if (ellipsoidSurface == NULL) { throw BrainModelAlgorithmException("The ellipsoid surface is invalid."); } if (depthSurfaceShapeFile == NULL) { throw BrainModelAlgorithmException("The surface shape file is invalid."); } if (paintFile == NULL) { throw BrainModelAlgorithmException("The paint file is invalid."); } if (areaColorFile == NULL) { throw BrainModelAlgorithmException("The area color file is invalid."); } if (borderProjectionFile == NULL) { throw BrainModelAlgorithmException("The border projection file is invalid."); } if (borderColorFile == NULL) { throw BrainModelAlgorithmException("The border color file is invalid."); } if ((depthSurfaceShapeFileColumnNumber < 0) || (depthSurfaceShapeFileColumnNumber >= depthSurfaceShapeFile->getNumberOfColumns())) { throw BrainModelAlgorithmException("Surface Shape File Depth column is invalid."); } const int originalNumberOfBorderColors = borderColorFile->getNumberOfColors(); // // Create a subdirectory for debug files // debugFilesDirectoryName = "LANDMARK_BORDER_DEBUG_FILES"; deleteDebugFilesDirectoryAndContents(); QDir debugFilesDir(QDir::currentPath()); debugFilesDir.mkdir(debugFilesDirectoryName); // // Clear out debug files // BorderProjectionFile bpf; borderDebugFileName = bpf.makeDefaultFileName("DebugBorders"); QFile::remove(borderDebugFileName); FociProjectionFile fpf; fociProjectionDebugFileName = fpf.makeDefaultFileName("DebugFoci"); fociProjectionDebugFileName = debugFilesDirectoryName + "/" + fociProjectionDebugFileName; QFile::remove(fociProjectionDebugFileName); FociColorFile fcf; fociColorDebugFileName = fcf.makeDefaultFileName("DebugFoci"); fociColorDebugFileName = debugFilesDirectoryName + "/" + fociColorDebugFileName; QFile::remove(fociColorDebugFileName); // // Verify left or right only // leftHemisphereFlag = false; surfaceStructure = inputFiducialSurface->getStructure().getType(); switch (surfaceStructure) { case Structure::STRUCTURE_TYPE_CORTEX_LEFT: leftHemisphereFlag = true; break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT: leftHemisphereFlag = false; break; case Structure::STRUCTURE_TYPE_CORTEX_BOTH: case Structure::STRUCTURE_TYPE_CEREBELLUM: case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_LEFT: case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_RIGHT: case Structure::STRUCTURE_TYPE_CORTEX_LEFT_OR_CEREBELLUM: case Structure::STRUCTURE_TYPE_CORTEX_RIGHT_OR_CEREBELLUM: case Structure::STRUCTURE_TYPE_CEREBRUM_CEREBELLUM: case Structure::STRUCTURE_TYPE_SUBCORTICAL: case Structure::STRUCTURE_TYPE_ALL: case Structure::STRUCTURE_TYPE_INVALID: throw BrainModelAlgorithmException("Structure must be left or right hemisphere in fiducial coordinate file."); break; } switch (inflatedSurface->getStructure().getType()) { case Structure::STRUCTURE_TYPE_CORTEX_LEFT: if (!leftHemisphereFlag) throw BrainModelAlgorithmException("Hemisphere must match in inflated surface."); break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT: if (leftHemisphereFlag) throw BrainModelAlgorithmException("Hemisphere must match in inflated surface."); break; case Structure::STRUCTURE_TYPE_CORTEX_BOTH: case Structure::STRUCTURE_TYPE_CEREBELLUM: case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_LEFT: case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_RIGHT: case Structure::STRUCTURE_TYPE_CORTEX_LEFT_OR_CEREBELLUM: case Structure::STRUCTURE_TYPE_CORTEX_RIGHT_OR_CEREBELLUM: case Structure::STRUCTURE_TYPE_CEREBRUM_CEREBELLUM: case Structure::STRUCTURE_TYPE_SUBCORTICAL: case Structure::STRUCTURE_TYPE_ALL: case Structure::STRUCTURE_TYPE_INVALID: throw BrainModelAlgorithmException("Structure must be left or right hemisphere in inflated coordinate file."); break; } switch (veryInflatedSurface->getStructure().getType()) { case Structure::STRUCTURE_TYPE_CORTEX_LEFT: if (!leftHemisphereFlag) throw BrainModelAlgorithmException("Hemisphere must match in very inflated surface."); break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT: if (leftHemisphereFlag) throw BrainModelAlgorithmException("Hemisphere must match in very inflated surface."); break; case Structure::STRUCTURE_TYPE_CORTEX_BOTH: case Structure::STRUCTURE_TYPE_CEREBELLUM: case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_LEFT: case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_RIGHT: case Structure::STRUCTURE_TYPE_CORTEX_LEFT_OR_CEREBELLUM: case Structure::STRUCTURE_TYPE_CORTEX_RIGHT_OR_CEREBELLUM: case Structure::STRUCTURE_TYPE_CEREBRUM_CEREBELLUM: case Structure::STRUCTURE_TYPE_SUBCORTICAL: case Structure::STRUCTURE_TYPE_ALL: case Structure::STRUCTURE_TYPE_INVALID: throw BrainModelAlgorithmException("Structure must be left or right hemisphere in very inflated coordinate file."); break; } switch (ellipsoidSurface->getStructure().getType()) { case Structure::STRUCTURE_TYPE_CORTEX_LEFT: if (!leftHemisphereFlag) throw BrainModelAlgorithmException("Hemisphere must match in ellipsoid surface."); break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT: if (leftHemisphereFlag) throw BrainModelAlgorithmException("Hemisphere must match in ellipsoid surface."); break; case Structure::STRUCTURE_TYPE_CORTEX_BOTH: case Structure::STRUCTURE_TYPE_CEREBELLUM: case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_LEFT: case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_RIGHT: case Structure::STRUCTURE_TYPE_CORTEX_LEFT_OR_CEREBELLUM: case Structure::STRUCTURE_TYPE_CORTEX_RIGHT_OR_CEREBELLUM: case Structure::STRUCTURE_TYPE_CEREBRUM_CEREBELLUM: case Structure::STRUCTURE_TYPE_SUBCORTICAL: case Structure::STRUCTURE_TYPE_ALL: case Structure::STRUCTURE_TYPE_INVALID: throw BrainModelAlgorithmException("Structure must be left or right hemisphere in ellipsoid coordinate file."); break; } // // Scale fiducial to be approximately 711-2* size // createAndScaleFiducialSurface(); // // Create data files // fociProjectionFile = new FociProjectionFile; fociColorFile = new FociColorFile; // // Identify the sulci // paintSulcalIdentification(); // // Generate curvature on Fiducial and Inflated Surfaces // generateSurfaceCurvatures(); // // Identify the landmarks // QStringList errorMessageStringList; if (errorMessageStringList.isEmpty()) { try { identifyCentralSulcus(); } catch (BrainModelAlgorithmException& e) { errorMessageStringList += "Central Sulcus Landmark Error\n"; errorMessageStringList += e.whatQString(); } } if (errorMessageStringList.isEmpty()) { try { identifySuperiorTemporalGyrus(); // Depends upon CeS } catch (BrainModelAlgorithmException& e) { errorMessageStringList += "Superior Temporal Gyrus Landmark Error\n"; errorMessageStringList += e.whatQString(); } } if (errorMessageStringList.isEmpty()) { try { identifySylvianFissure(); // Depends upon STG } catch (BrainModelAlgorithmException& e) { errorMessageStringList += "Sylvian Fissure Landmark Error\n"; errorMessageStringList += e.whatQString(); } } if (errorMessageStringList.isEmpty()) { try { identifyCalcarineSulcus(); } catch (BrainModelAlgorithmException& e) { errorMessageStringList += "Calcarine Sulcus Landmark Error\n"; errorMessageStringList += e.whatQString(); } } if (errorMessageStringList.isEmpty()) { try { identifyMedialWall(); } catch (BrainModelAlgorithmException& e) { errorMessageStringList += "Medial Wall Landmark Error\n"; errorMessageStringList += e.whatQString(); } } if (errorMessageStringList.isEmpty()) { try { extendCalcarineSulcusToMedialWall(); } catch (BrainModelAlgorithmException& e) { errorMessageStringList += "Calcarine Landmark Extension to Medial Wall Error\n"; errorMessageStringList += e.whatQString(); } } if (errorMessageStringList.isEmpty()) { try { identifyCuts(); } catch (BrainModelAlgorithmException& e) { errorMessageStringList += "Cut Generation Error\n"; errorMessageStringList += e.whatQString(); } } if (errorMessageStringList.isEmpty()) { try { createMedialWallDorsalAndVentralLandmarks(); } catch (BrainModelAlgorithmException& e) { errorMessageStringList += "Create Medial Wall Dorsal and Ventral Segments Error\n"; errorMessageStringList += e.whatQString(); } } // // Project the foci // projectFoci(); if (errorMessageStringList.isEmpty() == false) { throw BrainModelAlgorithmException(errorMessageStringList.join("\n")); } // // All created successfully // allLandmarksSuccessfulFlag = true; // // If NOT generating flattening landmarks // if ((operationSelectionMask & OPERATION_ID_FLATTENING_LANDMARKS) == 0) { const int num = borderProjectionFile->getNumberOfBorderProjections(); for (int i = (num - 1); i >= 0; i--) { BorderProjection* bp = borderProjectionFile->getBorderProjection(i); if (bp->getName().startsWith("FLATTEN")) { borderProjectionFile->removeBorderProjection(i); } } } // // If NOT generating registration landmarks // if ((operationSelectionMask & OPERATION_ID_REGISTRATION_LANDMARKS) == 0) { const int num = borderProjectionFile->getNumberOfBorderProjections(); for (int i = (num - 1); i >= 0; i--) { BorderProjection* bp = borderProjectionFile->getBorderProjection(i); if (bp->getName().startsWith("LANDMARK")) { borderProjectionFile->removeBorderProjection(i); } } } borderProjectionFile->setFileName( borderProjectionFile->makeDefaultFileName("Landmarks")); if (originalNumberOfBorderColors <= 0) { borderColorFile->setFileName( borderColorFile->makeDefaultFileName("Landmark")); } } /** * create a fiducial surface that is approximately scaled to 711-2* space. */ void BrainModelSurfaceBorderLandmarkIdentification::createAndScaleFiducialSurface() throw (BrainModelAlgorithmException) { // // Make a copy of the input surface so that it may be scaled // fiducialSurface = new BrainModelSurface(*inputFiducialSurface); brainSet->addBrainModel(fiducialSurface); float leftScale[3], rightScale[3]; if (getScalingForStereotaxicSpace(stereotaxicSpace, leftScale, rightScale) == false) { throw BrainModelAlgorithmException( "Stereotaxic space " + stereotaxicSpace.getName() + " not supported for border landmark identification."); } TransformationMatrix tm; if (leftHemisphereFlag) { tm.scale(leftScale); } else { tm.scale(rightScale); } fiducialSurface->applyTransformationMatrix(tm); CoordinateFile* cf = fiducialSurface->getCoordinateFile(); const QString name(debugFilesDirectoryName + "/" + cf->makeDefaultFileName("LandmarkFiducialScaled")); try { cf->writeFile(name); } catch (FileException&) { std::cout << "WARNING: Unable to write LandmarkFiducialScaled surface." << std::endl; } } /** * get supported stereotaxic spaces. */ void BrainModelSurfaceBorderLandmarkIdentification::getSupportedStereotaxicSpaces( std::vector& spacesOut) { spacesOut.clear(); std::vector allSpaces; StereotaxicSpace::getAllStereotaxicSpaces(allSpaces); const int numSpaces = static_cast(allSpaces.size()); for (int i = 0; i < numSpaces; i++) { float dummy[3]; if (getScalingForStereotaxicSpace(allSpaces[i], dummy, dummy)) { spacesOut.push_back(allSpaces[i]); } } } /** * space supported for landmark identification?. */ bool BrainModelSurfaceBorderLandmarkIdentification::isStereotaxicSpaceSupported( const StereotaxicSpace& stereotaxicSpaceIn) { float scaleLeft[3], scaleRight[3]; bool valid = getScalingForStereotaxicSpace(stereotaxicSpaceIn, scaleLeft, scaleRight); return valid; } /** * get scaling for stereotaxic space (returns true if supported space). */ bool BrainModelSurfaceBorderLandmarkIdentification::getScalingForStereotaxicSpace( const StereotaxicSpace& space, float scalingOutLeft[3], float scalingOutRight[3]) { scalingOutLeft[0] = 1.0; scalingOutLeft[1] = 1.0; scalingOutLeft[2] = 1.0; scalingOutRight[0] = 1.0; scalingOutRight[1] = 1.0; scalingOutRight[2] = 1.0; // // Algorithm was developed using 711-2* which is these values // const float standardLeftMaxXYZ[3] = { 63.90, 62.17, 73.99 }; const float standardRightMaxXYZ[3] = { 64.72, 63.09, 73.64 }; float spaceLeftMaxXYZ[3] = { 0.0, 0.0, 0.0 }; float spaceRightMaxXYZ[3] = { 0.0, 0.0, 0.0 }; bool spaceValid = false; switch(space.getSpace()) { case StereotaxicSpace::SPACE_UNKNOWN: break; case StereotaxicSpace::SPACE_OTHER: break; case StereotaxicSpace::SPACE_AFNI_TALAIRACH: spaceLeftMaxXYZ[0] = 62.17; spaceLeftMaxXYZ[1] = 65.15; spaceLeftMaxXYZ[2] = 69.70; spaceRightMaxXYZ[0] = 63.92; spaceRightMaxXYZ[1] = 66.08; spaceRightMaxXYZ[2] = 69.86; spaceValid = true; break; case StereotaxicSpace::SPACE_FLIRT: spaceLeftMaxXYZ[0] = 64.71; spaceLeftMaxXYZ[1] = 68.34; spaceLeftMaxXYZ[2] = 77.20; spaceRightMaxXYZ[0] = 68.18; spaceRightMaxXYZ[1] = 69.42; spaceRightMaxXYZ[2] = 76.80; spaceValid = true; break; case StereotaxicSpace::SPACE_FLIRT_222: break; case StereotaxicSpace::SPACE_MACAQUE_F6: break; case StereotaxicSpace::SPACE_MACAQUE_F99: break; case StereotaxicSpace::SPACE_MRITOTAL: spaceLeftMaxXYZ[0] = 66.18; spaceLeftMaxXYZ[1] = 70.85; spaceLeftMaxXYZ[2] = 79.31; spaceRightMaxXYZ[0] = 69.96; spaceRightMaxXYZ[1] = 71.71; spaceRightMaxXYZ[2] = 78.80; spaceValid = true; break; case StereotaxicSpace::SPACE_SPM_99: spaceLeftMaxXYZ[0] = 67.72; spaceLeftMaxXYZ[1] = 70.82; spaceLeftMaxXYZ[2] = 82.64; spaceRightMaxXYZ[0] = 70.70; spaceRightMaxXYZ[1] = 71.21; spaceRightMaxXYZ[2] = 82.44; spaceValid = true; break; case StereotaxicSpace::SPACE_SPM: break; case StereotaxicSpace::SPACE_SPM_95: spaceLeftMaxXYZ[0] = 62.17; spaceLeftMaxXYZ[1] = 65.15; spaceLeftMaxXYZ[2] = 69.70; spaceRightMaxXYZ[0] = 63.92; spaceRightMaxXYZ[1] = 66.08; spaceRightMaxXYZ[2] = 69.86; spaceValid = true; break; case StereotaxicSpace::SPACE_SPM_96: spaceLeftMaxXYZ[0] = 66.18; spaceLeftMaxXYZ[1] = 70.85; spaceLeftMaxXYZ[2] = 79.31; spaceRightMaxXYZ[0] = 69.96; spaceRightMaxXYZ[1] = 71.71; spaceRightMaxXYZ[2] = 78.80; spaceValid = true; break; case StereotaxicSpace::SPACE_SPM_2: spaceLeftMaxXYZ[0] = 66.15; spaceLeftMaxXYZ[1] = 70.94; spaceLeftMaxXYZ[2] = 80.53; spaceRightMaxXYZ[0] = 70.56; spaceRightMaxXYZ[1] = 71.54; spaceRightMaxXYZ[2] = 80.20; spaceValid = true; break; case StereotaxicSpace::SPACE_SPM_5: break; case StereotaxicSpace::SPACE_T88: break; case StereotaxicSpace::SPACE_WU_7112B: case StereotaxicSpace::SPACE_WU_7112B_111: case StereotaxicSpace::SPACE_WU_7112C: case StereotaxicSpace::SPACE_WU_7112C_111: case StereotaxicSpace::SPACE_WU_7112O: case StereotaxicSpace::SPACE_WU_7112O_111: case StereotaxicSpace::SPACE_WU_7112Y: case StereotaxicSpace::SPACE_WU_7112Y_111: spaceLeftMaxXYZ[0] = 63.90; spaceLeftMaxXYZ[1] = 62.17; spaceLeftMaxXYZ[2] = 73.99; spaceRightMaxXYZ[0] = 64.72; spaceRightMaxXYZ[1] = 63.09; spaceRightMaxXYZ[2] = 73.64; spaceValid = true; break; case StereotaxicSpace::SPACE_WU_7112B_222: case StereotaxicSpace::SPACE_WU_7112B_333: case StereotaxicSpace::SPACE_WU_7112C_222: case StereotaxicSpace::SPACE_WU_7112C_333: case StereotaxicSpace::SPACE_WU_7112O_222: case StereotaxicSpace::SPACE_WU_7112O_333: case StereotaxicSpace::SPACE_WU_7112Y_222: case StereotaxicSpace::SPACE_WU_7112Y_333: break; case StereotaxicSpace::SPACE_NUMBER_OF_SPACES: break; } if (spaceValid) { for (int i = 0; i < 3; i++) { scalingOutLeft[i] = standardLeftMaxXYZ[i] / spaceLeftMaxXYZ[i]; scalingOutRight[i] = standardRightMaxXYZ[i] / spaceRightMaxXYZ[i]; } } return spaceValid; } /** * generate surface curvatures. */ void BrainModelSurfaceBorderLandmarkIdentification::generateSurfaceCurvatures() throw (BrainModelAlgorithmException) { // // Create the curvature shape file // curvatureShapeFile = new SurfaceShapeFile; // // Generate mean curvature on fiducial surface // BrainModelSurfaceCurvature fidCurve(brainSet, fiducialSurface, curvatureShapeFile, BrainModelSurfaceCurvature::CURVATURE_COLUMN_CREATE_NEW, BrainModelSurfaceCurvature::CURVATURE_COLUMN_DO_NOT_GENERATE, "Mean Curvature Fiducial", ""); fidCurve.execute(); curvatureFiducialMeanColumnNumber = curvatureShapeFile->getNumberOfColumns() - 1; // // Generate mean curvature on fiducial surface and smooth it // const QString smoothFidName("Smoothed Mean Curvature Fiducial"); curvatureShapeFile->smoothAverageNeighbors( curvatureFiducialMeanColumnNumber, -1, smoothFidName, 1.0, 5, fiducialSurface->getTopologyFile()); curvatureFiducialSmoothedMeanColumnNumber = curvatureShapeFile->getColumnWithName(smoothFidName); // // Generate mean curvature on inflated surface // BrainModelSurfaceCurvature infCurve(brainSet, inflatedSurface, curvatureShapeFile, BrainModelSurfaceCurvature::CURVATURE_COLUMN_CREATE_NEW, BrainModelSurfaceCurvature::CURVATURE_COLUMN_DO_NOT_GENERATE, "Mean Curvature Inflated", ""); infCurve.execute(); curvatureInflatedMeanColumnNumber = curvatureShapeFile->getNumberOfColumns() - 1; const QString name(debugFilesDirectoryName + "/" + curvatureShapeFile->makeDefaultFileName("LandmarkCurvatures")); try { curvatureShapeFile->writeFile(name); } catch (FileException&) { std::cout << "WARNING: Unable to write landmark curvatures file." << std::endl; } } /** * identify the cuts. */ void BrainModelSurfaceBorderLandmarkIdentification::identifyCuts() throw (BrainModelAlgorithmException) { // // Get the flatten medial wall // const BorderProjection* medialWallFlattenBorderProjection = borderProjectionFile->getFirstBorderProjectionByName(getFlattenMedialWallBorderName()); if (medialWallFlattenBorderProjection == NULL) { throw BrainModelAlgorithmException("ERROR: Unable to find border named \"" + getFlattenMedialWallBorderName() + "\" for generating cuts."); } // // Get the center of gravity of the medial wall border // float medWallCOG[3]; medialWallFlattenBorderProjection->getCenterOfGravity( fiducialSurface->getCoordinateFile(), medWallCOG); const int medialWallCogNodeNumber = fiducialSurface->getCoordinateFile()->getCoordinateIndexClosestToPoint( medWallCOG[0], medWallCOG[1], medWallCOG[2]); // // Add a color for the cuts // borderColorFile->addColor("FLATTEN.CUT", 75, 255, 75); // // Generate the cuts // identifyCutCalcarine(medialWallCogNodeNumber); identifyCutCingulate(medialWallCogNodeNumber); identifyCutFrontal(medialWallCogNodeNumber); identifyCutSylvian(medialWallCogNodeNumber); identifyCutTemporal(medialWallCogNodeNumber); } /** * identify the cut calcarine. */ void BrainModelSurfaceBorderLandmarkIdentification::identifyCutCalcarine(const int medialWallCogNodeNumber) throw (BrainModelAlgorithmException) { flattenCutCalcarineName = getFlattenStandardCutsBorderNamePrefix() + "Calcarine"; const BrainModelSurface* surface = veryInflatedSurface; const CoordinateFile* coordFile = surface->getCoordinateFile(); // // Remove any existing cuts // borderProjectionFile->removeBordersWithName(flattenCutCalcarineName); // // Get the calcarine landmark // const BorderProjection* calcarineLandmark = borderProjectionFile->getFirstBorderProjectionByName(calcarineSulcusLandmarkName); if (calcarineLandmark == NULL) { throw BrainModelAlgorithmException("ERROR: Unable to find border named \"" + calcarineSulcusLandmarkName + "\" for generating cuts."); } BorderProjection calcarineCut(*calcarineLandmark); calcarineCut.setName(flattenCutCalcarineName); // // Get node number of first link in calcarine // const BorderProjectionLink* firstCalcarineLink = calcarineLandmark->getBorderProjectionLink(0); float firstCalcarineLinkXYZ[3]; firstCalcarineLink->unprojectLink(coordFile, firstCalcarineLinkXYZ); const int firstCalcarineLinkNodeNumber = coordFile->getCoordinateIndexClosestToPoint(firstCalcarineLinkXYZ); // // Get node number of last link in calcarine // const BorderProjectionLink* lastCalcarineLink = calcarineLandmark->getBorderProjectionLink(calcarineLandmark->getNumberOfLinks() - 1); float lastCalcarineLinkXYZ[3]; lastCalcarineLink->unprojectLink(coordFile, lastCalcarineLinkXYZ); const int lastCalcarineLinkNodeNumber = coordFile->getCoordinateIndexClosestToPoint(lastCalcarineLinkXYZ); // // Get node number that is 15mm lateral of the occipital pole // const float* occPoleXYZ = inflatedSurface->getCoordinateFile()->getCoordinate(calcarinePosteriorExtremeNodeNumber); float occPole15LateralXYZ[3] = { occPoleXYZ[0], occPoleXYZ[1], occPoleXYZ[2] }; occPole15LateralXYZ[0] = (leftHemisphereFlag ? -15.0 : 15.0); const int occPoleOffsetNodeNumber = inflatedSurface->getCoordinateFile()->getCoordinateIndexClosestToPoint( occPole15LateralXYZ); // medialWallCogNodeNumber); // // Draw border from the node lateral to occiptial pole to the occipital pole // const QString calcarineSegment0("CalcarineSegment0"); drawBorderGeodesic(surface, NULL, calcarineSegment0, occPoleOffsetNodeNumber, calcarinePosteriorExtremeNodeNumber, 2.0); // // Draw from occipital pole to first link in calcarine // const QString calcarineSegment1("CalcarineSegment1"); drawBorderGeodesic(surface, NULL, calcarineSegment1, calcarinePosteriorExtremeNodeNumber, firstCalcarineLinkNodeNumber, 2.0); // // Draw from last link in calcarine to medial wall COG // const QString calcarineSegment2("CalcarineSegment2"); drawBorderGeodesic(surface, NULL, calcarineSegment2, lastCalcarineLinkNodeNumber, medialWallCogNodeNumber, 2.0); // // Merge to create the calcarine cut // std::vector borderNames; borderNames.push_back(calcarineSegment0); borderNames.push_back(calcarineSegment1); borderNames.push_back(calcarineSulcusLandmarkName); borderNames.push_back(calcarineSegment2); mergeBorders(flattenCutCalcarineName, borderNames, false, false, surface, 0, 0); // // Remove segments // borderProjectionFile->removeBordersWithName(calcarineSegment0); borderProjectionFile->removeBordersWithName(calcarineSegment1); borderProjectionFile->removeBordersWithName(calcarineSegment2); // // Resample // resampleBorder(fiducialSurface, flattenCutCalcarineName, 2.0, false); } /** * identify the cut cingulate. */ void BrainModelSurfaceBorderLandmarkIdentification::identifyCutCingulate(const int medialWallCogNodeNumber) throw (BrainModelAlgorithmException) { const QString flattenCutCingulateName(getFlattenStandardCutsBorderNamePrefix() + "Cingulate"); // // Remove any existing cuts // borderProjectionFile->removeBordersWithName(flattenCutCingulateName); // // Draw from medial wall cog to tip of central sulcus // drawBorderGeodesic(inflatedSurface, NULL, flattenCutCingulateName, medialWallCogNodeNumber, cesMedialNodeNumber, 2.0); } /** * identify the cut frontal. */ void BrainModelSurfaceBorderLandmarkIdentification::identifyCutFrontal(const int medialWallCogNodeNumber) throw (BrainModelAlgorithmException) { flattenCutFrontalName = getFlattenStandardCutsBorderNamePrefix() + "Frontal"; // // Remove any existing cuts // borderProjectionFile->removeBordersWithName(flattenCutFrontalName); // // Default for middle point at approximate anterior of orbital sulcus // const float defaultMiddlePointXYZ[3] = { (leftHemisphereFlag ? -22.0 : 22.0), 46.0 -6.0 }; int middleNodeNumber = fiducialSurface->getCoordinateFile()->getCoordinateIndexClosestToPoint( defaultMiddlePointXYZ); // // Create an ROI of the orbital/olfactory sulcus where cut should pass through // BrainModelSurfaceROINodeSelection oribitalSulcusROI(brainSet); QString errorMessageORBS = oribitalSulcusROI.selectNodesWithPaint( BrainModelSurfaceROINodeSelection::SELECTION_LOGIC_NORMAL, fiducialSurface, paintFile, paintFileSulcusIdColumnNumber, "SUL.OrbS"); BrainModelSurfaceROINodeSelection transversOrbitalSulcusROI(brainSet); QString errorMessageTORBS = transversOrbitalSulcusROI.selectNodesWithPaint( BrainModelSurfaceROINodeSelection::SELECTION_LOGIC_NORMAL, fiducialSurface, paintFile, paintFileSulcusIdColumnNumber, "SUL.TOrbS"); //if ((errorMessageORBS.isEmpty() == false) && // (errorMessageTORBS.isEmpty() == false)) { // throw BrainModelAlgorithmException(errorMessageORBS + "\n" + errorMessageTORBS); //} if (oribitalSulcusROI.getNumberOfNodesSelected() > 0) { middleNodeNumber = oribitalSulcusROI.getNodeWithMaximumYCoordinate(fiducialSurface); } else if (transversOrbitalSulcusROI.getNumberOfNodesSelected() > 0) { middleNodeNumber = transversOrbitalSulcusROI.getNodeWithMaximumYCoordinate(fiducialSurface); } else { std::cout << "INFO: Using approximate location for frontal cut since " << "SUL.OrbS and SUL.TOrbS could not be found." << std::endl; } // // Default for endpoint // const float defaultEndPointXYZ[3] = { (leftHemisphereFlag ? -53.0: 53.0), 21.0, 19.0 }; int endNodeNumber = fiducialSurface->getCoordinateFile()->getCoordinateIndexClosestToPoint( defaultEndPointXYZ); // // Create an ROI of the inferior frontal sulcus where cut should end // BrainModelSurfaceROINodeSelection inferiorFrontalSulcusROI(brainSet); QString errorMessage; errorMessage = inferiorFrontalSulcusROI.selectNodesWithPaint( BrainModelSurfaceROINodeSelection::SELECTION_LOGIC_NORMAL, fiducialSurface, paintFile, paintFileSulcusIdColumnNumber, "SUL.IFS"); if (errorMessage.isEmpty() == false) { throw BrainModelAlgorithmException(errorMessage); } if (inferiorFrontalSulcusROI.getNumberOfNodesSelected() > 0) { endNodeNumber = inferiorFrontalSulcusROI.getNodeWithMinimumYCoordinate(fiducialSurface); } // // Draw border from medial wall COG to node at front/ventral part of SF // const QString frontalSegment0("FrontalSegment0"); drawBorderGeodesic(fiducialSurface, NULL, frontalSegment0, medialWallCogNodeNumber, sfVentralFrontalNodeNumber, 2.0); // // Draw border from front/ventral part of SF to the middle point in OrbS // const QString frontalSegment1("FrontalSegment1"); drawBorderGeodesic(fiducialSurface, NULL, frontalSegment1, sfVentralFrontalNodeNumber, middleNodeNumber, 2.0); // // Draw border from middle point in OrbS to the end point // const QString frontalSegment2("FrontalSegment2"); drawBorderGeodesic(fiducialSurface, NULL, frontalSegment2, middleNodeNumber, endNodeNumber, 2.0); // // Merge to create the frontal cut // std::vector borderNames; borderNames.push_back(frontalSegment0); borderNames.push_back(frontalSegment1); borderNames.push_back(frontalSegment2); mergeBorders(flattenCutFrontalName, borderNames, true, false, fiducialSurface, 0, 0); // // Resample // resampleBorder(fiducialSurface, flattenCutFrontalName, 2.0); } /** * identify the cut sylvian. */ void BrainModelSurfaceBorderLandmarkIdentification::identifyCutSylvian(const int medialWallCogNodeNumber) throw (BrainModelAlgorithmException) { const QString flattenCutSylvianName(getFlattenStandardCutsBorderNamePrefix() + "Sylvian"); // // Remove any existing cuts // borderProjectionFile->removeBordersWithName(flattenCutSylvianName); // // Draw from medial wall cog to tip of central sulcus // drawBorderGeodesic(inflatedSurface, NULL, flattenCutSylvianName, medialWallCogNodeNumber, sfInferiorBranchBeginNodeNumber, 2.0); } /** * identify the cut temporal. */ void BrainModelSurfaceBorderLandmarkIdentification::identifyCutTemporal(const int medialWallCogNodeNumber) throw (BrainModelAlgorithmException) { const QString flattenCutTemporalName(getFlattenStandardCutsBorderNamePrefix() + "Temporal"); // // Remove any existing cuts // borderProjectionFile->removeBordersWithName(flattenCutTemporalName); // // Get most inferior node in surface which should be in the ventral // part of the temporal lobe // BrainModelSurfaceROINodeSelection fiducialROI(brainSet); fiducialROI.selectAllNodes(fiducialSurface); const int mostInferiorNodeNumber = fiducialROI.getNodeWithMinimumZCoordinate(fiducialSurface); // // End point for temporal cut // const float endPointXYZ[3] = { (leftHemisphereFlag ? -60.0 : 60.0), -25.0, -28.0 }; const int endPointNodeNumber = fiducialSurface->getCoordinateFile()->getCoordinateIndexClosestToPoint( endPointXYZ); // // Draw border from Medial Wall COG to inferior temporal lobe // const QString temporalSegment1("TemporalSegment1"); drawBorderGeodesic(fiducialSurface, NULL, temporalSegment1, medialWallCogNodeNumber, mostInferiorNodeNumber, 2.0); // // Draw border from middle point in OrbS to the end point // const QString temporalSegment2("TemporalSegment2"); drawBorderGeodesic(fiducialSurface, NULL, temporalSegment2, mostInferiorNodeNumber, endPointNodeNumber, 2.0); // // Merge to create the temporal cut // std::vector borderNames; borderNames.push_back(temporalSegment1); borderNames.push_back(temporalSegment2); mergeBorders(flattenCutTemporalName, borderNames, true, false, fiducialSurface, 0, 0); // // Resample // resampleBorder(fiducialSurface, flattenCutTemporalName, 2.0); } /** * generate paint identification of sulci. */ void BrainModelSurfaceBorderLandmarkIdentification::paintSulcalIdentification() throw (BrainModelAlgorithmException) { // // Generate the probabilistic identification // BrainModelSurfacePaintSulcalIdentification sid(brainSet, fiducialSurface, inflatedSurface, veryInflatedSurface, paintFile, paintFileGeographyColumnNumber, areaColorFile, depthSurfaceShapeFile, depthSurfaceShapeFileColumnNumber, vocabularyFile); sid.execute(); // // Get the Sulcus ID paint column // paintFileSulcusIdColumnName = BrainModelSurfacePaintSulcalIdentification::getSulcusIdPaintColumnName(); paintFileSulcusIdColumnNumber = paintFile->getColumnWithName(paintFileSulcusIdColumnName); if (paintFileSulcusIdColumnNumber < 0) { throw BrainModelAlgorithmException("Unable to find paint column named \"" + BrainModelSurfacePaintSulcalIdentification::getSulcusIdPaintColumnName() + "\" in the paint file after identifying sulci."); } // // Get the output files of the probabilistic identification // metricFile = new MetricFile(*sid.getMetricFile()); } /** * identify the central sulcus. */ void BrainModelSurfaceBorderLandmarkIdentification::identifyCentralSulcus() throw (BrainModelAlgorithmException) { // // Name for ROI file // const QString cesRoiFileName(createFileName("CeS", SpecFile::getRegionOfInterestFileExtension())); const QString cesRoiStringentFileName(createFileName("CeS_Stringent", SpecFile::getRegionOfInterestFileExtension())); // // Remove any prexisting files // //rm Human.$SUBJECT.$HEM.CeS*.roi QFile::remove(cesRoiFileName); QFile::remove(cesRoiStringentFileName); // // Name for central sulcus // const QString centralSulcusLandmarkName(getCentralSulcusRegistrationLandmarkName()); const QString cesMedialFocusName("CeS-medial"); const QString cesVentralFocusName("CeS-ventral"); const QString cesMedialLandmarkFocusName("CeS-medial-Landmark"); const QString cesVentralLandmarkFocusName("CeS-ventral-Landmark"); const QString cesVentralExtremeFocusName("CeS-VentralExtreme"); const QString cesMedialExtremeFocusName("CeS-MedialExtreme"); // // Cleanup foci // //caret_command -surface-foci-delete // $OUTFOCIPROJ $OUTFOCIPROJ CeS-medial CeS-ventral CeS-medial-Landmark // CeS-ventral-Landmark CeS-VentralExtreme CeS-MedialExtreme // fociProjectionFile->deleteCellProjectionsWithName(cesMedialFocusName); fociProjectionFile->deleteCellProjectionsWithName(cesVentralFocusName); fociProjectionFile->deleteCellProjectionsWithName(cesMedialLandmarkFocusName); fociProjectionFile->deleteCellProjectionsWithName(cesVentralLandmarkFocusName); fociProjectionFile->deleteCellProjectionsWithName(cesVentralExtremeFocusName); fociProjectionFile->deleteCellProjectionsWithName(cesMedialExtremeFocusName); // // Add foci colors // //caret_command -color-file-add-color // $FOCICOLOR $FOCICOLOR CeS-medial 255 0 0 -point-size 3 -symbol SPHERE //caret_command -color-file-add-color // $FOCICOLOR $FOCICOLOR CeS-ventral 0 255 0 -point-size 3 -symbol SPHERE //caret_command -color-file-add-color // $FOCICOLOR $FOCICOLOR CeS-MedialExtreme 255 0 0 -point-size 3 -symbol SPHERE //caret_command -color-file-add-color // $FOCICOLOR $FOCICOLOR CeS-VentralExtreme 0 255 0 -point-size 3 -symbol SPHERE // addFocusColor(cesMedialFocusName, 255, 0, 0); addFocusColor(cesVentralFocusName, 0, 255, 0); addFocusColor(cesMedialLandmarkFocusName, 255, 0, 0); addFocusColor(cesVentralLandmarkFocusName, 0, 255, 0); addFocusColor(cesVentralExtremeFocusName, 0, 255, 0); addFocusColor(cesMedialExtremeFocusName, 255, 0, 0); // // Add border colors // //caret_command -color-file-add-color // $BORDERCOLOR $BORDERCOLOR LANDMARK.CentralSulcus 255 255 0 // borderColorFile->addColor(centralSulcusLandmarkName, 255, 255, 0); // // Remove any existing central sulcus landmark from border file // //caret_command -surface-border-delete // $OUTBORDERPROJ $OUTBORDERPROJ LANDMARK.CentralSulcus // borderProjectionFile->removeBordersWithName(centralSulcusLandmarkName); // // Select nodes in the CeS that have fiducial curvture between // -100.0 and -0.10. // //caret_command -surface-region-of-interest-selection // $INFLATED $TOPO Human.$SUBJECT.$HEM.CeS.roi Human.$SUBJECT.$HEM.CeS.roi // -paint Human.$SUBJECT.$HEM.SulcalID.paint "Sulcus ID" SUL.CeS NORMAL // -shape $SHAPE_OUT "Folding (Mean Curvature)" -100.0 -0.10 AND // BrainModelSurfaceROINodeSelection cesROI(brainSet); QString errorMessage = cesROI.selectNodesWithPaint( BrainModelSurfaceROINodeSelection::SELECTION_LOGIC_NORMAL, inflatedSurface, paintFile, paintFileSulcusIdColumnNumber, "SUL.CeS"); if (errorMessage.isEmpty() == false) { throw BrainModelAlgorithmException(errorMessage); } errorMessage = cesROI.selectNodesWithSurfaceShape( BrainModelSurfaceROINodeSelection::SELECTION_LOGIC_AND, inflatedSurface, curvatureShapeFile, curvatureFiducialMeanColumnNumber, -100.0, -0.10); if (errorMessage.isEmpty() == false) { throw BrainModelAlgorithmException(errorMessage); } saveRoiToFile(cesROI, cesRoiFileName); // // Get nodes at min/max geometric values of the ROI // int minXNode, maxXNode, minYNode, maxYNode, minZNode, maxZNode; int mostMedialXNode, mostLateralXNode; int absMinXNode, absMaxXNode, absMinYNode, absMaxYNode, absMinZNode, absMaxZNode; cesROI.getNodesWithMinMaxXYZValues(inflatedSurface, mostMedialXNode, mostLateralXNode, minXNode, maxXNode, minYNode, maxYNode, minZNode, maxZNode, absMinXNode, absMaxXNode, absMinYNode, absMaxYNode, absMinZNode, absMaxZNode); // // Add foci at medial and ventral extent of central sulcus // //caret_command -surface-place-foci-at-limits // $FIDUCIAL $INFLATED $TOPO Human.$SUBJECT.$HEM.CeS.roi // $OUTFOCIPROJ $OUTFOCIPROJ -z-min CeS-ventral -x-most-medial CeS-medial // const int cesVentralNodeNumber = minZNode; addFocusAtNode(cesVentralFocusName, cesVentralNodeNumber); inflatedSurface->getCoordinateFile()->getCoordinate(cesVentralNodeNumber, inflatedSurfaceCentralSulcusVentralTipXYZ); cesMedialNodeNumber = mostMedialXNode; addFocusAtNode(cesMedialFocusName, cesMedialNodeNumber); if (DebugControl::getDebugOn()) { std::cout << "CeS Landmark Medial Node Number: " << cesMedialNodeNumber << std::endl; std::cout << "CeS Landmark Ventral Node Number: " << cesVentralNodeNumber << std::endl; } // // Select nodes in the central sulcus with fiducial curvature // between -100.0 and -0.16. If necessary, dilate the ROI so // that it includes the most ventral and medial nodes in the CeS. // //caret_command -surface-region-of-interest-selection // $INFLATED $TOPO Human.$SUBJECT.$HEM.CeS_Stringent.roi // Human.$SUBJECT.$HEM.CeS_Stringent.roi // -paint Human.$SUBJECT.$HEM.SulcalID.paint "Sulcus ID" SUL.CeS NORMAL // -shape $SHAPE_OUT "Folding (Mean Curvature)" -100.0 -0.16 AND // BrainModelSurfaceROINodeSelection cesStringentROI(brainSet); errorMessage = cesStringentROI.selectNodesWithPaint( BrainModelSurfaceROINodeSelection::SELECTION_LOGIC_NORMAL, inflatedSurface, paintFile, paintFileSulcusIdColumnNumber, "SUL.CeS"); if (errorMessage.isEmpty() == false) { throw BrainModelAlgorithmException(errorMessage); } errorMessage = cesStringentROI.selectNodesWithSurfaceShape( BrainModelSurfaceROINodeSelection::SELECTION_LOGIC_AND, inflatedSurface, curvatureShapeFile, curvatureFiducialMeanColumnNumber, -100.0, -0.16); saveRoiToFile(cesStringentROI, cesRoiStringentFileName); if (errorMessage.isEmpty() == false) { throw BrainModelAlgorithmException(errorMessage); } // // Draw a border using the geodesic method between the most // medial and ventral nodes in the ROI. // //caret_command -surface-border-draw-geodesic // $INFLATED $TOPO $OUTFOCIPROJ CeS-ventral CeS-medial // Human.$SUBJECT.$HEM.CeS_Stringent.roi $OUTBORDERPROJ $OUTBORDERPROJ // LANDMARK.CentralSulcus 1.0 // drawBorderGeodesic(inflatedSurface, &cesStringentROI, centralSulcusLandmarkName, cesVentralNodeNumber, cesMedialNodeNumber, 1.0); // // Starting at the ventral node of the CeS, move down along // surface links limiting the Y movement. This will result // in the focus directly below the CeS on the edge of the // sylvian fissure. // //caret_command -surface-place-focus-at-extremum // $FIDUCIAL $INFLATED $TOPO $OUTFOCIPROJ CeS-ventral // $OUTFOCIPROJ CeS-VentralExtreme Z-NEG 100000.0 3.0 100000.0 // const int cesVentralExtremeNodeNumber = addFocusAtExtremum(inflatedSurface, cesVentralNodeNumber, BrainModelSurfaceFindExtremum::DIRECTION_Z_NEGATIVE, 100000.0, 3.0, 100000.0, cesVentralExtremeFocusName); // // Starting at the dorsal node of the CeS, move up along // surface links limiting the Y movement. This will result // in the focus at the most dorsal position above the CeS. // //caret_command -surface-place-focus-at-extremum // $FIDUCIAL $INFLATED $TOPO $OUTFOCIPROJ CeS-medial // $OUTFOCIPROJ CeS-MedialExtreme X-MEDIAL 100000.0 5.0 100000.0 // const int cesMedialExtremeNodeNumber = addFocusAtExtremum(inflatedSurface, cesMedialNodeNumber, BrainModelSurfaceFindExtremum::DIRECTION_MEDIAL, 100000.0, 5.0, 100000.0, cesMedialExtremeFocusName); // // Trim the ventral end of the CeS landmark, remove any links that // are near the sylvian fissure // //caret_command -surface-border-nibbler // $INFLATED $TOPO $OUTBORDERPROJ $OUTBORDERPROJ LANDMARK.CentralSulcus // LANDMARK.CentralSulcus $OUTFOCIPROJ CeS-VentralExtreme -within-z-distance 19 // nibbleBorderWithinDistance(inflatedSurface, centralSulcusLandmarkName, cesVentralExtremeNodeNumber, BORDER_NIBBLE_MODE_DISTANCE_Z, 19.0); // // Trim the dorsal end of the CeS landmark, removing any links that // are near the most dorsal part of the surface. // //caret_command -surface-border-nibbler // $INFLATED $TOPO $OUTBORDERPROJ $OUTBORDERPROJ LANDMARK.CentralSulcus // LANDMARK.CentralSulcus $OUTFOCIPROJ CeS-MedialExtreme -within-x-distance 18 // nibbleBorderWithinDistance(inflatedSurface, centralSulcusLandmarkName, cesMedialExtremeNodeNumber, BORDER_NIBBLE_MODE_DISTANCE_X, 18.0); // //caret_command -surface-border-link-to-focus // $FIDUCIAL $TOPO $OUTBORDERPROJ LANDMARK.CentralSulcus // $OUTFOCIPROJ $OUTFOCIPROJ -first-link CeS-medial-Landmark // // //caret_command -surface-border-link-to-focus // $FIDUCIAL $TOPO $OUTBORDERPROJ LANDMARK.CentralSulcus // $OUTFOCIPROJ $OUTFOCIPROJ -last-link CeS-ventral-Landmark // } /** * draw a border using metric method. */ void BrainModelSurfaceBorderLandmarkIdentification::drawBorderMetric( const BrainModelSurface* borderSurface, const BrainModelSurfaceROICreateBorderUsingMetricShape::MODE drawMode, const MetricFile* metricShapeFile, const int metricShapeFileColumn, const QString borderName, const int startNodeNumber, const int endNodeNumber, const float samplingDistance, const BrainModelSurfaceROINodeSelection* optionalROI) throw (BrainModelAlgorithmException) { BrainModelSurfaceROINodeSelection roi(brainSet); if (optionalROI != NULL) { roi = *optionalROI; } else { roi.selectAllNodes(borderSurface); } // // Force the starting and ending nodes to be in the ROI and connected // roi.expandSoNodesAreWithinAndConnected(borderSurface, startNodeNumber, endNodeNumber); Border border; int counter = 0; while (true) { BrainModelSurfaceROICreateBorderUsingMetricShape metricDraw(brainSet, (BrainModelSurface*)borderSurface, &roi, drawMode, metricShapeFile, metricShapeFileColumn, borderName, startNodeNumber, endNodeNumber, samplingDistance); try { metricDraw.execute(); border = metricDraw.getBorder(); if (border.getNumberOfLinks() <= 0) { throw BrainModelAlgorithmException("Metric/Shape drawing of border named \"" + borderName + "\" failed."); } break; } catch (BrainModelAlgorithmException& e) { if (counter < 3) { roi.dilate(borderSurface, 1); } else { throw e; } counter++; } } // // Project the border and add to border projection file // BorderFile borderFile; borderFile.addBorder(border); BorderProjectionFile bpf; BorderFileProjector projector(borderSurface, true); projector.projectBorderFile(&borderFile, &bpf, NULL); borderProjectionFile->append(bpf); const QString name(debugFilesDirectoryName + "/" + borderDebugFileName); try { borderProjectionFile->writeFile(name); } catch (FileException&) { std::cout << "WARNING: Unable to write landmark debug border projection file." << std::endl; } } /** * draw a border using geodesic method connecting a group of nodes. */ void BrainModelSurfaceBorderLandmarkIdentification::drawBorderGeodesic( const BrainModelSurface* borderSurface, const BrainModelSurfaceROINodeSelection* roiIn, const QString borderName, const std::vector& nodeNumbers, const float samplingDistance) throw (BrainModelAlgorithmException) { Border border(borderName); const int numToDraw = static_cast(nodeNumbers.size()) - 1; for (int i = 0; i < numToDraw; i++) { BrainModelSurfaceROINodeSelection roi(brainSet); if (roiIn != NULL) { roi = *roiIn; } else { roi.selectAllNodes(borderSurface); } // // Force the starting and ending nodes to be in the ROI and connected // const int startNodeNumber = nodeNumbers[i]; const int endNodeNumber = nodeNumbers[i + 1]; if (DebugControl::getDebugOn()) { std::cout << "Connecting node " << startNodeNumber << " to node " << endNodeNumber << std::endl; } roi.expandSoNodesAreWithinAndConnected(borderSurface, startNodeNumber, endNodeNumber); BrainModelSurfaceROICreateBorderUsingGeodesic cesDraw(brainSet, (BrainModelSurface*)borderSurface, &roi, borderName, startNodeNumber, endNodeNumber, samplingDistance); cesDraw.execute(); Border newSegment = cesDraw.getBorder(); if (newSegment.getNumberOfLinks() <= 0) { throw BrainModelAlgorithmException("Geodesic drawing of border named \"" + borderName + "\" segment " + QString::number(i) + " failed."); } // // Project the border and add to border projection file // border.appendBorder(newSegment); } // // Project the border and add to border projection file // BorderFile borderFile; borderFile.addBorder(border); BorderProjectionFile bpf; BorderFileProjector projector(borderSurface, true); projector.projectBorderFile(&borderFile, &bpf, NULL); borderProjectionFile->append(bpf); const QString name(debugFilesDirectoryName + "/" + borderDebugFileName); try { borderProjectionFile->writeFile(name); } catch (FileException&) { std::cout << "WARNING: Unable to write landmark debug border projection file." << std::endl; } } /** * draw a border using heuristic geodesic method connecting a group of nodes. */ void BrainModelSurfaceBorderLandmarkIdentification::drawBorderTargetedGeodesic( const BrainModelSurface* borderSurface, const BrainModelSurfaceROINodeSelection* roiIn, const QString borderName, const std::vector& nodeNumbers, const float samplingDistance, float target[3], float targetweight) throw (BrainModelAlgorithmException) { Border border(borderName); const int numToDraw = static_cast(nodeNumbers.size()) - 1; for (int i = 0; i < numToDraw; i++) { BrainModelSurfaceROINodeSelection roi(brainSet); if (roiIn != NULL) { roi = *roiIn; } else { roi.selectAllNodes(borderSurface); } // // Force the starting and ending nodes to be in the ROI and connected // int startNodeNumber = nodeNumbers[i]; int endNodeNumber = nodeNumbers[i + 1]; if (DebugControl::getDebugOn()) { std::cout << "Connecting node " << startNodeNumber << " to node " << endNodeNumber << std::endl; } roi.expandSoNodesAreWithinAndConnected(borderSurface, startNodeNumber, endNodeNumber); Border newSegment = drawHeuristic(borderSurface, &roi, startNodeNumber, endNodeNumber, target, targetweight); if (newSegment.getNumberOfLinks() <= 0) { throw BrainModelAlgorithmException("Geodesic heuristic drawing of border named \"" + borderName + "\" segment " + QString::number(i) + " failed."); } // // Project the border and add to border projection file // border.appendBorder(newSegment); } int dummyUnused; border.resampleBorderToDensity(samplingDistance, 2, dummyUnused); // // Project the border and add to border projection file // BorderFile borderFile; borderFile.addBorder(border); BorderProjectionFile bpf; BorderFileProjector projector(borderSurface, true); projector.projectBorderFile(&borderFile, &bpf, NULL); borderProjectionFile->append(bpf); const QString name(debugFilesDirectoryName + "/" + borderDebugFileName); try { borderProjectionFile->writeFile(name); } catch (FileException&) { std::cout << "WARNING: Unable to write landmark debug border projection file." << std::endl; } } /** * draw a border using heuristic geodesic method connecting a group of nodes. */ void BrainModelSurfaceBorderLandmarkIdentification::drawBorderMetricGeodesic( const BrainModelSurface* borderSurface, const BrainModelSurfaceROINodeSelection* roiIn, const QString borderName, const std::vector& nodeNumbers, const float samplingDistance, MetricFile* nodeCost, int metricColumn, float metricWeight) throw (BrainModelAlgorithmException) { Border border(borderName); const int numToDraw = static_cast(nodeNumbers.size()) - 1; for (int i = 0; i < numToDraw; i++) { BrainModelSurfaceROINodeSelection roi(brainSet); if (roiIn != NULL) { roi = *roiIn; } else { roi.selectAllNodes(borderSurface); } // // Force the starting and ending nodes to be in the ROI and connected // int startNodeNumber = nodeNumbers[i]; int endNodeNumber = nodeNumbers[i + 1]; if (DebugControl::getDebugOn()) { std::cout << "Connecting node " << startNodeNumber << " to node " << endNodeNumber << std::endl; } roi.expandSoNodesAreWithinAndConnected(borderSurface, startNodeNumber, endNodeNumber); Border newSegment = drawHeuristic(borderSurface, &roi, startNodeNumber, endNodeNumber, nodeCost, metricColumn, metricWeight); if (newSegment.getNumberOfLinks() <= 0) { throw BrainModelAlgorithmException("Geodesic heuristic drawing of border named \"" + borderName + "\" segment " + QString::number(i) + " failed."); } // // Project the border and add to border projection file // border.appendBorder(newSegment); } int dummyUnused; border.resampleBorderToDensity(samplingDistance, 2, dummyUnused); // // Project the border and add to border projection file // BorderFile borderFile; borderFile.addBorder(border); BorderProjectionFile bpf; BorderFileProjector projector(borderSurface, true); projector.projectBorderFile(&borderFile, &bpf, NULL); borderProjectionFile->append(bpf); const QString name(debugFilesDirectoryName + "/" + borderDebugFileName); try { borderProjectionFile->writeFile(name); } catch (FileException) { std::cout << "WARNING: Unable to write landmark debug border projection file." << std::endl; } } Border BrainModelSurfaceBorderLandmarkIdentification::drawHeuristic(const BrainModelSurface* borderSurface, BrainModelSurfaceROINodeSelection* roi, int startNodeNumber, int endNodeNumber, float target[], float targetweight) throw (BrainModelAlgorithmException) { std::list startQ; std::list::iterator iter, myend; int numVert = borderSurface->getNumberOfNodes(), i, j; searchNode** closedList = new searchNode*[numVert], *tempn, *tempn2 = NULL; for (i = 0; i < numVert; ++i) { closedList[i] = NULL; } const TopologyHelper* th = borderSurface->getTopologyFile()->getTopologyHelper(false, true, false);//only need neighbors const CoordinateFile* cf = borderSurface->getCoordinateFile(); std::vector neighbors; float startxyz[3], endxyz[3], tempxyz[3], tempxyz2[3], tempf = 0.0f, tempf2, tempf3, targoff; cf->getCoordinate(startNodeNumber, startxyz); cf->getCoordinate(endNodeNumber, endxyz); tempf3 = 0.0f; for (j = 0; j < 3; ++j) { tempf2 = target[j] - startxyz[j]; tempf3 += tempf2 * tempf2; } targoff = sqrtf(tempf3); tempf3 = 0.0f; for (j = 0; j < 3; ++j) { tempf2 = target[j] - endxyz[j]; tempf3 += tempf2 * tempf2; } targoff += sqrtf(tempf3); targoff /= 2.0f;//used to adjust the target following term to an optimal range, avoiding overflow with heavy weighting for (i = 0; i < 3; ++i) { tempf2 = (startxyz[i] - endxyz[i]); tempf += tempf2 * tempf2; } tempf = sqrtf(tempf);//used to calculate heuristic, if i find one tempn = new searchNode(); tempn->cost = 0.0f; tempn->heur = 0.0f; tempn->node = startNodeNumber; tempn->prev = -1; closedList[startNodeNumber] = tempn; startQ.push_front(tempn); bool found = false; iter = startQ.begin(); //std::cout << "start: " << startNodeNumber << " end: " << endNodeNumber << endl; //std::cout << "starting main loop" << endl; while (!startQ.empty() && !found) { tempn2 = *(startQ.begin()); if (tempn2->node == endNodeNumber) { found = true; break; } if (iter == startQ.begin()) ++iter; startQ.pop_front(); th->getNodeNeighbors(tempn2->node, neighbors); cf->getCoordinate(tempn2->node, tempxyz2); for (i = 0; i < (int)neighbors.size(); ++i) { if (!roi->getNodeSelected(neighbors[i])) continue; tempn = new searchNode(); tempn->node = neighbors[i]; tempn->prev = tempn2->node; cf->getCoordinate(neighbors[i], tempxyz); tempf = 0.0f; for (j = 0; j < 3; ++j) { tempf2 = tempxyz2[j] - tempxyz[j]; tempf += tempf2 * tempf2; } tempf = sqrtf(tempf); tempf3 = 0.0f; for (j = 0; j < 3; ++j) { tempf2 = target[j] - tempxyz[j]; tempf3 += tempf2 * tempf2; } tempf3 = sqrtf(tempf3); tempn->cost = tempn2->cost + tempf * pow(targetweight, tempf3 - targoff); tempf = 0.0f; for (j = 0; j < 3; ++j) { tempf2 = endxyz[j] - tempxyz[j]; tempf += tempf2 * tempf2; } tempf = sqrtf(tempf); tempn->heur = tempn->cost;//so its actually f, not h, but this is faster. Add a heuristic when you can think of an admissible one. if (closedList[neighbors[i]]) { if (closedList[neighbors[i]]->heur > tempn->heur) { closedList[neighbors[i]]->heur = tempn->heur; closedList[neighbors[i]]->cost = tempn->cost; closedList[neighbors[i]]->node = tempn->node; closedList[neighbors[i]]->prev = tempn->prev; delete tempn; tempn = closedList[neighbors[i]]; for (myend = startQ.begin(); myend != startQ.end(); ++myend) { if (*myend == tempn) { if (iter == myend) { if (iter == startQ.begin()) ++iter; else --iter; } startQ.erase(myend); break; } } } else { delete tempn; tempn = NULL; } } if (tempn) { if (iter == startQ.end() || (*iter)->heur > tempn->heur) { if (iter != startQ.begin()) { for (--iter; iter != startQ.begin() && (*iter)->heur > tempn->heur; --iter); if ((*iter)->heur <= tempn->heur) ++iter; } } else { for (++iter; iter != startQ.end() && (*iter)->heur <= tempn->heur; ++iter); } closedList[neighbors[i]] = tempn; startQ.insert(iter, tempn); myend = startQ.end(); --myend; for (iter = startQ.begin(); iter != myend;) { if ((*iter)->heur > (*(++iter))->heur) { cout << "."; } } } } } if (startQ.empty()) { throw BrainModelAlgorithmException("drawHeuristic() failed to connect the endpoints with the given ROI."); } //std::cout << "loop done" << endl; std::list startOrder;//build first half of border by backtracking i = tempn2->node; while (i != -1) { //std::cout << i << endl; startOrder.push_front(i); i = closedList[i]->prev; } //cout << startOrder.size() << " nodes in piece" << endl; Border ret; for (std::list::iterator myiter = startOrder.begin(); myiter != startOrder.end(); ++myiter) { cf->getCoordinate(*myiter, tempxyz); ret.addBorderLink(tempxyz); } for (i = 0; i < numVert; ++i) { if (closedList[i]) delete closedList[i]; } delete[] closedList; //int junk; //ret.resampleBorderToDensity(samplingDistance, 2, junk); return ret; } Border BrainModelSurfaceBorderLandmarkIdentification::drawHeuristic(const BrainModelSurface* borderSurface, BrainModelSurfaceROINodeSelection* roi, int startNodeNumber, int endNodeNumber, MetricFile* nodeCost, int metricColumn, float metricWeight) throw (BrainModelAlgorithmException) { std::list startQ; std::list::iterator iter, myend; int numVert = borderSurface->getNumberOfNodes(), i, j; if (numVert > nodeCost->getNumberOfNodes()) { throw BrainModelAlgorithmException("Number of nodes in surface exceeds number of nodes in metric."); } if (metricColumn >= nodeCost->getNumberOfColumns()) { throw BrainModelAlgorithmException("Metric column number exceeds number of columns in metric."); } searchNode** closedList = new searchNode*[numVert], *tempn, *tempn2 = NULL; for (i = 0; i < numVert; ++i) { closedList[i] = NULL; } const TopologyHelper* th = borderSurface->getTopologyFile()->getTopologyHelper(false, true, false);//only need neighbors const CoordinateFile* cf = borderSurface->getCoordinateFile(); std::vector neighbors; float tempxyz[3], tempxyz2[3], tempf = 0.0f, tempf2; tempn = new searchNode(); tempn->cost = 0.0f; tempn->heur = 0.0f; tempn->node = startNodeNumber; tempn->prev = -1; closedList[startNodeNumber] = tempn; startQ.push_front(tempn); bool found = false; iter = startQ.begin(); //std::cout << "start: " << startNodeNumber << " end: " << endNodeNumber << endl; //std::cout << "starting main loop" << endl; while (!startQ.empty() && !found) { tempn2 = *(startQ.begin()); if (tempn2->node == endNodeNumber) { found = true; break; } if (iter == startQ.begin()) ++iter; startQ.pop_front(); th->getNodeNeighbors(tempn2->node, neighbors); cf->getCoordinate(tempn2->node, tempxyz2); for (i = 0; i < (int)neighbors.size(); ++i) { if (!roi->getNodeSelected(neighbors[i])) continue; tempn = new searchNode(); tempn->node = neighbors[i]; tempn->prev = tempn2->node; cf->getCoordinate(neighbors[i], tempxyz); tempf = 0.0f; for (j = 0; j < 3; ++j) { tempf2 = tempxyz2[j] - tempxyz[j]; tempf += tempf2 * tempf2; } tempf = sqrtf(tempf); tempn->cost = tempn2->cost + tempf * pow(metricWeight, nodeCost->getValue(neighbors[i], metricColumn)); tempn->heur = tempn->cost;//so its actually f, not h, but this is faster. No heuristic, so just use uniform cost search. if (closedList[neighbors[i]]) { if (closedList[neighbors[i]]->heur > tempn->heur) { closedList[neighbors[i]]->heur = tempn->heur; closedList[neighbors[i]]->cost = tempn->cost; closedList[neighbors[i]]->node = tempn->node; closedList[neighbors[i]]->prev = tempn->prev; delete tempn; tempn = closedList[neighbors[i]]; for (myend = startQ.begin(); myend != startQ.end(); ++myend) { if (*myend == tempn) { if (iter == myend) { if (iter == startQ.begin()) ++iter; else --iter; } startQ.erase(myend); break; } } } else { delete tempn; tempn = NULL; } } if (tempn) { if (iter == startQ.end() || (*iter)->heur > tempn->heur) { if (iter != startQ.begin()) { for (--iter; iter != startQ.begin() && (*iter)->heur > tempn->heur; --iter); if ((*iter)->heur <= tempn->heur) ++iter; } } else { for (++iter; iter != startQ.end() && (*iter)->heur <= tempn->heur; ++iter); } closedList[neighbors[i]] = tempn; startQ.insert(iter, tempn); myend = startQ.end(); --myend; for (iter = startQ.begin(); iter != myend;) { if ((*iter)->heur > (*(++iter))->heur) { cout << "."; } } } } } if (startQ.empty()) { throw BrainModelAlgorithmException("drawHeuristic() failed to connect the endpoints with the given ROI."); } //std::cout << "loop done" << endl; std::list startOrder;//build first half of border by backtracking i = tempn2->node; while (i != -1) { //std::cout << i << endl; startOrder.push_front(i); i = closedList[i]->prev; } //cout << startOrder.size() << " nodes in piece" << endl; Border ret; for (std::list::iterator myiter = startOrder.begin(); myiter != startOrder.end(); ++myiter) { cf->getCoordinate(*myiter, tempxyz); ret.addBorderLink(tempxyz); } for (i = 0; i < numVert; ++i) { if (closedList[i]) delete closedList[i]; } delete[] closedList; //int junk; //ret.resampleBorderToDensity(samplingDistance, 2, junk); return ret; } /** * draw a border moving along the "most-lateral" nodes * DOES NOT WORK!!!! * void BrainModelSurfaceBorderLandmarkIdentification::drawBorderMostLateral( const BrainModelSurface* borderSurface, const BrainModelSurfaceROINodeSelection* roiIn, const QString borderName, const std::vector& nodeNumbers, const float samplingDistance) throw (BrainModelAlgorithmException) { BrainModelSurfaceROICreateBorderUsingMetricShape::MODE mode = BrainModelSurfaceROICreateBorderUsingMetricShape::MODE_FOLLOW_MOST_POSITIVE; std::vector segmentNames; const int numToDraw = static_cast(nodeNumbers.size()) - 1; for (int i = 0; i < numToDraw; i++) { const int startNodeNumber = nodeNumbers[i]; const int endNodeNumber = nodeNumbers[i + 1]; QString segmentName("MOST_LAT_" + QString::number(i)); drawBorderMetric(borderSurface, mode, depthSurfaceShapeFile, depthSurfaceShapeFileColumnNumber, segmentName, startNodeNumber, endNodeNumber, samplingDistance, roiIn); segmentNames.push_back(segmentName); } mergeBorders(borderName, segmentNames, true, false, borderSurface, 2, 1); } */ /** * draw a border using geodesic method. */ void BrainModelSurfaceBorderLandmarkIdentification::drawBorderGeodesic( const BrainModelSurface* borderSurface, const BrainModelSurfaceROINodeSelection* roiIn, const QString borderName, const int startNodeNumber, const int endNodeNumber, const float samplingDistance) throw (BrainModelAlgorithmException) { BrainModelSurfaceROINodeSelection roi(brainSet); if (roiIn != NULL) { roi = *roiIn; } else { roi.selectAllNodes(borderSurface); } // // Force the starting and ending nodes to be in the ROI and connected // roi.expandSoNodesAreWithinAndConnected(borderSurface, startNodeNumber, endNodeNumber); BrainModelSurfaceROICreateBorderUsingGeodesic cesDraw(brainSet, (BrainModelSurface*)borderSurface, &roi, borderName, startNodeNumber, endNodeNumber, samplingDistance); cesDraw.execute(); Border border = cesDraw.getBorder(); if (border.getNumberOfLinks() <= 0) { throw BrainModelAlgorithmException("Geodesic drawing of border named \"" + borderName + "\" failed."); } // // Project the border and add to border projection file // BorderFile borderFile; borderFile.addBorder(border); BorderProjectionFile bpf; BorderFileProjector projector(borderSurface, true); projector.projectBorderFile(&borderFile, &bpf, NULL); borderProjectionFile->append(bpf); const QString name(debugFilesDirectoryName + "/" + borderDebugFileName); try { borderProjectionFile->writeFile(name); } catch (FileException&) { std::cout << "WARNING: Unable to write landmark debug border projection file." << std::endl; } } /** * Find node at distance along geodesic path between nodes. */ int BrainModelSurfaceBorderLandmarkIdentification::findNodeAlongGeodesicPathBetweenNodes( const BrainModelSurface* surface, const int startNodeNumber, const int endNodeNumber, const float distanceFromStartNode, const BrainModelSurfaceROINodeSelection* roiIn) throw (BrainModelAlgorithmException) { BrainModelSurfaceROINodeSelection roi(brainSet); if (roiIn != NULL) { roi = *roiIn; } else { roi.selectAllNodes(surface); } // // Force the starting and ending nodes to be in the ROI and connected // roi.expandSoNodesAreWithinAndConnected(surface, startNodeNumber, endNodeNumber); // // Generate a border between nodes // BrainModelSurfaceROICreateBorderUsingGeodesic geodesic(brainSet, (BrainModelSurface*)surface, &roi, "JUNK", startNodeNumber, endNodeNumber, 1.0); geodesic.execute(); Border border = geodesic.getBorder(); const int numLinks = border.getNumberOfLinks(); if (numLinks <= 0) { throw BrainModelAlgorithmException("Geodesic path between \"" + QString::number(startNodeNumber) + " " + QString::number(endNodeNumber) + "\" failed."); } // // Follow border until distance from start node is reached // const CoordinateFile* cf = surface->getCoordinateFile(); float nodeXYZ[3]; border.getLinkXYZ(numLinks - 1, nodeXYZ); float totalDistance = 0.0; for (int i = 0; i < (numLinks - 1); i++) { const float d = border.distanceBetweenLinks(i, i + 1); totalDistance += d; if (totalDistance >= distanceFromStartNode) { border.getLinkXYZ(i, nodeXYZ); break; } } // // Get the node at the distance from starting node // const int nodeNumber = cf->getCoordinateIndexClosestToPoint(nodeXYZ[0], nodeXYZ[1], nodeXYZ[2]); return nodeNumber; } /** * project the foci. */ void BrainModelSurfaceBorderLandmarkIdentification::projectFoci() { CellFileProjector fociProjector(fiducialSurface); fociProjector.projectFile(fociProjectionFile, 0, CellFileProjector::PROJECTION_TYPE_ALL, 0, false, NULL); } /** * nibble border with offset. */ void BrainModelSurfaceBorderLandmarkIdentification::nibbleBorderWithinOffset( const BrainModelSurface* surface, const QString& borderName, const float xyz[3], const BORDER_NIBBLE_MODE_OFFSET nibbleMode, const float nibbleOffset) throw (BrainModelAlgorithmException) { BorderProjection* bp = borderProjectionFile->getFirstBorderProjectionByName(borderName); if (bp == NULL) { throw BrainModelAlgorithmException("Border named " + borderName + " not found for border nibbling."); } float extent[6] = { -std::numeric_limits::max(), std::numeric_limits::max(), -std::numeric_limits::max(), std::numeric_limits::max(), -std::numeric_limits::max(), std::numeric_limits::max() }; switch (nibbleMode) { case BORDER_NIBBLE_MODE_OFFSET_GREATER_THAN_X: extent[1] = xyz[0] + nibbleOffset; break; case BORDER_NIBBLE_MODE_OFFSET_GREATER_THAN_Y: extent[3] = xyz[1] + nibbleOffset; break; case BORDER_NIBBLE_MODE_OFFSET_GREATER_THAN_Z: extent[5] = xyz[2] + nibbleOffset; break; case BORDER_NIBBLE_MODE_OFFSET_LESS_THAN_X: extent[0] = xyz[0] + nibbleOffset; break; case BORDER_NIBBLE_MODE_OFFSET_LESS_THAN_Y: extent[2] = xyz[1] + nibbleOffset; break; case BORDER_NIBBLE_MODE_OFFSET_LESS_THAN_Z: extent[4] = xyz[2] + nibbleOffset; break; } bp->removeLinksOutsideExtent(surface->getCoordinateFile(), extent); } /** * remove loops from a border. */ void BrainModelSurfaceBorderLandmarkIdentification::removeLoopsFromBorder( const BrainModelSurface* surface, const QString& borderName, const char axisChar) throw (BrainModelAlgorithmException) { // // Get the border projection // const BorderProjection* bp = borderProjectionFile->getLastBorderProjectionByName(borderName); if (bp == NULL) { throw ("Unable to find border \"" + borderName + "\"for resampling"); } // // Place the border projection in a temporary file // BorderProjectionFile tempBorderProjectionFile; tempBorderProjectionFile.addBorderProjection(*bp); // // Unproject the border // BorderProjectionUnprojector unprojector; BorderFile tempBorderFile; unprojector.unprojectBorderProjections(*(surface->getCoordinateFile()), tempBorderProjectionFile, tempBorderFile); // // Get border // if (tempBorderFile.getNumberOfBorders() <= 0) { throw BrainModelAlgorithmException("Unprojection error when resampling " + borderName); } // // Remove loops from the border // Border* b = tempBorderFile.getBorder(0); const int oldNumLinks = b->getNumberOfLinks(); b->removeIntersectingLoops(axisChar); // // If no links removed, return // if (b->getNumberOfLinks() == oldNumLinks) { return; } // // Reproject the border // tempBorderProjectionFile.clear(); BorderFileProjector projector(surface, true); projector.projectBorderFile(&tempBorderFile, &tempBorderProjectionFile, NULL); // // Add border projection to output file // if (tempBorderProjectionFile.getNumberOfBorderProjections() <= 0) { throw BrainModelAlgorithmException("Reprojection error when resampling " + borderName); } borderProjectionFile->removeBordersWithName(borderName); borderProjectionFile->addBorderProjection( *tempBorderProjectionFile.getBorderProjection(0)); } /** * resample a border. */ void BrainModelSurfaceBorderLandmarkIdentification::resampleBorder( const BrainModelSurface* surface, const QString& borderName, const float samplingDistance, const bool projectToTilesFlag) throw (BrainModelAlgorithmException) { // // Get the border projection // const BorderProjection* bp = borderProjectionFile->getLastBorderProjectionByName(borderName); if (bp == NULL) { throw ("Unable to find border \"" + borderName + "\"for resampling"); } // // Place the border projection in a temporary file // BorderProjectionFile tempBorderProjectionFile; tempBorderProjectionFile.addBorderProjection(*bp); // // Unproject the border // BorderProjectionUnprojector unprojector; BorderFile tempBorderFile; unprojector.unprojectBorderProjections(*(surface->getCoordinateFile()), tempBorderProjectionFile, tempBorderFile); // // Get border // if (tempBorderFile.getNumberOfBorders() <= 0) { throw BrainModelAlgorithmException("Unprojection error when resampling " + borderName); } // // Resample the border // Border* b = tempBorderFile.getBorder(0); int newNumLinks = 0; b->resampleBorderToDensity(samplingDistance, 2, newNumLinks); // // Reproject the border // tempBorderProjectionFile.clear(); BorderFileProjector projector(surface, projectToTilesFlag); projector.projectBorderFile(&tempBorderFile, &tempBorderProjectionFile, NULL); // // Add border projection to output file // if (tempBorderProjectionFile.getNumberOfBorderProjections() <= 0) { throw BrainModelAlgorithmException("Reprojection error when resampling " + borderName); } borderProjectionFile->removeBordersWithName(borderName); borderProjectionFile->addBorderProjection( *tempBorderProjectionFile.getBorderProjection(0)); } /** * nibble border within distance. */ void BrainModelSurfaceBorderLandmarkIdentification::nibbleBorderWithinDistance( const BrainModelSurface* surface, const QString& borderName, const int nodeNumber, const BORDER_NIBBLE_MODE_DISTANCE nibbleMode, const float nibbleDistance) throw (BrainModelAlgorithmException) { const float* xyz = surface->getCoordinateFile()->getCoordinate(nodeNumber); BorderProjection* bp = borderProjectionFile->getFirstBorderProjectionByName(borderName); if (bp == NULL) { throw BrainModelAlgorithmException("Border named " + borderName + " not found for border nibbling."); } float withinXDistance = -1.0; float withinYDistance = -1.0; float withinZDistance = -1.0; float withinLinearDistance = -1.0; switch (nibbleMode) { case BORDER_NIBBLE_MODE_DISTANCE_X: withinXDistance = nibbleDistance; break; case BORDER_NIBBLE_MODE_DISTANCE_Y: withinYDistance = nibbleDistance; break; case BORDER_NIBBLE_MODE_DISTANCE_Z: withinZDistance = nibbleDistance; break; case BORDER_NIBBLE_MODE_DISTANCE_LINEAR: withinLinearDistance = nibbleDistance; break; } bp->removeLinksNearPoint(surface->getCoordinateFile(), xyz, withinXDistance, withinYDistance, withinZDistance, withinLinearDistance); } /** * nibble border beyond distance. */ void BrainModelSurfaceBorderLandmarkIdentification::nibbleBorderBeyondDistance( const BrainModelSurface* surface, const QString& borderName, const float nibbleFromHereXYZ[3], const BORDER_NIBBLE_MODE_DISTANCE nibbleMode, const float nibbleDistance) throw (BrainModelAlgorithmException) { BorderProjection* bp = borderProjectionFile->getFirstBorderProjectionByName(borderName); if (bp == NULL) { throw BrainModelAlgorithmException("Border named " + borderName + " not found for border nibbling."); } float withinXDistance = std::numeric_limits::max(); float withinYDistance = std::numeric_limits::max(); float withinZDistance = std::numeric_limits::max(); float withinLinearDistance = std::numeric_limits::max(); switch (nibbleMode) { case BORDER_NIBBLE_MODE_DISTANCE_X: withinXDistance = nibbleDistance; break; case BORDER_NIBBLE_MODE_DISTANCE_Y: withinYDistance = nibbleDistance; break; case BORDER_NIBBLE_MODE_DISTANCE_Z: withinZDistance = nibbleDistance; break; case BORDER_NIBBLE_MODE_DISTANCE_LINEAR: withinLinearDistance = nibbleDistance; break; } bp->removeLinksAwayFromPoint(surface->getCoordinateFile(), nibbleFromHereXYZ, withinXDistance, withinYDistance, withinZDistance, withinLinearDistance); } /** * nibble border within distance. */ void BrainModelSurfaceBorderLandmarkIdentification::nibbleBorderWithinDistance( const BrainModelSurface* surface, const QString& borderName, const float nibbleFromHereXYZ[3], const BORDER_NIBBLE_MODE_DISTANCE nibbleMode, const float nibbleDistance) throw (BrainModelAlgorithmException) { BorderProjection* bp = borderProjectionFile->getFirstBorderProjectionByName(borderName); if (bp == NULL) { throw BrainModelAlgorithmException("Border named " + borderName + " not found for border nibbling."); } float withinXDistance = -1.0; float withinYDistance = -1.0; float withinZDistance = -1.0; float withinLinearDistance = -1.0; switch (nibbleMode) { case BORDER_NIBBLE_MODE_DISTANCE_X: withinXDistance = nibbleDistance; break; case BORDER_NIBBLE_MODE_DISTANCE_Y: withinYDistance = nibbleDistance; break; case BORDER_NIBBLE_MODE_DISTANCE_Z: withinZDistance = nibbleDistance; break; case BORDER_NIBBLE_MODE_DISTANCE_LINEAR: withinLinearDistance = nibbleDistance; break; } bp->removeLinksNearPoint(surface->getCoordinateFile(), nibbleFromHereXYZ, withinXDistance, withinYDistance, withinZDistance, withinLinearDistance); } /** * add focus color. */ void BrainModelSurfaceBorderLandmarkIdentification::addFocusColor( const QString& colorName, const unsigned char red, const unsigned char green, const unsigned char blue) { fociColorFile->addColor(colorName, red, green, blue, 255, 3, 1, ColorFile::ColorStorage::SYMBOL_SPHERE); //const QString name(debugFilesDirectoryName // + "/" // + fociColorDebugFileName); try { fociColorFile->writeFile(fociColorDebugFileName); } catch (FileException&) { std::cout << "WARNING: Unable to write landmark debug foci color file." << std::endl; } } /** * add focus at extremum. */ int BrainModelSurfaceBorderLandmarkIdentification::addFocusAtExtremum( const BrainModelSurface* extremumSurface, const int startingNodeNumber, const BrainModelSurfaceFindExtremum::DIRECTION searchDirection, const float xMaximumMovement, const float yMaximumMovement, const float zMaximumMovement, const QString& focusName, BrainModelSurfaceROINodeSelection* roiAlongPath, const BrainModelSurfaceFindExtremum::NORMAL_RESTRICTION xr, const BrainModelSurfaceFindExtremum::NORMAL_RESTRICTION yr, const BrainModelSurfaceFindExtremum::NORMAL_RESTRICTION zr) throw (BrainModelAlgorithmException) { // // Get the extremum // const CoordinateFile* cf = extremumSurface->getCoordinateFile(); const float* startXYZ = cf->getCoordinate(startingNodeNumber); BrainModelSurfaceFindExtremum bmsfe(brainSet, (BrainModelSurface*)extremumSurface, searchDirection, startXYZ, xMaximumMovement, yMaximumMovement, zMaximumMovement); bmsfe.setNodeNormalRestriction(xr, yr, zr); bmsfe.execute(); const int node = bmsfe.getExtremumNode(); if (node < 0) { throw ("Find extremum failed to find node for " + focusName); } if (focusName.isEmpty() == false) { addFocusAtNode(focusName, node); } if (roiAlongPath != NULL) { bmsfe.setRegionOfInterestToNodesInPath(*roiAlongPath); } return node; } /** * add a focus at a node. */ void BrainModelSurfaceBorderLandmarkIdentification::addFocusAtNode( const QString& focusName, const int placeAtNodeNumber) throw (BrainModelAlgorithmException) { if ((placeAtNodeNumber >= 0) && (placeAtNodeNumber < fiducialSurface->getNumberOfNodes())) { fociProjectionFile->addCellProjection( CellProjection(focusName, fiducialSurface->getCoordinateFile(), placeAtNodeNumber, fiducialSurface->getStructure())); //const QString name(debugFilesDirectoryName // + "/" // + fociProjectionDebugFileName); try { fociProjectionFile->writeFile(fociProjectionDebugFileName); } catch (FileException&) { std::cout << "WARNING: Unable to write landmark debug foci projection file." << std::endl; } } else { throw BrainModelAlgorithmException("addFocusAtNode() Invalid node number " + QString::number(placeAtNodeNumber) + " for focus named " + focusName); } } /** * add a focus at the node nearest the XYZ. */ int BrainModelSurfaceBorderLandmarkIdentification::addFocusAtNodeNearestXYZ( const BrainModelSurface* surface, const QString& focusName, const float xyz[3]) { const int nodeNumber = surface->getCoordinateFile()->getCoordinateIndexClosestToPoint(xyz[0], xyz[1], xyz[2]); addFocusAtNode(focusName, nodeNumber); return nodeNumber; } /** * add a focus at a location. */ void BrainModelSurfaceBorderLandmarkIdentification::addFocusAtXYZ( const QString& focusName, const float xyz[3]) { CellProjection cp; cp.setName(focusName); cp.setXYZ(xyz); fociProjectionFile->addCellProjection(cp); //const QString name(debugFilesDirectoryName // + "/" // + fociProjectionDebugFileName); try { fociProjectionFile->writeFile(fociProjectionDebugFileName); } catch (FileException&) { std::cout << "WARNING: Unable to write landmark debug foci projection file." << std::endl; } } /** * add a focus at a location. */ void BrainModelSurfaceBorderLandmarkIdentification::addFocusAtXYZ( const BrainModelSurface* focusSurface, const QString& focusName, const float xyz[3]) { const CoordinateFile* cf = focusSurface->getCoordinateFile(); const int nodeNum = cf->getCoordinateIndexClosestToPoint(xyz[0], xyz[1], xyz[2]); addFocusAtNode(focusName, nodeNum); } /** * add a focus at a border link. */ void BrainModelSurfaceBorderLandmarkIdentification::addFocusAtBorderLink( const BorderProjection* bp, const int borderLinkNumber, const QString& focusName) { if ((borderLinkNumber >= 0) && (borderLinkNumber < bp->getNumberOfLinks())) { const BorderProjectionLink* bpl = bp->getBorderProjectionLink(borderLinkNumber); float xyz[3]; bpl->unprojectLink(fiducialSurface->getCoordinateFile(), xyz); addFocusAtXYZ(focusName, xyz); } } /** * save an ROI to a file. */ void BrainModelSurfaceBorderLandmarkIdentification::saveRoiToFile( const BrainModelSurfaceROINodeSelection& roi, const QString& roiFileName) throw (BrainModelAlgorithmException) { if (roi.getNumberOfNodesSelected() <= 0) { throw BrainModelAlgorithmException("ERROR: ROI created with name \"" + roiFileName + "\" contains no nodes."); } const QString name(debugFilesDirectoryName + "/" + roiFileName); NodeRegionOfInterestFile nroi; roi.setRegionOfInterestIntoFile(nroi); try { nroi.writeFile(name); } catch (FileException& e) { std::cout << "WARNING: Unable to write ROI file named " << name.toAscii().constData() << std::endl << " Error Message: " << e.whatQString().toAscii().constData() << std::endl; } } /** * identify the sylvian fissure. */ void BrainModelSurfaceBorderLandmarkIdentification::identifySylvianFissure() throw (BrainModelAlgorithmException) { // // Names of things // const QString sylvianFissureLandmarkName("LANDMARK.SylvianFissure"); const QString sfDorsalLandmarkName("LANDMARK.SFdorsal"); const QString sfAntLandmarkName("LANDMARK.SFant"); const QString sfSecondaryLandmarkName("LANDMARK.SF-secondary"); const QString sfGenericColorName("SF"); const QString sfAnteriorFocusName("SF_Anterior"); const QString sfAnteriorDeepFocusName("SF_Anterior_Deep"); const QString sfAnteriorBelowFocusName("SF_Anterior_Below_Deep"); const QString sfPosteriorFocusName("SF_Posterior"); const QString sfPosteriorLandmarkFocusName("SF_Posterior-Landmark"); const QString sfAnteriorLandmarkFocusName("SF_Anterior-Landmark"); const QString sfDorsalFocusName("SF_Dorsal"); const QString sfVentralFrontalFocusName("SF_VentralFrontal"); const QString sfVentralFrontalExtremeFocusName("SF_VentralFrontalExtreme"); const QString sfInferiorBranchBeginFocusName("SF_Inferior_Branch_Begin"); const QString sfIntersectSuperiorInferiorFocusName("SF_Intersect_Superior_Inferior"); const QString sfSaddleAnteriorLimitFocusName("SFsaddleAnteriorLimit"); const QString sfCogFocusName("SF_COG"); const QString sfRoiFileName(createFileName("SUL.SF", SpecFile::getRegionOfInterestFileExtension())); const QString sfDeep7RoiFileName(createFileName("SUL.SF.deep7", SpecFile::getRegionOfInterestFileExtension())); const QString sfDeepFundalRoiFileName(createFileName("SUL.SF.deep_fundal", SpecFile::getRegionOfInterestFileExtension())); const QString sfPosteriorRoiFileName(createFileName("SUL.SF.Posterior", SpecFile::getRegionOfInterestFileExtension())); const QString sfVeryPosteriorRoiFileName(createFileName("SUL.SF.VeryPosterior", SpecFile::getRegionOfInterestFileExtension())); const QString sfAnteriorRoiFileName(createFileName("SUL.SF.Anterior", SpecFile::getRegionOfInterestFileExtension())); const QString sfFundalRoiFileName(createFileName("SUL.SF.fundal", SpecFile::getRegionOfInterestFileExtension())); // // Add some colors // // caret_command -color-file-add-color $BORDERCOLOR $BORDERCOLOR // LANDMARK.SylvianFissure 0 255 255 -point-size 3 -symbol SPHERE // caret_command -color-file-add-color $FOCICOLOR $FOCICOLOR // SF 48 164 255 -point-size 3 -symbol SPHERE borderColorFile->addColor(sylvianFissureLandmarkName, 0, 255, 255, 255, 3, 1, ColorFile::ColorStorage::SYMBOL_SPHERE); addFocusColor(sfGenericColorName, 48, 164, 255); // // Remove existing foci // // caret_command -surface-foci-delete $OUTFOCIPROJ $OUTFOCIPROJ // SF_Anterior SF_Posterior SF_Posterior-Landmark SF_Anterior-Landmark // SF_Dorsal SF_VentralFrontal SF_VentralFrontalExtreme // SF_Inferior_Branch_Begin SF_Intersect_Superior_Inferior // SFsaddleAnteriorLimit SUL.SF_COG fociProjectionFile->deleteCellProjectionsWithName(sfAnteriorFocusName); fociProjectionFile->deleteCellProjectionsWithName(sfAnteriorDeepFocusName); fociProjectionFile->deleteCellProjectionsWithName(sfAnteriorBelowFocusName); fociProjectionFile->deleteCellProjectionsWithName(sfPosteriorFocusName); fociProjectionFile->deleteCellProjectionsWithName(sfPosteriorLandmarkFocusName); fociProjectionFile->deleteCellProjectionsWithName(sfAnteriorLandmarkFocusName); fociProjectionFile->deleteCellProjectionsWithName(sfDorsalFocusName); fociProjectionFile->deleteCellProjectionsWithName(sfVentralFrontalFocusName); fociProjectionFile->deleteCellProjectionsWithName(sfVentralFrontalExtremeFocusName); fociProjectionFile->deleteCellProjectionsWithName(sfInferiorBranchBeginFocusName); fociProjectionFile->deleteCellProjectionsWithName(sfIntersectSuperiorInferiorFocusName); fociProjectionFile->deleteCellProjectionsWithName(sfSaddleAnteriorLimitFocusName); fociProjectionFile->deleteCellProjectionsWithName(sfCogFocusName); // // Remove borders // // caret_command -surface-border-delete $OUTBORDERPROJ $OUTBORDERPROJ // LANDMARK.SylvianFissure LANDMARK.SFdorsal LANDMARK.SFant LANDMARK.SF-secondary // borderProjectionFile->removeBordersWithName(sylvianFissureLandmarkName); borderProjectionFile->removeBordersWithName(sfDorsalLandmarkName); borderProjectionFile->removeBordersWithName(sfAntLandmarkName); borderProjectionFile->removeBordersWithName(sfSecondaryLandmarkName); // // Remove ROI files // QFile::remove(sfRoiFileName); QFile::remove(sfDeep7RoiFileName); QFile::remove(sfDeepFundalRoiFileName); QFile::remove(sfPosteriorRoiFileName); QFile::remove(sfVeryPosteriorRoiFileName); QFile::remove(sfAnteriorRoiFileName); QFile::remove(sfFundalRoiFileName); // // Select nodes in the Sylvian Fissure // // caret_command -surface-region-of-interest-selection $INFLATED $TOPO // SUL.SF.roi SUL.SF.roi -paint $SULCAL_ID_PAINT "Sulcus ID" SUL.SF NORMAL // BrainModelSurfaceROINodeSelection sfROI(brainSet); QString errorMessage = sfROI.selectNodesWithPaint( BrainModelSurfaceROINodeSelection::SELECTION_LOGIC_NORMAL, inflatedSurface, paintFile, paintFileSulcusIdColumnNumber, "SUL.SF"); if (errorMessage.isEmpty() == false) { throw BrainModelAlgorithmException(errorMessage); } // // Remove islands from SUL.SF.roi (JWH) // // caret_command -surface-region-of-interest-selection $INFLATED $TOPO SUL.SF.roi SUL.SF.roi -remove-islands // sfROI.discardIslands(inflatedSurface); saveRoiToFile(sfROI, sfRoiFileName); // // Start with SF ROI and select nodes with depth (-500, -7) // // ### JWH 02/29/2008 Fix problem with SF Landmark going out of SF and towards the posterior // ### Using a larger DEPTH = -15.0 fixes case 9 LEFT // ###caret_command -surface-region-of-interest-selection $INFLATED $TOPO // ### SUL.SF.roi SUL.SF.deep7.roi -shape $SHAPE_OUT Depth -500.0 -7.0 AND // caret_command -surface-region-of-interest-selection $INFLATED $TOPO // SUL.SF.roi SUL.SF.deep7.roi -shape $SHAPE_OUT Depth -500.0 -7.0 AND // BrainModelSurfaceROINodeSelection sfDeep7ROI(sfROI); errorMessage = sfDeep7ROI.selectNodesWithSurfaceShape( BrainModelSurfaceROINodeSelection::SELECTION_LOGIC_AND, inflatedSurface, depthSurfaceShapeFile, depthSurfaceShapeFileColumnNumber, -500.0, -7.0); if (errorMessage.isEmpty() == false) { throw BrainModelAlgorithmException(errorMessage); } saveRoiToFile(sfDeep7ROI, sfDeep7RoiFileName); // // Further restrict the ROI to curvature (-100, -0.05) on inflated surface // // caret_command -surface-region-of-interest-selection $INFLATED $TOPO // SUL.SF.deep7.roi SUL.SF.deep_fundal.roi -shape $SHAPE_INFLATED // "Folding (Mean Curvature) INFLATED" -100.0 -0.05 AND BrainModelSurfaceROINodeSelection sfDeepFundalROI(sfDeep7ROI); errorMessage = sfDeepFundalROI.selectNodesWithSurfaceShape( BrainModelSurfaceROINodeSelection::SELECTION_LOGIC_AND, inflatedSurface, curvatureShapeFile, curvatureInflatedMeanColumnNumber, -100.0, -0.05); if (errorMessage.isEmpty() == false) { throw BrainModelAlgorithmException(errorMessage); } saveRoiToFile(sfDeepFundalROI, sfDeepFundalRoiFileName); // // Get center of gravity and place a focus there // // caret_command -surface-place-foci-at-limits $FIDUCIAL $FIDUCIAL $TOPO // SUL.SF.deep_fundal.roi $OUTFOCIPROJ $OUTFOCIPROJ -cog SUL.SF_COG // float sfCogXYZ[3]; sfDeepFundalROI.getCenterOfGravityOfSelectedNodes(fiducialSurface, sfCogXYZ); addFocusAtXYZ(sfCogFocusName, sfCogXYZ); // // Limit the maximum-Y in the SF ROI to the center of gravity // // caret_command -surface-region-of-interest-selection $FIDUCIAL $TOPO // SUL.SF.roi SUL.SF.Posterior.roi -limit-y-max-focus $OUTFOCIPROJ SUL.SF_COG // const float sfROIExtent[6] = { -std::numeric_limits::max(), std::numeric_limits::max(), -std::numeric_limits::max(), sfCogXYZ[1], -std::numeric_limits::max(), std::numeric_limits::max(), }; BrainModelSurfaceROINodeSelection sfPosteriorROI(sfROI); sfPosteriorROI.limitExtent(fiducialSurface, sfROIExtent); // Remove islands from SUL.SF.Posterior.roi since some appear on // the medial surface which causes an invalid placement of the focus // SF_Inferior_Branch_Begin // // caret_command -surface-region-of-interest-selection $FIDUCIAL $TOPO // SUL.SF.Posterior.roi SUL.SF.Posterior.roi -remove-islands sfPosteriorROI.discardIslands(fiducialSurface); saveRoiToFile(sfPosteriorROI, sfPosteriorRoiFileName); // // Get nodes at min/max geometric values of the SF-Posterior ROI // int minXNode, maxXNode, minYNode, maxYNode, minZNode, maxZNode; int mostMedialXNode, mostLateralXNode; int absMinXNode, absMaxXNode, absMinYNode, absMaxYNode, absMinZNode, absMaxZNode; sfPosteriorROI.getNodesWithMinMaxXYZValues(inflatedSurface, mostMedialXNode, mostLateralXNode, minXNode, maxXNode, minYNode, maxYNode, minZNode, maxZNode, absMinXNode, absMaxXNode, absMinYNode, absMaxYNode, absMinZNode, absMaxZNode); // // Get node at z-min of ROI and place a focus there // // caret_command -surface-place-foci-at-limits $FIDUCIAL $INFLATED $TOPO // SUL.SF.Posterior.roi $OUTFOCIPROJ $OUTFOCIPROJ -z-min SF_Inferior_Branch_Begin // sfInferiorBranchBeginNodeNumber = minZNode; if (DebugControl::getDebugOn()) { std::cout << sfInferiorBranchBeginFocusName.toAscii().constData() << " node number is " << sfInferiorBranchBeginNodeNumber << std::endl; } addFocusAtNode(sfInferiorBranchBeginFocusName, sfInferiorBranchBeginNodeNumber); // // Get bounds of inflated surface // // float inflatedSurfaceBounds[6]; inflatedSurface->getBounds(inflatedSurfaceBounds); float veryPosteriorMinX = inflatedSurfaceBounds[0] + 10.0; float veryPosteriorMaxX = std::numeric_limits::max(); if (leftHemisphereFlag) { veryPosteriorMinX = -std::numeric_limits::max(); veryPosteriorMaxX = inflatedSurfaceBounds[1] - 10.0; } // // Create a very posterior ROI // JWH 10 April // float veryPosteriorExtent[6] = { veryPosteriorMinX, //-std::numeric_limits::max(), veryPosteriorMaxX, // std::numeric_limits::max(), -std::numeric_limits::max(), -17.0, -std::numeric_limits::max(), std::numeric_limits::max(), }; BrainModelSurfaceROINodeSelection sfVeryPosteriorROI(brainSet); while ((sfVeryPosteriorROI.getNumberOfNodesSelected() < 25) && (veryPosteriorExtent[3] <= 0.0)) { sfVeryPosteriorROI = sfROI; veryPosteriorExtent[3] += 1.0; sfVeryPosteriorROI.limitExtent(inflatedSurface, veryPosteriorExtent); } saveRoiToFile(sfVeryPosteriorROI, sfVeryPosteriorRoiFileName); // // Get nodes at min/max geometric values of the Deep Fundal ROI // //sfDeepFundalROI.getNodesWithMinMaxXYZValues(inflatedSurface, // JWH 10 April sfVeryPosteriorROI.getNodesWithMinMaxXYZValues(fiducialSurface, mostMedialXNode, mostLateralXNode, minXNode, maxXNode, minYNode, maxYNode, minZNode, maxZNode, absMinXNode, absMaxXNode, absMinYNode, absMaxYNode, absMinZNode, absMaxZNode); // // Get node numbers and place foci at Y-Min and Z-Max of Deep-Fundal ROI // // caret_command -surface-place-foci-at-limits $FIDUCIAL $INFLATED $TOPO // SUL.SF.deep_fundal.roi $OUTFOCIPROJ $OUTFOCIPROJ -y-min SF_Posterior // -z-max SF_Dorsal const int sfPosteriorNodeNumber = minYNode; if (DebugControl::getDebugOn()) { std::cout << sfPosteriorFocusName.toAscii().constData() << " node number is " << sfPosteriorNodeNumber << std::endl; } addFocusAtNode(sfPosteriorFocusName, sfPosteriorNodeNumber); // JWH 10 April sfVeryPosteriorROI.getNodesWithMinMaxXYZValues(inflatedSurface, mostMedialXNode, mostLateralXNode, minXNode, maxXNode, minYNode, maxYNode, minZNode, maxZNode, absMinXNode, absMaxXNode, absMinYNode, absMaxYNode, absMinZNode, absMaxZNode); const int sfDorsalNodeNumber = maxZNode; if (DebugControl::getDebugOn()) { std::cout << sfDorsalFocusName.toAscii().constData() << " node number is " << sfDorsalNodeNumber << std::endl; } addFocusAtNode(sfDorsalFocusName, sfDorsalNodeNumber); // // LEFT RIGHT ISSUE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // // caret_command -surface-region-of-interest-selection $FIDUCIAL $TOPO // SUL.SF.deep_fundal.roi SUL.SF.Anterior.roi -limit-x-max-focus // $OUTFOCIPROJ SUL.SF_COG -limit-y-min-focus $OUTFOCIPROJ TemporalPole BrainModelSurfaceROINodeSelection sfAnteriorROI(sfDeepFundalROI); float sfAnteriorROIExtent[6] = { -std::numeric_limits::max(), std::numeric_limits::max(), fiducialSurfaceTemporalPoleXYZ[1], std::numeric_limits::max(), -std::numeric_limits::max(), std::numeric_limits::max() }; if (leftHemisphereFlag) { sfAnteriorROIExtent[1] = sfCogXYZ[0]; } else { sfAnteriorROIExtent[0] = sfCogXYZ[0]; } sfAnteriorROI.limitExtent(fiducialSurface, sfAnteriorROIExtent); int sfAnteriorCounter = 0; while (sfAnteriorROI.getNumberOfNodesSelected() <= 0) { sfAnteriorROI = sfDeepFundalROI; sfAnteriorROIExtent[2] -= 2.0; if (leftHemisphereFlag) { sfAnteriorROIExtent[1] += 2.0; } else { sfAnteriorROIExtent[0] -= 2.0; } sfAnteriorROI.limitExtent(fiducialSurface, sfAnteriorROIExtent); sfAnteriorCounter++; if (sfAnteriorCounter > 10) { break; } } saveRoiToFile(sfAnteriorROI, sfAnteriorRoiFileName); // // Place a focus at the COG of the SUL.SF.Anterior.ROI // // caret_command -surface-place-foci-at-limits $FIDUCIAL $FIDUCIAL $TOPO // SUL.SF.Anterior.roi $OUTFOCIPROJ $OUTFOCIPROJ -cog SF_Anterior float sfAnteriorXYZ[3]; sfAnteriorROI.getCenterOfGravityOfSelectedNodes(fiducialSurface, sfAnteriorXYZ); addFocusAtXYZ(sfAnteriorFocusName, sfAnteriorXYZ); const int sfAnteriorNodeNumber = fiducialSurface->getCoordinateFile()->getCoordinateIndexClosestToPoint( sfAnteriorXYZ[0], sfAnteriorXYZ[1], sfAnteriorXYZ[2]); if (DebugControl::getDebugOn()) { std::cout << sfAnteriorFocusName.toAscii().constData() << " node number is " << sfAnteriorNodeNumber << std::endl; } // // Find point inside the curved part of the fissure // /* const float* anteriorXYZ = fiducialSurface->getCoordinateFile()->getCoordinate(sfAnteriorFocusNodeNumber); const float sfDeepAnteriorExtent[6] = { -std::numeric_limits::max(), std::numeric_limits::max(), anteriorXYZ[1] - 20.0, anteriorXYZ[1], anteriorXYZ[2] - 15, anteriorXYZ[2] + 5.0, }; */ const int sfAnteriorDeepNodeNumber = getNearbyNodeWithShapeValue(fiducialSurface, depthSurfaceShapeFile, depthSurfaceShapeFileColumnNumber, -100000.0, sfAnteriorNodeNumber, 15.0, NULL, NULL); addFocusAtNode(sfAnteriorDeepFocusName, sfAnteriorDeepNodeNumber); if (DebugControl::getDebugOn()) { std::cout << sfAnteriorDeepFocusName.toAscii().constData() << " node number is " << sfAnteriorDeepNodeNumber << std::endl; } // // Find a spot forward of and below SF Anterior Deep // const float* deepXYZ = fiducialSurface->getCoordinateFile()->getCoordinate(sfAnteriorDeepNodeNumber); float deepExtent[6] = { deepXYZ[0] - 15.0, deepXYZ[0] + 15.0, deepXYZ[1], deepXYZ[1] + 10.0, deepXYZ[2] - 12.0, deepXYZ[2] - 6.0 }; int sfAnteriorDeepBelowNodeNumber = getNearbyNodeWithShapeValue(fiducialSurface, depthSurfaceShapeFile, depthSurfaceShapeFileColumnNumber, -100000.0, -1, 50.0, NULL, deepExtent); addFocusAtNode(sfAnteriorBelowFocusName, sfAnteriorDeepBelowNodeNumber); // // Draw a border along the deep fundus // // caret_command -surface-border-draw-geodesic $INFLATED $TOPO $OUTFOCIPROJ // SF_Posterior SF_Anterior SUL.SF.deep_fundal.roi // $OUTBORDERPROJ $OUTBORDERPROJ LANDMARK.SFdorsal 3.0 std::vector sfDorsalNodeNumbers; sfDorsalNodeNumbers.push_back(sfPosteriorNodeNumber); sfDorsalNodeNumbers.push_back(sfAnteriorDeepNodeNumber); sfDorsalNodeNumbers.push_back(sfAnteriorDeepBelowNodeNumber); /*float target[3]; float targetweight;*/ /*drawBorderGeodesic(inflatedSurface, &sfDeepFundalROI, sfDorsalLandmarkName, sfDorsalNodeNumbers, 3.0);*/ /*target[0] = -30.0f; target[1] = 35.0f; target[2] = 20.0f; targetweight = 1.18f; if (leftHemisphereFlag) { target[0] *= -1.0f; } drawBorderTargetedGeodesic(fiducialSurface, &sfDeepFundalROI, sfDorsalLandmarkName, sfDorsalNodeNumbers, 3.0, target, targetweight);*/ drawBorderMetricGeodesic(fiducialSurface, &sfDeepFundalROI, sfDorsalLandmarkName, sfDorsalNodeNumbers, 3.0, curvatureShapeFile, curvatureFiducialMeanColumnNumber,//curvatureFiducialSmoothedMeanColumnNumber ? 1.5f);//IMPORTANT: > 1 weight means prefer NEGATIVE values //drawBorderGeodesic(inflatedSurface, // &sfDeepFundalROI, // sfDorsalLandmarkName, // sfPosteriorNodeNumber, // sfAnteriorDeepNodeNumber, //sfAnteriorNodeNumber, // 3.0); // // Set X-Coord for left or right // // if [ $LEFT_FLAG -eq 1 ] // then // caret_command -surface-foci-create $FIDUCIAL $TOPO $OUTFOCIPROJ // $OUTFOCIPROJ -focus SF_VentralFrontal -16 12 -19 // else // caret_command -surface-foci-create $FIDUCIAL $TOPO $OUTFOCIPROJ // $OUTFOCIPROJ -focus SF_VentralFrontal 16 12 -19 // fi float sfVentralFrontalNodeXYZ[3] = { 16.0, 12.0, -19.0 }; if (leftHemisphereFlag) { sfVentralFrontalNodeXYZ[0] *= -1.0; } sfVentralFrontalNodeNumber = fiducialSurface->getCoordinateFile()->getCoordinateIndexClosestToPoint( sfVentralFrontalNodeXYZ[0], sfVentralFrontalNodeXYZ[1], sfVentralFrontalNodeXYZ[2]); addFocusAtNode(sfVentralFrontalFocusName, sfVentralFrontalNodeNumber); if (DebugControl::getDebugOn()) { std::cout << sfVentralFrontalFocusName.toAscii().constData() << " node number is " << sfVentralFrontalNodeNumber << std::endl; } // // Set X-Coord for LEFT // // if [ $LEFT_FLAG -eq 1 ] // then // caret_command -surface-place-focus-at-extremum $FIDUCIAL $FIDUCIAL $TOPO // $OUTFOCIPROJ SF_VentralFrontal $OUTFOCIPROJ SF_VentralFrontalExtreme Z-NEG -100000.0 100000.0 100000.0 // else // caret_command -surface-place-focus-at-extremum $FIDUCIAL $FIDUCIAL $TOPO // $OUTFOCIPROJ SF_VentralFrontal $OUTFOCIPROJ SF_VentralFrontalExtreme Z-NEG 100000.0 100000.0 100000.0 // fi float sfVentralFrontalExtremeLimitX = 100000.0; if (leftHemisphereFlag) { sfVentralFrontalExtremeLimitX = -100000.0; } const int sfVentralFrontalExtremeNodeNumber = addFocusAtExtremum(fiducialSurface, sfVentralFrontalNodeNumber, BrainModelSurfaceFindExtremum::DIRECTION_Z_NEGATIVE, sfVentralFrontalExtremeLimitX, 100000.0, 100000.0, sfVentralFrontalExtremeFocusName); if (DebugControl::getDebugOn()) { std::cout << sfVentralFrontalExtremeFocusName.toAscii().constData() << " node number is " << sfVentralFrontalExtremeNodeNumber << std::endl; } // // Create ROI of fundal region // // caret_command -surface-region-of-interest-selection $INFLATED $TOPO // SUL.SF.roi SUL.SF.fundal.roi -shape // $SHAPE_INFLATED "Folding (Mean Curvature) INFLATED" -100.0 -0.05 AND // BrainModelSurfaceROINodeSelection sfFundalROI(sfROI); sfFundalROI.selectNodesWithMetric(BrainModelSurfaceROINodeSelection::SELECTION_LOGIC_AND, inflatedSurface, curvatureShapeFile, curvatureInflatedMeanColumnNumber, -100.0, -0.05); saveRoiToFile(sfFundalROI, sfFundalRoiFileName); // // Draw a border from SF-Anterior to SF-Ventral Frontal Extreme // // caret_command -surface-border-draw-geodesic $INFLATED $TOPO // $OUTFOCIPROJ SF_Anterior SF_VentralFrontalExtreme SUL.SF.fundal.roi // $OUTBORDERPROJ $OUTBORDERPROJ LANDMARK.SFant 1.0 /*drawBorderGeodesic(inflatedSurface, &sfFundalROI, sfAntLandmarkName, sfAnteriorDeepBelowNodeNumber, //sfAnteriorDeepNodeNumber, // sfAnteriorNodeNumber, sfVentralFrontalNodeNumber, //sfVentralFrontalExtremeNodeNumber, 1.0);*/ std::vector mynodes; mynodes.push_back(sfAnteriorDeepBelowNodeNumber); mynodes.push_back(sfVentralFrontalNodeNumber);//TSC: "extreme" node threw the border off with an anterior low extrema drawBorderMetricGeodesic(fiducialSurface, &sfFundalROI, sfAntLandmarkName, mynodes, 1.0, curvatureShapeFile, curvatureFiducialMeanColumnNumber,//curvatureFiducialSmoothedMeanColumnNumber ? 1.8f);//IMPORTANT: > 1 weight means prefer NEGATIVE (or simply smaller) values // // Merge the LANDMARK.SFdorsal and LANDMARK.SFant into // LANDMARK.SylvianFissure // // caret_command -surface-border-merge $OUTBORDERPROJ $OUTBORDERPROJ // LANDMARK.SylvianFissure LANDMARK.SFdorsal LANDMARK.SFant // -delete-input-border-projections -smooth-junctions $INFLATED $TOPO 4 1 // BorderProjection* sylvianFissureBorderProjection = mergeBorders(sylvianFissureLandmarkName, sfDorsalLandmarkName, sfAntLandmarkName, !(DebugControl::getDebugOn()), false, inflatedSurface, 0,//TSC: fix cases where 3d smoothing made holes (unprojection dropping links?), border drawing method is inherently smooth 1); if (DebugControl::getDebugOn()) { BorderProjection unnibbled = *sylvianFissureBorderProjection; unnibbled.setName("SF_Unnibbled"); BorderProjectionFile bpf; bpf.addBorderProjection(unnibbled); borderProjectionFile->append(bpf); const QString name(debugFilesDirectoryName + "/" + borderDebugFileName); try { borderProjectionFile->writeFile(name); } catch (FileException&) { std::cout << "WARNING: Unable to write landmark debug border projection file." << std::endl; } } // // Draw a border along secondary SF // Typically starts deep in the Sylvian Fissure, exits SF, and ends // near or in parietal lobe. // // caret_command -surface-border-draw-metric $INFLATED $TOPO // $SHAPE_INFLATED "Folding (Mean Curvature) INFLATED" NEGATIVE // $OUTFOCIPROJ SF_Inferior_Branch_Begin SF_Posterior // $OUTBORDERPROJ $OUTBORDERPROJ LANDMARK.SF-secondary 1.0 // // Try ellipsoid surface since as the border exits the posterior // part of the sylvian fissure on the inflated surface, it may need // to turn and go in an anterior direction briefly which causes // this drawing method to fail since the as the path is built, the // distance to the end node must always decrease. // drawBorderMetric(ellipsoidSurface, //inflatedSurface, BrainModelSurfaceROICreateBorderUsingMetricShape::MODE_FOLLOW_MOST_NEGATIVE, curvatureShapeFile, curvatureInflatedMeanColumnNumber, sfSecondaryLandmarkName, sfInferiorBranchBeginNodeNumber, sfDorsalNodeNumber, // JWH 10 April sfPosteriorNodeNumber, 1.0); // // Get intersection of Landmark.SF-secondary and LANDMARK.SylvianFissure // // caret_command -surface-border-intersection $INFLATED $TOPO // $OUTBORDERPROJ $OUTFOCIPROJ $OUTFOCIPROJ // LANDMARK.SF-secondary LANDMARK.SylvianFissure SF_Intersect_Superior_Inferior 3.0 // // The SF starts at the posterior and runs anterior. However, for this // intersection test, we want the most anterior point of the SF that // intersects. So, reverse the order of the points in the SF and then // flip them back after the intersection test. // float sfInsersectSuperiorInferiorXYZ[3]; BorderProjection* sfRev = borderProjectionFile->getLastBorderProjectionByName(sylvianFissureLandmarkName); sfRev->reverseOrderOfBorderProjectionLinks(); getBorderIntersection(ellipsoidSurface, //inflatedSurface, sylvianFissureLandmarkName, sfSecondaryLandmarkName, sfIntersectSuperiorInferiorFocusName, 3.0, 15.0, 1.0, sfInsersectSuperiorInferiorXYZ); sfRev->reverseOrderOfBorderProjectionLinks(); //return; // // Delete intermediate borders ? // // if [ "$REMOVE_INTERMEDIATE_BORDERS" == "YES" ] // then // caret_command -surface-border-delete $OUTBORDERPROJ $OUTBORDERPROJ // LANDMARK.SF-secondary // fi // if (DebugControl::getDebugOn() == false) { borderProjectionFile->removeBordersWithName(sfSecondaryLandmarkName); } // // Trim the sylvian fissure border for everything less than SF/IntSupInf // intersection point minus 12 in Y-axis // // caret_command -surface-border-nibbler $ELLIPSOID $TOPO // $OUTBORDERPROJ $OUTBORDERPROJ LANDMARK.SylvianFissure // LANDMARK.SylvianFissure $OUTFOCIPROJ SF_Intersect_Superior_Inferior // -less-than-y -12 // nibbleBorderWithinOffset(ellipsoidSurface, sylvianFissureLandmarkName, sfInsersectSuperiorInferiorXYZ, BORDER_NIBBLE_MODE_OFFSET_LESS_THAN_Y, -12.0); // // Trim any 10 mm of Z // // caret_command -surface-border-nibbler $INFLATED $TOPO // $OUTBORDERPROJ $OUTBORDERPROJ LANDMARK.SylvianFissure // LANDMARK.SylvianFissure $OUTFOCIPROJ SF_VentralFrontalExtreme // -within-z-distance 10 // nibbleBorderWithinDistance(inflatedSurface, sylvianFissureLandmarkName, sfVentralFrontalExtremeNodeNumber, BORDER_NIBBLE_MODE_DISTANCE_Z, 10.0); // // Trim away from SF Anterior Deep which should remove links that extend // too far at the posterior/dorsal end of the sylvina fissure // const float anteriorDistance = 87.0; //92.0; // 98.0 nibbleBorderBeyondDistance(inflatedSurface, sylvianFissureLandmarkName, inflatedSurface->getCoordinateFile()->getCoordinate(sfAnteriorDeepNodeNumber), BORDER_NIBBLE_MODE_DISTANCE_LINEAR, anteriorDistance); // // Resample the Sylvian Fissure // // caret_command -surface-border-resample $INFLATED $TOPO // $OUTBORDERPROJ $OUTBORDERPROJ 3.0 -border-name LANDMARK.SF // resampleBorder(fiducialSurface, sylvianFissureLandmarkName, 3.0); } /** * get intersection of two borders (returns true if intersection valid). */ bool BrainModelSurfaceBorderLandmarkIdentification::getBorderIntersection( const BrainModelSurface* borderSurface, const QString& border1Name, const QString& border2Name, const QString& intersectionFocusName, const float intersectionTolerance, float* itersectionXYZOut, int* border1IntersectionLinkNumberOut, int* border2IntersectionLinkNumberOut) throw (BrainModelAlgorithmException) { // // Find the borders // BorderProjection* bp1 = borderProjectionFile->getLastBorderProjectionByName(border1Name); if (bp1 == NULL) { throw BrainModelAlgorithmException("unable to find border named " + border1Name + " when finding intersection of " + border1Name + " and " + border2Name); } BorderProjection* bp2 = borderProjectionFile->getLastBorderProjectionByName(border2Name); if (bp2 == NULL) { throw BrainModelAlgorithmException("unable to find border named " " when finding intersection of " + border1Name + " and " + border2Name); } // // Create another border projection file containing just the two borders // BorderProjectionFile tempBorderProjFile; tempBorderProjFile.addBorderProjection(*bp1); tempBorderProjFile.addBorderProjection(*bp2); // // Unproject the two borders // BorderFile borderFile; BorderProjectionUnprojector unprojector; unprojector.unprojectBorderProjections(*(borderSurface->getCoordinateFile()), tempBorderProjFile, borderFile); if (borderFile.getNumberOfBorders() != 2) { throw BrainModelAlgorithmException("unprojection of borders failed" " when finding intersection of " + border1Name + " and " + border2Name); } // // Find intersection of two borders // const Border* border1 = borderFile.getBorder(0); const Border* border2 = borderFile.getBorder(1); int border1IntersectionLink, border2IntersectionLink; if (border1->intersection3D(border2, intersectionTolerance, border1IntersectionLink, border2IntersectionLink) == false) { throw BrainModelAlgorithmException("no intersection within tolerance" " when finding intersection of " + border1Name + " and " + border2Name); } // // Get coordinate of intersection // float intersectionXYZ[3]; border1->getLinkXYZ(border1IntersectionLink, intersectionXYZ); if (itersectionXYZOut != NULL) { itersectionXYZOut[0] = intersectionXYZ[0]; itersectionXYZOut[1] = intersectionXYZ[1]; itersectionXYZOut[2] = intersectionXYZ[2]; } // // Add a focus at border intersection // if (intersectionFocusName.isEmpty() == false) { addFocusAtXYZ(borderSurface, intersectionFocusName, intersectionXYZ); } if (border1IntersectionLinkNumberOut != NULL) { *border1IntersectionLinkNumberOut = border1IntersectionLink; } if (border2IntersectionLinkNumberOut != NULL) { *border2IntersectionLinkNumberOut = border2IntersectionLink; } return true; } /** * get intersection of two borders (returns true if intersection valid). */ bool BrainModelSurfaceBorderLandmarkIdentification::getBorderIntersection( const BrainModelSurface* borderSurface, const QString& border1Name, const QString& border2Name, const QString& intersectionFocusName, const float intersectionToleranceMinimum, const float intersectionToleranceMaximum, const float intersectionToleranceStep, float itersectionXYZOut[3]) throw (BrainModelAlgorithmException) { QString errorMessage; for (float tolerance = intersectionToleranceMinimum; tolerance <= intersectionToleranceMaximum; tolerance += intersectionToleranceStep) { bool valid = false; try { valid = getBorderIntersection(borderSurface, border1Name, border2Name, intersectionFocusName, tolerance, itersectionXYZOut); if (valid) { return true; } } catch (BrainModelAlgorithmException& e) { errorMessage = e.whatQString(); } } throw BrainModelAlgorithmException(errorMessage); } /** * merge borders (returned border was added to border projection file). */ BorderProjection* BrainModelSurfaceBorderLandmarkIdentification::mergeBorders( const QString& outputBorderName, const QString& border1Name, const QString& border2Name, const bool deleteInputBordersFlag, const bool closeBorderFlag, const BrainModelSurface* smoothingSurface, const int smoothingIterations, const int smoothingNeighbors) throw (BrainModelAlgorithmException) { BorderProjection* border1 = borderProjectionFile->getFirstBorderProjectionByName(border1Name); if (border1 == NULL) { throw BrainModelAlgorithmException("Border named " + border1Name + " missing when merging to create border named " + outputBorderName); } BorderProjection* border2 = borderProjectionFile->getFirstBorderProjectionByName(border2Name); if (border2 == NULL) { throw BrainModelAlgorithmException("Border named " + border2Name + " missing when merging to create border named " + outputBorderName); } // // Merge the border // BorderProjection outputBorderProjection(outputBorderName); outputBorderProjection.append(*border1); const int junctionIndex = outputBorderProjection.getNumberOfLinks(); outputBorderProjection.append(*border2); // // Delete input borders // if (deleteInputBordersFlag) { borderProjectionFile->removeBordersWithName(border1Name); borderProjectionFile->removeBordersWithName(border2Name); } // // Smooth the border // if ((smoothingSurface != NULL) && (smoothingIterations > 0) && (smoothingNeighbors > 0)) { // // Put new border projection in temporary border projection file // BorderProjectionFile tempBorderProjectionFile; tempBorderProjectionFile.addBorderProjection(outputBorderProjection); // // Unproject the border // BorderProjectionUnprojector unprojector; BorderFile tempBorderFile; unprojector.unprojectBorderProjections(*smoothingSurface->getCoordinateFile(), tempBorderProjectionFile, tempBorderFile); // // Get border // if (tempBorderFile.getNumberOfBorders() <= 0) { throw BrainModelAlgorithmException("Border unprojection error when merging " + border1Name + " and " + border2Name + " into " + outputBorderName); } // // Get links for smoothing // Border* b = tempBorderFile.getBorder(0); const int numLinks = b->getNumberOfLinks(); std::vector smoothFlags(numLinks, true); if ((junctionIndex >= 0) && (junctionIndex < numLinks)) { smoothFlags[junctionIndex] = false; } // // Smooth the border // b->smoothBorderLinks(smoothingIterations, closeBorderFlag, &smoothFlags); // // Reproject the border // tempBorderProjectionFile.clear(); BorderFileProjector projector(inflatedSurface, true); projector.projectBorderFile(&tempBorderFile, &tempBorderProjectionFile, NULL); // // Add border projection to output file // if (tempBorderProjectionFile.getNumberOfBorderProjections() <= 0) { throw BrainModelAlgorithmException("Border reprojection error when merging " + border1Name + " and " + border2Name + " into " + outputBorderName); } borderProjectionFile->addBorderProjection( *tempBorderProjectionFile.getBorderProjection(0)); } else { // // Add border projection to output file // borderProjectionFile->addBorderProjection(outputBorderProjection); } return borderProjectionFile->getBorderProjection( borderProjectionFile->getNumberOfBorderProjections() - 1); } /** * merge borders (returned border was added to border projection file). */ BorderProjection* BrainModelSurfaceBorderLandmarkIdentification::mergeBorders( const QString& outputBorderName, const std::vector& borderNames, const bool deleteInputBordersFlag, const bool closeBorderFlag, const BrainModelSurface* smoothingSurface, const int smoothingIterations, const int smoothingNeighbors) throw (BrainModelAlgorithmException) { BorderProjection outputBorderProjection(outputBorderName); const int numBorders = static_cast(borderNames.size()); std::vector junctionIndices; std::vector borders; for (int i = 0; i < numBorders; i++) { BorderProjection* bp = borderProjectionFile->getFirstBorderProjectionByName(borderNames[i]); if (bp == NULL) { throw BrainModelAlgorithmException("Border named " + borderNames[i] + " missing when merging to create border named " + outputBorderName); } outputBorderProjection.append(*bp); junctionIndices.push_back(outputBorderProjection.getNumberOfLinks()); } // // Delete input borders // if (deleteInputBordersFlag) { for (int i = 0; i < numBorders; i++) { borderProjectionFile->removeBordersWithName(borderNames[i]); } } // // Smooth the border // if ((smoothingSurface != NULL) && (smoothingIterations > 0) && (smoothingNeighbors > 0)) { // // Put new border projection in temporary border projection file // BorderProjectionFile tempBorderProjectionFile; tempBorderProjectionFile.addBorderProjection(outputBorderProjection); // // Unproject the border // BorderProjectionUnprojector unprojector; BorderFile tempBorderFile; unprojector.unprojectBorderProjections(*smoothingSurface->getCoordinateFile(), tempBorderProjectionFile, tempBorderFile); // // Get border // if (tempBorderFile.getNumberOfBorders() <= 0) { throw BrainModelAlgorithmException( " Error getting border after projection when assembling " + outputBorderName); } // // Get links for smoothing // Border* b = tempBorderFile.getBorder(0); const int numLinks = b->getNumberOfLinks(); std::vector smoothFlags(numLinks, true); for (int i = 0; i < numBorders - 1; i++) { smoothFlags[junctionIndices[i]] = false; } // // Smooth the border // b->smoothBorderLinks(smoothingIterations, closeBorderFlag, &smoothFlags); // // Reproject the border // tempBorderProjectionFile.clear(); BorderFileProjector projector(inflatedSurface, true); projector.projectBorderFile(&tempBorderFile, &tempBorderProjectionFile, NULL); // // Add border projection to output file // if (tempBorderProjectionFile.getNumberOfBorderProjections() <= 0) { throw BrainModelAlgorithmException("Border reprojection error when merging " " into " + outputBorderName); } borderProjectionFile->addBorderProjection( *tempBorderProjectionFile.getBorderProjection(0)); } else { // // Add border projection to output file // borderProjectionFile->addBorderProjection(outputBorderProjection); } return borderProjectionFile->getBorderProjection( borderProjectionFile->getNumberOfBorderProjections() - 1); } /** * identify the superior temporal gyrus. */ void BrainModelSurfaceBorderLandmarkIdentification::identifySuperiorTemporalGyrus() throw (BrainModelAlgorithmException) { // // Names of items // const QString sfStsAntLandmarkBorderName("LANDMARK.SF_STSant"); const QString stgStsInflateVentralFocusName("STS_Inflated_Ventral"); const QString stgStsInflatedDorsalFocusName("STS_Inflated_Dorsal"); const QString stgTemporalPoleFocusName("TemporalPole"); const QString stgPosteriorFocusName("STG-posterior"); const QString stgCesLimitFocusName("STG-CES-limit"); const QString stgDorsalLandmarkFocusName("STG-dorsal-Landmark"); const QString stgVentralLandmarkFocusName("STG-ventral-Landmark"); const QString stgGenericColorName("STG"); const QString stgRoiFileName(createFileName("STG", SpecFile::getRegionOfInterestFileExtension())); const QString stsRoiFileName(createFileName("STS", SpecFile::getRegionOfInterestFileExtension())); const QString stgGyralRoiFileName(createFileName("GyralSTG", SpecFile::getRegionOfInterestFileExtension())); const QString stgGyralPaintName("GYRAL.STG"); // // Remove ROI files // QFile::remove(stgRoiFileName); QFile::remove(stsRoiFileName); QFile::remove(stgGyralRoiFileName); // caret_command -color-file-add-color $FOCICOLOR $FOCICOLOR // STS_Inflated_Ventral 0 150 255 -point-size 3 -symbol SPHERE addFocusColor(stgStsInflateVentralFocusName, 0, 150, 255); // caret_command -color-file-add-color $FOCICOLOR $FOCICOLOR // STS_Inflated_Dorsal 0 150 255 -point-size 3 -symbol SPHERE addFocusColor(stgStsInflatedDorsalFocusName, 0, 150, 255); // caret_command -color-file-add-color $FOCICOLOR $FOCICOLOR // TemporalPole 100 0 200 -point-size 3 -symbol SPHERE addFocusColor(stgTemporalPoleFocusName, 100, 0, 200); // caret_command -color-file-add-color $FOCICOLOR $FOCICOLOR // STG-posterior 0 150 255 -point-size 3 -symbol SPHERE addFocusColor(stgPosteriorFocusName, 0, 150, 255); // caret_command -color-file-add-color $FOCICOLOR $FOCICOLOR // STG-ventral 0 150 255 -point-size 3 -symbol SPHERE addFocusColor(stgVentralLandmarkFocusName, 0, 150, 255); // caret_command -color-file-add-color $FOCICOLOR $FOCICOLOR // STG 100 255 150 -point-size 3 -symbol SPHERE addFocusColor(stgGenericColorName, 100, 255, 150); // // Delete foci // // caret_command -surface-foci-delete $OUTFOCIPROJ $OUTFOCIPROJ // STS_Inflated_Ventral STS_Inflated_Dorsal TemporalPole STG-posterior // STG-CES-limit STG-dorsal-Landmark STG-ventral-Landmark fociProjectionFile->deleteCellProjectionsWithName(stgStsInflateVentralFocusName); fociProjectionFile->deleteCellProjectionsWithName(stgStsInflatedDorsalFocusName); fociProjectionFile->deleteCellProjectionsWithName(stgTemporalPoleFocusName); fociProjectionFile->deleteCellProjectionsWithName(stgPosteriorFocusName); fociProjectionFile->deleteCellProjectionsWithName(stgCesLimitFocusName); fociProjectionFile->deleteCellProjectionsWithName(stgDorsalLandmarkFocusName); fociProjectionFile->deleteCellProjectionsWithName(stgVentralLandmarkFocusName); // // Delete the border // // caret_command -surface-border-delete $OUTBORDERPROJ LANDMARK.SF_STSant // borderProjectionFile->removeBordersWithName(sfStsAntLandmarkBorderName); // // Add border color // // caret_command -color-file-add-color $BORDERCOLOR $BORDERCOLOR // LANDMARK.SF_STSant 255 0 187 -point-size 3 -symbol SPHERE // borderColorFile->addColor(sfStsAntLandmarkBorderName, 255, 0, 187, 255, 3, 1, ColorFile::ColorStorage::SYMBOL_SPHERE); // // Create an ROI of the Superior Temporal Sulcus // // caret_command -surface-region-of-interest-selection $INFLATED $TOPO // Human.$SUBJECT.$HEM.STG.roi Human.$SUBJECT.$HEM.STG.roi // -paint Human.$SUBJECT.$HEM.SulcalID.paint "Sulcus ID" SUL.STS NORMAL // BrainModelSurfaceROINodeSelection stsROI(brainSet); QString errorMessage = stsROI.selectNodesWithPaint( BrainModelSurfaceROINodeSelection::SELECTION_LOGIC_NORMAL, inflatedSurface, paintFile, paintFileSulcusIdColumnNumber, "SUL.STS"); if (errorMessage.isEmpty() == false) { throw BrainModelAlgorithmException(errorMessage); } saveRoiToFile(stsROI, stsRoiFileName); // // Get the extent of the ROI // int minXNode, maxXNode, minYNode, maxYNode, minZNode, maxZNode; int mostMedialXNode, mostLateralXNode; int absMinXNode, absMaxXNode, absMinYNode, absMaxYNode, absMinZNode, absMaxZNode; stsROI.getNodesWithMinMaxXYZValues(inflatedSurface, mostMedialXNode, mostLateralXNode, minXNode, maxXNode, minYNode, maxYNode, minZNode, maxZNode, absMinXNode, absMaxXNode, absMinYNode, absMaxYNode, absMinZNode, absMaxZNode); // // Get node number and place foci at Z-Min and Z-Max of the ROI // // caret_command -surface-place-foci-at-limits $FIDUCIAL $INFLATED $TOPO // Human.$SUBJECT.$HEM.STG.roi $OUTFOCIPROJ $OUTFOCIPROJ // -z-min STS_Inflated_Ventral // -z-max STS_Inflated_Dorsal const int stsInflatedVentralNodeNumber = minZNode; addFocusAtNode(stgStsInflateVentralFocusName, stsInflatedVentralNodeNumber); const int stsInflatedDorsalNodeNumber = maxZNode; addFocusAtNode(stgStsInflatedDorsalFocusName, stsInflatedDorsalNodeNumber); // // // // caret_command -surface-place-focus-at-extremum $FIDUCIAL $INFLATED $TOPO // $OUTFOCIPROJ STS_Inflated_Ventral $OUTFOCIPROJ TemporalPole // Y-POS 100000.0 100000.0 100000.0 temporalPoleNodeNumber = addFocusAtExtremum(inflatedSurface, stsInflatedVentralNodeNumber, BrainModelSurfaceFindExtremum::DIRECTION_Y_POSITIVE, 100000.0, 100000.0, 100000.0, stgTemporalPoleFocusName); fiducialSurface->getCoordinateFile()->getCoordinate(temporalPoleNodeNumber, fiducialSurfaceTemporalPoleXYZ); inflatedSurface->getCoordinateFile()->getCoordinate(temporalPoleNodeNumber, inflatedSurfaceTemporalPoleXYZ); // // Create a matrix for rotating surface +/- 45 degrees // // # // # Left surface needs to rotate POSITIVE 45 degrees // # // if [ $LEFT_FLAG -eq 1 ] // then // caret_command -transformation-matrix-create TempRotateYMinus45.matrix // TempRotateYMinus45.matrix RotateYMinus45 -delete-all-matrices-from-file // -matrix-comment "rotate minus 45 degrees about Y-axis" // -rotate 0.0 45.0 0.0 // else // caret_command -transformation-matrix-create TempRotateYMinus45.matrix // TempRotateYMinus45.matrix RotateYMinus45 -delete-all-matrices-from-file // -matrix-comment "rotate minus 45 degrees about Y-axis" // -rotate 0.0 -45.0 0.0 // fi TransformationMatrix matrix45; if (leftHemisphereFlag) { matrix45.rotateZ(0.0); matrix45.rotateX(0.0); matrix45.rotateY(45.0); } else { matrix45.rotateZ(0.0); matrix45.rotateX(0.0); matrix45.rotateY(-45.0); } // // Create a new inflated surface // // caret_command -surface-apply-transformation-matrix $INFLATED $TOPO // temp.rotatedY45.coord -matrix-file TempRotateYMinus45.matrix RotateYMinus45 // BrainModelSurface inflatedRotate45Surface(*inflatedSurface); inflatedRotate45Surface.applyTransformationMatrix(matrix45); // // Find the extremum by moving in the Z-direction which should // end at the posterior part of the sylvian fissure // // caret_command -surface-place-focus-at-extremum $FIDUCIAL temp.rotatedY45.coord // $TOPO $OUTFOCIPROJ TemporalPole $OUTFOCIPROJ STG-posterior // Z-POS 100000.0 100000.0 100000.0 -create-roi-from-path // Human.$SUBJECT.$HEM.STG.roi // BrainModelSurfaceROINodeSelection stgROI(brainSet); //const int stgPosteriorNodeNumber = addFocusAtExtremum(&inflatedRotate45Surface, temporalPoleNodeNumber, BrainModelSurfaceFindExtremum::DIRECTION_Z_POSITIVE, 100000.0, 100000.0, 100000.0, stgPosteriorFocusName, &stgROI); saveRoiToFile(stgROI, stgRoiFileName); // // Get extents of STG roi // stgROI.getNodesWithMinMaxXYZValues(inflatedSurface, mostMedialXNode, mostLateralXNode, minXNode, maxXNode, minYNode, maxYNode, minZNode, maxZNode, absMinXNode, absMaxXNode, absMinYNode, absMaxYNode, absMinZNode, absMaxZNode); // // Limit the extent of the STG ROI // // caret_command -surface-region-of-interest-selection $INFLATED $TOPO // Human.$SUBJECT.$HEM.STG.roi Human.$SUBJECT.$HEM.STG.roi -limit-y-min-focus // $OUTFOCIPROJ CeS-ventral -limit-y-max-focus $OUTFOCIPROJ TemporalPole // -limit-z-min-focus $OUTFOCIPROJ TemporalPole const float stgROIExtent[6] = { -std::numeric_limits::max(), std::numeric_limits::max(), inflatedSurfaceCentralSulcusVentralTipXYZ[1], inflatedSurfaceTemporalPoleXYZ[1], inflatedSurfaceTemporalPoleXYZ[2], std::numeric_limits::max(), }; stgROI.limitExtent(inflatedSurface, stgROIExtent); saveRoiToFile(stgROI, stgRoiFileName); // // Get extents of STG roi // stgROI.getNodesWithMinMaxXYZValues(inflatedSurface, mostMedialXNode, mostLateralXNode, minXNode, maxXNode, minYNode, maxYNode, minZNode, maxZNode, absMinXNode, absMaxXNode, absMinYNode, absMaxYNode, absMinZNode, absMaxZNode); // // Place a focus at the Y-Min of the ROI which is STG-CES-limit // // caret_command -surface-place-foci-at-limits $FIDUCIAL $INFLATED $TOPO // Human.$SUBJECT.$HEM.STG.roi $OUTFOCIPROJ $OUTFOCIPROJ -y-min STG-CES-limit // const int stgCesLimitNodeNumber = minYNode; addFocusAtNode(stgCesLimitFocusName, stgCesLimitNodeNumber); // // Draw a border from STG-CES-limit to the temporal pole // // caret_command -surface-border-draw-geodesic $INFLATED $TOPO $OUTFOCIPROJ // STG-CES-limit TemporalPole Human.$SUBJECT.$HEM.STG.roi // $OUTBORDERPROJ $OUTBORDERPROJ LANDMARK.SF_STSant 1.0 if (DebugControl::getDebugOn()) { std::cout << "STG Landmark CeS Limit node: " << stgCesLimitNodeNumber << std::endl; std::cout << "STG Landmark Temporal Pole node: " << temporalPoleNodeNumber << std::endl; } drawBorderGeodesic(inflatedSurface, &stgROI, sfStsAntLandmarkBorderName, stgCesLimitNodeNumber, temporalPoleNodeNumber, 3.0); // // Resample to coarse spacing // resampleBorder(fiducialSurface, sfStsAntLandmarkBorderName, 8.0); BorderProjection* stgBorder = borderProjectionFile->getFirstBorderProjectionByName(sfStsAntLandmarkBorderName); // // Move each link in the border so that it moves up onto the // top of the ridge which should be the true crown of the STG // const int numLinks = stgBorder->getNumberOfLinks(); const int halfNumLinks = numLinks / 2; for (int i = 1; i < (numLinks - 1); i++) { BorderProjectionLink* bpl = stgBorder->getBorderProjectionLink(i); int section; int vertices[3]; float areas[3]; float radius; bpl->getData(section, vertices, areas, radius); const float xMovement = (i >= halfNumLinks) ? 10.0 : 4.0; const int nodeNumber = addFocusAtExtremum(fiducialSurface, vertices[0], BrainModelSurfaceFindExtremum::DIRECTION_Z_POSITIVE, xMovement, 1.0, 10000.0, ""); vertices[0] = nodeNumber; vertices[1] = nodeNumber; vertices[2] = nodeNumber; areas[0] = 1.0; areas[1] = 0.0; areas[2] = 0.0; bpl->setData(section, vertices, areas, radius); } resampleBorder(fiducialSurface, sfStsAntLandmarkBorderName, 3.0); //-------------------------------------------------------------------------- // // The following code creates the STG Paint // // // Place foci at ends of STG border // // caret_command -surface-border-link-to-focus $FIDUCIAL $TOPO $OUTBORDERPROJ // LANDMARK.SF_STSant $OUTFOCIPROJ $OUTFOCIPROJ -first-link STG-dorsal-Landmark // caret_command -surface-border-link-to-focus $FIDUCIAL $TOPO $OUTBORDERPROJ // LANDMARK.SF_STSant $OUTFOCIPROJ $OUTFOCIPROJ -last-link STG-ventral-Landmark const BorderProjection* stgBP = borderProjectionFile->getFirstBorderProjectionByName(sfStsAntLandmarkBorderName); if (stgBP != NULL) { addFocusAtBorderLink(stgBP, 0, stgDorsalLandmarkFocusName); addFocusAtBorderLink(stgBP, stgBP->getNumberOfLinks() - 1, stgVentralLandmarkFocusName); } // // Create an ROI that identifies the STG // // caret_command -surface-region-of-interest-selection $INFLATED $TOPO // Human.$SUBJECT.$HEM.STG.roi Human.$SUBJECT.$HEM.STG.roi // -dilate-paint Human.$SUBJECT.$HEM.SulcalID.paint "Sulcus ID" SUL.SF 5 // -dilate-paint Human.$SUBJECT.$HEM.SulcalID.paint "Sulcus ID" GYRAL 5 // -limit-y-min-focus $OUTFOCIPROJ CeS-ventral // -limit-y-max-focus $OUTFOCIPROJ TemporalPole // -limit-z-min-focus $OUTFOCIPROJ TemporalPole // BrainModelSurfaceROINodeSelection stgGyralROI(stgROI); stgGyralROI.dilatePaintConstrained(inflatedSurface, paintFile, paintFileSulcusIdColumnNumber, "SUL.SF", 5); stgGyralROI.dilatePaintConstrained(inflatedSurface, paintFile, paintFileSulcusIdColumnNumber, "GYRAL", 5); const float stgGyralROIExtent[6] = { -std::numeric_limits::max(), std::numeric_limits::max(), inflatedSurfaceCentralSulcusVentralTipXYZ[1], inflatedSurfaceTemporalPoleXYZ[1], inflatedSurfaceTemporalPoleXYZ[2], std::numeric_limits::max(), }; stgGyralROI.limitExtent(inflatedSurface, stgGyralROIExtent); saveRoiToFile(stgGyralROI, stgGyralRoiFileName); // // Color for Gyral.STG // areaColorFile->addColor(stgGyralPaintName, 200, 0, 255); vocabularyFile->addVocabularyEntry( VocabularyFile::VocabularyEntry(stgGyralPaintName, "Superior Temporal Gyrus")); // // Use the gryal ROI to paint the STG // // ###caret_command -paint-assign-to-nodes Human.$SUBJECT.$HEM.SulcalID.paint Human.$SUBJECT.$HEM.SulcalID_withSTG.paint "Sulcus ID" GYRAL.STG -assign-from-roi-file Human.$SUBJECT.$HEM.STG.roi // caret_command -paint-assign-to-nodes Human.$SUBJECT.$HEM.SulcalID.paint // $SULCAL_ID_PAINT "Sulcus ID" GYRAL.STG -assign-from-roi-file // Human.$SUBJECT.$HEM.STG.roi NodeRegionOfInterestFile roiStgFile; stgGyralROI.setRegionOfInterestIntoFile(roiStgFile); try { paintFile->assignNodesFromROIFile(paintFileSulcusIdColumnNumber, roiStgFile, stgGyralPaintName, true); } catch (FileException& e) { throw BrainModelAlgorithmException(e); } const float fullExtent[6] = { -std::numeric_limits::max(), std::numeric_limits::max(), -std::numeric_limits::max(), std::numeric_limits::max(), -std::numeric_limits::max(), std::numeric_limits::max(), }; paintFile->dilatePaintID(fiducialSurface->getTopologyFile(), fiducialSurface->getCoordinateFile(), paintFileSulcusIdColumnNumber, 5, paintFile->getPaintIndexFromName(stgGyralPaintName), paintFile->getPaintIndexFromName("???"), fullExtent); } /** * identify the calcarine sulcus. */ void BrainModelSurfaceBorderLandmarkIdentification::identifyCalcarineSulcus() throw (BrainModelAlgorithmException) { // // Names of items // const QString calcarinePosteriorFocusName("CaS-posterior"); const QString calcarineAnteriorFocusName("CaS-anterior"); const QString calcarinePosteriorExtremeFocusName("CaS-PosteriorExtreme"); const QString calcarineRoiFileName(createFileName("Cas", SpecFile::getRegionOfInterestFileExtension())); const QString calcarineStringentRoiFileName(createFileName("CaS_Stringent", SpecFile::getRegionOfInterestFileExtension())); // // Remove ROI files // QFile::remove(calcarineRoiFileName); QFile::remove(calcarineStringentRoiFileName); // // Add some foci colors // // caret_command -color-file-add-color $FOCICOLOR $FOCICOLOR CaS-posterior // 0 150 255 -point-size 3 -symbol SPHERE // caret_command -color-file-add-color $FOCICOLOR $FOCICOLOR CaS-anterior // 0 150 255 -point-size 3 -symbol SPHERE // caret_command -color-file-add-color $FOCICOLOR $FOCICOLOR CaS-PosteriorExtreme // 0 255 0 -point-size 3 -symbol SPHERE // addFocusColor(calcarinePosteriorFocusName, 0, 150, 255); addFocusColor(calcarineAnteriorFocusName, 0, 155, 255); addFocusColor(calcarinePosteriorExtremeFocusName, 0, 255, 0); // // Add a border color for the landmark // // caret_command -color-file-add-color $BORDERCOLOR $BORDERCOLOR // LANDMARK.CalcarineSulcus 246 114 0 // borderColorFile->addColor(calcarineSulcusLandmarkName, 246, 114, 0, 255, 2, 1, ColorFile::ColorStorage::SYMBOL_SPHERE); // // Delete any previously created foci // // caret_command -surface-foci-delete $OUTFOCIPROJ CaS-anterior CaS-posterior // CaS-PosteriorExtreme CaS-anterior-Landmark CaS-posterior-Landmark // fociProjectionFile->deleteCellProjectionsWithName(calcarinePosteriorFocusName); fociProjectionFile->deleteCellProjectionsWithName(calcarineAnteriorFocusName); fociProjectionFile->deleteCellProjectionsWithName(calcarinePosteriorExtremeFocusName); // // Delete previously created border // // caret_command -surface-border-delete $OUTBORDERPROJ LANDMARK.CalcarineSulcus // borderProjectionFile->removeBordersWithName(calcarineSulcusLandmarkName); // // Create an ROI of the Calcarine Suclus with inflated surface curvature // // caret_command -surface-region-of-interest-selection $INFLATED $TOPO // Human.$SUBJECT.$HEM.CaS.roi Human.$SUBJECT.$HEM.CaS.roi // -paint Human.$SUBJECT.$HEM.SulcalID.paint "Sulcus ID" SUL.CaS NORMAL // -shape $SHAPE_INFLATED "Folding (Mean Curvature) INFLATED" -100.0 -0.07 AND BrainModelSurfaceROINodeSelection calcarineROI(brainSet); QString errorMessage = calcarineROI.selectNodesWithPaint( BrainModelSurfaceROINodeSelection::SELECTION_LOGIC_NORMAL, inflatedSurface, paintFile, paintFileSulcusIdColumnNumber, "SUL.CaS"); if (errorMessage.isEmpty() == false) { throw BrainModelAlgorithmException(errorMessage); } errorMessage = calcarineROI.selectNodesWithSurfaceShape( BrainModelSurfaceROINodeSelection::SELECTION_LOGIC_AND, inflatedSurface, curvatureShapeFile, curvatureInflatedMeanColumnNumber, -100.0, -0.07); if (errorMessage.isEmpty() == false) { throw BrainModelAlgorithmException(errorMessage); } saveRoiToFile(calcarineROI, calcarineRoiFileName); // // Get nodes at min/max geometric values of the ROI // int minXNode, maxXNode, minYNode, maxYNode, minZNode, maxZNode; int mostMedialXNode, mostLateralXNode; int absMinXNode, absMaxXNode, absMinYNode, absMaxYNode, absMinZNode, absMaxZNode; calcarineROI.getNodesWithMinMaxXYZValues(inflatedSurface, mostMedialXNode, mostLateralXNode, minXNode, maxXNode, minYNode, maxYNode, minZNode, maxZNode, absMinXNode, absMaxXNode, absMinYNode, absMaxYNode, absMinZNode, absMaxZNode); // // Identify some limits of the Calcarine Sulcus ROI // // caret_command -surface-place-foci-at-limits $FIDUCIAL $INFLATED $TOPO // Human.$SUBJECT.$HEM.CaS.roi $OUTFOCIPROJ $OUTFOCIPROJ -y-max CaS-anterior // -y-min CaS-posterior // calcarineAnteriorNodeNumber = maxYNode; addFocusAtNode(calcarineAnteriorFocusName, calcarineAnteriorNodeNumber); const int calcarinePosteriorNodeNumber = minYNode; addFocusAtNode(calcarinePosteriorFocusName, calcarinePosteriorNodeNumber); if (DebugControl::getDebugOn()) { std::cout << "Calcarine Anterior Node Number: " << calcarineAnteriorNodeNumber << std::endl; std::cout << "Calcarine Posterior Node Number: " << calcarinePosteriorNodeNumber << std::endl; } // // Create a more stringent ROI of the Calcarine Suclus with fiducial curvature // Try inflated curvature, JWH 24 March 2008 // // caret_command -surface-region-of-interest-selection $INFLATED $TOPO // Human.$SUBJECT.$HEM.CaS_Stringent.roi Human.$SUBJECT.$HEM.CaS_Stringent.roi // -paint Human.$SUBJECT.$HEM.SulcalID.paint "Sulcus ID" SUL.CaS NORMAL // -shape $SHAPE_OUT "Folding (Mean Curvature)" -100.0 -0.16 AND // BrainModelSurfaceROINodeSelection calcarineStringentROI(brainSet); errorMessage = calcarineStringentROI.selectNodesWithPaint( BrainModelSurfaceROINodeSelection::SELECTION_LOGIC_NORMAL, inflatedSurface, paintFile, paintFileSulcusIdColumnNumber, "SUL.CaS"); if (errorMessage.isEmpty() == false) { throw BrainModelAlgorithmException(errorMessage); } errorMessage = calcarineStringentROI.selectNodesWithSurfaceShape( BrainModelSurfaceROINodeSelection::SELECTION_LOGIC_AND, inflatedSurface, curvatureShapeFile, curvatureInflatedMeanColumnNumber, //curvatureFiducialMeanColumnNumber, -100.0, -0.16); if (errorMessage.isEmpty() == false) { throw BrainModelAlgorithmException(errorMessage); } saveRoiToFile(calcarineStringentROI, calcarineStringentRoiFileName); // // Try drawing the border with geodesic method // const QString testNameGeo(calcarineSulcusLandmarkName); //borderColorFile->addColor(testNameGeo, // 0, 100, 220, 255, // 3, 1, // ColorFile::ColorStorage::SYMBOL_SPHERE); const QString casSegment2("CaS-Segment2"); drawBorderGeodesic(inflatedSurface, &calcarineStringentROI, casSegment2, calcarinePosteriorNodeNumber, calcarineAnteriorNodeNumber, 2.0); // caret_command -surface-place-focus-at-extremum $FIDUCIAL $INFLATED $TOPO // $OUTFOCIPROJ CaS-posterior $OUTFOCIPROJ CaS-PosteriorExtreme Y-NEG // 100000.0 100000.0 100000.0 // calcarinePosteriorExtremeNodeNumber = addFocusAtExtremum(inflatedSurface, calcarinePosteriorNodeNumber, BrainModelSurfaceFindExtremum::DIRECTION_Y_NEGATIVE, 100000.0, 100000.0, 100000.0, calcarinePosteriorExtremeFocusName); // // All nodes in ROI // BrainModelSurfaceROINodeSelection allNodesCaS(brainSet); allNodesCaS.selectAllNodes(inflatedSurface); // // Draw border from posterior extreme to posterior // const QString casSegment1("CaS-Segment1"); drawBorderGeodesic(inflatedSurface, &allNodesCaS, casSegment1, calcarinePosteriorExtremeNodeNumber, calcarinePosteriorNodeNumber, 2.0); mergeBorders(calcarineSulcusLandmarkName, casSegment1, casSegment2, true, false, inflatedSurface, 5, 1); // // Trim the calcarine at the posterior // // caret_command -surface-border-nibbler $INFLATED $TOPO $OUTBORDERPROJ // $OUTBORDERPROJ LANDMARK.CalcarineSulcus LANDMARK.CalcarineSulcus // $OUTFOCIPROJ CaS-PosteriorExtreme -within-y-distance 24 // nibbleBorderWithinDistance(inflatedSurface, calcarineSulcusLandmarkName, calcarinePosteriorExtremeNodeNumber, BORDER_NIBBLE_MODE_DISTANCE_Y, 24.0); } /** * extend the calcarine sulcus to the medial wall. */ void BrainModelSurfaceBorderLandmarkIdentification::extendCalcarineSulcusToMedialWall() throw (BrainModelAlgorithmException) { // // Get the border projection // BorderProjection* calcarineBorderProjection = borderProjectionFile->getLastBorderProjectionByName(calcarineSulcusLandmarkName); if (calcarineBorderProjection == NULL) { throw BrainModelAlgorithmException("Unable to find calcarine border named \"" + calcarineSulcusLandmarkName + "\" for extension of calcarine sulcus."); } const BorderProjection* medialWallProjection = borderProjectionFile->getLastBorderProjectionByName(getFlattenMedialWallBorderName()); if (medialWallProjection == NULL) { throw BrainModelAlgorithmException("Unable to find medial wall border named \"" + getFlattenMedialWallBorderName() + "\" for extension of calcarine sulcus."); } // // Place the border projection in a temporary file // BorderProjectionFile tempBorderProjectionFile; tempBorderProjectionFile.addBorderProjection(*calcarineBorderProjection); tempBorderProjectionFile.addBorderProjection(*medialWallProjection); // // Unproject the border // BorderProjectionUnprojector unprojector; BorderFile tempBorderFile; unprojector.unprojectBorderProjections(*(inflatedSurface->getCoordinateFile()), tempBorderProjectionFile, tempBorderFile); // // Get the borders // const Border* tempCalcarineBorder = tempBorderFile.getBorderByName(calcarineSulcusLandmarkName); if (tempCalcarineBorder == NULL) { throw BrainModelAlgorithmException("Unable to find calcarine border after unprojection during calcarine extension."); } Border* tempMedialWallBorder = tempBorderFile.getBorderByName(getFlattenMedialWallBorderName()); if (tempMedialWallBorder == NULL) { throw BrainModelAlgorithmException("Unable to find medial wall border after unprojection during calcarine extension."); } // // Get last link of calcarine // if (tempCalcarineBorder->getNumberOfLinks() <= 0) { throw BrainModelAlgorithmException("calcarine border contains no links after unprojection during calcarine extension."); } const float* calcarineLastXYZ = tempCalcarineBorder->getLinkXYZ(tempCalcarineBorder->getNumberOfLinks() - 1); const float calcarineZ = calcarineLastXYZ[2]; // // Find posterior link in medial wall near Y of last calcarine link // int nearestLinkNumber = -1; float nearestLinkDistance = 10000000.0; const int numMedialWallLinks = tempMedialWallBorder->getNumberOfLinks(); for (int i = 0; i < numMedialWallLinks; i++) { const float* xyz = tempMedialWallBorder->getLinkXYZ(i); if (xyz[1] < -15.0) { const float dz = std::fabs(xyz[2] - calcarineZ); if (dz < nearestLinkDistance) { nearestLinkDistance = dz; nearestLinkNumber = i; } } } // // Was a medial wall link NOT found // if (nearestLinkNumber < 0) { throw BrainModelAlgorithmException("Unable to find medial wall border link near calcarine during calcarine extension."); } // // Find nearest node a little posterior of medial wall // float linkXYZ[3]; tempMedialWallBorder->getLinkXYZ(nearestLinkNumber, linkXYZ); // JWH 12jan2009, trim after splitting medial int dorsal/ventral linkXYZ[1] -= 3.0; const int nodeNumber = inflatedSurface->getCoordinateFile()->getCoordinateIndexClosestToPoint( linkXYZ[0], linkXYZ[1], linkXYZ[2]); // // Add additional link to border // const int nodeNumbers[3] = { nodeNumber, nodeNumber, nodeNumber }; const float areas[3] = { 1.0, 0.0, 0.0 }; BorderProjectionLink newBPL(0, nodeNumbers, areas, 0.00); calcarineBorderProjection->addBorderProjectionLink(newBPL); // // Resample // resampleBorder(veryInflatedSurface, calcarineSulcusLandmarkName, 2.0); } /** * identify the medial wall. */ void BrainModelSurfaceBorderLandmarkIdentification::identifyMedialWall() throw (BrainModelAlgorithmException) { // // Remove existing flatten medial wall // borderProjectionFile->removeBordersWithName(getFlattenMedialWallBorderName()); // // Create color for medial wall segments and flatten medial wall // borderColorFile->addColor("LANDMARK.MedialWall", 255, 0, 0); borderColorFile->addColor(getFlattenMedialWallBorderName(), 255, 50, 50); // // Identify the dorsal and medial sections // identifyDorsalMedialWallNew(); //identifyDorsalMedialWallOld(); identifyVentralMedialWall(); // depends upon dorsal medial wall // // Merge the dorsal and ventral segments of the landmark medial wall // to create the flatten medial wall // BorderProjection medialWallTempBorder(getFlattenMedialWallBorderName()); medialWallTempBorder.append( *borderProjectionFile->getFirstBorderProjectionByName( medialWallDorsalSectionName)); medialWallTempBorder.append( *borderProjectionFile->getFirstBorderProjectionByName( medialWallVentralSectionName)); borderProjectionFile->addBorderProjection(medialWallTempBorder); // // Remove dorsal and ventral sections // borderProjectionFile->removeBordersWithName(medialWallDorsalSectionName); borderProjectionFile->removeBordersWithName(medialWallVentralSectionName); // // Resample the medial wall border // resampleBorder(fiducialSurface, getFlattenMedialWallBorderName(), 2.0); } /** * create medial wall dorsal and ventral borders. */ void BrainModelSurfaceBorderLandmarkIdentification::createMedialWallDorsalAndVentralLandmarks() throw (BrainModelAlgorithmException) { const QString landmarkMedialWallDorsalName("LANDMARK.MedialWall.DORSAL"); const QString landmarkMedialWallVentralName("LANDMARK.MedialWall.VENTRAL"); // // Remove existing flatten medial wall // borderProjectionFile->removeBordersWithName(landmarkMedialWallDorsalName); borderProjectionFile->removeBordersWithName(landmarkMedialWallVentralName); // // Create color for medial wall segments and flatten medial wall // borderColorFile->addColor("LANDMARK.MedialWall.DORSAL", 122, 0, 255); borderColorFile->addColor("LANDMARK.MedialWall.VENTRAL", 165, 0, 122); // // The dorsal medial wall starts at the frontal cut // and continues to the calcarine cut. The ventral medial // wall starts at the calcarine cut and continues to the // frontal cut // // // Flatten medial wall border, frontal cut, and calcarine cut // const BorderProjection* flattenMedialWallBorder = borderProjectionFile->getFirstBorderProjectionByName(getFlattenMedialWallBorderName()); if (flattenMedialWallBorder == NULL) { throw BrainModelAlgorithmException("Unable to find \"" + getFlattenMedialWallBorderName() + " for creating dorsal and ventral medial wall segments."); } const BorderProjection* calcarineCutBorder = borderProjectionFile->getFirstBorderProjectionByName(flattenCutCalcarineName); if (calcarineCutBorder == NULL) { throw BrainModelAlgorithmException("Unable to find \"" + flattenCutCalcarineName + " for creating dorsal and ventral medial wall segments."); } const BorderProjection* frontalCutBorder = borderProjectionFile->getFirstBorderProjectionByName(flattenCutFrontalName); if (frontalCutBorder == NULL) { throw BrainModelAlgorithmException("Unable to find \"" + flattenCutFrontalName + " for creating dorsal and ventral medial wall segments."); } // // Find intersection of frontal and medial wall // int medialWallFrontalCutLinkNumber = 0; const bool frontValidFlag = getBorderIntersection(inflatedSurface, getFlattenMedialWallBorderName(), flattenCutFrontalName, "", 10.0, //5.0, NULL, &medialWallFrontalCutLinkNumber, NULL); if (frontValidFlag == false) { throw BrainModelAlgorithmException("Unable to find intersection of \"" + getFlattenMedialWallBorderName() + "\" and \"" + flattenCutFrontalName + " for creating medial wall ventral " "and dorsal landmarks."); } // // Move frontal/medial wall intersection a little bit dorsal // medialWallFrontalCutLinkNumber += 5; if (medialWallFrontalCutLinkNumber >= flattenMedialWallBorder->getNumberOfLinks()) { medialWallFrontalCutLinkNumber = flattenMedialWallBorder->getNumberOfLinks() - 1; } // // Get location of frontal cut intersection with medial wall // float frontalMedialWallCutXYZ[3]; flattenMedialWallBorder->getBorderProjectionLink( medialWallFrontalCutLinkNumber)->unprojectLink( inflatedSurface->getCoordinateFile(), frontalMedialWallCutXYZ); // // Find intersection of calcarine and medial wall // int medialWallCalcarineCutLinkNumber = 0; const bool calcarineValidFlag = getBorderIntersection(inflatedSurface, getFlattenMedialWallBorderName(), flattenCutCalcarineName, "", 5.0, NULL, &medialWallCalcarineCutLinkNumber, NULL); if (calcarineValidFlag == false) { throw BrainModelAlgorithmException("Unable to find intersection of \"" + getFlattenMedialWallBorderName() + "\" and \"" + flattenCutCalcarineName + " for creating medial wall ventral " "and dorsal landmarks."); } // // Get location of calcarine cut intersection with medial wall // float calcarineMedialWallCutXYZ[3]; flattenMedialWallBorder->getBorderProjectionLink( medialWallCalcarineCutLinkNumber)->unprojectLink( inflatedSurface->getCoordinateFile(), calcarineMedialWallCutXYZ); // // Create the dorsal landmark // BorderProjection dorsalBP = flattenMedialWallBorder->getSubSetOfBorderProjectionLinks( medialWallFrontalCutLinkNumber, medialWallCalcarineCutLinkNumber); dorsalBP.setName(landmarkMedialWallDorsalName); dorsalBP.removeLastBorderProjectionLink(); borderProjectionFile->addBorderProjection(dorsalBP); // // Create the ventral landmark // BorderProjection ventralBP = flattenMedialWallBorder->getSubSetOfBorderProjectionLinks( medialWallCalcarineCutLinkNumber, medialWallFrontalCutLinkNumber); ventralBP.setName(landmarkMedialWallVentralName); ventralBP.removeLastBorderProjectionLink(); borderProjectionFile->addBorderProjection(ventralBP); // // Nibble border points around frontal cut and medial wall intersection // const float calcarineNibbleDistance = 16.0 / 2.0; //(19mm gap) nibbleBorderWithinDistance(inflatedSurface, landmarkMedialWallDorsalName, calcarineMedialWallCutXYZ, BORDER_NIBBLE_MODE_DISTANCE_LINEAR, calcarineNibbleDistance); nibbleBorderWithinDistance(inflatedSurface, landmarkMedialWallVentralName, calcarineMedialWallCutXYZ, BORDER_NIBBLE_MODE_DISTANCE_LINEAR, calcarineNibbleDistance); // // Nibble calcarine sulcus equivalent amount // nibbleBorderWithinDistance(inflatedSurface, calcarineSulcusLandmarkName, calcarineMedialWallCutXYZ, BORDER_NIBBLE_MODE_DISTANCE_LINEAR, calcarineNibbleDistance); // // Nibble border points around frontal cut and medial wall intersection // const float frontNibbleDistance = 19.0 / 2.0; //(16mm gap) nibbleBorderWithinDistance(inflatedSurface, landmarkMedialWallDorsalName, frontalMedialWallCutXYZ, BORDER_NIBBLE_MODE_DISTANCE_LINEAR, frontNibbleDistance); nibbleBorderWithinDistance(inflatedSurface, landmarkMedialWallVentralName, frontalMedialWallCutXYZ, BORDER_NIBBLE_MODE_DISTANCE_LINEAR, frontNibbleDistance); } /** * identify the dorsal medial wall with an alternative method. */ void BrainModelSurfaceBorderLandmarkIdentification::identifyDorsalMedialWallNew() throw (BrainModelAlgorithmException) { medialWallDorsalSectionName = "MedialWallDorsalSection"; borderProjectionFile->removeBordersWithName(medialWallDorsalSectionName); int numberOfFoci = 7; const int medialWallStartFocusIndex = 0; const int genuFocusIndex = 1; const int spleniumPosteriorFocusIndex = numberOfFoci - 1; const QString ccColorName("XCC"); std::vector ccFociNames; for (int i = 0; i < numberOfFoci; i++) { const QString name(ccColorName + "_" + QString::number(i)); ccFociNames.push_back(name); fociProjectionFile->deleteCellProjectionsWithName(name); } const QString medialWallDorsalBorderName("X_MedialWallDorsalSection"); borderProjectionFile->removeBordersWithName(medialWallDorsalBorderName); borderColorFile->addColor(medialWallDorsalBorderName, 150, 255, 50); addFocusColor(ccColorName, 150, 255, 0); //# //# Create the corpus callosum volume slice //# // if [ $LEFT_FLAG -eq 1 ] // then // caret_command -volume-create-corpus-callosum-slice $VOLUME // CorpusCallosumSlice+orig.nii.gz left // else // caret_command -volume-create-corpus-callosum-slice $VOLUME // CorpusCallosumSlice+orig.nii.gz right // fi // caret_command -volume-smear-axis CorpusCallosumSlice+orig.nii.gz // CorpusCallosumSlice_Smear6+orig.nii.gz X 6 -1 1 // caret_command -volume-smear-axis CorpusCallosumSlice_Smear6+orig.nii.gz // CorpusCallosumSlice_Smear12+orig.nii.gz X 6 1 1 // caret_command -volume-smear-axis CorpusCallosumSlice_Smear12+orig.nii.gz // CorpusCallosumSlice_Smearx12_z3+orig.nii.gz Z 3 1 1 // caret_command -volume-dilate CorpusCallosumSlice_Smearx12_z3+orig.nii.gz // Human.$SUBJECT.$HEM.CorpusCallosumSlice_SmearXZ_Dilate+orig.nii.gz 2 // /*float voxMin, voxMax; anatomicalVolumeFile->getMinMaxVoxelValues(voxMin, voxMax);*/ int dimExtent[6]; float coordExtent[6]; int i, j, k;/*, count, total; bool redo;*/ VolumeFile corpusCallosumVolume; // // Anatomical volume may be just corpus callosum. If so, skip // generation of corpus callosum. // const QString anatFileName = anatomicalVolumeFile->getFileName(); bool anatomyVolumeIsCorpusCallosumFlag = (anatFileName.contains("corpus", Qt::CaseInsensitive) && anatFileName.contains("callosum", Qt::CaseInsensitive)); if (anatomyVolumeIsCorpusCallosumFlag) { corpusCallosumVolume = *anatomicalVolumeFile; corpusCallosumVolume.makeSegmentationZeroTwoFiftyFive(); } else { /*const StatisticHistogram* hist = anatomicalVolumeFile->getHistogram(); int grayPeakBucketNumber, whitePeakBucketNumber, grayMinimumBucketNumber, whiteMaximumBucketNumber, grayWhiteBoundaryBucketNumber, csfPeakBucketNumber; hist->getGrayWhitePeakEstimates(grayPeakBucketNumber, whitePeakBucketNumber, grayMinimumBucketNumber, whiteMaximumBucketNumber, grayWhiteBoundaryBucketNumber, csfPeakBucketNumber); float threshhold = (hist->getDataValueForBucket(grayPeakBucketNumber) + hist->getDataValueForBucket(whitePeakBucketNumber)) / 2.0f; delete hist; do { redo = false; try {*/ BrainModelVolumeSureFitSegmentation::generateCorpusCallosumSlice( *anatomicalVolumeFile, corpusCallosumVolume, surfaceStructure, -1.0f,//threshhold * 0.8f, -1.0f, true);//threshhold * 1.2f); corpusCallosumVolume.smearAxis(VolumeFile::VOLUME_AXIS_X, 6, -1, 1); corpusCallosumVolume.smearAxis(VolumeFile::VOLUME_AXIS_X, 6, 1, 1); corpusCallosumVolume.makeSegmentationZeroTwoFiftyFive(); // Fix 14L, 16L // // Erode and then dilate to try to remove anterior cerebral artery // const int erodeDilateIterations = 6; for (i = 0; i < erodeDilateIterations; i++) { corpusCallosumVolume.doVolMorphOps(0, 1); corpusCallosumVolume.doVolMorphOps(1, 0); } corpusCallosumVolume.removeIslandsFromSegmentation(); // Fix 14L, 16L // // Get extent of volume // MOVED 25 Jan 2010 to after close of else clause since needed // for both this method and when anatomy is the corpus callosum //corpusCallosumVolume.getNonZeroVoxelExtent(dimExtent, // coordExtent);//doesn't use normal "one-after" array size conventions /*if (dimExtent[0] != -1) { if (fabs(coordExtent[3] - coordExtent[2]) < 50.0f) { cout << "threshhold " << threshhold << ": y coord extent too small" << endl; voxMax = threshhold; redo = true; } else { i = (dimExtent[0] + dimExtent[1]) / 2;//only need to look at the middle slice count = 0; total = (dimExtent[3] - dimExtent[2] + 1) * (dimExtent[5] - dimExtent[4] + 1); for (j = dimExtent[2]; j <= dimExtent[3]; ++j) { for (k = dimExtent[4]; k <= dimExtent[5]; ++k) { if (corpusCallosumVolume.getVoxel(i, j, k) > 0.0f) { ++count; } } } cout << "threshhold " << threshhold << ": " << count << " / " << total; if (count < total * 0.25f) { cout << ", too few voxels" << endl; voxMax = threshhold; redo = true; } else { if (count > total * 0.55f) { cout << ", too many voxels" << endl; voxMin = threshhold; redo = true; } else { cout << ", acceptable" << endl; } } } } else { cout << "threshhold " << threshhold << ": no nonzero extent found" << endl; voxMax = threshhold; redo = true; } } catch (BrainModelAlgorithmException e) { cout << "threshhold " << threshhold << ": caught exception, retrying" << endl; voxMax = threshhold; redo = true; } threshhold = (voxMin + voxMax + threshhold) / 3.0f;//its like bisection search, except it moves slower so it doesnt try crazy values if (redo && voxMax != 0.0f && voxMin / voxMax > 0.98f) { cout << "giving up" << endl; redo = false; } } while (redo);*/ } // // Get extent of volume // corpusCallosumVolume.getNonZeroVoxelExtent(dimExtent, coordExtent);//doesn't use normal "one-after" array size conventions if (saveIntermediateFilesFlag) { try { corpusCallosumVolume.writeFile(debugFilesDirectoryName + "/" + "CorpusCallosum.nii.gz"); } catch (FileException) { std::cout << "WARNING: Unable to write debug corpus callosum volume file." << std::endl; } } // // Get dimensions of volume // int dimensions[3]; corpusCallosumVolume.getDimensions(dimensions); // // Get spacing // float spacing[3]; corpusCallosumVolume.getSpacing(spacing); // // Determine Coronal slices for foci (locate along the Y-axis starting // at the anterior and moving in a posterior direction // const int anteriorCoronalSliceJ = dimExtent[3]; const int posteriorCoronalSliceJ = dimExtent[2]; if (anteriorCoronalSliceJ <= posteriorCoronalSliceJ) { throw BrainModelAlgorithmException("Corpus callosum has no Y-axis extent."); } int coronalSliceStepJ = static_cast( (static_cast(anteriorCoronalSliceJ) - static_cast(posteriorCoronalSliceJ)) / static_cast(numberOfFoci - 2)); std::vector fociCoronalSlicesJ; for (i = 0; i < numberOfFoci; i++) { if (i == genuFocusIndex) { fociCoronalSlicesJ.push_back(anteriorCoronalSliceJ); } else if (i == spleniumPosteriorFocusIndex) { fociCoronalSlicesJ.push_back(posteriorCoronalSliceJ); } else if (i == medialWallStartFocusIndex) { const int dJ = static_cast(7.0 / spacing[1]); fociCoronalSlicesJ.push_back(anteriorCoronalSliceJ - dJ); } else { int sliceJ = anteriorCoronalSliceJ - static_cast(coronalSliceStepJ * (i - 1)); if (i == (numberOfFoci - 2)) { sliceJ -= static_cast((coronalSliceStepJ / 2) / spacing[1]); } fociCoronalSlicesJ.push_back(sliceJ); } } // // Add a focus on the ventral side of the splenium // int spleniumVentralFocusIndex = -1; bool addSpleniumVentralFocusFlag = true; if (addSpleniumVentralFocusFlag) { const QString name(ccColorName + "_SpleniumVentral"); ccFociNames.push_back(name); fociProjectionFile->deleteCellProjectionsWithName(name); spleniumVentralFocusIndex = numberOfFoci; numberOfFoci = static_cast(ccFociNames.size()); const int dJ = static_cast(3.0 / spacing[1]); fociCoronalSlicesJ.push_back(posteriorCoronalSliceJ + dJ); } // // Place foci along top of corpus callosum // std::vector nodeNumbersForDorsalMedialWallBorder; for (int n = 0; n < numberOfFoci; n++) { // // Coronal slice of focus // const int jSlice = fociCoronalSlicesJ[n]; if (DebugControl::getDebugOn()) { std::cout << "Coronal Focus " << n << " Slice: " << jSlice << std::endl; } // // Find first non-zero voxel // bool foundIt = false; int kStart = dimensions[2] - 1; int kEnd = 0; int kStep = -1; if ((n == medialWallStartFocusIndex) || (n == spleniumVentralFocusIndex)) { kStart = 0; kEnd = dimensions[2] - 1; kStep = 1; } for (k = kStart; k != kEnd; k += kStep) { //for (int k = dimensions[2] - 1; k >= 0; k--) { // // move along X-Axis // for (j = 1; j <= dimExtent[1] - dimExtent[0] + 1; j++) { i = (dimExtent[0] + dimExtent[1]) / 2 + (j % 2 ? 1 - j : j) / 2;//search from middle of x extent to avoid bias between hemispheres //yes, its a confusing one-liner, but I couldn't think of a better way to loop from middle outwards without missing any indices // // Non-zero voxel ? // if (corpusCallosumVolume.getVoxel(i, jSlice, k) != 0.0) { // // Allow the focus to move around a little when searching // for the most lateral position nearby the initial position // float moveExtent[6] = { -20.0, 20.0, -2.0, 2.0, -1.0, 3.0 }; float target[3] = {70.0, -10.0, 5.0}; // // Get coordinate for focus and add it. Offset depending // upon location of focus. // float xyz[3]; float maxGeoDistance = 10.0f; if (n == genuFocusIndex) { // genu (anterior cc) corpusCallosumVolume.getVoxelCoordinate(i, jSlice, k, xyz); moveExtent[2] = -4.0; moveExtent[3] = 2.0; moveExtent[4] = -2.0; moveExtent[5] = 2.0; target[0] = 80.0; target[1] = 10.0; target[2] = 20.0; maxGeoDistance = 5.0f;//prevent genu from falling into the singulate } else if (n == spleniumPosteriorFocusIndex) { // (posterior cc) corpusCallosumVolume.getVoxelCoordinate(i, jSlice - 2, k, xyz); moveExtent[2] = -3.0; moveExtent[3] = 5.0; moveExtent[4] = -2.0; moveExtent[5] = 2.0; } else if (n == spleniumVentralFocusIndex) { // (posterior but inferior to splenium) moveExtent[2] = -4.0; moveExtent[3] = 0.5; moveExtent[4] = -2.5; moveExtent[5] = 1.0; corpusCallosumVolume.getVoxelCoordinate(i, jSlice, k - 1, xyz); } else if (n == medialWallStartFocusIndex) { //(below CC towards anterior) moveExtent[2] = -3.5f; moveExtent[3] = 1.0f; moveExtent[4] = -3.0; moveExtent[5] = 1.0; corpusCallosumVolume.getVoxelCoordinate(i, jSlice, k - 2, xyz); } else { // somewhere dorsal of cc corpusCallosumVolume.getVoxelCoordinate(i, jSlice, k, xyz); } moveExtent[0] += xyz[0]; moveExtent[1] += xyz[0]; moveExtent[2] += xyz[1]; moveExtent[3] += xyz[1]; moveExtent[4] += xyz[2]; moveExtent[5] += xyz[2]; if (leftHemisphereFlag) target[0] *= -1.0f; /*int nodeNumber = getMostLateralNodeInExtent(fiducialSurface, xyz, moveExtent, maxGeoDistance); */ int nodeNumber = getClosestNodeInExtent(fiducialSurface, xyz, moveExtent, maxGeoDistance, target); if (nodeNumber < 0) { // // Enlarge Y & Z // float delta = 0.5; for (int imm = 0; imm < 5; imm++) { moveExtent[2] -= delta; moveExtent[3] += delta; moveExtent[4] -= delta; moveExtent[5] += delta; /*nodeNumber = getMostLateralNodeInExtent(fiducialSurface, xyz, moveExtent, maxGeoDistance);*/ nodeNumber = getClosestNodeInExtent(fiducialSurface, xyz, moveExtent, maxGeoDistance, target); if (nodeNumber >= 0) { break; } } } //cout << n << ": " << nodeNumber << endl; if (nodeNumber >= 0) { addFocusAtNode(ccFociNames[n], nodeNumber); if (n == medialWallStartFocusIndex) { medialWallStartNodeNumber = nodeNumber; } else if (n == spleniumPosteriorFocusIndex) { ccSpleniumEndNodeNumber = nodeNumber; } else if (n == spleniumVentralFocusIndex) { // // Make sure the splenium ventral focus is BELOW the // splenium posterior focus // if ((spleniumPosteriorFocusIndex >= 0) && (ccSpleniumEndNodeNumber >= 0)) { const float* spfXYZ = fiducialSurface->getCoordinateFile()->getCoordinate(ccSpleniumEndNodeNumber); const float* svfXYZ = fiducialSurface->getCoordinateFile()->getCoordinate(nodeNumber); if (svfXYZ[2] < spfXYZ[2]) { ccSpleniumEndNodeNumber = nodeNumber; } else { nodeNumber = -1; } } else { ccSpleniumEndNodeNumber = nodeNumber; } } if (nodeNumber >= 0) { nodeNumbersForDorsalMedialWallBorder.push_back(nodeNumber); } } else { throw BrainModelAlgorithmException( "Dorsal Medial Wall: Unable to locate a node in vicinity " "of (" + QString::number(xyz[0], 'f', 3) + ", " + QString::number(xyz[1], 'f', 3) + ", " + QString::number(xyz[2], 'f', 3) + ")"); } if (DebugControl::getDebugOn()) { std::cout << "Coronal Focus " << n << " name " << ccFociNames[n].toAscii().constData() << " XYZ: " << xyz[0] << ", " << xyz[1] << ", " << xyz[2] << " Node: " << nodeNumber << std::endl; } foundIt = true; break; } } if (foundIt) { break; } } } if (DebugControl::getDebugOn()) { std::cout << "Splenium End Node Number: " << ccSpleniumEndNodeNumber << std::endl; } if (nodeNumbersForDorsalMedialWallBorder.empty()) { throw BrainModelAlgorithmException("Dorsal Medial Wall: " " no nodes were found along dorsal region of corpus callosum"); } // // Create an ROI of all nodes // BrainModelSurfaceROINodeSelection allNodesRoi(brainSet); allNodesRoi.selectAllNodes(fiducialSurface); // // Draw a border connecting all of the nodes along the dorsal // region of the corpus callosum // int junki = nodeNumbersForDorsalMedialWallBorder[genuFocusIndex], maxIter = 5; bool first = true, changed; Border border(medialWallDorsalSectionName), newSegment; int numToDraw; BorderProjectionFile bpf; do { changed = false; if (!first) { //cout << "adjusting foci for spike removal" << endl; //borderProjectionFile->removeBorderProjection(borderProjectionFile->getNumberOfBorderProjections() - 1); }//instead, don't add until finished first = false; /*drawBorderTargetedGeodesic(fiducialSurface, &allNodesRoi, medialWallDorsalSectionName, nodeNumbersForDorsalMedialWallBorder, 2.0f, target, targetweight);*/ //do this manually so each segment can have specialized weights and target points numToDraw = static_cast(nodeNumbersForDorsalMedialWallBorder.size()) - 1; border.clearLinks(); for (i = 0; i < numToDraw; i++) { float target[3] = {130.0, -10.0, -10.0};//effectively, lateral float targetweight = 1.2f;//the ratio of step cost change for 1 millimeter farther from the target point if (i == genuFocusIndex) { targetweight = 1.03f;//compensate for missing structure between CC and singulate target[0] = 90.0f;//mostly geodesic, but look for a groove thats angled more forward and upward target[1] = -20.0f; target[2] = -30.0f; } if (i == medialWallStartFocusIndex) { targetweight = 1.05f;//use closer to geodesic method, there is not always a ridge to follow } if (leftHemisphereFlag) { target[0] *= -1.0; } newSegment = drawHeuristic(fiducialSurface, &allNodesRoi, nodeNumbersForDorsalMedialWallBorder[i], nodeNumbersForDorsalMedialWallBorder[i + 1], target, targetweight); if (newSegment.getNumberOfLinks() <= 0) { throw BrainModelAlgorithmException("Geodesic heuristic drawing of border named \"" + medialWallDorsalSectionName + "\" segment " + QString::number(i) + " failed."); } // // Project the border and add to border projection file // border.appendBorder(newSegment); } int dummyUnused; border.resampleBorderToDensity(2.0f, 2, dummyUnused); // // Project the border and add to border projection file // BorderFile borderFile; borderFile.addBorder(border); BorderFileProjector projector(fiducialSurface, true); bpf.clear(); projector.projectBorderFile(&borderFile, &bpf, NULL); if (--maxIter < 1) break; // look for spikes at foci and fix them BorderProjection* myborder = bpf.getBorderProjection(0); int mylinks = myborder->getNumberOfLinks(); float fociloc[3], nextloc[3], prevloc[3], vec1[3], vec2[3], mag1 = 0.0f, mag2 = 0.0f; float minDist; int whichLink, whichFocus = -1; for (std::vector::iterator myiter = nodeNumbersForDorsalMedialWallBorder.begin(); myiter != nodeNumbersForDorsalMedialWallBorder.end(); ++myiter) { ++whichFocus;//the iterator keeps me from needing to use the obscenely long nodeNumbersForDorsalMedialWallBorder variable float spikeweight = 0.9f;//in case we want to change it for different foci minDist = -1.0f; whichLink = -1; for (i = 0; i < mylinks; ++i) {//search in the border as geodesic border draw may smooth effects, so vectors between foci don't tell us much myborder->getBorderProjectionLink(i)->unprojectLink(inputFiducialSurface->getCoordinateFile(), fociloc); inputFiducialSurface->getCoordinateFile()->getCoordinate(*myiter, vec1); mag1 = 0.0f; for (j = 0; j < 3; ++j) { mag2 = fociloc[j] - vec1[j]; mag1 += mag2 * mag2; } if (minDist < 0.0f || mag1 < minDist) { minDist = mag1; whichLink = i; } } if (whichLink > 0 && whichLink < mylinks - 1) {//dont touch the endpoints, theres no information on the other side to tell us about them myborder->getBorderProjectionLink(whichLink)->unprojectLink(inputFiducialSurface->getCoordinateFile(), fociloc); myborder->getBorderProjectionLink(whichLink - 1)->unprojectLink(inputFiducialSurface->getCoordinateFile(), prevloc); myborder->getBorderProjectionLink(whichLink + 1)->unprojectLink(inputFiducialSurface->getCoordinateFile(), nextloc); mag1 = 0.0f; mag2 = 0.0f; for (k = 0; k < 3; ++k) { vec1[k] = prevloc[k] - fociloc[k]; vec2[k] = fociloc[k] - nextloc[k]; mag1 += vec1[k] * vec1[k]; mag2 += vec2[k] * vec2[k]; } //cout << mag1 << ", " << mag2 << endl; mag1 = sqrtf(mag1); mag2 = sqrtf(mag2); if (mag1 > 0.0f && mag2 > 0.0f) { for (k = 0; k < 3; ++k) { vec1[k] /= mag1; vec1[k] -= vec2[k] / mag2; vec1[k] *= spikeweight * sqrtf(73730.0 / inputFiducialSurface->getCoordinateFile()->getNumberOfCoordinates());//adjust sensitivity based on mesh density vec2[k] = inputFiducialSurface->getCoordinateFile()->getCoordinate(*myiter)[k]; vec1[k] += inputFiducialSurface->getCoordinateFile()->getCoordinate(*myiter)[k]; } junki = inputFiducialSurface->getCoordinateFile()->getCoordinateIndexClosestToPoint(vec1); //cout << "(" << vec2[0] << ", " << vec2[1] << ", " << vec2[2] << ") -> "; //cout << "(" << vec1[0] << ", " << vec1[1] << ", " << vec1[2] << ")" << endl; if (junki != *myiter) { //cout << "new focus index for focus at " << *myiter << ": " << junki << endl; *myiter = junki; changed = true; } } } else { //cout << "endpoint at node " << *myiter << " left alone" << endl; } } } while (changed); borderProjectionFile->append(bpf);//NOW append it so we don't need to keep deleting it const QString name(debugFilesDirectoryName + "/" + borderDebugFileName); try { borderProjectionFile->writeFile(name); } catch (FileException&) { std::cout << "WARNING: Unable to write landmark debug border projection file." << std::endl; } } int BrainModelSurfaceBorderLandmarkIdentification::getMostLateralNodeInExtent( const BrainModelSurface* surface, const float startXYZ[3], const float extent[6], const float maxGeodesicDistance) const { const CoordinateFile* cf = surface->getCoordinateFile(); const int numCoords = cf->getNumberOfCoordinates(); const TopologyHelper* th = surface->getTopologyFile()->getTopologyHelper(false, true, false); float lateralX = -10000.0; if (leftHemisphereFlag) { lateralX = 10000.0; } const int rootNodeNumber = cf->getCoordinateIndexClosestToPoint(startXYZ); GeodesicDistanceFile geoDistFile; geoDistFile.setNumberOfNodesAndColumns(numCoords, 1); BrainModelSurfaceGeodesic geodesic(brainSet, fiducialSurface, NULL, -1, "", &geoDistFile, 0, "dist", rootNodeNumber); geodesic.execute(); int mostLateralNode = -1; for (int i = 0; i < numCoords; i++) { if (th->getNodeHasNeighbors(i)) { const float geoDist = geoDistFile.getNodeParentDistance(i, 0); if (geoDist < maxGeodesicDistance) { const float* coord = cf->getCoordinate(i); if ((coord[0] >= extent[0]) && (coord[0] <= extent[1]) && (coord[1] >= extent[2]) && (coord[1] <= extent[3]) && (coord[2] >= extent[4]) && (coord[2] <= extent[5])) { if (leftHemisphereFlag) { if (coord[0] < lateralX) { mostLateralNode = i; lateralX = coord[0]; } } else { if (coord[0] > lateralX) { mostLateralNode = i; lateralX = coord[0]; } } } } } } return mostLateralNode; } int BrainModelSurfaceBorderLandmarkIdentification::getClosestNodeInExtent( const BrainModelSurface* surface, const float startXYZ[3], const float extent[6], const float maxGeodesicDistance, const float target[3]) const { const CoordinateFile* cf = surface->getCoordinateFile(); const int numCoords = cf->getNumberOfCoordinates(); const TopologyHelper* th = surface->getTopologyFile()->getTopologyHelper(false, true, false); const int rootNodeNumber = cf->getCoordinateIndexClosestToPoint(startXYZ); GeodesicDistanceFile geoDistFile; geoDistFile.setNumberOfNodesAndColumns(numCoords, 1); BrainModelSurfaceGeodesic geodesic(brainSet, fiducialSurface, NULL, -1, "", &geoDistFile, 0, "dist", rootNodeNumber); geodesic.execute(); float currGeoDist = -1.0f; int closestNode = -1; float closestDist = -1.0, deltx, delty, deltz, dist; for (int i = 0; i < numCoords; i++) { if (th->getNodeHasNeighbors(i)) { const float geoDist = geoDistFile.getNodeParentDistance(i, 0); if (geoDist < maxGeodesicDistance || (currGeoDist < 0.0f || (currGeoDist >= maxGeodesicDistance && geoDist < currGeoDist))) { const float* coord = cf->getCoordinate(i); if ((coord[0] >= extent[0]) && (coord[0] <= extent[1]) && (coord[1] >= extent[2]) && (coord[1] <= extent[3]) && (coord[2] >= extent[4]) && (coord[2] <= extent[5])) { deltx = coord[0] - target[0]; delty = coord[1] - target[1]; deltz = coord[2] - target[2]; dist = deltx * deltx + delty * delty + deltz * deltz;//actually distance squared, but this saves an unneeded sqrt call if ((currGeoDist < 0.0f || currGeoDist >= maxGeodesicDistance) || closestDist < 0.0 || dist < closestDist) { currGeoDist = geoDist; closestNode = i; closestDist = dist; } } } } } return closestNode; } /** * identify the ventral medial wall. */ void BrainModelSurfaceBorderLandmarkIdentification::identifyVentralMedialWall() throw (BrainModelAlgorithmException) { // // names for things // const QString hippocampalDorsalFocusName("HF.Dorsal"); const QString hippocampalVentralFocusName("HF.Ventral"); const QString hippocampalAnteriorFocusName("HF.Anterior"); const QString hippocampalFissureRoiFileName(createFileName("HF", SpecFile::getRegionOfInterestFileExtension())); const QString hippocampalFissureDeepRoiFileName(createFileName("HF.DEEP", SpecFile::getRegionOfInterestFileExtension())); const QString landmarkSpleniumLimitToHFDorsalName("LANDMARK.MW.SpleniumLimitToHFDorsal"); const QString landmarkSpleniumLimitToHFDorsalNameAlternate("LANDMARK.MW.SpleniumLimitToHFDorsalAlternate"); const QString landmarkHFDorsalToHFVentralName("LANDMARK.MW.HFDorsalToHFVentral"); const QString landmarkHFVentralToMedialWallStart("LANDMARK.MW.HFVentralToMedialWallStart"); medialWallVentralSectionName = "MedialWallVentralSection"; // // Delete old stuff // QFile::remove(hippocampalFissureRoiFileName); QFile::remove(hippocampalFissureDeepRoiFileName); fociProjectionFile->deleteCellProjectionsWithName(hippocampalDorsalFocusName); fociProjectionFile->deleteCellProjectionsWithName(hippocampalVentralFocusName); fociProjectionFile->deleteCellProjectionsWithName(hippocampalAnteriorFocusName); borderProjectionFile->removeBordersWithName(landmarkSpleniumLimitToHFDorsalName); borderProjectionFile->removeBordersWithName(landmarkSpleniumLimitToHFDorsalNameAlternate); borderProjectionFile->removeBordersWithName(landmarkHFDorsalToHFVentralName); borderProjectionFile->removeBordersWithName(landmarkHFVentralToMedialWallStart); borderProjectionFile->removeBordersWithName(medialWallVentralSectionName); // // Create colors // borderColorFile->addColor("LANDMARK.MW", 255, 50, 50); borderColorFile->addColor(medialWallVentralSectionName, 0, 255, 0); addFocusColor("HF", 0, 0, 200); // // Create an ROI in the Hippocampal Fissure // BrainModelSurfaceROINodeSelection hfRoi(brainSet); hfRoi.selectNodesWithPaint(BrainModelSurfaceROINodeSelection::SELECTION_LOGIC_NORMAL, fiducialSurface, paintFile, paintFileSulcusIdColumnNumber, "SUL.HF"); if (hfRoi.getNumberOfNodesSelected() <= 0) { throw BrainModelAlgorithmException( "\"SUL.HF\", the hippocampal fissure paint contains no nodes."); } // // Save the HF Roi // saveRoiToFile(hfRoi, hippocampalFissureRoiFileName); // // Create a more stringent ROI of the hippocampal fissure // BrainModelSurfaceROINodeSelection hfDeepRoi(hfRoi); hfDeepRoi.selectNodesWithMetric(BrainModelSurfaceROINodeSelection::SELECTION_LOGIC_AND, fiducialSurface, depthSurfaceShapeFile, depthSurfaceShapeFileColumnNumber, -50000.0, -10.0); // // Save the Deep HF Roi // saveRoiToFile(hfDeepRoi, hippocampalFissureDeepRoiFileName); // // Get limits of hippocampal fissure // int minXNode, maxXNode, minYNode, maxYNode, minZNode, maxZNode; int mostMedialXNode, mostLateralXNode; int absMinXNode, absMaxXNode, absMinYNode, absMaxYNode, absMinZNode, absMaxZNode; hfDeepRoi.getNodesWithMinMaxXYZValues(inflatedSurface, mostMedialXNode, mostLateralXNode, minXNode, maxXNode, minYNode, maxYNode, minZNode, maxZNode, absMinXNode, absMaxXNode, absMinYNode, absMaxYNode, absMinZNode, absMaxZNode); // // Dorsal and ventral nodes of Hippocampal Fissure // int hfDorsalNodeNumber = maxZNode; addFocusAtNode(hippocampalDorsalFocusName, hfDorsalNodeNumber); const int hfVentralNodeNumber = minZNode; addFocusAtNode(hippocampalVentralFocusName, hfVentralNodeNumber); // // If the spleium end node is ABOVE the dorsal hippocampal fissure // node, then use the splenium end node as the HF dorsal node. // const float* ccSpleniumEndXYZ = fiducialSurface->getCoordinateFile()->getCoordinate(ccSpleniumEndNodeNumber); const float* hfDorsalXYZ = fiducialSurface->getCoordinateFile()->getCoordinate(hfDorsalNodeNumber); if (hfDorsalXYZ[2] > ccSpleniumEndXYZ[2]) { hfDorsalNodeNumber = ccSpleniumEndNodeNumber; } const bool hfDorsalNodeValidFlag = (hfDorsalNodeNumber != ccSpleniumEndNodeNumber); { // // Move 10mm anterior // const int hippocampalFissureAnteriorNodeNumber = addFocusAtExtremum(inflatedSurface, hfVentralNodeNumber, BrainModelSurfaceFindExtremum::DIRECTION_Y_POSITIVE, 3.0, 8.0, // 10.0, 8.0, "HF_Ventral_Anterior_Test", NULL, BrainModelSurfaceFindExtremum::NORMAL_RESTRICTION_NONE, BrainModelSurfaceFindExtremum::NORMAL_RESTRICTION_NONE, BrainModelSurfaceFindExtremum::NORMAL_RESTRICTION_POSITIVE); // // This should put find the node on the parahippocampal gyrus at ventral end // const int hippocampalGyrusVentralNodeNumber = addFocusAtExtremum(inflatedSurface, hippocampalFissureAnteriorNodeNumber, //hfVentralNodeNumber, BrainModelSurfaceFindExtremum::DIRECTION_MEDIAL, 100000.0, 5.0, 100000.0, "HF_Ventral_Test", NULL, BrainModelSurfaceFindExtremum::NORMAL_RESTRICTION_NONE, BrainModelSurfaceFindExtremum::NORMAL_RESTRICTION_NONE, BrainModelSurfaceFindExtremum::NORMAL_RESTRICTION_POSITIVE); //const float* ventralXYZ = // inflatedSurface->getCoordinateFile()->getCoordinate(hippocampalGyrusVentralNodeNumber); // // Move 12mm laterally // const float lateralOffset = (leftHemisphereFlag ? -12.0 : 12.0); const int hippocampalGyrusVentralBorderNodeNumber = addFocusAtExtremum(inflatedSurface, hippocampalGyrusVentralNodeNumber, BrainModelSurfaceFindExtremum::DIRECTION_LATERAL, 12.5, 5.0, 100.0, "HF_Ventral_Border_Node", NULL, BrainModelSurfaceFindExtremum::NORMAL_RESTRICTION_NONE, BrainModelSurfaceFindExtremum::NORMAL_RESTRICTION_NONE, BrainModelSurfaceFindExtremum::NORMAL_RESTRICTION_POSITIVE); // // This should put find the node on the parahippocampal gyrus near middle // but limit to nodes with positive Z-normals // const int hippocampalGyrusMidPointNodeNumber = addFocusAtExtremum(inflatedSurface, hippocampalGyrusVentralNodeNumber, BrainModelSurfaceFindExtremum::DIRECTION_Y_NEGATIVE, 5.0, 35.0, //25.0, 100000.0, "HF_Midpoint_Y_Test", NULL, BrainModelSurfaceFindExtremum::NORMAL_RESTRICTION_NONE, BrainModelSurfaceFindExtremum::NORMAL_RESTRICTION_NONE, BrainModelSurfaceFindExtremum::NORMAL_RESTRICTION_POSITIVE); const float* midPointXYZ = inflatedSurface->getCoordinateFile()->getCoordinate(hippocampalGyrusMidPointNodeNumber); // // Move 12mm laterally // const int hippocampalGyrusMidPointBorderNodeNumber = inflatedSurface->getCoordinateFile()->getCoordinateIndexClosestToPoint( midPointXYZ[0] + lateralOffset, midPointXYZ[1], midPointXYZ[2] + 5.0); addFocusAtNode("HF_MidPoint_Border_Node", hippocampalGyrusMidPointBorderNodeNumber); // // Find node along path from temporal pole to HF ventral node // that is 24mm from temporal pole // const int hfAnteriorNodeNumber = findNodeAlongGeodesicPathBetweenNodes(inflatedSurface, temporalPoleNodeNumber, hfVentralNodeNumber, 30.0); addFocusAtNode(hippocampalAnteriorFocusName, hfAnteriorNodeNumber); // // Draw a border connecting the splenium limit node to the dorsal HF node // std::vector myNodeNumbers; float target[3]; float targetweight; const QString seg1Name("seg1Name"); /*drawBorderGeodesic(inflatedSurface, &hfRoi, seg1Name, hfDorsalNodeNumber, hippocampalGyrusMidPointBorderNodeNumber, 3.0);*/ myNodeNumbers.clear(); myNodeNumbers.push_back(hfDorsalNodeNumber); myNodeNumbers.push_back(hippocampalGyrusMidPointBorderNodeNumber); target[0] = 55.0f; target[1] = -75.0f; target[2] = -20.0f; targetweight = 1.15f; if (leftHemisphereFlag) { target[0] *= -1.0f; } drawBorderTargetedGeodesic(fiducialSurface, &hfRoi, seg1Name, myNodeNumbers, 3.0, target, targetweight); // // Draw a border connecting the dorsal HF node to the ventral HF node // const QString seg2Name("seg2Name"); /*drawBorderGeodesic(inflatedSurface, &hfDeepRoi, seg2Name, hippocampalGyrusMidPointBorderNodeNumber, hippocampalGyrusVentralBorderNodeNumber, 3.0);*/ myNodeNumbers.clear(); myNodeNumbers.push_back(hippocampalGyrusMidPointBorderNodeNumber); myNodeNumbers.push_back(hippocampalGyrusVentralBorderNodeNumber); target[0] = 60.0f; target[1] = -40.0f; target[2] = -40.0f; targetweight = 1.15f; if (leftHemisphereFlag) { target[0] *= -1.0f; } drawBorderTargetedGeodesic(fiducialSurface, &hfDeepRoi, seg2Name, myNodeNumbers, 3.0, target, targetweight); // // Draw a border connecting the ventral HF node to node // along path to temproral pole // const QString seg3Name("seg3Name"); const bool seg3Valid = (hippocampalGyrusVentralBorderNodeNumber != hfAnteriorNodeNumber); if (seg3Valid) { drawBorderGeodesic(inflatedSurface, NULL, seg3Name, hippocampalGyrusVentralBorderNodeNumber, hfAnteriorNodeNumber, 3.0);//use geodesic because its on a convex surface, and the foci are very close together /*myNodeNumbers.clear(); myNodeNumbers.push_back(hippocampalGyrusVentralBorderNodeNumber); myNodeNumbers.push_back(hfAnteriorNodeNumber); target[0] = 60.0f;//CHANGE THE TARGET, this is from previous section, no idea if it will work well target[1] = -40.0f; target[2] = -40.0f; targetweight = 1.15f; if (leftHemisphereFlag) { target[0] *= -1.0f; } drawBorderTargetedGeodesic(fiducialSurface, NULL, seg3Name, myNodeNumbers, 3.0, target, targetweight);*/ } // // Draw a border connection HF ventral to Medial Wall Start // const QString seg4Name("seg4Name"); /*drawBorderGeodesic(inflatedSurface, NULL, seg4Name, hfAnteriorNodeNumber, medialWallStartNodeNumber, 3.0);*/ //use targeted method to let the border curve inwards myNodeNumbers.clear(); myNodeNumbers.push_back(hfAnteriorNodeNumber); myNodeNumbers.push_back(medialWallStartNodeNumber); target[0] = 50.0f; target[1] = -60.0f; target[2] = 50.0f; targetweight = 1.03f;//don't let it run wild if (leftHemisphereFlag) { target[0] *= -1.0f; } drawBorderTargetedGeodesic(fiducialSurface, NULL, seg4Name, myNodeNumbers, 3.0, target, targetweight); { // // Draw a border connecting the splenium limit node to the dorsal HF node // const QString seg0NameAlternate("seg0NameAlternate"); if (hfDorsalNodeValidFlag) { try { drawBorderMetric(inflatedSurface, BrainModelSurfaceROICreateBorderUsingMetricShape::MODE_FOLLOW_MOST_NEGATIVE, curvatureShapeFile, curvatureFiducialSmoothedMeanColumnNumber, seg0NameAlternate, ccSpleniumEndNodeNumber, hfDorsalNodeNumber, 3.0); } catch (BrainModelAlgorithmException&) { // // If drawing using metric failed, try geodesic // drawBorderGeodesic(inflatedSurface, NULL, seg0NameAlternate, ccSpleniumEndNodeNumber, hfDorsalNodeNumber, 3.0); } } BorderProjection medialWallVentralBorderProjectionTest(medialWallVentralSectionName); if (hfDorsalNodeValidFlag) { medialWallVentralBorderProjectionTest.append( *borderProjectionFile->getFirstBorderProjectionByName( seg0NameAlternate)); } medialWallVentralBorderProjectionTest.append( *borderProjectionFile->getFirstBorderProjectionByName( seg1Name)); medialWallVentralBorderProjectionTest.append( *borderProjectionFile->getFirstBorderProjectionByName( seg2Name)); if (seg3Valid) { medialWallVentralBorderProjectionTest.append( *borderProjectionFile->getFirstBorderProjectionByName( seg3Name)); } medialWallVentralBorderProjectionTest.append( *borderProjectionFile->getFirstBorderProjectionByName( seg4Name)); borderProjectionFile->addBorderProjection(medialWallVentralBorderProjectionTest); borderProjectionFile->removeBordersWithName(seg0NameAlternate); } // // Remove the segments that were merged into the ventral medial wall // //borderProjectionFile->removeBordersWithName(seg0Name); borderProjectionFile->removeBordersWithName(seg1Name); borderProjectionFile->removeBordersWithName(seg2Name); borderProjectionFile->removeBordersWithName(seg3Name); borderProjectionFile->removeBordersWithName(seg4Name); } // // Remove any loops in the medial wall // removeLoopsFromBorder(veryInflatedSurface, medialWallVentralSectionName, 'X'); // // Resample border // resampleBorder(fiducialSurface, medialWallVentralSectionName, 2.0); } /** * create a file name. */ QString BrainModelSurfaceBorderLandmarkIdentification::createFileName(const QString& description, const QString& extension) const { QString species("Species"); if (brainSet->getSpecies().getName().isEmpty() == false) { species = brainSet->getSpecies().getName(); } QString subject("Subject"); if (brainSet->getSubject().isEmpty() == false) { subject = brainSet->getSubject(); } const QString name = (species + "." + subject + "." + Structure::convertTypeToAbbreviatedString(brainSet->getStructure().getType()) + "." + description + extension); return name; } /** * get node nearby that has the value closest to the target value. */ int BrainModelSurfaceBorderLandmarkIdentification::getNearbyNodeWithShapeValue( const BrainModelSurface* surface, const SurfaceShapeFile* shapeFile, const int shapeColumnNumber, const float targetValue, const int startNodeNumber, const float maxDistanceIn, const BrainModelSurfaceROINodeSelection* limitToWithinROI, const float* limitToExtent) const { float extent[6] = { -std::numeric_limits::max(), std::numeric_limits::max(), -std::numeric_limits::max(), std::numeric_limits::max(), -std::numeric_limits::max(), std::numeric_limits::max() }; if (limitToExtent != NULL) { for (int i = 0; i < 6; i++) { extent[i] = limitToExtent[i]; } } BrainModelSurfaceROINodeSelection roi(brainSet); if (limitToWithinROI != NULL) { roi = *limitToWithinROI; } else if (startNodeNumber < 0) { roi.selectAllNodes(surface); } else { roi.selectNodesWithinGeodesicDistance( BrainModelSurfaceROINodeSelection::SELECTION_LOGIC_NORMAL, surface, startNodeNumber, maxDistanceIn); } const int numNodes = surface->getNumberOfNodes(); const CoordinateFile* cf = surface->getCoordinateFile(); float maxDistanceSquared = maxDistanceIn * maxDistanceIn; int nodeNumber = startNodeNumber; float testValue = 0.0f; if (nodeNumber >= 0) { testValue = shapeFile->getValue(startNodeNumber, shapeColumnNumber); } for (int i = 0; i < numNodes; i++) { // // Is node in the ROI // if (roi.getNodeSelected(i)) { // // Is node within allowable distance from the starting node number // bool useIt = false; if (startNodeNumber < 0) { useIt = true; } else if (cf->getDistanceBetweenCoordinatesSquared(i, startNodeNumber) < maxDistanceSquared) { useIt = true; } if (useIt) { // // Is value closer ? // const float value = shapeFile->getValue(i, shapeColumnNumber); if (std::fabs(targetValue - value) < std::fabs(targetValue - testValue)) { // // Within extent // const float* nodeXYZ = cf->getCoordinate(i); if ((nodeXYZ[0] >= extent[0]) && (nodeXYZ[0] <= extent[1]) && (nodeXYZ[1] >= extent[2]) && (nodeXYZ[1] <= extent[3]) && (nodeXYZ[2] >= extent[4]) && (nodeXYZ[2] <= extent[5])) { testValue = value; nodeNumber = i; } } } } } return nodeNumber; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceBorderCutter.h0000664000175000017500000000501211572067322025726 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __BRAIN_MODEL_SURFACE_BORDER_CUTTER_H__ #define __BRAIN_MODEL_SURFACE_BORDER_CUTTER_H__ #include "BrainModelAlgorithm.h" #include "BorderFile.h" #include "BorderProjectionFile.h" class BrainModelSurface; class TopologyFile; /// This class applies borers as cuts to a surface class BrainModelSurfaceBorderCutter : public BrainModelAlgorithm { public: /// mode of cutting enum CUTTING_MODE { CUTTING_MODE_FLAT_SURFACE, CUTTING_MODE_NON_NEGATIVE_Z_ONLY, CUTTING_MODE_SPHERICAL_SURFACE }; /// Constructor BrainModelSurfaceBorderCutter(BrainSet* bsIn, BrainModelSurface* cuttingSurfaceIn, const BorderProjectionFile* cutBorderProjectionsIn, const CUTTING_MODE cuttingModeIn, const bool extendBordersToNearestEdgeNodeFlag); /// Destructor ~BrainModelSurfaceBorderCutter(); /// Execute the flattening virtual void execute() throw (BrainModelAlgorithmException); protected: // extend the border to nearest edge node void extendBorderToNearestEdgeNode(Border& border); /// surface to which cuts are applied BrainModelSurface* cuttingSurface; /// the border projections to be used as cuts const BorderProjectionFile* cutBorderProjectionFile; /// cutting mode const CUTTING_MODE cuttingMode; /// extend borders to nearest edge node flag const bool extendBordersToNearestEdgeNodeFlag; }; #endif // __BRAIN_MODEL_SURFACE_BORDER_CUTTER_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceBorderCutter.cxx0000664000175000017500000002540011572067322026304 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include "vtkLine.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceBorderCutter.h" #include "BrainSet.h" #include "BorderFile.h" #include "DebugControl.h" #include "MathUtilities.h" #include "TopologyFile.h" #include "TopologyHelper.h" /** * Constructor. */ BrainModelSurfaceBorderCutter::BrainModelSurfaceBorderCutter( BrainSet* bsIn, BrainModelSurface* cuttingSurfaceIn, const BorderProjectionFile* cutBorderProjectionFileIn, const CUTTING_MODE cuttingModeIn, const bool extendBordersToNearestEdgeNodeFlagIn) : BrainModelAlgorithm(bsIn), cuttingSurface(cuttingSurfaceIn), cutBorderProjectionFile(cutBorderProjectionFileIn), cuttingMode(cuttingModeIn), extendBordersToNearestEdgeNodeFlag(extendBordersToNearestEdgeNodeFlagIn) { } /** * Destructor. */ BrainModelSurfaceBorderCutter::~BrainModelSurfaceBorderCutter() { } /** * Execute the flattening. */ void BrainModelSurfaceBorderCutter::execute() throw (BrainModelAlgorithmException) { QTime timer; timer.start(); // // NOTE: We could save some time and use a topology helper. But, if the topology is messed // up and more than two tiles use an edge, not all tiles would be removed. So, just // test all tiles. // // // Get the topolgoy file // TopologyFile* topology = cuttingSurface->getTopologyFile(); const TopologyHelper* topologyHelper = topology->getTopologyHelper(false, true, false); // // Keep track of tiles that need to be deleted. // const int numTiles = topology->getNumberOfTiles(); std::vector deleteTheTile(numTiles, false); // // Apply all of the cuts // const int numBorderProjections = static_cast(cutBorderProjectionFile->getNumberOfBorderProjections()); for (int bpi = 0; bpi < numBorderProjections; bpi++) { // // only do cuts with at least two links // const BorderProjection& borderProjection = *cutBorderProjectionFile->getBorderProjection(bpi); if (borderProjection.getNumberOfLinks() > 1) { // // Copy the surface since it may need to be rotated // BrainModelSurface surface(*cuttingSurface); // // Get the coordinate file // const CoordinateFile* coords = surface.getCoordinateFile(); const float* coordXYZ = coords->getCoordinate(0); // // May need to rotate the surface to apply the cut // switch (cuttingMode) { case CUTTING_MODE_FLAT_SURFACE: break; case CUTTING_MODE_NON_NEGATIVE_Z_ONLY: break; case CUTTING_MODE_SPHERICAL_SURFACE: { // // Get the center of gravity of the border // float cog[3]; if (borderProjection.getCenterOfGravity(coords, topologyHelper, cog)) { } else { throw BrainModelAlgorithmException( "Unable to get center of gravity for cut " + borderProjection.getName()); } // // Orient sphere so that border COG is on positive Z-axis // surface.orientPointToPositiveZAxis(cog); } break; } // // Unproject the border // Border cut; borderProjection.unprojectBorderProjection(coords, topologyHelper, cut); // // Are borders to be extended // if (extendBordersToNearestEdgeNodeFlag) { extendBorderToNearestEdgeNode(cut); } const int numCutPoints = cut.getNumberOfLinks(); // // test each segment in the cut // if (numCutPoints > 1) { for (int cpi = 0; cpi < (numCutPoints - 1); cpi++) { float c1[3], c2[3]; cut.getLinkXYZ(cpi, c1); cut.getLinkXYZ(cpi + 1, c2); c1[2] = 0.0; c2[2] = 0.0; // // Test this cut segment agains all tiles // for (int tile = 0; tile < numTiles; tile++) { // // If tile has not already been marked for deletion // if (deleteTheTile[tile] == false) { // // Get the vertices of the tile // int v1, v2, v3; topology->getTile(tile, v1, v2, v3); const float* p1 = &coordXYZ[v1*3]; const float* p2 = &coordXYZ[v2*3]; const float* p3 = &coordXYZ[v3*3]; bool doCutCheck = true; switch(cuttingMode) { case CUTTING_MODE_FLAT_SURFACE: break; case CUTTING_MODE_NON_NEGATIVE_Z_ONLY: case CUTTING_MODE_SPHERICAL_SURFACE: if ((p1[2] < 0.0) || (p2[2] < 0.0) || (p3[2] < 0.0)) { doCutCheck = false; } break; } if (doCutCheck) { // // Check the cut segment against each tile edge // float intersection[2]; if (MathUtilities::lineIntersection2D(c1, c2, p1, p2, intersection)) { deleteTheTile[tile] = true; } else if (MathUtilities::lineIntersection2D(c1, c2, p2, p3, intersection)) { deleteTheTile[tile] = true; } else if (MathUtilities::lineIntersection2D(c1, c2, p3, p1, intersection)) { deleteTheTile[tile] = true; } } } } } } } } // // If cuts were made // if (std::find(deleteTheTile.begin(), deleteTheTile.end(), true) != deleteTheTile.end()) { // // Remove the cut tiles // if (DebugControl::getDebugOn()) { std::cout << "deleting tiles "; } int cnt = 0; std::vector tilesToDelete; for (int i = 0; i < numTiles; i++) { if (deleteTheTile[i]) { tilesToDelete.push_back(i); if (DebugControl::getDebugOn()) { std::cout << " " << i; } cnt++; } } if (DebugControl::getDebugOn()) { std::cout << std::endl; std::cout << "Deleting " << cnt << " tiles." << std::endl; } const int numTilesBeforeDelete = topology->getNumberOfTiles(); topology->deleteTiles(tilesToDelete); if (DebugControl::getDebugOn()) { std::cout << "Tiles before applying cuts: " << numTilesBeforeDelete << std::endl; std::cout << "Tiles after applying cuts: " << topology->getNumberOfTiles() << std::endl; } // // Set topolgy file type to cut // topology->setTopologyType(TopologyFile::TOPOLOGY_TYPE_CUT); } //std::cout << "Total time: " << timer.elapsed() / 1000 << " seconds." << std::endl; } /** * extend the borders to nearest edge node. */ void BrainModelSurfaceBorderCutter::extendBorderToNearestEdgeNode(Border& border) { // // Surface coordinate file // const CoordinateFile* cf = cuttingSurface->getCoordinateFile(); const int numCoords = cf->getNumberOfCoordinates(); TopologyFile* tf = cuttingSurface->getTopologyFile(); // // Classify nodes // brainSet->classifyNodes(tf, false); // // Check border // const int numLinks = border.getNumberOfLinks(); if (numLinks > 1) { const float* firstLinkXYZ = border.getLinkXYZ(0); float distToFirstLink = std::numeric_limits::max(); int nodeNearestFirstLink = -1; const float* lastLinkXYZ = border.getLinkXYZ(numLinks - 1); float distToLastLink = std::numeric_limits::max(); int nodeNearestLastLink = -1; // // Find node nearest to first and last links // for (int j = 0; j < numCoords; j++) { // // if NOT interior node // if (brainSet->getNodeAttributes(j)->getClassification() != BrainSetNodeAttribute::CLASSIFICATION_TYPE_INTERIOR) { const float distFirst = cf->getDistanceToPointSquared(j, firstLinkXYZ); if (distFirst < distToFirstLink) { distToFirstLink = distFirst; nodeNearestFirstLink = j; } const float distLast = cf->getDistanceToPointSquared(j, lastLinkXYZ); if (distLast < distToLastLink) { distToLastLink = distLast; nodeNearestLastLink = j; } } } // // Determine where new link should be inserted // if (distToFirstLink < distToLastLink) { if (nodeNearestFirstLink >= 0) { const float* xyz = cf->getCoordinate(nodeNearestFirstLink); border.insertBorderLink(0, xyz); } } else { if (nodeNearestLastLink >= 0) { const float* xyz = cf->getCoordinate(nodeNearestLastLink); border.addBorderLink(xyz); } } } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceBankStraddling.h0000664000175000017500000000366311572067322026223 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_BANK_STRADDLING_H__ #define __BRAIN_MODEL_SURFACE_BANK_STRADDLING_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelAlgorithm.h" class MetricFile; class TopologyHelper; /// class for create a functional volume using a probabilistic volume class BrainModelSurfaceBankStraddling : public BrainModelAlgorithm { public: /// Constructor BrainModelSurfaceBankStraddling(BrainSet* bs, int bsIndexIn, MetricFile* metricOutIn, int metricOutIndexIn, float voxdimIn[3], bool interpIn); /// Destructor ~BrainModelSurfaceBankStraddling(); /// execute the algorithm void execute() throw (BrainModelAlgorithmException); private: int setIndex, metricOutIndex; MetricFile* metricOut; float voxdim[3]; bool interp; }; #endif // __BRAIN_MODEL_SURFACE_BANK_STRADDLING_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceBankStraddling.cxx0000664000175000017500000001450011572067322026566 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelVolume.h" #include "BrainModelSurfaceBankStraddling.h" #include "BrainSet.h" #include "BrainModelSurface.h" #include "CoordinateFile.h" #include "TopologyFile.h" #include "TopologyHelper.h" #include "MetricFile.h" #include "GeodesicHelper.h" #include #include #include /** * Constructor. */ BrainModelSurfaceBankStraddling::BrainModelSurfaceBankStraddling( BrainSet* bs, int bsIndexIn, MetricFile* metricOutIn, int metricOutIndexIn, float voxdimIn[3], bool interpIn) : BrainModelAlgorithm(bs) { setIndex = bsIndexIn; metricOut = metricOutIn; metricOutIndex = metricOutIndexIn; interp = interpIn; voxdim[0] = voxdimIn[0]; voxdim[1] = voxdimIn[1]; voxdim[2] = voxdimIn[2]; } /** * Destructor. */ BrainModelSurfaceBankStraddling::~BrainModelSurfaceBankStraddling() { } /** * execute the algorithm. */ void BrainModelSurfaceBankStraddling::execute() throw (BrainModelAlgorithmException) { // // Verify files exist, are valid, etc. // BrainModelSurface* mysurf = brainSet->getBrainModelSurface(setIndex);//reference if (!mysurf) { throw BrainModelAlgorithmException("No input surface."); } CoordinateFile* source = mysurf->getCoordinateFile();//references TopologyFile* topo = mysurf->getTopologyFile(); GeodesicHelper mygeo(source, topo); if (voxdim[0] <= 0.0f || voxdim[1] <= 0.0f || voxdim[2] <= 0.0f) { throw BrainModelAlgorithmException("Invalid voxel dimensions."); } if (source == NULL) { throw BrainModelAlgorithmException("Invalid coordinate file."); } if (source->getNumberOfCoordinates() < 1) { throw BrainModelAlgorithmException("Not enough nodes in coordinate file."); } // // Check output files exist // if (metricOut == NULL) { throw BrainModelAlgorithmException("No valid output file."); } if (metricOut->getNumberOfNodes() != source->getNumberOfCoordinates()) { metricOut->setNumberOfNodesAndColumns(source->getNumberOfCoordinates(), 1); metricOutIndex = 0; } if (metricOutIndex < 0 || metricOutIndex >= metricOut->getNumberOfColumns()) { metricOutIndex = metricOut->getNumberOfColumns(); metricOut->addColumns(1); } metricOut->setColumnName(metricOutIndex, QString("Bank Straddling ") + QString::number(voxdim[0]) + QString("x") + QString::number(voxdim[0]) + QString("x") + QString::number(voxdim[0]) + QString("mm, ") + (interp ? QString("interpolated") : QString("enclosing"))); int numNodes = source->getNumberOfCoordinates(); int i, j, numInrange, whichnode, coordbase;//, worstnode; float rootCoord[3], selectrange[3]; float tempf, tempf2, tempf3; if (interp) { selectrange[0] = 2.0f * voxdim[0]; selectrange[1] = 2.0f * voxdim[1]; selectrange[2] = 2.0f * voxdim[2]; } else { selectrange[0] = voxdim[0]; selectrange[1] = voxdim[1]; selectrange[2] = voxdim[2]; } std::vector inrange; std::vector distances; float* outData = new float[numNodes]; float* sourceData = new float[numNodes * 3]; source->getAllCoordinates(sourceData); for (i = 0; i < numNodes; ++i) { coordbase = i * 3; rootCoord[0] = sourceData[coordbase]; rootCoord[1] = sourceData[coordbase + 1]; rootCoord[2] = sourceData[coordbase + 2]; inrange.clear(); for (j = 0; j < numNodes; ++j) { coordbase = j * 3; if (std::abs(rootCoord[0] - sourceData[coordbase]) < selectrange[0] && std::abs(rootCoord[1] - sourceData[coordbase + 1]) < selectrange[1] && std::abs(rootCoord[2] - sourceData[coordbase + 2]) < selectrange[2]) { inrange.push_back(j); } } mygeo.getGeoToTheseNodes(i, inrange, distances, true); numInrange = inrange.size(); tempf = -1.0f; if (interp) { for (j = 0; j < numInrange; ++j) { whichnode = inrange[j]; coordbase = whichnode * 3; tempf2 = (1 - std::abs(rootCoord[0] - sourceData[coordbase]) / selectrange[0]) * (1 - std::abs(rootCoord[1] - sourceData[coordbase + 1]) / selectrange[1]) * (1 - std::abs(rootCoord[2] - sourceData[coordbase + 2]) / selectrange[2]); tempf3 = 1 - tempf2; tempf2 *= tempf2; tempf3 *= tempf3; tempf2 /= (tempf2 + tempf3);//this is r^2 / (r^2 + (1 - r)^2), derived forced correlation tempf2 *= distances[j];//times geodesic distance if (tempf2 > tempf) { //worstnode = whichnode; tempf = tempf2; } } } else { for (j = 0; j < numInrange; ++j) { tempf2 = distances[j]; if (tempf2 > tempf) { //worstnode = inrange[j]; tempf = tempf2; } } } //std::cout << "node " << i << ": " << worstnode << endl; outData[i] = tempf; } metricOut->setColumnForAllNodes(metricOutIndex, outData); delete[] sourceData; delete[] outData; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceAndVolume.h0000664000175000017500000002164611572067322025227 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __BRAIN_MODEL_VOLUME_AND_SURFACE_H__ #define __BRAIN_MODEL_VOLUME_AND_SURFACE_H__ #include "BrainModelSurface.h" #include "SceneFile.h" class TransformationMatrix; class VolumeFile; /// BrainModelSurfaceAndVolume allows combined volume and surface rendering class BrainModelSurfaceAndVolume : public BrainModelSurface { public: /// constructor BrainModelSurfaceAndVolume(BrainSet* bs); /// Destructor virtual ~BrainModelSurfaceAndVolume(); /// reset the volume and surface void reset(); /// Apply a transformation matrix to the surface void applyTransformationMatrix(TransformationMatrix& tm); /// initialize the selected slices void initializeSelectedSlices(); /// Get a descriptive name of the model QString getDescriptiveName() const; /// get the anatomical volume file VolumeFile* getAnatomyVolumeFile(); /// get the functional volume file VolumeFile* getFunctionalVolumeFile(); /// get the segmenation volume file VolumeFile* getSegmentationVolumeFile(); /// get the vector volume file VolumeFile* getVectorVolumeFile(); /// update functional volume surface distances void updateFunctionalVolumeSurfaceDistances(); /// get the display horizontal slice flag bool getDisplayHorizontalSlice() const { return displayHorizontalSlice; } /// set the display horizontal slice flag void setDisplayHorizontalSlice(const bool ds) { displayHorizontalSlice = ds; } /// get the display parasagittal slice flag bool getDisplayParasagittalSlice() const { return displayParasagittalSlice; } /// set the display parasagittal slice flag void setDisplayParasagittalSlice(const bool ds) { displayParasagittalSlice = ds; } /// get the display coronal slice flag bool getDisplayCoronalSlice() const { return displayCoronalSlice; } /// set the display coronal slice flag void setDisplayCoronalSlice(const bool ds) { displayCoronalSlice = ds; } /// get the display view dependent slice flag bool getDisplayViewDependentSlice() const { return displayViewDependentSlice; } /// set the display view dependent slice flag void setDisplayViewDependentSlice(const bool ds) { displayViewDependentSlice = ds; } /// get the display surface flag bool getDisplaySurface() const { return displaySurface; } /// set the display surface flag void setDisplaySurface(const bool ds); /// get the secondary overlay volume file VolumeFile* getOverlaySecondaryVolumeFile(); /// get the primary overlay volume file VolumeFile* getOverlayPrimaryVolumeFile(); /// get the voxel cloud display list unsigned int getVoxelCloudDisplayListNumber() const; /// set the voxel cloud display list void setVoxelCloudDisplayListNumber(const unsigned int num); /// clear the voxel cloud display list void clearVoxelCloudDisplayList(); /// get display segmentation volume data cloud bool getDisplaySegmentationVolumeCloud() const { return displaySegmentationVolumeCloud; } /// set display segmentation volume data cloud void setDisplaySegmentationVolumeCloud(const bool fvc); /// get display vector volume data bool getDisplayVectorVolumeCloud() const { return displayVectorVolumeCloud; } /// set display vector volume data cloud void setDisplayVectorVolumeCloud(const bool vvc) { displayVectorVolumeCloud = vvc; } /// get display functional volume data cloud bool getDisplayFunctionalVolumeCloud() const { return displayFunctionalVolumeCloud; } /// set display functional volume data cloud void setDisplayFunctionalVolumeCloud(const bool fvc); /// get functional volume cloud opacity enabled bool getFunctionalVolumeCloudOpacityEnabled() { return functionalVolumeCloudOpacityEnabled; } /// set functional volume cloud opacity enabled void setFunctionalVolumeCloudOpacityEnabled(const bool fcoe); /// get the functional volume cloud opacity float getFunctionalVolumeCloudOpacity() const { return functionalVolumeCloudOpacity; } /// set the functional volume cloud opacity void setFunctionalVolumeCloudOpacity(const float fvco) { functionalVolumeCloudOpacity = fvco; } /// get the functional volume distance threshold float getFunctionalVolumeDistanceThreshold() const { return functionalVolumeDistanceThreshold; } /// set the functional volume distance threshold void setFunctionalVolumeDistanceThreshold(const float fvdt); /// get display secondary overlay on slices bool getDisplaySecondaryOverlayVolumeOnSlices() const { return displaySecondaryOverlayVolumeOnSlices; } /// set display secondary overlay on slices void setDisplaySecondaryOverlayVolumeOnSlices(const bool sovs) { displaySecondaryOverlayVolumeOnSlices = sovs; } /// get display primary overlay on slices bool getDisplayPrimaryOverlayVolumeOnSlices() const { return displayPrimaryOverlayVolumeOnSlices; } /// set display primary overlay on slices void setDisplayPrimaryOverlayVolumeOnSlices(const bool povs) { displayPrimaryOverlayVolumeOnSlices = povs; } /// get the selected slices void getSelectedSlices(int slices[3]); /// set the selected slices void setSelectedSlices(const int slices[3]); /// Copy active fiducial surface into this surface void setSurface(); /// get draw black anatomy voxels bool getDrawAnatomyBlackVoxels() const { return drawAnatomyBlackVoxels; } /// set draw black anatomy voxels void setDrawAnatomyBlackVoxels(const bool b) { drawAnatomyBlackVoxels = b; } /// apply a scene (set display settings) void showScene(const SceneFile::Scene& scene, QString& errorMessage) ; /// create a scene (read display settings) void saveScene(SceneFile::Scene& scene, const bool onlyIfSelectedFlag); private: /// display surface flag bool displaySurface; /// display secondary overlay volume data on slices bool displaySecondaryOverlayVolumeOnSlices; /// display primary overlay volume data on slices bool displayPrimaryOverlayVolumeOnSlices; /// display the functional volume as a cloud bool displayFunctionalVolumeCloud; /// display the segmentation volume as a cloud bool displaySegmentationVolumeCloud; /// display the vector volume as a cloud bool displayVectorVolumeCloud; /// the selected slices int selectedSlices[3]; /// display horizontal slice flag bool displayHorizontalSlice; /// display parasagittal slice flag bool displayParasagittalSlice; /// display coronal slice flag bool displayCoronalSlice; /// display view dependent slice bool displayViewDependentSlice; /// functional volume cloud opacity float functionalVolumeCloudOpacity; /// functional volume cloud opacity enabled bool functionalVolumeCloudOpacityEnabled; /// functional volume distance threshold float functionalVolumeDistanceThreshold; /// voxel cloud display list number unsigned int voxelCloudDisplayListNumber; /// previous functional volume file VolumeFile* previousFunctionalVolumeFile; /// previous segmentation volume file VolumeFile* previousSegmentationVolumeFile; /// draw anatomy voxels that are black bool drawAnatomyBlackVoxels; }; #endif // __BRAIN_MODEL_VOLUME_AND_SURFACE_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceAndVolume.cxx0000664000175000017500000004177511572067322025607 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainSet.h" #include "BrainModelSurfaceAndVolume.h" #include "BrainModelSurfacePointLocator.h" #include "BrainModelVolume.h" #include "DisplaySettingsVolume.h" #include "MathUtilities.h" #include "TopologyHelper.h" #include "TransformationMatrixFile.h" #include "VolumeFile.h" /** * constructor. */ BrainModelSurfaceAndVolume::BrainModelSurfaceAndVolume(BrainSet* bs) : BrainModelSurface(bs, BrainModel::BRAIN_MODEL_SURFACE_AND_VOLUME) { voxelCloudDisplayListNumber = 0; reset(); setSurface(); } /** * Destructor. */ BrainModelSurfaceAndVolume::~BrainModelSurfaceAndVolume() { clearVoxelCloudDisplayList(); } /** * Get a descriptive name of the model. */ QString BrainModelSurfaceAndVolume::getDescriptiveName() const { return "SURFACE & VOLUME"; } /** * Copy active fiducial surface into this surface */ void BrainModelSurfaceAndVolume::setSurface() { coordinates.clear(); topology = NULL; normals.clear(); surfaceType = SURFACE_TYPE_UNKNOWN; BrainModelSurface* bms = brainSet->getActiveFiducialSurface(); if (bms != NULL) { coordinates = *(bms->getCoordinateFile()); topology = bms->getTopologyFile(); setSurfaceType(SURFACE_TYPE_FIDUCIAL); computeNormals(); setStructure(bms->getStructure()); } } /** * Reset the volume. */ void BrainModelSurfaceAndVolume::reset() { BrainModelSurface::reset(); previousFunctionalVolumeFile = NULL; previousSegmentationVolumeFile = NULL; selectedSlices[0] = 0; selectedSlices[1] = 0; selectedSlices[2] = 0; displayHorizontalSlice = true; displayParasagittalSlice = true; displayCoronalSlice = true; displayViewDependentSlice = false; displaySurface = true; displayFunctionalVolumeCloud = false; displaySegmentationVolumeCloud = false; displayVectorVolumeCloud = false; displaySecondaryOverlayVolumeOnSlices = false; displayPrimaryOverlayVolumeOnSlices = false; functionalVolumeCloudOpacity = 0.5; functionalVolumeCloudOpacityEnabled = false; functionalVolumeDistanceThreshold = 1000.0; drawAnatomyBlackVoxels = true; clearVoxelCloudDisplayList(); } /** * Apply a transformation matrix to the surface. */ void BrainModelSurfaceAndVolume::applyTransformationMatrix(TransformationMatrix& tm) { const TopologyHelper* th = topology->getTopologyHelper(false, true, false); const int numNodes = getNumberOfNodes(); for (int i = 0; i < numNodes; i++) { float xyz[3] = { 0.0, 0.0, 0.0 }; if (th->getNodeHasNeighbors(i)) { coordinates.getCoordinate(i, xyz); double p[4] = { xyz[0], xyz[1], xyz[2], 1.0 }; tm.multiplyPoint(p); xyz[0] = p[0]; xyz[1] = p[1]; xyz[2] = p[2]; } coordinates.setCoordinate(i, xyz); } computeNormals(); } /** * Initialize the selected slices */ void BrainModelSurfaceAndVolume::initializeSelectedSlices() { VolumeFile* vf = getAnatomyVolumeFile(); if (vf != NULL) { int voxelDimensions[3]; vf->getDimensions(voxelDimensions); selectedSlices[0] = voxelDimensions[0] / 2; selectedSlices[1] = voxelDimensions[1] / 2; selectedSlices[2] = voxelDimensions[2] / 2; } } /** * Get the selected slices. */ void BrainModelSurfaceAndVolume::getSelectedSlices(int slices[3]) { slices[0] = selectedSlices[0]; slices[1] = selectedSlices[1]; slices[2] = selectedSlices[2]; VolumeFile* vf = getAnatomyVolumeFile(); if (vf != NULL) { int dim[3]; vf->getDimensions(dim); if ((slices[0] >= dim[0]) || (slices[1] >= dim[1]) || (slices[2] >= dim[2])) { initializeSelectedSlices(); slices[0] = selectedSlices[0]; slices[1] = selectedSlices[1]; slices[2] = selectedSlices[2]; } } } /** * Set the selected slices. */ void BrainModelSurfaceAndVolume::setSelectedSlices(const int slices[3]) { selectedSlices[0] = slices[0]; selectedSlices[1] = slices[1]; selectedSlices[2] = slices[2]; } /** * get the selected anatomy volume file. */ VolumeFile* BrainModelSurfaceAndVolume::getAnatomyVolumeFile() { DisplaySettingsVolume* dsv = brainSet->getDisplaySettingsVolume(); VolumeFile* anatomyVolumeFile = NULL; if ((dsv->getSelectedAnatomyVolume() >= 0) && (dsv->getSelectedAnatomyVolume() < brainSet->getNumberOfVolumeAnatomyFiles())) { anatomyVolumeFile = brainSet->getVolumeAnatomyFile(dsv->getSelectedAnatomyVolume()); } return anatomyVolumeFile; } /** * get the selected functional volume file. */ VolumeFile* BrainModelSurfaceAndVolume::getFunctionalVolumeFile() { DisplaySettingsVolume* dsv = brainSet->getDisplaySettingsVolume(); VolumeFile* functionalVolumeFile = NULL; if ((dsv->getSelectedFunctionalVolumeView() >= 0) && (dsv->getSelectedFunctionalVolumeView() < brainSet->getNumberOfVolumeFunctionalFiles())) { functionalVolumeFile = brainSet->getVolumeFunctionalFile(dsv->getSelectedFunctionalVolumeView()); } if (functionalVolumeFile != previousFunctionalVolumeFile) { clearVoxelCloudDisplayList(); } previousFunctionalVolumeFile = functionalVolumeFile; return functionalVolumeFile; } /** * get the selected segmentation volume file. */ VolumeFile* BrainModelSurfaceAndVolume::getSegmentationVolumeFile() { DisplaySettingsVolume* dsv = brainSet->getDisplaySettingsVolume(); VolumeFile* segmentationVolumeFile = NULL; if ((dsv->getSelectedSegmentationVolume() >= 0) && (dsv->getSelectedSegmentationVolume() < brainSet->getNumberOfVolumeSegmentationFiles())) { segmentationVolumeFile = brainSet->getVolumeSegmentationFile(dsv->getSelectedSegmentationVolume()); } if (segmentationVolumeFile != previousSegmentationVolumeFile) { //clearVoxelCloudDisplayList(); } previousSegmentationVolumeFile = segmentationVolumeFile; return segmentationVolumeFile; } /** * get the selected vector volume file. */ VolumeFile* BrainModelSurfaceAndVolume::getVectorVolumeFile() { DisplaySettingsVolume* dsv = brainSet->getDisplaySettingsVolume(); VolumeFile* vectorVolumeFile = NULL; if ((dsv->getSelectedVectorVolume() >= 0) && (dsv->getSelectedVectorVolume() < brainSet->getNumberOfVolumeVectorFiles())) { vectorVolumeFile = brainSet->getVolumeVectorFile(dsv->getSelectedVectorVolume()); } return vectorVolumeFile; } /** * get the secondary overlay volume file. */ VolumeFile* BrainModelSurfaceAndVolume::getOverlaySecondaryVolumeFile() { BrainModelVolume* bmv = brainSet->getBrainModelVolume(); if (bmv != NULL) { return bmv->getOverlaySecondaryVolumeFile(); } return NULL; } /** * get the voxel cloud display list. */ unsigned int BrainModelSurfaceAndVolume::getVoxelCloudDisplayListNumber() const { return voxelCloudDisplayListNumber; } /** * set the voxel cloud display list. */ void BrainModelSurfaceAndVolume::setVoxelCloudDisplayListNumber(const unsigned int num) { voxelCloudDisplayListNumber = num; } /** * clear the voxel cloud display list. */ void BrainModelSurfaceAndVolume::clearVoxelCloudDisplayList() { if (voxelCloudDisplayListNumber > 0) { glDeleteLists(voxelCloudDisplayListNumber, 1); voxelCloudDisplayListNumber = 0; } } /** * set display functional volume data on slices. */ void BrainModelSurfaceAndVolume::setDisplayFunctionalVolumeCloud(const bool fvc) { displayFunctionalVolumeCloud = fvc; clearVoxelCloudDisplayList(); } /** * set display segmentation volume data cloud. */ void BrainModelSurfaceAndVolume::setDisplaySegmentationVolumeCloud(const bool fvc) { displaySegmentationVolumeCloud = fvc; } /** * set functional volume cloud opacity enabled. */ void BrainModelSurfaceAndVolume::setFunctionalVolumeCloudOpacityEnabled(const bool fcoe) { functionalVolumeCloudOpacityEnabled = fcoe; clearVoxelCloudDisplayList(); } /** * set the functional volume distance threshold. */ void BrainModelSurfaceAndVolume::setFunctionalVolumeDistanceThreshold(const float fvdt) { functionalVolumeDistanceThreshold = fvdt; clearVoxelCloudDisplayList(); } /** * get the primary overlay volume file. */ VolumeFile* BrainModelSurfaceAndVolume::getOverlayPrimaryVolumeFile() { BrainModelVolume* bmv = brainSet->getBrainModelVolume(); if (bmv != NULL) { return bmv->getOverlayPrimaryVolumeFile(); } return NULL; } /** * Update functional volume file voxel to surface distances */ void BrainModelSurfaceAndVolume::updateFunctionalVolumeSurfaceDistances() { BrainModelSurface* bms = brainSet->getActiveFiducialSurface(); if (bms != NULL) { VolumeFile* vf = getFunctionalVolumeFile(); if (vf->getVoxelToSurfaceDistancesValid() == false) { if (vf != NULL) { float* voxelToSurfaceDistances = vf->getVoxelToSurfaceDistances(); if (voxelToSurfaceDistances != NULL) { // // Point locator for finding node nearest to voxels // BrainModelSurfacePointLocator pl(bms, true); // // Get volume dimensions // int dim[3]; vf->getDimensions(dim); // // Get volume spacing // float spacing[3]; vf->getSpacing(spacing); const float sx = spacing[0]; const float sy = spacing[1]; const float sz = spacing[2]; // // Get volume origin in center of voxel // float origin[3]; vf->getOrigin(origin); const float ox = origin[0] + sx * 0.5; const float oy = origin[1] + sy * 0.5; const float oz = origin[2] + sz * 0.5; const CoordinateFile* cf = bms->getCoordinateFile(); // // do all voxels // for (int i = 0; i < dim[0]; i++) { for (int j = 0; j < dim[1]; j++) { for (int k = 0; k < dim[2]; k++) { int ijk[3] = { i, j, k }; const int id = vf->getVoxelNumber(ijk); if (id >= 0) { // // XYZ of voxel center // const float xyz[3] = { ox + sx * i, oy + sy * j, oz + sz * k }; const int node = pl.getNearestPoint(xyz); float dist = 0.0; if (node >= 0) { const float* nodeXYZ = cf->getCoordinate(node); dist = MathUtilities::distance3D(nodeXYZ, xyz); } voxelToSurfaceDistances[id] = dist; } } } } vf->setVoxelToSurfaceDistancesValid(true); } } } } } /** * set the display surface flag. */ void BrainModelSurfaceAndVolume::setDisplaySurface(const bool ds) { // // If turning surface on/off need to delete display lists // if (displaySurface != ds) { brainSet->clearAllDisplayLists(); } displaySurface = ds; } /** * apply a scene (set display settings). */ void BrainModelSurfaceAndVolume::showScene(const SceneFile::Scene& scene, QString& /*errorMessage*/) { const int numClasses = scene.getNumberOfSceneClasses(); for (int nc = 0; nc < numClasses; nc++) { const SceneFile::SceneClass* sc = scene.getSceneClass(nc); if (sc->getName() == "BrainModelSurfaceAndVolume") { const int num = sc->getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc->getSceneInfo(i); const QString infoName = si->getName(); if (infoName == "displaySurface") { si->getValue(displaySurface); } else if (infoName == "displaySecondaryOverlayVolumeOnSlices") { si->getValue(displaySecondaryOverlayVolumeOnSlices); } else if (infoName == "displayPrimaryOverlayVolumeOnSlices") { si->getValue(displayPrimaryOverlayVolumeOnSlices); } else if (infoName == "displayFunctionalVolumeCloud") { si->getValue(displayFunctionalVolumeCloud); } else if (infoName == "displaySegmentationVolumeCloud") { si->getValue(displaySegmentationVolumeCloud); } else if (infoName == "selectedSlices0") { si->getValue(selectedSlices[0]); } else if (infoName == "selectedSlices1") { si->getValue(selectedSlices[1]); } else if (infoName == "selectedSlices2") { si->getValue(selectedSlices[2]); } else if (infoName == "displayHorizontalSlice") { si->getValue(displayHorizontalSlice); } else if (infoName == "displayParasagittalSlice") { si->getValue(displayParasagittalSlice); } else if (infoName == "displayCoronalSlice") { si->getValue(displayCoronalSlice); } else if (infoName == "functionalVolumeCloudOpacity") { si->getValue(functionalVolumeCloudOpacity); } else if (infoName == "functionalVolumeCloudOpacityEnabled") { si->getValue(functionalVolumeCloudOpacityEnabled); } else if (infoName == "drawAnatomyBlackVoxels") { si->getValue(drawAnatomyBlackVoxels); } } } } } /** * create a scene (read display settings). */ void BrainModelSurfaceAndVolume::saveScene(SceneFile::Scene& scene, const bool /*onlyIfSelectedFlag*/) { SceneFile::SceneClass sc("BrainModelSurfaceAndVolume"); sc.addSceneInfo(SceneFile::SceneInfo("displaySurface", displaySurface)); sc.addSceneInfo(SceneFile::SceneInfo("displaySecondaryOverlayVolumeOnSlices", displaySecondaryOverlayVolumeOnSlices)); sc.addSceneInfo(SceneFile::SceneInfo("displayPrimaryOverlayVolumeOnSlices", displayPrimaryOverlayVolumeOnSlices)); sc.addSceneInfo(SceneFile::SceneInfo("displayFunctionalVolumeCloud", displayFunctionalVolumeCloud)); sc.addSceneInfo(SceneFile::SceneInfo("displaySegmentationVolumeCloud", displaySegmentationVolumeCloud)); sc.addSceneInfo(SceneFile::SceneInfo("selectedSlices0", selectedSlices[0])); sc.addSceneInfo(SceneFile::SceneInfo("selectedSlices1", selectedSlices[1])); sc.addSceneInfo(SceneFile::SceneInfo("selectedSlices2", selectedSlices[2])); sc.addSceneInfo(SceneFile::SceneInfo("displayHorizontalSlice", displayHorizontalSlice)); sc.addSceneInfo(SceneFile::SceneInfo("displayParasagittalSlice", displayParasagittalSlice)); sc.addSceneInfo(SceneFile::SceneInfo("displayCoronalSlice", displayCoronalSlice)); sc.addSceneInfo(SceneFile::SceneInfo("functionalVolumeCloudOpacity", functionalVolumeCloudOpacity)); sc.addSceneInfo(SceneFile::SceneInfo("functionalVolumeCloudOpacityEnabled", functionalVolumeCloudOpacityEnabled)); sc.addSceneInfo(SceneFile::SceneInfo("drawAnatomyBlackVoxels", drawAnatomyBlackVoxels)); scene.addSceneClass(sc); } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceAffineRegression.h0000664000175000017500000000367611572067322026571 0ustar michaelmichael #ifndef __BRAIN_MODEL_SURFACE_AFFINE_REGRESSION_H__ #define __BRAIN_MODEL_SURFACE_AFFINE_REGRESSION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelAlgorithm.h" class CoordinateFile; /// class for create a functional volume using a probabilistic volume class BrainModelSurfaceAffineRegression : public BrainModelAlgorithm { public: /// Constructor BrainModelSurfaceAffineRegression(BrainSet* bs, CoordinateFile* sourceIn, CoordinateFile* targetIn, CoordinateFile* registeredOutIn, const QString& coordNameIn); /// Destructor ~BrainModelSurfaceAffineRegression(); /// execute the algorithm void execute() throw (BrainModelAlgorithmException); double getAffine(short i, short j); private: CoordinateFile* source, *target, *registered; QString coordName; double affine[3][4]; }; #endif // __BRAIN_MODEL_VOLUME_LIGASE_SEGMENTATION_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurfaceAffineRegression.cxx0000664000175000017500000001613311572067322027134 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelVolume.h" #include "BrainModelSurfaceAffineRegression.h" #include "BrainSet.h" #include "CoordinateFile.h" #include /** * Constructor. */ BrainModelSurfaceAffineRegression::BrainModelSurfaceAffineRegression( BrainSet* bs, CoordinateFile* sourceIn, CoordinateFile* targetIn, CoordinateFile* registeredOutIn, const QString& coordNameIn) : BrainModelAlgorithm(bs) { source = sourceIn; target = targetIn; registered = registeredOutIn; coordName = coordNameIn; } /** * Destructor. */ BrainModelSurfaceAffineRegression::~BrainModelSurfaceAffineRegression() { } /** * execute the algorithm. */ void BrainModelSurfaceAffineRegression::execute() throw (BrainModelAlgorithmException) { // // Verify files exist, are valid, etc. // if (source == NULL || target == NULL) { throw BrainModelAlgorithmException("Invalid coordinate file."); } if (source->getNumberOfCoordinates() < 1) { throw BrainModelAlgorithmException("Not enough nodes in coordinate files."); } if (source->getNumberOfCoordinates() != target->getNumberOfCoordinates()) { throw BrainModelAlgorithmException("Node numbers do not match."); } // // Create output coord file if neccesary // bool createdRegisteredCoord = false; BrainModelSurface *mySurf = NULL; if (registered == NULL) { mySurf = new BrainModelSurface(brainSet); registered = mySurf->getCoordinateFile(); registered->setNumberOfCoordinates(source->getNumberOfCoordinates()); createdRegisteredCoord = true; } if (source->getNumberOfCoordinates() != registered->getNumberOfCoordinates()) { registered->setNumberOfCoordinates(source->getNumberOfCoordinates()); } registered->setFileName(coordName); // // Initialization // double indep[4][4]; double dep[3][4]; double tempd; long i, j, k, l, nodes = source->getNumberOfCoordinates(); long triples = nodes * 3; float* sourceData = new float[triples]; float* targetData = new float[triples]; float* registeredData = new float[triples]; source->getAllCoordinates(sourceData); target->getAllCoordinates(targetData); for (i = 0; i < 3; ++i) { for (j = 0; j < 4; ++j) { dep[i][j] = 0.0; indep[i][j] = 0.0; } } for (i = 0; i < 4; ++i) indep[3][i] = 0.0; // // Gather Xt * X and (Xt * Y)'s from the normal equations // for (i = 0; i < triples; i += 3) { for (j = 0; j < 3; ++j) { for (k = 0; k < 3; ++k) { indep[j][k] += ((double)sourceData[i + j]) * ((double)sourceData[i + k]); dep[j][k] += ((double)sourceData[i + k]) * ((double)targetData[i + j]); } indep[j][3] += (double)sourceData[i + j]; dep[j][3] += (double)targetData[i + j]; } for (j = 0; j < 3; ++j) { indep[3][j] += (double)sourceData[i + j]; } indep[3][3] += 1.0; } double rref[5][4]; for (i = 0; i < 3; ++i) { // // Set up a normal equation as a system of linear equations, solve by reduced row echelon form // for (j = 0; j < 5; ++j) { for (k = 0; k < 4; ++k) { if (j == 4) { rref[j][k] = dep[i][k]; } else { rref[j][k] = indep[j][k]; } } } // // Reduced row echelon computation // for (j = 0; j < 4; ++j) { // // Find pivot row, swap if needed // if (rref[j][j] == 0.0)//naive expectance of exact 0 for nonpivot, but shouldn't happen anyway { k = j + 1; while (k < 4 && rref[j][k] == 0.0) ++k;//ditto if (k == 4) { delete[] sourceData; delete[] targetData; delete[] registeredData; throw BrainModelAlgorithmException("Pivot missing, does the surface have 3 independent dimensions?"); } for (l = 0; l < 5; ++l) { tempd = rref[l][j]; rref[l][j] = rref[l][k]; rref[l][k] = tempd; } } // // Divide by pivot to get leading 1 // tempd = rref[j][j]; for (k = 0; k < 5; ++k) { rref[k][j] /= tempd; } // // Zero the rest of the pivot column via row operations // for (k = 0; k < 4; ++k)//assumes exact 1 after division by itself, such that all other rows in the pivot column will be zeroed {//by simple subtraction of the assumed one times the value of the position to be zeroed, but all we want is the last column anyway if (k != j) { tempd = rref[j][k]; for (l = 0; l < 5; ++l) { rref[l][k] -= rref[l][j] * tempd; } } } }//rref complete! // // Copy solution into appropriate column of affine transformation matrix (3x3, multiply X by it to get transformed coordinates) // for (j = 0; j < 4; ++j) { affine[i][j] = rref[4][j]; } }//affine computation complete! // // Matrix multiplication by affine transform matrix // for (i = 0; i < triples; i += 3) { for (j = 0; j < 3; ++j) { registeredData[i + j] = 0.0f; for (k = 0; k < 3; ++k) { registeredData[i + j] += affine[j][k] * ((double)sourceData[i + k]); } registeredData[i + j] += affine[j][3]; } } // // Set the new coordinates // registered->setAllCoordinates(registeredData); // // Add new registered coordinate file to brain set // if (createdRegisteredCoord) { brainSet->addBrainModel(mySurf); } delete[] sourceData; delete[] targetData; delete[] registeredData; } double BrainModelSurfaceAffineRegression::getAffine(short i, short j) { return affine[i][j]; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurface.h0000664000175000017500000006136511572067322023416 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_SURFACE_H__ #define __VE_SURFACE_H__ #include "vtkPolyData.h" #include "BrainModel.h" #include "CoordinateFile.h" #include "Structure.h" class BorderFile; class BorderProjection; class BrainModelSurfaceROINodeSelection; class BrainVoyagerFile; class CellProjectionFile; class DeformationFieldFile; class LatLonFile; class MetricFile; class MniObjSurfaceFile; class PaintFile; class RgbPaintFile; class SurfaceShapeFile; class TopologyFile; class VectorFile; /// BrainModelSurface stores geometry and topology for a brain surface /** * Stores the geometry and topology for a surface and methods for * operations on the surface. */ class BrainModelSurface : public BrainModel { public: /// Types of surfaces enum SURFACE_TYPES { SURFACE_TYPE_RAW, SURFACE_TYPE_FIDUCIAL, SURFACE_TYPE_INFLATED, SURFACE_TYPE_VERY_INFLATED, SURFACE_TYPE_SPHERICAL, SURFACE_TYPE_ELLIPSOIDAL, SURFACE_TYPE_COMPRESSED_MEDIAL_WALL, SURFACE_TYPE_FLAT, SURFACE_TYPE_FLAT_LOBAR, SURFACE_TYPE_HULL, SURFACE_TYPE_UNKNOWN, SURFACE_TYPE_UNSPECIFIED }; /// Plane for modifying coordinates enum COORDINATE_PLANE { COORDINATE_PLANE_NONE, COORDINATE_PLANE_MOVE_POSITIVE_X_TO_ZERO, COORDINATE_PLANE_MOVE_NEGATIVE_X_TO_ZERO, COORDINATE_PLANE_MOVE_POSITIVE_Y_TO_ZERO, COORDINATE_PLANE_MOVE_NEGATIVE_Y_TO_ZERO, COORDINATE_PLANE_MOVE_POSITIVE_Z_TO_ZERO, COORDINATE_PLANE_MOVE_NEGATIVE_Z_TO_ZERO, COORDINATE_PLANE_RESTORE }; /// Constructor BrainModelSurface(BrainSet* bs, const BrainModel::BRAIN_MODEL_TYPE bmt = BrainModel::BRAIN_MODEL_SURFACE); /// Copy constructor BrainModelSurface(const BrainModelSurface& bms); /// Destructor virtual ~BrainModelSurface(); /// add a node to the surface void addNode(const float xyz[3]); /// Align to standard orientation (flat or spherical) void alignToStandardOrientation(const BrainModelSurface* fiducialSurface, const BorderProjection* centralSulcusBorderProjection, const bool generateSphericalLatitudeLongitude, const bool scaleToFiducialArea); /// Align to standard orientation (flat or spherical) void alignToStandardOrientation(const int ventralTipCentralSulcusNode, const int dorsalMedialTipCentralSulcusNode, const bool generateSphericalLatitudeLongitude, const bool scaleToFiducialArea); /// Apply a transformation matrix to the surface void applyTransformationMatrix(TransformationMatrix& tm); /// apply a view (transformation) to the coordinates of the surface void applyViewToCoordinates(const BrainModel::STANDARD_VIEWS surfaceView); /// Apply current view to surface void applyCurrentView(const int surfaceViewNumber, const bool applyTranslation, const bool applyRotation, const bool applyScaling); /// OLD Apply current view to surface that uses OpenGL void OLDapplyCurrentView(const int surfaceViewNumber, const bool applyTranslation, const bool applyRotation, const bool applyScaling); /// smooth the surface by moving nodes along their normals multiplied by curvature. void smoothSurfaceUsingCurvature(const float strength, const int numSteps, const float curvatureMaximum); /// expand the surface by moving nodes along their normals by the specified amount void expandSurface(const float expandAmount); /// get the number of nodes in the surface int getNumberOfNodes() const { return coordinates.getNumberOfCoordinates(); } /// get information about the surface void getSurfaceInformation(std::vector& labels, std::vector& values) const; /// get the name of the coordinate file QString getFileName() const { return coordinates.getFileName(); } /// Get a descriptive name of the model virtual QString getDescriptiveName() const; /// append a string to the coordinate file's comment void appendToCoordinateFileComment(const QString& s); /// append a string to the topology file's comment void appendToTopologyFileComment(const QString& s); /// get node closest to point int getNodeClosestToPoint(const float xyz[3]) const; /// get access to coordinate file for this surface CoordinateFile* getCoordinateFile() { return &coordinates; } /// get access to coordinate file for this surface (const method) const CoordinateFile* getCoordinateFile() const { return &coordinates; } /// create latitude longitude for this surface void createLatitudeLongitude(LatLonFile* llf, const int columnNumber, const QString& columnNameIn, const bool setDeformedLatLonFlag, const bool sphereInDorsalViewFlag); /// create spherical lat/lon borders for this surface void createSphericalLatLonBorders(BorderFile& bf, const bool sphereInDorsalViewFlag); /// create flat grid borders for this surface void createFlatGridBorders(BorderFile& bf, const float gridSpacing, const int pointSpacing); /// create flat grid borders for analysis void createFlatGridBordersForAnalysis(BorderFile& bf, const float bounds[4], const float resolution); /// Create deformation field vectors for an ATLAS surface. void createDeformationField(const BrainModelSurface* indivSourceSurface, const BrainModelSurface* indivDeformSurface, const int columnNumberIn, const QString& columnName, DeformationFieldFile& dff) const; /// Create deformation field vectors for a surface and its deformed surface. void createDeformationField(const BrainModelSurface* deformedSurface, const int columnNumber, const QString& columnName, DeformationFieldFile& dff) const; /// compute normals void computeNormals(const float* coordsIn = NULL); /// copy normals to vector file void copyNormalsToVectorFile(VectorFile* vf) const; /// convert to a sphere with the specified area void convertToSphereWithSurfaceArea(const float desiredSphereArea = 0.0); /// convert to a sphere with the specified radius void convertToSphereWithRadius(const float radius, const int startNodeIndexIn = -1, const int endNodeIndexIn = -1); /// convert an elliptical surface to a sphere (if area is zero the ellipsoid area will be used) void convertEllipsoidToSphereWithSurfaceArea(const float desiredSphereArea = 0); /// convert a sphere to a compressed medial wall surface void convertSphereToCompressedMedialWall(const float compressionFactor = 0.5); /// move the surface so that the midpoint of the surface is at the origin void translateMidpointToOrigin(); /// convert a sphere to a flat surface void convertSphereToFlat(); /// convert to an ellipsoid surface void convertToEllipsoid(); /// Create the inflated and ellipsoid surfaces starting from a fiducial surface. void createInflatedAndEllipsoidFromFiducial(const bool createInflated, const bool createVeryInflated, const bool createEllipsoid, const bool createSphere, const bool createCompressedMedialWall, const bool enableFingerSmoothing, const bool scaleToMatchFiducialArea, const float iterationsScale, MetricFile* metricMeasurementsFile, const float compressionFactorIn = 0.95) const; /// convert "this" surface to VTK PolyData vtkPolyData* convertToVtkPolyData() const; /// copy the coordinates from the VTK PolyData to this surface void copyCoordinatesFromVTK(vtkPolyData* polyData); /// copy the topology from the VTK PolyData to this surface void copyTopologyFromVTK(vtkPolyData* polyData); /// Rotate a surface so that the node is on the positive Z-axis (facing user). void orientNodeToPositiveScreenZ(const int nodeNumber, const int surfaceViewNumber); /// compress the front face of a surface. void compressFrontFace(const float compressionFactor, const int surfaceViewNumber); /// convert normals to rgb paint void convertNormalsToRgbPaint(RgbPaintFile* rpf); /// get normal for a point const float* getNormal(const int coordinateNumber) const { return &normals[coordinateNumber * 3]; } /// set a normal void setNormal(const int coordinateNumber, const float normalVector[3]); /// get the radius of a spherical surface (assumes spherical surface with center at origin) float getSphericalSurfaceRadius() const; /// perform a crossover check (returns number of crossover tiles void crossoverCheck(int& numberOfTileCrossoversOut, int& numberOfNodeCrossoversOut, const SURFACE_TYPES surfaceTypeHint = SURFACE_TYPE_UNKNOWN); /// surefit ellipsoid crossover check int crossoverCheckSureFitEllipsoid(); /// get the bounds of the connected surface void getBounds(float bounds[6]) const; /// get the display list for this brain model unsigned int getDisplayListNumber(); /// set the display list for this brain model void setDisplayListNumber(unsigned int num); /// import from a brain voyager file void importFromBrainVoyagerFile(const BrainVoyagerFile& bvf) throw (FileException); /// import from a MNI OBJ Surface File void importFromMniObjSurfaceFile(const MniObjSurfaceFile& mni) throw (FileException); /// import from a VTK surface file void importFromVtkFile(vtkPolyData* polyData, const QString& fileName) throw (FileException); /// allocate and initialize the normals void initializeNormals(const int numCoordsIn = -1); /// move disconnected nodes to origin void moveDisconnectedNodesToOrigin(); /// reset the surface virtual void reset(); /// get access to the topology for this surface TopologyFile* getTopologyFile() const { return topology; } /// see if the surface is topologically correct (has no handles) bool isTopologicallyCorrect() const; /// read the specified coordinate file void readCoordinateFile(const QString& filename) throw(FileException); /// read the specified surface file void readSurfaceFile(const QString& filename) throw(FileException); /// write the surface file void writeSurfaceFile(const QString& filename, const AbstractFile::FILE_FORMAT fileFormat = AbstractFile::FILE_FORMAT_XML) throw (FileException); /// write the file's memory in caret6 format to the specified name QString writeSurfaceInCaret6Format(const QString& filenameIn, const QString& prependToFileNameExtension, Structure structure, const bool useCaret6ExtensionFlag) throw (FileException); /// get the structure Structure getStructure() const { return structure; } /// set the structure void setStructure(const Structure::STRUCTURE_TYPE st); /// set the structure void setStructure(const Structure s); /// see if surface is a fiducial surface bool getIsFiducialSurface() const; /// see if surface is a flat surface bool getIsFlatSurface() const; /// get the surface type SURFACE_TYPES getSurfaceType() const { return surfaceType; } /// get the surface type's name QString getSurfaceTypeName() const; /// get the surface type from a surface configuration ID static SURFACE_TYPES getSurfaceTypeFromConfigurationID(const QString& name); /// get the configuration ID from the surface type static QString getSurfaceConfigurationIDFromType(const SURFACE_TYPES st); /// Get the spec file tag from the coord type. static QString getCoordSpecFileTagFromSurfaceType(const SURFACE_TYPES st); /// Get the spec file tag from the surface type. static QString getSurfaceSpecFileTagFromSurfaceType(const SURFACE_TYPES st); /// Get all surface types and names static void getSurfaceTypesAndNames(std::vector& typesOut, std::vector& typeNamesOut); /// flip the normals void flipNormals(); /// orient the normals so that they point out of the surface (returns true if flipped) bool orientNormalsOut(); /// orient the tiles consistently void orientTilesConsistently(); /// orient all tiles so that each tile's normal points outward (flat and sphere only) void orientTilesOutward(const SURFACE_TYPES st); /// get the area of the surface float getSurfaceArea(const TopologyFile* tfin = NULL) const; // get the volume displacment of the surface float getSurfaceVolumeDisplacement() const; /// Get the area of a tile in the surface float getTileArea(const int tileNum) const; /// Get the area of a tile in the surface using three nodes float getTileArea(const int n1, const int n2, const int n3) const; /// get the area of all tiles void getAreaOfAllTiles(std::vector& tileAreas) const; /// get the area of all nodes void getAreaOfAllNodes(std::vector& nodeAreas) const; /// get the mean distance between nodes void getMeanDistanceBetweenNodes(BrainModelSurfaceROINodeSelection* surfaceROI, float& meanDist, float& minDist, float& maxDist) const; /// push (save) the coordinates void pushCoordinates(); /// pop (restore) the coordinates (must have done a push prior to this call) void popCoordinates(); /// project the coordinates to a plane void projectCoordinatesToPlane(const COORDINATE_PLANE plane); /// Scale a surface to the specified area. void scaleSurfaceToArea(const float desiredArea, const bool flatRatioFlag); /// set the surface type void setSurfaceType(const SURFACE_TYPES st); /// set the topology file for this surface (returns true if topology has more nodes than coord) bool setTopologyFile(TopologyFile* topologyIn); /// get the rotation matrix //vtkTransform* getRotationTransformMatrix(const int surfaceViewNumber) { // return rotationMatrix[surfaceViewNumber]; //} /// get the surface's scaling //float getScaling(const int surfaceViewNumber) const { // return scaling[surfaceViewNumber]; //} /// set the surface's scaling //void setScaling(const int surfaceViewNumber, const float scaleIn) { // scaling[surfaceViewNumber] = scaleIn; //} /// get the default scale float getDefaultScaling() const { return defaultScaling; } /// set the default scaling void setDefaultScaling(const float scale); /// set the default scale from orthographic projection void setDefaultScaling(const double orthoRight, const double orthoTop); /// update the default scaling void updateForDefaultScaling(); /// set to a standard view virtual void setToStandardView(const int surfaceViewNumber, const STANDARD_VIEWS view); /// apply surface shape to a surface (typically a flat or spherical surface) void applyShapeToSurface(const SurfaceShapeFile& ssf, const int shapeColumn, const float shapeMultiplier); /// inflate the surface void inflate(const int smoothingIterations, const int inflationIterations, const float inflationFactor); /// Inflate surface and smooth fingers void inflateSurfaceAndSmoothFingers(const BrainModelSurface* fiducialSurfaceIn, const int numberSmoothingCycles, const float regularSmoothingStrength, const int regularSmoothingIterations, const float inflationFactor, const float compressStretchThreshold, const float fingerSmoothingStrength, const int fingerSmoothingIterations, MetricFile* metricMeasurementsFile); /// translate a surface to its center of mass void translateToCenterOfMass(); /// get the center of mass for a surface void getCenterOfMass(float centerOfMass[3]) const; /// orient nodes with paint to be on negative Z axis /// (returns true if matching nodes were NOT found) bool orientPaintedNodesToNegativeZAxis(const PaintFile* paintFile, const std::vector paintNames, const int paintColumn, QString& errorMessage); /// orient a sphere so that the point is placed on the negative Z axis void orientPointToNegativeZAxis(const float p[3]); /// orient a sphere so that the point is placed on the positive Z axis void orientPointToPositiveZAxis(const float p[3]); /// linearly smooth the surface void linearSmoothing(const float strength, const int iterations, const int smoothEdgesEveryXIterations, const std::vector* smoothOnlyTheseNodes = NULL, const int projectToSphereEveryXIterations = -1); /// linearly smooth the surface void arealSmoothing(const float strength, const int iterations, const int smoothEdgesEveryXIterations, const std::vector* smoothOnlyTheseNodes = NULL, const int projectToSphereEveryXIterations = -1); /// landmark constrained areal smoothing void landmarkConstrainedSmoothing(const float strength, const int iterations, const std::vector& landmarkNodeFlag, const int projectToSphereEveryXIterations); /// Performed landmark neighbor constrained smoothing. void landmarkNeighborConstrainedSmoothing(const float strength, const int iterations, const std::vector& landmarkNodeFlag, const int smoothNeighborsEveryX, const int projectToSphereEveryXIterations); /// (try to) smooth out flat surface overlap bool smoothOutFlatSurfaceOverlap(const float strength = 0.5, const int numberOfCycles = 5, const int iterationsPerCycle = 50, const int smoothEdgesEveryXIterations = 10, const int neighborDepth = 10); /// Smooth out crossovers in a surface void smoothOutSurfaceCrossovers(const float strength = 1.0, const int numberOfCycles = 5, const int iterationsPerCycle = 10, const int smoothEdgesEveryXIterations = 10, const int projectToSphereEveryXIterations = -1, const int neighborDepth = 5, const SURFACE_TYPES surfaceTypeHint = SURFACE_TYPE_UNKNOWN); /// mark neighbor nodes to specified depth void markNeighborNodesToDepth(std::vector& nodeFlags, const int depth); /// simplify the surface to a fewer number of polygons vtkPolyData* simplifySurface(const int maxPolygons) const; /// Create a string of c-language arrays containing vertices, normals, triangles QString convertToCLanguageArrays() const; protected: // // NOTE NOTE NOTE NOTE NOTE NOTE NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!! // // If any members are added, update the copy constructor // /// Coordinates for this surface CoordinateFile coordinates; /// Pointer to topology for this surface (Do not ever "delete" topology) TopologyFile* topology; /// Normal vectors std::vector normals; /// surface type SURFACE_TYPES surfaceType; /// structure Structure structure; /// Default scale float defaultScaling; /// default perspective zooming float defaultPerspectiveZooming; /// Saved coordinates for push and pop operations std::vector pushPopCoordinates; /// half of display for default scaling in X float displayHalfX; /// half of display for default scaling in Y float displayHalfY; /// last topology modification status unsigned long lastTopologyModificationNumber; // // NOTE NOTE NOTE NOTE NOTE NOTE NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!! // // If any members are added, update the copy constructor // }; #endif caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelSurface.cxx0000664000175000017500000073714611572067322024000 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include // needed for Q_OS_WIN32 #ifdef Q_OS_WIN32 // required for M_PI in #define _USE_MATH_DEFINES #define NOMINMAX #endif #include #include #include #include #include #include #include #include #include "vtkCellArray.h" #include "vtkDecimatePro.h" #include "vtkDelaunay3D.h" #include "vtkMath.h" #include "vtkPointData.h" #include "vtkPolyDataNormals.h" #include "vtkTransform.h" #include "vtkTriangle.h" #include "vtkTriangleFilter.h" #include "vtkUnstructuredGrid.h" #include "BorderFile.h" #include "BorderProjectionFile.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceCurvature.h" #include "BrainModelSurfaceROINodeSelection.h" #include "BrainModelSurfacePointLocator.h" #include "BrainModelSurfacePointProjector.h" #include "BrainModelSurfaceSmoothing.h" #include "BrainModelSurfaceToVolumeSegmentationConverter.h" #include "BrainSet.h" #include "DebugControl.h" #include "DeformationFieldFile.h" #include "FileUtilities.h" #include "LatLonFile.h" #include "MathUtilities.h" #include "MniObjSurfaceFile.h" #include "PaintFile.h" #include "RgbPaintFile.h" #include "StringUtilities.h" #include "SurfaceFile.h" #include "SurfaceShapeFile.h" #include "SystemUtilities.h" #include "TopologyFile.h" #include "TopologyHelper.h" #include "TransformationMatrixFile.h" #include "VectorFile.h" /** * The constructor. */ BrainModelSurface::BrainModelSurface(BrainSet* bs, const BrainModel::BRAIN_MODEL_TYPE bmt) : BrainModel(bs, bmt) { reset(); } /** * The copy constructor */ BrainModelSurface::BrainModelSurface(const BrainModelSurface& bms) : BrainModel(bms) { reset(); coordinates = bms.coordinates; coordinates.setFileName(""); coordinates.setModified(); topology = bms.topology; normals = bms.normals; surfaceType = bms.surfaceType; setStructure(bms.getStructure()); defaultScaling = bms.defaultScaling; defaultPerspectiveZooming = bms.defaultPerspectiveZooming; pushPopCoordinates = bms.pushPopCoordinates; displayHalfX = bms.displayHalfX; displayHalfY = bms.displayHalfY; } /** * The destructor. */ BrainModelSurface::~BrainModelSurface() { reset(); } /** * get information about the surface. */ void BrainModelSurface::getSurfaceInformation(std::vector& labels, std::vector& values) const { labels.clear(); values.clear(); labels.push_back("Coordinate File"); values.push_back(FileUtilities::basename(coordinates.getFileName())); labels.push_back("Topology File"); if (topology != NULL) { values.push_back(FileUtilities::basename(topology->getFileName())); } else { values.push_back(""); } labels.push_back("Topology Type"); if (topology != NULL) { values.push_back(topology->getTopologyTypeName()); } else { values.push_back(""); } labels.push_back("Surface Type"); values.push_back(getSurfaceTypeName()); labels.push_back("Structure"); values.push_back(getStructure().getTypeAsString()); labels.push_back("Number of Nodes"); values.push_back(QString::number(getNumberOfNodes())); labels.push_back("Number of Tiles"); if (topology != NULL) { values.push_back(QString::number(topology->getNumberOfTiles())); } else { values.push_back(""); } float bounds[6]; getBounds(bounds); labels.push_back("X Extent"); values.push_back(QString::number(bounds[0], 'f', 2) + " " + QString::number(bounds[1], 'f', 2)); labels.push_back("Y Extent"); values.push_back(QString::number(bounds[2], 'f', 2) + " " + QString::number(bounds[3], 'f', 2)); labels.push_back("Z Extent"); values.push_back(QString::number(bounds[4], 'f', 2) + " " + QString::number(bounds[5], 'f', 2)); labels.push_back("Surface Area"); values.push_back(QString::number(getSurfaceArea(), 'f', 2)); float meanDist, minDist, maxDist; getMeanDistanceBetweenNodes(NULL, meanDist, minDist, maxDist); labels.push_back("Mean/Min/Max Distance"); values.push_back(QString::number(meanDist, 'f', 6) + "/" + QString::number(minDist, 'f', 6) + "/" + QString::number(maxDist, 'f', 6)); labels.push_back("Spherical Radius"); if (getSurfaceType() == BrainModelSurface::SURFACE_TYPE_SPHERICAL) { values.push_back(QString::number(getSphericalSurfaceRadius(), 'f', 2)); } else { values.push_back("N/A"); } } /** * Get a descriptive name of the model. */ QString BrainModelSurface::getDescriptiveName() const { QString name(StringUtilities::makeUpperCase(getSurfaceTypeName())); name.append(" "); const CoordinateFile* cf = getCoordinateFile(); name.append(FileUtilities::basename(cf->getFileName())); return name; } /** * append a string to the coordinate file's comment. */ void BrainModelSurface::appendToCoordinateFileComment(const QString& s) { coordinates.appendToFileComment(s); } /** * append a string to the topology file's comment. */ void BrainModelSurface::appendToTopologyFileComment(const QString& s) { if (topology != NULL) { topology->appendToFileComment(s); } } /** * Add a node to this brain model surface. */ void BrainModelSurface::addNode(const float xyz[3]) { coordinates.addCoordinate(xyz); normals.push_back(0.0); normals.push_back(0.0); normals.push_back(1.0); if (topology != NULL) { topology->setNumberOfNodes(coordinates.getNumberOfCoordinates()); } } /** * surefit ellipsoid crossover check. */ int BrainModelSurface::crossoverCheckSureFitEllipsoid() { const int numNodes = getNumberOfNodes(); if (numNodes <= 0) { return 0; } float totalCrossovers = 0.0; // // Pointer to node attributes // BrainSetNodeAttribute* nodeAttributes = brainSet->getNodeAttributes(0); // // Default to no crssovers // for (int i = 0; i < numNodes; i++) { nodeAttributes[i].setCrossover(BrainSetNodeAttribute::CROSSOVER_NO); } // // Create a topology helper with node neighbors sorted // const TopologyHelper* th = topology->getTopologyHelper(false, true, true); // // Get this surface's coordinate file // CoordinateFile* cf = getCoordinateFile(); // // Get the center of mass for this surface // float centerOfMass[3]; getCenterOfMass(centerOfMass); // // Examine each node // for (int i = 0; i < numNodes; i++) { int numCrossoversThisNode = 0; // // Get the nodes coordinate // const float* nodeXYZ = cf->getCoordinate(i); // // Determine the ellipsoid normal for this node // float pos[3]; pos[0] = nodeXYZ[0] - centerOfMass[0]; pos[1] = nodeXYZ[1] - centerOfMass[1]; pos[2] = nodeXYZ[2] - centerOfMass[2]; // HAD 7.21.97 Want normals to point *out* on ellipsoid float ellipsoidNormal[3]; if (pos[0] < 0) { ellipsoidNormal[0] = -1.0; } else { ellipsoidNormal[0] = 1.0; } if (pos[1] < 0) { ellipsoidNormal[1] = -1.0; } else { ellipsoidNormal[1] = 1.0; } if (pos[2] < 0) { ellipsoidNormal[2] = -1.0; } else { ellipsoidNormal[2] = 1.0; } MathUtilities::normalize(ellipsoidNormal); // // Get this nodes neighbors // int numNeighbors = 0; const int* neighbors = th->getNodeNeighbors(i, numNeighbors); // // Check tiles formed by neighbors // if (numNeighbors >= 2) { for (int j = 0; j < numNeighbors; j++) { // // Get node numbers of two neighbors // const int n1 = neighbors[j]; int nextNeighIndex = j + 1; if (nextNeighIndex >= numNeighbors) { nextNeighIndex = 0; } const int n2 = neighbors[nextNeighIndex]; // // Calculate normal of tile formed by neighboring nodes // const float* n1XYZ = cf->getCoordinate(n1); const float* n2XYZ = cf->getCoordinate(n2); float tileNormal[3]; MathUtilities::computeNormal((float*)nodeXYZ, (float*)n1XYZ, (float*)n2XYZ, tileNormal); // // Determine angle between node normal and tile normal // const float dot = MathUtilities::dotProduct(ellipsoidNormal, tileNormal); // // Is this a crossover ? // if (dot < 0.0) { nodeAttributes[i].setCrossover(BrainSetNodeAttribute::CROSSOVER_YES); numCrossoversThisNode += 2; } } } totalCrossovers += (static_cast(numCrossoversThisNode) / static_cast(numNeighbors)); } // for return static_cast(totalCrossovers); } /** * Peform a crossover check. */ void BrainModelSurface::crossoverCheck(int& numberOfTileCrossovers, int& numberOfNodeCrossovers, const SURFACE_TYPES surfaceTypeHint) { numberOfTileCrossovers = 0; numberOfNodeCrossovers = 0; const int numNodes = getNumberOfNodes(); if (numNodes <= 0) { return; } // // Pointer to node attributes // BrainSetNodeAttribute* nodeAttributes = brainSet->getNodeAttributes(0); // // Default to no crssovers // for (int i = 0; i < numNodes; i++) { nodeAttributes[i].setCrossover(BrainSetNodeAttribute::CROSSOVER_NO); } enum METHOD_TYPE { METHOD_FLAT, METHOD_SPHERE, METHOD_OTHER }; METHOD_TYPE methodType = METHOD_OTHER; switch (surfaceTypeHint) { case SURFACE_TYPE_RAW: methodType = METHOD_OTHER; break; case SURFACE_TYPE_FIDUCIAL: methodType = METHOD_OTHER; break; case SURFACE_TYPE_INFLATED: methodType = METHOD_OTHER; break; case SURFACE_TYPE_VERY_INFLATED: methodType = METHOD_OTHER; break; case SURFACE_TYPE_SPHERICAL: methodType = METHOD_SPHERE; break; case SURFACE_TYPE_ELLIPSOIDAL: methodType = METHOD_OTHER; break; case SURFACE_TYPE_COMPRESSED_MEDIAL_WALL: methodType = METHOD_OTHER; break; case SURFACE_TYPE_FLAT: methodType = METHOD_FLAT; break; case SURFACE_TYPE_FLAT_LOBAR: methodType = METHOD_FLAT; break; case SURFACE_TYPE_HULL: methodType = METHOD_OTHER; break; case SURFACE_TYPE_UNKNOWN: methodType = METHOD_OTHER; break; case SURFACE_TYPE_UNSPECIFIED: methodType = METHOD_OTHER; break; } // // Pointer to coordinates // const float* coords = coordinates.getCoordinate(0); switch (methodType) { case METHOD_FLAT: { const float cosine30Degrees = 0.866; const int numTiles = topology->getNumberOfTiles(); for (int i = 0; i < numTiles; i++) { // // Get the nodes of the tile // int n1, n2, n3; topology->getTile(i, n1, n2, n3); // // Determine the tile's normal // float tileNormal[3]; MathUtilities::computeNormal((float*)&coords[n1*3], (float*)&coords[n2*3], (float*)&coords[n3*3], tileNormal); // // Normal should be pointing straight up // if (tileNormal[2] < cosine30Degrees) { nodeAttributes[n1].setCrossover(BrainSetNodeAttribute::CROSSOVER_YES); nodeAttributes[n2].setCrossover(BrainSetNodeAttribute::CROSSOVER_YES); nodeAttributes[n3].setCrossover(BrainSetNodeAttribute::CROSSOVER_YES); numberOfTileCrossovers++; } } } break; case METHOD_SPHERE: { const float cosine30Degrees = 0.866; const int numTiles = topology->getNumberOfTiles(); for (int i = 0; i < numTiles; i++) { // // Get the nodes of the tile // int n1, n2, n3; topology->getTile(i, n1, n2, n3); // // Determine the tile's normal // float tileNormal[3]; MathUtilities::computeNormal((float*)&coords[n1*3], (float*)&coords[n2*3], (float*)&coords[n3*3], tileNormal); // // Determine the sphere normal (ray from origin thru center of tile) // float sphereNormal[3] = { (coords[n1*3] + coords[n2*3] + coords[n3*3]) / 3.0, (coords[n1*3+1] + coords[n2*3+1] + coords[n3*3+1]) / 3.0, (coords[n1*3+2] + coords[n2*3+2] + coords[n3*3+2]) / 3.0 }; MathUtilities::normalize(sphereNormal); // // Angle between sphere normal and tile normal // const float dot = MathUtilities::dotProduct(sphereNormal, tileNormal); // // Normal should be pointing out of the sphere (within 15 degrees) // if (dot < cosine30Degrees) { nodeAttributes[n1].setCrossover(BrainSetNodeAttribute::CROSSOVER_YES); nodeAttributes[n2].setCrossover(BrainSetNodeAttribute::CROSSOVER_YES); nodeAttributes[n3].setCrossover(BrainSetNodeAttribute::CROSSOVER_YES); numberOfTileCrossovers++; } } } break; case METHOD_OTHER: { // // distance between two coincident vertices // const float tooSmall = 0.00001; // // Determine crossovers by examining angles between tiles // const TopologyHelper* th = topology->getTopologyHelper(true, false, false); const std::set& edges = th->getEdgeInfo(); for (std::set::const_iterator iter = edges.begin(); iter != edges.end(); iter++) { BrainSetNodeAttribute::CROSSOVER_STATUS crossoverStatus = BrainSetNodeAttribute::CROSSOVER_NO; // // Get nodes used by the edge // int node1, node2; iter->getNodes(node1, node2); // // if edge is very, very, very short then declare it a crossover // const float mag = MathUtilities::distance3D(&coords[node1*3], &coords[node2*3]); if (iter->getEdgeUsedByMoreThanTwoTriangles()) { if (DebugControl::getDebugOn()) { std::cout << "Crossover Edge: " << node1 << " " << node2 << " is used by more than two triangles" << std::endl; } crossoverStatus = BrainSetNodeAttribute::CROSSOVER_DEGENERATE_EDGE; } else if (mag < tooSmall) { if (DebugControl::getDebugOn()) { std::cout << "Crossover Edge: " << node1 << " " << node2 << "are essentially the same " << mag << " units apart" << std::endl; } crossoverStatus = BrainSetNodeAttribute::CROSSOVER_DEGENERATE_EDGE; } else { int tile1, tile2; iter->getTiles(tile1, tile2); if ((tile1 > 0) && (tile2 > 0)) { // // Get the nodes used by the two tiles // const int* t1n = topology->getTile(tile1); const int* t2n = topology->getTile(tile2); // // Calculate the normals of the two tiles // float tile1Normal[3]; float tile2Normal[3]; MathUtilities::computeNormal((float*)&coords[t1n[0]*3], (float*)&coords[t1n[1]*3], (float*)&coords[t1n[2]*3], tile1Normal); MathUtilities::computeNormal((float*)&coords[t2n[0]*3], (float*)&coords[t2n[1]*3], (float*)&coords[t2n[2]*3], tile2Normal); // // Dot product between tile normals gives arccos angle between tiles // const float invCosAngle = MathUtilities::dotProduct(tile1Normal, tile2Normal); if (iter->getEdgeOrientation(t1n) == iter->getEdgeOrientation(t2n)) { if (DebugControl::getDebugOn()) { std::cout << "Crossover Edge: " << node1 << " " << node2 << " is not oriented correctly for tiles " << tile1 << " " << tile2 << std::endl; } crossoverStatus = BrainSetNodeAttribute::CROSSOVER_DEGENERATE_EDGE; } // if angle between tiles is 179 to 181 degrees assume a crossover // std::cos(179) == std::cos(181) == -0.9998477 else if (invCosAngle < -0.9998477) { const double angle = std::acos(invCosAngle) * (180.0 / M_PI); if (DebugControl::getDebugOn()) { std::cout << "Crossover Edge: " << node1 << " " << node2 << " angle " << angle << " inverse " << invCosAngle << std::endl; } crossoverStatus = BrainSetNodeAttribute::CROSSOVER_YES; } } } if (crossoverStatus != BrainSetNodeAttribute::CROSSOVER_NO) { nodeAttributes[node1].setCrossover(crossoverStatus); nodeAttributes[node2].setCrossover(crossoverStatus); numberOfTileCrossovers++; } } } break; } // // Count node crossovers // numberOfNodeCrossovers = 0; for (int i = 0; i < numNodes; i++) { if (nodeAttributes[i].getCrossover() == BrainSetNodeAttribute::CROSSOVER_YES) { numberOfNodeCrossovers++; } } brainSet->clearAllDisplayLists(); } /** * read the specified surface file. */ void BrainModelSurface::readSurfaceFile(const QString& fileName) throw(FileException) { SurfaceFile sf; try { // // Read the surface file // sf.readFile(fileName); // // Name of file without an extension // const QString fileNameNoExt = FileUtilities::filenameWithoutExtension(fileName); // // copy coordinates to coordinate file and process normals // allocate normals once number of coordinates is set // const int numCoords = sf.getNumberOfCoordinates(); coordinates.setNumberOfCoordinates(numCoords); initializeNormals(numCoords); for (int i = 0; i < numCoords; i++) { coordinates.setCoordinate(i, sf.getCoordinate(i)); } // // Set name of coordinate file // if (fileNameNoExt.isEmpty() == false) { QString coordFileName(fileNameNoExt); coordFileName.append(SpecFile::getCoordinateFileExtension()); coordinates.setFileName(coordFileName); } // // Transfer coordinate metaData // const GiftiMetaData* coordMetaData = sf.getCoordinateMetaData(); if (coordMetaData != NULL) { coordMetaData->copyMetaDataToCaretFile(&coordinates); //const GiftiMetaData::MetaDataContainer* data = coordMetaData->getMetaData(); //for (GiftiMetaData::ConstMetaDataIterator iter = data->begin(); iter != data->end(); iter++) { // coordinates.setHeaderTag(iter->first, iter->second); //} } // // Get the type of coordinates // //coordinates.setHeaderTag(AbstractFile::headerTagConfigurationID, sf.getCoordinateType()); setSurfaceType(getSurfaceTypeFromConfigurationID(sf.getCoordinateType())); // // Declare coord file not modified // coordinates.clearModified(); // // Get triangles // const int numTriangles = sf.getNumberOfTriangles(); if (numTriangles > 0) { TopologyFile* topoFile = new TopologyFile; topoFile->setNumberOfTiles(numTriangles); for (int i = 0; i < numTriangles; i++) { topoFile->setTile(i, sf.getTriangle(i)); } // // Set name of topo file // if (fileNameNoExt.isEmpty() == false) { QString topoFileName(fileNameNoExt); topoFileName.append(SpecFile::getTopoFileExtension()); topoFile->setFileName(topoFileName); } // // Transfer topology metaData // const GiftiMetaData* topoMetaData = sf.getTopologyMetaData(); if (topoMetaData != NULL) { topoMetaData->copyMetaDataToCaretFile(topoFile); //const GiftiMetaData::MetaDataContainer* data = topoMetaData->getMetaData(); //for (GiftiMetaData::ConstMetaDataIterator iter = data->begin(); iter != data->end(); iter++) { // topoFile->setHeaderTag(iter->first, iter->second); //} } // // Set the type of topology // topoFile->setTopologyType(TopologyFile::getTopologyTypeFromPerimeterID(sf.getTopologyType())); // // Declare topo file not modified // topoFile->clearModified(); // // Add topology to brain set parent // if (brainSet != NULL) { // // Do not load topology if it duplicates already loaded topology // bool topologyIsDuplicate = false; for (int i = 0; i < brainSet->getNumberOfTopologyFiles(); i++) { TopologyFile* tf = brainSet->getTopologyFile(i); // // Are the topology files equivalent (exact same tiles) // if (tf->equivalent(*topoFile)) { // // Do not need newly loaded topology file // delete topoFile; // // Use the duplicate topology already loaded // topoFile = tf; topologyIsDuplicate = true; break; } } // // If the topology does not duplicate an already loaded topology, add to brain set // if (topologyIsDuplicate == false) { brainSet->addTopologyFile(topoFile); } } // // Use the topology file // topology = topoFile; } } catch (FileException& e) { reset(); throw e; } } /** * Write the file's memory in caret6 format to the specified name. */ QString BrainModelSurface::writeSurfaceInCaret6Format(const QString& filenameIn, const QString& prependToFileNameExtension, Structure structure, const bool useCaret6ExtensionFlag) throw (FileException) { this->setStructure(structure); // // Determine number of coordinates and triangles // coordinates.updateMetaDataForCaret6(); const int numCoords = coordinates.getNumberOfCoordinates(); int numTriangles = 0; if (topology != NULL) { topology->updateMetaDataForCaret6(); numTriangles = topology->getNumberOfTiles(); } // // Create the surface file // SurfaceFile sf(numCoords, numTriangles); // // Copy the coordinates and normals // for (int i = 0; i < numCoords; i++) { sf.setCoordinate(i, coordinates.getCoordinate(i)); } // // Copy the triangles // for (int i = 0; i < numTriangles; i++) { sf.setTriangle(i, topology->getTile(i)); } // // set the metadata // GiftiMetaData* coordMetaData = sf.getCoordinateMetaData(); if (coordMetaData != NULL) { coordMetaData->copyMetaDataFromCaretFile(&coordinates); } GiftiMetaData* topoMetaData = sf.getTopologyMetaData(); if (topoMetaData != NULL) { topoMetaData->copyMetaDataFromCaretFile(topology); } sf.removeHeaderTag("date"); sf.removeHeaderTag("encoding"); sf.setHeaderTag("Date", QDateTime::currentDateTime().toString(Qt::ISODate)); sf.setHeaderTag("UserName", SystemUtilities::getUserName()); // // Set the coordinate type and topology type // sf.setCoordinateType(getSurfaceTypeName()); if (topology != NULL) { sf.setTopologyType(topology->getTopologyTypeName()); } QString fileName = FileUtilities::basename(filenameIn); if (fileName.endsWith(".coord")) { fileName = FileUtilities::replaceExtension(fileName, ".coord", prependToFileNameExtension + SpecFile::getGiftiSurfaceFileExtension()); } else if (fileName.endsWith(".surf.gii")) { fileName = FileUtilities::replaceExtension(fileName, ".surf.gii", prependToFileNameExtension + SpecFile::getGiftiSurfaceFileExtension()); } else if (fileName.endsWith(".coord.gii")) { fileName = FileUtilities::replaceExtension(fileName, ".coord.gii", prependToFileNameExtension + SpecFile::getGiftiSurfaceFileExtension()); } else { fileName = fileName + prependToFileNameExtension + SpecFile::getGiftiSurfaceFileExtension(); } // // Write the file // try { sf.setFileWriteType(AbstractFile::FILE_FORMAT_XML_GZIP_BASE64); sf.writeFile(fileName); } catch (FileException& e) { throw e; } // // clear modified status for coordinates and topology // coordinates.clearModified(); return fileName; } /** * write the surface file. */ void BrainModelSurface::writeSurfaceFile(const QString& filename, const AbstractFile::FILE_FORMAT fileFormat) throw (FileException) { // // Determine number of coordinates and triangles // const int numCoords = coordinates.getNumberOfCoordinates(); int numTriangles = 0; if (topology != NULL) { numTriangles = topology->getNumberOfTiles(); } // // Create the surface file // SurfaceFile sf(numCoords, numTriangles); // // Copy the coordinates and normals // for (int i = 0; i < numCoords; i++) { sf.setCoordinate(i, coordinates.getCoordinate(i)); } // // Copy the triangles // for (int i = 0; i < numTriangles; i++) { sf.setTriangle(i, topology->getTile(i)); } // // set the metadata // GiftiMetaData* coordMetaData = sf.getCoordinateMetaData(); if (coordMetaData != NULL) { coordMetaData->copyMetaDataFromCaretFile(&coordinates); } GiftiMetaData* topoMetaData = sf.getTopologyMetaData(); if (topoMetaData != NULL) { topoMetaData->copyMetaDataFromCaretFile(topology); } // // Set the coordinate type and topology type // sf.setCoordinateType(getSurfaceTypeName()); if (topology != NULL) { sf.setTopologyType(topology->getTopologyTypeName()); } // // Write the file // try { sf.setFileWriteType(fileFormat); sf.writeFile(filename); } catch (FileException& e) { throw e; } // // clear modified status for coordinates and topology // coordinates.clearModified(); //if (topology != NULL) { // topology->clearModified(); //} } /** * Read the specified coordinate file. May throw FileException. */ void BrainModelSurface::readCoordinateFile(const QString& filename) throw(FileException) { try { coordinates.readFile(filename); initializeNormals(); const QString st = coordinates.getHeaderTag(AbstractFile::headerTagStructure); structure.setTypeFromString(st); //setStructure(hemisphereStringToType(hem)); coordinates.clearModified(); // setting hem caused modification } catch (FileException& e) { reset(); throw e; } } /** * set a normal. */ void BrainModelSurface::setNormal(const int coordinateNumber, const float normalVector[3]) { const int i3 = coordinateNumber * 3; normals[i3] = normalVector[0]; normals[i3+1] = normalVector[1]; normals[i3+2] = normalVector[2]; } /** * Create the normals */ void BrainModelSurface::initializeNormals(const int numCoordsIn) { int numCoords = numCoordsIn; if (numCoords <= 0) { numCoords = coordinates.getNumberOfCoordinates(); } normals.clear(); if (numCoords > 0) { for (int i = 0; i < numCoords; i++) { normals.push_back(0.0); normals.push_back(0.0); normals.push_back(1.0); } } } /** * get the display list for this brain model. */ unsigned int BrainModelSurface::getDisplayListNumber() { // // Check to see if topology modification has changed // if (topology != NULL) { const unsigned long topoModNumber = topology->getModified(); if (topoModNumber != lastTopologyModificationNumber) { coordinates.clearDisplayList(); } lastTopologyModificationNumber = topoModNumber; } return coordinates.getDisplayListNumber(); } /** * set the display list for this brain model. */ void BrainModelSurface::setDisplayListNumber(unsigned int num) { coordinates.setDisplayListNumber(num); } /** * Reset the surface - clear everything in it, usually called prior to * loading new files. */ void BrainModelSurface::reset() { surfaceType = SURFACE_TYPE_UNKNOWN; structure.setType(Structure::STRUCTURE_TYPE_INVALID); coordinates.clear(); normals.clear(); topology = NULL; defaultScaling = 1.0; defaultPerspectiveZooming = 200.0; displayHalfX = 0; displayHalfY = 0; resetViewingTransformations(); lastTopologyModificationNumber = 100002283; // big number } /** * Set the topology for this surface */ bool BrainModelSurface::setTopologyFile(TopologyFile* topologyIn) { bool tooManyNodesInTopology = false;; if (topologyIn != NULL) { if (getNumberOfNodes() < topologyIn->getNumberOfNodes()) { tooManyNodesInTopology = true; } } topology = topologyIn; if (topology != NULL) { topology->setNumberOfNodes(getNumberOfNodes()); } coordinates.clearDisplayList(); QString topoFileName; if (topology != NULL) { topoFileName = FileUtilities::basename(topology->getFileName()); } if (topoFileName.isEmpty() == false) { const unsigned long modifiedStatus = coordinates.getModified(); coordinates.setHeaderTag(SpecFile::getUnknownTopoFileMatchTag(), topoFileName); coordinates.setModifiedCounter(modifiedStatus); } return tooManyNodesInTopology; } /** * see if the surface is topologically correct (has no handles). */ bool BrainModelSurface::isTopologicallyCorrect() const { int faces, vertices, edges, eulerCount, holes, objects; const bool flatFlag = ((surfaceType == SURFACE_TYPE_FLAT) || (surfaceType == SURFACE_TYPE_FLAT_LOBAR)); if (topology != NULL) { topology->getEulerCount(flatFlag, faces, vertices, edges, eulerCount, holes, objects); if (flatFlag) { if (eulerCount == 1) { return true; } } else if (eulerCount == 2) { return true; } } return false; } /** * Convert this surface and its current topology to a VTK surface. */ vtkPolyData* BrainModelSurface::convertToVtkPolyData() const { if (topology != NULL) { const int numTiles = topology->getNumberOfTiles(); const int numCoords = coordinates.getNumberOfCoordinates(); if ((numCoords > 0) && (numTiles > 0)) { vtkPoints* pointData = vtkPoints::New(); for (int i = 0; i < numCoords; i++) { pointData->InsertPoint(i, coordinates.getCoordinate(i)); } vtkCellArray* cells = vtkCellArray::New(); int size = cells->EstimateSize(numTiles, 3); cells->Allocate(size, 25); for (int j = 0; j < numTiles; j++) { int v[3]; topology->getTile(j, v[0], v[1], v[2]); vtkIdType vt[3] = { v[0], v[1], v[2] }; cells->InsertNextCell(static_cast(3), vt); } vtkPolyData* polyData = vtkPolyData::New(); polyData->SetPoints(pointData); polyData->SetPolys(cells); vtkPolyDataNormals* normals = vtkPolyDataNormals::New(); normals->SetInput(polyData); normals->SplittingOff(); normals->ConsistencyOn(); normals->ComputePointNormalsOn(); normals->NonManifoldTraversalOn(); normals->SetAutoOrientNormals(1); normals->Update(); vtkPolyData* polyOut = vtkPolyData::New(); polyOut->DeepCopy(normals->GetOutput()); normals->Delete(); polyData->Delete(); cells->Delete(); pointData->Delete(); return polyOut; } } return NULL; } /** * import from a MNI OBJ Surface File. */ void BrainModelSurface::importFromMniObjSurfaceFile(const MniObjSurfaceFile& mni) throw (FileException) { try { coordinates.importFromMniObjSurfaceFile(mni); initializeNormals(); const int num = mni.getNumberOfPoints(); for (int i = 0; i < num; i++) { const float* nv = mni.getNormal(i); normals[i*3] = nv[0]; normals[i*3+1] = nv[1]; normals[i*3+2] = nv[2]; } appendToCoordinateFileComment("Imported from "); appendToCoordinateFileComment(mni.getFileName()); appendToCoordinateFileComment("\n"); } catch (FileException& e) { reset(); throw e; } } /** * import from a brain voyager file. */ void BrainModelSurface::importFromBrainVoyagerFile(const BrainVoyagerFile& bvf) throw (FileException) { try { coordinates.importFromBrainVoyagerFile(bvf); initializeNormals(); appendToCoordinateFileComment("Imported from "); appendToCoordinateFileComment(bvf.getFileName()); appendToCoordinateFileComment("\n"); } catch (FileException& e) { reset(); throw e; } } /** * import from a VTK surface file */ void BrainModelSurface::importFromVtkFile(vtkPolyData* polyData, const QString& fileName) throw (FileException) { try { coordinates.importFromVtkFile(polyData); initializeNormals(); if (fileName.isEmpty() == false) { appendToCoordinateFileComment("Imported from "); appendToCoordinateFileComment(fileName); appendToCoordinateFileComment("\n"); } } catch (FileException& e) { reset(); throw e; } } /** * Copy the Coordinates from the VTK PolyData. */ void BrainModelSurface::copyCoordinatesFromVTK(vtkPolyData* polyData) { const int numCoords = coordinates.getNumberOfCoordinates(); const int numPoints = polyData->GetNumberOfPoints(); if (numCoords == numPoints) { vtkPoints* points = polyData->GetPoints(); for (int i = 0; i < numPoints; i++) { #ifdef HAVE_VTK5 double xyz[3]; #else // HAVE_VTK5 float xyz[3]; #endif // HAVE_VTK5 points->GetPoint(i, xyz); coordinates.setCoordinate(i, xyz); } if ((normals.size() == 0) && (numPoints > 0)) { initializeNormals(); } } else { std::cerr << "VTK poly data has different number of points" << std::endl; } } /** * Copy the Topology from the VTK PolyData. */ void BrainModelSurface::copyTopologyFromVTK(vtkPolyData* polyData) { if (topology != NULL) { vtkTriangleFilter* triangleFilter = NULL; if (polyData->GetNumberOfStrips() > 0) { triangleFilter = vtkTriangleFilter::New(); triangleFilter->SetInput(polyData); triangleFilter->Update(); polyData->Delete(); polyData = triangleFilter->GetOutput(); } const int numTiles = topology->getNumberOfTiles(); vtkCellArray* cells = polyData->GetPolys(); if (cells->GetNumberOfCells() == numTiles) { int cellID = 0; vtkIdType npts; vtkIdType* pts; for (cells->InitTraversal(); cells->GetNextCell(npts, pts); cellID++) { if (npts == 3) { int verts[3]; topology->getTile(cellID, verts[0], verts[1], verts[2]); if ((pts[0] != verts[0]) || (pts[1] != verts[1]) || (pts[2] != verts[2])) { topology->setTile(cellID, pts[0], pts[1], pts[2]); } } } } else { std::cerr << "VTK poly data has different number of tiles" << std::endl; } } } /** * Orient the normals so that they point out of the surface. This is accomplished by * finding the coordinate with the largest Z. The normal's Z should be positive. If * not, all tiles in the surface need to have their orientation flipped and the normals * need to be flipped. NOTE: Normals must be computed prior to calling this method. * Returns true if the normals were flipped. */ bool BrainModelSurface::orientNormalsOut() { bool normalsWereFlipped = false; if (topology != NULL) { const int numTiles = topology->getNumberOfTiles(); const int numCoords = coordinates.getNumberOfCoordinates(); if ((numCoords > 0) && (numTiles > 0)) { // // Some coordinates may not be used by tiles so they need to be ignored. // bool* coordUsed = new bool[numCoords]; for (int k = 0; k < numCoords; k++) { coordUsed[k] = false; } for (int j = 0; j < numTiles; j++) { int v1, v2, v3; topology->getTile(j, v1, v2, v3); coordUsed[v1] = true; coordUsed[v2] = true; coordUsed[v3] = true; } // // Find coordinate with largest Z value; // float maxZ = 0.0; int maxIndex = -1; for (int i = 0; i < numCoords; i++) { if (coordUsed[i]) { const float* xyz = coordinates.getCoordinate(i); if ((maxIndex < 0) || (xyz[2] > maxZ)) { maxZ = xyz[2]; maxIndex = i; } } } // // If normal at coord with max Z is negative, then flip tiles and normals // if (maxIndex >= 0) { const float* normal = getNormal(maxIndex); if (normal[2] < 0.0) { flipNormals(); normalsWereFlipped = true; } } delete[] coordUsed; } } coordinates.clearDisplayList(); return normalsWereFlipped; } /** * Flip the normal's orientation */ void BrainModelSurface::flipNormals() { /* const int num = normals.size(); for (int i = 0; i < num; i++) { normals[i] = -normals[i]; } */ if (topology != NULL) { topology->flipTileOrientation(); for (int i = 0; i < brainSet->getNumberOfBrainModels(); i++) { BrainModelSurface* bms = brainSet->getBrainModelSurface(i); if (bms != NULL) { if (bms->getTopologyFile() == topology) { bms->computeNormals(); } } } } coordinates.clearDisplayList(); } /** * convert normals to rgb paint. */ void BrainModelSurface::convertNormalsToRgbPaint(RgbPaintFile* rpf) { const int numNodes = getNumberOfNodes(); if (numNodes <= 0) { return; } if (rpf->getNumberOfNodes() <= 0) { rpf->setNumberOfNodesAndColumns(numNodes, 1); } else { rpf->addColumns(1); } const int columnNumber = rpf->getNumberOfColumns() - 1; QString comment("Surface normals from "); comment.append(FileUtilities::basename(coordinates.getFileName())); rpf->setColumnComment(columnNumber, comment); rpf->setScaleRed(columnNumber, 0.0, 255.0); rpf->setScaleGreen(columnNumber, 0.0, 255.0); rpf->setScaleBlue(columnNumber, 0.0, 255.0); for (int i = 0; i < numNodes; i++) { const int i3 = i * 3; float r = fabs(normals[i3]) * 255.0; float g = fabs(normals[i3+1]) * 255.0; float b = fabs(normals[i3+2]) * 255.0; rpf->setRgb(i, columnNumber, r, g, b); /* float r = fabs(normals[i3] - 0.5); float g = fabs(normals[i3+1] - 0.5); float b = fabs(normals[i3+2] - 0.5); const float tot = std::sqrt(r*r + g*g + b*b); if (tot != 0.0) { r /= tot; g /= tot; b /= tot; r *= 255.0; g *= 255.0; b *= 255.0; rpf->setRgb(i, columnNumber, r, g, b); } */ } } /** * copy normals to surface vector file. */ void BrainModelSurface::copyNormalsToVectorFile(VectorFile* vf) const { const int numNodes = getNumberOfNodes(); // // Add column to surface vector file (if needed) // if (vf->getNumberOfVectors() != this->getNumberOfNodes()) { vf->setNumberOfVectors(numNodes); } for (int i = 0; i < numNodes; i++) { const float* xyz = this->coordinates.getCoordinate(i); vf->setVectorData(i, xyz, &normals[i*3], 1.0, i); } } /** * Compute the normals for this surface. * If "coordsIn" is not NULL, then "coordsIn" is used as the coordinates for * determining the normals. Otherwise, the surface's coordinates are used. * Passing the coordinates in may speed up some algorithms so that they * do not have to load the coordinates into the surface. */ void BrainModelSurface::computeNormals(const float* coordsIn) { if (topology != NULL) { const int numCoords = coordinates.getNumberOfCoordinates(); if (numCoords > 0) { float* numContribute = new float[numCoords]; for (int j = 0; j < numCoords; j++) { numContribute[j] = 0.0; } // // pointer to coordinates // const float* coords = (coordsIn != NULL) ? coordsIn : coordinates.getCoordinate(0); // // See if normals need to be created // if (static_cast(normals.size()) != (numCoords * 3)) { initializeNormals(); } std::fill(normals.begin(), normals.end(), 0.0); // // node normals are average of the node's tiles' normals // const int numTiles = topology->getNumberOfTiles(); for (int i = 0; i < numTiles; i++) { int va, vb, vc; topology->getTile(i, va, vb, vc); const int va3 = va * 3; const int vb3 = vb * 3; const int vc3 = vc * 3; float tileNormal[3]; MathUtilities::computeNormal((float*)&coords[va3], (float*)&coords[vb3], (float*)&coords[vc3], tileNormal); normals[va3] += tileNormal[0]; normals[va3+1] += tileNormal[1]; normals[va3+2] += tileNormal[2]; numContribute[va] += 1.0; normals[vb3] += tileNormal[0]; normals[vb3+1] += tileNormal[1]; normals[vb3+2] += tileNormal[2]; numContribute[vb] += 1.0; normals[vc3] += tileNormal[0]; normals[vc3+1] += tileNormal[1]; normals[vc3+2] += tileNormal[2]; numContribute[vc] += 1.0; } for (int k = 0; k < numCoords; k++) { const int k3 = k * 3; if (numContribute[k] > 0.0) { normals[k3] /= numContribute[k]; normals[k3+1] /= numContribute[k]; normals[k3+2] /= numContribute[k]; MathUtilities::normalize(&normals[k3]); } else { normals[k3] = 0.0; normals[k3+1] = 0.0; normals[k3+2] = 0.0; } } delete[] numContribute; } } coordinates.clearDisplayList(); } /* * Compute normals but use VTK's normals generation which tries to make * sure all tiles have their nodes ordered consistently. * void BrainModelSurface::computeNormalsWithTileOrientationConsistency() { const int numCoords = coordinates.getNumberOfCoordinates(); if (topology == NULL) { if ((numCoords * 3) != static_cast(normals.size())) { initializeNormals(); } return; } vtkPolyData* polyData = convertToVtkPolyData(); // // Use VTK to compute normals. // Do not split edges. // Make tiles consistent. // Compute Normals for the points. // vtkPolyDataNormals* polyNormals = vtkPolyDataNormals::New(); polyNormals->SetInput(polyData); polyNormals->SplittingOff(); polyNormals->ConsistencyOn(); polyNormals->ComputePointNormalsOn(); polyNormals->NonManifoldTraversalOn(); polyNormals->Update(); vtkPolyData* output = polyNormals->GetOutput(); vtkPointData* outputPoints = output->GetPointData(); vtkDataArray* normalsOut = outputPoints->GetNormals(); if ((numCoords * 3) != static_cast(normals.size())) { initializeNormals(); } if ((normalsOut->GetNumberOfTuples() == numCoords) && (normalsOut->GetNumberOfComponents() == 3)) { for (int i = 0; i < numCoords; i++) { const float* xyz = normalsOut->GetTuple3(i); normals[i * 3] = xyz[0]; normals[i * 3 + 1] = xyz[1]; normals[i * 3 + 2] = xyz[2]; } copyTopologyFromVTK(output); } else { for (int i = 0; i < numCoords; i++) { normals[i * 3] = 0.0; normals[i * 3 + 1] = 0.0; normals[i * 3 + 2] = 1.0; } std::cerr << "Normals calculation failed" << std::endl; } // normalsOut->Delete(); // outputPoints->Delete(); // output->Delete(); polyNormals->Delete(); polyData->Delete(); } */ /** * Orient the tiles consistently for this surface */ void BrainModelSurface::orientTilesConsistently() { // // Ensure topology // if (topology == NULL) { return; } if (topology->getNumberOfTiles() <= 0) { return; } vtkPolyData* polyData = convertToVtkPolyData(); // // Use VTK to compute normals. // Do not split edges. // Make tiles CONSISTENT. // Compute Normals for the points. // vtkPolyDataNormals* polyNormals = vtkPolyDataNormals::New(); polyNormals->SetInput(polyData); polyNormals->SplittingOff(); polyNormals->ConsistencyOn(); polyNormals->ComputePointNormalsOn(); polyNormals->NonManifoldTraversalOn(); polyNormals->Update(); vtkPolyData* output = polyNormals->GetOutput(); vtkPointData* outputPoints = output->GetPointData(); vtkDataArray* normalsOut = outputPoints->GetNormals(); const int numCoords = coordinates.getNumberOfCoordinates(); if ((normalsOut->GetNumberOfTuples() == numCoords) && (normalsOut->GetNumberOfComponents() == 3)) { copyTopologyFromVTK(output); } else { std::cerr << "Normals calculation failed for orienting tiles" << std::endl; } // normalsOut->Delete(); // outputPoints->Delete(); // output->Delete(); polyNormals->Delete(); polyData->Delete(); computeNormals(); orientNormalsOut(); coordinates.clearDisplayList(); } /** * Orient the tiles so that each tile's normal points outward. * This should only be used for flat and spherical surfaces. * This is probably a bad thing to do since it may screw up the topology. */ void BrainModelSurface::orientTilesOutward(const SURFACE_TYPES st) { // // Check for flat or spherical surface // bool sphereFlag = false; bool flatFlag = false; switch (st) { case SURFACE_TYPE_RAW: break; case SURFACE_TYPE_FIDUCIAL: break; case SURFACE_TYPE_INFLATED: break; case SURFACE_TYPE_VERY_INFLATED: break; case SURFACE_TYPE_SPHERICAL: sphereFlag = true; break; case SURFACE_TYPE_ELLIPSOIDAL: break; case SURFACE_TYPE_COMPRESSED_MEDIAL_WALL: break; case SURFACE_TYPE_FLAT: flatFlag = true; break; case SURFACE_TYPE_FLAT_LOBAR: flatFlag = true; break; case SURFACE_TYPE_HULL: break; case SURFACE_TYPE_UNKNOWN: break; case SURFACE_TYPE_UNSPECIFIED: break; } if ((sphereFlag == false) && (flatFlag == false)) { return; } TopologyFile* tf = getTopologyFile(); if (tf != NULL) { // // Check each tile // const int numTiles = tf->getNumberOfTiles(); for (int i = 0; i < numTiles; i++) { // // Get the nodes in the tile // int n1, n2, n3; tf->getTile(i, n1, n2, n3); // // Get the coordinates of the nodes // const float* c1 = coordinates.getCoordinate(n1); const float* c2 = coordinates.getCoordinate(n2); const float* c3 = coordinates.getCoordinate(n3); // // Compute the tiles normal // float normal[3]; MathUtilities::computeNormal((float*)c1, (float*)c2, (float*)c3, normal); bool flipOrientation = false; if (flatFlag) { // // Does normal point downward ? // if (normal[2] < 0.0) { flipOrientation = true; } } else if (sphereFlag) { // // Use average of the three nodes as normal // Assumes sphere is centered at origin // float avg[3] = { (c1[0] + c2[0] + c3[0]) / 3.0, (c1[1] + c2[1] + c3[1]) / 3.0, (c1[2] + c2[2] + c3[2]) / 3.0 }; MathUtilities::normalize(avg); // // Does normal point into the sphere // if (MathUtilities::dotProduct(normal, avg) < 0.0) { flipOrientation = true; } } if (flipOrientation) { tf->setTile(i, n3, n2, n1); } } } coordinates.clearDisplayList(); } /** * smooth the surface by moving nodes along their normals multiplied by curvature. */ void BrainModelSurface::smoothSurfaceUsingCurvature(const float strength, const int numSteps, const float curvatureMaximum) { QTime timer; timer.start(); const int numNodes = coordinates.getNumberOfCoordinates(); int curvatureCounter = 1; const int updateCurvatureEveryX = 1; SurfaceShapeFile ssf; ssf.setNumberOfNodesAndColumns(numNodes, 1); const int curvatureColumn = 0; float* coords = coordinates.getCoordinate(0); const TopologyHelper* th = topology->getTopologyHelper(false, true, false); for (int steps = 1; steps <= numSteps; steps++) { // // Determine if curvature should be generated // bool doCurvature = false; if (steps == 1) { doCurvature = true; } if (updateCurvatureEveryX > 0) { if (curvatureCounter == updateCurvatureEveryX) { doCurvature = true; curvatureCounter = 1; } else { curvatureCounter++; } } if (doCurvature) { // // Update the surface curvature (does normals too) // BrainModelSurfaceCurvature bmsc(brainSet, this, &ssf, curvatureColumn, BrainModelSurfaceCurvature::CURVATURE_COLUMN_DO_NOT_GENERATE, "meanCurv", ""); try { bmsc.execute(); } catch (BrainModelAlgorithmException&) { } } else { computeNormals(); } // // Adjust each nodes position // for (int i = 0; i < numNodes; i++) { if (th->getNodeHasNeighbors(i)) { float curv = ssf.getValue(i, curvatureColumn); curv = std::max(curv, -curvatureMaximum); curv = std::min(curv, curvatureMaximum); float* norm = &normals[i*3]; const float delta[3] = { norm[0] * curv * strength, norm[1] * curv * strength, norm[2] * curv * strength, }; coords[i*3] += delta[0]; coords[i*3+1] += delta[1]; coords[i*3+2] += delta[2]; } } coordinates.setModified(); // // Possibly redraw this brain model // brainSet->drawBrainModel(this, steps); std::cout << "Iter: " << steps << std::endl; } std::cout << "time: " << (static_cast(timer.elapsed()) / 1000.0) << std::endl; } /** * expand the surface by moving nodes along their normals by the specified amount. */ void BrainModelSurface::expandSurface(const float expandAmount) { const int numNodes = getNumberOfNodes(); for (int i = 0; i < numNodes; i++) { float xyz[3]; coordinates.getCoordinate(i, xyz); if ((xyz[0] != 0.0) || (xyz[1] != 0.0) || (xyz[2] != 0.0)) { const int i3 = i * 3; xyz[0] += (normals[i3] * expandAmount); xyz[1] += (normals[i3+1] * expandAmount); xyz[2] += (normals[i3+2] * expandAmount); coordinates.setCoordinate(i, xyz); } } computeNormals(); } /** * Set the surface to a standard view */ void BrainModelSurface::setToStandardView(const int viewNumber, const STANDARD_VIEWS view) { float m[16]; bool valid = true; switch(view) { case VIEW_LATERAL: if (structure.getType() != Structure::STRUCTURE_TYPE_CORTEX_RIGHT) { m[0] = 0.0; m[1] = 0.0; m[2] = -1.0; m[3] = 0.0; m[4] = -1.0; m[5] = 0.0; m[6] = 0.0; m[7] = 0.0; m[8] = 0.0; m[9] = 1.0; m[10] = 0.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; } else { m[0] = 0.0; m[1] = 0.0; m[2] = 1.0; m[3] = 0.0; m[4] = 1.0; m[5] = 0.0; m[6] = 0.0; m[7] = 0.0; m[8] = 0.0; m[9] = 1.0; m[10] = 0.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; } break; case VIEW_MEDIAL: if (structure.getType() != Structure::STRUCTURE_TYPE_CORTEX_RIGHT) { m[0] = 0.0; m[1] = 0.0; m[2] = 1.0; m[3] = 0.0; m[4] = 1.0; m[5] = 0.0; m[6] = 0.0; m[7] = 0.0; m[8] = 0.0; m[9] = 1.0; m[10] = 0.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; } else { m[0] = 0.0; m[1] = 0.0; m[2] = -1.0; m[3] = 0.0; m[4] = -1.0; m[5] = 0.0; m[6] = 0.0; m[7] = 0.0; m[8] = 0.0; m[9] = 1.0; m[10] = 0.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; } break; case VIEW_POSTERIOR: if (structure.getType() != Structure::STRUCTURE_TYPE_CORTEX_RIGHT) { m[0] = 1.0; m[1] = 0.0; m[2] = 0.0; m[3] = 0.0; m[4] = 0.0; m[5] = 0.0; m[6] = -1.0; m[7] = 0.0; m[8] = 0.0; m[9] = 1.0; m[10] = 0.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; } else { m[0] = 1.0; m[1] = 0.0; m[2] = 0.0; m[3] = 0.0; m[4] = 0.0; m[5] = 0.0; m[6] = -1.0; m[7] = 0.0; m[8] = 0.0; m[9] = 1.0; m[10] = 0.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; } break; case VIEW_ANTERIOR: if (structure.getType() != Structure::STRUCTURE_TYPE_CORTEX_RIGHT) { m[0] = -1.0; m[1] = 0.0; m[2] = 0.0; m[3] = 0.0; m[4] = 0.0; m[5] = 0.0; m[6] = 1.0; m[7] = 0.0; m[8] = 0.0; m[9] = 1.0; m[10] = 0.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; } else { m[0] = -1.0; m[1] = 0.0; m[2] = 0.0; m[3] = 0.0; m[4] = 0.0; m[5] = 0.0; m[6] = 1.0; m[7] = 0.0; m[8] = 0.0; m[9] = 1.0; m[10] = 0.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; } break; case VIEW_VENTRAL: if (structure.getType() != Structure::STRUCTURE_TYPE_CORTEX_RIGHT) { m[0] = -1.0; m[1] = 0.0; m[2] = 0.0; m[3] = 0.0; m[4] = 0.0; m[5] = 1.0; m[6] = 0.0; m[7] = 0.0; m[8] = 0.0; m[9] = 0.0; m[10] = -1.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; } else { m[0] = -1.0; m[1] = 0.0; m[2] = 0.0; m[3] = 0.0; m[4] = 0.0; m[5] = 1.0; m[6] = 0.0; m[7] = 0.0; m[8] = 0.0; m[9] = 0.0; m[10] = -1.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; } break; case VIEW_DORSAL: if (structure.getType() != Structure::STRUCTURE_TYPE_CORTEX_RIGHT) { m[0] = 1.0; m[1] = 0.0; m[2] = 0.0; m[3] = 0.0; m[4] = 0.0; m[5] = 1.0; m[6] = 0.0; m[7] = 0.0; m[8] = 0.0; m[9] = 0.0; m[10] = 1.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; } else { m[0] = 1.0; m[1] = 0.0; m[2] = 0.0; m[3] = 0.0; m[4] = 0.0; m[5] = 1.0; m[6] = 0.0; m[7] = 0.0; m[8] = 0.0; m[9] = 0.0; m[10] = 1.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; } break; case VIEW_RESET: m[0] = 1.0; m[1] = 0.0; m[2] = 0.0; m[3] = 0.0; m[4] = 0.0; m[5] = 1.0; m[6] = 0.0; m[7] = 0.0; m[8] = 0.0; m[9] = 0.0; m[10] = 1.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; perspectiveZooming[viewNumber] = defaultPerspectiveZooming; scaling[viewNumber][0] = defaultScaling; scaling[viewNumber][1] = defaultScaling; scaling[viewNumber][2] = defaultScaling; translation[viewNumber][0] = 0.0; translation[viewNumber][1] = 0.0; translation[viewNumber][2] = 0.0; break; case VIEW_ROTATE_X_90: rotationMatrix[viewNumber]->RotateX(90.0); valid = false; break; case VIEW_ROTATE_Y_90: rotationMatrix[viewNumber]->RotateY(90.0); valid = false; break; case VIEW_ROTATE_Z_90: rotationMatrix[viewNumber]->RotateZ(-90.0); valid = false; break; case VIEW_NONE: default: valid = false; break; } if (valid) { setRotationMatrix(viewNumber, m); } } /** * Get the text name of the surface type */ QString BrainModelSurface::getSurfaceTypeName() const { QString s("Other"); switch(surfaceType) { case SURFACE_TYPE_RAW: s = "Raw"; break; case SURFACE_TYPE_FIDUCIAL: s = "Fiducial"; break; case SURFACE_TYPE_INFLATED: s = "Inflated"; break; case SURFACE_TYPE_VERY_INFLATED: s = "VeryInflated"; break; case SURFACE_TYPE_SPHERICAL: s = "Spherical"; break; case SURFACE_TYPE_ELLIPSOIDAL: s = "Ellipsoidal"; break; case SURFACE_TYPE_COMPRESSED_MEDIAL_WALL: s = "CompMedWall"; break; case SURFACE_TYPE_FLAT: s = "Flat"; break; case SURFACE_TYPE_FLAT_LOBAR: s = "FlatLobar"; break; case SURFACE_TYPE_HULL: s = "Hull"; break; case SURFACE_TYPE_UNKNOWN: s = "Unknown"; break; case SURFACE_TYPE_UNSPECIFIED: default: s = "Unspecified"; break; } return s; } /** * Get all surface types and names. */ void BrainModelSurface::getSurfaceTypesAndNames(std::vector& typesOut, std::vector& typeNamesOut) { typesOut.clear(); typeNamesOut.clear(); typesOut.push_back(SURFACE_TYPE_RAW); typeNamesOut.push_back(getSurfaceConfigurationIDFromType(SURFACE_TYPE_RAW)); typesOut.push_back(SURFACE_TYPE_FIDUCIAL); typeNamesOut.push_back(getSurfaceConfigurationIDFromType(SURFACE_TYPE_FIDUCIAL)); typesOut.push_back(SURFACE_TYPE_INFLATED); typeNamesOut.push_back(getSurfaceConfigurationIDFromType(SURFACE_TYPE_INFLATED)); typesOut.push_back(SURFACE_TYPE_VERY_INFLATED); typeNamesOut.push_back(getSurfaceConfigurationIDFromType(SURFACE_TYPE_VERY_INFLATED)); typesOut.push_back(SURFACE_TYPE_SPHERICAL); typeNamesOut.push_back(getSurfaceConfigurationIDFromType(SURFACE_TYPE_SPHERICAL)); typesOut.push_back(SURFACE_TYPE_ELLIPSOIDAL); typeNamesOut.push_back(getSurfaceConfigurationIDFromType(SURFACE_TYPE_ELLIPSOIDAL)); typesOut.push_back(SURFACE_TYPE_COMPRESSED_MEDIAL_WALL); typeNamesOut.push_back(getSurfaceConfigurationIDFromType(SURFACE_TYPE_COMPRESSED_MEDIAL_WALL)); typesOut.push_back(SURFACE_TYPE_FLAT); typeNamesOut.push_back(getSurfaceConfigurationIDFromType(SURFACE_TYPE_FLAT)); typesOut.push_back(SURFACE_TYPE_FLAT_LOBAR); typeNamesOut.push_back(getSurfaceConfigurationIDFromType(SURFACE_TYPE_FLAT_LOBAR)); typesOut.push_back(SURFACE_TYPE_HULL); typeNamesOut.push_back(getSurfaceConfigurationIDFromType(SURFACE_TYPE_HULL)); typesOut.push_back(SURFACE_TYPE_UNKNOWN); typeNamesOut.push_back(getSurfaceConfigurationIDFromType(SURFACE_TYPE_UNKNOWN)); typesOut.push_back(SURFACE_TYPE_UNSPECIFIED); typeNamesOut.push_back(getSurfaceConfigurationIDFromType(SURFACE_TYPE_UNSPECIFIED)); } /** * Get the surface type for a surface type name */ BrainModelSurface::SURFACE_TYPES BrainModelSurface::getSurfaceTypeFromConfigurationID(const QString& name) { if (name == "RAW") return SURFACE_TYPE_RAW; else if (name == "FIDUCIAL") return SURFACE_TYPE_FIDUCIAL; else if (name == "INFLATED") return SURFACE_TYPE_INFLATED; else if (name == "VERY_INFLATED") return SURFACE_TYPE_VERY_INFLATED; else if (name == "SPHERICAL") return SURFACE_TYPE_SPHERICAL; else if (name == "ELLIPSOIDAL") return SURFACE_TYPE_ELLIPSOIDAL; else if (name == "CMW") return SURFACE_TYPE_COMPRESSED_MEDIAL_WALL; else if (name == "FLAT") return SURFACE_TYPE_FLAT; else if (name == "FLAT_LOBAR") return SURFACE_TYPE_FLAT_LOBAR; else if (name == "HULL") return SURFACE_TYPE_HULL; else return SURFACE_TYPE_UNKNOWN; } /** * Get the Configuration ID from the surface type. */ QString BrainModelSurface::getSurfaceConfigurationIDFromType(const SURFACE_TYPES st) { QString configID("UNKNOWN"); switch(st) { case SURFACE_TYPE_RAW: configID = "RAW"; break; case SURFACE_TYPE_FIDUCIAL: configID = "FIDUCIAL"; break; case SURFACE_TYPE_INFLATED: configID = "INFLATED"; break; case SURFACE_TYPE_VERY_INFLATED: configID = "VERY_INFLATED"; break; case SURFACE_TYPE_SPHERICAL: configID = "SPHERICAL"; break; case SURFACE_TYPE_ELLIPSOIDAL: configID = "ELLIPSOIDAL"; break; case SURFACE_TYPE_COMPRESSED_MEDIAL_WALL: configID = "CMW"; break; case SURFACE_TYPE_FLAT: configID = "FLAT"; break; case SURFACE_TYPE_FLAT_LOBAR: configID = "FLAT_LOBAR"; break; case SURFACE_TYPE_HULL: configID = "HULL"; break; case SURFACE_TYPE_UNKNOWN: case SURFACE_TYPE_UNSPECIFIED: configID = "UNKNOWN"; break; } return configID; } /** * Get the spec file tag from the coord type. */ QString BrainModelSurface::getCoordSpecFileTagFromSurfaceType(const SURFACE_TYPES st) { QString tag(SpecFile::getUnknownCoordFileMatchTag()); switch(st) { case BrainModelSurface::SURFACE_TYPE_RAW: tag = SpecFile::getRawCoordFileTag(); break; case BrainModelSurface::SURFACE_TYPE_FIDUCIAL: tag = SpecFile::getFiducialCoordFileTag(); break; case BrainModelSurface::SURFACE_TYPE_INFLATED: tag = SpecFile::getInflatedCoordFileTag(); break; case BrainModelSurface::SURFACE_TYPE_VERY_INFLATED: tag = SpecFile::getVeryInflatedCoordFileTag(); break; case BrainModelSurface::SURFACE_TYPE_SPHERICAL: tag = SpecFile::getSphericalCoordFileTag(); break; case BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL: tag = SpecFile::getEllipsoidCoordFileTag(); break; case BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL: tag = SpecFile::getCompressedCoordFileTag(); break; case BrainModelSurface::SURFACE_TYPE_FLAT: tag = SpecFile::getFlatCoordFileTag(); break; case BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR: tag = SpecFile::getLobarFlatCoordFileTag(); break; case BrainModelSurface::SURFACE_TYPE_HULL: tag = SpecFile::getHullCoordFileTag(); break; case BrainModelSurface::SURFACE_TYPE_UNKNOWN: case BrainModelSurface::SURFACE_TYPE_UNSPECIFIED: tag = SpecFile::getUnknownCoordFileMatchTag(); break; } return tag; } /** * Get the spec file tag from the surface type. */ QString BrainModelSurface::getSurfaceSpecFileTagFromSurfaceType(const SURFACE_TYPES st) { QString tag(SpecFile::getUnknownSurfaceFileMatchTag()); switch(st) { case BrainModelSurface::SURFACE_TYPE_RAW: tag = SpecFile::getRawSurfaceFileTag(); break; case BrainModelSurface::SURFACE_TYPE_FIDUCIAL: tag = SpecFile::getFiducialSurfaceFileTag(); break; case BrainModelSurface::SURFACE_TYPE_INFLATED: tag = SpecFile::getInflatedSurfaceFileTag(); break; case BrainModelSurface::SURFACE_TYPE_VERY_INFLATED: tag = SpecFile::getVeryInflatedSurfaceFileTag(); break; case BrainModelSurface::SURFACE_TYPE_SPHERICAL: tag = SpecFile::getSphericalSurfaceFileTag(); break; case BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL: tag = SpecFile::getEllipsoidSurfaceFileTag(); break; case BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL: tag = SpecFile::getCompressedSurfaceFileTag(); break; case BrainModelSurface::SURFACE_TYPE_FLAT: tag = SpecFile::getFlatSurfaceFileTag(); break; case BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR: tag = SpecFile::getLobarFlatSurfaceFileTag(); break; case BrainModelSurface::SURFACE_TYPE_HULL: tag = SpecFile::getHullSurfaceFileTag(); break; case BrainModelSurface::SURFACE_TYPE_UNKNOWN: case BrainModelSurface::SURFACE_TYPE_UNSPECIFIED: tag = SpecFile::getUnknownSurfaceFileMatchTag(); break; } return tag; } /** * see if surface is a fiducial surface. */ bool BrainModelSurface::getIsFiducialSurface() const { switch(surfaceType) { case BrainModelSurface::SURFACE_TYPE_RAW: break; case BrainModelSurface::SURFACE_TYPE_FIDUCIAL: return true; break; case BrainModelSurface::SURFACE_TYPE_INFLATED: break; case BrainModelSurface::SURFACE_TYPE_VERY_INFLATED: break; case BrainModelSurface::SURFACE_TYPE_SPHERICAL: break; case BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL: break; case BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL: break; case BrainModelSurface::SURFACE_TYPE_FLAT: break; case BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR: break; case BrainModelSurface::SURFACE_TYPE_HULL: break; case BrainModelSurface::SURFACE_TYPE_UNKNOWN: case BrainModelSurface::SURFACE_TYPE_UNSPECIFIED: break; } return false; } /** * see if surface is a flat surface. */ bool BrainModelSurface::getIsFlatSurface() const { switch(surfaceType) { case BrainModelSurface::SURFACE_TYPE_RAW: break; case BrainModelSurface::SURFACE_TYPE_FIDUCIAL: break; case BrainModelSurface::SURFACE_TYPE_INFLATED: break; case BrainModelSurface::SURFACE_TYPE_VERY_INFLATED: break; case BrainModelSurface::SURFACE_TYPE_SPHERICAL: break; case BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL: break; case BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL: break; case BrainModelSurface::SURFACE_TYPE_FLAT: return true; break; case BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR: return true; break; case BrainModelSurface::SURFACE_TYPE_HULL: break; case BrainModelSurface::SURFACE_TYPE_UNKNOWN: case BrainModelSurface::SURFACE_TYPE_UNSPECIFIED: break; } return false; } /** * set the surface type and update the configuration ID too. */ void BrainModelSurface::setSurfaceType(const SURFACE_TYPES st) { surfaceType = st; const QString configID = BrainModelSurface::getSurfaceConfigurationIDFromType(st); coordinates.setHeaderTag(AbstractFile::headerTagConfigurationID, configID); } /** * set the structure. */ void BrainModelSurface::setStructure(const Structure::STRUCTURE_TYPE st) { structure.setType(st); coordinates.setHeaderTag(AbstractFile::headerTagStructure, structure.getTypeAsString()); } /** * set the structure. */ void BrainModelSurface::setStructure(const Structure st) { structure = st; coordinates.setHeaderTag(AbstractFile::headerTagStructure, structure.getTypeAsString()); } /** * Set the default scaling for the surface so that the surface fills * most of the window. */ void BrainModelSurface::setDefaultScaling(const double orthoRight, const double orthoTop) { displayHalfX = orthoRight; displayHalfY = orthoTop; updateForDefaultScaling(); coordinates.clearDisplayList(); } /** * set the default scaling. */ void BrainModelSurface::setDefaultScaling(const float scale) { defaultScaling = scale; coordinates.clearDisplayList(); } /** * Update the default scaling so that the surface fits in the graphics window */ void BrainModelSurface::updateForDefaultScaling() { const CoordinateFile* cf = getCoordinateFile(); if (cf->getNumberOfCoordinates() <= 0) { defaultScaling = 1.0; defaultPerspectiveZooming = 200.0; return; } if ((displayHalfX <= 0) || (displayHalfY <= 0)) { return; } float bounds[6]; cf->getBounds(bounds); float bigX = bounds[1]; if (fabs(bounds[0]) > bigX) { bigX = fabs(bounds[0]); } float bigY = bounds[3]; if (fabs(bounds[2]) > bigY) { bigY = fabs(bounds[2]); } const float ratio = displayHalfX / displayHalfY; const float percentScreenToUse = 0.90; const float percentScreenX = displayHalfX * percentScreenToUse * ratio; const float percentScreenY = displayHalfY * percentScreenToUse; const float scaleX = percentScreenX / bigX; const float scaleY = percentScreenY / bigY; if (scaleX < scaleY) { defaultScaling = scaleX; } else { defaultScaling = scaleY; } defaultPerspectiveZooming = 200; if ((bigX > 0.0) && (bigY > 0.0)) { const float big = std::max(bigX, bigY) * 1.10; defaultPerspectiveZooming = big / tan(perspectiveFieldOfView * 0.5 * MathUtilities::degreesToRadians()); } for (int i = 0; i < NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS; i++) { setScaling(i, defaultScaling, defaultScaling, defaultScaling); setPerspectiveZooming(i, defaultPerspectiveZooming); } coordinates.clearDisplayList(); } /** * Create latitude longitude for this spherical surface */ void BrainModelSurface::createLatitudeLongitude(LatLonFile* llf, const int columnNumberIn, const QString& columnName, const bool setDeformedLatLonFlag, const bool sphereInDorsalViewFlag) { const int numNodes = getNumberOfNodes(); int columnNumber = columnNumberIn; if ((columnNumber < 0) || (columnNumber >= llf->getNumberOfColumns())) { if (llf->getNumberOfColumns() > 0) { llf->addColumns(1); } else { llf->setNumberOfNodesAndColumns(numNodes, 1); } columnNumber = llf->getNumberOfColumns() - 1; } llf->setColumnName(columnNumber, columnName); std::ostringstream str; str << "\nLatitude-Longitude calculated on surface " << FileUtilities::basename(coordinates.getFileName()).toAscii().constData(); if (topology != NULL) { str << " with topology " << FileUtilities::basename(topology->getFileName()).toAscii().constData(); } str << "\n"; llf->appendToFileComment(str.str().c_str()); std::vector savedNormals; if (sphereInDorsalViewFlag) { // // Put surface in lateral view for lat/lon computation // pushCoordinates(); savedNormals = normals; float m[16]; if (structure.getType() != Structure::STRUCTURE_TYPE_CORTEX_RIGHT) { m[0] = 0.0; m[1] = 0.0; m[2] = -1.0; m[3] = 0.0; m[4] = -1.0; m[5] = 0.0; m[6] = 0.0; m[7] = 0.0; m[8] = 0.0; m[9] = 1.0; m[10] = 0.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; } else { m[0] = 0.0; m[1] = 0.0; m[2] = 1.0; m[3] = 0.0; m[4] = 1.0; m[5] = 0.0; m[6] = 0.0; m[7] = 0.0; m[8] = 0.0; m[9] = 1.0; m[10] = 0.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; } vtkMatrix4x4* matrix =vtkMatrix4x4::New(); int cnt = 0; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { matrix->SetElement(i, j, m[cnt]); cnt++; } } vtkTransform* rotationMatrix = vtkTransform::New(); rotationMatrix->SetMatrix(matrix); TransformationMatrix rot; rot.setMatrix(rotationMatrix); rot.transpose(); // I'm not sure why this works JWH perhaps OpenGL backwards from VTK. applyTransformationMatrix(rot); matrix->Delete(); rotationMatrix->Delete(); } const bool leftHemisphereFlag = (structure.getType() == Structure::STRUCTURE_TYPE_CORTEX_LEFT); for (int i = 0; i < numNodes; i++) { float xyz[3]; coordinates.getCoordinate(i, xyz); if (leftHemisphereFlag) { xyz[0] = -xyz[0]; } const float xy = std::sqrt(xyz[0]*xyz[0] + xyz[1]*xyz[1]); float lat = 0.0, lon = 0.0; if (xy == 0.0) { if (xyz[0] >= 0.0) { lat = 90.0; } else { lat = -90.0; } } else { lat = std::atan2(xyz[2], xy) * MathUtilities::radiansToDegrees(); } //if (xyz[0] == 0.0) { // lon = 0.0; //} //else { lon = std::atan2(xyz[1], xyz[0]) * MathUtilities::radiansToDegrees(); //} if (setDeformedLatLonFlag) { llf->setDeformedLatLon(i, columnNumber, lat, lon); } else { llf->setLatLon(i, columnNumber, lat, lon); } } if (sphereInDorsalViewFlag) { popCoordinates(); normals = savedNormals; } } /** * Create Spherical Lat/Lon borders. */ void BrainModelSurface::createSphericalLatLonBorders(BorderFile& bf, const bool sphereInDorsalViewFlag) { // // Create a matrix that is applied to the borders // TransformationMatrix transMatrix; // // Is the sphere in a dorsal view ? // const bool leftHemFlag = (structure.getType() == Structure::STRUCTURE_TYPE_CORTEX_LEFT); if (sphereInDorsalViewFlag) { if (leftHemFlag) { transMatrix.rotate(TransformationMatrix::ROTATE_Y_AXIS, 90.0); transMatrix.rotate(TransformationMatrix::ROTATE_Z_AXIS, 90.0); transMatrix.inverse(); } else { transMatrix.rotate(TransformationMatrix::ROTATE_Y_AXIS, -90.0); transMatrix.rotate(TransformationMatrix::ROTATE_Z_AXIS, -90.0); transMatrix.inverse(); } } const float sphereRadius = getSphericalSurfaceRadius(); const int numLat = 6; const int latStep = 180 / numLat; const int latStart = -90 + latStep; for (int lat = latStart; lat < 90.0; lat += latStep) { QString ML; if (lat > 0.0) { if (leftHemFlag) { ML = "+"; } else { ML = "+"; } } else if (lat < 0.0) { if (leftHemFlag) { ML = "-"; } else { ML = "-"; } } std::ostringstream str; str << "LAT." << ML.toAscii().constData() << abs(lat); Border border(str.str().c_str()); // // angle from positive Z axis // const float z = sphereRadius * std::sin(lat * MathUtilities::degreesToRadians()); float radiusAtLat = std::sqrt(sphereRadius * sphereRadius - z * z); int imax = static_cast(360.0 * (radiusAtLat / sphereRadius)); for (int i = 0; i < imax; i++) { const float phi = (2.0 * i * M_PI) / imax; const float xyz[3] = { radiusAtLat * std::cos(phi), radiusAtLat * std::sin(phi), z }; border.addBorderLink(xyz); } border.applyTransformationMatrix(transMatrix); bf.addBorder(border); } // // For a right hemisphere in a lateral view, 0 longitude is on the screen // X-axis. Hence the zero longitude line starts at the lateral pole and // and wraps around the frontal pole, ending at the medial pole. // Longitude increases in a counter-clockwise direction. // const int longStep = latStep; for (int longitude = 0; longitude < 360; longitude += longStep) { std::ostringstream str; QString negLabel("");; int lonLabel = longitude; if (leftHemFlag) { lonLabel = 180 - lonLabel; } if (lonLabel > 180.0) { negLabel = "-"; lonLabel = 360 - lonLabel; } else if ((lonLabel > 0) && (lonLabel < 180.0)) { negLabel = "+"; } /* if (getStructure() == HEMISPHERE_RIGHT) { int lonLabel = 180 - longitude; if (lonLabel < 0) { lonLabel += 360; } } */ str << "LONG." << negLabel.toAscii().constData() << lonLabel; Border border(str.str().c_str()); const float clon = std::cos(longitude * MathUtilities::degreesToRadians()); const float slon = std::sin(longitude * MathUtilities::degreesToRadians()); for (int lat = -90; lat <= 90; lat++) { const float clat = std::cos(lat * MathUtilities::degreesToRadians()); const float slat = std::sin(lat * MathUtilities::degreesToRadians()); const float xyz[3] = { sphereRadius * clat * clon, sphereRadius * clat * slon, sphereRadius * slat }; border.addBorderLink(xyz); } border.applyTransformationMatrix(transMatrix); bf.addBorder(border); } } /* void BrainModelSurface::createSphericalLatLonBorders(BorderFile& bf) { TransformationMatrix matrix; if (getStructure() == HEMISPHERE_LEFT) { matrix.rotate(TransformationMatrix::ROTATE_Y_AXIS, 90.0); matrix.rotate(TransformationMatrix::ROTATE_X_AXIS, 90.0); } else { matrix.rotate(TransformationMatrix::ROTATE_Y_AXIS, -90.0); matrix.rotate(TransformationMatrix::ROTATE_X_AXIS, 90.0); } const float sphereRadius = getSphericalSurfaceRadius(); const int sectorAngle = 30; const int sectorsPerQuadrant = static_cast(((90.0 / sectorAngle) - 1.0)); const int longTotal = 4 * (sectorsPerQuadrant + 1); int latitude = 90 - sectorAngle; for (int n = -sectorsPerQuadrant; n <= sectorsPerQuadrant; n++) { QString ML; if (latitude > 0.0) { ML = "L"); } else if (latitude < 0.0) { ML = "M"); } std::ostringstream str; str << "LAT." << ML << latitude; Border border(str.str().c_str()); float t1 = (n * M_PI) / (2.0 * (sectorsPerQuadrant + 1.0)); float z = 0.0; if (n != 0) { z = (n / fabs(n)) * sphereRadius * std::cos(t1); } float radiusAtLat = std::sqrt(sphereRadius * sphereRadius - z * z); int imax = static_cast(360.0 * (radiusAtLat / sphereRadius)); for (int i = 0; i < imax; i++) { const float phi = (2.0 * i * M_PI) / imax; const float xyz[3] = { radiusAtLat * std::cos(phi), radiusAtLat * std::sin(phi), z }; border.addBorderLink(xyz); } border.applyTransformationMatrix(matrix); bf.addBorder(border); latitude -= sectorAngle; } int longitude = 0; for (int n = 0; n < longTotal; n++) { std::ostringstream str; str << "LON." << longitude; Border border(str.str().c_str()); const float phi = (2.0 * M_PI * n) / static_cast(longTotal); for (int i = 0; i < 180; i++) { const float theta = (static_cast(i) * M_PI) / 180.0; const float z = sphereRadius * std::cos(theta); const float t1 = std::sqrt(sphereRadius * sphereRadius - z * z); const float xyz[3] = { t1 * std::cos(phi), t1 * std::sin(phi), z }; border.addBorderLink(xyz); } border.applyTransformationMatrix(matrix); bf.addBorder(border); longitude += sectorAngle; } } */ /** * create flat grid borders for analysis. * Each border consists of one point and each border has a unique name. */ void BrainModelSurface::createFlatGridBordersForAnalysis(BorderFile& bf, const float bounds[4], const float resolution) { const float minX = bounds[0]; const float maxX = bounds[1]; const float minY = bounds[2]; const float maxY = bounds[3]; int j = 0; for (float y = minY; y <= maxY; y += resolution) { int i = 0; for (float x = minX; x <= maxX; x += resolution) { const QString name("Grid_" + QString::number(i) + "_" + QString::number(j)); float xyz[3] = { x, y, 0.0 }; Border b(name); b.addBorderLink(xyz); bf.addBorder(b); i++; } j++; } } /** * Create Flat Grid Borders. */ void BrainModelSurface::createFlatGridBorders(BorderFile& bf, const float gridSpacing, const int pointSpacing) { float bounds[6]; coordinates.getBounds(bounds); const int gridSpacingInt = static_cast(gridSpacing); int xGridLeft = (static_cast(bounds[0]) / gridSpacingInt) * gridSpacingInt; if (xGridLeft > 0) { xGridLeft -= gridSpacingInt; } else { xGridLeft -= (2 * gridSpacingInt); } int xGridRight = (static_cast(bounds[1]) / gridSpacingInt) * gridSpacingInt; if (xGridRight >= 0) { xGridRight += (2 * gridSpacingInt); } else { xGridRight += gridSpacingInt; } const int xGridLines = ((xGridRight - xGridLeft) / gridSpacingInt) + 1; int yGridBottom = (static_cast(bounds[2]) / gridSpacingInt) * gridSpacingInt; if (yGridBottom > 0) { yGridBottom -= gridSpacingInt; } else { yGridBottom -= (2 * gridSpacingInt); } int yGridTop = (static_cast(bounds[3]) / gridSpacingInt) * gridSpacingInt; if (yGridTop >= 0) { yGridTop += (2 * gridSpacingInt); } else { yGridTop += gridSpacingInt; } const int yGridLines = ((yGridTop - yGridBottom) / gridSpacingInt) + 1; float x = static_cast(xGridLeft); for (int i = 0; i < xGridLines; i++) { Border border("GridX"); float y = static_cast(yGridBottom); for (int j = 0; j < yGridLines; j++) { float xyz[3] = { x, y, 0.0 }; border.addBorderLink(xyz); float nextY = y + gridSpacing; if ((pointSpacing > 0) && (j < (yGridLines - 1))) { float increment = gridSpacing / static_cast(pointSpacing); y += increment; for (int k = 0; k < pointSpacing - 1; k++) { float xyz[3] = { x, y, 0.0 }; border.addBorderLink(xyz); y += increment; } } y = nextY; } bf.addBorder(border); x += gridSpacing; } float y = static_cast(yGridBottom); for (int i = 0; i < yGridLines; i++) { Border border("GridY"); float x = static_cast(xGridLeft); for (int j = 0; j < xGridLines; j++) { float xyz[3] = { x, y, 0.0 }; border.addBorderLink(xyz); float nextX = x + gridSpacing; if ((pointSpacing > 0) && (j < (xGridLines - 1))) { float increment = gridSpacing / static_cast(pointSpacing); x += increment; for (int k = 0; k < pointSpacing - 1; k++) { float xyz[3] = { x, y, 0.0 }; border.addBorderLink(xyz); x += increment; } } x = nextX; } bf.addBorder(border); y += gridSpacing; } } /** * get the volume displacment of the surface. Returns negative if it fails. */ float BrainModelSurface::getSurfaceVolumeDisplacement() const { // // Get the bounds of the surface // float bounds[6]; getBounds(bounds); const float dx = bounds[1] - bounds[0]; const float dy = bounds[3] - bounds[2]; const float dz = bounds[5] - bounds[4]; // // Create the empty volume // const float pad = 10.0; const int dim[3] = { static_cast(dx + pad), static_cast(dy + pad), static_cast(dz + pad) }; const float origin[3] = { bounds[0] - (pad / 2.0), bounds[2] - (pad / 2.0), bounds[4] - (pad / 2.0), }; const float spacing[3] = { 1.0, 1.0, 1.0 }; const VolumeFile::ORIENTATION orient[3] = { VolumeFile::ORIENTATION_LEFT_TO_RIGHT, VolumeFile::ORIENTATION_POSTERIOR_TO_ANTERIOR, VolumeFile::ORIENTATION_INFERIOR_TO_SUPERIOR }; VolumeFile vf; vf.initialize(VolumeFile::VOXEL_DATA_TYPE_FLOAT, dim, orient, origin, spacing, true, true); // // Convert the surface to a volume // try { BrainModelSurfaceToVolumeSegmentationConverter s2v((BrainSet*)getBrainSet(), (BrainModelSurface*)this, &vf, true, false); s2v.execute(); } catch (BrainModelAlgorithmException&) { return 0; } if (DebugControl::getDebugOn()) { try { vf.writeFile("DebugSurfaceVolumeDisplacement.nii.gz"); } catch (FileException&) { } } float displacement = vf.getNumberOfNonZeroVoxels(); // // If all voxels set, probably open topology file // if (displacement == vf.getTotalNumberOfVoxelElements()) { displacement = -1; } return displacement; } /** * Get the surface's area */ float BrainModelSurface::getSurfaceArea(const TopologyFile* tfin) const { float area = 0.0; const TopologyFile* tf = ((tfin != NULL) ? tfin : topology); const int numTiles = tf->getNumberOfTiles(); for (int i = 0; i < numTiles; i++) { const int* nodes = tf->getTile(i); const float* p1 = coordinates.getCoordinate(nodes[0]); const float* p2 = coordinates.getCoordinate(nodes[1]); const float* p3 = coordinates.getCoordinate(nodes[2]); area += MathUtilities::triangleArea((float*)p1, (float*)p2, (float*)p3); } return area; } /** * Get the area of a tile in the surface */ float BrainModelSurface::getTileArea(const int tileNum) const { const int* nodes = topology->getTile(tileNum); const float* p1 = coordinates.getCoordinate(nodes[0]); const float* p2 = coordinates.getCoordinate(nodes[1]); const float* p3 = coordinates.getCoordinate(nodes[2]); const float area = MathUtilities::triangleArea((float*)p1, (float*)p2, (float*)p3); return area; } /** * Get the area of a tile in the surface using three nodes */ float BrainModelSurface::getTileArea(const int n1, const int n2, const int n3) const { const float* p1 = coordinates.getCoordinate(n1); const float* p2 = coordinates.getCoordinate(n2); const float* p3 = coordinates.getCoordinate(n3); const float area = MathUtilities::triangleArea((float*)p1, (float*)p2, (float*)p3); return area; } /** * get the area of all tiles. */ void BrainModelSurface::getAreaOfAllTiles(std::vector& tileAreas) const { tileAreas.clear(); if (topology != NULL) { const int numTiles = topology->getNumberOfTiles(); tileAreas.resize(numTiles); for (int i = 0; i < numTiles; i++) { tileAreas[i] = getTileArea(i); } } } /** * get the area of all nodes. */ void BrainModelSurface::getAreaOfAllNodes(std::vector& nodeAreas) const { // // Since each tile consists of three nodes, apply one third of the tile area // to the node and sum these values // nodeAreas.clear(); const int numNodes = getNumberOfNodes(); if (numNodes >= 0) { nodeAreas.resize(numNodes, 0.0); std::vector tileAreas; getAreaOfAllTiles(tileAreas); const int numTiles = static_cast(tileAreas.size()); if (numTiles > 0) { for (int i = 0; i < numTiles; i++) { const int* nodes = topology->getTile(i); const float oneThirdTileArea = tileAreas[i] * 0.33333; nodeAreas[nodes[0]] += oneThirdTileArea; nodeAreas[nodes[1]] += oneThirdTileArea; nodeAreas[nodes[2]] += oneThirdTileArea; } } } } /** * Apply a transformation matrix to the surface. */ void BrainModelSurface::applyTransformationMatrix(TransformationMatrix& tm) { const TopologyHelper* th = topology->getTopologyHelper(false, true, false); const int numNodes = getNumberOfNodes(); for (int i = 0; i < numNodes; i++) { float xyz[3] = { 0.0, 0.0, 0.0 }; if (th->getNodeHasNeighbors(i)) { coordinates.getCoordinate(i, xyz); double p[4] = { xyz[0], xyz[1], xyz[2], 1.0 }; tm.multiplyPoint(p); xyz[0] = p[0]; xyz[1] = p[1]; xyz[2] = p[2]; } coordinates.setCoordinate(i, xyz); } // resetViewingTransformations(); computeNormals(); /* appendToCoordinateFileComment("Applied transformation matrix:\n"); double m[4][4]; tm.getMatrix(m); for (int i = 0; i < 4; i++) { appendToCoordinateFileComment(" "); for (int j = 0; j < 4; j++) { appendToCoordinateFileComment(" "); appendToCoordinateFileComment(StringUtilities::fromNumber(static_cast(m[i][j]))); } appendToCoordinateFileComment("\n"); } */ } /** * apply a view (transformation) to the coordinates of the surface. */ void BrainModelSurface::applyViewToCoordinates(const BrainModel::STANDARD_VIEWS surfaceView) { if (structure.getType() == Structure::STRUCTURE_TYPE_CORTEX_RIGHT) { switch (surfaceView) { case BrainModel::VIEW_NONE: break; case BrainModel::VIEW_RESET: break; case BrainModel::VIEW_ANTERIOR: { TransformationMatrix tm; tm.rotateX(-90.0); applyTransformationMatrix(tm); tm.identity(); tm.rotateY(180.0); applyTransformationMatrix(tm); } break; case BrainModel::VIEW_DORSAL: // // Do nothing, dorsal is default view // break; case BrainModel::VIEW_LATERAL: { TransformationMatrix tm; tm.rotateX(-90.0); applyTransformationMatrix(tm); tm.identity(); tm.rotateY(-90.0); applyTransformationMatrix(tm); } break; case BrainModel::VIEW_MEDIAL: { TransformationMatrix tm; tm.rotateX(-90.0); applyTransformationMatrix(tm); tm.identity(); tm.rotateY(90.0); applyTransformationMatrix(tm); } break; case BrainModel::VIEW_POSTERIOR: { TransformationMatrix tm; tm.rotateX(-90.0); applyTransformationMatrix(tm); } break; case BrainModel::VIEW_VENTRAL: { TransformationMatrix tm; tm.rotateY(180.0); applyTransformationMatrix(tm); } break; case BrainModel::VIEW_ROTATE_X_90: break; case BrainModel::VIEW_ROTATE_Y_90: break; case BrainModel::VIEW_ROTATE_Z_90: break; } } else if (structure.getType() == Structure::STRUCTURE_TYPE_CORTEX_LEFT) { switch (surfaceView) { case BrainModel::VIEW_NONE: break; case BrainModel::VIEW_RESET: break; case BrainModel::VIEW_ANTERIOR: { TransformationMatrix tm; tm.rotateX(-90.0); applyTransformationMatrix(tm); tm.identity(); tm.rotateY(180.0); applyTransformationMatrix(tm); } break; case BrainModel::VIEW_DORSAL: // // Do nothing, dorsal is default view // break; case BrainModel::VIEW_LATERAL: { TransformationMatrix tm; tm.rotateX(-90.0); applyTransformationMatrix(tm); tm.identity(); tm.rotateY(90.0); applyTransformationMatrix(tm); } break; case BrainModel::VIEW_MEDIAL: { TransformationMatrix tm; tm.rotateX(-90.0); applyTransformationMatrix(tm); tm.identity(); tm.rotateY(-90.0); applyTransformationMatrix(tm); } break; case BrainModel::VIEW_POSTERIOR: { TransformationMatrix tm; tm.rotateX(-90.0); applyTransformationMatrix(tm); } break; case BrainModel::VIEW_VENTRAL: { TransformationMatrix tm; tm.rotateY(180.0); applyTransformationMatrix(tm); } break; case BrainModel::VIEW_ROTATE_X_90: break; case BrainModel::VIEW_ROTATE_Y_90: break; case BrainModel::VIEW_ROTATE_Z_90: break; } } } /** * Apply current view to surface */ void BrainModelSurface::OLDapplyCurrentView(const int surfaceViewNumber, const bool applyTranslation, const bool applyRotation, const bool applyScaling) { /* TransformationMatrix tm; if (applyTranslation) { tm.translate(translation[surfaceViewNumber][0], translation[surfaceViewNumber][1], translation[surfaceViewNumber][2]); translation[surfaceViewNumber][0] = 0.0; translation[surfaceViewNumber][1] = 0.0; translation[surfaceViewNumber][2] = 0.0; } if (applyRotation) { TransformationMatrix rot; rot.setMatrix(rotationMatrix[surfaceViewNumber]); rot.transpose(); // I'm not sure why this works JWH perhaps OpenGL backwards from VTK. tm.multiply(rot); setToStandardView(surfaceViewNumber, VIEW_DORSAL); } if (applyScaling) { tm.scale(scaling[surfaceViewNumber]); setDefaultScaling(1.0); setScaling(surfaceViewNumber, 1.0, 1.0, 1.0); } applyTransformationMatrix(tm); coordinates.clearDisplayList(); */ /* if (applyRotation) { TransformationMatrix rot; rot.setMatrix(rotationMatrix[surfaceViewNumber]); rot.transpose(); // I'm not sure why this works JWH perhaps OpenGL backwards from VTK. TransformationMatrix tm; tm.multiply(rot); setToStandardView(surfaceViewNumber, VIEW_DORSAL); applyTransformationMatrix(tm); } if (applyTranslation) { TransformationMatrix tm; tm.translate(translation[surfaceViewNumber][0], translation[surfaceViewNumber][1], translation[surfaceViewNumber][2]); applyTransformationMatrix(tm); translation[surfaceViewNumber][0] = 0.0; translation[surfaceViewNumber][1] = 0.0; translation[surfaceViewNumber][2] = 0.0; } if (applyScaling) { TransformationMatrix tm; tm.scale(scaling[surfaceViewNumber]); setDefaultScaling(1.0); setScaling(surfaceViewNumber, 1.0, 1.0, 1.0); applyTransformationMatrix(tm); } */ glPushMatrix(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); if (applyTranslation) { float t[3]; getTranslation(surfaceViewNumber, t); glTranslatef(t[0], t[1], t[2]); t[0] = 0.0; t[1] = 0.0; t[2] = 0.0; setTranslation(surfaceViewNumber, t); } if (applyRotation) { float m[16]; getRotationMatrix(surfaceViewNumber, m); glMultMatrixf(m); } if (applyScaling) { float s[3]; getScaling(surfaceViewNumber, s); glScalef(s[0], s[1], s[2]); s[0] = 1.0; s[1] = 1.0; s[2] = 1.0; setScaling(surfaceViewNumber, s); setDefaultScaling(1.0); } float matrix[16]; glGetFloatv(GL_MODELVIEW_MATRIX, matrix); TransformationMatrix tm; tm.setMatrix(matrix); applyTransformationMatrix(tm); if (applyRotation) { setToStandardView(surfaceViewNumber, VIEW_DORSAL); } glPopMatrix(); coordinates.clearDisplayList(); } /** * Apply current view to surface */ void BrainModelSurface::applyCurrentView(const int surfaceViewNumber, const bool applyTranslation, const bool applyRotation, const bool applyScaling) { TransformationMatrix tm; if (applyRotation) { float m[16]; getRotationMatrix(surfaceViewNumber, m); TransformationMatrix rotMatrix; rotMatrix.setMatrix(m); tm.preMultiply(rotMatrix); } if (applyScaling) { float s[3]; getScaling(surfaceViewNumber, s); tm.scale(s); } if (applyTranslation) { float t[3]; getTranslation(surfaceViewNumber, t); tm.translate(t); } applyTransformationMatrix(tm); if (applyRotation) { setToStandardView(surfaceViewNumber, VIEW_DORSAL); } if (applyTranslation) { float t[3]; t[0] = 0.0; t[1] = 0.0; t[2] = 0.0; setTranslation(surfaceViewNumber, t); } if (applyScaling) { float s[3]; s[0] = 1.0; s[1] = 1.0; s[2] = 1.0; setScaling(surfaceViewNumber, s); setDefaultScaling(1.0); } } /** * Get the bounds of the connected surface. */ void BrainModelSurface::getBounds(float bounds[6]) const { const TopologyFile* tf = getTopologyFile(); if (tf != NULL) { const TopologyHelper* th = tf->getTopologyHelper(false, true, false); const int numNodes = getNumberOfNodes(); bounds[0] = std::numeric_limits::max(); bounds[1] = -std::numeric_limits::max(); bounds[2] = std::numeric_limits::max(); bounds[3] = -std::numeric_limits::max(); bounds[4] = std::numeric_limits::max(); bounds[5] = -std::numeric_limits::max(); for (int i = 0; i < numNodes; i++) { if (th->getNodeHasNeighbors(i)) { const float* xyz = coordinates.getCoordinate(i); bounds[0] = std::min(bounds[0], xyz[0]); bounds[1] = std::max(bounds[1], xyz[0]); bounds[2] = std::min(bounds[2], xyz[1]); bounds[3] = std::max(bounds[3], xyz[1]); bounds[4] = std::min(bounds[4], xyz[2]); bounds[5] = std::max(bounds[5], xyz[2]); } } } else { bounds[0] = 0.0; bounds[1] = 0.0; bounds[2] = 0.0; bounds[3] = 0.0; bounds[4] = 0.0; bounds[5] = 0.0; } } /** * move disconnected nodes to origin */ void BrainModelSurface::moveDisconnectedNodesToOrigin() { const TopologyHelper* th = topology->getTopologyHelper(false, true, false); const int numNodes = getNumberOfNodes(); const float xyz[3] = { 0.0, 0.0, 0.0 }; for (int i = 0; i < numNodes; i++) { if (th->getNodeHasNeighbors(i) == false) { coordinates.setCoordinate(i, xyz); } } } /** * Scale a flat surface to the specified area. * The "flatRatioFlag" should be set if the surface being scaled is flat * and the desired area is from a non-flat surface. */ void BrainModelSurface::scaleSurfaceToArea(const float desiredArea, const bool flatRatioFlag) { float currentSurfaceArea = getSurfaceArea(); float ratio = desiredArea / currentSurfaceArea; if (flatRatioFlag) { ratio = std::sqrt(ratio); if (ratio > 0.0) { TransformationMatrix tm; tm.scale(ratio, ratio, ratio); applyTransformationMatrix(tm); } } else { const int maxIter = 5; std::vector coords(maxIter + 1); std::vector coordAreas(maxIter + 1, -1.0); coords[0] = coordinates; coordAreas[0] = currentSurfaceArea; // // Save unscaled coordinates // pushCoordinates(); for (int i = 1; i <= maxIter; i++) { if (ratio != 0.0) { TransformationMatrix tm; tm.scale(ratio, ratio, ratio); applyTransformationMatrix(tm); } // // Save coordinates and surface area // coords[i] = coordinates; coordAreas[i] = getSurfaceArea(); // // See if new area is within an acceptable range // const float newArea = getSurfaceArea(); const float diffArea = newArea - desiredArea; //if ((fabs(diffArea) / desiredArea) > 0.05) { // // Was surface being made larger // if (ratio > 1.0) { const float delta = ratio - 1.0; if (diffArea > 0) { // // Reduce scaling since surface is too large // ratio = delta * 0.5 + 1.0; } else { // // Increase scaling since surface is too small // ratio = delta * 2.0 + 1.0; } } // // Otherwise surface being made smaller // else { const float delta = 1.0 - ratio; if (diffArea > 0) { // // Reduce scaling since surface is too large // ratio = 1.0 - (delta * 2.0); } else { // // Increase scaling since surface is too small // ratio = 1.0 - (delta * 0.5); } } //} // // Restore saved coordinates // popCoordinates(); } if (DebugControl::getDebugOn()) { std::cout << "Scaling to area: " << desiredArea << std::endl; } int bestFit = -1; float smallestDiff = std::numeric_limits::max(); for (int j = 0; j < static_cast(coords.size()); j++) { if (DebugControl::getDebugOn()) { std::cout << " Iteration: " << j << " surface area: " << coordAreas[j] << std::endl; float* xyz = coords[j].getCoordinate(0); std::cout << " Coord 0: " << xyz[0] << ", " << xyz[1] << ", " << xyz[2] << std::endl; } if (coordAreas[j] > 0.0) { const float diff = fabs(coordAreas[j] - desiredArea); if (diff < smallestDiff) { bestFit = j; smallestDiff = diff; } } } if (bestFit >= 0) { coordinates = coords[bestFit]; } if (DebugControl::getDebugOn()) { std::cout << " best fit is : " << bestFit << std::endl; } } coordinates.clearDisplayList(); if (DebugControl::getDebugOn()) { std::cout << "Surface area after scaling: " << this->getSurfaceArea() << std::endl; } } /** * Get the mean, min, max distance between the nodes */ void BrainModelSurface::getMeanDistanceBetweenNodes(BrainModelSurfaceROINodeSelection* surfaceROI, float& meanDist, float& minDist, float& maxDist) const { const TopologyHelper* helper = topology->getTopologyHelper(false, true, false); const float numNodes = helper->getNumberOfNodes(); bool useRoiFlag = false; if (surfaceROI != NULL) { surfaceROI->update(); useRoiFlag = true; } meanDist = 0.0; minDist = std::numeric_limits::max(); maxDist = -std::numeric_limits::max(); for (int i = 0; i < numNodes; i++) { bool doNode = true; if (useRoiFlag) { doNode = surfaceROI->getNodeSelected(i); } if (doNode) { std::vector neighbors; helper->getNodeNeighbors(i, neighbors); const int numNeighbors = static_cast(neighbors.size()); float dist = 0.0; int neighCount = 0; for (int j = 0; j < numNeighbors; j++) { const int neigh = neighbors[j]; bool checkNeigh = true; if (useRoiFlag) { checkNeigh = surfaceROI->getNodeSelected(neigh); } if (checkNeigh) { neighCount++; float nodeDist = coordinates.getDistanceBetweenCoordinates(i, neigh); dist += nodeDist; minDist = std::min(nodeDist, minDist); maxDist = std::max(nodeDist, maxDist); } } if (neighCount > 1) { meanDist += (dist / static_cast(neighCount)); } } } if (numNodes > 1) { meanDist /= static_cast(numNodes); } } /** * Linearly Smooth the surface based upon edges connecting nodes */ void BrainModelSurface::linearSmoothing(const float strength, const int iterations, const int smoothEdgesEveryXIterations, const std::vector* smoothOnlyTheseNodes, const int projectToSphereEveryXIterations) { PreferencesFile* pf = brainSet->getPreferencesFile(); const int numThreads = pf->getMaximumNumberOfThreads(); if (numThreads > 0) { BrainModelSurfaceSmoothing smoothObject(brainSet, this, BrainModelSurfaceSmoothing::SMOOTHING_TYPE_LINEAR, strength, iterations, smoothEdgesEveryXIterations, 0, smoothOnlyTheseNodes, NULL, projectToSphereEveryXIterations, numThreads); try { smoothObject.execute(); } catch (BrainModelAlgorithmException&) { } return; } /* appendToCoordinateFileComment("Linear Smoothing: "); appendToCoordinateFileComment(StringUtilities::fromNumber(strength)); appendToCoordinateFileComment(" "); appendToCoordinateFileComment(StringUtilities::fromNumber(iterations)); appendToCoordinateFileComment(" "); appendToCoordinateFileComment(StringUtilities::fromNumber(smoothEdgesEveryXIterations)); appendToCoordinateFileComment("\n"); */ // // Update node classification // brainSet->classifyNodes(getTopologyFile(), true); const float invStrength = 1.0 - strength; const int numNodes = getNumberOfNodes(); if (numNodes <= 0) { return; } QTime timer; timer.start(); const TopologyHelper* helper = topology->getTopologyHelper(false, true, false); if (DebugControl::getDebugOn()) { std::cout << "Topology Helper time: " << (static_cast(timer.elapsed()) / 1000.0) << std::endl; } std::vector interiorNode(numNodes); for (int i = 0; i < numNodes; i++) { const BrainSetNodeAttribute* bna = brainSet->getNodeAttributes(i); interiorNode[i] = (bna->getClassification() == BrainSetNodeAttribute::CLASSIFICATION_TYPE_INTERIOR); } // // See smoothing is limited to a subset of nodes // bool smoothSubsetOfNodes = false; if (smoothOnlyTheseNodes != NULL) { if (static_cast(smoothOnlyTheseNodes->size()) == numNodes) { smoothSubsetOfNodes = true; } } // // Get the radius in the event that this is a sphere // const float sphereRadius = getSphericalSurfaceRadius(); // // Reduce calls to coord file // float* nodeCoords = new float[numNodes * 3]; float* nodes = new float[numNodes * 3]; for (int i = 0; i < numNodes; i++) { coordinates.getCoordinate(i, &nodeCoords[i*3]); } // // Do 1 to iterations so that modulus check for edge smoothing works // for (int k = 1; k <= iterations; k++) { //std::vector nodes(numNodes * 3); // // See if edges should be smoothed // bool smoothEdges = false; if (smoothEdgesEveryXIterations > 0) { if ((k % smoothEdgesEveryXIterations) == 0) { smoothEdges = true; } } for (int i = 0; i < numNodes; i++) { //coordinates.getCoordinate(i, &nodes[i*3]); nodes[i*3] = nodeCoords[i*3]; nodes[i*3+1] = nodeCoords[i*3+1]; nodes[i*3+2] = nodeCoords[i*3+2]; bool smoothIt = true; if (interiorNode[i] == false) { smoothIt = smoothEdges; } if (smoothIt && smoothSubsetOfNodes) { smoothIt = (*smoothOnlyTheseNodes)[i]; } if (smoothIt) { //std::vector neighbors; //helper->getNodeNeighbors(i, neighbors); //const int numNeighbors = static_cast(neighbors.size()); int numNeighbors; const int* neighbors = helper->getNodeNeighbors(i, numNeighbors); if (numNeighbors > 0) { float neighXYZ[3] = { 0.0, 0.0, 0.0 }; for (int j = 0; j < numNeighbors; j++) { //float np[3]; //coordinates.getCoordinate(neighbors[j], np); const int n = neighbors[j]; neighXYZ[0] += nodeCoords[n*3]; //np[0]; neighXYZ[1] += nodeCoords[n*3+1]; //np[1]; neighXYZ[2] += nodeCoords[n*3+2]; //np[2]; } const float floatNumNeigh = numNeighbors; neighXYZ[0] /= floatNumNeigh; neighXYZ[1] /= floatNumNeigh; neighXYZ[2] /= floatNumNeigh; nodes[i*3] = nodeCoords[i*3] * invStrength + neighXYZ[0] * strength; nodes[i*3+1] = nodeCoords[i*3+1] * invStrength + neighXYZ[1] * strength; nodes[i*3+2] = nodeCoords[i*3+2] * invStrength + neighXYZ[2] * strength; } } } // // If the surface should be projected to a sphere // if (projectToSphereEveryXIterations > 0) { if ((k % projectToSphereEveryXIterations) == 0) { for (int j = 0; j < numNodes; j++) { MathUtilities::setVectorLength(&nodes[j*3], sphereRadius); } } } for (int i = 0; i < numNodes; i++) { nodeCoords[i*3] = nodes[i*3]; nodeCoords[i*3+1] = nodes[i*3+1]; nodeCoords[i*3+2] = nodes[i*3+2]; coordinates.setCoordinate(i, &nodes[i*3]); } // // Update the displayed brain model // brainSet->drawBrainModel(this, k); } //for (int i = 0; i < numNodes; i++) { // coordinates.setCoordinate(i, &nodeCoords[i*3]); //} delete[] nodes; delete[] nodeCoords; if (DebugControl::getDebugOn()) { std::cout << "Total time: " << (static_cast(timer.elapsed()) / 1000.0) << std::endl; } } /** * Areal Smooth the surface based upon tile areas. * If "smoothOnlyTheseNodes" is not NULL and its number of elements is equal * to the number of nodes, only those nodes with *smoothOnlyTheseNodes[nodeNum] * will be smoothed. */ void BrainModelSurface::arealSmoothing(const float strength, const int iterations, const int smoothEdgesEveryXIterations, const std::vector* smoothOnlyTheseNodes, const int projectToSphereEveryXIterations) { PreferencesFile* pf = brainSet->getPreferencesFile(); const int numThreads = pf->getMaximumNumberOfThreads(); if (numThreads > 0) { BrainModelSurfaceSmoothing smoothObject(brainSet, this, BrainModelSurfaceSmoothing::SMOOTHING_TYPE_AREAL, strength, iterations, smoothEdgesEveryXIterations, 0, smoothOnlyTheseNodes, NULL, projectToSphereEveryXIterations, numThreads); try { smoothObject.execute(); } catch (BrainModelAlgorithmException&) { } return; } /* appendToCoordinateFileComment("Areal Smoothing: "); appendToCoordinateFileComment(StringUtilities::fromNumber(strength)); appendToCoordinateFileComment(" "); appendToCoordinateFileComment(StringUtilities::fromNumber(iterations)); appendToCoordinateFileComment(" "); appendToCoordinateFileComment(StringUtilities::fromNumber(smoothEdgesEveryXIterations)); appendToCoordinateFileComment("\n"); */ // // Update node classification // brainSet->classifyNodes(getTopologyFile(), true); const float invStrength = 1.0 - strength; const int numNodes = getNumberOfNodes(); if ((numNodes <= 0) || (topology->getNumberOfTiles() <= 0)) { return; } QTime timer; timer.start(); const TopologyHelper* helper = topology->getTopologyHelper(false, true, true); if (DebugControl::getDebugOn()) { std::cout << "Topology Helper time: " << (static_cast(timer.elapsed()) / 1000.0) << std::endl; } int* interiorNode = new int[numNodes]; for (int i = 0; i < numNodes; i++) { const BrainSetNodeAttribute* bna = brainSet->getNodeAttributes(i); interiorNode[i] = (bna->getClassification() == BrainSetNodeAttribute::CLASSIFICATION_TYPE_INTERIOR); } // // See smoothing is limited to a subset of nodes // bool smoothSubsetOfNodes = false; if (smoothOnlyTheseNodes != NULL) { if (static_cast(smoothOnlyTheseNodes->size()) == numNodes) { smoothSubsetOfNodes = true; } } // // Get the radius in the event that this is a sphere // const float sphereRadius = getSphericalSurfaceRadius(); // // Reduce calls to coord file // float* nodeCoords = new float[numNodes * 3]; float* nodes = new float[numNodes * 3]; for (int i = 0; i < numNodes; i++) { coordinates.getCoordinate(i, &nodeCoords[i*3]); } // Do 1 to iterations so that modulus check for edge smoothing works // for (int k = 1; k <= iterations; k++) { //std::vector nodes(numNodes * 3); // // See if edges should be smoothed // bool smoothEdges = false; if (smoothEdgesEveryXIterations > 0) { if ((k % smoothEdgesEveryXIterations) == 0) { smoothEdges = true; } } for (int i = 0; i < numNodes; i++) { nodes[i*3] = nodeCoords[i*3]; nodes[i*3+1] = nodeCoords[i*3+1]; nodes[i*3+2] = nodeCoords[i*3+2]; // coordinates.getCoordinate(i, &nodes[i*3]); } for (int i = 0; i < numNodes; i++) { bool smoothIt = true; if (interiorNode[i] == false) { smoothIt = smoothEdges; } if (smoothIt && smoothSubsetOfNodes) { smoothIt = (*smoothOnlyTheseNodes)[i]; } if (smoothIt) { //std::vector neighbors; //helper->getNodeNeighbors(i, neighbors); //const int numNeighbors = static_cast(neighbors.size()); int numNeighbors; const int* neighbors = helper->getNodeNeighbors(i, numNeighbors); if (numNeighbors > 1) { std::vector tileAreas(numNeighbors); std::vector tileCenters(numNeighbors*3); float totalArea = 0.0; for (int j = 0; j < numNeighbors; j++) { // // get 2 consecutive neighbors of this node const int n1 = neighbors[j]; int next = j + 1; if (next >= numNeighbors) { next = 0; } const int n2 = neighbors[next]; // // Area of the triangle // const float area = MathUtilities::triangleArea(&nodeCoords[i*3], &nodeCoords[n1*3], &nodeCoords[n2*3]); tileAreas[j] = area; totalArea += area; // // Save center of this tile // for (int k = 0; k < 3; k++) { float p = (nodeCoords[i*3+k] + nodeCoords[n1*3+k] + nodeCoords[n2*3+k]) / 3.0; tileCenters[j*3+k] = p; } } // // Compute the influence of the neighboring nodes // float xa = 0.0; float ya = 0.0; float za = 0.0; for (int j = 0; j < numNeighbors; j++) { if (tileAreas[j] > 0.0) { const float weight = tileAreas[j] / totalArea; xa += weight * tileCenters[j*3]; ya += weight * tileCenters[j*3+1]; za += weight * tileCenters[j*3+2]; } } // // Update the nodes position // nodes[i*3] = nodeCoords[i*3] * invStrength + xa * strength; nodes[i*3+1] = nodeCoords[i*3+1] * invStrength + ya * strength; nodes[i*3+2] = nodeCoords[i*3+2] * invStrength + za * strength; } } } // // If the surface should be projected to a sphere // if (projectToSphereEveryXIterations > 0) { if ((k % projectToSphereEveryXIterations) == 0) { for (int j = 0; j < numNodes; j++) { MathUtilities::setVectorLength(&nodes[j*3], sphereRadius); } } } for (int i = 0; i < numNodes; i++) { nodeCoords[i*3] = nodes[i*3]; nodeCoords[i*3+1] = nodes[i*3+1]; nodeCoords[i*3+2] = nodes[i*3+2]; coordinates.setCoordinate(i, &nodes[i*3]); } // // Update the displayed brain model // brainSet->drawBrainModel(this, k); } //for (int i = 0; i < numNodes; i++) { // coordinates.setCoordinate(i, &nodeCoords[i*3]); //} delete[] nodes; delete[] nodeCoords; delete[] interiorNode; //if (DebugControl::getDebugOn()) { std::cout << "Total time: " << (static_cast(timer.elapsed()) / 1000.0) << std::endl; //} } /** * Search topology to mark nodes to the specified depth. "Depth" cycles are run and during * each cycle, if a node's "nodeFlags" is set, the neighbors of the node have their * "nodeFlags" set. This is a non-recursive algorithm since recursion can be slow and * since the call stack is small on OSX operating systems. */ void BrainModelSurface::markNeighborNodesToDepth(std::vector& nodeFlags, const int depthIn) { const int numNodes = getNumberOfNodes(); if (numNodes <= 0) { return; } // // Get the topology helper // const TopologyFile* tf = getTopologyFile(); const TopologyHelper* th = tf->getTopologyHelper(false, true, false); // // Flag that marks neighbors // std::vector neighborFlag(numNodes); // // Loop for specified depth // for (int depth = 0; depth < depthIn; depth++) { // // Clear neighbor flags // std::fill(neighborFlag.begin(), neighborFlag.end(), false); // // loop for each node // for (int i = 0; i < numNodes; i++) { // // If this node is flagged // if (nodeFlags[i]) { // // Mark its neighbors // int numNeighbors = 0; const int* neighbors = th->getNodeNeighbors(i, numNeighbors); for (int j = 0; j < numNeighbors; j++) { neighborFlag[neighbors[j]] = true; } } } // // Update node flags with neighbors that were just marked // for (int i = 0; i < numNodes; i++) { if (neighborFlag[i]) { nodeFlags[i] = true; } } } } /** * Smooth out crossovers in a surface */ void BrainModelSurface::smoothOutSurfaceCrossovers(const float strength, const int numberOfCycles, const int iterationsPerCycle, const int smoothEdgesEveryXIterations, const int projectToSphereEveryXIterations, const int neighborDepth, const SURFACE_TYPES surfaceTypeHint) { const int numNodes = getNumberOfNodes(); if (numNodes <= 0) { return; } std::vector crossoverFlags(numNodes); // // Loop for the number of cycles // for (int i = 0; i < numberOfCycles; i++) { // // Get number of crossovers // int numNodeCrossovers = 0; int numTileCrossovers = 0; crossoverCheck(numTileCrossovers, numNodeCrossovers, surfaceTypeHint); // // See if there are crossovers // if (numNodeCrossovers > 0) { // // Find the nodes that are crossovers // std::fill(crossoverFlags.begin(), crossoverFlags.end(), false); for (int j = 0; j < numNodes; j++) { BrainSetNodeAttribute* bna = brainSet->getNodeAttributes(j); if (bna->getCrossover() == BrainSetNodeAttribute::CROSSOVER_YES) { crossoverFlags[j] = true; } } // // Mark the neighboring nodes to the specified depth // markNeighborNodesToDepth(crossoverFlags, neighborDepth); if (DebugControl::getDebugOn()) { int numXOver = 0; for (int k = 0; k < numNodes; k++) { if (crossoverFlags[k]) { numXOver++; } BrainSetNodeAttribute* bna = brainSet->getNodeAttributes(k); if (crossoverFlags[k]) { bna->setCrossover(BrainSetNodeAttribute::CROSSOVER_YES); } else { bna->setCrossover(BrainSetNodeAttribute::CROSSOVER_NO); } } std::cout << "Crossover Smoothing: " << numXOver << " nodes will be smoothed." << std::endl; } // // Smooth the crossovers and surrounding nodes // arealSmoothing(strength, iterationsPerCycle, smoothEdgesEveryXIterations, &crossoverFlags, projectToSphereEveryXIterations); } else { break; } } coordinates.clearDisplayList(); } /** * (try to) smooth out flat surface overlap. Returns true if any smoothing was done */ bool BrainModelSurface::smoothOutFlatSurfaceOverlap(const float strength, const int numberOfCycles, const int iterationsPerCycle, const int smoothEdgesEveryXIterations, const int neighborDepth) { bool surfaceWasSmoothed = false; const int numNodes = getNumberOfNodes(); if (numNodes <= 0) { return surfaceWasSmoothed; } // // Get the topology file and the number of tiles // TopologyFile* tf = getTopologyFile(); const int numTiles = tf->getNumberOfTiles(); if (numTiles <= 0) { return surfaceWasSmoothed; } // // Use a multiple of the mean distance between nodes for searching around node // float meanDist, minDist, maxDist; getMeanDistanceBetweenNodes(NULL, meanDist, minDist, maxDist); float longestLinkDistance = meanDist * 3; if (DebugControl::getDebugOn()) { std::cout << "Longest link distance is " << longestLinkDistance << std::endl; } // // Topology helper to get tiles used by each node // const TopologyHelper* topologyHelper = topology->getTopologyHelper(false, true, false); // // Classify the nodes as interior and edges // brainSet->classifyNodes(tf); for (int cycles = 0; cycles < numberOfCycles; cycles++) { // // Flags overlapping nodes // std::vector overlapNodeFlag(numNodes, false); // // Create a point locator to find nodes // BrainModelSurfacePointLocator bmspl(this, true); // // Check all edge nodes // for (int i = 0; i < numNodes; i++) { if (brainSet->getNodeAttributes(i)->getClassification() != BrainSetNodeAttribute::CLASSIFICATION_TYPE_INTERIOR) { const float* xyz = coordinates.getCoordinate(i); // // Find nodes near this node // std::vector nearbyNodes; bmspl.getPointsWithinRadius(xyz, longestLinkDistance, nearbyNodes); if (DebugControl::getDebugNodeNumber() == i) { std::cout << "Node " << i << " has " << nearbyNodes.size() << " nearby neighbors" << std::endl; } // // Find tiles used by the nearby nodes // std::set tilesToCheck; const int numNearbyNodes = static_cast(nearbyNodes.size()); for (int j = 0 ; j < numNearbyNodes; j++) { const int node = nearbyNodes[j]; if (node != i) { std::vector tiles; topologyHelper->getNodeTiles(node, tiles); tilesToCheck.insert(tiles.begin(), tiles.end()); } } // // Check to see if node is on another tile indicating overlap // for (std::set::iterator iter = tilesToCheck.begin(); iter != tilesToCheck.end(); iter++) { const int tileNum = *iter; int v1, v2, v3; topology->getTile(tileNum, v1, v2, v3); if ((v1 != i) && (v2 != i) && (v3 != i)) { const float area1 = MathUtilities::signedTriangleArea2D(coordinates.getCoordinate(v1), coordinates.getCoordinate(v2), xyz); if (area1 > 0.0) { const float area2 = MathUtilities::signedTriangleArea2D(coordinates.getCoordinate(v2), coordinates.getCoordinate(v3), xyz); if (area2 > 0.0) { const float area3 = MathUtilities::signedTriangleArea2D(coordinates.getCoordinate(v3), coordinates.getCoordinate(v1), xyz); if (area3 > 0.0) { overlapNodeFlag[i] = true; if (DebugControl::getDebugOn()) { std::cout << "Node " << i << " overlaps on tile " << tileNum << " with nodes " << v1 << " " << v2 << " " << v3 << std::endl; } break; } } } } } } } // // Mark the neighbors of overlap nodes // for (int depth = 0; depth < neighborDepth; depth++) { std::vector overlapNodeNeighborsFlag(numNodes, false); for (int i = 0; i < numNodes; i++) { if (overlapNodeFlag[i]) { int numNeighbors = 0; const int* neighbors = topologyHelper->getNodeNeighbors(i, numNeighbors); for (int j = 0; j < numNeighbors; j++) { overlapNodeNeighborsFlag[neighbors[j]] = true; } } } for (int i = 0; i < numNodes; i++) { if (overlapNodeNeighborsFlag[i]) { overlapNodeFlag[i] = true; } } } // // Mark overlapped nodes as crossovers // int numMarked = 0; for (int i = 0; i < numNodes; i++) { brainSet->getNodeAttributes(i)->setCrossover(BrainSetNodeAttribute::CROSSOVER_NO); if (overlapNodeFlag[i]) { brainSet->getNodeAttributes(i)->setCrossover(BrainSetNodeAttribute::CROSSOVER_YES); numMarked++; } } if (DebugControl::getDebugOn()) { std::cout << "Num nodes flagged as overlap " << numMarked << std::endl; } if (numMarked > 0) { linearSmoothing(strength, iterationsPerCycle, smoothEdgesEveryXIterations, &overlapNodeFlag); //linearSmoothing(0.5, 3, 2); surfaceWasSmoothed = true; } else { break; } } if (surfaceWasSmoothed) { // appendToCoordinateFileComment("Smoothed out flat surface overlap\n"); } coordinates.clearDisplayList(); return surfaceWasSmoothed; } /// Keeps track of info for nodes for landmark neighbors class NodeInfo { public: // // Three types of nodes // enum NODE_TYPE { NODE_NORMAL, NODE_LANDMARK, NODE_LANDMARK_NEIGHBOR }; float xyz[3]; float offset[3]; NODE_TYPE nodeType; int numLandmarkNeighbors; NodeInfo() { xyz[0] = xyz[1] = xyz[2] = 0.0; offset[0] = offset[1] = offset[2] = 0; nodeType = NODE_NORMAL; numLandmarkNeighbors = 0; } }; /** * Performed landmark constrained smoothing. */ void BrainModelSurface::landmarkConstrainedSmoothing(const float strength, const int iterations, const std::vector& landmarkNodeFlag, const int projectToSphereEveryXIterations) { PreferencesFile* pf = brainSet->getPreferencesFile(); const int numThreads = pf->getMaximumNumberOfThreads(); if (numThreads > 0) { BrainModelSurfaceSmoothing smoothObject(brainSet, this, BrainModelSurfaceSmoothing::SMOOTHING_TYPE_LANDMARK_CONSTRAINED, strength, iterations, 0, 0, NULL, &landmarkNodeFlag, projectToSphereEveryXIterations, numThreads); try { smoothObject.execute(); } catch (BrainModelAlgorithmException&) { } return; } const float inverseStrength = 1.0 - strength; const int numNodes = getNumberOfNodes(); const TopologyHelper* helper = topology->getTopologyHelper(false, true, true); std::vector nodeInfo(numNodes); float scale = 0.0; bool haveScale = false; appendToCoordinateFileComment("Landmark Constrained Smoothing: "); appendToCoordinateFileComment(StringUtilities::fromNumber(strength)); appendToCoordinateFileComment(" "); appendToCoordinateFileComment(StringUtilities::fromNumber(iterations)); appendToCoordinateFileComment("\n"); // // Set node info for all nodes // for (int i = 0; i < numNodes; i++) { // // Is this node a landmarkd // if (landmarkNodeFlag[i]) { nodeInfo[i].nodeType = NodeInfo::NODE_LANDMARK; } else { // // See if any of nodes neighbors are landmarks // std::vector neighbors; helper->getNodeNeighbors(i, neighbors); for (int j = 0; j < static_cast(neighbors.size()); j++) { const int n = neighbors[j]; if (landmarkNodeFlag[n]) { nodeInfo[i].numLandmarkNeighbors++; } else { if (haveScale == false) { haveScale = true; scale = MathUtilities::distance3D(coordinates.getCoordinate(i), coordinates.getCoordinate(n)) / std::sqrt(3.0); } } } if (nodeInfo[i].numLandmarkNeighbors > 0) { nodeInfo[i].nodeType = NodeInfo::NODE_LANDMARK_NEIGHBOR; } } } // // smooth for specified number of iterations // for (int iter = 0; iter < iterations; iter++) { for (int i = 0; i < numNodes; i++) { // // Get the coordinate // coordinates.getCoordinate(i, nodeInfo[i].xyz); // // Get the neighbors for this node // //std::vector neighbors; //helper->getNodeNeighbors(i, neighbors); //const int numNeighbors = static_cast(neighbors.size()); int numNeighbors; const int* neighbors = helper->getNodeNeighbors(i, numNeighbors); const float floatNumNeighbors = numNeighbors; // // Ignore nodes without neighbors and ignore landmark nodes // if ((numNeighbors > 1) && (nodeInfo[i].nodeType != NodeInfo::NODE_LANDMARK)) { // // Get average of neighbor coordinates // float sumx = 0.0, sumy = 0.0, sumz = 0.0; for (int k = 0; k < numNeighbors; k++) { const float* neighXYZ = coordinates.getCoordinate(neighbors[k]); sumx += neighXYZ[0]; sumy += neighXYZ[1]; sumz += neighXYZ[2]; } float meanX = sumx / floatNumNeighbors; float meanY = sumy / floatNumNeighbors; float meanZ = sumz / floatNumNeighbors; // // Is this a node neither landmark nor landmark neighbor // if (nodeInfo[i].nodeType == NodeInfo::NODE_NORMAL) { // // Normal smoothing // nodeInfo[i].xyz[0] = nodeInfo[i].xyz[0] * inverseStrength + strength * meanX; nodeInfo[i].xyz[1] = nodeInfo[i].xyz[1] * inverseStrength + strength * meanY; nodeInfo[i].xyz[2] = nodeInfo[i].xyz[2] * inverseStrength + strength * meanZ; } else { // // To get here node must be a neighbor of a landmark node // for (int k = 0; k < numNeighbors; k++) { // // Is neighbor a landmark node ? // const int neigh = neighbors[k]; if (nodeInfo[neigh].nodeType == NodeInfo::NODE_LANDMARK) { // // Get the next and previous neigbors of this landmark node // int prevNeighIndex = k - 1; if (prevNeighIndex < 0) { prevNeighIndex = numNeighbors - 1; } const int neighA = neighbors[prevNeighIndex]; int nextNeighIndex = k + 1; if (nextNeighIndex >= numNeighbors) { nextNeighIndex = 0; } const int neighB = neighbors[nextNeighIndex]; // // Get coordinates of this landmark neighbor and next and previous neighbors // float ai[3]; coordinates.getCoordinate(neighA, ai); float bi[3]; coordinates.getCoordinate(neighB, bi); float li[3]; coordinates.getCoordinate(neigh, li); // // Adjust the position of neighbor average // float p[3]; p[0] = 2*li[0] - ai[0] - bi[0]; p[1] = 2*li[1] - ai[1] - bi[1]; p[2] = 2*li[2] - ai[2] - bi[2]; float len = std::sqrt(p[0]*p[0] + p[1]*p[1] + p[2]*p[2]); p[0] /= len; p[1] /= len; p[2] /= len; meanX += li[0] + scale * p[0]; meanY += li[1] + scale * p[1]; meanZ += li[2] + scale * p[2]; } } meanX /= (nodeInfo[i].numLandmarkNeighbors + 1); meanY /= (nodeInfo[i].numLandmarkNeighbors + 1); meanZ /= (nodeInfo[i].numLandmarkNeighbors + 1); nodeInfo[i].xyz[0] = inverseStrength * nodeInfo[i].xyz[0] + strength * meanX; nodeInfo[i].xyz[1] = inverseStrength * nodeInfo[i].xyz[1] + strength * meanY; nodeInfo[i].xyz[2] = inverseStrength * nodeInfo[i].xyz[2] + strength * meanZ; } } } // // Set the coordinates // for (int i = 0; i < numNodes; i++) { coordinates.setCoordinate(i, nodeInfo[i].xyz); } // // Update the displayed brain model // brainSet->drawBrainModel(this, iter); } coordinates.clearDisplayList(); } /** * Performed landmark neighbor constrained smoothing. */ void BrainModelSurface::landmarkNeighborConstrainedSmoothing(const float strength, const int iterations, const std::vector& landmarkNodeFlag, const int smoothNeighborsEveryX, const int projectToSphereEveryXIterations) { PreferencesFile* pf = brainSet->getPreferencesFile(); int numThreads = pf->getMaximumNumberOfThreads(); // numThreads = 0; // if (numThreads > 0) { // BrainModelSurfaceSmoothing smoothObject(brainSet, // this, // BrainModelSurfaceSmoothing::SMOOTHING_TYPE_LANDMARK_NEIGHBOR_CONSTRAINED, // strength, // iterations, // 0, // smoothNeighborsEveryX, // NULL, // &landmarkNodeFlag, // projectToSphereEveryXIterations, // numThreads); // try { // smoothObject.execute(); // } // catch (BrainModelAlgorithmException&) { // } // // return; // } const float sphereRadius = getSphericalSurfaceRadius(); const float inverseStrength = 1.0 - strength; const int numNodes = getNumberOfNodes(); const TopologyHelper* helper = topology->getTopologyHelper(false, true, true); std::vector nodeInfo(numNodes); appendToCoordinateFileComment("Landmark Neighbor Constrained Smoothing: "); appendToCoordinateFileComment(StringUtilities::fromNumber(strength)); appendToCoordinateFileComment(" "); appendToCoordinateFileComment(StringUtilities::fromNumber(iterations)); appendToCoordinateFileComment(" "); appendToCoordinateFileComment(StringUtilities::fromNumber(smoothNeighborsEveryX)); appendToCoordinateFileComment("\n"); // // Set node info for all nodes // for (int i = 0; i < numNodes; i++) { // // Get neighbors for this node // //std::vector neighbors; //helper->getNodeNeighbors(i, neighbors); //const int numNeighbors = static_cast(neighbors.size()); int numNeighbors; const int* neighbors = helper->getNodeNeighbors(i, numNeighbors); const float floatNumNeighbors = numNeighbors; // // Is this node a landmarkd // if (landmarkNodeFlag[i]) { nodeInfo[i].nodeType = NodeInfo::NODE_LANDMARK; // // Calculate offset of this landmark node from the average of neighbors // float neighborSum[3] = { 0.0, 0.0, 0.0 }; for (int j = 0; j < numNeighbors; j++) { const float* xyz = coordinates.getCoordinate(neighbors[j]); neighborSum[0] += xyz[0]; neighborSum[1] += xyz[1]; neighborSum[2] += xyz[2]; } const float* xyz = coordinates.getCoordinate(i); nodeInfo[i].offset[0] = xyz[0] - (neighborSum[0] / floatNumNeighbors); nodeInfo[i].offset[1] = xyz[1] - (neighborSum[1] / floatNumNeighbors); nodeInfo[i].offset[2] = xyz[2] - (neighborSum[2] / floatNumNeighbors); } else { // // See if any of nodes neighbors are landmarks // for (int j = 0; j < numNeighbors; j++) { const int n = neighbors[j]; if (landmarkNodeFlag[n]) { nodeInfo[i].numLandmarkNeighbors++; } } if (nodeInfo[i].numLandmarkNeighbors > 0) { nodeInfo[i].nodeType = NodeInfo::NODE_LANDMARK_NEIGHBOR; } } } // // Apply offsets to landmark neighbors // for (int i = 0; i < numNodes; i++) { if (nodeInfo[i].nodeType == NodeInfo::NODE_LANDMARK_NEIGHBOR) { // // Get neighbors for this node // //std::vector neighbors; //helper->getNodeNeighbors(i, neighbors); //const int numNeighbors = static_cast(neighbors.size()); int numNeighbors; const int* neighbors = helper->getNodeNeighbors(i, numNeighbors); // // Get average of landmark neighbor offsets // float avg[3] = { 0.0, 0.0, 0.0 }; for (int j = 0; j < numNeighbors; j++) { const int n = neighbors[j]; if (nodeInfo[n].nodeType == NodeInfo::NODE_LANDMARK) { avg[0] += nodeInfo[n].offset[0]; avg[1] += nodeInfo[n].offset[1]; avg[2] += nodeInfo[n].offset[2]; } } // // Offset this landmark neighbor // const float floatNumLandmarkNeighbors = nodeInfo[i].numLandmarkNeighbors; float xyz[3]; coordinates.getCoordinate(i, xyz); xyz[0] += (avg[0] / floatNumLandmarkNeighbors); xyz[1] += (avg[1] / floatNumLandmarkNeighbors); xyz[2] += (avg[2] / floatNumLandmarkNeighbors); coordinates.setCoordinate(i, xyz); } } // // smooth for specified number of iterations // int smoothNeighborCounter = 1; for (int iter = 1; iter <= iterations; iter++) { for (int i = 0; i < numNodes; i++) { // // Get the coordinate // coordinates.getCoordinate(i, nodeInfo[i].xyz); // // Get the neighbors for this node // //std::vector neighbors; //helper->getNodeNeighbors(i, neighbors); //const int numNeighbors = static_cast(neighbors.size()); int numNeighbors; const int* neighbors = helper->getNodeNeighbors(i, numNeighbors); const float floatNumNeighbors = numNeighbors; // // Only smooth nodes with neighbors // if (numNeighbors > 0) { // // Do not smooth landmark nodes // smooth landmark neighbors every "smoothNeighborsEveryX" iterations // smooth normal nodes every iteration // if ((nodeInfo[i].nodeType == NodeInfo::NODE_NORMAL) || ((nodeInfo[i].nodeType == NodeInfo::NODE_LANDMARK_NEIGHBOR) && (smoothNeighborCounter == smoothNeighborsEveryX))) { // // Get average of neighbors coordinates // float neighborAverage[3] = { 0.0, 0.0, 0.0 }; for (int j = 0; j < numNeighbors; j++) { const int n = neighbors[j]; const float* xyz = coordinates.getCoordinate(n); neighborAverage[0] += xyz[0]; neighborAverage[1] += xyz[1]; neighborAverage[2] += xyz[2]; } neighborAverage[0] /= floatNumNeighbors; neighborAverage[1] /= floatNumNeighbors; neighborAverage[2] /= floatNumNeighbors; // // Smooth the node // nodeInfo[i].xyz[0] = nodeInfo[i].xyz[0] * inverseStrength + strength * neighborAverage[0]; nodeInfo[i].xyz[1] = nodeInfo[i].xyz[1] * inverseStrength + strength * neighborAverage[1]; nodeInfo[i].xyz[2] = nodeInfo[i].xyz[2] * inverseStrength + strength * neighborAverage[2]; } } } // // Update the neighbor smoothing counter // if (smoothNeighborCounter >= smoothNeighborsEveryX) { smoothNeighborCounter = 1; } else { smoothNeighborCounter++; } // // If the surface should be projected to a sphere // if (projectToSphereEveryXIterations > 0) { if ((iter % projectToSphereEveryXIterations) == 0) { for (int j = 0; j < numNodes; j++) { MathUtilities::setVectorLength(nodeInfo[j].xyz, sphereRadius); } } } // // Set the coordinates // for (int i = 0; i < numNodes; i++) { coordinates.setCoordinate(i, nodeInfo[i].xyz); } // // If the surface should be projected to a sphere // //if (projectToSphereEveryXIterations > 0) { // if ((iter % projectToSphereEveryXIterations) == 0) { // convertToSphereWithRadius(sphereRadius); // } //} // // Update the displayed brain model // brainSet->drawBrainModel(this, iter); } coordinates.clearDisplayList(); } /** * Convert to a sphere with the specified area. * Disconnected nodes are placed at origin. * Assumes surface is already centered at origin. */ void BrainModelSurface::convertToSphereWithSurfaceArea(const float desiredSphereAreaIn) { float desiredSphereArea = desiredSphereAreaIn; // // If area not set just use the surface area // if (desiredSphereArea <= 0.0) { desiredSphereArea = getSurfaceArea(); } // // Area sphere is 4 * PI * Radius * Radius // const float radius = std::sqrt(desiredSphereArea / (4.0 * M_PI)); //appendToCoordinateFileComment("Convert to sphere with area: "); //appendToCoordinateFileComment(StringUtilities::fromNumber(desiredSphereAreaIn)); //appendToCoordinateFileComment("\n"); convertToSphereWithRadius(radius); } /** * Convert to a sphere with the specified radius. * Disconnected nodes are placed at origin. * Assumes surface is already centered at origin. */ void BrainModelSurface::convertToSphereWithRadius(const float radius, const int startNodeIndexIn, const int endNodeIndexIn) { const int numNodes = getNumberOfNodes(); const TopologyHelper* helper = topology->getTopologyHelper(false, true, false); // // Set start and end nodes if needed // int startNodeIndex = startNodeIndexIn; if (startNodeIndex < 0) { startNodeIndex = 0; } int endNodeIndex = endNodeIndexIn; if (endNodeIndex < 0) { endNodeIndex = numNodes; } for (int i = startNodeIndex; i < endNodeIndex; i++) { float p[3]; if (helper->getNodeHasNeighbors(i)) { coordinates.getCoordinate(i, p); const float prad = std::sqrt(p[0]*p[0] + p[1]*p[1] + p[2]*p[2]); if (prad > 0.0) { const float scale = radius / prad; p[0] *= scale; p[1] *= scale; p[2] *= scale; } } else { p[0] = p[1] = p[2] = 0.0; } coordinates.setCoordinate(i, p); } // // set the surface type to a sphere // setSurfaceType(SURFACE_TYPE_SPHERICAL); // // Reset the viewing transformations // resetViewingTransformations(); // appendToCoordinateFileComment("Convert to sphere with radius: "); // appendToCoordinateFileComment(StringUtilities::fromNumber(radius)); // appendToCoordinateFileComment("\n"); } /** * move the surface so that the midpoint of the surface is at the origin. */ void BrainModelSurface::translateMidpointToOrigin() { /* * Get bounds */ float bounds[6]; this->getBounds(bounds); /* * Get center of sphere */ float center[] = { ((bounds[0] + bounds[1]) / 2.0f), ((bounds[2] + bounds[3]) / 2.0f), ((bounds[4] + bounds[5]) / 2.0f) }; /* * Set translation */ TransformationMatrix tm; tm.translate(-center[0], -center[1], -center[2]); this->applyTransformationMatrix(tm); } /** * Convert an ellipsoidal surface to a sphere (if area is zero the ellipsoidal area will be used). */ void BrainModelSurface::convertEllipsoidToSphereWithSurfaceArea(const float desiredSphereAreaIn) { // // Get a topology helper // const TopologyHelper* th = topology->getTopologyHelper(false, true, false); // // Determine surface area if necessary // float desiredSurfaceArea = desiredSphereAreaIn; if (desiredSurfaceArea <= 0.0) { desiredSurfaceArea = getSurfaceArea(); } // // Determine radius of the output sphere. // Note: Sphere surface area = 4 * PI * Radius * Radius // const float sphereRadius = std::sqrt(desiredSurfaceArea / (4.0 * M_PI)); // // Determine lengths of the axes // float bounds[6]; coordinates.getBounds(bounds); const float A = (fabs(bounds[0]) + fabs(bounds[1])) * 0.5; const float B = (fabs(bounds[2]) + fabs(bounds[3])) * 0.5; const float C = (fabs(bounds[4]) + fabs(bounds[5])) * 0.5; // // Convert the coordinates from ellipsoid to sphere // const float aSquared = A * A; const float bSquared = B * B; const float cSquared = C * C; const int numCoords = getNumberOfNodes(); for (int i = 0; i < numCoords; i++) { float xyz[3] = { 0.0, 0.0, 0.0 }; if (th->getNodeHasNeighbors(i)) { coordinates.getCoordinate(i, xyz); // // "unitize" the ellipsoidal coordinates // // x*x y*y z*z // --- + --- + --- = 1.0 // A*A B*B C*C // const float t1 = (xyz[0]*xyz[0]) / (aSquared); const float t2 = (xyz[1]*xyz[1]) / (bSquared); const float t3 = (xyz[2]*xyz[2]) / (cSquared); const float f = std::sqrt(t1 + t2 + t3); if (f != 0.0) { xyz[0] /= f; xyz[1] /= f; xyz[2] /= f; } // // Push coordinate onto the sphere // xyz[0] = (sphereRadius * xyz[0]) / A; xyz[1] = (sphereRadius * xyz[1]) / B; xyz[2] = (sphereRadius * xyz[2]) / C; } coordinates.setCoordinate(i, xyz); } // // set the surface type to a sphere // setSurfaceType(SURFACE_TYPE_SPHERICAL); // // Reset the viewing transformations // resetViewingTransformations(); appendToCoordinateFileComment("Convert to ellipoid with area: "); appendToCoordinateFileComment(StringUtilities::fromNumber(desiredSphereAreaIn)); appendToCoordinateFileComment("\n"); } /** * convert to an ellipsoid surface. */ void BrainModelSurface::convertToEllipsoid() { // // Get a topology helper // const TopologyHelper* th = topology->getTopologyHelper(false, true, false); // // Translate the surface to its center of mass // translateToCenterOfMass(); // // Determine lengths of the axes // float bounds[6]; coordinates.getBounds(bounds); const float A = (fabs(bounds[0]) + fabs(bounds[1])) * 0.5; const float B = (fabs(bounds[2]) + fabs(bounds[3])) * 0.5; const float C = (fabs(bounds[4]) + fabs(bounds[5])) * 0.5; const float aSquared = A * A; const float bSquared = B * B; const float cSquared = C * C; // // "normalize" the ellipsoidal coordinates // const int numCoords = getNumberOfNodes(); for (int i = 0; i < numCoords; i++) { float xyz[3] = { 0.0, 0.0, 0.0 }; if (th->getNodeHasNeighbors(i)) { coordinates.getCoordinate(i, xyz); // x*x y*y z*z // --- + --- + --- = 1.0 // A*A B*B C*C // const float t1 = (xyz[0]*xyz[0]) / (aSquared); const float t2 = (xyz[1]*xyz[1]) / (bSquared); const float t3 = (xyz[2]*xyz[2]) / (cSquared); const float f = std::sqrt(t1 + t2 + t3); if (f != 0.0) { xyz[0] /= f; xyz[1] /= f; xyz[2] /= f; } } coordinates.setCoordinate(i, xyz); } // // Scale the surface to its original major axis size // coordinates.getBounds(bounds); const float newA = (fabs(bounds[0]) + fabs(bounds[1])) * 0.5; if (newA > 0.0) { const float scaleFactor = A / newA; TransformationMatrix tm; tm.scale(scaleFactor, scaleFactor, scaleFactor); } setSurfaceType(SURFACE_TYPE_ELLIPSOIDAL); appendToCoordinateFileComment("Convert to ellipsoid."); } /** * Rotate a surface so that the node is on the positive Z-axis (facing user). */ void BrainModelSurface::orientNodeToPositiveScreenZ(const int nodeNumber, const int surfaceViewNumber) { bool flatFlag = false; switch (surfaceType) { case SURFACE_TYPE_RAW: case SURFACE_TYPE_FIDUCIAL: case SURFACE_TYPE_INFLATED: case SURFACE_TYPE_VERY_INFLATED: case SURFACE_TYPE_SPHERICAL: case SURFACE_TYPE_ELLIPSOIDAL: case SURFACE_TYPE_COMPRESSED_MEDIAL_WALL: break; case SURFACE_TYPE_FLAT: case SURFACE_TYPE_FLAT_LOBAR: flatFlag = true; break; case SURFACE_TYPE_HULL: case SURFACE_TYPE_UNKNOWN: case SURFACE_TYPE_UNSPECIFIED: break; } const int numNodes = getNumberOfNodes(); if ((nodeNumber > 0) && (nodeNumber < numNodes)) { // // Get the node's coordinate // float vect[3]; coordinates.getCoordinate(nodeNumber, vect); if (flatFlag) { setToStandardView(surfaceViewNumber, VIEW_RESET); setTranslation(surfaceViewNumber, vect); } else { // // Normalize the point // MathUtilities::normalize(vect); // assume a vector goes from the center of gravity in the // positive z direction so it would be something like (0, 0, 1). // The dot product of the positive Z vector and "vect" is just vect[2] // since the x & y components of the vector down positive Z are (0, 0). // The arc-cosine of the dot product is the angle between the // two vectors. const float angle = std::acos(vect[2]) * MathUtilities::radiansToDegrees(); // vector perpendicular (90 degrees ccw) to the vect in X/Y plane double perp[3]; perp[0] = -vect[1]; perp[1] = vect[0]; perp[2] = 0.0; MathUtilities::normalize(perp); // // Create a transformation matrix for the rotation and apply it to the surface // TransformationMatrix tm; tm.rotate(angle, perp); float matrix[16]; tm.getMatrix(matrix); setRotationMatrix(surfaceViewNumber, matrix); } } } /** * compress the front face of a surface. */ void BrainModelSurface::compressFrontFace(const float compressionFactor, const int surfaceViewNumber) { // // Save current rotation matrix // //float matrix[16]; //getRotationMatrix(surfaceViewNumber, matrix); // // Apply the current rotation matrix // TransformationMatrix rot; rot.setMatrix(rotationMatrix[surfaceViewNumber]); rot.rotate(TransformationMatrix::ROTATE_Y_AXIS, 180.0); // backface gets rotated rot.transpose(); // I'm not sure why this works JWH perhaps OpenGL backwards from VTK. applyTransformationMatrix(rot); // // Compress the front face // const SURFACE_TYPES st = getSurfaceType(); convertSphereToCompressedMedialWall(compressionFactor); setSurfaceType(st); // // Apply the current rotation matrix // rot.identity(); rot.rotate(TransformationMatrix::ROTATE_Y_AXIS, 180.0); // backface gets rotated rot.transpose(); // I'm not sure why this works JWH perhaps OpenGL backwards from VTK. applyTransformationMatrix(rot); // // Set to default view // setToStandardView(surfaceViewNumber, BrainModelSurface::VIEW_RESET); // // Apply inverse of rotation matrix // //rot.transpose(); //applyTransformationMatrix(rot); // // Restore rotation matrix // //setRotationMatrix(surfaceViewNumber, matrix); coordinates.clearDisplayList(); } /** * convert a sphere to a compressed medial wall surface. */ void BrainModelSurface::convertSphereToCompressedMedialWall(const float compressionFactor) { const float piDiv2 = M_PI / 2.0; // // Get a topology helper // const TopologyHelper* th = topology->getTopologyHelper(false, true, false); // // get the spherical surface radius // const float radius = getSphericalSurfaceRadius(); // // Compress the sphere's nodes // const int numNodes = getNumberOfNodes(); for (int i = 0; i < numNodes; i++) { float xyz[3] = { 0.0, 0.0, 0.0 }; if (th->getNodeHasNeighbors(i)) { // // Get the coordinate and its distance from the sphere center // coordinates.getCoordinate(i, xyz); // // Normalize the spherical coordinate // const float length = MathUtilities::normalize(xyz); if (length > 0.0) { // // Convert cartesian coordinates to spherical coordinates // double phi = std::acos(xyz[2]); const double theta = std::atan2(xyz[1], xyz[0]); // // Compress the node around the sphere // if (phi < (piDiv2 * compressionFactor)) { phi /= compressionFactor; } else { phi = (phi + M_PI * (1.0 - compressionFactor)) / (2.0 - compressionFactor); } // // Convert spherical coordinates back to cartesian // xyz[0] = radius * std::cos(theta) * std::sin(phi); xyz[1] = radius * std::sin(theta) * std::sin(phi); xyz[2] = radius * std::cos(phi); } } // // Replace the coordinate // coordinates.setCoordinate(i, xyz); } setSurfaceType(SURFACE_TYPE_COMPRESSED_MEDIAL_WALL); appendToCoordinateFileComment("Convert to compressed medial wall with compression factor: "); appendToCoordinateFileComment(StringUtilities::fromNumber(compressionFactor)); appendToCoordinateFileComment("\n"); } /** * Convert a spherical surface to flat. */ void BrainModelSurface::convertSphereToFlat() { const float piDiv2 = M_PI / 2.0; // // Get a topology helper // const TopologyHelper* th = topology->getTopologyHelper(false, true, false); const int numNodes = getNumberOfNodes(); for (int i = 0; i < numNodes; i++) { float x = 0.0, y = 0.0, z = 0.0; if (th->getNodeHasNeighbors(i)) { // // Get the coordinate and its distance from the sphere center // coordinates.getCoordinate(i, x, y, z); const float radius = std::sqrt(x*x + y*y + z*z); if (radius > 0.0) { // // // float zmult = 1.0; if (z <= 0.0) { const float t1 = (z*z) / (radius*radius); zmult = std::pow((1.0 - t1), -0.25); } const float rad = radius * zmult * std::acos(z / radius); float phi; if (fabs(y) > 0.00001) { phi = std::atan(x/y); } else { phi = piDiv2; } const float u = (x / fabs(x)) * rad * fabs(std::sin(phi)); const float v = (y / fabs(y)) * rad * fabs(std::cos(phi)); x = u; y = v; z = 0.0; } } coordinates.setCoordinate(i, x, y, z); } // // set the surface type to a sphere // setSurfaceType(SURFACE_TYPE_FLAT); // // Reset the viewing transformations // resetViewingTransformations(); appendToCoordinateFileComment("Convert Sphere to Flat\n"); // // Surface is cartesian non-standard // coordinates.setHeaderTag(AbstractFile::headerTagCoordFrameID, "CN"); } /** * apply surface shape to a surface (typically a flat or spherical surface). */ void BrainModelSurface::applyShapeToSurface(const SurfaceShapeFile& ssf, const int shapeColumn, const float shapeMultiplier) { // // Make sure shape data valid // const int numNodes = getNumberOfNodes(); if (numNodes != ssf.getNumberOfNodes()) { return; } if ((shapeColumn < 0) || (shapeColumn >= ssf.getNumberOfColumns())) { return; } // // Get radius of sphere // const float radius = getSphericalSurfaceRadius(); // // Apply relief to nodes // for (int i = 0; i < numNodes; i++) { float xyz[3]; coordinates.getCoordinate(i, xyz); const float offset = ssf.getValue(i, shapeColumn) * shapeMultiplier; switch (surfaceType) { case SURFACE_TYPE_RAW: break; case SURFACE_TYPE_FIDUCIAL: break; case SURFACE_TYPE_INFLATED: break; case SURFACE_TYPE_VERY_INFLATED: break; case SURFACE_TYPE_SPHERICAL: if (radius > 0.0) { const float scale = (radius + offset) / radius; xyz[0] *= scale; xyz[1] *= scale; xyz[2] *= scale; } break; case SURFACE_TYPE_ELLIPSOIDAL: break; case SURFACE_TYPE_COMPRESSED_MEDIAL_WALL: break; case SURFACE_TYPE_FLAT: xyz[2] += offset; break; case SURFACE_TYPE_FLAT_LOBAR: xyz[2] += offset; break; case SURFACE_TYPE_HULL: break; case SURFACE_TYPE_UNKNOWN: break; case SURFACE_TYPE_UNSPECIFIED: break; } coordinates.setCoordinate(i, xyz); } // // Update normals // computeNormals(); } /** * inflate the surface */ void BrainModelSurface::inflate(const int smoothingIterations, const int inflationIterations, const float inflationFactorIn) { appendToCoordinateFileComment("Inflated: "); appendToCoordinateFileComment(StringUtilities::fromNumber(smoothingIterations)); appendToCoordinateFileComment(" "); appendToCoordinateFileComment(StringUtilities::fromNumber(inflationIterations)); appendToCoordinateFileComment(" "); appendToCoordinateFileComment(StringUtilities::fromNumber(inflationFactorIn)); appendToCoordinateFileComment("\n"); // // See if a progress dialog should be displayed // QProgressDialog* progressDialog = NULL; QWidget* progressDialogParent = brainSet->getProgressDialogParent(); if (progressDialogParent != NULL) { progressDialog = new QProgressDialog("Inflate Surface", "Cancel", 0, inflationIterations + 1, progressDialogParent); progressDialog->setWindowTitle("Inflate Surface"); progressDialog->setValue(0); progressDialog->show(); } const float inflationFactor = inflationFactorIn; // * 0.01; // // Move center of mass to origin // translateToCenterOfMass(); // // Find node furthest from the origin // const int numNodes = getNumberOfNodes(); float radius = 0.0; for (int i = 0; i < numNodes; i++) { const float* xyz = coordinates.getCoordinate(i); const float dist = xyz[0]*xyz[0] + xyz[1]*xyz[1] + xyz[2]*xyz[2]; radius = std::max(radius, dist); } radius = std::sqrt(radius); // // Get number of smoothing iterations per inflation iterations // const int numSmoothPerInflate = smoothingIterations / inflationIterations; // // Smooth and inflate the surface // for (int iter = 0; iter < inflationIterations; iter++) { // // Set progress dialog // if (progressDialog != NULL) { // // See if progress dialog was cancelled // if (progressDialog->wasCanceled()) { break; } // // update progress dialog // progressDialog->setValue(iter + 1); progressDialog->setLabelText("Inflating"); qApp->processEvents(); // note: qApp is global in QApplication } // // Smooth the surface // arealSmoothing(1.0, numSmoothPerInflate, 0); // // Move center of mass to origin // translateToCenterOfMass(); // // Inflate the surface // for (int i = 0; i < numNodes; i++) { float p[3]; coordinates.getCoordinate(i, p); const double radiusPoint = std::sqrt(p[0]*p[0] + p[1]*p[1] + p[2]*p[2]); double factor = 1.0 + ( (inflationFactor - 1.0) * (1.0 - (radiusPoint / radius)) ); p[0] *= factor; p[1] *= factor; p[2] *= factor; coordinates.setCoordinate(i, p); } } // // Remove progress dialog // if (progressDialog != NULL) { progressDialog->setValue(inflationIterations + 2); delete progressDialog; qApp->processEvents(); // note: qApp is global in QApplication } } /** * Create the inflated and ellipsoid surfaces starting from a fiducial surface. * The inflated and ellipsoid surfaces are added to the brain set. * Use iteration scaling when the surface contains a large number of nodes. * If the surface contains 150,000 nodes, try an iterations scale of 2.5. */ void BrainModelSurface::createInflatedAndEllipsoidFromFiducial(const bool createInflated, const bool createVeryInflated, const bool createEllipsoid, const bool createSphere, const bool createCompressedMedialWall, const bool enableFingerSmoothing, const bool scaleToMatchFiducialArea, const float iterationsScaleIn, MetricFile* metricMeasurementsFileOut, const float compressionFactorIn) const { if ((createInflated == false) && (createVeryInflated == false) && (createEllipsoid == false) && (createSphere == false) && (createCompressedMedialWall == false)) { return; } const int numNodes = getNumberOfNodes(); // // Free surfer surfaces have lots of nodes (150,000) versus Caret (75,000) // so the number of iterations may need to be increased // float iterationScale = 1.0; if (iterationsScaleIn != 0.0) { iterationScale = iterationsScaleIn; } // // Fiducial surface is "this" surface // const BrainModelSurface* fiducialSurface = this; const float fiducialSurfaceArea = fiducialSurface->getSurfaceArea(); // // Copy the surface // BrainModelSurface* lowSmoothSurface = new BrainModelSurface(*fiducialSurface); // // Create the "low smooth" surface // MetricFile metricMeasureFile1; lowSmoothSurface->inflateSurfaceAndSmoothFingers(fiducialSurface, 1, // number of cycles 0.2, // regular smoothing strength static_cast(50 * iterationScale), // regular smoothing iterations 1.0, // inflation factor 3.0, // finger compress/stretch threshold 1.0, // finger smoothing strength 0, // finger smoothing iterations &metricMeasureFile1); if (DebugControl::getDebugOn()) { if (metricMeasurementsFileOut != NULL) { metricMeasurementsFileOut->append(metricMeasureFile1); } } // // Find the "gaussian_neg" column // int lowSmoothGaussNegColumn = -1; //if (metricMeasureFile1 != NULL) { lowSmoothGaussNegColumn = metricMeasureFile1.getColumnWithName("gaussian_neg"); //} // // High smooth and low smooth metric files // MetricFile highSmoothMetric; MetricFile lowSmoothMetric; MetricFile compStretchMetric; // // Get the gaussian neg for the low smooth // if (lowSmoothGaussNegColumn >= 0) { lowSmoothMetric.setNumberOfNodesAndColumns(numNodes, 1); lowSmoothMetric.setColumnName(0, "gaussian_neg.LowSmooth"); for (int i = 0; i < numNodes; i++) { lowSmoothMetric.setValue(i, 0, metricMeasureFile1.getValue(i, lowSmoothGaussNegColumn)); } } // // Copy the surface // BrainModelSurface* inflatedSurface = new BrainModelSurface(*lowSmoothSurface); inflatedSurface->setSurfaceType(BrainModelSurface::SURFACE_TYPE_INFLATED); if (createInflated) { CoordinateFile* cf = inflatedSurface->getCoordinateFile(); cf->makeDefaultFileName(inflatedSurface->getSurfaceTypeName()); brainSet->addBrainModel(inflatedSurface); } // // Create the inflated surface // int fingerSmoothingIterations = 0; if (enableFingerSmoothing) { fingerSmoothingIterations = static_cast(30 * iterationScale); } MetricFile metricMeasureFile2; inflatedSurface->inflateSurfaceAndSmoothFingers(fiducialSurface, 2, // number of cycles 1.0, // regular smoothing strength static_cast(30 * iterationScale), // regular smoothing iterations 1.4, // inflation factor 3.0, // finger compress/stretch threshold 1.0, // finger smoothing strength fingerSmoothingIterations, &metricMeasureFile2); if (scaleToMatchFiducialArea) { inflatedSurface->scaleSurfaceToArea(fiducialSurfaceArea, false); } // // If the very inflated surface should be created // if (createVeryInflated) { // // Copy the surface // BrainModelSurface* veryInflatedSurface = new BrainModelSurface(*inflatedSurface); veryInflatedSurface->setSurfaceType(BrainModelSurface::SURFACE_TYPE_VERY_INFLATED); CoordinateFile* cf = veryInflatedSurface->getCoordinateFile(); cf->makeDefaultFileName(veryInflatedSurface->getSurfaceTypeName()); brainSet->addBrainModel(veryInflatedSurface); // // Create the very inflated surface // MetricFile metricMeasureFile3; veryInflatedSurface->inflateSurfaceAndSmoothFingers(fiducialSurface, 4, // number of cycles 1.0, // regular smoothing strength static_cast(30 * iterationScale), // regular smoothing iterations 1.1, // inflation factor 3.0, // finger compress/stretch threshold 1.0, // finger smoothing strength 0, // finger smoothing iterations &metricMeasureFile3); if (scaleToMatchFiducialArea) { veryInflatedSurface->scaleSurfaceToArea(fiducialSurfaceArea, false); } } // // If the ellipsoid should be created // BrainModelSurface* highSmoothSurface = NULL; BrainModelSurface* ellipsoidSurface = NULL; if (createEllipsoid || createSphere || createCompressedMedialWall) { // // Copy the surface // highSmoothSurface = new BrainModelSurface(*inflatedSurface); // // Create the high smooth surface // int fingerSmoothingIterations = 0; if (enableFingerSmoothing) { fingerSmoothingIterations = static_cast(60 * iterationScale); } MetricFile metricMeasureFile4; highSmoothSurface->inflateSurfaceAndSmoothFingers(fiducialSurface, 6, // number of cycles 1.0, // regular smoothing strength static_cast(60 * iterationScale), // regular smoothing iterations 1.6, // inflation factor 3.0, // finger compress/stretch threshold 1.0, // finger smoothing strength fingerSmoothingIterations, // finger smoothing iterations &metricMeasureFile4); // // Find the "compressed" column // int highSmoothedCompressedColumn = -1; //if (metricMeasurementsFile != NULL) { highSmoothedCompressedColumn = metricMeasureFile4.getColumnWithName("compressed"); //} // // Get the compressed for the high smooth // if (highSmoothedCompressedColumn >= 0) { highSmoothMetric.setNumberOfNodesAndColumns(numNodes, 1); highSmoothMetric.setColumnName(0, "compressed.HighSmooth"); for (int i = 0; i < numNodes; i++) { highSmoothMetric.setValue(i, 0, metricMeasureFile4.getValue(i, highSmoothedCompressedColumn)); } } // // Copy the surface // ellipsoidSurface = new BrainModelSurface(*highSmoothSurface); ellipsoidSurface->setSurfaceType(BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL); if (createEllipsoid) { CoordinateFile* cf = ellipsoidSurface->getCoordinateFile(); cf->makeDefaultFileName(ellipsoidSurface->getSurfaceTypeName()); brainSet->addBrainModel(ellipsoidSurface); } // // Create the ellipsoid surface // MetricFile metricMeasureFile5; ellipsoidSurface->inflateSurfaceAndSmoothFingers(fiducialSurface, 6, // number of cycles 1.0, // regular smoothing strength static_cast(50 * iterationScale), // regular smoothing iterations 1.4, // inflation factor 4.0, // finger compress/stretch threshold 1.0, // finger smoothing strength fingerSmoothingIterations, // finger smoothing iterations &metricMeasureFile5); if (scaleToMatchFiducialArea) { ellipsoidSurface->scaleSurfaceToArea(fiducialSurfaceArea, false); } // // Find the "average_cosi" column // int averageCosiColumn = -1; //if (metricMeasurementsFile != NULL) { averageCosiColumn = metricMeasureFile5.getColumnWithName("average_cosi"); //} // // Get the compressed for the high smooth // if (averageCosiColumn >= 0) { compStretchMetric.setNumberOfNodesAndColumns(numNodes, 1); compStretchMetric.setColumnName(0, "Ellipsoid_CompressedOrStretched"); for (int i = 0; i < numNodes; i++) { compStretchMetric.setValue(i, 0, metricMeasureFile5.getValue(i, averageCosiColumn)); } } } BrainModelSurface* sphereSurface = NULL; if (createSphere || createCompressedMedialWall) { // // Copy the surface // sphereSurface = new BrainModelSurface(*ellipsoidSurface); sphereSurface->setSurfaceType(BrainModelSurface::SURFACE_TYPE_SPHERICAL); sphereSurface->convertEllipsoidToSphereWithSurfaceArea(fiducialSurfaceArea); CoordinateFile* cf = sphereSurface->getCoordinateFile(); cf->makeDefaultFileName(sphereSurface->getSurfaceTypeName()); if (createSphere) { brainSet->addBrainModel(sphereSurface); } } if (createCompressedMedialWall) { // // Copy the surface // BrainModelSurface* cmwSurface = new BrainModelSurface(*sphereSurface); cmwSurface->setSurfaceType(BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL); CoordinateFile* cf = cmwSurface->getCoordinateFile(); cf->makeDefaultFileName(cmwSurface->getSurfaceTypeName()); cmwSurface->setToStandardView(0, VIEW_MEDIAL); cmwSurface->applyCurrentView(0, true, true, true); TransformationMatrix tm; tm.rotate(TransformationMatrix::ROTATE_X_AXIS, -27.0); cmwSurface->applyTransformationMatrix(tm); cmwSurface->convertSphereToCompressedMedialWall(compressionFactorIn); //0.95); //0.85); cmwSurface->projectCoordinatesToPlane( BrainModelSurface::COORDINATE_PLANE_MOVE_POSITIVE_Z_TO_ZERO); cmwSurface->computeNormals(); brainSet->addBrainModel(cmwSurface); } delete lowSmoothSurface; if (highSmoothSurface != NULL) { delete highSmoothSurface; } if (ellipsoidSurface != NULL) { if (createEllipsoid == false) { delete ellipsoidSurface; } } if (sphereSurface != NULL) { if (createSphere == false) { delete sphereSurface; } } if (createInflated == false) { delete inflatedSurface; } if (metricMeasurementsFileOut != NULL) { if (lowSmoothMetric.getNumberOfColumns() > 0) { metricMeasurementsFileOut->append(lowSmoothMetric); } if (highSmoothMetric.getNumberOfColumns() > 0) { metricMeasurementsFileOut->append(highSmoothMetric); } if (compStretchMetric.getNumberOfColumns() > 0) { metricMeasurementsFileOut->append(compStretchMetric); } } } /** * Inflate surface and smooth fingers */ void BrainModelSurface::inflateSurfaceAndSmoothFingers(const BrainModelSurface* fiducialSurfaceIn, const int numberSmoothingCycles, const float regularSmoothingStrength, const int regularSmoothingIterations, const float inflationFactorIn, const float compressStretchThreshold, const float fingerSmoothingStrength, const int fingerSmoothingIterations, MetricFile* metricMeasurementsFile) { if (fiducialSurfaceIn == NULL) { std::cout << "ERROR: BrainModelSurface::inflateSurfaceAndSmoothFingers - No fiducial surface as input." << std::endl; return; } const int numNodes = getNumberOfNodes(); if (numNodes <= 0) { return; } appendToCoordinateFileComment("Inflate Surface and Smooth Fingers: "); appendToCoordinateFileComment(StringUtilities::fromNumber(numberSmoothingCycles)); appendToCoordinateFileComment(" "); appendToCoordinateFileComment(StringUtilities::fromNumber(regularSmoothingStrength)); appendToCoordinateFileComment(" "); appendToCoordinateFileComment(StringUtilities::fromNumber(regularSmoothingIterations)); appendToCoordinateFileComment(" "); appendToCoordinateFileComment(StringUtilities::fromNumber(inflationFactorIn)); appendToCoordinateFileComment(" "); appendToCoordinateFileComment(StringUtilities::fromNumber(compressStretchThreshold)); appendToCoordinateFileComment(" "); appendToCoordinateFileComment(StringUtilities::fromNumber(fingerSmoothingStrength)); appendToCoordinateFileComment(" "); appendToCoordinateFileComment(StringUtilities::fromNumber(fingerSmoothingIterations)); appendToCoordinateFileComment("\n"); const float inflationFactor = inflationFactorIn - 1.0; QTime timer; timer.start(); // // Copy the fiducial surface since it will be modified (translated to center of mass) // BrainModelSurface* fiducialSurface = new BrainModelSurface(*fiducialSurfaceIn); // // Step 2: Translate AUX coord origin to center of gravity // Caret Menu: Operate->Surface Translation->Translate To Center of Mass translateToCenterOfMass(); // // Translate the fiducial to center of mass // fiducialSurface->translateToCenterOfMass(); // // Get bounds of fiducial surface // float fiducialBounds[6]; fiducialSurface->getBounds(fiducialBounds); const float xdiff = fiducialBounds[1] - fiducialBounds[0]; const float ydiff = fiducialBounds[3] - fiducialBounds[2]; const float zdiff = fiducialBounds[5] - fiducialBounds[4]; // // Step 5: Calculate surface area of fiducial surface // const float fiducialSurfaceArea = fiducialSurface->getSurfaceArea(); //float* arealCompression = new float[numNodes]; float* averageCompressedStretched = new float[numNodes]; float* maximumLinearDistortion = new float[numNodes]; float* averageArealCompression = new float[numNodes]; float* compressedStretched = new float[numNodes]; float* stretching = new float[numNodes]; float surfaceAreaRatio = 0.0; // // The surface's coordinates // CoordinateFile* surfaceCoords = getCoordinateFile(); const float* surfacePos = surfaceCoords->getCoordinate(0); const CoordinateFile* fiducialCoords = fiducialSurface->getCoordinateFile(); const float* fiducialPos = fiducialCoords->getCoordinate(0); // // Step 6: Main Smoothing Cycle // Note: No smoothing takes place in the "+1" cycle, just metric calculation // for (int cycles = 0; cycles < (numberSmoothingCycles + 1); cycles++) { if (cycles < numberSmoothingCycles) { // // Step 6a: Apply Smoothing to AUX coord // Caret Menu: Operate->Smoothing->Smoothing... // arealSmoothing(regularSmoothingStrength, regularSmoothingIterations, 1); // // Step 6b: Incrementally Inflate AUX Surface by Ellipsoidal Projection // for (int i = 0; i < numNodes; i++) { float xyz[3]; surfaceCoords->getCoordinate(i, xyz); const float x = xyz[0] / xdiff; const float y = xyz[1] / ydiff; const float z = xyz[2] / zdiff; const float r = std::sqrt(x*x + y*y + z*z); const float k = 1.0 + inflationFactor * (1.0 - r); xyz[0] *= k; xyz[1] *= k; xyz[2] *= k; surfaceCoords->setCoordinate(i, xyz); } } // Step 6c: Calculate surface area of this surface const float inflatedSurfaceArea = getSurfaceArea(); // // Ratio of inflated and spherical surfaces // surfaceAreaRatio = inflatedSurfaceArea / fiducialSurfaceArea; // // Topology helper for neighbors // const TopologyHelper* th = getTopologyFile()->getTopologyHelper(false, true, false); // // Step 6d: Calculate compress/stretched value for each node // for (int i = 0; i < numNodes; i++) { // // Get position of node in both this and fiducial surface // //float nodePos[3]; //surfaceCoords->getCoordinate(i, nodePos); const float* nodePos = &surfacePos[i * 3]; //float nodeFiducialPos[3]; //fiducialCoords->getCoordinate(i, nodeFiducialPos); const float* nodeFiducialPos = &fiducialPos[i * 3]; maximumLinearDistortion[i] = 0.0; //arealCompression[i] = 0.0; averageArealCompression[i] = 0.0; //float tileArea = 0.0; //float fiducialTileArea = 0.0; float numValidNeighbors = 0; // // Get neighbors for this node // int numNeighbors; const int* neighbors = th->getNodeNeighbors(i, numNeighbors); // // log(2.0) to avoid recomputation each iteration // //const double log2 = log(2.0); // // Loop through the neighbors // for (int j = 0; j < numNeighbors; j++) { const int neighbor = neighbors[j]; //const float* neighPos = surfaceCoords->getCoordinate(neighbor); const float* neighPos = &surfacePos[neighbor * 3]; //const float* neighFiducialPos = fiducialCoords->getCoordinate(neighbor); const float* neighFiducialPos = &fiducialPos[neighbor * 3]; // // calculate maximum linear distortion on aux and ref surface // float dx = neighPos[0] - nodePos[0]; float dy = neighPos[1] - nodePos[1]; float dz = neighPos[2] - nodePos[2]; float dist = std::sqrt(dx*dx + dy*dy + dz*dz); dx = neighFiducialPos[0] - nodeFiducialPos[0]; dy = neighFiducialPos[1] - nodeFiducialPos[1]; dz = neighFiducialPos[2] - nodeFiducialPos[2]; float fiducialDist = std::sqrt(dx*dx + dy*dy + dz*dz); if (fiducialDist > 0.0) { const float ratio = dist / fiducialDist; if (ratio > maximumLinearDistortion[i]) { maximumLinearDistortion[i] = ratio; } } // // Next neighbor // int jNext = j + 1; if (jNext >= numNeighbors) { jNext = 0; } const int nextNeighbor = neighbors[jNext]; // // compute area of tiles on aux and ref surfaces // //3/4/05 tileArea += getTileArea(i, neighbor, nextNeighbor); //3/4/05 fiducialTileArea = fiducialSurface->getTileArea(i, neighbor, nextNeighbor); const float tileArea = getTileArea(i, neighbor, nextNeighbor); const float fiducialTileArea = fiducialSurface->getTileArea(i, neighbor, nextNeighbor); // // average areal compression of tiles associated with node // float distort = 0.0; if (tileArea > 0.0) { distort = fiducialTileArea / tileArea; } else { if (fiducialTileArea != 0.0) { distort = 10000.0; // big dist since denominator zero } else { distort = 1.0; // if both zero then use assume same area } } // // Zero will cause -inf // if (distort < 0.00000001) { distort = 0.00000001; } averageArealCompression[i] += distort; //arealCompression[i] += distort; //log(distort) / log2; numValidNeighbors += 1.0; } if (numValidNeighbors > 0) { //arealCompression[i] /= numValidNeighbors; averageArealCompression[i] /= numValidNeighbors; } // // compressed/stretched for node // compressedStretched[i] = maximumLinearDistortion[i] * averageArealCompression[i] //arealCompression[i] * surfaceAreaRatio; // // stretching for node // stretching[i] = maximumLinearDistortion[i] * std::sqrt(averageArealCompression[i] //arealCompression[i] * surfaceAreaRatio); } // // average compressed/stretched for all nodes by averaging with neighbors // for (int i = 0; i < numNodes; i++) { averageCompressedStretched[i] = compressedStretched[i]; if (DebugControl::getDebugOn()) { if ((i % 1000) == 0) { std::cout << "comp-stretch " << i << " " << compressedStretched[i] << std::endl; } } int numNeighbors; const int* neighbors = th->getNodeNeighbors(i, numNeighbors); if (numNeighbors > 0) { for (int j = 0; j < numNeighbors; j++) { const int n = neighbors[j]; averageCompressedStretched[i] += compressedStretched[n]; } averageCompressedStretched[i] /= ((float)(numNeighbors + 1)); } } // // average areal compression for all nodes by averaging with neighbors // /* for (int i = 0; i < numNodes; i++) { averageArealCompression[i] = arealCompression[i]; int numNeighbors; const int* neighbors = th->getNodeNeighbors(i, numNeighbors); if (numNeighbors > 0) { for (int j = 0; j < numNeighbors; j++) { const int n = neighbors[j]; averageArealCompression[i] += arealCompression[n]; } averageArealCompression[i] /= ((float)(numNeighbors + 1)); } } */ // // Step 6e: Flag highly compressed/stretched nodes for targeted smoothing // int numDistortionAboveThreshold = 0; float maxDistortion = -std::numeric_limits::max(); float minDistortion = std::numeric_limits::max(); std::vector needSmoothing(numNodes); for (int i = 0; i < numNodes; i++) { if (averageCompressedStretched[i] > compressStretchThreshold) { numDistortionAboveThreshold++; needSmoothing[i] = true; } else { needSmoothing[i] = false; } if (averageCompressedStretched[i] > maxDistortion) { maxDistortion = averageCompressedStretched[i]; } if (averageCompressedStretched[i] < minDistortion) { minDistortion = averageCompressedStretched[i]; } } if (DebugControl::getDebugOn()) { std::cout << "Distortion Info:" << endl; std::cout << " " << numDistortionAboveThreshold << " of " << numNodes << " points are above " << "threshold = " << compressStretchThreshold << endl; std::cout << " minimum distortion: " << minDistortion << endl; std::cout << " maximum distortion: " << maxDistortion << endl; } if (cycles < numberSmoothingCycles) { // // Step 6f: Targeted smoothing // arealSmoothing(fingerSmoothingStrength, fingerSmoothingIterations, 1, &needSmoothing); } } computeNormals(); // // If metrics should be created // if (metricMeasurementsFile != NULL) { // // Column names // const QString averageCosiColumnName("average_cosi"); const QString compressedColumnName("compressed"); const QString stretchedColumnName("stretched"); const QString gaussianNegColumnName("gaussian_neg"); // // See if columns exist // int averageCosiColumn = metricMeasurementsFile->getColumnWithName(averageCosiColumnName); int compressedColumn = metricMeasurementsFile->getColumnWithName(compressedColumnName); int stretchedColumn = metricMeasurementsFile->getColumnWithName(stretchedColumnName); int gaussianNegColumn = metricMeasurementsFile->getColumnWithName(gaussianNegColumnName); // // Determine how many new columns are needed // int newColumnsNeeded = 0; if (averageCosiColumn < 0) newColumnsNeeded++; if (compressedColumn < 0) newColumnsNeeded++; if (stretchedColumn < 0) newColumnsNeeded++; if (gaussianNegColumn < 0) newColumnsNeeded++; // // Add columns to the metric file // if (newColumnsNeeded > 0) { if (metricMeasurementsFile->getNumberOfColumns() == 0) { metricMeasurementsFile->setNumberOfNodesAndColumns(numNodes, newColumnsNeeded); } else { metricMeasurementsFile->addColumns(newColumnsNeeded); } } // // Get the column numbers for the new data // int newCnt = 1; if (gaussianNegColumn < 0) { gaussianNegColumn = metricMeasurementsFile->getNumberOfColumns() - newCnt; newCnt++; } if (stretchedColumn < 0) { stretchedColumn = metricMeasurementsFile->getNumberOfColumns() - newCnt; newCnt++; } if (compressedColumn < 0) { compressedColumn = metricMeasurementsFile->getNumberOfColumns() - newCnt; newCnt++; } if (averageCosiColumn < 0) { averageCosiColumn = metricMeasurementsFile->getNumberOfColumns() - newCnt; newCnt++; } // // Name the columns // metricMeasurementsFile->setColumnName(averageCosiColumn, averageCosiColumnName); metricMeasurementsFile->setColumnName(compressedColumn, compressedColumnName); metricMeasurementsFile->setColumnName(stretchedColumn, stretchedColumnName); metricMeasurementsFile->setColumnName(gaussianNegColumn, gaussianNegColumnName); // // Set the average cosi column // for (int i = 0; i < numNodes; i++) { metricMeasurementsFile->setValue(i, averageCosiColumn, averageCompressedStretched[i]); metricMeasurementsFile->setValue(i, compressedColumn, averageArealCompression[i] * surfaceAreaRatio); metricMeasurementsFile->setValue(i, stretchedColumn, stretching[i]); } // // Compute gaussian curvature // SurfaceShapeFile ssf; const QString gaussColumnName("gauss"); BrainModelSurfaceCurvature bmss(brainSet, this, &ssf, BrainModelSurfaceCurvature::CURVATURE_COLUMN_DO_NOT_GENERATE, BrainModelSurfaceCurvature::CURVATURE_COLUMN_CREATE_NEW, "", gaussColumnName); float* tempArray = new float[numNodes]; for (int i = 0; i < numNodes; i++) { tempArray[i] = 0.0; //-1.0; // was 0.0 3/3/05 } try { // // Generate curvature // bmss.execute(); // // Compute negative gaussian curvature // const int gaussColumn = ssf.getColumnWithName(gaussColumnName); if (gaussColumn >= 0) { for (int i = 0; i < numNodes; i++) { const float gauss = ssf.getValue(i, gaussColumn); if ((gauss < 0.0) && (averageArealCompression[i] > 0.0)) { tempArray[i] = -gauss; tempArray[i] *= averageArealCompression[i]; } } } } catch (BrainModelAlgorithmException&) { // curvature calculation failed } for (int i = 0; i < numNodes; i++) { metricMeasurementsFile->setValue(i, gaussianNegColumn, tempArray[i]); } // // Log 10 scale the values // metricMeasurementsFile->scaleColumnLog10(averageCosiColumn); metricMeasurementsFile->scaleColumnLog10(compressedColumn); metricMeasurementsFile->scaleColumnLog10(stretchedColumn); metricMeasurementsFile->scaleColumnLog10(gaussianNegColumn); delete[] tempArray; } delete fiducialSurface; //delete[] arealCompression; delete[] averageCompressedStretched; delete[] maximumLinearDistortion; delete[] averageArealCompression; delete[] compressedStretched; delete[] stretching; if (DebugControl::getDebugOn()) { std::cout << "Total time: " << (static_cast(timer.elapsed()) / 1000.0) << std::endl; } } /** * translate a surface to its center of mass. */ void BrainModelSurface::translateToCenterOfMass() { // appendToCoordinateFileComment("Translate to Center of Mass"); float com[3]; getCenterOfMass(com); TransformationMatrix tm; tm.translate(-com[0], -com[1], -com[2]); applyTransformationMatrix(tm); coordinates.clearDisplayList(); } /** * Get the center of mass for a surface. */ void BrainModelSurface::getCenterOfMass(float centerOfMass[3]) const { const TopologyFile* tf = getTopologyFile(); const TopologyHelper* th = tf->getTopologyHelper(false, true, false); const int numNodes = getNumberOfNodes(); double cx = 0.0, cy = 0.0, cz = 0.0; float numNodesWithNeighbors = 0.0; for (int i = 0; i < numNodes; i++) { if (th->getNodeHasNeighbors(i)) { const float* xyz = coordinates.getCoordinate(i); cx += xyz[0]; cy += xyz[1]; cz += xyz[2]; numNodesWithNeighbors += 1.0; } } if (numNodesWithNeighbors > 0.0) { centerOfMass[0] = cx / numNodesWithNeighbors; centerOfMass[1] = cy / numNodesWithNeighbors; centerOfMass[2] = cz / numNodesWithNeighbors; } else { centerOfMass[0] = 0.0; centerOfMass[1] = 0.0; centerOfMass[2] = 0.0; } } /** * Get the radius of a spherical surface (assumes surface is a sphere * with its center at the origin). */ float BrainModelSurface::getSphericalSurfaceRadius() const { const int numNodes = getNumberOfNodes(); const TopologyHelper* helper = topology->getTopologyHelper(false, true, false); for (int i = 0; i < numNodes; i++) { float p[3]; if (helper->getNodeHasNeighbors(i)) { coordinates.getCoordinate(i, p); const float radius = std::sqrt(p[0]*p[0] + p[1]*p[1] + p[2]*p[2]); return radius; } } return 0.0; } /** * Orient a spherical surface so that a group of nodes identified by paint are placed * on the negative Z axis. Returns true if matching nodes are NOT found. */ bool BrainModelSurface::orientPaintedNodesToNegativeZAxis(const PaintFile* pf, const std::vector paintNames, const int paintColumn, QString& errorMessage) { errorMessage = ""; // // Make sure paint column is valid // if ((paintColumn < 0) && (paintColumn >= pf->getNumberOfColumns())) { errorMessage = "Paint column number is invalid."; return false; } // // convert paint names into paint indices // std::vector paintIndices; for (int i = 0; i < static_cast(paintNames.size()); i++) { const int index = pf->getPaintIndexFromName(paintNames[i]); if (index >= 0) { paintIndices.push_back(index); } } if (paintIndices.size() == 0) { std::ostringstream str; str << "Paint names ("; for (unsigned int i = 0; i < paintNames.size(); i++) { if (i > 0) { str << ", "; } str << paintNames[i].toAscii().constData(); } str << ") needed" << "\n"; str << "for orienting the surface were not found."; errorMessage = str.str().c_str(); return true; } // // find the center of gravity of the painted nodes // double sumCOG[3] = { 0.0, 0.0, 0.0 }; const int numNodes = getNumberOfNodes(); float numMatchingNodes = 0.0; for (int i = 0; i < numNodes; i++) { const float* xyz = coordinates.getCoordinate(i); const int paintIndex = pf->getPaint(i, paintColumn); if (std::find(paintIndices.begin(), paintIndices.end(), paintIndex) != paintIndices.end()) { sumCOG[0] += xyz[0]; sumCOG[1] += xyz[1]; sumCOG[2] += xyz[2]; numMatchingNodes += 1.0; } } // // Make sure nodes were found // if (numMatchingNodes == 0.0) { errorMessage = "No matching paint names found:"; for (int i = 0; i < static_cast(paintNames.size()); i++) { errorMessage.append(" "); errorMessage.append(paintNames[i]); } return true; } // // Place the center of gravity of the matching nodes on the negative Z axis // const float cog[3] = { (sumCOG[0] / numMatchingNodes), (sumCOG[1] / numMatchingNodes), (sumCOG[2] / numMatchingNodes) }; orientPointToNegativeZAxis(cog); return false; } /** * Orient a sphere so that the point is placed on the negative Z axis. * Assumes that the surface is center is at the origin. */ void BrainModelSurface::orientPointToNegativeZAxis(const float pIn[3]) { float vect[3] = { pIn[0], pIn[1], pIn[2] }; // // Normalize the point // MathUtilities::normalize(vect); // assume a vector goes from the center of gravity in the // negative z direction so it would be something like (0, 0, -1). // The dot product of the negative Z vector and "vect" is just -vect[2] // since the x & y components of the vector down negative Z are (0, 0). // The arc-cosine of the dot product is the angle between the // two vectors. const float angle = std::acos(-vect[2]) * MathUtilities::radiansToDegrees(); // vector perpendicular (90 degrees ccw) to the vect in X/Y plane double perp[3]; perp[0] = -vect[1]; perp[1] = vect[0]; perp[2] = 0.0; MathUtilities::normalize(perp); // // Create a transformation matrix for the rotation and apply it to the surface // TransformationMatrix tm; tm.rotate(angle, perp); applyTransformationMatrix(tm); coordinates.clearDisplayList(); } /** * orient a sphere so that the point is placed on the positive Z axis. */ void BrainModelSurface::orientPointToPositiveZAxis(const float p[3]) { // // Put on negative Z // orientPointToNegativeZAxis(p); // // Rotate 180 about Y so point on positive Z-Axis // TransformationMatrix tm; tm.rotate(TransformationMatrix::ROTATE_Y_AXIS, 180.0); applyTransformationMatrix(tm); } /** * push (save) the coordinates */ void BrainModelSurface::pushCoordinates() { pushPopCoordinates.clear(); const int numNodes = getNumberOfNodes(); for (int i = 0; i < numNodes; i++) { float x, y, z; coordinates.getCoordinate(i, x, y, z); pushPopCoordinates.push_back(x); pushPopCoordinates.push_back(y); pushPopCoordinates.push_back(z); } } /** * pop (restore) the coordinates (must have done a push prior to this call) */ void BrainModelSurface::popCoordinates() { const int numNodes = getNumberOfNodes(); if (numNodes == static_cast(pushPopCoordinates.size() / 3)) { for (int i = 0; i < numNodes; i++) { coordinates.setCoordinate(i, &pushPopCoordinates[i*3]); } } else { std::cout << "Number of nodes incorrect in BrainModelSurface::popCoordinates() at " << __LINE__ << " in " << __FILE__ << std::endl; } coordinates.clearDisplayList(); } /** * project the coordinates to a plane */ void BrainModelSurface::projectCoordinatesToPlane(const COORDINATE_PLANE plane) { const unsigned long modFlag = coordinates.getModified(); switch (plane) { case COORDINATE_PLANE_NONE: break; case COORDINATE_PLANE_MOVE_POSITIVE_X_TO_ZERO: case COORDINATE_PLANE_MOVE_NEGATIVE_X_TO_ZERO: case COORDINATE_PLANE_MOVE_POSITIVE_Y_TO_ZERO: case COORDINATE_PLANE_MOVE_NEGATIVE_Y_TO_ZERO: case COORDINATE_PLANE_MOVE_POSITIVE_Z_TO_ZERO: case COORDINATE_PLANE_MOVE_NEGATIVE_Z_TO_ZERO: { pushCoordinates(); const int numNodes = getNumberOfNodes(); for (int i = 0; i < numNodes; i++) { float x, y, z; coordinates.getCoordinate(i, x, y, z); switch (plane) { case COORDINATE_PLANE_NONE: break; case COORDINATE_PLANE_MOVE_POSITIVE_X_TO_ZERO: x = std::min(x, 0.0f); break; case COORDINATE_PLANE_MOVE_NEGATIVE_X_TO_ZERO: x = std::max(x, 0.0f); break; case COORDINATE_PLANE_MOVE_POSITIVE_Y_TO_ZERO: y = std::min(y, 0.0f); break; case COORDINATE_PLANE_MOVE_NEGATIVE_Y_TO_ZERO: y = std::max(y, 0.0f); break; case COORDINATE_PLANE_MOVE_POSITIVE_Z_TO_ZERO: z = std::min(z, 0.0f); break; case COORDINATE_PLANE_MOVE_NEGATIVE_Z_TO_ZERO: z = std::max(z, 0.0f); break; case COORDINATE_PLANE_RESTORE: break; } coordinates.setCoordinate(i, x, y, z); } } break; case COORDINATE_PLANE_RESTORE: popCoordinates(); break; } /* const int numNodes = getNumberOfNodes(); switch (plane) { case COORDINATE_PLANE_MOVE_POSITIVE_Z_TO_ZERO: pushCoordinates(); for (int i = 0; i < numNodes; i++) { float x, y, z; coordinates.getCoordinate(i, x, y, z); if (z > 0.0) { z = 0.0; coordinates.setCoordinate(i, x, y, z); } } break; case COORDINATE_PLANE_MOVE_NEGATIVE_Z_TO_ZERO: pushCoordinates(); for (int i = 0; i < numNodes; i++) { float x, y, z; coordinates.getCoordinate(i, x, y, z); if (z < 0.0) { z = 0.0; coordinates.setCoordinate(i, x, y, z); } } break; case COORDINATE_PLANE_RESTORE: popCoordinates(); break; } */ coordinates.setModifiedCounter(modFlag); } /** * Align to standard orientation (flat or spherical). */ void BrainModelSurface::alignToStandardOrientation(const BrainModelSurface* fiducialSurface, const BorderProjection* centralSulcusBorderProjection, const bool generateSphericalLatitudeLongitude, const bool scaleToFiducialArea) { if (fiducialSurface == NULL) { return; } if (centralSulcusBorderProjection == NULL) { return; } // // Unproject the central sulcus border to the fiducial surface // const CoordinateFile* fiducialCoordinateFile = fiducialSurface->getCoordinateFile(); Border centralSulcusBorder; centralSulcusBorderProjection->unprojectBorderProjection( fiducialCoordinateFile, getTopologyFile()->getTopologyHelper(false, true, false), centralSulcusBorder); const int numLinks = centralSulcusBorder.getNumberOfLinks(); if (numLinks < 2) { return; } // // Get position of first link on the FIDUCIAL surface // const float* firstLinkXYZ = centralSulcusBorder.getLinkXYZ(0); // // Get position of last link on the FIDUCIAL surface // const float* lastLinkXYZ = centralSulcusBorder.getLinkXYZ(numLinks - 1); // // Determine ventral and dorsal ends of central sulcus // int ventralNodeNumber = fiducialCoordinateFile->getCoordinateIndexClosestToPoint(firstLinkXYZ); int dorsalNodeNumber = fiducialCoordinateFile->getCoordinateIndexClosestToPoint(lastLinkXYZ); if (firstLinkXYZ[2] > lastLinkXYZ[2]) { std::swap(ventralNodeNumber, dorsalNodeNumber); } // // Align the surface // alignToStandardOrientation(ventralNodeNumber, dorsalNodeNumber, generateSphericalLatitudeLongitude, scaleToFiducialArea); } /** * Align to standard orientation (flat or spherical). */ void BrainModelSurface::alignToStandardOrientation(const int ventralTipCentralSulcusNode, const int dorsalMedialTipCentralSulcusNode, const bool generateSphericalLatitudeLongitude, const bool scaleToFiducialArea) { if ((ventralTipCentralSulcusNode >= 0) && (dorsalMedialTipCentralSulcusNode >= 0)) { const double leftHemAngleFromVertical = 75.0; const double rightHemAngleFromVertical = 105; // // Aligning flat surface // if ((getSurfaceType() == SURFACE_TYPE_FLAT) || (getSurfaceType() == SURFACE_TYPE_FLAT_LOBAR)) { // // Position of medial and ventral tip nodes // const float* ventralTipPos = coordinates.getCoordinate(ventralTipCentralSulcusNode); const float* medialTipPos = coordinates.getCoordinate(dorsalMedialTipCentralSulcusNode); // // angle from ventral tip to medial tip in degrees // const double dx = medialTipPos[0] - ventralTipPos[0]; const double dy = medialTipPos[1] - ventralTipPos[1]; const double angle = std::atan2(dy, dx) * MathUtilities::radiansToDegrees(); // // Set rotation angle appropriate for hemisphere // float rotateAngle; if (structure.getType() == Structure::STRUCTURE_TYPE_CORTEX_LEFT) { rotateAngle = leftHemAngleFromVertical - angle; } else { rotateAngle = rightHemAngleFromVertical - angle; } // // Transform the surface // TransformationMatrix tm; tm.translate(-ventralTipPos[0], -ventralTipPos[1], 0.0f); applyTransformationMatrix(tm); const float* transVentralTipPos = coordinates.getCoordinate(ventralTipCentralSulcusNode); tm.identity(); tm.rotate(TransformationMatrix::ROTATE_Z_AXIS, rotateAngle); applyTransformationMatrix(tm); if (DebugControl::getDebugOn()) { std::cout << "Surface Alignment: " << std::endl; std::cout << " Ventral Node: " << ventralTipCentralSulcusNode << std::endl; std::cout << " Ventral Pos: " << ventralTipPos[0] << " " << ventralTipPos[1] << " " << ventralTipPos[2] << std::endl; std::cout << " Dorsal Node: " << dorsalMedialTipCentralSulcusNode << std::endl; std::cout << " Dorsal Pos: " << medialTipPos[0] << " " << medialTipPos[1] << " " << medialTipPos[2] << std::endl; std::cout << " Rotate Angle: " << rotateAngle << std::endl; std::cout << " Ventral Pos After Translate: " << transVentralTipPos[0] << " " << transVentralTipPos[1] << " " << transVentralTipPos[2] << std::endl; const float* newVentralTipPos = coordinates.getCoordinate(ventralTipCentralSulcusNode); std::cout << " Ventral Pos After Rotate: " << newVentralTipPos[0] << " " << newVentralTipPos[1] << " " << newVentralTipPos[2] << std::endl; } // // If surface should be scaled to match the area of the fiducial surface // if (scaleToFiducialArea) { if (brainSet != NULL) { const BrainModelSurface* fiducial = brainSet->getActiveFiducialSurface(); if (fiducial == NULL) { fiducial = brainSet->getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_FIDUCIAL); } if (fiducial != NULL) { const float fiducialArea = fiducial->getSurfaceArea(getTopologyFile()); scaleSurfaceToArea(fiducialArea, true); } } } // // Surface is now cartesian standard // coordinates.setHeaderTag(AbstractFile::headerTagCoordFrameID, "CS"); } else if (getSurfaceType() == SURFACE_TYPE_SPHERICAL) { // // Place the ventral tip node on the positive Z-Axis. Use the negative // of the node since the method places the point on the negative Z-Axis. // orientPointToNegativeZAxis(coordinates.getCoordinate(ventralTipCentralSulcusNode)); // // Rotate so ventral tip on positive Z-Axis // TransformationMatrix tm; tm.rotate(TransformationMatrix::ROTATE_Y_AXIS, 180.0); applyTransformationMatrix(tm); // // Position of medial and ventral tip nodes // const float* ventralTipPos = coordinates.getCoordinate(ventralTipCentralSulcusNode); const float* medialTipPos = coordinates.getCoordinate(dorsalMedialTipCentralSulcusNode); // // angle from ventral tip to medial tip in degrees // const double dx = medialTipPos[0] - ventralTipPos[0]; const double dy = medialTipPos[1] - ventralTipPos[1]; const double angle = std::atan2(dy, dx) * MathUtilities::radiansToDegrees(); // // Set rotation angle appropriate for hemisphere // float rotateAngle; if (structure.getType() == Structure::STRUCTURE_TYPE_CORTEX_LEFT) { rotateAngle = leftHemAngleFromVertical - angle; } else { rotateAngle = rightHemAngleFromVertical - angle; } // // Transform the surface // tm.identity(); tm.rotate(TransformationMatrix::ROTATE_Z_AXIS, rotateAngle); applyTransformationMatrix(tm); // // Generate latitude/longitude if requested // if (generateSphericalLatitudeLongitude) { createLatitudeLongitude(brainSet->getLatLonFile(), -1, "Created by Standard Orientation", false, false); } tm.identity(); if (structure.getType() == Structure::STRUCTURE_TYPE_CORTEX_LEFT) { tm.rotate(TransformationMatrix::ROTATE_Y_AXIS, 270); applyTransformationMatrix(tm); tm.identity(); tm.rotate(TransformationMatrix::ROTATE_X_AXIS, 90.0); applyTransformationMatrix(tm); } else { tm.rotate(TransformationMatrix::ROTATE_Y_AXIS, 90.0); applyTransformationMatrix(tm); tm.identity(); tm.rotate(TransformationMatrix::ROTATE_X_AXIS, 90.0); applyTransformationMatrix(tm); } // // If surface should be scaled to match the area of the fiducial surface // if (scaleToFiducialArea) { if (brainSet != NULL) { const BrainModelSurface* fiducial = brainSet->getActiveFiducialSurface(); if (fiducial != NULL) { const float fiducialArea = fiducial->getSurfaceArea(getTopologyFile()); convertToSphereWithSurfaceArea(fiducialArea); } } } // // Surface is now spherical standard // coordinates.setHeaderTag(AbstractFile::headerTagCoordFrameID, "SS"); } } coordinates.clearDisplayList(); } /** * Create deformation field vectors. * * For each node, the vector originates at the node's "this" surface coordinate. The * vector tip ends at the deformed surfaces's coordinate which is projected to "this" * surface. This the tip is at a barycentric coordinate so that it may be shown on * any surface configuration. */ void BrainModelSurface::createDeformationField(const BrainModelSurface* deformedSurfaceIn, const int columnNumberIn, const QString& columnName, DeformationFieldFile& dff) const { const int numNodes = getNumberOfNodes(); if (numNodes != deformedSurfaceIn->getNumberOfNodes()) { return; } // // Make a copy of the deformed surface since it will get modified in this method // BrainModelSurface deformedSurface(*deformedSurfaceIn); // // Scale deformed sphere to same radius as normal sphere // deformedSurface.convertToSphereWithRadius(getSphericalSurfaceRadius()); // // Setup deformation field file // int columnNumber = columnNumberIn; if (dff.getNumberOfColumns() <= 0) { dff.setNumberOfNodesAndColumns(numNodes, 1); columnNumber = 0; } else if (dff.getNumberOfNodes() != numNodes) { return; } else if ((columnNumber < 0) || (columnNumber >= dff.getNumberOfColumns())) { dff.addColumns(1); columnNumber = dff.getNumberOfColumns() - 1; } dff.setColumnName(columnNumber, columnName); dff.setDeformedTopologyFileName(columnNumber, FileUtilities::basename(getTopologyFile()->getFileName())); dff.setTopologyFileName(columnNumber, FileUtilities::basename(getTopologyFile()->getFileName())); const CoordinateFile* deformedCoords = deformedSurface.getCoordinateFile(); dff.setDeformedCoordinateFileName(columnNumber, FileUtilities::basename(deformedCoords->getFileName())); const CoordinateFile* origCoords = getCoordinateFile(); dff.setPreDeformedCoordinateFileName(columnNumber, FileUtilities::basename(origCoords->getFileName())); dff.setCoordinateFileName(columnNumber, FileUtilities::basename(origCoords->getFileName())); // // Create a point projector // BrainModelSurfacePointProjector bspp(this, BrainModelSurfacePointProjector::SURFACE_TYPE_HINT_SPHERE, false); // // for each node // for (int i = 0; i < numNodes; i++) { const float* xyz = deformedCoords->getCoordinate(i); // // Project deformed node position on original coord file // int nearestNode = -1; int tileNodes[3]; float tileAreas[3]; const int tile = bspp.projectBarycentric(xyz, nearestNode, tileNodes, tileAreas); if (tile < 0) { if (nearestNode >= 0) { tileNodes[0] = nearestNode; tileNodes[1] = nearestNode; tileNodes[2] = nearestNode; tileAreas[0] = 1.0; tileAreas[1] = 1.0; tileAreas[2] = 1.0; } } DeformationFieldNodeInfo* dffi = dff.getDeformationInfo(i, columnNumber); dffi->setData(tileNodes, tileAreas); /* if ((i > 20000) && (i < 20100)) { float pos[3]; BrainModelSurfacePointProjector::unprojectPoint(tileNodes, tileAreas, origCoords, pos); std::cout << "before proj: " << xyz[0] << ", " << xyz[1] << ", " << xyz[2] << " after: " << pos[0] << ", " << pos[1] << ", " << pos[2] << std::endl; } */ } } /** * Create deformation field vectors for an ATLAS surface. * * For each node in "this" surface: * 1) Project it to the indivDeformSurface producing barycentric coordinates * 2) Apply the barycentric coordinates using the indivSourceSurface * 3) Project back to "this" surface and store the barycentric coordinates. */ void BrainModelSurface::createDeformationField(const BrainModelSurface* indivSourceSurfaceIn, const BrainModelSurface* indivDeformSurfaceIn, const int columnNumberIn, const QString& columnName, DeformationFieldFile& dff) const { if (indivSourceSurfaceIn->getNumberOfNodes() != indivDeformSurfaceIn->getNumberOfNodes()) { return; } // // Make a copy of the indiv surfaces since they will get modified in this method // BrainModelSurface indivSourceSurface(*indivSourceSurfaceIn); BrainModelSurface indivDeformedSurface(*indivDeformSurfaceIn); // // Scale indiv spheres to same radius as "this" sphere // indivSourceSurface.convertToSphereWithRadius(getSphericalSurfaceRadius()); indivDeformedSurface.convertToSphereWithRadius(getSphericalSurfaceRadius()); const int numNodes = getNumberOfNodes(); // // Setup deformation field file // int columnNumber = columnNumberIn; if (dff.getNumberOfColumns() <= 0) { dff.setNumberOfNodesAndColumns(numNodes, 1); columnNumber = 0; } else if (dff.getNumberOfNodes() != numNodes) { return; } else if ((columnNumber < 0) || (columnNumber >= dff.getNumberOfColumns())) { dff.addColumns(1); columnNumber = dff.getNumberOfColumns() - 1; } dff.setColumnName(columnNumber, columnName); const TopologyFile* indivTopoFile = indivDeformedSurface.getTopologyFile(); if (indivTopoFile != NULL) { dff.setDeformedTopologyFileName(columnNumber, FileUtilities::basename(indivTopoFile->getFileName())); } if (topology == NULL) { return; } dff.setTopologyFileName(columnNumber, FileUtilities::basename(topology->getFileName())); const CoordinateFile* deformedCoords = indivDeformedSurface.getCoordinateFile(); dff.setDeformedCoordinateFileName(columnNumber, FileUtilities::basename(deformedCoords->getFileName())); const CoordinateFile* indivCoords = indivSourceSurface.getCoordinateFile(); dff.setPreDeformedCoordinateFileName(columnNumber, FileUtilities::basename(indivCoords->getFileName())); const CoordinateFile* coords = getCoordinateFile(); dff.setCoordinateFileName(columnNumber, FileUtilities::basename(coords->getFileName())); // // Create a point projector for indiv deformed surface // BrainModelSurfacePointProjector indivDeformedProjector(&indivDeformedSurface, BrainModelSurfacePointProjector::SURFACE_TYPE_HINT_SPHERE, false); // // Create a point projector for "this" surface // BrainModelSurfacePointProjector thisProjector(this, BrainModelSurfacePointProjector::SURFACE_TYPE_HINT_SPHERE, false); // // Topology Helper // const TopologyHelper* th = topology->getTopologyHelper(false, true, false); // // for each node // for (int i = 0; i < numNodes; i++) { int tileNodes[3] = { -1, -1, -1 }; float tileAreas[3] = { 0.0, 0.0, 0.0 }; // // If node in this surface has neighbors // if (th->getNodeHasNeighbors(i)) { // // Get coordinate in this surface // float xyz[3]; coords->getCoordinate(i, xyz); // // Project node onto deformed surface // int nearestNode = -1; const int tile = indivDeformedProjector.projectBarycentric(xyz, nearestNode, tileNodes, tileAreas); if (tile < 0) { if (nearestNode >= 0) { tileNodes[0] = nearestNode; tileNodes[1] = nearestNode; tileNodes[2] = nearestNode; tileAreas[0] = 1.0; tileAreas[1] = 1.0; tileAreas[2] = 1.0; } } // // If not projected correctly // if (tileNodes[0] > 0) { // // Unproject onto indiv source surface // BrainModelSurfacePointProjector::unprojectPoint(tileNodes, tileAreas, indivCoords, xyz); // // Project onto this surface // thisProjector.projectBarycentric(xyz, nearestNode, tileNodes, tileAreas); } } // // Add to deformation field // DeformationFieldNodeInfo* dffi = dff.getDeformationInfo(i, columnNumber); dffi->setData(tileNodes, tileAreas); } } /** * simplify the surface to a fewer number of polygons. */ vtkPolyData* BrainModelSurface::simplifySurface(const int maxPolygons) const { // // See if polygons need to be reduced // const int numTriangles = topology->getNumberOfTiles(); if (numTriangles < maxPolygons) { // // Number of polygons is already less than desired // return NULL; } // // Convert to vtk's poly data format // vtkPolyData* inputPolyData = convertToVtkPolyData(); // // If conversion to vtk's polydata format successful // if (inputPolyData != NULL) { // // Set up to Decimate the polygon data // vtkDecimatePro* decimater = vtkDecimatePro::New(); decimater->SetInput(inputPolyData); const float reduction = 1.0 - ((float)maxPolygons / (float)numTriangles); if (DebugControl::getDebugOn()) { std::cout << "Reduction is " << reduction * 100.0 << "%" << std::endl; } const double errorVal = VTK_DOUBLE_MAX; //1.0; decimater->SetInput(inputPolyData); decimater->SetTargetReduction(reduction); decimater->PreserveTopologyOff(); //On(); decimater->SetFeatureAngle(30); decimater->SplittingOff(); decimater->PreSplitMeshOff(); decimater->SetMaximumError(errorVal); decimater->BoundaryVertexDeletionOff(); decimater->SetDegree(25); decimater->AccumulateErrorOn(); decimater->SetAbsoluteError(errorVal); decimater->SetErrorIsAbsolute(1); // // Compute normals on the surface // vtkPolyDataNormals* vtkNormals = vtkPolyDataNormals::New(); vtkNormals->SetInput(decimater->GetOutput()); vtkNormals->SplittingOff(); vtkNormals->ConsistencyOn(); vtkNormals->ComputePointNormalsOn(); vtkNormals->NonManifoldTraversalOn(); vtkNormals->Update(); vtkPolyData* polyOut = vtkPolyData::New(); polyOut->DeepCopy(vtkNormals->GetOutput()); decimater->Delete(); vtkNormals->Delete(); inputPolyData->Delete(); return polyOut; } return NULL; } /** * get node closest to point. */ int BrainModelSurface::getNodeClosestToPoint(const float pointXYZ[3]) const { int nearestNodeNumber = -1; float nearestNodeDistance = std::numeric_limits::max();; const TopologyHelper* th = topology->getTopologyHelper(false, true, false); const int num = coordinates.getNumberOfNodes(); for (int i = 0; i < num; i++) { if (th->getNodeHasNeighbors(i)) { const float* xyz = coordinates.getCoordinate(i); const float dist = MathUtilities::distanceSquared3D(xyz, pointXYZ); if (dist < nearestNodeDistance) { nearestNodeNumber = i; nearestNodeDistance = dist; } } } return nearestNodeNumber; } /** * Create a string of c-language arrays containing vertices, normals, triangles. */ QString BrainModelSurface::convertToCLanguageArrays() const { // // Get the number of vertices and triangles // const CoordinateFile* cf = this->getCoordinateFile(); const int numVertices = cf->getNumberOfCoordinates(); const TopologyFile* tf = this->getTopologyFile(); const int numTriangles = tf->getNumberOfTiles(); if ((numVertices <= 0) || (numTriangles <= 0)) { return ""; } // // Estimate storage to avoid excessive memory reallocations // const int charactersPerVertex = 8; const int charactersPerTriangle = 4; const int estimatedStorage = charactersPerVertex * 2 * numVertices + charactersPerTriangle * numTriangles; QString s; s.reserve(estimatedStorage); // // Wrap a text stream around the string // QTextStream stream(&s, QIODevice::WriteOnly); // // Add number of vertices and triangles to string // stream << "const int numVertices = " << numVertices << ";\n"; stream << "const int numTriangles = " << numTriangles << ";\n"; stream << "\n"; // // Write the vertices // stream << "float vertices[] = {\n"; for (int i = 0; i < numVertices; i++) { const float* xyz = cf->getCoordinate(i); stream << " " << xyz[0] << ", " << xyz[1] << ", " << xyz[2]; if ((i + 1) < numVertices) { stream << ","; } stream << "\n"; } stream << "};\n\n"; // // Write the normals // stream << "float normals[] = {\n"; for (int i = 0; i < numVertices; i++) { const float* xyz = this->getNormal(i); stream << " " << xyz[0] << ", " << xyz[1] << ", " << xyz[2]; if ((i + 1) < numVertices) { stream << ","; } stream << "\n"; } stream << "};\n\n"; // // Write the triangles // stream << "int triangles[] = {\n"; for (int i = 0; i < numTriangles; i++) { const int* tile = tf->getTile(i); stream << " " << tile[0] << ", " << tile[1] << ", " << tile[2]; if ((i + 1) < numTriangles) { stream << ","; } stream << "\n"; } stream << "};\n\n"; return s; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelStandardSurfaceReplacement.h0000664000175000017500000000326311572067322027250 0ustar michaelmichael #ifndef __BRAIN_MODEL_STANDARD_SURFACE_REPLACEMENT_H__ #define __BRAIN_MODEL_STANDARD_SURFACE_REPLACEMENT_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelAlgorithm.h" class BrainModelSurface; /// Class for replacing surface(s) with a standard surface and handle removal class BrainModelStandardSurfaceReplacement : public BrainModelAlgorithm { public: /// Constructor BrainModelStandardSurfaceReplacement(BrainSet* bs, BrainModelSurface* sphericalSurfaceIn); /// Destructor ~BrainModelStandardSurfaceReplacement(); /// execute the algorithm void execute() throw (BrainModelAlgorithmException); protected: /// spherical surface input BrainModelSurface* sphericalSurface; }; #endif // __BRAIN_MODEL_STANDARD_SURFACE_REPLACEMENT_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelStandardSurfaceReplacement.cxx0000664000175000017500000002133311572067322027621 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelStandardSurfaceReplacement.h" #include "BrainModelSurface.h" #include "BrainModelSurfacePointProjector.h" #include "BrainSet.h" #include "DeformationMapFile.h" #include "TopologyFile.h" #include "TopologyHelper.h" /** * Constructor. */ BrainModelStandardSurfaceReplacement::BrainModelStandardSurfaceReplacement( BrainSet* bs, BrainModelSurface* sphericalSurfaceIn) : BrainModelAlgorithm(bs) { sphericalSurface = sphericalSurfaceIn; } /** * Destructor. */ BrainModelStandardSurfaceReplacement::~BrainModelStandardSurfaceReplacement() { } /** * execute the algorithm. */ void BrainModelStandardSurfaceReplacement::execute() throw (BrainModelAlgorithmException) { // // Get the radius of the input sphere // const float sphereRadius = sphericalSurface->getSphericalSurfaceRadius(); // // Read in the standard sphere // QString standardSphereSpecName(brainSet->getCaretHomeDirectory()); standardSphereSpecName.append("/data_files/REGISTER.SPHERE/sphere.v5.6.spec"); // // Read in the standard sphere spec file // BrainSet standardBrain(standardSphereSpecName, true, false); if (standardBrain.getNumberOfBrainModels() < 0) { QString msg("Unable to read standard sphere from spec: "); msg.append(standardSphereSpecName); throw BrainModelAlgorithmException(msg); } // // Get the standard spherical surface // BrainModelSurface* standardSphere = standardBrain.getBrainModelSurface(0); if (standardSphere == NULL) { throw BrainModelAlgorithmException("Unable to find standard sphere after reading it"); } // // Set the standard sphere to the radius of the input sphere // standardSphere->convertToSphereWithRadius(sphereRadius); // // Get the standard sphere coordinate file // const CoordinateFile* standardCoord = standardSphere->getCoordinateFile(); const int numStandardNodes = standardSphere->getNumberOfNodes(); // // Create a point projector for projecting standard sphere coords to input sphere // BrainModelSurfacePointProjector bmspp(sphericalSurface, BrainModelSurfacePointProjector::SURFACE_TYPE_HINT_SPHERE, false); // // Use a deformation map to store the projection information // DeformationMapFile defMapFile; defMapFile.setNumberOfNodes(numStandardNodes); // // Get the standard sphere's topology file // const TopologyFile* tf = standardSphere->getTopologyFile(); // // Get a topology helper for connected nodes // const TopologyHelper* th = tf->getTopologyHelper(false, true, false); // // Project the standard sphere to the input sphere // for (int i = 0; i < numStandardNodes; i++) { int tileNodes[3] = { -1, -1, -1 }; float tileAreas[3]; if (th->getNodeHasNeighbors(i)) { // // Project node from standard sphere // int nearestNode = -1; float xyz[3]; standardCoord->getCoordinate(i, xyz); bmspp.projectBarycentric(xyz, nearestNode, tileNodes, tileAreas, true); if (tileNodes[0] < 0) { // // Move point slightly and try again // std::cout << "Trying agin for node : " << i << std::endl; const float delta = 0.001; xyz[0] += delta; xyz[1] += delta; xyz[2] += delta; bmspp.projectBarycentric(xyz, nearestNode, tileNodes, tileAreas, true); if (tileNodes[0] < 0) { std::cout << "Moving to nearest node" << std::endl; if (nearestNode >= 0) { tileNodes[0] = nearestNode; tileNodes[1] = nearestNode; tileNodes[2] = nearestNode; tileAreas[0] = 1.0; tileAreas[1] = 0.0; tileAreas[2] = 0.0; } else { std::cout << "Node " << i << " did not project. Nearest: " << nearestNode << std::endl; } } } } // // set deform data for node // defMapFile.setDeformDataForNode(i, tileNodes, tileAreas); } // // Copy the standard sphere's topology file // TopologyFile* topologyFile = new TopologyFile(*tf); // // Keep track of new surfaces // std::vector surfaces; // // Deform to each of input brain set's surfaces // for (int i = 0; i < brainSet->getNumberOfBrainModels(); i++) { const BrainModelSurface* bms = brainSet->getBrainModelSurface(i); if (bms != NULL) { // // Create a new brain model surface, get coord file, set nodes // BrainModelSurface* newSurface = new BrainModelSurface(brainSet); newSurface->setSurfaceType(bms->getSurfaceType()); CoordinateFile* newCoord = newSurface->getCoordinateFile(); newCoord->setNumberOfCoordinates(numStandardNodes); // // Keep track of nodes that need to be smoothed // std::vector smoothNode(numStandardNodes, false); // // Unproject nodes to create new surface // const CoordinateFile* oldCoord = bms->getCoordinateFile(); for (int j = 0; j < numStandardNodes; j++) { int nodes[3]; float areas[3]; defMapFile.getDeformDataForNode(j, nodes, areas); float xyz[3] = { 0.0, 0.0, 0.0 }; if (nodes[0] >= 0) { BrainModelSurfacePointProjector::unprojectPoint(nodes, areas, oldCoord, xyz); if ((xyz[0] == 0.0) && (xyz[1] == 0.0) && (xyz[2] == 0.0)) { smoothNode[j] = true; } } newCoord->setCoordinate(j, xyz); } // // Add topology // newSurface->setTopologyFile(topologyFile); // // Smooth connected nodes that are at origin // newSurface->arealSmoothing(1.0, 25, 0, &smoothNode); // // Smooth surface one iteration // int sphereIter = 0; if (newSurface->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_SPHERICAL) { sphereIter = 1; } newSurface->arealSmoothing(1.0, 1, sphereIter); // // Keep track of the surfaces // surfaces.push_back(newSurface); } } Structure structure = brainSet->getStructure(); // // Reset the current brain set // brainSet->reset(); brainSet->setStructure(structure); brainSet->addTopologyFile(topologyFile); for (unsigned int i = 0; i < surfaces.size(); i++) { surfaces[i]->computeNormals(); surfaces[i]->setStructure(structure); brainSet->addBrainModel(surfaces[i], true); } // // Reset node coloring // brainSet->getPrimarySurfaceOverlay()->setOverlay(-1, BrainModelSurfaceOverlay::OVERLAY_NONE); brainSet->getSecondarySurfaceOverlay()->setOverlay(-1, BrainModelSurfaceOverlay::OVERLAY_NONE); brainSet->getSurfaceUnderlay()->setOverlay(-1, BrainModelSurfaceOverlay::OVERLAY_NONE); brainSet->postSpecFileReadInitializations(); } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelRunExternalProgram.h0000664000175000017500000000424711572067322025621 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __BRAIN_MODEL_RUN_EXTERNAL_PROGRAM_H__ #define __BRAIN_MODEL_RUN_EXTERNAL_PROGRAM_H__ #include #include #include "BrainModelAlgorithm.h" /// Class to run an external program class BrainModelRunExternalProgram : public BrainModelAlgorithm { Q_OBJECT public: /// Constructor BrainModelRunExternalProgram(const QString& programNameIn, const QStringList& programArgumentsIn, const bool programIsInCaretSlashBinDirectoryFlagIn); /// Destructor ~BrainModelRunExternalProgram(); // execute the utility program. void execute() throw (BrainModelAlgorithmException); /// get output of command QString getOutputText() const { return outputText; } protected: /// program name QString programName; /// program arguments QStringList programArguments; /// wait until program is finished before returning from execute() bool waitUntilDone; /// output of program QString outputText; /// program is in caret/bin directory flag bool programIsInCaretSlashBinDirectoryFlag; }; #endif // __BRAIN_MODEL_RUN_EXTERNAL_PROGRAM_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelRunExternalProgram.cxx0000664000175000017500000001610511572067322026170 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "BrainModelRunExternalProgram.h" #include "BrainSet.h" #include "DebugControl.h" /** * Constructor. */ BrainModelRunExternalProgram::BrainModelRunExternalProgram( const QString& programNameIn, const QStringList& programArgumentsIn, const bool programIsInCaretSlashBinDirectoryFlagIn) : BrainModelAlgorithm(NULL) { programName = programNameIn; programArguments = programArgumentsIn; programIsInCaretSlashBinDirectoryFlag = programIsInCaretSlashBinDirectoryFlagIn; } /** * Destructor. */ BrainModelRunExternalProgram::~BrainModelRunExternalProgram() { } /** * Execute the program. If the program is not started successfully, a * BrainModelAlgorithmException will be thrown. */ void BrainModelRunExternalProgram::execute() throw (BrainModelAlgorithmException) { outputText = ""; if (DebugControl::getDebugOn()) { std::cout << "Caret Home Directory: " << BrainSet::getCaretHomeDirectory().toAscii().constData() << std::endl; std::cout << "Caret Bin Directory: " << BrainSet::getBinDirectoryName().toAscii().constData() << std::endl; } // // Start path to executable // QString pgm; if (programIsInCaretSlashBinDirectoryFlag) { pgm.append(BrainSet::getCaretHomeDirectory()); pgm.append("/"); pgm.append(BrainSet::getBinDirectoryName()); pgm.append("/"); /* #ifdef Q_OS_MACX pgm.append("/bin_macosx/"); #elif Q_OS_WIN32 pgm.append("/bin_windows/"); #elif Q_OS_FREEBSD pgm.append("/bin_freebsd/"); #elif Q_OS_UNIX pgm.append("/bin_linux/"); #else pgm.append("/bin_other/"); #endif */ } pgm.append(programName); if (DebugControl::getDebugOn()) { std::cout << "Program to run is: " << pgm.toAscii().constData() << std::endl; } /* #ifdef Q_OS_MACX //pgm.append("/apps/map_fmri_to_surface.app/Contents/MacOS/"); pgm.append("/bin/"); pgm.append(utilityProgramName); if (macApplicationFlag == false) { doingMacCommandLineProgram = true; } #endif // Q_OS_MACX #ifdef Q_OS_WIN32 pgm.append("\\bin\\"); pgm.append(utilityProgramName); pgm.append(".exe"); #endif // Q_OS_WIN32 #ifdef Q_OS_UNIX #ifndef Q_OS_MACX pgm.append("/bin/"); pgm.append(utilityProgramName); #endif // Q_OS_MACX #endif // Q_OS_UNIX bool doingFreeBSDCommandLineProgram = false; #ifdef Q_OS_FREEBSD doingFreeBSDCommandLineProgram = true; #endif // // On a Macintosh, Qt's QProcess expects the program to be a Mac Application bundle so // simple command line programs have to be specially handled on the Mac. // if (doingMacCommandLineProgram || doingFreeBSDCommandLineProgram) { if (utilityProgramArguments.isEmpty() == false) { pgm.append(" "); pgm.append(utilityProgramArguments); } if (waitUntilDone == false) { pgm.append(" &"); } if (DebugControl::getDebugOn()) { std::cout << "About to run external program: " << pgm.toAscii().constData() << std::endl; } int result = system(pgm.toAscii().constData()); result = ((result >> 8) & 0xff); if (result != 0) { std::ostringstream str; str << "Execution of program failed:" << "\n" << pgm.toAscii().constData() << "\n" << "with arguments: " << utilityProgramArguments.toAscii().constData() << "\n" << "Exit status: " << result; throw BrainModelAlgorithmException(str.str().c_str()); } return; } */ // // Create the process object // QProcess* process = new QProcess(this); if (DebugControl::getDebugOn()) { std::cout << "Parameters for QProcess" << std::endl; std::cout << " Program to run: " << pgm.toAscii().constData() << std::endl; } int numArgs = this->programArguments.size(); for (int i = 0; i < numArgs; i++) { QString p = this->programArguments.at(i); if (DebugControl::getDebugOn()) { std::cout << " Arg " << i << ": " << p.toAscii().constData() << std::endl; } if (p.startsWith('"') && p.endsWith('"')) { const int len = p.length(); if (len > 2) { p = p.mid(1, len - 2); this->programArguments.replace(i, p); if (DebugControl::getDebugOn()) { std::cout << " Removed quotes, now: " << p.toAscii().constData() << std::endl; } } } } // // Execute the process // bool errorFlag = false; process->start(pgm, programArguments); if (process->waitForStarted()) { // // See if the program is still running // process->waitForFinished(std::numeric_limits::max()); if (process->exitStatus() == QProcess::NormalExit) { if (process->exitCode() == 0) { outputText.append("COMMAND SUCCESSFUL\n\n"); } else { errorFlag = true; outputText.append("COMMAND Reported Error: \n"); } } else { errorFlag = true; QString str = ("Execution of program failed:\n" + pgm + "\n" + "with arguments: " + programArguments.join(" ") + "\n"); outputText.append(str); } outputText += process->readAllStandardError(); if (outputText.isEmpty() == false) { outputText += "\n"; } outputText += process->readAllStandardOutput(); } else { errorFlag = true; QString str = ("Starting of program failed:\n" + pgm + "\n" + "with arguments: " + programArguments.join(" ") + "\n"); outputText.append(str); } delete process; if (errorFlag) { throw BrainModelAlgorithmException(outputText); } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelOpenGLWidget.h0000664000175000017500000000505211572067322024305 0ustar michaelmichael #ifndef __BRAIN_MODEL_OPENGL_WIDGET_H__ #define __BRAIN_MODEL_OPENGL_WIDGET_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "PreferencesFile.h" class BrainModel; class BrainModelOpenGL; class BrainSet; /// class used for offscreen opengl rendering class BrainModelOpenGLWidget : public QGLWidget { public: /// constructor BrainModelOpenGLWidget(BrainSet* bsin, QWidget* parent = 0, const char* name = 0); /// destructor ~BrainModelOpenGLWidget(); /// set the brain model that is to be drawn void drawBrainModel(BrainModel* bm); /// capture an image of a brain model (returns true if successful) bool captureBrainModelImage(BrainModel* bm, const QString& imageFileName, const PreferencesFile::IMAGE_CAPTURE_TYPE imageCaptureType, const int imageQuality = 75); /// get the renderer for OpenGL BrainModelOpenGL* getBrainModelOpenGL() { return brainModelOpenGL; } /// set the fixed size of the OpenGL widget void setWidgetToFixedSize(const int width, const int height); protected: /// rendering for OpenGL BrainModelOpenGL* brainModelOpenGL; /// brain model that is to be drawn BrainModel* brainModel; /// initialize the OpenGL void initializeGL(); /// widget is being resized void resizeGL( int, int ); /// update the widget (draw with OpenGL) void paintGL(); }; #endif // __BRAIN_MODEL_OPENGL_WIDGET_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelOpenGLWidget.cxx0000664000175000017500000000713711572067322024666 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModel.h" #include "BrainModelOpenGL.h" #include "BrainModelOpenGLWidget.h" #include "BrainSet.h" /** * constructor. */ BrainModelOpenGLWidget::BrainModelOpenGLWidget(BrainSet* bsin, QWidget* parent, const char* name) : QGLWidget(parent, name) { brainModel = NULL; brainModelOpenGL = new BrainModelOpenGL(bsin); } /** * destructor. */ BrainModelOpenGLWidget::~BrainModelOpenGLWidget() { delete brainModelOpenGL; } /** * draw a brain model. */ void BrainModelOpenGLWidget::drawBrainModel(BrainModel* bm) { brainModel = bm; updateGL(); brainModel = NULL; } /** * capture an image of a brain model */ bool BrainModelOpenGLWidget::captureBrainModelImage(BrainModel* bm, const QString& imageFileName, const PreferencesFile::IMAGE_CAPTURE_TYPE imageCaptureType, const int imageQuality) { brainModel = bm; updateGL(); bool wroteImage = false; switch (imageCaptureType) { case PreferencesFile::IMAGE_CAPTURE_PIXMAP: { // // Save as a pixmap (mac/windows like this best) // QPixmap pix = renderPixmap(); wroteImage = pix.save(imageFileName, "JPEG", imageQuality); } break; case PreferencesFile::IMAGE_CAPTURE_OPENGL_BUFFER: { // // Save with grabbing frame buffer (unix likes this best) // QImage image(grabFrameBuffer()); wroteImage = image.save(imageFileName, "JPEG", imageQuality); } } brainModel = NULL; return wroteImage; } /** * initialize the OpenGL. */ void BrainModelOpenGLWidget::initializeGL() { brainModelOpenGL->initializeOpenGL(); } /** * widget is being resized. */ void BrainModelOpenGLWidget::resizeGL(int w, int h) { glViewport(0, 0, w, h); brainModelOpenGL->updateOrthoSize(0, w, h); } /** * set the fixed size of the OpenGL widget. */ void BrainModelOpenGLWidget::setWidgetToFixedSize(const int width, const int height) { setFixedSize(QSize(width, height)); updateGL(); } /** * update the widget (draw with OpenGL). */ void BrainModelOpenGLWidget::paintGL() { // // Get the size of the widget for use as viewport // QSize sz = size(); const int viewport[4] = { 0, 0, sz.width(), sz.height() }; if (brainModel != NULL) { brainModelOpenGL->drawBrainModel(brainModel, 0, // viewing window number viewport, this); } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelOpenGLSelectedItem.h0000664000175000017500000001306211572067322025431 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __BRAIN_MODEL_OPENGL_SELECTED_ITEM_H__ #define __BRAIN_MODEL_OPENGL_SELECTED_ITEM_H__ class BrainModel; class BrainModelContours; class BrainModelSurface; class BrainModelVolume; class BrainSet; /// This class contains information about a selected item class BrainModelOpenGLSelectedItem { public: /// types of selected items enum ITEM_TYPE { ITEM_TYPE_NONE, ITEM_TYPE_TILE, ITEM_TYPE_NODE, ITEM_TYPE_BORDER, ITEM_TYPE_BORDER_PROJ, ITEM_TYPE_VOLUME_BORDER, ITEM_TYPE_CELL_PROJECTION, ITEM_TYPE_VOLUME_CELL, ITEM_TYPE_CONTOUR, ITEM_TYPE_TRANSFORM_CONTOUR, ITEM_TYPE_CONTOUR_CELL, ITEM_TYPE_TRANSFORM_CONTOUR_CELL, ITEM_TYPE_TRANSFORM_CELL, ITEM_TYPE_CUT, ITEM_TYPE_FOCUS_PROJECTION, ITEM_TYPE_VOLUME_FOCI, ITEM_TYPE_TRANSFORM_FOCI, ITEM_TYPE_PALETTE_METRIC, ITEM_TYPE_PALETTE_SHAPE, ITEM_TYPE_VOXEL_UNDERLAY, ITEM_TYPE_VOXEL_OVERLAY_SECONDARY, ITEM_TYPE_VOXEL_OVERLAY_PRIMARY, ITEM_TYPE_VOXEL_FUNCTIONAL_CLOUD, ITEM_TYPE_LINK, ITEM_TYPE_TRANSFORMATION_MATRIX_AXES, ITEM_TYPE_VTK_MODEL }; /// Constructor BrainModelOpenGLSelectedItem(); /// Destructor ~BrainModelOpenGLSelectedItem(); /// Replace the current instance if these parameters are "better". /// returns true if replacement took place. bool replaceIfCloser(const float depthIn, const float distIn, const ITEM_TYPE itemTypeIn, const int index1In, const int index2In = -1, const int index3In = -1, const int index4In = -1, const int index5In = -1, const int index6In = -1); /// Get the item index1 int getItemIndex1() const { return index1; } /// Get the item index2 int getItemIndex2() const { return index2; } /// Get the item index3 int getItemIndex3() const { return index3; } /// Get the item index4 int getItemIndex4() const { return index4; } /// Get the item index5 int getItemIndex5() const { return index5; } /// Get the item index6 int getItemIndex6() const { return index6; } /// Set the item index1 void setItemIndex1(const int i) { index1 = i; } /// Set the item index2 void setItemIndex2(const int i) { index2 = i; } /// Set the item index3 void setItemIndex3(const int i) { index3 = i; } /// Set the item index4 void setItemIndex4(const int i) { index4 = i; } /// Set the item index5 void setItemIndex5(const int i) { index5 = i; } /// Set the item index6 void setItemIndex6(const int i) { index6 = i; } /// Get the item type ITEM_TYPE getItemType() const { return itemType; } /// Get the depth of the selection (smaller is nearer to user) float getDepth() const { return depth; } /// Reinitialize this item void reset(BrainSet* brainSetIn, BrainModel* brainModelIn, const int viewingWindowNumberIn); /// get the brain set BrainSet* getBrainSet() { return brainSet; } /// get the brain model BrainModel* getBrainModel() { return brainModel; } /// get the brain model surface BrainModelSurface* getBrainModelSurface(); /// get the brain model volume BrainModelVolume* getBrainModelVolume(); /// get the brain model contours BrainModelContours* getBrainModelContours(); /// get the viewing window number int getViewingWindowNumber() const { return viewingWindowNumber; } private: /// BrainSet of the selected item BrainSet* brainSet; /// BrainModel of the selected item BrainModel* brainModel; /// viewing window number of the selected item int viewingWindowNumber; /// Depth of selected item float depth; /// Distance of item from pick position float distToPick; /// Item type ITEM_TYPE itemType; /// First index int index1; /// Second index int index2; /// Third index int index3; /// Fourth index int index4; /// Fifth index int index5; /// Sixth index int index6; }; #endif caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelOpenGLSelectedItem.cxx0000664000175000017500000000670011572067322026005 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModel.h" #include "BrainModelContours.h" #include "BrainModelOpenGLSelectedItem.h" #include "BrainModelSurface.h" #include "BrainModelVolume.h" /** * Constructor. */ BrainModelOpenGLSelectedItem::BrainModelOpenGLSelectedItem() { reset(NULL, NULL, -1); } /** * Destructor. */ BrainModelOpenGLSelectedItem::~BrainModelOpenGLSelectedItem() { } /** * Reinitialize this item. */ void BrainModelOpenGLSelectedItem::reset(BrainSet* brainSetIn, BrainModel* brainModelIn, const int viewingWindowNumberIn) { brainSet = brainSetIn; brainModel = brainModelIn; viewingWindowNumber = viewingWindowNumberIn; itemType = ITEM_TYPE_NONE; index1 = -1; index2 = -1; index3 = -1; index4 = -1; index5 = -1; index6 = -1; } /** * Replace current item if parameters in are "closer". */ bool BrainModelOpenGLSelectedItem::replaceIfCloser(const float depthIn, const float distIn, const ITEM_TYPE itemTypeIn, const int index1In, const int index2In, const int index3In, const int index4In, const int index5In, const int index6In) { bool replaceIt = false; if (itemType == ITEM_TYPE_NONE) { replaceIt = true; } else if (depthIn < depth) { replaceIt = true; } else if (depthIn == depth) { if (distIn < distToPick) { replaceIt = true; } } if (replaceIt) { depth = depthIn; distToPick = distIn; itemType = itemTypeIn; index1 = index1In; index2 = index2In; index3 = index3In; index4 = index4In; index5 = index5In; index6 = index6In; } return replaceIt; } /** * get the brain model surface. */ BrainModelSurface* BrainModelOpenGLSelectedItem::getBrainModelSurface() { return dynamic_cast(brainModel); } /** * get the brain model volume. */ BrainModelVolume* BrainModelOpenGLSelectedItem::getBrainModelVolume() { return dynamic_cast(brainModel); } /** * get the brain model contours. */ BrainModelContours* BrainModelOpenGLSelectedItem::getBrainModelContours() { return dynamic_cast(brainModel); } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelOpenGL.h0000664000175000017500000011301611572067322023141 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __BRAIN_MODEL_OPENGL_H__ #define __BRAIN_MODEL_OPENGL_H__ #include #include // includes OpenGL includes ;) #include #include "BorderFile.h" #include "BrainModel.h" #include "BrainModelOpenGLSelectedItem.h" #include "ColorFile.h" #include "VolumeFile.h" class BrainModelContours; class BrainModelSurface; class BrainModelSurfaceAndVolume; class BrainModelSurfaceNodeColoring; class BrainModelVolume; class BrainSet; class CellFile; class CellProjectionFile; class ContourFile; class CoordinateFile; class DisplaySettingsCells; class QImage; class TopologyFile; class VtkModelFile; /// This class is used to draw BrainModels using OpenGL class BrainModelOpenGL { public: /// bitmasks for selecting objects enum /* SELECTION_MASK */ { SELECTION_MASK_OFF = 0, SELECTION_MASK_NODE = 1, SELECTION_MASK_BORDER = 2, SELECTION_MASK_CELL_PROJECTION = 4, SELECTION_MASK_FOCUS_PROJECTION = 8, SELECTION_MASK_PALETTE_METRIC = 16, SELECTION_MASK_PALETTE_SHAPE = 32, SELECTION_MASK_CUT = 64, SELECTION_MASK_CONTOUR = 128, SELECTION_MASK_CONTOUR_CELL = 256, // 2^8 SELECTION_MASK_VOXEL_UNDERLAY = 512, SELECTION_MASK_VOXEL_OVERLAY_SECONDARY = 1024, SELECTION_MASK_VOXEL_OVERLAY_PRIMARY = 2048, SELECTION_MASK_VOXEL_FUNCTIONAL_CLOUD = 4096, SELECTION_MASK_TILE = 8192, SELECTION_MASK_LINK = 16384, SELECTION_MASK_VOLUME_BORDER = 32768, SELECTION_MASK_VOLUME_CELL = 65536, // 2^16 SELECTION_MASK_VOLUME_FOCI = 131072, SELECTION_MASK_TRANSFORMATION_MATRIX_AXES = 262144, SELECTION_MASK_VTK_MODEL = 524288, SELECTION_MASK_TRANSFORM_CELL = 1048576, SELECTION_MASK_TRANSFORM_FOCI = 2097152, SELECTION_MASK_TRANSFORM_CONTOUR_CELL = 4194304, SELECTION_MASK_TRANSFORM_CONTOUR = 8388608, // 2^23 SELECTION_MASK_ALL = 0xffffffff // ALL bitmasks ON }; /// Constructor BrainModelOpenGL(); /// Destructor ~BrainModelOpenGL(); /// Draw a brain model for WebCaret void drawBrainModelWebCaret(BrainSet* bs, BrainModel* bm, const int viewingWindowNumberIn, const int viewportIn[4]); /// Draw a brain model void drawBrainModel(BrainSet* bs, BrainModel* bm, const int viewingWindowNumberIn, const int viewportIn[4], QGLWidget* glWidgetIn); /// select something in the brain model for WebCaret void selectBrainModelItemWebCaret(BrainSet* bs, BrainModel* bm, const int viewportIn[4], const unsigned long selectionMaskIn, const int selectionXIn, const int selectionYIn); /// Identify something in the brain model for WebCaret QString identifyBrainModelItemWebCaret(BrainSet* bs, BrainModel* bm, const int viewingWindowNumberIn, const int viewportIn[4], const unsigned long selectionMaskIn, const int selectionXIn, const int selectionYIn, const bool enableHtml, const bool enableVocabularyLinks); /// select something in the brain model void selectBrainModelItem(BrainSet* bs, BrainModel* bm, const int viewingWindowNumberIn, const int viewportIn[4], QGLWidget* glWidgetIn, const unsigned long selectionMaskIn, const int selectionXIn, const int selectionYIn, const bool viewModeFlag); /// identify items in the brain model (returns text for ID display) QString identifyBrainModelItem(BrainSet* bs, BrainModel* bm, BrainModel* allWindowBrainModelsForIdentificationIn[BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS], const int viewingWindowNumberIn, const int viewportIn[4], QGLWidget* glWidgetIn, const unsigned long selectionMaskIn, const int selectionXIn, const int selectionYIn, const bool viewModeFlag, const bool enableHtml, const bool enableVocabularyLinks); /// all brain models displayed in windows for identification /// ONLY VALID WHEN ::identifyBrainModel... called BrainModel* getBrainModelInWindowNumberForIdentification(const int windowNumber); /// Draw all fiducial surface brain models void drawAllFiducialSurfaceBrainModels(std::vector brainSets, const int viewingWindowNumberIn, const int viewportIn[4], QGLWidget* glWidgetIn); /// Get a 3D point on a surface at a screen X/Y. bool getSurfacePointAtDisplayXY(BrainSet* bs, BrainModelSurface* bms, const int viewingWindowNumberIn, const int viewportIn[4], const int displayX, const int displayY, float pointOut[3]); /// initialize OpenGL (should only call one time) void initializeOpenGL(const bool offScreenRenderingFlagIn); // set the image subregion box/display void setImageSubRegion(const int box[4], const bool showFlag); /// get the editing segmentation volume flag bool getEditingSegmentationVolumeFlag() const { return editingSegmentationVolumeFlag; } /// set the editing segmentation volume flag void setEditingSegmentationVolumeFlag(const bool b) { editingSegmentationVolumeFlag = b; } /// get the editing paint volume flag bool getEditingPaintVolumeFlag() const { return editingPaintVolumeFlag; } /// set the editing paint volume flag void setEditingPaintVolumeFlag(const bool b) { editingPaintVolumeFlag = b; } /// get the orthographic size void getOrtho(float& orthoRight, float& orthoTop) const; /// Update the orthographic window size. void updateOrthoSize(const int windowNumber, const int width, const int height); /// get caption displayed in main window QString getMainWindowCaption() const { return mainWindowCaption; } /// set caption displayed in main window void setMainWindowCaption(const QString& s) { mainWindowCaption = s; } /// selected node BrainModelOpenGLSelectedItem getSelectedNode() const { return selectedNode; } /// selected border (first) BrainModelOpenGLSelectedItem getSelectedBorder1() const { return selectedBorder1; } /// selected border (second) BrainModelOpenGLSelectedItem getSelectedBorder2() const { return selectedBorder2; } /// selected border (volume) BrainModelOpenGLSelectedItem getSelectedVolumeBorder() const { return selectedVolumeBorder; } /// selected cell projection BrainModelOpenGLSelectedItem getSelectedCellProjection() const { return selectedCellProjection; } /// selected cell (volume) BrainModelOpenGLSelectedItem getSelectedVolumeCell() const { return selectedVolumeCell; } /// selected cut BrainModelOpenGLSelectedItem getSelectedCut() const { return selectedCut; } /// selected foci projection BrainModelOpenGLSelectedItem getSelectedFocusProjection() const { return selectedFocusProjection; } /// selected foci (volume) BrainModelOpenGLSelectedItem getSelectedVolumeFoci() const { return selectedVolumeFoci; } /// selected palette for metric BrainModelOpenGLSelectedItem getSelectedPaletteMetric() const { return selectedPaletteMetric; } /// selected palette for shape BrainModelOpenGLSelectedItem getSelectedPaletteShape() const { return selectedPaletteShape; } /// selected contour BrainModelOpenGLSelectedItem getSelectedContour() const { return selectedContour; } /// selected contour cell BrainModelOpenGLSelectedItem getSelectedContourCell() const { return selectedContourCell; } /// selected voxel underlay BrainModelOpenGLSelectedItem getSelectedVoxelUnderlay() const { return selectedVoxelUnderlay; } /// selected voxel overlay secondary BrainModelOpenGLSelectedItem getSelectedVoxelOverlaySecondary() const { return selectedVoxelOverlaySecondary; } /// selected voxel overlay primary BrainModelOpenGLSelectedItem getSelectedVoxelOverlayPrimary() const { return selectedVoxelOverlayPrimary; } /// selected functional voxel (surface and volume cloud) BrainModelOpenGLSelectedItem getSelectedVoxelFunctionalCloud() const { return selectedVoxelFunctionalCloud; } /// selected surface tile BrainModelOpenGLSelectedItem getSelectedSurfaceTile() const { return selectedSurfaceTile; } /// selected link (index 1 & 2 are nodes) BrainModelOpenGLSelectedItem getSelectedLink() const { return selectedLink; } /// selected transformation axes BrainModelOpenGLSelectedItem getSelectedTransformationMatrixAxes() const { return selectedTransformationMatrixAxes; } /// selected transformation cell BrainModelOpenGLSelectedItem getSelectedTransformationCell() const { return selectedTransformCell; } /// selected transformation foci BrainModelOpenGLSelectedItem getSelectedTransformationFoci() const { return selectedTransformFoci; } /// selected transformation contour BrainModelOpenGLSelectedItem getSelectedTransformationContour() const { return selectedTransformContour; } /// selected transformation contour cell BrainModelOpenGLSelectedItem getSelectedTransformationContourCell() const { return selectedTransformContourCell; } /// selected vtk model BrainModelOpenGLSelectedItem getSelectedVtkModel() const { return selectedVtkModel; } /// get the selection modelview matrix GLdouble* getSelectionModelviewMatrix(const int viewWindowNumber) { return selectionModelviewMatrix[viewWindowNumber]; } /// get the selection projection matrix GLdouble* getSelectionProjectionMatrix(const int viewWindowNumber) { return selectionProjectionMatrix[viewWindowNumber]; } /// get the selection viewport GLint* getSelectionViewport(const int viewWindowNumber) { return selectionViewport[viewWindowNumber]; } /// Get the dimensions of the surface orthographic projection void getOrthographicBox(const int modelViewNumber, double& orthoLeft, double& orthoRight, double& orthoBottom, double& orthoTop, double& orthoNear, double& orthoFar) const; /// set the linear object for drawing borders, cuts, etc. void setLinearObject(const Border& lo) { linearObjectBeingDrawn = lo; } /// set the linear object valid void setDrawLinearObjectOnly(const bool loo) { drawLinearObjectOnly = loo; } /// set node special highlighting void setNodeSpecialHighlighting(const std::vector& nsh) { nodeSpecialHighlighting = nsh; } /// set OpenGL text enabled static void setOpenGLTextEnabled(const bool b) { openGLTextEnabledFlag = b; } /// get the default ortho right and top for command line scene generation static void getDefaultOrthoRightAndTop(const int windowWidthIn, const int windowHeightIn, double& orthoRightOut, double& orthoTopOut); /// get minimum/maximum point size static void getMinMaxPointSize(float& minSizeOut, float& maxSizeOut); /// get minimum/maximum line width static void getMinMaxLineWidth(float& minWidthOut, float& maxWidthOut); protected: /// Draw a brain model void drawBrainModelPrivate(BrainModel* bm, const int viewingWindowNumberIn, const int viewportIn[4], QGLWidget* glWidgetIn); /// draw contours void drawBrainModelContours(BrainModelContours* bmc); /// draw surface void drawBrainModelSurface(BrainModelSurface* bms, BrainModelSurfaceAndVolume* bmsv, const bool drawTheSurface, const bool surfaceInVolumeAllViewFlag); /// draw surface and volume void drawBrainModelSurfaceAndVolume(BrainModelSurfaceAndVolume* bmsv); /// draw volume void drawBrainModelVolume(BrainModelVolume* bmv); /// draw volume in montage void drawBrainModelVolumeMontage(BrainModelVolume* bmv); /// draw volume with all axis void drawBrainModelVolumeAllAxis(BrainModelVolume* bmv); /// draw volume with oblique axis montage void drawBrainModelVolumeObliqueAxisMontage(BrainModelVolume* bmv, const bool selectFlag); /// draw volume with oblique axis void drawBrainModelVolumeObliqueAxis(BrainModelVolume* bmv); /// draw volume with oblique ALL axis void drawBrainModelVolumeObliqueAllAxis(BrainModelVolume* bmv); /// draw volume with oblique axis slice void drawBrainModelVolumeObliqueAxisSlice(BrainModelVolume* bmv, VolumeFile::VOLUME_AXIS axis, const int montageOffset, const bool selectFlag); /// Draw volume crosshairs void drawVolumeCrosshairs(BrainModelVolume* bmv, const VolumeFile* vf, const VolumeFile::VOLUME_AXIS volumeSliceAxis); /// Draw volume crosshair coordinates void drawVolumeCrosshairCoordinates(BrainModelVolume* bmv, const VolumeFile* vf, const int viewportHeight); /// Draw the volume cropping lines void drawVolumeCroppingLines(BrainModelVolume* bmv, VolumeFile* vf, VolumeFile::VOLUME_AXIS volumeSliceAxis); /// stuff for web caret void webCaretCommon(BrainSet* bs, const int viewport[4]); /// Create a sphere quadric and put it in a display list. void createSphereQuadricAndDisplayList(); /// Create a disk quadric and put it in a display list. void createDiskQuadricAndDisplayList(); /// Create a cone quadic and put it in a display list void createConeQuadricAndDisplayList(); /// Create a cylinder quadric and put it in a display list void createCylinderQuadricAndDisplayList(); /// Create a square and put it in a display list void createSquareDisplayList(); /// Create a box and put it in a display list void createBoxDisplayList(); /// Create a ring and put it in a display list void createRingQuadricAndDisplayList(); /// Create a diamond and put it in a display list void createDiamondQuadricAndDisplayList(); /// Execute OpenGL commands to draw a sphere. void drawingCommandsSphere(); /// Execute OpenGL commands to draw a disk. void drawingCommandsDisk(); /// Execute OpenGL commands to draw a cone void drawingCommandsCone(); /// Execute OpenGL commands to draw a cylinder void drawingCommandsCylinder(); /// Execute OpenGL commands to draw a box void drawingCommandsBox(); /// Execute OpenGL commands to draw a ring void drawingCommandsRing(); /// Execute OpenGL commands to draw a diamond void drawingCommandsDiamond(); /// Execute OpenGL commands to draw a square void drawingCommandsSquare(); /// Draw the surface as points. void drawSurfaceNodes(const BrainModelSurfaceNodeColoring* bs, const int modelNumber, const CoordinateFile* cf, const int numCoords, const bool drawInSurfaceEditColor); /// Draw the surface as links. void drawSurfaceLinks(const BrainModelSurfaceNodeColoring* bs, const int modelNumber, const CoordinateFile* cf, const TopologyFile* tf, const int numTiles, const bool drawEdgesOnly, const bool drawInSurfaceEditColor); /// Draw the surface as links with hidden line removal. void drawSurfaceLinksNoBackside(const BrainModelSurfaceNodeColoring* bs, const int modelNumber, const CoordinateFile* cf, const TopologyFile* tf, const int numTiles); /// Draw the surface as tiles, possibly with lighting. void drawSurfaceTiles(const BrainModelSurfaceNodeColoring* bs, const BrainModelSurface* s, const CoordinateFile* cf, TopologyFile* tf, const int numTiles, const int numCoords); /// Draw the surface normals void drawSurfaceNormals(const BrainModelSurface* bms, const CoordinateFile* cf, const int numCoords); /// Draw the surface forces void drawSurfaceForces(const CoordinateFile* cf, const int numCoords); /// draw a sphere void drawSphere(const float diameter); /// draw a 2D disk (filled circle) void drawDisk(const float diameter); /// draw a cone void drawCone(); /// draw cylinder void drawCylinder(); /// draw a box void drawBox(); /// draw a ring void drawRing(); /// draw a square void drawSquare(); /// draw a diamond void drawDiamond(); /// draw a symbol void drawSymbol(const ColorFile::ColorStorage::SYMBOL symbol, const float x, const float y, const float z, const float size, const BrainModel* bm); /// Draw node highlighting. void drawNodeHighlighting(const BrainModelSurface* bms, const int numCoords); /// Draw Surface ROI members. void drawSurfaceROIMembers(const BrainModelSurface* bms, const int numCoords); /// Draw a transformation cell or foci file void drawTransformationCellOrFociFile(BrainModel* bm, CellFile* cellFile, ColorFile* colorFile, const DisplaySettingsCells* dsc, const int transformFileNumber, const int selectionMask); // Draw a cell or foci projection file void drawCellOrFociProjectionFile(BrainModelSurface* bms, CellProjectionFile* cellProjectionFile, ColorFile* colorFile, const DisplaySettingsCells* dsc, const bool fociFileFlag); /// Draw cell projection and foci projections void drawCellAndFociProjections(BrainModelSurface* s); /// draw the geodesic path. void drawGeodesicPath(const CoordinateFile* cf); /// Draw a surface outline and transform axes over the volume. void drawVolumeSurfaceOutlineAndTransformationMatrixAxes( const BrainModelVolume* bmv, const VolumeFile::VOLUME_AXIS axis, const float axisCoord); /// Draw a cuts file. void drawCuts(); /// Draw the borders. void drawBorders(BrainModelSurface* s); /// draw main window caption void drawMainWindowCaption(); /// Draw the Surface Shape palette colorbar. void drawShapePalette(const int modelNumber); /// Draw the metric's palette colorbar. void drawMetricPalette(const int modelNumber, const bool surfaceFlag); /// Display a QImage in the OpenGL window. void displayAnImage(QImage* image); /// Display background and splash images void displayImages(); /// Draw the linear object (typically used while drawing borders) void drawLinearObject(); /// Draw transformation data files void drawTransformationDataFiles(const TransformationMatrix* tm); /// Draw all the VTK models. void drawAllVtkModels(); /// Draw a VTK model file void drawVtkModelFile(VtkModelFile* vmf, const int modelNum); /// Draw the transformation axes void drawTransformationMatrixAxes(const BrainModel* bm); /// Draw the surface axes void drawSurfaceAxes(const BrainModelSurface* bms); /// Draw the deformation field vectors. void drawDeformationFieldVectors(BrainModelSurface* bms); /// Draw the vectors in 3d void drawVectorFile3D(BrainModelSurface* bms); /// check a vectors orientation (true if orientation is valid for display) bool checkVectorOrientation(const float vector[3]); /// Draw an arrow symbol void drawArrowSymbol(const float xyz[3], const float tipXYZ[3], const float radius); /// Draw a cylinder symbol void drawCylinderSymbol(const float xyz[3], const float tipXYZ[3], const float radius); /// Draw the volume foci file. void drawVectorsOnVolume(const VolumeFile::VOLUME_AXIS axis, const float axisCoord, const float voxelSize); /// Convert from volume item XYZ to screen XYZ void convertVolumeItemXYZToScreenXY(const VolumeFile::VOLUME_AXIS axis, float xyz[3]); /// Draw the volume border file void drawVolumeBorderFile(const VolumeFile::VOLUME_AXIS axis, const float axisCoord, const float voxelSize); /// Draw the volume contour file void drawVolumeContourFile(const VolumeFile::VOLUME_AXIS axis, const float axisCoord, const float voxelSize); /// Draw the volume cell file void drawVolumeCellFile(const VolumeFile::VOLUME_AXIS axis, const float axisCoord, const float voxelSize); /// Draw the volume foci file void drawVolumeFociFile(const VolumeFile::VOLUME_AXIS axis, const float axisCoord, const float voxelSize); /// Draw the oblique volume cell file void drawObliqueVolumeCellFile(const VolumeFile::VOLUME_AXIS axis, const CellFile* cf, const DisplaySettingsCells* dsc, const ColorFile* colorFile, const float voxelSize, const TransformationMatrix* tm, const float sliceCornerCoords[4][3], const int transformDataFileIndex = -1); /// Draw the oblique volume foci file void drawObliqueVolumeFociFile(const VolumeFile::VOLUME_AXIS axis, const float voxelSize, const TransformationMatrix* tm, const float sliceCornerCoords[4][3]); /// Draw the oblique volume contour file. void drawObliqueContourFile(const VolumeFile::VOLUME_AXIS axis, const ContourFile* cf, const float voxelSize, const TransformationMatrix* tm, const float sliceCornerCoords[4][3]); /// Draw the volume identify symbols void drawVolumeIdentifySymbols(const VolumeFile::VOLUME_AXIS axis, const float axisCoord); /// Draw a volume file slice void drawVolumeFileSlice(VolumeFile* vf, const VolumeFile::VOLUME_AXIS axis, const int currentSlice, const unsigned long maskForThisUnderlayOrOverlay, const bool overlayFlag); /// Draw the contours that are being aligned. void drawModelContoursAlignment(BrainModelContours* bmc, const int alignmentSectionNumber); /// process hits made while selecting objects with mouse void processSelectedItems(const int numItems); /// Draw a volume slice void drawVolumeSliceOverlayAndUnderlay(BrainModelVolume* bmv, const VolumeFile::VOLUME_AXIS volumeSliceAxis, const int currentSlice, VolumeFile* &firstVolume); /// check for an OpenGL Error void checkForOpenGLError(const BrainModel* bm, const QString& msg = ""); /// get valid line width GLfloat getValidLineWidth(const GLfloat widthIn) const; /// get valid point size GLfloat getValidPointSize(const GLfloat pointSizeIn) const; // enable the surface clipping planes void enableSurfaceClippingPlanes(BrainModelSurface* bms); // disable the surface clipping planes void disableSurfaceClippingPlanes(); /// linear (border, cut, contour) being drawn Border linearObjectBeingDrawn; /// resampling density of linear object being drawn float linearObjectBeingDrawnSampling; /// linear object augment border count int linearObjectAugmentBorderCount; /// draw linear object flag bool drawLinearObjectOnly; /// draw image sub region box bool drawImageSubRegionBoxFlag; /// image sub region box int imageSubRegionBox[4]; /// quadric containing a sphere GLUquadricObj* sphereQuadric; /// quadric containing a 2D disk (filled circle) GLUquadricObj* diskQuadric; /// quadric containing a cone GLUquadricObj* coneQuadric; /// quadric containing a cylinder GLUquadricObj* cylinderQuadric; /// quadric containing a diamond GLUquadricObj* diamondQuadric; /// quadric containing a ring GLUquadricObj* ringQuadric; /// display list containing a sphere GLuint sphereDisplayList; /// display list containing a 2D disk (filled circle) GLuint diskDisplayList; /// display list containing a cone GLuint coneDisplayList; /// display list for a cylinder GLuint cylinderDisplayList; /// display list for a square GLuint squareDisplayList; /// display list for a box GLuint boxDisplayList; /// display list for a diamond GLuint diamondDisplayList; /// display list for a ring GLuint ringDisplayList; /// version number of OpenGL static float versionOfOpenGL; /// the brain set BrainSet* brainSet; /// the selection mask unsigned long selectionMask; /// node special highlighting (used when adding tiles with mouse) std::vector nodeSpecialHighlighting; /// the main window flag bool mainWindowFlag; /// the viewport int viewport[4]; /// QT OpenGL widget being drawn into (may be NULL) QGLWidget* glWidget; /// selection x coordinate int selectionX; /// selection y coordinate int selectionY; /// viewing window number (0 = main window) int viewingWindowNumber; /// default orthographic window size static float defaultOrthoWindowSize; /// orthographic projection box for model double orthographicLeft[BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS]; double orthographicRight[BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS]; double orthographicBottom[BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS]; double orthographicTop[BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS]; double orthographicFar[BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS]; double orthographicNear[BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS]; /// Modelview matrix created when display last drawn. /// Used for projecting items selected with the mouse. GLdouble selectionModelviewMatrix[BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS][16]; /// Projection matrix created when last resize event received. /// Used for projecting items selected with the mouse. GLdouble selectionProjectionMatrix[BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS][16]; /// Viewport set when last resize event received. /// Used for projecting items selected with the mouse. GLint selectionViewport[BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS][4]; /// Mutex to allow only one model to be drawn at a time QMutex paintMutex; /// volume slice axis //VolumeFile::VOLUME_AXIS volumeSliceAxis; /// volume slice coordinate float volumeSliceCoordinate; /// editing segmentation volume flag bool editingSegmentationVolumeFlag; /// editing paint volume flag bool editingPaintVolumeFlag; /// selection buffer size enum { SELECTION_BUFFER_SIZE = 5000}; /// selection buffer GLuint selectionBuffer[SELECTION_BUFFER_SIZE]; /// selected node BrainModelOpenGLSelectedItem selectedNode; /// selected border (first) BrainModelOpenGLSelectedItem selectedBorder1; /// selected border (second) BrainModelOpenGLSelectedItem selectedBorder2; /// selected border (volume) BrainModelOpenGLSelectedItem selectedVolumeBorder; /// selected cell projection BrainModelOpenGLSelectedItem selectedCellProjection; /// selected cell (volume) BrainModelOpenGLSelectedItem selectedVolumeCell; /// selected cut BrainModelOpenGLSelectedItem selectedCut; /// selected foci projection BrainModelOpenGLSelectedItem selectedFocusProjection; /// selected foci (volume) BrainModelOpenGLSelectedItem selectedVolumeFoci; /// selected palette for metric BrainModelOpenGLSelectedItem selectedPaletteMetric; /// selected palette for shape BrainModelOpenGLSelectedItem selectedPaletteShape; /// selected contour BrainModelOpenGLSelectedItem selectedContour; /// selected contour cell BrainModelOpenGLSelectedItem selectedContourCell; /// selected voxel underlay BrainModelOpenGLSelectedItem selectedVoxelUnderlay; /// selected voxel overlay secondary BrainModelOpenGLSelectedItem selectedVoxelOverlaySecondary; /// selected voxel overlay primary BrainModelOpenGLSelectedItem selectedVoxelOverlayPrimary; /// selected functional voxel (surface and volume cloud) BrainModelOpenGLSelectedItem selectedVoxelFunctionalCloud; /// selected surface tile BrainModelOpenGLSelectedItem selectedSurfaceTile; /// selected link (index 1 & 2 are nodes) BrainModelOpenGLSelectedItem selectedLink; /// selected transformation axes BrainModelOpenGLSelectedItem selectedTransformationMatrixAxes; /// selected vtk model BrainModelOpenGLSelectedItem selectedVtkModel; /// selected transform cell BrainModelOpenGLSelectedItem selectedTransformCell; /// selected transform foci BrainModelOpenGLSelectedItem selectedTransformFoci; /// selected transform contour BrainModelOpenGLSelectedItem selectedTransformContour; /// selected transform contour cell BrainModelOpenGLSelectedItem selectedTransformContourCell; /// the brain model being drawn BrainModel* brainModel; /// all brain models displayed in windows for identification /// ONLY VALID WHEN ::identifyBrainModel... called BrainModel* allWindowBrainModelsForIdentification[BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS]; /// disable clearing flag (used my draw all fiducial mode) bool disableClearingFlag; /// initialization completed flag bool initializationCompletedFlag; /// offScreen rendering (WebCaret, caret_command) bool offScreenRenderingFlag; /// use display lists for shapes (spheres, boxes, rings, etc) bool useDisplayListsForShapes; /// surface edit drawing color static unsigned char surfaceEditDrawColor[3]; /// stippling for polygon static GLubyte polygonStipple[128]; /// OpenGL text enabled static bool openGLTextEnabledFlag; /// maximum point size float maximumPointSize; /// minimum point size float minimumPointSize; /// maximum line width float maximumLineWidth; /// minimum line width float minimumLineWidth; /// caption displayed in main window QString mainWindowCaption; }; #ifdef __BRAIN_MODEL_OPENGL_MAIN__ float BrainModelOpenGL::versionOfOpenGL = 0.0; float BrainModelOpenGL::defaultOrthoWindowSize = 125.0; unsigned char BrainModelOpenGL::surfaceEditDrawColor[3] = { 0, 0, 255 }; GLubyte BrainModelOpenGL::polygonStipple[128]; bool BrainModelOpenGL::openGLTextEnabledFlag = true; #endif // __BRAIN_MODEL_OPENGL_MAIN__ #endif // __BRAIN_MODEL_OPENGL_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelOpenGL.cxx0000664000175000017500000156617411572067322023536 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #ifdef Q_OS_WIN32 #define NOMINMAX #endif #include "AreaColorFile.h" #include "BorderColorFile.h" #include "BrainModel.h" #include "BrainModelContours.h" #include "BrainModelIdentification.h" #define __BRAIN_MODEL_OPENGL_MAIN__ #include "BrainModelOpenGL.h" #undef __BRAIN_MODEL_OPENGL_MAIN__ #include "BrainModelSurface.h" #include "BrainModelSurfaceAndVolume.h" #include "BrainModelSurfaceNodeColoring.h" #include "BrainModelSurfacePointProjector.h" #include "BrainModelSurfaceROINodeSelection.h" #include "BrainModelVolume.h" #include "BrainModelVolumeRegionOfInterest.h" #include "BrainModelVolumeVoxelColoring.h" #include "BrainSet.h" #include "BrainSetNodeAttribute.h" #include "CellColorFile.h" #include "CellFile.h" #include "ColorFile.h" #include "ContourCellColorFile.h" #include "ContourCellFile.h" #include "CutsFile.h" #include "DebugControl.h" #include "DeformationFieldFile.h" #include "DisplaySettingsDeformationField.h" #include "DisplaySettingsBorders.h" #include "DisplaySettingsCells.h" #include "DisplaySettingsCoCoMac.h" #include "DisplaySettingsContours.h" #include "DisplaySettingsCuts.h" #include "DisplaySettingsFoci.h" #include "DisplaySettingsGeodesicDistance.h" #include "DisplaySettingsImages.h" #include "DisplaySettingsMetric.h" #include "DisplaySettingsSurface.h" #include "DisplaySettingsSurfaceShape.h" #include "DisplaySettingsVectors.h" #include "DisplaySettingsVolume.h" #include "DisplaySettingsModels.h" #include "FileUtilities.h" #include "FociColorFile.h" #include "FociFile.h" #include "FociProjectionFile.h" #include "GeodesicDistanceFile.h" #include "MathUtilities.h" #include "PaletteFile.h" #include "SectionFile.h" #include "SurfaceShapeFile.h" #include "VectorFile.h" #include "TopologyHelper.h" #include "TransformationMatrixFile.h" #include "VtkModelFile.h" #include "vtkMath.h" #include "vtkTransform.h" #include "vtkTriangle.h" /* Number of slices used in Cylinder,Disk,Cone quadrics */ static const int QUADRIC_NUMBER_OF_SLICES = 4; /** * Constructor. */ BrainModelOpenGL::BrainModelOpenGL() { initializationCompletedFlag = false; offScreenRenderingFlag = false; useDisplayListsForShapes = true; disableClearingFlag = false; brainSet = NULL; sphereQuadric = NULL; diskQuadric = NULL; coneQuadric = NULL; cylinderQuadric = NULL; diamondQuadric = NULL; ringQuadric = NULL; boxDisplayList = 0; coneDisplayList = 0; diamondDisplayList = 0; cylinderDisplayList = 0; diskDisplayList = 0; ringDisplayList = 0; sphereDisplayList = 0; squareDisplayList = 0; selectionMask = SELECTION_MASK_OFF; nodeSpecialHighlighting.clear(); drawLinearObjectOnly = false; //qt4if (paintMutex.locked()) { // paintMutex.unlock(); //qt4} drawImageSubRegionBoxFlag = false; static bool firstTime = true; if (firstTime) { for (int i = 0; i < 16; i++) { const int indx = i * 8; polygonStipple[indx+0] = 0xAA; polygonStipple[indx+1] = 0xAA; polygonStipple[indx+2] = 0xAA; polygonStipple[indx+3] = 0xAA; polygonStipple[indx+4] = 0x55; polygonStipple[indx+5] = 0x55; polygonStipple[indx+6] = 0x55; polygonStipple[indx+7] = 0x55; } } firstTime = false; } /** * Destructor. */ BrainModelOpenGL::~BrainModelOpenGL() { if (sphereQuadric != NULL) { gluDeleteQuadric(sphereQuadric); sphereQuadric = NULL; } if (diskQuadric != NULL) { gluDeleteQuadric(diskQuadric); diskQuadric = NULL; } if (coneQuadric != NULL) { gluDeleteQuadric(coneQuadric); coneQuadric = NULL; } if (cylinderQuadric != NULL) { gluDeleteQuadric(cylinderQuadric); cylinderQuadric = NULL; } if (diamondQuadric != NULL) { gluDeleteQuadric(diamondQuadric); diamondQuadric = NULL; } if (ringQuadric != NULL) { gluDeleteQuadric(ringQuadric); ringQuadric = NULL; } /* if (sphereDisplayList > 0) { glDeleteLists(sphereDisplayList, 1); sphereDisplayList = 0; } if (diskDisplayList > 0) { glDeleteLists(diskDisplayList, 1); diskDisplayList = 0; } */ } /** * stuff for web caret. */ void BrainModelOpenGL::webCaretCommon(BrainSet* bs, const int viewport[4]) { offScreenRenderingFlag = true; PreferencesFile* pf = bs->getPreferencesFile(); pf->setDisplayListsEnabled(false); useDisplayListsForShapes = false; initializeOpenGL(true); updateOrthoSize(0, viewport[2], viewport[3]); bs->setDisplaySplashImage(false); } /** * Draw a brain model for WebCaret. */ void BrainModelOpenGL::drawBrainModelWebCaret(BrainSet* bs, BrainModel* bm, const int viewingWindowNumberIn, const int viewportIn[4]) { webCaretCommon(bs, viewportIn); drawBrainModel(bs, bm, viewingWindowNumberIn, viewportIn, NULL); } /** * select (Identify) something in the brain model for WebCaret. */ void BrainModelOpenGL::selectBrainModelItemWebCaret(BrainSet* bs, BrainModel* bm, const int viewportIn[4], const unsigned long selectionMaskIn, const int selectionXIn, const int selectionYIn) { webCaretCommon(bs, viewportIn); selectBrainModelItem(bs, bm, 0, viewportIn, NULL, selectionMaskIn, selectionXIn, selectionYIn, true); } /** * Identify something in the brain model for WebCaret. */ QString BrainModelOpenGL::identifyBrainModelItemWebCaret(BrainSet* bs, BrainModel* bm, const int viewingWindowNumberIn, const int viewportIn[4], const unsigned long selectionMaskIn, const int selectionXIn, const int selectionYIn, const bool enableHtml, const bool enableVocabularyLinks) { webCaretCommon(bs, viewportIn); BrainModel* allWindowBrainModelsForIdentification[BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS]; for (int i = 0; i < BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS; i++) { allWindowBrainModelsForIdentification[i] = NULL; } allWindowBrainModelsForIdentification[BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW] = bm; return identifyBrainModelItem(bs, bm, allWindowBrainModelsForIdentification, viewingWindowNumberIn, viewportIn, NULL, selectionMaskIn, selectionXIn, selectionYIn, true, enableHtml, enableVocabularyLinks); } /** * all brain models displayed in windows for identification * ONLY VALID WHEN ::identifyBrainModel... called */ BrainModel* BrainModelOpenGL::getBrainModelInWindowNumberForIdentification(const int windowNumber) { return allWindowBrainModelsForIdentification[windowNumber]; } /** * Draw a brain model. */ void BrainModelOpenGL::drawBrainModel(BrainSet* bs, BrainModel* bm, const int viewingWindowNumberIn, const int viewportIn[4], QGLWidget* glWidgetIn) { brainSet = bs; selectionMask = SELECTION_MASK_OFF; drawBrainModelPrivate(bm, viewingWindowNumberIn, viewportIn, glWidgetIn); brainSet = NULL; } /** * Draw all fiducial surface brain models. */ void BrainModelOpenGL::drawAllFiducialSurfaceBrainModels(std::vector brainSetsIn, const int viewingWindowNumberIn, const int viewportIn[4], QGLWidget* glWidgetIn) { selectionMask = SELECTION_MASK_OFF; QString firstFiducialTransforms; bool firstFiducialFlag = true; // // loop through brain sets looking for fiducial surfaces // for (unsigned int i = 0; i < brainSetsIn.size(); i++) { BrainModelSurface* bms = brainSetsIn[i]->getActiveFiducialSurface(); if (bms != NULL) { brainSet = brainSetsIn[i]; // // If not the first fiducial surface, replace its transforms with // those from the first fiducial surface // const QString savedTransformations = bms->getTransformationsAsString(viewingWindowNumberIn); if (firstFiducialFlag == false) { bms->setTransformationsAsString(viewingWindowNumberIn, firstFiducialTransforms); } // // Draw the fiducial surface // drawBrainModelPrivate(bms, viewingWindowNumberIn, viewportIn, glWidgetIn); // // Was this the first fiducial surface ? // if (firstFiducialFlag) { // // Save its transformations and disable clearing // firstFiducialTransforms = bms->getTransformationsAsString(viewingWindowNumberIn); firstFiducialFlag = false; disableClearingFlag = true; } else { // // Restore transformations // bms->setTransformationsAsString(viewingWindowNumberIn, savedTransformations); } } } brainSet = NULL; disableClearingFlag = false; } /** * Draw a brain model. */ void BrainModelOpenGL::drawBrainModelPrivate(BrainModel* bm, const int viewingWindowNumberIn, const int viewportIn[4], QGLWidget* glWidgetIn) { if (DebugControl::getOpenGLDebugOn()) { checkForOpenGLError(bm, "At beginning of drawBrainModelPrivate()"); } brainModel = bm; mainWindowFlag = (viewingWindowNumberIn == 0); viewport[0] = viewportIn[0]; viewport[1] = viewportIn[1]; viewport[2] = viewportIn[2]; viewport[3] = viewportIn[3]; viewingWindowNumber = viewingWindowNumberIn; glWidget = glWidgetIn; // // No text will be drawn if (glWidget == NULL) // if (openGLTextEnabledFlag == false) { glWidget = NULL; } if (DebugControl::getOpenGLDebugOn()) { checkForOpenGLError(bm, "In drawBrainModelPrivate() before viewport set"); } glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); selectionViewport[viewingWindowNumber][0] = viewport[0]; selectionViewport[viewingWindowNumber][1] = viewport[1]; selectionViewport[viewingWindowNumber][2] = viewport[2]; selectionViewport[viewingWindowNumber][3] = viewport[3]; if (DebugControl::getOpenGLDebugOn()) { checkForOpenGLError(bm, "In drawBrainModelPrivate() after viewport set"); } if (mainWindowFlag) { brainSet->updateNodeDisplayFlags(); } paintMutex.lock(); glMatrixMode(GL_MODELVIEW); PreferencesFile* pf = brainSet->getPreferencesFile(); if (brainSet->getDisplaySplashImage()) { glClearColor(1.0, 1.0, 1.0, 0.0); } else { unsigned char rb, gb, bb; pf->getSurfaceBackgroundColor(rb, gb, bb); const float bg[3] = { static_cast(rb) / 255.0, static_cast(gb) / 255.0, static_cast(bb) / 255.0 }; glClearColor(bg[0], bg[1], bg[2], 0.0); } if (DebugControl::getOpenGLDebugOn()) { checkForOpenGLError(bm, "In drawBrainModelPrivate() after glClear()"); } glPushMatrix(); glLoadIdentity(); float lightPosition[4]; pf->getLightPosition(lightPosition[0], lightPosition[1], lightPosition[2]); lightPosition[3] = 0.0; 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(); if (DebugControl::getOpenGLDebugOn()) { checkForOpenGLError(bm, "In drawBrainModelPrivate() after lighting"); } // // if this flag is set, we are only drawing the linear object and leaving // the previously drawn display as it was. // if (disableClearingFlag == false) { if (drawLinearObjectOnly == false) { if (selectionMask != SELECTION_MASK_OFF) { // // Not clearing color buffer prevents flashing when ID'ing a volume slice voxel // glClear(GL_DEPTH_BUFFER_BIT); } else { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } } } glLoadIdentity(); if (mainWindowFlag) { displayImages(); } if (DebugControl::getOpenGLDebugOn()) { checkForOpenGLError(bm, "In drawBrainModelPrivate() after image display"); } if (bm != NULL) { switch (bm->getModelType()) { case BrainModel::BRAIN_MODEL_CONTOURS: drawBrainModelContours(dynamic_cast(bm)); break; case BrainModel::BRAIN_MODEL_SURFACE: drawBrainModelSurface(dynamic_cast(bm), NULL, true, false); break; case BrainModel::BRAIN_MODEL_VOLUME: drawBrainModelVolume(dynamic_cast(bm)); break; case BrainModel::BRAIN_MODEL_SURFACE_AND_VOLUME: drawBrainModelSurfaceAndVolume(dynamic_cast(bm)); break; } } if (mainWindowFlag) { drawMainWindowCaption(); } if (drawImageSubRegionBoxFlag) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0.0, static_cast(viewport[2]), 0.0, static_cast(viewport[3]), -1.0, 1.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glColor3f(1.0, 0.0, 0.0); const int x1 = std::min(imageSubRegionBox[0], imageSubRegionBox[2]); const int x2 = std::max(imageSubRegionBox[0], imageSubRegionBox[2]); const int y1 = std::min(imageSubRegionBox[1], imageSubRegionBox[3]); const int y2 = std::max(imageSubRegionBox[1], imageSubRegionBox[3]); GLboolean depthBufferOn = glIsEnabled(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST); glLineWidth(getValidLineWidth(1.0)); glBegin(GL_LINE_LOOP); glVertex2i(x1, y1); glVertex2i(x2, y1); glVertex2i(x2, y2); glVertex2i(x1, y2); glEnd(); if (depthBufferOn) { glEnable(GL_DEPTH_TEST); } } /** GLenum errorCode = glGetError(); if (errorCode != GL_NO_ERROR) { std::cout << std::endl; std::cout << "OpenGL Error: " << (char*)gluErrorString(errorCode) << std::endl; if (bm != NULL) { std::cout << "While drawing brain model " << bm->getDescriptiveName().toAscii().constData() << std::endl; } std::cout << "In window number " << viewingWindowNumber << std::endl; GLint nameStackDepth, modelStackDepth, projStackDepth; glGetIntegerv(GL_PROJECTION_STACK_DEPTH, &projStackDepth); glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &modelStackDepth); glGetIntegerv(GL_NAME_STACK_DEPTH, &nameStackDepth); std::cout << "Projection Matrix Stack Depth " << projStackDepth << std::endl; std::cout << "Model Matrix Stack Depth " << modelStackDepth << std::endl; std::cout << "Name Matrix Stack Depth " << nameStackDepth << std::endl; std::cout << std::endl; } */ glFlush(); paintMutex.unlock(); checkForOpenGLError(bm, "At end of drawBrainModelPrivate()."); } /** * check for an OpenGL Error. */ void BrainModelOpenGL::checkForOpenGLError(const BrainModel* bm, const QString& msg) { GLenum errorCode = glGetError(); if (errorCode != GL_NO_ERROR) { std::cout << std::endl; std::cout << "OpenGL Error: " << (char*)gluErrorString(errorCode) << std::endl; std::cout << "OpenGL Version: " << (char*)(glGetString(GL_VERSION)) << std::endl; std::cout << "OpenGL Vendor: " << (char*)(glGetString(GL_VENDOR)) << std::endl; if (msg.isEmpty() == false) { std::cout << msg.toAscii().constData() << std::endl; } if (bm != NULL) { std::cout << "While drawing brain model " << bm->getDescriptiveName().toAscii().constData() << std::endl; } std::cout << "In window number " << viewingWindowNumber << std::endl; GLint nameStackDepth, modelStackDepth, projStackDepth; glGetIntegerv(GL_PROJECTION_STACK_DEPTH, &projStackDepth); glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &modelStackDepth); glGetIntegerv(GL_NAME_STACK_DEPTH, &nameStackDepth); std::cout << "Projection Matrix Stack Depth " << projStackDepth << std::endl; std::cout << "Model Matrix Stack Depth " << modelStackDepth << std::endl; std::cout << "Name Matrix Stack Depth " << nameStackDepth << std::endl; std::cout << std::endl; } } /** * initialize OpenGL (should only call one time). */ void BrainModelOpenGL::initializeOpenGL(const bool offScreenRenderingFlagIn) { offScreenRenderingFlag = offScreenRenderingFlagIn; if (versionOfOpenGL == 0.0) { // // Note: The version string might be something like 1.2.4. std::atof() // will get just the 1.2 which is okay. // const char* versionStr = (char*)(glGetString(GL_VERSION)); versionOfOpenGL = std::atof(versionStr); } drawImageSubRegionBoxFlag = false; glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); glClearDepth(1.0); glFrontFace(GL_CCW); #ifndef GL_VERSION_1_3 glEnable(GL_NORMALIZE); #else if (versionOfOpenGL >= 1.3) { glEnable(GL_RESCALE_NORMAL); } else { glEnable(GL_NORMALIZE); } #endif // glEnable(GL_CULL_FACE); // glCullFace(GL_BACK); glShadeModel(GL_SMOOTH); glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE); glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_FALSE); const GLfloat lightColor[4] = { 0.9, 0.9, 0.9, 1.0 }; glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor); glLightfv(GL_LIGHT1, GL_DIFFUSE, lightColor); glEnable(GL_LIGHT0); glDisable(GL_LIGHT1); const GLfloat materialColor[4] = { 0.8, 0.8, 0.8, 1.0 }; glMaterialfv(GL_FRONT, GL_DIFFUSE, materialColor); glColorMaterial(GL_FRONT, GL_DIFFUSE); const GLfloat ambient[4] = { 0.8, 0.8, 0.8, 1.0 }; glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient); createBoxDisplayList(); createConeQuadricAndDisplayList(); createCylinderQuadricAndDisplayList(); createDiamondQuadricAndDisplayList(); createDiskQuadricAndDisplayList(); createRingQuadricAndDisplayList(); createSphereQuadricAndDisplayList(); createSquareDisplayList(); float sizes[2]; glGetFloatv(GL_POINT_SIZE_RANGE, sizes); minimumPointSize = sizes[0]; maximumPointSize = sizes[1]; glGetFloatv(GL_LINE_WIDTH_RANGE, sizes); minimumLineWidth = sizes[0]; maximumLineWidth = sizes[1]; initializationCompletedFlag = true; } /** * get minimum/maximum point size. */ void BrainModelOpenGL::getMinMaxPointSize(float& minSizeOut, float& maxSizeOut) { float sizes[2]; glGetFloatv(GL_POINT_SIZE_RANGE, sizes); minSizeOut = sizes[0]; maxSizeOut = sizes[1]; } /** * get minimum/maximum line width. */ void BrainModelOpenGL::getMinMaxLineWidth(float& minWidthOut, float& maxWidthOut) { float sizes[2]; glGetFloatv(GL_LINE_WIDTH_RANGE, sizes); minWidthOut = sizes[0]; maxWidthOut = sizes[1]; } /** * draw contours. */ void BrainModelOpenGL::drawBrainModelContours(BrainModelContours* bmc) { const DisplaySettingsContours* dsc = brainSet->getDisplaySettingsContours(); // // See if contours are being aligned // bool aligningContours = dsc->getAlignmentContourValid(); int alignmentSectionNumber = dsc->getAlignmentContourNumber(); // // Don't set projection matrix when selecting // if (selectionMask == SELECTION_MASK_OFF) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(orthographicLeft[viewingWindowNumber], orthographicRight[viewingWindowNumber], orthographicBottom[viewingWindowNumber], orthographicTop[viewingWindowNumber], orthographicNear[viewingWindowNumber], orthographicFar[viewingWindowNumber]); glGetDoublev(GL_PROJECTION_MATRIX, selectionProjectionMatrix[viewingWindowNumber]); } glMatrixMode(GL_MODELVIEW); glLoadIdentity(); float translate[3]; bmc->getTranslation(viewingWindowNumber, translate); glTranslatef(translate[0], translate[1], translate[2]); // // Origin cross (do before rotation and scaling) // if (dsc->getDisplayCrossAtOrigin()) { unsigned char r, g, b; PreferencesFile* pref = brainSet->getPreferencesFile(); pref->getSurfaceForegroundColor(r, g, b); glColor3ub(r, g, b); const float length = orthographicRight[viewingWindowNumber] * 0.20; glBegin(GL_LINES); const float z = 10.0 - orthographicFar[viewingWindowNumber]; glVertex3f(-length, 0.0, z); glVertex3f( length, 0.0, z); glVertex3f(0.0, -length, z); glVertex3f(0.0, length, z); glEnd(); } float matrix[16]; bmc->getRotationMatrix(viewingWindowNumber, matrix); glMultMatrixf(matrix); float scale[3]; bmc->getScaling(viewingWindowNumber, scale); glScalef(scale[0], scale[1], scale[2]); // // Save modeling matrix // if (selectionMask == SELECTION_MASK_OFF) { glGetDoublev(GL_MODELVIEW_MATRIX, selectionModelviewMatrix[viewingWindowNumber]); } // // If this flag is set we only want to draw the linear object. When this // flag is set, glClear() is not called so the previous stuff is not erased. // if (drawLinearObjectOnly) { glDisable(GL_DEPTH_TEST); const int num = linearObjectBeingDrawn.getNumberOfLinks(); glPointSize(getValidPointSize(2.0)); glColor3f(1.0, 0.0, 0.0); glBegin(GL_POINTS); for (int i = 0; i < num; i++) { glVertex3fv(linearObjectBeingDrawn.getLinkXYZ(i)); } glEnd(); glEnable(GL_DEPTH_TEST); //return; } const ContourFile* cf = bmc->getContourFile(); const int numContours = cf->getNumberOfContours(); const float spacing = cf->getSectionSpacing(); const int minimumSection = cf->getMinimumSelectedSection(); const int maximumSection = cf->getMaximumSelectedSection(); const ContourCellFile* cellFile = brainSet->getContourCellFile(); const int numCells = cellFile->getNumberOfCells(); const ContourCellColorFile* colorFile = brainSet->getContourCellColorFile(); const int numColors = colorFile->getNumberOfColors(); // // Are contours hidden ? // const bool hideContours = (cf->getSectionType() == ContourFile::SECTION_TYPE_HIDE); // // Set color for cells with missing colors // unsigned char noColorRed, noColorGreen, noColorBlue; PreferencesFile* pref = brainSet->getPreferencesFile(); pref->getSurfaceForegroundColor(noColorRed, noColorGreen, noColorBlue); const float cellSize = dsc->getContourCellSize(); glPointSize(getValidPointSize(dsc->getPointSize())); glLineWidth(getValidLineWidth(dsc->getLineThickness())); if (hideContours == false) { if (selectionMask & SELECTION_MASK_CONTOUR) { glPushName(SELECTION_MASK_CONTOUR); for (int i = 0; i < numContours; i++) { const CaretContour* contour = cf->getContour(i); const int sectionNumber = contour->getSectionNumber(); if ((sectionNumber >= minimumSection) && (sectionNumber <= maximumSection)) { const int numPoints = contour->getNumberOfPoints(); const float z = sectionNumber * spacing; glPushName(i); for (int j = 0; j < numPoints; j++) { float x, y; contour->getPointXY(j, x, y); glPushName(j); glBegin(GL_POINTS); glVertex3f(x, y, z); glEnd(); glPopName(); } glPopName(); } } glPopName(); } if (selectionMask & SELECTION_MASK_CONTOUR_CELL) { if (dsc->getDisplayContourCells()) { glPushName(SELECTION_MASK_CONTOUR_CELL); for (int i = 0; i < numCells; i++) { const CellData* cd = cellFile->getCell(i); if (cd->getDisplayFlag() == false) { continue; } const int sectionNumber = cd->getSectionNumber(); if ((sectionNumber >= minimumSection) && (sectionNumber <= maximumSection)) { const int colorIndex = cd->getColorIndex(); float pointSize = 1; float lineSize = 1; if ((colorIndex >= 0) && (colorIndex < numColors)) { colorFile->getPointLineSizeByIndex(colorIndex, pointSize, lineSize); } if (pointSize < 1) { pointSize = 1; } const float size = pointSize * cellSize; float xyz[3]; cd->getXYZ(xyz); xyz[2] = sectionNumber * spacing; glPushName(i); glPointSize(getValidPointSize(size)); glBegin(GL_POINTS); glVertex3fv(xyz); glEnd(); glPopName(); } } glPopName(); } } if (selectionMask == SELECTION_MASK_OFF) { bool drawPoints = false; bool drawLines = false; switch (dsc->getDrawMode()) { case DisplaySettingsContours::DRAW_MODE_POINTS: drawPoints = true; break; case DisplaySettingsContours::DRAW_MODE_LINES: drawLines = true; break; case DisplaySettingsContours::DRAW_MODE_POINTS_AND_LINES: drawPoints = true; drawLines = true; break; } if (drawLines) { for (int i = 0; i < numContours; i++) { const CaretContour* contour = cf->getContour(i); const int sectionNumber = contour->getSectionNumber(); if ((sectionNumber >= minimumSection) && (sectionNumber <= maximumSection)) { // // Don't draw alignment section number // if (aligningContours && (sectionNumber == alignmentSectionNumber)) { continue; } const float z = sectionNumber * spacing; const int numPoints = contour->getNumberOfPoints(); if (numPoints > 1) { glColor3ub(0, 125, 0); glBegin(GL_LINE_LOOP); for (int j = 0; j < numPoints; j++) { float x, y; contour->getPointXY(j, x, y); glVertex3f(x, y, z); } glEnd(); } } } } if (drawPoints) { for (int i = 0; i < numContours; i++) { const CaretContour* contour = cf->getContour(i); const int sectionNumber = contour->getSectionNumber(); if ((sectionNumber >= minimumSection) && (sectionNumber <= maximumSection)) { // // Don't draw alignment section number // if (aligningContours && (sectionNumber == alignmentSectionNumber)) { continue; } const float z = sectionNumber * spacing; const int numPoints = contour->getNumberOfPoints(); if (numPoints > 0) { glPointSize(getValidPointSize(dsc->getPointSize())); glColor3ub(0, 175, 0); glBegin(GL_POINTS); for (int j = 0; j < numPoints; j++) { if ((j == 0) && (dsc->getShowEndPoints())) { continue; // skip as drawn later } else { float x, y; contour->getPointXY(j, x, y); glVertex3f(x, y, z); } } glEnd(); // // Draw highlighted contours // glPointSize(getValidPointSize(dsc->getPointSize() * 2.0)); glColor3ub(0, 255, 0); glBegin(GL_POINTS); for (int j = 0; j < numPoints; j++) { if ((j == 0) && (dsc->getShowEndPoints())) { continue; // skip as drawn later } else if (contour->getHighlightFlag(j)) { float x, y; contour->getPointXY(j, x, y); glVertex3f(x, y, z); } } glEnd(); // // Draw end points in red // if (dsc->getShowEndPoints()) { glPointSize(getValidPointSize(dsc->getPointSize() * 2.0)); glColor3ub(255, 0, 0); float x, y; contour->getPointXY(0, x, y); glBegin(GL_POINTS); glVertex3f(x, y, z); glEnd(); } } } } } if (dsc->getDisplayContourCells()) { for (int i = 0; i < numCells; i++) { const CellData* cd = cellFile->getCell(i); if (cd->getDisplayFlag() == false) { continue; } const int sectionNumber = cd->getSectionNumber(); // // Don't draw alignment section number cells // if (aligningContours && (sectionNumber == alignmentSectionNumber)) { continue; } if ((sectionNumber >= minimumSection) && (sectionNumber <= maximumSection)) { const int colorIndex = cd->getColorIndex(); float pointSize = 1; float lineSize = 1; unsigned char r = 0, g = 0, b = 0; if ((colorIndex >= 0) && (colorIndex < numColors)) { colorFile->getColorByIndex(colorIndex, r, g, b); colorFile->getPointLineSizeByIndex(colorIndex, pointSize, lineSize); } else { r = noColorRed; g = noColorGreen; b = noColorBlue; } if (pointSize < 1) { pointSize = 1; } const float size = pointSize * cellSize; float xyz[3]; cd->getXYZ(xyz); xyz[2] = sectionNumber * spacing; glColor3ub(r, g, b); glPointSize(getValidPointSize(size)); glBegin(GL_POINTS); glVertex3fv(xyz); glEnd(); } } } } } // if (hideContours == false) ... // // Draw alignment section // if (aligningContours) { drawModelContoursAlignment(bmc, alignmentSectionNumber); } } /** * Draw the contours that are being aligned. */ void BrainModelOpenGL::drawModelContoursAlignment(BrainModelContours* bmc, const int alignmentSectionNumber) { // // Display alignment region box // if (bmc->getAligningRegionFlag()) { if (bmc->getAlignmentRegionBoxValid()) { float bounds[4]; bmc->getAlignmentRegionBox(bounds); const float minX = std::min(bounds[0], bounds[2]); const float maxX = std::max(bounds[0], bounds[2]); const float minY = std::min(bounds[1], bounds[3]); const float maxY = std::max(bounds[1], bounds[3]); glColor3ub(125, 0, 0); glBegin(GL_LINE_LOOP); glVertex3f(minX, minY, -1.0); glVertex3f(maxX, minY, -1.0); glVertex3f(maxX, maxY, -1.0); glVertex3f(minX, maxY, -1.0); glEnd(); } } const ContourFile* cf = bmc->getContourFile(); // // Create the alignment transformation matrix // glPushMatrix(); glLoadIdentity(); // Get the center of gravity of the contour section and translate to it // so that contour rotates around its center of gravity and not // the origin // float cogX, cogY; cf->getSectionCOG(alignmentSectionNumber, cogX, cogY); glTranslatef(cogX, cogY, 0.0); float translate[3]; bmc->getAlignmentTranslation(translate); glTranslatef(translate[0], translate[1], translate[2]); float matrix[16]; bmc->getAlignmentRotationMatrix(matrix); glMultMatrixf(matrix); const float scale = bmc->getAlignmentScaling(); glScalef(scale, scale, 1.0); // // Undo the Center of Gravity Translation // glTranslatef(-cogX, -cogY, 0.0); // // Get the alignment transformation matrix // double alignmentMatrix[16]; //[4][4]; glGetDoublev(GL_MODELVIEW_MATRIX, (double*)alignmentMatrix); glPopMatrix(); // // Used when contours are aligned // TransformationMatrix am; am.setMatrix(alignmentMatrix); bmc->setAlignmentMatrix(am); /* !!!!!!!!!!!! NEED TO FINISH !!!!!!!!!!!!!!!!!!!!!!!!!! // // Copy the matrix to the alignment dialog // GuiContourAlignmentDialog* cad = theMainWindow->getContourAlignmentDialog(false); if (cad != NULL) { cad->setAlignmentTransformationMatrix(alignmentMatrix); } */ const int numContours = cf->getNumberOfContours(); const float spacing = cf->getSectionSpacing(); const DisplaySettingsContours* dsc = brainSet->getDisplaySettingsContours(); glPointSize(getValidPointSize(dsc->getPointSize())); glLineWidth(getValidLineWidth(dsc->getLineThickness())); // // First iteration draw region being aligned // Second iteration draw what is not in the region (or everything if no region) // const bool regionAlignment = bmc->getAligningRegionFlag(); for (int iter = 0; iter < 2; iter++) { // // Use the alignment matrix // glPushMatrix(); if (iter == 0) { if (regionAlignment == false) { glPopMatrix(); continue; } glMultMatrixd((double*)alignmentMatrix); } else { if (regionAlignment == false) { glMultMatrixd((double*)alignmentMatrix); } } for (int i = 0; i < numContours; i++) { const CaretContour* contour = cf->getContour(i); const int sectionNumber = contour->getSectionNumber(); if (sectionNumber == alignmentSectionNumber) { const float z = sectionNumber * spacing; const int numPoints = contour->getNumberOfPoints(); glBegin(GL_POINTS); for (int j = 0; j < numPoints; j++) { glColor3ub(0, 0, 255); bool drawIt = false; if (iter == 0) { if (contour->getSpecialFlag(j)) { drawIt = true; } } else { if (regionAlignment) { if (contour->getSpecialFlag(j) == false) { drawIt = true; glColor3ub(0, 0, 150); } } else { drawIt = true; } } if (drawIt) { float x, y; contour->getPointXY(j, x, y); glVertex3f(x, y, z); } } glEnd(); } } if (dsc->getDisplayContourCells()) { CellFile* cellFile = brainSet->getContourCellFile(); const int numCells = cellFile->getNumberOfCells(); for (int i = 0; i < numCells; i++) { const CellData* cd = cellFile->getCell(i); if (cd->getDisplayFlag() == false) { continue; } const int sectionNumber = cd->getSectionNumber(); if (sectionNumber == alignmentSectionNumber) { float pointSize = 6; const float size = pointSize; float xyz[3]; cd->getXYZ(xyz); xyz[2] = sectionNumber * spacing; glColor3ub(0, 0, 255); bool drawIt = false; if (iter == 0) { if (cd->getSpecialFlag()) { drawIt = true; } } else { if (regionAlignment) { if (cd->getSpecialFlag() == false) { drawIt = true; glColor3ub(0, 0, 150); } } else { drawIt = true; } } if (drawIt) { glPointSize(getValidPointSize(size)); glBegin(GL_POINTS); glVertex3fv(xyz); glEnd(); } } } } glPopMatrix(); } } /** * get the default ortho right and top for command line scene generation. */ void BrainModelOpenGL::getDefaultOrthoRightAndTop(const int windowWidthIn, const int windowHeightIn, double& orthoRightOut, double& orthoTopOut) { const double aspectRatio = (static_cast(windowWidthIn)) / (static_cast(windowHeightIn)); orthoRightOut = defaultOrthoWindowSize * aspectRatio; orthoTopOut = defaultOrthoWindowSize; } /** * Update the orthographic window size. */ void BrainModelOpenGL::updateOrthoSize(const int windowNumber, const int width, const int height) { const double aspectRatio = (static_cast(width)) / (static_cast(height)); orthographicRight[windowNumber] = defaultOrthoWindowSize * aspectRatio; orthographicLeft[windowNumber] = -defaultOrthoWindowSize * aspectRatio; orthographicTop[windowNumber] = defaultOrthoWindowSize; orthographicBottom[windowNumber] = -defaultOrthoWindowSize; orthographicNear[windowNumber] = -5000.0; //-500.0; //-10000.0; orthographicFar[windowNumber] = 5000.0; //500.0; // 10000.0; } /** * draw surface. */ void BrainModelOpenGL::drawBrainModelSurface(BrainModelSurface* bms, BrainModelSurfaceAndVolume* bmsv, const bool drawTheSurface, const bool surfaceInVolumeAllViewFlag) { if (DebugControl::getOpenGLDebugOn()) { checkForOpenGLError(bms, "At beginning of drawBrainModelSurface()"); } const DisplaySettingsSurface* dss = brainSet->getDisplaySettingsSurface(); // // Don't set projection matrix when selecting // if (selectionMask == SELECTION_MASK_OFF) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); const double aspectRatio = (static_cast(viewport[2])) / (static_cast(viewport[3])); switch (dss->getViewingProjection()) { case DisplaySettingsSurface::VIEWING_PROJECTION_ORTHOGRAPHIC: glOrtho(orthographicLeft[viewingWindowNumber], orthographicRight[viewingWindowNumber], orthographicBottom[viewingWindowNumber], orthographicTop[viewingWindowNumber], orthographicNear[viewingWindowNumber], orthographicFar[viewingWindowNumber]); break; case DisplaySettingsSurface::VIEWING_PROJECTION_PERSPECTIVE: gluPerspective(bms->getPerspectiveFieldOfView(), aspectRatio, 1.0, 1000.0); break; } glGetDoublev(GL_PROJECTION_MATRIX, selectionProjectionMatrix[viewingWindowNumber]); } glMatrixMode(GL_MODELVIEW); glLoadIdentity(); switch (dss->getViewingProjection()) { case DisplaySettingsSurface::VIEWING_PROJECTION_ORTHOGRAPHIC: break; case DisplaySettingsSurface::VIEWING_PROJECTION_PERSPECTIVE: gluLookAt(0.0, 0.0, bms->getPerspectiveZooming(viewingWindowNumber), 0.0, 0.0,0.0, 0.0,1.0, 0.0); break; } float translate[3]; bms->getTranslation(viewingWindowNumber, translate); glTranslatef(translate[0], translate[1], translate[2]); float matrix[16]; bms->getRotationMatrix(viewingWindowNumber, matrix); glMultMatrixf(matrix); if (DebugControl::getDebugOn()) { vtkTransform* tm = bms->getRotationTransformMatrix(viewingWindowNumber); float angles[3]; tm->GetOrientation(angles); // std::cout << "angles: " // << angles[0] << " " // << angles[1] << " " // << angles[2] << std::endl; } float scale[3]; bms->getScaling(viewingWindowNumber, scale); glScalef(scale[0], scale[1], scale[2]); // // Save modeling matrix // bool idMode = true; if (selectionMask == SELECTION_MASK_OFF) { idMode = false; glGetDoublev(GL_MODELVIEW_MATRIX, selectionModelviewMatrix[viewingWindowNumber]); } // // If this flag is set we only want to draw the linear object. When this // flag is set, glClear() is not called so the previous stuff is not erased. // if (drawLinearObjectOnly && (bmsv == NULL)) { drawLinearObject(); return; } // // Allow clipping planes // enableSurfaceClippingPlanes(bms); const CoordinateFile* cf = bms->getCoordinateFile(); const int modelNumber = bms->getBrainModelIndex(); const int numCoords = cf->getNumberOfCoordinates(); switch (bms->getSurfaceType()) { case BrainModelSurface::SURFACE_TYPE_RAW: case BrainModelSurface::SURFACE_TYPE_FIDUCIAL: // // Draw the VTK models // drawAllVtkModels(); break; case BrainModelSurface::SURFACE_TYPE_INFLATED: case BrainModelSurface::SURFACE_TYPE_VERY_INFLATED: case BrainModelSurface::SURFACE_TYPE_SPHERICAL: case BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL: case BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL: case BrainModelSurface::SURFACE_TYPE_FLAT: case BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR: case BrainModelSurface::SURFACE_TYPE_HULL: case BrainModelSurface::SURFACE_TYPE_UNKNOWN: case BrainModelSurface::SURFACE_TYPE_UNSPECIFIED: break; } // // Draw cells and foci here so that they show through a transparent surface // drawCellAndFociProjections(bms); // // Get display list number for this surface // PreferencesFile* pf = brainSet->getPreferencesFile(); const bool displayListsEnabled = pf->getDisplayListsEnabled(); unsigned long displayListNumber = bms->getDisplayListNumber(); // // If need to redraw surface // if ((displayListNumber == 0) || (displayListsEnabled == false) || idMode) { // // If not ID mode then need to create a new display list for this surface // bool creatingDisplayList = false; if (displayListsEnabled && (idMode == false)) { displayListNumber = glGenLists(1); bms->setDisplayListNumber(displayListNumber); glNewList(displayListNumber, GL_COMPILE); creatingDisplayList = true; } // // Draw vectors here so surface opacity functions successfully. // Otherwise Z-Buffer prevents vectors from being drawn inside the surface. // if (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FIDUCIAL) { this->disableSurfaceClippingPlanes(); drawVectorFile3D(bms); this->enableSurfaceClippingPlanes(bms); } int numTiles = -1; TopologyFile* tf = bms->getTopologyFile(); if (tf != NULL) { numTiles = tf->getNumberOfTiles(); } const DisplaySettingsSurface::DRAW_MODE surfaceDrawingMode = dss->getDrawMode(); if ((numCoords > 0) && drawTheSurface) { glColor3ub(170, 170, 170); BrainModelSurfaceNodeColoring* bsnc = brainSet->getNodeColoring(); if ((selectionMask & SELECTION_MASK_NODE) || (selectionMask & SELECTION_MASK_TILE) || (selectionMask & SELECTION_MASK_LINK)) { if (surfaceDrawingMode != DisplaySettingsSurface::DRAW_MODE_NONE) { if (selectionMask & SELECTION_MASK_NODE) { drawSurfaceNodes(bsnc, modelNumber, cf, numCoords, false); } if (selectionMask & SELECTION_MASK_TILE) { if (numTiles > 0) { if (surfaceDrawingMode != DisplaySettingsSurface::DRAW_MODE_NONE) { drawSurfaceTiles(bsnc, bms, cf, tf, numTiles, numCoords); } } } if (selectionMask & SELECTION_MASK_LINK) { if ((surfaceDrawingMode == DisplaySettingsSurface::DRAW_MODE_LINKS) || (surfaceDrawingMode == DisplaySettingsSurface::DRAW_MODE_NODES_AND_LINKS) || (surfaceDrawingMode == DisplaySettingsSurface::DRAW_MODE_LINK_HIDDEN_LINE_REMOVAL) || (surfaceDrawingMode == DisplaySettingsSurface::DRAW_MODE_TILES_LINKS_NODES)) { drawSurfaceLinks(bsnc, modelNumber, cf, tf, numTiles, false, false); } if (surfaceDrawingMode == DisplaySettingsSurface::DRAW_MODE_LINKS_EDGES_ONLY) { brainSet->classifyNodes(NULL, true); drawSurfaceLinks(bsnc, modelNumber, cf, tf, numTiles, true, false); } } } } else if (selectionMask == SELECTION_MASK_OFF) { if (numTiles > 0) { if ((surfaceDrawingMode == DisplaySettingsSurface::DRAW_MODE_TILES) || (surfaceDrawingMode == DisplaySettingsSurface::DRAW_MODE_TILES_WITH_LIGHT)) { drawSurfaceTiles(bsnc, bms, cf, tf, numTiles, numCoords); } if ((surfaceDrawingMode == DisplaySettingsSurface::DRAW_MODE_TILES_WITH_LIGHT_NO_BACK) || (surfaceDrawingMode == DisplaySettingsSurface::DRAW_MODE_LINK_HIDDEN_LINE_REMOVAL)) { glEnable(GL_CULL_FACE); glCullFace(GL_BACK); if (surfaceDrawingMode == DisplaySettingsSurface::DRAW_MODE_LINK_HIDDEN_LINE_REMOVAL) { glLineWidth(getValidLineWidth(dss->getLinkSize())); glPolygonMode(GL_FRONT, GL_LINE); } drawSurfaceTiles(bsnc, bms, cf, tf, numTiles, numCoords); glPolygonMode(GL_FRONT, GL_FILL); glDisable(GL_CULL_FACE); } if ((surfaceDrawingMode == DisplaySettingsSurface::DRAW_MODE_LINKS) || (surfaceDrawingMode == DisplaySettingsSurface::DRAW_MODE_NODES_AND_LINKS)) { drawSurfaceLinks(bsnc, modelNumber, cf, tf, numTiles, false, false); } if (surfaceDrawingMode == DisplaySettingsSurface::DRAW_MODE_LINKS_EDGES_ONLY) { brainSet->classifyNodes(NULL, true); drawSurfaceLinks(bsnc, modelNumber, cf, tf, numTiles, true, false); } //if (surfaceDrawingMode == DisplaySettingsSurface::DRAW_MODE_LINK_HIDDEN_LINE_REMOVAL) { // drawSurfaceLinksNoBackside(bsnc, modelNumber, cf, tf, numTiles); //} } if (surfaceDrawingMode == DisplaySettingsSurface::DRAW_MODE_TILES_LINKS_NODES) { if (numTiles > 0) { glPolygonOffset(1.0, 1.0); glEnable(GL_POLYGON_OFFSET_FILL); drawSurfaceTiles(bsnc, bms, cf, tf, numTiles, numCoords); glDisable(GL_POLYGON_OFFSET_FILL); drawSurfaceLinks(bsnc, modelNumber, cf, tf, numTiles, false, true); } drawSurfaceNodes(bsnc, modelNumber, cf, numCoords, true); } if ((surfaceDrawingMode == DisplaySettingsSurface::DRAW_MODE_NODES) || (surfaceDrawingMode == DisplaySettingsSurface::DRAW_MODE_NODES_AND_LINKS)) { drawSurfaceNodes(bsnc, modelNumber, cf, numCoords, false); } // // Push node ID symbols above a flat surface // glPushMatrix(); if ((bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FLAT) || (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR)) { glTranslatef(0.0, 0.0, 0.5); } drawSurfaceROIMembers(bms, numCoords); drawNodeHighlighting(bms, numCoords); glPopMatrix(); if (dss->getShowNormals()) { drawSurfaceNormals(bms, cf, numCoords); } drawSurfaceForces(cf, numCoords); } } // // End display list if creating a display list // if (creatingDisplayList) { glEndList(); } } // // If display lists enabled, execute it // if (displayListsEnabled && (idMode == false)) { if (glIsList(displayListNumber)) { glCallList(displayListNumber); } else { std::cout << "PROGRAM WARNING: display list " << displayListNumber << " does not exist for surface " << bms->getDescriptiveName().toAscii().constData() << " in window " << viewingWindowNumber << std::endl; } } drawBorders(bms); //drawCellAndFociProjections(bms); drawCuts(); drawGeodesicPath(cf); drawDeformationFieldVectors(bms); drawSurfaceAxes(bms); drawTransformationMatrixAxes(bms); /* switch (bms->getSurfaceType()) { case BrainModelSurface::SURFACE_TYPE_RAW: case BrainModelSurface::SURFACE_TYPE_FIDUCIAL: // // Draw the VTK models // drawAllVtkModels(); break; case BrainModelSurface::SURFACE_TYPE_INFLATED: case BrainModelSurface::SURFACE_TYPE_VERY_INFLATED: case BrainModelSurface::SURFACE_TYPE_SPHERICAL: case BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL: case BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL: case BrainModelSurface::SURFACE_TYPE_FLAT: case BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR: case BrainModelSurface::SURFACE_TYPE_HULL: case BrainModelSurface::SURFACE_TYPE_UNKNOWN: case BrainModelSurface::SURFACE_TYPE_UNSPECIFIED: break; } */ if ((bmsv == NULL) && (surfaceInVolumeAllViewFlag == false)) { drawMetricPalette(modelNumber, true); drawShapePalette(modelNumber); const int num = linearObjectBeingDrawn.getNumberOfLinks(); if (num > 0) { glDisable(GL_DEPTH_TEST); glPointSize(getValidPointSize(2.0)); glColor3f(1.0, 0.0, 0.0); glBegin(GL_POINTS); for (int i = 0; i < num; i++) { glVertex3fv(linearObjectBeingDrawn.getLinkXYZ(i)); } glEnd(); glEnable(GL_DEPTH_TEST); } } disableSurfaceClippingPlanes(); if (DebugControl::getOpenGLDebugOn()) { checkForOpenGLError(bms, "At end of drawBrainModelSurface()"); } } /** * Enable the surface clipping planes. */ void BrainModelOpenGL::enableSurfaceClippingPlanes(BrainModelSurface* bms) { // // Setup clipping planes // DisplaySettingsSurface* dss = brainSet->getDisplaySettingsSurface(); bool applyClippingPlanesFlag = false; switch (dss->getClippingPlaneApplication()) { case DisplaySettingsSurface::CLIPPING_PLANE_APPLICATION_MAIN_WINDOW_ONLY: if (viewingWindowNumber == BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) { applyClippingPlanesFlag = true; } break; case DisplaySettingsSurface::CLIPPING_PLANE_APPLICATION_FIDUCIAL_SURFACES_ONLY: if (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FIDUCIAL) { applyClippingPlanesFlag = true; } break; case DisplaySettingsSurface::CLIPPING_PLANE_APPLICATION_ALL_SURFACES: applyClippingPlanesFlag = true; break; } if (applyClippingPlanesFlag) { // // Negative X // if (dss->getClippingPlaneEnabled(DisplaySettingsSurface::CLIPPING_PLANE_AXIS_X_NEGATIVE)) { GLdouble plane[4] = { 1.0, 0.0, 0.0, -dss->getClippingPlaneCoordinate(DisplaySettingsSurface::CLIPPING_PLANE_AXIS_X_NEGATIVE) }; glClipPlane(GL_CLIP_PLANE0, plane); glEnable(GL_CLIP_PLANE0); } // // Positive X // if (dss->getClippingPlaneEnabled(DisplaySettingsSurface::CLIPPING_PLANE_AXIS_X_POSITIVE)) { GLdouble plane[4] = { -1.0, 0.0, 0.0, dss->getClippingPlaneCoordinate(DisplaySettingsSurface::CLIPPING_PLANE_AXIS_X_POSITIVE) }; glClipPlane(GL_CLIP_PLANE1, plane); glEnable(GL_CLIP_PLANE1); } // // Negative Y // if (dss->getClippingPlaneEnabled(DisplaySettingsSurface::CLIPPING_PLANE_AXIS_Y_NEGATIVE)) { GLdouble plane[4] = { 0.0, 1.0, 0.0, -dss->getClippingPlaneCoordinate(DisplaySettingsSurface::CLIPPING_PLANE_AXIS_Y_NEGATIVE) }; glClipPlane(GL_CLIP_PLANE2, plane); glEnable(GL_CLIP_PLANE2); } // // Positive Y // if (dss->getClippingPlaneEnabled(DisplaySettingsSurface::CLIPPING_PLANE_AXIS_Y_POSITIVE)) { GLdouble plane[4] = { 0.0, -1.0, 0.0, dss->getClippingPlaneCoordinate(DisplaySettingsSurface::CLIPPING_PLANE_AXIS_Y_POSITIVE) }; glClipPlane(GL_CLIP_PLANE3, plane); glEnable(GL_CLIP_PLANE3); } // // Negative Z // if (dss->getClippingPlaneEnabled(DisplaySettingsSurface::CLIPPING_PLANE_AXIS_Z_NEGATIVE)) { GLdouble plane[4] = { 0.0, 0.0, 1.0, -dss->getClippingPlaneCoordinate(DisplaySettingsSurface::CLIPPING_PLANE_AXIS_Z_NEGATIVE) }; glClipPlane(GL_CLIP_PLANE4, plane); glEnable(GL_CLIP_PLANE4); } // // Positive Z // if (dss->getClippingPlaneEnabled(DisplaySettingsSurface::CLIPPING_PLANE_AXIS_Z_POSITIVE)) { GLdouble plane[4] = { 0.0, 0.0, -1.0, dss->getClippingPlaneCoordinate(DisplaySettingsSurface::CLIPPING_PLANE_AXIS_Z_POSITIVE) }; glClipPlane(GL_CLIP_PLANE5, plane); glEnable(GL_CLIP_PLANE5); } } } /** * Disable the surface clipping planes. */ void BrainModelOpenGL::disableSurfaceClippingPlanes() { glDisable(GL_CLIP_PLANE0); glDisable(GL_CLIP_PLANE1); glDisable(GL_CLIP_PLANE2); glDisable(GL_CLIP_PLANE3); glDisable(GL_CLIP_PLANE4); glDisable(GL_CLIP_PLANE5); } /** * Draw the surface axes. */ void BrainModelOpenGL::drawSurfaceAxes(const BrainModelSurface* bms) { if (selectionMask != SELECTION_MASK_OFF) { return; } DisplaySettingsSurface* dss = brainSet->getDisplaySettingsSurface(); bool showAxes, showLetters, showHashMarks; float axesLength; float axesOffset[3]; dss->getSurfaceAxesInfo(showAxes, showLetters, showHashMarks, axesLength, axesOffset); if (showAxes) { // // Get the foreground color // PreferencesFile* pref = brainSet->getPreferencesFile(); unsigned char r, g, b; pref->getSurfaceForegroundColor(r, g, b); glColor3ub(r, g, b); glLineWidth(getValidLineWidth(2.0)); // // See if flat surface // bool flatSurfaceFlag = false; switch (bms->getSurfaceType()) { case BrainModelSurface::SURFACE_TYPE_RAW: case BrainModelSurface::SURFACE_TYPE_FIDUCIAL: case BrainModelSurface::SURFACE_TYPE_INFLATED: case BrainModelSurface::SURFACE_TYPE_VERY_INFLATED: case BrainModelSurface::SURFACE_TYPE_SPHERICAL: case BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL: case BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL: break; case BrainModelSurface::SURFACE_TYPE_FLAT: case BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR: flatSurfaceFlag = true; break; case BrainModelSurface::SURFACE_TYPE_HULL: case BrainModelSurface::SURFACE_TYPE_UNKNOWN: case BrainModelSurface::SURFACE_TYPE_UNSPECIFIED: break; } glPushMatrix(); { glTranslatef(axesOffset[0], axesOffset[1], axesOffset[2]); // // Draw the axes // glBegin(GL_LINES); glVertex3f(-axesLength, 0.0, 0.0); glVertex3f( axesLength, 0.0, 0.0); glVertex3f(0.0, -axesLength, 0.0); glVertex3f(0.0, axesLength, 0.0); if (flatSurfaceFlag == false) { glVertex3f(0.0, 0.0, -axesLength); glVertex3f(0.0, 0.0, axesLength); } glEnd(); if (showHashMarks) { const float hashStep = 10.0; const float hashSize = 10.0; if (flatSurfaceFlag == false) { // // Along Z-axis with hashmarks in +/- X/Y // glBegin(GL_LINES); for (float z = -axesLength; z <= axesLength; z+= hashStep) { glVertex3f(-hashSize, 0.0, z); glVertex3f( hashSize, 0.0, z); glVertex3f(0.0, -hashSize, z); glVertex3f(0.0, hashSize, z); } glVertex3f(-hashSize, 0.0, axesLength); glVertex3f( hashSize, 0.0, axesLength); glVertex3f(0.0, -hashSize, axesLength); glVertex3f(0.0, hashSize, axesLength); glEnd(); } // // Along Y-axis with hashmarks in +/- X // glBegin(GL_LINES); for (float y = -axesLength; y <= axesLength; y+= hashStep) { glVertex3f(-hashSize, y, 0.0); glVertex3f( hashSize, y, 0.0); glVertex3f(0.0, y, -hashSize); glVertex3f(0.0, y, hashSize); } glVertex3f(-hashSize, axesLength, 0.0); glVertex3f( hashSize, axesLength, 0.0); glVertex3f(0.0, axesLength, -hashSize); glVertex3f(0.0, axesLength, hashSize); glEnd(); // // Along X-axis with hashmarks in +/- Y // glBegin(GL_LINES); for (float x = -axesLength; x <= axesLength; x+= hashStep) { glVertex3f(x, -hashSize, 0.0); glVertex3f(x, hashSize, 0.0); glVertex3f(x, 0.0, -hashSize); glVertex3f(x, 0.0, hashSize); } glVertex3f(axesLength, -hashSize, 0.0); glVertex3f(axesLength, hashSize, 0.0); glVertex3f(axesLength, 0.0, -hashSize); glVertex3f(axesLength, 0.0, hashSize); glEnd(); } if (showLetters && (glWidget != NULL) && (flatSurfaceFlag == false)) { const float letterOffset = 10.0; glWidget->renderText(0.0, 0.0, -axesLength - letterOffset, "I"); glWidget->renderText(0.0, 0.0, axesLength + letterOffset, "S"); glWidget->renderText(0.0, -axesLength - letterOffset, 0.0, "P"); glWidget->renderText(0.0, axesLength + letterOffset, 0.0, "A"); if (bms->getStructure() == Structure::STRUCTURE_TYPE_CORTEX_RIGHT) { glWidget->renderText(-axesLength - letterOffset, 0.0, 0.0, "M"); glWidget->renderText(axesLength + letterOffset, 0.0, 0.0, "L"); } else { glWidget->renderText(-axesLength - letterOffset, 0.0, 0.0, "L"); glWidget->renderText(axesLength + letterOffset, 0.0, 0.0, "M"); } } } glPopMatrix(); } } /** * Draw the transformation axes. */ void BrainModelOpenGL::drawTransformationMatrixAxes(const BrainModel* bm) { // // Get the transformation matrix file and the number of matrices in it // TransformationMatrixFile* tmf = brainSet->getTransformationMatrixFile(); const int numMatrices = tmf->getNumberOfMatrices(); if (numMatrices <= 0) { return; } // // See if Translation axes should be drawn // bool drawAxes = false; bool volumeFlag = false; const BrainModelSurface* bms = dynamic_cast(bm); if (bms != NULL) { switch (bms->getSurfaceType()) { case BrainModelSurface::SURFACE_TYPE_RAW: case BrainModelSurface::SURFACE_TYPE_FIDUCIAL: drawAxes = true; break; case BrainModelSurface::SURFACE_TYPE_INFLATED: case BrainModelSurface::SURFACE_TYPE_VERY_INFLATED: case BrainModelSurface::SURFACE_TYPE_SPHERICAL: case BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL: case BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL: case BrainModelSurface::SURFACE_TYPE_FLAT: case BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR: case BrainModelSurface::SURFACE_TYPE_HULL: case BrainModelSurface::SURFACE_TYPE_UNKNOWN: case BrainModelSurface::SURFACE_TYPE_UNSPECIFIED: break; } } if (dynamic_cast(bm) != NULL) { drawAxes = true; volumeFlag = true; } if (dynamic_cast(bm) != NULL) { drawAxes = true; } // // Check for selection being made // bool doingSelection = false; if (drawAxes) { if (selectionMask != SELECTION_MASK_OFF) { if (selectionMask & SELECTION_MASK_TRANSFORMATION_MATRIX_AXES) { doingSelection = true; } else { drawAxes = false; } } } // // Draw the translation axes // if (drawAxes) { for (int i = 0; i < numMatrices; i++) { const TransformationMatrix* tm = tmf->getTransformationMatrix(i); if (tm->getShowAxes()) { if (doingSelection) { glPushName(SELECTION_MASK_TRANSFORMATION_MATRIX_AXES); glPushName(i); } glPushMatrix(); { // // Do the transformation // double matrix[16]; tm->getMatrix(matrix); glMultMatrixd(matrix); const unsigned char xColor[3] = { 255, 0, 0 }; const unsigned char yColor[3] = { 0, 255, 0 }; const unsigned char zColor[3] = { 0, 0, 255 }; float thickness = 2.0; if (tmf->getSelectedTransformationAxesIndex() == i) { thickness = 4.0; } if (volumeFlag) { // // Draw the axes as OpenGL lines // const float axisEnd = tm->getAxesLength(); const float axisStart = -axisEnd * 0.10; const float axesLength = tm->getAxesLength(); glLineWidth(getValidLineWidth(thickness)); glBegin(GL_LINES); glColor3ubv(xColor); glVertex3f(axisStart, 0.0, 0.0); glVertex3f(axisEnd, 0.0, 0.0); glColor3ubv(yColor); glVertex3f(0.0, axisStart, 0.0); glVertex3f(0.0, axisEnd, 0.0); glColor3ubv(zColor); glVertex3f(0.0, 0.0, axisStart); glVertex3f(0.0, 0.0, axisEnd); glEnd(); if (doingSelection == false) { const float letterPos = axesLength + 5; glColor3ubv(xColor); glWidget->renderText(letterPos, 0.0, 0.0, "X"); glColor3ubv(yColor); glWidget->renderText(0.0, letterPos, 0.0, "Y"); glColor3ubv(zColor); glWidget->renderText(0.0, 0.0, letterPos, "Z"); } } else { // // Draw the axes as cylinders // const float axesDiameter = thickness; const float axesLength = tm->getAxesLength(); const float axisBehindOriginLength = axesLength * 0.10; const float axisTotalLength = axesLength + axisBehindOriginLength; glEnable(GL_LIGHTING); glEnable(GL_COLOR_MATERIAL); glPushMatrix(); glColor3ubv(xColor); glRotatef(90.0, 0.0, 1.0, 0.0); glTranslatef(0.0, 0.0, -axisBehindOriginLength); glPushMatrix(); glScalef(1.0, 1.0, -1.0); drawDisk(axesDiameter); // caps off end of cylinder glPopMatrix(); glScalef(axesDiameter, axesDiameter, axisTotalLength); drawCylinder(); glPopMatrix(); glPushMatrix(); glColor3ubv(yColor); glRotatef(-90.0, 1.0, 0.0, 0.0); glTranslatef(0.0, 0.0, -axisBehindOriginLength); glPushMatrix(); glScalef(1.0, 1.0, -1.0); drawDisk(axesDiameter); // caps off end of cylinder glPopMatrix(); glScalef(axesDiameter, axesDiameter, axisTotalLength); drawCylinder(); glPopMatrix(); glPushMatrix(); glColor3ubv(zColor); glTranslatef(0.0, 0.0, -axisBehindOriginLength); glPushMatrix(); glScalef(1.0, 1.0, -1.0); drawDisk(axesDiameter); // caps off end of cylinder glPopMatrix(); glScalef(axesDiameter, axesDiameter, axisTotalLength); drawCylinder(); glPopMatrix(); // // Draw the arrow heads // glEnable(GL_LIGHTING); glEnable(GL_COLOR_MATERIAL); const float coneSize = axesDiameter + 5.0; glPushMatrix(); glColor3ubv(xColor); glTranslatef(axesLength, 0.0, 0.0); glRotatef(90.0, 0.0, 1.0, 0.0); glScalef(coneSize, coneSize, coneSize); drawCone(); glPopMatrix(); glPushMatrix(); glColor3ubv(yColor); glTranslatef(0.0, axesLength, 0.0); glRotatef(-90.0, 1.0, 0.0, 0.0); glScalef(coneSize, coneSize, coneSize); drawCone(); glPopMatrix(); glPushMatrix(); glColor3ubv(zColor); glTranslatef(0.0, 0.0, axesLength); glScalef(coneSize, coneSize, coneSize); drawCone(); glPopMatrix(); glDisable(GL_COLOR_MATERIAL); glDisable(GL_LIGHTING); if (doingSelection == false) { const float letterPos = axesLength + coneSize + 5; glColor3ubv(xColor); glWidget->renderText(letterPos, 0.0, 0.0, "X"); glColor3ubv(yColor); glWidget->renderText(0.0, letterPos, 0.0, "Y"); glColor3ubv(zColor); glWidget->renderText(0.0, 0.0, letterPos, "Z"); } } } glPopMatrix(); if (doingSelection) { glPopName(); glPopName(); } } // if show axes } // for (i == } // if (drawAxes) for (int i = 0; i < numMatrices; i++) { const TransformationMatrix* tm = tmf->getTransformationMatrix(i); glPushMatrix(); { // // Do the transformation // double matrix[16]; tm->getMatrix(matrix); glMultMatrixd(matrix); // // Draw the data files associated with the axes // if (volumeFlag == false) { drawTransformationDataFiles(tm); } } glPopMatrix(); } } /** * draw surface and volume. */ void BrainModelOpenGL::drawBrainModelSurfaceAndVolume(BrainModelSurfaceAndVolume* bmsv) { // // Draw the surface // drawBrainModelSurface(bmsv, bmsv, bmsv->getDisplaySurface(), false); // // Make sure there is an anatomical volume // VolumeFile* anatomyVolume = bmsv->getAnatomyVolumeFile(); if (anatomyVolume == NULL) { return; } // // Check for valid dimensions // int dim[3]; anatomyVolume->getDimensions(dim); if ((dim[0] <= 0) || (dim[1] <= 0) || (dim[2] <= 0)) { return; } // // Make sure/update anatomy volume coloring // BrainModelVolumeVoxelColoring* voxelColoring = brainSet->getVoxelColoring(); // // Get the selected slices // int slices[3]; bmsv->getSelectedSlices(slices); // // Get the volume spacing // float spacing[3]; anatomyVolume->getSpacing(spacing); // // Get the origin // float originCenter[3], originCorner[3]; anatomyVolume->getOrigin(originCenter); anatomyVolume->getOriginAtCornerOfVoxel(originCorner); // // Might be drawing secondary overlay on the slices // bool drawSecondaryDataOnSlices = false; VolumeFile* secondaryVolumeFile = bmsv->getOverlaySecondaryVolumeFile(); if (bmsv->getDisplaySecondaryOverlayVolumeOnSlices()) { if (secondaryVolumeFile != NULL) { drawSecondaryDataOnSlices = true; } } // // Might be drawing primary overlay on the slices // bool drawPrimaryDataOnSlices = false; VolumeFile* primaryVolumeFile = bmsv->getOverlayPrimaryVolumeFile(); if (bmsv->getDisplayPrimaryOverlayVolumeOnSlices()) { if (primaryVolumeFile != NULL) { drawPrimaryDataOnSlices = true; } } // // Draw the horizontal slice // if (bmsv->getDisplayHorizontalSlice()) { const float sliceZ = slices[2] * spacing[2] + originCenter[2]; for (int i = 0; i < dim[0]; i++) { for (int j = 0; j < dim[1]; j++) { int ijk[3] = { i, j, slices[2] }; unsigned char rgb[4]; voxelColoring->getVoxelColoring(anatomyVolume, ijk[0], ijk[1], ijk[2], rgb); glColor3ubv(rgb); const float xCenter = i * spacing[0] + originCenter[0]; const float yCenter = j * spacing[1] + originCenter[1]; const float xCorner = i * spacing[0] + originCorner[0]; const float yCorner = j * spacing[1] + originCorner[1]; bool drawIt = false; if (rgb[3] == VolumeFile::VOXEL_COLOR_STATUS_VALID) { // // Avoid drawing black voxels // if ((rgb[0] != 0) || (rgb[1] != 0) || (rgb[2] != 0)) { drawIt = true; } if (bmsv->getDrawAnatomyBlackVoxels()) { drawIt = true; } } unsigned long maskForThisSlice = SELECTION_MASK_OFF; if (selectionMask & SELECTION_MASK_VOXEL_UNDERLAY) { maskForThisSlice = SELECTION_MASK_VOXEL_UNDERLAY; } if (drawSecondaryDataOnSlices) { float xyz[3] = { xCenter, yCenter, sliceZ }; float p[3]; if (secondaryVolumeFile->convertCoordinatesToVoxelIJK(xyz, ijk, p)!=0) { voxelColoring->getVoxelColoring(secondaryVolumeFile, ijk[0], ijk[1], ijk[2], rgb); if (rgb[3] == VolumeFile::VOXEL_COLOR_STATUS_VALID) { glColor3ubv(rgb); drawIt = true; if (selectionMask & SELECTION_MASK_VOXEL_OVERLAY_SECONDARY) { maskForThisSlice = SELECTION_MASK_VOXEL_OVERLAY_SECONDARY; } } } } if (drawPrimaryDataOnSlices) { float xyz[3] = { xCenter, yCenter, sliceZ }; float p[3]; if (primaryVolumeFile->convertCoordinatesToVoxelIJK(xyz, ijk, p)!=0) { voxelColoring->getVoxelColoring(primaryVolumeFile, ijk[0], ijk[1], ijk[2], rgb); if (rgb[3] == VolumeFile::VOXEL_COLOR_STATUS_VALID) { glColor3ubv(rgb); drawIt = true; if (selectionMask & SELECTION_MASK_VOXEL_OVERLAY_PRIMARY) { maskForThisSlice = SELECTION_MASK_VOXEL_OVERLAY_PRIMARY; } } } } if (drawIt) { if (maskForThisSlice != SELECTION_MASK_OFF) { glPushName(maskForThisSlice); glPushName(ijk[0]); glPushName(ijk[1]); glPushName(ijk[2]); glPushName(VolumeFile::VOLUME_AXIS_Z); } glBegin(GL_QUADS); glVertex3f(xCorner, yCorner, sliceZ); glVertex3f(xCorner + spacing[0], yCorner, sliceZ); glVertex3f(xCorner + spacing[0], yCorner + spacing[1], sliceZ); glVertex3f(xCorner, yCorner + spacing[1], sliceZ); glEnd(); if (maskForThisSlice != SELECTION_MASK_OFF) { glPopName(); glPopName(); glPopName(); glPopName(); glPopName(); } } } } } // // Draw the coronal slice // if (bmsv->getDisplayCoronalSlice()) { const float sliceY = slices[1] * spacing[1] + originCenter[1]; for (int i = 0; i < dim[0]; i++) { for (int k = 0; k < dim[2]; k++) { int ijk[3] = { i, slices[1], k }; unsigned char rgb[4]; voxelColoring->getVoxelColoring(anatomyVolume, ijk[0], ijk[1], ijk[2], rgb); glColor3ubv(rgb); const float xCenter = i * spacing[0] + originCenter[0]; const float zCenter = k * spacing[2] + originCenter[2]; const float xCorner = i * spacing[0] + originCorner[0]; const float zCorner = k * spacing[2] + originCorner[2]; bool drawIt = false; if (rgb[3] == VolumeFile::VOXEL_COLOR_STATUS_VALID) { // // Avoid drawing black voxels // if ((rgb[0] != 0) || (rgb[1] != 0) || (rgb[2] != 0)) { drawIt = true; } if (bmsv->getDrawAnatomyBlackVoxels()) { drawIt = true; } } unsigned long maskForThisSlice = SELECTION_MASK_OFF; if (selectionMask & SELECTION_MASK_VOXEL_UNDERLAY) { maskForThisSlice = SELECTION_MASK_VOXEL_UNDERLAY; } if (drawSecondaryDataOnSlices) { float xyz[3] = { xCenter, sliceY, zCenter }; float p[3]; if (secondaryVolumeFile->convertCoordinatesToVoxelIJK(xyz, ijk, p)!=0) { voxelColoring->getVoxelColoring(secondaryVolumeFile, ijk[0], ijk[1], ijk[2], rgb); if (rgb[3] == VolumeFile::VOXEL_COLOR_STATUS_VALID) { glColor3ubv(rgb); drawIt = true; if (selectionMask & SELECTION_MASK_VOXEL_OVERLAY_SECONDARY) { maskForThisSlice = SELECTION_MASK_VOXEL_OVERLAY_SECONDARY; } } } } if (drawPrimaryDataOnSlices) { float xyz[3] = { xCenter, sliceY, zCenter }; float p[3]; if (primaryVolumeFile->convertCoordinatesToVoxelIJK(xyz, ijk, p)!=0) { voxelColoring->getVoxelColoring(primaryVolumeFile, ijk[0], ijk[1], ijk[2], rgb); if (rgb[3] == VolumeFile::VOXEL_COLOR_STATUS_VALID) { glColor3ubv(rgb); drawIt = true; if (selectionMask & SELECTION_MASK_VOXEL_OVERLAY_PRIMARY) { maskForThisSlice = SELECTION_MASK_VOXEL_OVERLAY_PRIMARY; } } } } if (drawIt) { if (maskForThisSlice != SELECTION_MASK_OFF) { glPushName(maskForThisSlice); glPushName(ijk[0]); glPushName(ijk[1]); glPushName(ijk[2]); glPushName(VolumeFile::VOLUME_AXIS_Y); } glBegin(GL_QUADS); glVertex3f(xCorner, sliceY, zCorner); glVertex3f(xCorner + spacing[0], sliceY, zCorner); glVertex3f(xCorner + spacing[0], sliceY, zCorner + spacing[2]); glVertex3f(xCorner, sliceY, zCorner + spacing[2]); glEnd(); if (maskForThisSlice != SELECTION_MASK_OFF) { glPopName(); glPopName(); glPopName(); glPopName(); glPopName(); } } } } } // // Draw the parasaggital slice // if (bmsv->getDisplayParasagittalSlice()) { const float sliceX = slices[0] * spacing[0] + originCenter[0]; for (int j = 0; j < dim[1]; j++) { for (int k = 0; k < dim[2]; k++) { int ijk[3] = { slices[0], j, k }; unsigned char rgb[4]; voxelColoring->getVoxelColoring(anatomyVolume, ijk[0], ijk[1], ijk[2], rgb); glColor3ubv(rgb); const float yCenter = j * spacing[1] + originCenter[1]; const float zCenter = k * spacing[2] + originCenter[2]; const float yCorner = j * spacing[1] + originCorner[1]; const float zCorner = k * spacing[2] + originCorner[2]; bool drawIt = false; if (rgb[3] == VolumeFile::VOXEL_COLOR_STATUS_VALID) { // // Avoid drawing black voxels // if ((rgb[0] != 0) || (rgb[1] != 0) || (rgb[2] != 0)) { drawIt = true; } if (bmsv->getDrawAnatomyBlackVoxels()) { drawIt = true; } } unsigned long maskForThisSlice = SELECTION_MASK_OFF; if (selectionMask & SELECTION_MASK_VOXEL_UNDERLAY) { maskForThisSlice = SELECTION_MASK_VOXEL_UNDERLAY; } if (drawSecondaryDataOnSlices) { float xyz[3] = { sliceX, yCenter, zCenter }; float p[3]; if (secondaryVolumeFile->convertCoordinatesToVoxelIJK(xyz, ijk, p)!=0) { voxelColoring->getVoxelColoring(secondaryVolumeFile, ijk[0], ijk[1], ijk[2], rgb); if (rgb[3] == VolumeFile::VOXEL_COLOR_STATUS_VALID) { glColor3ubv(rgb); drawIt = true; if (selectionMask & SELECTION_MASK_VOXEL_OVERLAY_SECONDARY) { maskForThisSlice = SELECTION_MASK_VOXEL_OVERLAY_SECONDARY; } } } } if (drawPrimaryDataOnSlices) { float xyz[3] = { sliceX, yCenter, zCenter }; float p[3]; if (primaryVolumeFile->convertCoordinatesToVoxelIJK(xyz, ijk, p)!=0) { voxelColoring->getVoxelColoring(primaryVolumeFile, ijk[0], ijk[1], ijk[2], rgb); if (rgb[3] == VolumeFile::VOXEL_COLOR_STATUS_VALID) { glColor3ubv(rgb); drawIt = true; if (selectionMask & SELECTION_MASK_VOXEL_OVERLAY_PRIMARY) { maskForThisSlice = SELECTION_MASK_VOXEL_OVERLAY_PRIMARY; } } } } if (drawIt) { if (maskForThisSlice != SELECTION_MASK_OFF) { glPushName(maskForThisSlice); glPushName(ijk[0]); glPushName(ijk[1]); glPushName(ijk[2]); glPushName(VolumeFile::VOLUME_AXIS_X); } glBegin(GL_QUADS); glVertex3f(sliceX, yCorner, zCorner); glVertex3f(sliceX, yCorner + spacing[1], zCorner); glVertex3f(sliceX, yCorner + spacing[1], zCorner + spacing[2]); glVertex3f(sliceX, yCorner, zCorner + spacing[2]); glEnd(); if (maskForThisSlice != SELECTION_MASK_OFF) { glPopName(); glPopName(); glPopName(); glPopName(); glPopName(); } } } } } // // Draw functional and segmentation volume clouds and view dependend anatomy slice // for (int mm = 0; mm < 4; mm++) { // // Get display list number for this surface // PreferencesFile* pf = brainSet->getPreferencesFile(); bool displayListsEnabled = pf->getDisplayListsEnabled(); displayListsEnabled = false; /// DISPLAY LISTS DO NOT WORK FOR VOLUME CLOUD /// MAC HANGS WHEN LIST EXECUTED unsigned long displayListNumber = 0; bool showIt = false; VolumeFile* vf = NULL; unsigned char alpha = 255; bool opacityEnabled = false; int cloudSelectionMask = 0; bool useLighting = true; bool doingAnatomyViewDepSlice = false; switch (mm) { case 0: // functional volume cloud showIt = bmsv->getDisplayFunctionalVolumeCloud(); vf = bmsv->getFunctionalVolumeFile(); displayListNumber = bmsv->getVoxelCloudDisplayListNumber(); opacityEnabled = bmsv->getFunctionalVolumeCloudOpacityEnabled(); alpha = static_cast( std::min(bmsv->getFunctionalVolumeCloudOpacity() * 255.0, 255.0)); cloudSelectionMask = SELECTION_MASK_VOXEL_FUNCTIONAL_CLOUD; break; case 1: // segmentation volume cloud showIt = bmsv->getDisplaySegmentationVolumeCloud(); vf = bmsv->getSegmentationVolumeFile(); displayListNumber = 0; break; case 2: // view dependent anatomy slice showIt = bmsv->getDisplayViewDependentSlice(); vf = bmsv->getAnatomyVolumeFile(); displayListNumber = 0; useLighting = false; doingAnatomyViewDepSlice = true; break; case 3: showIt = bmsv->getDisplayVectorVolumeCloud(); vf = bmsv->getVectorVolumeFile(); displayListNumber = 0; useLighting = false; break; } // // Display volume "cloud" // if (showIt) { // // Make sure volume is valid // if (vf != NULL) { // // If need to redraw surface // const bool idMode = (selectionMask != 0); if ((displayListNumber == 0) || (displayListsEnabled == false) || idMode) { // // If not ID mode then need to create a new display list for this surface // bool creatingDisplayList = false; if (displayListsEnabled && (idMode == false)) { displayListNumber = glGenLists(1); bmsv->setVoxelCloudDisplayListNumber(displayListNumber); glNewList(displayListNumber, GL_COMPILE); creatingDisplayList = true; } // // turn on lighting // if (useLighting) { glEnable(GL_LIGHTING); glEnable(GL_LIGHT1); glEnable(GL_COLOR_MATERIAL); } // // Get the volume spacing // float spacing[3]; vf->getSpacing(spacing); // // Get the origin // float originCorner[3]; vf->getOriginAtCornerOfVoxel(originCorner); float originCenter[3]; vf->getOrigin(originCenter); // // Check for valid dimensions // int dim[3]; vf->getDimensions(dim); if (opacityEnabled) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } // // Check/Update voxel to surface distances // const float distanceThreshold = bmsv->getFunctionalVolumeDistanceThreshold(); float* voxelToSurfaceDistances = NULL; const bool voxelToSurfaceDistancesValid = false; // // If this is the anatomical view dependent slice // if (doingAnatomyViewDepSlice) { glPushMatrix(); glLoadIdentity(); // // Create and enable the clipping planes to only draw // when (-thickness <= Z <= thickness) // const float thickness = 1.0; GLdouble clipPlanePositive[4] = { // should clip (Z < -thickness) 0.0, 0.0, -1.0, //-thickness, thickness }; GLdouble clipPlaneNegative[4] = { // should clip (Z > thickness) 0.0, 0.0, 1.0, // thickness, thickness }; glClipPlane(GL_CLIP_PLANE0, clipPlanePositive); glClipPlane(GL_CLIP_PLANE1, clipPlaneNegative); glEnable(GL_CLIP_PLANE0); glEnable(GL_CLIP_PLANE1); glPopMatrix(); } const float sx = spacing[0]; const float sy = spacing[1]; const float sz = spacing[2]; const bool drawVectorsFlag = (vf->getVolumeType() == VolumeFile::VOLUME_TYPE_VECTOR); int increment = 1; if (drawVectorsFlag) { DisplaySettingsVolume* dsv = brainSet->getDisplaySettingsVolume(); increment = dsv->getVectorVolumeSparsity(); } // // Draw the voxels // for (int i = 0; i < dim[0]; i += increment) { for (int j = 0; j < dim[1]; j += increment) { for (int k = 0; k < dim[2]; k += increment) { int ijk[3] = { i, j, k }; const int pointID = vf->getVoxelNumber(ijk); if (voxelToSurfaceDistancesValid) { if (voxelToSurfaceDistances[pointID] > distanceThreshold) { continue; } } unsigned char rgb[4]; voxelColoring->getVoxelColoring(vf, i, j, k, rgb); if (rgb[3] == VolumeFile::VOXEL_COLOR_STATUS_VALID) { glColor4ub(rgb[0], rgb[1], rgb[2], alpha); if (selectionMask & cloudSelectionMask) { glPushName(cloudSelectionMask); glPushName(i); glPushName(j); glPushName(k); } // // Is this a vector volume // if (drawVectorsFlag) { const float x = i * sx + originCenter[0]; const float y = j * sy + originCenter[1]; const float z = k * sz + originCenter[2]; const float xp = x + sx; const float yp = y + sy; const float zp = z + sz; const float mag = vf->getVoxel(i, j, k, 3); glBegin(GL_LINES); glColor4ub(255, 0, 0, 255); glVertex3f(xp, yp, zp); glColor4ub(255, 255, 0, 255); glVertex3f(xp + vf->getVoxel(i, j, k, 0) * mag, yp + vf->getVoxel(i, j, k, 1) * mag, zp + vf->getVoxel(i, j, k, 2) * mag); glEnd(); } else { const float x = i * sx + originCorner[0]; const float y = j * sy + originCorner[1]; const float z = k * sz + originCorner[2]; glBegin(GL_QUADS); // // Near face // glNormal3f(0.0, 0.0, 1.0); glVertex3f( x, y, z); glVertex3f(x + sx, y, z); glVertex3f(x + sx, y + sy, z); glVertex3f( x, y + sy, z); // // Far face // glNormal3f(0.0, 0.0, -1.0); glVertex3f(x + sx, y, z + sz); glVertex3f( x, y, z + sz); glVertex3f( x, y + sy, z + sz); glVertex3f(x + sx, y + sy, z + sz); // // Right face // glNormal3f(1.0, 0.0, 0.0); glVertex3f(x + sx, y, z); glVertex3f(x + sx, y, z + sz); glVertex3f(x + sx, y + sy, z + sz); glVertex3f(x + sx, y + sy, z); // // Left face // glNormal3f(-1.0, 0.0, 0.0); glVertex3f(x, y, z); glVertex3f(x, y + sy, z); glVertex3f(x, y + sy, z + sz); glVertex3f(x, y, z + sz); // // Bottom face // glNormal3f(0.0, -1.0, 0.0); glVertex3f(x, y, z); glVertex3f(x, y, z + sz); glVertex3f(x + sx, y, z + sz); glVertex3f(x + sx, y, z); // // Top face // glNormal3f(0.0, 1.0, 0.0); glVertex3f(x, y + sy, z); glVertex3f(x + sx, y + sy, z); glVertex3f(x + sx, y + sy, z + sz); glVertex3f(x, y + sy, z + sz); glEnd(); } if (selectionMask & cloudSelectionMask) { glPopName(); glPopName(); glPopName(); glPopName(); } } } } } if (opacityEnabled) { glDisable(GL_BLEND); } //glDisable(GL_COLOR_MATERIAL); glDisable(GL_LIGHTING); glDisable(GL_LIGHT1); glDisable(GL_COLOR_MATERIAL); // // If this is the anatomical view dependent slice // if (doingAnatomyViewDepSlice) { glDisable(GL_CLIP_PLANE0); glDisable(GL_CLIP_PLANE1); } // // End display list if creating a display list // if (creatingDisplayList) { glEndList(); } } // // If display lists enabled, execute it // if (displayListsEnabled && (idMode == false)) { if (glIsList(displayListNumber)) { glCallList(displayListNumber); } else { std::cout << "PROGRAM WARNING: display list " << displayListNumber << " does not exist for surface and volume " << bmsv->getDescriptiveName().toAscii().constData() << " in window " << viewingWindowNumber << std::endl; } } } } } // // turn off lighting // glDisable(GL_LIGHTING); glDisable(GL_LIGHT1); // // Draw the palette // drawMetricPalette(bmsv->getBrainModelIndex(), true); // // Draw shape bar // drawShapePalette(bmsv->getBrainModelIndex()); } /** * Draw a volume slice */ void BrainModelOpenGL::drawVolumeSliceOverlayAndUnderlay(BrainModelVolume* bmv, const VolumeFile::VOLUME_AXIS volumeSliceAxis, const int currentSlice, VolumeFile* &firstVolume) { bool firstVolumeFlag = true; firstVolume = NULL; float firstVolumeVoxelSize = 1.0; float volumeSliceCoordinate = 0.0; // // Draw the underlay and the overlays // for (int i = 0; i < 4; i++) { // // Should only the underlay be shown in a viewing window // if (i > 0) { if (viewingWindowNumber > 0) { if (bmv->getUnderlayVolumeFile()) { if (bmv->getShowUnderlayOnlyInWindow(viewingWindowNumber)) { continue; } } } } bool overlayFlag = false; unsigned long theSelectionMask = SELECTION_MASK_OFF; VolumeFile* vf = NULL; switch(i) { case 0: theSelectionMask = SELECTION_MASK_VOXEL_UNDERLAY; vf = bmv->getUnderlayVolumeFile(); break; case 1: theSelectionMask = SELECTION_MASK_VOXEL_OVERLAY_SECONDARY; vf = bmv->getOverlaySecondaryVolumeFile(); overlayFlag = true; break; case 2: theSelectionMask = SELECTION_MASK_VOXEL_OVERLAY_PRIMARY; vf = bmv->getOverlayPrimaryVolumeFile(); overlayFlag = true; break; case 3: { // // Draw the selected voxels for Region of Interest // BrainModelVolumeRegionOfInterest* roi = brainSet->getVolumeRegionOfInterestController(); if (roi->getDisplayVolumeROI()) { vf = roi->getROIVolume(); } } break; } if (vf != NULL) { // // Get origin and spacing // float originCenter[3], originCorner[3], spacing[3]; int dim[3]; vf->getOrigin(originCenter); vf->getOriginAtCornerOfVoxel(originCorner); vf->getSpacing(spacing); vf->getDimensions(dim); int sliceToDraw = currentSlice; if (firstVolumeFlag) { firstVolumeFlag = false; firstVolume = vf; switch(volumeSliceAxis) { case VolumeFile::VOLUME_AXIS_X: // PARASAGITTAL volumeSliceCoordinate = currentSlice * spacing[0] + originCenter[0]; firstVolumeVoxelSize = spacing[0]; break; case VolumeFile::VOLUME_AXIS_Y: // CORONAL volumeSliceCoordinate = currentSlice * spacing[1] + originCenter[1]; firstVolumeVoxelSize = spacing[1]; break; case VolumeFile::VOLUME_AXIS_Z: // HORIZONTAL volumeSliceCoordinate = currentSlice * spacing[2] + originCenter[2]; firstVolumeVoxelSize = spacing[2]; break; default: std::cout << "PROGRAM ERROR: Invalid volume axis at " << __LINE__ << " in " << __FILE__ << std::endl; return; } } else { sliceToDraw = -1; float sliceDistance = std::numeric_limits::max(); switch(volumeSliceAxis) { case VolumeFile::VOLUME_AXIS_X: // PARASAGITTAL for (int i = 0; i < dim[0]; i++) { const float val = i * spacing[0] + originCenter[0]; const float dist = fabs(volumeSliceCoordinate - val); if (dist < sliceDistance) { sliceToDraw = i; sliceDistance = dist; } } break; case VolumeFile::VOLUME_AXIS_Y: // CORONAL for (int i = 0; i < dim[1]; i++) { const float val = i * spacing[1] + originCenter[1]; const float dist = fabs(volumeSliceCoordinate - val); if (dist < sliceDistance) { sliceToDraw = i; sliceDistance = dist; } } break; case VolumeFile::VOLUME_AXIS_Z: // HORIZONTAL for (int i = 0; i < dim[2]; i++) { const float val = i * spacing[2] + originCenter[2]; const float dist = fabs(volumeSliceCoordinate - val); if (dist < sliceDistance) { sliceToDraw = i; sliceDistance = dist; } } break; default: std::cout << "PROGRAM ERROR: Invalid volume axis at " << __LINE__ << " in " << __FILE__ << std::endl; return; } } drawVolumeFileSlice(vf, volumeSliceAxis, sliceToDraw, theSelectionMask, overlayFlag); } } // // Draw volume borders // DisplaySettingsBorders* dsb = brainSet->getDisplaySettingsBorders(); if (dsb->getDisplayBorders()) { drawVolumeBorderFile(volumeSliceAxis, volumeSliceCoordinate, firstVolumeVoxelSize); } // // Draw the volume cells // DisplaySettingsCells* dsc = brainSet->getDisplaySettingsCells(); if (dsc->getDisplayVolumeCells()) { drawVolumeCellFile(volumeSliceAxis, volumeSliceCoordinate, firstVolumeVoxelSize); } // // Draw the volume foci // DisplaySettingsFoci* dsf = brainSet->getDisplaySettingsFoci(); if (dsf->getDisplayVolumeCells()) { drawVolumeFociFile(volumeSliceAxis, volumeSliceCoordinate, firstVolumeVoxelSize); } // // Draw vectors on the volume // drawVectorsOnVolume(volumeSliceAxis, volumeSliceCoordinate, firstVolumeVoxelSize); // // Draw contours over volume slices // drawVolumeContourFile(volumeSliceAxis, volumeSliceCoordinate, firstVolumeVoxelSize); // // Draw outline of surface and transformation axes // drawVolumeSurfaceOutlineAndTransformationMatrixAxes(bmv, volumeSliceAxis, volumeSliceCoordinate); // // Draw the identify symbols // drawVolumeIdentifySymbols(volumeSliceAxis, volumeSliceCoordinate); } /** * draw volume with oblique ALL axis. */ void BrainModelOpenGL::drawBrainModelVolumeObliqueAllAxis(BrainModelVolume* bmv) { glDisable(GL_DEPTH_TEST); // // See if selecting // bool selectFlag = false; if (selectionMask & SELECTION_MASK_VOXEL_UNDERLAY) { selectFlag = true; } else if (selectionMask != 0) { return; } // // Get the current slices // //int slices[3]; //bmv->getSelectedSlices(viewingWindowNumber, slices); // // Determine viewport height and width // const int vpHeight = viewport[3] / 2; const int vpWidth = viewport[2] / 2; for (int j = 0; j < 2; j++) { for (int i = 0; i < 2; i++) { // // viewport X & Y // const int vpX = i * vpWidth; const int vpY = j * vpHeight; // // if selecting, only draw if mouse is in this viewport // if (selectionMask != SELECTION_MASK_OFF) { if ((selectionX < vpX) || (selectionY < vpY) || (selectionX > (vpX + vpWidth)) || (selectionY > (vpY + vpHeight))) { continue; } } // // Set the viewport // glViewport(vpX, vpY, vpWidth, vpHeight); if (selectionMask == SELECTION_MASK_OFF) { glGetIntegerv(GL_VIEWPORT, selectionViewport[viewingWindowNumber]); } // // Set orthographic transform // if (selectionMask == SELECTION_MASK_OFF) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(orthographicLeft[viewingWindowNumber], orthographicRight[viewingWindowNumber], orthographicBottom[viewingWindowNumber], orthographicTop[viewingWindowNumber], orthographicNear[viewingWindowNumber], orthographicFar[viewingWindowNumber]); glGetDoublev(GL_PROJECTION_MATRIX, selectionProjectionMatrix[viewingWindowNumber]); } glMatrixMode(GL_MODELVIEW); glLoadIdentity(); // // Save modeling matrix // if (selectionMask == SELECTION_MASK_OFF) { glGetDoublev(GL_MODELVIEW_MATRIX, selectionModelviewMatrix[viewingWindowNumber]); } if (i == 0) { if (j == 0) { VolumeFile* vf = bmv->getUnderlayVolumeFile(); if (vf == NULL) { vf = bmv->getOverlaySecondaryVolumeFile(); } if (vf == NULL) { vf = bmv->getOverlayPrimaryVolumeFile(); } // // Draw the crosshair coordinates // if (vf != NULL) { //drawVolumeCrosshairCoordinates(bmv, vf, vpHeight); } BrainModelSurface* bms = brainSet->getActiveFiducialSurface(); if (bms != NULL) { glEnable(GL_DEPTH_TEST); drawBrainModelSurface(bms, NULL, true, true); // // Get the current oblique slices // int slices[3]; bmv->getSelectedObliqueSlices(slices); // // Draw the volume slices // if (vf != NULL) { int dim[3]; vf->getDimensions(dim); float originCenter[3], originCorner[3], spacing[3]; vf->getOrigin(originCenter); vf->getOriginAtCornerOfVoxel(originCorner); vf->getSpacing(spacing); const float minX = originCorner[0]; const float maxX = originCorner[0] + spacing[0] * dim[0]; const float minY = originCorner[1]; const float maxY = originCorner[1] + spacing[1] * dim[1]; const float minZ = originCorner[2]; const float maxZ = originCorner[2] + spacing[2] * dim[2]; float sliceX = originCenter[0] + spacing[0] * slices[0]; float sliceY = originCenter[1] + spacing[1] * slices[1]; float sliceZ = originCenter[2] + spacing[2] * slices[2]; int sliceOffsets[3]; bmv->getSelectedObliqueSliceOffsets(viewingWindowNumber, sliceOffsets); sliceX += sliceOffsets[0]; sliceY += sliceOffsets[1]; sliceZ += sliceOffsets[2]; glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glColor4ub(190, 190, 190, 130); glPushMatrix(); GLfloat mat[16]; DisplaySettingsVolume* dsv = brainSet->getDisplaySettingsVolume(); const TransformationMatrix* obtm = dsv->getObliqueSlicesTransformationMatrix(); if (obtm != NULL) { obtm->getMatrix(mat); } else { bmv->getObliqueRotationMatrix(mat); // USE MAIN WINDOW MATRIX } glMultMatrixf(mat); glBegin(GL_TRIANGLES); glVertex3f(sliceX, minY, minZ); glVertex3f(sliceX, maxY, minZ); glVertex3f(sliceX, maxY, maxZ); glVertex3f(sliceX, minY, minZ); glVertex3f(sliceX, maxY, maxZ); glVertex3f(sliceX, minY, maxZ); glVertex3f(minX, sliceY, minZ); glVertex3f(maxX, sliceY, minZ); glVertex3f(maxX, sliceY, maxZ); glVertex3f(minX, sliceY, minZ); glVertex3f(maxX, sliceY, maxZ); glVertex3f(minX, sliceY, maxZ); glVertex3f(minX, minY, sliceZ); glVertex3f(maxX, minY, sliceZ); glVertex3f(maxX, maxY, sliceZ); glVertex3f(minX, minY, sliceZ); glVertex3f(maxX, maxY, sliceZ); glVertex3f(minX, maxY, sliceZ); glEnd(); glPopMatrix(); glDisable(GL_BLEND); } glDisable(GL_DEPTH_TEST); } } else { // // Draw parasaggital // drawBrainModelVolumeObliqueAxisSlice(bmv, VolumeFile::VOLUME_AXIS_OBLIQUE_X, 0, selectFlag); } } else { if (j == 0) { // // Draw horizontal // drawBrainModelVolumeObliqueAxisSlice(bmv, VolumeFile::VOLUME_AXIS_OBLIQUE_Z, 0, selectFlag); } else { // // Draw coronal // drawBrainModelVolumeObliqueAxisSlice(bmv, VolumeFile::VOLUME_AXIS_OBLIQUE_Y, 0, selectFlag); } } } } glEnable(GL_DEPTH_TEST); } /** * draw volume with oblique axis montage. */ void BrainModelOpenGL::drawBrainModelVolumeObliqueAxisMontage(BrainModelVolume* bmv, const bool selectFlag) { const DisplaySettingsVolume* dsv = brainSet->getDisplaySettingsVolume(); // // Don't set projection matrix when selecting // if (selectionMask == SELECTION_MASK_OFF) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(orthographicLeft[viewingWindowNumber], orthographicRight[viewingWindowNumber], orthographicBottom[viewingWindowNumber], orthographicTop[viewingWindowNumber], orthographicNear[viewingWindowNumber], orthographicFar[viewingWindowNumber]); glGetDoublev(GL_PROJECTION_MATRIX, selectionProjectionMatrix[viewingWindowNumber]); } // // Get montage info // int rows, columns, sliceIncrement; dsv->getMontageViewSettings(rows, columns, sliceIncrement); // // Montage slice offset // int montageSliceOffset = 0; // // Determine viewport height and width // const int vpHeight = viewport[3] / rows; const int vpWidth = viewport[2] / columns; for (int i = (rows - 1); i >= 0; i--) { for (int j = 0; j < columns; j++) { //for (int i = 0; i < rows; i++) { const int vpX = j * vpWidth; const int vpY = i * vpHeight; // // if selecting, only draw if mouse is in this viewport // if (selectFlag) { if ((selectionX < vpX) || (selectionY < vpY) || (selectionX > (vpX + vpWidth)) || (selectionY > (vpY + vpHeight))) { continue; } } // // Set the viewport // glViewport(vpX, vpY, vpWidth, vpHeight); // // Don't set projection matrix when selecting // if (selectFlag == false) { // // Set orthographic transform // glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(orthographicLeft[viewingWindowNumber], orthographicRight[viewingWindowNumber], orthographicBottom[viewingWindowNumber], orthographicTop[viewingWindowNumber], orthographicNear[viewingWindowNumber], orthographicFar[viewingWindowNumber]); glGetDoublev(GL_PROJECTION_MATRIX, selectionProjectionMatrix[viewingWindowNumber]); } glMatrixMode(GL_MODELVIEW); glLoadIdentity(); drawBrainModelVolumeObliqueAxisSlice(bmv, bmv->getSelectedAxis(viewingWindowNumber), montageSliceOffset, selectFlag); // // Move to next slice // montageSliceOffset += sliceIncrement; } } } /** * draw volume with oblique axis. */ void BrainModelOpenGL::drawBrainModelVolumeObliqueAxis(BrainModelVolume* bmv) { // // Get the master volume file // const VolumeFile* masterVolume = bmv->getMasterVolumeFile(); if (masterVolume == NULL) { return; } DisplaySettingsVolume* dsv = brainSet->getDisplaySettingsVolume(); // // See if selecting // bool selectFlag = false; if (selectionMask & SELECTION_MASK_VOXEL_UNDERLAY) { selectFlag = true; } else if (selectionMask != 0) { return; } switch(bmv->getSelectedAxis(viewingWindowNumber)) { case VolumeFile::VOLUME_AXIS_X: case VolumeFile::VOLUME_AXIS_Y: case VolumeFile::VOLUME_AXIS_Z: case VolumeFile::VOLUME_AXIS_ALL: case VolumeFile::VOLUME_AXIS_OBLIQUE: break; case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: if (dsv->getMontageViewSelected()) { drawBrainModelVolumeObliqueAxisMontage(bmv, selectFlag); return; } break; case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } // // Don't set projection matrix when selecting // if (selectFlag == false) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(orthographicLeft[viewingWindowNumber], orthographicRight[viewingWindowNumber], orthographicBottom[viewingWindowNumber], orthographicTop[viewingWindowNumber], orthographicNear[viewingWindowNumber], orthographicFar[viewingWindowNumber]); glGetDoublev(GL_PROJECTION_MATRIX, selectionProjectionMatrix[viewingWindowNumber]); } glMatrixMode(GL_MODELVIEW); glLoadIdentity(); drawBrainModelVolumeObliqueAxisSlice(bmv, bmv->getSelectedAxis(viewingWindowNumber), 0, selectFlag); } /** * draw volume with oblique axis. */ void BrainModelOpenGL::drawBrainModelVolumeObliqueAxisSlice(BrainModelVolume* bmv, VolumeFile::VOLUME_AXIS axis, const int montageOffset, const bool selectFlag) { // // Get the master volume file // const VolumeFile* masterVolume = bmv->getMasterVolumeFile(); if (masterVolume == NULL) { return; } DisplaySettingsVolume* dsv = brainSet->getDisplaySettingsVolume(); // // Save modeling matrix // if (selectFlag == false) { glGetDoublev(GL_MODELVIEW_MATRIX, selectionModelviewMatrix[viewingWindowNumber]); } // // Create a transformation matrix // TransformationMatrix tm; int sliceOffsets[3] = { 0, 0, 0 }; switch (axis) { case VolumeFile::VOLUME_AXIS_X: return; break; case VolumeFile::VOLUME_AXIS_Y: return; break; case VolumeFile::VOLUME_AXIS_Z: return; break; case VolumeFile::VOLUME_AXIS_ALL: return; break; case VolumeFile::VOLUME_AXIS_OBLIQUE: { // // Get the current oblique slices // int slices[3]; bmv->getSelectedObliqueSlices(slices); // // Get coordinate of slices // float xyz[3]; masterVolume->getVoxelCoordinate(slices, xyz); // // Translate by the slices // tm.translate(xyz); // // Rotate by the oblique rotation matrix // vtkTransform* rotationMatrix = bmv->getObliqueRotationMatrix(); TransformationMatrix rotMatrix; rotMatrix.setMatrix(rotationMatrix); tm.preMultiply(rotMatrix); } break; case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: { int montageSliceOffsets[3] = { 0, 0, 0 }; if (axis == VolumeFile::VOLUME_AXIS_OBLIQUE_X) { montageSliceOffsets[0] = montageOffset; } else if (axis == VolumeFile::VOLUME_AXIS_OBLIQUE_Y) { montageSliceOffsets[1] = montageOffset; } else if (axis == VolumeFile::VOLUME_AXIS_OBLIQUE_Z) { montageSliceOffsets[2] = montageOffset; } // // NEED TO ADD SLICE OFFSETS // const TransformationMatrix* obtm = dsv->getObliqueSlicesTransformationMatrix(); if (obtm != NULL) { tm = *obtm; TransformationMatrix rotMatrix = tm; rotMatrix.setTranslation(0.0, 0.0, 0.0); // // Add in slice offsets // bmv->getSelectedObliqueSliceOffsets(viewingWindowNumber, sliceOffsets); // // Montage offsets // sliceOffsets[0] += montageSliceOffsets[0]; sliceOffsets[1] += montageSliceOffsets[1]; sliceOffsets[2] += montageSliceOffsets[2]; float offsetXYZ[3] = { static_cast(sliceOffsets[0]), static_cast(sliceOffsets[1]), static_cast(sliceOffsets[2]) }; rotMatrix.multiplyPoint(offsetXYZ); TransformationMatrix tm2; tm2.translate(offsetXYZ[0], offsetXYZ[1], offsetXYZ[2]); tm.preMultiply(tm2); } else { // // Get the rotation matrix // vtkTransform* rotationMatrix = bmv->getObliqueRotationMatrix(); tm.setMatrix(rotationMatrix); const TransformationMatrix rotMatrix = tm; // // Get the current oblique slices // int slices[3]; bmv->getSelectedObliqueSlices(slices); // // Get coordinate of slices // float xyz[3]; masterVolume->getVoxelCoordinate(slices, xyz); // // Set the translation // tm.setTranslation(xyz[0], xyz[1], xyz[2]); // // Add in slice offsets // bmv->getSelectedObliqueSliceOffsets(viewingWindowNumber, sliceOffsets); // // Montage offsets // sliceOffsets[0] += montageSliceOffsets[0]; sliceOffsets[1] += montageSliceOffsets[1]; sliceOffsets[2] += montageSliceOffsets[2]; float offsetXYZ[3] = { static_cast(sliceOffsets[0]), static_cast(sliceOffsets[1]), static_cast(sliceOffsets[2]) }; rotMatrix.multiplyPoint(offsetXYZ); TransformationMatrix tm2; tm2.translate(offsetXYZ[0], offsetXYZ[1], offsetXYZ[2]); tm.preMultiply(tm2); } } break; case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: return; break; case VolumeFile::VOLUME_AXIS_UNKNOWN: std::cout << "PROGRAM ERROR: UNKNOWN axis for drawing." << std::endl; return; break; } // // Translate but not with matrix // float trans[3]; bmv->getTranslation(viewingWindowNumber, trans); glTranslatef(trans[0], trans[1], trans[2]); // // Apply scaling to the matrix // float scale[3]; bmv->getScaling(viewingWindowNumber, scale); glScalef(scale[0], scale[1], scale[2]); // // Get voxel coloring // BrainModelVolumeVoxelColoring* voxelColoring = brainSet->getVoxelColoring(); // // Determine coords to draw // const float minCoordX = orthographicLeft[viewingWindowNumber]; //-100.0; const float maxCoordX = orthographicRight[viewingWindowNumber]; // 100.0; const float minCoordY = orthographicBottom[viewingWindowNumber]; // -100.0; const float maxCoordY = orthographicTop[viewingWindowNumber]; // 100.0; const float voxSize = dsv->getObliqueSlicesSamplingSize(); //1.0; // // Loop through "oblique slice" // for (float x = minCoordX; x < maxCoordX; x += voxSize) { for (float y = minCoordY; y < maxCoordY; y += voxSize) { // // Apply the transformation matrix to the point // float pt[3] = { x, y, 0.0 }; switch (axis) { case VolumeFile::VOLUME_AXIS_X: return; break; case VolumeFile::VOLUME_AXIS_Y: return; break; case VolumeFile::VOLUME_AXIS_Z: return; break; case VolumeFile::VOLUME_AXIS_ALL: return; break; case VolumeFile::VOLUME_AXIS_OBLIQUE: pt[0] = x; pt[1] = y; pt[2] = 0; break; case VolumeFile::VOLUME_AXIS_OBLIQUE_X: pt[0] = 0.0; pt[1] = x; pt[2] = y; break; case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: pt[0] = x; pt[1] = 0.0; pt[2] = y; break; case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: pt[0] = x; pt[1] = y; pt[2] = 0; break; case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: break; case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } // // Pick location slice offset // const int pickLocation[3] = { static_cast(pt[0]) + sliceOffsets[0], static_cast(pt[1]) + sliceOffsets[1], static_cast(pt[2]) + sliceOffsets[2] }; // // Transforms screen into plane // tm.multiplyPoint(pt); // // Get voxel to draw from "top-most" volume // bool ijkValid = false; int ijk[3]; VolumeFile* vf = NULL; unsigned char rgb[4]; GLuint selMask = SELECTION_MASK_OFF; for (int i = 0; i < 3; i++) { vf = NULL; selMask = SELECTION_MASK_OFF; switch (i) { case 0: if (selectFlag) { selMask = SELECTION_MASK_VOXEL_OVERLAY_PRIMARY; } vf = bmv->getOverlayPrimaryVolumeFile(); break; case 1: if (selectFlag) { selMask = SELECTION_MASK_VOXEL_OVERLAY_SECONDARY; } vf = bmv->getOverlaySecondaryVolumeFile(); break; case 2: if (selectFlag) { selMask = SELECTION_MASK_VOXEL_UNDERLAY; } vf = bmv->getUnderlayVolumeFile(); break; } if (vf != NULL) { // // See if the 3D point is inside the volume // ijkValid = vf->convertCoordinatesToVoxelIJK(pt, ijk); if (ijkValid) { // // See if voxel color is valid // voxelColoring->getVoxelColoring(vf, ijk[0], ijk[1], ijk[2], rgb); ijkValid = (rgb[3] == VolumeFile::VOXEL_COLOR_STATUS_VALID); if (ijkValid) { break; } } } // if (vf != NULL... } // for (i... // // Voxel is in volume // if ((vf != NULL) && ijkValid) { if (selMask != SELECTION_MASK_OFF) { glPushName(selMask); glPushName(ijk[0]); glPushName(ijk[1]); glPushName(ijk[2]); glPushName(pickLocation[0]); glPushName(pickLocation[1]); glPushName(pickLocation[2]); } // // Draw if coloring is valid // glBegin(GL_QUADS); { glColor3ubv(rgb); glVertex2f(x, y); glVertex2f(x + voxSize, y); glVertex2f(x + voxSize, y + voxSize); glVertex2f(x, y + voxSize); } glEnd(); if (selMask != SELECTION_MASK_OFF) { glPopName(); glPopName(); glPopName(); glPopName(); glPopName(); glPopName(); glPopName(); } } } } // // Points on screen counterclockwise starting at bottom left corner // const float screenCornerCoords[4][2] = { { minCoordX, minCoordY }, { maxCoordX, minCoordY }, { maxCoordX, maxCoordY }, { minCoordX, maxCoordY } }; // // Screen coordinates converted to slice stereotaxic coordinates // float sliceCornerCoords[4][3]; // // Loop through "oblique slice" // for (int i = 0; i < 4; i++) { // // Apply the transformation matrix to the point // const float x = screenCornerCoords[i][0]; const float y = screenCornerCoords[i][1]; float pt[3] = { x, y, 0.0 }; switch (axis) { case VolumeFile::VOLUME_AXIS_X: return; break; case VolumeFile::VOLUME_AXIS_Y: return; break; case VolumeFile::VOLUME_AXIS_Z: return; break; case VolumeFile::VOLUME_AXIS_ALL: return; break; case VolumeFile::VOLUME_AXIS_OBLIQUE: pt[0] = x; pt[1] = y; pt[2] = 0; break; case VolumeFile::VOLUME_AXIS_OBLIQUE_X: pt[0] = 0.0; pt[1] = x; pt[2] = y; break; case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: pt[0] = x; pt[1] = 0.0; pt[2] = y; break; case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: pt[0] = x; pt[1] = y; pt[2] = 0; break; case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: return; break; case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } tm.multiplyPoint(pt); sliceCornerCoords[i][0] = pt[0]; sliceCornerCoords[i][1] = pt[1]; sliceCornerCoords[i][2] = pt[2]; } if (dsv->getDisplayCrosshairs()) { const float bigNumber = 10000.0; switch (axis) { case VolumeFile::VOLUME_AXIS_X: return; break; case VolumeFile::VOLUME_AXIS_Y: return; break; case VolumeFile::VOLUME_AXIS_Z: return; break; case VolumeFile::VOLUME_AXIS_ALL: return; break; case VolumeFile::VOLUME_AXIS_OBLIQUE: glBegin(GL_LINES); glColor3f(1.0, 0.0, 0.0); glVertex2f(-bigNumber, 0.0); glVertex2f( bigNumber, 0.0); glColor3f(0.0, 1.0, 0.0); glVertex2f(0.0, -bigNumber); glVertex2f(0.0, bigNumber); glEnd(); break; case VolumeFile::VOLUME_AXIS_OBLIQUE_X: glBegin(GL_LINES); glColor3f(0.0, 1.0, 0.0); glVertex2f(-bigNumber, 0.0); glVertex2f( bigNumber, 0.0); glColor3f(0.0, 0.0, 1.0); glVertex2f(0.0, -bigNumber); glVertex2f(0.0, bigNumber); glEnd(); break; case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: glBegin(GL_LINES); glColor3f(1.0, 0.0, 0.0); glVertex2f(-bigNumber, 0.0); glVertex2f( bigNumber, 0.0); glColor3f(0.0, 0.0, 1.0); glVertex2f(0.0, -bigNumber); glVertex2f(0.0, bigNumber); glEnd(); break; case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: glBegin(GL_LINES); glColor3f(1.0, 0.0, 0.0); glVertex2f(-bigNumber, 0.0); glVertex2f( bigNumber, 0.0); glColor3f(0.0, 1.0, 0.0); glVertex2f(0.0, -bigNumber); glVertex2f(0.0, bigNumber); glEnd(); break; case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: return; break; case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } } drawObliqueVolumeCellFile(axis, brainSet->getVolumeCellFile(), brainSet->getDisplaySettingsCells(), brainSet->getCellColorFile(), voxSize, &tm, sliceCornerCoords, -1); drawObliqueVolumeFociFile(axis, voxSize, &tm, sliceCornerCoords); // // Draw transformation cell files // const int num = brainSet->getNumberOfTransformationDataFiles(); for (int i = 0; i < num; i++) { AbstractFile* af = brainSet->getTransformationDataFile(i); FociFile* ff = dynamic_cast(af); if (ff != NULL) { /* const TransformationMatrix* fociXForm = ff->getAssociatedTransformationMatrix(); if (fociXForm != NULL) { FociFile ffCopy = *ff; ffCopy.applyTransformationMatrix(-std::numeric_limits::min(), std::numeric_limits::max(), *fociXForm, false); drawObliqueVolumeCellOrFociFile(axis, &ffCopy, brainSet->getDisplaySettingsFoci(), brainSet->getFociColorFile(), voxSize, &tm, sliceCornerCoords, i); } */ } ContourCellFile* ccf = dynamic_cast(af); if ((ff == NULL) && (ccf != NULL)) { const TransformationMatrix* cellXForm1 = ccf->getAssociatedTransformationMatrix(); if (cellXForm1 != NULL) { CellFile cfCopy = *ccf; TransformationMatrix cellXForm = *cellXForm1; cfCopy.applyTransformationMatrix(-std::numeric_limits::min(), std::numeric_limits::max(), cellXForm, false); drawObliqueVolumeCellFile(axis, &cfCopy, brainSet->getDisplaySettingsCells(), brainSet->getContourCellColorFile(), voxSize, &tm, sliceCornerCoords, i); } } CellFile* cf = dynamic_cast(af); if ((ff == NULL) && (ccf == NULL) && (cf != NULL)) { const TransformationMatrix* cellXForm1 = cf->getAssociatedTransformationMatrix(); if (cellXForm1 != NULL) { CellFile cfCopy = *cf; TransformationMatrix cellXForm = *cellXForm1; cfCopy.applyTransformationMatrix(-std::numeric_limits::min(), std::numeric_limits::max(), cellXForm, false); drawObliqueVolumeCellFile(axis, &cfCopy, brainSet->getDisplaySettingsCells(), brainSet->getCellColorFile(), voxSize, &tm, sliceCornerCoords, i); } } ContourFile* contourFile = dynamic_cast(af); if (contourFile != NULL) { const TransformationMatrix* contourXForm1 = contourFile->getAssociatedTransformationMatrix(); if (contourXForm1 != NULL) { ContourFile cfCopy = *contourFile; TransformationMatrix contourXForm = *contourXForm1; cfCopy.applyTransformationMatrix(std::numeric_limits::min(), std::numeric_limits::max(), contourXForm, false); drawObliqueContourFile(axis, &cfCopy, voxSize, &tm, sliceCornerCoords); } } } } /** * Draw volume with all axis. */ void BrainModelOpenGL::drawBrainModelVolumeAllAxis(BrainModelVolume* bmv) { glDisable(GL_DEPTH_TEST); // // Don't set projection matrix when selecting // /* if (selectionMask == SELECTION_MASK_OFF) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(orthographicLeft[viewingWindowNumber], orthographicRight[viewingWindowNumber], orthographicBottom[viewingWindowNumber], orthographicTop[viewingWindowNumber], orthographicNear[viewingWindowNumber], orthographicFar[viewingWindowNumber]); glGetDoublev(GL_PROJECTION_MATRIX, selectionProjectionMatrix[viewingWindowNumber]); } */ // // Get slice for drawing // int slices[3]; bmv->getSelectedOrthogonalSlices(viewingWindowNumber, slices); // // Determine viewport height and width // const int vpHeight = viewport[3] / 2; const int vpWidth = viewport[2] / 2; for (int j = 0; j < 2; j++) { for (int i = 0; i < 2; i++) { // // viewport X & Y // const int vpX = i * vpWidth; const int vpY = j * vpHeight; // // if selecting, only draw if mouse is in this viewport // if (selectionMask != SELECTION_MASK_OFF) { if ((selectionX < vpX) || (selectionY < vpY) || (selectionX > (vpX + vpWidth)) || (selectionY > (vpY + vpHeight))) { continue; } } // // Set the viewport // glViewport(vpX, vpY, vpWidth, vpHeight); if (selectionMask == SELECTION_MASK_OFF) { glGetIntegerv(GL_VIEWPORT, selectionViewport[viewingWindowNumber]); } // // Set orthographic transform // if (selectionMask == SELECTION_MASK_OFF) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(orthographicLeft[viewingWindowNumber], orthographicRight[viewingWindowNumber], orthographicBottom[viewingWindowNumber], orthographicTop[viewingWindowNumber], orthographicNear[viewingWindowNumber], orthographicFar[viewingWindowNumber]); glGetDoublev(GL_PROJECTION_MATRIX, selectionProjectionMatrix[viewingWindowNumber]); } glMatrixMode(GL_MODELVIEW); glLoadIdentity(); float translate[3]; bmv->getTranslation(viewingWindowNumber, translate); glTranslatef(translate[0], translate[1], translate[2]); glRotatef(bmv->getDisplayRotation(viewingWindowNumber), 0.0, 0.0, 1.0); float scale[3]; bmv->getScaling(viewingWindowNumber, scale); glScalef(scale[0], scale[1], scale[2]); // // Save modeling matrix // if (selectionMask == SELECTION_MASK_OFF) { glGetDoublev(GL_MODELVIEW_MATRIX, selectionModelviewMatrix[viewingWindowNumber]); } VolumeFile::VOLUME_AXIS volumeSliceAxis = VolumeFile::VOLUME_AXIS_ALL; VolumeFile* firstVolume = NULL; if (i == 0) { if (j == 0) { VolumeFile* vf = bmv->getUnderlayVolumeFile(); if (vf == NULL) { vf = bmv->getOverlaySecondaryVolumeFile(); } if (vf == NULL) { vf = bmv->getOverlayPrimaryVolumeFile(); } // // Draw the crosshair coordinates // if (vf != NULL) { drawVolumeCrosshairCoordinates(bmv, vf, vpHeight); } BrainModelSurface* bms = brainSet->getActiveFiducialSurface(); if (bms != NULL) { glEnable(GL_DEPTH_TEST); drawBrainModelSurface(bms, NULL, true, true); // // Draw the volume slices // if (vf != NULL) { int dim[3]; vf->getDimensions(dim); float originCenter[3], originCorner[3], spacing[3]; vf->getOrigin(originCenter); vf->getOriginAtCornerOfVoxel(originCorner); vf->getSpacing(spacing); const float minX = originCorner[0]; const float maxX = originCorner[0] + spacing[0] * dim[0]; const float minY = originCorner[1]; const float maxY = originCorner[1] + spacing[1] * dim[1]; const float minZ = originCorner[2]; const float maxZ = originCorner[2] + spacing[2] * dim[2]; const float sliceX = originCenter[0] + spacing[0] * slices[0]; const float sliceY = originCenter[1] + spacing[1] * slices[1]; const float sliceZ = originCenter[2] + spacing[2] * slices[2]; glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glColor4ub(190, 190, 190, 130); glBegin(GL_TRIANGLES); glVertex3f(sliceX, minY, minZ); glVertex3f(sliceX, maxY, minZ); glVertex3f(sliceX, maxY, maxZ); glVertex3f(sliceX, minY, minZ); glVertex3f(sliceX, maxY, maxZ); glVertex3f(sliceX, minY, maxZ); glVertex3f(minX, sliceY, minZ); glVertex3f(maxX, sliceY, minZ); glVertex3f(maxX, sliceY, maxZ); glVertex3f(minX, sliceY, minZ); glVertex3f(maxX, sliceY, maxZ); glVertex3f(minX, sliceY, maxZ); glVertex3f(minX, minY, sliceZ); glVertex3f(maxX, minY, sliceZ); glVertex3f(maxX, maxY, sliceZ); glVertex3f(minX, minY, sliceZ); glVertex3f(maxX, maxY, sliceZ); glVertex3f(minX, maxY, sliceZ); glEnd(); glDisable(GL_BLEND); } glDisable(GL_DEPTH_TEST); } } else { // // Draw parasaggital // volumeSliceAxis = VolumeFile::VOLUME_AXIS_X; drawVolumeSliceOverlayAndUnderlay(bmv, VolumeFile::VOLUME_AXIS_X, slices[0], firstVolume); } } else { if (j == 0) { // // Draw horizontal // volumeSliceAxis = VolumeFile::VOLUME_AXIS_Z; drawVolumeSliceOverlayAndUnderlay(bmv, VolumeFile::VOLUME_AXIS_Z, slices[2], firstVolume); } else { // // Draw coronal // volumeSliceAxis = VolumeFile::VOLUME_AXIS_Y; drawVolumeSliceOverlayAndUnderlay(bmv, VolumeFile::VOLUME_AXIS_Y, slices[1], firstVolume); } } if (firstVolume != NULL) { // // Draw the crosshairs // drawVolumeCrosshairs(bmv, firstVolume, volumeSliceAxis); // // Draw the cropping lines // drawVolumeCroppingLines(bmv, firstVolume, volumeSliceAxis); } } } glEnable(GL_DEPTH_TEST); } /** * Draw volume crosshairs */ void BrainModelOpenGL::drawVolumeCrosshairs(BrainModelVolume* bmv, const VolumeFile* vf, const VolumeFile::VOLUME_AXIS volumeSliceAxis) { DisplaySettingsVolume* dsv = brainSet->getDisplaySettingsVolume(); // // Draw the crosshairs // if ((vf != NULL) && (selectionMask == SELECTION_MASK_OFF) && (dsv->getCroppingSlicesValid() == false)) { // // Draw the crosshairs // if (dsv->getDisplayCrosshairs()) { unsigned char red[3] = { 255, 0, 0 }; unsigned char green[3] = { 0, 255, 0 }; unsigned char blue[3] = { 0, 0, 255 }; // // Get slice for drawing // int slices[3]; bmv->getSelectedOrthogonalSlices(viewingWindowNumber, slices); float crosshairX = 0; float crosshairY = 0; // // Coordinate // float xyz[3]; vf->getVoxelCoordinate(slices, xyz); unsigned char* xColor = red; unsigned char* yColor = red; switch(volumeSliceAxis) { case VolumeFile::VOLUME_AXIS_X: // PARASAGITTAL crosshairX = xyz[1]; //slices[1] * spacing[1] + origin[1]; xColor = green; crosshairY = xyz[2]; //slices[2] * spacing[2] + origin[2]; yColor = blue; break; case VolumeFile::VOLUME_AXIS_Y: // CORONAL crosshairX = xyz[0]; //slices[0] * spacing[0] + origin[0]; xColor = red; crosshairY = xyz[2]; //slices[2] * spacing[2] + origin[2]; yColor = blue; break; case VolumeFile::VOLUME_AXIS_Z: // HORIZONTAL crosshairX = xyz[0]; //slices[0] * spacing[0] + origin[0]; xColor = red; crosshairY = xyz[1]; //slices[1] * spacing[1] + origin[1]; yColor = green; break; case VolumeFile::VOLUME_AXIS_ALL: case VolumeFile::VOLUME_AXIS_OBLIQUE: case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } const float bigNumber = 10000; glLineWidth(getValidLineWidth(1.0)); glColor3ubv(yColor); glBegin(GL_LINES); glVertex3f(crosshairX, -bigNumber, 0.0); glVertex3f(crosshairX, bigNumber, 0.0); glEnd(); glColor3ubv(xColor); glBegin(GL_LINES); glVertex3f(-bigNumber, crosshairY, 0.0); glVertex3f( bigNumber, crosshairY, 0.0); glEnd(); } } } /** * Draw the volume cropping lines */ void BrainModelOpenGL::drawVolumeCroppingLines(BrainModelVolume* bmv, VolumeFile* vf, VolumeFile::VOLUME_AXIS volumeSliceAxis) { DisplaySettingsVolume* dsv = brainSet->getDisplaySettingsVolume(); // // Draw the cropping volume is cropping dialog valid and this is the underlay volume // if (selectionMask == SELECTION_MASK_OFF) { VolumeFile* underlayVolume = bmv->getUnderlayVolumeFile(); if (underlayVolume != NULL) { if (dsv->getCroppingSlicesValid()) { int croppingLines[6]; dsv->getCroppingSlices(croppingLines); float origin[3]; float spacing[3]; vf->getOrigin(origin); vf->getSpacing(spacing); float crosshairX1 = 0; float crosshairX2 = 0; float crosshairY1 = 0; float crosshairY2 = 0; switch(volumeSliceAxis) { case VolumeFile::VOLUME_AXIS_X: // PARASAGITTAL crosshairX1 = croppingLines[2] * spacing[1] + origin[1]; crosshairX2 = croppingLines[3] * spacing[1] + origin[1]; crosshairY1 = croppingLines[4] * spacing[2] + origin[2]; crosshairY2 = croppingLines[5] * spacing[2] + origin[2]; break; case VolumeFile::VOLUME_AXIS_Y: // CORONAL crosshairX1 = croppingLines[0] * spacing[0] + origin[0]; crosshairX2 = croppingLines[1] * spacing[0] + origin[0]; crosshairY1 = croppingLines[4] * spacing[2] + origin[2]; crosshairY2 = croppingLines[5] * spacing[2] + origin[2]; break; case VolumeFile::VOLUME_AXIS_Z: // HORIZONTAL crosshairX1 = croppingLines[0] * spacing[0] + origin[0]; crosshairX2 = croppingLines[1] * spacing[0] + origin[0]; crosshairY1 = croppingLines[2] * spacing[1] + origin[1]; crosshairY2 = croppingLines[3] * spacing[1] + origin[1]; break; case VolumeFile::VOLUME_AXIS_ALL: case VolumeFile::VOLUME_AXIS_OBLIQUE: case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } const float bigNumber = 10000; glLineWidth(getValidLineWidth(1.0)); glBegin(GL_LINES); glColor3ub(0, 150, 150); glVertex3f(crosshairX1, -bigNumber, 0.0); glVertex3f(crosshairX1, bigNumber, 0.0); glColor3ub(0, 255, 255); glVertex3f(crosshairX2, -bigNumber, 0.0); glVertex3f(crosshairX2, bigNumber, 0.0); glEnd(); glBegin(GL_LINES); glColor3ub(150, 150, 0); glVertex3f(-bigNumber, crosshairY1, 0.0); glVertex3f( bigNumber, crosshairY1, 0.0); glColor3ub(255, 255, 0); glVertex3f(-bigNumber, crosshairY2, 0.0); glVertex3f( bigNumber, crosshairY2, 0.0); glEnd(); } } } } /** * Draw volume crosshair coordinates */ void BrainModelOpenGL::drawVolumeCrosshairCoordinates(BrainModelVolume* bmv, const VolumeFile* vf, const int viewportHeight) { DisplaySettingsVolume* dsv = brainSet->getDisplaySettingsVolume(); // // Draw the coordinate's of the crosshairs // if (dsv->getDisplayCrosshairCoordinates() && (glWidget != NULL)) { // // Draw in the foreground color // PreferencesFile* pf = brainSet->getPreferencesFile(); unsigned char rf, gf, bf; pf->getSurfaceForegroundColor(rf, gf, bf); glColor3ub(rf, gf, bf); // // Font for drawing numbers // const int fontHeight = 12; QFont font("times", fontHeight); // // Get slice for drawing // int slices[3]; bmv->getSelectedOrthogonalSlices(viewingWindowNumber, slices); // // Determine the crosshair coordinates // float xyz[3]; vf->getVoxelCoordinate(slices, xyz); // // Draw the text (Note: this renderText() method is done in window coordinates // with the origin in the top left corner of the window). // QString s; s.sprintf("(%0.2f, %0.2f, %0.2f)", xyz[0], xyz[1], xyz[2]); if (glWidget != NULL) { if (DebugControl::getOpenGLDebugOn()) { checkForOpenGLError(bmv, "Before renderText() in drawVolumeCrosshairCoordinates"); } glWidget->renderText(10, viewportHeight - 15, s, font); if (DebugControl::getOpenGLDebugOn()) { checkForOpenGLError(bmv, "After renderText() in drawVolumeCrosshairCoordinates"); } } } } /** * draw volume in montage. */ void BrainModelOpenGL::drawBrainModelVolumeMontage(BrainModelVolume* bmv) { const DisplaySettingsVolume* dsv = brainSet->getDisplaySettingsVolume(); glDisable(GL_DEPTH_TEST); // // Don't set projection matrix when selecting // if (selectionMask == SELECTION_MASK_OFF) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(orthographicLeft[viewingWindowNumber], orthographicRight[viewingWindowNumber], orthographicBottom[viewingWindowNumber], orthographicTop[viewingWindowNumber], orthographicNear[viewingWindowNumber], orthographicFar[viewingWindowNumber]); glGetDoublev(GL_PROJECTION_MATRIX, selectionProjectionMatrix[viewingWindowNumber]); } // // Axis to be drawn // VolumeFile::VOLUME_AXIS volumeSliceAxis = bmv->getSelectedAxis(viewingWindowNumber); // // Get slice for drawing // int slices[3]; bmv->getSelectedOrthogonalSlices(viewingWindowNumber, slices); int currentSlice; switch(volumeSliceAxis) { case VolumeFile::VOLUME_AXIS_X: // PARASAGITTAL currentSlice = slices[0]; break; case VolumeFile::VOLUME_AXIS_Y: // CORONAL currentSlice = slices[1]; break; case VolumeFile::VOLUME_AXIS_Z: // HORIZONTAL currentSlice = slices[2]; break; default: std::cout << "PROGRAM ERROR: Invalid volume axis at " << __LINE__ << " in " << __FILE__ << std::endl; return; } // // Get montage info // int rows, columns, sliceIncrement; dsv->getMontageViewSettings(rows, columns, sliceIncrement); // // Determine viewport height and width // const int vpHeight = viewport[3] / rows; const int vpWidth = viewport[2] / columns; for (int i = (rows - 1); i >= 0; i--) { for (int j = 0; j < columns; j++) { //for (int i = 0; i < rows; i++) { const int vpX = j * vpWidth; const int vpY = i * vpHeight; // // if selecting, only draw if mouse is in this viewport // bool drawSlice = true; if (selectionMask != SELECTION_MASK_OFF) { if ((selectionX < vpX) || (selectionY < vpY) || (selectionX > (vpX + vpWidth)) || (selectionY > (vpY + vpHeight))) { drawSlice = false; } } if (drawSlice) { // // Set the viewport // glViewport(vpX, vpY, vpWidth, vpHeight); // // Don't set projection matrix when selecting // if (selectionMask == SELECTION_MASK_OFF) { // // Set orthographic transform // glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(orthographicLeft[viewingWindowNumber], orthographicRight[viewingWindowNumber], orthographicBottom[viewingWindowNumber], orthographicTop[viewingWindowNumber], orthographicNear[viewingWindowNumber], orthographicFar[viewingWindowNumber]); glGetDoublev(GL_PROJECTION_MATRIX, selectionProjectionMatrix[viewingWindowNumber]); } glMatrixMode(GL_MODELVIEW); glLoadIdentity(); float translate[3]; bmv->getTranslation(viewingWindowNumber, translate); glTranslatef(translate[0], translate[1], translate[2]); glRotatef(bmv->getDisplayRotation(viewingWindowNumber), 0.0, 0.0, 1.0); float scale[3]; bmv->getScaling(viewingWindowNumber, scale); glScalef(scale[0], scale[1], scale[2]); // // Save modeling matrix // if (selectionMask == SELECTION_MASK_OFF) { glGetDoublev(GL_MODELVIEW_MATRIX, selectionModelviewMatrix[viewingWindowNumber]); } VolumeFile* firstVolume = NULL; drawVolumeSliceOverlayAndUnderlay(bmv, volumeSliceAxis, currentSlice, firstVolume); } // // Move to next slice // currentSlice += sliceIncrement; } } glEnable(GL_DEPTH_TEST); } /** * draw volume. */ void BrainModelOpenGL::drawBrainModelVolume(BrainModelVolume* bmv) { if (DebugControl::getOpenGLDebugOn()) { checkForOpenGLError(bmv, "Beginning of drawBrainModelVolume()"); } const DisplaySettingsVolume* dsv = brainSet->getDisplaySettingsVolume(); switch (bmv->getSelectedAxis(viewingWindowNumber)) { case VolumeFile::VOLUME_AXIS_X: break; case VolumeFile::VOLUME_AXIS_Y: break; case VolumeFile::VOLUME_AXIS_Z: break; case VolumeFile::VOLUME_AXIS_ALL: drawBrainModelVolumeAllAxis(bmv); return; break; case VolumeFile::VOLUME_AXIS_OBLIQUE: case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: drawBrainModelVolumeObliqueAxis(bmv); drawMetricPalette(0, false); return; break; case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: drawBrainModelVolumeObliqueAllAxis(bmv); return; break; case VolumeFile::VOLUME_AXIS_UNKNOWN: std::cout << "PROGRAM ERROR: UNKNOWN axis for drawing." << std::endl; return; break; } if (dsv->getMontageViewSelected()) { drawBrainModelVolumeMontage(bmv); return; } glDisable(GL_DEPTH_TEST); // // Don't set projection matrix when selecting // if (selectionMask == SELECTION_MASK_OFF) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(orthographicLeft[viewingWindowNumber], orthographicRight[viewingWindowNumber], orthographicBottom[viewingWindowNumber], orthographicTop[viewingWindowNumber], orthographicNear[viewingWindowNumber], orthographicFar[viewingWindowNumber]); glGetDoublev(GL_PROJECTION_MATRIX, selectionProjectionMatrix[viewingWindowNumber]); } glMatrixMode(GL_MODELVIEW); glLoadIdentity(); float translate[3]; bmv->getTranslation(viewingWindowNumber, translate); glTranslatef(translate[0], translate[1], translate[2]); glRotatef(bmv->getDisplayRotation(viewingWindowNumber), 0.0, 0.0, 1.0); float scale[3]; bmv->getScaling(viewingWindowNumber, scale); glScalef(scale[0], scale[1], scale[2]); // // Save modeling matrix // if (selectionMask == SELECTION_MASK_OFF) { glGetDoublev(GL_MODELVIEW_MATRIX, selectionModelviewMatrix[viewingWindowNumber]); } // // Axis to be drawn // VolumeFile::VOLUME_AXIS volumeSliceAxis = bmv->getSelectedAxis(viewingWindowNumber); // // Get slice for drawing // int slices[3]; bmv->getSelectedOrthogonalSlices(viewingWindowNumber, slices); int currentSlice; switch(volumeSliceAxis) { case VolumeFile::VOLUME_AXIS_X: // PARASAGITTAL currentSlice = slices[0]; break; case VolumeFile::VOLUME_AXIS_Y: // CORONAL currentSlice = slices[1]; break; case VolumeFile::VOLUME_AXIS_Z: // HORIZONTAL currentSlice = slices[2]; break; default: std::cout << "PROGRAM ERROR: Invalid volume axis at " << __LINE__ << " in " << __FILE__ << std::endl; return; } if (DebugControl::getOpenGLDebugOn()) { checkForOpenGLError(bmv, "Before drawVolumeSliceOverlayAndUnderlay"); } VolumeFile* firstVolume = NULL; drawVolumeSliceOverlayAndUnderlay(bmv, volumeSliceAxis, currentSlice, firstVolume); if (DebugControl::getOpenGLDebugOn()) { checkForOpenGLError(bmv, "After drawVolumeSliceOverlayAndUnderlay"); } // // Draw the palette // drawMetricPalette(0, false); if (DebugControl::getOpenGLDebugOn()) { checkForOpenGLError(bmv, "After drawing palette"); } // // Draw the cropping volume is cropping dialog valid and this is the underlay volume // bool croppingLinesDisplayed = false; if (selectionMask == SELECTION_MASK_OFF) { VolumeFile* underlayVolume = bmv->getUnderlayVolumeFile(); if (underlayVolume != NULL) { drawVolumeCroppingLines(bmv, underlayVolume, volumeSliceAxis); } } // // Draw the crosshairs // if ((firstVolume != NULL) && (selectionMask == SELECTION_MASK_OFF) && (croppingLinesDisplayed == false)) { // // Draw the crosshairs and coordinates // drawVolumeCrosshairs(bmv, firstVolume, volumeSliceAxis); if (DebugControl::getOpenGLDebugOn()) { checkForOpenGLError(bmv, "After drawVolumeCrosshairs"); } drawVolumeCrosshairCoordinates(bmv, firstVolume, viewport[3]); if (DebugControl::getOpenGLDebugOn()) { checkForOpenGLError(bmv, "After drawVolumeCrosshairCoordinates"); } } if ((selectionMask == SELECTION_MASK_OFF) && (glWidget != NULL)) { if (dsv->getDisplayOrientationLabels()) { // // Orientation labels // QString orientLeftSideLabel; QString orientRightSideLabel; QString orientBottomSideLabel; QString orientTopSideLabel; switch(volumeSliceAxis) { case VolumeFile::VOLUME_AXIS_X: // PARASAGITTAL orientLeftSideLabel = "P"; orientRightSideLabel = "A"; orientBottomSideLabel = "V"; orientTopSideLabel = "D"; break; case VolumeFile::VOLUME_AXIS_Y: // CORONAL orientLeftSideLabel = "L"; orientRightSideLabel = "R"; orientBottomSideLabel = "V"; orientTopSideLabel = "D"; break; case VolumeFile::VOLUME_AXIS_Z: // HORIZONTAL orientLeftSideLabel = "L"; orientRightSideLabel = "R"; orientBottomSideLabel = "P"; orientTopSideLabel = "A"; break; case VolumeFile::VOLUME_AXIS_ALL: case VolumeFile::VOLUME_AXIS_OBLIQUE: case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } // // Font for drawing orientation labels // QFont font("times", 16); font.setBold(true); QFontMetrics fm(font); const int fontWidth = fm.width(orientBottomSideLabel) / 2; const int fontHeight = fm.height(); const int halfX = viewport[2] / 2; const int halfY = (viewport[3] / 2) + (fontHeight / 2); // // Draw orientation labels // glColor3ub(0, 255, 255); if (glWidget != NULL) { glWidget->renderText((fontWidth / 2), halfY, orientLeftSideLabel, font); glWidget->renderText(viewport[2] - (fontWidth * 3), halfY, orientRightSideLabel, font); glWidget->renderText(halfX - (fontWidth / 2), static_cast(viewport[3] - fontHeight * 1.5), orientBottomSideLabel, font); glWidget->renderText(halfX - (fontWidth / 2), static_cast(fontHeight * 1.5), orientTopSideLabel, font); if (DebugControl::getOpenGLDebugOn()) { checkForOpenGLError(bmv, "After drawing orientation labels"); } } } } // // If this flag is set we only want to draw the linear object. When this // flag is set, glClear() is not called so the previous stuff is not erased. // if (drawLinearObjectOnly) { drawLinearObject(); } glEnable(GL_DEPTH_TEST); } /** * Draw a surface outline over the volume. */ void BrainModelOpenGL::drawVolumeSurfaceOutlineAndTransformationMatrixAxes( const BrainModelVolume* bmv, const VolumeFile::VOLUME_AXIS axis, const float axisCoord) { DisplaySettingsVolume* dsv = brainSet->getDisplaySettingsVolume(); glPushMatrix(); for (int surfNum = 0; surfNum < DisplaySettingsVolume::MAXIMUM_OVERLAY_SURFACES; surfNum++) { float thickness = dsv->getOverlaySurfaceOutlineThickness(surfNum); BrainModelSurface* bms = dsv->getOverlaySurface(surfNum); bool drawSurfaceOutline = dsv->getDisplayOverlaySurfaceOutline(surfNum); DisplaySettingsVolume::SURFACE_OUTLINE_COLOR surfaceOutlineColor = dsv->getOverlaySurfaceOutlineColor(surfNum); // // No selections for outline surface // if (selectionMask != SELECTION_MASK_OFF) { drawSurfaceOutline = false; } // // Find the fiducial surface // if (bms == NULL) { drawSurfaceOutline = false; } // // Create and enable the clipping planes to only draw // when (-thickness <= Z <= thickness) // GLdouble clipPlanePositive[4] = { // should clip (Z < -thickness) 0.0, 0.0, -1.0, //-thickness, thickness }; GLdouble clipPlaneNegative[4] = { // should clip (Z > thickness) 0.0, 0.0, 1.0, // thickness, thickness }; glClipPlane(GL_CLIP_PLANE0, clipPlanePositive); glClipPlane(GL_CLIP_PLANE1, clipPlaneNegative); glEnable(GL_CLIP_PLANE0); glEnable(GL_CLIP_PLANE1); // // Since transformations are used for drawing transform data files // only modify transforms on last overlay surface drawn // if (surfNum < (DisplaySettingsVolume::MAXIMUM_OVERLAY_SURFACES - 1)) { glPushMatrix(); } // // Transform the surface as needed // switch(axis) { case VolumeFile::VOLUME_AXIS_X: // PARASAGITTAL glRotatef(-90.0, 0.0, 1.0, 0.0); glRotatef(-90.0, 1.0, 0.0, 0.0); glTranslatef(-axisCoord, 0.0, 0.0); break; case VolumeFile::VOLUME_AXIS_Y: // CORONAL glRotatef(-90.0, 1.0, 0.0, 0.0); glTranslatef(0.0, -axisCoord, 0.0); break; case VolumeFile::VOLUME_AXIS_Z: // HORIZONTAL glTranslatef(0.0, 0.0, -axisCoord); break; case VolumeFile::VOLUME_AXIS_ALL: break; case VolumeFile::VOLUME_AXIS_OBLIQUE: case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } // // Should surface outline be shown ? // if (drawSurfaceOutline) { // // color for surface // switch (surfaceOutlineColor) { case DisplaySettingsVolume::SURFACE_OUTLINE_COLOR_BLACK: glColor3f(0.0, 0.0, 0.0); break; case DisplaySettingsVolume::SURFACE_OUTLINE_COLOR_BLUE: glColor3f(0.0, 0.0, 1.0); break; case DisplaySettingsVolume::SURFACE_OUTLINE_COLOR_GREEN: glColor3f(0.0, 1.0, 0.0); break; case DisplaySettingsVolume::SURFACE_OUTLINE_COLOR_RED: glColor3f(1.0, 0.0, 0.0); break; case DisplaySettingsVolume::SURFACE_OUTLINE_COLOR_WHITE: glColor3f(1.0, 1.0, 1.0); break; } CoordinateFile* cf = bms->getCoordinateFile(); TopologyFile* tf = bms->getTopologyFile(); const int numTiles = tf->getNumberOfTiles(); //#define DRAW_AS_LINKS #ifdef DRAW_AS_LINKS glLineWidth(getValidLineWidth(1.0)); glBegin(GL_LINES); for (int i = 0; i < numTiles; i++) { int v1, v2, v3; tf->getTile(i, v1, v2, v3); glVertex3fv(cf->getCoordinate(v1)); glVertex3fv(cf->getCoordinate(v2)); glVertex3fv(cf->getCoordinate(v2)); glVertex3fv(cf->getCoordinate(v3)); glVertex3fv(cf->getCoordinate(v1)); glVertex3fv(cf->getCoordinate(v3)); } glEnd(); #else // DRAW_AS_LINKS #ifdef GL_VERSION_1_1 glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(3, GL_FLOAT, 0, cf->getCoordinate(0)); glDrawElements(GL_TRIANGLES, (3 * numTiles), GL_UNSIGNED_INT, static_cast(tf->getTile(0))); glDisableClientState(GL_VERTEX_ARRAY); #else // GL_VERSION_1_1 glBegin(GL_TRIANGLES); for (int i = 0; i < numTiles; i++) { unsigned int v1, v2, v3; tf->getTile(i, v1, v2, v3); glVertex3fv(cf->getCoordinate(v1)); glVertex3fv(cf->getCoordinate(v2)); glVertex3fv(cf->getCoordinate(v3)); } glEnd(); #endif // GL_VERSION_1_1 #endif // DRAW_AS_LINKS } // draw surface outline // // Since transformations are used for drawing transform data files // only modify transforms on last overlay surface drawn // if (surfNum < (DisplaySettingsVolume::MAXIMUM_OVERLAY_SURFACES - 1)) { glPopMatrix(); } glDisable(GL_CLIP_PLANE0); glDisable(GL_CLIP_PLANE1); } // // Draw the translation axes // drawTransformationMatrixAxes(bmv); glPopMatrix(); } /** * Convert from border XYZ to screen XYZ */ void BrainModelOpenGL::convertVolumeItemXYZToScreenXY(const VolumeFile::VOLUME_AXIS axis, float xyz[3]) { const float zPos = 1.0; float xyzOut[3] = { 0.0, 0.0, 0.0 }; switch (axis) { case VolumeFile::VOLUME_AXIS_X: xyzOut[0] = xyz[1]; xyzOut[1] = xyz[2]; xyzOut[2] = xyz[0]; break; case VolumeFile::VOLUME_AXIS_Y: xyzOut[0] = xyz[0]; xyzOut[1] = xyz[2]; xyzOut[2] = xyz[1]; break; case VolumeFile::VOLUME_AXIS_Z: xyzOut[0] = xyz[0]; xyzOut[1] = xyz[1]; xyzOut[2] = xyz[2]; break; case VolumeFile::VOLUME_AXIS_OBLIQUE: case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: case VolumeFile::VOLUME_AXIS_ALL: case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } xyz[0] = xyzOut[0]; xyz[1] = xyzOut[1]; xyz[2] = zPos; } /** * Draw the oblique volume cell file. * If "transformDataFileIndex" is greater than or equal to zero, the a * transform data (cell or foci) file is being drawn. */ void BrainModelOpenGL::drawObliqueVolumeCellFile(const VolumeFile::VOLUME_AXIS axis, const CellFile* cf, const DisplaySettingsCells* dsc, const ColorFile* colorFile, const float voxelSize, const TransformationMatrix* tm, const float sliceCornerCoords[4][3], const int transformDataFileIndex) { if (transformDataFileIndex < 0) { if (dsc->getDisplayVolumeCells() == false) { return; } } // // Set color for cells/foci with missing colors // unsigned char noColorRed, noColorGreen, noColorBlue; PreferencesFile* pref = brainSet->getPreferencesFile(); pref->getSurfaceForegroundColor(noColorRed, noColorGreen, noColorBlue); const float halfVoxelSize = voxelSize * 0.6; const bool contourCellFlag = (dynamic_cast(cf) != NULL); // // Check for selection mode // bool selectFlag = false; if (contourCellFlag) { if (transformDataFileIndex >= 0) { if (selectionMask & SELECTION_MASK_TRANSFORM_CONTOUR_CELL) { glPushName(SELECTION_MASK_TRANSFORM_CONTOUR_CELL); glPushName(transformDataFileIndex); selectFlag = true; } } } else { if (transformDataFileIndex >= 0) { if (selectionMask & SELECTION_MASK_TRANSFORM_CELL) { glPushName(SELECTION_MASK_TRANSFORM_CELL); glPushName(transformDataFileIndex); selectFlag = true; } } else { if (selectionMask & SELECTION_MASK_VOLUME_CELL) { glPushName(SELECTION_MASK_VOLUME_CELL); selectFlag = true; } } } if ((selectFlag == false) && (selectionMask != SELECTION_MASK_OFF)) { return; } // // Normal of plane // float planeNormal[3]; MathUtilities::computeNormal((float*)sliceCornerCoords[0], (float*)sliceCornerCoords[1], (float*)sliceCornerCoords[2], planeNormal); // // Draw cells larger when selecting on a flat surface // float cellSize = dsc->getDrawSize(); const int numCells = cf->getNumberOfCells(); if (numCells > 0) { const int numColors = colorFile->getNumberOfColors(); for (int i = 0; i < numCells; i++) { const CellData* cd = cf->getCell(i); if (transformDataFileIndex < 0) { if (cd->getDisplayFlag() == false) { continue; } } ColorFile::ColorStorage::SYMBOL symbol = ColorFile::ColorStorage::SYMBOL_OPENGL_POINT; const int colorIndex = cd->getColorIndex(); float pointSize = 1; float lineSize = 1; unsigned char r = 0, g = 0, b = 0, alpha = 255; if ((colorIndex >= 0) && (colorIndex < numColors)) { const ColorFile::ColorStorage* cs = colorFile->getColor(colorIndex); cs->getRgba(r, g, b, alpha); lineSize = cs->getLineSize(); pointSize = cs->getPointSize(); symbol = cs->getSymbol(); } else { r = noColorRed; g = noColorGreen; b = noColorBlue; } if (dsc->getSymbolOverride() != ColorFile::ColorStorage::SYMBOL_NONE) { symbol = dsc->getSymbolOverride(); } if (pointSize < 1) { pointSize = 1; } float size = pointSize * cellSize; float xyz[3]; cd->getXYZ(xyz); // // Get distance and point on plane // float intersection[3]; float signedDistanceFromPlaneOut; bool valid = MathUtilities::rayIntersectPlane(sliceCornerCoords[0], sliceCornerCoords[1], sliceCornerCoords[2], xyz, planeNormal, intersection, &signedDistanceFromPlaneOut); if (signedDistanceFromPlaneOut < 0.0) { signedDistanceFromPlaneOut = -signedDistanceFromPlaneOut; } if (valid) { if (signedDistanceFromPlaneOut > halfVoxelSize) { valid = false; } } if (valid) { // // Undo screen to slice transformation // xyz[0] = intersection[0]; xyz[1] = intersection[1]; xyz[2] = intersection[2]; tm->inverseMultiplyPoint(xyz); // // Convert to screen X/Y // float pt[3] = { xyz[0], xyz[1], xyz[2] }; switch (axis) { case VolumeFile::VOLUME_AXIS_X: return; break; case VolumeFile::VOLUME_AXIS_Y: return; break; case VolumeFile::VOLUME_AXIS_Z: return; break; case VolumeFile::VOLUME_AXIS_ALL: return; break; case VolumeFile::VOLUME_AXIS_OBLIQUE: xyz[0] = pt[0]; xyz[1] = pt[1]; xyz[2] = 0.0; break; case VolumeFile::VOLUME_AXIS_OBLIQUE_X: xyz[0] = pt[1]; xyz[1] = pt[2]; xyz[2] = 0.0; break; case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: xyz[0] = pt[0]; xyz[1] = pt[2]; xyz[2] = 0.0; break; case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: xyz[0] = pt[0]; xyz[1] = pt[1]; xyz[2] = 0.0; break; case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: break; case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } glColor3ub(r, g, b); if (selectFlag) { glPushName(i); size *= 2; } if (alpha < 255) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } switch (symbol) { case ColorFile::ColorStorage::SYMBOL_OPENGL_POINT: // // Points must be at least 1.0 for OpenGL to draw something // size = std::max(size, 1.0f); glPointSize(getValidPointSize(size)); glBegin(GL_POINTS); glVertex3f(xyz[0], xyz[1], xyz[2]); glEnd(); break; case ColorFile::ColorStorage::SYMBOL_SPHERE: glEnable(GL_LIGHTING); glEnable(GL_COLOR_MATERIAL); glPushMatrix(); glTranslatef(xyz[0], xyz[1], xyz[2]); drawSphere(size); glPopMatrix(); break; case ColorFile::ColorStorage::SYMBOL_BOX: glEnable(GL_LIGHTING); glEnable(GL_COLOR_MATERIAL); glPushMatrix(); glTranslatef(xyz[0], xyz[1], xyz[2]); glScalef(size, size, size); drawBox(); glPopMatrix(); break; case ColorFile::ColorStorage::SYMBOL_DIAMOND: glEnable(GL_LIGHTING); glEnable(GL_COLOR_MATERIAL); glPushMatrix(); glTranslatef(xyz[0], xyz[1], xyz[2]); glScalef(size, size, size); drawDiamond(); glPopMatrix(); break; case ColorFile::ColorStorage::SYMBOL_DISK: glEnable(GL_LIGHTING); glEnable(GL_COLOR_MATERIAL); glPushMatrix(); glTranslatef(xyz[0], xyz[1], xyz[2]); drawDisk(size); glPopMatrix(); break; case ColorFile::ColorStorage::SYMBOL_RING: glEnable(GL_LIGHTING); glEnable(GL_COLOR_MATERIAL); glPushMatrix(); glTranslatef(xyz[0], xyz[1], xyz[2]); glScalef(size, size, size); drawRing(); glPopMatrix(); break; case ColorFile::ColorStorage::SYMBOL_NONE: break; case ColorFile::ColorStorage::SYMBOL_SQUARE: glEnable(GL_LIGHTING); glEnable(GL_COLOR_MATERIAL); glPushMatrix(); glTranslatef(xyz[0], xyz[1], xyz[2]); glScalef(size, size, size); drawSquare(); glPopMatrix(); break; } if (selectFlag) { glPopName(); } glDisable(GL_BLEND); glDisable(GL_LIGHTING); glDisable(GL_COLOR_MATERIAL); } } } if (selectFlag) { glPopName(); if (transformDataFileIndex >= 0) { glPopName(); } } } /** * Draw the oblique volume foci file. * If "transformDataFileIndex" is greater than or equal to zero, the a * transform data (cell or foci) file is being drawn. */ void BrainModelOpenGL::drawObliqueVolumeFociFile(const VolumeFile::VOLUME_AXIS axis, const float voxelSize, const TransformationMatrix* tm, const float sliceCornerCoords[4][3]) { const FociProjectionFile* fpf = brainSet->getFociProjectionFile(); const DisplaySettingsCells* dsf = brainSet->getDisplaySettingsFoci(); const FociColorFile* colorFile = brainSet->getFociColorFile(); // // Set color for cells/foci with missing colors // unsigned char noColorRed, noColorGreen, noColorBlue; PreferencesFile* pref = brainSet->getPreferencesFile(); pref->getSurfaceForegroundColor(noColorRed, noColorGreen, noColorBlue); const float halfVoxelSize = voxelSize * 0.6; // // Check for selection mode // bool selectFlag = false; if (selectionMask & SELECTION_MASK_VOLUME_FOCI) { glPushName(SELECTION_MASK_VOLUME_FOCI); selectFlag = true; } if ((selectFlag == false) && (selectionMask != SELECTION_MASK_OFF)) { return; } // // Normal of plane // float planeNormal[3]; MathUtilities::computeNormal((float*)sliceCornerCoords[0], (float*)sliceCornerCoords[1], (float*)sliceCornerCoords[2], planeNormal); // // Draw cells larger when selecting on a flat surface // float cellSize = dsf->getDrawSize(); const int numCells = fpf->getNumberOfCellProjections(); if (numCells > 0) { const int numColors = colorFile->getNumberOfColors(); for (int i = 0; i < numCells; i++) { const CellProjection* cd = fpf->getCellProjection(i); ColorFile::ColorStorage::SYMBOL symbol = ColorFile::ColorStorage::SYMBOL_OPENGL_POINT; const int colorIndex = cd->getColorIndex(); float pointSize = 1; float lineSize = 1; unsigned char r = 0, g = 0, b = 0, alpha = 255; if ((colorIndex >= 0) && (colorIndex < numColors)) { const ColorFile::ColorStorage* cs = colorFile->getColor(colorIndex); cs->getRgba(r, g, b, alpha); lineSize = cs->getLineSize(); pointSize = cs->getPointSize(); symbol = cs->getSymbol(); } else { r = noColorRed; g = noColorGreen; b = noColorBlue; } if (dsf->getSymbolOverride() != ColorFile::ColorStorage::SYMBOL_NONE) { symbol = dsf->getSymbolOverride(); } if (pointSize < 1) { pointSize = 1; } float size = pointSize * cellSize; // // Double size for highlighting // if (cd->getHighlightFlag()) { size *= 2.0; } float xyz[3]; cd->getVolumeXYZ(xyz); if ((xyz[0] == 0.0) && (xyz[1] == 0.0) && (xyz[2] == 0.0)) { continue; } // // Get distance and point on plane // float intersection[3]; float signedDistanceFromPlaneOut; bool valid = MathUtilities::rayIntersectPlane(sliceCornerCoords[0], sliceCornerCoords[1], sliceCornerCoords[2], xyz, planeNormal, intersection, &signedDistanceFromPlaneOut); if (signedDistanceFromPlaneOut < 0.0) { signedDistanceFromPlaneOut = -signedDistanceFromPlaneOut; } if (valid) { if (signedDistanceFromPlaneOut > halfVoxelSize) { valid = false; } } if (valid) { // // Undo screen to slice transformation // xyz[0] = intersection[0]; xyz[1] = intersection[1]; xyz[2] = intersection[2]; tm->inverseMultiplyPoint(xyz); // // Convert to screen X/Y // float pt[3] = { xyz[0], xyz[1], xyz[2] }; switch (axis) { case VolumeFile::VOLUME_AXIS_X: return; break; case VolumeFile::VOLUME_AXIS_Y: return; break; case VolumeFile::VOLUME_AXIS_Z: return; break; case VolumeFile::VOLUME_AXIS_ALL: return; break; case VolumeFile::VOLUME_AXIS_OBLIQUE: xyz[0] = pt[0]; xyz[1] = pt[1]; xyz[2] = 0.0; break; case VolumeFile::VOLUME_AXIS_OBLIQUE_X: xyz[0] = pt[1]; xyz[1] = pt[2]; xyz[2] = 0.0; break; case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: xyz[0] = pt[0]; xyz[1] = pt[2]; xyz[2] = 0.0; break; case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: xyz[0] = pt[0]; xyz[1] = pt[1]; xyz[2] = 0.0; break; case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: break; case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } glColor3ub(r, g, b); if (selectFlag) { glPushName(i); size *= 2; } if (alpha < 255) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } switch (symbol) { case ColorFile::ColorStorage::SYMBOL_OPENGL_POINT: // // Points must be at least 1.0 for OpenGL to draw something // size = std::max(size, 1.0f); glPointSize(getValidPointSize(size)); glBegin(GL_POINTS); glVertex3f(xyz[0], xyz[1], xyz[2]); glEnd(); break; case ColorFile::ColorStorage::SYMBOL_SPHERE: glEnable(GL_LIGHTING); glEnable(GL_COLOR_MATERIAL); glPushMatrix(); glTranslatef(xyz[0], xyz[1], xyz[2]); drawSphere(size); glPopMatrix(); break; case ColorFile::ColorStorage::SYMBOL_BOX: glEnable(GL_LIGHTING); glEnable(GL_COLOR_MATERIAL); glPushMatrix(); glTranslatef(xyz[0], xyz[1], xyz[2]); glScalef(size, size, size); drawBox(); glPopMatrix(); break; case ColorFile::ColorStorage::SYMBOL_DIAMOND: glEnable(GL_LIGHTING); glEnable(GL_COLOR_MATERIAL); glPushMatrix(); glTranslatef(xyz[0], xyz[1], xyz[2]); glScalef(size, size, size); drawDiamond(); glPopMatrix(); break; case ColorFile::ColorStorage::SYMBOL_DISK: glEnable(GL_LIGHTING); glEnable(GL_COLOR_MATERIAL); glPushMatrix(); glTranslatef(xyz[0], xyz[1], xyz[2]); drawDisk(size); glPopMatrix(); break; case ColorFile::ColorStorage::SYMBOL_RING: glEnable(GL_LIGHTING); glEnable(GL_COLOR_MATERIAL); glPushMatrix(); glTranslatef(xyz[0], xyz[1], xyz[2]); glScalef(size, size, size); drawRing(); glPopMatrix(); break; case ColorFile::ColorStorage::SYMBOL_NONE: break; case ColorFile::ColorStorage::SYMBOL_SQUARE: glEnable(GL_LIGHTING); glEnable(GL_COLOR_MATERIAL); glPushMatrix(); glTranslatef(xyz[0], xyz[1], xyz[2]); glScalef(size, size, size); drawSquare(); glPopMatrix(); break; } if (selectFlag) { glPopName(); } glDisable(GL_BLEND); glDisable(GL_LIGHTING); glDisable(GL_COLOR_MATERIAL); } } } if (selectFlag) { glPopName(); } } /** * Draw the oblique volume contour file. */ void BrainModelOpenGL::drawObliqueContourFile(const VolumeFile::VOLUME_AXIS axis, const ContourFile* cf, const float voxelSize, const TransformationMatrix* tm, const float sliceCornerCoords[4][3]) { const DisplaySettingsContours* dsc = brainSet->getDisplaySettingsContours(); const float halfVoxelSize = voxelSize * 0.6; // // Normal of plane // float planeNormal[3]; MathUtilities::computeNormal((float*)sliceCornerCoords[0], (float*)sliceCornerCoords[1], (float*)sliceCornerCoords[2], planeNormal); const int numContours = cf->getNumberOfContours(); if (numContours > 0) { for (int i = 0; i < numContours; i++) { const CaretContour* contour = cf->getContour(i); const int numPoints = contour->getNumberOfPoints(); for (int j = 0; j < numPoints; j++) { if ((j == 0) && (dsc->getShowEndPoints())) { glColor3ub(255, 0, 0); } else { glColor3ub(0, 255, 0); } float x, y, z; contour->getPointXYZ(j, x, y, z); float xyz[3] = { x, y, z }; // // Get distance and point on plane // float intersection[3]; float signedDistanceFromPlaneOut; bool valid = MathUtilities::rayIntersectPlane(sliceCornerCoords[0], sliceCornerCoords[1], sliceCornerCoords[2], xyz, planeNormal, intersection, &signedDistanceFromPlaneOut); if (signedDistanceFromPlaneOut < 0.0) { signedDistanceFromPlaneOut = -signedDistanceFromPlaneOut; } if (valid) { if (signedDistanceFromPlaneOut > halfVoxelSize) { valid = false; } } if (valid) { // // Undo screen to slice transformation // xyz[0] = intersection[0]; xyz[1] = intersection[1]; xyz[2] = intersection[2]; tm->inverseMultiplyPoint(xyz); // // Convert to screen X/Y // float pt[3] = { xyz[0], xyz[1], xyz[2] }; switch (axis) { case VolumeFile::VOLUME_AXIS_X: return; break; case VolumeFile::VOLUME_AXIS_Y: return; break; case VolumeFile::VOLUME_AXIS_Z: return; break; case VolumeFile::VOLUME_AXIS_ALL: return; break; case VolumeFile::VOLUME_AXIS_OBLIQUE: xyz[0] = pt[0]; xyz[1] = pt[1]; xyz[2] = 0.0; break; case VolumeFile::VOLUME_AXIS_OBLIQUE_X: xyz[0] = pt[1]; xyz[1] = pt[2]; xyz[2] = 0.0; break; case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: xyz[0] = pt[0]; xyz[1] = pt[2]; xyz[2] = 0.0; break; case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: xyz[0] = pt[0]; xyz[1] = pt[1]; xyz[2] = 0.0; break; case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: break; case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } //if (alpha < 255) { // glEnable(GL_BLEND); // glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); //} glBegin(GL_POINTS); glVertex3fv(xyz); glEnd(); //glDisable(GL_BLEND); } } } } } /** * Draw the volume contour file. */ void BrainModelOpenGL::drawVolumeContourFile(const VolumeFile::VOLUME_AXIS axis, const float axisCoord, const float voxelSize) { const DisplaySettingsContours* dsc = brainSet->getDisplaySettingsContours(); const float halfVoxelSize = voxelSize * 0.6; BrainModelContours* bmc = brainSet->getBrainModelContours(); if (bmc != NULL) { const ContourFile* cf = bmc->getContourFile(); const int numContours = cf->getNumberOfContours(); glPointSize(getValidPointSize(dsc->getPointSize())); glLineWidth(getValidLineWidth(dsc->getLineThickness())); glColor3f(0.0, 1.0, 0.0); for (int i = 0; i < numContours; i++) { const CaretContour* contour = cf->getContour(i); const float z = contour->getSectionNumber(); const int numPoints = contour->getNumberOfPoints(); glBegin(GL_POINTS); for (int j = 0; j < numPoints; j++) { if ((j == 0) && (dsc->getShowEndPoints())) { glColor3ub(255, 0, 0); } else { glColor3ub(0, 255, 0); } float x, y; contour->getPointXY(j, x, y); float xyz[3] = { x, y, z }; if (fabs(xyz[axis] - axisCoord) < halfVoxelSize) { convertVolumeItemXYZToScreenXY(axis, xyz); glVertex3fv(xyz); } } glEnd(); } if (dsc->getDisplayContourCells()) { ContourCellFile* ccf = brainSet->getContourCellFile(); const int numCells = ccf->getNumberOfCells(); if (numCells > 0) { const float cellSize = dsc->getContourCellSize(); const ContourCellColorFile* colorFile = brainSet->getContourCellColorFile(); // // Set color for cells with missing colors // unsigned char noColorRed, noColorGreen, noColorBlue; PreferencesFile* pref = brainSet->getPreferencesFile(); pref->getSurfaceForegroundColor(noColorRed, noColorGreen, noColorBlue); const int numColors = colorFile->getNumberOfColors(); for (int i = 0; i < numCells; i++) { const CellData* cd = ccf->getCell(i); const int colorIndex = cd->getColorIndex(); float pointSize = 1; unsigned char r = 0, g = 0, b = 0; if ((colorIndex >= 0) && (colorIndex < numColors)) { const ColorFile::ColorStorage* cs = colorFile->getColor(colorIndex); cs->getRgb(r, g, b); pointSize = cs->getPointSize(); } else { r = noColorRed; g = noColorGreen; b = noColorBlue; } if (pointSize < 1) { pointSize = 1; } float size = pointSize * cellSize; float xyz[3]; cd->getXYZ(xyz); xyz[2] = cd->getSectionNumber() * cf->getSectionSpacing(); if (fabs(xyz[axis] - axisCoord) < halfVoxelSize) { convertVolumeItemXYZToScreenXY(axis, xyz); glColor3ub(r, g, b); // // Points must be at least 1.0 for OpenGL to draw something // size = std::max(size, 1.0f); glPointSize(getValidPointSize(size)); glBegin(GL_POINTS); glVertex3f(xyz[0], xyz[1], xyz[2]); glEnd(); } } } } } } /** * Draw the volume cell file. */ void BrainModelOpenGL::drawVolumeCellFile(const VolumeFile::VOLUME_AXIS axis, const float axisCoord, const float voxelSize) { const CellFile* cf = brainSet->getVolumeCellFile(); const DisplaySettingsCells* dsc = brainSet->getDisplaySettingsCells(); const CellColorFile* colorFile = brainSet->getCellColorFile(); // // Set color for cells/foci with missing colors // unsigned char noColorRed, noColorGreen, noColorBlue; PreferencesFile* pref = brainSet->getPreferencesFile(); pref->getSurfaceForegroundColor(noColorRed, noColorGreen, noColorBlue); const float halfVoxelSize = voxelSize * 0.6; // // Check for selection mode // bool selectFlag = false; if (selectionMask & SELECTION_MASK_VOLUME_CELL) { glPushName(SELECTION_MASK_VOLUME_CELL); selectFlag = true; } if ((selectFlag == false) && (selectionMask != SELECTION_MASK_OFF)) { return; } int axisIndex = 0; switch (axis) { case VolumeFile::VOLUME_AXIS_X: axisIndex = 0; break; case VolumeFile::VOLUME_AXIS_Y: axisIndex = 1; break; case VolumeFile::VOLUME_AXIS_Z: axisIndex = 2; break; case VolumeFile::VOLUME_AXIS_ALL: case VolumeFile::VOLUME_AXIS_OBLIQUE: case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: case VolumeFile::VOLUME_AXIS_UNKNOWN: return; break; } // // Draw cells larger when selecting on a flat surface // float cellSize = dsc->getDrawSize(); const int numCells = cf->getNumberOfCells(); if (numCells > 0) { const int numColors = colorFile->getNumberOfColors(); for (int i = 0; i < numCells; i++) { const CellData* cd = cf->getCell(i); if (cd->getDisplayFlag() == false) { continue; } ColorFile::ColorStorage::SYMBOL symbol = ColorFile::ColorStorage::SYMBOL_OPENGL_POINT; const int colorIndex = cd->getColorIndex(); float pointSize = 1; float lineSize = 1; unsigned char r = 0, g = 0, b = 0, alpha = 255; if ((colorIndex >= 0) && (colorIndex < numColors)) { const ColorFile::ColorStorage* cs = colorFile->getColor(colorIndex); cs->getRgba(r, g, b, alpha); lineSize = cs->getLineSize(); pointSize = cs->getPointSize(); symbol = cs->getSymbol(); } else { r = noColorRed; g = noColorGreen; b = noColorBlue; } if (dsc->getSymbolOverride() != ColorFile::ColorStorage::SYMBOL_NONE) { symbol = dsc->getSymbolOverride(); } if (pointSize < 1) { pointSize = 1; } float size = pointSize * cellSize; float xyz[3]; cd->getXYZ(xyz); if (fabs(xyz[axisIndex] - axisCoord) < halfVoxelSize) { convertVolumeItemXYZToScreenXY(axis, xyz); glColor3ub(r, g, b); if (selectFlag) { glPushName(i); } if (alpha < 255) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } drawSymbol(symbol, xyz[0], xyz[1], xyz[2], size, NULL); if (selectFlag) { glPopName(); } glDisable(GL_BLEND); glDisable(GL_LIGHTING); glDisable(GL_COLOR_MATERIAL); } } } if (selectFlag) { glPopName(); } } /** * Draw the volume foci file. */ void BrainModelOpenGL::drawVolumeFociFile(const VolumeFile::VOLUME_AXIS axis, const float axisCoord, const float voxelSize) { const FociProjectionFile* fpf = brainSet->getFociProjectionFile(); const DisplaySettingsFoci* dsf = brainSet->getDisplaySettingsFoci(); const FociColorFile* colorFile = brainSet->getFociColorFile(); // // Set color for cells/foci with missing colors // unsigned char noColorRed, noColorGreen, noColorBlue; PreferencesFile* pref = brainSet->getPreferencesFile(); pref->getSurfaceForegroundColor(noColorRed, noColorGreen, noColorBlue); const float halfVoxelSize = voxelSize * 0.6; // // Check for selection mode // bool selectFlag = false; if (selectionMask & SELECTION_MASK_VOLUME_FOCI) { glPushName(SELECTION_MASK_VOLUME_FOCI); selectFlag = true; } if ((selectFlag == false) && (selectionMask != SELECTION_MASK_OFF)) { return; } int axisIndex = 0; switch (axis) { case VolumeFile::VOLUME_AXIS_X: axisIndex = 0; break; case VolumeFile::VOLUME_AXIS_Y: axisIndex = 1; break; case VolumeFile::VOLUME_AXIS_Z: axisIndex = 2; break; case VolumeFile::VOLUME_AXIS_ALL: case VolumeFile::VOLUME_AXIS_OBLIQUE: case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: case VolumeFile::VOLUME_AXIS_UNKNOWN: return; break; } // // Draw foci larger when selecting on a flat surface // float fociSize = dsf->getDrawSize(); const int numFoci = fpf->getNumberOfCellProjections(); if (numFoci > 0) { const int numColors = colorFile->getNumberOfColors(); for (int i = 0; i < numFoci; i++) { const CellProjection* focus = fpf->getCellProjection(i); if (focus->getDisplayFlag() == false) { continue; } ColorFile::ColorStorage::SYMBOL symbol = ColorFile::ColorStorage::SYMBOL_OPENGL_POINT; const int colorIndex = focus->getColorIndex(); float pointSize = 1; float lineSize = 1; unsigned char r = 0, g = 0, b = 0, alpha = 255; if ((colorIndex >= 0) && (colorIndex < numColors)) { const ColorFile::ColorStorage* cs = colorFile->getColor(colorIndex); cs->getRgba(r, g, b, alpha); lineSize = cs->getLineSize(); pointSize = cs->getPointSize(); symbol = cs->getSymbol(); } else { r = noColorRed; g = noColorGreen; b = noColorBlue; } if (dsf->getSymbolOverride() != ColorFile::ColorStorage::SYMBOL_NONE) { symbol = dsf->getSymbolOverride(); } if (pointSize < 1) { pointSize = 1; } float size = pointSize * fociSize; // // Double size for highlighting // if (focus->getHighlightFlag()) { size *= 2.0; } float xyz[3]; focus->getVolumeXYZ(xyz); if ((xyz[0] != 0.0) || (xyz[1] != 0.0) || (xyz[2] != 0.0)) { if (fabs(xyz[axisIndex] - axisCoord) < halfVoxelSize) { convertVolumeItemXYZToScreenXY(axis, xyz); glColor3ub(r, g, b); if (selectFlag) { glPushName(i); } if (alpha < 255) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } drawSymbol(symbol, xyz[0], xyz[1], xyz[2], size, NULL); if (selectFlag) { glPopName(); } glDisable(GL_BLEND); glDisable(GL_LIGHTING); glDisable(GL_COLOR_MATERIAL); } } } } if (selectFlag) { glPopName(); } } /** * Draw the volume border file */ void BrainModelOpenGL::drawVolumeBorderFile(const VolumeFile::VOLUME_AXIS axis, const float axisCoord, const float voxelSize) { BorderFile* bf = brainSet->getVolumeBorderFile(); const float halfVoxelSize = voxelSize * 0.6; // // Set color for borders with missing colors // unsigned char noColorRed, noColorGreen, noColorBlue; PreferencesFile* pref = brainSet->getPreferencesFile(); pref->getSurfaceForegroundColor(noColorRed, noColorGreen, noColorBlue); BorderColorFile* colorFile = brainSet->getBorderColorFile(); const int numColors = colorFile->getNumberOfColors(); // // Draw borders larger when selecting on a flat surface // DisplaySettingsBorders* dsb = brainSet->getDisplaySettingsBorders(); float drawSize = dsb->getDrawSize(); // // Check for selection mode // bool selectFlag = false; if (selectionMask & SELECTION_MASK_VOLUME_BORDER) { glPushName(SELECTION_MASK_VOLUME_BORDER); selectFlag = true; } if ((selectFlag == false) && (selectionMask != SELECTION_MASK_OFF)) { return; } int axisIndex = 0; switch (axis) { case VolumeFile::VOLUME_AXIS_X: axisIndex = 0; break; case VolumeFile::VOLUME_AXIS_Y: axisIndex = 1; break; case VolumeFile::VOLUME_AXIS_Z: axisIndex = 2; break; case VolumeFile::VOLUME_AXIS_ALL: case VolumeFile::VOLUME_AXIS_OBLIQUE: case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: case VolumeFile::VOLUME_AXIS_UNKNOWN: return; break; } const int numBorders = bf->getNumberOfBorders(); for (int i = 0; i < numBorders; i++) { const Border* b = bf->getBorder(i); if (b->getDisplayFlag()) { const int numLinks = b->getNumberOfLinks(); const int colorIndex = b->getBorderColorIndex(); float pointSize = 1; float lineSize = 1; unsigned char red = 0, green = 0, blue = 0; if ((colorIndex >= 0) && (colorIndex < numColors)) { colorFile->getColorByIndex(colorIndex, red, green, blue); colorFile->getPointLineSizeByIndex(colorIndex, pointSize, lineSize); } else { red = noColorRed; green = noColorGreen; blue = noColorBlue; } if (selectFlag) { glPushName(i); glPointSize(getValidPointSize(pointSize * drawSize)); for (int j = 0; j < numLinks; j++) { glPushName(j); glBegin(GL_POINTS); float xyz[3]; b->getLinkXYZ(j, xyz); if (fabs(xyz[axisIndex] - axisCoord) < halfVoxelSize) { convertVolumeItemXYZToScreenXY(axis, xyz); glVertex3fv(xyz); } glEnd(); glPopName(); } glPopName(); } else { if ((dsb->getDrawMode() == DisplaySettingsBorders::BORDER_DRAW_AS_SYMBOLS) || (dsb->getDrawMode() == DisplaySettingsBorders::BORDER_DRAW_AS_SYMBOLS_AND_LINES)) { glPointSize(getValidPointSize(pointSize * drawSize)); int startLink = 0; glBegin(GL_POINTS); if (dsb->getDisplayFirstLinkRed()) { glColor3ub(255, 0, 0); float xyz[3]; b->getLinkXYZ(0, xyz); if (fabs(xyz[axisIndex] - axisCoord) < halfVoxelSize) { convertVolumeItemXYZToScreenXY(axis, xyz); glVertex3fv(xyz); } startLink = 1; } glColor3ub(red, green, blue); float xyz[3]; for (int j = startLink; j < numLinks; j++) { b->getLinkXYZ(j, xyz); if (fabs(xyz[axisIndex] - axisCoord) < halfVoxelSize) { convertVolumeItemXYZToScreenXY(axis, xyz); glVertex3fv(xyz); } } glEnd(); } if ((dsb->getDrawMode() == DisplaySettingsBorders::BORDER_DRAW_AS_LINES) || (dsb->getDrawMode() == DisplaySettingsBorders::BORDER_DRAW_AS_UNSTRETCHED_LINES) || (dsb->getDrawMode() == DisplaySettingsBorders::BORDER_DRAW_AS_SYMBOLS_AND_LINES)) { glLineWidth(getValidLineWidth(lineSize * drawSize)); glBegin(GL_LINES); int startLink = 0; if (dsb->getDisplayFirstLinkRed()) { glColor3ub(255, 0, 0); float xyz[3]; b->getLinkXYZ(0, xyz); if (fabs(xyz[axisIndex] - axisCoord) < halfVoxelSize) { convertVolumeItemXYZToScreenXY(axis, xyz); glVertex3fv(xyz); glVertex3fv(xyz); } startLink = 1; } glColor3ub(red, green, blue); float xyz[3]; for (int j = startLink + 1; j < numLinks; j++) { b->getLinkXYZ(j - 1, xyz); if (fabs(xyz[axisIndex] - axisCoord) < halfVoxelSize) { convertVolumeItemXYZToScreenXY(axis, xyz); glVertex3fv(xyz); b->getLinkXYZ(j, xyz); convertVolumeItemXYZToScreenXY(axis, xyz); glVertex3fv(xyz); } } glEnd(); } } } } if (selectFlag) { glPopName(); } } /** * Draw the volume identify symbols */ void BrainModelOpenGL::drawVolumeIdentifySymbols(const VolumeFile::VOLUME_AXIS axis, const float axisCoord) { BrainModelVolume* bmv = brainSet->getBrainModelVolume(); if (bmv == NULL) { return; } // // Check for selection mode // if (selectionMask != SELECTION_MASK_OFF) { return; } int axisIndex = 0; switch (axis) { case VolumeFile::VOLUME_AXIS_X: axisIndex = 0; break; case VolumeFile::VOLUME_AXIS_Y: axisIndex = 1; break; case VolumeFile::VOLUME_AXIS_Z: axisIndex = 2; break; case VolumeFile::VOLUME_AXIS_ALL: case VolumeFile::VOLUME_AXIS_OBLIQUE: case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: case VolumeFile::VOLUME_AXIS_UNKNOWN: return; break; } glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glColor4f(0.0, 1.0, 0.0, 0.5); const BrainModelSurface* bms = brainSet->getActiveFiducialSurface(); if (bms != NULL) { const CoordinateFile* cf = bms->getCoordinateFile(); const int numCoords = cf->getNumberOfCoordinates(); // // See if node uncertainty should be displayed // const SurfaceShapeFile* ssf = brainSet->getSurfaceShapeFile(); const DisplaySettingsSurfaceShape* dsss = brainSet->getDisplaySettingsSurfaceShape(); int shapeColumn = -1; if (dsss->getNodeUncertaintyEnabled()) { shapeColumn = dsss->getNodeUncertaintyColumn(); if (shapeColumn >= ssf->getNumberOfColumns()) { shapeColumn = -1; } } BrainSetNodeAttribute* attributes = brainSet->getNodeAttributes(0); // // Show node highlighting // for (int i = 0; i < numCoords; i++) { if (attributes[i].getDisplayFlag()) { BrainSetNodeAttribute* bna = brainSet->getNodeAttributes(i); float xyz[3]; cf->getCoordinate(i, xyz); bool drawIt = false; if (bna->getHighlighting() == BrainSetNodeAttribute::HIGHLIGHT_NODE_LOCAL) { glColor4f(0, 1.0, 0, 0.5); drawIt = true; } else if (bna->getHighlighting() == BrainSetNodeAttribute::HIGHLIGHT_NODE_REMOTE) { glColor4f(0, 0, 1.0, 0.5); drawIt = true; } if (drawIt) { if (shapeColumn >= 0) { const float radius = fabs(ssf->getValue(i, shapeColumn)); const float dist = fabs(xyz[axisIndex] - axisCoord); if (dist < radius) { float size = radius; if (dist > 0.0) { // // Disk should be smaller the further it is from the ID node // const float angle = std::acos(dist / radius); size = radius * std::sin(angle); } convertVolumeItemXYZToScreenXY(axis, xyz); glPushMatrix(); glTranslatef(xyz[0], xyz[1], xyz[2]); drawDisk(size * 2.0); glPopMatrix(); } } else { // glBegin(GL_POINTS); // glVertex3fv(xyz); // glEnd(); } } } } } glDisable(GL_BLEND); } /** * Draw a volume file sliece */ void BrainModelOpenGL::drawVolumeFileSlice(VolumeFile* vf, const VolumeFile::VOLUME_AXIS axis, const int currentSlice, const unsigned long maskForThisUnderlayOrOverlay, const bool overlayFlag) { if (vf == NULL) { return; } int voldim[3]; vf->getDimensions(voldim); if ((voldim[0] <= 0) || (voldim[1] <= 0) || (voldim[2] <= 0)) { return; } // // Do not draw invalid slices // switch(axis) { case VolumeFile::VOLUME_AXIS_X: // PARASAGITTAL if ((currentSlice < 0) || (currentSlice >= voldim[0])) { return; } break; case VolumeFile::VOLUME_AXIS_Y: // CORONAL if ((currentSlice < 0) || (currentSlice >= voldim[1])) { return; } break; case VolumeFile::VOLUME_AXIS_Z: // HORIZONTAL if ((currentSlice < 0) || (currentSlice >= voldim[2])) { return; } break; case VolumeFile::VOLUME_AXIS_ALL: case VolumeFile::VOLUME_AXIS_OBLIQUE: case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: case VolumeFile::VOLUME_AXIS_UNKNOWN: std::cout << "PROGAM ERROR: Invalid volume axis at " << __LINE__ << " in " << __FILE__ << std::endl; return; } // // Get volume display settings // DisplaySettingsVolume* dsv = brainSet->getDisplaySettingsVolume(); BrainModelVolume* bmv = brainSet->getBrainModelVolume(); BrainModelVolumeVoxelColoring* voxelColoring = brainSet->getVoxelColoring(); // // Setup these dimensions for displaying the surface // int dim[3] = { 0, 0, 0 }; switch(axis) { case VolumeFile::VOLUME_AXIS_X: // PARASAGITTAL dim[0] = voldim[1]; dim[1] = voldim[2]; dim[2] = voldim[0]; break; case VolumeFile::VOLUME_AXIS_Y: // CORONAL dim[0] = voldim[0]; dim[1] = voldim[2]; dim[2] = voldim[1]; break; case VolumeFile::VOLUME_AXIS_Z: // HORIZONTAL dim[0] = voldim[0]; dim[1] = voldim[1]; dim[2] = voldim[2]; break; case VolumeFile::VOLUME_AXIS_ALL: case VolumeFile::VOLUME_AXIS_OBLIQUE: case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: case VolumeFile::VOLUME_AXIS_UNKNOWN: std::cout << "PROGAM ERROR: Invalid volume axis at " << __LINE__ << " in " << __FILE__ << std::endl; return; } // // Get the volume spacing // float spacing[3]; vf->getSpacing(spacing); float voxelSizeX = 1.0; float voxelSizeY = 1.0; // // Get the origin // float origin[3]; vf->getOrigin(origin); float voxelOriginX = 1.0; float voxelOriginY = 1.0; // // See if this is a vector volume // const bool drawVectorsFlag = (vf->getVolumeType() == VolumeFile::VOLUME_TYPE_VECTOR); // // See if anatomy volume and if it is being thresholded // bool thresholdValid = false; float thresholdValue[2] = { 0.0, 1.0e10 }; if (vf->getVolumeType() == VolumeFile::VOLUME_TYPE_ANATOMY) { if (dsv->getAnatomyThresholdValid()) { thresholdValid = true; dsv->getAnatomyThreshold(thresholdValue[0], thresholdValue[1]); } } // // Check for selection mode // bool selectFlag = false; bool drawAllVoxels = false; if (selectionMask & maskForThisUnderlayOrOverlay) { glPushName(maskForThisUnderlayOrOverlay); selectFlag = true; // // If segmentation volume editing // if (editingSegmentationVolumeFlag) { // // See if the volume being drawn is the segmentation volume // BrainModelVolume* bmv = brainSet->getBrainModelVolume(); if (bmv != NULL) { if (vf == bmv->getSelectedVolumeSegmentationFile()) { drawAllVoxels = true; } } } // // If paint volume editing // if (editingPaintVolumeFlag) { // // See if the volume being drawn is the paint volume // BrainModelVolume* bmv = brainSet->getBrainModelVolume(); if (bmv != NULL) { if (vf == bmv->getSelectedVolumePaintFile()) { drawAllVoxels = true; } } } } if ((selectFlag == false) && (selectionMask != SELECTION_MASK_OFF)) { return; } // // Disable blending // unsigned char alphaValue = 255; // // drawing type for segmentation volume // DisplaySettingsVolume::SEGMENTATION_DRAW_TYPE drawType = DisplaySettingsVolume::SEGMENTATION_DRAW_TYPE_SOLID; // // If this is a segmentation volume // if ((vf->getVolumeType() == VolumeFile::VOLUME_TYPE_SEGMENTATION) && (selectFlag == false)) { // // Get the segmentation drawing type // drawType = dsv->getSegmentationDrawType(); // // If draw type is blending // if (drawType == DisplaySettingsVolume::SEGMENTATION_DRAW_TYPE_BLEND) { // // If underlay is anatomy // BrainModelVolumeVoxelColoring* voxelColoring = brainSet->getVoxelColoring(); if (voxelColoring->getUnderlay() == BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_ANATOMY) { // // If the anatomy volume is valid // if (bmv->getSelectedVolumeAnatomyFile() != NULL) { // // Enable blending // alphaValue = static_cast(dsv->getSegmentationTranslucency() * 255); } } } } else if (selectFlag == false) { if (overlayFlag) { alphaValue = static_cast(dsv->getOverlayOpacity() * 255); } } // // ROI volumes always use alpha // if (vf->getVolumeType() == VolumeFile::VOLUME_TYPE_ROI) { //alphaValue = 165; } // // If alpha blending is on // if (alphaValue < 255) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } int increment = 1; if (drawVectorsFlag) { increment = dsv->getVectorVolumeSparsity(); } // // Draw the voxels of the selected slice // for (int i = 0; i < dim[0]; i += increment) { for (int j = 0; j < dim[1]; j += increment) { int ijk[3]; switch(axis) { case VolumeFile::VOLUME_AXIS_X: // PARASAGITTAL ijk[0] = currentSlice; ijk[1] = i; ijk[2] = j; voxelSizeX = spacing[1]; voxelSizeY = spacing[2]; voxelOriginX = origin[1]; voxelOriginY = origin[2]; break; case VolumeFile::VOLUME_AXIS_Y: // CORONAL ijk[0] = i; ijk[1] = currentSlice; ijk[2] = j; voxelSizeX = spacing[0]; voxelSizeY = spacing[2]; voxelOriginX = origin[0]; voxelOriginY = origin[2]; break; case VolumeFile::VOLUME_AXIS_Z: // HORIZONTAL ijk[0] = i; ijk[1] = j; ijk[2] = currentSlice; voxelSizeX = spacing[0]; voxelSizeY = spacing[1]; voxelOriginX = origin[0]; voxelOriginY = origin[1]; break; case VolumeFile::VOLUME_AXIS_ALL: case VolumeFile::VOLUME_AXIS_OBLIQUE: case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } // // Don't draw black voxels // Note: Only draw voxel if its 4th color component is non-zero // unsigned char rgb[4]; voxelColoring->getVoxelColoring(vf, ijk[0], ijk[1], ijk[2], rgb); if ((rgb[3] == VolumeFile::VOXEL_COLOR_STATUS_VALID) || drawAllVoxels) { // // Override coloring if thresholding an anatomical volume // if (thresholdValid) { float val = vf->getVoxel(ijk); if ((val > thresholdValue[0]) && (val < thresholdValue[1])) { // // Above threshold is green so turn off red and blue // rgb[0] = 0; rgb[2] = 0; } } // // Set the voxels color // glColor4ub(rgb[0], rgb[1], rgb[2], alphaValue); // // If selecting voxels // if (selectFlag) { glPushName(ijk[0]); glPushName(ijk[1]); glPushName(ijk[2]); glPushName(axis); } // // Set voxel coordinate and draw it // float voxelX = i * voxelSizeX + voxelOriginX; float voxelY = j * voxelSizeY + voxelOriginY; // // Is voxel coordinate at center of voxel? // JWH 07/11/2008 // voxelX -= (voxelSizeX * 0.5); voxelY -= (voxelSizeY * 0.5); if (drawVectorsFlag) { voxelX += voxelSizeX * 0.5; voxelY += voxelSizeY * 0.5; glBegin(GL_LINES); glColor4ub(255, 0, 0, 255); glVertex2f(voxelX, voxelY); glColor4ub(255, 255, 0, 255); const float mag = vf->getVoxel(ijk, 3); switch(axis) { case VolumeFile::VOLUME_AXIS_X: // PARASAGITTAL glVertex2f(voxelX + vf->getVoxel(ijk, 1) * mag, voxelY + vf->getVoxel(ijk, 2) * mag); break; case VolumeFile::VOLUME_AXIS_Y: // CORONAL glVertex2f(voxelX + vf->getVoxel(ijk, 0) * mag, voxelY + vf->getVoxel(ijk, 2) * mag); break; case VolumeFile::VOLUME_AXIS_Z: // HORIZONTAL glVertex2f(voxelX + vf->getVoxel(ijk, 0) * mag, voxelY + vf->getVoxel(ijk, 1) * mag); break; case VolumeFile::VOLUME_AXIS_ALL: case VolumeFile::VOLUME_AXIS_OBLIQUE: case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } glEnd(); } else { switch (drawType) { case DisplaySettingsVolume::SEGMENTATION_DRAW_TYPE_SOLID: glRectf(voxelX, voxelY, voxelX + voxelSizeX, voxelY + voxelSizeY); break; case DisplaySettingsVolume::SEGMENTATION_DRAW_TYPE_BLEND: glRectf(voxelX, voxelY, voxelX + voxelSizeX, voxelY + voxelSizeY); break; case DisplaySettingsVolume::SEGMENTATION_DRAW_TYPE_BOX: glBegin(GL_LINE_LOOP); glVertex2f(voxelX, voxelY); glVertex2f(voxelX + voxelSizeX, voxelY); glVertex2f(voxelX + voxelSizeX, voxelY + voxelSizeY); glVertex2f(voxelX, voxelY + voxelSizeY); glEnd(); break; case DisplaySettingsVolume::SEGMENTATION_DRAW_TYPE_CROSS: glBegin(GL_LINES); glVertex2f(voxelX, voxelY); glVertex2f(voxelX + voxelSizeX, voxelY + voxelSizeY); glVertex2f(voxelX + voxelSizeX, voxelY); glVertex2f(voxelX, voxelY + voxelSizeY); glEnd(); break; } } // // If selecting voxels // if (selectFlag) { glPopName(); glPopName(); glPopName(); glPopName(); } } } } // // Turn off alpha blending // glDisable(GL_BLEND); if (selectFlag) { glPopName(); } } /* * Called if an error occurs while creating a quadric object. */ static void quadricErrorCallback(GLenum errorCode) { const GLubyte* str = gluErrorString(errorCode); std::cout << "GLU Quadric Error: " << str << std::endl; } /** * draw a sphere. */ void BrainModelOpenGL::drawSphere(const float diameter) { bool useDisplayList = false; if (useDisplayListsForShapes) { if (sphereDisplayList == 0) { std::cout << "ERROR: Sphere Display List has not been created. Was initializeOpenGL() called ?" << std::endl; } else if (glIsList(sphereDisplayList) == GL_TRUE) { useDisplayList = true; } else { std::cout << "ERROR: sphere display list number is an invalid display list number." << std::endl; } } glPushMatrix(); glScalef(diameter, diameter, diameter); if (useDisplayList) { glCallList(sphereDisplayList); } else { drawingCommandsSphere(); } glPopMatrix(); } /** * Create a cone quadric and put it in a display list. * The cone is one unit in diameter and one unit in height. */ void BrainModelOpenGL::createCylinderQuadricAndDisplayList() { if (cylinderQuadric != NULL) { gluDeleteQuadric(cylinderQuadric); cylinderQuadric = NULL; } cylinderQuadric = gluNewQuadric(); #ifdef Q_OS_MACX gluQuadricCallback(cylinderQuadric, GLU_ERROR, (GLvoid (*)())quadricErrorCallback); #endif #ifdef Q_OS_WIN32 gluQuadricCallback(cylinderQuadric, GLU_ERROR, (void (__stdcall*)(void))quadricErrorCallback); #endif #ifdef Q_OS_LINUX gluQuadricCallback(cylinderQuadric, (GLenum)GLU_ERROR, (GLvoid (*)())quadricErrorCallback); #endif #ifdef Q_OS_UNIX #ifndef Q_OS_MACX #ifndef Q_OS_LINUX gluQuadricCallback(cylinderQuadric, GLU_ERROR, (GLvoid (*)())quadricErrorCallback); #endif #endif #endif #ifdef Q_OS_LINUX gluQuadricDrawStyle(cylinderQuadric, (GLenum)GLU_FILL); gluQuadricOrientation(cylinderQuadric, (GLenum)GLU_OUTSIDE); gluQuadricNormals(cylinderQuadric, (GLenum)GLU_SMOOTH); #else gluQuadricDrawStyle(cylinderQuadric, GLU_FILL); gluQuadricOrientation(cylinderQuadric, GLU_OUTSIDE); gluQuadricNormals(cylinderQuadric, GLU_SMOOTH); #endif if (useDisplayListsForShapes) { if (glIsList(cylinderDisplayList)) { glDeleteLists(cylinderDisplayList, 1); } cylinderDisplayList = glGenLists(1); glNewList(cylinderDisplayList, GL_COMPILE); drawingCommandsCylinder(); glEndList(); } } /** * Execute OpenGL commands to draw a cylinder. */ void BrainModelOpenGL::drawingCommandsCylinder() { //gluCylinder(cylinderQuadric, 0.5, 0.5, 1.0, 10, 10); gluCylinder(cylinderQuadric, 0.5, 0.5, 1.0, QUADRIC_NUMBER_OF_SLICES, 1); } /** * Create a cone quadric and put it in a display list. * The cone is one unit in diameter and one unit in height. */ void BrainModelOpenGL::createConeQuadricAndDisplayList() { if (coneQuadric != NULL) { gluDeleteQuadric(coneQuadric); coneQuadric = NULL; } coneQuadric = gluNewQuadric(); #ifdef Q_OS_MACX gluQuadricCallback(coneQuadric, GLU_ERROR, (GLvoid (*)())quadricErrorCallback); #endif #ifdef Q_OS_WIN32 gluQuadricCallback(coneQuadric, GLU_ERROR, (void (__stdcall*)(void))quadricErrorCallback); #endif #ifdef Q_OS_LINUX gluQuadricCallback(coneQuadric, (GLenum)GLU_ERROR, (GLvoid (*)())quadricErrorCallback); #endif #ifdef Q_OS_UNIX #ifndef Q_OS_MACX #ifndef Q_OS_LINUX gluQuadricCallback(coneQuadric, GLU_ERROR, (GLvoid (*)())quadricErrorCallback); #endif #endif #endif #ifdef Q_OS_LINUX gluQuadricDrawStyle(coneQuadric, (GLenum)GLU_FILL); gluQuadricOrientation(coneQuadric, (GLenum)GLU_OUTSIDE); gluQuadricNormals(coneQuadric, (GLenum)GLU_SMOOTH); #else gluQuadricDrawStyle(coneQuadric, GLU_FILL); gluQuadricOrientation(coneQuadric, GLU_OUTSIDE); gluQuadricNormals(coneQuadric, GLU_SMOOTH); #endif if (useDisplayListsForShapes) { if (glIsList(coneDisplayList)) { glDeleteLists(coneDisplayList, 1); } coneDisplayList = glGenLists(1); glNewList(coneDisplayList, GL_COMPILE); drawingCommandsCone(); glEndList(); } } /** * Execute OpenGL commands to draw a cone. */ void BrainModelOpenGL::drawingCommandsCone() { gluCylinder(coneQuadric, 0.5, 0.0, 1.0, QUADRIC_NUMBER_OF_SLICES, 1); //10); } /** * Create a sphere quadric and put it in a display list. * The sphere is one unit in diameter. */ void BrainModelOpenGL::createSphereQuadricAndDisplayList() { if (sphereQuadric != NULL) { gluDeleteQuadric(sphereQuadric); sphereQuadric = NULL; } sphereQuadric = gluNewQuadric(); #ifdef Q_OS_MACX gluQuadricCallback(sphereQuadric, GLU_ERROR, (GLvoid (*)())quadricErrorCallback); #endif #ifdef Q_OS_WIN32 gluQuadricCallback(sphereQuadric, GLU_ERROR, (void (__stdcall*)(void))quadricErrorCallback); #endif #ifdef Q_OS_LINUX gluQuadricCallback(sphereQuadric, (GLenum)GLU_ERROR, (GLvoid (*)())quadricErrorCallback); #endif #ifdef Q_OS_UNIX #ifndef Q_OS_MACX #ifndef Q_OS_LINUX gluQuadricCallback(sphereQuadric, GLU_ERROR, (GLvoid (*)())quadricErrorCallback); #endif #endif #endif #ifdef Q_OS_LINUX gluQuadricDrawStyle(sphereQuadric, (GLenum)GLU_FILL); gluQuadricOrientation(sphereQuadric, (GLenum)GLU_OUTSIDE); gluQuadricNormals(sphereQuadric, (GLenum)GLU_SMOOTH); #else gluQuadricDrawStyle(sphereQuadric, GLU_FILL); gluQuadricOrientation(sphereQuadric, GLU_OUTSIDE); gluQuadricNormals(sphereQuadric, GLU_SMOOTH); #endif if (useDisplayListsForShapes) { if (glIsList(sphereDisplayList)) { glDeleteLists(sphereDisplayList, 1); } sphereDisplayList = glGenLists(1); if (sphereDisplayList == 0) { std::cout << "ERROR: Unable to create a display list for the sphere." << std::endl; return; } glNewList(sphereDisplayList, GL_COMPILE); drawingCommandsSphere(); glEndList(); } } /** * Execute OpenGL commands to draw a sphere. */ void BrainModelOpenGL::drawingCommandsSphere() { gluSphere(sphereQuadric, 0.5, 10, 10); } /** * draw a 2D Disk (filled circle). */ void BrainModelOpenGL::drawDisk(const float diameter) { bool useDisplayList = false; if (useDisplayListsForShapes) { if (diskDisplayList == 0) { std::cout << "Disk Display List has not been created. Was initializeOpenGL() called ?" << std::endl; } else if (glIsList(diskDisplayList) == GL_TRUE) { useDisplayList = true; } else { std::cout << "ERROR: Disk display list number is an invalid display list number." << std::endl; } } glPushMatrix(); glScalef(diameter, diameter, diameter); if (useDisplayList) { glCallList(diskDisplayList); } else { drawingCommandsDisk(); } glPopMatrix(); } /** * draw a cone. */ void BrainModelOpenGL::drawCone() { bool useDisplayList = false; if (useDisplayListsForShapes) { if (coneDisplayList == 0) { std::cout << "ERROR: Cone Display List has not been created. Was initializeOpenGL() called ?" << std::endl; } else if (glIsList(coneDisplayList) == GL_TRUE) { useDisplayList = true; } else { std::cout << "ERROR: Cone display list number is an invalid display list number." << std::endl; } } glPushMatrix(); if (useDisplayList) { glCallList(coneDisplayList); } else { drawingCommandsCone(); } glPopMatrix(); } /** * draw cylinder. */ void BrainModelOpenGL::drawCylinder() { bool useDisplayList = false; if (useDisplayListsForShapes) { if (cylinderDisplayList == 0) { std::cout << "ERROR: Cylinder Display List has not been created. Was initializeOpenGL() called ?" << std::endl; } else if (glIsList(cylinderDisplayList) == GL_TRUE) { useDisplayList = true; } else { std::cout << "ERROR: Cylinder display list number is an invalid display list number." << std::endl; } } glPushMatrix(); if (useDisplayList) { glCallList(cylinderDisplayList); } else { drawingCommandsCylinder(); } glPopMatrix(); } /** * draw a square. */ void BrainModelOpenGL::drawSquare() { bool useDisplayList = false; if (useDisplayListsForShapes) { if (squareDisplayList == 0) { std::cout << "ERROR: Square Display List has not been created. Was initializeOpenGL() called ?" << std::endl; } else if (glIsList(squareDisplayList) == GL_TRUE) { useDisplayList = true; } else { std::cout << "ERROR: Square display list number is an invalid display list number." << std::endl; } } glPushMatrix(); if (useDisplayList) { glCallList(squareDisplayList); } else { drawingCommandsSquare(); } glPopMatrix(); } /** * draw a box. */ void BrainModelOpenGL::drawBox() { bool useDisplayList = false; if (useDisplayListsForShapes) { if (boxDisplayList == 0) { std::cout << "ERROR: Box Display List has not been created. Was initializeOpenGL() called ?" << std::endl; } else if (glIsList(boxDisplayList) == GL_TRUE) { useDisplayList = true; } else { std::cout << "ERROR: Box display list number is an invalid display list number." << std::endl; } } glPushMatrix(); if (useDisplayList) { glCallList(boxDisplayList); } else { drawingCommandsBox(); } glPopMatrix(); } /** * a ring. */ void BrainModelOpenGL::drawRing() { bool useDisplayList = false; if (useDisplayListsForShapes) { if (ringDisplayList == 0) { std::cout << "ERROR: Ring Display List has not been created. Was initializeOpenGL() called ?" << std::endl; } else if (glIsList(ringDisplayList) == GL_TRUE) { useDisplayList = true; } else { std::cout << "ERROR: Ring display list number is an invalid display list number." << std::endl; } } glPushMatrix(); if (useDisplayList) { glCallList(ringDisplayList); } else { drawingCommandsRing(); } glPopMatrix(); } /** * draw a diamond. */ void BrainModelOpenGL::drawDiamond() { bool useDisplayList = false; if (useDisplayListsForShapes) { if (diamondDisplayList == 0) { std::cout << "ERROR: Diamond Display List has not been created. Was initializeOpenGL() called ?" << std::endl; } else if (glIsList(diamondDisplayList) == GL_TRUE) { useDisplayList = true; } else { std::cout << "ERROR: Diamond display list number is an invalid display list number." << std::endl; } } glPushMatrix(); if (useDisplayList) { glCallList(diamondDisplayList); } else { drawingCommandsDiamond(); } glPopMatrix(); } /** * Create a 2D disk quadric (filled circle) and put it in a display list. * The disk is one unit in diameter. */ void BrainModelOpenGL::createDiskQuadricAndDisplayList() { if (diskQuadric != NULL) { gluDeleteQuadric(diskQuadric); diskQuadric = NULL; } diskQuadric = gluNewQuadric(); #ifdef Q_OS_MACX gluQuadricCallback(diskQuadric, GLU_ERROR, (GLvoid (*)())quadricErrorCallback); #endif #ifdef Q_OS_WIN32 gluQuadricCallback(diskQuadric, GLU_ERROR, (void (__stdcall*)(void))quadricErrorCallback); #endif #ifdef Q_OS_LINUX gluQuadricCallback(diskQuadric, (GLenum)GLU_ERROR, (GLvoid (*)())quadricErrorCallback); #endif #ifdef Q_OS_UNIX #ifndef Q_OS_MACX #ifndef Q_OS_LINUX gluQuadricCallback(diskQuadric, GLU_ERROR, (GLvoid (*)())quadricErrorCallback); #endif #endif #endif #ifdef Q_OS_LINUX gluQuadricDrawStyle(diskQuadric, (GLenum)GLU_FILL); gluQuadricOrientation(diskQuadric, (GLenum)GLU_OUTSIDE); gluQuadricNormals(diskQuadric, (GLenum)GLU_SMOOTH); #else gluQuadricDrawStyle(diskQuadric, GLU_FILL); gluQuadricOrientation(diskQuadric, GLU_OUTSIDE); gluQuadricNormals(diskQuadric, GLU_SMOOTH); #endif if (useDisplayListsForShapes) { if (glIsList(diskDisplayList)) { glDeleteLists(diskDisplayList, 1); } diskDisplayList = glGenLists(1); glNewList(diskDisplayList, GL_COMPILE); drawingCommandsDisk(); glEndList(); } } /** * Execute OpenGL commands to draw a disk. */ void BrainModelOpenGL::drawingCommandsDisk() { gluDisk(diskQuadric, 0.0, 0.5, QUADRIC_NUMBER_OF_SLICES, 1); } /** * Create a square and put it in a display list. */ void BrainModelOpenGL::createSquareDisplayList() { if (useDisplayListsForShapes) { if (glIsList(squareDisplayList)) { glDeleteLists(squareDisplayList, 1); } squareDisplayList = glGenLists(1); glNewList(squareDisplayList, GL_COMPILE); drawingCommandsSquare(); glEndList(); } } /** * Create a box and put it in a display list. */ void BrainModelOpenGL::createBoxDisplayList() { if (useDisplayListsForShapes) { if (glIsList(boxDisplayList)) { glDeleteLists(boxDisplayList, 1); } boxDisplayList = glGenLists(1); glNewList(boxDisplayList, GL_COMPILE); drawingCommandsBox(); glEndList(); } } /** * Execute OpenGL commands to draw a square. */ void BrainModelOpenGL::drawingCommandsSquare() { 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); glEnd(); } /** * Execute OpenGL commands to draw a box. */ void BrainModelOpenGL::drawingCommandsBox() { glBegin(GL_QUADS); // // Bottom // glNormal3f(0.0, 0.0, -1.0); glVertex3f(-0.5, 0.5, -0.5); glVertex3f( 0.5, 0.5, -0.5); glVertex3f( 0.5, -0.5, -0.5); glVertex3f(-0.5, -0.5, -0.5); // // Top // glNormal3f(0.0, 0.0, 1.0); glVertex3f(-0.5, -0.5, 0.5); glVertex3f( 0.5, -0.5, 0.5); glVertex3f( 0.5, 0.5, 0.5); glVertex3f(-0.5, 0.5, 0.5); // // Left // glNormal3f(-1.0, 0.0, 0.0); glVertex3f(-0.5, 0.5, -0.5); glVertex3f(-0.5, -0.5, -0.5); glVertex3f(-0.5, -0.5, 0.5); glVertex3f(-0.5, 0.5, 0.5); // // Right // glNormal3f(1.0, 0.0, 0.0); glVertex3f( 0.5, -0.5, -0.5); glVertex3f( 0.5, 0.5, -0.5); glVertex3f( 0.5, 0.5, 0.5); glVertex3f( 0.5, -0.5, 0.5); // // Front // glNormal3f(0.0, -1.0, 0.0); glVertex3f(-0.5, -0.5, -0.5); glVertex3f( 0.5, -0.5, -0.5); glVertex3f( 0.5, -0.5, 0.5); glVertex3f(-0.5, -0.5, 0.5); // // Back // glNormal3f(0.0, 1.0, 0.0); glVertex3f( 0.5, 0.5, -0.5); glVertex3f(-0.5, 0.5, -0.5); glVertex3f(-0.5, 0.5, 0.5); glVertex3f( 0.5, 0.5, 0.5); glEnd(); } /** * Create a ring and put it in a display list. */ void BrainModelOpenGL::createRingQuadricAndDisplayList() { if (ringQuadric != NULL) { gluDeleteQuadric(ringQuadric); ringQuadric = NULL; } ringQuadric = gluNewQuadric(); #ifdef Q_OS_MACX gluQuadricCallback(ringQuadric, GLU_ERROR, (GLvoid (*)())quadricErrorCallback); #endif #ifdef Q_OS_WIN32 gluQuadricCallback(ringQuadric, GLU_ERROR, (void (__stdcall*)(void))quadricErrorCallback); #endif #ifdef Q_OS_LINUX gluQuadricCallback(ringQuadric, (GLenum)GLU_ERROR, (GLvoid (*)())quadricErrorCallback); #endif #ifdef Q_OS_UNIX #ifndef Q_OS_MACX #ifndef Q_OS_LINUX gluQuadricCallback(ringQuadric, GLU_ERROR, (GLvoid (*)())quadricErrorCallback); #endif #endif #endif #ifdef Q_OS_LINUX gluQuadricDrawStyle(ringQuadric, (GLenum)GLU_FILL); gluQuadricOrientation(ringQuadric, (GLenum)GLU_OUTSIDE); gluQuadricNormals(ringQuadric, (GLenum)GLU_SMOOTH); #else gluQuadricDrawStyle(ringQuadric, GLU_FILL); gluQuadricOrientation(ringQuadric, GLU_OUTSIDE); gluQuadricNormals(ringQuadric, GLU_SMOOTH); #endif if (useDisplayListsForShapes) { if (glIsList(ringDisplayList)) { glDeleteLists(ringDisplayList, 1); } ringDisplayList = glGenLists(1); glNewList(ringDisplayList, GL_COMPILE); drawingCommandsRing(); glEndList(); } } /** * Execute OpenGL commands to draw a ring. */ void BrainModelOpenGL::drawingCommandsRing() { gluDisk(ringQuadric, 0.4, 0.5, 8, 3); } /** * Create a diamond and put it in a display list. */ void BrainModelOpenGL::createDiamondQuadricAndDisplayList() { if (diamondQuadric != NULL) { gluDeleteQuadric(diamondQuadric); diamondQuadric = NULL; } diamondQuadric = gluNewQuadric(); #ifdef Q_OS_MACX gluQuadricCallback(diamondQuadric, GLU_ERROR, (GLvoid (*)())quadricErrorCallback); #endif #ifdef Q_OS_WIN32 gluQuadricCallback(diamondQuadric, GLU_ERROR, (void (__stdcall*)(void))quadricErrorCallback); #endif #ifdef Q_OS_LINUX gluQuadricCallback(diamondQuadric, (GLenum)GLU_ERROR, (GLvoid (*)())quadricErrorCallback); #endif #ifdef Q_OS_UNIX #ifndef Q_OS_MACX #ifndef Q_OS_LINUX gluQuadricCallback(diamondQuadric, GLU_ERROR, (GLvoid (*)())quadricErrorCallback); #endif #endif #endif #ifdef Q_OS_LINUX gluQuadricDrawStyle(diamondQuadric, (GLenum)GLU_FILL); gluQuadricOrientation(diamondQuadric, (GLenum)GLU_OUTSIDE); gluQuadricNormals(diamondQuadric, (GLenum)GLU_FLAT); //GLU_SMOOTH); #else gluQuadricDrawStyle(diamondQuadric, GLU_FILL); gluQuadricOrientation(diamondQuadric, GLU_OUTSIDE); gluQuadricNormals(diamondQuadric, GLU_FLAT); //GLU_SMOOTH); #endif if (useDisplayListsForShapes) { if (glIsList(diamondDisplayList)) { glDeleteLists(diamondDisplayList, 1); } diamondDisplayList = glGenLists(1); glNewList(diamondDisplayList, GL_COMPILE); drawingCommandsDiamond(); glEndList(); } } /** * Execute OpenGL commands to draw a diamond. */ void BrainModelOpenGL::drawingCommandsDiamond() { gluSphere(diamondQuadric, 0.5, 4, 2); } /** * Draw the surface forces */ void BrainModelOpenGL::drawSurfaceForces(const CoordinateFile* cf, const int numCoords) { DisplaySettingsSurface* dsn = brainSet->getDisplaySettingsSurface(); const float length = dsn->getForceVectorDisplayLength(); glLineWidth(getValidLineWidth(1.0)); glBegin(GL_LINES); for (int i = 0; i < numCoords; i++) { BrainSetNodeAttribute* bna = brainSet->getNodeAttributes(i); if (bna->getDisplayFlag()) { float linearForce[3], angularForce[3], totalForce[3]; bna->getMorphingForces(linearForce, angularForce, totalForce); const float* pos = cf->getCoordinate(i); if (dsn->getShowMorphingTotalForces()) { float vect[3] = { pos[0] + length * totalForce[0], pos[1] + length * totalForce[1], pos[2] + length * totalForce[2] }; glColor3ub(0, 0, 255); glVertex3fv(pos); glVertex3fv(vect); } if (dsn->getShowMorphingAngularForces()) { float vect[3] = { pos[0] + length * angularForce[0], pos[1] + length * angularForce[1], pos[2] + length * angularForce[2] }; glColor3ub(0, 255, 0); glVertex3fv(pos); glVertex3fv(vect); } if (dsn->getShowMorphingLinearForces()) { float vect[3] = { pos[0] + length * linearForce[0], pos[1] + length * linearForce[1], pos[2] + length * linearForce[2] }; glColor3ub(255, 0, 0); glVertex3fv(pos); glVertex3fv(vect); } } } glEnd(); } /** * Draw the surface as points. */ void BrainModelOpenGL::drawSurfaceNodes(const BrainModelSurfaceNodeColoring* bs, const int modelNumber, const CoordinateFile* cf, const int numCoords, const bool drawInSurfaceEditColor) { DisplaySettingsSurface* dsn = brainSet->getDisplaySettingsSurface(); const BrainSetNodeAttribute* attributes = brainSet->getNodeAttributes(0); const DisplaySettingsSurface::DRAW_MODE surfaceDrawingMode = dsn->getDrawMode(); glPointSize(getValidPointSize(dsn->getNodeSize())); if (drawInSurfaceEditColor) { glColor3ubv(surfaceEditDrawColor); glBegin(GL_POINTS); for (int i = 0; i < numCoords; i++) { if (attributes[i].getDisplayFlag()) { glVertex3fv(cf->getCoordinate(i)); } } glEnd(); if (nodeSpecialHighlighting.empty() == false) { glPointSize(getValidPointSize(dsn->getNodeSize() * 2.0)); glColor3ub(255, 0, 0); glBegin(GL_POINTS); for (int i = 0; i < static_cast(nodeSpecialHighlighting.size()); i++) { glVertex3fv(cf->getCoordinate(nodeSpecialHighlighting[i])); } glEnd(); } return; } if (selectionMask == SELECTION_MASK_OFF) { #ifdef GL_VERSION_1_1 glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glVertexPointer(3, GL_FLOAT, 0, cf->getCoordinate(0)); glColorPointer(4, GL_UNSIGNED_BYTE, 0, bs->getNodeColor(modelNumber, 0)); if (brainSet->getDisplayAllNodes()) { glDrawArrays(GL_POINTS, 0, numCoords); } else { for (int i = 0; i < numCoords; i++) { if (attributes[i].getDisplayFlag()) { glArrayElement(i); } } } glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); #else // GL_VERSION_1_1 glBegin(GL_POINTS); for (int i = 0; i < numCoords; i++) { if (attributes[i]->getDisplayFlag()) { glColor4ubv(bs->getNodeColor(i)); glVertex3fv(cf->getCoordinate(i)); } } glEnd(); #endif // GL_VERSION_1_1 if (nodeSpecialHighlighting.empty() == false) { glPointSize(getValidPointSize(dsn->getNodeSize() * 2.0)); glColor3ub(255, 0, 0); glBegin(GL_POINTS); for (int i = 0; i < static_cast(nodeSpecialHighlighting.size()); i++) { glVertex3fv(cf->getCoordinate(nodeSpecialHighlighting[i])); } glEnd(); } } else if (selectionMask & SELECTION_MASK_NODE) { glPushName(SELECTION_MASK_NODE); for (int i = 0; i < numCoords; i++) { if (attributes[i].getDisplayFlag()) { bool drawIt = true; if (surfaceDrawingMode == DisplaySettingsSurface::DRAW_MODE_LINKS_EDGES_ONLY) { drawIt = (attributes[i].getClassification() != BrainSetNodeAttribute::CLASSIFICATION_TYPE_INTERIOR); } if (drawIt) { glPushName(i); glBegin(GL_POINTS); glVertex3fv(cf->getCoordinate(i)); glEnd(); glPopName(); } } } glPopName(); } } /** * Draw the surface as links. */ void BrainModelOpenGL::drawSurfaceLinks(const BrainModelSurfaceNodeColoring* bs, const int modelNumber, const CoordinateFile* cf, const TopologyFile* tf, const int numTiles, const bool drawEdgesOnly, const bool drawInSurfaceEditColor) { DisplaySettingsSurface* dsn = brainSet->getDisplaySettingsSurface(); const BrainSetNodeAttribute* attributes = brainSet->getNodeAttributes(0); glLineWidth(getValidLineWidth(dsn->getLinkSize())); const bool idLinkMode = (selectionMask & SELECTION_MASK_LINK); if (idLinkMode) { glLineWidth(getValidLineWidth(5.0)); } if (idLinkMode == false) { glBegin(GL_LINES); } for (int i = 0; i < numTiles; i++) { int v1, v2, v3; tf->getTile(i, v1, v2, v3); bool drawV1 = attributes[v1].getDisplayFlag(); bool drawV2 = attributes[v2].getDisplayFlag(); bool drawV3 = attributes[v3].getDisplayFlag(); if (drawEdgesOnly) { if (drawV1) { drawV1 = (attributes[v1].getClassification() != BrainSetNodeAttribute::CLASSIFICATION_TYPE_INTERIOR); } if (drawV2) { drawV2 = (attributes[v2].getClassification() != BrainSetNodeAttribute::CLASSIFICATION_TYPE_INTERIOR); } if (drawV3) { drawV3 = (attributes[v3].getClassification() != BrainSetNodeAttribute::CLASSIFICATION_TYPE_INTERIOR); } } if (drawV1 && drawV2) { if (idLinkMode) { glPushName(SELECTION_MASK_LINK); glPushName(v1); glPushName(v2); glBegin(GL_LINES); } if (drawInSurfaceEditColor) { glColor3ubv(surfaceEditDrawColor); } else { glColor4ubv(bs->getNodeColor(modelNumber, v1)); } glVertex3fv(cf->getCoordinate(v1)); if (drawInSurfaceEditColor) { glColor3ubv(surfaceEditDrawColor); } else { glColor4ubv(bs->getNodeColor(modelNumber, v2)); } glVertex3fv(cf->getCoordinate(v2)); if (idLinkMode) { glEnd(); glPopName(); glPopName(); glPopName(); } } if (drawV2 && drawV3) { if (idLinkMode) { glPushName(SELECTION_MASK_LINK); glPushName(v2); glPushName(v3); glBegin(GL_LINES); } if (drawInSurfaceEditColor) { glColor3ubv(surfaceEditDrawColor); } else { glColor4ubv(bs->getNodeColor(modelNumber, v2)); } glVertex3fv(cf->getCoordinate(v2)); if (drawInSurfaceEditColor) { glColor3ubv(surfaceEditDrawColor); } else { glColor4ubv(bs->getNodeColor(modelNumber, v3)); } glVertex3fv(cf->getCoordinate(v3)); if (idLinkMode) { glEnd(); glPopName(); glPopName(); glPopName(); } } if (drawV1 && drawV3) { if (idLinkMode) { glPushName(SELECTION_MASK_LINK); glPushName(v1); glPushName(v3); glBegin(GL_LINES); } if (drawInSurfaceEditColor) { glColor3ubv(surfaceEditDrawColor); } else { glColor4ubv(bs->getNodeColor(modelNumber, v1)); } glVertex3fv(cf->getCoordinate(v1)); if (drawInSurfaceEditColor) { glColor3ubv(surfaceEditDrawColor); } else { glColor4ubv(bs->getNodeColor(modelNumber, v3)); } glVertex3fv(cf->getCoordinate(v3)); if (idLinkMode) { glEnd(); glPopName(); glPopName(); glPopName(); } } } if (idLinkMode == false) { glEnd(); } } /** * Draw the surface as links with hidden line removal. * From page 585 of OpenGL Programming Guide Version 1.2. */ /* void BrainModelOpenGL::drawSurfaceLinksNoBackside(const BrainModelSurfaceNodeColoring* bs, const int modelNumber, const CoordinateFile* cf, const TopologyFile* tf, const int numTiles) { glDisable(GL_LIGHTING); glDisable(GL_COLOR_MATERIAL); BrainSetNodeAttribute* attributes = brainSet->getNodeAttributes(0); DisplaySettingsSurface* dsn = brainSet->getDisplaySettingsSurface(); glLineWidth(getValidLineWidth(dsn->getLinkSize())); // // First, draw as wireframe // glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); for (int i = 0; i < numTiles; i++) { int v1, v2, v3; tf->getTile(i, v1, v2, v3); if (attributes[v1].getDisplayFlag() || attributes[v2].getDisplayFlag() || attributes[v3].getDisplayFlag()) { glBegin(GL_POLYGON); glColor4ubv(bs->getNodeColor(modelNumber, v1)); glVertex3fv(cf->getCoordinate(v1)); glColor4ubv(bs->getNodeColor(modelNumber, v2)); glVertex3fv(cf->getCoordinate(v2)); glColor4ubv(bs->getNodeColor(modelNumber, v3)); glVertex3fv(cf->getCoordinate(v3)); glEnd(); } } glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); // // set background color // unsigned char rb, gb, bb; PreferencesFile* pref = brainSet->getPreferencesFile(); pref->getSurfaceBackgroundColor(rb, gb, bb); glColor3ub(rb, gb, bb); // // Now draw with tiles to hide the "hidden" portion // glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(1.0, 1.0); // glLineWidth(getValidLineWidth(1.0)); for (int i = 0; i < numTiles; i++) { int v1, v2, v3; tf->getTile(i, v1, v2, v3); if (attributes[v1].getDisplayFlag() || attributes[v2].getDisplayFlag() || attributes[v3].getDisplayFlag()) { glBegin(GL_POLYGON); glVertex3fv(cf->getCoordinate(v1)); glVertex3fv(cf->getCoordinate(v2)); glVertex3fv(cf->getCoordinate(v3)); glEnd(); } } glDisable(GL_POLYGON_OFFSET_FILL); } */ /** * Draw the surface as tiles, possibly with lighting. */ void BrainModelOpenGL::drawSurfaceTiles(const BrainModelSurfaceNodeColoring* bs, const BrainModelSurface* s, const CoordinateFile* cf, TopologyFile* tf, const int numTiles, const int numCoords) { // // Enable opacity // const DisplaySettingsSurface* dsn = brainSet->getDisplaySettingsSurface(); if (dsn->getOpacity() < 1.0) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } const BrainSetNodeAttribute* attributes = brainSet->getNodeAttributes(0); const int modelNumber = s->getBrainModelIndex(); glDisable(GL_LIGHTING); glDisable(GL_COLOR_MATERIAL); bool partialLighting = false; // // Do not light a flat surface // if ((s->getSurfaceType() != BrainModelSurface::SURFACE_TYPE_FLAT) && (s->getSurfaceType() != BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR)) { glEnable(GL_LIGHTING); glEnable(GL_COLOR_MATERIAL); int numLightsOn = 0; for (int i = 0; i < brainSet->getNumberOfSurfaceOverlays(); i++) { if (brainSet->getSurfaceOverlay(i)->getLightingEnabled()) { numLightsOn++; } } if (numLightsOn > 0) { if (numLightsOn < brainSet->getNumberOfSurfaceOverlays()) { partialLighting = true; } } else { glDisable(GL_LIGHTING); glDisable(GL_COLOR_MATERIAL); } } if (selectionMask & SELECTION_MASK_TILE) { // // Set partialLighting so that each tile is drawn individually and push the mask // partialLighting = true; glPushName(SELECTION_MASK_TILE); } #ifdef GL_VERSION_1_1 glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glVertexPointer(3, GL_FLOAT, 0, cf->getCoordinate(0)); glColorPointer(4, GL_UNSIGNED_BYTE, 0, bs->getNodeColor(modelNumber, 0)); glNormalPointer(GL_FLOAT, 0, s->getNormal(0)); #endif // GL_VERSION_1_1 if (partialLighting) { static std::vector lightNodeFlag; if (numCoords != static_cast(lightNodeFlag.size())) { lightNodeFlag.resize(numCoords); } for (int j = 0; j < numCoords; j++) { lightNodeFlag[j] = false; const int nodeOverlayIndex = bs->getNodeColorSource(modelNumber, j); if (nodeOverlayIndex >= 0) { if (brainSet->getSurfaceOverlay(nodeOverlayIndex)->getLightingEnabled()) { lightNodeFlag[j] = true; } } } for (int k = 0; k < 2; k++) { if (k == 1) { glDisable(GL_LIGHTING); glDisable(GL_COLOR_MATERIAL); } for (int i = 0; i < numTiles; i++) { int v1, v2, v3; tf->getTile(i, v1, v2, v3); if (attributes[v1].getDisplayFlag() || attributes[v2].getDisplayFlag() || attributes[v3].getDisplayFlag()) { bool drawIt = false; if (k == 0) { if (lightNodeFlag[v1] && lightNodeFlag[v2] && lightNodeFlag[v3]) { drawIt = true; } } else { if ((lightNodeFlag[v1] == false) || (lightNodeFlag[v2] == false) || (lightNodeFlag[v3] == false)) { drawIt = true; } } if (drawIt) { if (selectionMask & SELECTION_MASK_TILE) { glPushName(i); } #ifdef GL_VERSION_1_1 unsigned int triangle[3] = { v1, v2, v3 }; glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, static_cast(triangle)); #else // GL_VERSION_1_1 glBegin(GL_TRIANGLES); glColor4ubv(bs->getNodeColor(modelNumber, v1)); glNormal3fv(s->getNormal(v1)); glVertex3fv(cf->getCoordinate(v1)); glColor4ubv(bs->getNodeColor(modelNumber, v2)); glNormal3fv(s->getNormal(v2)); glVertex3fv(cf->getCoordinate(v2)); glColor4ubv(bs->getNodeColor(modelNumber, v3)); glNormal3fv(s->getNormal(v3)); glVertex3fv(cf->getCoordinate(v3)); glEnd(); #endif // GL_VERSION_1_1 if (selectionMask & SELECTION_MASK_TILE) { glPopName(); } } } } } } else { #ifdef GL_VERSION_1_1 if (brainSet->getDisplayAllNodes()) { glDrawElements(GL_TRIANGLES, (3 * numTiles), GL_UNSIGNED_INT, static_cast(tf->getTile(0))); } else { for (int i = 0; i < numTiles; i++) { const int* theTile = tf->getTile(i); if (attributes[theTile[0]].getDisplayFlag() || attributes[theTile[1]].getDisplayFlag() || attributes[theTile[2]].getDisplayFlag()) { glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, static_cast(theTile)); } } } #else // GL_VERSION_1_1 glBegin(GL_TRIANGLES); for (int i = 0; i < numTiles; i++) { unsigned int v1, v2, v3; tf->getTile(i, v1, v2, v3); if (attributes[v1].getDisplayFlag() || attributes[v2].getDisplayFlag() || attributes[v3].getDisplayFlag()) { glColor4ubv(bs->getNodeColor(modelNumber, v1)); glNormal3fv(s->getNormal(v1)); glVertex3fv(cf->getCoordinate(v1)); glColor4ubv(bs->getNodeColor(modelNumber, v2)); glNormal3fv(s->getNormal(v2)); glVertex3fv(cf->getCoordinate(v2)); glColor4ubv(bs->getNodeColor(modelNumber, v3)); glNormal3fv(s->getNormal(v3)); glVertex3fv(cf->getCoordinate(v3)); } } glEnd(); #endif // GL_VERSION_1_1 } glDisable(GL_LIGHTING); glDisable(GL_COLOR_MATERIAL); #ifdef GL_VERSION_1_1 glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); #endif // GL_VERSION_1_1 if (selectionMask & SELECTION_MASK_TILE) { glPopName(); } // // Disable opacity // glDisable(GL_BLEND); glDisable(GL_POLYGON_STIPPLE); } /** * Draw Surface ROI members. */ void BrainModelOpenGL::drawSurfaceROIMembers(const BrainModelSurface* bms, const int numCoords) { const CoordinateFile* cf = bms->getCoordinateFile(); BrainModelSurfaceROINodeSelection* surfaceROI = brainSet->getBrainModelSurfaceRegionOfInterestNodeSelection(); const DisplaySettingsSurface* dsn = brainSet->getDisplaySettingsSurface(); surfaceROI->update(); if (surfaceROI->getDisplaySelectedNodes()) { glPointSize(getValidPointSize(dsn->getNodeSize())); glColor3ub(0, 200, 0); // darker green glBegin(GL_POINTS); for (int i = 0; i < numCoords; i++) { const BrainSetNodeAttribute* bna = brainSet->getNodeAttributes(i); if (bna->getDisplayFlag()) { // node displayed check if (surfaceROI->getNodeSelected(i)) { glVertex3fv(cf->getCoordinate(i)); } } } glEnd(); } } /** * Draw node highlighting. */ void BrainModelOpenGL::drawNodeHighlighting(const BrainModelSurface* bms, const int numCoords) { const CoordinateFile* cf = bms->getCoordinateFile(); DisplaySettingsSurface* dsn = brainSet->getDisplaySettingsSurface(); BrainSetNodeAttribute* attributes = brainSet->getNodeAttributes(0); // // See if node uncertainty should be displayed // const SurfaceShapeFile* ssf = brainSet->getSurfaceShapeFile(); const DisplaySettingsSurfaceShape* dsss = brainSet->getDisplaySettingsSurfaceShape(); int shapeColumn = -1; if (dsss->getNodeUncertaintyEnabled()) { shapeColumn = dsss->getNodeUncertaintyColumn(); if (shapeColumn >= ssf->getNumberOfColumns()) { shapeColumn = -1; } } if (shapeColumn >= 0) { glEnable(GL_LIGHTING); glEnable(GL_COLOR_MATERIAL); } // // Show node highlighting // glPointSize(getValidPointSize(3.0 * dsn->getNodeSize())); for (int i = 0; i < numCoords; i++) { if (attributes[i].getDisplayFlag()) { BrainSetNodeAttribute* bna = brainSet->getNodeAttributes(i); const float* xyz = cf->getCoordinate(i); bool drawIt = false; if ((bna->getHighlighting() == BrainSetNodeAttribute::HIGHLIGHT_NODE_LOCAL) || (bna->getHighlighting() == BrainSetNodeAttribute::HIGHLIGHT_NODE_REMOTE)) { glColor3ub(0, 255, 0); drawIt = true; switch (dsn->getIdentifyNodeColor()) { case DisplaySettingsSurface::IDENTIFY_NODE_COLOR_BLACK: glColor3ub(0, 0, 0); break; case DisplaySettingsSurface::IDENTIFY_NODE_COLOR_BLUE: glColor3ub(0, 0, 255); break; case DisplaySettingsSurface::IDENTIFY_NODE_COLOR_GREEN: glColor3ub(0, 255, 0); break; case DisplaySettingsSurface::IDENTIFY_NODE_COLOR_RED: glColor3ub(255, 0, 0); break; case DisplaySettingsSurface::IDENTIFY_NODE_COLOR_WHITE: glColor3ub(255, 255, 255); break; } } //else if (bna->getHighlighting() == BrainSetNodeAttribute::HIGHLIGHT_NODE_REMOTE) { // glColor3ub(0, 0, 255); // drawIt = true; //} if (drawIt) { if (shapeColumn >= 0) { const float radius = fabs(ssf->getValue(i, shapeColumn)) * 2.0; // sphere radius is 0.5 glPushMatrix(); glTranslatef(xyz[0], xyz[1], xyz[2]); drawSphere(radius); glPopMatrix(); } else { glBegin(GL_POINTS); glVertex3fv(xyz); glEnd(); } } } } glDisable(GL_LIGHTING); glDisable(GL_COLOR_MATERIAL); const int crossNode = brainSet->getDisplayCrossForNode(); if ((crossNode > 0) && (crossNode < numCoords) && (offScreenRenderingFlag == false)) { bool showCross = true; const BrainModelSurface* idSurface = brainSet->getDisplayCrossSurface(); // // Avoid showing cross on surface that was used for the ID selection // if (idSurface == bms) { showCross = false; } //if (idSurface->getCoordinateFile() == cf) { // showCross = false; //} if (showCross) { glDisable(GL_DEPTH_TEST); glPushMatrix(); const float gap = 10.0; const float lineLength = 500.0; const float* pos = cf->getCoordinate(crossNode); glColor3ub(0, 0, 255); glBegin(GL_LINES); glVertex3f(pos[0] + gap, pos[1], pos[2]); glVertex3f(pos[0] + lineLength, pos[1], pos[2]); glVertex3f(pos[0] - gap, pos[1], pos[2]); glVertex3f(pos[0] - lineLength, pos[1], pos[2]); glVertex3f(pos[0], pos[1] + gap, pos[2]); glVertex3f(pos[0], pos[1] + lineLength, pos[2]); glVertex3f(pos[0], pos[1] - gap, pos[2]); glVertex3f(pos[0], pos[1] - lineLength, pos[2]); glVertex3f(pos[0], pos[1], pos[2] + gap); glVertex3f(pos[0], pos[1], pos[2] + lineLength); glVertex3f(pos[0], pos[1], pos[2] - gap); glVertex3f(pos[0], pos[1], pos[2] - lineLength); glEnd(); glPopMatrix(); glEnable(GL_DEPTH_TEST); } } } /** * Draw the surface normals */ void BrainModelOpenGL::drawSurfaceNormals(const BrainModelSurface* bms, const CoordinateFile* cf, const int numCoords) { const BrainSetNodeAttribute* attributes = brainSet->getNodeAttributes(0); const float length = 10.0; glLineWidth(getValidLineWidth(1.0)); glBegin(GL_LINES); glColor3ub(255, 0, 0); for (int i = 0; i < numCoords; i++) { if (attributes[i].getDisplayFlag()) { const float* pos = cf->getCoordinate(i); const float* normal = bms->getNormal(i); float vect[3] = { pos[0] + length * normal[0], pos[1] + length * normal[1], pos[2] + length * normal[2] }; glVertex3fv(pos); glVertex3fv(vect); } } glEnd(); } /** * Draw a transformation cell or foci file */ void BrainModelOpenGL::drawTransformationCellOrFociFile(BrainModel* bm, CellFile* cellFile, ColorFile* colorFile, const DisplaySettingsCells* dsc, const int transformFileNumber, const int dataSelectionMask) { // // Set color for cells/foci with missing colors // unsigned char noColorRed, noColorGreen, noColorBlue; PreferencesFile* pref = brainSet->getPreferencesFile(); pref->getSurfaceForegroundColor(noColorRed, noColorGreen, noColorBlue); // // Check for selection mode // bool selectFlag = false; if (selectionMask & dataSelectionMask) { glPushName(dataSelectionMask); glPushName(transformFileNumber); selectFlag = true; } if ((selectFlag == false) && (selectionMask != SELECTION_MASK_OFF)) { return; } // // Draw cells larger when selecting on a flat surface // float cellSize = dsc->getDrawSize(); const int numCells = cellFile->getNumberOfCells(); if (numCells > 0) { const int numColors = colorFile->getNumberOfColors(); for (int i = 0; i < numCells; i++) { CellData* cd = cellFile->getCell(i); ColorFile::ColorStorage::SYMBOL symbol = ColorFile::ColorStorage::SYMBOL_OPENGL_POINT; const int colorIndex = cd->getColorIndex(); float pointSize = 1; float lineSize = 1; unsigned char r = noColorRed, g = noColorGreen, b = noColorBlue, alpha = 255; if ((colorIndex >= 0) && (colorIndex < numColors)) { const ColorFile::ColorStorage* cs = colorFile->getColor(colorIndex); symbol = cs->getSymbol(); cs->getRgba(r, g, b, alpha); lineSize = cs->getLineSize(); pointSize = cs->getPointSize(); } float size = pointSize * cellSize; //if (cd->getSize() > 0.0) { // size *= cd->getSize(); //} const float* xyz = cd->getXYZ(); glColor4ub(r, g, b, alpha); float z = xyz[2]; if (selectFlag) { glPushName(i); } if (dsc->getSymbolOverride() != ColorFile::ColorStorage::SYMBOL_NONE) { symbol = dsc->getSymbolOverride(); } if (alpha < 255) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } drawSymbol(symbol, xyz[0], xyz[1], z, size, bm); if (selectFlag) { glPopName(); } } glDisable(GL_BLEND); glDisable(GL_LIGHTING); glDisable(GL_COLOR_MATERIAL); } if (selectFlag) { glPopName(); glPopName(); } } /** * draw a symbol. */ void BrainModelOpenGL::drawSymbol(const ColorFile::ColorStorage::SYMBOL symbol, const float x, const float y, const float z, const float sizeIn, const BrainModel* bm) { bool surfaceFlag = false; if (bm != NULL) { if (dynamic_cast(bm) != NULL) { surfaceFlag = true; } } // // Need lighting // glEnable(GL_LIGHTING); glEnable(GL_COLOR_MATERIAL); float size = sizeIn; switch (symbol) { case ColorFile::ColorStorage::SYMBOL_OPENGL_POINT: // // No lighting for OpenGL Points // glDisable(GL_LIGHTING); glDisable(GL_COLOR_MATERIAL); // // Points must be at least 1.0 for OpenGL to draw something // size = std::max(size, 1.0f); glPointSize(getValidPointSize(size)); glBegin(GL_POINTS); glVertex3f(x, y, z); glEnd(); break; case ColorFile::ColorStorage::SYMBOL_SPHERE: glPushMatrix(); glTranslatef(x, y, z); drawSphere(size); glPopMatrix(); break; case ColorFile::ColorStorage::SYMBOL_BOX: glPushMatrix(); glTranslatef(x, y, z); glScalef(size, size, size); drawBox(); glPopMatrix(); break; case ColorFile::ColorStorage::SYMBOL_DIAMOND: glPushMatrix(); glTranslatef(x, y, z); glScalef(size, size, size); drawDiamond(); glPopMatrix(); break; case ColorFile::ColorStorage::SYMBOL_DISK: glPushMatrix(); { glTranslatef(x, y, z); // // Undo Rotation // if (surfaceFlag) { float matrix[16]; bm->getRotationMatrixInverse(viewingWindowNumber, matrix); glMultMatrixf(matrix); } drawDisk(size); } glPopMatrix(); break; case ColorFile::ColorStorage::SYMBOL_RING: glPushMatrix(); { glTranslatef(x, y, z); // // Undo Rotation // if (surfaceFlag) { float matrix[16]; bm->getRotationMatrixInverse(viewingWindowNumber, matrix); glMultMatrixf(matrix); } glScalef(size, size, size); drawRing(); } glPopMatrix(); break; case ColorFile::ColorStorage::SYMBOL_NONE: break; case ColorFile::ColorStorage::SYMBOL_SQUARE: glPushMatrix(); { glTranslatef(x, y, z); // // Undo Rotation // if (surfaceFlag) { float matrix[16]; bm->getRotationMatrixInverse(viewingWindowNumber, matrix); glMultMatrixf(matrix); } glScalef(size, size, size); drawSquare(); } glPopMatrix(); break; } } /** * Draw cell projection and foci projections. */ void BrainModelOpenGL::drawCellAndFociProjections(BrainModelSurface* s) { DisplaySettingsCells* dsc = brainSet->getDisplaySettingsCells(); if (dsc->getDisplayCells()) { drawCellOrFociProjectionFile(s, brainSet->getCellProjectionFile(), brainSet->getCellColorFile(), dsc, false); } DisplaySettingsFoci* dsf = brainSet->getDisplaySettingsFoci(); if (dsf->getDisplayCells()) { drawCellOrFociProjectionFile(s, brainSet->getFociProjectionFile(), brainSet->getFociColorFile(), dsf, true); } } /** * Draw a cell or foci projection file */ void BrainModelOpenGL::drawCellOrFociProjectionFile(BrainModelSurface* bms, CellProjectionFile* cellProjectionFile, ColorFile* colorFile, const DisplaySettingsCells* dsc, const bool fociFileFlag) { const bool flatFlag = ((bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FLAT) || (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR)); // // Set color for cells/foci with missing colors // unsigned char noColorRed, noColorGreen, noColorBlue; PreferencesFile* pref = brainSet->getPreferencesFile(); pref->getSurfaceForegroundColor(noColorRed, noColorGreen, noColorBlue); // // Check for selection mode (transform cell files have negative fileNumber) // bool selectFlag = false; if (fociFileFlag) { if (selectionMask & SELECTION_MASK_FOCUS_PROJECTION) { glPushName(SELECTION_MASK_FOCUS_PROJECTION); selectFlag = true; } } else { if (selectionMask & SELECTION_MASK_CELL_PROJECTION) { glPushName(SELECTION_MASK_CELL_PROJECTION); selectFlag = true; } } if ((selectFlag == false) && (selectionMask != SELECTION_MASK_OFF)) { return; } const Structure::STRUCTURE_TYPE surfaceStructure = bms->getStructure().getType(); bool drawRaised = false; if (flatFlag) { if (dsc->getDisplayFlatCellsRaised()) { drawRaised = true; } } else if (fociFileFlag) { if (dsc->getDisplayPasteCellsOnto3D()) { drawRaised = true; } } const float opacity = dsc->getOpacity(); // // Draw cells larger when selecting on a flat surface // float cellSize = dsc->getDrawSize(); if (selectFlag && flatFlag) { cellSize *= 2.0; } // // Check for fiducial surface // const bool fiducialSurfaceFlag = ((bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_RAW) || (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FIDUCIAL)); const int numCells = cellProjectionFile->getNumberOfCellProjections(); if (numCells > 0) { // // If backfaces are on with opacity, one can get foci that are // half dark and half light // glEnable(GL_CULL_FACE); glCullFace(GL_BACK); const int numColors = colorFile->getNumberOfColors(); const CoordinateFile* cf = bms->getCoordinateFile(); const TopologyFile* tf = bms->getTopologyFile(); for (int i = 0; i < numCells; i++) { CellProjection* cp = cellProjectionFile->getCellProjection(i); if (cp->getDisplayFlag() == false) { continue; } // // Skip cells/foci with invalid structures // const Structure::STRUCTURE_TYPE cellStructure = cp->getCellStructure(); if ((cellStructure == Structure::STRUCTURE_TYPE_INVALID) || (surfaceStructure == Structure::STRUCTURE_TYPE_INVALID)) { continue; } // // Using cell structure, determine on which surfaces the // cells should be displayed // // From DVE 28 FEB 2008 // In the Foci Main page, when 'show foci on correct hemisphere only' // is selected, all cerebellar foci should be displayed only on the // cerebellum; Cerebellum_Left-Cerebral or Cerebellum_Right-Cerebral // should be displayed on both the cerebellum and the appropriate // cerebral hemisphere. If 'show foci on correct hemisphere only' // is DE-selected, the cerebellar foci should still be shown ONLY on // the cerebellum. // // bool displayOnLeftSurface = false; bool displayOnRightSurface = false; bool displayOnCerebellumSurface = false; switch (cellStructure) { case Structure::STRUCTURE_TYPE_CORTEX_LEFT: displayOnLeftSurface = true; if (dsc->getDisplayCellsOnCorrectHemisphereOnly() == false) { displayOnRightSurface = true; } break; case Structure::STRUCTURE_TYPE_CORTEX_LEFT_OR_CEREBELLUM: if (dsc->getDisplayCellsOnCorrectHemisphereOnly()) { displayOnLeftSurface = true; } break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT: displayOnRightSurface = true; if (dsc->getDisplayCellsOnCorrectHemisphereOnly() == false) { displayOnLeftSurface = true; } break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT_OR_CEREBELLUM: if (dsc->getDisplayCellsOnCorrectHemisphereOnly()) { displayOnRightSurface = true; } break; case Structure::STRUCTURE_TYPE_CORTEX_BOTH: break; case Structure::STRUCTURE_TYPE_CEREBELLUM: displayOnCerebellumSurface = true; break; case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_LEFT: if (dsc->getDisplayCellsOnCorrectHemisphereOnly()) { displayOnCerebellumSurface = true; } break; case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_RIGHT: if (dsc->getDisplayCellsOnCorrectHemisphereOnly()) { displayOnCerebellumSurface = true; } break; case Structure::STRUCTURE_TYPE_CEREBRUM_CEREBELLUM: case Structure::STRUCTURE_TYPE_SUBCORTICAL: case Structure::STRUCTURE_TYPE_ALL: case Structure::STRUCTURE_TYPE_INVALID: break; } // // Skip over foci inappropriate for surface structure // switch (surfaceStructure) { case Structure::STRUCTURE_TYPE_CORTEX_LEFT: if (displayOnLeftSurface == false) { continue; } break; case Structure::STRUCTURE_TYPE_CORTEX_LEFT_OR_CEREBELLUM: continue; break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT: if (displayOnRightSurface == false) { continue; } break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT_OR_CEREBELLUM: continue; break; case Structure::STRUCTURE_TYPE_CORTEX_BOTH: if ((displayOnLeftSurface == false) && (displayOnRightSurface == false)) { } break; case Structure::STRUCTURE_TYPE_CEREBELLUM: if (displayOnCerebellumSurface == false) { continue; } break; case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_LEFT: continue; break; case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_RIGHT: continue; break; case Structure::STRUCTURE_TYPE_CEREBRUM_CEREBELLUM: case Structure::STRUCTURE_TYPE_SUBCORTICAL: case Structure::STRUCTURE_TYPE_ALL: case Structure::STRUCTURE_TYPE_INVALID: continue; break; } ColorFile::ColorStorage::SYMBOL symbol = ColorFile::ColorStorage::SYMBOL_OPENGL_POINT; const int colorIndex = cp->getColorIndex(); float pointSize = 1; float lineSize = 1; unsigned char r = noColorRed, g = noColorGreen, b = noColorBlue, alpha = 255; if ((colorIndex >= 0) && (colorIndex < numColors)) { const ColorFile::ColorStorage* cs = colorFile->getColor(colorIndex); symbol = cs->getSymbol(); cs->getRgba(r, g, b, alpha); lineSize = cs->getLineSize(); pointSize = cs->getPointSize(); } float size = pointSize * cellSize; // // Double size for highlighting // if (cp->getHighlightFlag()) { size *= 2.0; } float xyz[3]; if (cp->getProjectedPosition(cf, tf, fiducialSurfaceFlag, flatFlag, drawRaised, xyz) == false) { // // No position available // continue; } // // Use display setting's opacity // if ((opacity >= 0.0) && (opacity < 1.0)) { alpha = static_cast(alpha * opacity); } glColor4ub(r, g, b, alpha); float z = xyz[2]; if (selectFlag) { glPushName(i); } if (dsc->getSymbolOverride() != ColorFile::ColorStorage::SYMBOL_NONE) { symbol = dsc->getSymbolOverride(); } if (alpha < 255) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } drawSymbol(symbol, xyz[0], xyz[1], z, size, bms); if (selectFlag) { glPopName(); } } glDisable(GL_CULL_FACE); glDisable(GL_BLEND); glDisable(GL_LIGHTING); glDisable(GL_COLOR_MATERIAL); } if (selectFlag) { glPopName(); } } /** * draw the geodesic path. */ void BrainModelOpenGL::drawGeodesicPath(const CoordinateFile* cf) { DisplaySettingsGeodesicDistance* dsgd = brainSet->getDisplaySettingsGeodesicDistance(); GeodesicDistanceFile* gdf = brainSet->getGeodesicDistanceFile(); const int column = dsgd->getDisplayColumn(); if ((column < 0) || (column >= gdf->getNumberOfColumns())) { return; } const int rootNode = gdf->getRootNode(column); if ((rootNode < 0) || (rootNode >= cf->getNumberOfCoordinates())) { return; } const float* coords = cf->getCoordinate(0); const ColorFile* colorFile = brainSet->getAreaColorFile(); if (dsgd->getShowRootNode()) { unsigned char r = 255, g = 0, b = 0; bool match; colorFile->getColorByName("GEODESIC_SYMBOL", match, r, g, b); glColor3ub(r, g, b); glEnable(GL_LIGHTING); glEnable(GL_COLOR_MATERIAL); glPushMatrix(); glTranslatef(coords[rootNode*3], coords[rootNode*3+1], coords[rootNode*3+2]); drawSphere(5.0); glPopMatrix(); glDisable(GL_LIGHTING); glDisable(GL_COLOR_MATERIAL); } if (dsgd->getPathDisplayEnabled()) { int node = dsgd->getPathDisplayNodeNumber(); const int numCoord = cf->getNumberOfCoordinates(); if ((node >= 0) && (node < numCoord)) { const float* coords = cf->getCoordinate(0); glLineWidth(getValidLineWidth(dsgd->getPathLineWidth())); unsigned char r = 0, g = 255, b = 255; bool match; colorFile->getColorByName("GEODESIC_PATH", match, r, g, b); glColor3ub(r, g, b); glBegin(GL_LINE_STRIP); bool done = false; while (done == false) { const int parent = gdf->getNodeParent(node, column); if ((parent == node) || (node == rootNode)) { done = true; } else if (parent == -1) { done = true; } glVertex3fv(&coords[parent*3]); node = parent; } glEnd(); } } } /** * Draw a cuts file. */ void BrainModelOpenGL::drawCuts() { // // Only show cuts in main window // if (mainWindowFlag == false) { return; } DisplaySettingsCuts* dsc = brainSet->getDisplaySettingsCuts(); if (dsc->getDisplayCuts() == false) { return; } BorderFile* bf = brainSet->getCutsFile(); // // Check for selection mode // bool selectFlag = false; if (selectionMask & SELECTION_MASK_CUT) { glPushName(SELECTION_MASK_CUT); selectFlag = true; } if ((selectFlag == false) && (selectionMask != SELECTION_MASK_OFF)) { return; } const int numBorders = bf->getNumberOfBorders(); if (numBorders > 0) { glColor3f(0.0, 0.0, 1.0); for (int i = 0; i < numBorders; i++) { Border* b = bf->getBorder(i); const int numLinks = b->getNumberOfLinks(); if ((numLinks > 0) && b->getDisplayFlag()) { const float pointSize = 2; if (selectFlag) { glPushName(i); glPointSize(getValidPointSize(pointSize)); for (int j = 0; j < numLinks; j++) { glPushName(j); glBegin(GL_POINTS); float xyz[3]; b->getLinkXYZ(j, xyz); xyz[2] = 1.0; glVertex3fv(xyz); glEnd(); glPopName(); } glPopName(); } else { glPointSize(getValidPointSize(pointSize)); glBegin(GL_POINTS); float xyz[3]; for (int j = 0; j < numLinks; j++) { b->getLinkXYZ(j, xyz); xyz[2] = 1.0; glVertex3fv(xyz); } glEnd(); } } } } if (selectFlag) { glPopName(); } } /** * Draw the borders. */ void BrainModelOpenGL::drawBorders(BrainModelSurface* s) { DisplaySettingsBorders* dsb = brainSet->getDisplaySettingsBorders(); if (dsb->getDisplayBorders() == false) { return; } bool flatFlag = false; switch(s->getSurfaceType()) { case BrainModelSurface::SURFACE_TYPE_RAW: break; case BrainModelSurface::SURFACE_TYPE_FIDUCIAL: break; case BrainModelSurface::SURFACE_TYPE_INFLATED: break; case BrainModelSurface::SURFACE_TYPE_VERY_INFLATED: break; case BrainModelSurface::SURFACE_TYPE_SPHERICAL: break; case BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL: break; case BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL: break; case BrainModelSurface::SURFACE_TYPE_FLAT: flatFlag = true; break; case BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR: flatFlag = true; break; case BrainModelSurface::SURFACE_TYPE_HULL: break; case BrainModelSurface::SURFACE_TYPE_UNKNOWN: break; case BrainModelSurface::SURFACE_TYPE_UNSPECIFIED: break; } const int brainModelIndex = brainSet->getBrainModelIndex(s); if (brainModelIndex < 0) { std::cout << "PROGRAM ERROR: invalid brain model index at " << __LINE__ << " in " << __FILE__ << std::endl; return; } // // Set color for borders with missing colors // unsigned char noColorRed, noColorGreen, noColorBlue; PreferencesFile* pref = brainSet->getPreferencesFile(); pref->getSurfaceForegroundColor(noColorRed, noColorGreen, noColorBlue); // // Check for selection mode // bool selectFlag = false; if (selectionMask & SELECTION_MASK_BORDER) { glPushName(SELECTION_MASK_BORDER); glPushName(brainModelIndex); selectFlag = true; } if ((selectFlag == false) && (selectionMask != SELECTION_MASK_OFF)) { return; } bool drawRaised = false; if (flatFlag && dsb->getDisplayFlatBordersRaised()) { drawRaised = true; } ColorFile* areaColorFile = brainSet->getAreaColorFile(); const int numAreaColors = areaColorFile->getNumberOfColors(); ColorFile* borderColorFile = brainSet->getBorderColorFile(); const int numBorderColors = borderColorFile->getNumberOfColors(); // // Draw borders larger when selecting on a flat surface // float drawSize = dsb->getDrawSize(); if (selectFlag && flatFlag) { drawSize *= 2.0; } const float stretchFactorSquared = dsb->getDrawAsStretchedLinesStretchFactor() * dsb->getDrawAsStretchedLinesStretchFactor(); BrainModelBorderSet* bmbs = brainSet->getBorderSet(); const int numBorders = bmbs->getNumberOfBorders(); const bool overrideWithAreaColorsFlag = dsb->getOverrideBorderColorsWithAreaColors(); const float opacity = dsb->getOpacity(); unsigned char alpha = 255; if ((opacity >= 0.0) && (opacity < 1.0)) { alpha = static_cast(opacity * 255.0); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } for (int i = 0; i < numBorders; i++) { const BrainModelBorder* b = bmbs->getBorder(i); if (b->getValidForBrainModel(brainModelIndex) && b->getDisplayFlag()) { const int numLinks = b->getNumberOfBorderLinks(); if ((numLinks > 0) && b->getDisplayFlag()) { const int borderColorIndex = b->getBorderColorFileIndex(); const int areaColorIndex = b->getAreaColorFileIndex(); float pointSize = 1; float lineSize = 1; unsigned char red = 0, green = 0, blue = 0; if (overrideWithAreaColorsFlag && ((areaColorIndex >= 0) && (areaColorIndex < numAreaColors))) { areaColorFile->getColorByIndex(areaColorIndex, red, green, blue); if ((borderColorIndex >= 0) && (borderColorIndex < numBorderColors)) { borderColorFile->getPointLineSizeByIndex(borderColorIndex, pointSize, lineSize); } } else if ((borderColorIndex >= 0) && (borderColorIndex < numBorderColors)) { borderColorFile->getColorByIndex(borderColorIndex, red, green, blue); borderColorFile->getPointLineSizeByIndex(borderColorIndex, pointSize, lineSize); } else { red = noColorRed; green = noColorGreen; blue = noColorBlue; } // // Double size if highlighted // if (b->getHighlightFlag()) { pointSize *= 2.0; lineSize *= 2.0; } const ColorFile::ColorStorage::SYMBOL symbol = dsb->getSymbolType(); if (selectFlag) { glPushName(i); for (int j = 0; j < numLinks; j++) { const BrainModelBorderLink* link = b->getBorderLink(j); glPushName(j); float xyz[3]; link->getLinkPosition(brainModelIndex, xyz); if (drawRaised) { xyz[2] = 1.0; } drawSymbol(symbol, xyz[0], xyz[1], xyz[2], pointSize*drawSize, s); glPopName(); } glPopName(); glDisable(GL_LIGHTING); // get turned on when drawing symbols glDisable(GL_COLOR_MATERIAL); } else { if ((dsb->getDrawMode() == DisplaySettingsBorders::BORDER_DRAW_AS_SYMBOLS) || (dsb->getDrawMode() == DisplaySettingsBorders::BORDER_DRAW_AS_SYMBOLS_AND_LINES)) { int startLink = 0; if (dsb->getDisplayFirstLinkRed()) { glColor4ub(255, 0, 0, alpha); float xyz[3]; const BrainModelBorderLink* link = b->getBorderLink(0); link->getLinkPosition(brainModelIndex, xyz); if (drawRaised) { xyz[2] = 1.0; } drawSymbol(symbol, xyz[0], xyz[1], xyz[2], pointSize*drawSize, s); startLink = 1; } glColor4ub(red, green, blue, alpha); float xyz[3]; for (int j = startLink; j < numLinks; j++) { const BrainModelBorderLink* link = b->getBorderLink(j); link->getLinkPosition(brainModelIndex, xyz); if (drawRaised) { xyz[2] = 1.0; } drawSymbol(symbol, xyz[0], xyz[1], xyz[2], pointSize*drawSize, s); } glDisable(GL_LIGHTING); // get turned on when drawing symbols glDisable(GL_COLOR_MATERIAL); } if ((dsb->getDrawMode() == DisplaySettingsBorders::BORDER_DRAW_AS_VARIABILITY) || (dsb->getDrawMode() == DisplaySettingsBorders::BORDER_DRAW_AS_VARIABILITY_AND_LINES)) { glEnable(GL_LIGHTING); glEnable(GL_COLOR_MATERIAL); for (int j = 0; j < numLinks; j++) { if ((j == 0) && dsb->getDisplayFirstLinkRed()) { glColor4ub(255, 0, 0, alpha); } else { glColor4ub(red, green, blue, alpha); } const BrainModelBorderLink* link = b->getBorderLink(j); const float radius = link->getRadius(); if (radius > 0.0) { glPushMatrix(); float xyz[3]; link->getLinkPosition(brainModelIndex, xyz); glTranslatef(xyz[0], xyz[1], xyz[2]); drawSphere(radius); glPopMatrix(); } } glEnable(GL_COLOR_MATERIAL); glDisable(GL_LIGHTING); } if ((dsb->getDrawMode() == DisplaySettingsBorders::BORDER_DRAW_AS_LINES) || (dsb->getDrawMode() == DisplaySettingsBorders::BORDER_DRAW_AS_UNSTRETCHED_LINES) || (dsb->getDrawMode() == DisplaySettingsBorders::BORDER_DRAW_AS_SYMBOLS_AND_LINES) || (dsb->getDrawMode() == DisplaySettingsBorders::BORDER_DRAW_AS_VARIABILITY_AND_LINES)) { // // See if drawing as unstretched lines // bool unstretched = false; if (flatFlag && (dsb->getDrawMode() == DisplaySettingsBorders::BORDER_DRAW_AS_UNSTRETCHED_LINES)) { unstretched = true; } glLineWidth(getValidLineWidth(lineSize * drawSize)); glBegin(GL_LINES); glColor4ub(red, green, blue, alpha); float pos1[3]; float pos2[3]; for (int j = 1; j < numLinks; j++) { const BrainModelBorderLink* link1 = b->getBorderLink(j - 1); const BrainModelBorderLink* link2 = b->getBorderLink(j); link1->getLinkPosition(brainModelIndex, pos1); link2->getLinkPosition(brainModelIndex, pos2); if (unstretched) { if (vtkMath::Distance2BetweenPoints(pos1, pos2) > stretchFactorSquared) { continue; } } if (drawRaised) { pos1[2] = 1.0; pos2[2] = 1.0; } glVertex3fv(pos1); glVertex3fv(pos2); } glEnd(); glLineWidth(getValidLineWidth(1.0)); } } if (dsb->getDisplayUncertaintyVectors() && (selectFlag == false)) { float xyz[3]; const float normalLength = b->getArealUncertainty(); glBegin(GL_LINES); for (int j = 0; j < numLinks; j++) { const BrainModelBorderLink* link = b->getBorderLink(j); link->getLinkPosition(brainModelIndex, xyz); if (drawRaised) { xyz[2] = 1.0; } glVertex3fv(xyz); const float* normal = link->getFlatNormal(); xyz[0] += normal[0] * normalLength; xyz[1] += normal[1] * normalLength; xyz[2] = 0.0; glVertex3fv(xyz); } glEnd(); } } } } glDisable(GL_BLEND); if (selectFlag) { glPopName(); glPopName(); } } /** * Draw the Surface Shape colorbar. */ void BrainModelOpenGL::drawShapePalette(const int modelNumber) { // // Check for selection mode // bool selectFlag = false; if (selectionMask & SELECTION_MASK_PALETTE_SHAPE) { selectFlag = true; } else if (selectionMask != SELECTION_MASK_OFF) { return; } DisplaySettingsSurfaceShape* dsss = brainSet->getDisplaySettingsSurfaceShape(); if (dsss->getDisplayColorBar() == false) { return; } SurfaceShapeFile* ssf = brainSet->getSurfaceShapeFile(); if (ssf->getNumberOfColumns() <= 0) { return; } BrainModelSurfaceNodeColoring* bsnc = brainSet->getNodeColoring(); if (brainSet->isASurfaceOverlay(modelNumber, BrainModelSurfaceOverlay::OVERLAY_SURFACE_SHAPE) == false) { return; } glPushMatrix(); glDisable(GL_DEPTH_TEST); glMatrixMode(GL_PROJECTION); // save the projection matrix for the surface GLfloat savedProjectionMatrix[16]; glGetFloatv(GL_PROJECTION_MATRIX, savedProjectionMatrix); // save the viewport GLint savedViewport[4]; glGetIntegerv(GL_VIEWPORT, savedViewport); // // colorbar is in lower right corner of graphics window // const GLint colorbarViewportWidth = static_cast(viewport[2] * 0.25); const GLint colorbarViewportHeight = 50; const GLint colorbarViewportLeft = 10; const int yOffset = 15; // prevent colorbar under resize tab glViewport(colorbarViewportLeft, yOffset, colorbarViewportWidth, colorbarViewportHeight + yOffset); const GLdouble halfWidth = static_cast(colorbarViewportWidth / 2); const GLdouble halfHeight = static_cast(colorbarViewportHeight / 2); glLoadIdentity(); if (selectFlag) { GLint vp[4]; glGetIntegerv(GL_VIEWPORT, vp); gluPickMatrix((GLdouble)selectionX, (GLdouble)(selectionY), //(savedViewport[3] - selectionY), 5.0, 5.0, vp); } const GLdouble margin = 1.1; const GLdouble orthoWidth = halfWidth * margin; const GLdouble orthoHeight = halfHeight * margin; glOrtho(-orthoWidth, orthoWidth, -orthoHeight, orthoHeight, -1.0, 1.0); glMatrixMode (GL_MODELVIEW); glLoadIdentity(); // // set background color // unsigned char rb, gb, bb; PreferencesFile* pref = brainSet->getPreferencesFile(); pref->getSurfaceBackgroundColor(rb, gb, bb); glColor3ub(rb, gb, bb); glRectf(-orthoWidth, -orthoHeight, orthoWidth, orthoHeight); Palette* palette = NULL; bool interpolatePaletteColor = false; switch (dsss->getColorMap()) { case DisplaySettingsSurfaceShape::SURFACE_SHAPE_COLOR_MAP_GRAY: glBegin(GL_POLYGON); glColor3ub(0, 0, 0); glVertex3f(-halfWidth, -halfHeight, 0.0); glVertex3f(-halfWidth, 0.0, 0.0); glColor3ub(255, 255, 255); glVertex3f(halfWidth, 0.0, 0.0); glVertex3f(halfWidth, -halfHeight, 0.0); glEnd(); break; case DisplaySettingsSurfaceShape::SURFACE_SHAPE_COLOR_MAP_ORANGE_YELLOW: { unsigned char lut[256][3]; bsnc->getShapeLookupTable(lut); glPushMatrix(); glTranslatef(-halfWidth, 0.0, 0.0); for (int i = 0; i < 255; i++) { glBegin(GL_POLYGON); glColor3ubv(lut[i]); glVertex3f(((i * halfWidth * 2) / 256.0), -halfHeight, 0.0); glColor3ubv(lut[i+1]); glVertex3f((((i + 1) * halfWidth * 2) / 256.0), -halfHeight, 0.0); glColor3ubv(lut[i+1]); glVertex3f((((i + 1) * halfWidth * 2) / 256.0), 0.0, 0.0); glColor3ubv(lut[i]); glVertex3f(((i * halfWidth * 2) / 256.0), 0.0, 0.0); glEnd(); } glPopMatrix(); } break; case DisplaySettingsSurfaceShape::SURFACE_SHAPE_COLOR_MAP_PALETTE: { PaletteFile* pf = brainSet->getPaletteFile(); if (pf->getNumberOfPalettes() <= 0) { glPopMatrix(); return; } const int paletteNumber = dsss->getSelectedPaletteIndex(); palette = pf->getPalette(paletteNumber); if (palette->getNumberOfPaletteEntries() <= 1) { glPopMatrix(); return; } // // Always interpolate if the palette has only two colors // interpolatePaletteColor = (dsss->getInterpolatePaletteColors() != 0); if (palette->getNumberOfPaletteEntries() == 2) { interpolatePaletteColor = true; } if (selectFlag) { glPushName(SELECTION_MASK_PALETTE_SHAPE); glPushName(paletteNumber); } // // Draw the colorbar // for (int i = 1; i < palette->getNumberOfPaletteEntries(); i++) { PaletteEntry* lastPE = (PaletteEntry*)palette->getPaletteEntry(i - 1); float lastValue = lastPE->getValue(); const int lastColorIndex = lastPE->getColorIndex(); const PaletteColor* lastColor = pf->getPaletteColor(lastColorIndex); const QString lastName = lastColor->getName(); const bool lastNoneColorFlag = lastColor->isNoneColor(); unsigned char lastRGB[3]; lastColor->getRGB(lastRGB); const PaletteEntry* pe = palette->getPaletteEntry(i); float value = pe->getValue(); const int colorIndex = pe->getColorIndex(); const PaletteColor* color = pf->getPaletteColor(colorIndex); const QString name = color->getName(); unsigned char rgb[3]; color->getRGB(rgb); if (selectFlag) { glPushName(i - 1); } if (lastNoneColorFlag == false) { if (interpolatePaletteColor) { glBegin(GL_POLYGON); glColor3ubv(rgb); glVertex3f(value * halfWidth, -halfHeight, 0.0); glVertex3f(value * halfWidth, 0.0, 0.0); glColor3ubv(lastRGB); glVertex3f(lastValue * halfWidth, 0.0, 0.0); glVertex3f(lastValue * halfWidth, -halfHeight, 0.0); glEnd(); } else { glColor3ubv(lastRGB); glRectf(value * halfWidth, -halfHeight, lastValue * halfWidth, 0.0); } } if (selectFlag) { if (lastNoneColorFlag) { glRectf(value * halfWidth, -halfHeight, lastValue * halfWidth, 0.0); } glPopName(); } lastPE = (PaletteEntry*)pe; // // is this the last palette entry // if (i == (palette->getNumberOfPaletteEntries() - 1)) { if ((value > -1.0) && (value < 0.0)) { if (selectFlag) { glPushName(i); } glColor3ubv(rgb); glRectf(-1.0 * halfWidth, -halfHeight, value * halfWidth, 0.0); if (selectFlag) { glPopName(); } } } } if (selectFlag) { glPopName(); glPopName(); } } break; } if (selectFlag == false) { // // Draw the min/max numbers // GLdouble maxX, minX, winY, winZ; GLdouble modelMatrix[16]; GLdouble projMatrix[16]; GLint viewport[4]; glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix); glGetDoublev(GL_PROJECTION_MATRIX, projMatrix); glGetIntegerv(GL_VIEWPORT, viewport); gluProject(halfWidth, 0.0, 0.0, modelMatrix, projMatrix, viewport, &maxX, &winY, &winZ); gluProject(-halfWidth, 0.0, 0.0, modelMatrix, projMatrix, viewport, &minX, &winY, &winZ); float minShape = -1.0; float maxShape = 1.0; const int col = dsss->getShapeColumnForPaletteAndColorMapping(); if (col < 0) { return; } ssf->getColumnColorMappingMinMax(col, minShape, maxShape); // // do everything in pixel display // glViewport(0, 0, viewport[2], viewport[3]); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0.0, viewport[2], 0.0, viewport[3], -1.0, 1.0); glMatrixMode (GL_MODELVIEW); PreferencesFile* pf = brainSet->getPreferencesFile(); unsigned char rf, gf, bf; pf->getSurfaceForegroundColor(rf, gf, bf); glColor3ub(rf, gf, bf); if (glWidget != NULL) { // // Font for drawing numbers // const int fontHeight = 12; QFont font("times", fontHeight); QFontMetrics fontMetrics(font); const double fontY = winY + (fontHeight * 0.75) - 5; // // draw minimum numbers // const double minFontX = minX; QString qs(QString::number(minShape, 'f', 2)); if (glWidget != NULL) { glWidget->renderText(minFontX, fontY, 0.0, qs, font); } // // draw maximum numbers // qs = QString::number(maxShape, 'f', 2); const double maxFontX = maxX - fontMetrics.width(qs); if (glWidget != NULL) { glWidget->renderText(maxFontX, fontY, 0.0, qs, font); } if (palette != NULL) { if ((palette->getNumberOfPaletteEntries() == 2) && interpolatePaletteColor) { // nothing } else { // // draw 0.0 // const QString qs("0.0"); const double fontX = (minX + maxX)*0.5 - fontMetrics.width(qs) * 0.5; if (glWidget != NULL) { glWidget->renderText(fontX, fontY, 0.0, qs, font); } } } } glViewport(savedViewport[0], savedViewport[1], savedViewport[2], savedViewport[3]); glMatrixMode(GL_PROJECTION); glLoadMatrixf(savedProjectionMatrix); glMatrixMode(GL_MODELVIEW); glEnable(GL_DEPTH_TEST); glPopMatrix(); } } /** * Draw the metric's palette colorbar. */ void BrainModelOpenGL::drawMetricPalette(const int modelNumber, const bool surfaceFlag) { // // Check for selection mode // bool selectFlag = false; if (selectionMask & SELECTION_MASK_PALETTE_METRIC) { selectFlag = true; } else if (selectionMask != SELECTION_MASK_OFF) { return; } bool displayIt = false; if (surfaceFlag) { if (brainSet->isASurfaceOverlay(modelNumber, BrainModelSurfaceOverlay::OVERLAY_METRIC)) { displayIt = true; } } else if (surfaceFlag == false) { BrainModelVolume* bmv = brainSet->getBrainModelVolume(); if (bmv != NULL) { VolumeFile* vf = bmv->getSelectedVolumeFunctionalViewFile(); if (vf != NULL) { const BrainModelVolumeVoxelColoring* vc = brainSet->getVoxelColoring(); if (vc->isUnderlayOrOverlay(BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_FUNCTIONAL)) { displayIt = true; } } } } if (displayIt) { DisplaySettingsMetric* dsm = brainSet->getDisplaySettingsMetric(); if (surfaceFlag) { if (dsm->getDisplayColorBar() == false) { return; } } else { DisplaySettingsVolume* dsv = brainSet->getDisplaySettingsVolume(); if (dsv->getDisplayColorBar() == false) { return; } } PaletteFile* pf = brainSet->getPaletteFile(); if (pf->getNumberOfPalettes() <= 0) { return; } const int paletteNumber = dsm->getSelectedPaletteIndex(); const Palette* palette = pf->getPalette(paletteNumber); if (palette->getNumberOfPaletteEntries() <= 1) { return; } MetricFile* mf = brainSet->getMetricFile(); if (surfaceFlag) { if (mf->getNumberOfColumns() <= 0) { return; } } glPushMatrix(); glDisable(GL_DEPTH_TEST); glMatrixMode(GL_PROJECTION); // save the projection matrix for the surface GLfloat savedProjectionMatrix[16]; glGetFloatv(GL_PROJECTION_MATRIX, savedProjectionMatrix); // save the viewport GLint savedViewport[4]; glGetIntegerv(GL_VIEWPORT, savedViewport); // // colorbar is in lower right corner of graphics window // const GLint colorbarViewportWidth = static_cast(viewport[2] * 0.25); const GLint colorbarViewportHeight = 50; const GLint colorbarViewportLeft = viewport[2] - colorbarViewportWidth; const int yOffset = 15; // prevent colorbar under resize tab glViewport(colorbarViewportLeft, yOffset, colorbarViewportWidth, colorbarViewportHeight + yOffset); const GLdouble halfWidth = static_cast(colorbarViewportWidth / 2); const GLdouble halfHeight = static_cast(colorbarViewportHeight / 2); glLoadIdentity(); if (selectFlag) { GLint vp[4]; glGetIntegerv(GL_VIEWPORT, vp); gluPickMatrix((GLdouble)selectionX, (GLdouble)(selectionY), //(savedViewport[3] - selectionY), 5.0, 5.0, vp); } const GLdouble margin = 1.1; const GLdouble orthoWidth = halfWidth * margin; const GLdouble orthoHeight = halfHeight * margin; glOrtho(-orthoWidth, orthoWidth, -orthoHeight, orthoHeight, -1.0, 1.0); glMatrixMode (GL_MODELVIEW); glLoadIdentity(); // // set background color // unsigned char rb, gb, bb; PreferencesFile* pref = brainSet->getPreferencesFile(); pref->getSurfaceBackgroundColor(rb, gb, bb); glColor3ub(rb, gb, bb); glRectf(-orthoWidth, -orthoHeight, orthoWidth, orthoHeight); bool haveNegativeInPalette = false; // // Always interpolate if the palette has only two colors // bool interpolateColor = (dsm->getInterpolateColors() != 0); if (palette->getNumberOfPaletteEntries() == 2) { interpolateColor = true; } if (selectFlag) { glPushName(SELECTION_MASK_PALETTE_METRIC); glPushName(paletteNumber); } // // Draw the colorbar // for (int i = 1; i < palette->getNumberOfPaletteEntries(); i++) { PaletteEntry* lastPE = (PaletteEntry*)palette->getPaletteEntry(i - 1); float lastValue = lastPE->getValue(); const int lastColorIndex = lastPE->getColorIndex(); const PaletteColor* lastColor = pf->getPaletteColor(lastColorIndex); const QString lastName = lastColor->getName(); const bool lastNoneColorFlag = lastColor->isNoneColor(); unsigned char lastRGB[3]; lastColor->getRGB(lastRGB); const PaletteEntry* pe = palette->getPaletteEntry(i); float value = pe->getValue(); const int colorIndex = pe->getColorIndex(); const PaletteColor* color = pf->getPaletteColor(colorIndex); const QString name = color->getName(); unsigned char rgb[3]; color->getRGB(rgb); if (selectFlag) { glPushName(i - 1); } if (lastNoneColorFlag == false) { if (interpolateColor) { glBegin(GL_POLYGON); glColor3ubv(rgb); glVertex3f(value * halfWidth, -halfHeight, 0.0); glVertex3f(value * halfWidth, 0.0, 0.0); glColor3ubv(lastRGB); glVertex3f(lastValue * halfWidth, 0.0, 0.0); glVertex3f(lastValue * halfWidth, -halfHeight, 0.0); glEnd(); } else { glColor3ubv(lastRGB); switch(dsm->getDisplayMode()) { case DisplaySettingsMetric::METRIC_DISPLAY_MODE_POSITIVE_AND_NEGATIVE: glRectf(value * halfWidth, -halfHeight, lastValue * halfWidth, 0.0); break; case DisplaySettingsMetric::METRIC_DISPLAY_MODE_NEGATIVE_ONLY: if (value <= 0.0) { if (lastValue > 0.0) { lastValue = 0.0; } glRectf(value * halfWidth, -halfHeight, lastValue * halfWidth, 0.0); } break; case DisplaySettingsMetric::METRIC_DISPLAY_MODE_POSITIVE_ONLY: if (lastValue >= 0.0) { if (value < 0.0) { value = 0.0; } glRectf(value * halfWidth, -halfHeight, lastValue * halfWidth, 0.0); } break; } } } if (selectFlag) { if (lastNoneColorFlag) { glRectf(value * halfWidth, -halfHeight, lastValue * halfWidth, 0.0); } glPopName(); } lastPE = (PaletteEntry*)pe; if (value < 0) { haveNegativeInPalette = true; } // // is this the last palette entry // if (i == (palette->getNumberOfPaletteEntries() - 1)) { if ((value > -1.0) && (value < 0.0)) { if (dsm->getDisplayMode() != DisplaySettingsMetric::METRIC_DISPLAY_MODE_POSITIVE_ONLY) { if (selectFlag) { glPushName(i); } glColor3ubv(rgb); glRectf(-1.0 * halfWidth, -halfHeight, value * halfWidth, 0.0); if (selectFlag) { glPopName(); } } } } } float posMinMetric = 0.0, posMaxMetric = 0.0, negMinMetric = 0.0, negMaxMetric = 0.0; int displayColumn, thresholdColumn; dsm->getMetricsForColoringAndPalette(displayColumn, thresholdColumn, negMaxMetric, negMinMetric, posMinMetric, posMaxMetric); // // Are thresholds shown in green // if (dsm->getShowSpecialColorForThresholdedNodes()) { if ((thresholdColumn >= 0) && (thresholdColumn < mf->getNumberOfColumns())) { unsigned char negColor[3]; unsigned char posColor[3]; dsm->getSpecialColorsForThresholdedNodes(negColor, posColor); float negThresh, posThresh; mf->getColumnThresholding(thresholdColumn, negThresh, posThresh); if (negThresh < 0.0) { if (negMaxMetric < 0.0) { const float negPct = negThresh / negMaxMetric; glColor3ubv(negColor); glRectf(-negPct * halfWidth, -halfHeight, 0.0, 0.0); } } if (posThresh > 0.0) { if (posMaxMetric > 0.0) { const float posPct = posThresh / posMaxMetric; glColor3ubv(posColor); glRectf(0.0, -halfHeight, posPct * halfWidth, 0.0); } } } } if (selectFlag) { glPopName(); glPopName(); } else if (glWidget != NULL) { // // Draw the min/max numbers // GLdouble maxX, minX, winY, winZ; GLdouble modelMatrix[16]; GLdouble projMatrix[16]; GLint viewport[4]; glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix); glGetDoublev(GL_PROJECTION_MATRIX, projMatrix); glGetIntegerv(GL_VIEWPORT, viewport); gluProject(halfWidth, 0.0, 0.0, modelMatrix, projMatrix, viewport, &maxX, &winY, &winZ); gluProject(-halfWidth, 0.0, 0.0, modelMatrix, projMatrix, viewport, &minX, &winY, &winZ); // // do everything in pixel display // glViewport(0, 0, savedViewport[2], savedViewport[3]); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0.0, savedViewport[2], 0.0, savedViewport[3], -1.0, 1.0); glMatrixMode (GL_MODELVIEW); PreferencesFile* prf = brainSet->getPreferencesFile(); unsigned char rf, gf, bf; prf->getSurfaceForegroundColor(rf, gf, bf); glColor3ub(rf, gf, bf); // // Font for drawing numbers // const int fontHeight = 12; QFont font("times", fontHeight); QFontMetrics fontMetrics(font); const double fontY = winY + (fontHeight * 0.75) - 5; if (dsm->getDisplayMode() != DisplaySettingsMetric::METRIC_DISPLAY_MODE_POSITIVE_ONLY) { // // draw minimum numbers // if (palette->getPositiveOnly() == false) { if ((negMaxMetric < 0.0) && haveNegativeInPalette) { const double minFontX = minX; const QString qs(QString::number(negMaxMetric, 'f', 1)); if (glWidget != NULL) { glWidget->renderText(minFontX, fontY, 0.0, qs, font); } } } } if (dsm->getDisplayMode() != DisplaySettingsMetric::METRIC_DISPLAY_MODE_NEGATIVE_ONLY) { // // draw maximum numbers // if (posMaxMetric > 0.0) { const QString qs(QString::number(posMaxMetric, 'f', 1)); const double maxFontX = maxX - fontMetrics.width(qs); if (glWidget != NULL) { glWidget->renderText(maxFontX, fontY, 0.0, qs, font); } } } if ((palette->getNumberOfPaletteEntries() == 2) && interpolateColor) { // nothing } else { // // Determine if pos and/or neg min should be shown // bool showNeg = false; bool showPos = false; switch (dsm->getDisplayMode()) { case DisplaySettingsMetric::METRIC_DISPLAY_MODE_POSITIVE_AND_NEGATIVE: showNeg = true; if (negMinMetric != posMinMetric) { showPos = true; } break; case DisplaySettingsMetric::METRIC_DISPLAY_MODE_POSITIVE_ONLY: showPos = true; break; case DisplaySettingsMetric::METRIC_DISPLAY_MODE_NEGATIVE_ONLY: showNeg = true; break; } QString qs; if (showNeg) { qs += QString::number(negMinMetric, 'f', 1); } if (showPos) { if (qs.isEmpty() == false) { qs += "/"; } qs += QString::number(posMinMetric, 'f', 1); } const double fontX = (minX + maxX)*0.5 - fontMetrics.width(qs) * 0.5; if (glWidget != NULL) { glWidget->renderText(fontX, fontY, 0.0, qs, font); } } } glViewport(savedViewport[0], savedViewport[1], savedViewport[2], savedViewport[3]); glMatrixMode(GL_PROJECTION); glLoadMatrixf(savedProjectionMatrix); glMatrixMode(GL_MODELVIEW); glEnable(GL_DEPTH_TEST); glPopMatrix(); } } /** * draw main window caption. */ void BrainModelOpenGL::drawMainWindowCaption() { if (mainWindowCaption.isEmpty()) { return; } glDisable(GL_DEPTH_TEST); PreferencesFile* prf = brainSet->getPreferencesFile(); unsigned char rf, gf, bf; prf->getSurfaceForegroundColor(rf, gf, bf); glColor3ub(rf, gf, bf); // // Font for drawing numbers // const int fontHeight = 18; QFont font("times", fontHeight); QFontMetrics fontMetrics(font); const int halfWidth = static_cast(fontMetrics.width(mainWindowCaption) * 0.5); const int fontX = static_cast(viewport[0] + (viewport[2] * 0.50)) - halfWidth; const int fontY = static_cast(viewport[1] + (viewport[3] * 0.90)); if (glWidget != NULL) { glWidget->renderText(fontX, fontY, mainWindowCaption, font); } glEnable(GL_DEPTH_TEST); } /** * Display a QImage in the OpenGL window. */ void BrainModelOpenGL::displayAnImage(QImage* image) { DisplaySettingsImages* dsi = brainSet->getDisplaySettingsImages(); const float xScale = static_cast(viewport[2]) / static_cast(image->width()); const float yScale = static_cast(viewport[3]) / static_cast(image->height()); float pixelZoom = 1.0; float xPos = 0.0; float yPos = 0.0; switch (dsi->getImagePositionMode()) { case DisplaySettingsImages::IMAGE_POSITION_MODE_CENTER_OF_WINDOW: { const float imageCenterX = image->width() * 0.5; const float imageCenterY = image->height() * 0.5; const float windowCenterX = viewport[2] * 0.5; const float windowCenterY = viewport[3] * 0.5; xPos = windowCenterX - imageCenterX; yPos = windowCenterY - imageCenterY; if (xScale < yScale) { pixelZoom = xScale; } else { pixelZoom = yScale; } xPos = windowCenterX - (imageCenterX * pixelZoom); xPos = std::max(0.0f, xPos); yPos = windowCenterY - (imageCenterY * pixelZoom); yPos = std::max(0.0f, yPos); } break; case DisplaySettingsImages::IMAGE_POSITION_MODE_SCALE_TO_WINDOW: { bool centerImageX = false, centerImageY = false; if (xScale < yScale) { pixelZoom = xScale; centerImageY = true; } else { pixelZoom = yScale; centerImageX = true; } if (centerImageY) { // center image vertically const float ySize = image->height() * pixelZoom; const float margin = viewport[3] - ySize; yPos = margin * 0.5; } if (centerImageX) { // center image horizontally const float xSize = image->width() * pixelZoom; const float margin = viewport[3] - xSize; xPos = margin * 0.5; } } break; } glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(0, viewport[2], 0, viewport[3], orthographicNear[viewingWindowNumber], orthographicFar[viewingWindowNumber]); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); // // Draw image near far clipping plane // const float imageZ = 10.0 -orthographicFar[viewingWindowNumber]; glRasterPos3f(xPos, yPos, imageZ); //-500.0); // set Z so image behind surface glPixelZoom(pixelZoom, pixelZoom); glDrawPixels(image->width(), image->height(), GL_RGBA, GL_UNSIGNED_BYTE, image->bits()); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); } /** * Display background and splash images */ void BrainModelOpenGL::displayImages() { if (brainSet->getDisplaySplashImage()) { displayAnImage(brainSet->getSplashImage()); } DisplaySettingsImages* dsi = brainSet->getDisplaySettingsImages(); if (dsi->getShowImageInMainWindow() && (dsi->getMainWindowImageNumber() >= 0) && (dsi->getMainWindowImageNumber() < brainSet->getNumberOfImageFiles())) { QImage* image = dsi->getMainWindowImage(); if (image != NULL) { displayAnImage(image); } } } /** * Draw the linear object (typically used while drawing borders) */ void BrainModelOpenGL::drawLinearObject() { glDisable(GL_DEPTH_TEST); const int num = linearObjectBeingDrawn.getNumberOfLinks(); glPointSize(getValidPointSize(2.0)); glColor3f(1.0, 0.0, 0.0); glBegin(GL_POINTS); for (int i = 0; i < num; i++) { glVertex3fv(linearObjectBeingDrawn.getLinkXYZ(i)); } glEnd(); glEnable(GL_DEPTH_TEST); } /** * Draw the VTK models. */ void BrainModelOpenGL::drawAllVtkModels() { const int num = brainSet->getNumberOfVtkModelFiles(); for (int modelNum = 0; modelNum < num; modelNum++) { VtkModelFile* vmf = brainSet->getVtkModelFile(modelNum); drawVtkModelFile(vmf, modelNum); } } /** * Draw a VTK model file. */ void BrainModelOpenGL::drawVtkModelFile(VtkModelFile* vmf, const int modelNum) { DisplaySettingsModels* dsm = brainSet->getDisplaySettingsModels(); TransformationMatrixFile* tmf = brainSet->getTransformationMatrixFile(); bool drawModelFlag = false; bool doingSelectionAnyFlag = false; bool doingSelectionTrianglesFlag = false; bool doingSelectionVerticesFlag = false; if (vmf->getDisplayFlag()) { drawModelFlag = true; if (selectionMask != SELECTION_MASK_OFF) { if (selectionMask & SELECTION_MASK_VTK_MODEL) { if (modelNum >= 0) { doingSelectionAnyFlag = true; doingSelectionVerticesFlag = true; doingSelectionTrianglesFlag = true; } } else { drawModelFlag = false; } } } const float opacityFloat = dsm->getOpacity(); const unsigned char alphaOverride = static_cast(opacityFloat * 255.0); if (drawModelFlag) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glPushMatrix(); { if (doingSelectionTrianglesFlag || doingSelectionAnyFlag) { glPushName(SELECTION_MASK_VTK_MODEL); glPushName(modelNum); } const TransformationMatrix* tm = vmf->getAssociatedTransformationMatrix(); if (tmf->getMatrixIndex(tm) >= 0) { float matrix[16]; tm->getMatrix(matrix); glMultMatrixf(matrix); } const CoordinateFile* cf = vmf->getCoordinateFile(); if (cf->getNumberOfCoordinates() > 0) { const float* coords = cf->getCoordinate(0); const unsigned char* colors = vmf->getPointColor(0); const float* normals = vmf->getPointNormal(0); // // Draw polygons // if (dsm->getLightPolygonsEnabled()) { glEnable(GL_LIGHTING); glEnable(GL_COLOR_MATERIAL); } else { glDisable(GL_LIGHTING); glDisable(GL_COLOR_MATERIAL); } if (dsm->getShowPolygons()) { const int numPolys = vmf->getNumberOfPolygons(); for (int i = 0; i < numPolys; i++) { const VtkModelFile::VtkModelObject* poly = vmf->getPolygon(i); glBegin(GL_POLYGON); const int num = poly->getNumberOfItems(); const int* pts = poly->getPointIndex(0); for (int n = 0; n < num; n++) { const int p3 = pts[n] * 3; const int p4 = pts[n] * 4; unsigned char alpha = colors[p4+3]; if (alphaOverride < 255) { alpha = alphaOverride; } glColor4ub(colors[p4], colors[p4+1], colors[p4+2], alpha); glNormal3fv(&normals[p3]); glVertex3fv(&coords[p3]); } glEnd(); } } // // Draw triangles // if (dsm->getShowTriangles()) { const int numTriangles = vmf->getNumberOfTriangles(); if (numTriangles > 0) { for (int i = 0; i < numTriangles; i++) { if (doingSelectionTrianglesFlag) { glPushName(GL_TRIANGLES); // selecting triangles glPushName(i); } glBegin(GL_TRIANGLES); const int* t = vmf->getTriangle(i); const int p1 = t[0] * 3; const int p2 = t[1] * 3; const int p3 = t[2] * 3; const int p14 = t[0] * 4; const int p24 = t[1] * 4; const int p34 = t[2] * 4; unsigned char alpha1 = colors[p14+3]; unsigned char alpha2 = colors[p24+3]; unsigned char alpha3 = colors[p34+3]; if (alphaOverride < 255) { alpha1 = alphaOverride; alpha2 = alphaOverride; alpha3 = alphaOverride; } glColor4ub(colors[p14], colors[p14+1], colors[p14+2], alpha1); glNormal3fv(&normals[p1]); glVertex3fv(&coords[p1]); glColor4ub(colors[p24], colors[p24+1], colors[p24+2], alpha2); glNormal3fv(&normals[p2]); glVertex3fv(&coords[p2]); glColor4ub(colors[p34], colors[p34+1], colors[p34+2], alpha3); glNormal3fv(&normals[p3]); glVertex3fv(&coords[p3]); glEnd(); if (doingSelectionTrianglesFlag) { glPopName(); glPopName(); } } } } // // Draw lines // if (dsm->getLightLinesEnabled()) { glEnable(GL_LIGHTING); glEnable(GL_COLOR_MATERIAL); } else { glDisable(GL_LIGHTING); glDisable(GL_COLOR_MATERIAL); } if (dsm->getShowLines()) { const int numLines = vmf->getNumberOfLines(); glLineWidth(getValidLineWidth(dsm->getLineWidth())); for (int i = 0; i < numLines; i++) { const VtkModelFile::VtkModelObject* line = vmf->getLine(i); glBegin(GL_LINE_STRIP); const int num = line->getNumberOfItems(); const int* pts = line->getPointIndex(0); for (int n = 0; n < num; n++) { const int p3 = pts[n] * 3; const int p4 = pts[n] * 4; unsigned char alpha = colors[p4+3]; if (alphaOverride < 255) { alpha = alphaOverride; } glColor4ub(colors[p4], colors[p4+1], colors[p4+2], alpha); glNormal3fv(&normals[p3]); glVertex3fv(&coords[p3]); } glEnd(); } } // // Draw vertices // if (dsm->getLightVerticesEnabled()) { glEnable(GL_LIGHTING); glEnable(GL_COLOR_MATERIAL); } else { glDisable(GL_LIGHTING); glDisable(GL_COLOR_MATERIAL); } if (dsm->getShowVertices()) { const int numVerts = vmf->getNumberOfVertices(); const float s = dsm->getVertexSize() * 0.5; for (int i = 0; i < numVerts; i++) { const int pointNumber = *vmf->getVertex(i); const int p3 = pointNumber * 3; const int p4 = pointNumber * 4; unsigned char alpha = colors[p4+3]; if (alphaOverride < 255) { alpha = alphaOverride; } glPushMatrix(); if (doingSelectionVerticesFlag) { glPushName(GL_POINTS); // selecting points glPushName(i); } glColor4ub(colors[p4], colors[p4+1], colors[p4+2], alpha); glTranslatef(coords[p3], coords[p3+1], coords[p3+2]); drawSphere(s); if (doingSelectionVerticesFlag) { glPopName(); glPopName(); } glPopMatrix(); } } } if (doingSelectionAnyFlag) { glPopName(); glPopName(); } } glPopMatrix(); glDisable(GL_BLEND); } glDisable(GL_LIGHTING); glDisable(GL_COLOR_MATERIAL); } /** * Draw transformation data files. */ void BrainModelOpenGL::drawTransformationDataFiles(const TransformationMatrix* tm) { const int num = brainSet->getNumberOfTransformationDataFiles(); for (int i = 0; i < num; i++) { AbstractFile* af = brainSet->getTransformationDataFile(i); if (af->getAssociatedTransformationMatrix() == tm) { FociFile* ff = dynamic_cast(af); if (ff != NULL) { drawTransformationCellOrFociFile(NULL, ff, brainSet->getFociColorFile(), brainSet->getDisplaySettingsFoci(), i, SELECTION_MASK_TRANSFORM_FOCI); } ContourCellFile* ccf = dynamic_cast(af); if (ccf != NULL) { drawTransformationCellOrFociFile(NULL, ccf, brainSet->getContourCellColorFile(), brainSet->getDisplaySettingsCells(), i, SELECTION_MASK_TRANSFORM_CONTOUR_CELL); } CellFile* cf = dynamic_cast(af); if ((ff == NULL) && (ccf == NULL) && (cf != NULL)) { drawTransformationCellOrFociFile(NULL, cf, brainSet->getCellColorFile(), brainSet->getDisplaySettingsCells(), i, SELECTION_MASK_TRANSFORM_CELL); } VtkModelFile* vmf = dynamic_cast(af); if (vmf != NULL) { drawVtkModelFile(vmf, -1); } { glPushMatrix(); ContourFile* cf = dynamic_cast(af); if (cf != NULL) { const DisplaySettingsContours* dsc = brainSet->getDisplaySettingsContours(); const int numContours = cf->getNumberOfContours(); const float spacing = cf->getSectionSpacing(); for (int k = 0; k < numContours; k++) { const CaretContour* contour = cf->getContour(k); const int sectionNumber = contour->getSectionNumber(); const float z = sectionNumber * spacing; const int numPoints = contour->getNumberOfPoints(); if (dsc->getDrawMode() != DisplaySettingsContours::DRAW_MODE_POINTS) { glBegin(GL_LINE_LOOP); } else { glBegin(GL_POINTS); } for (int j = 0; j < numPoints; j++) { if ((j == 0) && (dsc->getShowEndPoints())) { glColor3ub(255, 0, 0); } else { glColor3ub(0, 255, 0); } float x, y; contour->getPointXY(j, x, y); glVertex3f(x, y, z); } glEnd(); } } // if glPopMatrix(); } } } } /** * Draw the deformation field vectors. */ void BrainModelOpenGL::drawDeformationFieldVectors(BrainModelSurface* bms) { DeformationFieldFile* dff = brainSet->getDeformationFieldFile(); if (dff->getNumberOfColumns() <= 0) { return; } DisplaySettingsDeformationField* dsdf = brainSet->getDisplaySettingsDeformationField(); switch (dsdf->getDisplayMode()) { case DisplaySettingsDeformationField::DISPLAY_MODE_ALL: break; case DisplaySettingsDeformationField::DISPLAY_MODE_NONE: break; case DisplaySettingsDeformationField::DISPLAY_MODE_SPARSE: break; } const CoordinateFile* coords = bms->getCoordinateFile(); const int numNodes = bms->getNumberOfNodes(); const int column = dsdf->getSelectedDisplayColumn(); const TopologyHelper* th = bms->getTopologyFile()->getTopologyHelper(false, true, false); const BrainModelSurface* fiducialBMS = brainSet->getActiveFiducialSurface(); const CoordinateFile* fiducialCoords = (fiducialBMS != NULL) ? fiducialBMS->getCoordinateFile() : NULL; const float *fiducialXYZ = (fiducialCoords != NULL) ? fiducialCoords->getCoordinate(0) : NULL; float unstretchFactor = 1.0; bool showUnstretched = false; dsdf->getShowUnstretchedOnFlat(unstretchFactor, showUnstretched); int nodes[3]; float areas[3]; const float* xyz = coords->getCoordinate(0); glBegin(GL_LINES); for (int i = 0; i < numNodes; i++) { const int i3 = i * 3; // // If vector should be displayed // if (dsdf->getDisplayVectorForNode(i)) { // // If node has neighbors // if (th->getNodeHasNeighbors(i)) { // // Get tip of vector // DeformationFieldNodeInfo* dfni = dff->getDeformationInfo(i, column); dfni->getData(nodes, areas); bool showIt = true; for (int j = 0; j < 3; j++) { if ((nodes[j] < 0) || (nodes[j] >= numNodes)) { showIt = false; break; } if (th->getNodeHasNeighbors(nodes[j]) == false) { showIt = false; break; } } if (showIt) { // // Unproject // float tipXYZ[3]; BrainModelSurfacePointProjector::unprojectPoint(nodes, areas, coords, tipXYZ); if ((bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FLAT) || (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR)) { if (showUnstretched) { if (fiducialBMS != NULL) { float fidTipXYZ[3]; BrainModelSurfacePointProjector::unprojectPoint(nodes, areas, fiducialCoords, fidTipXYZ); const float vecLength = MathUtilities::distance3D(&xyz[i3], tipXYZ); const float fidLength = MathUtilities::distance3D(&fiducialXYZ[i3], fidTipXYZ); if (fidLength != 0.0) { if ((vecLength / fidLength) > unstretchFactor) { showIt = false; } } } } } if (showIt) { // // Start drawing at node and continue to tip // glColor3ub(255, 255, 0); glVertex3fv(&xyz[i3]); glColor3ub(255, 0, 0); glVertex3fv(tipXYZ); if (DebugControl::getDebugOn()) { if (DebugControl::getDebugNodeNumber() == i) { const float vecLength = MathUtilities::distance3D(&xyz[i3], tipXYZ); std::cout << "Def Field Vector Tip (" << FileUtilities::basename(coords->getFileName()).toAscii().constData() << ") " << tipXYZ[0] << ", " << tipXYZ[1] << ", " << tipXYZ[2] << " length: " << vecLength << std::endl; } } } } } } } glEnd(); } /** * Check a vector's orientation (true if orientation is valid for display). */ bool BrainModelOpenGL::checkVectorOrientation(const float vector[3]) { bool valid = true; DisplaySettingsVectors* dsv = brainSet->getDisplaySettingsVectors(); const DisplaySettingsVectors::DISPLAY_ORIENTATION orientation = dsv->getDisplayOrientation(); if (orientation != DisplaySettingsVectors::DISPLAY_ORIENTATION_ANY) { float axisVector[3]; switch (orientation) { case DisplaySettingsVectors::DISPLAY_ORIENTATION_ANY: break; case DisplaySettingsVectors::DISPLAY_ORIENTATION_LEFT_RIGHT: axisVector[0] = 1.0; axisVector[1] = 0.0; axisVector[2] = 0.0; break; case DisplaySettingsVectors::DISPLAY_ORIENTATION_POSTERIOR_ANTERIOR: axisVector[0] = 0.0; axisVector[1] = 1.0; axisVector[2] = 0.0; break; case DisplaySettingsVectors::DISPLAY_ORIENTATION_INFERIOR_SUPERIOR: axisVector[0] = 0.0; axisVector[1] = 0.0; axisVector[2] = 1.0; break; } const DisplaySettingsVectors::VECTOR_TYPE vectorType = dsv->getVectorType(); bool directedFlag = false; switch (vectorType) { case DisplaySettingsVectors::VECTOR_TYPE_BIDIRECTIONAL: break; case DisplaySettingsVectors::VECTOR_TYPE_UNIDIRECTIONAL_ARROW: case DisplaySettingsVectors::VECTOR_TYPE_UNIDIRECTIONAL_CYLINDER: directedFlag = true; break; } // // Dot produce is cosine of angle between vectors // const float angle = dsv->getDisplayOrientationAngle(); if (directedFlag) { float angleCosine = std::cos(angle * MathUtilities::degreesToRadians()); float dot = MathUtilities::dotProduct(vector, axisVector); if (angle < 0.0) { angleCosine = -angleCosine; if (dot >= angleCosine) { valid = false; } } else { if (dot < angleCosine) { valid = false; } } } else { const float angleCosine = std::cos(angle * MathUtilities::degreesToRadians()); float dot = std::fabs(MathUtilities::dotProduct(vector, axisVector)); if (dot < angleCosine) { valid = false; } } } return valid; } /** * Draw the vectors in 3D space. */ void BrainModelOpenGL::drawVectorFile3D(BrainModelSurface* bms) { const int numVectorFiles = brainSet->getNumberOfVectorFiles(); if (numVectorFiles <= 0) { return; } DisplaySettingsVectors* dsv = brainSet->getDisplaySettingsVectors(); int displayIncrement = 1; switch (dsv->getDisplayModeSurface()) { case DisplaySettingsVectors::DISPLAY_MODE_ALL: break; case DisplaySettingsVectors::DISPLAY_MODE_NONE: return; break; case DisplaySettingsVectors::DISPLAY_MODE_SPARSE: displayIncrement = dsv->getSparseDisplayDistance(); break; } DisplaySettingsSurface* dss = brainSet->getDisplaySettingsSurface(); // // Setup clipping planes // bool applyClippingPlanesFlag = false; switch (dss->getClippingPlaneApplication()) { case DisplaySettingsSurface::CLIPPING_PLANE_APPLICATION_MAIN_WINDOW_ONLY: if (viewingWindowNumber == BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) { applyClippingPlanesFlag = true; } break; case DisplaySettingsSurface::CLIPPING_PLANE_APPLICATION_FIDUCIAL_SURFACES_ONLY: if (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FIDUCIAL) { applyClippingPlanesFlag = true; } break; case DisplaySettingsSurface::CLIPPING_PLANE_APPLICATION_ALL_SURFACES: applyClippingPlanesFlag = true; break; } // // Surface clipping, use coordinate of vector rather than clipping // planes since clipping planes chop off part of a vector instead // of the whole thing. // float xMin = -std::numeric_limits::max(); float xMax = std::numeric_limits::max(); float yMin = -std::numeric_limits::max(); float yMax = std::numeric_limits::max(); float zMin = -std::numeric_limits::max(); float zMax = std::numeric_limits::max(); if (applyClippingPlanesFlag) { if (dss->getClippingPlaneEnabled(DisplaySettingsSurface::CLIPPING_PLANE_AXIS_X_NEGATIVE)) { xMin = dss->getClippingPlaneCoordinate(DisplaySettingsSurface::CLIPPING_PLANE_AXIS_X_NEGATIVE); } if (dss->getClippingPlaneEnabled(DisplaySettingsSurface::CLIPPING_PLANE_AXIS_X_POSITIVE)) { xMax = dss->getClippingPlaneCoordinate(DisplaySettingsSurface::CLIPPING_PLANE_AXIS_X_POSITIVE); } if (dss->getClippingPlaneEnabled(DisplaySettingsSurface::CLIPPING_PLANE_AXIS_Y_NEGATIVE)) { yMin = dss->getClippingPlaneCoordinate(DisplaySettingsSurface::CLIPPING_PLANE_AXIS_Y_NEGATIVE); } if (dss->getClippingPlaneEnabled(DisplaySettingsSurface::CLIPPING_PLANE_AXIS_Y_POSITIVE)) { yMax = dss->getClippingPlaneCoordinate(DisplaySettingsSurface::CLIPPING_PLANE_AXIS_Y_POSITIVE); } if (dss->getClippingPlaneEnabled(DisplaySettingsSurface::CLIPPING_PLANE_AXIS_Z_NEGATIVE)) { zMin = dss->getClippingPlaneCoordinate(DisplaySettingsSurface::CLIPPING_PLANE_AXIS_Z_NEGATIVE); } if (dss->getClippingPlaneEnabled(DisplaySettingsSurface::CLIPPING_PLANE_AXIS_Z_POSITIVE)) { zMax = dss->getClippingPlaneCoordinate(DisplaySettingsSurface::CLIPPING_PLANE_AXIS_Z_POSITIVE); } } const DisplaySettingsVectors::COLOR_MODE colorMode = dsv->getColorMode(); const DisplaySettingsVectors::VECTOR_TYPE vectorType = dsv->getVectorType(); const DisplaySettingsVectors::SURFACE_SYMBOL surfaceSymbol = dsv->getSurfaceSymbol(); const bool drawWithMagnitudeFlag = dsv->getDrawWithMagnitude(); const float lengthMultiplier = dsv->getLengthMultiplier(); const float minimumMagnitude = dsv->getMagnitudeThreshold(); const float lineRadius = dsv->getSurfaceVectorLineWidth(); VolumeFile* segmentationMaskVolume = NULL; if (dsv->getSegmentationMaskingVolumeEnabled()) { segmentationMaskVolume = dsv->getSegmentationMaskingVolumeFile(); } VolumeFile* functionalMaskVolume = NULL; const float functionalMaskNegThresh = dsv->getFunctionalMaskingVolumeNegativeThreshold(); const float functionalMaskPosThresh = dsv->getFunctionalMaskingVolumePositiveThreshold(); if (dsv->getFunctionalMaskingVolumeEnabled()) { functionalMaskVolume = dsv->getFunctionalMaskingVolumeFile(); } GLboolean cullFaceStatus = glIsEnabled(GL_CULL_FACE); glEnable(GL_CULL_FACE); glColor3f(0.0, 1.0, 0.0); switch (surfaceSymbol) { case DisplaySettingsVectors::SURFACE_SYMBOL_3D: glEnable(GL_COLOR_MATERIAL); glEnable(GL_LIGHTING); break; case DisplaySettingsVectors::SURFACE_SYMBOL_2D_LINE: glDisable(GL_COLOR_MATERIAL); glDisable(GL_LIGHTING); break; } for (int m = 0; m < numVectorFiles; m++) { if (dsv->getDisplayVectorFile(m)) { VectorFile* vf = brainSet->getVectorFile(m); const int numVectors = vf->getNumberOfVectors(); for (int i = 0; i < numVectors; i += displayIncrement) { float xyz[3], vector[3], rgba[4], magnitude, radius; int nodeNumber; vf->getVectorData(i, xyz, vector, magnitude, nodeNumber, rgba, radius); if (magnitude < minimumMagnitude) { continue; } float length = lengthMultiplier; if (drawWithMagnitudeFlag) { length *= magnitude; } // // Adjust radius for surface vector line width for drawing as lines // switch (surfaceSymbol) { case DisplaySettingsVectors::SURFACE_SYMBOL_3D: break; case DisplaySettingsVectors::SURFACE_SYMBOL_2D_LINE: radius *= lineRadius; break; } switch (vectorType) { case DisplaySettingsVectors::VECTOR_TYPE_BIDIRECTIONAL: { xyz[0] -= (vector[0] * length * 0.5); xyz[1] -= (vector[1] * length * 0.5); xyz[2] -= (vector[2] * length * 0.5); } break; case DisplaySettingsVectors::VECTOR_TYPE_UNIDIRECTIONAL_ARROW: case DisplaySettingsVectors::VECTOR_TYPE_UNIDIRECTIONAL_CYLINDER: break; } // // Check surface clipping // if (applyClippingPlanesFlag) { if (xyz[0] < xMin) { continue; } if (xyz[0] > xMax) { continue; } if (xyz[1] < yMin) { continue; } if (xyz[1] > yMax) { continue; } if (xyz[2] < zMin) { continue; } if (xyz[2] > zMax) { continue; } } // // Is coordinate within the mask volume // if (segmentationMaskVolume != NULL) { int ijk[3]; if (segmentationMaskVolume->convertCoordinatesToVoxelIJK(xyz, ijk)) { if (segmentationMaskVolume->getVoxel(ijk) == 0.0) { continue; } } else { continue; } } if (functionalMaskVolume != NULL) { int ijk[3]; if (functionalMaskVolume->convertCoordinatesToVoxelIJK(xyz, ijk)) { const float value = functionalMaskVolume->getVoxel(ijk); if (value > 0.0) { if (value < functionalMaskPosThresh) { continue; } } else if (value < 0.0) { if (value > functionalMaskNegThresh) { continue; } } else { continue; } } else { continue; } } if (checkVectorOrientation(vector) == false) { continue; } float endPoint[3] = { xyz[0] + vector[0] * length, xyz[1] + vector[1] * length, xyz[2] + vector[2] * length }; switch(colorMode) { case DisplaySettingsVectors::COLOR_MODE_VECTOR_COLORS: break; case DisplaySettingsVectors::COLOR_MODE_XYZ_AS_RGB: rgba[0] = std::fabs(vector[0]); rgba[1] = std::fabs(vector[1]); rgba[2] = std::fabs(vector[2]); rgba[3] = 1.0; break; } glColor4fv(rgba); switch (vectorType) { case DisplaySettingsVectors::VECTOR_TYPE_BIDIRECTIONAL: switch (surfaceSymbol) { case DisplaySettingsVectors::SURFACE_SYMBOL_3D: drawCylinderSymbol(xyz, endPoint, radius); break; case DisplaySettingsVectors::SURFACE_SYMBOL_2D_LINE: { glLineWidth(getValidLineWidth(radius)); glBegin(GL_LINES); glVertex3fv(xyz); glVertex3fv(endPoint); glEnd(); } break; } break; case DisplaySettingsVectors::VECTOR_TYPE_UNIDIRECTIONAL_ARROW: switch (surfaceSymbol) { case DisplaySettingsVectors::SURFACE_SYMBOL_3D: drawArrowSymbol(xyz, endPoint, radius); break; case DisplaySettingsVectors::SURFACE_SYMBOL_2D_LINE: { glLineWidth(getValidLineWidth(radius)); glBegin(GL_LINES); glVertex3fv(xyz); glVertex3fv(endPoint); glEnd(); glPointSize(getValidPointSize(radius * 3.0)); glBegin(GL_POINTS); glVertex3fv(endPoint); glEnd(); } break; } break; case DisplaySettingsVectors::VECTOR_TYPE_UNIDIRECTIONAL_CYLINDER: switch (surfaceSymbol) { case DisplaySettingsVectors::SURFACE_SYMBOL_3D: drawCylinderSymbol(xyz, endPoint, radius); break; case DisplaySettingsVectors::SURFACE_SYMBOL_2D_LINE: { glLineWidth(getValidLineWidth(radius)); glBegin(GL_LINES); glVertex3fv(xyz); glVertex3fv(endPoint); glEnd(); } break; } break; } } } } if (cullFaceStatus == GL_FALSE) { glDisable(GL_CULL_FACE); } glDisable(GL_COLOR_MATERIAL); glDisable(GL_LIGHTING); glDisable(GL_BLEND); } /** * Draw the volume foci file. */ void BrainModelOpenGL::drawVectorsOnVolume(const VolumeFile::VOLUME_AXIS axis, const float axisCoord, const float /*voxelSize*/) { //const float halfVoxelSize = voxelSize * 0.6; const int numVectorFiles = brainSet->getNumberOfVectorFiles(); if (numVectorFiles <= 0) { return; } DisplaySettingsVectors* dsv = brainSet->getDisplaySettingsVectors(); int displayIncrement = 1; switch (dsv->getDisplayModeVolume()) { case DisplaySettingsVectors::DISPLAY_MODE_ALL: break; case DisplaySettingsVectors::DISPLAY_MODE_NONE: return; break; case DisplaySettingsVectors::DISPLAY_MODE_SPARSE: displayIncrement = dsv->getSparseDisplayDistance(); break; } int axisIndex = 0; switch (axis) { case VolumeFile::VOLUME_AXIS_X: axisIndex = 0; break; case VolumeFile::VOLUME_AXIS_Y: axisIndex = 1; break; case VolumeFile::VOLUME_AXIS_Z: axisIndex = 2; break; case VolumeFile::VOLUME_AXIS_ALL: case VolumeFile::VOLUME_AXIS_OBLIQUE: case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: case VolumeFile::VOLUME_AXIS_UNKNOWN: return; break; } const DisplaySettingsVectors::COLOR_MODE colorMode = dsv->getColorMode(); const bool drawWithMagnitudeFlag = dsv->getDrawWithMagnitude(); const DisplaySettingsVectors::VECTOR_TYPE vectorType = dsv->getVectorType(); const float lengthMultiplier = dsv->getLengthMultiplier(); const float aboveLimit = dsv->getVolumeSliceDistanceAboveLimit(); const float belowLimit = dsv->getVolumeSliceDistanceBelowLimit(); const float minimumMagnitude = dsv->getMagnitudeThreshold(); VolumeFile* segmentationMaskVolume = NULL; if (dsv->getSegmentationMaskingVolumeEnabled()) { segmentationMaskVolume = dsv->getSegmentationMaskingVolumeFile(); } VolumeFile* functionalMaskVolume = NULL; const float functionalMaskNegThresh = dsv->getFunctionalMaskingVolumeNegativeThreshold(); const float functionalMaskPosThresh = dsv->getFunctionalMaskingVolumePositiveThreshold(); if (dsv->getFunctionalMaskingVolumeEnabled()) { functionalMaskVolume = dsv->getFunctionalMaskingVolumeFile(); } glLineWidth(1.0); for (int m = 0; m < numVectorFiles; m++) { VectorFile* vf = brainSet->getVectorFile(m); const int numVectors = vf->getNumberOfVectors(); if (dsv->getDisplayVectorFile(m)) { for (int i = 0; i < numVectors; i += displayIncrement) { float xyzOrigin[3], vector[3], rgba[4], magnitude, radius; int nodeNumber; vf->getVectorData(i, xyzOrigin, vector, magnitude, nodeNumber, rgba, radius); if (magnitude < minimumMagnitude) { continue; } const float dist = xyzOrigin[axisIndex] - axisCoord; if ((dist > belowLimit) && (dist < aboveLimit)) { // // Is coordinate within the mask volume // if (segmentationMaskVolume != NULL) { int ijk[3]; if (segmentationMaskVolume->convertCoordinatesToVoxelIJK(xyzOrigin, ijk)) { if (segmentationMaskVolume->getVoxel(ijk) == 0.0) { continue; } } else { continue; } } if (functionalMaskVolume != NULL) { int ijk[3]; if (functionalMaskVolume->convertCoordinatesToVoxelIJK(xyzOrigin, ijk)) { const float value = functionalMaskVolume->getVoxel(ijk); if (value > 0.0) { if (value < functionalMaskPosThresh) { continue; } } else if (value < 0.0) { if (value > functionalMaskNegThresh) { continue; } } else { continue; } } else { continue; } } if (checkVectorOrientation(vector) == false) { continue; } float xyzScreen[3] = { xyzOrigin[0], xyzOrigin[1], xyzOrigin[2] }; convertVolumeItemXYZToScreenXY(axis, xyzScreen); float lengthMag = lengthMultiplier; if (drawWithMagnitudeFlag) { lengthMag *= magnitude; } float endPoint[3] = { xyzOrigin[0] + vector[0] * lengthMag, xyzOrigin[1] + vector[1] * lengthMag, xyzOrigin[2] + vector[2] * lengthMag }; convertVolumeItemXYZToScreenXY(axis, endPoint); const float dz = endPoint[2] - xyzScreen[2]; const float dy = endPoint[1] - xyzScreen[1]; const float dx = endPoint[0] - xyzScreen[0]; const float length = std::sqrt(dx*dx + dy*dy + dz*dz); const float rotation = std::atan2(dy, dx); glPushMatrix(); glTranslatef(xyzScreen[0], xyzScreen[1], xyzScreen[2]); glRotatef(rotation * MathUtilities::radiansToDegrees(), 0.0, 0.0, 1.0); const float z = xyzScreen[2]; glLineWidth(getValidLineWidth(radius)); switch(colorMode) { case DisplaySettingsVectors::COLOR_MODE_VECTOR_COLORS: break; case DisplaySettingsVectors::COLOR_MODE_XYZ_AS_RGB: rgba[0] = std::fabs(vector[0]); rgba[1] = std::fabs(vector[1]); rgba[2] = std::fabs(vector[2]); rgba[3] = 1.0; break; } switch (vectorType) { case DisplaySettingsVectors::VECTOR_TYPE_BIDIRECTIONAL: { glScalef(length, length * radius, 1.0); glBegin(GL_LINES); glColor4fv(rgba); glVertex3f(-0.5, 0.0, z); glVertex3f( 0.5, 0.0, z); glEnd(); } break; case DisplaySettingsVectors::VECTOR_TYPE_UNIDIRECTIONAL_ARROW: { glScalef(length, length * radius, 1.0); glBegin(GL_LINES); glColor4fv(rgba); glVertex3f(0.0, 0.0, z); glVertex3f(1.0, 0.0, z); glVertex3f(1.0, 0.0, z); glVertex3f(0.75, 0.25, z); glVertex3f(1.0, 0.0, z); glVertex3f(0.75, -0.25, z); glEnd(); } break; case DisplaySettingsVectors::VECTOR_TYPE_UNIDIRECTIONAL_CYLINDER: { glScalef(length, length * radius, 1.0); glBegin(GL_LINES); glColor4fv(rgba); glVertex3f(0.0, 0.0, z); glVertex3f(1.0, 0.0, z); glEnd(); } break; } glPopMatrix(); } } } } } /** * Draw an arrow symbol. * From: http://lifeofaprogrammergeek.blogspot.com/2008/07/rendering-cylinder-between-two-points.html */ void BrainModelOpenGL::drawArrowSymbol(const float xyz[3], const float tipXYZ[3], const float radius) { const float x1 = xyz[0]; const float y1 = xyz[1]; const float z1 = xyz[2]; float vx = tipXYZ[0] - x1; //x2-x1; float vy = tipXYZ[1] - y1; //y2-y1; float vz = tipXYZ[2] - z1; //z2-z1; float v = std::sqrt( vx*vx + vy*vy + vz*vz ); double ax = 0.0; double zero = 1.0e-3; if (std::fabs(vz) < zero) { ax = 57.2957795*std::acos( vx/v ); // rotation angle in x-y plane //if ( vx <= 0.0 ) ax = -ax; // JWH Fixes when Z is near zero if ( vy <= 0.0 ) ax = -ax; // JWH Fixes when Z is near zero } else { ax = 57.2957795*std::acos( vz/v ); // rotation angle if ( vz <= 0.0 ) ax = -ax; } float rx = -vy*vz; float ry = vx*vz; glPushMatrix(); glTranslatef( x1,y1,z1 ); if (fabs(vz) < zero) { glRotated(90.0, 0, 1, 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(); glScalef(radius, radius, v); drawCylinder(); glPopMatrix(); glPushMatrix(); glTranslatef(0.0, 0.0, v); glScalef(radius*2, radius*2, 1.0); drawCone(); glPopMatrix(); glPushMatrix(); glTranslatef(0.0, 0.0, 0.0); glScalef(radius, radius, 1.0); drawDisk(1.0); glPopMatrix(); glPopMatrix(); } /** * Draw a cylinder symbol. * From: http://lifeofaprogrammergeek.blogspot.com/2008/07/rendering-cylinder-between-two-points.html */ void BrainModelOpenGL::drawCylinderSymbol(const float xyz[3], const float tipXYZ[3], const float radius) { const float x1 = xyz[0]; const float y1 = xyz[1]; const float z1 = xyz[2]; float vx = tipXYZ[0] - x1; //x2-x1; float vy = tipXYZ[1] - y1; //y2-y1; float vz = tipXYZ[2] - z1; //z2-z1; float v = std::sqrt( vx*vx + vy*vy + vz*vz ); double ax = 0.0; double zero = 1.0e-3; if (std::fabs(vz) < zero) { ax = 57.2957795*std::acos( vx/v ); // rotation angle in x-y plane //if ( vx <= 0.0 ) ax = -ax; // JWH Fixes when Z is near zero if ( vy <= 0.0 ) ax = -ax; // JWH Fixes when Z is near zero } else { ax = 57.2957795*std::acos( vz/v ); // rotation angle if ( vz <= 0.0 ) ax = -ax; } float rx = -vy*vz; float ry = vx*vz; glPushMatrix(); glTranslatef( x1,y1,z1 ); if (fabs(vz) < zero) { glRotated(90.0, 0, 1, 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(); glScalef(radius, radius, v); drawCylinder(); glPopMatrix(); /* glPushMatrix(); glTranslatef(0.0, 0.0, v); glScalef(radius, radius, 1.0); drawDisk(1.0); glPopMatrix(); glPushMatrix(); glTranslatef(0.0, 0.0, 0.0); glScalef(radius, radius, 1.0); drawDisk(1.0); glPopMatrix(); */ glPopMatrix(); } /** * get the orthographic size. */ void BrainModelOpenGL::getOrtho(float& orthoRight, float& orthoTop) const { orthoRight = orthographicRight[0]; orthoTop = orthographicTop[0]; } /** * Called to get a 3D point on a model at a screen X/Y. * Returns "true" if the pointOut is valid. */ bool BrainModelOpenGL::getSurfacePointAtDisplayXY(BrainSet* bs, BrainModelSurface* bms, const int viewingWindowNumber, const int viewport[4], const int displayX, const int displayY, float pointOut[3]) { // // Must be a surface // if (bms == NULL) { return false; } brainSet = bs; if (DebugControl::getDebugOn()) { std::cout << "Doing special tile selection." << std::endl; } GLboolean ditheringOn = glIsEnabled(GL_DITHER); glDisable(GL_DITHER); glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); glMatrixMode(GL_PROJECTION); glLoadIdentity(); const double aspectRatio = (static_cast(viewport[2])) / (static_cast(viewport[3])); DisplaySettingsSurface* dss = brainSet->getDisplaySettingsSurface(); switch (dss->getViewingProjection()) { case DisplaySettingsSurface::VIEWING_PROJECTION_ORTHOGRAPHIC: glOrtho(orthographicLeft[viewingWindowNumber], orthographicRight[viewingWindowNumber], orthographicBottom[viewingWindowNumber], orthographicTop[viewingWindowNumber], orthographicNear[viewingWindowNumber], orthographicFar[viewingWindowNumber]); break; case DisplaySettingsSurface::VIEWING_PROJECTION_PERSPECTIVE: gluPerspective(bms->getPerspectiveFieldOfView(), aspectRatio, 1.0, 1000.0); break; } glMatrixMode(GL_MODELVIEW); glLoadIdentity(); switch (dss->getViewingProjection()) { case DisplaySettingsSurface::VIEWING_PROJECTION_ORTHOGRAPHIC: break; case DisplaySettingsSurface::VIEWING_PROJECTION_PERSPECTIVE: gluLookAt(0.0, 0.0, bms->getPerspectiveZooming(viewingWindowNumber), 0.0, 0.0,0.0, 0.0,1.0, 0.0); break; } float translate[3]; bms->getTranslation(viewingWindowNumber, translate); glTranslatef(translate[0], translate[1], translate[2]); float matrix[16]; bms->getRotationMatrix(viewingWindowNumber, matrix); glMultMatrixf(matrix); const BrainSetNodeAttribute* attributes = brainSet->getNodeAttributes(0); float scale[3]; bms->getScaling(viewingWindowNumber, scale); glScalef(scale[0], scale[1], scale[2]); glDisable(GL_LIGHTING); glDisable(GL_COLOR_MATERIAL); glDrawBuffer(GL_BACK); glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); const CoordinateFile* cf = bms->getCoordinateFile(); const TopologyFile* tf = bms->getTopologyFile(); const float* coords = cf->getCoordinate(0); const int numTiles = tf->getNumberOfTiles(); for (int i = 0; i < numTiles; i++) { int v1, v2, v3; tf->getTile(i, v1, v2, v3); if (attributes[v1].getDisplayFlag() || attributes[v2].getDisplayFlag() || attributes[v3].getDisplayFlag()) { const int maskFF = 0xff; const int tile = i + 1; /// can't have zero since zero is where no drawing occurs const unsigned char blue = tile & maskFF; const unsigned char green = (tile >> 8) & maskFF; const unsigned char red = (tile >> 16) & maskFF; glColor3ub(red, green, blue); glBegin(GL_TRIANGLES); glVertex3fv(&coords[v1*3]); glVertex3fv(&coords[v2*3]); glVertex3fv(&coords[v3*3]); glEnd(); } } // // Figure out which tile was pickes // glReadBuffer(GL_BACK); unsigned char pixels[3] = { 0, 0, 0 }; glPixelStorei( GL_PACK_SKIP_ROWS, 0); glPixelStorei( GL_PACK_SKIP_PIXELS, 0); glPixelStorei( GL_PACK_ALIGNMENT, 1); glReadPixels(displayX, viewport[3] - displayY, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, (GLvoid*)pixels); const int red = pixels[0]; const int green = pixels[1]; const int blue = pixels[2]; int tile = (red << 16) + (green << 8) + blue; tile--; if (ditheringOn) { glEnable(GL_DITHER); } if (DebugControl::getDebugOn()) { std::cout << "Tile selected: " << tile << std::endl; } if (tile < 0) { brainSet = NULL; return false; } // CONVERT DISPLAY X/Y INTO BARYCENTRIC COORD IN TILE AND THEN // POINT IN TILE TO 3D // // Get vertices of tile // int v1, v2, v3; tf->getTile(tile, v1, v2, v3); // // Get coordinates of vertices // float nodePos[3][3]; cf->getCoordinate(v1, nodePos[0]); cf->getCoordinate(v2, nodePos[1]); cf->getCoordinate(v3, nodePos[2]); // // Convert vertices of tile to display coordinates // GLdouble modelMatrix[16]; glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix); GLdouble projMatrix[16]; glGetDoublev(GL_PROJECTION_MATRIX, projMatrix); float nodeDispPos[3][3]; for (int i = 0; i < 3; i++) { GLdouble wx, wy, wz; if (gluProject(nodePos[i][0], nodePos[i][1], nodePos[i][2], modelMatrix, projMatrix, (GLint*)viewport, &wx, &wy, &wz) == GL_FALSE) { brainSet = NULL; return false; } nodeDispPos[i][0] = wx; nodeDispPos[i][1] = wy; nodeDispPos[i][2] = 0.0; // WANT ZERO } // // Compute area of tile in display coordinates // const float tileArea = MathUtilities::triangleArea(nodeDispPos[0], nodeDispPos[1], nodeDispPos[2]); if (DebugControl::getDebugOn()) { std::cout << "Triangle area: " << tileArea << std::endl; } // // If tile area is small use a vertex from the tile // if (tileArea < 0.001) { pointOut[0] = nodePos[0][0]; pointOut[1] = nodePos[0][1]; pointOut[2] = nodePos[0][2]; } else { // // Determine barycentric coordinates of display X/Y in tile // float displayXYZ[3] = { displayX, viewport[3] - displayY, 0.0 }; const float areaU = MathUtilities::triangleArea(displayXYZ, nodeDispPos[1], nodeDispPos[2]) / tileArea; const float areaV = MathUtilities::triangleArea(displayXYZ, nodeDispPos[2], nodeDispPos[0]) / tileArea; const float areaW = MathUtilities::triangleArea(displayXYZ, nodeDispPos[0], nodeDispPos[1]) / tileArea; float totalArea = areaU + areaV + areaW; if (totalArea <= 0) { totalArea = 1.0; } if ((areaU < 0.0) || (areaV < 0.0) || (areaW < 0.0)) { std::cout << "Invalid tile area: less than zero." << std::endl; brainSet = NULL; return false; } // // Convert to surface coordinates // pointOut[0] = (nodePos[0][0]*areaU + nodePos[1][0]*areaV + nodePos[2][0]*areaW) / totalArea; pointOut[1] = (nodePos[0][1]*areaU + nodePos[1][1]*areaV + nodePos[2][1]*areaW) / totalArea; pointOut[2] = (nodePos[0][2]*areaU + nodePos[1][2]*areaV + nodePos[2][2]*areaW) / totalArea; } if (DebugControl::getDebugOn()) { std::cout << "Point in tile: " << pointOut[0] << " " << pointOut[1] << " " << pointOut[2] << std::endl; } // // Determing position of surface point on window // GLdouble winX, winY, winZ; if (gluProject(pointOut[0], pointOut[1], pointOut[2], modelMatrix, projMatrix, (GLint*)viewport, &winX, &winY, &winZ) == GL_FALSE) { brainSet = NULL; return false; } winY = viewport[3] - winY; // // For some reason, point occaisionally project to some weird location. // So check their distance from the display location input to this method // and throw out those that do not appear to be correct. // const float dist = std::sqrt((winX - displayX) * (winX - displayX) + (winY - displayY) * (winY - displayY)); if (DebugControl::getDebugOn()) { std::cout << "INPUT (" << displayX << ", " << displayY << ") " << "PROJ-TO (" << winX << ", " << winY << ")" << std::endl; } if (dist > 1.8) { brainSet = NULL; return false; } return true; } /** * identify items in the brain model (returns text for ID display). */ QString BrainModelOpenGL::identifyBrainModelItem(BrainSet* bs, BrainModel* bm, BrainModel* allWindowBrainModelsForIdentificationIn[BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS], const int viewingWindowNumberIn, const int viewportIn[4], QGLWidget* glWidgetIn, const unsigned long selectionMaskIn, const int selectionXIn, const int selectionYIn, const bool viewModeFlag, const bool enableHtml, const bool enableVocabularyLinks) { for (int i = 0; i < BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS; i++) { allWindowBrainModelsForIdentification[i] = allWindowBrainModelsForIdentificationIn[i]; } // // Select items // selectBrainModelItem(bs, bm, viewingWindowNumberIn, viewportIn, glWidgetIn, selectionMaskIn, selectionXIn, selectionYIn, viewModeFlag); // // Generate identification text // BrainModelIdentification* bmid = bs->getBrainModelIdentification(); const QString idText = bmid->getIdentificationText(this, enableHtml, enableVocabularyLinks); //std::cout << "ID Information: " << std::endl // << idText.toAscii().constData() << std::endl; return idText; } /** * Called when an Identify mouse click has been made on a brain model. */ void BrainModelOpenGL::selectBrainModelItem(BrainSet* bs, BrainModel* bm, const int viewingWindowNumberIn, const int viewportIn[4], QGLWidget* glWidgetIn, const unsigned long selectionMaskIn, const int selectionXIn, const int selectionYIn, const bool viewModeFlag) { brainSet = bs; brainModel = bm; viewport[0] = viewportIn[0]; viewport[1] = viewportIn[1]; viewport[2] = viewportIn[2]; viewport[3] = viewportIn[3]; viewingWindowNumber = viewingWindowNumberIn; glWidget = glWidgetIn; glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); selectedSurfaceTile.reset(brainSet, brainModel, viewingWindowNumber); selectedNode.reset(brainSet, brainModel, viewingWindowNumber); selectedBorder1.reset(brainSet, brainModel, viewingWindowNumber); selectedBorder2.reset(brainSet, brainModel, viewingWindowNumber); selectedVolumeBorder.reset(brainSet, brainModel, viewingWindowNumber); selectedCellProjection.reset(brainSet, brainModel, viewingWindowNumber); selectedVolumeCell.reset(brainSet, brainModel, viewingWindowNumber); selectedCut.reset(brainSet, brainModel, viewingWindowNumber); selectedFocusProjection.reset(brainSet, brainModel, viewingWindowNumber); selectedVolumeFoci.reset(brainSet, brainModel, viewingWindowNumber); selectedPaletteMetric.reset(brainSet, brainModel, viewingWindowNumber); selectedPaletteShape.reset(brainSet, brainModel, viewingWindowNumber); selectedContour.reset(brainSet, brainModel, viewingWindowNumber); selectedContourCell.reset(brainSet, brainModel, viewingWindowNumber); selectedTransformCell.reset(brainSet, brainModel, viewingWindowNumber); selectedTransformFoci.reset(brainSet, brainModel, viewingWindowNumber); selectedTransformContour.reset(brainSet, brainModel, viewingWindowNumber); selectedTransformContourCell.reset(brainSet, brainModel, viewingWindowNumber); selectedVoxelUnderlay.reset(brainSet, brainModel, viewingWindowNumber); selectedVoxelOverlaySecondary.reset(brainSet, brainModel, viewingWindowNumber); selectedVoxelOverlayPrimary.reset(brainSet, brainModel, viewingWindowNumber); selectedVoxelFunctionalCloud.reset(brainSet, brainModel, viewingWindowNumber); selectedLink.reset(brainSet, brainModel, viewingWindowNumber); selectedTransformationMatrixAxes.reset(brainSet, brainModel, viewingWindowNumber); selectedVtkModel.reset(brainSet, brainModel, viewingWindowNumber); selectionMask = selectionMaskIn; //GLint viewport[4]; //glGetIntegerv(GL_VIEWPORT, viewport); glSelectBuffer(SELECTION_BUFFER_SIZE, selectionBuffer); glRenderMode(GL_SELECT); glInitNames(); glMatrixMode(GL_PROJECTION); //GLfloat projectionMatrix[16]; //glGetFloatv(GL_PROJECTION_MATRIX, projectionMatrix); glLoadIdentity(); selectionX = selectionXIn; selectionY = selectionViewport[viewingWindowNumber][3] - selectionYIn; GLdouble pickWidth = 5.0; GLdouble pickHeight = 5.0; DisplaySettingsVolume* dsv = brainSet->getDisplaySettingsVolume(); // // Special stuff for some volume modes that draw more than one volume slice // if (bm->getModelType() == BrainModel::BRAIN_MODEL_VOLUME) { BrainModelVolume* bmv = brainSet->getBrainModelVolume(); if (bmv != NULL) { switch (bmv->getSelectedAxis(viewingWindowNumber)) { case VolumeFile::VOLUME_AXIS_X: case VolumeFile::VOLUME_AXIS_Y: case VolumeFile::VOLUME_AXIS_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: if (dsv->getMontageViewSelected()) { // // Get montage info // int rows, columns, sliceIncrement; dsv->getMontageViewSettings(rows, columns, sliceIncrement); const int vpHeight = viewport[3] / rows; const int vpWidth = viewport[2] / columns; for (int i = (rows - 1); i >= 0; i--) { for (int j = 0; j < columns; j++) { //for (int i = 0; i < rows; i++) { const int vpX = j * vpWidth; const int vpY = i * vpHeight; if ((selectionX > vpX) && (selectionY > vpY) && (selectionX < (vpX + vpWidth)) && (selectionY < (vpY + vpHeight))) { selectionViewport[viewingWindowNumber][0] = vpX; selectionViewport[viewingWindowNumber][1] = vpY; selectionViewport[viewingWindowNumber][2] = vpWidth; selectionViewport[viewingWindowNumber][3] = vpHeight; } } } } break; case VolumeFile::VOLUME_AXIS_ALL: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: { int startX = 0; int startY = 0; const int halfX = viewport[2] / 2; const int halfY = viewport[3] / 2; selectionX = selectionXIn; selectionY = viewportIn[3] - selectionYIn; if (selectionX > halfX) { startX = halfX; } if (selectionY > halfY) { startY = halfY; } selectionViewport[viewingWindowNumber][0] = startX; selectionViewport[viewingWindowNumber][1] = startY; selectionViewport[viewingWindowNumber][2] = halfX; selectionViewport[viewingWindowNumber][3] = halfY; } break; case VolumeFile::VOLUME_AXIS_OBLIQUE: case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } } } // // If only picking tiles // if (selectionMask == SELECTION_MASK_TILE) { pickWidth = 0.0; pickHeight = 0.0; } gluPickMatrix((GLdouble)selectionXIn, //(GLdouble)(selectionViewport[viewingWindowNumber][3] - selectionYIn), (GLdouble)(viewportIn[3] - selectionYIn), pickWidth, pickHeight, selectionViewport[viewingWindowNumber]); glOrtho(orthographicLeft[viewingWindowNumber], orthographicRight[viewingWindowNumber], orthographicBottom[viewingWindowNumber], orthographicTop[viewingWindowNumber], orthographicNear[viewingWindowNumber], orthographicFar[viewingWindowNumber]); drawBrainModelPrivate(bm, viewingWindowNumber, viewportIn, glWidgetIn); const GLint numHits = glRenderMode(GL_RENDER); processSelectedItems(numHits); glMatrixMode(GL_PROJECTION); glLoadMatrixd(selectionProjectionMatrix[viewingWindowNumber]); glMatrixMode(GL_MODELVIEW); // // If both a tile and node found // if ((selectionMask & SELECTION_MASK_NODE) && (selectionMask & SELECTION_MASK_TILE)) { if ((selectedNode.getItemIndex1() >= 0) && (selectedSurfaceTile.getItemIndex1() >= 0)) { // // If tile is closer // if (selectedSurfaceTile.getDepth() < selectedNode.getDepth()) { // // Use tile // selectedNode.setItemIndex1(-1); } } } // // If no nodes found but a tile was found (user may be zoomed in on surface) // if ((selectionMask & SELECTION_MASK_NODE) && (selectionMask & SELECTION_MASK_TILE)) { if ((selectedNode.getItemIndex1() < 0) && (selectedSurfaceTile.getItemIndex1() >= 0)) { // // Get the nodes in the tile // BrainModelSurface* bms = dynamic_cast(bm); if (bms != NULL) { const TopologyFile* tf = bms->getTopologyFile(); if (tf != NULL) { int nodes[3]; tf->getTile(selectedSurfaceTile.getItemIndex1(), nodes); // // Find node nearest cursor // int nearestNode = -1; float nearestDistance = std::numeric_limits::max(); for (int k = 0; k < 3; k++) { const CoordinateFile* cf = bms->getCoordinateFile(); float pos[3]; cf->getCoordinate(nodes[k], pos); GLdouble windowPos[3]; if (gluProject(pos[0], pos[1], pos[2], getSelectionModelviewMatrix(viewingWindowNumberIn), getSelectionProjectionMatrix(viewingWindowNumberIn), getSelectionViewport(viewingWindowNumberIn), &windowPos[0], &windowPos[1], &windowPos[2]) == GL_TRUE) { const double dx = windowPos[0] - selectionX; const double dy = windowPos[1] - selectionY; const double dist = std::sqrt(dx*dx + dy*dy); if (dist < nearestDistance) { nearestDistance = dist; nearestNode = nodes[k]; } } } if (nearestNode >= 0) { selectedNode.replaceIfCloser(0.0, 0.0, BrainModelOpenGLSelectedItem::ITEM_TYPE_NODE, nearestNode); if (DebugControl::getDebugOn()) { std::cout << "Setting selectedNode via selectedTile, node: " << nearestNode << std::endl; } } } } } } // // In a viewing mode? // if (viewModeFlag) { // // Is this surface and volume ? // if (dynamic_cast(bm) != NULL) { // // In surface and volume, display ID for only node/voxel nearest viewer // if ((selectedNode.getItemIndex1() >= 0) && (selectedVoxelUnderlay.getItemIndex1() >= 0)) { if (selectedNode.getDepth() < selectedVoxelUnderlay.getDepth()) { selectedVoxelUnderlay.setItemIndex1(-1); } else { selectedNode.setItemIndex1(-1); } } } // // Is this surface ? If so, highlight voxel in overlay/underlay volumes and contours // //if ((dynamic_cast(bm) == NULL) && // (dynamic_cast(bm) != NULL)) { if (dynamic_cast(bm) != NULL) { BrainModelSurface* bms = dynamic_cast(bm); switch (bms->getStructure().getType()) { case Structure::STRUCTURE_TYPE_CORTEX_LEFT: bms = bs->getLeftFiducialVolumeInteractionSurface(); break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT: bms = bs->getRightFiducialVolumeInteractionSurface(); break; case Structure::STRUCTURE_TYPE_CORTEX_BOTH: bms = NULL; break; case Structure::STRUCTURE_TYPE_CEREBELLUM: bms = bs->getCerebellumFiducialVolumeInteractionSurface(); break; case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_LEFT: bms = NULL; break; case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_RIGHT: bms = NULL; break; case Structure::STRUCTURE_TYPE_CORTEX_LEFT_OR_CEREBELLUM: bms = NULL; break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT_OR_CEREBELLUM: bms = NULL; break; case Structure::STRUCTURE_TYPE_CEREBRUM_CEREBELLUM: case Structure::STRUCTURE_TYPE_SUBCORTICAL: case Structure::STRUCTURE_TYPE_ALL: case Structure::STRUCTURE_TYPE_INVALID: bms = NULL; break; } if (bms == NULL) { bms = bs->getActiveFiducialSurface(); } const int nodeNumber = selectedNode.getItemIndex1(); if ((bms != NULL) && (nodeNumber >= 0)) { // // Get the nodes position // CoordinateFile* cf = bms->getCoordinateFile(); float xyz[3]; cf->getCoordinate(nodeNumber, xyz); // // See if contours are loaded // BrainModelContours* bmc = bs->getBrainModelContours(-1); if (bmc != NULL) { // // highlight nearest contour point // const ContourFile* cf = bmc->getContourFile(); int contourNumber; int contourPointNumber; cf->findContourPoint(xyz, 3.0, contourNumber, contourPointNumber); if ((contourNumber >= 0) && (contourPointNumber >= 0)) { selectedContour.reset(bs, bms, viewingWindowNumber); selectedContour.setItemIndex1(contourNumber); selectedContour.setItemIndex2(contourPointNumber); } } // // See if there is a volume loaded // BrainModelVolume* bmv = bs->getBrainModelVolume(-1); if (bmv != NULL) { // // Highlight primary overlay voxel nearest node // VolumeFile* vf3 = bmv->getOverlayPrimaryVolumeFile(); if (vf3 != NULL) { int ijk[3]; if (vf3->convertCoordinatesToVoxelIJK(xyz, ijk)) { selectedVoxelOverlayPrimary.reset(bs, bmv, viewingWindowNumber); selectedVoxelOverlayPrimary.setItemIndex1(ijk[0]); selectedVoxelOverlayPrimary.setItemIndex2(ijk[1]); selectedVoxelOverlayPrimary.setItemIndex3(ijk[2]); } } // // Highlight secondary overlay voxel nearest node // VolumeFile* vf2 = bmv->getOverlaySecondaryVolumeFile(); if (vf2 != NULL) { int ijk[3]; if (vf2->convertCoordinatesToVoxelIJK(xyz, ijk)) { selectedVoxelOverlaySecondary.reset(bs, bmv, viewingWindowNumber); selectedVoxelOverlaySecondary.setItemIndex1(ijk[0]); selectedVoxelOverlaySecondary.setItemIndex2(ijk[1]); selectedVoxelOverlaySecondary.setItemIndex3(ijk[2]); } } // // Highlight underlay voxel nearest node // VolumeFile* vf1 = bmv->getUnderlayVolumeFile(); if (vf1 != NULL) { int ijk[3]; if (vf1->convertCoordinatesToVoxelIJK(xyz, ijk)) { selectedVoxelUnderlay.reset(bs, bmv, viewingWindowNumber); selectedVoxelUnderlay.setItemIndex1(ijk[0]); selectedVoxelUnderlay.setItemIndex2(ijk[1]); selectedVoxelUnderlay.setItemIndex3(ijk[2]); } } // // Set slices in "lowest volume the windows selected slices // VolumeFile* vfm = bmv->getMasterVolumeFile(); if (vfm != NULL) { int ijk[3]; if (vfm->convertCoordinatesToVoxelIJK(xyz, ijk)) { for (int m = 0; m < BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS; m++) { bmv->setSelectedOrthogonalSlices(m, ijk); } } } } } } // // Is this volume ? // if (dynamic_cast(bm) != NULL) { if (selectedVoxelUnderlay.getItemIndex1() >= 0) { BrainModelVolume* bmv = bs->getBrainModelVolume(); if (bmv != NULL) { // // Get underlay volume file // VolumeFile* vf1 = bmv->getUnderlayVolumeFile(); if (vf1 != NULL) { // // Convert voxel to coordinate // const int ijk[3] = { selectedVoxelUnderlay.getItemIndex1(), selectedVoxelUnderlay.getItemIndex2(), selectedVoxelUnderlay.getItemIndex3() }; float xyz[3]; vf1->getVoxelCoordinate(ijk, xyz); // // Find closest fiducial/volume interaction surface // float fiducialDistance = std::numeric_limits::max(); int fiducialNodeNumber = -1; BrainModelSurface* fiducialBMS = NULL; BrainModelSurface* leftBMS = bs->getLeftFiducialVolumeInteractionSurface(); if (leftBMS != NULL) { // // Find nearest node // const CoordinateFile* cf = leftBMS->getCoordinateFile(); const int node = cf->getCoordinateIndexClosestToPoint(xyz[0], xyz[1], xyz[2]); if (node >= 0) { const float dist = cf->getDistanceToPoint(node, xyz); if (dist < fiducialDistance) { fiducialDistance = dist; fiducialNodeNumber = node; fiducialBMS = leftBMS; } } } BrainModelSurface* rightBMS = bs->getRightFiducialVolumeInteractionSurface(); if (rightBMS != NULL) { // // Find nearest node // const CoordinateFile* cf = rightBMS->getCoordinateFile(); const int node = cf->getCoordinateIndexClosestToPoint(xyz[0], xyz[1], xyz[2]); if (node >= 0) { const float dist = cf->getDistanceToPoint(node, xyz); if (dist < fiducialDistance) { fiducialDistance = dist; fiducialNodeNumber = node; fiducialBMS = rightBMS; } } } BrainModelSurface* cerebellumBMS = bs->getCerebellumFiducialVolumeInteractionSurface(); if (cerebellumBMS != NULL) { // // Find nearest node // const CoordinateFile* cf = cerebellumBMS->getCoordinateFile(); const int node = cf->getCoordinateIndexClosestToPoint(xyz[0], xyz[1], xyz[2]); if (node >= 0) { const float dist = cf->getDistanceToPoint(node, xyz); if (dist < fiducialDistance) { fiducialDistance = dist; fiducialNodeNumber = node; fiducialBMS = cerebellumBMS; } } } if (fiducialNodeNumber >= 0) { // // Highlight nearest node // selectedNode.reset(bs, fiducialBMS, viewingWindowNumber); selectedNode.setItemIndex1(fiducialNodeNumber); } } } } } // // Special processing for CoCoMac // if (selectionMask & SELECTION_MASK_NODE) { const int modelIndex = bm->getBrainModelIndex(); BrainModelSurfaceNodeColoring* bsnc = brainSet->getNodeColoring(); DisplaySettingsCoCoMac* dsc = brainSet->getDisplaySettingsCoCoMac(); if (brainSet->isASurfaceOverlay(modelIndex, BrainModelSurfaceOverlay::OVERLAY_COCOMAC)) { if (selectedNode.getItemIndex1() >= 0) { dsc->setSelectedNode(selectedNode.getItemIndex1()); } else { dsc->setSelectedNode(-1); } bsnc->assignColors(); } else { dsc->setSelectedNode(-1); } } // // Is this contours ? // if (dynamic_cast(bm) != NULL) { BrainModelContours* bmc = dynamic_cast(bm); const int contourNumber = selectedContour.getItemIndex1(); const int contourPointNumber = selectedContour.getItemIndex2(); if ((contourNumber >= 0) && (contourPointNumber >= 0)) { const ContourFile* cf = bmc->getContourFile(); const CaretContour* cc = cf->getContour(contourNumber); float xyz[3]; cc->getPointXYZ(contourPointNumber, xyz); // // Find fiducial coordinate file // BrainModelSurface* bms = bs->getActiveFiducialSurface(); if (bms != NULL) { // // Find nearest node // const CoordinateFile* cf = bms->getCoordinateFile(); const int node = cf->getCoordinateIndexClosestToPoint(xyz[0], xyz[1], xyz[2]); // // Highlight nearest node // if (node > 0) { selectedNode.reset(bs, bms, viewingWindowNumber); selectedNode.setItemIndex1(node); } } } } // // If axes selected in a view mode disable any node or voxel identification // if (selectedTransformationMatrixAxes.getItemIndex1() >= 0) { selectedNode.setItemIndex1(-1); selectedVoxelUnderlay.setItemIndex1(-1); selectedVoxelOverlaySecondary.setItemIndex1(-1); selectedVoxelOverlayPrimary.setItemIndex1(-1); selectedVoxelFunctionalCloud.setItemIndex1(-1); } } // if (viewModeFlag) selectionMask = SELECTION_MASK_OFF; brainSet = NULL; } /** * Called to process hits made while selecting objects with mouse. */ void BrainModelOpenGL::processSelectedItems(const int numItems) { GLuint* ptr = &selectionBuffer[0]; const float depthScale = static_cast(0x7fffffff); if (DebugControl::getDebugOn()) { std::cout << "Number of Hits: " << numItems << std::endl; } for (int i = 0; i < numItems; i++) { // // Number of names associated with this hit // const int nameStackSize = *ptr; ptr++; if (DebugControl::getDebugOn()) { std::cout << " Hit " << i << " contains " << nameStackSize << " items." << std::endl; } // // Depth of this hit // const float minDepth = static_cast(*ptr) / depthScale; ptr++; //const float maxDepth = static_cast(*ptr) / depthScale; ptr++; // skip over max depth unsigned long sm = SELECTION_MASK_OFF; int index1 = -1; int index2 = -1; int index3 = -1; int index4 = -1; int index5 = -1; int index6 = -1; for (int j = 0; j < nameStackSize; j++) { if (j == 0) { sm = static_cast(*ptr); ptr++; } else { if (j == 1) { index1 = *ptr; } else if (j == 2) { index2 = *ptr; } else if (j == 3) { index3 = *ptr; } else if (j == 4) { index4 = *ptr; } else if (j == 5) { index5 = *ptr; } else if (j == 6) { index6 = *ptr; } ptr++; } } if (DebugControl::getDebugOn()) { QString name("UNKNOWN"); switch(sm) { case SELECTION_MASK_OFF: name = "OFF"; break; case SELECTION_MASK_NODE: name = "NODE"; break; case SELECTION_MASK_BORDER: name = "BORDER"; break; case SELECTION_MASK_VOLUME_BORDER: name = "BORDER-VOLUME"; break; case SELECTION_MASK_CELL_PROJECTION: name = "CELL"; break; case SELECTION_MASK_VOLUME_CELL: name = "CELL-VOLUME"; break; case SELECTION_MASK_FOCUS_PROJECTION: name = "FOCIUS"; break; case SELECTION_MASK_VOLUME_FOCI: name = "FOCI-VOLUME"; break; case SELECTION_MASK_PALETTE_METRIC: name = "Palette Metric"; break; case SELECTION_MASK_PALETTE_SHAPE: name = "Palette Shape"; break; case SELECTION_MASK_CUT: name = "CUT"; break; case SELECTION_MASK_CONTOUR: name = "CONTOUR"; break; case SELECTION_MASK_CONTOUR_CELL: name = "CONTOUR CELL"; break; case SELECTION_MASK_VOXEL_UNDERLAY: name = "VOXEL UNDERLAY"; break; case SELECTION_MASK_VOXEL_OVERLAY_SECONDARY: name = "VOXEL SECONDARY OVERLAY"; break; case SELECTION_MASK_VOXEL_OVERLAY_PRIMARY: name = "VOXEL PRIMARY OVERLAY"; break; case SELECTION_MASK_VOXEL_FUNCTIONAL_CLOUD: name = "VOXEL_FUNCTIONAL"; break; case SELECTION_MASK_TILE: name = "TILE"; break; case SELECTION_MASK_LINK: name = "LINK"; break; case SELECTION_MASK_TRANSFORMATION_MATRIX_AXES: name = "TRANSFORMATION MATRIX AXES"; break; case SELECTION_MASK_VTK_MODEL: name = "VTK MODEL"; break; case SELECTION_MASK_ALL: name = "ALL"; break; case SELECTION_MASK_TRANSFORM_CELL: name = "CELL-TRANSFORM"; break; case SELECTION_MASK_TRANSFORM_FOCI: name = "FOCI-TRANSFORM"; break; case SELECTION_MASK_TRANSFORM_CONTOUR: name = "CONTOUR-TRANSFORM"; break; case SELECTION_MASK_TRANSFORM_CONTOUR_CELL: name = "CONTOUR-CELL-TRANSFORM"; break; } std::cout << " name: " << name.toAscii().constData() << " mask: " << sm << " indices: (" << index1 << ", " << index2 << ", " << index3 << ", " << index4 << ", " << index5 << ", " << index6 << ")" << std::endl; } if (index1 < 0) { continue; } float objectPos[3]; bool objectPosValid = false; BrainModelSurface* bms = dynamic_cast(brainModel); BrainModelSurfaceAndVolume* bmsv = dynamic_cast(brainModel); BrainModelContours* bmc = dynamic_cast(brainModel); BrainModelVolume* bmv = dynamic_cast(brainModel); // // Check for fiducial surface // bool fiducialSurfaceFlag = false; if (bms != NULL) { fiducialSurfaceFlag = ((bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_RAW) || (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FIDUCIAL)); } switch(sm) { case SELECTION_MASK_LINK: { if (bms != NULL) { const CoordinateFile* cf = bms->getCoordinateFile(); if (cf != NULL) { cf->getCoordinate(index1, objectPos); objectPosValid = true; } } else { if (bmsv != NULL) { const CoordinateFile* cf = bmsv->getCoordinateFile(); if (cf != NULL) { cf->getCoordinate(index1, objectPos); objectPosValid = true; } } } } break; case SELECTION_MASK_TILE: { if (bms != NULL) { const TopologyFile* tf = bms->getTopologyFile(); if (tf != NULL) { int nodes[3]; tf->getTile(index1, nodes); const CoordinateFile* cf = bms->getCoordinateFile(); cf->getCoordinate(nodes[0], objectPos); objectPosValid = true; } } else { if (bmsv != NULL) { const TopologyFile* tf = bmsv->getTopologyFile(); if (tf != NULL) { int nodes[3]; tf->getTile(index1, nodes); const CoordinateFile* cf = bmsv->getCoordinateFile(); cf->getCoordinate(nodes[0], objectPos); objectPosValid = true; } } } } break; case SELECTION_MASK_NODE: { if (bms != NULL) { const CoordinateFile* cf = bms->getCoordinateFile(); cf->getCoordinate(index1, objectPos); objectPosValid = true; } else { if (bmsv != NULL) { const CoordinateFile* cf = bmsv->getCoordinateFile(); cf->getCoordinate(index1, objectPos); objectPosValid = true; } } } break; case SELECTION_MASK_VOLUME_BORDER: if ((index1 >= 0) && (index2 >= 0)) { const BorderFile* bf = brainSet->getVolumeBorderFile(); const Border* b = bf->getBorder(index1); b->getLinkXYZ(index2, objectPos); objectPosValid = true; } break; case SELECTION_MASK_BORDER: if ((index2 >= 0) && (index3 >= 0)) { const BrainModelBorderSet* bmbs = brainSet->getBorderSet(); const BrainModelBorder* b = bmbs->getBorder(index2); const BrainModelBorderLink* link = b->getBorderLink(index3); link->getLinkPosition(index1, objectPos); objectPosValid = true; } break; case SELECTION_MASK_CELL_PROJECTION: if (index1 >= 0) { CellProjectionFile* cpf = brainSet->getCellProjectionFile(); if (index1 < cpf->getNumberOfCellProjections()) { if (bms != NULL) { CellProjection* cp = cpf->getCellProjection(index1); objectPosValid = cp->getProjectedPosition(bms->getCoordinateFile(), bms->getTopologyFile(), fiducialSurfaceFlag, false, false, objectPos); } } } break; case SELECTION_MASK_VOLUME_CELL: if (index1 >= 0) { CellFile* cf = brainSet->getVolumeCellFile(); CellData* cell = cf->getCell(index1); cell->getXYZ(objectPos); objectPosValid = true; } break; case SELECTION_MASK_CUT: if (index1 >= 0) { BorderFile* bf = brainSet->getCutsFile(); Border* b = bf->getBorder(index1); b->getLinkXYZ(index2, objectPos); objectPosValid = true; } break; case SELECTION_MASK_FOCUS_PROJECTION: if (index1 >= 0) { FociProjectionFile* fpf = brainSet->getFociProjectionFile(); if (index1 < fpf->getNumberOfCellProjections()) { if (bms != NULL) { CellProjection* cp = fpf->getCellProjection(index1); objectPosValid = cp->getProjectedPosition(bms->getCoordinateFile(), bms->getTopologyFile(), fiducialSurfaceFlag, false, false, objectPos); } } } break; case SELECTION_MASK_VOLUME_FOCI: if (index1 >= 0) { FociProjectionFile* fpf = brainSet->getFociProjectionFile(); CellProjection* focus = fpf->getCellProjection(index1); focus->getVolumeXYZ(objectPos); objectPosValid = true; } break; case SELECTION_MASK_TRANSFORM_FOCI: if ((index1 >= 0) && (index2 >= 0)) { FociFile* cf = dynamic_cast(brainSet->getTransformationDataFile(index1)); if (cf != NULL) { CellData* cell = cf->getCell(index2); cell->getXYZ(objectPos); objectPosValid = true; } } break; case SELECTION_MASK_TRANSFORM_CELL: if ((index1 >= 0) && (index2 >= 0)) { CellFile* cf = dynamic_cast(brainSet->getTransformationDataFile(index1)); if (cf != NULL) { CellData* cell = cf->getCell(index2); cell->getXYZ(objectPos); objectPosValid = true; } } break; case SELECTION_MASK_TRANSFORM_CONTOUR: if ((index1 >= 0) && (index2 >= 0)) { ContourFile* cf = dynamic_cast(brainSet->getTransformationDataFile(index1)); if (cf != NULL) { CaretContour* cc = cf->getContour(index2); cc->getPointXY(index2, objectPos[0], objectPos[1]); objectPos[2] = cc->getSectionNumber() * cf->getSectionSpacing(); objectPosValid = true; } } break; case SELECTION_MASK_TRANSFORM_CONTOUR_CELL: if ((index1 >= 0) && (index2 >= 0)) { ContourCellFile* cf = dynamic_cast(brainSet->getTransformationDataFile(index1)); if (cf != NULL) { CellData* cell = cf->getCell(index2); cell->getXYZ(objectPos); objectPosValid = true; } } break; case SELECTION_MASK_PALETTE_METRIC: selectedPaletteMetric.replaceIfCloser(0, 0, BrainModelOpenGLSelectedItem::ITEM_TYPE_PALETTE_METRIC, index1, index2); break; case SELECTION_MASK_PALETTE_SHAPE: selectedPaletteShape.replaceIfCloser(0, 0, BrainModelOpenGLSelectedItem::ITEM_TYPE_PALETTE_SHAPE, index1, index2); break; case SELECTION_MASK_CONTOUR: if (index2 >= 0) { if (bmc != NULL) { ContourFile* cf = bmc->getContourFile(); CaretContour* cc = cf->getContour(index1); cc->getPointXY(index2, objectPos[0], objectPos[1]); objectPos[2] = cc->getSectionNumber() * cf->getSectionSpacing(); objectPosValid = true; } } break; case SELECTION_MASK_CONTOUR_CELL: if (index1 >= 0) { if (bmc != NULL) { ContourFile* contourFile = bmc->getContourFile(); CellFile* cf = brainSet->getContourCellFile(); if (cf != NULL) { CellData* cd = cf->getCell(index1); cd->getXYZ(objectPos); objectPos[2] = cd->getSectionNumber() * contourFile->getSectionSpacing(); objectPosValid = true; } } } break; case SELECTION_MASK_VOXEL_UNDERLAY: if ((index1 >= 0) && (index2 >= 0) && (index3 >= 0)) { if (bmv != NULL) { VolumeFile* vf = bmv->getUnderlayVolumeFile(); if (vf != NULL) { float spacing[3]; float origin[3]; vf->getOrigin(origin); vf->getSpacing(spacing); objectPos[0] = spacing[0]*index1 + spacing[0]*0.5 + origin[0]; objectPos[1] = spacing[1]*index2 + spacing[1]*0.5 + origin[1]; objectPos[2] = spacing[2]*index3 + spacing[2]*0.5 + origin[2]; objectPosValid = true; } } else { if (bmsv != NULL) { VolumeFile* vf = bmsv->getAnatomyVolumeFile(); if (vf != NULL) { float spacing[3]; float origin[3]; vf->getOrigin(origin); vf->getSpacing(spacing); objectPos[0] = spacing[0]*index1 + spacing[0]*0.5 + origin[0]; objectPos[1] = spacing[1]*index2 + spacing[1]*0.5 + origin[1]; objectPos[2] = spacing[2]*index3 + spacing[2]*0.5 + origin[2]; objectPosValid = true; } } } } break; case SELECTION_MASK_VOXEL_OVERLAY_SECONDARY: if ((index1 >= 0) && (index2 >= 0) && (index3 >= 0)) { if (bmv != NULL) { VolumeFile* vf = bmv->getOverlaySecondaryVolumeFile(); if (vf != NULL) { float spacing[3]; float origin[3]; vf->getOrigin(origin); vf->getSpacing(spacing); objectPos[0] = spacing[0]*index1 + spacing[0]*0.5 + origin[0]; objectPos[1] = spacing[1]*index2 + spacing[1]*0.5 + origin[1]; objectPos[2] = spacing[2]*index3 + spacing[2]*0.5 + origin[2]; objectPosValid = true; } } else { if (bmsv != NULL) { VolumeFile* vf = bmsv->getOverlaySecondaryVolumeFile(); if (vf != NULL) { float spacing[3]; float origin[3]; vf->getOrigin(origin); vf->getSpacing(spacing); objectPos[0] = spacing[0]*index1 + spacing[0]*0.5 + origin[0]; objectPos[1] = spacing[1]*index2 + spacing[1]*0.5 + origin[1]; objectPos[2] = spacing[2]*index3 + spacing[2]*0.5 + origin[2]; objectPosValid = true; } } } } break; case SELECTION_MASK_VOXEL_OVERLAY_PRIMARY: if ((index1 >= 0) && (index2 >= 0) && (index3 >= 0)) { if (bmv != NULL) { VolumeFile* vf = bmv->getOverlayPrimaryVolumeFile(); if (vf != NULL) { float spacing[3]; float origin[3]; vf->getOrigin(origin); vf->getSpacing(spacing); objectPos[0] = spacing[0]*index1 + spacing[0]*0.5 + origin[0]; objectPos[1] = spacing[1]*index2 + spacing[1]*0.5 + origin[1]; objectPos[2] = spacing[2]*index3 + spacing[2]*0.5 + origin[2]; objectPosValid = true; } } else { if (bmsv != NULL) { VolumeFile* vf = bmsv->getOverlayPrimaryVolumeFile(); if (vf != NULL) { float spacing[3]; float origin[3]; vf->getOrigin(origin); vf->getSpacing(spacing); objectPos[0] = spacing[0]*index1 + spacing[0]*0.5 + origin[0]; objectPos[1] = spacing[1]*index2 + spacing[1]*0.5 + origin[1]; objectPos[2] = spacing[2]*index3 + spacing[2]*0.5 + origin[2]; objectPosValid = true; } } } } break; case SELECTION_MASK_VOXEL_FUNCTIONAL_CLOUD: { if (bmsv != NULL) { VolumeFile* vf = bmsv->getFunctionalVolumeFile(); if (vf != NULL) { float spacing[3]; float origin[3]; vf->getOrigin(origin); vf->getSpacing(spacing); objectPos[0] = spacing[0]*index1 + spacing[0]*0.5 + origin[0]; objectPos[1] = spacing[1]*index2 + spacing[1]*0.5 + origin[1]; objectPos[2] = spacing[2]*index3 + spacing[2]*0.5 + origin[2]; objectPosValid = true; } } } break; case SELECTION_MASK_TRANSFORMATION_MATRIX_AXES: { TransformationMatrixFile* tmf = brainSet->getTransformationMatrixFile(); if ((index1 >= 0) && (index1 < tmf->getNumberOfMatrices())) { TransformationMatrix* tm = tmf->getTransformationMatrix(index1); tm->getTranslation(objectPos[0], objectPos[1], objectPos[2]); objectPosValid = true; } } break; case SELECTION_MASK_VTK_MODEL: { if ((index1 >= 0) && (index1 < brainSet->getNumberOfVtkModelFiles())) { VtkModelFile* vmf = brainSet->getVtkModelFile(index1); vmf->getTriangleCoordinate(index3, objectPos); const TransformationMatrixFile* tmf = brainSet->getTransformationMatrixFile(); const TransformationMatrix* tm = vmf->getAssociatedTransformationMatrix(); if (tmf->getMatrixValid(tm)) { //tm->multiplyPoint(objectPos); } objectPosValid = true; } } break; case SELECTION_MASK_OFF: case SELECTION_MASK_ALL: default: break; } if (objectPosValid) { GLdouble windowPos[3]; if (gluProject(objectPos[0], objectPos[1], objectPos[2], selectionModelviewMatrix[viewingWindowNumber], selectionProjectionMatrix[viewingWindowNumber], selectionViewport[viewingWindowNumber], &windowPos[0], &windowPos[1], &windowPos[2]) == GL_TRUE) { const double dx = windowPos[0] - selectionX; const double dy = windowPos[1] - selectionY; const double dist = std::sqrt(dx*dx + dy*dy); if (DebugControl::getDebugOn()) { std::cout << " minDepth=" << minDepth << ", dist=" << dist << std::endl; } switch(sm) { case SELECTION_MASK_TILE: selectedSurfaceTile.replaceIfCloser(minDepth, dist, BrainModelOpenGLSelectedItem::ITEM_TYPE_TILE, index1, index2); break; case SELECTION_MASK_NODE: selectedNode.replaceIfCloser(minDepth, dist, BrainModelOpenGLSelectedItem::ITEM_TYPE_NODE, index1, index2); break; case SELECTION_MASK_LINK: selectedLink.replaceIfCloser(minDepth, dist, BrainModelOpenGLSelectedItem::ITEM_TYPE_LINK, index1, index2); break; case SELECTION_MASK_VOLUME_BORDER: selectedVolumeBorder.replaceIfCloser(minDepth, dist, BrainModelOpenGLSelectedItem::ITEM_TYPE_VOLUME_BORDER, index1, index2); break; case SELECTION_MASK_BORDER: { const BrainModelOpenGLSelectedItem::ITEM_TYPE itemType = BrainModelOpenGLSelectedItem::ITEM_TYPE_BORDER; // // Two borders can be highlighted. // const BrainModelOpenGLSelectedItem savedBorder1 = selectedBorder1; if (selectedBorder1.replaceIfCloser(minDepth, dist, itemType, index1, index2, index3)) { // // Do not let same border in both border selections // index1 is border file number, index2 is border number // if (savedBorder1.getItemIndex1() != index1) { selectedBorder2 = savedBorder1; } else if (savedBorder1.getItemIndex2() != index2) { selectedBorder2 = savedBorder1; } // // If new border 1 selection is same border as in border 2 // else if (index1 == selectedBorder2.getItemIndex1()) { selectedBorder2 = savedBorder1; } } else { // // Do not allow same border for both border selections // index1 is border file number, index2 is border number // if (selectedBorder1.getItemIndex1() != index1) { selectedBorder2.replaceIfCloser(minDepth, dist, itemType, index1, index2, index3); } else if (selectedBorder1.getItemIndex2() != index2) { selectedBorder2.replaceIfCloser(minDepth, dist, itemType, index1, index2, index3); } } } break; case SELECTION_MASK_CELL_PROJECTION: selectedCellProjection.replaceIfCloser(minDepth, dist, BrainModelOpenGLSelectedItem::ITEM_TYPE_CELL_PROJECTION, index1); break; case SELECTION_MASK_VOLUME_CELL: selectedVolumeCell.replaceIfCloser(minDepth, dist, BrainModelOpenGLSelectedItem::ITEM_TYPE_VOLUME_CELL, index1); break; case SELECTION_MASK_CUT: selectedCut.replaceIfCloser(minDepth, dist, BrainModelOpenGLSelectedItem::ITEM_TYPE_CUT, index1, index2); break; case SELECTION_MASK_FOCUS_PROJECTION: selectedFocusProjection.replaceIfCloser(minDepth, dist, BrainModelOpenGLSelectedItem::ITEM_TYPE_FOCUS_PROJECTION, index1); break; case SELECTION_MASK_VOLUME_FOCI: selectedVolumeFoci.replaceIfCloser(minDepth, dist, BrainModelOpenGLSelectedItem::ITEM_TYPE_VOLUME_FOCI, index1); break; case SELECTION_MASK_TRANSFORM_CELL: selectedTransformCell.replaceIfCloser(minDepth, dist, BrainModelOpenGLSelectedItem::ITEM_TYPE_TRANSFORM_CELL, index1, index2); break; case SELECTION_MASK_TRANSFORM_FOCI: selectedTransformFoci.replaceIfCloser(minDepth, dist, BrainModelOpenGLSelectedItem::ITEM_TYPE_TRANSFORM_FOCI, index1, index2); break; case SELECTION_MASK_TRANSFORM_CONTOUR: selectedTransformContour.replaceIfCloser(minDepth, dist, BrainModelOpenGLSelectedItem::ITEM_TYPE_TRANSFORM_CONTOUR, index1, index2); break; case SELECTION_MASK_TRANSFORM_CONTOUR_CELL: selectedTransformContourCell.replaceIfCloser(minDepth, dist, BrainModelOpenGLSelectedItem::ITEM_TYPE_TRANSFORM_CONTOUR_CELL, index1, index2); case SELECTION_MASK_PALETTE_METRIC: break; case SELECTION_MASK_PALETTE_SHAPE: break; case SELECTION_MASK_CONTOUR: selectedContour.replaceIfCloser(minDepth, dist, BrainModelOpenGLSelectedItem::ITEM_TYPE_CONTOUR, index1, index2, index3); break; case SELECTION_MASK_CONTOUR_CELL: selectedContourCell.replaceIfCloser(minDepth, dist, BrainModelOpenGLSelectedItem::ITEM_TYPE_CONTOUR_CELL, index1); break; case SELECTION_MASK_VOXEL_UNDERLAY: selectedVoxelUnderlay.replaceIfCloser(minDepth, dist, BrainModelOpenGLSelectedItem::ITEM_TYPE_VOXEL_UNDERLAY, index1, index2, index3, index4, index5, index6); break; case SELECTION_MASK_VOXEL_OVERLAY_SECONDARY: selectedVoxelOverlaySecondary.replaceIfCloser(minDepth, dist, BrainModelOpenGLSelectedItem::ITEM_TYPE_VOXEL_OVERLAY_SECONDARY, index1, index2, index3, index4, index5, index6); break; case SELECTION_MASK_VOXEL_OVERLAY_PRIMARY: selectedVoxelOverlayPrimary.replaceIfCloser(minDepth, dist, BrainModelOpenGLSelectedItem::ITEM_TYPE_VOXEL_OVERLAY_PRIMARY, index1, index2, index3, index4, index5, index6); break; case SELECTION_MASK_VOXEL_FUNCTIONAL_CLOUD: selectedVoxelFunctionalCloud.replaceIfCloser(minDepth, dist, BrainModelOpenGLSelectedItem::ITEM_TYPE_VOXEL_FUNCTIONAL_CLOUD, index1, index2, index3); break; case SELECTION_MASK_TRANSFORMATION_MATRIX_AXES: selectedTransformationMatrixAxes.replaceIfCloser(minDepth, dist, BrainModelOpenGLSelectedItem::ITEM_TYPE_TRANSFORMATION_MATRIX_AXES, index1); break; case SELECTION_MASK_VTK_MODEL: selectedVtkModel.replaceIfCloser(minDepth, dist, BrainModelOpenGLSelectedItem::ITEM_TYPE_VTK_MODEL, index1, index2, index3); break; case SELECTION_MASK_OFF: case SELECTION_MASK_ALL: default: break; } } } } } /** * Get the dimensions of the surface orthographic projection */ void BrainModelOpenGL::getOrthographicBox(const int modelViewNumber, double& orthoLeft, double& orthoRight, double& orthoBottom, double& orthoTop, double& orthoNear, double& orthoFar) const { orthoLeft = orthographicLeft[modelViewNumber]; orthoRight = orthographicRight[modelViewNumber]; orthoBottom = orthographicBottom[modelViewNumber]; orthoTop = orthographicTop[modelViewNumber]; orthoNear = orthographicNear[modelViewNumber]; orthoFar = orthographicFar[modelViewNumber]; } /** * set the image subregion box/display. */ void BrainModelOpenGL::setImageSubRegion(const int box[4], const bool showFlag) { imageSubRegionBox[0] = box[0]; imageSubRegionBox[1] = box[1]; imageSubRegionBox[2] = box[2]; imageSubRegionBox[3] = box[3]; drawImageSubRegionBoxFlag = showFlag; } /** * get valid line width. */ GLfloat BrainModelOpenGL::getValidLineWidth(const float widthIn) const { GLfloat width = widthIn; if (width > maximumLineWidth) { width = maximumLineWidth; } else if (width < minimumLineWidth) { width = minimumLineWidth; } return width; } /** * get valid point size. */ GLfloat BrainModelOpenGL::getValidPointSize(const float pointSizeIn) const { GLfloat pointSize = pointSizeIn; if (pointSize > maximumPointSize) { pointSize = maximumPointSize; } else if (pointSize < minimumPointSize) { pointSize = minimumPointSize; } return pointSize; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelIdentification.h0000664000175000017500000015066011572067322024754 0ustar michaelmichael #ifndef __BRAIN_MODEL_IDENTIFICATION_H__ #define __BRAIN_MODEL_IDENTIFICATION_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelOpenGLSelectedItem.h" #include "SceneFile.h" #include "StudyMetaDataFile.h" class BrainModelOpenGL; class BrainModelSurface; class BrainModelVolume; class BrainSet; class CellProjection; class FociFile; class StudyMetaDataLink; class StudyMetaDataLinkSet; class VolumeFile; /// class for providing identification information class BrainModelIdentification : public QObject { public: // constructor BrainModelIdentification(BrainSet* brainSetIn, QObject* parent = 0); // destructor ~BrainModelIdentification(); // get the identification text for all QString getIdentificationText(BrainModelOpenGL* openGL, const bool enableHtml, const bool enableVocabularyLinksIn); // get the identification text for node only QString getIdentificationTextForNode(BrainModelOpenGL* openGL, const bool enableHtml, const bool enableVocabularyLinksIn); // get the identification text for node by its number QString getIdentificationTextForNode(BrainSet* brainSet, const int NodeNumber, const bool enableHtml, const bool enableVocabularyLinksIn); // get the identification text for cell only QString getIdentificationTextForCell(BrainModelOpenGL* openGL, const bool enableHtml, const bool enableVocabularyLinksIn); // get the identification text for focus only QString getIdentificationTextForFocus(BrainModelOpenGL* openGL, const bool enableHtml, const bool enableVocabularyLinksIn); // get the identification text for border only QString getIdentificationTextForBorder(BrainModelOpenGL* openGL, const bool enableHtml, const bool enableVocabularyLinksIn); // get the identification text for studies QString getIdentificationTextForStudies(const bool enableHtml, const StudyMetaDataFile* smdf, const StudyMetaDataLinkSet& smdls); // get the identification text for a study QString getIdentificationTextForStudy(const bool enableHtml, const StudyMetaData* smd, const int studyIndex, const StudyMetaDataLink* smdl = NULL); // get the identification text for vocabulary QString getIdentificationTextForVocabulary(const bool enableHtml, const QString& vocabularyName); /// find out if border information should be displayed bool getDisplayBorderInformation() const { return idFilter.displayBorderInformation; } /// find out if cell information should be displayed bool getDisplayCellInformation() const { return idFilter.displayCellInformation; } /// find out if voxel information should be displayed bool getDisplayVoxelInformation() const { return idFilter.displayVoxelInformation; } /// find out if contour information should be displayed bool getDisplayContourInformation() const { return idFilter.displayContourInformation; } /// find out if node information should be displayed bool getDisplayNodeInformation() const { return idFilter.displayNodeInformation; } /// find out if node coordinate information should be displayed bool getDisplayNodeCoordInformation() const { return idFilter.displayNodeCoordInformation; } /// find out if node lat/lon information should be displayed bool getDisplayNodeLatLonInformation() const { return idFilter.displayNodeLatLonInformation;} /// find out if node paint information should be displayed bool getDisplayNodePaintInformation() const { return idFilter.displayNodePaintInformation; } /// find out if node prob atlas information should be displayed bool getDisplayNodeProbAtlasInformation() const { return idFilter.displayNodeProbAtlasInformation; } /// find out if node rgb paint information should be displayed bool getDisplayNodeRgbPaintInformation() const { return idFilter.displayNodeRgbPaintInformation; } /// find out if node metric information should be displayed bool getDisplayNodeMetricInformation() const { return idFilter.displayNodeMetricInformation; } /// find out if node surface shape information should be displayed bool getDisplayNodeShapeInformation() const { return idFilter.displayNodeShapeInformation; } /// find out if node metric information should be displayed bool getDisplayNodeSectionInformation() const { return idFilter.displayNodeSectionInformation; } /// find out if node areal est information should be displayed bool getDisplayNodeArealEstInformation() const { return idFilter.displayNodeArealEstInformation; } /// find out if node topography information should be displayed bool getDisplayNodeTopographyInformation() const { return idFilter.displayNodeTopographyInformation; } /// find out if foci information should be displayed bool getDisplayFociInformation() const { return idFilter.displayFociInformation; } /// foci name information should be displayed bool getDisplayFociNameInformation() const { return idFilter.displayFociNameInformation; } /// foci class information should be displayed bool getDisplayFociClassInformation() const { return idFilter.displayFociClassInformation; } /// foci original stereotaxic position information should be displayed bool getDisplayFociOriginalStereotaxicPositionInformation() const { return idFilter.displayFociOriginalStereotaxicPositionInformation; } /// foci stereotaxic position information should be displayed bool getDisplayFociStereotaxicPositionInformation() const { return idFilter.displayFociStereotaxicPositionInformation; } /// foci area information should be displayed bool getDisplayFociAreaInformation() const { return idFilter.displayFociAreaInformation; } /// foci geography information should be displayed bool getDisplayFociGeographyInformation() const { return idFilter.displayFociGeographyInformation; } /// foci region of interest information should be displayed bool getDisplayFociRegionOfInterestInformation() const { return idFilter.displayFociRegionOfInterestInformation; } /// foci size information should be displayed bool getDisplayFociSizeInformation() const { return idFilter.displayFociSizeInformation; } /// foci structure information should be displayed bool getDisplayFociStructureInformation() const { return idFilter.displayFociStructureInformation; } /// foci statistic information should be displayed bool getDisplayFociStatisticInformation() const { return idFilter.displayFociStatisticInformation; } /// foci comment information should be displayed bool getDisplayFociCommentInformation() const { return idFilter.displayFociCommentInformation; } /// find out if study information should be displayed bool getDisplayStudyInformation() const { return idFilter.displayStudyInformation; } /// study title information should be displayed bool getDisplayStudyTitleInformation() const { return idFilter.displayStudyTitleInformation; } /// study authors information should be displayed bool getDisplayStudyAuthorsInformation() const { return idFilter.displayStudyAuthorsInformation; } /// study citation information should be displayed bool getDisplayStudyCitationInformation() const { return idFilter.displayStudyCitationInformation; } /// study comment information should be displayed bool getDisplayStudyCommentInformation() const { return idFilter.displayStudyCommentInformation; } /// study data format information should be displayed bool getDisplayStudyDataFormatInformation() const { return idFilter.displayStudyDataFormatInformation; } /// study data type information should be displayed bool getDisplayStudyDataTypeInformation() const { return idFilter.displayStudyDataTypeInformation; } /// study DOI information should be displayed bool getDisplayStudyDOIInformation() const { return idFilter.displayStudyDOIInformation; } /// study keywords information should be displayed bool getDisplayStudyKeywordsInformation() const { return idFilter.displayStudyKeywordsInformation; } /// study medical subject headings information should be displayed bool getDisplayStudyMedicalSubjectHeadingsInformation() const { return idFilter.displayStudyMedicalSubjectHeadingsInformation; } /// study meta-analysis information should be displayed bool getDisplayStudyMetaAnalysisInformation() const { return idFilter.displayStudyMetaAnalysisInformation; } /// study meta-analysis name information should be displayed bool getDisplayStudyMetaAnalysisNameInformation() const { return idFilter.displayStudyMetaAnalysisNameInformation; } /// study meta-analysis title information should be displayed bool getDisplayStudyMetaAnalysisTitleInformation() const { return idFilter.displayStudyMetaAnalysisTitleInformation; } /// study meta-analysis authors information should be displayed bool getDisplayStudyMetaAnalysisAuthorsInformation() const { return idFilter.displayStudyMetaAnalysisAuthorsInformation; } /// study meta-analysis citation information should be displayed bool getDisplayStudyMetaAnalysisCitationInformation() const { return idFilter.displayStudyMetaAnalysisCitationInformation; } /// study meta-analysis DOI/URL information should be displayed bool getDisplayStudyMetaAnalysisDoiUrlInformation() const { return idFilter.displayStudyMetaAnalysisDoiUrlInformation; } /// study name should be displayed bool getDisplayStudyNameInformation() const { return idFilter.displayStudyNameInformation; } /// study part scheme abbreviation information should be displayed bool getDisplayStudyPartSchemeAbbrevInformation() const { return idFilter.displayStudyPartSchemeAbbrevInformation; } /// study part scheme full name information should be displayed bool getDisplayStudyPartSchemeFullInformation() const { return idFilter.displayStudyPartSchemeFullInformation; } /// study PubMed ID information should be displayed bool getDisplayStudyPubMedIDInformation() const { return idFilter.displayStudyPubMedIDInformation; } /// study Project ID information should be displayed bool getDisplayStudyProjectIDInformation() const { return idFilter.displayStudyProjectIDInformation; } /// study stereotaxic space information should be displayed bool getDisplayStudyStereotaxicSpaceInformation() const { return idFilter.displayStudyStereotaxicSpaceInformation; } /// study stereotaxic space details information should be displayed bool getDisplayStudyStereotaxicSpaceDetailsInformation() const { return idFilter.displayStudyStereotaxicSpaceDetailsInformation; } /// study URL information should be displayed bool getDisplayStudyURLInformation() const { return idFilter.displayStudyURLInformation; } /// study table information should be displayed bool getDisplayStudyTableInformation() const { return idFilter.displayStudyTableInformation; } /// study table header information should be displayed bool getDisplayStudyTableHeaderInformation() const { return idFilter.displayStudyTableHeaderInformation; } /// study table footer information should be displayed bool getDisplayStudyTableFooterInformation() const { return idFilter.displayStudyTableFooterInformation; } /// study table size units information should be displayed bool getDisplayStudyTableSizeUnitsInformation() const { return idFilter.displayStudyTableSizeUnitsInformation; } /// study table voxel size information should be displayed bool getDisplayStudyTableVoxelSizeInformation() const { return idFilter.displayStudyTableVoxelSizeInformation; } /// study table statistic information should be displayed bool getDisplayStudyTableStatisticInformation() const { return idFilter.displayStudyTableStatisticInformation; } /// study table statistic description information should be displayed bool getDisplayStudyTableStatisticDescriptionInformation() const { return idFilter.displayStudyTableStatisticDescriptionInformation; } /// study figure information should be displayed bool getDisplayStudyFigureInformation() const { return idFilter.displayStudyFigureInformation; } /// study figure legend information should be displayed bool getDisplayStudyFigureLegendInformation() const { return idFilter.displayStudyFigureLegendInformation; } /// study figure panel information should be displayed bool getDisplayStudyFigurePanelInformation() const { return idFilter.displayStudyFigurePanelInformation; } /// study figure panel description information should be displayed bool getDisplayStudyFigurePanelDescriptionInformation() const { return idFilter.displayStudyFigurePanelDescriptionInformation; } /// study figure panel task description information should be displayed bool getDisplayStudyFigurePanelTaskDescriptionInformation() const { return idFilter.displayStudyFigurePanelTaskDescriptionInformation; } /// study figure panel task baseline information should be displayed bool getDisplayStudyFigurePanelTaskBaselineInformation() const { return idFilter.displayStudyFigurePanelTaskBaselineInformation; } /// study figure panel test attributesinformation should be displayed bool getDisplayStudyFigurePanelTestAttributesInformation() const { return idFilter.displayStudyFigurePanelTestAttributesInformation; } /// study sub header information should be displayed bool getDisplayStudySubHeaderInformation() const { return idFilter.displayStudySubHeaderInformation; } /// study sub header name information should be displayed bool getDisplayStudySubHeaderNameInformation() const { return idFilter.displayStudySubHeaderNameInformation; } /// study sub header short name information should be displayed bool getDisplayStudySubHeaderShortNameInformation() const { return idFilter.displayStudySubHeaderShortNameInformation; } /// study sub header task description information should be displayed bool getDisplayStudySubHeaderTaskDescriptionInformation() const { return idFilter.displayStudySubHeaderTaskDescriptionInformation; } /// study sub header task baseline information should be displayed bool getDisplayStudySubHeaderTaskBaselineInformation() const { return idFilter.displayStudySubHeaderTaskBaselineInformation; } /// study sub header test attributes information should be displayed bool getDisplayStudySubHeaderTestAttributesInformation() const { return idFilter.displayStudySubHeaderTestAttributesInformation; } /// study page reference information should be displayed bool getDisplayStudyPageReferenceInformation() const { return idFilter.displayStudyPageReferenceInformation; } /// study page reference header information should be displayed bool getDisplayStudyPageReferenceHeaderInformation() const { return idFilter.displayStudyPageReferenceHeaderInformation; } /// study page reference comment information should be displayed bool getDisplayStudyPageReferenceCommentInformation() const { return idFilter.displayStudyPageReferenceCommentInformation; } /// study page reference size units information should be displayed bool getDisplayStudyPageReferenceSizeUnitsInformation() const { return idFilter.displayStudyPageReferenceSizeUnitsInformation; } /// study page reference voxel size information should be displayed bool getDisplayStudyPageReferenceVoxelSizeInformation() const { return idFilter.displayStudyPageReferenceVoxelSizeInformation; } /// study page reference statistic information should be displayed bool getDisplayStudyPageReferenceStatisticInformation() const { return idFilter.displayStudyPageReferenceStatisticInformation; } /// study page reference statistic description information should be displayed bool getDisplayStudyPageReferenceStatisticDescriptionInformation() const { return idFilter.displayStudyPageReferenceStatisticDescriptionInformation; } /// study page number information should be displayed //bool getDisplayStudyPageNumberInformation() const { return idFilter.displayStudyPageNumberInformation; } /// find out if green symbols should be displayed on surface bool getDisplayIDSymbol() const { return displayIDSymbol; } /// get significant digits for floating point numbers int getSignificantDigits() const { return significantDigits; } // apply a scene (update dialog) void showScene(const SceneFile::Scene& scene, QString& errorMessage); // create a scene (save dialog settings) void saveScene(SceneFile::Scene& scene); public slots: /// set border information should be displayed void setDisplayBorderInformation(const bool displayIt) { idFilter.displayBorderInformation = displayIt; } /// set cell information should be displayed void setDisplayCellInformation(const bool displayIt) { idFilter.displayCellInformation = displayIt; } /// set voxel information should be displayed void setDisplayVoxelInformation(const bool displayIt) { idFilter.displayVoxelInformation = displayIt; } /// set contour information should be displayed void setDisplayContourInformation(const bool displayIt) { idFilter.displayContourInformation = displayIt; } /// set node information should be displayed void setDisplayNodeInformation(const bool displayIt) { idFilter.displayNodeInformation = displayIt; } /// set node coordinate information should be displayed void setDisplayNodeCoordInformation(const bool displayIt) { idFilter.displayNodeCoordInformation = displayIt; } /// set node lat/lon information should be displayed void setDisplayNodeLatLonInformation(const bool displayIt) { idFilter.displayNodeLatLonInformation = displayIt;} /// set node paint information should be displayed void setDisplayNodePaintInformation(const bool displayIt) { idFilter.displayNodePaintInformation = displayIt; } /// set node prob atlas information should be displayed void setDisplayNodeProbAtlasInformation(const bool displayIt) { idFilter.displayNodeProbAtlasInformation = displayIt; } /// set node rgb paint information should be displayed void setDisplayNodeRgbPaintInformation(const bool displayIt) { idFilter.displayNodeRgbPaintInformation = displayIt; } /// set node metric information should be displayed void setDisplayNodeMetricInformation(const bool displayIt) { idFilter.displayNodeMetricInformation = displayIt; } /// set node surface shape information should be displayed void setDisplayNodeShapeInformation(const bool displayIt) { idFilter.displayNodeShapeInformation = displayIt; } /// set node metric information should be displayed void setDisplayNodeSectionInformation(const bool displayIt) { idFilter.displayNodeSectionInformation = displayIt; } /// set node areal est information should be displayed void setDisplayNodeArealEstInformation(const bool displayIt) { idFilter.displayNodeArealEstInformation = displayIt; } /// set node topography information should be displayed void setDisplayNodeTopographyInformation(const bool displayIt) { idFilter.displayNodeTopographyInformation = displayIt; } /// set foci information should be displayed void setDisplayFociInformation(const bool displayIt) { idFilter.displayFociInformation = displayIt; } /// foci name information should be displayed void setDisplayFociNameInformation(const bool displayIt) { idFilter.displayFociNameInformation = displayIt; } /// foci class information should be displayed void setDisplayFociClassInformation(const bool displayIt) { idFilter.displayFociClassInformation = displayIt; } /// foci original stereotaxic position information should be displayed void setDisplayFociOriginalStereotaxicPositionInformation(const bool displayIt) { idFilter.displayFociOriginalStereotaxicPositionInformation = displayIt; } /// foci stereotaxic position information should be displayed void setDisplayFociStereotaxicPositionInformation(const bool displayIt) { idFilter.displayFociStereotaxicPositionInformation = displayIt; } /// foci area information should be displayed void setDisplayFociAreaInformation(const bool displayIt) { idFilter.displayFociAreaInformation = displayIt; } /// foci geography information should be displayed void setDisplayFociGeographyInformation(const bool displayIt) { idFilter.displayFociGeographyInformation = displayIt; } /// foci region of interest information should be displayed void setDisplayFociRegionOfInterestInformation(const bool displayIt) { idFilter.displayFociRegionOfInterestInformation = displayIt; } /// foci size information should be displayed void setDisplayFociSizeInformation(const bool displayIt) { idFilter.displayFociSizeInformation = displayIt; } /// foci structure information should be displayed void setDisplayFociStructureInformation(const bool displayIt) { idFilter.displayFociStructureInformation = displayIt; } /// foci statistic information should be displayed void setDisplayFociStatisticInformation(const bool displayIt) { idFilter.displayFociStatisticInformation = displayIt; } /// foci comment information should be displayed void setDisplayFociCommentInformation(const bool displayIt) { idFilter.displayFociCommentInformation = displayIt; } /// set study information should be displayed void setDisplayStudyInformation(const bool displayIt) { idFilter.displayStudyInformation = displayIt; } /// study title information should be displayed void setDisplayStudyTitleInformation(const bool displayIt) { idFilter.displayStudyTitleInformation = displayIt; } /// study authors information should be displayed void setDisplayStudyAuthorsInformation(const bool displayIt) { idFilter.displayStudyAuthorsInformation = displayIt; } /// study citation information should be displayed void setDisplayStudyCitationInformation(const bool displayIt) { idFilter.displayStudyCitationInformation = displayIt; } /// study comment information should be displayed void setDisplayStudyCommentInformation(const bool displayIt) { idFilter.displayStudyCommentInformation = displayIt; } /// study data format information should be displayed void setDisplayStudyDataFormatInformation(const bool displayIt) { idFilter.displayStudyDataFormatInformation = displayIt; } /// study data type information should be displayed void setDisplayStudyDataTypeInformation(const bool displayIt) { idFilter.displayStudyDataTypeInformation = displayIt; } /// study DOI information should be displayed void setDisplayStudyDOIInformation(const bool displayIt) { idFilter.displayStudyDOIInformation = displayIt; } /// study keywords information should be displayed void setDisplayStudyKeywordsInformation(const bool displayIt) { idFilter.displayStudyKeywordsInformation = displayIt; } /// study medical subject headings should be displayed void setDisplayStudyMedicalSubjectHeadingsInformation(const bool displayIt) { idFilter.displayStudyMedicalSubjectHeadingsInformation = displayIt; } /// study meta-analysis should be displayed void setDisplayStudyMetaAnalysisInformation(const bool displayIt) { idFilter.displayStudyMetaAnalysisInformation = displayIt; } /// study meta-analysis name should be displayed void setDisplayStudyMetaAnalysisNameInformation(const bool displayIt) { idFilter.displayStudyMetaAnalysisNameInformation = displayIt; } /// study meta-analysis title should be displayed void setDisplayStudyMetaAnalysisTitleInformation(const bool displayIt) { idFilter.displayStudyMetaAnalysisTitleInformation = displayIt; } /// study meta-analysis authors should be displayed void setDisplayStudyMetaAnalysisAuthorsInformation(const bool displayIt) { idFilter.displayStudyMetaAnalysisAuthorsInformation = displayIt; } /// study meta-analysis citation should be displayed void setDisplayStudyMetaAnalysisCitationInformation(const bool displayIt) { idFilter.displayStudyMetaAnalysisCitationInformation = displayIt; } /// study meta-analysis DOI/URL should be displayed void setDisplayStudyMetaAnalysisDoiUrlInformation(const bool displayIt) { idFilter.displayStudyMetaAnalysisDoiUrlInformation = displayIt; } /// study name should be displayed void setDisplayStudyNameInformation(const bool displayIt) { idFilter.displayStudyNameInformation = displayIt; } /// study part scheme abbreviation information should be displayed void setDisplayStudyPartSchemeAbbrevInformation(const bool displayIt) { idFilter.displayStudyPartSchemeAbbrevInformation = displayIt; } /// study part scheme full name information should be displayed void setDisplayStudyPartSchemeFullInformation(const bool displayIt) { idFilter.displayStudyPartSchemeFullInformation = displayIt; } /// study PubMed ID information should be displayed void setDisplayStudyPubMedIDInformation(const bool displayIt) { idFilter.displayStudyPubMedIDInformation = displayIt; } /// study Project ID information should be displayed void setDisplayStudyProjectIDInformation(const bool displayIt) { idFilter.displayStudyProjectIDInformation = displayIt; } /// study stereotaxic space information should be displayed void setDisplayStudyStereotaxicSpaceInformation(const bool displayIt) { idFilter.displayStudyStereotaxicSpaceInformation = displayIt; } /// study stereotaxic space details information should be displayed void setDisplayStudyStereotaxicSpaceDetailsInformation(const bool displayIt) { idFilter.displayStudyStereotaxicSpaceDetailsInformation = displayIt; } /// study URL information should be displayed void setDisplayStudyURLInformation(const bool displayIt) { idFilter.displayStudyURLInformation = displayIt; } /// study table information should be displayed void setDisplayStudyTableInformation(const bool displayIt) { idFilter.displayStudyTableInformation = displayIt; } /// study table header information should be displayed void setDisplayStudyTableHeaderInformation(const bool displayIt) { idFilter.displayStudyTableHeaderInformation = displayIt; } /// study table footer information should be displayed void setDisplayStudyTableFooterInformation(const bool displayIt) { idFilter.displayStudyTableFooterInformation = displayIt; } /// study table size units information should be displayed void setDisplayStudyTableSizeUnitsInformation(const bool displayIt) { idFilter.displayStudyTableSizeUnitsInformation = displayIt; } /// study table voxel size information should be displayed void setDisplayStudyTableVoxelSizeInformation(const bool displayIt) { idFilter.displayStudyTableVoxelSizeInformation = displayIt; } /// study table statistic information should be displayed void setDisplayStudyTableStatisticInformation(const bool displayIt) { idFilter.displayStudyTableStatisticInformation = displayIt; } /// study table statistic description information should be displayed void setDisplayStudyTableStatisticDescriptionInformation(const bool displayIt) { idFilter.displayStudyTableStatisticDescriptionInformation = displayIt; } /// study figure information should be displayed void setDisplayStudyFigureInformation(const bool displayIt) { idFilter.displayStudyFigureInformation = displayIt; } /// study figure legend information should be displayed void setDisplayStudyFigureLegendInformation(const bool displayIt) { idFilter.displayStudyFigureLegendInformation = displayIt; } /// study figure panel information should be displayed void setDisplayStudyFigurePanelInformation(const bool displayIt) { idFilter.displayStudyFigurePanelInformation = displayIt; } /// study figure panel description information should be displayed void setDisplayStudyFigurePanelDescriptionInformation(const bool displayIt) { idFilter.displayStudyFigurePanelDescriptionInformation = displayIt; } /// study figure panel task description information should be displayed void setDisplayStudyFigurePanelTaskDescriptionInformation(const bool displayIt) { idFilter.displayStudyFigurePanelTaskDescriptionInformation = displayIt; } /// study figure panel task baseline information should be displayed void setDisplayStudyFigurePanelTaskBaselineInformation(const bool displayIt) { idFilter.displayStudyFigurePanelTaskBaselineInformation = displayIt; } /// study figure panel test attributes information should be displayed void setDisplayStudyFigurePanelTestAttributesInformation(const bool displayIt) { idFilter.displayStudyFigurePanelTestAttributesInformation = displayIt; } /// study subh header information should be displayed void setDisplayStudySubHeaderInformation(const bool displayIt) { idFilter.displayStudySubHeaderInformation = displayIt; } /// study sub header name information should be displayed void setDisplayStudySubHeaderNameInformation(const bool displayIt) { idFilter.displayStudySubHeaderNameInformation = displayIt; } /// study sub header short name information should be displayed void setDisplayStudySubHeaderShortNameInformation(const bool displayIt) { idFilter.displayStudySubHeaderShortNameInformation = displayIt; } /// study sub header task description information should be displayed void setDisplayStudySubHeaderTaskDescriptionInformation(const bool displayIt) { idFilter.displayStudySubHeaderTaskDescriptionInformation = displayIt; } /// study sub header task baseline information should be displayed void setDisplayStudySubHeaderTaskBaselineInformation(const bool displayIt) { idFilter.displayStudySubHeaderTaskBaselineInformation = displayIt; } /// study sub header test attributes information should be displayed void setDisplayStudySubHeaderTestAttributesInformation(const bool displayIt) { idFilter.displayStudySubHeaderTestAttributesInformation = displayIt; } /// study page reference information should be displayed void setDisplayStudyPageReferenceInformation(const bool displayIt) { idFilter.displayStudyPageReferenceInformation = displayIt; } /// study page reference header information should be displayed void setDisplayStudyPageReferenceHeaderInformation(const bool displayIt) { idFilter.displayStudyPageReferenceHeaderInformation = displayIt; } /// study page reference comment information should be displayed void setDisplayStudyPageReferenceCommentInformation(const bool displayIt) { idFilter.displayStudyPageReferenceCommentInformation = displayIt; } /// study page reference size units information should be displayed void setDisplayStudyPageReferenceSizeUnitsInformation(const bool displayIt) { idFilter.displayStudyPageReferenceSizeUnitsInformation = displayIt; } /// study page reference voxel size information should be displayed void setDisplayStudyPageReferenceVoxelSizeInformation(const bool displayIt) { idFilter.displayStudyPageReferenceVoxelSizeInformation = displayIt; } /// study page reference statistic information should be displayed void setDisplayStudyPageReferenceStatisticInformation(const bool displayIt) { idFilter.displayStudyPageReferenceStatisticInformation = displayIt; } /// study page reference statistic description information should be displayed void setDisplayStudyPageReferenceStatisticDescriptionInformation(const bool displayIt) { idFilter.displayStudyPageReferenceStatisticDescriptionInformation = displayIt; } /// study page number information should be displayed //void setDisplayStudyPageNumberInformation(const bool displayIt) { idFilter.displayStudyPageNumberInformation = displayIt; } /// set green symbols should be displayed on surface void setDisplayIDSymbol(const bool displayIt) { displayIDSymbol = displayIt; } /// get significant digits for floating point numbers void setSignificantDigits(const int num); // all identification off (if any on, all turned off, otherwise all off) void toggleAllIdentificationOnOff(); // all identification on void setAllIdentificationOn(); // all identification off void setAllIdentificationOff(); protected: /// class for identification filtering class IdFilter { public: // constructor IdFilter(); // destructor ~IdFilter(); // turn all off void allOff(const bool turnSubFlagsOff = true); // turn all on void allOn(); // toggle all on/off void toggleAllOnOff(); /// report if any node information should be displayed bool anyNodeDataOn() const; /// border information should be displayed bool displayBorderInformation; /// cell information should be displayed bool displayCellInformation; /// voxel information should be displayed bool displayVoxelInformation; /// contour information should be displayed bool displayContourInformation; /// node information should be displayed bool displayNodeInformation; /// node coordinate information should be displayed bool displayNodeCoordInformation; /// node lat/lon information should be displayed bool displayNodeLatLonInformation; /// node paint information should be displayed bool displayNodePaintInformation; /// node prob atlas information should be displayed bool displayNodeProbAtlasInformation; /// node rgb paint information should be displayed bool displayNodeRgbPaintInformation; /// node metric information should be displayed bool displayNodeMetricInformation; /// node surface shape information should be displayed bool displayNodeShapeInformation; /// node metric information should be displayed bool displayNodeSectionInformation; /// node areal est information should be displayed bool displayNodeArealEstInformation; /// node topography information should be displayed bool displayNodeTopographyInformation; /// study information should be displayed bool displayStudyInformation; /// study title information should be displayed bool displayStudyTitleInformation; /// study authors information should be displayed bool displayStudyAuthorsInformation; /// study citation information should be displayed bool displayStudyCitationInformation; /// study comment information should be displayed bool displayStudyCommentInformation; /// study data format information should be displayed bool displayStudyDataFormatInformation; /// study data type information should be displayed bool displayStudyDataTypeInformation; /// study DOI information should be displayed bool displayStudyDOIInformation; /// study keywords information should be displayed bool displayStudyKeywordsInformation; /// study medical subject headings should be displayed bool displayStudyMedicalSubjectHeadingsInformation; /// study meta-analysis should be displayed bool displayStudyMetaAnalysisInformation; /// study meta-analysis name should be displayed bool displayStudyMetaAnalysisNameInformation; /// study meta-analysis title should be displayed bool displayStudyMetaAnalysisTitleInformation; /// study meta-analysis authors should be displayed bool displayStudyMetaAnalysisAuthorsInformation; /// study meta-analysis citation should be displayed bool displayStudyMetaAnalysisCitationInformation; /// study meta-analysis DOI/URL should be displayed bool displayStudyMetaAnalysisDoiUrlInformation; /// study name should be displayed bool displayStudyNameInformation; /// study part scheme abbreviation information should be displayed bool displayStudyPartSchemeAbbrevInformation; /// study part scheme full name information should be displayed bool displayStudyPartSchemeFullInformation; /// study PubMed ID information should be displayed bool displayStudyPubMedIDInformation; /// study Project ID information should be displayed bool displayStudyProjectIDInformation; /// study stereotaxic space information should be displayed bool displayStudyStereotaxicSpaceInformation; /// study stereotaxic space details information should be displayed bool displayStudyStereotaxicSpaceDetailsInformation; /// study URL information should be displayed bool displayStudyURLInformation; /// study table information should be displayed bool displayStudyTableInformation; /// study table header information should be displayed bool displayStudyTableHeaderInformation; /// study table footer information should be displayed bool displayStudyTableFooterInformation; /// study table size units information should be displayed bool displayStudyTableSizeUnitsInformation; /// study table voxel size information should be displayed bool displayStudyTableVoxelSizeInformation; /// study table statistic information should be displayed bool displayStudyTableStatisticInformation; /// study table statistic description information should be displayed bool displayStudyTableStatisticDescriptionInformation; /// study figure information should be displayed bool displayStudyFigureInformation; /// study figure legend information should be displayed bool displayStudyFigureLegendInformation; /// study figure panel information should be displayed bool displayStudyFigurePanelInformation; /// study figure panel description information should be displayed bool displayStudyFigurePanelDescriptionInformation; /// study figure panel task description information should be displayed bool displayStudyFigurePanelTaskDescriptionInformation; /// study figure panel task baseline information should be displayed bool displayStudyFigurePanelTaskBaselineInformation; /// study figure panel test attributes information should be displayed bool displayStudyFigurePanelTestAttributesInformation; /// study sub header information should be displayed bool displayStudySubHeaderInformation; /// study sub header name information should be displayed bool displayStudySubHeaderNameInformation; /// study sub header short name information should be displayed bool displayStudySubHeaderShortNameInformation; /// study sub header task description information should be displayed bool displayStudySubHeaderTaskDescriptionInformation; /// study sub header task baseline information should be displayed bool displayStudySubHeaderTaskBaselineInformation; /// study sub header test attributes information should be displayed bool displayStudySubHeaderTestAttributesInformation; /// study page reference information should be displayed bool displayStudyPageReferenceInformation; /// study page reference header information should be displayed bool displayStudyPageReferenceHeaderInformation; /// study page reference comment information should be displayed bool displayStudyPageReferenceCommentInformation; /// study page reference size units information should be displayed bool displayStudyPageReferenceSizeUnitsInformation; /// study page reference voxel size information should be displayed bool displayStudyPageReferenceVoxelSizeInformation; /// study page reference statistic information should be displayed bool displayStudyPageReferenceStatisticInformation; /// study page reference statistic description information should be displayed bool displayStudyPageReferenceStatisticDescriptionInformation; /// study page number information should be displayed //bool displayStudyPageNumberInformation; /// foci information should be displayed bool displayFociInformation; /// report if any foci information should be displayed bool anyFociDataOn() const; /// report if any study meta-analysis information should be displayed bool anyStudyMetaAnalysisDataOn() const; /// report if any study information should be displayed bool anyStudyDataOn() const; /// report if any study table information should be displayed bool anyStudyTableDataOn() const; /// report if any study figure panel information should be displayed bool anyStudyFigurePanelDataOn() const; /// report if any study figure information should be displayed bool anyStudyFigureDataOn() const; /// report if any sub header information should be displayed bool anySubHeaderDataOn() const; /// report if any page reference information should be displayed bool anyPageReferenceDataOn() const; /// foci name information should be displayed bool displayFociNameInformation; /// foci class information should be displayed bool displayFociClassInformation; /// foci original stereotaxic position information should be displayed bool displayFociOriginalStereotaxicPositionInformation; /// foci stereotaxic position information should be displayed bool displayFociStereotaxicPositionInformation; /// foci area information should be displayed bool displayFociAreaInformation; /// foci geography information should be displayed bool displayFociGeographyInformation; /// foci region of interest information should be displayed bool displayFociRegionOfInterestInformation; /// foci size information should be displayed bool displayFociSizeInformation; /// foci structure information should be displayed bool displayFociStructureInformation; /// foci statistic information should be displayed bool displayFociStatisticInformation; /// foci comment information should be displayed bool displayFociCommentInformation; }; // get identification text for node QString getIdentificationTextForNode(); // get identification text for node QString getIdentificationTextForNode(const int nodeNumber, const int windowNumber, BrainSet* brainSet, BrainModelSurface* bms); // get the identification text for studies QString getIdentificationTextForStudies(const StudyMetaDataFile* smdf, const StudyMetaDataLinkSet& smdls); // get the identification text for a study QString getIdentificationTextForStudy(const StudyMetaData* smd, const int studyIndex, const StudyMetaDataLink* smdl = NULL); // setup the tags for html or text void setupHtmlOrTextTags(const bool doHTML); // get identification text for surface border QString getIdentificationTextForSurfaceBorder(); // get identification text for volume border QString getIdentificationTextForVolumeBorder(); // get identification text for cell QString getIdentificationTextForCellProjection(); // get identification text for foci QString getIdentificationTextForFoci(); // get identification text for a single focus QString getIdentificationTextForSingleFocus( BrainModelOpenGLSelectedItem focusID, CellProjection* focus, FociProjectionFile* fociProjectionFile, const bool volumeFlag); // get identification text for voxel QString getIdentificationTextForVoxel(); // get identification text for volume cell QString getIdentificationTextForVolumeCell(); // get identification text for volume foci QString getIdentificationTextForVolumeFoci(); // get identification text for transform cell QString getIdentificationTextForTransformCell(); // get identification text for transform contour cell QString getIdentificationTextForTransformContourCell(); // get identification text for transform foci QString getIdentificationTextForTransformFoci(); // get identification text for palette QString getIdentificationTextForPalette(const bool metricFlag); // get identification text for voxel cloud functional QString getIdentificationTextForVoxelCloudFunctional(); // get identification text for VTK model QString getIdentificationTextForVtkModel(); // get identification text for Contour QString getIdentificationTextForContour(); // get identification text for contour cell QString getIdentificationTextForContourCell(); // Get ID string for study meta data sub header QString getStudyMetaDataSubHeaderIdentificationText( const StudyMetaData::SubHeader* subHeader, const QString& namePrefix) const; // get identification text for a volume file QString getVolumeFileIdentificationText(BrainSet* brainSet, BrainModelVolume* bmv, VolumeFile* selectionVolume, const int vi, const int vj, const int vk); // get the name of a window QString getWindowName(const int windowNumber) const; // make name a link to vocabulary file if it matches a vocabulary file entry QString linkToVocabulary(BrainSet* brainSet, const QString& name); // make a list of names separated by semicolon possible links to vocabulary QString linkStringToVocabulary(BrainSet* brainSet, const QString& s); /// translate special HTML characters to HTML special characters QString htmlTranslate(const QString& ss) const; /// current identification filter IdFilter idFilter; /// OpenGL Drawing class BrainModelOpenGL* openGL; /// bold start tag QString tagBoldStart; /// bold end tag QString tagBoldEnd; /// newline tag QString tagNewLine; /// indentation QString tagIndentation; /// brain set with which this identification is associated BrainSet* brainSetParent; /// green symbols should be displayed on surface (not used in all on/off) bool displayIDSymbol; /// number of significant digits for floating point number display int significantDigits; /// enable links to vocabulary in html bool enableVocabularyLinks; /// enable HTML output bool htmlFlag; }; #endif // __BRAIN_MODEL_IDENTIFICATION_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelIdentification.cxx0000664000175000017500000046212111572067322025325 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "ArealEstimationFile.h" #include "BrainModelContours.h" #include "BrainModelIdentification.h" #include "BrainModelOpenGL.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceNodeColoring.h" #include "BrainModelVolume.h" #include "BrainSet.h" #include "CellFile.h" #include "CellProjectionFile.h" #include "ContourCellFile.h" #include "ContourFile.h" #include "DisplaySettingsArealEstimation.h" #include "DisplaySettingsCoCoMac.h" #include "DisplaySettingsGeodesicDistance.h" #include "DisplaySettingsMetric.h" #include "DisplaySettingsPaint.h" #include "DisplaySettingsRgbPaint.h" #include "DisplaySettingsSurfaceShape.h" #include "DisplaySettingsTopography.h" #include "FileUtilities.h" #include "FociFile.h" #include "FociProjectionFile.h" #include "GeodesicDistanceFile.h" #include "LatLonFile.h" #include "MathUtilities.h" #include "MetricFile.h" #include "PaintFile.h" #include "PaletteFile.h" #include "PreferencesFile.h" #include "ProbabilisticAtlasFile.h" #include "RgbPaintFile.h" #include "SectionFile.h" #include "StereotaxicSpace.h" #include "StringUtilities.h" #include "StudyMetaDataFile.h" #include "SurfaceShapeFile.h" #include "TopographyFile.h" #include "TransformationMatrixFile.h" #include "VolumeFile.h" #include "VocabularyFile.h" #include "VtkModelFile.h" /** * constructor. */ BrainModelIdentification::BrainModelIdentification(BrainSet* brainSetIn, QObject* parent) : QObject(parent) { brainSetParent = brainSetIn; displayIDSymbol = true; significantDigits = 2; const PreferencesFile* pf = BrainSet::getPreferencesFile(); if (pf != NULL) { significantDigits = pf->getSignificantDigitsDisplay(); } } /** * destructor. */ BrainModelIdentification::~BrainModelIdentification() { } /** * get the identification text. */ QString BrainModelIdentification::getIdentificationTextForCell(BrainModelOpenGL* openGL, const bool enableHtml, const bool enableVocabularyLinksIn) { htmlFlag = enableHtml; // // Save current id filter // IdFilter savedFilter = idFilter; // // Turn on all but node // idFilter.allOff(false); setDisplayCellInformation(true); // // Do ID // QString idString = getIdentificationText(openGL, enableHtml, enableVocabularyLinksIn); // // Restore ID filter // idFilter = savedFilter; return idString; } /** * get the identification text. */ QString BrainModelIdentification::getIdentificationTextForFocus(BrainModelOpenGL* openGL, const bool enableHtml, const bool enableVocabularyLinksIn) { htmlFlag = enableHtml; // // Save current id filter // IdFilter savedFilter = idFilter; // // Turn on all but node // idFilter.allOff(false); setDisplayFociInformation(true); // // Do ID // QString idString = getIdentificationText(openGL, enableHtml, enableVocabularyLinksIn); // // Restore ID filter // idFilter = savedFilter; return idString; } /** * get the identification text. */ QString BrainModelIdentification::getIdentificationTextForBorder(BrainModelOpenGL* openGL, const bool enableHtml, const bool enableVocabularyLinksIn) { htmlFlag = enableHtml; // // Save current id filter // IdFilter savedFilter = idFilter; // // Turn on all but node // idFilter.allOff(false); setDisplayBorderInformation(true); // // Do ID // QString idString = getIdentificationText(openGL, enableHtml, enableVocabularyLinksIn); // // Restore ID filter // idFilter = savedFilter; return idString; } /** * get the identification text. */ QString BrainModelIdentification::getIdentificationTextForNode(BrainModelOpenGL* openGL, const bool enableHtml, const bool enableVocabularyLinksIn) { htmlFlag = enableHtml; // // Save current id filter // IdFilter savedFilter = idFilter; // // Turn on all but node // idFilter.allOn(); setDisplayBorderInformation(false); setDisplayCellInformation(false); setDisplayFociInformation(false); setDisplayVoxelInformation(false); // // Do ID // QString idString = getIdentificationText(openGL, enableHtml, enableVocabularyLinksIn); // // Restore ID filter // idFilter = savedFilter; return idString; } /** * get the identification text for node by its number. */ QString BrainModelIdentification::getIdentificationTextForNode(BrainSet* brainSet, const int nodeNumber, const bool enableHtml, const bool enableVocabularyLinksIn) { htmlFlag = enableHtml; enableVocabularyLinks = (enableVocabularyLinksIn && enableHtml); setupHtmlOrTextTags(enableHtml); QString idString; idString += getIdentificationTextForNode(nodeNumber, -1, // window number brainSet, brainSet->getActiveFiducialSurface()); return idString; } /** * setup the tags for html or text. */ void BrainModelIdentification::setupHtmlOrTextTags(const bool doHTML) { tagBoldStart = ""; tagBoldEnd = ""; tagIndentation = " "; tagNewLine = "\n"; if (doHTML) { tagBoldStart = ""; tagBoldEnd = ""; tagIndentation = "    "; tagNewLine = "
    "; } } /** * get the identification text. */ QString BrainModelIdentification::getIdentificationText(BrainModelOpenGL* openGLIn, const bool enableHtml, const bool enableVocabularyLinksIn) { openGL = openGLIn; htmlFlag = enableHtml; enableVocabularyLinks = (enableVocabularyLinksIn && enableHtml); setupHtmlOrTextTags(enableHtml); QString idString; if (getDisplayFociInformation()) { idString += getIdentificationTextForFoci(); idString += getIdentificationTextForTransformFoci(); } if (getDisplayCellInformation()) { idString += getIdentificationTextForCellProjection(); idString += getIdentificationTextForTransformCell(); } if (getDisplayNodeInformation()) { idString += getIdentificationTextForNode(); } if (getDisplayBorderInformation()) { idString += getIdentificationTextForSurfaceBorder(); } idString += getIdentificationTextForVtkModel(); if (getDisplayVoxelInformation()) { idString += getIdentificationTextForVoxel(); idString += getIdentificationTextForVolumeBorder(); idString += getIdentificationTextForVolumeCell(); idString += getIdentificationTextForVolumeFoci(); idString += getIdentificationTextForVoxelCloudFunctional(); } idString += getIdentificationTextForPalette(true); idString += getIdentificationTextForPalette(false); if (getDisplayContourInformation()) { idString += getIdentificationTextForContour(); idString += getIdentificationTextForContourCell(); } idString += getIdentificationTextForTransformContourCell(); /* if (idString.isEmpty() == false) { if (enableHtml) { idString.insert(0, "

    "); } else { idString.insert(0, QString(60, '-') + "\n"); } } */ return idString; } /** * get identification text for node. */ QString BrainModelIdentification::getIdentificationTextForNode() { BrainModelOpenGLSelectedItem nodeID = openGL->getSelectedNode(); return getIdentificationTextForNode(nodeID.getItemIndex1(), nodeID.getViewingWindowNumber(), nodeID.getBrainSet(), nodeID.getBrainModelSurface()); } /** * Get the identification text for a node. */ QString BrainModelIdentification::getIdentificationTextForNode(const int nodeNumber, const int windowNumber, BrainSet* brainSet, BrainModelSurface* bms) { // // Keep track of last identified node per window // static bool lastValid[BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS]; static float lastXYZ[BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS][3]; static bool firstTime = true; if (firstTime) { firstTime = false; for (int i = 0; i < BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS; i++) { lastValid[i] = false; } } // // Verify that a node was selected // if (nodeNumber < 0) { return ""; } // // Verify that at least one node display filter is enabled // if (idFilter.anyNodeDataOn() == false) { return ""; } QString idString; // // Add node number // idString += (tagBoldStart + "Node " + QString::number(nodeNumber) + tagBoldEnd + tagNewLine); // // Set if BrainSet and Surface are valid // if ((brainSet != NULL) && (bms != NULL)) { // // Index of brain model in BrainSet // const int brainModelIndex = bms->getBrainModelIndex(); // // If there is not a surface in the window then it must be a volume // and the surface passed in is the active fiducial surface // bool mustBeVolumeIdFlag = false; if (windowNumber >= 0) { BrainModel* bm = openGL->getBrainModelInWindowNumberForIdentification(windowNumber); if (bm != NULL) { // // NOT a surface // if (dynamic_cast(bm) == NULL) { mustBeVolumeIdFlag = true; } } } else { mustBeVolumeIdFlag = true; } // // IDing node corresponding to volume voxel? // if (mustBeVolumeIdFlag) { // // Coordinate of node // const CoordinateFile* cf = bms->getCoordinateFile(); float xyz[3]; cf->getCoordinate(nodeNumber, xyz); // // XYZ postion // idString += (tagIndentation + bms->getSurfaceTypeName() + " XYZ: " + QString::number(xyz[0], 'f', significantDigits) + ", " + QString::number(xyz[1], 'f', significantDigits) + ", " + QString::number(xyz[2], 'f', significantDigits) + tagNewLine); } else { // // Identifying node in a window, show xyz for all surfaces in windows // Get displayed brain models in each window // for (int j = 0; j < BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS; j++) { BrainModel* bm = openGL->getBrainModelInWindowNumberForIdentification(j); if (bm != NULL) { BrainModelSurface* idSurface = dynamic_cast(bm); if (idSurface != NULL) { // // Coordinate of node // const CoordinateFile* cf = idSurface->getCoordinateFile(); float xyz[3]; cf->getCoordinate(nodeNumber, xyz); // // Distance from last identified node // QString distanceString; if (windowNumber == j) { if (lastValid[windowNumber]) { const double dist = MathUtilities::distance3D(xyz, lastXYZ[windowNumber]); distanceString = (" Distance: " + QString::number(dist, 'f', significantDigits)); } lastValid[windowNumber] = true; lastXYZ[windowNumber][0] = xyz[0]; lastXYZ[windowNumber][1] = xyz[1]; lastXYZ[windowNumber][2] = xyz[2]; } // // XYZ postion // idString += (tagIndentation + getWindowName(j) + " " + idSurface->getSurfaceTypeName() + " XYZ: " + QString::number(xyz[0], 'f', significantDigits) + ", " + QString::number(xyz[1], 'f', significantDigits) + ", " + QString::number(xyz[2], 'f', significantDigits) + distanceString + tagNewLine); } } } } // // Areal Estimation Information // if (getDisplayNodeArealEstInformation()) { ArealEstimationFile* aef = brainSet->getArealEstimationFile(); const int numCols = aef->getNumberOfColumns(); if (numCols > 0) { DisplaySettingsArealEstimation* dsae = brainSet->getDisplaySettingsArealEstimation(); //const int selectedColumn = dsae->getSelectedDisplayColumn(brainModelIndex); std::vector selectedColumnFlags; dsae->getSelectedColumnFlags(brainModelIndex, selectedColumnFlags); for (int i = 0; i < numCols; i++) { idString += (tagIndentation + "Areal Estimation: "); if (selectedColumnFlags[i]) { idString += tagBoldStart; } idString += (aef->getColumnName(i) + " "); QString areas[4]; float prob[4]; aef->getNodeData(nodeNumber, i, areas, prob); for (int j = 0; j < 4; j++) { idString += (linkToVocabulary(brainSet, areas[j]) + " " + QString::number(prob[j], 'f', significantDigits) + " "); } if (selectedColumnFlags[i]) { idString += tagBoldEnd; } idString += tagNewLine; } for (int i = 0; i < numCols; i++) { if (selectedColumnFlags[i]) { // // Study Meta Data from Study Metadata File // const StudyMetaDataLinkSet smdls = aef->getColumnStudyMetaDataLinkSet(i); StudyMetaDataFile* smdf = brainSet->getStudyMetaDataFile(); idString += getIdentificationTextForStudies(smdf, smdls); } } } } // // CoCoMac Information // if (brainSet->isASurfaceOverlay(brainModelIndex, BrainModelSurfaceOverlay::OVERLAY_COCOMAC)) { DisplaySettingsCoCoMac* dsc = brainSet->getDisplaySettingsCoCoMac(); dsc->setSelectedNode(nodeNumber); idString += htmlTranslate(dsc->getIDInfo()); } // // Geodesic Distance // DisplaySettingsGeodesicDistance* dsgd = brainSet->getDisplaySettingsGeodesicDistance(); GeodesicDistanceFile* gdf = brainSet->getGeodesicDistanceFile(); if (dsgd->getPathDisplayEnabled()) { const int column = dsgd->getDisplayColumn(); if ((column >= 0) && (column < gdf->getNumberOfColumns())) { if ((nodeNumber >= 0) && (nodeNumber < gdf->getNumberOfNodes())) { dsgd->setPathDisplayNodeNumber(nodeNumber); const float dist = gdf->getNodeParentDistance(nodeNumber, column); idString += (tagIndentation + "Geodesic Distance: " + QString::number(dist, 'f', significantDigits) + tagNewLine); } } } // // Show lat lon of node // if (getDisplayNodeLatLonInformation()) { LatLonFile* llf = brainSet->getLatLonFile(); int numCols = llf->getNumberOfColumns(); for (int j = 0; j < numCols; j++) { float lat, lon; llf->getLatLon(nodeNumber, j, lat, lon); const QString name(llf->getColumnName(j)); idString += (tagIndentation + "Lat/Lon " + htmlTranslate(name) + ": " + QString::number(lat, 'f', significantDigits) + " " + QString::number(lon, 'f', significantDigits) + tagNewLine); if (llf->getDeformedLatLonValid(j)) { llf->getDeformedLatLon(nodeNumber, j, lat, lon); idString += (tagIndentation + "Lat/Lon " + htmlTranslate(name) + ": " + QString::number(lat, 'f', significantDigits) + " " + QString::number(lon, 'f', significantDigits) + tagNewLine); } } } if (getDisplayNodeMetricInformation()) { // // Show metric // MetricFile* mf = brainSet->getMetricFile(); const int numCols = mf->getNumberOfColumns(); if (numCols > 0) { DisplaySettingsMetric* dsm = brainSet->getDisplaySettingsMetric(); //const int selectedColumn = dsm->getSelectedDisplayColumn(brainModelIndex); std::vector selectedColumnFlags; dsm->getSelectedColumnFlags(brainModelIndex, selectedColumnFlags); idString += (tagIndentation + "Metric: "); for (int i = 0; i < mf->getNumberOfColumns(); i++) { if (selectedColumnFlags[i]) { idString += tagBoldStart; } idString += (QString::number(mf->getValue(nodeNumber, i), 'f', significantDigits) + " "); if (selectedColumnFlags[i]) { idString += tagBoldEnd; } } idString += tagNewLine; for (int i = 0; i < numCols; i++) { if ((selectedColumnFlags[i]) && (mf->getValue(nodeNumber, i) != 0.0)) { // // Study Meta Data from Study Metadata File // const StudyMetaDataLinkSet smdls = mf->getColumnStudyMetaDataLinkSet(i); StudyMetaDataFile* smdf = brainSet->getStudyMetaDataFile(); idString += getIdentificationTextForStudies(smdf, smdls); } } } } // // Show Paint Information // if (getDisplayNodePaintInformation()) { PaintFile* pf = brainSet->getPaintFile(); const int numCols = pf->getNumberOfColumns(); if (numCols > 0) { DisplaySettingsPaint* dsp = brainSet->getDisplaySettingsPaint(); //const int selectedPaintColumn = dsp->getSelectedDisplayColumn(brainModelIndex); std::vector selectedColumnFlags; dsp->getSelectedColumnFlags(brainModelIndex, selectedColumnFlags); idString += (tagIndentation + "Paint: "); for (int i = 0; i < numCols; i++) { const int paintIndex = pf->getPaint(nodeNumber, i); if (selectedColumnFlags[i]) { idString += tagBoldStart; } idString += linkToVocabulary(brainSet, pf->getPaintNameFromIndex(paintIndex)); if (selectedColumnFlags[i]) { idString += tagBoldEnd; } idString += " "; } idString += tagNewLine; for (int i = 0; i < numCols; i++) { if (selectedColumnFlags[i]) { // // Is this an "unassigned" paint // bool showMetaDataFlag = true; const int paintIndex = pf->getPaint(nodeNumber, i); if ((paintIndex >= 0) && (paintIndex < pf->getNumberOfPaintNames())) { const QString paintName = pf->getPaintNameFromIndex(paintIndex); if (paintName.startsWith("?")) { showMetaDataFlag = false; } } // // Study Meta Data from Study Metadata File // if (showMetaDataFlag) { const StudyMetaDataLinkSet smdls = pf->getColumnStudyMetaDataLinkSet(i); StudyMetaDataFile* smdf = brainSet->getStudyMetaDataFile(); idString += getIdentificationTextForStudies(smdf, smdls); } } } } } // // Show probabilistic atlas information // if (getDisplayNodeProbAtlasInformation()) { ProbabilisticAtlasFile* pf = brainSet->getProbabilisticAtlasSurfaceFile(); const int numCols = pf->getNumberOfColumns(); if (numCols > 0) { idString += (tagIndentation + "Prob Atlas: "); for (int i = 0; i < pf->getNumberOfColumns(); i++) { const int paintIndex = pf->getPaint(nodeNumber, i); idString += (linkToVocabulary(brainSet, pf->getPaintNameFromIndex(paintIndex)) + " "); } idString += tagNewLine; // // Study Meta Data from Study Metadata File // const StudyMetaDataLinkSet smdls = pf->getStudyMetaDataLinkSet(); StudyMetaDataFile* smdf = brainSet->getStudyMetaDataFile(); idString += getIdentificationTextForStudies(smdf, smdls); } } // // Show RGB Paint Information // if (getDisplayNodeRgbPaintInformation()) { RgbPaintFile* rpf = brainSet->getRgbPaintFile(); const int numCols = rpf->getNumberOfColumns(); if (numCols > 0) { DisplaySettingsRgbPaint* dsrp = brainSet->getDisplaySettingsRgbPaint(); //const int selectedColumn = dsrp->getSelectedDisplayColumn(brainModelIndex); std::vector selectedColumnFlags; dsrp->getSelectedColumnFlags(brainModelIndex, selectedColumnFlags); for (int i = 0; i < numCols; i++) { idString += (tagIndentation + "RGB Paint: "); if (selectedColumnFlags[i]) { idString + tagBoldStart; } float r, g, b; rpf->getRgb(nodeNumber, i, r, g, b); idString += (htmlTranslate(rpf->getColumnName(i)) + " " + QString::number(r, 'f', significantDigits) + " " + QString::number(g, 'f', significantDigits) + " " + QString::number(b, 'f', significantDigits)); if (selectedColumnFlags[i]) { idString += tagBoldEnd; } idString += tagNewLine; } } } // // Section information // if (getDisplayNodeSectionInformation()) { SectionFile* sf = brainSet->getSectionFile(); int numCols = sf->getNumberOfColumns(); if (numCols > 0) { idString += (tagIndentation + "Section: "); for (int j = 0; j < numCols; j++) { idString += (QString::number(sf->getSection(nodeNumber, j)) + " "); } idString += tagNewLine; } } // // Surface shape information // if (getDisplayNodeShapeInformation()) { SurfaceShapeFile* ssf = brainSet->getSurfaceShapeFile(); const int numCols = ssf->getNumberOfColumns(); if (numCols > 0) { DisplaySettingsSurfaceShape* dss = brainSet->getDisplaySettingsSurfaceShape(); //const int selectedColumn = dss->getSelectedDisplayColumn(brainModelIndex); std::vector selectedColumnFlags; dss->getSelectedColumnFlags(brainModelIndex, selectedColumnFlags); idString += (tagIndentation + "Shape: "); for (int i = 0; i < ssf->getNumberOfColumns(); i++) { if (selectedColumnFlags[i]) { idString += tagBoldStart; } idString += (QString::number(ssf->getValue(nodeNumber, i), 'f', significantDigits) + " "); if (selectedColumnFlags[i]) { idString += tagBoldEnd; } } idString += tagNewLine; for (int i = 0; i < ssf->getNumberOfColumns(); i++) { if (selectedColumnFlags[i]) { // // Study Meta Data from Study Metadata File // const StudyMetaDataLinkSet smdls = ssf->getColumnStudyMetaDataLinkSet(i); StudyMetaDataFile* smdf = brainSet->getStudyMetaDataFile(); idString += getIdentificationTextForStudies(smdf, smdls); } } } } // // Topography information // if (getDisplayNodeTopographyInformation()) { TopographyFile* tf = brainSet->getTopographyFile(); const int numCols = tf->getNumberOfColumns(); if (numCols > 0) { DisplaySettingsTopography* dst = brainSet->getDisplaySettingsTopography(); //const int selectedColumn = dst->getSelectedDisplayColumn(brainModelIndex); std::vector selectedColumnFlags; dst->getSelectedColumnFlags(brainModelIndex, selectedColumnFlags); for (int i = 0; i < numCols; i++) { const NodeTopography nt = tf->getNodeTopography(nodeNumber, i); float eMean, eLow, eHigh, pMean, pLow, pHigh; QString areaName; nt.getData(eMean, eLow, eHigh, pMean, pLow, pHigh, areaName); if (areaName.isEmpty() == false) { if (selectedColumnFlags[i]) { idString += tagBoldStart; } idString += (tagIndentation + "Topography Eccentricity: " + "mean: " + QString::number(eMean, 'f', significantDigits) + " range: " + QString::number(eLow, 'f', significantDigits) + " to " + QString::number(eHigh, 'f', significantDigits)); if (selectedColumnFlags[i]) { idString += tagBoldEnd; } if (selectedColumnFlags[i]) { idString += tagBoldStart; } idString += (tagIndentation + "Topography Polar Angle: " + "mean: " + QString::number(pMean, 'f', significantDigits) + " range: " + QString::number(pLow, 'f', significantDigits) + " to " + QString::number(pHigh, 'f', significantDigits)); if (selectedColumnFlags[i]) { idString += tagBoldEnd; } idString += tagNewLine; } } } } } return idString; } /** * get the name of a window. */ QString BrainModelIdentification::getWindowName(const int windowNumber) const { QString windowName; switch (static_cast(windowNumber)) { case BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW: windowName = "Main Window "; break; case BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_2: windowName = "View Window 2 "; break; case BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_3: windowName = "View Window 3 "; break; case BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_4: windowName = "View Window 4 "; break; case BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_5: windowName = "View Window 5 "; break; case BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_6: windowName = "View Window 6 "; break; case BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_7: windowName = "View Window 7 "; break; case BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_8: windowName = "View Window 8 "; break; case BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_9: windowName = "View Window 9 "; break; case BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_10: windowName = "View Window 10 "; break; case BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS: break; } return windowName; } /** * get identification text for volume border. */ QString BrainModelIdentification::getIdentificationTextForVolumeBorder() { QString idString; BrainModelOpenGLSelectedItem volumeBorderItem = openGL->getSelectedVolumeBorder(); BrainSet* brainSet = volumeBorderItem.getBrainSet(); const int borderNumber = volumeBorderItem.getItemIndex1(); const int linkNumber = volumeBorderItem.getItemIndex2(); if ((brainSet != NULL) && (borderNumber >= 0) && (linkNumber >= 0)) { const BorderFile* bf = brainSet->getVolumeBorderFile(); const Border* b = bf->getBorder(borderNumber); const float* xyz = b->getLinkXYZ(linkNumber); idString += (tagBoldStart + "Volume Border" + tagBoldEnd + ": " + QString::number(borderNumber) + " Link: " + QString::number(linkNumber) + ", Name: " + linkToVocabulary(brainSet, htmlTranslate(b->getName())) + " (" + QString::number(xyz[0], 'f', significantDigits) + ", " + QString::number(xyz[1], 'f', significantDigits) + ", " + QString::number(xyz[2], 'f', significantDigits) + ")" + tagNewLine); } return idString; } /** * get identification text for surface border. */ QString BrainModelIdentification::getIdentificationTextForSurfaceBorder() { QString idString; // // two borders may be identified // for (int i = 0; i < 2; i++) { // // Get the selected border information // BrainModelOpenGLSelectedItem borderID = openGL->getSelectedBorder1(); if (i == 1) { borderID = openGL->getSelectedBorder2(); } // // Make sure valid border identified // BrainSet* brainSet = borderID.getBrainSet(); const int brainModelIndex = borderID.getItemIndex1(); const int borderNumber = borderID.getItemIndex2(); const int linkNumber = borderID.getItemIndex3(); if ((brainSet != NULL) && (brainModelIndex >= 0) && (borderNumber >= 0) && (linkNumber >= 0)) { BrainModelBorderSet* bmbs = brainSet->getBorderSet(); if (bmbs->getNumberOfBorders() > borderNumber) { BrainModelBorder* b = bmbs->getBorder(borderNumber); BrainModelBorderLink* link = b->getBorderLink(linkNumber); float xyz[3]; link->getLinkPosition(brainModelIndex, xyz); idString += (tagBoldStart + "Surface Border" + tagBoldEnd + ": " + QString::number(borderNumber) + " Link: " + QString::number(linkNumber) + " Name: " + linkToVocabulary(brainSet, htmlTranslate(b->getName())) + " (" + QString::number(xyz[0], 'f', significantDigits) + ", " + QString::number(xyz[1], 'f', significantDigits) + ", " + QString::number(xyz[2], 'f', significantDigits) + ")" + tagNewLine); } } } return idString; } /** * get identification text for cell. */ QString BrainModelIdentification::getIdentificationTextForCellProjection() { QString idString; BrainModelOpenGLSelectedItem cellID = openGL->getSelectedCellProjection(); BrainSet* brainSet = cellID.getBrainSet(); const int cellNumber = cellID.getItemIndex1(); if ((brainSet != NULL) && (cellNumber >= 0)) { CellProjectionFile* cf = brainSet->getCellProjectionFile(); if (cf == NULL) { return ""; } CellProjection* cell = cf->getCellProjection(cellNumber); const float* xyz = cell->getXYZ(); idString += (tagBoldStart + "Cell" + tagBoldEnd + " " + QString::number(cellNumber) + ": " + linkToVocabulary(brainSet, htmlTranslate(cell->getName())) + " Class: " + cell->getClassName() + " Position: (" + QString::number(xyz[0], 'f', significantDigits) + ", " + QString::number(xyz[1], 'f', significantDigits) + ", " + QString::number(xyz[2], 'f', significantDigits) + ")" + tagNewLine); } return idString; } /** * get identification text for foci. */ QString BrainModelIdentification::getIdentificationTextForFoci() { if (idFilter.anyFociDataOn() == false) { return ""; } QString idString; BrainModelOpenGLSelectedItem focusID = openGL->getSelectedFocusProjection(); const int focusNumber = focusID.getItemIndex1(); BrainSet* brainSet = focusID.getBrainSet(); if ((brainSet != NULL) && (focusNumber >= 0)) { FociProjectionFile* ff = brainSet->getFociProjectionFile(); if (ff == NULL) { return ""; } CellProjection* focus = ff->getCellProjection(focusNumber); idString += getIdentificationTextForSingleFocus(focusID, focus, ff, false); } return idString; } /** * get identification text for a focus. */ QString BrainModelIdentification::getIdentificationTextForSingleFocus( BrainModelOpenGLSelectedItem focusID, CellProjection* focus, FociProjectionFile* fociProjectionFile, const bool volumeFlag) { QString idString; const int focusNumber = focusID.getItemIndex1(); BrainSet* brainSet = focusID.getBrainSet(); if (focus != NULL) { idString += (tagBoldStart + "Focus " + tagBoldEnd + QString::number(focusNumber) + tagNewLine); if (getDisplayFociAreaInformation()) { if (focus->getArea().isEmpty() == false) { idString += (tagIndentation + tagBoldStart + "Area: " + tagBoldEnd + linkStringToVocabulary(brainSet, focus->getArea()) + tagNewLine); } } if (getDisplayFociClassInformation()) { if (focus->getClassName().isEmpty() == false) { idString += (tagIndentation + tagBoldStart + "Class: " + tagBoldEnd + htmlTranslate(focus->getClassName()) + tagNewLine); } } if (getDisplayFociCommentInformation()) { if (focus->getComment().isEmpty() == false) { idString += (tagIndentation + tagBoldStart + "Comment: " + tagBoldEnd + StringUtilities::convertURLsToHyperlinks(htmlTranslate(focus->getComment())) + tagNewLine); } } if (getDisplayFociGeographyInformation()) { if (focus->getGeography().isEmpty() == false) { idString += (tagIndentation + tagBoldStart + "Geography: " + tagBoldEnd + linkStringToVocabulary(brainSet, focus->getGeography()) + tagNewLine); } } if (getDisplayFociNameInformation()) { idString += (tagIndentation + tagBoldStart + "Name: " + tagBoldEnd + linkToVocabulary(brainSet, htmlTranslate(focus->getName())) + tagNewLine); } float xyz[3]; focus->getXYZ(xyz); QString spaceName; const int studyNumber = focus->getStudyNumber(); const CellStudyInfo* csi = fociProjectionFile->getStudyInfo(studyNumber); if (csi != NULL) { spaceName = csi->getStereotaxicSpace(); if (spaceName.isEmpty() == false) { spaceName.insert(0, "("); spaceName.append(")"); } } if (getDisplayFociSizeInformation()) { if (focus->getSize() != 0.0) { idString += (tagIndentation + tagBoldStart + "Extent: " + tagBoldEnd + QString::number(focus->getSize(), 'f', significantDigits) + tagNewLine); } } if (getDisplayFociRegionOfInterestInformation()) { if (focus->getRegionOfInterest().isEmpty() == false) { idString += (tagIndentation + tagBoldStart + "RegionOfInterest: " + tagBoldEnd + linkStringToVocabulary(brainSet, focus->getRegionOfInterest()) + tagNewLine); } } Structure focusStructure; if (getDisplayFociOriginalStereotaxicPositionInformation()) { float volumeXYZ[3]; focus->getVolumeXYZ(volumeXYZ); if ((volumeFlag) || (volumeXYZ[0] != 0.0)) { idString += (tagIndentation + tagBoldStart + "Volume Position" + tagBoldEnd + spaceName + ": (" + QString::number(volumeXYZ[0], 'f', significantDigits) + ", " + QString::number(volumeXYZ[1], 'f', significantDigits) + ", " + QString::number(volumeXYZ[2], 'f', significantDigits) + ")" + tagNewLine); if (volumeXYZ[0] > 0) { focusStructure.setType(Structure::STRUCTURE_TYPE_CORTEX_RIGHT); } else if (volumeXYZ[1] < 0) { focusStructure.setType(Structure::STRUCTURE_TYPE_CORTEX_LEFT); } } } if (getDisplayFociOriginalStereotaxicPositionInformation()) { idString += (tagIndentation + tagBoldStart + "Stereotaxic Position (Original)" + tagBoldEnd + spaceName + ": (" + QString::number(xyz[0], 'f', significantDigits) + ", " + QString::number(xyz[1], 'f', significantDigits) + ", " + QString::number(xyz[2], 'f', significantDigits) + ")" + tagNewLine); } if (getDisplayFociStereotaxicPositionInformation()) { const BrainModelSurface* bms = focusID.getBrainModelSurface(); if (bms != NULL) { focusStructure = bms->getStructure(); } for (int i = 0; i < brainSet->getNumberOfBrainModels(); i++) { const BrainModelSurface* surface = brainSet->getBrainModelSurface(i); if (surface != NULL) { if (surface->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FIDUCIAL) { if (surface->getStructure() == focusStructure) { const CoordinateFile* cf = surface->getCoordinateFile(); QString surfaceSpaceName = cf->getHeaderTag(AbstractFile::headerTagCoordFrameID); bool doIt = false; if (StereotaxicSpace::validStereotaxicSpaceName(surfaceSpaceName)) { doIt = true; } else if (bms == surface) { doIt = true; surfaceSpaceName = "Unknown Space"; } if (doIt) { float projPos[3]; CellProjection* cp = dynamic_cast(focus); if (cp != NULL) { if (cp->getProjectedPosition(cf, surface->getTopologyFile(), false, false, false, projPos)) { idString += (tagIndentation + tagBoldStart + "Stereotaxic Position" + tagBoldEnd + " (" + surfaceSpaceName + "): (" + QString::number(projPos[0], 'f', significantDigits) + ", " + QString::number(projPos[1], 'f', significantDigits) + ", " + QString::number(projPos[2], 'f', significantDigits) + ")" + tagNewLine); } } } } } } } } if (getDisplayFociStatisticInformation()) { if (focus->getStatistic().isEmpty() == false) { idString += (tagIndentation + tagBoldStart + "Statistic: " + tagBoldEnd + focus->getStatistic() + tagNewLine); } } if (getDisplayFociStructureInformation()) { if (Structure::convertTypeToString(focus->getCellStructure()).isEmpty() == false) { idString += (tagIndentation + tagBoldStart + "Structure: " + tagBoldEnd + Structure::convertTypeToString(focus->getCellStructure()) + tagNewLine); } } // // Study Meta Data from Study Metadata File // const StudyMetaDataLinkSet smdls = focus->getStudyMetaDataLinkSet(); StudyMetaDataFile* smdf = brainSet->getStudyMetaDataFile(); idString += getIdentificationTextForStudies(smdf, smdls); // // Old Study Info // if ((studyNumber >= 0) && (studyNumber < fociProjectionFile->getNumberOfStudyInfo())) { csi = fociProjectionFile->getStudyInfo(studyNumber); } if (csi != NULL) { if (csi->getTitle().isEmpty() == false) { idString += (tagIndentation + tagBoldStart + "Study Title: " + tagBoldEnd + csi->getTitle() + tagNewLine); } if (csi->getAuthors().isEmpty() == false) { idString += (tagIndentation + tagBoldStart + "Study Authors: " + tagBoldEnd + csi->getAuthors() + tagNewLine); } if (csi->getCitation().isEmpty() == false) { idString += (tagIndentation + tagBoldStart + "Study Citation: " + tagBoldEnd + csi->getCitation() + tagNewLine); } if (csi->getURL().isEmpty() == false) { idString += (tagIndentation + tagBoldStart + "Study URL: " + tagBoldEnd + StringUtilities::convertURLsToHyperlinks(csi->getURL()) + tagNewLine); } if (csi->getKeywords().isEmpty() == false) { idString += (tagIndentation + tagBoldStart + "Study Keywords: " + tagBoldEnd + csi->getKeywords() + tagNewLine); } if (csi->getStereotaxicSpace().isEmpty() == false) { idString += (tagIndentation + tagBoldStart + "Study Stereotaxic Space: " + tagBoldEnd + csi->getStereotaxicSpace() + tagNewLine); } if (csi->getComment().isEmpty() == false) { idString += (tagIndentation + tagBoldStart + "Study Comment: " + tagBoldEnd + StringUtilities::convertURLsToHyperlinks(htmlTranslate(csi->getComment())) + tagNewLine); } } } return idString; } /** * get identification text for voxel. */ QString BrainModelIdentification::getIdentificationTextForVoxel() { QString idString; for (int indx = 0; indx < 3; indx++) { BrainModelOpenGLSelectedItem voxelID; switch (indx) { case 0: voxelID = openGL->getSelectedVoxelUnderlay(); break; case 1: voxelID = openGL->getSelectedVoxelOverlaySecondary(); break; case 2: voxelID = openGL->getSelectedVoxelOverlayPrimary(); break; } BrainSet* brainSet = voxelID.getBrainSet(); const int i = voxelID.getItemIndex1(); const int j = voxelID.getItemIndex2(); const int k = voxelID.getItemIndex3(); if ((brainSet != NULL) && (i >= 0) && (j >= 0) && (k >= 0)) { BrainModelVolume* bmv = brainSet->getBrainModelVolume(); if (bmv != NULL) { VolumeFile* selectionVolume = NULL; switch (indx) { case 0: selectionVolume = bmv->getUnderlayVolumeFile(); break; case 1: selectionVolume = bmv->getOverlaySecondaryVolumeFile(); break; case 2: selectionVolume = bmv->getOverlayPrimaryVolumeFile(); break; } // switch if (selectionVolume != NULL) { idString += getVolumeFileIdentificationText(brainSet, bmv, selectionVolume, i, j, k); // // Only show info for the first volume since it will cause // values for all volumes at the identified location // break; } } // if (bmv != NULL... } // if (brainSet != NULL... } // for (indx... return idString; } /* BrainModelVolume* bmv = theMainWindow->getBrainSet(windowNumber)->getBrainModelVolume(-1); if (bmv != NULL) { const BrainSet* selectedBrainSet = theMainWindow->getBrainSet(windowNumber); // // Place all volume viewer at selected voxel // int ijk[3] = { i, j, k }; for (int k = 0; k < BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS; k++) { // // Skip this window if the brain sets do no match // if (theMainWindow->getBrainSet(static_cast(k)) != selectedBrainSet) { continue; } bool adjustSlicesFlag = true; if (windowNumber == k) { if (tm != NULL) { adjustSlicesFlag = false; } } switch (bmv->getSelectedAxis(windowNumber)) { case VolumeFile::VOLUME_AXIS_X: case VolumeFile::VOLUME_AXIS_Y: case VolumeFile::VOLUME_AXIS_Z: case VolumeFile::VOLUME_AXIS_ALL: break; case VolumeFile::VOLUME_AXIS_OBLIQUE: case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: adjustSlicesFlag = false; break; case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } if (adjustSlicesFlag) { bmv->setSelectedOrthogonalSlices(k, ijk); GuiToolBar::updateAllToolBars(false); } } } */ /** * get identification text for a volume file. */ QString BrainModelIdentification::getVolumeFileIdentificationText(BrainSet* brainSet, BrainModelVolume* bmv, VolumeFile* selectionVolume, const int vi, const int vj, const int vk) { QString idString; // // Coordinate of voxel // float xyz[3]; selectionVolume->getVoxelCoordinate(vi, vj, vk, xyz); //if (tm != NULL) { // tm->multiplyPoint(xyz); //} const QString indent("\t"); // // Display the voxel index and coordinate // idString += (tagBoldStart + "VOXEL (" + selectionVolume->getVolumeTypeDescription() + ")" + tagBoldEnd + " IJK (" + QString::number(vi) + ", " + QString::number(vj) + ", " + QString::number(vk) + ") XYZ (" + QString::number(xyz[0], 'f', significantDigits) + ", " + QString::number(xyz[1], 'f', significantDigits) + ", " + QString::number(xyz[2], 'f', significantDigits) + ")" + tagNewLine); // // Loop through the file types // for (int m = 0; m < 6; m++) { // // Get name of file type and the files of that type // QString volumeName; std::vector files; VolumeFile::VOLUME_TYPE volumeType = VolumeFile::VOLUME_TYPE_UNKNOWN; switch (static_cast(m)) { case VolumeFile::VOLUME_TYPE_ANATOMY: volumeName = "Anatomy: "; brainSet->getVolumeAnatomyFiles(files); volumeType = VolumeFile::VOLUME_TYPE_ANATOMY; break; case VolumeFile::VOLUME_TYPE_FUNCTIONAL: volumeName = "Functional: "; brainSet->getVolumeFunctionalFiles(files); volumeType = VolumeFile::VOLUME_TYPE_FUNCTIONAL; break; case VolumeFile::VOLUME_TYPE_PAINT: volumeName = "Paint: "; brainSet->getVolumePaintFiles(files); volumeType = VolumeFile::VOLUME_TYPE_PAINT; break; case VolumeFile::VOLUME_TYPE_PROB_ATLAS: volumeName = "Prob Atlas: "; brainSet->getVolumeProbAtlasFiles(files); volumeType = VolumeFile::VOLUME_TYPE_PROB_ATLAS; break; case VolumeFile::VOLUME_TYPE_RGB: volumeName = "RGB: "; brainSet->getVolumeRgbFiles(files); volumeType = VolumeFile::VOLUME_TYPE_RGB; break; case VolumeFile::VOLUME_TYPE_ROI: volumeName = "ROI: "; //brainSet->getVolumeRgbFiles(files); volumeType = VolumeFile::VOLUME_TYPE_ROI; break; case VolumeFile::VOLUME_TYPE_SEGMENTATION: volumeName = "Segmentation: "; brainSet->getVolumeSegmentationFiles(files); volumeType = VolumeFile::VOLUME_TYPE_SEGMENTATION; break; case VolumeFile::VOLUME_TYPE_VECTOR: volumeName = "Vector: "; brainSet->getVolumeVectorFiles(files); volumeType = VolumeFile::VOLUME_TYPE_VECTOR; break; case VolumeFile::VOLUME_TYPE_UNKNOWN: break; } // // If there are data files // if (files.empty() == false) { // // add name of file type // idString += (volumeName); // // Print info about each file // for (unsigned int n = 0; n < files.size(); n++) { int ijk[3]; if (files[n]->convertCoordinatesToVoxelIJK(xyz, ijk)) { switch (volumeType) { case VolumeFile::VOLUME_TYPE_ANATOMY: if (bmv->getSelectedVolumeAnatomyFile() == files[n]) { idString += tagBoldStart; } idString += QString::number(files[n]->getVoxel(ijk), 'f', significantDigits); if (bmv->getSelectedVolumeAnatomyFile() == files[n]) { idString += tagBoldEnd; } break; case VolumeFile::VOLUME_TYPE_FUNCTIONAL: if (bmv->getSelectedVolumeFunctionalViewFile() == files[n]) { idString += tagBoldStart; } idString += QString::number(files[n]->getVoxel(ijk), 'f', significantDigits); if (bmv->getSelectedVolumeFunctionalViewFile() == files[n]) { idString += tagBoldEnd; } break; case VolumeFile::VOLUME_TYPE_PAINT: { if (bmv->getSelectedVolumePaintFile() == files[n]) { idString += tagBoldStart; } const int voxel = static_cast(files[n]->getVoxel(ijk)); if ((voxel >= 0) && (voxel < files[n]->getNumberOfRegionNames())) { idString += linkToVocabulary(brainSet, files[n]->getRegionNameFromIndex(voxel)); } else { idString += ("bad-index=" + QString::number(voxel)); } if (bmv->getSelectedVolumePaintFile() == files[n]) { idString += tagBoldEnd; } } break; case VolumeFile::VOLUME_TYPE_PROB_ATLAS: { const int voxel = static_cast(files[n]->getVoxel(ijk)); if ((voxel >= 0) && (voxel < files[n]->getNumberOfRegionNames())) { idString += linkToVocabulary(brainSet, files[n]->getRegionNameFromIndex(voxel)); } else { idString += "bad-index"; } } break; case VolumeFile::VOLUME_TYPE_ROI: break; case VolumeFile::VOLUME_TYPE_RGB: { if (bmv->getSelectedVolumeRgbFile() == files[n]) { idString += tagBoldStart; } const float rgb[3] = { files[n]->getVoxel(vi, vj, vk, 0), files[n]->getVoxel(vi, vj, vk, 1), files[n]->getVoxel(vi, vj, vk, 2) }; idString += ("(" + QString::number(rgb[0], 'f', significantDigits) + ", " + QString::number(rgb[1], 'f', significantDigits) + ", " + QString::number(rgb[2], 'f', significantDigits) + ")"); if (bmv->getSelectedVolumeRgbFile() == files[n]) { idString += tagBoldEnd; } } break; case VolumeFile::VOLUME_TYPE_SEGMENTATION: if (bmv->getSelectedVolumeSegmentationFile() == files[n]) { idString += tagBoldStart; } idString += QString::number(files[n]->getVoxel(ijk), 'f', significantDigits); if (bmv->getSelectedVolumeSegmentationFile() == files[n]) { idString += tagBoldEnd; } break; case VolumeFile::VOLUME_TYPE_VECTOR: if (bmv->getSelectedVolumeVectorFile() == files[n]) { idString += tagBoldStart; } idString += QString::number(files[n]->getVoxel(ijk), 'f', significantDigits); if (bmv->getSelectedVolumeVectorFile() == files[n]) { idString += tagBoldEnd; } break; case VolumeFile::VOLUME_TYPE_UNKNOWN: break; } // switch } // if (files[n]->convertCoordinatesToVoxelIJK(xyz, ijk)) { idString += " "; } // for idString += tagNewLine; for (unsigned int n = 0; n < files.size(); n++) { const StudyMetaDataLinkSet smdls = files[n]->getStudyMetaDataLinkSet(); const StudyMetaDataFile* smdf = brainSetParent->getStudyMetaDataFile(); idString += getIdentificationTextForStudies(smdf, smdls); // // Only show 1st prob atlas // if (volumeType == VolumeFile::VOLUME_TYPE_PROB_ATLAS) { break; } } } // if (files.empty() } // for (m... idString += tagNewLine; return idString; } /** * get identification text for volume cell. */ QString BrainModelIdentification::getIdentificationTextForVolumeCell() { QString idString; BrainModelOpenGLSelectedItem volumeCellID = openGL->getSelectedVolumeCell(); BrainSet* brainSet = volumeCellID.getBrainSet(); const int cellNumber = volumeCellID.getItemIndex1(); if ((brainSet != NULL) && (cellNumber >= 0)) { CellFile* cf = brainSet->getVolumeCellFile(); if (cf == NULL) { return ""; } CellData* cell = cf->getCell(cellNumber); idString += (tagBoldStart + "Volume Cell" + tagBoldEnd + " " + QString::number(cellNumber) + ": " + cell->getName() + tagNewLine); idString += (tagIndentation + tagBoldStart + "Class: " + tagBoldEnd + cell->getClassName() + tagNewLine); float xyz[3]; cell->getXYZ(xyz); idString += (tagIndentation + "Position: (" + QString::number(xyz[0], 'f', significantDigits) + ", " + QString::number(xyz[1], 'f', significantDigits) + ", " + QString::number(xyz[2], 'f', significantDigits) + ")" + tagNewLine); } return idString; } /** * get identification text for volume foci. */ QString BrainModelIdentification::getIdentificationTextForVolumeFoci() { QString idString; BrainModelOpenGLSelectedItem volumeFociID = openGL->getSelectedVolumeFoci(); BrainSet* brainSet = volumeFociID.getBrainSet(); const int focusNumber = volumeFociID.getItemIndex1(); if ((brainSet != NULL) && (focusNumber >= 0)) { FociProjectionFile* fpf = brainSet->getFociProjectionFile(); if (fpf == NULL) { return ""; } CellProjection* focus = fpf->getCellProjection(focusNumber); idString += getIdentificationTextForSingleFocus(volumeFociID, focus, fpf, true); /* idString += (tagBoldStart + "Volume Focus" + tagBoldEnd + " " + QString::number(focusNumber) + ": " + focus->getName() + " " + "Class: " + focus->getClassName() + tagNewLine); float xyz[3]; focus->getXYZ(xyz); idString += (tagIndentation + "Position: (" + QString::number(xyz[0], 'f', significantDigits) + ", " + QString::number(xyz[1], 'f', significantDigits) + ", " + QString::number(xyz[2], 'f', significantDigits) + ")" + tagNewLine); */ } return idString; } /** * get identification text for transform cell. */ QString BrainModelIdentification::getIdentificationTextForTransformCell() { QString idString; BrainModelOpenGLSelectedItem cellID = openGL->getSelectedTransformationCell(); BrainSet* brainSet = cellID.getBrainSet(); const int fileNumber = cellID.getItemIndex1(); const int cellNumber = cellID.getItemIndex2(); if ((brainSet != NULL) && (fileNumber >= 0) && (cellNumber >= 0)) { // // Note that a foci file is derived from a cell file // FociFile* ff = dynamic_cast(brainSet->getTransformationDataFile(fileNumber)); CellFile* cf = dynamic_cast(brainSet->getTransformationDataFile(fileNumber)); if ((ff == NULL) & (cf != NULL)) { CellData* cell = cf->getCell(cellNumber); idString += (tagBoldStart + "Transform Cell" + tagBoldEnd + " " + QString::number(cellNumber) + ": " + cell->getName() + tagIndentation + "Class: " + cell->getClassName() + tagNewLine); float xyz[3]; cell->getXYZ(xyz); idString += (tagIndentation + "Position: (" + QString::number(xyz[0], 'f', significantDigits) + ", " + QString::number(xyz[1], 'f', significantDigits) + ", " + QString::number(xyz[2], 'f', significantDigits) + ")" + tagNewLine); } } return idString; } /** * get identification text for transform contour cell. */ QString BrainModelIdentification::getIdentificationTextForTransformContourCell() { QString idString; BrainModelOpenGLSelectedItem cellID = openGL->getSelectedTransformationContourCell(); BrainSet* brainSet = cellID.getBrainSet(); const int fileNumber = cellID.getItemIndex1(); const int cellNumber = cellID.getItemIndex2(); if ((brainSet != NULL) && (fileNumber >= 0) && (cellNumber >= 0)) { // // Note that a foci file is derived from a cell file // FociFile* ff = dynamic_cast(brainSet->getTransformationDataFile(fileNumber)); CellFile* cf = dynamic_cast(brainSet->getTransformationDataFile(fileNumber)); if ((ff == NULL) & (cf != NULL)) { CellData* cell = cf->getCell(cellNumber); idString += (tagBoldStart + "Transform Contour Cell" + tagBoldEnd + " " + QString::number(cellNumber) + ": " + cell->getName() + tagIndentation + "Class: " + cell->getClassName() + tagNewLine); float xyz[3]; cell->getXYZ(xyz); idString += (tagIndentation + "Position: (" + QString::number(xyz[0], 'f', significantDigits) + ", " + QString::number(xyz[1], 'f', significantDigits) + ", " + QString::number(xyz[2], 'f', significantDigits) + ")" + tagNewLine); } } return idString; } /** * get identification text for transform foci. */ QString BrainModelIdentification::getIdentificationTextForTransformFoci() { QString idString; BrainModelOpenGLSelectedItem focusID = openGL->getSelectedTransformationFoci(); BrainSet* brainSet = focusID.getBrainSet(); const int fileNumber = focusID.getItemIndex1(); const int focusNumber = focusID.getItemIndex2(); if ((brainSet != NULL) && (fileNumber >= 0) && (focusNumber >= 0)) { // // Note that a foci file is derived from a cell file // FociFile* ff = dynamic_cast(brainSet->getTransformationDataFile(fileNumber)); if (ff != NULL) { CellData* focus = ff->getCell(focusNumber); idString += (tagBoldStart + "Transform Focus" + tagBoldEnd + " " + QString::number(focusNumber) + ": " + focus->getName() + tagIndentation + "Class: " + focus->getClassName() + tagNewLine); float xyz[3]; focus->getXYZ(xyz); idString += (tagIndentation + "Position: (" + QString::number(xyz[0], 'f', significantDigits) + ", " + QString::number(xyz[1], 'f', significantDigits) + ", " + QString::number(xyz[2], 'f', significantDigits) + ")" + tagNewLine); } } return idString; } /** * get identification text for palette. */ QString BrainModelIdentification::getIdentificationTextForPalette(const bool metricFlag) { QString idString; BrainModelOpenGLSelectedItem paletteID = openGL->getSelectedPaletteShape(); QString paletteName("Shape Palette"); if (metricFlag) { paletteID = openGL->getSelectedPaletteMetric(); paletteName = "Metric Palette"; } BrainSet* brainSet = paletteID.getBrainSet(); const int paletteNumber = paletteID.getItemIndex1(); const int entryIndex = paletteID.getItemIndex2(); //const int windowNumber = paletteID.getViewingWindowNumber(); PaletteFile* pf = brainSet->getPaletteFile(); if ((paletteNumber < 0) || (paletteNumber >= pf->getNumberOfPalettes())) { return ""; } DisplaySettingsMetric* dsm = brainSet->getDisplaySettingsMetric(); //MetricFile* mf = brainSet->getMetricFile(); const Palette* palette = pf->getPalette(paletteNumber); if (entryIndex >= palette->getNumberOfPaletteEntries()) { return ""; } PaletteEntry* pe = (PaletteEntry*)palette->getPaletteEntry(entryIndex); float value = pe->getValue(); const int colorIndex = pe->getColorIndex(); const PaletteColor* pc = pf->getPaletteColor(colorIndex); QString name = pc->getName(); const int nextPaletteEntryIndex = entryIndex + 1; float valueNext = 0.0; if (nextPaletteEntryIndex >= palette->getNumberOfPaletteEntries()) { if (palette->getPositiveOnly()) { valueNext = 0.0; } else { valueNext = -1.0; } } else { PaletteEntry* pe = (PaletteEntry*)palette->getPaletteEntry(nextPaletteEntryIndex); valueNext = pe->getValue(); } BrainModelOpenGLSelectedItem nodeID = openGL->getSelectedNode(); float posMinMetric = 0.0, posMaxMetric = 0.0, negMinMetric = 0.0, negMaxMetric = 0.0; if (metricFlag) { int displayColumn, thresholdColumn; dsm->getMetricsForColoringAndPalette(displayColumn, thresholdColumn, negMaxMetric, negMinMetric, posMinMetric, posMaxMetric); } else { DisplaySettingsSurfaceShape* dsss = brainSet->getDisplaySettingsSurfaceShape(); const int col = dsss->getShapeColumnForPaletteAndColorMapping(); SurfaceShapeFile* ssf = brainSet->getSurfaceShapeFile(); if (col >= 0) { ssf->getColumnColorMappingMinMax(col, negMaxMetric, posMaxMetric); } else { return ""; } //const int col = dsss->getSelectedDisplayColumn(windowNumber); //ssf->getColumnColorMappingMinMax(col, negMaxMetric, posMaxMetric); } if (value >= 0.0) { value = value * (posMaxMetric - posMinMetric) + posMinMetric; } else { float num = (negMaxMetric - negMinMetric); if (num < 0.0) { num = -num; } value = value * num + negMinMetric; } if (valueNext >= 0.0) { valueNext = valueNext * (posMaxMetric - posMinMetric) + posMinMetric; } else { float num = (negMaxMetric - negMinMetric); if (num < 0.0) { num = -num; } valueNext = valueNext * num + negMinMetric; } idString += (paletteName + ": " + name + " (" + QString::number(valueNext, 'f', significantDigits) + ", " + QString::number(value, 'f', significantDigits) + ")" + tagNewLine); return idString; } /** * get identification text for voxel cloud functional. */ QString BrainModelIdentification::getIdentificationTextForVoxelCloudFunctional() { QString idString; BrainModelOpenGLSelectedItem cloudID = openGL->getSelectedVoxelFunctionalCloud(); BrainSet* brainSet = cloudID.getBrainSet(); const int i = cloudID.getItemIndex1(); const int j = cloudID.getItemIndex2(); const int k = cloudID.getItemIndex3(); if ((brainSet != NULL) && (i >= 0) && (j >= 0) && (k >= 0)) { BrainModelVolume* bmv = brainSet->getBrainModelVolume(); if (bmv != NULL) { VolumeFile* vf = bmv->getSelectedVolumeFunctionalViewFile(); if (vf != NULL) { idString += getVolumeFileIdentificationText(brainSet, bmv, vf, i, j, k); } } } return idString; } /** * get identification text for VTK model. */ QString BrainModelIdentification::getIdentificationTextForVtkModel() { QString idString; BrainModelOpenGLSelectedItem vtkID = openGL->getSelectedVtkModel(); BrainSet* brainSet = vtkID.getBrainSet(); const int modelNum = vtkID.getItemIndex1(); const int openGLType = vtkID.getItemIndex2(); const int itemNum = vtkID.getItemIndex3(); if ((brainSet != NULL) && (modelNum >= 0) && (itemNum >= 0)) { if ((modelNum >= 0) && (modelNum < brainSet->getNumberOfVtkModelFiles())) { const VtkModelFile* vmf = brainSet->getVtkModelFile(modelNum); if (openGLType == GL_TRIANGLES) { float xyz[3]; vmf->getTriangleCoordinate(itemNum, xyz); const TransformationMatrixFile* tmf = brainSet->getTransformationMatrixFile(); const TransformationMatrix* tm = vmf->getAssociatedTransformationMatrix(); if (tmf->getMatrixValid(tm)) { tm->multiplyPoint(xyz); } const int* tv = vmf->getTriangle(itemNum); idString += ("VTK Model " + FileUtilities::basename(vmf->getFileName()) + ", Triangle " + QString::number(itemNum) + " (" + QString::number(tv[0]) + ", " + QString::number(tv[1]) + ", " + QString::number(tv[2]) + ") " + ": (" + QString::number(xyz[0], 'f', significantDigits) + ", " + QString::number(xyz[1], 'f', significantDigits) + ", " + QString::number(xyz[2], 'f', significantDigits) + ")" + tagNewLine); } else if (openGLType == GL_POINTS) { const int pointNumber = *vmf->getVertex(itemNum); const float* xyz = vmf->getCoordinateFile()->getCoordinate(pointNumber); const unsigned char* rgba = vmf->getPointColor(pointNumber); idString += ("VTK Model " + FileUtilities::basename(vmf->getFileName()) + ", Vertex " + QString::number(itemNum) + ": (" + QString::number(xyz[0], 'f', significantDigits) + ", " + QString::number(xyz[1], 'f', significantDigits) + ", " + QString::number(xyz[2], 'f', significantDigits) + ") Color (" + QString::number(rgba[0]) + ", " + QString::number(rgba[1]) + ", " + QString::number(rgba[2]) + ", " + QString::number(rgba[3]) + ")" + tagNewLine); } } } return idString; } /** * get identification text for Contour. */ QString BrainModelIdentification::getIdentificationTextForContour() { QString idString; BrainModelOpenGLSelectedItem contourID = openGL->getSelectedContour(); BrainSet* brainSet = contourID.getBrainSet(); const int contourNumber = contourID.getItemIndex1(); if ((brainSet != NULL) && (contourNumber >= 0)) { BrainModelContours* bmc = brainSet->getBrainModelContours(); if (bmc != NULL) { if (contourNumber >= 0) { const ContourFile* cf = bmc->getContourFile(); if (cf != NULL) { const CaretContour* contour = cf->getContour(contourNumber); if (contour != NULL) { const int pointNumber = contourID.getItemIndex2(); idString += (tagBoldStart + "Contour" + tagBoldEnd + ": " + QString::number(contourNumber) + ", Point: " + QString::number(pointNumber) + tagNewLine); idString += (tagIndentation + "Section: " + QString::number(contour->getSectionNumber()) + tagNewLine); float x, y, z; contour->getPointXYZ(pointNumber, x, y, z); idString += (tagIndentation + "Position: (" + QString::number(x, 'f', significantDigits) + ", " + QString::number(y, 'f', significantDigits) + ", " + QString::number(z, 'f', significantDigits) + ")" + tagNewLine); } } } } } return idString; } /** * get identification text for contour cell. */ QString BrainModelIdentification::getIdentificationTextForContourCell() { QString idString; BrainModelOpenGLSelectedItem cellID = openGL->getSelectedContourCell(); BrainSet* brainSet = cellID.getBrainSet(); const int cellNumber = cellID.getItemIndex1(); if ((brainSet != NULL) && (cellNumber >= 0)) { ContourCellFile* cf = brainSet->getContourCellFile(); if (cf != NULL) { CellData* cell = cf->getCell(cellNumber); idString += (tagBoldStart + "Contour Cell" + tagBoldEnd + " " + QString::number(cellNumber) + ": " + cell->getName() + tagIndentation + "Class: " + cell->getClassName() + tagNewLine); float xyz[3]; cell->getXYZ(xyz); idString += (tagIndentation + "Position: (" + QString::number(xyz[0], 'f', significantDigits) + ", " + QString::number(xyz[1], 'f', significantDigits) + ", " + QString::number(xyz[2], 'f', significantDigits) + ")" + tagNewLine); } } return idString; } /** * get the identification text for vocabulary. */ QString BrainModelIdentification::getIdentificationTextForVocabulary(const bool enableHtml, const QString& vocabularyName) { setupHtmlOrTextTags(enableHtml); const VocabularyFile* vf = brainSetParent->getVocabularyFile(); const bool caseSensitiveFlag = false; const VocabularyFile::VocabularyEntry* ve = vf->getBestMatchingVocabularyEntry(vocabularyName, caseSensitiveFlag); if (ve == NULL) { return ""; } QString idString; idString += tagBoldStart; idString += "Abbreviation"; idString += tagBoldEnd; idString += ": "; idString += ve->getAbbreviation(); idString += tagNewLine; if (ve->getFullName().isEmpty() == false) { idString += tagBoldStart; idString += "Full Name"; idString += tagBoldEnd; idString += ": "; idString += ve->getFullName(); idString += tagNewLine; } if (ve->getClassName().isEmpty() == false) { idString += tagBoldStart; idString += "Class Name"; idString += tagBoldEnd; idString += ": "; idString += ve->getClassName(); idString += tagNewLine; } if (ve->getVocabularyID().isEmpty() == false) { idString += tagBoldStart; idString += "Vocabulary ID"; idString += tagBoldEnd; idString += ": "; idString += ve->getVocabularyID(); idString += tagNewLine; } if (ve->getOntologySource().isEmpty() == false) { idString += tagBoldStart; idString += "Ontology Source"; idString += tagBoldEnd; idString += ": "; idString += ve->getOntologySource(); idString += tagNewLine; } if (ve->getTermID().isEmpty() == false) { idString += tagBoldStart; idString += "Term ID"; idString += tagBoldEnd; idString += ": "; idString += ve->getTermID(); idString += tagNewLine; } if (ve->getDescription().isEmpty() == false) { idString += tagBoldStart; idString += "Description"; idString += tagBoldEnd; idString += ": "; idString += ve->getDescription(); idString += tagNewLine; } const StudyMetaDataFile* smdf = brainSetParent->getStudyMetaDataFile(); idString += getIdentificationTextForStudies(enableHtml, smdf, ve->getStudyMetaDataLinkSet()); /* const int studyIndex = smdf->getStudyIndexFromLink(ve->getStudyMetaDataLink()); if (studyIndex >= 0) { const StudyMetaDataLink smdl = ve->getStudyMetaDataLink(); idString += getIdentificationTextForStudy(enableHtml, smdf->getStudyMetaData(studyIndex), studyIndex, &smdl); } */ if (vf != NULL) { const int studyNumber = ve->getStudyNumber(); if ((studyNumber >= 0) && (studyNumber < vf->getNumberOfStudyInfo())) { const CellStudyInfo* csi = vf->getStudyInfo(studyNumber); const QString s2 = csi->getFullDescriptionForDisplayToUser(true); if (s2.isEmpty() == false) { idString += s2; } } } return idString; } /** * get the identification text for studies. */ QString BrainModelIdentification::getIdentificationTextForStudies(const bool enableHtml, const StudyMetaDataFile* smdf, const StudyMetaDataLinkSet& smdls) { setupHtmlOrTextTags(enableHtml); return getIdentificationTextForStudies(smdf, smdls); } /** * get the identification text for a study. */ QString BrainModelIdentification::getIdentificationTextForStudy(const bool enableHtml, const StudyMetaData* smd, const int studyIndex, const StudyMetaDataLink* smdl) { setupHtmlOrTextTags(enableHtml); return getIdentificationTextForStudy(smd, studyIndex, smdl); } /** * get the identification text for studies. */ QString BrainModelIdentification::getIdentificationTextForStudies(const StudyMetaDataFile* smdf, const StudyMetaDataLinkSet& smdls) { QString idString; const int num = smdls.getNumberOfStudyMetaDataLinks(); for (int i = 0; i < num; i++) { const StudyMetaDataLink smdl = smdls.getStudyMetaDataLink(i); const int smdIndex = smdf->getStudyIndexFromLink(smdl); if ((smdIndex >= 0) && (smdIndex < smdf->getNumberOfStudyMetaData())) { const StudyMetaData* smd = smdf->getStudyMetaData(smdIndex); if (smd != NULL) { idString += getIdentificationTextForStudy(smd, smdIndex, &smdl); } } } return idString; } /** * get the identification text for a study. */ QString BrainModelIdentification::getIdentificationTextForStudy(const StudyMetaData* smd, const int studyIndex, const StudyMetaDataLink* smdl) { if (getDisplayStudyInformation() == false) { return ""; } if (idFilter.anyStudyDataOn() == false) { return ""; } QString idString; // // Study Number // idString += (tagBoldStart + "Study Number " + tagBoldEnd + QString::number(studyIndex + 1) + tagNewLine); // // Do Name first // if (smd->getName().isEmpty() == false) { if (getDisplayStudyNameInformation()) { idString += tagIndentation; idString += tagBoldStart; idString += "Study Name"; idString += tagBoldEnd; idString += ": "; idString += htmlTranslate(smd->getName()); idString += tagNewLine; } } if (smd->getTitle().isEmpty() == false) { if (getDisplayStudyTitleInformation()) { idString += tagIndentation; idString += tagBoldStart; idString += "Study Title"; idString += tagBoldEnd; idString += ": "; idString += htmlTranslate(smd->getTitle()); idString += tagNewLine; } } if (smd->getAuthors().isEmpty() == false) { if (getDisplayStudyAuthorsInformation()) { idString += tagIndentation; idString += tagBoldStart; idString += "Study Authors"; idString += tagBoldEnd; idString += ": "; idString += htmlTranslate(smd->getAuthors()); idString += tagNewLine; } } if (smd->getCitation().isEmpty() == false) { if (getDisplayStudyCitationInformation()) { idString += tagIndentation; idString += tagBoldStart; idString += "Study Citation"; idString += tagBoldEnd; idString += ": "; idString += htmlTranslate(smd->getCitation()); idString += tagNewLine; } } if (smd->getComment().isEmpty() == false) { if (getDisplayStudyCommentInformation()) { idString += tagIndentation; idString += tagBoldStart; idString += "Study Comment"; idString += tagBoldEnd; idString += ": "; idString += StringUtilities::convertURLsToHyperlinks(htmlTranslate(smd->getComment())); idString += tagNewLine; } } if (smd->getStudyDataFormat().isEmpty() == false) { if (getDisplayStudyDataFormatInformation()) { idString += tagIndentation; idString += tagBoldStart; idString += "Study Data Format"; idString += tagBoldEnd; idString += ": "; idString += htmlTranslate(smd->getStudyDataFormat()); idString += tagNewLine; } } if (smd->getStudyDataType().isEmpty() == false) { if (getDisplayStudyDataTypeInformation()) { idString += tagIndentation; idString += tagBoldStart; idString += "Study Data Type"; idString += tagBoldEnd; idString += ": "; idString += htmlTranslate(smd->getStudyDataType()); idString += tagNewLine; } } if (smd->getDocumentObjectIdentifier().isEmpty() == false) { if (getDisplayStudyDOIInformation()) { idString += tagIndentation; QString theURL; if (smd->getDocumentObjectIdentifier().startsWith("http:")) { theURL = smd->getDocumentObjectIdentifier(); } else { theURL = "http://dx.doi.org/" + smd->getDocumentObjectIdentifier(); } idString += tagBoldStart; idString += "Study DOI/URL"; idString += tagBoldEnd; idString += ": "; idString += StringUtilities::convertURLsToHyperlinks(theURL); idString += tagNewLine; } } if (smd->getKeywords().isEmpty() == false) { if (getDisplayStudyKeywordsInformation()) { idString += tagIndentation; idString += tagBoldStart; idString += "Study Keywords"; idString += tagBoldEnd; idString += ": "; idString += htmlTranslate(smd->getKeywords()); idString += tagNewLine; } } if (smd->getMedicalSubjectHeadings().isEmpty() == false) { if (getDisplayStudyMedicalSubjectHeadingsInformation()) { idString += tagIndentation; idString += tagBoldStart; idString += "Study Medical Subject Headings"; idString += tagBoldEnd; idString += ": "; idString += htmlTranslate(smd->getMedicalSubjectHeadings()); idString += tagNewLine; } } if (smd->getPartitioningSchemeAbbreviation().isEmpty() == false) { if (getDisplayStudyPartSchemeAbbrevInformation()) { idString += tagIndentation; idString += tagBoldStart; idString += "Study Partitioning Scheme Abbreviation"; idString += tagBoldEnd; idString += ": "; idString += htmlTranslate(smd->getPartitioningSchemeAbbreviation()); idString += tagNewLine; } } if (smd->getPartitioningSchemeFullName().isEmpty() == false) { if (getDisplayStudyPartSchemeFullInformation()) { idString += tagIndentation; idString += tagBoldStart; idString += "Study Partitioning Scheme Full Name"; idString += tagBoldEnd; idString += ": "; idString += htmlTranslate(smd->getPartitioningSchemeFullName()); idString += tagNewLine; } } if (smd->getPubMedID().isEmpty() == false) { if (getDisplayStudyPubMedIDInformation()) { if (smd->getPubMedID().startsWith(StudyMetaData::getProjectIDInPubMedIDPrefix())) { idString += tagIndentation; idString += tagBoldStart; idString += "Study PubMed ID"; idString += tagBoldEnd; idString += ": "; idString += smd->getPubMedID(); idString += tagNewLine; } else { const QString pubURL = "http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?cmd=retrieve&db=pubmed&list_uids=" + smd->getPubMedID().trimmed(); idString += tagIndentation; idString += tagBoldStart; idString += "Study PubMed URL"; idString += tagBoldEnd; idString += ": "; idString += ("" + smd->getPubMedID().trimmed() + ""); //idString += StringUtilities::convertURLsToHyperlinks(pubURL); idString += tagNewLine; } } } if (smd->getProjectID().isEmpty() == false) { if (getDisplayStudyProjectIDInformation()) { idString += tagIndentation; idString += tagBoldStart; idString += "Study Project ID"; idString += tagBoldEnd; idString += ": "; idString += smd->getProjectID(); idString += tagNewLine; } } if (smd->getStereotaxicSpace().isEmpty() == false) { if (getDisplayStudyStereotaxicSpaceInformation()) { idString += tagIndentation; idString += tagBoldStart; idString += "Study Stereotaxic Space"; idString += tagBoldEnd; idString += ": "; idString += htmlTranslate(smd->getStereotaxicSpace()); idString += tagNewLine; } } if (smd->getStereotaxicSpaceDetails().isEmpty() == false) { if (getDisplayStudyStereotaxicSpaceDetailsInformation()) { idString += tagIndentation; idString += tagBoldStart; idString += "Study Stereotaxic Space Details"; idString += tagBoldEnd; idString += ": "; idString += htmlTranslate(smd->getStereotaxicSpaceDetails()); idString += tagNewLine; } } // // Is link valid // if (smdl != NULL) { // // Display table information? // if (getDisplayStudyTableInformation() && idFilter.anyStudyTableDataOn()) { const QString tableNumber = smdl->getTableNumber(); const StudyMetaData::Table* table = smd->getTableByTableNumber(tableNumber); if (table != NULL) { idString += tagIndentation; idString += tagBoldStart; idString += "Table Number"; idString += tagBoldEnd; idString += ": "; idString += table->getNumber(); idString += tagNewLine; if (table->getFooter().isEmpty() == false) { if (getDisplayStudyTableFooterInformation()) { idString += tagIndentation; idString += tagBoldStart; idString += "Table Footer"; idString += tagBoldEnd; idString += ": "; idString += htmlTranslate(table->getFooter()); idString += tagNewLine; } } if (table->getHeader().isEmpty() == false) { if (getDisplayStudyTableHeaderInformation()) { idString += tagIndentation; idString += tagBoldStart; idString += "Table Header"; idString += tagBoldEnd; idString += ": "; idString += htmlTranslate(table->getHeader()); idString += tagNewLine; } } if (table->getSizeUnits().isEmpty() == false) { if (getDisplayStudyTableSizeUnitsInformation()) { idString += tagIndentation; idString += tagBoldStart; idString += "Table Size Units"; idString += tagBoldEnd; idString += ": "; idString += htmlTranslate(table->getSizeUnits()); idString += tagNewLine; } } if (table->getStatisticType().isEmpty() == false) { if (getDisplayStudyTableStatisticInformation()) { idString += tagIndentation; idString += tagBoldStart; idString += "Table Statistic Type"; idString += tagBoldEnd; idString += ": "; idString += htmlTranslate(table->getStatisticType()); idString += tagNewLine; } } if (table->getStatisticDescription().isEmpty() == false) { if (getDisplayStudyTableStatisticDescriptionInformation()) { idString += tagIndentation; idString += tagBoldStart; idString += "Table Statistic Description"; idString += tagBoldEnd; idString += ": "; idString += htmlTranslate(table->getStatisticDescription()); idString += tagNewLine; } } if (table->getVoxelDimensions().isEmpty() == false) { if (getDisplayStudyTableVoxelSizeInformation()) { idString += tagIndentation; idString += tagBoldStart; idString += "Table Voxel Dimensions"; idString += tagBoldEnd; idString += ": "; idString += htmlTranslate(table->getVoxelDimensions()); idString += tagNewLine; } } // // Is link valid? // if (smdl != NULL) { const StudyMetaData::SubHeader* sh = table->getSubHeaderBySubHeaderNumber(smdl->getTableSubHeaderNumber()); if (sh != NULL) { idString += getStudyMetaDataSubHeaderIdentificationText(sh, "Table"); } } } } // // Display figure information? // if (getDisplayStudyFigureInformation() && idFilter.anyStudyFigureDataOn()) { const QString figureNumber = smdl->getFigureNumber(); const StudyMetaData::Figure* figure = smd->getFigureByFigureNumber(figureNumber); if (figure != NULL) { // // Do number first // idString += tagIndentation; idString += tagBoldStart; idString += "Figure Number"; idString += tagBoldEnd; idString += ": "; idString += figure->getNumber(); idString += tagNewLine; if (figure->getLegend().isEmpty() == false) { if (getDisplayStudyFigureInformation()) { idString += tagIndentation; idString += tagBoldStart; idString += "Figure Legend"; idString += tagBoldEnd; idString += ": "; idString += htmlTranslate(figure->getLegend()); idString += tagNewLine; } } if (smdl != NULL) { const StudyMetaData::Figure::Panel* panel = figure->getPanelByPanelNumberOrLetter(smdl->getFigurePanelNumberOrLetter()); if (panel != NULL) { if (idFilter.anyStudyFigurePanelDataOn()) { // // Do number first // idString += tagIndentation; idString += tagBoldStart; idString += "Figure Panel Number/Letter"; idString += tagBoldEnd; idString += ": "; idString += QString(panel->getPanelNumberOrLetter()); idString += tagNewLine; if (getDisplayStudyFigurePanelDescriptionInformation()) { if (panel->getDescription().isEmpty() == false) { idString += tagIndentation; idString += tagBoldStart; idString += "Figure Panel Description"; idString += tagBoldEnd; idString += ": "; idString += htmlTranslate(panel->getDescription()); idString += tagNewLine; } } if (getDisplayStudyFigurePanelTaskDescriptionInformation()) { if (panel->getTaskDescription().isEmpty() == false) { idString += tagIndentation; idString += tagBoldStart; idString += "Figure Panel Task Description"; idString += tagBoldEnd; idString += ": "; idString += htmlTranslate(panel->getTaskDescription()); idString += tagNewLine; } } if (getDisplayStudyFigurePanelTaskBaselineInformation()) { if (panel->getTaskBaseline().isEmpty() == false) { idString += tagIndentation; idString += tagBoldStart; idString += "Figure Panel Task Baseline"; idString += tagBoldEnd; idString += ": "; idString += htmlTranslate(panel->getTaskBaseline()); idString += tagNewLine; } } if (getDisplayStudyFigurePanelTestAttributesInformation()) { if (panel->getTestAttributes().isEmpty() == false) { idString += tagIndentation; idString += tagBoldStart; idString += "Figure Panel Test Attributes"; idString += tagBoldEnd; idString += ": "; idString += htmlTranslate(panel->getTestAttributes()); idString += tagNewLine; } } } } } } } // // Display Page Reference information? // if (idFilter.anyPageReferenceDataOn()) { const QString pageRefPageNumber = smdl->getPageReferencePageNumber(); const StudyMetaData::PageReference* pageRef = smd->getPageReferenceByPageNumber(pageRefPageNumber); if (pageRef != NULL) { // // Do number first // idString += tagIndentation; idString += tagBoldStart; idString += "Page Reference"; idString += tagBoldEnd; idString += ": "; idString += pageRef->getPageNumber(); idString += tagNewLine; if (getDisplayStudyPageReferenceCommentInformation()) { if (pageRef->getComment().isEmpty() == false) { idString += tagIndentation; idString += tagBoldStart; idString += "Page Reference Comment"; idString += tagBoldEnd; idString += ": "; idString += htmlTranslate(pageRef->getComment()); idString += tagNewLine; } } if (getDisplayStudyPageReferenceHeaderInformation()) { if (pageRef->getHeader().isEmpty() == false) { idString += tagIndentation; idString += tagBoldStart; idString += "Page Reference Header"; idString += tagBoldEnd; idString += ": "; idString += htmlTranslate(pageRef->getHeader()); idString += tagNewLine; } } if (getDisplayStudyPageReferenceSizeUnitsInformation()) { if (pageRef->getSizeUnits().isEmpty() == false) { idString += tagIndentation; idString += tagBoldStart; idString += "Page Reference Size Units"; idString += tagBoldEnd; idString += ": "; idString += htmlTranslate(pageRef->getSizeUnits()); idString += tagNewLine; } } if (getDisplayStudyPageReferenceStatisticInformation()) { if (pageRef->getStatisticType().isEmpty() == false) { idString += tagIndentation; idString += tagBoldStart; idString += "PageReference Statistic Type"; idString += tagBoldEnd; idString += ": "; idString += htmlTranslate(pageRef->getStatisticType()); idString += tagNewLine; } } if (getDisplayStudyPageReferenceStatisticDescriptionInformation()) { if (pageRef->getStatisticDescription().isEmpty() == false) { idString += tagIndentation; idString += tagBoldStart; idString += "Page Reference Statistic Description"; idString += tagBoldEnd; idString += ": "; idString += htmlTranslate(pageRef->getStatisticDescription()); idString += tagNewLine; } } if (getDisplayStudyPageReferenceVoxelSizeInformation()) { if (pageRef->getVoxelDimensions().isEmpty() == false) { idString += tagIndentation; idString += tagBoldStart; idString += "Page Reference Voxel Dimensions"; idString += tagBoldEnd; idString += ": "; idString += htmlTranslate(pageRef->getVoxelDimensions()); idString += tagNewLine; } } // // Is link valid? // if (smdl != NULL) { const StudyMetaData::SubHeader* sh = pageRef->getSubHeaderBySubHeaderNumber(smdl->getPageReferenceSubHeaderNumber()); if (sh != NULL) { idString += getStudyMetaDataSubHeaderIdentificationText(sh, "Page Reference"); } } } } /* if (smdl->getPageNumber().isEmpty() == false) { if (getDisplayStudyPageNumberInformation()) { idString += tagIndentation; idString += tagBoldStart; idString += "Page Number"; idString += tagBoldEnd; idString += ": "; idString += smdl->getPageNumber(); idString += tagNewLine; } } */ } return idString; } /** * Get ID string for study meta data sub header */ QString BrainModelIdentification::getStudyMetaDataSubHeaderIdentificationText( const StudyMetaData::SubHeader* sh, const QString& namePrefix) const { if (idFilter.anySubHeaderDataOn() == false) { return ""; } QString idString; idString += tagIndentation; idString += tagBoldStart; idString += namePrefix; idString += " Sub Header Number"; idString += tagBoldEnd; idString += ": "; idString += sh->getNumber(); idString += tagNewLine; if (getDisplayStudySubHeaderNameInformation()) { if (sh->getName().isEmpty() == false) { idString += tagIndentation; idString += tagBoldStart; idString += namePrefix; idString += " Sub Header Name"; idString += tagBoldEnd; idString += ": "; idString += htmlTranslate(sh->getName()); idString += tagNewLine; } } if (getDisplayStudySubHeaderShortNameInformation()) { if (sh->getShortName().isEmpty() == false) { idString += tagIndentation; idString += tagBoldStart; idString += namePrefix; idString += " Sub Header Short Name"; idString += tagBoldEnd; idString += ": "; idString += htmlTranslate(sh->getShortName()); idString += tagNewLine; } } if (getDisplayStudySubHeaderTaskDescriptionInformation()) { if (sh->getTaskDescription().isEmpty() == false) { idString += tagIndentation; idString += tagBoldStart; idString += namePrefix; idString += " Sub Header Task Description"; idString += tagBoldEnd; idString += ": "; idString += htmlTranslate(sh->getTaskDescription()); idString += tagNewLine; } } if (getDisplayStudySubHeaderTaskBaselineInformation()) { if (sh->getTaskBaseline().isEmpty() == false) { idString += tagIndentation; idString += tagBoldStart; idString += namePrefix; idString += " Sub Header Task Baseline"; idString += tagBoldEnd; idString += ": "; idString += htmlTranslate(sh->getTaskBaseline()); idString += tagNewLine; } } if (getDisplayStudySubHeaderTestAttributesInformation()) { if (sh->getTestAttributes().isEmpty() == false) { idString += tagIndentation; idString += tagBoldStart; idString += namePrefix; idString += " Sub Header Test Attributes"; idString += tagBoldEnd; idString += ": "; idString += htmlTranslate(sh->getTestAttributes()); idString += tagNewLine; } } return idString; } /** * apply a scene (update dialog). */ void BrainModelIdentification::showScene(const SceneFile::Scene& scene, QString& /*errorMessage*/) { const int numClasses = scene.getNumberOfSceneClasses(); for (int nc = 0; nc < numClasses; nc++) { const SceneFile::SceneClass* sc = scene.getSceneClass(nc); if (sc->getName() == "BrainModelIdentification") { const int num = sc->getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc->getSceneInfo(i); const QString infoName(si->getName()); if (infoName == "displayBorderInformation") { setDisplayBorderInformation(si->getValueAsBool()); } else if (infoName == "displayCellInformation") { setDisplayCellInformation(si->getValueAsBool()); } else if (infoName == "displayFociInformation") { setDisplayFociInformation(si->getValueAsBool()); } else if (infoName == "displayFociNameInformation") { setDisplayFociNameInformation(si->getValueAsBool()); } else if (infoName == "displayFociClassInformation") { setDisplayFociClassInformation(si->getValueAsBool()); } else if (infoName == "displayFociOriginalStereotaxicPositionInformation") { setDisplayFociOriginalStereotaxicPositionInformation(si->getValueAsBool()); } else if (infoName == "displayFociStereotaxicPositionInformation") { setDisplayFociStereotaxicPositionInformation(si->getValueAsBool()); } else if (infoName == "displayFociAreaInformation") { setDisplayFociAreaInformation(si->getValueAsBool()); } else if (infoName == "displayFociGeographyInformation") { setDisplayFociGeographyInformation(si->getValueAsBool()); } else if (infoName == "displayFociRegionOfInterestInformation") { setDisplayFociRegionOfInterestInformation(si->getValueAsBool()); } else if (infoName == "displayFociSizeInformation") { setDisplayFociSizeInformation(si->getValueAsBool()); } else if (infoName == "displayFociStructureInformation") { setDisplayFociStructureInformation(si->getValueAsBool()); } else if (infoName == "displayFociStatisticInformation") { setDisplayFociStatisticInformation(si->getValueAsBool()); } else if (infoName == "displayFociCommentInformation") { setDisplayFociCommentInformation(si->getValueAsBool()); } else if (infoName == "displayVoxelInformation") { setDisplayVoxelInformation(si->getValueAsBool()); } else if (infoName == "displayContourInformation") { setDisplayContourInformation(si->getValueAsBool()); } else if (infoName == "displayNodeInformation") { setDisplayNodeInformation(si->getValueAsBool()); } else if (infoName == "displayNodeCoordInformation") { setDisplayNodeCoordInformation(si->getValueAsBool()); } else if (infoName == "displayNodeLatLonInformation") { setDisplayNodeLatLonInformation(si->getValueAsBool()); } else if (infoName == "displayNodePaintInformation") { setDisplayNodePaintInformation(si->getValueAsBool()); } else if (infoName == "displayNodeProbAtlasInformation") { setDisplayNodeProbAtlasInformation(si->getValueAsBool()); } else if (infoName == "displayNodeRgbPaintInformation") { setDisplayNodeRgbPaintInformation(si->getValueAsBool()); } else if (infoName == "displayNodeMetricInformation") { setDisplayNodeMetricInformation(si->getValueAsBool()); } else if (infoName == "displayNodeShapeInformation") { setDisplayNodeShapeInformation(si->getValueAsBool()); } else if (infoName == "displayNodeSectionInformation") { setDisplayNodeSectionInformation(si->getValueAsBool()); } else if (infoName == "displayNodeArealEstInformation") { setDisplayNodeArealEstInformation(si->getValueAsBool()); } else if (infoName == "displayNodeTopographyInformation") { setDisplayNodeTopographyInformation(si->getValueAsBool()); } else if (infoName == "displayIDSymbol") { setDisplayIDSymbol(si->getValueAsBool()); } else if (infoName == "displayStudyInformation") { setDisplayStudyInformation(si->getValueAsBool()); } else if (infoName == "displayStudyTitleInformation") { setDisplayStudyTitleInformation(si->getValueAsBool()); } else if (infoName == "displayStudyAuthorsInformation") { setDisplayStudyAuthorsInformation(si->getValueAsBool()); } else if (infoName == "displayStudyCitationInformation") { setDisplayStudyCitationInformation(si->getValueAsBool()); } else if (infoName == "displayStudyCommentInformation") { setDisplayStudyCommentInformation(si->getValueAsBool()); } else if (infoName == "displayStudyDataFormatInformation") { setDisplayStudyDataFormatInformation(si->getValueAsBool()); } else if (infoName == "displayStudyDataTypeInformation") { setDisplayStudyDataTypeInformation(si->getValueAsBool()); } else if (infoName == "displayStudyDOIInformation") { setDisplayStudyDOIInformation(si->getValueAsBool()); } else if (infoName == "displayStudyKeywordsInformation") { setDisplayStudyKeywordsInformation(si->getValueAsBool()); } else if (infoName == "displayStudyMedicalSubjectHeadingsInformation") { setDisplayStudyMedicalSubjectHeadingsInformation(si->getValueAsBool()); } else if (infoName == "displayStudyMetaAnalysisInformation") { setDisplayStudyMetaAnalysisInformation(si->getValueAsBool()); } else if (infoName == "displayStudyMetaAnalysisNameInformation") { setDisplayStudyMetaAnalysisNameInformation(si->getValueAsBool()); } else if (infoName == "displayStudyMetaAnalysisTitleInformation") { setDisplayStudyMetaAnalysisTitleInformation(si->getValueAsBool()); } else if (infoName == "displayStudyMetaAnalysisAuthorsInformation") { setDisplayStudyMetaAnalysisAuthorsInformation(si->getValueAsBool()); } else if (infoName == "displayStudyMetaAnalysisCitationInformation") { setDisplayStudyMetaAnalysisCitationInformation(si->getValueAsBool()); } else if (infoName == "displayStudyMetaAnalysisDoiUrlInformation") { setDisplayStudyMetaAnalysisDoiUrlInformation(si->getValueAsBool()); } else if (infoName == "displayStudyNameInformation") { setDisplayStudyNameInformation(si->getValueAsBool()); } else if (infoName == "displayStudyPartSchemeAbbrevInformation") { setDisplayStudyPartSchemeAbbrevInformation(si->getValueAsBool()); } else if (infoName == "displayStudyPartSchemeFullInformation") { setDisplayStudyPartSchemeFullInformation(si->getValueAsBool()); } else if (infoName == "displayStudyPubMedIDInformation") { setDisplayStudyPubMedIDInformation(si->getValueAsBool()); } else if (infoName == "displayStudyProjectIDInformation") { setDisplayStudyProjectIDInformation(si->getValueAsBool()); } else if (infoName == "displayStudyStereotaxicSpaceInformation") { setDisplayStudyStereotaxicSpaceInformation(si->getValueAsBool()); } else if (infoName == "displayStudyStereotaxicSpaceDetailsInformation") { setDisplayStudyStereotaxicSpaceDetailsInformation(si->getValueAsBool()); } else if (infoName == "displayStudyURLInformation") { setDisplayStudyURLInformation(si->getValueAsBool()); } else if (infoName == "displayStudyTableInformation") { setDisplayStudyTableInformation(si->getValueAsBool()); } else if (infoName == "displayStudyTableHeaderInformation") { setDisplayStudyTableHeaderInformation(si->getValueAsBool()); } else if (infoName == "displayStudyTableFooterInformation") { setDisplayStudyTableFooterInformation(si->getValueAsBool()); } else if (infoName == "displayStudyTableSizeUnitsInformation") { setDisplayStudyTableSizeUnitsInformation(si->getValueAsBool()); } else if (infoName == "displayStudyTableVoxelSizeInformation") { setDisplayStudyTableVoxelSizeInformation(si->getValueAsBool()); } else if (infoName == "displayStudyTableStatisticInformation") { setDisplayStudyTableStatisticInformation(si->getValueAsBool()); } else if (infoName == "displayStudyTableStatisticDescriptionInformation") { setDisplayStudyTableStatisticDescriptionInformation(si->getValueAsBool()); } else if (infoName == "displayStudyFigureInformation") { setDisplayStudyFigureInformation(si->getValueAsBool()); } else if (infoName == "displayStudyFigureLegendInformation") { setDisplayStudyFigureLegendInformation(si->getValueAsBool()); } else if (infoName == "displayStudyFigurePanelInformation") { setDisplayStudyFigurePanelInformation(si->getValueAsBool()); } else if (infoName == "displayStudyFigurePanelDescriptionInformation") { setDisplayStudyFigurePanelDescriptionInformation(si->getValueAsBool()); } else if (infoName == "displayStudyFigurePanelTaskDescriptionInformation") { setDisplayStudyFigurePanelTaskDescriptionInformation(si->getValueAsBool()); } else if (infoName == "displayStudyFigurePanelTaskBaselineInformation") { setDisplayStudyFigurePanelTaskBaselineInformation(si->getValueAsBool()); } else if (infoName == "displayStudyFigurePanelTestAttributesInformation") { setDisplayStudyFigurePanelTestAttributesInformation(si->getValueAsBool()); } else if (infoName == "displayStudySubHeaderInformation") { setDisplayStudySubHeaderInformation(si->getValueAsBool()); } else if (infoName == "displayStudySubHeaderNameInformation") { setDisplayStudySubHeaderNameInformation(si->getValueAsBool()); } else if (infoName == "displayStudySubHeaderShortNameInformation") { setDisplayStudySubHeaderShortNameInformation(si->getValueAsBool()); } else if (infoName == "displayStudySubHeaderTaskDescriptionInformation") { setDisplayStudySubHeaderTaskDescriptionInformation(si->getValueAsBool()); } else if (infoName == "displayStudySubHeaderTaskBaselineInformation") { setDisplayStudySubHeaderTaskBaselineInformation(si->getValueAsBool()); } else if (infoName == "displayStudySubHeaderTestAttributesInformation") { setDisplayStudySubHeaderTestAttributesInformation(si->getValueAsBool()); } else if (infoName == "displayStudyPageReferenceInformation") { setDisplayStudyPageReferenceInformation(si->getValueAsBool()); } else if (infoName == "displayStudyPageReferenceHeaderInformation") { setDisplayStudyPageReferenceHeaderInformation(si->getValueAsBool()); } else if (infoName == "displayStudyPageReferenceCommentInformation") { setDisplayStudyPageReferenceCommentInformation(si->getValueAsBool()); } else if (infoName == "displayStudyPageReferenceSizeUnitsInformation") { setDisplayStudyPageReferenceSizeUnitsInformation(si->getValueAsBool()); } else if (infoName == "displayStudyPageReferenceVoxelSizeInformation") { setDisplayStudyPageReferenceVoxelSizeInformation(si->getValueAsBool()); } else if (infoName == "displayStudyPageReferenceStatisticInformation") { setDisplayStudyPageReferenceStatisticInformation(si->getValueAsBool()); } else if (infoName == "displayStudyPageReferenceStatisticDescriptionInformation") { setDisplayStudyPageReferenceStatisticDescriptionInformation(si->getValueAsBool()); } //else if (infoName == "displayStudyPageNumberInformation") { // setDisplayStudyPageNumberInformation(si->getValueAsBool()); //} } } else if (sc->getName() == "GuiIdentifyMainWindow") { // used to be in Identify Dialog const int num = sc->getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc->getSceneInfo(i); const QString infoName = si->getName(); if (infoName == "borderButton") { setDisplayBorderInformation(si->getValueAsBool()); } else if (infoName == "cellButton") { setDisplayCellInformation(si->getValueAsBool()); } else if (infoName == "fociButton") { setDisplayFociInformation(si->getValueAsBool()); } else if (infoName == "voxelButton") { setDisplayVoxelInformation(si->getValueAsBool()); } else if (infoName == "nodeCoordButton") { setDisplayNodeCoordInformation(si->getValueAsBool()); } else if (infoName == "nodeLatLonButton") { setDisplayNodeLatLonInformation(si->getValueAsBool()); } else if (infoName == "nodePaintButton") { setDisplayNodePaintInformation(si->getValueAsBool()); } else if (infoName == "nodeProbAtlasButton") { setDisplayNodeProbAtlasInformation(si->getValueAsBool()); } else if (infoName == "nodeRgbPaintButton") { setDisplayNodeRgbPaintInformation(si->getValueAsBool()); } else if (infoName == "nodeMetricButton") { setDisplayNodeMetricInformation(si->getValueAsBool()); } else if (infoName == "nodeShapeButton") { setDisplayNodeShapeInformation(si->getValueAsBool()); } else if (infoName == "nodeSectionButton") { setDisplayNodeSectionInformation(si->getValueAsBool()); } else if (infoName == "nodeArealEstButton") { setDisplayNodeArealEstInformation(si->getValueAsBool()); } else if (infoName == "nodeTopographyButton") { setDisplayNodeTopographyInformation(si->getValueAsBool()); } else if (infoName == "showIDButton") { setDisplayIDSymbol(si->getValueAsBool()); } else if (infoName == "significantDigitsSpinBox") { setSignificantDigits(si->getValueAsInt()); } } } } } /** * get significant digits for floating point numbers. */ void BrainModelIdentification::setSignificantDigits(const int num) { significantDigits = num; PreferencesFile* pf = brainSetParent->getPreferencesFile(); if (significantDigits != pf->getSignificantDigitsDisplay()) { pf->setSignificantDigitsDisplay(significantDigits); try { pf->writeFile(pf->getFileName()); } catch (FileException& e) { } } } /** * create a scene (save dialog settings) */ void BrainModelIdentification::saveScene(SceneFile::Scene& scene) { SceneFile::SceneClass sc("BrainModelIdentification"); sc.addSceneInfo(SceneFile::SceneInfo("displayBorderInformation", getDisplayBorderInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayCellInformation", getDisplayCellInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayFociInformation", getDisplayFociInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayFociNameInformation", getDisplayFociNameInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayFociClassInformation", getDisplayFociClassInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayFociOriginalStereotaxicPositionInformation", getDisplayFociOriginalStereotaxicPositionInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayFociStereotaxicPositionInformation", getDisplayFociStereotaxicPositionInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayFociAreaInformation", getDisplayFociAreaInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayFociRegionOfInterestInformation", getDisplayFociRegionOfInterestInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayFociGeographyInformation", getDisplayFociGeographyInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayFociSizeInformation", getDisplayFociSizeInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayFociStructureInformation", getDisplayFociStructureInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayFociStatisticInformation", getDisplayFociStatisticInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayFociCommentInformation", getDisplayFociCommentInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayVoxelInformation", getDisplayVoxelInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayContourInformation", getDisplayContourInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayNodeInformation", getDisplayNodeInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayNodeCoordInformation", getDisplayNodeCoordInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayNodeLatLonInformation", getDisplayNodeLatLonInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayNodePaintInformation", getDisplayNodePaintInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayNodeProbAtlasInformation", getDisplayNodeProbAtlasInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayNodeRgbPaintInformation", getDisplayNodeRgbPaintInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayNodeMetricInformation", getDisplayNodeMetricInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayNodeShapeInformation", getDisplayNodeShapeInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayNodeSectionInformation", getDisplayNodeSectionInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayNodeArealEstInformation", getDisplayNodeArealEstInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayNodeTopographyInformation", getDisplayNodeTopographyInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayIDSymbol", displayIDSymbol)); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyInformation", getDisplayStudyInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyTitleInformation", getDisplayStudyTitleInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyAuthorsInformation", getDisplayStudyAuthorsInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyCitationInformation", getDisplayStudyCitationInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyCommentInformation", getDisplayStudyCommentInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyDataFormatInformation", getDisplayStudyDataFormatInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyDataTypeInformation", getDisplayStudyDataTypeInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyDOIInformation", getDisplayStudyDOIInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyKeywordsInformation", getDisplayStudyKeywordsInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyMedicalSubjectHeadingsInformation", getDisplayStudyMedicalSubjectHeadingsInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyMetaAnalysisInformation", getDisplayStudyMetaAnalysisInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyMetaAnalysisNameInformation", getDisplayStudyMetaAnalysisNameInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyMetaAnalysisTitleInformation", getDisplayStudyMetaAnalysisTitleInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyMetaAnalysisAuthorsInformation", getDisplayStudyMetaAnalysisAuthorsInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyMetaAnalysisCitationInformation", getDisplayStudyMetaAnalysisCitationInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyMetaAnalysisDoiUrlInformation", getDisplayStudyMetaAnalysisDoiUrlInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyNameInformation", getDisplayStudyNameInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyPartSchemeAbbrevInformation", getDisplayStudyPartSchemeAbbrevInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyPartSchemeFullInformation", getDisplayStudyPartSchemeFullInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyPubMedIDInformation", getDisplayStudyPubMedIDInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyProjectIDInformation", getDisplayStudyProjectIDInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyStereotaxicSpaceInformation", getDisplayStudyStereotaxicSpaceInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyStereotaxicSpaceDetailsInformation", getDisplayStudyStereotaxicSpaceDetailsInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyURLInformation", getDisplayStudyURLInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyTableInformation", getDisplayStudyTableInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyTableHeaderInformation", getDisplayStudyTableHeaderInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyTableFooterInformation", getDisplayStudyTableFooterInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyTableSizeUnitsInformation", getDisplayStudyTableSizeUnitsInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyTableVoxelSizeInformation", getDisplayStudyTableVoxelSizeInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyTableStatisticInformation", getDisplayStudyTableStatisticInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyTableStatisticDescriptionInformation", getDisplayStudyTableStatisticDescriptionInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyFigureInformation", getDisplayStudyFigureInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyFigureLegendInformation", getDisplayStudyFigureLegendInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyFigurePanelInformation", getDisplayStudyFigurePanelInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyFigurePanelDescriptionInformation", getDisplayStudyFigurePanelDescriptionInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyFigurePanelTaskDescriptionInformation", getDisplayStudyFigurePanelTaskDescriptionInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyFigurePanelTaskBaselineInformation", getDisplayStudyFigurePanelTaskBaselineInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyFigurePanelTestAttributesInformation", getDisplayStudyFigurePanelTestAttributesInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyPageReferenceInformation", getDisplayStudyPageReferenceInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyPageReferenceHeaderInformation", getDisplayStudyPageReferenceHeaderInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyPageReferenceCommentInformation", getDisplayStudyPageReferenceCommentInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyPageReferenceSizeUnitsInformation", getDisplayStudyPageReferenceSizeUnitsInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyPageReferenceVoxelSizeInformation", getDisplayStudyPageReferenceVoxelSizeInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyPageReferenceStatisticInformation", getDisplayStudyPageReferenceStatisticInformation())); sc.addSceneInfo(SceneFile::SceneInfo("displayStudyPageReferenceStatisticDescriptionInformation", getDisplayStudyPageReferenceStatisticDescriptionInformation())); //sc.addSceneInfo(SceneFile::SceneInfo("displayStudyPageNumberInformation", getDisplayStudyPageNumberInformation())); scene.addSceneClass(sc); } /** * all identification off (if any on, all turned off, otherwise all off) . */ void BrainModelIdentification::toggleAllIdentificationOnOff() { idFilter.toggleAllOnOff(); } /** * all identification on. */ void BrainModelIdentification::setAllIdentificationOn() { idFilter.allOn(); } /** * all identification off. */ void BrainModelIdentification::setAllIdentificationOff() { idFilter.allOff(); } /** * make name a link to vocabulary file if it matches a vocabulary file entry. */ QString BrainModelIdentification::linkToVocabulary(BrainSet* brainSet, const QString& name) { if (enableVocabularyLinks) { VocabularyFile* vf = brainSet->getVocabularyFile(); VocabularyFile::VocabularyEntry* ve = vf->getBestMatchingVocabularyEntry(name); if (ve != NULL) { QString link = ("" + name + ""); return link; } } return name; } /** * make a list of names separated by semicolon possible links to vocabulary. */ QString BrainModelIdentification::linkStringToVocabulary(BrainSet* brainSet, const QString& s) { QString stringOut; const QStringList sl = s.split(';', QString::SkipEmptyParts); for (int i = 0; i < sl.count(); i++) { if (i > 0) { stringOut += "; "; } stringOut += linkToVocabulary(brainSet, sl.at(i).trimmed()); } return stringOut; } //================================================================================== /** * constructor. */ BrainModelIdentification::IdFilter::IdFilter() { allOn(); } /** * destructor. */ BrainModelIdentification::IdFilter::~IdFilter() { } /** * turn all off. */ void BrainModelIdentification::IdFilter::allOff(const bool turnSubFlagsOff) { displayBorderInformation = false; displayCellInformation = false; displayFociInformation = false; if (turnSubFlagsOff) { displayFociNameInformation = false; displayFociClassInformation = false; displayFociOriginalStereotaxicPositionInformation = false; displayFociStereotaxicPositionInformation = false; displayFociAreaInformation = false; displayFociGeographyInformation = false; displayFociRegionOfInterestInformation = false; displayFociSizeInformation = false; displayFociStructureInformation = false; displayFociStatisticInformation = false; displayFociCommentInformation = false; } displayVoxelInformation = false; displayContourInformation = false; displayNodeInformation = false; if (turnSubFlagsOff) { displayNodeCoordInformation = false; displayNodeLatLonInformation = false; displayNodePaintInformation = false; displayNodeProbAtlasInformation = false; displayNodeRgbPaintInformation = false; displayNodeMetricInformation = false; displayNodeShapeInformation = false; displayNodeSectionInformation = false; displayNodeArealEstInformation = false; displayNodeTopographyInformation = false; } if (turnSubFlagsOff) { displayStudyInformation = false; displayStudyTitleInformation = false; displayStudyAuthorsInformation = false; displayStudyCitationInformation = false; displayStudyCommentInformation = false; displayStudyDataFormatInformation = false; displayStudyDataTypeInformation = false; displayStudyDOIInformation = false; displayStudyKeywordsInformation = false; displayStudyMedicalSubjectHeadingsInformation = false; displayStudyMetaAnalysisInformation = false; displayStudyMetaAnalysisNameInformation = false; displayStudyMetaAnalysisTitleInformation = false; displayStudyMetaAnalysisAuthorsInformation = false; displayStudyMetaAnalysisCitationInformation = false; displayStudyMetaAnalysisDoiUrlInformation = false; displayStudyNameInformation = false; displayStudyPartSchemeAbbrevInformation = false; displayStudyPartSchemeFullInformation = false; displayStudyPubMedIDInformation = false; displayStudyProjectIDInformation = false; displayStudyStereotaxicSpaceInformation = false; displayStudyStereotaxicSpaceDetailsInformation = false; displayStudyURLInformation = false; displayStudyTableInformation = false; displayStudyTableHeaderInformation = false; displayStudyTableFooterInformation = false; displayStudyTableSizeUnitsInformation = false; displayStudyTableVoxelSizeInformation = false; displayStudyTableStatisticInformation = false; displayStudyTableStatisticDescriptionInformation = false; displayStudyFigureInformation = false; displayStudyFigureLegendInformation = false; displayStudyFigurePanelInformation = false; displayStudyFigurePanelDescriptionInformation = false; displayStudyFigurePanelTaskDescriptionInformation = false; displayStudyFigurePanelTaskBaselineInformation = false; displayStudyFigurePanelTestAttributesInformation = false; displayStudySubHeaderInformation = false; displayStudySubHeaderNameInformation = false; displayStudySubHeaderShortNameInformation = false; displayStudySubHeaderTaskDescriptionInformation = false; displayStudySubHeaderTaskBaselineInformation = false; displayStudySubHeaderTestAttributesInformation = false; displayStudyPageReferenceInformation = false; displayStudyPageReferenceHeaderInformation = false; displayStudyPageReferenceCommentInformation = false; displayStudyPageReferenceSizeUnitsInformation = false; displayStudyPageReferenceVoxelSizeInformation = false; displayStudyPageReferenceStatisticInformation = false; displayStudyPageReferenceStatisticDescriptionInformation = false; //displayStudyPageNumberInformation = false; } } /** * turn all on. */ void BrainModelIdentification::IdFilter::allOn() { displayBorderInformation = true; displayCellInformation = true; displayFociInformation = true; displayFociNameInformation = true; displayFociClassInformation = true; displayFociOriginalStereotaxicPositionInformation = true; displayFociStereotaxicPositionInformation = true; displayFociAreaInformation = true; displayFociGeographyInformation = true; displayFociRegionOfInterestInformation = true; displayFociSizeInformation = true; displayFociStructureInformation = true; displayFociStatisticInformation = true; displayFociCommentInformation = true; displayVoxelInformation = true; displayContourInformation = true; displayNodeInformation = true; displayNodeCoordInformation = true; displayNodeLatLonInformation = true; displayNodePaintInformation = true; displayNodeProbAtlasInformation = true; displayNodeRgbPaintInformation = true; displayNodeMetricInformation = true; displayNodeShapeInformation = true; displayNodeSectionInformation = true; displayNodeArealEstInformation = true; displayNodeTopographyInformation = true; displayStudyInformation = true; displayStudyTitleInformation = true; displayStudyAuthorsInformation = true; displayStudyCitationInformation = true; displayStudyCommentInformation = true; displayStudyDataFormatInformation = true; displayStudyDataTypeInformation = true; displayStudyDOIInformation = true; displayStudyKeywordsInformation = true; displayStudyMedicalSubjectHeadingsInformation = true; displayStudyMetaAnalysisInformation = true; displayStudyMetaAnalysisNameInformation = true; displayStudyMetaAnalysisTitleInformation = true; displayStudyMetaAnalysisAuthorsInformation = true; displayStudyMetaAnalysisCitationInformation = true; displayStudyMetaAnalysisDoiUrlInformation = true; displayStudyNameInformation = true; displayStudyPartSchemeAbbrevInformation = true; displayStudyPartSchemeFullInformation = true; displayStudyPubMedIDInformation = true; displayStudyProjectIDInformation = true; displayStudyStereotaxicSpaceInformation = true; displayStudyStereotaxicSpaceDetailsInformation = true; displayStudyURLInformation = true; displayStudyTableInformation = true; displayStudyTableHeaderInformation = true; displayStudyTableFooterInformation = true; displayStudyTableSizeUnitsInformation = true; displayStudyTableVoxelSizeInformation = true; displayStudyTableStatisticInformation = true; displayStudyTableStatisticDescriptionInformation = true; displayStudyFigureInformation = true; displayStudyFigureLegendInformation = true; displayStudyFigurePanelInformation = true; displayStudyFigurePanelDescriptionInformation = true; displayStudyFigurePanelTaskDescriptionInformation = true; displayStudyFigurePanelTaskBaselineInformation = true; displayStudyFigurePanelTestAttributesInformation = true; displayStudySubHeaderInformation = true; displayStudySubHeaderNameInformation = true; displayStudySubHeaderShortNameInformation = true; displayStudySubHeaderTaskDescriptionInformation = true; displayStudySubHeaderTaskBaselineInformation = true; displayStudySubHeaderTestAttributesInformation = true; displayStudyPageReferenceInformation = true; displayStudyPageReferenceHeaderInformation = true; displayStudyPageReferenceCommentInformation = true; displayStudyPageReferenceSizeUnitsInformation = true; displayStudyPageReferenceVoxelSizeInformation = true; displayStudyPageReferenceStatisticInformation = true; displayStudyPageReferenceStatisticDescriptionInformation = true; //displayStudyPageNumberInformation = true; } /** * toggle all on/off. */ void BrainModelIdentification::IdFilter::toggleAllOnOff() { const bool anyOn = displayBorderInformation || displayCellInformation || displayFociInformation || anyFociDataOn() || /* displayFociNameInformation || displayFociClassInformation || displayFociOriginalStereotaxicPositionInformation || displayFociStereotaxicPositionInformation || displayFociAreaInformation || displayFociGeographyInformation || displayFociRegionOfInterestInformation || displayFociSizeInformation || displayFociStructureInformation || displayFociStatisticInformation || displayFociCommentInformation || */ displayVoxelInformation || displayContourInformation || displayNodeInformation || anyNodeDataOn() || /* displayNodeCoordInformation || displayNodeLatLonInformation || displayNodePaintInformation || displayNodeProbAtlasInformation || displayNodeRgbPaintInformation || displayNodeMetricInformation || displayNodeShapeInformation || displayNodeSectionInformation || displayNodeArealEstInformation || displayNodeTopographyInformation || */ displayStudyInformation || anyStudyDataOn(); if (anyOn) { allOff(); } else { allOn(); } } /** * report if any node information should be displayed. */ bool BrainModelIdentification::IdFilter::anyNodeDataOn() const { const bool anyOn = displayNodeCoordInformation || displayNodeLatLonInformation || displayNodePaintInformation || displayNodeProbAtlasInformation || displayNodeRgbPaintInformation || displayNodeMetricInformation || displayNodeShapeInformation || displayNodeSectionInformation || displayNodeArealEstInformation || displayNodeTopographyInformation; return anyOn; } /** * report if any foci information should be displayed. */ bool BrainModelIdentification::IdFilter::anyFociDataOn() const { const bool anyOn = displayFociNameInformation || displayFociClassInformation || displayFociOriginalStereotaxicPositionInformation || displayFociStereotaxicPositionInformation || displayFociAreaInformation || displayFociGeographyInformation || displayFociRegionOfInterestInformation || displayFociSizeInformation || displayFociStatisticInformation || displayFociStructureInformation || displayFociCommentInformation; return anyOn; } /** * report if any study meta-analysis information should be displayed. */ bool BrainModelIdentification::IdFilter::anyStudyMetaAnalysisDataOn() const { const bool anyOn = displayStudyMetaAnalysisNameInformation || displayStudyMetaAnalysisTitleInformation || displayStudyMetaAnalysisAuthorsInformation || displayStudyMetaAnalysisCitationInformation || displayStudyMetaAnalysisDoiUrlInformation; return anyOn; } /** * report if any study information should be displayed. */ bool BrainModelIdentification::IdFilter::anyStudyDataOn() const { const bool anyOn = displayStudyTitleInformation || displayStudyAuthorsInformation || displayStudyCitationInformation || displayStudyCommentInformation || displayStudyDataFormatInformation || displayStudyDataTypeInformation || displayStudyDOIInformation || displayStudyKeywordsInformation || displayStudyMedicalSubjectHeadingsInformation || displayStudyNameInformation || displayStudyPartSchemeAbbrevInformation || displayStudyPartSchemeFullInformation || displayStudyPubMedIDInformation || displayStudyProjectIDInformation || displayStudyStereotaxicSpaceInformation || displayStudyStereotaxicSpaceDetailsInformation || displayStudyURLInformation || anyStudyTableDataOn() || anyStudyFigureDataOn() || anySubHeaderDataOn() || anyPageReferenceDataOn(); // || //displayStudyPageNumberInformation; return anyOn; } /** * report if any study table information should be displayed */ bool BrainModelIdentification::IdFilter::anyStudyTableDataOn() const { const bool anyOn = (displayStudyTableInformation && (displayStudyTableHeaderInformation || displayStudyTableFooterInformation || displayStudyTableSizeUnitsInformation || displayStudyTableVoxelSizeInformation || displayStudyTableStatisticInformation || displayStudyTableStatisticDescriptionInformation)); return anyOn; } /** * report if any study figure information should be displayed. */ bool BrainModelIdentification::IdFilter::anyStudyFigureDataOn() const { const bool anyOn = (displayStudyFigureInformation && (displayStudyFigureLegendInformation) && anyStudyFigurePanelDataOn()); return anyOn; } /** * report if any study figure panel information should be displayed. */ bool BrainModelIdentification::IdFilter::anyStudyFigurePanelDataOn() const { const bool anyOn = (displayStudyFigurePanelInformation && (displayStudyFigurePanelDescriptionInformation || displayStudyFigurePanelTaskDescriptionInformation || displayStudyFigurePanelTaskBaselineInformation || displayStudyFigurePanelTestAttributesInformation)); return anyOn; } /** * report if any subh header information should be displayed. */ bool BrainModelIdentification::IdFilter::anySubHeaderDataOn() const { const bool anyOn = (displayStudySubHeaderInformation && (displayStudySubHeaderNameInformation || displayStudySubHeaderShortNameInformation || displayStudySubHeaderTaskDescriptionInformation || displayStudySubHeaderTaskBaselineInformation || displayStudySubHeaderTestAttributesInformation)); return anyOn; } /** * report if any page reference information should be displayed. */ bool BrainModelIdentification::IdFilter::anyPageReferenceDataOn() const { const bool anyOn = (displayStudyPageReferenceInformation && (displayStudyPageReferenceHeaderInformation || displayStudyPageReferenceCommentInformation || displayStudyPageReferenceSizeUnitsInformation || displayStudyPageReferenceVoxelSizeInformation || displayStudyPageReferenceStatisticInformation)); return anyOn; } /** * translate special HTML characters to HTML special characters. */ QString BrainModelIdentification::htmlTranslate(const QString& ss) const { QString s = ss; if (htmlFlag) { s = s.replace("&", "&"); s = s.replace("<", "<"); s = s.replace(">", ">"); } return s; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelContours.h0000664000175000017500000001306511572067322023634 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __BRAIN_MODEL_CONTOURS_H__ #define __BRAIN_MODEL_CONTOURS_H__ #include "BrainModel.h" #include "ContourFile.h" class MDPlotFile; class NeurolucidaFile; /// Class for handling contours class BrainModelContours : public BrainModel { public: /// Constructor BrainModelContours(BrainSet* bs); /// Destructor ~BrainModelContours(); /// get access to the contours ContourFile* getContourFile() { return &contours; } /// get access to the contours const ContourFile* getContourFile() const { return &contours; } /// Get a descriptive name of the model QString getDescriptiveName() const; /// read the contour file void readContourFile(const QString& filename, const bool append) throw(FileException); /// import the MD Plot file void importMDPlotFile(const MDPlotFile& mf, const bool append) throw(FileException); /// import the NeurolucidaFile file void importNeurolucidaFile(const NeurolucidaFile& nf, const bool append) throw (FileException); /// reset this contour file void reset(); /// apply alignment transforms to a section void applyAlignmentToSection(const int sectionNumber); /// apply transformations to all section void applyTransformationsToAllContours(); /// get the alignment rotation matrix void getAlignmentRotationMatrix(float matrix[16]) const; /// set the alignment rotation matrix void setAlignmentRotationMatrix(const float matrix[16]); /// get the alignment rotation matrix vtkTransform* getAlignmentRotationTransformMatrix() { return alignmentRotationMatrix; } /// get the model's alignment scaling float getAlignmentScaling() const { return alignmentScaling; } /// set the model's alignment scaling void setAlignmentScaling(const float scaleIn) { alignmentScaling = scaleIn; } /// get the model's alignment translation void getAlignmentTranslation(float translationOut[3]) const; /// set the model's alignment translation void setAlignmentTranslation(const float translationIn[3]); /// reset the alignment transformations void resetAlignmentTransformations(); /// reset the viewing transform void resetViewingTransform(const int viewNumber); /// Reset the alignment region box. void resetAlignmentRegionBox(); /// Set alignment region box start. void setAlignmentRegionBoxEnd(const float xy[2]); /// Set alignment region box start. void setAlignmentRegionBoxStart(const float xy[2]); /// Get the alignment region box void getAlignmentRegionBox(float bounds[4]); /// Get alignment region box valid bool getAlignmentRegionBoxValid() const { return alignmentRegionBoxValid; } /// Set alignment region box valid void setAlignmentRegionBoxValid(const int valid) { alignmentRegionBoxValid = valid; } /// Get alignment region flag bool getAligningRegionFlag() const { return aligningRegionFlag; } /// Set alignment region flag void setAligningRegionFlag(const int flag) { aligningRegionFlag = flag; } /// get the alignment matrix TransformationMatrix* getAlignmentMatrix() { return &alignmentMatrix; } /// get the alignment matrix const TransformationMatrix* getAlignmentMatrix() const { return &alignmentMatrix; } /// get the alignment matrix void setAlignmentMatrix(const TransformationMatrix tm) { alignmentMatrix = tm; } /// set the model's scaling virtual void setScaling(const int viewNumber, const float scaleIn[3]); /// set the model's scaling virtual void setScaling(const int viewNumber, const float sx, const float sy, const float sz); private: /// the contours ContourFile contours; /// Rotation for section alignment vtkTransform* alignmentRotationMatrix; /// Scaling for section alignment float alignmentScaling; /// Translation for section alignment float alignmentTranslation[3]; /// alignment region box float alignmentRegionBox[4]; /// alignment region box valid bool alignmentRegionBoxValid; /// aligning region flag bool aligningRegionFlag; /// matrix for aligning TransformationMatrix alignmentMatrix; }; #endif // __BRAIN_MODEL_CONTOURS_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelContours.cxx0000664000175000017500000002214011572067322024201 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelContours.h" #include "BrainSet.h" #include "ContourCellFile.h" #include "FileUtilities.h" #include "MDPlotFile.h" #include "NeurolucidaFile.h" #include "vtkTransform.h" /** * Constructor. */ BrainModelContours::BrainModelContours(BrainSet* bs) : BrainModel(bs, BrainModel::BRAIN_MODEL_CONTOURS) { alignmentRotationMatrix = vtkTransform::New(); reset(); } /** * Destructor. */ BrainModelContours::~BrainModelContours() { alignmentRotationMatrix->Delete(); } /** * Get a descriptive name of the model. */ QString BrainModelContours::getDescriptiveName() const { QString name("CONTOURS "); const ContourFile* cf = getContourFile(); name.append(FileUtilities::basename(cf->getFileName())); return name; } /** * Reset this brain model contours. */ void BrainModelContours::reset() { contours.clear(); resetAlignmentTransformations(); } /** * Read the specified contours file. May throw FileException. */ void BrainModelContours::readContourFile(const QString& filename, const bool append) throw(FileException) { try { if (append && (contours.getNumberOfContours() > 0)) { ContourFile cf; cf.readFile(filename); QString msg; contours.append(cf, msg); if (msg.isEmpty() == false) { throw FileException(filename, msg); } } else { contours.readFile(filename); // // Use scaling saved in contour file if valid // float scale[3]; contours.getMainWindowScaling(scale); if ((scale[0] > 0.0) && (scale[1] > 0.0) && (scale[2] > 0.0)) { setScaling(0, scale); } else { setScaling(0, 1.0, 1.0, 1.0); } } } catch (FileException& e) { reset(); throw e; } } /** * import the NeurolucidaFile file. */ void BrainModelContours::importNeurolucidaFile(const NeurolucidaFile& nf, const bool append) throw (FileException) { try { if (append == false) { contours.clear(); } contours.importNeurolucidaFile(nf); } catch (FileException& e) { reset(); throw e; } } /** * import the MD Plot file. */ void BrainModelContours::importMDPlotFile(const MDPlotFile& mf, const bool append) throw(FileException) { try { if (append == false) { contours.clear(); } contours.importMDPlotFile(mf); } catch (FileException& e) { reset(); throw e; } } /** * Reset the aligment transformations of the model */ void BrainModelContours::resetAlignmentTransformations() { alignmentMatrix.identity(); alignmentRotationMatrix->Identity(); alignmentScaling = 1.0; alignmentTranslation[0] = 0.0; alignmentTranslation[1] = 0.0; alignmentTranslation[2] = 0.0; aligningRegionFlag = false; resetAlignmentRegionBox(); } /** * Get the alignment region box. */ void BrainModelContours::getAlignmentRegionBox(float bounds[4]) { bounds[0] = alignmentRegionBox[0]; bounds[1] = alignmentRegionBox[1]; bounds[2] = alignmentRegionBox[2]; bounds[3] = alignmentRegionBox[3]; } /** * Set alignment region box start. */ void BrainModelContours::setAlignmentRegionBoxStart(const float xy[2]) { alignmentRegionBox[0] = xy[0]; alignmentRegionBox[1] = xy[1]; alignmentRegionBox[2] = xy[0]; alignmentRegionBox[3] = xy[1]; alignmentRegionBoxValid = true; } /** * Set alignment region box start. */ void BrainModelContours::setAlignmentRegionBoxEnd(const float xy[2]) { alignmentRegionBox[2] = xy[0]; alignmentRegionBox[3] = xy[1]; } /** * Reset the alignment region box. */ void BrainModelContours::resetAlignmentRegionBox() { alignmentRegionBox[0] = 0.0; alignmentRegionBox[1] = 0.0; alignmentRegionBox[2] = 0.0; alignmentRegionBox[3] = 0.0; alignmentRegionBoxValid = false; } /** * Get the alignment rotation matrix as an array */ void BrainModelContours::getAlignmentRotationMatrix(float matrix[16]) const { vtkMatrix4x4* m = vtkMatrix4x4::New(); alignmentRotationMatrix->GetMatrix(m); int cnt = 0; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { matrix[cnt] = m->GetElement(i, j); cnt++; } } m->Delete(); } /** * Set the alignment rotation matrix as an array. */ void BrainModelContours::setAlignmentRotationMatrix(const float matrix[16]) { vtkMatrix4x4* m = vtkMatrix4x4::New(); alignmentRotationMatrix->GetMatrix(m); int cnt = 0; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { m->SetElement(i, j, matrix[cnt]); cnt++; } } alignmentRotationMatrix->SetMatrix(m); m->Delete(); } /** * Get the model's alignment translation. */ void BrainModelContours::getAlignmentTranslation(float translationOut[3]) const { translationOut[0] = alignmentTranslation[0]; translationOut[1] = alignmentTranslation[1]; translationOut[2] = alignmentTranslation[2]; } /** * Set the model's alignment translation. */ void BrainModelContours::setAlignmentTranslation(const float translationIn[3]) { alignmentTranslation[0] = translationIn[0]; alignmentTranslation[1] = translationIn[1]; alignmentTranslation[2] = translationIn[2]; } /** * apply alignment transforms to a section. */ void BrainModelContours::applyAlignmentToSection(const int sectionNumber) { /* TransformationMatrix tm ; float cogX, cogY; contours.getSectionCOG(sectionNumber, cogX, cogY); tm.translate(cogX, cogY, 0.0f); tm.translate(alignmentTranslation[0], alignmentTranslation[1], alignmentTranslation[2]); TransformationMatrix rot; rot.setMatrix(alignmentRotationMatrix); rot.transpose(); // I'm not sure why this works JWH perhaps OpenGL backwards from VTK. tm.multiply(rot); tm.scale(alignmentScaling, alignmentScaling, 1.0f); tm.translate(-cogX, -cogY, 0.0f); */ contours.applyTransformationMatrix(sectionNumber, sectionNumber, alignmentMatrix, getAligningRegionFlag()); ContourCellFile* contourCells = brainSet->getContourCellFile(); contourCells->applyTransformationMatrix(sectionNumber, sectionNumber, alignmentMatrix, getAligningRegionFlag()); } /** * apply transformations to all section. */ void BrainModelContours::applyTransformationsToAllContours() { TransformationMatrix tm; tm.translate(translation[0][0], translation[0][1], translation[0][2]); TransformationMatrix rot; rot.setMatrix(rotationMatrix[0]); tm.preMultiply(rot); tm.scale(scaling[0][0], scaling[0][1], 1.0f); contours.applyTransformationMatrix(contours.getMinimumSection(), contours.getMaximumSection(), tm, false); resetViewingTransformations(); } /** * reset the viewing transform. */ void BrainModelContours::resetViewingTransform(const int viewNumber) { float m[16]; m[0] = 1.0; m[1] = 0.0; m[2] = 0.0; m[3] = 0.0; m[4] = 0.0; m[5] = 1.0; m[6] = 0.0; m[7] = 0.0; m[8] = 0.0; m[9] = 0.0; m[10] = 1.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; scaling[viewNumber][0] = 1.0; scaling[viewNumber][1] = 1.0; scaling[viewNumber][2] = 1.0; translation[viewNumber][0] = 0.0; translation[viewNumber][1] = 0.0; translation[viewNumber][2] = 0.0; setRotationMatrix(viewNumber, m); } /** * set the model's scaling. */ void BrainModelContours::setScaling(const int viewNumber, const float scaleIn[3]) { BrainModel::setScaling(viewNumber, scaleIn); if (viewNumber == 0) { contours.setMainWindowScaling(scaleIn); } } /** * set the model's scaling. */ void BrainModelContours::setScaling(const int viewNumber, const float sx, const float sy, const float sz) { float s[3] = { sx, sy, sz }; setScaling(viewNumber, s); } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelContourToSurfaceConverter.h0000664000175000017500000000434211572067322027153 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __BRAIN_MODEL_CONTOUR_TO_SURFACE_CONVERTER_H__ #define __BRAIN_MODEL_CONTOUR_TO_SURFACE_CONVERTER_H__ #include "BrainModelAlgorithm.h" #include "Structure.h" class ContourFile; /// Convert contours into a surface class BrainModelContourToSurfaceConverter : public BrainModelAlgorithm { public: /// Constructor BrainModelContourToSurfaceConverter(BrainSet* bs, ContourFile* contourFileIn, const int voxelDimIn, const int polygonLimitIn, const Structure::STRUCTURE_TYPE structureIn, const bool convertCellsIn); /// Destructor ~BrainModelContourToSurfaceConverter(); /// execute the algorithm virtual void execute() throw (BrainModelAlgorithmException); private: /// the contour file ContourFile* contourFile; /// voxel dimension int voxelDimension; /// polygon limit int polygonLimit; /// structure Structure::STRUCTURE_TYPE structure; /// convert cells flag bool convertCellsFlag; }; #endif // __BRAIN_MODEL_CONTOUR_TO_SURFACE_CONVERTER_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelContourToSurfaceConverter.cxx0000664000175000017500000004573211572067322027536 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #ifdef Q_OS_WIN32 #define NOMINMAX #endif #include #include #include "BrainModelContourToSurfaceConverter.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceNodeColoring.h" #include "BrainSet.h" #include "CellColorFile.h" #include "CellProjectionFile.h" #include "ContourCellFile.h" #include "ContourCellColorFile.h" #include "ContourFile.h" #include "DebugControl.h" #include "SectionFile.h" #include "TransformationMatrixFile.h" #include "vtkCellArray.h" #include "vtkCleanPolyData.h" #include "vtkDecimatePro.h" #include "vtkPoints.h" #include "vtkPiecewiseFunction.h" #include "vtkPolyData.h" #include "vtkPolyDataWriter.h" #include "vtkTriangleFilter.h" #include "vtkVoxelContoursToSurfaceFilter.h" //#define USE_VTK_DECIMATE_CARET 1 #ifdef USE_VTK_DECIMATE_CARET #include "vtkDecimateCaret.h" #endif // USE_VTK_DECIMATE_CARET /** * Constructor. */ BrainModelContourToSurfaceConverter::BrainModelContourToSurfaceConverter( BrainSet* bs, ContourFile* contourFileIn, const int voxelDimIn, const int polygonLimitIn, const Structure::STRUCTURE_TYPE structureIn, const bool convertCellsIn) : BrainModelAlgorithm(bs) { contourFile = contourFileIn; voxelDimension = voxelDimIn; polygonLimit = polygonLimitIn; structure = structureIn; convertCellsFlag = convertCellsIn; } /** * Destructor. */ BrainModelContourToSurfaceConverter::~BrainModelContourToSurfaceConverter() { } /** * execute the algorithm. */ void BrainModelContourToSurfaceConverter::execute() throw (BrainModelAlgorithmException) { // // Make sure contour file is valid and has contours // if (contourFile == NULL) { throw BrainModelAlgorithmException("Contour File is invalid."); } const int numContours = contourFile->getNumberOfContours(); if (contourFile->getNumberOfContours() < 0) { throw BrainModelAlgorithmException("Contour File contains no contours."); } // // VTK requires that section numbers are increasing. // contourFile->sortBySectionNumber(); // // Create the VTK data structures. // vtkPolyData* contours = vtkPolyData::New(); vtkPoints* pointData = vtkPoints::New(); vtkCellArray* cells = vtkCellArray::New(); const float spacing = contourFile->getSectionSpacing(); // // VTK requires that Z values are consecutive integers so // handle any skips in the section numbers. // int lastSectionNumber = 0; bool lastSectionNumberValid = false; int vtkSectionNumber = 1; float minSectionZ = std::numeric_limits::max(); float maxSectionZ = -std::numeric_limits::max(); // // Use VTK's piecewise function to convert from a VTK consecutive // section number to the true Z of the section // vtkPiecewiseFunction* vtkSectionToZ = vtkPiecewiseFunction::New(); for (int i = 0; i < numContours; i++) { CaretContour* cc = contourFile->getContour(i); const int numPoints = cc->getNumberOfPoints(); const int sectionNumber = cc->getSectionNumber(); if (numPoints < 3) { std::cout << "Contour " << i << " section " << sectionNumber << " has less than three points, ignored" << std::endl; continue; } vtkIdType* verts = new vtkIdType[numPoints]; if (lastSectionNumberValid) { if (sectionNumber != lastSectionNumber) { vtkSectionNumber++; const float sectionZ = sectionNumber * spacing; vtkSectionToZ->AddPoint(vtkSectionNumber, sectionZ); if (sectionZ < minSectionZ) minSectionZ = sectionZ; if (sectionZ > maxSectionZ) maxSectionZ = sectionZ; } } else { const float sectionZ = sectionNumber * spacing; vtkSectionToZ->AddPoint(vtkSectionNumber, sectionZ); if (sectionZ < minSectionZ) minSectionZ = sectionZ; if (sectionZ > maxSectionZ) maxSectionZ = sectionZ; } if (DebugControl::getDebugOn()) { std::cout << "Contour section=" << sectionNumber << ", VTK-section=" << vtkSectionNumber << std::endl; } vtkIdType pointCount = 0; for (int j = 0; j < numPoints; j++) { float x, y; cc->getPointXY(j, x, y); verts[pointCount] = pointData->InsertNextPoint(x, y, vtkSectionNumber); pointCount++; } lastSectionNumber = sectionNumber; lastSectionNumberValid = true; if (pointCount > 2) { cells->InsertNextCell(pointCount, verts); } else { printf("Contour %d has less than 3 points\n", i); } } vtkSectionToZ->ClampingOn(); // // Get extent of contours // float minX, minY, maxX, maxY; contourFile->getExtent(minX, maxX, minY, maxY); if (DebugControl::getDebugOn()) { std::cout << "Contour Ranges: " << "(" << minX << ", " << maxX << ") " << "(" << minY << ", " << maxY << ") " << "(" << minSectionZ << ", " << maxSectionZ << ") " << lastSectionNumber << std::endl; } float minZ = std::numeric_limits::max(); float maxZ = -std::numeric_limits::max(); minX = std::numeric_limits::max(); maxX = -std::numeric_limits::max(); minY = std::numeric_limits::max(); maxY = -std::numeric_limits::max(); const int numPoints = pointData->GetNumberOfPoints(); for (int m = 0; m < numPoints; m++) { #ifdef HAVE_VTK5 double xyz[3]; #else // HAVE_VTK5 float xyz[3]; #endif // HAVE_VTK5 pointData->GetPoint(m, xyz); if (xyz[0] > maxX) maxX = xyz[0]; if (xyz[0] < minX) minX = xyz[0]; if (xyz[1] > maxY) maxY = xyz[1]; if (xyz[1] < minY) minY = xyz[1]; if (xyz[2] > maxZ) maxZ = xyz[2]; if (xyz[2] < minZ) minZ = xyz[2]; } const float contourMinX = minX; const float contourMinY = minY; if (DebugControl::getDebugOn()) { std::cout << "Contour Convertex to Voxel Ranges: " << "(" << minX << ", " << maxX << ") " << "(" << minY << ", " << maxY << ") " << "(" << minZ << ", " << maxZ << ") " << std::endl; } // // Scale to fit within volume // const float volumeSize = static_cast(voxelDimension); const float dx = maxX - minX; const float dy = maxY - minY; float greatest = dx; if (dy > greatest) { greatest = dy; } const float xyScale = (volumeSize - 4.0) / greatest; // // Setup matrix to // 1) Translate so (minX, minY) is at the origin. // 2) Scale to fit inside volume // 3) Translate so (minX, minY) is at 2, 2 // TransformationMatrix matrix; matrix.translate(-contourMinX, -contourMinY, 0.0f); matrix.scale(xyScale, xyScale, 1.0f); matrix.translate(2.0, 2.0, 0.0); minZ = std::numeric_limits::max(); maxZ = -std::numeric_limits::max(); minX = std::numeric_limits::max(); maxX = -std::numeric_limits::max(); minY = std::numeric_limits::max(); maxY = -std::numeric_limits::max(); // // Apply transformation to the surface points // for (int m = 0; m < numPoints; m++) { #ifdef HAVE_VTK5 double xyz[3]; #else // HAVE_VTK5 float xyz[3]; #endif // HAVE_VTK5 pointData->GetPoint(m, xyz); double xyzw[4] = { xyz[0], xyz[1], xyz[2], 1.0 }; matrix.multiplyPoint(xyzw); xyz[0] = xyzw[0]; xyz[1] = xyzw[1]; xyz[2] = xyzw[2]; // // "Round" the coordinates. vtkVoxelContoursToSurfaceFilter expects integers. This must // be done after transforming the points or else the surface will look super noisyish. // if (xyz[0] > 0.0) xyz[0] += 0.5; else if (xyz[0] < 0.0) xyz[0] -= 0.5; if (xyz[1] > 0.0) xyz[1] += 0.5; else if (xyz[1] < 0.0) xyz[1] -= 0.5; xyz[0] = static_cast(xyz[0]); xyz[1] = static_cast(xyz[1]); pointData->SetPoint(m, xyz); if (xyz[0] > maxX) maxX = xyz[0]; if (xyz[0] < minX) minX = xyz[0]; if (xyz[1] > maxY) maxY = xyz[1]; if (xyz[1] < minY) minY = xyz[1]; if (xyz[2] > maxZ) maxZ = xyz[2]; if (xyz[2] < minZ) minZ = xyz[2]; } if (DebugControl::getDebugOn()) { std::cout << "Contour Ranges after Transformation: " << "(" << minX << ", " << maxX << ") " << "(" << minY << ", " << maxY << ") " << "(" << minZ << ", " << maxZ << ") " << std::endl; } contours->SetPoints(pointData); contours->SetPolys(cells); cells->Delete(); pointData->Delete(); if (DebugControl::getDebugOn()) { vtkPolyDataWriter* contourWriter = vtkPolyDataWriter::New(); contourWriter->SetInput(contours); contourWriter->SetHeader(""); contourWriter->SetFileName("contours.vtk"); contourWriter->Write(); contourWriter->Delete(); } // // run a filter to convert the contours to a surface // vtkVoxelContoursToSurfaceFilter *surface = vtkVoxelContoursToSurfaceFilter::New(); surface->SetInput(contours); surface->SetMemoryLimitInBytes(1000000000); // // Save the surface to a VTK PolyData file. // if (DebugControl::getDebugOn()) { vtkPolyDataWriter* writer1 = vtkPolyDataWriter::New(); writer1->SetInput(surface->GetOutput()); writer1->SetHeader(""); writer1->SetFileName("raw_surface.vtk"); writer1->Write(); writer1->Delete(); std::cout << "..._raw_surface.vtk contains the surface from vtkVoxelContoursToSurfaceFilter" << endl; } // // Make sure mesh is only triangles // vtkTriangleFilter *triangleFilter = vtkTriangleFilter::New(); triangleFilter->SetInput(surface->GetOutput()); triangleFilter->Update(); // // Find number of triangles // vtkPolyData* surfaceData = triangleFilter->GetOutput(); const int numberOfPolygons = surfaceData->GetPolys()->GetNumberOfCells(); if (numberOfPolygons <= 0) { triangleFilter->Delete(); surface->Delete(); contours->Delete(); throw BrainModelAlgorithmException("Reconstruction failed.\n" "Are the sections in the XY-plane?"); } // // Convert Z (section numbers) to true Z, untranslate, and unscale the surface // vtkPoints *surfacePoints = surfaceData->GetPoints(); for (int nn = 0; nn < surfacePoints->GetNumberOfPoints(); nn++) { #ifdef HAVE_VTK5 double xyz[3]; #else // HAVE_VTK5 float xyz[3]; #endif // HAVE_VTK5 surfacePoints->GetPoint(nn, xyz); xyz[2] = vtkSectionToZ->GetValue(xyz[2]); surfacePoints->SetPoint(nn, xyz); } vtkCleanPolyData* clean1 = NULL; vtkCleanPolyData* clean2 = NULL; #ifdef USE_VTK_DECIMATE_CARET // // Decimate the VTK surface if it is large // vtkDecimateCaret* decimater = NULL; if (polygonLimit < numberOfPolygons) { if (DebugControl::getDebugOn()) { std::cout << "Before decimation surface has " << numberOfPolygons << " polygons." << std::endl; } decimater = vtkDecimateCaret::New(); decimater->SetInput(surfaceData); const float reduction = 1.0 - ((float)polygonLimit / (float)numberOfPolygons); if (DebugControl::getDebugOn()) { std::cout << "Reduction is " << reduction * 100.0 << "%" << std::endl; } decimater->SetTargetReduction(reduction); decimater->PreserveTopologyOn(); decimater->SetMaximumError(VTK_LARGE_FLOAT); decimater->BoundaryVertexDeletionOff(); //decimater->SplittingOff(); decimater->Update(); surfaceData = decimater->GetOutput(); if (DebugControl::getDebugOn()) { std::cout << "After decimation surface has " << surfaceData->GetPolys()->GetNumberOfCells() << std::endl; } } #else // USE_VTK_DECIMATE_CARET // // Decimate the VTK surface if it is large // vtkDecimatePro* decimater = NULL; if (polygonLimit < numberOfPolygons) { clean1 = vtkCleanPolyData::New(); clean1->SetInput(surfaceData); if (DebugControl::getDebugOn()) { std::cout << "Before decimation surface has " << numberOfPolygons << " polygons." << std::endl; } const double errorVal = 0.001; const double reduction = 1.0 - static_cast(polygonLimit) / static_cast(numberOfPolygons); decimater = vtkDecimatePro::New(); decimater->SetInput(clean1->GetOutput()); decimater->SetTargetReduction(reduction); //0.90); decimater->PreserveTopologyOn(); decimater->SetFeatureAngle(180.0); //5); //30); decimater->SplittingOff(); decimater->PreSplitMeshOff(); decimater->SetMaximumError(errorVal); decimater->BoundaryVertexDeletionOff(); decimater->SetDegree(25); decimater->AccumulateErrorOn(); decimater->SetAbsoluteError(errorVal); decimater->SetErrorIsAbsolute(1); vtkCleanPolyData* clean2 = vtkCleanPolyData::New(); clean2->SetInput(decimater->GetOutput()); clean2->Update(); surfaceData = clean2->GetOutput(); if (DebugControl::getDebugOn()) { std::cout << "After decimation surface has " << surfaceData->GetPolys()->GetNumberOfCells() << std::endl; } } #endif minZ = std::numeric_limits::max(); maxZ = -std::numeric_limits::max(); minX = std::numeric_limits::max(); maxX = -std::numeric_limits::max(); minY = std::numeric_limits::max(); maxY = -std::numeric_limits::max(); // // Invert the matrix for converting back into contour space // matrix.inverse(); // // Convert Z (section numbers) to true Z, untranslate, and unscale the surface // surfacePoints = surfaceData->GetPoints(); for (int nn = 0; nn < surfacePoints->GetNumberOfPoints(); nn++) { #ifdef HAVE_VTK5 double xyz[3]; #else // HAVE_VTK5 float xyz[3]; #endif // HAVE_VTK5 surfacePoints->GetPoint(nn, xyz); double xyzw[4] = { xyz[0], xyz[1], xyz[2], 1.0 }; matrix.multiplyPoint(xyzw); xyz[0] = xyzw[0]; xyz[1] = xyzw[1]; xyz[2] = xyzw[2]; //xyz[2] = vtkSectionToZ->GetValue(xyz[2]); surfacePoints->SetPoint(nn, xyz); if (xyz[0] > maxX) maxX = xyz[0]; if (xyz[0] < minX) minX = xyz[0]; if (xyz[1] > maxY) maxY = xyz[1]; if (xyz[1] < minY) minY = xyz[1]; if (xyz[2] > maxZ) maxZ = xyz[2]; if (xyz[2] < minZ) minZ = xyz[2]; } if (DebugControl::getDebugOn()) { std::cout << "Reconstructed Surface Ranges: " << "(" << minX << ", " << maxX << ") " << "(" << minY << ", " << maxY << ") " << "(" << minZ << ", " << maxZ << ") " << lastSectionNumber << std::endl; } // // Save the surface to a VTK PolyData file. // if (DebugControl::getDebugOn()) { vtkPolyDataWriter* writer = vtkPolyDataWriter::New(); writer->SetInput(surfaceData); writer->SetHeader(""); writer->SetFileName("surface.vtk"); writer->Write(); writer->Delete(); std::cout << "...surface.vtk contains the surface" << endl; } // // Since reconstruction successful clear out any existing surfaces // brainSet->deleteAllBrainModelSurfaces(); // // Convert to vtk file to a brain model surface // try { brainSet->importVtkTypeFileHelper("surface.vtk", surfaceData, true, true, false, BrainModelSurface::SURFACE_TYPE_RAW, TopologyFile::TOPOLOGY_TYPE_CLOSED); } catch (FileException& e) { throw BrainModelAlgorithmException(e.whatQString()); } // // Newest brain model should be the surface // BrainModelSurface* bms = brainSet->getBrainModelSurface(brainSet->getNumberOfBrainModels() - 1); if (bms != NULL) { bms->orientNormalsOut(); bms->setStructure(structure); bms->setSurfaceType(BrainModelSurface::SURFACE_TYPE_RAW); } // // Release memory // if (decimater != NULL) decimater->Delete(); if (clean1 != NULL) clean1->Delete(); if (clean2 != NULL) clean2->Delete(); triangleFilter->Delete(); surface->Delete(); contours->Delete(); brainSet->getNodeColoring()->assignColors(); // // Create sections // if (bms != NULL) { const CoordinateFile* cf = bms->getCoordinateFile(); const int numNodes = cf->getNumberOfCoordinates(); if (numNodes > 0) { SectionFile* sf = brainSet->getSectionFile(); sf->setNumberOfNodesAndColumns(numNodes, 1); sf->setColumnName(0, "Reconstruction"); sf->setColumnComment(0, "Created during reconstruction from contours."); for (int i = 0; i < numNodes; i++) { const float* xyz = cf->getCoordinate(i); sf->setSection(i, 0, static_cast(xyz[2] / spacing)); } } } // // Convert cells if desired // if (convertCellsFlag) { ContourCellFile* contourCellFile = brainSet->getContourCellFile(); const int numContourCells = contourCellFile->getNumberOfCells(); if (numContourCells > 0) { brainSet->deleteAllCells(true, false); brainSet->getCellProjectionFile()->appendFiducialCellFile(*contourCellFile); ContourCellColorFile* contourCellColorFile = brainSet->getContourCellColorFile(); if (contourCellColorFile->getNumberOfColors() > 0) { brainSet->clearCellColorFile(); CellColorFile* cellColor = brainSet->getCellColorFile(); cellColor->append(*contourCellColorFile); } } } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelCiftiCorrelationMatrix.h0000664000175000017500000000455411572067322026450 0ustar michaelmichael #ifndef __BRAIN_MODEL_CIFTI_CORRELATION_MATRIX_H__ #define __BRAIN_MODEL_CIFTI_CORRELATION_MATRIX_H__ #include #include "BrainModelAlgorithm.h" #include "CiftiFile.h" /** * Compute correlation of each metric column with all other metric columns. */ class BrainModelCiftiCorrelationMatrix : public BrainModelAlgorithm { public: // constructor for files that have already been read BrainModelCiftiCorrelationMatrix( BrainSet* bs, CiftiFile * inputCiftiFile, const bool applyFisherZTransformFlag, const bool parallelFlag); // destructor ~BrainModelCiftiCorrelationMatrix(); // execute the algorithm void execute() throw (BrainModelAlgorithmException); // get the output metric file (if called caller is reponsible for DELETING // returned metric file. CiftiFile* getOutputCiftiFile(); private: // initialize variables void initialize(); // load the data values void loadDataValues(); // create output metric file void createOutputCiftiFile(); // compute the means void computeMeans(); // compute the sum-squared void computeSumSquared(); // compute the correlations void computeCorrelations(); // compute correlations for rows until there are no more rows to process void computeCorrelationsForRows(); QString m_inputCiftiFileName; CiftiFile* m_inputCiftiFile; QString m_outputCiftiFileName; CiftiFile* m_outputCiftiFile; float** m_outputDataArrayColumns; long m_inputNumRows; long m_inputNumColumns; long m_outputDimension; // All values in one-dim array float* m_dataValues; // mean of all column values for each row float* m_rowMeans; // sum-squared of all column values for each row double* m_rowSumSquared; const bool m_applyFisherZTransformFlag; bool m_deleteOutputCiftiFlag; long m_nextRowToProcess; const bool m_parallelFlag; }; #endif // __BRAIN_MODEL_SURFACE_METRIC_CORRELATION_MATRIX_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelCiftiCorrelationMatrix.cxx0000664000175000017500000003217611572067322027024 0ustar michaelmichael/* * BrainModelCiftiCorrelationMatrix.cxx * caret_brain_set * * Created by John Harwell on 12/30/10. * Copyright 2010 Washington University School of Medicine. All rights reserved. * */ #include #include #include #include #include #include #include #include #include "BrainModelCiftiCorrelationMatrix.h" #include #ifdef _OPENMP #include #endif static const bool timingFlag = false; /** * constructor. */ BrainModelCiftiCorrelationMatrix::BrainModelCiftiCorrelationMatrix( BrainSet* bs, CiftiFile* inputCiftiFile, const bool applyFisherZTransformFlag, const bool parallelFlag) : BrainModelAlgorithm(bs), m_inputCiftiFile(inputCiftiFile), m_applyFisherZTransformFlag(applyFisherZTransformFlag), m_parallelFlag(parallelFlag) { this->initialize(); } /** * destructor. */ BrainModelCiftiCorrelationMatrix::~BrainModelCiftiCorrelationMatrix() { if (this->m_deleteOutputCiftiFlag) { if (this->m_outputCiftiFile != NULL) { delete this->m_outputCiftiFile; } } if (this->m_dataValues != NULL) { delete[] this->m_dataValues; } if (this->m_rowMeans != NULL) { delete[] this->m_rowMeans; } if (this->m_rowSumSquared != NULL) { delete[] this->m_rowSumSquared; } } /** * initialize variables. */ void BrainModelCiftiCorrelationMatrix::initialize() { this->m_deleteOutputCiftiFlag = true; this->m_outputCiftiFile = NULL; this->m_dataValues = NULL; this->m_rowMeans = NULL; this->m_rowSumSquared = NULL; this->m_nextRowToProcess = -1; } /** * execute the algorithm. */ void BrainModelCiftiCorrelationMatrix::execute() throw (BrainModelAlgorithmException) { QTime loadTimer; loadTimer.start(); Nifti2Header header; nifti_2_header head; this->m_inputCiftiFile->getHeader(header); header.getHeaderStruct(head); if(DebugControl::getDebugOn()) std::cout << "Input Number of Rows is: " << head.dim[5] << std::endl; if(DebugControl::getDebugOn()) std::cout << "Input Number of Columns is: " << head.dim[6] << std::endl; this->m_inputNumRows = head.dim[5]; this->m_inputNumColumns = head.dim[6]; if ((this->m_inputNumRows <= 0) || (this->m_inputNumColumns <= 0)) { throw BrainModelAlgorithmException( "Input Cifti file is empty: " ); //+ this->m_inputCiftiFile->getFileName()); } this->loadDataValues(); if (timingFlag) { std::cout << "Loaded data values in " << (loadTimer.elapsed() * 0.001) << " seconds." << std::endl; } /* * Compute the means */ QTime meanTimer; meanTimer.start(); this->computeMeans(); if (timingFlag) { std::cout << "Computed means in " << (meanTimer.elapsed() * 0.001) << " seconds." << std::endl; } /* * Compute the sumSquared */ QTime ssTimer; ssTimer.start(); this->computeSumSquared(); if (timingFlag) { std::cout << "Computed sum-squareds in " << (ssTimer.elapsed() * 0.001) << " seconds." << std::endl; } /* * Set output dimension output */ this->m_outputDimension = this->m_inputNumRows; /* * Create the output metric file */ QTime createCiftiTimer; createCiftiTimer.start(); this->createOutputCiftiFile(); if (timingFlag) { std::cout << "Created output file in " << (createCiftiTimer.elapsed() * 0.001) << " seconds." << std::endl; } /* * Comute the correlations */ QTime corrTimer; corrTimer.start(); this->computeCorrelations(); if (timingFlag) { std::cout << "Computed correlations in " << (corrTimer.elapsed() * 0.001) << " seconds." << std::endl; } /* * Write output file. */ //not needed for in memory calculation } /** * load the data values. */ void BrainModelCiftiCorrelationMatrix::loadDataValues() { /* * Create and load the data values. */ CiftiMatrix *matrix= m_inputCiftiFile->getCiftiMatrix(); matrix->setCopyData(false); std::vector dimensions; matrix->getMatrixData(this->m_dataValues,dimensions); } /** * get the output metric file (if called, caller is reponsible for DELETING * returned metric file). */ CiftiFile* BrainModelCiftiCorrelationMatrix::getOutputCiftiFile() { this->m_deleteOutputCiftiFlag = false; if(!this->m_outputCiftiFile) { this->m_outputCiftiFile = new CiftiFile(); Nifti2Header header; CiftiXML xml; CiftiMatrix *matrix = new CiftiMatrix(); m_inputCiftiFile->getHeader(header); m_inputCiftiFile->getCiftiXML(xml); nifti_2_header head; header.getHeaderStruct(head); head.dim[6]=head.dim[5];//dimensions are square now head.intent_code = NIFTI_INTENT_CONNECTIVITY_DENSE; memset(head.intent_name,0x00,16); memcpy(head.intent_name,"ConnDense",9); header.SetHeaderStuct(head); CiftiRootElement root; xml.getXMLRoot(root); int mmCount = root.m_matrices.at(0).m_matrixIndicesMap.size(); std::vector mmTemp; std::vector *mm; mm = &(root.m_matrices.at(0).m_matrixIndicesMap); for(int i = 0;iat(i).m_indicesMapToDataType != CIFTI_INDEX_TYPE_TIME_POINTS) mmTemp.push_back(mm->at(i)); } *mm = mmTemp; std::vector appliesToDim (2,0); appliesToDim[0]=0; appliesToDim[1]=1; mm->at(0).m_appliesToMatrixDimension = appliesToDim; xml.setXMLRoot(root); std::vector dim (2,0); dim[0]=head.dim[5]; dim[1]=head.dim[5]; matrix->setCopyData(false); matrix->setMatrixData(this->m_outputDataArrayColumns[0],dim); this->m_outputCiftiFile->setHeader(header); this->m_outputCiftiFile->setCiftiXML(xml); this->m_outputCiftiFile->setCiftiMatrix(*matrix); } return this->m_outputCiftiFile; } /** * compute the means. */ void BrainModelCiftiCorrelationMatrix::computeMeans() { this->m_rowMeans = new float[this->m_inputNumRows]; const long numRows = this->m_inputNumRows; const long numCols = this->m_inputNumColumns; if (this->m_parallelFlag) { #pragma omp parallel for for (long iRow = 0; iRow < numRows; iRow++) { double sum = 0.0; for (long j = 0; j < numCols; j++) { const long indx = iRow * numCols + j; sum += this->m_dataValues[indx]; } this->m_rowMeans[iRow] = sum / numCols; } } else { for (long iRow = 0; iRow < numRows; iRow++) { double sum = 0.0; for (long j = 0; j < numCols; j++) { const long indx = iRow * numCols + j; sum += this->m_dataValues[indx]; } this->m_rowMeans[iRow] = sum / numCols; } } } /** * compute the sum squared. After this, the dataValues array * will contain the value after the mean has been subtracted. */ void BrainModelCiftiCorrelationMatrix::computeSumSquared() { const long numRows = this->m_inputNumRows; const long numCols = this->m_inputNumColumns; this->m_rowSumSquared = new double[numRows]; if (this->m_parallelFlag) { #pragma omp parallel for for (long iRow = 0; iRow < numRows; iRow++) { double ss = 0.0; double mean = this->m_rowMeans[iRow]; for (long jCol = 0; jCol < numCols; jCol++) { const long indx = iRow * numCols + jCol; float f = this->m_dataValues[indx] - mean; ss += (f * f); /* * Save difference of node from for use during correlation calculation */ this->m_dataValues[indx] = f; } this->m_rowSumSquared[iRow] = ss; } } else { for (long iRow = 0; iRow < numRows; iRow++) { double ss = 0.0; double mean = this->m_rowMeans[iRow]; for (long jCol = 0; jCol < numCols; jCol++) { const long indx = iRow * numCols + jCol; float f = this->m_dataValues[indx] - mean; ss += (f * f); /* * Save difference of node from for use during correlation calculation */ this->m_dataValues[indx] = f; } this->m_rowSumSquared[iRow] = ss; } } } /** * compute the correlations. */ void BrainModelCiftiCorrelationMatrix::computeCorrelations() { this->m_nextRowToProcess = -1; #ifdef _OPENMP if (this->m_parallelFlag) { long numThreads = omp_get_max_threads(); if (numThreads > 1) { #pragma omp parallel for for (long i = 0; i < numThreads; i++) { this->computeCorrelationsForRows(); } } else { this->computeCorrelationsForRows(); } } else { this->computeCorrelationsForRows(); } #else this->computeCorrelationsForRows(); #endif } /** * Sompute correlations for rows until there are no more rows to process. * Since the correlation matrix is symmetric, we only need to calculate * the lower half and can then copy the result to the upper half. */ void BrainModelCiftiCorrelationMatrix::computeCorrelationsForRows() { const double tinyValue = 1.0e-20; const long numJ = this->m_outputDimension; const long numCols = this->m_inputNumColumns; while (true) { long iRow = -1; // // Only one thread may execute this block at any time // #pragma omp critical { this->m_nextRowToProcess++; iRow = this->m_nextRowToProcess; if (timingFlag) { if ((iRow % 1000) == 0) { std::cout << "Processing row " << iRow << std::endl; } } } if (iRow >= this->m_outputDimension) { break; } // // Compare with remaining rows // for (long jRow = iRow; jRow < numJ; jRow++) { // // // diff of mean from col I multiplied by diff of mean from column J // double sumSquaredBothColumns = 0.0; for (long jCol = 0; jCol < numCols; jCol++) { const long indxI = iRow * numCols + jCol; const long indxJ = jRow * numCols + jCol; sumSquaredBothColumns += (this->m_dataValues[indxI] * this->m_dataValues[indxJ]); } // // Compute correlation coefficient // const double denominator = this->m_rowSumSquared[iRow] * this->m_rowSumSquared[jRow]; float r = 0.0; if (denominator != 0.0) { double sd = std::sqrt(denominator); r = sumSquaredBothColumns / sd; } else { r = sumSquaredBothColumns / tinyValue; } /* * Apply the Fisher Z-Transform? */ if (this->m_applyFisherZTransformFlag) { float denom = (1.0 - r); if (denom != 0.0) { r = 0.5 * std::log((1.0 + r) / denom); } else { r = 0.5 * std::log((1.0 + r) / tinyValue); } } // // Matrix is symmetric !!!! // //this->outputCiftiFile->setValue(iRow, jRow, r); //this->outputCiftiFile->setValue(jRow, iRow, r); *(this->m_outputDataArrayColumns[iRow] + jRow) = r; *(this->m_outputDataArrayColumns[jRow] + iRow) = r; } } } /** * create output metric file. */ void BrainModelCiftiCorrelationMatrix::createOutputCiftiFile() { if(DebugControl::getDebugOn()) std::cout << "Creating output file of "<< this->m_outputDimension << "x" << this->m_outputDimension << std::endl; this->m_outputDataArrayColumns = new float*[this->m_outputDimension]; unsigned long size = this->m_outputDimension*this->m_outputDimension; if(DebugControl::getDebugOn()) std::cout << "Size to allocate is " << size << " floats" << std::endl; float *temp = new float [size]; if(temp == NULL) { std::cout << "There was an error allocating enough space for the Cifti Output File" << std::endl; exit(1); } if(DebugControl::getDebugOn()) std::cout << "Initializing output array" <m_outputDimension; i++) { long offset = i*this->m_outputDimension; this->m_outputDataArrayColumns[i] = (temp+offset); } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelBorderSet.h0000664000175000017500000006357211572067322023721 0ustar michaelmichael/* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __BRAIN_MODEL_BORDER_SET_H__ #define __BRAIN_MODEL_BORDER_SET_H__ #include #include "BorderFile.h" #include "BrainModelSurface.h" class Border; class BorderFile; class BorderProjection; class BorderProjectionFile; class BrainModelSurface; class BrainSet; class BrainModelBorder; class TransformationMatrix; /********************************************************************************/ /********************************************************************************/ /********************************************************************************/ /// class for a border link class BrainModelBorderLink { public: /// Constructor BrainModelBorderLink(const int numBrainModels); /// Copy Constructor BrainModelBorderLink(const BrainModelBorderLink& bmbl); /// Destructor ~BrainModelBorderLink(); /// add a brain model void addBrainModel(const float xyzIn[3]); /// delete a brain model's links void deleteBrainModel(const int brainModelIndex); /// get the section number int getSection() const { return section; } /// set the section number void setSection(const int secNum); /// get the radius float getRadius() const { return radius; } /// set the radius void setRadius(const float radiusIn); /// get the projection information void getProjection(int verticesOut[3], float areasOut[3]) const; /// get the projection information void setProjection(const int verticesIn[3], const float areasIn[3]); /// get the link position for a brain model const float* getLinkPosition(const int brainModelIndex) const; /// get the link position for a brain model void getLinkPosition(const int brainModelIndex, float xyzOut[3]) const; /// set the link position for a brain model void setLinkPosition(const int brainModelIndex, const float xyzIn[3]); /// get the link position from the border file void getLinkFilePosition(float xyzOut[3]) const; /// set the link position from the border file void setLinkFilePosition(const float xyzIn[3]); /// apply a transformation matrix to a brain model's borders void applyTransformationMatrix(const int brainModelIndex, const TransformationMatrix& tm); /// get the flat normal const float* getFlatNormal() const { return flatNormal; } /// set the flat normal void setFlatNormal(const float normal[3]); /// unproject a border link void unprojectLink(const CoordinateFile* cf, const int brainModelIndex); /// set the BrainModelBorder using this link void setBrainModelBorder(BrainModelBorder* bmb); /// Set the border holding this brain model's link as modified void setModified(const int brainModelIndex); /// Set the border holding this projection as modified void setProjectionModified(); protected: /// section of this border link int section; /// vertices for this border projection point int vertices[3]; /// barycentric areas for this border projection point float areas[3]; /// xyz from border file float fileXYZ[3]; /// xyz for each surface (3 per surface) std::vector xyz; /// flat normals float flatNormal[3]; /// radius of link float radius; /// the brain model border using this link (do not copy in copy constructor) BrainModelBorder* brainModelBorder; // be sure to update copy constructor if members added }; /********************************************************************************/ /********************************************************************************/ /********************************************************************************/ /// class for a single border class BrainModelBorder { public: /// source of border enum BORDER_TYPE { BORDER_TYPE_UNKNOWN, BORDER_TYPE_NORMAL, BORDER_TYPE_PROJECTION }; /// Constructor BrainModelBorder(BrainSet* bs, const QString& nameIn, const BORDER_TYPE typeIn, const BrainModelSurface::SURFACE_TYPES borderFileSurfaceTypeIn = BrainModelSurface::SURFACE_TYPE_UNKNOWN); /// Constructor for a border from a border file BrainModelBorder(BrainSet* bs, const Border* b, const BrainModelSurface::SURFACE_TYPES borderFileSurfaceTypeIn); /// Constructor for a border associated with a surface BrainModelBorder(BrainSet* bs, const BrainModelSurface* bms, const Border* b); /// Constructor for a border from a border projection file BrainModelBorder(BrainSet* bs, BorderProjection* bp); /// Copy constructor BrainModelBorder(const BrainModelBorder& bmb); /// Destructor ~BrainModelBorder(); /// assignment void operator=(const BrainModelBorder& bmb); /// add a link to this border void addBorderLink(const BrainModelBorderLink& bmbl); /// compute flat normals for this model void computeFlatNormals(const BrainModelSurface* bms); ///Copy the border to a border file border (user should destroy returned Border*) Border* copyToBorderFileBorder(const BrainModelSurface* bms) const; /// get the display flag bool getDisplayFlag() const { return displayFlag; } /// set the display flag void setDisplayFlag(const bool df) { displayFlag = df; } /// get the name display flag bool getNameDisplayFlag() const { return nameDisplayFlag; } /// set the name display flag void setNameDisplayFlag(const bool df) { nameDisplayFlag = df; } /// update the border for the addition of a new brain model void addBrainModel(const BrainModel* bm); /// update the border for the deletion of a brain model void deleteBrainModel(const BrainModel* bm); /// get the name of the border QString getName() const { return name; } /// set the name of the border void setName(const QString& s); /// get the sampling density float getSamplingDensity() const { return samplingDensity; } /// set the sampling density void setSamplingDensity(const float samplingDensity); /// get the variance float getVariance() const { return variance; } /// set the variance void setVariance(const float var); /// get the topography value float getTopography() const { return topographyValue; } /// set the topography value void setTopography(const float topography); /// get the areal uncertainty float getArealUncertainty() const { return arealUncertainty; } /// set the areal uncertainty void setArealUncertainty(const float uncertainty); /// get the border color index int getBorderColorFileIndex() const { return borderFileColorIndex; } /// set the border color index void setBorderColorFileIndex(const int indx) { borderFileColorIndex = indx; } /// get the area color file index int getAreaColorFileIndex() const { return areaColorFileIndex; } /// set the area color file index void setAreaColorFileIndex(const int indx) { areaColorFileIndex = indx; } /// get the border valid for a brain model bool getValidForBrainModel(const int brainModelIndex) const; /// get the type of the border (projection or border file) BORDER_TYPE getType() const { return borderType; } /// get the surface type of this border BrainModelSurface::SURFACE_TYPES getSurfaceType() const { return borderFileSurfaceType; } /// set the type of the border (projection or border file) void setType(const BORDER_TYPE bt); /// get a border link BrainModelBorderLink* getBorderLink(const int index); /// get a border link (const method) const BrainModelBorderLink* getBorderLink(const int index) const; /// get the number of border links int getNumberOfBorderLinks() const { return borderLinks.size(); } /// delete a border link void deleteBorderLink(const int linkNumber); /// Determine the bounds of a border for a surface. void getBounds(const BrainModelSurface* bms, float bounds[6]) const; /// Determine the bounds of a border for a surface. void getBounds(const BrainModelSurface* bms, double bounds[6]) const; /// Unproject the border links for a surface void unprojectLinks(const BrainModelSurface* surface); /// reverse the order of links in a border void reverseLinks(); /// orient the links in a border clockwise void orientLinksClockwise(const BrainModelSurface* bms); /// determine if a set of points are inside a polygon formed by a border void pointsInsideBorder(const BrainModelSurface* bms, const float* points, const int numPoints, std::vector& insideFlags, const bool checkNonNegativeZPointsOnly) const; /// resample the border to the specified density void resampleToDensity(const BrainModelSurface* bms, const float density, const int minimumNumberOfLinks, int& newNumberOfLinks); /// resample the border to the specified number of links void resampleToNumberOfLinks(const BrainModelSurface* bms, const int newNumberOfLinks); /// set this brain model's link as modified void setModified(const int brainModelIndex, const bool mod); /// Set this projection as modified void setProjectionModified(const bool mod); /// get this brain model's link as modified bool getModified(const int brainModelIndex) const; /// get this projection as modified bool getProjectionModified() const { return projectionModified; } /// apply a transformation matrix to a brain model's borders void applyTransformationMatrix(const int brainModelIndex, const TransformationMatrix& tm); /// get highlight flag bool getHighlightFlag() const { return highlightFlag; } /// set highlight flag void setHighlightFlag(const bool hf) { highlightFlag = hf; } /// get the link nearest the coordinate (returns -1 if found) int getLinkNearestCoordinate(const int brainModelIndex, const float xyz[3]) const; protected: /// initialize variables in this object void initialize(BrainSet* bs); /// brain set this border is part of BrainSet* brainSet; /// type of the border BORDER_TYPE borderType; /// if BORDER_TYPE_NORMAL type of surface this border associated with BrainModelSurface::SURFACE_TYPES borderFileSurfaceType; /// name of the border QString name; /// sampline density of this border float samplingDensity; /// variance of this border float variance; /// topography of this border float topographyValue; /// uncertainty of this border float arealUncertainty; /// index into border color file int borderFileColorIndex; /// index into area color file int areaColorFileIndex; /// border valid for each brain model std::vector brainModelValidity; /// border modified flags for each brain model std::vector brainModelModified; /// projection modified flags bool projectionModified; /// the border links std::vector borderLinks; /// display flag bool displayFlag; /// name display flag bool nameDisplayFlag; /// highlight border flag bool highlightFlag; // be sure to update copy constructor and operator = if members added friend class BrainModelBorderSet; }; /********************************************************************************/ /********************************************************************************/ /********************************************************************************/ /// class for info about border files that have been read class BrainModelBorderFileInfo { public: /// constructor BrainModelBorderFileInfo() {} /// destructor ~BrainModelBorderFileInfo() { clear(); } /// Set the contents to a border file's values. void loadFromBorderFile(const AbstractFile& af); /// Load the contents into a border file void loadIntoBorderFile(AbstractFile& af) const; /// clear the contents void clear(); /// get the comment QString getFileComment() const; /// set the file comment void setFileComment(const QString& comm); /// get the file name QString getFileName() const { return fileName; } /// set the file name void setFileName(const QString& name) { fileName = name; } /// get the file title QString getFileTitle() const { return fileTitle; } /// set the file title void setFileTitle(const QString& title) { fileTitle = title; } /// get the file header AbstractFile::AbstractFileHeaderContainer getFileHeader() const { return fileHeader; } /// set the file header void setFileHeader(const AbstractFile::AbstractFileHeaderContainer& head) { fileHeader = head; } /// get the PubMed ID QString getPubMedID() const { return pubMedID; } /// set the PubMed ID void setPubMedID(const QString& s) { pubMedID = s; } protected: /// the file's name QString fileName; /// the file's title QString fileTitle; /// the file's header AbstractFile::AbstractFileHeaderContainer fileHeader; /// the file's PubMed ID QString pubMedID; }; /********************************************************************************/ /********************************************************************************/ /********************************************************************************/ /// class for storing all loaded borders and border projections class BrainModelBorderSet { public: /// Constructor BrainModelBorderSet(BrainSet* bs); /// Destructor ~BrainModelBorderSet(); /// add a border void addBorder(BrainModelBorder* border); /// add a brain model void addBrainModel(const BrainModel* bm); /// delete a brain model void deleteBrainModel(const BrainModel* bm); /// assign colors to the borders void assignColors(); /// clear border highlighting void clearBorderHighlighting(); /// compute the flat normals void computeFlatNormals(const BrainModel* bm); /// delete all borders (clears this data) void deleteAllBorders(); /// delete a border void deleteBorder(const int borderIndex); /// delete a border link void deleteBorderLink(const int borderIndex, const int linkIndex); /// delete borders using any of the names. void deleteBordersWithNames(const std::vector& names); /// delete border not displayed on a brain model void deleteBordersNotDisplayedOnBrainModel(const BrainModel* bm); /// delete all projection borders void deleteBorderProjections(); /// get the number of borders int getNumberOfBorders() const { return borders.size(); } /// get a border BrainModelBorder* getBorder(const int index); /// get a border (const method) const BrainModelBorder* getBorder(const int index) const; /// Orient all borders displayed on the model clockwise void orientDisplayedBordersClockwise(const BrainModel* bm); /// project borders for a surface void projectBorders(const BrainModelSurface* bms, const bool barycentricMode = true, const int firstBorderToProject = -1, const int lastBorderToProject = -1); /// unproject borders for a surface void unprojectBorders(const BrainModelSurface* bms, const int firstBorderToProject = -1, const int lastBorderToProject = -1); /// unproject borders for all surfaces void unprojectBordersForAllSurfaces(const int firstBorderToProject = -1, const int lastBorderToProject = -1); /// copy the borders from border file void copyBordersFromBorderFile(const BorderFile* borderFile, const BrainModelSurface::SURFACE_TYPES typeIn); /// copy the borders from border file void copyBordersFromBorderFile(const BrainModelSurface* bms, const BorderFile* borderFile); /// copy the borders from a border projection file void copyBordersFromBorderProjectionFile(BorderProjectionFile* borderProjFile); /// copy borders used by a surface to a border file void copyBordersToBorderFile(const BrainModelSurface* bms, BorderFile& borderFile) const; /// copy borders that are of the specified type BorderFile* copyBordersOfSpecifiedType(const BrainModelSurface::SURFACE_TYPES surfaceType) const; /// copy borders to a border projection file void copyBordersToBorderProjectionFile(BorderProjectionFile& borderProjFile) const; /// interpolate two borders to create new borders (input borders will be resampled too) void createInterpolatedBorders(const BrainModelSurface* bms, const int border1Index, const int border2Index, const QString& namePrefix, const int numberOfNewBorders, const float sampling, QString& errorMessageOut); /// Resample displayed borders for the model to the specified density. void resampleDisplayedBorders(const BrainModel* bm, const float density); /// Reverse displayed borders for model. void reverseDisplayedBorders(const BrainModel* bm); /// get the unique names of all borders void getAllBorderNames(std::vector& names, const bool reverseOrderFlag); /// get indeces of borders with name void getAllBordersWithName(const QString& nameIn, std::vector& indicesOut) const; /// copy a border void copyBorder(const int borderToCopyIndex, const QString& nameForCopiedBorder); /// See if a surface's borders are modified. bool getSurfaceBordersModified(const BrainModelSurface* bms) const; ///Set a surface's borders as modified. void setSurfaceBordersModified(const BrainModelSurface* bms, const bool mod); /// See if any projections are modified. bool getProjectionsModified() const; /// Set projections modified. void setProjectionsModified(const bool mod); /// Set the modification status of all borders void setAllBordersModifiedStatus(const bool mod); /// Set display flag for borders with specified name void setNameDisplayFlagForBordersWithName(const QString& name, const bool flag); /// get the border file info BrainModelBorderFileInfo* getBorderFileInfo(const BrainModelSurface::SURFACE_TYPES st); /// get the border file info const BrainModelBorderFileInfo* getBorderFileInfo(const BrainModelSurface::SURFACE_TYPES st) const; /// set the border file info void setBorderFileInfo(const BrainModelSurface::SURFACE_TYPES st, const BrainModelBorderFileInfo& fileInfo); /// get the border projection file info BrainModelBorderFileInfo* getBorderProjectionFileInfo() { return &fileInfoProjection; } /// get the border projection file info (const method) const BrainModelBorderFileInfo* getBorderProjectionFileInfo() const { return &fileInfoProjection; } /// set the border projection file info void setBorderProjectionFileInfo(const BrainModelBorderFileInfo& fileInfo) { fileInfoProjection = fileInfo; } /// get the volume's borders BorderFile* getVolumeBorders() { return &volumeBorders; } /// get the volume's borders (const method) const BorderFile* getVolumeBorders() const { return &volumeBorders; } /// copy the volume borders to the fiducial borders void copyVolumeBordersToFiducialBorders(); /// apply a transformation matrix to a brain model's borders void applyTransformationMatrix(const BrainModelSurface* bms, const TransformationMatrix& tm); /// set default file names if they are empty void setDefaultFileNames(); /// find border and links nearest 3D coordinate (returns true if found) bool findBorderAndLinkNearestCoordinate(const BrainModelSurface* bms, const float xyz[3], int& borderNumberOut, int& borderLinkOut) const; /// update border mode enum UPDATE_BORDER_MODE { /// update border mode none UPDATE_BORDER_MODE_NONE, /// update border mode replace segment in middle of border UPDATE_BORDER_MODE_REPLACE_SEGMENT_IN_MIDDLE_OF_BORDER, /// update border erase UPDATE_BORDER_MODE_ERASE, /// update border mode extend border from end UPDATE_BORDER_MODE_EXTEND_BORDER_FROM_END }; /// update a border with a new segment void updateBorder(const BrainModelSurface* bms, const UPDATE_BORDER_MODE updateMode, Border* newBorderSegment, const float samplingDensity, const bool projectBorderFlag, QString& errorMessageOut); protected: /// brain set using this object BrainSet* brainSet; /// the borders std::vector borders; /// header information for border projection file BrainModelBorderFileInfo fileInfoProjection; /// header information for raw borders BrainModelBorderFileInfo fileInfoRaw; /// header information for fiducial borders BrainModelBorderFileInfo fileInfoFiducial; /// header information for inflated borders BrainModelBorderFileInfo fileInfoInflated; /// header information for very inflated borders BrainModelBorderFileInfo fileInfoVeryInflated; /// header information for spherical borders BrainModelBorderFileInfo fileInfoSpherical; /// header information for ellipsoidal borders BrainModelBorderFileInfo fileInfoEllipsoidal; /// header information for compressed medial wall borders BrainModelBorderFileInfo fileInfoCompMedWall; /// header information for flat borders BrainModelBorderFileInfo fileInfoFlat; /// header information for lobar flat borders BrainModelBorderFileInfo fileInfoLobarFlat; /// header information for lobar flat borders BrainModelBorderFileInfo fileInfoHull; /// header information for unknown borders BrainModelBorderFileInfo fileInfoUnknown; /// the volume's borders BorderFile volumeBorders; }; #endif // __BRAIN_MODEL_BORDER_SET_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelBorderSet.cxx0000664000175000017500000024617511572067322024276 0ustar michaelmichael/* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include // needed for Q_OS_WIN32 #ifdef Q_OS_WIN32 // required for M_PI in #define _USE_MATH_DEFINES #define NOMINMAX #endif #include #include #include #include #include "vtkMath.h" #include "vtkPolygon.h" #include "AreaColorFile.h" #include "BorderColorFile.h" #include "BorderFile.h" #include "BorderProjectionFile.h" #include "BrainModelBorderSet.h" #include "BrainModelSurfacePointProjector.h" #include "BrainModelVolume.h" #include "BrainSet.h" #include "ColorFile.h" #include "DebugControl.h" #include "MathUtilities.h" #include "StringUtilities.h" #include "TransformationMatrixFile.h" /*************************************************************************************/ /** ** BrainModelBorderSet methods **/ /*************************************************************************************/ /** * Constructor. */ BrainModelBorderSet::BrainModelBorderSet(BrainSet* bs) { brainSet = bs; } /** * Destructor. */ BrainModelBorderSet::~BrainModelBorderSet() { deleteAllBorders(); } /** * set default file names if they are empty. */ void BrainModelBorderSet::setDefaultFileNames() { BrainModelBorderFileInfo* bpi = getBorderProjectionFileInfo(); if (bpi->getFileName().isEmpty()) { BorderProjectionFile bpf; bpi->setFileName(bpf.getFileName()); } for (int i = BrainModelSurface::SURFACE_TYPE_RAW; i <= BrainModelSurface::SURFACE_TYPE_UNSPECIFIED; i++) { const BrainModelSurface::SURFACE_TYPES surfaceType = static_cast(i); BrainModelBorderFileInfo* bfi = getBorderFileInfo(surfaceType); if (bfi != NULL) { if (bfi->getFileName().isEmpty()) { BorderFile bf; bfi->setFileName(bf.getFileName()); } } } } /** * add a brain model. */ void BrainModelBorderSet::addBrainModel(const BrainModel* bm) { const int num = getNumberOfBorders(); for (int i = 0; i < num; i++) { BrainModelBorder* b = getBorder(i); b->addBrainModel(bm); } } /** * delete a brain model */ void BrainModelBorderSet::deleteBrainModel(const BrainModel* bm) { const int num = getNumberOfBorders(); for (int i = 0; i < num; i++) { BrainModelBorder* b = getBorder(i); b->deleteBrainModel(bm); } } /** * Assign colors to the borders */ void BrainModelBorderSet::assignColors() { const AreaColorFile* acf = brainSet->getAreaColorFile(); const BorderColorFile* bcf = brainSet->getBorderColorFile(); const int num = getNumberOfBorders(); for (int i = 0; i < num; i++) { BrainModelBorder* b = getBorder(i); bool match; b->setAreaColorFileIndex(acf->getColorIndexByName(b->getName(), match)); b->setBorderColorFileIndex(bcf->getColorIndexByName(b->getName(), match)); } volumeBorders.assignColors(*bcf); } /** * clear border highlighting. */ void BrainModelBorderSet::clearBorderHighlighting() { const int num = getNumberOfBorders(); for (int i = 0; i < num; i++) { BrainModelBorder* b = getBorder(i); b->setHighlightFlag(false); } } /** * delete all borders (clears this data). */ void BrainModelBorderSet::deleteAllBorders() { const int num = getNumberOfBorders(); for (int i = 0; i < num; i++) { delete borders[i]; } borders.clear(); fileInfoProjection.clear(); fileInfoRaw.clear(); fileInfoFiducial.clear(); fileInfoInflated.clear(); fileInfoVeryInflated.clear(); fileInfoSpherical.clear(); fileInfoEllipsoidal.clear(); fileInfoCompMedWall.clear(); fileInfoFlat.clear(); fileInfoLobarFlat.clear(); fileInfoHull.clear(); fileInfoUnknown.clear(); volumeBorders.clear(); SpecFile* sf = brainSet->getLoadedFilesSpecFile(); sf->rawBorderFile.setAllSelections(SpecFile::SPEC_FALSE); sf->fiducialBorderFile.setAllSelections(SpecFile::SPEC_FALSE); sf->inflatedBorderFile.setAllSelections(SpecFile::SPEC_FALSE); sf->veryInflatedBorderFile.setAllSelections(SpecFile::SPEC_FALSE); sf->sphericalBorderFile.setAllSelections(SpecFile::SPEC_FALSE); sf->ellipsoidBorderFile.setAllSelections(SpecFile::SPEC_FALSE); sf->compressedBorderFile.setAllSelections(SpecFile::SPEC_FALSE); sf->flatBorderFile.setAllSelections(SpecFile::SPEC_FALSE); sf->lobarFlatBorderFile.setAllSelections(SpecFile::SPEC_FALSE); sf->unknownBorderFile.setAllSelections(SpecFile::SPEC_FALSE); sf->hullBorderFile.setAllSelections(SpecFile::SPEC_FALSE); sf->volumeBorderFile.setAllSelections(SpecFile::SPEC_FALSE); sf->borderProjectionFile.setAllSelections(SpecFile::SPEC_FALSE); setDefaultFileNames(); } /** * get the border file info. */ BrainModelBorderFileInfo* BrainModelBorderSet::getBorderFileInfo(const BrainModelSurface::SURFACE_TYPES st) { switch (st) { case BrainModelSurface::SURFACE_TYPE_RAW: return &fileInfoRaw; break; case BrainModelSurface::SURFACE_TYPE_FIDUCIAL: return &fileInfoFiducial; break; case BrainModelSurface::SURFACE_TYPE_INFLATED: return &fileInfoInflated; break; case BrainModelSurface::SURFACE_TYPE_VERY_INFLATED: return &fileInfoVeryInflated; break; case BrainModelSurface::SURFACE_TYPE_SPHERICAL: return &fileInfoSpherical; break; case BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL: return &fileInfoEllipsoidal; break; case BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL: return &fileInfoCompMedWall; break; case BrainModelSurface::SURFACE_TYPE_FLAT: return &fileInfoFlat; break; case BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR: return &fileInfoLobarFlat; break; case BrainModelSurface::SURFACE_TYPE_HULL: return &fileInfoHull; break; case BrainModelSurface::SURFACE_TYPE_UNKNOWN: case BrainModelSurface::SURFACE_TYPE_UNSPECIFIED: return &fileInfoUnknown; break; } return NULL; } /** * get the border file info (const method). */ const BrainModelBorderFileInfo* BrainModelBorderSet::getBorderFileInfo(const BrainModelSurface::SURFACE_TYPES st) const { switch (st) { case BrainModelSurface::SURFACE_TYPE_RAW: return &fileInfoRaw; break; case BrainModelSurface::SURFACE_TYPE_FIDUCIAL: return &fileInfoFiducial; break; case BrainModelSurface::SURFACE_TYPE_INFLATED: return &fileInfoInflated; break; case BrainModelSurface::SURFACE_TYPE_VERY_INFLATED: return &fileInfoVeryInflated; break; case BrainModelSurface::SURFACE_TYPE_SPHERICAL: return &fileInfoSpherical; break; case BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL: return &fileInfoEllipsoidal; break; case BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL: return &fileInfoCompMedWall; break; case BrainModelSurface::SURFACE_TYPE_FLAT: return &fileInfoFlat; break; case BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR: return &fileInfoLobarFlat; break; case BrainModelSurface::SURFACE_TYPE_HULL: return &fileInfoHull; break; case BrainModelSurface::SURFACE_TYPE_UNKNOWN: case BrainModelSurface::SURFACE_TYPE_UNSPECIFIED: return &fileInfoUnknown; break; } return NULL; } /** * set the border file info. */ void BrainModelBorderSet::setBorderFileInfo(const BrainModelSurface::SURFACE_TYPES st, const BrainModelBorderFileInfo& fileInfo) { switch (st) { case BrainModelSurface::SURFACE_TYPE_RAW: fileInfoRaw = fileInfo; break; case BrainModelSurface::SURFACE_TYPE_FIDUCIAL: fileInfoFiducial = fileInfo; break; case BrainModelSurface::SURFACE_TYPE_INFLATED: fileInfoInflated = fileInfo; break; case BrainModelSurface::SURFACE_TYPE_VERY_INFLATED: fileInfoVeryInflated = fileInfo; break; case BrainModelSurface::SURFACE_TYPE_SPHERICAL: fileInfoSpherical = fileInfo; break; case BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL: fileInfoEllipsoidal = fileInfo; break; case BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL: fileInfoCompMedWall = fileInfo; break; case BrainModelSurface::SURFACE_TYPE_FLAT: fileInfoFlat = fileInfo; break; case BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR: fileInfoLobarFlat = fileInfo; break; case BrainModelSurface::SURFACE_TYPE_HULL: fileInfoHull = fileInfo; break; case BrainModelSurface::SURFACE_TYPE_UNKNOWN: case BrainModelSurface::SURFACE_TYPE_UNSPECIFIED: fileInfoUnknown = fileInfo; break; } } /** * Delete a border. */ void BrainModelBorderSet::deleteBorder(const int borderIndex) { if ((borderIndex >= 0) && (borderIndex < getNumberOfBorders())) { delete borders[borderIndex]; borders.erase(borders.begin() + borderIndex, borders.begin() + borderIndex + 1); } setProjectionsModified(true); } /** * Delete a border link */ void BrainModelBorderSet::deleteBorderLink(const int borderIndex, const int linkIndex) { if ((borderIndex >= 0) && (borderIndex < getNumberOfBorders())) { borders[borderIndex]->deleteBorderLink(linkIndex); } setProjectionsModified(true); } /** * delete all projection borders. */ void BrainModelBorderSet::deleteBorderProjections() { std::vector bordersToDelete; const int numBorders = getNumberOfBorders(); for (int i = 0; i < numBorders; i++) { if (getBorder(i)->getType() == BrainModelBorder::BORDER_TYPE_PROJECTION) { if (DebugControl::getDebugOn()) { std::cout << "Will delete border " << i << std::endl; } bordersToDelete.push_back(i); } } for (int i = (static_cast(bordersToDelete.size()) - 1); i >= 0; i--) { deleteBorder(bordersToDelete[i]); } fileInfoProjection.clear(); SpecFile* sf = brainSet->getLoadedFilesSpecFile(); sf->borderProjectionFile.setAllSelections(SpecFile::SPEC_FALSE); } /** * update a border with a new segment. */ void BrainModelBorderSet::updateBorder(const BrainModelSurface* bms, const UPDATE_BORDER_MODE updateMode, Border* newBorderSegment, const float samplingDensity, const bool projectBorderFlag, QString& errorMessageOut) { const int brainModelIndex = bms->getBrainModelIndex(); if (brainModelIndex <= 0) { return; } const int numberOfBrainModels = brainSet->getNumberOfBrainModels(); const int numberOfLinksInNewSegment = newBorderSegment->getNumberOfLinks(); if (numberOfLinksInNewSegment <= 1) { return; } // // Links where new border segment is inserted // BrainModelBorder* bmb = NULL; int borderNumber = -1; int startLinkNumber = -1; int endLinkNumber = -1; bool reverseOrderFlag = false; // // New segment must be this close to an existing border link // const float distanceTolerance = 25.0; // // Start and end based upon update mode // const bool eraseModeFlag = (updateMode == UPDATE_BORDER_MODE_ERASE); switch (updateMode) { case UPDATE_BORDER_MODE_NONE: errorMessageOut = "Update MODE is invalid."; return; break; case UPDATE_BORDER_MODE_REPLACE_SEGMENT_IN_MIDDLE_OF_BORDER: case UPDATE_BORDER_MODE_ERASE: { // // Find border link nearest start of updated links // if (findBorderAndLinkNearestCoordinate(bms, newBorderSegment->getLinkXYZ(0), borderNumber, startLinkNumber) == false) { errorMessageOut = "Unable to find border near start of new links."; return; } // // Find the link nearest the end of updated links // bmb = getBorder(borderNumber); endLinkNumber = bmb->getLinkNearestCoordinate(brainModelIndex, newBorderSegment->getLinkXYZ(numberOfLinksInNewSegment - 1)); if (endLinkNumber < 0) { errorMessageOut = "Unable to find border near end of new links."; return; } QString newEraseString("New"); if (eraseModeFlag) { newEraseString = "Erase"; } // // Make sure new segment starts and ends near new border // const float* borderStartXYZ = bmb->getBorderLink(startLinkNumber)->getLinkPosition(brainModelIndex); const float distToStart = MathUtilities::distance3D(borderStartXYZ, newBorderSegment->getLinkXYZ(0)); if (distToStart > distanceTolerance) { errorMessageOut = newEraseString + " segment does not start close to a border."; return; } const float* borderEndXYZ = bmb->getBorderLink(endLinkNumber)->getLinkPosition(brainModelIndex); const float distToEnd = MathUtilities::distance3D(borderEndXYZ, newBorderSegment->getLinkXYZ(numberOfLinksInNewSegment - 1)); if (distToEnd > distanceTolerance) { errorMessageOut = newEraseString + " segment does not end close to a border."; return; } // // If needed, reverse links // if (startLinkNumber > endLinkNumber) { reverseOrderFlag = true; std::swap(startLinkNumber, endLinkNumber); } } break; case UPDATE_BORDER_MODE_EXTEND_BORDER_FROM_END: { // // Find border link nearest start of updated links // int nearestLinkNumber = -1; if (findBorderAndLinkNearestCoordinate(bms, newBorderSegment->getLinkXYZ(0), borderNumber, nearestLinkNumber) == false) { errorMessageOut = "Unable to find border near start of new links."; return; } bmb = getBorder(borderNumber); // // Get distance from both ends of existing border to first // link in new segment // const float* borderStartXYZ = bmb->getBorderLink(0)->getLinkPosition(brainModelIndex); const float distToStart = MathUtilities::distance3D(borderStartXYZ, newBorderSegment->getLinkXYZ(0)); const float* borderEndXYZ = bmb->getBorderLink(bmb->getNumberOfBorderLinks() - 1)->getLinkPosition(brainModelIndex); const float distToEnd = MathUtilities::distance3D(borderEndXYZ, newBorderSegment->getLinkXYZ(0)); // // Add on to start or ending end of border // if (distToStart < distToEnd) { if (distToStart > distanceTolerance) { errorMessageOut = "New segment is not close to a border."; return; } endLinkNumber = nearestLinkNumber; reverseOrderFlag = true; } else { if (distToEnd > distanceTolerance) { errorMessageOut = "New segment is not close to a border."; return; } startLinkNumber = nearestLinkNumber; } } break; } // // Create a new border // BrainModelBorder* newBorder = new BrainModelBorder(*bmb); newBorder->borderLinks.clear(); // // Add in links prior to updated links // if (startLinkNumber >= 0) { for (int i = 0; i < (startLinkNumber - 1); i++) { BrainModelBorderLink newLink(*(bmb->getBorderLink(i))); newBorder->addBorderLink(newLink); } } // // If not erasing // if (eraseModeFlag == false) { // // Add new links // if (reverseOrderFlag) { for (int i = (numberOfLinksInNewSegment - 1); i >= 0; i--) { const float* xyz = newBorderSegment->getLinkXYZ(i); BrainModelBorderLink newLink(numberOfBrainModels); newLink.setLinkPosition(brainModelIndex, xyz); newBorder->addBorderLink(newLink); } } else { for (int i = 0; i < numberOfLinksInNewSegment; i++) { const float* xyz = newBorderSegment->getLinkXYZ(i); BrainModelBorderLink newLink(numberOfBrainModels); newLink.setLinkPosition(brainModelIndex, xyz); newBorder->addBorderLink(newLink); } } } // // Add in links after updated links // if (endLinkNumber >= 0) { for (int i = (endLinkNumber + 1); i < bmb->getNumberOfBorderLinks(); i++) { BrainModelBorderLink newLink(*(bmb->getBorderLink(i))); newBorder->addBorderLink(newLink); } } // // Delete the old border // borders.erase(borders.begin() + borderNumber); // // Resample // int dummyInt; newBorder->resampleToDensity(bms, samplingDensity, 2, dummyInt); // // Add the new border // addBorder(newBorder); if (projectBorderFlag) { const int lastBorderNumber = getNumberOfBorders() - 1; projectBorders(bms, true, lastBorderNumber, lastBorderNumber); } } /** * find border and links nearest 3D coordinate (returns true if found). */ bool BrainModelBorderSet::findBorderAndLinkNearestCoordinate(const BrainModelSurface* bms, const float xyz[3], int& borderNumberOut, int& borderLinkOut) const { borderNumberOut = -1; borderLinkOut = -1; float maxDist = std::numeric_limits::max(); const int brainModelIndex = bms->getBrainModelIndex(); if (brainModelIndex <= 0) { return false; } const int numBorders = getNumberOfBorders(); for (int i = 0; i < numBorders; i++) { const BrainModelBorder* bmb = getBorder(i); const int nearestLink = bmb->getLinkNearestCoordinate(brainModelIndex, xyz); if (nearestLink >= 0) { const BrainModelBorderLink* bmbl = bmb->getBorderLink(nearestLink); const float* pos = bmbl->getLinkPosition(brainModelIndex); if (pos != NULL) { const float dist = MathUtilities::distanceSquared3D(pos, xyz); if (dist < maxDist) { borderNumberOut = i; borderLinkOut = nearestLink; maxDist = dist; } } } } return (borderNumberOut >= 0); } /** * delete border not displayed on a brain model. */ void BrainModelBorderSet::deleteBordersNotDisplayedOnBrainModel(const BrainModel* bm) { const int brainModelIndex = brainSet->getBrainModelIndex(bm); if (brainModelIndex < 0) { std::cout << "PROGRAM ERROR: invalid brain model index at " << __LINE__ << " in " << __FILE__ << std::endl; return; } std::vector bordersToDelete; const int numBorders = getNumberOfBorders(); for (int i = (numBorders - 1); i >= 0; i--) { const BrainModelBorder* b = getBorder(i); if (b->getValidForBrainModel(brainModelIndex) && b->getDisplayFlag()) { // keep border } else { deleteBorder(i); } } } /** * Delete borders using any of the names. */ void BrainModelBorderSet::deleteBordersWithNames(const std::vector& names) { std::vector bordersToDelete; const int numBorders = getNumberOfBorders(); for (int i = 0; i < numBorders; i++) { const QString name(getBorder(i)->getName()); if (std::find(names.begin(), names.end(), name) != names.end()) { if (DebugControl::getDebugOn()) { std::cout << "Will delete border " << i << " with name " << name.toAscii().constData() << std::endl; } bordersToDelete.push_back(i); } } for (int i = (static_cast(bordersToDelete.size()) - 1); i >= 0; i--) { deleteBorder(bordersToDelete[i]); } bordersToDelete.clear(); for (int i = 0; i < volumeBorders.getNumberOfBorders(); i++) { const QString name = volumeBorders.getBorder(i)->getName(); if (std::find(names.begin(), names.end(), name) != names.end()) { bordersToDelete.push_back(i); } } volumeBorders.removeBordersWithIndices(bordersToDelete); } /** * get a border. */ BrainModelBorder* BrainModelBorderSet::getBorder(const int index) { if (index < getNumberOfBorders()) { return borders[index]; } return NULL; } /** * get a border (const method). */ const BrainModelBorder* BrainModelBorderSet::getBorder(const int index) const { if (index < getNumberOfBorders()) { return borders[index]; } return NULL; } /** * copy the borders from border file. */ void BrainModelBorderSet::copyBordersFromBorderFile(const BorderFile* borderFile, const BrainModelSurface::SURFACE_TYPES surfaceType) { const int numBorders = borderFile->getNumberOfBorders(); if (numBorders > 0) { for (int i = 0; i < numBorders; i++) { BrainModelBorder* border = new BrainModelBorder(brainSet, borderFile->getBorder(i), surfaceType); if (border->getNumberOfBorderLinks() > 0) { addBorder(border); } else { delete border; } } BrainModelBorderFileInfo* bfi = getBorderFileInfo(surfaceType); if (bfi != NULL) { bfi->loadFromBorderFile(*borderFile); } } } /** * copy the borders from border file. */ void BrainModelBorderSet::copyBordersFromBorderFile(const BrainModelSurface* bms, const BorderFile* borderFile) { const int numBorders = borderFile->getNumberOfBorders(); if (numBorders > 0) { for (int i = 0; i < numBorders; i++) { BrainModelBorder* border = new BrainModelBorder(brainSet, bms, borderFile->getBorder(i)); if (border->getNumberOfBorderLinks() > 0) { addBorder(border); } else { delete border; } } BrainModelBorderFileInfo* bfi = getBorderFileInfo(bms->getSurfaceType()); if (bfi != NULL) { bfi->loadFromBorderFile(*borderFile); } } } /** * copy the borders from a border projection file. */ void BrainModelBorderSet::copyBordersFromBorderProjectionFile(BorderProjectionFile* borderProjFile) { const int numBorders = borderProjFile->getNumberOfBorderProjections(); if (numBorders > 0) { for (int i = 0; i < numBorders; i++) { BrainModelBorder* border = new BrainModelBorder(brainSet, borderProjFile->getBorderProjection(i)); if (border->getNumberOfBorderLinks() > 0) { addBorder(border); } else { delete border; } } BrainModelBorderFileInfo* bfi = getBorderProjectionFileInfo(); if (bfi != NULL) { bfi->loadFromBorderFile(*borderProjFile); } } } /** * copy borders to a border projection file. */ void BrainModelBorderSet::copyBordersToBorderFile(const BrainModelSurface* bms, BorderFile& borderFile) const { // // Clear the border file // borderFile.clear(); const int brainModelIndex = brainSet->getBrainModelIndex(bms); if (brainModelIndex < 0) { std::cout << "PROGRAM ERROR: Cannot find brain model at " << __LINE__ << " in " << __FILE__ << std::endl; return; } //const float center[3] = { 0.0, 0.0, 0.0 }; // // Check each border // const int numBorders = getNumberOfBorders(); for (int i = 0; i < numBorders; i++) { Border* border = getBorder(i)->copyToBorderFileBorder(bms); if (border->getNumberOfLinks() > 0) { borderFile.addBorder(*border); } } const BrainModelBorderFileInfo* bfi = getBorderFileInfo(bms->getSurfaceType()); if (bfi != NULL) { bfi->loadIntoBorderFile(borderFile); } } /** * copy borders that are of the specified type. */ BorderFile* BrainModelBorderSet::copyBordersOfSpecifiedType(const BrainModelSurface::SURFACE_TYPES surfaceType) const { BorderFile* borderFile = new BorderFile; const int numBrainModels = brainSet->getNumberOfBrainModels(); if (numBrainModels <= 0) { return NULL; } // // Find surfaces that are of the specified type // std::vector matchingSurfaceFlag(numBrainModels, false); for (int i = 0; i < numBrainModels; i++) { const BrainModelSurface* bms = brainSet->getBrainModelSurface(i); if (bms != NULL) { if (bms->getSurfaceType() == surfaceType) { matchingSurfaceFlag[i] = true; } } } // // Check each border // const int numBorders = getNumberOfBorders(); for (int i = 0; i < numBorders; i++) { BrainModelSurface* surface = NULL; const BrainModelBorder* b = getBorder(i); bool useBorder = false; for (int i = 0; i < numBrainModels; i++) { if (matchingSurfaceFlag[i]) { if (b->getValidForBrainModel(i)) { useBorder = true; surface = brainSet->getBrainModelSurface(i); break; } } } // // Convert from BrainModelBorderSet border to BorderFile border // if (useBorder) { Border* border = b->copyToBorderFileBorder(surface); if (border->getNumberOfLinks() > 0) { borderFile->addBorder(*border); } delete border; } } const BrainModelBorderFileInfo* bfi = getBorderFileInfo(surfaceType); if (bfi != NULL) { bfi->loadIntoBorderFile(*borderFile); } return borderFile; } /** * copy borders to a border projection file. */ void BrainModelBorderSet::copyBordersToBorderProjectionFile(BorderProjectionFile& borderProjFile) const { // // Clear the border projectionfile // borderProjFile.clear(); const float center[3] = { 0.0, 0.0, 0.0 }; // // Check each border // const int numBorders = getNumberOfBorders(); for (int i = 0; i < numBorders; i++) { // // Is border projected // const BrainModelBorder* b = getBorder(i); if (b->getType() == BrainModelBorder::BORDER_TYPE_PROJECTION) { // // Create the border for the border file // BorderProjection borderProj(b->getName(), center, b->getSamplingDensity(), b->getVariance(), b->getTopography(), b->getArealUncertainty()); // // Copy the links to the border file's border // const int numLinks = b->getNumberOfBorderLinks(); for (int j = 0; j < numLinks; j++) { const BrainModelBorderLink* link = b->getBorderLink(j); int vertices[3]; float areas[3]; link->getProjection(vertices, areas); BorderProjectionLink bpl(link->getSection(), vertices, areas, link->getRadius()); borderProj.addBorderProjectionLink(bpl); } // // Add the border to the border file // if (borderProj.getNumberOfLinks() > 0) { borderProjFile.addBorderProjection(borderProj); } } } const BrainModelBorderFileInfo* bfi = getBorderProjectionFileInfo(); if (bfi != NULL) { bfi->loadIntoBorderFile(borderProjFile); } } /** * add a border. */ void BrainModelBorderSet::addBorder(BrainModelBorder* border) { borders.push_back(border); for (int i = 0; i < brainSet->getNumberOfBrainModels(); i++) { if (border->getValidForBrainModel(i)) { border->setModified(i, true); } } } /** * Unproject the borders for a surface. */ void BrainModelBorderSet::unprojectBorders(const BrainModelSurface* bms, const int firstBorderToProject, const int lastBorderToProject) { // // Start & stop border indices // const int numBorders = getNumberOfBorders(); int startIndex = 0; int endIndex = numBorders; if (firstBorderToProject >= 0) { startIndex = firstBorderToProject; if (startIndex > numBorders) { startIndex = numBorders; } } if (lastBorderToProject >= 0) { endIndex = lastBorderToProject + 1; if (endIndex > numBorders) { endIndex = numBorders; } } for (int i = startIndex; i < endIndex; i++) { borders[i]->unprojectLinks(bms); } } /** * Unproject the borders for all surfaces. */ void BrainModelBorderSet::unprojectBordersForAllSurfaces(const int firstBorderToProject, const int lastBorderToProject) { const int num = brainSet->getNumberOfBrainModels(); for (int i = 0; i < num; i++) { const BrainModelSurface* bms = brainSet->getBrainModelSurface(i); if (bms != NULL) { unprojectBorders(bms, firstBorderToProject, lastBorderToProject); } } setAllBordersModifiedStatus(false); } /** * Project the borders for a surface. */ void BrainModelBorderSet::projectBorders(const BrainModelSurface* bms, const bool barycentricMode, const int firstBorderToProject, const int lastBorderToProject) { const int brainModelIndex = brainSet->getBrainModelIndex(bms); if (brainModelIndex < 0) { std::cout << "PROGRAM ERROR: Cannot find brain model at " << __LINE__ << " in " << __FILE__ << std::endl; return; } // // Create a point projector for projecting the borders // BrainModelSurfacePointProjector pointProjector(bms, BrainModelSurfacePointProjector::SURFACE_TYPE_HINT_OTHER, false); // // Keeps track of borders for keeping // const int numBorders = getNumberOfBorders(); std::vector bordersToKeep(numBorders, true); // // Start & stop border indices // int startIndex = 0; int endIndex = numBorders; if (firstBorderToProject >= 0) { startIndex = firstBorderToProject; if (startIndex > numBorders) { startIndex = numBorders; } } if (lastBorderToProject >= 0) { endIndex = lastBorderToProject + 1; if (endIndex > numBorders) { endIndex = numBorders; } } for (int i = startIndex; i < endIndex; i++) { // // Border is now a projected border // BrainModelBorder* b = getBorder(i); // // Only keep borders that are valid for this brain model // const bool validBorder = b->getValidForBrainModel(brainModelIndex); bordersToKeep[i] = validBorder; // // If this border should be projected // if (validBorder) { // // Border is now a projected border // b->setType(BrainModelBorder::BORDER_TYPE_PROJECTION); // // Keep track of which links are successfully projected // std::vector linksToKeep; // // Project each link // const int numLinks = b->getNumberOfBorderLinks(); for (int j = 0; j < numLinks; j++) { BrainModelBorderLink* link = b->getBorderLink(j); // // Position of link for this surface // float xyz[3]; link->getLinkPosition(brainModelIndex, xyz); // // Project the link for this surface // int vertices[3]; float areas[3]; bool validPoint = false; // // Points at origin were not successfully projected so ignore them // if ((xyz[0] != 0.0) || (xyz[1] != 0.0) || (xyz[2] != 0.0)) { if (barycentricMode) { int nearestNode = -1; const int tileNumber = pointProjector.projectBarycentric(xyz, nearestNode, vertices, areas); if ((nearestNode >= 0) && (tileNumber >= 0)) { validPoint = true; } } else { const int nearestNode = pointProjector.projectToNearestNode(xyz); if (nearestNode >= 0) { vertices[0] = nearestNode; vertices[1] = nearestNode; vertices[2] = nearestNode; areas[0] = 1.0; areas[1] = 0.0; areas[2] = 0.0; validPoint = true; } } } // // keep track of valid projected links // linksToKeep.push_back(validPoint); // // Set the projection information for this link // if (validPoint) { link->setProjection(vertices, areas); } } // // Delete links that were not projected successfully // for (int j = (numLinks - 1); j >= 0; j--) { if (linksToKeep[j] == false) { b->deleteBorderLink(j); } } } } // // Delete borders that were not valid for this surface // for (int i = (numBorders - 1); i >= 0; i--) { if (bordersToKeep[i] == false) { deleteBorder(i); } } // // Unproject all borders // unprojectBordersForAllSurfaces(firstBorderToProject, lastBorderToProject); // // Set all projected borders modified // setProjectionsModified(true); // // Set projection file info using an empty file // BrainModelBorderFileInfo* bfi = getBorderProjectionFileInfo(); if (bfi == NULL) { BorderProjectionFile bpf; bfi->loadFromBorderFile(bpf); } else { if (bfi->getFileName().isEmpty()) { bfi->clear(); BorderProjectionFile bpf; bfi->loadFromBorderFile(bpf); } } } /** * Orient the borders displayed on this surface clockwise. */ void BrainModelBorderSet::orientDisplayedBordersClockwise(const BrainModel* bm) { const BrainModelSurface* bms = dynamic_cast(bm); if (bms != NULL) { const int numBorders = getNumberOfBorders(); for (int i = 0; i < numBorders; i++) { BrainModelBorder* b = getBorder(i); if (b->getDisplayFlag()) { b->orientLinksClockwise(bms); } } } else if (dynamic_cast(bm) != NULL) { volumeBorders.orientDisplayedBordersClockwise(); } } /** * Reverse the borders displayed on this surface. */ void BrainModelBorderSet::reverseDisplayedBorders(const BrainModel* bm) { if (dynamic_cast(bm) != NULL) { const int numBorders = getNumberOfBorders(); for (int i = 0; i < numBorders; i++) { BrainModelBorder* b = getBorder(i); if (b->getDisplayFlag()) { b->reverseLinks(); } } } else if (dynamic_cast(bm) != NULL) { volumeBorders.reverseDisplayedBorders(); } } /** * Compute the flat normals for all border. */ void BrainModelBorderSet::computeFlatNormals(const BrainModel* bm) { const BrainModelSurface* bms = dynamic_cast(bm); if (bms != NULL) { const int numBorders = getNumberOfBorders(); for (int i = 0; i < numBorders; i++) { getBorder(i)->computeFlatNormals(bms); } } else if (dynamic_cast(bm) != NULL) { volumeBorders.computeFlatNormals(); } } /** * interpolate two borders to create new borders (input borders will be resampled too). */ void BrainModelBorderSet::createInterpolatedBorders(const BrainModelSurface* bms, const int border1Index, const int border2Index, const QString& namePrefix, const int numberOfNewBorders, const float sampling, QString& errorMessageOut) { errorMessageOut = ""; const int numBorders = getNumberOfBorders(); if ((border1Index < 0) || (border1Index >= numBorders)) { errorMessageOut = "Border 1 index is invalid."; return; } if ((border2Index < 0) || (border2Index >= numBorders)) { errorMessageOut = "Border 2 index is invalid."; return; } if (bms == NULL) { errorMessageOut = "Surface is invalid."; return; } // // Get the input brain model borders // BrainModelBorder* brainModelBorder1 = getBorder(border1Index); BrainModelBorder* brainModelBorder2 = getBorder(border2Index); // // Convert to border file borders // Border* border1 = brainModelBorder1->copyToBorderFileBorder(bms); Border* border2 = brainModelBorder2->copyToBorderFileBorder(bms); std::vector newBorders; try { // // User border file to create interpolated borders // Border::createInterpolatedBorders(border1, border2, namePrefix, numberOfNewBorders, sampling, newBorders); // // Convert all back to brain model borders // BrainModelBorder b1(brainSet, border1, bms->getSurfaceType()); brainModelBorder1->initialize(brainSet); *brainModelBorder1 = b1; BrainModelBorder b2(brainSet, border2, bms->getSurfaceType()); brainModelBorder2->initialize(brainSet); *brainModelBorder2 = b2; for (unsigned int i = 0; i < newBorders.size(); i++) { BrainModelBorder* border = new BrainModelBorder(brainSet, newBorders[i], bms->getSurfaceType()); addBorder(border); } } catch (FileException& e) { errorMessageOut = e.whatQString(); } // // Clean up // delete border1; delete border2; for (unsigned int i = 0; i < newBorders.size(); i++) { delete newBorders[i]; } } /** * Resample displayed borders for the surface to the specified density. */ void BrainModelBorderSet::resampleDisplayedBorders(const BrainModel* bm, const float density) { const BrainModelSurface* bms = dynamic_cast(bm); if (bms != NULL) { const int numBorders = getNumberOfBorders(); for (int i = 0; i < numBorders; i++) { BrainModelBorder* border = getBorder(i); if (border->getDisplayFlag()) { int dummy = 0; border->resampleToDensity(bms, density, 2, dummy); } } } else if (dynamic_cast(bm) != NULL) { volumeBorders.resampleDisplayedBorders(density); } } /** * get indeces of borders with name. */ void BrainModelBorderSet::getAllBordersWithName(const QString& nameIn, std::vector& indicesOut) const { indicesOut.clear(); const int numBorders = getNumberOfBorders(); for (int i = 0; i < numBorders; i++) { if (getBorder(i)->getName() == nameIn) { indicesOut.push_back(i); } } } /** * copy a border. */ void BrainModelBorderSet::copyBorder(const int borderToCopyIndex, const QString& nameForCopiedBorder) { BrainModelBorder* b = new BrainModelBorder(*getBorder(borderToCopyIndex)); b->setName(nameForCopiedBorder); addBorder(b); } /** * get the unique names of all borders. */ void BrainModelBorderSet::getAllBorderNames(std::vector& names, const bool reverseOrderFlag) { std::set uniqueNames; const int numBorders = getNumberOfBorders(); for (int i = 0; i < numBorders; i++) { uniqueNames.insert(getBorder(i)->getName()); } const int numVolumeBorders = volumeBorders.getNumberOfBorders(); for (int i = 0; i < numVolumeBorders; i++) { uniqueNames.insert(volumeBorders.getBorder(i)->getName()); } names.clear(); names.insert(names.end(), uniqueNames.begin(), uniqueNames.end()); StringUtilities::sortCaseInsensitive(names, reverseOrderFlag, false); } /** * See if a surface's borders are modified. */ bool BrainModelBorderSet::getSurfaceBordersModified(const BrainModelSurface* bms) const { const int brainModelIndex = brainSet->getBrainModelIndex(bms); if (brainModelIndex < 0) { std::cout << "PROGRAM ERROR: Cannot find brain model at " << __LINE__ << " in " << __FILE__ << std::endl; return false; } const int numBorders = getNumberOfBorders(); for (int i = 0; i < numBorders; i++) { if (getBorder(i)->getModified(brainModelIndex)) { return true; } } return false; } /** * Set a surface's borders as modified. */ void BrainModelBorderSet::setSurfaceBordersModified(const BrainModelSurface* bms, const bool mod) { if (bms == NULL) { return; // must be a volume } const int brainModelIndex = brainSet->getBrainModelIndex(bms); if (brainModelIndex < 0) { std::cout << "PROGRAM ERROR: Cannot find brain model at " << __LINE__ << " in " << __FILE__ << std::endl; return; } const int numBorders = getNumberOfBorders(); for (int i = 0; i < numBorders; i++) { getBorder(i)->setModified(brainModelIndex, mod); } } /** * Set the modification status of all borders and the projections */ void BrainModelBorderSet::setAllBordersModifiedStatus(const bool mod) { const int num = brainSet->getNumberOfBrainModels(); for (int i = 0; i < num; i++) { const BrainModelSurface* bms = brainSet->getBrainModelSurface(i); setSurfaceBordersModified(bms, mod); } } /** * Set display flag for borders with specified name. */ void BrainModelBorderSet::setNameDisplayFlagForBordersWithName(const QString& name, const bool flag) { const int num = getNumberOfBorders(); for (int i = 0; i < num; i++) { BrainModelBorder* b = getBorder(i); if (b->getName() == name) { b->setNameDisplayFlag(flag); } } const int numVolumeBorders = volumeBorders.getNumberOfBorders(); for (int i = 0; i < numVolumeBorders; i++) { Border* b = volumeBorders.getBorder(i); if (b->getName() == name) { b->setNameDisplayFlag(flag); } } } /** * See if any projections are modified. */ bool BrainModelBorderSet::getProjectionsModified() const { const int numBorders = getNumberOfBorders(); for (int i = 0; i < numBorders; i++) { if (getBorder(i)->getProjectionModified()) { return true; } } return false; } /** * Set projections modified. */ void BrainModelBorderSet::setProjectionsModified(const bool mod) { const int numBorders = getNumberOfBorders(); for (int i = 0; i < numBorders; i++) { getBorder(i)->setProjectionModified(mod); } } /** * apply a transformation matrix to a brain model's borders. */ void BrainModelBorderSet::applyTransformationMatrix(const BrainModelSurface* bms, const TransformationMatrix& tm) { if (bms == NULL) { return; // must be a volume } const int brainModelIndex = brainSet->getBrainModelIndex(bms); if (brainModelIndex < 0) { std::cout << "PROGRAM ERROR: Cannot find brain model at " << __LINE__ << " in " << __FILE__ << std::endl; return; } const int numBorders = getNumberOfBorders(); for (int i = 0; i < numBorders; i++) { getBorder(i)->applyTransformationMatrix(brainModelIndex, tm); } } /** * copy the volume borders to the fiducial borders. */ void BrainModelBorderSet::copyVolumeBordersToFiducialBorders() { copyBordersFromBorderFile(&volumeBorders, BrainModelSurface::SURFACE_TYPE_FIDUCIAL); } /*************************************************************************************/ /** ** BrainModelBorderFileInfo methods **/ /*************************************************************************************/ /** * Get the comment. */ QString BrainModelBorderFileInfo::getFileComment() const { const QString headerTagComment("comment"); const std::map::const_iterator iter = fileHeader.find(headerTagComment); if (iter != fileHeader.end()) { return iter->second; } return ""; } /** * Set the comment. */ void BrainModelBorderFileInfo::setFileComment(const QString& comm) { fileHeader["comment"] = comm; } /** * Set the contents to a border file's values. */ void BrainModelBorderFileInfo::loadFromBorderFile(const AbstractFile& af) { fileName = af.getFileName(); fileTitle = af.getFileTitle(); fileHeader = af.getHeader(); pubMedID = af.getFilePubMedID(); } /** * Load the contents into a border file's values. */ void BrainModelBorderFileInfo::loadIntoBorderFile(AbstractFile& af) const { af.setFileName(fileName); af.setFileTitle(fileTitle); af.setHeader(fileHeader); af.setFilePubMedID(pubMedID); } /** * Clear the contents. */ void BrainModelBorderFileInfo::clear() { fileName = ""; fileTitle = ""; fileHeader.clear(); pubMedID = ""; } /*************************************************************************************/ /** ** BrainModelBorder methods **/ /*************************************************************************************/ /** * Constructor. */ BrainModelBorder::BrainModelBorder(BrainSet* bs, const QString& nameIn, const BORDER_TYPE typeIn, const BrainModelSurface::SURFACE_TYPES borderFileSurfaceTypeIn) { initialize(bs); name = nameIn; borderType = typeIn; borderFileSurfaceType = borderFileSurfaceTypeIn; } /** * Copy constructor. */ BrainModelBorder::BrainModelBorder(const BrainModelBorder& bmb) { brainSet = bmb.brainSet; borderType = bmb.borderType; borderFileSurfaceType = bmb.borderFileSurfaceType; name = bmb.name; samplingDensity = bmb.samplingDensity; variance = bmb.variance; topographyValue = bmb.topographyValue; arealUncertainty = bmb.arealUncertainty; borderFileColorIndex = bmb.borderFileColorIndex; areaColorFileIndex = bmb.areaColorFileIndex; brainModelValidity = bmb.brainModelValidity; brainModelModified = bmb.brainModelModified; projectionModified = bmb.projectionModified; borderLinks = bmb.borderLinks; displayFlag = bmb.displayFlag; highlightFlag = bmb.highlightFlag; nameDisplayFlag = bmb.nameDisplayFlag; for (int i = 0; i < getNumberOfBorderLinks(); i++) { BrainModelBorderLink* bmbl = getBorderLink(i); bmbl->setBrainModelBorder(this); } } /** * assignment */ void BrainModelBorder::operator=(const BrainModelBorder& bmb) { brainSet = bmb.brainSet; borderType = bmb.borderType; borderFileSurfaceType = bmb.borderFileSurfaceType; name = bmb.name; samplingDensity = bmb.samplingDensity; variance = bmb.variance; topographyValue = bmb.topographyValue; arealUncertainty = bmb.arealUncertainty; borderFileColorIndex = bmb.borderFileColorIndex; areaColorFileIndex = bmb.areaColorFileIndex; brainModelValidity = bmb.brainModelValidity; brainModelModified = bmb.brainModelModified; projectionModified = bmb.projectionModified; borderLinks = bmb.borderLinks; displayFlag = bmb.displayFlag; nameDisplayFlag = bmb.nameDisplayFlag; highlightFlag = bmb.highlightFlag; for (int i = 0; i < getNumberOfBorderLinks(); i++) { BrainModelBorderLink* bmbl = getBorderLink(i); bmbl->setBrainModelBorder(this); } } /** * Constructor for a border from a border projection file */ BrainModelBorder::BrainModelBorder(BrainSet* bs, BorderProjection* bp) { initialize(bs); float center[3]; bp->getData(name, center, samplingDensity, variance, topographyValue, arealUncertainty); borderType = BORDER_TYPE_PROJECTION; // // Determine which brain models this border is valid for // const int numBrainModels = brainSet->getNumberOfBrainModels(); for (int i = 0; i < numBrainModels; i++) { brainModelValidity[i] = false; const BrainModelSurface* bms = brainSet->getBrainModelSurface(i); if (bms != NULL) { brainModelValidity[i] = true; setModified(i, true); } } // // Copy the links for each brain model // const int numLinks = bp->getNumberOfLinks(); for (int j = 0; j < numLinks; j++) { BrainModelBorderLink bmbl(numBrainModels); const BorderProjectionLink* bpl = bp->getBorderProjectionLink(j); int section, vertices[3]; float areas[3]; float radius; bpl->getData(section, vertices, areas, radius); bmbl.setSection(section); bmbl.setRadius(radius); bmbl.setProjection(vertices, areas); addBorderLink(bmbl); } for (int i = 0; i < numBrainModels; i++) { const BrainModelSurface* bms = brainSet->getBrainModelSurface(i); if (bms != NULL) { unprojectLinks(bms); } } } /** * Constructor for a border from a border file. */ BrainModelBorder::BrainModelBorder(BrainSet* bs, const Border* b, const BrainModelSurface::SURFACE_TYPES surfaceTypeIn) { initialize(bs); name = b->getName(); borderType = BORDER_TYPE_NORMAL; borderFileSurfaceType = surfaceTypeIn; samplingDensity = b->getSamplingDensity(); variance = b->getVariance(); topographyValue = b->getTopographyValue(); arealUncertainty = b->getArealUncertainty(); // // Determine which brain models this border is valid for // const int numBrainModels = brainSet->getNumberOfBrainModels(); for (int i = 0; i < numBrainModels; i++) { brainModelValidity[i] = false; const BrainModelSurface* bms = brainSet->getBrainModelSurface(i); if (bms != NULL) { if (bms->getSurfaceType() == borderFileSurfaceType) { brainModelValidity[i] = true; setModified(i, true); } } } // // Copy the links for each brain model // const int numLinks = b->getNumberOfLinks(); for (int j = 0; j < numLinks; j++) { BrainModelBorderLink bmbl(numBrainModels); bmbl.setSection(b->getLinkSectionNumber(j)); bmbl.setRadius(b->getLinkRadius(j)); float xyz[3]; b->getLinkXYZ(j, xyz); bmbl.setLinkFilePosition(xyz); for (int i = 0; i < numBrainModels; i++) { bmbl.setLinkPosition(i, xyz); } addBorderLink(bmbl); } } /** * Constructor for a border from a border file. */ BrainModelBorder::BrainModelBorder(BrainSet* bs, const BrainModelSurface* bms, const Border* b) { initialize(bs); name = b->getName(); borderType = BORDER_TYPE_NORMAL; borderFileSurfaceType = bms->getSurfaceType(); samplingDensity = b->getSamplingDensity(); variance = b->getVariance(); topographyValue = b->getTopographyValue(); arealUncertainty = b->getArealUncertainty(); // // Determine which brain models this border is valid for // const int numBrainModels = brainSet->getNumberOfBrainModels(); for (int i = 0; i < numBrainModels; i++) { brainModelValidity[i] = false; if (bms == brainSet->getBrainModelSurface(i)) { brainModelValidity[i] = true; setModified(i, true); } } // // Copy the links for each brain model // const int numLinks = b->getNumberOfLinks(); for (int j = 0; j < numLinks; j++) { BrainModelBorderLink bmbl(numBrainModels); bmbl.setSection(b->getLinkSectionNumber(j)); float xyz[3]; b->getLinkXYZ(j, xyz); bmbl.setLinkFilePosition(xyz); for (int i = 0; i < numBrainModels; i++) { bmbl.setLinkPosition(i, xyz); } addBorderLink(bmbl); } } /** * Destructor. */ BrainModelBorder::~BrainModelBorder() { } /** * Add a border link to this border */ void BrainModelBorder::addBorderLink(const BrainModelBorderLink& bmbl) { borderLinks.push_back(bmbl); BrainModelBorderLink* link = getBorderLink(getNumberOfBorderLinks() - 1); link->setBrainModelBorder(this); } /** * Copy the border to a border file border (user should destroy returned Border*) */ Border* BrainModelBorder::copyToBorderFileBorder(const BrainModelSurface* bms) const { // // Create the border for the border file // const float center[3] = { 0.0, 0.0, 0.0 }; Border* border = new Border(getName(), center, getSamplingDensity(), getVariance(), getTopography(), getArealUncertainty()); const int brainModelIndex = brainSet->getBrainModelIndex(bms); if (brainModelIndex < 0) { std::cout << "PROGRAM ERROR: Cannot find brain model at " << __LINE__ << " in " << __FILE__ << std::endl; return border; } border->setBorderColorIndex(borderFileColorIndex); border->setDisplayFlag(displayFlag); if (getValidForBrainModel(brainModelIndex)) { // // Copy the links to the border file's border // const int numLinks = getNumberOfBorderLinks(); for (int j = 0; j < numLinks; j++) { const BrainModelBorderLink* link = getBorderLink(j); border->addBorderLink(link->getLinkPosition(brainModelIndex), link->getSection(), link->getRadius()); } } return border; } /** * Update the border for the addition of a new brain model. */ void BrainModelBorder::addBrainModel(const BrainModel* bm) { const BrainModelSurface* bms = dynamic_cast(bm); bool matchedSurfaceType = false; const CoordinateFile* cf = ((bms != NULL) ? bms->getCoordinateFile() : NULL); if (bms != NULL) { if (bms->getSurfaceType() == borderFileSurfaceType) { matchedSurfaceType = true; } } bool projectionFlag = false; switch (borderType) { case BORDER_TYPE_UNKNOWN: break; case BORDER_TYPE_NORMAL: break; case BORDER_TYPE_PROJECTION: if (bms != NULL) { projectionFlag = true; } break; } // // Border valid for this brain model // const bool valid = projectionFlag || matchedSurfaceType; brainModelValidity.push_back(valid); brainModelModified.push_back(false); // // Get the brain model index // const int brainModelIndex = brainSet->getBrainModelIndex(bm); if (brainModelIndex < 0) { std::cout << "PROGRAM ERROR: invalid brain model index at " << __LINE__ << " in " << __FILE__ << std::endl; return; } // // Set link position for this border // if (valid) { const int num = getNumberOfBorderLinks(); for (int i = 0; i < num; i++) { BrainModelBorderLink* bmbl = getBorderLink(i); float xyz[3]; bmbl->getLinkFilePosition(xyz); bmbl->addBrainModel(xyz); if (projectionFlag) { bmbl->unprojectLink(cf, brainModelIndex); } } } } /** * Update the border for the deletion of a brain model. */ void BrainModelBorder::deleteBrainModel(const BrainModel* bm) { // // Get the brain model index // const int brainModelIndex = brainSet->getBrainModelIndex(bm); if (brainModelIndex < 0) { std::cout << "PROGRAM ERROR: invalid brain model index at " << __LINE__ << " in " << __FILE__ << std::endl; return; } const int num = getNumberOfBorderLinks(); for (int i = 0; i < num; i++) { BrainModelBorderLink* bmbl = getBorderLink(i); bmbl->deleteBrainModel(brainModelIndex); } brainModelValidity.erase(brainModelValidity.begin() + brainModelIndex, brainModelValidity.begin() + brainModelIndex + 1); brainModelModified.erase(brainModelModified.begin() + brainModelIndex, brainModelModified.begin() + brainModelIndex + 1); } /** * Delete a border link */ void BrainModelBorder::deleteBorderLink(const int linkNumber) { if ((linkNumber >= 0) && (linkNumber < getNumberOfBorderLinks())) { borderLinks.erase(borderLinks.begin() + linkNumber, borderLinks.begin() + linkNumber + 1); } } /** * Initialize variables in a BrainModelBorder */ void BrainModelBorder::initialize(BrainSet* bs) { brainSet = bs; name = ""; samplingDensity = 0.0; variance = 0.0; topographyValue = 0.0; arealUncertainty = 0.0; borderType = BORDER_TYPE_UNKNOWN; borderFileSurfaceType = BrainModelSurface::SURFACE_TYPE_UNKNOWN; borderFileColorIndex = -1; areaColorFileIndex = -1; highlightFlag = false; const int numBrainModels = brainSet->getNumberOfBrainModels(); brainModelValidity.resize(numBrainModels); std::fill(brainModelValidity.begin(), brainModelValidity.end(), false); brainModelModified.resize(numBrainModels); std::fill(brainModelModified.begin(), brainModelModified.end(), false); projectionModified = false; displayFlag = true; nameDisplayFlag = true; } /** * Orient the links in the border clockwise assuming the borders are flat. */ void BrainModelBorder::orientLinksClockwise(const BrainModelSurface* bms) { const int brainModelIndex = brainSet->getBrainModelIndex(bms); if (brainModelIndex < 0) { std::cout << "PROGRAM ERROR: Cannot find brain model at " << __LINE__ << " in " << __FILE__ << std::endl; return; } // // Is this border valid for this surface // if (getValidForBrainModel(brainModelIndex) == false) { return; } // // Find the link with the minimum X value // float minX = std::numeric_limits::max(); int minIndexX = -1; const int numLinks = getNumberOfBorderLinks(); for (int i = 0; i < numLinks; i++) { const float* xyz = getBorderLink(i)->getLinkPosition(brainModelIndex); if (xyz[0] < minX) { minIndexX = i; minX = xyz[0]; } } if (minIndexX >= 0) { int iNext = minIndexX + 1; if (iNext >= numLinks) { iNext = 0; } const float* nextPos = getBorderLink(iNext)->getLinkPosition(brainModelIndex); const float* minPos = getBorderLink(minIndexX)->getLinkPosition(brainModelIndex); // // If next link is below the one with the minimum X then the border must be counter-clockwise // if (nextPos[1] < minPos[1]) { reverseLinks(); } } } /** * Reverse the links in the border. */ void BrainModelBorder::reverseLinks() { std::reverse(borderLinks.begin(), borderLinks.end()); } /** * Compute the flat normals for a border. */ void BrainModelBorder::computeFlatNormals(const BrainModelSurface* bms) { const int brainModelIndex = brainSet->getBrainModelIndex(bms); if (brainModelIndex < 0) { std::cout << "PROGRAM ERROR: Cannot find brain model at " << __LINE__ << " in " << __FILE__ << std::endl; return; } // // Is this border valid for this surface // if (getValidForBrainModel(brainModelIndex) == false) { return; } // // Loop through the links // const int numLinks = getNumberOfBorderLinks(); for (int i = 0; i < numLinks; i++) { int iNext = i + 1; if (iNext >= numLinks) iNext = 0; int iPrev = i - 1; if (iPrev < 0) iPrev = numLinks - 1; // // Calculate the normal // float vec[3]; MathUtilities::subtractVectors(getBorderLink(iNext)->getLinkPosition(brainModelIndex), getBorderLink(iPrev)->getLinkPosition(brainModelIndex), vec); MathUtilities::normalize(vec); const float normal[3] = { vec[1], -vec[0], 0.0 }; getBorderLink(i)->setFlatNormal(normal); } } /** * resample the border to the specified number of links. */ void BrainModelBorder::resampleToNumberOfLinks(const BrainModelSurface* bms, const int newNumberOfLinks) { if (getNumberOfBorderLinks() == newNumberOfLinks) { return; } const int brainModelIndex = brainSet->getBrainModelIndex(bms); if (brainModelIndex < 0) { std::cout << "PROGRAM ERROR: Cannot find brain model at " << __LINE__ << " in " << __FILE__ << std::endl; return; } // // Is this border valid for this surface // if (getValidForBrainModel(brainModelIndex) == false) { return; } Border* border = copyToBorderFileBorder(bms); if (border->getNumberOfLinks() > 0) { border->resampleBorderToNumberOfLinks(newNumberOfLinks); BrainModelBorder b(brainSet, border, bms->getSurfaceType()); const int numBefore = getNumberOfBorderLinks(); initialize(brainSet); *this = b; if (DebugControl::getDebugOn()) { std::cout << "Border named " << getName().toAscii().constData() << " has " << getNumberOfBorderLinks() << " after resampling. " << "Had " << numBefore << " links before." << std::endl; } } delete border; } /** * Resample the border to the specified density. */ void BrainModelBorder::resampleToDensity(const BrainModelSurface* bms, const float density, const int minimumNumberOfLinks, int& newNumberOfLinks) { const int brainModelIndex = brainSet->getBrainModelIndex(bms); if (brainModelIndex < 0) { std::cout << "PROGRAM ERROR: Cannot find brain model at " << __LINE__ << " in " << __FILE__ << std::endl; return; } // // Is this border valid for this surface // if (getValidForBrainModel(brainModelIndex) == false) { return; } Border* border = copyToBorderFileBorder(bms); if (border->getNumberOfLinks() > 0) { border->resampleBorderToDensity(density, minimumNumberOfLinks, newNumberOfLinks); BrainModelBorder b(brainSet, border, bms->getSurfaceType()); const int numBefore = getNumberOfBorderLinks(); initialize(brainSet); *this = b; if (DebugControl::getDebugOn()) { std::cout << "Border named " << getName().toAscii().constData() << " has " << getNumberOfBorderLinks() << " after resampling. " << "Had " << numBefore << " links before." << std::endl; } } delete border; } /** * Set the type of a border. */ void BrainModelBorder::setType(const BORDER_TYPE bt) { borderType = bt; } /** * Unproject the border links for a surface */ void BrainModelBorder::unprojectLinks(const BrainModelSurface* surface) { const int brainModelIndex = brainSet->getBrainModelIndex(surface); if (brainModelIndex < 0) { std::cout << "PROGRAM ERROR: Cannot find brain model at " << __LINE__ << " in " << __FILE__ << std::endl; return; } if (borderType != BORDER_TYPE_PROJECTION) { return; } const CoordinateFile* cf = surface->getCoordinateFile(); // // Border is valid for the surface // brainModelValidity[brainModelIndex] = true; const int num = getNumberOfBorderLinks(); for (int i = 0; i < num; i++) { BrainModelBorderLink* link = getBorderLink(i); link->unprojectLink(cf, brainModelIndex); /* int vertices[3]; float areas[3]; link->getProjection(vertices, areas); float xyz[3] = { 0.0, 0.0, 0.0 }; if (vertices[0] >= 0) { const float totalArea = areas[0] + areas[1] + areas[2]; if (totalArea > 0.0) { const float* v1 = cf->getCoordinate(vertices[0]); const float* v2 = cf->getCoordinate(vertices[1]); const float* v3 = cf->getCoordinate(vertices[2]); xyz[0] = (v1[0] * areas[1] + v2[0] * areas[2] + v3[0] * areas[0]) / totalArea; xyz[1] = (v1[1] * areas[1] + v2[1] * areas[2] + v3[1] * areas[0]) / totalArea; xyz[2] = (v1[2] * areas[1] + v2[2] * areas[2] + v3[2] * areas[0]) / totalArea; } else { cf->getCoordinate(vertices[0], xyz); } } link->setLinkPosition(brainModelIndex, xyz); */ } } /** * set the name of the border. */ void BrainModelBorder::setName(const QString& s) { name = s; } /** * set the sampling density. */ void BrainModelBorder::setSamplingDensity(const float density) { samplingDensity = density; } /** * set the variance. */ void BrainModelBorder::setVariance(const float var) { variance = var; } /** * set the topography value. */ void BrainModelBorder::setTopography(const float topography) { topographyValue = topography; } /** * set the areal uncertainty. */ void BrainModelBorder::setArealUncertainty(const float uncertainty) { arealUncertainty = uncertainty; } /** * get the border valid for a brain model. */ bool BrainModelBorder::getValidForBrainModel(const int brainModelIndex) const { if (brainModelIndex < static_cast(brainModelValidity.size())) { return brainModelValidity[brainModelIndex]; } return false; } /** * get a border link. */ BrainModelBorderLink* BrainModelBorder::getBorderLink(const int index) { if (index < getNumberOfBorderLinks()) { return &borderLinks[index]; } return NULL; } /** * get a border link (const method). */ const BrainModelBorderLink* BrainModelBorder::getBorderLink(const int index) const { if (index < getNumberOfBorderLinks()) { return &borderLinks[index]; } return NULL; } /** * Determine the bounds of a border for a surface. */ void BrainModelBorder::getBounds(const BrainModelSurface* bms, double bounds[6]) const { float floatBounds[6]; getBounds(bms, floatBounds); bounds[0] = floatBounds[0]; bounds[1] = floatBounds[1]; bounds[2] = floatBounds[2]; bounds[3] = floatBounds[3]; bounds[4] = floatBounds[4]; bounds[5] = floatBounds[5]; } /** * Determine the bounds of a border for a surface. */ void BrainModelBorder::getBounds(const BrainModelSurface* bms, float bounds[6]) const { const int brainModelIndex = brainSet->getBrainModelIndex(bms); if (brainModelIndex < 0) { std::cout << "PROGRAM ERROR: Cannot find brain model at " << __LINE__ << " in " << __FILE__ << std::endl; return; } bounds[0] = std::numeric_limits::max(); bounds[1] = -std::numeric_limits::max(); bounds[2] = std::numeric_limits::max(); bounds[3] = -std::numeric_limits::max(); bounds[4] = std::numeric_limits::max(); bounds[5] = -std::numeric_limits::max(); // // Is this border valid for this surface // if (getValidForBrainModel(brainModelIndex) == false) { return; } const int numLinks = getNumberOfBorderLinks(); for (int i = 0; i < numLinks; i++) { const float* pos = getBorderLink(i)->getLinkPosition(brainModelIndex); bounds[0] = std::min(bounds[0], pos[0]); bounds[1] = std::max(bounds[1], pos[0]); bounds[2] = std::min(bounds[2], pos[1]); bounds[3] = std::max(bounds[3], pos[1]); bounds[4] = std::min(bounds[4], pos[2]); bounds[5] = std::max(bounds[5], pos[2]); } } /** * Determine if points are inside this border. * The border is assumed to be flat, in the X-Y plane. */ void BrainModelBorder::pointsInsideBorder(const BrainModelSurface* bms, const float* points, const int numPoints, std::vector& insideFlags, const bool checkNonNegativeZPointsOnly) const { if (static_cast(insideFlags.size()) < numPoints) { insideFlags.resize(numPoints); } std::fill(insideFlags.begin(), insideFlags.end(), false); const int brainModelIndex = brainSet->getBrainModelIndex(bms); if (brainModelIndex < 0) { std::cout << "PROGRAM ERROR: Cannot find brain model at " << __LINE__ << " in " << __FILE__ << std::endl; return; } // // Is this border valid for this surface // if (getValidForBrainModel(brainModelIndex) == false) { return; } // // Since the coordinates are typically less than 100, this can cause // problems with the point in polygon algorithm (it will report a // degenerate polygon). Scaling all coordinates elminates this problem. // Using every other point in the border also helps. // const float scaleFactor = 1000.0; const int numLinks = getNumberOfBorderLinks(); #ifdef HAVE_VTK5 std::vector polygon; #else // HAVE_VTK5 std::vector polygon; #endif // HAVE_VTK5 int numToSkip = 1; int numInPolygon = 0; for (int i = 0; i < (numLinks - 1); i++) { const float* pos = getBorderLink(i)->getLinkPosition(brainModelIndex); polygon.push_back(pos[0] * scaleFactor); polygon.push_back(pos[1] * scaleFactor); polygon.push_back(pos[2] * scaleFactor); numInPolygon++; i += numToSkip; } if (numInPolygon < 3) { return; } #ifdef HAVE_VTK5 double normal[3] = { 0.0, 0.0, 1.0 }; double bounds[6]; #else // HAVE_VTK5 float normal[3] = { 0.0, 0.0, 1.0 }; float bounds[6]; #endif // HAVE_VTK5 getBounds(bms, bounds); bounds[0] *= scaleFactor; bounds[1] *= scaleFactor; bounds[2] *= scaleFactor; bounds[3] *= scaleFactor; bounds[4] = -1.0; bounds[5] = 1.0; for (int i = 0; i < numPoints; i++) { #ifdef HAVE_VTK5 double xyz[3]; #else // HAVE_VTK5 float xyz[3]; #endif // HAVE_VTK5 xyz[0] = points[i*3] * scaleFactor; xyz[1] = points[i*3+1] * scaleFactor; xyz[2] = points[i*3+2] * scaleFactor; int result = 0; bool checkIt = true; if (checkNonNegativeZPointsOnly) { if (xyz[2] < 0.0) { checkIt = false; } } if (checkIt) { #ifdef HAVE_VTK5 result = MathUtilities::pointInPolygon(xyz, numInPolygon, (double*)&polygon[0], bounds, normal); #else // HAVE_VTK5 result = MathUtilities::pointInPolygon(xyz, numInPolygon, (float*)&polygon[0], bounds, normal); #endif // HAVE_VTK5 } if (result > 0) { insideFlags[i] = true; } else if (result < 0) { std::cerr << "Border polygon passed to MathUtilities::pointInPolygon " " is degenerate." << std::endl; std::cerr << "Polygon: " << std::endl; for (int j = 0; j < numInPolygon; j++) { std::cerr << " " << j << " " << polygon[j*3] << " " << polygon[j*3+1] << " " << polygon[j*3+2] << std::endl; } break; } } } /** * set this brain model's link as modified. */ void BrainModelBorder::setModified(const int brainModelIndex, const bool mod) { brainModelModified[brainModelIndex] = mod; } /** * Set this projection as modified. */ void BrainModelBorder::setProjectionModified(const bool mod) { projectionModified = mod; } /** * get this brain model's link as modified. */ bool BrainModelBorder::getModified(const int brainModelIndex) const { // // Is this border valid for this surface // if (getValidForBrainModel(brainModelIndex) == false) { return false; } return brainModelModified[brainModelIndex]; } /** * get the link nearest the coordinate (returns -1 if found). */ int BrainModelBorder::getLinkNearestCoordinate(const int brainModelIndex, const float xyz[3]) const { int nearestLinkNumber = -1; float maxDist = std::numeric_limits::max(); const int numLinks = getNumberOfBorderLinks(); for (int j = 0; j < numLinks; j++) { const BrainModelBorderLink* bmbl = getBorderLink(j); const float* pos = bmbl->getLinkPosition(brainModelIndex); if (pos != NULL) { const float dist = MathUtilities::distanceSquared3D(pos, xyz); if (dist < maxDist) { nearestLinkNumber = j; maxDist = dist; } } } return nearestLinkNumber; } /** * apply a transformation matrix to a brain model's borders. */ void BrainModelBorder::applyTransformationMatrix(const int brainModelIndex, const TransformationMatrix& tm) { if (getValidForBrainModel(brainModelIndex)) { const int numLinks = getNumberOfBorderLinks(); for (int i = 0; i < numLinks; i++) { BrainModelBorderLink* bmbl = getBorderLink(i); bmbl->applyTransformationMatrix(brainModelIndex, tm); } } } /*************************************************************************************/ /** ** BrainModelBorderLink methods **/ /*************************************************************************************/ /** * Constructor. */ BrainModelBorderLink::BrainModelBorderLink(const int numBrainModels) { areas[0] = 0.0; areas[1] = 0.0; areas[2] = 0.0; section = 0; radius = 0.0; vertices[0] = -1; vertices[1] = -1; vertices[2] = -1; flatNormal[0] = 0.0; flatNormal[1] = 1.0; flatNormal[2] = 0.0; fileXYZ[0] = 0.0; fileXYZ[1] = 0.0; fileXYZ[2] = 0.0; for (int i = 0; i < numBrainModels; i++) { xyz.push_back(0.0); xyz.push_back(0.0); xyz.push_back(0.0); } brainModelBorder = NULL; } /** * Copy Constructor */ BrainModelBorderLink::BrainModelBorderLink(const BrainModelBorderLink& bmbl) { section = bmbl.section; radius = bmbl.radius; vertices[0] = bmbl.vertices[0]; vertices[1] = bmbl.vertices[1]; vertices[2] = bmbl.vertices[2]; areas[0] = bmbl.areas[0]; areas[1] = bmbl.areas[1]; areas[2] = bmbl.areas[2]; fileXYZ[0] = bmbl.fileXYZ[0]; fileXYZ[1] = bmbl.fileXYZ[1]; fileXYZ[2] = bmbl.fileXYZ[2]; xyz = bmbl.xyz; flatNormal[0] = bmbl.flatNormal[0]; flatNormal[1] = bmbl.flatNormal[1]; flatNormal[2] = bmbl.flatNormal[2]; brainModelBorder = NULL; } /** * Destructor. */ BrainModelBorderLink::~BrainModelBorderLink() { } /** * Add a brain model */ void BrainModelBorderLink::addBrainModel(const float xyzIn[3]) { xyz.push_back(xyzIn[0]); xyz.push_back(xyzIn[1]); xyz.push_back(xyzIn[2]); } /** * Set the section number. */ void BrainModelBorderLink::setSection(const int secNum) { section = secNum; } /** * Set the radius. */ void BrainModelBorderLink::setRadius(const float radiusIn) { radius = radiusIn; } /** * get the projection information. */ void BrainModelBorderLink::getProjection(int verticesOut[3], float areasOut[3]) const { verticesOut[0] = vertices[0]; verticesOut[1] = vertices[1]; verticesOut[2] = vertices[2]; areasOut[0] = areas[0]; areasOut[1] = areas[1]; areasOut[2] = areas[2]; } /** * get the projection information. */ void BrainModelBorderLink::setProjection(const int verticesIn[3], const float areasIn[3]) { vertices[0] = verticesIn[0]; vertices[1] = verticesIn[1]; vertices[2] = verticesIn[2]; areas[0] = areasIn[0]; areas[1] = areasIn[1]; areas[2] = areasIn[2]; setProjectionModified(); } /** * get the link position for a brain model. */ const float* BrainModelBorderLink::getLinkPosition(const int brainModelIndex) const { static const float zeros[3] = { 0.0, 0.0, 0.0 }; const int index = brainModelIndex * 3; if (index < static_cast(xyz.size())) { return &xyz[index]; } return zeros; } /** * get the link position for a brain model (const method) */ void BrainModelBorderLink::getLinkPosition(const int brainModelIndex, float xyzOut[3]) const { const int index = brainModelIndex * 3; if (index < static_cast(xyz.size())) { xyzOut[0] = xyz[index]; xyzOut[1] = xyz[index+1]; xyzOut[2] = xyz[index+2]; return; } std::cout << "PROGRAM ERROR: Invalid index in BrainModelBorderLink::getLinkPosition" << std::endl; xyzOut[0] = 0.0; xyzOut[1] = 0.0; xyzOut[2] = 0.0; } /** * Set the link position for a brain model. */ void BrainModelBorderLink::setLinkPosition(const int brainModelIndex, const float xyzIn[3]) { const int index = brainModelIndex * 3; if (index < static_cast(xyz.size())) { xyz[index] = xyzIn[0]; xyz[index+1] = xyzIn[1]; xyz[index+2] = xyzIn[2]; setModified(brainModelIndex); } else { std::cout << "PROGRAM ERROR: Invalid index in BrainModelBorderLink::setLinkPosition" << std::endl; } } /** * apply a transformation matrix to a brain model's borders. */ void BrainModelBorderLink::applyTransformationMatrix(const int brainModelIndex, const TransformationMatrix& tm) { float xyz[3]; getLinkPosition(brainModelIndex, xyz); tm.multiplyPoint(xyz); setLinkPosition(brainModelIndex, xyz); } /** * get the link position from the border file. */ void BrainModelBorderLink::getLinkFilePosition(float xyzOut[3]) const { xyzOut[0] = fileXYZ[0]; xyzOut[1] = fileXYZ[1]; xyzOut[2] = fileXYZ[2]; } /** * set the link position from the border file. */ void BrainModelBorderLink::setLinkFilePosition(const float xyzIn[3]) { fileXYZ[0] = xyzIn[0]; fileXYZ[1] = xyzIn[1]; fileXYZ[2] = xyzIn[2]; } /** * Delete a brain model from the links. */ void BrainModelBorderLink::deleteBrainModel(const int brainModelIndex) { const int index = brainModelIndex * 3; if (index < static_cast(xyz.size())) { xyz.erase(xyz.begin() + index, xyz.begin() + index + 3); } else { std::cout << "PROGRAM ERROR: Invalid index in BrainModelBorderLink::deleteBrainModel" << std::endl; } } /** * Set the BrainModelBorder this link is part of. */ void BrainModelBorderLink::setBrainModelBorder(BrainModelBorder* bmb) { brainModelBorder = bmb; } /** * Unproject a border link. */ void BrainModelBorderLink::unprojectLink(const CoordinateFile* cf, const int brainModelIndex) { float xyz[3] = { 0.0, 0.0, 0.0 }; if (vertices[0] >= 0) { const float totalArea = areas[0] + areas[1] + areas[2]; if (totalArea > 0.0) { const float* v1 = cf->getCoordinate(vertices[0]); const float* v2 = cf->getCoordinate(vertices[1]); const float* v3 = cf->getCoordinate(vertices[2]); xyz[0] = (v1[0] * areas[1] + v2[0] * areas[2] + v3[0] * areas[0]) / totalArea; xyz[1] = (v1[1] * areas[1] + v2[1] * areas[2] + v3[1] * areas[0]) / totalArea; xyz[2] = (v1[2] * areas[1] + v2[2] * areas[2] + v3[2] * areas[0]) / totalArea; } else { cf->getCoordinate(vertices[0], xyz); } } setLinkPosition(brainModelIndex, xyz); setModified(brainModelIndex); } /** * set the flat normal. */ void BrainModelBorderLink::setFlatNormal(const float normal[3]) { flatNormal[0] = normal[0]; flatNormal[1] = normal[1]; flatNormal[2] = normal[2]; } /** * Set the border holding this link as modified */ void BrainModelBorderLink::setModified(const int brainModelIndex) { if (brainModelBorder != NULL) { brainModelBorder->setModified(brainModelIndex, true); } } /** * Set the border holding this projection as modified */ void BrainModelBorderLink::setProjectionModified() { if (brainModelBorder != NULL) { brainModelBorder->setProjectionModified(true); } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelAlgorithmRunAsThread.h0000664000175000017500000000472311572067322026050 0ustar michaelmichael #ifndef __BRAIN_MODEL_ALGORITHM_RUN_AS_THREAD_H__ #define __BRAIN_MODEL_ALGORITHM_RUN_AS_THREAD_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include class BrainModelAlgorithm; /// class that runs a brain model algorithm in a thread class BrainModelAlgorithmRunAsThread : public QThread { public: // constructor BrainModelAlgorithmRunAsThread(BrainModelAlgorithm* algorithmToRunIn, const bool deleteBrainModelAlgorithmInDestructorFlagIn); // destructor ~BrainModelAlgorithmRunAsThread(); // call after thread finishes to see if an exception occurred during algorithm execution bool getAlgorithmThrewAnException() const { return exceptionThrownFlag; } // get the exception error message QString getExceptionErrorMessage() const { return exceptionMessage; } // get the algorithm BrainModelAlgorithm* getBrainModelAlgorithm() { return algorithmToRun; } // get the algorithm (const method) const BrainModelAlgorithm* getBrainModelAlgorithm() const { return algorithmToRun; } protected: /// runs the algorithm void run(); /// the algorithm that is to be run in a thread BrainModelAlgorithm* algorithmToRun; /// will get set if algorithm throws an exception bool exceptionThrownFlag; /// will get set if algorithm throws an exception QString exceptionMessage; /// delete the brain model algorithm in the destructor bool deleteBrainModelAlgorithmInDestructorFlag; }; #endif // __BRAIN_MODEL_ALGORITHM_RUN_AS_THREAD_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelAlgorithmRunAsThread.cxx0000664000175000017500000000373611572067322026426 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelAlgorithm.h" #include "BrainModelAlgorithmRunAsThread.h" /** * constructor. */ BrainModelAlgorithmRunAsThread::BrainModelAlgorithmRunAsThread(BrainModelAlgorithm* algorithmToRunIn, const bool deleteBrainModelAlgorithmInDestructorFlagIn) { algorithmToRun = algorithmToRunIn; deleteBrainModelAlgorithmInDestructorFlag = deleteBrainModelAlgorithmInDestructorFlagIn; exceptionThrownFlag = false; exceptionMessage = ""; } /** * destructor. */ BrainModelAlgorithmRunAsThread::~BrainModelAlgorithmRunAsThread() { if (deleteBrainModelAlgorithmInDestructorFlag) { delete algorithmToRun; algorithmToRun = NULL; } } /** * runs the algorithm. */ void BrainModelAlgorithmRunAsThread::run() { if (algorithmToRun == NULL) { exceptionThrownFlag = true; exceptionMessage = "PROGRAM ERROR: Thread passed to constructor was NULL"; return; } try { algorithmToRun->execute(); } catch (BrainModelAlgorithmException& e) { exceptionThrownFlag = true; exceptionMessage = e.whatQString(); } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelAlgorithmMultiThreaded.h0000664000175000017500000001060211572067322026414 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __BRAIN_MODEL_ALGORITHM_MULTI_THREADED_H__ #define __BRAIN_MODEL_ALGORITHM_MULTI_THREADED_H__ #include #include #include "BrainModelAlgorithm.h" /// Abstract class for multi-threaded algorithms that work on brain models class BrainModelAlgorithmMultiThreaded : public BrainModelAlgorithm, protected QThread { public: /// get the number of thread to run int getNumberOfThreadsToRun() const { return numberOfThreadsToRun; } /// set the number of thread to run void setNumberOfThreadsToRun(const int num) { numberOfThreadsToRun = num; } /// destructor virtual ~BrainModelAlgorithmMultiThreaded(); /// Increment the number of children threads that have started their iterations void incrementNumChildThreadStarted(); /// Increment the number of children thread that are done with their iteration. void incrementNumChildThreadDone(); protected: // // initialize // /// constructor BrainModelAlgorithmMultiThreaded(BrainSet* bs, BrainModelAlgorithmMultiThreaded* parentOfThisThreadIn, int threadNumberIn, const bool iAmAThread); /// get the parent of this thread BrainModelAlgorithmMultiThreaded* getParentOfThisThread() { return parentOfThisThread; } /// get the thread keep looping flag bool getThreadKeepLoopingFlag() const { return threadKeepLoopingFlag; } /// set the thread keep looping flag void setThreadKeepLoopingFlag(const bool flag) { threadKeepLoopingFlag = flag; } /// get the number of this thread int getThreadNumber() const { return threadNumber; } /// Get the number of children threads that have started int getNumChildThreadStarted(); /// Reset the number of children thread done (set it to zero). void resetNumChildThreadDone(); /// Get the number of children thread that are done with their iteration. int getNumChildThreadDone(); /// Get the threaded iteration done flag bool getThreadedIterationDoneFlag(); /// Set the threaded iteration done flag void setThreadedIterationDoneFlag(const bool flag); /// see if i'm a thread instance bool getImAThread() const { return threadFlag; } private: /// number of threads to run int numberOfThreadsToRun; /// thread flag (set if this instance is run as a thread) bool threadFlag; /// mutex for accessing number of children thread started QMutex mutexNumChildThreadStarted; /// number of children threads started int numChildThreadStarted; /// number of children thread done int numChildThreadDone; /// mutex for accessing number of children thread done QMutex mutexNumChildThreadDone; /// threaded iteration done flag bool threadedIterationDoneFlag; /// mutex for accessing the threaded iteration done flag QMutex mutexThreadedIterationDoneFlag; /// number of this thread int threadNumber; /// used to remain in run() when running as a thread bool threadKeepLoopingFlag; /// parent of this thread BrainModelAlgorithmMultiThreaded* parentOfThisThread; }; #endif // __BRAIN_MODEL_ALGORITHM_MULTI_THREADED_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelAlgorithmMultiThreaded.cxx0000664000175000017500000000761611572067322027002 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelAlgorithmMultiThreaded.h" #include "BrainSet.h" #include "PreferencesFile.h" /** * Constructor. */ BrainModelAlgorithmMultiThreaded::BrainModelAlgorithmMultiThreaded(BrainSet* bs, BrainModelAlgorithmMultiThreaded* parentOfThisThreadIn, int threadNumberIn, const bool iAmAThread) : BrainModelAlgorithm(bs) { parentOfThisThread = parentOfThisThreadIn; threadNumber = threadNumberIn; threadFlag = iAmAThread; threadKeepLoopingFlag = false; numberOfThreadsToRun = 1; // // Get number of threads from preferences file // if (bs != NULL) { PreferencesFile* pf = bs->getPreferencesFile(); numberOfThreadsToRun = pf->getMaximumNumberOfThreads(); } numChildThreadStarted = 0; if (numberOfThreadsToRun > 1) { mutexNumChildThreadStarted.unlock(); } resetNumChildThreadDone(); if (numberOfThreadsToRun > 1) { mutexNumChildThreadDone.unlock(); } threadedIterationDoneFlag = false; if (numberOfThreadsToRun > 1) { mutexThreadedIterationDoneFlag.unlock(); } } /** * Destructor. */ BrainModelAlgorithmMultiThreaded::~BrainModelAlgorithmMultiThreaded() { } /** * Get the number of children thread that have started. */ int BrainModelAlgorithmMultiThreaded::getNumChildThreadStarted() { mutexNumChildThreadStarted.lock(); const int num = numChildThreadStarted; mutexNumChildThreadStarted.unlock(); return num; } /** * Increment number of children thread that have started. */ void BrainModelAlgorithmMultiThreaded::incrementNumChildThreadStarted() { mutexNumChildThreadStarted.lock(); numChildThreadStarted++; mutexNumChildThreadStarted.unlock(); } /** * Reset the number of children thread done (set it to zero). */ void BrainModelAlgorithmMultiThreaded::resetNumChildThreadDone() { numChildThreadDone = 0; } /** * Get the number of children thread that are done with their iteration. */ int BrainModelAlgorithmMultiThreaded::getNumChildThreadDone() { mutexNumChildThreadDone.lock(); const int num = numChildThreadDone; mutexNumChildThreadDone.unlock(); return num; } /** * Increment number of children thread that are done with their iteration. */ void BrainModelAlgorithmMultiThreaded::incrementNumChildThreadDone() { mutexNumChildThreadDone.lock(); numChildThreadDone++; mutexNumChildThreadDone.unlock(); } /** * Get the threaded iteration done flag */ bool BrainModelAlgorithmMultiThreaded::getThreadedIterationDoneFlag() { mutexThreadedIterationDoneFlag.lock(); const bool flag = threadedIterationDoneFlag; mutexThreadedIterationDoneFlag.unlock(); return flag; } /** * Set the threaded iteration done flag */ void BrainModelAlgorithmMultiThreaded::setThreadedIterationDoneFlag(const bool flag) { mutexThreadedIterationDoneFlag.lock(); threadedIterationDoneFlag = flag; mutexThreadedIterationDoneFlag.unlock(); } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelAlgorithmMultiThreadExecutor.h0000664000175000017500000000451611572067322027631 0ustar michaelmichael #ifndef __BRAIN_MODEL_ALGORITHM_MULTI_THREAD_EXECUTOR_H__ #define __BRAIN_MODEL_ALGORITHM_MULTI_THREAD_EXECUTOR_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include class BrainModelAlgorithm; /// class for executing brain model algorithms in parallel class BrainModelAlgorithmMultiThreadExecutor : public QObject { Q_OBJECT public: // constructor BrainModelAlgorithmMultiThreadExecutor(std::vector algorithmsIn, const int numberOfThreadsToRunIn, const bool stopIfAlogorithmThrowsExceptionIn); // destructor BrainModelAlgorithmMultiThreadExecutor(); // start executing the threads void startExecution(); // get any exeception messages void getExceptionMessages(std::vector& exceptionMessagesOut) const; signals: // emits algorithm description (if non-blank) when algorithm starts void algorithmStartedDescription(const QString&); protected: // the algorithms std::vector algorithms; // number of simultaneous threads int numberOfThreadsToRun; // stop executing if an algorithms throws an exception bool stopIfAlogorithmThrowsException; // exeception messages std::vector exceptionMessages; }; #endif // __BRAIN_MODEL_ALGORITHM_MULTI_THREAD_EXECUTOR_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelAlgorithmMultiThreadExecutor.cxx0000664000175000017500000001262211572067322030201 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelAlgorithm.h" #include "BrainModelAlgorithmMultiThreadExecutor.h" #include "BrainModelAlgorithmRunAsThread.h" /** * constructor. */ BrainModelAlgorithmMultiThreadExecutor::BrainModelAlgorithmMultiThreadExecutor( std::vector algorithmsIn, const int numberOfThreadsToRunIn, const bool stopIfAlogorithmThrowsExceptionIn) { algorithms = algorithmsIn; numberOfThreadsToRun = numberOfThreadsToRunIn; if (numberOfThreadsToRun < 1) { numberOfThreadsToRun = 1; } stopIfAlogorithmThrowsException = stopIfAlogorithmThrowsExceptionIn; } /** * destructor. */ BrainModelAlgorithmMultiThreadExecutor::BrainModelAlgorithmMultiThreadExecutor() { } /** * start executing the threads. */ void BrainModelAlgorithmMultiThreadExecutor::startExecution() { // // Count of algorithms // const int numAlgorithmsToRun = static_cast(algorithms.size()); if (numAlgorithmsToRun <= 0) { return; } int nextAlgorithmToRun = 0; // // Pointers for algorithm threads // std::vector algorithmThreads(numberOfThreadsToRun); for (int i = 0; i < numberOfThreadsToRun; i++) { algorithmThreads[i] = NULL; } // // Time to wait for a thread // const unsigned long threadWaitTimeInMilliseconds = 5; // // Loop for creating and executing threads // bool done = false; while (done == false) { // // Loop through threads to see if any are done and create new threads // for (int iThread = 0; iThread < numberOfThreadsToRun; iThread++) { // // Is thread valid ? // if (algorithmThreads[iThread] != NULL) { // // Wait on the thread // algorithmThreads[iThread]->wait(threadWaitTimeInMilliseconds); // // Is thread finished ? // if (algorithmThreads[iThread]->isFinished()) { // // Get any error message // if (algorithmThreads[iThread]->getAlgorithmThrewAnException()) { exceptionMessages.push_back(algorithmThreads[iThread]->getExceptionErrorMessage()); // // Should execution stop ? // if (stopIfAlogorithmThrowsException) { nextAlgorithmToRun = numAlgorithmsToRun; } } // // delete the thread (does not delete the algorithm) // delete algorithmThreads[iThread]; algorithmThreads[iThread] = NULL; } } // // Is thread available // if (algorithmThreads[iThread] == NULL) { // // Are there algorithms that still need to run ? // if (nextAlgorithmToRun < numAlgorithmsToRun) { // // Create the new thread and start it // algorithmThreads[iThread] = new BrainModelAlgorithmRunAsThread(algorithms[nextAlgorithmToRun], false); algorithmThreads[iThread]->start(QThread::HighestPriority); // // Inform caller of algorithm description // const QString s = algorithms[nextAlgorithmToRun]->getTextDescription(); if (s.isEmpty() == false) { emit algorithmStartedDescription(s); } // // Increment to next algorithm // nextAlgorithmToRun++; } } } // for (iThread // // Loop through the threads to see if any are still valid and if time to stop // done = true; for (int iThread = 0; iThread < numberOfThreadsToRun; iThread++) { if (algorithmThreads[iThread] != NULL) { done = false; } } // // Allow other events to process // QApplication::processEvents(); } // while (done == false) } /** * get any exeception messages. */ void BrainModelAlgorithmMultiThreadExecutor::getExceptionMessages(std::vector& exceptionMessagesOut) const { exceptionMessagesOut = exceptionMessages; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelAlgorithmException.h0000664000175000017500000000365511572067322025631 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_BRAIN_MODEL_ALGORITHM_EXCEPTION_H__ #define __VE_BRAIN_MODEL_ALGORITHM_EXCEPTION_H__ #include #include class FileException; class StatisticException; /// Class for exceptions thrown by algorithms that operate on BrainModels class BrainModelAlgorithmException : public std::exception { public: /// Constructor BrainModelAlgorithmException(const QString& msg); /// Constructor BrainModelAlgorithmException(const FileException& fioe); /// Constructor BrainModelAlgorithmException(const StatisticException& fioe); /// Destructor virtual ~BrainModelAlgorithmException() throw(); /// get description of exception virtual QString whatQString() const throw(); protected: /// Description of the exception QString description; private: /// get description of exception (private to prevent its use) virtual const char* what() const throw() { return ""; } }; #endif // __VE_BRAIN_MODEL_ALGORITHM_EXCEPTION_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelAlgorithmException.cxx0000664000175000017500000000354311572067322026200 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelAlgorithmException.h" #include "FileException.h" #include "StatisticException.h" #include "StringUtilities.h" /** * Constructor. */ BrainModelAlgorithmException::BrainModelAlgorithmException(const QString& msg) { description = msg; } /** * Constructor. */ BrainModelAlgorithmException::BrainModelAlgorithmException(const FileException& fe) { description = fe.whatQString(); } /** * Constructor. */ BrainModelAlgorithmException::BrainModelAlgorithmException(const StatisticException& se) { description = StringUtilities::fromStdString(se.whatStdString()); } /** * Destructor. */ BrainModelAlgorithmException::~BrainModelAlgorithmException() throw() { } /** * get description of exception. */ /* const char* BrainModelAlgorithmException::what() const throw() { return description.toAscii().constData(); } */ /** * get description of exception. */ QString BrainModelAlgorithmException::whatQString() const throw() { return description; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelAlgorithm.h0000664000175000017500000000574411572067322023753 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_BRAIN_MODEL_ALGORITHM_H__ #define __VE_BRAIN_MODEL_ALGORITHM_H__ #include #include "BrainModelAlgorithmException.h" class QProgressDialog; class BrainSet; class QString; /// Abstract class for algorithms that operate on brain models class BrainModelAlgorithm : public QObject { Q_OBJECT public: /// execute the algorithm virtual void execute() throw (BrainModelAlgorithmException) = 0; /// Destructor virtual ~BrainModelAlgorithm(); /// get warnings from execution QString getWarningMessages() const { return warningMessages; } /// get a text description of algorithm virtual QString getTextDescription() const; signals: /// signal emitted to indicate progress void signalProgressUpdate(const QString& text, const int progressNumber, const int totalNumberOfSteps); protected: /// Constructor BrainModelAlgorithm(BrainSet* bs); /// Create the progress dialog. void createProgressDialog(const QString& title, const int totalNumberOfSteps, const QString& dialogName); /// Update the progress dialog. Throws exception if cancel button pressed by user. void updateProgressDialog(const QString& text, const int progressNumber = -1, const int totalNumberOfSteps = -1) throw (BrainModelAlgorithmException); /// Remove and delete the progress dialog. void removeProgressDialog(); /// add to warning messages (newline automatically added after message) void addToWarningMessages(const QString& msg); /// allow GUI events to process void allowEventsToProcess(); /// the brain set BrainSet* brainSet; /// the progress dialog QProgressDialog* progressDialog; /// warnings encountered during algorithm execution QString warningMessages; }; #endif // __VE_BRAIN_MODEL_ALGORITHM_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModelAlgorithm.cxx0000664000175000017500000001072111572067322024315 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include "BrainModelAlgorithm.h" #include "BrainSet.h" /** * Constructor. */ BrainModelAlgorithm::BrainModelAlgorithm(BrainSet* bs) : QObject(0) { brainSet = bs; progressDialog = NULL; warningMessages = ""; } /** * Destructor. */ BrainModelAlgorithm::~BrainModelAlgorithm() { removeProgressDialog(); } /** * add to warning messages (newline automatically added after message). */ void BrainModelAlgorithm::addToWarningMessages(const QString& msg) { if (warningMessages.isEmpty() == false) { warningMessages += "\n"; } warningMessages += msg; } /** * Create the progress dialog. */ void BrainModelAlgorithm::createProgressDialog(const QString& title, const int totalNumberOfSteps, const QString& /*dialogName*/) { // // See if a progress dialog should be displayed // progressDialog = NULL; QWidget* progressDialogParent = brainSet->getProgressDialogParent(); if (progressDialogParent != NULL) { progressDialog = new QProgressDialog(title, "Cancel", 0, totalNumberOfSteps, progressDialogParent); progressDialog->move(progressDialogParent->pos()); progressDialog->setWindowTitle(title); progressDialog->setValue(0); progressDialog->setLabelText(""); progressDialog->show(); } } /** * Update the progress dialog. Returns true if cancel button pressed by user. */ void BrainModelAlgorithm::updateProgressDialog(const QString& text, const int progressNumber, const int totalNumberOfSteps) throw (BrainModelAlgorithmException) { // // Set progress dialog // if (progressDialog != NULL) { qApp->processEvents(); // note: qApp is global in QApplication // // See if progress dialog was cancelled // if (progressDialog->wasCanceled()) { removeProgressDialog(); throw BrainModelAlgorithmException("Operation cancelled by user."); } // // update progress dialog // if (progressNumber >= 0) { if (totalNumberOfSteps >= 0) { progressDialog->setValue(progressNumber); progressDialog->setMaximum(totalNumberOfSteps); } else { progressDialog->setValue(progressNumber); } } progressDialog->setLabelText(text); qApp->processEvents(); // note: qApp is global in QApplication } else if (qApp != NULL) { if (qApp->type() == QApplication::Tty) { // std::cout << text.toAscii().constData() << std::endl; } } emit signalProgressUpdate(text, progressNumber, totalNumberOfSteps); } /** * Remove and delete the progress dialog. */ void BrainModelAlgorithm::removeProgressDialog() { // // Remove progress dialog // if (progressDialog != NULL) { progressDialog->setValue(1000000); delete progressDialog; progressDialog = NULL; qApp->processEvents(); // note: qApp is global in QApplication } } /** * allow GUI events to process. */ void BrainModelAlgorithm::allowEventsToProcess() { if (brainSet->getProgressDialogParent() != NULL) { qApp->processEvents(); } } /** * get a text description of algorithm. */ QString BrainModelAlgorithm::getTextDescription() const { return ""; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModel.h0000664000175000017500000001444211572067322022077 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_BRAIN_MODEL_H__ #define __VE_BRAIN_MODEL_H__ #include class BrainSet; class vtkTransform; /// Class for the different brain model types. This class cannot be instantiated. /// Must create subclass. class BrainModel { public: /// Number of brain model viewers (also update brain model open gl enum BRAIN_MODEL_VIEW_NUMBER { BRAIN_MODEL_VIEW_MAIN_WINDOW = 0, BRAIN_MODEL_VIEW_AUX_WINDOW_2 = 1, BRAIN_MODEL_VIEW_AUX_WINDOW_3 = 2, BRAIN_MODEL_VIEW_AUX_WINDOW_4 = 3, BRAIN_MODEL_VIEW_AUX_WINDOW_5 = 4, BRAIN_MODEL_VIEW_AUX_WINDOW_6 = 5, BRAIN_MODEL_VIEW_AUX_WINDOW_7 = 6, BRAIN_MODEL_VIEW_AUX_WINDOW_8 = 7, BRAIN_MODEL_VIEW_AUX_WINDOW_9 = 8, BRAIN_MODEL_VIEW_AUX_WINDOW_10 = 9, NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS = 10 }; /// The brain model types available enum BRAIN_MODEL_TYPE { BRAIN_MODEL_CONTOURS, BRAIN_MODEL_SURFACE, BRAIN_MODEL_VOLUME, BRAIN_MODEL_SURFACE_AND_VOLUME }; /// Standard views enumerated types enum STANDARD_VIEWS { // if the order of these is changed then VIEW_NONE, // the combo box that uses these must be VIEW_RESET, // updated. VIEW_ANTERIOR, VIEW_DORSAL, VIEW_LATERAL, VIEW_MEDIAL, VIEW_POSTERIOR, VIEW_VENTRAL, VIEW_ROTATE_X_90, VIEW_ROTATE_Y_90, VIEW_ROTATE_Z_90 }; /// Destructor virtual ~BrainModel(); /// Get a descriptive name of the model virtual QString getDescriptiveName() const = 0; /// Get the model type. BRAIN_MODEL_TYPE getModelType() const { return modelType; } /// Get the index of this model in the brain set int getBrainModelIndex() const; /// get the brain set BrainSet* getBrainSet() { return brainSet; } /// get the brain set const methods const BrainSet* getBrainSet() const { return brainSet; } /// set the brain set void setBrainSet(BrainSet* bs) { brainSet = bs; } /// Copy the sources transformation to me void copyTransformations(BrainModel* sourceModel, const int sourceModelNumber, const int targetModelNumber); /// get the rotation matrix inverse void getRotationMatrixInverse(const int viewNumber, float matrix[16]) const; /// get the rotation matrix void getRotationMatrix(const int viewNumber, float matrix[16]) const; /// set the rotation matrix void setRotationMatrix(const int viewNumber, const float matrix[16]); /// get the rotation matrix vtkTransform* getRotationTransformMatrix(const int viewNumber) { return rotationMatrix[viewNumber]; } /// get the model's scaling void getScaling(const int viewNumber, float scaleOut[3]) const; /// set the model's scaling virtual void setScaling(const int viewNumber, const float scaleIn[3]); /// set the model's scaling virtual void setScaling(const int viewNumber, const float sx, const float sy, const float sz); /// get the model's translation void getTranslation(const int viewNumber, float translationOut[3]) const; /// set the model's translation void setTranslation(const int viewNumber, const float translationIn[3]); /// get the model's perspective zooming float getPerspectiveZooming(const int viewNumber) const; /// set the model's perspective translation void setPerspectiveZooming(const int viewNumber, const float zoomingIn); /// reset the viewing transformations void resetViewingTransformations(); /// get the perspective field of view float getPerspectiveFieldOfView() const { return perspectiveFieldOfView; } /// get transformations as string (3 trans, 16 rot, 1 scale, 1 persp fov) QString getTransformationsAsString(const int viewNumber) const; /// set transformations from string (3 trans, 16 rot, 1 scale, 1 persp fov) void setTransformationsAsString(const int viewNumber, const QString s); /// set to a standard view virtual void setToStandardView(const int viewNumber, const STANDARD_VIEWS view); protected: /// Constructor BrainModel(BrainSet* bs, const BRAIN_MODEL_TYPE bmt); /// Copy Constructor BrainModel(const BrainModel& bm); /// brain set this model is associated with BrainSet* brainSet; /// the model type BRAIN_MODEL_TYPE modelType; /// Rotation of model vtkTransform* rotationMatrix[NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS]; /// Scaling of model float scaling[NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS][3]; /// Translation of model float translation[NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS][3]; /// Perspective (translate in Z) float perspectiveZooming[NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS]; /// perspective field of view float perspectiveFieldOfView; private: /// initialize this object void initialize(BrainSet* bs, const BRAIN_MODEL_TYPE bmt); }; #endif caret-5.6.4~dfsg.1.orig/caret_brain_set/BrainModel.cxx0000664000175000017500000003623211572067322022453 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainModel.h" #include "BrainSet.h" #include "StringUtilities.h" #include "vtkTransform.h" /** * Constructor */ BrainModel::BrainModel(BrainSet* bs, const BRAIN_MODEL_TYPE bmt) { initialize(bs, bmt); } /** * Copy Constructor. */ BrainModel::BrainModel(const BrainModel& bm) { initialize(bm.brainSet, bm.modelType); // // Do not copy these members // rotationMatrix // scaling // translation // } /** * Destructor. */ BrainModel::~BrainModel() { for (int i = 0; i < NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS; i++) { rotationMatrix[i]->Delete(); } } /** * Initialize this object */ void BrainModel::initialize(BrainSet* bs, const BRAIN_MODEL_TYPE bmt) { brainSet = bs; modelType = bmt; for (int i = 0; i < NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS; i++) { rotationMatrix[i] = vtkTransform::New(); } perspectiveFieldOfView = 30.0; resetViewingTransformations(); } /** * Get the index of this model in the brain set. */ int BrainModel::getBrainModelIndex() const { int modelNumber = -1; if (brainSet != NULL) { for (int i = 0; i < brainSet->getNumberOfBrainModels(); i++) { if (brainSet->getBrainModel(i) == this) { modelNumber = i; break; } } } return modelNumber; } /** * Reset the viewing transformations of the model */ void BrainModel::resetViewingTransformations() { for (int i = 0; i < NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS; i++) { rotationMatrix[i]->Identity(); scaling[i][0] = 1.0; scaling[i][1] = 1.0; scaling[i][2] = 1.0; translation[i][0] = 0.0; translation[i][1] = 0.0; translation[i][2] = 0.0; perspectiveZooming[i] = 200.0; } } /** * Get the rotation matrix as an array */ void BrainModel::getRotationMatrix(const int viewNumber, float matrix[16]) const { vtkMatrix4x4* m = vtkMatrix4x4::New(); rotationMatrix[viewNumber]->GetMatrix(m); int cnt = 0; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { matrix[cnt] = m->GetElement(i, j); cnt++; } } m->Delete(); } /** * Get the rotation matrix inverse as an array */ void BrainModel::getRotationMatrixInverse(const int viewNumber, float matrix[16]) const { vtkMatrix4x4* m = vtkMatrix4x4::New(); rotationMatrix[viewNumber]->GetMatrix(m); m->Invert(); int cnt = 0; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { matrix[cnt] = m->GetElement(i, j); cnt++; } } m->Delete(); } /** * Set the rotation matrix as an array. */ void BrainModel::setRotationMatrix(const int viewNumber, const float matrix[16]) { vtkMatrix4x4* m = vtkMatrix4x4::New(); rotationMatrix[viewNumber]->GetMatrix(m); int cnt = 0; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { m->SetElement(i, j, matrix[cnt]); cnt++; } } rotationMatrix[viewNumber]->SetMatrix(m); m->Delete(); } /** * Get the model's translation. */ void BrainModel::getTranslation(const int viewNumber, float translationOut[3]) const { translationOut[0] = translation[viewNumber][0]; translationOut[1] = translation[viewNumber][1]; translationOut[2] = translation[viewNumber][2]; } /** * Set the model's translation. */ void BrainModel::setTranslation(const int viewNumber, const float translationIn[3]) { translation[viewNumber][0] = translationIn[0]; translation[viewNumber][1] = translationIn[1]; translation[viewNumber][2] = translationIn[2]; } /** * get the model's scaling. */ void BrainModel::getScaling(const int viewNumber, float scaleOut[3]) const { scaleOut[0] = scaling[viewNumber][0]; scaleOut[1] = scaling[viewNumber][1]; scaleOut[2] = scaling[viewNumber][2]; } /** * set the model's scaling. */ void BrainModel::setScaling(const int viewNumber, const float scaleIn[3]) { scaling[viewNumber][0] = scaleIn[0]; scaling[viewNumber][1] = scaleIn[1]; scaling[viewNumber][2] = scaleIn[2]; } /** * set the model's scaling. */ void BrainModel::setScaling(const int viewNumber, const float sx, const float sy, const float sz) { scaling[viewNumber][0] = sx; scaling[viewNumber][1] = sy; scaling[viewNumber][2] = sz; } /** * Get the model's perspective zooming. */ float BrainModel::getPerspectiveZooming(const int viewNumber) const { return perspectiveZooming[viewNumber]; } /** * Set the model's perspective zooming. */ void BrainModel::setPerspectiveZooming(const int viewNumber, const float zoomingIn) { perspectiveZooming[viewNumber] = zoomingIn; } /** * Copy the transformations from the specified model and model viewer. Used when * views are yoked. */ void BrainModel::copyTransformations(BrainModel* sourceModel, const int sourceModelNumber, const int targetModelNumber) { // // Copy scaling. // float scale[3]; sourceModel->getScaling(sourceModelNumber, scale); setScaling(targetModelNumber, scale); // // Copy translation. // float trans[3]; sourceModel->getTranslation(sourceModelNumber, trans); setTranslation(targetModelNumber, trans); // // Copy perspective zooming. // setPerspectiveZooming(targetModelNumber, sourceModel->getPerspectiveZooming(sourceModelNumber)); // // Copy rotation matrix // float mat[16]; sourceModel->getRotationMatrix(sourceModelNumber, mat); setRotationMatrix(targetModelNumber, mat); } /** * get transformations as string (3 trans, 16 rot, 3 scale, 1 persp fov). */ QString BrainModel::getTransformationsAsString(const int viewNumber) const { std::ostringstream str; str.precision(2); str.setf(std::ios::fixed); float trans[3]; getTranslation(viewNumber, trans); for (int i = 0; i < 3; i++) { str << trans[i] << " "; } float mat[16]; getRotationMatrix(viewNumber, mat); for (int i = 0; i < 16; i++) { str << mat[i] << " "; } float scale[3]; getScaling(viewNumber, scale); str << scale[0] << " " << scale[1] << " " << scale[2] << " " << getPerspectiveZooming(viewNumber); const QString s(str.str().c_str()); return s; } /** * set transformations from string (3 trans, 16 rot, 1 (or 3) scale, 1 persp fov). */ void BrainModel::setTransformationsAsString(const int viewNumber, const QString s) { std::vector tokens; StringUtilities::token(s, " ", tokens); QString s2(s); QTextStream textStream(&s2, QIODevice::ReadOnly); float trans[3]; textStream >> trans[0] >> trans[1] >> trans[2]; setTranslation(viewNumber, trans); float mat[16]; for (int i = 0; i < 16; i++) { textStream >> mat[i]; } setRotationMatrix(viewNumber, mat); float scale[3] = { 1.0, 1.0, 1.0 }; textStream >> scale[0]; if (tokens.size() == 23) { textStream >> scale[1]; textStream >> scale[2]; } else { scale[1] = scale[0]; scale[2] = scale[0]; } setScaling(viewNumber, scale); float perZoom; textStream >> perZoom; setPerspectiveZooming(viewNumber, perZoom); } /** * Set the surface to a standard view */ void BrainModel::setToStandardView(const int viewNumber, const STANDARD_VIEWS view) { float m[16]; bool valid = true; const Structure structure = brainSet->getStructure(); switch(view) { case VIEW_LATERAL: if (structure.getType() != Structure::STRUCTURE_TYPE_CORTEX_RIGHT) { m[0] = 0.0; m[1] = 0.0; m[2] = -1.0; m[3] = 0.0; m[4] = -1.0; m[5] = 0.0; m[6] = 0.0; m[7] = 0.0; m[8] = 0.0; m[9] = 1.0; m[10] = 0.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; } else { m[0] = 0.0; m[1] = 0.0; m[2] = 1.0; m[3] = 0.0; m[4] = 1.0; m[5] = 0.0; m[6] = 0.0; m[7] = 0.0; m[8] = 0.0; m[9] = 1.0; m[10] = 0.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; } break; case VIEW_MEDIAL: if (structure.getType() != Structure::STRUCTURE_TYPE_CORTEX_RIGHT) { m[0] = 0.0; m[1] = 0.0; m[2] = 1.0; m[3] = 0.0; m[4] = 1.0; m[5] = 0.0; m[6] = 0.0; m[7] = 0.0; m[8] = 0.0; m[9] = 1.0; m[10] = 0.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; } else { m[0] = 0.0; m[1] = 0.0; m[2] = -1.0; m[3] = 0.0; m[4] = -1.0; m[5] = 0.0; m[6] = 0.0; m[7] = 0.0; m[8] = 0.0; m[9] = 1.0; m[10] = 0.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; } break; case VIEW_POSTERIOR: if (structure.getType() != Structure::STRUCTURE_TYPE_CORTEX_RIGHT) { m[0] = 1.0; m[1] = 0.0; m[2] = 0.0; m[3] = 0.0; m[4] = 0.0; m[5] = 0.0; m[6] = -1.0; m[7] = 0.0; m[8] = 0.0; m[9] = 1.0; m[10] = 0.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; } else { m[0] = 1.0; m[1] = 0.0; m[2] = 0.0; m[3] = 0.0; m[4] = 0.0; m[5] = 0.0; m[6] = -1.0; m[7] = 0.0; m[8] = 0.0; m[9] = 1.0; m[10] = 0.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; } break; case VIEW_ANTERIOR: if (structure.getType() != Structure::STRUCTURE_TYPE_CORTEX_RIGHT) { m[0] = -1.0; m[1] = 0.0; m[2] = 0.0; m[3] = 0.0; m[4] = 0.0; m[5] = 0.0; m[6] = 1.0; m[7] = 0.0; m[8] = 0.0; m[9] = 1.0; m[10] = 0.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; } else { m[0] = -1.0; m[1] = 0.0; m[2] = 0.0; m[3] = 0.0; m[4] = 0.0; m[5] = 0.0; m[6] = 1.0; m[7] = 0.0; m[8] = 0.0; m[9] = 1.0; m[10] = 0.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; } break; case VIEW_VENTRAL: if (structure.getType() != Structure::STRUCTURE_TYPE_CORTEX_RIGHT) { m[0] = -1.0; m[1] = 0.0; m[2] = 0.0; m[3] = 0.0; m[4] = 0.0; m[5] = 1.0; m[6] = 0.0; m[7] = 0.0; m[8] = 0.0; m[9] = 0.0; m[10] = -1.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; } else { m[0] = -1.0; m[1] = 0.0; m[2] = 0.0; m[3] = 0.0; m[4] = 0.0; m[5] = 1.0; m[6] = 0.0; m[7] = 0.0; m[8] = 0.0; m[9] = 0.0; m[10] = -1.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; } break; case VIEW_DORSAL: if (structure.getType() != Structure::STRUCTURE_TYPE_CORTEX_RIGHT) { m[0] = 1.0; m[1] = 0.0; m[2] = 0.0; m[3] = 0.0; m[4] = 0.0; m[5] = 1.0; m[6] = 0.0; m[7] = 0.0; m[8] = 0.0; m[9] = 0.0; m[10] = 1.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; } else { m[0] = 1.0; m[1] = 0.0; m[2] = 0.0; m[3] = 0.0; m[4] = 0.0; m[5] = 1.0; m[6] = 0.0; m[7] = 0.0; m[8] = 0.0; m[9] = 0.0; m[10] = 1.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; } break; case VIEW_RESET: m[0] = 1.0; m[1] = 0.0; m[2] = 0.0; m[3] = 0.0; m[4] = 0.0; m[5] = 1.0; m[6] = 0.0; m[7] = 0.0; m[8] = 0.0; m[9] = 0.0; m[10] = 1.0; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; perspectiveZooming[viewNumber] = 100.0; //defaultPerspectiveZooming; scaling[viewNumber][0] = 1.0; scaling[viewNumber][1] = 1.0; scaling[viewNumber][2] = 1.0; translation[viewNumber][0] = 0.0; translation[viewNumber][1] = 0.0; translation[viewNumber][2] = 0.0; break; case VIEW_ROTATE_X_90: rotationMatrix[viewNumber]->RotateX(90.0); valid = false; break; case VIEW_ROTATE_Y_90: rotationMatrix[viewNumber]->RotateY(90.0); valid = false; break; case VIEW_ROTATE_Z_90: rotationMatrix[viewNumber]->RotateZ(-90.0); valid = false; break; case VIEW_NONE: default: valid = false; break; } if (valid) { setRotationMatrix(viewNumber, m); } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BorderUncertaintyToArealEstimationConverter.h0000664000175000017500000001274011572067322030722 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __BORDER_UNCERTAINTY_TO_AREAL_ESTIMATION_CONVERTER_H__ #define __BORDER_UNCERTAINTY_TO_AREAL_ESTIMATION_CONVERTER_H__ #include #include "BrainModelAlgorithm.h" class ArealEstimationFile; class BorderFile; class BrainModelSurface; class PaintFile; /// Class that creates an areal estimation file from border uncertainty class BorderUncertaintyToArealEstimationConverter : public BrainModelAlgorithm { public: enum MODE { MODE_ALL_NODES, MODE_NODES_WITH_PAINT }; /// Constructor BorderUncertaintyToArealEstimationConverter( BrainSet* bs, BrainModelSurface* surfaceIn, ArealEstimationFile* arealEstimationFileIn, BorderFile* borderFileIn, PaintFile* paintFileIn, const MODE modeIn, const int arealEstimationFileColumnIn, const QString& arealEstimationFileColumnNameIn, const QString& longNameIn, const QString& commentIn, const int paintColumnIn, const QString paintMatchNameIn, const bool overrideBorderUncertaintyIn, const float overrideBorderUncertaintyValueIn); /// Destructor ~BorderUncertaintyToArealEstimationConverter(); /// execute the algorithm void execute() throw (BrainModelAlgorithmException); private: /// class to help with finding the nearest borders class BorderDist { public: int borderNumber; int borderNearestLink; float distanceToBorder; BorderDist(const int borderNumberIn, const int borderNearestLinkIn, const float distanceToBorderIn) { borderNumber = borderNumberIn; borderNearestLink = borderNearestLinkIn; distanceToBorder = distanceToBorderIn; } bool operator<(const BorderDist& b) const { if (distanceToBorder < b.distanceToBorder) { return true; } if (distanceToBorder > b.distanceToBorder) { return false; } if (borderNumber < b.borderNumber) { return true; } return false; } }; /// Class for sorting 4 borders with normalized probabilities class ProbabilitySort { public: QString name; float probability; ProbabilitySort(const QString& n, const float p) { name = n; probability = p; } bool operator<(const ProbabilitySort& p) const { if (probability > p.probability) { return true; } if (probability < p.probability) { return false; } if (name.compare(p.name) < 0) { return true; } return false; } }; float determineSignedDistance(const float* pos, const BorderDist& bd); void findClosestBorderLinks2D(const float* pos, std::set& closestBorders); /// the areal estimation file ArealEstimationFile* arealEstimationFile; /// column in the areal estimation file int arealEstimationFileColumn; /// name of areal estimation file column QString arealEstimationFileColumnName; /// the paint file PaintFile* paintFile; /// the paint column int paintColumn; /// the border file BorderFile* borderFile; /// paint name to match QString paintMatchName; /// long name for column QString longName; /// comment for column QString comment; /// the surface used BrainModelSurface* surface; /// mode MODE mode; /// override border file uncertainties bool overrideBorderUncertainty; /// border override uncertainty value float overrideBorderUncertaintyValue; }; #endif // __BORDER_UNCERTAINTY_TO_AREAL_ESTIMATION_CONVERTER_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BorderUncertaintyToArealEstimationConverter.cxx0000664000175000017500000002570211572067322031277 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #ifdef Q_OS_WIN32 #define NOMINMAX #endif #include #include #include "ArealEstimationFile.h" #include "BorderFile.h" #include "BorderUncertaintyToArealEstimationConverter.h" #include "BrainModelSurface.h" #include "BrainSet.h" #include "FileUtilities.h" #include "MathUtilities.h" #include "PaintFile.h" /** * Constructor. */ BorderUncertaintyToArealEstimationConverter::BorderUncertaintyToArealEstimationConverter( BrainSet* bs, BrainModelSurface* surfaceIn, ArealEstimationFile* arealEstimationFileIn, BorderFile* borderFileIn, PaintFile* paintFileIn, const MODE modeIn, const int arealEstimationFileColumnIn, const QString& arealEstimationFileColumnNameIn, const QString& longNameIn, const QString& commentIn, const int paintColumnIn, const QString paintMatchNameIn, const bool overrideBorderUncertaintyIn, const float overrideBorderUncertaintyValueIn) : BrainModelAlgorithm(bs) { surface = surfaceIn; arealEstimationFile = arealEstimationFileIn; borderFile = borderFileIn; paintFile = paintFileIn; mode = modeIn; arealEstimationFileColumn = arealEstimationFileColumnIn; arealEstimationFileColumnName = arealEstimationFileColumnNameIn; longName = longNameIn; comment = commentIn; paintColumn = paintColumnIn; paintMatchName = paintMatchNameIn; overrideBorderUncertainty = overrideBorderUncertaintyIn; overrideBorderUncertaintyValue = overrideBorderUncertaintyValueIn; comment.append("\nBorder File: "); comment.append("\nUncertainty override: "); comment.append(FileUtilities::basename(borderFile->getFileName())); if (overrideBorderUncertainty) { comment.append(QString::number(overrideBorderUncertaintyValue, 'f', 2)); } else { comment.append("use values from border file."); } } // // Find closest link in all borders from pos in X-Y plane. // void BorderUncertaintyToArealEstimationConverter::findClosestBorderLinks2D(const float* pos, std::set& closestBorders) { closestBorders.clear(); const int numBorders = borderFile->getNumberOfBorders(); for (int j = 0; j < numBorders; j++) { int closestLink = -1; float distanceToLink = std::numeric_limits::max(); Border* b = borderFile->getBorder(j); if (b->getDisplayFlag()) { const int numLinks = b->getNumberOfLinks(); for (int i = 0; i < numLinks; i++) { const float* borderPos = b->getLinkXYZ(i); const float dx = pos[0] - borderPos[0]; const float dy = pos[1] - borderPos[1]; const float dist = dx*dx + dy*dy; if (dist < distanceToLink) { distanceToLink = dist; closestLink = i; } } if (closestLink >= 0) { distanceToLink = std::sqrt(distanceToLink); BorderDist bd(j, closestLink, distanceToLink); closestBorders.insert(bd); } } } } float BorderUncertaintyToArealEstimationConverter::determineSignedDistance(const float* pos, const BorderDist& bd) { Border* border = borderFile->getBorder(bd.borderNumber); const float* borderPos = border->getLinkXYZ(bd.borderNearestLink); // // vector from border point to node // float bpToNode[3]; MathUtilities::subtractVectors((float*)pos, borderPos, bpToNode); const float bpMag = std::sqrt(bpToNode[0]*bpToNode[0] + bpToNode[1]*bpToNode[1]); if (bpMag != 0.0) { bpToNode[0] /= bpMag; bpToNode[1] /= bpMag; } else { return 0.0; } // // signed distance of node from border point // Note: both bpToNode and the border normal are unit vectors so the dot // product of bpToNode and the border normal give the cosine of the angle // formed by them. // const float* flatNormal = border->getLinkFlatNormal(bd.borderNearestLink); const float cosAngle = bpToNode[0] * flatNormal[0] + bpToNode[1] * flatNormal[1]; const float signedDistance = (cosAngle * bpMag); return signedDistance; } /** * Destructor. */ BorderUncertaintyToArealEstimationConverter::~BorderUncertaintyToArealEstimationConverter() { } /** * execute the algorithm. */ void BorderUncertaintyToArealEstimationConverter::execute() throw (BrainModelAlgorithmException) { const int numNodes = surface->getNumberOfNodes(); if (numNodes <= 0) { throw BrainModelAlgorithmException("Surface contains nodes."); } // // Make sure we have some paints // const int numPaintColumns = paintFile->getNumberOfColumns(); if (numPaintColumns == 0) { if (mode == MODE_NODES_WITH_PAINT) { throw BrainModelAlgorithmException("The paint file is empty."); } } // // Make sure there are some borders // const int numBorders = borderFile->getNumberOfBorders(); if (numBorders <= 0) { throw BrainModelAlgorithmException("The border file is empty."); } // // Compute normals for flat borders // borderFile->computeFlatNormals(); // // Determine which paint names match the name entered by the user // std::vector matchingPaints; switch (mode) { case MODE_ALL_NODES: break; case MODE_NODES_WITH_PAINT: { const int numPaintNames = paintFile->getNumberOfPaintNames(); if (numPaintNames <= 0) { throw BrainModelAlgorithmException("There are no paint names."); } matchingPaints.resize(numPaintNames, false); for (int j = 0; j < numPaintNames; j++) { if (paintFile->getPaintNameFromIndex(j) == paintMatchName) { matchingPaints[j] = true; } } } break; } // // Get access to surface's Areal Estimation File // if (arealEstimationFile->getNumberOfColumns() <= 0) { arealEstimationFile->setNumberOfNodesAndColumns(numNodes, 1); arealEstimationFileColumn = arealEstimationFile->getNumberOfColumns() - 1; } else { if ((arealEstimationFileColumn < 0) || (arealEstimationFileColumn >= arealEstimationFile->getNumberOfColumns())) { arealEstimationFile->addColumns(1); arealEstimationFileColumn = arealEstimationFile->getNumberOfColumns() - 1; } } arealEstimationFile->setColumnName(arealEstimationFileColumn, arealEstimationFileColumnName); arealEstimationFile->setLongName(arealEstimationFileColumn, longName); arealEstimationFile->setColumnComment(arealEstimationFileColumn, comment); // // Search through the nodes // const CoordinateFile* cf = surface->getCoordinateFile(); for (int i = 0; i < numNodes; i++) { // // See if this node should be used // bool useNode = false; switch (mode) { case MODE_ALL_NODES: useNode = true; break; case MODE_NODES_WITH_PAINT: useNode = matchingPaints[paintFile->getPaint(i, paintColumn)]; break; } if (useNode) { std::set closestBorders; findClosestBorderLinks2D(cf->getCoordinate(i), closestBorders); int ctr = 0; QString names[4] = { "NULL", "NULL", "NULL", "NULL" }; float probabilities[4] = { 0.0, 0.0, 0.0, 0.0 }; float sumProbability = 0.0; for (std::set::iterator cbi = closestBorders.begin(); cbi != closestBorders.end(); cbi++) { const int borderNumber = cbi->borderNumber; Border* border = borderFile->getBorder(borderNumber); const QString borderName(border->getName()); // // Make sure border with same name is not already found // bool useIt = true; for (int ib = 0; ib < ctr; ib++) { if (borderName == names[ib]) { useIt = false; break; } } if (useIt) { names[ctr] = borderName; const float signedDistance = determineSignedDistance( cf->getCoordinate(i), *cbi); float borderUncertainty = border->getArealUncertainty(); if (overrideBorderUncertainty) { borderUncertainty = overrideBorderUncertaintyValue; } float temp = ((signedDistance / borderUncertainty) - 1.0) * 0.5; if (temp < -10.0) { temp = -10.0; } probabilities[ctr] = exp(temp); if (probabilities[ctr] > 1.0) { probabilities[ctr] = 1.0; } sumProbability += probabilities[ctr]; ctr++; if (ctr >= 4) { break; } } } std::set probSort; for (int m = 0; m < ctr; m++) { ProbabilitySort ps(names[m], probabilities[m] / sumProbability); probSort.insert(ps); } int pctr =0; for (std::set::iterator pi = probSort.begin(); pi != probSort.end(); pi++) { names[pctr] = pi->name; probabilities[pctr] = pi->probability; pctr++; } arealEstimationFile->setNodeData(i, arealEstimationFileColumn, names, probabilities); } } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BorderToTopographyConverter.h0000664000175000017500000000711711572067322025551 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __BORDER_TO_TOPOGRAPHY_CONVERTER_H__ #define __BORDER_TO_TOPOGRAPHY_CONVERTER_H__ #include "BrainModelAlgorithm.h" class Border; class BorderFile; class BrainModelSurface; class PaintFile; class QRegExp; class TopographyFile; /// class to convert borders into topography class BorderToTopographyConverter : public BrainModelAlgorithm { public: /// constructor BorderToTopographyConverter(BrainSet* bs, BrainModelSurface* surfaceIn, BorderFile* borderFileIn, PaintFile* paintFileIn, TopographyFile* topographyFileIn, const int topographyFileColumnIn, const QString topographyFileColumnNameIn); /// destructor ~BorderToTopographyConverter(); /// execute the algorithm void execute() throw (BrainModelAlgorithmException); private: enum TOPOGRAPHY_TYPES { TYPE_EMEAN = 0, TYPE_ELOW = 1, TYPE_EHIGH = 2, TYPE_PMEAN = 3, TYPE_PLOW = 4, TYPE_PHIGH = 5, TYPE_NONE = 6 }; void getBorderAreaAndType( const QString borderName, QRegExp& regExpr, QString& areaNameOut, TOPOGRAPHY_TYPES& topographyTypeOut, int& areaNumberOut); void getNodeAreaTypeAndBorders( const QString& nodeName, QRegExp& regExpr, QString& areaNameOut, TOPOGRAPHY_TYPES& topographyTypeOut, int& areaNumber1Out, int& areaNumber2Out); /// Interpolate the topography values between two points. float interpolateBorderTopoValues( const float nearDist, const float farDist, const float nearValue, const float farValue) const; /// Find the distance to the link that is closest to the nodes' position float getClosestBorderPointDistance(const Border* b, const float nodeXYZ[3]) const; /// the surface BrainModelSurface* surface; /// the border file BorderFile* borderFile; /// the paint file PaintFile* paintFile; /// the topography file TopographyFile* topographyFile; /// the topography file column int topographyFileColumn; /// the topography file column name QString topographyFileColumnName; }; #endif // __BORDER_TO_TOPOGRAPHY_CONVERTER_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BorderToTopographyConverter.cxx0000664000175000017500000004145611572067322026130 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #ifdef Q_OS_WIN32 #define NOMINMAX #endif #include #include #include #include "BorderFile.h" #include "BorderToTopographyConverter.h" #include "BrainModelSurface.h" #include "PaintFile.h" #include "TopographyFile.h" /* static QString topographyNames[] = { "Emean", "Elow", "Ehigh", "Pmean", "Plow", "Phigh", "None" }; */ /** * constructor. */ BorderToTopographyConverter::BorderToTopographyConverter(BrainSet* bs, BrainModelSurface* surfaceIn, BorderFile* borderFileIn, PaintFile* paintFileIn, TopographyFile* topographyFileIn, const int topographyFileColumnIn, const QString topographyFileColumnNameIn) : BrainModelAlgorithm(bs) { surface = surfaceIn; borderFile = borderFileIn; paintFile = paintFileIn; topographyFile = topographyFileIn; topographyFileColumn = topographyFileColumnIn; topographyFileColumnName = topographyFileColumnNameIn; } /** * destructor. */ BorderToTopographyConverter::~BorderToTopographyConverter() { } /** * execute the algorithm */ void BorderToTopographyConverter::execute() throw (BrainModelAlgorithmException) { if (surface == NULL) { throw BrainModelAlgorithmException("No surface provided."); } CoordinateFile* coords = surface->getCoordinateFile(); const int numNodes = coords->getNumberOfCoordinates(); if (numNodes <= 0) { throw BrainModelAlgorithmException("Surface has no coordinates."); } if (borderFile == NULL) { throw BrainModelAlgorithmException("No borders provided."); } const int numBorders = borderFile->getNumberOfBorders(); if (numBorders <= 0) { throw BrainModelAlgorithmException("Border file is empty."); } if (paintFile == NULL) { throw BrainModelAlgorithmException("No paint file provided."); } if (paintFile->getNumberOfColumns() != 6) { throw BrainModelAlgorithmException("Paint file must have six columns."); } // // use a regular expression to match borders // borders to match are of the form area.type.number // examples: v1.Pmean.2 v2.Ehigh.8 // QString topoBorderStringRE = "(.+)\\.(.+)\\.([0-9]+)$"; QRegExp topoBorderRE(topoBorderStringRE); if (topoBorderRE.isValid() == false) { QString msg("Regular expression error: "); msg.append(topoBorderStringRE); throw BrainModelAlgorithmException(msg); } // // use a regular expression to match node names // node names to match are of the form area.type_number1_number2 // examples: V1.Emean_1_2 V2.Ehigh_5_6 // QString areaBorderStringRE = "(.+)\\.(.+)_([0-9]+)_([0-9]+)$"; QRegExp areaBorderRE(areaBorderStringRE); if (areaBorderRE.isValid() == false) { QString msg("Regular expression error: "); msg.append(areaBorderStringRE); throw BrainModelAlgorithmException(msg); } // loop through borders to get its area name and type // TOPOGRAPHY_TYPES* borderType = new TOPOGRAPHY_TYPES[numBorders]; QString* borderAreaName = new QString[numBorders]; int* borderAreaNumber = new int[numBorders]; bool haveTopographyValue = false; bool haveTopographyBorders = false; for (int j = 0; j < numBorders; j++) { Border* b = borderFile->getBorder(j); getBorderAreaAndType(b->getName(), topoBorderRE, borderAreaName[j], borderType[j], borderAreaNumber[j]); /* printf("Border %d: TYPE = %s AREA NAME = %s NUMBER = %d " "TOPOGRAPHY_VALUE = %f\n", j, topographyNames[static_cast(borderType[j])], borderAreaName[j], borderAreaNumber[j], b.topographyValue); */ if (borderType[j] != TYPE_NONE) { haveTopographyBorders = true; if (b->getTopographyValue() != 0.0) { haveTopographyValue = true; } } } if (haveTopographyBorders == false) { throw BrainModelAlgorithmException( "No Borders are of topography type like \"v1.Pmean.2\""); delete[] borderType; delete[] borderAreaName; return; } if (haveTopographyValue == false) { throw BrainModelAlgorithmException( "All topography borders have topography value equal to zero"); delete[] borderType; delete[] borderAreaName; return; } bool* topoValid = new bool[numNodes]; QString* topoAreaName = new QString[numNodes]; float* topoEmean = new float[numNodes]; float* topoElow = new float[numNodes]; float* topoEhigh = new float[numNodes]; float* topoPmean = new float[numNodes]; float* topoPlow = new float[numNodes]; float* topoPhigh = new float[numNodes]; for (int m = 0; m < numNodes; m++) { topoValid[m] = false; topoEmean[m] = 0.0; topoElow[m] = 0.0; topoEhigh[m] = 0.0; topoPmean[m] = 0.0; topoPlow[m] = 0.0; topoPhigh[m] = 0.0; } // // loop through 6 Topography Types (Emean, Elow, Ehigh, Pmean, Plow, Phigh) // for (int paintIndex = 0; paintIndex < 6; paintIndex++ ) { for (int j = 0; j < numNodes; j++) { // // see if point has a valid name // const QString nodeName = paintFile->getPaintNameFromIndex(paintFile->getPaint(j, paintIndex)); if (nodeName == "???") { QString nodeAreaName; TOPOGRAPHY_TYPES nodeTopographyType; int nodeArea1, nodeArea2; getNodeAreaTypeAndBorders(nodeName, areaBorderRE, nodeAreaName, nodeTopographyType, nodeArea1, nodeArea2); // // if node is of type being tested // //if (nodeTopographyType == topographyTest) { if (nodeTopographyType != TYPE_NONE) { int closestBorder1 = -1; int closestBorder2 = -1; float closestBorderDist1 = std::numeric_limits::max(); float closestBorderDist2 = std::numeric_limits::max(); // // loop through borders // for (int i = 0; i < numBorders; i++) { Border* b = borderFile->getBorder(i); // // if border is of type being checked // if (nodeTopographyType == borderType[i]) { // // see if border's area number matches one of the // nodes border area numbers // if ((borderAreaNumber[i] == nodeArea1) || (borderAreaNumber[i] == nodeArea2)) { // // if border area name is in node's area name // if (nodeAreaName.indexOf(borderAreaName[i]) != -1) { topoAreaName[j] = borderAreaName[i]; // nodeAreaName; const float dist = getClosestBorderPointDistance( b, coords->getCoordinate(j)); if (dist < closestBorderDist1) { closestBorderDist2 = closestBorderDist1; closestBorder2 = closestBorder1; closestBorderDist1 = dist; closestBorder1 = i; } else if (dist < closestBorderDist2) { closestBorderDist2 = dist; closestBorder2 = i; } } // matched border name } // matched border number } // matched border type } // number of borders if (closestBorder2 >= 0) { topoValid[j] = true; const Border* b1 = borderFile->getBorder(closestBorder1); const Border* b2 = borderFile->getBorder(closestBorder2); const float value = interpolateBorderTopoValues( closestBorderDist1, closestBorderDist2, b1->getTopographyValue(), b2->getTopographyValue()); switch(nodeTopographyType) { case TYPE_EMEAN: topoEmean[j] = value; break; case TYPE_ELOW: topoElow[j] = value; break; case TYPE_EHIGH: topoEhigh[j] = value; break; case TYPE_PMEAN: topoPmean[j] = value; break; case TYPE_PLOW: topoPlow[j] = value; break; case TYPE_PHIGH: topoPhigh[j] = value; break; case TYPE_NONE: break; } } /* else if (closestBorder1 >= 0) { printf("ERROR: Only matched one border for node %d: %s\n", j, nodeName); } else { printf("ERROR: Unable to match borders for node %d: %s\n", j, nodeName); } */ } // matched node type } // node name not "???" } // s.num_points } // for k = 1 to 6 // // Get access to surface's Areal Estimation File // if (topographyFile->getNumberOfColumns() <= 0) { topographyFile->setNumberOfNodesAndColumns(numNodes, 1); topographyFileColumn = topographyFile->getNumberOfColumns() - 1; } else { if ((topographyFileColumn < 0) || (topographyFileColumn >= topographyFile->getNumberOfColumns())) { topographyFile->addColumns(1); topographyFileColumn = topographyFile->getNumberOfColumns() - 1; } } topographyFile->setColumnName(topographyFileColumn, topographyFileColumnName); for (int i = 0; i < numNodes; i++) { if (topoValid[i]) { NodeTopography nt(topoEmean[i], topoElow[i], topoEhigh[i], topoPmean[i], topoPlow[i], topoPhigh[i], topoAreaName[i]); topographyFile->setNodeTopography(i, topographyFileColumn, nt); } } /* float em[2], el[2], eh[2], pm[2], pl[2], ph[2]; s.topographyFile.getMinMaxTopography(em, el, eh, pm, pl, ph); printf("Eccentricity Mean Minimum: %f\n", em[0]); printf("Eccentricity Mean Maximum: %f\n", em[1]); printf("Eccentricity Low Minimum: %f\n", el[0]); printf("Eccentricity Low Maximum: %f\n", el[1]); printf("Eccentricity High Minimum: %f\n", eh[0]); printf("Eccentricity High Maximum: %f\n", eh[1]); printf("Polar Angle Mean Minimum: %f\n", pm[0]); printf("Polar Angle Mean Maximum: %f\n", pm[1]); printf("Polar Angle Low Minimum: %f\n", pl[0]); printf("Polar Angle Low Maximum: %f\n", pl[1]); printf("Polar Angle High Minimum: %f\n", ph[0]); printf("Polar Angle High Maximum: %f\n", ph[1]); */ delete[] topoAreaName; delete[] topoValid; delete[] topoEmean; delete[] topoElow; delete[] topoEhigh; delete[] topoPmean; delete[] topoPlow; delete[] topoPhigh; delete[] borderType; delete[] borderAreaName; delete[] borderAreaNumber; } /** * Extract data from border names like "V1.Emean.0" where "V1" is the area, * "Emean" is the type, and "0" is the border id. */ void BorderToTopographyConverter::getBorderAreaAndType( const QString borderName, QRegExp& regExpr, QString& areaNameOut, TOPOGRAPHY_TYPES& topographyTypeOut, int& areaNumberOut) { topographyTypeOut = TYPE_NONE; if (regExpr.indexIn(borderName) < 0) { return; } const int numMatches = regExpr.numCaptures(); if (numMatches < 4) { return; } const QString areaName(regExpr.cap(1)); areaNameOut = areaName; const QString typeName(regExpr.cap(2)); if (typeName.indexOf("Emean") != -1) { topographyTypeOut = TYPE_EMEAN; } else if (typeName.indexOf("Elow") != -1) { topographyTypeOut = TYPE_ELOW; } else if (typeName.indexOf("Ehigh") != -1) { topographyTypeOut = TYPE_EHIGH; } else if (typeName.indexOf("Pmean") != -1) { topographyTypeOut = TYPE_PMEAN; } else if (typeName.indexOf("Plow") != -1) { topographyTypeOut = TYPE_PLOW; } else if (typeName.indexOf("Phigh") != -1) { topographyTypeOut = TYPE_PHIGH; } const QString areaNumberChars(regExpr.cap(3)); areaNumberOut = areaNumberChars.toInt(); } /** * Extract the data from the node's name which comes from paint/atlas file. * Looking for names like "V1.Emean_0_1" where "V1" is the area, "Emean" is * the type, and "0" and "1" are the border ids. The matching borders are * "V1.Emean.0" and "V1.Emean.1". */ void BorderToTopographyConverter::getNodeAreaTypeAndBorders( const QString& nodeName, QRegExp& regExpr, QString& areaNameOut, TOPOGRAPHY_TYPES& topographyTypeOut, int& areaNumber1Out, int& areaNumber2Out) { topographyTypeOut = TYPE_NONE; if (regExpr.indexIn(nodeName) < 0) { return; } if (regExpr.numCaptures() < 4) { return; } areaNameOut = regExpr.cap(1); const QString typeName(regExpr.cap(2)); if (typeName.indexOf("Emean") != -1) { topographyTypeOut = TYPE_EMEAN; } else if (typeName.indexOf("Elow") != -1) { topographyTypeOut = TYPE_ELOW; } else if (typeName.indexOf("Ehigh") != -1) { topographyTypeOut = TYPE_EHIGH; } else if (typeName.indexOf("Pmean") != -1) { topographyTypeOut = TYPE_PMEAN; } else if (typeName.indexOf("Plow") != -1) { topographyTypeOut = TYPE_PLOW; } else if (typeName.indexOf("Phigh") != -1) { topographyTypeOut = TYPE_PHIGH; } areaNumber1Out = regExpr.cap(3).toInt(); areaNumber2Out = regExpr.cap(4).toInt(); } /** * Find the distance to the link that is closest to the nodes' position */ float BorderToTopographyConverter::getClosestBorderPointDistance(const Border* b, const float nodeXYZ[3]) const { float minDist = std::numeric_limits::max(); const int numLinks = b->getNumberOfLinks(); for (int i = 0; i < numLinks; i++) { const float* linkPos = b->getLinkXYZ(i); const float dx = linkPos[0] - nodeXYZ[0]; const float dy = linkPos[1] - nodeXYZ[1]; const float dz = linkPos[2] - nodeXYZ[2]; const float dist = dx*dx + dy*dy + dz*dz; if (dist < minDist) minDist = dist; } return std::sqrt(minDist); } /** * Interpolate the topography values between two points. */ float BorderToTopographyConverter::interpolateBorderTopoValues( const float nearDist, const float farDist, const float nearValue, const float farValue) const { const float totalDist = nearDist + farDist; const float interp = nearValue * (1.0 - (nearDist / totalDist)) + farValue * (nearDist / totalDist); return interp; } caret-5.6.4~dfsg.1.orig/caret_brain_set/BorderProjectionUnprojector.h0000664000175000017500000000337011572067322025566 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_BORDER_PROJECTION_UNPROJECTOR_H__ #define __VE_BORDER_PROJECTION_UNPROJECTOR_H__ #include "BorderFile.h" #include "BorderProjectionFile.h" #include "BrainModelSurface.h" /// class for unprojecting border projections class BorderProjectionUnprojector { private: /// unproject a border projection void unprojectBorderProjectionLink(const BorderProjectionLink* bl, const CoordinateFile& cf, float xyz[3], int& section, float& radius); public: /// Constructor BorderProjectionUnprojector(); /// Desstructor ~BorderProjectionUnprojector(); /// Unproject the border projections void unprojectBorderProjections(const CoordinateFile& cf, const BorderProjectionFile& bpf, BorderFile& bf, const int startAtProjection = 0); }; #endif caret-5.6.4~dfsg.1.orig/caret_brain_set/BorderProjectionUnprojector.cxx0000664000175000017500000000751011572067322026141 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BorderProjectionUnprojector.h" /** * Unproject a border projection point */ void BorderProjectionUnprojector::unprojectBorderProjectionLink(const BorderProjectionLink* bl, const CoordinateFile& cf, float xyz[3], int& section, float& radius) { section = 0; xyz[0] = 0.0; xyz[1] = 0.0; xyz[2] = 0.0; radius = 0.0; int vertices[3]; float areas[3]; bl->getData(section, vertices, areas, radius); const float totalArea = areas[0] + areas[1] + areas[2]; if (totalArea > 0.0) { const float* v1 = cf.getCoordinate(vertices[0]); const float* v2 = cf.getCoordinate(vertices[1]); const float* v3 = cf.getCoordinate(vertices[2]); xyz[0] = (v1[0] * areas[1] + v2[0] * areas[2] + v3[0] * areas[0]) / totalArea; xyz[1] = (v1[1] * areas[1] + v2[1] * areas[2] + v3[1] * areas[0]) / totalArea; xyz[2] = (v1[2] * areas[1] + v2[2] * areas[2] + v3[2] * areas[0]) / totalArea; /* xyz[0] = (v1[0] * areas[2] + v2[0] * areas[0] + v3[0] * areas[1]) / totalArea; xyz[1] = (v1[1] * areas[2] + v2[1] * areas[0] + v3[1] * areas[1]) / totalArea; xyz[2] = (v1[2] * areas[2] + v2[2] * areas[0] + v3[2] * areas[1]) / totalArea; */ } } /** * Constructor */ BorderProjectionUnprojector::BorderProjectionUnprojector() { } /** * Destructor */ BorderProjectionUnprojector::~BorderProjectionUnprojector() { } /** * Unproject a border projection file into surfaces projected borders */ void BorderProjectionUnprojector::unprojectBorderProjections(const CoordinateFile& cf, const BorderProjectionFile& bpf, BorderFile& bf, const int startAtProjection) { const int numProj = bpf.getNumberOfBorderProjections(); for (int i = startAtProjection; i < numProj; i++) { const BorderProjection* bp = bpf.getBorderProjection(i); const int numLinks = bp->getNumberOfLinks(); QString name; float center[3]; float sampling, variance, topography, uncertainty; bp->getData(name, center, sampling, variance, topography, uncertainty); Border b(name, center, sampling, variance, topography, uncertainty); b.setBorderColorIndex(bp->getBorderColorIndex()); for (int j = 0; j < numLinks; j++) { const BorderProjectionLink* bpl = bp->getBorderProjectionLink(j); int section; float xyz[3]; float radius; unprojectBorderProjectionLink(bpl, cf, xyz, section, radius); b.addBorderLink(xyz, section, radius); } b.setBorderProjectionID(bp->getUniqueID()); b.setBorderColorIndex(bp->getBorderColorIndex()); bf.addBorder(b); } } caret-5.6.4~dfsg.1.orig/caret_brain_set/BorderFileProjector.h0000664000175000017500000000402211572067322023761 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_BORDER_FILE_PROJECTOR_H__ #define __VE_BORDER_FILE_PROJECTOR_H__ class QProgressDialog; class QWidget; class BorderFile; class BorderProjectionFile; class BrainModelSurface; class BrainModelSurfacePointProjector; /// This class is used to project a BorderFile to a BrainModelSurface and store the /// results in a border projection file. class BorderFileProjector { public: /// Constructor BorderFileProjector(const BrainModelSurface* bmsIn, const bool barycentricModeIn); /// Destructor ~BorderFileProjector(); /// Project the border file to the border projection file using the BrainModelSurface /// passed to the constructor. void projectBorderFile(const BorderFile* bf, BorderProjectionFile* bpf, QWidget* progressDialogParent); private: /// used to project the border points BrainModelSurfacePointProjector* pointProjector; /// barycentric projection flag bool barycentricMode; }; #endif // __VE_BORDER_FILE_PROJECTOR_H__ caret-5.6.4~dfsg.1.orig/caret_brain_set/BorderFileProjector.cxx0000664000175000017500000001365511572067322024350 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include "BorderFile.h" #include "BorderFileProjector.h" #include "BorderProjectionFile.h" #include "BrainModelSurfacePointProjector.h" #include "DebugControl.h" /** * Constructor. If "barycentricModeIn" is true, the border file will be projected to * barycentric coordinates in tiles, otherwise, the border points will be projected to * the nearest nodes in the BrainModelSurface. */ BorderFileProjector::BorderFileProjector(const BrainModelSurface* bmsIn, const bool barycentricModeIn) { barycentricMode = barycentricModeIn; pointProjector = new BrainModelSurfacePointProjector(bmsIn, BrainModelSurfacePointProjector::SURFACE_TYPE_HINT_OTHER, false); } /** * Destructor. */ BorderFileProjector::~BorderFileProjector() { } /** * Project a border file to a border projection file using the BrainModelSurface passed to * the constructor. If "progressDialogParent" is not NULL, a progress dialog will be * displayed while borders are being projected. */ void BorderFileProjector::projectBorderFile(const BorderFile* bf, BorderProjectionFile* bpf, QWidget* progressDialogParent) { const int numBorders = bf->getNumberOfBorders(); if (numBorders > 0) { // // Create a progress dialog // QProgressDialog* progressDialog = NULL; if (progressDialogParent != NULL) { progressDialog = new QProgressDialog("Projecting Borders", 0, 0, numBorders + 1, progressDialogParent); progressDialog->setWindowTitle("Projecting Borders"); progressDialog->setValue(0); progressDialog->show(); } for (int i = 0; i < numBorders; i++) { const Border* b = bf->getBorder(i); const int numLinks = b->getNumberOfLinks(); if (numLinks > 0) { if (progressDialog != NULL) { if (progressDialog->wasCanceled()) { break; } progressDialog->setValue(i + 1); qApp->processEvents(); // note: qApp is global in QApplication } // // Transfer border attribute data from the border to the border projection // QString name; float center[3]; float sampDensity; float variance; float topography; float arealUncertainty; b->getData(name, center, sampDensity, variance, topography, arealUncertainty); BorderProjection bp(name, center, sampDensity, variance, topography, arealUncertainty); bp.setBorderColorIndex(b->getBorderColorIndex()); // // Project the border link points to the border projection file // for (int j = 0; j < numLinks; j++) { float xyz[3]; b->getLinkXYZ(j, xyz); int vertices[3]; float areas[3]; bool validPoint = false; if (barycentricMode) { int nearestNode = -1; const int tileNumber = pointProjector->projectBarycentric(xyz, nearestNode, vertices, areas); if ((nearestNode >= 0) && (tileNumber >= 0)) { validPoint = true; } } else { const int nearestNode = pointProjector->projectToNearestNode(xyz); if (nearestNode >= 0) { vertices[0] = nearestNode; vertices[1] = nearestNode; vertices[2] = nearestNode; areas[0] = 1.0; areas[1] = 0.0; areas[2] = 0.0; validPoint = true; } } if (validPoint) { BorderProjectionLink bpl(b->getLinkSectionNumber(j), vertices, areas, b->getLinkRadius(j)); bp.addBorderProjectionLink(bpl); } else if (DebugControl::getDebugOn()) { std::cout << "INFO: Border Link (" << i << "," << j << ") in "<< name.toAscii().constData() << " does not project to a tile and has been discarded" << std::endl; } } if (bp.getNumberOfLinks() > 0) { bpf->addBorderProjection(bp); } } } // // Remove the progress dialog // if (progressDialog != NULL) { progressDialog->setValue(numBorders + 1); delete progressDialog; } } } caret-5.6.4~dfsg.1.orig/caret_brain_set/.project0000664000175000017500000000470411572067322021361 0ustar michaelmichael caret_brain_set org.eclipse.wst.common.project.facet.core.builder org.eclipse.cdt.managedbuilder.core.genmakebuilder clean,full,incremental, ?name? org.eclipse.cdt.make.core.append_environment true org.eclipse.cdt.make.core.autoBuildTarget all org.eclipse.cdt.make.core.buildArguments org.eclipse.cdt.make.core.buildCommand make org.eclipse.cdt.make.core.cleanBuildTarget clean org.eclipse.cdt.make.core.contents org.eclipse.cdt.make.core.activeConfigSettings org.eclipse.cdt.make.core.enableAutoBuild false org.eclipse.cdt.make.core.enableCleanBuild true org.eclipse.cdt.make.core.enableFullBuild true org.eclipse.cdt.make.core.fullBuildTarget all org.eclipse.cdt.make.core.stopOnError true org.eclipse.cdt.make.core.useDefaultBuildCmd true org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder org.eclipse.cdt.core.cnature org.eclipse.cdt.core.ccnature org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature org.eclipse.wst.common.project.facet.core.nature caret-5.6.4~dfsg.1.orig/caret_brain_set/.cproject0000664000175000017500000002073311572067322021524 0ustar michaelmichael make all true true true caret-5.6.4~dfsg.1.orig/caret/0000775000175000017500000000000011572067322015657 5ustar michaelmichaelcaret-5.6.4~dfsg.1.orig/caret/main.cxx0000664000175000017500000006351211572067322017336 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ // // This file contains the main function // #include #ifdef Q_OS_WIN32 //#include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "BrainSet.h" #include "CaretVersion.h" #include "DebugControl.h" #include "FileUtilities.h" #include "GuiMacOSXApplication.h" #include "GuiMainWindow.h" #include "GuiMainWindowFileActions.h" #include "GuiMainWindowFileMenu.h" #include "GiftiDataArrayFile.h" #include "SpecFile.h" #include "SpecFileUtilities.h" #include "StringUtilities.h" #include "UbuntuMessage.h" #include "WuQFileDialog.h" #include "QtTextEditDialog.h" #define CARET_MAIN_FLAG #include "global_variables.h" #undef CARET_MAIN_FLAG enum INITIAL_SPEC_MODE { INITIAL_SPEC_MODE_NONE, INITIAL_SPEC_MODE_LOAD, INITIAL_SPEC_MODE_DIALOG }; static bool debugFlag = false; static std::vector initialSpecFiles; static INITIAL_SPEC_MODE initialSpecMode = INITIAL_SPEC_MODE_NONE; static bool glTimingFlag = false; static int openGLsizeX = -1; static int openGLsizeY = -1; /** * List the available QT GUI styles. */ static void listGuiStyles() { QStringList styles = QStyleFactory::keys(); if (styles.count() > 0) { std::cout << " -style style-name" << std::endl << " Set the user-interface style where \"style-name\" is one of:" << std::endl; for (QStringList::Iterator it = styles.begin(); it != styles.end(); it++) { QString s = *it; std::cout << " " << s.toAscii().constData() << std::endl; } std::cout << "" << std::endl; } } /** * Print command line option help. */ static void printHelp(const QString& programNameIn) { const QString programName(FileUtilities::basename(programNameIn)); std::cout << "NAME" << std::endl << " " << programName.toAscii().constData() << std::endl << "" << std::endl << "SYNOPSIS" << std::endl << " " << programName.toAscii().constData() << " [options]" << std::endl << "" << std::endl << "DESCRIPTION" << std::endl << " Visualize cerebral and cerebellar cortical maps." << std::endl << "" << std::endl << " If spec-file-name is specified, the spec file by that name will" << std::endl << " be loaded into a spec file dialog." << std::endl << "" << std::endl << " " << programName.toAscii().constData() << " has the following options:" << std::endl << "" << std::endl << " -debug" << std::endl << " Enable the printing of debugging information to the console." << std::endl << "" << std::endl << " -gl-timing" << std::endl << " Adds a menu item to the view menu to enable the timing" << std::endl << " of OpenGL graphics." << std::endl << "" << std::endl << " -h or -help" << std::endl << " Displays this help information." << std::endl << "" << std::endl << " -loadspec ... " << std::endl << " Automatically loads all of the data files in each of the spec" << std::endl << " files at startup." << std::endl << "" << std::endl << " -notext" << std::endl << " Inhibits use of text in OpenGL drawing such as the text" << std::endl << " shown on volume slices indicating stereotaxic coordinates." << std::endl << " This option may prevent crashes on Linux systems with " << std::endl << " FreeType library problems." << std::endl << "" << std::endl << " -read-time" << std::endl << " Enable printing of time required to read each file." << std::endl << "" << std::endl << " -spec " << std::endl << " Automatically loads \"spec-file-name\" into the spec file dialog at" << std::endl << " startup." << std::endl << "" << std::endl; listGuiStyles(); std::cout << " -v" << std::endl << " Print the version number." << std::endl << std::endl << " -xy X Y" << std::endl << " Set the main window graphics to be \"X by Y\" size." << std::endl << " This is typically used when recording to MPEG so that" << std::endl << " the video is a specific size." << std::endl << std::endl; exit(0); } /** * process the command line options */ static void processCommandLineOptions(int argc, char* argv[]) { const QString programName(FileUtilities::basename(QString(argv[0]))); for (int i = 1; i < argc; i++) { const QString arg(argv[i]); if (arg == "-debug") { debugFlag = true; } else if ((arg == "-h") || (arg == "-help")) { printHelp(argv[0]); } else if (arg == "-loadspec") { for (i = i + 1; i < argc; i++) { QString argValue = argv[i]; if (argValue.startsWith("-")) { i--; break; } else { initialSpecFiles.push_back(argv[i]); initialSpecMode = INITIAL_SPEC_MODE_LOAD; } } /* i++; if (i >= argc) { std::cerr << "ERROR: missing name of spec file on \"-loadspec\" option." << std::endl; exit(-1); } initialSpecFiles.push_back(argv[i]); initialSpecMode = INITIAL_SPEC_MODE_LOAD; */ } else if (arg == "-spec") { i++; if (i >= argc) { std::cerr << "ERROR: missing name of spec file on \"-spec\" option." << std::endl; exit(-1); } initialSpecFiles.push_back(argv[i]); initialSpecMode = INITIAL_SPEC_MODE_DIALOG; } else if (arg == "-style") { i++; // -style is used by QApplication } else if (arg == "-test1") { DebugControl::setTestFlag1(true); } else if (arg == "-test2") { DebugControl::setTestFlag2(true); } else if (arg == "-gl-timing") { glTimingFlag = true; } else if (arg == "-notext") { BrainModelOpenGL::setOpenGLTextEnabled(false); } else if (arg == "-read-time") { DebugControl::setFileReadTimingFlag(true); } else if ((arg == "-v") || (arg == "-version")) { std::cout << programName.toAscii().constData() << " version " << CaretVersion::getCaretVersionAsString().toAscii().constData() << std::endl; std::exit(0); } else if (arg == "-xy") { i++; if (i >= argc) { std::cerr << "ERROR: Window size missing on \"-xy\" option." << std::endl; exit(-1); } openGLsizeX = QString(argv[i]).toInt(); i++; if (i >= argc) { std::cerr << "ERROR: Window Y size missing on \"-xy\" option." << std::endl; exit(-1); } openGLsizeY = QString(argv[i]).toInt(); } else if (arg.mid(0, 4) == "-psn") { // ignore this arg which occurs if a spec file is double clicked on in mac finder } else { if (StringUtilities::endsWith(arg, SpecFile::getSpecFileExtension())) { initialSpecFiles.push_back(arg); initialSpecMode = INITIAL_SPEC_MODE_DIALOG; } else { std::cerr << "ERROR: Unrecognized command line option: " << arg.toAscii().constData() << std::endl; //exit(-1); } } } } /* static void testRE(const QString& filenameIn) { QString directory, QString species; QString casename; QString anatomy; QString hemisphere; QString description; QString descriptionNoType; QString theDate; QString numNodes; QString extension; if (FileUtilities::parseCaretDataFileName(filenameIn, directory, species, casename, anatomy, hemisphere, description, descriptionNoType, theDate, numNodes, extension)) { std::cout << "reassembled: " << FileUtilities::reassembleCaretDataFileName( directory, species, casename, anatomy, hemisphere, description, theDate, numNodes, extension) << std::endl << std::endl; } } static void testRegularExpressions() { std::cout << std::endl << std::endl; testRE("Human.colin.L.surface_shape"); testRE("Human.colin.L.12345.surface_shape"); testRE("Human.colin.L.2003-05-12.12345.surface_shape"); testRE("Human.colin.L.03-05-12.12345.surface_shape"); testRE("Human.colin.L.2003-05.12345.surface_shape"); testRE("Human.colin.L.03-05.12345.surface_shape"); testRE("Human.colin.Cerebral.R.71723.surface_shape"); testRE("Human.colin.Cerebral.R.ATLAS.QuickStart.03-05.71723.spec"); testRE("Human.colin.Cerebral.R.COMPOSITE.03-05-25.71723.paint"); testRE("Human.colin.Cerebral.R.FIDUCIAL.TLRC.711-2B-afni.71723.coord"); testRE("Human.colin.R.COMPOSITE_FUNCTIONAL_QuickStart.03-05-26.71723.metric"); testRE("Human.colin.R.VISION.COMPOSITE.MapToSPM.03-05.fociproj"); testRE("Human.colin.Cerebral.R.FLAT.CartSTD.71723.coord"); testRE("Human.colin.Cerebral.R.SPHERE.STD.71723.coord"); std::cout << std::endl << std::endl; } */ /** * Initialize the File Dialog */ void initializeFileDialog() { WuQFileDialog::TypeExtensionToTypeNameMap typeMap; typeMap[SpecFile::getTopoFileExtension()] = "Topology"; typeMap[SpecFile::getCoordinateFileExtension()] = "Coordinate"; typeMap[SpecFile::getTransformationMatrixFileExtension()] = "Transformation Matrix"; typeMap[SpecFile::getLatLonFileExtension()] = "Latitude/Longitude"; typeMap[SpecFile::getSectionFileExtension()] = "Section"; typeMap[SpecFile::getPaintFileExtension()] = "Paint"; typeMap[SpecFile::getRegionOfInterestFileExtension()] = "Region of Interest"; typeMap[SpecFile::getProbabilisticAtlasFileExtension()] = "Probabilistic Atlas"; typeMap[SpecFile::getAreaColorFileExtension()] = "Area Color"; typeMap[SpecFile::getRgbPaintFileExtension()] = "RGB Paint"; typeMap[SpecFile::getBorderFileExtension()] = "Border"; typeMap[SpecFile::getBorderColorFileExtension()] = "Border Color"; typeMap[SpecFile::getBorderProjectionFileExtension()] = "Border Projection"; typeMap[SpecFile::getPaletteFileExtension()] = "Palette"; typeMap[SpecFile::getTopographyFileExtension()] = "Topography"; typeMap[SpecFile::getCellFileExtension()] = "Cell"; typeMap[SpecFile::getCellColorFileExtension()] = "Cell Color"; typeMap[SpecFile::getCellProjectionFileExtension()] = "Cell Projection"; typeMap[SpecFile::getContourFileExtension()] = "Contour"; typeMap[SpecFile::getContourCellColorFileExtension()] = "Contour Cell Color"; typeMap[SpecFile::getContourCellFileExtension()] = "Contour Cell"; typeMap[SpecFile::getMetricFileExtension()] = "Metric"; typeMap[SpecFile::getSurfaceShapeFileExtension()] = "Surface Shape"; typeMap[SpecFile::getCocomacConnectivityFileExtension()] = "Cocomac Connectivity"; typeMap[SpecFile::getArealEstimationFileExtension()] = "Areal Estimation"; typeMap[SpecFile::getCutsFileExtension()] = "Cuts"; typeMap[SpecFile::getFociFileExtension()] = "Foci"; typeMap[SpecFile::getFociColorFileExtension()] = "Foci Color"; typeMap[SpecFile::getFociProjectionFileExtension()] = "Foci Projection"; typeMap[SpecFile::getParamsFileExtension()] = "Params File"; typeMap[SpecFile::getDeformationMapFileExtension()] = "Deformation Map"; typeMap[SpecFile::getDeformationFieldFileExtension()] = "Deformation Field"; typeMap[SpecFile::getVtkModelFileExtension()] = "VTK Model"; typeMap[SpecFile::getGeodesicDistanceFileExtension()] = "Geodesic Distance"; typeMap[SpecFile::getAtlasSurfaceDirectoryFileExtension()] = "Atlas Surface Directory"; typeMap[SpecFile::getBrainVoyagerFileExtension()] = "Brain Voyager"; typeMap[SpecFile::getAtlasSpaceFileExtension()] = "Atlas Space"; typeMap[SpecFile::getFreeSurferAsciiCurvatureFileExtension()] = "Free Surfer Curvature (ASCII)"; typeMap[SpecFile::getFreeSurferBinaryCurvatureFileExtension()] = "Free Surfer Curvature (Binary)"; typeMap[SpecFile::getFreeSurferAsciiFunctionalFileExtension()] = "Free Surfer Functional (ASCII)"; typeMap[SpecFile::getFreeSurferBinaryFunctionalFileExtension()] = "Free Surfer Functional (Binary)"; typeMap[SpecFile::getFreeSurferLabelFileExtension()] = "Free Surfer Label"; typeMap[SpecFile::getFreeSurferAsciiSurfaceFileExtension()] = "Free Surfer Surface (ASCII)"; typeMap[SpecFile::getFreeSurferBinarySurfaceFileExtension()] = "Free Surfer Surface (Binary)"; typeMap[SpecFile::getSumaRgbFileExtension()] = "SUMA RGB"; typeMap[SpecFile::getPreferencesFileExtension()] = "Preferences"; typeMap[SpecFile::getSpecFileExtension()] = "Specification"; typeMap[SpecFile::getAnalyzeVolumeFileExtension()] = "Volume - Analyze or SPM"; typeMap[SpecFile::getAfniVolumeFileExtension().toLower()] = "Volume - AFNI"; typeMap[SpecFile::getWustlVolumeFileExtension()] = "Volume - WUSTL"; typeMap[SpecFile::getMincVolumeFileExtension()] = "Volume - MINC"; typeMap[SpecFile::getNiftiVolumeFileExtension()] = "NIFTI"; typeMap[SpecFile::getNiftiGzipVolumeFileExtension()] = "NIFTI - Compressed"; typeMap[SpecFile::getSceneFileExtension()] = "Scene"; typeMap[SpecFile::getSureFitVectorFileExtension()] = "SureFit Vector"; typeMap[SpecFile::getWustlRegionFileExtension()] = "WUSTL Region"; typeMap[SpecFile::getLimitsFileExtension()] = "Limits"; typeMap[SpecFile::getMDPlotFileExtension()] = "MD Plot"; typeMap[SpecFile::getGiftiCoordinateFileExtension()] = "GIFTI Coordinate"; typeMap[SpecFile::getGiftiFunctionalFileExtension()] = "GIFTI Functional"; typeMap[SpecFile::getGiftiLabelFileExtension()] = "GIFTI Label"; typeMap[SpecFile::getGiftiRgbaFileExtension()] = "GIFTI RGBA"; typeMap[SpecFile::getGiftiShapeFileExtension()] = "GIFTI Shape"; typeMap[SpecFile::getGiftiSurfaceFileExtension()] = "GIFTI Surface"; typeMap[SpecFile::getGiftiTensorFileExtension()] = "GIFTI Tensor"; typeMap[SpecFile::getGiftiTopologyFileExtension()] = "GIFTI Topology"; typeMap[SpecFile::getGiftiVectorFileExtension()] = "GIFTI Vector"; typeMap[SpecFile::getGiftiGenericFileExtension()] = "GIFTI Generic"; typeMap[SpecFile::getCommaSeparatedValueFileExtension()] = "Comma Separated Value"; typeMap[SpecFile::getVocabularyFileExtension()] = "Vocabulary"; typeMap[SpecFile::getStudyMetaDataFileExtension()] = "Study Metadata"; typeMap[SpecFile::getStudyCollectionFileExtension()] = "Study Collection"; typeMap[SpecFile::getXmlFileExtension()] = "XML"; typeMap[SpecFile::getTextFileExtension()] = "Text"; typeMap[SpecFile::getNeurolucidaFileExtension()] = "Neurolucida"; typeMap[SpecFile::getCaretScriptFileExtension()] = "Caret Script"; WuQFileDialog::setFileExtensionToTypeNameMap(typeMap); } /** * Unexpected handler */ void unexpectedHandler() { std::cout << "WARNING: unhandled exception." << std::endl; if (theMainWindow != NULL) { const QString msg("Caret will be terminating due to an unexpected exception.\n" "abort() will be called and a core file may be created."); QMessageBox::critical(theMainWindow, "ERROR", msg); } abort(); } /** * New handler */ void newHandler() { std::ostringstream str; str << "\n" << "OUT OF MEMORY\n" << "\n" << "This means that Caret 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::cout << str.str().c_str() << std::endl; if (theMainWindow != NULL) { QMessageBox::critical(theMainWindow, "OUT OF MEMORY", "Out of memory, Caret terminating"); std::exit(-1); } } /* * Can be used to print all events (and there are lots of them) class CatchEvents : public QObject { protected: bool eventFilter(QObject* o, QEvent* e) { std::cout << "Class/Name: " << o->className() << ", " << o->name() << std::endl; return false; } }; */ /** * THE program's main. */ int main(int argc, char* argv[]) { #ifdef Q_OS_WIN32 // // Disables some window debugging stuff that gets stuck in calls to new() // //_CrtSetDbgFlag(0); #endif // // Set handlers in case sh*t happens // std::set_unexpected(unexpectedHandler); std::set_new_handler(newHandler); /* #ifdef Q_OS_LINUX // // Set style to Motif for Linux so that combo boxes use option menus // bool haveStyle = false; for (int i = 1; i < argc; i++) { if (QString(argv[i]) == "-style") { haveStyle = true; break; } } if (haveStyle == false) { //QT4 CONVERSION QApplication::setStyle(new QMotifStyle); } #endif */ //std::cout << "Home Directory: "; //std::cout << QDir::homePath().toAscii().constData() // << std::endl; QString allArgs; for (int i = 1; i < argc; i++) { allArgs.append(argv[i]); allArgs.append("\n"); } // // needed for static linking to have JPEG support // #ifndef UBUNTU #if QT_VERSION < 0x040600 Q_IMPORT_PLUGIN(qjpeg) //QJpegPlugin) Q_IMPORT_PLUGIN(qgif) //QGifPlugin) Q_IMPORT_PLUGIN(qtiff) //QTiffPlugin) #endif //QT_VERSION #endif // // Set the locale to prevent crashes due to non-english date formats // QLocale::setDefault(QLocale::c()); #ifdef Q_OS_MACX GuiMacOSXApplication app(argc, argv); #else QApplication app(argc, argv); #endif /// shows all events app.installEventFilter(new CatchEvents); processCommandLineOptions(argc, argv); //std::cout << "INFO: Set the environment variable CARET_DEBUG for debugging information." << std::endl; DebugControl::setDebugOnWithEnvironmentVariable("CARET_DEBUG"); if (debugFlag) { DebugControl::setDebugOn(true); } if (getenv("CARET_TEST1") != NULL) { DebugControl::setTestFlag1(true); } if (getenv("CARET_TEST2") != NULL) { DebugControl::setTestFlag2(true); } // // Make sure OpenGL is available. // if (!QGLFormat::hasOpenGL()) { qWarning( "This system has no OpenGL support. Exiting." ); return -1; } // // Setup OpenGL // QGLFormat glfmt; glfmt.setDoubleBuffer(true); glfmt.setDirectRendering(true); if ((getenv("CARET_TIMING") != NULL) || glTimingFlag) { glfmt.setDoubleBuffer(false); glTimingFlag = true; } QGLFormat::setDefaultFormat(glfmt); // // Get byte order // if (DebugControl::getDebugOn()) { if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { std::cout << "big endian system" << std::endl; } else { std::cout << "little endian system" << std::endl; } QDesktopWidget* dt = QApplication::desktop(); std::cout << "Screen size (" << dt->width() << ", " << dt->height() << ")" << std::endl; } // // Create and display the main window. // theMainWindow = new GuiMainWindow(glTimingFlag, openGLsizeX, openGLsizeY); //theMainWindow->resize(500, 500); //app.setMainWidget(theMainWindow); theMainWindow->show(); app.connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit())); #ifdef Q_OS_MACX // // Enable getting the open file event // app.setGuiMainWindow(theMainWindow); #endif #ifdef UBUNTU QtTextEditDialog* te = new QtTextEditDialog(theMainWindow, true, true); te->setWindowTitle("UBUNTU WARNING"); te->setMinimumSize(600, 600); te->setText(UbuntuMessage::getWarningMessage()); te->exec(); #endif UBUNTU if (initialSpecFiles.empty() == false) { if (QFile::exists(initialSpecFiles[0]) == false) { std::cerr << "The spec file " << initialSpecFiles[0].toAscii().constData() << " specified on the command line not found." << std::endl; initialSpecFiles.clear(); } } else if (initialSpecFiles.empty()) { std::vector specFiles; SpecFileUtilities::findSpecFilesInDirectory(QDir::currentPath(), specFiles); if (specFiles.size() == 1) { initialSpecFiles.push_back(specFiles[0]); initialSpecMode = INITIAL_SPEC_MODE_DIALOG; } else if (specFiles.size() > 1) { // // Show file dialog for choosing a spec file // theMainWindow->getFileActions()->openSpecFileSlot(); } } // // Without this and if "-loadspec" option is used, the caret image will fail to be drawn // GuiBrainModelOpenGL::updateAllGL(); QString welcomeMessage; const QTime timeNow(QTime::currentTime()); if (timeNow.hour() < 12) { welcomeMessage.append("Good morning."); } else if (timeNow.hour() < 18) { welcomeMessage.append("Good afternoon."); } else { welcomeMessage.append("Good evening."); } welcomeMessage.append(" Welcome to carrot."); theMainWindow->speakText(welcomeMessage, false); if (initialSpecFiles.empty() == false) { QFileInfo fileInfo(initialSpecFiles[0]); switch (initialSpecMode) { case INITIAL_SPEC_MODE_NONE: break; case INITIAL_SPEC_MODE_LOAD: for (unsigned int i = 0; i < initialSpecFiles.size(); i++) { SpecFile sf; try { QString path(FileUtilities::dirname(initialSpecFiles[i])); if (QDir::isRelativePath(path)) { path = QDir::currentPath(); path.append("/"); path.append(initialSpecFiles[i]); initialSpecFiles[i] = QDir::cleanPath(path); } sf.readFile(initialSpecFiles[i]); sf.setAllFileSelections(SpecFile::SPEC_TRUE); theMainWindow->loadSpecFilesDataFiles(sf, NULL, true); } catch (FileException& e) { QMessageBox::warning(theMainWindow, "ERROR", e.whatQString()); } } break; case INITIAL_SPEC_MODE_DIALOG: theMainWindow->readSpecFile(fileInfo.absoluteFilePath()); break; } } if (QFile::exists(theMainWindow->getBrainSet()->getCaretHomeDirectory()) == false) { QString msg("It appears that Caret is unable to determine its\n" "installation directory. Please set the environment\n" "variable CARET5_HOME to the Caret installation\n" "directory. Until this is corrected, some Caret features\n" "may not operate properly."); QMessageBox::warning(theMainWindow, "Install Warning", msg); } // // Initialize the file selection dialog // initializeFileDialog(); // // Show command line arguments in an information dialog // //QMessageBox::information(theMainWindow, "args", allArgs); int result = -1; try { result = app.exec(); } catch (BrainModelAlgorithmException& e) { QString msg("PROGRAM ERROR: BrainModelAlgorithmException not caught (this should not happen):\n" "Please copy the contents of this message and send to john@brainvis.wustl.edu."); msg.append(e.whatQString()); std::cerr << msg.toAscii().constData() << std::endl; } catch (FileException& e) { QString msg("PROGRAM ERROR: FileException not caught (this should not happen):\n" "Please copy the contents of this message and send to john@brainvis.wustl.edu."); msg.append(e.whatQString()); std::cerr << msg.toAscii().constData() << std::endl; } catch (std::exception& e) { QString msg("PROGRAM ERROR: std::exception not caught (this should not happen):\n" "Please copy the contents of this message and send to john@brainvis.wustl.edu."); msg.append(e.what()); std::cerr << msg.toAscii().constData() << std::endl; } //catch (std::bad_alloc) { // std::cout << "Out of memory (bad_alloc) " << std::endl; //} theMainWindow->hide();//keeps paint events from causing assertion error in close return result; } caret-5.6.4~dfsg.1.orig/caret/global_variables.h0000664000175000017500000000247011572067322021323 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_GLOBAL_VARIABLES_H__ #define __VE_GLOBAL_VARIABLES_H__ #ifdef CARET_MAIN_FLAG #define CARET_EXTERN #define CARET_INIT_VALUE(x) = (x) #define CARET_INIT_VALUE3(x,y,z) = { (x), (y), (z) } #else #define CARET_EXTERN extern #define CARET_INIT_VALUE(x) #define CARET_INIT_VALUE3(x,y,z) #endif class GuiMainWindow; /// THE main window CARET_EXTERN GuiMainWindow* theMainWindow CARET_INIT_VALUE(NULL); #endif // __VE_GLOBAL_VARIABLES_H__ caret-5.6.4~dfsg.1.orig/caret/caret5.rc0000664000175000017500000000005511572067322017370 0ustar michaelmichaelIDI_ICON1 ICON DISCARDABLE "caret5.ico" caret-5.6.4~dfsg.1.orig/caret/caret5.pro0000755000175000017500000005452611572067322017601 0ustar michaelmichael###################################################################### # Automatically generated by qmake (1.04a) Tue Jan 14 11:58:13 2003 ###################################################################### !vs:TEMPLATE = app vs:TEMPLATE=vcapp # # For JPEG support with static linking # #message("QT VERSION: $$[QT_VERSION]") contains(QT_VERSION, ^4\\.[0-6]\\..*) { QTPLUGIN += qgif qjpeg qtiff } LIBS += -L$(QTDIR)/plugins/imageformats INCLUDEPATH += . include(../caret_qmake_include.pro) CONFIG += assistant unix:release:!debug:!profile { QMAKE_POST_LINK=strip $(TARGET) ##QMAKE_POST_LINK=strip --strip-debug $(TARGET) } win32 { !vs:!nmake { CONFIG(debug) { LIBS += ..\caret_common\debug\libCaretCommon.a \ ..\caret_command_operations\debug\libCaretCommandOperations.a \ ..\caret_brain_set\debug\libCaretBrainSet.a \ ..\caret_vtk4_classes\debug\libCaretVtk4Classes.a \ ..\caret_files\debug\libCaretFiles.a \ ..\caret_uniformize\debug\libCaretUniformize.a \ ..\caret_statistics\debug\libCaretStatistics.a \ ..\caret_widgets\debug\libCaretWidgets.a \ ..\caret_common\debug\libCaretCommon.a \ ..\caret_cifti\debug\libCaretCifti.a } CONFIG(release) { LIBS += ..\caret_common\release\libCaretCommon.a \ ..\caret_command_operations\release\libCaretCommandOperations.a \ ..\caret_brain_set\release\libCaretBrainSet.a \ ..\caret_vtk4_classes\release\libCaretVtk4Classes.a \ ..\caret_files\release\libCaretFiles.a \ ..\caret_uniformize\release\libCaretUniformize.a \ ..\caret_statistics\release\libCaretStatistics.a \ ..\caret_widgets\release\libCaretWidgets.a \ ..\caret_common\release\libCaretCommon.a \ ..\caret_cifti\release\libCaretCifti.a } LIBS += $$VTK_LIBS } else { #it's either vs or nmake if it failed the test above CONFIG(debug,debug|release) { LIBS += ..\caret_common\debug\CaretCommon.lib \ ..\caret_command_operations\debug\CaretCommandOperations.lib \ ..\caret_brain_set\debug\CaretBrainSet.lib \ ..\caret_vtk4_classes\debug\CaretVtk4Classes.lib \ ..\caret_files\debug\CaretFiles.lib \ ..\caret_uniformize\debug\CaretUniformize.lib \ ..\caret_statistics\debug\CaretStatistics.lib \ ..\caret_widgets\debug\CaretWidgets.lib \ ..\caret_common\debug\CaretCommon.lib \ ..\caret_cifti\debug\CaretCifti.lib LIBS-=$$VTK_RELEASE_LIBS LIBS+=$$VTK_LIBS } CONFIG(release,debug|release) { LIBS += ..\caret_common\release\CaretCommon.lib \ ..\caret_command_operations\release\CaretCommandOperations.lib \ ..\caret_brain_set\release\CaretBrainSet.lib \ ..\caret_vtk4_classes\release\CaretVtk4Classes.lib \ ..\caret_files\release\CaretFiles.lib \ ..\caret_uniformize\release\CaretUniformize.lib \ ..\caret_statistics\release\CaretStatistics.lib \ ..\caret_widgets\release\CaretWidgets.lib \ ..\caret_common\release\CaretCommon.lib \ ..\caret_cifti\release\CaretCifti.lib LIBS-=$$VTK_LIBS LIBS+=$$VTK_RELEASE_LIBS } } RC_FILE = caret5.rc CONFIG(debug,debug|release) { CONFIG -= windows CONFIG += console } CONFIG(release,debug|release) { CONFIG -= windows CONFIG += console } contains( DEFINES, HAVE_QWT ) { LIBS += $$QWT_LIBS } contains( DEFINES, HAVE_MINC ) { LIBS += $$NETCDF_LIBS } } unix:!ubuntu { !dll { PRE_TARGETDEPS += \ ../caret_command_operations/libCaretCommandOperations.a \ ../caret_brain_set/libCaretBrainSet.a \ ../caret_vtk4_classes/libCaretVtk4Classes.a \ ../caret_files/libCaretFiles.a \ ../caret_uniformize/libCaretUniformize.a \ ../caret_statistics/libCaretStatistics.a \ ../caret_common/libCaretCommon.a \ ../caret_widgets/libCaretWidgets.a \ ../caret_cifti/libCaretCifti.a } dll { PRE_TARGETDEPS += \ ../caret_command_operations/libCaretCommandOperations.so \ ../caret_brain_set/libCaretBrainSet.so \ ../caret_vtk4_classes/libCaretVtk4Classes.so \ ../caret_files/libCaretFiles.so \ ../caret_uniformize/libCaretUniformize.so \ ../caret_statistics/libCaretStatistics.so \ ../caret_common/libCaretCommon.so \ ../caret_widgets/libCaretWidgets.so \ ../caret_cifti/libCaretCifti.so LIBS += -ldl } } macx { QMAKE_LFLAGS_APP -= -prebind LIBS += \ -L../caret_command_operations -lCaretCommandOperations \ -L../caret_brain_set -lCaretBrainSet \ -L../caret_vtk4_classes -lCaretVtk4Classes \ -L../caret_files -lCaretFiles \ -L../caret_uniformize -lCaretUniformize \ -L../caret_statistics -lCaretStatistics \ -L../caret_common -lCaretCommon \ -L../caret_widgets -lCaretWidgets \ -L../caret_cifti -lCaretCifti LIBS += \ -framework Carbon \ -framework Quicktime LIBS += $$VTK_LIBS # RC_FILE = caret5.icns # QMAKE_INFO_PLIST = Info.plist contains( DEFINES, HAVE_QWT ) { LIBS += $$QWT_LIBS } contains( DEFINES, HAVE_MINC ) { LIBS += $$NETCDF_LIBS } # # Icon for Mac version of Caret # ICON = caret5.icns # # QMAKE_POST_LINK may have "strip" if release # so need semicolon between commands # # qt_menu.nib must be in resources or application will abort # !isEmpty( QMAKE_POST_LINK) { QMAKE_POST_LINK += ; } QMAKE_POST_LINK += cp -r $$(QTDIR)/src/gui/mac/qt_menu.nib ./caret5.app/Contents/Resources } ubuntu { PRE_TARGETDEPS += \ ../caret_command_operations/libCaretCommandOperations.so \ ../caret_brain_set/libCaretBrainSet.so \ ../caret_files/libCaretFiles.so \ ../caret_uniformize/libCaretUniformize.so \ ../caret_statistics/libCaretStatistics.so \ ../caret_common/libCaretCommon.so \ ../caret_widgets/libCaretWidgets.so \ ../caret_cifti/libCaretCifti.so LIBS += \ -L../caret_command_operations -lCaretCommandOperations \ -L../caret_brain_set -lCaretBrainSet \ -L../caret_files -lCaretFiles \ -L../caret_uniformize -lCaretUniformize \ -L../caret_statistics -lCaretStatistics \ -L../caret_common -lCaretCommon \ -L../caret_widgets -lCaretWidgets \ -L../caret_cifti -lCaretCifti LIBS += $$VTK_LIBS LIBS -= -lvtkjpeg -lvtkpng -lvtkexpat -lvtkzlib LIBS += -ldl QTPLUGIN -= qgif qjpeg qtiff QMAKE_CXXFLAGS += -DUBUNTU contains( DEFINES, HAVE_MINC ) { LIBS += $$NETCDF_LIBS } } unix:!macx:!ubuntu { LIBS += \ -L../caret_command_operations -lCaretCommandOperations \ -L../caret_brain_set -lCaretBrainSet \ -L../caret_vtk4_classes -lCaretVtk4Classes \ -L../caret_files -lCaretFiles \ -L../caret_uniformize -lCaretUniformize \ -L../caret_statistics -lCaretStatistics \ -L../caret_common -lCaretCommon \ -L../caret_widgets -lCaretWidgets \ -L../caret_cifti -lCaretCifti LIBS += $$VTK_LIBS contains( DEFINES, HAVE_QWT ) { LIBS += $$QWT_LIBS } contains( DEFINES, HAVE_MINC ) { LIBS += $$NETCDF_LIBS } dll:LIBS -= -ldl dll:LIBS += -ldl } unix:!macx:release:!debug:!profile { QMAKE_POST_LINK=strip --strip-debug $(TARGET) } # Input HEADERS += global_variables.h \ CommunicatorClientAFNI.h \ CommunicatorClientFIV.h \ CommunicatorClientBase.h \ GuiAddCellsDialog.h \ GuiAlignSurfaceToStandardOrientationDialog.h \ GuiApplyDeformationMapDialog.h \ GuiAverageBorderDialog.h \ GuiAverageCoordinateDialog.h \ GuiAutomaticRotationDialog.h \ GuiBatchCommandDialog.h \ GuiBorderAttributesDialog.h \ GuiBorderComparisonDialog.h \ GuiBorderDrawUpdateDialog.h \ GuiBorderNamesListBoxSelectionDialog.h \ GuiBorderOperationsDialog.h \ GuiBorderProjectionDialog.h \ GuiBordersCreateInterpolatedDialog.h \ GuiBrainModelOpenGL.h \ GuiBrainModelOpenGLKeyEvent.h \ GuiBrainModelOpenGLMouseEvent.h \ GuiBrainModelOpenGLPopupMenu.h \ GuiBrainModelSelectionComboBox.h \ GuiBrainModelSurfaceSelectionComboBox.h \ GuiBrainModelViewingWindow.h \ GuiBrainSetAndModelSelectionControl.h \ GuiCaptureWindowImageDialog.h \ GuiCaretCommandDialog.h \ GuiCaretCommandScriptBuilderDialog.h \ GuiCaretCommandWidget.h \ GuiCaretTipsDialog.h \ GuiCategoryComboBox.h \ GuiCellAndFociAttributeAssignmentDialog.h \ GuiCellAndFociReportDialog.h \ GuiCellAttributesDialog.h \ GuiCellsOrFociProjectionDialog.h \ GuiChooseNodeAttributeColumnDialog.h \ GuiChooseSpecFileDialog.h \ GuiColorFileEditorDialog.h \ GuiColorFileEditorWidget.h \ GuiColorKeyDialog.h \ GuiColorSelectionDialog.h \ GuiCommaSeparatedValueFileEditor.h \ GuiCommunicatorClientConnectDialog.h \ GuiConnectivityDialog.h \ GuiContourAlignmentDialog.h \ GuiContourDrawDialog.h \ GuiContourReconstructionDialog.h \ GuiContourSectionControlDialog.h \ GuiContourSetScaleDialog.h \ GuiConvertDataFileDialog.h \ GuiCopySpecFileDialog.h \ GuiCurrentColoringToRgbPaintDialog.h \ GuiDataFileCommentDialog.h \ GuiDataFileImportOptionsDialog.h \ GuiDataFileMathDialog.h \ GuiDataFileOpenDialog.h \ GuiDataFileSaveDialog.h \ GuiDeformationFieldDialog.h \ GuiDeleteBordersByNameDialog.h \ GuiDisplayControlDialog.h \ GuiDisplayControlSurfaceOverlayWidget.h \ GuiDistortionDialog.h \ GuiDrawBorderDialog.h \ GuiFilesModified.h \ GuiFileDialogWithInstructions.h \ GuiFileSelectionButton.h \ GuiFileSelectionButtonAndLineEditWidget.h \ GuiFileSelectionListWidget.h \ GuiFociPalsProjectionDialog.h \ GuiFociSearchWidget.h \ GuiFociUncertaintyLimitsDialog.h \ GuiFlattenFullHemisphereDialog.h \ GuiFlattenHemisphereDialog.h \ GuiFlattenHemisphereInstructionsDialog.h \ GuiGenerateArealEstimationDialog.h \ GuiGenerateSulcalDepthDialog.h \ GuiGenerateSurfaceCurvatureDialog.h \ GuiGraphWidget.h \ GuiGraphWidgetDialog.h \ GuiHelpAssistantWindow.h \ GuiHelpViewerWindow.h \ GuiHistogramDisplayDialog.h \ GuiHtmlColorChooserDialog.h \ GuiHyperLinkTextBrowser.h \ GuiIdentifyDialog.h \ GuiImageEditorWindow.h \ GuiImageFormatComboBox.h \ GuiImageResizeDialog.h \ GuiImageViewingWindow.h \ GuiInflateAndSmoothFingersDialog.h \ GuiInflateSurfaceDialog.h \ GuiInterpolateSurfacesDialog.h \ GuiLoadedFileManagementDialog.h \ GuiMacOSXApplication.h \ GuiMainWindow.h \ GuiMainWindowAttributesActions.h \ GuiMainWindowAttributesMenu.h \ GuiMainWindowCommActions.h \ GuiMainWindowCommMenu.h \ GuiMainWindowFileActions.h \ GuiMainWindowFileMenu.h \ GuiMainWindowHelpActions.h \ GuiMainWindowHelpMenu.h \ GuiMainWindowLayersActions.h \ GuiMainWindowLayersMenu.h \ GuiMainWindowSurfaceActions.h \ GuiMainWindowSurfaceMenu.h \ GuiMainWindowTimingActions.h \ GuiMainWindowTimingMenu.h \ GuiMainWindowVolumeActions.h \ GuiMainWindowVolumeMenu.h \ GuiMainWindowWindowActions.h \ GuiMainWindowWindowMenu.h \ GuiMapFmriAtlasDialog.h \ GuiMapFmriDialog.h \ GuiMapFmriMappingSet.h \ GuiMapFmriMetricInfo.h \ GuiMapFmriSpecFileTopoCoordDialog.h \ GuiMapFmriThresholdDialog.h \ GuiMapFmriVolume.h \ GuiMapStereotaxicFocusDialog.h \ GuiMetricModificationDialog.h \ GuiMetricsToRgbPaintDialog.h \ GuiModelSelectionControl.h \ GuiModelsEditorDialog.h \ GuiMorphingDialog.h \ GuiMorphingMeasurementsDialog.h \ GuiMouseModePopupMenu.h \ GuiMultipleInputDialog.h \ GuiMultiresolutionMorphingDialog.h \ GuiNameSelectionDialog.h \ GuiNodeAttributeColumnSelectionComboBox.h \ GuiNodeAttributeFileClearResetDialog.h \ GuiLoadNodeAttributeFileColumnSelectionDialog.h \ GuiPaintColumnNamesListBoxSelectionDialog.h \ GuiPaintNameEditorDialog.h \ GuiPaletteColorSelectionDialog.h \ GuiPaletteEditorDialog.h \ GuiParamsFileEditorDialog.h \ GuiPreferencesDialog.h \ GuiPreviousSpecFileComboBox.h \ GuiRecordingDialog.h \ GuiResectionDialog.h \ GuiSectionControlDialog.h \ GuiSetTopologyDialog.h \ GuiSetViewDialog.h \ GuiShapeOrVectorsFromCoordinateSubtractionDialog.h \ GuiShellCommandWindow.h \ GuiSmoothingDialog.h \ GuiSpecAndSceneFileCreationDialog.h \ GuiSpecFileCreationDialog.h \ GuiSpecFileDialog.h \ GuiSpeciesComboBox.h \ GuiStandardMeshDialog.h \ GuiStereotaxicSpaceComboBox.h \ GuiStructureComboBox.h \ GuiStudyCollectionFileEditorDialog.h \ GuiStudyInfoEditorWidget.h \ GuiStudyMetaDataFileEditorDialog.h \ GuiStudyMetaDataLinkCreationDialog.h \ GuiSumsDialog.h \ GuiSurfaceDeformationDialog.h \ GuiSurfaceInformationDialog.h \ GuiSurfaceRegionOfInterestDialog.h \ GuiSurfaceRegionOfInterestDialogOLD.h \ GuiSurfaceSpmTransformDialog.h \ GuiSurfaceToVolumeDialog.h \ GuiSurfaceTopologyReportDialog.h \ GuiSurfaceTypeComboBox.h \ GuiTextBrowser.h \ GuiToolBar.h \ GuiToolBarActions.h \ GuiTopologyFileComboBox.h \ GuiTopologyTypeComboBox.h \ GuiTransformationMatrixDialog.h \ GuiTransformationMatrixSelectionControl.h \ GuiUserViewSaveDialog.h \ GuiVectorFileComboBox.h \ GuiVocabularyFileEditorDialog.h \ GuiVolumeAttributesDialog.h \ GuiVolumeBiasCorrectionDialog.h \ GuiVolumeCreateDialog.h \ GuiVolumeFileOrientationComboBox.h \ GuiVolumeFileSelectionComboBox.h \ GuiVolumeFileTypeComboBox.h \ GuiVolumeHandleFinderDialog.h \ GuiVolumePaintEditorDialog.h \ GuiVolumeReconstructionDialog.h \ GuiVolumeRegionOfInterestDialog.h \ GuiVolumeRescaleDialog.h \ GuiVolumeResizingDialog.h \ GuiVolumeSegmentationEditorDialog.h \ GuiVolumeSelectionControl.h \ GuiVolumeSelectionDialog.h \ GuiVolumeSureFitSegmentationDialog.h \ GuiVolumeThresholdSegmentationDialog.h \ GuiVolumeTopologyReportDialog.h \ GuiVolumeTypeComboBox.h \ GuiVolumeVoxelDataTypeComboBox.h \ GuiZipSpecFileDialog.h SOURCES += CommunicatorClientAFNI.cxx \ CommunicatorClientFIV.cxx \ CommunicatorClientBase.cxx \ GuiAddCellsDialog.cxx \ GuiAlignSurfaceToStandardOrientationDialog.cxx \ GuiApplyDeformationMapDialog.cxx \ GuiAutomaticRotationDialog.cxx \ GuiAverageBorderDialog.cxx \ GuiAverageCoordinateDialog.cxx \ GuiBatchCommandDialog.cxx \ GuiBorderAttributesDialog.cxx \ GuiBorderComparisonDialog.cxx \ GuiBorderDrawUpdateDialog.cxx \ GuiBorderNamesListBoxSelectionDialog.cxx \ GuiBorderOperationsDialog.cxx \ GuiBorderProjectionDialog.cxx \ GuiBordersCreateInterpolatedDialog.cxx \ GuiBrainModelOpenGL.cxx \ GuiBrainModelOpenGLKeyEvent.cxx \ GuiBrainModelOpenGLMouseEvent.cxx \ GuiBrainModelOpenGLPopupMenu.cxx \ GuiBrainModelSelectionComboBox.cxx \ GuiBrainModelSurfaceSelectionComboBox.cxx \ GuiBrainModelViewingWindow.cxx \ GuiBrainSetAndModelSelectionControl.cxx \ GuiCaptureWindowImageDialog.cxx \ GuiCaretCommandDialog.cxx \ GuiCaretCommandScriptBuilderDialog.cxx \ GuiCaretCommandWidget.cxx \ GuiCaretTipsDialog.cxx \ GuiCategoryComboBox.cxx \ GuiCellAndFociAttributeAssignmentDialog.cxx \ GuiCellAndFociReportDialog.cxx \ GuiCellAttributesDialog.cxx \ GuiCellsOrFociProjectionDialog.cxx \ GuiChooseNodeAttributeColumnDialog.cxx \ GuiChooseSpecFileDialog.cxx \ GuiColorFileEditorDialog.cxx \ GuiColorFileEditorWidget.cxx \ GuiColorKeyDialog.cxx \ GuiColorSelectionDialog.cxx \ GuiCommaSeparatedValueFileEditor.cxx \ GuiCommunicatorClientConnectDialog.cxx \ GuiConnectivityDialog.cxx \ GuiContourAlignmentDialog.cxx \ GuiContourDrawDialog.cxx \ GuiContourReconstructionDialog.cxx \ GuiContourSectionControlDialog.cxx \ GuiContourSetScaleDialog.cxx \ GuiConvertDataFileDialog.cxx \ GuiCopySpecFileDialog.cxx \ GuiCurrentColoringToRgbPaintDialog.cxx \ GuiDataFileCommentDialog.cxx \ GuiDataFileImportOptionsDialog.cxx \ GuiDataFileMathDialog.cxx \ GuiDataFileOpenDialog.cxx \ GuiDataFileSaveDialog.cxx \ GuiDeformationFieldDialog.cxx \ GuiDeleteBordersByNameDialog.cxx \ GuiDisplayControlDialog.cxx \ GuiDisplayControlSurfaceOverlayWidget.cxx \ GuiDistortionDialog.cxx \ GuiDrawBorderDialog.cxx \ GuiFilesModified.cxx \ GuiFileDialogWithInstructions.cxx \ GuiFileSelectionButton.cxx \ GuiFileSelectionButtonAndLineEditWidget.cxx \ GuiFileSelectionListWidget.cxx \ GuiFociPalsProjectionDialog.cxx \ GuiFociSearchWidget.cxx \ GuiFociUncertaintyLimitsDialog.cxx \ GuiFlattenFullHemisphereDialog.cxx \ GuiFlattenHemisphereDialog.cxx \ GuiFlattenHemisphereInstructionsDialog.cxx \ GuiGenerateArealEstimationDialog.cxx \ GuiGenerateSulcalDepthDialog.cxx \ GuiGenerateSurfaceCurvatureDialog.cxx \ GuiGraphWidget.cxx \ GuiGraphWidgetDialog.cxx \ GuiHelpAssistantWindow.cxx \ GuiHelpViewerWindow.cxx \ GuiHistogramDisplayDialog.cxx \ GuiHtmlColorChooserDialog.cxx \ GuiHyperLinkTextBrowser.cxx \ GuiIdentifyDialog.cxx \ GuiImageEditorWindow.cxx \ GuiImageFormatComboBox.cxx \ GuiImageResizeDialog.cxx \ GuiImageViewingWindow.cxx \ GuiInflateAndSmoothFingersDialog.cxx \ GuiInflateSurfaceDialog.cxx \ GuiInterpolateSurfacesDialog.cxx \ GuiLoadedFileManagementDialog.cxx \ GuiMacOSXApplication.cxx \ GuiMainWindow.cxx \ GuiMainWindowAttributesActions.cxx \ GuiMainWindowAttributesMenu.cxx \ GuiMainWindowCommActions.cxx \ GuiMainWindowCommMenu.cxx \ GuiMainWindowFileActions.cxx \ GuiMainWindowFileMenu.cxx \ GuiMainWindowHelpActions.cxx \ GuiMainWindowHelpMenu.cxx \ GuiMainWindowLayersActions.cxx \ GuiMainWindowLayersMenu.cxx \ GuiMainWindowTimingActions.cxx \ GuiMainWindowTimingMenu.cxx \ GuiMainWindowSurfaceActions.cxx \ GuiMainWindowSurfaceMenu.cxx \ GuiMainWindowVolumeActions.cxx \ GuiMainWindowVolumeMenu.cxx \ GuiMainWindowWindowActions.cxx \ GuiMainWindowWindowMenu.cxx \ GuiMapFmriAtlasDialog.cxx \ GuiMapFmriDialog.cxx \ GuiMapFmriMappingSet.cxx \ GuiMapFmriMetricInfo.cxx \ GuiMapFmriSpecFileTopoCoordDialog.cxx \ GuiMapFmriThresholdDialog.cxx \ GuiMapFmriVolume.cxx \ GuiMapStereotaxicFocusDialog.cxx \ GuiMetricModificationDialog.cxx \ GuiMetricsToRgbPaintDialog.cxx \ GuiModelSelectionControl.cxx \ GuiModelsEditorDialog.cxx \ GuiMorphingDialog.cxx \ GuiMorphingMeasurementsDialog.cxx \ GuiMouseModePopupMenu.cxx \ GuiMultipleInputDialog.cxx \ GuiMultiresolutionMorphingDialog.cxx \ GuiNameSelectionDialog.cxx \ GuiNodeAttributeColumnSelectionComboBox.cxx \ GuiNodeAttributeFileClearResetDialog.cxx \ GuiLoadNodeAttributeFileColumnSelectionDialog.cxx \ GuiPaintColumnNamesListBoxSelectionDialog.cxx \ GuiPaintNameEditorDialog.cxx \ GuiPaletteColorSelectionDialog.cxx \ GuiPaletteEditorDialog.cxx \ GuiParamsFileEditorDialog.cxx \ GuiPreferencesDialog.cxx \ GuiPreviousSpecFileComboBox.cxx \ GuiRecordingDialog.cxx \ GuiResectionDialog.cxx \ GuiSetTopologyDialog.cxx \ GuiSetViewDialog.cxx \ GuiShapeOrVectorsFromCoordinateSubtractionDialog.cxx \ GuiSectionControlDialog.cxx \ GuiShellCommandWindow.cxx \ GuiSmoothingDialog.cxx \ GuiSpecAndSceneFileCreationDialog.cxx \ GuiSpecFileCreationDialog.cxx \ GuiSpecFileDialog.cxx \ GuiSpeciesComboBox.cxx \ GuiStandardMeshDialog.cxx \ GuiStereotaxicSpaceComboBox.cxx \ GuiStructureComboBox.cxx \ GuiStudyCollectionFileEditorDialog.cxx \ GuiStudyInfoEditorWidget.cxx \ GuiStudyMetaDataFileEditorDialog.cxx \ GuiStudyMetaDataLinkCreationDialog.cxx \ GuiSumsDialog.cxx \ GuiSurfaceDeformationDialog.cxx \ GuiSurfaceInformationDialog.cxx \ GuiSurfaceRegionOfInterestDialog.cxx \ GuiSurfaceRegionOfInterestDialogOLD.cxx \ GuiSurfaceSpmTransformDialog.cxx \ GuiSurfaceToVolumeDialog.cxx \ GuiSurfaceTopologyReportDialog.cxx \ GuiSurfaceTypeComboBox.cxx \ GuiTextBrowser.cxx \ GuiTopologyTypeComboBox.cxx \ GuiToolBar.cxx \ GuiToolBarActions.cxx \ GuiTopologyFileComboBox.cxx \ GuiTransformationMatrixDialog.cxx \ GuiTransformationMatrixSelectionControl.cxx \ GuiUserViewSaveDialog.cxx \ GuiVectorFileComboBox.cxx \ GuiVocabularyFileEditorDialog.cxx \ GuiVolumeAttributesDialog.cxx \ GuiVolumeBiasCorrectionDialog.cxx \ GuiVolumeCreateDialog.cxx \ GuiVolumeFileOrientationComboBox.cxx \ GuiVolumeFileSelectionComboBox.cxx \ GuiVolumeFileTypeComboBox.cxx \ GuiVolumeHandleFinderDialog.cxx \ GuiVolumePaintEditorDialog.cxx \ GuiVolumeReconstructionDialog.cxx \ GuiVolumeRegionOfInterestDialog.cxx \ GuiVolumeRescaleDialog.cxx \ GuiVolumeResizingDialog.cxx \ GuiVolumeSegmentationEditorDialog.cxx \ GuiVolumeSelectionControl.cxx \ GuiVolumeSelectionDialog.cxx \ GuiVolumeSureFitSegmentationDialog.cxx \ GuiVolumeThresholdSegmentationDialog.cxx \ GuiVolumeTopologyReportDialog.cxx \ GuiVolumeTypeComboBox.cxx \ GuiVolumeVoxelDataTypeComboBox.cxx \ GuiZipSpecFileDialog.cxx \ main.cxx caret-5.6.4~dfsg.1.orig/caret/caret5.png0000664000175000017500000000732211572067322017554 0ustar michaelmichaelPNG  IHDR00WsBIT|dIDAThml[U=Inmn'8nt+ G̎"% H+@OJ0"H3#U+ ]TZhU+t-HC#$N$No%p}ݼ\_s^n_.8a(}LMfzz˲8/&uOɓqJYuU-֝8\$J'tƍ]0M۶0 4M ٶ8||x!wBFNsӋ,//"Gos7kTc@jqq˗/344CQB&凉zmLL!W҃8 ካxN4{M0::iW1BXVo]EQRkSVݣ?٪ƽ$Tݨ1韼 ޥ%BֺeYlll 0 Z[[Ik8 +YIZi#b BvkW5}<7 à\.ҢB 8PJSM-{*hqPm\4ROɯcdd$7oIJ,}|nndo'Rc˓D=" $@f%L]EǽY%28@\B@KK _q(d[.ӲƸR*JIz=Jf@U3̌Q__GPg7~OTBf. 5h>ƀ.4 )fd2[J(":׭XEP,@W^e߾}4C⋼ ?~ L*LFT:Z}_ c'H;mxa 1==*UL cqm^~e|Id!hPZW^M"V] JU6? x <1_52gx܅xLFEBcM"}uS8c&?0 * JEQ" JiU:q~Кtun,l5"OX!SKu-Rv^7+ɔǎ= /s @]-ym4MȜʐԒDB&_ŰmH$RVy+q677M__Gѣ!뮻zkl& w:w5ţ"+%` xxj߯EMov8i߯!Z󫌎?*Nr,:3g֣L6\H8$Q,LLLw}GGGߏ7_1??6hk׮j…a188_*I$R)K *a   U\.ŋ֥vg &`bbeb7 d,Nӣmvv6ʿU砂Pّ`ooZn mYkkk-}>\[u~3T*$q,BeY:)ؘ;W#SLyν& K- cgl{ɛaӇY[[cf&m۶PSدʍq|>Lv_ oe+@ٳgyw8q,K0K0$vt)cf  !bbb0e 0 Mb묬`Y>}|zSgiLHXcA)~|A"K"'k|>]T`)PMdD.Jtttp1fgg B\?z&:00[+W^zmJ)$g߾}{daz-tu GA(o) ioQUeEKKKivF1m twucpKs@an֖{ԝwI4q麟U]6IUFGG/'IENDB`caret-5.6.4~dfsg.1.orig/caret/caret5.ico0000664000175000017500000001454611572067322017550 0ustar michaelmichael(F n00V00h( xwxwwxwxwxwwxwxwxwwxwxpwwwww( @;3sspwwpw;3s7x31pww;1wwp333xwwwx37wwwwx{3;7wwwwwsq33;3wwwwwwx3;13wwwww337333wwwwwp3733wwwwwp33;3wwwwwx333wwwwwxs33;3wwwwwws333wwwww3wwwww3;3wwwwwp2wwwwwx33;2wwwwxs;32wwp;;333;"s3"32"232&""&#r '`?  ppp08x~(0` ʦ """)))UUUMMMBBB999|PP3f3333f333ff3fffff3f3f̙f3333f3333333333f3333333f3f33ff3f3f3f3333f3333333f3̙33333f333ff3ffffff3f33f3ff3f3f3ffff3fffffffff3fffffff3f̙ffff3ff333f3ff33fff33f3ff̙3f3f3333f333ff3fffff̙̙3̙f̙̙̙3f̙3f3f3333f333ff3fffff3f3f̙3ffffffffff!___www쒒mmrDmoEoooohmnEEEECnELLooDELuEL#DnE##$#DKL*t#sn#RRt#nDRSRRKJES222RJs$S222R#"tS22+tJmRS2SRRJmmRRS+RtRRSRRmQRRSL#tnsKz1$#LmJQL$#+RRRmmm)##*SRSSLRtKs"RSRRRSSRLt"smmmJQRRRLRR1SRKJ(ImmmmmnK*RSL#+SS+RP('rmmmmm#RL+LRL*R1*0(O!mmmmmmmmDLS+RttR++10..U'rmmmmmKRR+#*##RR1.-OO!mmmm#R2+##"#1R0).UOmmKRS+*RKK1RR/ONUOmmmmmms*S2RRLS22R/.UUUOmmmmm#SSSSSS22R(--UO'rmDS2211221..--O!mmmES,SSS121.4UO'rmmmES+$11#*XQ.4UO!mmDRS1S1+17/.3UOI*SSSSS11/O4U'rKRSSS1Y0(O-O'#RRXR0)!OO'In"Q//('IO!I(POP!'OII'OO''I!!IOOBmr!!!(0`pwwwpwppwwpxwwwpxwwwwwwwwwwwpwwwxpwwxxwwwwxwxwpwxxxwxwxwpwwwxxwwwwwwxx3wwwwwwwwxppwwwwwxwwwwwxxPwwpwwwwxxxxpwwwwwwww8wwwpwxwwwwwww1xwwwxpwwwwwww38wxwxpppxp8wwpp;33wps;3pspps;3wxw8wxpw31pp;1xx333x38sp3;88p33;3203;132(x338333#pxp38s33"33;3""'333""(33;3""(333""(xpq3""(xps3;3""'s2"s33;2 p;32*"x;;33*(w3;""'q3"" p32"bp232&h""&#ppx (>N~~~~~~`?? ?? ppp08x~/?caret-5.6.4~dfsg.1.orig/caret/caret5.icns0000664000175000017500000015211511572067322017725 0ustar michaelmichaelicnsMics#H` =}y}s!~ ` =}y}s!~ is32T  iH Utga  x}Wh! gp^"Y@ |kSt3H }U]1T ٶʪʪ׹ K,͂ Ϣg+W ߾һ۠`i1 UtgaЂ x}Wy] gp^V]; zkSt3m&Z U^Lb ٶʪym׹ -͂ Ϣu'_ ߾һ۠  l( Utgc  x}W% gp^  E {kSt3  U],kH3 ٶʪ ׹  ,͂ Ϣv(a ߾һ۠s8mk!C;vX;~'ZICN#<~??????8??1<~??????8??1il32w" I $L9  e 9}p_sYjl mrze_t[D+'Ƈ HhtL^cP uutX mrNe&R4q3 Y^{K I>7Asʁich#H?@`>?@`>ih32Xut   #  ߡ     W0  s ΓxaciG uNkR]rPUn RM^uZR}ToW54}  `UTtzjgu_a e >^v}ffFffrw Ћ ]i{qU52JN6 ^uxSw|;VJgՁ2g ! ocPDfvEHPT} & }v]WqTJ[>f  hhw}q{]W݁#~Y?"ZoSG~{ihy6k  qizS]dWuKl@ҷȴw $m{h}kpSogtsO3_H\  \wnsaci}_Xd>p\ igBjajdmSP' ~gWU]n^Wl1@N.8Vz @e jHWtR $ i PT䀠 Pލ֤>4߷|zN ^'Ҁ|NJ .  )ܗrǕԉ%ٟơKe¥ر&܎ƙ˷ÜǴժ@ۆ&ֹĮ׏ږR ̖͔֧ʓ#Jعd}:,ͧ$ۖϓfµߊ&Ώ1ٺu”יߘж޲$ӫ5zg`+%AV,=׵ߌ ݶ~wnԔߠܨ ˑƖۑ!ɲõߜӫƞܳ˶ꔹ㕑޹ȰГֵ͒ԭԼĪݕܕ鿁ׁ q` E0o s'ߡ У A[ó D]c˓xaci 1i˻ uNkR]rPUn`ͯV RM^uZR}ToW.mM@ `UTtzjgu_a_ >^v}ffFffrwiήU׋ ]i{qU52JNE{˴ٻ3 ^uxSw|;VJgՁxղ] ocPDfvEHPTyWdvfո }v]WqTJ񉒚3"B}RtȌ hhw}q{]W݁鎐8U^LD;"ZoSG~{ihy6k`jh qizS]dWuKl9si3ulv$jzh}kpSogtsO37En'1[ ltnsaci}_XdB} IȠd Y rgBjajdmSMs| gWUYk^WYGp~)N.7Vz F}@MGUyV +m] k .K倠 PJ|֤?3{ZzO ^'tbwQ ZO   ܗ>Ǖԉ%ٟ`y2ne¤ر&܎ƙ˷ÜǴڨ, ۆ&ֹĮ׏Ι͔&֧ʓ#<.ͧ$ۖϓ {aµߊ&Ώ1 lڙיߘж޲$ӫ4tuwl'!I`.=׵ߌ ݶ~vmԔߠܨ ˑ’ۑ!ɲõߜӫƞܳ˶ꔹ㕑޹ȰГֵ͒ԭԼĪݕܕ鿁ׁy w  -   ߡ         ̓xadl )    uNkR]rRWp RM^uZR}VqY 4   `UTtzjgubc  a >^v}ffFffrw    ڋ ]i{qU52JN    ^uxSw|;VJgՂ  % ocPDfvEHPT  ( }v]WqTJ    ) hhw}q{]W݁    E"ZoSG~{ihy6k    qizS]dWuKl2  $j{h}kpSogtsO3    funsaci}_XdF   Y ogBjajdmSQ  ! gWU[k^W  h,N/9W| K J[|Y ## gk yl)I} PX֤?4* 4xN^& 2~ P <   & ܗ Ǖԉ%ٟ  bú¤ر&܎ƙ˷ÜǴ٩"ۆ&ֹĮ׏ޚ ę͔&֧ʓ"  :-ͧ$ۖϓ g`µߊ&Ώ1em Ֆיߘж޲$ӫ5ww}g(&Fa*=׵ߌ ݶvoԔߠܨ ˑÓۑ!ɲõߜӫƞܳʶꔹ㕑޹ȰГֵ͒ԭԼĪݕܕ鿁ׁh8mk U[p)i!#0b1Y4CuIst-<(HV:E A#wW KpJw9oP$Ed>c<;af-o P1W}'Z _ it32g շ E)?ۂ a(   5 #  @     U )  #I  5x     C    jW    %     +   $   j|!?yL   r W0    v$5*  EJ! Bs  " ̌$+A3   -󟠀NTjỉ l  ѸZ^_VEns]A&[*-V   іJ\lpZO^wzgWnG/L]m)3  ژuHHUckgRaXclrnKP`?jrn݆)#QHT~96U_dQKRTZPSoxeaoQ9nU_ep-ߙ~gp7HNiyoOZdZW}h]i`{yrBEmvilS@$͂W qaEsMHcQkwuzZ[^GO}S6T~`bWυ*5F4u74%   P{IcqiTSo]]ymcjtkJWZ+SuPH\X$r&$Rڍd)D. uUbep@`han{N`{kxzNDe_+ԑ\7  rKjRL_bixxpVDLfZQn{eD?wdRۅ.]n44;KJCepsvt^;L~aQUE==h|d~bK#  O jL>[\aTv}sffkfxwFao\mfDTrwzu )  $!7B/@]pw`qmsyRcG5rRTupfӇu8   $!bBDPLk]ngl[SeKbV^tuvotyr&BM   7 m]Mxi{{}q~UD;.;2aJUmxWNof-\l  A ygmf[rrx]lmlT1kTF}t{Z^gP    O ҕkkyolvULdj6drkl\/R~ɤH'C   B"Nopv]g]{j^^Q`q~MT`c0dl/1&{[ cnfn"pvC  9!b}e_zKWbh~ce\ccSSexSYkUuphlj/-T]y Y^"KXο3    8 gjeZ^e^Qxep^g|k{u~bEJX\|ԉ/2L)9nx9?a   E!pp^_rPobjtiykyC_[Vv/2|56n%   ԟ!n\h{rN?krNZeouiLo{mgWP|_Y.(.Į5eҵwg $!ZwgRSPDGMt{d[ixnbly\6sO\;`/K,噡矬1   E"b\yh[[^c\IAU{zX}nahL]jR~ ׄ/)+РΨ袸 "`uka^poWI9܉ͩб\wi(݅u  M'qm{wgss{RFO[q}o`J|hiU@YswQI :,I ( TX^aiphZkloZQGPekvr{e}viTg`e`QO ='RRy O \mosnosaIQccjitx}b]oXe3d >AZ@Gw \"sXumyfh[Rt|VGb{s[|zhw0\#[|AWjkc_yn^tr~DdmQKvtwcU~jم-[65♤ځ LRzYBg]B,JuOay[Edy}mLMX)6ÝZ 'm݀ќ\W@mft]faN]ZE[gU]`!I^͋C䚅j}jIOdSGWYQNfWX]W忉+L+eֺ4 |ꗩzh Q"5ˎy 8Ӫ(. KDr bUu0蕅 . ⯉l% !ZɃ6 ɨ= N  2J U?d \]$.n eD" )] N |Iu"e)*Ѿ$$lhŴӯږ'sQŤҢ ܝ(+ ǖԝ 䏍أ͹+Jɝ?˓К/Ռ㺭զ.Mt[qݵ¯඘eΏٞԩų"mVXߩлǨЖP񩍳қšºͷԟ̸M 2@\6œ׵ߖg됖ڭм˸ÚӴݼu@*Ț*کѦەh씔شѵЖ™ůιѷȨ޲v:ǔ_2ת¤g̼ɔѮڴƹϘo Dz4ĦϘf쵱ãҾƞ̮ý᲏ڲnNӇR@B Ȗ߷Ϊ⺖d鮒ؕఴѲןƻڞd=>"M[5_TB[]ۜfⓕǻ٢߲B/Gg@>!$uɗűfγȺً̝̺8p񨂋Hsut̛ڸݗeܴdzſѦ˙TS@U垮2<ԡbΧ՞ΜS9}c&¸çaȽ™!gޕ ­ͮẖh槮͔ܾ«4_Ԋ̨evGA—ݼiϙΕb8굜٧ЩuZӱf]Ӟ߫Э͢ƙcܵSRධծlΥ3uŔfY TɛșثпˮKfyx¹F?fJ'1sśɘܧԀU; ;WUWqP( EJ1! &DjƔȨ˸ף٦VΓֶĊ[  +Tw`bXUȡžԿ۾ǖW횒ȤӨ~ywvpnv寘ԳϮըˑǔ!񤏒νķ3ԯܫԜőȘό㶐1֦͖ܲӝءѣ ̠1ܬ߹Ʊ㷐9ٮ׵ܕסͬˣ ̡GԜƗٯԭZɘ˷îͥƱӝͨƲY׸٠я’༏дѥФTշ¤ꓗЦ㼓Լ࿛¶Źퟒ̮ǽ͖ȔȾӸ0멕˨Ӛ̻ջϝŵׄ"Мٴ˱ϡ æȰ߇˴۴̀ʩӮކգ۹úͿٰ ޵ ϼ̰͸βІ 潑鿉Ȣ׊ᣞ̌̚ г N =^&IsC  T"_ЯBNS3 ??`SpԺbAKoqԧ+uВvOaFEpjx0 G{L Nroąln}dn)/ AѮ!LЇu M!ms2Zo'fN$þЎ :k:rl"/r&ʒCҖvt%oinq|3UΧ^-_cjnnllsys^hr qˤ v Asc[ł%{ c$2Krde E̫[r">$TLk Jg0IL DDvDȞ )"vB[ƅ+󟠀NTjỉ%j_|zѸZ^_VEns]A&[*%&ra3іJ\lpZO^wzgWnG/L]mhuÈ˒5ژuHHUckgRaXclrnKP`?jrn݆)#)EřVH~96U_dQKRTZPSoxeaoQ9nU_ep-ߜ]\Ԫ7p7HNiyoOZdZW}h]i`{yrBEmvilS-;MnD#OvhnΑ IaEsMHcQkwuzZ[^GO}S6T~`bWυ*."p>rf̧@J{IcqiTSo]]ymcjtkJWZ+SuPH\X*?h9p^W"(\‘D uUbep@`han{N`{kxzNDe_ԝU^-{Y»IrKjRL_bixxpVDLfZQn{eD?wdRۅiUC]L';KJCepsvt^;L~aQUE==h|d~ dY2\_\ jL>[\aTv}sffkfxwFao\mfDTrwzu ^h5ʸΧɎUT!7B/@]pw`qmsyRcG5rRTupfӇ Aj!Ѓ8gk/!bBDPLk]ngl[SeKbV^tuvotyr(n%sţ4 ҕkkyolvULdj6drkl\/TciEL~W](dkNfOۼǜD;"Nopv]g]{j^^Q`q~MT`c0dl/1 LS3 8KB=}D\Hdj!b}e_zKWbh~ce\ccSSexSYkUuphlj/]1g51!26U~nyӆW_ىU gjeZ^e^Qxep^g|k{u~bEJX\|ԉ/[ /=11&1DYn9u̞TO\P]2!pp^_rPobjtiykyC_[Vv/cJ _?JvYaddԐhDԤۻ9ԟ!n\h{rN?krNZeouiLo{mgWP|_Y./kq[ =cpqRnxm@WhdP"jqsw[jzeSMGspdhhR]rsuXDSnl+W09as~Uis3@Wul>vS~ϿռE$rxaVrrD^_aoT[U[|fmmP[XF5`Z~Ip^`6D\CPn]]p5קgA2bslsuira}^coPQs^Mayyop<9JEM~Tn%[ua:{>w9G'`dyygss{RFO[q}o`J|hiU@YswQI :,VEpY X^aJk[XZ]gohZkloZQGPekvr{e}viTg`e`QO =,9eB4x`l/X ltm{snosaIQccjitx}b]oXe3d B25g be-GFpXY"}kTumyfh[Rt|VGb{s[|zhw0\%X*g{mpLZpM Pڈ^mhc_yn^tr~EdmQKvtwcU~jم-h a} y_qpAwW#(F`^Bg]B,JtNay[Edy}mLMX) }[seW"cـӚy\W@mft]c^KZZE[gU]`,:C o~8{qG䜂j}jIOdSHWTMIaWX]W忉+H>Pn^=5E ]]PH?^[Jn_PHtahhW׍(,~,Gttc` KOiRgVFymP{itxy5cGH N[ ˰|_N{x.G86QVzlb#FOpW@ MoMquWg|S.CnU`z\rdr#':eygJ}CJ~gάEc}nHDzoqrwda${ZR9 Jcjړ*GVk?WyfdV`_#+Ndw~=H蟸 ЯO0/79Ei"NE_2?rYO2Mx#QUuC ճ itWTAQt!%:pjq^$P%0J] %r GMpyj Rgcx3o& ?ֹ3 {Z쐡zh&U .iăAժ(. LDo^skn@r/ 蕅 0t vaMo! '[ёgxa Q Z OQDrJ|_ 1c%J lw)U_+y}Lt ?Bp2ֿ$& rDb˶үږ'{)i\ƣӢ ܝ(Fs ǖԝ 䏍أ͹+/iPVɔК/Ռ㺭զ.LOjOfDf9h۳¯඘eΏٞԩųqe 52cߩлǨЖP񩍳қšºͷԟʳIckg&/aBœ׵ߖg됖ڭм˸ÚӴ߼ !##U,٩Ѧەh씔شѵЖ™ůιѷȪ߯n   ת¤g̼ɔѮڴƹѣh L# òĦϘf쵱ãҾƞ̮ý᲏Ξ[ D>͠ӸΪ⺖d鮒ؕఴѲןƻbNUm=Xr!Wd՞fⓕǻ٢ܪEU qr )uɗűfγȺ̝̺ہ!  P+v@^y)v̛ڸݗeܴdzſѦ˙Rd2cA 4>ԡ>Χ՞ΜT>>    {(¸çaȽ™" ĭͮẖ:槮͔ܾ«4^u (*2HC—ݼiϙΕb7 >b2٥i_Ӟ߫Э͢ƙcܵSRܻ"GxҷEuÝzsgX UɛșثпˮKdʲwɠL $WG%1sśɘܧԀU? 7KccmQ5! :F8%  '[\aTv}sffkfxwFao\mfDTrwzu      !7B/@]pw`qmsyRcG5rRTupfӇ  #  +ª!bBDPLk]ngl[SeKbV^tuvotyr ( %   > m]Mxi{{}q~UD;.;2aJUmxWNof-    9 ygmf[rrx]lmlT1kTF}t{Z^gV      M ҕkkyolvULdj6drkl\/Y  1    @"Nopv]g]{j^^Q`q~MT`c0dl/4  1    ;!b}e_zKWbh~ce\ccSSexSYkUuphlj/'  -x2   4 gjeZ^e^Qxep^g|k{u~bEJX\|ԉ/$ 6>     ,  K!pp^_rPobjtiykyC_[Vv/  +    *ԟ!n\h{rN?krNZeouiLo{mgWP|_Y.7 $        !ZwgRSPDGMt{d[ixnbly\6sO\;`/c         I"b\yh[[^c\IAU{zX}nahL]jR~ ׄ/B    ")     "`uka^poWI   -    fsn|snosaIQccjitx}b]oXe3d FM   %5    Y"mUumyfh[Rt|VGb{s[|zhw0_0   _4   ZVhjc_yn^tr~EdmQKvtwcU~jم'`( 1Q   bV_Bg]B,JtNay[Edy}mLMX)   & !eЙ\W@mft]d_M[ZE[gU]`,%&      O䜈j}jIOdSHWUNJbWX]W忉+M,     \]PH?_\Kn`QIu`hhW׍( 2%   V^) OQiRgVGznQ|jtxy    ư|_N{x/J:8SW|mb#K )  wvWgW1FqXc}_tdr#,AE#  %{̬ DcrLH~suvydakE!  G€ސ-J\qE[|igYb_##PA g蠻 бS41: 8PbfxU+ ;G1 $@jƔȨ˸ף٦VΓֶNjV"+X{icSMwxȡžԿ۾ǖW횒ȤѦywupo{诖ԳϮըˑǔ%񤏒νķ/޶ܫԜőȘό㶐4դ͖ܲӝءѣ ̠ب&߹Ʊ㷐0ٮ׵ܕסͬˣ ̡0ԜƗٯԭZɘ˷îͥƱӝͨƲY׸٠я’༏дѥФTշ¤ꓗЦ㼓Լ࿛¶Źퟒ̮ǽ͖ȔȾӸ0멕˨Ӛ̻ջϝŵׄ"Мٴ˱ϡ æȰ߇˴۴̀ʩӮކգ۹úͿٰ ޵ ϼ̰͸βІ 潑鿉Ȣ׊ᣞ̌̚t8mk@anUh9 r(x6q8 $ CZ ipao!s)}G T3 Ic=& |r?CAMpq(G|2b !0~zb13U1`4"?Y `0 )3/ɯ &F0h@_%b8u3N7I7&U-dW Z`- #include #include #include #include #include #include #include #include #include #include "GuiChooseSpecFileDialog.h" #include "GuiZipSpecFileDialog.h" #include "SpecFileUtilities.h" #include "StringUtilities.h" #include "WuQFileDialog.h" /** * constructor. */ GuiZipSpecFileDialog::GuiZipSpecFileDialog(QWidget* parent, PreferencesFile* pref) : WuQDialog(parent) { preferencesFile = pref; setWindowTitle("Zip Spec File"); // // Get the layout // QVBoxLayout* dialogLayout = new QVBoxLayout(this); // // Grid layout for dialog items // QGridLayout* grid = new QGridLayout; dialogLayout->addLayout(grid); grid->setMargin(5); const int lineEditWidth = 350; // // Spec File // QPushButton* specButton = new QPushButton("Zip This Spec File..."); specButton->setAutoDefault(false); QObject::connect(specButton, SIGNAL(clicked()), this, SLOT(slotSpecFileButton())); specFileLineEdit = new QLineEdit; specFileLineEdit->setReadOnly(true); specFileLineEdit->setMinimumWidth(lineEditWidth); specFileLineEdit->setToolTip( "Spec File that will be zipped."); // // Zip File // QPushButton* zipButton = new QPushButton("Create This Zip File..."); zipButton->setAutoDefault(false); QObject::connect(zipButton, SIGNAL(clicked()), this, SLOT(slotZipFileButton())); zipFileLineEdit = new QLineEdit; zipFileLineEdit->setMinimumWidth(lineEditWidth); zipFileLineEdit->setToolTip( "Name of ZIP file that will be created."); // // Unzip directory // QLabel* unzipLabel = new QLabel("Unzips to Subdirectory"); unzipDirLineEdit = new QLineEdit; unzipDirLineEdit->setMinimumWidth(lineEditWidth); unzipDirLineEdit->setToolTip( "When the user unzips the ZIP file,\n" "the Spec File and its data files\n" "will be placed in this subdirectory."); // // Add widgets to grid // grid->addWidget(specButton, 0, 0, Qt::AlignLeft); grid->addWidget(specFileLineEdit, 0, 1); grid->addWidget(zipButton, 1, 0, Qt::AlignLeft); grid->addWidget(zipFileLineEdit, 1, 1); grid->addWidget(unzipLabel, 2, 0, Qt::AlignLeft); grid->addWidget(unzipDirLineEdit, 2, 1); // // Dialog buttons // QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Apply | QDialogButtonBox::Close); dialogLayout->addWidget(buttonBox); QPushButton* applyButton = buttonBox->button(QDialogButtonBox::Apply); QObject::connect(applyButton, SIGNAL(clicked()), this, SLOT(slotApplyButton())); QObject::connect(buttonBox, SIGNAL(rejected()), this, SLOT(close())); } /** * destructor. */ GuiZipSpecFileDialog::~GuiZipSpecFileDialog() { } /** * called when apply button is pressed. */ void GuiZipSpecFileDialog::slotApplyButton() { // // Check parameters // const QString specFileName(specFileLineEdit->text()); if (specFileName.isEmpty()) { QMessageBox::critical(this, "ERROR", "Spec File name is empty."); return; } QString zipFileName(zipFileLineEdit->text()); if (zipFileName.isEmpty()) { QMessageBox::critical(this, "ERROR", "Zip File name is empty."); return; } const QString unzipDirName(unzipDirLineEdit->text()); if (unzipDirName.isEmpty()) { QMessageBox::critical(this, "ERROR", "Unzip directory name is empty."); return; } if (QFile::exists(specFileName) == false) { QMessageBox::critical(this, "ERROR", "Spec File does not exist."); return; } // // Add zip file extension (if needed) // if (StringUtilities::endsWith(StringUtilities::makeLowerCase(zipFileName), ".zip") == false) { zipFileName.append(".zip"); zipFileLineEdit->setText(zipFileName); } // // Warn user if zip file already exists // if (QFile::exists(zipFileName)) { std::ostringstream str; str << "The ZIP file " << zipFileName.toAscii().constData() << "\n" << " already exists.\n" << "Do you want to overwrite it?"; if (QMessageBox::question(this, "Overwrite", str.str().c_str(), (QMessageBox::Yes | QMessageBox::No), QMessageBox::No) == QMessageBox::No) { return; } QFile::remove(zipFileName); } showWaitCursor(); // // Zip the spec file // QString errorMessage; const bool errorFlag = SpecFileUtilities::zipSpecFile(specFileName, zipFileName, unzipDirName, errorMessage); showNormalCursor(); if (errorFlag) { QMessageBox::critical(this, "ERROR", errorMessage); return; } QMessageBox::information(this, "Success", "ZIP file has been created."); } /** * called when spec file button is pressed. */ void GuiZipSpecFileDialog::slotSpecFileButton() { // // Choose the spec file to be copied // GuiChooseSpecFileDialog csfd(this, preferencesFile, true); if (csfd.exec() == GuiChooseSpecFileDialog::Accepted) { specFileLineEdit->setText(csfd.getSelectedSpecFile()); } } /** * called when zip file button is pressed. */ void GuiZipSpecFileDialog::slotZipFileButton() { // // Create a zip file dialog to select the zip file. // WuQFileDialog zipFileDialog(this); zipFileDialog.setModal(true); zipFileDialog.setDirectory(QDir::currentPath()); zipFileDialog.setAcceptMode(WuQFileDialog::AcceptSave); zipFileDialog.setWindowTitle("Choose Zip File"); zipFileDialog.setFileMode(WuQFileDialog::AnyFile); zipFileDialog.setFilters(QStringList("Zip File (*.zip)")); if (zipFileDialog.exec() == WuQFileDialog::Accepted) { if (zipFileDialog.selectedFiles().count() > 0) { zipFileLineEdit->setText(zipFileDialog.selectedFiles().at(0)); } } } caret-5.6.4~dfsg.1.orig/caret/GuiVolumeVoxelDataTypeComboBox.h0000664000175000017500000000344311572067322024053 0ustar michaelmichael #ifndef __GUI_VOLUME_VOXEL_DATA_TYPE_COMBO_BOX_H__ #define __GUI_VOLUME_VOXEL_DATA_TYPE_COMBO_BOX_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "VolumeFile.h" /// class for selecting a volume voxel data type class GuiVolumeVoxelDataTypeComboBox : public QComboBox { Q_OBJECT public: // constructor GuiVolumeVoxelDataTypeComboBox(const bool showUnknown = false, QWidget* parent = 0); // destructor ~GuiVolumeVoxelDataTypeComboBox(); // get the volume voxel data type VolumeFile::VOXEL_DATA_TYPE getVolumeVoxelDataType() const; // set the volume voxel data type void setVolumeVoxelDataType(const VolumeFile::VOXEL_DATA_TYPE vt); protected: /// the volume types in the combo box std::vector types; }; #endif // __GUI_VOLUME_VOXEL_DATA_TYPE_COMBO_BOX_H__ caret-5.6.4~dfsg.1.orig/caret/GuiVolumeVoxelDataTypeComboBox.cxx0000664000175000017500000000400711572067322024423 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "GuiVolumeVoxelDataTypeComboBox.h" /** * constructor. */ GuiVolumeVoxelDataTypeComboBox::GuiVolumeVoxelDataTypeComboBox(const bool showUnknown, QWidget* parent) : QComboBox(parent) { // // Get the volume types // std::vector names; VolumeFile::getAllVoxelDataTypesAndNames(types, names, showUnknown); for (unsigned int i = 0; i < types.size(); i++) { addItem(names[i]); } } /** * destructor. */ GuiVolumeVoxelDataTypeComboBox::~GuiVolumeVoxelDataTypeComboBox() { } /** * get the volume type. */ VolumeFile::VOXEL_DATA_TYPE GuiVolumeVoxelDataTypeComboBox::getVolumeVoxelDataType() const { const int item = currentIndex(); if ((item >= 0) && (item < static_cast(types.size()))) { return types[item]; } return VolumeFile::VOXEL_DATA_TYPE_UNKNOWN; } /** * set the volume type. */ void GuiVolumeVoxelDataTypeComboBox::setVolumeVoxelDataType(const VolumeFile::VOXEL_DATA_TYPE vt) { for (unsigned int i = 0; i < types.size(); i++) { if (types[i] == vt) { setCurrentIndex(i); break; } } } caret-5.6.4~dfsg.1.orig/caret/GuiVolumeTypeComboBox.h0000664000175000017500000000330311572067322022236 0ustar michaelmichael #ifndef __GUI_VOLUME_TYPE_COMBO_BOX_H__ #define __GUI_VOLUME_TYPE_COMBO_BOX_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "VolumeFile.h" /// class for selecting a volume type (anatomy, functional, etc) class GuiVolumeTypeComboBox : public QComboBox { Q_OBJECT public: // constructor GuiVolumeTypeComboBox(const bool showUnknown = false, QWidget* parent = 0); // destructor ~GuiVolumeTypeComboBox(); // get the volume type VolumeFile::VOLUME_TYPE getVolumeType() const; // set the volume type void setVolumeType(const VolumeFile::VOLUME_TYPE vt); protected: /// the volume types in the combo box std::vector types; }; #endif // __GUI_VOLUME_TYPE_COMBO_BOX_H__ caret-5.6.4~dfsg.1.orig/caret/GuiVolumeTypeComboBox.cxx0000664000175000017500000000362511572067322022620 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "GuiVolumeTypeComboBox.h" /** * constructor. */ GuiVolumeTypeComboBox::GuiVolumeTypeComboBox(const bool showUnknown, QWidget* parent) : QComboBox(parent) { // // Get the volume types // std::vector names; VolumeFile::getAllVolumeTypesAndNames(types, names, showUnknown); for (unsigned int i = 0; i < types.size(); i++) { addItem(names[i]); } } /** * destructor. */ GuiVolumeTypeComboBox::~GuiVolumeTypeComboBox() { } /** * get the volume type. */ VolumeFile::VOLUME_TYPE GuiVolumeTypeComboBox::getVolumeType() const { const int item = currentIndex(); if ((item >= 0) && (item < static_cast(types.size()))) { return types[item]; } return VolumeFile::VOLUME_TYPE_UNKNOWN; } /** * set the volume type. */ void GuiVolumeTypeComboBox::setVolumeType(const VolumeFile::VOLUME_TYPE vt) { for (unsigned int i = 0; i < types.size(); i++) { if (types[i] == vt) { setCurrentIndex(i); break; } } } caret-5.6.4~dfsg.1.orig/caret/GuiVolumeTopologyReportDialog.h0000664000175000017500000000446011572067322024021 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_VOLUME_TOPOLOGY_REPORT_DIALOG_H__ #define __GUI_VOLUME_TOPOLOGY_REPORT_DIALOG_H__ #include #include "WuQDialog.h" class QLabel; class QTextBrowser; /// Dialog for displaying a volume topology error report class GuiVolumeTopologyReportDialog : public WuQDialog { Q_OBJECT public: /// constructor GuiVolumeTopologyReportDialog(QWidget* parent); /// destructor ~GuiVolumeTopologyReportDialog(); /// show the dialog (overrides QDialog's show()) virtual void show(); protected slots: /// called when apply button pressed void slotApplyButton(); /// called when close button pressed void slotCloseButton(); protected: /// clear the dialog's data void clearDialog(); /// set the label with green if the value is correct, else red. void setLabel(QLabel* label, const int value, const int correctValue); /// number of cavities label QLabel* numberOfCavitiesLabel; /// number of objects label QLabel* numberOfObjectsLabel; /// euler count label QLabel* eulerCountLabel; /// numbe of holes label QLabel* numberOfHolesLabel; /// default label value QString defaultLabelValue; /// text browser for information QTextBrowser* infoTextBrowser; }; #endif // __GUI_VOLUME_TOPOLOGY_REPORT_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiVolumeTopologyReportDialog.cxx0000664000175000017500000001730411572067322024375 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include "BrainModelVolume.h" #include "BrainSet.h" #include "GuiMainWindow.h" #include "GuiVolumeTopologyReportDialog.h" #include "QtUtilities.h" #include "VolumeFile.h" #include "global_variables.h" /** * constructor. */ GuiVolumeTopologyReportDialog::GuiVolumeTopologyReportDialog(QWidget* parent) : WuQDialog(parent) { setWindowTitle("Topology Error Report"); defaultLabelValue = " "; // // Layout for dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(3); // // number of cavities items // QLabel* cavitiesLabel = new QLabel("Number of Cavities "); numberOfCavitiesLabel = new QLabel(defaultLabelValue); // // number of objects items // QLabel* objectsLabel = new QLabel("Number of Objects "); numberOfObjectsLabel = new QLabel(defaultLabelValue); // // euler count items // QLabel* eulerLabel = new QLabel("Euler Count"); eulerCountLabel = new QLabel(defaultLabelValue); // // number of holes items // QLabel* holesLabel = new QLabel("Number of Handles "); numberOfHolesLabel = new QLabel(defaultLabelValue); // // Group box for results // QGroupBox* reportGroupBox = new QGroupBox("Results"); dialogLayout->addWidget(reportGroupBox); QGridLayout* reportLayout = new QGridLayout(reportGroupBox); reportLayout->addWidget(cavitiesLabel, 0, 0); reportLayout->addWidget(numberOfCavitiesLabel, 0, 1); reportLayout->addWidget(objectsLabel, 1, 0); reportLayout->addWidget(numberOfObjectsLabel, 1, 1); reportLayout->addWidget(eulerLabel, 2, 0); reportLayout->addWidget(eulerCountLabel, 2, 1); reportLayout->addWidget(holesLabel, 3, 0); reportLayout->addWidget(numberOfHolesLabel, 3, 1); // // Info text browser // infoTextBrowser = new QTextBrowser; QString infoText = "" "Number of Cavities
    " "Number of cavities is the number of contiguous enclosed regions in the " "with voxels equal to zero. " "

    " "Number of Objects
    " "Number of objects is the number of disjoint (unconnected) pieces of voxels. " "If there is more than one object, all but the largest object can be removed " "using Volume Menu:Segmentation:Remove Islands." "

    " "Euler Count
    " "An Euler Count is a formula that tells us if the voxels will form a closed surface " "after reconstruction. A 3D closed surface will have an Euler count of 2. More " "information about the Euler count is available at " "http://mathworld.wolfram.com/EulerCharacteristic.html." "

    " "Number of Handles
    " "The number of handles is derived using the Euler count. If there is more than one " "object or cavities, the number of holes may be incorrect. " "The formula used is Nodes - Links + Triangles = 2 - (2 * number_of_holes). " "The number of holes is also known as the genus. See " "http://mathworld.wolfram.com/Genus.html for more information. " "

    " ""; infoTextBrowser->setHtml(infoText); // // Help information box // QGroupBox* helpBox = new QGroupBox("Information"); dialogLayout->addWidget(helpBox); QVBoxLayout* helpLayout = new QVBoxLayout(helpBox); helpLayout->addWidget(infoTextBrowser); // // Layout for buttons // QHBoxLayout* buttonLayout = new QHBoxLayout; buttonLayout->setSpacing(5); dialogLayout->addLayout(buttonLayout); // // Apply button // QPushButton* applyButton = new QPushButton("Apply"); applyButton->setAutoDefault(false); buttonLayout->addWidget(applyButton); QObject::connect(applyButton, SIGNAL(clicked()), this, SLOT(slotApplyButton())); // // close button // QPushButton* closeButton = new QPushButton("Close"); closeButton->setAutoDefault(false); buttonLayout->addWidget(closeButton); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(slotCloseButton())); QtUtilities::makeButtonsSameSize(applyButton, closeButton); } /** * destructor. */ GuiVolumeTopologyReportDialog::~GuiVolumeTopologyReportDialog() { } /** * show the dialog (overrides QDialog's show()). */ void GuiVolumeTopologyReportDialog::show() { clearDialog(); WuQDialog::show(); slotApplyButton(); } /** * clear the dialog's data. */ void GuiVolumeTopologyReportDialog::clearDialog() { numberOfCavitiesLabel->setText(defaultLabelValue); numberOfObjectsLabel->setText(defaultLabelValue); eulerCountLabel->setText(defaultLabelValue); numberOfHolesLabel->setText(defaultLabelValue); } /** * called when apply button pressed. */ void GuiVolumeTopologyReportDialog::slotApplyButton() { clearDialog(); BrainModelVolume* bmv = theMainWindow->getBrainModelVolume(); if (bmv == NULL) { return; } const VolumeFile* vf = bmv->getSelectedVolumeSegmentationFile(); if (vf == NULL) { return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); /* const int numCavities = vf->getNumberOfSegmentationCavities(); const int numObjects = vf->getNumberOfSegmentationObjects(); const int eulerCount = vf->getEulerNumberForSegmentationVolume(); const int numHoles = numObjects + numCavities - eulerCount; //(eulerCount - 2) / (-2); */ int numObjects, numberOfCavities, numberOfHoles, eulerCount; vf->getSegmentationTopologyInformation(numObjects, numberOfCavities, numberOfHoles, eulerCount); setLabel(numberOfCavitiesLabel, numberOfCavities, 0); setLabel(numberOfObjectsLabel, numObjects, 1); setLabel(eulerCountLabel, eulerCount, 2); setLabel(numberOfHolesLabel, numberOfHoles, 0); QApplication::restoreOverrideCursor(); QApplication::beep(); } /** * set the label with green if the value is correct, else red. */ void GuiVolumeTopologyReportDialog::setLabel(QLabel* label, const int value, const int correctValue) { std::ostringstream str; str << ""; } else { str << "red>"; } str << value << " "; if (value != correctValue) { str << " (should be " << correctValue << ")"; } label->setText(str.str().c_str()); } /** * called when close button pressed. */ void GuiVolumeTopologyReportDialog::slotCloseButton() { clearDialog(); QDialog::close(); } caret-5.6.4~dfsg.1.orig/caret/GuiVolumeThresholdSegmentationDialog.h0000664000175000017500000000426711572067322025330 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_VOLUME_THRESHOLD_SEGMENTATION_DIALOG_H__ #define __GUI_VOLUME_THRESHOLD_SEGMENTATION_DIALOG_H__ #include #include "WuQDialog.h" /// dialog for segmenting an anatomical volume using a threshold class GuiVolumeThresholdSegmentationDialog : public WuQDialog { Q_OBJECT public: /// constructor GuiVolumeThresholdSegmentationDialog(QWidget* parent); /// destructor ~GuiVolumeThresholdSegmentationDialog(); /// called to update the dialog void updateDialog(); /// called to show the dialog (override's QDialog's show() method) void show(); public slots: /// called to close the dialog (override's QDialog's close() method) void close(); protected slots: /// called when apply button is pressed void slotApplyPushButton(); /// called when min thresh spin box value is changed void slotMinThresholdSpinBox(double val); /// called when max thresh spin box value is changed void slotMaxThresholdSpinBox(double val); protected: /// min threshold spin box QDoubleSpinBox* minThresholdSpinBox; /// max threshold spin box QDoubleSpinBox* maxThresholdSpinBox; }; #endif // __GUI_VOLUME_THRESHOLD_SEGMENTATION_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiVolumeThresholdSegmentationDialog.cxx0000664000175000017500000001646211572067322025703 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include "BrainModelVolumeThresholdSegmentation.h" #include "BrainModelVolumeVoxelColoring.h" #include "BrainSet.h" #include "DisplaySettingsVolume.h" #include "GuiBrainModelOpenGL.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "GuiVolumeThresholdSegmentationDialog.h" #include "QtUtilities.h" #include "global_variables.h" /** * constructor. */ GuiVolumeThresholdSegmentationDialog::GuiVolumeThresholdSegmentationDialog(QWidget* parent) : WuQDialog(parent) { setWindowTitle("Anatomy Threshold Segmentation"); // // min thresh // QLabel* minThreshLabel = new QLabel("Minimum Threshold"); minThresholdSpinBox = new QDoubleSpinBox; minThresholdSpinBox->setMinimum(-std::numeric_limits::max()); minThresholdSpinBox->setMaximum(std::numeric_limits::max()); minThresholdSpinBox->setSingleStep(1.0); minThresholdSpinBox->setDecimals(5); QObject::connect(minThresholdSpinBox, SIGNAL(valueChanged(double)), this, SLOT(slotMinThresholdSpinBox(double))); minThresholdSpinBox->setValue(175); // // max thresh // QLabel* maxThreshLabel = new QLabel("Maximum Threshold"); maxThresholdSpinBox = new QDoubleSpinBox; maxThresholdSpinBox->setMinimum(-std::numeric_limits::max()); maxThresholdSpinBox->setMaximum(std::numeric_limits::max()); maxThresholdSpinBox->setSingleStep(1.0); maxThresholdSpinBox->setDecimals(5); QObject::connect(maxThresholdSpinBox, SIGNAL(valueChanged(double)), this, SLOT(slotMaxThresholdSpinBox(double))); maxThresholdSpinBox->setValue(256); // // Grid Layout for thesholds // QGridLayout* gridLayout = new QGridLayout; gridLayout->addWidget(minThreshLabel, 0, 0, 1, 1); gridLayout->addWidget(minThresholdSpinBox, 0, 1, 1, 1); gridLayout->addWidget(maxThreshLabel, 1, 0, 1, 1); gridLayout->addWidget(maxThresholdSpinBox, 1, 1, 1, 1); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); // // Apply button // QPushButton* applyButton = new QPushButton("Apply"); buttonsLayout->addWidget(applyButton); applyButton->setAutoDefault(false); QObject::connect(applyButton, SIGNAL(clicked()), this, SLOT(slotApplyPushButton())); // // Close button // QPushButton* closeButton = new QPushButton("Close"); buttonsLayout->addWidget(closeButton); closeButton->setAutoDefault(false); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); // // Make buttons same size // QtUtilities::makeButtonsSameSize(applyButton, closeButton); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); dialogLayout->addLayout(gridLayout); dialogLayout->addLayout(buttonsLayout); } /** * destructor. */ GuiVolumeThresholdSegmentationDialog::~GuiVolumeThresholdSegmentationDialog() { } /** * called to update the dialog. */ void GuiVolumeThresholdSegmentationDialog::updateDialog() { if (theMainWindow->getBrainSet()->getNumberOfVolumeAnatomyFiles() <= 0) { close(); } } /** * called to show the dialog (override's QDialog's show() method). */ void GuiVolumeThresholdSegmentationDialog::show() { slotMinThresholdSpinBox(minThresholdSpinBox->value()); slotMaxThresholdSpinBox(maxThresholdSpinBox->value()); WuQDialog::show(); } /** * called to close the dialog (override's QDialog's close() method). */ void GuiVolumeThresholdSegmentationDialog::close() { DisplaySettingsVolume* dsv = theMainWindow->getBrainSet()->getDisplaySettingsVolume(); dsv->setAnatomyThresholdValid(false); GuiBrainModelOpenGL::updateAllGL(); WuQDialog::close(); } /** * called when min spin box value is changed. */ void GuiVolumeThresholdSegmentationDialog::slotMinThresholdSpinBox(double val) { DisplaySettingsVolume* dsv = theMainWindow->getBrainSet()->getDisplaySettingsVolume(); dsv->setAnatomyThresholdValid(true); float thresh[2]; dsv->getAnatomyThreshold(thresh[0], thresh[1]); thresh[0] = val; dsv->setAnatomyThreshold(thresh[0], thresh[1]); GuiBrainModelOpenGL::updateAllGL(); } /** * called when max spin box value is changed. */ void GuiVolumeThresholdSegmentationDialog::slotMaxThresholdSpinBox(double val) { DisplaySettingsVolume* dsv = theMainWindow->getBrainSet()->getDisplaySettingsVolume(); dsv->setAnatomyThresholdValid(true); float thresh[2]; dsv->getAnatomyThreshold(thresh[0], thresh[1]); thresh[1] = val; dsv->setAnatomyThreshold(thresh[0], thresh[1]); GuiBrainModelOpenGL::updateAllGL(); } /** * called when apply button is pressed. */ void GuiVolumeThresholdSegmentationDialog::slotApplyPushButton() { BrainModelVolume* bmv = theMainWindow->getBrainSet()->getBrainModelVolume(); if (bmv != NULL) { VolumeFile* vf = bmv->getSelectedVolumeAnatomyFile(); if (vf == NULL) { QMessageBox::critical(this, "ERROR", "No anatomy volume selected."); return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); try { const float thresh[2] = { minThresholdSpinBox->value(), maxThresholdSpinBox->value() }; BrainModelVolumeThresholdSegmentation bmvts(theMainWindow->getBrainSet(), vf, thresh); bmvts.execute(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); return; } BrainModelVolumeVoxelColoring* bmvvc = theMainWindow->getBrainSet()->getVoxelColoring(); bmvvc->setPrimaryOverlay(BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_SEGMENTATION); DisplaySettingsVolume* dsv = theMainWindow->getBrainSet()->getDisplaySettingsVolume(); dsv->setSelectedSegmentationVolume(theMainWindow->getBrainSet()->getNumberOfVolumeSegmentationFiles() - 1); GuiFilesModified fm; fm.setVolumeModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); QApplication::beep(); } } caret-5.6.4~dfsg.1.orig/caret/GuiVolumeSureFitSegmentationDialog.h0000664000175000017500000002650211572067322024751 0ustar michaelmichael #ifndef __GUI_VOLUME_SUREFIT_SEGMENTATION_DIALOG_H__ #define __GUI_VOLUME_SUREFIT_SEGMENTATION_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "WuQDialog.h" #include "VolumeFile.h" class GuiGraphWidget; class GuiStereotaxicSpaceComboBox; class GuiStructureComboBox; class GuiVolumeSelectionControl; class QCheckBox; class QComboBox; class QGroupBox; class QLabel; class QLineEdit; class QRadioButton; class QSlider; class GuiSpeciesComboBox; class QSpinBox; class QStackedWidget; class QTextEdit; class StatisticHistogram; /// Dialog for segmenting an anatomy volume class GuiVolumeSureFitSegmentationDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiVolumeSureFitSegmentationDialog(QWidget* parent); /// Destructor ~GuiVolumeSureFitSegmentationDialog(); /// Update the dialog void updateDialog(); /// called to show the dialog (overrides parent's method) void show(); protected slots: /// called when close button is pressed void slotCloseButton(); /// Enable/Disable pushbuttons based upon selections. void slotEnableDisablePushButtons(); /// Called when next pushbutton pressed void slotNextPushButton(); /// Called when back pushbutton pressed void slotBackPushButton(); /// Perform the segmentation (returns true if an error occurred) bool performSegmentation(); /// called to enable/disable selection check boxes void slotEnableDisableSelectionCheckBoxes(); /// called when gray or white peak radio button selected void slotPeakRadioButton(); /// called when directory push button is pressed void slotDirectoryPushButton(); /// called when a spec file is selected on spec file page void slotSpecFileSelected(const QString& name); /// called when correct topological errors in fiducial surface checkbox toggled void slotGenerateTopologicallyCorrectFiducialSurfaceCheckBox(bool b); /// called when smooth button pressed void slotSmoothHistogramPushButton(); protected: /// hind brain removal thresholds enum HIND_BRAIN_THRESHOLD { /// high threshold HIND_BRAIN_THRESHOLD_HIGH, /// low threshold HIND_BRAIN_THRESHOLD_LOW }; /// mode for processing volumes enum MODE { /// no mode MODE_NONE, /// segment anatomical volume MODE_ANATOMICAL_VOLUME_SEGMENTATION, /// segmentation post processing MODE_SEMENTATION_VOLUME_POST_PROCESSING }; /// add a page to the dialog void addPage(QWidget* w, const QString& legend); /// Prepare some pages when they are about to be shown void showPage(QWidget* page, const bool backPushButtonPressed = false); /// see if the current directory is set to the caret installation directory bool currentDirectoryIsCaretInstallationDirectory(); /// load histogram into graph void loadHistogramIntoGraph(); /// create change directory page QWidget* createChangeDirectoryPage(); /// Create the subject info page QWidget* createSubjectInfoPage(); /// Create the spec file page QWidget* createSpecFilePage(); /// Create the volume selection page QWidget* createVolumeSelectionPage(); /// Create the volume file type page QWidget* createVolumeFileTypePage(); /// Create the volume attributes page QWidget* createVolumeAttributesPage(); /// Create the gray white peaks page QWidget* createGrayWhitePeaksPage(); /// Create the segmentation selections page QWidget* createSegmentationSelectionsPage(); /// Create the segmentation complete page QWidget* createSegmentationCompletePage(); /// update the volume attributes page void updateVolumeAttributesPage(); /// update the current directory page void updateCurrentDirectoryPage(); /// mode for processing volumes MODE mode; /// mode anatomical volume segmentation radio button QRadioButton* modeAnatomicalVolumeProcessingRadioButton; /// mode segmentation volume post processing radio button QRadioButton* modeSegmentationVolumeProcessingRadioButton; /// volume selection group box QGroupBox* volumeSelectionGroupBox; /// the change directory page widget QWidget* changeDirectoryPage; /// the subject info page widget QWidget* subjectInfoPage; /// the spec file page QWidget* specFilePage; /// the volume selection page QWidget* volumeSelectionPage; /// the volume file type page QWidget* volumeFileTypePage; /// the volume attributes page widget QWidget* volumeAttributesPage; /// the gray white peaks page page widget QWidget* grayWhitePeaksPage; /// gray peak radio button QRadioButton* grayPeakRadioButton; /// white peak radio button QRadioButton* whitePeakRadioButton; /// the segmentation selections page widget QWidget* segmentationSelectionsPage; /// the segmentation complete page widget QWidget* segmentationCompletePage; /// spin box for setting gray matter peak QSpinBox* grayPeakSpinBox; /// spin box for setting white matter peak QSpinBox* whitePeakSpinBox; /// histogram widget for setting peaks GuiGraphWidget* peakHistogramWidget; /// override peak average check box QCheckBox* overrideThreshSetCheckBox; /// spin box for peak average override check box QSpinBox* overridePeakSpinBox; /// estimate peak label QLabel* csfPeakLabel; /// estimate peak label QLabel* grayPeakLabel; /// estimate peak label QLabel* whitePeakLabel; /// the species combo box GuiSpeciesComboBox* speciesComboBox; /// the stereotaxic space combo box GuiStereotaxicSpaceComboBox* stereotaxicSpaceComboBox; /// the subject line edit QLineEdit* subjectLineEdit; /// the structure combo box GuiStructureComboBox* structureComboBox; /// anaotmical volume options group box QGroupBox* anatomicalVolumeOptionsGroupBox; /// segmentation volume options group box QGroupBox* segmentationVolumeOptionsGroupBox; /// disconnect eye check box QCheckBox* disconnectEyeCheckBox; /// disconnect hindbrain check box QCheckBox* disconnectHindbrainCheckBox; /// disconnect hindbrain hi/lo threshold combo box QComboBox* hindLoHiThreshComboBox; /// cut corpus callosum check box QCheckBox* cutCorpusCallosumCheckBox; /// generate segmentation check box QCheckBox* generateSegmentationCheckBox; /// fill ventricles check box QCheckBox* fillVentriclesCheckBox; /// generate raw and fiducial surface check box QCheckBox* generateRawAndFiducialSurfaceCheckBox; /// generate topologically correct fiducial surface check box QCheckBox* generateTopologicallyCorrectFiducialSurfaceCheckBox; /// limit polygons in generated surfaces check box QCheckBox* generateSurfaceLimitPolygonsCheckBox; /// generate inflated check box QCheckBox* generateInflatedSurfaceCheckBox; /// generate very inflated check box QCheckBox* generateVeryInflatedSurfaceCheckBox; /// generate ellipsoid check box QCheckBox* generateEllipsoidSurfaceCheckBox; /// generate spherical check box QCheckBox* generateSphericalSurfaceCheckBox; /// generate comp med wall check box QCheckBox* generateCompMedWallSurfaceCheckBox; /// generate hull check box QCheckBox* generateHullCheckBox; /// volume error correction check box QCheckBox* volumeErrorCorrectionCheckBox; /// volume error correction method combo box QComboBox* volumeErrorCorrectionMethodComboBox; /// generate depth, curvature, geography check box QCheckBox* generateDepthCurvatureGeographyCheckBox; /// generate landmark borders check box QCheckBox* generateLandmarkBordersCheckBox; /// auto save files check box QCheckBox* autoSaveFilesCheckBox; /// label for the volume attributes label QLabel* volumeAttributesLabel; /// anatomy volume selection control GuiVolumeSelectionControl* volumeAnatomySelectionControl; /// segmentation volume selection control GuiVolumeSelectionControl* volumeSegmentationSelectionControl; /// line edit for spec file name QLineEdit* specFileNameLineEdit; /// text edit for spec file comment QTextEdit* specFileCommentTextEdit; /// segmentation time label QLabel* segmentationCompleteTimeLabel; /// segmentation surface handle count QLabel* segmentationCompleteHandleLabel; /// time needed by segmentation algorithm float segmentationTime; /// initialize graph scale flag bool initializeGraphScaleFlag; /// stacked widget for pages QStackedWidget* pagesStackedWidget; /// label for current page's legend QLabel* currentPageLegend; /// legends for pages std::vector pageLegends; /// the back push button QPushButton* backPushButton; /// the next push button QPushButton* nextPushButton; /// current directory line edit QLineEdit* currentDirectoryLineEdit; /// current directory label QLabel* currentDirectoryLabel; /// AFNI file type radio button QRadioButton* fileTypeAfniRadioButton; /// NIFTI file type radio button QRadioButton* fileTypeNiftiRadioButton; /// NIFTI GZIP file type radio button QRadioButton* fileTypeNiftiGzipRadioButton; /// type of volume files to write VolumeFile::FILE_READ_WRITE_TYPE typeOfVolumesToWrite; /// histogram for gray/white peaks StatisticHistogram* peakHistogram; }; #endif // __GUI_VOLUME_SUREFIT_SEGMENTATION_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiVolumeSureFitSegmentationDialog.cxx0000664000175000017500000027260611572067322025334 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "BrainModelSurface.h" #include "BrainModelSurfaceBorderLandmarkIdentification.h" #include "BrainModelVolume.h" #include "BrainModelVolumeSureFitSegmentation.h" #include "BrainModelVolumeVoxelColoring.h" #include "BrainSet.h" #include "DisplaySettingsVolume.h" #include "FileFilters.h" #include "FileUtilities.h" #include "GuiBrainModelOpenGL.h" #include "GuiFilesModified.h" #include "GuiFileSelectionButton.h" #include "GuiGraphWidget.h" #include "GuiStereotaxicSpaceComboBox.h" #include "GuiStructureComboBox.h" #include "GuiMainWindow.h" #include "GuiMainWindowFileActions.h" #include "GuiSpeciesComboBox.h" #include "GuiVolumeSureFitSegmentationDialog.h" #include "GuiVolumeSelectionControl.h" #include "StatisticHistogram.h" #include "ParamsFile.h" #include "QtListBoxSelectionDialog.h" #include "QtUtilities.h" #include "SpecFile.h" #include "Species.h" #include "StringUtilities.h" #include "VolumeFile.h" #include "WuQDataEntryDialog.h" #include "global_variables.h" /** * Constructor. */ GuiVolumeSureFitSegmentationDialog::GuiVolumeSureFitSegmentationDialog(QWidget* parent) : WuQDialog(parent) { setAttribute(Qt::WA_DeleteOnClose); initializeGraphScaleFlag = true; typeOfVolumesToWrite = VolumeFile::FILE_READ_WRITE_TYPE_NIFTI_GZIP; peakHistogram = NULL; anatomicalVolumeOptionsGroupBox = NULL; segmentationVolumeOptionsGroupBox = NULL; volumeSelectionGroupBox = NULL; mode = MODE_NONE; setWindowTitle("SureFit Segmentation Operations"); // // label for current page legend // currentPageLegend = new QLabel(""); // // stacked widget for pages // pagesStackedWidget = new QStackedWidget; // // Create the pages // changeDirectoryPage = createChangeDirectoryPage(); addPage(changeDirectoryPage, "Change/Verify Current Directory"); subjectInfoPage = createSubjectInfoPage(); addPage(subjectInfoPage, "Subject Information"); specFilePage = createSpecFilePage(); addPage(specFilePage, "Spec File Selection"); volumeSelectionPage = createVolumeSelectionPage(); addPage(volumeSelectionPage, "Volume Selection"); volumeFileTypePage = createVolumeFileTypePage(); addPage(volumeFileTypePage, "Volume File Type"); volumeAttributesPage = createVolumeAttributesPage(); addPage(volumeAttributesPage, "Volume Attributes"); grayWhitePeaksPage = createGrayWhitePeaksPage(); addPage(grayWhitePeaksPage, "Set Gray and White Matter Peaks"); segmentationSelectionsPage = createSegmentationSelectionsPage(); addPage(segmentationSelectionsPage, "Segmentation Operations"); segmentationCompletePage = createSegmentationCompletePage(); addPage(segmentationCompletePage, "Segmentation Complete"); // // back button // backPushButton = new QPushButton("Back"); backPushButton->setAutoDefault(false); QObject::connect(backPushButton, SIGNAL(clicked()), this, SLOT(slotBackPushButton())); // // next button // nextPushButton = new QPushButton("Next"); nextPushButton->setAutoDefault(false); QObject::connect(nextPushButton, SIGNAL(clicked()), this, SLOT(slotNextPushButton())); // // close button // QPushButton* closePushButton = new QPushButton("Close"); closePushButton->setAutoDefault(false); QObject::connect(closePushButton, SIGNAL(clicked()), this, SLOT(slotCloseButton())); // // Make all of the buttons the same size // QtUtilities::makeButtonsSameSize(backPushButton, nextPushButton, closePushButton); // // Layout the buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout(); buttonsLayout->addWidget(backPushButton); buttonsLayout->addWidget(nextPushButton); buttonsLayout->addWidget(closePushButton); // // Layout for dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->addWidget(currentPageLegend); dialogLayout->addWidget(pagesStackedWidget); dialogLayout->addLayout(buttonsLayout); } /** * Destructor. */ GuiVolumeSureFitSegmentationDialog::~GuiVolumeSureFitSegmentationDialog() { } /** * add a page to the dialog. */ void GuiVolumeSureFitSegmentationDialog::addPage(QWidget* w, const QString& legend) { pagesStackedWidget->addWidget(w); pageLegends.push_back(legend); } /** * called when close button is pressed. */ void GuiVolumeSureFitSegmentationDialog::slotCloseButton() { // // Turn off any thresholding // DisplaySettingsVolume* dsv = theMainWindow->getBrainSet()->getDisplaySettingsVolume(); dsv->setAnatomyThresholdValid(false); GuiBrainModelOpenGL::updateAllGL(); WuQDialog::close(); } /** * called to show the dialog (overrides parent's method). */ void GuiVolumeSureFitSegmentationDialog::show() { showPage(pagesStackedWidget->widget(0)); WuQDialog::show(); slotEnableDisablePushButtons(); } /** * create change directory page. */ QWidget* GuiVolumeSureFitSegmentationDialog::createChangeDirectoryPage() { // // Current directory line edit // currentDirectoryLineEdit = new QLineEdit; currentDirectoryLineEdit->setReadOnly(true); // // Pushbutton to change the current directory // QPushButton* directoryPushButton = new QPushButton("Change Current Directory..."); directoryPushButton->setAutoDefault(false); directoryPushButton->setFixedSize(directoryPushButton->sizeHint()); QObject::connect(directoryPushButton, SIGNAL(clicked()), this, SLOT(slotDirectoryPushButton())); // // Current directory text // currentDirectoryLabel = new QLabel(""); // // Dummy widget stretched at bottom // QWidget* dummyWidget = new QWidget; // // Widget for page and layout // QWidget* w = new QWidget; QVBoxLayout* layout = new QVBoxLayout(w); layout->addWidget(currentDirectoryLineEdit); layout->addWidget(directoryPushButton); layout->addWidget(currentDirectoryLabel); layout->setStretchFactor(currentDirectoryLineEdit, 0); layout->setStretchFactor(currentDirectoryLabel, 0); layout->setStretchFactor(directoryPushButton, 0); layout->setStretchFactor(dummyWidget, 100); return w; } /** * called when directory push button is pressed. */ void GuiVolumeSureFitSegmentationDialog::slotDirectoryPushButton() { GuiMainWindowFileActions* fileActions = theMainWindow->getFileActions(); fileActions->slotSetCurrentDirectory(); updateCurrentDirectoryPage(); } /** * see if the current directory is set to the caret installation directory. */ bool GuiVolumeSureFitSegmentationDialog::currentDirectoryIsCaretInstallationDirectory() { const QString currentPath = QDir::currentPath(); const bool inInstallDir = (currentPath.contains("caret/bin") || currentPath.contains("caret\\bin") || currentPath.contains("caret/apps")); return inInstallDir; } /** * update the current directory page. */ void GuiVolumeSureFitSegmentationDialog::updateCurrentDirectoryPage() { QString msg; if (currentDirectoryIsCaretInstallationDirectory()) { msg = "" "The current path needs to be changed as it is currently set to
    " "the directory containing the Caret program.
    " "
    " "
    " "Press the Change Current Directory push button to change the
    " "current directory to the directory containing the volume you
    " "plan to segment."; } else { msg = "If the current directory is not set to the directory containing the
    " "volume you are segmenting use the Change Current Directory to
    " "set the current directory.
    " "
    " "If you have loaded a spec file containing a volume, there is no need
    " "to change the current directory."; } currentDirectoryLineEdit->setText(QDir::currentPath()); currentDirectoryLabel->setTextFormat(Qt::RichText); currentDirectoryLabel->setText(msg); slotEnableDisablePushButtons(); } /** * Create the subject info page. */ QWidget* GuiVolumeSureFitSegmentationDialog::createSubjectInfoPage() { // // Species information // QLabel* speciesLabel = new QLabel("Species"); speciesComboBox = new GuiSpeciesComboBox; speciesComboBox->setSelectedSpecies(theMainWindow->getBrainSet()->getSpecies()); QObject::connect(speciesComboBox, SIGNAL(activated(int)), this, SLOT(slotEnableDisablePushButtons())); // // Stereotaxic space // QLabel* stereotaxicSpaceLabel = new QLabel("Stereotaxic Space"); stereotaxicSpaceComboBox = new GuiStereotaxicSpaceComboBox; stereotaxicSpaceComboBox->setSelectedStereotaxicSpace(theMainWindow->getBrainSet()->getStereotaxicSpace()); QObject::connect(stereotaxicSpaceComboBox, SIGNAL(activated(int)), this, SLOT(slotEnableDisablePushButtons())); // // Subject information // QLabel* subjectLabel = new QLabel("Subject"); subjectLineEdit = new QLineEdit; QObject::connect(subjectLineEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotEnableDisablePushButtons())); // // Hemisphere // // // hemisphere combo box and line edit // QLabel* structureLabel = new QLabel("Structure"); structureComboBox = new GuiStructureComboBox(0, 0, true); structureComboBox->setStructure(theMainWindow->getBrainSet()->getStructure().getType()); QObject::connect(structureComboBox, SIGNAL(activated(int)), this, SLOT(slotEnableDisablePushButtons())); // // Arrange the widgets in a grid layout // QGridLayout* gridLayout = new QGridLayout; gridLayout->addWidget(speciesLabel, 0, 0); gridLayout->addWidget(speciesComboBox, 0, 1); gridLayout->addWidget(stereotaxicSpaceLabel, 1, 0); gridLayout->addWidget(stereotaxicSpaceComboBox, 1, 1); gridLayout->addWidget(subjectLabel, 2, 0); gridLayout->addWidget(subjectLineEdit, 2, 1); gridLayout->addWidget(structureLabel, 3, 0); gridLayout->addWidget(structureComboBox, 3, 1); gridLayout->setColumnStretch(0, 0); // // Widget for page and layout // QWidget* w = new QWidget; QVBoxLayout* layout = new QVBoxLayout(w); layout->addLayout(gridLayout); layout->addStretch(); return w; } /** * Create the spec file page. */ QWidget* GuiVolumeSureFitSegmentationDialog::createSpecFilePage() { // // Line edit for name of spec file // specFileNameLineEdit = new QLineEdit; QObject::connect(specFileNameLineEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotEnableDisablePushButtons())); // // Button to select spec file // GuiFileSelectionButton* specFilePushButton = new GuiFileSelectionButton(NULL, "Choose Spec File...", FileFilters::getSpecFileFilter(), false); QObject::connect(specFilePushButton, SIGNAL(fileSelected(const QString&)), specFileNameLineEdit, SLOT(setText(const QString&))); QObject::connect(specFilePushButton, SIGNAL(fileSelected(const QString&)), this, SLOT(slotSpecFileSelected(const QString&))); specFilePushButton->setFixedSize(specFilePushButton->sizeHint()); QGroupBox* specFileGroupBox = new QGroupBox("Spec File Selection"); QVBoxLayout* specFileLayout = new QVBoxLayout(specFileGroupBox); specFileLayout->addWidget(specFilePushButton); specFileLayout->addWidget(specFileNameLineEdit); specFileCommentTextEdit = new QTextEdit; specFileCommentTextEdit->setMaximumHeight(100); QGroupBox* commentGroupBox = new QGroupBox("Comment"); QVBoxLayout* commentGroupLayout = new QVBoxLayout(commentGroupBox); commentGroupLayout->addWidget(specFileCommentTextEdit); const QString msg = "The spec file is used to organize a subject's data files.\n" "\n" "Use the \"Choose Spec File\" pushbutton to choose a different spec file or to \n" "use a different directory. In the Choose Spec File selection dialog, press the \n" "icon containing a folder with a \"*\" in its top right corner to create new\n" "directories.\n" "\n" "All new files created during the SureFit process will be placed into the\n" "directory containing the spec file.\n" "\n" "If you choose to generate raw and fiducial coord files, all surface related\n" "files will be removed from the spec file.\n" ; QLabel* label = new QLabel(msg); // // Widget and layout for dialog // QWidget* w = new QWidget; QVBoxLayout* layout = new QVBoxLayout(w); layout->addWidget(specFileGroupBox); layout->addWidget(commentGroupBox); layout->addWidget(label); layout->addStretch(); return w; } /** * called when a spec file is selected on spec file page. */ void GuiVolumeSureFitSegmentationDialog::slotSpecFileSelected(const QString& name) { try { SpecFile sf; sf.readFile(name); specFileCommentTextEdit->setPlainText(sf.getFileComment()); specFileCommentTextEdit->setWindowModified(false); } catch (FileException&) { } } /** * Create the volume file type page. */ QWidget* GuiVolumeSureFitSegmentationDialog::createVolumeFileTypePage() { fileTypeAfniRadioButton = new QRadioButton("AFNI"); fileTypeNiftiRadioButton = new QRadioButton("NIFTI"); fileTypeNiftiGzipRadioButton = new QRadioButton("NIFTI-GZIP"); QButtonGroup* buttGroup = new QButtonGroup(this); buttGroup->addButton(fileTypeAfniRadioButton); buttGroup->addButton(fileTypeNiftiRadioButton); buttGroup->addButton(fileTypeNiftiGzipRadioButton); QObject::connect(buttGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotEnableDisablePushButtons())); QLabel* infoLabel = new QLabel("\n" "Choose the type of volume files that Caret will create\n" "when volume files are automatically saved. Temporary\n" "volume files will also be saved in this file format.\n" "It is RECOMMENDED that you use the NIFTI file format. \n" "NIFTI is supported by most brain mapping software packages\n" "and stores all data in one file."); QWidget* w = new QWidget; QVBoxLayout* layout = new QVBoxLayout(w); layout->addWidget(fileTypeAfniRadioButton); layout->addWidget(fileTypeNiftiRadioButton); layout->addWidget(fileTypeNiftiGzipRadioButton); layout->addWidget(infoLabel); layout->addStretch(); return w; } /** * Create the volume selection page. */ QWidget* GuiVolumeSureFitSegmentationDialog::createVolumeSelectionPage() { // // Mode radio buttons // modeAnatomicalVolumeProcessingRadioButton = new QRadioButton("Anatomical Volume Segmentation"); modeSegmentationVolumeProcessingRadioButton = new QRadioButton("Segmentation Volume Post Processing"); // // Button group to keep mode buttons mutually exclusive // QButtonGroup* modeButtonGroup = new QButtonGroup(this); modeButtonGroup->addButton(modeAnatomicalVolumeProcessingRadioButton); modeButtonGroup->addButton(modeSegmentationVolumeProcessingRadioButton); QObject::connect(modeButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotEnableDisablePushButtons())); // // Group box for mode buttons // QGroupBox* modeGroupBox = new QGroupBox("Segmentation Mode"); QVBoxLayout* modeGroupLayout = new QVBoxLayout(modeGroupBox); modeGroupLayout->addWidget(modeAnatomicalVolumeProcessingRadioButton); modeGroupLayout->addWidget(modeSegmentationVolumeProcessingRadioButton); modeGroupBox->setFixedSize(modeGroupBox->sizeHint()); // // Control for selecting the anatomical volume // volumeAnatomySelectionControl = new GuiVolumeSelectionControl(0, true, false, false, false, false, false, false, GuiVolumeSelectionControl::LABEL_MODE_FILE_LABEL_AND_NAME, "volumeAnatomySelectionControl", false, false, false); QObject::connect(volumeAnatomySelectionControl, SIGNAL(signalSelectionChanged()), this, SLOT(slotEnableDisablePushButtons())); // // Control for selecting the segmentation volume // volumeSegmentationSelectionControl = new GuiVolumeSelectionControl(0, false, false, false, false, false, true, false, GuiVolumeSelectionControl::LABEL_MODE_FILE_LABEL_AND_NAME, "volumeSegmentationSelectionControl", false, false, false); QObject::connect(volumeSegmentationSelectionControl, SIGNAL(signalSelectionChanged()), this, SLOT(slotEnableDisablePushButtons())); // // Group box and layout for volume selection // volumeSelectionGroupBox = new QGroupBox("Volume Selection"); QVBoxLayout* volumeSelectionGroupLayout = new QVBoxLayout(volumeSelectionGroupBox); volumeSelectionGroupLayout->addWidget(volumeAnatomySelectionControl); volumeSelectionGroupLayout->addWidget(volumeSegmentationSelectionControl); volumeSelectionGroupBox->setFixedSize(volumeSelectionGroupBox->sizeHint()); QWidget* w = new QWidget; QVBoxLayout* layout = new QVBoxLayout(w); layout->addWidget(modeGroupBox); layout->addWidget(volumeSelectionGroupBox); layout->addStretch(); return w; } /** * Create the anatomy attributes page. */ QWidget* GuiVolumeSureFitSegmentationDialog::createVolumeAttributesPage() { volumeAttributesLabel = new QLabel(""); QWidget* w = new QWidget; QVBoxLayout* layout = new QVBoxLayout(w); layout->addWidget(volumeAttributesLabel); return w; } /** * update the volume attributes page. */ void GuiVolumeSureFitSegmentationDialog::updateVolumeAttributesPage() { QString voxelRangeMessage; VolumeFile* vfa = volumeAnatomySelectionControl->getSelectedVolumeFile(); if (vfa != NULL) { float minVoxel, maxVoxel; vfa->getMinMaxVoxelValues(minVoxel, maxVoxel); std::ostringstream s1; QString fontStart1, fontEnd1; if (minVoxel != 0.0) { fontStart1 = ""; fontEnd1 = ""; } QString fontStart2, fontEnd2; if (maxVoxel != 255.0) { fontStart2 = ""; fontEnd2 = ""; } s1 << "The selected anatomy volume's voxels range from " << fontStart1.toAscii().constData() << minVoxel << fontEnd1.toAscii().constData() << " to " << fontStart2.toAscii().constData() << maxVoxel << fontEnd2.toAscii().constData() << "."; voxelRangeMessage += s1.str().c_str(); } /* VolumeFile* vfb = volumeAnatomySelectionControl->getSelectedVolumeFile(); if (vfb != NULL) { float minVoxel, maxVoxel; vfa->getMinMaxVoxelValues(minVoxel, maxVoxel); std::ostringstream s1; QString fontStart1, fontEnd1; if (minVoxel != 0.0) { fontStart1 = ""; fontEnd1 = ""; } QString fontStart2, fontEnd2; if (maxVoxel != 255.0) { fontStart2 = ""; fontEnd2 = ""; } s1 << "The selected anatomy volume's voxels range from " << fontStart1.toAscii().constData() << minVoxel << fontEnd1.toAscii().constData() << " to " << fontStart2.toAscii().constData() << maxVoxel << fontEnd2.toAscii().constData() << "."; voxelRangeMessage += s1.str().c_str(); } */ std::ostringstream str; str << "The volume must be in an LPI (-x is left, -y is posterior, -z is inferior)
    " << "orientation.
    " << "
    " << "The origin (stereotaxic coordinates of [0, 0, 0]) must be located at the
    " << "anterior commissure. If you have a full hemisphere, pressing the \"R\"
    " << "button in the toolbar should result in the the crosshairs intersecting at
    " << "the anterior commissure.
    " << "
    " << "The voxel size must be 1mm in each axis.
    " << "
    " << "The ANATOMY voxels must be in the range 0 to 255.
    "; if (vfa != NULL) { str << voxelRangeMessage.toAscii().constData() << "
    "; } str << "
    " << "All of these items may be adjusted by selecting \"Edit Volume Attributes\"
    " << "from the \"Volume Menu\".
    " << "
    " << "If any of the above conditions are not met, an error message will be displayed
    " << "when the \"Next\" button is pressed.
    "; volumeAttributesLabel->setTextFormat(Qt::RichText); volumeAttributesLabel->setText(str.str().c_str()); } /** * Create the gray white peaks page. */ QWidget* GuiVolumeSureFitSegmentationDialog::createGrayWhitePeaksPage() { // // Create the histogram widget // peakHistogramWidget = new GuiGraphWidget(0, ""); // // GroupBox and layout for histogram // QGroupBox* histoGroupBox = new QGroupBox("Histogram"); QVBoxLayout* histoLayout = new QVBoxLayout(histoGroupBox); histoLayout->addWidget(peakHistogramWidget); // // Gray peak radio button and spin box // grayPeakRadioButton = new QRadioButton("Gray"); grayPeakRadioButton->setToolTip( "When this item is selected, anatomy volume voxels\n" "greater than the gray peak threshold will be \n" "colored in green."); grayPeakSpinBox = new QSpinBox; grayPeakSpinBox->setMinimum(0); grayPeakSpinBox->setMaximum(255); grayPeakSpinBox->setSingleStep(1); QObject::connect(grayPeakSpinBox, SIGNAL(valueChanged(int)), peakHistogramWidget, SLOT(slotSetMinimumPeak(int))); QObject::connect(grayPeakSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotPeakRadioButton())); // // White peak radio button and spin box // whitePeakRadioButton = new QRadioButton("White"); whitePeakRadioButton->setToolTip( "When this item is selected, anatomy volume voxels\n" "greater than the white peak threshold will be \n" "colored in green."); whitePeakSpinBox = new QSpinBox; whitePeakSpinBox->setMinimum(0); whitePeakSpinBox->setMaximum(255); whitePeakSpinBox->setSingleStep(1); QObject::connect(whitePeakSpinBox, SIGNAL(valueChanged(int)), peakHistogramWidget, SLOT(slotSetMaximumPeak(int))); QObject::connect(whitePeakSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotPeakRadioButton())); // // Override check box and spin box // overrideThreshSetCheckBox = new QCheckBox("Override"); overrideThreshSetCheckBox->setToolTip( "Enable this item to override the average\n" "of the gray and white matter peaks."); overridePeakSpinBox = new QSpinBox; overridePeakSpinBox->setMinimum(0); overridePeakSpinBox->setMaximum(255); overridePeakSpinBox->setSingleStep(1); QObject::connect(overrideThreshSetCheckBox, SIGNAL(toggled(bool)), overridePeakSpinBox, SLOT(setEnabled(bool))); overridePeakSpinBox->setToolTip( "Enter the value for overriding the average\n" "of the gray and white matter peaks here."); // // Smooth button // QPushButton* smoothHistogramPushButton = new QPushButton("Smooth"); smoothHistogramPushButton->setFixedSize(smoothHistogramPushButton->sizeHint()); smoothHistogramPushButton->setAutoDefault(false); smoothHistogramPushButton->setToolTip("Smoothing the histogram may make the peaks\n" "easier to identify. Each time the smooth\n" "button is pressed, one iteration of smoothing\n" "is performed so multiple pressings of the \n" "smooth button may be needed. To reset the\n" "graph, press the Back button to return to the\n" "previous page and then press the Next button."); QObject::connect(smoothHistogramPushButton, SIGNAL(clicked()), this, SLOT(slotSmoothHistogramPushButton())); // // Group box for gray/white/override controls // QGroupBox* peaksGroupBox = new QGroupBox("Peaks"); QGridLayout* peaksGridLayout = new QGridLayout(peaksGroupBox); peaksGridLayout->addWidget(grayPeakRadioButton, 0, 0); peaksGridLayout->addWidget(grayPeakSpinBox, 0, 1); peaksGridLayout->addWidget(whitePeakRadioButton, 1, 0); peaksGridLayout->addWidget(whitePeakSpinBox, 1, 1); peaksGridLayout->addWidget(overrideThreshSetCheckBox, 2, 0); peaksGridLayout->addWidget(overridePeakSpinBox, 2, 1); peaksGridLayout->addWidget(smoothHistogramPushButton, 3, 0, 2, 1); peaksGroupBox->setFixedSize(peaksGroupBox->sizeHint()); // // Button group for white/gray radio buttons // QButtonGroup* grayWhiteButtonGroup = new QButtonGroup(this); QObject::connect(grayWhiteButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotPeakRadioButton())); grayWhiteButtonGroup->addButton(grayPeakRadioButton, 0); grayWhiteButtonGroup->addButton(whitePeakRadioButton, 1); // // Estimated peaks labels // QLabel* csfPeakTextLabel = new QLabel("CSF "); csfPeakLabel = new QLabel(""); QLabel* grayPeakTextLabel = new QLabel("Gray "); grayPeakLabel = new QLabel(""); QLabel* whitePeakTextLabel = new QLabel("White "); whitePeakLabel = new QLabel(""); // // Layout for estimated peaks // QGridLayout* peakEstGridLayout = new QGridLayout; peakEstGridLayout->addWidget(csfPeakTextLabel, 0, 0); peakEstGridLayout->addWidget(csfPeakLabel, 0, 1); peakEstGridLayout->addWidget(grayPeakTextLabel, 1, 0); peakEstGridLayout->addWidget(grayPeakLabel, 1, 1); peakEstGridLayout->addWidget(whitePeakTextLabel, 2, 0); peakEstGridLayout->addWidget(whitePeakLabel, 2, 1); QGroupBox* peakEstGroupBox = new QGroupBox("Peak Estimates"); QHBoxLayout* peakEstBoxLayout = new QHBoxLayout(peakEstGroupBox); peakEstBoxLayout->addLayout(peakEstGridLayout); peakEstBoxLayout->addStretch(); // // Layout for page // QVBoxLayout* rightColumnLayout = new QVBoxLayout; rightColumnLayout->addWidget(peaksGroupBox); rightColumnLayout->addWidget(peakEstGroupBox); rightColumnLayout->addStretch(); QWidget* w = new QWidget; QHBoxLayout* layout = new QHBoxLayout(w); layout->addWidget(histoGroupBox); layout->addLayout(rightColumnLayout); return w; } /** * called when gray or white peak radio button selected. */ void GuiVolumeSureFitSegmentationDialog::slotPeakRadioButton() { DisplaySettingsVolume* dsv = theMainWindow->getBrainSet()->getDisplaySettingsVolume(); if (grayPeakRadioButton->isChecked()) { dsv->setAnatomyThreshold(grayPeakSpinBox->value()); dsv->setAnatomyThresholdValid(true); } else if (whitePeakRadioButton->isChecked()) { dsv->setAnatomyThreshold(whitePeakSpinBox->value()); dsv->setAnatomyThresholdValid(true); } else { dsv->setAnatomyThresholdValid(false); } GuiBrainModelOpenGL::updateAllGL(); } /** * Create the segmentation selections page. */ QWidget* GuiVolumeSureFitSegmentationDialog::createSegmentationSelectionsPage() { disconnectEyeCheckBox = new QCheckBox("Disconnect Eye and Skull"); disconnectEyeCheckBox->setChecked(true); disconnectHindbrainCheckBox = new QCheckBox("Disconnect Hindbrain"); hindLoHiThreshComboBox = new QComboBox; hindLoHiThreshComboBox->insertItem(HIND_BRAIN_THRESHOLD_HIGH, "High Threshold"); hindLoHiThreshComboBox->insertItem(HIND_BRAIN_THRESHOLD_LOW, "Low Threshold"); QObject::connect(disconnectHindbrainCheckBox, SIGNAL(toggled(bool)), hindLoHiThreshComboBox, SLOT(setEnabled(bool))); disconnectHindbrainCheckBox->setChecked(true); QHBoxLayout* hindbrainLayout = new QHBoxLayout; hindbrainLayout->addWidget(disconnectHindbrainCheckBox); hindbrainLayout->addWidget(hindLoHiThreshComboBox); hindbrainLayout->addStretch(); cutCorpusCallosumCheckBox = new QCheckBox("Cut Corpus Callosum"); cutCorpusCallosumCheckBox->setChecked(true); generateSegmentationCheckBox = new QCheckBox("Generate Segmentation"); generateSegmentationCheckBox->setChecked(true); QObject::connect(generateSegmentationCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotEnableDisableSelectionCheckBoxes())); fillVentriclesCheckBox = new QCheckBox("Fill Ventricles"); fillVentriclesCheckBox->setChecked(true); volumeErrorCorrectionCheckBox = new QCheckBox("Volume Error Correction Method"); volumeErrorCorrectionCheckBox->setChecked(true); QObject::connect(volumeErrorCorrectionCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotEnableDisableSelectionCheckBoxes())); volumeErrorCorrectionMethodComboBox = new QComboBox; std::vector errorCorrectionValues; std::vector errorCorrectionNames; BrainModelVolumeSureFitSegmentation::getErrorCorrectionMethodsAndNames( errorCorrectionNames, errorCorrectionValues); int defaultErrorIndex = 0; for (unsigned int i = 0; i < errorCorrectionNames.size(); i++) { if (errorCorrectionValues[i] != BrainModelVolumeSureFitSegmentation::ERROR_CORRECTION_METHOD_NONE) { volumeErrorCorrectionMethodComboBox->addItem( errorCorrectionNames[i], static_cast(errorCorrectionValues[i])); if (errorCorrectionValues[i] == BrainModelVolumeSureFitSegmentation::ERROR_CORRECTION_METHOD_SUREFIT_AND_GRAPH) { defaultErrorIndex = volumeErrorCorrectionMethodComboBox->count() - 1; } } } volumeErrorCorrectionMethodComboBox->setCurrentIndex(defaultErrorIndex); QHBoxLayout* errorCorrectionLayout = new QHBoxLayout; errorCorrectionLayout->addWidget(volumeErrorCorrectionCheckBox); errorCorrectionLayout->addWidget(volumeErrorCorrectionMethodComboBox); errorCorrectionLayout->addStretch(); generateRawAndFiducialSurfaceCheckBox = new QCheckBox("Generate Raw and Fiducial Surfaces"); generateRawAndFiducialSurfaceCheckBox->setChecked(true); QObject::connect(generateRawAndFiducialSurfaceCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotEnableDisableSelectionCheckBoxes())); generateTopologicallyCorrectFiducialSurfaceCheckBox = new QCheckBox("Correct All Topological Errors in Fiducial Surface (USE WITH CAUTION)"); generateTopologicallyCorrectFiducialSurfaceCheckBox->setChecked(false); QObject::connect(generateTopologicallyCorrectFiducialSurfaceCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotGenerateTopologicallyCorrectFiducialSurfaceCheckBox(bool))); generateSurfaceLimitPolygonsCheckBox = new QCheckBox("Limit Polygons in Generated Surface(s)"); generateSurfaceLimitPolygonsCheckBox->setChecked(true); generateInflatedSurfaceCheckBox = new QCheckBox("Generate Inflated Surface"); generateInflatedSurfaceCheckBox->setChecked(true); generateVeryInflatedSurfaceCheckBox = new QCheckBox("Generate Very Inflated Surface"); generateVeryInflatedSurfaceCheckBox->setChecked(true); generateEllipsoidSurfaceCheckBox = new QCheckBox("Generate Ellipsoid Surface (for Flattening)"); generateEllipsoidSurfaceCheckBox->setChecked(true); generateSphericalSurfaceCheckBox = new QCheckBox("Generate Spherical Surface"); generateSphericalSurfaceCheckBox->setChecked(false); generateCompMedWallSurfaceCheckBox = new QCheckBox("Generate Compressed Medial Wall Surface"); generateCompMedWallSurfaceCheckBox->setChecked(false); generateHullCheckBox = new QCheckBox("Generate Cerebral Hull"); generateHullCheckBox->setChecked(true); generateDepthCurvatureGeographyCheckBox = new QCheckBox("Create Curvature, Depth, and Geography Attributes"); generateDepthCurvatureGeographyCheckBox->setChecked(true); generateLandmarkBordersCheckBox = new QCheckBox("Create Flatten and Registration Landmark Borders"); generateLandmarkBordersCheckBox->setChecked(false); autoSaveFilesCheckBox = new QCheckBox("Auto Save Generated Data Files"); autoSaveFilesCheckBox->setChecked(true); // // Group box and layout for anatomical volume controls // anatomicalVolumeOptionsGroupBox = new QGroupBox("Anatomical Volume Options"); QVBoxLayout* anatomicalVolumeGroupLayout = new QVBoxLayout(anatomicalVolumeOptionsGroupBox); anatomicalVolumeGroupLayout->addWidget(disconnectEyeCheckBox); anatomicalVolumeGroupLayout->addLayout(hindbrainLayout); anatomicalVolumeGroupLayout->addWidget(cutCorpusCallosumCheckBox); anatomicalVolumeGroupLayout->addWidget(generateSegmentationCheckBox); anatomicalVolumeGroupLayout->addWidget(fillVentriclesCheckBox); // // Group box and layout for segmentation volume options // segmentationVolumeOptionsGroupBox = new QGroupBox("Segmentation Volume Options"); QVBoxLayout* segmentationVolumeGroupLayout = new QVBoxLayout(segmentationVolumeOptionsGroupBox); segmentationVolumeGroupLayout->addLayout(errorCorrectionLayout); segmentationVolumeGroupLayout->addWidget(generateRawAndFiducialSurfaceCheckBox); segmentationVolumeGroupLayout->addWidget(generateSurfaceLimitPolygonsCheckBox); segmentationVolumeGroupLayout->addWidget(generateTopologicallyCorrectFiducialSurfaceCheckBox); segmentationVolumeGroupLayout->addWidget(generateInflatedSurfaceCheckBox); segmentationVolumeGroupLayout->addWidget(generateVeryInflatedSurfaceCheckBox); segmentationVolumeGroupLayout->addWidget(generateEllipsoidSurfaceCheckBox); segmentationVolumeGroupLayout->addWidget(generateSphericalSurfaceCheckBox); segmentationVolumeGroupLayout->addWidget(generateCompMedWallSurfaceCheckBox); segmentationVolumeGroupLayout->addWidget(generateHullCheckBox); segmentationVolumeGroupLayout->addWidget(generateDepthCurvatureGeographyCheckBox); segmentationVolumeGroupLayout->addWidget(generateLandmarkBordersCheckBox); segmentationVolumeGroupLayout->addWidget(autoSaveFilesCheckBox); // // widget and layout for page // QWidget* w = new QWidget; QVBoxLayout* layout = new QVBoxLayout(w); layout->addWidget(anatomicalVolumeOptionsGroupBox); layout->addWidget(segmentationVolumeOptionsGroupBox); layout->addStretch(); return w; } /** * called when correct topological errors in fiducial surface checkbox toggled. */ void GuiVolumeSureFitSegmentationDialog::slotGenerateTopologicallyCorrectFiducialSurfaceCheckBox(bool b) { static bool warningAlreadyGivenFlag = false; if (b) { if (warningAlreadyGivenFlag == false) { //warningAlreadyGivenFlag = true; const QString msg = "This option, which corrects all topological errors in the fiducial surface," "should be used with caution. While the resulting surface will be topologically" "correct, it will not necessarily be anatomically correct. In areas of the " "surface where correction occurs, there may be adjacent triangles with sharply" "angled edges, such as those you might find on a diamond or cubic zirconia. It" "is best to correct the topological errors in the segmentation, particularly if" "the topological errors are large or involve non-cortical material such as a" "blood vessel or the optic chiasm.\n" "\n" "This option is probably best used if there are small topological errors in" "the medial wall or if the user is unable to find remaining topological " "errors. The user may check for topological errors by selecting Surface" "Menu->Topology->Topology Error Report. An \"Euler Count\" of 2 indicates" "that there are no topological errors and the surface is topologically " "equivalent to a sphere.\n" "\n" "If you are using surface shape depth maps for comparing coritical shape " "your topological corrections MUST be done in the volume since the " "segmentation volume is used to generate the cerebral hull which in turn" "is used to compute depth measurements.\n" "\n" "When this option is used, two fiducial coordinate files and two closed" "topology files will be produced. One fiducial coordinate and closed" "topology file pair will contain the uncorrected surface and the other" "will contain the corrected surface.\n" "\n" "If you have questions or wish to provided feedback on this option, please" "send an email to john@brainmap.wustl.edu."; QMessageBox::warning(this, "WARNING", msg); } } } /** * called to enable/disable selection check boxes. */ void GuiVolumeSureFitSegmentationDialog::slotEnableDisableSelectionCheckBoxes() { anatomicalVolumeOptionsGroupBox->setEnabled(false); segmentationVolumeOptionsGroupBox->setEnabled(false); disconnectEyeCheckBox->setEnabled(false); disconnectHindbrainCheckBox->setEnabled(false); cutCorpusCallosumCheckBox->setEnabled(false); generateSegmentationCheckBox->setEnabled(false); fillVentriclesCheckBox->setEnabled(false); generateRawAndFiducialSurfaceCheckBox->setEnabled(false); generateSurfaceLimitPolygonsCheckBox->setEnabled(false); generateInflatedSurfaceCheckBox->setEnabled(false); generateVeryInflatedSurfaceCheckBox->setEnabled(false); generateEllipsoidSurfaceCheckBox->setEnabled(false); generateSphericalSurfaceCheckBox->setEnabled(false); generateCompMedWallSurfaceCheckBox->setEnabled(false); generateHullCheckBox->setEnabled(false); volumeErrorCorrectionCheckBox->setEnabled(false); volumeErrorCorrectionMethodComboBox->setEnabled(false); generateDepthCurvatureGeographyCheckBox->setEnabled(false); generateLandmarkBordersCheckBox->setEnabled(false); const VolumeFile* anatomyVolumeFile = volumeAnatomySelectionControl->getSelectedVolumeFile(); const VolumeFile* segmentationVolumeFile = volumeSegmentationSelectionControl->getSelectedVolumeFile(); if ((anatomyVolumeFile == NULL) && (segmentationVolumeFile == NULL)) { return; } const bool anatValid = ((anatomyVolumeFile != NULL) && (mode == MODE_ANATOMICAL_VOLUME_SEGMENTATION)); if (anatValid) { anatomicalVolumeOptionsGroupBox->setEnabled(true); disconnectEyeCheckBox->setEnabled(true); disconnectHindbrainCheckBox->setEnabled(true); cutCorpusCallosumCheckBox->setEnabled(true); generateSegmentationCheckBox->setEnabled(true); fillVentriclesCheckBox->setEnabled(true); volumeErrorCorrectionCheckBox->setEnabled(true); } switch (mode) { case MODE_NONE: break; case MODE_ANATOMICAL_VOLUME_SEGMENTATION: if (anatValid && generateSegmentationCheckBox->isChecked()) { segmentationVolumeOptionsGroupBox->setEnabled(true); } break; case MODE_SEMENTATION_VOLUME_POST_PROCESSING: if (segmentationVolumeFile != NULL) { segmentationVolumeOptionsGroupBox->setEnabled(true); } break; } if (segmentationVolumeOptionsGroupBox->isEnabled()) { volumeErrorCorrectionCheckBox->setEnabled(true); generateRawAndFiducialSurfaceCheckBox->setEnabled(true); const bool createRawFidValid = generateRawAndFiducialSurfaceCheckBox->isChecked() && generateRawAndFiducialSurfaceCheckBox->isEnabled(); generateSurfaceLimitPolygonsCheckBox->setEnabled(createRawFidValid); generateTopologicallyCorrectFiducialSurfaceCheckBox->setEnabled(createRawFidValid); generateInflatedSurfaceCheckBox->setEnabled(createRawFidValid); generateVeryInflatedSurfaceCheckBox->setEnabled(createRawFidValid); generateEllipsoidSurfaceCheckBox->setEnabled(createRawFidValid); generateSphericalSurfaceCheckBox->setEnabled(createRawFidValid); generateCompMedWallSurfaceCheckBox->setEnabled(createRawFidValid); generateDepthCurvatureGeographyCheckBox->setEnabled(createRawFidValid); const bool validLandmarkSpaceFlag = BrainModelSurfaceBorderLandmarkIdentification::isStereotaxicSpaceSupported( theMainWindow->getBrainSet()->getStereotaxicSpace()); generateLandmarkBordersCheckBox->setEnabled((anatomyVolumeFile != NULL) && createRawFidValid && (generateInflatedSurfaceCheckBox->isEnabled() && generateInflatedSurfaceCheckBox->isChecked()) && (generateVeryInflatedSurfaceCheckBox->isEnabled() && generateVeryInflatedSurfaceCheckBox->isChecked()) && (generateEllipsoidSurfaceCheckBox->isEnabled() && generateEllipsoidSurfaceCheckBox->isChecked()) && (generateDepthCurvatureGeographyCheckBox->isEnabled() && generateDepthCurvatureGeographyCheckBox->isChecked()) && validLandmarkSpaceFlag); generateHullCheckBox->setEnabled(generateDepthCurvatureGeographyCheckBox->isEnabled() && generateDepthCurvatureGeographyCheckBox->isChecked()); } volumeErrorCorrectionMethodComboBox->setEnabled( volumeErrorCorrectionCheckBox->isEnabled() && volumeErrorCorrectionCheckBox->isChecked()); } /** * Create the segmentation complete page. */ QWidget* GuiVolumeSureFitSegmentationDialog::createSegmentationCompletePage() { QLabel* completeLabel = new QLabel("The segmentation has successfully completed."); segmentationCompleteTimeLabel = new QLabel(""); segmentationCompleteHandleLabel = new QLabel(""); QWidget* w = new QWidget; QVBoxLayout* layout = new QVBoxLayout(w); layout->addWidget(completeLabel); layout->addWidget(segmentationCompleteTimeLabel); layout->addWidget(segmentationCompleteHandleLabel); layout->addStretch(); return w; } /** * Called when back pushbutton pressed. */ void GuiVolumeSureFitSegmentationDialog::slotBackPushButton() { BrainModelVolume* bmv = theMainWindow->getBrainSet()->getBrainModelVolume(); if (bmv == NULL) { QMessageBox::critical(this, "ERROR", "There are no volumes loaded."); showPage(pagesStackedWidget->widget(0), true); return; } const int indx = pagesStackedWidget->currentIndex() - 1; if (indx >= 0) { QWidget* nextPage = pagesStackedWidget->widget(indx); if (nextPage == grayWhitePeaksPage) { // // Doing anatomy volume ? // const bool anatValid = (volumeAnatomySelectionControl->getSelectedVolumeFile() != NULL); if (anatValid == false) { // // Since no anatomical volume, go to volume attributes page // nextPage = volumeAttributesPage; } } showPage(nextPage, true); } } /** * Called to select the next page. */ void GuiVolumeSureFitSegmentationDialog::slotNextPushButton() { BrainModelVolume* bmv = theMainWindow->getBrainSet()->getBrainModelVolume(); if (bmv == NULL) { QMessageBox::critical(this, "ERROR", "There are no volumes loaded."); showPage(pagesStackedWidget->widget(0)); return; } // // Get the current page // QWidget* currentPage = pagesStackedWidget->currentWidget(); // // If the current page is subject info // if (currentPage == subjectInfoPage) { QString msg; const StereotaxicSpace space = stereotaxicSpaceComboBox->getSelectedStereotaxicSpace(); const Structure::STRUCTURE_TYPE hemisphere = structureComboBox->getSelectedStructure(); const Species species = speciesComboBox->getSelectedSpecies(); const QString subject = subjectLineEdit->text(); if (space.isValid() == false) { msg.append("Steretaxic Space is invalid."); } if (hemisphere == Structure::STRUCTURE_TYPE_INVALID) { msg.append("Hemisphere must be not be Unknown.\n"); } if (species.isValid() == false) { msg.append("The species is invalid.\n"); } if (subject.isEmpty()) { msg.append("You must enter a subject.\n"); } if (msg.isEmpty() == false) { QMessageBox::critical(this, "ERROR", msg); return; } // // Update brain set // const bool dataChanged = ((theMainWindow->getBrainSet()->getStructure() != hemisphere) || (theMainWindow->getBrainSet()->getSpecies() != species) || (theMainWindow->getBrainSet()->getSubject() != subject) || (theMainWindow->getBrainSet()->getStereotaxicSpace() != space)); theMainWindow->getBrainSet()->setStructure(hemisphere); theMainWindow->getBrainSet()->setSpecies(Species(species)); theMainWindow->getBrainSet()->setSubject(subject); theMainWindow->getBrainSet()->setStereotaxicSpace(space); // // Update spec file if needed // if (dataChanged) { const QString specFileName(theMainWindow->getBrainSet()->getSpecFileName()); SpecFile specFile; try { specFile.readFile(specFileName); specFile.setStructure(theMainWindow->getBrainSet()->getStructure().getTypeAsString()); specFile.setSpecies(theMainWindow->getBrainSet()->getSpecies().getName()); specFile.setSubject(theMainWindow->getBrainSet()->getSubject()); specFile.setSpace(theMainWindow->getBrainSet()->getStereotaxicSpace()); specFile.writeFile(specFileName); } catch (FileException&) { } } } // // If the current page is the spec file page // if (currentPage == specFilePage) { const QString specFileName(specFileNameLineEdit->text()); const QString filename(FileUtilities::basename(specFileName)); if (QFile::exists(specFileName)) { if (StringUtilities::endsWith(specFileName, "/") || StringUtilities::endsWith(specFileName, "\\")) { QMessageBox::critical(this, "ERROR", "Name of spec file is missing."); return; } } else { const QString directory(FileUtilities::dirname(specFileName)); if (QFile::exists(directory) == false) { QMessageBox::critical(this, "ERROR", "Directory of spec file does not exist." "Create the directory before continuing."); return; } if (filename == SpecFile::getSpecFileExtension()) { QMessageBox::critical(this, "ERROR", "Name of spec file is missing, just have extension.\n"); return; } } // // Set the name of the spec file and the current directory // theMainWindow->getBrainSet()->setSpecFileName(specFileName); QDir::setCurrent(FileUtilities::dirname(specFileName)); // // Update spec file if necessary // { SpecFile specFile; try { specFile.readFile(FileUtilities::basename(specFileName)); } catch (FileException&) { // // Spec file may not exist but that is OK // } const bool updateSpecFile = ((specFile.getStructure() != theMainWindow->getBrainSet()->getStructure().getTypeAsString()) || (specFile.getSpecies().getName() != theMainWindow->getBrainSet()->getSpecies().getName()) || (specFile.getSubject() != theMainWindow->getBrainSet()->getSubject()) || (specFileCommentTextEdit->document()->isModified())); if (updateSpecFile) { specFile.setStructure(theMainWindow->getBrainSet()->getStructure().getTypeAsString()); specFile.setSpecies(theMainWindow->getBrainSet()->getSpecies()); specFile.setSubject(theMainWindow->getBrainSet()->getSubject()); specFile.setFileComment(specFileCommentTextEdit->toPlainText()); try { specFile.writeFile(specFileName); } catch (FileException&) { } } } } VolumeFile* vfa = volumeAnatomySelectionControl->getSelectedVolumeFile(); const VolumeFile* vfs = volumeSegmentationSelectionControl->getSelectedVolumeFile(); // // If the current page is the volume selection page // if (currentPage == volumeSelectionPage) { if ((vfa == NULL) && (vfs == NULL)) { QMessageBox::critical(this, "ERROR", "You must select a volume."); return; } if (vfa != NULL) { if (vfa != bmv->getSelectedVolumeAnatomyFile()) { if (QMessageBox::warning(this, "Warning", "The anatomy volume selected for segmenting is " "different than the anatomy volume selected on " "the Display Control Dialog.", (QMessageBox::Ok | QMessageBox::Cancel), QMessageBox::Cancel) == QMessageBox::Cancel) { return; } } } if (vfs != NULL) { if (vfs != bmv->getSelectedVolumeSegmentationFile()) { if (QMessageBox::warning(this, "Warning", "The segmentation volume selected for processing is " "different than the segmentation volume selected " "on the Display Control Dialog.", (QMessageBox::Ok | QMessageBox::Cancel), QMessageBox::Cancel) == QMessageBox::Cancel) { return; } } } switch (mode) { case MODE_NONE: break; case MODE_ANATOMICAL_VOLUME_SEGMENTATION: break; case MODE_SEMENTATION_VOLUME_POST_PROCESSING: if (vfa == NULL) { if (QMessageBox::warning(this, "Warning", "No anatomical volume is selected. The anatomical " "volume is required if you want to generate " "landmark borders.", (QMessageBox::Ok | QMessageBox::Cancel), QMessageBox::Cancel) == QMessageBox::Cancel) { return; } } break; } } QString msg; // // If the current page is the attributes page // if (currentPage == volumeAttributesPage) { if ((vfa == NULL) && (vfs == NULL)) { QMessageBox::critical(this, "ERROR", "You must select a volume."); return; } if (vfa != NULL) { VolumeFile::ORIENTATION orient[3]; vfa->getOrientation(orient); bool orientationError = false; if (orient[0] != VolumeFile::ORIENTATION_LEFT_TO_RIGHT) { msg.append("The X axis must be in left-to-right orientation.\n"); orientationError = true; } if (orient[1] != VolumeFile::ORIENTATION_POSTERIOR_TO_ANTERIOR) { msg.append("The Y axis must be in posterior-to-anterior orientation.\n"); orientationError = true; } if (orient[2] != VolumeFile::ORIENTATION_INFERIOR_TO_SUPERIOR) { msg.append("The Z axis must be in inferior-to-superior orientation.\n"); orientationError = true; } if (orientationError) { msg.append("Press the OK button to close this message dialog. After doing so,\n" "select \"Edit Volume Attributes\" from the Volume Menu. Press the tab\n" "labeled \"Orientation\".\n"); } float minVoxel, maxVoxel; vfa->getMinMaxVoxelValues(minVoxel, maxVoxel); if ((minVoxel < 0.0) || (maxVoxel > 255.0) || (maxVoxel <= 1.0)) { std::ostringstream str; str << "Voxels must be in the range (0.0, 255.0).\n" << "The selected volume's range is (" << minVoxel << ", " << maxVoxel << ").\n" << "Press the OK button to close this message dialog. After doing so," << "select \"Edit Volume Attributes\" from the Volume Menu. Press the tab" << "labeled \"Data\" and then press the button labeled \"Rescale Voxels\"."; if (msg.isEmpty() == false) { msg.append("\n"); } msg.append(str.str().c_str()); } } if (vfs != NULL) { VolumeFile::ORIENTATION orient[3]; vfs->getOrientation(orient); float origin[3]; vfs->getOrigin(origin); float spacing[3]; vfs->getSpacing(spacing); bool orientationError = false; if (orient[0] != VolumeFile::ORIENTATION_LEFT_TO_RIGHT) { msg.append("The X axis must be in left-to-right orientation.\n"); orientationError = true; } if (orient[1] != VolumeFile::ORIENTATION_POSTERIOR_TO_ANTERIOR) { msg.append("The Y axis must be in posterior-to-anterior orientation.\n"); orientationError = true; } if (orient[2] != VolumeFile::ORIENTATION_INFERIOR_TO_SUPERIOR) { msg.append("The Z axis must be in inferior-to-superior orientation.\n"); orientationError = true; } if (orientationError) { msg.append("Press the OK button to close this message dialog. After doing so,\n" "select \"Edit Volume Attributes\" from the Volume Menu. Press the tab\n" "labeled \"Orientation\".\n"); } } if (msg.isEmpty() == false) { QMessageBox::critical(this, "ERROR", msg); return; } bool voxelSizeOK = true; if (vfa != NULL) { float anatomySpacing[3]; vfa->getSpacing(anatomySpacing); for (int i = 0; i < 3; i++) { if ((anatomySpacing[i] < 0.99) || (anatomySpacing[i] > 1.01)) { voxelSizeOK = false; } } } if (vfa != NULL) { float anatomyOrigin[3]; vfa->getOrigin(anatomyOrigin); if ((anatomyOrigin[0] >= 0.0) || (anatomyOrigin[1] >= 0.0) || (anatomyOrigin[2] >= 0.0)) { QString msg("At least one anatomy origin value is greater than or equal to zero." "This indicates that the origin may not be at the Anterior" "commissure. Do you want to continue ?"); if (QMessageBox::warning(this, "Warning", msg, (QMessageBox::Yes | QMessageBox::No), QMessageBox::No) == QMessageBox::No) { return; } } } } // // If the current page is the volume file type page // if (currentPage == volumeFileTypePage) { if (fileTypeAfniRadioButton->isChecked()) { typeOfVolumesToWrite = VolumeFile::FILE_READ_WRITE_TYPE_AFNI; } else if (fileTypeNiftiRadioButton->isChecked()) { typeOfVolumesToWrite = VolumeFile::FILE_READ_WRITE_TYPE_NIFTI; } else if (fileTypeNiftiGzipRadioButton->isChecked()) { typeOfVolumesToWrite = VolumeFile::FILE_READ_WRITE_TYPE_NIFTI_GZIP; } else { QMessageBox::critical(this, "ERROR", "Choose a volume file write type."); return; } } // // If the current page is the gray/white peaks page // if (currentPage == grayWhitePeaksPage) { QString msg; if (grayPeakSpinBox->value() <= 0) { msg.append("The gray peak must be greater than zero.\n"); } if (whitePeakSpinBox->value() <= 0) { msg.append("The white peak must be greater than zero.\n"); } if (whitePeakSpinBox->value() < grayPeakSpinBox->value()) { msg.append("The white peak must be greater than the gray peak.\n"); } if (msg.isEmpty() == false) { QMessageBox::critical(this, "ERROR", msg); return; } // // Update the parameters file // ParamsFile* pf = theMainWindow->getBrainSet()->getParamsFile(); pf->setParameter(ParamsFile::keyCGMpeak, grayPeakSpinBox->value()); pf->setParameter(ParamsFile::keyWMpeak, whitePeakSpinBox->value()); if (overrideThreshSetCheckBox->isChecked()) { pf->setParameter(ParamsFile::keyWMThreshSet, overridePeakSpinBox->value()); } else { pf->setParameter(ParamsFile::keyWMThreshSet, 0); } // // Write the parameters file // try { theMainWindow->getBrainSet()->writeParamsFile(pf->getFileName()); //pf->writeFile(pf->getFileName()); } catch (FileException& e) { std::cout << "INFO: Unable to write parameters file: " << e.whatQString().toAscii().constData() << std::endl; } // // Turn off any thresholding // DisplaySettingsVolume* dsv = theMainWindow->getBrainSet()->getDisplaySettingsVolume(); dsv->setAnatomyThresholdValid(false); GuiBrainModelOpenGL::updateAllGL(); } // // If segmentation selections page // if (currentPage == segmentationSelectionsPage) { performSegmentation(); } //================================================================================= // // Move to next page // const int indx = pagesStackedWidget->currentIndex() + 1; if (indx < pagesStackedWidget->count()) { QWidget* nextPage = pagesStackedWidget->widget(indx); // // If next page is gray/white peaks page // if (nextPage == grayWhitePeaksPage) { // // Doing anatomy volume ? // const bool anatValid = ((volumeAnatomySelectionControl->getSelectedVolumeFile() != NULL) && (mode == MODE_ANATOMICAL_VOLUME_SEGMENTATION)); if (anatValid == false) { // // Skip to segmentation page // nextPage = segmentationSelectionsPage; } } showPage(nextPage); } } /** * Prepare some pages when they are about to be shown */ void GuiVolumeSureFitSegmentationDialog::showPage(QWidget* page, const bool backPushButtonPressed) { // // If NOT moving forward thru pages // if (backPushButtonPressed == false) { // // If about to show the current directory page // if (page == changeDirectoryPage) { updateCurrentDirectoryPage(); } // // If the page about to show is the subject info page // if (page == subjectInfoPage) { // // Set species, subject, and hemisphere // stereotaxicSpaceComboBox->setSelectedStereotaxicSpace(theMainWindow->getBrainSet()->getStereotaxicSpace()); speciesComboBox->setSelectedSpecies(theMainWindow->getBrainSet()->getSpecies()); subjectLineEdit->setText(theMainWindow->getBrainSet()->getSubject()); structureComboBox->setStructure(theMainWindow->getBrainSet()->getStructure().getType()); } // // If the volume attributes page is about to show // if (page == volumeAttributesPage) { updateVolumeAttributesPage(); } // // If the current page is the volume file type page // if (page == volumeFileTypePage) { fileTypeAfniRadioButton->setChecked(false); fileTypeNiftiRadioButton->setChecked(false); fileTypeNiftiGzipRadioButton->setChecked(false); switch (typeOfVolumesToWrite) { case VolumeFile::FILE_READ_WRITE_TYPE_RAW: break; case VolumeFile::FILE_READ_WRITE_TYPE_AFNI: fileTypeAfniRadioButton->setChecked(true); break; case VolumeFile::FILE_READ_WRITE_TYPE_ANALYZE: break; case VolumeFile::FILE_READ_WRITE_TYPE_NIFTI: fileTypeNiftiRadioButton->setChecked(true); break; case VolumeFile::FILE_READ_WRITE_TYPE_NIFTI_GZIP: fileTypeNiftiGzipRadioButton->setChecked(true); break; case VolumeFile::FILE_READ_WRITE_TYPE_SPM_OR_MEDX: break; case VolumeFile::FILE_READ_WRITE_TYPE_WUNIL: break; case VolumeFile::FILE_READ_WRITE_TYPE_UNKNOWN: break; } } // // If the spec file page is about to be displayed // if (page == specFilePage) { QString name = theMainWindow->getBrainSet()->getSpecFileName(); if (name.isEmpty()) { std::ostringstream str; str << QDir::currentPath().toAscii().constData() << QString(QDir::separator()).toAscii().constData() << theMainWindow->getBrainSet()->getSpecies().getName().toAscii().constData() << "." << theMainWindow->getBrainSet()->getSubject().toAscii().constData() << "." << theMainWindow->getBrainSet()->getStructure().getTypeAsString().toAscii().constData() << SpecFile::getSpecFileExtension().toAscii().constData(); name = str.str().c_str(); } specFileNameLineEdit->setText(name); slotSpecFileSelected(name); } // // If about to show volume selection page // if (page == volumeSelectionPage) { // // anatomy selected and no anatomy files but have segmentation files // if ((volumeAnatomySelectionControl->getSelectedVolumeType() == VolumeFile::VOLUME_TYPE_ANATOMY) && (theMainWindow->getBrainSet()->getNumberOfVolumeAnatomyFiles() <= 0) && (theMainWindow->getBrainSet()->getNumberOfVolumeSegmentationFiles() > 0)) { volumeAnatomySelectionControl->setSelectedVolumeType(VolumeFile::VOLUME_TYPE_SEGMENTATION); } // // segmentation selected and no segmentation files but have anatomy files // if ((volumeSegmentationSelectionControl->getSelectedVolumeType() == VolumeFile::VOLUME_TYPE_SEGMENTATION) && (theMainWindow->getBrainSet()->getNumberOfVolumeSegmentationFiles() <= 0) && (theMainWindow->getBrainSet()->getNumberOfVolumeAnatomyFiles() > 0)) { volumeSegmentationSelectionControl->setSelectedVolumeType(VolumeFile::VOLUME_TYPE_ANATOMY); } } // // If the page about to be shown is the gray white peaks page // if (page == grayWhitePeaksPage) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); ParamsFile* pf = theMainWindow->getBrainSet()->getParamsFile(); int gray = 0; int white = 0; pf->getParameter(ParamsFile::keyCGMpeak, gray); pf->getParameter(ParamsFile::keyWMpeak, white); int peakOverride = 0; pf->getParameter(ParamsFile::keyWMThreshSet, peakOverride); overridePeakSpinBox->setValue(peakOverride); overrideThreshSetCheckBox->setChecked(peakOverride != 0); overridePeakSpinBox->setEnabled(overrideThreshSetCheckBox->isChecked()); // // Get the selected volume // VolumeFile* vfa = volumeAnatomySelectionControl->getSelectedVolumeFile(); if (vfa != NULL) { if (peakHistogram != NULL) { delete peakHistogram; peakHistogram = NULL; } peakHistogram = vfa->getHistogram(); loadHistogramIntoGraph(); // // Estimate the peaks // int grayBucket, whiteBucket, grayMinBucket, whiteMaxBucket, grayWhiteBucket, csfBucket; peakHistogram->getGrayWhitePeakEstimates(grayBucket, whiteBucket, grayMinBucket, whiteMaxBucket, grayWhiteBucket, csfBucket); int csfPeakEstimate = 0; int grayPeakEstimate = 0; int whitePeakEstimate = 0; if (grayBucket >= 0) { csfPeakEstimate = static_cast(peakHistogram->getDataValueForBucket(csfBucket)); grayPeakEstimate = static_cast(peakHistogram->getDataValueForBucket(grayBucket)); whitePeakEstimate = static_cast(peakHistogram->getDataValueForBucket(whiteBucket)); } csfPeakLabel->setNum(csfPeakEstimate); grayPeakLabel->setNum(grayPeakEstimate); whitePeakLabel->setNum(whitePeakEstimate); // // If no peaks yet, use estimates // if ((gray == 0) && (white == 0)) { gray = grayPeakEstimate; white = whitePeakEstimate; } // // Initialize graph scaling // if (initializeGraphScaleFlag) { const float minX = gray - 5.0; const float maxX = white + 10.0; initializeGraphScaleFlag = false; float theMax = -1.0; // // Use max of gray and white if available // if ((grayBucket > 0) && (whiteBucket > 0)) { if (grayBucket > whiteBucket) { float x, y; peakHistogram->getDataForBucket(grayBucket, x, y); theMax = y; } else { float x, y; peakHistogram->getDataForBucket(whiteBucket, x, y); theMax = y; } theMax *= 2.0; } else { const int numBuckets = peakHistogram->getNumberOfBuckets(); for (int j = 0; j < numBuckets; j++) { float x, y; peakHistogram->getDataForBucket(j, x, y); if ((x >= minX) && (x <= maxX)) { theMax = std::max(theMax, y) * 1.75; } } } if (theMax > 0.0) { peakHistogramWidget->setScaleYMaximum(theMax); } } // // Set the controls // grayPeakSpinBox->setValue(gray); whitePeakSpinBox->setValue(white); // // Update histogram widget // peakHistogramWidget->slotSetMinimumPeak(grayPeakSpinBox->value()); peakHistogramWidget->slotSetMaximumPeak(whitePeakSpinBox->value()); // // For volume coloring // if ((whitePeakRadioButton->isChecked() == false) && (grayPeakRadioButton->isChecked() == false)) { grayPeakRadioButton->setChecked(true); } slotPeakRadioButton(); } QApplication::restoreOverrideCursor(); } // // If the segmentation selections // if (page == segmentationSelectionsPage) { slotEnableDisableSelectionCheckBoxes(); } // // If the segmentation complete page is about to show // if (page == segmentationCompletePage) { // // Total execution time // std::ostringstream str; str << "Total Time: " << segmentationTime << " seconds."; segmentationCompleteTimeLabel->setText(str.str().c_str()); // // Handles in fiducial surface // str.str(""); if (generateRawAndFiducialSurfaceCheckBox->isEnabled() && generateRawAndFiducialSurfaceCheckBox->isChecked()) { BrainModelSurface* bms = theMainWindow->getBrainSet()->getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_FIDUCIAL); if (bms != NULL) { const TopologyFile* tf = bms->getTopologyFile(); if (tf != NULL) { int numFaces, numVertices, numEdges, eulerCount, numberOfHoles, numberOfObjects; tf->getEulerCount(false, numFaces, numVertices, numEdges, eulerCount, numberOfHoles, numberOfObjects); if ((numberOfHoles == 0) && (numberOfObjects == 1)) { str << "The fiducial surface has no topological defects."; } else { if (numberOfHoles > 0) { str << "The fiducial surface has " << numberOfHoles << " topological defects\n"; } if (numberOfObjects > 1) { str << "The fiducial surface has " << (numberOfObjects - 1) << " islands.\n"; } } } } } segmentationCompleteHandleLabel->setText(str.str().c_str()); } } // moving forward thru pages // // Show the pages // pagesStackedWidget->setCurrentWidget(page); currentPageLegend->setText(pageLegends[pagesStackedWidget->currentIndex()]); slotEnableDisablePushButtons(); } /** * load histogram into graph. */ void GuiVolumeSureFitSegmentationDialog::loadHistogramIntoGraph() { // // Clear all data from the graph // peakHistogramWidget->removeAllData(); // // Put data in histogram widget // const int numBuckets = peakHistogram->getNumberOfBuckets(); std::vector dataX, dataY; for (int j = 0; j < numBuckets; j++) { float x, y; peakHistogram->getDataForBucket(j, x, y); if (j == 0) { if (x > 0.0) { dataX.push_back(0.0); dataY.push_back(0.0); } } dataX.push_back(x); dataY.push_back(y); if (j == (numBuckets - 1)) { if (x < 255.0) { dataX.push_back(255.0); dataY.push_back(0.0); } } } peakHistogramWidget->addData(dataX, dataY, QColor(255, 0, 0), GuiGraphWidget::DRAW_DATA_TYPE_BARS); } /** * called when smooth button pressed. */ void GuiVolumeSureFitSegmentationDialog::slotSmoothHistogramPushButton() { double xMin, xMax, yMin, yMax; peakHistogramWidget->getGraphMinMax(xMin, xMax, yMin, yMax); const float strength = 0.50; const int iterations = 1; const int neighborDepth = 3; peakHistogram->smoothHistogram(strength, iterations, neighborDepth); loadHistogramIntoGraph(); peakHistogramWidget->setGraphMinMax(xMin, xMax, yMin, yMax); } /** * Enable/Disable push buttons. */ void GuiVolumeSureFitSegmentationDialog::slotEnableDisablePushButtons() { bool backValid = false; bool nextValid = false; // // Get the current page // QWidget* currentPage = pagesStackedWidget->currentWidget(); if (currentPage == changeDirectoryPage) { if (currentDirectoryIsCaretInstallationDirectory() == false) { nextValid = true; } } else if (currentPage == subjectInfoPage) { backValid = true; if (speciesComboBox->getSelectedSpecies().isValid() && stereotaxicSpaceComboBox->getSelectedStereotaxicSpace().isValid() && (subjectLineEdit->text().isEmpty() == false) && (structureComboBox->getSelectedStructure() != Structure::STRUCTURE_TYPE_INVALID)) { nextValid = true; } } else if (currentPage == specFilePage) { backValid = true; if (specFileNameLineEdit->text().isEmpty() == false) { nextValid = true; } } else if (currentPage == volumeSelectionPage) { backValid = true; volumeSelectionGroupBox->setEnabled(false); volumeAnatomySelectionControl->setEnabled(false); volumeSegmentationSelectionControl->setEnabled(false); mode = MODE_NONE; if (modeAnatomicalVolumeProcessingRadioButton->isChecked()) { mode = MODE_ANATOMICAL_VOLUME_SEGMENTATION; } else if (modeSegmentationVolumeProcessingRadioButton->isChecked()) { mode = MODE_SEMENTATION_VOLUME_POST_PROCESSING; } switch (mode) { case MODE_NONE: break; case MODE_ANATOMICAL_VOLUME_SEGMENTATION: volumeSelectionGroupBox->setEnabled(true); volumeAnatomySelectionControl->setEnabled(true); if (volumeAnatomySelectionControl->getSelectedVolumeFile() != NULL) { nextValid = true; } break; case MODE_SEMENTATION_VOLUME_POST_PROCESSING: volumeSelectionGroupBox->setEnabled(true); volumeAnatomySelectionControl->setEnabled(true); volumeSegmentationSelectionControl->setEnabled(true); if (volumeSegmentationSelectionControl->getSelectedVolumeFile() != NULL) { nextValid = true; } break; } } else if (currentPage == volumeFileTypePage) { if (fileTypeAfniRadioButton->isChecked()) { typeOfVolumesToWrite = VolumeFile::FILE_READ_WRITE_TYPE_AFNI; } else if (fileTypeNiftiGzipRadioButton->isChecked()) { typeOfVolumesToWrite = VolumeFile::FILE_READ_WRITE_TYPE_NIFTI_GZIP; } else if (fileTypeNiftiRadioButton->isChecked()) { typeOfVolumesToWrite = VolumeFile::FILE_READ_WRITE_TYPE_NIFTI; } backValid = true; nextValid = (fileTypeAfniRadioButton->isChecked() || fileTypeNiftiRadioButton->isChecked() || (fileTypeNiftiGzipRadioButton->isChecked())); } else if (currentPage == volumeAttributesPage) { backValid = true; nextValid = true; } else if (currentPage == grayWhitePeaksPage) { backValid = true; nextValid = true; } else if (currentPage == segmentationSelectionsPage) { backValid = true; nextValid = true; } else if (currentPage == segmentationCompletePage) { backValid = true; nextValid = false; } backPushButton->setEnabled(backValid); nextPushButton->setEnabled(nextValid); } /** * Perform the segmentation. */ bool GuiVolumeSureFitSegmentationDialog::performSegmentation() { BrainModelVolume* bmv = theMainWindow->getBrainSet()->getBrainModelVolume(); if (bmv == NULL) { QMessageBox::critical(this, "ERROR", "There are no volumes loaded."); return true; } VolumeFile* anatomyVolume = volumeAnatomySelectionControl->getSelectedVolumeFile(); VolumeFile* segmentationVolume = volumeSegmentationSelectionControl->getSelectedVolumeFile(); // // Get the selected volume // switch (mode) { case MODE_NONE: break; case MODE_ANATOMICAL_VOLUME_SEGMENTATION: if (anatomyVolume == NULL) { QMessageBox::critical(this, "ERROR", "No anatomical volume selected"); } break; case MODE_SEMENTATION_VOLUME_POST_PROCESSING: if (segmentationVolume == NULL) { QMessageBox::critical(this, "ERROR", "No segmentation volume selected"); } break; } if ((anatomyVolume == NULL) && (segmentationVolume == NULL)) { QMessageBox::critical(this, "ERROR", "No Anatomical Volume is Selected."); return true; } const float zeros[3] = { 0.0, 0.0, 0.0 }; int acIJK[3] = { 0, 0, 0 }; if (anatomyVolume != NULL) { if (anatomyVolume->convertCoordinatesToVoxelIJK(zeros, acIJK) == false) { if (QMessageBox::warning(this, "WARNING", "The Anterior Commissure is not located inside the volume." "If you are segmenting a partial hemisphere, this is " "probably okay. If you are segmenting a full hemisphere," "the origin of the volume is probably not set correctly.", (QMessageBox::Ok | QMessageBox::Cancel), QMessageBox::Cancel) == QMessageBox::Cancel) { return true; } } } else if (segmentationVolume != NULL) { if (segmentationVolume->convertCoordinatesToVoxelIJK(zeros, acIJK) == false) { if (QMessageBox::warning(this, "WARNING", "The Anterior Commissure is not located inside the volume." "If you are segmenting a partial hemisphere, this is " "probably okay. If you are segmenting a full hemisphere," "the origin of the volume is probably not set correctly.", (QMessageBox::Ok | QMessageBox::Cancel), QMessageBox::Cancel) == QMessageBox::Cancel) { return true; } } } // // Notify user about surface files in the spec file being removed // if (generateRawAndFiducialSurfaceCheckBox->isChecked() && generateRawAndFiducialSurfaceCheckBox->isEnabled()) { if (QMessageBox::information(this, "INFORMATION", "You have chosen to generate raw and fiducial surfaces. " "If the selected spec file contains any surface type files" "(coordinate, metric, topology, etc.) they will be removed" "from the spec file and deleted from the disk. These files" "will be deleted since the number of nodes in the newly " "generated files will be different and thus incompatible " " with the previously generated files.\n", (QMessageBox::Ok | QMessageBox::Cancel), QMessageBox::Ok) == QMessageBox::Cancel) { return true; } } const Structure::STRUCTURE_TYPE hemisphere = structureComboBox->getSelectedStructure(); // // If generating raw, fiducial, and ellipsoid surfaces // int paddingAmount[6] = { 0, 0, 0, 0, 0, 0 }; if ((generateRawAndFiducialSurfaceCheckBox->isChecked() && generateRawAndFiducialSurfaceCheckBox->isEnabled()) && (generateEllipsoidSurfaceCheckBox->isChecked() && generateEllipsoidSurfaceCheckBox->isEnabled())) { // // Check parameters file for padding from previous runs // int negX, posX, negY, posY, negZ, posZ; ParamsFile* pf = theMainWindow->getBrainSet()->getParamsFile(); pf->getParameter(ParamsFile::keyOldPadNegX, negX); pf->getParameter(ParamsFile::keyOldPadPosX, posX); pf->getParameter(ParamsFile::keyOldPadNegY, negY); pf->getParameter(ParamsFile::keyOldPadPosY, posY); pf->getParameter(ParamsFile::keyOldPadNegZ, negZ); pf->getParameter(ParamsFile::keyOldPadPosZ, posZ); QApplication::beep(); // // Dialog for optional padding // WuQDataEntryDialog pad(this); pad.setWindowTitle("Partial Hemisphere Padding"); pad.setTextAtTop("If the volume being reconstructed is a full hemisphere,\n" "no padding is needed. In this case, leave all checkboxes\n" "unchecked and press the \"OK\" button.\n" "\n" "If the volume being reconstructed is a partial hemisphere,\n" "please identify the location(s) of the cuts. Prior to \n" "reconstructing the surface, the volume will be padded where\n" "cuts have been made. This padding is necessary so that \n" "the surface can be flattened in Caret. After identifying\n" "the cuts, press the \"OK\" button to continue.", false); QCheckBox* negxCheckBox = pad.addCheckBox("Negative X", negX != 0); QCheckBox* posxCheckBox = pad.addCheckBox("Positive X", posX != 0); QCheckBox* negyCheckBox = pad.addCheckBox("Negative Y (Posterior)", negY != 0); QCheckBox* posyCheckBox = pad.addCheckBox("Positive Y (Anterior)", posY != 0); QCheckBox* negzCheckBox = pad.addCheckBox("Negative Z (Inferior)", negZ != 0); QCheckBox* poszCheckBox = pad.addCheckBox("Positive Z (Superior)", posZ != 0); switch (hemisphere) { case Structure::STRUCTURE_TYPE_CORTEX_LEFT: negxCheckBox->setText("Negative X (Lateral)"); posxCheckBox->setText("Positive X (Medial)"); break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT: negxCheckBox->setText("Negative X (Medial)"); posxCheckBox->setText("Positive X (Lateral)"); break; case Structure::STRUCTURE_TYPE_CEREBELLUM: break; case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_LEFT: break; case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_RIGHT: break; case Structure::STRUCTURE_TYPE_CORTEX_LEFT_OR_CEREBELLUM: break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT_OR_CEREBELLUM: break; case Structure::STRUCTURE_TYPE_CORTEX_BOTH: break; case Structure::STRUCTURE_TYPE_CEREBRUM_CEREBELLUM: case Structure::STRUCTURE_TYPE_SUBCORTICAL: case Structure::STRUCTURE_TYPE_ALL: case Structure::STRUCTURE_TYPE_INVALID: break; } QSpinBox* paddingAmountSpinBox = pad.addSpinBox("Padding Slices", 30, 1, 500, 1); if (pad.exec() == QDialog::Accepted) { if (negxCheckBox->isChecked()) { paddingAmount[0] = paddingAmountSpinBox->value(); } if (posxCheckBox->isChecked()) { paddingAmount[1] = paddingAmountSpinBox->value(); } if (negyCheckBox->isChecked()) { paddingAmount[2] = paddingAmountSpinBox->value(); } if (posyCheckBox->isChecked()) { paddingAmount[3] = paddingAmountSpinBox->value(); } if (negzCheckBox->isChecked()) { paddingAmount[4] = paddingAmountSpinBox->value(); } if (poszCheckBox->isChecked()) { paddingAmount[5] = paddingAmountSpinBox->value(); } // // Update params file with padding // pf->setParameter(ParamsFile::keyOldPadNegX, paddingAmount[0]); pf->setParameter(ParamsFile::keyOldPadPosX, paddingAmount[1]); pf->setParameter(ParamsFile::keyOldPadNegY, paddingAmount[2]); pf->setParameter(ParamsFile::keyOldPadPosY, paddingAmount[3]); pf->setParameter(ParamsFile::keyOldPadNegZ, paddingAmount[4]); pf->setParameter(ParamsFile::keyOldPadPosZ, paddingAmount[5]); try { theMainWindow->getBrainSet()->writeParamsFile(pf->getFileName()); } catch (FileException&) { } } else { return true; } } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainModelVolumeSureFitSegmentation::ERROR_CORRECTION_METHOD errorCorrectionMethod = BrainModelVolumeSureFitSegmentation::ERROR_CORRECTION_METHOD_NONE; if (volumeErrorCorrectionCheckBox->isEnabled() && volumeErrorCorrectionCheckBox->isChecked()) { errorCorrectionMethod = static_cast( volumeErrorCorrectionMethodComboBox->itemData( volumeErrorCorrectionMethodComboBox->currentIndex()).toInt()); } // // Segmentation algorithm // BrainModelVolumeSureFitSegmentation bmvs(theMainWindow->getBrainSet(), anatomyVolume, segmentationVolume, typeOfVolumesToWrite, acIJK, paddingAmount, whitePeakSpinBox->value(), grayPeakSpinBox->value(), 0.0, hemisphere, disconnectEyeCheckBox->isChecked() && disconnectEyeCheckBox->isEnabled(), disconnectHindbrainCheckBox->isChecked() && disconnectHindbrainCheckBox->isEnabled(), (hindLoHiThreshComboBox->currentIndex() == HIND_BRAIN_THRESHOLD_HIGH), cutCorpusCallosumCheckBox->isChecked() && cutCorpusCallosumCheckBox->isEnabled(), generateSegmentationCheckBox->isChecked() && generateSegmentationCheckBox->isEnabled(), fillVentriclesCheckBox->isChecked() && fillVentriclesCheckBox->isEnabled(), errorCorrectionMethod, generateRawAndFiducialSurfaceCheckBox->isChecked() && generateRawAndFiducialSurfaceCheckBox->isEnabled(), (generateSurfaceLimitPolygonsCheckBox->isChecked() == false), generateTopologicallyCorrectFiducialSurfaceCheckBox->isChecked() && generateTopologicallyCorrectFiducialSurfaceCheckBox->isEnabled(), generateInflatedSurfaceCheckBox->isChecked() && generateInflatedSurfaceCheckBox->isEnabled(), generateVeryInflatedSurfaceCheckBox->isChecked() && generateVeryInflatedSurfaceCheckBox->isEnabled(), generateEllipsoidSurfaceCheckBox->isChecked() && generateEllipsoidSurfaceCheckBox->isEnabled(), generateSphericalSurfaceCheckBox->isChecked() && generateSphericalSurfaceCheckBox->isEnabled(), generateCompMedWallSurfaceCheckBox->isChecked() && generateCompMedWallSurfaceCheckBox->isEnabled(), generateHullCheckBox->isChecked() && generateHullCheckBox->isEnabled(), generateDepthCurvatureGeographyCheckBox->isChecked() && generateDepthCurvatureGeographyCheckBox->isEnabled(), generateLandmarkBordersCheckBox->isChecked() && generateLandmarkBordersCheckBox->isEnabled(), autoSaveFilesCheckBox->isChecked()); // // Make the dialog disappear while the algorithms are executed // this->hide(); QTime algorithmTimer; algorithmTimer.start(); segmentationTime = 0.0; try { bmvs.execute(); WuQDialog::show(); // use this otherwise initial page gets shown segmentationTime = algorithmTimer.elapsed() * 0.001; // // make newest segmentation the selected segmentation // DisplaySettingsVolume* dsv = theMainWindow->getBrainSet()->getDisplaySettingsVolume(); if (theMainWindow->getBrainSet()->getNumberOfVolumeSegmentationFiles() > 0) { dsv->setSelectedSegmentationVolume(theMainWindow->getBrainSet()->getNumberOfVolumeSegmentationFiles() - 1); } // // Make segmentation the primary overlay, no secondary overlay, // and set the underlay to anatomy // BrainModelVolumeVoxelColoring* bmvvc = theMainWindow->getBrainSet()->getVoxelColoring(); bmvvc->setPrimaryOverlay(BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_SEGMENTATION); bmvvc->setSecondaryOverlay(BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_NONE); bmvvc->setUnderlay(BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_ANATOMY); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); WuQDialog::show(); // use this otherwise initial page gets shown segmentationTime = algorithmTimer.elapsed() * 0.001; return true; } // // If there is a fiducial surface, show it in the main window // BrainModelSurface* fidbms = theMainWindow->getBrainSet()->getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_FIDUCIAL); if (fidbms != NULL) { theMainWindow->displayBrainModelInMainWindow(fidbms); } // // Notify GUI that volumes have changed // GuiFilesModified fm; fm.setStatusForAll(true); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); QApplication::beep(); return false; } /** * Update the dialog. */ void GuiVolumeSureFitSegmentationDialog::updateDialog() { volumeAnatomySelectionControl->updateControl(); volumeSegmentationSelectionControl->updateControl(); const VolumeFile* vfa = volumeAnatomySelectionControl->getSelectedVolumeFile(); const VolumeFile* vfs = volumeSegmentationSelectionControl->getSelectedVolumeFile(); if ((vfa == NULL) && (vfs == NULL)) { // // clear entries on first page and close dialog // WuQDialog::close(); } } caret-5.6.4~dfsg.1.orig/caret/GuiVolumeSelectionDialog.h0000664000175000017500000000546011572067322022737 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "WuQDialog.h" #include "GuiVolumeSelectionControl.h" /// dialog for selecting a volume file class GuiVolumeSelectionDialog : public WuQDialog { public: /// Constructor GuiVolumeSelectionDialog(QWidget* parent, const bool showAnatomyVolumes, const bool showFunctionalVolumes, const bool showPaintVolumes, const bool showProbAtlasVolumes, const bool showRgbPaintVolumes, const bool showSegmentationVolumes, const bool showVectorVolumes, const GuiVolumeSelectionControl::LABEL_MODE labelModeIn, const char* name, const bool enableNewVolumeSelectionIn, const bool enableNameTextEntryIn, const bool enableDescriptiveLabelTextEntryIn); /// Destructor ~GuiVolumeSelectionDialog(); /// get the selected volume type VolumeFile::VOLUME_TYPE getSelectedVolumeType() const; /// get the selected volume file (if null NEW might be selected) VolumeFile* getSelectedVolumeFile(); /// get the selected volume file (const method) const VolumeFile* getSelectedVolumeFile() const; /// get "New Volume" selected bool getNewVolumeSelected() const; /// set the selected volume file void setSelectedVolumeFile(const VolumeFile* vf); /// get the name for the selected file QString getSelectedVolumeFileName() const; /// get the descriptive label for the selected file QString getSelectedVolumeDescriptiveLabel() const; protected: /// the volume selection control GuiVolumeSelectionControl* volumeSelectionControl; }; caret-5.6.4~dfsg.1.orig/caret/GuiVolumeSelectionDialog.cxx0000664000175000017500000001176511572067322023317 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "GuiVolumeSelectionDialog.h" #include "QtUtilities.h" /** * Constructor. */ GuiVolumeSelectionDialog::GuiVolumeSelectionDialog(QWidget* parent, const bool showAnatomyVolumes, const bool showFunctionalVolumes, const bool showPaintVolumes, const bool showProbAtlasVolumes, const bool showRgbPaintVolumes, const bool showSegmentationVolumes, const bool showVectorVolumes, const GuiVolumeSelectionControl::LABEL_MODE labelModeIn, const char* name, const bool enableNewVolumeSelectionIn, const bool enableNameTextEntryIn, const bool enableDescriptiveLabelTextEntryIn) : WuQDialog(parent) { setModal(true); setWindowTitle("Volume Selection"); // // Layout for dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(3); dialogLayout->setSpacing(3); // // Volume selection control // volumeSelectionControl = new GuiVolumeSelectionControl( this, showAnatomyVolumes, showFunctionalVolumes, showPaintVolumes, showProbAtlasVolumes, showRgbPaintVolumes, showSegmentationVolumes, showVectorVolumes, labelModeIn, name, enableNewVolumeSelectionIn, enableNameTextEntryIn, enableDescriptiveLabelTextEntryIn); dialogLayout->addWidget(volumeSelectionControl); // // Layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout;; buttonsLayout->setSpacing(3); dialogLayout->addLayout(buttonsLayout); // // OK button // QPushButton* okButton = new QPushButton("OK"); buttonsLayout->addWidget(okButton); okButton->setAutoDefault(false); QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); // // Cancel button // QPushButton* cancelButton = new QPushButton("Cancel"); buttonsLayout->addWidget(cancelButton); cancelButton->setAutoDefault(false); QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); QtUtilities::makeButtonsSameSize(okButton, cancelButton); } /** * Destructor. */ GuiVolumeSelectionDialog::~GuiVolumeSelectionDialog() { } /** * get the selected volume type. */ VolumeFile::VOLUME_TYPE GuiVolumeSelectionDialog::getSelectedVolumeType() const { return volumeSelectionControl->getSelectedVolumeType(); } /** * get the selected volume file (if null NEW might be selected). */ VolumeFile* GuiVolumeSelectionDialog::getSelectedVolumeFile() { return volumeSelectionControl->getSelectedVolumeFile(); } /** * get the selected volume file (const method). */ const VolumeFile* GuiVolumeSelectionDialog::getSelectedVolumeFile() const { return volumeSelectionControl->getSelectedVolumeFile(); } /** * get "New Volume" selected. */ bool GuiVolumeSelectionDialog::getNewVolumeSelected() const { return volumeSelectionControl->getNewVolumeSelected(); } /** * set the selected volume file. */ void GuiVolumeSelectionDialog::setSelectedVolumeFile(const VolumeFile* vf) { volumeSelectionControl->setSelectedVolumeFile(vf); } /** * get the name for the selected file. */ QString GuiVolumeSelectionDialog::getSelectedVolumeFileName() const { return volumeSelectionControl->getSelectedVolumeFileName(); } /** * get the descriptive label for the selected file. */ QString GuiVolumeSelectionDialog::getSelectedVolumeDescriptiveLabel() const { return volumeSelectionControl->getSelectedVolumeDescriptiveLabel(); } caret-5.6.4~dfsg.1.orig/caret/GuiVolumeSelectionControl.h0000664000175000017500000001075411572067322023162 0ustar michaelmichael #ifndef __GUI_VOLUME_SELECTION_CONTROL_H__ #define __GUI_VOLUME_SELECTION_CONTROL_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "VolumeFile.h" class QComboBox; class QLabel; class QLineEdit; /// class for selecting a volume loaded in memory class GuiVolumeSelectionControl : public QWidget { Q_OBJECT public: /// type of label for display enum LABEL_MODE { LABEL_MODE_FILE_NAME, LABEL_MODE_FILE_LABEL, LABEL_MODE_FILE_LABEL_AND_NAME }; /// Constructor GuiVolumeSelectionControl(QWidget* parent, const bool showAnatomyVolumes, const bool showFunctionalVolumes, const bool showPaintVolumes, const bool showProbAtlasVolumes, const bool showRgbPaintVolumes, const bool showSegmentationVolumes, const bool showVectorVolumes, const LABEL_MODE labelModeIn, const char* name, const bool enableNewVolumeSelectionIn, const bool enableNameTextEntryIn, const bool enableDescriptiveLabelTextEntryIn); /// Destructor ~GuiVolumeSelectionControl(); /// get the selected volume type VolumeFile::VOLUME_TYPE getSelectedVolumeType() const; /// set the selected volume type void setSelectedVolumeType(const VolumeFile::VOLUME_TYPE vt); /// get the selected volume file (if null NEW might be selected) VolumeFile* getSelectedVolumeFile(); /// get the selected volume file (const method) const VolumeFile* getSelectedVolumeFile() const; /// get "New Volume" selected bool getNewVolumeSelected() const; /// set the selected volume file void setSelectedVolumeFile(const VolumeFile* vf); /// get the name for the selected file QString getSelectedVolumeFileName() const; /// get the descriptive label for the selected file QString getSelectedVolumeDescriptiveLabel() const; /// show only the volume type void showOnlyVolumeType(const bool b); signals: /// emitted when type or file is selected void signalSelectionChanged(); public slots: /// Update the control void updateControl(); /// Update the volume name line edit void updateNameLineEdit(); protected: /// volume type label QLabel* volumeTypeLabel; /// volume type combo box QComboBox* volumeTypeComboBox; /// type of volumes to display std::vector volumeTypesToDisplay; /// the file label QLabel* volumeFileLabel; /// volume file combo box QComboBox* volumeFileComboBox; /// volume files in the combo box std::vector volumeFiles; /// index of "new" volume int newVolumeIndex; /// enable selection of "new" volume bool enableNewVolumeSelection; /// name label QLabel* nameLabel; /// name entry line edit QLineEdit* nameLineEdit; /// the descriptive label QLabel* descriptiveLabel; /// descriptive label line edit QLineEdit* descriptiveLabelLineEdit; /// type of label to display in control LABEL_MODE labelMode; }; #endif // __GUI_VOLUME_SELECTION_CONTROL_H__ caret-5.6.4~dfsg.1.orig/caret/GuiVolumeSelectionControl.cxx0000664000175000017500000003543111572067322023534 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include "BrainSet.h" #include "FileUtilities.h" #include "GuiMainWindow.h" #include "GuiVolumeSelectionControl.h" #include "global_variables.h" /** * Constructor. Creates a grid widget with labels and combo boxes for selecting * a volume type and a specific volume of the selected volume type. If only one * type of volume is enabled, the type selection is hidden. */ GuiVolumeSelectionControl::GuiVolumeSelectionControl(QWidget* parent, const bool showAnatomyVolumes, const bool showFunctionalVolumes, const bool showPaintVolumes, const bool showProbAtlasVolumes, const bool showRgbPaintVolumes, const bool showSegmentationVolumes, const bool showVectorVolumes, const LABEL_MODE labelModeIn, const char* name, const bool enableNewVolumeSelectionIn, const bool enableNameTextEntryIn, const bool enableDescriptiveLabelTextEntryIn) : QWidget(parent) { setObjectName(name); enableNewVolumeSelection = enableNewVolumeSelectionIn; labelMode = labelModeIn; // // Load the volume type combo box // volumeTypeLabel = new QLabel("Volume Type "); volumeTypeLabel->setFixedSize(volumeTypeLabel->sizeHint()); volumeTypeComboBox = new QComboBox; QObject::connect(volumeTypeComboBox, SIGNAL(activated(int)), this, SLOT(updateControl())); QString singleVolumeLabel; if (showAnatomyVolumes) { volumeTypesToDisplay.push_back(VolumeFile::VOLUME_TYPE_ANATOMY); volumeTypeComboBox->addItem("Anatomy"); singleVolumeLabel = "Anatomy"; } if (showFunctionalVolumes) { volumeTypesToDisplay.push_back(VolumeFile::VOLUME_TYPE_FUNCTIONAL); volumeTypeComboBox->addItem("Functional"); singleVolumeLabel = "Functional"; } if (showPaintVolumes) { volumeTypesToDisplay.push_back(VolumeFile::VOLUME_TYPE_PAINT); volumeTypeComboBox->addItem("Paint"); singleVolumeLabel = "Paint"; } if (showProbAtlasVolumes) { volumeTypesToDisplay.push_back(VolumeFile::VOLUME_TYPE_PROB_ATLAS); volumeTypeComboBox->addItem("Prob Atlas"); singleVolumeLabel = "Prob Atlas"; } if (showRgbPaintVolumes) { volumeTypesToDisplay.push_back(VolumeFile::VOLUME_TYPE_RGB); volumeTypeComboBox->addItem("RGB Paint"); singleVolumeLabel = "RGB Paint"; } if (showSegmentationVolumes) { volumeTypesToDisplay.push_back(VolumeFile::VOLUME_TYPE_SEGMENTATION); volumeTypeComboBox->addItem("Segmentation"); singleVolumeLabel = "Segmentation"; } if (showVectorVolumes) { volumeTypesToDisplay.push_back(VolumeFile::VOLUME_TYPE_VECTOR); volumeTypeComboBox->addItem("Vector"); singleVolumeLabel = "Vector"; } // // If only one type of volume is displayed, hide type selection // if (volumeTypeComboBox->count() == 1) { volumeTypeLabel->hide(); volumeTypeComboBox->hide(); } // // Create the volume file selection combo box // volumeFileLabel = NULL; if (volumeTypeComboBox->count() == 1) { volumeFileLabel = new QLabel(singleVolumeLabel); } else { volumeFileLabel = new QLabel("Volume File "); } volumeFileLabel->setFixedSize(volumeFileLabel->sizeHint()); volumeFileComboBox = new QComboBox; QObject::connect(volumeFileComboBox, SIGNAL(activated(int)), this, SLOT(updateNameLineEdit())); // // layout for widget // QGridLayout* gridLayout = new QGridLayout(this); gridLayout->setSpacing(5); gridLayout->addWidget(volumeTypeLabel, 0, 0); gridLayout->addWidget(volumeTypeComboBox, 0, 1); gridLayout->addWidget(volumeFileLabel, 1, 0); gridLayout->addWidget(volumeFileComboBox, 1, 1); // // Should the volume name text entry be enabled // nameLabel = NULL; nameLineEdit = NULL; if (enableNameTextEntryIn) { const int rowNum = gridLayout->rowCount(); nameLabel = new QLabel("Volume Name"); gridLayout->addWidget(nameLabel, rowNum, 0); nameLineEdit = new QLineEdit; gridLayout->addWidget(nameLineEdit, rowNum, 1); } // // Should the volume descriptive label text entry be enabled // descriptiveLabel = NULL; descriptiveLabelLineEdit = NULL; if (enableDescriptiveLabelTextEntryIn) { descriptiveLabel = new QLabel("Volume Label"); const int rowNum = gridLayout->rowCount(); gridLayout->addWidget(descriptiveLabel, rowNum, 0); descriptiveLabelLineEdit = new QLineEdit; gridLayout->addWidget(descriptiveLabelLineEdit, rowNum, 1); } // // default the new volume index // newVolumeIndex = -1; // // Load the volume files // updateControl(); QObject::connect(volumeTypeComboBox, SIGNAL(activated(int)), this, SIGNAL(signalSelectionChanged())); QObject::connect(volumeFileComboBox, SIGNAL(activated(int)), this, SIGNAL(signalSelectionChanged())); } /** * Destructor. */ GuiVolumeSelectionControl::~GuiVolumeSelectionControl() { } /** * show only the volume type. */ void GuiVolumeSelectionControl::showOnlyVolumeType(const bool hideIt) { volumeFileLabel->setHidden(hideIt); volumeFileComboBox->setHidden(hideIt); if (nameLabel != NULL) { nameLabel->setHidden(hideIt); } if (nameLineEdit != NULL) { nameLineEdit->setHidden(hideIt); } if (descriptiveLabel != NULL) { descriptiveLabel->setHidden(hideIt); } if (descriptiveLabelLineEdit != NULL) { descriptiveLabelLineEdit->setHidden(hideIt); } } /** * Update the control. */ void GuiVolumeSelectionControl::updateControl() { VolumeFile* currentVolume = NULL; // // Get volume type currently selected // const VolumeFile::VOLUME_TYPE vt = volumeTypesToDisplay[volumeTypeComboBox->currentIndex()]; // // If there were volume files previously in this control // if (volumeFileComboBox->count() > 0) { // // Get the previously selected volume file // const int item = volumeFileComboBox->currentIndex(); if ((item >= 0) && (item < static_cast(volumeFiles.size()))) { currentVolume = volumeFiles[item]; } } // // clear the volume file selection // volumeFiles.clear(); volumeFileComboBox->clear(); // // Get volumes for selected type // BrainSet* brainSet = theMainWindow->getBrainSet(); BrainModelVolume* bmv = brainSet->getBrainModelVolume(); VolumeFile* selVolume = NULL; switch (vt) { case VolumeFile::VOLUME_TYPE_ANATOMY: brainSet->getVolumeAnatomyFiles(volumeFiles); if (bmv != NULL) { selVolume = bmv->getSelectedVolumeAnatomyFile(); } break; case VolumeFile::VOLUME_TYPE_FUNCTIONAL: brainSet->getVolumeFunctionalFiles(volumeFiles); if (bmv != NULL) { selVolume = bmv->getSelectedVolumeFunctionalViewFile(); } break; case VolumeFile::VOLUME_TYPE_PAINT: brainSet->getVolumePaintFiles(volumeFiles); if (bmv != NULL) { selVolume = bmv->getSelectedVolumePaintFile(); } break; case VolumeFile::VOLUME_TYPE_PROB_ATLAS: brainSet->getVolumeProbAtlasFiles(volumeFiles); break; case VolumeFile::VOLUME_TYPE_RGB: brainSet->getVolumeRgbFiles(volumeFiles); if (bmv != NULL) { selVolume = bmv->getSelectedVolumeRgbFile(); } break; case VolumeFile::VOLUME_TYPE_ROI: break; case VolumeFile::VOLUME_TYPE_SEGMENTATION: brainSet->getVolumeSegmentationFiles(volumeFiles); if (bmv != NULL) { selVolume = bmv->getSelectedVolumeSegmentationFile(); } break; case VolumeFile::VOLUME_TYPE_VECTOR: brainSet->getVolumeVectorFiles(volumeFiles); if (bmv != NULL) { selVolume = bmv->getSelectedVolumeVectorFile(); } case VolumeFile::VOLUME_TYPE_UNKNOWN: break; } // // Override current volume with the selected volume // currentVolume = selVolume; // // Load the combo box // int defaultItem = -1; for (unsigned int i = 0; i < volumeFiles.size(); i++) { QString comboBoxLabel; switch (labelMode) { case LABEL_MODE_FILE_NAME: comboBoxLabel = FileUtilities::basename(volumeFiles[i]->getFileName()); break; case LABEL_MODE_FILE_LABEL: comboBoxLabel = volumeFiles[i]->getDescriptiveLabel(); break; case LABEL_MODE_FILE_LABEL_AND_NAME: { const QString name(FileUtilities::basename(volumeFiles[i]->getFileName())); const QString label(volumeFiles[i]->getDescriptiveLabel()); if ((name != label) && (label.isEmpty() == false)) { comboBoxLabel.append(label); comboBoxLabel.append(" ("); comboBoxLabel.append(name); comboBoxLabel.append(")"); } else { if (label.isEmpty() == false) { comboBoxLabel.append(label); } else { comboBoxLabel.append(name); } } } break; } volumeFileComboBox->addItem(comboBoxLabel); if (volumeFiles[i] == currentVolume) { defaultItem = i; } } // // If new volume enabled // newVolumeIndex = -1; if (enableNewVolumeSelection) { newVolumeIndex = volumeFileComboBox->count(); volumeFileComboBox->addItem("New Volume"); } // // If volume file was already in combo box // if (defaultItem >= 0) { volumeFileComboBox->setCurrentIndex(defaultItem); } updateNameLineEdit(); } /** * get the name for the selected file. */ QString GuiVolumeSelectionControl::getSelectedVolumeFileName() const { QString name("Invalid"); if (nameLineEdit != NULL) { name = nameLineEdit->text(); } else { const VolumeFile* vf = getSelectedVolumeFile(); if (vf != NULL) { name = vf->getFileName(); } } return name; } /** * get the descriptive label for the selected file. */ QString GuiVolumeSelectionControl::getSelectedVolumeDescriptiveLabel() const { QString label("Invalid"); if (descriptiveLabelLineEdit != NULL) { label = descriptiveLabelLineEdit->text(); } else { const VolumeFile* vf = getSelectedVolumeFile(); if (vf != NULL) { label = vf->getFileName(); label = vf->getDescriptiveLabel(); } } return label; } /** * Update the volume name line edit. */ void GuiVolumeSelectionControl::updateNameLineEdit() { if (nameLineEdit != NULL) { QString name("volume"); const VolumeFile* vf = getSelectedVolumeFile(); if (vf != NULL) { name = vf->getFileName(); } nameLineEdit->setText(name); } if (descriptiveLabelLineEdit != NULL) { QString name("label"); const VolumeFile* vf = getSelectedVolumeFile(); if (vf != NULL) { name = vf->getDescriptiveLabel(); } descriptiveLabelLineEdit->setText(name); } } /** * get the selected volume type. */ VolumeFile::VOLUME_TYPE GuiVolumeSelectionControl::getSelectedVolumeType() const { VolumeFile::VOLUME_TYPE vt = VolumeFile::VOLUME_TYPE_UNKNOWN; const int item = volumeTypeComboBox->currentIndex(); if ((item >= 0) && (item < static_cast(volumeTypesToDisplay.size()))) { vt = volumeTypesToDisplay[item]; } return vt; } /** * set the selected volume type. */ void GuiVolumeSelectionControl::setSelectedVolumeType(const VolumeFile::VOLUME_TYPE vt) { for (unsigned int i = 0; i < volumeTypesToDisplay.size(); i++) { if (vt == volumeTypesToDisplay[i]) { volumeTypeComboBox->blockSignals(true); volumeTypeComboBox->setCurrentIndex(i); volumeTypeComboBox->blockSignals(false); updateControl(); } } } /** * get the selected volume file. */ VolumeFile* GuiVolumeSelectionControl::getSelectedVolumeFile() { VolumeFile * vf = NULL; const int item = volumeFileComboBox->currentIndex(); if ((item >= 0) && (item < static_cast(volumeFiles.size()))) { vf = volumeFiles[item]; } return vf; } /** * get the selected volume file (const method). */ const VolumeFile* GuiVolumeSelectionControl::getSelectedVolumeFile() const { VolumeFile * vf = NULL; const int item = volumeFileComboBox->currentIndex(); if ((item >= 0) && (item < static_cast(volumeFiles.size()))) { vf = volumeFiles[item]; } return vf; } /** * get "New Volume" selected. */ bool GuiVolumeSelectionControl::getNewVolumeSelected() const { const int item = volumeFileComboBox->currentIndex(); if (item >= 0) { if (item == newVolumeIndex) { return true; } } return false; } /** * set the selected volume file. */ void GuiVolumeSelectionControl::setSelectedVolumeFile(const VolumeFile* vf) { for (unsigned int i = 0; i < volumeFiles.size(); i++) { if (volumeFiles[i] == vf) { volumeFileComboBox->setCurrentIndex(i); updateNameLineEdit(); break; } } } caret-5.6.4~dfsg.1.orig/caret/GuiVolumeSegmentationEditorDialog.h0000664000175000017500000001150111572067322024607 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_VOLUME_SEGMENTATION_EDITOR_DIALOG_H__ #define __GUI_VOLUME_SEGMENTATION_EDITOR_DIALOG_H__ #include #include #include "WuQDialog.h" #include "VolumeFile.h" #include "VolumeModification.h" class QComboBox; class QGroupBox; class QTextBrowser; class GuiVolumeSelectionControl; /// class dialog that allows editing of a segmentation volume class GuiVolumeSegmentationEditorDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiVolumeSegmentationEditorDialog(QWidget* parent); /// Destructor ~GuiVolumeSegmentationEditorDialog(); /// called when a voxel is selected for editing in the main window void processVoxel(const int i, const int j, const int k, const VolumeFile::VOLUME_AXIS pickAxis); /// called when dialog is popped up virtual void show(); /// update the dialog void updateDialog(); private slots: /// called when dialog is closed virtual void close(); /// called when edit mode combo box selection made void slotModeComboBox(int item); /// called when the undo button is pressed void slotUndoButton(); /// called when apply button is pressed void slotApplyButton(); private: /// the edit mode enum EDIT_MODE { /// copy subvolume edit mode EDIT_MODE_COPY_SUBVOLUME, /// dilate edit mode EDIT_MODE_DILATE, /// erode edit mode EDIT_MODE_ERODE, /// flood fill 2D edit mode EDIT_MODE_FLOOD_FILL_2D, /// flood fill 3D edit mode EDIT_MODE_FLOOD_FILL_3D, /// remove connected 2D edit mode EDIT_MODE_REMOVE_CONNECTED_2D, /// remove connected 3D edit mode EDIT_MODE_REMOVE_CONNECTED_3D, /// retain all voxels connected to the selected voxel edit mode EDIT_MODE_RETAIN_CONNECTED_3D, /// turn voxels on edit mode EDIT_MODE_TURN_VOXELS_ON, /// turn voxels off edit mode EDIT_MODE_TURN_VOXELS_OFF }; /// creates the toggle voxel section QWidget* createToggleVoxelsSection(); /// create the other volume section QWidget* createOtherVolumeSection(); /// clear the undo stack void clearUndoStack(); /// enable the undo button void enableUndoButton(); /// Set the help information. void loadHelpInformation(const QString& info); /// get the memory size of the undo container int getUndoContainerMemorySize() const; /// voxel region size enum TOGGLE_VOXELS_SIZE { TOGGLE_VOXELS_SIZE_1_BY_1, TOGGLE_VOXELS_SIZE_3_BY_3, TOGGLE_VOXELS_SIZE_5_BY_5, TOGGLE_VOXELS_SIZE_7_BY_7, TOGGLE_VOXELS_SIZE_9_BY_9, TOGGLE_VOXELS_SIZE_11_BY_11, TOGGLE_VOXELS_SIZE_ALL }; /// the current editing mode EDIT_MODE editMode; /// mode combo box QComboBox* modeComboBox; /// toggle voxels widget QWidget* toggleVoxelsWidget; /// box for horizontal voxel size QGroupBox* currentSliceGroupBox; /// box for three dimensional info QGroupBox* threeDimGroupBox; /// box for other volume QGroupBox* otherVolumeVBox; /// combo box for three dimensional operations QComboBox* threeDimSizeComboBox; /// toggle voxels size combo box QComboBox* toggleVoxelsSizeComboBox; /// the undo button QPushButton* undoButton; /// container for storing voxel changes std::list undoContainer; /// text browser for help QTextBrowser* helpBrowser; /// other volume selection box GuiVolumeSelectionControl* otherVolumeComboBox; }; #endif // __GUI_VOLUME_SEGMENTATION_EDITOR_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiVolumeSegmentationEditorDialog.cxx0000664000175000017500000007153711572067322025201 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include "BrainModelVolume.h" #include "BrainModelVolumeVoxelColoring.h" #include "BrainSet.h" #include "GuiBrainModelOpenGL.h" #include "GuiMainWindow.h" #include "GuiVolumeSegmentationEditorDialog.h" #include "GuiVolumeSelectionControl.h" #include "QtUtilities.h" #include "global_variables.h" /** * Constructor. */ GuiVolumeSegmentationEditorDialog::GuiVolumeSegmentationEditorDialog(QWidget* parent) : WuQDialog(parent) { editMode = EDIT_MODE_TURN_VOXELS_ON; setWindowTitle("Segmentation Volume Editor"); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // Add to the mode combo box // modeComboBox = new QComboBox; QObject::connect(modeComboBox, SIGNAL(activated(int)), this, SLOT(slotModeComboBox(int))); modeComboBox->insertItem(EDIT_MODE_COPY_SUBVOLUME, "Copy Sub-Volume"); modeComboBox->insertItem(EDIT_MODE_DILATE, "Dilate"); modeComboBox->insertItem(EDIT_MODE_ERODE, "Erode"); modeComboBox->insertItem(EDIT_MODE_FLOOD_FILL_2D, "Flood Fill 2D"); modeComboBox->insertItem(EDIT_MODE_FLOOD_FILL_3D, "Flood Fill 3D"); modeComboBox->insertItem(EDIT_MODE_REMOVE_CONNECTED_2D, "Remove Connected Voxels 2D"); modeComboBox->insertItem(EDIT_MODE_REMOVE_CONNECTED_3D, "Remove Connected Voxels 3D"); modeComboBox->insertItem(EDIT_MODE_RETAIN_CONNECTED_3D, "Retain Connected Voxels 3D"); modeComboBox->insertItem(EDIT_MODE_TURN_VOXELS_ON, "Turn Voxels On"); modeComboBox->insertItem(EDIT_MODE_TURN_VOXELS_OFF, "Turn Voxels Off"); // // Horizontal layout for mode label and combo box // QGroupBox* modeGroupBox = new QGroupBox("Editing Mode"); dialogLayout->addWidget(modeGroupBox); QVBoxLayout* modeGroupLayout = new QVBoxLayout(modeGroupBox); modeGroupLayout->addWidget(modeComboBox); modeGroupLayout->addStretch(); // // Mode options widget stack // QGroupBox* optionsGroupBox = new QGroupBox("Editing Control"); dialogLayout->addWidget(optionsGroupBox); QVBoxLayout* optionsGroupLayout = new QVBoxLayout(optionsGroupBox); // // Create the toggle voxels section // optionsGroupLayout->addWidget(createToggleVoxelsSection()); // // Create the other volume section dialogLayout->addWidget(createOtherVolumeSection()); // // Text Browser for help // helpBrowser = new QTextBrowser; //QT4 CONVERSION helpBrowser->setBackgroundMode(PaletteBackground); helpBrowser->setReadOnly(true); QGroupBox* helpGroup = new QGroupBox("Information"); dialogLayout->addWidget(helpGroup); QHBoxLayout* helpLayout = new QHBoxLayout(helpGroup); helpLayout->addWidget(helpBrowser); // // Limit height of help group // const int maxHeight = 150; int height = helpGroup->sizeHint().height(); if (height > maxHeight) { height = maxHeight; } helpGroup->setMaximumHeight(maxHeight); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); dialogLayout->addLayout(buttonsLayout); // // Apply button // QPushButton* applyButton = new QPushButton("Apply"); buttonsLayout->addWidget(applyButton); applyButton->setAutoDefault(false); QObject::connect(applyButton, SIGNAL(clicked()), this, SLOT(slotApplyButton())); // // // Undo button // undoButton = new QPushButton("Undo"); buttonsLayout->addWidget(undoButton); undoButton->setAutoDefault(false); QObject::connect(undoButton, SIGNAL(clicked()), this, SLOT(slotUndoButton())); // // Close button // QPushButton* closeButton = new QPushButton("Close"); buttonsLayout->addWidget(closeButton); closeButton->setAutoDefault(false); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); // // Make buttons same size // QtUtilities::makeButtonsSameSize(applyButton, undoButton, closeButton); // // Initialize dialog // modeComboBox->setCurrentIndex(editMode); slotModeComboBox(editMode); clearUndoStack(); // // Update the dialog // updateDialog(); } /** * Destructor. */ GuiVolumeSegmentationEditorDialog::~GuiVolumeSegmentationEditorDialog() { } /** * update the dialog. */ void GuiVolumeSegmentationEditorDialog::updateDialog() { otherVolumeComboBox->updateControl(); } /** * called when apply button is pressed. */ void GuiVolumeSegmentationEditorDialog::slotApplyButton() { theMainWindow->getBrainModelOpenGL()->setMouseMode( GuiBrainModelOpenGL::MOUSE_MODE_VOLUME_SEGMENTATION_EDIT); } /** * Set the help information. */ void GuiVolumeSegmentationEditorDialog::loadHelpInformation(const QString& info) { helpBrowser->setHtml(info); } /** * Create the toggle voxels widget. */ QWidget* GuiVolumeSegmentationEditorDialog::createToggleVoxelsSection() { // // Voxel size combo box and label // QLabel* brushSizeLabel = new QLabel("Brush Size"); toggleVoxelsSizeComboBox = new QComboBox; toggleVoxelsSizeComboBox->insertItem(TOGGLE_VOXELS_SIZE_1_BY_1, "1 x 1"); toggleVoxelsSizeComboBox->insertItem(TOGGLE_VOXELS_SIZE_3_BY_3, "3 x 3"); toggleVoxelsSizeComboBox->insertItem(TOGGLE_VOXELS_SIZE_5_BY_5, "5 x 5"); toggleVoxelsSizeComboBox->insertItem(TOGGLE_VOXELS_SIZE_7_BY_7, "7 x 7"); toggleVoxelsSizeComboBox->insertItem(TOGGLE_VOXELS_SIZE_9_BY_9, "9 x 9"); toggleVoxelsSizeComboBox->insertItem(TOGGLE_VOXELS_SIZE_11_BY_11, "11 x 11"); toggleVoxelsSizeComboBox->insertItem(TOGGLE_VOXELS_SIZE_ALL, "All Voxels in Slice"); toggleVoxelsSizeComboBox->setCurrentIndex(TOGGLE_VOXELS_SIZE_1_BY_1); currentSliceGroupBox = new QGroupBox("Current Slice"); QHBoxLayout* currentSliceGroupLayout = new QHBoxLayout(currentSliceGroupBox); currentSliceGroupLayout->addWidget(brushSizeLabel); currentSliceGroupLayout->addWidget(toggleVoxelsSizeComboBox); // // Three D // QLabel* brushThicknessLabel = new QLabel("Brush Thickness (3D)"); threeDimSizeComboBox = new QComboBox; threeDimSizeComboBox->insertItem(TOGGLE_VOXELS_SIZE_1_BY_1, "Current Slice Only"); threeDimSizeComboBox->insertItem(TOGGLE_VOXELS_SIZE_3_BY_3, "Current Slice +/- 1"); threeDimSizeComboBox->insertItem(TOGGLE_VOXELS_SIZE_5_BY_5, "Current Slice +/- 2"); threeDimSizeComboBox->insertItem(TOGGLE_VOXELS_SIZE_7_BY_7, "Current Slice +/- 3"); threeDimSizeComboBox->insertItem(TOGGLE_VOXELS_SIZE_9_BY_9, "Current Slice +/- 4"); threeDimSizeComboBox->insertItem(TOGGLE_VOXELS_SIZE_11_BY_11, "Current Slice +/- 5"); threeDimSizeComboBox->insertItem(TOGGLE_VOXELS_SIZE_ALL, "All Slices"); threeDimSizeComboBox->setCurrentIndex(TOGGLE_VOXELS_SIZE_1_BY_1); threeDimGroupBox = new QGroupBox("Three Dimensional"); QHBoxLayout* threeDimGroupLayout = new QHBoxLayout(threeDimGroupBox); threeDimGroupLayout->addWidget(brushThicknessLabel); threeDimGroupLayout->addWidget(threeDimSizeComboBox); QWidget* toggleVoxelsWidget = new QWidget; QVBoxLayout* toggleVoxelsLayout = new QVBoxLayout(toggleVoxelsWidget); toggleVoxelsLayout->addWidget(currentSliceGroupBox); toggleVoxelsLayout->addWidget(threeDimGroupBox); toggleVoxelsLayout->setAlignment(currentSliceGroupBox, Qt::AlignLeft); toggleVoxelsLayout->setAlignment(threeDimGroupBox, Qt::AlignLeft); return toggleVoxelsWidget; } /** * create the other volume section. */ QWidget* GuiVolumeSegmentationEditorDialog::createOtherVolumeSection() { otherVolumeComboBox = new GuiVolumeSelectionControl(0, false, false, false, false, false, true, false, GuiVolumeSelectionControl::LABEL_MODE_FILE_NAME, "otherVolumeComboBox", false, false, false); otherVolumeVBox = new QGroupBox("Other Volume"); QVBoxLayout* otherVolumeLayout = new QVBoxLayout(otherVolumeVBox); otherVolumeLayout->addWidget(otherVolumeComboBox); return otherVolumeVBox; } /** * called when dialog is closed. */ void GuiVolumeSegmentationEditorDialog::close() { clearUndoStack(); // // If in segmentation edit mode, switch to view mode // GuiBrainModelOpenGL* openGL = theMainWindow->getBrainModelOpenGL(); if (openGL->getMouseMode() == GuiBrainModelOpenGL::MOUSE_MODE_VOLUME_SEGMENTATION_EDIT) { openGL->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_VIEW); } QDialog::close(); } /** * called when dialog is popped up. */ void GuiVolumeSegmentationEditorDialog::show() { clearUndoStack(); WuQDialog::show(); theMainWindow->getBrainModelOpenGL()->setMouseMode( GuiBrainModelOpenGL::MOUSE_MODE_VOLUME_SEGMENTATION_EDIT); } /** * Called when a voxel is selected for editing in the main window. */ void GuiVolumeSegmentationEditorDialog::processVoxel(const int ii, const int jj, const int kk, const VolumeFile::VOLUME_AXIS pickAxis) { unsigned char rgbsON[4], rgbsOFF[4]; BrainModelVolumeVoxelColoring::getSegmentationVoxelOnColor(rgbsON); BrainModelVolumeVoxelColoring::getSegmentationVoxelOffColor(rgbsOFF); const float voxelValueON = 255.0; const float voxelValueOFF = 0.0; BrainModelVolume* bmv = theMainWindow->getBrainModelVolume(); if (bmv == NULL) { close(); return; } switch (editMode) { case EDIT_MODE_COPY_SUBVOLUME: QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); break; case EDIT_MODE_DILATE: break; case EDIT_MODE_ERODE: break; case EDIT_MODE_FLOOD_FILL_2D: break; case EDIT_MODE_FLOOD_FILL_3D: QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); break; case EDIT_MODE_REMOVE_CONNECTED_2D: break; case EDIT_MODE_REMOVE_CONNECTED_3D: QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); break; case EDIT_MODE_RETAIN_CONNECTED_3D: QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); break; case EDIT_MODE_TURN_VOXELS_ON: break; case EDIT_MODE_TURN_VOXELS_OFF: break; } VolumeFile::VOLUME_AXIS axis = bmv->getSelectedAxis(0); switch (axis) { case VolumeFile::VOLUME_AXIS_X: break; case VolumeFile::VOLUME_AXIS_Y: break; case VolumeFile::VOLUME_AXIS_Z: break; case VolumeFile::VOLUME_AXIS_ALL: if ((pickAxis == VolumeFile::VOLUME_AXIS_X) || (pickAxis == VolumeFile::VOLUME_AXIS_Y) || (pickAxis == VolumeFile::VOLUME_AXIS_Z)) { axis = pickAxis; } else { return; } break; case VolumeFile::VOLUME_AXIS_OBLIQUE: case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", "Editing of oblique slices is not allowed."); return; case VolumeFile::VOLUME_AXIS_UNKNOWN: return; break; } VolumeFile* vf = bmv->getSelectedVolumeSegmentationFile(); if (vf != NULL) { // // Voxel value and its color // float voxelValue = 0.0; unsigned char rgb[4] = { 0, 0, 0, 0 }; switch (editMode) { case EDIT_MODE_COPY_SUBVOLUME: break; case EDIT_MODE_DILATE: case EDIT_MODE_FLOOD_FILL_2D: case EDIT_MODE_FLOOD_FILL_3D: case EDIT_MODE_TURN_VOXELS_ON: voxelValue = voxelValueON; rgb[0] = rgbsON[0]; rgb[1] = rgbsON[1]; rgb[2] = rgbsON[2]; rgb[3] = rgbsON[3]; break; case EDIT_MODE_REMOVE_CONNECTED_2D: case EDIT_MODE_REMOVE_CONNECTED_3D: voxelValue = voxelValueOFF; rgb[0] = rgbsOFF[0]; rgb[1] = rgbsOFF[1]; rgb[2] = rgbsOFF[2]; rgb[3] = rgbsOFF[3]; break; case EDIT_MODE_RETAIN_CONNECTED_3D: break; case EDIT_MODE_TURN_VOXELS_OFF: case EDIT_MODE_ERODE: voxelValue = voxelValueOFF; rgb[0] = rgbsOFF[0]; rgb[1] = rgbsOFF[1]; rgb[2] = rgbsOFF[2]; rgb[3] = rgbsOFF[3]; break; } // // Set indice range for voxels that are to be processed // int mm = 0; switch (static_cast(toggleVoxelsSizeComboBox->currentIndex())) { case TOGGLE_VOXELS_SIZE_1_BY_1: mm = 0; break; case TOGGLE_VOXELS_SIZE_3_BY_3: mm = 1; break; case TOGGLE_VOXELS_SIZE_5_BY_5: mm = 2; break; case TOGGLE_VOXELS_SIZE_7_BY_7: mm = 3; break; case TOGGLE_VOXELS_SIZE_9_BY_9: mm = 4; break; case TOGGLE_VOXELS_SIZE_11_BY_11: mm = 5; break; case TOGGLE_VOXELS_SIZE_ALL: mm = 10000; break; } int ijkMin[3] = { ii - mm, jj - mm, kk - mm }; int ijkMax[3] = { ii + mm, jj + mm, kk + mm }; // // Process three dim aspect // int threeDim = 0; bool threeDimFlag = false; switch (static_cast(threeDimSizeComboBox->currentIndex())) { case TOGGLE_VOXELS_SIZE_1_BY_1: threeDim = 0; threeDimFlag = false; break; case TOGGLE_VOXELS_SIZE_3_BY_3: threeDim = 1; threeDimFlag = true; break; case TOGGLE_VOXELS_SIZE_5_BY_5: threeDim = 2; threeDimFlag = true; break; case TOGGLE_VOXELS_SIZE_7_BY_7: threeDim = 3; threeDimFlag = true; break; case TOGGLE_VOXELS_SIZE_9_BY_9: threeDim = 4; threeDimFlag = true; break; case TOGGLE_VOXELS_SIZE_11_BY_11: threeDim = 5; threeDimFlag = true; break; case TOGGLE_VOXELS_SIZE_ALL: threeDim = 1000000; threeDimFlag = true; break; } // // handle three dim "thickness" // switch (axis) { case VolumeFile::VOLUME_AXIS_X: ijkMin[0] = ii - threeDim; ijkMax[0] = ii + threeDim; break; case VolumeFile::VOLUME_AXIS_Y: ijkMin[1] = jj - threeDim; ijkMax[1] = jj + threeDim; break; case VolumeFile::VOLUME_AXIS_Z: ijkMin[2] = kk - threeDim; ijkMax[2] = kk + threeDim; break; case VolumeFile::VOLUME_AXIS_ALL: case VolumeFile::VOLUME_AXIS_OBLIQUE: case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } // // Some modes only need the starting voxel // bool singleVoxelOnly = false; switch (editMode) { case EDIT_MODE_COPY_SUBVOLUME: break; case EDIT_MODE_DILATE: break; case EDIT_MODE_ERODE: break; case EDIT_MODE_FLOOD_FILL_2D: singleVoxelOnly = true; break; case EDIT_MODE_FLOOD_FILL_3D: singleVoxelOnly = true; break; case EDIT_MODE_REMOVE_CONNECTED_2D: singleVoxelOnly = true; break; case EDIT_MODE_REMOVE_CONNECTED_3D: singleVoxelOnly = true; break; case EDIT_MODE_RETAIN_CONNECTED_3D: break; case EDIT_MODE_TURN_VOXELS_ON: break; case EDIT_MODE_TURN_VOXELS_OFF: break; } if (singleVoxelOnly) { ijkMin[0] = ii; ijkMax[0] = ii; ijkMin[1] = jj; ijkMax[1] = jj; ijkMin[2] = kk; ijkMax[2] = kk; } VolumeModification modifiedVoxels; // // Perform operation on the volume // switch (editMode) { case EDIT_MODE_COPY_SUBVOLUME: { const VolumeFile* otherVolume = otherVolumeComboBox->getSelectedVolumeFile(); if (otherVolume == NULL) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", "There is no \"Other Volume\" from which to copy voxels."); } else if (otherVolume == vf) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", "The \"Other Volume\" is the same as the volume being edited."); } try { const int extent[6] = { ijkMin[0], ijkMax[0], ijkMin[1], ijkMax[1], ijkMin[2], ijkMax[2] }; vf->copySubVolume(otherVolume, extent, rgbsOFF, rgbsON, &modifiedVoxels); } catch (FileException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); } } break; case EDIT_MODE_DILATE: vf->performSegmentationOperation(VolumeFile::SEGMENTATION_OPERATION_DILATE, axis, threeDimFlag, ijkMin, ijkMax, voxelValue, rgb, &modifiedVoxels); break; case EDIT_MODE_ERODE: vf->performSegmentationOperation(VolumeFile::SEGMENTATION_OPERATION_ERODE, axis, threeDimFlag, ijkMin, ijkMax, voxelValue, rgb, &modifiedVoxels); break; case EDIT_MODE_FLOOD_FILL_2D: threeDimFlag = false; vf->performSegmentationOperation(VolumeFile::SEGMENTATION_OPERATION_FLOOD_FILL_2D, axis, threeDimFlag, ijkMin, ijkMax, voxelValue, rgb, &modifiedVoxels); break; case EDIT_MODE_FLOOD_FILL_3D: vf->performSegmentationOperation(VolumeFile::SEGMENTATION_OPERATION_FLOOD_FILL_3D, axis, threeDimFlag, ijkMin, ijkMax, voxelValue, rgb, &modifiedVoxels); break; case EDIT_MODE_REMOVE_CONNECTED_2D: threeDimFlag = false; vf->performSegmentationOperation(VolumeFile::SEGMENTATION_OPERATION_REMOVE_CONNECTED_2D, axis, threeDimFlag, ijkMin, ijkMax, voxelValue, rgb, &modifiedVoxels); break; case EDIT_MODE_REMOVE_CONNECTED_3D: vf->performSegmentationOperation(VolumeFile::SEGMENTATION_OPERATION_REMOVE_CONNECTED_3D, axis, threeDimFlag, ijkMin, ijkMax, voxelValue, rgb, &modifiedVoxels); break; case EDIT_MODE_RETAIN_CONNECTED_3D: vf->floodFillWithVTK(ijkMin, 255, 255, 0, &modifiedVoxels); vf->setVoxelColoringInvalid(); break; case EDIT_MODE_TURN_VOXELS_ON: vf->performSegmentationOperation(VolumeFile::SEGMENTATION_OPERATION_TOGGLE_ON, axis, threeDimFlag, ijkMin, ijkMax, voxelValue, rgb, &modifiedVoxels); break; case EDIT_MODE_TURN_VOXELS_OFF: vf->performSegmentationOperation(VolumeFile::SEGMENTATION_OPERATION_TOGGLE_OFF, axis, threeDimFlag, ijkMin, ijkMax, voxelValue, rgb, &modifiedVoxels); break; } if (modifiedVoxels.getNumberOfVoxels() > 0) { undoContainer.push_front(modifiedVoxels); // // Limit the size of the undo container // const int maxSize = 1024 * 1024 * 10; // 10 meg while (getUndoContainerMemorySize() > maxSize) { if (undoContainer.size() <= 1) { break; } undoContainer.pop_back(); } } enableUndoButton(); GuiBrainModelOpenGL::updateAllGL(); } QApplication::restoreOverrideCursor(); } /** * Clear the undo stack */ void GuiVolumeSegmentationEditorDialog::clearUndoStack() { undoContainer.clear(); enableUndoButton(); } /** * Called when the undo button is pressed. */ void GuiVolumeSegmentationEditorDialog::slotUndoButton() { BrainModelVolume* bmv = theMainWindow->getBrainModelVolume(); if (bmv == NULL) { close(); return; } VolumeFile* vf = bmv->getSelectedVolumeSegmentationFile(); if (vf != NULL) { if (undoContainer.empty() == false) { VolumeModification volumeModification = undoContainer.front(); undoContainer.pop_front(); vf->undoModification(&volumeModification); getUndoContainerMemorySize(); } GuiBrainModelOpenGL::updateAllGL(); } enableUndoButton(); } /** * Enable the undo button. */ void GuiVolumeSegmentationEditorDialog::enableUndoButton() { undoButton->setEnabled(undoContainer.empty() == false); } /** * Called when an edit mode combo box selection is made. */ void GuiVolumeSegmentationEditorDialog::slotModeComboBox(int item) { editMode = static_cast(item); QString helpInfo; otherVolumeComboBox->setEnabled(false); bool enableVoxelSize = false; switch (editMode) { case EDIT_MODE_COPY_SUBVOLUME: otherVolumeComboBox->setEnabled(true); enableVoxelSize = true; helpInfo = "Copy Sub-Volume will copy of regions from the other segmentation " "volume into the currently selected segmentation volume. To use, set " "the \"other volume\" from which you want to copy voxels. Drag the mouse " "over voxels and the corresponding voxels from the \"other volume\" " "will be copied to the currently displayed volume."; break; case EDIT_MODE_DILATE: enableVoxelSize = true; helpInfo = "Dilate will add voxels onto the edge of a region."; break; case EDIT_MODE_ERODE: enableVoxelSize = true; helpInfo = "Erode will remove voxels from the edge of a region."; break; case EDIT_MODE_FLOOD_FILL_2D: enableVoxelSize = false; helpInfo = "Flood Fill will fill a hole in a region for the current slice."; break; case EDIT_MODE_FLOOD_FILL_3D: enableVoxelSize = false; helpInfo = "Flood Fill will fill a hole in a region for all voxels connected to the selected voxel."; break; case EDIT_MODE_REMOVE_CONNECTED_2D: enableVoxelSize = false; helpInfo = "Remove Connected Voxels will remove a connected set of voxels " "from the current slice only."; break; case EDIT_MODE_REMOVE_CONNECTED_3D: enableVoxelSize = false; helpInfo = "Remove Connected Voxels will remove a connected set of voxels."; break; case EDIT_MODE_RETAIN_CONNECTED_3D: enableVoxelSize = false; helpInfo = "Retain Connected Voxels 3D will turn off all voxels not " "connected to the selected voxels. After selecting this mode, " "press the Apply button. After doing so, click the mouse on a " "voxel in the part of the segmentation that is to remain. All " "voxels not connected to the selected voxel will be discarded."; break; case EDIT_MODE_TURN_VOXELS_ON: enableVoxelSize = true; helpInfo = "Toggle Voxels On will turn on voxels around the cursor."; break; case EDIT_MODE_TURN_VOXELS_OFF: enableVoxelSize = true; helpInfo = "Toggle Voxels Off will turn off voxels around the cursor."; break; } // // Set the help information // loadHelpInformation(helpInfo); currentSliceGroupBox->setEnabled(enableVoxelSize); threeDimGroupBox->setEnabled(enableVoxelSize); slotApplyButton(); } /** * get the size of the undo container. */ int GuiVolumeSegmentationEditorDialog::getUndoContainerMemorySize() const { int totalSize = 0; for (std::list::const_iterator iter = undoContainer.begin(); iter != undoContainer.end(); iter++) { totalSize += iter->getMemorySize(); } //std::cout << "UNDO container size: " << totalSize; return totalSize; } caret-5.6.4~dfsg.1.orig/caret/GuiVolumeResizingDialog.h0000664000175000017500000000553611572067322022610 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_VOLUME_RESIZING_DIALOG_H__ #define __GUI_VOLUME_RESIZING_DIALOG_H__ #include "WuQDialog.h" class QCheckBox; class QSpinBox; /// Dialog for resizing a volume class GuiVolumeResizingDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiVolumeResizingDialog(QWidget* parent); /// Destructor ~GuiVolumeResizingDialog(); /// shows the dialog (override of QDialog::show()) virtual void show(); /// update the dialog void updateDialog(const bool fileChangeUpdateFlag); public slots: /// Called when OK button pressed void slotApplyButton(); /// called when dialog is being closed virtual void close(); /// reset the cropping slices void slotResetPushButton(); private slots: /// called when x minimum spin box changed void slotXMinSpinBox(int value); /// called when x maximum spin box changed void slotXMaxSpinBox(int value); /// called when y minimum spin box changed void slotYMinSpinBox(int value); /// called when y maximum spin box changed void slotYMaxSpinBox(int value); /// called when z minimum spin box changed void slotZMinSpinBox(int value); /// called when z maximum spin box changed void slotZMaxSpinBox(int value); private: /// x minimum spin box QSpinBox* xMinSpinBox; /// x maximum spin box QSpinBox* xMaxSpinBox; /// x minimum spin box QSpinBox* yMinSpinBox; /// x maximum spin box QSpinBox* yMaxSpinBox; /// x minimum spin box QSpinBox* zMinSpinBox; /// x maximum spin box QSpinBox* zMaxSpinBox; /// dialog is being updated bool updatingDialog; /// use X/Y/Z Min for ParametersFile X/Y/Z min QCheckBox* useXyzMinForParametersCheckBox; }; #endif // __GUI_VOLUME_RESIZING_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiVolumeResizingDialog.cxx0000664000175000017500000003702311572067322023157 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include "BrainModelVolume.h" #include "BrainSet.h" #include "DisplaySettingsVolume.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "GuiToolBar.h" #include "GuiVolumeResizingDialog.h" #include "ParamsFile.h" #include "QtUtilities.h" #include "global_variables.h" /** * Constructor. */ GuiVolumeResizingDialog::GuiVolumeResizingDialog(QWidget* parent) : WuQDialog(parent) { DisplaySettingsVolume* dsv = theMainWindow->getBrainSet()->getDisplaySettingsVolume(); int slices[6]; slices[0] = 0; slices[1] = 0; slices[2] = 0; slices[3] = 0; slices[4] = 0; slices[5] = 0; dsv->setCroppingSlices(slices); dsv->setCroppingSlicesValid(false); updatingDialog = true; setWindowTitle("Resize Volume"); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // Group box for labels, sliders, and slider values // QGroupBox* boundsGroupBox = new QGroupBox("Bounds"); dialogLayout->addWidget(boundsGroupBox); QVBoxLayout* boundsGroupLayout = new QVBoxLayout(boundsGroupBox); // // Group box for labels, sliders, and slider values // QGridLayout* gridLayout = new QGridLayout; boundsGroupLayout->addLayout(gridLayout); const int minSlice = -100000; const int maxSlice = 100000; // // X Minimum slider // gridLayout->addWidget(new QLabel("X Min "), 0, 0); xMinSpinBox = new QSpinBox; xMinSpinBox->setMinimum(minSlice); xMinSpinBox->setMaximum(maxSlice); xMinSpinBox->setSingleStep(1); QObject::connect(xMinSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotXMinSpinBox(int))); gridLayout->addWidget(xMinSpinBox, 0, 1); // // X Maximum slider // gridLayout->addWidget(new QLabel("X Max "), 1, 0); xMaxSpinBox = new QSpinBox; xMaxSpinBox->setMinimum(minSlice); xMaxSpinBox->setMaximum(maxSlice); xMaxSpinBox->setSingleStep(1); QObject::connect(xMaxSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotXMaxSpinBox(int))); gridLayout->addWidget(xMaxSpinBox, 1, 1); // // Y Minimum slider // gridLayout->addWidget(new QLabel("Y Min "), 2, 0); yMinSpinBox = new QSpinBox; yMinSpinBox->setMinimum(minSlice); yMinSpinBox->setMaximum(maxSlice); yMinSpinBox->setSingleStep(1); QObject::connect(yMinSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotYMinSpinBox(int))); gridLayout->addWidget(yMinSpinBox, 2, 1); // // Y Maximum slider // gridLayout->addWidget(new QLabel("Y Max "), 3, 0); yMaxSpinBox = new QSpinBox; yMaxSpinBox->setMinimum(minSlice); yMaxSpinBox->setMaximum(maxSlice); yMaxSpinBox->setSingleStep(1); QObject::connect(yMaxSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotYMaxSpinBox(int))); gridLayout->addWidget(yMaxSpinBox, 3, 1); // // Z Minimum slider // gridLayout->addWidget(new QLabel("Z Min "), 4, 0); zMinSpinBox = new QSpinBox; zMinSpinBox->setMinimum(minSlice); zMinSpinBox->setMaximum(maxSlice); zMinSpinBox->setSingleStep(1); QObject::connect(zMinSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotZMinSpinBox(int))); gridLayout->addWidget(zMinSpinBox, 4, 1); // // Z Maximum slider // gridLayout->addWidget(new QLabel("Z Max "), 5, 0); zMaxSpinBox = new QSpinBox; zMaxSpinBox->setMinimum(minSlice); zMaxSpinBox->setMaximum(maxSlice); zMaxSpinBox->setSingleStep(1); QObject::connect(zMaxSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotZMaxSpinBox(int))); gridLayout->addWidget(zMaxSpinBox, 5, 1); boundsGroupLayout->addWidget(new QLabel( "\n" "To make the volume larger, increase the \"max\" values\n" "or decrease the \"min\" values (make them negative).\n" "Any new voxels are set to zero.")); // // Parameters group box // QGroupBox* paramsGroupBox = new QGroupBox("Parameters File Update"); dialogLayout->addWidget(paramsGroupBox); QVBoxLayout* paramsGroupLayout = new QVBoxLayout(paramsGroupBox); // // x/y/z min check box // useXyzMinForParametersCheckBox = new QCheckBox("Set Parameters File X/Y/Z Min"); useXyzMinForParametersCheckBox->setChecked(true); paramsGroupLayout->addWidget(useXyzMinForParametersCheckBox); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); dialogLayout->addLayout(buttonsLayout); // // Apply button // QPushButton* applyButton = new QPushButton("Apply"); applyButton->setAutoDefault(false); buttonsLayout->addWidget(applyButton); QObject::connect(applyButton, SIGNAL(clicked()), this, SLOT(slotApplyButton())); // // Reset button // QPushButton* resetButton = new QPushButton("Reset"); resetButton->setAutoDefault(false); buttonsLayout->addWidget(resetButton); QObject::connect(resetButton, SIGNAL(clicked()), this, SLOT(slotResetPushButton())); // // Close button // QPushButton* closeButton = new QPushButton("Close"); closeButton->setAutoDefault(false); buttonsLayout->addWidget(closeButton); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); QtUtilities::makeButtonsSameSize(applyButton, resetButton, closeButton); } /** * Destructor. */ GuiVolumeResizingDialog::~GuiVolumeResizingDialog() { } /** * Override to show dialog */ void GuiVolumeResizingDialog::show() { updateDialog(false); WuQDialog::show(); } /** * Called when dialog is being closed. */ void GuiVolumeResizingDialog::close() { DisplaySettingsVolume* dsv = theMainWindow->getBrainSet()->getDisplaySettingsVolume(); dsv->setCroppingSlicesValid(false); GuiBrainModelOpenGL::updateAllGL(); QDialog::close(); } /** * Reset the cropping lines. */ void GuiVolumeResizingDialog::slotResetPushButton() { updateDialog(false); GuiBrainModelOpenGL::updateAllGL(); } /** * Update the dialog. */ void GuiVolumeResizingDialog::updateDialog(const bool fileChangeUpdateFlag) { DisplaySettingsVolume* dsv = theMainWindow->getBrainSet()->getDisplaySettingsVolume(); updatingDialog = true; // // Make sure there is still an underlay volume displayed in the main window // bool haveValidVolume = false; dsv->setCroppingSlicesValid(false); BrainModelVolume* bmv = theMainWindow->getBrainModelVolume(); if (bmv != NULL) { VolumeFile* vf = bmv->getUnderlayVolumeFile(); if (vf != NULL) { haveValidVolume = true; if (fileChangeUpdateFlag == false) { dsv->setCroppingSlicesValid(true); } // // Initialize the valid slices // int dim[3]; vf->getDimensions(dim); int slices[6]; slices[0] = 0; slices[1] = dim[0] - 1; slices[2] = 0; slices[3] = dim[1] - 1; slices[4] = 0; slices[5] = dim[2] - 1; dsv->setCroppingSlices(slices); // // Set the spin box min & max value // //xMinSpinBox->setMaxValue(dim[0] - 1); //xMaxSpinBox->setMaxValue(dim[0] - 1); //yMinSpinBox->setMaxValue(dim[1] - 1); //yMaxSpinBox->setMaxValue(dim[1] - 1); //zMinSpinBox->setMaxValue(dim[2] - 1); //zMaxSpinBox->setMaxValue(dim[2] - 1); // // Update with values from paramaters files // ParamsFile* paramsFile = theMainWindow->getBrainSet()->getParamsFile(); if (paramsFile != NULL) { QString cropValue; if (paramsFile->getParameter(ParamsFile::keyCropped, cropValue)) { if (cropValue == ParamsFile::keyValueYes) { int slicesTemp[6]; if (paramsFile->getParameter(ParamsFile::keyCropMinX, slicesTemp[0]) && paramsFile->getParameter(ParamsFile::keyCropMaxX, slicesTemp[1]) && paramsFile->getParameter(ParamsFile::keyCropMinY, slicesTemp[2]) && paramsFile->getParameter(ParamsFile::keyCropMaxY, slicesTemp[3]) && paramsFile->getParameter(ParamsFile::keyCropMinZ, slicesTemp[4]) && paramsFile->getParameter(ParamsFile::keyCropMaxZ, slicesTemp[5])) { slices[0] = slicesTemp[0]; slices[1] = slicesTemp[1]; slices[2] = slicesTemp[2]; slices[3] = slicesTemp[3]; slices[4] = slicesTemp[4]; slices[5] = slicesTemp[5]; } } } } // // Set the spin boxes current values // xMinSpinBox->setValue(slices[0]); xMaxSpinBox->setValue(slices[1]); yMinSpinBox->setValue(slices[2]); yMaxSpinBox->setValue(slices[3]); zMinSpinBox->setValue(slices[4]); zMaxSpinBox->setValue(slices[5]); } } if (haveValidVolume == false) { // // Close the dialog // close(); } updatingDialog = false; } /** * Called when Apply button pressed. */ void GuiVolumeResizingDialog::slotApplyButton() { DisplaySettingsVolume* dsv = theMainWindow->getBrainSet()->getDisplaySettingsVolume(); // // Go ahead and crop the underlay volume. // if (dsv->getCroppingSlicesValid()) { BrainModelVolume* bmv = theMainWindow->getBrainModelVolume(); if (bmv != NULL) { VolumeFile* vf = bmv->getUnderlayVolumeFile(); if (vf != NULL) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); int slices[6] = { xMinSpinBox->value(), xMaxSpinBox->value(), yMinSpinBox->value(), yMaxSpinBox->value(), zMinSpinBox->value(), zMaxSpinBox->value() }; dsv->setCroppingSlices(slices); ParamsFile* pf = theMainWindow->getBrainSet()->getParamsFile(); int oldDim[3]; vf->getDimensions(oldDim); vf->resize(slices, pf); if (useXyzMinForParametersCheckBox->isChecked()) { pf->setParameter(ParamsFile::keyXmin, xMinSpinBox->value()); pf->setParameter(ParamsFile::keyYmin, yMinSpinBox->value()); pf->setParameter(ParamsFile::keyZmin, zMinSpinBox->value()); try { theMainWindow->getBrainSet()->writeParamsFile(pf->getFileName()); } catch (FileException& e) { QString msg("Unable to write parameters file: "); msg.append(e.whatQString()); QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", msg); } GuiFilesModified fm; fm.setParameterModified(); theMainWindow->fileModificationUpdate(fm); } int dim[3]; vf->getDimensions(dim); if (dim[0] != oldDim[0]) { slices[0] = 0; slices[1] = dim[0] - 1; } if (dim[1] != oldDim[1]) { slices[2] = 0; slices[3] = dim[1] - 1; } if (dim[2] != oldDim[2]) { slices[4] = 0; slices[5] = dim[2] - 1; } dsv->setCroppingSlices(slices); xMinSpinBox->setValue(slices[0]); xMaxSpinBox->setValue(slices[1]); yMinSpinBox->setValue(slices[2]); yMaxSpinBox->setValue(slices[3]); zMinSpinBox->setValue(slices[4]); zMaxSpinBox->setValue(slices[5]); bmv->resetViewingTransform(0); GuiToolBar::updateAllToolBars(false); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } } } } /** * called when x minimum spin box value changed. */ void GuiVolumeResizingDialog::slotXMinSpinBox(int value) { DisplaySettingsVolume* dsv = theMainWindow->getBrainSet()->getDisplaySettingsVolume(); int slices[6]; dsv->getCroppingSlices(slices); slices[0] = value; dsv->setCroppingSlices(slices); if (updatingDialog == false) { GuiBrainModelOpenGL::updateAllGL(); } } /** * called when x maximum spin box value changed. */ void GuiVolumeResizingDialog::slotXMaxSpinBox(int value) { DisplaySettingsVolume* dsv = theMainWindow->getBrainSet()->getDisplaySettingsVolume(); int slices[6]; dsv->getCroppingSlices(slices); slices[1] = value; dsv->setCroppingSlices(slices); if (updatingDialog == false) { GuiBrainModelOpenGL::updateAllGL(); } } /** * called when y minimum spin box value changed. */ void GuiVolumeResizingDialog::slotYMinSpinBox(int value) { DisplaySettingsVolume* dsv = theMainWindow->getBrainSet()->getDisplaySettingsVolume(); int slices[6]; dsv->getCroppingSlices(slices); slices[2] = value; dsv->setCroppingSlices(slices); if (updatingDialog == false) { GuiBrainModelOpenGL::updateAllGL(); } } /** * called when y maximum spin box value changed. */ void GuiVolumeResizingDialog::slotYMaxSpinBox(int value) { DisplaySettingsVolume* dsv = theMainWindow->getBrainSet()->getDisplaySettingsVolume(); int slices[6]; dsv->getCroppingSlices(slices); slices[3] = value; dsv->setCroppingSlices(slices); if (updatingDialog == false) { GuiBrainModelOpenGL::updateAllGL(); } } /** * called when z minimum spin box value changed. */ void GuiVolumeResizingDialog::slotZMinSpinBox(int value) { DisplaySettingsVolume* dsv = theMainWindow->getBrainSet()->getDisplaySettingsVolume(); int slices[6]; dsv->getCroppingSlices(slices); slices[4] = value; dsv->setCroppingSlices(slices); if (updatingDialog == false) { GuiBrainModelOpenGL::updateAllGL(); } } /** * called when z maximum spin box value changed. */ void GuiVolumeResizingDialog::slotZMaxSpinBox(int value) { DisplaySettingsVolume* dsv = theMainWindow->getBrainSet()->getDisplaySettingsVolume(); int slices[6]; dsv->getCroppingSlices(slices); slices[5] = value; dsv->setCroppingSlices(slices); if (updatingDialog == false) { GuiBrainModelOpenGL::updateAllGL(); } } caret-5.6.4~dfsg.1.orig/caret/GuiVolumeRescaleDialog.h0000664000175000017500000000475611572067322022377 0ustar michaelmichael #ifndef __GUI_VOLUME_RESCALE_DIALOG_H__ #define __GUI_VOLUME_RESCALE_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "WuQDialog.h" class VolumeFile; class QLineEdit; /// dialog for rescaling a volume's voxel values class GuiVolumeRescaleDialog : public WuQDialog { Q_OBJECT public: // Constructor GuiVolumeRescaleDialog(QWidget* parent, const QString& message, VolumeFile* volumeFileIn, const float* outputMinMaxValues = NULL); // Destructor ~GuiVolumeRescaleDialog(); protected slots: // called when set input values button pressed void slotSetInputValuesPushButton(); // called when set output values button pressed void slotSetOutputValuesPushButton(); protected: // loads the input min/max line edits void loadInputMinMaxLineEdits(const float minValue, const float maxValue); // loads the output min/max line edits void loadOutputMinMaxLineEdits(const float minValue, const float maxValue); // called when ok/cancel pressed void done(int r); // choose values selection dialog void chooseValuesDialog(const bool inputVolumeFlag); /// the volume file VolumeFile* volumeFile; /// input min line edit QLineEdit* inputMinimumLineEdit; /// input max line edit QLineEdit* inputMaximumLineEdit; /// output min line edit QLineEdit* outputMinimumLineEdit; /// output max line edit QLineEdit* outputMaximumLineEdit; }; #endif // __GUI_VOLUME_RESCALE_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiVolumeRescaleDialog.cxx0000664000175000017500000002550611572067322022746 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include "GuiBrainModelOpenGL.h" #include "GuiVolumeRescaleDialog.h" #include "QtRadioButtonSelectionDialog.h" #include "QtUtilities.h" #include "VolumeFile.h" /** * Constructor. */ GuiVolumeRescaleDialog::GuiVolumeRescaleDialog(QWidget* parent, const QString& message, VolumeFile* volumeFileIn, const float* outputMinMaxValues) : WuQDialog(parent) { setModal(true); volumeFile = volumeFileIn; setWindowTitle("Rescale Voxels"); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // Display message // if (message.isEmpty() == false) { dialogLayout->addWidget(new QLabel(message, this)); } // // Input values // QLabel* currentRangeLabel = new QLabel("Current Range "); inputMinimumLineEdit = new QLineEdit; new QDoubleValidator(inputMinimumLineEdit); inputMaximumLineEdit = new QLineEdit; new QDoubleValidator(inputMaximumLineEdit); float minValue = 0.0, maxValue = 0.0; if (volumeFile != NULL) { volumeFile->getMinMaxVoxelValues(minValue, maxValue); } loadInputMinMaxLineEdits(minValue, maxValue); // // Set input values push button // QPushButton* setInputValuesPushButton = new QPushButton("Set..."); setInputValuesPushButton->setAutoDefault(false); setInputValuesPushButton->setFixedSize(setInputValuesPushButton->sizeHint()); QObject::connect(setInputValuesPushButton, SIGNAL(clicked()), this, SLOT(slotSetInputValuesPushButton())); // // output values // QLabel* outputRangeLabel = new QLabel("Output Range "); outputMinimumLineEdit = new QLineEdit; new QDoubleValidator(outputMinimumLineEdit); outputMaximumLineEdit = new QLineEdit; new QDoubleValidator(outputMaximumLineEdit); if (outputMinMaxValues != NULL) { minValue = outputMinMaxValues[0]; maxValue = outputMinMaxValues[1]; } loadOutputMinMaxLineEdits(minValue, maxValue); // // Set output values push button // QPushButton* setOutputValuesPushButton = new QPushButton("Set..."); setOutputValuesPushButton->setAutoDefault(false); setOutputValuesPushButton->setFixedSize(setOutputValuesPushButton->sizeHint()); QObject::connect(setOutputValuesPushButton, SIGNAL(clicked()), this, SLOT(slotSetOutputValuesPushButton())); // // Group box and grid for scaling // QGroupBox* scaleGroupBox = new QGroupBox("Voxel Rescaling"); dialogLayout->addWidget(scaleGroupBox); QGridLayout* scaleGridLayout = new QGridLayout(scaleGroupBox); scaleGridLayout->addWidget(currentRangeLabel, 0, 0); scaleGridLayout->addWidget(inputMinimumLineEdit, 0, 1); scaleGridLayout->addWidget(inputMaximumLineEdit, 0, 2); scaleGridLayout->addWidget(setInputValuesPushButton, 0, 3); scaleGridLayout->addWidget(outputRangeLabel, 1, 0); scaleGridLayout->addWidget(outputMinimumLineEdit, 1, 1); scaleGridLayout->addWidget(outputMaximumLineEdit, 1, 2); scaleGridLayout->addWidget(setOutputValuesPushButton, 1, 3); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); dialogLayout->addLayout(buttonsLayout); // // OK button // QPushButton* okButton = new QPushButton("OK"); okButton->setAutoDefault(true); buttonsLayout->addWidget(okButton); QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); // // Cancel button // QPushButton* cancelButton = new QPushButton("Cancel"); cancelButton->setAutoDefault(true); buttonsLayout->addWidget(cancelButton); QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); QtUtilities::makeButtonsSameSize(okButton, cancelButton); } /** * Destructor. */ GuiVolumeRescaleDialog::~GuiVolumeRescaleDialog() { } /** * called when set input values button pressed. */ void GuiVolumeRescaleDialog::slotSetInputValuesPushButton() { chooseValuesDialog(true); } /** * called when set output values button pressed. */ void GuiVolumeRescaleDialog::slotSetOutputValuesPushButton() { chooseValuesDialog(false); } /** * loads the input min/max line edits. */ void GuiVolumeRescaleDialog::loadInputMinMaxLineEdits(const float minValue, const float maxValue) { inputMinimumLineEdit->setText(QString::number(minValue, 'f', 3)); inputMaximumLineEdit->setText(QString::number(maxValue, 'f', 3)); } /** * loads the output min/max line edits. */ void GuiVolumeRescaleDialog::loadOutputMinMaxLineEdits(const float minValue, const float maxValue) { outputMinimumLineEdit->setText(QString::number(minValue, 'f', 3)); outputMaximumLineEdit->setText(QString::number(maxValue, 'f', 3)); } /** * called when ok/cancel pressed. */ void GuiVolumeRescaleDialog::done(int r) { if (r == QDialog::Accepted) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); if (volumeFile != NULL) { volumeFile->rescaleVoxelValues(inputMinimumLineEdit->text().toFloat(), inputMaximumLineEdit->text().toFloat(), outputMinimumLineEdit->text().toFloat(), outputMaximumLineEdit->text().toFloat()); } GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } QDialog::done(r); } /** * choose values selection dialog. */ void GuiVolumeRescaleDialog::chooseValuesDialog(const bool inputVolumeFlag) { std::vector labels; labels.push_back("Byte - Unsigned (" + QString::number(std::numeric_limits::min()) + " to " + QString::number(std::numeric_limits::max()) + ")"); labels.push_back("Byte - Signed (" + QString::number(std::numeric_limits::min()) + " to " + QString::number(std::numeric_limits::max()) + ")"); labels.push_back("Short - Unsigned (" + QString::number(std::numeric_limits::min()) + " to " + QString::number(std::numeric_limits::max()) + ")"); labels.push_back("Short - Signed (" + QString::number(std::numeric_limits::min()) + " to " + QString::number(std::numeric_limits::max()) + ")"); labels.push_back("Int - Unsigned (" + QString::number(std::numeric_limits::min()) + " to " + QString::number(std::numeric_limits::max()) + ")"); labels.push_back("Int - Signed (" + QString::number(std::numeric_limits::min()) + " to " + QString::number(std::numeric_limits::max()) + ")"); labels.push_back("Float (" + QString::number(-std::numeric_limits::max()) + " to " + QString::number(std::numeric_limits::max()) + ")"); labels.push_back("Volume Min/Max"); labels.push_back("Volume 2% to 98%"); QtRadioButtonSelectionDialog rbsd(this, "Choose Values", "Choose Desired Values", labels, -1); if (rbsd.exec() == QDialog::Accepted) { const int item = rbsd.getSelectedItemIndex(); if (item < 0) { QMessageBox::critical(this, "ERROR", "No selection made."); return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); float minValue = 0.0, maxValue = 0.0; switch (item) { case 0: minValue = std::numeric_limits::min(); maxValue = std::numeric_limits::max(); break; case 1: minValue = std::numeric_limits::min(); maxValue = std::numeric_limits::max(); break; case 2: minValue = std::numeric_limits::min(); maxValue = std::numeric_limits::max(); break; case 3: minValue = std::numeric_limits::min(); maxValue = std::numeric_limits::max(); break; case 4: minValue = std::numeric_limits::min(); maxValue = std::numeric_limits::max(); break; case 5: minValue = std::numeric_limits::min(); maxValue = std::numeric_limits::max(); break; case 6: minValue = -std::numeric_limits::max(); maxValue = std::numeric_limits::max(); break; case 7: if (volumeFile != NULL) { volumeFile->getMinMaxVoxelValues(minValue, maxValue); } break; case 8: if (volumeFile != NULL) { volumeFile->getTwoToNinetyEightPercentMinMaxVoxelValues(minValue, maxValue); } break; } if (inputVolumeFlag) { loadInputMinMaxLineEdits(minValue, maxValue); } else { loadOutputMinMaxLineEdits(minValue, maxValue); } QApplication::restoreOverrideCursor(); } } caret-5.6.4~dfsg.1.orig/caret/GuiVolumeRegionOfInterestDialog.h0000664000175000017500000002063411572067322024240 0ustar michaelmichael #ifndef __GUI_VOLUME_REGION_OF_INTEREST_DIALOG_H__ #define __GUI_VOLUME_REGION_OF_INTEREST_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "QtDialogWizard.h" class GuiVolumeSelectionControl; class QCheckBox; class QDoubleSpinBox; class QLabel; class QLineEdit; class QPushButton; class QRadioButton; class QTextEdit; /// dialog for performing region of interest operations class GuiVolumeRegionOfInterestDialog : public QtDialogWizard { Q_OBJECT public: // constructor GuiVolumeRegionOfInterestDialog(QWidget* parent); // destructor ~GuiVolumeRegionOfInterestDialog(); // update the dialog virtual void updateDialog(); protected slots: // called to select a paint id for voxel selection void slotSelectionPaintVoxelIdPushButton(); // slot called to save report page to a file. void slotReportSavePushButton(); // slot called to clear report page. void slotReportClearPushButton(); // called when select voxels push button pressed void slotSelectVoxelsPushButton(); // called when show selected voxels check box void slotShowSelectedVoxelsCheckBox(bool val); // called to clear the selected voxels void slotClearSelectedVoxels(); // called when the finished button is pressed void slotFinishPushButtonPressed(); // called to choose paint assignment name void slotPaintAssignmentNamePushButton(); protected: /// selection mode (how to select voxels) enum SELECTION_MODE { SELECTION_MODE_NONE, SELECTION_MODE_ALL_UNDERLAY_VOXELS, SELECTION_MODE_ANATOMY_ALL_VOXELS_DISPLAYED, SELECTION_MODE_FUNCTIONAL_ALL_VOXELS_DISPLAYED, SELECTION_MODE_FUNCTIONAL_VOXEL_RANGE, SELECTION_MODE_PAINT_VOXELS_WITH_PAINT_ID, SELECTION_MODE_SEGMENTATION_ALL_VOXELS_DISPLAYED }; /// operations mode enum OPERATIONS_MODE { OPERATIONS_MODE_NONE, OPERATIONS_MODE_FUNCTIONAL_ASSIGNMENT, OPERATIONS_MODE_PAINT_ID_ASSIGNMENT, OPERATIONS_MODE_PAINT_REGION_CENTER_OF_GRAVITY, OPERATIONS_MODE_PAINT_PERCENTAGE_REPORT, OPERATIONS_MODE_PROBABILISTIC_PAINT, OPERATIONS_MODE_SEGMENTATION_CENTER_OF_GRAVITY }; // called to set the number of selected voxels label void setNumberOfSelectedVoxelsLabel(); // called when a page is about to show user should override this void pageAboutToShow(QWidget* pageWidget); // set the pages that are valid and buttons that are valid (all invalid when this called) void setValidPagesAndButtons(QWidget* currentWidget); // create the selection page QWidget* createSelectionPage(); // create the operation page QWidget* createOperationPage(); // create the operation paint ID assignment page QWidget* createOperationPaintIdAssignmentPage(); // create the operation functional value assignment page QWidget* createOperationFunctionalValueAssignmentPage(); // create the operation paint region COG page QWidget* createOperationPaintRegionCOGPage(); // create the operation paint percent report page QWidget* createOperationPaintPercentReportPage(); // create the operation page QWidget* createOperationPageProbPaintOverlap(); // create the operation page QWidget* createOperationPageSegmentationCOG(); // create the output report page QWidget* createOutputReportPage(); /// the selection mode SELECTION_MODE selectionMode; /// the operations mode OPERATIONS_MODE operationsMode; /// selection all underlay voxels radio button QRadioButton* selectionAllUnderlayVoxelsRadioButton; /// selection anatomy voxels displayed radio button QRadioButton* selectionAnatomyVoxelsDisplayedRadioButton; /// selection segmentation voxels displayed radio button QRadioButton* selectionSegmentationVoxelsDisplayedRadioButton; /// selection functional voxels displayed radio button QRadioButton* selectionFunctionalVoxelsDisplayedRadioButton; /// selection functional voxel range radio button QRadioButton* selectionFunctionalVoxelsRangeRadioButton; /// selection paint voxel ID radio button QRadioButton* selectionPaintVoxelIdRadioButton; /// the selection page QWidget* selectionPage; /// the operations page QWidget* operationsPage; /// the operation paint ID assignment page QWidget* operationPaintIdAssignmentPage; /// the operation functional value assignment page QWidget* operationFunctionalVolumeAssignmentPage; /// the operation Paint Region COG page QWidget* operationPaintRegionCOGPage; /// the operation Paint Percentage Report page QWidget* operationPaintPercentReportPage; /// the operation Prob Paint Overlap page QWidget* operationProbPaintOverlapPage; /// the operation segmentation cog page QWidget* operationSegmentationCOGPage; /// the output report page QWidget* outputReportPage; /// the operation paint ID assignment radio button QRadioButton* operationPaintIdAssignmentRadioButton; /// the operation functional value assignment radio button QRadioButton* operationFunctionalVolumeAssignmentRadioButton; /// the operation Paint Region COG radio button QRadioButton* operationPaintRegionCOGRadioButton; /// the operation Paint Percentage Report radio button QRadioButton* operationPaintPercentReportRadioButton; /// the operation Prob Paint Overlap radio button QRadioButton* operationProbPaintOverlapRadioButton; /// the operation segmentation cog radio button QRadioButton* operationSegmentationCOGRadioButton; /// functional range minimum double spin box QDoubleSpinBox* functionalRangeMinimumDoubleSpinBox; /// functional range maximum double spin box QDoubleSpinBox* functionalRangeMaximumDoubleSpinBox; /// paint voxel selection push button QPushButton* selectionPaintVoxelIdPushButton; /// paint voxel selection label QLabel* selectionPaintNameLabel; /// control for segmention COG volume selection GuiVolumeSelectionControl* segmentationVolumeCogControl; /// control for paint percentage volume selection GuiVolumeSelectionControl* paintVolumePercentControl; /// control for paint COG volume selection GuiVolumeSelectionControl* paintVolumeCogControl; /// control for paint assignment volume selection GuiVolumeSelectionControl* paintVolumeAssignmentControl; /// line edit for paint volume assignment paint name QLineEdit* paintVolumeAssignmentLineEdit; /// control for functional assignment volume selection GuiVolumeSelectionControl* functionalVolumeAssignmentControl; /// double spin box for functional volume assignment value QDoubleSpinBox* functionalVolumeAssignmentValueDoubleSpinBox; /// text edit for report QTextEdit* reportTextEdit; /// voxels selected text QString voxelsSelectedText; /// number of selected voxels label QLabel* numberOfSelectedVoxelsLabel; }; #endif // __GUI_VOLUME_REGION_OF_INTEREST_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiVolumeRegionOfInterestDialog.cxx0000664000175000017500000011262211572067322024612 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include "WuQFileDialog.h" #include #include #include #include #include #include #include #include #include #include #include "BrainModelVolume.h" #include "BrainModelVolumeRegionOfInterest.h" #include "BrainSet.h" #include "GuiBrainModelOpenGL.h" #include "GuiMainWindow.h" #include "GuiNameSelectionDialog.h" #include "GuiVolumeRegionOfInterestDialog.h" #include "GuiVolumeSelectionControl.h" #include "QtUtilities.h" #include "global_variables.h" /** * constructor. */ GuiVolumeRegionOfInterestDialog::GuiVolumeRegionOfInterestDialog(QWidget* parent) : QtDialogWizard(parent) { setWindowTitle("Volume Region of Interest"); voxelsSelectedText = " voxels selected. \"Next\" disabled until voxels are selected."; // // Create the pages // selectionPage = createSelectionPage(); operationsPage = createOperationPage(); operationPaintIdAssignmentPage = createOperationPaintIdAssignmentPage(); operationFunctionalVolumeAssignmentPage = createOperationFunctionalValueAssignmentPage(); operationPaintRegionCOGPage = createOperationPaintRegionCOGPage(); operationPaintPercentReportPage = createOperationPaintPercentReportPage(); operationProbPaintOverlapPage = createOperationPageProbPaintOverlap(); operationSegmentationCOGPage = createOperationPageSegmentationCOG(); outputReportPage = createOutputReportPage(); // // Add pages to dialog // addPage(selectionPage); addPage(operationsPage); addPage(operationPaintIdAssignmentPage); addPage(operationFunctionalVolumeAssignmentPage); addPage(operationPaintRegionCOGPage); addPage(operationPaintPercentReportPage); addPage(operationProbPaintOverlapPage); addPage(operationSegmentationCOGPage); addPage(outputReportPage); selectionMode = SELECTION_MODE_NONE; operationsMode = OPERATIONS_MODE_NONE; // // Connect the finish button // QObject::connect(this, SIGNAL(signalFinishButtonPressed()), this, SLOT(slotFinishPushButtonPressed())); initializeDialog(); } /** * destructor. */ GuiVolumeRegionOfInterestDialog::~GuiVolumeRegionOfInterestDialog() { } /** * update the dialog. */ void GuiVolumeRegionOfInterestDialog::updateDialog() { segmentationVolumeCogControl->updateControl(); paintVolumePercentControl->updateControl(); paintVolumeCogControl->updateControl(); paintVolumeAssignmentControl->updateControl(); functionalVolumeAssignmentControl->updateControl(); setNumberOfSelectedVoxelsLabel(); slotUpdatePageAndButtonValidity(); } /** * called when a page is about to show user should override this. */ void GuiVolumeRegionOfInterestDialog::pageAboutToShow(QWidget* pageWidget) { BrainSet* bs = theMainWindow->getBrainSet(); //BrainModelVolume* bmv = bs->getBrainModelVolume(); if (pageWidget == selectionPage) { //selectionAllUnderlayVoxelsRadioButton->setEnabled(bmv->getUnderlayVolumeFile() != NULL); //selectionAnatomyVoxelsDisplayedRadioButton->setEnabled(bmv->getVolumeIsAnUnderlayOrAnOverlay(bmv->getSelectedVolumeAnatomyFile())); //selectionSegmentationVoxelsDisplayedRadioButton->setEnabled(bmv->getVolumeIsAnUnderlayOrAnOverlay(bmv->getSelectedVolumeSegmentationFile())); //selectionFunctionalVoxelsDisplayedRadioButton->setEnabled(bmv->getVolumeIsAnUnderlayOrAnOverlay(bmv->getSelectedVolumeFunctionalViewFile())); //selectionFunctionalVoxelsRangeRadioButton->setEnabled(bmv->getSelectedVolumeFunctionalViewFile() != NULL); //selectionPaintVoxelIdRadioButton->setEnabled(bmv->getSelectedVolumePaintFile() != NULL); } else if (pageWidget == operationsPage) { operationPaintIdAssignmentRadioButton->setEnabled(bs->getNumberOfVolumePaintFiles() > 0); operationFunctionalVolumeAssignmentRadioButton->setEnabled(bs->getNumberOfVolumeFunctionalFiles()); operationPaintRegionCOGRadioButton->setEnabled(bs->getNumberOfVolumePaintFiles() > 0); operationPaintPercentReportRadioButton->setEnabled(bs->getNumberOfVolumePaintFiles() > 0); operationProbPaintOverlapRadioButton->setEnabled(bs->getNumberOfVolumePaintFiles()); operationSegmentationCOGRadioButton->setEnabled(bs->getNumberOfVolumeSegmentationFiles() > 0); } } /** * set the pages that are valid and buttons that are valid (all invalid when this called). */ void GuiVolumeRegionOfInterestDialog::setValidPagesAndButtons(QWidget* currentPage) { BrainSet* bs = theMainWindow->getBrainSet(); BrainModelVolumeRegionOfInterest* roi = bs->getVolumeRegionOfInterestController(); setPageValid(selectionPage, true); if (currentPage == selectionPage) { selectionMode = SELECTION_MODE_NONE; if (selectionAllUnderlayVoxelsRadioButton->isChecked() && selectionAllUnderlayVoxelsRadioButton->isEnabled()) { selectionMode = SELECTION_MODE_ALL_UNDERLAY_VOXELS; } else if (selectionAnatomyVoxelsDisplayedRadioButton->isChecked() && selectionAnatomyVoxelsDisplayedRadioButton->isEnabled()) { selectionMode = SELECTION_MODE_ANATOMY_ALL_VOXELS_DISPLAYED; } else if (selectionFunctionalVoxelsDisplayedRadioButton->isChecked() && selectionFunctionalVoxelsDisplayedRadioButton->isEnabled()) { selectionMode = SELECTION_MODE_FUNCTIONAL_ALL_VOXELS_DISPLAYED; } else if (selectionFunctionalVoxelsRangeRadioButton->isChecked() && selectionFunctionalVoxelsRangeRadioButton->isEnabled()) { selectionMode = SELECTION_MODE_FUNCTIONAL_VOXEL_RANGE; } else if (selectionPaintVoxelIdRadioButton->isChecked() && selectionPaintVoxelIdRadioButton->isEnabled()) { selectionMode = SELECTION_MODE_PAINT_VOXELS_WITH_PAINT_ID; } else if (selectionSegmentationVoxelsDisplayedRadioButton->isChecked() && selectionSegmentationVoxelsDisplayedRadioButton->isEnabled()) { selectionMode = SELECTION_MODE_SEGMENTATION_ALL_VOXELS_DISPLAYED; } //setNextButtonEnabled(true); } else if (currentPage == operationsPage) { operationsMode = OPERATIONS_MODE_NONE; if (operationFunctionalVolumeAssignmentRadioButton->isChecked()) { operationsMode = OPERATIONS_MODE_FUNCTIONAL_ASSIGNMENT; } else if (operationPaintIdAssignmentRadioButton->isChecked()) { operationsMode = OPERATIONS_MODE_PAINT_ID_ASSIGNMENT; } else if (operationPaintRegionCOGRadioButton->isChecked()) { operationsMode = OPERATIONS_MODE_PAINT_REGION_CENTER_OF_GRAVITY; } else if (operationPaintPercentReportRadioButton->isChecked()) { operationsMode = OPERATIONS_MODE_PAINT_PERCENTAGE_REPORT; } else if (operationProbPaintOverlapRadioButton->isChecked()) { operationsMode = OPERATIONS_MODE_PROBABILISTIC_PAINT; } else if (operationSegmentationCOGRadioButton->isChecked()) { operationsMode = OPERATIONS_MODE_SEGMENTATION_CENTER_OF_GRAVITY; } //setFinishButtonEnabled(true); //setNextButtonEnabled(true); } else { //setNextButtonEnabled(true); } switch (selectionMode) { case SELECTION_MODE_NONE: break; case SELECTION_MODE_ALL_UNDERLAY_VOXELS: case SELECTION_MODE_ANATOMY_ALL_VOXELS_DISPLAYED: case SELECTION_MODE_FUNCTIONAL_ALL_VOXELS_DISPLAYED: case SELECTION_MODE_FUNCTIONAL_VOXEL_RANGE: case SELECTION_MODE_PAINT_VOXELS_WITH_PAINT_ID: case SELECTION_MODE_SEGMENTATION_ALL_VOXELS_DISPLAYED: if (roi->getNumberOfVoxelsInROI() > 0) { setPageValid(operationsPage, true); } break; } if (getPageValid(operationsPage)) { switch (operationsMode) { case OPERATIONS_MODE_NONE: break; case OPERATIONS_MODE_FUNCTIONAL_ASSIGNMENT: setPageValid(operationFunctionalVolumeAssignmentPage, operationFunctionalVolumeAssignmentRadioButton->isEnabled()); break; case OPERATIONS_MODE_PAINT_ID_ASSIGNMENT: setPageValid(operationPaintIdAssignmentPage, operationPaintIdAssignmentRadioButton->isEnabled()); break; case OPERATIONS_MODE_PAINT_REGION_CENTER_OF_GRAVITY: setPageValid(operationPaintRegionCOGPage, operationPaintRegionCOGRadioButton->isEnabled()); break; case OPERATIONS_MODE_PAINT_PERCENTAGE_REPORT: setPageValid(operationPaintPercentReportPage, operationPaintPercentReportRadioButton->isEnabled()); break; case OPERATIONS_MODE_PROBABILISTIC_PAINT: setPageValid(operationProbPaintOverlapPage, operationProbPaintOverlapRadioButton->isEnabled()); break; case OPERATIONS_MODE_SEGMENTATION_CENTER_OF_GRAVITY: setPageValid(operationSegmentationCOGPage, operationSegmentationCOGRadioButton->isEnabled()); break; } } // // Is functional volume assigment ready? // if (currentPage == operationFunctionalVolumeAssignmentPage) { if (getPageValid(operationFunctionalVolumeAssignmentPage)) { if (functionalVolumeAssignmentControl->getSelectedVolumeFile() != NULL) { setFinishButtonEnabled(true); } } } // // Is paint ID assigment ready // if (currentPage == operationPaintIdAssignmentPage) { if (getPageValid(operationPaintIdAssignmentPage)) { if ((paintVolumeAssignmentControl->getSelectedVolumeFile() != NULL) && (paintVolumeAssignmentLineEdit->text().isEmpty() == false)) { setFinishButtonEnabled(true); } } } // // Is paint region center of gravity ready // if (currentPage == operationPaintRegionCOGPage) { if (getPageValid(operationPaintRegionCOGPage)) { if (paintVolumeCogControl->getSelectedVolumeFile() != NULL) { setFinishButtonEnabled(true); } } } // // Is paint percentage report ready // if (currentPage == operationPaintPercentReportPage) { if (getPageValid(operationPaintPercentReportPage)) { if (paintVolumePercentControl->getSelectedVolumeFile() != NULL) { setFinishButtonEnabled(true); } } } // // Is segmentation cog ready // if (currentPage == operationSegmentationCOGPage) { if (getPageValid(operationSegmentationCOGPage)) { if (segmentationVolumeCogControl->getSelectedVolumeFile() != NULL) { setFinishButtonEnabled(true); } } } // // Is paint prob overlap ready // if (currentPage == operationProbPaintOverlapPage) { if (getPageValid(operationProbPaintOverlapPage)) { setFinishButtonEnabled(true); } } } /** * create the selection page. */ QWidget* GuiVolumeRegionOfInterestDialog::createSelectionPage() { BrainSet* bs = theMainWindow->getBrainSet(); BrainModelVolumeRegionOfInterest* roi = bs->getVolumeRegionOfInterestController(); const int doubleSpinBoxWidth = 140; // // all underlay voxels radio button // selectionAllUnderlayVoxelsRadioButton = new QRadioButton("All Underlay Voxels"); selectionAllUnderlayVoxelsRadioButton->setToolTip("Use to select all voxels\n" "in the underlay volume."); // // dispalyed anatomy voxels radio button // selectionAnatomyVoxelsDisplayedRadioButton = new QRadioButton("Anatomy Voxels"); selectionAnatomyVoxelsDisplayedRadioButton->setToolTip("Use to select all anatomy voxels\n" "that are or would be displayed."); // // displayed segmentation voxels radio button // selectionSegmentationVoxelsDisplayedRadioButton = new QRadioButton("Segmentation Voxels"); selectionSegmentationVoxelsDisplayedRadioButton->setToolTip("Use to select all segmentation voxels\n" "that are or would be displayed."); // // displayed functional voxels radio button // selectionFunctionalVoxelsDisplayedRadioButton = new QRadioButton("Functional Voxels"); selectionFunctionalVoxelsDisplayedRadioButton->setToolTip("Use to select all functional voxels\n" "that are or would be displayed."); // // functional voxel range radio button // selectionFunctionalVoxelsRangeRadioButton = new QRadioButton("Functional Voxels Range"); selectionFunctionalVoxelsRangeRadioButton->setToolTip("Use to select voxels in the selected functional\n" "volume that are within a specified range."); functionalRangeMinimumDoubleSpinBox = new QDoubleSpinBox; functionalRangeMinimumDoubleSpinBox->setFixedWidth(doubleSpinBoxWidth); functionalRangeMinimumDoubleSpinBox->setMinimum(-std::numeric_limits::max()); functionalRangeMinimumDoubleSpinBox->setMaximum( std::numeric_limits::max()); functionalRangeMinimumDoubleSpinBox->setSingleStep(1.0); functionalRangeMinimumDoubleSpinBox->setDecimals(3); functionalRangeMinimumDoubleSpinBox->setToolTip("Enter range minimum here."); functionalRangeMaximumDoubleSpinBox = new QDoubleSpinBox; functionalRangeMaximumDoubleSpinBox->setFixedWidth(doubleSpinBoxWidth); functionalRangeMaximumDoubleSpinBox->setMinimum(-std::numeric_limits::max()); functionalRangeMaximumDoubleSpinBox->setMaximum( std::numeric_limits::max()); functionalRangeMaximumDoubleSpinBox->setSingleStep(1.0); functionalRangeMaximumDoubleSpinBox->setDecimals(3); functionalRangeMaximumDoubleSpinBox->setToolTip("Enter range maximum here."); QHBoxLayout* funcRangeLayout = new QHBoxLayout; funcRangeLayout->addWidget(selectionFunctionalVoxelsRangeRadioButton); funcRangeLayout->addWidget(functionalRangeMinimumDoubleSpinBox); funcRangeLayout->addWidget(functionalRangeMaximumDoubleSpinBox); funcRangeLayout->addStretch(); // // paint voxel ID radio button // selectionPaintVoxelIdRadioButton = new QRadioButton("Paint Voxels with ID"); selectionPaintVoxelIdRadioButton->setToolTip("Use to select paint voxels\n" "with a specific paint ID."); selectionPaintVoxelIdPushButton = new QPushButton("Name..."); selectionPaintVoxelIdPushButton->setAutoDefault(false); selectionPaintVoxelIdPushButton->setFixedSize(selectionPaintVoxelIdPushButton->sizeHint()); QObject::connect(selectionPaintVoxelIdPushButton, SIGNAL(clicked()), this, SLOT(slotSelectionPaintVoxelIdPushButton())); selectionPaintNameLabel = new QLabel(" "); selectionPaintNameLabel->setMinimumWidth(250); QHBoxLayout* paintLayout = new QHBoxLayout; paintLayout->addWidget(selectionPaintVoxelIdRadioButton); paintLayout->addWidget(selectionPaintVoxelIdPushButton); paintLayout->addWidget(selectionPaintNameLabel); paintLayout->addStretch(); // // button group to keep radio buttons mutually exclusive // QButtonGroup* buttGroup = new QButtonGroup(this); buttGroup->addButton(selectionAllUnderlayVoxelsRadioButton); buttGroup->addButton(selectionAnatomyVoxelsDisplayedRadioButton); buttGroup->addButton(selectionSegmentationVoxelsDisplayedRadioButton); buttGroup->addButton(selectionFunctionalVoxelsDisplayedRadioButton); buttGroup->addButton(selectionFunctionalVoxelsRangeRadioButton); buttGroup->addButton(selectionPaintVoxelIdRadioButton); QObject::connect(buttGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotClearSelectedVoxels())); QObject::connect(buttGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotUpdatePageAndButtonValidity())); // // Select voxels radio button // QPushButton* selectVoxelsPushButton = new QPushButton("Select Voxels"); selectVoxelsPushButton->setAutoDefault(false); selectVoxelsPushButton->setFixedSize(selectVoxelsPushButton->sizeHint()); QObject::connect(selectVoxelsPushButton, SIGNAL(clicked()), this, SLOT(slotSelectVoxelsPushButton())); // // Number of selected voxels label // numberOfSelectedVoxelsLabel = new QLabel("0" + voxelsSelectedText); // // Show selected voxels check box // QCheckBox* showSelectedVoxelsCheckBox = new QCheckBox("Show Selected Voxels"); showSelectedVoxelsCheckBox->setChecked(true); QObject::connect(showSelectedVoxelsCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowSelectedVoxelsCheckBox(bool))); roi->setDisplayVolumeROI(showSelectedVoxelsCheckBox->isChecked()); // // Widget and layout for page // QGroupBox* w = new QGroupBox("ROI Selection"); QVBoxLayout* l = new QVBoxLayout(w); l->addWidget(selectionAllUnderlayVoxelsRadioButton, 0, Qt::AlignLeft); l->addWidget(selectionAnatomyVoxelsDisplayedRadioButton, 0, Qt::AlignLeft); l->addWidget(selectionFunctionalVoxelsDisplayedRadioButton, 0, Qt::AlignLeft); l->addLayout(funcRangeLayout); l->addLayout(paintLayout); l->addWidget(selectionSegmentationVoxelsDisplayedRadioButton, 0, Qt::AlignLeft); l->addWidget(new QLabel(" ")); l->addWidget(selectVoxelsPushButton); l->addWidget(showSelectedVoxelsCheckBox); l->addWidget(numberOfSelectedVoxelsLabel); l->addStretch(); return w; } /** * called to select a paint id for voxel selection. */ void GuiVolumeRegionOfInterestDialog::slotSelectionPaintVoxelIdPushButton() { BrainSet* bs = theMainWindow->getBrainSet(); BrainModelVolume* bmv = bs->getBrainModelVolume(); VolumeFile* paintVolume = bmv->getSelectedVolumePaintFile(); if (paintVolume != NULL) { GuiNameSelectionDialog gnsd(this, GuiNameSelectionDialog::LIST_VOLUME_PAINT_NAMES_ALPHA, GuiNameSelectionDialog::LIST_VOLUME_PAINT_NAMES_ALPHA); if (gnsd.exec() == GuiNameSelectionDialog::Accepted) { slotClearSelectedVoxels(); selectionPaintNameLabel->setText(gnsd.getNameSelected()); } } else { QMessageBox::critical(this, "ERROR", "No paint volume is loaded."); } } /** * called when select voxels push button pressed. */ void GuiVolumeRegionOfInterestDialog::slotSelectVoxelsPushButton() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainSet* bs = theMainWindow->getBrainSet(); BrainModelVolume* bmv = bs->getBrainModelVolume(); BrainModelVolumeRegionOfInterest* roi = bs->getVolumeRegionOfInterestController(); switch (selectionMode) { case SELECTION_MODE_NONE: break; case SELECTION_MODE_ALL_UNDERLAY_VOXELS: roi->setVolumeROIToAllVoxels(bmv->getUnderlayVolumeFile()); break; case SELECTION_MODE_ANATOMY_ALL_VOXELS_DISPLAYED: roi->setVolumeROIToAllDisplayedVoxels(bmv->getSelectedVolumeAnatomyFile()); break; case SELECTION_MODE_FUNCTIONAL_ALL_VOXELS_DISPLAYED: roi->setVolumeROIToAllDisplayedVoxels(bmv->getSelectedVolumeFunctionalViewFile()); break; case SELECTION_MODE_FUNCTIONAL_VOXEL_RANGE: roi->setVolumeROIToVoxelsInRangeOfValues(bmv->getSelectedVolumeFunctionalViewFile(), functionalRangeMinimumDoubleSpinBox->value(), functionalRangeMaximumDoubleSpinBox->value()); break; case SELECTION_MODE_PAINT_VOXELS_WITH_PAINT_ID: roi->setVolumeROIToPaintIDVoxels(bmv->getSelectedVolumePaintFile(), selectionPaintNameLabel->text()); break; case SELECTION_MODE_SEGMENTATION_ALL_VOXELS_DISPLAYED: roi->setVolumeROIToAllDisplayedVoxels(bmv->getSelectedVolumeSegmentationFile()); break; } setNumberOfSelectedVoxelsLabel(); slotUpdatePageAndButtonValidity(); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } /** * called to clear the selected voxels. */ void GuiVolumeRegionOfInterestDialog::slotClearSelectedVoxels() { BrainSet* bs = theMainWindow->getBrainSet(); BrainModelVolumeRegionOfInterest* roi = bs->getVolumeRegionOfInterestController(); roi->setVolumeROIToAllVoxels(NULL); setNumberOfSelectedVoxelsLabel(); slotUpdatePageAndButtonValidity(); GuiBrainModelOpenGL::updateAllGL(); } /** * called to set the number of selected voxels label. */ void GuiVolumeRegionOfInterestDialog::setNumberOfSelectedVoxelsLabel() { BrainSet* bs = theMainWindow->getBrainSet(); BrainModelVolumeRegionOfInterest* roi = bs->getVolumeRegionOfInterestController(); const QString labelText = QString::number(roi->getNumberOfVoxelsInROI()) + voxelsSelectedText; numberOfSelectedVoxelsLabel->setText(labelText); } /** * called when show selected voxels check box. */ void GuiVolumeRegionOfInterestDialog::slotShowSelectedVoxelsCheckBox(bool val) { BrainModelVolumeRegionOfInterest* roi = theMainWindow->getBrainSet()->getVolumeRegionOfInterestController(); roi->setDisplayVolumeROI(val); GuiBrainModelOpenGL::updateAllGL(); } /** * create the operation page. */ QWidget* GuiVolumeRegionOfInterestDialog::createOperationPage() { operationPaintIdAssignmentRadioButton = new QRadioButton("Paint ID Assigment"); operationPaintIdAssignmentRadioButton->setToolTip(""); operationFunctionalVolumeAssignmentRadioButton = new QRadioButton("Functional Volume Assignment"); operationFunctionalVolumeAssignmentRadioButton->setToolTip(""); operationPaintRegionCOGRadioButton = new QRadioButton("Paint Region Center of Gravity Analysis"); operationPaintRegionCOGRadioButton->setToolTip(""); operationPaintPercentReportRadioButton = new QRadioButton("Paint Percent Report"); operationPaintPercentReportRadioButton->setToolTip(""); operationProbPaintOverlapRadioButton = new QRadioButton("Probabilistic Paint Volume Overlap Analysis"); operationProbPaintOverlapRadioButton->setToolTip(""); operationSegmentationCOGRadioButton = new QRadioButton("Segmentation Center of Gravity Analysis"); operationSegmentationCOGRadioButton->setToolTip(""); // // button group to keep radio buttons mutually exclusive // QButtonGroup* buttGroup = new QButtonGroup(this); buttGroup->addButton(operationPaintIdAssignmentRadioButton); buttGroup->addButton(operationFunctionalVolumeAssignmentRadioButton); buttGroup->addButton(operationPaintRegionCOGRadioButton); buttGroup->addButton(operationPaintPercentReportRadioButton); buttGroup->addButton(operationProbPaintOverlapRadioButton); buttGroup->addButton(operationSegmentationCOGRadioButton); QObject::connect(buttGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotUpdatePageAndButtonValidity())); // // widget and layout for the page // QGroupBox* w = new QGroupBox("ROI Operation"); QVBoxLayout* l = new QVBoxLayout(w); l->addWidget(operationFunctionalVolumeAssignmentRadioButton); l->addWidget(operationPaintIdAssignmentRadioButton); l->addWidget(operationPaintPercentReportRadioButton); l->addWidget(operationPaintRegionCOGRadioButton); l->addWidget(operationProbPaintOverlapRadioButton); l->addWidget(operationSegmentationCOGRadioButton); l->addStretch(); return w; } /** * create the operation paint ID assignment page. */ QWidget* GuiVolumeRegionOfInterestDialog::createOperationPaintIdAssignmentPage() { paintVolumeAssignmentControl = new GuiVolumeSelectionControl(0, false, false, true, false, false, false, false, GuiVolumeSelectionControl::LABEL_MODE_FILE_LABEL_AND_NAME, "paintVolumeAssignmentControl", false, false, false); QPushButton* paintAssignmentNamePushButton = new QPushButton("Paint Name..."); paintAssignmentNamePushButton->setFixedSize(paintAssignmentNamePushButton->sizeHint()), paintAssignmentNamePushButton->setAutoDefault(false); QObject::connect(paintAssignmentNamePushButton, SIGNAL(clicked()), this, SLOT(slotPaintAssignmentNamePushButton())); paintVolumeAssignmentLineEdit = new QLineEdit; QObject::connect(paintVolumeAssignmentLineEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotUpdatePageAndButtonValidity())); QGridLayout* volLayout = new QGridLayout; volLayout->addWidget(paintVolumeAssignmentControl, 0, 0, 1, 2); volLayout->addWidget(paintAssignmentNamePushButton, 1, 0, 1, 1); volLayout->addWidget(paintVolumeAssignmentLineEdit, 1, 1, 1, 1); volLayout->setColumnStretch(0, 0); volLayout->setColumnStretch(1, 100); QGroupBox* w = new QGroupBox("Paint Volume Assignment"); QVBoxLayout* l = new QVBoxLayout(w); l->addLayout(volLayout); l->addStretch(); return w; } /** * called to choose paint assignment name. */ void GuiVolumeRegionOfInterestDialog::slotPaintAssignmentNamePushButton() { GuiNameSelectionDialog gnsd(this, GuiNameSelectionDialog::LIST_ALL, GuiNameSelectionDialog::LIST_VOLUME_PAINT_NAMES_ALPHA); if (gnsd.exec() == GuiNameSelectionDialog::Accepted) { paintVolumeAssignmentLineEdit->setText(gnsd.getNameSelected()); } } /** * create the operation functional value assignment page. */ QWidget* GuiVolumeRegionOfInterestDialog::createOperationFunctionalValueAssignmentPage() { functionalVolumeAssignmentControl = new GuiVolumeSelectionControl(0, false, true, false, false, false, false, false, GuiVolumeSelectionControl::LABEL_MODE_FILE_LABEL_AND_NAME, "functionalVolumeAssignmentControl", false, false, false); QLabel* funcLabel = new QLabel("Functional Value "); functionalVolumeAssignmentValueDoubleSpinBox = new QDoubleSpinBox; functionalVolumeAssignmentValueDoubleSpinBox->setMinimum(-std::numeric_limits::max()); functionalVolumeAssignmentValueDoubleSpinBox->setMaximum(std::numeric_limits::max()); functionalVolumeAssignmentValueDoubleSpinBox->setDecimals(3); functionalVolumeAssignmentValueDoubleSpinBox->setSingleStep(1.0); QGridLayout* volLayout = new QGridLayout; volLayout->addWidget(functionalVolumeAssignmentControl, 0, 0, 1, 2); volLayout->addWidget(funcLabel, 1, 0, 1, 1); volLayout->addWidget(functionalVolumeAssignmentValueDoubleSpinBox, 1, 1, 1, 1); volLayout->setColumnStretch(0, 0); volLayout->setColumnStretch(1, 100); QGroupBox* w = new QGroupBox("Functional Volume Assignment"); QVBoxLayout* l = new QVBoxLayout(w); l->addLayout(volLayout); l->addStretch(); return w; } /** * create the operation paint region COG page. */ QWidget* GuiVolumeRegionOfInterestDialog::createOperationPaintRegionCOGPage() { paintVolumeCogControl = new GuiVolumeSelectionControl(0, false, false, true, false, false, false, false, GuiVolumeSelectionControl::LABEL_MODE_FILE_LABEL_AND_NAME, "paintVolumeCogControl", false, false, false); QHBoxLayout* volLayout = new QHBoxLayout; volLayout->addWidget(paintVolumeCogControl, 1000); QGroupBox* w = new QGroupBox("Paint Region Center Of Gravity"); QVBoxLayout* l = new QVBoxLayout(w); l->addLayout(volLayout); l->addStretch(); return w; } /** * create the operation paint percent report page. */ QWidget* GuiVolumeRegionOfInterestDialog::createOperationPaintPercentReportPage() { paintVolumePercentControl = new GuiVolumeSelectionControl(0, false, false, true, false, false, false, false, GuiVolumeSelectionControl::LABEL_MODE_FILE_LABEL_AND_NAME, "paintVolumePercentControl", false, false, false); QHBoxLayout* volLayout = new QHBoxLayout; volLayout->addWidget(paintVolumePercentControl, 1000); QGroupBox* w = new QGroupBox("Paint Percentage Report"); QVBoxLayout* l = new QVBoxLayout(w); l->addLayout(volLayout); l->addStretch(); return w; } /** * create the operation prob paint overlap page. */ QWidget* GuiVolumeRegionOfInterestDialog::createOperationPageProbPaintOverlap() { QGroupBox* w = new QGroupBox("Probabilistic Paint Volume Overlap Analysis"); QVBoxLayout* l = new QVBoxLayout(w); l->addWidget(new QLabel("Press Finish button to generate report.")); l->addStretch(); return w; } /** * create the operation page. */ QWidget* GuiVolumeRegionOfInterestDialog::createOperationPageSegmentationCOG() { segmentationVolumeCogControl = new GuiVolumeSelectionControl(0, false, false, false, false, false, true, false, GuiVolumeSelectionControl::LABEL_MODE_FILE_LABEL_AND_NAME, "segmentationVolumeCogControl", false, false, false); QHBoxLayout* volLayout = new QHBoxLayout; volLayout->addWidget(segmentationVolumeCogControl, 1000); QGroupBox* w = new QGroupBox("Segmentation Center of Gravity"); QVBoxLayout* l = new QVBoxLayout(w); l->addLayout(volLayout); l->addStretch(); return w; } /** * slot called to clear report page. */ void GuiVolumeRegionOfInterestDialog::slotReportClearPushButton() { reportTextEdit->clear(); } /** * slot called to save report page to a file. */ void GuiVolumeRegionOfInterestDialog::slotReportSavePushButton() { WuQFileDialog fd(this); fd.setModal(true); fd.setWindowTitle("Choose ROI Text File Name"); fd.setDirectory(QDir::currentPath()); fd.setAcceptMode(WuQFileDialog::AcceptSave); fd.setFilter("Text Files (*.txt)"); fd.setFileMode(WuQFileDialog::AnyFile); if (fd.exec() == QDialog::Accepted) { if (fd.selectedFiles().count() > 0) { const QString fileName = fd.selectedFiles().at(0); QFile file(fileName); if (file.open(QIODevice::WriteOnly)) { QTextStream stream(&file); stream << reportTextEdit->toPlainText(); file.close(); } else { QString msg("Unable to open for writing: "); msg.append(fileName); QMessageBox::critical(this, "Error Opening File", msg); } } } } /** * create the output report page. */ QWidget* GuiVolumeRegionOfInterestDialog::createOutputReportPage() { // // TextEdit for report contents // reportTextEdit = new QTextEdit; // // Buttons // QPushButton* clearPushButton = new QPushButton("Clear"); clearPushButton->setAutoDefault(false); QObject::connect(clearPushButton, SIGNAL(clicked()), this, SLOT(slotReportClearPushButton())); QPushButton* savePushButton = new QPushButton("Save To File..."); savePushButton->setAutoDefault(false); QObject::connect(savePushButton, SIGNAL(clicked()), this, SLOT(slotReportSavePushButton())); QtUtilities::makeButtonsSameSize(clearPushButton, savePushButton); QHBoxLayout* buttonHBoxLayout = new QHBoxLayout; buttonHBoxLayout->addWidget(clearPushButton); buttonHBoxLayout->addWidget(savePushButton); QGroupBox* w = new QGroupBox("Output Report"); QVBoxLayout* l = new QVBoxLayout(w); l->addWidget(reportTextEdit, 100); l->addLayout(buttonHBoxLayout, 0); return w; } /** * called when the finished button is pressed. */ void GuiVolumeRegionOfInterestDialog::slotFinishPushButtonPressed() { try { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); QString reportText; BrainSet* bs = theMainWindow->getBrainSet(); BrainModelVolumeRegionOfInterest* roi = bs->getVolumeRegionOfInterestController(); switch (operationsMode) { case OPERATIONS_MODE_NONE: break; case OPERATIONS_MODE_FUNCTIONAL_ASSIGNMENT: roi->operationAssignFunctionalVolumeValue(functionalVolumeAssignmentControl->getSelectedVolumeFile(), functionalVolumeAssignmentValueDoubleSpinBox->value()); break; case OPERATIONS_MODE_PAINT_ID_ASSIGNMENT: roi->operationAssignPaintVolumeID(paintVolumeAssignmentControl->getSelectedVolumeFile(), paintVolumeAssignmentLineEdit->text()); break; case OPERATIONS_MODE_PAINT_REGION_CENTER_OF_GRAVITY: roi->operationPaintRegionCenterOfGravity(paintVolumeCogControl->getSelectedVolumeFile(), reportText); break; case OPERATIONS_MODE_PAINT_PERCENTAGE_REPORT: roi->operationPaintPercentageReport(paintVolumePercentControl->getSelectedVolumeFile(), reportText); break; case OPERATIONS_MODE_PROBABILISTIC_PAINT: { std::vector paintVolumes; bs->getVolumePaintFiles(paintVolumes); roi->operationPaintOverlapAnalysis(paintVolumes, reportText); } break; case OPERATIONS_MODE_SEGMENTATION_CENTER_OF_GRAVITY: roi->operationSegmentationRegionCenterOfGravity(segmentationVolumeCogControl->getSelectedVolumeFile(), reportText); break; } if (reportText.isEmpty() == false) { const QString newText = reportTextEdit->toPlainText() + "\n" + reportText; reportTextEdit->setPlainText(newText); setPageValid(outputReportPage, true); slotNextPushButton(); } GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); return; } } caret-5.6.4~dfsg.1.orig/caret/GuiVolumeReconstructionDialog.h0000664000175000017500000000534611572067322024036 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_VOLUME_RECONSTRUCTION_DIALOG_H__ #define __GUI_VOLUME_RECONSTRUCTION_DIALOG_H__ #include "WuQDialog.h" class QCheckBox; class QComboBox; class QSpinBox; class QGroupBox; class VolumeFile; /// Dialog for constructing a surface from a volume class GuiVolumeReconstructionDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiVolumeReconstructionDialog(QWidget* parent, VolumeFile* segmentationVolumeFileIn, bool modalFlag = true, Qt::WindowFlags f = 0); /// Destructor ~GuiVolumeReconstructionDialog(); private slots: /// Called when OK or Cancel button is pressed void done(int r); /// called when surface type selected void slotSurfaceTypeComboBox(int item); private: /// surface type enum SURFACE_TYPE { /// brain model surface SURFACE_TYPE_BRAIN_MODEL = 0, /// solid structure SURFACE_TYPE_SOLID_STRUCTURE, /// visualization toolkit model SURFACE_TYPE_VTK_MODEL }; /// segmentation volume being reconstructed VolumeFile* segmentationVolumeFile; /// left hemisphere check box QCheckBox* leftHemisphereCheckBox; /// right hemisphere check box QCheckBox* rightHemisphereCheckBox; /// hemisphere group box QGroupBox* hemisphereGroup; /// surface type combo box QComboBox* surfaceTypeComboBox; /// misc group box QGroupBox* miscGroup; /// hypersmooth check box QCheckBox* hypersmoothCheckBox; /// maximumu polygons check box QCheckBox* maximumPolygonsCheckBox; }; #ifdef __GUI_VOLUME_RECONSTRUCTION_DIALOG_MAIN__ #endif // __GUI_VOLUME_RECONSTRUCTION_DIALOG_MAIN__ #endif // __GUI_VOLUME_RECONSTRUCTION_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiVolumeReconstructionDialog.cxx0000664000175000017500000002352011572067322024403 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #define __GUI_VOLUME_RECONSTRUCTION_DIALOG_MAIN__ #include "GuiVolumeReconstructionDialog.h" #undef __GUI_VOLUME_RECONSTRUCTION_DIALOG_MAIN__ #include #include #include #include #include #include #include #include #include #include "BrainModelVolumeToSurfaceConverter.h" #include "BrainSet.h" #include "GuiBrainModelOpenGL.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "QtUtilities.h" #include "VolumeFile.h" #include "global_variables.h" /** * Constructor. */ GuiVolumeReconstructionDialog::GuiVolumeReconstructionDialog(QWidget* parent, VolumeFile* segmentationVolumeFileIn, bool modalFlag, Qt::WindowFlags f) : WuQDialog(parent, f) { setModal(modalFlag); segmentationVolumeFile = segmentationVolumeFileIn; setWindowTitle("Volume Reconstruction Into Surface"); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // Type of surface to generate // surfaceTypeComboBox = new QComboBox; surfaceTypeComboBox->insertItem(SURFACE_TYPE_BRAIN_MODEL, "Brain Model Surface"); surfaceTypeComboBox->insertItem(SURFACE_TYPE_SOLID_STRUCTURE, "Solid Structure VTK Model"); surfaceTypeComboBox->insertItem(SURFACE_TYPE_VTK_MODEL, "VTK Model"); QObject::connect(surfaceTypeComboBox, SIGNAL(activated(int)), this, SLOT(slotSurfaceTypeComboBox(int))); QGroupBox* surfaceTypeGroupBox = new QGroupBox("Surface Type"); dialogLayout->addWidget(surfaceTypeGroupBox); QHBoxLayout* surfaceTypeGroupLayout = new QHBoxLayout(surfaceTypeGroupBox); surfaceTypeGroupLayout->addWidget(surfaceTypeComboBox); // // left and right hemisphere checkboxes // leftHemisphereCheckBox = new QCheckBox("Left"); rightHemisphereCheckBox = new QCheckBox("Right"); // // Group box for hemisphere // hemisphereGroup = new QGroupBox("Hemisphere"); dialogLayout->addWidget(hemisphereGroup); QVBoxLayout* hemisphereLayout = new QVBoxLayout(hemisphereGroup); hemisphereLayout->addWidget(leftHemisphereCheckBox); hemisphereLayout->addWidget(rightHemisphereCheckBox); // // Hypersmooth option // hypersmoothCheckBox = new QCheckBox("Generate Hypersmooth Surface"); // // Maximum Polygons check box // maximumPolygonsCheckBox = new QCheckBox("Maximum Polygons"); // // Misc box // miscGroup = new QGroupBox("Misc", this); dialogLayout->addWidget(miscGroup); QVBoxLayout* miscLayout = new QVBoxLayout(miscGroup); miscLayout->addWidget(hypersmoothCheckBox); miscLayout->addWidget(maximumPolygonsCheckBox); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); dialogLayout->addLayout(buttonsLayout); // // OK button // QPushButton* okButton = new QPushButton("OK"); okButton->setAutoDefault(false); buttonsLayout->addWidget(okButton); QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); // // Cancel button // QPushButton* cancelButton = new QPushButton("Cancel"); cancelButton->setAutoDefault(false); buttonsLayout->addWidget(cancelButton); QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); QtUtilities::makeButtonsSameSize(okButton, cancelButton); switch (theMainWindow->getBrainSet()->getStructure().getType()) { case Structure::STRUCTURE_TYPE_CEREBRUM_CEREBELLUM: case Structure::STRUCTURE_TYPE_SUBCORTICAL: case Structure::STRUCTURE_TYPE_ALL: case Structure::STRUCTURE_TYPE_INVALID: leftHemisphereCheckBox->setChecked(false); rightHemisphereCheckBox->setChecked(false); break; case Structure::STRUCTURE_TYPE_CORTEX_LEFT: leftHemisphereCheckBox->setChecked(true); rightHemisphereCheckBox->setChecked(false); break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT: leftHemisphereCheckBox->setChecked(false); rightHemisphereCheckBox->setChecked(true); break; case Structure::STRUCTURE_TYPE_CEREBELLUM: case Structure::STRUCTURE_TYPE_CORTEX_BOTH: leftHemisphereCheckBox->setChecked(true); rightHemisphereCheckBox->setChecked(true); break; case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_LEFT: leftHemisphereCheckBox->setChecked(false); rightHemisphereCheckBox->setChecked(false); break; case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_RIGHT: leftHemisphereCheckBox->setChecked(false); rightHemisphereCheckBox->setChecked(false); break; case Structure::STRUCTURE_TYPE_CORTEX_LEFT_OR_CEREBELLUM: leftHemisphereCheckBox->setChecked(false); rightHemisphereCheckBox->setChecked(false); break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT_OR_CEREBELLUM: leftHemisphereCheckBox->setChecked(false); rightHemisphereCheckBox->setChecked(false); break; } surfaceTypeComboBox->setCurrentIndex(0); slotSurfaceTypeComboBox(0); } /** * Destructor. */ GuiVolumeReconstructionDialog::~GuiVolumeReconstructionDialog() { } /** * called when surface type selected. */ void GuiVolumeReconstructionDialog::slotSurfaceTypeComboBox(int item) { hemisphereGroup->setEnabled(item == 0); miscGroup->setEnabled(item == 0); } /** * Called when OK or Cancel button pressed. */ void GuiVolumeReconstructionDialog::done(int r) { if (r == QDialog::Accepted) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); if (segmentationVolumeFile == NULL) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "Convert to Surface Error", "There is no selected segmentation volume file."); return; } BrainModelVolumeToSurfaceConverter::RECONSTRUCTION_MODE reconMode = BrainModelVolumeToSurfaceConverter::RECONSTRUCTION_MODE_SUREFIT_SURFACE; switch (static_cast(surfaceTypeComboBox->currentIndex())) { case SURFACE_TYPE_BRAIN_MODEL: if (maximumPolygonsCheckBox->isChecked()) { reconMode = BrainModelVolumeToSurfaceConverter::RECONSTRUCTION_MODE_SUREFIT_SURFACE_MAXIMUM_POLYGONS; } else { reconMode = BrainModelVolumeToSurfaceConverter::RECONSTRUCTION_MODE_SUREFIT_SURFACE; } break; case SURFACE_TYPE_SOLID_STRUCTURE: reconMode = BrainModelVolumeToSurfaceConverter::RECONSTRUCTION_MODE_SOLID_STRUCTURE; break; case SURFACE_TYPE_VTK_MODEL: if (maximumPolygonsCheckBox->isChecked()) { reconMode = BrainModelVolumeToSurfaceConverter::RECONSTRUCTION_MODE_VTK_MODEL_MAXIMUM_POLYGONS; } else { reconMode = BrainModelVolumeToSurfaceConverter::RECONSTRUCTION_MODE_VTK_MODEL; } break; } const bool doHyper = hypersmoothCheckBox->isChecked() && (reconMode != BrainModelVolumeToSurfaceConverter::RECONSTRUCTION_MODE_VTK_MODEL); BrainModelVolumeToSurfaceConverter bmvsc(theMainWindow->getBrainSet(), segmentationVolumeFile, reconMode, rightHemisphereCheckBox->isChecked(), leftHemisphereCheckBox->isChecked(), doHyper); try { bmvsc.execute(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "Convert to Surface Error", e.whatQString()); return; } GuiFilesModified fm; fm.setStatusForAll(true); /** fm.setCoordinateModified(); fm.setTopologyModified(); fm.setVtkModelModified(); */ theMainWindow->fileModificationUpdate(fm); BrainModelSurface* bms = theMainWindow->getBrainSet()->getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_FIDUCIAL); if (bms != NULL) { theMainWindow->displayBrainModelInMainWindow(bms); } else { theMainWindow->displayNewestSurfaceInMainWindow(); } GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); theMainWindow->speakText("The surface has been reconstructed.", false); } QDialog::done(r); } caret-5.6.4~dfsg.1.orig/caret/GuiVolumePaintEditorDialog.h0000664000175000017500000000575611572067322023244 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_VOLUME_PAINT_EDITOR_DIALOG_H__ #define __GUI_VOLUME_PAINT_EDITOR_DIALOG_H__ #include #include #include "WuQDialog.h" #include "VolumeFile.h" #include "VolumeModification.h" class QComboBox; class QLineEdit; class QPushButton; /// class dialog that allows editing of a paint volume class GuiVolumePaintEditorDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiVolumePaintEditorDialog(QWidget* parent); /// Destructor ~GuiVolumePaintEditorDialog(); /// called when a voxel is selected for editing in the main window void processVoxel(const int i, const int j, const int k, const VolumeFile::VOLUME_AXIS pickAxis); /// called when dialog is popped up virtual void show(); /// update the dialog void updateDialog(); private slots: /// called when dialog is closed virtual void close(); /// called when the undo button is pressed void slotUndoButton(); /// called when apply button is pressed void slotApplyButton(); /// called when name select push button is pressed void slotNameSelectionPushButton(); private: /// Create the toggle voxels widget. QWidget* createToggleVoxelsSection(); /// clear the undo stack void clearUndoStack(); /// enable the undo button void enableUndoButton(); /// voxel region size enum TOGGLE_VOXELS_SIZE { TOGGLE_VOXELS_SIZE_1_BY_1, TOGGLE_VOXELS_SIZE_3_BY_3, TOGGLE_VOXELS_SIZE_5_BY_5, TOGGLE_VOXELS_SIZE_7_BY_7, TOGGLE_VOXELS_SIZE_9_BY_9, TOGGLE_VOXELS_SIZE_11_BY_11 }; /// voxel edit size combo box QComboBox* toggleVoxelsSizeComboBox; /// the undo button QPushButton* undoButton; /// container for storing voxel changes std::stack undoStack; /// paint name line edit QLineEdit* paintNameLineEdit; }; #endif // __GUI_VOLUME_SEGMENTATION_EDITOR_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiVolumePaintEditorDialog.cxx0000664000175000017500000003340611572067322023610 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include "AreaColorFile.h" #include "BrainModelVolume.h" #include "BrainModelVolumeVoxelColoring.h" #include "BrainSet.h" #include "GuiBrainModelOpenGL.h" #include "GuiColorSelectionDialog.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "GuiNameSelectionDialog.h" #include "GuiVolumePaintEditorDialog.h" #include "QtUtilities.h" #include "global_variables.h" /** * Constructor. */ GuiVolumePaintEditorDialog::GuiVolumePaintEditorDialog(QWidget* parent) : WuQDialog(parent) { setWindowTitle("Paint Volume Editor"); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // Create the toggle voxels section // dialogLayout->addWidget(createToggleVoxelsSection()); // // Paint name // QLabel* paintNameLabel = new QLabel("Paint Name "); paintNameLineEdit = new QLineEdit; QPushButton* nameButton = new QPushButton("Select..."); nameButton->setFixedSize(nameButton->sizeHint()); nameButton->setAutoDefault(false); QObject::connect(nameButton, SIGNAL(clicked()), this, SLOT(slotNameSelectionPushButton())); // // Arrange paint name items // QHBoxLayout* paintNameLayout = new QHBoxLayout; paintNameLayout->addWidget(paintNameLabel); paintNameLayout->addWidget(paintNameLineEdit); paintNameLayout->addWidget(nameButton); paintNameLayout->setStretchFactor(paintNameLabel, 0); paintNameLayout->setStretchFactor(paintNameLineEdit, 1000); paintNameLayout->setStretchFactor(nameButton, 0); dialogLayout->addLayout(paintNameLayout); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); dialogLayout->addLayout(buttonsLayout); // // Apply button // QPushButton* applyButton = new QPushButton("Apply"); buttonsLayout->addWidget(applyButton); applyButton->setAutoDefault(false); QObject::connect(applyButton, SIGNAL(clicked()), this, SLOT(slotApplyButton())); // // // Undo button // undoButton = new QPushButton("Undo"); buttonsLayout->addWidget(undoButton); undoButton->setAutoDefault(false); QObject::connect(undoButton, SIGNAL(clicked()), this, SLOT(slotUndoButton())); // // Close button // QPushButton* closeButton = new QPushButton("Close"); buttonsLayout->addWidget(closeButton); closeButton->setAutoDefault(false); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); // // Make buttons same size // QtUtilities::makeButtonsSameSize(applyButton, undoButton, closeButton); // // Initialize dialog // clearUndoStack(); // // Update the dialog // updateDialog(); } /** * Destructor. */ GuiVolumePaintEditorDialog::~GuiVolumePaintEditorDialog() { } /** * called when name select push button is pressed. */ void GuiVolumePaintEditorDialog::slotNameSelectionPushButton() { static GuiNameSelectionDialog::LIST_ITEMS_TYPE itemForDisplay = GuiNameSelectionDialog::LIST_AREA_COLORS_ALPHA; GuiNameSelectionDialog nsd(this, GuiNameSelectionDialog::LIST_ALL, itemForDisplay); if (nsd.exec() == QDialog::Accepted) { QString name(nsd.getNameSelected()); if (name.isEmpty() == false) { paintNameLineEdit->setText(name); } } } /** * update the dialog. */ void GuiVolumePaintEditorDialog::updateDialog() { } /** * called when apply button is pressed. */ void GuiVolumePaintEditorDialog::slotApplyButton() { QString paintName = paintNameLineEdit->text(); // // Find the matching color // bool areaColorMatch = false; AreaColorFile* areaColorFile = theMainWindow->getBrainSet()->getAreaColorFile(); const int areaColorIndex = areaColorFile->getColorIndexByName(paintName, areaColorMatch); // // Area color may need to be created // if (areaColorMatch == false) { QString msg("Matching area color \""); msg.append(paintName); msg.append("\" not found"); QString defineButtonText("Define Area Color "); int result = 0; if (areaColorIndex >= 0) { QString partialMatchButtonText("Use "); partialMatchButtonText.append(areaColorFile->getColorNameByIndex(areaColorIndex)); QMessageBox msgBox(this); msgBox.setWindowTitle("Set Area Color"); msgBox.setText(msg); msgBox.addButton(defineButtonText, QMessageBox::ActionRole); QPushButton* partialMatchPushButton = msgBox.addButton(partialMatchButtonText, QMessageBox::ActionRole); if (msgBox.clickedButton() == partialMatchPushButton) { result = 1; } else { result = 0; } } if (result == 0) { // // define the area color // QString title("Create Area Color: "); title.append(paintName); GuiColorSelectionDialog* csd = new GuiColorSelectionDialog(this, title, false, false, false, false); csd->exec(); // // Add new area color // float pointSize = 2.0, lineSize = 1.0; unsigned char r, g, b, a; ColorFile::ColorStorage::SYMBOL symbol; csd->getColorInformation(r, g, b, a, pointSize, lineSize, symbol); areaColorFile->addColor(paintName, r, g, b, a, pointSize, lineSize, symbol); // // Area Color File has changed // GuiFilesModified fm; fm.setAreaColorModified(); theMainWindow->fileModificationUpdate(fm); } else if (result == 2) { // // do nothing so that partially matching color is used // } } theMainWindow->getBrainModelOpenGL()->setMouseMode( GuiBrainModelOpenGL::MOUSE_MODE_VOLUME_PAINT_EDIT); } /** * Create the toggle voxels widget. */ QWidget* GuiVolumePaintEditorDialog::createToggleVoxelsSection() { // // Voxel size combo box and label // QLabel* toggleVoxelsLabel = new QLabel("Brush Size"); toggleVoxelsSizeComboBox = new QComboBox; toggleVoxelsSizeComboBox->insertItem(TOGGLE_VOXELS_SIZE_1_BY_1, "1 x 1"); toggleVoxelsSizeComboBox->insertItem(TOGGLE_VOXELS_SIZE_3_BY_3, "3 x 3"); toggleVoxelsSizeComboBox->insertItem(TOGGLE_VOXELS_SIZE_5_BY_5, "5 x 5"); toggleVoxelsSizeComboBox->insertItem(TOGGLE_VOXELS_SIZE_7_BY_7, "7 x 7"); toggleVoxelsSizeComboBox->insertItem(TOGGLE_VOXELS_SIZE_9_BY_9, "9 x 9"); toggleVoxelsSizeComboBox->insertItem(TOGGLE_VOXELS_SIZE_11_BY_11, "11 x 11"); toggleVoxelsSizeComboBox->setCurrentIndex(TOGGLE_VOXELS_SIZE_1_BY_1); // // Layout the items // QWidget* toggleVoxelsWidget = new QWidget; QHBoxLayout* toggleVoxelsLayout = new QHBoxLayout(toggleVoxelsWidget); toggleVoxelsLayout->addWidget(toggleVoxelsLabel); toggleVoxelsLayout->addWidget(toggleVoxelsSizeComboBox); toggleVoxelsLayout->addStretch(); return toggleVoxelsWidget; } /** * called when dialog is closed. */ void GuiVolumePaintEditorDialog::close() { clearUndoStack(); // // If in paint edit mode, switch to view mode // GuiBrainModelOpenGL* openGL = theMainWindow->getBrainModelOpenGL(); if (openGL->getMouseMode() == GuiBrainModelOpenGL::MOUSE_MODE_VOLUME_PAINT_EDIT) { openGL->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_VIEW); } QDialog::close(); } /** * called when dialog is popped up. */ void GuiVolumePaintEditorDialog::show() { clearUndoStack(); WuQDialog::show(); theMainWindow->getBrainModelOpenGL()->setMouseMode( GuiBrainModelOpenGL::MOUSE_MODE_VOLUME_PAINT_EDIT); } /** * Called when a voxel is selected for editing in the main window. */ void GuiVolumePaintEditorDialog::processVoxel(const int ii, const int jj, const int kk, const VolumeFile::VOLUME_AXIS pickAxis) { BrainModelVolume* bmv = theMainWindow->getBrainModelVolume(); if (bmv == NULL) { close(); return; } VolumeFile::VOLUME_AXIS axis = bmv->getSelectedAxis(0); switch (axis) { case VolumeFile::VOLUME_AXIS_X: break; case VolumeFile::VOLUME_AXIS_Y: break; case VolumeFile::VOLUME_AXIS_Z: break; case VolumeFile::VOLUME_AXIS_ALL: if ((pickAxis == VolumeFile::VOLUME_AXIS_X) || (pickAxis == VolumeFile::VOLUME_AXIS_Y) || (pickAxis == VolumeFile::VOLUME_AXIS_Z)) { axis = pickAxis; } else { return; } break; case VolumeFile::VOLUME_AXIS_OBLIQUE: case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", "Editing of oblique slices is not allowed."); return; case VolumeFile::VOLUME_AXIS_UNKNOWN: return; break; } VolumeFile* vf = bmv->getSelectedVolumePaintFile(); if (vf != NULL) { // // Set indice range for voxels that are to be processed // int mm = 0; switch (static_cast(toggleVoxelsSizeComboBox->currentIndex())) { case TOGGLE_VOXELS_SIZE_1_BY_1: mm = 0; break; case TOGGLE_VOXELS_SIZE_3_BY_3: mm = 1; break; case TOGGLE_VOXELS_SIZE_5_BY_5: mm = 2; break; case TOGGLE_VOXELS_SIZE_7_BY_7: mm = 3; break; case TOGGLE_VOXELS_SIZE_9_BY_9: mm = 4; break; case TOGGLE_VOXELS_SIZE_11_BY_11: mm = 5; break; } int ijkMin[3] = { ii - mm, jj - mm, kk - mm }; int ijkMax[3] = { ii + mm, jj + mm, kk + mm }; // // Process three dim aspect // int threeDim = 0; switch (axis) { case VolumeFile::VOLUME_AXIS_X: ijkMin[0] = ii - threeDim; ijkMax[0] = ii + threeDim; break; case VolumeFile::VOLUME_AXIS_Y: ijkMin[1] = jj - threeDim; ijkMax[1] = jj + threeDim; break; case VolumeFile::VOLUME_AXIS_Z: ijkMin[2] = kk - threeDim; ijkMax[2] = kk + threeDim; break; case VolumeFile::VOLUME_AXIS_ALL: case VolumeFile::VOLUME_AXIS_OBLIQUE: case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } VolumeModification modifiedVoxels; // // Perform operation on the volume // vf->assignPaintVolumeVoxels(paintNameLineEdit->text(), ijkMin, ijkMax, &modifiedVoxels); if (modifiedVoxels.getNumberOfVoxels()) { undoStack.push(modifiedVoxels); } enableUndoButton(); GuiBrainModelOpenGL::updateAllGL(); } QApplication::restoreOverrideCursor(); } /** * Clear the undo stack */ void GuiVolumePaintEditorDialog::clearUndoStack() { while (undoStack.empty() == false) { undoStack.pop(); } enableUndoButton(); } /** * Called when the undo button is pressed. */ void GuiVolumePaintEditorDialog::slotUndoButton() { BrainModelVolume* bmv = theMainWindow->getBrainModelVolume(); if (bmv == NULL) { close(); return; } VolumeFile* vf = bmv->getSelectedVolumePaintFile(); if (vf != NULL) { if (undoStack.empty() == false) { VolumeModification volumeModification = undoStack.top(); undoStack.pop(); vf->undoModification(&volumeModification); } GuiBrainModelOpenGL::updateAllGL(); } enableUndoButton(); } /** * Enable the undo button. */ void GuiVolumePaintEditorDialog::enableUndoButton() { undoButton->setEnabled(undoStack.empty() == false); } caret-5.6.4~dfsg.1.orig/caret/GuiVolumeHandleFinderDialog.h0000664000175000017500000000642611572067322023340 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_VOLUME_HANDLE_FINDER_DIALOG_H__ #define __GUI_VOLUME_HANDLE_FINDER_DIALOG_H__ #include #include "WuQDialog.h" #include "BrainModelVolumeTopologicalError.h" class QCheckBox; class QListWidget; class QPushButton; class QRadioButton; class WuQWidgetGroup; /// Dialog for handle finding class GuiVolumeHandleFinderDialog : public WuQDialog { Q_OBJECT public: /// constructor GuiVolumeHandleFinderDialog(QWidget* parent); /// destructor ~GuiVolumeHandleFinderDialog(); /// called to display the dialog virtual void show(); /// called to close the dialog virtual void close(); private slots: /// called when find handles pushbutton is pressed void slotFindHandlesPushButton(); /// called when fill selected handle push button is pressed void slotFillHandlePushButton(); /// called when and items is selected in the handles list box void handleListBoxSelection(int item); /// called when search method radio button clicked void slotSearchMethodButton(); private: /// clear any current handles void clearHandles(); /// load handles into list box void loadHandlesIntoListBox(); /// search axis X check box QCheckBox* searchAxisXCheckBox; /// search axis Y check box QCheckBox* searchAxisYCheckBox; /// search axis Z check box QCheckBox* searchAxisZCheckBox; /// search segmentation radio button QRadioButton* searchSegmentationRadioButton; /// crossovers search radio button QRadioButton* searchCrossoversRadioButton; /// handles list box QListWidget* handlesListWidget; /// handles from last search std::vector handles; /// create a volume showing the handles check box QCheckBox* createVolumeShowingHandlesCheckBox; /// create an rgb paint file showing the handles on the surface QCheckBox* createRgbPaintSurfaceHandlesCheckBox; /// index of selected handle int selectedHandleIndex; /// search segmentation widget group WuQWidgetGroup* searchSegmentationWidgetGroup; /// fill handle push button QPushButton* fillHandlePushButton; }; #endif // __GUI_VOLUME_HANDLE_FINDER_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiVolumeHandleFinderDialog.cxx0000664000175000017500000005625611572067322023721 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include "BrainModelVolume.h" #include "BrainSet.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceNodeColoring.h" #include "BrainModelVolumeCrossoverHandleFinder.h" #include "BrainModelVolumeHandleFinder.h" #include "BrainModelVolumeVoxelColoring.h" #include "DebugControl.h" #include "DisplaySettingsRgbPaint.h" #include "DisplaySettingsVolume.h" #include "GuiBrainModelOpenGL.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "GuiToolBar.h" #include "GuiVolumeHandleFinderDialog.h" #include "WuQWidgetGroup.h" #include "RgbPaintFile.h" #include "global_variables.h" /** * constructor. */ GuiVolumeHandleFinderDialog::GuiVolumeHandleFinderDialog(QWidget* parent) : WuQDialog(parent) { setWindowTitle("Volume Handle Finder"); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // Search axis check boxes // searchAxisXCheckBox = new QCheckBox("X Axis (Parasagittal)"); searchAxisYCheckBox = new QCheckBox("Y Axis (Coronal)"); searchAxisZCheckBox = new QCheckBox("Z Axis (Horizontal)"); QVBoxLayout* searchSegmentationVerticalLayout = new QVBoxLayout; searchSegmentationVerticalLayout->addWidget(searchAxisXCheckBox); searchSegmentationVerticalLayout->addWidget(searchAxisYCheckBox); searchSegmentationVerticalLayout->addWidget(searchAxisZCheckBox); QHBoxLayout* searchSegmentationGroupLayout = new QHBoxLayout; searchSegmentationGroupLayout->addWidget(new QLabel(" ")); searchSegmentationGroupLayout->addLayout(searchSegmentationVerticalLayout); searchSegmentationGroupLayout->addStretch(); // // Widget group for enabling/disabling search axis check boxes // searchSegmentationWidgetGroup = new WuQWidgetGroup(this); searchSegmentationWidgetGroup->addWidget(searchAxisXCheckBox); searchSegmentationWidgetGroup->addWidget(searchAxisYCheckBox); searchSegmentationWidgetGroup->addWidget(searchAxisZCheckBox); // // Search segmentation and crossovradio button // searchSegmentationRadioButton = new QRadioButton("Search Segmentation Method"); searchSegmentationRadioButton->setToolTip("Search the segmentation volume for \n" "topological defects along the sepcified\n" "axes. Once no more defects are found\n" "using this method, switch to the\n" "crossover search."); searchCrossoversRadioButton = new QRadioButton("Search Crossovers Method"); searchCrossoversRadioButton->setToolTip("Create a spherical surface from the \n" "segmentation volume and examine the\n" "spherical surface for crossovers. Map\n" "any crossovers back to the volume. Use\n" "this method after no defects are detected\n" "using the segmentation method."); // // Button group to keep mutually exclusive // QButtonGroup* searchButtonGroup = new QButtonGroup(this); QObject::connect(searchButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotSearchMethodButton())); searchButtonGroup->addButton(searchSegmentationRadioButton); searchButtonGroup->addButton(searchCrossoversRadioButton); // // Search for handles push button // QPushButton* searchPushButton = new QPushButton("Search For Handles"); searchPushButton->setAutoDefault(false); searchPushButton->setFixedSize(searchPushButton->sizeHint()); QObject::connect(searchPushButton, SIGNAL(clicked()), this, SLOT(slotFindHandlesPushButton())); // // Search Group Box and Layout // QGroupBox* searchGroupBox = new QGroupBox("Search"); dialogLayout->addWidget(searchGroupBox); QVBoxLayout* searchGroupLayout = new QVBoxLayout(searchGroupBox); searchGroupLayout->addWidget(searchSegmentationRadioButton); searchGroupLayout->addLayout(searchSegmentationGroupLayout); searchGroupLayout->addWidget(searchCrossoversRadioButton); searchGroupLayout->addWidget(searchPushButton); // // add some space // //searchGroupBox->addSpace(10); // // Create rgb volume showing handles check box // createVolumeShowingHandlesCheckBox = new QCheckBox("Create RGB Volume Showing Handles"); createVolumeShowingHandlesCheckBox->setChecked(true); // // Create rgb paint showing handles on surface check box // createRgbPaintSurfaceHandlesCheckBox = new QCheckBox("Create RGB Paint Showing Handles on Surfaces"); bool haveSurfaces = false; for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfBrainModels(); i++) { if (theMainWindow->getBrainSet()->getBrainModelSurface(i) != NULL) { haveSurfaces = true; break; } } createRgbPaintSurfaceHandlesCheckBox->setEnabled(true); createRgbPaintSurfaceHandlesCheckBox->setChecked(true); // // Show Handles Group Box // QGroupBox* showGroupBox = new QGroupBox("Show Handles"); dialogLayout->addWidget(showGroupBox); QVBoxLayout* showGroupLayout = new QVBoxLayout(showGroupBox); showGroupLayout->addWidget(createVolumeShowingHandlesCheckBox); showGroupLayout->addWidget(createRgbPaintSurfaceHandlesCheckBox); // // Handles list box // handlesListWidget = new QListWidget; QObject::connect(handlesListWidget, SIGNAL(currentRowChanged(int)), this, SLOT(handleListBoxSelection(int))); // // Fill selected handle button // fillHandlePushButton = new QPushButton("Fill Selected Handle"); fillHandlePushButton->setAutoDefault(false); fillHandlePushButton->setFixedSize(fillHandlePushButton->sizeHint()); QObject::connect(fillHandlePushButton, SIGNAL(clicked()), this, SLOT(slotFillHandlePushButton())); // // Group box for handles // QGroupBox* handlesGroupBox = new QGroupBox("Handles"); dialogLayout->addWidget(handlesGroupBox); QVBoxLayout* handlesGroupLayout = new QVBoxLayout(handlesGroupBox); handlesGroupLayout->addWidget(handlesListWidget); handlesGroupLayout->addWidget(fillHandlePushButton); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); dialogLayout->addLayout(buttonsLayout); // // Close button // QPushButton* closeButton = new QPushButton("Close"); buttonsLayout->addWidget(closeButton); closeButton->setAutoDefault(false); closeButton->setFixedSize(closeButton->sizeHint()); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); clearHandles(); } /** * destructor. */ GuiVolumeHandleFinderDialog::~GuiVolumeHandleFinderDialog() { } /** * called when search method radio button clicked. */ void GuiVolumeHandleFinderDialog::slotSearchMethodButton() { fillHandlePushButton->setEnabled(searchSegmentationRadioButton->isChecked()); searchSegmentationWidgetGroup->setEnabled(searchSegmentationRadioButton->isChecked()); } /** * called to display the dialog. */ void GuiVolumeHandleFinderDialog::show() { clearHandles(); WuQDialog::show(); } /** * called to close the dialog. */ void GuiVolumeHandleFinderDialog::close() { clearHandles(); QDialog::close(); } /** * Called when go to handle push button pressed. */ void GuiVolumeHandleFinderDialog::handleListBoxSelection(int item) { selectedHandleIndex = -1; BrainSet* bs = theMainWindow->getBrainSet(); if ((item >= 0) && (item < static_cast(handles.size()))) { BrainModelVolume* bmv = bs->getBrainModelVolume(); if (bmv != NULL) { selectedHandleIndex = item; BrainModelVolumeTopologicalError& handle = handles[item]; float xyz[3]; int ijk[3], slices[2], numVoxels; VolumeFile::VOLUME_AXIS axis; handle.getInfo(ijk, xyz, slices, numVoxels, axis); const VolumeFile* vf = bmv->getMasterVolumeFile(); if (vf != NULL) { vf->convertCoordinatesToVoxelIJK(xyz, ijk); // // Highlight in all windows // for (int i = 0; i < BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS; i++) { bmv->setSelectedOrthogonalSlices(i, ijk); if ((axis == VolumeFile::VOLUME_AXIS_X) || (axis == VolumeFile::VOLUME_AXIS_Y) || (axis == VolumeFile::VOLUME_AXIS_Z)) { bmv->setSelectedAxis(i, axis); } } // // Highlight nearby node in surfaces // BrainModelSurface* bms = bs->getActiveFiducialSurface(); if (bms != NULL) { const CoordinateFile* cf = bms->getCoordinateFile(); const int nodeNum = cf->getCoordinateIndexClosestToPoint(xyz[0], xyz[1], xyz[2]); if (nodeNum >= 0) { bs->setDisplayCrossForNode(nodeNum, NULL); BrainSetNodeAttribute* bna = bs->getNodeAttributes(nodeNum); bna->setHighlighting(BrainSetNodeAttribute::HIGHLIGHT_NODE_LOCAL); } } GuiToolBar::updateAllToolBars(false); GuiBrainModelOpenGL::updateAllGL(); } } } } /** * called when fill selected handle push button is pressed. */ void GuiVolumeHandleFinderDialog::slotFillHandlePushButton() { if ((selectedHandleIndex >= 0) && (selectedHandleIndex < static_cast(handles.size()))) { BrainModelVolume* bmv = theMainWindow->getBrainModelVolume(); if (bmv != NULL) { // // Get the segmentation volume // VolumeFile* segmentVolume = bmv->getSelectedVolumeSegmentationFile(); // // Get the voxels that make up the handle // std::vector handleVoxels; handles[selectedHandleIndex].getHandleVoxels(handleVoxels); if (handleVoxels.size() > 0) { // // Set the voxels // segmentVolume->setVoxel(handleVoxels, 255.0); // // Assign voxel colors and redraw // //BrainModelVolumeVoxelColoring* voxelColoring = theMainWindow->getBrainSet()->getVoxelColoring(); segmentVolume->setVoxelColoringInvalid(); GuiBrainModelOpenGL::updateAllGL(); } } } } /** * Clear any handles currently in dialog. */ void GuiVolumeHandleFinderDialog::clearHandles() { selectedHandleIndex = -1; handles.clear(); handlesListWidget->clear(); } /** * load handles into list box. */ void GuiVolumeHandleFinderDialog::loadHandlesIntoListBox() { const int numHandles = static_cast(handles.size()); for (int i = 0; i < numHandles; i++) { const BrainModelVolumeTopologicalError& handle = handles[i]; float xyz[3]; int ijk[3], slices[2], numVoxels; VolumeFile::VOLUME_AXIS axis; handle.getInfo(ijk, xyz, slices, numVoxels, axis); char axisChar = ' '; switch (axis) { case VolumeFile::VOLUME_AXIS_X: axisChar = 'X'; break; case VolumeFile::VOLUME_AXIS_Y: axisChar = 'Y'; break; case VolumeFile::VOLUME_AXIS_Z: axisChar = 'Z'; break; case VolumeFile::VOLUME_AXIS_ALL: axisChar = 'A'; break; case VolumeFile::VOLUME_AXIS_OBLIQUE: axisChar = 'O'; break; case VolumeFile::VOLUME_AXIS_OBLIQUE_X: axisChar = 'O'; break; case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: axisChar = 'O'; break; case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: axisChar = 'O'; break; case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: axisChar = 'O'; break; case VolumeFile::VOLUME_AXIS_UNKNOWN: axisChar = 'U'; break; } QString str = // + "voxel (" // + QString::number(ijk[0]) + "," // + QString::number(ijk[1]) + "," // + QString::number(ijk[2]) + ") " + "xyz (" + QString::number(xyz[0], 'f', 1) + "," + QString::number(xyz[1], 'f', 1) + "," + QString::number(xyz[2], 'f', 1) + ") "; if (axisChar != 'U') { str += axisChar; } if (slices[0] >= 0) { str += " slices (" + QString::number(slices[0]) + ", " + QString::number(slices[1]) + ")"; } str += " involves " + QString::number(numVoxels) + " voxels."; if (DebugControl::getDebugOn()) { std::cout << str.toAscii().constData() << std::endl; } handlesListWidget->blockSignals(true); handlesListWidget->addItem(str); handlesListWidget->blockSignals(false); } } /** * Called when the find handles pushbutton is pressed. */ void GuiVolumeHandleFinderDialog::slotFindHandlesPushButton() { clearHandles(); BrainModelVolume* bmv = theMainWindow->getBrainSet()->getBrainModelVolume(-1); if (bmv == NULL) { return; } VolumeFile* vf = bmv->getSelectedVolumeSegmentationFile(); if (vf != NULL) { if (searchSegmentationRadioButton->isChecked()) { if ((searchAxisXCheckBox->isChecked() == false) && (searchAxisYCheckBox->isChecked() == false) && (searchAxisZCheckBox->isChecked() == false)) { QMessageBox::critical(this, "ERROR", "You must choose at least one axis to search."); return; } } else if (searchCrossoversRadioButton->isChecked() == false) { QMessageBox::critical(this, "ERROR", "You must select a search method."); return; } bool doRgbPaintSurfaceHandles = false; if (createRgbPaintSurfaceHandlesCheckBox->isEnabled()) { doRgbPaintSurfaceHandles = createRgbPaintSurfaceHandlesCheckBox->isChecked(); } bool doRgbVolumeHandles = createVolumeShowingHandlesCheckBox->isChecked(); QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); if (searchCrossoversRadioButton->isChecked()) { BrainModelVolumeCrossoverHandleFinder bmvchf(theMainWindow->getBrainSet(), vf, doRgbVolumeHandles, doRgbPaintSurfaceHandles); try { bmvchf.execute(); const int numHandles = bmvchf.getNumberOfHandles(); if (numHandles == 0) { QApplication::restoreOverrideCursor(); QMessageBox::information(this, "Information", "No handles found."); } else { for (int i = 0; i < numHandles; i++) { const BrainModelVolumeTopologicalError* handle = bmvchf.getHandleInfo(i); handles.push_back(*handle); } loadHandlesIntoListBox(); GuiFilesModified fm; fm.setVolumeModified(); fm.setRgbPaintModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); } } else { BrainModelVolumeHandleFinder bmvhf(theMainWindow->getBrainSet(), vf, doRgbVolumeHandles, searchAxisXCheckBox->isChecked(), searchAxisYCheckBox->isChecked(), searchAxisZCheckBox->isChecked(), doRgbPaintSurfaceHandles); try { bmvhf.execute(); GuiFilesModified fm; fm.setVolumeModified(); fm.setRgbPaintModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); const int numHandles = bmvhf.getNumberOfHandles(); if (numHandles == 0) { QApplication::restoreOverrideCursor(); QMessageBox::information(this, "Information", "No handles found."); } else { for (int i = 0; i < numHandles; i++) { const BrainModelVolumeTopologicalError* handle = bmvhf.getHandleInfo(i); handles.push_back(*handle); } loadHandlesIntoListBox(); /* std::ostringstream str; str << numHandles << " handles were found."; theMainWindow->speakText(str.str().c_str(), false); QString s(str.str().c_str()); s.append("\n\n"); for (int i = 0; i < numHandles; i++) { const BrainModelVolumeTopologicalError* handle = bmvhf.getHandleInfo(i); handles.push_back(*handle); int ijk[3], slices[2], numVoxels; VolumeFile::VOLUME_AXIS axis; handle->getInfo(ijk, slices, numVoxels, axis); char axisChar = ' '; switch (axis) { case VolumeFile::VOLUME_AXIS_X: axisChar = 'X'; break; case VolumeFile::VOLUME_AXIS_Y: axisChar = 'Y'; break; case VolumeFile::VOLUME_AXIS_Z: axisChar = 'Z'; break; case VolumeFile::VOLUME_AXIS_ALL: axisChar = 'A'; break; case VolumeFile::VOLUME_AXIS_OBLIQUE: axisChar = 'O'; break; case VolumeFile::VOLUME_AXIS_OBLIQUE_X: axisChar = 'O'; break; case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: axisChar = 'O'; break; case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: axisChar = 'O'; break; case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: axisChar = 'O'; break; case VolumeFile::VOLUME_AXIS_UNKNOWN: axisChar = 'U'; break; } std::ostringstream str; str << "voxel (" << ijk[0] << ", " << ijk[1] << ", " << ijk[2] << ") " << axisChar << " slices (" << slices[0] << ", " << slices[1] << ") involves " << numVoxels << " voxels."; if (DebugControl::getDebugOn()) { std::cout << str.str().c_str() << std::endl; } handlesListWidget->blockSignals(true); handlesListWidget->addItem(str.str().c_str()); handlesListWidget->blockSignals(false); } */ } } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); } } if (doRgbVolumeHandles) { // // Make newest RGB volume to show the handles // DisplaySettingsVolume* dsv = theMainWindow->getBrainSet()->getDisplaySettingsVolume(); dsv->setSelectedRgbVolume(theMainWindow->getBrainSet()->getNumberOfVolumeRgbFiles() - 1); // // Set primary overlay to Segmentation, secondary overlay to RGB Volume, // and underlay to Anatomy // BrainModelVolumeVoxelColoring* voxelColoring = theMainWindow->getBrainSet()->getVoxelColoring(); voxelColoring->setPrimaryOverlay(BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_SEGMENTATION); voxelColoring->setSecondaryOverlay(BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_RGB); voxelColoring->setUnderlay(BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_ANATOMY); } if (doRgbPaintSurfaceHandles) { // // Make RGB paint the newest RGB Paint // DisplaySettingsRgbPaint* dsrp = theMainWindow->getBrainSet()->getDisplaySettingsRgbPaint(); RgbPaintFile* rgbPaint = theMainWindow->getBrainSet()->getRgbPaintFile(); dsrp->setSelectedDisplayColumn(-1, -1, rgbPaint->getNumberOfColumns() - 1); // // Set primary overlay to RGB Paint and Underlay to shape // BrainModelSurfaceNodeColoring* bsnc = theMainWindow->getBrainSet()->getNodeColoring(); theMainWindow->getBrainSet()->getPrimarySurfaceOverlay()->setOverlay(-1, BrainModelSurfaceOverlay::OVERLAY_RGB_PAINT); theMainWindow->getBrainSet()->getSurfaceUnderlay()->setOverlay(-1, BrainModelSurfaceOverlay::OVERLAY_SURFACE_SHAPE); bsnc->assignColors(); } GuiBrainModelOpenGL::updateAllGL(); GuiToolBar::updateAllToolBars(false); theMainWindow->updateDisplayControlDialog(); } } caret-5.6.4~dfsg.1.orig/caret/GuiVolumeFileTypeComboBox.h0000664000175000017500000000357311572067322023047 0ustar michaelmichael #ifndef __GUI_VOLUME_FILE_TYPE_COMBO_BOX_H__ #define __GUI_VOLUME_FILE_TYPE_COMBO_BOX_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "VolumeFile.h" /// class for selecting a volume file type class GuiVolumeFileTypeComboBox : public QComboBox { Q_OBJECT public: // constructor GuiVolumeFileTypeComboBox(const bool showRaw = false, const bool showUnknown = false, QWidget* parent = 0); // destructor ~GuiVolumeFileTypeComboBox(); // get the volume file type VolumeFile::FILE_READ_WRITE_TYPE getVolumeFileType() const; // get the volume file type name QString getVolumeFileTypeName() const; // set the volume file type void setVolumeFileType(const VolumeFile::FILE_READ_WRITE_TYPE ft); protected: // types in the combo box std::vector volumeFileTypes; }; #endif // __GUI_VOLUME_FILE_TYPE_COMBO_BOX_H__ caret-5.6.4~dfsg.1.orig/caret/GuiVolumeFileTypeComboBox.cxx0000664000175000017500000000570711572067322023423 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "GuiVolumeFileTypeComboBox.h" /** * constructor. */ GuiVolumeFileTypeComboBox::GuiVolumeFileTypeComboBox(const bool showRaw, const bool showUnknown, QWidget* parent) : QComboBox(parent) { std::vector fileTypes; std::vector fileTypeNames; VolumeFile::getVolumeFileTypesAndNames(fileTypes, fileTypeNames); for (unsigned int i = 0; i < fileTypes.size(); i++) { bool useIt = true; if (fileTypes[i] == VolumeFile::FILE_READ_WRITE_TYPE_RAW) { useIt = showRaw; } if (fileTypes[i] == VolumeFile::FILE_READ_WRITE_TYPE_UNKNOWN) { useIt = showUnknown; } if (useIt) { addItem(fileTypeNames[i]); volumeFileTypes.push_back(fileTypes[i]); } } } /** * destructor. */ GuiVolumeFileTypeComboBox::~GuiVolumeFileTypeComboBox() { } /** * get the volume file type name. */ QString GuiVolumeFileTypeComboBox::getVolumeFileTypeName() const { const VolumeFile::FILE_READ_WRITE_TYPE ft = getVolumeFileType(); std::vector fileTypes; std::vector fileTypeNames; VolumeFile::getVolumeFileTypesAndNames(fileTypes, fileTypeNames); for (unsigned int i = 0; i < fileTypes.size(); i++) { if (fileTypes[i] == ft) { return fileTypeNames[i]; break; } } return "UNKNOWN"; } /** * get the volume type. */ VolumeFile::FILE_READ_WRITE_TYPE GuiVolumeFileTypeComboBox::getVolumeFileType() const { const int item = currentIndex(); if ((item >= 0) && (item < static_cast(volumeFileTypes.size()))) { return volumeFileTypes[item]; } return VolumeFile::FILE_READ_WRITE_TYPE_UNKNOWN; } /** * set the volume type. */ void GuiVolumeFileTypeComboBox::setVolumeFileType(const VolumeFile::FILE_READ_WRITE_TYPE ft) { for (unsigned int i = 0; i < volumeFileTypes.size(); i++) { if (volumeFileTypes[i] == ft) { setCurrentIndex(i); break; } } } caret-5.6.4~dfsg.1.orig/caret/GuiVolumeFileSelectionComboBox.h0000664000175000017500000000457711572067322024060 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_VOLUME_FILE_SELECTION_COMBO_BOX_H__ #define __GUI_VOLUME_FILE_SELECTION_COMBO_BOX_H__ #include #include "VolumeFile.h" /// combo box for selection of different types of volumes class GuiVolumeFileSelectionComboBox : public QComboBox { public: /// Constructor GuiVolumeFileSelectionComboBox(const VolumeFile::VOLUME_TYPE volumeTypeIn, const bool addAllSelectionFlag = false, QWidget* parent = 0, const char* name = 0); /// Destructor ~GuiVolumeFileSelectionComboBox(); /// get all volumes selected bool getAllVolumesSelected() const; /// Get the selected volume file (NULL if no volumes or ALL selected) VolumeFile* getSelectedVolumeFile(); /// Get the selected volume file index (negative if no volumes or ALL selected) int getSelectedVolumeFileIndex() const; /// Set the selected volume file index void setSelectedVolumeFileWithIndex(const int index); /// set the selected volume file void setSelectedVolumeFile(const VolumeFile* vf); /// update the items in the combo box void updateComboBox(); protected: /// type of volumes for this combo box VolumeFile::VOLUME_TYPE volumeType; /// all selection enabled bool allSelectionEnabled; }; #endif // __GUI_VOLUME_SELECTION_COMBO_BOX_H__ caret-5.6.4~dfsg.1.orig/caret/GuiVolumeFileSelectionComboBox.cxx0000664000175000017500000001534511572067322024426 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainSet.h" #include "FileUtilities.h" #include "GuiMainWindow.h" #include "GuiVolumeFileSelectionComboBox.h" #include "global_variables.h" static const qlonglong ALL_VOLUMES_VALUE = 1; /** * Constructor. */ GuiVolumeFileSelectionComboBox::GuiVolumeFileSelectionComboBox( const VolumeFile::VOLUME_TYPE volumeTypeIn, const bool addAllSelectionFlag, QWidget* parent, const char* /* name */) : QComboBox(parent) { volumeType = volumeTypeIn; allSelectionEnabled = addAllSelectionFlag; updateComboBox(); } /** * Destructor. */ GuiVolumeFileSelectionComboBox::~GuiVolumeFileSelectionComboBox() { } /** * get all volumes selected. */ bool GuiVolumeFileSelectionComboBox::getAllVolumesSelected() const { const int indx = currentIndex(); if ((indx >= 0) && (indx < count())) { if (itemData(indx).toLongLong() == ALL_VOLUMES_VALUE) { return true; } } return false; } /** * Get the selected volume file. */ VolumeFile* GuiVolumeFileSelectionComboBox::getSelectedVolumeFile() { const int indx = currentIndex(); if ((indx >= 0) && (indx < count())) { if (itemData(indx).toLongLong() != ALL_VOLUMES_VALUE) { return (VolumeFile*)(itemData(indx).toLongLong()); } } return NULL; } /** * Get the selected volume file index. */ int GuiVolumeFileSelectionComboBox::getSelectedVolumeFileIndex() const { const int indx = currentIndex(); if ((indx >= 0) && (indx < count())) { if (itemData(indx).toLongLong() != ALL_VOLUMES_VALUE) { return indx; } } return -1; } /** * Set the selected volume file index. */ void GuiVolumeFileSelectionComboBox::setSelectedVolumeFileWithIndex(const int indx) { if ((indx >= 0) && (indx < count())) { setCurrentIndex(indx); } } /** * Set the selected volume file. */ void GuiVolumeFileSelectionComboBox::setSelectedVolumeFile(const VolumeFile* vf) { for (int i = 0; i < count(); i++) { if (itemData(i).toLongLong() == qlonglong(vf)) { setCurrentIndex(i); break; } } } /** * Update the items in the combo box. */ void GuiVolumeFileSelectionComboBox::updateComboBox() { // // Find currently selected volume file // VolumeFile* defaultVolumeFile = NULL; const int currentIndexVal = currentIndex(); if ((currentIndexVal >= 0) && (currentIndexVal < count())) { defaultVolumeFile = (VolumeFile*)(itemData(currentIndexVal).toLongLong()); } // // Remove everything from the combo box // clear(); // // Load the combo box // switch (volumeType) { case VolumeFile::VOLUME_TYPE_ANATOMY: for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfVolumeAnatomyFiles(); i++) { VolumeFile* vf = theMainWindow->getBrainSet()->getVolumeAnatomyFile(i); addItem(FileUtilities::basename(vf->getFileName()), qlonglong(vf)); } break; case VolumeFile::VOLUME_TYPE_FUNCTIONAL: for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfVolumeFunctionalFiles(); i++) { VolumeFile* vf = theMainWindow->getBrainSet()->getVolumeFunctionalFile(i); addItem(FileUtilities::basename(vf->getFileName()), qlonglong(vf)); } break; case VolumeFile::VOLUME_TYPE_PAINT: for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfVolumePaintFiles(); i++) { VolumeFile* vf = theMainWindow->getBrainSet()->getVolumePaintFile(i); addItem(FileUtilities::basename(vf->getFileName()), qlonglong(vf)); } break; case VolumeFile::VOLUME_TYPE_PROB_ATLAS: for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfVolumeProbAtlasFiles(); i++) { VolumeFile* vf = theMainWindow->getBrainSet()->getVolumeProbAtlasFile(i); addItem(FileUtilities::basename(vf->getFileName()), qlonglong(vf)); } break; case VolumeFile::VOLUME_TYPE_RGB: for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfVolumeRgbFiles(); i++) { VolumeFile* vf = theMainWindow->getBrainSet()->getVolumeRgbFile(i); addItem(FileUtilities::basename(vf->getFileName()), qlonglong(vf)); } break; case VolumeFile::VOLUME_TYPE_ROI: break; case VolumeFile::VOLUME_TYPE_SEGMENTATION: for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfVolumeSegmentationFiles(); i++) { VolumeFile* vf = theMainWindow->getBrainSet()->getVolumeSegmentationFile(i); addItem(FileUtilities::basename(vf->getFileName()), qlonglong(vf)); } break; case VolumeFile::VOLUME_TYPE_VECTOR: for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfVolumeVectorFiles(); i++) { VolumeFile* vf = theMainWindow->getBrainSet()->getVolumeVectorFile(i); addItem(FileUtilities::basename(vf->getFileName()), qlonglong(vf)); } break; case VolumeFile::VOLUME_TYPE_UNKNOWN: break; } // // Add all // if (allSelectionEnabled) { if (count() > 0) { addItem("ALL VOLUMES", qlonglong(ALL_VOLUMES_VALUE)); } } // // Initialize default item // int defaultIndex = 0; for (int i = 0; i < count(); i++) { if (itemData(i).toLongLong() == qlonglong(defaultVolumeFile)) { defaultIndex = i; break; } } if ((defaultIndex >= 0) && (defaultIndex < count())) { setCurrentIndex(defaultIndex); } } caret-5.6.4~dfsg.1.orig/caret/GuiVolumeFileOrientationComboBox.h0000664000175000017500000000300211572067322024404 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "VolumeFile.h" /// class for a volume file orientation combo box class GuiVolumeFileOrientationComboBox : public QComboBox { public: /// Constructor GuiVolumeFileOrientationComboBox(QWidget* parent, const VolumeFile::VOLUME_AXIS axisIn, const char* name = 0); /// Destructor ~GuiVolumeFileOrientationComboBox(); /// set the orientation void setOrientation(const VolumeFile::ORIENTATION orient); /// get the orientation VolumeFile::ORIENTATION getOrientation() const; }; caret-5.6.4~dfsg.1.orig/caret/GuiVolumeFileOrientationComboBox.cxx0000664000175000017500000001304411572067322024766 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "GuiVolumeFileOrientationComboBox.h" /** * Constructor. */ GuiVolumeFileOrientationComboBox::GuiVolumeFileOrientationComboBox(QWidget* parent, const VolumeFile::VOLUME_AXIS axisIn, const char* /* name */) : QComboBox(parent) { switch (axisIn) { case VolumeFile::VOLUME_AXIS_X: addItem("X-Unknown", VolumeFile::ORIENTATION_UNKNOWN); addItem("X-Right to Left", VolumeFile::ORIENTATION_RIGHT_TO_LEFT); addItem("X-Left to Right", VolumeFile::ORIENTATION_LEFT_TO_RIGHT); addItem("X-Posterior to Anterior", VolumeFile::ORIENTATION_POSTERIOR_TO_ANTERIOR); addItem("X-Anterior to Posterior", VolumeFile::ORIENTATION_ANTERIOR_TO_POSTERIOR); addItem("X-Inferior to Superior", VolumeFile::ORIENTATION_INFERIOR_TO_SUPERIOR); addItem("X-Superior to Inferior", VolumeFile::ORIENTATION_SUPERIOR_TO_INFERIOR); break; case VolumeFile::VOLUME_AXIS_Y: addItem("Y-Unknown", VolumeFile::ORIENTATION_UNKNOWN); addItem("Y-Right to Left", VolumeFile::ORIENTATION_RIGHT_TO_LEFT); addItem("Y-Left to Right", VolumeFile::ORIENTATION_LEFT_TO_RIGHT); addItem("Y-Posterior to Anterior", VolumeFile::ORIENTATION_POSTERIOR_TO_ANTERIOR); addItem("Y-Anterior to Posterior", VolumeFile::ORIENTATION_ANTERIOR_TO_POSTERIOR); addItem("Y-Inferior to Superior", VolumeFile::ORIENTATION_INFERIOR_TO_SUPERIOR); addItem("Y-Superior to Inferior", VolumeFile::ORIENTATION_SUPERIOR_TO_INFERIOR); break; case VolumeFile::VOLUME_AXIS_Z: addItem("Z-Unknown", VolumeFile::ORIENTATION_UNKNOWN); addItem("Z-Right to Left", VolumeFile::ORIENTATION_RIGHT_TO_LEFT); addItem("Z-Left to Right", VolumeFile::ORIENTATION_LEFT_TO_RIGHT); addItem("Z-Posterior to Anterior", VolumeFile::ORIENTATION_POSTERIOR_TO_ANTERIOR); addItem("Z-Anterior to Posterior", VolumeFile::ORIENTATION_ANTERIOR_TO_POSTERIOR); addItem("Z-Inferior to Superior", VolumeFile::ORIENTATION_INFERIOR_TO_SUPERIOR); addItem("Z-Superior to Inferior", VolumeFile::ORIENTATION_SUPERIOR_TO_INFERIOR); break; case VolumeFile::VOLUME_AXIS_ALL: addItem("Unknown", VolumeFile::ORIENTATION_UNKNOWN); addItem("Right to Left", VolumeFile::ORIENTATION_RIGHT_TO_LEFT); addItem("Left to Right", VolumeFile::ORIENTATION_LEFT_TO_RIGHT); addItem("Posterior to Anterior", VolumeFile::ORIENTATION_POSTERIOR_TO_ANTERIOR); addItem("Anterior to Posterior", VolumeFile::ORIENTATION_ANTERIOR_TO_POSTERIOR); addItem("Inferior to Superior", VolumeFile::ORIENTATION_INFERIOR_TO_SUPERIOR); addItem("Superior to Inferior", VolumeFile::ORIENTATION_SUPERIOR_TO_INFERIOR); break; case VolumeFile::VOLUME_AXIS_OBLIQUE: case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: addItem("Unknown", VolumeFile::ORIENTATION_UNKNOWN); addItem("Right to Left", VolumeFile::ORIENTATION_RIGHT_TO_LEFT); addItem("Left to Right", VolumeFile::ORIENTATION_LEFT_TO_RIGHT); addItem("Posterior to Anterior", VolumeFile::ORIENTATION_POSTERIOR_TO_ANTERIOR); addItem("Anterior to Posterior", VolumeFile::ORIENTATION_ANTERIOR_TO_POSTERIOR); addItem("Inferior to Superior", VolumeFile::ORIENTATION_INFERIOR_TO_SUPERIOR); addItem("Superior to Inferior", VolumeFile::ORIENTATION_SUPERIOR_TO_INFERIOR); break; case VolumeFile::VOLUME_AXIS_UNKNOWN: addItem("Unknown", VolumeFile::ORIENTATION_UNKNOWN); addItem("Right to Left", VolumeFile::ORIENTATION_RIGHT_TO_LEFT); addItem("Left to Right", VolumeFile::ORIENTATION_LEFT_TO_RIGHT); addItem("Posterior to Anterior", VolumeFile::ORIENTATION_POSTERIOR_TO_ANTERIOR); addItem("Anterior to Posterior", VolumeFile::ORIENTATION_ANTERIOR_TO_POSTERIOR); addItem("Inferior to Superior", VolumeFile::ORIENTATION_INFERIOR_TO_SUPERIOR); addItem("Superior to Inferior", VolumeFile::ORIENTATION_SUPERIOR_TO_INFERIOR); break; } } /** * Destructor. */ GuiVolumeFileOrientationComboBox::~GuiVolumeFileOrientationComboBox() { } /** * set the orientation. */ void GuiVolumeFileOrientationComboBox::setOrientation(const VolumeFile::ORIENTATION orient) { setCurrentIndex(static_cast(orient)); } /** * get the orientation. */ VolumeFile::ORIENTATION GuiVolumeFileOrientationComboBox::getOrientation() const { return static_cast(currentIndex()); } caret-5.6.4~dfsg.1.orig/caret/GuiVolumeCreateDialog.h0000664000175000017500000000502111572067322022206 0ustar michaelmichael #ifndef __GUI_VOLUME_CREATE_DIALOG_H__ #define __GUI_VOLUME_CREATE_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "WuQDialog.h" class QComboBox; class QLineEdit; class QSpinBox; class QDoubleSpinBox; /// dialog for creating a volume class GuiVolumeCreateDialog : public WuQDialog { Q_OBJECT public: // constructor GuiVolumeCreateDialog(QWidget* parent); // destructor ~GuiVolumeCreateDialog(); protected slots: // called to set the volume attributes using a volume file void slotSetAttsFromFilePushButton(); // called to set the volume attributes using a standard space void slotSetAttsUsingStandardSpace(); protected: // called when OK or Cancel button pressed void done(int r); /// X dimension spin box QSpinBox* xDimensionSpinBox; /// Y dimension spin box QSpinBox* yDimensionSpinBox; /// Z dimension spin box QSpinBox* zDimensionSpinBox; /// X voxel size float spin box QDoubleSpinBox* xVoxelSizeDoubleSpinBox; /// Y voxel size float spin box QDoubleSpinBox* yVoxelSizeDoubleSpinBox; /// Z voxel size float spin box QDoubleSpinBox* zVoxelSizeDoubleSpinBox; /// X origin float spin box QDoubleSpinBox* xOriginDoubleSpinBox; /// Y origin float spin box QDoubleSpinBox* yOriginDoubleSpinBox; /// Z origin float spin box QDoubleSpinBox* zOriginDoubleSpinBox; /// volume type combo box QComboBox* volumeTypeComboBox; /// name line edit QLineEdit* nameLineEdit; }; #endif // __GUI_VOLUME_CREATE_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiVolumeCreateDialog.cxx0000664000175000017500000003625611572067322022577 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include "WuQFileDialog.h" #include #include #include #include #include #include #include #include #include #include "BrainSet.h" #include "FileFilters.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "GuiVolumeCreateDialog.h" #include #include "QtRadioButtonSelectionDialog.h" #include "QtUtilities.h" #include "SpecFile.h" #include "StereotaxicSpace.h" #include "VolumeFile.h" #include "global_variables.h" /** * constructor. */ GuiVolumeCreateDialog::GuiVolumeCreateDialog(QWidget* parent) : WuQDialog(parent) { setModal(true); setWindowTitle("Create Volume"); // // Layout for dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(3); dialogLayout->setSpacing(3); // // Volume type // QLabel* typeLabel = new QLabel("Type "); volumeTypeComboBox = new QComboBox; volumeTypeComboBox->addItem("Anatomy", VolumeFile::VOLUME_TYPE_ANATOMY); volumeTypeComboBox->addItem("Functional", VolumeFile::VOLUME_TYPE_FUNCTIONAL); volumeTypeComboBox->addItem("Paint", VolumeFile::VOLUME_TYPE_PAINT); volumeTypeComboBox->addItem("Probabilistic Atlas", VolumeFile::VOLUME_TYPE_PROB_ATLAS); volumeTypeComboBox->addItem("RGB Paint", VolumeFile::VOLUME_TYPE_RGB); volumeTypeComboBox->addItem("Segmentation", VolumeFile::VOLUME_TYPE_SEGMENTATION); // // Volume name // QLabel* nameLabel = new QLabel("Name "); nameLineEdit = new QLineEdit; static int nameCtr = 0; std::ostringstream str; str << "volume_" << nameCtr << "+orig" << SpecFile::getAfniVolumeFileExtension().toAscii().constData(); nameLineEdit->setText(str.str().c_str()); nameCtr++; // // Group box for name and type // QGroupBox* nameGroupBox = new QGroupBox("Voxel Attributes"); dialogLayout->addWidget(nameGroupBox); QGridLayout* nameGroupLayout = new QGridLayout(nameGroupBox); nameGroupLayout->addWidget(typeLabel, 0, 0); nameGroupLayout->addWidget(volumeTypeComboBox, 0, 1); nameGroupLayout->addWidget(nameLabel, 1, 0); nameGroupLayout->addWidget(nameLineEdit, 1, 1); // // Dimensions // QLabel* dimensionsLabel = new QLabel("Dimensions "); xDimensionSpinBox = new QSpinBox; xDimensionSpinBox->setMinimum(1); xDimensionSpinBox->setMaximum(std::numeric_limits::max()); xDimensionSpinBox->setSingleStep(1); yDimensionSpinBox = new QSpinBox; yDimensionSpinBox->setMinimum(1); yDimensionSpinBox->setMaximum(std::numeric_limits::max()); yDimensionSpinBox->setSingleStep(1); zDimensionSpinBox = new QSpinBox; zDimensionSpinBox->setMinimum(1); zDimensionSpinBox->setMaximum(std::numeric_limits::max()); zDimensionSpinBox->setSingleStep(1); // // Voxel sizes // QLabel* voxelSizeLabel = new QLabel("Voxel Sizes "); xVoxelSizeDoubleSpinBox = new QDoubleSpinBox; xVoxelSizeDoubleSpinBox->setMinimum(0.0); xVoxelSizeDoubleSpinBox->setMaximum(50000.0); xVoxelSizeDoubleSpinBox->setSingleStep(1.0); xVoxelSizeDoubleSpinBox->setDecimals(3); xVoxelSizeDoubleSpinBox->setValue(1.0); yVoxelSizeDoubleSpinBox = new QDoubleSpinBox; yVoxelSizeDoubleSpinBox->setMinimum(0.0); yVoxelSizeDoubleSpinBox->setMaximum(50000.0); yVoxelSizeDoubleSpinBox->setSingleStep(1.0); yVoxelSizeDoubleSpinBox->setDecimals(3); yVoxelSizeDoubleSpinBox->setValue(1.0); zVoxelSizeDoubleSpinBox = new QDoubleSpinBox; zVoxelSizeDoubleSpinBox->setMinimum(0.0); zVoxelSizeDoubleSpinBox->setMaximum(50000.0); zVoxelSizeDoubleSpinBox->setSingleStep(1.0); zVoxelSizeDoubleSpinBox->setDecimals(3); zVoxelSizeDoubleSpinBox->setValue(1.0); // // origin // QLabel* originLabel = new QLabel("Origin at Center\nof First Voxel"); xOriginDoubleSpinBox = new QDoubleSpinBox; xOriginDoubleSpinBox->setMinimum(-50000.0); xOriginDoubleSpinBox->setMaximum(50000.0); xOriginDoubleSpinBox->setSingleStep(1.0); xOriginDoubleSpinBox->setDecimals(3); yOriginDoubleSpinBox = new QDoubleSpinBox; yOriginDoubleSpinBox->setMinimum(-50000.0); yOriginDoubleSpinBox->setMaximum(50000.0); yOriginDoubleSpinBox->setSingleStep(1.0); yOriginDoubleSpinBox->setDecimals(3); zOriginDoubleSpinBox = new QDoubleSpinBox; zOriginDoubleSpinBox->setMinimum(-50000.0); zOriginDoubleSpinBox->setMaximum(50000.0); zOriginDoubleSpinBox->setSingleStep(1.0); zOriginDoubleSpinBox->setDecimals(3); // // Set attributes using volume file // QPushButton* setAttsFromFilePushButton = new QPushButton("Set Attributes Using Volume File..."); setAttsFromFilePushButton->setAutoDefault(false); QObject::connect(setAttsFromFilePushButton, SIGNAL(clicked()), this, SLOT(slotSetAttsFromFilePushButton())); setAttsFromFilePushButton->setToolTip( "This button displays a dialog for selecting a volume\n" "file. The volume's dimensions, voxel sizes, and origin\n" "will be placed into the dialog."); // // set attributes using standard space // QPushButton* setAttsUsingSpacePushButton = new QPushButton("Set Attributes Using Standard Stereotaxic Space..."); setAttsUsingSpacePushButton->setAutoDefault(false); QObject::connect(setAttsUsingSpacePushButton, SIGNAL(clicked()), this, SLOT(slotSetAttsUsingStandardSpace())); setAttsUsingSpacePushButton->setToolTip( "This button displays a dialog for selecting a standard\n" "space that will be used for setting the dimensions,\n" "voxel sizes, and origin."); // // Grid for volume attributes // QGridLayout* volAttGridLayout = new QGridLayout; volAttGridLayout->addWidget(dimensionsLabel, 0, 0); volAttGridLayout->addWidget(xDimensionSpinBox, 0, 1); volAttGridLayout->addWidget(yDimensionSpinBox, 0, 2); volAttGridLayout->addWidget(zDimensionSpinBox, 0, 3); volAttGridLayout->addWidget(voxelSizeLabel, 1, 0); volAttGridLayout->addWidget(xVoxelSizeDoubleSpinBox, 1, 1); volAttGridLayout->addWidget(yVoxelSizeDoubleSpinBox, 1, 2); volAttGridLayout->addWidget(zVoxelSizeDoubleSpinBox, 1, 3); volAttGridLayout->addWidget(originLabel, 2, 0); volAttGridLayout->addWidget(xOriginDoubleSpinBox, 2, 1); volAttGridLayout->addWidget(yOriginDoubleSpinBox, 2, 2); volAttGridLayout->addWidget(zOriginDoubleSpinBox, 2, 3); // // Group box for volume dimensions and stuff // QGroupBox* volAttGroupBox = new QGroupBox("Voxel Attributes"); dialogLayout->addWidget(volAttGroupBox); QVBoxLayout* volAttLayout = new QVBoxLayout(volAttGroupBox); volAttLayout->addLayout(volAttGridLayout); volAttLayout->addWidget(setAttsFromFilePushButton); volAttLayout->addWidget(setAttsUsingSpacePushButton); // // Layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(3); dialogLayout->addLayout(buttonsLayout); // // OK button // QPushButton* okButton = new QPushButton("OK"); buttonsLayout->addWidget(okButton); okButton->setAutoDefault(false); QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); // // Cancel button // QPushButton* cancelButton = new QPushButton("Cancel"); buttonsLayout->addWidget(cancelButton); cancelButton->setAutoDefault(false); QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); QtUtilities::makeButtonsSameSize(okButton, cancelButton); } /** * destructor. */ GuiVolumeCreateDialog::~GuiVolumeCreateDialog() { } /** * called to set the volume attributes using a volume file. */ void GuiVolumeCreateDialog::slotSetAttsFromFilePushButton() { // // Create a spec file dialog to select the spec file. // WuQFileDialog openVolumeFileDialog(this); openVolumeFileDialog.setModal(true); openVolumeFileDialog.setWindowTitle("Choose Volume File"); openVolumeFileDialog.setFileMode(WuQFileDialog::ExistingFile); openVolumeFileDialog.setDirectory(QDir::currentPath()); openVolumeFileDialog.setAcceptMode(WuQFileDialog::AcceptOpen); openVolumeFileDialog.setFilter(FileFilters::getVolumeGenericFileFilter()); if (openVolumeFileDialog.exec() == QDialog::Accepted) { if (openVolumeFileDialog.selectedFiles().count() > 0) { const QString vname(openVolumeFileDialog.selectedFiles().at(0)); if (vname.isEmpty() == false) { VolumeFile vf; try { vf.readFile(vname); float origin[3]; float spacing[3]; int dim[3]; vf.getDimensions(dim); vf.getOrigin(origin); vf.getSpacing(spacing); xDimensionSpinBox->setValue(dim[0]); yDimensionSpinBox->setValue(dim[1]); zDimensionSpinBox->setValue(dim[2]); xOriginDoubleSpinBox->setValue(origin[0]); yOriginDoubleSpinBox->setValue(origin[1]); zOriginDoubleSpinBox->setValue(origin[2]); xVoxelSizeDoubleSpinBox->setValue(spacing[0]); yVoxelSizeDoubleSpinBox->setValue(spacing[1]); zVoxelSizeDoubleSpinBox->setValue(spacing[2]); } catch (FileException& e) { QMessageBox::critical(this, "Error Reading Volume", e.whatQString()); } } } } } /** * called to set the volume attributes using a standard space. */ void GuiVolumeCreateDialog::slotSetAttsUsingStandardSpace() { std::vector spaces; StereotaxicSpace::getAllStereotaxicSpaces(spaces); std::vector spaceNames; for (unsigned int i = 0; i < spaces.size(); i++) { float spacing[3]; spaces[i].getVoxelSize(spacing); std::ostringstream str; str << "Space: " << spaces[i].getName().toAscii().constData() << " voxel size: (" << spacing[0] << ", " << spacing[1] << ", " << spacing[2] << ")"; spaceNames.push_back(str.str().c_str()); } QtRadioButtonSelectionDialog rbsd(this, "Choose Standard Space", "Choose Standard Space", spaceNames, 0); if (rbsd.exec() == QDialog::Accepted) { const int indx = rbsd.getSelectedItemIndex(); if ((indx >= 0) && (indx < static_cast(spaces.size()))) { QString name; int dim[3]; float origin[3]; float spacing[3]; spaces[indx].getOrigin(origin); spaces[indx].getVoxelSize(spacing); spaces[indx].getDimensions(dim); xDimensionSpinBox->setValue(dim[0]); yDimensionSpinBox->setValue(dim[1]); zDimensionSpinBox->setValue(dim[2]); xVoxelSizeDoubleSpinBox->setValue(spacing[0]); yVoxelSizeDoubleSpinBox->setValue(spacing[1]); zVoxelSizeDoubleSpinBox->setValue(spacing[2]); xOriginDoubleSpinBox->setValue(origin[0]); yOriginDoubleSpinBox->setValue(origin[1]); zOriginDoubleSpinBox->setValue(origin[2]); } } } /** * called when OK or Cancel button pressed. */ void GuiVolumeCreateDialog::done(int r) { if (r == QDialog::Accepted) { QString errorMessage; // // Check file name // const QString name(nameLineEdit->text()); if (name.isEmpty()) { errorMessage.append("Filename must not be empty.\n"); } // // Get and verify dimensions // const int dim[3] = { xDimensionSpinBox->value(), yDimensionSpinBox->value(), zDimensionSpinBox->value() }; for (int i = 0; i < 3; i++) { if (dim[i] <= 0) { errorMessage.append("Dimensions must be greater than zero.\n"); break; } } // // Get and verify voxel sizes // const float voxSize[3] = { xVoxelSizeDoubleSpinBox->value(), yVoxelSizeDoubleSpinBox->value(), zVoxelSizeDoubleSpinBox->value() }; for (int i = 0; i < 3; i++) { if (voxSize[i] <= 0) { errorMessage.append("Voxel sizes must be greater than zero.\n"); break; } } // // Get the origin // const float origin[3] = { xOriginDoubleSpinBox->value(), yOriginDoubleSpinBox->value(), zOriginDoubleSpinBox->value() }; // // See if there are error // if (errorMessage.isEmpty() == false) { QMessageBox::critical(this, "ERROR", errorMessage); return; } // // Create the volume file // VolumeFile* vf = new VolumeFile; const VolumeFile::ORIENTATION orient[3] = { VolumeFile::ORIENTATION_LEFT_TO_RIGHT, VolumeFile::ORIENTATION_POSTERIOR_TO_ANTERIOR, VolumeFile::ORIENTATION_INFERIOR_TO_SUPERIOR }; vf->initialize(VolumeFile::VOXEL_DATA_TYPE_FLOAT, dim, orient, origin, voxSize, true, true); vf->setVolumeType(static_cast(volumeTypeComboBox->currentIndex())); if ((vf->getVolumeType() == VolumeFile::VOLUME_TYPE_PAINT) || (vf->getVolumeType() == VolumeFile::VOLUME_TYPE_PROB_ATLAS)) { vf->addRegionName("???"); } vf->setFileName(name); // // Add the volume to the brain set // theMainWindow->getBrainSet()->addVolumeFile(vf->getVolumeType(), vf, name, true, false); if (vf->getVolumeType() == VolumeFile::VOLUME_TYPE_PROB_ATLAS) { theMainWindow->getBrainSet()->synchronizeProbAtlasVolumeRegionNames(); } // // Update GUI // GuiFilesModified fm; fm.setVolumeModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } QDialog::done(r); } caret-5.6.4~dfsg.1.orig/caret/GuiVolumeBiasCorrectionDialog.h0000664000175000017500000000444011572067322023715 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_VOLUME_BIAS_CORRECTION_DIALOG_H__ #define __GUI_VOLUME_BIAS_CORRECTION_DIALOG_H__ #include #include "WuQDialog.h" /// dialog for segmenting an anatomical volume using a threshold class GuiVolumeBiasCorrectionDialog : public WuQDialog { Q_OBJECT public: /// constructor GuiVolumeBiasCorrectionDialog(QWidget* parent); /// destructor ~GuiVolumeBiasCorrectionDialog(); /// called to update the dialog void updateDialog(); /// called to show the dialog (override's QDialog's show() method) void show(); public slots: /// called to close the dialog (override's QDialog's close() method) void close(); protected slots: /// called when apply button is pressed void slotApplyPushButton(); /// called when min gray value spin box value is changed void slotMinGrayValueSpinBox(int val); /// called when max white value spin box value is changed void slotMaxWhiteValueSpinBox(int val); /// called when histogram button pressed void slotHistogramPushButton(); protected: /// min gray value spin box QSpinBox* minGrayValueSpinBox; /// max white value spin box QSpinBox* maxWhiteValueSpinBox; /// iterations spin box QSpinBox* iterationsSpinBox; }; #endif // __GUI_VOLUME_BIAS_CORRECTION_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiVolumeBiasCorrectionDialog.cxx0000664000175000017500000002314211572067322024270 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include "BrainModelVolumeVoxelColoring.h" #include "BrainSet.h" #include "DisplaySettingsVolume.h" #include "FileUtilities.h" #include "GuiBrainModelOpenGL.h" #include "GuiFilesModified.h" #include "GuiHistogramDisplayDialog.h" #include "GuiMainWindow.h" #include "GuiVolumeBiasCorrectionDialog.h" #include "QtUtilities.h" #include "global_variables.h" /** * constructor. */ GuiVolumeBiasCorrectionDialog::GuiVolumeBiasCorrectionDialog(QWidget* parent) : WuQDialog(parent) { setWindowTitle("Anatomy Volume Bias Correction"); // // min gray // QLabel* minGrayLabel = new QLabel("Gray Minimum"); minGrayValueSpinBox = new QSpinBox; minGrayValueSpinBox->setMinimum(std::numeric_limits::min()); minGrayValueSpinBox->setMaximum(std::numeric_limits::max()); minGrayValueSpinBox->setSingleStep(1); QObject::connect(minGrayValueSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotMinGrayValueSpinBox(int))); minGrayValueSpinBox->setValue(0); // // max hwite // QLabel* maxWhiteLabel = new QLabel("White Maximum"); maxWhiteValueSpinBox = new QSpinBox; maxWhiteValueSpinBox->setMinimum(std::numeric_limits::min()); maxWhiteValueSpinBox->setMaximum(std::numeric_limits::max()); maxWhiteValueSpinBox->setSingleStep(1); QObject::connect(maxWhiteValueSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotMaxWhiteValueSpinBox(int))); maxWhiteValueSpinBox->setValue(255); // // iterations spin box // QLabel* iterationsLabel = new QLabel("Iterations"); iterationsSpinBox = new QSpinBox; iterationsSpinBox->setMinimum(1); iterationsSpinBox->setMaximum(10000); iterationsSpinBox->setSingleStep(1); iterationsSpinBox->setValue(5); // // Grid Layout for thesholds // QGridLayout* gridLayout = new QGridLayout; gridLayout->addWidget(minGrayLabel, 0, 0, 1, 1); gridLayout->addWidget(minGrayValueSpinBox, 0, 1, 1, 1); gridLayout->addWidget(maxWhiteLabel, 1, 0, 1, 1); gridLayout->addWidget(maxWhiteValueSpinBox, 1, 1, 1, 1); gridLayout->addWidget(iterationsLabel, 2, 0, 1, 1); gridLayout->addWidget(iterationsSpinBox, 2, 1, 1, 1); // // Histogram push button // QPushButton* histogramPushButton = new QPushButton("View Histogram..."); histogramPushButton->setAutoDefault(false); histogramPushButton->setFixedSize(histogramPushButton->sizeHint()); QObject::connect(histogramPushButton, SIGNAL(clicked()), this, SLOT(slotHistogramPushButton())); // // Instructions // const QString helpInstructions = "Set the \"Gray Minimum\" so that it is just below the smallest\n" "gray value in the volume. Set the \"White Maximum\" so it is just \n" "above the largest white value in the volume. You should see all gray\n" "and white matter voxels colored in green in the main window. Viewing\n" "the anatomy volume's histogram may be helpful.\n" "\n" "Normally, 5 iterations is sufficent. However, if the bias is\n" "significant, a value of 30 or greater may be needed."; QLabel* instructionsLabel = new QLabel(helpInstructions); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); // // Apply button // QPushButton* applyButton = new QPushButton("Apply"); buttonsLayout->addWidget(applyButton); applyButton->setAutoDefault(false); QObject::connect(applyButton, SIGNAL(clicked()), this, SLOT(slotApplyPushButton())); // // Close button // QPushButton* closeButton = new QPushButton("Close"); buttonsLayout->addWidget(closeButton); closeButton->setAutoDefault(false); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); // // Make buttons same size // QtUtilities::makeButtonsSameSize(applyButton, closeButton); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); dialogLayout->addLayout(gridLayout); dialogLayout->addWidget(histogramPushButton); dialogLayout->addWidget(instructionsLabel); dialogLayout->addLayout(buttonsLayout); } /** * destructor. */ GuiVolumeBiasCorrectionDialog::~GuiVolumeBiasCorrectionDialog() { } /** * called to update the dialog. */ void GuiVolumeBiasCorrectionDialog::updateDialog() { if (theMainWindow->getBrainSet()->getNumberOfVolumeAnatomyFiles() <= 0) { close(); } } /** * called to show the dialog (override's QDialog's show() method). */ void GuiVolumeBiasCorrectionDialog::show() { slotMinGrayValueSpinBox(minGrayValueSpinBox->value()); slotMaxWhiteValueSpinBox(maxWhiteValueSpinBox->value()); WuQDialog::show(); } /** * called to close the dialog (override's QDialog's close() method). */ void GuiVolumeBiasCorrectionDialog::close() { DisplaySettingsVolume* dsv = theMainWindow->getBrainSet()->getDisplaySettingsVolume(); dsv->setAnatomyThresholdValid(false); GuiBrainModelOpenGL::updateAllGL(); QDialog::close(); } /** * called when min spin box value is changed. */ void GuiVolumeBiasCorrectionDialog::slotMinGrayValueSpinBox(int val) { DisplaySettingsVolume* dsv = theMainWindow->getBrainSet()->getDisplaySettingsVolume(); dsv->setAnatomyThresholdValid(true); float thresh[2]; dsv->getAnatomyThreshold(thresh[0], thresh[1]); thresh[0] = val; dsv->setAnatomyThreshold(thresh[0], thresh[1]); GuiBrainModelOpenGL::updateAllGL(); } /** * called when max spin box value is changed. */ void GuiVolumeBiasCorrectionDialog::slotMaxWhiteValueSpinBox(int val) { DisplaySettingsVolume* dsv = theMainWindow->getBrainSet()->getDisplaySettingsVolume(); dsv->setAnatomyThresholdValid(true); float thresh[2]; dsv->getAnatomyThreshold(thresh[0], thresh[1]); thresh[1] = val; dsv->setAnatomyThreshold(thresh[0], thresh[1]); GuiBrainModelOpenGL::updateAllGL(); } /** * called when histogram button pressed. */ void GuiVolumeBiasCorrectionDialog::slotHistogramPushButton() { BrainModelVolume* bmv = theMainWindow->getBrainSet()->getBrainModelVolume(); if (bmv != NULL) { VolumeFile* vf = bmv->getSelectedVolumeAnatomyFile(); if (vf == NULL) { QMessageBox::critical(this, "ERROR", "No anatomy volume selected."); return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); const int numVoxels = vf->getTotalNumberOfVoxels(); std::vector values(numVoxels); float minValue = std::numeric_limits::max(); float maxValue = -std::numeric_limits::max(); for (int i = 0; i < numVoxels; i++) { values[i] = vf->getVoxelWithFlatIndex(i, 0); minValue = std::min(minValue, values[i]); maxValue = std::max(maxValue, values[i]); } GuiHistogramDisplayDialog* ghd = new GuiHistogramDisplayDialog(theMainWindow, FileUtilities::basename(vf->getFileName()), values, true, static_cast(Qt::WA_DeleteOnClose)); ghd->show(); QApplication::restoreOverrideCursor(); } } /** * called when apply button is pressed. */ void GuiVolumeBiasCorrectionDialog::slotApplyPushButton() { BrainModelVolume* bmv = theMainWindow->getBrainSet()->getBrainModelVolume(); if (bmv != NULL) { VolumeFile* vf = bmv->getSelectedVolumeAnatomyFile(); if (vf == NULL) { QMessageBox::critical(this, "ERROR", "No anatomy volume selected."); return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); try { vf->biasCorrectionWithAFNI(minGrayValueSpinBox->value(), maxWhiteValueSpinBox->value(), iterationsSpinBox->value()); } catch (FileException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); return; } DisplaySettingsVolume* dsv = theMainWindow->getBrainSet()->getDisplaySettingsVolume(); dsv->setAnatomyThresholdValid(false); GuiFilesModified fm; fm.setVolumeModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); QApplication::beep(); } } caret-5.6.4~dfsg.1.orig/caret/GuiVolumeAttributesDialog.h0000664000175000017500000001574011572067322023142 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_VOLUME_ATTRIBUTES_DIALOG_H__ #define __GUI_VOLUME_ATTRIBUTES_DIALOG_H__ #include "WuQDialog.h" class GuiVolumeFileOrientationComboBox; class QComboBox; class QLabel; class QLineEdit; class QSpinBox; class QTabWidget; class QDoubleSpinBox; class VolumeFile; /// Dialog for viewing and editing volume attributes class GuiVolumeAttributesDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiVolumeAttributesDialog(QWidget* parent, const bool modal = false, Qt::WindowFlags f = 0); /// Destructor ~GuiVolumeAttributesDialog(); /// update the dialog void updateDialog(); private slots: /// called when apply button pressed void slotApplyButton(); /// called when flip X pushbutton is selected void slotFlipXPushButton(); /// called when flip Y pushbutton is selected void slotFlipYPushButton(); /// called when a volume type is selected void slotVolumeTypeSelected(); /// called when a volume file is selected void slotVolumeFileSelected(); /// called enter ac pushbutton is pressed void slotAcPushButton(); /// called when main window crosshairs as AC pushbutton is pressed void slotMainWindowXHairPushButton(); /// called when get parameters from volume file is pressed void slotParamtersFromVolumePushButton(); /// called when rotate push button is pressed void slotRotatePushButton(); /// called when histogram button is pressed void slotHistogramButton(); /// called when rescale voxels button is pressed void slotRescaleVoxelsButton(); /// called when uniformity correction button is pressed void slotUniformityCorrection(); /// called when convert to LPI pushbutton is pressed void slotLpiPushButton(); /// called when use AC from Params File pushbutton is pressed void slotParamsAcPushButton(); /// called when use Whole Volume AC from Params File pushbutton is pressed void slotParamsWholeAcPushButton(); /// called when use Standard Space pushbutton is pressed void slotParamsStandardSpacePushButton(); /// called when Update Params File AC pushbutton is pressed void slotParamsUpdateAC(); /// called when Update Params File Whole Volume AC pushbutton is pressed void slotParamsUpdateWholeVolumeAC(); // called when align set AC X-Hairs button pressed void slotCrosshairsAlignAC(); // called when align set PC X-Hairs button pressed void slotCrosshairsAlignPC(); // called when align set LF X-Hairs button pressed void slotCrosshairsAlignLF(); private: /// get the selected volume VolumeFile* getSelectedVolume(const bool requireVolumeInMainWindow); /// create the alignment page void createAlignmentPage(); /// create the coordinates page void createCoordinatesPage(); /// create the orientation page void createOrientationPage(); /// create the resampling page void createResamplingPage(); /// create the data page void createDataPage(); /// loads the volume file combo box void loadVolumeFileComboBox(); /// loads the volume parameters void loadVolumeParameters(); /// load the resampling parameters void loadVolumeResampling(); /// Called to resample the volume. void resampleVolume(); /// the tab widget QTabWidget* tabWidget; /// the alignment page QWidget* alignmentPage; /// the coordinates widget QWidget* coordinatesPage; /// the orientation widget QWidget* orientationPage; /// the data widget QWidget* dataPage; /// dimension X label QLabel* dimensionXLabel; /// dimension Y line edit QLabel* dimensionYLabel; /// dimension Z line edit QLabel* dimensionZLabel; /// volume type combo box QComboBox* volumeTypeComboBox; /// volume file combo box QComboBox* volumeFileComboBox; /// voxel size X float spin box QDoubleSpinBox* voxelSizeXDoubleSpinBox; /// voxel size Y float spin box QDoubleSpinBox* voxelSizeYDoubleSpinBox; /// voxel size Z float spin box QDoubleSpinBox* voxelSizeZDoubleSpinBox; /// Origin X float spin box QDoubleSpinBox* originXDoubleSpinBox; /// Origin Y float spin box QDoubleSpinBox* originYDoubleSpinBox; /// Origin Z float spin box QDoubleSpinBox* originZDoubleSpinBox; /// X orientation combo box GuiVolumeFileOrientationComboBox* xOrientationComboBox; /// Y orientation combo box GuiVolumeFileOrientationComboBox* yOrientationComboBox; /// Z orientation combo box GuiVolumeFileOrientationComboBox* zOrientationComboBox; /// the resampling page QWidget* resamplingPage; /// resampling method combo box QComboBox* resamplingMethodComboBox; /// resampling float spin box QDoubleSpinBox* resamplingXDoubleSpinBox; /// resampling float spin box QDoubleSpinBox* resamplingYDoubleSpinBox; /// resampling float spin box QDoubleSpinBox* resamplingZDoubleSpinBox; /// aligment AC X QSpinBox* alignAcXSpinBox; /// aligment AC Y QSpinBox* alignAcYSpinBox; /// aligment AC Z QSpinBox* alignAcZSpinBox; /// aligment PC X QSpinBox* alignPcXSpinBox; /// aligment PC Y QSpinBox* alignPcYSpinBox; /// aligment PC Z QSpinBox* alignPcZSpinBox; /// aligment LF X QSpinBox* alignLfXSpinBox; /// aligment LF Y QSpinBox* alignLfYSpinBox; /// aligment LF Z QSpinBox* alignLfZSpinBox; }; #endif // __GUI_VOLUME_ATTRIBUTES_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiVolumeAttributesDialog.cxx0000664000175000017500000020004611572067322023510 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "WuQFileDialog.h" #include #include #include #include #include #include #include #include #include #include #include "vtkTransform.h" #include "BrainModelVolume.h" #include "BrainModelVolumeBiasCorrection.h" #include "BrainModelVolumeVoxelColoring.h" #include "BrainSet.h" #include "FileFilters.h" #include "FileUtilities.h" #include "GuiBrainModelOpenGL.h" #include "GuiFilesModified.h" #include "GuiHistogramDisplayDialog.h" #include "GuiMainWindow.h" #include "GuiToolBar.h" #include "GuiVolumeAttributesDialog.h" #include "GuiVolumeFileOrientationComboBox.h" #include "GuiVolumeRescaleDialog.h" #include "ParamsFile.h" #include #include "QtMultipleInputDialog.h" #include "QtRadioButtonSelectionDialog.h" #include "QtUtilities.h" #include "StereotaxicSpace.h" #include "VolumeFile.h" #include "global_variables.h" /** * Constructor. */ GuiVolumeAttributesDialog::GuiVolumeAttributesDialog(QWidget* parent, const bool modalFlag, Qt::WindowFlags f) : WuQDialog(parent, f) { setModal(modalFlag); setWindowTitle("Volume Attributes Editor"); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // Label and combo box for volume type // QLabel* volumeTypeLabel = new QLabel("Volume Type"); volumeTypeComboBox = new QComboBox; volumeTypeComboBox->insertItem(VolumeFile::VOLUME_TYPE_ANATOMY, "Anatomy"); volumeTypeComboBox->insertItem(VolumeFile::VOLUME_TYPE_FUNCTIONAL, "Functional"); volumeTypeComboBox->insertItem(VolumeFile::VOLUME_TYPE_PAINT, "Paint"); volumeTypeComboBox->insertItem(VolumeFile::VOLUME_TYPE_PROB_ATLAS, "Prob Atlas"); volumeTypeComboBox->insertItem(VolumeFile::VOLUME_TYPE_RGB, "RGB"); volumeTypeComboBox->insertItem(VolumeFile::VOLUME_TYPE_SEGMENTATION, "Segmentation"); volumeTypeComboBox->insertItem(VolumeFile::VOLUME_TYPE_VECTOR, "Vector"); QObject::connect(volumeTypeComboBox, SIGNAL(activated(int)), this, SLOT(slotVolumeTypeSelected())); volumeTypeComboBox->setToolTip( "Use this control to select the\n" "type of volume for editing."); // // Label and combo box for volume file selection // QLabel* volumeFileLabel = new QLabel("Volume File"); volumeFileComboBox = new QComboBox; QObject::connect(volumeFileComboBox, SIGNAL(activated(int)), this, SLOT(slotVolumeFileSelected())); volumeFileComboBox->setToolTip( "Use this control to select a volume file."); // // Group box and layout for volume selection // QGroupBox* volumeGroupBox = new QGroupBox("Volume Selection"); dialogLayout->addWidget(volumeGroupBox); QGridLayout* volumeGroupLayout = new QGridLayout(volumeGroupBox); volumeGroupLayout->addWidget(volumeTypeLabel, 0, 0); volumeGroupLayout->addWidget(volumeTypeComboBox, 0, 1); volumeGroupLayout->addWidget(volumeFileLabel, 1, 0); volumeGroupLayout->addWidget(volumeFileComboBox, 1, 1); // // Create the tab widget // tabWidget = new QTabWidget; // // create the alignment page // createAlignmentPage(); // // create the coordinates page // createCoordinatesPage(); // // create the orientation page // createOrientationPage(); // // create the resampling page // createResamplingPage(); // // create the data page // createDataPage(); // // Group box and layout for tab widget // QGroupBox* tabGroupBox = new QGroupBox("Volume Attributes"); QVBoxLayout* tabGroupLayout = new QVBoxLayout(tabGroupBox); tabGroupLayout->addWidget(tabWidget); dialogLayout->addWidget(tabGroupBox); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); dialogLayout->addLayout(buttonsLayout); // // Apply button // QPushButton* applyButton = new QPushButton("Apply"); applyButton->setAutoDefault(false); buttonsLayout->addWidget(applyButton); QObject::connect(applyButton, SIGNAL(clicked()), this, SLOT(slotApplyButton())); // // Close button // QPushButton* closeButton = new QPushButton("Close"); closeButton->setAutoDefault(false); buttonsLayout->addWidget(closeButton); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); QtUtilities::makeButtonsSameSize(applyButton, closeButton); tabWidget->setCurrentWidget(coordinatesPage); updateDialog(); } /** * Destructor. */ GuiVolumeAttributesDialog::~GuiVolumeAttributesDialog() { } /** * create the alignment page. */ void GuiVolumeAttributesDialog::createAlignmentPage() { // // colum labels // QLabel* structureLabel = new QLabel("Structure"); QLabel* xLabel = new QLabel("X"); QLabel* yLabel = new QLabel("Y"); QLabel* zLabel = new QLabel("Z"); // // AC spin boxes // QLabel* acLabel = new QLabel("Anterior Commissure"); alignAcXSpinBox = new QSpinBox; alignAcXSpinBox->setMinimum(0); alignAcXSpinBox->setMaximum(1000000); alignAcXSpinBox->setSingleStep(1); alignAcYSpinBox = new QSpinBox; alignAcYSpinBox->setMinimum(0); alignAcYSpinBox->setMaximum(1000000); alignAcYSpinBox->setSingleStep(1); alignAcZSpinBox = new QSpinBox; alignAcZSpinBox->setMinimum(0); alignAcZSpinBox->setMaximum(1000000); alignAcZSpinBox->setSingleStep(1); QPushButton* acPushButton = new QPushButton("Use Crosshairs"); acPushButton->setAutoDefault(false); QObject::connect(acPushButton, SIGNAL(clicked()), this, SLOT(slotCrosshairsAlignAC())); // // PC spin boxes // QLabel* pcLabel = new QLabel("Posterior Commissure"); alignPcXSpinBox = new QSpinBox; alignPcXSpinBox->setMinimum(0); alignPcXSpinBox->setMaximum(1000000); alignPcXSpinBox->setSingleStep(1); alignPcYSpinBox = new QSpinBox; alignPcYSpinBox->setMinimum(0); alignPcYSpinBox->setMaximum(1000000); alignPcYSpinBox->setSingleStep(1); alignPcZSpinBox = new QSpinBox; alignPcZSpinBox->setMinimum(0); alignPcZSpinBox->setMaximum(1000000); alignPcZSpinBox->setSingleStep(1); QPushButton* pcPushButton = new QPushButton("Use Crosshairs"); pcPushButton->setAutoDefault(false); QObject::connect(pcPushButton, SIGNAL(clicked()), this, SLOT(slotCrosshairsAlignPC())); // // CC spin boxes // QLabel* lfLabel = new QLabel("Longitudinal Fissure"); alignLfXSpinBox = new QSpinBox; alignLfXSpinBox->setMinimum(0); alignLfXSpinBox->setMaximum(1000000); alignLfXSpinBox->setSingleStep(1); alignLfYSpinBox = new QSpinBox; alignLfYSpinBox->setMinimum(0); alignLfYSpinBox->setMaximum(1000000); alignLfYSpinBox->setSingleStep(1); alignLfZSpinBox = new QSpinBox; alignLfZSpinBox->setMinimum(0); alignLfZSpinBox->setMaximum(1000000); alignLfZSpinBox->setSingleStep(1); QPushButton* lfPushButton = new QPushButton("Use Crosshairs"); lfPushButton->setAutoDefault(false); QObject::connect(lfPushButton, SIGNAL(clicked()), this, SLOT(slotCrosshairsAlignLF())); // // Instructions // const QString instructions = "Place the crosshairs over the Anterior Commissure and press\n" "the \"Use Crosshairs\" button.\n" "\n" "Place the crosshairs over the Posterior Commissure and press \n" "the \"Use Crosshairs\" button.\n" "\n" "Place the crosshairs over a voxel in the superior region of the \n" "longitudinal fissure and press the \"Use Crosshairs\" button.\n" "\n" "Press the \"Apply\" button to AC-PC align the volume."; QLabel* instructionsLabel = new QLabel(instructions); // // Arrange the grid widgets // // // Child of page // QWidget* alignWidget = new QWidget; alignWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); QGridLayout* alignGrid = new QGridLayout(alignWidget); alignGrid->setMargin(3); alignGrid->setSpacing(3); alignGrid->addWidget(structureLabel, 0, 0, Qt::AlignHCenter); alignGrid->addWidget(xLabel, 0, 1, Qt::AlignHCenter); alignGrid->addWidget(yLabel, 0, 2, Qt::AlignHCenter); alignGrid->addWidget(zLabel, 0, 3, Qt::AlignHCenter); alignGrid->addWidget(acLabel, 1, 0); alignGrid->addWidget(alignAcXSpinBox, 1, 1); alignGrid->addWidget(alignAcYSpinBox, 1, 2); alignGrid->addWidget(alignAcZSpinBox, 1, 3); alignGrid->addWidget(acPushButton, 1, 4); alignGrid->addWidget(pcLabel, 2, 0); alignGrid->addWidget(alignPcXSpinBox, 2, 1); alignGrid->addWidget(alignPcYSpinBox, 2, 2); alignGrid->addWidget(alignPcZSpinBox, 2, 3); alignGrid->addWidget(pcPushButton, 2, 4); alignGrid->addWidget(lfLabel, 3, 0); alignGrid->addWidget(alignLfXSpinBox, 3, 1); alignGrid->addWidget(alignLfYSpinBox, 3, 2); alignGrid->addWidget(alignLfZSpinBox, 3, 3); alignGrid->addWidget(lfPushButton, 3, 4); alignGrid->addWidget(instructionsLabel, 4, 0, 1, 5); // // widget and layout for page // // // Create the alignment page // alignmentPage = new QWidget; tabWidget->addTab(alignmentPage, "AC-PC Align"); QVBoxLayout* pageLayout = new QVBoxLayout(alignmentPage); pageLayout->setSpacing(3); pageLayout->addWidget(alignWidget); } /** * called when align set AC X-Hairs button pressed. */ void GuiVolumeAttributesDialog::slotCrosshairsAlignAC() { BrainModelVolume* bmv = theMainWindow->getBrainModelVolume(); if (bmv == NULL) { QMessageBox::critical(this, "ERROR", "There is no volume in the Main Window."); return; } int slices[3]; bmv->getSelectedOrthogonalSlices(0, slices); alignAcXSpinBox->setValue(slices[0]); alignAcYSpinBox->setValue(slices[1]); alignAcZSpinBox->setValue(slices[2]); } /** * called when align set PC X-Hairs button pressed. */ void GuiVolumeAttributesDialog::slotCrosshairsAlignPC() { BrainModelVolume* bmv = theMainWindow->getBrainModelVolume(); if (bmv == NULL) { QMessageBox::critical(this, "ERROR", "There is no volume in the Main Window."); return; } int slices[3]; bmv->getSelectedOrthogonalSlices(0, slices); alignPcXSpinBox->setValue(slices[0]); alignPcYSpinBox->setValue(slices[1]); alignPcZSpinBox->setValue(slices[2]); } /** * called when align set LF X-Hairs button pressed. */ void GuiVolumeAttributesDialog::slotCrosshairsAlignLF() { BrainModelVolume* bmv = theMainWindow->getBrainModelVolume(); if (bmv == NULL) { QMessageBox::critical(this, "ERROR", "There is no volume in the Main Window."); return; } int slices[3]; bmv->getSelectedOrthogonalSlices(0, slices); alignLfXSpinBox->setValue(slices[0]); alignLfYSpinBox->setValue(slices[1]); alignLfZSpinBox->setValue(slices[2]); } /** * Create the data page. */ void GuiVolumeAttributesDialog::createDataPage() { // // Histogram button // QPushButton* histogramButton = new QPushButton("Show Histogram..."); histogramButton->setFixedSize(histogramButton->sizeHint()); histogramButton->setAutoDefault(false); QObject::connect(histogramButton, SIGNAL(clicked()), this, SLOT(slotHistogramButton())); histogramButton->setToolTip( "Pressing this button will display a\n" "histogram for the selected volume."); // // Rescale Voxels button // QPushButton* rescaleButton = new QPushButton("Rescale Voxels Values..."); rescaleButton->setFixedSize(rescaleButton->sizeHint()); rescaleButton->setAutoDefault(false); QObject::connect(rescaleButton, SIGNAL(clicked()), this, SLOT(slotRescaleVoxelsButton())); rescaleButton->setToolTip( "Pressing this button will display a\n" "dialog for rescaling the selected \n" "volume's voxels."); QPushButton* uniformityButton = NULL; #ifdef HAVE_ITK // // uniformity correction button // uniformityButton = new QPushButton("Non-Uniformity Correction..."); uniformityButton->setFixedSize(uniformityButton->sizeHint()); uniformityButton->setAutoDefault(false); QObject::connect(uniformityButton, SIGNAL(clicked()), this, SLOT(slotUniformityCorrection())); uniformityButton->setToolTip( "Pressing this button will perform\n" "corrections for non-uniformity of \n" "the volume's voxels."); #endif // HAVE_ITK // // Create the data page // dataPage = new QWidget; QVBoxLayout* dataPageLayout = new QVBoxLayout(dataPage); dataPageLayout->addWidget(histogramButton); dataPageLayout->addWidget(rescaleButton); if (uniformityButton != NULL) { dataPageLayout->addWidget(uniformityButton); } dataPageLayout->addStretch(); tabWidget->addTab(dataPage, "Data"); } /** * called when uniformity correction button is pressed. */ void GuiVolumeAttributesDialog::slotUniformityCorrection() { VolumeFile* vf = getSelectedVolume(false); if (vf != NULL) { try { //vf->uniformityCorrection(); std::vector labels, values; labels.push_back("Gray Min "); values.push_back("80"); labels.push_back("Gray Max "); values.push_back("125"); labels.push_back("White Min "); values.push_back("140"); labels.push_back("White Max "); values.push_back("190"); labels.push_back("Threshold - Low "); values.push_back("30"); labels.push_back("Threshold - High "); values.push_back("255"); labels.push_back("Iterations - X "); values.push_back("25"); labels.push_back("Iterations - Y "); values.push_back("25"); labels.push_back("Iterations - Z "); values.push_back("25"); QtMultipleInputDialog mid(this, "Enter Parameters", "Enter min/max gray and white matter values.\n" "Enter lower and upper thresholds.\n" "Enter Iterations for each slice axis.", labels, values, true, true); if (mid.exec() == QDialog::Accepted) { QTime timer; timer.start(); QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); std::vector floatValues; mid.getValues(floatValues); std::vector intValues; mid.getValues(intValues); const float grayWhite[4] = { floatValues[0], floatValues[1], floatValues[2], floatValues[3] }; const float thresholds[2] = { floatValues[4], floatValues[5] }; const int iterations[3] = { intValues[6], intValues[7], intValues[8] }; BrainModelVolumeBiasCorrection biasCorrector(vf, grayWhite, thresholds, iterations); biasCorrector.execute(); const float elapsedTime = (static_cast(timer.elapsed()) * 0.001) / 60.0; std::ostringstream str; str << "Uniformity Correction Time: " << elapsedTime << " minutes."; QApplication::restoreOverrideCursor(); QMessageBox::information(this, "INFO", str.str().c_str()); beep(); GuiBrainModelOpenGL::updateAllGL(); } } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); } catch (FileException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); } } } /** * called when rescale voxels button is pressed. */ void GuiVolumeAttributesDialog::slotRescaleVoxelsButton() { VolumeFile* vf = getSelectedVolume(true); if (vf != NULL) { GuiVolumeRescaleDialog vrd(this, "", vf); vrd.exec(); } } /** * Called when histogram button is pressed. */ void GuiVolumeAttributesDialog::slotHistogramButton() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); VolumeFile* vf = getSelectedVolume(true); if (vf != NULL) { const int numVoxels = vf->getTotalNumberOfVoxels(); std::vector values(numVoxels); float minValue = std::numeric_limits::max(); float maxValue = -std::numeric_limits::max(); for (int i = 0; i < numVoxels; i++) { values[i] = vf->getVoxelWithFlatIndex(i, 0); minValue = std::min(minValue, values[i]); maxValue = std::max(maxValue, values[i]); } bool showPeaksFlag = (static_cast(volumeTypeComboBox->currentIndex()) == VolumeFile::VOLUME_TYPE_ANATOMY); GuiHistogramDisplayDialog* ghd = new GuiHistogramDisplayDialog(this, FileUtilities::basename(vf->getFileName()), values, showPeaksFlag, static_cast(Qt::WA_DeleteOnClose)); ghd->show(); } QApplication::restoreOverrideCursor(); } /** * Create the orientation page. */ void GuiVolumeAttributesDialog::createResamplingPage() { // // Resampling method // QLabel* resamplingMethodLabel = new QLabel("Interpolation Method"); resamplingMethodComboBox = new QComboBox; resamplingMethodComboBox->addItem("Cubic (Best Quality)", static_cast(VolumeFile::INTERPOLATION_TYPE_CUBIC)); resamplingMethodComboBox->addItem("Linear", static_cast(VolumeFile::INTERPOLATION_TYPE_LINEAR)); resamplingMethodComboBox->addItem("Nearest Neighbor (use for Paint and Atlas)", static_cast(VolumeFile::INTERPOLATION_TYPE_NEAREST_NEIGHBOR)); QHBoxLayout* resamplingLayout = new QHBoxLayout; resamplingLayout->addWidget(resamplingMethodLabel); resamplingLayout->addWidget(resamplingMethodComboBox); resamplingLayout->addStretch(); // // spin boxes for resampling // QLabel* voxelSizeLabel = new QLabel("Voxel Size "); resamplingXDoubleSpinBox = new QDoubleSpinBox; resamplingXDoubleSpinBox->setMinimum(-10000.0); resamplingXDoubleSpinBox->setMaximum(10000.0); resamplingXDoubleSpinBox->setSingleStep(1.0); resamplingXDoubleSpinBox->setDecimals(3); resamplingYDoubleSpinBox = new QDoubleSpinBox; resamplingYDoubleSpinBox->setMinimum(-10000.0); resamplingYDoubleSpinBox->setMaximum(10000.0); resamplingYDoubleSpinBox->setSingleStep(1.0); resamplingYDoubleSpinBox->setDecimals(3); resamplingZDoubleSpinBox = new QDoubleSpinBox; resamplingZDoubleSpinBox->setMinimum(-10000.0); resamplingZDoubleSpinBox->setMaximum(10000.0); resamplingZDoubleSpinBox->setSingleStep(1.0); resamplingZDoubleSpinBox->setDecimals(3); QHBoxLayout* resampleLayout = new QHBoxLayout; resampleLayout->addWidget(voxelSizeLabel); resampleLayout->addWidget(resamplingXDoubleSpinBox); resampleLayout->addWidget(resamplingYDoubleSpinBox); resampleLayout->addWidget(resamplingZDoubleSpinBox); resampleLayout->addStretch(); // // Create the resampling page // resamplingPage = new QWidget; QVBoxLayout* resamplePageLayout = new QVBoxLayout(resamplingPage); resamplePageLayout->addLayout(resampleLayout); resamplePageLayout->addLayout(resamplingLayout); resamplePageLayout->addStretch(); tabWidget->addTab(resamplingPage, "Resample"); } /** * load the resampling parameters. */ void GuiVolumeAttributesDialog::loadVolumeResampling() { VolumeFile* vf = getSelectedVolume(false); if (vf != NULL) { float spacing[3]; vf->getSpacing(spacing); resamplingXDoubleSpinBox->setValue(spacing[0]); resamplingYDoubleSpinBox->setValue(spacing[1]); resamplingZDoubleSpinBox->setValue(spacing[2]); } } /** * Called to resample the volume. */ void GuiVolumeAttributesDialog::resampleVolume() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); VolumeFile* vf = getSelectedVolume(false); if (vf != NULL) { float volSpace[3]; vf->getSpacing(volSpace); if ((volSpace[0] <= 0.0) || (volSpace[1] <= 0.0) || (volSpace[2] <= 0.0)) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", "The volume's X, Y, and Z voxel sizes (set using the Coordinates tab)\n" "must all be positive for resampling to function correctly."); return; } const float spacing[3] = { resamplingXDoubleSpinBox->value(), resamplingYDoubleSpinBox->value(), resamplingZDoubleSpinBox->value() }; if ((spacing[0] <= 0.0) || (spacing[1] <= 0.0) || (spacing[2] <= 0.0)) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", "The volume's X, Y, and Z resampling voxel sizes must\n" "all be positive for resampling to function correctly."); return; } const int methodIndex = resamplingMethodComboBox->currentIndex(); const VolumeFile::INTERPOLATION_TYPE interpolationType = static_cast( resamplingMethodComboBox->itemData(methodIndex).toInt()); vf->resampleToSpacing(spacing, interpolationType); loadVolumeParameters(); loadVolumeResampling(); } GuiBrainModelOpenGL::updateAllGL(); GuiToolBar::updateAllToolBars(false); QApplication::restoreOverrideCursor(); } /** * Create the orientation page. */ void GuiVolumeAttributesDialog::createOrientationPage() { // // Orientation combo boxes // xOrientationComboBox = new GuiVolumeFileOrientationComboBox(0, VolumeFile::VOLUME_AXIS_X); QObject::connect(xOrientationComboBox, SIGNAL(activated(int)), this, SLOT(slotApplyButton())); xOrientationComboBox->setToolTip( "Use this control to set the orientation of the\n" "volume in its X-Axis. Note that Caret always\n" "draws volume assuming they are in LPI orientation."); yOrientationComboBox = new GuiVolumeFileOrientationComboBox(0, VolumeFile::VOLUME_AXIS_Y); QObject::connect(yOrientationComboBox, SIGNAL(activated(int)), this, SLOT(slotApplyButton())); yOrientationComboBox->setToolTip( "Use this control to set the orientation of the\n" "volume in its Y-Axis. Note that Caret always\n" "draws volume assuming they are in LPI orientation."); zOrientationComboBox = new GuiVolumeFileOrientationComboBox(0, VolumeFile::VOLUME_AXIS_Z); QObject::connect(zOrientationComboBox, SIGNAL(activated(int)), this, SLOT(slotApplyButton())); zOrientationComboBox->setToolTip( "Use this control to set the orientation of the\n" "volume in its Z-Axis. Note that Caret always\n" "draws volume assuming they are in LPI orientation."); QHBoxLayout* orientationLayout = new QHBoxLayout; orientationLayout->setSpacing(5); orientationLayout->addWidget(xOrientationComboBox); orientationLayout->addWidget(yOrientationComboBox); orientationLayout->addWidget(zOrientationComboBox); // // convert to LPI button // QPushButton* lpiPushButton = new QPushButton("Convert to LPI Orientation"); lpiPushButton->setAutoDefault(false); lpiPushButton->setFixedSize(lpiPushButton->sizeHint()); QObject::connect(lpiPushButton, SIGNAL(clicked()), this, SLOT(slotLpiPushButton())); lpiPushButton->setToolTip( "Pressing this button will perform operations to place\n" "the volume into LPI orientation using the current orientation\n" "as show in the combo boxes above."); // // Flip X, Y, Z push buttons // QPushButton* flipXPushButton = new QPushButton("Flip About X Screen Axis"); flipXPushButton->setAutoDefault(false); QObject::connect(flipXPushButton, SIGNAL(clicked()), this, SLOT(slotFlipXPushButton())); flipXPushButton->setToolTip( "Flips the volume about the SCREEN X-AXIS so that\n" "the top and bottom parts of the volume are flipped."); QPushButton* flipYPushButton = new QPushButton("Flip About Y Screen Axis"); flipYPushButton->setAutoDefault(false); QObject::connect(flipYPushButton, SIGNAL(clicked()), this, SLOT(slotFlipYPushButton())); flipYPushButton->setToolTip( "Flips the volume about the SCREEN Y-AXIS so that\n" "the right and left parts of the volume are flipped."); QHBoxLayout* flipLayout = new QHBoxLayout; flipLayout->setSpacing(5); flipLayout->addWidget(flipXPushButton); flipLayout->addWidget(flipYPushButton); flipLayout->addStretch(); // // Rotate volume button // QPushButton* rotatePushButton = new QPushButton("Rotate Clockwise"); rotatePushButton->setAutoDefault(false); rotatePushButton->setFixedSize(rotatePushButton->sizeHint()); QObject::connect(rotatePushButton, SIGNAL(clicked()), this, SLOT(slotRotatePushButton())); rotatePushButton->setToolTip( "Rotates the volume clockwise so that the\n" "right side of the volume is shown at the\n" "bottom of the screen."); const QString lpiMessage = "NOTE: If the origin and voxel sizes are not properly set (on the \n" "Coordinates tab) the \"Convert to LPI Orientation\" operation will \n" "not operate correctly."; QLabel* lpiLabel = new QLabel(lpiMessage); // // Create the orientation page // orientationPage = new QWidget; QVBoxLayout* orientationPageLayout = new QVBoxLayout(orientationPage); orientationPageLayout->addLayout(orientationLayout); orientationPageLayout->addWidget(lpiPushButton); orientationPageLayout->addLayout(flipLayout); orientationPageLayout->addWidget(rotatePushButton); orientationPageLayout->addWidget(lpiLabel); orientationPageLayout->addStretch(); tabWidget->addTab(orientationPage, "Orientation"); } /** * Create the coordinates page. */ void GuiVolumeAttributesDialog::createCoordinatesPage() { // // Column titles // QLabel* xLabel = new QLabel("X"); QLabel* yLabel = new QLabel("Y"); QLabel* zLabel = new QLabel("Z"); // // Dimensions // QLabel* dimensionsLabel = new QLabel("Dimensions"); dimensionXLabel = new QLabel(" "); dimensionYLabel = new QLabel(" "); dimensionZLabel = new QLabel(" "); // // Voxel size // QLabel* voxelSizeLabel = new QLabel("Voxel Size"); voxelSizeXDoubleSpinBox = new QDoubleSpinBox; voxelSizeXDoubleSpinBox->setMinimum(-5000.0); voxelSizeXDoubleSpinBox->setMaximum(5000.0); voxelSizeXDoubleSpinBox->setSingleStep(0.5); voxelSizeXDoubleSpinBox->setDecimals(3); voxelSizeYDoubleSpinBox = new QDoubleSpinBox; voxelSizeYDoubleSpinBox->setMinimum(-5000.0); voxelSizeYDoubleSpinBox->setMaximum(5000.0); voxelSizeYDoubleSpinBox->setSingleStep(0.5); voxelSizeYDoubleSpinBox->setDecimals(3); voxelSizeZDoubleSpinBox = new QDoubleSpinBox; voxelSizeZDoubleSpinBox->setMinimum(-5000.0); voxelSizeZDoubleSpinBox->setMaximum(5000.0); voxelSizeZDoubleSpinBox->setSingleStep(0.5); voxelSizeZDoubleSpinBox->setDecimals(3); // // origin // QLabel* originLabel = new QLabel("Origin at Center\nof First Voxel"); originXDoubleSpinBox = new QDoubleSpinBox; originXDoubleSpinBox->setMinimum(-5000.0); originXDoubleSpinBox->setMaximum(5000.0); originXDoubleSpinBox->setSingleStep(0.5); originXDoubleSpinBox->setDecimals(3); originYDoubleSpinBox = new QDoubleSpinBox; originYDoubleSpinBox->setMinimum(-5000.0); originYDoubleSpinBox->setMaximum(5000.0); originYDoubleSpinBox->setSingleStep(0.5); originYDoubleSpinBox->setDecimals(3); originZDoubleSpinBox = new QDoubleSpinBox; originZDoubleSpinBox->setMinimum(-5000.0); originZDoubleSpinBox->setMaximum(5000.0); originZDoubleSpinBox->setSingleStep(0.5); originZDoubleSpinBox->setDecimals(3); originXDoubleSpinBox->setValue(0.0); originYDoubleSpinBox->setValue(0.0); originZDoubleSpinBox->setValue(0.0); // // Layout for parameters // QGridLayout* parametersLayout = new QGridLayout; parametersLayout->addWidget(xLabel, 0, 1); parametersLayout->addWidget(yLabel, 0, 2); parametersLayout->addWidget(zLabel, 0, 3); parametersLayout->addWidget(dimensionsLabel, 1, 0); parametersLayout->addWidget(dimensionXLabel, 1, 1); parametersLayout->addWidget(dimensionYLabel, 1, 2); parametersLayout->addWidget(dimensionZLabel, 1, 3); parametersLayout->addWidget(voxelSizeLabel, 2, 0); parametersLayout->addWidget(voxelSizeXDoubleSpinBox, 2, 1); parametersLayout->addWidget(voxelSizeYDoubleSpinBox, 2, 2); parametersLayout->addWidget(voxelSizeZDoubleSpinBox, 2, 3); parametersLayout->addWidget(originLabel, 3, 0); parametersLayout->addWidget(originXDoubleSpinBox, 3, 1); parametersLayout->addWidget(originYDoubleSpinBox, 3, 2); parametersLayout->addWidget(originZDoubleSpinBox, 3, 3); // // Use main window crosshairs as AC // QPushButton* mwXHairPushButton = new QPushButton( "Use Main Window Crosshairs as AC Location"); mwXHairPushButton->setAutoDefault(false); QObject::connect(mwXHairPushButton, SIGNAL(clicked()), this, SLOT(slotMainWindowXHairPushButton())); mwXHairPushButton->setToolTip("This button will use the main window\n" "crosshairs as the Anterior Commissure\n" "location. The Anterior Commissure\n" "position and the voxel sizes will be\n" "used to determine the volume origin."); // // Enter AC button // QPushButton* acPushButton = new QPushButton("Enter AC Voxel..."); acPushButton->setAutoDefault(false); QObject::connect(acPushButton, SIGNAL(clicked()), this, SLOT(slotAcPushButton())); acPushButton->setToolTip("This button displays a dialog for entry of the \n" "Anterior Commissure voxel indices. These voxel\n" "indices will be used with the voxel size in the\n" "dialog to determine the volume origin."); // // Get AC from params file // QPushButton* paramsAcPushButton = new QPushButton("Use AC From Params File"); paramsAcPushButton->setAutoDefault(false); QObject::connect(paramsAcPushButton, SIGNAL(clicked()), this, SLOT(slotParamsAcPushButton())); paramsAcPushButton->setToolTip("Press this button will use the Anterior\n" "Commissure position stored in the params\n" "file to determine the volume's origin."); // // Get AC from params file // QPushButton* paramsWholeAcPushButton = new QPushButton("Use Whole Volume AC From Params File"); paramsWholeAcPushButton->setAutoDefault(false); QObject::connect(paramsWholeAcPushButton, SIGNAL(clicked()), this, SLOT(slotParamsWholeAcPushButton())); paramsWholeAcPushButton->setToolTip("Press this button will use the Whole \n" "Anterior Commissure position stored in the \n" "params file to determine the volume's origin."); // // Get parameters from a volume file // QPushButton* paramtersFromVolumePushButton = new QPushButton("Get Parameters From Volume File..."); paramtersFromVolumePushButton->setAutoDefault(false); QObject::connect(paramtersFromVolumePushButton, SIGNAL(clicked()), this, SLOT(slotParamtersFromVolumePushButton())); paramtersFromVolumePushButton->setToolTip( "This button displays a dialog for selecting a volume\n" "file. The volume's spacing and origin will be\n" "placed into the dialog."); // // Get parameters from a standard space // QPushButton* standardSpacePushButton = new QPushButton("Use Standard Stereotaxic Space..."); standardSpacePushButton->setAutoDefault(false); QObject::connect(standardSpacePushButton, SIGNAL(clicked()), this, SLOT(slotParamsStandardSpacePushButton())); standardSpacePushButton->setToolTip( "This button displays a dialog for selecting a standard\n" "space that will be used for setting the origin and spacing.\n" "Only standard spaces having dimensions matching those\n" "shown in the dialog will be listed for selection."); std::vector pbs; pbs.push_back(mwXHairPushButton); pbs.push_back(acPushButton); pbs.push_back(paramsAcPushButton); pbs.push_back(paramsWholeAcPushButton); pbs.push_back(paramtersFromVolumePushButton); pbs.push_back(standardSpacePushButton); QtUtilities::makeButtonsSameSize(pbs); // // Group box and layoutfor setting origin // QGroupBox* setOriginGroupBox = new QGroupBox("Set Origin"); QVBoxLayout* setOriginGroupLayout = new QVBoxLayout(setOriginGroupBox); setOriginGroupLayout->addWidget(mwXHairPushButton); setOriginGroupLayout->addWidget(acPushButton); setOriginGroupLayout->addWidget(paramsAcPushButton); setOriginGroupLayout->addWidget(paramsWholeAcPushButton); setOriginGroupLayout->addWidget(paramtersFromVolumePushButton); setOriginGroupLayout->addWidget(standardSpacePushButton); // // Use main window crosshairs as AC // QPushButton* paramsACPushButton = new QPushButton("Update AC"); paramsACPushButton->setAutoDefault(false); QObject::connect(paramsACPushButton, SIGNAL(clicked()), this, SLOT(slotParamsUpdateAC())); paramsACPushButton->setToolTip("This button will use the current dimensions,\n" "origin, and voxel sizes to set the parameter\n" "files's ACx, ACy, and ACz parameters."); // // Use main window crosshairs as AC // QPushButton* paramsWholeACPushButton = new QPushButton("Update Whole Volume AC"); paramsWholeACPushButton->setAutoDefault(false); QObject::connect(paramsWholeACPushButton, SIGNAL(clicked()), this, SLOT(slotParamsUpdateWholeVolumeAC())); paramsWholeACPushButton->setToolTip("This button will use the current dimensions,\n" "origin, and voxel sizes to set the parameter\n" "files's ACx_WholeVolume, ACy_WholeVolume, and\n" "ACz_WholeVolume parameters."); QtUtilities::makeButtonsSameSize(paramsACPushButton, paramsWholeACPushButton); // // Group box and layout for updating params file // QGroupBox* paramsGroupBox = new QGroupBox("Update Parameters File"); QVBoxLayout* paramsGroupLayout = new QVBoxLayout(paramsGroupBox); paramsGroupLayout->addWidget(paramsACPushButton); paramsGroupLayout->addWidget(paramsWholeACPushButton); paramsGroupLayout->addStretch(); // // Horizontal layout for settings origin and update params file // QHBoxLayout* originParamsHBoxLayout = new QHBoxLayout; originParamsHBoxLayout->addWidget(setOriginGroupBox); originParamsHBoxLayout->addWidget(paramsGroupBox); // // Create the coordinates page // coordinatesPage = new QWidget; QVBoxLayout* coordinatesLayout = new QVBoxLayout(coordinatesPage); coordinatesLayout->addLayout(parametersLayout); coordinatesLayout->addLayout(originParamsHBoxLayout); coordinatesLayout->addStretch(); tabWidget->addTab(coordinatesPage, "Coordinates"); } /** * called when Update Params File AC pushbutton is pressed. */ void GuiVolumeAttributesDialog::slotParamsUpdateAC() { const float origin[3] = { originXDoubleSpinBox->value(), originYDoubleSpinBox->value(), originZDoubleSpinBox->value(), }; const float voxelSize[3] = { voxelSizeXDoubleSpinBox->value(), voxelSizeYDoubleSpinBox->value(), voxelSizeZDoubleSpinBox->value(), }; int ac[3]; for (int i = 0; i < 3; i++) { if (voxelSize[i] == 0.0) { QMessageBox::critical(this, "ERROR", "All voxel sizes must be non-zero."); return; } ac[i] = -static_cast(origin[i] / voxelSize[i]); } ParamsFile* pf = theMainWindow->getBrainSet()->getParamsFile(); pf->setParameter(ParamsFile::keyACx, ac[0]); pf->setParameter(ParamsFile::keyACy, ac[1]); pf->setParameter(ParamsFile::keyACz, ac[2]); try { theMainWindow->getBrainSet()->writeParamsFile(pf->getFileName()); } catch (FileException& e) { QString msg("Unable to write parameters file: "); msg.append(e.whatQString()); QMessageBox::critical(this, "ERROR", msg); } GuiFilesModified fm; fm.setParameterModified(); theMainWindow->fileModificationUpdate(fm); } /** * called when Update Params File Whole Volume AC pushbutton is pressed. */ void GuiVolumeAttributesDialog::slotParamsUpdateWholeVolumeAC() { const float origin[3] = { originXDoubleSpinBox->value(), originYDoubleSpinBox->value(), originZDoubleSpinBox->value(), }; const float voxelSize[3] = { voxelSizeXDoubleSpinBox->value(), voxelSizeYDoubleSpinBox->value(), voxelSizeZDoubleSpinBox->value(), }; int ac[3]; for (int i = 0; i < 3; i++) { if (voxelSize[i] == 0.0) { QMessageBox::critical(this, "ERROR", "All voxel sizes must be non-zero."); return; } ac[i] = -static_cast(origin[i] / voxelSize[i]); } ParamsFile* pf = theMainWindow->getBrainSet()->getParamsFile(); pf->setParameter(ParamsFile::keyWholeVolumeACx, ac[0]); pf->setParameter(ParamsFile::keyWholeVolumeACy, ac[1]); pf->setParameter(ParamsFile::keyWholeVolumeACz, ac[2]); try { theMainWindow->getBrainSet()->writeParamsFile(pf->getFileName()); } catch (FileException& e) { QString msg("Unable to write parameters file: "); msg.append(e.whatQString()); QMessageBox::critical(this, "ERROR", msg); } GuiFilesModified fm; fm.setParameterModified(); theMainWindow->fileModificationUpdate(fm); } /** * called when use Standard Space pushbutton is pressed. */ void GuiVolumeAttributesDialog::slotParamsStandardSpacePushButton() { const int volDim[3] = { dimensionXLabel->text().toInt(), dimensionYLabel->text().toInt(), dimensionZLabel->text().toInt(), }; std::vector allSpaces; StereotaxicSpace::getAllStereotaxicSpaces(allSpaces); std::vector matchingSpaces; std::vector matchingSpaceNames; for (unsigned int i = 0; i < allSpaces.size(); i++) { int dim[3]; allSpaces[i].getDimensions(dim); if ((volDim[0] == dim[0]) && (volDim[1] == dim[1]) && (volDim[2] == dim[2])) { matchingSpaces.push_back(allSpaces[i]); float spacing[3]; allSpaces[i].getVoxelSize(spacing); std::ostringstream str; str << "Space: " << allSpaces[i].getName().toAscii().constData() << " voxel size: (" << spacing[0] << ", " << spacing[1] << ", " << spacing[2] << ")"; matchingSpaceNames.push_back(str.str().c_str()); } } if (matchingSpaces.empty()) { QMessageBox::critical(this, "ERROR", "No standard spaces have matching volume dimensions."); return; } QtRadioButtonSelectionDialog rbsd(this, "Choose Standard Space", "Choose Standard Space", matchingSpaceNames, 0); if (rbsd.exec() == QDialog::Accepted) { const int indx = rbsd.getSelectedItemIndex(); if ((indx >= 0) && (indx < static_cast(matchingSpaces.size()))) { float origin[3]; float spacing[3]; matchingSpaces[indx].getOrigin(origin); matchingSpaces[indx].getVoxelSize(spacing); voxelSizeXDoubleSpinBox->setValue(spacing[0]); voxelSizeYDoubleSpinBox->setValue(spacing[1]); voxelSizeZDoubleSpinBox->setValue(spacing[2]); originXDoubleSpinBox->setValue(origin[0]); originYDoubleSpinBox->setValue(origin[1]); originZDoubleSpinBox->setValue(origin[2]); } } } /** * called when main window crosshairs as AC pushbutton is pressed. */ void GuiVolumeAttributesDialog::slotMainWindowXHairPushButton() { BrainModelVolume* bmv = theMainWindow->getBrainModelVolume(); if (bmv == NULL) { QMessageBox::critical(this, "ERROR", "There is no volume in the Main Window."); return; } int acSlices[3]; bmv->getSelectedOrthogonalSlices(0, acSlices); const float voxelSize[3] = { voxelSizeXDoubleSpinBox->value(), voxelSizeYDoubleSpinBox->value(), voxelSizeZDoubleSpinBox->value(), }; float origin[3] = { -(acSlices[0] * voxelSize[0]), -(acSlices[1] * voxelSize[1]), -(acSlices[2] * voxelSize[2]) }; originXDoubleSpinBox->setValue(origin[0]); originYDoubleSpinBox->setValue(origin[1]); originZDoubleSpinBox->setValue(origin[2]); } /** * Called when Use AC from Params File pushbutton pressed. */ void GuiVolumeAttributesDialog::slotParamsAcPushButton() { ParamsFile* pf = theMainWindow->getBrainSet()->getParamsFile(); float x, y, z; if (pf->empty()) { QMessageBox::critical(this, "ERROR", "No parameters are loaded."); } else if (pf->getParameter(ParamsFile::keyACx, x) && pf->getParameter(ParamsFile::keyACy, y) && pf->getParameter(ParamsFile::keyACz, z)) { const float voxelSize[3] = { voxelSizeXDoubleSpinBox->value(), voxelSizeYDoubleSpinBox->value(), voxelSizeZDoubleSpinBox->value(), }; float origin[3] = { -(x * voxelSize[0]), -(y * voxelSize[1]), -(z * voxelSize[2]) }; originXDoubleSpinBox->setValue(origin[0]); originYDoubleSpinBox->setValue(origin[1]); originZDoubleSpinBox->setValue(origin[2]); } else { QMessageBox::critical(this, "ERROR", "AC not found in params file", "OK"); } } /** * Called when Use AC from Params File pushbutton pressed. */ void GuiVolumeAttributesDialog::slotParamsWholeAcPushButton() { ParamsFile* pf = theMainWindow->getBrainSet()->getParamsFile(); float x, y, z; if (pf->empty()) { QMessageBox::critical(this, "ERROR", "No parameters are loaded."); } else if (pf->getParameter(ParamsFile::keyWholeVolumeACx, x) && pf->getParameter(ParamsFile::keyWholeVolumeACy, y) && pf->getParameter(ParamsFile::keyWholeVolumeACz, z)) { const float voxelSize[3] = { voxelSizeXDoubleSpinBox->value(), voxelSizeYDoubleSpinBox->value(), voxelSizeZDoubleSpinBox->value(), }; float origin[3] = { -(x * voxelSize[0]), -(y * voxelSize[1]), -(z * voxelSize[2]) }; originXDoubleSpinBox->setValue(origin[0]); originYDoubleSpinBox->setValue(origin[1]); originZDoubleSpinBox->setValue(origin[2]); } else { QMessageBox::critical(this, "ERROR", "AC not found in params file"); } } /** * Called when convert to LPI pushbutton is pressed. */ void GuiVolumeAttributesDialog::slotLpiPushButton() { VolumeFile* vf = getSelectedVolume(true); if (vf != NULL) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); VolumeFile::ORIENTATION lpiOrientation[3] = { VolumeFile::ORIENTATION_LEFT_TO_RIGHT, VolumeFile::ORIENTATION_POSTERIOR_TO_ANTERIOR, VolumeFile::ORIENTATION_INFERIOR_TO_SUPERIOR }; try { vf->permuteToOrientation(lpiOrientation); } catch (FileException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); return; } GuiBrainModelOpenGL::updateAllGL(); loadVolumeParameters(); loadVolumeResampling(); QApplication::restoreOverrideCursor(); } } /** * called when rotate push button is pressed. */ void GuiVolumeAttributesDialog::slotRotatePushButton() { bool volumeInMainWindow = false; VolumeFile* vf = getSelectedVolume(true); if (vf != NULL) { BrainModelVolume* bmv = theMainWindow->getBrainModelVolume(); if (bmv != NULL) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); volumeInMainWindow = true; switch (bmv->getSelectedAxis(0)) { case VolumeFile::VOLUME_AXIS_X: vf->rotate(VolumeFile::VOLUME_AXIS_X); break; case VolumeFile::VOLUME_AXIS_Y: vf->rotate(VolumeFile::VOLUME_AXIS_Y); break; case VolumeFile::VOLUME_AXIS_Z: vf->rotate(VolumeFile::VOLUME_AXIS_Z); break; case VolumeFile::VOLUME_AXIS_ALL: case VolumeFile::VOLUME_AXIS_OBLIQUE: case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } GuiBrainModelOpenGL::updateAllGL(); loadVolumeParameters(); loadVolumeResampling(); QApplication::restoreOverrideCursor(); const QString msg = "After rotating a volume, an axis may appear upside down in one or more\n" "views. This is a result of an origin having a component with a positive\n" "value and its corresponding voxel size being negative after rotation. \n" "Flipping the signs of these two items will correct the problem.\n" "Note that Caret is designed to display and operate on volumes in an LPI\n" "(Left=neg-X, Posterior=neg-Y, Inferior=neg-Z) orientation."; QApplication::restoreOverrideCursor(); QMessageBox::information(this, "INFO", msg); } } } /** * called enter ac pushbutton is pressed. */ void GuiVolumeAttributesDialog::slotAcPushButton() { std::vector labels; labels.push_back("AC X Voxel Index "); labels.push_back("AC Y Voxel Index "); labels.push_back("AC Z Voxel Index "); std::vector values; values.push_back("0"); values.push_back("0"); values.push_back("0"); // // Popup a dialog to get the AC position // QtMultipleInputDialog mid(this, "Enter Anterior Commissure Voxel Indices", "", labels, values, true, true); if (mid.exec() == QDialog::Accepted) { std::vector acxyz(3); mid.getValues(acxyz); const float voxelSize[3] = { voxelSizeXDoubleSpinBox->value(), voxelSizeYDoubleSpinBox->value(), voxelSizeZDoubleSpinBox->value(), }; float origin[3] = { -(acxyz[0] * voxelSize[0]), -(acxyz[1] * voxelSize[1]), -(acxyz[2] * voxelSize[2]) }; originXDoubleSpinBox->setValue(origin[0]); originYDoubleSpinBox->setValue(origin[1]); originZDoubleSpinBox->setValue(origin[2]); } } /** * called when get parameters from volume file is pressed. */ void GuiVolumeAttributesDialog::slotParamtersFromVolumePushButton() { // // Create a spec file dialog to select the spec file. // WuQFileDialog openVolumeFileDialog(this); openVolumeFileDialog.setModal(true); openVolumeFileDialog.setAcceptMode(WuQFileDialog::AcceptOpen); openVolumeFileDialog.setDirectory(QDir::currentPath()); openVolumeFileDialog.setWindowTitle("Choose Volume File"); openVolumeFileDialog.setFileMode(WuQFileDialog::ExistingFile); openVolumeFileDialog.setFilter(FileFilters::getVolumeGenericFileFilter()); if (openVolumeFileDialog.exec() == QDialog::Accepted) { const QString vname(openVolumeFileDialog.selectedFiles().at(0)); if (vname.isEmpty() == false) { VolumeFile vf; try { vf.readFile(vname); /* const VolumeFile::ORIENTATION lpiOrientation[3] = { VolumeFile::ORIENTATION_LEFT_TO_RIGHT, VolumeFile::ORIENTATION_POSTERIOR_TO_ANTERIOR, VolumeFile::ORIENTATION_INFERIOR_TO_SUPERIOR }; vf.permuteToOrientation(lpiOrientation); */ float origin[3]; float spacing[3]; vf.getOrigin(origin); vf.getSpacing(spacing); originXDoubleSpinBox->setValue(origin[0]); originYDoubleSpinBox->setValue(origin[1]); originZDoubleSpinBox->setValue(origin[2]); voxelSizeXDoubleSpinBox->setValue(spacing[0]); voxelSizeYDoubleSpinBox->setValue(spacing[1]); voxelSizeZDoubleSpinBox->setValue(spacing[2]); } catch (FileException& e) { QMessageBox::critical(this, "Error Reading Volume", e.whatQString()); } } } } /** * Called when flip X push button is pressed. */ void GuiVolumeAttributesDialog::slotFlipXPushButton() { bool volumeInMainWindow = false; VolumeFile* vf = getSelectedVolume(true); if (vf != NULL) { BrainModelVolume* bmv = theMainWindow->getBrainModelVolume(); if (bmv != NULL) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); switch (bmv->getSelectedAxis(0)) { case VolumeFile::VOLUME_AXIS_X: vf->flip(VolumeFile::VOLUME_AXIS_Z, false); break; case VolumeFile::VOLUME_AXIS_Y: vf->flip(VolumeFile::VOLUME_AXIS_Z, false); break; case VolumeFile::VOLUME_AXIS_Z: vf->flip(VolumeFile::VOLUME_AXIS_Y, false); break; case VolumeFile::VOLUME_AXIS_ALL: case VolumeFile::VOLUME_AXIS_OBLIQUE: case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } GuiBrainModelOpenGL::updateAllGL(); loadVolumeParameters(); loadVolumeResampling(); QApplication::restoreOverrideCursor(); volumeInMainWindow = true; } } } /** * Called when flip Y push button is pressed. */ void GuiVolumeAttributesDialog::slotFlipYPushButton() { bool volumeInMainWindow = false; VolumeFile* vf = getSelectedVolume(true); if (vf != NULL) { BrainModelVolume* bmv = theMainWindow->getBrainModelVolume(); if (bmv != NULL) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); switch (bmv->getSelectedAxis(0)) { case VolumeFile::VOLUME_AXIS_X: vf->flip(VolumeFile::VOLUME_AXIS_Y, false); break; case VolumeFile::VOLUME_AXIS_Y: vf->flip(VolumeFile::VOLUME_AXIS_X, false); break; case VolumeFile::VOLUME_AXIS_Z: vf->flip(VolumeFile::VOLUME_AXIS_X, false); break; case VolumeFile::VOLUME_AXIS_ALL: case VolumeFile::VOLUME_AXIS_OBLIQUE: case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } GuiBrainModelOpenGL::updateAllGL(); loadVolumeParameters(); loadVolumeResampling(); QApplication::restoreOverrideCursor(); volumeInMainWindow = true; } } if (volumeInMainWindow = false) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", "The selected volume must be displayed in\n" "the main window to use this operation."); } } /** * Called when apply button is pressed. */ void GuiVolumeAttributesDialog::slotApplyButton() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); VolumeFile* vf = getSelectedVolume(true); if (vf != NULL) { if (tabWidget->currentWidget() == alignmentPage) { const int ac[3] = { alignAcXSpinBox->value(), alignAcYSpinBox->value(), alignAcZSpinBox->value() }; const int pc[3] = { alignPcXSpinBox->value(), alignPcYSpinBox->value(), alignPcZSpinBox->value() }; const int lf[3] = { alignLfXSpinBox->value(), alignLfYSpinBox->value(), alignLfZSpinBox->value() }; vf->acPcAlign(ac, pc, lf); GuiToolBar* toolbar = theMainWindow->getToolBar(); if (toolbar != NULL) { toolbar->setViewSelection(BrainModel::VIEW_RESET); } GuiBrainModelOpenGL::updateAllGL(); } else if (tabWidget->currentWidget() == coordinatesPage) { float origin[3] = { originXDoubleSpinBox->value(), originYDoubleSpinBox->value(), originZDoubleSpinBox->value() }; float spacing[3] = { voxelSizeXDoubleSpinBox->value(), voxelSizeYDoubleSpinBox->value(), voxelSizeZDoubleSpinBox->value() }; vf->setOrigin(origin); vf->setSpacing(spacing); GuiBrainModelOpenGL::updateAllGL(); } else if (tabWidget->currentWidget() == orientationPage) { VolumeFile::ORIENTATION orientation[3]; vf->getOrientation(orientation); bool changeMade = false; if (orientation[0] != xOrientationComboBox->getOrientation()) { orientation[0] = xOrientationComboBox->getOrientation(); changeMade = true; } if (orientation[1] != yOrientationComboBox->getOrientation()) { orientation[1] = yOrientationComboBox->getOrientation(); changeMade = true; } if (orientation[2] != zOrientationComboBox->getOrientation()) { orientation[2] = zOrientationComboBox->getOrientation(); changeMade = true; } if (changeMade) { vf->setOrientation(orientation); } } else if (tabWidget->currentWidget() == resamplingPage) { resampleVolume(); } else if (tabWidget->currentWidget() == dataPage) { /* to be done later */ } loadVolumeParameters(); loadVolumeResampling(); } QApplication::restoreOverrideCursor(); } /** * Called when a volume file is selected */ void GuiVolumeAttributesDialog::slotVolumeFileSelected() { loadVolumeParameters(); loadVolumeResampling(); } /** * Called when a volume type is selected */ void GuiVolumeAttributesDialog::slotVolumeTypeSelected() { loadVolumeFileComboBox(); loadVolumeParameters(); loadVolumeResampling(); } /** * Get the selected volume. */ VolumeFile* GuiVolumeAttributesDialog::getSelectedVolume(const bool requireVolumeInMainWindow) { VolumeFile* vf = NULL; const int fileIndex = volumeFileComboBox->currentIndex(); switch(static_cast(volumeTypeComboBox->currentIndex())) { case VolumeFile::VOLUME_TYPE_ANATOMY: vf = theMainWindow->getBrainSet()->getVolumeAnatomyFile(fileIndex); break; case VolumeFile::VOLUME_TYPE_FUNCTIONAL: vf = theMainWindow->getBrainSet()->getVolumeFunctionalFile(fileIndex); break; case VolumeFile::VOLUME_TYPE_PAINT: vf = theMainWindow->getBrainSet()->getVolumePaintFile(fileIndex); break; case VolumeFile::VOLUME_TYPE_PROB_ATLAS: vf = theMainWindow->getBrainSet()->getVolumeProbAtlasFile(fileIndex); break; case VolumeFile::VOLUME_TYPE_RGB: vf = theMainWindow->getBrainSet()->getVolumeRgbFile(fileIndex); break; case VolumeFile::VOLUME_TYPE_ROI: break; case VolumeFile::VOLUME_TYPE_SEGMENTATION: vf = theMainWindow->getBrainSet()->getVolumeSegmentationFile(fileIndex); break; case VolumeFile::VOLUME_TYPE_VECTOR: vf = theMainWindow->getBrainSet()->getVolumeVectorFile(fileIndex); break; case VolumeFile::VOLUME_TYPE_UNKNOWN: break; } if (requireVolumeInMainWindow && (vf != NULL)) { bool inMainWindowFlag = false; BrainModelVolume* bmv = theMainWindow->getBrainModelVolume(); if (bmv != NULL) { if ((vf == bmv->getUnderlayVolumeFile()) || (vf == bmv->getOverlayPrimaryVolumeFile()) || (vf == bmv->getOverlaySecondaryVolumeFile())) { inMainWindowFlag = true; } } if (inMainWindowFlag == false) { if (QMessageBox::question(this, "ERROR", "The selected volume is not displayed in the main window.\n" "Do you want to continue applying your changes?", (QMessageBox::Yes | QMessageBox::No), QMessageBox::No) == QMessageBox::No) { vf = NULL; } } } return vf; } /** * Load the volume parameters. */ void GuiVolumeAttributesDialog::loadVolumeParameters() { VolumeFile* vf = getSelectedVolume(false); if (vf != NULL) { int dim[3]; vf->getDimensions(dim); dimensionXLabel->setText(QString::number(dim[0])); dimensionYLabel->setText(QString::number(dim[1])); dimensionZLabel->setText(QString::number(dim[2])); float spacing[3]; vf->getSpacing(spacing); voxelSizeXDoubleSpinBox->setValue(spacing[0]); voxelSizeYDoubleSpinBox->setValue(spacing[1]); voxelSizeZDoubleSpinBox->setValue(spacing[2]); float origin[3]; vf->getOrigin(origin); originXDoubleSpinBox->setValue(origin[0]); originYDoubleSpinBox->setValue(origin[1]); originZDoubleSpinBox->setValue(origin[2]); VolumeFile::ORIENTATION orientation[3]; vf->getOrientation(orientation); xOrientationComboBox->setOrientation(orientation[0]); yOrientationComboBox->setOrientation(orientation[1]); zOrientationComboBox->setOrientation(orientation[2]); } } /** * load the volume file combo box */ void GuiVolumeAttributesDialog::loadVolumeFileComboBox() { const int currentItem = volumeFileComboBox->currentIndex(); volumeFileComboBox->clear(); switch(static_cast(volumeTypeComboBox->currentIndex())) { case VolumeFile::VOLUME_TYPE_ANATOMY: for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfVolumeAnatomyFiles(); i++) { volumeFileComboBox->addItem( theMainWindow->getBrainSet()->getVolumeAnatomyFile(i)->getDescriptiveLabel()); } break; case VolumeFile::VOLUME_TYPE_FUNCTIONAL: for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfVolumeFunctionalFiles(); i++) { volumeFileComboBox->addItem( theMainWindow->getBrainSet()->getVolumeFunctionalFile(i)->getDescriptiveLabel()); } break; case VolumeFile::VOLUME_TYPE_PAINT: for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfVolumePaintFiles(); i++) { volumeFileComboBox->addItem( theMainWindow->getBrainSet()->getVolumePaintFile(i)->getDescriptiveLabel()); } break; case VolumeFile::VOLUME_TYPE_PROB_ATLAS: for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfVolumeProbAtlasFiles(); i++) { volumeFileComboBox->addItem( theMainWindow->getBrainSet()->getVolumeProbAtlasFile(i)->getDescriptiveLabel()); } break; case VolumeFile::VOLUME_TYPE_RGB: for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfVolumeRgbFiles(); i++) { volumeFileComboBox->addItem( theMainWindow->getBrainSet()->getVolumeRgbFile(i)->getDescriptiveLabel()); } break; case VolumeFile::VOLUME_TYPE_ROI: break; case VolumeFile::VOLUME_TYPE_SEGMENTATION: for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfVolumeSegmentationFiles(); i++) { volumeFileComboBox->addItem( theMainWindow->getBrainSet()->getVolumeSegmentationFile(i)->getDescriptiveLabel()); } break; case VolumeFile::VOLUME_TYPE_VECTOR: for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfVolumeVectorFiles(); i++) { volumeFileComboBox->addItem( theMainWindow->getBrainSet()->getVolumeVectorFile(i)->getDescriptiveLabel()); } break; case VolumeFile::VOLUME_TYPE_UNKNOWN: break; } if ((currentItem >= 0) && (currentItem < volumeFileComboBox->count())) { volumeFileComboBox->setCurrentIndex(currentItem); } } /** * Called to update the dialog. */ void GuiVolumeAttributesDialog::updateDialog() { loadVolumeFileComboBox(); loadVolumeParameters(); loadVolumeResampling(); } caret-5.6.4~dfsg.1.orig/caret/GuiVocabularyFileEditorDialog.h0000664000175000017500000000734511572067322023704 0ustar michaelmichael #ifndef __GUI_VOCABULARY_FILE_EDITOR_DIALOG_H__ #define __GUI_VOCABULARY_FILE_EDITOR_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "WuQDialog.h" class GuiStudyInfoEditorWidget; class QComboBox; class QLineEdit; class QRadioButton; class QSpinBox; class QTabWidget; class QTextEdit; class WuQWidgetGroup; /// dialog for editing a vocabulary file class GuiVocabularyFileEditorDialog : public WuQDialog { Q_OBJECT public: // constructor GuiVocabularyFileEditorDialog(QWidget* parent); // destructor ~GuiVocabularyFileEditorDialog(); // update the dialog void updateDialog(); protected slots: // called when apply button pressed void slotApplyButton(); // called when abbreviation button pressed void slotAbbreviationPushButton(); // called when delete button pressed void slotDeleteEntryPushButton(); // called when Add or Edit radio button selected void slotEntryModeChanged(); // called to load a vocabulary entry void slotLoadVocabularyEntry(int indx); // update the study number combo box void slotUpdateStudyNumberComboBox(); // called when vocab study meta data button pressed void slotVocabularStudyMetaDataPushButton(); // called when ontology source push button pressed void slotOntologySourcePushButton(); protected: // create the vocabulary widget QWidget* createVocabularyWidget(); // update edit spin box min/max void updateEditEntrySpinBoxMinMax(); /// the tab widget QTabWidget* tabWidget; /// the vocabulary widget QWidget* vocabularyWidget; /// the study info widget GuiStudyInfoEditorWidget* studyInfoEditorWidget; /// abbreviation line edit QLineEdit* abbreviationLineEdit; /// full name line edit QLineEdit* fullNameLineEdit; /// class name line edit QLineEdit* classNameLineEdit; /// vocabulary ID line edit QLineEdit* vocabularyIdLineEdit; /// study meta data line edit QLineEdit* vocabularyStudyMetaDataLineEdit; /// ontology source line edit QLineEdit* ontologySourceLineEdit; /// term id line edit QLineEdit* termIDLineEdit; /// study number combo box QComboBox* studyNumberComboBox; /// description line edit QTextEdit* descriptionTextEdit; /// add entry radio button QRadioButton* entryAddRadioButton; /// edit entry radio button QRadioButton* entryEditRadioButton; /// editing number spin box QSpinBox* entryEditSpinBox; /// widget group for edit spin box and delete button WuQWidgetGroup* entryEditWidgetGroup; }; #endif // __GUI_VOCABULARY_FILE_EDITOR_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiVocabularyFileEditorDialog.cxx0000664000175000017500000004304711572067322024256 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "BrainSet.h" #include "GuiMainWindow.h" #include "GuiNameSelectionDialog.h" #include "GuiStudyInfoEditorWidget.h" #include "GuiStudyMetaDataLinkCreationDialog.h" #include "GuiVocabularyFileEditorDialog.h" #include "QtListBoxSelectionDialog.h" #include "WuQWidgetGroup.h" #include "VocabularyFile.h" #include "global_variables.h" static const QString noneStudyName("None"); /** * constructor. */ GuiVocabularyFileEditorDialog::GuiVocabularyFileEditorDialog(QWidget* parent) : WuQDialog(parent) { setWindowTitle("Vocabulary Editor"); // // Create the vocabulary entry widget // vocabularyWidget = createVocabularyWidget(); // // Create the study info editor widget // VocabularyFile* vf = theMainWindow->getBrainSet()->getVocabularyFile(); studyInfoEditorWidget = new GuiStudyInfoEditorWidget(vf->getPointerToStudyInfo()); studyInfoEditorWidget->hideStereotaxicSpaceControls(true); // // Create the tab widget // tabWidget = new QTabWidget; tabWidget->addTab(vocabularyWidget, "Vocabulary"); tabWidget->addTab(studyInfoEditorWidget, "Studies"); // // get the layout for the dialog // QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(tabWidget); // // Dialog buttons // QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Apply | QDialogButtonBox::Close); layout->addWidget(buttonBox); QPushButton* applyButton = buttonBox->button(QDialogButtonBox::Apply); QObject::connect(applyButton, SIGNAL(clicked()), this, SLOT(slotApplyButton())); QObject::connect(buttonBox, SIGNAL(rejected()), this, SLOT(close())); // // Initialize // entryAddRadioButton->setChecked(true); updateDialog(); } /** * destructor. */ GuiVocabularyFileEditorDialog::~GuiVocabularyFileEditorDialog() { } /** * create the vocabulary widget. */ QWidget* GuiVocabularyFileEditorDialog::createVocabularyWidget() { // // Add and edit radio buttons radio button // entryAddRadioButton = new QRadioButton("Add"); entryEditRadioButton = new QRadioButton("Edit"); // // Button group to keep add/edit buttons mutually exclusive // QButtonGroup* entryButtonGroup = new QButtonGroup(this); QObject::connect(entryButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotEntryModeChanged())); entryButtonGroup->addButton(entryAddRadioButton, 0); entryButtonGroup->addButton(entryEditRadioButton, 1); // // Edit spin box // entryEditSpinBox = new QSpinBox; entryEditSpinBox->setSingleStep(1); QObject::connect(entryEditSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotLoadVocabularyEntry(int))); // // delete push button // QPushButton* deleteEntryPushButton = new QPushButton("Delete"); deleteEntryPushButton->setFixedSize(deleteEntryPushButton->sizeHint()); deleteEntryPushButton->setAutoDefault(false); QObject::connect(deleteEntryPushButton, SIGNAL(clicked()), this, SLOT(slotDeleteEntryPushButton())); // // Widget group for edit spin box and delete button // entryEditWidgetGroup = new WuQWidgetGroup(this); entryEditWidgetGroup->addWidget(entryEditSpinBox); entryEditWidgetGroup->addWidget(deleteEntryPushButton); // // Group box and layout for entry mode // QGroupBox* entryModeGroupBox = new QGroupBox("Entry Mode"); QGridLayout* entryModeGridLayout = new QGridLayout(entryModeGroupBox); entryModeGridLayout->addWidget(entryAddRadioButton, 0, 0); entryModeGridLayout->addWidget(entryEditRadioButton, 1, 0); entryModeGridLayout->addWidget(entryEditSpinBox, 1, 1); entryModeGridLayout->addWidget(deleteEntryPushButton, 1, 2); entryModeGridLayout->setColumnStretch(0, 0); entryModeGridLayout->setColumnStretch(1, 0); entryModeGridLayout->setColumnStretch(2, 0); entryModeGridLayout->setColumnStretch(3, 100); // // pushbutton and line edit for abbreviation // QPushButton* abbreviationPushButton = new QPushButton("Abbreviation..."); abbreviationPushButton->setAutoDefault(false); QObject::connect(abbreviationPushButton, SIGNAL(clicked()), this, SLOT(slotAbbreviationPushButton())); abbreviationLineEdit = new QLineEdit; // // Label and line edit for full name // QLabel* fullNameLabel = new QLabel("Full Name"); fullNameLineEdit = new QLineEdit; // // Label and line edit for class name // QLabel* classNameLabel = new QLabel("Class Name"); classNameLineEdit = new QLineEdit; // // Label and line edit for vocabulary // QLabel* vocabularyIdLabel = new QLabel("Vocabulary ID"); vocabularyIdLineEdit = new QLineEdit; // // Push Button and line edit for ontology source // QPushButton* ontologySourcePushButton = new QPushButton("Ontology Source..."); ontologySourcePushButton->setAutoDefault(false); ontologySourcePushButton->setFixedSize(ontologySourcePushButton->sizeHint()); QObject::connect(ontologySourcePushButton, SIGNAL(clicked()), this, SLOT(slotOntologySourcePushButton())); ontologySourceLineEdit = new QLineEdit; // // Label and line edit for Term ID // QLabel* termIDLabel = new QLabel("Term ID"); termIDLineEdit = new QLineEdit; // // Label and line edit for study number // QLabel* studyNumberLabel = new QLabel("Study in Vocab File"); studyNumberComboBox = new QComboBox; // // Label and line edit for study meta data // QPushButton* vocabularyStudyMetaDataPushButton = new QPushButton("Study Metadata..."); vocabularyStudyMetaDataPushButton->setAutoDefault(false); QObject::connect(vocabularyStudyMetaDataPushButton, SIGNAL(clicked()), this, SLOT(slotVocabularStudyMetaDataPushButton())); vocabularyStudyMetaDataLineEdit = new QLineEdit; // // Label and text edit for description // QLabel* descriptionLabel = new QLabel("Description"); descriptionTextEdit = new QTextEdit; // // Group Box and Layout for vocabulary data // QGroupBox* dataGroupBox = new QGroupBox("Data"); QGridLayout* dataGridLayout = new QGridLayout(dataGroupBox); dataGridLayout->addWidget(abbreviationPushButton, 0, 0); dataGridLayout->addWidget(abbreviationLineEdit, 0, 1); dataGridLayout->addWidget(fullNameLabel, 1, 0); dataGridLayout->addWidget(fullNameLineEdit, 1, 1); dataGridLayout->addWidget(classNameLabel, 2, 0); dataGridLayout->addWidget(classNameLineEdit, 2, 1); dataGridLayout->addWidget(vocabularyIdLabel, 3, 0); dataGridLayout->addWidget(vocabularyIdLineEdit, 3, 1); dataGridLayout->addWidget(ontologySourcePushButton, 4, 0); dataGridLayout->addWidget(ontologySourceLineEdit, 4, 1); dataGridLayout->addWidget(termIDLabel, 5, 0); dataGridLayout->addWidget(termIDLineEdit, 5, 1); dataGridLayout->addWidget(studyNumberLabel, 6, 0); dataGridLayout->addWidget(studyNumberComboBox, 6, 1); dataGridLayout->addWidget(vocabularyStudyMetaDataPushButton, 7, 0); dataGridLayout->addWidget(vocabularyStudyMetaDataLineEdit, 7, 1); dataGridLayout->addWidget(descriptionLabel, 8, 0); dataGridLayout->addWidget(descriptionTextEdit, 8, 1); // // widget and layout // QWidget* w = new QWidget; QVBoxLayout* l = new QVBoxLayout(w); l->addWidget(entryModeGroupBox); l->addWidget(dataGroupBox); return w; } /** * called when ontology source push button pressed. */ void GuiVocabularyFileEditorDialog::slotOntologySourcePushButton() { std::vector names; VocabularyFile::VocabularyEntry::getOntologySourceValues(names); QtListBoxSelectionDialog lbsd(this, "Ontology Sources", "", names); if (lbsd.exec() == QtListBoxSelectionDialog::Accepted) { ontologySourceLineEdit->setText(lbsd.getSelectedText()); } } /** * called when study meta data button pressed. */ void GuiVocabularyFileEditorDialog::slotVocabularStudyMetaDataPushButton() { GuiStudyMetaDataLinkCreationDialog smdlcd(this); StudyMetaDataLinkSet smdls; smdls.setLinkSetFromCodedText(vocabularyStudyMetaDataLineEdit->text()); smdlcd.initializeSelectedLinkSet(smdls); if (smdlcd.exec() == GuiStudyMetaDataLinkCreationDialog::Accepted) { vocabularyStudyMetaDataLineEdit->setText(smdlcd.getLinkSetCreated().getLinkSetAsCodedText()); vocabularyStudyMetaDataLineEdit->home(false); } } /** * called when apply button pressed. */ void GuiVocabularyFileEditorDialog::slotApplyButton() { if (tabWidget->currentWidget() == vocabularyWidget) { const QString& abbreviation = abbreviationLineEdit->text(); if (abbreviation.isEmpty()) { QMessageBox::critical(this, "ERROR", "Abbreviation is empty."); return; } // // Get the vocabulary file // VocabularyFile* vf = theMainWindow->getBrainSet()->getVocabularyFile(); // // Add button checked ? // if (entryAddRadioButton->isChecked()) { // // Add a new vocabulary entry and update the edit spin box to new entry // VocabularyFile::VocabularyEntry temp(abbreviation); vf->addVocabularyEntry(temp); updateEditEntrySpinBoxMinMax(); entryEditSpinBox->blockSignals(true); entryEditSpinBox->setValue(vf->getNumberOfVocabularyEntries() - 1); entryEditSpinBox->blockSignals(false); } // // Edit button checked // else if (entryEditRadioButton->isChecked()) { // do nothing } else { std::cout << "PROGRAM ERROR in GuiVocabularyFileEditorDialog::slotApplyButton()" << std::endl; return; } const int indx = entryEditSpinBox->value(); if ((indx < 0) || (indx >= vf->getNumberOfVocabularyEntries())) { QMessageBox::critical(this, "ERROR", "Invalid editing number selection."); return; } StudyMetaDataLinkSet smdls; smdls.setLinkSetFromCodedText(vocabularyStudyMetaDataLineEdit->text()); // // Get the currently selected item and set its parameters // VocabularyFile::VocabularyEntry* ve = vf->getVocabularyEntry(indx); ve->setAbbreviation(abbreviation); ve->setFullName(fullNameLineEdit->text()); ve->setClassName(classNameLineEdit->text()); ve->setVocabularyID(vocabularyIdLineEdit->text()); ve->setOntologySource(ontologySourceLineEdit->text()); ve->setTermID(termIDLineEdit->text()); ve->setStudyMetaDataLinkSet(smdls); int studyNum = studyNumberComboBox->currentIndex(); if (studyNumberComboBox->currentText() == noneStudyName) { studyNum = -1; } else if (studyNum >= vf->getNumberOfStudyInfo()) { studyNum = -1; } ve->setStudyNumber(studyNum); ve->setDescription(descriptionTextEdit->toPlainText()); } else if (tabWidget->currentWidget() == studyInfoEditorWidget) { studyInfoEditorWidget->slotAcceptEditorContents(); slotUpdateStudyNumberComboBox(); } } /** * called to load a vocabulary entry. */ void GuiVocabularyFileEditorDialog::slotLoadVocabularyEntry(int indx) { // // Get the vocabulary file // VocabularyFile* vf = theMainWindow->getBrainSet()->getVocabularyFile(); // // Get the currently selected item and get its parameters // if ((indx >= 0) && (indx < vf->getNumberOfVocabularyEntries())) { VocabularyFile::VocabularyEntry* ve = vf->getVocabularyEntry(indx); abbreviationLineEdit->setText(ve->getAbbreviation()); fullNameLineEdit->setText(ve->getFullName()); classNameLineEdit->setText(ve->getClassName()); vocabularyIdLineEdit->setText(ve->getVocabularyID()); ontologySourceLineEdit->setText(ve->getOntologySource()); termIDLineEdit->setText(ve->getTermID()); int studyNum = ve->getStudyNumber(); if ((studyNum < 0) || (studyNum >= vf->getNumberOfStudyInfo())) { studyNum = vf->getNumberOfStudyInfo(); } studyNumberComboBox->setCurrentIndex(studyNum); descriptionTextEdit->setText(ve->getDescription()); vocabularyStudyMetaDataLineEdit->setText(ve->getStudyMetaDataLinkSet().getLinkSetAsCodedText()); vocabularyStudyMetaDataLineEdit->home(false); } } /** * called when Add or Edit radio button selected. */ void GuiVocabularyFileEditorDialog::slotEntryModeChanged() { VocabularyFile* vf = theMainWindow->getBrainSet()->getVocabularyFile(); // // If no entries, switch to add mode // if (vf->getNumberOfVocabularyEntries() == 0) { entryAddRadioButton->blockSignals(true); entryEditRadioButton->blockSignals(true); entryAddRadioButton->setChecked(true); entryEditRadioButton->setChecked(false); entryAddRadioButton->blockSignals(false); entryEditRadioButton->blockSignals(false); } // // Disable editing controls if "Add" mode // entryEditWidgetGroup->setDisabled(entryAddRadioButton->isChecked()); // // If switched to editing, update edit number spin box // if (entryEditRadioButton->isChecked()) { int indx = entryEditSpinBox->value(); if ((indx < 0) || (indx >= vf->getNumberOfVocabularyEntries())) { indx = 0; } slotLoadVocabularyEntry(indx); } } /** * called when delete entry button pressed. */ void GuiVocabularyFileEditorDialog::slotDeleteEntryPushButton() { if (QMessageBox::question(this, "Confirm", "Are you sure you want to delete the current vocabulary entry?", (QMessageBox::Yes | QMessageBox::No), QMessageBox::Yes) == QMessageBox::Yes) { if (entryEditRadioButton->isChecked()) { int indx = entryEditSpinBox->value(); VocabularyFile* vf = theMainWindow->getBrainSet()->getVocabularyFile(); if ((indx >= 0) && (indx < vf->getNumberOfVocabularyEntries())) { vf->deleteVocabularyEntry(indx); } updateEditEntrySpinBoxMinMax(); slotEntryModeChanged(); } } } /** * called when abbreviation button pressed. */ void GuiVocabularyFileEditorDialog::slotAbbreviationPushButton() { GuiNameSelectionDialog nsd(this, GuiNameSelectionDialog::LIST_ALL); if (nsd.exec() == QDialog::Accepted) { QString name(nsd.getNameSelected()); if (name.isEmpty() == false) { abbreviationLineEdit->setText(name); } } } /** * update edit spin box min/max. */ void GuiVocabularyFileEditorDialog::updateEditEntrySpinBoxMinMax() { VocabularyFile* vf = theMainWindow->getBrainSet()->getVocabularyFile(); entryEditSpinBox->setMinimum(0); const int maxNum = std::max(0, vf->getNumberOfVocabularyEntries() - 1); entryEditSpinBox->setMaximum(maxNum); } /** * update the dialog. */ void GuiVocabularyFileEditorDialog::updateDialog() { updateEditEntrySpinBoxMinMax(); slotEntryModeChanged(); VocabularyFile* vf = theMainWindow->getBrainSet()->getVocabularyFile(); studyInfoEditorWidget->updateWidget(vf->getPointerToStudyInfo()); slotUpdateStudyNumberComboBox(); } /** * update the study number combo box. */ void GuiVocabularyFileEditorDialog::slotUpdateStudyNumberComboBox() { const bool noneFlag = (studyNumberComboBox->currentText() == noneStudyName); const int oldIndx = studyNumberComboBox->currentIndex(); studyNumberComboBox->clear(); VocabularyFile* vf = theMainWindow->getBrainSet()->getVocabularyFile(); const int numStudys = vf->getNumberOfStudyInfo(); for (int i = 0; i < numStudys; i++) { const CellStudyInfo* csi = vf->getStudyInfo(i); QString s(csi->getTitle()); if (s.length() > 30) { s.resize(30); } QString qs(QString::number(i)); qs.append(" - "); qs.append(s); studyNumberComboBox->addItem(qs); } const int noneIndex = studyNumberComboBox->count(); studyNumberComboBox->addItem(noneStudyName); if (noneFlag) { studyNumberComboBox->setCurrentIndex(noneIndex); } else if ((oldIndx >= 0) && (oldIndx < numStudys)) { studyNumberComboBox->setCurrentIndex(oldIndx); } else { studyNumberComboBox->setCurrentIndex(noneIndex); } } caret-5.6.4~dfsg.1.orig/caret/GuiVectorFileComboBox.h0000664000175000017500000000352711572067322022177 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_VECTOR_FILE_COMBO_BOX_H__ #define __GUI_VECTOR_FILE_COMBO_BOX_H__ #include #include class VectorFile; /// class for combo box used for selecting a vector file class GuiVectorFileComboBox : public QComboBox { public: /// Constructor GuiVectorFileComboBox(QWidget* parent = 0, const char* name = 0); /// Destructor ~GuiVectorFileComboBox(); /// get the selected vector file VectorFile* getSelectedVectorFile() const; /// get the selected vector file index int getSelectedVectorFileIndex() const; /// set the selected vector file void setSelectedVectorFile(const VectorFile* tf); /// update the items in the combo box void updateComboBox(); private: /// keeps track of topology files std::vector vectorFilePointers; }; #endif // __GUI_VECTOR_FILE_COMBO_BOX_H__ caret-5.6.4~dfsg.1.orig/caret/GuiVectorFileComboBox.cxx0000664000175000017500000000610011572067322022540 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainSet.h" #include "FileUtilities.h" #include "GuiMainWindow.h" #include "GuiVectorFileComboBox.h" #include "VectorFile.h" #include "global_variables.h" /** * Constructor. */ GuiVectorFileComboBox::GuiVectorFileComboBox(QWidget* parent, const char* /*name*/) : QComboBox(parent) { updateComboBox(); } /** * Destructor. */ GuiVectorFileComboBox::~GuiVectorFileComboBox() { } /** * set the selected vector file. */ void GuiVectorFileComboBox::setSelectedVectorFile(const VectorFile* tf) { if (tf != NULL) { for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfVectorFiles(); i++) { if (tf == theMainWindow->getBrainSet()->getVectorFile(i)) { setCurrentIndex(i); break; } } } } /** * get the selected vector file. */ VectorFile* GuiVectorFileComboBox::getSelectedVectorFile() const { const int index = getSelectedVectorFileIndex(); if (index >= 0) { return vectorFilePointers[index]; } return NULL; } /** * get the selected vector file index. */ int GuiVectorFileComboBox::getSelectedVectorFileIndex() const { const int index = currentIndex(); if ((index >= 0) && (index < count())) { return index; } return -1; } /** * update the items in the combo box. */ void GuiVectorFileComboBox::updateComboBox() { // // Find currently selected vector file // VectorFile* defaultVectorFile = NULL; const int index = currentIndex(); if ((index >= 0) && (index < count())) { defaultVectorFile = vectorFilePointers[index]; } // // Clear out the vector selections // clear(); vectorFilePointers.clear(); // // Load up the vector files // int defaultIndex = 0; const int num = theMainWindow->getBrainSet()->getNumberOfVectorFiles(); for (int i = 0; i < num; i++) { VectorFile* vf = theMainWindow->getBrainSet()->getVectorFile(i); vectorFilePointers.push_back(vf); addItem(FileUtilities::basename(vf->getFileName())); if (vf == defaultVectorFile) { defaultIndex = i; } } if (count() > 0) { setCurrentIndex(defaultIndex); } } caret-5.6.4~dfsg.1.orig/caret/GuiUserViewSaveDialog.h0000664000175000017500000000326511572067322022213 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_USER_VIEW_SAVE_DIALOG_H__ #define __GUI_USER_VIEW_SAVE_DIALOG_H__ #include "WuQDialog.h" class QCheckBox; class QLineEdit; /// class for saving user views class GuiUserViewSaveDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiUserViewSaveDialog(QWidget* parent); /// Destructor ~GuiUserViewSaveDialog(); private: /// called when OK or Cancel button pressed. void done(int r); /// view name line edit QLineEdit* viewNameLineEdit; /// save rotation check box QCheckBox* saveRotationCheckBox; /// save scaling check box QCheckBox* saveScalingCheckBox; /// save translation check box QCheckBox* saveTranslationCheckBox; }; #endif // __GUI_USER_VIEW_SAVE_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiUserViewSaveDialog.cxx0000664000175000017500000001072211572067322022562 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include "BrainModelSurface.h" #include "BrainSet.h" #include "GuiMainWindow.h" #include "GuiUserViewSaveDialog.h" #include "QtUtilities.h" #include "global_variables.h" /** * Constructor. */ GuiUserViewSaveDialog::GuiUserViewSaveDialog(QWidget* parent) : WuQDialog(parent) { setModal(true); setWindowTitle("Set Surface View"); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // Name of view // QHBoxLayout* nameBoxLayout = new QHBoxLayout; dialogLayout->addLayout(nameBoxLayout); nameBoxLayout->addWidget(new QLabel("View Name ")); viewNameLineEdit = new QLineEdit; nameBoxLayout->addWidget(viewNameLineEdit); // // Transform component check boxes // saveRotationCheckBox = new QCheckBox("Save Rotation"); saveRotationCheckBox->setChecked(true); dialogLayout->addWidget(saveRotationCheckBox); saveScalingCheckBox = new QCheckBox("Save Scale"); saveScalingCheckBox->setChecked(true); dialogLayout->addWidget(saveScalingCheckBox); saveTranslationCheckBox = new QCheckBox("Save Translation"); saveTranslationCheckBox->setChecked(true); dialogLayout->addWidget(saveTranslationCheckBox); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); dialogLayout->addLayout(buttonsLayout); // // OK button // QPushButton* okButton = new QPushButton("OK"); okButton->setAutoDefault(false); buttonsLayout->addWidget(okButton); QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); // // Close button // QPushButton* cancelButton = new QPushButton("Cancel"); cancelButton->setAutoDefault(false); buttonsLayout->addWidget(cancelButton); QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); QtUtilities::makeButtonsSameSize(okButton, cancelButton); } /** * Destructor. */ GuiUserViewSaveDialog::~GuiUserViewSaveDialog() { } /** * called when OK or Cancel button pressed. */ void GuiUserViewSaveDialog::done(int r) { if (r == QDialog::Accepted) { BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { // // Check the name of the view // const QString viewName(viewNameLineEdit->text()); if (viewName.isEmpty()) { QMessageBox::critical(this, "ERROR", "Name of view is missing."); return; } // // Get the view transformations // float matrix[16]; bms->getRotationMatrix(0, matrix); float trans[3]; bms->getTranslation(0, trans); float scale[3]; bms->getScaling(0, scale); // // Update the preferences file // PreferencesFile::UserView uv(viewName, matrix, trans, scale, saveRotationCheckBox->isChecked(), saveTranslationCheckBox->isChecked(), saveScalingCheckBox->isChecked()); PreferencesFile* pf = theMainWindow->getBrainSet()->getPreferencesFile(); pf->addUserView(uv); try { pf->writeFile(pf->getFileName()); } catch (FileException& /*e*/) { } } } QDialog::done(r); } caret-5.6.4~dfsg.1.orig/caret/GuiTransformationMatrixSelectionControl.h0000664000175000017500000000352611572067322026105 0ustar michaelmichael #ifndef __GUI_TRANSFORMATION_MATRIX_SELECTION_CONTROL_H__ #define __GUI_TRANSFORMATION_MATRIX_SELECTION_CONTROL_H__ #include class TransformationMatrix; class TransformationMatrixFile; /// combo box for selecting a matrix from a transformation matrix file class GuiTransformationMatrixSelectionControl : public QComboBox { Q_OBJECT public: enum { /// "none" matrix index NONE_MATRIX_INDEX = -1 }; /// Constructor GuiTransformationMatrixSelectionControl(QWidget* parent, TransformationMatrixFile* matrixFile, const bool enableNoneSelectionIn, const char* name = 0); /// Destructor ~GuiTransformationMatrixSelectionControl(); /// get the selected matrix TransformationMatrix* getSelectedMatrix(); /// set the none label void setNoneLabel(const QString& s); /// get the selected matrix (returns NULL if "none" selected) const TransformationMatrix* getSelectedMatrix() const; /// set the selected matrix void setSelectedMatrix(const TransformationMatrix* tm); /// get the selected matrix index (returns -1 if "none" selected) int getSelectedMatrixIndex() const; /// set the selected matrix void setSelectedMatrixIndex(const int indx); /// update the control void updateControl(); protected: /// the matrix file for this combo box TransformationMatrixFile* matrixFile; /// none selection enabled bool noneSelectionEnabled; /// label for none QString noneLabel; }; #endif // __GUI_TRANSFORMATION_MATRIX_SELECTION_CONTROL_H__ caret-5.6.4~dfsg.1.orig/caret/GuiTransformationMatrixSelectionControl.cxx0000664000175000017500000000735011572067322026457 0ustar michaelmichael #include "GuiTransformationMatrixSelectionControl.h" #include "StringUtilities.h" #include "TransformationMatrixFile.h" /** * Constructor. */ GuiTransformationMatrixSelectionControl::GuiTransformationMatrixSelectionControl( QWidget* parent, TransformationMatrixFile* matrixFileIn, const bool enableNoneSelectionIn, const char* /*name*/) : QComboBox(parent) { noneLabel = "None"; noneSelectionEnabled = enableNoneSelectionIn; matrixFile = matrixFileIn; updateControl(); } /** * Destructor. */ GuiTransformationMatrixSelectionControl::~GuiTransformationMatrixSelectionControl() { } /** * get the selected matrix. */ TransformationMatrix* GuiTransformationMatrixSelectionControl::getSelectedMatrix() { const int item = getSelectedMatrixIndex(); if ((item >= 0) && (item < matrixFile->getNumberOfMatrices())) { return matrixFile->getTransformationMatrix(item); } return NULL; } /** * get the selected matrix. */ const TransformationMatrix* GuiTransformationMatrixSelectionControl::getSelectedMatrix() const { const int item = getSelectedMatrixIndex(); if ((item >= 0) && (item < matrixFile->getNumberOfMatrices())) { return matrixFile->getTransformationMatrix(item); } return NULL; } /** * set the selected matrix. */ void GuiTransformationMatrixSelectionControl::setSelectedMatrix(const TransformationMatrix* tm) { if (tm == NULL) { setSelectedMatrixIndex(NONE_MATRIX_INDEX); } else { for (int i = 0; i < matrixFile->getNumberOfMatrices(); i++) { if (matrixFile->getTransformationMatrix(i) == tm) { setSelectedMatrixIndex(i); break; } } } } /** * get the selected matrix index. */ int GuiTransformationMatrixSelectionControl::getSelectedMatrixIndex() const { // // is NONE selected // if (currentIndex() >= matrixFile->getNumberOfMatrices()) { return -1; } return currentIndex(); } /** * set the selected matrix. */ void GuiTransformationMatrixSelectionControl::setSelectedMatrixIndex(const int indxIn) { int indx = indxIn; if (indx == NONE_MATRIX_INDEX) { indx = count() - 1; } setCurrentIndex(indx); } /** * set the none label. */ void GuiTransformationMatrixSelectionControl::setNoneLabel(const QString& s) { noneLabel = s; updateControl(); } /** * update the control. */ void GuiTransformationMatrixSelectionControl::updateControl() { const TransformationMatrix* selectedMatrix = getSelectedMatrix(); int defaultItem = 0; if ((selectedMatrix == NULL) && noneSelectionEnabled) { if (getSelectedMatrixIndex() == NONE_MATRIX_INDEX) { defaultItem = NONE_MATRIX_INDEX; } } clear(); const int num = matrixFile->getNumberOfMatrices(); for (int i = 0; i < num; i++) { const TransformationMatrix* tm = matrixFile->getTransformationMatrix(i); if (tm == selectedMatrix) { defaultItem = i; } QString name(tm->getMatrixName()); if (name.isEmpty()) { name = "Matrix "; name.append(StringUtilities::fromNumber(i)); } addItem(name); } if (noneSelectionEnabled) { addItem(noneLabel); } if ((defaultItem >= 0) && (defaultItem < num)) { setSelectedMatrixIndex(defaultItem); } else { // // Default to none // if (noneSelectionEnabled) { setSelectedMatrixIndex(NONE_MATRIX_INDEX); } else if (count() > 0) { setSelectedMatrixIndex(0); } } } caret-5.6.4~dfsg.1.orig/caret/GuiTransformationMatrixDialog.h0000664000175000017500000002074211572067322024015 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_GUI_TRANSFORMATION_MATRIX_DIALOG_H__ #define __VE_GUI_TRANSFORMATION_MATRIX_DIALOG_H__ #include #include #include "WuQDialog.h" class GuiTransformationMatrixSelectionControl; class QCheckBox; class QComboBox; class QGridLayout; class QLabel; class QLineEdit; class QPushButton; class QTabWidget; class QDoubleSpinBox; class TransformationMatrix; class vtkTransform; /// Dialog for editing transformation matrices. class GuiTransformationMatrixDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiTransformationMatrixDialog(QWidget* parent); /// Destructor ~GuiTransformationMatrixDialog(); /// called when the mouse is pressed to make matrix available for undo void axesEventInMainWindow(); /// update the dialog void updateDialog(); /// update the display if the matrix is linked to main window or axis void updateMatrixDisplay(const TransformationMatrix* tm); /// set the translation values void setTranslation(const float tx, const float ty, const float tz); private slots: /// called to close the dialog void slotCloseDialog(); /// called when a matrix is selected void slotMatrixSelectionComboBox(int item); /// called when a matrix component is changed void slotMatrixComponentChanged(); /// called to set the matrix to the identity matrix void slotOperationIdentity(); /// called to set the matrix to its inverse void slotOperationInverse(); /// called to transpose the matrix void slotOperationTranspose(); /// called to multiply the matrix by another matrix void slotOperationMultiply(); /// called to translate in screen axes void slotTranslateScreenAxes(); /// called to translate in object axes void slotTranslateObjectAxes(); /// called to rotate in screen axes void slotRotateScreenAxes(); /// called to rotate in object axes void slotRotateObjectAxes(); /// called to scale object void slotScale(); /// called to set translation with mouse void slotSetTranslationWithMouse(); /// called when new matrix button pressed void slotMatrixNew(); /// called when delete matrix button pressed void slotMatrixDelete(); /// called when matrix attributes button pressed void slotMatrixAttributes(); /// called when copy matrix button pressed void slotMatrixCopy(); /// called when paste matrix button pressed void slotMatrixPaste(); /// called when apply matrix to main window button pressed void slotMatrixApplyMainWindow(); /// called when apply matrix to transform data file button pressed void slotMatrixApplyTransformDataFile(); /// called when load matrix button pressed void slotMatrixLoad(); /// called when the show axes check box is toggled void slotShowAxesCheckBox(bool val); /// called to pop a matrix off the undo stack void slotUndoPushButton(); /// called when a matrix is selected for a data file void slotTransformMatrixSelection(); private: /// class for storing a matrix for "undoing" an operation class UndoMatrix { public: /// Constructor UndoMatrix(const TransformationMatrix* tm); /// Destructor UndoMatrix(); /// get the matrix void getMatrix(TransformationMatrix* tm) const; protected: /// the matrix double mm[16]; }; /// matrix view type enum MATRIX_VIEW_TYPE { MATRIX_VIEW_MATRIX, MATRIX_VIEW_TRANSFORMATIONS }; /// create the matrix section QWidget* createMatrixSection(); /// create the operations section QWidget* createOperationsSection(); /// create the operation section. QWidget* createMatrixButtonsSection(); /// add current matrix values to the undo stack void addMatrixToUndoStack(); /// enable/disable the undo button void enableDisableUndoPushButton(); /// clear the undo stack void clearUndoStack(); /// transfer the matrix into the matrix element part of dialog void transferMatrixIntoMatrixElementLineEdits(); /// transfer the matrix into the matrix transformation spin boxes void transferMatrixIntoMatrixTransformSpinBoxes(); /// transfer the matrix into the dialog void transferMatrixIntoDialog(); /// transfer dialog values into matrix void transferDialogValuesIntoMatrix(); /// get the matrix view type MATRIX_VIEW_TYPE getMatrixViewType() const; /// get main window transform matrix vtkTransform* getMainWindowRotationTransform(); /// create the matrix editor page QWidget* createMatrixEditorPage(); /// create the transform data file page QWidget* createTransformDataFilePage(); /// update the main window viewing matrix void updateMainWindowViewingMatrix(); /// tab widget for matrices and data files QTabWidget* matricesDataFilesTabWidget; /// matrix editor page QWidget* matrixEditorPage; /// transform data file page QWidget* transformDataFilePage; /// transform data file grid layout QGridLayout* transformDataFileGridLayout; /// transform data file labels std::vector transformFileLabels; /// transform data file matrix control std::vector transformFileMatrixControls; /// tab widget for matrix or trans/rotate QTabWidget* matrixViewTabWidget; /// widget for matrix elements QWidget* matrixElementWidget; /// line edits for matrix elements QLineEdit* matrixElementLineEdits[4][4]; /// comment label QLabel* commentLabel; /// matrix selection combo box QComboBox* matrixSelectionComboBox; /// matrix transformations widget QWidget* matrixTransformationsWidget; /// matrix view translation X QDoubleSpinBox* matrixTranslateXDoubleSpinBox; /// matrix view translation Y QDoubleSpinBox* matrixTranslateYDoubleSpinBox; /// matrix view translation Z QDoubleSpinBox* matrixTranslateZDoubleSpinBox; /// matrix view rotate X QDoubleSpinBox* matrixRotateXDoubleSpinBox; /// matrix view rotate Y QDoubleSpinBox* matrixRotateYDoubleSpinBox; /// matrix view rotate Z QDoubleSpinBox* matrixRotateZDoubleSpinBox; /// matrix view scale X QDoubleSpinBox* matrixScaleXDoubleSpinBox; /// matrix view scale Y QDoubleSpinBox* matrixScaleYDoubleSpinBox; /// matrix view scale Z QDoubleSpinBox* matrixScaleZDoubleSpinBox; /// the show axes check box QCheckBox* showAxesCheckBox; /// yoke to main window QCheckBox* yokeToMainWindowCheckBox; /// current matrix in dialog TransformationMatrix* currentMatrix; /// the undo matrix stack std::stack undoMatrixStack; /// the undo push button QPushButton* undoPushButton; }; #endif // __VE_GUI_TRANSFORMATION_MATRIX_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiTransformationMatrixDialog.cxx0000664000175000017500000024730111572067322024372 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifdef Q_OS_WIN32 #define NOMINMAX #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "AbstractFile.h" #include "BorderFile.h" #include "BrainModelBorderSet.h" #include "BrainModelContours.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceAndVolume.h" #include "BrainModelVolume.h" #include "BrainSet.h" #include "CellFile.h" #include "CellProjectionFile.h" #include "ContourFile.h" #include "ContourCellFile.h" #include "DisplaySettingsCells.h" #include "DisplaySettingsContours.h" #include "DisplaySettingsFoci.h" #include "DisplaySettingsVolume.h" #include "FileUtilities.h" #include "FociFile.h" #include "FociProjectionFile.h" #include "GuiBrainModelOpenGL.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "GuiTransformationMatrixDialog.h" #include "GuiTransformationMatrixSelectionControl.h" #include "MathUtilities.h" #include #include "QtMultipleInputDialog.h" #include "QtRadioButtonSelectionDialog.h" #include "TransformationMatrixFile.h" #include "VectorFile.h" #include "VolumeFile.h" #include "VtkModelFile.h" #include "WuQDataEntryDialog.h" #include "global_variables.h" #include "vtkTransform.h" /** * Constructor. */ GuiTransformationMatrixDialog::GuiTransformationMatrixDialog(QWidget* parent) : WuQDialog(parent) { currentMatrix = NULL; setWindowTitle("Transformation Matrix Editor"); // // Vertical box layout of all items // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(3); dialogLayout->setSpacing(3); // // Create a tab widget for matrices and data files // matricesDataFilesTabWidget = new QTabWidget; dialogLayout->addWidget(matricesDataFilesTabWidget); // // Create the matrix editing page // matrixEditorPage = createMatrixEditorPage(); matricesDataFilesTabWidget->addTab(matrixEditorPage, "Matrix Editor"); // // Create the transform data file page // transformDataFilePage = createTransformDataFilePage(); matricesDataFilesTabWidget->addTab(transformDataFilePage, "Transform Data Files"); // // Close button // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(3); dialogLayout->addLayout(buttonsLayout); QPushButton* closeButton = new QPushButton("Close"); buttonsLayout->addWidget(closeButton); closeButton->setAutoDefault(false); closeButton->setFixedSize(closeButton->sizeHint()); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(slotCloseDialog())); // // Default to transform view // matrixViewTabWidget->setCurrentWidget(matrixTransformationsWidget); if (matrixSelectionComboBox->count() > 0) { slotMatrixSelectionComboBox(0); } updateDialog(); } /** * Destructor. */ GuiTransformationMatrixDialog::~GuiTransformationMatrixDialog() { } /** * create the transform data file page. */ QWidget* GuiTransformationMatrixDialog::createTransformDataFilePage() { // // Grid for transform data files and associated matrices // QWidget* transformDataFileGrid = new QWidget; transformDataFileGridLayout = new QGridLayout(transformDataFileGrid); transformDataFileGridLayout->setSpacing(5); transformDataFileGridLayout->addWidget(new QLabel("Data File Name "), 0, 0); transformDataFileGridLayout->addWidget(new QLabel("Display Transform Matrix"), 0, 1); transformDataFileGridLayout->setRowStretch(1000, 1000); // // Scroll box for models // QWidget* transformDataWidget = new QWidget; QVBoxLayout* transformDataLayout = new QVBoxLayout(transformDataWidget); QScrollArea* transformDataFileScrollView = new QScrollArea; transformDataFileScrollView->setWidgetResizable(true); transformDataFileScrollView->setWidget(transformDataFileGrid); transformDataLayout->addWidget(transformDataFileScrollView); transformDataLayout->addStretch(); return transformDataWidget; } /** * create the matrix editor page. */ QWidget* GuiTransformationMatrixDialog::createMatrixEditorPage() { QWidget* editorHBox = new QWidget; QHBoxLayout* editorLayout = new QHBoxLayout(editorHBox); // // Vertical box for matrix and operations // QVBoxLayout* matrixLayout = new QVBoxLayout; editorLayout->addLayout(matrixLayout); // // Create the matrix section // matrixLayout->addWidget(createMatrixSection()); // // Create the operations section // matrixLayout->addWidget(createOperationsSection()); // // Create the matrix buttons column // editorLayout->addWidget(createMatrixButtonsSection()); return editorHBox; } /** * create the matrix section. */ QWidget* GuiTransformationMatrixDialog::createMatrixSection() { QGroupBox* matrixGroupBox = new QGroupBox("Matrix Data"); QVBoxLayout* matrixGroupLayout = new QVBoxLayout(matrixGroupBox); // // Matrix selection combo box // matrixSelectionComboBox = new QComboBox; matrixGroupLayout->addWidget(matrixSelectionComboBox); QObject::connect(matrixSelectionComboBox, SIGNAL(activated(int)), this, SLOT(slotMatrixSelectionComboBox(int))); // // Comment label // QHBoxLayout* commentHBoxLayout = new QHBoxLayout; matrixGroupLayout->addLayout(commentHBoxLayout); QLabel* commLabel = new QLabel("Comment: "); commentHBoxLayout->addWidget(commLabel); commentHBoxLayout->setStretchFactor(commLabel, 0); commentLabel = new QLabel(" "); commentLabel->setAlignment(Qt::AlignLeft); commentHBoxLayout->addWidget(commentLabel); commentHBoxLayout->setStretchFactor(commentLabel, 100); // // Show axes check box // showAxesCheckBox = new QCheckBox("Show Axes"); matrixGroupLayout->addWidget(showAxesCheckBox); QObject::connect(showAxesCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowAxesCheckBox(bool))); // // Yoke to main window check box // yokeToMainWindowCheckBox = new QCheckBox("Yoke to Main Window"); matrixGroupLayout->addWidget(yokeToMainWindowCheckBox); // // tab widget for how to view matrix // matrixViewTabWidget = new QTabWidget(matrixGroupBox); matrixGroupLayout->addWidget(matrixViewTabWidget); // // matrix element widget // matrixElementWidget = new QWidget; QGridLayout* matrixElementGrid = new QGridLayout(matrixElementWidget); matrixElementGrid->setSpacing(5); matrixViewTabWidget->addTab(matrixElementWidget, "Matrix View"); // // matrix element line edits // const int minWidth = 125; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { matrixElementLineEdits[i][j] = new QLineEdit; matrixElementLineEdits[i][j]->setFixedWidth(minWidth); QObject::connect(matrixElementLineEdits[i][j], SIGNAL(editingFinished()), this, SLOT(slotMatrixComponentChanged())); matrixElementGrid->addWidget(matrixElementLineEdits[i][j], i, j); } } // // Squish matrix element grid widget // matrixElementWidget->setFixedSize(matrixElementWidget->sizeHint()); // // transformation widget // matrixTransformationsWidget = new QWidget; QGridLayout* matrixTransformationsGrid = new QGridLayout(matrixTransformationsWidget); matrixTransformationsGrid->setSpacing(5); matrixViewTabWidget->addTab(matrixTransformationsWidget, "Transform View"); // // Column labels // matrixTransformationsGrid->addWidget(new QLabel("X"), 0, 1, Qt::AlignHCenter); matrixTransformationsGrid->addWidget(new QLabel("Y"), 0, 2, Qt::AlignHCenter); matrixTransformationsGrid->addWidget(new QLabel("Z"), 0, 3, Qt::AlignHCenter); // // Translate controls // matrixTransformationsGrid->addWidget(new QLabel("Translate "), 1, 0); matrixTranslateXDoubleSpinBox = new QDoubleSpinBox; matrixTranslateXDoubleSpinBox->setMinimum(-25000.0); matrixTranslateXDoubleSpinBox->setMaximum( 25000.0); matrixTranslateXDoubleSpinBox->setSingleStep(1.0); matrixTranslateXDoubleSpinBox->setDecimals(4); QObject::connect(matrixTranslateXDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(slotMatrixComponentChanged())); matrixTranslateYDoubleSpinBox = new QDoubleSpinBox; matrixTranslateYDoubleSpinBox->setMinimum(-25000.0); matrixTranslateYDoubleSpinBox->setMaximum( 25000.0); matrixTranslateYDoubleSpinBox->setSingleStep(1.0); matrixTranslateYDoubleSpinBox->setDecimals(4); QObject::connect(matrixTranslateYDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(slotMatrixComponentChanged())); matrixTranslateZDoubleSpinBox = new QDoubleSpinBox; matrixTranslateZDoubleSpinBox->setMinimum(-25000.0); matrixTranslateZDoubleSpinBox->setMaximum( 25000.0); matrixTranslateZDoubleSpinBox->setSingleStep(1.0); matrixTranslateZDoubleSpinBox->setDecimals(4); QObject::connect(matrixTranslateZDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(slotMatrixComponentChanged())); matrixTransformationsGrid->addWidget(matrixTranslateXDoubleSpinBox, 1, 1); matrixTransformationsGrid->addWidget(matrixTranslateYDoubleSpinBox, 1, 2); matrixTransformationsGrid->addWidget(matrixTranslateZDoubleSpinBox, 1, 3); // // Rotate controls // matrixTransformationsGrid->addWidget(new QLabel("Rotate "), 2, 0); matrixRotateXDoubleSpinBox = new QDoubleSpinBox; matrixRotateXDoubleSpinBox->setMinimum(-360.0); matrixRotateXDoubleSpinBox->setMaximum(360.0); matrixRotateXDoubleSpinBox->setSingleStep(1.0); matrixRotateXDoubleSpinBox->setDecimals(4); QObject::connect(matrixRotateXDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(slotMatrixComponentChanged())); matrixRotateYDoubleSpinBox = new QDoubleSpinBox; matrixRotateYDoubleSpinBox->setMinimum(-360.0); matrixRotateYDoubleSpinBox->setMaximum(360.0); matrixRotateYDoubleSpinBox->setSingleStep(1.0); matrixRotateYDoubleSpinBox->setDecimals(4); QObject::connect(matrixRotateYDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(slotMatrixComponentChanged())); matrixRotateZDoubleSpinBox = new QDoubleSpinBox; matrixRotateZDoubleSpinBox->setMinimum(-360.0); matrixRotateZDoubleSpinBox->setMaximum(360.0); matrixRotateZDoubleSpinBox->setSingleStep(1.0); matrixRotateZDoubleSpinBox->setDecimals(4); QObject::connect(matrixRotateZDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(slotMatrixComponentChanged())); matrixTransformationsGrid->addWidget(matrixRotateXDoubleSpinBox, 2, 1); matrixTransformationsGrid->addWidget(matrixRotateYDoubleSpinBox, 2, 2); matrixTransformationsGrid->addWidget(matrixRotateZDoubleSpinBox, 2, 3); // // Scale controls // matrixTransformationsGrid->addWidget(new QLabel("Scale "), 3, 0); matrixScaleXDoubleSpinBox = new QDoubleSpinBox; matrixScaleXDoubleSpinBox->setMinimum(-25000.0); matrixScaleXDoubleSpinBox->setMaximum(25000.0); matrixScaleXDoubleSpinBox->setSingleStep(1.0); matrixScaleXDoubleSpinBox->setDecimals(4); QObject::connect(matrixScaleXDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(slotMatrixComponentChanged())); matrixScaleYDoubleSpinBox = new QDoubleSpinBox; matrixScaleYDoubleSpinBox->setMinimum(-25000.0); matrixScaleYDoubleSpinBox->setMaximum(25000.0); matrixScaleYDoubleSpinBox->setSingleStep(1.0); matrixScaleYDoubleSpinBox->setDecimals(4); QObject::connect(matrixScaleYDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(slotMatrixComponentChanged())); matrixScaleZDoubleSpinBox = new QDoubleSpinBox; matrixScaleZDoubleSpinBox->setMinimum(-25000.0); matrixScaleZDoubleSpinBox->setMaximum(25000.0); matrixScaleZDoubleSpinBox->setSingleStep(1.0); matrixScaleZDoubleSpinBox->setDecimals(4); QObject::connect(matrixScaleZDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(slotMatrixComponentChanged())); matrixTransformationsGrid->addWidget(matrixScaleXDoubleSpinBox, 3, 1); matrixTransformationsGrid->addWidget(matrixScaleYDoubleSpinBox, 3, 2); matrixTransformationsGrid->addWidget(matrixScaleZDoubleSpinBox, 3, 3); // // Squish matrix transformations grid widget // matrixTransformationsWidget->setFixedSize(matrixTransformationsWidget->sizeHint()); return matrixGroupBox; } /** * called when the show axes check box is toggled. */ void GuiTransformationMatrixDialog::slotShowAxesCheckBox(bool val) { if (currentMatrix != NULL) { currentMatrix->setShowAxes(val); GuiBrainModelOpenGL::updateAllGL(); } } /** * called when a matrix component is changed. */ void GuiTransformationMatrixDialog::slotMatrixComponentChanged() { // // Add previous matrix to undo stack // addMatrixToUndoStack(); transferDialogValuesIntoMatrix(); updateMainWindowViewingMatrix(); if (currentMatrix->getShowAxes()) { GuiBrainModelOpenGL::updateAllGL(); } } /** * called when a matrix is selected. */ void GuiTransformationMatrixDialog::slotMatrixSelectionComboBox(int item) { TransformationMatrixFile* tmf = theMainWindow->getBrainSet()->getTransformationMatrixFile(); if ((item >= 0) && (item < tmf->getNumberOfMatrices())) { currentMatrix = tmf->getTransformationMatrix(item); transferMatrixIntoDialog(); } } /** * create the operation section. */ QWidget* GuiTransformationMatrixDialog::createOperationsSection() { // // identity push button // QPushButton* identityPushButton = new QPushButton("Identity"); identityPushButton->setAutoDefault(false); identityPushButton->setToolTip( "Set the matrix to the identity matrix."); QObject::connect(identityPushButton, SIGNAL(clicked()), this, SLOT(slotOperationIdentity())); // // inverse push button // QPushButton* inversePushButton = new QPushButton("Inverse"); inversePushButton->setAutoDefault(false); inversePushButton->setToolTip( "Set the matrix to its inverse."); QObject::connect(inversePushButton, SIGNAL(clicked()), this, SLOT(slotOperationInverse())); // // transpose push button // QPushButton* transposePushButton = new QPushButton("Transpose"); transposePushButton->setAutoDefault(false); transposePushButton->setToolTip( "Transpose the matrix."); QObject::connect(transposePushButton, SIGNAL(clicked()), this, SLOT(slotOperationTranspose())); // // multiply push button // QPushButton* multiplyPushButton = new QPushButton("Multiply (Post)..."); multiplyPushButton->setAutoDefault(false); multiplyPushButton->setToolTip( "Post Multiply the matrix by another matrix."); QObject::connect(multiplyPushButton, SIGNAL(clicked()), this, SLOT(slotOperationMultiply())); // // Translate screen axes // QPushButton* translateScreenAxesPushButton = new QPushButton("Translate About Screen Axes..."); translateScreenAxesPushButton->setAutoDefault(false); translateScreenAxesPushButton->setToolTip( "Translate with respect to screen axes."); QObject::connect(translateScreenAxesPushButton, SIGNAL(clicked()), this, SLOT(slotTranslateScreenAxes())); // // Translate object axes // QPushButton* translatePushButton = new QPushButton("Translate About Object Axes..."); translatePushButton->setAutoDefault(false); translatePushButton->setToolTip( "Translate with respect to object axes."); QObject::connect(translatePushButton, SIGNAL(clicked()), this, SLOT(slotTranslateObjectAxes())); // // Rotate screen axes // QPushButton* rotateScreenAxesPushButton = new QPushButton("Rotate About Screen Axes..."); rotateScreenAxesPushButton->setAutoDefault(false); rotateScreenAxesPushButton->setToolTip( "Rotate with respect to screen axes."); QObject::connect(rotateScreenAxesPushButton, SIGNAL(clicked()), this, SLOT(slotRotateScreenAxes())); // // Rotate object axes // QPushButton* rotatePushButton = new QPushButton("Rotate About Object Axes..."); rotatePushButton->setAutoDefault(false); rotatePushButton->setToolTip( "Rotate with respect to object axes."); QObject::connect(rotatePushButton, SIGNAL(clicked()), this, SLOT(slotRotateObjectAxes())); // // Scale // QPushButton* scalePushButton = new QPushButton("Scale..."); scalePushButton->setAutoDefault(false); scalePushButton->setToolTip( "Apply scaling to the matrix."); QObject::connect(scalePushButton, SIGNAL(clicked()), this, SLOT(slotScale())); // // Set translate with mouse // QPushButton* mouseTransButton = new QPushButton("Set Translate With Mouse"); mouseTransButton->setAutoDefault(false); mouseTransButton->setToolTip( "Set the mouse mode so that when\n" "the mouse is clicked in the main\n" "window, the matrix's translation\n" "is set to the model coordinates at\n" "the location of the mouse click."); QObject::connect(mouseTransButton, SIGNAL(clicked()), this, SLOT(slotSetTranslationWithMouse())); // // Undo // undoPushButton = new QPushButton("Undo"); undoPushButton->setAutoDefault(false); undoPushButton->setToolTip( "Restore the matrix to its\n" "values previous to the last\n" "operation performed on the matrix."); QObject::connect(undoPushButton, SIGNAL(clicked()), this, SLOT(slotUndoPushButton())); // // Grid layout for all of the buttons // QGroupBox* operationsGroupBox = new QGroupBox("Matrix Operations"); QGridLayout* operationsGrid = new QGridLayout(operationsGroupBox); operationsGrid->setMargin(4); operationsGrid->setSpacing(4); operationsGrid->addWidget(identityPushButton, 0, 0); operationsGrid->addWidget(inversePushButton, 0, 1); operationsGrid->addWidget(transposePushButton, 0, 2); operationsGrid->addWidget(multiplyPushButton, 0, 3); operationsGrid->addWidget(translateScreenAxesPushButton, 1, 0, 1, 2); operationsGrid->addWidget(translatePushButton, 1, 2, 1, 2); operationsGrid->addWidget(rotateScreenAxesPushButton, 2, 0, 1, 2); operationsGrid->addWidget(rotatePushButton, 2, 2, 1, 2); operationsGrid->addWidget(scalePushButton, 3, 0, 1, 1); operationsGrid->addWidget(mouseTransButton, 3, 1, 1, 2); operationsGrid->addWidget(undoPushButton, 3, 3, 1, 1); return operationsGroupBox; } /** * called to set translation with mouse. */ void GuiTransformationMatrixDialog::slotSetTranslationWithMouse() { theMainWindow->getBrainModelOpenGL()->setMouseMode( GuiBrainModelOpenGL::MOUSE_MODE_TRANSFORMATION_MATRIX_SET_TRANSLATE); } /** * set the translation values. */ void GuiTransformationMatrixDialog::setTranslation(const float tx, const float ty, const float tz) { if (currentMatrix != NULL) { addMatrixToUndoStack(); currentMatrix->setTranslation(tx, ty, tz); transferMatrixIntoDialog(); updateMainWindowViewingMatrix(); if (currentMatrix->getShowAxes()) { GuiBrainModelOpenGL::updateAllGL(); } } } /** * called to scale object. */ void GuiTransformationMatrixDialog::slotScale() { if (currentMatrix != NULL) { std::vector labels; std::vector values; labels.push_back("Scale X"); values.push_back("1.0"); labels.push_back("Scale Y"); values.push_back("1.0"); labels.push_back("Scale Z"); values.push_back("1.0"); QtMultipleInputDialog mid(this, "Scale", "", labels, values, true, true); if (mid.exec() == QDialog::Accepted) { // // Add previous matrix to undo stack // addMatrixToUndoStack(); double v[3]; mid.getValues(v); transferDialogValuesIntoMatrix(); currentMatrix->scale(v); transferMatrixIntoDialog(); updateMainWindowViewingMatrix(); if (currentMatrix->getShowAxes()) { GuiBrainModelOpenGL::updateAllGL(); } } } } /** * called to translate in screen axes. */ void GuiTransformationMatrixDialog::slotTranslateScreenAxes() { if (currentMatrix != NULL) { std::vector labels; std::vector values; labels.push_back("Translate X"); values.push_back("0.0"); labels.push_back("Translate Y"); values.push_back("0.0"); labels.push_back("Translate Z"); values.push_back("0.0"); QtMultipleInputDialog mid(this, "Translate Screen Axes", "", labels, values, true, true); if (mid.exec() == QDialog::Accepted) { // // Add previous matrix to undo stack // addMatrixToUndoStack(); double v[3]; mid.getValues(v); transferDialogValuesIntoMatrix(); if (yokeToMainWindowCheckBox->isChecked()) { currentMatrix->translate(v); } else { currentMatrix->translate(v, getMainWindowRotationTransform()); } transferMatrixIntoDialog(); updateMainWindowViewingMatrix(); if (currentMatrix->getShowAxes()) { GuiBrainModelOpenGL::updateAllGL(); } } } } /** * called to translate in object axes. */ void GuiTransformationMatrixDialog::slotTranslateObjectAxes() { if (currentMatrix != NULL) { std::vector labels; std::vector values; labels.push_back("Translate X"); values.push_back("0.0"); labels.push_back("Translate Y"); values.push_back("0.0"); labels.push_back("Translate Z"); values.push_back("0.0"); QtMultipleInputDialog mid(this, "Translate Object Axes", "", labels, values, true, true); if (mid.exec() == QDialog::Accepted) { // // Add previous matrix to undo stack // addMatrixToUndoStack(); double v[3]; mid.getValues(v); transferDialogValuesIntoMatrix(); if (yokeToMainWindowCheckBox->isChecked()) { TransformationMatrix tm; tm.setMatrix(getMainWindowRotationTransform()); vtkTransform* m = vtkTransform::New(); tm.getMatrix(m); m->Inverse(); currentMatrix->translate(v, m); m->Delete(); } else { currentMatrix->translate(v, NULL); } transferMatrixIntoDialog(); updateMainWindowViewingMatrix(); if (currentMatrix->getShowAxes()) { GuiBrainModelOpenGL::updateAllGL(); } } } } /** * called to rotate in screen axes. */ void GuiTransformationMatrixDialog::slotRotateScreenAxes() { if (currentMatrix != NULL) { std::vector labels; std::vector values; labels.push_back("Rotate X (Degrees)"); values.push_back("0.0"); labels.push_back("Rotate Y (Degrees)"); values.push_back("0.0"); labels.push_back("Rotate Z (Degrees)"); values.push_back("0.0"); QtMultipleInputDialog mid(this, "Rotate Screen Axes", "", labels, values, true, true); if (mid.exec() == QDialog::Accepted) { // // Add previous matrix to undo stack // addMatrixToUndoStack(); double v[3]; mid.getValues(v); transferDialogValuesIntoMatrix(); currentMatrix->rotate(v, getMainWindowRotationTransform()); //NULL); transferMatrixIntoDialog(); updateMainWindowViewingMatrix(); if (currentMatrix->getShowAxes()) { GuiBrainModelOpenGL::updateAllGL(); } } } } /** * called to rotate in object axes. */ void GuiTransformationMatrixDialog::slotRotateObjectAxes() { if (currentMatrix != NULL) { std::vector labels; std::vector values; labels.push_back("Rotate X (Degrees)"); values.push_back("0.0"); labels.push_back("Rotate Y (Degrees)"); values.push_back("0.0"); labels.push_back("Rotate Z (Degrees)"); values.push_back("0.0"); QtMultipleInputDialog mid(this, "Rotate Object Axes", "", labels, values, true, true); if (mid.exec() == QDialog::Accepted) { // // Add previous matrix to undo stack // addMatrixToUndoStack(); double v[3]; mid.getValues(v); transferDialogValuesIntoMatrix(); //currentMatrix->rotate(v, getMainWindowRotationTransform()); currentMatrix->rotateZ(v[2]); currentMatrix->rotateX(v[0]); currentMatrix->rotateY(v[1]); transferMatrixIntoDialog(); updateMainWindowViewingMatrix(); if (currentMatrix->getShowAxes()) { GuiBrainModelOpenGL::updateAllGL(); } } } } /** * called to set the matrix to the identity matrix. */ void GuiTransformationMatrixDialog::slotOperationIdentity() { if (currentMatrix != NULL) { // // Add previous matrix to undo stack // addMatrixToUndoStack(); transferDialogValuesIntoMatrix(); currentMatrix->identity(); transferMatrixIntoDialog(); updateMainWindowViewingMatrix(); if (currentMatrix->getShowAxes()) { GuiBrainModelOpenGL::updateAllGL(); } } } /** * called to set the matrix to its inverse. */ void GuiTransformationMatrixDialog::slotOperationInverse() { if (currentMatrix != NULL) { // // Add previous matrix to undo stack // addMatrixToUndoStack(); transferDialogValuesIntoMatrix(); currentMatrix->inverse(); transferMatrixIntoDialog(); updateMainWindowViewingMatrix(); if (currentMatrix->getShowAxes()) { GuiBrainModelOpenGL::updateAllGL(); } } } /** * called to transpose the matrix. */ void GuiTransformationMatrixDialog::slotOperationTranspose() { if (currentMatrix != NULL) { // // Add previous matrix to undo stack // addMatrixToUndoStack(); transferDialogValuesIntoMatrix(); currentMatrix->transpose(); transferMatrixIntoDialog(); updateMainWindowViewingMatrix(); if (currentMatrix->getShowAxes()) { GuiBrainModelOpenGL::updateAllGL(); } } } /** * called to multiply the matrix by another matrix. */ void GuiTransformationMatrixDialog::slotOperationMultiply() { if (currentMatrix != NULL) { // // Add previous matrix to undo stack // addMatrixToUndoStack(); transferDialogValuesIntoMatrix(); TransformationMatrixFile* matrixFile = theMainWindow->getBrainSet()->getTransformationMatrixFile(); std::vector matrixNames; for (int i = 0; i < matrixFile->getNumberOfMatrices(); i++) { TransformationMatrix* tm = matrixFile->getTransformationMatrix(i); matrixNames.push_back(tm->getMatrixName()); } QtRadioButtonSelectionDialog rbsd(this, "Post Multiply by Matrix", "", matrixNames, -1); if (rbsd.exec() == QDialog::Accepted) { const int matrixNumber = rbsd.getSelectedItemIndex(); if (matrixNumber >= 0) { TransformationMatrix tm = *(matrixFile->getTransformationMatrix(matrixNumber)); currentMatrix->postMultiply(tm); transferMatrixIntoDialog(); updateMainWindowViewingMatrix(); if (currentMatrix->getShowAxes()) { GuiBrainModelOpenGL::updateAllGL(); } } } } } /** * update the display if the matrix is being manipulated. */ void GuiTransformationMatrixDialog::updateMatrixDisplay(const TransformationMatrix* tm) { // // If current matrix yoked to main window viewing matrix // if (yokeToMainWindowCheckBox->isChecked() && (tm == NULL)) { DisplaySettingsVolume* dsv = theMainWindow->getBrainSet()->getDisplaySettingsVolume(); currentMatrix->identity(); float trans[3]; BrainModel* bm = theMainWindow->getBrainModel(); bm->getTranslation(0, trans); currentMatrix->translate(trans); TransformationMatrix rot; BrainModelVolume* bmv = theMainWindow->getBrainModelVolume(); if (bmv != NULL) { switch (bmv->getSelectedAxis(0)) { case VolumeFile::VOLUME_AXIS_X: rot.rotateX(-bmv->getDisplayRotation(0)); break; case VolumeFile::VOLUME_AXIS_Y: rot.rotateY(bmv->getDisplayRotation(0)); break; case VolumeFile::VOLUME_AXIS_Z: rot.rotateZ(-bmv->getDisplayRotation(0)); break; case VolumeFile::VOLUME_AXIS_ALL: break; case VolumeFile::VOLUME_AXIS_OBLIQUE: rot.setMatrix(bmv->getObliqueRotationMatrix()); rot.transpose(); break; case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: { TransformationMatrix* tmv = dsv->getObliqueSlicesTransformationMatrix(); if (tmv != NULL) { rot = *tmv; } else { rot.setMatrix(bmv->getObliqueRotationMatrix()); rot.transpose(); } //int sliceOffsets[3]; //bmv->getSelectedObliqueSliceOffsets(0, sliceOffsets); //rot.translate(sliceOffsets[0], sliceOffsets[1], sliceOffsets[2]); } break; case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } float scale[3]; bm->getScaling(0, scale); for (int j = 0; j < 3; j++) { if (scale[j] == 0.0) { scale[j] = 1.0; } scale[j] = 1.0 / scale[j]; } //rot.scale(scale); } else { rot.setMatrix(bm->getRotationTransformMatrix(0)); rot.transpose(); } currentMatrix->preMultiply(rot); float scale[3]; bm->getScaling(0, scale); currentMatrix->scale(scale); updateDialog(); return; } // // If updating axes // if (showAxesCheckBox->isChecked()) { if (currentMatrix == tm) { if (currentMatrix->getShowAxes()) { transferMatrixIntoDialog(); } } } } /** * update the dialog. */ void GuiTransformationMatrixDialog::updateDialog() { TransformationMatrix* previousMatrix = currentMatrix; matrixSelectionComboBox->clear(); TransformationMatrixFile* tmf = theMainWindow->getBrainSet()->getTransformationMatrixFile(); int numMatrices = tmf->getNumberOfMatrices(); if (numMatrices <= 0) { TransformationMatrix tm; tmf->addTransformationMatrix(tm); numMatrices = tmf->getNumberOfMatrices(); } if (numMatrices > 0) { int defaultItem = 0; for (int i = 0; i < numMatrices; i++) { const TransformationMatrix* tm = tmf->getTransformationMatrix(i); matrixSelectionComboBox->addItem(tm->getMatrixName()); if (currentMatrix == tm) { defaultItem = i; } } matrixSelectionComboBox->setCurrentIndex(defaultItem); if ((defaultItem >= 0) && (defaultItem < tmf->getNumberOfMatrices())) { currentMatrix = tmf->getTransformationMatrix(defaultItem); } } else { currentMatrix = NULL; } transferMatrixIntoDialog(); if (currentMatrix != previousMatrix) { clearUndoStack(); } // // Update the transform data files section // const int numTransformDataFiles = theMainWindow->getBrainSet()->getNumberOfTransformationDataFiles(); const int numExistingTransformDataFiles = static_cast(transformFileLabels.size()); // // Add items as needed // for (int i = numExistingTransformDataFiles; i < numTransformDataFiles; i++) { QLabel* label = new QLabel(""); transformFileLabels.push_back(label); GuiTransformationMatrixSelectionControl* msc = new GuiTransformationMatrixSelectionControl(0, theMainWindow->getBrainSet()->getTransformationMatrixFile(), true); msc->setNoneLabel("Do Not Display"); msc->setToolTip( "Use this control to choose the matrix\n" "that is used to display this transform\n" "data file."); QObject::connect(msc, SIGNAL(activated(int)), this, SLOT(slotTransformMatrixSelection())); transformFileMatrixControls.push_back(msc); transformDataFileGridLayout->addWidget(label, i + 1, 0); transformDataFileGridLayout->addWidget(msc, i + 1, 1); } // // Update items // for (int i = 0; i < numTransformDataFiles; i++) { AbstractFile* tdf = theMainWindow->getBrainSet()->getTransformationDataFile(i); transformFileLabels[i]->setText(FileUtilities::basename(tdf->getFileName())); transformFileLabels[i]->show(); transformFileMatrixControls[i]->show(); transformFileMatrixControls[i]->blockSignals(true); transformFileMatrixControls[i]->updateControl(); transformFileMatrixControls[i]->setSelectedMatrixIndex( tmf->getMatrixIndex(tdf->getAssociatedTransformationMatrix())); transformFileMatrixControls[i]->blockSignals(false); } // // Hide unneeded items // for (int i = numTransformDataFiles; i < numExistingTransformDataFiles; i++) { transformFileLabels[i]->hide(); transformFileMatrixControls[i]->hide(); } } /** * called when a matrix is selected for a data file. */ void GuiTransformationMatrixDialog::slotTransformMatrixSelection() { const int numTransformDataFiles = theMainWindow->getBrainSet()->getNumberOfTransformationDataFiles(); const int numExistingTransformDataFiles = static_cast(transformFileLabels.size()); if (numTransformDataFiles > numExistingTransformDataFiles) { std::cout << "PROGRAM ERROR: Number of transform data files exceeds those in dialog." << std::endl; return; } for (int i = 0; i < numTransformDataFiles; i++) { if (i < numExistingTransformDataFiles) { AbstractFile* af = theMainWindow->getBrainSet()->getTransformationDataFile(i); af->setAssociatedTransformationMatrix(transformFileMatrixControls[i]->getSelectedMatrix()); } } GuiBrainModelOpenGL::updateAllGL(); } /** * get the matrix view type. */ GuiTransformationMatrixDialog::MATRIX_VIEW_TYPE GuiTransformationMatrixDialog::getMatrixViewType() const { return static_cast(matrixViewTabWidget->currentIndex()); } /** * transfer dialog values into matrix. */ void GuiTransformationMatrixDialog::transferDialogValuesIntoMatrix() { if (currentMatrix != NULL) { switch (getMatrixViewType()) { case MATRIX_VIEW_MATRIX: for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { currentMatrix->setMatrixElement(i, j, matrixElementLineEdits[i][j]->text().toDouble()); } } transferMatrixIntoMatrixTransformSpinBoxes(); break; case MATRIX_VIEW_TRANSFORMATIONS: currentMatrix->identity(); currentMatrix->translate(matrixTranslateXDoubleSpinBox->value(), matrixTranslateYDoubleSpinBox->value(), matrixTranslateZDoubleSpinBox->value()); const double trans[3] = { matrixTranslateXDoubleSpinBox->value(), matrixTranslateYDoubleSpinBox->value(), matrixTranslateZDoubleSpinBox->value() }; const double rot[3] = { matrixRotateXDoubleSpinBox->value(), matrixRotateYDoubleSpinBox->value(), matrixRotateZDoubleSpinBox->value() }; const double scalem[3] = { matrixScaleXDoubleSpinBox->value(), matrixScaleYDoubleSpinBox->value(), matrixScaleZDoubleSpinBox->value() }; currentMatrix->setMatrix(trans, rot, scalem); transferMatrixIntoMatrixElementLineEdits(); break; } } } /** * transfer the matrix into the matrix element part of dialog. */ void GuiTransformationMatrixDialog::transferMatrixIntoMatrixElementLineEdits() { if (currentMatrix != NULL) { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { matrixElementLineEdits[i][j]->blockSignals(true); matrixElementLineEdits[i][j]->setText( QString::number(currentMatrix->getMatrixElement(i, j), 'f', 6)); matrixElementLineEdits[i][j]->blockSignals(false); } } } } /** * transfer the matrix into the matrix transformation spin boxes. */ void GuiTransformationMatrixDialog::transferMatrixIntoMatrixTransformSpinBoxes() { if (currentMatrix != NULL) { double tx, ty, tz; currentMatrix->getTranslation(tx, ty, tz); matrixTranslateXDoubleSpinBox->blockSignals(true); matrixTranslateXDoubleSpinBox->setValue(tx); matrixTranslateXDoubleSpinBox->blockSignals(false); matrixTranslateYDoubleSpinBox->blockSignals(true); matrixTranslateYDoubleSpinBox->setValue(ty); matrixTranslateYDoubleSpinBox->blockSignals(false); matrixTranslateZDoubleSpinBox->blockSignals(true); matrixTranslateZDoubleSpinBox->setValue(tz); matrixTranslateZDoubleSpinBox->blockSignals(false); double rx, ry, rz; currentMatrix->getRotationAngles(rx, ry, rz); matrixRotateXDoubleSpinBox->blockSignals(true); matrixRotateXDoubleSpinBox->setValue(rx); matrixRotateXDoubleSpinBox->blockSignals(false); matrixRotateYDoubleSpinBox->blockSignals(true); matrixRotateYDoubleSpinBox->setValue(ry); matrixRotateYDoubleSpinBox->blockSignals(false); matrixRotateZDoubleSpinBox->blockSignals(true); matrixRotateZDoubleSpinBox->setValue(rz); matrixRotateZDoubleSpinBox->blockSignals(false); double sx, sy, sz; currentMatrix->getScaling(sx, sy, sz); matrixScaleXDoubleSpinBox->blockSignals(true); matrixScaleXDoubleSpinBox->setValue(sx); matrixScaleXDoubleSpinBox->blockSignals(false); matrixScaleYDoubleSpinBox->blockSignals(true); matrixScaleYDoubleSpinBox->setValue(sy); matrixScaleYDoubleSpinBox->blockSignals(false); matrixScaleZDoubleSpinBox->blockSignals(true); matrixScaleZDoubleSpinBox->setValue(sz); matrixScaleZDoubleSpinBox->blockSignals(false); } } /** * transfer the matrix into the dialog. */ void GuiTransformationMatrixDialog::transferMatrixIntoDialog() { if (currentMatrix != NULL) { showAxesCheckBox->setChecked(currentMatrix->getShowAxes()); commentLabel->setText(currentMatrix->getMatrixComment()); transferMatrixIntoMatrixElementLineEdits(); transferMatrixIntoMatrixTransformSpinBoxes(); showAxesCheckBox->blockSignals(true); showAxesCheckBox->setChecked(currentMatrix->getShowAxes()); showAxesCheckBox->blockSignals(false); } } /** * called to close the dialog. */ void GuiTransformationMatrixDialog::slotCloseDialog() { QDialog::close(); } /** * create the operation section. */ QWidget* GuiTransformationMatrixDialog::createMatrixButtonsSection() { // // apply button // QPushButton* applyMatrixMainWindowButton = new QPushButton("Apply Matrix to\n" "Main Window..."); applyMatrixMainWindowButton->setAutoDefault(false); QObject::connect(applyMatrixMainWindowButton, SIGNAL(clicked()), this, SLOT(slotMatrixApplyMainWindow())); // // apply button // QPushButton* applyMatrixFileButton = new QPushButton("Apply Matrix to\n" "Transform Data File..."); applyMatrixFileButton->setAutoDefault(false); QObject::connect(applyMatrixFileButton, SIGNAL(clicked()), this, SLOT(slotMatrixApplyTransformDataFile())); // // load button // QPushButton* loadMatrixButton = new QPushButton("Load Matrix..."); loadMatrixButton->setAutoDefault(false); loadMatrixButton->hide(); QObject::connect(loadMatrixButton, SIGNAL(clicked()), this, SLOT(slotMatrixLoad())); // // new matrix button // QPushButton* newMatrixButton = new QPushButton("New Matrix..."); newMatrixButton->setAutoDefault(false); QObject::connect(newMatrixButton, SIGNAL(clicked()), this, SLOT(slotMatrixNew())); // // delete matrix button // QPushButton* deleteMatrixButton = new QPushButton("Delete Matrix..."); deleteMatrixButton->setAutoDefault(false); QObject::connect(deleteMatrixButton, SIGNAL(clicked()), this, SLOT(slotMatrixDelete())); // // copy matrix button // //QPushButton* copyMatrixButton = new QPushButton("Copy Matrix", // matrixButtonsGroupBox, // "copyMatrixButton"); //copyMatrixButton->setAutoDefault(false); //QObject::connect(copyMatrixButton, SIGNAL(clicked()), // this, SLOT(slotMatrixCopy())); // // paste matrix button // //QPushButton* pasteMatrixButton = new QPushButton("Paste Matrix", // matrixButtonsGroupBox, // "pasteMatrixButton"); //pasteMatrixButton->setAutoDefault(false); //QObject::connect(pasteMatrixButton, SIGNAL(clicked()), // this, SLOT(slotMatrixPaste())); // // attributes button // QPushButton* matrixAttributesButton = new QPushButton("Attributes..."); matrixAttributesButton->setAutoDefault(false); QObject::connect(matrixAttributesButton, SIGNAL(clicked()), this, SLOT(slotMatrixAttributes())); // // Group box and layout // QGroupBox* matrixButtonsGroupBox = new QGroupBox("File Operations"); QVBoxLayout* matrixButtonsLayout = new QVBoxLayout(matrixButtonsGroupBox); matrixButtonsLayout->addWidget(applyMatrixMainWindowButton); matrixButtonsLayout->addWidget(applyMatrixFileButton); matrixButtonsLayout->addWidget(loadMatrixButton); matrixButtonsLayout->addWidget(newMatrixButton); matrixButtonsLayout->addWidget(deleteMatrixButton); matrixButtonsLayout->addWidget(matrixAttributesButton); matrixButtonsLayout->addStretch(); return matrixButtonsGroupBox; } /** * called when new matrix button pressed. */ void GuiTransformationMatrixDialog::slotMatrixNew() { TransformationMatrixFile* tmf = theMainWindow->getBrainSet()->getTransformationMatrixFile(); std::ostringstream str; str << "Matrix " << TransformationMatrix::getMatrixNumberCounter(); std::vector labels, labelValues; labels.push_back("Matrix Name"); labelValues.push_back(str.str().c_str()); labels.push_back("Matrix Comment"); labelValues.push_back(""); QtMultipleInputDialog mid(this, "New Matrix", "", labels, labelValues, true, true); if (mid.exec() == QDialog::Accepted) { std::vector values; mid.getValues(values); TransformationMatrix tm; tm.setMatrixName(values[0]); tm.setMatrixComment(values[1]); tmf->addTransformationMatrix(tm); TransformationMatrix* oldMatrix = currentMatrix; double oldMatrixComponents[4][4]; if (oldMatrix != NULL) { oldMatrix->getMatrix(oldMatrixComponents); } currentMatrix = tmf->getTransformationMatrix(tmf->getNumberOfMatrices() - 1); currentMatrix->identity(); // // Choose matrix default values // std::vector itemLabels; itemLabels.push_back("Identity Matrix"); int currentMatrixIndex = -1; if (oldMatrix != NULL) { currentMatrixIndex = static_cast(itemLabels.size()); itemLabels.push_back("Use Current Matrix in Matrix Editor"); } int surfaceIndex = -1; float surfacePos[3]; BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { if (GuiBrainModelOpenGL::getMainWindowCenterModelCoordinate(surfacePos)) { surfaceIndex = static_cast(itemLabels.size()); itemLabels.push_back("Point at Center of Surface View"); } } int viewMatrixTranslateIndex = -1; BrainModel* bm = theMainWindow->getBrainModel(); if (bm != NULL) { viewMatrixTranslateIndex = static_cast(itemLabels.size()); itemLabels.push_back("Main Window Viewing Transformation Matrix (Translate Only)"); } int viewMatrixIndex = -1; if (bm != NULL) { viewMatrixIndex = static_cast(itemLabels.size()); itemLabels.push_back("Main Window Viewing Transformation Matrix (Translate and Rotate)"); } int volumeIndex = -1; float volumePos[3]; BrainModelVolume* bmv = theMainWindow->getBrainModelVolume(); if (bmv != NULL) { DisplaySettingsVolume* dsv = theMainWindow->getBrainSet()->getDisplaySettingsVolume(); switch (bmv->getSelectedAxis(0)) { case VolumeFile::VOLUME_AXIS_X: case VolumeFile::VOLUME_AXIS_Y: case VolumeFile::VOLUME_AXIS_Z: case VolumeFile::VOLUME_AXIS_ALL: { int slices[3]; bmv->getSelectedOrthogonalSlices(0, slices); VolumeFile* vf = bmv->getMasterVolumeFile(); if (vf != NULL) { float origin[3], spacing[3]; vf->getOrigin(origin); vf->getSpacing(spacing); volumePos[0] = origin[0] + spacing[0] * slices[0]; volumePos[1] = origin[1] + spacing[1] * slices[1]; volumePos[2] = origin[2] + spacing[2] * slices[2]; volumeIndex = static_cast(itemLabels.size()); itemLabels.push_back("Volume Crosshairs"); } } break; case VolumeFile::VOLUME_AXIS_OBLIQUE: { int slices[3]; bmv->getSelectedObliqueSlices(slices); VolumeFile* vf = bmv->getMasterVolumeFile(); if (vf != NULL) { float origin[3], spacing[3]; vf->getOrigin(origin); vf->getSpacing(spacing); volumePos[0] = origin[0] + spacing[0] * slices[0]; volumePos[1] = origin[1] + spacing[1] * slices[1]; volumePos[2] = origin[2] + spacing[2] * slices[2]; volumeIndex = static_cast(itemLabels.size()); itemLabels.push_back("Volume Crosshairs"); } } break; case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: { int slices[3]; const TransformationMatrix* obtm = dsv->getObliqueSlicesTransformationMatrix(); if (obtm != NULL) { float t[3]; obtm->getTranslation(t[0], t[1], t[2]); slices[0] = static_cast(t[0]); slices[1] = static_cast(t[1]); slices[2] = static_cast(t[2]); } else { //int slices[3]; bmv->getSelectedObliqueSlices(slices); } int sliceOffsets[3]; bmv->getSelectedObliqueSliceOffsets(0, sliceOffsets); VolumeFile* vf = bmv->getMasterVolumeFile(); if (vf != NULL) { float origin[3], spacing[3]; vf->getOrigin(origin); vf->getSpacing(spacing); volumePos[0] = origin[0] + spacing[0] * slices[0]; volumePos[1] = origin[1] + spacing[1] * slices[1]; volumePos[2] = origin[2] + spacing[2] * slices[2]; volumePos[0] += spacing[0] * sliceOffsets[0]; volumePos[1] += spacing[1] * sliceOffsets[1]; volumePos[2] += spacing[2] * sliceOffsets[2]; volumeIndex = static_cast(itemLabels.size()); itemLabels.push_back("Volume Crosshairs"); } } break; case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } } QtRadioButtonSelectionDialog rbd(&mid, "Initial Matrix Values", "", itemLabels, 0); if (rbd.exec() == QDialog::Accepted) { if (rbd.getSelectedItemIndex() > 0) { if (rbd.getSelectedItemIndex() == currentMatrixIndex) { if (oldMatrix != NULL) { currentMatrix->setMatrix(oldMatrixComponents); } } else if (rbd.getSelectedItemIndex() == surfaceIndex) { currentMatrix->identity(); currentMatrix->translate(surfacePos); } else if (rbd.getSelectedItemIndex() == volumeIndex) { currentMatrix->identity(); currentMatrix->translate(volumePos); } else if ((rbd.getSelectedItemIndex() == viewMatrixIndex) || (rbd.getSelectedItemIndex() == viewMatrixTranslateIndex)) { float obliqueSlicesPos[3]; if (bmv != NULL) { VolumeFile* vf = bmv->getMasterVolumeFile(); int obliqueSlices[3]; bmv->getSelectedObliqueSlices(obliqueSlices); vf->getVoxelCoordinate(obliqueSlices, obliqueSlicesPos); int obliqueSliceOffsets[3]; bmv->getSelectedObliqueSliceOffsets(0, obliqueSliceOffsets); } currentMatrix->identity(); float trans[3]; bm->getTranslation(0, trans); currentMatrix->translate(trans); TransformationMatrix rot; if (bmv != NULL) { switch (bmv->getSelectedAxis(0)) { case VolumeFile::VOLUME_AXIS_X: rot.rotateX(-bmv->getDisplayRotation(0)); break; case VolumeFile::VOLUME_AXIS_Y: rot.rotateY(bmv->getDisplayRotation(0)); break; case VolumeFile::VOLUME_AXIS_Z: rot.rotateZ(-bmv->getDisplayRotation(0)); break; case VolumeFile::VOLUME_AXIS_ALL: break; case VolumeFile::VOLUME_AXIS_OBLIQUE: currentMatrix->translate(obliqueSlicesPos[0], obliqueSlicesPos[1], obliqueSlicesPos[2]); rot.setMatrix(bmv->getObliqueRotationMatrix()); rot.transpose(); break; case VolumeFile::VOLUME_AXIS_OBLIQUE_X: currentMatrix->translate(obliqueSlicesPos[0], obliqueSlicesPos[1], obliqueSlicesPos[2]); rot.setMatrix(bmv->getObliqueRotationMatrix()); rot.rotateX(90.0); rot.transpose(); break; case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: currentMatrix->translate(obliqueSlicesPos[0], obliqueSlicesPos[1], obliqueSlicesPos[2]); rot.setMatrix(bmv->getObliqueRotationMatrix()); rot.rotateY(90.0); rot.transpose(); break; case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: currentMatrix->translate(obliqueSlicesPos[0], obliqueSlicesPos[1], obliqueSlicesPos[2]); rot.setMatrix(bmv->getObliqueRotationMatrix()); rot.transpose(); break; case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: break; case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } float scale[3]; bm->getScaling(0, scale); for (int j = 0; j < 3; j++) { if (scale[j] == 0.0) { scale[j] = 1.0; } scale[j] = 1.0 / scale[j]; } if (rbd.getSelectedItemIndex() == viewMatrixTranslateIndex) { // // Translate only so eliminate rotation // rot.identity(); } rot.scale(scale); currentMatrix->preMultiply(rot); } else { rot.setMatrix(bm->getRotationTransformMatrix(0)); rot.transpose(); currentMatrix->identity(); if (rbd.getSelectedItemIndex() != viewMatrixTranslateIndex) { currentMatrix->preMultiply(rot); } currentMatrix->translate(trans); } } } } updateDialog(); GuiFilesModified fm; fm.setTransformationMatrixModified(); theMainWindow->fileModificationUpdate(fm); updateMainWindowViewingMatrix(); } } /** * called when delete matrix button pressed. */ void GuiTransformationMatrixDialog::slotMatrixDelete() { if (currentMatrix != NULL) { if (QMessageBox::warning(this, "Confirm", "Are you sure you want to delete the current matrix ?", (QMessageBox::Yes | QMessageBox::No), QMessageBox::Yes) == QMessageBox::Yes) { TransformationMatrixFile* tmf = theMainWindow->getBrainSet()->getTransformationMatrixFile(); const int numMatrices = tmf->getNumberOfMatrices(); for (int i = 0; i < numMatrices; i++) { if (tmf->getTransformationMatrix(i) == currentMatrix) { tmf->deleteMatrix(i); bool axesOn = false; if (currentMatrix != NULL) { axesOn = currentMatrix->getShowAxes(); } currentMatrix = NULL; updateDialog(); GuiFilesModified fm; fm.setTransformationMatrixModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); break; } } } } } /** * called when matrix attributes button pressed. */ void GuiTransformationMatrixDialog::slotMatrixAttributes() { if (currentMatrix != NULL) { std::vector labels, labelValues; labels.push_back("Matrix Name"); labels.push_back("Matrix Comment"); labelValues.push_back(currentMatrix->getMatrixName()); labelValues.push_back(currentMatrix->getMatrixComment()); QtMultipleInputDialog mid(this, "Matrix Attributes", "", labels, labelValues, true, true); if (mid.exec() == QDialog::Accepted) { std::vector values; mid.getValues(values); currentMatrix->setMatrixName(values[0]); currentMatrix->setMatrixComment(values[1]); updateDialog(); } } } /** * called when copy matrix button pressed. */ void GuiTransformationMatrixDialog::slotMatrixCopy() { } /** * called when paste matrix button pressed. */ void GuiTransformationMatrixDialog::slotMatrixPaste() { } /** * called when apply matrix to transform data file button pressed. */ void GuiTransformationMatrixDialog::slotMatrixApplyTransformDataFile() { transferDialogValuesIntoMatrix(); const int num = theMainWindow->getBrainSet()->getNumberOfTransformationDataFiles(); // // Dialog for choosing transformation data files // WuQDataEntryDialog ded(this); ded.setWindowTitle("Apply Transformation"); std::vector checkBoxes; for (int i = 0; i < num; i++) { const AbstractFile* af = theMainWindow->getBrainSet()->getTransformationDataFile(i); QCheckBox* cb = ded.addCheckBox(FileUtilities::basename(af->getFileName()), false); checkBoxes.push_back(cb); } if (ded.exec() == QDialog::Accepted) { bool ok = false; QString commentString = QInputDialog::getText(this, "Enter Comment Information", "Enter Comment Describing Transform", QLineEdit::Normal, "", &ok); QString operationComment; if (ok) { if (commentString.isEmpty() == false) { operationComment.append("\n"); operationComment.append(commentString); } } else { return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); bool addedCells = false; bool addedContours = false; bool addedContourCells = false; bool addedFoci = false; bool addedVtkModelFile = false; for (int i = 0; i < num; i++) { if (checkBoxes[i]->isChecked()) { AbstractFile* af = theMainWindow->getBrainSet()->getTransformationDataFile(i); CellFile* cf = dynamic_cast(af); if ((cf != NULL) && (dynamic_cast(af) == NULL) && (dynamic_cast(af) == NULL)) { const int numCells = cf->getNumberOfCells(); if (numCells > 0) { addedCells = true; CellFile newCellFile; for (int j = 0; j < numCells; j++) { CellData cd = *(cf->getCell(j)); float xyz[3]; cd.getXYZ(xyz); currentMatrix->multiplyPoint(xyz); cd.setXYZ(xyz); if (xyz[0] < 0.0) { cd.setCellStructure(Structure::STRUCTURE_TYPE_CORTEX_LEFT); } else { cd.setCellStructure(Structure::STRUCTURE_TYPE_CORTEX_RIGHT); } newCellFile.addCell(cd); } newCellFile.setFileComment(operationComment); theMainWindow->getBrainSet()->getCellProjectionFile()->appendFiducialCellFile(newCellFile); } } FociFile* ff = dynamic_cast(af); if (ff != NULL) { const int numCells = ff->getNumberOfCells(); if (numCells > 0) { addedFoci = true; FociFile newFociFile; for (int j = 0; j < numCells; j++) { CellData cd = *(ff->getCell(j)); float xyz[3]; cd.getXYZ(xyz); currentMatrix->multiplyPoint(xyz); cd.setXYZ(xyz); if (xyz[0] < 0.0) { cd.setCellStructure(Structure::STRUCTURE_TYPE_CORTEX_LEFT); } else { cd.setCellStructure(Structure::STRUCTURE_TYPE_CORTEX_RIGHT); } newFociFile.addCell(cd); } newFociFile.setFileComment(operationComment); theMainWindow->getBrainSet()->getFociProjectionFile()->appendFiducialCellFile(newFociFile); } } ContourFile* crf = dynamic_cast(af); if (crf != NULL) { const int numContours = crf->getNumberOfContours(); if (numContours > 0) { addedContours = true; BrainModelContours* bmc = theMainWindow->getBrainSet()->getBrainModelContours(-1); if (bmc == NULL) { bmc = new BrainModelContours(theMainWindow->getBrainSet()); theMainWindow->getBrainSet()->addBrainModel(bmc); } ContourFile* contourFile = bmc->getContourFile(); contourFile->setSectionSpacing(crf->getSectionSpacing()); for (int j = 0; j < numContours; j++) { CaretContour* cc = crf->getContour(j); CaretContour caretContour; caretContour.setSectionNumber(cc->getSectionNumber()); for (int k = 0; k < cc->getNumberOfPoints(); k++) { float xyz[3]; cc->getPointXYZ(k, xyz[0], xyz[1], xyz[2]); currentMatrix->multiplyPoint(xyz); caretContour.addPoint(xyz[0], xyz[1], xyz[2]); } if (caretContour.getNumberOfPoints() > 0) { contourFile->addContour(caretContour); } } } } ContourCellFile* ccf = dynamic_cast(af); if (ccf != NULL) { const int numCells = ccf->getNumberOfCells(); if (numCells > 0) { addedContourCells = true; ContourCellFile* contourCells = theMainWindow->getBrainSet()->getContourCellFile(); for (int j = 0; j < numCells; j++) { CellData* cd = ccf->getCell(j); float xyz[3]; cd->getXYZ(xyz); currentMatrix->multiplyPoint(xyz); CellData newCell(cd->getName(), xyz[0], xyz[1], xyz[2]); newCell.setSectionNumber(static_cast(xyz[2] + 0.5)); contourCells->addCell(newCell); } contourCells->appendToFileComment(operationComment); } } VtkModelFile* vmf = dynamic_cast(af); if (vmf != NULL) { VtkModelFile* copyVMF = new VtkModelFile(*vmf); if (copyVMF != NULL) { copyVMF->applyTransformationMatrix(*currentMatrix); copyVMF->appendToFileComment(operationComment); copyVMF->setDisplayFlag(true); theMainWindow->getBrainSet()->addVtkModelFile(copyVMF); addedVtkModelFile = true; } } } } if (addedCells) { GuiFilesModified fm; fm.setCellModified(); theMainWindow->fileModificationUpdate(fm); theMainWindow->getBrainSet()->assignCellColors(); DisplaySettingsCells* dsc = theMainWindow->getBrainSet()->getDisplaySettingsCells(); dsc->setDisplayCells(true); GuiBrainModelOpenGL::updateAllGL(); } if (addedContours) { GuiFilesModified fm; fm.setContourModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } if (addedContourCells) { GuiFilesModified fm; fm.setContourCellModified(); theMainWindow->fileModificationUpdate(fm); theMainWindow->getBrainSet()->assignContourCellColors(); DisplaySettingsContours* dsc = theMainWindow->getBrainSet()->getDisplaySettingsContours(); dsc->setDisplayContourCells(true); GuiBrainModelOpenGL::updateAllGL(); } if (addedFoci) { GuiFilesModified fm; fm.setFociModified(); theMainWindow->fileModificationUpdate(fm); theMainWindow->getBrainSet()->assignFociColors(); DisplaySettingsFoci* dsf = theMainWindow->getBrainSet()->getDisplaySettingsFoci(); dsf->setDisplayCells(true); GuiBrainModelOpenGL::updateAllGL(); } if (addedVtkModelFile) { GuiFilesModified fm; fm.setVtkModelModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } QApplication::restoreOverrideCursor(); } } /** * called when apply matrix button pressed. */ void GuiTransformationMatrixDialog::slotMatrixApplyMainWindow() { transferDialogValuesIntoMatrix(); // // Dialog for choosing items getting transformed // WuQDataEntryDialog ded(this); ded.setWindowTitle("Apply Transformation"); QCheckBox* contourCheckBox = NULL; QCheckBox* contourCellCheckBox = NULL; QCheckBox* surfaceCheckBox = NULL; QCheckBox* volumeCheckBox = NULL; QCheckBox* surfaceVolumeCheckBox = NULL; BrainModelContours* bmc = theMainWindow->getBrainModelContours(); BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); BrainModelVolume* bmv = theMainWindow->getBrainModelVolume(); BrainModelSurfaceAndVolume* bmsv = theMainWindow->getBrainModelSurfaceAndVolume(); if (bmsv != NULL) { surfaceVolumeCheckBox = ded.addCheckBox("Main Window Surface And Volume", false); } else if (bms != NULL) { surfaceCheckBox = ded.addCheckBox("Main Window Surface", false); } else if (bmv != NULL) { volumeCheckBox = ded.addCheckBox("Main Window Volume", false); } else if (bmc != NULL) { contourCheckBox = ded.addCheckBox("Main Window Contours", false); contourCellCheckBox = ded.addCheckBox("Main Window Contour Cells", false); } QCheckBox* surfaceBordersCheckBox = NULL; BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); if (bms != NULL) { const int brainModelIndex = theMainWindow->getBrainSet()->getBrainModelIndex(bms); if (brainModelIndex < 0) { std::cout << "PROGRAM ERROR: invalid brain model index at " << __LINE__ << " in " << __FILE__ << std::endl; return; } const int num = bmbs->getNumberOfBorders(); for (int i = 0; i < num; i++) { const BrainModelBorder* b = bmbs->getBorder(i); if (b->getValidForBrainModel(brainModelIndex) && b->getDisplayFlag()) { surfaceBordersCheckBox = ded.addCheckBox("Main Window Surface Borders", false); break; } } } QCheckBox* volumeBordersCheckBox = NULL; if (bmv != NULL) { BorderFile* bf = theMainWindow->getBrainSet()->getVolumeBorderFile(); if (bf->getNumberOfBorders() > 0) { volumeBordersCheckBox = ded.addCheckBox("Main Window Volume Borders", false); } } bool fiducialFlag = false; if (bms != NULL) { fiducialFlag = ((bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_RAW) || (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FIDUCIAL)); } QCheckBox* cellsCheckBox = NULL; if (fiducialFlag) { CellProjectionFile* cf = theMainWindow->getBrainSet()->getCellProjectionFile(); if (cf->getNumberOfCellProjections() > 0) { cellsCheckBox = ded.addCheckBox("Main Window Cells", false); } } QCheckBox* fociCheckBox = NULL; if (fiducialFlag) { FociProjectionFile* ff = theMainWindow->getBrainSet()->getFociProjectionFile(); if (ff->getNumberOfCellProjections() > 0) { fociCheckBox = ded.addCheckBox("Main Window Foci", false); } } QCheckBox* vectorsCheckBox = NULL; if (fiducialFlag) { if (theMainWindow->getBrainSet()->getNumberOfVectorFiles() > 0) { vectorsCheckBox = ded.addCheckBox("Main Window Vectors", false); } } if (ded.exec() == QDialog::Accepted) { bool ok = false; QString commentString = QInputDialog::getText(this, "Enter Comment Information", "Enter Comment Describing Transform", QLineEdit::Normal, "", &ok); QString operationComment; if (ok) { if (commentString.isEmpty() == false) { operationComment.append("\n"); operationComment.append(commentString); } } else { return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); if (surfaceCheckBox != NULL) { if (surfaceCheckBox->isChecked()) { bms->applyTransformationMatrix(*currentMatrix); bms->setToStandardView(0, BrainModelSurface::VIEW_RESET); bms->appendToCoordinateFileComment(operationComment); } } if (volumeCheckBox != NULL) { if (volumeCheckBox->isChecked()) { /* TransformationMatrix tm(*currentMatrix); float trans[3]; tm.getTranslation(trans[0], trans[1], trans[2]); tm.translate(0.0, 0.0, 0.0); tm.transpose(); tm.translate(trans[0], trans[1], trans[2]); */ VolumeFile* primaryOverlay = bmv->getOverlayPrimaryVolumeFile(); TransformationMatrix tm = *currentMatrix; for (int j = 0; j < 3; j++) { float f = tm.getMatrixElement(j, 3); f = -f; tm.setMatrixElement(j, 3, f); } tm.transpose(); if (primaryOverlay != NULL) { primaryOverlay->applyTransformationMatrix(tm); primaryOverlay->appendToFileComment(operationComment); } VolumeFile* secondaryOverlay = bmv->getOverlaySecondaryVolumeFile(); if (secondaryOverlay != NULL) { secondaryOverlay->applyTransformationMatrix(tm); secondaryOverlay->appendToFileComment(operationComment); } VolumeFile* underlay = bmv->getUnderlayVolumeFile(); if (underlay != NULL) { underlay->applyTransformationMatrix(tm); underlay->appendToFileComment(operationComment); } } } if (contourCheckBox != NULL) { if (contourCheckBox->isChecked()) { ContourFile* cf = bmc->getContourFile(); cf->applyTransformationMatrix(std::numeric_limits::min(), std::numeric_limits::max(), *currentMatrix, false); } } if (contourCellCheckBox != NULL) { if (contourCellCheckBox->isChecked()) { ContourCellFile* ccf = theMainWindow->getBrainSet()->getContourCellFile(); ccf->applyTransformationMatrix(*currentMatrix); } } if (surfaceVolumeCheckBox != NULL) { if (surfaceVolumeCheckBox->isChecked()) { bmsv->applyTransformationMatrix(*currentMatrix); bmsv->setToStandardView(0, BrainModelSurface::VIEW_RESET); bmsv->appendToCoordinateFileComment(operationComment); } } if (surfaceBordersCheckBox != NULL) { if (surfaceBordersCheckBox->isChecked()) { BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); bmbs->applyTransformationMatrix(bms, *currentMatrix); BrainModelBorderFileInfo* bmbfi = bmbs->getBorderFileInfo(bms->getSurfaceType()); if (bmbfi != NULL) { if (operationComment.isEmpty() == false) { QString fileComment(bmbfi->getFileComment()); fileComment.append(operationComment); bmbfi->setFileComment(fileComment); } } } } if (volumeBordersCheckBox != NULL) { if (volumeBordersCheckBox->isChecked()) { BorderFile* bf = theMainWindow->getBrainSet()->getVolumeBorderFile(); bf->applyTransformationMatrix(*currentMatrix); bf->appendToFileComment(operationComment); } } if (cellsCheckBox != NULL) { if (cellsCheckBox->isChecked()) { CellProjectionFile* cf = theMainWindow->getBrainSet()->getCellProjectionFile(); cf->applyTransformationMatrix(bms->getCoordinateFile(), bms->getTopologyFile(), fiducialFlag, std::numeric_limits::min(), std::numeric_limits::max(), *currentMatrix, false); cf->appendToFileComment(operationComment); } } if (fociCheckBox != NULL) { if (fociCheckBox->isChecked()) { FociProjectionFile* ff = theMainWindow->getBrainSet()->getFociProjectionFile(); ff->applyTransformationMatrix(bms->getCoordinateFile(), bms->getTopologyFile(), fiducialFlag, std::numeric_limits::min(), std::numeric_limits::max(), *currentMatrix, false); ff->appendToFileComment(operationComment); } } if (vectorsCheckBox != NULL) { if (vectorsCheckBox->isChecked()) { for (int m = 0; m < theMainWindow->getBrainSet()->getNumberOfVectorFiles(); m++) { VectorFile* vf = theMainWindow->getBrainSet()->getVectorFile(m); vf->applyTransformationMatrix(*currentMatrix); vf->appendToFileComment(operationComment); } } } theMainWindow->getBrainSet()->clearAllDisplayLists(); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } } /** * called when load matrix button pressed. */ void GuiTransformationMatrixDialog::slotMatrixLoad() { } /** * get main window transform matrix. */ vtkTransform* GuiTransformationMatrixDialog::getMainWindowRotationTransform() { BrainModelSurfaceAndVolume* bmsv = theMainWindow->getBrainModelSurfaceAndVolume(); if (bmsv != NULL) { return bmsv->getRotationTransformMatrix(0); } BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { return bms->getRotationTransformMatrix(0); } BrainModelVolume* bmv = theMainWindow->getBrainModelVolume(); if (bmv != NULL) { return bmv->getRotationTransformMatrix(0); } BrainModelContours* bmc = theMainWindow->getBrainModelContours(); if (bmc != NULL) { return bmc->getRotationTransformMatrix(0); } return NULL; } /** * add current matrix values to the undo stack. */ void GuiTransformationMatrixDialog::addMatrixToUndoStack() { if (currentMatrix != NULL) { undoMatrixStack.push(UndoMatrix(currentMatrix)); } enableDisableUndoPushButton(); } /** * called to pop a matrix off the undo stack. */ void GuiTransformationMatrixDialog::slotUndoPushButton() { if (undoMatrixStack.empty() == false) { UndoMatrix ums = undoMatrixStack.top(); undoMatrixStack.pop(); if (currentMatrix != NULL) { ums.getMatrix(currentMatrix); transferMatrixIntoDialog(); if (currentMatrix->getShowAxes()) { GuiBrainModelOpenGL::updateAllGL(); } } } enableDisableUndoPushButton(); } /** * enable/disable the undo button. */ void GuiTransformationMatrixDialog::enableDisableUndoPushButton() { undoPushButton->setEnabled(undoMatrixStack.empty() == false); } /** * clear the undo stack */ void GuiTransformationMatrixDialog::clearUndoStack() { while (undoMatrixStack.empty() == false) { undoMatrixStack.pop(); } enableDisableUndoPushButton(); } /** * called when the axes is moved int the main window with mouse or keyboard. */ void GuiTransformationMatrixDialog::axesEventInMainWindow() { addMatrixToUndoStack(); } /** * update the main window viewing matrix. */ void GuiTransformationMatrixDialog::updateMainWindowViewingMatrix() { bool redrawFlag = false; BrainModelVolume* bmv = theMainWindow->getBrainModelVolume(); BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); // // Is matrix yoked to main window viewing matrix // if (yokeToMainWindowCheckBox->isChecked()) { redrawFlag = true; // // Get transformations from matrix // BrainModel* bm = theMainWindow->getBrainModel(); if (bm != NULL) { float t[3]; currentMatrix->getTranslation(t[0], t[1], t[2]); bm->setTranslation(BrainModel:: BRAIN_MODEL_VIEW_MAIN_WINDOW, t); float rx, ry, rz; currentMatrix->getRotationAngles(rx, ry, rz); TransformationMatrix rot; const double zeros[3] = { 0.0, 0.0, 0.0 }; const double ones[3] = { 1.0, 1.0, 1.0 }; const double r[3] = { rx, ry, rz }; rot.setMatrix(zeros, r, ones); float mat[16]; rot.getMatrix(mat); if (bms != NULL) { bms->setRotationMatrix(BrainModel:: BRAIN_MODEL_VIEW_MAIN_WINDOW, mat); } if (bmv != NULL) { switch (bmv->getSelectedAxis(0)) { case VolumeFile::VOLUME_AXIS_X: case VolumeFile::VOLUME_AXIS_Y: case VolumeFile::VOLUME_AXIS_Z: case VolumeFile::VOLUME_AXIS_ALL: bmv->setRotationMatrix(BrainModel:: BRAIN_MODEL_VIEW_MAIN_WINDOW, mat); break; case VolumeFile::VOLUME_AXIS_OBLIQUE: bmv->setObliqueRotationMatrix(mat); break; case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: { DisplaySettingsVolume* dsv = theMainWindow->getBrainSet()->getDisplaySettingsVolume(); TransformationMatrix* obtm = dsv->getObliqueSlicesTransformationMatrix(); if (obtm != NULL) { obtm->setMatrix(mat); } else { bmv->setObliqueRotationMatrix(mat); } } break; case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } } float sx, sy, sz; currentMatrix->getScaling(sx, sy, sz); bm->setScaling(BrainModel:: BRAIN_MODEL_VIEW_MAIN_WINDOW, sx, sy, sz); } } // // Are there oblique brain model volume slices displayed // if (bmv != NULL) { DisplaySettingsVolume* dsv = theMainWindow->getBrainSet()->getDisplaySettingsVolume(); if (dsv->getObliqueSlicesTransformationMatrix() == currentMatrix) { if (GuiBrainModelOpenGL::viewingObliqueSlice()) { redrawFlag = true; } } } if (redrawFlag) { GuiBrainModelOpenGL::updateAllGL(); } } //===================================================================================== /** * Constructor. */ GuiTransformationMatrixDialog::UndoMatrix::UndoMatrix(const TransformationMatrix* tm) { double m[16]; tm->getMatrix(m); for (int i = 0; i < 16; i++) { mm[i] = m[i]; } } /** * Destructor. */ GuiTransformationMatrixDialog::UndoMatrix::UndoMatrix() { } /** * get the matrix. */ void GuiTransformationMatrixDialog::UndoMatrix::getMatrix(TransformationMatrix* tm) const { tm->setMatrix(mm); } caret-5.6.4~dfsg.1.orig/caret/GuiTopologyTypeComboBox.h0000664000175000017500000000336011572067322022606 0ustar michaelmichael #ifndef __GUI_TOPOLOGY_TYPE_COMBO_BOX_H__ #define __GUI_TOPOLOGY_TYPE_COMBO_BOX_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "TopologyFile.h" /// combo box for choosing a topology type class GuiTopologyTypeComboBox : public QComboBox { Q_OBJECT public: // constructor GuiTopologyTypeComboBox(const bool showUnknown = true, QWidget* parent = 0); // constructor GuiTopologyTypeComboBox(const std::vector showTheseTypes, QWidget* parent = 0); // destructor ~GuiTopologyTypeComboBox(); // set topology type void setTopologyType(const TopologyFile::TOPOLOGY_TYPES st); // get topology type TopologyFile::TOPOLOGY_TYPES getTopologyType() const; protected: }; #endif // __GUI_TOPOLOGY_TYPE_COMBO_BOX_H__ caret-5.6.4~dfsg.1.orig/caret/GuiTopologyTypeComboBox.cxx0000664000175000017500000000572711572067322023172 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "GuiTopologyTypeComboBox.h" /** * constructor. */ GuiTopologyTypeComboBox::GuiTopologyTypeComboBox(const bool showUnknown, QWidget* parent) : QComboBox(parent) { addItem(TopologyFile::getPerimeterIDFromTopologyType(TopologyFile::TOPOLOGY_TYPE_CLOSED), static_cast(TopologyFile::TOPOLOGY_TYPE_CLOSED)); addItem(TopologyFile::getPerimeterIDFromTopologyType(TopologyFile::TOPOLOGY_TYPE_OPEN), static_cast(TopologyFile::TOPOLOGY_TYPE_OPEN)); addItem(TopologyFile::getPerimeterIDFromTopologyType(TopologyFile::TOPOLOGY_TYPE_CUT), static_cast(TopologyFile::TOPOLOGY_TYPE_CUT)); addItem(TopologyFile::getPerimeterIDFromTopologyType(TopologyFile::TOPOLOGY_TYPE_LOBAR_CUT), static_cast(TopologyFile::TOPOLOGY_TYPE_LOBAR_CUT)); if (showUnknown) { addItem(TopologyFile::getPerimeterIDFromTopologyType(TopologyFile::TOPOLOGY_TYPE_UNKNOWN), static_cast(TopologyFile::TOPOLOGY_TYPE_UNKNOWN)); setTopologyType(TopologyFile::TOPOLOGY_TYPE_UNKNOWN); } } /** * constructor. */ GuiTopologyTypeComboBox::GuiTopologyTypeComboBox(const std::vector showTheseTypes, QWidget* parent) : QComboBox(parent) { for (unsigned int i = 0; i < showTheseTypes.size(); i++) { const TopologyFile::TOPOLOGY_TYPES st = showTheseTypes[i]; addItem(TopologyFile::getPerimeterIDFromTopologyType(st), static_cast(st)); } } /** * destructor. */ GuiTopologyTypeComboBox::~GuiTopologyTypeComboBox() { } /** * set topology type. */ void GuiTopologyTypeComboBox::setTopologyType(const TopologyFile::TOPOLOGY_TYPES st) { for (int i = 0; i < count(); i++) { if (itemData(i).toInt() == static_cast(st)) { setCurrentIndex(i); return; } } } /** * get topology type. */ TopologyFile::TOPOLOGY_TYPES GuiTopologyTypeComboBox::getTopologyType() const { return static_cast(itemData(currentIndex()).toInt()); } caret-5.6.4~dfsg.1.orig/caret/GuiTopologyFileComboBox.h0000664000175000017500000000357511572067322022554 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_TOPOLOGY_FILE_COMBO_BOX_H__ #define __GUI_TOPOLOGY_FILE_COMBO_BOX_H__ #include #include class TopologyFile; /// class for combo box used for selecting a topology file class GuiTopologyFileComboBox : public QComboBox { public: /// Constructor GuiTopologyFileComboBox(QWidget* parent = 0, const char* name = 0); /// Destructor ~GuiTopologyFileComboBox(); /// get the selected topology file TopologyFile* getSelectedTopologyFile() const; /// get the selected topology file index int getSelectedTopologyFileIndex() const; /// set the selected topology file void setSelectedTopologyFile(const TopologyFile* tf); /// update the items in the combo box void updateComboBox(); private: /// keeps track of topology files std::vector topologyFilePointers; }; #endif // __GUI_TOPOLOGY_FILE_COMBO_BOX_H__ caret-5.6.4~dfsg.1.orig/caret/GuiTopologyFileComboBox.cxx0000664000175000017500000000613211572067322023117 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainSet.h" #include "GuiMainWindow.h" #include "GuiTopologyFileComboBox.h" #include "TopologyFile.h" #include "global_variables.h" /** * Constructor. */ GuiTopologyFileComboBox::GuiTopologyFileComboBox(QWidget* parent, const char* /*name*/) : QComboBox(parent) { updateComboBox(); } /** * Destructor. */ GuiTopologyFileComboBox::~GuiTopologyFileComboBox() { } /** * set the selected topology file. */ void GuiTopologyFileComboBox::setSelectedTopologyFile(const TopologyFile* tf) { if (tf != NULL) { for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfTopologyFiles(); i++) { if (tf == theMainWindow->getBrainSet()->getTopologyFile(i)) { setCurrentIndex(i); break; } } } } /** * get the selected topology file. */ TopologyFile* GuiTopologyFileComboBox::getSelectedTopologyFile() const { const int index = getSelectedTopologyFileIndex(); if (index >= 0) { return topologyFilePointers[index]; } return NULL; } /** * get the selected topology file index. */ int GuiTopologyFileComboBox::getSelectedTopologyFileIndex() const { const int index = currentIndex(); if ((index >= 0) && (index < count())) { return index; } return -1; } /** * update the items in the combo box. */ void GuiTopologyFileComboBox::updateComboBox() { // // Find currently selected topology file // TopologyFile* defaultTopologyFile = NULL; const int index = currentIndex(); if ((index >= 0) && (index < count())) { defaultTopologyFile = topologyFilePointers[index]; } // // Clear out the topology selections // clear(); topologyFilePointers.clear(); // // Load up the topology files // int defaultIndex = 0; const int num = theMainWindow->getBrainSet()->getNumberOfTopologyFiles(); for (int i = 0; i < num; i++) { TopologyFile* tf = theMainWindow->getBrainSet()->getTopologyFile(i); topologyFilePointers.push_back(tf); addItem(tf->getDescriptiveName()); if (tf == defaultTopologyFile) { defaultIndex = i; } } if (count() > 0) { setCurrentIndex(defaultIndex); } } caret-5.6.4~dfsg.1.orig/caret/GuiToolBarActions.h0000664000175000017500000001405511572067322021365 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_TOOLBAR_ACTIONS_H__ #define __GUI_TOOLBAR_ACTIONS_H__ #include #include "BrainModel.h" class GuiBrainModelOpenGL; class GuiToolBar; class QAction; /// ToolBar actions class GuiToolBarActions : public QObject { Q_OBJECT public: /// Constructor GuiToolBarActions(GuiBrainModelOpenGL* brainModelOpenGLIn, GuiToolBar* myParentToolbarIn = 0); /// Destructor ~GuiToolBarActions(); /// action for view mode QAction* getViewModeAction() { return viewModeAction; } /// action for medial view QAction* getMedialViewAction() { return medialViewAction; } /// action for lateral view QAction* getLateralViewAction() { return lateralViewAction; } /// action for anterior view QAction* getAnteriorViewAction() { return anteriorViewAction; } /// action for posterior QAction* getPosteriorViewAction() { return posteriorViewAction; } /// action for dorsal view QAction* getDorsalViewAction() { return dorsalViewAction; } /// action for ventral view QAction* getVentralViewAction() { return ventralViewAction; } /// action for reset view QAction* getResetViewAction() { return resetViewAction; } /// action for x rotation 90 QAction* getXRotation90Action() { return xRotation90Action; } /// action for y rotation 90 QAction* getYRotation90Action() { return yRotation90Action; } /// action for z rotation 90 QAction* getZRotation90Action() { return zRotation90Action; } /// action for display control dialog QAction* getDisplayControlDialogAction() { return displayControlDialogAction; } /// action for spec dialog QAction* getSpecDialogAction() { return specDialogAction; } /// action for yoke QAction* getYokeAction() { return yokeAction; } /// action for swap with main window QAction* getSwapAction() { return swapAction; } // action for volume underlay only QAction* getUnderlayVolumeOnlyAction() { return volumeUnderlayOnlyAction; } public slots: // called when View Mode tool button is selected void viewModeSlot(); // called when medial view tool button is selected void medialViewSlot(); // called when lateral view tool button is selected void lateralViewSlot(); // called when anterior view tool button is selected void anteriorViewSlot(); // called when posterior view tool button is selected void posteriorViewSlot(); // called when dorsal view tool button is selected void dorsalViewSlot(); // called when ventral view tool button is selected void ventralViewSlot(); // called when reset view tool button is selected void resetViewSlot(); // called when X rotation 90 tool button is selected void xRotation90Slot(); // called when Y rotation 90 tool button is selected void yRotation90Slot(); // called when Z rotation 90 tool button is selected void zRotation90Slot(); // called when display control button pressed void displayControlDialogSlot(); // called when spec button pressed void specDialogSlot(); // called when yoke button toggled void yokeSlot(bool b); // called when swap button set void swapSlot(); // Called when a standard view is selected. void setViewSelection(const BrainModel::STANDARD_VIEWS standardView); // called when underlay only button toggled void underlayOnlySlot(bool b); protected: /// Called when a rotation axis is selected. void setRotationSelection(int axis); /// the OpenGL widget for the actions GuiBrainModelOpenGL* brainModelOpenGL; /// action for view mode QAction* viewModeAction; /// action for medial view QAction* medialViewAction; /// action for lateral view QAction* lateralViewAction; /// action for anterior view QAction* anteriorViewAction; /// action for posterior QAction* posteriorViewAction; /// action for dorsal view QAction* dorsalViewAction; /// action for ventral view QAction* ventralViewAction; /// action for reset view QAction* resetViewAction; /// action for x rotation 90 QAction* xRotation90Action; /// action for y rotation 90 QAction* yRotation90Action; /// action for z rotation 90 QAction* zRotation90Action; /// action for display control dialog QAction* displayControlDialogAction; /// action for spec dialog QAction* specDialogAction; /// action for yoking QAction* yokeAction; /// action for swap with main window QAction* swapAction; /// action for volume underlay only QAction* volumeUnderlayOnlyAction; /// my parent toolbar GuiToolBar* parentToolBar; }; #endif // __GUI_TOOLBAR_ACTIONS_H__ caret-5.6.4~dfsg.1.orig/caret/GuiToolBarActions.cxx0000664000175000017500000004146111572067322021741 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelContours.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceAndVolume.h" #include "BrainModelVolume.h" #include "GuiBrainModelOpenGL.h" #include "GuiMainWindow.h" #include "GuiToolBar.h" #include "GuiToolBarActions.h" #include "global_variables.h" /** * Constructor. * Parent is the window that this toolbar is being added to. * mainWindowIn is Caret's main window. * mainWindowFlag is set if this tool bar is being added to Caret's main window. */ GuiToolBarActions::GuiToolBarActions(GuiBrainModelOpenGL* brainModelOpenGLIn, GuiToolBar* myParentToolBarIn) : QObject(myParentToolBarIn) { parentToolBar = myParentToolBarIn; brainModelOpenGL = brainModelOpenGLIn; viewModeAction = new QAction(this); viewModeAction->setText("View"); viewModeAction->setToolTip("Set Mouse Mode to View"); QObject::connect(viewModeAction, SIGNAL(triggered()), this, SLOT(viewModeSlot())); medialViewAction = new QAction(this); medialViewAction->setText("M"); medialViewAction->setToolTip("Switch to Medial View of Surface"); QObject::connect(medialViewAction, SIGNAL(triggered()), this, SLOT(medialViewSlot())); lateralViewAction = new QAction(this); lateralViewAction->setText("L"); lateralViewAction->setToolTip("Switch to Lateral View of Surface"); QObject::connect(lateralViewAction, SIGNAL(triggered()), this, SLOT(lateralViewSlot())); anteriorViewAction = new QAction(this); anteriorViewAction->setText("A"); anteriorViewAction->setToolTip("Switch to Anterior View of Surface"); QObject::connect(anteriorViewAction, SIGNAL(triggered()), this, SLOT(anteriorViewSlot())); posteriorViewAction = new QAction(this); posteriorViewAction->setText("P"); posteriorViewAction->setToolTip("Switch to Posterior View of Surface"); QObject::connect(posteriorViewAction, SIGNAL(triggered()), this, SLOT(posteriorViewSlot())); dorsalViewAction = new QAction(this); dorsalViewAction->setText("D"); dorsalViewAction->setToolTip("Switch to Dorsal View of Surface"); QObject::connect(dorsalViewAction, SIGNAL(triggered()), this, SLOT(dorsalViewSlot())); ventralViewAction = new QAction(this); ventralViewAction->setText("V"); ventralViewAction->setToolTip("Switch to Ventral View of Surface"); QObject::connect(ventralViewAction, SIGNAL(triggered()), this, SLOT(ventralViewSlot())); resetViewAction = new QAction(this); resetViewAction->setText("R"); resetViewAction->setToolTip("Reset the View of Model"); QObject::connect(resetViewAction, SIGNAL(triggered()), this, SLOT(resetViewSlot())); xRotation90Action = new QAction(this); xRotation90Action->setText("X"); xRotation90Action->setToolTip("Rotate Surface 90 Degress Around X Axis"); QObject::connect(xRotation90Action, SIGNAL(triggered()), this, SLOT(xRotation90Slot())); yRotation90Action = new QAction(this); yRotation90Action->setText("Y"); yRotation90Action->setToolTip("Rotate Surface 90 Degress Around Y Axis"); QObject::connect(yRotation90Action, SIGNAL(triggered()), this, SLOT(yRotation90Slot())); zRotation90Action = new QAction(this); zRotation90Action->setText("Z"); zRotation90Action->setToolTip("Rotate Surface 90 Degress Around Z Axis"); QObject::connect(zRotation90Action, SIGNAL(triggered()), this, SLOT(zRotation90Slot())); displayControlDialogAction = new QAction(this); displayControlDialogAction->setText("D/C"); displayControlDialogAction->setToolTip("Show Display Control Dialog"); QObject::connect(displayControlDialogAction, SIGNAL(triggered()), this, SLOT(displayControlDialogSlot())); specDialogAction = new QAction(this); specDialogAction->setText("Spec"); specDialogAction->setToolTip("Quickly open file from spec file."); QObject::connect(specDialogAction, SIGNAL(triggered()), this, SLOT(specDialogSlot())); yokeAction = new QAction(this); yokeAction->setText("Yoke"); yokeAction->setCheckable(true); yokeAction->setToolTip("Selecting Yoke will set the view of\n" "model in this window to the view used\n" "in the main window."); QObject::connect(yokeAction, SIGNAL(triggered(bool)), this, SLOT(yokeSlot(bool))); swapAction = new QAction(this); swapAction->setText("Swap"); swapAction->setToolTip("Swap the brain model in this \n" "viewing window with the brain \n" "model in the main window."); QAction::connect(swapAction, SIGNAL(triggered()), this, SLOT(swapSlot())); volumeUnderlayOnlyAction = new QAction(this); volumeUnderlayOnlyAction->setText("UO"); volumeUnderlayOnlyAction->setCheckable(true); volumeUnderlayOnlyAction->setToolTip("Selecting Underlay Only will inhibit\n" "the display of overlays on volume \n" "slices in this window. This may be \n" "useful when editing a segmentation \n" "volume in the Main Window."); QObject::connect(volumeUnderlayOnlyAction, SIGNAL(triggered(bool)), this, SLOT(underlayOnlySlot(bool))); } /** * Destructor. */ GuiToolBarActions::~GuiToolBarActions() { } /** * Called when a standard view is selected. */ void GuiToolBarActions::setViewSelection(const BrainModel::STANDARD_VIEWS standardView) { BrainModel* bm = brainModelOpenGL->getDisplayedBrainModel(); if (bm != NULL) { switch (bm->getModelType()) { case BrainModel::BRAIN_MODEL_SURFACE: { BrainModelSurface* s = dynamic_cast(bm); // // If yoked set the view of the caret main window // bool surfaceYokedFlag = false; BrainModelSurface* mainWindowModelSurface = NULL; GuiBrainModelOpenGL* mainWindowBrainModelOpenGL = NULL; int mainWindowModelViewNumber = -1; if (brainModelOpenGL->getYokeView()) { surfaceYokedFlag = GuiBrainModelOpenGL::getCaretMainWindowModelInfo(mainWindowModelSurface, mainWindowBrainModelOpenGL, mainWindowModelViewNumber); } // // Might be yoked to volume // bool volumeYokedFlag = false; BrainModelVolume* bmv = theMainWindow->getBrainModelVolume(); if (brainModelOpenGL->getYokeView()) { if (bmv != NULL) { if (bmv->getSelectedAxis(0) == VolumeFile::VOLUME_AXIS_OBLIQUE) { volumeYokedFlag = true; } } } if (surfaceYokedFlag) { mainWindowModelSurface->setToStandardView(mainWindowModelViewNumber, standardView); } else if (volumeYokedFlag) { bmv->setToStandardView(0, standardView); } else { s->setToStandardView(brainModelOpenGL->getModelViewNumber(), standardView); } if (brainModelOpenGL->getModelViewNumber() == BrainModel:: BRAIN_MODEL_VIEW_MAIN_WINDOW) { theMainWindow->updateTransformationMatrixEditor(NULL); } GuiBrainModelOpenGL::updateAllGL(brainModelOpenGL); } break; case BrainModel::BRAIN_MODEL_SURFACE_AND_VOLUME: { BrainModelSurfaceAndVolume* s = dynamic_cast(bm); s->setToStandardView(brainModelOpenGL->getModelViewNumber(), standardView); if (brainModelOpenGL->getModelViewNumber() == BrainModel:: BRAIN_MODEL_VIEW_MAIN_WINDOW) { theMainWindow->updateTransformationMatrixEditor(NULL); } GuiBrainModelOpenGL::updateAllGL(brainModelOpenGL); } break; case BrainModel::BRAIN_MODEL_CONTOURS: { BrainModelContours* bmc = dynamic_cast(bm); bmc->resetViewingTransform(brainModelOpenGL->getModelViewNumber()); if (brainModelOpenGL->getModelViewNumber() == BrainModel:: BRAIN_MODEL_VIEW_MAIN_WINDOW) { theMainWindow->updateTransformationMatrixEditor(NULL); } GuiBrainModelOpenGL::updateAllGL(brainModelOpenGL); } break; case BrainModel::BRAIN_MODEL_VOLUME: { BrainModelVolume* bmv = dynamic_cast(bm); bmv->resetViewingTransform(brainModelOpenGL->getModelViewNumber()); bmv->initializeSelectedSlices(brainModelOpenGL->getModelViewNumber(), false); GuiToolBar::updateAllToolBars(false); if (brainModelOpenGL->getModelViewNumber() == BrainModel:: BRAIN_MODEL_VIEW_MAIN_WINDOW) { theMainWindow->updateTransformationMatrixEditor(NULL); } GuiBrainModelOpenGL::updateAllGL(); // update all, not just this window's OpenGL } break; } } } /** * Called when a rotation axis is selected. */ void GuiToolBarActions::setRotationSelection(int axis) { brainModelOpenGL->setRotationAxis(static_cast(axis)); } /** * Called when yoke button is pressed */ void GuiToolBarActions::yokeSlot(bool selected) { brainModelOpenGL->setYokeView(selected); GuiBrainModelOpenGL::updateAllGL(brainModelOpenGL); } /** * called when swap button set. */ void GuiToolBarActions::swapSlot() { // // Get brain model and transform from viewing window // BrainModel* myBrainModel = brainModelOpenGL->getDisplayedBrainModel(); if (myBrainModel == NULL) { return; } const BrainModel::BRAIN_MODEL_VIEW_NUMBER myWindowNumber = parentToolBar->getViewWindowNumber(); const QString myViewTransformation = myBrainModel->getTransformationsAsString(myWindowNumber); VolumeFile::VOLUME_AXIS myVolumeAxis = VolumeFile::VOLUME_AXIS_UNKNOWN; int myVolumeSlices[3]; BrainModelVolume* myBrainModelVolume = dynamic_cast(myBrainModel); if (myBrainModelVolume != NULL) { myVolumeAxis = myBrainModelVolume->getSelectedAxis(myWindowNumber); myBrainModelVolume->getSelectedOrthogonalSlices(myWindowNumber, myVolumeSlices); } // // Get info about brain model in main window // const int mainWindowBrainModelIndex = theMainWindow->getBrainModelIndex(); BrainModel* mainWindowBrainModel = theMainWindow->getBrainModel(); if (mainWindowBrainModel == NULL) { return; } const QString mainWindowTransformation = mainWindowBrainModel->getTransformationsAsString(BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW); VolumeFile::VOLUME_AXIS mainWindowVolumeAxis = VolumeFile::VOLUME_AXIS_UNKNOWN; int mainWindowVolumeSlices[3]; BrainModelVolume* mainWindowBrainModelVolume = dynamic_cast(mainWindowBrainModel); if (mainWindowBrainModelVolume != NULL) { mainWindowVolumeAxis = mainWindowBrainModelVolume->getSelectedAxis(BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW); mainWindowBrainModelVolume->getSelectedOrthogonalSlices(BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW, mainWindowVolumeSlices); } // // Put brain model in main window // if (myBrainModel != NULL) { theMainWindow->displayBrainModelInMainWindow(myBrainModel); myBrainModel->setTransformationsAsString(BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW, myViewTransformation); if (myBrainModelVolume != NULL) { myBrainModelVolume->setSelectedOrthogonalSlices(BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW, myVolumeSlices); myBrainModelVolume->setSelectedAxis(BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW, myVolumeAxis); } } // // Put brain model in viewing window // if (parentToolBar != NULL) { if (mainWindowBrainModelIndex >= 0) { parentToolBar->setModelSelection(mainWindowBrainModelIndex); mainWindowBrainModel->setTransformationsAsString(myWindowNumber, mainWindowTransformation); if (mainWindowBrainModelVolume != NULL) { mainWindowBrainModelVolume->setSelectedOrthogonalSlices(myWindowNumber, mainWindowVolumeSlices); mainWindowBrainModelVolume->setSelectedAxis(myWindowNumber, mainWindowVolumeAxis); } } } GuiBrainModelOpenGL::updateAllGL(); } /** * called when underlay only button toggled. */ void GuiToolBarActions::underlayOnlySlot(bool b) { BrainModelVolume* bmv = brainModelOpenGL->getDisplayedBrainModelVolume(); bmv->setShowUnderlayOnlyInWindow(brainModelOpenGL->getModelViewNumber(), b); GuiBrainModelOpenGL::updateAllGL(brainModelOpenGL); } /* * Called when medial view tool button is pressed. */ void GuiToolBarActions::medialViewSlot() { setViewSelection(BrainModelSurface::VIEW_MEDIAL); } /** * Called when lateral view tool button is pressed. */ void GuiToolBarActions::lateralViewSlot() { setViewSelection(BrainModelSurface::VIEW_LATERAL); } /** * Called when anterior view tool button is pressed. */ void GuiToolBarActions::anteriorViewSlot() { setViewSelection(BrainModelSurface::VIEW_ANTERIOR); } /** * Called when posterior view tool button is pressed. */ void GuiToolBarActions::posteriorViewSlot() { setViewSelection(BrainModelSurface::VIEW_POSTERIOR); } /** * Called when dorsal view tool button is pressed. */ void GuiToolBarActions::dorsalViewSlot() { setViewSelection(BrainModelSurface::VIEW_DORSAL); } /** * Called when ventral view tool button is pressed. */ void GuiToolBarActions::ventralViewSlot() { setViewSelection(BrainModelSurface::VIEW_VENTRAL); } /** * Called when reset view tool button is pressed. */ void GuiToolBarActions::resetViewSlot() { setViewSelection(BrainModelSurface::VIEW_RESET); } /** * Called when rotate X 90 tool button is pressed. */ void GuiToolBarActions::xRotation90Slot() { setViewSelection(BrainModelSurface::VIEW_ROTATE_X_90); } /** * Called when rotate Y 90 tool button is pressed. */ void GuiToolBarActions::yRotation90Slot() { setViewSelection(BrainModelSurface::VIEW_ROTATE_Y_90); } /** * Called when rotate Z 90 tool button is pressed. */ void GuiToolBarActions::zRotation90Slot() { setViewSelection(BrainModelSurface::VIEW_ROTATE_Z_90); } /** * called to switch to view mode */ void GuiToolBarActions::viewModeSlot() { brainModelOpenGL->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_VIEW); } /** * called when display control button pressed. */ void GuiToolBarActions::displayControlDialogSlot() { theMainWindow->displayDisplayControlDialog(); } /** * called when spec button pressed. */ void GuiToolBarActions::specDialogSlot() { theMainWindow->displayFastOpenDataFileDialog(); } caret-5.6.4~dfsg.1.orig/caret/GuiToolBar.h0000664000175000017500000001454411572067322020047 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_TOOLBAR_H__ #define __GUI_TOOLBAR_H__ #include #include class GuiBrainModelOpenGL; class GuiMainWindow; #include "BrainModelSurface.h" class GuiBrainSetAndModelSelectionControl; class GuiToolBarActions; class QComboBox; class QDoubleSpinBox; class QMainWindow; class QToolButton; /// This class creates a toolbar for use in main and viewing windows class GuiToolBar : public QToolBar { Q_OBJECT public: /// Constructor GuiToolBar(QMainWindow* parent, GuiMainWindow* mainWindowIn, GuiBrainModelOpenGL* brainModelOpenGLIn, const BrainModel::BRAIN_MODEL_VIEW_NUMBER viewWindowNumberIn); /// Destructor ~GuiToolBar(); /// load the models into the model combo box void loadModelComboBox(); /// update the view controls based upon the loaded brain model void updateViewControls(); /// clear all yoking static void clearAllYoking(); /// update all toolbars (typically called when new surfaces loaded) static void updateAllToolBars(const bool additionalFilesLoaded); /// set yoke status void setYokeStatus(const bool b); /// called when a standard view is selected void setViewSelection(const BrainModel::STANDARD_VIEWS standardView); /// update mouse mode combo box void updateMouseModeComboBox(); /// get the viewing window used by this toolbar BrainModel::BRAIN_MODEL_VIEW_NUMBER getViewWindowNumber() const { return viewWindowNumber; } signals: /// Signal emitted when the model selection combo box is changed. Normally, /// this signal does not need to be used by the parent of the toolbar. The /// toolbar will update the model in the BrainModelOpenGL object that is /// passed to the constructor. void modelSelection(int modelNum); /// Signal emitted when rotation axis is changed. Normally, /// this signal does not need to be used by the parent of the toolbar. The /// toolbar will update the model in the BrainModelOpenGL object that is /// passed to the constructor. void rotationAxisSelection(int rotNum); public slots: /// called when model is selected void setModelSelection(int modelNum); /// called when rotation axis is selected void setRotationSelection(int axis); /// called when X slice changed void volumeSliceXChanged(double value); /// called when Y slice changed void volumeSliceYChanged(double value); /// called when Z slice changed void volumeSliceZChanged(double value); /// called when volume view axis changed void volumeAxisChanged(int value); /// called when volume stereotaxic coordinates is toggled void volumeStereotaxicCoordinatesSlot(bool b); /// called when a mouse mode is selected void slotMouseModeComboBoxActivated(int item); /// view mode button clicked void slotViewModeButtonClicked(); protected: /// called when toolbar is resized void resizeEvent(QResizeEvent* e); /// Caret's main window GuiMainWindow* mainWindow; /// model selection combo box GuiBrainSetAndModelSelectionControl* modelFileComboBox; /// rotation combo box QComboBox* rotationAxisComboBox; /// yoke toggle button QToolButton* yokeButton; /// volume underlay only button QToolButton* volumeUnderlayOnlyButton; /// Medial View Tool Button QToolButton* medialViewToolButton; /// Lateral View Tool Button QToolButton* lateralViewToolButton; /// Anterior View Tool Button QToolButton* anteriorViewToolButton; /// Posterior View Tool Button QToolButton* posteriorViewToolButton; /// Dorsal View Tool Button QToolButton* dorsalViewToolButton; /// Ventral View Tool Button QToolButton* ventralViewToolButton; /// Reset View Tool Button QToolButton* resetViewToolButton; /// X 90 Rotation Tool Button QToolButton* xRotation90ToolButton; /// Y 90 Rotation Tool Button QToolButton* yRotation90ToolButton; /// Z 90 Rotation Tool Button QToolButton* zRotation90ToolButton; /// volume slice spin box QDoubleSpinBox* volumeSpinBoxSliceX; /// volume slice spin box QDoubleSpinBox* volumeSpinBoxSliceY; /// volume slice spin box QDoubleSpinBox* volumeSpinBoxSliceZ; /// volume view axis combo box QComboBox* volumeAxisComboBox; /// show stereotaxic coordinates button QToolButton* volumeStereotaxicCoordinatesToolButton; /// Windows OpenGL widget GuiBrainModelOpenGL* brainModelOpenGL; /// toolbar's actions GuiToolBarActions* toolBarActions; /// Keeps track of toolbars so that they can be updated when /// the models change. static std::vector allToolBars; /// mouse mode combo box QComboBox* mouseModeComboBox; /// the viewing window used by this toolbar BrainModel::BRAIN_MODEL_VIEW_NUMBER viewWindowNumber; }; #ifdef __GUI_TOOLBAR_MAIN__ std::vector GuiToolBar::allToolBars; #endif // __GUI_TOOLBAR_MAIN__ #endif // __GUI_TOOLBAR_H__ caret-5.6.4~dfsg.1.orig/caret/GuiToolBar.cxx0000664000175000017500000017206511572067322020425 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include "BrainModelContours.h" #include "BrainModelSurfaceAndVolume.h" #include "BrainModelVolumeVoxelColoring.h" #include "BrainSet.h" #include "DisplaySettingsCuts.h" #include "DisplaySettingsSurface.h" #include "GuiBrainModelOpenGL.h" #include "GuiBrainSetAndModelSelectionControl.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "GuiMainWindowLayersActions.h" #include "GuiMainWindowVolumeActions.h" #include "GuiMouseModePopupMenu.h" #include "GuiToolBarActions.h" #define __GUI_TOOLBAR_MAIN__ #include "GuiToolBar.h" #undef __GUI_TOOLBAR_MAIN__ #include "FileUtilities.h" #include "global_variables.h" #include "StringUtilities.h" /** * Constructor. * Parent is the window that this toolbar is being added to. * mainWindowIn is Caret's main window. * mainWindowFlag is set if this tool bar is being added to Caret's main window. */ GuiToolBar::GuiToolBar(QMainWindow* parent, GuiMainWindow* mainWindowIn, GuiBrainModelOpenGL* brainModelOpenGLIn, const BrainModel::BRAIN_MODEL_VIEW_NUMBER viewWindowNumberIn) : QToolBar(parent) { setMovable(false); mainWindow = mainWindowIn; brainModelOpenGL = brainModelOpenGLIn; viewWindowNumber = viewWindowNumberIn; const bool mainWindowFlag = (viewWindowNumber == BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW); // // actions for toolbar // toolBarActions = new GuiToolBarActions(brainModelOpenGL, this); // // Combo box for model files // modelFileComboBox = new GuiBrainSetAndModelSelectionControl; modelFileComboBox->addItem(" "); // if (mainWindowFlag) { // //setStretchableWidget(modelFileComboBox); // } // else { // modelFileComboBox->setFixedSize(modelFileComboBox->sizeHint()); // } modelFileComboBox->setEditable(false); modelFileComboBox->setToolTip( "This control is used to select the\n" "displayed contour, surface, or\n" "volume."); QObject::connect(modelFileComboBox, SIGNAL(activated(int)), this, SLOT(setModelSelection(int))); QObject::connect(modelFileComboBox, SIGNAL(activated(int)), this, SIGNAL(modelSelection(int))); //modelFileComboBox->updateControl(); brainModelOpenGL->setModelSelectionControl(modelFileComboBox); QToolButton* viewButton = NULL; if (mainWindowFlag) { // // View mode tool button // viewButton = new QToolButton; viewButton->setText("View"); QObject::connect(viewButton, SIGNAL(clicked()), this, SLOT(slotViewModeButtonClicked())); //viewButton->setDefaultAction(toolBarActions->getViewModeAction()); viewButton->setMenu(new GuiMouseModePopupMenu(brainModelOpenGL, false, viewButton)); viewButton->setPopupMode(QToolButton::MenuButtonPopup); } // // Standard Medial View Button // medialViewToolButton = new QToolButton; medialViewToolButton->setDefaultAction(toolBarActions->getMedialViewAction()); // // Standard View Lateral Button // lateralViewToolButton = new QToolButton; lateralViewToolButton->setDefaultAction(toolBarActions->getLateralViewAction()); // // Standard View Anterior Button // anteriorViewToolButton = new QToolButton; anteriorViewToolButton->setDefaultAction(toolBarActions->getAnteriorViewAction()); // // Standard View Posterior Button // posteriorViewToolButton = new QToolButton; posteriorViewToolButton->setDefaultAction(toolBarActions->getPosteriorViewAction()); // // Standard View Dorsal Button // dorsalViewToolButton = new QToolButton; dorsalViewToolButton->setDefaultAction(toolBarActions->getDorsalViewAction()); // // Standard View Ventral Button // ventralViewToolButton = new QToolButton; ventralViewToolButton->setDefaultAction(toolBarActions->getVentralViewAction()); // // Standard View Reset Button // resetViewToolButton = new QToolButton; resetViewToolButton->setDefaultAction(toolBarActions->getResetViewAction()); // // X Rotation 90 Button // xRotation90ToolButton = new QToolButton; xRotation90ToolButton->setDefaultAction(toolBarActions->getXRotation90Action()); // // Y Rotation 90 Button // yRotation90ToolButton = new QToolButton; yRotation90ToolButton->setDefaultAction(toolBarActions->getYRotation90Action()); // // Z Rotation 90 Button // zRotation90ToolButton = new QToolButton; zRotation90ToolButton->setDefaultAction(toolBarActions->getZRotation90Action()); // // Combo box for rotation axis // rotationAxisComboBox = new QComboBox; rotationAxisComboBox->insertItem(GuiBrainModelOpenGL::BRAIN_MODEL_ROTATION_AXIS_X, "X"); rotationAxisComboBox->insertItem(GuiBrainModelOpenGL::BRAIN_MODEL_ROTATION_AXIS_Y, "Y"); rotationAxisComboBox->insertItem(GuiBrainModelOpenGL::BRAIN_MODEL_ROTATION_AXIS_Z, "Z"); rotationAxisComboBox->insertItem(GuiBrainModelOpenGL::BRAIN_MODEL_ROTATION_AXIS_XY, "XY"); rotationAxisComboBox->insertItem(GuiBrainModelOpenGL::BRAIN_MODEL_ROTATION_AXIS_OFF, "OFF"); QSize rotationSize = rotationAxisComboBox->sizeHint(); rotationSize.setWidth(55); rotationAxisComboBox->setFixedSize(rotationSize); QObject::connect(rotationAxisComboBox, SIGNAL(activated(int)), this, SIGNAL(rotationAxisSelection(int))); QObject::connect(rotationAxisComboBox, SIGNAL(activated(int)), this, SLOT(setRotationSelection(int))); rotationAxisComboBox->setToolTip("This control is used to\n" "select the axis that the\n" "surface rotates around."); rotationAxisComboBox->setCurrentIndex(static_cast(brainModelOpenGL->getRotationAxis())); // // Stereotaxic coordinates action and button // volumeStereotaxicCoordinatesToolButton = new QToolButton; volumeStereotaxicCoordinatesToolButton->setText("S"); volumeStereotaxicCoordinatesToolButton->setCheckable(true); volumeStereotaxicCoordinatesToolButton->setToolTip("For orthogonal views only. When on, the\n" "volume slice controls show stereotaxic\n" "stereotaxic coordinates. When off, the \n" "volume slice controls show slice indices.\n"); QObject::connect(volumeStereotaxicCoordinatesToolButton, SIGNAL(toggled(bool)), this, SLOT(volumeStereotaxicCoordinatesSlot(bool))); // // Combo box for volume axis // volumeAxisComboBox = new QComboBox; volumeAxisComboBox->insertItem(VolumeFile::VOLUME_AXIS_X, "P (YZ)"); volumeAxisComboBox->insertItem(VolumeFile::VOLUME_AXIS_Y, "C (XZ)"); volumeAxisComboBox->insertItem(VolumeFile::VOLUME_AXIS_Z, "H (XY)"); volumeAxisComboBox->insertItem(VolumeFile::VOLUME_AXIS_ALL, "All"); volumeAxisComboBox->insertItem(VolumeFile::VOLUME_AXIS_OBLIQUE, "Oblique"); volumeAxisComboBox->insertItem(VolumeFile::VOLUME_AXIS_OBLIQUE_X, "X-Oblique"); volumeAxisComboBox->insertItem(VolumeFile::VOLUME_AXIS_OBLIQUE_Y, "Y-Oblique"); volumeAxisComboBox->insertItem(VolumeFile::VOLUME_AXIS_OBLIQUE_Z, "Z-Oblique"); volumeAxisComboBox->insertItem(VolumeFile::VOLUME_AXIS_OBLIQUE_ALL, "All-Oblique"); QSize axisSize = volumeAxisComboBox->sizeHint(); axisSize.setWidth(70); volumeAxisComboBox->setFixedSize(axisSize); QObject::connect(volumeAxisComboBox, SIGNAL(activated(int)), this, SLOT(volumeAxisChanged(int))); volumeAxisComboBox->setToolTip("This control chooses the axis\n" "for viewing the volume\n" " Coronal\n" " Parasagittal\n" " Horizontal\n" " All 3 Slices\n" " Oblique Rotatable Slice\n" " Oblique \"X\" Slice\n" " Oblique \"Y\" Slice\n" " Oblique \"Z\" Slice\n" " Oblique ALL Slices\n" ); // // Volume Slice X Spin Box // volumeSpinBoxSliceX = new QDoubleSpinBox; QObject::connect(volumeSpinBoxSliceX, SIGNAL(valueChanged(double)), this, SLOT(volumeSliceXChanged(double))); volumeSpinBoxSliceX->setToolTip("This control is used to\n" "select the parasagittal slice."); // // Volume Slice Y Spin Box // volumeSpinBoxSliceY = new QDoubleSpinBox; QObject::connect(volumeSpinBoxSliceY, SIGNAL(valueChanged(double)), this, SLOT(volumeSliceYChanged(double))); volumeSpinBoxSliceY->setToolTip("This control is used to\n" "select the coronal slice."); // // Volume Slice Z Spin Box // volumeSpinBoxSliceZ = new QDoubleSpinBox; QObject::connect(volumeSpinBoxSliceZ, SIGNAL(valueChanged(double)), this, SLOT(volumeSliceZChanged(double))); volumeSpinBoxSliceZ->setToolTip("This control is used to\n" "select the horizontal slice."); QToolButton* dcButton = NULL; QToolButton* specButton = NULL; yokeButton = NULL; QToolButton* swapButton = NULL; volumeUnderlayOnlyButton = NULL; if (mainWindowFlag) { // // Display Control toolbar button // dcButton = new QToolButton; dcButton->setDefaultAction(toolBarActions->getDisplayControlDialogAction()); // // Fast Open Data file dialog // specButton = new QToolButton; specButton->setDefaultAction(toolBarActions->getSpecDialogAction()); } else { // // Underlay only button // volumeUnderlayOnlyButton = new QToolButton; volumeUnderlayOnlyButton->setDefaultAction(toolBarActions->getUnderlayVolumeOnlyAction()); // // Yoke toolbar button // yokeButton = new QToolButton; yokeButton->setDefaultAction(toolBarActions->getYokeAction()); // // Swap toolbar button // swapButton = new QToolButton; swapButton->setDefaultAction(toolBarActions->getSwapAction()); } QHBoxLayout* l1 = new QHBoxLayout; if (viewButton != NULL) { l1->addWidget(viewButton, 0); } l1->addWidget(medialViewToolButton, 0); l1->addWidget(lateralViewToolButton, 0); l1->addWidget(anteriorViewToolButton, 0); l1->addWidget(posteriorViewToolButton, 0); l1->addWidget(dorsalViewToolButton, 0); l1->addWidget(ventralViewToolButton, 0); l1->addWidget(resetViewToolButton, 0); l1->addWidget(xRotation90ToolButton, 0); l1->addWidget(yRotation90ToolButton, 0); l1->addWidget(zRotation90ToolButton, 0); l1->addWidget(rotationAxisComboBox, 0); l1->addWidget(volumeStereotaxicCoordinatesToolButton, 0); l1->addWidget(volumeAxisComboBox, 0); l1->addWidget(volumeSpinBoxSliceX, 0); l1->addWidget(volumeSpinBoxSliceY); l1->addWidget(volumeSpinBoxSliceZ, 0); if (dcButton != NULL) { l1->addWidget(dcButton, 0); } if (specButton != NULL) { l1->addWidget(specButton, 0); } if (volumeUnderlayOnlyButton != NULL) { l1->addWidget(volumeUnderlayOnlyButton, 0); } if (yokeButton != NULL) { l1->addWidget(yokeButton, 0); } if (swapButton != NULL) { l1->addWidget(swapButton, 0); } l1->addStretch(); //1000); // // Layout for second and third rows (mode and mouse) // QGridLayout* modeMouseLayout = new QGridLayout; modeMouseLayout->setColumnStretch(0, 0); modeMouseLayout->setColumnStretch(1, 1000); // // Model selection control // QLabel* modelLabel = new QLabel("Model "); modeMouseLayout->addWidget(modelLabel, 0, 0); modeMouseLayout->addWidget(modelFileComboBox, 0, 1); // // Mouse mode combo box // mouseModeComboBox = NULL; const bool showMouseModeComboBoxFlag = false; //mainWindowFlag; if (showMouseModeComboBoxFlag) { QLabel* mouseModeLabel = new QLabel("Mouse "); mouseModeComboBox = new QComboBox; QObject::connect(mouseModeComboBox, SIGNAL(activated(int)), this, SLOT(slotMouseModeComboBoxActivated(int))); modeMouseLayout->addWidget(mouseModeLabel, 1, 0); modeMouseLayout->addWidget(mouseModeComboBox, 1, 1); } QWidget* vb = new QWidget; QVBoxLayout* vl = new QVBoxLayout(vb); vl->addLayout(l1); vl->addLayout(modeMouseLayout); addWidget(vb); // // Keep track of all toolbars that get created // bool found = false; for (unsigned int i = 0; i < allToolBars.size(); i++) { if (allToolBars[i] == NULL) { allToolBars[i] = this; found = true; break; } } if (found == false) { allToolBars.push_back(this); } // if (mainWindowFlag) { loadModelComboBox(); updateViewControls(); // } setMinimumWidth(512); #if (QT_VERSION == QT_VERSION_CHECK(4,3,0)) // setMaximumWidth(512); // QT 4.3 bug make toolbar way too wide #endif } /** * Destructor. */ GuiToolBar::~GuiToolBar() { for (unsigned int i = 0; i < allToolBars.size(); i++) { if (allToolBars[i] == this) { allToolBars[i] = NULL; break; } } } /** * view mode button clicked. */ void GuiToolBar::slotViewModeButtonClicked() { brainModelOpenGL->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_VIEW); } /** * Update toolbar */ void GuiToolBar::updateViewControls() { bool showContourControls = false; bool showSurfaceControls = false; bool showVolumeControls = false; // // Model number selected // const int modelNum = modelFileComboBox->currentIndex(); // // Loop through brain sets // if (theMainWindow != NULL) { int modelComboBoxOffset = 0; const int numBrainSets = theMainWindow->getNumberOfBrainSets(); for (int i = 0; i < numBrainSets; i++) { // // Get a brain set and its number of models // BrainSet* bs = theMainWindow->getBrainSetByIndex(i); const int brainSetNumberOfModels = bs->getNumberOfBrainModels(); // // See if model combo box is using this brain set's model // const int firstBrainModelIndex = modelComboBoxOffset; const int lastBrainModelIndex = modelComboBoxOffset + brainSetNumberOfModels; if ((modelNum >= firstBrainModelIndex) && (modelNum < lastBrainModelIndex)) { // // Update controls based upon type of brain model // BrainModel* bm = bs->getBrainModel(modelNum - modelComboBoxOffset); if (bm != NULL) { switch (bm->getModelType()) { case BrainModel::BRAIN_MODEL_CONTOURS: showContourControls = true; break; case BrainModel::BRAIN_MODEL_SURFACE: showSurfaceControls = true; break; case BrainModel::BRAIN_MODEL_SURFACE_AND_VOLUME: showSurfaceControls = true; break; case BrainModel::BRAIN_MODEL_VOLUME: showVolumeControls = true; break; } } // // Jump out of loop // break; } // // model combo box offset for next brain set // modelComboBoxOffset += brainSetNumberOfModels; } } // // If no controls enabled, show surface controls // if ((showContourControls == false) && (showSurfaceControls == false) && (showVolumeControls == false)) { showSurfaceControls = true; } /* if (theMainWindow != NULL) { const int numModels = theMainWindow->getBrainSet(brainModelOpenGL->getModelViewNumber())->getNumberOfBrainModels(); if ((modelNum >= 0) && (modelNum < numModels) && (numModels > 0)) { BrainModel* bm = theMainWindow->getBrainSet(brainModelOpenGL->getModelViewNumber())->getBrainModel(modelNum); if (bm != NULL) { switch (bm->getModelType()) { case BrainModel::BRAIN_MODEL_CONTOURS: showContourControls = true; break; case BrainModel::BRAIN_MODEL_SURFACE: showSurfaceControls = true; break; case BrainModel::BRAIN_MODEL_SURFACE_AND_VOLUME: showSurfaceControls = true; break; case BrainModel::BRAIN_MODEL_VOLUME: showVolumeControls = true; break; } } else { showSurfaceControls = true; } } else { showSurfaceControls = true; } } */ // // Show surface controls // medialViewToolButton->setHidden(! showSurfaceControls); lateralViewToolButton->setHidden(! showSurfaceControls); anteriorViewToolButton->setHidden(! showSurfaceControls); posteriorViewToolButton->setHidden(! showSurfaceControls); dorsalViewToolButton->setHidden(! showSurfaceControls); ventralViewToolButton->setHidden(! showSurfaceControls); xRotation90ToolButton->setHidden(! showSurfaceControls); yRotation90ToolButton->setHidden(! showSurfaceControls); zRotation90ToolButton->setHidden(! showSurfaceControls); rotationAxisComboBox->setHidden(! showSurfaceControls); rotationAxisComboBox->blockSignals(true); rotationAxisComboBox->setCurrentIndex(brainModelOpenGL->getRotationAxis()); rotationAxisComboBox->blockSignals(false); // // Show volume controls // volumeSpinBoxSliceX->setHidden(! showVolumeControls); volumeSpinBoxSliceY->setHidden(! showVolumeControls); volumeSpinBoxSliceZ->setHidden(! showVolumeControls); volumeAxisComboBox->setHidden(! showVolumeControls); volumeStereotaxicCoordinatesToolButton->setHidden( ! showVolumeControls); if (volumeUnderlayOnlyButton != NULL) { volumeUnderlayOnlyButton->setHidden(! showVolumeControls); } if (showVolumeControls) { // // Block signals from slice controls // volumeSpinBoxSliceX->blockSignals(true); volumeSpinBoxSliceY->blockSignals(true); volumeSpinBoxSliceZ->blockSignals(true); volumeStereotaxicCoordinatesToolButton->blockSignals(true); BrainModelVolume* bmv = brainModelOpenGL->getDisplayedBrainModelVolume(); if (bmv != NULL) { const int viewNumber = brainModelOpenGL->getModelViewNumber(); volumeAxisComboBox->blockSignals(true); volumeAxisComboBox->setCurrentIndex( static_cast(bmv->getSelectedAxis(viewNumber))); volumeAxisComboBox->blockSignals(false); volumeStereotaxicCoordinatesToolButton->setChecked(bmv->getViewStereotaxicCoordinatesFlag(viewNumber)); if (volumeUnderlayOnlyButton != NULL) { volumeUnderlayOnlyButton->blockSignals(true); volumeUnderlayOnlyButton->setChecked(bmv->getShowUnderlayOnlyInWindow(viewNumber)); volumeUnderlayOnlyButton->blockSignals(false); } bool slicesViewFlag = false; switch (bmv->getSelectedAxis(viewNumber)) { case VolumeFile::VOLUME_AXIS_X: case VolumeFile::VOLUME_AXIS_Y: case VolumeFile::VOLUME_AXIS_Z: case VolumeFile::VOLUME_AXIS_ALL: { VolumeFile* vf = bmv->getMasterVolumeFile(); if (vf != NULL) { int dim[3] = { 0, 0, 0 }; vf->getDimensions(dim); int slices[3]; bmv->getSelectedOrthogonalSlices(viewNumber, slices); if (bmv->getViewStereotaxicCoordinatesFlag(viewNumber)) { float minXYZ[3], maxXYZ[3]; vf->getVoxelCoordinate(0, 0, 0, minXYZ); vf->getVoxelCoordinate(dim, maxXYZ); volumeSpinBoxSliceX->setMinimum(minXYZ[0]); volumeSpinBoxSliceX->setMaximum(maxXYZ[1]); volumeSpinBoxSliceX->setSingleStep(1); volumeSpinBoxSliceX->setDecimals(1); volumeSpinBoxSliceY->setMinimum(minXYZ[1]); volumeSpinBoxSliceY->setMaximum(maxXYZ[1]); volumeSpinBoxSliceY->setSingleStep(1); volumeSpinBoxSliceY->setDecimals(1); volumeSpinBoxSliceZ->setMinimum(minXYZ[2]); volumeSpinBoxSliceZ->setMaximum(maxXYZ[2]); volumeSpinBoxSliceZ->setSingleStep(1); volumeSpinBoxSliceZ->setDecimals(1); float sliceXYZ[3]; vf->getVoxelCoordinate(slices, sliceXYZ); volumeSpinBoxSliceX->setValue(sliceXYZ[0]); volumeSpinBoxSliceY->setValue(sliceXYZ[1]); volumeSpinBoxSliceZ->setValue(sliceXYZ[2]); } else { volumeSpinBoxSliceX->setMinimum(0); volumeSpinBoxSliceX->setMaximum(dim[0] - 1); volumeSpinBoxSliceX->setSingleStep(1); volumeSpinBoxSliceX->setDecimals(0); volumeSpinBoxSliceY->setMinimum(0); volumeSpinBoxSliceY->setMaximum(dim[1] - 1); volumeSpinBoxSliceY->setSingleStep(1); volumeSpinBoxSliceY->setDecimals(0); volumeSpinBoxSliceZ->setMinimum(0); volumeSpinBoxSliceZ->setMaximum(dim[2] - 1); volumeSpinBoxSliceZ->setSingleStep(1); volumeSpinBoxSliceZ->setDecimals(0); volumeSpinBoxSliceX->setValue(slices[0]); volumeSpinBoxSliceY->setValue(slices[1]); volumeSpinBoxSliceZ->setValue(slices[2]); } } } break; case VolumeFile::VOLUME_AXIS_OBLIQUE: { VolumeFile* vf = bmv->getMasterVolumeFile(); if (vf != NULL) { int dim[3] = { 0, 0, 0 }; vf->getDimensions(dim); volumeSpinBoxSliceX->setMinimum(0); volumeSpinBoxSliceX->setMaximum(dim[0] - 1); volumeSpinBoxSliceX->setSingleStep(1); volumeSpinBoxSliceX->setDecimals(0); volumeSpinBoxSliceY->setMinimum(0); volumeSpinBoxSliceY->setMaximum(dim[1] - 1); volumeSpinBoxSliceY->setSingleStep(1); volumeSpinBoxSliceY->setDecimals(0); volumeSpinBoxSliceZ->setMinimum(0); volumeSpinBoxSliceZ->setMaximum(dim[2] - 1); volumeSpinBoxSliceZ->setSingleStep(1); volumeSpinBoxSliceZ->setDecimals(0); int slices[3]; bmv->getSelectedObliqueSlices(slices); volumeSpinBoxSliceX->setValue(slices[0]); volumeSpinBoxSliceY->setValue(slices[1]); volumeSpinBoxSliceZ->setValue(slices[2]); } } break; case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: { const int bigNum = 1000000; volumeSpinBoxSliceX->setMinimum(-bigNum); volumeSpinBoxSliceX->setMaximum(bigNum); volumeSpinBoxSliceX->setSingleStep(1); volumeSpinBoxSliceX->setDecimals(0); volumeSpinBoxSliceY->setMinimum(-bigNum); volumeSpinBoxSliceY->setMaximum(bigNum); volumeSpinBoxSliceY->setSingleStep(1); volumeSpinBoxSliceY->setDecimals(0); volumeSpinBoxSliceZ->setMinimum(-bigNum); volumeSpinBoxSliceZ->setMaximum(bigNum); volumeSpinBoxSliceZ->setSingleStep(1); volumeSpinBoxSliceZ->setDecimals(0); int slices[3]; bmv->getSelectedObliqueSliceOffsets(viewNumber, slices); volumeSpinBoxSliceX->setValue(slices[0]); volumeSpinBoxSliceY->setValue(slices[1]); volumeSpinBoxSliceZ->setValue(slices[2]); } slicesViewFlag = true; break; case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } if (slicesViewFlag) { volumeSpinBoxSliceX->setToolTip("This control is used to\n" "select the X' slice offset\n" "from the oblique view."); volumeSpinBoxSliceY->setToolTip("This control is used to\n" "select the Y' slice offset\n" "from the oblique view."); volumeSpinBoxSliceZ->setToolTip("This control is used to\n" "select the Z' slice offset\n" "from the oblique view."); } else { volumeSpinBoxSliceX->setToolTip("This control is used to\n" "select the parasagittal slice."); volumeSpinBoxSliceY->setToolTip("This control is used to\n" "select the coronal slice."); volumeSpinBoxSliceZ->setToolTip("This control is used to\n" "select the horizontal slice."); } } // // Unblock signals from slice controls // volumeSpinBoxSliceX->blockSignals(false); volumeSpinBoxSliceY->blockSignals(false); volumeSpinBoxSliceZ->blockSignals(false); volumeStereotaxicCoordinatesToolButton->blockSignals(false); } updateMouseModeComboBox(); adjustSize(); } /** * clear all yoking. */ void GuiToolBar::clearAllYoking() { GuiBrainModelOpenGL::setPaintingEnabled(false); for (unsigned int i = 0; i < allToolBars.size(); i++) { if (allToolBars[i] != NULL) { if (allToolBars[i]->yokeButton != NULL) { allToolBars[i]->brainModelOpenGL->setYokeView(false); allToolBars[i]->yokeButton->setChecked(false); } } } GuiBrainModelOpenGL::setPaintingEnabled(true); } /** * Update all toolbars with brain models. */ void GuiToolBar::updateAllToolBars(const bool additionalFilesLoaded) { GuiBrainModelOpenGL::setPaintingEnabled(false); for (unsigned int i = 0; i < allToolBars.size(); i++) { if (allToolBars[i] != NULL) { allToolBars[i]->loadModelComboBox(); allToolBars[i]->updateViewControls(); // // if loading all files then turn off yoking // if (allToolBars[i]->yokeButton != NULL) { if (additionalFilesLoaded) { //allToolBars[i]->yokeButton->setDown(false); //allToolBars[i]->brainModelOpenGL->setYokeView(false); } //allToolBars[i]->yokeButton->setChecked(allToolBars[i]->brainModelOpenGL->getYokeView()); } } } GuiBrainModelOpenGL::setPaintingEnabled(true); } /** * set yoke status. */ void GuiToolBar::setYokeStatus(const bool b) { if (toolBarActions != NULL) { toolBarActions->getYokeAction()->setChecked(!b); toolBarActions->getYokeAction()->trigger(); } /* if (yokeButton != NULL) { yokeButton->setChecked(b); } */ } /** * Load the model names into the model combo box. */ void GuiToolBar::loadModelComboBox() { if (theMainWindow == NULL) { return; } BrainSet* theBrain = theMainWindow->getBrainSet(brainModelOpenGL->getModelViewNumber()); BrainModel* theBrainModel = brainModelOpenGL->getDisplayedBrainModel(); modelFileComboBox->updateControl(theBrain, theBrainModel); } /** * Called when a standard view is selected. */ void GuiToolBar::setViewSelection(const BrainModel::STANDARD_VIEWS standardView) { BrainModel* bm = brainModelOpenGL->getDisplayedBrainModel(); if (bm != NULL) { switch (bm->getModelType()) { case BrainModel::BRAIN_MODEL_SURFACE: { BrainModelSurface* s = dynamic_cast(bm); // // If yoked set the view of the caret main window // bool surfaceYokedFlag = false; BrainModelSurface* mainWindowModelSurface = NULL; GuiBrainModelOpenGL* mainWindowBrainModelOpenGL = NULL; int mainWindowModelViewNumber = -1; if (brainModelOpenGL->getYokeView()) { surfaceYokedFlag = GuiBrainModelOpenGL::getCaretMainWindowModelInfo(mainWindowModelSurface, mainWindowBrainModelOpenGL, mainWindowModelViewNumber); } // // Might be yoked to volume // bool volumeYokedFlag = false; BrainModelVolume* bmv = theMainWindow->getBrainModelVolume(); if (brainModelOpenGL->getYokeView()) { if (bmv != NULL) { if (bmv->getSelectedAxis(0) == VolumeFile::VOLUME_AXIS_OBLIQUE) { volumeYokedFlag = true; } } } if (surfaceYokedFlag) { mainWindowModelSurface->setToStandardView(mainWindowModelViewNumber, standardView); } else if (volumeYokedFlag) { bmv->setToStandardView(0, standardView); } else { s->setToStandardView(brainModelOpenGL->getModelViewNumber(), standardView); } if (brainModelOpenGL->getModelViewNumber() == BrainModel:: BRAIN_MODEL_VIEW_MAIN_WINDOW) { theMainWindow->updateTransformationMatrixEditor(NULL); } GuiBrainModelOpenGL::updateAllGL(brainModelOpenGL); } break; case BrainModel::BRAIN_MODEL_SURFACE_AND_VOLUME: { BrainModelSurfaceAndVolume* s = dynamic_cast(bm); s->setToStandardView(brainModelOpenGL->getModelViewNumber(), standardView); if (brainModelOpenGL->getModelViewNumber() == BrainModel:: BRAIN_MODEL_VIEW_MAIN_WINDOW) { theMainWindow->updateTransformationMatrixEditor(NULL); } GuiBrainModelOpenGL::updateAllGL(brainModelOpenGL); } break; case BrainModel::BRAIN_MODEL_CONTOURS: { BrainModelContours* bmc = dynamic_cast(bm); bmc->resetViewingTransform(brainModelOpenGL->getModelViewNumber()); if (brainModelOpenGL->getModelViewNumber() == BrainModel:: BRAIN_MODEL_VIEW_MAIN_WINDOW) { theMainWindow->updateTransformationMatrixEditor(NULL); } GuiBrainModelOpenGL::updateAllGL(brainModelOpenGL); } break; case BrainModel::BRAIN_MODEL_VOLUME: { BrainModelVolume* bmv = dynamic_cast(bm); bmv->resetViewingTransform(brainModelOpenGL->getModelViewNumber()); bmv->initializeSelectedSlices(brainModelOpenGL->getModelViewNumber(), false); updateAllToolBars(false); if (brainModelOpenGL->getModelViewNumber() == BrainModel:: BRAIN_MODEL_VIEW_MAIN_WINDOW) { theMainWindow->updateTransformationMatrixEditor(NULL); } GuiBrainModelOpenGL::updateAllGL(); // update all, not just this window's OpenGL } break; } } } /** * Called when a model is selected */ void GuiToolBar::setModelSelection(int modelNum) { if (theMainWindow->getBrainSet()->getNumberOfBrainModels() != modelFileComboBox->count()) { updateAllToolBars(true); } if (modelNum < modelFileComboBox->count()) { if (modelNum < modelFileComboBox->count()) { modelFileComboBox->setCurrentIndex(modelNum); const BrainSet* oldBrainSet = theMainWindow->getBrainSet(brainModelOpenGL->getModelViewNumber()); theMainWindow->setBrainSet(brainModelOpenGL->getModelViewNumber(), modelFileComboBox->getSelectedBrainSet()); brainModelOpenGL->setDisplayedBrainModel(modelFileComboBox->getSelectedBrainModel()); if (brainModelOpenGL == mainWindow->getBrainModelOpenGL()) { mainWindow->updateStatusBarLabel(); //} //if (brainModelOpenGL->getModelViewNumber() == BrainModel:: BRAIN_MODEL_VIEW_MAIN_WINDOW) { theMainWindow->updateTransformationMatrixEditor(NULL); // // If brain set has been changed need to update all display settings // if (oldBrainSet != theMainWindow->getBrainSet(brainModelOpenGL->getModelViewNumber())) { GuiFilesModified fm; fm.setStatusForAll(true); theMainWindow->fileModificationUpdate(fm); } } GuiBrainModelOpenGL::updateAllGL(brainModelOpenGL); } updateViewControls(); } } /** * Called when a rotation axis is selected. */ void GuiToolBar::setRotationSelection(int axis) { brainModelOpenGL->setRotationAxis(static_cast(axis)); } /** * Called when slice X changed. */ void GuiToolBar::volumeSliceXChanged(double value) { const int viewNumber = brainModelOpenGL->getModelViewNumber(); BrainModelVolume* bmv = brainModelOpenGL->getDisplayedBrainModelVolume(); if (bmv != NULL) { VolumeFile* vf = bmv->getMasterVolumeFile(); if (vf != NULL) { switch (bmv->getSelectedAxis(viewNumber)) { case VolumeFile::VOLUME_AXIS_X: case VolumeFile::VOLUME_AXIS_Y: case VolumeFile::VOLUME_AXIS_Z: case VolumeFile::VOLUME_AXIS_ALL: { int slices[3]; bmv->getSelectedOrthogonalSlices(viewNumber, slices); if (bmv->getViewStereotaxicCoordinatesFlag(viewNumber)) { const float xyz[3] = { value, volumeSpinBoxSliceY->value(), volumeSpinBoxSliceZ->value() }; vf->convertCoordinatesToVoxelIJK(xyz, slices); } else { slices[0] = static_cast(value); } bmv->setSelectedOrthogonalSlices(viewNumber, slices); // // If main window or yoked to main window // update selected slices in the main and yoked windows // if ((brainModelOpenGL == GuiBrainModelOpenGL::getBrainModelOpenGLForWindow(BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW)) || brainModelOpenGL->getYokeView()) { for (int i = 0; i < BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS; i++) { GuiBrainModelOpenGL* glWindow = GuiBrainModelOpenGL::getBrainModelOpenGLForWindow(static_cast(i)); if (glWindow != NULL) { BrainModelVolume* bmv2 = glWindow->getDisplayedBrainModelVolume(); if (bmv2 != NULL) { if ((i == BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) || glWindow->getYokeView()) { bmv2->setSelectedOrthogonalSlices(i, slices); if (allToolBars[i] != this) { allToolBars[i]->updateViewControls(); } } } } } } } break; case VolumeFile::VOLUME_AXIS_OBLIQUE: { int slices[3]; bmv->getSelectedObliqueSlices(slices); slices[0] = static_cast(value); bmv->setSelectedObliqueSlices(slices); } break; case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: { int slices[3]; bmv->getSelectedObliqueSliceOffsets(viewNumber, slices); slices[0] = static_cast(value); bmv->setSelectedObliqueSliceOffsets(viewNumber, slices); } break; case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } if (bmv->getSelectedAxis(viewNumber) == VolumeFile::VOLUME_AXIS_OBLIQUE) { GuiBrainModelOpenGL::updateAllGL(); } else { GuiBrainModelOpenGL::updateAllGL(brainModelOpenGL); } } } } /** * Called when slice Y changed. */ void GuiToolBar::volumeSliceYChanged(double value) { const int viewNumber = brainModelOpenGL->getModelViewNumber(); BrainModelVolume* bmv = brainModelOpenGL->getDisplayedBrainModelVolume(); if (bmv != NULL) { VolumeFile* vf = bmv->getMasterVolumeFile(); if (vf != NULL) { switch (bmv->getSelectedAxis(viewNumber)) { case VolumeFile::VOLUME_AXIS_X: case VolumeFile::VOLUME_AXIS_Y: case VolumeFile::VOLUME_AXIS_Z: case VolumeFile::VOLUME_AXIS_ALL: /* { int slices[3]; bmv->getSelectedOrthogonalSlices(viewNumber, slices); slices[1] = static_cast(value); bmv->setSelectedOrthogonalSlices(viewNumber, slices); } */ { int slices[3]; bmv->getSelectedOrthogonalSlices(viewNumber, slices); if (bmv->getViewStereotaxicCoordinatesFlag(viewNumber)) { const float xyz[3] = { volumeSpinBoxSliceX->value(), value, volumeSpinBoxSliceZ->value() }; vf->convertCoordinatesToVoxelIJK(xyz, slices); } else { slices[1] = static_cast(value); } bmv->setSelectedOrthogonalSlices(viewNumber, slices); // // If main window or yoked to main window // update selected slices in the main and yoked windows // if ((brainModelOpenGL == GuiBrainModelOpenGL::getBrainModelOpenGLForWindow(BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW)) || brainModelOpenGL->getYokeView()) { for (int i = 0; i < BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS; i++) { GuiBrainModelOpenGL* glWindow = GuiBrainModelOpenGL::getBrainModelOpenGLForWindow(static_cast(i)); if (glWindow != NULL) { BrainModelVolume* bmv2 = glWindow->getDisplayedBrainModelVolume(); if (bmv2 != NULL) { if ((i == BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) || glWindow->getYokeView()) { bmv2->setSelectedOrthogonalSlices(i, slices); if (allToolBars[i] != this) { allToolBars[i]->updateViewControls(); } } } } } } } break; case VolumeFile::VOLUME_AXIS_OBLIQUE: { int slices[3]; bmv->getSelectedObliqueSlices(slices); slices[1] = static_cast(value); bmv->setSelectedObliqueSlices(slices); } break; case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: { int slices[3]; bmv->getSelectedObliqueSliceOffsets(viewNumber, slices); slices[1] = static_cast(value); bmv->setSelectedObliqueSliceOffsets(viewNumber, slices); } break; case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } if (bmv->getSelectedAxis(viewNumber) == VolumeFile::VOLUME_AXIS_OBLIQUE) { GuiBrainModelOpenGL::updateAllGL(); } else { GuiBrainModelOpenGL::updateAllGL(brainModelOpenGL); } } } } /** * Called when slice Z changed. */ void GuiToolBar::volumeSliceZChanged(double value) { const int viewNumber = brainModelOpenGL->getModelViewNumber(); BrainModelVolume* bmv = brainModelOpenGL->getDisplayedBrainModelVolume(); if (bmv != NULL) { VolumeFile* vf = bmv->getMasterVolumeFile(); if (vf != NULL) { switch (bmv->getSelectedAxis(viewNumber)) { case VolumeFile::VOLUME_AXIS_X: case VolumeFile::VOLUME_AXIS_Y: case VolumeFile::VOLUME_AXIS_Z: case VolumeFile::VOLUME_AXIS_ALL: /* { int slices[3]; bmv->getSelectedOrthogonalSlices(viewNumber, slices); slices[2] = static_cast(value); bmv->setSelectedOrthogonalSlices(viewNumber, slices); } */ { int slices[3]; bmv->getSelectedOrthogonalSlices(viewNumber, slices); if (bmv->getViewStereotaxicCoordinatesFlag(viewNumber)) { const float xyz[3] = { volumeSpinBoxSliceX->value(), volumeSpinBoxSliceY->value(), value }; vf->convertCoordinatesToVoxelIJK(xyz, slices); } else { slices[2] = static_cast(value); } bmv->setSelectedOrthogonalSlices(viewNumber, slices); // // If main window or yoked to main window // update selected slices in the main and yoked windows // if ((brainModelOpenGL == GuiBrainModelOpenGL::getBrainModelOpenGLForWindow(BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW)) || brainModelOpenGL->getYokeView()) { for (int i = 0; i < BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS; i++) { GuiBrainModelOpenGL* glWindow = GuiBrainModelOpenGL::getBrainModelOpenGLForWindow(static_cast(i)); if (glWindow != NULL) { BrainModelVolume* bmv2 = glWindow->getDisplayedBrainModelVolume(); if (bmv2 != NULL) { if ((i == BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) || glWindow->getYokeView()) { bmv2->setSelectedOrthogonalSlices(i, slices); if (allToolBars[i] != this) { allToolBars[i]->updateViewControls(); } } } } } } } break; case VolumeFile::VOLUME_AXIS_OBLIQUE: { int slices[3]; bmv->getSelectedObliqueSlices(slices); slices[2] = static_cast(value); bmv->setSelectedObliqueSlices(slices); } break; case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: { int slices[3]; bmv->getSelectedObliqueSliceOffsets(viewNumber, slices); slices[2] = static_cast(value); bmv->setSelectedObliqueSliceOffsets(viewNumber, slices); } break; case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } if (bmv->getSelectedAxis(viewNumber) == VolumeFile::VOLUME_AXIS_OBLIQUE) { GuiBrainModelOpenGL::updateAllGL(); } else { GuiBrainModelOpenGL::updateAllGL(brainModelOpenGL); } } } } /** * Called when volume view axis changed. */ void GuiToolBar::volumeAxisChanged(int value) { BrainModelVolume* bmv = brainModelOpenGL->getDisplayedBrainModelVolume(); if (bmv != NULL) { bmv->setSelectedAxis(brainModelOpenGL->getModelViewNumber(), static_cast(value)); updateViewControls(); GuiBrainModelOpenGL::updateAllGL(brainModelOpenGL); } mainWindow->updateStatusBarLabel(); } /** * called when volume stereotaxic coordinates is toggled. */ void GuiToolBar::volumeStereotaxicCoordinatesSlot(bool b) { BrainModelVolume* bmv = brainModelOpenGL->getDisplayedBrainModelVolume(); if (bmv != NULL) { bmv->setViewStereotaxicCoordinatesFlag(brainModelOpenGL->getModelViewNumber(), b); updateViewControls(); GuiBrainModelOpenGL::updateAllGL(brainModelOpenGL); } } /** * called when toolbar is resized */ void GuiToolBar::resizeEvent(QResizeEvent* /*e*/) { /* updateViewControls(); QToolBar::resizeEvent(e); updateViewControls(); */ } /** * update mouse mode combo box. */ void GuiToolBar::updateMouseModeComboBox() { if (mouseModeComboBox == NULL) { return; } // // Clear combo box // mouseModeComboBox->clear(); mouseModeComboBox->addItem("Select Mode", GuiBrainModelOpenGL::MOUSE_MODE_NONE); BrainModel* bm = brainModelOpenGL->getDisplayedBrainModel(); if (bm != NULL) { switch (bm->getModelType()) { case BrainModel::BRAIN_MODEL_SURFACE: mouseModeComboBox->addItem("View", static_cast(GuiBrainModelOpenGL::MOUSE_MODE_VIEW)); mouseModeComboBox->addItem("Border Draw", static_cast(GuiBrainModelOpenGL::MOUSE_MODE_BORDER_DRAW)); mouseModeComboBox->addItem("Border Draw NEW", static_cast(GuiBrainModelOpenGL::MOUSE_MODE_BORDER_DRAW_NEW)); mouseModeComboBox->addItem("Border Delete", static_cast(GuiBrainModelOpenGL::MOUSE_MODE_BORDER_DELETE)); mouseModeComboBox->addItem("Border Rename", static_cast(GuiBrainModelOpenGL::MOUSE_MODE_BORDER_RENAME)); mouseModeComboBox->addItem("Border Reverse Point Order", static_cast(GuiBrainModelOpenGL::MOUSE_MODE_BORDER_REVERSE)); mouseModeComboBox->addItem("Border Point Delete", static_cast(GuiBrainModelOpenGL::MOUSE_MODE_BORDER_DELETE_POINT)); mouseModeComboBox->addItem("Border Point Move", static_cast(GuiBrainModelOpenGL::MOUSE_MODE_BORDER_MOVE_POINT)); mouseModeComboBox->addItem("Border Update", static_cast(GuiBrainModelOpenGL::MOUSE_MODE_BORDER_UPDATE)); mouseModeComboBox->addItem("Border Update NEW", static_cast(GuiBrainModelOpenGL::MOUSE_MODE_BORDER_UPDATE_NEW)); mouseModeComboBox->addItem("Cell Add", static_cast(GuiBrainModelOpenGL::MOUSE_MODE_CELL_ADD)); mouseModeComboBox->addItem("Cell Delete", static_cast(GuiBrainModelOpenGL::MOUSE_MODE_CELL_DELETE)); mouseModeComboBox->addItem("Cut Draw", static_cast(GuiBrainModelOpenGL::MOUSE_MODE_CUT_DRAW)); mouseModeComboBox->addItem("Cut Delete", static_cast(GuiBrainModelOpenGL::MOUSE_MODE_CUT_DELETE)); mouseModeComboBox->addItem("Foci Delete", static_cast(GuiBrainModelOpenGL::MOUSE_MODE_FOCI_DELETE)); break; case BrainModel::BRAIN_MODEL_SURFACE_AND_VOLUME: mouseModeComboBox->addItem("View", static_cast(GuiBrainModelOpenGL::MOUSE_MODE_VIEW)); break; case BrainModel::BRAIN_MODEL_CONTOURS: mouseModeComboBox->addItem("View", static_cast(GuiBrainModelOpenGL::MOUSE_MODE_VIEW)); mouseModeComboBox->addItem("Contour Draw", static_cast(GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_DRAW)); mouseModeComboBox->addItem("Contour Delete", static_cast(GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_DELETE)); mouseModeComboBox->addItem("Contour Merge", static_cast(GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_MERGE)); mouseModeComboBox->addItem("Contour Reverse Point Order", static_cast(GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_REVERSE)); mouseModeComboBox->addItem("Contour Point Delete", static_cast(GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_POINT_DELETE)); mouseModeComboBox->addItem("Contour Point Move", static_cast(GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_POINT_MOVE)); mouseModeComboBox->addItem("Contour Cell Add", static_cast(GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_CELL_ADD)); mouseModeComboBox->addItem("Contour Cell Delete", static_cast(GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_CELL_DELETE)); mouseModeComboBox->addItem("Contour Cell Move", static_cast(GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_CELL_MOVE)); break; case BrainModel::BRAIN_MODEL_VOLUME: { BrainModelVolumeVoxelColoring* voxelColoring = theMainWindow->getBrainSet()->getVoxelColoring(); mouseModeComboBox->addItem("View", static_cast(GuiBrainModelOpenGL::MOUSE_MODE_VIEW)); mouseModeComboBox->addItem("Border Delete", static_cast(GuiBrainModelOpenGL::MOUSE_MODE_BORDER_DELETE)); mouseModeComboBox->addItem("Border Rename", static_cast(GuiBrainModelOpenGL::MOUSE_MODE_BORDER_RENAME)); mouseModeComboBox->addItem("Border Reverse Point Order", static_cast(GuiBrainModelOpenGL::MOUSE_MODE_BORDER_REVERSE)); mouseModeComboBox->addItem("Border Point Delete", static_cast(GuiBrainModelOpenGL::MOUSE_MODE_BORDER_DELETE_POINT)); mouseModeComboBox->addItem("Border Point Move", static_cast(GuiBrainModelOpenGL::MOUSE_MODE_BORDER_MOVE_POINT)); if (voxelColoring->isUnderlayOrOverlay(BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_PAINT)) { mouseModeComboBox->addItem("Volume Paint Edit", static_cast(GuiBrainModelOpenGL::MOUSE_MODE_VOLUME_PAINT_EDIT)); } if (voxelColoring->isUnderlayOrOverlay(BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_SEGMENTATION)) { mouseModeComboBox->addItem("Volume Segmentation Edit", static_cast(GuiBrainModelOpenGL::MOUSE_MODE_VOLUME_SEGMENTATION_EDIT)); } } break; } } // // Display the current mode // int defaultItem = 0; const int num = mouseModeComboBox->count(); for (int i = 0; i < num; i++) { const GuiBrainModelOpenGL::MOUSE_MODES mode = static_cast(mouseModeComboBox->itemData(i).toInt()); if (mode == brainModelOpenGL->getMouseMode()) { defaultItem = i; break; } } mouseModeComboBox->blockSignals(true); mouseModeComboBox->setCurrentIndex(defaultItem); mouseModeComboBox->blockSignals(false); } /** * called when a mouse mode is selected. */ void GuiToolBar::slotMouseModeComboBoxActivated(int indx) { // // Set the mouse mode // if ((indx >= 0) && (indx < mouseModeComboBox->count())) { const GuiBrainModelOpenGL::MOUSE_MODES mode = static_cast(mouseModeComboBox->itemData(indx).toInt()); if (mode != GuiBrainModelOpenGL::MOUSE_MODE_NONE) { brainModelOpenGL->setMouseMode(mode); // // main window actions // GuiMainWindowLayersActions* layersActions = theMainWindow->getLayersActions(); GuiMainWindowVolumeActions* volumeActions = theMainWindow->getVolumeActions(); // // Possibly display dialogs // switch (mode) { case GuiBrainModelOpenGL::MOUSE_MODE_NONE: break; case GuiBrainModelOpenGL::MOUSE_MODE_VIEW: break; case GuiBrainModelOpenGL::MOUSE_MODE_BORDER_DRAW: { QAction* action = layersActions->getBordersDrawAction(); action->trigger(); } break; case GuiBrainModelOpenGL::MOUSE_MODE_BORDER_DRAW_NEW: break; case GuiBrainModelOpenGL::MOUSE_MODE_BORDER_DELETE: break; case GuiBrainModelOpenGL::MOUSE_MODE_BORDER_DELETE_POINT: break; case GuiBrainModelOpenGL::MOUSE_MODE_BORDER_INTERPOLATE: break; case GuiBrainModelOpenGL::MOUSE_MODE_BORDER_INTERPOLATE_NEW: break; case GuiBrainModelOpenGL::MOUSE_MODE_BORDER_MOVE_POINT: break; case GuiBrainModelOpenGL::MOUSE_MODE_BORDER_REVERSE: break; case GuiBrainModelOpenGL::MOUSE_MODE_BORDER_RENAME: break; case GuiBrainModelOpenGL::MOUSE_MODE_BORDER_UPDATE: break; case GuiBrainModelOpenGL::MOUSE_MODE_BORDER_UPDATE_NEW: break; case GuiBrainModelOpenGL::MOUSE_MODE_CUT_DRAW: { DisplaySettingsCuts* dsc = theMainWindow->getBrainSet()->getDisplaySettingsCuts(); dsc->setDisplayCuts(! dsc->getDisplayCuts()); GuiBrainModelOpenGL::updateAllGL(NULL); } break; case GuiBrainModelOpenGL::MOUSE_MODE_CUT_DELETE: break; case GuiBrainModelOpenGL::MOUSE_MODE_FOCI_DELETE: break; case GuiBrainModelOpenGL::MOUSE_MODE_CELL_ADD: { QAction* action = layersActions->getCellsAddAction(); action->trigger(); } break; case GuiBrainModelOpenGL::MOUSE_MODE_CELL_DELETE: break; case GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_BORDER_SELECT: break; case GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_PAINT_INDEX_SELECT: break; case GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_METRIC_NODE_SELECT: break; case GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_GEODESIC_NODE_SELECT: break; case GuiBrainModelOpenGL::MOUSE_MODE_ALIGN_STANDARD_ORIENTATION: break; case GuiBrainModelOpenGL::MOUSE_MODE_ALIGN_STANDARD_ORIENTATION_FULL_HEM_FLATTEN: break; case GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_SET_SCALE: break; case GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_DRAW: { QAction* action = layersActions->getContourDrawAction(); action->trigger(); } break; case GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_ALIGN: break; case GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_ALIGN_REGION: break; case GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_POINT_MOVE: break; case GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_POINT_DELETE: break; case GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_DELETE: break; case GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_REVERSE: break; case GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_MERGE: break; case GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_CELL_ADD: { QAction* action = layersActions->getCellsAddAction(); action->trigger(); } break; case GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_CELL_DELETE: break; case GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_CELL_MOVE: break; case GuiBrainModelOpenGL::MOUSE_MODE_VOLUME_SEGMENTATION_EDIT: { QAction* action = volumeActions->getEditSegmentationAction(); action->trigger(); } break; case GuiBrainModelOpenGL::MOUSE_MODE_EDIT_ADD_NODE: break; case GuiBrainModelOpenGL::MOUSE_MODE_EDIT_ADD_TILE: break; case GuiBrainModelOpenGL::MOUSE_MODE_EDIT_DELETE_TILE_BY_LINK: break; case GuiBrainModelOpenGL::MOUSE_MODE_EDIT_DISCONNECT_NODE: break; case GuiBrainModelOpenGL::MOUSE_MODE_EDIT_MOVE_NODE: break; case GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_SHAPE_NODE_SELECT: break; case GuiBrainModelOpenGL::MOUSE_MODE_TRANSFORMATION_MATRIX_AXES: break; case GuiBrainModelOpenGL::MOUSE_MODE_TRANSFORMATION_MATRIX_SET_TRANSLATE: break; case GuiBrainModelOpenGL::MOUSE_MODE_VOLUME_PAINT_EDIT: { QAction* action = volumeActions->getEditPaintVolumeAction(); action->trigger(); } break; case GuiBrainModelOpenGL::MOUSE_MODE_IMAGE_SUBREGION: break; case GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_SULCAL_BORDER_NODE_START: break; case GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_SULCAL_BORDER_NODE_END: break; } } } } caret-5.6.4~dfsg.1.orig/caret/GuiTextBrowser.h0000664000175000017500000000253711572067322020774 0ustar michaelmichael #ifndef __GUI_TEXT_BROWSER_H__ #define __GUI_TEXT_BROWSER_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include /// extend QTextBrowser to intercept web pages class GuiTextBrowser : public QTextBrowser { Q_OBJECT public: /// constructor GuiTextBrowser(QWidget* parent = 0); /// destructor virtual ~GuiTextBrowser(); public slots: /// intercept http web pages void setSource(const QUrl& name); protected: }; #endif // __GUI_TEXT_BROWSER_H__ caret-5.6.4~dfsg.1.orig/caret/GuiTextBrowser.cxx0000664000175000017500000000306711572067322021346 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "GuiMainWindow.h" #include "GuiTextBrowser.h" #include "global_variables.h" /** * constructor. */ GuiTextBrowser::GuiTextBrowser(QWidget* parent) : QTextBrowser(parent) { } /** * destructor. */ GuiTextBrowser::~GuiTextBrowser() { } /** * intercept http web pages. */ void GuiTextBrowser::setSource(const QUrl& name) { const QString pageName(name.toString()); if (pageName.startsWith("http://")) { setHtml("The help page requested (" + pageName + ") is a web site and " "will be displayed in your web browser"); theMainWindow->displayWebPage(pageName); return; } QTextBrowser::setSource(name); } caret-5.6.4~dfsg.1.orig/caret/GuiSurfaceTypeComboBox.h0000664000175000017500000000336511572067322022367 0ustar michaelmichael #ifndef __GUI_SURFACE_TYPE_COMBO_BOX_H__ #define __GUI_SURFACE_TYPE_COMBO_BOX_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "BrainModelSurface.h" /// combo box for choosing a surface type class GuiSurfaceTypeComboBox : public QComboBox { Q_OBJECT public: // constructor GuiSurfaceTypeComboBox(const bool showUnknown = true, QWidget* parent = 0); // constructor GuiSurfaceTypeComboBox(const std::vector showTheseTypes, QWidget* parent = 0); // destructor ~GuiSurfaceTypeComboBox(); // set surface type void setSurfaceType(const BrainModelSurface::SURFACE_TYPES st); // get surface type BrainModelSurface::SURFACE_TYPES getSurfaceType() const; protected: }; #endif // __GUI_SURFACE_TYPE_COMBO_BOX_H__ caret-5.6.4~dfsg.1.orig/caret/GuiSurfaceTypeComboBox.cxx0000664000175000017500000001024011572067322022730 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "GuiSurfaceTypeComboBox.h" /** * constructor. */ GuiSurfaceTypeComboBox::GuiSurfaceTypeComboBox(const bool showUnknown, QWidget* parent) : QComboBox(parent) { addItem(BrainModelSurface::getSurfaceConfigurationIDFromType(BrainModelSurface::SURFACE_TYPE_RAW), static_cast(BrainModelSurface::SURFACE_TYPE_RAW)); addItem(BrainModelSurface::getSurfaceConfigurationIDFromType(BrainModelSurface::SURFACE_TYPE_FIDUCIAL), static_cast(BrainModelSurface::SURFACE_TYPE_FIDUCIAL)); addItem(BrainModelSurface::getSurfaceConfigurationIDFromType(BrainModelSurface::SURFACE_TYPE_INFLATED), static_cast(BrainModelSurface::SURFACE_TYPE_INFLATED)); addItem(BrainModelSurface::getSurfaceConfigurationIDFromType(BrainModelSurface::SURFACE_TYPE_VERY_INFLATED), static_cast(BrainModelSurface::SURFACE_TYPE_VERY_INFLATED)); addItem(BrainModelSurface::getSurfaceConfigurationIDFromType(BrainModelSurface::SURFACE_TYPE_SPHERICAL), static_cast(BrainModelSurface::SURFACE_TYPE_SPHERICAL)); addItem(BrainModelSurface::getSurfaceConfigurationIDFromType(BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL), static_cast(BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL)); addItem(BrainModelSurface::getSurfaceConfigurationIDFromType(BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL), static_cast(BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL)); addItem(BrainModelSurface::getSurfaceConfigurationIDFromType(BrainModelSurface::SURFACE_TYPE_FLAT), static_cast(BrainModelSurface::SURFACE_TYPE_FLAT)); addItem(BrainModelSurface::getSurfaceConfigurationIDFromType(BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR), static_cast(BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR)); addItem(BrainModelSurface::getSurfaceConfigurationIDFromType(BrainModelSurface::SURFACE_TYPE_HULL), static_cast(BrainModelSurface::SURFACE_TYPE_HULL)); if (showUnknown) { addItem(BrainModelSurface::getSurfaceConfigurationIDFromType(BrainModelSurface::SURFACE_TYPE_UNKNOWN), static_cast(BrainModelSurface::SURFACE_TYPE_UNKNOWN)); setSurfaceType(BrainModelSurface::SURFACE_TYPE_UNKNOWN); } } /** * constructor. */ GuiSurfaceTypeComboBox::GuiSurfaceTypeComboBox(const std::vector showTheseTypes, QWidget* parent) : QComboBox(parent) { for (unsigned int i = 0; i < showTheseTypes.size(); i++) { const BrainModelSurface::SURFACE_TYPES st = showTheseTypes[i]; addItem(BrainModelSurface::getSurfaceConfigurationIDFromType(st), static_cast(st)); } } /** * destructor. */ GuiSurfaceTypeComboBox::~GuiSurfaceTypeComboBox() { } /** * set surface type. */ void GuiSurfaceTypeComboBox::setSurfaceType(const BrainModelSurface::SURFACE_TYPES st) { for (int i = 0; i < count(); i++) { if (itemData(i).toInt() == static_cast(st)) { setCurrentIndex(i); return; } } } /** * get surface type. */ BrainModelSurface::SURFACE_TYPES GuiSurfaceTypeComboBox::getSurfaceType() const { return static_cast(itemData(currentIndex()).toInt()); } caret-5.6.4~dfsg.1.orig/caret/GuiSurfaceTopologyReportDialog.h0000664000175000017500000000614711572067322024146 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_SURFACE_TOPOLOGY_REPORT_DIALOG_H__ #define __GUI_SURFACE_TOPOLOGY_REPORT_DIALOG_H__ #include #include "WuQDialog.h" class QCheckBox; class QLabel; class QTextBrowser; /// Dialog for displaying a surface topology error report class GuiSurfaceTopologyReportDialog : public WuQDialog { Q_OBJECT public: /// constructor GuiSurfaceTopologyReportDialog(QWidget* parent); /// destructor ~GuiSurfaceTopologyReportDialog(); /// show the dialog (overrides QDialog's show()) virtual void show(); protected slots: /// called when apply button pressed void slotApplyButton(); /// called when close button pressed void slotCloseButton(); protected: /// clear the dialog's data void clearDialog(); /// set the label with green if the value is correct, else red. void setLabel(QLabel* label, const int value, const int correctValue, const QString& message = ""); /// show non-manifold nodes check box QCheckBox* showNonManifoldNodesCheckBox; /// show straggler tiles check box QCheckBox* showStragglerTilesCheckBox; /// degenerate edges check box QCheckBox* degenEdgesCheckBox; /// surface type label QLabel* surfaceTypeLabel; /// non-manifold nodes label QLabel* nonManifoldNodesLabel; /// straggler tiles label QLabel* stragglerTilesLabel; /// degenerate edges label QLabel* degenEdgesLabel; /// number of objects label QLabel* numberOfObjectsLabel; /// euler count label QLabel* eulerCountLabel; /// numbe of holes label QLabel* numberOfHolesLabel; /// nodes label QLabel* numberOfNodesLabel; /// connected nodes label QLabel* numberOfConnectedNodesLabel; /// edges label QLabel* numberOfEdgesLabel; /// tiles label QLabel* numberOfTilesLabel; /// default label value QString defaultLabelValue; /// text browser for information QTextBrowser* infoTextBrowser; }; #endif // __GUI_SURFACE_TOPOLOGY_REPORT_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiSurfaceTopologyReportDialog.cxx0000664000175000017500000003375211572067322024523 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include "BrainModelSurface.h" #include "BrainSet.h" #include "BrainSetNodeAttribute.h" #include "GuiBrainModelOpenGL.h" #include "GuiMainWindow.h" #include "GuiSurfaceTopologyReportDialog.h" #include "QtUtilities.h" #include "TopologyFile.h" #include "global_variables.h" /** * constructor. */ GuiSurfaceTopologyReportDialog::GuiSurfaceTopologyReportDialog(QWidget* parent) : WuQDialog(parent) { setWindowTitle("Topology Error Report"); defaultLabelValue = " "; // // Layout for dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(3); // // Show non-manifold nodes check box // showNonManifoldNodesCheckBox = new QCheckBox("Show Non-manifold Nodes"); showNonManifoldNodesCheckBox->setChecked(true); // // Show straggler tiles check box // showStragglerTilesCheckBox = new QCheckBox("Show Straggler Tiles"); showStragglerTilesCheckBox->setChecked(true); // // Degenerate edges check box // degenEdgesCheckBox = new QCheckBox("Show Degenerate Links"); degenEdgesCheckBox->setChecked(true); // // Query group box // QGroupBox* queryBox = new QGroupBox("Query"); dialogLayout->addWidget(queryBox); QVBoxLayout* queryLayout = new QVBoxLayout(queryBox); queryLayout->addWidget(showNonManifoldNodesCheckBox); queryLayout->addWidget(showStragglerTilesCheckBox); queryLayout->addWidget(degenEdgesCheckBox); // // Group box for results // QGroupBox* reportBox = new QGroupBox("Results"); dialogLayout->addWidget(reportBox); QGridLayout* reportLayout = new QGridLayout(reportBox); int rowNum = 0; // // toplogy type items // reportLayout->addWidget(new QLabel("Surface Type "), rowNum, 0); surfaceTypeLabel = new QLabel(defaultLabelValue); reportLayout->addWidget(surfaceTypeLabel, rowNum, 1); rowNum++; // // non-manfifold nodes items // reportLayout->addWidget(new QLabel("Non-manifold Nodes "), rowNum, 0); nonManifoldNodesLabel = new QLabel(defaultLabelValue); reportLayout->addWidget(nonManifoldNodesLabel, rowNum, 1); rowNum++; // // straggler tiles items // reportLayout->addWidget(new QLabel("Straggler Tiles "), rowNum, 0); stragglerTilesLabel = new QLabel(defaultLabelValue); reportLayout->addWidget(stragglerTilesLabel, rowNum, 1); rowNum++; // // degenerate edges items // reportLayout->addWidget(new QLabel("Degenerate Links "), rowNum, 0); degenEdgesLabel = new QLabel(defaultLabelValue); reportLayout->addWidget(degenEdgesLabel, rowNum, 1); rowNum++; // // number of objects items // reportLayout->addWidget(new QLabel("Number of Objects "), rowNum, 0); numberOfObjectsLabel = new QLabel(defaultLabelValue); reportLayout->addWidget(numberOfObjectsLabel, rowNum, 1); rowNum++; // // euler count items // reportLayout->addWidget(new QLabel("Euler Count"), rowNum, 0); eulerCountLabel = new QLabel(defaultLabelValue); reportLayout->addWidget(eulerCountLabel, rowNum, 1); rowNum++; // // number of holes items // reportLayout->addWidget(new QLabel("Number of Handles "), rowNum, 0); numberOfHolesLabel = new QLabel(defaultLabelValue); reportLayout->addWidget(numberOfHolesLabel, rowNum, 1); rowNum++; // // number of nodes items // reportLayout->addWidget(new QLabel("Total Nodes "), rowNum, 0); numberOfNodesLabel = new QLabel(defaultLabelValue); reportLayout->addWidget(numberOfNodesLabel, rowNum, 1); rowNum++; // // number of connected nodes items // reportLayout->addWidget(new QLabel("Connected Nodes "), rowNum, 0); numberOfConnectedNodesLabel = new QLabel(defaultLabelValue); reportLayout->addWidget(numberOfConnectedNodesLabel, rowNum, 1); rowNum++; // // number of edges items // reportLayout->addWidget(new QLabel("Number of Edges "), rowNum, 0); numberOfEdgesLabel = new QLabel(defaultLabelValue); reportLayout->addWidget(numberOfEdgesLabel, rowNum, 1); rowNum++; // // number of tiles items // reportLayout->addWidget(new QLabel("Number of Tiles "), rowNum, 0); numberOfTilesLabel = new QLabel(defaultLabelValue); reportLayout->addWidget(numberOfTilesLabel, rowNum, 1); rowNum++; // // Help information box // QGroupBox* helpBox = new QGroupBox("Information"); dialogLayout->addWidget(helpBox); QVBoxLayout* helpLayout = new QVBoxLayout(helpBox); // // Info text browser // infoTextBrowser = new QTextBrowser; helpLayout->addWidget(infoTextBrowser); QString infoText = "" "Non-manifold Nodes
    " "Non-manifold nodes are nodes that have at least 4 boundary edges. " "A simple example would be two triangles that are connected at only a single node. " "In Caret terminology we might refer to this as a bowtie." "

    " "Straggler Tiles
    " "Straggler tiles are tiles that are connected to the surface at only a single node " "in the tile and can cause problems during multi-resolution morphing. Stragglers " "can be removed by using Surface Menu:Topology:Remove Corner And Straggler Tiles. " "

    " "Degenerate Links
    " "Degenerate links are links that are used by three or more triangles. " "Interior links use two triangles and boundary links use one triangle. " "

    " "Number of Objects
    " "Number of objects is the number of disjoint (unconnected) pieces of surface. " "If there is more than one object, all but the largest object can be removed " "using Surface Menu:Topology:Remove Islands." "

    " "Euler Count
    " "An Euler Count is a formula that tells us if the surface is properly made up of " "triangles and nodes. A 3D closed surface will have an Euler count of 2. An flat " "surface will have an Euler count of 1. The formula for an Euler count is " "Nodes - Links + Triangles. More information about the Euler count is available " "at http://mathworld.wolfram.com/EulerCharacteristic.html." "

    " "Number of Handles
    " "The number of handles is derived using the Euler count. If there is more than one " "object or there are degenerate edges, the number of handles may be incorrect. " "The number of handles (holes) is also known as the genus. See " "http://mathworld.wolfram.com/Genus.html for more information. " "

    " ""; infoTextBrowser->setHtml(infoText); // // Layout for buttons // QHBoxLayout* buttonLayout = new QHBoxLayout; buttonLayout->setSpacing(5); dialogLayout->addLayout(buttonLayout); // // Apply button // QPushButton* applyButton = new QPushButton("Apply"); applyButton->setAutoDefault(false); buttonLayout->addWidget(applyButton); QObject::connect(applyButton, SIGNAL(clicked()), this, SLOT(slotApplyButton())); // // close button // QPushButton* closeButton = new QPushButton("Close"); closeButton->setAutoDefault(false); buttonLayout->addWidget(closeButton); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(slotCloseButton())); QtUtilities::makeButtonsSameSize(applyButton, closeButton); } /** * destructor. */ GuiSurfaceTopologyReportDialog::~GuiSurfaceTopologyReportDialog() { } /** * show the dialog (overrides QDialog's show()). */ void GuiSurfaceTopologyReportDialog::show() { clearDialog(); WuQDialog::show(); slotApplyButton(); } /** * clear the dialog's data. */ void GuiSurfaceTopologyReportDialog::clearDialog() { surfaceTypeLabel->setText(defaultLabelValue); nonManifoldNodesLabel->setText(defaultLabelValue); stragglerTilesLabel->setText(defaultLabelValue); degenEdgesLabel->setText(defaultLabelValue); numberOfObjectsLabel->setText(defaultLabelValue); eulerCountLabel->setText(defaultLabelValue); numberOfHolesLabel->setText(defaultLabelValue); numberOfNodesLabel->setText(defaultLabelValue); numberOfConnectedNodesLabel->setText(defaultLabelValue); numberOfEdgesLabel->setText(defaultLabelValue); numberOfTilesLabel->setText(defaultLabelValue); } /** * called when apply button pressed. */ void GuiSurfaceTopologyReportDialog::slotApplyButton() { clearDialog(); BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms == NULL) { return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); const TopologyFile* tf = bms->getTopologyFile(); // // Determine if the surface is 2D or 3D // bool twoDimFlag = true; const CoordinateFile* cf = bms->getCoordinateFile(); const int numCoords = cf->getNumberOfCoordinates(); for (int i = 0; i < numCoords; i++) { const float* xyz = cf->getCoordinate(i); if (xyz[2] != 0.0) { twoDimFlag = false; break; } } std::vector nonManifoldNodes; tf->getNonManifoldNodes(nonManifoldNodes); int numDegenerateEdges; std::vector nodesUsedByDegenerateEdges; tf->getDegenerateEdges(numDegenerateEdges, nodesUsedByDegenerateEdges); std::vector stragglerTiles; tf->findCornerTiles(2, stragglerTiles); int numFaces, numVertices, numEdges, eulerCount, numHoles, numObjects; tf->getEulerCount(twoDimFlag, numFaces, numVertices, numEdges, eulerCount, numHoles, numObjects); int correctEulerCount = 2; if (twoDimFlag) { correctEulerCount = 1; surfaceTypeLabel->setText("2D"); } else { surfaceTypeLabel->setText("3D"); } setLabel(nonManifoldNodesLabel, nonManifoldNodes.size(), 0); setLabel(stragglerTilesLabel, stragglerTiles.size(), 0); setLabel(degenEdgesLabel, numDegenerateEdges, 0); setLabel(numberOfObjectsLabel, numObjects, 1); setLabel(eulerCountLabel, eulerCount, correctEulerCount); if (numObjects != 1) { setLabel(numberOfHolesLabel, numHoles, 0, "(Multiple Objects)"); } else { setLabel(numberOfHolesLabel, numHoles, 0); } numberOfNodesLabel->setText(QString::number(bms->getNumberOfNodes())); numberOfConnectedNodesLabel->setText(QString::number(numVertices)); numberOfEdgesLabel->setText(QString::number(numEdges)); numberOfTilesLabel->setText(QString::number(numFaces)); if (showNonManifoldNodesCheckBox->isChecked() || degenEdgesCheckBox->isChecked() || showStragglerTilesCheckBox->isChecked()) { theMainWindow->getBrainSet()->clearNodeHighlightSymbols(); } if (showNonManifoldNodesCheckBox->isChecked()) { for (unsigned int i = 0; i < nonManifoldNodes.size(); i++) { BrainSetNodeAttribute* bna = theMainWindow->getBrainSet()->getNodeAttributes(nonManifoldNodes[i]); bna->setHighlighting(BrainSetNodeAttribute::HIGHLIGHT_NODE_LOCAL); } } if (showStragglerTilesCheckBox->isChecked()) { for (unsigned int i = 0; i < stragglerTiles.size(); i++) { int n1, n2, n3; tf->getTile(stragglerTiles[i], n1, n2, n3); BrainSetNodeAttribute* bna = theMainWindow->getBrainSet()->getNodeAttributes(n1); bna->setHighlighting(BrainSetNodeAttribute::HIGHLIGHT_NODE_LOCAL); bna = theMainWindow->getBrainSet()->getNodeAttributes(n2); bna->setHighlighting(BrainSetNodeAttribute::HIGHLIGHT_NODE_LOCAL); bna = theMainWindow->getBrainSet()->getNodeAttributes(n3); bna->setHighlighting(BrainSetNodeAttribute::HIGHLIGHT_NODE_LOCAL); } } if (degenEdgesCheckBox->isChecked()) { for (unsigned int i = 0; i < nodesUsedByDegenerateEdges.size(); i++) { BrainSetNodeAttribute* bna = theMainWindow->getBrainSet()->getNodeAttributes(nodesUsedByDegenerateEdges[i]); bna->setHighlighting(BrainSetNodeAttribute::HIGHLIGHT_NODE_LOCAL); } } GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); QApplication::beep(); } /** * set the label with green if the value is correct, else red. */ void GuiSurfaceTopologyReportDialog::setLabel(QLabel* label, const int value, const int correctValue, const QString& message) { std::ostringstream str; str << ""; } else { str << "red>"; } str << value; if (message.isEmpty() == false) { str << " " << message.toAscii().constData(); } str << ""; if ((value != correctValue) && (message.isEmpty())) { str << " (should be " << correctValue << ")"; } label->setText(str.str().c_str()); } /** * called when close button pressed. */ void GuiSurfaceTopologyReportDialog::slotCloseButton() { clearDialog(); QDialog::close(); } caret-5.6.4~dfsg.1.orig/caret/GuiSurfaceToVolumeDialog.h0000664000175000017500000001756711572067322022720 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_SURFACE_TO_VOLUME_DIALOG_H__ #define __GUI_SURFACE_TO_VOLUME_DIALOG_H__ #include "WuQDialog.h" #include "BrainModelSurfaceToVolumeConverter.h" #include "StereotaxicSpace.h" #include "VolumeFile.h" class QCheckBox; class QComboBox; class QDoubleSpinBox; class QLabel; class QLineEdit; class QSpinBox; class BrainModel; class BrainModelSurface; class BrainModelVolume; class GuiBrainModelSelectionComboBox; class GuiNodeAttributeColumnSelectionComboBox; /// Dialog for converting a surface to a volume. class GuiSurfaceToVolumeDialog : public WuQDialog { Q_OBJECT public: /// mode of dialog enum DIALOG_MODE { DIALOG_MODE_NORMAL, DIALOG_MODE_PAINT, DIALOG_MODE_METRIC, DIALOG_MODE_SEGMENT_VOLUME, DIALOG_MODE_SURFACE_SHAPE }; /// Constructor GuiSurfaceToVolumeDialog(QWidget* parent, const DIALOG_MODE modeIn, const QString& dialogTitle, const bool showSurfaceSelectionOptionsFlag = true); /// Destructor ~GuiSurfaceToVolumeDialog(); /// get the selected surface BrainModelSurface* getSelectedSurface() const; /// get the selected node attribute (metric/paint/shape) column int getSelectedNodeAttributeColumn() const; /// get the offset void getSurfaceOffset(float offset[3]) const; /// get the inner boundary float getSurfaceInnerBoundary() const; /// get the outer boundary float getSurfaceOuterBoundary() const; /// get the desired surface thickness step float getSurfaceThicknessStep() const; /// get the volume dimensions void getVolumeDimensions(int dim[3]) const; /// set the volume dimensions void setVolumeDimensions(const int dim[3]); /// get the volume voxel sizes void getVolumeVoxelSizes(float voxelSize[3]) const; /// set the volume voxel sizes void setVolumeVoxelSizes(const float voxelSize[3]); /// Get the volume origin. void getVolumeOrigin(float origin[3]) const; /// Set the volume origin. void setVolumeOrigin(const float origin[3]); /// get the standard volume space StereotaxicSpace getStandardVolumeSpace() const; /// get node to voxel mapping enabled bool getNodeToVoxelMappingEnabled() const; /// get node to voxel file name QString getNodeToVoxelMappingFileName() const; /// get the metric conversion mode BrainModelSurfaceToVolumeConverter::CONVERSION_MODE getMetricConversionMode() const; private slots: /// called when a volume space is selected void slotVolumeSpaceSelection(int item); /// called enter ac pushbutton is pressed void slotAcPushButton(); /// called when get parameters from volume file is pressed void slotParamtersFromVolumePushButton(); /// called when apply button pressed void done(int r); private: /// surface selection combo box GuiBrainModelSelectionComboBox* surfaceSelectionBox; /// surface offset X line edit QDoubleSpinBox* surfaceOffsetXDoubleSpinBox; /// surface offset Y line edit QDoubleSpinBox* surfaceOffsetYDoubleSpinBox; /// surface offset Z line edit QDoubleSpinBox* surfaceOffsetZDoubleSpinBox; /// surface inner boundary line edit QDoubleSpinBox* surfaceInnerBoundaryDoubleSpinBox; /// surface outer boundary line edit QDoubleSpinBox* surfaceOuterBoundaryDoubleSpinBox; /// surface thickness step line edit QDoubleSpinBox* surfaceThicknessStepDoubleSpinBox; /// volume X dimension line edit QSpinBox* volumeDimensionXSpinBox; /// volume Y dimension line edit QSpinBox* volumeDimensionYSpinBox; /// volume Z dimension line edit QSpinBox* volumeDimensionZSpinBox; /// volume voxel size x line edit QDoubleSpinBox* volumeVoxelSizeXDoubleSpinBox; /// volume voxel size y line edit QDoubleSpinBox* volumeVoxelSizeYDoubleSpinBox; /// volume voxel size z line edit QDoubleSpinBox* volumeVoxelSizeZDoubleSpinBox; /// volume origin x line edit QDoubleSpinBox* volumeOriginXDoubleSpinBox; /// volume origin y line edit QDoubleSpinBox* volumeOriginYDoubleSpinBox; /// volume origin z line edit QDoubleSpinBox* volumeOriginZDoubleSpinBox; /// mode of dialog DIALOG_MODE mode; /// combo box for space selection QComboBox* volumeSpaceComboBox; /// node attribute (metric/paint/shape) column selection combo box GuiNodeAttributeColumnSelectionComboBox* nodeAttributeColumnComboBox; /// metric algorithm combo box QComboBox* metricAlgorithmComboBox; /// node to voxel mapping check box QCheckBox* nodeToVoxelCheckBox; /// line edit for node to voxel file name QLineEdit* nodeToVoxelFileNameLineEdit; /// offset from last time static float savedOffset[3]; /// outer boundary from last time static float savedOuterBoundary; /// inner boundary from last time static float savedInnerBoundary; /// thickness step from last time static float savedThicknessStep; /// dimensions from last time static int savedDimensions[3]; /// voxel size from last time static float savedVoxelSize[3]; /// volume origin from last time static float savedOrigin[3]; /// surface from last time static BrainModel* savedSurface; /// volume space from last time static StereotaxicSpace savedVolumeSpace; /// create node to voxel mapping last time static bool savedNodeToVoxelMapping; /// node to voxel file name from last time static QString savedNodeToVoxelFileName; /// the standard volume spaces std::vector volumeSpaceComboBoxSpaces; }; #ifdef __GUI_SURFACE_TO_VOLUME_DIALOG_MAIN__ float GuiSurfaceToVolumeDialog::savedOffset[3] = { 0.0, 0.0, 0.0 }; float GuiSurfaceToVolumeDialog::savedInnerBoundary = -1.5; float GuiSurfaceToVolumeDialog::savedOuterBoundary = 1.5; float GuiSurfaceToVolumeDialog::savedThicknessStep = 0.5; int GuiSurfaceToVolumeDialog::savedDimensions[3] = { 0, 0, 0 }; float GuiSurfaceToVolumeDialog::savedVoxelSize[3] = { 1.0, 1.0, 1.0 }; float GuiSurfaceToVolumeDialog::savedOrigin[3] = { 0.0, 0.0, 0.0 }; BrainModel* GuiSurfaceToVolumeDialog::savedSurface = NULL; StereotaxicSpace GuiSurfaceToVolumeDialog::savedVolumeSpace; bool GuiSurfaceToVolumeDialog::savedNodeToVoxelMapping; QString GuiSurfaceToVolumeDialog::savedNodeToVoxelFileName; #endif // __GUI_SURFACE_TO_VOLUME_DIALOG_MAIN__ #endif // __GUI_SURFACE_TO_VOLUME_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiSurfaceToVolumeDialog.cxx0000664000175000017500000010672611572067322023267 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "WuQFileDialog.h" #include #include #include #include #include #include #include #include #include #define __GUI_SURFACE_TO_VOLUME_DIALOG_MAIN__ #include "GuiSurfaceToVolumeDialog.h" #undef __GUI_SURFACE_TO_VOLUME_DIALOG_MAIN__ #include "BrainSet.h" #include "DisplaySettingsMetric.h" #include "DisplaySettingsPaint.h" #include "DisplaySettingsSurfaceShape.h" #include "FileFilters.h" #include "GuiBrainModelSelectionComboBox.h" #include "GuiNodeAttributeColumnSelectionComboBox.h" #include "GuiMainWindow.h" #include "MetricFile.h" #include "PaintFile.h" #include "ParamsFile.h" #include "QtMultipleInputDialog.h" #include "QtUtilities.h" #include "SurfaceShapeFile.h" #include "global_variables.h" /** * Constructor. */ GuiSurfaceToVolumeDialog::GuiSurfaceToVolumeDialog(QWidget* parent, const DIALOG_MODE modeIn, const QString& dialogTitle, const bool showSurfaceSelectionOptionsFlag) : WuQDialog(parent) { mode = modeIn; static bool firstTime = true; setWindowTitle(dialogTitle); // // Find surface and volume from last time // int surfaceModelIndex = -1; for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfBrainModels(); i++) { if (savedSurface == theMainWindow->getBrainSet()->getBrainModel(i)) { surfaceModelIndex = i; } } // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // vertical box for surface selections // QGroupBox* surfaceGroupBox = new QGroupBox("Surface Selection", this); dialogLayout->addWidget(surfaceGroupBox); QVBoxLayout* surfaceGroupLayout = new QVBoxLayout(surfaceGroupBox); // // Surface File // surfaceSelectionBox = new GuiBrainModelSelectionComboBox(false, true, false, "", 0); surfaceGroupLayout->addWidget(surfaceSelectionBox); if (surfaceModelIndex >= 0) { surfaceSelectionBox->setSelectedBrainModelIndex(surfaceModelIndex); } if (showSurfaceSelectionOptionsFlag == false) { surfaceSelectionBox->setHidden(true); } const int spinWidth = 120; const double floatMin = -std::numeric_limits::max(); const double floatMax = std::numeric_limits::max(); const int intMax = std::numeric_limits::max(); // // Surface thickness and step grid // QGridLayout* surfaceGridLayout = new QGridLayout; surfaceGridLayout->setSpacing(3); surfaceGroupLayout->addLayout(surfaceGridLayout); int rowNum = 0; surfaceInnerBoundaryDoubleSpinBox = NULL; surfaceOuterBoundaryDoubleSpinBox = NULL; surfaceThicknessStepDoubleSpinBox = NULL; if (mode != DIALOG_MODE_SEGMENT_VOLUME) { // // Inner boundary label and text box // QLabel* innerLabel = new QLabel("Inner Boundary (mm)"); surfaceInnerBoundaryDoubleSpinBox = new QDoubleSpinBox; surfaceInnerBoundaryDoubleSpinBox->setFixedWidth(spinWidth); surfaceInnerBoundaryDoubleSpinBox->setSingleStep(0.5); surfaceInnerBoundaryDoubleSpinBox->setDecimals(3); surfaceInnerBoundaryDoubleSpinBox->setMinimum(floatMin); surfaceInnerBoundaryDoubleSpinBox->setMaximum(floatMax); surfaceInnerBoundaryDoubleSpinBox->setValue(savedInnerBoundary); surfaceGridLayout->addWidget(innerLabel, rowNum, 0); surfaceGridLayout->addWidget(surfaceInnerBoundaryDoubleSpinBox, rowNum, 1); rowNum++; // // Outer boundary label and text box // QLabel* outerLabel = new QLabel("Outer Boundary (mm)"); surfaceOuterBoundaryDoubleSpinBox = new QDoubleSpinBox; surfaceOuterBoundaryDoubleSpinBox->setFixedWidth(spinWidth); surfaceOuterBoundaryDoubleSpinBox->setSingleStep(0.5); surfaceOuterBoundaryDoubleSpinBox->setDecimals(3); surfaceOuterBoundaryDoubleSpinBox->setMinimum(floatMin); surfaceOuterBoundaryDoubleSpinBox->setMaximum(floatMax); surfaceOuterBoundaryDoubleSpinBox->setValue(savedOuterBoundary); surfaceGridLayout->addWidget(outerLabel, rowNum, 0); surfaceGridLayout->addWidget(surfaceOuterBoundaryDoubleSpinBox, rowNum, 1); rowNum++; // // Thickness step // QLabel* thickLabel = new QLabel("Intersection Step (mm)"); surfaceThicknessStepDoubleSpinBox = new QDoubleSpinBox; surfaceThicknessStepDoubleSpinBox->setFixedWidth(spinWidth); surfaceThicknessStepDoubleSpinBox->setSingleStep(0.5); surfaceThicknessStepDoubleSpinBox->setDecimals(3); surfaceThicknessStepDoubleSpinBox->setMinimum(0.0); surfaceThicknessStepDoubleSpinBox->setMinimum(floatMin); surfaceThicknessStepDoubleSpinBox->setMaximum(floatMax); surfaceThicknessStepDoubleSpinBox->setValue(savedThicknessStep); surfaceGridLayout->addWidget(thickLabel, rowNum, 0); surfaceGridLayout->addWidget(surfaceThicknessStepDoubleSpinBox, rowNum, 1); rowNum++; } // // Offset // QLabel* transLabel = new QLabel("Translation (mm)"); surfaceOffsetXDoubleSpinBox = new QDoubleSpinBox; surfaceOffsetXDoubleSpinBox->setFixedWidth(spinWidth); surfaceOffsetXDoubleSpinBox->setSingleStep(1.0); surfaceOffsetXDoubleSpinBox->setDecimals(3); surfaceOffsetXDoubleSpinBox->setMinimum(floatMin); surfaceOffsetXDoubleSpinBox->setMaximum(floatMax); surfaceOffsetYDoubleSpinBox = new QDoubleSpinBox; surfaceOffsetYDoubleSpinBox->setFixedWidth(spinWidth); surfaceOffsetYDoubleSpinBox->setSingleStep(1.0); surfaceOffsetYDoubleSpinBox->setDecimals(3); surfaceOffsetYDoubleSpinBox->setMinimum(floatMin); surfaceOffsetYDoubleSpinBox->setMaximum(floatMax); surfaceOffsetZDoubleSpinBox = new QDoubleSpinBox; surfaceOffsetZDoubleSpinBox->setFixedWidth(spinWidth); surfaceOffsetZDoubleSpinBox->setSingleStep(1.0); surfaceOffsetZDoubleSpinBox->setDecimals(3); surfaceOffsetZDoubleSpinBox->setMinimum(floatMin); surfaceOffsetZDoubleSpinBox->setMaximum(floatMax); surfaceGridLayout->addWidget(transLabel, rowNum, 0); surfaceGridLayout->addWidget(surfaceOffsetXDoubleSpinBox, rowNum, 1); surfaceGridLayout->addWidget(surfaceOffsetYDoubleSpinBox, rowNum, 2); surfaceGridLayout->addWidget(surfaceOffsetZDoubleSpinBox, rowNum, 3); rowNum++; if (showSurfaceSelectionOptionsFlag == false) { transLabel->setHidden(true); surfaceOffsetXDoubleSpinBox->setHidden(true); surfaceOffsetYDoubleSpinBox->setHidden(true); surfaceOffsetZDoubleSpinBox->setHidden(true); } const ParamsFile* pf = theMainWindow->getBrainSet()->getParamsFile(); if (showSurfaceSelectionOptionsFlag) { // // Parameters file contains information for offset // xmin, ymin, zmin // QString xmin, ymin, zmin; if (pf->getParameter(ParamsFile::keyXmin, xmin) && pf->getParameter(ParamsFile::keyYmin, ymin) && pf->getParameter(ParamsFile::keyZmin, zmin)) { QLabel* xyzLabel = new QLabel("XYZ min"); QLabel* xLabel = new QLabel(xmin); QLabel* yLabel = new QLabel(ymin); QLabel* zLabel = new QLabel(zmin); surfaceGridLayout->addWidget(xyzLabel, rowNum, 0); surfaceGridLayout->addWidget(xLabel, rowNum, 1); surfaceGridLayout->addWidget(yLabel, rowNum, 2); surfaceGridLayout->addWidget(zLabel, rowNum, 3); rowNum++; } // // AC position // QString acx, acy, acz; if (pf->getParameter(ParamsFile::keyACx, acx) && pf->getParameter(ParamsFile::keyACy, acy) && pf->getParameter(ParamsFile::keyACz, acz)) { QLabel* xyzLabel = new QLabel("AC xyz"); QLabel* xLabel = new QLabel(acx); QLabel* yLabel = new QLabel(acy); QLabel* zLabel = new QLabel(acz); surfaceGridLayout->addWidget(xyzLabel, rowNum, 0); surfaceGridLayout->addWidget(xLabel, rowNum, 1); surfaceGridLayout->addWidget(yLabel, rowNum, 2); surfaceGridLayout->addWidget(zLabel, rowNum, 3); rowNum++; } // // Whole volume ac // QString wholeAcx, wholeAcy, wholeAcz; if (pf->getParameter(ParamsFile::keyWholeVolumeACx, wholeAcx) && pf->getParameter(ParamsFile::keyWholeVolumeACy, wholeAcy) && pf->getParameter(ParamsFile::keyWholeVolumeACz, wholeAcz)) { QLabel* xyzLabel = new QLabel("Whole Vol AC xyz"); QLabel* xLabel = new QLabel(wholeAcx); QLabel* yLabel = new QLabel(wholeAcy); QLabel* zLabel = new QLabel(wholeAcz); surfaceGridLayout->addWidget(xyzLabel, rowNum, 0); surfaceGridLayout->addWidget(xLabel, rowNum, 1); surfaceGridLayout->addWidget(yLabel, rowNum, 2); surfaceGridLayout->addWidget(zLabel, rowNum, 3); rowNum++; } } // // Shrink the grid // //surfaceGrid->setFixedSize(surfaceGrid->sizeHint()); // // vertical box for volume selections // QGroupBox* volumeGroupBox = new QGroupBox("Volume Selection"); dialogLayout->addWidget(volumeGroupBox); QVBoxLayout* volumeGroupLayout = new QVBoxLayout(volumeGroupBox); // // Grid for volume parameters // QGridLayout* volumeGridLayout = new QGridLayout; volumeGridLayout->setSpacing(3); volumeGroupLayout->addLayout(volumeGridLayout); int rowNumber = 0; // // Volume Space // int spaceIndex = -1; volumeGridLayout->addWidget(new QLabel("Space"), rowNumber, 0, Qt::AlignLeft); volumeSpaceComboBox = new QComboBox; volumeGridLayout->addWidget(volumeSpaceComboBox, rowNumber, 1, 1, 3, Qt::AlignLeft); StereotaxicSpace::getAllStereotaxicSpaces(volumeSpaceComboBoxSpaces); for (unsigned int i = 0; i < volumeSpaceComboBoxSpaces.size(); i++) { volumeSpaceComboBox->addItem(volumeSpaceComboBoxSpaces[i].getName()); if (savedVolumeSpace == volumeSpaceComboBoxSpaces[i]) { spaceIndex = i; } } QObject::connect(volumeSpaceComboBox, SIGNAL(activated(int)), this, SLOT(slotVolumeSpaceSelection(int))); rowNumber++; // // Volume Dimensions // volumeGridLayout->addWidget(new QLabel("Dimension"), rowNumber, 0, Qt::AlignLeft); volumeDimensionXSpinBox = new QSpinBox; volumeDimensionXSpinBox->setMinimum(1); volumeDimensionXSpinBox->setMaximum(intMax); volumeDimensionXSpinBox->setSingleStep(1); volumeDimensionXSpinBox->setFixedWidth(spinWidth); volumeGridLayout->addWidget(volumeDimensionXSpinBox, rowNumber, 1, Qt::AlignLeft); volumeDimensionYSpinBox = new QSpinBox; volumeDimensionYSpinBox->setMinimum(1); volumeDimensionYSpinBox->setMaximum(intMax); volumeDimensionYSpinBox->setSingleStep(1); volumeDimensionYSpinBox->setFixedWidth(spinWidth); volumeGridLayout->addWidget(volumeDimensionYSpinBox, rowNumber, 2, Qt::AlignLeft); volumeDimensionZSpinBox = new QSpinBox; volumeDimensionZSpinBox->setMinimum(1); volumeDimensionZSpinBox->setMaximum(intMax); volumeDimensionZSpinBox->setSingleStep(1); volumeDimensionZSpinBox->setFixedWidth(spinWidth); volumeGridLayout->addWidget(volumeDimensionZSpinBox, rowNumber, 3, Qt::AlignLeft); rowNumber++; // // Volume voxel sizes // volumeGridLayout->addWidget(new QLabel("Voxel Size"), rowNumber, 0, Qt::AlignLeft); volumeVoxelSizeXDoubleSpinBox = new QDoubleSpinBox; volumeVoxelSizeXDoubleSpinBox->setFixedWidth(spinWidth); volumeVoxelSizeXDoubleSpinBox->setSingleStep(0.5); volumeVoxelSizeXDoubleSpinBox->setDecimals(3); volumeVoxelSizeXDoubleSpinBox->setMinimum(0.0); volumeVoxelSizeXDoubleSpinBox->setMaximum(floatMax); volumeGridLayout->addWidget(volumeVoxelSizeXDoubleSpinBox, rowNumber, 1, Qt::AlignLeft); volumeVoxelSizeYDoubleSpinBox = new QDoubleSpinBox; volumeVoxelSizeYDoubleSpinBox->setFixedWidth(spinWidth); volumeVoxelSizeYDoubleSpinBox->setSingleStep(0.5); volumeVoxelSizeYDoubleSpinBox->setDecimals(3); volumeVoxelSizeYDoubleSpinBox->setMinimum(0.0); volumeVoxelSizeYDoubleSpinBox->setMaximum(floatMax); volumeGridLayout->addWidget(volumeVoxelSizeYDoubleSpinBox, rowNumber, 2, Qt::AlignLeft); volumeVoxelSizeZDoubleSpinBox = new QDoubleSpinBox; volumeVoxelSizeZDoubleSpinBox->setFixedWidth(spinWidth); volumeVoxelSizeZDoubleSpinBox->setSingleStep(0.5); volumeVoxelSizeZDoubleSpinBox->setDecimals(3); volumeVoxelSizeZDoubleSpinBox->setMinimum(0.0); volumeVoxelSizeZDoubleSpinBox->setMaximum(floatMax); volumeGridLayout->addWidget(volumeVoxelSizeZDoubleSpinBox, rowNumber, 3, Qt::AlignLeft); rowNumber++; // // Volume origin // volumeGridLayout->addWidget(new QLabel("Volume Origin at Center\nof First Voxel"), rowNumber, 0, Qt::AlignLeft); volumeOriginXDoubleSpinBox = new QDoubleSpinBox; volumeOriginXDoubleSpinBox->setFixedWidth(spinWidth); volumeOriginXDoubleSpinBox->setSingleStep(0.5); volumeOriginXDoubleSpinBox->setDecimals(3); volumeOriginXDoubleSpinBox->setMinimum(floatMin); volumeOriginXDoubleSpinBox->setMaximum(floatMax); volumeGridLayout->addWidget(volumeOriginXDoubleSpinBox, rowNumber, 1, Qt::AlignLeft); volumeOriginYDoubleSpinBox = new QDoubleSpinBox; volumeOriginYDoubleSpinBox->setFixedWidth(spinWidth); volumeOriginYDoubleSpinBox->setSingleStep(0.5); volumeOriginYDoubleSpinBox->setDecimals(3); volumeOriginYDoubleSpinBox->setMinimum(floatMin); volumeOriginYDoubleSpinBox->setMaximum(floatMax); volumeGridLayout->addWidget(volumeOriginYDoubleSpinBox, rowNumber, 2, Qt::AlignLeft); volumeOriginZDoubleSpinBox = new QDoubleSpinBox; volumeOriginZDoubleSpinBox->setFixedWidth(spinWidth); volumeOriginZDoubleSpinBox->setSingleStep(0.5); volumeOriginZDoubleSpinBox->setDecimals(3); volumeOriginZDoubleSpinBox->setMinimum(floatMin); volumeOriginZDoubleSpinBox->setMaximum(floatMax); volumeGridLayout->addWidget(volumeOriginZDoubleSpinBox, rowNumber, 3, Qt::AlignLeft); rowNumber++; // // Volume dimensions // QString xdim, ydim, zdim; if (pf->getParameter(ParamsFile::keyXdim, xdim) && pf->getParameter(ParamsFile::keyYdim, ydim) && pf->getParameter(ParamsFile::keyZdim, zdim)) { volumeGridLayout->addWidget(new QLabel("XYZ dim"), rowNumber, 0, Qt::AlignLeft); volumeGridLayout->addWidget(new QLabel(xdim), rowNumber, 1, Qt::AlignLeft); volumeGridLayout->addWidget(new QLabel(ydim), rowNumber, 2, Qt::AlignLeft); volumeGridLayout->addWidget(new QLabel(zdim), rowNumber, 3, Qt::AlignLeft); rowNumber++; if (firstTime) { savedDimensions[0] = xdim.toInt(); savedDimensions[1] = ydim.toInt(); savedDimensions[2] = zdim.toInt(); } } // // Whole volume dimensions // QString wholeXdim, wholeYdim, wholeZdim; if (pf->getParameter(ParamsFile::keyXdim, wholeXdim) && pf->getParameter(ParamsFile::keyYdim, wholeYdim) && pf->getParameter(ParamsFile::keyZdim, wholeZdim)) { volumeGridLayout->addWidget(new QLabel("Whole XYZ dim"), rowNumber, 0, Qt::AlignLeft); volumeGridLayout->addWidget(new QLabel(wholeXdim), rowNumber, 1, Qt::AlignLeft); volumeGridLayout->addWidget(new QLabel(wholeYdim), rowNumber, 2, Qt::AlignLeft); volumeGridLayout->addWidget(new QLabel(wholeZdim), rowNumber, 3, Qt::AlignLeft); rowNumber++; if (firstTime) { savedDimensions[0] = wholeXdim.toInt(); savedDimensions[1] = wholeYdim.toInt(); savedDimensions[2] = wholeZdim.toInt(); } } QString resolution; if (pf->getParameter(ParamsFile::keyResolution, resolution)) { volumeGridLayout->addWidget(new QLabel("Resolution"), rowNumber, 0, Qt::AlignLeft); volumeGridLayout->addWidget(new QLabel(resolution), rowNumber, 1, Qt::AlignLeft); volumeGridLayout->addWidget(new QLabel(" "), rowNumber, 2, Qt::AlignLeft); volumeGridLayout->addWidget(new QLabel(" "), rowNumber, 3, Qt::AlignLeft); rowNumber++; } // // Enter AC button // QPushButton* acPushButton = new QPushButton("Enter AC to Determine Origin..."); acPushButton->setAutoDefault(false); acPushButton->setFixedSize(acPushButton->sizeHint()); QObject::connect(acPushButton, SIGNAL(clicked()), this, SLOT(slotAcPushButton())); acPushButton->setToolTip("This button displays a dialog for entry of the \n" "Anterior Commissure voxel indices. These voxel\n" "indices will be used with the voxel size in the\n" "dialog to determine the volume origin."); volumeGroupLayout->addWidget(acPushButton); // // Get parameters from a volume file // QPushButton* paramtersFromVolumePushButton = new QPushButton("Get Parameters Using a Volume File..."); paramtersFromVolumePushButton->setAutoDefault(false); paramtersFromVolumePushButton->setFixedSize(paramtersFromVolumePushButton->sizeHint()); QObject::connect(paramtersFromVolumePushButton, SIGNAL(clicked()), this, SLOT(slotParamtersFromVolumePushButton())); paramtersFromVolumePushButton->setToolTip( "This button displays a dialog for selecting a volume\n" "file. The volume's dimensions, voxel size, and origin\n" "will be placed into the dialog."); volumeGroupLayout->addWidget(paramtersFromVolumePushButton); // // Initialize volume dimensions // volumeDimensionXSpinBox->setValue(savedDimensions[0]); volumeDimensionYSpinBox->setValue(savedDimensions[1]); volumeDimensionZSpinBox->setValue(savedDimensions[2]); // // Initialize volume voxel dimensions // volumeVoxelSizeXDoubleSpinBox->setValue(savedVoxelSize[0]); volumeVoxelSizeYDoubleSpinBox->setValue(savedVoxelSize[1]); volumeVoxelSizeZDoubleSpinBox->setValue(savedVoxelSize[2]); // // Initialize volume origin // volumeOriginXDoubleSpinBox->setValue(savedOrigin[0]); volumeOriginYDoubleSpinBox->setValue(savedOrigin[1]); volumeOriginZDoubleSpinBox->setValue(savedOrigin[2]); // // Initialize surface offset // surfaceOffsetXDoubleSpinBox->setValue(savedOffset[0]); surfaceOffsetYDoubleSpinBox->setValue(savedOffset[1]); surfaceOffsetZDoubleSpinBox->setValue(savedOffset[2]); // // Initialize space // if (spaceIndex >= 0) { slotVolumeSpaceSelection(spaceIndex); volumeSpaceComboBox->setCurrentIndex(spaceIndex); } int nodeAttributeColumn = 0; QString nodeAttributeLabel; GUI_NODE_FILE_TYPE nodeFileType = GUI_NODE_FILE_TYPE_NONE; switch(mode) { case DIALOG_MODE_NORMAL: break; case DIALOG_MODE_PAINT: { // // set up for paint // DisplaySettingsPaint* dsp = theMainWindow->getBrainSet()->getDisplaySettingsPaint(); PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); nodeAttributeLabel = "Paint"; if (pf->getNumberOfColumns() > 0) { nodeAttributeColumn = dsp->getFirstSelectedColumnForBrainModel(surfaceModelIndex); } nodeFileType = GUI_NODE_FILE_TYPE_PAINT; } break; case DIALOG_MODE_METRIC: { // // set up for metric // MetricFile* mf = theMainWindow->getBrainSet()->getMetricFile(); nodeAttributeLabel = "Metric"; if (mf->getNumberOfColumns() > 0) { DisplaySettingsMetric* dsm = theMainWindow->getBrainSet()->getDisplaySettingsMetric(); nodeAttributeColumn = dsm->getFirstSelectedColumnForBrainModel(surfaceModelIndex); } nodeFileType = GUI_NODE_FILE_TYPE_METRIC; } break; case DIALOG_MODE_SURFACE_SHAPE: { // // set up for surface shape // SurfaceShapeFile* ssf = theMainWindow->getBrainSet()->getSurfaceShapeFile(); nodeAttributeLabel = "Surface Shape"; if (ssf->getNumberOfColumns() > 0) { DisplaySettingsSurfaceShape* dsss = theMainWindow->getBrainSet()->getDisplaySettingsSurfaceShape(); nodeAttributeColumn = dsss->getFirstSelectedColumnForBrainModel(surfaceModelIndex); } nodeFileType = GUI_NODE_FILE_TYPE_SURFACE_SHAPE; } break; case DIALOG_MODE_SEGMENT_VOLUME: break; } // // Create the column selection for node attribute (metric/paint/shape) conversions // metricAlgorithmComboBox = NULL; nodeAttributeColumnComboBox = NULL; if (nodeFileType != GUI_NODE_FILE_TYPE_NONE) { // // vertical box for node attribute column // QGroupBox* nodeAttributeGroupBox = new QGroupBox(nodeAttributeLabel); dialogLayout->addWidget(nodeAttributeGroupBox); QVBoxLayout* nodeAttributeLayout = new QVBoxLayout(nodeAttributeGroupBox); // // Node attribute column selection // nodeAttributeColumnComboBox = new GuiNodeAttributeColumnSelectionComboBox( nodeFileType, false, false, false); if (nodeAttributeColumnComboBox->count() > 0) { nodeAttributeColumnComboBox->setCurrentIndex(nodeAttributeColumn); } nodeAttributeLayout->addWidget(nodeAttributeColumnComboBox); if (mode == DIALOG_MODE_METRIC) { QLabel* metricLabel = new QLabel("Metric Algorithm "); metricAlgorithmComboBox = new QComboBox; metricAlgorithmComboBox->addItem("Interpolate"); metricAlgorithmComboBox->addItem("Largest Value"); metricAlgorithmComboBox->setToolTip( "Interpolate - The output voxel is the average\n" "of all surface pieces that intersect the voxel.\n" "\n" "Largest Value - The output voxel is the largest\n" "value of all surface pieces that intersect the voxel."); QHBoxLayout* metricLayout = new QHBoxLayout; metricLayout->addWidget(metricLabel); metricLayout->addWidget(metricAlgorithmComboBox); nodeAttributeLayout->addLayout(metricLayout); } } // // vertical box for misc selections // QGroupBox* miscGroupBox = new QGroupBox("Miscellaneous"); QVBoxLayout* miscGroupLayout = new QVBoxLayout(miscGroupBox); dialogLayout->addWidget(miscGroupBox); // // Create node to voxel mapping // nodeToVoxelCheckBox = new QCheckBox("Create Node to Voxel Mapping"); miscGroupLayout->addWidget(nodeToVoxelCheckBox); // // Node to voxel mapping file name // QLabel* nodeToVoxelLabel = new QLabel("File Name "); nodeToVoxelFileNameLineEdit = new QLineEdit; nodeToVoxelFileNameLineEdit->setText(savedNodeToVoxelFileName); QHBoxLayout* nodeToVoxelLayout = new QHBoxLayout; nodeToVoxelLayout->addWidget(nodeToVoxelLabel); nodeToVoxelLayout->addWidget(nodeToVoxelFileNameLineEdit); miscGroupLayout->addLayout(nodeToVoxelLayout); // // Enable node to voxel mapping filename when checkbox checked // QObject::connect(nodeToVoxelCheckBox, SIGNAL(toggled(bool)), nodeToVoxelFileNameLineEdit, SLOT(setEnabled(bool))); nodeToVoxelCheckBox->setChecked(savedNodeToVoxelMapping); nodeToVoxelFileNameLineEdit->setEnabled(savedNodeToVoxelMapping); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); dialogLayout->addLayout(buttonsLayout); // // Apply button // QPushButton* okButton = new QPushButton("OK"); okButton->setAutoDefault(false); buttonsLayout->addWidget(okButton); QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); // // Close button connects to QDialogs close() slot. // QPushButton* cancelButton = new QPushButton("Cancel"); cancelButton->setAutoDefault(false); buttonsLayout->addWidget(cancelButton); QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); QtUtilities::makeButtonsSameSize(okButton, cancelButton); firstTime = false; } /** * Destructor. */ GuiSurfaceToVolumeDialog::~GuiSurfaceToVolumeDialog() { } /** * called enter ac pushbutton is pressed. */ void GuiSurfaceToVolumeDialog::slotAcPushButton() { std::vector labels; labels.push_back("AC X Voxel Index "); labels.push_back("AC Y Voxel Index "); labels.push_back("AC Z Voxel Index "); std::vector values; values.push_back("0"); values.push_back("0"); values.push_back("0"); // // Popup a dialog to get the AC position // QtMultipleInputDialog mid(this, "Enter Anterior Commissure Voxel Indices", "", labels, values, true, true); if (mid.exec() == QDialog::Accepted) { std::vector acxyz(3); mid.getValues(acxyz); float voxelSize[3]; getVolumeVoxelSizes(voxelSize); float origin[3] = { -(acxyz[0] * voxelSize[0]), -(acxyz[1] * voxelSize[1]), -(acxyz[2] * voxelSize[2]) }; setVolumeOrigin(origin); } } /** * called when get parameters from volume file is pressed. */ void GuiSurfaceToVolumeDialog::slotParamtersFromVolumePushButton() { // // Create a spec file dialog to select the spec file. // WuQFileDialog openVolumeFileDialog(this); openVolumeFileDialog.setDirectory(QDir::currentPath()); openVolumeFileDialog.setModal(true); openVolumeFileDialog.setAcceptMode(WuQFileDialog::AcceptOpen); openVolumeFileDialog.setWindowTitle("Choose Volume File"); openVolumeFileDialog.setFileMode(WuQFileDialog::ExistingFile); openVolumeFileDialog.setFilter(FileFilters::getVolumeGenericFileFilter()); if (openVolumeFileDialog.exec() == QDialog::Accepted) { if (openVolumeFileDialog.selectedFiles().count() > 0) { const QString vname(openVolumeFileDialog.selectedFiles().at(0)); if (vname.isEmpty() == false) { VolumeFile vf; try { vf.readFile(vname, VolumeFile::VOLUME_READ_HEADER_ONLY); const VolumeFile::ORIENTATION lpiOrientation[3] = { VolumeFile::ORIENTATION_LEFT_TO_RIGHT, VolumeFile::ORIENTATION_POSTERIOR_TO_ANTERIOR, VolumeFile::ORIENTATION_INFERIOR_TO_SUPERIOR }; vf.permuteToOrientation(lpiOrientation); float origin[3]; float spacing[3]; int dim[3]; vf.getDimensions(dim); vf.getOrigin(origin); vf.getSpacing(spacing); setVolumeDimensions(dim); setVolumeVoxelSizes(spacing); setVolumeOrigin(origin); } catch (FileException& e) { QMessageBox::critical(this, "Error Reading Volume", e.whatQString()); } } } } } /** * Called when a volume space is selected. */ void GuiSurfaceToVolumeDialog::slotVolumeSpaceSelection(int item) { if (volumeSpaceComboBox->count() == 0) { return; } savedVolumeSpace = volumeSpaceComboBoxSpaces[item]; int dim[3] = { 0, 0, 0 }; float size[3] = { 0.0, 0.0, 0.0 }; float origin[3] = { 0.0, 0.0, 0.0 }; savedVolumeSpace.getDimensions(dim); savedVolumeSpace.getVoxelSize(size); savedVolumeSpace.getOrigin(origin); const bool standardSpaceFlag = (dim[0] > 0); if (standardSpaceFlag) { volumeDimensionXSpinBox->setValue(dim[0]); volumeDimensionYSpinBox->setValue(dim[1]); volumeDimensionZSpinBox->setValue(dim[2]); volumeVoxelSizeXDoubleSpinBox->setValue(size[0]); volumeVoxelSizeYDoubleSpinBox->setValue(size[1]); volumeVoxelSizeZDoubleSpinBox->setValue(size[2]); volumeOriginXDoubleSpinBox->setValue(origin[0]); volumeOriginYDoubleSpinBox->setValue(origin[1]); volumeOriginZDoubleSpinBox->setValue(origin[2]); } volumeDimensionXSpinBox->setEnabled(! standardSpaceFlag); volumeDimensionYSpinBox->setEnabled(! standardSpaceFlag); volumeDimensionZSpinBox->setEnabled(! standardSpaceFlag); volumeVoxelSizeXDoubleSpinBox->setEnabled(! standardSpaceFlag); volumeVoxelSizeYDoubleSpinBox->setEnabled(! standardSpaceFlag); volumeVoxelSizeZDoubleSpinBox->setEnabled(! standardSpaceFlag); volumeOriginXDoubleSpinBox->setEnabled(! standardSpaceFlag); volumeOriginYDoubleSpinBox->setEnabled(! standardSpaceFlag); volumeOriginZDoubleSpinBox->setEnabled(! standardSpaceFlag); } /** * get the selected surface */ BrainModelSurface* GuiSurfaceToVolumeDialog::getSelectedSurface() const { const int modelIndex = surfaceSelectionBox->getSelectedBrainModelIndex(); if (modelIndex < theMainWindow->getBrainSet()->getNumberOfBrainModels()) { return dynamic_cast(theMainWindow->getBrainSet()->getBrainModel(modelIndex)); } return NULL; } /** * get the selected paint column. */ int GuiSurfaceToVolumeDialog::getSelectedNodeAttributeColumn() const { if (nodeAttributeColumnComboBox != NULL) { return nodeAttributeColumnComboBox->currentIndex(); } return -1; } /** * get the offset */ void GuiSurfaceToVolumeDialog::getSurfaceOffset(float offset[3]) const { offset[0] = surfaceOffsetXDoubleSpinBox->text().toFloat(); offset[1] = surfaceOffsetYDoubleSpinBox->text().toFloat(); offset[2] = surfaceOffsetZDoubleSpinBox->text().toFloat(); } /** * get the desired surface inner boundary. */ float GuiSurfaceToVolumeDialog::getSurfaceInnerBoundary() const { if (surfaceThicknessStepDoubleSpinBox != NULL) { return surfaceInnerBoundaryDoubleSpinBox->text().toFloat(); } return 0; } /** * get the desired surface outer boundary. */ float GuiSurfaceToVolumeDialog::getSurfaceOuterBoundary() const { if (surfaceOuterBoundaryDoubleSpinBox != NULL) { return surfaceOuterBoundaryDoubleSpinBox->text().toFloat(); } return 0; } /** * get the desired surface thickness step. */ float GuiSurfaceToVolumeDialog::getSurfaceThicknessStep() const { if (surfaceThicknessStepDoubleSpinBox != NULL) { return surfaceThicknessStepDoubleSpinBox->text().toFloat(); } return 0; } /** * get the volume dimensions */ void GuiSurfaceToVolumeDialog::getVolumeDimensions(int dim[3]) const { dim[0] = volumeDimensionXSpinBox->value(); dim[1] = volumeDimensionYSpinBox->value(); dim[2] = volumeDimensionZSpinBox->value(); } /** * set the volume dimensions */ void GuiSurfaceToVolumeDialog::setVolumeDimensions(const int dim[3]) { volumeDimensionXSpinBox->setValue(dim[0]); volumeDimensionYSpinBox->setValue(dim[1]); volumeDimensionZSpinBox->setValue(dim[2]); } /** * Get the volume voxel sizes. */ void GuiSurfaceToVolumeDialog::getVolumeVoxelSizes(float voxelSize[3]) const { voxelSize[0] = volumeVoxelSizeXDoubleSpinBox->text().toFloat(); voxelSize[1] = volumeVoxelSizeYDoubleSpinBox->text().toFloat(); voxelSize[2] = volumeVoxelSizeZDoubleSpinBox->text().toFloat(); } /** * Set the volume voxel sizes. */ void GuiSurfaceToVolumeDialog::setVolumeVoxelSizes(const float voxelSize[3]) { volumeVoxelSizeXDoubleSpinBox->setValue(voxelSize[0]); volumeVoxelSizeYDoubleSpinBox->setValue(voxelSize[1]); volumeVoxelSizeZDoubleSpinBox->setValue(voxelSize[2]); } /** * Get the volume origin. */ void GuiSurfaceToVolumeDialog::getVolumeOrigin(float origin[3]) const { origin[0] = volumeOriginXDoubleSpinBox->text().toFloat(); origin[1] = volumeOriginYDoubleSpinBox->text().toFloat(); origin[2] = volumeOriginZDoubleSpinBox->text().toFloat(); } /** * Set the volume origin. */ void GuiSurfaceToVolumeDialog::setVolumeOrigin(const float origin[3]) { volumeOriginXDoubleSpinBox->setValue(origin[0]); volumeOriginYDoubleSpinBox->setValue(origin[1]); volumeOriginZDoubleSpinBox->setValue(origin[2]); } /** * get the standard volume space. */ StereotaxicSpace GuiSurfaceToVolumeDialog::getStandardVolumeSpace() const { StereotaxicSpace volumeSpace = StereotaxicSpace(StereotaxicSpace::SPACE_UNKNOWN); if (volumeSpaceComboBox->count() > 0) { volumeSpace = volumeSpaceComboBoxSpaces[volumeSpaceComboBox->currentIndex()]; } return volumeSpace; } /** * Get node to voxel mapping enabled. */ bool GuiSurfaceToVolumeDialog::getNodeToVoxelMappingEnabled() const { return nodeToVoxelCheckBox->isChecked(); } /** * Get node to voxel file name. */ QString GuiSurfaceToVolumeDialog::getNodeToVoxelMappingFileName() const { return nodeToVoxelFileNameLineEdit->text(); } /** * Called when OK or Cancel buttons pressed. */ void GuiSurfaceToVolumeDialog::done(int r) { if (r == QDialog::Accepted) { getSurfaceOffset(savedOffset); getVolumeDimensions(savedDimensions); getVolumeVoxelSizes(savedVoxelSize); getVolumeOrigin(savedOrigin); savedInnerBoundary = getSurfaceInnerBoundary(); savedOuterBoundary = getSurfaceOuterBoundary(); savedThicknessStep = getSurfaceThicknessStep(); savedSurface = getSelectedSurface(); savedVolumeSpace = volumeSpaceComboBoxSpaces[volumeSpaceComboBox->currentIndex()]; savedNodeToVoxelMapping = getNodeToVoxelMappingEnabled(); savedNodeToVoxelFileName = getNodeToVoxelMappingFileName(); } QDialog::done(r); } /** * get the metric conversion mode. */ BrainModelSurfaceToVolumeConverter::CONVERSION_MODE GuiSurfaceToVolumeDialog::getMetricConversionMode() const { BrainModelSurfaceToVolumeConverter::CONVERSION_MODE conversionMode = BrainModelSurfaceToVolumeConverter::CONVERT_TO_ROI_VOLUME_USING_METRIC_INTERPOLATE; if (metricAlgorithmComboBox != NULL) { if (metricAlgorithmComboBox->currentIndex() != 0) { conversionMode = BrainModelSurfaceToVolumeConverter::CONVERT_TO_ROI_VOLUME_USING_METRIC_NO_INTERPOLATE; } } return conversionMode; } caret-5.6.4~dfsg.1.orig/caret/GuiSurfaceSpmTransformDialog.h0000664000175000017500000000732611572067322023571 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_SURFACE_SPM_TRANSFORM_DIALOG_H__ #define __GUI_SURFACE_SPM_TRANSFORM_DIALOG_H__ #include #include "WuQDialog.h" class GuiBrainModelSelectionComboBox; class QCheckBox; class QLabel; /// Dialog for transforming a surface using SPM inverse transforms class GuiSurfaceSpmTransformDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiSurfaceSpmTransformDialog(QWidget* parent); /// Destructor ~GuiSurfaceSpmTransformDialog(); private slots: /// called when apply button pressed void done(int r); /// called when normalized volume select push button pressed void slotNormalizedVolumeButton(); /// called when inverse X volume select push button pressed void slotInverseXVolumeButton(); /// called when inverse Y volume select push button pressed void slotInverseYVolumeButton(); /// called when inverse Z volume select push button pressed void slotInverseZVolumeButton(); private: enum FILE_SELECTION_TYPE { FILE_SELECTION_VOLUME_NORMALIZED, FILE_SELECTION_VOLUME_INVERSE_X, FILE_SELECTION_VOLUME_INVERSE_Y, FILE_SELECTION_VOLUME_INVERSE_Z }; /// called to select a volume file void selectVolumeFile(const FILE_SELECTION_TYPE fst); /// display the selected files void displayFileNames(); /// combo box for selecting coord file GuiBrainModelSelectionComboBox* coordFileComboBox; /// label normalized volume QLabel* normalizedVolumeLabel; /// label for inverse X volume QLabel* inverseXVolumeLabel; /// label for inverse Y volume QLabel* inverseYVolumeLabel; /// label for inverse Z volume QLabel* inverseZVolumeLabel; /// interpolate voxels checkbox QCheckBox* interpolateVoxelsCheckBox; /// name of volume file static QString normalizedVolumeFileName; /// name of inverse X volume file static QString inverseXVolumeFileName; /// name of inverse Y volume file static QString inverseYVolumeFileName; /// name of inverse Z volume file static QString inverseZVolumeFileName; /// interpolate among voxels static bool interpolateVoxelsFlag; }; #ifdef __GUI_SURFACE_SPM_TRANSFORM_DIALOG_MAIN_H__ QString GuiSurfaceSpmTransformDialog::normalizedVolumeFileName; QString GuiSurfaceSpmTransformDialog::inverseXVolumeFileName; QString GuiSurfaceSpmTransformDialog::inverseYVolumeFileName; QString GuiSurfaceSpmTransformDialog::inverseZVolumeFileName; bool GuiSurfaceSpmTransformDialog::interpolateVoxelsFlag = true; #endif // __GUI_SURFACE_SPM_TRANSFORM_DIALOG_MAIN_H__ #endif // __GUI_SURFACE_SPM_TRANSFORM_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiSurfaceSpmTransformDialog.cxx0000664000175000017500000004404411572067322024142 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include "WuQFileDialog.h" #include #include #include #include #include #include "BrainModelSurface.h" #include "BrainSet.h" #include "FileUtilities.h" #include "GuiBrainModelOpenGL.h" #include "GuiBrainModelSelectionComboBox.h" #include "GuiMainWindow.h" #define __GUI_SURFACE_SPM_TRANSFORM_DIALOG_MAIN_H__ #include "GuiSurfaceSpmTransformDialog.h" #undef __GUI_SURFACE_SPM_TRANSFORM_DIALOG_MAIN_H__ #include "MathUtilities.h" #include "QtUtilities.h" #include "VolumeFile.h" #include "global_variables.h" /* * Getting inverse files from SPM: Using SPM99 Input volume: colin_7112B_111.hdr/img Normalized volume produced by SPM ncolin_7112B_111.hdr/img Goal: Determine how to map coordinates in "input volume space" into coordinates in "normalized volume space". After normalization: Used toolbox: deformations: deformations from sn3d.mat Specified the colin_7112B_111_sn3d.mat file bounding box = Default voxel sizes = 1, 1, 1 Toolbar deformations: Invert Deformations Number of subjects = 1 Deformation field 1: selecte y1_colin_7112B_111.img y2_colin_7112B_111.img, y3_colin_7112B_111.img. Image to Base Inverse on: colin_7112B_111.img output is iy1_colin_7112B_111.hdr, iy2_colin_7112B_111.hdr, and iy3_colin_7112B_111.hdr Use Display: Selected iy1_colin_7112B_111.img. Changed World Space to Voxel Space Entered 122 153 86 resulting intensity = 35.318 Use Display: Selected iy2_colin_7112B_111.img. Changed World Space to Voxel Space Entered 122 153 86 resulting intensity = 36.140 Use Display: Selected iy3_colin_7112B_111.img. Changed World Space to Voxel Space Entered 122 153 86 resulting intensity = 8.14 I assume (35.318, 36.140, 8.14) are relative to the SPM origin (79 113 51) obtained by running "mayo_analyze ncolin_7112B_111.hdr". Adding the spm origin to the gives (114.318 149.1 59.14). */ /** * Constructor */ GuiSurfaceSpmTransformDialog::GuiSurfaceSpmTransformDialog(QWidget* parent) : WuQDialog(parent) { setModal(true); setWindowTitle("Apply SPM Inverse Transform"); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // Layout for all dialog items // QGridLayout* gridLayout = new QGridLayout; gridLayout->setSpacing(3); dialogLayout->addLayout(gridLayout); int rowNumber = 0; // // Coordinate file // gridLayout->addWidget(new QLabel("Coordinate File"), rowNumber, 0, Qt::AlignLeft); coordFileComboBox = new GuiBrainModelSelectionComboBox(false, true, false, "", 0); coordFileComboBox->setSelectedBrainModel(theMainWindow->getBrainSet()->getActiveFiducialSurface()); gridLayout->addWidget(coordFileComboBox, rowNumber, 1, Qt::AlignLeft); rowNumber++; const QString blanks(" "); // // Normalized volume label and selection button // QPushButton* normalizedVolumePushButton = new QPushButton("Normalized Volume..."); gridLayout->addWidget(normalizedVolumePushButton, rowNumber, 0); normalizedVolumePushButton->setAutoDefault(false); QObject::connect(normalizedVolumePushButton, SIGNAL(clicked()), this, SLOT(slotNormalizedVolumeButton())); normalizedVolumeLabel = new QLabel(blanks); gridLayout->addWidget(normalizedVolumeLabel, rowNumber, 1, Qt::AlignLeft); rowNumber++; // // inverse X volume label and selection button // QPushButton* inverseXVolumePushButton = new QPushButton("Inverse X Volume..."); gridLayout->addWidget(inverseXVolumePushButton, rowNumber, 0); inverseXVolumePushButton->setAutoDefault(false); QObject::connect(inverseXVolumePushButton, SIGNAL(clicked()), this, SLOT(slotInverseXVolumeButton())); inverseXVolumeLabel = new QLabel(blanks); gridLayout->addWidget(inverseXVolumeLabel, rowNumber, 1, Qt::AlignLeft); rowNumber++; // // inverse Y volume label and selection button // QPushButton* inverseYVolumePushButton = new QPushButton("Inverse Y Volume..."); gridLayout->addWidget(inverseYVolumePushButton, rowNumber, 0); inverseYVolumePushButton->setAutoDefault(false); QObject::connect(inverseYVolumePushButton, SIGNAL(clicked()), this, SLOT(slotInverseYVolumeButton())); inverseYVolumeLabel = new QLabel(blanks); gridLayout->addWidget(inverseYVolumeLabel, rowNumber, 1, Qt::AlignLeft); rowNumber++; // // inverse Z volume label and selection button // QPushButton* inverseZVolumePushButton = new QPushButton("Inverse Z Volume..."); gridLayout->addWidget(inverseZVolumePushButton, rowNumber, 0); inverseZVolumePushButton->setAutoDefault(false); QObject::connect(inverseZVolumePushButton, SIGNAL(clicked()), this, SLOT(slotInverseZVolumeButton())); inverseZVolumeLabel = new QLabel(blanks); gridLayout->addWidget(inverseZVolumeLabel, rowNumber, 1, Qt::AlignLeft); rowNumber++; // // Interpolate voxels check box // interpolateVoxelsCheckBox = new QCheckBox("Interpolate Voxels"); interpolateVoxelsCheckBox->setChecked(interpolateVoxelsFlag); dialogLayout->addWidget(interpolateVoxelsCheckBox); // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); dialogLayout->addLayout(buttonsLayout); // // ok button connects to QDialogs accept() slot. // QPushButton* okButton = new QPushButton("OK"); buttonsLayout->addWidget(okButton); QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); // // Cancel button connects to QDialogs close() slot. // QPushButton* cancelButton = new QPushButton("Cancel"); buttonsLayout->addWidget(cancelButton); QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); QtUtilities::makeButtonsSameSize(okButton, cancelButton); displayFileNames(); } /** * Destructor */ GuiSurfaceSpmTransformDialog::~GuiSurfaceSpmTransformDialog() { } /** * Called when OK button pressed. */ void GuiSurfaceSpmTransformDialog::done(int r) { if (r == QDialog::Accepted) { QString msg; BrainModelSurface* bms = coordFileComboBox->getSelectedBrainModelSurface(); if (bms == NULL) { msg.append("You must select a surface.\n"); } if (normalizedVolumeFileName.isEmpty()) { msg.append("You must select a normalized volume.\n"); } if (inverseXVolumeFileName.isEmpty()) { msg.append("You must select an inverse X volume.\n"); } if (inverseYVolumeFileName.isEmpty()) { msg.append("You must select an inverse Y volume.\n"); } if (inverseZVolumeFileName.isEmpty()) { msg.append("You must select an inverse Z volume.\n"); } if (msg.isEmpty() == false) { QMessageBox::critical(this, "Error", msg); return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); interpolateVoxelsFlag = interpolateVoxelsCheckBox->isChecked(); try { // // Read the header of the normalized volume file // VolumeFile normalizedVolumeFile; normalizedVolumeFile.readFile(normalizedVolumeFileName, VolumeFile::VOLUME_READ_HEADER_ONLY); float ac[3]; normalizedVolumeFile.getSpmAcPosition(ac); // // Read the volume containing the inverse X deformations // VolumeFile inverseXVolumeFile; inverseXVolumeFile.readFile(inverseXVolumeFileName, 0); // // Read the volume containing the inverse Y deformations // VolumeFile inverseYVolumeFile; inverseYVolumeFile.readFile(inverseYVolumeFileName, 0); // // Read the volume containing the inverse Z deformations // VolumeFile inverseZVolumeFile; inverseZVolumeFile.readFile(inverseZVolumeFileName, 0); // // Dimensions of one of the inverse volumes (should all be the same dimensions) // int dims[3]; inverseZVolumeFile.getDimensions(dims); // // 1/2 size of voxels // float halfVoxelSize[3]; inverseZVolumeFile.getSpacing(halfVoxelSize); halfVoxelSize[0] *= 0.5; halfVoxelSize[1] *= 0.5; halfVoxelSize[2] *= 0.5; // // Transform the coordinates // CoordinateFile* cf = bms->getCoordinateFile(); const int numCoords = cf->getNumberOfCoordinates(); for (int i = 0; i < numCoords; i++) { float xyz[3]; cf->getCoordinate(i, xyz); // // Get the voxel coordinates // int ijk[3]; float pcoords[3]; const int insideVolume = inverseXVolumeFile.convertCoordinatesToVoxelIJK(xyz, ijk, pcoords); if (insideVolume) { bool edgeVoxel = false; if ((ijk[0] == 0) || (ijk[0] == (dims[0] - 1)) || (ijk[1] == 0) || (ijk[1] == (dims[1] - 1)) || (ijk[2] == 0) || (ijk[2] == (dims[2] - 1))) { edgeVoxel = true; } if (interpolateVoxelsFlag && (edgeVoxel == false)) { // // Offset position by half of the voxel size // const float vxyz[3] = { xyz[0] - halfVoxelSize[0], xyz[1] - halfVoxelSize[1], xyz[2] - halfVoxelSize[2] }; inverseXVolumeFile.convertCoordinatesToVoxelIJK((float*)vxyz, ijk, pcoords); const float r = pcoords[0]; const float s = pcoords[1]; const float t = pcoords[2]; xyz[0] = 0.0; xyz[1] = 0.0; xyz[2] = 0.0; // // Weighting from book Visualization Toolkit, 2nd Ed, page 316 // for (int j = 0; j < 8; j++) { int dijk[3] = { 0, 0, 0 }; float weight = 0.0; switch(j) { case 0: weight = (1.0 - r) * (1.0 - s) * (1.0 - t); break; case 1: weight = r * (1.0 - s) * (1.0 - t); dijk[0] = 1; break; case 2: weight = (1.0 - r) * s * (1.0 - t); dijk[1] = 1; break; case 3: weight = r * s * (1.0 - t); dijk[0] = 1; dijk[1] = 1; break; case 4: weight = (1.0 - r) * (1.0 - s) * t; dijk[2] = 1; break; case 5: weight = r * (1.0 - s) * t; dijk[0] = 1; dijk[2] = 1; break; case 6: weight = (1.0 - r) * s * t; dijk[1] = 1; dijk[2] = 1; break; case 7: weight = r * s * t; dijk[0] = 1; dijk[1] = 1; dijk[2] = 1; break; } // // adjust the voxel indices // int vijk[3] = { ijk[0] + dijk[0], ijk[1] + dijk[1], ijk[2] + dijk[2] }; xyz[0] += (inverseXVolumeFile.getVoxel(vijk, 0) + ac[0]) * weight; xyz[1] += (inverseYVolumeFile.getVoxel(vijk, 0) + ac[1]) * weight; xyz[2] += (inverseZVolumeFile.getVoxel(vijk, 0) + ac[2]) * weight; // // For some voxels, the SPM Inverse has NaN (Not a Number) // if (MathUtilities::isNaN(xyz[0]) || MathUtilities::isNaN(xyz[1]) || MathUtilities::isNaN(xyz[2])) { xyz[0] = 0.0; xyz[1] = 0.0; xyz[2] = 0.0; break; } } // for (i = 0; i < 8) } else { xyz[0] = inverseXVolumeFile.getVoxel(ijk, 0) + ac[0]; xyz[1] = inverseYVolumeFile.getVoxel(ijk, 0) + ac[1]; xyz[2] = inverseZVolumeFile.getVoxel(ijk, 0) + ac[2]; // // For some voxels, the SPM Inverse has NaN (Not a Number) // if (MathUtilities::isNaN(xyz[0]) || MathUtilities::isNaN(xyz[1]) || MathUtilities::isNaN(xyz[2])) { xyz[0] = 0.0; xyz[1] = 0.0; xyz[2] = 0.0; } } cf->setCoordinate(i, xyz); } else { std::cout << "Info: " << xyz[0] << " " << xyz[1] << " " << xyz[2] << " is outside volume." << std::endl; } } } catch(FileException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "Error", e.whatQString()); return; } GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); } QDialog::done(r); } /** * called when normalized volume select push button pressed */ void GuiSurfaceSpmTransformDialog::slotNormalizedVolumeButton() { selectVolumeFile(FILE_SELECTION_VOLUME_NORMALIZED); } /** * called when inverse X volume select push button pressed */ void GuiSurfaceSpmTransformDialog::slotInverseXVolumeButton() { selectVolumeFile(FILE_SELECTION_VOLUME_INVERSE_X); } /** * called when inverse Y volume select push button pressed */ void GuiSurfaceSpmTransformDialog::slotInverseYVolumeButton() { selectVolumeFile(FILE_SELECTION_VOLUME_INVERSE_Y); } /** * called when inverse Z volume select push button pressed */ void GuiSurfaceSpmTransformDialog::slotInverseZVolumeButton() { selectVolumeFile(FILE_SELECTION_VOLUME_INVERSE_Z); } /** * Called to select a file */ void GuiSurfaceSpmTransformDialog::selectVolumeFile(const FILE_SELECTION_TYPE fst) { QString caption; switch (fst) { case FILE_SELECTION_VOLUME_NORMALIZED: caption = "Normalized Volume File"; break; case FILE_SELECTION_VOLUME_INVERSE_X: caption = "Inverse X Deformation Volume File"; break; case FILE_SELECTION_VOLUME_INVERSE_Y: caption = "Inverse Y Deformation Volume File"; break; case FILE_SELECTION_VOLUME_INVERSE_Z: caption = "Inverse Z Deformation Volume File"; break; } WuQFileDialog fd(this); fd.setModal(true); fd.setAcceptMode(WuQFileDialog::AcceptOpen); fd.setDirectory(QDir::currentPath()); fd.setFilter("SPM Volume Files (*.hdr)"); fd.setWindowTitle(caption); if (fd.exec() == QDialog::Accepted) { if (fd.selectedFiles().count() > 0) { const QString fn = fd.selectedFiles().at(0); switch (fst) { case FILE_SELECTION_VOLUME_NORMALIZED: normalizedVolumeFileName = fn; break; case FILE_SELECTION_VOLUME_INVERSE_X: inverseXVolumeFileName = fn; break; case FILE_SELECTION_VOLUME_INVERSE_Y: inverseYVolumeFileName = fn; break; case FILE_SELECTION_VOLUME_INVERSE_Z: inverseZVolumeFileName = fn; break; } } } displayFileNames(); } /** * Called to select a file */ void GuiSurfaceSpmTransformDialog::displayFileNames() { normalizedVolumeLabel->setText(FileUtilities::basename(normalizedVolumeFileName)); inverseXVolumeLabel->setText(FileUtilities::basename(inverseXVolumeFileName)); inverseYVolumeLabel->setText(FileUtilities::basename(inverseYVolumeFileName)); inverseZVolumeLabel->setText(FileUtilities::basename(inverseZVolumeFileName)); } caret-5.6.4~dfsg.1.orig/caret/GuiSurfaceRegionOfInterestDialogOLD.h0000664000175000017500000005723411572067322024726 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_SURFACE_REGION_OF_INTEREST_DIALOG_OLD_H__ #define __GUI_SURFACE_REGION_OF_INTEREST_DIALOG_OLD_H__ #include #include #include "WuQDialog.h" #include "BrainModelSurfaceROINodeSelection.h" class BrainModelSurface; class GuiBrainModelSelectionComboBox; class GuiNodeAttributeColumnSelectionComboBox; class GuiPaintColumnNamesComboBox; //class GuiTopologyFileComboBox; class GiftiNodeDataFile; class NodeAttributeFile; class QCheckBox; class QComboBox; class QLabel; class QLineEdit; class QRadioButton; class QSpinBox; class QStackedWidget; class QTextEdit; class QDoubleSpinBox; class QTabWidget; class QVBoxLayout; class TopologyFile; /// Dialog for performing surface region of interest queries class GuiSurfaceRegionOfInterestDialogOLD : public WuQDialog { Q_OBJECT public: /// Constructor GuiSurfaceRegionOfInterestDialogOLD(QWidget* parent); /// Destructor ~GuiSurfaceRegionOfInterestDialogOLD(); /// get the query paint column int getQueryPaintColumn() const; /// update the dialog (typically due to file changes) void updateDialog(); /// set border name for query void setBorderNameForQuery(const QString& borderName); /// set paint index for query void setPaintIndexForQuery(const int paintIndex); /// set metric node for query void setMetricNodeForQuery(const int metricNodeForQueryIn); /// set shape node for query void setShapeNodeForQuery(const int shapeNodeForQueryIn); /// set node for geodesic query void setNodeForGeodesicQuery(const int nodeNumber); /// set open border start node void setCreateBorderOpenStartNode(const int nodeNumber); /// set open border end node void setCreateBorderOpenEndNode(const int nodeNumber); public slots: // show the dialog void show(); private slots: /// called when dialog closed void close(); /// called when help button is pressed void slotHelpButton(); /// Called to assign paint to nodes void slotAssignPaintToNodes(); /// called when an assign paint column name column selected void slotAssignPaintColumn(int item); /// called when create volume from displayed query nodes push button pressed void slotCreateVolumeFromQueryNodesButton(); /// called when select nodes button pressed void slotSelectNodesButton(); /// call when invert nodes button pressed void slotInvertNodeSelectionPushButton(); /// called when deselect nodes button pressed void slotDeselectNodesButton(); /// called when create report button pressed void slotCreateReportButton(); /// called when create paint subregion report button pressed void slotCreatePaintReportButton(); /// called when disconnect nodes button is pressed void slotDisconnectNodes(); /// called when border name from list push button pressed void slotBorderNameFromListPushButton(); /// called when border name from mouse push button pressed void slotBorderNameFromMousePushButton(); /// called when paint name from list push button pressed void slotPaintNameFromListPushButton(); /// called when paint name from mouse push button pressed void slotPaintNameFromMousePushButton(); /// called when report save push button pressed void slotSavePushButton(); /// called when report clear push button pressed void slotClearPushButton(); /// Called to change the mouse mode to select the node for the geodesic query. void slotGeodesicNodePushButton(); /// called when geodesic push button pressed void slotGeodesicPushButton(); /// called to default geodesic column names void slotUpdateGeodesicColumnNames(); /// called when a metric mode is selected void slotMetricModeSelection(int metricMode); /// called when an operation mode is selected void slotOperationMode(int item); /// called when one of the query mode radio buttons is selected void slotSelectionMode(int); /// called when show selected nodes toggle is changed void slotShowSelectedNodes(bool on); /// update the operation topology label void slotSurfaceSelection(); /// called when topology is changed //void slotTopologySelection(); /// called to display smoothing dialog void slotSmoothNodes(); /// Called to create shape correlation report. void slotCorrelationShapeReport(); /// Called when metric all on pushbutton is pressed void slotMetricAllOnPushButton(); /// Called when metric all off pushbutton is pressed void slotMetricAllOffPushButton(); /// Called when paint all on pushbutton is pressed void slotPaintAllOnPushButton(); /// Called when paint all off pushbutton is pressed void slotPaintAllOffPushButton(); /// Called when shape all on pushbutton is pressed void slotShapeAllOnPushButton(); /// Called when shape all off pushbutton is pressed void slotShapeAllOffPushButton(); /// Called when a shape mode is selected. void slotShapeModeSelection(int shapeMode); /// Called to assign metrics for a node void slotAssignMetricToNodes(); /// Called to assign surface shape for a node void slotAssignSurfaceShapeToNodes(); /// Called to create the prob atlas report void slotCreateProbAtlasReport(); /// Called to create shape cluster report void slotShapeClusterReport(); /// Called to set create borders from clusters name void slotBorderClusterNamePushButton(); /// Called run create borders from clusters void slotCreateBordersFromClusters(); /// called to run compute integrated folding index void slotComputeIntegratedFoldingIndex(); /// called to create a border from the ROI void slotCreateBorderFromROIPushButton(); /// called to set name of border for border from ROI void slotCreateBorderFromROINamePushButton(); /// called to select start node for border from ROI void slotCreateBorderFromROIStartNodePushButton(); /// called to select start node for border from ROI void slotCreateBorderFromROIEndNodePushButton(); /// called when load ROI button is pressed void slotLoadROIPushButton(); /// called when save ROI button is pressed void slotSaveROIPushButton(); /// called when dilate button is pressed void slotDilatePushButton(); /// called when erode button is pressed void slotErodePushButton(); private: /// operation mode enum OPERATION_MODE { OPERATION_MODE_ASSIGN_METRIC, OPERATION_MODE_ASSIGN_PAINT, OPERATION_MODE_ASSIGN_SURFACE_SHAPE, OPERATION_MODE_COMPUTE_INTEGRATED_FOLDING_INDEX, OPERATION_MODE_CREATE_BORDERS_FROM_CLUSTERS, OPERATION_MODE_CREATE_BORDERS_FROM_ROI, OPERATION_MODE_CREATE_VOLUME_ROI, OPERATION_MODE_DISCONNECT_NODES, OPERATION_MODE_GEODESIC, OPERATION_MODE_PROB_ATLAS_OVERLAP, OPERATION_MODE_SMOOTH_NODES, OPERATION_MODE_STATISTICAL_REPORT, OPERATION_MODE_STATISTICAL_PAINT_REPORT, OPERATION_MODE_SHAPE_CORRELATION, OPERATION_MODE_SHAPE_CLUSTER_ANALYSIS }; /// selction mode (type of attribute used to select) enum SELECTION_MODE { SELECTION_MODE_ENTIRE_SURFACE, SELECTION_MODE_NODES_WITH_PAINT, SELECTION_MODE_NODES_WITHIN_BORDER, SELECTION_MODE_NODES_WITHIN_LATLON, SELECTION_MODE_NODES_WITH_METRIC, SELECTION_MODE_NODES_WITH_SHAPE, SELECTION_MODE_NODES_WITH_CROSSOVERS, SELECTION_MODE_NONE }; /// get the query mode SELECTION_MODE selectionMode; /// get the selection logic BrainModelSurfaceROINodeSelection::SELECTION_LOGIC getSelectionLogic() const; /// create the node selection section QWidget* createNodeSelectionSection(); /// create the node selection with paint section void createNodeSelectionPaint(); /// create the node selection with border section void createNodeSelectionBorder(); /// create the node selection with latlon void createNodeSelectionLatLon(); /// create the node selection with metric void createNodeSelectionMetric(); /// create the node selection with shape void createNodeSelectionShape(); /// create the assign metric operation section void createOperationAssignMetric(); /// create the assign paint operation section void createOperationAssignPaint(); /// create the prob atlas analysis operation section void createOperationProbAtlas(); /// create the assign surface shape operation section void createOperationAssignSurfaceShape(); /// create the borders around clusters section void createOperationsBordersAroundClusters(); /// create the border from ROI void createOperationsBordersFromROI(); /// create the create volume ROI operation section void createOperationCreateVolumeROI(); /// create the disconnect nodes operation section void createOperationDisconnectNodes(); /// create the geodesic operation section void createOperationGeodesicDistance(); /// create the integrated folding index operation void createOperationIntegratedFoldingIndex(); /// create the statistical report operation section void createOperationStatisticalReport(); /// create the statistical report on paint subregion operation section void createOperationStatisticalPaintReport(); /// create the smoothnodes operation section void createOperationSmoothNodes(); /// create the surface shape correlation coefficient section void createShapeCorrelationCoefficientReport(); /// create the surface shape cluster section void createShapeClusterReport(); /// create the query page void createQuerySelectionPage(); /// create the attribute page void createAttributeSelectionPage(); /// Create the report header (returns true if no nodes in query) bool createReportHeader(const QString& headerText, const bool tabSeparateReportIn, float& roiAreaOut); /// create the report page void createReportPage(); /// create the report void createReport(const QString& headerText, const bool tabSeparateFlag, const bool doConclusion); /// reset the marked nodes and update/clear the report header void resetMarkedNodesAndReportHeader(const bool deselectNodesInROI); /// update a node attribute file's categories void updateNodeAttributeGroupBox( QVBoxLayout* layout, std::vector& checkBoxes, NodeAttributeFile* naf); /// update a node attribute file's categories void updateNodeAttributeGroupBox( QVBoxLayout* layout, std::vector& checkBoxes, GiftiNodeDataFile* naf); // /// perform ROI //void metricAndSurfaceShapeROI(const bool metricFlag); // /// perform ROI //void paintROI(const BrainModelSurface* bms, const double roiArea); /// select all nodes void selectNodesAll(); /// select nodes by border void selectNodesBorder(); /// select nodes by lat/lon void selectNodesLatLon(); /// select nodes by metric void selectNodesMetric(); /// select nodes by shape void selectNodesShape(); /// select nodes by paint void selectNodesPaint(); /// select nodes by crossovers void selectNodesCrossovers(); /// update the number of selected nodes labels void updateNumberOfSelectedNodesLabel(); /// query page for how ROI selected QWidget* queryPage; /// attributes page for controlling query output QWidget* attributesPage; /// report page QWidget* reportPage; /// selection mode combo box QComboBox* selectionModeComboBox; /// nodes with crossovers widget QWidget* nodesWithCrossoversWidget; /// entire surface empty widget QWidget* queryEntireSurfaceWidget; /// widget containing nodes within lat/lon items QWidget* nodesWithinLatLonQVBox; /// widget containing nodes with metric items QWidget* nodesWithMetricQVBox; /// widget containing nodes with paint items QWidget* nodesWithPaintQVBox; /// query control widget stack QStackedWidget* queryControlWidgetStack; /// layout for metric QVBoxLayout* metricOutputLayout; /// line edit for lower metric threshold QDoubleSpinBox* metricLowerThresholdDoubleSpinBox; /// line edit for upper metric threshold QDoubleSpinBox* metricUpperThresholdDoubleSpinBox; /// metric all nodes radio button QRadioButton* metricAllNodesRadioButton; /// metric choose nodes with mouse radio button QRadioButton* metricChooseNodesRadioButton; /// metric node selection column combo box GuiNodeAttributeColumnSelectionComboBox* metricCategoryComboBox; /// metric node number label QLabel* metricNodeNumberLabel; /// check buttons for metric attribute selections std::vector metricCheckBoxes; /// layout for paint output QVBoxLayout* paintOutputLayout; /// check buttons for paint selections std::vector paintCheckBoxes; /// layout for surface shape QVBoxLayout* shapeOutputLayout; /// check buttons for surface shape selections std::vector surfaceShapeCheckBoxes; /// shape node selection column combo box GuiNodeAttributeColumnSelectionComboBox* shapeCategoryComboBox; /// report text editor QTextEdit* reportTextEdit; /// nodes with paint category combo box GuiNodeAttributeColumnSelectionComboBox* paintWithNameCategoryComboBox; /// nodes with paint selected name label QLabel* paintWithNameSelectedLabel; /// selected paint index int paintWithNameIndex; /// borders widget QWidget* nodesWithinBorderQVBox; /// selected border name label QLabel* borderNameSelectedLabel; /// name of the selected border QString selectedBorderName; /// lat min double spin box QDoubleSpinBox* latLowerRangeDoubleSpinBox; /// lat max double spin box QDoubleSpinBox* latUpperRangeDoubleSpinBox; /// lon min double spin box QDoubleSpinBox* lonLowerRangeDoubleSpinBox; /// lon min double spin box QDoubleSpinBox* lonUpperRangeDoubleSpinBox; /// if true, indicates tile is in ROI std::vector tileInROI; /// tile area std::vector tileArea; /// combo box for operation surface GuiBrainModelSelectionComboBox* operationSurfaceComboBox; /// combo box topology file //GuiTopologyFileComboBox* topologyComboBox; /// tab separate check box QCheckBox* tabSeparateReportCheckBox; /// tab separate the report bool tabSeparateReport; /// combo box for selecting border surface GuiBrainModelSelectionComboBox* borderSurfaceComboBox; /// metric node for query int metricNodeForQuery; /// shape node for query int shapeNodeForQuery; /// number of nodes selected label QLabel* numberOfNodesSelectedLabel; /// show selected nodes check box QCheckBox* showSelectedNodesCheckBox; /// select logic combo box QComboBox* selectionLogicComboBox; /// operation combo box QComboBox* operationComboBox; /// operations widget stack QStackedWidget* operationsWidgetStack; /// assign metric operation widget QWidget* operationAssignMetricWidget; /// assign paint operation widget QWidget* operationAssignPaintWidget; /// assign surface shape operation widget QWidget* operationAssignSurfaceShapeWidget; /// create borders around clusters widget QWidget* operationCreateBordersFromClustersWidget; /// create border from ROI widget QWidget* operationCreateBordersFromROIWidget; /// volume ROI operation widget QWidget* operationCreateVolumeRoiWidget; /// disconnect nodes operation widget QWidget* operationDisconnectNodesWidget; /// statistical paint subregion report operation widget QWidget* operationStatisticalPaintReportWidget; /// tabe separate paint report widget QCheckBox* tabSeparatePaintReportCheckBox; /// statistical report operation widget QWidget* operationStatisticalReportWidget; /// smooth nodes operation widget QWidget* operationSmoothNodesWidget; /// shape cluster analysis QWidget* operationShapeClusterWidget; /// geodesic operations widget QWidget* operationGeodesicWidget; /// integrated folding index operations widget QWidget* operationComputeIntegratedFoldingIndexWidget; /// shape correlation coefficient widget QWidget* operationShapeCorrelationWidget; /// report header that describes node selection QString reportHeader; /// assign paint name combo box GuiNodeAttributeColumnSelectionComboBox* paintColumnAssignComboBox; /// assign paint name column name QLineEdit* paintColumnAssignNameLineEdit; /// assign paint name QLineEdit* paintAssignNameLineEdit; /// geodesic node number spin box QSpinBox* geodesicNodeSpinBox; /// shape correlation column combo box GuiNodeAttributeColumnSelectionComboBox* shapeCorrelationColumnComboBox; /// shape correlation tab separate check box QCheckBox* shapeCorrelationTabSeparateCheckBox; /// group box for shape selection items QWidget* nodesWithShapeQVBox; /// shape lower threshold line edit QDoubleSpinBox* shapeLowerThresholdDoubleSpinBox; /// shape upper threshold line edit QDoubleSpinBox* shapeUpperThresholdDoubleSpinBox; /// shape radio button QRadioButton* shapeAllNodesRadioButton; /// shape radio button QRadioButton* shapeChooseNodesRadioButton; /// shape node number label QLabel* shapeNodeNumberLabel; /// metric column assign combo box GuiNodeAttributeColumnSelectionComboBox* metricColumnAssignComboBox; /// metric column name line edit QLineEdit* metricColumnAssignNameLineEdit; /// metric column assign line QDoubleSpinBox* metricValueDoubleSpinBox; /// surface shape column assign combo box GuiNodeAttributeColumnSelectionComboBox* surfaceShapeColumnAssignComboBox; /// surface shape column name line edit QLineEdit* surfaceShapeColumnAssignNameLineEdit; /// surface shape column assign line QDoubleSpinBox* surfaceShapeValueDoubleSpinBox; /// geodesic metric file column combo box GuiNodeAttributeColumnSelectionComboBox* geodesicMetricColumnComboBox; /// geodesic metric column name line edit QLineEdit* geodesicMetricColumnNameLineEdit; /// geodesic distance file column combo box GuiNodeAttributeColumnSelectionComboBox* geodesicDistanceColumnComboBox; /// geodesic distance column name line edit QLineEdit* geodesicDistanceColumnNameLineEdit; /// paint region combo box GuiNodeAttributeColumnSelectionComboBox* paintRegionReportColumnComboBox; /// prob atlas operation widget QWidget* operationProbAtlasWidget; /// prob atlas separate with tab option QCheckBox* probAtlasTabSeparateCheckBox; /// the separator character QString separatorCharacter; /// shape cluster areal distortion selection column combo box GuiNodeAttributeColumnSelectionComboBox* shapeClusterMetricArealDistortionComboBox; /// shape cluster report threshold float spin box QDoubleSpinBox* shapeClusterThresholdDoubleSpinBox; /// check box for shape cluster report separate with tabs QCheckBox* shapeClusterTabSeparateCheckBox; /// line edit for name for border around clusters QLineEdit* clusterBorderNameLineEdit; /// auto project borders around clusters QCheckBox* clusterBorderAutoProjectCheckBox; /// distortion correction for statistical report GuiNodeAttributeColumnSelectionComboBox* distortionCorrectionMetricColumnComboBox; /// tab widget for dialog QTabWidget* tabWidget; /// name for create border from ROI line edit QLineEdit* createBorderFromROINameLineEdit; /// create border automatic radio button QRadioButton* createBorderFromROIAutomaticRadioButton; /// create border choose nodes radio button QRadioButton* createBorderFromROIManualRadioButton; /// create border start node spin box QSpinBox* createBorderFromROIStartNodeSpinBox; /// create border end node spin box QSpinBox* createBorderFromROIEndNodeSpinBox; /// create border from roi node selection widget QWidget* createBorderFromROINodeSelectionWidget; /// create border from roi sampling density QDoubleSpinBox* createBorderFromROISamplingDensityDoubleSpinBox; /// value of show selected nodes when dialog was closed bool showSelectedNodesCheckBoxValueWhenDialogClosed; }; #endif // __GUI_SURFACE_REGION_OF_INTEREST_DIALOG_OLD_H__ caret-5.6.4~dfsg.1.orig/caret/GuiSurfaceRegionOfInterestDialogOLD.cxx0000664000175000017500000057360411572067322025305 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include "WuQFileDialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "global_variables.h" #include "AreaColorFile.h" #include "BorderColorFile.h" #include "BrainModelBorderSet.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceClusterToBorderConverter.h" #include "BrainModelSurfaceConnectedSearchMetric.h" #include "BrainModelSurfaceGeodesic.h" #include "BrainModelSurfaceMetricClustering.h" #include "BrainModelSurfaceNodeColoring.h" #include "BrainModelSurfaceROICreateBorderUsingGeodesic.h" #include "BrainModelSurfaceROITextReport.h" #include "BrainModelSurfaceToVolumeConverter.h" #include "BrainSet.h" #include "ColorFile.h" #include "DisplaySettingsBorders.h" #include "DisplaySettingsMetric.h" #include "DisplaySettingsSurface.h" #include "DisplaySettingsSurfaceShape.h" #include "FileFilters.h" #include "FileUtilities.h" #include "GuiBorderNamesListBoxSelectionDialog.h" #include "GuiBrainModelSelectionComboBox.h" #include "GuiColorSelectionDialog.h" #include "GuiFilesModified.h" #include "GeodesicDistanceFile.h" #include "GuiMainWindow.h" #include "GuiNameSelectionDialog.h" #include "GuiNodeAttributeColumnSelectionComboBox.h" #include "GuiNodeFileType.h" #include "GuiPaintColumnNamesListBoxSelectionDialog.h" #include "GuiSmoothingDialog.h" #include "GuiSurfaceRegionOfInterestDialogOLD.h" #include "GuiSurfaceToVolumeDialog.h" #include "LatLonFile.h" #include "MathUtilities.h" #include "MetricFile.h" #include "NameIndexSort.h" #include "NodeRegionOfInterestFile.h" #include "QtUtilities.h" #include "PaintFile.h" #include "ProbabilisticAtlasFile.h" #include "QtUtilities.h" #include "StatisticDataGroup.h" #include "StatisticsUtilities.h" #include "StringUtilities.h" #include "SurfaceShapeFile.h" #include "TopologyHelper.h" #include "global_variables.h" static const int maxComboBoxWidth = 400; /** * Constructor. */ GuiSurfaceRegionOfInterestDialogOLD::GuiSurfaceRegionOfInterestDialogOLD(QWidget* parent) : WuQDialog(parent) { showSelectedNodesCheckBoxValueWhenDialogClosed = true; separatorCharacter = ";"; paintWithNameIndex = -1; metricNodeForQuery = -1; shapeNodeForQuery = -1; selectionMode = SELECTION_MODE_ENTIRE_SURFACE; setSizeGripEnabled(true); setWindowTitle("Surface Region of Interest"); // // Layout for dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(3); // // Tab widget for dialog // tabWidget = new QTabWidget; dialogLayout->addWidget(tabWidget); createQuerySelectionPage(); createAttributeSelectionPage(); createReportPage(); // // The close button // QPushButton* closeButton = new QPushButton("Close"); closeButton->setAutoDefault(false); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); QPushButton* helpButton = new QPushButton("Help"); helpButton->setAutoDefault(false); QObject::connect(helpButton, SIGNAL(clicked()), this, SLOT(slotHelpButton())); // // Layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(5); buttonsLayout->addWidget(closeButton); buttonsLayout->addWidget(helpButton); dialogLayout->addLayout(buttonsLayout); QtUtilities::makeButtonsSameSize(closeButton, helpButton); const int width = 750; const QSize defSize(width /*queryPage->sizeHint().width()*/, sizeHint().height()); updateDialog(); slotSelectionMode(selectionMode); resize(defSize); setFixedWidth(width); adjustSize(); // std::cout << "Current: " << static_cast(size().width()) // << ", " << static_cast(size().height()) << std::endl; // std::cout << "Maximum: " << static_cast(maximumSize().width()) // << ", " << static_cast(maximumSize().height()) << std::endl; } /** * Destructor. */ GuiSurfaceRegionOfInterestDialogOLD::~GuiSurfaceRegionOfInterestDialogOLD() { } /** * Called when help button pressed. */ void GuiSurfaceRegionOfInterestDialogOLD::slotHelpButton() { theMainWindow->showHelpViewerDialog("dialogs/surface_roi_dialog.html"); } /** * show the dialog. */ void GuiSurfaceRegionOfInterestDialogOLD::show() { // // May want to show selected nodes // showSelectedNodesCheckBox->setChecked(true); // showSelectedNodesCheckBoxValueWhenDialogClosed); slotShowSelectedNodes(showSelectedNodesCheckBox->isChecked()); updateNumberOfSelectedNodesLabel(); WuQDialog::show(); } /** * Called when dialog closed. */ void GuiSurfaceRegionOfInterestDialogOLD::close() { showSelectedNodesCheckBoxValueWhenDialogClosed = showSelectedNodesCheckBox->isChecked(); BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); surfaceROI->setDisplaySelectedNodes(false); resetMarkedNodesAndReportHeader(false); updateNumberOfSelectedNodesLabel(); GuiBrainModelOpenGL::MOUSE_MODES m = theMainWindow->getBrainModelOpenGL()->getMouseMode(); if ((m == GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_BORDER_SELECT) || (m == GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_PAINT_INDEX_SELECT) || (m == GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_METRIC_NODE_SELECT) || (m == GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_GEODESIC_NODE_SELECT)) { theMainWindow->getBrainModelOpenGL()->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_VIEW); } theMainWindow->getBrainSet()->clearAllDisplayLists(); GuiBrainModelOpenGL::updateAllGL(); QDialog::close(); } /** * Reset/resize the marked nodes flags. */ void GuiSurfaceRegionOfInterestDialogOLD::resetMarkedNodesAndReportHeader(const bool deselectNodesInROI) { switch (getSelectionLogic()) { case BrainModelSurfaceROINodeSelection::SELECTION_LOGIC_NORMAL: reportHeader = ""; break; case BrainModelSurfaceROINodeSelection::SELECTION_LOGIC_AND: reportHeader.append("\n--- AND ---\n"); break; case BrainModelSurfaceROINodeSelection::SELECTION_LOGIC_OR: reportHeader.append("\n--- OR ----\n"); break; case BrainModelSurfaceROINodeSelection::SELECTION_LOGIC_AND_NOT: reportHeader = "\n--- AND NOT ---\n"; break; } if (deselectNodesInROI) { BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); surfaceROI->deselectAllNodes(); } } /** * Peform Metric ROI. */ /* void GuiSurfaceRegionOfInterestDialogOLD::metricAndSurfaceShapeROI(const bool metricFlag) { MetricFile* mf = NULL; if (metricFlag) { mf = theMainWindow->getBrainSet()->getMetricFile(); } else { mf = theMainWindow->getBrainSet()->getSurfaceShapeFile(); } const int numNodes = mf->getNumberOfNodes(); const int numCols = mf->getNumberOfColumns(); if ((numNodes <= 0) || (numCols <= 0)) { return; } bool firstWrite = true; int longestColumnNameLength = 10; for (int j = 0; j < numCols; j++) { longestColumnNameLength = std::max(longestColumnNameLength, static_cast(mf->getColumnName(j).length())); } longestColumnNameLength += 5; const int columnNumberLength = 10; const int numberSize = 16; for (int j = 0; j < numCols; j++) { bool doIt = false; if (metricFlag) { doIt = metricCheckBoxes[j]->isChecked(); } else { doIt = surfaceShapeCheckBoxes[j]->isChecked(); } if (doIt) { std::vector values; for (int i = 0; i < numNodes; i++) { if (nodeInROI[i]) { values.push_back(mf->getValue(i, j)); } } if (values.size() > 0) { StatisticsUtilities::DescriptiveStatistics statistics; StatisticsUtilities::computeStatistics(values, true, statistics); if (firstWrite) { if (metricFlag) { reportTextEdit->append("\nMetrics for Region Of Interest\n"); } else { reportTextEdit->append("\nSurface Shape for Region of Interest\n"); } QString str; str.append(StringUtilities::rightJustify("Column", columnNumberLength)); str.append(" "); if (tabSeparateReport) str.append(separatorCharacter); str.append(StringUtilities::leftJustify("Name", longestColumnNameLength)); if (tabSeparateReport) str.append(separatorCharacter); str.append(StringUtilities::rightJustify("Average", numberSize)); if (tabSeparateReport) str.append(separatorCharacter); str.append(StringUtilities::rightJustify("Sample Deviation", numberSize)); if (tabSeparateReport) str.append(separatorCharacter); str.append(StringUtilities::rightJustify("Abs-Average", numberSize)); if (tabSeparateReport) str.append(separatorCharacter); str.append(StringUtilities::rightJustify("Sample Abs-Deviation", numberSize)); if (tabSeparateReport) str.append(separatorCharacter); str.append(StringUtilities::rightJustify("Minimum", numberSize)); if (tabSeparateReport) str.append(separatorCharacter); str.append(StringUtilities::rightJustify("Maximum", numberSize)); if (tabSeparateReport) str.append(separatorCharacter); str.append(StringUtilities::rightJustify("Range", numberSize)); if (tabSeparateReport) str.append(separatorCharacter); str.append(StringUtilities::rightJustify("Median", numberSize)); if (tabSeparateReport) str.append(separatorCharacter); str.append(StringUtilities::rightJustify("Abs-Median", numberSize)); reportTextEdit->append(str); firstWrite = false; } QString stats; stats.append(StringUtilities::rightJustify(QString::number(j), columnNumberLength)); stats.append(" "); if (tabSeparateReport) stats.append(separatorCharacter); stats.append(StringUtilities::leftJustify(mf->getColumnName(j), longestColumnNameLength)); if (tabSeparateReport) stats.append(separatorCharacter); stats.append(StringUtilities::rightJustify(QString::number(statistics.average, 'f', 6), numberSize)); if (tabSeparateReport) stats.append(separatorCharacter); stats.append(StringUtilities::rightJustify(QString::number(statistics.standardDeviation, 'f', 6), numberSize)); if (tabSeparateReport) stats.append(separatorCharacter); stats.append(StringUtilities::rightJustify(QString::number(statistics.absAverage, 'f', 6), numberSize)); if (tabSeparateReport) stats.append(separatorCharacter); stats.append(StringUtilities::rightJustify(QString::number(statistics.absStandardDeviation, 'f', 6), numberSize)); if (tabSeparateReport) stats.append(separatorCharacter); stats.append(StringUtilities::rightJustify(QString::number(statistics.minValue, 'f', 6), numberSize)); if (tabSeparateReport) stats.append(separatorCharacter); stats.append(StringUtilities::rightJustify(QString::number(statistics.maxValue, 'f', 6), numberSize)); if (tabSeparateReport) stats.append(separatorCharacter); stats.append(StringUtilities::rightJustify(QString::number(statistics.range, 'f', 6), numberSize)); if (tabSeparateReport) stats.append(separatorCharacter); stats.append(StringUtilities::rightJustify(QString::number(statistics.median, 'f', 6), numberSize)); if (tabSeparateReport) stats.append(separatorCharacter); stats.append(StringUtilities::rightJustify(QString::number(statistics.absMedian, 'f', 6), numberSize)); reportTextEdit->append(stats); } } } } */ /** * Peform Paint ROI. */ /* void GuiSurfaceRegionOfInterestDialogOLD::paintROI(const BrainModelSurface* bms, const double roiArea) { const CoordinateFile* cf = bms->getCoordinateFile(); //const TopologyFile* tf = topologyComboBox->getSelectedTopologyFile(); const TopologyFile* tf = bms->getTopologyFile(); const int numTiles = tf->getNumberOfTiles(); PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); const int numPaintNames = pf->getNumberOfPaintNames(); LatLonFile* llf = theMainWindow->getBrainSet()->getLatLonFile(); const bool latLonValid = (llf->getNumberOfColumns() > 0); MetricFile* metricFile = theMainWindow->getBrainSet()->getMetricFile(); const int metricCorrectionColumn = distortionCorrectionMetricColumnComboBox->currentIndex(); // // Find longest paint name use in the ROI // int longestPaintNameLength = 11; for (int m = 0; m < numPaintNames; m++) { longestPaintNameLength = std::max(static_cast(pf->getPaintNameFromIndex(m).length()), longestPaintNameLength); } longestPaintNameLength += 3; const int numberSize = 16; // // surface area for each paint name // std::vector paintNameAreas(numPaintNames, 0.0); std::vector paintNameAreasCorrected(numPaintNames, 0.0); std::vector paintNameAreasCogX(numPaintNames, 0.0); std::vector paintNameAreasCogY(numPaintNames, 0.0); std::vector paintNameAreasCogZ(numPaintNames, 0.0); std::vector paintNameAreasLat(numPaintNames, 0.0); std::vector paintNameAreasLon(numPaintNames, 0.0); std::vector paintNameNodeCounts(numPaintNames, 0); const int numPaintColumns = pf->getNumberOfColumns(); for (int j = 0; j < numPaintColumns; j++) { if (paintCheckBoxes[j]->isChecked()) { // // Reset surface area for each paint name, COG, Lat/Lon // std::fill(paintNameAreas.begin(), paintNameAreas.end(), 0.0); std::fill(paintNameAreasCorrected.begin(), paintNameAreasCorrected.end(), 0.0); for (int i = 0; i < numTiles; i++) { // // Is tile in the ROI ? // if (tileInROI[i]) { int tileNodes[3]; tf->getTile(i, tileNodes); for (int k = 0; k < 3; k++) { // // Is this node in the ROI // if (nodeInROI[tileNodes[k]]) { const int node = tileNodes[k]; // // Update area node's paint // const int paintNameIndex = pf->getPaint(node, j); float nodeArea = tileArea[i] / 3.0; paintNameAreas[paintNameIndex] += nodeArea; float areaDistCorrect = nodeArea; if (metricCorrectionColumn >= 0) { const double metric = metricFile->getValue(node, metricCorrectionColumn); areaDistCorrect *= std::pow(2.0, metric); } paintNameAreasCorrected[paintNameIndex] += areaDistCorrect; } } } } std::fill(paintNameAreasCogX.begin(), paintNameAreasCogX.end(), 0.0); std::fill(paintNameAreasCogY.begin(), paintNameAreasCogY.end(), 0.0); std::fill(paintNameAreasCogZ.begin(), paintNameAreasCogZ.end(), 0.0); std::fill(paintNameAreasLat.begin(), paintNameAreasLat.end(), 0.0); std::fill(paintNameAreasLon.begin(), paintNameAreasLon.end(), 0.0); std::fill(paintNameNodeCounts.begin(), paintNameNodeCounts.end(), 0); const int numNodes = bms->getNumberOfNodes(); for (int i = 0; i < numNodes; i++) { if (nodeInROI[i]) { const int paintNameIndex = pf->getPaint(i, j); // // Update COG // const float* xyz = cf->getCoordinate(i); paintNameAreasCogX[paintNameIndex] += xyz[0]; paintNameAreasCogY[paintNameIndex] += xyz[1]; paintNameAreasCogZ[paintNameIndex] += xyz[2]; paintNameNodeCounts[paintNameIndex]++; // // Update Lat/Lon // if (latLonValid) { float lat, lon; llf->getLatLon(i, 0, lat, lon); paintNameAreasLat[paintNameIndex] += lat; paintNameAreasLon[paintNameIndex] += lon; } } } // // See which paint names are used by the ROI // bool headerWritten = false; for (int m = 0; m < numPaintNames; m++) { if (paintNameAreas[m] > 0.0) { const QString indent(" "); if (headerWritten == false) { // // Write the header for this paint column // headerWritten = true; reportTextEdit->append("\n"); QString line; line.append("Paint Column "); line.append(QString::number(j)); line.append(" "); line.append(pf->getColumnName(j)); reportTextEdit->append(line); line = ""; line.append(indent); if (tabSeparateReport) line.append(separatorCharacter); line.append(StringUtilities::leftJustify("Paint Name", longestPaintNameLength)); if (tabSeparateReport) line.append(separatorCharacter); line.append(StringUtilities::rightJustify("Area", numberSize)); if (tabSeparateReport) line.append(separatorCharacter); line.append(StringUtilities::rightJustify("Percent Area", numberSize)); if (tabSeparateReport) line.append(separatorCharacter); if (metricCorrectionColumn >= 0) { line.append(StringUtilities::rightJustify("Area-Corr", numberSize)); if (tabSeparateReport) line.append(separatorCharacter); } line.append(StringUtilities::rightJustify("COG - X", numberSize)); if (tabSeparateReport) line.append(separatorCharacter); line.append(StringUtilities::rightJustify("COG - Y", numberSize)); if (tabSeparateReport) line.append(separatorCharacter); line.append(StringUtilities::rightJustify("COG - Z", numberSize)); if (tabSeparateReport) line.append(separatorCharacter); line.append(StringUtilities::rightJustify("Latitude", numberSize)); if (tabSeparateReport) line.append(separatorCharacter); line.append(StringUtilities::rightJustify("Longitude", numberSize)); reportTextEdit->append(line); } // // Write the area for this paint name // QString stats; stats.append(indent); if (tabSeparateReport) stats.append(separatorCharacter); stats.append(StringUtilities::leftJustify(pf->getPaintNameFromIndex(m), longestPaintNameLength)); if (tabSeparateReport) stats.append(separatorCharacter); stats.append(StringUtilities::rightJustify(QString::number(paintNameAreas[m], 'f', 3), numberSize)); if (tabSeparateReport) stats.append(separatorCharacter); const double percent = (paintNameAreas[m] / roiArea) * 100.0; stats.append(StringUtilities::rightJustify(QString::number(percent, 'f', 3), numberSize)); if (tabSeparateReport) stats.append(separatorCharacter); if (metricCorrectionColumn >= 0) { stats.append(StringUtilities::rightJustify(QString::number(paintNameAreasCorrected[m], 'f', 3), numberSize)); if (tabSeparateReport) stats.append(separatorCharacter); } const double numNodesForPaint = paintNameNodeCounts[m]; double cogX = 0.0; if (numNodesForPaint > 0) { cogX = paintNameAreasCogX[m] / numNodesForPaint; } stats.append(StringUtilities::rightJustify(QString::number(cogX, 'f', 3), numberSize)); if (tabSeparateReport) stats.append(separatorCharacter); double cogY = 0.0; if (numNodesForPaint > 0) { cogY = paintNameAreasCogY[m] / numNodesForPaint; } stats.append(StringUtilities::rightJustify(QString::number(cogY, 'f', 3), numberSize)); if (tabSeparateReport) stats.append(separatorCharacter); double cogZ = 0.0; if (numNodesForPaint > 0) { cogZ = paintNameAreasCogZ[m] / numNodesForPaint; } stats.append(StringUtilities::rightJustify(QString::number(cogZ, 'f', 3), numberSize)); if (tabSeparateReport) stats.append(separatorCharacter); double cogLat = 0.0; if (numNodesForPaint > 0) { cogLat = paintNameAreasLat[m] / numNodesForPaint; } stats.append(StringUtilities::rightJustify(QString::number(cogLat, 'f', 3), numberSize)); if (tabSeparateReport) stats.append(separatorCharacter); double cogLon = 0.0; if (numNodesForPaint > 0) { cogLon = paintNameAreasLon[m] / numNodesForPaint; } stats.append(StringUtilities::rightJustify(QString::number(cogLon, 'f', 3), numberSize)); reportTextEdit->append(stats); } } } } } */ /** * Peform a query on all nodes. */ void GuiSurfaceRegionOfInterestDialogOLD::selectNodesAll() { BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); surfaceROI->selectAllNodes(theMainWindow->getBrainModelSurface()); reportHeader.append("\nQUERY: All Nodes."); } /** * Select nodes by border. */ void GuiSurfaceRegionOfInterestDialogOLD::selectNodesBorder() { // // Get the selected flat surface for border queries // if (borderSurfaceComboBox->count() == 0) { QMessageBox::warning(this, "No Flat Surface", "There is no flat surface which is required for border queries."); return; } const BrainModelSurface* bms = borderSurfaceComboBox->getSelectedBrainModelSurface(); BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); surfaceROI->selectNodesWithinBorder(getSelectionLogic(), theMainWindow->getBrainModelSurface(), bms, bmbs, selectedBorderName); QString str("\nQuery: All nodes within all border(s) named "); str.append(selectedBorderName); reportTextEdit->append(str); str = "Flat surface for border node inclusion: "; str.append(bms->getDescriptiveName()); reportHeader.append(str); } /** * select nodes by lat/lon. */ void GuiSurfaceRegionOfInterestDialogOLD::selectNodesLatLon() { BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); const int columnNumber = 0; surfaceROI->selectNodesWithLatLong(getSelectionLogic(), theMainWindow->getBrainModelSurface(), theMainWindow->getBrainSet()->getLatLonFile(), columnNumber, latLowerRangeDoubleSpinBox->value(), latUpperRangeDoubleSpinBox->value(), lonLowerRangeDoubleSpinBox->value(), lonUpperRangeDoubleSpinBox->value()); } /** * Select nodes by metric. */ void GuiSurfaceRegionOfInterestDialogOLD::selectNodesMetric() { BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms == NULL) { return; } MetricFile* metricFile = theMainWindow->getBrainSet()->getMetricFile(); BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); const bool checkAllNodes = metricAllNodesRadioButton->isChecked(); if (checkAllNodes) { surfaceROI->selectNodesWithMetric(getSelectionLogic(), bms, metricFile, metricCategoryComboBox->currentIndex(), metricLowerThresholdDoubleSpinBox->value(), metricUpperThresholdDoubleSpinBox->value()); } else{ surfaceROI->selectConnectedNodesWithMetric(getSelectionLogic(), bms, metricFile, metricCategoryComboBox->currentIndex(), metricLowerThresholdDoubleSpinBox->value(), metricUpperThresholdDoubleSpinBox->value(), metricNodeForQuery); } QString modeMessage; if (checkAllNodes) { modeMessage = "All nodes with metric threshold range"; } else { modeMessage = "Node selected with mouse with metric threshold range"; } std::ostringstream str; str << "\nQUERY: " << modeMessage.toAscii().constData() << " (" << metricLowerThresholdDoubleSpinBox->value() << ", " << metricUpperThresholdDoubleSpinBox->value() << ")\n" << "Starting Node: " << metricNodeForQuery << "\n" << "Column Name: " << metricFile->getColumnName(metricCategoryComboBox->currentIndex()).toAscii().constData() << "\n"; reportHeader.append(str.str().c_str()); } /** * select nodes by crossovers. */ void GuiSurfaceRegionOfInterestDialogOLD::selectNodesCrossovers() { BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms == NULL) { return; } BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); surfaceROI->selectNodesThatAreCrossovers(getSelectionLogic(), bms); } /** * Select nodes by shape. */ void GuiSurfaceRegionOfInterestDialogOLD::selectNodesShape() { BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms == NULL) { return; } SurfaceShapeFile* ssf = theMainWindow->getBrainSet()->getSurfaceShapeFile(); BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); const int column = shapeCategoryComboBox->currentIndex(); const bool checkAllNodes = shapeAllNodesRadioButton->isChecked(); if (checkAllNodes) { surfaceROI->selectNodesWithSurfaceShape(getSelectionLogic(), bms, ssf, column, shapeLowerThresholdDoubleSpinBox->value(), shapeUpperThresholdDoubleSpinBox->value()); } else{ surfaceROI->selectConnectedNodesWithSurfaceShape(getSelectionLogic(), bms, ssf, column, shapeLowerThresholdDoubleSpinBox->value(), shapeUpperThresholdDoubleSpinBox->value(), shapeNodeForQuery); } QString modeMessage; if (checkAllNodes) { modeMessage = "All nodes with shape threshold range"; } else { modeMessage = "Node selected with mouse with shape threshold range"; } std::ostringstream str; str << "\nQUERY: " << modeMessage.toAscii().constData() << " (" << shapeLowerThresholdDoubleSpinBox->value() << ", " << shapeUpperThresholdDoubleSpinBox->value() << ")\n" << "Starting Node: " << shapeNodeForQuery << "\n" << "Column Name: " << ssf->getColumnName(column).toAscii().constData() << "\n"; reportHeader.append(str.str().c_str()); } /** * select nodes by paint */ void GuiSurfaceRegionOfInterestDialogOLD::selectNodesPaint() { const int column = paintWithNameCategoryComboBox->currentIndex(); if (column >= 0) { BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); const PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); surfaceROI->selectNodesWithPaint(getSelectionLogic(), theMainWindow->getBrainModelSurface(), pf, column, pf->getPaintNameFromIndex(paintWithNameIndex)); // // Header for text report // QString str("\nQUERY: All nodes with paint category "); str.append(pf->getColumnName(column)); str.append(" equal to "); str.append(pf->getPaintNameFromIndex(paintWithNameIndex)); reportHeader.append(str); } } /** * Called to deselect nodes. */ void GuiSurfaceRegionOfInterestDialogOLD::slotDeselectNodesButton() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); resetMarkedNodesAndReportHeader(true); BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); surfaceROI->deselectAllNodes(); updateNumberOfSelectedNodesLabel(); theMainWindow->getBrainSet()->clearAllDisplayLists(); GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); } BrainModelSurfaceROINodeSelection::SELECTION_LOGIC GuiSurfaceRegionOfInterestDialogOLD::getSelectionLogic() const { return static_cast(selectionLogicComboBox->currentIndex()); } /** * call when invert nodes button pressed. */ void GuiSurfaceRegionOfInterestDialogOLD::slotInvertNodeSelectionPushButton() { BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); if (surfaceROI->anyNodesSelected() == false) { QMessageBox::critical(this, "No Nodes Selected", "No nodes are presently selected so inverting the node election\" will\n" "select nothing. Change to \"Normal Selection\" then select nodes."); return; } surfaceROI->invertSelectedNodes(operationSurfaceComboBox->getSelectedBrainModelSurface()); updateNumberOfSelectedNodesLabel(); reportHeader = "\n--- NOT ---\n"; theMainWindow->getBrainSet()->clearAllDisplayLists(); GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); } /** * Called to select nodes. */ void GuiSurfaceRegionOfInterestDialogOLD::slotSelectNodesButton() { if (selectionMode == SELECTION_MODE_NONE) { QMessageBox::critical(this, "ROI Error", "You must select a query type"); return; } BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); switch(getSelectionLogic()) { case BrainModelSurfaceROINodeSelection::SELECTION_LOGIC_NORMAL: break; case BrainModelSurfaceROINodeSelection::SELECTION_LOGIC_AND: if (surfaceROI->anyNodesSelected() == false) { QMessageBox::critical(this, "No Nodes Selected", "No nodes are presently selected so an \"AND Selection\" will\n" "select nothing. Change to \"Normal Selection\" then select nodes."); return; } break; case BrainModelSurfaceROINodeSelection::SELECTION_LOGIC_OR: break; case BrainModelSurfaceROINodeSelection::SELECTION_LOGIC_AND_NOT: if (surfaceROI->anyNodesSelected() == false) { QMessageBox::critical(this, "No Nodes Selected", "No nodes are presently selected so a \"NOT AND Selection\" will\n" "select nothing. Change to \"Normal Selection\" then select nodes."); return; } break; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); resetMarkedNodesAndReportHeader(false); switch(selectionMode) { case SELECTION_MODE_ENTIRE_SURFACE: selectNodesAll(); break; case SELECTION_MODE_NODES_WITH_PAINT: selectNodesPaint(); break; case SELECTION_MODE_NODES_WITHIN_BORDER: if (selectedBorderName.isEmpty()) { QMessageBox::critical(this, "ROI Error", "You must select a border name"); return; } selectNodesBorder(); break; case SELECTION_MODE_NODES_WITHIN_LATLON: selectNodesLatLon(); break; case SELECTION_MODE_NODES_WITH_METRIC: selectNodesMetric(); break; case SELECTION_MODE_NODES_WITH_SHAPE: selectNodesShape(); break; case SELECTION_MODE_NODES_WITH_CROSSOVERS: selectNodesCrossovers(); break; case SELECTION_MODE_NONE: break; } // // Set node highlighting // updateNumberOfSelectedNodesLabel(); slotShowSelectedNodes(showSelectedNodesCheckBox->isChecked()); QApplication::restoreOverrideCursor(); } /** * Create the report header (returns true if no nodes in query) */ bool GuiSurfaceRegionOfInterestDialogOLD::createReportHeader(const QString& headerText, const bool tabSeparateReportIn, float& roiAreaOut) { tabSeparateReport = tabSeparateReportIn; BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); // // Add the header describing the node selection // reportTextEdit->append(reportHeader); BrainModelSurface* bms = operationSurfaceComboBox->getSelectedBrainModelSurface(); if (bms == NULL) { return true; } // const TopologyFile* tf = topologyComboBox->getSelectedTopologyFile(); //bms->getTopologyFile(); const TopologyFile* tf = bms->getTopologyFile(); const int numNodes = theMainWindow->getBrainSet()->getNumberOfNodes(); // // Determine total area and selected area. // const CoordinateFile* cf = bms->getCoordinateFile(); double totalArea = 0.0; roiAreaOut = 0.0; const int numTiles = tf->getNumberOfTiles(); tileArea.resize(numTiles); std::fill(tileArea.begin(), tileArea.end(), 0.0); tileInROI.resize(numTiles); std::fill(tileInROI.begin(), tileInROI.end(), false); double centerOfGravity[3] = { 0.0, 0.0, 0.0 }; for (int i = 0; i < numTiles; i++) { int nodes[3]; tf->getTile(i, nodes); tileArea[i] = MathUtilities::triangleArea(cf->getCoordinate(nodes[0]), cf->getCoordinate(nodes[1]), cf->getCoordinate(nodes[2])); totalArea += tileArea[i]; double numMarked = 0.0; if (surfaceROI->getNodeSelected(nodes[0])) numMarked += 1.0; if (surfaceROI->getNodeSelected(nodes[1])) numMarked += 1.0; if (surfaceROI->getNodeSelected(nodes[2])) numMarked += 1.0; if (tileArea[i] > 0.0) { roiAreaOut += (numMarked / 3.0) * tileArea[i]; } tileInROI[i] = (numMarked > 0.0); } for (int m = 0; m < numNodes; m++) { if (surfaceROI->getNodeSelected(m)) { const float* xyz = cf->getCoordinate(m); centerOfGravity[0] += xyz[0]; centerOfGravity[1] += xyz[1]; centerOfGravity[2] += xyz[2]; } } if (headerText.isEmpty() == false) { reportTextEdit->append(headerText); reportTextEdit->append("\n"); } QString surf("Surface: "); surf.append(bms->getDescriptiveName()); surf.append("\n"); reportTextEdit->append(surf); QString topo("Topology: "); topo.append(tf->getDescriptiveName()); topo.append("\n"); reportTextEdit->append(topo); reportTextEdit->append(""); const int count = surfaceROI->getNumberOfNodesSelected(); std::ostringstream str; str << count << " of " << numNodes << " nodes in region of interest\n" << std::ends; reportTextEdit->append(str.str().c_str()); str.str(""); // clears contents str << "Total Surface Area: " << totalArea << std::ends; reportTextEdit->append(str.str().c_str()); str.str(""); // clears contents str << "Region of Interest Surface Area: " << roiAreaOut << std::ends; reportTextEdit->append(str.str().c_str()); centerOfGravity[0] = centerOfGravity[0] / static_cast(count); centerOfGravity[1] = centerOfGravity[1] / static_cast(count); centerOfGravity[2] = centerOfGravity[2] / static_cast(count); str.str(""); // clears contents str << "Region of Interest Center of Gravity: " << centerOfGravity[0] << " " << centerOfGravity[1] << " " << centerOfGravity[2] << std::ends; reportTextEdit->append(str.str().c_str()); float meanDist, minDist, maxDist; bms->getMeanDistanceBetweenNodes(surfaceROI, meanDist, minDist, maxDist); str.str(""); // clears contents str << "Region Mean Distance Between Nodes: " << meanDist << std::ends; reportTextEdit->append(str.str().c_str()); reportTextEdit->append(" "); return false; } /** * Called when create paint subregion report button pressed. */ void GuiSurfaceRegionOfInterestDialogOLD::slotCreatePaintReportButton() { BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); // // Make sure nodes are selected // if (surfaceROI->anyNodesSelected() == false) { QMessageBox::critical(this, "Error: no nodes in ROI", "There are no nodes in the region of interest."); return; } // // Make sure a valid paint column is selected // PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); const int paintColumn = paintRegionReportColumnComboBox->currentIndex(); if ((paintColumn < 0) || (paintColumn >= pf->getNumberOfColumns())) { QMessageBox::critical(this, "ERROR", "Invalid (or no) paint column selected."); return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); // // Get all of the paint names for the column // std::vector paintIndices; pf->getPaintNamesForColumn(paintColumn, paintIndices); // // process each paint index // const int numPaintIndices = static_cast(paintIndices.size()); for (int i = 0; i < numPaintIndices; i++) { // // Get the index // const int paintIndex = paintIndices[i]; // // Save the selected nodes // const int numNodes = pf->getNumberOfNodes(); std::vector savedNodeInROI(numNodes, 0); // // Limit nodes in ROI to those with valid paint column // for (int j = 0; j < numNodes; j++) { savedNodeInROI[j] = surfaceROI->getNodeSelected(j); if (surfaceROI->getNodeSelected(j)) { if (pf->getPaint(j, paintColumn) == paintIndex) { surfaceROI->setNodeSelected(j, true); } } } // // Print the report // std::ostringstream str; str << "Paint Subregion Name: " << pf->getPaintNameFromIndex(paintIndex).toAscii().constData(); createReport(str.str().c_str(), tabSeparatePaintReportCheckBox->isChecked(), (i == (numPaintIndices - 1))); // // Restore the selected nodes // for (int j = 0; j < numNodes; j++) { surfaceROI->setNodeSelected(j, (savedNodeInROI[j] != 0)); } } QApplication::restoreOverrideCursor(); } /** * Called when create report button pressed. */ void GuiSurfaceRegionOfInterestDialogOLD::slotCreateReportButton() { BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); if (surfaceROI->anyNodesSelected() == false) { QMessageBox::critical(this, "Error: no nodes in ROI", "There are no nodes in the region of interest."); return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); createReport("", tabSeparateReportCheckBox->isChecked(), true); QApplication::restoreOverrideCursor(); } /** * create the report. */ void GuiSurfaceRegionOfInterestDialogOLD::createReport(const QString& headerText, const bool tabSeparateReportFlag, const bool doConclusion) { std::vector metricSelections; for (unsigned int i = 0; i < metricCheckBoxes.size(); i++) { metricSelections.push_back(metricCheckBoxes[i]->isChecked()); } std::vector shapeSelections; for (unsigned int i = 0; i < surfaceShapeCheckBoxes.size(); i++) { shapeSelections.push_back(surfaceShapeCheckBoxes[i]->isChecked()); } std::vector paintSelections; for (unsigned int i = 0; i < paintCheckBoxes.size(); i++) { paintSelections.push_back(paintCheckBoxes[i]->isChecked()); } BrainSet* bs = theMainWindow->getBrainSet(); BrainModelSurfaceROITextReport bmsri(bs, operationSurfaceComboBox->getSelectedBrainModelSurface(), bs->getBrainModelSurfaceRegionOfInterestNodeSelection(), bs->getMetricFile(), metricSelections, bs->getSurfaceShapeFile(), shapeSelections, bs->getPaintFile(), paintSelections, bs->getLatLonFile(), 0, // lat/lon file column //reportHeader, headerText, bs->getMetricFile(), distortionCorrectionMetricColumnComboBox->currentIndex(), tabSeparateReportFlag); try { bmsri.execute(); } catch (BrainModelAlgorithmException& e) { QMessageBox::critical(this, "ERROR", e.whatQString()); return; } reportTextEdit->setText(bmsri.getReportText()); /* float roiArea = 0.0; if (createReportHeader(headerText, tabSeparateReportFlag, roiArea)) { return; } // // ROI for metrics // metricAndSurfaceShapeROI(true); // // ROI for surface shape // metricAndSurfaceShapeROI(false); // // ROI for paint // BrainModelSurface* bms = operationSurfaceComboBox->getSelectedBrainModelSurface(); if (bms == NULL) { return; } paintROI(bms, roiArea); */ if (doConclusion) { // // Switch to report page // tabWidget->setCurrentWidget(reportPage); QApplication::beep(); theMainWindow->speakText("The report is ready.", false); } } /** * Create the query page */ void GuiSurfaceRegionOfInterestDialogOLD::createQuerySelectionPage() { // // Create the query page // queryPage = new QWidget; tabWidget->addTab(queryPage, "Query"); QVBoxLayout* layout = new QVBoxLayout(queryPage); layout->setSpacing(3); //----------------------------------------------------------------------------- // // Group Box for node selection // QGroupBox* selectionModeGroupBox = new QGroupBox("Region of Interest Node Selection on Main Window Surface"); layout->addWidget(selectionModeGroupBox); QVBoxLayout* selectionModeGroupLayout = new QVBoxLayout(selectionModeGroupBox); // // Node selection method label and combo box // QLabel* selectionMethodLabel = new QLabel("Selection Method "); selectionModeComboBox = new QComboBox; QObject::connect(selectionModeComboBox, SIGNAL(activated(int)), this, SLOT(slotSelectionMode(int))); selectionModeComboBox->insertItem(SELECTION_MODE_ENTIRE_SURFACE, "Entire Surface"); selectionModeComboBox->insertItem(SELECTION_MODE_NODES_WITH_PAINT, "Nodes With Paint"); selectionModeComboBox->insertItem(SELECTION_MODE_NODES_WITHIN_BORDER, "Nodes Within Border"); selectionModeComboBox->insertItem(SELECTION_MODE_NODES_WITHIN_LATLON, "Nodes within Lat/Long Range"); selectionModeComboBox->insertItem(SELECTION_MODE_NODES_WITH_METRIC, "Nodes With Metric"); selectionModeComboBox->insertItem(SELECTION_MODE_NODES_WITH_SHAPE, "Nodes with Surface Shape"); selectionModeComboBox->insertItem(SELECTION_MODE_NODES_WITH_CROSSOVERS, "Nodes with Crossovers"); selectionModeComboBox->setFixedWidth(selectionModeComboBox->sizeHint().width()); QHBoxLayout* selectionMethodBoxLayout = new QHBoxLayout; selectionModeGroupLayout->addLayout(selectionMethodBoxLayout); selectionMethodBoxLayout->addWidget(selectionMethodLabel); selectionMethodBoxLayout->addWidget(selectionModeComboBox); //selectionMethodBoxLayout->setStretchFactor(selectionMethodLabel, 0); //selectionMethodBoxLayout->setStretchFactor(selectionModeComboBox, 100); selectionMethodBoxLayout->addStretch(); //----------------------------------------------------------------------------- // // Widget stack for different query controls // queryControlWidgetStack = new QStackedWidget; selectionModeGroupLayout->addWidget(queryControlWidgetStack); //----------------------------------------------------------------------------- // // Empty widget for entire surface // queryEntireSurfaceWidget = new QWidget; queryControlWidgetStack->addWidget(queryEntireSurfaceWidget); //----------------------------------------------------------------------------- // // nodes with paint // createNodeSelectionPaint(); queryControlWidgetStack->addWidget(nodesWithPaintQVBox); //----------------------------------------------------------------------------- // // nodes within border // createNodeSelectionBorder(); queryControlWidgetStack->addWidget(nodesWithinBorderQVBox); //----------------------------------------------------------------------------- // // nodes with lat/lon // createNodeSelectionLatLon(); queryControlWidgetStack->addWidget(nodesWithinLatLonQVBox); //----------------------------------------------------------------------------- // // nodes with metric // createNodeSelectionMetric(); queryControlWidgetStack->addWidget(nodesWithMetricQVBox); //----------------------------------------------------------------------------- // // nodes with shape // createNodeSelectionShape(); queryControlWidgetStack->addWidget(nodesWithShapeQVBox); //----------------------------------------------------------------------------- // // nodes with crossovers // nodesWithCrossoversWidget = new QWidget; queryControlWidgetStack->addWidget(nodesWithCrossoversWidget); //----------------------------------------------------------------------------- // // Frame used as a separator // //QT4 CONVERSION Q3GroupBox* separatorFrame = new Q3GroupBox(selectionModeGroupBox); //QT4 CONVERSION separatorFrame->setFrameStyle(Q3Frame::HLine); //QT4 CONVERSION separatorFrame->setLineWidth(3); //----------------------------------------------------------------------------- // // Select Nodes // selectionModeGroupLayout->addWidget(createNodeSelectionSection()); //----------------------------------------------------------------------------- // // operation surface label and combo box // QLabel* operationSurfaceLabel = new QLabel("Surface "); operationSurfaceComboBox = new GuiBrainModelSelectionComboBox(false, true, false, "", 0, "operationSurfaceComboBox"); operationSurfaceComboBox->setSelectedBrainModel(theMainWindow->getBrainSet()->getActiveFiducialSurface()); operationSurfaceComboBox->setMaximumWidth(maxComboBoxWidth); QObject::connect(operationSurfaceComboBox, SIGNAL(activated(int)), this, SLOT(slotSurfaceSelection())); QHBoxLayout* operationSurfaceLayout = new QHBoxLayout; operationSurfaceLayout->addWidget(operationSurfaceLabel); operationSurfaceLayout->addWidget(operationSurfaceComboBox); //operationSurfaceLayout->setStretchFactor(operationSurfaceLabel, 0); //operationSurfaceLayout->setStretchFactor(operationSurfaceComboBox, 100); operationSurfaceLayout->addStretch(); // // operation topology file // /* QLabel* operationTopoLabel = new QLabel("Topology "); topologyComboBox = new GuiTopologyFileComboBox(0); QObject::connect(topologyComboBox, SIGNAL(activated(int)), this, SLOT(slotTopologySelection())); QHBoxLayout* operationTopologyLayout = new QHBoxLayout; operationTopologyLayout->addWidget(operationTopoLabel); operationTopologyLayout->addWidget(topologyComboBox); operationTopologyLayout->setStretchFactor(operationTopoLabel, 0); operationTopologyLayout->setStretchFactor(topologyComboBox, 100); */ // // Group Box for operation surface section // QGroupBox* operationSurfaceGroupBox = new QGroupBox("Operation Surface and Topology"); layout->addWidget(operationSurfaceGroupBox); QVBoxLayout* operationSurfaceGroupLayout = new QVBoxLayout(operationSurfaceGroupBox); operationSurfaceGroupLayout->addLayout(operationSurfaceLayout); // operationSurfaceGroupLayout->addLayout(operationTopologyLayout); //----------------------------------------------------------------------------- // // Operation combo box // QLabel* operationLabel = new QLabel("Operation"); operationComboBox = new QComboBox; QObject::connect(operationComboBox, SIGNAL(activated(int)), this, SLOT(slotOperationMode(int))); operationComboBox->insertItem(OPERATION_MODE_ASSIGN_METRIC, "Assign Metric Column for Selected Nodes"); operationComboBox->insertItem(OPERATION_MODE_ASSIGN_PAINT, "Assign Paint Attributes to Selected Nodes"); operationComboBox->insertItem(OPERATION_MODE_ASSIGN_SURFACE_SHAPE, "Assign Surface Shape Column for Selected Nodes"); operationComboBox->insertItem(OPERATION_MODE_COMPUTE_INTEGRATED_FOLDING_INDEX, "Compute Integrated Folding Index"); operationComboBox->insertItem(OPERATION_MODE_CREATE_BORDERS_FROM_CLUSTERS, "Create Borders Around Clusters"); operationComboBox->insertItem(OPERATION_MODE_CREATE_BORDERS_FROM_ROI, "Create Open (Linear) Border from ROI"); operationComboBox->insertItem(OPERATION_MODE_CREATE_VOLUME_ROI, "Create Volume ROI from Selected Nodes"); operationComboBox->insertItem(OPERATION_MODE_DISCONNECT_NODES, "Disconnect Selected Nodes"); operationComboBox->insertItem(OPERATION_MODE_GEODESIC, "Geodesic Distance"); operationComboBox->insertItem(OPERATION_MODE_PROB_ATLAS_OVERLAP, "Probabilistic Atlas Overlap Analysis"); operationComboBox->insertItem(OPERATION_MODE_SMOOTH_NODES, "Smooth Selected Nodes"); operationComboBox->insertItem(OPERATION_MODE_STATISTICAL_REPORT, "Statistical Report on Selected Nodes"); operationComboBox->insertItem(OPERATION_MODE_STATISTICAL_PAINT_REPORT, "Statistical Report on Paint Subregions"); operationComboBox->insertItem(OPERATION_MODE_SHAPE_CORRELATION, "Surface Shape Correlation Coefficient Report"); operationComboBox->insertItem(OPERATION_MODE_SHAPE_CLUSTER_ANALYSIS, "Surface Shape Cluster Analysis"); QHBoxLayout* operationBoxLayout = new QHBoxLayout; operationBoxLayout->addWidget(operationLabel); operationBoxLayout->addWidget(operationComboBox); //operationBoxLayout->setStretchFactor(operationLabel, 0); //operationBoxLayout->setStretchFactor(operationComboBox, 100); operationBoxLayout->addStretch(); // // Widget stack for different operations // operationsWidgetStack = new QStackedWidget; // // create the assign metric operations widget // createOperationAssignMetric(); operationsWidgetStack->addWidget(operationAssignMetricWidget); // // create the assign paint operations widget // createOperationAssignPaint(); operationsWidgetStack->addWidget(operationAssignPaintWidget); // // create the assign surface shape operations widget // createOperationAssignSurfaceShape(); operationsWidgetStack->addWidget(operationAssignSurfaceShapeWidget); // // create the create borders around clusters widget // createOperationsBordersAroundClusters(); operationsWidgetStack->addWidget(operationCreateBordersFromClustersWidget); // // Create border from ROI widget // createOperationsBordersFromROI(); operationsWidgetStack->addWidget(operationCreateBordersFromROIWidget); // // create the create volume roi operations widget // createOperationCreateVolumeROI(); operationsWidgetStack->addWidget(operationCreateVolumeRoiWidget); // // create the disconnect nodes operations widget // createOperationDisconnectNodes(); operationsWidgetStack->addWidget(operationDisconnectNodesWidget); // // Create the geodesic distance widget // createOperationGeodesicDistance(); operationsWidgetStack->addWidget(operationGeodesicWidget); // // Create the integrated folding index widget // createOperationIntegratedFoldingIndex(); operationsWidgetStack->addWidget(operationComputeIntegratedFoldingIndexWidget); // // // Create the geodesic distance widget // createOperationProbAtlas(); operationsWidgetStack->addWidget(operationProbAtlasWidget); // // create the smooth nodes operation widget // createOperationSmoothNodes(); operationsWidgetStack->addWidget(operationSmoothNodesWidget); // // create the statistical report operations widget // createOperationStatisticalReport(); operationsWidgetStack->addWidget(operationStatisticalReportWidget); // // create the statistical report on paint subregion operations widget // createOperationStatisticalPaintReport(); operationsWidgetStack->addWidget(operationStatisticalPaintReportWidget); // // create the surface shape correlation coefficient report widget // createShapeCorrelationCoefficientReport(); operationsWidgetStack->addWidget(operationShapeCorrelationWidget); // // create the surface shape cluster report widget // createShapeClusterReport(); operationsWidgetStack->addWidget(operationShapeClusterWidget); // // Group Box for operation section // QGroupBox* operationGroupBox = new QGroupBox("Operate on Selected Nodes"); layout->addWidget(operationGroupBox); QVBoxLayout* operationGroupLayout = new QVBoxLayout(operationGroupBox); operationGroupLayout->addLayout(operationBoxLayout); operationGroupLayout->addWidget(operationsWidgetStack); } /** * create the assign metric operation section */ void GuiSurfaceRegionOfInterestDialogOLD::createOperationAssignMetric() { // // Metric column and new metric value // QLabel* metricColumnLabel = new QLabel("Metric Column "); metricColumnAssignComboBox = new GuiNodeAttributeColumnSelectionComboBox( GUI_NODE_FILE_TYPE_METRIC, true, false, false); metricColumnAssignComboBox->setMaximumWidth(maxComboBoxWidth); metricColumnAssignNameLineEdit = new QLineEdit; metricColumnAssignNameLineEdit->setMinimumWidth(150); QObject::connect(metricColumnAssignComboBox, SIGNAL(itemNameSelected(const QString&)), metricColumnAssignNameLineEdit, SLOT(setText(const QString&))); metricColumnAssignNameLineEdit->setText(metricColumnAssignComboBox->getCurrentLabel()); QHBoxLayout* columnLayout = new QHBoxLayout; columnLayout->addWidget(metricColumnLabel); columnLayout->addWidget(metricColumnAssignComboBox); columnLayout->addWidget(metricColumnAssignNameLineEdit); columnLayout->setStretchFactor(metricColumnLabel, 0); columnLayout->setStretchFactor(metricColumnAssignNameLineEdit, 0); //columnLayout->setStretchFactor(metricColumnAssignComboBox, 100); columnLayout->addStretch(); // // Metric value and assign button // QLabel* valueLabel = new QLabel("New Value "); metricValueDoubleSpinBox = new QDoubleSpinBox; metricValueDoubleSpinBox->setMinimum(-std::numeric_limits::max()); metricValueDoubleSpinBox->setMaximum(std::numeric_limits::max()); metricValueDoubleSpinBox->setSingleStep(1.0); metricValueDoubleSpinBox->setDecimals(3); metricValueDoubleSpinBox->setFixedWidth(150); metricValueDoubleSpinBox->setValue(0.0); QPushButton* assignMetricPushButton = new QPushButton("Assign Metric"); assignMetricPushButton->setFixedSize(assignMetricPushButton->sizeHint()); assignMetricPushButton->setAutoDefault(false); QObject::connect(assignMetricPushButton, SIGNAL(clicked()), this, SLOT(slotAssignMetricToNodes())); QHBoxLayout* assignLayout = new QHBoxLayout; assignLayout->addWidget(valueLabel); assignLayout->addWidget(metricValueDoubleSpinBox); assignLayout->addWidget(new QLabel(" ")); assignLayout->addWidget(assignMetricPushButton); assignLayout->addStretch(); // // layout metric page // operationAssignMetricWidget = new QWidget; QVBoxLayout* metricLayout = new QVBoxLayout(operationAssignMetricWidget); metricLayout->setSpacing(3); metricLayout->addLayout(columnLayout); metricLayout->addLayout(assignLayout); metricLayout->addStretch(); } /** * Called to assign metrics for a node. */ void GuiSurfaceRegionOfInterestDialogOLD::slotAssignMetricToNodes() { BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); if (surfaceROI->anyNodesSelected() == false) { QMessageBox::critical(this, "Error: no nodes in ROI", "There are no nodes in the region of interest."); return; } const int numNodes = theMainWindow->getBrainSet()->getNumberOfNodes(); MetricFile* mf = theMainWindow->getBrainSet()->getMetricFile(); int metricColumn = metricColumnAssignComboBox->currentIndex(); if (metricColumn == GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NEW) { if (mf->getNumberOfColumns() == 0) { mf->setNumberOfNodesAndColumns(numNodes, 1); } else { mf->addColumns(1); } metricColumn = mf->getNumberOfColumns() - 1; } if ((metricColumn < 0) || (metricColumn >= mf->getNumberOfColumns())) { QMessageBox::critical(this, "Invalid metric column", "An invalid metric column is selected."); return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); // // Set column name // mf->setColumnName(metricColumn, metricColumnAssignNameLineEdit->text()); // // Assign the metric index to the nodes // const float value = metricValueDoubleSpinBox->value(); for (int i = 0; i < numNodes; i++) { if (surfaceROI->getNodeSelected(i)) { mf->setValue(i, metricColumn, value); } } // // Metric File has changed // GuiFilesModified fm; fm.setMetricModified(); theMainWindow->fileModificationUpdate(fm); // // Update node colors and redraw // theMainWindow->getBrainSet()->getNodeColoring()->assignColors(); GuiBrainModelOpenGL::updateAllGL(NULL); // // Save assigned column // metricColumnAssignComboBox->setCurrentIndex(metricColumn); QApplication::restoreOverrideCursor(); theMainWindow->speakText("Metric assignments to nodes are complete.", false); } /** * create the border from ROI. */ void GuiSurfaceRegionOfInterestDialogOLD::createOperationsBordersFromROI() { // // Border info widgets // QPushButton* borderNamePushButton = new QPushButton("Name..."); borderNamePushButton->setAutoDefault(false); borderNamePushButton->setFixedSize(borderNamePushButton->sizeHint()); QObject::connect(borderNamePushButton, SIGNAL(clicked()), this, SLOT(slotCreateBorderFromROINamePushButton())); createBorderFromROINameLineEdit = new QLineEdit; createBorderFromROINameLineEdit->setMaximumWidth(250); QLabel* densityLabel = new QLabel("Sampling Density"); createBorderFromROISamplingDensityDoubleSpinBox = new QDoubleSpinBox; createBorderFromROISamplingDensityDoubleSpinBox->setMinimum(0.01); createBorderFromROISamplingDensityDoubleSpinBox->setMaximum(100000.0); createBorderFromROISamplingDensityDoubleSpinBox->setSingleStep(1.0); createBorderFromROISamplingDensityDoubleSpinBox->setDecimals(2); createBorderFromROISamplingDensityDoubleSpinBox->setValue(2.0); createBorderFromROISamplingDensityDoubleSpinBox->setMaximumWidth(100); // // Border info group box and layout // QGroupBox* borderGroupBox = new QGroupBox("Border Information"); QGridLayout* borderGroupLayout = new QGridLayout(borderGroupBox); borderGroupLayout->addWidget(borderNamePushButton, 0, 0); borderGroupLayout->addWidget(createBorderFromROINameLineEdit, 0, 1); borderGroupLayout->addWidget(densityLabel, 0, 2); borderGroupLayout->addWidget(createBorderFromROISamplingDensityDoubleSpinBox, 0, 3); // // Node selection options // createBorderFromROIAutomaticRadioButton = new QRadioButton("Automatic"); createBorderFromROIManualRadioButton = new QRadioButton("Manual"); QLabel* startNodeLabel = new QLabel("Start Node"); QLabel* endNodeLabel = new QLabel("End Node"); createBorderFromROIStartNodeSpinBox = new QSpinBox; createBorderFromROIStartNodeSpinBox->setMinimum(0); createBorderFromROIStartNodeSpinBox->setMaximum(std::numeric_limits::max()); createBorderFromROIStartNodeSpinBox->setSingleStep(1); createBorderFromROIEndNodeSpinBox = new QSpinBox; createBorderFromROIEndNodeSpinBox->setMinimum(-1); createBorderFromROIEndNodeSpinBox->setMaximum(std::numeric_limits::max()); createBorderFromROIEndNodeSpinBox->setSingleStep(1); // // Select start/end nodes with mouse push buttons // QPushButton* selectStartNodeWithMousePushButton = new QPushButton("Select with Mouse"); selectStartNodeWithMousePushButton->setAutoDefault(false); selectStartNodeWithMousePushButton->setFixedSize(selectStartNodeWithMousePushButton->sizeHint()); QObject::connect(selectStartNodeWithMousePushButton, SIGNAL(clicked()), this, SLOT(slotCreateBorderFromROIStartNodePushButton())); QPushButton* selectEndNodeWithMousePushButton = new QPushButton("Select with Mouse"); selectEndNodeWithMousePushButton->setAutoDefault(false); selectEndNodeWithMousePushButton->setFixedSize(selectEndNodeWithMousePushButton->sizeHint()); QObject::connect(selectEndNodeWithMousePushButton, SIGNAL(clicked()), this, SLOT(slotCreateBorderFromROIEndNodePushButton())); // // Button group to keep radio buttons mutually exclusive // QButtonGroup* buttGroup = new QButtonGroup; buttGroup->addButton(createBorderFromROIAutomaticRadioButton); buttGroup->addButton(createBorderFromROIManualRadioButton); // // Layout for node selection options // createBorderFromROINodeSelectionWidget = new QWidget; QGridLayout* nodeNumbersLayout = new QGridLayout(createBorderFromROINodeSelectionWidget); nodeNumbersLayout->addWidget(startNodeLabel, 0, 0); nodeNumbersLayout->addWidget(createBorderFromROIStartNodeSpinBox, 0, 1); nodeNumbersLayout->addWidget(selectStartNodeWithMousePushButton, 0, 2); nodeNumbersLayout->addWidget(endNodeLabel, 1, 0); nodeNumbersLayout->addWidget(createBorderFromROIEndNodeSpinBox, 1, 1); nodeNumbersLayout->addWidget(selectEndNodeWithMousePushButton, 1, 2); QGroupBox* nodeSelectionGroupBox = new QGroupBox("Starting and Ending Node Selection"); QGridLayout* nodeSelectionLayout = new QGridLayout(nodeSelectionGroupBox); nodeSelectionLayout->addWidget(createBorderFromROIAutomaticRadioButton, 0, 0); nodeSelectionLayout->addWidget(createBorderFromROIManualRadioButton, 1, 0); nodeSelectionLayout->addWidget(createBorderFromROINodeSelectionWidget, 1, 1); // // Connect signals to disable node selection if automatic // createBorderFromROINodeSelectionWidget->setEnabled(false); QObject::connect(createBorderFromROIManualRadioButton, SIGNAL(toggled(bool)), createBorderFromROINodeSelectionWidget, SLOT(setEnabled(bool))); createBorderFromROIAutomaticRadioButton->setChecked(true); // // Create border push button // QPushButton* createBorderPushButton = new QPushButton("Create Border Along Sulcus Using Geodesic"); createBorderPushButton->setAutoDefault(false); createBorderPushButton->setFixedSize(createBorderPushButton->sizeHint()); QObject::connect(createBorderPushButton, SIGNAL(clicked()), this, SLOT(slotCreateBorderFromROIPushButton())); // // Widget and layout for panel // operationCreateBordersFromROIWidget = new QWidget; QVBoxLayout* layout = new QVBoxLayout(operationCreateBordersFromROIWidget); layout->addWidget(borderGroupBox); layout->addWidget(nodeSelectionGroupBox, 0, Qt::AlignLeft); layout->addWidget(createBorderPushButton); layout->addStretch(); } /** * called to select start node for border from ROI. */ void GuiSurfaceRegionOfInterestDialogOLD::slotCreateBorderFromROIStartNodePushButton() { theMainWindow->getBrainModelOpenGL()->setMouseMode( GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_SULCAL_BORDER_NODE_START); } /** * called to select start node for border from ROI. */ void GuiSurfaceRegionOfInterestDialogOLD::slotCreateBorderFromROIEndNodePushButton() { theMainWindow->getBrainModelOpenGL()->setMouseMode( GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_SULCAL_BORDER_NODE_END); } /** * set open border start node. */ void GuiSurfaceRegionOfInterestDialogOLD::setCreateBorderOpenStartNode(const int nodeNumber) { BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); if (surfaceROI->getNodeSelected(nodeNumber)) { createBorderFromROIStartNodeSpinBox->setValue(nodeNumber); } else { QMessageBox::critical(this, "ERROR", "Node selected is not in the ROI."); } } /** * set open border end node. */ void GuiSurfaceRegionOfInterestDialogOLD::setCreateBorderOpenEndNode(const int nodeNumber) { BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); if (surfaceROI->getNodeSelected(nodeNumber)) { createBorderFromROIEndNodeSpinBox->setValue(nodeNumber); } else { QMessageBox::critical(this, "ERROR", "Node selected is not in the ROI."); } } /** * called to set name of borer for border from ROI. */ void GuiSurfaceRegionOfInterestDialogOLD::slotCreateBorderFromROINamePushButton() { static GuiNameSelectionDialog::LIST_ITEMS_TYPE itemForDisplay = GuiNameSelectionDialog::LIST_BORDER_COLORS_ALPHA; GuiNameSelectionDialog nsd(this, GuiNameSelectionDialog::LIST_ALL, itemForDisplay); if (nsd.exec() == QDialog::Accepted) { createBorderFromROINameLineEdit->setText(nsd.getNameSelected()); } } /** * called to create a border from the ROI. */ void GuiSurfaceRegionOfInterestDialogOLD::slotCreateBorderFromROIPushButton() { // // Create the border from the ROI // BrainModelSurface* operationSurface = operationSurfaceComboBox->getSelectedBrainModelSurface(); const QString borderName(createBorderFromROINameLineEdit->text()); int startNode = -1; int endNode = -1; if (createBorderFromROIManualRadioButton->isChecked()) { startNode = createBorderFromROIStartNodeSpinBox->value(); endNode = createBorderFromROIEndNodeSpinBox->value(); } BrainModelSurfaceROICreateBorderUsingGeodesic roi(theMainWindow->getBrainSet(), operationSurface, theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(), borderName, startNode, endNode, createBorderFromROISamplingDensityDoubleSpinBox->value()); try { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); roi.execute(); QApplication::restoreOverrideCursor(); } catch (BrainModelAlgorithmException& e) { QMessageBox::critical(this, "ERROR", e.whatQString()); return; } // // Get border created and display it // Border border = roi.getBorder(); if (border.getNumberOfLinks() <= 0) { QMessageBox::critical(this, "ERROR", "Border created has no links."); return; } // // Find the matching color // bool borderColorMatch = false; BorderColorFile* borderColorFile = theMainWindow->getBrainSet()->getBorderColorFile(); int borderColorIndex = borderColorFile->getColorIndexByName(borderName, borderColorMatch); // // Border color may need to be created // bool createBorderColor = false; if ((borderColorIndex >= 0) && (borderColorMatch == true)) { createBorderColor = false; } else if ((borderColorIndex >= 0) && (borderColorMatch == false)) { QString msg("Use border color \""); msg.append(borderColorFile->getColorNameByIndex(borderColorIndex)); msg.append("\" for border "); msg.append(borderName); msg.append(" ?"); QString noButton("No, define color "); noButton.append(borderName); QMessageBox msgBox(this); msgBox.setWindowTitle("Use Partially Matching Color"); msgBox.setText(msg); msgBox.addButton("Yes", QMessageBox::YesRole); QPushButton* defineColorPushButton = msgBox.addButton(noButton, QMessageBox::NoRole); msgBox.exec(); if (msgBox.clickedButton() == defineColorPushButton) { createBorderColor = true; } } else { createBorderColor = true; } if (createBorderColor) { QString title("Create Border Color: "); title.append(borderName); QApplication::beep(); GuiColorSelectionDialog* csd = new GuiColorSelectionDialog(this, title, false, false, false, false); csd->exec(); // // Add new border color // float pointSize = 2.0, lineSize = 1.0; unsigned char r, g, b, a; ColorFile::ColorStorage::SYMBOL symbol; csd->getColorInformation(r, g, b, a, pointSize, lineSize, symbol); borderColorFile->addColor(borderName, r, g, b, a, pointSize, lineSize, symbol); borderColorIndex = borderColorFile->getNumberOfColors() - 1; } // // Add border // BrainModelBorder* b = new BrainModelBorder(theMainWindow->getBrainSet(), &border, operationSurface->getSurfaceType()); BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); bmbs->addBorder(b); // // Project the border // const int borderNumber = bmbs->getNumberOfBorders() - 1; if (borderNumber >= 0) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); bmbs->projectBorders(operationSurface, true, borderNumber, borderNumber); QApplication::restoreOverrideCursor(); } // // Display borders // DisplaySettingsBorders* dsb = theMainWindow->getBrainSet()->getDisplaySettingsBorders(); dsb->setDisplayBorders(true); // // Files have changed // GuiFilesModified fm; fm.setBorderColorModified(); fm.setBorderModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } /** * create the borders around clusters operation section */ void GuiSurfaceRegionOfInterestDialogOLD::createOperationsBordersAroundClusters() { // // border to assign // QPushButton* clusterNamePushButton = new QPushButton("Border Name..."); clusterNamePushButton->setAutoDefault(false); clusterNamePushButton->setFixedSize(clusterNamePushButton->sizeHint()); QObject::connect(clusterNamePushButton, SIGNAL(clicked()), this, SLOT(slotBorderClusterNamePushButton())); clusterBorderNameLineEdit = new QLineEdit; clusterBorderNameLineEdit->setFixedWidth(250); QHBoxLayout* borderNameLayout = new QHBoxLayout; borderNameLayout->addWidget(clusterNamePushButton); borderNameLayout->addWidget(clusterBorderNameLineEdit); borderNameLayout->addStretch(); // // Auto project borders // clusterBorderAutoProjectCheckBox = new QCheckBox("Auto Project"); clusterBorderAutoProjectCheckBox->setChecked(true); // // create borders push button // QPushButton* createBordersPushButton = new QPushButton("Create Borders Around Clusters"); createBordersPushButton->setFixedSize(createBordersPushButton->sizeHint()); createBordersPushButton->setAutoDefault(false); QObject::connect(createBordersPushButton, SIGNAL(clicked()), this, SLOT(slotCreateBordersFromClusters())); operationCreateBordersFromClustersWidget = new QWidget; QVBoxLayout* layout = new QVBoxLayout(operationCreateBordersFromClustersWidget); layout->setSpacing(3); layout->addLayout(borderNameLayout); layout->addWidget(clusterBorderAutoProjectCheckBox); layout->addWidget(createBordersPushButton); layout->addStretch(); } /** * Called to set create borders from clusters name. */ void GuiSurfaceRegionOfInterestDialogOLD::slotBorderClusterNamePushButton() { GuiNameSelectionDialog nsd(this); if (nsd.exec() == QDialog::Accepted) { clusterBorderNameLineEdit->setText(nsd.getNameSelected()); } } /** * Called run create borders from clusters. */ void GuiSurfaceRegionOfInterestDialogOLD::slotCreateBordersFromClusters() { const QString borderName = clusterBorderNameLineEdit->text(); if (borderName.isEmpty()) { QMessageBox::critical(this, "ERROR", "Please enter a border name."); return; } BrainModelSurface* bms = operationSurfaceComboBox->getSelectedBrainModelSurface(); if (bms == NULL) { QMessageBox::critical(this, "ERROR", "Operation surface is invalid."); return; } //TopologyFile* topologyFile = topologyComboBox->getSelectedTopologyFile(); TopologyFile* topologyFile = bms->getTopologyFile(); if (topologyFile == NULL) { QMessageBox::critical(this, "ERROR", "Operation topology is invalid."); return; } int numberOfBordersCreated = 0; BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); try { BrainModelSurfaceClusterToBorderConverter scbc(theMainWindow->getBrainSet(), bms, topologyFile, borderName, surfaceROI, clusterBorderAutoProjectCheckBox->isChecked()); scbc.execute(); numberOfBordersCreated = scbc.getNumberOfBordersCreated(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); return; } QApplication::restoreOverrideCursor(); if (numberOfBordersCreated > 0) { std::ostringstream str; str << numberOfBordersCreated << " border(s) were created\n"; // // Find the matching color // bool borderColorMatch = false; BorderColorFile* borderColorFile = theMainWindow->getBrainSet()->getBorderColorFile(); const int borderColorIndex = borderColorFile->getColorIndexByName(borderName, borderColorMatch); // // Border color may need to be created // bool createBorderColor = false; if ((borderColorIndex >= 0) && (borderColorMatch == true)) { QMessageBox::information(this, "INFO", str.str().c_str()); createBorderColor = false; } else if ((borderColorIndex >= 0) && (borderColorMatch == false)) { str << "You may use border color \"" << borderColorFile->getColorNameByIndex(borderColorIndex).toAscii().constData() << "\" for border " << borderName.toAscii().constData() << "\"\n or define a new color."; QString b2("Use color "); b2.append(borderColorFile->getColorNameByIndex(borderColorIndex)); QString b1("Define color "); b1.append(borderName); QMessageBox msgBox(this); msgBox.setWindowTitle("Color"); msgBox.setText(str.str().c_str()); QPushButton* pb1 = msgBox.addButton(b1, QMessageBox::NoRole); msgBox.addButton(b2, QMessageBox::NoRole); msgBox.exec(); if (msgBox.clickedButton() == pb1) { createBorderColor = true; } } else { str << "There is no matching color for " << borderName.toAscii().constData() << "\n" << "Would you like to define the color " << borderName.toAscii().constData() << "?"; QString b1("Define color "); b1.append(borderName); QMessageBox msgBox(this); msgBox.setWindowTitle("Color"); msgBox.setText(str.str().c_str()); QPushButton* pb1 = msgBox.addButton(b1, QMessageBox::YesRole); msgBox.addButton("No", QMessageBox::NoRole); msgBox.exec(); if (msgBox.clickedButton() == pb1) { createBorderColor = true; } } if (createBorderColor) { QString title("Create Border Color: "); title.append(borderName); GuiColorSelectionDialog* csd = new GuiColorSelectionDialog(this, title, false, false, false, false); csd->exec(); // // Add new border color // float pointSize = 2.0, lineSize = 1.0; unsigned char r, g, b, a; ColorFile::ColorStorage::SYMBOL symbol; csd->getColorInformation(r, g, b, a, pointSize, lineSize, symbol); borderColorFile->addColor(borderName, r, g, b, a, pointSize, lineSize, symbol); } // // Display borders // theMainWindow->getBrainSet()->assignBorderColors(); DisplaySettingsBorders* dsb = theMainWindow->getBrainSet()->getDisplaySettingsBorders(); dsb->setDisplayBorders(true); // // Update GUI // GuiFilesModified fm; fm.setBorderColorModified(); fm.setBorderModified(); theMainWindow->fileModificationUpdate(fm); } else { QMessageBox::information(this, "INFO", "No clusters were found."); } GuiBrainModelOpenGL::updateAllGL(); } /** * create the assign surface shape operation section */ void GuiSurfaceRegionOfInterestDialogOLD::createOperationAssignSurfaceShape() { // // SurfaceShape column and new surface shape value // QLabel* surfaceShapeColumnLabel = new QLabel("Surface Shape Column "); surfaceShapeColumnAssignComboBox = new GuiNodeAttributeColumnSelectionComboBox( GUI_NODE_FILE_TYPE_SURFACE_SHAPE, true, false, false); surfaceShapeColumnAssignComboBox->setMaximumWidth(maxComboBoxWidth); surfaceShapeColumnAssignNameLineEdit = new QLineEdit; surfaceShapeColumnAssignNameLineEdit->setMinimumWidth(150); QObject::connect(surfaceShapeColumnAssignComboBox, SIGNAL(itemNameSelected(const QString&)), surfaceShapeColumnAssignNameLineEdit, SLOT(setText(const QString&))); surfaceShapeColumnAssignNameLineEdit->setText(surfaceShapeColumnAssignComboBox->getCurrentLabel()); QHBoxLayout* columnLayout = new QHBoxLayout; columnLayout->addWidget(surfaceShapeColumnLabel); columnLayout->addWidget(surfaceShapeColumnAssignComboBox); columnLayout->addWidget(surfaceShapeColumnAssignNameLineEdit); columnLayout->setStretchFactor(surfaceShapeColumnLabel, 0); //columnLayout->setStretchFactor(surfaceShapeColumnAssignComboBox, 100); columnLayout->setStretchFactor(surfaceShapeColumnAssignNameLineEdit, 0); columnLayout->addStretch(); // // Value to assign // QLabel* valueLabel = new QLabel("New Value "); surfaceShapeValueDoubleSpinBox = new QDoubleSpinBox; surfaceShapeValueDoubleSpinBox->setMinimum(-std::numeric_limits::max()); surfaceShapeValueDoubleSpinBox->setMaximum(std::numeric_limits::max()); surfaceShapeValueDoubleSpinBox->setSingleStep(1.0); surfaceShapeValueDoubleSpinBox->setDecimals(3); surfaceShapeValueDoubleSpinBox->setFixedWidth(150); surfaceShapeValueDoubleSpinBox->setValue(0.0); // // Assign surfaceShape push button // QPushButton* assignSurfaceShapePushButton = new QPushButton("Assign Surface Shape"); assignSurfaceShapePushButton->setFixedSize(assignSurfaceShapePushButton->sizeHint()); assignSurfaceShapePushButton->setAutoDefault(false); QObject::connect(assignSurfaceShapePushButton, SIGNAL(clicked()), this, SLOT(slotAssignSurfaceShapeToNodes())); // // assign layout // QHBoxLayout* assignLayout = new QHBoxLayout; assignLayout->addWidget(valueLabel); assignLayout->addWidget(surfaceShapeValueDoubleSpinBox); assignLayout->addWidget(new QLabel(" ")); assignLayout->addWidget(assignSurfaceShapePushButton); assignLayout->addStretch(); // // layout for page // operationAssignSurfaceShapeWidget = new QWidget; QVBoxLayout* layout = new QVBoxLayout(operationAssignSurfaceShapeWidget); layout->setSpacing(3); layout->addLayout(columnLayout); layout->addLayout(assignLayout); layout->addStretch(); } /** * Called to assign surfaceShape for a node. */ void GuiSurfaceRegionOfInterestDialogOLD::slotAssignSurfaceShapeToNodes() { BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); if (surfaceROI->anyNodesSelected() == false) { QMessageBox::critical(this, "Error: no nodes in ROI", "There are no nodes in the region of interest."); return; } const int numNodes = theMainWindow->getBrainSet()->getNumberOfNodes(); SurfaceShapeFile* ssf = theMainWindow->getBrainSet()->getSurfaceShapeFile(); int surfaceShapeColumn = surfaceShapeColumnAssignComboBox->currentIndex(); if (surfaceShapeColumn == GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NEW) { if (ssf->getNumberOfColumns() == 0) { ssf->setNumberOfNodesAndColumns(numNodes, 1); } else { ssf->addColumns(1); } surfaceShapeColumn = ssf->getNumberOfColumns() - 1; } if ((surfaceShapeColumn < 0) || (surfaceShapeColumn >= ssf->getNumberOfColumns())) { QMessageBox::critical(this, "Invalid surface shape column", "An invalid surface shape column is selected."); return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); // // Assign the surface shape index to the nodes // const float value = surfaceShapeValueDoubleSpinBox->value(); for (int i = 0; i < numNodes; i++) { if (surfaceROI->getNodeSelected(i)) { ssf->setValue(i, surfaceShapeColumn, value); } } // // SurfaceShape File has changed // GuiFilesModified fm; fm.setSurfaceShapeModified(); theMainWindow->fileModificationUpdate(fm); // // Update node colors and redraw // theMainWindow->getBrainSet()->getNodeColoring()->assignColors(); GuiBrainModelOpenGL::updateAllGL(NULL); // // Save assigned column // surfaceShapeColumnAssignComboBox->setCurrentIndex(surfaceShapeColumn); QApplication::restoreOverrideCursor(); theMainWindow->speakText("Surface Shape assignments to nodes are complete.", false); } /** * create the assign paint operation section */ void GuiSurfaceRegionOfInterestDialogOLD::createOperationAssignPaint() { // // Paint column and new paint column name // QLabel* paintColumnLabel = new QLabel("Paint Column "); paintColumnAssignComboBox = new GuiNodeAttributeColumnSelectionComboBox( GUI_NODE_FILE_TYPE_PAINT, true, false, false); QObject::connect(paintColumnAssignComboBox, SIGNAL(itemSelected(int)), this, SLOT(slotAssignPaintColumn(int))); paintColumnAssignComboBox->setMaximumWidth(maxComboBoxWidth); paintColumnAssignNameLineEdit = new QLineEdit; paintColumnAssignNameLineEdit->setMinimumWidth(150); // // layout for column widgets // QHBoxLayout* columnLayout = new QHBoxLayout; columnLayout->addWidget(paintColumnLabel); columnLayout->addWidget(paintColumnAssignComboBox); columnLayout->addWidget(paintColumnAssignNameLineEdit); columnLayout->setStretchFactor(paintColumnLabel, 0); //columnLayout->setStretchFactor(paintColumnAssignComboBox, 100); columnLayout->setStretchFactor(paintColumnAssignNameLineEdit, 0); columnLayout->addStretch(); slotAssignPaintColumn(paintColumnAssignComboBox->currentIndex()); // // Paint name for assignment // QLabel* paintNameLabel = new QLabel("Paint Name "); paintAssignNameLineEdit = new QLineEdit; paintAssignNameLineEdit->setMinimumWidth(250); // // Assignment layout // QHBoxLayout* assignLayout = new QHBoxLayout; assignLayout->addWidget(paintNameLabel); assignLayout->addWidget(paintAssignNameLineEdit); //assignLayout->setStretchFactor(paintNameLabel, 0); //assignLayout->setStretchFactor(paintAssignNameLineEdit, 100); assignLayout->addStretch(); // // Assign paint push button // QPushButton* assignPaintPushButton = new QPushButton("Assign Paint"); assignPaintPushButton->setFixedSize(assignPaintPushButton->sizeHint()); assignPaintPushButton->setAutoDefault(false); QObject::connect(assignPaintPushButton, SIGNAL(clicked()), this, SLOT(slotAssignPaintToNodes())); operationAssignPaintWidget = new QWidget; QVBoxLayout* layout = new QVBoxLayout(operationAssignPaintWidget); layout->setSpacing(3); layout->addLayout(columnLayout); layout->addLayout(assignLayout); layout->addWidget(assignPaintPushButton); layout->addStretch(); } /** * Called to assign paint IDs to nodes. */ void GuiSurfaceRegionOfInterestDialogOLD::slotAssignPaintToNodes() { BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); if (surfaceROI->anyNodesSelected() == false) { QMessageBox::critical(this, "Error: no nodes in ROI", "There are no nodes in the region of interest."); return; } const int numNodes = theMainWindow->getBrainSet()->getNumberOfNodes(); PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); int paintColumn = paintColumnAssignComboBox->currentIndex(); if (paintColumn == GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NEW) { if (pf->getNumberOfColumns() == 0) { pf->setNumberOfNodesAndColumns(numNodes, 1); } else { pf->addColumns(1); } paintColumn = pf->getNumberOfColumns() - 1; } if ((paintColumn < 0) || (paintColumn >= pf->getNumberOfColumns())) { QMessageBox::critical(this, "Invalid paint column", "An invalid paint column is selected."); return; } const QString paintName(paintAssignNameLineEdit->text()); if (paintName.isEmpty()) { QMessageBox::critical(this, "No Paint Name", "The name for the paint is empty."); return; } // // Set the name of the paint column // pf->setColumnName(paintColumn, paintColumnAssignNameLineEdit->text()); AreaColorFile* cf = theMainWindow->getBrainSet()->getAreaColorFile(); bool areaColorMatch = false; int areaColorIndex = cf->getColorIndexByName(paintName, areaColorMatch); // area color may need to be created // bool createAreaColor = false; if ((areaColorIndex >= 0) && (areaColorMatch == true)) { createAreaColor = false; } else if ((areaColorIndex >= 0) && (areaColorMatch == false)) { QString msg("Use area color \""); msg.append(cf->getColorNameByIndex(areaColorIndex)); msg.append("\" for paint "); msg.append(paintName); msg.append(" ?"); QString noButton("No, define color "); noButton.append(paintName); QMessageBox msgBox(this); msgBox.setWindowTitle("Use Partially Matching Color"); msgBox.setText(msg); msgBox.addButton("Yes", QMessageBox::YesRole); QPushButton* noPushButton = msgBox.addButton(noButton, QMessageBox::NoRole); msgBox.exec(); if (msgBox.clickedButton() == noPushButton) { createAreaColor = true; } } else { createAreaColor = true; } if (createAreaColor) { QString title("Create Area Color: "); title.append(paintName); GuiColorSelectionDialog* csd = new GuiColorSelectionDialog(this, title, false, false, false, false); csd->exec(); // // Add new area color // float pointSize = 2.0, lineSize = 1.0; unsigned char r, g, b, a; ColorFile::ColorStorage::SYMBOL symbol; csd->getColorInformation(r, g, b, a, pointSize, lineSize, symbol); cf->addColor(paintName, r, g, b, a, pointSize, lineSize, symbol); areaColorIndex = cf->getNumberOfColors() - 1; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); // // add or get index of paint name // const int paintIndex = pf->addPaintName(paintName); // // Assign the paint index to the nodes // for (int i = 0; i < numNodes; i++) { if (surfaceROI->getNodeSelected(i)) { pf->setPaint(i, paintColumn, paintIndex); } } // // Node Color File has changed // GuiFilesModified fm; fm.setPaintModified(); if (createAreaColor) { fm.setAreaColorModified(); } theMainWindow->fileModificationUpdate(fm); // // Update node colors and redraw // theMainWindow->getBrainSet()->getNodeColoring()->assignColors(); GuiBrainModelOpenGL::updateAllGL(NULL); // // Save assigned column // paintColumnAssignComboBox->setCurrentIndex(paintColumn); slotAssignPaintColumn(paintColumn); QApplication::restoreOverrideCursor(); theMainWindow->speakText("Paint assignments to nodes are complete.", false); } /** * Called when an assign paint column is selected. */ void GuiSurfaceRegionOfInterestDialogOLD::slotAssignPaintColumn(int item) { paintColumnAssignNameLineEdit->setText("New Column Name"); PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); if ((item >= 0) && (item < pf->getNumberOfColumns())) { paintColumnAssignNameLineEdit->setText(pf->getColumnName(item)); } } /** * create the create volume ROI operation section */ void GuiSurfaceRegionOfInterestDialogOLD::createOperationCreateVolumeROI() { QPushButton* createVolumeFromQueryNodesPushButton = new QPushButton( "Create Volume From Displayed Query Nodes..."); createVolumeFromQueryNodesPushButton->setAutoDefault(false); createVolumeFromQueryNodesPushButton->setFixedSize(createVolumeFromQueryNodesPushButton->sizeHint()); QObject::connect(createVolumeFromQueryNodesPushButton, SIGNAL(clicked()), this, SLOT(slotCreateVolumeFromQueryNodesButton())); operationCreateVolumeRoiWidget = new QWidget; QVBoxLayout* layout = new QVBoxLayout(operationCreateVolumeRoiWidget); layout->addWidget(createVolumeFromQueryNodesPushButton); layout->addStretch(); } /** * create the prob atlas operation section */ void GuiSurfaceRegionOfInterestDialogOLD::createOperationProbAtlas() { QPushButton* createReportPushButton = new QPushButton("Create Report"); createReportPushButton->setAutoDefault(false); createReportPushButton->setFixedSize(createReportPushButton->sizeHint()); QObject::connect(createReportPushButton, SIGNAL(clicked()), this, SLOT(slotCreateProbAtlasReport())); probAtlasTabSeparateCheckBox = new QCheckBox("Separate Report With Semicolons (for import to spreadsheet)"); operationProbAtlasWidget = new QWidget; QVBoxLayout* layout = new QVBoxLayout(operationProbAtlasWidget);; layout->addWidget(createReportPushButton); layout->addWidget(probAtlasTabSeparateCheckBox); layout->addStretch(); } /** * Called to create the prob atlas report. */ void GuiSurfaceRegionOfInterestDialogOLD::slotCreateProbAtlasReport() { BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); ProbabilisticAtlasFile* pf = theMainWindow->getBrainSet()->getProbabilisticAtlasSurfaceFile(); const int numNodes = pf->getNumberOfNodes(); const int numCols = pf->getNumberOfColumns(); if ((numNodes <= 0) || (numCols <= 0)) { QMessageBox::critical(this, "ERROR", "The Probabilistic Atlas File is Empty."); return; } const int numNames = pf->getNumberOfPaintNames(); if (numNames <= 0) { QMessageBox::critical(this, "ERROR", "No names in Probabilistic Atlas File."); } float roiArea = 0.0; if (createReportHeader("Probabilistic Atlas Analysis", false, roiArea)) { return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); QString blankTab(" "); const bool useTabs = probAtlasTabSeparateCheckBox->isChecked(); if (useTabs) { blankTab = separatorCharacter; } const int numNodesSelected = surfaceROI->getNumberOfNodesSelected(); const int countCols = numCols + 1; int* counts = new int[countCols]; // // Sort the paint names // std::vector indices; std::vector names; for (int i = 0; i < numNames; i++) { indices.push_back(i); names.push_back(pf->getPaintNameFromIndex(i)); } NameIndexSort sortNames(indices, names); if (useTabs) { std::ostringstream str; str << "Name "; for (int j = 0; j < countCols; j++) { str << blankTab.toAscii().constData() << j; } reportTextEdit->append(str.str().c_str()); } // // Loop through paint names // for (int m = 0; m < numNames; m++) { // // Get the paint name and index // int indx = -1; QString name; sortNames.getSortedNameAndIndex(m, indx, name); // // Clear counts // for (int j = 0; j < countCols; j++) { counts[j] = 0; } // // Find nodes using paint // for (int i = 0; i < numNodes; i++) { if (surfaceROI->getNodeSelected(i)) { int cnt = 0; for (int j = 0; j < numCols; j++) { if (pf->getPaint(i, j) == indx) { cnt++; } } counts[cnt]++; } } std::ostringstream str; str.precision(2); if (useTabs) { str << name.toAscii().constData(); for (int j = 0; j < countCols; j++) { str << blankTab.toAscii().constData() << counts[j]; } } else { reportTextEdit->append(name); str << blankTab.toAscii().constData(); for (int j = 0; j < countCols; j++) { str << counts[j] << " with " << j << " entries "; } } reportTextEdit->append(str.str().c_str()); str.str(""); str.setf(std::ios::fixed); if (useTabs) { str << " "; for (int j = 0; j < countCols; j++) { const float pct = (static_cast(counts[j]) / static_cast(numNodesSelected)) * 100.0; str << blankTab.toAscii().constData() << pct; } } else { str << blankTab.toAscii().constData(); for (int j = 0; j < countCols; j++) { const float pct = (static_cast(counts[j]) / static_cast(numNodesSelected)) * 100.0; str << pct << "% with " << j << " entries "; } } reportTextEdit->append(str.str().c_str()); reportTextEdit->append(" "); } delete[] counts; /* SurfaceShapeFile* ssf = theMainWindow->getBrainSet()->getSurfaceShapeFile(); std::vector coefficients; const int column = shapeCorrelationColumnComboBox->currentIndex(); if (column == GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_ALL) { const int lastColumn = ssf->getNumberOfColumns() - 1; std::ostringstream str; for (int j = 0; j < ssf->getNumberOfColumns(); j++) { str << ssf->getColumnName(j); if (j != lastColumn) { str << blankTab; } } reportTextEdit->append(str.str().c_str()); for (int j = 0; j < ssf->getNumberOfColumns(); j++) { ssf->correlationCoefficient(j, coefficients, &nodeInROI); std::ostringstream str; str.setf(std::ios::fixed); for (int i = 0; i < ssf->getNumberOfColumns(); i++) { str << coefficients[i]; if (i != lastColumn) { str << blankTab; } } reportTextEdit->append(str.str().c_str()); } } else { ssf->correlationCoefficient(column, coefficients, &nodeInROI); std::ostringstream str; str.setf(std::ios::fixed); str << "\n" << "Correlation for " << ssf->getColumnName(column); reportTextEdit->append(str.str().c_str()); for (int i = 0; i < ssf->getNumberOfColumns(); i++) { str.str(""); str << (i + 1) << blankTab << ssf->getColumnName(i) << blankTab << coefficients[i]; reportTextEdit->append(str.str().c_str()); } } */ // // Swith to report page // tabWidget->setCurrentWidget(reportPage); QApplication::beep(); QApplication::restoreOverrideCursor(); theMainWindow->speakText("The report is ready.", false); } /** * create the disconnect nodes operation section */ void GuiSurfaceRegionOfInterestDialogOLD::createOperationDisconnectNodes() { QPushButton* disconnectButton = new QPushButton("Disconnect Selected Nodes"); disconnectButton->setAutoDefault(false); disconnectButton->setFixedSize(disconnectButton->sizeHint()); QObject::connect(disconnectButton, SIGNAL(clicked()), this, SLOT(slotDisconnectNodes())); operationDisconnectNodesWidget = new QWidget; QVBoxLayout* layout = new QVBoxLayout(operationDisconnectNodesWidget); layout->addWidget(disconnectButton); layout->addStretch(); } /** * create the surface shape correlation coefficient section. */ void GuiSurfaceRegionOfInterestDialogOLD::createShapeClusterReport() { QLabel* metricArealDistortionLabel = new QLabel("Metric Areal Distortion"); shapeClusterMetricArealDistortionComboBox = new GuiNodeAttributeColumnSelectionComboBox(GUI_NODE_FILE_TYPE_METRIC, false, false, false); QHBoxLayout* arealDistLayout = new QHBoxLayout; arealDistLayout->addWidget(metricArealDistortionLabel); arealDistLayout->addWidget(shapeClusterMetricArealDistortionComboBox); arealDistLayout->addStretch(); QLabel* threshLabel = new QLabel("Threshold "); shapeClusterThresholdDoubleSpinBox = new QDoubleSpinBox; shapeClusterThresholdDoubleSpinBox->setMinimum(-10000.0); shapeClusterThresholdDoubleSpinBox->setMaximum( 10000.0); shapeClusterThresholdDoubleSpinBox->setSingleStep(1.0); shapeClusterThresholdDoubleSpinBox->setDecimals(3); QHBoxLayout* threshLayout = new QHBoxLayout; threshLayout->addWidget(threshLabel); threshLayout->addWidget(shapeClusterThresholdDoubleSpinBox); threshLayout->addStretch(); shapeClusterTabSeparateCheckBox = new QCheckBox("Separate Report With Semicolons"); QPushButton* createClusterReportPushButton = new QPushButton("Create Cluster Report"); createClusterReportPushButton->setFixedSize(createClusterReportPushButton->sizeHint()); createClusterReportPushButton->setAutoDefault(false); QObject::connect(createClusterReportPushButton, SIGNAL(clicked()), this, SLOT(slotShapeClusterReport())); operationShapeClusterWidget = new QWidget; QVBoxLayout* layout = new QVBoxLayout(operationShapeClusterWidget); layout->addLayout(arealDistLayout); layout->addLayout(threshLayout); layout->addWidget(shapeClusterTabSeparateCheckBox); layout->addWidget(createClusterReportPushButton); layout->addStretch(); } /** * Called to create shape correlation report. */ void GuiSurfaceRegionOfInterestDialogOLD::slotShapeClusterReport() { BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); if (surfaceROI->anyNodesSelected() == false) { QMessageBox::critical(this, "Error: no nodes in ROI", "There are no nodes in the region of interest."); return; } SurfaceShapeFile* ssf = theMainWindow->getBrainSet()->getSurfaceShapeFile(); const int numNodes = ssf->getNumberOfNodes(); if (numNodes <= 0) { QMessageBox::critical(this, "ERROR", "The surface shape file is empty."); return; } BrainModelSurface* bms = operationSurfaceComboBox->getSelectedBrainModelSurface(); if (bms == NULL) { QMessageBox::critical(this, "ERROR", "There is no selected surface."); return; } // // Metric column for area correction // int metricColumn = -1; const MetricFile* mf = theMainWindow->getBrainSet()->getMetricFile(); if (mf->empty() == false) { metricColumn = shapeClusterMetricArealDistortionComboBox->currentIndex(); QString msg("Areal Distortion Correction using metric column:\n "); msg.append(mf->getColumnName(metricColumn)); if (QMessageBox::information(this, "INFO", msg, (QMessageBox::Ok | QMessageBox::Cancel), QMessageBox::Ok) == QMessageBox::Cancel) { return; } } else { const QString msg("No metric column for distortion correction is loaded."); if (QMessageBox::information(this, "INFO", msg, (QMessageBox::Ok | QMessageBox::Cancel), QMessageBox::Ok) == QMessageBox::Cancel) { return; } } float roiArea = 0.0; QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); if (createReportHeader("", shapeClusterTabSeparateCheckBox->isChecked(), roiArea)) { return; } std::ostringstream str1; str1 << "Surface Shape File: " << FileUtilities::basename(ssf->getFileName()).toAscii().constData() << "\n"; if ((mf != NULL ) && (metricColumn >= 0)) { str1 << "Metric File: " << FileUtilities::basename(mf->getFileName()).toAscii().constData() << "\n" << "Metric Column " << mf->getColumnName(metricColumn).toAscii().constData() << "\n"; } str1 << "\n"; reportTextEdit->append(str1.str().c_str()); QString blankTab(" "); if (shapeClusterTabSeparateCheckBox->isChecked()) { blankTab = separatorCharacter; } // // Report header // std::ostringstream str; str << "Threshold" << blankTab.toAscii().constData() << "Column" << blankTab.toAscii().constData() << "Num-Nodes" << blankTab.toAscii().constData() << "Area " << blankTab.toAscii().constData() << "Area Corrected" << blankTab.toAscii().constData() << "COG-X" << blankTab.toAscii().constData() << "COG-Y" << blankTab.toAscii().constData() << "COG-Z"; reportTextEdit->append(str.str().c_str()); float posMin = 0.0; float posMax = 0.0; float negMin = 0.0; float negMax = 0.0; const float thresh = shapeClusterThresholdDoubleSpinBox->value(); if (thresh >= 0.0) { posMin = thresh; posMax = std::numeric_limits::max(); negMin = -1.0; negMax = 0.0; } else { posMin = 1.0; posMax = 0.0; negMin = thresh; negMax = -std::numeric_limits::max(); } // // Process each column // const int numColumns = ssf->getNumberOfColumns(); for (int i = 0; i < numColumns; i++) { // // Ignore deselected shape columns // if (i < static_cast(surfaceShapeCheckBoxes.size())) { if (surfaceShapeCheckBoxes[i]->isChecked() == false) { continue; } } if (DebugControl::getDebugOn()) { std::cout << "Cluster analysis for column: " << i << std::endl; } // // Create a shape file containing just the single column // SurfaceShapeFile tempShapeFile; tempShapeFile.setNumberOfNodesAndColumns(numNodes, 1); std::vector nodeValues; ssf->getColumnForAllNodes(i, nodeValues); tempShapeFile.setColumnForAllNodes(0, nodeValues); // // Find the clusters // BrainModelSurfaceMetricClustering bmsmc(theMainWindow->getBrainSet(), bms, &tempShapeFile, BrainModelSurfaceMetricClustering::CLUSTER_ALGORITHM_MINIMUM_SURFACE_AREA, 0, 0, "cluster", 1, 0.001, negMin, negMax, posMin, posMax, true); try { bmsmc.execute(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); return; } // // Node areas // std::vector nodeAreas; bms->getAreaOfAllNodes(nodeAreas); // // Process the clusters // const int numClusters = bmsmc.getNumberOfClusters(); for (int j = 0; j < numClusters; j++) { const BrainModelSurfaceMetricClustering::Cluster* cluster = bmsmc.getCluster(j); const int numNodesInCluster = cluster->getNumberOfNodesInCluster(); // // Corrected area is sum of each node's area multiplied by // 2 to the power of the selected metric column for the node // float correctedArea = 0.0; if (metricColumn >= 0) { for (int k = 0; k < numNodesInCluster; k++) { const int nodeNum = cluster->getNodeInCluster(k); float nodeArea = nodeAreas[nodeNum]; const double metric = mf->getValue(nodeNum, metricColumn); correctedArea += (nodeArea * std::pow(2.0, metric)); } } // // Add to the report // float cog[3]; cluster->getCenterOfGravity(cog); std::ostringstream str; str << thresh << blankTab.toAscii().constData() << (i + 1) << blankTab.toAscii().constData() << numNodesInCluster << blankTab.toAscii().constData() << cluster->getArea() << blankTab.toAscii().constData() << correctedArea << blankTab.toAscii().constData() << cog[0] << blankTab.toAscii().constData() << cog[1] << blankTab.toAscii().constData() << cog[2]; reportTextEdit->append(str.str().c_str()); } } // // Swith to report page // tabWidget->setCurrentWidget(reportPage); QApplication::beep(); QApplication::restoreOverrideCursor(); theMainWindow->speakText("The report is ready.", false); } /** * create the surface shape correlation coefficient section. */ void GuiSurfaceRegionOfInterestDialogOLD::createShapeCorrelationCoefficientReport() { QLabel* shapeLabel = new QLabel("Reference Column "); shapeCorrelationColumnComboBox = new GuiNodeAttributeColumnSelectionComboBox( GUI_NODE_FILE_TYPE_SURFACE_SHAPE, false, false, true); shapeCorrelationColumnComboBox->setMaximumWidth(maxComboBoxWidth); shapeCorrelationColumnComboBox->setCurrentIndex( GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_ALL); QHBoxLayout* columnLayout = new QHBoxLayout; columnLayout->addWidget(shapeLabel); columnLayout->addWidget(shapeCorrelationColumnComboBox); //columnLayout->setStretchFactor(shapeLabel, 0); //columnLayout->setStretchFactor(shapeCorrelationColumnComboBox, 100); columnLayout->addStretch(); shapeCorrelationTabSeparateCheckBox = new QCheckBox("Separate Report With Semicolons"); QPushButton* createReportPushButton = new QPushButton("Create Correlation Report"); createReportPushButton->setFixedSize(createReportPushButton->sizeHint()); createReportPushButton->setAutoDefault(false); QObject::connect(createReportPushButton, SIGNAL(clicked()), this, SLOT(slotCorrelationShapeReport())); operationShapeCorrelationWidget = new QWidget; QVBoxLayout* layout = new QVBoxLayout(operationShapeCorrelationWidget); layout->addLayout(columnLayout); layout->addWidget(shapeCorrelationTabSeparateCheckBox); layout->addWidget(createReportPushButton); layout->addStretch(); } /** * Called to create shape correlation report. */ void GuiSurfaceRegionOfInterestDialogOLD::slotCorrelationShapeReport() { float roiArea = 0.0; QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); if (createReportHeader("", shapeCorrelationTabSeparateCheckBox->isChecked(), roiArea)) { return; } QString blankTab(" "); if (shapeCorrelationTabSeparateCheckBox->isChecked()) { blankTab = separatorCharacter; } BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); std::vector nodesAreInROI; surfaceROI->getNodesInROI(nodesAreInROI); SurfaceShapeFile* ssf = theMainWindow->getBrainSet()->getSurfaceShapeFile(); std::vector coefficients; const int column = shapeCorrelationColumnComboBox->currentIndex(); if (column == GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_ALL) { const int lastColumn = ssf->getNumberOfColumns() - 1; std::ostringstream str; for (int j = 0; j < ssf->getNumberOfColumns(); j++) { str << ssf->getColumnName(j).toAscii().constData(); if (j != lastColumn) { str << blankTab.toAscii().constData(); } } reportTextEdit->append(str.str().c_str()); for (int j = 0; j < ssf->getNumberOfColumns(); j++) { ssf->correlationCoefficient(j, coefficients, &nodesAreInROI); std::ostringstream str; str.setf(std::ios::fixed); for (int i = 0; i < ssf->getNumberOfColumns(); i++) { str << coefficients[i]; if (i != lastColumn) { str << blankTab.toAscii().constData(); } } reportTextEdit->append(str.str().c_str()); } } else { ssf->correlationCoefficient(column, coefficients, &nodesAreInROI); std::ostringstream str; str.setf(std::ios::fixed); str << "\n" << "Correlation for " << ssf->getColumnName(column).toAscii().constData(); reportTextEdit->append(str.str().c_str()); for (int i = 0; i < ssf->getNumberOfColumns(); i++) { str.str(""); str << (i + 1) << blankTab.toAscii().constData() << ssf->getColumnName(i).toAscii().constData() << blankTab.toAscii().constData() << coefficients[i]; reportTextEdit->append(str.str().c_str()); } } // // Swith to report page // tabWidget->setCurrentWidget(reportPage); QApplication::beep(); QApplication::restoreOverrideCursor(); theMainWindow->speakText("The report is ready.", false); } /** * Called to disconnect the selected nodes. */ void GuiSurfaceRegionOfInterestDialogOLD::slotDisconnectNodes() { BrainModelSurface* bms = operationSurfaceComboBox->getSelectedBrainModelSurface(); if (bms != NULL) { //TopologyFile* tf = topologyComboBox->getSelectedTopologyFile(); //bms->getTopologyFile(); TopologyFile* tf = bms->getTopologyFile(); if (tf != NULL) { BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); std::vector nodesAreInROI; surfaceROI->getNodesInROI(nodesAreInROI); theMainWindow->getBrainSet()->disconnectNodes(tf, nodesAreInROI); GuiBrainModelOpenGL::updateAllGL(NULL); theMainWindow->speakText("Nodes have been disconnected.", false); } } } /** * set node for geodesic query. */ void GuiSurfaceRegionOfInterestDialogOLD::setNodeForGeodesicQuery(const int nodeNumber) { geodesicNodeSpinBox->setValue(nodeNumber); } /** * called to default geodesic column names. */ void GuiSurfaceRegionOfInterestDialogOLD::slotUpdateGeodesicColumnNames() { const int nodeNumber = geodesicNodeSpinBox->value(); QString newName("Node "); newName.append(StringUtilities::fromNumber(nodeNumber)); const QString geoName(geodesicDistanceColumnNameLineEdit->text()); if (geoName == geodesicDistanceColumnComboBox->getNewColumnLabel()) { geodesicDistanceColumnNameLineEdit->setText(newName); } const QString metricName(geodesicMetricColumnNameLineEdit->text()); if (metricName == geodesicMetricColumnComboBox->getNewColumnLabel()) { geodesicMetricColumnNameLineEdit->setText(newName); } } /** * create the integrated folding index widget */ void GuiSurfaceRegionOfInterestDialogOLD::createOperationIntegratedFoldingIndex() { QPushButton* computePushButton = new QPushButton("Compute Integrated Folding Index"); computePushButton->setFixedSize(computePushButton->sizeHint()); computePushButton->setAutoDefault(false); QObject::connect(computePushButton, SIGNAL(clicked()), this, SLOT(slotComputeIntegratedFoldingIndex())); operationComputeIntegratedFoldingIndexWidget = new QWidget; QVBoxLayout* layout = new QVBoxLayout(operationComputeIntegratedFoldingIndexWidget); layout->addWidget(computePushButton); layout->addStretch(); } /** * called to run compute integrated folding index. */ void GuiSurfaceRegionOfInterestDialogOLD::slotComputeIntegratedFoldingIndex() { BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); if (surfaceROI->anyNodesSelected() == false) { QMessageBox::critical(this, "Error: no nodes in ROI", "There are no nodes in the region of interest."); return; } SurfaceShapeFile* ssf = theMainWindow->getBrainSet()->getSurfaceShapeFile(); const int numColumns = ssf->getNumberOfColumns(); if (numColumns <= 0) { QMessageBox::critical(this, "ERROR", "No surface shape columns are selected."); return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); float roiArea = 0.0; if (createReportHeader("Integrated Folding Index", false, roiArea)) { return; } BrainModelSurface* bms = operationSurfaceComboBox->getSelectedBrainModelSurface(); if (bms != NULL) { TopologyFile* tf = bms->getTopologyFile(); if (tf != NULL) { std::vector areaTimesFoldingSum(numColumns, 0.0); const int numTriangles = tf->getNumberOfTiles(); for (int i = 0; i < numTriangles; i++) { if (tileInROI[i]) { int n1, n2, n3; tf->getTile(i, n1, n2, n3); for (int j = 0; j < numColumns; j++) { if (surfaceShapeCheckBoxes[j]->isChecked()) { // // Average folding index is: // SUM(Ai * Abs(Fi)) / SUM(Ai); // // Ai = area of triangle (less if not all nodes in ROI) // Fi = average shape value of triangle's three nodes // SUM(Ai) is the same as the ROI's area // float shapeSum = 0.0; float numInROI = 0.0; if (surfaceROI->getNodeSelected(n1)) { shapeSum += ssf->getValue(n1, j); numInROI += 1.0; } if (surfaceROI->getNodeSelected(n2)) { shapeSum += ssf->getValue(n2, j); numInROI += 1.0; } if (surfaceROI->getNodeSelected(n3)) { shapeSum += ssf->getValue(n3, j); numInROI += 1.0; } if (numInROI > 0.0) { const float averageShape = std::fabs(shapeSum) / numInROI; areaTimesFoldingSum[j] += averageShape * tileArea[i]; } } } } } int longestColumnNameLength = 10; for (int j = 0; j < numColumns; j++) { if (surfaceShapeCheckBoxes[j]->isChecked()) { longestColumnNameLength = std::max(longestColumnNameLength, static_cast(ssf->getColumnName(j).length())); } } longestColumnNameLength += 5; QString s = StringUtilities::leftJustify("Name", longestColumnNameLength) + StringUtilities::rightJustify("IFI", 12); reportTextEdit->append(s); for (int j = 0; j < numColumns; j++) { if (surfaceShapeCheckBoxes[j]->isChecked()) { const float integratedFloatingIndex = areaTimesFoldingSum[j] / roiArea; QString s = StringUtilities::leftJustify(ssf->getColumnName(j), longestColumnNameLength) + StringUtilities::rightJustify(QString::number(integratedFloatingIndex, 'f', 6), 12); reportTextEdit->append(s); } } } } // // Switch to report page // tabWidget->setCurrentWidget(reportPage); QApplication::beep(); QApplication::restoreOverrideCursor(); } /** * create the disconnect nodes operation section */ void GuiSurfaceRegionOfInterestDialogOLD::createOperationGeodesicDistance() { QLabel* nodeLabel = new QLabel("Query Node"); geodesicNodeSpinBox = new QSpinBox; geodesicNodeSpinBox->setMinimum(0); geodesicNodeSpinBox->setMaximum(100000000); geodesicNodeSpinBox->setSingleStep(1); QObject::connect(geodesicNodeSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotUpdateGeodesicColumnNames())); QPushButton* geodesicNodeButton = new QPushButton("Choose Node With Mouse"); geodesicNodeSpinBox->setValue(-1); geodesicNodeButton->setAutoDefault(false); geodesicNodeButton->setFixedSize(geodesicNodeButton->sizeHint()); QObject::connect(geodesicNodeButton, SIGNAL(clicked()), this, SLOT(slotGeodesicNodePushButton())); QHBoxLayout* nodeLayout = new QHBoxLayout; nodeLayout->addWidget(nodeLabel); nodeLayout->addWidget(geodesicNodeSpinBox); nodeLayout->addWidget(geodesicNodeButton); nodeLayout->addStretch(); QLabel* metricLabel = new QLabel("Metric "); geodesicMetricColumnComboBox = new GuiNodeAttributeColumnSelectionComboBox( GUI_NODE_FILE_TYPE_METRIC, true, true, false); geodesicMetricColumnComboBox->setMaximumWidth(maxComboBoxWidth); geodesicMetricColumnNameLineEdit = new QLineEdit; QObject::connect(geodesicMetricColumnComboBox, SIGNAL(itemNameSelected(const QString&)), geodesicMetricColumnNameLineEdit, SLOT(setText(const QString&))); geodesicMetricColumnNameLineEdit->setText(geodesicMetricColumnComboBox->getCurrentLabel()); QLabel* geoLabel = new QLabel("Geodesic "); geodesicDistanceColumnComboBox = new GuiNodeAttributeColumnSelectionComboBox( GUI_NODE_FILE_TYPE_GEODESIC_DISTANCE, true, true, false); geodesicDistanceColumnComboBox->setMaximumWidth(maxComboBoxWidth); geodesicDistanceColumnNameLineEdit = new QLineEdit; QObject::connect(geodesicDistanceColumnComboBox, SIGNAL(itemNameSelected(const QString&)), geodesicDistanceColumnNameLineEdit, SLOT(setText(const QString&))); geodesicDistanceColumnNameLineEdit->setText(geodesicDistanceColumnComboBox->getCurrentLabel()); QGridLayout* fileGridLayout = new QGridLayout; fileGridLayout->addWidget(metricLabel, 0, 0); fileGridLayout->addWidget(geodesicMetricColumnComboBox, 0, 1); fileGridLayout->addWidget(geodesicMetricColumnNameLineEdit, 0, 2); fileGridLayout->addWidget(geoLabel, 1, 0); fileGridLayout->addWidget(geodesicDistanceColumnComboBox, 1, 1); fileGridLayout->addWidget(geodesicDistanceColumnNameLineEdit, 1, 2); QHBoxLayout* fileLayout = new QHBoxLayout; fileLayout->addLayout(fileGridLayout); fileLayout->addStretch(); QPushButton* geodesicButton = new QPushButton("Determine Geodesic Distances"); geodesicButton->setAutoDefault(false); geodesicButton->setFixedSize(geodesicButton->sizeHint()); QObject::connect(geodesicButton, SIGNAL(clicked()), this, SLOT(slotGeodesicPushButton())); operationGeodesicWidget = new QWidget; QVBoxLayout* layout = new QVBoxLayout(operationGeodesicWidget); layout->addLayout(nodeLayout); layout->addLayout(fileLayout); layout->addWidget(geodesicButton); layout->addStretch(); } /** * Called to change the mouse mode to select the node for the geodesic query. */ void GuiSurfaceRegionOfInterestDialogOLD::slotGeodesicNodePushButton() { theMainWindow->getBrainModelOpenGL()->setMouseMode( GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_GEODESIC_NODE_SELECT); } /** * Called to execute the geodesic query. */ void GuiSurfaceRegionOfInterestDialogOLD::slotGeodesicPushButton() { BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); if (surfaceROI->anyNodesSelected() == false) { QMessageBox::critical(this, "Error: no nodes in ROI", "There are no nodes in the region of interest."); return; } const int nodeNumber = geodesicNodeSpinBox->value(); BrainModelSurface* bms = operationSurfaceComboBox->getSelectedBrainModelSurface(); if (bms != NULL) { if ((nodeNumber < 0) || (nodeNumber >= bms->getNumberOfNodes())) { QMessageBox::critical(this, "Error", "No query node selected"); return; } //TopologyFile* tf = topologyComboBox->getSelectedTopologyFile(); //bms->getTopologyFile(); TopologyFile* tf = bms->getTopologyFile(); if (tf != NULL) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainModelSurfaceGeodesic bmsg(theMainWindow->getBrainSet(), bms, theMainWindow->getBrainSet()->getMetricFile(), geodesicMetricColumnComboBox->currentIndex(), geodesicMetricColumnNameLineEdit->text(), theMainWindow->getBrainSet()->getGeodesicDistanceFile(), geodesicDistanceColumnComboBox->currentIndex(), geodesicDistanceColumnNameLineEdit->text(), nodeNumber, surfaceROI); try { bmsg.execute(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "Error", e.whatQString()); } GuiFilesModified fm; fm.setMetricModified(); fm.setGeodesicModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); theMainWindow->speakText("Geodesic data has been created.", false); } } } /** * create the smooth nodes operation section */ void GuiSurfaceRegionOfInterestDialogOLD::createOperationSmoothNodes() { QPushButton* smoothButton = new QPushButton("Smooth Selected Nodes..."); smoothButton->setAutoDefault(false); smoothButton->setFixedSize(smoothButton->sizeHint()); QObject::connect(smoothButton, SIGNAL(clicked()), this, SLOT(slotSmoothNodes())); operationSmoothNodesWidget = new QWidget; QVBoxLayout* layout = new QVBoxLayout(operationSmoothNodesWidget); layout->addWidget(smoothButton); layout->addStretch(); } /** * Called to smooth the selected nodes. */ void GuiSurfaceRegionOfInterestDialogOLD::slotSmoothNodes() { BrainModelSurface* bms = operationSurfaceComboBox->getSelectedBrainModelSurface(); if (bms != NULL) { BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); std::vector nodesAreInROI; surfaceROI->getNodesInROI(nodesAreInROI); GuiSmoothingDialog sd(this, true, false, &nodesAreInROI); if (sd.exec()) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); } } } /** * create the statistical report operation section */ void GuiSurfaceRegionOfInterestDialogOLD::createOperationStatisticalReport() { QLabel* distLabel = new QLabel("Distortion Correction"); distortionCorrectionMetricColumnComboBox = new GuiNodeAttributeColumnSelectionComboBox(GUI_NODE_FILE_TYPE_METRIC, false, true, false); distortionCorrectionMetricColumnComboBox->setCurrentIndex(GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NONE); distortionCorrectionMetricColumnComboBox->setToolTip( "Use this control to select a metric file column\n" "that contains a distortion correction ratio."); QHBoxLayout* distLayout = new QHBoxLayout; distLayout->addWidget(distLabel); distLayout->addWidget(distortionCorrectionMetricColumnComboBox); distLayout->addWidget(distLabel, 0); distLayout->addWidget(distortionCorrectionMetricColumnComboBox, 100); tabSeparateReportCheckBox = new QCheckBox( "Separate Report With Semicolons (for import to spreadsheet)"); QPushButton* createReportButton = new QPushButton("Create Report"); createReportButton->setAutoDefault(false); createReportButton->setFixedSize(createReportButton->sizeHint()); QObject::connect(createReportButton, SIGNAL(clicked()), this, SLOT(slotCreateReportButton())); operationStatisticalReportWidget = new QWidget; QVBoxLayout* layout = new QVBoxLayout(operationStatisticalReportWidget); layout->addLayout(distLayout); layout->addWidget(tabSeparateReportCheckBox); layout->addWidget(createReportButton); layout->addStretch(); } /** * create the statistical report operation section */ void GuiSurfaceRegionOfInterestDialogOLD::createOperationStatisticalPaintReport() { QLabel* paintLabel = new QLabel("Paint Column "); paintRegionReportColumnComboBox = new GuiNodeAttributeColumnSelectionComboBox( GUI_NODE_FILE_TYPE_PAINT, false, false, false); paintRegionReportColumnComboBox->setMaximumWidth(maxComboBoxWidth); QHBoxLayout* columnLayout = new QHBoxLayout; columnLayout->addWidget(paintLabel); columnLayout->addWidget(paintRegionReportColumnComboBox); //columnLayout->setStretchFactor(paintLabel, 0); //columnLayout->setStretchFactor(paintRegionReportColumnComboBox, 100); columnLayout->addStretch(); tabSeparatePaintReportCheckBox = new QCheckBox( "Separate Paint Subregion Report With Semicolons (for import to spreadsheet)"); QPushButton* createPaintReportButton = new QPushButton("Create Paint Subregion Report"); createPaintReportButton->setAutoDefault(false); createPaintReportButton->setFixedSize(createPaintReportButton->sizeHint()); QObject::connect(createPaintReportButton, SIGNAL(clicked()), this, SLOT(slotCreatePaintReportButton())); operationStatisticalPaintReportWidget = new QWidget; QVBoxLayout* layout = new QVBoxLayout(operationStatisticalPaintReportWidget); layout->addLayout(columnLayout); layout->addWidget(tabSeparatePaintReportCheckBox); layout->addWidget(createPaintReportButton); layout->addStretch(); } /** * Called when an operation combo box selection is made */ void GuiSurfaceRegionOfInterestDialogOLD::slotOperationMode(int item) { const OPERATION_MODE opMode = static_cast(item); switch(opMode) { case OPERATION_MODE_ASSIGN_METRIC: operationsWidgetStack->setCurrentWidget(operationAssignMetricWidget); break; case OPERATION_MODE_ASSIGN_PAINT: operationsWidgetStack->setCurrentWidget(operationAssignPaintWidget); break; case OPERATION_MODE_ASSIGN_SURFACE_SHAPE: operationsWidgetStack->setCurrentWidget(operationAssignSurfaceShapeWidget); break; case OPERATION_MODE_COMPUTE_INTEGRATED_FOLDING_INDEX: operationsWidgetStack->setCurrentWidget(operationComputeIntegratedFoldingIndexWidget); break; case OPERATION_MODE_CREATE_BORDERS_FROM_CLUSTERS: operationsWidgetStack->setCurrentWidget(operationCreateBordersFromClustersWidget); break; case OPERATION_MODE_CREATE_BORDERS_FROM_ROI: operationsWidgetStack->setCurrentWidget(operationCreateBordersFromROIWidget); break; case OPERATION_MODE_CREATE_VOLUME_ROI: operationsWidgetStack->setCurrentWidget(operationCreateVolumeRoiWidget); break; case OPERATION_MODE_DISCONNECT_NODES: operationsWidgetStack->setCurrentWidget(operationDisconnectNodesWidget); break; case OPERATION_MODE_GEODESIC: operationsWidgetStack->setCurrentWidget(operationGeodesicWidget); break; case OPERATION_MODE_PROB_ATLAS_OVERLAP: operationsWidgetStack->setCurrentWidget(operationProbAtlasWidget); break; case OPERATION_MODE_STATISTICAL_REPORT: operationsWidgetStack->setCurrentWidget(operationStatisticalReportWidget); break; case OPERATION_MODE_STATISTICAL_PAINT_REPORT: operationsWidgetStack->setCurrentWidget(operationStatisticalPaintReportWidget); break; case OPERATION_MODE_SMOOTH_NODES: operationsWidgetStack->setCurrentWidget(operationSmoothNodesWidget); break; case OPERATION_MODE_SHAPE_CORRELATION: operationsWidgetStack->setCurrentWidget(operationShapeCorrelationWidget); break; case OPERATION_MODE_SHAPE_CLUSTER_ANALYSIS: operationsWidgetStack->setCurrentWidget(operationShapeClusterWidget); } } /** * Create the node selection section. */ QWidget* GuiSurfaceRegionOfInterestDialogOLD::createNodeSelectionSection() { // // Select Nodes // QPushButton* selectNodesPushButton = new QPushButton("Select Nodes"); selectNodesPushButton->setAutoDefault(false); selectNodesPushButton->setFixedSize(selectNodesPushButton->sizeHint()); QObject::connect(selectNodesPushButton, SIGNAL(clicked()), this, SLOT(slotSelectNodesButton())); // // Selection logic combo box // selectionLogicComboBox = new QComboBox; std::vector selectionTypes; std::vector selectionNames; BrainModelSurfaceROINodeSelection::getNodeSelectionTypesAndNames(selectionTypes, selectionNames); for (unsigned int i = 0; i < selectionNames.size(); i++) { selectionLogicComboBox->insertItem(selectionTypes[i], selectionNames[i]); } selectionLogicComboBox->setFixedSize(selectionLogicComboBox->sizeHint()); // // Invert selection combo box // QPushButton* invertNodeSelectionPushButton = new QPushButton("Invert Node Selection"); invertNodeSelectionPushButton->setAutoDefault(false); invertNodeSelectionPushButton->setFixedSize(invertNodeSelectionPushButton->sizeHint()); QObject::connect(invertNodeSelectionPushButton, SIGNAL(clicked()), this, SLOT(slotInvertNodeSelectionPushButton())); // // layout on left // QVBoxLayout* selectLayout = new QVBoxLayout; selectLayout->addWidget(selectNodesPushButton); selectLayout->addWidget(selectionLogicComboBox); selectLayout->addWidget(invertNodeSelectionPushButton); selectLayout->addStretch(); // // Deselect Nodes // QPushButton* deselectNodesPushButton = new QPushButton("Deselect Nodes"); deselectNodesPushButton->setAutoDefault(false); deselectNodesPushButton->setFixedSize(deselectNodesPushButton->sizeHint()); QObject::connect(deselectNodesPushButton, SIGNAL(clicked()), this, SLOT(slotDeselectNodesButton())); // // Selected nodes label // QLabel* nodesSelLabel = new QLabel("Nodes Selected: "); numberOfNodesSelectedLabel = new QLabel(" "); updateNumberOfSelectedNodesLabel(); // // Show nodes check box // BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); showSelectedNodesCheckBox = new QCheckBox("Show Selected Nodes"); QObject::connect(showSelectedNodesCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowSelectedNodes(bool))); showSelectedNodesCheckBox->setChecked(surfaceROI->getDisplaySelectedNodes()); slotShowSelectedNodes(showSelectedNodesCheckBox->isChecked()); // // layout for some items // QHBoxLayout* selNodesLayout = new QHBoxLayout; selNodesLayout->addWidget(nodesSelLabel); selNodesLayout->addWidget(numberOfNodesSelectedLabel); selNodesLayout->addStretch(); QVBoxLayout* togglesLayout = new QVBoxLayout; togglesLayout->addWidget(deselectNodesPushButton); togglesLayout->addLayout(selNodesLayout); togglesLayout->addWidget(showSelectedNodesCheckBox); // // Dilate Push Button // QPushButton* dilatePushButton = new QPushButton("Dilate"); dilatePushButton->setAutoDefault(false); dilatePushButton->setToolTip("Each press of this button will add\n" "a layer of nodes to the outside\n" "of the current region of interest."); QObject::connect(dilatePushButton, SIGNAL(clicked()), this, SLOT(slotDilatePushButton())); // // Erode Push Button // QPushButton* erodePushButton = new QPushButton("Erode"); erodePushButton->setAutoDefault(false); dilatePushButton->setToolTip("Each press of this button will remove\n" "a layer of nodes from the outside\n" "of the current region of interest."); QObject::connect(erodePushButton, SIGNAL(clicked()), this, SLOT(slotErodePushButton())); // // Layout and sizes of Dilate/Erode push buttons // QtUtilities::makeButtonsSameSize(dilatePushButton, erodePushButton); QVBoxLayout* dilateErodeLayout = new QVBoxLayout; dilateErodeLayout->addWidget(dilatePushButton); dilateErodeLayout->addWidget(erodePushButton); dilateErodeLayout->addStretch(); // // Load ROI Push Button // QPushButton* loadROIPushButton = new QPushButton("Load ROI..."); loadROIPushButton->setAutoDefault(false); QObject::connect(loadROIPushButton, SIGNAL(clicked()), this, SLOT(slotLoadROIPushButton())); // // Save ROI Push Button // QPushButton* saveROIPushButton = new QPushButton("Save ROI..."); saveROIPushButton->setAutoDefault(false); QObject::connect(saveROIPushButton, SIGNAL(clicked()), this, SLOT(slotSaveROIPushButton())); // // layout and sizes of Load/Save push buttons // QtUtilities::makeButtonsSameSize(loadROIPushButton, saveROIPushButton); QVBoxLayout* loadSaveLayout = new QVBoxLayout; loadSaveLayout->addWidget(loadROIPushButton); loadSaveLayout->addWidget(saveROIPushButton); loadSaveLayout->addStretch(); // // Widget and layout for page // QWidget* nodeBox = new QWidget; QHBoxLayout* layout = new QHBoxLayout(nodeBox); layout->addLayout(selectLayout); layout->addLayout(togglesLayout); layout->addLayout(dilateErodeLayout); layout->addLayout(loadSaveLayout); return nodeBox; } /** * called when dilate button is pressed. */ void GuiSurfaceRegionOfInterestDialogOLD::slotDilatePushButton() { BrainModelSurface* bms = operationSurfaceComboBox->getSelectedBrainModelSurface(); if (bms == NULL) { return; } // // Dilate the ROI // BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); surfaceROI->dilate(bms, 1); // // Set node highlighting // updateNumberOfSelectedNodesLabel(); slotShowSelectedNodes(showSelectedNodesCheckBox->isChecked()); theMainWindow->getBrainSet()->clearAllDisplayLists(); GuiBrainModelOpenGL::updateAllGL(NULL); } /** * called when erode button is pressed. */ void GuiSurfaceRegionOfInterestDialogOLD::slotErodePushButton() { BrainModelSurface* bms = operationSurfaceComboBox->getSelectedBrainModelSurface(); if (bms == NULL) { return; } // // Erode the ROI // BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); surfaceROI->erode(bms, 1); // // Set node highlighting // updateNumberOfSelectedNodesLabel(); slotShowSelectedNodes(showSelectedNodesCheckBox->isChecked()); theMainWindow->getBrainSet()->clearAllDisplayLists(); GuiBrainModelOpenGL::updateAllGL(NULL); } /** * called when load ROI button is pressed. */ void GuiSurfaceRegionOfInterestDialogOLD::slotLoadROIPushButton() { WuQFileDialog fd(this); fd.setModal(true); fd.setDirectory(QDir::currentPath()); fd.setAcceptMode(WuQFileDialog::AcceptOpen); fd.setWindowTitle("Choose Region of Interest File Name"); fd.setFilter(FileFilters::getRegionOfInterestFileFilter()); fd.setFileMode(WuQFileDialog::ExistingFile); if (fd.exec() == QDialog::Accepted) { if (fd.selectedFiles().count() > 0) { const QString fileName = fd.selectedFiles().at(0); NodeRegionOfInterestFile roiFile; try { roiFile.readFile(fileName); BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); surfaceROI->getRegionOfInterestFromFile(roiFile); // // Set node highlighting // resetMarkedNodesAndReportHeader(false); updateNumberOfSelectedNodesLabel(); slotShowSelectedNodes(showSelectedNodesCheckBox->isChecked()); theMainWindow->getBrainSet()->clearAllDisplayLists(); GuiBrainModelOpenGL::updateAllGL(NULL); } catch (FileException& e) { QMessageBox::critical(this, "ERROR", e.whatQString()); return; } } } } /** * called when save ROI button is pressed. */ void GuiSurfaceRegionOfInterestDialogOLD::slotSaveROIPushButton() { WuQFileDialog fd(this); fd.setModal(true); fd.setDirectory(QDir::currentPath()); fd.setAcceptMode(WuQFileDialog::AcceptSave); fd.setWindowTitle("Choose Region of Interest File Name"); fd.setFilter(FileFilters::getRegionOfInterestFileFilter()); fd.setFileMode(WuQFileDialog::AnyFile); if (fd.exec() == QDialog::Accepted) { if (fd.selectedFiles().count() > 0) { const QString fileName = fd.selectedFiles().at(0); NodeRegionOfInterestFile roiFile; BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); surfaceROI->setRegionOfInterestIntoFile(roiFile); try { roiFile.writeFile(fileName); } catch (FileException& e) { QMessageBox::critical(this, "ERROR", e.whatQString()); return; } } } } /** * Called when show selected nodes paint toggle is changed. */ void GuiSurfaceRegionOfInterestDialogOLD::slotShowSelectedNodes(bool on) { BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); surfaceROI->setDisplaySelectedNodes(on); theMainWindow->getBrainSet()->clearAllDisplayLists(); GuiBrainModelOpenGL::updateAllGL(NULL); } /** * Update the number of selected nodes label */ void GuiSurfaceRegionOfInterestDialogOLD::updateNumberOfSelectedNodesLabel() { BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); numberOfNodesSelectedLabel->setNum(surfaceROI->getNumberOfNodesSelected()); } /** * Create the paint node selection section. */ void GuiSurfaceRegionOfInterestDialogOLD::createNodeSelectionPaint() { const int minComboWidth = 200; // // paint category // QLabel* categoryLabel = new QLabel("Category "); paintWithNameCategoryComboBox = new GuiNodeAttributeColumnSelectionComboBox( GUI_NODE_FILE_TYPE_PAINT, false, false, false); paintWithNameCategoryComboBox->setMaximumWidth(maxComboBoxWidth); paintWithNameCategoryComboBox->setMinimumWidth(minComboWidth); QHBoxLayout* categoryLayout = new QHBoxLayout; categoryLayout->addWidget(categoryLabel); categoryLayout->addWidget(paintWithNameCategoryComboBox); categoryLayout->setStretchFactor(categoryLabel, 0); categoryLayout->setStretchFactor(paintWithNameCategoryComboBox, 100); categoryLayout->addStretch(); // // Selection buttons // QPushButton* paintNameFromListPushButton = new QPushButton("Select Name From List..."); paintNameFromListPushButton->setAutoDefault(false); QObject::connect(paintNameFromListPushButton, SIGNAL(clicked()), this, SLOT(slotPaintNameFromListPushButton())); QPushButton* paintNameFromMousePushButton = new QPushButton("Select Node With Mouse..."); paintNameFromMousePushButton->setAutoDefault(false); QObject::connect(paintNameFromMousePushButton, SIGNAL(clicked()), this, SLOT(slotPaintNameFromMousePushButton())); QtUtilities::makeButtonsSameSize(paintNameFromListPushButton, paintNameFromMousePushButton); QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->addWidget(paintNameFromListPushButton); buttonsLayout->addWidget(paintNameFromMousePushButton); buttonsLayout->addStretch(); // // paint name // QLabel* nameLabel = new QLabel("Name "); paintWithNameSelectedLabel = new QLabel(" "); QHBoxLayout* nameLayout = new QHBoxLayout; nameLayout->addWidget(nameLabel); nameLayout->addWidget(paintWithNameSelectedLabel); nameLayout->setStretchFactor(nameLabel, 0); nameLayout->setStretchFactor(paintWithNameSelectedLabel, 100); // // Group Box for Nodes with Paint // nodesWithPaintQVBox = new QWidget; QVBoxLayout* layout = new QVBoxLayout(nodesWithPaintQVBox); layout->addLayout(categoryLayout); layout->addLayout(buttonsLayout); layout->addLayout(nameLayout); } /** * Create the border node selection section. */ void GuiSurfaceRegionOfInterestDialogOLD::createNodeSelectionBorder() { const int minComboWidth = 200; // // Selection buttons // QPushButton* borderNameFromListPushButton = new QPushButton("Select Name From List..."); borderNameFromListPushButton->setAutoDefault(false); QObject::connect(borderNameFromListPushButton, SIGNAL(clicked()), this, SLOT(slotBorderNameFromListPushButton())); QPushButton* borderNameFromMousePushButton = new QPushButton("Select Border With Mouse..."); borderNameFromMousePushButton->setAutoDefault(false); QObject::connect(borderNameFromMousePushButton, SIGNAL(clicked()), this, SLOT(slotBorderNameFromMousePushButton())); QtUtilities::makeButtonsSameSize(borderNameFromListPushButton, borderNameFromMousePushButton); QHBoxLayout* selectLayout = new QHBoxLayout; selectLayout->addWidget(borderNameFromListPushButton); selectLayout->addWidget(borderNameFromMousePushButton); selectLayout->addStretch(); // // border name label // QLabel* nameLabel = new QLabel("Name "); borderNameSelectedLabel = new QLabel(" "); QHBoxLayout* nameLayout = new QHBoxLayout; nameLayout->addWidget(nameLabel); nameLayout->addWidget(borderNameSelectedLabel); nameLayout->setStretchFactor(nameLabel, 0); nameLayout->setStretchFactor(borderNameSelectedLabel, 100); // // Flat surface // QLabel* surfaceLabel = new QLabel("Flat Surface"); borderSurfaceComboBox = new GuiBrainModelSelectionComboBox(false, true, false, "", 0, "borderSurfaceComboBox", true); borderSurfaceComboBox->setMaximumWidth(maxComboBoxWidth); borderSurfaceComboBox->setMinimumWidth(minComboWidth); QHBoxLayout* surfaceLayout = new QHBoxLayout; surfaceLayout->addWidget(surfaceLabel); surfaceLayout->addWidget(borderSurfaceComboBox); //surfaceLayout->setStretchFactor(surfaceLabel, 0); //surfaceLayout->setStretchFactor(borderSurfaceComboBox, 100); surfaceLayout->addStretch(); // // widget and layout for nodes within border // nodesWithinBorderQVBox = new QWidget; QVBoxLayout* layout = new QVBoxLayout(nodesWithinBorderQVBox); layout->addLayout(selectLayout); layout->addLayout(nameLayout); layout->addLayout(surfaceLayout); } /** * create the node selection with metric. */ void GuiSurfaceRegionOfInterestDialogOLD::createNodeSelectionMetric() { // // metric category // QLabel* categoryLabel = new QLabel("Category "); metricCategoryComboBox = new GuiNodeAttributeColumnSelectionComboBox( GUI_NODE_FILE_TYPE_METRIC, false, false, false); QHBoxLayout* categoryLayout = new QHBoxLayout; categoryLayout->addWidget(categoryLabel); categoryLayout->addWidget(metricCategoryComboBox); categoryLayout->setStretchFactor(categoryLabel, 0); categoryLayout->setStretchFactor(metricCategoryComboBox, 100); categoryLayout->addStretch(); QLabel* lowLabel = new QLabel("Threshold Low"); metricLowerThresholdDoubleSpinBox = new QDoubleSpinBox; metricLowerThresholdDoubleSpinBox->setMinimum(-std::numeric_limits::max()); metricLowerThresholdDoubleSpinBox->setMaximum(std::numeric_limits::max()); metricLowerThresholdDoubleSpinBox->setSingleStep(1.0); metricLowerThresholdDoubleSpinBox->setDecimals(3); metricLowerThresholdDoubleSpinBox->setValue(1.0); metricLowerThresholdDoubleSpinBox->setFixedWidth(120); QLabel* highLabel = new QLabel(" High"); metricUpperThresholdDoubleSpinBox = new QDoubleSpinBox; metricUpperThresholdDoubleSpinBox->setMinimum(-std::numeric_limits::max()); metricUpperThresholdDoubleSpinBox->setMaximum(std::numeric_limits::max()); metricUpperThresholdDoubleSpinBox->setSingleStep(1.0); metricUpperThresholdDoubleSpinBox->setDecimals(3); metricUpperThresholdDoubleSpinBox->setValue(50000.0); metricUpperThresholdDoubleSpinBox->setFixedWidth(120); QHBoxLayout* threshLayout = new QHBoxLayout; threshLayout->addWidget(lowLabel); threshLayout->addWidget(metricLowerThresholdDoubleSpinBox); threshLayout->addWidget(highLabel); threshLayout->addWidget(metricUpperThresholdDoubleSpinBox); threshLayout->addStretch(); QButtonGroup* metricSelectionButtonGroup = new QButtonGroup(this); QObject::connect(metricSelectionButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotMetricModeSelection(int))); metricAllNodesRadioButton = new QRadioButton("All Nodes Within Threshold"); metricSelectionButtonGroup->addButton(metricAllNodesRadioButton, 0); metricChooseNodesRadioButton = new QRadioButton( "Nodes Within Threshold Connected to Node Selected With Mouse"); metricSelectionButtonGroup->addButton(metricChooseNodesRadioButton, 1); metricAllNodesRadioButton->setChecked(true); metricNodeNumberLabel = new QLabel(" "); // // Group Box for nodes with metric // nodesWithMetricQVBox = new QWidget; QVBoxLayout* layout = new QVBoxLayout(nodesWithMetricQVBox); layout->addLayout(categoryLayout); layout->addLayout(threshLayout); layout->addWidget(metricAllNodesRadioButton); layout->addWidget(metricChooseNodesRadioButton); layout->addWidget(metricNodeNumberLabel); } /** * Create the lat/long node selection section. */ void GuiSurfaceRegionOfInterestDialogOLD::createNodeSelectionLatLon() { latLowerRangeDoubleSpinBox = new QDoubleSpinBox; latLowerRangeDoubleSpinBox->setMinimum(-90.0); latLowerRangeDoubleSpinBox->setMaximum( 90.0); latLowerRangeDoubleSpinBox->setSingleStep(1.0); latLowerRangeDoubleSpinBox->setDecimals(3); latLowerRangeDoubleSpinBox->setValue(-90.0); latLowerRangeDoubleSpinBox->setFixedWidth(120); latUpperRangeDoubleSpinBox = new QDoubleSpinBox; latUpperRangeDoubleSpinBox->setMinimum(-90.0); latUpperRangeDoubleSpinBox->setMaximum( 90.0); latUpperRangeDoubleSpinBox->setSingleStep(1.0); latUpperRangeDoubleSpinBox->setDecimals(3); latUpperRangeDoubleSpinBox->setValue(90.0); latUpperRangeDoubleSpinBox->setFixedWidth(120); lonLowerRangeDoubleSpinBox = new QDoubleSpinBox; lonLowerRangeDoubleSpinBox->setMinimum(-360.0); lonLowerRangeDoubleSpinBox->setMaximum( 360.0); lonLowerRangeDoubleSpinBox->setSingleStep(1.0); lonLowerRangeDoubleSpinBox->setDecimals(3); lonLowerRangeDoubleSpinBox->setValue(-180.0); lonLowerRangeDoubleSpinBox->setFixedWidth(120); lonUpperRangeDoubleSpinBox = new QDoubleSpinBox; lonUpperRangeDoubleSpinBox->setMinimum(-360.0); lonUpperRangeDoubleSpinBox->setMaximum( 360.0); lonUpperRangeDoubleSpinBox->setSingleStep(1.0); lonUpperRangeDoubleSpinBox->setDecimals(3); lonUpperRangeDoubleSpinBox->setValue(180.0); lonUpperRangeDoubleSpinBox->setFixedWidth(120); QWidget* gridWidget = new QWidget; QGridLayout* latLonLayout = new QGridLayout(gridWidget); latLonLayout->addWidget(new QLabel("Min-Value"), 0, 1); latLonLayout->addWidget(new QLabel("Max-Value"), 0, 2); latLonLayout->addWidget(new QLabel("Latitude"), 1, 0); latLonLayout->addWidget(new QLabel("Longitude"), 2, 0); latLonLayout->addWidget(latLowerRangeDoubleSpinBox, 1, 1); latLonLayout->addWidget(latUpperRangeDoubleSpinBox, 1, 2); latLonLayout->addWidget(lonLowerRangeDoubleSpinBox, 2, 1); latLonLayout->addWidget(lonUpperRangeDoubleSpinBox, 2, 2); gridWidget->setFixedSize(gridWidget->sizeHint()); nodesWithinLatLonQVBox = new QWidget; QVBoxLayout* layout = new QVBoxLayout(nodesWithinLatLonQVBox); layout->addWidget(gridWidget, 0, Qt::AlignLeft); layout->addStretch(); } /** * Create the shape node selection section. */ void GuiSurfaceRegionOfInterestDialogOLD::createNodeSelectionShape() { // // metric category // QLabel* categoryLabel = new QLabel("Category "); shapeCategoryComboBox = new GuiNodeAttributeColumnSelectionComboBox( GUI_NODE_FILE_TYPE_SURFACE_SHAPE, false, false, false); shapeCategoryComboBox->setMaximumWidth(maxComboBoxWidth); QHBoxLayout* categoryLayout = new QHBoxLayout; categoryLayout->addWidget(categoryLabel); categoryLayout->addWidget(shapeCategoryComboBox); categoryLayout->setStretchFactor(categoryLabel, 0); categoryLayout->setStretchFactor(shapeCategoryComboBox, 100); categoryLayout->addStretch(); QLabel* lowLabel = new QLabel("Threshold Low"); shapeLowerThresholdDoubleSpinBox = new QDoubleSpinBox; shapeLowerThresholdDoubleSpinBox->setMinimum(-std::numeric_limits::max()); shapeLowerThresholdDoubleSpinBox->setMaximum(std::numeric_limits::max()); shapeLowerThresholdDoubleSpinBox->setSingleStep(1.0); shapeLowerThresholdDoubleSpinBox->setDecimals(3); shapeLowerThresholdDoubleSpinBox->setValue(1.0); shapeLowerThresholdDoubleSpinBox->setFixedWidth(120); QLabel* highLabel = new QLabel(" High"); shapeUpperThresholdDoubleSpinBox = new QDoubleSpinBox; shapeUpperThresholdDoubleSpinBox->setMinimum(-std::numeric_limits::max()); shapeUpperThresholdDoubleSpinBox->setMaximum(std::numeric_limits::max()); shapeUpperThresholdDoubleSpinBox->setSingleStep(1.0); shapeUpperThresholdDoubleSpinBox->setDecimals(3); shapeUpperThresholdDoubleSpinBox->setValue(50000.0); shapeUpperThresholdDoubleSpinBox->setFixedWidth(120); QHBoxLayout* threshLayout = new QHBoxLayout; threshLayout->addWidget(lowLabel); threshLayout->addWidget(shapeLowerThresholdDoubleSpinBox); threshLayout->addWidget(highLabel); threshLayout->addWidget(shapeUpperThresholdDoubleSpinBox); threshLayout->addStretch(); QButtonGroup* shapeSelectionButtonGroup = new QButtonGroup(this); QObject::connect(shapeSelectionButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotShapeModeSelection(int))); shapeAllNodesRadioButton = new QRadioButton("All Nodes Within Threshold"); shapeSelectionButtonGroup->addButton(shapeAllNodesRadioButton, 0); shapeChooseNodesRadioButton = new QRadioButton( "Nodes Within Threshold Connected to Node Selected With Mouse"); shapeSelectionButtonGroup->addButton(shapeChooseNodesRadioButton, 1); shapeAllNodesRadioButton->setChecked(true); shapeNodeNumberLabel = new QLabel(" "); // // widget and layout for nodes with shape // nodesWithShapeQVBox = new QWidget; QVBoxLayout* layout = new QVBoxLayout(nodesWithShapeQVBox); layout->addLayout(categoryLayout); layout->addLayout(threshLayout); layout->addWidget(shapeAllNodesRadioButton); layout->addWidget(shapeChooseNodesRadioButton); layout->addWidget(shapeNodeNumberLabel); } /** * Called when a shape mode is selected. */ void GuiSurfaceRegionOfInterestDialogOLD::slotShapeModeSelection(int shapeMode) { if (shapeMode == 1) { theMainWindow->getBrainModelOpenGL()->setMouseMode( GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_SHAPE_NODE_SELECT); } } /** * Called to create a volume from the display query nodes. */ void GuiSurfaceRegionOfInterestDialogOLD::slotCreateVolumeFromQueryNodesButton() { BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); if (surfaceROI->anyNodesSelected() == false) { QMessageBox::critical(this, "Error: no nodes in ROI", "There are no nodes in the region of interest."); return; } GuiSurfaceToVolumeDialog svd(this, GuiSurfaceToVolumeDialog::DIALOG_MODE_NORMAL, "Create Region Of Interest Volume"); if (svd.exec() == QDialog::Accepted) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); float offset[3]; int dim[3]; float origin[3]; float voxelSize[3]; svd.getSurfaceOffset(offset); svd.getVolumeDimensions(dim); svd.getVolumeVoxelSizes(voxelSize); svd.getVolumeOrigin(origin); BrainModelSurfaceToVolumeConverter stv(theMainWindow->getBrainSet(), svd.getSelectedSurface(), svd.getStandardVolumeSpace(), offset, dim, voxelSize, origin, svd.getSurfaceInnerBoundary(), svd.getSurfaceOuterBoundary(), svd.getSurfaceThicknessStep(), BrainModelSurfaceToVolumeConverter::CONVERT_TO_ROI_VOLUME_USING_ROI_NODES); stv.setNodeToVoxelMappingEnabled(svd.getNodeToVoxelMappingEnabled(), svd.getNodeToVoxelMappingFileName()); try { stv.execute(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "Error", e.whatQString()); return; } theMainWindow->speakText("The region of interest volume has been created.", false); GuiFilesModified fm; fm.setVolumeModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); } } /** * Called when a metric mode is selected. */ void GuiSurfaceRegionOfInterestDialogOLD::slotMetricModeSelection(int metricMode) { if (metricMode == 1) { theMainWindow->getBrainModelOpenGL()->setMouseMode( GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_METRIC_NODE_SELECT); } } /** * Called when paint name push button is selected. */ void GuiSurfaceRegionOfInterestDialogOLD::slotPaintNameFromListPushButton() { GuiPaintColumnNamesListBoxSelectionDialog pd(this, paintWithNameCategoryComboBox->currentIndex()); if (pd.exec() == QDialog::Accepted) { setPaintIndexForQuery(pd.getSelectedItemIndex()); } } /** * Called when paint name from mouse push button is selected. */ void GuiSurfaceRegionOfInterestDialogOLD::slotPaintNameFromMousePushButton() { theMainWindow->getBrainModelOpenGL()->setMouseMode( GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_PAINT_INDEX_SELECT); } /** * Called when border name from mouse push button is pressed. */ void GuiSurfaceRegionOfInterestDialogOLD::slotBorderNameFromMousePushButton() { theMainWindow->getBrainModelOpenGL()->setMouseMode( GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_BORDER_SELECT); } /** * Called when border name push from list button is pressed. */ void GuiSurfaceRegionOfInterestDialogOLD::slotBorderNameFromListPushButton() { GuiBorderNamesListBoxSelectionDialog bs(this, selectedBorderName); if (bs.exec() == QDialog::Accepted) { setBorderNameForQuery(bs.getSelectedText()); } } /** * Called when a query mode selection is made. */ void GuiSurfaceRegionOfInterestDialogOLD::slotSelectionMode(int item) { selectionModeComboBox->setCurrentIndex(item); selectionMode = static_cast(item); const bool havePaints = (theMainWindow->getBrainSet()->getPaintFile()->getNumberOfColumns() > 0); BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); bool haveBorders = bmbs->getNumberOfBorders(); const bool haveLatLon = (theMainWindow->getBrainSet()->getLatLonFile()->getNumberOfColumns() > 0); const bool haveMetrics = (theMainWindow->getBrainSet()->getMetricFile()->getNumberOfColumns() > 0); const bool haveShape = (theMainWindow->getBrainSet()->getSurfaceShapeFile()->getNumberOfColumns() > 0); // // Disable items initially nodesWithPaintQVBox->setEnabled(false); nodesWithinBorderQVBox->setEnabled(false); nodesWithMetricQVBox->setEnabled(false); // // Enable dialog items based upon mode. // switch(selectionMode) { case SELECTION_MODE_ENTIRE_SURFACE: queryControlWidgetStack->setCurrentWidget(queryEntireSurfaceWidget); break; case SELECTION_MODE_NODES_WITH_PAINT: nodesWithPaintQVBox->setEnabled(havePaints); queryControlWidgetStack->setCurrentWidget(nodesWithPaintQVBox); break; case SELECTION_MODE_NODES_WITHIN_BORDER: nodesWithinBorderQVBox->setEnabled(haveBorders); queryControlWidgetStack->setCurrentWidget(nodesWithinBorderQVBox); break; case SELECTION_MODE_NODES_WITHIN_LATLON: nodesWithinLatLonQVBox->setEnabled(haveLatLon); queryControlWidgetStack->setCurrentWidget(nodesWithinLatLonQVBox); break; case SELECTION_MODE_NODES_WITH_METRIC: nodesWithMetricQVBox->setEnabled(haveMetrics); queryControlWidgetStack->setCurrentWidget(nodesWithMetricQVBox); break; case SELECTION_MODE_NODES_WITH_SHAPE: nodesWithShapeQVBox->setEnabled(haveShape); queryControlWidgetStack->setCurrentWidget(nodesWithShapeQVBox); break; case SELECTION_MODE_NODES_WITH_CROSSOVERS: queryControlWidgetStack->setCurrentWidget(nodesWithCrossoversWidget); break; case SELECTION_MODE_NONE: break; } } /** * Create the attributes page */ void GuiSurfaceRegionOfInterestDialogOLD::createAttributeSelectionPage() { // // Create the output page. // attributesPage = new QWidget; attributesPage->setMinimumSize(300, 300); tabWidget->addTab(attributesPage, "Attributes"); // // Vertical layout output groups // QVBoxLayout* attributesLayout = new QVBoxLayout(attributesPage); attributesLayout->setMargin(3); attributesLayout->setSpacing(3); // // Scrolling widget and QWidget for output selections // //scrollView->setMinimumSize(400, 400); QWidget* outputScrolledContents = new QWidget; QScrollArea* scrollView = new QScrollArea; attributesLayout->addWidget(scrollView); scrollView->setWidget(outputScrolledContents); scrollView->setWidgetResizable(true); // // Vertical layout output groups // QVBoxLayout* outputLayout = new QVBoxLayout(outputScrolledContents); outputLayout->setMargin(3); outputLayout->setSpacing(3); // // Metric All On/Off buttons // QPushButton* metricAllOnPushButton = new QPushButton("All On"); metricAllOnPushButton->setAutoDefault(false); QObject::connect(metricAllOnPushButton, SIGNAL(clicked()), this, SLOT(slotMetricAllOnPushButton())); QPushButton* metricAllOffPushButton = new QPushButton("All Off"); metricAllOffPushButton->setAutoDefault(false); QObject::connect(metricAllOffPushButton, SIGNAL(clicked()), this, SLOT(slotMetricAllOffPushButton())); QtUtilities::makeButtonsSameSize(metricAllOnPushButton, metricAllOffPushButton); QHBoxLayout* metricHBoxLayout = new QHBoxLayout; metricHBoxLayout->addWidget(metricAllOnPushButton); metricHBoxLayout->addWidget(metricAllOffPushButton); metricHBoxLayout->addStretch(); // // Vertical group box for metric selections // QGroupBox* metricOutputGroupBox = new QGroupBox("Metric Categories"); metricOutputLayout = new QVBoxLayout(metricOutputGroupBox); outputLayout->addWidget(metricOutputGroupBox); metricOutputLayout->addLayout(metricHBoxLayout); // // All On/Off buttons // QPushButton* paintAllOnPushButton = new QPushButton("All On"); paintAllOnPushButton->setAutoDefault(false); QObject::connect(paintAllOnPushButton, SIGNAL(clicked()), this, SLOT(slotPaintAllOnPushButton())); QPushButton* paintAllOffPushButton = new QPushButton("All Off"); paintAllOffPushButton->setAutoDefault(false); QObject::connect(paintAllOffPushButton, SIGNAL(clicked()), this, SLOT(slotPaintAllOffPushButton())); QtUtilities::makeButtonsSameSize(paintAllOnPushButton, paintAllOffPushButton); QHBoxLayout* paintHBoxLayout = new QHBoxLayout; paintHBoxLayout->addWidget(paintAllOnPushButton); paintHBoxLayout->addWidget(paintAllOffPushButton); paintHBoxLayout->addStretch(); // // Vertical group box for paint selections // QGroupBox* paintOutputGroupBox = new QGroupBox("Paint Categories"); paintOutputLayout = new QVBoxLayout(paintOutputGroupBox); outputLayout->addWidget(paintOutputGroupBox); paintOutputLayout->addLayout(paintHBoxLayout); // // Shape All On/Off buttons // QPushButton* shapeAllOnPushButton = new QPushButton("All On"); shapeAllOnPushButton->setAutoDefault(false); QObject::connect(shapeAllOnPushButton, SIGNAL(clicked()), this, SLOT(slotShapeAllOnPushButton())); QPushButton* shapeAllOffPushButton = new QPushButton("All Off"); shapeAllOffPushButton->setAutoDefault(false); QObject::connect(shapeAllOffPushButton, SIGNAL(clicked()), this, SLOT(slotShapeAllOffPushButton())); QtUtilities::makeButtonsSameSize(shapeAllOnPushButton, shapeAllOffPushButton); QHBoxLayout* shapeHBoxLayout = new QHBoxLayout; shapeHBoxLayout->addWidget(shapeAllOnPushButton); shapeHBoxLayout->addWidget(shapeAllOffPushButton); shapeHBoxLayout->addStretch(); // // Vertical group box for shape selections // QGroupBox* surfaceShapeOutputGroupBox = new QGroupBox("Surface Shape Categories"); shapeOutputLayout = new QVBoxLayout(surfaceShapeOutputGroupBox); outputLayout->addWidget(surfaceShapeOutputGroupBox); shapeOutputLayout->addLayout(shapeHBoxLayout); // // Squish the items together // //outputScrolledContents->setMinimumSize(outputScrolledContents->sizeHint()); } /** * Called when metric all on pushbutton is pressed. */ void GuiSurfaceRegionOfInterestDialogOLD::slotMetricAllOnPushButton() { for (int i = 0; i < static_cast(metricCheckBoxes.size()); i++) { metricCheckBoxes[i]->setChecked(true); } } /** * Called when metric all off pushbutton is pressed. */ void GuiSurfaceRegionOfInterestDialogOLD::slotMetricAllOffPushButton() { for (int i = 0; i < static_cast(metricCheckBoxes.size()); i++) { metricCheckBoxes[i]->setChecked(false); } } /** * Called when paint all on pushbutton is pressed. */ void GuiSurfaceRegionOfInterestDialogOLD::slotPaintAllOnPushButton() { for (int i = 0; i < static_cast(paintCheckBoxes.size()); i++) { paintCheckBoxes[i]->setChecked(true); } } /** * Called when paint all off pushbutton is pressed. */ void GuiSurfaceRegionOfInterestDialogOLD::slotPaintAllOffPushButton() { for (int i = 0; i < static_cast(paintCheckBoxes.size()); i++) { paintCheckBoxes[i]->setChecked(false); } } /** * Called when shape all on pushbutton is pressed. */ void GuiSurfaceRegionOfInterestDialogOLD::slotShapeAllOnPushButton() { for (int i = 0; i < static_cast(surfaceShapeCheckBoxes.size()); i++) { surfaceShapeCheckBoxes[i]->setChecked(true); } } /** * Called when shape all off pushbutton is pressed. */ void GuiSurfaceRegionOfInterestDialogOLD::slotShapeAllOffPushButton() { for (int i = 0; i < static_cast(surfaceShapeCheckBoxes.size()); i++) { surfaceShapeCheckBoxes[i]->setChecked(false); } } /** * Create the report page. */ void GuiSurfaceRegionOfInterestDialogOLD::createReportPage() { // // Create the query page // reportPage = new QWidget; tabWidget->addTab(reportPage, "Report"); // // Layout for page // QVBoxLayout* layout = new QVBoxLayout(reportPage); layout->setMargin(3); layout->setSpacing(3); // // Font for text edit // //QFont font("Fixed", 12); QFont font("Monaco", 12); // // Report text editor // reportTextEdit = new QTextEdit; reportTextEdit->setLineWrapMode(QTextEdit::NoWrap); reportTextEdit->setFont(font); layout->addWidget(reportTextEdit); // // Layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(3); layout->addLayout(buttonsLayout); // // Buttons // QPushButton* clearPushButton = new QPushButton("Clear"); clearPushButton->setAutoDefault(false); buttonsLayout->addWidget(clearPushButton); QObject::connect(clearPushButton, SIGNAL(clicked()), this, SLOT(slotClearPushButton())); QPushButton* savePushButton = new QPushButton("Save To File..."); savePushButton->setAutoDefault(false); buttonsLayout->addWidget(savePushButton); QObject::connect(savePushButton, SIGNAL(clicked()), this, SLOT(slotSavePushButton())); QtUtilities::makeButtonsSameSize(clearPushButton, savePushButton); } /** * slot called when report push button pressed. */ void GuiSurfaceRegionOfInterestDialogOLD::slotClearPushButton() { reportTextEdit->clear(); } /** * slot called when report push button pressed. */ void GuiSurfaceRegionOfInterestDialogOLD::slotSavePushButton() { WuQFileDialog fd(this); fd.setModal(true); fd.setDirectory(QDir::currentPath()); fd.setAcceptMode(WuQFileDialog::AcceptSave); fd.setWindowTitle("Choose ROI Text File Name"); fd.setFilter("Text Files (*.txt)"); fd.setFileMode(WuQFileDialog::AnyFile); if (fd.exec() == QDialog::Accepted) { if (fd.selectedFiles().count() > 0) { const QString fileName = fd.selectedFiles().at(0); QFile file(fileName); if (file.open(QIODevice::WriteOnly)) { QTextStream stream(&file); stream << reportTextEdit->toPlainText(); file.close(); } else { QString msg("Unable to open for writing: "); msg.append(fileName); QMessageBox::critical(this, "Error Opening File", msg); } } } } /** * Update the section with the node attribute file */ void GuiSurfaceRegionOfInterestDialogOLD::updateNodeAttributeGroupBox( QVBoxLayout* layout, std::vector& checkBoxes, NodeAttributeFile* naf) { const int numColumns = naf->getNumberOfColumns(); const int numExistingButtons = checkBoxes.size(); // // save existing selections // std::map currentSelections; const int maxButton = std::min(numExistingButtons, numColumns); for (int i = 0; i < maxButton; i++) { currentSelections[naf->getColumnName(i)] = checkBoxes[i]->isChecked(); } // // Load up with current columns // for (int i = 0; i < numColumns; i++) { if (i < numExistingButtons) { checkBoxes[i]->setText(naf->getColumnName(i)); checkBoxes[i]->show(); checkBoxes[i]->setChecked(true); std::map::iterator iter = currentSelections.find(naf->getColumnName(i)); if (iter != currentSelections.end()) { checkBoxes[i]->setChecked(iter->second); } } else { QCheckBox* checkBox = new QCheckBox(naf->getColumnName(i)); checkBox->setChecked(true); checkBoxes.push_back(checkBox); layout->addWidget(checkBox); } } // // Hide unneeded radio buttons // for (int i = numColumns; i < numExistingButtons; i++) { checkBoxes[i]->hide(); } } /** * Update the section with the node attribute file */ void GuiSurfaceRegionOfInterestDialogOLD::updateNodeAttributeGroupBox( QVBoxLayout* layout, std::vector& checkBoxes, GiftiNodeDataFile* naf) { const int numColumns = naf->getNumberOfColumns(); const int numExistingButtons = checkBoxes.size(); // // save existing selections // std::map currentSelections; const int maxButton = std::min(numExistingButtons, numColumns); for (int i = 0; i < maxButton; i++) { currentSelections[naf->getColumnName(i)] = checkBoxes[i]->isChecked(); } // // Load up with current columns // for (int i = 0; i < numColumns; i++) { if (i < numExistingButtons) { checkBoxes[i]->setText(naf->getColumnName(i)); checkBoxes[i]->show(); checkBoxes[i]->setChecked(true); std::map::iterator iter = currentSelections.find(naf->getColumnName(i)); if (iter != currentSelections.end()) { checkBoxes[i]->setChecked(iter->second); } } else { QCheckBox* checkBox = new QCheckBox(naf->getColumnName(i)); checkBox->setChecked(true); checkBoxes.push_back(checkBox); layout->addWidget(checkBox); } } // // Hide unneeded radio buttons // for (int i = numColumns; i < numExistingButtons; i++) { checkBoxes[i]->hide(); } } /** * Set border name for query. */ void GuiSurfaceRegionOfInterestDialogOLD::setBorderNameForQuery(const QString& name) { selectedBorderName = name; borderNameSelectedLabel->setText(selectedBorderName); } /** * Set paint index for query. */ void GuiSurfaceRegionOfInterestDialogOLD::setPaintIndexForQuery(const int paintIndex) { paintWithNameIndex = paintIndex; PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); paintWithNameSelectedLabel->setText(pf->getPaintNameFromIndex(paintWithNameIndex)); } /** * Set the node for a metric query. */ void GuiSurfaceRegionOfInterestDialogOLD::setMetricNodeForQuery(const int metricNodeForQueryIn) { BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms == NULL) { return; } metricNodeForQuery = metricNodeForQueryIn; MetricFile* mf = theMainWindow->getBrainSet()->getMetricFile(); if (mf->getNumberOfColumns() <= 0) { QMessageBox::critical(this, "Error", "There are no metric columns."); return; } const int column = metricCategoryComboBox->currentIndex(); if ((column < 0) || (column >= mf->getNumberOfColumns())) { QMessageBox::critical(this, "Error", "Metric column is invalid."); return; } std::ostringstream str; str << " Node Number: " << metricNodeForQuery << " Metric " << QString::number(mf->getValue(metricNodeForQuery, column), 'f', 6).toAscii().constData(); metricNodeNumberLabel->setText(str.str().c_str()); } /** * Set the node for a shape query. */ void GuiSurfaceRegionOfInterestDialogOLD::setShapeNodeForQuery(const int shapeNodeForQueryIn) { BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms == NULL) { return; } shapeNodeForQuery = shapeNodeForQueryIn; SurfaceShapeFile* ssf = theMainWindow->getBrainSet()->getSurfaceShapeFile(); if (ssf->getNumberOfColumns() <= 0) { QMessageBox::critical(this, "Error", "There are no shape columns."); return; } const int column = shapeCategoryComboBox->currentIndex(); if ((column < 0) || (column >= ssf->getNumberOfColumns())) { QMessageBox::critical(this, "Error", "Column is invalid."); return; } std::ostringstream str; str << " Node Number: " << shapeNodeForQuery << " Shape " << QString::number(ssf->getValue(shapeNodeForQuery, column), 'f', 6).toAscii().constData(); shapeNodeNumberLabel->setText(str.str().c_str()); } /** * Get the paint query column. */ int GuiSurfaceRegionOfInterestDialogOLD::getQueryPaintColumn() const { return paintWithNameCategoryComboBox->currentIndex(); } /** * */ void GuiSurfaceRegionOfInterestDialogOLD::slotSurfaceSelection() { BrainModelSurface* bms = operationSurfaceComboBox->getSelectedBrainModelSurface(); if (bms != NULL) { const TopologyFile* tf = bms->getTopologyFile(); if (tf != NULL) { // topologyComboBox->setSelectedTopologyFile(tf); } } } /** * Called when topology is changed. */ /* void GuiSurfaceRegionOfInterestDialogOLD::slotTopologySelection() { BrainModelSurface* bms = operationSurfaceComboBox->getSelectedBrainModelSurface(); if (bms != NULL) { if (topologyComboBox->getSelectedTopologyFile() != bms->getTopologyFile()) { TopologyFile* oldTopologyFile = bms->getTopologyFile(); if (bms->setTopologyFile(topologyComboBox->getSelectedTopologyFile())) { std::ostringstream str; str << "Topology File " << FileUtilities::basename(bms->getTopologyFile()->getFileName()).toAscii().constData() << "\n is not for use with coordinate file " << FileUtilities::basename(bms->getCoordinateFile()->getFileName()).toAscii().constData() << ".\n Topo file has tiles with node numbers exceeding \n" << "the number of coordinates in the coordinate file."; bms->setTopologyFile(oldTopologyFile); QMessageBox::critical(this, "ERROR", str.str().c_str()); return; } GuiFilesModified fm; fm.setCoordinateModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(NULL); } } } */ /** * Update the dialog. */ void GuiSurfaceRegionOfInterestDialogOLD::updateDialog() { // // Update border surface combo box // borderSurfaceComboBox->updateComboBox(); // // update query surface combo box // operationSurfaceComboBox->updateComboBox(); slotSurfaceSelection(); // // Update metric distortion // distortionCorrectionMetricColumnComboBox->updateComboBox(); // // update topology combo box // // topologyComboBox->updateComboBox(); // slotTopologySelection(); // // Initialize the query mode // slotSelectionMode(selectionMode); // // Reset paints // paintWithNameIndex = -1; PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); const QString paintName(paintWithNameSelectedLabel->text()); if (paintName.isEmpty() == false) { paintWithNameIndex = pf->getPaintIndexFromName(paintName); } paintWithNameSelectedLabel->setText(pf->getPaintNameFromIndex(paintWithNameIndex)); paintWithNameCategoryComboBox->updateComboBox(pf); metricCategoryComboBox->updateComboBox(); shapeCategoryComboBox->updateComboBox(); paintWithNameCategoryComboBox->updateComboBox(); paintRegionReportColumnComboBox->updateComboBox(); shapeClusterMetricArealDistortionComboBox->updateComboBox(); // // paint column assignment // paintColumnAssignComboBox->updateComboBox(pf); slotAssignPaintColumn(paintColumnAssignComboBox->currentIndex()); // // Update metric assignment // metricColumnAssignComboBox->updateComboBox(); // // Update surface shape assignment // surfaceShapeColumnAssignComboBox->updateComboBox(); // // Update geodesic // geodesicDistanceColumnComboBox->updateComboBox(); geodesicMetricColumnComboBox->updateComboBox(); // // Reset borders // bool haveBorderName = false; if (selectedBorderName.isEmpty() == false) { BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); const int numBorders = bmbs->getNumberOfBorders(); for (int j = 0; j < numBorders; j++) { if (bmbs->getBorder(j)->getName() == selectedBorderName) { haveBorderName = true; break; } } } if (haveBorderName == false) { selectedBorderName = ""; } borderNameSelectedLabel->setText(selectedBorderName); // // Update paint region column // paintRegionReportColumnComboBox->updateComboBox(); updateNodeAttributeGroupBox(metricOutputLayout, metricCheckBoxes, theMainWindow->getBrainSet()->getMetricFile()); updateNodeAttributeGroupBox(paintOutputLayout, paintCheckBoxes, theMainWindow->getBrainSet()->getPaintFile()); updateNodeAttributeGroupBox(shapeOutputLayout, surfaceShapeCheckBoxes, theMainWindow->getBrainSet()->getSurfaceShapeFile()); updateNumberOfSelectedNodesLabel(); shapeCorrelationColumnComboBox->updateComboBox(); } caret-5.6.4~dfsg.1.orig/caret/GuiSurfaceRegionOfInterestDialog.h0000664000175000017500000006457211572067322024372 0ustar michaelmichael #ifndef __GUI_SURFACE_REGION_OF_INTEREST_DIALOG_H__ #define __GUI_SURFACE_REGION_OF_INTEREST_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "WuQWizard.h" class BrainModelSurface; class CoordinateFile; class GuiBrainModelSelectionComboBox; class GuiNodeAttributeColumnSelectionComboBox; class GuiSurfaceROIOperationPage; class GuiSurfaceROINodeSelectionPage; class GuiSurfaceROIReportPage; class GuiSurfaceROISurfaceAndTopologySelectionPage; class GuiTopologyFileComboBox; class MetricFile; class QCheckBox; class QComboBox; class QDoubleSpinBox; class QLabel; class QLineEdit; class QSpinBox; class QRadioButton; class QStackedWidget; class QTextEdit; /// wizard dialog for surface region of interest operations class GuiSurfaceRegionOfInterestDialog: public WuQWizard { Q_OBJECT public: // constructor GuiSurfaceRegionOfInterestDialog(QWidget* parent); // destructor ~GuiSurfaceRegionOfInterestDialog(); // update the dialog (typically due to file changes) void updateDialog(); // set border name for query void setBorderNameForQuery(const QString& borderName); // set paint index for query void setPaintIndexForQuery(const int paintIndex); // set metric node for query void setMetricNodeForQuery(const int metricNodeForQueryIn); // set shape node for query void setShapeNodeForQuery(const int shapeNodeForQueryIn); // set node for geodesic query void setNodeForGeodesicQuery(const int nodeNumber); // set linear border start node void setCreateLinearBorderStartNode(const int nodeNumber); // set linear border end node void setCreateLinearBorderEndNode(const int nodeNumber); // get the query paint column int getQueryPaintColumn() const; // get the operation coordinate file CoordinateFile* getOperationCoordinateFile(); // get a COPY of operation surface with operation topology (user must delete object) BrainModelSurface* getCopyOfOperationSurface(); public slots: // show the dialog void show(); // called when dialog closed void reject(); protected: // page identifiers enum PAGE_ID { // operation surface page identifier PAGE_ID_OPERATION_SURFACE_AND_TOPOLOGY, // node selection page identifier PAGE_ID_NODE_SELECTION, // operation page PAGE_ID_OPERATION, // report page PAGE_ID_REPORT }; // node selection page GuiSurfaceROINodeSelectionPage* roiNodeSelectionPage; // surface selection page GuiSurfaceROISurfaceAndTopologySelectionPage* surfaceSelectionPage; // operation page GuiSurfaceROIOperationPage* operationPage; // report page GuiSurfaceROIReportPage* reportPage; }; /// surface region of interest report page class GuiSurfaceROIReportPage : public QWizardPage { Q_OBJECT public: // constructor GuiSurfaceROIReportPage(GuiSurfaceRegionOfInterestDialog* roiDialogIn); // destructor ~GuiSurfaceROIReportPage(); // clean up the page void cleanupPage(); // initialize the page void initializePage(); // validate the page bool validatePage(); // is page complete bool isComplete(); // update the page void updatePage(); // set the report page's text edit void setReportText(const QString& S); protected slots: // called when save report to text file button pressed void slotSaveReportToTextFile(); // called when clear report button pressed void slotClearReportTextEdit(); protected: /// parent ROI dialog GuiSurfaceRegionOfInterestDialog* roiDialog; // the report text edit QTextEdit* reportTextEdit; }; /// surface region of interest operation page class GuiSurfaceROIOperationPage : public QWizardPage { Q_OBJECT public: // constructor GuiSurfaceROIOperationPage(GuiSurfaceRegionOfInterestDialog* roiDialogIn, GuiSurfaceROIReportPage* reportPageIn); // destructor ~GuiSurfaceROIOperationPage(); // clean up the page void cleanupPage(); // initialize the page void initializePage(); // validate the page bool validatePage(); // is page complete bool isComplete(); // update the page void updatePage(); protected slots: // called when an operation is selected void slotOperationSelectionComboBox(int); // called to assign metric void slotAssignMetricPushButton(); // called to assign node areas to metric void slotNodeAreaMetricPushButton(); // called to assign paint void slotAssignPaintPushButton(); // called to assign shape void slotAssignShapePushButton(); /// called to run compute integrated folding index void slotComputeIntegratedFoldingIndex(); /// called to run the folding measurements void slotFoldingMeasurements(); /// Called to set create borders from clusters name. void slotArealBorderClusterNamePushButton(); /// Called run create borders from clusters. void slotCreateArealBordersFromClusters(); /// Called to set linear border name void slotLinearCreateBorderFromROINamePushButton(); /// called to set linear border start node void slotCreateLinearBorderFromROIStartNodePushButton(); /// called to set linear border end node void slotCreateLinearBorderFromROIEndNodePushButton(); /// called to create the linear border void slotCreateLinearBorderFromROIPushButton(); /// called to create a volume ROI from ROI nodes void slotCreateVolumeFromQueryNodesButton(); /// called to disconnect node in ROI void slotDisconnectNodes(); /// called to update geodesic column names void slotGeodesicUpdateColumnNames(); /// called when geodesic choose node with mouse button pressed void slotGeodesicNodePushButton(); /// called to create geodesic void slotGeodesicPushButton(); /// called to generate prob atlas overlap report void slotCreateProbAtlasOverlapReport(); /// called to smooth nodes void slotSmoothNodesPushButtonPressed(); /// called to create paint region report void slotCreatePaintReportButton(); /// called to create statistical report void slotCreateStatisticalReportButton(); /// called to create shape correleation report void slotCorrelationShapeReportPushButton(); /// called to create shape cluster report void slotShapeClusterReportPushButton(); /// called to create metric cluster report void slotMetricClusterReportPushButton(); protected: /// operation mode enum OPERATION_MODE { OPERATION_MODE_ASSIGN_METRIC, OPERATION_MODE_ASSIGN_METRIC_NODE_AREAS, OPERATION_MODE_ASSIGN_PAINT, OPERATION_MODE_ASSIGN_SURFACE_SHAPE, OPERATION_MODE_COMPUTE_INTEGRATED_FOLDING_INDEX, OPERATION_MODE_CREATE_BORDERS_FROM_CLUSTERS, OPERATION_MODE_CREATE_BORDERS_FROM_ROI, OPERATION_MODE_CREATE_VOLUME_ROI, OPERATION_MODE_DISCONNECT_NODES, OPERATION_MODE_FOLDING_MEASUREMENTS, OPERATION_MODE_GEODESIC, OPERATION_MODE_METRIC_CLUSTER_ANALYSIS, OPERATION_MODE_PROB_ATLAS_OVERLAP, OPERATION_MODE_SMOOTH_NODES, OPERATION_MODE_STATISTICAL_PAINT_REPORT, OPERATION_MODE_STATISTICAL_REPORT, OPERATION_MODE_SHAPE_CORRELATION, OPERATION_MODE_SHAPE_CLUSTER_ANALYSIS }; // create the assign metric page QWidget* createAssignMetricPage(); // create the assign paint page QWidget* createAssignPaintPage(); // create the assign shape page QWidget* createAssignShapePage(); // create the compute integrated folding index page QWidget* createComputeIntegratedFoldingIndexPage(); // create the folding measurements page QWidget* createFoldingMeasurementsPage(); // create the create borders from clusters page QWidget* createCreateArealBordersPage(); // create the create linear borders page QWidget* createLinearBordersPage(); // create the create volume roi page QWidget* createCreateVolumeROIPage(); // create the disconnect nodes page QWidget* createDisconnectNodesPage(); // create the geodesic page QWidget* createGeodesicPage(); // create the metric cluster analysis page QWidget* createMetricClusterAnalysisPage(); // create the probabilistic atlas overlap page QWidget* createProbAtlasOverlapPage(); // create the smoothing page QWidget* createSmoothingPage(); // create the statistical paint report page QWidget* createPaintReportPage(); // create the statistical report page QWidget* createStatisticalReportPage(); // create the shape correlation page QWidget* createShapeCorrelationPage(); // create the shape cluster analysis page QWidget* createShapeClusterAnalysisPage(); // create the node areas page QWidget* createNodeAreasPage(); // run a metric or shape cluster report void runMetricShapeClusterAnalysis(MetricFile* metricShapeFile, MetricFile* distortionMetricFile, const int distortionMetricColumn, const std::vector& metricShapeColumnsSelected, const float thresholdValue, const bool separateReportWithSemicolonsFlag); /// parent ROI dialog GuiSurfaceRegionOfInterestDialog* roiDialog; /// the report page GuiSurfaceROIReportPage* reportPage; /// operation selection combo box QComboBox* operationSelectionComboBox; /// stacked widget for operations QStackedWidget* operationsStackedWidget; /// the assign metric page QWidget* assignMetricPage; /// the assign node areas page QWidget* nodeAreaMetricPage; /// the assign paint page QWidget* assignPaintPage; /// the assign shape page QWidget* assignShapePage; /// the compute integrated folding index page QWidget* computeIntegratedFoldingIndexPage; /// the create borders from clusters page QWidget* createArealBordersPage; /// the folding measurements page QWidget* foldingMeasurementsPage; /// the create linear borders page QWidget* linearBordersPage; /// the create volume roi page QWidget* createVolumeROIPage; /// the disconnect nodes page QWidget* disconnectNodesPage; /// the geodesic page QWidget* geodesicPage; /// the metric cluster analysis page QWidget* metricClusterAnalysisPage; /// the probabilistic atlas overlap page QWidget* probAtlasOverlapPage; /// the smoothing page QWidget* smoothingPage; /// the statistical paint report page QWidget* paintReportPage; /// the statistical report page QWidget* statisticalReportPage; /// the shape correlation page QWidget* shapeCorrelationPage; /// the shape cluster analysis page QWidget* shapeClusterAnalysisPage; /// assign metric column selection GuiNodeAttributeColumnSelectionComboBox* assignMetricColumnSelectionComboBox; /// assign metric column name line edit QLineEdit* assignMetricColumnNameLineEdit; /// assign metric value double spin box QDoubleSpinBox* assignMetricValueDoubleSpinBox; /// node area column selection GuiNodeAttributeColumnSelectionComboBox* nodeAreaMetricColumnSelectionComboBox; /// node area column name line edit QLineEdit* nodeAreaMetricColumnNameLineEdit; /// node area percentage check box QCheckBox* nodeAreaPercentageCheckBox; /// assign paint column selection GuiNodeAttributeColumnSelectionComboBox* assignPaintColumnSelectionComboBox; /// assign paint column name line edit QLineEdit* assignPaintColumnNameLineEdit; /// assign paint name line edit QLineEdit* assignPaintNameLineEdit; /// assign shape column selection GuiNodeAttributeColumnSelectionComboBox* assignShapeColumnSelectionComboBox; /// assign shape column name line edit QLineEdit* assignShapeColumnNameLineEdit; /// assign shape value double spin box QDoubleSpinBox* assignShapeValueDoubleSpinBox; /// semicolon separet integrated folding index report QCheckBox* semicolonSeparateFoldingIndexReportCheckBox; /// areal border name line edit QLineEdit* clusterArealBorderNameLineEdit; /// areal border auto project check box QCheckBox* clusterArealBorderAutoProjectCheckBox; /// linear border name line edit QLineEdit* createLinearBorderFromROINameLineEdit; /// linear border sampling density double spin box QDoubleSpinBox* createLinearBorderFromROISamplingDensityDoubleSpinBox; /// linear border automatic radio button QRadioButton* createLinearBorderFromROIAutomaticRadioButton; /// linear border manual radio button QRadioButton* createLinearBorderFromROIManualRadioButton; /// linear border start node spin box QSpinBox* createLinearBorderFromROIStartNodeSpinBox; /// linear border end node spin box QSpinBox* createLinearBorderFromROIEndNodeSpinBox; /// geodesic node spin box QSpinBox* geodesicNodeSpinBox; /// geodesic's metric column selection GuiNodeAttributeColumnSelectionComboBox* geodesicMetricColumnComboBox; /// geodesic's metric column name line edit QLineEdit* geodesicMetricColumnNameLineEdit; /// geodesic's geodesic column selection GuiNodeAttributeColumnSelectionComboBox* geodesicDistanceColumnComboBox; /// geodesic's geodesic column name line edit QLineEdit* geodesicDistanceColumnNameLineEdit; /// prob atlas overlap separate with semicolons check box QCheckBox* probAtlasOverlapSemicolonSeparateCheckBox; /// paint region report's paint column selection combo box GuiNodeAttributeColumnSelectionComboBox* paintRegionReportColumnComboBox; /// paint report metric column areal distortion GuiNodeAttributeColumnSelectionComboBox* paintRegionReportDistortionCorrectionMetricColumnComboBox; /// paint region report separate with semicolons QCheckBox* paintReportSeparateWithSemicolonsCheckBox; /// statistical report metric column areal distortion GuiNodeAttributeColumnSelectionComboBox* statisticalReportDistortionCorrectionMetricColumnComboBox; /// statistical report separate with semicolons QCheckBox* statisticalReportSeparateWithSemicolonsCheckBox; /// shape correlation combo box GuiNodeAttributeColumnSelectionComboBox* shapeCorrelationColumnComboBox; /// shape correlation report separate with semicolons QCheckBox* shapeCorrelationSeparateWithSemicolonsCheckBox; /// shape cluster metric distortion column combo box GuiNodeAttributeColumnSelectionComboBox* shapeClusterMetricArealDistortionComboBox; /// shape cluster threshold double spin box QDoubleSpinBox* shapeClusterThresholdDoubleSpinBox; /// shape cluster report separate with semicolons QCheckBox* shapeClusterSeparateWithSemicolonsCheckBox; /// metric cluster metric distortion column combo box GuiNodeAttributeColumnSelectionComboBox* metricClusterMetricArealDistortionComboBox; /// metric cluster threshold double spin box QDoubleSpinBox* metricClusterThresholdDoubleSpinBox; /// metric cluster report separate with semicolons QCheckBox* metricClusterSeparateWithSemicolonsCheckBox; QCheckBox* foldingMeasurementsMetricFileCheckBox; QLineEdit* foldingMeasurementsMetricFileNameLineEdit; friend class GuiSurfaceRegionOfInterestDialog; }; /// surface region of interest surface topology selection page class GuiSurfaceROISurfaceAndTopologySelectionPage : public QWizardPage { Q_OBJECT public: // constructor GuiSurfaceROISurfaceAndTopologySelectionPage(GuiSurfaceRegionOfInterestDialog* roiDialogIn); // destructor ~GuiSurfaceROISurfaceAndTopologySelectionPage(); // clean up the page void cleanupPage(); // initialize the page void initializePage(); // validate the page bool validatePage(); // is page complete bool isComplete(); // update the page void updatePage(); // get the operation coordinate file CoordinateFile* getOperationCoordinateFile(); // get a COPY of operation surface with operation topology (user must delete object) BrainModelSurface* getCopyOfOperationSurface(); protected slots: // called when a surface is selected void slotOperationSurfaceSelectionComboBox(); // called when topology is selected void slotOperationTopologyComboBox(); protected: // parent ROI dialog GuiSurfaceRegionOfInterestDialog* roiDialog; /// operation surface selection control GuiBrainModelSelectionComboBox* operationSurfaceSelectionComboBox; /// operation topology selection control GuiTopologyFileComboBox* operationTopologyComboBox; }; /// surface region of interest node selection page class GuiSurfaceROINodeSelectionPage : public QWizardPage { Q_OBJECT public: // constructor GuiSurfaceROINodeSelectionPage(GuiSurfaceRegionOfInterestDialog* roiDialogIn); // destructor ~GuiSurfaceROINodeSelectionPage(); // clean up the page void cleanupPage(); // initialize the page void initializePage(); // validate the page bool validatePage(); // is page complete bool isComplete(); // update the page void updatePage(); protected slots: // called when a selection source is made void slotSelectionSourceComboBox(int); // called when select nodes push button pressed void slotSelectedNodesPushButton(); // called when delselect nodes push button pressed void slotDeselectNodesPushButton(); // called when invert push button pressed void slotInvertNodesPushButton(); // called when load ROI push button pressed void slotLoadROIPushButton(); // called when save ROI push button pressed void slotSaveROIPushButton(); // called when dilate ROI push button pressed void slotDilateROIPushButton(); // called when erode ROI push button pressed void slotErodeROIPushButton(); // called when extent push button pressed void slotExtentPushButton(); // called when remove islands button pressed void slotRemoveIslands(); // called when paint name from list pushbutton pressed void slotSelectPaintNameFromListPushButton(); // called when paint select node with mouse pushbutton pressed void slotSelectPaintNameNodeWithMousePushButton(); // called when border name from list pushbutton pressed void slotSelectBorderNameFromListPushButton(); // called when border select with mouse pushbutton pressed void slotSelectBorderNameWithMousePushButton(); // called when metric threshold radio button clicked void slotMetricSelectionButtonGroup(); // called when shape threshold radio button clicked void slotShapeSelectionButtonGroup(); // update selected number of nodes label void updateNumberOfSelectedNodesLabel(); // called when show selected nodes checkbox toggled void slotShowSelectedNodesCheckBox(bool); protected: /// selection source (source of node selection) enum SELECTION_SOURCE { SELECTION_SOURCE_ALL_NODES, SELECTION_SOURCE_NODES_WITHIN_BORDER, SELECTION_SOURCE_NODES_WITH_CROSSOVERS, SELECTION_SOURCE_NODES_WITH_EDGES, SELECTION_SOURCE_NODES_WITHIN_LATLON, SELECTION_SOURCE_NODES_WITH_METRIC, SELECTION_SOURCE_NODES_WITH_PAINT, SELECTION_SOURCE_NODES_WITH_SHAPE }; // parent ROI dialog GuiSurfaceRegionOfInterestDialog* roiDialog; // create the node selection source options widget QStackedWidget* createNodeSelectionSourceOptionsWidget(); /// selection source combo box QComboBox* selectionSourceComboBox; /// selection logic combo box QComboBox* selectionLogicComboBox; /// number of nodes selected label QLabel* numberOfNodesSelectedLabel; /// show selected nodes check box QCheckBox* showSelectedNodesCheckBox; /// deselect nodes push button QPushButton* deselectNodesPushButton; /// dilate nodes push button QPushButton* dilateSelectedNodesPushButton; /// erode nodes push button QPushButton* erodeSelectedNodesPushButton; /// extend nodes push button QPushButton* extentPushButton; /// invert nodes push button QPushButton* invertSelectedNodesPushButton; /// remove islands nodes push button QPushButton* removeIslandsPushButton; /// load ROI push button QPushButton* loadROIPushButton; /// save ROI push button QPushButton* saveROIPushButton; /// selection options stacked widget QStackedWidget* selectionSourceOptionsStackedWidget; /// selection options for all nodes QWidget* selectionSourceOptionsAllNodesWidget; /// selection options for borders QWidget* selectionSourceOptionsBordersWidget; /// border flat surface selection control GuiBrainModelSelectionComboBox* borderFlatSurfaceSelectionComboBox; /// border name selection label QLabel* borderNameSelectionLabel; /// selection options for crossovers QWidget* selectionSourceOptionsCrossoversWidget; /// selection options for edges QWidget* selectionSourceOptionsEdgesWidget; /// selection options for lat/long QWidget* selectionSourceOptionsLatLongWidget; /// lat min double spin box QDoubleSpinBox* latLowerRangeDoubleSpinBox; /// lat max double spin box QDoubleSpinBox* latUpperRangeDoubleSpinBox; /// lon min double spin box QDoubleSpinBox* lonLowerRangeDoubleSpinBox; /// lon min double spin box QDoubleSpinBox* lonUpperRangeDoubleSpinBox; /// selection options for metric QWidget* selectionSourceOptionsMetricWidget; /// metric column selection combo box GuiNodeAttributeColumnSelectionComboBox* metricColumnSelectionComboBox; /// metric range lower double spin box; QDoubleSpinBox* metricSelectionLowerDoubleSpinBox; /// metric range upper double spin box; QDoubleSpinBox* metricSelectionUpperDoubleSpinBox; /// metric selection all nodes radio button QRadioButton* metricSelectionAllNodesRadioButton; /// metric selection connect to node with mouse radio button QRadioButton* metricSelectionConnectedToNodeRadioButton; /// metric selection node number label QLabel* metricSelectionNodeNumberLabel; /// metric selection node value label QLabel* metricSelectionNodeValueLabel; /// selection options for paint QWidget* selectionSourceOptionsPaintWidget; /// paint column selection combo box GuiNodeAttributeColumnSelectionComboBox* paintColumnSelectionComboBox; /// paint name selection label QLabel* paintNameSelectionLabel; /// selection options for shape QWidget* selectionSourceOptionsShapeWidget; /// shape column selection combo box GuiNodeAttributeColumnSelectionComboBox* shapeColumnSelectionComboBox; /// shape range lower double spin box; QDoubleSpinBox* shapeSelectionLowerDoubleSpinBox; /// shape range upper double spin box; QDoubleSpinBox* shapeSelectionUpperDoubleSpinBox; /// shape selection all nodes radio button QRadioButton* shapeSelectionAllNodesRadioButton; /// shape selection connect to node with mouse radio button QRadioButton* shapeSelectionConnectedToNodeRadioButton; /// shape selection node number label QLabel* shapeSelectionNodeNumberLabel; /// shape selection node value label QLabel* shapeSelectionNodeValueLabel; friend class GuiSurfaceRegionOfInterestDialog; }; #endif // __GUI_SURFACE_REGION_OF_INTEREST_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiSurfaceRegionOfInterestDialog.cxx0000664000175000017500000047642511572067322024751 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "AreaColorFile.h" #include "BorderColorFile.h" #include "BrainModelBorderSet.h" #include "BrainModelSurfaceClusterToBorderConverter.h" #include "BrainModelSurfaceGeodesic.h" #include "BrainModelSurfaceNodeColoring.h" #include "BrainModelSurfaceROIAssignMetric.h" #include "BrainModelSurfaceROIAssignMetricNodeArea.h" #include "BrainModelSurfaceROIAssignPaint.h" #include "BrainModelSurfaceROIAssignShape.h" #include "BrainModelSurfaceROICreateBorderUsingGeodesic.h" #include "BrainModelSurfaceROIFoldingMeasurementReport.h" #include "BrainModelSurfaceROIIntegratedFoldingIndexReport.h" #include "BrainModelSurfaceROIMetricClusterReport.h" #include "BrainModelSurfaceROINodeSelection.h" #include "BrainModelSurfaceROIPaintReport.h" #include "BrainModelSurfaceROIProbAtlasOverlapReport.h" #include "BrainModelSurfaceROIShapeCorrelationReport.h" #include "BrainModelSurfaceROITextReport.h" #include "BrainModelSurfaceToVolumeConverter.h" #include "BrainSet.h" #include "DisplaySettingsBorders.h" #include "FileFilters.h" #include "GuiBorderNamesListBoxSelectionDialog.h" #include "GuiBrainModelOpenGL.h" #include "GuiBrainModelSelectionComboBox.h" #include "GuiColorSelectionDialog.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "GuiNameSelectionDialog.h" #include "GuiNodeAttributeColumnSelectionComboBox.h" #include "GuiPaintColumnNamesListBoxSelectionDialog.h" #include "GuiSmoothingDialog.h" #include "GuiSurfaceRegionOfInterestDialog.h" #include "GuiSurfaceToVolumeDialog.h" #include "GuiTopologyFileComboBox.h" #include "LatLonFile.h" #include "MetricFile.h" #include "NodeRegionOfInterestFile.h" #include "PaintFile.h" #include "QtUtilities.h" #include "PreferencesFile.h" #include "SurfaceShapeFile.h" #include "WuQDataEntryDialog.h" #include "WuQFileDialog.h" #include "WuQWidgetGroup.h" #include "global_variables.h" /** * constructor. */ GuiSurfaceRegionOfInterestDialog::GuiSurfaceRegionOfInterestDialog(QWidget* parent) : WuQWizard(parent) { setWindowTitle("Surface Region of Interest"); setOption(QWizard::NoCancelButton, false); setWizardStyle(QWizard::ModernStyle); surfaceSelectionPage = new GuiSurfaceROISurfaceAndTopologySelectionPage(this); setPage(PAGE_ID_OPERATION_SURFACE_AND_TOPOLOGY, surfaceSelectionPage); roiNodeSelectionPage = new GuiSurfaceROINodeSelectionPage(this); setPage(PAGE_ID_NODE_SELECTION, roiNodeSelectionPage); reportPage = new GuiSurfaceROIReportPage(this); setPage(PAGE_ID_REPORT, reportPage); operationPage = new GuiSurfaceROIOperationPage(this, reportPage); setPage(PAGE_ID_OPERATION, operationPage); } /** * destructor. */ GuiSurfaceRegionOfInterestDialog::~GuiSurfaceRegionOfInterestDialog() { } /** * show the dialog. */ void GuiSurfaceRegionOfInterestDialog::show() { // // May want to show selected nodes // roiNodeSelectionPage->showSelectedNodesCheckBox->setChecked(true); roiNodeSelectionPage->slotShowSelectedNodesCheckBox(roiNodeSelectionPage->showSelectedNodesCheckBox->isChecked()); roiNodeSelectionPage->updateNumberOfSelectedNodesLabel(); WuQWizard::show(); } /** * called when dialog closed. */ void GuiSurfaceRegionOfInterestDialog::reject() { BrainModelSurfaceROINodeSelection* roi = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); roi->setDisplaySelectedNodes(false); GuiBrainModelOpenGL::MOUSE_MODES m = theMainWindow->getBrainModelOpenGL()->getMouseMode(); if ((m == GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_BORDER_SELECT) || (m == GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_PAINT_INDEX_SELECT) || (m == GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_METRIC_NODE_SELECT) || (m == GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_GEODESIC_NODE_SELECT)) { theMainWindow->getBrainModelOpenGL()->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_VIEW); } theMainWindow->getBrainSet()->clearAllDisplayLists(); GuiBrainModelOpenGL::updateAllGL(); WuQWizard::reject(); } /** * update the dialog (typically due to file changes). */ void GuiSurfaceRegionOfInterestDialog::updateDialog() { roiNodeSelectionPage->updatePage(); surfaceSelectionPage->updatePage(); operationPage->updatePage(); } /** * set border name for query. */ void GuiSurfaceRegionOfInterestDialog::setBorderNameForQuery(const QString& borderName) { roiNodeSelectionPage->borderNameSelectionLabel->setText(borderName); } /** * set paint index for query. */ void GuiSurfaceRegionOfInterestDialog::setPaintIndexForQuery(const int paintIndex) { PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); roiNodeSelectionPage->paintNameSelectionLabel->setText(pf->getPaintNameFromIndex(paintIndex)); } /** * set metric node for query. */ void GuiSurfaceRegionOfInterestDialog::setMetricNodeForQuery(const int metricNodeForQuery) { //BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); //if (bms == NULL) { // return; //} roiNodeSelectionPage->metricSelectionNodeNumberLabel->setNum(metricNodeForQuery); MetricFile* mf = theMainWindow->getBrainSet()->getMetricFile(); if (mf->getNumberOfColumns() <= 0) { QMessageBox::critical(this, "Error", "There are no metric columns."); return; } const int column = roiNodeSelectionPage->metricColumnSelectionComboBox->currentIndex(); if ((column < 0) || (column >= mf->getNumberOfColumns())) { QMessageBox::critical(this, "Error", "Metric column is invalid."); return; } roiNodeSelectionPage->metricSelectionNodeValueLabel->setText( QString::number(mf->getValue(metricNodeForQuery, column), 'f', 4)); } /** * set shape node for query. */ void GuiSurfaceRegionOfInterestDialog::setShapeNodeForQuery(const int shapeNodeForQuery) { //BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); //if (bms == NULL) { // return; //} roiNodeSelectionPage->shapeSelectionNodeNumberLabel->setNum(shapeNodeForQuery); SurfaceShapeFile* ssf = theMainWindow->getBrainSet()->getSurfaceShapeFile(); if (ssf->getNumberOfColumns() <= 0) { QMessageBox::critical(this, "Error", "There are no surface shape columns."); return; } const int column = roiNodeSelectionPage->shapeColumnSelectionComboBox->currentIndex(); if ((column < 0) || (column >= ssf->getNumberOfColumns())) { QMessageBox::critical(this, "Error", "Surface Shape column is invalid."); return; } roiNodeSelectionPage->shapeSelectionNodeValueLabel->setText( QString::number(ssf->getValue(shapeNodeForQuery, column), 'f', 4)); } /** * set node for geodesic query. */ void GuiSurfaceRegionOfInterestDialog::setNodeForGeodesicQuery(const int nodeNumber) { operationPage->geodesicNodeSpinBox->setValue(nodeNumber); } /** * get the query paint column. */ int GuiSurfaceRegionOfInterestDialog::getQueryPaintColumn() const { return roiNodeSelectionPage->paintColumnSelectionComboBox->currentIndex(); } /** * get a COPY of operation surface with operation topology (user must delete object). */ BrainModelSurface* GuiSurfaceRegionOfInterestDialog::getCopyOfOperationSurface() { return surfaceSelectionPage->getCopyOfOperationSurface(); } /** * get the operation coordinate file. */ CoordinateFile* GuiSurfaceRegionOfInterestDialog::getOperationCoordinateFile() { return surfaceSelectionPage->getOperationCoordinateFile(); } //============================================================================ //============================================================================ //============================================================================ /** * constructor. */ GuiSurfaceROIReportPage::GuiSurfaceROIReportPage(GuiSurfaceRegionOfInterestDialog* roiDialogIn) : QWizardPage(0) { roiDialog = roiDialogIn; setTitle("ROI Report"); // // The report text edit // reportTextEdit = new QTextEdit; //reportTextEdit->setReadOnly(true); reportTextEdit->setLineWrapMode(QTextEdit::NoWrap); // // Clear text report push button // QPushButton* clearReportPushButton = new QPushButton("Clear"); clearReportPushButton->setAutoDefault(false); QObject::connect(clearReportPushButton, SIGNAL(clicked()), this, SLOT(slotClearReportTextEdit())); // // Save text edit to a file push button // QPushButton* saveReportPushButton = new QPushButton("Save Report to File..."); saveReportPushButton->setAutoDefault(false); saveReportPushButton->setFixedSize(saveReportPushButton->sizeHint()); QObject::connect(saveReportPushButton, SIGNAL(clicked()), this, SLOT(slotSaveReportToTextFile())); QtUtilities::makeButtonsSameSize(clearReportPushButton, saveReportPushButton); // // Layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->addWidget(clearReportPushButton); buttonsLayout->addWidget(saveReportPushButton); // // Layout for page // QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(reportTextEdit); layout->addLayout(buttonsLayout); } /** * destructor. */ GuiSurfaceROIReportPage::~GuiSurfaceROIReportPage() { } /** * clean up the page. */ void GuiSurfaceROIReportPage::cleanupPage() { } /** * initialize the page. */ void GuiSurfaceROIReportPage::initializePage() { } /** * validate the page. */ bool GuiSurfaceROIReportPage::validatePage() { return true; } /** * is page complete. */ bool GuiSurfaceROIReportPage::isComplete() { return true; } /** * update the page. */ void GuiSurfaceROIReportPage::updatePage() { } /** * set the report page's text edit. */ void GuiSurfaceROIReportPage::setReportText(const QString& s) { reportTextEdit->setPlainText(s); } /** * called when clear report button pressed. */ void GuiSurfaceROIReportPage::slotClearReportTextEdit() { reportTextEdit->clear(); } /** * called when save report to text file button pressed. */ void GuiSurfaceROIReportPage::slotSaveReportToTextFile() { WuQFileDialog fd(this); fd.setModal(true); fd.setDirectory(QDir::currentPath()); fd.setAcceptMode(WuQFileDialog::AcceptSave); fd.setWindowTitle("Choose Report Text File Name"); fd.setFilter(FileFilters::getTextFileFilter()); fd.setFileMode(WuQFileDialog::AnyFile); fd.setHistory(theMainWindow->getBrainSet()->getPreferencesFile()->getRecentDataFileDirectories()); if (fd.exec() == QDialog::Accepted) { if (fd.selectedFiles().count() > 0) { const QString fileName = fd.selectedFiles().at(0); QFile file(fileName); if (file.open(QIODevice::WriteOnly)) { QTextStream stream(&file); stream << reportTextEdit->toPlainText(); file.close(); } else { QString msg("Unable to open for writing: "); msg.append(fileName); QMessageBox::critical(this, "Error Opening File", msg); } } } } //============================================================================ //============================================================================ //============================================================================ /** * constructor. */ GuiSurfaceROINodeSelectionPage::GuiSurfaceROINodeSelectionPage(GuiSurfaceRegionOfInterestDialog* roiDialogIn) : QWizardPage(0) { roiDialog = roiDialogIn; setTitle("Node Selection"); // // selection source label and combo box // QLabel* selectionSourceLabel = new QLabel("Selection Source"); selectionSourceComboBox = new QComboBox; QObject::connect(selectionSourceComboBox, SIGNAL(activated(int)), this, SLOT(slotSelectionSourceComboBox(int))); selectionSourceComboBox->addItem("All Nodes", static_cast(SELECTION_SOURCE_ALL_NODES)); selectionSourceComboBox->addItem("Borders", static_cast(SELECTION_SOURCE_NODES_WITHIN_BORDER)); selectionSourceComboBox->addItem("Crossovers", static_cast(SELECTION_SOURCE_NODES_WITH_CROSSOVERS)); selectionSourceComboBox->addItem("Edges", static_cast(SELECTION_SOURCE_NODES_WITH_EDGES)); selectionSourceComboBox->addItem("Lat/Long", static_cast(SELECTION_SOURCE_NODES_WITHIN_LATLON)); selectionSourceComboBox->addItem("Metric", static_cast(SELECTION_SOURCE_NODES_WITH_METRIC)); selectionSourceComboBox->addItem("Paint", static_cast(SELECTION_SOURCE_NODES_WITH_PAINT)); selectionSourceComboBox->addItem("Surface Shape", static_cast(SELECTION_SOURCE_NODES_WITH_SHAPE)); // // selection logic label and combo box // QLabel* selectionLogicLabel = new QLabel("Selection Logic"); selectionLogicComboBox = new QComboBox; selectionLogicComboBox->addItem("Normal", static_cast(BrainModelSurfaceROINodeSelection::SELECTION_LOGIC_NORMAL)); selectionLogicComboBox->addItem("And (Intersection)", static_cast(BrainModelSurfaceROINodeSelection::SELECTION_LOGIC_AND)); selectionLogicComboBox->addItem("Or (Union)", static_cast(BrainModelSurfaceROINodeSelection::SELECTION_LOGIC_OR)); selectionLogicComboBox->addItem("And-Not", static_cast(BrainModelSurfaceROINodeSelection::SELECTION_LOGIC_AND_NOT)); // // Nodes selected labels and layout // QLabel* nodesSelectedLabel = new QLabel("Nodes Selected: "); numberOfNodesSelectedLabel = new QLabel(" "); QHBoxLayout* nodesSelectedLayout = new QHBoxLayout; nodesSelectedLayout->addWidget(nodesSelectedLabel); nodesSelectedLayout->addWidget(numberOfNodesSelectedLabel); nodesSelectedLayout->addStretch(); // // Show selected nodes check box // showSelectedNodesCheckBox = new QCheckBox("Show Selected Nodes"); QObject::connect(showSelectedNodesCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowSelectedNodesCheckBox(bool))); // // selection options stacked widget // selectionSourceOptionsStackedWidget = createNodeSelectionSourceOptionsWidget(); // // Group box and layout for node selection // QGridLayout* selectionGridLayout = new QGridLayout; selectionGridLayout->addWidget(selectionSourceLabel, 0, 0); selectionGridLayout->addWidget(selectionSourceComboBox, 0, 1); selectionGridLayout->addWidget(selectionLogicLabel, 1, 0); selectionGridLayout->addWidget(selectionLogicComboBox, 1, 1); selectionGridLayout->addWidget(showSelectedNodesCheckBox, 2, 0, 1, 1); selectionGridLayout->addLayout(nodesSelectedLayout, 2, 1, 1, 2); QGroupBox* selectionGroupBox = new QGroupBox("Node Selection Source on Main Window Surface"); QVBoxLayout* selectionGroupLayout = new QVBoxLayout(selectionGroupBox); selectionGroupLayout->addLayout(selectionGridLayout); selectionGroupLayout->addWidget(selectionSourceOptionsStackedWidget); selectionGroupLayout->addStretch(); // //------------------------------------------------------------------------- // // // Select Nodes push button // QPushButton* selectNodesPushButton = new QPushButton("Select Nodes"); selectNodesPushButton->setToolTip("Select nodes using the current\n" "selection source and logic."); selectNodesPushButton->setAutoDefault(true); QObject::connect(selectNodesPushButton, SIGNAL(clicked()), this, SLOT(slotSelectedNodesPushButton())); // // Deselect Nodes push button // deselectNodesPushButton = new QPushButton("Deselect All Nodes"); deselectNodesPushButton->setToolTip("Deselect all nodes."); deselectNodesPushButton->setAutoDefault(false); QObject::connect(deselectNodesPushButton, SIGNAL(clicked()), this, SLOT(slotDeselectNodesPushButton())); // // Dilate ROI push button // dilateSelectedNodesPushButton = new QPushButton("Dilate"); dilateSelectedNodesPushButton->setToolTip("Dilate the selected nodes.\n" "\n" "Select a node if any of its \n" "immediate neighbors are selected\n" "(\"Grows\" the ROI)."); dilateSelectedNodesPushButton->setAutoDefault(false); QObject::connect(dilateSelectedNodesPushButton, SIGNAL(clicked()), this, SLOT(slotDilateROIPushButton())); // // erode ROI push button // erodeSelectedNodesPushButton = new QPushButton("Erode"); erodeSelectedNodesPushButton->setToolTip("Erode the selected nodes.\n" "\n" "Deselect a node if any of \n" "its immediate neighbors are \n" "not selected.\n" "(\"Shrinks\" the ROI)."); erodeSelectedNodesPushButton->setAutoDefault(false); QObject::connect(erodeSelectedNodesPushButton, SIGNAL(clicked()), this, SLOT(slotErodeROIPushButton())); // // Extent push button // extentPushButton = new QPushButton("Extent..."); extentPushButton->setToolTip("Limit nodes to a coordinate bounded region.\n"); extentPushButton->setAutoDefault(false); QObject::connect(extentPushButton, SIGNAL(clicked()), this, SLOT(slotExtentPushButton())); // // Invert ROI push button // invertSelectedNodesPushButton = new QPushButton("Invert"); invertSelectedNodesPushButton->setToolTip("Invert the current selection."); invertSelectedNodesPushButton->setAutoDefault(false); QObject::connect(invertSelectedNodesPushButton, SIGNAL(clicked()), this, SLOT(slotInvertNodesPushButton())); // // Remove islands // removeIslandsPushButton = new QPushButton("Remove Islands"); removeIslandsPushButton->setToolTip("If there are disjoint (unconnected)\n" "regions in the selected nodes, the\n" "largest region is retained and any\n" "nodes in smaller regions are deselected."); removeIslandsPushButton->setAutoDefault(false); QObject::connect(removeIslandsPushButton, SIGNAL(clicked()), this, SLOT(slotRemoveIslands())); // // Group box and layout for modify ROI // QHBoxLayout* row1Layout = new QHBoxLayout; row1Layout->addWidget(selectNodesPushButton); row1Layout->addWidget(deselectNodesPushButton); row1Layout->addWidget(invertSelectedNodesPushButton); row1Layout->addStretch(); QHBoxLayout* row2Layout = new QHBoxLayout; row2Layout->addWidget(removeIslandsPushButton); row2Layout->addWidget(dilateSelectedNodesPushButton); row2Layout->addWidget(erodeSelectedNodesPushButton); row2Layout->addWidget(extentPushButton); row2Layout->addStretch(); QGroupBox* modifyROIGroupBox = new QGroupBox("Select Nodes and Modify Region of Interest"); QVBoxLayout* modifyROILayout = new QVBoxLayout(modifyROIGroupBox); modifyROILayout->addLayout(row1Layout); modifyROILayout->addLayout(row2Layout); modifyROILayout->addStretch(); // //------------------------------------------------------------------------- // // // Load an ROI pushbutton // loadROIPushButton = new QPushButton("Load..."); loadROIPushButton->setToolTip("Set the ROI using the status from\n" "Region of Interest File."); loadROIPushButton->setAutoDefault(false); QObject::connect(loadROIPushButton, SIGNAL(clicked()), this, SLOT(slotLoadROIPushButton())); // // Save an ROI pushbutton // saveROIPushButton = new QPushButton("Save..."); saveROIPushButton->setToolTip("Save the ROI status into\n" "a Region of Interest File."); saveROIPushButton->setAutoDefault(false); QObject::connect(saveROIPushButton, SIGNAL(clicked()), this, SLOT(slotSaveROIPushButton())); // // Group box and layout for laod/save options // QGroupBox* fileOperationsGroupBox = new QGroupBox("ROI File Operations"); QVBoxLayout* fileOperationsLayout = new QVBoxLayout(fileOperationsGroupBox); fileOperationsLayout->addWidget(loadROIPushButton); fileOperationsLayout->addWidget(saveROIPushButton); fileOperationsLayout->addStretch(); // //------------------------------------------------------------------------- // // // Layout for page // QHBoxLayout* modifyAndFileLayout = new QHBoxLayout; modifyAndFileLayout->addWidget(modifyROIGroupBox); modifyAndFileLayout->addWidget(fileOperationsGroupBox); modifyAndFileLayout->addStretch(); QVBoxLayout* pageLayout = new QVBoxLayout(this); pageLayout->addWidget(selectionGroupBox); pageLayout->addLayout(modifyAndFileLayout); pageLayout->addStretch(); } /** * destructor. */ GuiSurfaceROINodeSelectionPage::~GuiSurfaceROINodeSelectionPage() { } /** * create the node selection source options widget. */ QStackedWidget* GuiSurfaceROINodeSelectionPage::createNodeSelectionSourceOptionsWidget() { //-------------------------------------------------------------------------- // // selection widget for all nodes (no options) // selectionSourceOptionsAllNodesWidget = new QWidget; //-------------------------------------------------------------------------- // // selection widget for borders // // // Flat surface label and selection // QLabel* borderFlatSurfaceLabel = new QLabel("Flat Surface"); borderFlatSurfaceSelectionComboBox = new GuiBrainModelSelectionComboBox( GuiBrainModelSelectionComboBox::OPTION_SHOW_SURFACES_FLAT); // // Choose border name from a list of border names // QPushButton* selectBorderNameFromListPushButton = new QPushButton("Select Name From List..."); selectBorderNameFromListPushButton->setAutoDefault(false); QObject::connect(selectBorderNameFromListPushButton, SIGNAL(clicked()), this, SLOT(slotSelectBorderNameFromListPushButton())); // // Choose paint name by clicking on a node with the mouse // QPushButton* selectBorderNameNodeWithMousePushButton = new QPushButton("Select Border With Mouse..."); selectBorderNameNodeWithMousePushButton->setAutoDefault(false); QObject::connect(selectBorderNameNodeWithMousePushButton, SIGNAL(clicked()), this, SLOT(slotSelectBorderNameWithMousePushButton())); // // Make the buttons the same size // WuQWidgetGroup* borderButtonWidgetGroup = new WuQWidgetGroup(this); borderButtonWidgetGroup->addWidget(selectBorderNameFromListPushButton); borderButtonWidgetGroup->addWidget(selectBorderNameNodeWithMousePushButton); borderButtonWidgetGroup->resizeAllToLargestSizeHint(); // // Selected name label // QLabel* borderNameLabel = new QLabel("Name "); borderNameSelectionLabel = new QLabel(" "); // // borders group box and layout // selectionSourceOptionsBordersWidget = new QGroupBox("Border Options"); QGridLayout* selectionBorderLayout = new QGridLayout(selectionSourceOptionsBordersWidget); selectionBorderLayout->setColumnStretch(0, 0); selectionBorderLayout->setColumnStretch(1, 100); selectionBorderLayout->addWidget(borderFlatSurfaceLabel, 0, 0); selectionBorderLayout->addWidget(borderFlatSurfaceSelectionComboBox, 0, 1, Qt::AlignLeft); selectionBorderLayout->addWidget(selectBorderNameFromListPushButton, 1, 0, 1, 2, Qt::AlignLeft); selectionBorderLayout->addWidget(selectBorderNameNodeWithMousePushButton, 2, 0, 1, 2, Qt::AlignLeft); selectionBorderLayout->addWidget(borderNameLabel, 3, 0); selectionBorderLayout->addWidget(borderNameSelectionLabel, 3, 1, Qt::AlignLeft); //-------------------------------------------------------------------------- // // selection widget for crossovers (no options) // selectionSourceOptionsCrossoversWidget = new QWidget; //-------------------------------------------------------------------------- // // selection widget for edges (no options) // selectionSourceOptionsEdgesWidget = new QWidget; //-------------------------------------------------------------------------- // // selection widget for lat/long // // // Lower latitude // latLowerRangeDoubleSpinBox = new QDoubleSpinBox; latLowerRangeDoubleSpinBox->setMinimum(-90.0); latLowerRangeDoubleSpinBox->setMaximum( 90.0); latLowerRangeDoubleSpinBox->setSingleStep(1.0); latLowerRangeDoubleSpinBox->setDecimals(3); latLowerRangeDoubleSpinBox->setValue(-90.0); latLowerRangeDoubleSpinBox->setFixedWidth(120); // // Upper latitude // latUpperRangeDoubleSpinBox = new QDoubleSpinBox; latUpperRangeDoubleSpinBox->setMinimum(-90.0); latUpperRangeDoubleSpinBox->setMaximum( 90.0); latUpperRangeDoubleSpinBox->setSingleStep(1.0); latUpperRangeDoubleSpinBox->setDecimals(3); latUpperRangeDoubleSpinBox->setValue(90.0); latUpperRangeDoubleSpinBox->setFixedWidth(120); // // lower longitude // lonLowerRangeDoubleSpinBox = new QDoubleSpinBox; lonLowerRangeDoubleSpinBox->setMinimum(-360.0); lonLowerRangeDoubleSpinBox->setMaximum( 360.0); lonLowerRangeDoubleSpinBox->setSingleStep(1.0); lonLowerRangeDoubleSpinBox->setDecimals(3); lonLowerRangeDoubleSpinBox->setValue(-180.0); lonLowerRangeDoubleSpinBox->setFixedWidth(120); // // upper longitude // lonUpperRangeDoubleSpinBox = new QDoubleSpinBox; lonUpperRangeDoubleSpinBox->setMinimum(-360.0); lonUpperRangeDoubleSpinBox->setMaximum( 360.0); lonUpperRangeDoubleSpinBox->setSingleStep(1.0); lonUpperRangeDoubleSpinBox->setDecimals(3); lonUpperRangeDoubleSpinBox->setValue(180.0); lonUpperRangeDoubleSpinBox->setFixedWidth(120); // // Widget and layout for latitutude/longitude // selectionSourceOptionsLatLongWidget = new QGroupBox("Lat/Long Options") ; QGridLayout* latLonLayout = new QGridLayout(selectionSourceOptionsLatLongWidget); latLonLayout->addWidget(new QLabel("Min-Value"), 0, 1); latLonLayout->addWidget(new QLabel("Max-Value"), 0, 2); latLonLayout->addWidget(new QLabel("Latitude"), 1, 0); latLonLayout->addWidget(new QLabel("Longitude"), 2, 0); latLonLayout->addWidget(latLowerRangeDoubleSpinBox, 1, 1); latLonLayout->addWidget(latUpperRangeDoubleSpinBox, 1, 2); latLonLayout->addWidget(lonLowerRangeDoubleSpinBox, 2, 1); latLonLayout->addWidget(lonUpperRangeDoubleSpinBox, 2, 2); //-------------------------------------------------------------------------- // // selection widget for metric // // // Metric column selection and label // QLabel* metricCategoryLabel = new QLabel("Category"); metricColumnSelectionComboBox = new GuiNodeAttributeColumnSelectionComboBox(GUI_NODE_FILE_TYPE_METRIC, false, false, false); QHBoxLayout* metricCategoryLayout = new QHBoxLayout; metricCategoryLayout->addWidget(metricCategoryLabel); metricCategoryLayout->addWidget(metricColumnSelectionComboBox); metricCategoryLayout->addStretch(); // // Metric range label and spin boxes // QLabel* metricSelectionRangeLabel = new QLabel("Range "); metricSelectionLowerDoubleSpinBox = new QDoubleSpinBox; metricSelectionLowerDoubleSpinBox->setMinimum(-10000000.0); metricSelectionLowerDoubleSpinBox->setMaximum( 10000000.0); metricSelectionLowerDoubleSpinBox->setSingleStep(1.0); metricSelectionLowerDoubleSpinBox->setDecimals(4); metricSelectionLowerDoubleSpinBox->setValue(1.0); QLabel* metricSelectionToLabel = new QLabel(" to "); metricSelectionUpperDoubleSpinBox = new QDoubleSpinBox; metricSelectionUpperDoubleSpinBox->setMinimum(-10000000.0); metricSelectionUpperDoubleSpinBox->setMaximum( 10000000.0); metricSelectionUpperDoubleSpinBox->setSingleStep(1.0); metricSelectionUpperDoubleSpinBox->setDecimals(4); metricSelectionUpperDoubleSpinBox->setValue(50000.0); QHBoxLayout* metricRangeLayout = new QHBoxLayout; metricRangeLayout->addWidget(metricSelectionRangeLabel); metricRangeLayout->addWidget(metricSelectionLowerDoubleSpinBox); metricRangeLayout->addWidget(metricSelectionToLabel); metricRangeLayout->addWidget(metricSelectionUpperDoubleSpinBox); metricRangeLayout->addStretch(); // // metric selection radio buttons // metricSelectionAllNodesRadioButton = new QRadioButton("All Nodes Within Range"); metricSelectionConnectedToNodeRadioButton = new QRadioButton("Nodes Within Range Connected to Node Selected With Mouse"); QButtonGroup* metricSelectionButtonGroup = new QButtonGroup(this); metricSelectionButtonGroup->addButton(metricSelectionAllNodesRadioButton); metricSelectionButtonGroup->addButton(metricSelectionConnectedToNodeRadioButton); QObject::connect(metricSelectionButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotMetricSelectionButtonGroup())); // // Metric selection node number and value labels // QLabel* metricSelectionNodeLabel = new QLabel(" Node Number "); metricSelectionNodeNumberLabel = new QLabel(" "); QLabel* metricSelectionValueLabel = new QLabel(" Value "); metricSelectionNodeValueLabel = new QLabel(" "); QHBoxLayout* metricNodeLayout = new QHBoxLayout; metricNodeLayout->addWidget(metricSelectionNodeLabel); metricNodeLayout->addWidget(metricSelectionNodeNumberLabel); metricNodeLayout->addWidget(metricSelectionValueLabel); metricNodeLayout->addWidget(metricSelectionNodeValueLabel); metricNodeLayout->addStretch(); // // Metric widget and options // selectionSourceOptionsMetricWidget = new QGroupBox("Metric Options"); QVBoxLayout* metricSelectionLayout = new QVBoxLayout(selectionSourceOptionsMetricWidget); metricSelectionLayout->addLayout(metricCategoryLayout); metricSelectionLayout->addLayout(metricRangeLayout); metricSelectionLayout->addWidget(metricSelectionAllNodesRadioButton); metricSelectionLayout->addWidget(metricSelectionConnectedToNodeRadioButton); metricSelectionLayout->addLayout(metricNodeLayout); metricSelectionLayout->addStretch(); //-------------------------------------------------------------------------- // // selection widget for paint // // // Paint column selection and label // QLabel* paintCategoryLabel = new QLabel("Category"); paintColumnSelectionComboBox = new GuiNodeAttributeColumnSelectionComboBox(GUI_NODE_FILE_TYPE_PAINT, false, false, false); // // Choose paint name from a list of paint names // QPushButton* selectPaintNameFromListPushButton = new QPushButton("Select Name From List..."); selectPaintNameFromListPushButton->setAutoDefault(false); QObject::connect(selectPaintNameFromListPushButton, SIGNAL(clicked()), this, SLOT(slotSelectPaintNameFromListPushButton())); // // Choose paint name by clicking on a node with the mouse // QPushButton* selectPaintNameNodeWithMousePushButton = new QPushButton("Select Node With Mouse..."); selectPaintNameNodeWithMousePushButton->setAutoDefault(false); QObject::connect(selectPaintNameNodeWithMousePushButton, SIGNAL(clicked()), this, SLOT(slotSelectPaintNameNodeWithMousePushButton())); // // Make the buttons the same size // WuQWidgetGroup* buttonWidgetGroup = new WuQWidgetGroup(this); buttonWidgetGroup->addWidget(selectPaintNameFromListPushButton); buttonWidgetGroup->addWidget(selectPaintNameNodeWithMousePushButton); buttonWidgetGroup->resizeAllToLargestSizeHint(); // // Selected name label // QLabel* paintNameLabel = new QLabel("Name "); paintNameSelectionLabel = new QLabel(" "); // // Paint options widget and layout // selectionSourceOptionsPaintWidget = new QGroupBox("Paint Options"); QGridLayout* selectionPaintLayout = new QGridLayout(selectionSourceOptionsPaintWidget); selectionPaintLayout->setColumnStretch(0, 0); selectionPaintLayout->setColumnStretch(0, 100); selectionPaintLayout->addWidget(paintCategoryLabel, 0, 0); selectionPaintLayout->addWidget(paintColumnSelectionComboBox, 0, 1, Qt::AlignLeft); selectionPaintLayout->addWidget(selectPaintNameFromListPushButton, 1, 0, 1, 2, Qt::AlignLeft); selectionPaintLayout->addWidget(selectPaintNameNodeWithMousePushButton, 2, 0, 1, 2, Qt::AlignLeft); selectionPaintLayout->addWidget(paintNameLabel, 3, 0); selectionPaintLayout->addWidget(paintNameSelectionLabel, 3, 1, Qt::AlignLeft); //-------------------------------------------------------------------------- // // selection widget for surface shape // // // Shape column selection and label // QLabel* shapeCategoryLabel = new QLabel("Category"); shapeColumnSelectionComboBox = new GuiNodeAttributeColumnSelectionComboBox(GUI_NODE_FILE_TYPE_SURFACE_SHAPE, false, false, false); QHBoxLayout* shapeCategoryLayout = new QHBoxLayout; shapeCategoryLayout->addWidget(shapeCategoryLabel); shapeCategoryLayout->addWidget(shapeColumnSelectionComboBox); shapeCategoryLayout->addStretch(); // // Shape range label and spin boxes // QLabel* shapeSelectionRangeLabel = new QLabel("Range "); shapeSelectionLowerDoubleSpinBox = new QDoubleSpinBox; shapeSelectionLowerDoubleSpinBox->setMinimum(-10000000.0); shapeSelectionLowerDoubleSpinBox->setMaximum( 10000000.0); shapeSelectionLowerDoubleSpinBox->setSingleStep(1.0); shapeSelectionLowerDoubleSpinBox->setDecimals(4); shapeSelectionLowerDoubleSpinBox->setValue(1.0); QLabel* shapeSelectionToLabel = new QLabel(" to "); shapeSelectionUpperDoubleSpinBox = new QDoubleSpinBox; shapeSelectionUpperDoubleSpinBox->setMinimum(-10000000.0); shapeSelectionUpperDoubleSpinBox->setMaximum( 10000000.0); shapeSelectionUpperDoubleSpinBox->setSingleStep(1.0); shapeSelectionUpperDoubleSpinBox->setDecimals(4); shapeSelectionUpperDoubleSpinBox->setValue(50000.0); QHBoxLayout* shapeRangeLayout = new QHBoxLayout; shapeRangeLayout->addWidget(shapeSelectionRangeLabel); shapeRangeLayout->addWidget(shapeSelectionLowerDoubleSpinBox); shapeRangeLayout->addWidget(shapeSelectionToLabel); shapeRangeLayout->addWidget(shapeSelectionUpperDoubleSpinBox); shapeRangeLayout->addStretch(); // // shape selection radio buttons // shapeSelectionAllNodesRadioButton = new QRadioButton("All Nodes Within Range"); shapeSelectionConnectedToNodeRadioButton = new QRadioButton("Nodes Within Range Connected to Node Selected With Mouse"); QButtonGroup* shapeSelectionButtonGroup = new QButtonGroup(this); shapeSelectionButtonGroup->addButton(shapeSelectionAllNodesRadioButton); shapeSelectionButtonGroup->addButton(shapeSelectionConnectedToNodeRadioButton); QObject::connect(shapeSelectionButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotShapeSelectionButtonGroup())); // // Shape selection node number and value labels // QLabel* shapeSelectionNodeLabel = new QLabel(" Node Number "); shapeSelectionNodeNumberLabel = new QLabel(" "); QLabel* shapeSelectionValueLabel = new QLabel(" Value "); shapeSelectionNodeValueLabel = new QLabel(" "); QHBoxLayout* shapeNodeLayout = new QHBoxLayout; shapeNodeLayout->addWidget(shapeSelectionNodeLabel); shapeNodeLayout->addWidget(shapeSelectionNodeNumberLabel); shapeNodeLayout->addWidget(shapeSelectionValueLabel); shapeNodeLayout->addWidget(shapeSelectionNodeValueLabel); shapeNodeLayout->addStretch(); // // Shape widget and options // selectionSourceOptionsShapeWidget = new QGroupBox("Surface Shape Options"); QVBoxLayout* shapeSelectionLayout = new QVBoxLayout(selectionSourceOptionsShapeWidget); shapeSelectionLayout->addLayout(shapeCategoryLayout); shapeSelectionLayout->addLayout(shapeRangeLayout); shapeSelectionLayout->addWidget(shapeSelectionAllNodesRadioButton); shapeSelectionLayout->addWidget(shapeSelectionConnectedToNodeRadioButton); shapeSelectionLayout->addLayout(shapeNodeLayout); shapeSelectionLayout->addStretch(); // // stacked widget // QStackedWidget* stackedWidget = new QStackedWidget; stackedWidget->addWidget(selectionSourceOptionsAllNodesWidget); stackedWidget->addWidget(selectionSourceOptionsBordersWidget); stackedWidget->addWidget(selectionSourceOptionsCrossoversWidget); stackedWidget->addWidget(selectionSourceOptionsEdgesWidget); stackedWidget->addWidget(selectionSourceOptionsLatLongWidget); stackedWidget->addWidget(selectionSourceOptionsMetricWidget); stackedWidget->addWidget(selectionSourceOptionsPaintWidget); stackedWidget->addWidget(selectionSourceOptionsShapeWidget); return stackedWidget; } /** * called when shape threshold radio button clicked. */ void GuiSurfaceROINodeSelectionPage::slotShapeSelectionButtonGroup() { if (shapeSelectionConnectedToNodeRadioButton->isChecked()) { theMainWindow->getBrainModelOpenGL()->setMouseMode( GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_SHAPE_NODE_SELECT); } } /** * called when metric threshold radio button clicked. */ void GuiSurfaceROINodeSelectionPage::slotMetricSelectionButtonGroup() { if (metricSelectionConnectedToNodeRadioButton->isChecked()) { theMainWindow->getBrainModelOpenGL()->setMouseMode( GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_METRIC_NODE_SELECT); } } /** * called when border name from list pushbutton pressed. */ void GuiSurfaceROINodeSelectionPage::slotSelectBorderNameFromListPushButton() { GuiBorderNamesListBoxSelectionDialog bs(this, borderNameSelectionLabel->text()); if (bs.exec() == QDialog::Accepted) { roiDialog->setBorderNameForQuery(bs.getSelectedText()); } } /** * called when border select with mouse pushbutton pressed. */ void GuiSurfaceROINodeSelectionPage::slotSelectBorderNameWithMousePushButton() { theMainWindow->getBrainModelOpenGL()->setMouseMode( GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_BORDER_SELECT); } /** * called when paint name from list pushbutton pressed. */ void GuiSurfaceROINodeSelectionPage::slotSelectPaintNameFromListPushButton() { GuiPaintColumnNamesListBoxSelectionDialog pd(this, paintColumnSelectionComboBox->currentIndex()); if (pd.exec() == QDialog::Accepted) { roiDialog->setPaintIndexForQuery(pd.getSelectedItemIndex()); } } /** * called when paint select node with mouse pushbutton pressed. */ void GuiSurfaceROINodeSelectionPage::slotSelectPaintNameNodeWithMousePushButton() { theMainWindow->getBrainModelOpenGL()->setMouseMode( GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_PAINT_INDEX_SELECT); } /** * called when a selection source is made. */ void GuiSurfaceROINodeSelectionPage::slotSelectionSourceComboBox(int item) { const SELECTION_SOURCE selectionSource = static_cast(selectionSourceComboBox->itemData(item).toInt()); switch (selectionSource) { case SELECTION_SOURCE_ALL_NODES: selectionSourceOptionsStackedWidget->setCurrentWidget(selectionSourceOptionsAllNodesWidget); break; case SELECTION_SOURCE_NODES_WITHIN_BORDER: selectionSourceOptionsStackedWidget->setCurrentWidget(selectionSourceOptionsBordersWidget); break; case SELECTION_SOURCE_NODES_WITH_CROSSOVERS: selectionSourceOptionsStackedWidget->setCurrentWidget(selectionSourceOptionsCrossoversWidget); break; case SELECTION_SOURCE_NODES_WITH_EDGES: selectionSourceOptionsStackedWidget->setCurrentWidget(selectionSourceOptionsEdgesWidget); break; case SELECTION_SOURCE_NODES_WITHIN_LATLON: selectionSourceOptionsStackedWidget->setCurrentWidget(selectionSourceOptionsLatLongWidget); break; case SELECTION_SOURCE_NODES_WITH_METRIC: selectionSourceOptionsStackedWidget->setCurrentWidget(selectionSourceOptionsMetricWidget); break; case SELECTION_SOURCE_NODES_WITH_PAINT: selectionSourceOptionsStackedWidget->setCurrentWidget(selectionSourceOptionsPaintWidget); break; case SELECTION_SOURCE_NODES_WITH_SHAPE: selectionSourceOptionsStackedWidget->setCurrentWidget(selectionSourceOptionsShapeWidget); break; } } /** * called when select nodes push button pressed. */ void GuiSurfaceROINodeSelectionPage::slotSelectedNodesPushButton() { // // Get operational surface // const BrainModelSurface* bms = roiDialog->getCopyOfOperationSurface(); if (bms == NULL) { QMessageBox::critical(this, "ERROR", "The operational surface is invalid."); return; } // // Get type of data used to select nodes // const int sourceIndex = selectionSourceComboBox->currentIndex(); const SELECTION_SOURCE selectionSource = static_cast(selectionSourceComboBox->itemData(sourceIndex).toInt()); // // Get logic for selection // const int logicIndex = selectionLogicComboBox->currentIndex(); const BrainModelSurfaceROINodeSelection::SELECTION_LOGIC selectionLogic = static_cast( selectionLogicComboBox->itemData(logicIndex).toInt()); // // Get the ROI // BrainModelSurfaceROINodeSelection* roi = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); QString errorMessage; switch (selectionSource) { case SELECTION_SOURCE_ALL_NODES: errorMessage = roi->selectAllNodes(bms); break; case SELECTION_SOURCE_NODES_WITHIN_BORDER: { const BrainModelSurface* flatSurface = borderFlatSurfaceSelectionComboBox->getSelectedBrainModelSurface(); if (flatSurface == NULL) { errorMessage = "There is no selected flat surface which is required for border queries."; } else { const QString selectedBorderName = borderNameSelectionLabel->text(); if (selectedBorderName.isEmpty()) { errorMessage = "There is no selected border name."; } else { BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); errorMessage = roi->selectNodesWithinBorder(selectionLogic, bms, flatSurface, bmbs, selectedBorderName); } } } break; case SELECTION_SOURCE_NODES_WITH_CROSSOVERS: errorMessage = roi->selectNodesThatAreCrossovers(selectionLogic, bms); break; case SELECTION_SOURCE_NODES_WITH_EDGES: { errorMessage = roi->selectNodesThatAreEdges(selectionLogic, bms); // // Update Display Control // GuiFilesModified fm; theMainWindow->fileModificationUpdate(fm); } break; case SELECTION_SOURCE_NODES_WITHIN_LATLON: { const double minLat = latLowerRangeDoubleSpinBox->value(); const double maxLat = latUpperRangeDoubleSpinBox->value(); if (minLat > maxLat) { errorMessage = "Minimum Latitude is greater than Maximum Latitude"; } const double minLon = lonLowerRangeDoubleSpinBox->value(); const double maxLon = lonUpperRangeDoubleSpinBox->value(); if (minLon > maxLon) { errorMessage = "Minimum Longitude is greater than Maximum Longitude"; } if (errorMessage.isEmpty()) { const int columnNumber = 0; errorMessage = roi->selectNodesWithLatLong(selectionLogic, bms, theMainWindow->getBrainSet()->getLatLonFile(), columnNumber, minLat, maxLat, minLon, maxLon); } } break; case SELECTION_SOURCE_NODES_WITH_METRIC: { MetricFile* metricFile = theMainWindow->getBrainSet()->getMetricFile(); if (metricSelectionAllNodesRadioButton->isChecked()) { errorMessage = roi->selectNodesWithMetric(selectionLogic, bms, metricFile, metricColumnSelectionComboBox->currentIndex(), metricSelectionLowerDoubleSpinBox->value(), metricSelectionUpperDoubleSpinBox->value()); } else if (metricSelectionConnectedToNodeRadioButton->isChecked()) { const int metricNodeForQuery = metricSelectionNodeNumberLabel->text().toInt(); if ((metricNodeForQuery < 0) || (metricNodeForQuery >= bms->getNumberOfNodes())) { errorMessage = "Metric node number selected is invalid."; } else { errorMessage = roi->selectConnectedNodesWithMetric(selectionLogic, bms, metricFile, metricColumnSelectionComboBox->currentIndex(), metricSelectionLowerDoubleSpinBox->value(), metricSelectionUpperDoubleSpinBox->value(), metricNodeForQuery); } } else { errorMessage = "Select either All Nodes or Node or Nodes Within \n" "Range Connected to Node Selected with Mouse button."; } } break; case SELECTION_SOURCE_NODES_WITH_PAINT: { const QString paintName = paintNameSelectionLabel->text(); if (paintName.isEmpty()) { errorMessage = "No paint name is selected."; } else { const PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); errorMessage = roi->selectNodesWithPaint(selectionLogic, bms, pf, paintColumnSelectionComboBox->currentIndex(), paintName); } } break; case SELECTION_SOURCE_NODES_WITH_SHAPE: { SurfaceShapeFile* ssf = theMainWindow->getBrainSet()->getSurfaceShapeFile(); if (shapeSelectionAllNodesRadioButton->isChecked()) { errorMessage = roi->selectNodesWithSurfaceShape(selectionLogic, bms, ssf, shapeColumnSelectionComboBox->currentIndex(), shapeSelectionLowerDoubleSpinBox->value(), shapeSelectionUpperDoubleSpinBox->value()); } else if (shapeSelectionConnectedToNodeRadioButton->isChecked()) { const int shapeNodeForQuery = shapeSelectionNodeNumberLabel->text().toInt(); if ((shapeNodeForQuery < 0) || (shapeNodeForQuery >= bms->getNumberOfNodes())) { errorMessage = "Surface Shape node number selected is invalid."; } else { errorMessage = roi->selectConnectedNodesWithSurfaceShape(selectionLogic, bms, ssf, shapeColumnSelectionComboBox->currentIndex(), shapeSelectionLowerDoubleSpinBox->value(), shapeSelectionUpperDoubleSpinBox->value(), shapeNodeForQuery); } } else { errorMessage = "Select either All Nodes or Node or Nodes Within \n" "Range Connected to Node Selected with Mouse button."; } } break; } updateNumberOfSelectedNodesLabel(); slotShowSelectedNodesCheckBox(showSelectedNodesCheckBox->isChecked()); QApplication::restoreOverrideCursor(); if (errorMessage.isEmpty() == false) { QMessageBox::critical(this, "ERROR", errorMessage); } // // Free surface copy // delete bms; bms = NULL; // // Update complete status // emit completeChanged(); } /** * called when show selected nodes checkbox toggled. */ void GuiSurfaceROINodeSelectionPage::slotShowSelectedNodesCheckBox(bool on) { BrainModelSurfaceROINodeSelection* roi = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); roi->setDisplaySelectedNodes(on); theMainWindow->getBrainSet()->clearAllDisplayLists(); GuiBrainModelOpenGL::updateAllGL(NULL); } /** * update selected number of nodes label. */ void GuiSurfaceROINodeSelectionPage::updateNumberOfSelectedNodesLabel() { BrainModelSurfaceROINodeSelection* roi = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); numberOfNodesSelectedLabel->setNum(roi->getNumberOfNodesSelected()); } /** * called when delselect nodes push button pressed. */ void GuiSurfaceROINodeSelectionPage::slotDeselectNodesPushButton() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainModelSurfaceROINodeSelection* roi = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); roi->deselectAllNodes(); updateNumberOfSelectedNodesLabel(); theMainWindow->getBrainSet()->clearAllDisplayLists(); GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); // // Update complete status // emit completeChanged(); } /** * called when remove islands button pressed. */ void GuiSurfaceROINodeSelectionPage::slotRemoveIslands() { // // Get operational surface // const BrainModelSurface* bms = roiDialog->getCopyOfOperationSurface(); if (bms == NULL) { QMessageBox::critical(this, "ERROR", "The operational surface is invalid."); return; } BrainModelSurfaceROINodeSelection* roi = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); const int numIslandsRemoved = roi->discardIslands(bms); updateNumberOfSelectedNodesLabel(); theMainWindow->getBrainSet()->clearAllDisplayLists(); GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); // // Free copy of surface // delete bms; bms = NULL; QMessageBox::information(this, "Remove Islands", QString::number(numIslandsRemoved) + " islands were removed."); // // Update complete status // emit completeChanged(); } /** * called when invert push button pressed. */ void GuiSurfaceROINodeSelectionPage::slotInvertNodesPushButton() { // // Get operational surface // const BrainModelSurface* bms = roiDialog->getCopyOfOperationSurface(); if (bms == NULL) { QMessageBox::critical(this, "ERROR", "The operational surface is invalid."); return; } BrainModelSurfaceROINodeSelection* roi = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); roi->invertSelectedNodes(bms); updateNumberOfSelectedNodesLabel(); theMainWindow->getBrainSet()->clearAllDisplayLists(); GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); // // Free copy of surface // delete bms; bms = NULL; // // Update complete status // emit completeChanged(); } /** * called when load ROI push button pressed. */ void GuiSurfaceROINodeSelectionPage::slotLoadROIPushButton() { WuQFileDialog fd(this); fd.setModal(true); fd.setDirectory(QDir::currentPath()); fd.setAcceptMode(WuQFileDialog::AcceptOpen); fd.setWindowTitle("Choose Region of Interest File Name"); fd.setFilter(FileFilters::getRegionOfInterestFileFilter()); fd.setFileMode(WuQFileDialog::ExistingFile); if (fd.exec() == QDialog::Accepted) { if (fd.selectedFiles().count() > 0) { const QString fileName = fd.selectedFiles().at(0); NodeRegionOfInterestFile roiFile; try { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); roiFile.readFile(fileName); BrainModelSurfaceROINodeSelection* roi = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); roi->getRegionOfInterestFromFile(roiFile); updateNumberOfSelectedNodesLabel(); theMainWindow->getBrainSet()->clearAllDisplayLists(); GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); } catch (FileException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); } } } // // Update complete status // emit completeChanged(); } /** * called when save ROI push button pressed. */ void GuiSurfaceROINodeSelectionPage::slotSaveROIPushButton() { WuQFileDialog fd(this); fd.setModal(true); fd.setDirectory(QDir::currentPath()); fd.setAcceptMode(WuQFileDialog::AcceptSave); fd.setWindowTitle("Choose Region of Interest File Name"); fd.setFilter(FileFilters::getRegionOfInterestFileFilter()); fd.setFileMode(WuQFileDialog::AnyFile); if (fd.exec() == QDialog::Accepted) { if (fd.selectedFiles().count() > 0) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); const QString fileName = fd.selectedFiles().at(0); NodeRegionOfInterestFile roiFile; BrainModelSurfaceROINodeSelection* roi = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); roi->setRegionOfInterestIntoFile(roiFile); try { roiFile.writeFile(fileName); } catch (FileException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); return; } QApplication::restoreOverrideCursor(); } } } /** * called when dilate ROI push button pressed. */ void GuiSurfaceROINodeSelectionPage::slotDilateROIPushButton() { // // Get operational surface // const BrainModelSurface* bms = roiDialog->getCopyOfOperationSurface(); if (bms == NULL) { QMessageBox::critical(this, "ERROR", "The operational surface is invalid."); return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainModelSurfaceROINodeSelection* roi = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); roi->dilate(bms, 1); updateNumberOfSelectedNodesLabel(); theMainWindow->getBrainSet()->clearAllDisplayLists(); GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); // // Free copy of surface // delete bms; bms = NULL; // // Update complete status // emit completeChanged(); } /** * called when erode ROI push button pressed. */ void GuiSurfaceROINodeSelectionPage::slotErodeROIPushButton() { // // Get operational surface // const BrainModelSurface* bms = roiDialog->getCopyOfOperationSurface(); if (bms == NULL) { QMessageBox::critical(this, "ERROR", "The operational surface is invalid."); return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainModelSurfaceROINodeSelection* roi = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); roi->erode(bms, 1); updateNumberOfSelectedNodesLabel(); theMainWindow->getBrainSet()->clearAllDisplayLists(); GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); // // Free the copy of the surface // delete bms; bms = NULL; // // Update complete status // emit completeChanged(); } /** * called when extent push button pressed. */ void GuiSurfaceROINodeSelectionPage::slotExtentPushButton() { // // Get operational surface // const BrainModelSurface* bms = roiDialog->getCopyOfOperationSurface(); if (bms == NULL) { QMessageBox::critical(this, "ERROR", "The operational surface is invalid."); return; } const float defaultValue = 10000000.0; WuQDataEntryDialog ded(this); QDoubleSpinBox* xMinSpinBox = ded.addDoubleSpinBox("X-Min", -defaultValue); QDoubleSpinBox* xMaxSpinBox = ded.addDoubleSpinBox("X-Max", defaultValue); QDoubleSpinBox* yMinSpinBox = ded.addDoubleSpinBox("Y-Min", -defaultValue); QDoubleSpinBox* yMaxSpinBox = ded.addDoubleSpinBox("Y-Max", defaultValue); QDoubleSpinBox* zMinSpinBox = ded.addDoubleSpinBox("Z-Min", -defaultValue); QDoubleSpinBox* zMaxSpinBox = ded.addDoubleSpinBox("Z-Max", defaultValue); if (ded.exec() == WuQDataEntryDialog::Accepted) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); const float extent[6] = { xMinSpinBox->value(), xMaxSpinBox->value(), yMinSpinBox->value(), yMaxSpinBox->value(), zMinSpinBox->value(), zMaxSpinBox->value() }; BrainModelSurfaceROINodeSelection* roi = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); roi->limitExtent(bms, extent); updateNumberOfSelectedNodesLabel(); theMainWindow->getBrainSet()->clearAllDisplayLists(); GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); } // // Free the copy of the surface // delete bms; bms = NULL; // // Update complete status // emit completeChanged(); } /** * clean up the page. */ void GuiSurfaceROINodeSelectionPage::cleanupPage() { updateNumberOfSelectedNodesLabel(); } /** * initialize the page. */ void GuiSurfaceROINodeSelectionPage::initializePage() { updateNumberOfSelectedNodesLabel(); } /** * update the page. */ void GuiSurfaceROINodeSelectionPage::updatePage() { borderFlatSurfaceSelectionComboBox->updateComboBox(); metricColumnSelectionComboBox->updateComboBox(); paintColumnSelectionComboBox->updateComboBox(); shapeColumnSelectionComboBox->updateComboBox(); updateNumberOfSelectedNodesLabel(); } /** * validate the page. */ bool GuiSurfaceROINodeSelectionPage::validatePage() { BrainModelSurfaceROINodeSelection* roi = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); if (roi->anyNodesSelected()) { return true; } QMessageBox::critical(this, "ERROR", "No Nodes Selected\n" "Did you forget to press the \"Select Nodes\" button?"); return false; } /** * is page complete. */ bool GuiSurfaceROINodeSelectionPage::isComplete() { BrainModelSurfaceROINodeSelection* roi = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); if (roi->anyNodesSelected()) { return true; } return false; } //============================================================================ //============================================================================ //============================================================================ /** * constructor. */ GuiSurfaceROISurfaceAndTopologySelectionPage::GuiSurfaceROISurfaceAndTopologySelectionPage( GuiSurfaceRegionOfInterestDialog* roiDialogIn) { roiDialog = roiDialogIn; setTitle("Surface and Topology Selection"); // // Surface selection // QLabel* surfaceSelectionLabel = new QLabel("Surface"); operationSurfaceSelectionComboBox = new GuiBrainModelSelectionComboBox(GuiBrainModelSelectionComboBox::OPTION_SHOW_SURFACES_ALL); QObject::connect(operationSurfaceSelectionComboBox, SIGNAL(activated(int)), this, SLOT(slotOperationSurfaceSelectionComboBox())); // // Topology Selection // QLabel* topologySelectionLabel = new QLabel("Topology"); operationTopologyComboBox = new GuiTopologyFileComboBox; QObject::connect(operationTopologyComboBox, SIGNAL(activated(int)), this, SLOT(slotOperationTopologyComboBox())); // // Layout the widgets // QGridLayout* surfaceTopologyLayout = new QGridLayout; surfaceTopologyLayout->setColumnStretch(0, 0); surfaceTopologyLayout->setColumnStretch(100, 0); surfaceTopologyLayout->addWidget(surfaceSelectionLabel, 0, 0); surfaceTopologyLayout->addWidget(operationSurfaceSelectionComboBox, 0, 1); surfaceTopologyLayout->addWidget(topologySelectionLabel, 1, 0); surfaceTopologyLayout->addWidget(operationTopologyComboBox, 1, 1); QVBoxLayout* pageLayout = new QVBoxLayout(this); pageLayout->addLayout(surfaceTopologyLayout); pageLayout->addStretch(); } /** * destructor. */ GuiSurfaceROISurfaceAndTopologySelectionPage::~GuiSurfaceROISurfaceAndTopologySelectionPage() { } /** * clean up the page. */ void GuiSurfaceROISurfaceAndTopologySelectionPage::cleanupPage() { } /** * initialize the page. */ void GuiSurfaceROISurfaceAndTopologySelectionPage::initializePage() { updatePage(); } /** * validate the page. */ bool GuiSurfaceROISurfaceAndTopologySelectionPage::validatePage() { return isComplete(); } /** * is page complete. */ bool GuiSurfaceROISurfaceAndTopologySelectionPage::isComplete() { if ((operationSurfaceSelectionComboBox->getSelectedBrainModelSurface() != NULL) && (operationTopologyComboBox->getSelectedTopologyFile() != NULL)) { return true; } return false; } /** * update the page. */ void GuiSurfaceROISurfaceAndTopologySelectionPage::updatePage() { operationSurfaceSelectionComboBox->updateComboBox(); operationTopologyComboBox->updateComboBox(); slotOperationSurfaceSelectionComboBox(); } /** * get the operation coordinate file. */ CoordinateFile* GuiSurfaceROISurfaceAndTopologySelectionPage::getOperationCoordinateFile() { BrainModelSurface* bms = operationSurfaceSelectionComboBox->getSelectedBrainModelSurface(); if (bms != NULL) { return bms->getCoordinateFile(); } return NULL; } /** * get a COPY of operation surface with operation topology (user must delete object). */ BrainModelSurface* GuiSurfaceROISurfaceAndTopologySelectionPage::getCopyOfOperationSurface() { BrainModelSurface* bms = operationSurfaceSelectionComboBox->getSelectedBrainModelSurface(); if (bms != NULL) { TopologyFile* tf = operationTopologyComboBox->getSelectedTopologyFile(); if (tf != NULL) { BrainModelSurface* bmsCopy = new BrainModelSurface(*bms); bmsCopy->getCoordinateFile()->setFileName(bms->getCoordinateFile()->getFileName()); bmsCopy->setTopologyFile(tf); return bmsCopy; } } return NULL; } /** * called when a surface is selected. */ void GuiSurfaceROISurfaceAndTopologySelectionPage::slotOperationSurfaceSelectionComboBox() { const BrainModelSurface* bms = operationSurfaceSelectionComboBox->getSelectedBrainModelSurface(); if (bms != NULL) { const TopologyFile* tf = bms->getTopologyFile(); if (tf != NULL) { operationTopologyComboBox->setSelectedTopologyFile(tf); } } } /** * called when topology is selected. */ void GuiSurfaceROISurfaceAndTopologySelectionPage::slotOperationTopologyComboBox() { } //============================================================================ //============================================================================ //============================================================================ /** * constructor. */ GuiSurfaceROIOperationPage::GuiSurfaceROIOperationPage(GuiSurfaceRegionOfInterestDialog* roiDialogIn, GuiSurfaceROIReportPage* reportPageIn) { roiDialog = roiDialogIn; reportPage = reportPageIn; setTitle("Region of Interest Operation"); // // Operation selection combo box // operationSelectionComboBox = new QComboBox; QObject::connect(operationSelectionComboBox, SIGNAL(activated(int)), this, SLOT(slotOperationSelectionComboBox(int))); // // Load operation // operationSelectionComboBox->addItem("Assign Metric", OPERATION_MODE_ASSIGN_METRIC); operationSelectionComboBox->addItem("Assign Metric With Node Areas", OPERATION_MODE_ASSIGN_METRIC_NODE_AREAS); operationSelectionComboBox->addItem("Assign Paint", OPERATION_MODE_ASSIGN_PAINT); operationSelectionComboBox->addItem("Assign Surface Shape", OPERATION_MODE_ASSIGN_SURFACE_SHAPE); operationSelectionComboBox->addItem("Compute Integrated Folding Index", OPERATION_MODE_COMPUTE_INTEGRATED_FOLDING_INDEX); operationSelectionComboBox->addItem("Create Areal Borders From Clusters", OPERATION_MODE_CREATE_BORDERS_FROM_CLUSTERS); operationSelectionComboBox->addItem("Create Linear Borders From Region of Interest", OPERATION_MODE_CREATE_BORDERS_FROM_ROI); operationSelectionComboBox->addItem("Create Volume Region of Interest", OPERATION_MODE_CREATE_VOLUME_ROI); operationSelectionComboBox->addItem("Disconnect Nodes", OPERATION_MODE_DISCONNECT_NODES); operationSelectionComboBox->addItem("Folding Measurements", OPERATION_MODE_FOLDING_MEASUREMENTS); operationSelectionComboBox->addItem("Geodesic Distance", OPERATION_MODE_GEODESIC); operationSelectionComboBox->addItem("Metric Clusters Analysis", OPERATION_MODE_METRIC_CLUSTER_ANALYSIS); operationSelectionComboBox->addItem("Probabilistic Atlas Overlap", OPERATION_MODE_PROB_ATLAS_OVERLAP); operationSelectionComboBox->addItem("Smoothing", OPERATION_MODE_SMOOTH_NODES); operationSelectionComboBox->addItem("Statistical Paint Report", OPERATION_MODE_STATISTICAL_PAINT_REPORT); operationSelectionComboBox->addItem("Statistical Report", OPERATION_MODE_STATISTICAL_REPORT); operationSelectionComboBox->addItem("Surface Shape Correlation Report", OPERATION_MODE_SHAPE_CORRELATION); operationSelectionComboBox->addItem("Surface Shape Clusters Analysis", OPERATION_MODE_SHAPE_CLUSTER_ANALYSIS); // // Group box for operation selection // QGroupBox* operationSelectionGroupBox = new QGroupBox("Operation Selection"); QHBoxLayout* operationSelectionLayout = new QHBoxLayout(operationSelectionGroupBox); operationSelectionLayout->addWidget(operationSelectionComboBox); operationSelectionLayout->addStretch(); // // the assign metric page // assignMetricPage = createAssignMetricPage(); // assign metric with node areas nodeAreaMetricPage = createNodeAreasPage(); // the assign paint page assignPaintPage = createAssignPaintPage(); // the assign shape page assignShapePage = createAssignShapePage(); // the compute integrated folding index page computeIntegratedFoldingIndexPage = createComputeIntegratedFoldingIndexPage(); // the folding measurements page foldingMeasurementsPage = createFoldingMeasurementsPage(); // the create borders from clusters page createArealBordersPage = createCreateArealBordersPage(); // the create linear borders page linearBordersPage = createLinearBordersPage(); // the create volume roi page createVolumeROIPage = createCreateVolumeROIPage(); // the disconnect nodes page disconnectNodesPage = createDisconnectNodesPage(); // the geodesic page geodesicPage = createGeodesicPage(); // the metric cluster analysis page metricClusterAnalysisPage = createMetricClusterAnalysisPage(); // the probabilistic atlas overlap page probAtlasOverlapPage = createProbAtlasOverlapPage(); // the smoothing page smoothingPage = createSmoothingPage(); // the statistical paint report page paintReportPage = createPaintReportPage(); // the statistical report page statisticalReportPage = createStatisticalReportPage(); // the shape correlation page shapeCorrelationPage = createShapeCorrelationPage(); // the shape cluster analysis page shapeClusterAnalysisPage = createShapeClusterAnalysisPage(); // // Operation stacked widget // operationsStackedWidget = new QStackedWidget; operationsStackedWidget->addWidget(assignMetricPage); operationsStackedWidget->addWidget(nodeAreaMetricPage); operationsStackedWidget->addWidget(assignPaintPage); operationsStackedWidget->addWidget(assignShapePage); operationsStackedWidget->addWidget(computeIntegratedFoldingIndexPage); operationsStackedWidget->addWidget(createArealBordersPage); operationsStackedWidget->addWidget(foldingMeasurementsPage); operationsStackedWidget->addWidget(linearBordersPage); operationsStackedWidget->addWidget(createVolumeROIPage); operationsStackedWidget->addWidget(disconnectNodesPage); operationsStackedWidget->addWidget(geodesicPage); operationsStackedWidget->addWidget(metricClusterAnalysisPage); operationsStackedWidget->addWidget(probAtlasOverlapPage); operationsStackedWidget->addWidget(smoothingPage); operationsStackedWidget->addWidget(paintReportPage); operationsStackedWidget->addWidget(statisticalReportPage); operationsStackedWidget->addWidget(shapeCorrelationPage); operationsStackedWidget->addWidget(shapeClusterAnalysisPage); // // Group box for operation parameters // QGroupBox* operationParametersGroupBox = new QGroupBox("Operation Parameters"); QVBoxLayout* operationParametersLayout = new QVBoxLayout(operationParametersGroupBox); operationParametersLayout->addWidget(operationsStackedWidget); operationParametersLayout->addStretch(); // // Layout for widget // QVBoxLayout* pageLayout = new QVBoxLayout(this); pageLayout->addWidget(operationSelectionGroupBox); pageLayout->addWidget(operationParametersGroupBox); pageLayout->addStretch(); } /** * destructor. */ GuiSurfaceROIOperationPage::~GuiSurfaceROIOperationPage() { } /** * clean up the page. */ void GuiSurfaceROIOperationPage::cleanupPage() { updatePage(); } /** * initialize the page. */ void GuiSurfaceROIOperationPage::initializePage() { updatePage(); } /** * validate the page. */ bool GuiSurfaceROIOperationPage::validatePage() { return true; } /** * is page complete. */ bool GuiSurfaceROIOperationPage::isComplete() { return true; } /** * update the page. */ void GuiSurfaceROIOperationPage::updatePage() { assignMetricColumnSelectionComboBox->updateComboBox(); assignMetricColumnNameLineEdit->setText(assignMetricColumnSelectionComboBox->currentText()); assignPaintColumnSelectionComboBox->updateComboBox(); assignPaintColumnNameLineEdit->setText(assignPaintColumnSelectionComboBox->currentText()); assignShapeColumnSelectionComboBox->updateComboBox(); assignShapeColumnNameLineEdit->setText(assignShapeColumnSelectionComboBox->currentText()); geodesicMetricColumnComboBox->updateComboBox(); geodesicMetricColumnNameLineEdit->setText(geodesicMetricColumnComboBox->currentText()); geodesicDistanceColumnComboBox->updateComboBox(); geodesicDistanceColumnNameLineEdit->setText(geodesicDistanceColumnComboBox->currentText()); paintRegionReportColumnComboBox->updateComboBox(); statisticalReportDistortionCorrectionMetricColumnComboBox->updateComboBox(); paintRegionReportDistortionCorrectionMetricColumnComboBox->updateComboBox(); shapeCorrelationColumnComboBox->updateComboBox(); shapeClusterMetricArealDistortionComboBox->updateComboBox(); metricClusterMetricArealDistortionComboBox->updateComboBox(); } /** * called when an operation is selected. */ void GuiSurfaceROIOperationPage::slotOperationSelectionComboBox(int indx) { const OPERATION_MODE mode = static_cast(operationSelectionComboBox->itemData(indx).toInt()); switch (mode) { case OPERATION_MODE_ASSIGN_METRIC: operationsStackedWidget->setCurrentWidget(assignMetricPage); break; case OPERATION_MODE_ASSIGN_METRIC_NODE_AREAS: operationsStackedWidget->setCurrentWidget(nodeAreaMetricPage); break; case OPERATION_MODE_ASSIGN_PAINT: operationsStackedWidget->setCurrentWidget(assignPaintPage); break; case OPERATION_MODE_ASSIGN_SURFACE_SHAPE: operationsStackedWidget->setCurrentWidget(assignShapePage); break; case OPERATION_MODE_COMPUTE_INTEGRATED_FOLDING_INDEX: operationsStackedWidget->setCurrentWidget(computeIntegratedFoldingIndexPage); break; case OPERATION_MODE_CREATE_BORDERS_FROM_CLUSTERS: operationsStackedWidget->setCurrentWidget(createArealBordersPage); break; case OPERATION_MODE_CREATE_BORDERS_FROM_ROI: operationsStackedWidget->setCurrentWidget(linearBordersPage); break; case OPERATION_MODE_CREATE_VOLUME_ROI: operationsStackedWidget->setCurrentWidget(createVolumeROIPage); break; case OPERATION_MODE_DISCONNECT_NODES: operationsStackedWidget->setCurrentWidget(disconnectNodesPage); break; case OPERATION_MODE_FOLDING_MEASUREMENTS: operationsStackedWidget->setCurrentWidget(foldingMeasurementsPage); break; case OPERATION_MODE_GEODESIC: operationsStackedWidget->setCurrentWidget(geodesicPage); break; case OPERATION_MODE_METRIC_CLUSTER_ANALYSIS: operationsStackedWidget->setCurrentWidget(metricClusterAnalysisPage); break; case OPERATION_MODE_PROB_ATLAS_OVERLAP: operationsStackedWidget->setCurrentWidget(probAtlasOverlapPage); break; case OPERATION_MODE_SMOOTH_NODES: operationsStackedWidget->setCurrentWidget(smoothingPage); break; case OPERATION_MODE_STATISTICAL_PAINT_REPORT: operationsStackedWidget->setCurrentWidget(paintReportPage); break; case OPERATION_MODE_STATISTICAL_REPORT: operationsStackedWidget->setCurrentWidget(statisticalReportPage); break; case OPERATION_MODE_SHAPE_CORRELATION: operationsStackedWidget->setCurrentWidget(shapeCorrelationPage); break; case OPERATION_MODE_SHAPE_CLUSTER_ANALYSIS: operationsStackedWidget->setCurrentWidget(shapeClusterAnalysisPage); break; } } /** * create the node areas page. */ QWidget* GuiSurfaceROIOperationPage::createNodeAreasPage() { // // Column selection // QLabel* metricLabel = new QLabel("Metric Column Selection"); nodeAreaMetricColumnSelectionComboBox = new GuiNodeAttributeColumnSelectionComboBox(GUI_NODE_FILE_TYPE_METRIC, true, false, false); // // Edit Column name // QLabel* editLabel = new QLabel("Edit Column Name"); nodeAreaMetricColumnNameLineEdit = new QLineEdit; QObject::connect(nodeAreaMetricColumnSelectionComboBox, SIGNAL(itemNameSelected(const QString&)), nodeAreaMetricColumnNameLineEdit, SLOT(setText(const QString&))); // // Percentage check box // nodeAreaPercentageCheckBox = new QCheckBox("Set Percentage of Total Surface Area"); nodeAreaPercentageCheckBox->setToolTip("If this box is checked, the value \n" "assigned to each node is the percentage\n" "of the total surface contributed by the\n" "node."); // // node area metric button // QPushButton* nodeAreaMetricPushButton = new QPushButton("Assign Metric Node Areas"); nodeAreaMetricPushButton->setAutoDefault(false); nodeAreaMetricPushButton->setFixedSize(nodeAreaMetricPushButton->sizeHint()); QObject::connect(nodeAreaMetricPushButton, SIGNAL(clicked()), this, SLOT(slotNodeAreaMetricPushButton())); // // Layout widgets // QGridLayout* gridLayout = new QGridLayout; gridLayout->addWidget(metricLabel, 0, 0); gridLayout->addWidget(nodeAreaMetricColumnSelectionComboBox, 0, 1); gridLayout->addWidget(editLabel, 1, 0); gridLayout->addWidget(nodeAreaMetricColumnNameLineEdit, 1, 1); gridLayout->addWidget(nodeAreaPercentageCheckBox, 2, 0, 2, 1); QWidget* w = new QWidget; QVBoxLayout* layout = new QVBoxLayout(w); layout->addLayout(gridLayout); layout->addWidget(nodeAreaMetricPushButton); layout->addStretch(); return w; } /** * called to set node areas for metric. */ void GuiSurfaceROIOperationPage::slotNodeAreaMetricPushButton() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); QString errorMessage; BrainModelSurface* bms = roiDialog->getCopyOfOperationSurface(); MetricFile* mf = theMainWindow->getBrainSet()->getMetricFile(); int metricColumn = nodeAreaMetricColumnSelectionComboBox->currentIndex(); try { BrainModelSurfaceROINodeSelection* roi = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); BrainModelSurfaceROIAssignMetricNodeArea metricROI(theMainWindow->getBrainSet(), bms, roi, mf, metricColumn, assignMetricColumnNameLineEdit->text(), nodeAreaPercentageCheckBox->isChecked()); metricROI.execute(); metricColumn = metricROI.getAssignedMetricColumn(); } catch (BrainModelAlgorithmException& e) { errorMessage = e.whatQString(); } delete bms; // // Metric File has changed // GuiFilesModified fm; fm.setMetricModified(); theMainWindow->fileModificationUpdate(fm); // // Update node colors and redraw // theMainWindow->getBrainSet()->getNodeColoring()->assignColors(); GuiBrainModelOpenGL::updateAllGL(NULL); // // Save assigned column since it may be new // assignMetricColumnSelectionComboBox->setCurrentIndex(metricColumn); assignMetricColumnNameLineEdit->setText(assignMetricColumnSelectionComboBox->currentText()); QApplication::restoreOverrideCursor(); if (errorMessage.isEmpty() == false) { QMessageBox::critical(this, "ERROR", errorMessage); } } /** * create the assign metric page. */ QWidget* GuiSurfaceROIOperationPage::createAssignMetricPage() { // // Column selection // QLabel* metricLabel = new QLabel("Metric Column Selection"); assignMetricColumnSelectionComboBox = new GuiNodeAttributeColumnSelectionComboBox(GUI_NODE_FILE_TYPE_METRIC, true, false, false); // // Edit Column name // QLabel* editLabel = new QLabel("Edit Column Name"); assignMetricColumnNameLineEdit = new QLineEdit; QObject::connect(assignMetricColumnSelectionComboBox, SIGNAL(itemNameSelected(const QString&)), assignMetricColumnNameLineEdit, SLOT(setText(const QString&))); // // New metric value // QLabel* newValueLabel = new QLabel("Assign Value"); assignMetricValueDoubleSpinBox = new QDoubleSpinBox; assignMetricValueDoubleSpinBox->setMinimum(-std::numeric_limits::max()); assignMetricValueDoubleSpinBox->setMaximum(std::numeric_limits::max()); assignMetricValueDoubleSpinBox->setDecimals(4); assignMetricValueDoubleSpinBox->setSingleStep(1.0); // // Assign metric button // QPushButton* assignMetricPushButton = new QPushButton("Assign Metric"); assignMetricPushButton->setAutoDefault(false); assignMetricPushButton->setFixedSize(assignMetricPushButton->sizeHint()); QObject::connect(assignMetricPushButton, SIGNAL(clicked()), this, SLOT(slotAssignMetricPushButton())); // // Layout widgets // QGridLayout* gridLayout = new QGridLayout; gridLayout->addWidget(metricLabel, 0, 0); gridLayout->addWidget(assignMetricColumnSelectionComboBox, 0, 1); gridLayout->addWidget(editLabel, 1, 0); gridLayout->addWidget(assignMetricColumnNameLineEdit, 1, 1); gridLayout->addWidget(newValueLabel, 2, 0); gridLayout->addWidget(assignMetricValueDoubleSpinBox, 2, 1); QWidget* w = new QWidget; QVBoxLayout* layout = new QVBoxLayout(w); layout->addLayout(gridLayout); layout->addWidget(assignMetricPushButton); layout->addStretch(); return w; } /** * called to assign metric. */ void GuiSurfaceROIOperationPage::slotAssignMetricPushButton() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); QString errorMessage; BrainModelSurface* bms = roiDialog->getCopyOfOperationSurface(); MetricFile* mf = theMainWindow->getBrainSet()->getMetricFile(); int metricColumn = assignMetricColumnSelectionComboBox->currentIndex(); try { BrainModelSurfaceROINodeSelection* roi = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); BrainModelSurfaceROIAssignMetric metricROI(theMainWindow->getBrainSet(), bms, roi, mf, metricColumn, assignMetricColumnNameLineEdit->text(), assignMetricValueDoubleSpinBox->value()); metricROI.execute(); metricColumn = metricROI.getAssignedMetricColumn(); } catch (BrainModelAlgorithmException& e) { errorMessage = e.whatQString(); } delete bms; // // Metric File has changed // GuiFilesModified fm; fm.setMetricModified(); theMainWindow->fileModificationUpdate(fm); // // Update node colors and redraw // theMainWindow->getBrainSet()->getNodeColoring()->assignColors(); GuiBrainModelOpenGL::updateAllGL(NULL); // // Save assigned column since it may be new // assignMetricColumnSelectionComboBox->setCurrentIndex(metricColumn); assignMetricColumnNameLineEdit->setText(assignMetricColumnSelectionComboBox->currentText()); QApplication::restoreOverrideCursor(); if (errorMessage.isEmpty() == false) { QMessageBox::critical(this, "ERROR", errorMessage); } } /** * create the assign paint page. */ QWidget* GuiSurfaceROIOperationPage::createAssignPaintPage() { // // Column selection // QLabel* paintLabel = new QLabel("Paint Column Selection"); assignPaintColumnSelectionComboBox = new GuiNodeAttributeColumnSelectionComboBox(GUI_NODE_FILE_TYPE_PAINT, true, false, false); // // Edit Column name // QLabel* editLabel = new QLabel("Edit Column Name"); assignPaintColumnNameLineEdit = new QLineEdit; QObject::connect(assignPaintColumnSelectionComboBox, SIGNAL(itemNameSelected(const QString&)), assignPaintColumnNameLineEdit, SLOT(setText(const QString&))); // // New paint name // QLabel* newNameLabel = new QLabel("Assign Name"); assignPaintNameLineEdit = new QLineEdit; // // Assign paint button // QPushButton* assignPaintPushButton = new QPushButton("Assign Paint"); assignPaintPushButton->setAutoDefault(false); assignPaintPushButton->setFixedSize(assignPaintPushButton->sizeHint()); QObject::connect(assignPaintPushButton, SIGNAL(clicked()), this, SLOT(slotAssignPaintPushButton())); // // Layout widgets // QGridLayout* gridLayout = new QGridLayout; gridLayout->addWidget(paintLabel, 0, 0); gridLayout->addWidget(assignPaintColumnSelectionComboBox, 0, 1); gridLayout->addWidget(editLabel, 1, 0); gridLayout->addWidget(assignPaintColumnNameLineEdit, 1, 1); gridLayout->addWidget(newNameLabel, 2, 0); gridLayout->addWidget(assignPaintNameLineEdit, 2, 1); QWidget* w = new QWidget; QVBoxLayout* layout = new QVBoxLayout(w); layout->addLayout(gridLayout); layout->addWidget(assignPaintPushButton); layout->addStretch(); return w; } /** * called to assign paint. */ void GuiSurfaceROIOperationPage::slotAssignPaintPushButton() { const QString paintName = assignPaintNameLineEdit->text(); if (paintName.isEmpty()) { QMessageBox::critical(this, "ERROR", "Paint name is empty."); } AreaColorFile* cf = theMainWindow->getBrainSet()->getAreaColorFile(); bool areaColorMatch = false; int areaColorIndex = cf->getColorIndexByName(paintName, areaColorMatch); // area color may need to be created // bool createAreaColor = false; if ((areaColorIndex >= 0) && (areaColorMatch == true)) { createAreaColor = false; } else if ((areaColorIndex >= 0) && (areaColorMatch == false)) { QString msg("Use area color \""); msg.append(cf->getColorNameByIndex(areaColorIndex)); msg.append("\" for paint "); msg.append(paintName); msg.append(" ?"); QString noButton("No, define color "); noButton.append(paintName); QMessageBox msgBox(this); msgBox.setWindowTitle("Use Partially Matching Color"); msgBox.setText(msg); msgBox.addButton("Yes", QMessageBox::YesRole); QPushButton* noPushButton = msgBox.addButton(noButton, QMessageBox::NoRole); msgBox.exec(); if (msgBox.clickedButton() == noPushButton) { createAreaColor = true; } } else { createAreaColor = true; } if (createAreaColor) { QString title("Create Area Color: "); title.append(paintName); GuiColorSelectionDialog* csd = new GuiColorSelectionDialog(this, title, false, false, false, false); csd->exec(); // // Add new area color // float pointSize = 2.0, lineSize = 1.0; unsigned char r, g, b, a; ColorFile::ColorStorage::SYMBOL symbol; csd->getColorInformation(r, g, b, a, pointSize, lineSize, symbol); cf->addColor(paintName, r, g, b, a, pointSize, lineSize, symbol); areaColorIndex = cf->getNumberOfColors() - 1; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); QString errorMessage; BrainModelSurface* bms = roiDialog->getCopyOfOperationSurface(); PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); int paintColumn = assignPaintColumnSelectionComboBox->currentIndex(); try { BrainModelSurfaceROINodeSelection* roi = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); BrainModelSurfaceROIAssignPaint paintROI(theMainWindow->getBrainSet(), bms, roi, pf, paintColumn, assignPaintColumnNameLineEdit->text(), paintName); paintROI.execute(); paintColumn = paintROI.getAssignedPaintColumn(); } catch (BrainModelAlgorithmException& e) { errorMessage = e.whatQString(); } delete bms; // // Paint File has changed // GuiFilesModified fm; fm.setPaintModified(); theMainWindow->fileModificationUpdate(fm); // // Update node colors and redraw // theMainWindow->getBrainSet()->getNodeColoring()->assignColors(); GuiBrainModelOpenGL::updateAllGL(NULL); // // Save assigned column since it may be new // assignPaintColumnSelectionComboBox->setCurrentIndex(paintColumn); assignPaintColumnNameLineEdit->setText(assignPaintColumnSelectionComboBox->currentText()); QApplication::restoreOverrideCursor(); if (errorMessage.isEmpty() == false) { QMessageBox::critical(this, "ERROR", errorMessage); } } /** * create the assign shape page. */ QWidget* GuiSurfaceROIOperationPage::createAssignShapePage() { // // Column selection // QLabel* shapeLabel = new QLabel("Shape Column Selection"); assignShapeColumnSelectionComboBox = new GuiNodeAttributeColumnSelectionComboBox(GUI_NODE_FILE_TYPE_SURFACE_SHAPE, true, false, false); // // Edit Column name // QLabel* editLabel = new QLabel("Edit Column Name"); assignShapeColumnNameLineEdit = new QLineEdit; QObject::connect(assignShapeColumnSelectionComboBox, SIGNAL(itemNameSelected(const QString&)), assignShapeColumnNameLineEdit, SLOT(setText(const QString&))); // // New shape value // QLabel* newValueLabel = new QLabel("Assign Value"); assignShapeValueDoubleSpinBox = new QDoubleSpinBox; assignShapeValueDoubleSpinBox->setMinimum(-std::numeric_limits::max()); assignShapeValueDoubleSpinBox->setMaximum(std::numeric_limits::max()); assignShapeValueDoubleSpinBox->setDecimals(4); assignShapeValueDoubleSpinBox->setSingleStep(1.0); // // Assign shape button // QPushButton* assignShapePushButton = new QPushButton("Assign Shape"); assignShapePushButton->setAutoDefault(false); assignShapePushButton->setFixedSize(assignShapePushButton->sizeHint()); QObject::connect(assignShapePushButton, SIGNAL(clicked()), this, SLOT(slotAssignShapePushButton())); // // Layout widgets // QGridLayout* gridLayout = new QGridLayout; gridLayout->addWidget(shapeLabel, 0, 0); gridLayout->addWidget(assignShapeColumnSelectionComboBox, 0, 1); gridLayout->addWidget(editLabel, 1, 0); gridLayout->addWidget(assignShapeColumnNameLineEdit, 1, 1); gridLayout->addWidget(newValueLabel, 2, 0); gridLayout->addWidget(assignShapeValueDoubleSpinBox, 2, 1); QWidget* w = new QWidget; QVBoxLayout* layout = new QVBoxLayout(w); layout->addLayout(gridLayout); layout->addWidget(assignShapePushButton); layout->addStretch(); return w; } /** * called to assign metric. */ void GuiSurfaceROIOperationPage::slotAssignShapePushButton() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); QString errorMessage; BrainModelSurface* bms = roiDialog->getCopyOfOperationSurface(); SurfaceShapeFile* ssf = theMainWindow->getBrainSet()->getSurfaceShapeFile(); int shapeColumn = assignShapeColumnSelectionComboBox->currentIndex(); try { BrainModelSurfaceROINodeSelection* roi = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); BrainModelSurfaceROIAssignShape shapeROI(theMainWindow->getBrainSet(), bms, roi, ssf, shapeColumn, assignShapeColumnNameLineEdit->text(), assignShapeValueDoubleSpinBox->value()); shapeROI.execute(); shapeColumn = shapeROI.getAssignedShapeColumn(); } catch (BrainModelAlgorithmException& e) { errorMessage = e.whatQString(); } delete bms; // // Shape File has changed // GuiFilesModified fm; fm.setSurfaceShapeModified(); theMainWindow->fileModificationUpdate(fm); // // Update node colors and redraw // theMainWindow->getBrainSet()->getNodeColoring()->assignColors(); GuiBrainModelOpenGL::updateAllGL(NULL); // // Save assigned column since it may be new // assignShapeColumnSelectionComboBox->setCurrentIndex(shapeColumn); assignShapeColumnNameLineEdit->setText(assignShapeColumnSelectionComboBox->currentText()); QApplication::restoreOverrideCursor(); if (errorMessage.isEmpty() == false) { QMessageBox::critical(this, "ERROR", errorMessage); } } /** * create the compute integrated folding index page. */ QWidget* GuiSurfaceROIOperationPage::createComputeIntegratedFoldingIndexPage() { semicolonSeparateFoldingIndexReportCheckBox = new QCheckBox("Semicolon Separate Integrated Folding Report"); QPushButton* computePushButton = new QPushButton("Compute Integrated Folding Index"); computePushButton->setFixedSize(computePushButton->sizeHint()); computePushButton->setAutoDefault(false); QObject::connect(computePushButton, SIGNAL(clicked()), this, SLOT(slotComputeIntegratedFoldingIndex())); QWidget* w = new QWidget; QVBoxLayout* layout = new QVBoxLayout(w); layout->addWidget(semicolonSeparateFoldingIndexReportCheckBox); layout->addWidget(computePushButton); return w; } /** * called to run compute integrated folding index. */ void GuiSurfaceROIOperationPage::slotComputeIntegratedFoldingIndex() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); QString errorMessage; BrainModelSurface* bms = roiDialog->getCopyOfOperationSurface(); SurfaceShapeFile* ssf = theMainWindow->getBrainSet()->getSurfaceShapeFile(); try { BrainModelSurfaceROINodeSelection* roi = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); QString headerText("Integrated Folding Index"); BrainModelSurfaceROIIntegratedFoldingIndexReport ifi( theMainWindow->getBrainSet(), bms, roi, ssf, headerText, semicolonSeparateFoldingIndexReportCheckBox->isChecked()); ifi.execute(); // // set report text // reportPage->setReportText(ifi.getReportText()); } catch (BrainModelAlgorithmException& e) { errorMessage = e.whatQString(); } delete bms; QApplication::restoreOverrideCursor(); if (errorMessage.isEmpty() == false) { QMessageBox::critical(this, "ERROR", errorMessage); } // // Move to next page // roiDialog->next(); } /** * create the folding measurements page. */ QWidget* GuiSurfaceROIOperationPage::createFoldingMeasurementsPage() { foldingMeasurementsMetricFileCheckBox = new QCheckBox("Create Metric File "); foldingMeasurementsMetricFileNameLineEdit = new QLineEdit; foldingMeasurementsMetricFileNameLineEdit->setText("FoldingMeasurements.metric"); QHBoxLayout* metricLayout = new QHBoxLayout(); metricLayout->addWidget(foldingMeasurementsMetricFileCheckBox); metricLayout->addWidget(foldingMeasurementsMetricFileNameLineEdit); QObject::connect(foldingMeasurementsMetricFileCheckBox, SIGNAL(toggled(bool)), foldingMeasurementsMetricFileNameLineEdit, SLOT(setEnabled(bool))); bool defaultFlag = false; foldingMeasurementsMetricFileNameLineEdit->setEnabled(defaultFlag); foldingMeasurementsMetricFileCheckBox->setChecked(defaultFlag); QPushButton* computePushButton = new QPushButton("Compute Folding Measurements"); computePushButton->setFixedSize(computePushButton->sizeHint()); computePushButton->setAutoDefault(false); QObject::connect(computePushButton, SIGNAL(clicked()), this, SLOT(slotFoldingMeasurements())); QWidget* w = new QWidget; QVBoxLayout* layout = new QVBoxLayout(w); layout->addLayout(metricLayout); layout->addWidget(computePushButton); layout->addStretch(); return w; } /** * called to run the folding measurements. */ void GuiSurfaceROIOperationPage::slotFoldingMeasurements() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); QString errorMessage; BrainModelSurface* bms = roiDialog->getCopyOfOperationSurface(); try { BrainModelSurfaceROINodeSelection* roi = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); QString metricFileName = ""; if (foldingMeasurementsMetricFileCheckBox->isChecked()) { metricFileName = foldingMeasurementsMetricFileNameLineEdit->text(); } QString headerText("Folding Measures"); BrainModelSurfaceROIFoldingMeasurementReport fr( theMainWindow->getBrainSet(), bms, roi, headerText, false, NULL, metricFileName); fr.execute(); // // set report text // reportPage->setReportText(fr.getReportText()); } catch (BrainModelAlgorithmException& e) { errorMessage = e.whatQString(); } delete bms; QApplication::restoreOverrideCursor(); if (errorMessage.isEmpty() == false) { QMessageBox::critical(this, "ERROR", errorMessage); } // // Move to next page // roiDialog->next(); } /** * create the create borders from clusters page. */ QWidget* GuiSurfaceROIOperationPage::createCreateArealBordersPage() { // // border to assign // QPushButton* clusterNamePushButton = new QPushButton("Border Name..."); clusterNamePushButton->setAutoDefault(false); clusterNamePushButton->setFixedSize(clusterNamePushButton->sizeHint()); QObject::connect(clusterNamePushButton, SIGNAL(clicked()), this, SLOT(slotArealBorderClusterNamePushButton())); clusterArealBorderNameLineEdit = new QLineEdit; QHBoxLayout* borderNameLayout = new QHBoxLayout; borderNameLayout->addWidget(clusterNamePushButton); borderNameLayout->addWidget(clusterArealBorderNameLineEdit); borderNameLayout->setStretchFactor(clusterNamePushButton, 0); borderNameLayout->setStretchFactor(clusterArealBorderNameLineEdit, 100); // // Auto project borders // clusterArealBorderAutoProjectCheckBox = new QCheckBox("Auto Project"); clusterArealBorderAutoProjectCheckBox->setChecked(true); // // create borders push button // QPushButton* createBordersPushButton = new QPushButton("Create Borders Around Clusters"); createBordersPushButton->setFixedSize(createBordersPushButton->sizeHint()); createBordersPushButton->setAutoDefault(false); QObject::connect(createBordersPushButton, SIGNAL(clicked()), this, SLOT(slotCreateArealBordersFromClusters())); QWidget* w = new QWidget; QVBoxLayout* layout = new QVBoxLayout(w); layout->addLayout(borderNameLayout); layout->addWidget(clusterArealBorderAutoProjectCheckBox); layout->addWidget(createBordersPushButton); layout->addStretch(); return w; } /** * Called to set create borders from clusters name. */ void GuiSurfaceROIOperationPage::slotArealBorderClusterNamePushButton() { GuiNameSelectionDialog nsd(this); if (nsd.exec() == QDialog::Accepted) { clusterArealBorderNameLineEdit->setText(nsd.getNameSelected()); } } /** * Called run create borders from clusters. */ void GuiSurfaceROIOperationPage::slotCreateArealBordersFromClusters() { const QString borderName = clusterArealBorderNameLineEdit->text(); if (borderName.isEmpty()) { QMessageBox::critical(this, "ERROR", "Please enter a border name."); return; } // // Surface must be in the brain set // BrainModelSurface* bms = roiDialog->getCopyOfOperationSurface(); theMainWindow->getBrainSet()->addBrainModel(bms, false); int numberOfBordersCreated = 0; BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); try { BrainModelSurfaceClusterToBorderConverter scbc(theMainWindow->getBrainSet(), bms, bms->getTopologyFile(), borderName, surfaceROI, clusterArealBorderAutoProjectCheckBox->isChecked()); scbc.execute(); numberOfBordersCreated = scbc.getNumberOfBordersCreated(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); } QApplication::restoreOverrideCursor(); if (numberOfBordersCreated > 0) { QString str = (QString::number(numberOfBordersCreated) + " border(s) were created\n"); // // Find the matching color // bool borderColorMatch = false; BorderColorFile* borderColorFile = theMainWindow->getBrainSet()->getBorderColorFile(); const int borderColorIndex = borderColorFile->getColorIndexByName(borderName, borderColorMatch); // // Border color may need to be created // bool createBorderColor = false; if ((borderColorIndex >= 0) && (borderColorMatch == true)) { QMessageBox::information(this, "INFO", str); createBorderColor = false; } else if ((borderColorIndex >= 0) && (borderColorMatch == false)) { str += ("You may use border color \"" + borderColorFile->getColorNameByIndex(borderColorIndex) + "\" for border " + borderName + "\"\n or define a new color."); QString b2("Use color "); b2.append(borderColorFile->getColorNameByIndex(borderColorIndex)); QString b1("Define color "); b1.append(borderName); QMessageBox msgBox(this); msgBox.setWindowTitle("Color"); msgBox.setText(str); QPushButton* pb1 = msgBox.addButton(b1, QMessageBox::NoRole); msgBox.addButton(b2, QMessageBox::NoRole); msgBox.exec(); if (msgBox.clickedButton() == pb1) { createBorderColor = true; } } else { str += ("There is no matching color for " + borderName + "\n" + "Would you like to define the color " + borderName + "?"); QString b1("Define color "); b1.append(borderName); QMessageBox msgBox(this); msgBox.setWindowTitle("Color"); msgBox.setText(str); QPushButton* pb1 = msgBox.addButton(b1, QMessageBox::YesRole); msgBox.addButton("No", QMessageBox::NoRole); msgBox.exec(); if (msgBox.clickedButton() == pb1) { createBorderColor = true; } } if (createBorderColor) { QString title("Create Border Color: "); title.append(borderName); GuiColorSelectionDialog* csd = new GuiColorSelectionDialog(this, title, false, false, false, false); csd->exec(); // // Add new border color // float pointSize = 2.0, lineSize = 1.0; unsigned char r, g, b, a; ColorFile::ColorStorage::SYMBOL symbol; csd->getColorInformation(r, g, b, a, pointSize, lineSize, symbol); borderColorFile->addColor(borderName, r, g, b, a, pointSize, lineSize, symbol); } // // Display borders // theMainWindow->getBrainSet()->assignBorderColors(); DisplaySettingsBorders* dsb = theMainWindow->getBrainSet()->getDisplaySettingsBorders(); dsb->setDisplayBorders(true); // // Update GUI // GuiFilesModified fm; fm.setBorderColorModified(); fm.setBorderModified(); theMainWindow->fileModificationUpdate(fm); } else { QMessageBox::information(this, "INFO", "No clusters were found."); } // // Delete the brain model // theMainWindow->getBrainSet()->deleteBrainModel(bms); GuiBrainModelOpenGL::updateAllGL(); } /** * create the create linear borders page. */ QWidget* GuiSurfaceROIOperationPage::createLinearBordersPage() { // // Border info widgets // QPushButton* borderNamePushButton = new QPushButton("Name..."); borderNamePushButton->setAutoDefault(false); borderNamePushButton->setFixedSize(borderNamePushButton->sizeHint()); QObject::connect(borderNamePushButton, SIGNAL(clicked()), this, SLOT(slotLinearCreateBorderFromROINamePushButton())); createLinearBorderFromROINameLineEdit = new QLineEdit; QLabel* densityLabel = new QLabel("Sampling Density"); createLinearBorderFromROISamplingDensityDoubleSpinBox = new QDoubleSpinBox; createLinearBorderFromROISamplingDensityDoubleSpinBox->setMinimum(0.01); createLinearBorderFromROISamplingDensityDoubleSpinBox->setMaximum(100000.0); createLinearBorderFromROISamplingDensityDoubleSpinBox->setSingleStep(1.0); createLinearBorderFromROISamplingDensityDoubleSpinBox->setDecimals(2); createLinearBorderFromROISamplingDensityDoubleSpinBox->setValue(2.0); createLinearBorderFromROISamplingDensityDoubleSpinBox->setMaximumWidth(100); // // Border info group box and layout // QGroupBox* borderInfoGroupBox = new QGroupBox("Border Information"); QGridLayout* borderInfoGroupLayout = new QGridLayout(borderInfoGroupBox); borderInfoGroupLayout->addWidget(borderNamePushButton, 0, 0); borderInfoGroupLayout->addWidget(createLinearBorderFromROINameLineEdit, 0, 1); borderInfoGroupLayout->addWidget(densityLabel, 1, 0); borderInfoGroupLayout->addWidget(createLinearBorderFromROISamplingDensityDoubleSpinBox, 1, 1, 1, 2); // // Node selection options // createLinearBorderFromROIAutomaticRadioButton = new QRadioButton("Automatic"); createLinearBorderFromROIManualRadioButton = new QRadioButton("Manual"); QLabel* startNodeLabel = new QLabel("Start Node"); QLabel* endNodeLabel = new QLabel("End Node"); createLinearBorderFromROIStartNodeSpinBox = new QSpinBox; createLinearBorderFromROIStartNodeSpinBox->setMinimum(0); createLinearBorderFromROIStartNodeSpinBox->setMaximum(std::numeric_limits::max()); createLinearBorderFromROIStartNodeSpinBox->setSingleStep(1); createLinearBorderFromROIEndNodeSpinBox = new QSpinBox; createLinearBorderFromROIEndNodeSpinBox->setMinimum(-1); createLinearBorderFromROIEndNodeSpinBox->setMaximum(std::numeric_limits::max()); createLinearBorderFromROIEndNodeSpinBox->setSingleStep(1); // // Select start/end nodes with mouse push buttons // QPushButton* selectStartNodeWithMousePushButton = new QPushButton("Select with Mouse"); selectStartNodeWithMousePushButton->setAutoDefault(false); selectStartNodeWithMousePushButton->setFixedSize(selectStartNodeWithMousePushButton->sizeHint()); QObject::connect(selectStartNodeWithMousePushButton, SIGNAL(clicked()), this, SLOT(slotCreateLinearBorderFromROIStartNodePushButton())); QPushButton* selectEndNodeWithMousePushButton = new QPushButton("Select with Mouse"); selectEndNodeWithMousePushButton->setAutoDefault(false); selectEndNodeWithMousePushButton->setFixedSize(selectEndNodeWithMousePushButton->sizeHint()); QObject::connect(selectEndNodeWithMousePushButton, SIGNAL(clicked()), this, SLOT(slotCreateLinearBorderFromROIEndNodePushButton())); // // Button group to keep radio buttons mutually exclusive // QButtonGroup* buttGroup = new QButtonGroup; buttGroup->addButton(createLinearBorderFromROIAutomaticRadioButton); buttGroup->addButton(createLinearBorderFromROIManualRadioButton); // // Layout for start and end node node selection options // QWidget* createBorderFromROINodeSelectionWidget = new QWidget; QGridLayout* nodeNumbersLayout = new QGridLayout(createBorderFromROINodeSelectionWidget); nodeNumbersLayout->addWidget(new QLabel(" "), 0, 0); nodeNumbersLayout->addWidget(startNodeLabel, 0, 1); nodeNumbersLayout->addWidget(createLinearBorderFromROIStartNodeSpinBox, 0, 2); nodeNumbersLayout->addWidget(selectStartNodeWithMousePushButton, 0, 3); nodeNumbersLayout->addWidget(endNodeLabel, 1, 1); nodeNumbersLayout->addWidget(createLinearBorderFromROIEndNodeSpinBox, 1, 2); nodeNumbersLayout->addWidget(selectEndNodeWithMousePushButton, 1, 3); // // Node selection group box and layout // QGroupBox* nodeSelectionGroupBox = new QGroupBox("Starting and Ending Node Selection"); QVBoxLayout* nodeSelectionLayout = new QVBoxLayout(nodeSelectionGroupBox); nodeSelectionLayout->addWidget(createLinearBorderFromROIAutomaticRadioButton); nodeSelectionLayout->addWidget(createLinearBorderFromROIManualRadioButton); nodeSelectionLayout->addWidget(createBorderFromROINodeSelectionWidget); // // Connect signals to disable node selection if automatic // createBorderFromROINodeSelectionWidget->setEnabled(false); QObject::connect(createLinearBorderFromROIManualRadioButton, SIGNAL(toggled(bool)), createBorderFromROINodeSelectionWidget, SLOT(setEnabled(bool))); createLinearBorderFromROIAutomaticRadioButton->setChecked(true); // // Create border push button // QPushButton* createBorderPushButton = new QPushButton("Create Linear Border Using Geodesic"); createBorderPushButton->setAutoDefault(false); createBorderPushButton->setFixedSize(createBorderPushButton->sizeHint()); QObject::connect(createBorderPushButton, SIGNAL(clicked()), this, SLOT(slotCreateLinearBorderFromROIPushButton())); // // Widget and layout // QWidget* w = new QWidget; QVBoxLayout* layout = new QVBoxLayout(w); layout->addWidget(borderInfoGroupBox); layout->addWidget(nodeSelectionGroupBox, 0, Qt::AlignLeft); layout->addWidget(createBorderPushButton); return w; } /** * Called to set linear border name. */ void GuiSurfaceROIOperationPage::slotLinearCreateBorderFromROINamePushButton() { static GuiNameSelectionDialog::LIST_ITEMS_TYPE itemForDisplay = GuiNameSelectionDialog::LIST_BORDER_COLORS_ALPHA; GuiNameSelectionDialog nsd(this, GuiNameSelectionDialog::LIST_ALL, itemForDisplay); if (nsd.exec() == QDialog::Accepted) { createLinearBorderFromROINameLineEdit->setText(nsd.getNameSelected()); } } /** * called to set linear border start node. */ void GuiSurfaceROIOperationPage::slotCreateLinearBorderFromROIStartNodePushButton() { theMainWindow->getBrainModelOpenGL()->setMouseMode( GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_SULCAL_BORDER_NODE_START); } /** * called to set linear border end node. */ void GuiSurfaceROIOperationPage::slotCreateLinearBorderFromROIEndNodePushButton() { theMainWindow->getBrainModelOpenGL()->setMouseMode( GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_SULCAL_BORDER_NODE_END); } /** * set open border start node. */ void GuiSurfaceRegionOfInterestDialog::setCreateLinearBorderStartNode(const int nodeNumber) { BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); if (surfaceROI->getNodeSelected(nodeNumber)) { operationPage->createLinearBorderFromROIStartNodeSpinBox->setValue(nodeNumber); } else { QMessageBox::critical(this, "ERROR", "Node selected is not in the ROI."); } } /** * set open border end node. */ void GuiSurfaceRegionOfInterestDialog::setCreateLinearBorderEndNode(const int nodeNumber) { BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); if (surfaceROI->getNodeSelected(nodeNumber)) { operationPage->createLinearBorderFromROIEndNodeSpinBox->setValue(nodeNumber); } else { QMessageBox::critical(this, "ERROR", "Node selected is not in the ROI."); } } /** * called to create the linear border. */ void GuiSurfaceROIOperationPage::slotCreateLinearBorderFromROIPushButton() { // // Surface must be in the brain set // BrainModelSurface* bms = roiDialog->getCopyOfOperationSurface(); theMainWindow->getBrainSet()->addBrainModel(bms, false); // // Create the border from the ROI // const QString borderName(createLinearBorderFromROINameLineEdit->text()); int startNode = -1; int endNode = -1; if (createLinearBorderFromROIManualRadioButton->isChecked()) { startNode = createLinearBorderFromROIStartNodeSpinBox->value(); endNode = createLinearBorderFromROIEndNodeSpinBox->value(); } BrainModelSurfaceROICreateBorderUsingGeodesic roi(theMainWindow->getBrainSet(), bms, theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(), borderName, startNode, endNode, createLinearBorderFromROISamplingDensityDoubleSpinBox->value()); try { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); roi.execute(); QApplication::restoreOverrideCursor(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); theMainWindow->getBrainSet()->deleteBrainModel(bms); return; } // // Get border created and display it // Border border = roi.getBorder(); if (border.getNumberOfLinks() <= 0) { QMessageBox::critical(this, "ERROR", "Border created has no links."); theMainWindow->getBrainSet()->deleteBrainModel(bms); return; } // // Find the matching color // bool borderColorMatch = false; BorderColorFile* borderColorFile = theMainWindow->getBrainSet()->getBorderColorFile(); int borderColorIndex = borderColorFile->getColorIndexByName(borderName, borderColorMatch); // // Border color may need to be created // bool createBorderColor = false; if ((borderColorIndex >= 0) && (borderColorMatch == true)) { createBorderColor = false; } else if ((borderColorIndex >= 0) && (borderColorMatch == false)) { QString msg("Use border color \""); msg.append(borderColorFile->getColorNameByIndex(borderColorIndex)); msg.append("\" for border "); msg.append(borderName); msg.append(" ?"); QString noButton("No, define color "); noButton.append(borderName); QMessageBox msgBox(this); msgBox.setWindowTitle("Use Partially Matching Color"); msgBox.setText(msg); msgBox.addButton("Yes", QMessageBox::YesRole); QPushButton* defineColorPushButton = msgBox.addButton(noButton, QMessageBox::NoRole); msgBox.exec(); if (msgBox.clickedButton() == defineColorPushButton) { createBorderColor = true; } } else { createBorderColor = true; } if (createBorderColor) { QString title("Create Border Color: "); title.append(borderName); QApplication::beep(); GuiColorSelectionDialog* csd = new GuiColorSelectionDialog(this, title, false, false, false, false); csd->exec(); // // Add new border color // float pointSize = 2.0, lineSize = 1.0; unsigned char r, g, b, a; ColorFile::ColorStorage::SYMBOL symbol; csd->getColorInformation(r, g, b, a, pointSize, lineSize, symbol); borderColorFile->addColor(borderName, r, g, b, a, pointSize, lineSize, symbol); borderColorIndex = borderColorFile->getNumberOfColors() - 1; } // // Add border // BrainModelBorder* b = new BrainModelBorder(theMainWindow->getBrainSet(), &border, bms->getSurfaceType()); BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); bmbs->addBorder(b); // // Project the border // const int borderNumber = bmbs->getNumberOfBorders() - 1; if (borderNumber >= 0) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); bmbs->projectBorders(bms, true, borderNumber, borderNumber); QApplication::restoreOverrideCursor(); } // // Display borders // DisplaySettingsBorders* dsb = theMainWindow->getBrainSet()->getDisplaySettingsBorders(); dsb->setDisplayBorders(true); // // Delete copy of surface // theMainWindow->getBrainSet()->deleteBrainModel(bms); // // Files have changed // GuiFilesModified fm; fm.setBorderColorModified(); fm.setBorderModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } /** * create the create volume roi page. */ QWidget* GuiSurfaceROIOperationPage::createCreateVolumeROIPage() { QPushButton* createVolumeFromQueryNodesPushButton = new QPushButton( "Create Volume From Displayed Region of Interest Nodes..."); createVolumeFromQueryNodesPushButton->setAutoDefault(false); createVolumeFromQueryNodesPushButton->setFixedSize(createVolumeFromQueryNodesPushButton->sizeHint()); QObject::connect(createVolumeFromQueryNodesPushButton, SIGNAL(clicked()), this, SLOT(slotCreateVolumeFromQueryNodesButton())); QWidget* w = new QWidget; QVBoxLayout* layout = new QVBoxLayout(w); layout->addWidget(createVolumeFromQueryNodesPushButton); layout->addStretch(); return w; } /** * Called to create a volume from the display query nodes. */ void GuiSurfaceROIOperationPage::slotCreateVolumeFromQueryNodesButton() { BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); if (surfaceROI->anyNodesSelected() == false) { QMessageBox::critical(this, "Error: no nodes in ROI", "There are no nodes in the region of interest."); return; } GuiSurfaceToVolumeDialog svd(this, GuiSurfaceToVolumeDialog::DIALOG_MODE_NORMAL, "Create Region Of Interest Volume", false); if (svd.exec() == QDialog::Accepted) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainModelSurface* bms = roiDialog->getCopyOfOperationSurface(); float offset[3]; int dim[3]; float origin[3]; float voxelSize[3]; svd.getSurfaceOffset(offset); svd.getVolumeDimensions(dim); svd.getVolumeVoxelSizes(voxelSize); svd.getVolumeOrigin(origin); BrainModelSurfaceToVolumeConverter stv(theMainWindow->getBrainSet(), bms, svd.getStandardVolumeSpace(), offset, dim, voxelSize, origin, svd.getSurfaceInnerBoundary(), svd.getSurfaceOuterBoundary(), svd.getSurfaceThicknessStep(), BrainModelSurfaceToVolumeConverter::CONVERT_TO_ROI_VOLUME_USING_ROI_NODES); stv.setNodeToVoxelMappingEnabled(svd.getNodeToVoxelMappingEnabled(), svd.getNodeToVoxelMappingFileName()); try { stv.execute(); delete bms; } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "Error", e.whatQString()); delete bms; return; } theMainWindow->speakText("The region of interest volume has been created.", false); GuiFilesModified fm; fm.setVolumeModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); } } /** * create the disconnect nodes page. */ QWidget* GuiSurfaceROIOperationPage::createDisconnectNodesPage() { QPushButton* disconnectButton = new QPushButton("Disconnect Selected Nodes"); disconnectButton->setAutoDefault(false); disconnectButton->setFixedSize(disconnectButton->sizeHint()); QObject::connect(disconnectButton, SIGNAL(clicked()), this, SLOT(slotDisconnectNodes())); QWidget* w = new QWidget; QVBoxLayout* layout = new QVBoxLayout(w); layout->addWidget(disconnectButton); layout->addStretch(); return w; } /** * Called to disconnect the selected nodes. */ void GuiSurfaceROIOperationPage::slotDisconnectNodes() { BrainModelSurface* bms = roiDialog->getCopyOfOperationSurface(); if (bms != NULL) { TopologyFile* tf = bms->getTopologyFile(); if (tf != NULL) { BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); std::vector nodesAreInROI; surfaceROI->getNodesInROI(nodesAreInROI); theMainWindow->getBrainSet()->disconnectNodes(tf, nodesAreInROI); GuiBrainModelOpenGL::updateAllGL(NULL); theMainWindow->speakText("Nodes have been disconnected.", false); } } delete bms; } /** * create the geodesic page. */ QWidget* GuiSurfaceROIOperationPage::createGeodesicPage() { static const int maxComboBoxWidth = 400; QLabel* nodeLabel = new QLabel("Query Node"); geodesicNodeSpinBox = new QSpinBox; geodesicNodeSpinBox->setMinimum(0); geodesicNodeSpinBox->setMaximum(100000000); geodesicNodeSpinBox->setSingleStep(1); geodesicNodeSpinBox->setValue(0); QObject::connect(geodesicNodeSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotGeodesicUpdateColumnNames())); QPushButton* geodesicNodeButton = new QPushButton("Choose Node With Mouse"); geodesicNodeButton->setAutoDefault(false); geodesicNodeButton->setFixedSize(geodesicNodeButton->sizeHint()); QObject::connect(geodesicNodeButton, SIGNAL(clicked()), this, SLOT(slotGeodesicNodePushButton())); QHBoxLayout* nodeLayout = new QHBoxLayout; nodeLayout->addWidget(nodeLabel); nodeLayout->addWidget(geodesicNodeSpinBox); nodeLayout->addWidget(geodesicNodeButton); nodeLayout->addStretch(); QLabel* metricLabel = new QLabel("Metric "); geodesicMetricColumnComboBox = new GuiNodeAttributeColumnSelectionComboBox( GUI_NODE_FILE_TYPE_METRIC, true, true, false); geodesicMetricColumnComboBox->setMaximumWidth(maxComboBoxWidth); geodesicMetricColumnNameLineEdit = new QLineEdit; QObject::connect(geodesicMetricColumnComboBox, SIGNAL(itemNameSelected(const QString&)), geodesicMetricColumnNameLineEdit, SLOT(setText(const QString&))); geodesicMetricColumnNameLineEdit->setText(geodesicMetricColumnComboBox->getCurrentLabel()); QLabel* geoLabel = new QLabel("Geodesic "); geodesicDistanceColumnComboBox = new GuiNodeAttributeColumnSelectionComboBox( GUI_NODE_FILE_TYPE_GEODESIC_DISTANCE, true, true, false); geodesicDistanceColumnComboBox->setMaximumWidth(maxComboBoxWidth); geodesicDistanceColumnNameLineEdit = new QLineEdit; QObject::connect(geodesicDistanceColumnComboBox, SIGNAL(itemNameSelected(const QString&)), geodesicDistanceColumnNameLineEdit, SLOT(setText(const QString&))); geodesicDistanceColumnNameLineEdit->setText(geodesicDistanceColumnComboBox->getCurrentLabel()); QGridLayout* fileGridLayout = new QGridLayout; fileGridLayout->addWidget(metricLabel, 0, 0); fileGridLayout->addWidget(geodesicMetricColumnComboBox, 0, 1); fileGridLayout->addWidget(geodesicMetricColumnNameLineEdit, 0, 2); fileGridLayout->addWidget(geoLabel, 1, 0); fileGridLayout->addWidget(geodesicDistanceColumnComboBox, 1, 1); fileGridLayout->addWidget(geodesicDistanceColumnNameLineEdit, 1, 2); QHBoxLayout* fileLayout = new QHBoxLayout; fileLayout->addLayout(fileGridLayout); fileLayout->addStretch(); QPushButton* geodesicButton = new QPushButton("Determine Geodesic Distances"); geodesicButton->setAutoDefault(false); geodesicButton->setFixedSize(geodesicButton->sizeHint()); QObject::connect(geodesicButton, SIGNAL(clicked()), this, SLOT(slotGeodesicPushButton())); QWidget* w = new QWidget; QVBoxLayout* layout = new QVBoxLayout(w); layout->addLayout(nodeLayout); layout->addLayout(fileLayout); layout->addWidget(geodesicButton); layout->addStretch(); return w; } /** * called to update geodesic column names. */ void GuiSurfaceROIOperationPage::slotGeodesicUpdateColumnNames() { const int nodeNumber = geodesicNodeSpinBox->value(); QString newName("Node "); newName.append(QString::number(nodeNumber)); const QString geoName(geodesicDistanceColumnNameLineEdit->text()); if (geoName == geodesicDistanceColumnComboBox->getNewColumnLabel()) { geodesicDistanceColumnNameLineEdit->setText(newName); } const QString metricName(geodesicMetricColumnNameLineEdit->text()); if (metricName == geodesicMetricColumnComboBox->getNewColumnLabel()) { geodesicMetricColumnNameLineEdit->setText(newName); } } /** * called when geodesic choose node with mouse button pressed. */ void GuiSurfaceROIOperationPage::slotGeodesicNodePushButton() { theMainWindow->getBrainModelOpenGL()->setMouseMode( GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_GEODESIC_NODE_SELECT); } /** * called to create geodesic. */ void GuiSurfaceROIOperationPage::slotGeodesicPushButton() { BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); if (surfaceROI->anyNodesSelected() == false) { QMessageBox::critical(this, "Error: no nodes in ROI", "There are no nodes in the region of interest."); return; } const int nodeNumber = geodesicNodeSpinBox->value(); BrainModelSurface* bms = roiDialog->getCopyOfOperationSurface(); if (bms != NULL) { if ((nodeNumber < 0) || (nodeNumber >= bms->getNumberOfNodes())) { QMessageBox::critical(this, "Error", "No query node selected"); } else { //TopologyFile* tf = topologyComboBox->getSelectedTopologyFile(); //bms->getTopologyFile(); TopologyFile* tf = bms->getTopologyFile(); if (tf != NULL) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainModelSurfaceGeodesic bmsg(theMainWindow->getBrainSet(), bms, theMainWindow->getBrainSet()->getMetricFile(), geodesicMetricColumnComboBox->currentIndex(), geodesicMetricColumnNameLineEdit->text(), theMainWindow->getBrainSet()->getGeodesicDistanceFile(), geodesicDistanceColumnComboBox->currentIndex(), geodesicDistanceColumnNameLineEdit->text(), nodeNumber, surfaceROI); try { bmsg.execute(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "Error", e.whatQString()); } GuiFilesModified fm; fm.setMetricModified(); fm.setGeodesicModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); theMainWindow->speakText("Geodesic data has been created.", false); } } delete bms; } } /** * create the probabilistic atlas overlap page. */ QWidget* GuiSurfaceROIOperationPage::createProbAtlasOverlapPage() { QPushButton* createReportPushButton = new QPushButton("Create Probabilistic Atlas Overlap Report"); createReportPushButton->setAutoDefault(false); createReportPushButton->setFixedSize(createReportPushButton->sizeHint()); QObject::connect(createReportPushButton, SIGNAL(clicked()), this, SLOT(slotCreateProbAtlasOverlapReport())); probAtlasOverlapSemicolonSeparateCheckBox = new QCheckBox("Separate Report With Semicolons (for import to spreadsheet)"); QWidget* w = new QWidget; QVBoxLayout* layout = new QVBoxLayout(w); layout->addWidget(createReportPushButton); layout->addWidget(probAtlasOverlapSemicolonSeparateCheckBox); layout->addStretch(); return w; } /** * called to generate prob atlas overlap report. */ void GuiSurfaceROIOperationPage::slotCreateProbAtlasOverlapReport() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); QString errorMessage; BrainModelSurface* bms = roiDialog->getCopyOfOperationSurface(); ProbabilisticAtlasFile* probAtlasFile = theMainWindow->getBrainSet()->getProbabilisticAtlasSurfaceFile(); try { BrainModelSurfaceROINodeSelection* roi = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); QString headerText("Probabilistic Overlap Report"); BrainModelSurfaceROIProbAtlasOverlapReport overlap( theMainWindow->getBrainSet(), bms, roi, probAtlasFile, headerText, probAtlasOverlapSemicolonSeparateCheckBox->isChecked()); overlap.execute(); // // set report text // reportPage->setReportText(overlap.getReportText()); } catch (BrainModelAlgorithmException& e) { errorMessage = e.whatQString(); } delete bms; QApplication::restoreOverrideCursor(); if (errorMessage.isEmpty() == false) { QMessageBox::critical(this, "ERROR", errorMessage); } // // Move to next page // roiDialog->next(); } /** * create the smoothing page. */ QWidget* GuiSurfaceROIOperationPage::createSmoothingPage() { QPushButton* smoothButton = new QPushButton("Smooth Selected Nodes..."); smoothButton->setAutoDefault(false); smoothButton->setFixedSize(smoothButton->sizeHint()); QObject::connect(smoothButton, SIGNAL(clicked()), this, SLOT(slotSmoothNodesPushButtonPressed())); QWidget* w = new QWidget; QVBoxLayout* layout = new QVBoxLayout(w); layout->addWidget(smoothButton); layout->addStretch(); return w; } /** * called to smooth nodes. */ void GuiSurfaceROIOperationPage::slotSmoothNodesPushButtonPressed() { // // Copy surface // BrainModelSurface* bms = roiDialog->getCopyOfOperationSurface(); if (bms != NULL) { BrainModelSurfaceROINodeSelection* surfaceROI = theMainWindow->getBrainSet()->getBrainModelSurfaceRegionOfInterestNodeSelection(); std::vector nodesAreInROI; surfaceROI->getNodesInROI(nodesAreInROI); // // Smooth the surface copy. We cannot smooth the ROI surface because // the users is allowed to choose the coord and topo files which may // not be one of the loaded surfaces. // GuiSmoothingDialog sd(this, true, false, &nodesAreInROI); sd.setSmoothingSurface(bms); if (sd.exec()) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); } // // Copy coordinates to the ROI surfaces's coordinates // CoordinateFile* operationCoords = roiDialog->getOperationCoordinateFile(); const CoordinateFile* smoothedCoords = bms->getCoordinateFile(); const int numCoords = smoothedCoords->getNumberOfCoordinates(); for (int i = 0; i < numCoords; i++) { operationCoords->setCoordinate(i, smoothedCoords->getCoordinate(i)); } delete bms; } } /** * create the statistical paint report page. */ QWidget* GuiSurfaceROIOperationPage::createPaintReportPage() { QLabel* paintLabel = new QLabel("Paint Column "); paintRegionReportColumnComboBox = new GuiNodeAttributeColumnSelectionComboBox( GUI_NODE_FILE_TYPE_PAINT, false, false, false); QHBoxLayout* columnLayout = new QHBoxLayout; columnLayout->addWidget(paintLabel); columnLayout->addWidget(paintRegionReportColumnComboBox); columnLayout->addStretch(); // // Distortion correction // QLabel* distLabel = new QLabel("Distortion Correction"); paintRegionReportDistortionCorrectionMetricColumnComboBox = new GuiNodeAttributeColumnSelectionComboBox(GUI_NODE_FILE_TYPE_METRIC, false, true, false); paintRegionReportDistortionCorrectionMetricColumnComboBox->setCurrentIndex(GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NONE); paintRegionReportDistortionCorrectionMetricColumnComboBox->setToolTip( "Use this control to select a metric file column\n" "that contains a distortion correction ratio."); QHBoxLayout* distLayout = new QHBoxLayout; distLayout->addWidget(distLabel); distLayout->addWidget(paintRegionReportDistortionCorrectionMetricColumnComboBox); distLayout->addStretch(); paintReportSeparateWithSemicolonsCheckBox = new QCheckBox( "Separate Paint Subregion Report With Semicolons (for import to spreadsheet)"); QPushButton* createPaintReportButton = new QPushButton("Create Paint Subregion Report"); createPaintReportButton->setAutoDefault(false); createPaintReportButton->setFixedSize(createPaintReportButton->sizeHint()); QObject::connect(createPaintReportButton, SIGNAL(clicked()), this, SLOT(slotCreatePaintReportButton())); QWidget* w = new QWidget; QVBoxLayout* layout = new QVBoxLayout(w); layout->addLayout(columnLayout); layout->addLayout(distLayout); layout->addWidget(paintReportSeparateWithSemicolonsCheckBox); layout->addWidget(createPaintReportButton); layout->addStretch(); return w; } /** * called to create paint region report. */ void GuiSurfaceROIOperationPage::slotCreatePaintReportButton() { // // Copy surface // BrainModelSurface* bms = roiDialog->getCopyOfOperationSurface(); if (bms != NULL) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainSet* bs = theMainWindow->getBrainSet(); MetricFile* mf = bs->getMetricFile(); std::vector metricSelections(mf->getNumberOfColumns(), true); SurfaceShapeFile* ssf = bs->getSurfaceShapeFile(); std::vector shapeSelections(ssf->getNumberOfColumns(), true); PaintFile* pf = bs->getPaintFile(); std::vector paintSelections(pf->getNumberOfColumns(), true); BrainModelSurfaceROINodeSelection* roi = bs->getBrainModelSurfaceRegionOfInterestNodeSelection(); BrainModelSurfaceROIPaintReport roipr(bs, bms, roi, mf, metricSelections, ssf, shapeSelections, pf, paintSelections, paintRegionReportColumnComboBox->currentIndex(), bs->getLatLonFile(), 0, // lat/lon file column mf, paintRegionReportDistortionCorrectionMetricColumnComboBox->currentIndex(), paintReportSeparateWithSemicolonsCheckBox->isChecked()); try { roipr.execute(); QApplication::restoreOverrideCursor(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); } reportPage->setReportText(roipr.getReportText()); delete bms; // // Move to next page // roiDialog->next(); } } /** * create the statistical report page. */ QWidget* GuiSurfaceROIOperationPage::createStatisticalReportPage() { // // Distortion correction // QLabel* distLabel = new QLabel("Distortion Correction"); statisticalReportDistortionCorrectionMetricColumnComboBox = new GuiNodeAttributeColumnSelectionComboBox(GUI_NODE_FILE_TYPE_METRIC, false, true, false); statisticalReportDistortionCorrectionMetricColumnComboBox->setCurrentIndex(GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NONE); statisticalReportDistortionCorrectionMetricColumnComboBox->setToolTip( "Use this control to select a metric file column\n" "that contains a distortion correction ratio."); QHBoxLayout* distLayout = new QHBoxLayout; distLayout->addWidget(distLabel); distLayout->addWidget(statisticalReportDistortionCorrectionMetricColumnComboBox); distLayout->addStretch(); // // Separate report with semicolon's check box // statisticalReportSeparateWithSemicolonsCheckBox = new QCheckBox( "Separate Report With Semicolons"); QPushButton* createReportButton = new QPushButton("Create Report"); createReportButton->setAutoDefault(false); createReportButton->setFixedSize(createReportButton->sizeHint()); QObject::connect(createReportButton, SIGNAL(clicked()), this, SLOT(slotCreateStatisticalReportButton())); QWidget* w = new QWidget; QVBoxLayout* layout = new QVBoxLayout(w); layout->addLayout(distLayout); layout->addWidget(statisticalReportSeparateWithSemicolonsCheckBox); layout->addWidget(createReportButton); layout->addStretch(); return w; } /** * called to create statistical report. */ void GuiSurfaceROIOperationPage::slotCreateStatisticalReportButton() { // // Copy surface // BrainModelSurface* bms = roiDialog->getCopyOfOperationSurface(); if (bms != NULL) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainSet* bs = theMainWindow->getBrainSet(); MetricFile* mf = bs->getMetricFile(); std::vector metricSelections(mf->getNumberOfColumns(), true); SurfaceShapeFile* ssf = bs->getSurfaceShapeFile(); std::vector shapeSelections(ssf->getNumberOfColumns(), true); PaintFile* pf = bs->getPaintFile(); std::vector paintSelections(pf->getNumberOfColumns(), true); BrainModelSurfaceROINodeSelection* roi = bs->getBrainModelSurfaceRegionOfInterestNodeSelection(); BrainModelSurfaceROITextReport bmsri(bs, bms, roi, mf, metricSelections, ssf, shapeSelections, pf, paintSelections, bs->getLatLonFile(), 0, // lat/lon file column //reportHeader, "Statistical Report", mf, statisticalReportDistortionCorrectionMetricColumnComboBox->currentIndex(), statisticalReportSeparateWithSemicolonsCheckBox->isChecked()); try { bmsri.execute(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); } QApplication::restoreOverrideCursor(); reportPage->setReportText(bmsri.getReportText()); delete bms; // // Move to next page // roiDialog->next(); } } /** * create the shape correlation page. */ QWidget* GuiSurfaceROIOperationPage::createShapeCorrelationPage() { QLabel* shapeLabel = new QLabel("Reference Column "); shapeCorrelationColumnComboBox = new GuiNodeAttributeColumnSelectionComboBox( GUI_NODE_FILE_TYPE_SURFACE_SHAPE, false, false, true); shapeCorrelationColumnComboBox->setCurrentIndex( GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_ALL); QHBoxLayout* columnLayout = new QHBoxLayout; columnLayout->addWidget(shapeLabel); columnLayout->addWidget(shapeCorrelationColumnComboBox); columnLayout->addStretch(); shapeCorrelationSeparateWithSemicolonsCheckBox = new QCheckBox("Separate Report With Semicolons"); QPushButton* createReportPushButton = new QPushButton("Create Correlation Report"); createReportPushButton->setFixedSize(createReportPushButton->sizeHint()); createReportPushButton->setAutoDefault(false); QObject::connect(createReportPushButton, SIGNAL(clicked()), this, SLOT(slotCorrelationShapeReportPushButton())); QWidget* w = new QWidget; QVBoxLayout* layout = new QVBoxLayout(w); layout->addLayout(columnLayout); layout->addWidget(shapeCorrelationSeparateWithSemicolonsCheckBox); layout->addWidget(createReportPushButton); layout->addStretch(); return w; } /** * called to create shape correleation report. */ void GuiSurfaceROIOperationPage::slotCorrelationShapeReportPushButton() { // // Copy surface // BrainModelSurface* bms = roiDialog->getCopyOfOperationSurface(); if (bms != NULL) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainSet* bs = theMainWindow->getBrainSet(); SurfaceShapeFile* ssf = bs->getSurfaceShapeFile(); BrainModelSurfaceROINodeSelection* roi = bs->getBrainModelSurfaceRegionOfInterestNodeSelection(); const int column = shapeCorrelationColumnComboBox->currentIndex(); BrainModelSurfaceROIShapeCorrelationReport shapeCorr(bs, bms, roi, ssf, column, shapeCorrelationSeparateWithSemicolonsCheckBox->isChecked()); try { shapeCorr.execute(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); } QApplication::restoreOverrideCursor(); reportPage->setReportText(shapeCorr.getReportText()); delete bms; // // Move to next page // roiDialog->next(); } } /** * create the shape cluster analysis page. */ QWidget* GuiSurfaceROIOperationPage::createShapeClusterAnalysisPage() { QLabel* metricArealDistortionLabel = new QLabel("Metric Areal Distortion"); shapeClusterMetricArealDistortionComboBox = new GuiNodeAttributeColumnSelectionComboBox(GUI_NODE_FILE_TYPE_METRIC, false, true, false); shapeClusterMetricArealDistortionComboBox->setCurrentIndex( GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NONE); QHBoxLayout* arealDistLayout = new QHBoxLayout; arealDistLayout->addWidget(metricArealDistortionLabel); arealDistLayout->addWidget(shapeClusterMetricArealDistortionComboBox); arealDistLayout->addStretch(); QLabel* threshLabel = new QLabel("Threshold "); shapeClusterThresholdDoubleSpinBox = new QDoubleSpinBox; shapeClusterThresholdDoubleSpinBox->setMinimum(-10000000.0); shapeClusterThresholdDoubleSpinBox->setMaximum( 10000000.0); shapeClusterThresholdDoubleSpinBox->setSingleStep(1.0); shapeClusterThresholdDoubleSpinBox->setDecimals(3); QHBoxLayout* threshLayout = new QHBoxLayout; threshLayout->addWidget(threshLabel); threshLayout->addWidget(shapeClusterThresholdDoubleSpinBox); threshLayout->addStretch(); shapeClusterSeparateWithSemicolonsCheckBox = new QCheckBox("Separate Report With Semicolons"); QPushButton* createClusterReportPushButton = new QPushButton("Create Cluster Report"); createClusterReportPushButton->setFixedSize(createClusterReportPushButton->sizeHint()); createClusterReportPushButton->setAutoDefault(false); QObject::connect(createClusterReportPushButton, SIGNAL(clicked()), this, SLOT(slotShapeClusterReportPushButton())); QWidget* w = new QWidget; QVBoxLayout* layout = new QVBoxLayout(w); layout->addLayout(arealDistLayout); layout->addLayout(threshLayout); layout->addWidget(shapeClusterSeparateWithSemicolonsCheckBox); layout->addWidget(createClusterReportPushButton); layout->addStretch(); return w; } /** * called to creaet shape cluster report. */ void GuiSurfaceROIOperationPage::slotShapeClusterReportPushButton() { BrainSet* bs = theMainWindow->getBrainSet(); std::vector columnsSelected(bs->getSurfaceShapeFile()->getNumberOfColumns(), true); runMetricShapeClusterAnalysis(bs->getSurfaceShapeFile(), bs->getMetricFile(), shapeClusterMetricArealDistortionComboBox->currentIndex(), columnsSelected, shapeClusterThresholdDoubleSpinBox->value(), shapeClusterSeparateWithSemicolonsCheckBox->isChecked()); /* // // Copy surface // BrainModelSurface* bms = roiDialog->getCopyOfOperationSurface(); if (bms != NULL) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainSet* bs = theMainWindow->getBrainSet(); SurfaceShapeFile* ssf = bs->getSurfaceShapeFile(); std::vector columnSelectedFlags(ssf->getNumberOfColumns(), true); BrainModelSurfaceROINodeSelection* roi = bs->getBrainModelSurfaceRegionOfInterestNodeSelection(); BrainModelSurfaceROIMetricClusterReport cluster(bs, bms, roi, ssf, columnSelectedFlags, bs->getMetricFile(), shapeClusterMetricArealDistortionComboBox->currentIndex(), shapeClusterThresholdDoubleSpinBox->value(), shapeClusterSeparateWithSemicolonsCheckBox->isChecked()); try { cluster.execute(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); } QApplication::restoreOverrideCursor(); reportPage->setReportText(cluster.getReportText()); delete bms; // // Move to next page // roiDialog->next(); } */ } /** * create the metric cluster analysis page. */ QWidget* GuiSurfaceROIOperationPage::createMetricClusterAnalysisPage() { QLabel* metricArealDistortionLabel = new QLabel("Metric Areal Distortion"); metricClusterMetricArealDistortionComboBox = new GuiNodeAttributeColumnSelectionComboBox(GUI_NODE_FILE_TYPE_METRIC, false, true, false); metricClusterMetricArealDistortionComboBox->setCurrentIndex( GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NONE); QHBoxLayout* arealDistLayout = new QHBoxLayout; arealDistLayout->addWidget(metricArealDistortionLabel); arealDistLayout->addWidget(metricClusterMetricArealDistortionComboBox); arealDistLayout->addStretch(); QLabel* threshLabel = new QLabel("Threshold "); metricClusterThresholdDoubleSpinBox = new QDoubleSpinBox; metricClusterThresholdDoubleSpinBox->setMinimum(-10000000.0); metricClusterThresholdDoubleSpinBox->setMaximum( 10000000.0); metricClusterThresholdDoubleSpinBox->setSingleStep(1.0); metricClusterThresholdDoubleSpinBox->setDecimals(3); QHBoxLayout* threshLayout = new QHBoxLayout; threshLayout->addWidget(threshLabel); threshLayout->addWidget(metricClusterThresholdDoubleSpinBox); threshLayout->addStretch(); metricClusterSeparateWithSemicolonsCheckBox = new QCheckBox("Separate Report With Semicolons"); QPushButton* createClusterReportPushButton = new QPushButton("Create Cluster Report"); createClusterReportPushButton->setFixedSize(createClusterReportPushButton->sizeHint()); createClusterReportPushButton->setAutoDefault(false); QObject::connect(createClusterReportPushButton, SIGNAL(clicked()), this, SLOT(slotMetricClusterReportPushButton())); QWidget* w = new QWidget; QVBoxLayout* layout = new QVBoxLayout(w); layout->addLayout(arealDistLayout); layout->addLayout(threshLayout); layout->addWidget(metricClusterSeparateWithSemicolonsCheckBox); layout->addWidget(createClusterReportPushButton); layout->addStretch(); return w; } /** * called to create metric cluster report. */ void GuiSurfaceROIOperationPage::slotMetricClusterReportPushButton() { BrainSet* bs = theMainWindow->getBrainSet(); std::vector columnsSelected(bs->getMetricFile()->getNumberOfColumns(), true); runMetricShapeClusterAnalysis(bs->getMetricFile(), bs->getMetricFile(), metricClusterMetricArealDistortionComboBox->currentIndex(), columnsSelected, metricClusterThresholdDoubleSpinBox->value(), metricClusterSeparateWithSemicolonsCheckBox->isChecked()); } /** * run a metric or shape cluster report. */ void GuiSurfaceROIOperationPage::runMetricShapeClusterAnalysis(MetricFile* metricShapeFile, MetricFile* distortionMetricFile, const int distortionMetricColumn, const std::vector& metricShapeColumnsSelected, const float thresholdValue, const bool separateReportWithSemicolonsFlag) { // // Copy surface // BrainModelSurface* bms = roiDialog->getCopyOfOperationSurface(); if (bms != NULL) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainSet* bs = theMainWindow->getBrainSet(); std::vector columnSelectedFlags(metricShapeFile->getNumberOfColumns(), true); BrainModelSurfaceROINodeSelection* roi = bs->getBrainModelSurfaceRegionOfInterestNodeSelection(); BrainModelSurfaceROIMetricClusterReport cluster(bs, bms, roi, metricShapeFile, metricShapeColumnsSelected, distortionMetricFile, distortionMetricColumn, thresholdValue, separateReportWithSemicolonsFlag); try { cluster.execute(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); } QApplication::restoreOverrideCursor(); reportPage->setReportText(cluster.getReportText()); delete bms; // // Move to next page // roiDialog->next(); } } caret-5.6.4~dfsg.1.orig/caret/GuiSurfaceInformationDialog.h0000664000175000017500000000406211572067322023415 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_SURFACE_INFORMATION_DIALOG_H__ #define __GUI_SURFACE_INFORMATION_DIALOG_H__ #include #include "WuQDialog.h" class GuiBrainModelSelectionComboBox; class GuiStructureComboBox; class QGridLayout; class QLabel; class QPushButton; /// dialog for setting and viewing surface information class GuiSurfaceInformationDialog : public WuQDialog { Q_OBJECT public: /// constructor GuiSurfaceInformationDialog(QWidget* parent); /// destructor ~GuiSurfaceInformationDialog(); private slots: /// called when a surface is selected void slotSurfaceSelection(); /// called when a hemisphere is selected void slotHemisphereComboBox(); private: /// surface selection combo box GuiBrainModelSelectionComboBox* surfaceComboBox; /// label for names std::vector namesLabels; /// label for values std::vector valuesLabels; /// hemisphere combo box GuiStructureComboBox* hemisphereComboBox; /// layout for names and values QGridLayout* namesAndValuesGridLayout; }; #endif // __GUI_SURFACE_INFORMATION_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiSurfaceInformationDialog.cxx0000664000175000017500000001126611572067322023774 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "BrainModelSurface.h" #include "BrainSet.h" #include "FileUtilities.h" #include "GuiBrainModelOpenGL.h" #include "GuiBrainModelSelectionComboBox.h" #include "GuiStructureComboBox.h" #include "GuiMainWindow.h" #include "GuiSurfaceInformationDialog.h" #include "global_variables.h" /** * Constructor. */ GuiSurfaceInformationDialog::GuiSurfaceInformationDialog(QWidget* parent) : WuQDialog(parent) { setModal(true); setWindowTitle("Surface Information"); // // layout for entire dialog // QVBoxLayout* rows = new QVBoxLayout(this); rows->setMargin(3); rows->setSpacing(5); // // Surface selection // QLabel* surfaceLabel = new QLabel("Surface"); surfaceComboBox = new GuiBrainModelSelectionComboBox(false, true, false, "", 0); surfaceComboBox->setMaximumWidth(400); QObject::connect(surfaceComboBox, SIGNAL(activated(int)), this, SLOT(slotSurfaceSelection())); QHBoxLayout* surfaceLayout = new QHBoxLayout; surfaceLayout->addWidget(surfaceLabel); surfaceLayout->addWidget(surfaceComboBox); surfaceLayout->addStretch(); rows->addLayout(surfaceLayout); // // Grid layout for coord and topology // namesAndValuesGridLayout = new QGridLayout; namesAndValuesGridLayout->setMargin(2); namesAndValuesGridLayout->setSpacing(5); rows->addLayout(namesAndValuesGridLayout); // // Layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(5); rows->addLayout(buttonsLayout); // // OK pushbutton // QPushButton* okButton = new QPushButton("OK"); okButton->setAutoDefault(false); okButton->setFixedSize(okButton->sizeHint()); QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); buttonsLayout->addWidget(okButton); surfaceComboBox->setSelectedBrainModel(theMainWindow->getBrainModelSurface()); slotSurfaceSelection(); } /** * called when a hemisphere is selected. */ void GuiSurfaceInformationDialog::slotHemisphereComboBox() { // // Set topology file to one used by this surface. // BrainModelSurface* bms = surfaceComboBox->getSelectedBrainModelSurface(); if (bms != NULL) { bms->setStructure(hemisphereComboBox->getSelectedStructure()); } } /** * Called when a surface is selected. */ void GuiSurfaceInformationDialog::slotSurfaceSelection() { // // Set topology file to one used by this surface. // BrainModelSurface* bms = surfaceComboBox->getSelectedBrainModelSurface(); if (bms != NULL) { std::vector labels, values; bms->getSurfaceInformation(labels, values); for (unsigned int i = namesLabels.size(); i < labels.size(); i++) { QLabel* nl = new QLabel; QLabel* vl = new QLabel; namesLabels.push_back(nl); valuesLabels.push_back(vl); namesAndValuesGridLayout->addWidget(nl, i, 0, 1, 1); namesAndValuesGridLayout->addWidget(vl, i, 1, 1, 1); } for (unsigned int i = labels.size(); i < namesLabels.size(); i++) { namesLabels[i]->hide(); valuesLabels[i]->hide(); } for (unsigned int i = 0; i < labels.size(); i++) { namesLabels[i]->setText(labels[i]); namesLabels[i]->show(); valuesLabels[i]->setText(values[i]); valuesLabels[i]->show(); } } } /** * Destructor. */ GuiSurfaceInformationDialog::~GuiSurfaceInformationDialog() { } caret-5.6.4~dfsg.1.orig/caret/GuiSurfaceDeformationDialog.h0000664000175000017500000004700311572067322023401 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_SURFACE_DEFORMATION_DIALOG_H__ #define __GUI_SURFACE_DEFORMATION_DIALOG_H__ #include #include #include #include "WuQDialog.h" #include "DeformationMapFile.h" class QButtonGroup; class QCheckBox; class QComboBox; class QGridLayout; class QRadioButton; class QSpinBox; class QTabWidget; class QDoubleSpinBox; class SpecFile; class WuQWidgetGroup; /// class for keeping track of deformation data files class DeformationDataFiles { public: /// data file types enum DATA_FILE_TYPES { DATA_FILE_BORDER_FLAT, DATA_FILE_BORDER_FLAT_LOBAR, DATA_FILE_BORDER_SPHERICAL, DATA_FILE_BORDER_PROJECTION, DATA_FILE_TOPO_CLOSED, DATA_FILE_TOPO_CUT, DATA_FILE_TOPO_CUT_LOBAR, DATA_FILE_COORD_FIDUCIAL, DATA_FILE_COORD_FLAT, DATA_FILE_COORD_FLAT_LOBAR, DATA_FILE_COORD_SPHERICAL }; /// constructor DeformationDataFiles(); /// destructor ~DeformationDataFiles(); /// load data files from a spec file void loadSpecFile(const SpecFile& sf, const bool flatDeformFlag); /// border file names std::vector borderFileNames; /// border file types std::vector borderFileTypes; /// selected border file int borderFileSelected[DeformationMapFile::MAX_SPHERICAL_STAGES]; /// file names std::vector closedTopoFileNames; /// file types std::vector closedTopoFileTypes; /// selected file int closedTopoFileSelected; /// file names std::vector cutTopoFileNames; /// file types std::vector cutTopoFileTypes; /// selected file int cutTopoFileSelected; /// file names std::vector fiducialCoordFileNames; /// file types std::vector fiducialCoordFileTypes; /// selected file int fiducialCoordFileSelected; /// file names std::vector sphericalCoordFileNames; /// file types std::vector sphericalCoordFileTypes; /// selected file int sphericalCoordFileSelected; /// file names std::vector flatCoordFileNames; /// file types std::vector flatCoordFileTypes; /// selected file int flatCoordFileSelected; }; /// class for an entry line class FileEntryLine { public: /// constructor FileEntryLine(QPushButton* pushButtonIn, QLineEdit* lineEditIn, QPushButton* extraPushButtonIn = NULL) { this->pushButton = pushButtonIn; this->lineEdit = lineEditIn; this->extraButton = extraPushButtonIn; } /// destructor ~FileEntryLine() { } /// set the widgets visible void setVisible(bool visible) { this->pushButton->setVisible(visible); this->lineEdit->setVisible(visible); if (this->extraButton != NULL) { this->extraButton->setVisible(visible); } } /// set the widgets enabled void setEnabled(bool enable) { this->pushButton->setEnabled(enable); this->lineEdit->setEnabled(enable); if (this->extraButton != NULL) { this->extraButton->setEnabled(enable); } } /// the push button QPushButton* pushButton; /// the line edit QLineEdit* lineEdit; /// the extra button QPushButton* extraButton; }; /// Dialog for deforming one surface to another class GuiSurfaceDeformationDialog : public WuQDialog { Q_OBJECT public: /// constructor GuiSurfaceDeformationDialog(QWidget* parent, const DeformationMapFile::DEFORMATION_TYPE deformationTypeIn); /// destructor ~GuiSurfaceDeformationDialog(); private slots: /// Called when an atlas file selection is made void atlasFileSelection(int itemNum); /// Called when an indiv file selection is made void indivFileSelection(int itemNum); /// called when load deformation map file push button is pressed void loadDeformationMapFilePushButton(); /// called when save deformation map file push button is pressed void saveDeformationMapFilePushButton(); /// called when number of spherical cycles is changed void slotSphereNumberOfCyclesSpinBox(int item); /// called when sphere edit cycle is changed void slotSphereEditCycleSpinBox(int value); /// called when number of spherical stages is changed void slotSphereNumberOfStagesSpinBox(int item); /// called when sphere edit stage is changed void slotSphereEditStageSpinBox(int value); /// called when Use Standard Parameters button pressed void slotStandardParametersPushButton(); /// called to edit individual borders void slotBordersEditIndividual(); /// called to edit atlas borders void slotBordersEditAtlas(int index); /// called to update deformation map file names void slotUpdateDeformationMapFileNames(); /// called when a spherical algorithm is selected void slotSphericalAlgorithmSelection(); /// called when apply button pressed void slotApplyButton(); /// called to read the deformation parameters from the dialog void slotDeformationParameterChanged(); /// called to read the flat parameters from the dialog void slotFlatParameterChanged(); /// called when a smoothing parameter is altered void slotSmoothingParameterChanged(); /// called when a morphing parameter is changed void slotMorphingParameterChanged(); /// called when a landmark vector parameter is changed void slotLandmarkVectorParameterChanged(); /// called if sphere resolution is changed void slotSphereResolutionChanged(); /// called when a correct for spherical distortion changed void slotCorrectSphericalDistortionChanged(); private: /// file selection types enum SELECTION_TYPE { SELECTION_TYPE_ATLAS, SELECTION_TYPE_INDIV }; /// Unique ID's for file types enum FILE_TYPES { FILE_TYPE_SPEC, FILE_TYPE_TOPO_CLOSED, FILE_TYPE_TOPO_CUT, FILE_TYPE_COORD_FIDUCIAL, FILE_TYPE_COORD_FLAT, FILE_TYPE_COORD_SPHERICAL, FILE_TYPE_BORDER_1, FILE_TYPE_BORDER_2, FILE_TYPE_BORDER_3, FILE_TYPE_BORDER_4, FILE_TYPE_BORDER_5, FILE_TYPE_BORDER_6, FILE_TYPE_BORDER_7, FILE_TYPE_BORDER_8, FILE_TYPE_BORDER_9, FILE_TYPE_BORDER_10, FILE_TYPE_BORDER_11, FILE_TYPE_BORDER_12, FILE_TYPE_BORDER_13, FILE_TYPE_BORDER_14, FILE_TYPE_BORDER_15, FILE_TYPE_BORDER_16, FILE_TYPE_BORDER_17, FILE_TYPE_BORDER_18, FILE_TYPE_BORDER_19, FILE_TYPE_BORDER_20 }; /// Add to the command. void addToCommand(std::ostringstream& commandStr, const QString& cmd, const QString& value, const QString& value2 = ""); /// load the deformation map file void loadDeformationMapFile(std::vector& errorMessages); /// create the atlas widget void createAtlasWidget(); /// create the individual widget void createIndividualWidget(); /// create the parameters widget void createParametersWidget(); /// create the deformation widget void createDeformationWidget(); /// create the border resampling section QWidget* createBorderResampling(); /// create the metric deformation section QWidget* createMetricDeformation(); /// create the spherical parameters section QWidget* createSphericalParameters(); /// create the spherical algorithm section QWidget* createSphericalAlgorithmSection(); /// create the landmark vector options QWidget* createLandmarkVectorOptionsSection(); /// create the flat parameters section QWidget* createFlatParameters(); /// create the morphing parameters section QWidget* createMorphingParametersSection(); /// create the smoothing parameters section QWidget* createSmoothingParametersSection(); /// create the Spherical parameters section QWidget* createSphericalParametersSection(); /// display the atlas data files void displayAtlasFiles(); /// display the indiv data files void displayIndivFiles(); /// display dialog for deformation data file selection void displayFileSelection(const QString& title, const std::vector& labelsIn, const std::vector fileTypes, int& selectedItem); /// read an atlas or indiv spec file void readSpecFile(const SELECTION_TYPE st); /// create the pushbutton and the line edit FileEntryLine* createFileEntryLine(const QString& buttonLabel, const FILE_TYPES fileType, QGridLayout* parentGridLayout, QButtonGroup* buttonGroup, QPushButton* extraButton = NULL); /// load the flat/spherical parameters from a deformation map file void loadParametersIntoDialog(); /// edit a border file void editBorderFile(const QString& specFileName, const QString& borderFileName, const DeformationDataFiles::DATA_FILE_TYPES fileType); /// setup connections for automatic update of deformation map file names void setConnectionsForAutoDefMapFileNameUpdates(); /// update atlas border selections void updateAtlasBorderSelections(); /// update the smoothing parameters void updateSmoothingParameters(); /// update the landmark vector parameters void updateLandmarkVectorParameters(); /// update the morphing parameters void updateMorphingParameters(); /// update the sphere edit cycle spin box void updateSphereEditCycleSpinBox(); /// update the sphere number of cycles spin box void updateSphereNumberOfCyclesSpinBox(); /// update the sphere edit stage spin box void updateSphereEditStageSpinBox(); /// update the spherical number of stages spin box void updateSphereNumberOfStagesSpinBox(); /// update the spherical resolution combo box void updateSphericalResolutionComboBox(); /// update correct spherical distortion correction void updateCorrectSphericalDistortion(); /// update the flat parameters */ void updateFlatParameters(); /// update the deformation parameters void updateDeformationParametersPage(); /// update algorithm selection void updateAlgorithmSelection(); /// atlas data files for deformation DeformationDataFiles atlasDeformationFiles; /// indiv data files for deformation DeformationDataFiles indivDeformationFiles; /// atlas spec file name QString atlasSpecFileName; /// indiv spec file name QString indivSpecFileName; /// the deformation map file DeformationMapFile dmf; /// the dialogs tab widget QTabWidget* dialogTabWidget; /// individual's files widget QWidget* individualWidgetTop; /// atlas' files widget QWidget* atlasWidgetTop; /// parameters widget QWidget* parametersWidget; /// deformation widget QWidget* deformationWidgetTop; /// atlas file line edit QLineEdit* atlasSpecLineEdit; /// atlas file line edit QLineEdit* atlasBorderLineEdit[DeformationMapFile::MAX_SPHERICAL_STAGES]; FileEntryLine* atlasBorderFileEntryLine[DeformationMapFile::MAX_SPHERICAL_STAGES] ; /// atlas file line edit QLineEdit* atlasClosedTopoLineEdit; /// atlas file line edit QLineEdit* atlasCutTopoLineEdit; /// atlas file line edit QLineEdit* atlasFiducialCoordLineEdit; /// atlas file line edit QLineEdit* atlasSphericalCoordLineEdit; /// atlas file line edit QLineEdit* atlasFlatCoordLineEdit; /// atlas file line edit QLineEdit* indivSpecLineEdit; /// atlas file line edit QLineEdit* indivBorderLineEdit; /// atlas file line edit QLineEdit* indivClosedTopoLineEdit; /// atlas file line edit QLineEdit* indivCutTopoLineEdit; /// atlas file line edit QLineEdit* indivFiducialCoordLineEdit; /// atlas file line edit QLineEdit* indivSphericalCoordLineEdit; /// atlas file line edit QLineEdit* indivFlatCoordLineEdit; /// border resampling none radio button QRadioButton* borderResamplingNoneRadioButton; /// border resampling from file radio button QRadioButton* borderResamplingFromFileRadioButton; /// border resampling to value radio button QRadioButton* borderResamplingToValueRadioButton; /// border resampling value Spin Box QDoubleSpinBox* borderResamplingDoubleSpinBox; /// metric nearest node radio button QRadioButton* metricNearestNodeRadioButton; /// metric average tile nodes radio button QRadioButton* metricAverageTileNodesRadioButton; /// flat sub sampling tiles spin box QSpinBox* flatSubSamplingTilesSpinBox; /// flat beta double spin box QDoubleSpinBox* flatBetaDoubleSpinBox; /// flat variance multiplier double spin box QDoubleSpinBox* flatVarMultDoubleSpinBox; /// flat iterations spin box QSpinBox* flatIterationsSpinBox; /// smoothing strength float spin box QDoubleSpinBox* smoothingStrengthDoubleSpinBox; /// smoothing cycles spin box QSpinBox* smoothingCyclesSpinBox; /// smoothing iterations spin box QSpinBox* smoothingIterationsSpinBox; /// smoothing neighbors spin box QSpinBox* smoothingNeighborsSpinBox; /// smoothing final iterations spin box QSpinBox* smoothingFinalSpinBox; /// morphing cycles spin box QSpinBox* morphingCyclesSpinBox; /// morphing linear force spin box QDoubleSpinBox* morphingLinearForceDoubleSpinBox; /// morphing angular force spin box QDoubleSpinBox* morphingAngularForceDoubleSpinBox; /// morphing step size spin box QDoubleSpinBox* morphingStepSizeDoubleSpinBox; /// morphing landmark step size spin box QDoubleSpinBox* morphingLandmarkStepSizeDoubleSpinBox; /// morphing iterations spin box QSpinBox* morphingIterationsSpinBox; /// morphing smooth iterations spin box QSpinBox* morphingSmoothIterationsSpinBox; /// widget group for sphere stages WuQWidgetGroup* sphereStagesWidgetGroup; /// sphere number of stages spin box QSpinBox* sphereNumberOfStagesSpinBox; /// sphere edige stages spin box QSpinBox* sphereEditStageSpinBox; /// sphere number of cycles spin box QSpinBox* sphereNumberOfCyclesSpinBox; /// sphere edit cycles spin box QSpinBox* sphereEditCycleSpinBox; /// sphere resolution combo box QComboBox* sphereResolutionComboBox; /// deform both ways check box QCheckBox* deformBothWaysCheckBox; /// deformed file prefix line edit QLineEdit* deformedFilePrefixLineEdit; /// deformed column prefix line edit QLineEdit* deformedColumnPrefixLineEdit; /// delete intermediate files check box QCheckBox* deleteIntermediateFilesCheckBox; /// fiducial sphere distortion correction check box QCheckBox* sphereDistortionCorrectionCheckBox; /// fiducial sphere distortion correction value float spin box QDoubleSpinBox* sphereDistortionDoubleSpinBox; /// deform indiv coord files to atlas check box QCheckBox* deformIndivFiducialCoordCheckBox; /// deform indiv coord files to atlas check box QCheckBox* deformIndivInflatedCoordCheckBox; /// deform indiv coord files to atlas check box QCheckBox* deformIndivVeryInflatedCoordCheckBox; /// deform indiv coord files to atlas check box QCheckBox* deformIndivSphericalCoordCheckBox; /// deform indiv coord files to atlas check box QCheckBox* deformIndivFlatCoordCheckBox; /// deform indiv coord files to atlas check box QCheckBox* deformIndivFlatLobarCoordCheckBox; /// smooth deformed coord files QCheckBox* smoothCoordsOneIterationCheckBox; /// indiv-to-atlas deformation map file name line edit QLineEdit* indivToAtlasDeformMapFileNameLineEdit; /// atlas-to-indiv deformation map file name line edit QLineEdit* atlasToIndivDeformMapFileNameLineEdit; /// landmark-constrained spherical algorithm radio button QRadioButton* sphericalLandmarkConstrainedRadioButton; /// landmark-vector spherical algorithm radio button QRadioButton* sphericalLandmarkVectorRadioButton; /// landmark-vector single stage algorithm radio button QRadioButton* sphericalLandmarkVectorSingleStageRadioButton; /// landmark-vector smoothing iterations QSpinBox* vectorSmoothingIterationsSpinBox; /// landmark-vector displacement factor double spin box QDoubleSpinBox* vectorDisplacementFactorDoubleSpinBox; /// landmark-vector endpoint factor double spin box QDoubleSpinBox* vectorEndpointFactorDoubleSpinBox; /// pause for crossover confirmation check box QCheckBox* pauseForCrossoversConfirmationCheckBox; /// landmark vector options widget QWidget* landmarkVectorOptionsWidget; /// widget group for smoothing parameters WuQWidgetGroup* smoothingParametersWidgetGroup; /// widget group for landmark vector parameters WuQWidgetGroup* landmarkVectorParametersWidgetGroup; /// widget group for morphing parameters WuQWidgetGroup* morphingParametersWidgetGroup; }; #endif // __GUI_SURFACE_DEFORMATION_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiSurfaceDeformationDialog.cxx0000664000175000017500000040037511572067322023761 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include "WuQFileDialog.h" #include #include #include #include #include #include #include #include #include #include #include #include "GuiBrainModelOpenGL.h" #include "BrainModelSurfaceDeformDataFile.h" #include "BrainModelSurfaceDeformationFlat.h" #include "BrainModelSurfaceDeformationMultiStageSphericalVector.h" #include "BrainModelSurfaceDeformationSpherical.h" #include "BrainModelSurfaceDeformationSphericalVector.h" #include "BrainSet.h" #include "DebugControl.h" #include "DisplaySettingsSurface.h" #include "FileUtilities.h" #include "GuiBatchCommandDialog.h" #include "GuiBorderAttributesDialog.h" #include "GuiChooseSpecFileDialog.h" #include "GuiMainWindow.h" #include "GuiSurfaceDeformationDialog.h" #include "DeformationMapFile.h" #include "QtRadioButtonSelectionDialog.h" #include #include "QtUtilities.h" #include "SpecFile.h" #include "StringUtilities.h" #include "WuQWidgetGroup.h" #include "global_variables.h" #include "GuiStudyMetaDataFileEditorDialog.h" static const QString continuationAndNewLine = " \\\n"; /** * constructor */ GuiSurfaceDeformationDialog::GuiSurfaceDeformationDialog( QWidget* parent, const DeformationMapFile::DEFORMATION_TYPE deformationTypeIn) : WuQDialog(parent) { dmf.setFlatOrSphereSelection(deformationTypeIn); switch (dmf.getFlatOrSphereSelection()) { case DeformationMapFile::DEFORMATION_TYPE_FLAT: setWindowTitle("Flat Surface Deformation"); break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE: setWindowTitle("Spherical Surface Deformation"); break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: setWindowTitle("Spherical Surface Deformation"); break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: setWindowTitle("Spherical Surface Deformation"); break; } deformBothWaysCheckBox = NULL; for (int i = 0; i < DeformationMapFile::MAX_SPHERICAL_STAGES; i++) { atlasBorderFileEntryLine[i] = NULL; } // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // create the tabbed widgets // dialogTabWidget = new QTabWidget(this); dialogLayout->addWidget(dialogTabWidget); createIndividualWidget(); createAtlasWidget(); createParametersWidget(); createDeformationWidget(); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); dialogLayout->addLayout(buttonsLayout); // // Apply button // QPushButton* applyButton = new QPushButton("Apply"); buttonsLayout->addWidget(applyButton); QObject::connect(applyButton, SIGNAL(clicked()), this, SLOT(slotApplyButton())); // // Cancel button // QPushButton* closeButton = new QPushButton("Close"); buttonsLayout->addWidget(closeButton); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); QtUtilities::makeButtonsSameSize(applyButton, closeButton); // // Load the parameters into the dialog // loadParametersIntoDialog(); setConnectionsForAutoDefMapFileNameUpdates(); updateAtlasBorderSelections(); } /** * Add to the command. */ void GuiSurfaceDeformationDialog::addToCommand(std::ostringstream& commandStr, const QString& cmd, const QString& value, const QString& value2) { if (value.isEmpty() == false) { commandStr << continuationAndNewLine.toAscii().constData(); commandStr << " " << cmd.toAscii().constData() << " " << value.toAscii().constData(); if (value2.isEmpty() == false) { commandStr << " " << value2.toAscii().constData(); } } } /** * destructor */ GuiSurfaceDeformationDialog::~GuiSurfaceDeformationDialog() { } /** * Create the atlas tab. */ void GuiSurfaceDeformationDialog::createAtlasWidget() { // // Grid to hold pushbuttons and line edits // atlasWidgetTop = new QWidget; QScrollArea* scrollArea = new QScrollArea(); scrollArea->setWidget(atlasWidgetTop); scrollArea->setWidgetResizable(true); dialogTabWidget->addTab(scrollArea, "Atlas"); // // Put everything in a QGrid // QGridLayout* atlasWidgetLayout = new QGridLayout(atlasWidgetTop); // // Button group for file selections // QButtonGroup* atlasButtonGroup = new QButtonGroup(this); QObject::connect(atlasButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(atlasFileSelection(int))); // // Edit borders button // QButtonGroup* editButtonGroup = new QButtonGroup(this); QObject::connect(editButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotBordersEditAtlas(int))); QPushButton* editBordersPushButton[DeformationMapFile::MAX_SPHERICAL_STAGES]; for (int i = 0; i < DeformationMapFile::MAX_SPHERICAL_STAGES; i++) { editBordersPushButton[i] = new QPushButton("Edit..."); editBordersPushButton[i]->setAutoDefault(false); editButtonGroup->addButton(editBordersPushButton[i], i); } // // Create the pushbuttons and line edits // atlasSpecLineEdit = createFileEntryLine("Spec File...", FILE_TYPE_SPEC, atlasWidgetLayout, atlasButtonGroup)->lineEdit;; atlasClosedTopoLineEdit = createFileEntryLine("Closed Topo File...", FILE_TYPE_TOPO_CLOSED, atlasWidgetLayout, atlasButtonGroup)->lineEdit;; atlasCutTopoLineEdit = createFileEntryLine("Cut Topo File...", FILE_TYPE_TOPO_CUT, atlasWidgetLayout, atlasButtonGroup)->lineEdit;; atlasFiducialCoordLineEdit = createFileEntryLine("Fiducial Coord File...", FILE_TYPE_COORD_FIDUCIAL, atlasWidgetLayout, atlasButtonGroup)->lineEdit;; atlasSphericalCoordLineEdit = createFileEntryLine("Spherical Coord File...", FILE_TYPE_COORD_SPHERICAL, atlasWidgetLayout, atlasButtonGroup)->lineEdit;; atlasFlatCoordLineEdit = createFileEntryLine("Flat Coord...", FILE_TYPE_COORD_FLAT, atlasWidgetLayout, atlasButtonGroup)->lineEdit;; atlasBorderFileEntryLine[0] = createFileEntryLine("Border File Stage 1...", FILE_TYPE_BORDER_1, atlasWidgetLayout, atlasButtonGroup, editBordersPushButton[0]); atlasBorderFileEntryLine[1] = createFileEntryLine("Border File Stage 2...", FILE_TYPE_BORDER_2, atlasWidgetLayout, atlasButtonGroup, editBordersPushButton[1]); atlasBorderFileEntryLine[2] = createFileEntryLine("Border File Stage 3...", FILE_TYPE_BORDER_3, atlasWidgetLayout, atlasButtonGroup, editBordersPushButton[2]); atlasBorderFileEntryLine[3] = createFileEntryLine("Border File Stage 4...", FILE_TYPE_BORDER_4, atlasWidgetLayout, atlasButtonGroup, editBordersPushButton[3]); atlasBorderFileEntryLine[4] = createFileEntryLine("Border File Stage 5...", FILE_TYPE_BORDER_5, atlasWidgetLayout, atlasButtonGroup, editBordersPushButton[4]); atlasBorderFileEntryLine[5] = createFileEntryLine("Border File Stage 6...", FILE_TYPE_BORDER_6, atlasWidgetLayout, atlasButtonGroup, editBordersPushButton[5]); atlasBorderFileEntryLine[6] = createFileEntryLine("Border File Stage 7...", FILE_TYPE_BORDER_7, atlasWidgetLayout, atlasButtonGroup, editBordersPushButton[6]); atlasBorderFileEntryLine[7] = createFileEntryLine("Border File Stage 8...", FILE_TYPE_BORDER_8, atlasWidgetLayout, atlasButtonGroup, editBordersPushButton[7]); atlasBorderFileEntryLine[8] = createFileEntryLine("Border File Stage 9...", FILE_TYPE_BORDER_9, atlasWidgetLayout, atlasButtonGroup, editBordersPushButton[8]); atlasBorderFileEntryLine[9] = createFileEntryLine("Border File Stage 10...", FILE_TYPE_BORDER_10, atlasWidgetLayout, atlasButtonGroup, editBordersPushButton[9]); atlasBorderFileEntryLine[10] = createFileEntryLine("Border File Stage 11...", FILE_TYPE_BORDER_11, atlasWidgetLayout, atlasButtonGroup, editBordersPushButton[10]); atlasBorderFileEntryLine[11] = createFileEntryLine("Border File Stage 12...", FILE_TYPE_BORDER_12, atlasWidgetLayout, atlasButtonGroup, editBordersPushButton[11]); atlasBorderFileEntryLine[12] = createFileEntryLine("Border File Stage 13...", FILE_TYPE_BORDER_13, atlasWidgetLayout, atlasButtonGroup, editBordersPushButton[12]); atlasBorderFileEntryLine[13] = createFileEntryLine("Border File Stage 14...", FILE_TYPE_BORDER_14, atlasWidgetLayout, atlasButtonGroup, editBordersPushButton[13]); atlasBorderFileEntryLine[14] = createFileEntryLine("Border File Stage 15...", FILE_TYPE_BORDER_15, atlasWidgetLayout, atlasButtonGroup, editBordersPushButton[14]); atlasBorderFileEntryLine[15] = createFileEntryLine("Border File Stage 16...", FILE_TYPE_BORDER_16, atlasWidgetLayout, atlasButtonGroup, editBordersPushButton[15]); atlasBorderFileEntryLine[16] = createFileEntryLine("Border File Stage 17...", FILE_TYPE_BORDER_17, atlasWidgetLayout, atlasButtonGroup, editBordersPushButton[16]); atlasBorderFileEntryLine[17] = createFileEntryLine("Border File Stage 18...", FILE_TYPE_BORDER_18, atlasWidgetLayout, atlasButtonGroup, editBordersPushButton[17]); atlasBorderFileEntryLine[18] = createFileEntryLine("Border File Stage 19...", FILE_TYPE_BORDER_19, atlasWidgetLayout, atlasButtonGroup, editBordersPushButton[18]); atlasBorderFileEntryLine[19] = createFileEntryLine("Border File Stage 20...", FILE_TYPE_BORDER_20, atlasWidgetLayout, atlasButtonGroup, editBordersPushButton[19]); for (int i = 0; i < DeformationMapFile::MAX_SPHERICAL_STAGES; i++) { atlasBorderLineEdit[i] = atlasBorderFileEntryLine[i]->lineEdit; } //atlasWidgetTop->setFixedSize(atlasWidgetTop->sizeHint()); const int numRows = atlasWidgetLayout->rowCount(); atlasWidgetLayout->addWidget(new QWidget, numRows, 0); atlasWidgetLayout->setRowStretch(numRows, 1000); } /** * update atlas border selections. */ void GuiSurfaceDeformationDialog::updateAtlasBorderSelections() { if (DebugControl::getDebugOn()) { std::cout << "Deformation Dialog Update: " << "Atlas Border Selections" << std::endl; } if (this->atlasBorderFileEntryLine[0] == NULL) { return; } // // Default spherical algorithm // switch (dmf.getFlatOrSphereSelection()) { case DeformationMapFile::DEFORMATION_TYPE_FLAT: case DeformationMapFile::DEFORMATION_TYPE_SPHERE: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: for (int i = 1; i < DeformationMapFile::MAX_SPHERICAL_STAGES; i++) { this->atlasBorderFileEntryLine[i]->setVisible(false); } this->atlasBorderFileEntryLine[0]->pushButton->setText("Border File..."); break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: this->atlasBorderFileEntryLine[0]->pushButton->setText("Border File Stage 1..."); for (int i = 1; i < DeformationMapFile::MAX_SPHERICAL_STAGES; i++) { this->atlasBorderFileEntryLine[i]->setVisible(true); bool enableFlag = (i < this->sphereNumberOfStagesSpinBox->value()); this->atlasBorderFileEntryLine[i]->setEnabled(enableFlag); } break; } } /** * Create the individual tab. */ void GuiSurfaceDeformationDialog::createIndividualWidget() { // // Start with a QVBox to prevent parameters from showing through // individualWidgetTop = new QWidget; dialogTabWidget->addTab(individualWidgetTop, "Individual"); QVBoxLayout* indivWidgetLayout = new QVBoxLayout(individualWidgetTop); // // Put everything in a QGrid // QGridLayout* individualGridLayout = new QGridLayout; indivWidgetLayout->addLayout(individualGridLayout); // // Button group for file selections // QButtonGroup* indivButtonGroup = new QButtonGroup(this); QObject::connect(indivButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(indivFileSelection(int))); // // Edit borders button // QPushButton* editBordersPushButton = new QPushButton("Edit..."); editBordersPushButton->setAutoDefault(false); QObject::connect(editBordersPushButton, SIGNAL(clicked()), this, SLOT(slotBordersEditIndividual())); // // Create the pushbuttons and line edits // indivSpecLineEdit = createFileEntryLine("Spec File...", FILE_TYPE_SPEC, individualGridLayout, indivButtonGroup)->lineEdit; indivClosedTopoLineEdit = createFileEntryLine("Closed Topo File...", FILE_TYPE_TOPO_CLOSED, individualGridLayout, indivButtonGroup)->lineEdit; indivCutTopoLineEdit = createFileEntryLine("Cut Topo File...", FILE_TYPE_TOPO_CUT, individualGridLayout, indivButtonGroup)->lineEdit; indivFiducialCoordLineEdit = createFileEntryLine("Fiducial Coord File...", FILE_TYPE_COORD_FIDUCIAL, individualGridLayout, indivButtonGroup)->lineEdit; indivSphericalCoordLineEdit = createFileEntryLine("Spherical Coord File...", FILE_TYPE_COORD_SPHERICAL, individualGridLayout, indivButtonGroup)->lineEdit; indivFlatCoordLineEdit = createFileEntryLine("Flat Coord...", FILE_TYPE_COORD_FLAT, individualGridLayout, indivButtonGroup)->lineEdit; indivBorderLineEdit = createFileEntryLine("Border File...", FILE_TYPE_BORDER_1, individualGridLayout, indivButtonGroup, editBordersPushButton)->lineEdit; //individualWidget->setFixedSize(individualWidget->sizeHint()); // // Box for control of coordinate file deformation // QGroupBox* indivCoordDeformGroupBox = new QGroupBox("Deform Coordinate Files To Atlas"); QGridLayout* indivCoordGridLayout = new QGridLayout(indivCoordDeformGroupBox); indivCoordGridLayout->setSpacing(10); indivWidgetLayout->addWidget(indivCoordDeformGroupBox); // // Request that fiducial coord files be deformed // deformIndivFiducialCoordCheckBox = new QCheckBox("Fiducial"); deformIndivFiducialCoordCheckBox->setChecked(true); indivCoordGridLayout->addWidget(deformIndivFiducialCoordCheckBox, 0, 0); // // Request that inflated coord files be deformed // deformIndivInflatedCoordCheckBox = new QCheckBox("Inflated"); deformIndivInflatedCoordCheckBox->setChecked(true); indivCoordGridLayout->addWidget(deformIndivInflatedCoordCheckBox, 0, 1); // // Request that very inflated coord files be deformed // deformIndivVeryInflatedCoordCheckBox = new QCheckBox("Very Inflated"); deformIndivVeryInflatedCoordCheckBox->setChecked(true); indivCoordGridLayout->addWidget(deformIndivVeryInflatedCoordCheckBox, 1, 0); // // Request that spherical coord files be deformed // deformIndivSphericalCoordCheckBox = new QCheckBox("Spherical"); deformIndivSphericalCoordCheckBox->setChecked(true); indivCoordGridLayout->addWidget(deformIndivSphericalCoordCheckBox, 1, 1); // // Request that flat coord files be deformed // deformIndivFlatCoordCheckBox = new QCheckBox("Flat"); deformIndivFlatCoordCheckBox->setChecked(true); indivCoordGridLayout->addWidget(deformIndivFlatCoordCheckBox, 2, 0); // // Request that flat lobar coord files be deformed // deformIndivFlatLobarCoordCheckBox = new QCheckBox("Flat Lobar"); deformIndivFlatLobarCoordCheckBox->setChecked(true); deformIndivFlatLobarCoordCheckBox->setHidden(true); indivCoordGridLayout->addWidget(deformIndivFlatLobarCoordCheckBox, 2, 1); // // Limit box size // //indivCoordDeformGroupBox->setFixedSize(indivCoordDeformGroupBox->sizeHint()); // // Only allow coord deformations if spherical deformation // switch (dmf.getFlatOrSphereSelection()) { case DeformationMapFile::DEFORMATION_TYPE_FLAT: indivCoordDeformGroupBox->setHidden(true); indivCoordDeformGroupBox->setEnabled(false); break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: indivCoordDeformGroupBox->setHidden(false); indivCoordDeformGroupBox->setEnabled(true); break; } indivWidgetLayout->addStretch(); } /** * called to edit individual borders. */ void GuiSurfaceDeformationDialog::slotBordersEditIndividual() { if (indivDeformationFiles.borderFileSelected[0] < 0) { QMessageBox::critical(this, "ERROR", "There are no individual border files."); return; } editBorderFile(indivSpecFileName, indivDeformationFiles.borderFileNames[indivDeformationFiles.borderFileSelected[0]], indivDeformationFiles.borderFileTypes[indivDeformationFiles.borderFileSelected[0]]); } /** * edit a border file. */ void GuiSurfaceDeformationDialog::editBorderFile(const QString& specFileName, const QString& borderFileName, const DeformationDataFiles::DATA_FILE_TYPES fileType) { // // Check inputs // if (specFileName.isEmpty()) { QMessageBox::critical(this, "ERROR", "Invalid spec file name"); return; } if (borderFileName.isEmpty()) { QMessageBox::critical(this, "ERROR", "Invalid border file name"); return; } // // Get the type of border file // GuiBorderAttributesDialog::BORDER_FILE_TYPE borderFileType = GuiBorderAttributesDialog::BORDER_FILE_TYPE_BORDER; switch(fileType) { case DeformationDataFiles::DATA_FILE_BORDER_FLAT: borderFileType = GuiBorderAttributesDialog::BORDER_FILE_TYPE_BORDER; break; case DeformationDataFiles::DATA_FILE_BORDER_FLAT_LOBAR: borderFileType = GuiBorderAttributesDialog::BORDER_FILE_TYPE_BORDER; break; case DeformationDataFiles::DATA_FILE_BORDER_SPHERICAL: borderFileType = GuiBorderAttributesDialog::BORDER_FILE_TYPE_BORDER; break; case DeformationDataFiles::DATA_FILE_BORDER_PROJECTION: borderFileType = GuiBorderAttributesDialog::BORDER_FILE_TYPE_BORDER_PROJECTION; break; case DeformationDataFiles::DATA_FILE_TOPO_CLOSED: case DeformationDataFiles::DATA_FILE_TOPO_CUT: case DeformationDataFiles::DATA_FILE_TOPO_CUT_LOBAR: case DeformationDataFiles::DATA_FILE_COORD_FIDUCIAL: case DeformationDataFiles::DATA_FILE_COORD_FLAT: case DeformationDataFiles::DATA_FILE_COORD_FLAT_LOBAR: case DeformationDataFiles::DATA_FILE_COORD_SPHERICAL: QMessageBox::critical(this, "ERROR", "Border file type is invalid"); return; break; } // // Save current directory // const QString savedDirectory = QDir::currentPath(); // // Set to directory containing spec file // QDir::setCurrent(FileUtilities::dirname(specFileName)); // // Launch the border editing dialog // GuiBorderAttributesDialog bad(this, borderFileName, borderFileType, false); bad.exec(); // // Restore current directory // QDir::setCurrent(savedDirectory); } /** * called to edit atlas borders. */ void GuiSurfaceDeformationDialog::slotBordersEditAtlas(int index) { if (atlasDeformationFiles.borderFileSelected[index] < 0) { QMessageBox::critical(this, "ERROR", "There are no atlas border files."); return; } editBorderFile(atlasSpecFileName, atlasDeformationFiles.borderFileNames[atlasDeformationFiles.borderFileSelected[index]], atlasDeformationFiles.borderFileTypes[atlasDeformationFiles.borderFileSelected[index]]); } /** * Create the parameters tab. */ void GuiSurfaceDeformationDialog::createParametersWidget() { QString tabTitle("ERROR"); QWidget* sphereFlatParmsWidget = NULL; bool showParamsButtonsFlag = false; switch (dmf.getFlatOrSphereSelection()) { case DeformationMapFile::DEFORMATION_TYPE_SPHERE: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: // // Create the spherical parameters // tabTitle = "Spherical Parameters"; sphereFlatParmsWidget = createSphericalParameters(); showParamsButtonsFlag = true; break; case DeformationMapFile::DEFORMATION_TYPE_FLAT: // // Create the spherical parameters // tabTitle = "Flat Parameters"; sphereFlatParmsWidget = createFlatParameters(); break; } // // Create a pushbutton to use standard parameters // QPushButton* standardParametersPushButton = new QPushButton("Select Standard Parameters..."); standardParametersPushButton->setAutoDefault(false); standardParametersPushButton->setFixedSize(standardParametersPushButton->sizeHint()); QObject::connect(standardParametersPushButton, SIGNAL(clicked()), this, SLOT(slotStandardParametersPushButton())); // // Create a pushbutton to load parameters from a DeformationMapFile // QPushButton* loadDefMapFilePushButton = new QPushButton("Read Parameter From Def Map File..."); loadDefMapFilePushButton->setAutoDefault(false); loadDefMapFilePushButton->setFixedSize(loadDefMapFilePushButton->sizeHint()); QObject::connect(loadDefMapFilePushButton, SIGNAL(clicked()), this, SLOT(loadDeformationMapFilePushButton())); // // Save parameters to a file // QPushButton* saveDefMapFilePushButton = new QPushButton("Save Parameters to Def Map File..."); saveDefMapFilePushButton->setAutoDefault(false); saveDefMapFilePushButton->setFixedSize(saveDefMapFilePushButton->sizeHint()); QObject::connect(saveDefMapFilePushButton, SIGNAL(clicked()), this, SLOT(saveDeformationMapFilePushButton())); QGroupBox* setParamsGroupBox = new QGroupBox("Set Parameters"); QHBoxLayout* setParamsLayout = new QHBoxLayout(setParamsGroupBox); setParamsLayout->addWidget(standardParametersPushButton); setParamsLayout->addWidget(saveDefMapFilePushButton); setParamsLayout->addWidget(loadDefMapFilePushButton); parametersWidget = new QWidget; QVBoxLayout* parametersLayout = new QVBoxLayout(parametersWidget); if (sphereFlatParmsWidget != NULL) { parametersLayout->addWidget(sphereFlatParmsWidget); } parametersLayout->addWidget(setParamsGroupBox); dialogTabWidget->addTab(parametersWidget, tabTitle); if (showParamsButtonsFlag == false) { setParamsGroupBox->setVisible(false); } } /** * Create the misc tab. */ void GuiSurfaceDeformationDialog::createDeformationWidget() { // // Create the border resampling section // QWidget* borderWidget = createBorderResampling(); // // Create the metric deformation // QWidget* metricWidget = createMetricDeformation(); // // Checkbox to deform in both directions // deformBothWaysCheckBox = new QCheckBox("Deform Indiv to Atlas and Atlas to Individual"); deformBothWaysCheckBox->setChecked(true); QObject::connect(deformBothWaysCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotDeformationParameterChanged())); // // Delete intermediate files check box // deleteIntermediateFilesCheckBox = new QCheckBox("Delete Intermediate Files"); QObject::connect(deleteIntermediateFilesCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotDeformationParameterChanged())); // // label and line edit for deformed file prefix // QLabel* deformedFileLabel = new QLabel("Deformed File Name Prefix "); deformedFilePrefixLineEdit = new QLineEdit; QObject::connect(deformedFilePrefixLineEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotDeformationParameterChanged())); QHBoxLayout* deformedFileLayout = new QHBoxLayout; deformedFileLayout->addWidget(deformedFileLabel); deformedFileLayout->addWidget(deformedFilePrefixLineEdit); // // label and line edit for deformed column name prefix // QLabel* deformedColumnLabel = new QLabel("Deformed Column Name Prefix "); deformedColumnPrefixLineEdit = new QLineEdit; QObject::connect(deformedColumnPrefixLineEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotDeformationParameterChanged())); QHBoxLayout* deformedColumnLayout = new QHBoxLayout; deformedColumnLayout->addWidget(deformedColumnLabel); deformedColumnLayout->addWidget(deformedColumnPrefixLineEdit); // // Deformation Control Group Box // QGroupBox* controlGroupBox = new QGroupBox("Deformation Control"); QVBoxLayout* controlGroupLayout = new QVBoxLayout(controlGroupBox); controlGroupLayout->addWidget(deformBothWaysCheckBox); controlGroupLayout->addWidget(deleteIntermediateFilesCheckBox); controlGroupLayout->addLayout(deformedFileLayout); controlGroupLayout->addLayout(deformedColumnLayout); // // Smooth Coordinate files option // smoothCoordsOneIterationCheckBox = new QCheckBox("Smooth One Iteration (Except Flat)"); smoothCoordsOneIterationCheckBox->setChecked(true); QObject::connect(smoothCoordsOneIterationCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotDeformationParameterChanged())); // // Coordinate file options // QGroupBox* coordGroupBox = new QGroupBox("Coordinate Data File Deformation Options"); QVBoxLayout* coordGroupLayout = new QVBoxLayout(coordGroupBox); coordGroupLayout->addWidget(smoothCoordsOneIterationCheckBox); // // Deformation map file names // QLabel* indivToAtlasDeformMapFileNameLabel = new QLabel("Indiv to Atlas"); indivToAtlasDeformMapFileNameLineEdit = new QLineEdit; QObject::connect(indivToAtlasDeformMapFileNameLineEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotDeformationParameterChanged())); QLabel* atlasToIndivDeformMapFileNameLabel = new QLabel("Atlas to Indiv"); atlasToIndivDeformMapFileNameLineEdit = new QLineEdit; QObject::connect(atlasToIndivDeformMapFileNameLineEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotDeformationParameterChanged())); QGroupBox* defMapNameGroupBox = new QGroupBox("Deformation Map File Names"); QGridLayout* defMapNameLayout = new QGridLayout(defMapNameGroupBox); defMapNameLayout->addWidget(indivToAtlasDeformMapFileNameLabel, 0, 0); defMapNameLayout->addWidget(indivToAtlasDeformMapFileNameLineEdit, 0, 1); defMapNameLayout->addWidget(atlasToIndivDeformMapFileNameLabel, 1, 0); defMapNameLayout->addWidget(atlasToIndivDeformMapFileNameLineEdit, 1, 1); defMapNameLayout->setColumnStretch(0, 0); defMapNameLayout->setColumnStretch(1, 100); // // Put border/metric items side by side // QHBoxLayout* borderMetricLayout = new QHBoxLayout; borderMetricLayout->addWidget(borderWidget); borderMetricLayout->addWidget(metricWidget); // // Top widget // deformationWidgetTop = new QWidget; dialogTabWidget->addTab(deformationWidgetTop, "Deformation"); QVBoxLayout* deformationWidgetLayout = new QVBoxLayout(deformationWidgetTop); deformationWidgetLayout->addLayout(borderMetricLayout); deformationWidgetLayout->addWidget(controlGroupBox); deformationWidgetLayout->addWidget(coordGroupBox); deformationWidgetLayout->addWidget(defMapNameGroupBox); deformationWidgetLayout->addStretch(); } /** * setup connections for automatic update of deformation map file names. */ void GuiSurfaceDeformationDialog::setConnectionsForAutoDefMapFileNameUpdates() { QObject::connect(this->deformedFilePrefixLineEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotUpdateDeformationMapFileNames())); QObject::connect(this->indivSpecLineEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotUpdateDeformationMapFileNames())); QObject::connect(this->atlasSpecLineEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotUpdateDeformationMapFileNames())); } /** * called to update deformation map file names. */ void GuiSurfaceDeformationDialog::slotUpdateDeformationMapFileNames() { QString indivToAtlasSpecFileName = BrainModelSurfaceDeformDataFile::createDeformedSpecFileName( this->deformedFilePrefixLineEdit->text(), this->indivSpecLineEdit->text(), this->atlasSpecLineEdit->text()); this->indivToAtlasDeformMapFileNameLineEdit->blockSignals(true); this->indivToAtlasDeformMapFileNameLineEdit->setText(indivToAtlasSpecFileName); this->indivToAtlasDeformMapFileNameLineEdit->blockSignals(false); QString atlasToIndivSpecFileName = BrainModelSurfaceDeformDataFile::createDeformedSpecFileName( this->deformedFilePrefixLineEdit->text(), this->atlasSpecLineEdit->text(), this->indivSpecLineEdit->text()); this->atlasToIndivDeformMapFileNameLineEdit->blockSignals(true); this->atlasToIndivDeformMapFileNameLineEdit->setText(atlasToIndivSpecFileName); this->atlasToIndivDeformMapFileNameLineEdit->blockSignals(false); } /** * */ QWidget* GuiSurfaceDeformationDialog::createBorderResampling() { // // "None" resampling // borderResamplingNoneRadioButton = new QRadioButton("None"); // // From border file resampling // borderResamplingFromFileRadioButton = new QRadioButton("From Border File"); // // Horizontal box for resample to button and spin box // borderResamplingToValueRadioButton = new QRadioButton("Resample To"); borderResamplingDoubleSpinBox = new QDoubleSpinBox; borderResamplingDoubleSpinBox->setMinimum(0.0); borderResamplingDoubleSpinBox->setMaximum(10000.0); borderResamplingDoubleSpinBox->setSingleStep(1.0); borderResamplingDoubleSpinBox->setDecimals(3); borderResamplingDoubleSpinBox->setFixedWidth(100); QObject::connect(borderResamplingDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(slotDeformationParameterChanged())); // // Put stuff in a vertical group box // QGroupBox* borderGroup = new QGroupBox("Border Resampling Interval"); QGridLayout* borderLayout = new QGridLayout(borderGroup); borderLayout->addWidget(borderResamplingNoneRadioButton, 0, 0); borderLayout->addWidget(borderResamplingFromFileRadioButton, 1, 0); borderLayout->addWidget(borderResamplingToValueRadioButton, 2, 0); borderLayout->addWidget(borderResamplingDoubleSpinBox, 2, 1); // // button group so that buttons remain mutually exclusive // QButtonGroup* borderButtonGroup = new QButtonGroup(borderGroup); borderButtonGroup->addButton(borderResamplingNoneRadioButton, 0); borderButtonGroup->addButton(borderResamplingFromFileRadioButton, 1); borderButtonGroup->addButton(borderResamplingToValueRadioButton, 2); QObject::connect(borderButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotDeformationParameterChanged())); return borderGroup; } /** * */ QWidget* GuiSurfaceDeformationDialog::createMetricDeformation() { metricNearestNodeRadioButton = new QRadioButton("Nearest Node"); metricAverageTileNodesRadioButton = new QRadioButton("Average of Tile's Nodes"); QGroupBox* metricGroupBox = new QGroupBox("Metric Deformation"); QVBoxLayout* metricGroupLayout = new QVBoxLayout(metricGroupBox); metricGroupLayout->addWidget(metricNearestNodeRadioButton); metricGroupLayout->addWidget(metricAverageTileNodesRadioButton); QButtonGroup* metricButtonGroup = new QButtonGroup(this); metricButtonGroup->addButton(metricNearestNodeRadioButton); metricButtonGroup->addButton(metricAverageTileNodesRadioButton); QObject::connect(metricButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotDeformationParameterChanged())); return metricGroupBox; } /** * create the landmark vector options. */ QWidget* GuiSurfaceDeformationDialog::createLandmarkVectorOptionsSection() { QLabel* vectorSmoothingLabel = new QLabel("Vector Smoothing Iterations"); vectorSmoothingIterationsSpinBox = new QSpinBox; vectorSmoothingIterationsSpinBox->setMinimum(0); vectorSmoothingIterationsSpinBox->setMaximum(100000); vectorSmoothingIterationsSpinBox->setSingleStep(1); vectorSmoothingIterationsSpinBox->setValue(10); QObject::connect(vectorSmoothingIterationsSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotLandmarkVectorParameterChanged())); QLabel* vectorDisplacementFactorLabel = new QLabel("Displacement Factor"); vectorDisplacementFactorDoubleSpinBox = new QDoubleSpinBox; vectorDisplacementFactorDoubleSpinBox->setMinimum(0.0); vectorDisplacementFactorDoubleSpinBox->setMaximum(100000.0); vectorDisplacementFactorDoubleSpinBox->setSingleStep(0.1); vectorDisplacementFactorDoubleSpinBox->setDecimals(2); vectorDisplacementFactorDoubleSpinBox->setValue(1.0); QObject::connect(vectorDisplacementFactorDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(slotLandmarkVectorParameterChanged())); QLabel* vectorEndpointFactorLabel = new QLabel("Endpoint Factor"); vectorEndpointFactorDoubleSpinBox = new QDoubleSpinBox; vectorEndpointFactorDoubleSpinBox->setMinimum(0.0); vectorEndpointFactorDoubleSpinBox->setMaximum(1000000.0); vectorEndpointFactorDoubleSpinBox->setSingleStep(0.1); vectorEndpointFactorDoubleSpinBox->setDecimals(2); vectorEndpointFactorDoubleSpinBox->setValue(1.0); QObject::connect(vectorEndpointFactorDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(slotLandmarkVectorParameterChanged())); pauseForCrossoversConfirmationCheckBox = new QCheckBox("Pause for Crossovers Confirmation"); QObject::connect(pauseForCrossoversConfirmationCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotLandmarkVectorParameterChanged())); QGroupBox* vectorGroupBox = new QGroupBox("Landmark Vector Options"); QGridLayout* vectorGridLayout = new QGridLayout(vectorGroupBox); vectorGridLayout->addWidget(vectorSmoothingLabel, 0, 0); vectorGridLayout->addWidget(vectorSmoothingIterationsSpinBox, 0, 1); vectorGridLayout->addWidget(vectorDisplacementFactorLabel, 1, 0); vectorGridLayout->addWidget(vectorDisplacementFactorDoubleSpinBox, 1, 1); vectorGridLayout->addWidget(vectorEndpointFactorLabel, 2, 0); vectorGridLayout->addWidget(vectorEndpointFactorDoubleSpinBox, 2, 1); vectorGridLayout->addWidget(pauseForCrossoversConfirmationCheckBox, 3, 0, 1, 2); vectorGroupBox->setMaximumHeight(vectorGroupBox->sizeHint().height()); landmarkVectorParametersWidgetGroup = new WuQWidgetGroup(this); landmarkVectorParametersWidgetGroup->addWidget(vectorSmoothingIterationsSpinBox); landmarkVectorParametersWidgetGroup->addWidget(vectorDisplacementFactorDoubleSpinBox); landmarkVectorParametersWidgetGroup->addWidget(vectorEndpointFactorDoubleSpinBox); landmarkVectorParametersWidgetGroup->addWidget(pauseForCrossoversConfirmationCheckBox); return vectorGroupBox; } /** * called when a landmark vector parameter is changed. */ void GuiSurfaceDeformationDialog::slotLandmarkVectorParameterChanged() { if (DebugControl::getDebugOn()) { std::cout << "Deformation Dialog Read: " << "Landmark Vector Parameter" << std::endl; } const int stageIndex = sphereEditStageSpinBox->value() - 1; const int cycleIndex = sphereEditCycleSpinBox->value() - 1; dmf.setLandmarkVectorParameters(stageIndex, cycleIndex, this->vectorSmoothingIterationsSpinBox->value(), this->vectorDisplacementFactorDoubleSpinBox->value()); dmf.setLandmarkVectorStageParameters(stageIndex, this->vectorEndpointFactorDoubleSpinBox->value()); dmf.setPauseForCrossoversConfirmation(this->pauseForCrossoversConfirmationCheckBox->isChecked()); } /** * update the landmark vector parameters. */ void GuiSurfaceDeformationDialog::updateLandmarkVectorParameters() { if (DebugControl::getDebugOn()) { std::cout << "Deformation Dialog Update: " << "Landmark Vector Parameters" << std::endl; } const int stageIndex = sphereEditStageSpinBox->value() - 1; const int cycleIndex = sphereEditCycleSpinBox->value() - 1; landmarkVectorParametersWidgetGroup->blockSignals(true); int vectorSmoothingIterations = 0; float vectorDisplacementFactor = 1.0; dmf.getLandmarkVectorParameters(stageIndex, cycleIndex, vectorSmoothingIterations, vectorDisplacementFactor); this->vectorSmoothingIterationsSpinBox->setValue(vectorSmoothingIterations); this->vectorDisplacementFactorDoubleSpinBox->setValue(vectorDisplacementFactor); float endpointFactor = 1.0; dmf.getLandmarkVectorStageParameters(stageIndex, endpointFactor); this->vectorEndpointFactorDoubleSpinBox->setValue(endpointFactor); this->pauseForCrossoversConfirmationCheckBox->setChecked(dmf.getPauseForCrossoversConfirmation()); landmarkVectorParametersWidgetGroup->blockSignals(false); } /** * called when a spherical algorithm is selected. */ void GuiSurfaceDeformationDialog::slotSphericalAlgorithmSelection() { if (DebugControl::getDebugOn()) { std::cout << "Deformation Dialog Read: " << "Spherical Algorithm" << std::endl; } if (this->sphericalLandmarkConstrainedRadioButton->isChecked()) { dmf.setFlatOrSphereSelection(DeformationMapFile::DEFORMATION_TYPE_SPHERE); this->sphereNumberOfStagesSpinBox->setValue(1); } else if (this->sphericalLandmarkVectorRadioButton->isChecked()) { dmf.setFlatOrSphereSelection(DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR); } else if (this->sphericalLandmarkVectorSingleStageRadioButton->isChecked()) { dmf.setFlatOrSphereSelection(DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR); this->sphereNumberOfStagesSpinBox->setValue(1); } updateAlgorithmSelection(); } /** * update algorithm selection. */ void GuiSurfaceDeformationDialog::updateAlgorithmSelection() { bool enableVectorOptionsFlag = false; this->sphericalLandmarkConstrainedRadioButton->blockSignals(true); this->sphericalLandmarkVectorRadioButton->blockSignals(true); this->sphericalLandmarkVectorSingleStageRadioButton->blockSignals(true); switch (dmf.getFlatOrSphereSelection()) { case DeformationMapFile::DEFORMATION_TYPE_FLAT: break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE: this->sphericalLandmarkConstrainedRadioButton->setChecked(true); break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: this->sphericalLandmarkVectorSingleStageRadioButton->setChecked(true); enableVectorOptionsFlag = true; break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: this->sphericalLandmarkVectorRadioButton->setChecked(true); enableVectorOptionsFlag = true; break; } this->sphericalLandmarkConstrainedRadioButton->blockSignals(false); this->sphericalLandmarkVectorRadioButton->blockSignals(false); this->sphericalLandmarkVectorSingleStageRadioButton->blockSignals(false); landmarkVectorOptionsWidget->setEnabled(enableVectorOptionsFlag); sphereStagesWidgetGroup->setEnabled(enableVectorOptionsFlag); updateAtlasBorderSelections(); } /** * create the spherical algorithm section. */ QWidget* GuiSurfaceDeformationDialog::createSphericalAlgorithmSection() { // // Create the algorithm selection radio buttons // sphericalLandmarkConstrainedRadioButton = new QRadioButton("Landmark Pinned Relaxation"); sphericalLandmarkVectorRadioButton = new QRadioButton("Landmark Vector Difference"); sphericalLandmarkVectorSingleStageRadioButton = new QRadioButton("Landmark Vector Difference Single Stage"); // // NO SINGLE STAGE VECTOR DEFORMATION // sphericalLandmarkVectorSingleStageRadioButton->setHidden(true); // // Button group to make buttons mutually exclusive // QButtonGroup* buttGroup = new QButtonGroup(this); buttGroup->addButton(sphericalLandmarkConstrainedRadioButton); buttGroup->addButton(sphericalLandmarkVectorRadioButton); buttGroup->addButton(sphericalLandmarkVectorSingleStageRadioButton); QObject::connect(buttGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotSphericalAlgorithmSelection())); // // Group box and layout // QGroupBox* algorithmGroupBox = new QGroupBox("Spherical Algorithm"); QVBoxLayout* layout = new QVBoxLayout(algorithmGroupBox); layout->addWidget(sphericalLandmarkConstrainedRadioButton); layout->addWidget(sphericalLandmarkVectorRadioButton); layout->addWidget(sphericalLandmarkVectorSingleStageRadioButton); algorithmGroupBox->setMaximumHeight(algorithmGroupBox->sizeHint().height()); return algorithmGroupBox; } /** * create the morphing parameters section. */ QWidget* GuiSurfaceDeformationDialog::createMorphingParametersSection() { // // label and spin box // QLabel* morphCyclesLabel = new QLabel("Cycles"); morphingCyclesSpinBox = new QSpinBox; QObject::connect(morphingCyclesSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotMorphingParameterChanged())); morphingCyclesSpinBox->setMinimum(0); morphingCyclesSpinBox->setMaximum(5000); morphingCyclesSpinBox->setSingleStep(1); morphingCyclesSpinBox->setFixedWidth(120); // // label and spin box // QLabel* morphingLinearForceLabel = new QLabel("Linear Force"); morphingLinearForceDoubleSpinBox = new QDoubleSpinBox; QObject::connect(morphingLinearForceDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(slotMorphingParameterChanged())); morphingLinearForceDoubleSpinBox->setMinimum(0.0); morphingLinearForceDoubleSpinBox->setMaximum(1.0); morphingLinearForceDoubleSpinBox->setSingleStep(0.05); morphingLinearForceDoubleSpinBox->setDecimals(3); morphingLinearForceDoubleSpinBox->setFixedWidth(120); // // label and spin box // QLabel* morphingAngularForceLabel = new QLabel("Angular Force"); morphingAngularForceDoubleSpinBox = new QDoubleSpinBox; QObject::connect(morphingAngularForceDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(slotMorphingParameterChanged())); morphingAngularForceDoubleSpinBox->setMinimum(0.0); morphingAngularForceDoubleSpinBox->setMaximum(1.0); morphingAngularForceDoubleSpinBox->setSingleStep(0.05); morphingAngularForceDoubleSpinBox->setDecimals(3); morphingAngularForceDoubleSpinBox->setFixedWidth(120); // // label and spin box // QLabel* morphingStepSizeLabel = new QLabel("Step Size"); morphingStepSizeDoubleSpinBox = new QDoubleSpinBox; QObject::connect(morphingStepSizeDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(slotMorphingParameterChanged())); morphingStepSizeDoubleSpinBox->setMinimum(0.0); morphingStepSizeDoubleSpinBox->setMaximum(1.0); morphingStepSizeDoubleSpinBox->setSingleStep(0.05); morphingStepSizeDoubleSpinBox->setDecimals(3); morphingStepSizeDoubleSpinBox->setFixedWidth(120); // // label and spin box // QLabel* morphingLandmarkLabel = new QLabel("Landmark Step Size"); morphingLandmarkStepSizeDoubleSpinBox = new QDoubleSpinBox; QObject::connect(morphingLandmarkStepSizeDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(slotMorphingParameterChanged())); morphingLandmarkStepSizeDoubleSpinBox->setMinimum(0.0); morphingLandmarkStepSizeDoubleSpinBox->setMaximum(1.0); morphingLandmarkStepSizeDoubleSpinBox->setSingleStep(0.05); morphingLandmarkStepSizeDoubleSpinBox->setDecimals(3); morphingLandmarkStepSizeDoubleSpinBox->setFixedWidth(120); // // label and spin box // QLabel* morphingIterationsLabel = new QLabel("Iterations"); morphingIterationsSpinBox = new QSpinBox; QObject::connect(morphingIterationsSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotMorphingParameterChanged())); morphingIterationsSpinBox->setMinimum(0); morphingIterationsSpinBox->setMaximum(5000); morphingIterationsSpinBox->setSingleStep(10); morphingIterationsSpinBox->setFixedWidth(120); // // label and spin box // QLabel* morphingSmoothLabel = new QLabel("Smooth Iterations"); morphingSmoothIterationsSpinBox = new QSpinBox; QObject::connect(morphingSmoothIterationsSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotMorphingParameterChanged())); morphingSmoothIterationsSpinBox->setMinimum(0); morphingSmoothIterationsSpinBox->setMaximum(5000); morphingSmoothIterationsSpinBox->setSingleStep(1); morphingSmoothIterationsSpinBox->setFixedWidth(120); // // Group box for morphing parameters // QGroupBox* morphGroupBox = new QGroupBox("Morphing Parameters"); QGridLayout* morphGroupLayout = new QGridLayout(morphGroupBox); morphGroupLayout->addWidget(morphCyclesLabel, 0, 0); morphGroupLayout->addWidget(morphingCyclesSpinBox, 0, 1); morphGroupLayout->addWidget(morphingLinearForceLabel, 1, 0); morphGroupLayout->addWidget(morphingLinearForceDoubleSpinBox, 1, 1); morphGroupLayout->addWidget(morphingAngularForceLabel, 2, 0); morphGroupLayout->addWidget(morphingAngularForceDoubleSpinBox, 2, 1); morphGroupLayout->addWidget(morphingStepSizeLabel, 3, 0); morphGroupLayout->addWidget(morphingStepSizeDoubleSpinBox, 3, 1); morphGroupLayout->addWidget(morphingLandmarkLabel, 4, 0); morphGroupLayout->addWidget(morphingLandmarkStepSizeDoubleSpinBox, 4, 1); morphGroupLayout->addWidget(morphingIterationsLabel, 5, 0); morphGroupLayout->addWidget(morphingIterationsSpinBox, 5, 1); morphGroupLayout->addWidget(morphingSmoothLabel, 6, 0); morphGroupLayout->addWidget(morphingSmoothIterationsSpinBox, 6, 1); //morphGroupLayout->setRowStretch(7, 100); morphGroupBox->setMaximumHeight(morphGroupBox->sizeHint().height()); morphingParametersWidgetGroup = new WuQWidgetGroup(this); morphingParametersWidgetGroup->addWidget(morphingCyclesSpinBox); morphingParametersWidgetGroup->addWidget(morphingLinearForceDoubleSpinBox); morphingParametersWidgetGroup->addWidget(morphingAngularForceDoubleSpinBox); morphingParametersWidgetGroup->addWidget(morphingStepSizeDoubleSpinBox); morphingParametersWidgetGroup->addWidget(morphingLandmarkStepSizeDoubleSpinBox); morphingParametersWidgetGroup->addWidget(morphingIterationsSpinBox); morphingParametersWidgetGroup->addWidget(morphingSmoothIterationsSpinBox); return morphGroupBox; } /** * called when a morphing parameter is changed. */ void GuiSurfaceDeformationDialog::slotMorphingParameterChanged() { if (DebugControl::getDebugOn()) { std::cout << "Deformation Dialog Read: " << "Morphing Parameters" << std::endl; } const int stageIndex = sphereEditStageSpinBox->value() - 1; const int cycleIndex = sphereEditCycleSpinBox->value() - 1; // // Get the morphing parameters // dmf.setMorphingParameters(stageIndex, cycleIndex, morphingCyclesSpinBox->value(), morphingLinearForceDoubleSpinBox->value(), morphingAngularForceDoubleSpinBox->value(), morphingStepSizeDoubleSpinBox->value(), morphingLandmarkStepSizeDoubleSpinBox->value(), morphingIterationsSpinBox->value(), morphingSmoothIterationsSpinBox->value()); } /** * update the morphing parameters. */ void GuiSurfaceDeformationDialog::updateMorphingParameters() { if (DebugControl::getDebugOn()) { std::cout << "Deformation Dialog Update: " << "Morphing Parameters" << std::endl; } const int stageIndex = sphereEditStageSpinBox->value() - 1; const int cycleIndex = sphereEditCycleSpinBox->value() - 1; morphingParametersWidgetGroup->blockSignals(true); float linearForce, angularForce, stepSize, landmarkStepSize; int cycles, iterations, smoothIterations; dmf.getMorphingParameters(stageIndex, cycleIndex, cycles, linearForce, angularForce, stepSize, landmarkStepSize, iterations, smoothIterations); morphingCyclesSpinBox->setValue(cycles); morphingLinearForceDoubleSpinBox->setValue(linearForce); morphingAngularForceDoubleSpinBox->setValue(angularForce); morphingStepSizeDoubleSpinBox->setValue(stepSize); morphingLandmarkStepSizeDoubleSpinBox->setValue(landmarkStepSize); morphingIterationsSpinBox->setValue(iterations); morphingSmoothIterationsSpinBox->setValue(smoothIterations); morphingParametersWidgetGroup->blockSignals(false); } /** * create the smoothing parameters section. */ QWidget* GuiSurfaceDeformationDialog::createSmoothingParametersSection() { // // label and strength spin box // QLabel* strengthLabel = new QLabel("Strength"); smoothingStrengthDoubleSpinBox = new QDoubleSpinBox; QObject::connect(smoothingStrengthDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(slotSmoothingParameterChanged())); smoothingStrengthDoubleSpinBox->setMinimum(0.0); smoothingStrengthDoubleSpinBox->setMaximum(1.0); smoothingStrengthDoubleSpinBox->setSingleStep(0.05); smoothingStrengthDoubleSpinBox->setDecimals(3); smoothingStrengthDoubleSpinBox->setFixedWidth(120); // // label and cycles spin box // QLabel* cyclesLabel = new QLabel("Cycles"); smoothingCyclesSpinBox = new QSpinBox; QObject::connect(smoothingCyclesSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotSmoothingParameterChanged())); smoothingCyclesSpinBox->setMinimum(0); smoothingCyclesSpinBox->setMaximum(50000); smoothingCyclesSpinBox->setSingleStep(10); smoothingCyclesSpinBox->setFixedWidth(120); // // label and iterations per cycle spin box // QLabel* iterationsLabel = new QLabel("Iterations/Cycle"); smoothingIterationsSpinBox = new QSpinBox; QObject::connect(smoothingIterationsSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotSmoothingParameterChanged())); smoothingIterationsSpinBox->setMinimum(0); smoothingIterationsSpinBox->setMaximum(50000); smoothingIterationsSpinBox->setSingleStep(5); smoothingIterationsSpinBox->setFixedWidth(120); // // label and smooth neighbors spin box // QLabel* smoothNeighborsLabel = new QLabel("Smooth Neighbors Every X"); smoothingNeighborsSpinBox = new QSpinBox; QObject::connect(smoothingNeighborsSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotSmoothingParameterChanged())); smoothingNeighborsSpinBox->setMinimum(0); smoothingNeighborsSpinBox->setMaximum(50000); smoothingNeighborsSpinBox->setSingleStep(1); smoothingNeighborsSpinBox->setFixedWidth(120); // // label and final smoothing iterations // QLabel* finalSmoothLabel = new QLabel("Final Smoothing Iterations"); smoothingFinalSpinBox = new QSpinBox; QObject::connect(smoothingFinalSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotSmoothingParameterChanged())); smoothingFinalSpinBox->setMinimum(0); smoothingFinalSpinBox->setMaximum(50000); smoothingFinalSpinBox->setSingleStep(1); smoothingFinalSpinBox->setFixedWidth(120); // // Group box and layout for smoothing parameters // QGroupBox* smoothingParamsGroupBox = new QGroupBox("Smoothing Parameters"); QGridLayout* smoothingParamsLayout = new QGridLayout(smoothingParamsGroupBox); smoothingParamsLayout->addWidget(strengthLabel, 0, 0); smoothingParamsLayout->addWidget(smoothingStrengthDoubleSpinBox, 0, 1); smoothingParamsLayout->addWidget(cyclesLabel, 1, 0); smoothingParamsLayout->addWidget(smoothingCyclesSpinBox, 1, 1); smoothingParamsLayout->addWidget(iterationsLabel, 2, 0); smoothingParamsLayout->addWidget(smoothingIterationsSpinBox, 2, 1); smoothingParamsLayout->addWidget(smoothNeighborsLabel, 3, 0); smoothingParamsLayout->addWidget(smoothingNeighborsSpinBox, 3, 1); smoothingParamsLayout->addWidget(finalSmoothLabel, 4, 0); smoothingParamsLayout->addWidget(smoothingFinalSpinBox, 4, 1); smoothingParamsGroupBox->setMaximumHeight(smoothingParamsGroupBox->sizeHint().height()); smoothingParametersWidgetGroup = new WuQWidgetGroup(this); smoothingParametersWidgetGroup->addWidget(smoothingStrengthDoubleSpinBox); smoothingParametersWidgetGroup->addWidget(smoothingCyclesSpinBox); smoothingParametersWidgetGroup->addWidget(smoothingIterationsSpinBox); smoothingParametersWidgetGroup->addWidget(smoothingNeighborsSpinBox); smoothingParametersWidgetGroup->addWidget(smoothingFinalSpinBox); return smoothingParamsGroupBox; } /** * called when a smoothing parameter is altered. */ void GuiSurfaceDeformationDialog::slotSmoothingParameterChanged() { if (DebugControl::getDebugOn()) { std::cout << "Deformation Dialog Read: " << "Smoothing Parameter" << std::endl; } const int stageIndex = sphereEditStageSpinBox->value() - 1; const int cycleIndex = sphereEditCycleSpinBox->value() - 1; // // Get the smoothing parameters // dmf.setSmoothingParameters(stageIndex, cycleIndex, smoothingStrengthDoubleSpinBox->value(), smoothingCyclesSpinBox->value(), smoothingIterationsSpinBox->value(), smoothingNeighborsSpinBox->value(), smoothingFinalSpinBox->value()); } /** * update the smoothing parameters. */ void GuiSurfaceDeformationDialog::updateSmoothingParameters() { if (DebugControl::getDebugOn()) { std::cout << "Deformation Dialog Update: " << "Smoothing Parameters" << std::endl; } const int stageIndex = sphereEditStageSpinBox->value() - 1; const int cycleIndex = sphereEditCycleSpinBox->value() - 1; smoothingParametersWidgetGroup->blockSignals(true); float strength; int cycles, iterations, neighbors, finals; dmf.getSmoothingParameters(stageIndex, cycleIndex, strength, cycles, iterations, neighbors, finals); smoothingStrengthDoubleSpinBox->setValue(strength); smoothingCyclesSpinBox->setValue(cycles); smoothingIterationsSpinBox->setValue(iterations); smoothingNeighborsSpinBox->setValue(neighbors); smoothingFinalSpinBox->setValue(finals); smoothingParametersWidgetGroup->blockSignals(false); } /** * update the spherical resolution combo box. */ void GuiSurfaceDeformationDialog::updateSphericalResolutionComboBox() { if (DebugControl::getDebugOn()) { std::cout << "Deformation Dialog Update: " << "Spherical Resolution" << std::endl; } const int stageIndex = sphereEditStageSpinBox->value() - 1; this->sphereResolutionComboBox->blockSignals(true); const int numNodesInSphere = dmf.getSphereResolution(stageIndex); switch(numNodesInSphere) { case 20: sphereResolutionComboBox->setCurrentIndex(0); break; case 74: sphereResolutionComboBox->setCurrentIndex(1); break; case 290: sphereResolutionComboBox->setCurrentIndex(2); break; case 1154: sphereResolutionComboBox->setCurrentIndex(3); break; case 4610: sphereResolutionComboBox->setCurrentIndex(4); break; case 18434: sphereResolutionComboBox->setCurrentIndex(5); break; case 73730: sphereResolutionComboBox->setCurrentIndex(6); break; default: sphereResolutionComboBox->setCurrentIndex(4); break; } this->sphereResolutionComboBox->blockSignals(false); } /** * called if sphere resolution is changed. */ void GuiSurfaceDeformationDialog::slotSphereResolutionChanged() { if (DebugControl::getDebugOn()) { std::cout << "Deformation Dialog Read: " << "Sphere Resolution" << std::endl; } int editStageNumber = sphereEditStageSpinBox->value() - 1; switch(sphereResolutionComboBox->currentIndex()) { case 0: dmf.setSphereResolution(editStageNumber, 20); break; case 1: dmf.setSphereResolution(editStageNumber, 74); break; case 2: dmf.setSphereResolution(editStageNumber, 290); break; case 3: dmf.setSphereResolution(editStageNumber, 1154); break; case 4: dmf.setSphereResolution(editStageNumber, 4610); break; case 5: dmf.setSphereResolution(editStageNumber, 18434); break; case 6: dmf.setSphereResolution(editStageNumber, 73730); break; default: dmf.setSphereResolution(editStageNumber, 4610); break; } } /** * create the Spherical parameters section. */ QWidget* GuiSurfaceDeformationDialog::createSphericalParametersSection() { // // Number of stages spin box and label // QLabel* sphereNumberOfStagesLabel = new QLabel("Number of Stages"); sphereNumberOfStagesSpinBox = new QSpinBox; sphereNumberOfStagesSpinBox->setMinimum(1); sphereNumberOfStagesSpinBox->setMaximum(DeformationMapFile::MAX_SPHERICAL_STAGES); sphereNumberOfStagesSpinBox->setSingleStep(1); QObject::connect(sphereNumberOfStagesSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotSphereNumberOfStagesSpinBox(int))); // // Edit Stages spin box and label // QLabel* sphereEditStagesLabel = new QLabel("Edit Stage"); sphereEditStageSpinBox = new QSpinBox; sphereEditStageSpinBox->setFixedSize(sphereEditStageSpinBox->sizeHint()); sphereEditStageSpinBox->setMinimum(1); sphereEditStageSpinBox->setMaximum(DeformationMapFile::MAX_SPHERICAL_CYCLES); QObject::connect(sphereEditStageSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotSphereEditStageSpinBox(int))); sphereStagesWidgetGroup = new WuQWidgetGroup(this); sphereStagesWidgetGroup->addWidget(sphereNumberOfStagesLabel); sphereStagesWidgetGroup->addWidget(sphereNumberOfStagesSpinBox); sphereStagesWidgetGroup->addWidget(sphereEditStagesLabel); sphereStagesWidgetGroup->addWidget(sphereEditStageSpinBox); // // Sphere resolution combo box and label and HBox // QLabel* sphereResolutionLabel = new QLabel("Sphere Resolution"); sphereResolutionComboBox = new QComboBox; QObject::connect(sphereResolutionComboBox, SIGNAL(activated(int)), this, SLOT(slotSphereResolutionChanged())); sphereResolutionComboBox->setFixedSize(sphereResolutionComboBox->sizeHint()); sphereResolutionComboBox->addItem(" 20 Nodes"); sphereResolutionComboBox->addItem(" 74 Nodes"); sphereResolutionComboBox->addItem(" 290 Nodes"); sphereResolutionComboBox->addItem(" 1154 Nodes"); sphereResolutionComboBox->addItem(" 4610 Nodes"); sphereResolutionComboBox->addItem("18434 Nodes"); sphereResolutionComboBox->addItem("73730 Nodes"); // // Number of Cycles spin box and label // QLabel* numberOfCyclesLabel = new QLabel("Number of Cycles"); sphereNumberOfCyclesSpinBox = new QSpinBox; sphereNumberOfCyclesSpinBox->setMinimum(1); sphereNumberOfCyclesSpinBox->setMaximum(DeformationMapFile::MAX_SPHERICAL_CYCLES); sphereNumberOfCyclesSpinBox->setSingleStep(1); QObject::connect(sphereNumberOfCyclesSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotSphereNumberOfCyclesSpinBox(int))); // // Edit Cycles spin box and label // QLabel* editCycleLabel = new QLabel("Edit Cycle"); sphereEditCycleSpinBox = new QSpinBox; sphereEditCycleSpinBox->setFixedSize(sphereEditCycleSpinBox->sizeHint()); sphereEditCycleSpinBox->setMinimum(1); sphereEditCycleSpinBox->setMaximum(DeformationMapFile::MAX_SPHERICAL_CYCLES); QObject::connect(sphereEditCycleSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotSphereEditCycleSpinBox(int))); // // Fiducial/sphere ratios // sphereDistortionCorrectionCheckBox = new QCheckBox("Correct For Spherical Distortion\n" "Relative to Fiducial"); QObject::connect(sphereDistortionCorrectionCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotCorrectSphericalDistortionChanged())); sphereDistortionDoubleSpinBox = new QDoubleSpinBox; QObject::connect(sphereDistortionDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(slotCorrectSphericalDistortionChanged())); sphereDistortionDoubleSpinBox->setMinimum(0.0); sphereDistortionDoubleSpinBox->setMaximum(1.0); sphereDistortionDoubleSpinBox->setSingleStep(0.5); sphereDistortionDoubleSpinBox->setDecimals(3); // // Group for spherical parameters // QGroupBox* sphericalParamsGroupBox = new QGroupBox("Spherical Parameters"); QGridLayout* sphericalParamsGroupLayout = new QGridLayout(sphericalParamsGroupBox); sphericalParamsGroupLayout->addWidget(sphereNumberOfStagesLabel, 0, 0); sphericalParamsGroupLayout->addWidget(sphereNumberOfStagesSpinBox, 0, 1); sphericalParamsGroupLayout->addWidget(sphereEditStagesLabel, 1, 0); sphericalParamsGroupLayout->addWidget(sphereEditStageSpinBox, 1, 1); sphericalParamsGroupLayout->addWidget(sphereResolutionLabel, 2, 0); sphericalParamsGroupLayout->addWidget(sphereResolutionComboBox, 2, 1); sphericalParamsGroupLayout->addWidget(numberOfCyclesLabel, 3, 0); sphericalParamsGroupLayout->addWidget(sphereNumberOfCyclesSpinBox, 3, 1); sphericalParamsGroupLayout->addWidget(editCycleLabel, 4, 0); sphericalParamsGroupLayout->addWidget(sphereEditCycleSpinBox, 4, 1); sphericalParamsGroupLayout->addWidget(sphereDistortionCorrectionCheckBox, 5, 0); sphericalParamsGroupLayout->addWidget(sphereDistortionDoubleSpinBox, 5, 1); sphericalParamsGroupBox->setMaximumHeight(sphericalParamsGroupBox->sizeHint().height()); return sphericalParamsGroupBox; } /** * update correct spherical distortion correction. */ void GuiSurfaceDeformationDialog::updateCorrectSphericalDistortion() { if (DebugControl::getDebugOn()) { std::cout << "Deformation Dialog Update: " << "Spherical Distortion Correction" << std::endl; } bool enabled = false; float ratio = 1.0; dmf.getSphereFiducialRatio(enabled, ratio); sphereDistortionCorrectionCheckBox->blockSignals(true); sphereDistortionCorrectionCheckBox->setChecked(enabled); sphereDistortionCorrectionCheckBox->blockSignals(false); sphereDistortionDoubleSpinBox->blockSignals(true); sphereDistortionDoubleSpinBox->setValue(ratio); sphereDistortionDoubleSpinBox->blockSignals(false); } /** * called when a correct for spherical distortion changed. */ void GuiSurfaceDeformationDialog::slotCorrectSphericalDistortionChanged() { if (DebugControl::getDebugOn()) { std::cout << "Deformation Dialog Read: " << "Spherical Distortion" << std::endl; } dmf.setSphereFiducialRatio(sphereDistortionCorrectionCheckBox->isChecked(), sphereDistortionDoubleSpinBox->value()); } /** * Create the spherical parameters section. */ QWidget* GuiSurfaceDeformationDialog::createSphericalParameters() { landmarkVectorOptionsWidget = createLandmarkVectorOptionsSection(); QWidget* sphericalAlgorithmWidget = createSphericalAlgorithmSection(); QVBoxLayout* leftColumnLayout = new QVBoxLayout; leftColumnLayout->addWidget(sphericalAlgorithmWidget); leftColumnLayout->addWidget(createSphericalParametersSection()); leftColumnLayout->addWidget(createSmoothingParametersSection()); //leftColumnLayout->addStretch(); QVBoxLayout* rightColumnLayout = new QVBoxLayout; rightColumnLayout->addWidget(landmarkVectorOptionsWidget); rightColumnLayout->addWidget(createMorphingParametersSection()); //rightColumnLayout->addStretch(); QWidget* sphereParamsPageWidget = new QWidget; QHBoxLayout* sphereParamsPageLayout = new QHBoxLayout(sphereParamsPageWidget); sphereParamsPageLayout->addLayout(leftColumnLayout); sphereParamsPageLayout->addLayout(rightColumnLayout); slotSphericalAlgorithmSelection(); return sphereParamsPageWidget; } /** * */ QWidget* GuiSurfaceDeformationDialog::createFlatParameters() { // // label and line edit // QLabel* flatSubSamplingLabel = new QLabel("Sub Sampling Tiles"); flatSubSamplingTilesSpinBox = new QSpinBox; flatSubSamplingTilesSpinBox->setMinimum(1); flatSubSamplingTilesSpinBox->setMaximum(50000); flatSubSamplingTilesSpinBox->setSingleStep(10); flatSubSamplingTilesSpinBox->setFixedWidth(150); QObject::connect(flatSubSamplingTilesSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotFlatParameterChanged())); // // label and line edit // QLabel* flatBetaLabel = new QLabel("Beta"); flatBetaDoubleSpinBox = new QDoubleSpinBox; flatBetaDoubleSpinBox->setFixedWidth(150); QObject::connect(flatBetaDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(slotFlatParameterChanged())); // // label and line edit // QLabel* flatVarMultLabel = new QLabel("Variance Multiplier"); flatVarMultDoubleSpinBox = new QDoubleSpinBox; flatVarMultDoubleSpinBox->setFixedWidth(150); QObject::connect(flatVarMultDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(slotFlatParameterChanged())); // // label and line edit // QLabel* flatIterationsLabel = new QLabel("Iterations"); flatIterationsSpinBox = new QSpinBox; flatIterationsSpinBox->setMinimum(0); flatIterationsSpinBox->setMaximum(50000); flatIterationsSpinBox->setSingleStep(5); flatIterationsSpinBox->setFixedWidth(150); QObject::connect(flatIterationsSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotFlatParameterChanged())); QGroupBox* flatParamsGroupBox = new QGroupBox("Parameters"); QGridLayout* flatParamsLayout = new QGridLayout(flatParamsGroupBox); flatParamsLayout->addWidget(flatSubSamplingLabel, 0, 0); flatParamsLayout->addWidget(flatSubSamplingTilesSpinBox, 0, 1); flatParamsLayout->addWidget(flatBetaLabel, 1, 0); flatParamsLayout->addWidget(flatBetaDoubleSpinBox, 1, 1); flatParamsLayout->addWidget(flatVarMultLabel, 2, 0); flatParamsLayout->addWidget(flatVarMultDoubleSpinBox, 2, 1); flatParamsLayout->addWidget(flatIterationsLabel, 3, 0); flatParamsLayout->addWidget(flatIterationsSpinBox, 3, 1); flatParamsGroupBox->setMaximumSize(flatParamsGroupBox->sizeHint()); return flatParamsGroupBox; } /** * Create a file entry line (pushbutton and line edit). */ FileEntryLine* GuiSurfaceDeformationDialog::createFileEntryLine(const QString& buttonLabel, const FILE_TYPES fileType, QGridLayout* parentGridLayout, QButtonGroup* buttonGroup, QPushButton* extraButton) { // // Create the push button // QPushButton* pb = new QPushButton(buttonLabel); pb->setAutoDefault(false); buttonGroup->addButton(pb, static_cast(fileType)); // // Create the line edit // const int lineEditWidth = 400; QLineEdit* le = new QLineEdit; le->setMinimumWidth(lineEditWidth); le->setReadOnly(true); const int rowNum = parentGridLayout->rowCount(); parentGridLayout->addWidget(pb, rowNum, 0, 1, 1); if (extraButton != NULL) { parentGridLayout->addWidget(extraButton, rowNum, 1, 1, 1); parentGridLayout->addWidget(le, rowNum, 2, 1, 1); } else { parentGridLayout->addWidget(le, rowNum, 1, 1, 2); } FileEntryLine* fel = new FileEntryLine(pb, le, extraButton); return fel; } /** * Allow user to select atlas files. */ void GuiSurfaceDeformationDialog::atlasFileSelection(int itemNum) { const FILE_TYPES ft = static_cast(itemNum); switch(ft) { case FILE_TYPE_SPEC: readSpecFile(SELECTION_TYPE_ATLAS); break; case FILE_TYPE_TOPO_CLOSED: displayFileSelection("Select Closed Topo File", atlasDeformationFiles.closedTopoFileNames, atlasDeformationFiles.closedTopoFileTypes, atlasDeformationFiles.closedTopoFileSelected); break; case FILE_TYPE_TOPO_CUT: displayFileSelection("Select Cut Topo File", atlasDeformationFiles.cutTopoFileNames, atlasDeformationFiles.cutTopoFileTypes, atlasDeformationFiles.cutTopoFileSelected); break; case FILE_TYPE_COORD_FIDUCIAL: displayFileSelection("Select Fiducial Coord File", atlasDeformationFiles.fiducialCoordFileNames, atlasDeformationFiles.fiducialCoordFileTypes, atlasDeformationFiles.fiducialCoordFileSelected); break; case FILE_TYPE_COORD_FLAT: displayFileSelection("Select Flat Coord File", atlasDeformationFiles.flatCoordFileNames, atlasDeformationFiles.flatCoordFileTypes, atlasDeformationFiles.flatCoordFileSelected); break; case FILE_TYPE_COORD_SPHERICAL: displayFileSelection("Select Spherical Coord File", atlasDeformationFiles.sphericalCoordFileNames, atlasDeformationFiles.sphericalCoordFileTypes, atlasDeformationFiles.sphericalCoordFileSelected); break; case FILE_TYPE_BORDER_1: displayFileSelection("Select Border File Stage 1", atlasDeformationFiles.borderFileNames, atlasDeformationFiles.borderFileTypes, atlasDeformationFiles.borderFileSelected[0]); break; case FILE_TYPE_BORDER_2: displayFileSelection("Select Border File Stage 2", atlasDeformationFiles.borderFileNames, atlasDeformationFiles.borderFileTypes, atlasDeformationFiles.borderFileSelected[1]); break; case FILE_TYPE_BORDER_3: displayFileSelection("Select Border File Stage 3", atlasDeformationFiles.borderFileNames, atlasDeformationFiles.borderFileTypes, atlasDeformationFiles.borderFileSelected[2]); break; case FILE_TYPE_BORDER_4: displayFileSelection("Select Border File Stage 4", atlasDeformationFiles.borderFileNames, atlasDeformationFiles.borderFileTypes, atlasDeformationFiles.borderFileSelected[3]); break; case FILE_TYPE_BORDER_5: displayFileSelection("Select Border File Stage 5", atlasDeformationFiles.borderFileNames, atlasDeformationFiles.borderFileTypes, atlasDeformationFiles.borderFileSelected[4]); break; case FILE_TYPE_BORDER_6: displayFileSelection("Select Border File Stage 6", atlasDeformationFiles.borderFileNames, atlasDeformationFiles.borderFileTypes, atlasDeformationFiles.borderFileSelected[5]); break; case FILE_TYPE_BORDER_7: displayFileSelection("Select Border File Stage 7", atlasDeformationFiles.borderFileNames, atlasDeformationFiles.borderFileTypes, atlasDeformationFiles.borderFileSelected[6]); break; case FILE_TYPE_BORDER_8: displayFileSelection("Select Border File Stage 8", atlasDeformationFiles.borderFileNames, atlasDeformationFiles.borderFileTypes, atlasDeformationFiles.borderFileSelected[7]); break; case FILE_TYPE_BORDER_9: displayFileSelection("Select Border File Stage 9", atlasDeformationFiles.borderFileNames, atlasDeformationFiles.borderFileTypes, atlasDeformationFiles.borderFileSelected[8]); break; case FILE_TYPE_BORDER_10: displayFileSelection("Select Border File Stage 10", atlasDeformationFiles.borderFileNames, atlasDeformationFiles.borderFileTypes, atlasDeformationFiles.borderFileSelected[9]); break; case FILE_TYPE_BORDER_11: displayFileSelection("Select Border File Stage 11", atlasDeformationFiles.borderFileNames, atlasDeformationFiles.borderFileTypes, atlasDeformationFiles.borderFileSelected[10]); break; case FILE_TYPE_BORDER_12: displayFileSelection("Select Border File Stage 12", atlasDeformationFiles.borderFileNames, atlasDeformationFiles.borderFileTypes, atlasDeformationFiles.borderFileSelected[11]); break; case FILE_TYPE_BORDER_13: displayFileSelection("Select Border File Stage 13", atlasDeformationFiles.borderFileNames, atlasDeformationFiles.borderFileTypes, atlasDeformationFiles.borderFileSelected[12]); break; case FILE_TYPE_BORDER_14: displayFileSelection("Select Border File Stage 14", atlasDeformationFiles.borderFileNames, atlasDeformationFiles.borderFileTypes, atlasDeformationFiles.borderFileSelected[13]); break; case FILE_TYPE_BORDER_15: displayFileSelection("Select Border File Stage 15", atlasDeformationFiles.borderFileNames, atlasDeformationFiles.borderFileTypes, atlasDeformationFiles.borderFileSelected[14]); break; case FILE_TYPE_BORDER_16: displayFileSelection("Select Border File Stage 16", atlasDeformationFiles.borderFileNames, atlasDeformationFiles.borderFileTypes, atlasDeformationFiles.borderFileSelected[15]); break; case FILE_TYPE_BORDER_17: displayFileSelection("Select Border File Stage 17", atlasDeformationFiles.borderFileNames, atlasDeformationFiles.borderFileTypes, atlasDeformationFiles.borderFileSelected[16]); break; case FILE_TYPE_BORDER_18: displayFileSelection("Select Border File Stage 18", atlasDeformationFiles.borderFileNames, atlasDeformationFiles.borderFileTypes, atlasDeformationFiles.borderFileSelected[17]); break; case FILE_TYPE_BORDER_19: displayFileSelection("Select Border File Stage 19", atlasDeformationFiles.borderFileNames, atlasDeformationFiles.borderFileTypes, atlasDeformationFiles.borderFileSelected[18]); break; case FILE_TYPE_BORDER_20: displayFileSelection("Select Border File Stage 20", atlasDeformationFiles.borderFileNames, atlasDeformationFiles.borderFileTypes, atlasDeformationFiles.borderFileSelected[19]); break; } displayAtlasFiles(); } /** * Select data files for deformation. */ void GuiSurfaceDeformationDialog::displayFileSelection(const QString& title, const std::vector& labelsIn, const std::vector fileTypes, int& selectedItem) { std::vector labels; for (int i = 0; i < static_cast(labelsIn.size()); i++) { QString name; switch(fileTypes[i]) { case DeformationDataFiles::DATA_FILE_BORDER_FLAT: name.append("FLAT - "); break; case DeformationDataFiles::DATA_FILE_BORDER_FLAT_LOBAR: name.append("FLAT LOBAR - "); break; case DeformationDataFiles::DATA_FILE_BORDER_SPHERICAL: name.append("SPHERICAL - "); break; case DeformationDataFiles::DATA_FILE_BORDER_PROJECTION: name.append("PROJECTION - "); break; case DeformationDataFiles::DATA_FILE_TOPO_CLOSED: name.append("CLOSED - "); break; case DeformationDataFiles::DATA_FILE_TOPO_CUT: name.append("CUT - "); break; case DeformationDataFiles::DATA_FILE_TOPO_CUT_LOBAR: name.append("CUT LOBAR - "); break; case DeformationDataFiles::DATA_FILE_COORD_FIDUCIAL: break; case DeformationDataFiles::DATA_FILE_COORD_FLAT: break; case DeformationDataFiles::DATA_FILE_COORD_FLAT_LOBAR: break; case DeformationDataFiles::DATA_FILE_COORD_SPHERICAL: break; } name.append(labelsIn[i]); labels.push_back(name); } QtRadioButtonSelectionDialog bsd(this, title, "", labels, selectedItem); if (bsd.exec() == QDialog::Accepted) { selectedItem = bsd.getSelectedItemIndex(); } } /** * Allow user to select indiv files. */ void GuiSurfaceDeformationDialog::indivFileSelection(int itemNum) { const FILE_TYPES ft = static_cast(itemNum); switch(ft) { case FILE_TYPE_SPEC: readSpecFile(SELECTION_TYPE_INDIV); break; case FILE_TYPE_BORDER_1: case FILE_TYPE_BORDER_2: case FILE_TYPE_BORDER_3: case FILE_TYPE_BORDER_4: case FILE_TYPE_BORDER_5: case FILE_TYPE_BORDER_6: case FILE_TYPE_BORDER_7: case FILE_TYPE_BORDER_8: case FILE_TYPE_BORDER_9: case FILE_TYPE_BORDER_10: case FILE_TYPE_BORDER_11: case FILE_TYPE_BORDER_12: case FILE_TYPE_BORDER_13: case FILE_TYPE_BORDER_14: case FILE_TYPE_BORDER_15: case FILE_TYPE_BORDER_16: case FILE_TYPE_BORDER_17: case FILE_TYPE_BORDER_18: case FILE_TYPE_BORDER_19: case FILE_TYPE_BORDER_20: displayFileSelection("Select Border File", indivDeformationFiles.borderFileNames, indivDeformationFiles.borderFileTypes, indivDeformationFiles.borderFileSelected[0]); break; case FILE_TYPE_TOPO_CLOSED: displayFileSelection("Select Closed Topo File", indivDeformationFiles.closedTopoFileNames, indivDeformationFiles.closedTopoFileTypes, indivDeformationFiles.closedTopoFileSelected); break; case FILE_TYPE_TOPO_CUT: displayFileSelection("Select Cut Topo File", indivDeformationFiles.cutTopoFileNames, indivDeformationFiles.cutTopoFileTypes, indivDeformationFiles.cutTopoFileSelected); break; case FILE_TYPE_COORD_FIDUCIAL: displayFileSelection("Select Fiducial Coord File", indivDeformationFiles.fiducialCoordFileNames, indivDeformationFiles.fiducialCoordFileTypes, indivDeformationFiles.fiducialCoordFileSelected); break; case FILE_TYPE_COORD_FLAT: displayFileSelection("Select Flat Coord File", indivDeformationFiles.flatCoordFileNames, indivDeformationFiles.flatCoordFileTypes, indivDeformationFiles.flatCoordFileSelected); break; case FILE_TYPE_COORD_SPHERICAL: displayFileSelection("Select Spherical Coord File", indivDeformationFiles.sphericalCoordFileNames, indivDeformationFiles.sphericalCoordFileTypes, indivDeformationFiles.sphericalCoordFileSelected); break; } displayIndivFiles(); } /** * Read an atlas or individual spec file */ void GuiSurfaceDeformationDialog::readSpecFile(const SELECTION_TYPE st) { // // Use choose spec file dialog // GuiChooseSpecFileDialog openSpec(this, theMainWindow->getBrainSet()->getPreferencesFile(), true); if (openSpec.exec() == QDialog::Accepted) { const QString sname(openSpec.getSelectedSpecFile()); // // Save the current directory since reading a spec file will change it // const QString currentDirectory = QDir::currentPath(); // // Read the spec file // SpecFile sf; try { sf.readFile(sname); } catch (FileException& e) { QMessageBox::critical(this, "Error Reading Spec", e.whatQString()); QDir::setCurrent(currentDirectory); return; } bool flatDeformFlag = false; switch(dmf.getFlatOrSphereSelection()) { case DeformationMapFile::DEFORMATION_TYPE_FLAT: flatDeformFlag = true; break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: flatDeformFlag = false; break; } switch(st) { case SELECTION_TYPE_ATLAS: atlasSpecFileName = sname; atlasDeformationFiles.loadSpecFile(sf, flatDeformFlag); displayAtlasFiles(); break; case SELECTION_TYPE_INDIV: indivSpecFileName = sname; indivDeformationFiles.loadSpecFile(sf, flatDeformFlag); displayIndivFiles(); break; } // // Restore the current directory after reading the spec file // QDir::setCurrent(currentDirectory); } } /** * Load the deformation map file. */ void GuiSurfaceDeformationDialog::loadDeformationMapFile(std::vector& errorMessages) { errorMessages.clear(); // // Set the source border file type // DeformationMapFile::BORDER_FILE_TYPE bft = DeformationMapFile::BORDER_FILE_UNKNOWN; if (indivDeformationFiles.borderFileSelected >= 0) { switch(indivDeformationFiles.borderFileTypes[indivDeformationFiles.borderFileSelected[0]]) { case DeformationDataFiles::DATA_FILE_BORDER_FLAT: bft = DeformationMapFile::BORDER_FILE_FLAT; break; case DeformationDataFiles::DATA_FILE_BORDER_FLAT_LOBAR: bft = DeformationMapFile::BORDER_FILE_FLAT_LOBAR; break; case DeformationDataFiles::DATA_FILE_BORDER_SPHERICAL: bft = DeformationMapFile::BORDER_FILE_SPHERICAL; break; case DeformationDataFiles::DATA_FILE_BORDER_PROJECTION: bft = DeformationMapFile::BORDER_FILE_PROJECTION; break; case DeformationDataFiles::DATA_FILE_TOPO_CLOSED: case DeformationDataFiles::DATA_FILE_TOPO_CUT: case DeformationDataFiles::DATA_FILE_TOPO_CUT_LOBAR: case DeformationDataFiles::DATA_FILE_COORD_FIDUCIAL: case DeformationDataFiles::DATA_FILE_COORD_FLAT: case DeformationDataFiles::DATA_FILE_COORD_FLAT_LOBAR: case DeformationDataFiles::DATA_FILE_COORD_SPHERICAL: break; } } // // Set the source file names // dmf.setSourceSpecFileName(indivSpecLineEdit->text()); const QString sourceBorderName(indivBorderLineEdit->text()); dmf.setSourceBorderFileName(sourceBorderName, bft); dmf.setSourceClosedTopoFileName(indivClosedTopoLineEdit->text()); dmf.setSourceCutTopoFileName(indivCutTopoLineEdit->text()); dmf.setSourceFiducialCoordFileName(indivFiducialCoordLineEdit->text()); dmf.setSourceSphericalCoordFileName(indivSphericalCoordLineEdit->text()); dmf.setSourceFlatCoordFileName(indivFlatCoordLineEdit->text()); // // Check to see that required individual files are provided // if (dmf.getSourceSpecFileName().isEmpty()) { errorMessages.push_back("Required individual spec file is missing."); } if (sourceBorderName.isEmpty()) { errorMessages.push_back("Required individual border file is missing."); } if (dmf.getSourceClosedTopoFileName().isEmpty()) { errorMessages.push_back("Required individual closed topo file is missing."); } if (dmf.getSourceCutTopoFileName().isEmpty()) { errorMessages.push_back("Required individual cut topo file is missing."); } if (dmf.getSourceFiducialCoordFileName().isEmpty()) { errorMessages.push_back("Required individual fiducial coord file is missing."); } switch(dmf.getFlatOrSphereSelection()) { case DeformationMapFile::DEFORMATION_TYPE_FLAT: if (dmf.getSourceFlatCoordFileName().isEmpty()) { errorMessages.push_back("Required individual flat coord file is missing."); } break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: if (dmf.getSourceSphericalCoordFileName().isEmpty()) { errorMessages.push_back("Required individual source spherical coord file is missing."); } break; } // // Set the target border file type // bft = DeformationMapFile::BORDER_FILE_UNKNOWN; if (atlasDeformationFiles.borderFileSelected[0] >= 0) { switch(atlasDeformationFiles.borderFileTypes[atlasDeformationFiles.borderFileSelected[0]]) { case DeformationDataFiles::DATA_FILE_BORDER_FLAT: bft = DeformationMapFile::BORDER_FILE_FLAT; break; case DeformationDataFiles::DATA_FILE_BORDER_FLAT_LOBAR: bft = DeformationMapFile::BORDER_FILE_FLAT_LOBAR; break; case DeformationDataFiles::DATA_FILE_BORDER_SPHERICAL: bft = DeformationMapFile::BORDER_FILE_SPHERICAL; break; case DeformationDataFiles::DATA_FILE_BORDER_PROJECTION: bft = DeformationMapFile::BORDER_FILE_PROJECTION; break; case DeformationDataFiles::DATA_FILE_TOPO_CLOSED: case DeformationDataFiles::DATA_FILE_TOPO_CUT: case DeformationDataFiles::DATA_FILE_TOPO_CUT_LOBAR: case DeformationDataFiles::DATA_FILE_COORD_FIDUCIAL: case DeformationDataFiles::DATA_FILE_COORD_FLAT: case DeformationDataFiles::DATA_FILE_COORD_FLAT_LOBAR: case DeformationDataFiles::DATA_FILE_COORD_SPHERICAL: break; } } // // Set the target file names // dmf.setTargetSpecFileName(atlasSpecLineEdit->text()); for (int i = 0; i < DeformationMapFile::MAX_SPHERICAL_STAGES; i++) { const QString targetBorderName(atlasBorderLineEdit[i]->text()); dmf.setTargetBorderFileName(i, targetBorderName, bft); if (i < dmf.getSphericalNumberOfStages()) { if (targetBorderName.isEmpty()) { errorMessages.push_back( "Required atlas border file " + QString::number(i + 1) + " is missing."); } } } dmf.setTargetClosedTopoFileName(atlasClosedTopoLineEdit->text()); dmf.setTargetCutTopoFileName(atlasCutTopoLineEdit->text()); dmf.setTargetFiducialCoordFileName(atlasFiducialCoordLineEdit->text()); dmf.setTargetSphericalCoordFileName(atlasSphericalCoordLineEdit->text()); dmf.setTargetFlatCoordFileName(atlasFlatCoordLineEdit->text()); // // Check to see that required atlas files are provided // if (dmf.getTargetSpecFileName().isEmpty()) { errorMessages.push_back("Required atlas spec file is missing."); } if (dmf.getTargetClosedTopoFileName().isEmpty()) { errorMessages.push_back("Required atlas closed topo file is missing."); } if (dmf.getTargetCutTopoFileName().isEmpty()) { errorMessages.push_back("Required atlas cut topo file is missing."); } if (dmf.getTargetFiducialCoordFileName().isEmpty()) { errorMessages.push_back("Required atlas fiducial coord file is missing."); } switch(dmf.getFlatOrSphereSelection()) { case DeformationMapFile::DEFORMATION_TYPE_FLAT: if (dmf.getTargetFlatCoordFileName().isEmpty()) { errorMessages.push_back("Required atlas flat coord file is missing."); } break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: if (dmf.getTargetSphericalCoordFileName().isEmpty()) { errorMessages.push_back("Required individual atlas spherical coord file is missing."); } break; } } /** * called when apply button pressed. */ void GuiSurfaceDeformationDialog::slotApplyButton() { std::vector errorMessages; // // Copy parameters to the deformation map file. // loadDeformationMapFile(errorMessages); // // Are any required files missing ? // if (errorMessages.size() > 0) { const QString msg = StringUtilities::combine(errorMessages, "\n"); QMessageBox::critical(this, "Files Missing", msg); return; } switch(dmf.getFlatOrSphereSelection()) { case DeformationMapFile::DEFORMATION_TYPE_FLAT: break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: if ((this->sphericalLandmarkConstrainedRadioButton->isChecked() == false) && (this->sphericalLandmarkVectorRadioButton->isChecked() == false) && (this->sphericalLandmarkVectorSingleStageRadioButton->isChecked() == false)) { QApplication::processEvents(); QMessageBox::critical(this, "Algorithm Selection", "You must choose the spherical algorithm (landmark " "constrained or landmark vector difference) on the " "Spherical Parameters page."); return; } break; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); DisplaySettingsSurface* dss = theMainWindow->getBrainSet()->getDisplaySettingsSurface(); QString completeMessage("The deformation has completed."); try { switch(dmf.getFlatOrSphereSelection()) { case DeformationMapFile::DEFORMATION_TYPE_FLAT: { BrainModelSurfaceDeformationFlat bmsdf(theMainWindow->getBrainSet(), &dmf); bmsdf.setDeformationMapFileNames( this->indivToAtlasDeformMapFileNameLineEdit->text(), this->atlasToIndivDeformMapFileNameLineEdit->text()); bmsdf.execute(); // // Check for deformation errors // const QString s2tMsg(bmsdf.getSourceToTargetDeformDataFileErrors()); if (s2tMsg.isEmpty() == false) { completeMessage.append("\nErrors were detected deforming the following data files from\n " "the individual to the atlas:\n"); completeMessage.append(s2tMsg); } const QString t2sMsg(bmsdf.getTargetToSourceDeformDataFileErrors()); if (t2sMsg.isEmpty() == false) { completeMessage.append("\nErrors were detected deforming the following data files from\n " "the atlas to the individual:\n"); completeMessage.append(t2sMsg); } } break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE: { dss->setDrawMode(DisplaySettingsSurface::DRAW_MODE_LINK_HIDDEN_LINE_REMOVAL); BrainModelSurfaceDeformationSpherical bmsds(theMainWindow->getBrainSet(), &dmf); bmsds.setDeformationMapFileNames( this->indivToAtlasDeformMapFileNameLineEdit->text(), this->atlasToIndivDeformMapFileNameLineEdit->text()); // // Enable coord file deformation for sphere // bmsds.setDeformSourceFiducialCoordFiles(deformIndivFiducialCoordCheckBox->isChecked()); bmsds.setDeformSourceInflatedCoordFiles(deformIndivInflatedCoordCheckBox->isChecked()); bmsds.setDeformSourceVeryInflatedCoordFiles(deformIndivVeryInflatedCoordCheckBox->isChecked()); bmsds.setDeformSourceSphericalCoordFiles(deformIndivSphericalCoordCheckBox->isChecked()); bmsds.setDeformSourceFlatCoordFiles(deformIndivFlatCoordCheckBox->isChecked()); // // Main Window Surface is used for Viewing Transformations // bmsds.setsurfaceWithViewingTransformations(theMainWindow->getBrainModelSurface()); bmsds.execute(); // // Check for deformation errors // const QString s2tMsg(bmsds.getSourceToTargetDeformDataFileErrors()); if (s2tMsg.isEmpty() == false) { completeMessage.append("\nErrors were detected deforming the following data files from\n " "the individual to the atlas:\n"); completeMessage.append(s2tMsg); } const QString t2sMsg(bmsds.getTargetToSourceDeformDataFileErrors()); if (t2sMsg.isEmpty() == false) { completeMessage.append("\nErrors were detected deforming the following data files from\n " "the atlas to the individual:\n"); completeMessage.append(t2sMsg); } } break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: { dss->setDrawMode(DisplaySettingsSurface::DRAW_MODE_LINK_HIDDEN_LINE_REMOVAL); BrainModelSurfaceDeformationMultiStageSphericalVector bmsdsv(theMainWindow->getBrainSet(), &dmf); bmsdsv.setDeformationMapFileNames( this->indivToAtlasDeformMapFileNameLineEdit->text(), this->atlasToIndivDeformMapFileNameLineEdit->text()); // // Enable coord file deformation for sphere // bmsdsv.setDeformSourceFiducialCoordFiles(deformIndivFiducialCoordCheckBox->isChecked()); bmsdsv.setDeformSourceInflatedCoordFiles(deformIndivInflatedCoordCheckBox->isChecked()); bmsdsv.setDeformSourceVeryInflatedCoordFiles(deformIndivVeryInflatedCoordCheckBox->isChecked()); bmsdsv.setDeformSourceSphericalCoordFiles(deformIndivSphericalCoordCheckBox->isChecked()); bmsdsv.setDeformSourceFlatCoordFiles(deformIndivFlatCoordCheckBox->isChecked()); // // Main Window Surface is used for Viewing Transformations // bmsdsv.setsurfaceWithViewingTransformations(theMainWindow->getBrainModelSurface()); bmsdsv.execute(); // // Check for deformation errors // const QString s2tMsg(bmsdsv.getSourceToTargetDeformDataFileErrors()); if (s2tMsg.isEmpty() == false) { completeMessage.append("\nErrors were detected deforming the following data files from\n " "the individual to the atlas:\n"); completeMessage.append(s2tMsg); } } break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: { dss->setDrawMode(DisplaySettingsSurface::DRAW_MODE_LINK_HIDDEN_LINE_REMOVAL); BrainModelSurfaceDeformationSphericalVector bmsdsv(theMainWindow->getBrainSet(), &dmf); bmsdsv.setDeformationMapFileNames( this->indivToAtlasDeformMapFileNameLineEdit->text(), this->atlasToIndivDeformMapFileNameLineEdit->text()); // // Enable coord file deformation for sphere // bmsdsv.setDeformSourceFiducialCoordFiles(deformIndivFiducialCoordCheckBox->isChecked()); bmsdsv.setDeformSourceInflatedCoordFiles(deformIndivInflatedCoordCheckBox->isChecked()); bmsdsv.setDeformSourceVeryInflatedCoordFiles(deformIndivVeryInflatedCoordCheckBox->isChecked()); bmsdsv.setDeformSourceSphericalCoordFiles(deformIndivSphericalCoordCheckBox->isChecked()); bmsdsv.setDeformSourceFlatCoordFiles(deformIndivFlatCoordCheckBox->isChecked()); // // Main Window Surface is used for Viewing Transformations // bmsdsv.setsurfaceWithViewingTransformations(theMainWindow->getBrainModelSurface()); bmsdsv.execute(); // // Check for deformation errors // const QString s2tMsg(bmsdsv.getSourceToTargetDeformDataFileErrors()); if (s2tMsg.isEmpty() == false) { completeMessage.append("\nErrors were detected deforming the following data files from\n " "the individual to the atlas:\n"); completeMessage.append(s2tMsg); } } break; } } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "Deformation Error", e.whatQString()); return; } // // Let the user know that the deformation has completed // QApplication::restoreOverrideCursor(); QMessageBox::information(this, "Deformation Completed", completeMessage); } /** * Display the atlas data files. */ void GuiSurfaceDeformationDialog::displayAtlasFiles() { atlasSpecLineEdit->setText(atlasSpecFileName); if (atlasDeformationFiles.borderFileNames.size() > 0) { for (int i = 0; i < DeformationMapFile::MAX_SPHERICAL_STAGES; i++) { atlasBorderLineEdit[i]->setText( atlasDeformationFiles.borderFileNames[atlasDeformationFiles.borderFileSelected[i]]); } } else { for (int i = 0; i < DeformationMapFile::MAX_SPHERICAL_STAGES; i++) { atlasBorderLineEdit[i]->setText(""); } } if (atlasDeformationFiles.closedTopoFileNames.size() > 0) { atlasClosedTopoLineEdit->setText( atlasDeformationFiles.closedTopoFileNames[atlasDeformationFiles.closedTopoFileSelected]); } else { atlasClosedTopoLineEdit->setText(""); } if (atlasDeformationFiles.cutTopoFileNames.size() > 0) { atlasCutTopoLineEdit->setText( atlasDeformationFiles.cutTopoFileNames[atlasDeformationFiles.cutTopoFileSelected]); } else { atlasCutTopoLineEdit->setText(""); } if (atlasDeformationFiles.fiducialCoordFileNames.size() > 0) { atlasFiducialCoordLineEdit->setText( atlasDeformationFiles.fiducialCoordFileNames[atlasDeformationFiles.fiducialCoordFileSelected]); } else { atlasFiducialCoordLineEdit->setText(""); } if (atlasDeformationFiles.sphericalCoordFileNames.size() > 0) { atlasSphericalCoordLineEdit->setText( atlasDeformationFiles.sphericalCoordFileNames[atlasDeformationFiles.sphericalCoordFileSelected]); } else { atlasSphericalCoordLineEdit->setText(""); } if (atlasDeformationFiles.flatCoordFileNames.size() > 0) { atlasFlatCoordLineEdit->setText( atlasDeformationFiles.flatCoordFileNames[atlasDeformationFiles.flatCoordFileSelected]); } else { atlasFlatCoordLineEdit->setText(""); } } /** * Display the indiv data files. */ void GuiSurfaceDeformationDialog::displayIndivFiles() { indivSpecLineEdit->setText(indivSpecFileName); if (indivDeformationFiles.borderFileNames.size() > 0) { indivBorderLineEdit->setText( indivDeformationFiles.borderFileNames[indivDeformationFiles.borderFileSelected[0]]); } else { indivBorderLineEdit->setText(""); } if (indivDeformationFiles.closedTopoFileNames.size() > 0) { indivClosedTopoLineEdit->setText( indivDeformationFiles.closedTopoFileNames[indivDeformationFiles.closedTopoFileSelected]); } else { indivClosedTopoLineEdit->setText(""); } if (indivDeformationFiles.cutTopoFileNames.size() > 0) { indivCutTopoLineEdit->setText( indivDeformationFiles.cutTopoFileNames[indivDeformationFiles.cutTopoFileSelected]); } else { indivCutTopoLineEdit->setText(""); } if (indivDeformationFiles.fiducialCoordFileNames.size() > 0) { indivFiducialCoordLineEdit->setText( indivDeformationFiles.fiducialCoordFileNames[indivDeformationFiles.fiducialCoordFileSelected]); } else { indivFiducialCoordLineEdit->setText(""); } if (indivDeformationFiles.sphericalCoordFileNames.size() > 0) { indivSphericalCoordLineEdit->setText( indivDeformationFiles.sphericalCoordFileNames[indivDeformationFiles.sphericalCoordFileSelected]); } else { indivSphericalCoordLineEdit->setText(""); } if (indivDeformationFiles.flatCoordFileNames.size() > 0) { indivFlatCoordLineEdit->setText( indivDeformationFiles.flatCoordFileNames[indivDeformationFiles.flatCoordFileSelected]); } else { indivFlatCoordLineEdit->setText(""); } } /** * Called when standard parameters pushbutton pressed. */ void GuiSurfaceDeformationDialog::slotStandardParametersPushButton() { QString subDirName; switch (dmf.getFlatOrSphereSelection()) { case DeformationMapFile::DEFORMATION_TYPE_SPHERE: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: subDirName = "/data_files/spherical_registration"; break; case DeformationMapFile::DEFORMATION_TYPE_FLAT: subDirName = "/data_files/flat_registration"; break; } if (subDirName.isEmpty()) { return; } QString templateDirectory(theMainWindow->getBrainSet()->getCaretHomeDirectory()); templateDirectory.append(subDirName); std::vector files; FileUtilities::findFilesInDirectory(templateDirectory, QStringList("*.deform_map"), files); if (files.empty()) { QString msg("No standard deformation map files were found in the directory\n"); msg.append(templateDirectory); QMessageBox::critical(this, "Files Not Found", msg); return; } std::vector templateFiles; std::vector labels; for (unsigned int i = 0; i < files.size(); i++) { DeformationMapFile df; try { QString name(templateDirectory); name.append("/"); name.append(files[i]); df.readFile(name); const QString descriptiveName(df.getHeaderTag("descriptive_name")); if (descriptiveName.isEmpty() == false) { labels.push_back(descriptiveName); } else { labels.push_back(files[i]); } templateFiles.push_back(name); } catch (FileException& /*e*/) { } } QtRadioButtonSelectionDialog rbd(this, "Choose Registration Parameters", "", labels, -1); if (rbd.exec() == QDialog::Accepted) { try { const int fileNum = rbd.getSelectedItemIndex(); dmf.clear(); dmf.readFile(templateFiles[fileNum]); loadParametersIntoDialog(); } catch (FileException& e) { QMessageBox::critical(this, "Open Error", e.whatQString()); return; } } } /** * called when save deformation map file push button is pressed. */ void GuiSurfaceDeformationDialog::saveDeformationMapFilePushButton() { // // Create a spec file dialog to select the spec file. // WuQFileDialog saveDefMap(this); saveDefMap.setModal(true); saveDefMap.setWindowTitle("Choose Deformation Map File"); saveDefMap.setFileMode(WuQFileDialog::AnyFile); saveDefMap.setAcceptMode(WuQFileDialog::AcceptSave); saveDefMap.setHistory(theMainWindow->getBrainSet()->getPreferencesFile()->getRecentDataFileDirectories()); saveDefMap.setDirectory(QDir::currentPath()); QString filterString("DeformationMapFile (*"); filterString.append(SpecFile::getDeformationMapFileExtension()); filterString.append(")"); saveDefMap.setFilters(QStringList(filterString)); if (saveDefMap.exec() == QDialog::Accepted) { try { if (saveDefMap.selectedFiles().count() > 0) { dmf.writeFile(saveDefMap.selectedFiles().at(0)); } } catch (FileException& e) { QMessageBox::critical(this, "Save Error", e.whatQString()); return; } } } /** * Called to load a deformation map file. */ void GuiSurfaceDeformationDialog::loadDeformationMapFilePushButton() { // // Create a spec file dialog to select the spec file. // WuQFileDialog openDefMap(this); openDefMap.setModal(true); openDefMap.setWindowTitle("Choose Deformation Map File"); openDefMap.setFileMode(WuQFileDialog::ExistingFile); openDefMap.setAcceptMode(WuQFileDialog::AcceptOpen); openDefMap.setHistory(theMainWindow->getBrainSet()->getPreferencesFile()->getRecentDataFileDirectories()); openDefMap.setDirectory(QDir::currentPath()); QString filterString("DeformationMapFile (*"); filterString.append(SpecFile::getDeformationMapFileExtension()); filterString.append(")"); openDefMap.setFilters(QStringList(filterString)); if (openDefMap.exec() == QDialog::Accepted) { try { dmf.clear(); if (openDefMap.selectedFiles().count() > 0) { dmf.readFile(openDefMap.selectedFiles().at(0)); loadParametersIntoDialog(); } } catch (FileException& e) { QMessageBox::critical(this, "Open Error", e.whatQString()); return; } } } /** * called to read the flat parameters from the dialog. */ void GuiSurfaceDeformationDialog::slotFlatParameterChanged() { if (DebugControl::getDebugOn()) { std::cout << "Deformation Dialog Read: " << "Flat Parameter" << std::endl; } dmf.setFlatParameters(flatSubSamplingTilesSpinBox->value(), flatBetaDoubleSpinBox->value(), flatVarMultDoubleSpinBox->value(), flatIterationsSpinBox->value()); } /** * update the flat parameters */ void GuiSurfaceDeformationDialog::updateFlatParameters() { if (DebugControl::getDebugOn()) { std::cout << "Deformation Dialog Update: " << "Flat Parameters" << std::endl; } int subSamplingTiles, numIters; float beta, varMult; dmf.getFlatParameters(subSamplingTiles, beta, varMult, numIters); flatSubSamplingTilesSpinBox->blockSignals(true); flatSubSamplingTilesSpinBox->setValue(subSamplingTiles); flatSubSamplingTilesSpinBox->blockSignals(false); flatBetaDoubleSpinBox->blockSignals(true); flatBetaDoubleSpinBox->setValue(beta); flatBetaDoubleSpinBox->blockSignals(false); flatVarMultDoubleSpinBox->blockSignals(true); flatVarMultDoubleSpinBox->setValue(varMult); flatVarMultDoubleSpinBox->blockSignals(false); flatIterationsSpinBox->blockSignals(true); flatIterationsSpinBox->setValue(numIters); flatIterationsSpinBox->blockSignals(false); } /** * called to read the deformation parameters from the dialog. */ void GuiSurfaceDeformationDialog::slotDeformationParameterChanged() { if (DebugControl::getDebugOn()) { std::cout << "Deformation Dialog Read: " << "Deformation Parameter" << std::endl; } // // set border resampling // DeformationMapFile::BORDER_RESAMPLING_TYPE borderResample = DeformationMapFile::BORDER_RESAMPLING_NONE; if (borderResamplingNoneRadioButton->isChecked()) { borderResample = DeformationMapFile::BORDER_RESAMPLING_NONE; } else if (borderResamplingFromFileRadioButton->isChecked()) { borderResample = DeformationMapFile::BORDER_RESAMPLING_FROM_BORDER_FILE; } else if (borderResamplingToValueRadioButton->isChecked()) { borderResample = DeformationMapFile::BORDER_RESAMPLING_VALUE; } dmf.setBorderResampling(borderResample, borderResamplingDoubleSpinBox->value()); // // set metric deformation // if (metricNearestNodeRadioButton->isChecked()) { dmf.setMetricDeformationType(DeformationMapFile::METRIC_DEFORM_NEAREST_NODE); } else if (metricAverageTileNodesRadioButton->isChecked()) { dmf.setMetricDeformationType(DeformationMapFile::METRIC_DEFORM_AVERAGE_TILE_NODES); } // // set deformation stuff // dmf.setDeformedFileNamePrefix(deformedFilePrefixLineEdit->text()); dmf.setDeformedColumnNamePrefix(deformedColumnPrefixLineEdit->text()); dmf.setDeformBothWays(deformBothWaysCheckBox->isChecked()); dmf.setDeleteIntermediateFiles(deleteIntermediateFilesCheckBox->isChecked()); dmf.setSmoothDeformedSurfacesFlag(smoothCoordsOneIterationCheckBox->isChecked()); } /** * update the deformation parameters. */ void GuiSurfaceDeformationDialog::updateDeformationParametersPage() { if (DebugControl::getDebugOn()) { std::cout << "Deformation Dialog Update: " << "Deformation Parameters" << std::endl; } // // set border resampling // DeformationMapFile::BORDER_RESAMPLING_TYPE borderResample; float resampleValue; dmf.getBorderResampling(borderResample, resampleValue); borderResamplingNoneRadioButton->blockSignals(true); borderResamplingFromFileRadioButton->blockSignals(true); borderResamplingToValueRadioButton->blockSignals(false); switch(borderResample) { case DeformationMapFile::BORDER_RESAMPLING_NONE: borderResamplingNoneRadioButton->setChecked(true); break; case DeformationMapFile::BORDER_RESAMPLING_FROM_BORDER_FILE: borderResamplingFromFileRadioButton->setChecked(true); break; case DeformationMapFile::BORDER_RESAMPLING_VALUE: borderResamplingToValueRadioButton->setChecked(true); break; } borderResamplingNoneRadioButton->blockSignals(false); borderResamplingFromFileRadioButton->blockSignals(false); borderResamplingToValueRadioButton->blockSignals(false); borderResamplingDoubleSpinBox->blockSignals(true); borderResamplingDoubleSpinBox->setValue(resampleValue); borderResamplingDoubleSpinBox->blockSignals(false); // // set metric deformation // metricNearestNodeRadioButton->blockSignals(true); metricAverageTileNodesRadioButton->blockSignals(true); switch(dmf.getMetricDeformationType()) { case DeformationMapFile::METRIC_DEFORM_NEAREST_NODE: metricNearestNodeRadioButton->setChecked(true); break; case DeformationMapFile::METRIC_DEFORM_AVERAGE_TILE_NODES: metricAverageTileNodesRadioButton->setChecked(true); break; } metricNearestNodeRadioButton->blockSignals(false); metricAverageTileNodesRadioButton->blockSignals(false); // // set deformation stuff // deformedFilePrefixLineEdit->blockSignals(true); deformedFilePrefixLineEdit->setText(dmf.getDeformedFileNamePrefix()); deformedFilePrefixLineEdit->blockSignals(false); deformedColumnPrefixLineEdit->blockSignals(true); deformedColumnPrefixLineEdit->setText(dmf.getDeformedColumnNamePrefix()); deformedColumnPrefixLineEdit->blockSignals(false); deformBothWaysCheckBox->blockSignals(true); deformBothWaysCheckBox->setChecked(dmf.getDeformBothWays()); deformBothWaysCheckBox->blockSignals(false); deleteIntermediateFilesCheckBox->blockSignals(true); deleteIntermediateFilesCheckBox->setChecked(dmf.getDeleteIntermediateFiles()); deleteIntermediateFilesCheckBox->blockSignals(false); smoothCoordsOneIterationCheckBox->blockSignals(true); smoothCoordsOneIterationCheckBox->setChecked(dmf.getSmoothDeformedSurfacesFlag()); smoothCoordsOneIterationCheckBox->blockSignals(false); } /** * Load the parameters from a deformation map file. */ void GuiSurfaceDeformationDialog::loadParametersIntoDialog() { switch(dmf.getFlatOrSphereSelection()) { case DeformationMapFile::DEFORMATION_TYPE_FLAT: updateFlatParameters(); break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: updateAlgorithmSelection(); sphereNumberOfStagesSpinBox->blockSignals(true); sphereNumberOfStagesSpinBox->setValue(dmf.getSphericalNumberOfStages()); sphereNumberOfStagesSpinBox->blockSignals(false); sphereEditStageSpinBox->blockSignals(true); sphereEditStageSpinBox->setValue(1); sphereEditStageSpinBox->blockSignals(false); slotSphereNumberOfStagesSpinBox(sphereNumberOfStagesSpinBox->value()); updateCorrectSphericalDistortion(); slotSphericalAlgorithmSelection(); updateAtlasBorderSelections(); slotUpdateDeformationMapFileNames(); break; } updateDeformationParametersPage(); } /** * update the spherical number of stages spin box. */ void GuiSurfaceDeformationDialog::updateSphereNumberOfStagesSpinBox() { if (DebugControl::getDebugOn()) { std::cout << "Deformation Dialog Update: " << "Number of Stages" << std::endl; } sphereNumberOfStagesSpinBox->blockSignals(true); sphereNumberOfStagesSpinBox->setValue(dmf.getSphericalNumberOfStages()); updateSphereEditStageSpinBox(); sphereNumberOfStagesSpinBox->blockSignals(false); updateAtlasBorderSelections(); } /** * called when number of spherical stages is changed. */ void GuiSurfaceDeformationDialog::slotSphereNumberOfStagesSpinBox(int item) { if (DebugControl::getDebugOn()) { std::cout << "Deformation Dialog Read: " << "Number of Stages" << std::endl; } dmf.setSphericalNumberOfStages(item); updateSphereEditStageSpinBox(); this->updateSphericalResolutionComboBox(); this->updateLandmarkVectorParameters(); this->updateMorphingParameters(); this->updateSmoothingParameters(); this->updateAtlasBorderSelections(); } /** * update the sphere edit stage spin box. */ void GuiSurfaceDeformationDialog::updateSphereEditStageSpinBox() { if (DebugControl::getDebugOn()) { std::cout << "Deformation Dialog Update: " << "Edit Stage" << std::endl; } sphereEditStageSpinBox->blockSignals(true); sphereEditStageSpinBox->setMaximum( dmf.getSphericalNumberOfStages()); sphereEditStageSpinBox->blockSignals(false); updateSphereNumberOfCyclesSpinBox(); } /** * called when sphere edit stage is changed. */ void GuiSurfaceDeformationDialog::slotSphereEditStageSpinBox(int /*value*/) { if (DebugControl::getDebugOn()) { std::cout << "Deformation Dialog Read: " << "Edit Stage" << std::endl; } updateSphereNumberOfCyclesSpinBox(); this->updateSphericalResolutionComboBox(); this->updateLandmarkVectorParameters(); this->updateMorphingParameters(); this->updateSmoothingParameters(); } /** * update the sphere number of cycles spin box. */ void GuiSurfaceDeformationDialog::updateSphereNumberOfCyclesSpinBox() { if (DebugControl::getDebugOn()) { std::cout << "Deformation Dialog Update: " << "Sphere Number of Cycles" << std::endl; } sphereNumberOfCyclesSpinBox->blockSignals(true); int stageIndex = sphereEditStageSpinBox->value() - 1; sphereNumberOfCyclesSpinBox->setValue( dmf.getSphericalNumberOfCycles(stageIndex)); sphereNumberOfCyclesSpinBox->blockSignals(false); updateSphereEditCycleSpinBox(); } /** * called when number of spherical cycles is changed. */ void GuiSurfaceDeformationDialog::slotSphereNumberOfCyclesSpinBox(int item) { if (DebugControl::getDebugOn()) { std::cout << "Deformation Dialog Read: " << "Number of Cycles" << std::endl; } const int stageIndex = sphereEditStageSpinBox->value() - 1; dmf.setSphericalNumberOfCycles(stageIndex, item); updateSphereEditCycleSpinBox(); this->updateLandmarkVectorParameters(); this->updateMorphingParameters(); this->updateSmoothingParameters(); } /** * update the edit cycle spin box. This in turn updates the landmark * vector, morphing, and smoothing parameters for the current stage * and cycle. */ void GuiSurfaceDeformationDialog::updateSphereEditCycleSpinBox() { if (DebugControl::getDebugOn()) { std::cout << "Deformation Dialog Update: " << "Edit Cycle" << std::endl; } this->sphereEditCycleSpinBox->blockSignals(true); const int stageIndex = sphereEditStageSpinBox->value() - 1; this->sphereEditCycleSpinBox->setMaximum( dmf.getSphericalNumberOfCycles(stageIndex)); this->sphereEditCycleSpinBox->blockSignals(false); } /** * called when sphere edit cycle is changed. */ void GuiSurfaceDeformationDialog::slotSphereEditCycleSpinBox(int /*value*/) { if (DebugControl::getDebugOn()) { std::cout << "Deformation Dialog Read: " << "Sphere Edit Cycle" << std::endl; } this->updateLandmarkVectorParameters(); this->updateMorphingParameters(); this->updateSmoothingParameters(); } //---------------------------------------------------------------------------------------------- /** * Constructor. */ DeformationDataFiles::DeformationDataFiles() { for (int i = 0; i < DeformationMapFile::MAX_SPHERICAL_STAGES; i++) { borderFileSelected[i] = -1; } closedTopoFileSelected = -1; cutTopoFileSelected = -1; fiducialCoordFileSelected = -1; flatCoordFileSelected = -1; sphericalCoordFileSelected = -1; } /** * Destructor. */ DeformationDataFiles::~DeformationDataFiles() { } /** * Load data file info from a spec file. */ void DeformationDataFiles::loadSpecFile(const SpecFile& sf, const bool flatDeformFlag) { // // landmark border files // borderFileNames.clear(); borderFileTypes.clear(); for (int i = 0; i < DeformationMapFile::MAX_SPHERICAL_STAGES; i++) { borderFileSelected[i] = -1; } for (int i = 0; i < sf.sphericalBorderFile.getNumberOfFiles(); i++) { borderFileNames.push_back(sf.sphericalBorderFile.files[i].filename); borderFileTypes.push_back(DATA_FILE_BORDER_SPHERICAL); if (flatDeformFlag == false) { for (int j = 0; j < DeformationMapFile::MAX_SPHERICAL_STAGES; j++) { if (borderFileSelected[j] < 0) { borderFileSelected[j] = static_cast(borderFileNames.size()) - 1; } } } } for (int i = 0; i < sf.flatBorderFile.getNumberOfFiles(); i++) { borderFileNames.push_back(sf.flatBorderFile.files[i].filename); borderFileTypes.push_back(DATA_FILE_BORDER_FLAT); if (flatDeformFlag) { for (int j = 0; j < DeformationMapFile::MAX_SPHERICAL_STAGES; j++) { if (borderFileSelected[j] < 0) { borderFileSelected[j] = static_cast(borderFileNames.size()) - 1; } } } } for (int i = 0; i < sf.lobarFlatBorderFile.getNumberOfFiles(); i++) { borderFileNames.push_back(sf.lobarFlatBorderFile.files[i].filename); borderFileTypes.push_back(DATA_FILE_BORDER_FLAT_LOBAR); if (flatDeformFlag) { for (int j = 0; j < DeformationMapFile::MAX_SPHERICAL_STAGES; j++) { if (borderFileSelected[j] < 0) { borderFileSelected[j] = static_cast(borderFileNames.size()) - 1; } } } } for (int i = 0; i < sf.borderProjectionFile.getNumberOfFiles(); i++) { borderFileNames.push_back(sf.borderProjectionFile.files[i].filename); borderFileTypes.push_back(DATA_FILE_BORDER_PROJECTION); } if (borderFileNames.size() > 0) { for (int j = 0; j < DeformationMapFile::MAX_SPHERICAL_STAGES; j++) { if (borderFileSelected[j] < 0) { borderFileSelected[j] = 0; } } } // // closed topo file // closedTopoFileNames.clear(); closedTopoFileTypes.clear(); for (int i = 0; i < sf.closedTopoFile.getNumberOfFiles(); i++) { closedTopoFileNames.push_back(sf.closedTopoFile.files[i].filename); closedTopoFileTypes.push_back(DATA_FILE_TOPO_CLOSED); } for (int i = 0; i < sf.cutTopoFile.getNumberOfFiles(); i++) { closedTopoFileNames.push_back(sf.cutTopoFile.files[i].filename); closedTopoFileTypes.push_back(DATA_FILE_TOPO_CUT); } for (int i = 0; i < sf.lobarCutTopoFile.getNumberOfFiles(); i++) { closedTopoFileNames.push_back(sf.lobarCutTopoFile.files[i].filename); closedTopoFileTypes.push_back(DATA_FILE_TOPO_CUT_LOBAR); } if (closedTopoFileNames.size() > 0) { closedTopoFileSelected = 0; } else { closedTopoFileSelected = -1; } // // cut topo file // cutTopoFileNames.clear(); cutTopoFileTypes.clear(); cutTopoFileSelected = -1; for (int i = 0; i < sf.closedTopoFile.getNumberOfFiles(); i++) { cutTopoFileNames.push_back(sf.closedTopoFile.files[i].filename); cutTopoFileTypes.push_back(DATA_FILE_TOPO_CLOSED); } for (int i = 0; i < sf.cutTopoFile.getNumberOfFiles(); i++) { cutTopoFileNames.push_back(sf.cutTopoFile.files[i].filename); cutTopoFileTypes.push_back(DATA_FILE_TOPO_CUT); if (cutTopoFileSelected < 0) { cutTopoFileSelected = static_cast(cutTopoFileNames.size()) - 1; } } for (int i = 0; i < sf.lobarCutTopoFile.getNumberOfFiles(); i++) { cutTopoFileNames.push_back(sf.lobarCutTopoFile.files[i].filename); cutTopoFileTypes.push_back(DATA_FILE_TOPO_CUT_LOBAR); if (cutTopoFileSelected < 0) { cutTopoFileSelected = static_cast(cutTopoFileNames.size()) - 1; } } if (cutTopoFileNames.size() > 0) { if (cutTopoFileSelected < 0) { cutTopoFileSelected = 0; } } // // fiducial coord file // fiducialCoordFileNames.clear(); fiducialCoordFileTypes.clear(); for (int i = 0; i < sf.fiducialCoordFile.getNumberOfFiles(); i++) { fiducialCoordFileNames.push_back(sf.fiducialCoordFile.files[i].filename); fiducialCoordFileTypes.push_back(DATA_FILE_COORD_FIDUCIAL); } if (fiducialCoordFileNames.size() > 0) { fiducialCoordFileSelected = 0; } else { fiducialCoordFileSelected = -1; } // // flat coord file // flatCoordFileNames.clear(); flatCoordFileTypes.clear(); for (int i = 0; i < sf.flatCoordFile.getNumberOfFiles(); i++) { flatCoordFileNames.push_back(sf.flatCoordFile.files[i].filename); flatCoordFileTypes.push_back(DATA_FILE_COORD_FLAT); } for (int i = 0; i < sf.lobarFlatCoordFile.getNumberOfFiles(); i++) { flatCoordFileNames.push_back(sf.lobarFlatCoordFile.files[i].filename); flatCoordFileTypes.push_back(DATA_FILE_COORD_FLAT_LOBAR); } if (flatCoordFileNames.size() > 0) { flatCoordFileSelected = 0; } else { flatCoordFileSelected = -1; } // // spherical coord file // sphericalCoordFileNames.clear(); sphericalCoordFileTypes.clear(); for (int i = 0; i < sf.sphericalCoordFile.getNumberOfFiles(); i++) { sphericalCoordFileNames.push_back(sf.sphericalCoordFile.files[i].filename); sphericalCoordFileTypes.push_back(DATA_FILE_COORD_SPHERICAL); } if (sphericalCoordFileNames.size() > 0) { sphericalCoordFileSelected = 0; } else { sphericalCoordFileSelected = -1; } } caret-5.6.4~dfsg.1.orig/caret/GuiSumsDialog.h0000664000175000017500000003453511572067322020556 0ustar michaelmichael#ifndef __GUI_SUMS_DIALOG_H__ #define __GUI_SUMS_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "GenericXmlFile.h" #include "SumsFileListFile.h" #include "WuQDialog.h" class PreferencesFile; class QCheckBox; class QComboBox; class QDateTimeEdit; class QGroupBox; class QLabel; class QLineEdit; class QListWidget; class QPushButton; class QRadioButton; class QSpinBox; class QStackedWidget; class QString; class QTableWidget; class QTextEdit; /// dialog for interacting with SuMS database class GuiSumsDialog : public WuQDialog { Q_OBJECT public: /// constructor GuiSumsDialog(QWidget* parent, PreferencesFile* preferencesFileIn); /// constructor ~GuiSumsDialog(); public slots: /// Show the dialog. void show(); protected slots: /// called when output directory select push button is pressed void slotDirectoryPushButton(); /// called when the download push button is pressed void slotFinishPushButton(); /// called when select all files push button is pressed void slotSelectAllDataFilesPushButton(); /// called when deselect all files push button is pressed void slotDeselectAllDataFilesPushButton(); /// Called to select the next page void slotNextPushButton(); /// Called to select the back page void slotBackPushButton(); /// enable/disable push buttons void slotEnableDisablePushButtons(); /// Called when close button pressed. void slotCloseButton(); /// Called when a header column is clicked for sorting void slotDataFileTableHeaderColumnClicked(int item); /// Called when a data file table item is changed void slotDataFileTableItemChanged(int row, int col); /// Called when a spec file header column is clicked for sorting void slotSpecFileTableHeaderColumnClicked(int item); /// Called when a spec file table item is changed void slotSpecFileTableItemChanged(int row, int col); /// Called when a download search file type is selected void slotDownloadSearchFileTypeComboBox(int item); /// Called when upload file add button is pressed void slotUploadAddPushButton(); /// Called when upload file remove button is pressed void slotUploadRemovePushButton(); /// Called when the logout button is pressed void slotLogoutButton(); protected: /// column indices for data file table enum DATA_TABLE_COLUMNS { DATA_TABLE_FILE_CHECK_BOX_COLUMN = 0, DATA_TABLE_FILE_DATE_COLUMN = 1, DATA_TABLE_FILE_TYPE_COLUMN = 2, DATA_TABLE_FILE_NAME_COLUMN = 3, DATA_TABLE_FILE_SUBDIR_COLUMN = 4, DATA_TABLE_FILE_STATE_COLUMN = 5, DATA_TABLE_FILE_COMMENT_COLUMN = 6, DATA_TABLE_NUMBER_OF_COLUMNS = 7 // this item must always be the last item }; /// column indices for spec file table enum SPEC_TABLE_COLUMNS{ SPEC_TABLE_FILE_CHECK_BOX_COLUMN = 0, SPEC_TABLE_FILE_DATE_COLUMN = 1, SPEC_TABLE_FILE_NAME_COLUMN = 2, SPEC_TABLE_FILE_COMMENT_COLUMN = 3, SPEC_TABLE_NUMBER_OF_COLUMNS = 4 }; /// dialog mode type enum DIALOG_MODE { DIALOG_MODE_NONE, DIALOG_MODE_ARCHIVE_ID, DIALOG_MODE_SPEC_FILE_ID, DIALOG_MODE_DOWNLOAD_ATLAS, DIALOG_MODE_DOWNLOAD_SEARCH, DIALOG_MODE_REFRESH_SPEC_FILE, DIALOG_MODE_UPLOAD_FILES }; enum UPLOAD_FILE_TYPE { UPLOAD_FILE_TYPE_OTHER_FILE, UPLOAD_FILE_TYPE_SPEC_FILE, UPLOAD_FILE_TYPE_SPEC_FILE_DATA_FILE }; /// add a page void addPage(QWidget* newPage, const QString& title); /// initialize the dialog void initializeDialog(); /// Create the database login page QWidget* createDatabaseLoginPage(); /// Create the database user information QWidget* createDatabaseUserInformation(); /// Create the database mode page QWidget* createDatabaseModePage(); /// Create the download atlas page QWidget* createDownloadAtlasPage(); /// Create the download search page QWidget* createDownloadSearchPage(); /// Create the listing of spec files QWidget* createSpecFileListSection(); /// Create the listing of data files. QWidget* createDataFileListSection(); /// Create the output directory section. QWidget* createOutputDirectorySection(); /// Create the refresh spec page QWidget* createRefereshSpecFilePage(); /// Create the upload files page QWidget* createUploadFilesPage(); /// Insert the session ID into the URL. QString insertSessionIdIntoURL(const QString urlIn); /// Prepare some pages when they are about to be shown void showPage(QWidget* page); /// Load the file list table void loadDataFileTable(); /// Get a SuMS file listing (returns true if valid) bool getSumsDataFileListing(const QString& specFileID = ""); /// Set the number of rows in the table void setDataFileTableNumberOfRows(const int num); /// Adds help information in a read only text widget. QGroupBox* addPageInformation(const QString& title, const QString& text); /// set the spec file selection check boxes void setSpecFileTableSelectionCheckBoxes(); /// set the data file selection check boxes void setDataFileTableSelectionCheckBoxes(); /// read the file selection check boxes void readDataFileTableSelectionCheckBoxes(); /// Get the list of spec files (returns true if valid) bool getSumsSpecFileListing(); /// set the number of rows in the spec file table void setSpecFileTableNumberOfRows(const int num); /// load the spec file table void loadSpecFileTable(); /// Append a parameter and its value to a URL. void appendParameterToURL(QString& url, const QString& paramName, const QString& paramValue); /// Append search parameters onto the URL. void appendSearchParametersToURL(QString& url, const bool specFileSearch); /// Login to SuMS. Returns true if login is successful bool loginToSums(); /// load the upload files list box void loadUploadFilesListBox(); /// upload data files. void uploadDataFiles(); /// download data files. void downloadDataFiles(); /// Load the database user information page. void loadDatabaseUserInformationPage(); /// relogin to sums if login prior to operation check box is checked bool reloginToSums(); /// table of spec files QTableWidget* specFileTable; /// table of data files QTableWidget* dataFileTable; /// data file listing produced by SuMS database SumsFileListFile sumsDataFileList; /// spec file listing produced by SuMS database SumsFileListFile sumsSpecFileList; /// directory name line edit QLineEdit* directoryNameLineEdit; /// download push button QPushButton* downloadPushButton; /// database login page QWidget* pageDatabaseLogin; /// database user information page QWidget* pageDatabaseUserInformation; /// database mode page QWidget* pageDatabaseMode; /// Download atlas page QWidget* pageDownloadAtlas; /// Download search page QWidget* pageDownloadSearch; /// Refresh spec file page QWidget* pageRefreshSpecFile; /// Upload files page QWidget* pageUploadFiles; /// spec file selection page QWidget* pageSpecFileSelection; /// data file selection page QWidget* pageDataFileSelection; /// output directory page QWidget* pageOutputDirectory; /// combo box for database selection QComboBox* databaseSelectionComboBox; /// search timeout spin box QSpinBox* searchTimeoutSpinBox; /// data file timeout spin box QSpinBox* dataFileTimeoutSpinBox; /// name of database host QString databaseHostName; /// database user name line edit QLineEdit* databaseUserNameLineEdit; /// database user name QString databaseUserName; /// database password line edit QLineEdit* databasePasswordLineEdit; /// database password QString databasePassword; /// mode download archive QRadioButton* modeDownloadArchiveRadioButton; /// mode download spec QRadioButton* modeDownloadSpecRadioButton; /// mode download atlas button QRadioButton* modeDownloadAtlasRadioButton; /// mode download search button QRadioButton* modeDownloadSearchRadioButton; /// mode refresh spec button QRadioButton* modeRefreshSpecRadioButton; /// mode upload files button QRadioButton* modeUploadFilesRadioButton; /// dialog mode DIALOG_MODE dialogMode; /// the cookie sent by SuMS QString sumsCookie; /// the session ID sent by SuMS QString sumsSessionID; // download archive number line edit QLineEdit* downloadArchiveNumberLineEdit; /// download spec number line edit QLineEdit* downloadSpecNumberLineEdit; /// number of times to try downloading a file QSpinBox* downloadNumTimesSpinBox; /// download atlas species combo box QComboBox* downloadAtlasSpeciesComboBox; /// download atlas hemisphere combo box QComboBox* downloadAtlasHemisphereComboBox; /// download atlas space combo box QComboBox* downloadAtlasSpaceComboBox; /// download search file name line edit QLineEdit* downloadSearchFileNameLineEdit; /// download search file type combo box QComboBox* downloadSearchFileTypeComboBox; /// download search list of file type names std::vector downloadSearchFileTypeNames; /// download search list of file extensions std::vector downloadSearchFileExtensions; /// download search species combo box QComboBox* downloadSearchSpeciesComboBox; /// download search hemisphere combo box QComboBox* downloadSearchHemisphereComboBox; /// download search space combo box QComboBox* downloadSearchSpaceComboBox; /// download search species label QLabel* downloadSearchSpeciesLabel; /// download search hemisphere label QLabel* downloadSearchHemisphereLabel; /// download search space label QLabel* downloadSearchSpaceLabel; /// download search keyword QLineEdit* downloadSearchKeywordLineEdit; /// download search file comment QLineEdit* downloadSearchFileCommentLineEdit; /// download search date check box QCheckBox* downloadSearchDateCheckBox; /// download search start date QDateTimeEdit* downloadSearchStartDateEdit; /// download search end date QDateTimeEdit* downloadSearchEndDateEdit; /// upload files list box listing files for upload QListWidget* uploadFilesListBox; /// upload comment line edit QLineEdit* uploadCommentLineEdit; /// files for uploading std::vector uploadFileNames; /// search file indices enum SEARCH_FILE_INDICES { SEARCH_FILE_INDEX_SPEC = 0, SEARCH_FILE_INDEX_ALL_EXCEPT_SPEC = 1 }; /// information about user return at time of successful login GenericXmlFile loginInfoFile; /// db info user name label QLabel* dbInfoUserNameLabel; /// db info usage/quota label QLabel* dbInfoUsageQuotaLabel; /// db info privileges label QLabel* dbInfoPrivilegesLabel; /// db human label QLabel* dbInfoHumanLabel; /// db info session id QLabel* dbInfoSessionIdLabel; /// upload button valid bool uploadButtonValid; /// login visitor radio button QRadioButton* loginVisitorRadioButton; /// login user name radio button QRadioButton* loginUserNameRadioButton; /// save login check box QCheckBox* saveLoginCheckBox; /// the preferences file PreferencesFile* preferencesFile; /// the database host names std::vector availableDatabaseHostNames; /// the logout button QPushButton* logoutButton; /// login before each operation check box QCheckBox* loginBeforeOperationCheckBox; /// widget stack for pages QStackedWidget* pagesStackedWidget; /// label for page title QLabel* pageTitleLabel; /// labels for each of the pages std::vector pageTitles; /// next push button QPushButton* nextPushButton; /// back push button QPushButton* backPushButton; /// finish push button QPushButton* finishPushButton; }; #endif // __GUI_SUMS_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiSumsDialog.cxx0000664000175000017500000037244611572067322021137 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include "WuQFileDialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "DebugControl.h" #include "FileFilters.h" #include "FileUtilities.h" #include "GuiFileDialogWithInstructions.h" #include "GuiSumsDialog.h" #include "HttpFileDownload.h" #include "PreferencesFile.h" #include "QtUtilities.h" #include "SceneFile.h" #include "SpecFile.h" #include "Species.h" #include "StereotaxicSpace.h" #include "StringUtilities.h" #include "Structure.h" #include "SystemUtilities.h" #include "VolumeFile.h" /** * constructor. */ GuiSumsDialog::GuiSumsDialog(QWidget* parent, PreferencesFile* preferencesFileIn) : WuQDialog(parent) { setWindowTitle("SumsDB Database"); dialogMode = DIALOG_MODE_NONE; preferencesFile = preferencesFileIn; // // Label for page title // pageTitleLabel = new QLabel(""); // // Widget stack for pages // pagesStackedWidget = new QStackedWidget; // // Create the database login page // pageDatabaseLogin = createDatabaseLoginPage(); addPage(pageDatabaseLogin, "Database Login"); // // User information page // pageDatabaseUserInformation = createDatabaseUserInformation(); addPage(pageDatabaseUserInformation, "Database User Information"); // // Create the mode page // pageDatabaseMode = createDatabaseModePage(); addPage(pageDatabaseMode, "Database Mode"); // // Create the download atlas // pageDownloadAtlas = createDownloadAtlasPage(); addPage(pageDownloadAtlas, "Download Atlas"); // // Create the download search page // pageDownloadSearch = createDownloadSearchPage(); addPage(pageDownloadSearch, "Download Search"); // // Create the refresh spec file page // pageRefreshSpecFile = createRefereshSpecFilePage(); addPage(pageRefreshSpecFile, "Refresh Spec File"); // // Create the upload files page // pageUploadFiles = createUploadFilesPage(); addPage(pageUploadFiles, "Upload Files"); // // Create the spec file list section // pageSpecFileSelection = createSpecFileListSection(); addPage(pageSpecFileSelection, "Spec Files Selections"); // // Create the data file list section // pageDataFileSelection = createDataFileListSection(); addPage(pageDataFileSelection, "Data File Selection"); // // Create the output directory section // pageOutputDirectory = createOutputDirectorySection(); addPage(pageOutputDirectory, "Output Directory Selection"); // // push button // QPushButton* logoutPushButton = new QPushButton("Logout"); logoutPushButton->setAutoDefault(false); QObject::connect(logoutPushButton, SIGNAL(clicked()), this, SLOT(slotLogoutButton())); // // push button // backPushButton = new QPushButton("Back"); backPushButton->setAutoDefault(false); QObject::connect(backPushButton, SIGNAL(clicked()), this, SLOT(slotBackPushButton())); // // push button // nextPushButton = new QPushButton("Next"); nextPushButton->setAutoDefault(false); QObject::connect(nextPushButton, SIGNAL(clicked()), this, SLOT(slotNextPushButton())); // // push button // finishPushButton = new QPushButton("Finish"); finishPushButton->setAutoDefault(false); QObject::connect(finishPushButton, SIGNAL(clicked()), this, SLOT(slotFinishPushButton())); // // push button // QPushButton* closePushButton = new QPushButton("Close"); closePushButton->setAutoDefault(false); QObject::connect(closePushButton, SIGNAL(clicked()), this, SLOT(slotCloseButton())); // // Make buttons same size // QtUtilities::makeButtonsSameSize(logoutPushButton, backPushButton, nextPushButton, finishPushButton, closePushButton); // // Layout for push buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->addWidget(backPushButton); buttonsLayout->addWidget(nextPushButton); buttonsLayout->addWidget(finishPushButton); //buttonsLayout->insertStretch(); buttonsLayout->addWidget(logoutPushButton); buttonsLayout->addWidget(closePushButton); // // Layout for dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->addWidget(pageTitleLabel); dialogLayout->addWidget(pagesStackedWidget); dialogLayout->addLayout(buttonsLayout); // // Initialize the dialog // initializeDialog(); } /** * Destructor. */ GuiSumsDialog::~GuiSumsDialog() { } /** * initialize the dialog. */ void GuiSumsDialog::initializeDialog() { dialogMode = DIALOG_MODE_NONE; // // Load default hosts // availableDatabaseHostNames.clear(); availableDatabaseHostNames.push_back("http://sumsdb.wustl.edu"); // // Get hosts from preferences file // if (preferencesFile != NULL) { const QString hosts = preferencesFile->getSumsDatabaseHosts(); if (hosts.isEmpty() == false) { std::vector tokens; StringUtilities::token(hosts, ",", tokens); for (int i = 0; i < static_cast(tokens.size()); i++) { const QString name = StringUtilities::trimWhitespace(tokens[i]); if (name.isEmpty() == false) { availableDatabaseHostNames.push_back(name); } } } } // // Find currently selected host and load database host combo box // databaseSelectionComboBox->clear(); for (int i = 0; i < static_cast(availableDatabaseHostNames.size()); i++) { databaseSelectionComboBox->addItem(availableDatabaseHostNames[i]); } if (preferencesFile != NULL) { QString userName; QString passWord; QString hostName; bool useLoginName; bool loginDataValid; preferencesFile->getSumsLoginInformation(userName, passWord, hostName, useLoginName, loginDataValid); if (loginDataValid) { databaseUserNameLineEdit->setText(userName); databasePasswordLineEdit->setText(passWord); for (int i = 0; i < databaseSelectionComboBox->count(); i++) { if (hostName == databaseSelectionComboBox->itemText(i)) { databaseSelectionComboBox->setCurrentIndex(i); break; } } if (useLoginName) { loginUserNameRadioButton->setChecked(true); } else { loginVisitorRadioButton->setChecked(true); } } saveLoginCheckBox->setChecked(loginDataValid); } showPage(pageDatabaseLogin); } /** * add a page. */ void GuiSumsDialog::addPage(QWidget* newPage, const QString& title) { pagesStackedWidget->addWidget(newPage); pageTitles.push_back(title); } /** * Called when the logout button is pressed. */ void GuiSumsDialog::slotLogoutButton() { // // URL for logging off // QString url(databaseHostName); url.append("/sums/dispatch.do?forward=logoff"); // // Send the request // QString contents; QString errorMessage; std::map headerTags; if (FileUtilities::downloadFileWithHttpGet(url, searchTimeoutSpinBox->value(), contents, errorMessage, &headerTags)) { //std::cout << "Logoff contents: " << contents.toAscii().constData() << std::endl; } showPage(pageDatabaseLogin); } /** * Called when close button pressed. */ void GuiSumsDialog::slotCloseButton() { if (WuQDialog::close() == false) { std::cout << "Closing of SumsDB Dialog rejected." << std::endl; } } /** * Show the dialog. */ void GuiSumsDialog::show() { slotEnableDisablePushButtons(); WuQDialog::show(); } /** * Create the database Mode page */ QWidget* GuiSumsDialog::createDatabaseModePage() { // // Download Archive button // modeDownloadArchiveRadioButton = new QRadioButton("Download Archive"); downloadArchiveNumberLineEdit = new QLineEdit; downloadArchiveNumberLineEdit->setText("568300"); downloadArchiveNumberLineEdit->setMaximumWidth(200); downloadArchiveNumberLineEdit->setEnabled(false); // // Download Spec button // modeDownloadSpecRadioButton = new QRadioButton("Download Spec"); downloadSpecNumberLineEdit = new QLineEdit; downloadSpecNumberLineEdit->setText("701006"); downloadSpecNumberLineEdit->setMaximumWidth(200); downloadSpecNumberLineEdit->setEnabled(false); // // Download Atlas button // modeDownloadAtlasRadioButton = new QRadioButton("Download Atlas"); // // Download Search button // modeDownloadSearchRadioButton = new QRadioButton("Download Search"); // // Refresh Spec button // modeRefreshSpecRadioButton = new QRadioButton("Refresh Spec File"); modeRefreshSpecRadioButton->setEnabled(false); // no refresh at this time // // Upload file button // modeUploadFilesRadioButton = new QRadioButton("Upload Files"); // // Group box and layout for database mode // QGroupBox* modeGroupBox = new QGroupBox("Database Mode"); QGridLayout* modeLayout = new QGridLayout(modeGroupBox); modeLayout->addWidget(modeDownloadArchiveRadioButton, 0, 0); modeLayout->addWidget(downloadArchiveNumberLineEdit, 0, 1); modeLayout->addWidget(modeDownloadSpecRadioButton, 1, 0); modeLayout->addWidget(downloadSpecNumberLineEdit, 1, 1); modeLayout->addWidget(modeDownloadAtlasRadioButton, 2, 0); modeLayout->addWidget(modeDownloadSearchRadioButton, 3, 0); modeLayout->addWidget(modeRefreshSpecRadioButton, 4, 0); modeLayout->addWidget(modeUploadFilesRadioButton, 5, 0); modeGroupBox->setFixedSize(modeGroupBox->sizeHint()); // // Button group for database mode selection // QButtonGroup* dbModeButtonGroup = new QButtonGroup(this); QObject::connect(dbModeButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotEnableDisablePushButtons())); dbModeButtonGroup->addButton(modeDownloadArchiveRadioButton); dbModeButtonGroup->addButton(modeDownloadSpecRadioButton); dbModeButtonGroup->addButton(modeDownloadAtlasRadioButton); dbModeButtonGroup->addButton(modeDownloadSearchRadioButton); dbModeButtonGroup->addButton(modeRefreshSpecRadioButton); dbModeButtonGroup->addButton(modeUploadFilesRadioButton); // // Add help information // QWidget* infoPage = addPageInformation( "Database Mode Information", "Download Archive - Choose this item and enter the id number of the " "archive to get a listing of the archive's files.\n\n" "Download Spec - Choose this item and enter the id number of the spec file " "to get a listing of the spec file's data files.\n\n" "Download Atlas - Choose this item to download an atlas data set.\n\n" "Download Search - Choose this to search the SumsDB database for files that " "are to be downloaded.\n\n" "Refresh Spec File - Choose this to refresh a spec file and " "its data files that have already been downloaded.\n\n" "Upload Files - Choose this to upload files to the SumsDB database."); QWidget* w = new QWidget; QVBoxLayout* pageLayout = new QVBoxLayout(w); pageLayout->addWidget(modeGroupBox); pageLayout->addWidget(infoPage); return w; } /** * Create the database login page */ QWidget* GuiSumsDialog::createDatabaseLoginPage() { // // SuMS database selection // QLabel* databaseLabel = new QLabel("Database "); databaseSelectionComboBox = new QComboBox; // // spacing between rows // QLabel* dummyRowLabel = new QLabel(" "); // // Visitor radio button and stuff // loginVisitorRadioButton = new QRadioButton(""); QLabel* visitorLabel = new QLabel("Visitor"); // // User name // loginUserNameRadioButton = new QRadioButton(""); QLabel* usernameLabel = new QLabel("Username "); databaseUserNameLineEdit = new QLineEdit; databaseUserNameLineEdit->setText(""); // // Password // QLabel* passwordLabel = new QLabel("Password "); databasePasswordLineEdit = new QLineEdit; databasePasswordLineEdit->setEchoMode(QLineEdit::Password); databasePasswordLineEdit->setText(""); // // Save login parameters check box // saveLoginCheckBox = new QCheckBox(""); QLabel* saveLoginLabel = new QLabel("Save Login"); // // Button group for visitor and username radio buttons // QButtonGroup* loginButtonGroup = new QButtonGroup(this); QObject::connect(loginButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotEnableDisablePushButtons())); loginButtonGroup->addButton(loginVisitorRadioButton); loginButtonGroup->addButton(loginUserNameRadioButton); // // Group box and layout for database login // QGroupBox* databaseLoginGroupBox = new QGroupBox("Database Login"); QGridLayout* databaseLayout = new QGridLayout(databaseLoginGroupBox); databaseLayout->addWidget(databaseLabel, 0, 1); databaseLayout->addWidget(databaseSelectionComboBox, 0, 2); databaseLayout->addWidget(dummyRowLabel, 1, 0); databaseLayout->addWidget(loginVisitorRadioButton, 2, 0); databaseLayout->addWidget(visitorLabel, 2, 1); databaseLayout->addWidget(loginUserNameRadioButton, 3, 0); databaseLayout->addWidget(usernameLabel, 3, 1); databaseLayout->addWidget(databaseUserNameLineEdit, 3, 2); databaseLayout->addWidget(passwordLabel, 4, 1); databaseLayout->addWidget(databasePasswordLineEdit, 4, 2); databaseLayout->addWidget(saveLoginCheckBox, 5, 0); databaseLayout->addWidget(saveLoginLabel, 5, 1); databaseLoginGroupBox->setFixedSize(databaseLoginGroupBox->sizeHint()); // // search timeout // QLabel* searchTimeoutLabel = new QLabel("Search Timeout (seconds) "); searchTimeoutSpinBox = new QSpinBox; searchTimeoutSpinBox->setMinimum(1); searchTimeoutSpinBox->setMaximum(10000000); searchTimeoutSpinBox->setSingleStep(10); searchTimeoutSpinBox->setValue(60); searchTimeoutSpinBox->setToolTip( "This value is the maximum time a database\n" "search may run before it is stopped."); // // data file timeout // QLabel* dataTimeoutLabel = new QLabel("Data File Timeout (seconds) "); dataFileTimeoutSpinBox = new QSpinBox; dataFileTimeoutSpinBox->setMinimum(1); dataFileTimeoutSpinBox->setMaximum(10000000); dataFileTimeoutSpinBox->setSingleStep(10); dataFileTimeoutSpinBox->setValue(preferencesFile->getSumsDatabaseDataFileTimeout()); dataFileTimeoutSpinBox->setToolTip( "This value is the maximum time\n" "allowed for downloading a file."); // // Max retries if file fails // QLabel* maxRetriesLabel = new QLabel("Max Retries "); downloadNumTimesSpinBox = new QSpinBox; downloadNumTimesSpinBox->setMinimum(1); downloadNumTimesSpinBox->setMaximum(100); downloadNumTimesSpinBox->setSingleStep(1); downloadNumTimesSpinBox->setValue(3); downloadNumTimesSpinBox->setToolTip( "This value is the number of attempts that\n" "will be made to download a file. Sometimes\n" "file downloads fail for no apparent reason, so\n" "keep this value greater than 1."); // // Login before each operation check box // loginBeforeOperationCheckBox = new QCheckBox("Login Prior to Each Operation"); loginBeforeOperationCheckBox->setChecked(true); // // Parameters group box and layout // QGridLayout* paramsGrid = new QGridLayout; paramsGrid->addWidget(searchTimeoutLabel, 0, 0); paramsGrid->addWidget(searchTimeoutSpinBox, 0, 1); paramsGrid->addWidget(dataTimeoutLabel, 1, 0); paramsGrid->addWidget(dataFileTimeoutSpinBox, 1, 1); paramsGrid->addWidget(maxRetriesLabel, 2, 0); paramsGrid->addWidget(downloadNumTimesSpinBox, 2, 1); QGroupBox* parametersGroupBox = new QGroupBox("Parameters"); QVBoxLayout* paramsLayout = new QVBoxLayout(parametersGroupBox); paramsLayout->addLayout(paramsGrid); paramsLayout->addWidget(loginBeforeOperationCheckBox); parametersGroupBox->setFixedSize(parametersGroupBox->sizeHint()); // // Add help information // QWidget* pageInfoWidget = addPageInformation( "Database Information", "If you have a username and password, select the radio (round) button " "next to \"Username\" and enter your username and password. Otherwise, " "select the radio (round) button next to \"Visitor\". Click the " "checkbox (square) button next to \"Save Login\" to save your login " "information so that you will not need to enter it next time."); // // Widget and layouts for page // QHBoxLayout* horizLayout = new QHBoxLayout; horizLayout->addWidget(databaseLoginGroupBox); horizLayout->addWidget(parametersGroupBox); QWidget* w = new QWidget; QVBoxLayout* pageLayout = new QVBoxLayout(w); pageLayout->addLayout(horizLayout); pageLayout->addWidget(pageInfoWidget); return w;; } /** * Create the database user information page */ QWidget* GuiSumsDialog::createDatabaseUserInformation() { // // String with sixty blanks // QString emptyItemStr; emptyItemStr.fill(' ', 60); const QString emptyItem(emptyItemStr); // // User name // QLabel* usernameLabel = new QLabel("Username "); dbInfoUserNameLabel = new QLabel(emptyItem); QLabel* usageLabel = new QLabel("Usage/Quota (Mb)"); dbInfoUsageQuotaLabel = new QLabel(emptyItem); QLabel* privilegesLabel = new QLabel("Privileges "); dbInfoPrivilegesLabel = new QLabel(emptyItem); QLabel* uploadLabel = new QLabel("Upload Human Data "); dbInfoHumanLabel = new QLabel(emptyItem); QLabel* sessionLabel = new QLabel("Session ID "); dbInfoSessionIdLabel = new QLabel(emptyItem); // // Group Box and label for items // QGroupBox* infoGroupBox = new QGroupBox("User Information"); QGridLayout* infoLayout = new QGridLayout(infoGroupBox); infoLayout->addWidget(usernameLabel, 0, 0); infoLayout->addWidget(dbInfoUserNameLabel, 0, 1); infoLayout->addWidget(usageLabel, 1, 0); infoLayout->addWidget(dbInfoUsageQuotaLabel, 1, 1); infoLayout->addWidget(privilegesLabel, 2, 0); infoLayout->addWidget(dbInfoPrivilegesLabel, 2, 1); infoLayout->addWidget(uploadLabel, 3, 0); infoLayout->addWidget(dbInfoHumanLabel, 3, 1); infoLayout->addWidget(sessionLabel, 4, 0); infoLayout->addWidget(dbInfoSessionIdLabel, 4, 1); infoLayout->setColumnStretch(0, 0); infoLayout->setColumnStretch(1, 100); infoGroupBox->setFixedHeight(infoGroupBox->sizeHint().height()); // // widget for page // QWidget* w = new QWidget; QVBoxLayout* layout = new QVBoxLayout(w); layout->addWidget(infoGroupBox); return w; } /** * Load the database user information page. */ void GuiSumsDialog::loadDatabaseUserInformationPage() { dbInfoUserNameLabel->setText(loginInfoFile.getValue("sums:login:user:username")); const QString usage(loginInfoFile.getValue("sums:login:user:current")); const QString quota(loginInfoFile.getValue("sums:login:user:quota")); dbInfoUsageQuotaLabel->setText(usage + "/" + quota); dbInfoHumanLabel->setText("No"); if ((loginInfoFile.getValue("sums:login:user:human") == "true") && (loginInfoFile.getValue("sums:login:user:code_agreement") == "true")) { dbInfoHumanLabel->setText("Yes"); } std::vector privs; loginInfoFile.getValue("sums:login:user:roles:role", privs); for (int i = 0; i < static_cast(privs.size()); i++) { if (privs[i] == "upload") { uploadButtonValid = true; } } dbInfoPrivilegesLabel->setText(StringUtilities::combine(privs, " ")); dbInfoSessionIdLabel->setText(sumsSessionID); if (loginVisitorRadioButton->isChecked()) { dbInfoUserNameLabel->setText("Visitor"); dbInfoPrivilegesLabel->setText("search"); } } /** * Adds help information in a read only text widget. */ QGroupBox* GuiSumsDialog::addPageInformation(const QString& title, const QString& text) { // // Create the text editor // const int maxHeight = 125; QTextEdit* textEditor = new QTextEdit; textEditor->setReadOnly(true); textEditor->setPlainText(text); int height = textEditor->sizeHint().height(); if (height > maxHeight) { height = maxHeight; } textEditor->setMaximumHeight(maxHeight); QGroupBox* group = new QGroupBox(title); QVBoxLayout* groupLayout = new QVBoxLayout(group); groupLayout->addWidget(textEditor); group->setFixedHeight(group->sizeHint().height()); return group; } /** * Create the download atlas page */ QWidget* GuiSumsDialog::createDownloadAtlasPage() { // // Atlas species // QLabel* speciesLabel = new QLabel("Species "); downloadAtlasSpeciesComboBox = new QComboBox; std::vector speciesTypes; std::vector speciesNames; Species::getAllSpeciesTypesAndNames(speciesTypes, speciesNames); downloadAtlasSpeciesComboBox->addItem("Any"); for (int i = 0; i < static_cast(speciesNames.size()); i++) { downloadAtlasSpeciesComboBox->addItem(speciesNames[i]); } // // Atlas hemisphere // QLabel* structLabel = new QLabel("Structure "); downloadAtlasHemisphereComboBox = new QComboBox; std::vector structureTypes; std::vector structureNames; Structure::getAllTypesAndNames(structureTypes, structureNames, false); downloadAtlasHemisphereComboBox->addItem("Any"); downloadAtlasHemisphereComboBox->addItem("left"); downloadAtlasHemisphereComboBox->addItem("right"); downloadAtlasHemisphereComboBox->addItem("both"); for (int i = 0; i < static_cast(structureNames.size()); i++) { downloadAtlasHemisphereComboBox->addItem(structureNames[i]); } // // Atlas space // QLabel* spaceLabel = new QLabel("Space "); downloadAtlasSpaceComboBox = new QComboBox; std::vector spaces; StereotaxicSpace::getAllStereotaxicSpaces(spaces); downloadAtlasSpaceComboBox->addItem("Any"); for (unsigned int i = 0; i < spaces.size(); i++) { downloadAtlasSpaceComboBox->addItem(spaces[i].getName()); } // // Download atlas group box and layout // QGroupBox* atlasGroupBox = new QGroupBox("Download Atlas"); QGridLayout* atlasGrid = new QGridLayout(atlasGroupBox); atlasGrid->addWidget(speciesLabel, 0, 0); atlasGrid->addWidget(downloadAtlasSpeciesComboBox, 0, 1); atlasGrid->addWidget(structLabel, 1, 0); atlasGrid->addWidget(downloadAtlasHemisphereComboBox, 1, 1); atlasGrid->addWidget(spaceLabel, 2, 0); atlasGrid->addWidget(downloadAtlasSpaceComboBox, 2, 1); atlasGrid->setColumnStretch(0, 0); atlasGrid->setColumnStretch(1, 100); atlasGroupBox->setFixedHeight(atlasGroupBox->sizeHint().height()); // // Add help information // QWidget* infoPage = addPageInformation( "Download Atlas Information", "Use the Species, Hemisphere, and Space selection to describe " "the atlas you are seeking. The next page will list the atlases " "that meet your criteria."); QWidget* w = new QWidget; QVBoxLayout* pageLayout = new QVBoxLayout(w); pageLayout->addWidget(atlasGroupBox); pageLayout->addWidget(infoPage); return w; } /** * Create the upload files page */ QWidget* GuiSumsDialog::createUploadFilesPage() { // // the list box containing the files for uploading // uploadFilesListBox = new QListWidget; uploadFilesListBox->setSelectionMode(QListWidget::ExtendedSelection); // // Add upload file button // QPushButton* uploadAddPushButton = new QPushButton("Add Files..."); uploadAddPushButton->setAutoDefault(false); QObject::connect(uploadAddPushButton, SIGNAL(clicked()), this, SLOT(slotUploadAddPushButton())); // // Remove upload file button // QPushButton* uploadRemovePushButton = new QPushButton("Remove Selected Files"); uploadRemovePushButton->setAutoDefault(false); QObject::connect(uploadRemovePushButton, SIGNAL(clicked()), this, SLOT(slotUploadRemovePushButton())); QtUtilities::makeButtonsSameSize(uploadAddPushButton, uploadRemovePushButton); // // Layouts for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->addWidget(uploadAddPushButton); buttonsLayout->addWidget(uploadRemovePushButton); // // Comment line edit // QLabel* commentLabel = new QLabel("Comment "); uploadCommentLineEdit = new QLineEdit; QHBoxLayout* commentLayout = new QHBoxLayout; commentLayout->addWidget(commentLabel); commentLayout->addWidget(uploadCommentLineEdit); // // Group box and layout for upload files section // QGroupBox* uploadGroupBox = new QGroupBox("Upload Files"); QVBoxLayout* uploadLayout = new QVBoxLayout(uploadGroupBox); uploadLayout->addWidget(uploadFilesListBox); uploadLayout->addLayout(buttonsLayout); uploadLayout->addLayout(commentLayout); // // Add help information // QWidget* infoWidget = addPageInformation( "Upload Files Information", "Press the \"Finish\" button to upload the files.\n\n" "Press the \"Add Files\" button to choose files for uploading.\n\n" "To remove files, select them with the mouse and press the " "\"Remove Selected Files\" button."); QWidget* w = new QWidget; QVBoxLayout* layout = new QVBoxLayout(w); layout->addWidget(uploadGroupBox); layout->addWidget(infoWidget); return w; } /** * Called when upload file add button is pressed. */ void GuiSumsDialog::slotUploadAddPushButton() { const QString allFilesFilter("All Files (*)"); QString instructions = "To select files, hold down the CTRL key while selecting " "border file names with the mouse (Macintosh users should " "hold downthe Apple key)."; GuiFileDialogWithInstructions addUploadFileDialog(this, instructions, "chooseUploadFile", true); addUploadFileDialog.setDirectory(QDir::currentPath()); addUploadFileDialog.setWindowTitle("Choose Files For Uploading"); addUploadFileDialog.setFileMode(GuiFileDialogWithInstructions::ExistingFiles); QStringList filterList; filterList.append(FileFilters::getSpecFileFilter()); filterList.append(FileFilters::getZipFileFilter()); filterList.append(allFilesFilter); addUploadFileDialog.setFilters(filterList); addUploadFileDialog.selectFilter(FileFilters::getSpecFileFilter()); if (addUploadFileDialog.exec() == GuiSumsDialog::Accepted) { QStringList list = addUploadFileDialog.selectedFiles(); QStringList::Iterator it = list.begin(); while( it != list.end() ) { QString filename((*it)); uploadFileNames.push_back(filename); ++it; } } loadUploadFilesListBox(); } /** * load the upload files list box. */ void GuiSumsDialog::loadUploadFilesListBox() { uploadFilesListBox->clear(); for (int i = 0; i < static_cast(uploadFileNames.size()); i++) { uploadFilesListBox->addItem(uploadFileNames[i]); } slotEnableDisablePushButtons(); } /** * Called when upload file remove button is pressed. */ void GuiSumsDialog::slotUploadRemovePushButton() { std::vector names; for (int i = 0; i < static_cast(uploadFileNames.size()); i++) { QListWidgetItem* item = uploadFilesListBox->item(i); if (uploadFilesListBox->isItemSelected(item) == false) { names.push_back(uploadFileNames[i]); } } uploadFileNames = names; loadUploadFilesListBox(); } /** * Create the refresh spec page */ QWidget* GuiSumsDialog::createRefereshSpecFilePage() { QLabel* notImpLabel = new QLabel("Not Implemented."); // // refresh group box // QGroupBox* refreshGroupBox = new QGroupBox("Refresh Spec File"); QVBoxLayout* refreshLayout = new QVBoxLayout(refreshGroupBox); refreshLayout->addWidget(notImpLabel); // // Add help information // QWidget* infoWidget = addPageInformation( "Refresh Spec File Information", ""); QWidget* w = new QWidget; QVBoxLayout* layout = new QVBoxLayout(w); layout->addWidget(refreshGroupBox); layout->addWidget(infoWidget); return w; } /** * Create the download search page */ QWidget* GuiSumsDialog::createDownloadSearchPage() { // // search file type // QLabel* fileTypeLabel = new QLabel("File Type "); downloadSearchFileTypeComboBox = new QComboBox; QObject::connect(downloadSearchFileTypeComboBox, SIGNAL(activated(int)), this, SLOT(slotDownloadSearchFileTypeComboBox(int))); // // Search filename // QLabel* fileNameLabel = new QLabel("File Name "); downloadSearchFileNameLineEdit = new QLineEdit; // // File comment // QLabel* fileCommentLabel = new QLabel("File Comment"); downloadSearchFileCommentLineEdit = new QLineEdit; // // Keyword // QLabel* keywordLabel = new QLabel("Keyword"); downloadSearchKeywordLineEdit = new QLineEdit; // // Layout for file information // QGridLayout* fileGridLayout = new QGridLayout; fileGridLayout->addWidget(fileTypeLabel, 0, 0); fileGridLayout->addWidget(downloadSearchFileTypeComboBox, 0, 1); fileGridLayout->addWidget(fileNameLabel, 1, 0); fileGridLayout->addWidget(downloadSearchFileNameLineEdit, 1, 1); fileGridLayout->addWidget(fileCommentLabel, 2, 0); fileGridLayout->addWidget(downloadSearchFileCommentLineEdit, 2, 1); fileGridLayout->addWidget(keywordLabel, 3, 0); fileGridLayout->addWidget(downloadSearchKeywordLineEdit, 3, 1); // // Date // const QString dateFormat("MMM dd YYYY"); downloadSearchDateCheckBox = new QCheckBox("File Date"); downloadSearchDateCheckBox->setFont(keywordLabel->font()); QLabel* startLabel = new QLabel("Start "); downloadSearchStartDateEdit = new QDateTimeEdit(QDate::currentDate()); downloadSearchStartDateEdit->setDisplayFormat(dateFormat); QLabel* endLabel = new QLabel(" End "); downloadSearchEndDateEdit = new QDateTimeEdit(QDate::currentDate()); downloadSearchEndDateEdit->setDisplayFormat(dateFormat); QObject::connect(downloadSearchDateCheckBox, SIGNAL(toggled(bool)), startLabel, SLOT(setEnabled(bool))); QObject::connect(downloadSearchDateCheckBox, SIGNAL(toggled(bool)), downloadSearchStartDateEdit, SLOT(setEnabled(bool))); QObject::connect(downloadSearchDateCheckBox, SIGNAL(toggled(bool)), endLabel, SLOT(setEnabled(bool))); QObject::connect(downloadSearchDateCheckBox, SIGNAL(toggled(bool)), downloadSearchEndDateEdit, SLOT(setEnabled(bool))); startLabel->setEnabled(false); downloadSearchStartDateEdit->setEnabled(false); endLabel->setEnabled(false); downloadSearchEndDateEdit->setEnabled(false); downloadSearchDateCheckBox->setChecked(false); QHBoxLayout* dateLayout = new QHBoxLayout; dateLayout->addWidget(downloadSearchDateCheckBox); dateLayout->addWidget(startLabel); dateLayout->addWidget(downloadSearchStartDateEdit); dateLayout->addWidget(endLabel); dateLayout->addWidget(downloadSearchEndDateEdit); dateLayout->addStretch(); // // Atlas hemisphere // downloadSearchHemisphereLabel = new QLabel("Structure "); downloadSearchHemisphereComboBox = new QComboBox; std::vector structureTypes; std::vector structureNames; Structure::getAllTypesAndNames(structureTypes, structureNames, false); downloadSearchHemisphereComboBox->addItem("Any"); for (int i = 0; i < static_cast(structureNames.size()); i++) { downloadSearchHemisphereComboBox->addItem(structureNames[i]); } // // Atlas space // downloadSearchSpaceLabel = new QLabel("Space "); downloadSearchSpaceComboBox = new QComboBox; std::vector allSpaces; StereotaxicSpace::getAllStereotaxicSpaces(allSpaces); downloadSearchSpaceComboBox->addItem("Any"); for (int i = 0; i < static_cast(allSpaces.size()); i++) { downloadSearchSpaceComboBox->addItem(allSpaces[i].getName()); } // // Atlas species // downloadSearchSpeciesLabel = new QLabel("Species "); downloadSearchSpeciesComboBox = new QComboBox; std::vector speciesTypes; std::vector speciesNames; Species::getAllSpeciesTypesAndNames(speciesTypes, speciesNames); downloadSearchSpeciesComboBox->addItem("Any"); for (int i = 0; i < static_cast(speciesNames.size()); i++) { downloadSearchSpeciesComboBox->addItem(speciesNames[i]); } // // Layout for attributes // QWidget* attWidget = new QWidget; QGridLayout* attributesGridLayout = new QGridLayout(attWidget); attributesGridLayout->addWidget(downloadSearchHemisphereLabel, 0, 0); attributesGridLayout->addWidget(downloadSearchHemisphereComboBox, 0, 1); attributesGridLayout->addWidget(downloadSearchSpaceLabel, 1, 0); attributesGridLayout->addWidget(downloadSearchSpaceComboBox, 1, 1); attributesGridLayout->addWidget(downloadSearchSpeciesLabel, 2, 0); attributesGridLayout->addWidget(downloadSearchSpeciesComboBox, 2, 1); attWidget->setFixedSize(attWidget->sizeHint()); // // Download search group box // QGroupBox* downloadGroupBox = new QGroupBox("Download Search"); QVBoxLayout* downloadGroupLayout = new QVBoxLayout(downloadGroupBox); downloadGroupLayout->addLayout(fileGridLayout); downloadGroupLayout->addLayout(dateLayout); downloadGroupLayout->addWidget(attWidget); // // Get file types from spec file and load into file type combo box // AbstractFile::getAllFileTypeNamesAndExtensions(downloadSearchFileTypeNames, downloadSearchFileExtensions); // // Add anything but spec // downloadSearchFileTypeNames.insert(downloadSearchFileTypeNames.begin(), "All EXCEPT Spec Files"); downloadSearchFileExtensions.insert(downloadSearchFileExtensions.begin(), ""); // // Make spec file the first item // downloadSearchFileTypeNames.insert(downloadSearchFileTypeNames.begin(), "Spec Files (*.spec)"); downloadSearchFileExtensions.insert(downloadSearchFileExtensions.begin(), "spec"); // // Load file type combo box // for (unsigned int i = 0; i < downloadSearchFileTypeNames.size(); i++) { if (i > 0) { if (downloadSearchFileTypeNames[i] == "Spec File") { continue; } } downloadSearchFileTypeComboBox->addItem(downloadSearchFileTypeNames[i]); } slotDownloadSearchFileTypeComboBox(downloadSearchFileTypeComboBox->currentIndex()); // // Add help information // QWidget* infoWidget = addPageInformation( "Download Search Information", "Enter information to search for file in the SumsDB database.\n\n" "If the File Type is set to \"Spec Files\", the next page will be a " "list of matching spec files. Otherwise, the next page will be a " "list of data files."); QWidget* w = new QWidget; QVBoxLayout* layout = new QVBoxLayout(w); layout->addWidget(downloadGroupBox); layout->addWidget(infoWidget); return w; } /** * Called when a download search file type is selected. */ void GuiSumsDialog::slotDownloadSearchFileTypeComboBox(int item) { bool showSpecSearchOptions = (item == SEARCH_FILE_INDEX_SPEC); downloadSearchSpeciesComboBox->setEnabled(showSpecSearchOptions); downloadSearchHemisphereComboBox->setEnabled(showSpecSearchOptions); downloadSearchSpaceComboBox->setEnabled(showSpecSearchOptions); downloadSearchSpeciesLabel->setEnabled(showSpecSearchOptions); downloadSearchHemisphereLabel->setEnabled(showSpecSearchOptions); downloadSearchSpaceLabel->setEnabled(showSpecSearchOptions); } /** * Create the listing of data files. */ QWidget* GuiSumsDialog::createDataFileListSection() { // // Table containing list of files // dataFileTable = new QTableWidget; QObject::connect(dataFileTable, SIGNAL(cellChanged(int,int)), this, SLOT(slotDataFileTableItemChanged(int,int))); dataFileTable->setColumnCount(DATA_TABLE_NUMBER_OF_COLUMNS); // dataFileTable->setColumnReadOnly(DATA_TABLE_FILE_DATE_COLUMN, true); // dataFileTable->setColumnReadOnly(DATA_TABLE_FILE_TYPE_COLUMN, true); // dataFileTable->setColumnReadOnly(DATA_TABLE_FILE_NAME_COLUMN, true); // dataFileTable->setColumnReadOnly(DATA_TABLE_FILE_SUBDIR_COLUMN, true); // dataFileTable->setColumnReadOnly(DATA_TABLE_FILE_STATE_COLUMN, true); // dataFileTable->setColumnReadOnly(DATA_TABLE_FILE_COMMENT_COLUMN, true); dataFileTable->setColumnWidth(DATA_TABLE_FILE_NAME_COLUMN, 500); dataFileTable->setColumnWidth(DATA_TABLE_FILE_COMMENT_COLUMN, 500); // // Data file table column headers // QHeaderView* header = dataFileTable->horizontalHeader(); QObject::connect(header, SIGNAL(sectionClicked(int)), this, SLOT(slotDataFileTableHeaderColumnClicked(int))); // // Column labels // QStringList columnNames; columnNames << "Download"; columnNames << "Date"; columnNames << "File Type"; columnNames << "File Name"; columnNames << "Directory"; columnNames << "State"; columnNames << "Comment"; dataFileTable->setHorizontalHeaderLabels(columnNames); // // Select all files button // QPushButton* selectAllFilesPushButton = new QPushButton("Select All Files"); selectAllFilesPushButton->setFixedSize(selectAllFilesPushButton->sizeHint()); selectAllFilesPushButton->setAutoDefault(false); QObject::connect(selectAllFilesPushButton, SIGNAL(clicked()), this, SLOT(slotSelectAllDataFilesPushButton())); // // Deselect all files button // QPushButton* deselectAllFilesPushButton = new QPushButton("Deselect All Files"); deselectAllFilesPushButton->setFixedSize(deselectAllFilesPushButton->sizeHint()); deselectAllFilesPushButton->setAutoDefault(false); QObject::connect(deselectAllFilesPushButton, SIGNAL(clicked()), this, SLOT(slotDeselectAllDataFilesPushButton())); // // Assemble the buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->addWidget(selectAllFilesPushButton); buttonsLayout->addWidget(deselectAllFilesPushButton); // // Group box for file selections // QGroupBox* dataFileGroupBox = new QGroupBox("Data Files"); QVBoxLayout* dataFileLayout = new QVBoxLayout(dataFileGroupBox); dataFileLayout->addWidget(dataFileTable); dataFileLayout->addLayout(buttonsLayout); // // Add help information // QWidget* infoWidget = addPageInformation( "Data Files Information", "Files with a checkmark in the \"Download\" column will be " "downloaded. The files may be sorted by data, type, or " "name by clicking on the appropriate column name header."); QWidget* w = new QWidget; QVBoxLayout* layout = new QVBoxLayout(w); layout->addWidget(dataFileGroupBox); layout->addWidget(infoWidget); return w; } /** * Called when a table item is changed. */ void GuiSumsDialog::slotDataFileTableItemChanged(int /*row*/, int col) { if (col == DATA_TABLE_FILE_CHECK_BOX_COLUMN) { readDataFileTableSelectionCheckBoxes(); slotEnableDisablePushButtons(); } } /** * Called when a header column is clicked for sorting. */ void GuiSumsDialog::slotDataFileTableHeaderColumnClicked(int item) { switch (item) { case DATA_TABLE_FILE_CHECK_BOX_COLUMN: case DATA_TABLE_FILE_DATE_COLUMN: readDataFileTableSelectionCheckBoxes(); sumsDataFileList.sort(SumsFileListFile::SORT_ORDER_DATE); loadDataFileTable(); break; case DATA_TABLE_FILE_TYPE_COLUMN: readDataFileTableSelectionCheckBoxes(); sumsDataFileList.sort(SumsFileListFile::SORT_ORDER_TYPE); loadDataFileTable(); break; case DATA_TABLE_FILE_NAME_COLUMN: readDataFileTableSelectionCheckBoxes(); sumsDataFileList.sort(SumsFileListFile::SORT_ORDER_NAME); loadDataFileTable(); break; case DATA_TABLE_FILE_SUBDIR_COLUMN: break; case DATA_TABLE_FILE_STATE_COLUMN: break; case DATA_TABLE_FILE_COMMENT_COLUMN: break; case DATA_TABLE_NUMBER_OF_COLUMNS: break; } } /** * set the file selection check boxes */ void GuiSumsDialog::setDataFileTableSelectionCheckBoxes() { const int num = sumsDataFileList.getNumberOfSumsFiles(); if (dataFileTable->rowCount() != num) { std::cout << "PROGRAM ERROR: GuiSumsDialog check boxes different size than list file." << std::endl; return; } dataFileTable->blockSignals(true); for (int i = 0; i < num; i++) { const SumsFileInfo* sfi = sumsDataFileList.getSumsFileInfo(i); QTableWidgetItem* item = dataFileTable->item(i, DATA_TABLE_FILE_CHECK_BOX_COLUMN); if (item != NULL) { if (sfi->getSelected()) { item->setCheckState(Qt::Checked); } else { item->setCheckState(Qt::Unchecked); } } } dataFileTable->blockSignals(false); } /** * read the file selection check boxes */ void GuiSumsDialog::readDataFileTableSelectionCheckBoxes() { const int num = sumsDataFileList.getNumberOfSumsFiles(); if (dataFileTable->rowCount() != num) { std::cout << "PROGRAM ERROR: GuiSumsDialog check boxes different size than list file." << std::endl; } else { for (int i = 0; i < num; i++) { SumsFileInfo* sfi = sumsDataFileList.getSumsFileInfo(i); QTableWidgetItem* item = dataFileTable->item(i, DATA_TABLE_FILE_CHECK_BOX_COLUMN); sfi->setSelected(item->checkState() == Qt::Checked); } } } /** * called when select all files push button is pressed. */ void GuiSumsDialog::slotSelectAllDataFilesPushButton() { sumsDataFileList.setAllFileSelectionStatus(true); setDataFileTableSelectionCheckBoxes(); slotEnableDisablePushButtons(); } /** * called when deselect all files push button is pressed. */ void GuiSumsDialog::slotDeselectAllDataFilesPushButton() { sumsDataFileList.setAllFileSelectionStatus(false); setDataFileTableSelectionCheckBoxes(); slotEnableDisablePushButtons(); } /** * Set the number of rows in the table */ void GuiSumsDialog::setDataFileTableNumberOfRows(const int num) { dataFileTable->setRowCount(num); if (num > 0) { dataFileTable->blockSignals(true); for (int i = 0; i < num; i++) { QTableWidgetItem* checkItem = new QTableWidgetItem; checkItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled); checkItem->setCheckState(Qt::Checked); dataFileTable->setItem(i, DATA_TABLE_FILE_CHECK_BOX_COLUMN, checkItem); const Qt::ItemFlags flags = (Qt::ItemIsSelectable | Qt::ItemIsEnabled); QTableWidgetItem* dateItem = new QTableWidgetItem; dateItem->setFlags(flags); dataFileTable->setItem(i, DATA_TABLE_FILE_DATE_COLUMN, dateItem); QTableWidgetItem* typeItem = new QTableWidgetItem; typeItem->setFlags(flags); dataFileTable->setItem(i, DATA_TABLE_FILE_TYPE_COLUMN, typeItem); QTableWidgetItem* nameItem = new QTableWidgetItem; nameItem->setFlags(flags); dataFileTable->setItem(i, DATA_TABLE_FILE_NAME_COLUMN, nameItem); QTableWidgetItem* subDirItem = new QTableWidgetItem; subDirItem->setFlags(flags); dataFileTable->setItem(i, DATA_TABLE_FILE_SUBDIR_COLUMN, subDirItem); QTableWidgetItem* stateItem = new QTableWidgetItem; stateItem->setFlags(flags); dataFileTable->setItem(i, DATA_TABLE_FILE_STATE_COLUMN, stateItem); QTableWidgetItem* commentItem = new QTableWidgetItem; commentItem->setFlags(flags); dataFileTable->setItem(i, DATA_TABLE_FILE_COMMENT_COLUMN, commentItem); } dataFileTable->blockSignals(false); } } /** * Load the file list table */ void GuiSumsDialog::loadDataFileTable() { const int numFiles = sumsDataFileList.getNumberOfSumsFiles(); if (numFiles < 0) { setDataFileTableNumberOfRows(0); return; } setDataFileTableNumberOfRows(numFiles); for (int i = 0; i < numFiles; i++) { const SumsFileInfo* sfi = sumsDataFileList.getSumsFileInfo(i); QTableWidgetItem* dateItem = dataFileTable->item(i, DATA_TABLE_FILE_DATE_COLUMN); dateItem->setText(sfi->getDate()); QTableWidgetItem* typeItem = dataFileTable->item(i, DATA_TABLE_FILE_TYPE_COLUMN); typeItem->setText(sfi->getTypeName()); QTableWidgetItem* nameItem = dataFileTable->item(i, DATA_TABLE_FILE_NAME_COLUMN); nameItem->setText(sfi->getNameWithoutPath()); QTableWidgetItem* subDirItem = dataFileTable->item(i, DATA_TABLE_FILE_SUBDIR_COLUMN); subDirItem->setText(FileUtilities::dirname(sfi->getNameWithPath())); QTableWidgetItem* stateItem = dataFileTable->item(i, DATA_TABLE_FILE_STATE_COLUMN); stateItem->setText(sfi->getState()); QTableWidgetItem* commentItem = dataFileTable->item(i, DATA_TABLE_FILE_COMMENT_COLUMN); commentItem->setText(sfi->getComment()); } setDataFileTableSelectionCheckBoxes(); } /** * Create the output directory section. */ QWidget* GuiSumsDialog::createOutputDirectorySection() { // // Pushbutton to select directory // QPushButton* directoryPushButton = new QPushButton("Select..."); directoryPushButton->setFixedSize(directoryPushButton->sizeHint()); directoryPushButton->setAutoDefault(false); QObject::connect(directoryPushButton, SIGNAL(clicked()), this, SLOT(slotDirectoryPushButton())); // // Directory name line edit // directoryNameLineEdit = new QLineEdit; directoryNameLineEdit->setText(QDir::currentPath()); QObject::connect(directoryNameLineEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotEnableDisablePushButtons())); // // Group box and layout for output directory // QGroupBox* directoryGroupBox = new QGroupBox("Output Directory"); QHBoxLayout* dirLayout = new QHBoxLayout(directoryGroupBox); dirLayout->addWidget(directoryPushButton); dirLayout->addWidget(directoryNameLineEdit); dirLayout->addStretch(); // // Add help information // QWidget* infoWidget = addPageInformation( "Output Directory Information", "Press the \"Finish\" button to begin downloading files." "\n\n" "In the text box above, enter the name of the directory in which " "the downloaded data files should be placed. If the directory does " "not exist, it will be created. The \"Select\" button will display " "a dialog for selecting existing directories. Typically, when data " "files are downloaded, they are placed in directories named " "\"RIGHT_HEM\", \"LEFT_HEM\", or \"CEREBELLUM\"."); QWidget* w = new QWidget; QVBoxLayout* layout = new QVBoxLayout(w); layout->addWidget(directoryGroupBox); layout->addWidget(infoWidget); return w; } /** * called when output directory select push button is pressed. */ void GuiSumsDialog::slotDirectoryPushButton() { // // Pop up a file dialog for selecting a directory // WuQFileDialog fd(this); fd.setModal(true); fd.setDirectory(QDir::current()); fd.setWindowTitle("Select Directory"); fd.setFileMode(WuQFileDialog::Directory); // // Popup the dialog // if (fd.exec() == GuiSumsDialog::Accepted) { directoryNameLineEdit->setText(fd.selectedFiles().at(0)); } } /** * Insert the session ID into the URL. */ QString GuiSumsDialog::insertSessionIdIntoURL(const QString urlIn) { QString urlString(urlIn); if (sumsSessionID.isEmpty() == false) { if (urlString.isEmpty() == false) { if (DebugControl::getDebugOn()) { std::cout << "URL: " << urlString.toAscii().constData() << std::endl; } int pos = urlString.indexOf('?'); if (pos != -1) { urlString.insert(pos, sumsSessionID); } else { pos = urlString.indexOf(".do"); if (pos != -1) { urlString.insert(pos + 3, sumsSessionID); } } if (DebugControl::getDebugOn()) { std::cout << "URL with session ID: " << urlString.toAscii().constData() << std::endl; } /* if (DebugControl::getDebugOn()) { std::cout << std::endl; std::cout << "URL: " << urlString << std::endl; } QUrl url(urlString); QString fileName(url.fileName()); fileName.append(";"); fileName.append(sumsSessionID); url.setFileName(fileName); QString theURL(url); if (DebugControl::getDebugOn()) { std::cout << "Before decode: " << theURL << std::endl; } QUrl::decode(theURL); if (DebugControl::getDebugOn()) { std::cout << "After decode: " << theURL << std::endl; } urlString = theURL); if (DebugControl::getDebugOn()) { std::cout << "URL with session id: " << urlString << std::endl; } */ } } return urlString; } /** * called when the download push button is pressed. */ void GuiSumsDialog::slotFinishPushButton() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); switch (dialogMode) { case DIALOG_MODE_NONE: break; case DIALOG_MODE_ARCHIVE_ID: downloadDataFiles(); break; case DIALOG_MODE_SPEC_FILE_ID: downloadDataFiles(); break; case DIALOG_MODE_DOWNLOAD_ATLAS: downloadDataFiles(); break; case DIALOG_MODE_DOWNLOAD_SEARCH: downloadDataFiles(); break; case DIALOG_MODE_REFRESH_SPEC_FILE: break; case DIALOG_MODE_UPLOAD_FILES: uploadDataFiles(); break; } QApplication::restoreOverrideCursor(); } /** * upload data files. */ void GuiSumsDialog::uploadDataFiles() { // // Make sure we're still logged in // if (reloginToSums() == false) { return; } // // Copy list of files to upload since it may be modified when spec files are being uploaded // std::vector filesToUpload; std::vector filesNameForSums; std::vector filesType; // // Files that will need to be deleted, typically spec files since paths are removed // std::vector filesToDelete; for (int i = 0; i < static_cast(uploadFileNames.size()); i++) { const QString& name = uploadFileNames[i]; // // Is this a spec file ? // if (StringUtilities::endsWith(name, SpecFile::getSpecFileExtension())) { // // See if the user also wants to upload the spec file' data files // QApplication::restoreOverrideCursor(); QString msg(FileUtilities::basename(name)); msg.append(" is a spec file.\n" "Do you also want to upload its associated data files ?"); const bool uploadDataFilesFlag = (QMessageBox::question(this, "Question", msg, (QMessageBox::Yes | QMessageBox::No), QMessageBox::Yes) == QMessageBox::Yes); QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); if (uploadDataFilesFlag) { // // Read in the spec file // SpecFile sf; try { sf.readFile(name); } catch (FileException&) { continue; } // // Path of spec file // const QString specFilePath(FileUtilities::dirname(name)); // // Get all of the files in the spec file // std::vector dataFiles; sf.getAllDataFilesInSpecFile(dataFiles, false); // // Temp name for spec file since paths of data files need to be removed // QString tempSpecFileName("temp_spec_file_for_upload_"); tempSpecFileName.append(QString::number(i)); tempSpecFileName.append(".spec"); // // Remove the paths from all spec file data file entries // sf.removePathsFromAllFiles(); // // Write the temp spec file // try { sf.writeFile(tempSpecFileName); } catch (FileException&) { } // // Add the spec file to the list of file to update // filesToUpload.push_back(tempSpecFileName); filesNameForSums.push_back(FileUtilities::basename(name)); filesType.push_back(UPLOAD_FILE_TYPE_SPEC_FILE); filesToDelete.push_back(tempSpecFileName); // // Add path to data files' name and add to list of files to upload // for (int j = 0; j < static_cast(dataFiles.size()); j++) { const QString dataFileName(dataFiles[j]); if (dataFileName.isEmpty() == false) { QString dataFileNameFullPath(dataFileName); QFileInfo fi(dataFileName); if (fi.isRelative()) { dataFileNameFullPath = specFilePath; dataFileNameFullPath.append(QDir::separator()); dataFileNameFullPath.append(dataFileName); } filesToUpload.push_back(dataFileNameFullPath); filesNameForSums.push_back(FileUtilities::basename(dataFileNameFullPath)); filesType.push_back(UPLOAD_FILE_TYPE_SPEC_FILE_DATA_FILE); } } } else { filesToUpload.push_back(name); filesNameForSums.push_back(FileUtilities::basename(name)); filesType.push_back(UPLOAD_FILE_TYPE_OTHER_FILE); } } else if (name.isEmpty() == false) { filesToUpload.push_back(name); filesNameForSums.push_back(FileUtilities::basename(name)); filesType.push_back(UPLOAD_FILE_TYPE_OTHER_FILE); } } // // See if any of the data files are volume files // std::vector volumeDataFiles; std::vector volumeDataFileTypes; for (int i = 0; i < static_cast(filesToUpload.size()); i++) { // // Get the extension // QString ext("."); ext.append(FileUtilities::filenameExtension(filesToUpload[i])); // // If a volume file, NOTE: ignore NIFTI/MINC volumes since they are in a single file. // if ((ext == SpecFile::getAfniVolumeFileExtension()) || (ext == SpecFile::getWustlVolumeFileExtension()) || (ext == SpecFile::getAnalyzeVolumeFileExtension())) { try { // // Read in the volume' header // VolumeFile vf; vf.readFile(filesToUpload[i], VolumeFile::VOLUME_READ_HEADER_ONLY); // // Determine the name of volume's data file. // QString inputVolumeName(vf.getDataFileName()); // // See if the data does not file exist // if (QFile::exists(inputVolumeName) == false) { // // See if the gzipped version exists // QString temp(inputVolumeName); temp.append(".gz"); if (QFile::exists(temp)) { inputVolumeName.append(".gz"); volumeDataFiles.push_back(inputVolumeName); volumeDataFileTypes.push_back(filesType[i]); } else { // // Even though it is missing, add it to the list of files so that // it will be found as "missing" with all other files // volumeDataFiles.push_back(inputVolumeName); volumeDataFileTypes.push_back(filesType[i]); } } else { volumeDataFiles.push_back(inputVolumeName); volumeDataFileTypes.push_back(filesType[i]); } } catch (FileException&) { } } } // // Loop through the list of volume data files that need to be uploaded // for (unsigned int mm = 0; mm < volumeDataFiles.size(); mm++) { // // See if the volume data file is already in the list of files to upload // std::vector::iterator iter = std::find(filesToUpload.begin(), filesToUpload.end(), volumeDataFiles[mm]); if (iter != filesToUpload.end()) { // // It is already there so do not add it to the list of files // } // // See if volume data file is "gzipped" // else if (volumeDataFiles[mm].endsWith(".gz")) { // // Take off the ".gz" extension // QString volDataNameNoGZ(volumeDataFiles[mm]); // // If it exists without the ".gz" extension // iter = std::find(filesToUpload.begin(), filesToUpload.end(), volDataNameNoGZ); if (iter != filesToUpload.end()) { // // Find its offset and replace it (replacing non-gzip-name with gzip-name) // const int offset = iter - filesToUpload.begin(); filesToUpload[offset] = volumeDataFiles[mm]; filesType[offset] = volumeDataFileTypes[mm]; filesNameForSums[offset] = FileUtilities::basename(volumeDataFiles[mm]); } else { filesToUpload.push_back(volumeDataFiles[mm]); filesType.push_back(volumeDataFileTypes[mm]); filesNameForSums.push_back(FileUtilities::basename(volumeDataFiles[mm])); } } else { filesToUpload.push_back(volumeDataFiles[mm]); filesType.push_back(volumeDataFileTypes[mm]); filesNameForSums.push_back(FileUtilities::basename(volumeDataFiles[mm])); } } // // Make sure all of the files exist // QString missingMessage; for (unsigned int nn = 0; nn < filesToUpload.size(); nn++) { if (QFile::exists(filesToUpload[nn]) == false) { if (missingMessage.isEmpty()) { missingMessage = "The following files listed below are selected for upload but do not exist.\n" "If you are uploading a spec file, remove these non-existant files from\n" "the spec file prior to continuing.\n" "\n"; } missingMessage.append(filesNameForSums[nn]); const QString path(FileUtilities::dirname(filesToUpload[nn])); if (path.length() > 1) { missingMessage.append(" ("); missingMessage.append(path); missingMessage.append(")"); } missingMessage.append("\n"); } } if (missingMessage.isEmpty() == false) { // // Remove temporary files // for (int i = 0; i < static_cast(filesToDelete.size()); i++) { QFile::remove(filesToDelete[i]); } // // display error messages // QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", missingMessage); return; } // // Hide the dialog while uploading // hide(); const int numFilesToUpload = static_cast(filesToUpload.size()); // // Create a progress dialog // QProgressDialog progressDialog(this); progressDialog.setMaximum(numFilesToUpload + 1); progressDialog.setValue(0); progressDialog.setWindowTitle("Upload to SumsDB"); progressDialog.show(); QString errorMessages; QString successMessages; QTime timer; timer.start(); // // parent ID for data files associated with a spec file // QString lastSpecFileParentID; for (int i = 0; i < numFilesToUpload; i++) { // // File name without path // const QString shortFileName(filesNameForSums[i]); if (DebugControl::getDebugOn()) { std::cout << "Uploading File: " << shortFileName.toAscii().constData() << " =============================================" << std::endl; } // // Update the progress dialog // qApp->processEvents(); // note: qApp is global in QApplication if (progressDialog.wasCanceled()) { break; } const int progressFileNumber = i + 1; progressDialog.setValue(progressFileNumber); QString progressMessage("Uploading "); progressMessage.append(QString::number(progressFileNumber)); progressMessage.append(" of "); progressMessage.append(QString::number(numFilesToUpload)); progressMessage.append(" files\n"); progressMessage.append(shortFileName); progressMessage.append("\n"); progressMessage.append("Elapsed time: "); progressMessage.append(QString::number(timer.elapsed() * 0.001, 'f', 0)); progressMessage.append(" seconds."); progressDialog.setLabelText(progressMessage); // // Is this a scene file // QString tempSceneFileName; QString ext("."); ext.append(FileUtilities::filenameExtension(filesToUpload[i])); if (ext == SpecFile::getSceneFileExtension()) { try { SceneFile sceneFile; sceneFile.readFile(filesToUpload[i]); tempSceneFileName = "temp_scene_file_for_sums.scene"; sceneFile.removePathsFromAllSpecFileDataFileNames(); sceneFile.writeFile(tempSceneFileName); filesToUpload[i] = tempSceneFileName; } catch (FileException& e) { tempSceneFileName = ""; } } // // URL for uploading // QString url(databaseHostName); url.append("/sums/caretupload.do"); url.append(sumsSessionID); //url.append("&caret_xml=yes"); HttpFileDownload http(url, dataFileTimeoutSpinBox->value()); http.setUploadFileName(filesToUpload[i], filesNameForSums[i]); http.setUploadFileComment(uploadCommentLineEdit->text()); std::map headerElements; if (sumsCookie.isEmpty() == false) { headerElements["Cookie"] = sumsCookie; } http.addToRequestHeader(headerElements); // // Additional items in multipart file // std::vector additionalBodyTags, additionalBodyValues; // // Is this file a data file associated with a spec file ? // if (filesType[i] == UPLOAD_FILE_TYPE_SPEC_FILE_DATA_FILE) { if (lastSpecFileParentID.isEmpty() == false) { additionalBodyTags.push_back("parent_id"); additionalBodyValues.push_back(lastSpecFileParentID); } } // // Upload the file // http.uploadFileToSums(additionalBodyTags, additionalBodyValues); if (DebugControl::getDebugOn()) { std::cout << "------------------- received -------------------------------" << std::endl; std::cout << "Response code: " << http.getResponseCode() << std::endl; std::cout << "Error message: " << http.getErrorMessage().toAscii().constData() << std::endl; std::map headerTagsOut = http.getResponseHeader(); for (std::map::iterator pos = headerTagsOut.begin(); pos != headerTagsOut.end(); pos++) { std::cout << "Upload tag/value: " << pos->first.toAscii().constData() << " " << pos->second.toAscii().constData() << std::endl; } } if (http.getDownloadSuccessful()) { // // Response content is a Sums File List File with info about file just uploaded // QString responseContent; http.getContent(responseContent); if (DebugControl::getDebugOn()) { std::cout << "Response content: " << responseContent.toAscii().constData() << std::endl; std::cout << std::endl; } SumsFileListFile flf; // flf.readFileFromString(responseContent); try { flf.readFileFromArray(responseContent.toAscii().constData(), responseContent.length(), "sums_upload_file.dat"); } catch (FileException& e) { errorMessages.append(e.whatQString()); } if (flf.getNumberOfSumsFiles() != 1) { QString msg("Failed (response content != 1): "); msg.append(shortFileName); msg.append("\n"); std::cout << "ERROR " << msg.toAscii().constData(); errorMessages.append(msg); } else { const SumsFileInfo* sfi = flf.getSumsFileInfo(0); switch (filesType[i]) { case UPLOAD_FILE_TYPE_SPEC_FILE: { lastSpecFileParentID = sfi->getID(); successMessages.append("Spec File: "); successMessages.append(shortFileName); successMessages.append(" ID = "); successMessages.append(lastSpecFileParentID); successMessages.append("\n"); } break; case UPLOAD_FILE_TYPE_OTHER_FILE: successMessages.append("File: "); successMessages.append(shortFileName); successMessages.append(" ID = "); successMessages.append(sfi->getID()); successMessages.append("\n"); lastSpecFileParentID = ""; break; case UPLOAD_FILE_TYPE_SPEC_FILE_DATA_FILE: break; } } } else { QString msg("Failed (download unsuccessful): "); msg.append(shortFileName); msg.append("\n"); std::cout << "ERROR " << msg.toAscii().constData(); errorMessages.append(msg); } if (tempSceneFileName.isEmpty() == false) { QFile::remove(tempSceneFileName); } } QString timeMsg("Total upload time: "); timeMsg.append(StringUtilities::fromNumber(timer.elapsed() * 0.001)); timeMsg.append("\n"); // // Show the dialog since it was hidden // show(); // // Remove the progress dialog // progressDialog.cancel(); if (errorMessages.isEmpty()) { timeMsg.append("All files were successfully uploaded.\n"); timeMsg.append(successMessages); QMessageBox::information(this, "SUCCESS", timeMsg); } else { QString msg(errorMessages); if (successMessages.isEmpty() == false) { successMessages.append("\n"); successMessages.append("The following files were successfully uploaded\n"); successMessages.append("(does not include data files in a spec file):\n"); successMessages.append(successMessages); } QMessageBox::critical(this, "ERROR", errorMessages); } // // Remove temporary files // for (int i = 0; i < static_cast(filesToDelete.size()); i++) { QFile::remove(filesToDelete[i]); } } /** * download data files. */ void GuiSumsDialog::downloadDataFiles() { // // Make sure we're still logged in // if (reloginToSums() == false) { return; } // // Number of items in table and in sums list file must match // const int numFiles = sumsDataFileList.getNumberOfSumsFiles(); if (numFiles != dataFileTable->rowCount()) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", "PROGRAM ERROR: number of rows in table does not match number in sums list file"); return; } // // Determine number of files that are to be downloaded // readDataFileTableSelectionCheckBoxes(); int numFilesToDownload = 0; for (int i = 0; i < numFiles; i++) { if (sumsDataFileList.getSumsFileInfo(i)->getSelected()) { numFilesToDownload++; } } // // Save the current directory // const QString savedDirectory(QDir::currentPath()); // // Create the output directory if necessary // const QString outputDirectoryName = directoryNameLineEdit->text(); if (QFile::exists(outputDirectoryName) == false) { QString msg("Create Directory "); msg.append(outputDirectoryName); QApplication::restoreOverrideCursor(); if (QMessageBox::question(this, "Create Directory", msg, (QMessageBox::Yes | QMessageBox::No), QMessageBox::Yes) == QMessageBox::No) { return; } if (FileUtilities::createDirectory(outputDirectoryName) == false) { QString msg("Unable to create directory: \n"); msg.append(outputDirectoryName); QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", msg); return; } } // // Hide the dialog while uploading // hide(); // // Set to the output directory // QDir::setCurrent(outputDirectoryName); // // Create a progress dialog // QProgressDialog progressDialog(this); progressDialog.setMaximum(numFilesToDownload + 1); progressDialog.setValue(0); progressDialog.setWindowTitle("Download from SumsDB"); progressDialog.show(); QString errorMessages; QTime timer; timer.start(); // // loop through each file // int progressFileNumber = 0; for (int i = 0; i < numFiles; i++) { // // Is file selected for download // if (sumsDataFileList.getSumsFileInfo(i)->getSelected()) { const SumsFileInfo* sfi = sumsDataFileList.getSumsFileInfo(i); const QString name(sfi->getNameWithPath()); QString url(sfi->getURL()); // // Add the session ID to the URL // url = insertSessionIdIntoURL(url); // // Update the progress dialog // qApp->processEvents(); // note: qApp is global in QApplication if (progressDialog.wasCanceled()) { break; } progressDialog.setValue(progressFileNumber); progressFileNumber++; QString progressMessage("Downloading "); progressMessage.append(QString::number(progressFileNumber)); progressMessage.append(" of "); progressMessage.append(QString::number(numFilesToDownload)); progressMessage.append(" files\n"); progressMessage.append(name); progressMessage.append("\n"); progressMessage.append("Elapsed time: "); progressMessage.append(QString::number(timer.elapsed() * 0.001, 'f', 0)); progressMessage.append(" seconds."); progressDialog.setLabelText(progressMessage); // // See if files will be gzipped // QString downloadName(name); bool gzipFlag = false; if (url.indexOf("downloadgzip") != -1) { gzipFlag = true; downloadName.append(".gz"); } // // See if a subdirectory needs to be created, and, if so, create it // const QString subDir(FileUtilities::dirname(downloadName)); if (DebugControl::getDebugOn()) { std::cout << "download name: " << downloadName.toAscii().constData() << " path: " << subDir.toAscii().constData() << std::endl; } if (subDir.isEmpty() == false) { if ((subDir != ".") && (subDir != "..")) { QString subDirPath(outputDirectoryName); subDirPath.append(QDir::separator()); subDirPath.append(subDir); if (QFile::exists(subDirPath) == false) { if (FileUtilities::createDirectory(subDirPath) == false) { QString msg("Unable to create directory: \n"); msg.append(subDirPath); QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", msg); show(); return; } } } } // // If the file fails to download the first time, try it again // const int maxTimes = downloadNumTimesSpinBox->value(); for (int k = 0; k < maxTimes; k++) { // // Download the file // QString downloadErrorMessage; const bool fileOK = FileUtilities::downloadFileWithHttpGet(url, downloadName, dataFileTimeoutSpinBox->value(), downloadErrorMessage); // // File failed to download // if (fileOK == false) { if (errorMessages.isEmpty() == false) { errorMessages.append("\n"); } QString msg(FileUtilities::basename(name)); msg.append(" "); msg.append(downloadErrorMessage); errorMessages.append(msg); } else { // // Was a gzip file requested // if (gzipFlag) { // // gunzip the file // if (FileUtilities::gunzipFile(downloadName, name)) { // // Remove the gzipped file // QFile::remove(downloadName); // // Is gunzipped file the correct size ? // QFileInfo fi(name); if (fi.size() == static_cast(sfi->getSize())) { // // File OK, get out of loop // k = maxTimes; // // See if a spec file // if (StringUtilities::endsWith(name, SpecFile::getSpecFileExtension())) { if (preferencesFile != NULL) { QString s(outputDirectoryName); s.append("/"); s.append(name); preferencesFile->addToRecentSpecFiles(s, true); } } } // // Was this the last try // else if (k == (maxTimes - 1)) { // // File failed // if (errorMessages.isEmpty() == false) { errorMessages.append("\n"); } QString msg("Download error - incorrect size: "); msg.append(sfi->getNameWithoutPath()); errorMessages.append(msg); } else { std::cout << "Info: download of " << sfi->getNameWithoutPath().toAscii().constData() << " failed. Will try again." << std::endl; std::cout << " Size: " << fi.size() << " SumsDB size: " << sfi->getSize() << std::endl; } } } // // File is not gzipped // else { // // File OK, get out of loop // k = maxTimes; // // See if a spec file // if (StringUtilities::endsWith(name, SpecFile::getSpecFileExtension())) { if (preferencesFile != NULL) { QString s(outputDirectoryName); s.append("/"); s.append(name); preferencesFile->addToRecentSpecFiles(s, true); } } } } } } } // // Hide the dialog while uploading // show(); QString timeMsg("Total download time: "); timeMsg.append(StringUtilities::fromNumber(timer.elapsed() * 0.001)); timeMsg.append("\n"); // // Restore the saved directory // QDir::setCurrent(savedDirectory); // // Remove the progress dialog // progressDialog.cancel(); if (errorMessages.isEmpty()) { timeMsg.append("All files were successfully downloaded."); QApplication::restoreOverrideCursor(); QMessageBox::information(this, "SUCCESS", timeMsg); } else { timeMsg.append(errorMessages); QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", timeMsg); } } /** * Get a list of spec files */ bool GuiSumsDialog::getSumsSpecFileListing() { // // Make sure we're still logged in // if (reloginToSums() == false) { return false; } // // Clear the file list and the data file table // sumsSpecFileList.clear(); setSpecFileTableNumberOfRows(0); QString url; switch (dialogMode) { case DIALOG_MODE_NONE: break; case DIALOG_MODE_ARCHIVE_ID: break; case DIALOG_MODE_SPEC_FILE_ID: break; case DIALOG_MODE_DOWNLOAD_ATLAS: url = databaseHostName; url.append("/sums/advancedsearch.do"); url.append(sumsSessionID); url.append("?property_label=category&property_value=ATLAS"); if (downloadAtlasSpeciesComboBox->currentIndex() > 0) { appendParameterToURL(url, "property_label", "species"); appendParameterToURL(url, "property_value", downloadAtlasSpeciesComboBox->currentText()); } if (downloadAtlasHemisphereComboBox->currentIndex() > 0) { appendParameterToURL(url, "property_label", "hem_flag"); appendParameterToURL(url, "property_value", downloadAtlasHemisphereComboBox->currentText()); } if (downloadAtlasSpaceComboBox->currentIndex() > 0) { appendParameterToURL(url, "property_label", "space"); appendParameterToURL(url, "property_value", downloadAtlasSpaceComboBox->currentText()); } appendParameterToURL(url, "caret_xml", "yes"); break; case DIALOG_MODE_DOWNLOAD_SEARCH: { url = databaseHostName; url.append("/sums/advancedsearch.do"); url.append(sumsSessionID); url.append("?filetype=spec"); appendSearchParametersToURL(url, true); /* const QString searchName(downloadSearchFileNameLineEdit->text()); if (searchName.empty() == false) { appendParameterToURL(url, "filename", searchName); } if (downloadSearchSpeciesComboBox->currentIndex() > 0) { appendParameterToURL(url, "property_label", "species"); appendParameterToURL(url, "property_value", downloadSearchSpeciesComboBox->currentText()); } if (downloadSearchHemisphereComboBox->currentIndex() > 0) { appendParameterToURL(url, "property_label", "hem_flag"); appendParameterToURL(url, "property_value", downloadSearchHemisphereComboBox->currentText()); } if (downloadSearchSpaceComboBox->currentIndex() > 0) { appendParameterToURL(url, "property_label", "space"); appendParameterToURL(url, "property_value", downloadSearchSpaceComboBox->currentText()); } appendParameterToURL(url, "caret_xml", "yes"); */ } break; case DIALOG_MODE_REFRESH_SPEC_FILE: break; case DIALOG_MODE_UPLOAD_FILES: break; } if (url.isEmpty()) { QMessageBox::critical(this, "Program Error", "Spec File Listing URL is empty."); return false; } if (DebugControl::getDebugOn()) { std::cout << "Spec File URL: " << url.toAscii().constData() << std::endl; } // // Get the archives list of files // QString contents; QString errorMessage; std::map headerTags; if (FileUtilities::downloadFileWithHttpGet(url, searchTimeoutSpinBox->value(), contents, errorMessage, &headerTags) == false) { QMessageBox::critical(this, "ERROR", errorMessage); return false; } // Parse the file listing // try { //sumsSpecFileList.readFileFromString(contents); sumsSpecFileList.readFileFromArray(contents.toAscii().constData(), contents.length(), "sums_file_list.dat"); } catch (FileException& e) { QMessageBox::critical(this, "ERROR", e.whatQString()); return false; } if (sumsSpecFileList.getNumberOfSumsFiles() <= 0) { QMessageBox::critical(this, "ERROR", "No matches found."); return false; } // // Default to no file selected // sumsSpecFileList.setAllFileSelectionStatus(false); // // Load the data file table // loadSpecFileTable(); return true; } /** * Append a parameter and its value to a URL. */ void GuiSumsDialog::appendParameterToURL(QString& url, const QString& paramName, const QString& paramValue) { if (paramName.isEmpty() || paramValue.isEmpty()) { return; } const int len = url.length(); if (len > 0) { const QCharRef lastChar = url[len - 1]; if (lastChar != '?') { url.append("&"); } url.append(paramName); url.append("="); url.append(paramValue); } } /** * Append search parameters onto the URL. */ void GuiSumsDialog::appendSearchParametersToURL(QString& url, const bool specFileSearch) { // // add on file name search // appendParameterToURL(url, "filename", downloadSearchFileNameLineEdit->text()); // // add on keyword search // appendParameterToURL(url, "keyword", downloadSearchKeywordLineEdit->text()); // // add on comment search // const QString comment(downloadSearchFileCommentLineEdit->text()); if (comment.isEmpty() == false) { appendParameterToURL(url, "property_name", "comment"); appendParameterToURL(url, "property_value", comment); } // // Are we searching for something OTHER than a spec file // if (specFileSearch == false) { const int item = downloadSearchFileTypeComboBox->currentIndex(); if (item > SEARCH_FILE_INDEX_ALL_EXCEPT_SPEC) { if ((item >= 0) && (item < downloadSearchFileTypeComboBox->count())) { appendParameterToURL(url, "filetype", downloadSearchFileExtensions[item]); } } } // // Area we searching for spec files // if (specFileSearch) { // // Add species search // if (downloadSearchSpeciesComboBox->currentIndex() > 0) { appendParameterToURL(url, "property_label", "species"); appendParameterToURL(url, "property_value", downloadSearchSpeciesComboBox->currentText()); } // // Add hemisphere search // if (downloadSearchHemisphereComboBox->currentIndex() > 0) { appendParameterToURL(url, "property_label", "hem_flag"); appendParameterToURL(url, "property_value", downloadSearchHemisphereComboBox->currentText()); } // // add space search // if (downloadSearchSpaceComboBox->currentIndex() > 0) { appendParameterToURL(url, "property_label", "space"); appendParameterToURL(url, "property_value", downloadSearchSpaceComboBox->currentText()); } } // // Add date search // if (downloadSearchDateCheckBox->isChecked()) { appendParameterToURL(url, "useDate", "true"); const QDate startDate = downloadSearchStartDateEdit->date(); appendParameterToURL(url, "minMonth", startDate.toString("MM")); appendParameterToURL(url, "minDay", startDate.toString("dd")); appendParameterToURL(url, "minYear", startDate.toString("yyyy")); const QDate endDate = downloadSearchEndDateEdit->date(); appendParameterToURL(url, "maxMonth", endDate.toString("MM")); appendParameterToURL(url, "maxDay", endDate.toString("dd")); appendParameterToURL(url, "maxYear", endDate.toString("yyyy")); } // // Want our results in XML format // appendParameterToURL(url, "caret_xml", "yes"); } /** * Create the listing of spec files. */ QWidget* GuiSumsDialog::createSpecFileListSection() { // // Table containing list of files // specFileTable = new QTableWidget; QObject::connect(specFileTable, SIGNAL(cellChanged(int,int)), this, SLOT(slotSpecFileTableItemChanged(int,int))); specFileTable->setColumnCount(SPEC_TABLE_NUMBER_OF_COLUMNS); // QT4 specFileTable->setColumnReadOnly(SPEC_TABLE_FILE_DATE_COLUMN, true); // specFileTable->setColumnReadOnly(SPEC_TABLE_FILE_NAME_COLUMN, true); // specFileTable->setColumnReadOnly(SPEC_TABLE_FILE_COMMENT_COLUMN, true); specFileTable->setColumnWidth(SPEC_TABLE_FILE_NAME_COLUMN, 500); specFileTable->setColumnWidth(SPEC_TABLE_FILE_COMMENT_COLUMN, 500); // // Spec file table headers // QHeaderView* header = specFileTable->horizontalHeader(); QObject::connect(header, SIGNAL(sectionClicked(int)), this, SLOT(slotSpecFileTableHeaderColumnClicked(int))); // // Set column header labels // QStringList headerLabels; headerLabels << "Download"; headerLabels << "Date"; headerLabels << "Spec File Name"; headerLabels << "Comment"; specFileTable->setHorizontalHeaderLabels(headerLabels); //header->setLabel(SPEC_TABLE_FILE_CHECK_BOX_COLUMN, "Download"); //header->setLabel(SPEC_TABLE_FILE_DATE_COLUMN, "Date"); //header->setLabel(SPEC_TABLE_FILE_NAME_COLUMN, "Spec File Name"); //header->setLabel(SPEC_TABLE_FILE_COMMENT_COLUMN, "Comment"); // // Group box and layout for spec file selections // QGroupBox* specGroupBox = new QGroupBox("Spec File Selections"); QVBoxLayout* specGroupLayout = new QVBoxLayout(specGroupBox); specGroupLayout->addWidget(specFileTable); // // Add help information // QWidget* infoWidget = addPageInformation( "Spec Files Information", "Select one spec file. The next page will list the data files " "associated with the selected spec file."); QWidget* w = new QWidget; QVBoxLayout* layout = new QVBoxLayout(w); layout->addWidget(specGroupBox); layout->addWidget(infoWidget); return w; } /** * Called when a spec file header column is clicked for sorting. */ void GuiSumsDialog::slotSpecFileTableHeaderColumnClicked(int item) { switch (item) { case SPEC_TABLE_FILE_CHECK_BOX_COLUMN: break; case SPEC_TABLE_FILE_DATE_COLUMN: sumsSpecFileList.sort(SumsFileListFile::SORT_ORDER_DATE); loadSpecFileTable(); break; case SPEC_TABLE_FILE_NAME_COLUMN: sumsSpecFileList.sort(SumsFileListFile::SORT_ORDER_NAME); loadSpecFileTable(); break; case SPEC_TABLE_FILE_COMMENT_COLUMN: break; case SPEC_TABLE_NUMBER_OF_COLUMNS: break; } } /** * Called when a spec file table item is changed. */ void GuiSumsDialog::slotSpecFileTableItemChanged(int row, int col) { if (col == SPEC_TABLE_FILE_CHECK_BOX_COLUMN) { // // Make the check boxes behave like radio buttons (mutually exclusive) // sumsSpecFileList.setAllFileSelectionStatus(false); SumsFileInfo* sfi = sumsSpecFileList.getSumsFileInfo(row); sfi->setSelected(true); setSpecFileTableSelectionCheckBoxes(); } slotEnableDisablePushButtons(); } /** * Set the number of rows in the spec file table. */ void GuiSumsDialog::setSpecFileTableNumberOfRows(const int num) { specFileTable->setRowCount(num); specFileTable->blockSignals(true); if (num > 0) { for (int i = 0; i < num; i++) { QTableWidgetItem* checkItem = new QTableWidgetItem; checkItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled); checkItem->setCheckState(Qt::Checked); specFileTable->setItem(i, SPEC_TABLE_FILE_CHECK_BOX_COLUMN, checkItem); const Qt::ItemFlags flags = (Qt::ItemIsSelectable | Qt::ItemIsEnabled); QTableWidgetItem* dateItem = new QTableWidgetItem; dateItem->setFlags(flags); specFileTable->setItem(i, SPEC_TABLE_FILE_DATE_COLUMN, dateItem); QTableWidgetItem* nameItem = new QTableWidgetItem; nameItem->setFlags(flags); specFileTable->setItem(i, SPEC_TABLE_FILE_NAME_COLUMN, nameItem); QTableWidgetItem* commentItem = new QTableWidgetItem; commentItem->setFlags(flags); specFileTable->setItem(i, SPEC_TABLE_FILE_COMMENT_COLUMN, commentItem); } } specFileTable->blockSignals(false); } /** * load the spec file table. */ void GuiSumsDialog::loadSpecFileTable() { const int numFiles = sumsSpecFileList.getNumberOfSumsFiles(); if (numFiles < 0) { setSpecFileTableNumberOfRows(0); return; } setSpecFileTableNumberOfRows(numFiles); specFileTable->blockSignals(true); for (int i = 0; i < numFiles; i++) { const SumsFileInfo* sfi = sumsSpecFileList.getSumsFileInfo(i); QTableWidgetItem* dateItem = specFileTable->item(i, SPEC_TABLE_FILE_DATE_COLUMN); dateItem->setText(sfi->getDate()); QTableWidgetItem* nameItem = specFileTable->item(i, SPEC_TABLE_FILE_NAME_COLUMN); nameItem->setText(sfi->getNameWithoutPath()); QTableWidgetItem* commentItem = specFileTable->item(i, SPEC_TABLE_FILE_COMMENT_COLUMN); commentItem->setText(sfi->getComment()); } specFileTable->blockSignals(false); setSpecFileTableSelectionCheckBoxes(); } /** * set the spec file selection check boxes. */ void GuiSumsDialog::setSpecFileTableSelectionCheckBoxes() { const int num = specFileTable->rowCount(); if (num != sumsSpecFileList.getNumberOfSumsFiles()) { std::cout << "PROGRAM ERROR: spec file table not same as sumsSpecFileList" << std::endl; return; } specFileTable->blockSignals(true); for (int i = 0; i < num; i++) { SumsFileInfo* sfi = sumsSpecFileList.getSumsFileInfo(i); QTableWidgetItem* item = specFileTable->item(i, SPEC_TABLE_FILE_CHECK_BOX_COLUMN); if (item != NULL) { if (sfi->getSelected()) { item->setCheckState(Qt::Checked); } else { item->setCheckState(Qt::Unchecked); } } } specFileTable->blockSignals(false); } /** * Get a SuMS data file listing. Returns true if listing is valid */ bool GuiSumsDialog::getSumsDataFileListing(const QString& specFileID) { // // Make sure we're still logged in // if (reloginToSums() == false) { return false; } bool excludeSpecFiles = false; bool deselectAllDataFiles = false; bool removeAllPaths = false; // // Clear the file list and the data file table // sumsDataFileList.clear(); setDataFileTableNumberOfRows(0); // // Set the archive's URL based upon the mode // QString archiveURL; switch (dialogMode) { case DIALOG_MODE_NONE: break; case DIALOG_MODE_ARCHIVE_ID: archiveURL = databaseHostName; archiveURL.append("/sums/archivelist.do"); archiveURL.append(sumsSessionID); archiveURL.append("?"); appendParameterToURL(archiveURL, "archive_id", downloadArchiveNumberLineEdit->text()); appendParameterToURL(archiveURL, "caret_xml", "yes"); break; case DIALOG_MODE_SPEC_FILE_ID: archiveURL = databaseHostName; archiveURL.append("/sums/specfile.do"); archiveURL.append(sumsSessionID); archiveURL.append("?"); appendParameterToURL(archiveURL, "archive_id", downloadSpecNumberLineEdit->text()); appendParameterToURL(archiveURL, "caret_xml", "yes"); break; case DIALOG_MODE_DOWNLOAD_ATLAS: archiveURL = databaseHostName; archiveURL.append("/sums/specfile.do"); archiveURL.append(sumsSessionID); archiveURL.append("?"); appendParameterToURL(archiveURL, "filetype", "spec"); appendParameterToURL(archiveURL, "state", "active"); appendParameterToURL(archiveURL, "archive_id", specFileID); appendParameterToURL(archiveURL, "caret_xml", "yes"); break; case DIALOG_MODE_DOWNLOAD_SEARCH: { const int item = downloadSearchFileTypeComboBox->currentIndex(); if (item == SEARCH_FILE_INDEX_SPEC) { // // Get a spec file's data files. // archiveURL = databaseHostName; archiveURL.append("/sums/specfile.do"); archiveURL.append(sumsSessionID); archiveURL.append("?"); appendParameterToURL(archiveURL, "filetype", "spec"); appendParameterToURL(archiveURL, "state", "active"); appendParameterToURL(archiveURL, "archive_id", specFileID); appendParameterToURL(archiveURL, "caret_xml", "yes"); } else { excludeSpecFiles = true; deselectAllDataFiles = true; removeAllPaths = true; archiveURL = databaseHostName; archiveURL.append("/sums/advancedsearch.do"); archiveURL.append(sumsSessionID); archiveURL.append("?"); appendSearchParametersToURL(archiveURL, false); /* const QString searchName(downloadSearchFileNameLineEdit->text()); if (searchName.empty() == false) { appendParameterToURL(archiveURL, "filename", searchName); } if ((item >= 0) && (item < downloadSearchFileTypeComboBox->count())) { const QString searchExt(downloadSearchFileExtensions[item]); if (searchExt.empty() == false) { appendParameterToURL(archiveURL, "filetype", searchExt); } } appendParameterToURL(archiveURL, "caret_xml", "yes"); */ } } break; case DIALOG_MODE_REFRESH_SPEC_FILE: break; case DIALOG_MODE_UPLOAD_FILES: break; } if (archiveURL.isEmpty()) { QMessageBox::critical(this, "Program Error", "Archive URL is empty."); return false; } if (DebugControl::getDebugOn()) { std::cout << "Search URL: " << archiveURL.toAscii().constData() << std::endl; } // // Get the archives list of files // QString contents; QString errorMessage; std::map headerTags; if (FileUtilities::downloadFileWithHttpGet(archiveURL, searchTimeoutSpinBox->value(), contents, errorMessage, &headerTags) == false) { QMessageBox::critical(this, "ERROR", errorMessage); return false; } // // if debugging print the file received // if (DebugControl::getDebugOn()) { std::cout << std::endl; std::cout << "spec listing length " << contents.length() << std::endl; std::cout << contents.toAscii().constData() << std::endl; std::cout << std::endl; } // // Parse the file listing // try { if (excludeSpecFiles) { sumsDataFileList.setExcludeSpecFileFlag(excludeSpecFiles); } // sumsDataFileList.readFileFromString(contents); sumsDataFileList.readFileFromArray(contents.toAscii().constData(), contents.length(), "sums_data_file_list.dat"); if (deselectAllDataFiles) { sumsDataFileList.setAllFileSelectionStatus(false); } if (removeAllPaths) { sumsDataFileList.removePathsFromAllFiles(); } } catch (FileException& e) { QMessageBox::critical(this, "ERROR", e.whatQString()); return false; } if (sumsDataFileList.getNumberOfSumsFiles() <= 0) { QMessageBox::critical(this, "ERROR", "File does not exist in SumsDB"); return false; } // // If the files the same directory prefix, remove it from the files and // add it onto the current directory and place in output directory line edit. // const QString prefix(sumsDataFileList.getCommonSubdirectoryPrefix()); if (prefix.isEmpty() == false) { sumsDataFileList.removeSubdirectoryPrefix(); QString outputDir = QDir::currentPath(); outputDir.append(QDir::separator()); outputDir.append(prefix); directoryNameLineEdit->blockSignals(true); directoryNameLineEdit->setText(outputDir); directoryNameLineEdit->blockSignals(false); } // // Load the data file table // loadDataFileTable(); return true; } /** * Called to select the back page. */ void GuiSumsDialog::slotBackPushButton() { QWidget* currentPage = pagesStackedWidget->currentWidget(); QWidget* prevPage = NULL; if (currentPage == pageDatabaseLogin) { } else if (currentPage == pageDatabaseUserInformation) { prevPage = pageDatabaseLogin; } else if (currentPage == pageDatabaseMode) { prevPage = pageDatabaseUserInformation; } else if (currentPage == pageDownloadAtlas) { prevPage = pageDatabaseMode; } else if (currentPage == pageDownloadSearch) { prevPage = pageDatabaseMode; } else if (currentPage == pageRefreshSpecFile) { prevPage = pageDatabaseMode; } else if (currentPage == pageUploadFiles) { prevPage = pageDatabaseMode; } else if (currentPage == pageSpecFileSelection) { switch (dialogMode) { case DIALOG_MODE_NONE: break; case DIALOG_MODE_ARCHIVE_ID: break; case DIALOG_MODE_SPEC_FILE_ID: break; case DIALOG_MODE_DOWNLOAD_ATLAS: prevPage = pageDownloadAtlas; break; case DIALOG_MODE_DOWNLOAD_SEARCH: prevPage = pageDownloadSearch; break; case DIALOG_MODE_REFRESH_SPEC_FILE: break; case DIALOG_MODE_UPLOAD_FILES: break; } } else if (currentPage == pageDataFileSelection) { switch (dialogMode) { case DIALOG_MODE_NONE: break; case DIALOG_MODE_ARCHIVE_ID: prevPage = pageDatabaseMode; break; case DIALOG_MODE_SPEC_FILE_ID: prevPage = pageDatabaseMode; break; case DIALOG_MODE_DOWNLOAD_ATLAS: prevPage = pageSpecFileSelection; break; case DIALOG_MODE_DOWNLOAD_SEARCH: prevPage = pageDownloadSearch; break; case DIALOG_MODE_REFRESH_SPEC_FILE: break; case DIALOG_MODE_UPLOAD_FILES: break; } } else if (currentPage == pageOutputDirectory) { switch (dialogMode) { case DIALOG_MODE_NONE: break; case DIALOG_MODE_ARCHIVE_ID: prevPage = pageDataFileSelection; break; case DIALOG_MODE_SPEC_FILE_ID: prevPage = pageDataFileSelection; break; case DIALOG_MODE_DOWNLOAD_ATLAS: prevPage = pageDataFileSelection; break; case DIALOG_MODE_DOWNLOAD_SEARCH: prevPage = pageDataFileSelection; break; case DIALOG_MODE_REFRESH_SPEC_FILE: break; case DIALOG_MODE_UPLOAD_FILES: break; } } if (prevPage != NULL) { showPage(prevPage); } slotEnableDisablePushButtons(); } /** * Called to select the next page. */ void GuiSumsDialog::slotNextPushButton() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); QWidget* currentPage = pagesStackedWidget->currentWidget(); // // Determine the next page for display // QWidget* nextPage = NULL; if (currentPage == pageDatabaseLogin) { sumsSessionID = ""; sumsCookie = ""; uploadButtonValid = false; dialogMode = DIALOG_MODE_NONE; modeDownloadArchiveRadioButton->setChecked(false); modeDownloadSpecRadioButton->setChecked(false); modeDownloadAtlasRadioButton->setChecked(false); modeDownloadSearchRadioButton->setChecked(false); modeRefreshSpecRadioButton->setChecked(false); modeUploadFilesRadioButton->setChecked(false); databaseUserName = databaseUserNameLineEdit->text(); databasePassword = databasePasswordLineEdit->text(); databaseHostName = ""; const int hostIndex = databaseSelectionComboBox->currentIndex(); if (hostIndex >= 0) { databaseHostName = availableDatabaseHostNames[hostIndex]; } if (databaseHostName.isEmpty()) { QMessageBox::critical(this, "ERROR", "No Hostname is selected."); return; } // // Login to SuMS successful ? // if (loginToSums()) { if (preferencesFile != NULL) { // // save login to preferences // preferencesFile->setSumsDatabaseDataFileTimeout(dataFileTimeoutSpinBox->value()); preferencesFile->setSumsLoginInformation(databaseUserName, databasePassword, databaseHostName, loginUserNameRadioButton->isChecked(), saveLoginCheckBox->isChecked()); try { preferencesFile->writeFile(preferencesFile->getFileName()); } catch (FileException&) { } // // Set the next page // nextPage = pageDatabaseUserInformation; } } } else if (currentPage == pageDatabaseUserInformation) { nextPage = pageDatabaseMode; } else if (currentPage == pageDatabaseMode) { switch (dialogMode) { case DIALOG_MODE_NONE: break; case DIALOG_MODE_ARCHIVE_ID: if (getSumsDataFileListing()) { nextPage = pageDataFileSelection; } break; case DIALOG_MODE_SPEC_FILE_ID: if (getSumsDataFileListing()) { nextPage = pageDataFileSelection; } break; case DIALOG_MODE_DOWNLOAD_ATLAS: nextPage = pageDownloadAtlas; break; case DIALOG_MODE_DOWNLOAD_SEARCH: nextPage = pageDownloadSearch; break; case DIALOG_MODE_REFRESH_SPEC_FILE: nextPage = pageRefreshSpecFile; break; case DIALOG_MODE_UPLOAD_FILES: nextPage = pageUploadFiles; break; } } else if (currentPage == pageDownloadAtlas) { if (getSumsSpecFileListing()) { nextPage = pageSpecFileSelection; } } else if (currentPage == pageDownloadSearch) { if (downloadSearchFileTypeComboBox->currentIndex() == SEARCH_FILE_INDEX_SPEC) { if (getSumsSpecFileListing()) { nextPage = pageSpecFileSelection; } } else { if (getSumsDataFileListing()) { nextPage = pageDataFileSelection; } } } else if (currentPage == pageRefreshSpecFile) { nextPage = NULL; } else if (currentPage == pageUploadFiles) { // // last page for uploading files // nextPage = NULL; } else if (currentPage == pageSpecFileSelection) { for (int i = 0; i < sumsSpecFileList.getNumberOfSumsFiles(); i++) { SumsFileInfo* sfi = sumsSpecFileList.getSumsFileInfo(i); if (sfi->getSelected()) { if (getSumsDataFileListing(sfi->getID())) { nextPage = pageDataFileSelection; } break; } } } else if (currentPage == pageDataFileSelection) { nextPage = pageOutputDirectory; } else if (currentPage == pageOutputDirectory) { // // last page for downloading files // nextPage = NULL; } /* if (currentPage == pageSpecFileSelection) { nextPageValid = false; for (int i = 0; i < sumsSpecFileList.getNumberOfSumsFiles(); i++) { SumsFileInfo* sfi = sumsSpecFileList.getSumsFileInfo(i); if (sfi->getSelected()) { nextPageValid = getSumsDataFileListing(sfi->getID()); break; } } } */ // // Should the next page be shown ? // if (nextPage != NULL) { showPage(nextPage); } slotEnableDisablePushButtons(); QApplication::restoreOverrideCursor(); } /** * Login to SuMS. Returns true if login is successful. */ bool GuiSumsDialog::loginToSums() { loginInfoFile.clear(); loginInfoFile.setRootXmlElementTagName("sums"); // // URL for initial login // QString url(databaseHostName); url.append("/sums/logon.do"); // // Send the URL // QString contents; QString errorMessage; std::map headerTagsOut; int responseCode = -1; FileUtilities::downloadFileWithHttpGet(url, searchTimeoutSpinBox->value(), contents, errorMessage, &headerTagsOut, &responseCode); if (responseCode != 302) { QString msg("Initial login attemp failed (login.do). Try again.\n"); msg.append(errorMessage); QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", msg); return false; } else { // // Get the session ID // if (headerTagsOut.find("set-cookie") != headerTagsOut.end()) { sumsSessionID = headerTagsOut["set-cookie"]; } else if (headerTagsOut.find("Set-Cookie") != headerTagsOut.end()) { sumsSessionID = headerTagsOut["Set-Cookie"]; } else { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", "Unable to find header tag " "\"Set-Cookie\" or \"set-cookie\" that is returned by SumsDB"); return false; } sumsCookie = ""; if (DebugControl::getDebugOn()) { std::cout << "Session ID tag: " << sumsSessionID.toAscii().constData() << std::endl; } if (sumsSessionID.isEmpty() == false) { std::vector tokens; StringUtilities::token(sumsSessionID, ";", tokens); if (tokens.empty() == false) { sumsCookie = tokens[0]; sumsSessionID = tokens[0]; StringUtilities::token(sumsSessionID, "=", tokens); if (tokens.size() >= 2) { sumsSessionID = ";"; sumsSessionID.append(StringUtilities::makeLowerCase(tokens[0])); sumsSessionID.append("="); sumsSessionID.append(tokens[1]); } else { sumsSessionID = ""; } } else { sumsSessionID = ""; } } if (DebugControl::getDebugOn()) { std::cout << "SessionID: (" << sumsSessionID.toAscii().constData() << ")" << std::endl; std::cout << "Cookie: (" << sumsCookie.toAscii().constData() << ")" << std::endl; } // // Are we just a vistor that does not need to login ? // All that is needed is the session ID // if (loginVisitorRadioButton->isChecked()) { return true; } // // Next request is a post, so setup post data that contains login information // QString password(databasePassword); password = QUrl::toPercentEncoding(password); //Q3Url::encode(password); QString postContents; std::ostringstream str; str << "j_username=" << databaseUserName.toAscii().constData() << "&" << "j_password=" << password.toAscii().constData() << "&form=login"; const QString postData(str.str().c_str()); // // URL for second phase of login // url = databaseHostName; url.append("/sums/login/j_security_check"); if (sumsSessionID.isEmpty() == false) { url.append(sumsSessionID); } // // Make the request // FileUtilities::downloadFileWithHttpPost(url, postData, searchTimeoutSpinBox->value(), postContents, errorMessage, NULL, &headerTagsOut, &responseCode); if (DebugControl::getDebugOn()) { std::cout << std::endl; std::cout << "Second part of request -------------------" << std::endl; std::cout << "URL: (" << url.toAscii().constData() << ")" << std::endl; std::cout << "Post data sent: (" << postData.toAscii().constData() << ")" << std::endl; std::cout << "Response Code: " << responseCode << std::endl; for (std::map::iterator pos = headerTagsOut.begin(); pos != headerTagsOut.end(); pos++) { std::cout << "Post tag/value: " << pos->first.toAscii().constData() << " " << pos->second.toAscii().constData() << std::endl; } std::cout << "Post Content: " << postContents.toAscii().constData() << std::endl; } if (responseCode != 302) { QString msg("Second phase of login attempt failed (j_security_check). Try again.\n"); msg.append(errorMessage); QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", msg); return false; } else { // // Third request // url = databaseHostName; url.append("/sums/logon.do"); //url.append("/sums/login/login.jsp"); if (sumsSessionID.isEmpty() == false) { url.append(sumsSessionID); } url.append("?caret_xml=yes"); FileUtilities::downloadFileWithHttpGet(url, searchTimeoutSpinBox->value(), contents, errorMessage, &headerTagsOut, &responseCode); if (DebugControl::getDebugOn()) { std::cout << "Third part of request --------------------" << std::endl; std::cout << "URL: (" << url.toAscii().constData() << ")" << std::endl; std::cout << "Response Code: " << responseCode << std::endl; for (std::map::iterator pos = headerTagsOut.begin(); pos != headerTagsOut.end(); pos++) { std::cout << "Third-GET tag/value: " << pos->first.toAscii().constData() << " " << pos->second.toAscii().constData() << std::endl; } std::cout << "GET Content: " << contents.toAscii().constData() << std::endl; } if (responseCode != 200) { QString msg("Third phase of login attempt failed (login.do).\n" "Check username and password.\n"); msg.append(errorMessage); QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", msg); return false; } // // XML returned by SuMS with info about the user // try { // loginInfoFile.readFileFromString(contents); loginInfoFile.readFileFromArray(contents.toAscii().constData(), contents.length(), "sums_login_info.dat"); } catch (FileException& e) { QString msg("Login successful, however, unable to parse\n" "user information.\n"); msg.append(e.whatQString()); QApplication::restoreOverrideCursor(); QMessageBox::information(this, "INFO", msg); return true; // login successful } if (DebugControl::getDebugOn()) { std::vector roles; loginInfoFile.getValue("sums:login:user:roles:role", roles); std::cout << "Email: " << loginInfoFile.getValue("sums:login:user:email").toAscii().constData() << std::endl; for (unsigned int m = 0; m < roles.size(); m++) { std::cout << "Roles: " << roles[m].toAscii().constData() << std::endl; } } } } return true; } /** * Since the SuMS session may time out, this may be used to relogin * prior to an operation so that the user does not need to go to the * starting page to login. * Returns true if login is successful, otherwise it will pop up an * error Message dialog and return false. * Relogin is only performed if the "Login Prior to Operation" checkbox * is checked. */ bool GuiSumsDialog::reloginToSums() { if (loginBeforeOperationCheckBox->isChecked()) { return loginToSums(); } return true; } /** * Prepare some pages when they are about to be shown */ void GuiSumsDialog::showPage(QWidget* page) { // // Show the page // pagesStackedWidget->setCurrentWidget(page); pageTitleLabel->setText(pageTitles[pagesStackedWidget->currentIndex()]); if (page == pageDatabaseUserInformation) { loadDatabaseUserInformationPage(); } if (page == pageDatabaseMode) { modeUploadFilesRadioButton->setEnabled(uploadButtonValid); } slotEnableDisablePushButtons(); } /** * Set the pages that are valid for viewing according to the current selections. */ void GuiSumsDialog::slotEnableDisablePushButtons() { backPushButton->setEnabled(true); nextPushButton->setEnabled(false); finishPushButton->setEnabled(false); const QWidget* currentPage = pagesStackedWidget->currentWidget(); bool finishValid = false; bool nextValid = false; // // Update the mode of the dialog // bool databaseModeNextValid = false; if (modeDownloadArchiveRadioButton->isChecked()) { dialogMode = DIALOG_MODE_ARCHIVE_ID; databaseModeNextValid = (downloadArchiveNumberLineEdit->text().isEmpty() == false); } else if (modeDownloadSpecRadioButton->isChecked()) { dialogMode = DIALOG_MODE_SPEC_FILE_ID; databaseModeNextValid = (downloadSpecNumberLineEdit->text().isEmpty() == false); } else if (modeDownloadAtlasRadioButton->isChecked()) { dialogMode = DIALOG_MODE_DOWNLOAD_ATLAS; databaseModeNextValid = true; } else if (modeDownloadSearchRadioButton->isChecked()) { dialogMode = DIALOG_MODE_DOWNLOAD_SEARCH; databaseModeNextValid = true; } else if (modeRefreshSpecRadioButton->isChecked()) { dialogMode = DIALOG_MODE_REFRESH_SPEC_FILE; databaseModeNextValid = true; } else if (modeUploadFilesRadioButton->isChecked()) { dialogMode = DIALOG_MODE_UPLOAD_FILES; databaseModeNextValid = true; } if (currentPage == pageDatabaseLogin) { databaseUserNameLineEdit->setEnabled(loginUserNameRadioButton->isChecked()); databasePasswordLineEdit->setEnabled(loginUserNameRadioButton->isChecked()); nextValid = (loginVisitorRadioButton->isChecked() || loginUserNameRadioButton->isChecked()); } else if (currentPage == pageDatabaseUserInformation) { nextValid = true; } else if (currentPage == pageDatabaseMode) { switch (dialogMode) { case DIALOG_MODE_NONE: nextValid = false; break; case DIALOG_MODE_ARCHIVE_ID: nextValid = (downloadArchiveNumberLineEdit->text().isEmpty() == false); break; case DIALOG_MODE_SPEC_FILE_ID: nextValid = (downloadSpecNumberLineEdit->text().isEmpty() == false); break; case DIALOG_MODE_DOWNLOAD_ATLAS: nextValid = true; break; case DIALOG_MODE_DOWNLOAD_SEARCH: nextValid = true; break; case DIALOG_MODE_REFRESH_SPEC_FILE: nextValid = true; break; case DIALOG_MODE_UPLOAD_FILES: nextValid = true; break; } } else if (currentPage == pageDownloadAtlas) { nextValid = true; } else if (currentPage == pageDownloadSearch) { nextValid = true; } else if (currentPage == pageRefreshSpecFile) { } else if (currentPage == pageUploadFiles) { if (uploadFileNames.empty() == false) { finishValid = true; } } else if (currentPage == pageSpecFileSelection) { for (int i = 0; i < sumsSpecFileList.getNumberOfSumsFiles(); i++) { SumsFileInfo* sfi = sumsSpecFileList.getSumsFileInfo(i); if (sfi->getSelected()) { nextValid = true; } } } else if (currentPage == pageDataFileSelection) { for (int i = 0; i < sumsDataFileList.getNumberOfSumsFiles(); i++) { if (sumsDataFileList.getSumsFileInfo(i)->getSelected()) { nextValid = true; break; } } } else if (currentPage == pageOutputDirectory) { finishValid = true; } // // enable the next & finish buttons push button // nextPushButton->setEnabled(nextValid); finishPushButton->setEnabled(finishValid); /* setAppropriate(pageDatabaseLogin, true); setAppropriate(pageDatabaseUserInformation, true); setAppropriate(pageDatabaseMode, true); setAppropriate(pageDownloadAtlas, false); setAppropriate(pageDownloadSearch, false); setAppropriate(pageRefreshSpecFile, false); setAppropriate(pageUploadFiles, false); setAppropriate(pageSpecFileSelection, false); setAppropriate(pageDataFileSelection, false); setAppropriate(pageOutputDirectory, false); downloadArchiveNumberLineEdit->setEnabled(dialogMode == DIALOG_MODE_ARCHIVE_ID); downloadSpecNumberLineEdit->setEnabled(dialogMode == DIALOG_MODE_SPEC_FILE_ID); setNextEnabled(pageDatabaseMode, databaseModeNextValid); if (databaseModeNextValid) { switch (dialogMode) { case DIALOG_MODE_NONE: break; case DIALOG_MODE_ARCHIVE_ID: break; case DIALOG_MODE_SPEC_FILE_ID: break; case DIALOG_MODE_DOWNLOAD_ATLAS: setAppropriate(pageDownloadAtlas, true); setNextEnabled(pageDownloadAtlas, true); if (sumsSpecFileList.empty() == false) { setAppropriate(pageSpecFileSelection, true); bool specFileSelected = false; for (int i = 0; i < sumsSpecFileList.getNumberOfSumsFiles(); i++) { SumsFileInfo* sfi = sumsSpecFileList.getSumsFileInfo(i); if (sfi->getSelected()) { specFileSelected = true; } } setNextEnabled(pageSpecFileSelection, specFileSelected); } break; case DIALOG_MODE_DOWNLOAD_SEARCH: setAppropriate(pageDownloadSearch, true); setNextEnabled(pageDownloadSearch, true); if (downloadSearchFileTypeComboBox->currentIndex() == SEARCH_FILE_INDEX_SPEC) { if (sumsSpecFileList.empty() == false) { setAppropriate(pageSpecFileSelection, true); bool specFileSelected = false; for (int i = 0; i < sumsSpecFileList.getNumberOfSumsFiles(); i++) { SumsFileInfo* sfi = sumsSpecFileList.getSumsFileInfo(i); if (sfi->getSelected()) { specFileSelected = true; } } setNextEnabled(pageSpecFileSelection, specFileSelected); } } break; case DIALOG_MODE_REFRESH_SPEC_FILE: setAppropriate(pageRefreshSpecFile, true); setNextEnabled(pageRefreshSpecFile, false); break; case DIALOG_MODE_UPLOAD_FILES: setAppropriate(pageUploadFiles, true); setNextEnabled(pageUploadFiles, false); setFinishEnabled(pageUploadFiles, (uploadFileNames.empty() == false)); break; } } if (sumsDataFileList.empty() == false) { setAppropriate(pageDataFileSelection, true); bool dataFilesSelected = false; for (int i = 0; i < sumsDataFileList.getNumberOfSumsFiles(); i++) { if (sumsDataFileList.getSumsFileInfo(i)->getSelected()) { dataFilesSelected = true; break; } } setNextEnabled(pageDataFileSelection, dataFilesSelected); if (dataFilesSelected) { setAppropriate(pageOutputDirectory, true); setFinishEnabled(pageOutputDirectory, directoryNameLineEdit->text().isEmpty() == false); } } setNextEnabled(pageOutputDirectory, false); */ } caret-5.6.4~dfsg.1.orig/caret/GuiStudyMetaDataLinkCreationDialog.h0000664000175000017500000001655511572067322024645 0ustar michaelmichael #ifndef __GUI_STUDY_META_DATA_LINK_CREATION_DIALOG_H__ #define __GUI_STUDY_META_DATA_LINK_CREATION_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "WuQDialog.h" #include "StudyMetaDataFile.h" #include "StudyMetaDataLinkSet.h" class QAction; class QComboBox; class QButtonGroup; class QDialogButtonBox; class QLabel; class QLineEdit; class QPushButton; class QRadioButton; class QSpinBox; class QTableWidget; class QToolButton; class WuQWidgetGroup; /// class for creating a link to a study in a study meta data file class GuiStudyMetaDataLinkCreationDialog : public WuQDialog { Q_OBJECT public: // constructor GuiStudyMetaDataLinkCreationDialog(QWidget* parent); // destructor ~GuiStudyMetaDataLinkCreationDialog(); // get the link set that was created StudyMetaDataLinkSet getLinkSetCreated() const; // initialize the selected link set void initializeSelectedLinkSet(const StudyMetaDataLinkSet& smdls); protected slots: // called when a study table item is changed void slotStudySelected(int row,int column); // enable/disable OK button void slotEnableDisableOkButton(); // called when a link widget selection is made void enableLinkSelections(); // called when a figure is selected void slotLinkFigureSelectionComboBox(int item); // called when a table is selected void slotLinkTableSelectionComboBox(int item); // called when a page reference is selected void slotLinkPageReferenceSelectionComboBox(int item); // called to add a new study meta data link void slotAddStudyMetaDataLink(); // called to delete the current study meta data link void slotDeleteStudyMetaDataLink(); // called by link selection up arrow void slotLinkSelectionUpArrowAction(); // called by link selection down arrow void slotLinkSelectionDownArrowAction(); protected: // called when OK or Cancel button pressed void done(int r); // get the selected study metadata link StudyMetaDataLink* getSelectedStudyMetaDataLink(); // set the selected study checkbox void setSelectedStudyCheckBox(const int studyIndex, const bool scrollToStudyFlag); // get the index of the selected study int getSelectedStudyIndex() const; // create the study table widget QWidget* createStudyTableWidget(); // create the type of link widget QWidget* createStudyLinkWidget(); // create the link selection widget QWidget* createLinkSelectionWidget(); // load the study table widget void loadStudyTableWidget(); // called to load the selected study metadata link void loadStudyMetaDataLink(const bool scrollToStudyFlag); // update the link selection controls void updateLinkSelectionControls(); /// Save the current study void saveCurrentStudy(); /// update the link selection labels and arrows void updateLinkSelectionLabelsAndArrows(); /// the study meta data link index int studyMetaDataLinkIndex; /// the study meta data link set StudyMetaDataLinkSet studyMetaDataLinkSet; /// the study table widget QTableWidget* studyTableWidget; /// study table column number for check box int studyTableColumnNumberCheckBox; /// study table column number for title int studyTableColumnNumberTitle; /// study table column number for author int studyTableColumnNumberAuthor; /// study table column number for pubmed id int studyTableColumnNumberPubMedID; /// study table column number for project id int studyTableColumnNumberProjectID; /// study table column number for file index int studyTableColumnNumberFileIndex; /// number of columns in study table int studyTableColumnTotal; /// titles of study table columns QStringList studyTableColumnTitles; /// link to study only radio button QRadioButton* linkToStudyOnlyRadioButton; /// link to study figure radio button QRadioButton* linkToFigureRadioButton; /// link to page reference radio button QRadioButton* linkToPageReferenceRadioButton; /// link to study table radio button QRadioButton* linkToTableRadioButton; /// button group for link to study buttons QButtonGroup* linkButtonGroup; /// link figure selection combo box QComboBox* linkFigureSelectionComboBox; /// link to figure panel combo box QComboBox* linkFigurePanelSelectionComboBox; /// contains widgets enabled if linking to a figure WuQWidgetGroup* linkFigureWidgetsGroup; /// link page ref selection combo box QComboBox* linkPageReferenceSelectionComboBox; /// link page ref sub-header combo box QComboBox* linkPageReferenceSubHeaderSelectionComboBox; /// contains widgets enabled if linking to a page ref WuQWidgetGroup* linkPageReferenceWidgetsGroup; /// link table selection combo box QComboBox* linkTableSelectionComboBox; /// link table sub-header combo box QComboBox* linkTableSubHeaderSelectionComboBox; /// contains widgets enabled if linking to a table WuQWidgetGroup* linkTableWidgetsGroup; /// page number widget group //WuQWidgetGroup* pageNumberWidgetGroup; /// link page number line edit //QLineEdit* linkPageNumberLineEdit; /// link selected number label QLabel* currentLinkNumberLabel; /// link total number label QLabel* numberOfLinksLabel; /// link selection up arrow QToolButton* linkSelectionUpArrowToolButton; /// link selection down arrow QToolButton* linkSelectionDownArrowToolButton; /// action for link selection up arrow QAction* linkSelectionUpArrowAction; /// action for link selection down arrow QAction* linkSelectionDownArrowAction; /// delete link push button QPushButton* deleteLinkPushButton; /// add link push button QPushButton* addNewLinkPushButton; /// the dialog buttons QDialogButtonBox* buttonBox; }; #endif // __GUI_STUDY_META_DATA_LINK_CREATION_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiStudyMetaDataLinkCreationDialog.cxx0000664000175000017500000010736211572067322025215 0ustar michaelmichael #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "BrainSet.h" #include "GuiMainWindow.h" #include "GuiStudyMetaDataLinkCreationDialog.h" #include "QtUtilities.h" #include "WuQWidgetGroup.h" #include "global_variables.h" /** * constructor. */ GuiStudyMetaDataLinkCreationDialog::GuiStudyMetaDataLinkCreationDialog(QWidget* parent) : WuQDialog(parent) { setWindowTitle("Link to Study Metadata"); // // Create the link selection widget // QWidget* linkSelWidget = createLinkSelectionWidget(); // // Create the study table widgets // QWidget* tableWidget = createStudyTableWidget(); // // Create the type of link widget // QWidget* linkWidget = createStudyLinkWidget(); // // Get the layout for the dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->addWidget(linkSelWidget); dialogLayout->addWidget(tableWidget); dialogLayout->addWidget(linkWidget); // // load the table // loadStudyTableWidget(); // // Dialog buttons // buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); dialogLayout->addWidget(buttonBox); QObject::connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); QObject::connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); } /** * destructor. */ GuiStudyMetaDataLinkCreationDialog::~GuiStudyMetaDataLinkCreationDialog() { } /** * create the study table widget. */ QWidget* GuiStudyMetaDataLinkCreationDialog::createStudyTableWidget() { // // setup column numbers for study table // studyTableColumnTotal = 0; studyTableColumnNumberCheckBox = studyTableColumnTotal++; studyTableColumnNumberTitle = studyTableColumnTotal++; studyTableColumnNumberAuthor = studyTableColumnTotal++; studyTableColumnNumberPubMedID = studyTableColumnTotal++; studyTableColumnNumberProjectID = studyTableColumnTotal++; studyTableColumnNumberFileIndex = studyTableColumnTotal++; // // Set the column titles // for (int i = 0; i < studyTableColumnTotal; i++) { if (i == studyTableColumnNumberCheckBox) { studyTableColumnTitles << "Select\nStudy"; } else if (i == studyTableColumnNumberTitle) { studyTableColumnTitles << "Title"; } else if (i == studyTableColumnNumberAuthor) { studyTableColumnTitles << "Authors"; } else if (i == studyTableColumnNumberPubMedID) { studyTableColumnTitles << "PubMed ID"; } else if (i == studyTableColumnNumberProjectID) { studyTableColumnTitles << "Project ID"; } else if (i == studyTableColumnNumberFileIndex) { studyTableColumnTitles << "File Index"; } } studyTableWidget = new QTableWidget; QObject::connect(studyTableWidget, SIGNAL(cellClicked(int,int)), // was cellChanged in QT 4.1.x this, SLOT(slotStudySelected(int,int))); QGroupBox* g = new QGroupBox("Study Selection"); QVBoxLayout* l = new QVBoxLayout(g); l->addWidget(studyTableWidget); return g; } /** * create the type of link widget. */ QWidget* GuiStudyMetaDataLinkCreationDialog::createStudyLinkWidget() { const int comboMinWidth = 200; // // Type of link radio buttons // linkToStudyOnlyRadioButton = new QRadioButton("Link to Study Only"); linkToFigureRadioButton = new QRadioButton("Link to Figure in Study"); linkToPageReferenceRadioButton = new QRadioButton("Link to Page Reference"); linkToTableRadioButton = new QRadioButton("Link to Table in Study"); // // Figure combo box, panel label, panel combo box // linkFigureSelectionComboBox = new QComboBox; linkFigureSelectionComboBox->setMinimumWidth(comboMinWidth); QObject::connect(linkFigureSelectionComboBox, SIGNAL(activated(int)), this, SLOT(slotLinkFigureSelectionComboBox(int))); QLabel* linkFigurePanelLabel = new QLabel("Panel"); linkFigurePanelSelectionComboBox = new QComboBox; linkFigurePanelSelectionComboBox->setMinimumWidth(comboMinWidth); linkFigureWidgetsGroup = new WuQWidgetGroup(this); linkFigureWidgetsGroup->addWidget(linkFigureSelectionComboBox); linkFigureWidgetsGroup->addWidget(linkFigurePanelLabel); linkFigureWidgetsGroup->addWidget(linkFigurePanelSelectionComboBox); // // Page ref combo box, sub header label, sub header combo box // linkPageReferenceSelectionComboBox = new QComboBox; linkPageReferenceSelectionComboBox->setMinimumWidth(comboMinWidth); QObject::connect(linkPageReferenceSelectionComboBox, SIGNAL(activated(int)), this, SLOT(slotLinkPageReferenceSelectionComboBox(int))); QLabel* linkPageReferenceSubHeaderLabel = new QLabel("Subheader"); linkPageReferenceSubHeaderSelectionComboBox = new QComboBox; linkPageReferenceSubHeaderSelectionComboBox->setMinimumWidth(comboMinWidth); linkPageReferenceWidgetsGroup = new WuQWidgetGroup(this); linkPageReferenceWidgetsGroup->addWidget(linkPageReferenceSelectionComboBox); linkPageReferenceWidgetsGroup->addWidget(linkPageReferenceSubHeaderLabel); linkPageReferenceWidgetsGroup->addWidget(linkPageReferenceSubHeaderSelectionComboBox); // // Table combo box, subheader label, subheader combo box // linkTableSelectionComboBox = new QComboBox; linkTableSelectionComboBox->setMinimumWidth(comboMinWidth); QObject::connect(linkTableSelectionComboBox, SIGNAL(activated(int)), this, SLOT(slotLinkTableSelectionComboBox(int))); QLabel* linkTableSubHeaderLabel = new QLabel("Subheader"); linkTableSubHeaderSelectionComboBox = new QComboBox; linkTableSubHeaderSelectionComboBox->setMinimumWidth(comboMinWidth); linkTableWidgetsGroup = new WuQWidgetGroup(this); linkTableWidgetsGroup->addWidget(linkTableSelectionComboBox); linkTableWidgetsGroup->addWidget(linkTableSubHeaderLabel); linkTableWidgetsGroup->addWidget(linkTableSubHeaderSelectionComboBox); // // Layout links // QGridLayout* gl = new QGridLayout; gl->addWidget(linkToStudyOnlyRadioButton, 0, 0, 1, 2, Qt::AlignLeft); gl->addWidget(linkToFigureRadioButton, 1, 0, 1, 2, Qt::AlignLeft); gl->addWidget(linkFigureSelectionComboBox, 1, 2, 1, 1, Qt::AlignLeft); gl->addWidget(linkFigurePanelLabel, 2, 1, 1, 1, Qt::AlignRight); gl->addWidget(linkFigurePanelSelectionComboBox, 2, 2, 1, 1, Qt::AlignLeft); gl->addWidget(linkToPageReferenceRadioButton, 3, 0, 1, 2, Qt::AlignLeft); gl->addWidget(linkPageReferenceSelectionComboBox, 3, 2, 1, 1, Qt::AlignLeft); gl->addWidget(linkPageReferenceSubHeaderLabel, 4, 1, 1, 1, Qt::AlignRight); gl->addWidget(linkPageReferenceSubHeaderSelectionComboBox, 4, 2, 1, 1, Qt::AlignLeft); gl->addWidget(linkToTableRadioButton, 5, 0, 1, 2, Qt::AlignLeft); gl->addWidget(linkTableSelectionComboBox, 5, 2, 1, 1, Qt::AlignLeft); gl->addWidget(linkTableSubHeaderLabel, 6, 1, 1, 1, Qt::AlignRight); gl->addWidget(linkTableSubHeaderSelectionComboBox, 6, 2, 1, 1, Qt::AlignLeft); gl->setColumnStretch(0, 0); gl->setColumnStretch(1, 0); gl->setColumnStretch(2, 100); // // Button group to keep link radio buttons mutually exclusive // linkButtonGroup = new QButtonGroup(this); QObject::connect(linkButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(enableLinkSelections())); linkButtonGroup->addButton(linkToStudyOnlyRadioButton, 0); linkButtonGroup->addButton(linkToFigureRadioButton, 1); linkButtonGroup->addButton(linkToPageReferenceRadioButton, 2); linkButtonGroup->addButton(linkToTableRadioButton, 3); // // Link page number // /* QLabel* pageNumberLabel = new QLabel("Page Number"); linkPageNumberLineEdit = new QLineEdit; QHBoxLayout* linkPageLayout = new QHBoxLayout; linkPageLayout->addWidget(pageNumberLabel); linkPageLayout->addWidget(linkPageNumberLineEdit); linkPageLayout->addStretch(); */ // // Widget group for page link // /* pageNumberWidgetGroup = new WuQWidgetGroup(this); pageNumberWidgetGroup->addWidget(pageNumberLabel); pageNumberWidgetGroup->addWidget(linkPageNumberLineEdit); */ // // Group box and layout for items // QGroupBox* gb = new QGroupBox("Link Type"); QVBoxLayout* l = new QVBoxLayout(gb); l->addLayout(gl); //l->addLayout(linkPageLayout); return gb; } /** * create the link selection widget. */ QWidget* GuiStudyMetaDataLinkCreationDialog::createLinkSelectionWidget() { // // link label, current link label, number of links label // QLabel* linkLabel = new QLabel("Link "); currentLinkNumberLabel = new QLabel(" "); currentLinkNumberLabel->setFixedSize(currentLinkNumberLabel->sizeHint()); QLabel* ofLabel = new QLabel(" of "); numberOfLinksLabel = new QLabel(" "); numberOfLinksLabel->setFixedSize(numberOfLinksLabel->sizeHint()); // // Selection arrow actions // linkSelectionUpArrowAction = new QAction(this); QObject::connect(linkSelectionUpArrowAction, SIGNAL(triggered(bool)), this, SLOT(slotLinkSelectionUpArrowAction())); linkSelectionDownArrowAction = new QAction(this); QObject::connect(linkSelectionDownArrowAction, SIGNAL(triggered(bool)), this, SLOT(slotLinkSelectionDownArrowAction())); // // Selection arrow tool buttons // linkSelectionUpArrowToolButton = new QToolButton; linkSelectionUpArrowToolButton->setArrowType(Qt::UpArrow); linkSelectionUpArrowToolButton->setDefaultAction(linkSelectionUpArrowAction); linkSelectionDownArrowToolButton = new QToolButton; linkSelectionDownArrowToolButton->setArrowType(Qt::DownArrow); linkSelectionDownArrowToolButton->setDefaultAction(linkSelectionDownArrowAction); // // Add new link button // addNewLinkPushButton = new QPushButton("Add"); addNewLinkPushButton->setToolTip("Press this button to add an \n" "additional Study Metadata Link."); addNewLinkPushButton->setAutoDefault(false); QObject::connect(addNewLinkPushButton, SIGNAL(clicked()), this, SLOT(slotAddStudyMetaDataLink())); // // Delete Link // deleteLinkPushButton = new QPushButton("Delete"); deleteLinkPushButton->setToolTip("Press this button to delete \n" "the current link."); deleteLinkPushButton->setAutoDefault(false); QObject::connect(deleteLinkPushButton, SIGNAL(clicked()), this, SLOT(slotDeleteStudyMetaDataLink())); QtUtilities::makeButtonsSameSize(addNewLinkPushButton, deleteLinkPushButton); // // Group box and layout // QGroupBox* linkGroupBox = new QGroupBox("Study Link Selection"); QHBoxLayout* layout = new QHBoxLayout(linkGroupBox); layout->addWidget(linkLabel); layout->addWidget(currentLinkNumberLabel); layout->addWidget(ofLabel); layout->addWidget(numberOfLinksLabel); layout->addWidget(linkSelectionDownArrowToolButton); layout->addWidget(linkSelectionUpArrowToolButton); layout->addWidget(addNewLinkPushButton); layout->addWidget(deleteLinkPushButton); layout->addStretch(); return linkGroupBox; } /** * called by link selection up arrow. */ void GuiStudyMetaDataLinkCreationDialog::slotLinkSelectionUpArrowAction() { saveCurrentStudy(); studyMetaDataLinkIndex++; if (studyMetaDataLinkIndex >= studyMetaDataLinkSet.getNumberOfStudyMetaDataLinks()) { studyMetaDataLinkIndex = studyMetaDataLinkSet.getNumberOfStudyMetaDataLinks() - 1; } loadStudyMetaDataLink(true); updateLinkSelectionLabelsAndArrows(); } /** * called by link selection down arrow. */ void GuiStudyMetaDataLinkCreationDialog::slotLinkSelectionDownArrowAction() { saveCurrentStudy(); studyMetaDataLinkIndex--; if (studyMetaDataLinkIndex < 0) { studyMetaDataLinkIndex = 0; } loadStudyMetaDataLink(true); updateLinkSelectionLabelsAndArrows(); } /** * called to add a new study meta data link. */ void GuiStudyMetaDataLinkCreationDialog::slotAddStudyMetaDataLink() { saveCurrentStudy(); StudyMetaDataLink smdl; studyMetaDataLinkSet.addStudyMetaDataLink(smdl); studyMetaDataLinkIndex = studyMetaDataLinkSet.getNumberOfStudyMetaDataLinks() - 1; updateLinkSelectionLabelsAndArrows(); setSelectedStudyCheckBox(-1, false); loadStudyMetaDataLink(true); } /** * update the link selection spin box. */ void GuiStudyMetaDataLinkCreationDialog::updateLinkSelectionLabelsAndArrows() { linkSelectionUpArrowAction->setEnabled(false); linkSelectionDownArrowAction->setEnabled(false); const int num = studyMetaDataLinkSet.getNumberOfStudyMetaDataLinks(); numberOfLinksLabel->setNum(num); currentLinkNumberLabel->setNum(studyMetaDataLinkIndex + 1); if (num > 0) { if (studyMetaDataLinkIndex > 0) { linkSelectionDownArrowAction->setEnabled(true); } if (studyMetaDataLinkIndex < (num - 1)) { linkSelectionUpArrowAction->setEnabled(true); } } else { currentLinkNumberLabel->setText(" "); } deleteLinkPushButton->setEnabled(num > 0); } /** * called to delete the current study meta data link. */ void GuiStudyMetaDataLinkCreationDialog::slotDeleteStudyMetaDataLink() { int num = studyMetaDataLinkSet.getNumberOfStudyMetaDataLinks(); if (num > 0) { if ((studyMetaDataLinkIndex >= 0) && (studyMetaDataLinkIndex < num)) { studyMetaDataLinkSet.removeStudyMetaDataLink(studyMetaDataLinkIndex); num = studyMetaDataLinkSet.getNumberOfStudyMetaDataLinks(); if (studyMetaDataLinkIndex >= num) { studyMetaDataLinkIndex--; } if (studyMetaDataLinkIndex < 0) { studyMetaDataLinkIndex = 0; } updateLinkSelectionLabelsAndArrows(); loadStudyMetaDataLink(true); } } } /** * update the link selection controls. */ void GuiStudyMetaDataLinkCreationDialog::updateLinkSelectionControls() { StudyMetaDataLink* smdl = getSelectedStudyMetaDataLink(); if (smdl != NULL) { //QTableWidgetItem* item = studyTableWidget->item(indx, studyTableColumnNumberCheckBox); //item->setCheckState(Qt::Checked); // // Default to study only // linkToStudyOnlyRadioButton->setChecked(true); // // Check for link to figure // const QString figNum = smdl->getFigureNumber(); if (figNum.isEmpty() == false) { linkToFigureRadioButton->setChecked(true); for (int i = 0; i < linkFigureSelectionComboBox->count(); i++) { if (linkFigureSelectionComboBox->itemData(i).toString() == figNum) { linkFigureSelectionComboBox->setCurrentIndex(i); slotLinkFigureSelectionComboBox(i); // // Check for link to figure panel // for (int j = 0; j < linkFigurePanelSelectionComboBox->count(); j++) { if (linkFigurePanelSelectionComboBox->itemData(j).toString() == smdl->getFigurePanelNumberOrLetter()) { linkFigurePanelSelectionComboBox->setCurrentIndex(j); break; } } break; } } } // // Check for link to page reference // const QString pageRefNum = smdl->getPageReferencePageNumber(); if (pageRefNum.isEmpty() == false) { linkToPageReferenceRadioButton->setChecked(true); for (int i = 0; i < linkPageReferenceSelectionComboBox->count(); i++) { linkPageReferenceSelectionComboBox->setCurrentIndex(i); slotLinkPageReferenceSelectionComboBox(i); // // Check for link to subheader // for (int j = 0; j < linkPageReferenceSubHeaderSelectionComboBox->count(); j++) { if (linkPageReferenceSubHeaderSelectionComboBox->itemData(j).toString() == smdl->getPageReferenceSubHeaderNumber()) { linkPageReferenceSubHeaderSelectionComboBox->setCurrentIndex(j); } } } } // // Check for link to table // const QString tableNum = smdl->getTableNumber(); if (tableNum.isEmpty() == false) { linkToTableRadioButton->setChecked(true); for (int i = 0; i < linkTableSelectionComboBox->count(); i++) { if (linkTableSelectionComboBox->itemData(i).toString() == tableNum) { linkTableSelectionComboBox->setCurrentIndex(i); slotLinkTableSelectionComboBox(i); // // Check for link to sub header // for (int j = 0; j < linkTableSubHeaderSelectionComboBox->count(); j++) { if (linkTableSubHeaderSelectionComboBox->itemData(j).toString() == smdl->getTableSubHeaderNumber()) { linkTableSubHeaderSelectionComboBox->setCurrentIndex(j); break; } } break; } } } //linkPageNumberLineEdit->setText(smdl->getPageNumber()); } } /** * initialize the selected link. */ void GuiStudyMetaDataLinkCreationDialog::initializeSelectedLinkSet(const StudyMetaDataLinkSet& smdls) { studyMetaDataLinkSet = smdls; studyMetaDataLinkIndex = 0; loadStudyMetaDataLink(true); updateLinkSelectionLabelsAndArrows(); } /** * get the selected study metadata link. */ StudyMetaDataLink* GuiStudyMetaDataLinkCreationDialog::getSelectedStudyMetaDataLink() { StudyMetaDataLink* smdl = NULL; if ((studyMetaDataLinkIndex >= 0) && (studyMetaDataLinkIndex < studyMetaDataLinkSet.getNumberOfStudyMetaDataLinks())) { smdl = studyMetaDataLinkSet.getStudyMetaDataLinkPointer(studyMetaDataLinkIndex); } return smdl; } /** * called to load the selected study metadata link. */ void GuiStudyMetaDataLinkCreationDialog::loadStudyMetaDataLink(const bool scrollToStudyFlag) { // // Default to linking to study only // linkToStudyOnlyRadioButton->setChecked(true); // // Clear figure and table combo boxes // linkFigureSelectionComboBox->clear(); linkFigurePanelSelectionComboBox->clear(); linkPageReferenceSelectionComboBox->clear(); linkPageReferenceSubHeaderSelectionComboBox->clear(); linkTableSelectionComboBox->clear(); linkTableSubHeaderSelectionComboBox->clear(); //linkPageNumberLineEdit->setText(""); // // Get the selected study meta data link // const StudyMetaDataLink* smdl = getSelectedStudyMetaDataLink(); if (smdl != NULL) { // // Load figure and table combo boxes // StudyMetaDataFile* smdf = theMainWindow->getBrainSet()->getStudyMetaDataFile(); const int indx = smdf->getStudyIndexFromPubMedID(smdl->getPubMedID()); if ((indx >= 0) && (indx < smdf->getNumberOfStudyMetaData())) { // // Update the checkbox next to the study // setSelectedStudyCheckBox(indx, scrollToStudyFlag); // // Get the study metadata // const StudyMetaData* smd = smdf->getStudyMetaData(indx); // // Update the available figure selections // const int numFigures = smd->getNumberOfFigures(); for (int i = 0; i < numFigures; i++) { const StudyMetaData::Figure* figure = smd->getFigure(i); linkFigureSelectionComboBox->addItem(figure->getNumber(), figure->getNumber()); } slotLinkFigureSelectionComboBox(0); // // Update the available page ref selections // const int numPageRefs = smd->getNumberOfPageReferences(); for (int i = 0; i < numPageRefs; i++) { const StudyMetaData::PageReference* pageRef = smd->getPageReference(i); linkPageReferenceSelectionComboBox->addItem(pageRef->getPageNumber(), pageRef->getPageNumber()); } slotLinkPageReferenceSelectionComboBox(0); // // Update the available table selections // const int numTables = smd->getNumberOfTables(); for (int i = 0; i < numTables; i++) { const StudyMetaData::Table* table = smd->getTable(i); linkTableSelectionComboBox->addItem(table->getNumber(), table->getNumber()); } slotLinkTableSelectionComboBox(0); } } // // Update the link control selections // updateLinkSelectionControls(); // // Enable selection of link controls // enableLinkSelections(); } /** * called when a figure is selected. */ void GuiStudyMetaDataLinkCreationDialog::slotLinkFigureSelectionComboBox(int item) { linkFigurePanelSelectionComboBox->clear(); StudyMetaDataFile* smdf = theMainWindow->getBrainSet()->getStudyMetaDataFile(); const int indx = getSelectedStudyIndex(); if ((indx >= 0) && (indx < smdf->getNumberOfStudyMetaData())) { const StudyMetaData* smd = smdf->getStudyMetaData(indx); const int numFigures = smd->getNumberOfFigures(); if ((item >= 0) && (item < numFigures)) { linkFigurePanelSelectionComboBox->addItem("No Panel", ""); const StudyMetaData::Figure* figure = smd->getFigure(item); const int numPanels = figure->getNumberOfPanels(); for (int j = 0; j < numPanels; j++) { const StudyMetaData::Figure::Panel* panel = figure->getPanel(j); linkFigurePanelSelectionComboBox->addItem(panel->getPanelNumberOrLetter(), panel->getPanelNumberOrLetter()); } } } } /** * called when a page reference is selected. */ void GuiStudyMetaDataLinkCreationDialog::slotLinkPageReferenceSelectionComboBox(int item) { linkPageReferenceSubHeaderSelectionComboBox->clear(); StudyMetaDataFile* smdf = theMainWindow->getBrainSet()->getStudyMetaDataFile(); const int indx = getSelectedStudyIndex(); if ((indx >= 0) && (indx < smdf->getNumberOfStudyMetaData())) { const StudyMetaData* smd = smdf->getStudyMetaData(indx); const int numPageReferences = smd->getNumberOfPageReferences(); if ((item >= 0) && (item < numPageReferences)) { linkPageReferenceSubHeaderSelectionComboBox->addItem("No Subheader", QVariant(-1)); const StudyMetaData::PageReference* pageRef = smd->getPageReference(item); const int numSubHeaders = pageRef->getNumberOfSubHeaders(); for (int j = 0; j < numSubHeaders; j++) { const StudyMetaData::SubHeader* subHeader = pageRef->getSubHeader(j); linkPageReferenceSubHeaderSelectionComboBox->addItem(subHeader->getNumber(), subHeader->getNumber()); } } } } /** * called when a table is selected. */ void GuiStudyMetaDataLinkCreationDialog::slotLinkTableSelectionComboBox(int item) { linkTableSubHeaderSelectionComboBox->clear(); StudyMetaDataFile* smdf = theMainWindow->getBrainSet()->getStudyMetaDataFile(); const int indx = getSelectedStudyIndex(); if ((indx >= 0) && (indx < smdf->getNumberOfStudyMetaData())) { const StudyMetaData* smd = smdf->getStudyMetaData(indx); const int numTables = smd->getNumberOfTables(); if ((item >= 0) && (item < numTables)) { linkTableSubHeaderSelectionComboBox->addItem("No Subheader", QVariant(-1)); const StudyMetaData::Table* table = smd->getTable(item); const int numSubHeaders = table->getNumberOfSubHeaders(); for (int j = 0; j < numSubHeaders; j++) { const StudyMetaData::SubHeader* subHeader = table->getSubHeader(j); linkTableSubHeaderSelectionComboBox->addItem(subHeader->getNumber(), subHeader->getNumber()); } } } } /** * called when a link widget selection is made. */ void GuiStudyMetaDataLinkCreationDialog::enableLinkSelections() { linkToStudyOnlyRadioButton->setEnabled(false); linkToFigureRadioButton->setEnabled(false); linkToPageReferenceRadioButton->setEnabled(false); linkToTableRadioButton->setEnabled(false); studyTableWidget->setEnabled(getSelectedStudyMetaDataLink() != NULL); if ((getSelectedStudyIndex() >= 0) && (getSelectedStudyMetaDataLink() != NULL)) { linkToStudyOnlyRadioButton->setEnabled(true); linkToFigureRadioButton->setEnabled(linkFigureSelectionComboBox->count() > 0); linkToPageReferenceRadioButton->setEnabled(linkPageReferenceSelectionComboBox->count() > 0); linkToTableRadioButton->setEnabled(linkTableSelectionComboBox->count() > 0); } linkFigureWidgetsGroup->setEnabled(linkToFigureRadioButton->isChecked() && linkToFigureRadioButton->isEnabled()); linkPageReferenceWidgetsGroup->setEnabled(linkToPageReferenceRadioButton->isChecked() && linkToPageReferenceRadioButton->isEnabled()); linkTableWidgetsGroup->setEnabled(linkToTableRadioButton->isChecked() && linkToTableRadioButton->isEnabled()); //pageNumberWidgetGroup->setEnabled(linkToStudyOnlyRadioButton->isEnabled()); slotEnableDisableOkButton(); } /** * enable/disable OK button. */ void GuiStudyMetaDataLinkCreationDialog::slotEnableDisableOkButton() { QPushButton* okButton = buttonBox->button(QDialogButtonBox::Ok); if (okButton != NULL) { okButton->setEnabled(getSelectedStudyIndex() >= 0); } } /** * get the index of the selected study. */ int GuiStudyMetaDataLinkCreationDialog::getSelectedStudyIndex() const { for (int i = 0; i < studyTableWidget->rowCount(); i++) { QTableWidgetItem* item = studyTableWidget->item(i, studyTableColumnNumberCheckBox); if (item->checkState() == Qt::Checked) { return i; } } return -1; } /** * set the selected study checkbox. */ void GuiStudyMetaDataLinkCreationDialog::setSelectedStudyCheckBox(const int studyIndex, const bool scrollToStudyFlag) { // // Block signals otherwise setting a checked status will result // in a signal calling this slot again (infinite recursion) // studyTableWidget->blockSignals(true); for (int i = 0; i < studyTableWidget->rowCount(); i++) { QTableWidgetItem* item = studyTableWidget->item(i, 0); if (i == studyIndex) { item->setCheckState(Qt::Checked); } else { item->setCheckState(Qt::Unchecked); } } if (scrollToStudyFlag && (studyIndex >= 0)) { studyTableWidget->scrollToItem(studyTableWidget->item(studyIndex, studyTableColumnNumberCheckBox), QAbstractItemView::PositionAtTop); } // // Allow signals // studyTableWidget->blockSignals(false); } /** * called when a study table item is changed. */ void GuiStudyMetaDataLinkCreationDialog::slotStudySelected(int row,int column) { StudyMetaDataFile* smdf = theMainWindow->getBrainSet()->getStudyMetaDataFile(); if ((row >= 0) && (row < smdf->getNumberOfStudyMetaData())) { StudyMetaData* smd = smdf->getStudyMetaData(row); if (column == studyTableColumnNumberCheckBox) { setSelectedStudyCheckBox(row, false); StudyMetaDataLink* smdl = getSelectedStudyMetaDataLink(); if (smdl != NULL) { // // Replace with new link // StudyMetaDataLink newLink; newLink.setPubMedID(smd->getPubMedID()); *smdl = newLink; } loadStudyMetaDataLink(false); } } } /** * load the study table widget. */ void GuiStudyMetaDataLinkCreationDialog::loadStudyTableWidget() { // // Block signals otherwise, signals will call slotStudySelected() // before the table is filled and hence a crash // studyTableWidget->blockSignals(true); StudyMetaDataFile* smdf = theMainWindow->getBrainSet()->getStudyMetaDataFile(); const int numberOfStudyMetaData = smdf->getNumberOfStudyMetaData(); if ((numberOfStudyMetaData > 0) && (studyTableColumnTotal > 0)) { // // set table size and enable it // studyTableWidget->setRowCount(numberOfStudyMetaData); studyTableWidget->setColumnCount(studyTableColumnTotal); studyTableWidget->setEnabled(true); studyTableWidget->setHorizontalHeaderLabels(studyTableColumnTitles); studyTableWidget->setColumnWidth(studyTableColumnNumberCheckBox, 80); // // Load the table // for (int i = 0; i < numberOfStudyMetaData; i++) { const StudyMetaData* smd = smdf->getStudyMetaData(i); QTableWidgetItem* checkItem = new QTableWidgetItem(" "); checkItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEditable); checkItem->setCheckState(Qt::Unchecked); studyTableWidget->setItem(i, studyTableColumnNumberCheckBox, checkItem); QTableWidgetItem* titleItem = new QTableWidgetItem(smd->getTitle()); titleItem->setFlags(titleItem->flags() & ~Qt::ItemIsEditable); studyTableWidget->setItem(i, studyTableColumnNumberTitle, titleItem); QTableWidgetItem* authorsItem = new QTableWidgetItem(smd->getAuthors()); authorsItem->setFlags(authorsItem->flags() & ~Qt::ItemIsEditable); studyTableWidget->setItem(i, studyTableColumnNumberAuthor, authorsItem); QTableWidgetItem* pubMedItem = new QTableWidgetItem(smd->getPubMedID()); pubMedItem->setFlags(pubMedItem->flags() & ~Qt::ItemIsEditable); studyTableWidget->setItem(i, studyTableColumnNumberPubMedID, pubMedItem); QTableWidgetItem* projectIDItem = new QTableWidgetItem(smd->getProjectID()); projectIDItem->setFlags(projectIDItem->flags() & ~Qt::ItemIsEditable); studyTableWidget->setItem(i, studyTableColumnNumberProjectID, projectIDItem); QTableWidgetItem* indexItem = new QTableWidgetItem(QString::number(i)); indexItem->setFlags(indexItem->flags() & ~Qt::ItemIsEditable); studyTableWidget->setItem(i, studyTableColumnNumberFileIndex, indexItem); } } else { // // Clear the table and disable it // studyTableWidget->clear(); studyTableWidget->setEnabled(false); } // // Allow signals // studyTableWidget->blockSignals(false); } /** * get the link that was created. */ StudyMetaDataLinkSet GuiStudyMetaDataLinkCreationDialog::getLinkSetCreated() const { return studyMetaDataLinkSet; } /** * Save the current study. */ void GuiStudyMetaDataLinkCreationDialog::saveCurrentStudy() { // // Clear the link // StudyMetaDataLink* smdl = getSelectedStudyMetaDataLink(); if (smdl != NULL) { smdl->clear(); // // See if a study is selected // StudyMetaDataFile* smdf = theMainWindow->getBrainSet()->getStudyMetaDataFile(); const int indx = getSelectedStudyIndex(); if ((indx >= 0) && (indx < smdf->getNumberOfStudyMetaData())) { const StudyMetaData* smd = smdf->getStudyMetaData(indx); // // Set PubMedID // smdl->setPubMedID(smd->getPubMedID()); // // if linking to figure // if (linkToFigureRadioButton->isChecked()) { const int figureIndex = linkFigureSelectionComboBox->currentIndex(); if ((figureIndex >= 0) && (figureIndex < smd->getNumberOfFigures())) { const QString figureNumber = linkFigureSelectionComboBox->itemData(figureIndex).toString(); const StudyMetaData::Figure* figure = smd->getFigureByFigureNumber(figureNumber); if (figure != NULL) { smdl->setFigureNumber(figureNumber); // // Linking to a panel in the figure ?? // if (linkFigurePanelSelectionComboBox->count() > 0) { const QString panelNumberOrLetter = linkFigurePanelSelectionComboBox->itemData( linkFigurePanelSelectionComboBox->currentIndex()).toString(); if (panelNumberOrLetter.isEmpty() == false) { smdl->setFigurePanelNumberOrLetter(panelNumberOrLetter); } } } } } // // If linking to page reference // if (linkToPageReferenceRadioButton->isChecked()) { const int pageRefIndex = linkPageReferenceSelectionComboBox->currentIndex(); if ((pageRefIndex >= 0) && (pageRefIndex < smd->getNumberOfPageReferences())) { const QString pageNumber = linkPageReferenceSelectionComboBox->itemData(pageRefIndex).toString(); smdl->setPageReferencePageNumber(pageNumber); // // Linking to subheader in the page reference ?? // if (linkPageReferenceSubHeaderSelectionComboBox->count() > 0) { const int subHeaderIndex = linkPageReferenceSubHeaderSelectionComboBox->currentIndex(); const QString subHeaderNumber = linkPageReferenceSubHeaderSelectionComboBox->itemData(subHeaderIndex).toString(); if (subHeaderNumber.isEmpty() == false) { smdl->setPageReferenceSubHeaderNumber(subHeaderNumber); } } } } // // If linking to table // if (linkToTableRadioButton->isChecked()) { const int tableIndex = linkTableSelectionComboBox->currentIndex(); if ((tableIndex >= 0) && (tableIndex < smd->getNumberOfTables())) { const QString tableNumber = linkTableSelectionComboBox->itemData(tableIndex).toString(); smdl->setTableNumber(tableNumber); // // Linking to a subheader in the table ?? // if (linkTableSubHeaderSelectionComboBox->count() > 0) { const int subHeaderIndex = linkTableSubHeaderSelectionComboBox->currentIndex(); const QString subHeaderNumber = linkTableSubHeaderSelectionComboBox->itemData(subHeaderIndex).toString(); if (subHeaderNumber.isEmpty() == false) { smdl->setTableSubHeaderNumber(subHeaderNumber); } } } } // // set page link // //smdl->setPageNumber(linkPageNumberLineEdit->text()); } } } /** * called when OK or Cancel button pressed. */ void GuiStudyMetaDataLinkCreationDialog::done(int r) { if (r == QDialog::Accepted) { saveCurrentStudy(); } WuQDialog::done(r); } caret-5.6.4~dfsg.1.orig/caret/GuiStudyMetaDataFileEditorDialog.h0000664000175000017500000007334611572067322024312 0ustar michaelmichael #ifndef __GUI_STUDY_META_DATA_FILE_EDITOR_DIALOG_H__ #define __GUI_STUDY_META_DATA_FILE_EDITOR_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "StudyMetaDataFile.h" #include "WuQDialog.h" class QButtonGroup; class QCheckBox; class QLabel; class QLineEdit; class QPushButton; class QRadioButton; class QScrollArea; class QSpinBox; class QTextEdit; class WuQWidgetGroup; class QVBoxLayout; class StudyFigurePanelWidget; class StudyFigureWidget; class StudyPageReferenceWidget; class StudyProvenanceWidget; class StudyTableWidget; class StudySubHeaderWidget; class StudyWidget; /// class for a GUI used to edit StudyMetaDataFile class GuiStudyMetaDataFileEditorDialog : public WuQDialog { Q_OBJECT public: // constructor GuiStudyMetaDataFileEditorDialog(QWidget* parent); // destructor ~GuiStudyMetaDataFileEditorDialog(); // update the dialog void updateDialog(); protected slots: // called when first study button pressed void slotFirstStudyPushButton(); // called study selection spin box value changed void slotStudySelectionSpinBoxValueChanged(int val); // called when last study button pressed void slotLastStudyPushButton(); // called when study title button pressed void slotStudyChooseTitlePushButton(); // called when study author button pressed void slotStudyChooseAuthorPushButton(); // called when study name button pressed void slotStudyChooseNamePushButton(); // called when new study button pressed void slotNewStudyPushButton(); // called when delete study button pressed void slotDeleteStudyPushButton(); // called to enable/disable selection push buttons void slotEnableDisablePushButtons(); // called to close the dialog void slotCloseDialog(); // called when add figure button pressed void slotFigureAddPushButton(); // called to add table button pressed void slotTableAddPushButton(); // called to add page reference button pressed void slotPageReferenceAddPushButton(); // called to add provenance button pressed void slotProvenanceAddPushButton(); // called when help button pressed void slotHelpPushButton(); // called when Fetch All PMID's button pressed void slotFetchAllStudiesPushButton(); // called when delete studies by name button pressed void slotDeleteStudiesByNamePushButton(); // called when delete unlinked studies button pressed void slotDeleteUnlinkedStudiesPushButton(); // called when pubmed ID button pressed void slotStudyFetchPubMedIDPushButton(); protected: // update the study selection spin box void updateStudySelectionSpinBox(); // get the current study widget StudyWidget* getCurrentStudyWidget(); // load study data into the dialog void loadStudyMetaDataIntoDialog(const bool saveCurrentDataFlag); // save study metadata currently in dialog void saveStudyMetaDataFromDialog(); // create the study selection buttons QWidget* createStudySelectionButtons(); /// the layout for editing widgets QVBoxLayout* editingWidgetsLayout; /// study selection spin box QSpinBox* studySelectionSpinBox; /// study first push button QPushButton* studyFirstPushButton; /// study last push button QPushButton* studyLastPushButton; /// study choose by title button QPushButton* studyChooseTitlePushButton; /// study choose by author button QPushButton* studyChooseAuthorPushButton; /// study choose by name button QPushButton* studyChooseNamePushButton; /// study new push button QPushButton* studyNewPushButton; /// study delete push button QPushButton* studyDeletePushButton; /// add figure push button QPushButton* figureAddPushButton; /// add table push button QPushButton* tableAddPushButton; /// fetch from PubMed Button QPushButton* studyPubMedIDFetchPushButton; /// add page reference push button QPushButton* pageReferenceAddPushButton; /// add provenance push button QPushButton* provenanceAddPushButton; /// fetch all studies push button QPushButton* fetchAllStudiesPushButton; /// delete unlinked studies push button QPushButton* deleteUnlinkedStudiesPushButton; /// delete studies by name push button QPushButton* deleteStudiesByNamePushButton; /// index of currently displayed study metadata int currentStudyMetaDataFileIndex; }; //========================================================================= // /// the study widget class StudyWidget : public QGroupBox { Q_OBJECT public: // constructor StudyWidget(GuiStudyMetaDataFileEditorDialog* parentStudyMetaDataFileEditorDialogIn, StudyMetaData* studyMetaDataIn, QWidget* parentIn = 0); // destructor ~StudyWidget(); // add a figure to the study (if NULL add new, empty figure) void addFigure(StudyMetaData::Figure* figure); // remove a figure widget from its layout (does not delete the widget) void removeFigureWidget(StudyFigureWidget* figureWidget); // add a table to the study (if NULL add new, empty table) void addTable(StudyMetaData::Table* table); // remove a table widget from its layout (does not delete the widget) void removeTableWidget(StudyTableWidget* tableWidget); // add a page reference to the study (if NULL add new, empty page reference) void addPageReference(StudyMetaData::PageReference* pageReference); // add a provenance to the study (if NULL add new, empty provenance) void addProvenance(StudyMetaData::Provenance* provenance); // remove a page reference widget from its layout (does not delete the widget) void removePageReferenceWidget(StudyPageReferenceWidget* pageReferenceWidget); // remove a provenance widget from its layout (does not delete the widget) void removeProvenanceWidget(StudyProvenanceWidget* provenanceWidget); // load data into the widget void loadData(); // get study metadata from study metadata file that is in this widget StudyMetaData* getCurrentStudyMetaData() { return studyMetaData; } public slots: // save the data into the study meta data table subheader void slotSaveData(); // called when project ID changed void slotStudyProjectIDLineEditChanged(); // called when title changed void slotStudyTitleLineEditChanged(); // called when authors changed void slotStudyAuthorsLineEditChanged(); // called when citation changed void slotStudyCitationLineEditChanged(); // called when mesh changed void slotStudyMeshLineEditChanged(); // called when name changed void slotStudyNameLineEditChanged(); // called when data format changed void slotStudyDataFormatLineEditChanged(); // called when data type changed void slotStudyDataTypeLineEditChanged(); // called when pubmed id changed void slotStudyPubMedIDSpinBoxChanged(); // called when DOI changed void slotStudyDocumentObjectIdentifierLineEditChanged(); // called when species changed void slotStudySpeciesLineEditChanged(); // called when space changed void slotStudyStereotaxicSpaceLineEditChanged(); // called when space description changed void slotStudyStereotaxicSpaceDetailsLineEditChanged(); // called to update quality void slotStudyQualityLineEditChanged(); // called to update keywords void slotStudyKeywordsLineEditChanged(); // called when keywords editing finished (return pressed or loses focus) void slotStudyKeywordsLineEditFinished(); // called to update keywords in GUI void slotUpdateKeywordsAndGUI(); // called when part scheme changed void slotStudyPartitioningSchemeAbbreviationLineEditChanged(); // called when part scheme abbreviation changed void slotStudyPartitioningSchemeFullNameLineEditChanged(); // called when comment changed void slotStudyCommentTextEditChanged(); // called when msl id changed void slotStudyMslIDLineEditChanged(); // called when parent id changed void slotStudyParentIDLineEditChanged(); // called when core data completed changed void slotStudyCoreDataCompletedLineEditChanged(); // called when completed changed void slotStudyCompletedLineEditChanged(); // called when public access changed void slotStudyPublicAccessLineEditChanged(); // called when species button pressed void slotStudySpeciesPushButton(); // called when stereotaxic space button pressed void slotStudyStereotaxicSpacePushButton(); // called when DOI/URL "LINK" button is pressed void slotStudyDocumentObjectIdentifierPushButton(); // called when PubMed ID "LINK" button is pressed void slotStudyPubMedIDPushButton(); // called when study data format ADD button is pressed void slotStudyDataFormatAddPushButton(); // called when study data type ADD button is pressed void slotStudyDataTypeAddPushButton(); public: // save all data including figures and tables void saveDataIncludingFiguresAndTables(); // all widgets in widget WuQWidgetGroup* allWidgetsGroup; // parent dialog GuiStudyMetaDataFileEditorDialog* parentStudyMetaDataFileEditorDialog; // study metadata from study metadata file that is in this widget StudyMetaData* studyMetaData; /// layout used by this widget QVBoxLayout* layout; /// study file index label QLabel* studyFileIndexDetailsLabel; /// project ID line edit QLineEdit* studyProjectIDLineEdit; /// title line edit QLineEdit* studyTitleLineEdit; /// mesh line edit QLineEdit* studyMeshLineEdit; /// name line edit QLineEdit* studyNameLineEdit; /// authors line edit QLineEdit* studyAuthorsLineEdit; /// citation line edit QLineEdit* studyCitationLineEdit; /// keywords line edit QLineEdit* studyKeywordsLineEdit; /// species line edit QLineEdit* studySpeciesLineEdit; /// stereotaxic space line edit QLineEdit* studyStereotaxicSpaceLineEdit; /// stereotaxic space details line edit QLineEdit* studyStereotaxicSpaceDetailsLineEdit; /// data format line edit QLineEdit* studyDataFormatLineEdit; /// data format type edit QLineEdit* studyDataTypeLineEdit; /// PubMed ID line edit QLineEdit* studyPubMedIDLineEdit; /// Document Object Identifier line edit QLineEdit* studyDocumentObjectIdentifierLineEdit; /// comment text edit QTextEdit* studyCommentTextEdit; /// partitioning scheme abbreviation line edit QLineEdit* studyPartitioningSchemeAbbreviationLineEdit; /// partitioning scheme full name line edit QLineEdit* studyPartitioningSchemeFullNameLineEdit; /// quality line edit QLineEdit* studyQualityLineEdit; /// last time study saved line edit QLineEdit* studyLastSaveLineEdit; /// study msl ID line edit QLineEdit* studyMslIDLineEdit; /// parent id line edit QLineEdit* studyParentIDLineEdit; /// core data completed line edit QLineEdit* studyCoreDataCompletedLineEdit; /// study completed line edit QLineEdit* studyCompletedLineEdit; /// public access line edit QLineEdit* studyPublicAccessLineEdit; /// layout for figures QVBoxLayout* figuresLayout; /// layout for page references QVBoxLayout* pageReferenceLayout; /// layout for provenances QVBoxLayout* provenanceLayout; /// layout for tables QVBoxLayout* tablesLayout; /// keeps track of changes to keywords bool keywordsModifiedFlag; }; //========================================================================= // /// the sub header widget class StudySubHeaderWidget : public QGroupBox { Q_OBJECT public: // constructor StudySubHeaderWidget(StudyMetaData::SubHeader* subHeaderIn, StudyTableWidget* parentStudyTableWidgetIn, StudyPageReferenceWidget* parentPageReferenceWidgetIn, QWidget* parentIn = 0); // destructor ~StudySubHeaderWidget(); // load data into the widget void loadData(); /// get the sub header in this widget StudyMetaData::SubHeader* getSubHeaderInThisWidget() { return subHeader; } public slots: // save the data into the study meta data table subheader void slotSaveData(); // called when delete this sub header button is pressed void slotDeleteThisSubHeader(); // called when short name to foci class button pressed void slotSubHeaderToFociClass(); // called when sub header number changed void slotSubHeaderNumberLineEditChanged(); // called when sub header name changed void slotSubHeaderNameLineEditChanged(); // called when sub header short name changed void slotSubHeaderShortNameLineEditChanged(); // called when sub header short name editing finished void slotSubHeaderShortNameEditingFinished(); // called when sub header task description changed void slotSubHeaderTaskDescriptionLineEditChanged(); // called when sub header task baseline changed void slotSubHeaderTaskBaselineLineEditChanged(); // called when test attributes changed void slotSubHeaderTestAttributesLineEditChanged(); // called to update gui void slotUpdateShortNamesAndGUI(); public: // all widgets in widget WuQWidgetGroup* allWidgetsGroup; // table that is in this widget StudyMetaData::SubHeader* subHeader; /// parent study table widget StudyTableWidget* parentStudyTableWidget; /// parent study page reference widget StudyPageReferenceWidget* parentPageReferenceWidget; /// layout used by this widget QVBoxLayout* layout; /// table subheader number line edit QLineEdit* subHeaderNumberLineEdit; /// table subheader name line edit QLineEdit* subHeaderNameLineEdit; /// table subheader short name line edit QLineEdit* subHeaderShortNameLineEdit; /// subheader short name has been modified bool shortNameModifiedFlag; /// table subheader panel task description QLineEdit* subHeaderTaskDescriptionLineEdit; /// table subheader panel task baseline QLineEdit* subHeaderTaskBaselineLineEdit; /// table subheader panel test attributes QLineEdit* subHeaderTestAttributesLineEdit; }; //========================================================================= // /// the table widget class StudyTableWidget : public QGroupBox { Q_OBJECT public: // constructor StudyTableWidget(StudyMetaData::Table* tableIn, StudyWidget* parentStudyWidgetIn, QWidget* parentIn = 0); // destructor ~StudyTableWidget(); // load data into the widget void loadData(); // add a sub header to this table widget void addSubHeader(StudyMetaData::SubHeader* subHeader); // remove a sub header widget void removeSubHeaderWidget(StudySubHeaderWidget* subHeaderWidget); // get the table in this table widget StudyMetaData::Table* getTableInThisWidget() { return table; } public slots: // save the data into the study meta data table void slotSaveData(); // called when add sub header button is pressed void slotAddSubHeaderPushButton(); // called when delete this table widget button is pressed. void slotDeleteThisTablePushButton(); // called when table number changed void slotTableNumberLineEditChanged(); // called when table header changed void slotTableHeaderLineEditChanged(); // called when table footer changed void slotTableFooterTextEditChanged(); // called when table size units changed void slotTableSizeUnitsLineEditChanged(); // called when table voxel size changed void slotTableVoxelSizeLineEditChanged(); // called when table statistic changed void slotTableStatisticLineEditChanged(); // called when table statistic description changed void slotTableStatisticDescriptionLineEditChanged(); // called when statistic push button pressed void slotTableStatisticPushButton(); public: // all widgets in widget WuQWidgetGroup* allWidgetsGroup; // table that is in this widget StudyMetaData::Table* table; /// layout used by this widget QVBoxLayout* layout; /// table number spin box QLineEdit* tableNumberLineEdit; /// table header line edit QLineEdit* tableHeaderLineEdit; /// table footer text edit QTextEdit* tableFooterTextEdit; /// table size units line edit QLineEdit* tableSizeUnitsLineEdit; /// table voxel size line edit QLineEdit* tableVoxelSizeLineEdit; /// table statistic type line edit QLineEdit* tableStatisticLineEdit; /// table statistic description line edit QLineEdit* tableStatisticDescriptionLineEdit; /// parent study widget StudyWidget* parentStudyWidget; /// layout for sub headers QVBoxLayout* subHeadersLayout; }; //========================================================================= // /// the figure widget class StudyFigureWidget : public QGroupBox { Q_OBJECT public: // constructor StudyFigureWidget(StudyMetaData::Figure* figureIn, StudyWidget* parentStudyWidgetIn, QWidget* parentIn = 0); // destructor ~StudyFigureWidget(); // load data into the widget void loadData(); // add a panel to this figure void addPanel(StudyMetaData::Figure::Panel* panel); // remove a panel widget from its layout (does not delete the widget) void removePanelWidget(StudyFigurePanelWidget* panelWidget); // get the figure in this figure widget StudyMetaData::Figure* getFigureInThisWidget() { return figure; } public slots: // save the data into the study meta data figure void slotSaveData(); // called when add panel button is pressed void slotAddPanelPushButton(); // called when delete this figure widget button is pressed void slotDeleteThisFigurePushButton(); // called when figure number changed void slotFigureNumberLineEditChanged(); // called when figure legend changed void slotFigureLegendLineEditChanged(); public: // all widgets in widget WuQWidgetGroup* allWidgetsGroup; // figure that is in this widget StudyMetaData::Figure* figure; /// layout used by this widget QVBoxLayout* layout; /// figure number line edit QLineEdit* figureNumberLineEdit; /// figure legend line edit QLineEdit* figureLegendLineEdit; /// parent study widget StudyWidget* parentStudyWidget; /// layout for panels QVBoxLayout* panelsLayout; }; //========================================================================= // /// the figure panel widget class StudyFigurePanelWidget : public QGroupBox { Q_OBJECT public: // constructor StudyFigurePanelWidget(StudyMetaData::Figure::Panel* figurePanelIn, StudyFigureWidget* parentFigureWidgetIn, QWidget* parentIn = 0); // destructor ~StudyFigurePanelWidget(); // load data into the widget void loadData(); /// get the panel in this widget StudyMetaData::Figure::Panel* getPanelInThisWidget() { return figurePanel; } public slots: // save the data into the study meta data figure panel void slotSaveData(); // called when delete this panel button pressed void slotDeleteThisPanelPushButton(); // called when figure panel identifier changed void slotFigurePanelIdentifierLineEditChanged(); // called when figure panel description changed void slotFigurePanelDescriptionLineEditChanged(); // called when figure panel task description changed void slotFigurePanelTaskDescriptionLineEditChanged(); // called when figure panel task baseline changed void slotFigurePanelTaskBaselineLineEditChanged(); // called when figure panel test attributes changed void slotFigurePanelTestAttributesLineEditChanged(); public: // all widgets in widget WuQWidgetGroup* allWidgetsGroup; // figure that is in this widget StudyMetaData::Figure::Panel* figurePanel; /// parent study figure widget StudyFigureWidget* parentFigureWidget; /// layout used by this widget QVBoxLayout* layout; /// figure panel identifier QLineEdit* figurePanelIdentifierLineEdit; /// figure panel description QLineEdit* figurePanelDescriptionLineEdit; /// figure panel task description QLineEdit* figurePanelTaskDescriptionLineEdit; /// figure panel task baseline QLineEdit* figurePanelTaskBaselineLineEdit; /// figure panel test attributes QLineEdit* figurePanelTestAttributesLineEdit; }; //========================================================================= // /// the page reference widget class StudyPageReferenceWidget : public QGroupBox { Q_OBJECT public: // constructor StudyPageReferenceWidget(StudyMetaData::PageReference* pageReferenceIn, StudyWidget* parentStudyWidgetIn, QWidget* parentIn = 0); // destructor ~StudyPageReferenceWidget(); // load data into the widget void loadData(); // add a sub header to this page reference widget void addSubHeader(StudyMetaData::SubHeader* subHeader); // remove a sub header widget void removeSubHeaderWidget(StudySubHeaderWidget* subHeaderWidget); // get the page reference in this page reference widget StudyMetaData::PageReference* getPageReferenceInThisWidget() { return pageReference; } public slots: // save the data into the study meta data page reference void slotSaveData(); // called when add sub header button is pressed void slotAddSubHeaderPushButton(); // called when delete this page reference widget button is pressed. void slotDeleteThisPageReferencePushButton(); // called when page referencepage number changed void slotPageReferencePageNumberLineEditChanged(); // called when page reference header changed void slotPageReferenceHeaderLineEditChanged(); // called when page reference comment changed void slotPageReferenceCommentTextEditChanged(); // called when page reference size units changed void slotPageReferenceSizeUnitsLineEditChanged(); // called when page reference voxel size changed void slotPageReferenceVoxelSizeLineEditChanged(); // called when page reference statistic changed void slotPageReferenceStatisticLineEditChanged(); // called when page reference statistic description changed void slotPageReferenceStatisticDescriptionLineEditChanged(); // called when statistic push button pressed void slotPageReferenceStatisticPushButton(); public: // all widgets in widget WuQWidgetGroup* allWidgetsGroup; // page reference that is in this widget StudyMetaData::PageReference* pageReference; /// layout used by this widget QVBoxLayout* layout; /// page reference number line edit QLineEdit* pageReferenceNumberLineEdit; /// page reference header line edit QLineEdit* pageReferenceHeaderLineEdit; /// page reference comment text edit QTextEdit* pageReferenceCommentTextEdit; /// page reference size units line edit QLineEdit* pageReferenceSizeUnitsLineEdit; /// page reference voxel size line edit QLineEdit* pageReferenceVoxelSizeLineEdit; /// page reference statistic type line edit QLineEdit* pageReferenceStatisticLineEdit; /// page reference statistic description line edit QLineEdit* pageReferenceStatisticDescriptionLineEdit; /// parent study widget StudyWidget* parentStudyWidget; /// layout for sub headers QVBoxLayout* subHeadersLayout; }; //========================================================================= // /// provenance widget class StudyProvenanceWidget : public QGroupBox { Q_OBJECT public: // constructor StudyProvenanceWidget(StudyMetaData::Provenance* provenanceIn, StudyWidget* parentStudyWidgetIn, QWidget* parentIn = 0); // destructor ~StudyProvenanceWidget(); // load data into the widget void loadData(); /// get the provenance in this widget StudyMetaData::Provenance* getProvenanceInThisWidget() { return provenance; } public slots: // save the data into the study meta data provenance void slotSaveData(); // called when delete this provenance widget button is pressed. void slotDeleteThisProvenancePushButton(); // called when name changed void slotNameLineEditChanged(); // called when date changed void slotDateLineEditChanged(); // called when comment changed void slotCommentLineEditChanged(); public: // all widgets in widget WuQWidgetGroup* allWidgetsGroup; // provenance that is in this widget StudyMetaData::Provenance* provenance; /// layout used by this widget QVBoxLayout* layout; /// provenance name line edit QLineEdit* provenanceNameLineEdit; /// provenance date line edit QLineEdit* provenanceDateLineEdit; /// provenance comment line edit QLineEdit* provenanceCommentLineEdit; /// parent study widget StudyWidget* parentStudyWidget; }; /// new study dialog class GuiStudyMetaDataNewDialog : public WuQDialog { Q_OBJECT public: // constructor GuiStudyMetaDataNewDialog(StudyMetaData* currentStudyMetaDataIn, QWidget* parent = 0); // destructor ~GuiStudyMetaDataNewDialog(); // get the new study StudyMetaData* getNewStudy() const; // called when OK/Cancel button pressed void done(int r); // get the PubMed ID QString getPubMedID() const; protected: /// new clear entries radio button QRadioButton* newEmptyStudyRadioButton; /// new copy current entries radio button QRadioButton* newCopyStudyRadioButton; /// the current study metadata StudyMetaData* currentStudyMetaData; /// button group for new study QButtonGroup* newStudyButtonGroup; /// new study PubMed ID Line Edit QLineEdit* newStudyPubMedIDLineEdit; /// last checked ID static int lastCheckedID; }; #ifdef __GUI_STUDY_META_DATA_FILE_EDITOR_DIALOG_MAIN_ int GuiStudyMetaDataNewDialog::lastCheckedID = -1; #endif // __GUI_STUDY_META_DATA_FILE_EDITOR_DIALOG_MAIN_ #endif // __GUI_STUDY_META_DATA_FILE_EDITOR_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiStudyMetaDataFileEditorDialog.cxx0000664000175000017500000036627511572067322024673 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 #include "BrainSet.h" #include "DisplaySettingsStudyMetaData.h" #include "DisplaySettingsFoci.h" #include "FileFilters.h" #include "FociProjectionFile.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "GuiNameSelectionDialog.h" #define __GUI_STUDY_META_DATA_FILE_EDITOR_DIALOG_MAIN_ #include "GuiStudyMetaDataFileEditorDialog.h" #undef __GUI_STUDY_META_DATA_FILE_EDITOR_DIALOG_MAIN_ #include "HttpFileDownload.h" #include "NameIndexSort.h" #include "PubMedArticleFile.h" #include "QtListBoxSelectionDialog.h" #include "QtUtilities.h" #include "WuQFileDialog.h" #include "WuQWidgetGroup.h" #include "StudyMetaDataFile.h" #include "global_variables.h" const int minimumTextEditHeight = 150; /** * constructor. */ GuiStudyMetaDataFileEditorDialog::GuiStudyMetaDataFileEditorDialog(QWidget* parent) : WuQDialog(parent) { setMinimumWidth(300); currentStudyMetaDataFileIndex = -1; setWindowTitle("Study Metadata Editor"); // // Create the study selection push buttons // QWidget* studyPushButtonWidget = createStudySelectionButtons(); // // Layout for left side containing buttons // QVBoxLayout* leftLayout = new QVBoxLayout; leftLayout->addWidget(studyPushButtonWidget); leftLayout->addStretch(); // // widget and its layout for editing widgets // QWidget* editingWidget = new QWidget; editingWidgetsLayout = new QVBoxLayout(editingWidget); // // Scroll area for editing studies // QScrollArea* editingScrollArea = new QScrollArea; editingScrollArea->setWidget(editingWidget); editingScrollArea->setWidgetResizable(true); // // Place the selection and editing widgets in a horizontal box // QHBoxLayout* horizLayout = new QHBoxLayout; horizLayout->addLayout(leftLayout); horizLayout->addWidget(editingScrollArea); // // add to the dialog layout // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->addLayout(horizLayout); // // Dialog buttons // QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Help | QDialogButtonBox::Close); dialogLayout->addWidget(buttonBox); QObject::connect(buttonBox, SIGNAL(helpRequested()), this, SLOT(slotHelpPushButton())); QObject::connect(buttonBox, SIGNAL(rejected()), this, SLOT(close())); // // If there are no studies, create one // StudyMetaDataFile* smdf = theMainWindow->getBrainSet()->getStudyMetaDataFile(); if (smdf->getNumberOfStudyMetaData() <= 0) { StudyMetaData* smd = new StudyMetaData; if (smd != NULL) { smdf->addStudyMetaData(smd); smdf->clearModified(); } } updateDialog(); } /** * destructor. */ GuiStudyMetaDataFileEditorDialog::~GuiStudyMetaDataFileEditorDialog() { } /** * called when help button pressed. */ void GuiStudyMetaDataFileEditorDialog::slotHelpPushButton() { theMainWindow->showHelpViewerDialog("dialogs/study_metadata.html"); } /** * called to close the dialog. */ void GuiStudyMetaDataFileEditorDialog::slotCloseDialog() { if (getCurrentStudyWidget() != NULL) { getCurrentStudyWidget()->slotStudyKeywordsLineEditFinished(); } // // Save any data in dialog // saveStudyMetaDataFromDialog(); // // close the dialog // close(); } /** * update the dialog. */ void GuiStudyMetaDataFileEditorDialog::updateDialog() { StudyMetaDataFile* smdf = theMainWindow->getBrainSet()->getStudyMetaDataFile(); if (currentStudyMetaDataFileIndex >= smdf->getNumberOfStudyMetaData()) { currentStudyMetaDataFileIndex = smdf->getNumberOfStudyMetaData() - 1; } if (currentStudyMetaDataFileIndex < 0) { if (smdf->getNumberOfStudyMetaData() > 0) { currentStudyMetaDataFileIndex = 0; } else { currentStudyMetaDataFileIndex = -1; } } updateStudySelectionSpinBox(); loadStudyMetaDataIntoDialog(true); } /** * get the current study widget. */ StudyWidget* GuiStudyMetaDataFileEditorDialog::getCurrentStudyWidget() { // // The study data widget will be the one and only widget in the layout // if (editingWidgetsLayout->count() > 0) { QLayoutItem* li = editingWidgetsLayout->itemAt(0); if (li != NULL) { QWidget* w = li->widget(); if (w != NULL) { StudyWidget* sw = dynamic_cast(w); return sw; } } } return NULL; } /** * save study metadata currently in dialog. */ void GuiStudyMetaDataFileEditorDialog::saveStudyMetaDataFromDialog() { StudyWidget* sw = getCurrentStudyWidget(); if (sw != NULL) { sw->saveDataIncludingFiguresAndTables(); } } /** * load study metadata into the dialog. */ void GuiStudyMetaDataFileEditorDialog::loadStudyMetaDataIntoDialog(const bool saveCurrentDataFlag) { if (saveCurrentDataFlag) { saveStudyMetaDataFromDialog(); } // // Remove previous widget and destroy it // if (editingWidgetsLayout->count() > 0) { QLayoutItem* li = editingWidgetsLayout->takeAt(0); if (li != NULL) { QWidget* w = li->widget(); if (w != NULL) { delete w; } } } // // Load study into dialog // StudyMetaDataFile* smdf = theMainWindow->getBrainSet()->getStudyMetaDataFile(); if ((currentStudyMetaDataFileIndex >= 0) && (currentStudyMetaDataFileIndex < smdf->getNumberOfStudyMetaData())) { StudyMetaData* smd = smdf->getStudyMetaData(currentStudyMetaDataFileIndex); QWidget* sw = new StudyWidget(this, smd); editingWidgetsLayout->addWidget(sw); //std::cout << "there are " << editingWidgetsLayout->count() << " items in layout." << std::endl; } slotEnableDisablePushButtons(); } /** * update the study selection combo box. */ void GuiStudyMetaDataFileEditorDialog::updateStudySelectionSpinBox() { const StudyMetaDataFile* smdf = theMainWindow->getBrainSet()->getStudyMetaDataFile(); studySelectionSpinBox->blockSignals(true); studySelectionSpinBox->setMinimum(1); studySelectionSpinBox->setMaximum(smdf->getNumberOfStudyMetaData()); studySelectionSpinBox->setValue(currentStudyMetaDataFileIndex + 1); studySelectionSpinBox->blockSignals(false); } /** * called study selection spin box value changed. */ void GuiStudyMetaDataFileEditorDialog::slotStudySelectionSpinBoxValueChanged(int val) { //if (getCurrentStudyWidget() != NULL) { // getCurrentStudyWidget()->slotStudyKeywordsLineEditFinished(); //} currentStudyMetaDataFileIndex = val - 1; const StudyMetaDataFile* smdf = theMainWindow->getBrainSet()->getStudyMetaDataFile(); if (currentStudyMetaDataFileIndex >= smdf->getNumberOfStudyMetaData()) { currentStudyMetaDataFileIndex = smdf->getNumberOfStudyMetaData() - 1; } if (currentStudyMetaDataFileIndex < 0) { currentStudyMetaDataFileIndex = 0; } slotEnableDisablePushButtons(); loadStudyMetaDataIntoDialog(true); } /** * called when first study button pressed. */ void GuiStudyMetaDataFileEditorDialog::slotFirstStudyPushButton() { if (getCurrentStudyWidget() != NULL) { getCurrentStudyWidget()->slotStudyKeywordsLineEditFinished(); } currentStudyMetaDataFileIndex = 0; updateStudySelectionSpinBox(); loadStudyMetaDataIntoDialog(true); } /** * called when study title button pressed. */ void GuiStudyMetaDataFileEditorDialog::slotStudyChooseTitlePushButton() { // // Get and sort the titles // const StudyMetaDataFile* smdf = theMainWindow->getBrainSet()->getStudyMetaDataFile(); const int num = smdf->getNumberOfStudyMetaData(); NameIndexSort nis; for (int i = 0; i < num; i++) { const StudyMetaData* smd = smdf->getStudyMetaData(i); nis.add(i, smd->getTitle()); } nis.sortByNameCaseSensitive(); // // Place sorted titles into a list selection dialog // std::vector titlesSorted; const int numItems = nis.getNumberOfItems(); for (int i = 0; i < numItems; i++) { int indx; QString title; nis.getSortedNameAndIndex(i, indx, title); titlesSorted.push_back(title); } QtListBoxSelectionDialog lbsd(this, "Choose Study by Title", "", titlesSorted); if (lbsd.exec() == QtListBoxSelectionDialog::Accepted) { const int itemNum = lbsd.getSelectedItemIndex(); int indx; QString title; nis.getSortedNameAndIndex(itemNum, indx, title); // // Show the new study // currentStudyMetaDataFileIndex = indx; updateStudySelectionSpinBox(); loadStudyMetaDataIntoDialog(true); } } /** * called when study name button pressed. */ void GuiStudyMetaDataFileEditorDialog::slotStudyChooseNamePushButton() { // // Get and sort the names // const StudyMetaDataFile* smdf = theMainWindow->getBrainSet()->getStudyMetaDataFile(); const int num = smdf->getNumberOfStudyMetaData(); NameIndexSort nis; for (int i = 0; i < num; i++) { const StudyMetaData* smd = smdf->getStudyMetaData(i); nis.add(i, smd->getName()); } nis.sortByNameCaseSensitive(); // // Place sorted authors into a list selection dialog // std::vector namesSorted; const int numItems = nis.getNumberOfItems(); for (int i = 0; i < numItems; i++) { int indx; QString name; nis.getSortedNameAndIndex(i, indx, name); namesSorted.push_back(name); } QtListBoxSelectionDialog lbsd(this, "Choose Study by Name", "", namesSorted); if (lbsd.exec() == QtListBoxSelectionDialog::Accepted) { const int itemNum = lbsd.getSelectedItemIndex(); int indx; QString name; nis.getSortedNameAndIndex(itemNum, indx, name); // // Show the new study // currentStudyMetaDataFileIndex = indx; updateStudySelectionSpinBox(); loadStudyMetaDataIntoDialog(true); } } /** * called when study author button pressed. */ void GuiStudyMetaDataFileEditorDialog::slotStudyChooseAuthorPushButton() { // // Get and sort the authors // const StudyMetaDataFile* smdf = theMainWindow->getBrainSet()->getStudyMetaDataFile(); const int num = smdf->getNumberOfStudyMetaData(); NameIndexSort nis; for (int i = 0; i < num; i++) { const StudyMetaData* smd = smdf->getStudyMetaData(i); nis.add(i, smd->getAuthors()); } nis.sortByNameCaseSensitive(); // // Place sorted authors into a list selection dialog // std::vector authorsSorted; const int numItems = nis.getNumberOfItems(); for (int i = 0; i < numItems; i++) { int indx; QString author; nis.getSortedNameAndIndex(i, indx, author); authorsSorted.push_back(author); } QtListBoxSelectionDialog lbsd(this, "Choose Study by Author", "", authorsSorted); if (lbsd.exec() == QtListBoxSelectionDialog::Accepted) { const int itemNum = lbsd.getSelectedItemIndex(); int indx; QString author; nis.getSortedNameAndIndex(itemNum, indx, author); // // Show the new study // currentStudyMetaDataFileIndex = indx; updateStudySelectionSpinBox(); loadStudyMetaDataIntoDialog(true); } } /** * called when last study button pressed. */ void GuiStudyMetaDataFileEditorDialog::slotLastStudyPushButton() { if (getCurrentStudyWidget() != NULL) { getCurrentStudyWidget()->slotStudyKeywordsLineEditFinished(); } const StudyMetaDataFile* smdf = theMainWindow->getBrainSet()->getStudyMetaDataFile(); currentStudyMetaDataFileIndex = smdf->getNumberOfStudyMetaData() - 1; if (currentStudyMetaDataFileIndex < 0) { currentStudyMetaDataFileIndex = 0; } updateStudySelectionSpinBox(); loadStudyMetaDataIntoDialog(true); } /** * called when new study button pressed. */ void GuiStudyMetaDataFileEditorDialog::slotNewStudyPushButton() { StudyMetaData* currentStudyMetaData = NULL; StudyWidget* sw = getCurrentStudyWidget(); if (sw != NULL) { currentStudyMetaData = sw->getCurrentStudyMetaData(); } GuiStudyMetaDataNewDialog smdnd(currentStudyMetaData, this); if (smdnd.exec() == GuiStudyMetaDataNewDialog::Accepted) { StudyMetaDataFile* smdf = theMainWindow->getBrainSet()->getStudyMetaDataFile(); StudyMetaData* smd = smdnd.getNewStudy(); if (smd != NULL) { smdf->addStudyMetaData(smd); currentStudyMetaDataFileIndex = smdf->getNumberOfStudyMetaData() - 1; } else { std::cout << "PROGRAM ERROR: new StudyMetaData is NULL." << std::endl; } } else { return; } updateStudySelectionSpinBox(); loadStudyMetaDataIntoDialog(true); } /** * called when delete study button pressed. */ void GuiStudyMetaDataFileEditorDialog::slotDeleteStudyPushButton() { StudyMetaDataFile* smdf = theMainWindow->getBrainSet()->getStudyMetaDataFile(); if ((currentStudyMetaDataFileIndex >= 0) && (currentStudyMetaDataFileIndex < smdf->getNumberOfStudyMetaData())) { if (QMessageBox::question(this, "Confirm", "Delete the current study metadata?", (QMessageBox::Yes | QMessageBox::No), QMessageBox::Yes) == QMessageBox::Yes) { smdf->deleteStudyMetaData(currentStudyMetaDataFileIndex); if (currentStudyMetaDataFileIndex >= smdf->getNumberOfStudyMetaData()) { currentStudyMetaDataFileIndex--; } } } updateStudySelectionSpinBox(); loadStudyMetaDataIntoDialog(false); } /** * called when add figure button pressed. */ void GuiStudyMetaDataFileEditorDialog::slotFigureAddPushButton() { StudyWidget* sw = getCurrentStudyWidget(); if (sw != NULL) { sw->addFigure(NULL); } } /** * called to add table button pressed. */ void GuiStudyMetaDataFileEditorDialog::slotTableAddPushButton() { StudyWidget* sw = getCurrentStudyWidget(); if (sw != NULL) { sw->addTable(NULL); } } /** * called to add page reference button pressed. */ void GuiStudyMetaDataFileEditorDialog::slotPageReferenceAddPushButton() { StudyWidget* sw = getCurrentStudyWidget(); if (sw != NULL) { sw->addPageReference(NULL); } } /** * called to add provenance button pressed. */ void GuiStudyMetaDataFileEditorDialog::slotProvenanceAddPushButton() { StudyWidget* sw = getCurrentStudyWidget(); if (sw != NULL) { sw->addProvenance(NULL); } } /** * called to enable/disable selection push buttons. */ void GuiStudyMetaDataFileEditorDialog::slotEnableDisablePushButtons() { studyNewPushButton->setEnabled(true); studyFirstPushButton->setEnabled(false); studyLastPushButton->setEnabled(false); studyChooseTitlePushButton->setEnabled(false); studyChooseAuthorPushButton->setEnabled(false); studyChooseNamePushButton->setEnabled(false); studyDeletePushButton->setEnabled(false); studySelectionSpinBox->setEnabled(false); fetchAllStudiesPushButton->setEnabled(false); deleteUnlinkedStudiesPushButton->setEnabled(false); deleteStudiesByNamePushButton->setEnabled(false); figureAddPushButton->setEnabled(false); tableAddPushButton->setEnabled(false); pageReferenceAddPushButton->setEnabled(false); provenanceAddPushButton->setEnabled(false); studyPubMedIDFetchPushButton->setEnabled(false); StudyMetaDataFile* smdf = theMainWindow->getBrainSet()->getStudyMetaDataFile(); const int numStudies = smdf->getNumberOfStudyMetaData(); if (numStudies > 0) { studyFirstPushButton->setEnabled(true); studyLastPushButton->setEnabled(true); studyChooseTitlePushButton->setEnabled(true); studyChooseAuthorPushButton->setEnabled(true); studyChooseNamePushButton->setEnabled(true); studyDeletePushButton->setEnabled(true); studySelectionSpinBox->setEnabled(true); fetchAllStudiesPushButton->setEnabled(true); deleteUnlinkedStudiesPushButton->setEnabled(true); deleteStudiesByNamePushButton->setEnabled(true); } if (getCurrentStudyWidget() != NULL) { figureAddPushButton->setEnabled(true); tableAddPushButton->setEnabled(true); pageReferenceAddPushButton->setEnabled(true); provenanceAddPushButton->setEnabled(true); studyPubMedIDFetchPushButton->setEnabled(true); } } /** * called when delete unlinked studies button pressed. */ void GuiStudyMetaDataFileEditorDialog::slotDeleteUnlinkedStudiesPushButton() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainSet* brainSet = theMainWindow->getBrainSet(); const int numRemoved = brainSet->removeUnlinkedStudiesFromStudyMetaDataFile(); updateStudySelectionSpinBox(); loadStudyMetaDataIntoDialog(false); QApplication::restoreOverrideCursor(); QMessageBox::information(this, "INFO", (QString::number(numRemoved) + " studies were deleted.")); } /** * called when delete studies by name button pressed. */ void GuiStudyMetaDataFileEditorDialog::slotDeleteStudiesByNamePushButton() { const QString instructions("Select studies that are to be deleted.\n" "Use the CTRL (Apple on Macs) key to \n" "select more than one study."); std::set studyNamesSet; StudyMetaDataFile* smdf = theMainWindow->getBrainSet()->getStudyMetaDataFile(); for (int i = 0; i < smdf->getNumberOfStudyMetaData(); i++) { const QString name(smdf->getStudyMetaData(i)->getName()); if (name.isEmpty() == false) { studyNamesSet.insert(name); } } std::vector studyNames; studyNames.insert(studyNames.end(), studyNamesSet.begin(), studyNamesSet.end()); QtListBoxSelectionDialog lbsd(this, "Delete Studies by Name", instructions, studyNames); lbsd.setAllowMultipleItemSelection(true); if (lbsd.exec() == QtListBoxSelectionDialog::Accepted) { std::vector selectedItems; lbsd.getSelectedItems(selectedItems); smdf->deleteStudiesWithNames(selectedItems); updateStudySelectionSpinBox(); loadStudyMetaDataIntoDialog(false); } } /** * called when Fetch All PMID's button pressed. */ void GuiStudyMetaDataFileEditorDialog::slotFetchAllStudiesPushButton() { if (QMessageBox::question(this, "Confirm", "Update all studies with valid PubMed IDs?", (QMessageBox::Yes | QMessageBox::No), QMessageBox::Yes) == QMessageBox::Yes) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); StudyMetaDataFile* smdf = theMainWindow->getBrainSet()->getStudyMetaDataFile(); StudyWidget* sw = getCurrentStudyWidget(); try { smdf->updateAllStudiesWithDataFromPubMedDotCom(); if (sw != NULL) { sw->loadData(); } } catch (FileException& e) { if (sw != NULL) { sw->loadData(); } QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); } QApplication::restoreOverrideCursor(); } } /** * create the study selection buttons. */ QWidget* GuiStudyMetaDataFileEditorDialog::createStudySelectionButtons() { studySelectionSpinBox = new QSpinBox; QObject::connect(studySelectionSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotStudySelectionSpinBoxValueChanged(int))); studyFirstPushButton = new QPushButton("First"); studyFirstPushButton->setAutoDefault(false); studyFirstPushButton->setToolTip("Press this button to select\n" "the first Study Metadata."); QObject::connect(studyFirstPushButton, SIGNAL(clicked()), this, SLOT(slotFirstStudyPushButton())); studyLastPushButton = new QPushButton("Last"); studyLastPushButton->setAutoDefault(false); studyLastPushButton->setToolTip("Press this button to select\n" "the last Study Metadata."); QObject::connect(studyLastPushButton, SIGNAL(clicked()), this, SLOT(slotLastStudyPushButton())); studyChooseAuthorPushButton = new QPushButton("Choose by Author..."); studyChooseAuthorPushButton->setAutoDefault(false); studyChooseAuthorPushButton->setToolTip("Press this button to choose\n" "a study by its author(s)."); QObject::connect(studyChooseAuthorPushButton, SIGNAL(clicked()), this, SLOT(slotStudyChooseAuthorPushButton())); studyChooseNamePushButton = new QPushButton("Choose by Name..."); studyChooseNamePushButton->setAutoDefault(false); studyChooseNamePushButton->setToolTip("Press this button to choose\n" "a study by its name."); QObject::connect(studyChooseNamePushButton, SIGNAL(clicked()), this, SLOT(slotStudyChooseNamePushButton())); studyChooseTitlePushButton = new QPushButton("Choose by Title..."); studyChooseTitlePushButton->setAutoDefault(false); studyChooseTitlePushButton->setToolTip("Press this button to choose\n" "a study by its name."); QObject::connect(studyChooseTitlePushButton, SIGNAL(clicked()), this, SLOT(slotStudyChooseTitlePushButton())); QGroupBox* ssg = new QGroupBox("Study Selection"); QVBoxLayout* ssl = new QVBoxLayout(ssg); ssl->addWidget(studySelectionSpinBox); ssl->addWidget(studyFirstPushButton); ssl->addWidget(studyLastPushButton); ssl->addWidget(studyChooseAuthorPushButton); ssl->addWidget(studyChooseNamePushButton); ssl->addWidget(studyChooseTitlePushButton); fetchAllStudiesPushButton = new QPushButton("Fetch All PMIDs"); fetchAllStudiesPushButton->setAutoDefault(false); fetchAllStudiesPushButton->setToolTip("Update all studies with valid\n" "PubMed IDs with data from \n" "www.pubmed.gov."); QObject::connect(fetchAllStudiesPushButton, SIGNAL(clicked()), this, SLOT(slotFetchAllStudiesPushButton())); deleteUnlinkedStudiesPushButton = new QPushButton("Delete Unlinked Studies"); deleteUnlinkedStudiesPushButton->setAutoDefault(false); deleteUnlinkedStudiesPushButton->setToolTip("Delete studies not linked\n" "by any data type."); QObject::connect(deleteUnlinkedStudiesPushButton, SIGNAL(clicked()), this, SLOT(slotDeleteUnlinkedStudiesPushButton())); deleteStudiesByNamePushButton = new QPushButton("Delete By Name..."); deleteStudiesByNamePushButton->setAutoDefault(false); deleteStudiesByNamePushButton->setToolTip("Delete Studies By Name"); QObject::connect(deleteStudiesByNamePushButton, SIGNAL(clicked()), this, SLOT(slotDeleteStudiesByNamePushButton())); studyNewPushButton = new QPushButton("Add New Study..."); studyNewPushButton->setAutoDefault(false); studyNewPushButton->setToolTip("Press this button to create\n" "new Study Metadata."); QObject::connect(studyNewPushButton, SIGNAL(clicked()), this, SLOT(slotNewStudyPushButton())); QGroupBox* studyFileGroupBox = new QGroupBox("File Operations"); QVBoxLayout* studyFileLayout = new QVBoxLayout(studyFileGroupBox); studyFileLayout->addWidget(studyNewPushButton); studyFileLayout->addWidget(deleteUnlinkedStudiesPushButton); studyFileLayout->addWidget(deleteStudiesByNamePushButton); studyFileLayout->addWidget(fetchAllStudiesPushButton); studyDeletePushButton = new QPushButton("Delete Study..."); studyDeletePushButton->setAutoDefault(false); studyDeletePushButton->setToolTip("Press this button to delete\n" "the current Study Metadata."); QObject::connect(studyDeletePushButton, SIGNAL(clicked()), this, SLOT(slotDeleteStudyPushButton())); figureAddPushButton = new QPushButton("Add Figure"); figureAddPushButton->setAutoDefault(false); figureAddPushButton->setToolTip("Press this button to add a\n" "figure to the current study."); QObject::connect(figureAddPushButton, SIGNAL(clicked()), this, SLOT(slotFigureAddPushButton())); pageReferenceAddPushButton = new QPushButton("Add Page Ref"); pageReferenceAddPushButton->setAutoDefault(false); pageReferenceAddPushButton->setToolTip("Press this button to add a page\n" "reference to the current study."); QObject::connect(pageReferenceAddPushButton, SIGNAL(clicked()), this, SLOT(slotPageReferenceAddPushButton())); provenanceAddPushButton = new QPushButton("Add Provenance"); provenanceAddPushButton->setAutoDefault(false); provenanceAddPushButton->setToolTip("Press this button to add a provenance\n" "to the current study."); QObject::connect(provenanceAddPushButton, SIGNAL(clicked()), this, SLOT(slotProvenanceAddPushButton())); tableAddPushButton = new QPushButton("Add Table"); tableAddPushButton->setAutoDefault(false); tableAddPushButton->setToolTip("Press this button to add a\n" "table to the current study."); QObject::connect(tableAddPushButton, SIGNAL(clicked()), this, SLOT(slotTableAddPushButton())); studyPubMedIDFetchPushButton = new QPushButton("Fetch from PubMed..."); studyPubMedIDFetchPushButton->setAutoDefault(false); studyPubMedIDFetchPushButton->setToolTip("After entering the PubMed ID,\n" "press this button to retrieve\n" "the article's information from\n" "the PubMed Website."); QObject::connect(studyPubMedIDFetchPushButton, SIGNAL(clicked()), this, SLOT(slotStudyFetchPubMedIDPushButton())); QGroupBox* sog = new QGroupBox("Study Operations"); QVBoxLayout* sol = new QVBoxLayout(sog); sol->addWidget(figureAddPushButton); sol->addWidget(pageReferenceAddPushButton); sol->addWidget(provenanceAddPushButton); sol->addWidget(tableAddPushButton); sol->addWidget(studyDeletePushButton); sol->addWidget(studyPubMedIDFetchPushButton); std::vector buttons; buttons.push_back(studyFirstPushButton); buttons.push_back(studyLastPushButton); buttons.push_back(studyChooseAuthorPushButton); buttons.push_back(studyChooseNamePushButton); buttons.push_back(studyChooseTitlePushButton); buttons.push_back(studyNewPushButton); buttons.push_back(studyDeletePushButton); buttons.push_back(figureAddPushButton); buttons.push_back(pageReferenceAddPushButton); buttons.push_back(provenanceAddPushButton); buttons.push_back(tableAddPushButton); buttons.push_back(fetchAllStudiesPushButton); buttons.push_back(deleteUnlinkedStudiesPushButton); buttons.push_back(deleteStudiesByNamePushButton); buttons.push_back(studyPubMedIDFetchPushButton); QtUtilities::makeButtonsSameSize(buttons); QWidget* w = new QWidget; QVBoxLayout* l = new QVBoxLayout(w); l->addWidget(ssg); l->addWidget(studyFileGroupBox); l->addWidget(sog); return w; } /** * called when pubmed ID button pressed. */ void GuiStudyMetaDataFileEditorDialog::slotStudyFetchPubMedIDPushButton() { StudyWidget* sw = getCurrentStudyWidget(); if (sw == NULL) { return; } StudyMetaData* studyMetaData = sw->getCurrentStudyMetaData(); if (studyMetaData == NULL) { return; } // // Confirm with user // const QString msg("Retrieve data for article with PubMed ID = " + studyMetaData->getPubMedID() +"?"); if (QMessageBox::question(this, "Confirm", msg, (QMessageBox::Ok | QMessageBox::Cancel), QMessageBox::Ok) == QMessageBox::Cancel) { return; } // // Update the study metadata // try { if (studyMetaData != NULL) { studyMetaData->updateDataFromPubMedDotComUsingPubMedID(); sw->loadData(); } } catch (FileException& e) { QMessageBox::critical(this, "ERROR", e.whatQString()); } /* // // Make sure a PubMed ID was entered // const QString pubMedID = studyPubMedIDLineEdit->text().trimmed(); if (pubMedID.isEmpty()) { QMessageBox::critical(this, "ERROR", "The PubMed ID has not been entered.", "OK"); return; } // // Confirm with user // const QString msg("Retrieve data for article with PubMed ID = " + pubMedID +"?"); if (QMessageBox::question(this, "Confirm", msg, "Continue", "Cancel") != 0) { return; } // // Get the article // PubMedArticleFile pubMedFile; try { pubMedFile.retrieveArticleWithPubMedID(pubMedID); if (pubMedFile.getArticleTitle().isEmpty() == false) { studyTitleLineEdit->setText(pubMedFile.getArticleTitle()); studyTitleLineEdit->home(false); slotStudyTitleLineEditChanged(); } if (pubMedFile.getAuthors().isEmpty() == false) { studyAuthorsLineEdit->setText(pubMedFile.getAuthors()); studyAuthorsLineEdit->home(false); slotStudyAuthorsLineEditChanged(); } if (pubMedFile.getJournalTitle().isEmpty() == false) { studyCitationLineEdit->setText(pubMedFile.getJournalTitle()); studyCitationLineEdit->home(false); slotStudyCitationLineEditChanged(); } if (pubMedFile.getDocumentObjectIdentifier().isEmpty() == false) { studyDocumentObjectIdentifierLineEdit->setText(pubMedFile.getDocumentObjectIdentifier()); studyDocumentObjectIdentifierLineEdit->home(false); slotStudyDocumentObjectIdentifierLineEditChanged(); } if (pubMedFile.getAbstractText().isEmpty() == false) { studyCommentTextEdit->setText(pubMedFile.getAbstractText()); slotStudyCommentTextEditChanged(); } if (pubMedFile.getMedicalSubjectHeadings().isEmpty() == false) { studyMeshLineEdit->setText(pubMedFile.getMedicalSubjectHeadings()); slotStudyMeshLineEditChanged(); } } catch (FileException& e) { QMessageBox::critical(this, "ERROR", e.whatQString(), "OK"); return; } */ } //===================================================================================== // // Widget for displaying a study // //===================================================================================== /** * constructor. */ StudyWidget::StudyWidget(GuiStudyMetaDataFileEditorDialog* parentStudyMetaDataFileEditorDialogIn, StudyMetaData* studyMetaDataIn, QWidget* parentIn) : QGroupBox("Study Metadata", parentIn) { parentStudyMetaDataFileEditorDialog = parentStudyMetaDataFileEditorDialogIn; studyMetaData = studyMetaDataIn; // // Validator for PubMed ID which is an optional minus sign followed by digits // Also allow it to be a project ID which begins with "ProjID" // QRegExpValidator* pubMedIDValidator = new QRegExpValidator( QRegExp("[P|0-9][r|0-9][o|0-9][j|0-9][I|0-9][D|0-9]\\d*"), //QRegExp("ProjID\\d+"), //("\\d+") this); QLabel* studyFileIndexLabel = new QLabel("File Index"); studyFileIndexDetailsLabel = new QLabel(""); QLabel* studyProjectIDLabel = new QLabel("Project ID"); studyProjectIDLineEdit = new QLineEdit; studyProjectIDLineEdit->setReadOnly(true); studyProjectIDLineEdit->setToolTip("A unique number for identifying this study.\n" "It is used to identify the study when a\n" "PubMed ID is not available."); QObject::connect(studyProjectIDLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotStudyProjectIDLineEditChanged())); QLabel* studyNameLabel = new QLabel("Name"); studyNameLineEdit = new QLineEdit; studyNameLineEdit->setToolTip("User-define name assigned to study.\n" "Sometimes this name is used for \n" "naming foci."); QObject::connect(studyNameLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotStudyNameLineEditChanged())); QLabel* studyTitleLabel = new QLabel("Title"); studyTitleLineEdit = new QLineEdit; studyTitleLineEdit->setToolTip("Title of the article."); QObject::connect(studyTitleLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotStudyTitleLineEditChanged())); QLabel* studyAuthorsLabel = new QLabel("Authors"); studyAuthorsLineEdit = new QLineEdit; studyAuthorsLineEdit->setToolTip("Author(s) of the article."); QObject::connect(studyAuthorsLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotStudyAuthorsLineEditChanged())); QLabel* studyCitationLabel = new QLabel("Citation"); studyCitationLineEdit = new QLineEdit; studyCitationLineEdit->setToolTip("Name of journal."); QObject::connect(studyCitationLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotStudyCitationLineEditChanged())); QLabel* studyKeywordsLabel = new QLabel("Keywords"); studyKeywordsLineEdit = new QLineEdit; studyKeywordsLineEdit->setToolTip("Article keywords."); QObject::connect(studyKeywordsLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotStudyKeywordsLineEditChanged())); QObject::connect(studyKeywordsLineEdit, SIGNAL(editingFinished()), this, SLOT(slotStudyKeywordsLineEditFinished())); keywordsModifiedFlag = false; QLabel* studyMeshLabel = new QLabel("Medical Subject Headings"); studyMeshLineEdit = new QLineEdit; studyMeshLineEdit->setToolTip("Medical Subject Headings"); QObject::connect(studyMeshLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotStudyMeshLineEditChanged())); QPushButton* studySpeciesPushButton = new QPushButton("Species..."); studySpeciesPushButton->setAutoDefault(false); QObject::connect(studySpeciesPushButton, SIGNAL(clicked()), this, SLOT(slotStudySpeciesPushButton())); studySpeciesLineEdit = new QLineEdit; studySpeciesLineEdit->setToolTip("Species used in study."); QObject::connect(studySpeciesLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotStudySpeciesLineEditChanged())); QPushButton* studyStereotaxicSpacePushButton = new QPushButton("Stereotaxic Space..."); studyStereotaxicSpacePushButton->setAutoDefault(false); QObject::connect(studyStereotaxicSpacePushButton, SIGNAL(clicked()), this, SLOT(slotStudyStereotaxicSpacePushButton())); studyStereotaxicSpaceLineEdit = new QLineEdit; studyStereotaxicSpaceLineEdit->setToolTip("Short name of stereotaxic space."); QObject::connect(studyStereotaxicSpaceLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotStudyStereotaxicSpaceLineEditChanged())); QLabel* studyStereotaxicSpaceDetailsLabel = new QLabel("Stereo Space Details"); studyStereotaxicSpaceDetailsLineEdit = new QLineEdit; studyStereotaxicSpaceDetailsLineEdit->setToolTip("Details about the stereotaxic space."); QObject::connect(studyStereotaxicSpaceDetailsLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotStudyStereotaxicSpaceDetailsLineEditChanged())); QLabel* studyDataFormatLabel = new QLabel("Data Format"); QPushButton* studyDataFormatAddPushButton = new QPushButton("Add"); studyDataFormatAddPushButton->setAutoDefault(false); QObject::connect(studyDataFormatAddPushButton, SIGNAL(clicked()), this, SLOT(slotStudyDataFormatAddPushButton())); QHBoxLayout* studyDataFormatLabelAndButtonLayout = new QHBoxLayout; studyDataFormatLabelAndButtonLayout->addWidget(studyDataFormatLabel); studyDataFormatLabelAndButtonLayout->addWidget(studyDataFormatAddPushButton); studyDataFormatLineEdit = new QLineEdit; studyDataFormatLineEdit->setToolTip("Format of study data (Metric, Paint, etc.)"); QObject::connect(studyDataFormatLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotStudyDataFormatLineEditChanged())); QLabel* studyDataTypeLabel = new QLabel("Data Type"); QPushButton* studyDataTypeAddPushButton = new QPushButton("Add"); studyDataTypeAddPushButton->setAutoDefault(false); QObject::connect(studyDataTypeAddPushButton, SIGNAL(clicked()), this, SLOT(slotStudyDataTypeAddPushButton())); QHBoxLayout* studyDataTypeLabelAndButtonLayout = new QHBoxLayout; studyDataTypeLabelAndButtonLayout->addWidget(studyDataTypeLabel); studyDataTypeLabelAndButtonLayout->addWidget(studyDataTypeAddPushButton); studyDataTypeLineEdit = new QLineEdit; studyDataTypeLineEdit->setToolTip("Type of study data (fMRI, PET, etc.)"); QObject::connect(studyDataTypeLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotStudyDataTypeLineEditChanged())); QLabel* studyPubMedIDLabel = new QLabel("PubMed ID"); QPushButton* studyPubMedIDPushButton = new QPushButton("Link"); studyPubMedIDPushButton->setAutoDefault(false); studyPubMedIDPushButton->setToolTip("Press this button to \n" "view the web-page for\n" "this PubMed ID."); QObject::connect(studyPubMedIDPushButton, SIGNAL(clicked()), this, SLOT(slotStudyPubMedIDPushButton())); studyPubMedIDLineEdit = new QLineEdit; studyPubMedIDLineEdit->setValidator(pubMedIDValidator); studyPubMedIDLineEdit->setToolTip("The PubMed ID of the article (www.pubmed.org)\n" "If there is not a PubMed ID for this study, this\n" "value should be the same as the Project ID."); QObject::connect(studyPubMedIDLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotStudyPubMedIDSpinBoxChanged())); QHBoxLayout* studyPubMedIdLabelAndFetchButtonLayout = new QHBoxLayout; studyPubMedIdLabelAndFetchButtonLayout->addWidget(studyPubMedIDLabel); studyPubMedIdLabelAndFetchButtonLayout->addWidget(studyPubMedIDPushButton); QLabel* studyDocumentObjectIdentifierLabel = new QLabel("DOI-URL"); QPushButton* studyDocumentObjectIdentifierPushButton = new QPushButton("Link"); studyDocumentObjectIdentifierPushButton->setAutoDefault(false); studyDocumentObjectIdentifierPushButton->setToolTip("Press this button to \n" "view the web-page for\n" "this DOI or URL."); QObject::connect(studyDocumentObjectIdentifierPushButton, SIGNAL(clicked()), this, SLOT(slotStudyDocumentObjectIdentifierPushButton())); QHBoxLayout* doiURLLayout = new QHBoxLayout; doiURLLayout->addWidget(studyDocumentObjectIdentifierLabel); doiURLLayout->addWidget(studyDocumentObjectIdentifierPushButton); studyDocumentObjectIdentifierLineEdit = new QLineEdit; studyDocumentObjectIdentifierLineEdit->setToolTip("DOI(Document Object Identifier, dx.ori.org) or URL of article.\n" "Use the DOI if it is available, otherwise use the URL."); QObject::connect(studyDocumentObjectIdentifierLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotStudyDocumentObjectIdentifierLineEditChanged())); QLabel* studyCommentLabel = new QLabel("Comment"); studyCommentTextEdit = new QTextEdit; studyCommentTextEdit->setReadOnly(false); studyCommentTextEdit->setToolTip("Comments about the article."); studyCommentTextEdit->setMinimumHeight(minimumTextEditHeight); QObject::connect(studyCommentTextEdit, SIGNAL(textChanged()), this, SLOT(slotStudyCommentTextEditChanged())); QLabel* studyPartitioningSchemeAbbreviationLabel = new QLabel("Part Scheme Abbrev"); studyPartitioningSchemeAbbreviationLineEdit = new QLineEdit; studyPartitioningSchemeAbbreviationLineEdit->setToolTip("Abbreviated name of partitioning scheme."); QObject::connect(studyPartitioningSchemeAbbreviationLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotStudyPartitioningSchemeAbbreviationLineEditChanged())); QLabel* studyPartitioningSchemeFullNameLabel = new QLabel("Part Scheme Name"); studyPartitioningSchemeFullNameLineEdit = new QLineEdit; studyPartitioningSchemeFullNameLineEdit->setToolTip("Full name of partitioning scheme."); QObject::connect(studyPartitioningSchemeFullNameLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotStudyPartitioningSchemeFullNameLineEditChanged())); QLabel* studyQualityLabel = new QLabel("Quality"); studyQualityLineEdit = new QLineEdit; studyQualityLineEdit->setToolTip("Trustworthiness of data."); QObject::connect(studyQualityLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotStudyQualityLineEditChanged())); QLabel* studyLastSaveLabel = new QLabel("Last Saved"); studyLastSaveLineEdit = new QLineEdit; studyLastSaveLineEdit->setToolTip("Contains last date and time this\n" "study was last saved."); studyLastSaveLineEdit->setReadOnly(true); int rowCounter = 0; const int studyIndexRow = rowCounter++; const int studyProjectIDRow = rowCounter++; const int studyPubMedIDRow = rowCounter++; const int studyNameRow = rowCounter++; const int studyTitleRow = rowCounter++; const int studyAuthorsRow = rowCounter++; const int studyCitationRow = rowCounter++; const int studyDocumentObjectIdentifierRow = rowCounter++; const int studySpeciesRow = rowCounter++; const int studyStereotaxicSpaceRow = rowCounter++; const int studyStereotaxicSpaceDetailsRow = rowCounter++; const int studyDataFormatRow = rowCounter++; const int studyDataTypeRow = rowCounter++; const int studyKeywordsRow = rowCounter++; const int studyMeshRow = rowCounter++; const int studyPartitioningSchemeAbbreviationRow = rowCounter++; const int studyPartitioningSchemeFullNameRow = rowCounter++; const int studyQualityRow = rowCounter++; const int studyCommentRow = rowCounter++; const int studyLastSaveRow = rowCounter++; QGridLayout* grid = new QGridLayout; grid->addWidget(studyFileIndexLabel, studyIndexRow, 0); grid->addWidget(studyFileIndexDetailsLabel, studyIndexRow, 1); grid->addWidget(studyProjectIDLabel, studyProjectIDRow, 0); grid->addWidget(studyProjectIDLineEdit, studyProjectIDRow, 1); grid->addLayout(studyPubMedIdLabelAndFetchButtonLayout, studyPubMedIDRow, 0); grid->addWidget(studyPubMedIDLineEdit, studyPubMedIDRow, 1); grid->addWidget(studyNameLabel, studyNameRow, 0); grid->addWidget(studyNameLineEdit, studyNameRow, 1); grid->addWidget(studyTitleLabel, studyTitleRow, 0); grid->addWidget(studyTitleLineEdit, studyTitleRow, 1); grid->addWidget(studyAuthorsLabel, studyAuthorsRow, 0); grid->addWidget(studyAuthorsLineEdit, studyAuthorsRow, 1); grid->addWidget(studyCitationLabel, studyCitationRow, 0); grid->addWidget(studyCitationLineEdit, studyCitationRow, 1); grid->addLayout(doiURLLayout, studyDocumentObjectIdentifierRow, 0); grid->addWidget(studyDocumentObjectIdentifierLineEdit, studyDocumentObjectIdentifierRow, 1); grid->addWidget(studySpeciesPushButton, studySpeciesRow, 0); grid->addWidget(studySpeciesLineEdit, studySpeciesRow, 1); grid->addWidget(studyStereotaxicSpacePushButton, studyStereotaxicSpaceRow, 0); grid->addWidget(studyStereotaxicSpaceLineEdit, studyStereotaxicSpaceRow, 1); grid->addWidget(studyStereotaxicSpaceDetailsLabel, studyStereotaxicSpaceDetailsRow, 0); grid->addWidget(studyStereotaxicSpaceDetailsLineEdit, studyStereotaxicSpaceDetailsRow, 1); grid->addLayout(studyDataFormatLabelAndButtonLayout, studyDataFormatRow, 0); grid->addWidget(studyDataFormatLineEdit, studyDataFormatRow, 1); grid->addLayout(studyDataTypeLabelAndButtonLayout, studyDataTypeRow, 0); grid->addWidget(studyDataTypeLineEdit, studyDataTypeRow, 1); grid->addWidget(studyKeywordsLabel, studyKeywordsRow, 0); grid->addWidget(studyKeywordsLineEdit, studyKeywordsRow, 1); grid->addWidget(studyMeshLabel, studyMeshRow, 0); grid->addWidget(studyMeshLineEdit, studyMeshRow, 1); grid->addWidget(studyPartitioningSchemeAbbreviationLabel, studyPartitioningSchemeAbbreviationRow, 0); grid->addWidget(studyPartitioningSchemeAbbreviationLineEdit, studyPartitioningSchemeAbbreviationRow, 1); grid->addWidget(studyPartitioningSchemeFullNameLabel, studyPartitioningSchemeFullNameRow, 0); grid->addWidget(studyPartitioningSchemeFullNameLineEdit, studyPartitioningSchemeFullNameRow, 1); grid->addWidget(studyQualityLabel, studyQualityRow, 0); grid->addWidget(studyQualityLineEdit, studyQualityRow, 1); grid->addWidget(studyCommentLabel, studyCommentRow, 0); grid->addWidget(studyCommentTextEdit, studyCommentRow, 1); grid->addWidget(studyLastSaveLabel, studyLastSaveRow, 0); grid->addWidget(studyLastSaveLineEdit, studyLastSaveRow, 1); QLabel* studyMslIDLabel = new QLabel("MSL ID"); studyMslIDLineEdit = new QLineEdit; studyMslIDLineEdit->setReadOnly(true); QObject::connect(studyMslIDLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotStudyMslIDLineEditChanged())); QLabel* studyParentIDLabel = new QLabel("Parent ID"); studyParentIDLineEdit = new QLineEdit; studyParentIDLineEdit->setReadOnly(true); QObject::connect(studyParentIDLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotStudyParentIDLineEditChanged())); QLabel* studyCoreDataCompletedLabel = new QLabel("Core Data Completed"); studyCoreDataCompletedLineEdit = new QLineEdit; studyCoreDataCompletedLineEdit->setReadOnly(true); QObject::connect(studyCoreDataCompletedLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotStudyCoreDataCompletedLineEditChanged())); QLabel* studyCompletedLabel = new QLabel("Completed"); studyCompletedLineEdit = new QLineEdit; studyCompletedLineEdit->setReadOnly(true); QObject::connect(studyCompletedLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotStudyCompletedLineEditChanged())); QLabel* studyPublicAccessLabel = new QLabel("Public Access"); studyPublicAccessLineEdit = new QLineEdit; studyPublicAccessLineEdit->setReadOnly(true); QObject::connect(studyPublicAccessLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotStudyPublicAccessLineEditChanged())); int rowCounter2 = 0; const int studyMslIDRow = rowCounter2++; const int studyParentIDRow = rowCounter2++; const int studyCoreDataCompletedRow = rowCounter2++; const int studyCompletedRow = rowCounter2++; const int studyPublicAccessRow = rowCounter2++; QGridLayout* grid2 = new QGridLayout; grid2->addWidget(studyMslIDLabel, studyMslIDRow, 0); grid2->addWidget(studyMslIDLineEdit, studyMslIDRow, 1); grid2->addWidget(studyParentIDLabel, studyParentIDRow, 0); grid2->addWidget(studyParentIDLineEdit, studyParentIDRow, 1); grid2->addWidget(studyCoreDataCompletedLabel, studyCoreDataCompletedRow, 0); grid2->addWidget(studyCoreDataCompletedLineEdit, studyCoreDataCompletedRow, 1); grid2->addWidget(studyCompletedLabel, studyCompletedRow, 0); grid2->addWidget(studyCompletedLineEdit, studyCompletedRow, 1); grid2->addWidget(studyPublicAccessLabel, studyPublicAccessRow, 0); grid2->addWidget(studyPublicAccessLineEdit, studyPublicAccessRow, 1); // // layouts for tables and figures // figuresLayout = new QVBoxLayout; pageReferenceLayout = new QVBoxLayout; provenanceLayout = new QVBoxLayout; tablesLayout = new QVBoxLayout; // // Layout for study information // layout = new QVBoxLayout(this); layout->addLayout(grid); layout->addLayout(figuresLayout); layout->addLayout(pageReferenceLayout); layout->addLayout(tablesLayout); layout->addLayout(grid2); layout->addLayout(provenanceLayout); // // Place the study data widgets into a widgets group for blocking signals // allWidgetsGroup = new WuQWidgetGroup(this); allWidgetsGroup->addWidget(studyFileIndexDetailsLabel); allWidgetsGroup->addWidget(studyProjectIDLineEdit); allWidgetsGroup->addWidget(studyNameLineEdit); allWidgetsGroup->addWidget(studyTitleLineEdit); allWidgetsGroup->addWidget(studyAuthorsLineEdit); allWidgetsGroup->addWidget(studyCitationLineEdit); allWidgetsGroup->addWidget(studyKeywordsLineEdit); allWidgetsGroup->addWidget(studyMeshLineEdit); allWidgetsGroup->addWidget(studySpeciesLineEdit); allWidgetsGroup->addWidget(studyStereotaxicSpaceLineEdit); allWidgetsGroup->addWidget(studyStereotaxicSpaceDetailsLineEdit); allWidgetsGroup->addWidget(studyDataFormatLineEdit); allWidgetsGroup->addWidget(studyDataTypeLineEdit); allWidgetsGroup->addWidget(studyPubMedIDLineEdit); allWidgetsGroup->addWidget(studyDocumentObjectIdentifierLineEdit); allWidgetsGroup->addWidget(studyCommentTextEdit); allWidgetsGroup->addWidget(studyPartitioningSchemeAbbreviationLineEdit); allWidgetsGroup->addWidget(studyPartitioningSchemeFullNameLineEdit); allWidgetsGroup->addWidget(studyQualityLineEdit); allWidgetsGroup->addWidget(studyLastSaveLineEdit); allWidgetsGroup->addWidget(studyMslIDLineEdit); allWidgetsGroup->addWidget(studyParentIDLineEdit); allWidgetsGroup->addWidget(studyCoreDataCompletedLineEdit); allWidgetsGroup->addWidget(studyCompletedLineEdit); allWidgetsGroup->addWidget(studyPublicAccessLineEdit); loadData(); } /** * destructor. */ StudyWidget::~StudyWidget() { } /** * called when PubMed ID "LINK" button is pressed. */ void StudyWidget::slotStudyPubMedIDPushButton() { QString theURL = studyPubMedIDLineEdit->text().trimmed(); if (theURL.startsWith(StudyMetaData::getProjectIDInPubMedIDPrefix())) { const QString msg("The contents of the PubMed ID edit box\n" "must be a PubMed ID, not a Project ID"); QMessageBox::critical(this, "ERROR", msg); return; } if (theURL.startsWith("http:")) { theURL = theURL; } else { theURL = "http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?cmd=retrieve&db=pubmed&list_uids=" + theURL; } theMainWindow->displayWebPage(theURL); } /** * called when study data format ADD button is pressed. */ void StudyWidget::slotStudyDataFormatAddPushButton() { std::vector dataFormats; StudyMetaData::getStudyDataFormatEntries(dataFormats); QtListBoxSelectionDialog lb(this, "Data Formats", "", dataFormats); lb.setAllowMultipleItemSelection(true); if (lb.exec() == QtListBoxSelectionDialog::Accepted) { std::vector items; lb.getSelectedItems(items); QString s = studyDataFormatLineEdit->text().trimmed(); for (unsigned int i = 0; i < items.size(); i++) { if (s.isEmpty() == false) { s += "; "; } s += items[i]; } studyDataFormatLineEdit->setText(s); slotStudyDataFormatLineEditChanged(); } } /** * called when study data type ADD button is pressed. */ void StudyWidget::slotStudyDataTypeAddPushButton() { std::vector dataTypes; StudyMetaData::getStudyDataTypeEntries(dataTypes); QtListBoxSelectionDialog lb(this, "Data Types", "", dataTypes); lb.setAllowMultipleItemSelection(true); if (lb.exec() == QtListBoxSelectionDialog::Accepted) { std::vector items; lb.getSelectedItems(items); QString s = studyDataTypeLineEdit->text().trimmed(); for (unsigned int i = 0; i < items.size(); i++) { if (s.isEmpty() == false) { s += "; "; } s += items[i]; } studyDataTypeLineEdit->setText(s); slotStudyDataTypeLineEditChanged(); } } /** * called when DOI/URL "LINK" button is pressed. */ void StudyWidget::slotStudyDocumentObjectIdentifierPushButton() { QString theURL = studyDocumentObjectIdentifierLineEdit->text().trimmed(); if (theURL.startsWith("http:")) { theURL = theURL; } else { theURL = "http://dx.doi.org/" + theURL; } theMainWindow->displayWebPage(theURL); } /** * load data into the widget. */ void StudyWidget::loadData() { StudyMetaDataFile* smdf = theMainWindow->getBrainSet()->getStudyMetaDataFile(); const QString indexString(QString::number(smdf->getStudyMetaDataIndex(studyMetaData) + 1) + " of " + QString::number(smdf->getNumberOfStudyMetaData())); allWidgetsGroup->blockSignals(true); studyFileIndexDetailsLabel->setText(indexString); studyProjectIDLineEdit->setText(studyMetaData->getProjectID()); studyNameLineEdit->setText(studyMetaData->getName()); studyNameLineEdit->home(false); studyTitleLineEdit->setText(studyMetaData->getTitle()); studyTitleLineEdit->home(false); studyAuthorsLineEdit->setText(studyMetaData->getAuthors()); studyAuthorsLineEdit->home(false); studyCitationLineEdit->setText(studyMetaData->getCitation()); studyCitationLineEdit->home(false); studyPubMedIDLineEdit->setText(studyMetaData->getPubMedID()); studyDocumentObjectIdentifierLineEdit->setText(studyMetaData->getDocumentObjectIdentifier()); studyDocumentObjectIdentifierLineEdit->home(false); studySpeciesLineEdit->setText(studyMetaData->getSpecies()); studySpeciesLineEdit->home(false); studyStereotaxicSpaceLineEdit->setText(studyMetaData->getStereotaxicSpace()); studyStereotaxicSpaceLineEdit->home(false); studyStereotaxicSpaceDetailsLineEdit->setText(studyMetaData->getStereotaxicSpaceDetails()); studyStereotaxicSpaceDetailsLineEdit->home(false); studyDataFormatLineEdit->setText(studyMetaData->getStudyDataFormat()); studyDataFormatLineEdit->home(false); studyDataTypeLineEdit->setText(studyMetaData->getStudyDataType()); studyDataTypeLineEdit->home(false); studyKeywordsLineEdit->setText(studyMetaData->getKeywords()); studyKeywordsLineEdit->home(false); keywordsModifiedFlag = false; studyMeshLineEdit->setText(studyMetaData->getMedicalSubjectHeadings()); studyMeshLineEdit->home(false); studyPartitioningSchemeAbbreviationLineEdit->setText(studyMetaData->getPartitioningSchemeAbbreviation()); studyPartitioningSchemeAbbreviationLineEdit->home(false); studyPartitioningSchemeFullNameLineEdit->setText(studyMetaData->getPartitioningSchemeFullName()); studyPartitioningSchemeFullNameLineEdit->home(false); studyQualityLineEdit->setText(studyMetaData->getQuality()); studyQualityLineEdit->home(false); studyCommentTextEdit->setPlainText(studyMetaData->getComment()); studyLastSaveLineEdit->setText(studyMetaData->getMostRecentDateAndTimeStamp()); studyMslIDLineEdit->setText(studyMetaData->getMslID()); studyParentIDLineEdit->setText(studyMetaData->getParentID()); studyCoreDataCompletedLineEdit->setText(studyMetaData->getCoreDataCompleted()); studyCompletedLineEdit->setText(studyMetaData->getCompleted()); studyPublicAccessLineEdit->setText(studyMetaData->getPublicAccess()); //QTextCursor tc; //tc.movePosition(QTextCursor::Start); //studyCommentTextEdit->setTextCursor(tc); allWidgetsGroup->blockSignals(false); const int numFigures = studyMetaData->getNumberOfFigures(); for (int i = 0; i < numFigures; i++) { addFigure(studyMetaData->getFigure(i)); } const int numPageRef = studyMetaData->getNumberOfPageReferences(); for (int i = 0; i < numPageRef; i++) { addPageReference(studyMetaData->getPageReference(i)); } const int numProvenance = studyMetaData->getNumberOfProvenances(); for (int i = 0; i < numProvenance; i++) { addProvenance(studyMetaData->getProvenance(i)); } const int numTables = studyMetaData->getNumberOfTables(); for (int i = 0; i < numTables; i++) { addTable(studyMetaData->getTable(i)); } } /** * add a figure to the study (if NULL create new figure). */ void StudyWidget::addFigure(StudyMetaData::Figure* figure) { if (figure == NULL) { figure = new StudyMetaData::Figure; studyMetaData->addFigure(figure); } StudyFigureWidget* figureWidget = new StudyFigureWidget(figure, this); figuresLayout->addWidget(figureWidget); } /** * remove a figure widget from its layout (does not delete the widget). */ void StudyWidget::removeFigureWidget(StudyFigureWidget* figureWidget) { figuresLayout->removeWidget(figureWidget); StudyMetaData::Figure* figure = figureWidget->getFigureInThisWidget(); studyMetaData->deleteFigure(figure); } /** * add a table to the study (if NULL add new, empty table). */ void StudyWidget::addTable(StudyMetaData::Table* table) { if (table == NULL) { // // Determine the number for the new table // QString tableNumber; StudyMetaData* smd = getCurrentStudyMetaData(); const int numTables = smd->getNumberOfTables(); if (numTables > 0) { const StudyMetaData::Table* t = smd->getTable(numTables - 1); bool ok = false; int tn = t->getNumber().toInt(&ok); if (ok) { tn++; tableNumber = QString::number(tn); } } // // Create the new table, add a subheader to the table, and add table to the study widget // table = new StudyMetaData::Table; if (tableNumber.isEmpty() == false) { table->setNumber(tableNumber); } table->addSubHeader(new StudyMetaData::SubHeader); studyMetaData->addTable(table); } StudyTableWidget* tableWidget = new StudyTableWidget(table, this); tablesLayout->addWidget(tableWidget); } /** * remove a table widget from its layout (does not delete the widget). */ void StudyWidget::removeTableWidget(StudyTableWidget* tableWidget) { tablesLayout->removeWidget(tableWidget); StudyMetaData::Table* table = tableWidget->getTableInThisWidget(); studyMetaData->deleteTable(table); } /** * add a page reference to the study (if NULL add new, empty page reference). */ void StudyWidget::addPageReference(StudyMetaData::PageReference* pageReference) { if (pageReference == NULL) { pageReference = new StudyMetaData::PageReference; studyMetaData->addPageReference(pageReference); } StudyPageReferenceWidget* pageReferenceWidget = new StudyPageReferenceWidget(pageReference, this); pageReferenceLayout->addWidget(pageReferenceWidget); } /** * add a provenance to the study (if NULL add new, empty provenance) */ void StudyWidget::addProvenance(StudyMetaData::Provenance* provenance) { if (provenance == NULL) { provenance = new StudyMetaData::Provenance; studyMetaData->addProvenance(provenance); } StudyProvenanceWidget* provenanceWidget = new StudyProvenanceWidget(provenance, this); provenanceLayout->addWidget(provenanceWidget); } /** * remove a page reference widget from its layout (does not delete the widget). */ void StudyWidget::removePageReferenceWidget(StudyPageReferenceWidget* pageReferenceWidget) { pageReferenceLayout->removeWidget(pageReferenceWidget); StudyMetaData::PageReference* pageRef = pageReferenceWidget->getPageReferenceInThisWidget(); studyMetaData->deletePageReference(pageRef); } /** * remove a provenance widget from its layout (does not delete the widget). */ void StudyWidget::removeProvenanceWidget(StudyProvenanceWidget* provenanceWidget) { provenanceLayout->removeWidget(provenanceWidget); StudyMetaData::Provenance* provenance = provenanceWidget->getProvenanceInThisWidget(); studyMetaData->deleteProvenance(provenance); } /** * save all data including figures and tables. */ void StudyWidget::saveDataIncludingFiguresAndTables() { // // Make sure study is still valid // StudyMetaDataFile* smdf = theMainWindow->getBrainSet()->getStudyMetaDataFile(); if (smdf->getStudyMetaDataIndex(studyMetaData) >= 0) { slotSaveData(); // // Save figure data // // // Save table data // } } /** * called when species button pressed. */ void StudyWidget::slotStudySpeciesPushButton() { GuiNameSelectionDialog nsd(this, GuiNameSelectionDialog::LIST_SPECIES, GuiNameSelectionDialog::LIST_SPECIES); if (nsd.exec() == GuiNameSelectionDialog::Accepted) { studySpeciesLineEdit->setText(nsd.getNameSelected()); slotStudySpeciesLineEditChanged(); } } /** * called when stereotaxic space button pressed. */ void StudyWidget::slotStudyStereotaxicSpacePushButton() { GuiNameSelectionDialog nsd(this, GuiNameSelectionDialog::LIST_STEREOTAXIC_SPACES, GuiNameSelectionDialog::LIST_STEREOTAXIC_SPACES); if (nsd.exec() == GuiNameSelectionDialog::Accepted) { studyStereotaxicSpaceLineEdit->setText(nsd.getNameSelected()); slotStudyStereotaxicSpaceLineEditChanged(); } } /** * called when study number changed. */ void StudyWidget::slotStudyProjectIDLineEditChanged() { studyMetaData->setProjectID(studyProjectIDLineEdit->text()); } /** * called when title changed. */ void StudyWidget::slotStudyTitleLineEditChanged() { studyMetaData->setTitle(studyTitleLineEdit->text()); } /** * called when authors changed. */ void StudyWidget::slotStudyAuthorsLineEditChanged() { studyMetaData->setAuthors(studyAuthorsLineEdit->text()); } /** * called when citation changed. */ void StudyWidget::slotStudyCitationLineEditChanged() { studyMetaData->setCitation(studyCitationLineEdit->text()); } /** * called when mesh changed. */ void StudyWidget::slotStudyMeshLineEditChanged() { studyMetaData->setMedicalSubjectHeadings(studyMeshLineEdit->text()); } /** * called when name changed. */ void StudyWidget::slotStudyNameLineEditChanged() { studyMetaData->setName(studyNameLineEdit->text()); } /** * called when pubmed id changed. */ void StudyWidget::slotStudyPubMedIDSpinBoxChanged() { studyMetaData->setPubMedID(studyPubMedIDLineEdit->text()); } /** * called when doi changed. */ void StudyWidget::slotStudyDocumentObjectIdentifierLineEditChanged() { studyMetaData->setDocumentObjectIdentifier(studyDocumentObjectIdentifierLineEdit->text()); } /** * called when species changed. */ void StudyWidget::slotStudySpeciesLineEditChanged() { studyMetaData->setSpecies(studySpeciesLineEdit->text()); } /** * called when space changed. */ void StudyWidget::slotStudyStereotaxicSpaceLineEditChanged() { studyMetaData->setStereotaxicSpace(studyStereotaxicSpaceLineEdit->text()); } /** * called when space details changed. */ void StudyWidget::slotStudyStereotaxicSpaceDetailsLineEditChanged() { studyMetaData->setStereotaxicSpaceDetails(studyStereotaxicSpaceDetailsLineEdit->text()); } /** * called when data format details changed. */ void StudyWidget::slotStudyDataFormatLineEditChanged() { studyMetaData->setStudyDataFormat(studyDataFormatLineEdit->text()); } /** * called when data type details changed. */ void StudyWidget::slotStudyDataTypeLineEditChanged() { studyMetaData->setStudyDataType(studyDataTypeLineEdit->text()); } /** * called when keywords changed. */ void StudyWidget::slotStudyKeywordsLineEditChanged() { keywordsModifiedFlag = (studyMetaData->getKeywords() != studyKeywordsLineEdit->text()); studyMetaData->setKeywords(studyKeywordsLineEdit->text()); } /** * called when keywords editing finished (return pressed or loses focus). */ void StudyWidget::slotStudyKeywordsLineEditFinished() { if (keywordsModifiedFlag) { QTimer::singleShot(0, this, SLOT(slotUpdateKeywordsAndGUI())); keywordsModifiedFlag = false; } } /** * called to update keywords in GUI. */ void StudyWidget::slotUpdateKeywordsAndGUI() { // GUI UPDATE IS TOO SLOW return; /* BrainSet* bs = theMainWindow->getBrainSet(); bs->getDisplaySettingsStudyMetaData()->update(); const StudyMetaDataFile* smdf = bs->getStudyMetaDataFile(); if ((bs->getFociProjectionFile()->empty() == false) && (smdf->getModified())) { bs->getDisplaySettingsFoci()->update(); bs->assignFociColors(); GuiFilesModified fm; fm.setFociModified(); fm.setStudyMetaDataModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } */ } /** * called when part scheme changed. */ void StudyWidget::slotStudyPartitioningSchemeAbbreviationLineEditChanged() { studyMetaData->setPartitioningSchemeAbbreviation(studyPartitioningSchemeAbbreviationLineEdit->text()); } /** * called when part schem name changed. */ void StudyWidget::slotStudyPartitioningSchemeFullNameLineEditChanged() { studyMetaData->setPartitioningSchemeFullName(studyPartitioningSchemeFullNameLineEdit->text()); } /** * called when quality changed. */ void StudyWidget::slotStudyQualityLineEditChanged() { studyMetaData->setQuality(studyQualityLineEdit->text()); } /** * called when msl id changed. */ void StudyWidget::slotStudyMslIDLineEditChanged() { studyMetaData->setMslID(studyMslIDLineEdit->text()); } /** * called when parent id changed. */ void StudyWidget::slotStudyParentIDLineEditChanged() { studyMetaData->setParentID(studyParentIDLineEdit->text()); } /** * called when core metadata changed. */ void StudyWidget::slotStudyCoreDataCompletedLineEditChanged() { studyMetaData->setCoreDataCompleted(studyCoreDataCompletedLineEdit->text()); } /** * called when completed changed. */ void StudyWidget::slotStudyCompletedLineEditChanged() { studyMetaData->setCompleted(studyCompletedLineEdit->text()); } /** * called when public access changed. */ void StudyWidget::slotStudyPublicAccessLineEditChanged() { studyMetaData->setPublicAccess(studyPublicAccessLineEdit->text()); } /** * called when comment changed. */ void StudyWidget::slotStudyCommentTextEditChanged() { studyMetaData->setComment(studyCommentTextEdit->toPlainText()); } /** * save the data into the study meta data table subheader. */ void StudyWidget::slotSaveData() { // // Make sure study is still valid // StudyMetaDataFile* smdf = theMainWindow->getBrainSet()->getStudyMetaDataFile(); if (smdf->getStudyMetaDataIndex(studyMetaData) >= 0) { } } //===================================================================================== // // Widget for displaying a table // //===================================================================================== /** * constructor. */ StudyTableWidget::StudyTableWidget(StudyMetaData::Table* tableIn, StudyWidget* parentStudyWidgetIn, QWidget* parentIn) : QGroupBox("Table", parentIn) { table = tableIn; parentStudyWidget = parentStudyWidgetIn; QLabel* tableNumberLabel = new QLabel("Number"); tableNumberLineEdit = new QLineEdit; tableNumberLineEdit->setToolTip("Enter the table number here."); QObject::connect(tableNumberLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotTableNumberLineEditChanged())); QLabel* tableHeaderLabel = new QLabel("Header"); tableHeaderLineEdit = new QLineEdit; tableHeaderLineEdit->setToolTip("Enter the table header here."); QObject::connect(tableHeaderLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotTableHeaderLineEditChanged())); QLabel* tableFooterLabel = new QLabel("Footer"); tableFooterTextEdit = new QTextEdit; tableFooterTextEdit->setReadOnly(false); tableFooterTextEdit->setMinimumHeight(minimumTextEditHeight); tableFooterTextEdit->setToolTip("Enter the table footer here."); QObject::connect(tableFooterTextEdit, SIGNAL(textChanged()), this, SLOT(slotTableFooterTextEditChanged())); QLabel* tableSizeUnitsLabel = new QLabel("Size Units"); tableSizeUnitsLineEdit = new QLineEdit; tableSizeUnitsLineEdit->setToolTip("Enter the size units (mm, voxels, etc) here."); QObject::connect(tableSizeUnitsLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotTableSizeUnitsLineEditChanged())); QLabel* tableVoxelSizeLabel = new QLabel("Voxel Size"); tableVoxelSizeLineEdit = new QLineEdit; tableVoxelSizeLineEdit->setToolTip("Enter voxel size here."); QObject::connect(tableVoxelSizeLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotTableVoxelSizeLineEditChanged())); QPushButton* tableStatisticPushButton = new QPushButton("Statistic..."); tableStatisticPushButton->setAutoDefault(false); QObject::connect(tableStatisticPushButton, SIGNAL(clicked()), this, SLOT(slotTableStatisticPushButton())); tableStatisticLineEdit = new QLineEdit; tableStatisticLineEdit->setToolTip("Enter the statistic type here."); QObject::connect(tableStatisticLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotTableStatisticLineEditChanged())); QLabel* tableStatisticDescriptionLabel = new QLabel("Stat Description"); tableStatisticDescriptionLineEdit = new QLineEdit; tableStatisticDescriptionLineEdit->setToolTip("Enter a description of the \n" "statistic test here."); QObject::connect(tableStatisticDescriptionLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotTableStatisticDescriptionLineEditChanged())); int rowCounter = 0; const int tableNumberRow = rowCounter++; const int tableHeaderRow = rowCounter++; const int tableFooterRow = rowCounter++; const int tableSizeUnitsRow = rowCounter++; const int tableVoxelSizeRow = rowCounter++; const int tableStatisticRow = rowCounter++; const int tableStatisticDescriptionRow = rowCounter++; QGridLayout* grid = new QGridLayout; grid->addWidget(tableNumberLabel, tableNumberRow, 0); grid->addWidget(tableNumberLineEdit, tableNumberRow, 1); grid->addWidget(tableHeaderLabel, tableHeaderRow, 0); grid->addWidget(tableHeaderLineEdit, tableHeaderRow, 1); grid->addWidget(tableFooterLabel, tableFooterRow, 0); grid->addWidget(tableFooterTextEdit, tableFooterRow, 1); grid->addWidget(tableSizeUnitsLabel, tableSizeUnitsRow, 0); grid->addWidget(tableSizeUnitsLineEdit, tableSizeUnitsRow, 1); grid->addWidget(tableVoxelSizeLabel, tableVoxelSizeRow, 0); grid->addWidget(tableVoxelSizeLineEdit, tableVoxelSizeRow, 1); grid->addWidget(tableStatisticPushButton, tableStatisticRow, 0); grid->addWidget(tableStatisticLineEdit, tableStatisticRow, 1); grid->addWidget(tableStatisticDescriptionLabel, tableStatisticDescriptionRow, 0); grid->addWidget(tableStatisticDescriptionLineEdit, tableStatisticDescriptionRow, 1); QPushButton* addSubHeaderPushButton = new QPushButton("Add Sub Header to This Table"); addSubHeaderPushButton->setAutoDefault(false); QObject::connect(addSubHeaderPushButton, SIGNAL(clicked()), this, SLOT(slotAddSubHeaderPushButton())); QPushButton* deleteThisTablePushButton = new QPushButton("Delete This Table"); deleteThisTablePushButton->setAutoDefault(false); QObject::connect(deleteThisTablePushButton, SIGNAL(clicked()), this, SLOT(slotDeleteThisTablePushButton())); QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->addWidget(addSubHeaderPushButton); buttonsLayout->addWidget(deleteThisTablePushButton); buttonsLayout->addStretch(); subHeadersLayout = new QVBoxLayout; layout = new QVBoxLayout(this); layout->addLayout(grid); layout->addLayout(subHeadersLayout); layout->addLayout(buttonsLayout); allWidgetsGroup = new WuQWidgetGroup(this); allWidgetsGroup->addWidget(tableNumberLineEdit); allWidgetsGroup->addWidget(tableHeaderLineEdit); allWidgetsGroup->addWidget(tableFooterTextEdit); allWidgetsGroup->addWidget(tableSizeUnitsLineEdit); allWidgetsGroup->addWidget(tableVoxelSizeLineEdit); allWidgetsGroup->addWidget(tableStatisticLineEdit); allWidgetsGroup->addWidget(tableStatisticDescriptionLineEdit); loadData(); } /** * destructor. */ StudyTableWidget::~StudyTableWidget() { } /** * add a sub header to this table widget. */ void StudyTableWidget::addSubHeader(StudyMetaData::SubHeader* subHeader) { if (subHeader == NULL) { subHeader = new StudyMetaData::SubHeader; subHeader->setNumber(QString::number(table->getNumberOfSubHeaders() + 1)); table->addSubHeader(subHeader); } StudySubHeaderWidget* subHeaderWidget = new StudySubHeaderWidget(subHeader, this, NULL); subHeadersLayout->addWidget(subHeaderWidget); } /** * called when add sub header button is pressed. */ void StudyTableWidget::slotAddSubHeaderPushButton() { addSubHeader(NULL); } /** * called when delete this table widget button is pressed. */ void StudyTableWidget::slotDeleteThisTablePushButton() { if (QMessageBox::question(this, "Confirm", "Delete this table", (QMessageBox::Yes | QMessageBox::No), QMessageBox::Yes) == QMessageBox::Yes) { // // Remove this widget from its parent layout // parentStudyWidget->removeTableWidget(this); // // Tell QT to delete this widget when it gets pack to its event loop // this->deleteLater(); } } /** * remove a sub header widget. */ void StudyTableWidget::removeSubHeaderWidget(StudySubHeaderWidget* subHeaderWidget) { subHeadersLayout->removeWidget(subHeaderWidget); StudyMetaData::SubHeader* subHeader = subHeaderWidget->getSubHeaderInThisWidget(); table->deleteSubHeader(subHeader); } /** * load data into the widget. */ void StudyTableWidget::loadData() { allWidgetsGroup->blockSignals(true); tableNumberLineEdit->setText(table->getNumber()); tableHeaderLineEdit->setText(table->getHeader()); tableHeaderLineEdit->home(false); tableFooterTextEdit->setPlainText(table->getFooter()); //QTextCursor tc; //tc.movePosition(QTextCursor::Start); //tableFooterTextEdit->setTextCursor(tc); tableSizeUnitsLineEdit->setText(table->getSizeUnits()); tableSizeUnitsLineEdit->home(false); tableVoxelSizeLineEdit->setText(table->getVoxelDimensions()); tableVoxelSizeLineEdit->home(false); tableStatisticLineEdit->setText(table->getStatisticType()); tableStatisticLineEdit->home(false); tableStatisticDescriptionLineEdit->setText(table->getStatisticDescription()); tableStatisticDescriptionLineEdit->home(false); for (int i = 0; i < table->getNumberOfSubHeaders(); i++) { addSubHeader(table->getSubHeader(i)); } allWidgetsGroup->blockSignals(false); } /** * called when statistic push button pressed. */ void StudyTableWidget::slotTableStatisticPushButton() { GuiNameSelectionDialog nsd(this, GuiNameSelectionDialog::LIST_STATISTICS, GuiNameSelectionDialog::LIST_STATISTICS); if (nsd.exec() == GuiNameSelectionDialog::Accepted) { tableStatisticLineEdit->setText(nsd.getNameSelected()); slotTableStatisticLineEditChanged(); } } /** * called when table number changed. */ void StudyTableWidget::slotTableNumberLineEditChanged() { table->setNumber(tableNumberLineEdit->text()); } /** * called when table header changed. */ void StudyTableWidget::slotTableHeaderLineEditChanged() { table->setHeader(tableHeaderLineEdit->text()); } /** * called when table footer changed. */ void StudyTableWidget::slotTableFooterTextEditChanged() { table->setFooter(tableFooterTextEdit->toPlainText()); } /** * called when table size units changed. */ void StudyTableWidget::slotTableSizeUnitsLineEditChanged() { table->setSizeUnits(tableSizeUnitsLineEdit->text()); } /** * called when table voxel size changed. */ void StudyTableWidget::slotTableVoxelSizeLineEditChanged() { table->setVoxelDimensions(tableVoxelSizeLineEdit->text()); } /** * called when table statistic changed. */ void StudyTableWidget::slotTableStatisticLineEditChanged() { table->setStatisticType(tableStatisticLineEdit->text()); } /** * called when table statistic description changed. */ void StudyTableWidget::slotTableStatisticDescriptionLineEditChanged() { table->setStatisticDescription(tableStatisticDescriptionLineEdit->text()); } /** * save the data into the study meta data table. */ void StudyTableWidget::slotSaveData() { } //===================================================================================== // // Widget for displaying a sub header // //===================================================================================== /** * constructor. */ StudySubHeaderWidget::StudySubHeaderWidget(StudyMetaData::SubHeader* subHeaderIn, StudyTableWidget* parentStudyTableWidgetIn, StudyPageReferenceWidget* parentPageReferenceWidgetIn, QWidget* parentIn) : QGroupBox("Sub Header", parentIn) { subHeader = subHeaderIn; parentStudyTableWidget = parentStudyTableWidgetIn; parentPageReferenceWidget = parentPageReferenceWidgetIn; QLabel* subHeaderNumberLabel = new QLabel("Number"); subHeaderNumberLineEdit = new QLineEdit; subHeaderNumberLineEdit->setToolTip(""); QObject::connect(subHeaderNumberLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotSubHeaderNumberLineEditChanged())); QLabel* subHeaderNameLabel = new QLabel("Name"); subHeaderNameLineEdit = new QLineEdit; subHeaderNameLineEdit->setToolTip(""); QObject::connect(subHeaderNameLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotSubHeaderNameLineEditChanged())); QLabel* subHeaderShortNameLabel = new QLabel("Short Name"); subHeaderShortNameLineEdit = new QLineEdit; subHeaderShortNameLineEdit->setToolTip(""); QObject::connect(subHeaderShortNameLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotSubHeaderShortNameLineEditChanged())); QObject::connect(subHeaderShortNameLineEdit, SIGNAL(editingFinished()), this, SLOT(slotSubHeaderShortNameEditingFinished())); shortNameModifiedFlag = false; QLabel* subHeaderTaskDescriptionLabel = new QLabel("Task Description"); subHeaderTaskDescriptionLineEdit = new QLineEdit; subHeaderTaskDescriptionLineEdit->setToolTip(""); QObject::connect(subHeaderTaskDescriptionLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotSubHeaderTaskDescriptionLineEditChanged())); QLabel* subHeaderTaskBaselineLabel = new QLabel("Task Baseline"); subHeaderTaskBaselineLineEdit = new QLineEdit; subHeaderTaskBaselineLineEdit->setToolTip(""); QObject::connect(subHeaderTaskBaselineLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotSubHeaderTaskBaselineLineEditChanged())); QLabel* subHeaderTestAttributesLabel = new QLabel("Test Attributes"); subHeaderTestAttributesLineEdit = new QLineEdit; subHeaderTestAttributesLineEdit->setToolTip(""); QObject::connect(subHeaderTestAttributesLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotSubHeaderTestAttributesLineEditChanged())); int rowCounter = 0; const int numberRow = rowCounter++; const int nameRow = rowCounter++; const int shortNameRow = rowCounter++; const int taskDescriptionRow = rowCounter++; const int taskBaselineRow = rowCounter++; const int testAttributesRow = rowCounter++; QGridLayout* grid = new QGridLayout; grid->addWidget(subHeaderNumberLabel, numberRow, 0); grid->addWidget(subHeaderNumberLineEdit, numberRow, 1); grid->addWidget(subHeaderNameLabel, nameRow, 0); grid->addWidget(subHeaderNameLineEdit, nameRow, 1); grid->addWidget(subHeaderShortNameLabel, shortNameRow, 0); grid->addWidget(subHeaderShortNameLineEdit, shortNameRow, 1); grid->addWidget(subHeaderTaskDescriptionLabel, taskDescriptionRow, 0); grid->addWidget(subHeaderTaskDescriptionLineEdit, taskDescriptionRow, 1); grid->addWidget(subHeaderTaskBaselineLabel, taskBaselineRow, 0); grid->addWidget(subHeaderTaskBaselineLineEdit, taskBaselineRow, 1); grid->addWidget(subHeaderTestAttributesLabel, testAttributesRow, 0); grid->addWidget(subHeaderTestAttributesLineEdit, testAttributesRow, 1); QPushButton* shortNameToClassPushButton = new QPushButton("Short Name to Foci Class"); shortNameToClassPushButton->setAutoDefault(false); shortNameToClassPushButton->setFixedSize(shortNameToClassPushButton->sizeHint()); QObject::connect(shortNameToClassPushButton, SIGNAL(clicked()), this, SLOT(slotSubHeaderToFociClass())); QPushButton* deleteThisSubHeaderPushButton = new QPushButton("Delete This Sub Header"); deleteThisSubHeaderPushButton->setAutoDefault(false); deleteThisSubHeaderPushButton->setFixedSize(deleteThisSubHeaderPushButton->sizeHint()); QObject::connect(deleteThisSubHeaderPushButton, SIGNAL(clicked()), this, SLOT(slotDeleteThisSubHeader())); QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->addWidget(shortNameToClassPushButton); buttonsLayout->addWidget(deleteThisSubHeaderPushButton); buttonsLayout->addStretch(); QVBoxLayout* layout = new QVBoxLayout(this); layout->addLayout(grid); layout->addLayout(buttonsLayout); allWidgetsGroup = new WuQWidgetGroup(this); allWidgetsGroup->addWidget(subHeaderNumberLineEdit); allWidgetsGroup->addWidget(subHeaderNameLineEdit); allWidgetsGroup->addWidget(subHeaderShortNameLineEdit); allWidgetsGroup->addWidget(subHeaderTaskDescriptionLineEdit); allWidgetsGroup->addWidget(subHeaderTaskBaselineLineEdit); allWidgetsGroup->addWidget(subHeaderTestAttributesLineEdit); loadData(); } /** * destructor. */ StudySubHeaderWidget::~StudySubHeaderWidget() { } /** * called when short name to foci class button pressed. */ void StudySubHeaderWidget::slotSubHeaderToFociClass() { const QString shortName = subHeaderShortNameLineEdit->text(); if (shortName.isEmpty() == false) { if (subHeader != NULL) { StudyMetaDataLink smdl; smdl.setTableSubHeaderNumber(subHeader->getNumber()); if (parentStudyTableWidget != NULL) { if (parentStudyTableWidget->table != NULL) { smdl.setTableNumber(parentStudyTableWidget->table->getNumber()); if (parentStudyTableWidget->parentStudyWidget != NULL) { if (parentStudyTableWidget->parentStudyWidget->studyMetaData != NULL) { smdl.setPubMedID( parentStudyTableWidget->parentStudyWidget->studyMetaData->getPubMedID()); theMainWindow->getBrainSet()->getFociProjectionFile( )->transferTableSubHeaderShortNameToCellClass(smdl, shortName); } } } } } } } /** * called when delete this sub header button is pressed. */ void StudySubHeaderWidget::slotDeleteThisSubHeader() { if (QMessageBox::question(this, "Confirm", "Delete this sub header", (QMessageBox::Yes | QMessageBox::No), QMessageBox::Yes) == QMessageBox::Yes) { // // Remove this widget from its parent layout // if (parentStudyTableWidget != NULL) { parentStudyTableWidget->removeSubHeaderWidget(this); } if (parentPageReferenceWidget != NULL) { parentPageReferenceWidget->removeSubHeaderWidget(this); } // // Tell QT to delete this widget when it gets pack to its event loop // this->deleteLater(); } } /** * load data into the widget. */ void StudySubHeaderWidget::loadData() { allWidgetsGroup->blockSignals(true); subHeaderNumberLineEdit->setText(subHeader->getNumber()); subHeaderNameLineEdit->setText(subHeader->getName()); subHeaderNameLineEdit->home(false); subHeaderShortNameLineEdit->setText(subHeader->getShortName()); subHeaderShortNameLineEdit->home(false); shortNameModifiedFlag = false; subHeaderTaskDescriptionLineEdit->setText(subHeader->getTaskDescription()); subHeaderTaskDescriptionLineEdit->home(false); subHeaderTaskBaselineLineEdit->setText(subHeader->getTaskBaseline()); subHeaderTaskBaselineLineEdit->home(false); subHeaderTestAttributesLineEdit->setText(subHeader->getTestAttributes()); subHeaderTestAttributesLineEdit->home(false); allWidgetsGroup->blockSignals(false); } /** * called when sub header number changed. */ void StudySubHeaderWidget::slotSubHeaderNumberLineEditChanged() { subHeader->setNumber(subHeaderNumberLineEdit->text()); } /** * called when sub header name changed. */ void StudySubHeaderWidget::slotSubHeaderNameLineEditChanged() { subHeader->setName(subHeaderNameLineEdit->text()); } /** * called when sub header short name changed. */ void StudySubHeaderWidget::slotSubHeaderShortNameLineEditChanged() { shortNameModifiedFlag = (subHeader->getShortName() != subHeaderShortNameLineEdit->text()); subHeader->setShortName(subHeaderShortNameLineEdit->text()); } /** * called when sub header short name editing finished. */ void StudySubHeaderWidget::slotSubHeaderShortNameEditingFinished() { if (shortNameModifiedFlag) { QTimer::singleShot(0, this, SLOT(slotUpdateShortNamesAndGUI())); shortNameModifiedFlag = false; } } /** * called to update gui. */ void StudySubHeaderWidget::slotUpdateShortNamesAndGUI() { // GUI UPDATE IS TOO SLOW return; /* BrainSet* bs = theMainWindow->getBrainSet(); bs->getDisplaySettingsStudyMetaData()->update(); const StudyMetaDataFile* smdf = bs->getStudyMetaDataFile(); if ((bs->getFociProjectionFile()->empty() == false) && (smdf->getModified())) { bs->getDisplaySettingsFoci()->update(); bs->assignFociColors(); GuiFilesModified fm; fm.setFociModified(); fm.setStudyMetaDataModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } */ } /** * called when sub header task description changed. */ void StudySubHeaderWidget::slotSubHeaderTaskDescriptionLineEditChanged() { subHeader->setTaskDescription(subHeaderTaskDescriptionLineEdit->text()); } /** * called when sub header task baseline changed. */ void StudySubHeaderWidget::slotSubHeaderTaskBaselineLineEditChanged() { subHeader->setTaskBaseline(subHeaderTaskBaselineLineEdit->text()); } /** * called when test attributes changed. */ void StudySubHeaderWidget::slotSubHeaderTestAttributesLineEditChanged() { subHeader->setTestAttributes(subHeaderTestAttributesLineEdit->text()); } /** * save the data into the study meta data table. */ void StudySubHeaderWidget::slotSaveData() { } //===================================================================================== // // Widget for displaying a figure // //===================================================================================== /** * constructor. */ StudyFigureWidget::StudyFigureWidget(StudyMetaData::Figure* figureIn, StudyWidget* parentStudyWidgetIn, QWidget* parentIn) : QGroupBox("Figure", parentIn) { figure = figureIn; parentStudyWidget = parentStudyWidgetIn; QLabel* figureNumberLabel = new QLabel("Number"); figureNumberLineEdit = new QLineEdit; figureNumberLineEdit->setToolTip("Enter the figure's number here."); QObject::connect(figureNumberLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotFigureNumberLineEditChanged())); QLabel* figureLegendLabel = new QLabel("Legend"); figureLegendLineEdit = new QLineEdit; figureLegendLineEdit->setToolTip("Enter the figure's legend here."); QObject::connect(figureLegendLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotFigureLegendLineEditChanged())); int rowCount = 0; const int figureNumberRow = rowCount++; const int figureLegendRow = rowCount++; QGridLayout* grid = new QGridLayout; grid->addWidget(figureNumberLabel, figureNumberRow, 0); grid->addWidget(figureNumberLineEdit, figureNumberRow, 1); grid->addWidget(figureLegendLabel, figureLegendRow, 0); grid->addWidget(figureLegendLineEdit, figureLegendRow, 1); QPushButton* addPanelPushButton = new QPushButton("Add Panel to This Figure"); addPanelPushButton->setAutoDefault(false); QObject::connect(addPanelPushButton, SIGNAL(clicked()), this, SLOT(slotAddPanelPushButton())); QPushButton* deleteThisFigurePushButton = new QPushButton("Delete This Figure"); deleteThisFigurePushButton->setAutoDefault(false); QObject::connect(deleteThisFigurePushButton, SIGNAL(clicked()), this, SLOT(slotDeleteThisFigurePushButton())); QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->addWidget(addPanelPushButton); buttonsLayout->addWidget(deleteThisFigurePushButton); buttonsLayout->addStretch(); panelsLayout = new QVBoxLayout; QVBoxLayout* layout = new QVBoxLayout(this); layout->addLayout(grid); layout->addLayout(panelsLayout); layout->addLayout(buttonsLayout); allWidgetsGroup = new WuQWidgetGroup(this); allWidgetsGroup->addWidget(figureNumberLineEdit); allWidgetsGroup->addWidget(figureLegendLineEdit); loadData(); } /** * destructor. */ StudyFigureWidget::~StudyFigureWidget() { } /** * called when add panel button is pressed. */ void StudyFigureWidget::slotAddPanelPushButton() { addPanel(NULL); } /** * called when delete this figure widget button is pressed. */ void StudyFigureWidget::slotDeleteThisFigurePushButton() { if (QMessageBox::question(this, "Confirm", "Delete this figure", (QMessageBox::Yes | QMessageBox::No), QMessageBox::Yes) == QMessageBox::Yes) { // // Remove this widget from its parent layout // parentStudyWidget->removeFigureWidget(this); // // Tell QT to delete this widget when it gets pack to its event loop // this->deleteLater(); } } /** * load data into the widget. */ void StudyFigureWidget::loadData() { allWidgetsGroup->blockSignals(true); figureNumberLineEdit->setText(figure->getNumber()); figureLegendLineEdit->setText(figure->getLegend()); figureLegendLineEdit->home(false); for (int i = 0; i < figure->getNumberOfPanels(); i++) { addPanel(figure->getPanel(i)); } allWidgetsGroup->blockSignals(false); } /** * called when figure number changed. */ void StudyFigureWidget::slotFigureNumberLineEditChanged() { figure->setNumber(figureNumberLineEdit->text()); } /** * called when figure legend changed. */ void StudyFigureWidget::slotFigureLegendLineEditChanged() { figure->setLegend(figureLegendLineEdit->text()); } /** * save the data into the study meta data table. */ void StudyFigureWidget::slotSaveData() { } /** * add a panel to this figure. */ void StudyFigureWidget::addPanel(StudyMetaData::Figure::Panel* panel) { if (panel == NULL) { panel = new StudyMetaData::Figure::Panel; figure->addPanel(panel); } StudyFigurePanelWidget* panelWidget = new StudyFigurePanelWidget(panel, this); panelsLayout->addWidget(panelWidget); } /** * remove a panel widget from its layout (does not delete the widget). */ void StudyFigureWidget::removePanelWidget(StudyFigurePanelWidget* panelWidget) { panelsLayout->removeWidget(panelWidget); StudyMetaData::Figure::Panel* panel = panelWidget->getPanelInThisWidget(); figure->deletePanel(panel); } //===================================================================================== // // Widget for displaying a figure panel // //===================================================================================== /** * constructor. */ StudyFigurePanelWidget::StudyFigurePanelWidget(StudyMetaData::Figure::Panel* figurePanelIn, StudyFigureWidget* parentFigureWidgetIn, QWidget* parentIn) : QGroupBox("Figure Panel", parentIn) { figurePanel = figurePanelIn; parentFigureWidget = parentFigureWidgetIn; QLabel* figurePaneIdentifierlLabel = new QLabel("Identifier"); figurePanelIdentifierLineEdit = new QLineEdit; figurePanelIdentifierLineEdit->setToolTip("Enter the figure panel's identifier here."); QObject::connect(figurePanelIdentifierLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotFigurePanelIdentifierLineEditChanged())); QLabel* figurePanelDescriptionLabel = new QLabel("Description"); figurePanelDescriptionLineEdit = new QLineEdit; figurePanelDescriptionLineEdit->setToolTip("Enter the figure panel's description here."); QObject::connect(figurePanelDescriptionLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotFigurePanelDescriptionLineEditChanged())); QLabel* figurePanelTaskDescriptionLabel = new QLabel("Task Description"); figurePanelTaskDescriptionLineEdit = new QLineEdit; figurePanelTaskDescriptionLineEdit->setToolTip("Enter the task's description here."); QObject::connect(figurePanelTaskDescriptionLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotFigurePanelTaskDescriptionLineEditChanged())); QLabel* figurePanelTaskBaselineLabel = new QLabel("Task Baseline"); figurePanelTaskBaselineLineEdit = new QLineEdit; figurePanelTaskBaselineLineEdit->setToolTip("Enter the task's baseline here."); QObject::connect(figurePanelTaskBaselineLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotFigurePanelTaskBaselineLineEditChanged())); QLabel* figurePanelTestAttributeslLabel = new QLabel("Test Attributes"); figurePanelTestAttributesLineEdit = new QLineEdit; figurePanelTestAttributesLineEdit->setToolTip("Enter the test's attributes here."); QObject::connect(figurePanelTestAttributesLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotFigurePanelTestAttributesLineEditChanged())); int rowCounter = 0; const int figurePanelIdentifierRow = rowCounter++; const int figurePanelDescriptionRow = rowCounter++; const int figurePanelTaskDescriptionRow = rowCounter++; const int figurePanelTaskBaselineRow = rowCounter++; const int figurePanelTestAttributesRow = rowCounter++; QGridLayout* grid = new QGridLayout; grid->addWidget(figurePaneIdentifierlLabel, figurePanelIdentifierRow, 0); grid->addWidget(figurePanelIdentifierLineEdit, figurePanelIdentifierRow, 1); grid->addWidget(figurePanelDescriptionLabel, figurePanelDescriptionRow, 0); grid->addWidget(figurePanelDescriptionLineEdit, figurePanelDescriptionRow, 1); grid->addWidget(figurePanelTaskDescriptionLabel, figurePanelTaskDescriptionRow, 0); grid->addWidget(figurePanelTaskDescriptionLineEdit, figurePanelTaskDescriptionRow, 1); grid->addWidget(figurePanelTaskBaselineLabel, figurePanelTaskBaselineRow, 0); grid->addWidget(figurePanelTaskBaselineLineEdit, figurePanelTaskBaselineRow, 1); grid->addWidget(figurePanelTestAttributeslLabel, figurePanelTestAttributesRow, 0); grid->addWidget(figurePanelTestAttributesLineEdit, figurePanelTestAttributesRow, 1); QPushButton* deleteThisPanelPushButton = new QPushButton("Delete This Panel"); deleteThisPanelPushButton->setAutoDefault(false); deleteThisPanelPushButton->setFixedSize(deleteThisPanelPushButton->sizeHint()); QObject::connect(deleteThisPanelPushButton, SIGNAL(clicked()), this, SLOT(slotDeleteThisPanelPushButton())); QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->addWidget(deleteThisPanelPushButton); buttonsLayout->addStretch(); layout = new QVBoxLayout(this); layout->addLayout(grid); layout->addLayout(buttonsLayout); allWidgetsGroup = new WuQWidgetGroup(this); allWidgetsGroup->addWidget(figurePanelIdentifierLineEdit); allWidgetsGroup->addWidget(figurePanelDescriptionLineEdit); allWidgetsGroup->addWidget(figurePanelTaskDescriptionLineEdit); allWidgetsGroup->addWidget(figurePanelTaskBaselineLineEdit); allWidgetsGroup->addWidget(figurePanelTestAttributesLineEdit); loadData(); } /** * destructor. */ StudyFigurePanelWidget::~StudyFigurePanelWidget() { } /** * called when delete this panel button pressed. */ void StudyFigurePanelWidget::slotDeleteThisPanelPushButton() { if (QMessageBox::question(this, "Confirm", "Delete this panel", (QMessageBox::Yes | QMessageBox::No), QMessageBox::Yes) == QMessageBox::Yes) { // // Remove this widget from its parent layout // parentFigureWidget->removePanelWidget(this); // // Tell QT to delete this widget when it gets pack to its event loop // this->deleteLater(); } } /** * load data into the widget. */ void StudyFigurePanelWidget::loadData() { allWidgetsGroup->blockSignals(true); figurePanelIdentifierLineEdit->setText(figurePanel->getPanelNumberOrLetter()); figurePanelIdentifierLineEdit->home(false); figurePanelDescriptionLineEdit->setText(figurePanel->getDescription()); figurePanelDescriptionLineEdit->home(false); figurePanelTaskDescriptionLineEdit->setText(figurePanel->getTaskDescription()); figurePanelTaskDescriptionLineEdit->home(false); figurePanelTaskBaselineLineEdit->setText(figurePanel->getTaskBaseline()); figurePanelTaskBaselineLineEdit->home(false); figurePanelTestAttributesLineEdit->setText(figurePanel->getTestAttributes()); figurePanelTestAttributesLineEdit->home(false); allWidgetsGroup->blockSignals(false); } /** * called when figure panel identifier changed. */ void StudyFigurePanelWidget::slotFigurePanelIdentifierLineEditChanged() { figurePanel->setPanelNumberOrLetter(figurePanelIdentifierLineEdit->text()); } /** * called when figure panel description changed. */ void StudyFigurePanelWidget::slotFigurePanelDescriptionLineEditChanged() { figurePanel->setDescription(figurePanelDescriptionLineEdit->text()); } /** * called when figure panel task description changed. */ void StudyFigurePanelWidget::slotFigurePanelTaskDescriptionLineEditChanged() { figurePanel->setTaskDescription(figurePanelTaskDescriptionLineEdit->text()); } /** * called when figure panel task baseline changed. */ void StudyFigurePanelWidget::slotFigurePanelTaskBaselineLineEditChanged() { figurePanel->setTaskBaseline(figurePanelTaskBaselineLineEdit->text()); } /** * called when figure panel test attributes changed. */ void StudyFigurePanelWidget::slotFigurePanelTestAttributesLineEditChanged() { figurePanel->setTestAttributes(figurePanelTestAttributesLineEdit->text()); } /** * save the data into the study meta data figure panel. */ void StudyFigurePanelWidget::slotSaveData() { } //===================================================================================== // // Widget for displaying a page reference // //===================================================================================== /** * constructor. */ StudyPageReferenceWidget::StudyPageReferenceWidget(StudyMetaData::PageReference* pageReferenceIn, StudyWidget* parentStudyWidgetIn, QWidget* parentIn) : QGroupBox("Page Reference", parentIn) { pageReference = pageReferenceIn; parentStudyWidget = parentStudyWidgetIn; QLabel* pageReferenceNumberLabel = new QLabel("Number"); pageReferenceNumberLineEdit = new QLineEdit; pageReferenceNumberLineEdit->setToolTip("Enter the page number here."); QObject::connect(pageReferenceNumberLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotPageReferencePageNumberLineEditChanged())); QLabel* pageReferenceHeaderLabel = new QLabel("Header"); pageReferenceHeaderLineEdit = new QLineEdit; pageReferenceHeaderLineEdit->setToolTip("Enter the page header here."); QObject::connect(pageReferenceHeaderLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotPageReferenceHeaderLineEditChanged())); QLabel* pageReferenceCommentLabel = new QLabel("Comment"); pageReferenceCommentTextEdit = new QTextEdit; pageReferenceCommentTextEdit->setReadOnly(false); pageReferenceCommentTextEdit->setMinimumHeight(minimumTextEditHeight); pageReferenceCommentTextEdit->setToolTip("Enter the pageReference footer here."); QObject::connect(pageReferenceCommentTextEdit, SIGNAL(textChanged()), this, SLOT(slotPageReferenceCommentTextEditChanged())); QLabel* pageReferenceSizeUnitsLabel = new QLabel("Size Units"); pageReferenceSizeUnitsLineEdit = new QLineEdit; pageReferenceSizeUnitsLineEdit->setToolTip("Enter the size units (mm, voxels, etc) here."); QObject::connect(pageReferenceSizeUnitsLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotPageReferenceSizeUnitsLineEditChanged())); QLabel* pageReferenceVoxelSizeLabel = new QLabel("Voxel Size"); pageReferenceVoxelSizeLineEdit = new QLineEdit; pageReferenceVoxelSizeLineEdit->setToolTip("Enter voxel size here."); QObject::connect(pageReferenceVoxelSizeLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotPageReferenceVoxelSizeLineEditChanged())); QPushButton* pageReferenceStatisticPushButton = new QPushButton("Statistic..."); pageReferenceStatisticPushButton->setAutoDefault(false); QObject::connect(pageReferenceStatisticPushButton, SIGNAL(clicked()), this, SLOT(slotPageReferenceStatisticPushButton())); pageReferenceStatisticLineEdit = new QLineEdit; pageReferenceStatisticLineEdit->setToolTip("Enter the statistic type here."); QObject::connect(pageReferenceStatisticLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotPageReferenceStatisticLineEditChanged())); QLabel* pageReferenceStatisticDescriptionLabel = new QLabel("Stat Description"); pageReferenceStatisticDescriptionLineEdit = new QLineEdit; pageReferenceStatisticDescriptionLineEdit->setToolTip("Enter a description of the \n" "statistic test here."); QObject::connect(pageReferenceStatisticDescriptionLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotPageReferenceStatisticDescriptionLineEditChanged())); int rowCounter = 0; const int pageReferenceNumberRow = rowCounter++; const int pageReferenceHeaderRow = rowCounter++; const int pageReferenceCommentRow = rowCounter++; const int pageReferenceSizeUnitsRow = rowCounter++; const int pageReferenceVoxelSizeRow = rowCounter++; const int pageReferenceStatisticRow = rowCounter++; const int pageReferenceStatisticDescriptionRow = rowCounter++; QGridLayout* grid = new QGridLayout; grid->addWidget(pageReferenceNumberLabel, pageReferenceNumberRow, 0); grid->addWidget(pageReferenceNumberLineEdit, pageReferenceNumberRow, 1); grid->addWidget(pageReferenceHeaderLabel, pageReferenceHeaderRow, 0); grid->addWidget(pageReferenceHeaderLineEdit, pageReferenceHeaderRow, 1); grid->addWidget(pageReferenceCommentLabel, pageReferenceCommentRow, 0); grid->addWidget(pageReferenceCommentTextEdit, pageReferenceCommentRow, 1); grid->addWidget(pageReferenceSizeUnitsLabel, pageReferenceSizeUnitsRow, 0); grid->addWidget(pageReferenceSizeUnitsLineEdit, pageReferenceSizeUnitsRow, 1); grid->addWidget(pageReferenceVoxelSizeLabel, pageReferenceVoxelSizeRow, 0); grid->addWidget(pageReferenceVoxelSizeLineEdit, pageReferenceVoxelSizeRow, 1); grid->addWidget(pageReferenceStatisticPushButton, pageReferenceStatisticRow, 0); grid->addWidget(pageReferenceStatisticLineEdit, pageReferenceStatisticRow, 1); grid->addWidget(pageReferenceStatisticDescriptionLabel, pageReferenceStatisticDescriptionRow, 0); grid->addWidget(pageReferenceStatisticDescriptionLineEdit, pageReferenceStatisticDescriptionRow, 1); QPushButton* addSubHeaderPushButton = new QPushButton("Add Sub Header to This Page Reference"); addSubHeaderPushButton->setAutoDefault(false); QObject::connect(addSubHeaderPushButton, SIGNAL(clicked()), this, SLOT(slotAddSubHeaderPushButton())); QPushButton* deleteThisPageReferencePushButton = new QPushButton("Delete This Page Reference"); deleteThisPageReferencePushButton->setAutoDefault(false); QObject::connect(deleteThisPageReferencePushButton, SIGNAL(clicked()), this, SLOT(slotDeleteThisPageReferencePushButton())); QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->addWidget(addSubHeaderPushButton); buttonsLayout->addWidget(deleteThisPageReferencePushButton); buttonsLayout->addStretch(); subHeadersLayout = new QVBoxLayout; layout = new QVBoxLayout(this); layout->addLayout(grid); layout->addLayout(subHeadersLayout); layout->addLayout(buttonsLayout); allWidgetsGroup = new WuQWidgetGroup(this); allWidgetsGroup->addWidget(pageReferenceNumberLineEdit); allWidgetsGroup->addWidget(pageReferenceHeaderLineEdit); allWidgetsGroup->addWidget(pageReferenceCommentTextEdit); allWidgetsGroup->addWidget(pageReferenceSizeUnitsLineEdit); allWidgetsGroup->addWidget(pageReferenceVoxelSizeLineEdit); allWidgetsGroup->addWidget(pageReferenceStatisticLineEdit); allWidgetsGroup->addWidget(pageReferenceStatisticDescriptionLineEdit); loadData(); } /** * destructor. */ StudyPageReferenceWidget::~StudyPageReferenceWidget() { } /** * add a sub header to this page reference widget. */ void StudyPageReferenceWidget::addSubHeader(StudyMetaData::SubHeader* subHeader) { if (subHeader == NULL) { subHeader = new StudyMetaData::SubHeader; subHeader->setNumber(QString::number(pageReference->getNumberOfSubHeaders() + 1)); pageReference->addSubHeader(subHeader); } StudySubHeaderWidget* subHeaderWidget = new StudySubHeaderWidget(subHeader, NULL, this); subHeadersLayout->addWidget(subHeaderWidget); } /** * called when add sub header button is pressed. */ void StudyPageReferenceWidget::slotAddSubHeaderPushButton() { addSubHeader(NULL); } /** * called when delete this pageReference widget button is pressed. */ void StudyPageReferenceWidget::slotDeleteThisPageReferencePushButton() { if (QMessageBox::question(this, "Confirm", "Delete this pageReference", (QMessageBox::Yes | QMessageBox::No), QMessageBox::Yes) == QMessageBox::Yes) { // // Remove this widget from its parent layout // parentStudyWidget->removePageReferenceWidget(this); // // Tell QT to delete this widget when it gets pack to its event loop // this->deleteLater(); } } /** * remove a sub header widget. */ void StudyPageReferenceWidget::removeSubHeaderWidget(StudySubHeaderWidget* subHeaderWidget) { subHeadersLayout->removeWidget(subHeaderWidget); StudyMetaData::SubHeader* subHeader = subHeaderWidget->getSubHeaderInThisWidget(); pageReference->deleteSubHeader(subHeader); } /** * load data into the widget. */ void StudyPageReferenceWidget::loadData() { allWidgetsGroup->blockSignals(true); pageReferenceNumberLineEdit->setText(pageReference->getPageNumber()); pageReferenceHeaderLineEdit->setText(pageReference->getHeader()); pageReferenceHeaderLineEdit->home(false); pageReferenceCommentTextEdit->setPlainText(pageReference->getComment()); //QTextCursor tc; //tc.movePosition(QTextCursor::Start); //pageReferenceFooterTextEdit->setTextCursor(tc); pageReferenceSizeUnitsLineEdit->setText(pageReference->getSizeUnits()); pageReferenceSizeUnitsLineEdit->home(false); pageReferenceVoxelSizeLineEdit->setText(pageReference->getVoxelDimensions()); pageReferenceVoxelSizeLineEdit->home(false); pageReferenceStatisticLineEdit->setText(pageReference->getStatisticType()); pageReferenceStatisticLineEdit->home(false); pageReferenceStatisticDescriptionLineEdit->setText(pageReference->getStatisticDescription()); pageReferenceStatisticDescriptionLineEdit->home(false); for (int i = 0; i < pageReference->getNumberOfSubHeaders(); i++) { addSubHeader(pageReference->getSubHeader(i)); } allWidgetsGroup->blockSignals(false); } /** * called when statistic push button pressed. */ void StudyPageReferenceWidget::slotPageReferenceStatisticPushButton() { GuiNameSelectionDialog nsd(this, GuiNameSelectionDialog::LIST_STATISTICS, GuiNameSelectionDialog::LIST_STATISTICS); if (nsd.exec() == GuiNameSelectionDialog::Accepted) { pageReferenceStatisticLineEdit->setText(nsd.getNameSelected()); slotPageReferenceStatisticLineEditChanged(); } } /** * called when page number changed. */ void StudyPageReferenceWidget::slotPageReferencePageNumberLineEditChanged() { pageReference->setPageNumber(pageReferenceNumberLineEdit->text()); } /** * called when page reference header changed. */ void StudyPageReferenceWidget::slotPageReferenceHeaderLineEditChanged() { pageReference->setHeader(pageReferenceHeaderLineEdit->text()); } /** * called when page reference comment changed. */ void StudyPageReferenceWidget::slotPageReferenceCommentTextEditChanged() { pageReference->setComment(pageReferenceCommentTextEdit->toPlainText()); } /** * called when page reference size units changed. */ void StudyPageReferenceWidget::slotPageReferenceSizeUnitsLineEditChanged() { pageReference->setSizeUnits(pageReferenceSizeUnitsLineEdit->text()); } /** * called when page reference voxel size changed. */ void StudyPageReferenceWidget::slotPageReferenceVoxelSizeLineEditChanged() { pageReference->setVoxelDimensions(pageReferenceVoxelSizeLineEdit->text()); } /** * called when page reference statistic changed. */ void StudyPageReferenceWidget::slotPageReferenceStatisticLineEditChanged() { pageReference->setStatisticType(pageReferenceStatisticLineEdit->text()); } /** * called when page reference statistic description changed. */ void StudyPageReferenceWidget::slotPageReferenceStatisticDescriptionLineEditChanged() { pageReference->setStatisticDescription(pageReferenceStatisticDescriptionLineEdit->text()); } /** * save the data into the study meta data page reference. */ void StudyPageReferenceWidget::slotSaveData() { } //===================================================================================== // // Widget for displaying provenance // //===================================================================================== /** * constructor. */ StudyProvenanceWidget::StudyProvenanceWidget(StudyMetaData::Provenance* provenanceIn, StudyWidget* parentStudyWidgetIn, QWidget* parentIn) : QGroupBox("Provenance", parentIn) { provenance = provenanceIn; parentStudyWidget = parentStudyWidgetIn; QLabel* provenanceNameLabel = new QLabel("Name"); provenanceNameLineEdit = new QLineEdit; provenanceNameLineEdit->setToolTip("Enter your name here."); QObject::connect(provenanceNameLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotNameLineEditChanged())); QLabel* provenanceDateLabel = new QLabel("Date"); provenanceDateLineEdit = new QLineEdit; provenanceDateLineEdit->setToolTip("Enter today's date here."); QObject::connect(provenanceDateLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotDateLineEditChanged())); QLabel* provenanceCommentLabel = new QLabel("Comment"); provenanceCommentLineEdit = new QLineEdit; provenanceCommentLineEdit->setToolTip("Enter comment here."); QObject::connect(provenanceCommentLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotCommentLineEditChanged())); int rowCounter = 0; const int nameRow = rowCounter++; const int dateRow = rowCounter++; const int commentRow = rowCounter++; QGridLayout* grid = new QGridLayout; grid->addWidget(provenanceNameLabel, nameRow, 0); grid->addWidget(provenanceNameLineEdit, nameRow, 1); grid->addWidget(provenanceDateLabel, dateRow, 0); grid->addWidget(provenanceDateLineEdit, dateRow, 1); grid->addWidget(provenanceCommentLabel, commentRow, 0); grid->addWidget(provenanceCommentLineEdit, commentRow, 1); QPushButton* deleteThisProvenancePushButton = new QPushButton("Delete This Provenance"); deleteThisProvenancePushButton->setAutoDefault(false); QObject::connect(deleteThisProvenancePushButton, SIGNAL(clicked()), this, SLOT(slotDeleteThisProvenancePushButton())); QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->addWidget(deleteThisProvenancePushButton); buttonsLayout->addStretch(); layout = new QVBoxLayout(this); layout->addLayout(grid); layout->addLayout(buttonsLayout); allWidgetsGroup = new WuQWidgetGroup(this); allWidgetsGroup->addWidget(provenanceNameLineEdit); allWidgetsGroup->addWidget(provenanceDateLineEdit); allWidgetsGroup->addWidget(provenanceCommentLineEdit); loadData(); } /** * destructor. */ StudyProvenanceWidget::~StudyProvenanceWidget() { } /** * load data into the widget. */ void StudyProvenanceWidget::loadData() { allWidgetsGroup->blockSignals(true); provenanceNameLineEdit->setText(provenance->getName()); provenanceNameLineEdit->home(false); provenanceDateLineEdit->setText(provenance->getDate()); provenanceDateLineEdit->home(false); provenanceCommentLineEdit->setText(provenance->getComment()); provenanceCommentLineEdit->home(false); allWidgetsGroup->blockSignals(false); } /** * save the data into the study meta data provenance. */ void StudyProvenanceWidget::slotSaveData() { } /** * called when delete this provenance widget button is pressed. */ void StudyProvenanceWidget::slotDeleteThisProvenancePushButton() { if (QMessageBox::question(this, "Confirm", "Delete this Provenance", (QMessageBox::Yes | QMessageBox::No), QMessageBox::Yes) == QMessageBox::Yes) { // // Remove this widget from its parent layout // parentStudyWidget->removeProvenanceWidget(this); // // Tell QT to delete this widget when it gets pack to its event loop // this->deleteLater(); } } /** * called when name changed. */ void StudyProvenanceWidget::slotNameLineEditChanged() { provenance->setName(provenanceNameLineEdit->text()); } /** * called when date changed. */ void StudyProvenanceWidget::slotDateLineEditChanged() { provenance->setDate(provenanceDateLineEdit->text()); } /** * called when comment changed. */ void StudyProvenanceWidget::slotCommentLineEditChanged() { provenance->setComment(provenanceCommentLineEdit->text()); } //===================================================================================== // // Widget for displaying a new study // //===================================================================================== /** * constructor. */ GuiStudyMetaDataNewDialog::GuiStudyMetaDataNewDialog(StudyMetaData* currentStudyMetaDataIn, QWidget* parent) : WuQDialog(parent) { setWindowTitle("New Study"); currentStudyMetaData = currentStudyMetaDataIn; // // Validator for PubMed ID which is an optional minus sign followed by digits // Also allow it to be a project ID which begins with "ProjID" // QRegExpValidator* pubMedIDValidator = new QRegExpValidator( QRegExp("[P|0-9][r|0-9][o|0-9][j|0-9][I|0-9][D|0-9]\\d*"), this); QLabel* idMessageLabel = new QLabel("If you have a PubMed ID for the new study, " "enter it in the box below. Otherwise, leave " "the box empty."); idMessageLabel->setWordWrap(true); newStudyPubMedIDLineEdit = new QLineEdit; newStudyPubMedIDLineEdit->setValidator(pubMedIDValidator); QGroupBox* studyGroupBox = new QGroupBox("PubMed ID"); QVBoxLayout* studyGroupLayout = new QVBoxLayout(studyGroupBox); studyGroupLayout->addWidget(idMessageLabel); studyGroupLayout->addWidget(newStudyPubMedIDLineEdit); newEmptyStudyRadioButton = new QRadioButton("New Study (empty)"); newCopyStudyRadioButton = new QRadioButton("New Study (copy current study)"); if (currentStudyMetaData == NULL) { newCopyStudyRadioButton->setEnabled(false); } newStudyButtonGroup = new QButtonGroup(this); newStudyButtonGroup->addButton(newEmptyStudyRadioButton, 0); newStudyButtonGroup->addButton(newCopyStudyRadioButton, 1); QWidget* newButtonWidget = new QWidget; QVBoxLayout* newButtonLayout = new QVBoxLayout(newButtonWidget); newButtonLayout->addWidget(newEmptyStudyRadioButton); newButtonLayout->addWidget(newCopyStudyRadioButton); // hide new/copy radio buttons newButtonWidget->hide(); QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(studyGroupBox); layout->addWidget(newButtonWidget); newEmptyStudyRadioButton->setChecked(true); if (lastCheckedID == 0) { newEmptyStudyRadioButton->setChecked(true); } else if (lastCheckedID == 1) { if (newCopyStudyRadioButton->isEnabled()) { newCopyStudyRadioButton->setChecked(true); } } // // Dialog buttons // QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); layout->addWidget(buttonBox); QObject::connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); QObject::connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); } /** * destructor. */ GuiStudyMetaDataNewDialog::~GuiStudyMetaDataNewDialog() { } /** * get the PubMed ID. */ QString GuiStudyMetaDataNewDialog::getPubMedID() const { return newStudyPubMedIDLineEdit->text().trimmed(); } /** * called when OK/Cancel button pressed. */ void GuiStudyMetaDataNewDialog::done(int r) { if (r == WuQDialog::Accepted) { const QString pmid = getPubMedID(); if (pmid.isEmpty() == false) { const StudyMetaDataFile* smdf = theMainWindow->getBrainSet()->getStudyMetaDataFile(); const int studyIndex = smdf->getStudyIndexFromPubMedID(pmid); if (studyIndex >= 0) { const QString msg("ERROR: The PubMed ID you entered (" + pmid + ") is in use by study " + QString::number(studyIndex + 1) + ". Each study must have " + "a unique PubMed ID."); QMessageBox::critical(this, "ERROR", msg); return; } } lastCheckedID = newStudyButtonGroup->checkedId(); const bool anyButtonChecked = newEmptyStudyRadioButton->isChecked() || (newCopyStudyRadioButton->isChecked() && newCopyStudyRadioButton->isEnabled()); if (anyButtonChecked == false) { QMessageBox::critical(this, "ERROR", "No study type selected."); return; } } WuQDialog::done(r); } /** * get the new study. */ StudyMetaData* GuiStudyMetaDataNewDialog::getNewStudy() const { //StudyMetaDataFile* smdf = theMainWindow->getBrainSet()->getStudyMetaDataFile(); StudyMetaData* smd = NULL; if (newEmptyStudyRadioButton->isChecked()) { smd = new StudyMetaData; } else if (newCopyStudyRadioButton->isChecked()) { smd = new StudyMetaData; if (currentStudyMetaData != NULL) { const QString projID = smd->getProjectID(); const QString pubMedID = smd->getPubMedID(); *smd = *currentStudyMetaData; smd->setProjectID(projID); smd->setPubMedID(pubMedID); } } const QString pmid = getPubMedID(); if (pmid.isEmpty() == false) { smd->setPubMedID(pmid); } return smd; } caret-5.6.4~dfsg.1.orig/caret/GuiStudyInfoEditorWidget.h0000664000175000017500000000637411572067322022746 0ustar michaelmichael #ifndef __GUI_STUDY_INFO_EDITOR_WIDGET_H__ #define __GUI_STUDY_INFO_EDITOR_WIDGET_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "CellStudyInfo.h" class QComboBox; class QLineEdit; class QTextEdit; class WuQWidgetGroup; /// widget for editing study info class GuiStudyInfoEditorWidget : public QWidget { Q_OBJECT public: // constructor GuiStudyInfoEditorWidget(std::vector* studyInfoIn, QWidget* parent = 0); // destructor ~GuiStudyInfoEditorWidget(); // update the widget void updateWidget(std::vector* studyInfoIn); // hide stereotaxic space controls void hideStereotaxicSpaceControls(const bool hideThem); // hide partitioning scheme controls void hidePartitioningSchemeControls(const bool hideThem); public slots: // accept changes in editor void slotAcceptEditorContents(); protected slots: // called when study selection combo box selected void slotStudySelectionComboBox(int item); // called when stereotaxic space push button pressed void slotStereotaxicSpacePushButton(); protected: /// load the selection combo box void loadStudySelectionComboBox(); /// the study info being edited std::vector* studyInfo; /// study selection combo box QComboBox* studySelectionComboBox; /// title line edit QLineEdit* titleLineEdit; /// authors line edit QLineEdit* authorsLineEdit; /// citation line edit QLineEdit* citationLineEdit; /// url line edit QLineEdit* urlLineEdit; /// keywords line edit QLineEdit* keywordsLineEdit; /// stereotaxic space line edit QLineEdit* stereotaxicSpaceLineEdit; /// partitioning scheme abbreviation line edit QLineEdit* partitioningSchemeAbbreviationLineEdit; /// partitioning scheme full name line edit QLineEdit* partitioningSchemeFullNameLineEdit; /// comment text edit QTextEdit* commentTextEdit; /// stereotaxic space widget group WuQWidgetGroup* stereotaxicSpaceWidgetGroup; /// partitioning scheme widget group WuQWidgetGroup* partitioningSchemeWidgetGroup; }; #endif // __GUI_STUDY_INFO_EDITOR_WIDGET_H__ caret-5.6.4~dfsg.1.orig/caret/GuiStudyInfoEditorWidget.cxx0000664000175000017500000002620611572067322023315 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include "GuiStudyInfoEditorWidget.h" #include "StereotaxicSpace.h" #include "QtListBoxSelectionDialog.h" #include "WuQWidgetGroup.h" static const QString newStudyRetainEntriesString("New - Retain Entries"); static const QString newStudyClearEntriesString("New - Clear Entries"); /** * constructor. */ GuiStudyInfoEditorWidget::GuiStudyInfoEditorWidget(std::vector* studyInfoIn, QWidget* parent) : QWidget(parent) { // // Point to the study info // studyInfo = studyInfoIn; // // study selection label and combo box // QLabel* studySelectionLabel = new QLabel("Study"); studySelectionComboBox = new QComboBox; QObject::connect(studySelectionComboBox, SIGNAL(activated(int)), this, SLOT(slotStudySelectionComboBox(int))); // label and line edit QLabel* titleLabel = new QLabel("Title"); titleLineEdit = new QLineEdit; // label and line edit QLabel* authorsLabel = new QLabel("Authors"); authorsLineEdit = new QLineEdit; // label and line edit QLabel* citationLabel = new QLabel("Citation"); citationLineEdit = new QLineEdit; // label and line edit QLabel* urlLabel = new QLabel("URL"); urlLineEdit = new QLineEdit; // label and line edit QLabel* keywordsLabel = new QLabel("Keywords"); keywordsLineEdit = new QLineEdit; // label and line edit QPushButton* stereotaxicSpacePushButton = new QPushButton("Stereotaxic\nSpace..."); stereotaxicSpacePushButton->setFixedSize(stereotaxicSpacePushButton->sizeHint()); stereotaxicSpacePushButton->setAutoDefault(false); QObject::connect(stereotaxicSpacePushButton, SIGNAL(clicked()), this, SLOT(slotStereotaxicSpacePushButton())); stereotaxicSpaceLineEdit = new QLineEdit; // // Widget group for stereotaxic space items // stereotaxicSpaceWidgetGroup = new WuQWidgetGroup(this); stereotaxicSpaceWidgetGroup->addWidget(stereotaxicSpacePushButton); stereotaxicSpaceWidgetGroup->addWidget(stereotaxicSpaceLineEdit); // label and line edit QLabel* partitioningSchemeAbbreviationLabel = new QLabel("Partitioning Scheme\nAbbreviation"); partitioningSchemeAbbreviationLineEdit = new QLineEdit; // label and line edit QLabel* partitioningSchemeFullNameLabel = new QLabel("Partitioning Scheme\nFull Name"); partitioningSchemeFullNameLineEdit = new QLineEdit; // // Widget group for stereotaxic space items // partitioningSchemeWidgetGroup = new WuQWidgetGroup(this); partitioningSchemeWidgetGroup->addWidget(partitioningSchemeAbbreviationLabel); partitioningSchemeWidgetGroup->addWidget(partitioningSchemeAbbreviationLineEdit); partitioningSchemeWidgetGroup->addWidget(partitioningSchemeFullNameLabel); partitioningSchemeWidgetGroup->addWidget(partitioningSchemeFullNameLineEdit); // comment text edit QLabel* commentLabel = new QLabel("Comment"); commentTextEdit = new QTextEdit; // // layout the widget items // QGridLayout* grid = new QGridLayout(this); grid->addWidget(studySelectionLabel, 0, 0); grid->addWidget(studySelectionComboBox, 0, 1); grid->addWidget(titleLabel, 1, 0); grid->addWidget(titleLineEdit, 1, 1); grid->addWidget(authorsLabel, 2, 0); grid->addWidget(authorsLineEdit, 2, 1); grid->addWidget(citationLabel, 3, 0); grid->addWidget(citationLineEdit, 3, 1); grid->addWidget(urlLabel, 4, 0); grid->addWidget(urlLineEdit, 4, 1); grid->addWidget(keywordsLabel, 5, 0); grid->addWidget(keywordsLineEdit, 5, 1); grid->addWidget(stereotaxicSpacePushButton, 6, 0); grid->addWidget(stereotaxicSpaceLineEdit, 6, 1); grid->addWidget(partitioningSchemeAbbreviationLabel, 7, 0); grid->addWidget(partitioningSchemeAbbreviationLineEdit, 7, 1); grid->addWidget(partitioningSchemeFullNameLabel, 8, 0); grid->addWidget(partitioningSchemeFullNameLineEdit, 8, 1); grid->addWidget(commentLabel, 9, 0); grid->addWidget(commentTextEdit, 9, 1); } /** * destructor. */ GuiStudyInfoEditorWidget::~GuiStudyInfoEditorWidget() { } /** * load the selection combo box. */ void GuiStudyInfoEditorWidget::loadStudySelectionComboBox() { bool newRetainFlag = false; bool newClearFlag = false; // // Get the currently selected study number // int currentStudyNumber = studySelectionComboBox->currentIndex(); if (studySelectionComboBox->currentText() == newStudyRetainEntriesString) { newRetainFlag = true; } if (studySelectionComboBox->currentText() == newStudyClearEntriesString) { newClearFlag = true; } // // load the study number combo box // studySelectionComboBox->clear(); const int numStudies = static_cast(studyInfo->size()); for (int i = 0; i < numStudies; i++) { const CellStudyInfo& csi = (*studyInfo)[i]; QString s(csi.getTitle()); if (s.length() > 30) { s.resize(30); } QString qs(QString::number(i)); qs.append(" - "); qs.append(s); studySelectionComboBox->addItem(qs); } // // Load new study info selection options // const int indexNewStudyClearEntries = studySelectionComboBox->count(); studySelectionComboBox->addItem(newStudyClearEntriesString); const int indexNewStudyRetainEntries = studySelectionComboBox->count(); studySelectionComboBox->addItem(newStudyRetainEntriesString); // // Set selected item // if (newRetainFlag) { studySelectionComboBox->setCurrentIndex(indexNewStudyRetainEntries); } else if (newClearFlag) { studySelectionComboBox->setCurrentIndex(indexNewStudyClearEntries); } else if ((currentStudyNumber >= 0) && (currentStudyNumber < numStudies)) { studySelectionComboBox->setCurrentIndex(currentStudyNumber); } else { studySelectionComboBox->setCurrentIndex(indexNewStudyRetainEntries); } slotStudySelectionComboBox(studySelectionComboBox->currentIndex()); } /** * update the widget. */ void GuiStudyInfoEditorWidget::updateWidget(std::vector* studyInfoIn) { studyInfo = studyInfoIn; loadStudySelectionComboBox(); } /** * called when study selection combo box selected. */ void GuiStudyInfoEditorWidget::slotStudySelectionComboBox(int item) { const int numStudies = static_cast(studyInfo->size()); if (studySelectionComboBox->currentText() == newStudyRetainEntriesString) { // nothing } else if (studySelectionComboBox->currentText() == newStudyClearEntriesString) { titleLineEdit->setText(""); authorsLineEdit->setText(""); citationLineEdit->setText(""); urlLineEdit->setText(""); keywordsLineEdit->setText(""); stereotaxicSpaceLineEdit->setText(""); partitioningSchemeAbbreviationLineEdit->setText(""); partitioningSchemeFullNameLineEdit->setText(""); commentTextEdit->setText(""); } else if ((item >= 0) && (item < numStudies)) { const CellStudyInfo& csi = (*studyInfo)[item]; titleLineEdit->setText(csi.getTitle()); authorsLineEdit->setText(csi.getAuthors()); citationLineEdit->setText(csi.getCitation()); urlLineEdit->setText(csi.getURL()); keywordsLineEdit->setText(csi.getKeywords()); stereotaxicSpaceLineEdit->setText(csi.getStereotaxicSpace()); partitioningSchemeAbbreviationLineEdit->setText(csi.getPartitioningSchemeAbbreviation()); partitioningSchemeFullNameLineEdit->setText(csi.getPartitioningSchemeFullName()); commentTextEdit->setText(csi.getComment()); } } /** * accept changes in editor. */ void GuiStudyInfoEditorWidget::slotAcceptEditorContents() { if (titleLineEdit->text().isEmpty()) { QMessageBox::critical(this, "ERROR", "You must enter a title."); return; } int indx = studySelectionComboBox->currentIndex(); if ((indx >= 0) && (indx < static_cast(studyInfo->size()))) { // nothing to do -- editing existing entry } else { CellStudyInfo temp; studyInfo->push_back(temp); indx = studyInfo->size() - 1; } CellStudyInfo& csi = (*studyInfo)[indx]; csi.setTitle(titleLineEdit->text()); csi.setAuthors(authorsLineEdit->text()); csi.setCitation(citationLineEdit->text()); csi.setURL(urlLineEdit->text()); csi.setKeywords(keywordsLineEdit->text()); csi.setStereotaxicSpace(stereotaxicSpaceLineEdit->text()); csi.setPartitioningSchemeAbbreviation(partitioningSchemeAbbreviationLineEdit->text()); csi.setPartitioningSchemeFullName(partitioningSchemeFullNameLineEdit->text()); csi.setComment(commentTextEdit->toPlainText()); if (studySelectionComboBox->currentText() == newStudyClearEntriesString) { titleLineEdit->setText(""); authorsLineEdit->setText(""); citationLineEdit->setText(""); urlLineEdit->setText(""); keywordsLineEdit->setText(""); stereotaxicSpaceLineEdit->setText(""); partitioningSchemeAbbreviationLineEdit->setText(""); partitioningSchemeFullNameLineEdit->setText(""); commentTextEdit->setText(""); } } /** * called when stereotaxic space push button pressed. */ void GuiStudyInfoEditorWidget::slotStereotaxicSpacePushButton() { std::vector spaces; StereotaxicSpace::getAllStereotaxicSpaces(spaces); std::vector spaceNames; for (unsigned int i = 0; i < spaces.size(); i++) { spaceNames.push_back(spaces[i].getName()); } QtListBoxSelectionDialog lbsd(this, "Stereotaxic Spaces", "", spaceNames, -1); if (lbsd.exec() == QDialog::Accepted) { const int item = lbsd.getSelectedItemIndex(); if (item >= 0) { stereotaxicSpaceLineEdit->setText(spaceNames[item]); } } } /** * hide stereotaxic space controls. */ void GuiStudyInfoEditorWidget::hideStereotaxicSpaceControls(const bool hideThem) { stereotaxicSpaceWidgetGroup->setHidden(hideThem); } /** * hide partitioning scheme controls. */ void GuiStudyInfoEditorWidget::hidePartitioningSchemeControls(const bool hideThem) { partitioningSchemeWidgetGroup->setHidden(hideThem); } caret-5.6.4~dfsg.1.orig/caret/GuiStudyCollectionFileEditorDialog.h0000664000175000017500000001613011572067322024711 0ustar michaelmichael#ifndef __GUI_STUDY_COLLECTION_FILE_EDITOR_DIALOG_H__ #define __GUI_STUDY_COLLECTION_FILE_EDITOR_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "WuQDialog.h" class QGridLayout; class QLineEdit; class QSignalMapper; class QSpinBox; class QTextEdit; class QToolButton; class StudyCollection; class WuQWidgetGroup; /// class for editing a study collection file class GuiStudyCollectionFileEditorDialog : public WuQDialog { Q_OBJECT public: // constructor GuiStudyCollectionFileEditorDialog(QWidget* parent = 0); // destructor ~GuiStudyCollectionFileEditorDialog(); // update the dialog void updateDialog(); protected slots: // when study collection selection spin box value changed void slotStudySelectionSpinBox(int); // called when add new collection push button pressed void slotAddCollectionPushButton(); // called when add studies to collection push button pressed void slotAddStudiesPushButton(); // called when delete collection push button pressed void slotDeleteCollectionPushButton(); /// called when collection name changed void slotCollectionNameLineEditChanged(const QString& text); /// called when collection creator changed void slotCollectionCreatorLineEditChanged(const QString& text); /// called when collection type changed void slotCollectionTypeLineEditChanged(const QString& text); /// called when collection comment changed void slotCollectionCommentTextEditChanged(); /// called when collection study name changed void slotCollectionStudyNameLineEditChanged(const QString& text); /// called when collection PMID changed void slotCollectionStudyPMIDLineEditChanged(const QString& text); /// called when collection search ID changed void slotCollectionSearchIDLineEditChanged(const QString& text); /// called when collection focus list ID changed void slotCollectionFociListIDLineEditChanged(const QString& text); /// called when collection focus color list ID changed void slotCollectionFociColorListIDLineEditChanged(const QString& text); /// called when collection topic changed void slotCollectionTopicLineEditChanged(const QString& text); /// called when collection category ID changed void slotCollectionCategoryIDLineEditChanged(const QString& text); /// called when collection ID changed void slotCollectionIDLineEditChanged(const QString& text); /// called when a study name is changed void slotCollectionStudyNameChanged(int); /// called when a study pmid is changed void slotCollectionStudyPMIDChanged(int); /// called when a study mslid is changed void slotCollectionStudyMSLIDChanged(int); /// called when a study delete push button pressed void slotCollectionStudyDeletePushButton(int); protected: // load the currently selected collection into the editor void loadSelectedCollectionIntoEditor(); // get the selected study collection StudyCollection* getSelectedCollection(); // get the index of the selected collection (-1 if invalid) int getIndexOfSelectedCollection() const; // create the study collection selection section QWidget* createStudyCollectionSelectionSection(); // create the study collection section QWidget* createStudyCollectionSection(); // create the file operations section QWidget* createFileOperationsSection(); // create the collection operations section QWidget* createCollectionOperationsSection(); /// study selection spin box QSpinBox* studySelectionSpinBox; /// collection name QLineEdit* collectionNameLineEdit; /// collection creator QLineEdit* collectionCreatorLineEdit; /// collection type QLineEdit* collectionTypeLineEdit; /// collection comment QTextEdit* collectionCommentTextEdit; /// collection study name QLineEdit* collectionStudyNameLineEdit; /// collection PMID QLineEdit* collectionStudyPMIDLineEdit; /// collection search ID QLineEdit* collectionSearchIDLineEdit; /// collection focus ID QLineEdit* collectionFociListIDLineEdit; /// collection focus color list ID QLineEdit* collectionFociColorListIDLineEdit; /// collection topic QLineEdit* collectionTopicLineEdit; /// category id line edit QLineEdit* collectionCategoryIDLineEdit; /// collection id line edit QLineEdit* collectionIDLineEdit; /// collection operations widget QWidget* collectionOperationsWidget; /// collection studies widget QWidget* collectionStudiesWidget; /// line edits containing names of studies in collection std::vector collectionStudiesNameLineEdits; /// line edits containing PMIDs of studies in collection std::vector collectionStudiesPMIDLineEdits; /// line edits containing MSL ID of studies in collection std::vector collectionStudyMslIDStudyLineEdits; /// delete push buttons for studies in collection std::vector collectionStudiesDeletePushButtons; /// widget group for study in collection std::vector collectionStudiesWidgetGroups; /// layout for collection study name/pmid QGridLayout* collectionStudiesNamePmidLayout; /// signal mapper for collection study name changed QSignalMapper* collectionStudyNameSignalMapper; /// signal mapper for collection study PMID changed QSignalMapper* collectionStudyPMIDSignalMapper; /// signal mapper for collection study MSLID changed QSignalMapper* collectionStudyMSLIDSignalMapper; /// signal mapper for collection study delete push button QSignalMapper* collectionStudyDeleteSignalMapper; }; #endif // __GUI_STUDY_COLLECTION_FILE_EDITOR_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiStudyCollectionFileEditorDialog.cxx0000664000175000017500000007106311572067322025272 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "BrainSet.h" #include "FociProjectionFile.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "GuiStudyCollectionFileEditorDialog.h" #include "StudyCollectionFile.h" #include "StudyMetaDataFile.h" #include "WuQDataEntryDialog.h" #include "WuQWidgetGroup.h" #include "global_variables.h" /** * constructor. */ GuiStudyCollectionFileEditorDialog::GuiStudyCollectionFileEditorDialog(QWidget* parent) : WuQDialog(parent) { setWindowTitle("Study Collection Editor"); // // Collection Selection // QWidget* collectionSelectionWidget = createStudyCollectionSelectionSection(); // // File Operations // QWidget* fileOperationsWidget = createFileOperationsSection(); // // Collection Operations // collectionOperationsWidget = createCollectionOperationsSection(); // // Collection Studies // collectionStudiesWidget = createStudyCollectionSection(); // Close button // QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); QObject::connect(buttonBox, SIGNAL(rejected()), this, SLOT(close())); // // Left column layout // QVBoxLayout* leftColumnLayout = new QVBoxLayout; leftColumnLayout->addWidget(collectionSelectionWidget); leftColumnLayout->addWidget(fileOperationsWidget); leftColumnLayout->addWidget(collectionOperationsWidget); leftColumnLayout->addStretch(); // // Horizontal layout // QHBoxLayout* horizontalLayout = new QHBoxLayout; horizontalLayout->addLayout(leftColumnLayout); horizontalLayout->addWidget(collectionStudiesWidget); horizontalLayout->setStretchFactor(leftColumnLayout, 0); horizontalLayout->setStretchFactor(collectionStudiesWidget, 100); // // Layout for dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->addLayout(horizontalLayout); dialogLayout->addWidget(buttonBox); updateDialog(); } /** * destructor. */ GuiStudyCollectionFileEditorDialog::~GuiStudyCollectionFileEditorDialog() { } /** * update the dialog. */ void GuiStudyCollectionFileEditorDialog::updateDialog() { StudyCollectionFile* scf = theMainWindow->getBrainSet()->getStudyCollectionFile(); const int numCollections = scf->getNumberOfStudyCollections(); studySelectionSpinBox->blockSignals(true); studySelectionSpinBox->setMinimum(1); studySelectionSpinBox->setMaximum(numCollections); studySelectionSpinBox->blockSignals(false); loadSelectedCollectionIntoEditor(); } /** * create the study collection selection section. */ QWidget* GuiStudyCollectionFileEditorDialog::createStudyCollectionSelectionSection() { // // Spin Box for study selection // studySelectionSpinBox = new QSpinBox; studySelectionSpinBox->setMinimum(1); studySelectionSpinBox->setMaximum(1); studySelectionSpinBox->setSingleStep(1); QObject::connect(studySelectionSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotStudySelectionSpinBox(int))); // // Group box and layout // QGroupBox* selectionGroupBox = new QGroupBox("Collection Selection"); QVBoxLayout* selectionLayout = new QVBoxLayout(selectionGroupBox); selectionLayout->addWidget(studySelectionSpinBox); return selectionGroupBox; } /** * when study collection selection spin box value changed. */ void GuiStudyCollectionFileEditorDialog::slotStudySelectionSpinBox(int /*value*/) { loadSelectedCollectionIntoEditor(); } /** * create the study collection section. */ QWidget* GuiStudyCollectionFileEditorDialog::createStudyCollectionSection() { // // collection name // QLabel* collectionNameLabel = new QLabel("Collection\nName"); collectionNameLineEdit = new QLineEdit; QObject::connect(collectionNameLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotCollectionNameLineEditChanged(const QString&))); // // creator // QLabel* collectionCreatorLabel = new QLabel("Creator"); collectionCreatorLineEdit = new QLineEdit; QObject::connect(collectionCreatorLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotCollectionCreatorLineEditChanged(const QString&))); // // type // QLabel* collectionTypeLabel = new QLabel("Type"); collectionTypeLineEdit = new QLineEdit; QObject::connect(collectionTypeLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotCollectionTypeLineEditChanged(const QString&))); // // comment // QLabel* collectionCommentLabel = new QLabel("Comment"); collectionCommentTextEdit = new QTextEdit; collectionCommentTextEdit->setMaximumHeight(100); QObject::connect(collectionCommentTextEdit, SIGNAL(textChanged()), this, SLOT(slotCollectionCommentTextEditChanged())); // // study name // QLabel* collectionStudyNameLabel = new QLabel("Study Name"); collectionStudyNameLineEdit = new QLineEdit; QObject::connect(collectionStudyNameLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotCollectionStudyNameLineEditChanged(const QString&))); // // pubmed id // QLabel* collectionStudyPMIDLabel = new QLabel("PubMed ID"); collectionStudyPMIDLineEdit = new QLineEdit; QObject::connect(collectionStudyPMIDLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotCollectionStudyPMIDLineEditChanged(const QString&))); // // search id // QLabel* collectionSearchIDLabel = new QLabel("Search ID"); collectionSearchIDLineEdit = new QLineEdit; QObject::connect(collectionSearchIDLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotCollectionSearchIDLineEditChanged(const QString&))); // // Foci List ID // QLabel* collectionFociListIDLabel = new QLabel("Foci List ID"); collectionFociListIDLineEdit = new QLineEdit; QObject::connect(collectionFociListIDLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotCollectionFociListIDLineEditChanged(const QString&))); // // Foci Color List ID // QLabel* collectionFociColorListIDLabel = new QLabel("Foci Color List ID"); collectionFociColorListIDLineEdit = new QLineEdit; QObject::connect(collectionFociColorListIDLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotCollectionFociColorListIDLineEditChanged(const QString&))); // // topic // QLabel* collectionTopicLabel = new QLabel("Topic"); collectionTopicLineEdit = new QLineEdit; QObject::connect(collectionTopicLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotCollectionTopicLineEditChanged(const QString&))); // // category ID // QLabel* collectionCategoryIDLabel = new QLabel("Category ID"); collectionCategoryIDLineEdit = new QLineEdit; QObject::connect(collectionCategoryIDLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotCollectionCategoryIDLineEditChanged(const QString&))); // // collection ID QLabel* collectionIDLabel = new QLabel("Collection ID"); collectionIDLineEdit = new QLineEdit; QObject::connect(collectionIDLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotCollectionIDLineEditChanged(const QString&))); // // Layout for collection information // QGridLayout* infoGridLayout = new QGridLayout; infoGridLayout->addWidget(collectionNameLabel, 0, 0); infoGridLayout->addWidget(collectionNameLineEdit, 0, 1); infoGridLayout->addWidget(collectionIDLabel, 1, 0); infoGridLayout->addWidget(collectionIDLineEdit, 1, 1); infoGridLayout->addWidget(collectionCreatorLabel, 2, 0); infoGridLayout->addWidget(collectionCreatorLineEdit, 2, 1); infoGridLayout->addWidget(collectionTypeLabel, 3, 0); infoGridLayout->addWidget(collectionTypeLineEdit, 3, 1); infoGridLayout->addWidget(collectionCommentLabel, 4, 0); infoGridLayout->addWidget(collectionCommentTextEdit, 4, 1); infoGridLayout->addWidget(collectionTopicLabel, 5, 0); infoGridLayout->addWidget(collectionTopicLineEdit, 5, 1); infoGridLayout->addWidget(collectionCategoryIDLabel, 6, 0); infoGridLayout->addWidget(collectionCategoryIDLineEdit, 6, 1); infoGridLayout->addWidget(collectionStudyNameLabel, 7, 0); infoGridLayout->addWidget(collectionStudyNameLineEdit, 7, 1); infoGridLayout->addWidget(collectionStudyPMIDLabel, 8, 0); infoGridLayout->addWidget(collectionStudyPMIDLineEdit, 8, 1); infoGridLayout->addWidget(collectionSearchIDLabel, 9, 0); infoGridLayout->addWidget(collectionSearchIDLineEdit, 9, 1); infoGridLayout->addWidget(collectionFociListIDLabel, 10, 0); infoGridLayout->addWidget(collectionFociListIDLineEdit, 10, 1); infoGridLayout->addWidget(collectionFociColorListIDLabel, 11, 0); infoGridLayout->addWidget(collectionFociColorListIDLineEdit, 11, 1); infoGridLayout->addWidget(new QLabel(" "), 12, 0); // empty row // // Layout for study name/PMIDs // QGroupBox* studiesGroupBox = new QGroupBox("Studies"); collectionStudiesNamePmidLayout = new QGridLayout(studiesGroupBox); collectionStudiesNamePmidLayout->addWidget(new QLabel("Index"), 0, 0); collectionStudiesNamePmidLayout->addWidget(new QLabel("Delete"), 0, 1); collectionStudiesNamePmidLayout->addWidget(new QLabel("Name"), 0, 2); collectionStudiesNamePmidLayout->addWidget(new QLabel("PMID"), 0, 3); collectionStudiesNamePmidLayout->addWidget(new QLabel("MSL ID"), 0, 4); // // Signal mappers for study names/PMIDS // collectionStudyNameSignalMapper = new QSignalMapper(this); QObject::connect(collectionStudyNameSignalMapper, SIGNAL(mapped(int)), this, SLOT(slotCollectionStudyNameChanged(int))); collectionStudyPMIDSignalMapper = new QSignalMapper(this); QObject::connect(collectionStudyPMIDSignalMapper, SIGNAL(mapped(int)), this, SLOT(slotCollectionStudyPMIDChanged(int))); collectionStudyMSLIDSignalMapper = new QSignalMapper(this); QObject::connect(collectionStudyMSLIDSignalMapper, SIGNAL(mapped(int)), this, SLOT(slotCollectionStudyMSLIDChanged(int))); collectionStudyDeleteSignalMapper = new QSignalMapper(this); QObject::connect(collectionStudyDeleteSignalMapper, SIGNAL(mapped(int)), this, SLOT(slotCollectionStudyDeletePushButton(int))); // // Widget and layout // QWidget* collectionWidget = new QWidget; QVBoxLayout* collectionWidgetLayout = new QVBoxLayout(collectionWidget); collectionWidgetLayout->addLayout(infoGridLayout); collectionWidgetLayout->addWidget(studiesGroupBox); // // Scroll Area // QScrollArea* scrollArea = new QScrollArea; scrollArea->setWidget(collectionWidget); scrollArea->setWidgetResizable(true); // // Group box and layout // QGroupBox* collectionGroupBox = new QGroupBox("Collection Studies"); QVBoxLayout* collectionLayout = new QVBoxLayout(collectionGroupBox); collectionLayout->addWidget(scrollArea); return collectionGroupBox; } /** * called when collection name changed. */ void GuiStudyCollectionFileEditorDialog::slotCollectionNameLineEditChanged(const QString& text) { getSelectedCollection()->setStudyCollectionName(text); } /** * called when collection creator changed. */ void GuiStudyCollectionFileEditorDialog::slotCollectionCreatorLineEditChanged(const QString& text) { getSelectedCollection()->setStudyCollectionCreator(text); } /** * called when collection type changed. */ void GuiStudyCollectionFileEditorDialog::slotCollectionTypeLineEditChanged(const QString& text) { getSelectedCollection()->setStudyType(text); } /** * called when collection comment changed. */ void GuiStudyCollectionFileEditorDialog::slotCollectionCommentTextEditChanged() { getSelectedCollection()->setComment(collectionCommentTextEdit->toPlainText()); } /** * called when collection study name changed. */ void GuiStudyCollectionFileEditorDialog::slotCollectionStudyNameLineEditChanged(const QString& text) { getSelectedCollection()->setStudyName(text); } /** * called when collection PMID changed. */ void GuiStudyCollectionFileEditorDialog::slotCollectionStudyPMIDLineEditChanged(const QString& text) { getSelectedCollection()->setPMID(text); } /** * called when collection search ID changed. */ void GuiStudyCollectionFileEditorDialog::slotCollectionSearchIDLineEditChanged(const QString& text) { getSelectedCollection()->setSearchID(text); } /** * called when collection foci list ID changed. */ void GuiStudyCollectionFileEditorDialog::slotCollectionFociListIDLineEditChanged(const QString& text) { getSelectedCollection()->setFociListID(text); } /** * called when collection foci color list ID changed. */ void GuiStudyCollectionFileEditorDialog::slotCollectionFociColorListIDLineEditChanged(const QString& text) { getSelectedCollection()->setFociColorListID(text); } /** * called when collection category ID changed. */ void GuiStudyCollectionFileEditorDialog::slotCollectionCategoryIDLineEditChanged(const QString& text) { getSelectedCollection()->setCategoryID(text); } /** * called when collection ID changed. */ void GuiStudyCollectionFileEditorDialog::slotCollectionIDLineEditChanged(const QString& text) { getSelectedCollection()->setStudyCollectionID(text); } /** * called when collection topic changed. */ void GuiStudyCollectionFileEditorDialog::slotCollectionTopicLineEditChanged(const QString& text) { getSelectedCollection()->setTopic(text); } /** * create the file operations section. */ QWidget* GuiStudyCollectionFileEditorDialog::createFileOperationsSection() { // // Add study collection push button // QPushButton* addCollectionPushButton = new QPushButton("Add New Collection..."); addCollectionPushButton->setAutoDefault(false); QObject::connect(addCollectionPushButton, SIGNAL(clicked()), this, SLOT(slotAddCollectionPushButton())); // // Group box and layout // QGroupBox* fileOperationsGroupBox = new QGroupBox("File Operations"); QVBoxLayout* fileOperationsLayout = new QVBoxLayout(fileOperationsGroupBox); fileOperationsLayout->addWidget(addCollectionPushButton); return fileOperationsGroupBox; } /** * called when add new collection push button pressed. */ void GuiStudyCollectionFileEditorDialog::slotAddCollectionPushButton() { // // Should any studies be added to the new collection // WuQDataEntryDialog ded(this); ded.setWindowTitle("Studies for New Collection"); //QRadioButton* emptyStudyRadioButton = ded.addRadioButton("No Studies", true); QRadioButton* fociStudyRadioButton = ded.addRadioButton("Add Studies Linked by Displayed Foci"); QRadioButton* allStudyRadioButton = ded.addRadioButton("Add All Studies"); if (ded.exec() == WuQDataEntryDialog::Accepted) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); StudyCollectionFile* scf = theMainWindow->getBrainSet()->getStudyCollectionFile(); const StudyMetaDataFile* smdf = theMainWindow->getBrainSet()->getStudyMetaDataFile(); StudyCollection* sc = new StudyCollection; std::vector studyPMIDs; if (fociStudyRadioButton->isChecked()) { FociProjectionFile* fpf = theMainWindow->getBrainSet()->getFociProjectionFile(); fpf->getPubMedIDsOfAllLinkedStudyMetaData(studyPMIDs, true); } else if (allStudyRadioButton->isChecked()) { const int num = smdf->getNumberOfStudyMetaData(); for (int i = 0; i < num; i++) { const StudyMetaData* smd = smdf->getStudyMetaData(i); studyPMIDs.push_back(smd->getPubMedID()); } } const int numStudyPMIDs = static_cast(studyPMIDs.size()); for (int i = 0; i < numStudyPMIDs; i++) { const QString pmid = studyPMIDs[i]; const int indx = smdf->getStudyIndexFromPubMedID(pmid); if (indx >= 0) { const StudyMetaData* smd = smdf->getStudyMetaData(indx); sc->addStudyPMID(new StudyNamePubMedID(smd->getName(), pmid, "")); } } scf->addStudyCollection(sc); GuiFilesModified fm; fm.setStudyCollectionModified(); theMainWindow->fileModificationUpdate(fm); studySelectionSpinBox->setValue(scf->getNumberOfStudyCollections()); loadSelectedCollectionIntoEditor(); QApplication::restoreOverrideCursor(); } } /** * create the collection operations section. */ QWidget* GuiStudyCollectionFileEditorDialog::createCollectionOperationsSection() { // // Add Studies to Collection // QPushButton* addStudiesPushButton = new QPushButton("Add Studies..."); addStudiesPushButton->setAutoDefault(false); QObject::connect(addStudiesPushButton, SIGNAL(clicked()), this, SLOT(slotAddStudiesPushButton())); // // Delete Collection // QPushButton* deleteCollectionPushButton = new QPushButton("Delete Collection..."); deleteCollectionPushButton->setAutoDefault(false); QObject::connect(deleteCollectionPushButton, SIGNAL(clicked()), this, SLOT(slotDeleteCollectionPushButton())); // // Group box and layout // QGroupBox* collectionOperationsGroupBox = new QGroupBox("Collection Operations"); QVBoxLayout* collectionOperationsLayout = new QVBoxLayout(collectionOperationsGroupBox); collectionOperationsLayout->addWidget(addStudiesPushButton); collectionOperationsLayout->addWidget(deleteCollectionPushButton); return collectionOperationsGroupBox; } /** * called when add studies to collection push button pressed. */ void GuiStudyCollectionFileEditorDialog::slotAddStudiesPushButton() { StudyCollection* sc = getSelectedCollection(); if (sc == NULL) { return; } const StudyMetaDataFile* smdf = theMainWindow->getBrainSet()->getStudyMetaDataFile(); const int numStudies = smdf->getNumberOfStudyMetaData(); if (numStudies <= 0) { QMessageBox::warning(this, "WARNING", "The Study Metadata File contains no studies."); return; } // // Create dialog for selecting studies // std::vector checkBoxes; WuQDataEntryDialog ded(this, true); ded.setWindowTitle("Choose Studies for Collection"); for (int i = 0; i < numStudies; i++) { const StudyMetaData* smd = smdf->getStudyMetaData(i); const QString labelText = (smd->getName() + " " + smd->getPubMedID()); checkBoxes.push_back(ded.addCheckBox(labelText)); } // // Add studies to current collection // if (ded.exec() == WuQDataEntryDialog::Accepted) { for (int i = 0; i < numStudies; i++) { if (checkBoxes[i]->isChecked()) { const StudyMetaData* smd = smdf->getStudyMetaData(i); sc->addStudyPMID(new StudyNamePubMedID(smd->getName(), smd->getPubMedID(), "")); } } } loadSelectedCollectionIntoEditor(); } /** * called when delete collection push button pressed. */ void GuiStudyCollectionFileEditorDialog::slotDeleteCollectionPushButton() { if (QMessageBox::question(this, "CONFIRM", "Delete current collection?", QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::Yes) { const int indx = getIndexOfSelectedCollection(); if (indx >= 0) { StudyCollectionFile* scf = theMainWindow->getBrainSet()->getStudyCollectionFile(); scf->deleteStudyCollection(indx); GuiFilesModified fm; fm.setStudyCollectionModified(); theMainWindow->fileModificationUpdate(fm); loadSelectedCollectionIntoEditor(); } } } /** * get the selected study collection. */ StudyCollection* GuiStudyCollectionFileEditorDialog::getSelectedCollection() { StudyCollection* sc = NULL; const int indx = getIndexOfSelectedCollection(); if (indx >= 0) { StudyCollectionFile* scf = theMainWindow->getBrainSet()->getStudyCollectionFile(); sc = scf->getStudyCollection(indx); } return sc; } /** * get the index of the selected collection (-1 if invalid). */ int GuiStudyCollectionFileEditorDialog::getIndexOfSelectedCollection() const { StudyCollectionFile* scf = theMainWindow->getBrainSet()->getStudyCollectionFile(); const int numCollections = scf->getNumberOfStudyCollections(); const int indx = studySelectionSpinBox->value() - 1; if ((indx >= 0) && (indx < numCollections)) { return indx; } return -1; } /** * load the currently selected collection into the editor. */ void GuiStudyCollectionFileEditorDialog::loadSelectedCollectionIntoEditor() { StudyCollection* sc = getSelectedCollection(); if (sc != NULL) { collectionNameLineEdit->setText(sc->getStudyCollectionName()); collectionCreatorLineEdit->setText(sc->getStudyCollectionCreator()); collectionTypeLineEdit->setText(sc->getStudyType()); collectionCommentTextEdit->setText(sc->getComment()); collectionStudyNameLineEdit->setText(sc->getStudyName()); collectionStudyPMIDLineEdit->setText(sc->getPMID()); collectionSearchIDLineEdit->setText(sc->getSearchID()); collectionTopicLineEdit->setText(sc->getTopic()); collectionFociListIDLineEdit->setText(sc->getFociListID()); collectionFociColorListIDLineEdit->setText(sc->getFociColorListID()); collectionCategoryIDLineEdit->setText(sc->getCategoryID()); collectionIDLineEdit->setText(sc->getStudyCollectionID()); const int numStudiesInCollection = sc->getNumberOfStudyPMIDs(); const int numStudiesInDialog = static_cast(collectionStudiesWidgetGroups.size()); // // Add new studies as needed // for (int i = numStudiesInDialog; i < numStudiesInCollection; i++) { // // Create new widgets for Name/PMID/MSL ID // QLineEdit* nameLE = new QLineEdit; nameLE->setMinimumWidth(160); QLineEdit* pmdidLE = new QLineEdit; pmdidLE->setFixedWidth(100); QLineEdit* mslidLE = new QLineEdit; mslidLE->setFixedWidth(100); // // Connect signals for text changed // QObject::connect(nameLE, SIGNAL(textEdited(const QString&)), collectionStudyNameSignalMapper, SLOT(map())); collectionStudyNameSignalMapper->setMapping(nameLE, i); QObject::connect(pmdidLE, SIGNAL(textEdited(const QString&)), collectionStudyPMIDSignalMapper, SLOT(map())); collectionStudyPMIDSignalMapper->setMapping(pmdidLE, i); QObject::connect(mslidLE, SIGNAL(textEdited(const QString&)), collectionStudyMSLIDSignalMapper, SLOT(map())); collectionStudyMSLIDSignalMapper->setMapping(mslidLE, i); // // Index in collection // QLabel* indexLabel = new QLabel(QString::number(i+1)); // // Delete push button // QToolButton* deletePushButton = new QToolButton; deletePushButton->setText("X"); deletePushButton->setToolTip("Delete this Study"); QObject::connect(deletePushButton, SIGNAL(clicked(bool)), collectionStudyDeleteSignalMapper, SLOT(map())); collectionStudyDeleteSignalMapper->setMapping(deletePushButton, i); // // Add to layout // collectionStudiesNamePmidLayout->addWidget(indexLabel, i + 1, 0, Qt::AlignRight); collectionStudiesNamePmidLayout->addWidget(deletePushButton, i + 1, 1); collectionStudiesNamePmidLayout->addWidget(nameLE, i + 1, 2); collectionStudiesNamePmidLayout->addWidget(pmdidLE, i + 1, 3); collectionStudiesNamePmidLayout->addWidget(mslidLE, i + 1, 4); // // Keep track of widgets // collectionStudiesDeletePushButtons.push_back(deletePushButton); collectionStudiesNameLineEdits.push_back(nameLE); collectionStudiesPMIDLineEdits.push_back(pmdidLE); collectionStudyMslIDStudyLineEdits.push_back(mslidLE); // // Add new widgets to widget group for that row // WuQWidgetGroup* wg = new WuQWidgetGroup(this); wg->addWidget(nameLE); wg->addWidget(pmdidLE); wg->addWidget(mslidLE); wg->addWidget(deletePushButton); collectionStudiesWidgetGroups.push_back(wg); } // // Put studies into GUI // for (int i = 0; i < numStudiesInCollection; i++) { const StudyNamePubMedID* snp = sc->getStudyPMID(i); collectionStudiesNameLineEdits[i]->setText(snp->getName()); collectionStudiesPMIDLineEdits[i]->setText(snp->getPubMedID()); collectionStudyMslIDStudyLineEdits[i]->setText(snp->getMslID()); collectionStudiesWidgetGroups[i]->setVisible(true); } // // Hide unused items in GUI // for (int i = numStudiesInCollection; i < numStudiesInDialog; i++) { collectionStudiesWidgetGroups[i]->setVisible(false); } } // // Enable widgets if there is a valid study // collectionOperationsWidget->setEnabled(sc != NULL); collectionStudiesWidget->setEnabled(sc != NULL); } /** * called when a study name is changed. */ void GuiStudyCollectionFileEditorDialog::slotCollectionStudyNameChanged(int indx) { StudyCollection* sc = getSelectedCollection(); if (sc != NULL) { if ((indx >= 0) && (indx < sc->getNumberOfStudyPMIDs())) { StudyNamePubMedID* sid = sc->getStudyPMID(indx); sid->setName(collectionStudiesNameLineEdits[indx]->text().trimmed()); } } } /** * called when a study pmid is changed. */ void GuiStudyCollectionFileEditorDialog::slotCollectionStudyPMIDChanged(int indx) { StudyCollection* sc = getSelectedCollection(); if (sc != NULL) { if ((indx >= 0) && (indx < sc->getNumberOfStudyPMIDs())) { StudyNamePubMedID* sid = sc->getStudyPMID(indx); sid->setPubMedID(collectionStudiesPMIDLineEdits[indx]->text().trimmed()); } } } /** * called when a study mslid is changed. */ void GuiStudyCollectionFileEditorDialog::slotCollectionStudyMSLIDChanged(int indx) { StudyCollection* sc = getSelectedCollection(); if (sc != NULL) { if ((indx >= 0) && (indx < sc->getNumberOfStudyPMIDs())) { StudyNamePubMedID* sid = sc->getStudyPMID(indx); sid->setMslID(collectionStudyMslIDStudyLineEdits[indx]->text().trimmed()); } } } /** * called when a study delete push button pressed. */ void GuiStudyCollectionFileEditorDialog::slotCollectionStudyDeletePushButton(int indx) { StudyCollection* sc = getSelectedCollection(); if (sc != NULL) { if ((indx >= 0) && (indx < sc->getNumberOfStudyPMIDs())) { sc->removeStudyPMID(indx); loadSelectedCollectionIntoEditor(); } } } caret-5.6.4~dfsg.1.orig/caret/GuiStructureComboBox.h0000664000175000017500000000405011572067322022125 0ustar michaelmichael #ifndef __GUI_STRUCTURE_COMBO_BOX_H__ #define __GUI_STRUCTURE_COMBO_BOX_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "Structure.h" /// class for structure selection combo box class GuiStructureComboBox : public QComboBox { Q_OBJECT public: // constructor GuiStructureComboBox(QWidget* parent = 0, const char* name = 0, const bool showInvalid = true); // destructor ~GuiStructureComboBox(); // get selected structure Structure::STRUCTURE_TYPE getSelectedStructure() const; // get selected structure as string QString getSelectedStructureAsString() const; // get selected structure as abbreviated string QString getSelectedStructureAsAbbreviatedString() const; // set the structure void setStructure(const Structure::STRUCTURE_TYPE st); protected: /// set the current item made protected to prevent user from calling it void setCurrentIndex(int indx); /// values of items in combo box std::vector comboItems; }; #endif // __GUI_STRUCTURE_COMBO_BOX_H__ caret-5.6.4~dfsg.1.orig/caret/GuiStructureComboBox.cxx0000664000175000017500000000522611572067322022506 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "GuiStructureComboBox.h" /** * constructor. */ GuiStructureComboBox::GuiStructureComboBox(QWidget* parent, const char* /*name */, const bool showInvalid) : QComboBox(parent) { std::vector structureTypes; std::vector structureNames; Structure::getAllTypesAndNames(structureTypes, structureNames, showInvalid); for (unsigned int i = 0; i < structureTypes.size(); i++) { addItem(structureNames[i]); comboItems.push_back(structureTypes[i]); } } /** * destructor. */ GuiStructureComboBox::~GuiStructureComboBox() { } /** * get selected structure. */ Structure::STRUCTURE_TYPE GuiStructureComboBox::getSelectedStructure() const { Structure::STRUCTURE_TYPE st = Structure::STRUCTURE_TYPE_INVALID; const int item = currentIndex(); if ((item >= 0) && (item < static_cast(count()))) { st = comboItems[item]; } return st; } /** * get selected structure as string. */ QString GuiStructureComboBox::getSelectedStructureAsString() const { return Structure::convertTypeToString(getSelectedStructure()); } /** * get selected structure as abbreviated string. */ QString GuiStructureComboBox::getSelectedStructureAsAbbreviatedString() const { return Structure::convertTypeToAbbreviatedString(getSelectedStructure()); } /** * set the structure. */ void GuiStructureComboBox::setStructure(const Structure::STRUCTURE_TYPE ht) { for (unsigned int i = 0; i < comboItems.size(); i++) { if (comboItems[i] == ht) { setCurrentIndex(i); break; } } } /** * set the current item made protected to prevent user from calling it. */ void GuiStructureComboBox::setCurrentIndex(int indx) { QComboBox::setCurrentIndex(indx); } caret-5.6.4~dfsg.1.orig/caret/GuiStereotaxicSpaceComboBox.h0000664000175000017500000000330411572067322023374 0ustar michaelmichael #ifndef __GUI_STEREOTAXIC_SPACE_COMBO_BOX_H__ #define __GUI_STEREOTAXIC_SPACE_COMBO_BOX_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "StereotaxicSpace.h" /// class for stereotaxic space selection combo box class GuiStereotaxicSpaceComboBox : public QComboBox { Q_OBJECT public: // constructor GuiStereotaxicSpaceComboBox(QWidget* parent = 0); // destructor ~GuiStereotaxicSpaceComboBox(); // get selected stereotaxic space StereotaxicSpace getSelectedStereotaxicSpace() const; // set the stereotaxic space void setSelectedStereotaxicSpace(const StereotaxicSpace& ss); protected: /// set the current item made protected to prevent user from calling it void setCurrentIndex(int indx); }; #endif // __GUI_STEREOTAXIC_SPACE_COMBO_BOX_H__ caret-5.6.4~dfsg.1.orig/caret/GuiStereotaxicSpaceComboBox.cxx0000664000175000017500000000414011572067322023746 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "GuiStereotaxicSpaceComboBox.h" /** * constructor. */ GuiStereotaxicSpaceComboBox::GuiStereotaxicSpaceComboBox(QWidget* parent) : QComboBox(parent) { std::vector spaces; StereotaxicSpace::getAllStereotaxicSpaces(spaces); for (unsigned int i = 0; i < spaces.size(); i++) { addItem(spaces[i].getName(), static_cast(spaces[i].getSpace())); } } /** * destructor. */ GuiStereotaxicSpaceComboBox::~GuiStereotaxicSpaceComboBox() { } /** * get selected stereotaxic space. */ StereotaxicSpace GuiStereotaxicSpaceComboBox::getSelectedStereotaxicSpace() const { StereotaxicSpace space; const int indx = currentIndex(); if (indx >= 0) { space = StereotaxicSpace(static_cast(itemData(indx).toInt())); } return space; } /** * set the stereotaxic space. */ void GuiStereotaxicSpaceComboBox::setSelectedStereotaxicSpace(const StereotaxicSpace& ss) { const int indx = findData(static_cast(ss.getSpace())); if (indx >= 0) { setCurrentIndex(indx); } } /** * set the current item made protected to prevent user from calling it. */ void GuiStereotaxicSpaceComboBox::setCurrentIndex(int indx) { QComboBox::setCurrentIndex(indx); } caret-5.6.4~dfsg.1.orig/caret/GuiStandardMeshDialog.h0000664000175000017500000004116211572067322022176 0ustar michaelmichael #ifndef __GUI_STANDARD_MESH_DIALOG_H__ #define __GUI_STANDARD_MESH_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include class BrainModelSurface; class BrainModelSurfaceMultiresolutionMorphing; class GuiBrainModelSurfaceSelectionComboBox; class GuiStandardMeshAtlasSelectionPage; class GuiStandardMeshBorderUpdatePage; class GuiStandardMeshBorderValidationPage; class GuiStandardMeshFiducialSurfacePage; class GuiStandardMeshFinishedPage; class GuiStandardMeshIntroPage; class GuiStandardMeshLandmarkGenerationPage; class GuiStandardMeshMorphDeformParamsPage; class GuiStandardMeshOutputSpecFilePage; class GuiStandardMeshSurfacesPage; class QCheckBox; class QLineEdit; /// the atlas class class StandardMeshAtlas { public: /// constructor StandardMeshAtlas(const QString& nameIn, const QString& specFilePathIn, const int numberOfNodesIn) : name(nameIn), specFilePath(specFilePathIn), numberOfNodes(numberOfNodesIn) { } /// destructor ~StandardMeshAtlas() { } /// get name QString getName() const { return name; } /// get spec file's path QString getSpecFilePath() const { return specFilePath; } /// get the number of nodes int getNumberOfNodes() const { return numberOfNodes; } protected: /// name of atlas QString name; /// spec file path QString specFilePath; /// number of nodes int numberOfNodes; }; /// dialog for generating standard meshes class GuiStandardMeshDialog : public QWizard { Q_OBJECT public: // constructor GuiStandardMeshDialog(QWidget* parent); // destructor ~GuiStandardMeshDialog(); // get the fiducial surface BrainModelSurface* getFiducialSurface(); // get the inflated surface BrainModelSurface* getInflatedSurface(); // get the very inflated surface BrainModelSurface* getVeryInflatedSurface(); // get the spherical surface BrainModelSurface* getSphericalSurface(); // show the first page of the dialog void showFirstPage(); // update the dialog void updateDialog(); // called to validate the current page bool validateCurrentPage(); // save new surfaces void saveSurfaces(const int indexOfFirstCoordinateFileToSave, const int indexOfFirstTopologyFileToSave = -1); /// get the number of atlases int getNumberOfAtlases() const { return atlases.size(); } /// get an atlas const StandardMeshAtlas* getAtlas(const int indx) const { return &atlases[indx]; } /// get the selected atlas const StandardMeshAtlas* getSelectedAtlas() const { return selectedAtlas; } /// set the selected atlas void setSelectedAtlas(StandardMeshAtlas* a) { selectedAtlas = a; } /// set the selected atlas void setSelectedAtlas(const int indx) { selectedAtlas = &atlases[indx]; } public slots: /// called when cancel button pressed void reject(); protected: // load the atlases QString loadAtlases(); /// the atlases std::vector atlases; /// the selected atlas StandardMeshAtlas* selectedAtlas; /// the intro page GuiStandardMeshIntroPage* introPage; /// the fidicual surface page GuiStandardMeshFiducialSurfacePage* fiducialSurfacePage; /// the surfaces page GuiStandardMeshSurfacesPage* surfacesPage; /// the atlas selection page GuiStandardMeshAtlasSelectionPage* atlasSelectionPage; /// the landmark border generation page GuiStandardMeshLandmarkGenerationPage* landmarkBorderGenerationPage; /// the border draw and update page GuiStandardMeshBorderUpdatePage* borderDrawUpdatePage; /// the border validation page GuiStandardMeshBorderValidationPage* borderValidationPage; /// the output spec file page GuiStandardMeshOutputSpecFilePage* outputSpecFilePage; /// morphing and deformation parameters page GuiStandardMeshMorphDeformParamsPage* morphDeformParamsPage; /// the finished page GuiStandardMeshFinishedPage* finishedPage; /// flat multi-resolution morphing parameters BrainModelSurfaceMultiresolutionMorphing* flatParameters; /// spherical multi-resolution morphing parameters BrainModelSurfaceMultiresolutionMorphing* sphericalParameters; }; //============================================================================= /// class for introduction page class GuiStandardMeshIntroPage : public QWizardPage { Q_OBJECT public: // constructor GuiStandardMeshIntroPage(QWidget* parent = 0); // destructor ~GuiStandardMeshIntroPage(); // cleanup page (called when showing page after "Back" pressed) void cleanupPage(); // initialize the page (called when showing page after "Next" pressed) void initializePage(); // page is complete bool isComplete(); // validate a page bool validatePage(); protected: }; //============================================================================= /// class for fiducial surface and topology page class GuiStandardMeshFiducialSurfacePage : public QWizardPage { Q_OBJECT public: // constructor GuiStandardMeshFiducialSurfacePage(QWidget* parent = 0); // destructor ~GuiStandardMeshFiducialSurfacePage(); // cleanup page (called when showing page after "Back" pressed) void cleanupPage(); // initialize the page (called when showing page after "Next" pressed) void initializePage(); // page is complete bool isComplete(); // validate a page bool validatePage(); // get the fiducial surface BrainModelSurface* getFiducialSurface(); signals: /// emitted when "complete" status of page changes void completeChanged(); protected: /// surface selection combo box GuiBrainModelSurfaceSelectionComboBox* fiducialSurfaceComboBox; }; //============================================================================= /// class for selecting surfaces class GuiStandardMeshSurfacesPage : public QWizardPage { Q_OBJECT public: // constructor GuiStandardMeshSurfacesPage(QWidget* parent = 0); // destructor ~GuiStandardMeshSurfacesPage(); // get the inflated surface BrainModelSurface* getInflatedSurface(); // get the very inflated surface BrainModelSurface* getVeryInflatedSurface(); // get the spherical surface BrainModelSurface* getSphericalSurface(); // cleanup page (called when showing page after "Back" pressed) void cleanupPage(); // initialize the page (called when showing page after "Next" pressed) void initializePage(); // page is complete bool isComplete(); // validate a page bool validatePage(); signals: /// emitted when "complete" status of page changes void completeChanged(); protected slots: // called when generate surfaces button clicked void slotGenerateSurfacesPushButton(); protected: /// surface selection combo box GuiBrainModelSurfaceSelectionComboBox* inflatedSurfaceComboBox; /// surface selection combo box GuiBrainModelSurfaceSelectionComboBox* veryInflatedSurfaceComboBox; /// surface selection combo box GuiBrainModelSurfaceSelectionComboBox* sphericalSurfaceComboBox; }; //============================================================================= /// class for atlas selection page class GuiStandardMeshAtlasSelectionPage : public QWizardPage { Q_OBJECT public: // constructor GuiStandardMeshAtlasSelectionPage(GuiStandardMeshDialog* smd, QWidget* parent = 0); // destructor ~GuiStandardMeshAtlasSelectionPage(); // cleanup page (called when showing page after "Back" pressed) void cleanupPage(); // initialize the page (called when showing page after "Next" pressed) void initializePage(); // page is complete bool isComplete(); // validate a page bool validatePage(); protected slots: // called when atlas button selected void slotAtlasSelection(int id); protected: }; //============================================================================= /// class for generating template cuts class GuiStandardMeshLandmarkGenerationPage : public QWizardPage { Q_OBJECT public: // constructor GuiStandardMeshLandmarkGenerationPage(QWidget* parent = 0); // destructor ~GuiStandardMeshLandmarkGenerationPage(); // cleanup page (called when showing page after "Back" pressed) void cleanupPage(); // initialize the page (called when showing page after "Next" pressed) void initializePage(); // page is complete bool isComplete(); // validate a page bool validatePage(); signals: /// emitted when "complete" status of page changes void completeChanged(); protected slots: // called to add landmark border cuts void slotAddLandmarkBordersPushButton(); protected: }; //============================================================================= /// class for drawing updating medial wall and cuts class GuiStandardMeshBorderUpdatePage : public QWizardPage { Q_OBJECT public: // constructor GuiStandardMeshBorderUpdatePage(QWidget* parent = 0); // destructor ~GuiStandardMeshBorderUpdatePage(); // cleanup page (called when showing page after "Back" pressed) void cleanupPage(); // initialize the page (called when showing page after "Next" pressed) void initializePage(); // page is complete bool isComplete(); // validate a page bool validatePage(); signals: /// emitted when "complete" status of page changes void completeChanged(); protected slots: // called when draw borders button pressed void slotDrawBordersPushButton(); // called when update borders button pressed void slotUpdateBordersPushButton(); // called when example images button pressed void slotBorderExampleImages(); // called when show only flattening borders selected void slotShowOnlyFlattenBordersPushButton(); protected: }; //============================================================================= /// class for border validation page class GuiStandardMeshBorderValidationPage : public QWizardPage { Q_OBJECT public: // constructor GuiStandardMeshBorderValidationPage(QWidget* parent = 0); // destructor ~GuiStandardMeshBorderValidationPage(); // cleanup page (called when showing page after "Back" pressed) void cleanupPage(); // initialize the page (called when showing page after "Next" pressed) void initializePage(); // page is complete bool isComplete(); // validate a page bool validatePage(); protected: }; //============================================================================= /// class for output spec file page class GuiStandardMeshOutputSpecFilePage : public QWizardPage { Q_OBJECT public: // constructor GuiStandardMeshOutputSpecFilePage(QWidget* parent = 0); // destructor ~GuiStandardMeshOutputSpecFilePage(); // cleanup page (called when showing page after "Back" pressed) void cleanupPage(); // initialize the page (called when showing page after "Next" pressed) void initializePage(); // page is complete bool isComplete(); // validate a page bool validatePage(); protected slots: // called to select directory void slotDirectorySelection(); // called to select output spec file void slotSpecFileSelection(); protected: /// line edit for directory QLineEdit* directoryLineEdit; /// line edit for spec file name QLineEdit* specFileLineEdit; }; //============================================================================= //============================================================================= /// class for morphing and deformation parameters page class GuiStandardMeshMorphDeformParamsPage : public QWizardPage { Q_OBJECT public: // constructor GuiStandardMeshMorphDeformParamsPage( BrainModelSurfaceMultiresolutionMorphing* flatParametersIn, BrainModelSurfaceMultiresolutionMorphing* sphericalParametersIn, QWidget* parent = 0); // destructor ~GuiStandardMeshMorphDeformParamsPage(); // cleanup page (called when showing page after "Back" pressed) void cleanupPage(); // initialize the page (called when showing page after "Next" pressed) void initializePage(); // page is complete bool isComplete(); // validate a page bool validatePage(); // is flat multi-res morphing selected bool getDoFlatMultiResMorphing() const; // is spherical multi-res morphing selected bool getDoSphericalMultiResMorphing() const; protected slots: // called to adjust flat multi-res morph parameters void slotFlatParamsPushButton(); // called to adjust spherical multi-res morph parameters void slotSphericalParamsPushButton(); protected: /// perform flat multi-res morphing check box QCheckBox* flatMultiMorphCheckBox; /// perform spherical multi-res morphing check box QCheckBox* sphericalMultiMorphCheckBox; /// flat multi-resolution morphing parameters BrainModelSurfaceMultiresolutionMorphing* flatParameters; /// spherical multi-resolution morphing parameters BrainModelSurfaceMultiresolutionMorphing* sphericalParameters; }; //============================================================================= /// class for final page class GuiStandardMeshFinishedPage : public QWizardPage { Q_OBJECT public: // constructor GuiStandardMeshFinishedPage(QWidget* parent = 0); // destructor ~GuiStandardMeshFinishedPage(); // cleanup page (called when showing page after "Back" pressed) void cleanupPage(); // initialize the page (called when showing page after "Next" pressed) void initializePage(); // page is complete bool isComplete(); // validate a page bool validatePage(); protected: }; //============================================================================= //============================================================================= //============================================================================= //============================================================================= //============================================================================= //============================================================================= //============================================================================= //============================================================================= //============================================================================= #endif // __GUI_STANDARD_MESH_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiStandardMeshDialog.cxx0000664000175000017500000017360611572067322022562 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "BrainModelSurface.h" #include "BrainModelSurfaceMultiresolutionMorphing.h" #include "CommaSeparatedValueFile.h" #include "BrainSet.h" #include "DisplaySettingsBorders.h" #include "FileFilters.h" #include "FileUtilities.h" #include "GuiBorderOperationsDialog.h" #include "GuiBrainModelOpenGL.h" #include "GuiBrainModelSurfaceSelectionComboBox.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "GuiMainWindowSurfaceActions.h" #include "GuiMultiresolutionMorphingDialog.h" #include "GuiStandardMeshDialog.h" #include "StringTable.h" #include "TopologyFile.h" #include "WuQFileDialog.h" #include "WuQMessageBox.h" #include "global_variables.h" /** * constructor. */ GuiStandardMeshDialog::GuiStandardMeshDialog(QWidget* parent) : QWizard(parent) { selectedAtlas = NULL; setOption(QWizard::NoCancelButton, false); setWizardStyle(ModernStyle); setWindowTitle("Standard Mesh Processing"); flatParameters = new BrainModelSurfaceMultiresolutionMorphing( NULL, NULL, NULL, BrainModelSurfaceMorphing::MORPHING_SURFACE_FLAT, NULL); sphericalParameters = new BrainModelSurfaceMultiresolutionMorphing( NULL, NULL, NULL, BrainModelSurfaceMorphing::MORPHING_SURFACE_SPHERICAL, NULL); const QString atlasErrorMessage = loadAtlases(); // // The introductory page // introPage = new GuiStandardMeshIntroPage; addPage(introPage); // // The fiducial surface page // fiducialSurfacePage = new GuiStandardMeshFiducialSurfacePage; addPage(fiducialSurfacePage); // // The surfaces page // surfacesPage = new GuiStandardMeshSurfacesPage; addPage(surfacesPage); // // The atlas selection page // atlasSelectionPage = new GuiStandardMeshAtlasSelectionPage(this); addPage(atlasSelectionPage); // // the landmark border generation page // landmarkBorderGenerationPage = new GuiStandardMeshLandmarkGenerationPage; addPage(landmarkBorderGenerationPage); // // border draw and update page // borderDrawUpdatePage = new GuiStandardMeshBorderUpdatePage; addPage(borderDrawUpdatePage); // // border validation page // borderValidationPage = new GuiStandardMeshBorderValidationPage; addPage(borderValidationPage); // // output spec file page // outputSpecFilePage = new GuiStandardMeshOutputSpecFilePage; addPage(outputSpecFilePage); // // morph & deform parameters page // morphDeformParamsPage = new GuiStandardMeshMorphDeformParamsPage( flatParameters, sphericalParameters); addPage(morphDeformParamsPage); // // the finshed page // finishedPage = new GuiStandardMeshFinishedPage; addPage(finishedPage); if (atlasErrorMessage.isEmpty() == false) { WuQMessageBox::critical(this, "ERROR", atlasErrorMessage); return; } } /** * destructor. */ GuiStandardMeshDialog::~GuiStandardMeshDialog() { } /** * called to validate the current page. */ bool GuiStandardMeshDialog::validateCurrentPage() { /* BrainSet* bs = theMainWindow->getBrainSet(); */ const QWizardPage* p = currentPage(); if (p == introPage) { if (atlases.empty()) { WuQMessageBox::critical(this, "ERROR", "No atlases found. Is Caret installed correctly?"); return false; } } /* if (p == fiducialSurfacePage) { // // Verify fiducial surface with topology // BrainModelSurface* fiducialSurface = getFiducialSurface(); if (fiducialSurface== NULL) { WuQMessageBox::critical(this, "ERROR", "There must be a fiducial surface to continue."); return false; } const TopologyFile* tf = fiducialSurface->getTopologyFile(); if (tf == NULL) { WuQMessageBox::critical(this, "ERROR", "The fiducial surface has no topology."); return false; } // // Check topology // showWaitCursor(); int faces, vertices, edges, eulerCount, numberOfHoles, numberOfObjects; tf->getEulerCount(false, faces, vertices, edges, eulerCount, numberOfHoles, numberOfObjects); showNormalCursor(); QString msg; if (eulerCount != 2) { msg += "The surface is not topologically correct.\n"; } if (numberOfHoles > 0) { msg += "The surface contains " + QString::number(numberOfHoles) + " holes.\n"; } if (numberOfObjects > 1) { msg += "The surface contains " + QString::number(numberOfObjects) + " unconnected pieces.\n"; } if (msg.isEmpty() == false) { msg += "These problems should be corrected before continuing.\n\n" "Do you want to continue?"; if (WuQMessageBox::question(this, "INFO", msg, WuQMessageBox::Yes | WuQMessageBox::No, WuQMessageBox::No) == WuQMessageBox::No) { return false; } } } if (p == sphericalSurfacePage) { QString msg; if (getFiducialSurface() == NULL) { msg += "A Fiducial Surface is required.\n"; } if (getSphericalSurface() == NULL) { msg += "A Spherical Surface is required.\n"; } if (msg.isEmpty() == false) { WuQMessageBox::critical(this, "ERROR", msg); return false; } } if (p == templateCutsPage) { saveNewBorders(); } if (p == borderDrawAndUpdatePage) { saveNewBorders(); std::vector flattenBorderNames; startFlatteningPage->getLoadedFlatteningBorders(flattenBorderNames); bool haveMedialWallFlag = false; int numberOfCuts = 0; for (std::vector::iterator iter = flattenBorderNames.begin(); iter != flattenBorderNames.end(); iter++) { if (*iter == BrainModelSurfaceBorderLandmarkIdentification::getFlattenMedialWallBorderName()) { haveMedialWallFlag = true; } else if (iter->startsWith( BrainModelSurfaceBorderLandmarkIdentification::getFlattenStandardCutsBorderNamePrefix())) { numberOfCuts++; } } QString msg; if (haveMedialWallFlag == false) { msg += ("There is no medial wall border named \"" + BrainModelSurfaceBorderLandmarkIdentification::getFlattenMedialWallBorderName() + "\".\n"); } if (numberOfCuts < 1) { msg += ("There must be at least one cut border whose name begins with \"" + BrainModelSurfaceBorderLandmarkIdentification::getFlattenStandardCutsBorderNamePrefix() + "\".\n"); } if (msg.isEmpty() == false) { WuQMessageBox::critical(this, "ERROR", msg); return false; } } if (p == surfaceAlignmentPage) { int ventralNodeNumber = -1; int dorsalMedialNodeNumber = -1; surfaceAlignmentPage->getCentralSulcusTips(ventralNodeNumber, dorsalMedialNodeNumber); if ((ventralNodeNumber < 0) || (dorsalMedialNodeNumber < 0)) { WuQMessageBox::critical(this, "ERROR", "The nodes at the ventral and dorsal-medial ends of the Central Sulcus must be set."); return false; } } if (p == startFlatteningPage) { BorderProjectionFile flattenBorderProjections; bs->getBorderSet()->copyBordersToBorderProjectionFile( flattenBorderProjections); BrainModelSurfaceFlattenHemisphere flatten(bs, fiducialSurfacePage->getFiducialSurface(), sphericalSurfacePage->getSphericalSurface(), &flattenBorderProjections, bs->getPaintFile(), bs->getAreaColorFile(), settingsPage->getCreateFiducialWithSmoothedMedialWallSelected(), getAutoSaveFilesSelected()); try { showWaitCursor(); flatten.execute(); } catch (BrainModelAlgorithmException& e) { showNormalCursor(); WuQMessageBox::critical(this, "ERROR", e.whatQString()); return false; } theMainWindow->displayNewestSurfaceInMainWindow(); BrainModelSurface* initialFlatSurface = theMainWindow->getBrainModelSurface(); if (initialFlatSurface != NULL) { if (initialFlatSurface->getIsFlatSurface()) { int numTileCrossovers = 0, numNodeCrossovers = 0; initialFlatSurface->crossoverCheck(numTileCrossovers, numNodeCrossovers, initialFlatSurface->getSurfaceType()); if ((numNodeCrossovers > 0) || (numTileCrossovers > 0)) { bs->getPrimarySurfaceOverlay()->setOverlay(-1, BrainModelSurfaceOverlay::OVERLAY_SHOW_CROSSOVERS); theMainWindow->updateDisplayControlDialog(); BrainModelSurfaceNodeColoring* bsnc = theMainWindow->getBrainSet()->getNodeColoring(); bsnc->assignColors(); } } } DisplaySettingsBorders* dsb = bs->getDisplaySettingsBorders(); dsb->setDisplayBorders(false); GuiFilesModified fm; fm.setPaintModified(); fm.setAreaColorModified(); fm.setCoordinateModified(); fm.setTopologyModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); showNormalCursor(); } if (p == initialFlatPage) { saveSurfaces(0, 0); saveNewBorders(); } if (p == multiMorphPage) { showWaitCursor(); // // Create a central sulcus border for surface alignment // int ventralNodeNumber, dorsalNodeNumber; surfaceAlignmentPage->getCentralSulcusTips(ventralNodeNumber, dorsalNodeNumber); BorderProjection centralSulcusBorderProjection( BrainModelSurfaceBorderLandmarkIdentification::getCentralSulcusRegistrationLandmarkName()); BorderProjection* centralSulcusPointer = NULL; if ((ventralNodeNumber >= 0) && (dorsalNodeNumber >= 0)) { const int ventralVertices[3] = { ventralNodeNumber, ventralNodeNumber, ventralNodeNumber }; const float ventralAreas[3] = { 1.0, 0.0, 0.0 }; const int dorsalVertices[3] = { dorsalNodeNumber, dorsalNodeNumber, dorsalNodeNumber }; const float dorsalAreas[3] = { 1.0, 0.0, 0.0 }; BorderProjectionLink ventralLink(0, ventralVertices, ventralAreas, 1.0); BorderProjectionLink dorsalLink(0, dorsalVertices, dorsalAreas, 1.0); centralSulcusBorderProjection.addBorderProjectionLink(ventralLink); centralSulcusBorderProjection.addBorderProjectionLink(dorsalLink); centralSulcusPointer = ¢ralSulcusBorderProjection; } // // Measurements output by flat and spherical multi-res morph // std::vector flatMeasurements; std::vector sphericalMeasurements; float flatTime = 0.0, sphereTime = 0.0; // // Flat morphing // BrainModelSurface* surfaceToDisplay = NULL; if (multiMorphPage->getDoFlatMultiResMorphing()) { try { BrainModelSurfaceMultiresolutionMorphing morph(bs, fiducialSurfacePage->getFiducialSurface(), bs->getBrainModelSurfaceOfType( BrainModelSurface::SURFACE_TYPE_FLAT), BrainModelSurfaceMorphing::MORPHING_SURFACE_FLAT, centralSulcusPointer); morph.copyParameters(*flatParameters); morph.setAutoSaveAllFiles(getAutoSaveFilesSelected()); QTime flatTimer; flatTimer.start(); morph.execute(); flatTime = flatTimer.elapsed() * 0.001; morph.getMorphingMeasurements(flatMeasurements); surfaceToDisplay = bs->getBrainModelSurfaceOfType( BrainModelSurface::SURFACE_TYPE_FLAT); saveSurfaces(0, 0); } catch (BrainModelAlgorithmException& e) { showNormalCursor(); WuQMessageBox::critical(this, "ERROR", e.whatQString()); return false; } } // // spherical morphing // if (multiMorphPage->getDoSphericalMultiResMorphing()) { try { BrainModelSurfaceMultiresolutionMorphing morph(bs, fiducialSurfacePage->getFiducialSurface(), sphericalSurfacePage->getSphericalSurface(), BrainModelSurfaceMorphing::MORPHING_SURFACE_SPHERICAL, centralSulcusPointer); morph.copyParameters(*sphericalParameters); morph.setAutoSaveAllFiles(getAutoSaveFilesSelected()); QTime sphereTimer; sphereTimer.start(); morph.execute(); sphereTime = sphereTimer.elapsed() * 0.001; morph.getMorphingMeasurements(sphericalMeasurements); if (surfaceToDisplay == NULL) { surfaceToDisplay = bs->getBrainModelSurfaceOfType( BrainModelSurface::SURFACE_TYPE_SPHERICAL); } saveSurfaces(0, 0); } catch (BrainModelAlgorithmException& e) { showNormalCursor(); WuQMessageBox::critical(this, "ERROR", e.whatQString()); return false; } } if (surfaceToDisplay != NULL) { theMainWindow->displayBrainModelInMainWindow(surfaceToDisplay); } GuiFilesModified fm; fm.setCoordinateModified(); fm.setTopologyModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); if (flatMeasurements.empty() == false) { GuiMorphingMeasurementsDialog* flatMD = new GuiMorphingMeasurementsDialog(flatMeasurements, flatTime, BrainModelSurfaceMorphing::MORPHING_SURFACE_FLAT, true, this); flatMD->show(); } if (sphericalMeasurements.empty() == false) { GuiMorphingMeasurementsDialog* sphereMD = new GuiMorphingMeasurementsDialog(sphericalMeasurements, sphereTime, BrainModelSurfaceMorphing::MORPHING_SURFACE_SPHERICAL, true, this); sphereMD->show(); } saveNewBorders(); showNormalCursor(); } */ return true; } /** * get the fiducial surface. */ BrainModelSurface* GuiStandardMeshDialog::getFiducialSurface() { return fiducialSurfacePage->getFiducialSurface(); } /** * get the inflated surface. */ BrainModelSurface* GuiStandardMeshDialog::getInflatedSurface() { return surfacesPage->getInflatedSurface(); } /** * get the very inflated surface. */ BrainModelSurface* GuiStandardMeshDialog::getVeryInflatedSurface() { return surfacesPage->getVeryInflatedSurface(); } /** * get the spherical surface. */ BrainModelSurface* GuiStandardMeshDialog::getSphericalSurface() { return surfacesPage->getSphericalSurface(); } /** * show the first page of the dialog. */ void GuiStandardMeshDialog::showFirstPage() { restart(); } /** * update the dialog. */ void GuiStandardMeshDialog::updateDialog() { const QWizardPage* p = currentPage(); if (p == introPage) { introPage->initializePage(); } else if (p == fiducialSurfacePage) { fiducialSurfacePage->initializePage(); } else if (p == surfacesPage) { surfacesPage->initializePage(); } else if (p == atlasSelectionPage) { atlasSelectionPage->initializePage(); } else if (p == landmarkBorderGenerationPage) { landmarkBorderGenerationPage->initializePage(); } else if (p == borderDrawUpdatePage) { borderDrawUpdatePage->initializePage(); } else if (p == borderValidationPage) { borderValidationPage->initializePage(); } else if (p == outputSpecFilePage) { outputSpecFilePage->initializePage(); } else if (p == morphDeformParamsPage) { morphDeformParamsPage->initializePage(); } else if (p == finishedPage) { finishedPage->initializePage(); } else if (p != NULL) { std::cout << "PROGRAM ERROR: unknown page in " "GuiStandardMeshDialog::updateDialog()" << std::endl; } } /** * load the atlases. */ QString GuiStandardMeshDialog::loadAtlases() { QString atlasErrorMessage = ""; atlases.clear(); // // Name of atlas directory file // const QString atlasDirectoryName = (BrainSet::getCaretHomeDirectory() + "/data_files/standard_mesh_atlases/"); const QString atlasDirectoryFileName = (atlasDirectoryName + "/atlases.csv"); CommaSeparatedValueFile csvFile; try { csvFile.readFile(atlasDirectoryFileName); const QString atlasSectionName("atlases"); const StringTable* st = csvFile.getDataSectionByName(atlasSectionName); if (st == NULL) { atlasErrorMessage += ("Unable to find section named \"" + atlasSectionName + "\" in the file " + atlasDirectoryFileName + "\n"); } else { const int nameColumn = st->getColumnIndexFromName("Name"); const int directoryColumn = st->getColumnIndexFromName("Directory"); const int specFileColumn = st->getColumnIndexFromName("SpecFileName"); const int numberOfNodesColumn = st->getColumnIndexFromName("NumberOfNodes"); const int numRows = st->getNumberOfRows(); if (nameColumn < 0) { atlasErrorMessage = "Unable to find \"Name\" column.\n"; } if (directoryColumn < 0) { atlasErrorMessage = "Unable to find \"Directory\" column.\n"; } if (specFileColumn < 0) { atlasErrorMessage = "Unable to find \"SpecFileName\" column.\n"; } if (numberOfNodesColumn < 0) { atlasErrorMessage = "Unable to find \"NumberOfNodes\" column.\n"; } if (atlasErrorMessage.isEmpty() == false) { atlasErrorMessage.insert(0, "Error in " + atlasDirectoryFileName); } else { for (int i = 0; i < numRows; i++) { const QString name = st->getElement(i, nameColumn); const QString subDirectory = st->getElement(i, directoryColumn); const QString specFileName = st->getElement(i, specFileColumn); const int numNodes = st->getElementAsInt(i, numberOfNodesColumn); const QString specFilePathName( atlasDirectoryName + "/" + subDirectory + "/" + specFileName); atlases.push_back(StandardMeshAtlas(name, specFilePathName, numNodes)); SpecFile sf; try { sf.readFile(specFilePathName); } catch (FileException& e) { atlasErrorMessage += "Unable to load atlas named \"" + name + "\" located at " + specFilePathName + "\n"; } } } } } catch (FileException& e) { atlasErrorMessage += e.whatQString(); } if (atlasErrorMessage.isEmpty() == false) { atlasErrorMessage.insert(0, "Error loading atlases.\n\n"); } return atlasErrorMessage; } /** * called when cancel button pressed. */ void GuiStandardMeshDialog::reject() { if ((currentPage() != introPage) && (currentPage() != finishedPage)) { if (WuQMessageBox::question(this, "ERROR", "Conversion to Standard Mesh is not complete. Stop Conversion?", WuQMessageBox::Yes | WuQMessageBox::No, WuQMessageBox::No) == WuQMessageBox::Yes) { QWizard::reject(); } else { return; } } QWizard::reject(); } /** * save new surfaces. */ void GuiStandardMeshDialog::saveSurfaces(const int indexOfFirstCoordinateFileToSave, const int indexOfFirstTopologyFileToSave) { BrainSet* bs = theMainWindow->getBrainSet(); if (indexOfFirstCoordinateFileToSave >= 0) { for (int i = indexOfFirstCoordinateFileToSave; i < bs->getNumberOfBrainModels(); i++) { BrainModelSurface* bms = bs->getBrainModelSurface(i); if (bms != NULL) { CoordinateFile* cf = bms->getCoordinateFile(); if (cf->getModified()) { try { bs->writeCoordinateFile(cf->getFileName(), bms->getSurfaceType(), cf); } catch (FileException& e) { WuQMessageBox::critical(this, "ERROR", e.whatQString()); } } } } } if (indexOfFirstTopologyFileToSave >= 0) { for (int i = indexOfFirstTopologyFileToSave; i < bs->getNumberOfTopologyFiles(); i++) { TopologyFile* tf = bs->getTopologyFile(i); if (tf != NULL) { if (tf->getModified()) { try { bs->writeTopologyFile(tf->getFileName(), tf->getTopologyType(), tf); } catch (FileException& e) { WuQMessageBox::critical(this, "ERROR", e.whatQString()); } } } } } } //============================================================================== //============================================================================== //============================================================================== /** * constructor. */ GuiStandardMeshIntroPage::GuiStandardMeshIntroPage(QWidget* parent) : QWizardPage(parent) { setTitle("Introduction"); const QString instructionsText = "This process will convert this subject to an Atlas Surface Space.

    " " " "Once in an Atlas Surface Space, data files can be exchanged with " "that atlas and all other subjects in the Atlas Surface Space.

    " " " "This process requires a fiducial surface, a spherical surface, and borders " "that identify landmarks on the subject. If the spherical surface or the " "borders are not present at this time, subsequent pages will allow you to " "generate these missing items. "; QLabel* instructionsLabel = new QLabel; instructionsLabel->setText(instructionsText); instructionsLabel->setTextFormat(Qt::RichText); instructionsLabel->setWordWrap(true); QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(instructionsLabel); layout->addStretch(); } /** * destructor. */ GuiStandardMeshIntroPage::~GuiStandardMeshIntroPage() { } /** * cleanup page (called when showing page after "Back" pressed). */ void GuiStandardMeshIntroPage::cleanupPage() { initializePage(); } /** * initialize the page (called when showing page after "Next" pressed). */ void GuiStandardMeshIntroPage::initializePage() { } /** * page is complete. */ bool GuiStandardMeshIntroPage::isComplete() { return true; } /** * validate a page. */ bool GuiStandardMeshIntroPage::validatePage() { return true; } //========================================================================= //========================================================================= //========================================================================= /** * constructor. */ GuiStandardMeshFiducialSurfacePage::GuiStandardMeshFiducialSurfacePage(QWidget* parent) : QWizardPage(parent) { setTitle("Fiducial Surface"); const QString topologyText = "If the Fiducial Surface is not topologically correct, it will cause " "problems, possibly severe, during the flattening process. The " "topology will be checked when the Next button is pressed. If " "there are topolgical problems, you will have the option to cancel and " "correct the problems.

    " "A surface that is topologically correct contains no holes (also " "referred to as handles or topological defects) and one connected " "piece of surface. The best way to correct a topologically " "incorrect surface is to correct the errors in the segmentation volume " "and regenerate the surface. If the segmentation volume is not " "available or the errors are small, Surface Menu->Topology->Correct " " Fiducial Surface Topology should be able to correct the topological " "errors. If there are multiple unconnected pieces of surface (islands), " "Surface Menu->Topology->Remove Islands can remove the islands."; QLabel* topologyLabel = new QLabel; topologyLabel->setText(topologyText); topologyLabel->setTextFormat(Qt::RichText); topologyLabel->setWordWrap(true); // // Fiducial Surface selection // QLabel* fiducialSurfaceLabel = new QLabel("Fiducial"); fiducialSurfaceComboBox = new GuiBrainModelSurfaceSelectionComboBox( BrainModelSurface::SURFACE_TYPE_FIDUCIAL); QHBoxLayout* surfaceLayout = new QHBoxLayout; surfaceLayout->addWidget(fiducialSurfaceLabel); surfaceLayout->addWidget(fiducialSurfaceComboBox); surfaceLayout->addStretch(); QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(topologyLabel); layout->addLayout(surfaceLayout); layout->addStretch(); } /** * destructor. */ GuiStandardMeshFiducialSurfacePage::~GuiStandardMeshFiducialSurfacePage() { } /** * cleanup page (called when showing page after "Back" pressed). */ void GuiStandardMeshFiducialSurfacePage::cleanupPage() { } /** * initialize the page (called when showing page after "Next" pressed). */ void GuiStandardMeshFiducialSurfacePage::initializePage() { fiducialSurfaceComboBox->updateComboBox(); } /** * get the fiducial surface. */ BrainModelSurface* GuiStandardMeshFiducialSurfacePage::getFiducialSurface() { return fiducialSurfaceComboBox->getSelectedBrainModelSurface(); } /** * page is complete. */ bool GuiStandardMeshFiducialSurfacePage::isComplete() { return true; } /** * validate a page. */ bool GuiStandardMeshFiducialSurfacePage::validatePage() { return true; } //============================================================================== //============================================================================== //============================================================================== /** * constructor. */ GuiStandardMeshSurfacesPage::GuiStandardMeshSurfacesPage(QWidget* parent) : QWizardPage(parent) { setTitle("Surface Selection and Generation"); // // Inflated Surface selection // QLabel* inflatedSurfaceLabel = new QLabel("Inflated"); inflatedSurfaceComboBox = new GuiBrainModelSurfaceSelectionComboBox( BrainModelSurface::SURFACE_TYPE_INFLATED); // // Very Inflated Surface selection // QLabel* veryInflatedSurfaceLabel = new QLabel("Very Inflated"); veryInflatedSurfaceComboBox = new GuiBrainModelSurfaceSelectionComboBox( BrainModelSurface::SURFACE_TYPE_VERY_INFLATED); // // Spherical Surface selection // QLabel* sphericalSurfaceLabel = new QLabel("Spherical"); sphericalSurfaceComboBox = new GuiBrainModelSurfaceSelectionComboBox( BrainModelSurface::SURFACE_TYPE_SPHERICAL); // // Layout for surface selection // QGridLayout* surfaceGridLayout = new QGridLayout; surfaceGridLayout->addWidget(sphericalSurfaceLabel, 1, 0); surfaceGridLayout->addWidget(sphericalSurfaceComboBox, 1, 1); surfaceGridLayout->addWidget(inflatedSurfaceLabel, 2, 0); surfaceGridLayout->addWidget(inflatedSurfaceComboBox, 2, 1); surfaceGridLayout->addWidget(veryInflatedSurfaceLabel, 3, 0); surfaceGridLayout->addWidget(veryInflatedSurfaceComboBox, 3, 1); surfaceGridLayout->setColumnStretch(0, 0); surfaceGridLayout->setColumnStretch(1, 100); const QString instructionsText = "A spherical surface is required. Inflated and very inflated surfaces " "are very helpful for drawing borders.

    " "" "If you need to generate surfaces, click the Generate Surfaces " "button below."; QLabel* instructionsLabel = new QLabel; instructionsLabel->setText(instructionsText); instructionsLabel->setTextFormat(Qt::RichText); instructionsLabel->setWordWrap(true); // // Button for generating surfaces // QPushButton* generateSurfacesPushButton = new QPushButton("Generate Surfaces..."); generateSurfacesPushButton->setAutoDefault(false); generateSurfacesPushButton->setFixedSize(generateSurfacesPushButton->sizeHint()); QObject::connect(generateSurfacesPushButton, SIGNAL(clicked()), this, SLOT(slotGenerateSurfacesPushButton())); // // Layout for page // QVBoxLayout* layout = new QVBoxLayout(this); layout->addLayout(surfaceGridLayout); layout->addWidget(instructionsLabel); layout->addWidget(generateSurfacesPushButton); layout->addStretch(); } /** * destructor. */ GuiStandardMeshSurfacesPage::~GuiStandardMeshSurfacesPage() { } /** * get the inflated surface. */ BrainModelSurface* GuiStandardMeshSurfacesPage::getInflatedSurface() { return inflatedSurfaceComboBox->getSelectedBrainModelSurface(); } /** * get the very inflated surface. */ BrainModelSurface* GuiStandardMeshSurfacesPage::getVeryInflatedSurface() { return veryInflatedSurfaceComboBox->getSelectedBrainModelSurface(); } /** * get the spherical surface. */ BrainModelSurface* GuiStandardMeshSurfacesPage::getSphericalSurface() { return sphericalSurfaceComboBox->getSelectedBrainModelSurface(); } /** * called when generate surfaces button clicked. */ void GuiStandardMeshSurfacesPage::slotGenerateSurfacesPushButton() { const int oldNumberOfBrainModels = theMainWindow->getBrainSet()->getNumberOfBrainModels(); BrainModelSurface* fiducialSurface = dynamic_cast(wizard())->getFiducialSurface(); if (fiducialSurface == NULL) { WuQMessageBox::critical(this, "ERROR", "There must be a fiducial surface."); return; } GuiMainWindowSurfaceActions* surfaceActions = theMainWindow->getSurfaceActions(); surfaceActions->generateInflatedAndOtherSurfaces( fiducialSurface, false, false, (inflatedSurfaceComboBox->getSelectedBrainModelSurface() == NULL), (veryInflatedSurfaceComboBox->getSelectedBrainModelSurface() == NULL), (sphericalSurfaceComboBox->getSelectedBrainModelSurface() == NULL)); GuiStandardMeshDialog* dialog = dynamic_cast(wizard()); dialog->saveSurfaces(oldNumberOfBrainModels); } /** * cleanup page (called when showing page after "Back" pressed). */ void GuiStandardMeshSurfacesPage::cleanupPage() { initializePage(); } /** * initialize the page (called when showing page after "Next" pressed). */ void GuiStandardMeshSurfacesPage::initializePage() { inflatedSurfaceComboBox->updateComboBox(); veryInflatedSurfaceComboBox->updateComboBox(); sphericalSurfaceComboBox->updateComboBox(); } /** * page is complete. */ bool GuiStandardMeshSurfacesPage::isComplete() { return true; } /** * validate a page. */ bool GuiStandardMeshSurfacesPage::validatePage() { return true; } //============================================================================== //============================================================================== //============================================================================== /** * constructor. */ GuiStandardMeshAtlasSelectionPage::GuiStandardMeshAtlasSelectionPage(GuiStandardMeshDialog* smd, QWidget* parent) : QWizardPage(parent) { setTitle("Atlas Selection"); const int numAtlases = smd->getNumberOfAtlases(); QButtonGroup* buttGroup = new QButtonGroup(this); QObject::connect(buttGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotAtlasSelection(int))); QVBoxLayout* atlasLayout = new QVBoxLayout; for (int i = 0; i < numAtlases; i++) { const StandardMeshAtlas* sma = smd->getAtlas(i); QRadioButton* rb = new QRadioButton(sma->getName()); buttGroup->addButton(rb, i); atlasLayout->addWidget(rb); } QVBoxLayout* layout = new QVBoxLayout(this); layout->addLayout(atlasLayout); layout->addStretch(); } /** * destructor. */ GuiStandardMeshAtlasSelectionPage::~GuiStandardMeshAtlasSelectionPage() { } /** * called when atlas button selected. */ void GuiStandardMeshAtlasSelectionPage::slotAtlasSelection(int id) { GuiStandardMeshDialog* smd = dynamic_cast(wizard()); smd->setSelectedAtlas(id); } /** * cleanup page (called when showing page after "Back" pressed). */ void GuiStandardMeshAtlasSelectionPage::cleanupPage() { initializePage(); } /** * initialize the page (called when showing page after "Next" pressed). */ void GuiStandardMeshAtlasSelectionPage::initializePage() { } /** * page is complete. */ bool GuiStandardMeshAtlasSelectionPage::isComplete() { return true; } /** * validate a page. */ bool GuiStandardMeshAtlasSelectionPage::validatePage() { return true; } //============================================================================== //============================================================================== //============================================================================== /** * constructor. */ GuiStandardMeshLandmarkGenerationPage::GuiStandardMeshLandmarkGenerationPage(QWidget* parent) : QWizardPage(parent) { setTitle("Registration and Flattening Borders Generation"); QPushButton* addLandmarkBordersPushButton = new QPushButton("Add Landmark Border Medial Wall and Cuts..."); addLandmarkBordersPushButton->setFixedSize(addLandmarkBordersPushButton->sizeHint()); addLandmarkBordersPushButton->setAutoDefault(false); QObject::connect(addLandmarkBordersPushButton, SIGNAL(clicked()), this, SLOT(slotAddLandmarkBordersPushButton())); const QString text = "Borders are needed that identify the medial wall and where cuts should " "be made. Pressing the \"Add Landmark Border Medial Wall and Cuts\" " "pushbutton will display controls for generating landmark borders. The " "landmark borders process examines the surfaces to determine the locations " "of the medial wall and cuts. Pressing the \"Add Template Border Medial " "Wall and Cuts\" pushbutton will create borders that roughly identify " "the location of the medial wall and cuts. \n\n" "" "Subsequent pages provide controls for drawing replacement borders and " "updating existing borders for the medial wall and cuts."; QLabel* textLabel = new QLabel(text); textLabel->setWordWrap(true); QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(addLandmarkBordersPushButton); layout->addWidget(textLabel); layout->addStretch(); } /** * destructor. */ GuiStandardMeshLandmarkGenerationPage::~GuiStandardMeshLandmarkGenerationPage() { } /** * called to add landmark border cuts. */ void GuiStandardMeshLandmarkGenerationPage::slotAddLandmarkBordersPushButton() { GuiStandardMeshDialog* fd = dynamic_cast(wizard()); GuiBorderOperationsDialog* borderOperationsDialog = theMainWindow->getBorderOperationsDialog(true); borderOperationsDialog->showPageCreateLandmarkBorders(true, true, fd->getFiducialSurface(), fd->getInflatedSurface(), fd->getVeryInflatedSurface(), fd->getSphericalSurface()); } /** * cleanup page (called when showing page after "Back" pressed). */ void GuiStandardMeshLandmarkGenerationPage::cleanupPage() { } /** * initialize the page (called when showing page after "Next" pressed). */ void GuiStandardMeshLandmarkGenerationPage::initializePage() { DisplaySettingsBorders* dsb = theMainWindow->getBrainSet()->getDisplaySettingsBorders(); dsb->setDisplayBorders(true); dsb->determineDisplayedBorders(); GuiBrainModelOpenGL::updateAllGL(); } /** * page is complete. */ bool GuiStandardMeshLandmarkGenerationPage::isComplete() { return true; } /** * validate a page. */ bool GuiStandardMeshLandmarkGenerationPage::validatePage() { return true; } //============================================================================== //============================================================================== //============================================================================== /** * constructor. */ GuiStandardMeshBorderUpdatePage::GuiStandardMeshBorderUpdatePage(QWidget* parent) : QWizardPage(parent) { setTitle("Draw and Update Borders"); QPushButton* drawBordersPushButton = new QPushButton("Draw Borders..."); drawBordersPushButton->setToolTip("Press this button to\n" "draw a new border."); drawBordersPushButton->setAutoDefault(false); drawBordersPushButton->setFixedSize(drawBordersPushButton->sizeHint()); QObject::connect(drawBordersPushButton, SIGNAL(clicked()), this, SLOT(slotDrawBordersPushButton())); QPushButton* updateBordersPushButton = new QPushButton("Update Borders..."); updateBordersPushButton->setToolTip("Press this button to\n" "modify one of the\n" "existing borders."); updateBordersPushButton->setAutoDefault(false); updateBordersPushButton->setFixedSize(updateBordersPushButton->sizeHint()); QObject::connect(updateBordersPushButton, SIGNAL(clicked()), this, SLOT(slotUpdateBordersPushButton())); QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->addWidget(drawBordersPushButton); buttonsLayout->addWidget(updateBordersPushButton); buttonsLayout->addStretch(); QPushButton* exampleImagesPushButton = new QPushButton("Images of Medial Wall and Cuts..."); exampleImagesPushButton->setAutoDefault(false); exampleImagesPushButton->setToolTip("View examples of Medial Wall and Cut Borders"); exampleImagesPushButton->setFixedSize(exampleImagesPushButton->sizeHint()); QObject::connect(exampleImagesPushButton, SIGNAL(clicked()), this, SLOT(slotBorderExampleImages())); QPushButton* showOnlyFlattenBordersPushButton = new QPushButton("Show Only Flattening Borders"); showOnlyFlattenBordersPushButton->setAutoDefault(false); showOnlyFlattenBordersPushButton->setFixedSize(showOnlyFlattenBordersPushButton->sizeHint()); QObject::connect(showOnlyFlattenBordersPushButton, SIGNAL(clicked()), this, SLOT(slotShowOnlyFlattenBordersPushButton())); const QString infoText = "For proper flattening, the medial wall must to be accurately identified " "so that no non-cortical material remains in the flattened surface. " "The accuracy required of the cuts is less than that of the medial wall and " "if the cuts were automatically generated, their locations are sufficiently " "correct. However, cuts MUST intersect the Medial Wall.

    " "The Medial Wall border must be named FLATTEN.HOLE.MedialWall. All " "of the cuts border names must begin with FLATTEN.CUT. Borders " "whose name does not begin with \"FLATTEN\" are ignored by the flattening " "process.

    " "The 3D border drawing mode enabled the drawing of borders on any surface " "and the drawn borders is automatically projected.

    ." "The Medial Wall border is drawn as an closed border and the cuts are " "drawn as open borders.

    " "It may be helpful to display the surface shape column named " "Folding (Mean Curvature to aid in border drawing.

    " "FLATTEN.HOLE.MedialWall This closed border is drawn so that it " "encloses the Medial Wall. The dorsal medial wall landmark runs along the " "corpus callosum, from a starting point just posterior to the olfactory " "sulcus to a termination just anterior to the calcarine sulcus. The " "ventral medial wall landmark runs from the same termination points, " "but in the opposite direction and along the medial margin of the " "hippocampal sulcus (15 mm medial to the parahippocampal gyrus at its " "maximum), and across the margins of cortex with the basal forebrain.

    " "FLATTEN.CUT.Std.Calcarine This cut starts inside the medial wall, " "is drawn along the calcarine sulcus to the occipital pole, and then " "continues in a lateral direction for several millimeters.

    " "FLATTEN.CUT.Std.Cingulate This cut starts inside the medial wall " "and is drawn to the dorsal/medial tip of the central sulcus.

    " "FLATTEN.CUT.Std.Frontal This cut starts inside the medial wall, " "is drawn in an anterior direction along the inferior frontal cortex, and " "concludes at the most posterior location in the Inferior Frontal Sulcus. " "

    " "FLATTEN.CUT.Std.Sylvian This cut starts inside the medial wall " "and is drawn so that it ends approximately one-third of the way into " "the Sylvian Fissure.

    " "FLATTEN.CUT.Std.Temporal This cut starts inside the medial wall, " "is drawn in an inferior direction so that it passes through the most " "inferior node in the temporal lobe, and then terminates about 15 to 20 " "millimeters below the Superior Temporal Sulcus."; QTextEdit* borderInfoTextEdit = new QTextEdit; borderInfoTextEdit->setHtml(infoText); QVBoxLayout* layout = new QVBoxLayout(this); layout->addLayout(buttonsLayout); layout->addWidget(exampleImagesPushButton); layout->addWidget(showOnlyFlattenBordersPushButton); layout->addWidget(borderInfoTextEdit); layout->addStretch(); } /** * destructor. */ GuiStandardMeshBorderUpdatePage::~GuiStandardMeshBorderUpdatePage() { } /** * called when draw borders button pressed. */ void GuiStandardMeshBorderUpdatePage::slotDrawBordersPushButton() { GuiBorderOperationsDialog* borderOperationsDialog = theMainWindow->getBorderOperationsDialog(true); borderOperationsDialog->showPageDrawBorders(); } /** * called when update borders button pressed. */ void GuiStandardMeshBorderUpdatePage::slotUpdateBordersPushButton() { GuiBorderOperationsDialog* borderOperationsDialog = theMainWindow->getBorderOperationsDialog(true); borderOperationsDialog->showPageUpdateBorders(); } /** * called when show only flattening borders selected. */ void GuiStandardMeshBorderUpdatePage::slotShowOnlyFlattenBordersPushButton() { BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); const int num = bmbs->getNumberOfBorders(); for (int i = 0; i < num; i++) { BrainModelBorder* b = bmbs->getBorder(i); if (b->getName().startsWith("FLATTEN")) { b->setNameDisplayFlag(true); } else { b->setNameDisplayFlag(false); } } DisplaySettingsBorders* dsb = theMainWindow->getBrainSet()->getDisplaySettingsBorders(); dsb->determineDisplayedBorders(); GuiFilesModified fm; fm.setBorderModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } /** * called when example images button pressed. */ void GuiStandardMeshBorderUpdatePage::slotBorderExampleImages() { static WuQDialog* d = NULL; if (d == NULL) { // // Get directory containing borders images // const QString templateDirectoryName = (BrainSet::getCaretHomeDirectory() + QDir::separator() + "data_files/flatten_landmarks/example_images"); QDir templateDirectory(templateDirectoryName); if (templateDirectory.exists() == false) { WuQMessageBox::critical(this, "ERROR", "Unable to find example border images. is Caret " "installed correctly?\n" "Looking in " + templateDirectoryName); return; } // // Get all border files in directory // QFileInfoList infoList = templateDirectory.entryInfoList(QStringList("*.jpg"), (QDir::Files | QDir::Readable | QDir::CaseSensitive), QDir::Name); if (infoList.count() <= 0) { WuQMessageBox::critical(this, "ERROR", "Unable to find example border images. \n" "No images found in " + templateDirectoryName); return; } QListIterator iter(infoList); QWidget* imagesWidget = new QWidget; QVBoxLayout* imagesLayout = new QVBoxLayout(imagesWidget); while (iter.hasNext()) { const QString imageFileName(iter.next().absoluteFilePath()); QPixmap p; if (p.load(imageFileName)) { QLabel* imageLabel = new QLabel(""); imageLabel->setPixmap(p); imagesLayout->addWidget(imageLabel); } } QScrollArea* scrollArea = new QScrollArea; scrollArea->setWidget(imagesWidget); d = new WuQDialog(this); d->setWindowTitle("Example Images of Medial Wall and Cuts"); QDialogButtonBox* bb = new QDialogButtonBox(QDialogButtonBox::Close); QObject::connect(bb, SIGNAL(rejected()), d, SLOT(close())); QVBoxLayout* layout = new QVBoxLayout(d); layout->addWidget(scrollArea); layout->addWidget(bb); } d->show(); } /** * cleanup page (called when showing page after "Back" pressed). */ void GuiStandardMeshBorderUpdatePage::cleanupPage() { } /** * initialize the page (called when showing page after "Next" pressed). */ void GuiStandardMeshBorderUpdatePage::initializePage() { } /** * page is complete. */ bool GuiStandardMeshBorderUpdatePage::isComplete() { return true; } /** * validate a page. */ bool GuiStandardMeshBorderUpdatePage::validatePage() { return true; } //============================================================================== //============================================================================== //============================================================================== /** * constructor. */ GuiStandardMeshBorderValidationPage::GuiStandardMeshBorderValidationPage(QWidget* parent) : QWizardPage(parent) { setTitle("Border Validation"); QLabel* label = new QLabel(" Page"); QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(label); layout->addStretch(); } /** * destructor. */ GuiStandardMeshBorderValidationPage::~GuiStandardMeshBorderValidationPage() { } /** * cleanup page (called when showing page after "Back" pressed). */ void GuiStandardMeshBorderValidationPage::cleanupPage() { initializePage(); } /** * initialize the page (called when showing page after "Next" pressed). */ void GuiStandardMeshBorderValidationPage::initializePage() { } /** * page is complete. */ bool GuiStandardMeshBorderValidationPage::isComplete() { return true; } /** * validate a page. */ bool GuiStandardMeshBorderValidationPage::validatePage() { return true; } //============================================================================== //============================================================================== //============================================================================== /** * constructor. */ GuiStandardMeshOutputSpecFilePage::GuiStandardMeshOutputSpecFilePage(QWidget* parent) : QWizardPage(parent) { setTitle("Output Spec File"); const QString instructionsText = "Choose the directory in which the output spec file and its data files" "will be placed. If the directory does not exist, it will be created. " "Also, enter the name for the output spec file. " ""; QLabel* instructionsLabel = new QLabel; instructionsLabel->setText(instructionsText); instructionsLabel->setTextFormat(Qt::RichText); instructionsLabel->setWordWrap(true); // // Directory button and line edit // QPushButton* directoryButton = new QPushButton("Directory..."); directoryButton->setFixedSize(directoryButton->sizeHint()); directoryButton->setAutoDefault(false); QObject::connect(directoryButton, SIGNAL(clicked()), this, SLOT(slotDirectorySelection())); directoryLineEdit = new QLineEdit; // // Spec File name and label // QPushButton* specFileButton = new QPushButton("Spec File..."); specFileButton->setFixedSize(specFileButton->sizeHint()); specFileButton->setAutoDefault(false); QObject::connect(specFileButton, SIGNAL(clicked()), this, SLOT(slotSpecFileSelection())); specFileLineEdit = new QLineEdit; // // Layout for directory and spec file name // QGridLayout* gridLayout = new QGridLayout; gridLayout->addWidget(directoryButton, 0, 0); gridLayout->addWidget(directoryLineEdit, 0, 1); gridLayout->addWidget(specFileButton, 1, 0); gridLayout->addWidget(specFileLineEdit, 1, 1); gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 100); QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(instructionsLabel); layout->addLayout(gridLayout); layout->addStretch(); } /** * destructor. */ GuiStandardMeshOutputSpecFilePage::~GuiStandardMeshOutputSpecFilePage() { } /** * called to select directory. */ void GuiStandardMeshOutputSpecFilePage::slotDirectorySelection() { WuQFileDialog fd(theMainWindow); fd.setModal(true); fd.setAcceptMode(WuQFileDialog::AcceptOpen); fd.setFileMode(WuQFileDialog::DirectoryOnly); QString dirText = directoryLineEdit->text(); QFileInfo fi(dirText); if (fi.exists() && fi.isDir()) { // ok, do nothing } else { dirText = QDir::currentPath(); } fd.setDirectory(dirText); fd.setWindowTitle("Choose Directory"); if (fd.exec() == QDialog::Accepted) { const QString path(fd.directory().absolutePath()); directoryLineEdit->setText(path); } } /** * called to select output spec file. */ void GuiStandardMeshOutputSpecFilePage::slotSpecFileSelection() { WuQFileDialog fd(theMainWindow); fd.setAcceptMode(WuQFileDialog::AcceptOpen); QString dirText = directoryLineEdit->text(); QFileInfo fi(dirText); if (fi.exists() && fi.isDir()) { // ok, do nothing } else { dirText = QDir::currentPath(); } fd.setFileMode(WuQFileDialog::ExistingFile); fd.setFilters(QStringList(FileFilters::getSpecFileFilter())); if (fd.exec() == WuQFileDialog::Accepted) { if (fd.selectedFiles().size() > 0) { const QString path = FileUtilities::dirname(fd.directory().absolutePath()); directoryLineEdit->setText(path); const QString name = FileUtilities::basename(fd.selectedFiles().at(0)); specFileLineEdit->setText(name); } } } /** * cleanup page (called when showing page after "Back" pressed). */ void GuiStandardMeshOutputSpecFilePage::cleanupPage() { initializePage(); } /** * initialize the page (called when showing page after "Next" pressed). */ void GuiStandardMeshOutputSpecFilePage::initializePage() { } /** * page is complete. */ bool GuiStandardMeshOutputSpecFilePage::isComplete() { return true; } /** * validate a page. */ bool GuiStandardMeshOutputSpecFilePage::validatePage() { return true; } //============================================================================== //============================================================================== //============================================================================== /** * constructor. */ GuiStandardMeshMorphDeformParamsPage::GuiStandardMeshMorphDeformParamsPage( BrainModelSurfaceMultiresolutionMorphing* flatParametersIn, BrainModelSurfaceMultiresolutionMorphing* sphericalParametersIn, QWidget* parent) : QWizardPage(parent) { setTitle("Multi-resolution Morphing and Deformation Parameters"); flatParameters = flatParametersIn; sphericalParameters = sphericalParametersIn; setTitle("Multi-resolution Morphing"); const QString morphtText = "Multi-resolution morphing will reduces the distortion in the flat " "and spherical surfaces."; QLabel* morphInfoLabel = new QLabel(""); morphInfoLabel->setTextFormat(Qt::RichText); morphInfoLabel->setWordWrap(true); morphInfoLabel->setText(morphtText); // // flat multi-res morph // flatMultiMorphCheckBox = new QCheckBox("Perform Flat Multi-resolution Morphing"); QPushButton* flatParamsPushButton = new QPushButton("Edit Parameters..."); flatParamsPushButton->setAutoDefault(false); QObject::connect(flatParamsPushButton, SIGNAL(clicked()), this, SLOT(slotFlatParamsPushButton())); // // flat multi-res morph // sphericalMultiMorphCheckBox = new QCheckBox("Perform Spherical Multi-resolution Morphing"); QPushButton* sphericalParamsPushButton = new QPushButton("Edit Parameters..."); sphericalParamsPushButton->setAutoDefault(false); QObject::connect(sphericalParamsPushButton, SIGNAL(clicked()), this, SLOT(slotSphericalParamsPushButton())); // // Disable edit buttons when morphing not selected // QObject::connect(flatMultiMorphCheckBox, SIGNAL(toggled(bool)), flatParamsPushButton, SLOT(setEnabled(bool))); QObject::connect(sphericalMultiMorphCheckBox, SIGNAL(toggled(bool)), sphericalParamsPushButton, SLOT(setEnabled(bool))); flatMultiMorphCheckBox->setChecked(true); sphericalMultiMorphCheckBox->setChecked(true); // // Layout for mrm // QGridLayout* mrmGridLayout = new QGridLayout; mrmGridLayout->addWidget(flatMultiMorphCheckBox, 0, 0); mrmGridLayout->addWidget(flatParamsPushButton, 0, 1); mrmGridLayout->addWidget(sphericalMultiMorphCheckBox, 1, 0); mrmGridLayout->addWidget(sphericalParamsPushButton, 1, 1); mrmGridLayout->setColumnStretch(0, 0); mrmGridLayout->setColumnStretch(1, 0); // // Layout for page // QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(morphInfoLabel); layout->addLayout(mrmGridLayout); layout->addStretch(); } /** * destructor. */ GuiStandardMeshMorphDeformParamsPage::~GuiStandardMeshMorphDeformParamsPage() { } /** * is flat multi-res morphing selected. */ bool GuiStandardMeshMorphDeformParamsPage::getDoFlatMultiResMorphing() const { return flatMultiMorphCheckBox->isChecked(); } /** * is spherical multi-res morphing selected. */ bool GuiStandardMeshMorphDeformParamsPage::getDoSphericalMultiResMorphing() const { return sphericalMultiMorphCheckBox->isChecked(); } /** * called to adjust flat multi-res morph parameters. */ void GuiStandardMeshMorphDeformParamsPage::slotFlatParamsPushButton() { GuiMultiresolutionMorphingDialog mmd(this, flatParameters, true); mmd.exec(); } /** * called to adjust spherical multi-res morph parameters. */ void GuiStandardMeshMorphDeformParamsPage::slotSphericalParamsPushButton() { GuiMultiresolutionMorphingDialog mmd(this, sphericalParameters, true); mmd.exec(); } /** * cleanup page (called when showing page after "Back" pressed). */ void GuiStandardMeshMorphDeformParamsPage::cleanupPage() { initializePage(); } /** * initialize the page (called when showing page after "Next" pressed). */ void GuiStandardMeshMorphDeformParamsPage::initializePage() { } /** * page is complete. */ bool GuiStandardMeshMorphDeformParamsPage::isComplete() { return true; } /** * validate a page. */ bool GuiStandardMeshMorphDeformParamsPage::validatePage() { return true; } //============================================================================== //============================================================================== //============================================================================== /** * constructor. */ GuiStandardMeshFinishedPage::GuiStandardMeshFinishedPage(QWidget* parent) : QWizardPage(parent) { setTitle("Finished"); QLabel* label = new QLabel(" Page"); QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(label); layout->addStretch(); } /** * destructor. */ GuiStandardMeshFinishedPage::~GuiStandardMeshFinishedPage() { } /** * cleanup page (called when showing page after "Back" pressed). */ void GuiStandardMeshFinishedPage::cleanupPage() { initializePage(); } /** * initialize the page (called when showing page after "Next" pressed). */ void GuiStandardMeshFinishedPage::initializePage() { } /** * page is complete. */ bool GuiStandardMeshFinishedPage::isComplete() { return true; } /** * validate a page. */ bool GuiStandardMeshFinishedPage::validatePage() { return true; } //============================================================================== //============================================================================== //============================================================================== //============================================================================== //============================================================================== //============================================================================== //============================================================================== //============================================================================== //============================================================================== //============================================================================== //============================================================================== //============================================================================== //============================================================================== //============================================================================== //============================================================================== //============================================================================== //============================================================================== //============================================================================== caret-5.6.4~dfsg.1.orig/caret/GuiSpeciesComboBox.h0000664000175000017500000000307711572067322021530 0ustar michaelmichael #ifndef __GUI_SPECIES_COMBO_BOX_H__ #define __GUI_SPECIES_COMBO_BOX_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "Species.h" /// class for species selection combo box class GuiSpeciesComboBox : public QComboBox { Q_OBJECT public: // constructor GuiSpeciesComboBox(QWidget* parent = 0); // destructor ~GuiSpeciesComboBox(); // get selected species Species getSelectedSpecies() const; // set the species void setSelectedSpecies(const Species& s); protected: /// set the current item made protected to prevent user from calling it void setCurrentIndex(int indx); }; #endif // __GUI_SPECIES_COMBO_BOX_H__ caret-5.6.4~dfsg.1.orig/caret/GuiSpeciesComboBox.cxx0000664000175000017500000000376211572067322022104 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "GuiSpeciesComboBox.h" /** * constructor. */ GuiSpeciesComboBox::GuiSpeciesComboBox(QWidget* parent) : QComboBox(parent) { std::vector speciesTypes; std::vector speciesNames; Species::getAllSpeciesTypesAndNames(speciesTypes, speciesNames); for (unsigned int i = 0; i < speciesNames.size(); i++) { addItem(speciesNames[i], static_cast(speciesTypes[i])); } } /** * destructor. */ GuiSpeciesComboBox::~GuiSpeciesComboBox() { } /** * get selected species. */ Species GuiSpeciesComboBox::getSelectedSpecies() const { Species species; const int indx = currentIndex(); if (indx >= 0) { species = static_cast(itemData(indx).toInt()); } return species; } /** * set the species. */ void GuiSpeciesComboBox::setSelectedSpecies(const Species& s) { const int indx = findData(static_cast(s.getType())); if (indx >= 0) { setCurrentIndex(indx); } } /** * set the current item made protected to prevent user from calling it. */ void GuiSpeciesComboBox::setCurrentIndex(int indx) { QComboBox::setCurrentIndex(indx); } caret-5.6.4~dfsg.1.orig/caret/GuiSpecFileDialog.h0000664000175000017500000004167411572067322021323 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_SPEC_FILE_DIALOG_H__ #define __GUI_SPEC_FILE_DIALOG_H__ #include #include "BrainModelSurface.h" #include "SpecFile.h" #include "TransformationMatrixFile.h" #include "WuQDialog.h" // // forward declarations to avoid include files // class GuiCategoryComboBox; class GuiSpeciesComboBox; class GuiSpecFileDialogMainWindow; class GuiStereotaxicSpaceComboBox; class GuiStructureComboBox; class QButtonGroup; class QCheckBox; class QComboBox; class QGroupBox; class QLabel; class QLineEdit; class QPushButton; class QScrollArea; class QToolButton; class QVBoxLayout; /// Dialog for making selections from the specification file. class GuiSpecFileDialog : public WuQDialog { Q_OBJECT public: /// dialog mode enum SPEC_DIALOG_MODE { /// open a spec file mode SPEC_DIALOG_MODE_OPEN_SPEC_FILE, /// fast open a data file SPEC_DIALOG_MODE_OPEN_DATA_FILE, /// view current files SPEC_DIALOG_MODE_VIEW_CURRENT_FILES }; /// Constructor GuiSpecFileDialog(QWidget* parent, SpecFile& sf, const SPEC_DIALOG_MODE dialogModeIn); /// Destructor ~GuiSpecFileDialog(); /// Display the dialog virtual void show(); public slots: /// close the dialog void slotCloseDialog(); /// close the dialog when close button pressed void slotCloseDialogButton(); private: /// the main window in this dialog GuiSpecFileDialogMainWindow* specFileDialogMainWindow; /// multiple fiducial coord files flag bool multipleFiducialCoordFlag; /// the dialog mode SPEC_DIALOG_MODE dialogMode; /// auto close check box QCheckBox* autoCloseCheckBox; /// directory containing spec file QString* directoryName; }; /// MainWindow placed in the Spec File Dialog class GuiSpecFileDialogMainWindow : public QMainWindow { Q_OBJECT public: /// Constructor GuiSpecFileDialogMainWindow(QWidget* parent, SpecFile& sf, const GuiSpecFileDialog::SPEC_DIALOG_MODE dialogModeIn); /// Destructor ~GuiSpecFileDialogMainWindow(); /// write the spec file if needed void writeSpecFileIfNeeded(); signals: /// requests that the dialog containing this object be closed void signalCloseDialogRequested(); public slots: /// select all files void slotSelectAllFiles(); /// deselect all files void slotDeselectAllFiles(); /// Called when OK button is pressed void slotOkButton(); /// Called when Create Spec button is pressed void slotCreateSpecButton(); /// Called when Load Scene(s) button is pressed void slotLoadScenesButton(); /// called when Comment button is pressed void slotCommentPushButton(); protected slots: private slots: /// Called when a fast open button is pressed void fastOpenButtonSlot(int buttonNumber); /// Called when an info button is pressed void infoButtonGroupSlot(int buttonNumber); /// Called when a delete (X) button is pressed void deleteButtonGroupSlot(int buttonNumber); /// Called when the toolbar all button is pressed void slotToolBarAllButton(); /// Called when the toolbar geometry button is pressed void slotToolBarGeometryButton(); /// Called when the toolbar border button is pressed void slotToolBarBorderButton(); /// Called when the toolbar cell button is pressed void slotToolBarCellButton(); /// Called when the toolbar foci button is pressed void slotToolBarFociButton(); /// Called when the toolbar metric button is pressed void slotToolBarMetricButton(); /// Called when the toolbar misc button is pressed void slotToolBarMiscButton(); /// Called when the toolbar paint button is pressed void slotToolBarPaintButton(); /// Called when the toolbar scene button is pressed void slotToolBarSceneButton(); /// Called when the toolbar volume button is pressed void slotToolBarVolumeButton(); /// Called when set transform button is pressed void slotSetTransformPushButton(); private: /// file filter types enum FILE_FILTER_TYPE { FILE_FILTER_ALL, FILE_FILTER_COORD_AND_TOPO, FILE_FILTER_BORDER, FILE_FILTER_PAINT, FILE_FILTER_METRIC_AND_PALETTE, FILE_FILTER_CELL, FILE_FILTER_FOCI, FILE_FILTER_SCENE, FILE_FILTER_VOLUME, FILE_FILTER_MISC }; /// This private class is used to keep track of selections made by the user /// and set the SpecFile selections when the dialog is closed. class SelectionItem { public: QWidget* groupWidget; // group checkbox is within for select/deselect all QCheckBox* checkbox; // used in open spec file mode QPushButton* pushbutton; // used in fast open mode QPushButton* infobutton; QPushButton* deletebutton; QLabel* typelabel; QLabel* namelabel; SpecFile::SPEC_FILE_BOOL* selected; // used in open spec file mode QString specFileTag; // Used in fast open mode QString* fileName; // Used in fast open mode and for removal from spec AbstractFile* dataFile; bool volumeFlag; // file is a volume file SelectionItem(QWidget* groupWidgetIn, QCheckBox* cb, QPushButton* pb, QPushButton* ib, QPushButton* db, QLabel* tl, QLabel* nl, SpecFile::SPEC_FILE_BOOL* sel, const QString specFileTagIn, QString* fileNameIn, AbstractFile* dataFileIn, const bool volumeFlagIn) { groupWidget = groupWidgetIn; checkbox = cb; pushbutton = pb; infobutton = ib; deletebutton = db; typelabel = tl; namelabel = nl; selected = sel; specFileTag = specFileTagIn; fileName = fileNameIn; dataFile = dataFileIn; volumeFlag = volumeFlagIn; }; }; /// create the toolbar void createToolBar(); /// disable tool bar buttons void disableToolBarButtons(); /// set the toolbar buttons on/off void setToolBarButtons(); /// List the surfaces parameters. QGroupBox* listSurfaceParameters(QVBoxLayout* layout); /// change the filename so that the path, if there is one, is in () after the filename QString prepareFileName(const QString& name); /// list files for selection by the user QGroupBox* listFiles(QVBoxLayout* layout, const QString& title, AbstractFile* dataFile, const QString& specFileTag, SpecFile::Entry& files, const bool allowCommentEditing = true, const bool volumeFileFlag = false); /// list border files for selection by user QGroupBox* listBorderFiles(QVBoxLayout* layout, SpecFile& sf); /// list surface files for selection by user QGroupBox* listSurfaceFiles(QVBoxLayout* layout, SpecFile& sf); /// list coordinate files for selection by user QGroupBox* listCoordinateFiles(QVBoxLayout* layout, SpecFile& sf); /// list topology files for selection by user QGroupBox* listTopologyFiles(QVBoxLayout* layout, SpecFile& sf); /// Set the files that are checked as seleted in the spec file. void setCheckedFilesAsSelected(); /// keeps association of QCheckBoxes and selected files std::vector selectionItems; /// the spec file that is being selected SpecFile specFile; /// the dialog mode GuiSpecFileDialog::SPEC_DIALOG_MODE dialogMode; /// button group for fast open buttons QButtonGroup* fastOpenButtonGroup; /// button group for info buttons QButtonGroup* infoButtonGroup; /// button group for delete X buttons QButtonGroup* deleteButtonGroup; /// group box containing files QGroupBox* areaColorGroup; /// group box containing files QGroupBox* arealEstGroup; /// group box containing files QGroupBox* borderColorGroup; /// group box containing files QGroupBox* borderProjGroup; /// group box containing files QGroupBox* cellGroup; /// group box containing volume cell files QGroupBox* cellVolumeGroup; /// group box containing files QGroupBox* cellColorGroup; /// group box containing files QGroupBox* cellProjectionGroup; /// cerebral hull files QGroupBox* cerebralHullGroup; /// group box containing files QGroupBox* cocomacGroup; /// group box containing files QGroupBox* contourGroup; /// group box containing files QGroupBox* contourCellGroup; /// group box containing files QGroupBox* contourCellColorGroup; /// group box containing files QGroupBox* cutsGroup; /// group box containing deformation field files QGroupBox* defFieldGroup; /// group box containing files QGroupBox* defMapGroup; /// group box containing document files QGroupBox* documentGroup; /// group box containing files QGroupBox* fociGroup; /// group box containing files QGroupBox* fociColorGroup; /// group box containing files QGroupBox* fociProjGroup; /// group box containing files QGroupBox* fociSearchGroup; /// group box containing image files QGroupBox* imagesGroup; /// group box containing files QGroupBox* latLonGroup; /// group box containing files QGroupBox* metricGroup; /// group box containing files QGroupBox* paintGroup; /// group box containing files QGroupBox* paletteGroup; /// group box containing files QGroupBox* paramsGroup; /// group box containing files QGroupBox* probAtlasGroup; /// group box containing files QGroupBox* rgbPaintGroup; /// group box containing files QGroupBox* sceneGroup; /// group box containing files QGroupBox* sectionGroup; /// group box containing files QGroupBox* shapeGroup; /// group box containing files QGroupBox* vectorGroup; /// group box containing files QGroupBox* topographyGroup; /// group box containing files QGroupBox* transMatrixGroup; /// group box containing files QGroupBox* transDataGroup; /// group box containing files QGroupBox* volumeAnatomyGroup; /// group box containing files QGroupBox* volumeFuncGroup; /// group box containing files QGroupBox* volumePaintGroup; /// group box containing files QGroupBox* volumeProbAtlasGroup; /// group box containing files QGroupBox* volumeRgbGroup; /// group box containing files QGroupBox* volumeSegmentGroup; /// group box containing files QGroupBox* volumeVectorGroup; /// group box containing files QGroupBox* topologyGroup; /// group box containing files QGroupBox* coordGroup; /// group box containing files QGroupBox* surfaceGroup; /// group box containing files QGroupBox* borderGroup; /// group box for surface parameters QGroupBox* surfaceParametersGroup; /// group box for study collection files QGroupBox* studyCollectionGroup; /// group box for study metadata files QGroupBox* studyMetaDataGroup; /// group box for vocabulary files QGroupBox* vocabularyGroup; /// group for vtk model files QGroupBox* vtkModelGroup; /// group box for wustl region files QGroupBox* wustlRegionGroup; /// group box for geodesic distance file QGroupBox* geodesicGroup; /// file filter values FILE_FILTER_TYPE fileFilterSelections; /// all filter tool button QToolButton* allButton; /// geometry filter tool button QToolButton* geomButton; /// border filter tool button QToolButton* borderButton; /// cell filter tool button QToolButton* cellButton; /// foci filter tool button QToolButton* fociButton; /// metric filter tool button QToolButton* metricButton; /// misc filter tool button QToolButton* miscButton; /// paint filter tool button QToolButton* paintButton; /// scene filter tool button QToolButton* sceneButton; /// volume filter tool button QToolButton* volumeButton; /// flag set when user removes a file from the spec file bool specFileNeedsToBeWritten; /// space combo box GuiStereotaxicSpaceComboBox* spaceComboBox; /// species combo box GuiSpeciesComboBox* speciesComboBox; /// category combo box GuiCategoryComboBox* categoryComboBox; /// subject line edit QLineEdit* subjectLineEdit; /// structure combo box GuiStructureComboBox* structureComboBox; /// comment value at time spec file loaded into dialog QString savedComment; /// species value at time spec file loaded into dialog Species savedSpecies; /// structure value at time spec file loaded into dialog Structure::STRUCTURE_TYPE savedStructure; /// space value at time spec file loaded into dialog StereotaxicSpace savedStereotaxicSpace; /// category value at time spec file loaded into dialog Category savedCategory; /// category value at time spec file loaded into dialog QString savedSubject; /// check for missing files flag bool checkForMissingFiles; /// the transformation matrix TransformationMatrix transformMatrix; /// scrolling for the the files lists QScrollArea* filesScrollArea; /// widget containing file selections QWidget* filesListWidget; /// action for all toolbar button QAction* allAction; /// action for toolbar button QAction* geomAction; /// action for toolbar button QAction* borderAction; /// action for toolbar button QAction* cellAction; /// action for toolbar button QAction* fociAction; /// action for toolbar button QAction* metricAction; /// action for toolbar button QAction* miscAction; /// action for toolbar button QAction* paintAction; /// action for toolbar button QAction* sceneAction; /// action for toolbar button QAction* volumeAction; /// directory containing spec file QString directoryName; }; #endif caret-5.6.4~dfsg.1.orig/caret/GuiSpecFileDialog.cxx0000664000175000017500000032111711572067322021667 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include "WuQFileDialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "AreaColorFile.h" #include "ArealEstimationFile.h" #include "BorderColorFile.h" #include "BorderFile.h" #include "BrainModelBorderSet.h" #include "BrainModelContours.h" #include "BrainSet.h" #include "Category.h" #include "CellColorFile.h" #include "CellProjectionFile.h" #include "CellFile.h" #include "CellProjectionFile.h" #include "CocomacConnectivityFile.h" #include "ContourCellFile.h" #include "ContourCellColorFile.h" #include "ContourFile.h" #include "CutsFile.h" #include "DebugControl.h" #include "DeformationFieldFile.h" #include "DeformationMapFile.h" #include "FileFilters.h" #include "FileUtilities.h" #include "FociColorFile.h" #include "FociFile.h" #include "FociProjectionFile.h" #include "FociSearchFile.h" #include "GeodesicDistanceFile.h" #include "GuiCategoryComboBox.h" #include "GuiDataFileOpenDialog.h" #include "GuiSpeciesComboBox.h" #include "GuiStereotaxicSpaceComboBox.h" #include "GuiStructureComboBox.h" #include "GuiMainWindow.h" #include "LatLonFile.h" #include "MetricFile.h" #include "QtListBoxSelectionDialog.h" #include "QtUtilities.h" #include "GuiDataFileCommentDialog.h" #include "GuiMainWindow.h" #include "GuiSpecFileDialog.h" #include "PaintFile.h" #include "PaletteFile.h" #include "ParamsFile.h" #include "ProbabilisticAtlasFile.h" #include "QtTextEditDialog.h" #include "RgbPaintFile.h" #include "SectionFile.h" #include "Species.h" #include "StereotaxicSpace.h" #include "StringUtilities.h" #include "StudyCollectionFile.h" #include "StudyMetaDataFile.h" #include "SurfaceShapeFile.h" #include "VectorFile.h" #include "TopographyFile.h" #include "VocabularyFile.h" #include "WuQFileDialog.h" #include "WustlRegionFile.h" #include "global_variables.h" /** * The Constructor. After calling the constructor, call "exec()" to popup this modal * dialog and which returns QDialog::Accepted or QDialog::Rejected. */ GuiSpecFileDialog::GuiSpecFileDialog(QWidget* parent, SpecFile& sfin, const SPEC_DIALOG_MODE dialogModeIn) : WuQDialog(parent) { setAttribute(Qt::WA_DeleteOnClose); dialogMode = dialogModeIn; setSizeGripEnabled(true); QString caption("Specification File: "); caption.append(FileUtilities::basename(sfin.getFileName())); setWindowTitle(caption); QVBoxLayout* rows = new QVBoxLayout(this); rows->setSpacing(5); // // Main window containing tool bar and file selections // specFileDialogMainWindow = new GuiSpecFileDialogMainWindow(0, sfin, dialogMode); rows->addWidget(specFileDialogMainWindow); rows->setStretchFactor(specFileDialogMainWindow, 1); // // Close window when main window requests it // QObject::connect(specFileDialogMainWindow, SIGNAL(signalCloseDialogRequested()), this, SLOT(slotCloseDialog())); switch (dialogMode) { case SPEC_DIALOG_MODE_OPEN_SPEC_FILE: { // // Dialog Buttons Row 1 // QHBoxLayout* buttonsLayout1 = new QHBoxLayout; rows->addLayout(buttonsLayout1); rows->setStretchFactor(buttonsLayout1, 1000); // // Load Scenes button // QPushButton* loadScenesButton = new QPushButton("Load Scene(s)"); loadScenesButton->setAutoDefault(false); QObject::connect(loadScenesButton, SIGNAL(clicked()), specFileDialogMainWindow, SLOT(slotLoadScenesButton())); buttonsLayout1->addWidget(loadScenesButton); loadScenesButton->setToolTip( "Load only the scene files, nothing else.\n" "The Display Control Dialog will be displayed\n" "and preset to the Scene Page."); if (sfin.sceneFile.files.empty()) { loadScenesButton->setEnabled(false); } // // Create new spec file button // QPushButton* createSpecButton = new QPushButton("Create New Spec..."); createSpecButton->setAutoDefault(false); QObject::connect(createSpecButton, SIGNAL(clicked()), specFileDialogMainWindow, SLOT(slotCreateSpecButton())); buttonsLayout1->addWidget(createSpecButton); createSpecButton->setToolTip( "Create a new spec file containing\n" "only the currently selected files."); // // Set transform button // QPushButton* setTransformPushButton = new QPushButton("Set Transform..."); setTransformPushButton->setAutoDefault(false); QObject::connect(setTransformPushButton, SIGNAL(clicked()), specFileDialogMainWindow, SLOT(slotSetTransformPushButton())); buttonsLayout1->addWidget(setTransformPushButton); setTransformPushButton->setToolTip( "Choose a transformation matrix that will\n" "be applied to RAW and FIDUCIAL border,\n" "cell, coordinate, foci, and volume files\n" "immediately after they are read. If this\n" "button is pressed and no matrix is selected\n" "the matrix defaults to the identity matrix."); QtUtilities::makeButtonsSameSize(loadScenesButton, createSpecButton, setTransformPushButton); } break; case SPEC_DIALOG_MODE_OPEN_DATA_FILE: break; case SPEC_DIALOG_MODE_VIEW_CURRENT_FILES: break; } // // Dialog Buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; rows->addLayout(buttonsLayout); rows->setStretchFactor(buttonsLayout, 1000); // // OK button // QPushButton* ok = NULL; switch (dialogMode) { case GuiSpecFileDialog::SPEC_DIALOG_MODE_OPEN_SPEC_FILE: ok = new QPushButton("Load"); ok->setAutoDefault(false); QObject::connect(ok, SIGNAL(clicked()), specFileDialogMainWindow, SLOT(slotOkButton())); buttonsLayout->addWidget(ok); ok->setToolTip("Load the currently selected\n" "files into Caret."); break; case GuiSpecFileDialog::SPEC_DIALOG_MODE_OPEN_DATA_FILE: break; case GuiSpecFileDialog::SPEC_DIALOG_MODE_VIEW_CURRENT_FILES: break; } QPushButton* allButton = NULL; QPushButton* deselectAllButton = NULL; switch (dialogMode) { case SPEC_DIALOG_MODE_OPEN_SPEC_FILE: // // Select all files button // allButton = new QPushButton("Select All"); allButton->setAutoDefault(false); QObject::connect(allButton, SIGNAL(clicked()), specFileDialogMainWindow, SLOT(slotSelectAllFiles())); buttonsLayout->addWidget(allButton); allButton->setToolTip( "Select All Files"); // // Deselect all files button // deselectAllButton = new QPushButton("Deselect All"); deselectAllButton->setAutoDefault(false); QObject::connect(deselectAllButton, SIGNAL(clicked()), specFileDialogMainWindow, SLOT(slotDeselectAllFiles())); buttonsLayout->addWidget(deselectAllButton); deselectAllButton->setToolTip( "Deselect All Files"); break; case SPEC_DIALOG_MODE_OPEN_DATA_FILE: break; case SPEC_DIALOG_MODE_VIEW_CURRENT_FILES: break; } // // Cancel/Close button // QPushButton* cancel = new QPushButton("Close"); cancel->setAutoDefault(false); QObject::connect(cancel, SIGNAL(clicked()), this, SLOT(slotCloseDialogButton())); buttonsLayout->addWidget(cancel); switch (dialogMode) { case SPEC_DIALOG_MODE_OPEN_SPEC_FILE: break; case SPEC_DIALOG_MODE_OPEN_DATA_FILE: cancel->setText("Close"); cancel->setFixedSize(cancel->sizeHint()); break; case SPEC_DIALOG_MODE_VIEW_CURRENT_FILES: cancel->setText("Close"); cancel->setFixedSize(cancel->sizeHint()); break; } cancel->setToolTip( "Close this dialog and\n" "take no further action."); autoCloseCheckBox = NULL; switch (dialogMode) { case SPEC_DIALOG_MODE_OPEN_SPEC_FILE: { std::vector buttons; buttons.push_back(ok); buttons.push_back(cancel); buttons.push_back(allButton); buttons.push_back(deselectAllButton); QtUtilities::makeButtonsSameSize(buttons); } break; case SPEC_DIALOG_MODE_OPEN_DATA_FILE: // // Create "Auto Close" checkbox // autoCloseCheckBox = new QCheckBox("Auto Close"); autoCloseCheckBox->setChecked(true); autoCloseCheckBox->setToolTip( "If checked, the dialog is\n" "closed after a file is chosen."); buttonsLayout->addWidget(autoCloseCheckBox); break; case SPEC_DIALOG_MODE_VIEW_CURRENT_FILES: break; } QtUtilities::positionAndSetDialogSize(theMainWindow, this, this->sizeHint()); adjustSize(); multipleFiducialCoordFlag = (sfin.fiducialCoordFile.getNumberOfFiles() > 1); } /** * The Destructor. */ GuiSpecFileDialog::~GuiSpecFileDialog() { } /** * Gets called when dialog is to be popped up. Intercept this call so that the multiple * fiducial warning can be displayed. */ void GuiSpecFileDialog::show() { // // Popup the dialog first // WuQDialog::show(); } /** * Called when close pushbutton is hit. This is called instead of slotCloseDialog * since the auto close check box may not be selected. */ void GuiSpecFileDialog::slotCloseDialogButton() { specFileDialogMainWindow->writeSpecFileIfNeeded(); QDialog::close(); } /** * Close the dialog. */ void GuiSpecFileDialog::slotCloseDialog() { if (autoCloseCheckBox != NULL) { if (autoCloseCheckBox->isChecked() == false) { return; } } specFileDialogMainWindow->writeSpecFileIfNeeded(); QDialog::close(); } //------------------------------------------------------------------------------- /** * Constructor. */ GuiSpecFileDialogMainWindow::GuiSpecFileDialogMainWindow(QWidget* parent, SpecFile& sf, const GuiSpecFileDialog::SPEC_DIALOG_MODE dialogModeIn) : QMainWindow(parent) { specFile = sf; dialogMode = dialogModeIn, directoryName = FileUtilities::dirname(sf.getFileName()); specFileNeedsToBeWritten = false; // // create the toolbar // createToolBar(); // // Main Widget // QWidget* vboxm = new QWidget(this); setCentralWidget(vboxm); QVBoxLayout* vbLayout = new QVBoxLayout(vboxm); // // Button Group for fast open buttons // fastOpenButtonGroup = new QButtonGroup(this); QObject::connect(fastOpenButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(fastOpenButtonSlot(int))); // // Button Group for info buttons // infoButtonGroup = new QButtonGroup(this); QObject::connect(infoButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(infoButtonGroupSlot(int))); // // Button Group for delete (X) buttons // deleteButtonGroup = new QButtonGroup(this); QObject::connect(deleteButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(deleteButtonGroupSlot(int))); // // Save the current directory and set to the spec file's directory // checkForMissingFiles = false; const QString savedDirectory(QDir::currentPath()); const QString specFileDir(FileUtilities::dirname(sf.getFileName())); //if (QDir::isRelativePath(specFileDir) == false) { QDir::setCurrent(specFileDir); checkForMissingFiles = true; //} BrainSet* bs = theMainWindow->getBrainSet(); // // Vertical Box Layout for the entire dialog // filesListWidget = new QWidget; QVBoxLayout* filesLayout = new QVBoxLayout; surfaceParametersGroup = listSurfaceParameters(filesLayout); topologyGroup = listTopologyFiles(filesLayout, specFile); coordGroup = listCoordinateFiles(filesLayout, specFile); surfaceGroup = listSurfaceFiles(filesLayout, specFile); areaColorGroup = listFiles(filesLayout, "Area Color Files", bs->getAreaColorFile(), SpecFile::getAreaColorFileTag(), specFile.areaColorFile); arealEstGroup = listFiles(filesLayout, "Areal Estimation Files", bs->getArealEstimationFile(), SpecFile::getArealEstimationFileTag(), specFile.arealEstimationFile); borderGroup = listBorderFiles(filesLayout, specFile); borderColorGroup = listFiles(filesLayout, "Border Color Files", bs->getBorderColorFile(), SpecFile::getBorderColorFileTag(), specFile.borderColorFile); borderProjGroup = listFiles(filesLayout, "Border Projection Files", NULL, SpecFile::getBorderProjectionFileTag(), specFile.borderProjectionFile); cellGroup = listFiles(filesLayout, "Cell Files (Fiducial)", bs->getCellProjectionFile(), // NOTE: all cells are stored in cell projection file SpecFile::getCellFileTag(), specFile.cellFile); cellVolumeGroup = listFiles(filesLayout, "Cell Files (Volume)", bs->getVolumeCellFile(), SpecFile::getVolumeCellFileTag(), specFile.volumeCellFile); cellColorGroup = listFiles(filesLayout, "Cell Color Files", bs->getCellColorFile(), SpecFile::getCellColorFileTag(), specFile.cellColorFile); cellProjectionGroup = listFiles(filesLayout, "Cell Projection Files", bs->getCellProjectionFile(), SpecFile::getCellProjectionFileTag(), specFile.cellProjectionFile); cerebralHullGroup = listFiles(filesLayout, "Cerebral Hull Files", NULL, SpecFile::getCerebralHullFileTag(), specFile.cerebralHullFile); cocomacGroup = listFiles(filesLayout, "CoCoMac Connectivity File", bs->getCocomacFile(), SpecFile::getCocomacConnectivityFileTag(), specFile.cocomacConnectivityFile, false); ContourFile* contourFile = NULL; BrainModelContours* bmc = bs->getBrainModelContours(); if (bmc != NULL) { contourFile = bmc->getContourFile(); } contourGroup = listFiles(filesLayout, "Contour File", contourFile, SpecFile::getContourFileTag(), specFile.contourFile); contourCellGroup = listFiles(filesLayout, "Contour Cell File", bs->getContourCellFile(), SpecFile::getContourCellFileTag(), specFile.contourCellFile); contourCellColorGroup = listFiles(filesLayout, "Contour Cell Color File", bs->getContourCellColorFile(), SpecFile::getContourCellColorFileTag(), specFile.contourCellColorFile); cutsGroup = listFiles(filesLayout, "Cuts File", bs->getCutsFile(), SpecFile::getCutsFileTag(), specFile.cutsFile); defFieldGroup = listFiles(filesLayout, "Deformation Field File", bs->getDeformationFieldFile(), SpecFile::getDeformationFieldFileTag(), specFile.deformationFieldFile); defMapGroup = listFiles(filesLayout, "Deformation Map File", NULL, SpecFile::getDeformationMapFileTag(), specFile.deformationMapFile); documentGroup = listFiles(filesLayout, "Document Files", NULL, SpecFile::getDocumentFileTag(), specFile.documentFile); fociGroup = listFiles(filesLayout, "Foci Files (Fiducial)", bs->getFociProjectionFile(), // NOTE: All foci are stored in foci projection file SpecFile::getFociFileTag(), specFile.fociFile); fociColorGroup = listFiles(filesLayout, "Foci Color File", bs->getFociColorFile(), SpecFile::getFociColorFileTag(), specFile.fociColorFile); fociProjGroup = listFiles(filesLayout, "Foci Projection File", bs->getFociProjectionFile(), SpecFile::getFociProjectionFileTag(), specFile.fociProjectionFile); fociSearchGroup = listFiles(filesLayout, "Foci Search File", bs->getFociSearchFile(), SpecFile::getFociSearchFileTag(), specFile.fociSearchFile); geodesicGroup = listFiles(filesLayout, "Geodesic Distance File", bs->getGeodesicDistanceFile(), SpecFile::getGeodesicDistanceFileTag(), specFile.geodesicDistanceFile); imagesGroup = listFiles(filesLayout, "Image Files", NULL, SpecFile::getImageFileTag(), specFile.imageFile); latLonGroup = listFiles(filesLayout, "Latitude Longitude Files", bs->getLatLonFile(), SpecFile::getLatLonFileTag(), specFile.latLonFile); metricGroup = listFiles(filesLayout, "Metric Files", bs->getMetricFile(), SpecFile::getMetricFileTag(), specFile.metricFile); paintGroup = listFiles(filesLayout, "Paint Files", bs->getPaintFile(), SpecFile::getPaintFileTag(), specFile.paintFile); paletteGroup = listFiles(filesLayout, "Palette Files", bs->getPaletteFile(), SpecFile::getPaletteFileTag(), specFile.paletteFile); paramsGroup = listFiles(filesLayout, "Params File", bs->getParamsFile(), SpecFile::getParamsFileTag(), specFile.paramsFile); probAtlasGroup = listFiles(filesLayout, "Probabilistic Atlas Files", bs->getProbabilisticAtlasSurfaceFile(), SpecFile::getAtlasFileTag(), specFile.atlasFile); rgbPaintGroup = listFiles(filesLayout, "RGB Paint Files", bs->getRgbPaintFile(), SpecFile::getRgbPaintFileTag(), specFile.rgbPaintFile); sceneGroup = listFiles(filesLayout, "Scene Files", bs->getSceneFile(), SpecFile::getSceneFileTag(), specFile.sceneFile); sectionGroup = listFiles(filesLayout, "Section Files", bs->getSectionFile(), SpecFile::getSectionFileTag(), specFile.sectionFile); shapeGroup = listFiles(filesLayout, "Surface Shape Files", bs->getSurfaceShapeFile(), SpecFile::getSurfaceShapeFileTag(), specFile.surfaceShapeFile); studyCollectionGroup = listFiles(filesLayout, "Study Collection Files", bs->getStudyCollectionFile(), SpecFile::getStudyCollectionFileTag(), specFile.studyCollectionFile); studyMetaDataGroup = listFiles(filesLayout, "Study Metadata Files", bs->getStudyMetaDataFile(), SpecFile::getStudyMetaDataFileTag(), specFile.studyMetaDataFile); topographyGroup = listFiles(filesLayout, "Topography Files", bs->getTopographyFile(), SpecFile::getTopographyFileTag(), specFile.topographyFile); transMatrixGroup = listFiles(filesLayout, "Transformation Matrix Files", bs->getTransformationMatrixFile(), SpecFile::getTransformationMatrixFileTag(), specFile.transformationMatrixFile); transDataGroup = listFiles(filesLayout, "Transformation Data Files", NULL, SpecFile::getTransformationDataFileTag(), specFile.transformationDataFile); vectorGroup = listFiles(filesLayout, "Vector Files", NULL, SpecFile::getVectorFileTag(), specFile.vectorFile, true, false); vocabularyGroup = listFiles(filesLayout, "Vocabulary Files", bs->getVocabularyFile(), SpecFile::getVocabularyFileTag(), specFile.vocabularyFile); volumeAnatomyGroup = listFiles(filesLayout, "Volume Files - Anatomy", NULL, SpecFile::getVolumeAnatomyFileTag(), specFile.volumeAnatomyFile, true, true); volumeFuncGroup = listFiles(filesLayout, "Volume Files - Functional", NULL, SpecFile::getVolumeFunctionalFileTag(), specFile.volumeFunctionalFile, true, true); volumePaintGroup = listFiles(filesLayout, "Volume Files - Paint", NULL, SpecFile::getVolumePaintFileTag(), specFile.volumePaintFile, true, true); volumeProbAtlasGroup = listFiles(filesLayout, "Volume Files - Prob Atlas", NULL, SpecFile::getVolumeProbAtlasFileTag(), specFile.volumeProbAtlasFile, true, true); volumeRgbGroup = listFiles(filesLayout, "Volume Files - RGB", NULL, SpecFile::getVolumeRgbFileTag(), specFile.volumeRgbFile, true, true); volumeSegmentGroup = listFiles(filesLayout, "Volume Files - Segmentation", NULL, SpecFile::getVolumeSegmentationFileTag(), specFile.volumeSegmentationFile, true, true); volumeVectorGroup = listFiles(filesLayout, "Volume Files - Vector", NULL, SpecFile::getVolumeVectorFileTag(), specFile.volumeVectorFile, true, true); vtkModelGroup = listFiles(filesLayout, "VTK Model Files", NULL, SpecFile::getVtkModelFileTag(), specFile.vtkModelFile); wustlRegionGroup = listFiles(filesLayout, "Wustl Region Files", bs->getWustlRegionFile(), SpecFile::getWustlRegionFileTag(), specFile.wustlRegionFile); QLabel* dummyLabel = new QLabel(" "); filesLayout->addWidget(dummyLabel); filesLayout->setStretchFactor(dummyLabel, 10000000); filesListWidget->setLayout(filesLayout); // // Scroll View for all selections // filesScrollArea = new QScrollArea; vbLayout->addWidget(filesScrollArea); filesScrollArea->setWidget(filesListWidget); filesScrollArea->setWidgetResizable(true); // // Restore the saved directory // QDir::setCurrent(savedDirectory); disableToolBarButtons(); slotToolBarAllButton(); } /** * Destructor. */ GuiSpecFileDialogMainWindow::~GuiSpecFileDialogMainWindow() { } /** * write the spec file if needed. */ void GuiSpecFileDialogMainWindow::writeSpecFileIfNeeded() { switch (dialogMode) { case GuiSpecFileDialog::SPEC_DIALOG_MODE_OPEN_SPEC_FILE: if (savedStructure != structureComboBox->getSelectedStructure()) { specFile.setStructure(structureComboBox->getSelectedStructureAsString()); specFileNeedsToBeWritten = true; } if (savedSpecies != speciesComboBox->getSelectedSpecies()) { specFile.setSpecies(speciesComboBox->getSelectedSpecies().getName()); specFileNeedsToBeWritten = true; } if (savedStereotaxicSpace != spaceComboBox->getSelectedStereotaxicSpace()) { specFile.setSpace(spaceComboBox->getSelectedStereotaxicSpace()); specFileNeedsToBeWritten = true; } if (savedCategory != categoryComboBox->getSelectedCategory()) { specFile.setCategory(categoryComboBox->getSelectedCategory()); specFileNeedsToBeWritten = true; } if (savedSubject != subjectLineEdit->text()) { specFile.setSubject(subjectLineEdit->text()); specFileNeedsToBeWritten = true; } if (savedComment != specFile.getFileComment()) { specFileNeedsToBeWritten = true; } break; case GuiSpecFileDialog::SPEC_DIALOG_MODE_OPEN_DATA_FILE: break; case GuiSpecFileDialog::SPEC_DIALOG_MODE_VIEW_CURRENT_FILES: break; } if (specFileNeedsToBeWritten) { try { specFile.writeFile(specFile.getFileName()); } catch (FileException& e) { QMessageBox::critical(this, "Error Writing Spec File", e.whatQString()); } specFileNeedsToBeWritten = false; } } /** * Load the file filter combo box */ void GuiSpecFileDialogMainWindow::createToolBar() { // // Toolbar for file filtering // QToolBar* toolbar = new QToolBar(this); addToolBar(toolbar); toolbar->setMovable(false); // // All files // allAction = new QAction("All", this); QObject::connect(allAction, SIGNAL(toggled(bool)), this, SLOT(slotToolBarAllButton())); allAction->setToolTip("Press this button to\n" "show all files."); allAction->setCheckable(true); allButton = new QToolButton; allButton->setDefaultAction(allAction); toolbar->addWidget(allButton); // // Coord and topology // geomAction = new QAction("Geom", this); geomAction->setCheckable(true); geomAction->setToolTip("Press this button to show\n" "only coord and topo files."); QObject::connect(geomAction, SIGNAL(toggled(bool)), this, SLOT(slotToolBarGeometryButton())); geomButton = new QToolButton; geomButton->setDefaultAction(geomAction); toolbar->addWidget(geomButton); // // Border files // borderAction = new QAction("Border", this); borderAction->setCheckable(true); borderAction->setToolTip( "Press this button to\n" "show only border files."); QObject::connect(borderAction, SIGNAL(toggled(bool)), this, SLOT(slotToolBarBorderButton())); borderButton = new QToolButton; borderButton->setDefaultAction(borderAction); toolbar->addWidget(borderButton); // // cell files // cellAction = new QAction("Cell", this); cellAction->setCheckable(true); cellAction->setToolTip("Press this button to\n" "show only cell files."); QObject::connect(cellAction, SIGNAL(toggled(bool)), this, SLOT(slotToolBarCellButton())); cellButton = new QToolButton; cellButton->setDefaultAction(cellAction); toolbar->addWidget(cellButton); // // foci files // fociAction = new QAction("Foci", this); fociAction->setCheckable(true); fociAction->setToolTip( "Press this button to\n" "show only foci files."); QObject::connect(fociAction, SIGNAL(toggled(bool)), this, SLOT(slotToolBarFociButton())); fociButton = new QToolButton; fociButton->setDefaultAction(fociAction); toolbar->addWidget(fociButton); // // metric/palette files // metricAction = new QAction("Metric", this); metricAction->setCheckable(true); metricAction->setToolTip( "Press this button to show\n" "only metric and palette files."); QObject::connect(metricAction, SIGNAL(toggled(bool)), this, SLOT(slotToolBarMetricButton())); metricButton = new QToolButton; metricButton->setDefaultAction(metricAction); toolbar->addWidget(metricButton); // // misc files // miscAction = new QAction("Misc", this); miscAction->setCheckable(true); miscAction->setToolTip( "Press this button to\n" "show all other file types."); QObject::connect(miscAction, SIGNAL(toggled(bool)), this, SLOT(slotToolBarMiscButton())); miscButton = new QToolButton; miscButton->setDefaultAction(miscAction); toolbar->addWidget(miscButton); // // paint files // paintAction = new QAction("Paint", this); paintAction->setCheckable(true); paintAction->setToolTip("Press this button to\n" "show only paint files."); QObject::connect(paintAction, SIGNAL(toggled(bool)), this, SLOT(slotToolBarPaintButton())); paintButton = new QToolButton; paintButton->setDefaultAction(paintAction); toolbar->addWidget(paintButton); // // scene files // sceneAction = new QAction("Scene", this); sceneAction->setCheckable(true); sceneAction->setToolTip("Press this button to\n" "show only scene files."); QObject::connect(sceneAction, SIGNAL(toggled(bool)), this, SLOT(slotToolBarSceneButton())); sceneButton = new QToolButton; sceneButton->setDefaultAction(sceneAction); toolbar->addWidget(sceneButton); // // volume files // volumeAction = new QAction("Volume", this); volumeAction->setCheckable(true); volumeAction->setToolTip( "Press this button to\n" "show only volume files."); QObject::connect(volumeAction, SIGNAL(toggled(bool)), this, SLOT(slotToolBarVolumeButton())); volumeButton = new QToolButton; volumeButton->setDefaultAction(volumeAction); toolbar->addWidget(volumeButton); } /** * Called when the toolbar cell button is pressed. */ void GuiSpecFileDialogMainWindow::slotToolBarCellButton() { fileFilterSelections = FILE_FILTER_CELL; setToolBarButtons(); } /** * Called when the toolbar foci button is pressed. */ void GuiSpecFileDialogMainWindow::slotToolBarFociButton() { fileFilterSelections = FILE_FILTER_FOCI; setToolBarButtons(); } /** * Called when the toolbar metric button is pressed. */ void GuiSpecFileDialogMainWindow::slotToolBarMetricButton() { fileFilterSelections = FILE_FILTER_METRIC_AND_PALETTE; setToolBarButtons(); } /** * Called when the toolbar misc button is pressed. */ void GuiSpecFileDialogMainWindow::slotToolBarMiscButton() { fileFilterSelections = FILE_FILTER_MISC; setToolBarButtons(); } /** * Called when the toolbar paint button is pressed. */ void GuiSpecFileDialogMainWindow::slotToolBarPaintButton() { fileFilterSelections = FILE_FILTER_PAINT; setToolBarButtons(); } /** * Called when the toolbar scene button is pressed. */ void GuiSpecFileDialogMainWindow::slotToolBarSceneButton() { fileFilterSelections = FILE_FILTER_SCENE; setToolBarButtons(); } /** * Called when the toolbar volume button is pressed. */ void GuiSpecFileDialogMainWindow::slotToolBarVolumeButton() { fileFilterSelections = FILE_FILTER_VOLUME; setToolBarButtons(); } /** * Called when the toolbar button is pressed. */ void GuiSpecFileDialogMainWindow::slotToolBarAllButton() { fileFilterSelections = FILE_FILTER_ALL; setToolBarButtons(); } /** * Called when the toolbar button is pressed. */ void GuiSpecFileDialogMainWindow::slotToolBarGeometryButton() { fileFilterSelections = FILE_FILTER_COORD_AND_TOPO; setToolBarButtons(); } /** * Called when the toolbar border button is pressed. */ void GuiSpecFileDialogMainWindow::slotToolBarBorderButton() { fileFilterSelections = FILE_FILTER_BORDER; setToolBarButtons(); } /** * Disable the file filter buttons for file types not loaded. */ void GuiSpecFileDialogMainWindow::disableToolBarButtons() { if ((coordGroup == NULL) && (topologyGroup == NULL) && (surfaceGroup == NULL)) { geomAction->setEnabled(false); } if ((borderGroup == NULL) && (borderColorGroup == NULL) && (borderProjGroup == NULL)) { borderAction->setEnabled(false); } if ((cellGroup == NULL) && (cellVolumeGroup == NULL) && (cellColorGroup == NULL) && (cellProjectionGroup == NULL)) { cellAction->setEnabled(false); } if ((fociGroup == NULL) && (fociColorGroup == NULL) && (fociProjGroup == NULL) && (fociSearchGroup == NULL) && (studyCollectionGroup == NULL) && (studyMetaDataGroup == NULL)) { fociAction->setEnabled(false); } if ((metricGroup == NULL) && (paletteGroup == NULL)) { metricAction->setEnabled(false); } if ((cerebralHullGroup == NULL) && (cocomacGroup == NULL) && (contourGroup == NULL) && (contourCellGroup == NULL) && (contourCellColorGroup == NULL) && (cutsGroup == NULL) && (defFieldGroup == NULL) && (defMapGroup == NULL) && (documentGroup == NULL) && (geodesicGroup == NULL) && (imagesGroup == NULL) && (latLonGroup == NULL) && (paramsGroup == NULL) && (sectionGroup == NULL) && (shapeGroup == NULL) && (studyCollectionGroup == NULL) && (studyMetaDataGroup == NULL) && (vectorGroup == NULL) && (topographyGroup == NULL) && (transMatrixGroup == NULL) && (transDataGroup == NULL) && (vocabularyGroup == NULL) && (vtkModelGroup == NULL) && (wustlRegionGroup == NULL)) { miscAction->setEnabled(false); } if ((areaColorGroup == NULL) && (arealEstGroup == NULL) && (paintGroup == NULL) && (probAtlasGroup == NULL) && (rgbPaintGroup == NULL)) { paintAction->setEnabled(false); } if (sceneGroup == NULL) { sceneAction->setEnabled(false); } if ((volumeAnatomyGroup == NULL) && (volumeFuncGroup == NULL) && (volumePaintGroup == NULL) && (volumeProbAtlasGroup == NULL) && (volumeRgbGroup == NULL) && (volumeSegmentGroup == NULL) && (volumeVectorGroup == NULL)) { volumeAction->setEnabled(false); } } /** * Set the toolbar buttons on/off. */ void GuiSpecFileDialogMainWindow::setToolBarButtons() { bool showSurfaceParameters = false; bool showAreaColors = false; bool showCoordTopo = false; bool showBorder = false; bool showPaint = false; bool showMetric = false; bool showCell = false; bool showFoci = false; bool showScene = false; bool showVolume = false; bool showMisc = false; // // block signals to toolbar buttons otherwise, this method gets // called every time one of buttons is set on or off // allAction->blockSignals(true); geomAction->blockSignals(true); borderAction->blockSignals(true); cellAction->blockSignals(true); fociAction->blockSignals(true); metricAction->blockSignals(true); miscAction->blockSignals(true); paintAction->blockSignals(true); sceneAction->blockSignals(true); volumeAction->blockSignals(true); allAction->setChecked(false); geomAction->setChecked(false); borderAction->setChecked(false); cellAction->setChecked(false); fociAction->setChecked(false); metricAction->setChecked(false); miscAction->setChecked(false); paintAction->setChecked(false); sceneAction->setChecked(false); volumeAction->setChecked(false); switch (fileFilterSelections) { case FILE_FILTER_ALL: allAction->setChecked(true); showSurfaceParameters = true; showAreaColors = true; showCoordTopo = true; showBorder = true; showPaint = true; showMetric = true; showCell = true; showFoci = true; showVolume = true; showMisc = true; showScene = true; break; case FILE_FILTER_COORD_AND_TOPO: geomAction->setChecked(true); showCoordTopo = true; break; case FILE_FILTER_BORDER: borderAction->setChecked(true); showBorder = true; break; case FILE_FILTER_PAINT: paintAction->setChecked(true); showAreaColors = true; showPaint = true; break; case FILE_FILTER_METRIC_AND_PALETTE: metricAction->setChecked(true); showMetric = true; break; case FILE_FILTER_CELL: cellAction->setChecked(true); showCell = true; break; case FILE_FILTER_FOCI: fociAction->setChecked(true); showFoci = true; break; case FILE_FILTER_SCENE: sceneAction->setChecked(true); showScene = true; break; case FILE_FILTER_VOLUME: volumeAction->setChecked(true); showVolume = true; if ((volumePaintGroup != NULL) || (volumeProbAtlasGroup != NULL)) { showAreaColors = true; } break; case FILE_FILTER_MISC: miscAction->setChecked(true); showMisc = true; break; } if (surfaceParametersGroup != NULL) { surfaceParametersGroup->setHidden(!showSurfaceParameters); } if (topologyGroup != NULL) { topologyGroup->setHidden(!showCoordTopo); } if (coordGroup != NULL) { coordGroup->setHidden(!showCoordTopo); } if (surfaceGroup != NULL) { surfaceGroup->setHidden(!showCoordTopo); } if (areaColorGroup != NULL) { areaColorGroup->setHidden(!showAreaColors); } if (arealEstGroup != NULL) { arealEstGroup->setHidden(!showPaint); } if (borderGroup != NULL) { borderGroup->setHidden(!showBorder); } if (borderColorGroup != NULL) { borderColorGroup->setHidden(!showBorder); } if (borderProjGroup != NULL) { borderProjGroup->setHidden(!showBorder); } if (cellGroup != NULL) { cellGroup->setHidden(!showCell); } if (cellVolumeGroup != NULL) { cellVolumeGroup->setHidden(!showCell); } if (cellColorGroup != NULL) { cellColorGroup->setHidden(!showCell); } if (cellProjectionGroup != NULL) { cellProjectionGroup->setHidden(!showCell); } if (cerebralHullGroup != NULL) { cerebralHullGroup->setHidden(!showMisc); } if (cocomacGroup != NULL) { cocomacGroup->setHidden(!showMisc); } if (contourGroup != NULL) { contourGroup->setHidden(!showMisc); } if (contourCellGroup != NULL) { contourCellGroup->setHidden(!showMisc); } if (contourCellColorGroup != NULL) { contourCellColorGroup->setHidden(!showMisc); } if (cutsGroup != NULL) { cutsGroup->setHidden(!showMisc); } if (defFieldGroup != NULL) { defFieldGroup->setHidden(!showMisc); } if (defMapGroup != NULL) { defMapGroup->setHidden(!showMisc); } if (documentGroup != NULL) { documentGroup->setHidden(!showMisc); } if (fociGroup != NULL) { fociGroup->setHidden(!showFoci); } if (fociColorGroup != NULL) { fociColorGroup->setHidden(!showFoci); } if (fociProjGroup != NULL) { fociProjGroup->setHidden(!showFoci); } if (fociSearchGroup != NULL) { fociSearchGroup->setHidden(!showFoci); } if (geodesicGroup != NULL) { geodesicGroup->setHidden(!showMisc); } if (imagesGroup != NULL) { imagesGroup->setHidden(!showMisc); } if (latLonGroup != NULL) { latLonGroup->setHidden(!showMisc); } if (metricGroup != NULL) { metricGroup->setHidden(!showMetric); } if (paintGroup != NULL) { paintGroup->setHidden(!showPaint); } if (paletteGroup != NULL) { paletteGroup->setHidden(!showMetric); } if (paramsGroup != NULL) { paramsGroup->setHidden(!showMisc); } if (probAtlasGroup != NULL) { probAtlasGroup->setHidden(!showPaint); } if (rgbPaintGroup != NULL) { rgbPaintGroup->setHidden(!showPaint); } if (sceneGroup != NULL) { sceneGroup->setHidden(!showScene); } if (sectionGroup != NULL) { sectionGroup->setHidden(!showMisc); } if (shapeGroup != NULL) { shapeGroup->setHidden(!showMisc); } if (studyCollectionGroup != NULL) { studyCollectionGroup->setHidden(!showMisc && !showFoci); } if (studyMetaDataGroup != NULL) { studyMetaDataGroup->setHidden(!showMisc && !showFoci); } if (vectorGroup != NULL) { vectorGroup->setHidden(!showMisc); } if (topographyGroup != NULL) { topographyGroup->setHidden(!showMisc); } if (transMatrixGroup != NULL) { transMatrixGroup->setHidden(!showMisc); } if (transDataGroup != NULL) { transDataGroup->setHidden(!showMisc); } if (vocabularyGroup != NULL) { vocabularyGroup->setHidden(!showMisc); } if (volumeAnatomyGroup != NULL) { volumeAnatomyGroup->setHidden(!showVolume); } if (volumeFuncGroup != NULL) { volumeFuncGroup->setHidden(!showVolume); } if (volumePaintGroup != NULL) { volumePaintGroup->setHidden(!showVolume); } if (volumeProbAtlasGroup != NULL) { volumeProbAtlasGroup->setHidden(!showVolume); } if (volumeRgbGroup != NULL) { volumeRgbGroup->setHidden(!showVolume); } if (volumeSegmentGroup != NULL) { volumeSegmentGroup->setHidden(!showVolume); } if (volumeVectorGroup != NULL) { volumeVectorGroup->setHidden(!showVolume); } if (vtkModelGroup != NULL) { vtkModelGroup->setHidden(!showMisc); } if (wustlRegionGroup != NULL) { wustlRegionGroup->setHidden(!showMisc); } allAction->blockSignals(false); geomAction->blockSignals(false); borderAction->blockSignals(false); cellAction->blockSignals(false); fociAction->blockSignals(false); metricAction->blockSignals(false); miscAction->blockSignals(false); paintAction->blockSignals(false); sceneAction->blockSignals(false); volumeAction->blockSignals(false); filesScrollArea->horizontalScrollBar()->setSliderPosition(0); filesScrollArea->verticalScrollBar()->setSliderPosition(0); } /** * Create a new spec file using the selected files. */ void GuiSpecFileDialogMainWindow::slotCreateSpecButton() { // // Save current directory and switch to directory of the spec file // const QString currentDirectory = QDir::currentPath(); if (DebugControl::getDebugOn()) { std::cout << "Current directory: " << currentDirectory.toAscii().constData() << std::endl; } // // Set current directory to that of the spec file in the dialog // specFile.setCurrentDirectoryToSpecFileDirectory(); if (DebugControl::getDebugOn()) { std::cout << "Spec File: " << specFile.getFileName().toAscii().constData() << std::endl; std::cout << "Current directory now: " << QDir::currentPath().toAscii().constData() << std::endl; } WuQFileDialog fd(this); fd.setModal(true); fd.setWindowTitle("Choose New Spec File Name"); fd.setFileMode(WuQFileDialog::AnyFile); fd.setFilters(QStringList(FileFilters::getSpecFileFilter())); fd.selectFilter(FileFilters::getSpecFileFilter()); fd.setDirectory(directoryName); fd.rereadDir(); // if (newSpecName.isNull() == false) { if (fd.exec() == QDialog::Accepted) { if (fd.selectedFiles().count() > 0) { QString name = fd.selectedFiles().at(0); if (name.isEmpty() == false) { // // Add file extension if necessary // if (name.length() > 5) { const QString ext = name.right(5); if (ext.compare(".spec") != 0) { name.append(".spec"); } } else { name.append(".spec"); } if (QFile::exists(name)) { if (QMessageBox::question(this, "Overwrite ?", "The Spec File you have selected exists.\n" "Do you want to replace it with this new\n" "Spec File that will contain only the \n" "selected files in the the Spec File Dialog?", (QMessageBox::Yes | QMessageBox::No), QMessageBox::No) == QMessageBox::No) { return; } } // // Save current spec file name // const QString saveName(specFile.getFileName()); // // Set the hemisphere, space, species, subject and category // specFile.setStructure(structureComboBox->getSelectedStructure()); specFile.setSpace(spaceComboBox->getSelectedStereotaxicSpace()); specFile.setSpecies(speciesComboBox->getSelectedSpecies()); specFile.setCategory(categoryComboBox->getSelectedCategory()); specFile.setSubject(subjectLineEdit->text()); // // Set the checked files as selected files in the spec file // setCheckedFilesAsSelected(); // // Write the spec file with only the selected files. // specFile.setWriteOnlySelectedFiles(true); try { specFile.writeFile(name); } catch (FileException& e) { QMessageBox::critical(this, "Error Updating Spec File", e.whatQString()); } specFile.setWriteOnlySelectedFiles(false); // // Restore the spec file's name // specFile.setFileName(saveName); // // Open new spec in a spec file dialog // theMainWindow->readSpecFile(name); // // Close this dialog // dynamic_cast(parent())->close(); } } } else { // // Restore the current directory // QDir::setCurrent(currentDirectory); } } /** * Called when Load Scene(s) button is pressed. */ void GuiSpecFileDialogMainWindow::slotLoadScenesButton() { // // Spec file might need to be saved // writeSpecFileIfNeeded(); specFile.setAllFileSelections(SpecFile::SPEC_FALSE); specFile.sceneFile.setAllSelections(SpecFile::SPEC_TRUE); theMainWindow->loadSpecFilesDataFiles(specFile, &transformMatrix); emit signalCloseDialogRequested(); } /** * Set the files that are checked as seleted in the spec file. */ void GuiSpecFileDialogMainWindow::setCheckedFilesAsSelected() { for (unsigned int i = 0; i < selectionItems.size(); i++) { if (selectionItems[i].checkbox->isChecked()) { (*(selectionItems[i].selected)) = SpecFile::SPEC_TRUE; } else { (*(selectionItems[i].selected)) = SpecFile::SPEC_FALSE; } } } /** * Called when set transform button is pressed. */ void GuiSpecFileDialogMainWindow::slotSetTransformPushButton() { // // Reset the transformation matrix // transformMatrix.identity(); // // Popup a dialog to choose a transformation matrix file // WuQFileDialog fd(this); fd.setDirectory(directoryName); fd.setFilter(FileFilters::getTransformationMatrixFileFilter()); fd.selectFilter(FileFilters::getTransformationMatrixFileFilter()); fd.setModal(true); fd.setFileMode(WuQFileDialog::ExistingFile); // // If the user selected a file // if (fd.exec() == WuQFileDialog::Accepted) { const QString filename = fd.selectedFiles().at(0); // // read the TransformationMatrixFile // TransformationMatrixFile tmf; try { tmf.readFile(filename); } catch (FileException& e) { QMessageBox::critical(this, "ERROR", e.whatQString()); return; } // // make sure there are matrices in the file // const int num = tmf.getNumberOfMatrices(); if (num <= 0) { QMessageBox::critical(this, "ERROR", "Matrix file contains no matrices."); return; } std::vector matrixNames; for (int i = 0; i < num; i++) { matrixNames.push_back(tmf.getTransformationMatrix(i)->getMatrixName()); } // // Popup a dialog to choose a matrix from the file // QtListBoxSelectionDialog lbsd(this, "Choose Matrix", "", matrixNames, -1); if (lbsd.exec() == QDialog::Accepted) { // // If the user chose a matrix // const int item = lbsd.getSelectedItemIndex(); transformMatrix = *(tmf.getTransformationMatrix(item)); } } } /** * Load the data files in my spec file. */ void GuiSpecFileDialogMainWindow::slotOkButton() { // // Spec file might need to be saved // writeSpecFileIfNeeded(); setCheckedFilesAsSelected(); // // If a flat coord file is selected, check to see if a cut topo is selected // if (specFile.flatCoordFile.getNumberOfFilesSelected() > 0) { if (specFile.cutTopoFile.getNumberOfFilesSelected() == 0) { if (QMessageBox::warning(this, "File Selection Warning", "You have selected a flat coordinate file but\n" "no cut topology file is selected.", (QMessageBox::Ok | QMessageBox::Cancel), QMessageBox::Cancel) == QMessageBox::Cancel) { return; } } } // // If a lobar flat coord file is selected, check to see if a lobar cut topo is selected // if (specFile.lobarFlatCoordFile.getNumberOfFilesSelected() > 0) { if (specFile.lobarCutTopoFile.getNumberOfFilesSelected() == 0) { if (QMessageBox::warning(this, "File Selection Warning", "You have selected a lobar flat coordinate file but\n" "no lobar cut topology file is selected.", (QMessageBox::Ok | QMessageBox::Cancel), QMessageBox::Cancel) == QMessageBox::Cancel) { return; } } } // // Check to see if any files that require an area color file area selected but no // area color file is selected. // if (specFile.areaColorFile.getNumberOfFilesSelected() == 0) { const int count = specFile.paintFile.getNumberOfFilesSelected() + specFile.arealEstimationFile.getNumberOfFilesSelected() + specFile.atlasFile.getNumberOfFilesSelected() + specFile.volumeProbAtlasFile.getNumberOfFilesSelected() + specFile.volumePaintFile.getNumberOfFilesSelected(); if (count > 0) { if (QMessageBox::warning(this, "File Selection Warning", "You have selected files that require an area\n" "color file but no area color file is selected.", (QMessageBox::Ok | QMessageBox::Cancel), QMessageBox::Cancel) == QMessageBox::Cancel) { return; } } } // // Check to see if any type of border file is selected, but no border color // file is selected. // if (specFile.borderColorFile.getNumberOfFilesSelected() == 0) { const int count = specFile.rawBorderFile.getNumberOfFilesSelected() + specFile.fiducialBorderFile.getNumberOfFilesSelected() + specFile.inflatedBorderFile.getNumberOfFilesSelected() + specFile.veryInflatedBorderFile.getNumberOfFilesSelected() + specFile.sphericalBorderFile.getNumberOfFilesSelected() + specFile.ellipsoidBorderFile.getNumberOfFilesSelected() + specFile.compressedBorderFile.getNumberOfFilesSelected() + specFile.flatBorderFile.getNumberOfFilesSelected() + specFile.lobarFlatBorderFile.getNumberOfFilesSelected() + specFile.unknownBorderFile.getNumberOfFilesSelected() + specFile.volumeBorderFile.getNumberOfFilesSelected() + specFile.borderProjectionFile.getNumberOfFilesSelected(); if (count > 0) { if (QMessageBox::warning(this, "File Selection Warning", "You have selected border files that require a border\n" "color file but no border color file is selected.", (QMessageBox::Ok | QMessageBox::Cancel), QMessageBox::Cancel) == QMessageBox::Cancel) { return; } } } // // See if any files requiring a cell color file are selected but no cell color file is selected // if (specFile.cellColorFile.getNumberOfFilesSelected() == 0) { const int count = specFile.cellFile.getNumberOfFilesSelected() + specFile.cellProjectionFile.getNumberOfFilesSelected(); if (count > 0) { if (QMessageBox::warning(this, "File Selection Warning", "You have selected cell files that require a cell\n" "color file but no cell color file is selected.", (QMessageBox::Ok | QMessageBox::Cancel), QMessageBox::Cancel) == QMessageBox::Cancel) { return; } } } // // See if any files requiring a cell color file are selected but no cell color file is selected // if (specFile.contourCellColorFile.getNumberOfFilesSelected() == 0) { const int count = specFile.contourCellFile.getNumberOfFilesSelected(); if (count > 0) { if (QMessageBox::warning(this, "File Selection Warning", "You have selected contour cell files that require a contour cell\n" "color file but no contour cell color file is selected.", (QMessageBox::Ok | QMessageBox::Cancel), QMessageBox::Cancel) == QMessageBox::Cancel) { return; } } } const int numFociSelected = specFile.fociFile.getNumberOfFilesSelected() + specFile.fociProjectionFile.getNumberOfFilesSelected(); // // See if any files requiring a foci color file are selected but no foci file is selected // if (specFile.fociColorFile.getNumberOfFilesSelected() == 0) { if (numFociSelected > 0) { if (QMessageBox::warning(this, "File Selection Warning", "You have selected foci files that require a foci\n" "color file but no foci color file is selected.", (QMessageBox::Ok | QMessageBox::Cancel), QMessageBox::Cancel) == QMessageBox::Cancel) { return; } } } // // Have foci selected and have study metadata but no study metadata selected // if (numFociSelected > 0) { if ((specFile.studyMetaDataFile.getNumberOfFiles() > 0) && (specFile.studyMetaDataFile.getNumberOfFilesSelected() == 0)) { if (QMessageBox::warning(this, "File Selection Warning", "You have selected foci or foci projection files.\n" "There is at least one study metadata file but it\n" "is not selected.", (QMessageBox::Ok | QMessageBox::Cancel), QMessageBox::Cancel) == QMessageBox::Cancel) { return; } } } theMainWindow->loadSpecFilesDataFiles(specFile, &transformMatrix); emit signalCloseDialogRequested(); } /** * Select all files in the dialog. */ void GuiSpecFileDialogMainWindow::slotSelectAllFiles() { for (unsigned int i = 0; i < selectionItems.size(); i++) { if (selectionItems[i].groupWidget->isVisible()) { const QString name = *(selectionItems[i].fileName); if (name.isEmpty() == false) { // // Note: "Deleted" files start with an '*' // if (name[0] != '*') { selectionItems[i].checkbox->setChecked(true); } } } } } /** * Deselect all files in the dialog. */ void GuiSpecFileDialogMainWindow::slotDeselectAllFiles() { for (unsigned int i = 0; i < selectionItems.size(); i++) { if (selectionItems[i].groupWidget->isVisible()) { const QString name = *(selectionItems[i].fileName); if (name.isEmpty() == false) { // // Note: "Deleted" files start with an '*' // if (name[0] != '*') { selectionItems[i].checkbox->setChecked(false); } } } } } /** * List the surfaces parameters. */ QGroupBox* GuiSpecFileDialogMainWindow::listSurfaceParameters(QVBoxLayout* layout) { switch (dialogMode) { case GuiSpecFileDialog::SPEC_DIALOG_MODE_OPEN_SPEC_FILE: break; case GuiSpecFileDialog::SPEC_DIALOG_MODE_OPEN_DATA_FILE: return NULL; break; case GuiSpecFileDialog::SPEC_DIALOG_MODE_VIEW_CURRENT_FILES: return NULL; break; } const int lineEditWidth = 125; // // species // QLabel* speciesLabel = new QLabel("Species"); speciesComboBox = new GuiSpeciesComboBox; savedSpecies = specFile.getSpecies(); speciesComboBox->setSelectedSpecies(savedSpecies); // // space // QLabel* spaceLabel = new QLabel("Space"); savedStereotaxicSpace = specFile.getSpace(); spaceComboBox = new GuiStereotaxicSpaceComboBox; spaceComboBox->setSelectedStereotaxicSpace(savedStereotaxicSpace); // // subject // QLabel* subjectLabel = new QLabel("Subject"); subjectLineEdit = new QLineEdit; subjectLineEdit->setFixedWidth(lineEditWidth); savedSubject = specFile.getSubject(); subjectLineEdit->setText(savedSubject); subjectLineEdit->setToolTip( "Enter the name of\n" "the subject here."); // // category // QLabel* categoryLabel = new QLabel("Category"); categoryComboBox = new GuiCategoryComboBox; savedCategory = specFile.getCategory(); categoryComboBox->setSelectedCategory(savedCategory); // // Structure // QLabel* structureLabel = new QLabel("Structure"); structureComboBox = new GuiStructureComboBox(0); savedStructure = specFile.getStructure().getType(); structureComboBox->setStructure(savedStructure); // // Comment // QPushButton* commentPushButton = new QPushButton("Comment..."); commentPushButton->setAutoDefault(false); QObject::connect(commentPushButton, SIGNAL(clicked()), this, SLOT(slotCommentPushButton())); commentPushButton->setToolTip( "Press this button to edit\n" "the spec file's comment."); savedComment = specFile.getFileComment(); QGroupBox* paramBox = new QGroupBox("Metadata"); QGridLayout* gridLayout = new QGridLayout(paramBox); gridLayout->setColumnMinimumWidth(2, 10); gridLayout->addWidget(speciesLabel, 0, 0); gridLayout->addWidget(speciesComboBox, 0, 1); gridLayout->addWidget(spaceLabel, 0, 3); gridLayout->addWidget(spaceComboBox, 0, 4); gridLayout->addWidget(subjectLabel, 1, 0); gridLayout->addWidget(subjectLineEdit, 1, 1); gridLayout->addWidget(categoryLabel, 1, 3); gridLayout->addWidget(categoryComboBox, 1, 4); gridLayout->addWidget(structureLabel, 2, 0); gridLayout->addWidget(structureComboBox, 2, 1); gridLayout->addWidget(commentPushButton, 2, 3); paramBox->setFixedSize(paramBox->sizeHint()); layout->addWidget(paramBox); return paramBox; } /** * called when Comment button is pressed. */ void GuiSpecFileDialogMainWindow::slotCommentPushButton() { QtTextEditDialog ted(this, false, true); ted.setText(specFile.getFileComment()); if (ted.exec() == QtTextEditDialog::Accepted) { specFile.setFileComment(ted.getText()); } } /** * List topology files for selection by user. */ QGroupBox* GuiSpecFileDialogMainWindow::listTopologyFiles(QVBoxLayout* layout, SpecFile& sf) { const int numFiles = sf.closedTopoFile.getNumberOfFiles() + sf.openTopoFile.getNumberOfFiles() + sf.cutTopoFile.getNumberOfFiles() + sf.lobarCutTopoFile.getNumberOfFiles() + sf.unknownTopoFile.getNumberOfFiles(); if (numFiles == 0) { return NULL; } switch (dialogMode) { case GuiSpecFileDialog::SPEC_DIALOG_MODE_OPEN_SPEC_FILE: break; case GuiSpecFileDialog::SPEC_DIALOG_MODE_OPEN_DATA_FILE: break; case GuiSpecFileDialog::SPEC_DIALOG_MODE_VIEW_CURRENT_FILES: if ((sf.closedTopoFile.getNumberOfFilesSelected() + sf.cutTopoFile.getNumberOfFilesSelected() + sf.lobarCutTopoFile.getNumberOfFilesSelected() + sf.unknownTopoFile.getNumberOfFilesSelected()) <= 0) { return NULL; } break; } QGroupBox* group = new QGroupBox("Topology Files"); QGridLayout* grid = new QGridLayout(group); int numColumns = 0; const int BUTTON_COLUMN = numColumns++; const int INFO_COLUMN = numColumns++; const int DELETE_COLUMN = numColumns++; const int TYPE_COLUMN = numColumns++; const int NAME_COLUMN = numColumns++; int rowNumber = 0; for (int i = 0; i < 5; i++) { QString typeLabel; SpecFile::Entry* fileEntryPtr = NULL; QString specFileTag; switch(i) { case 0: typeLabel = "CLOSED"; fileEntryPtr = &sf.closedTopoFile; specFileTag = SpecFile::getClosedTopoFileTag(); break; case 1: typeLabel = "OPEN"; fileEntryPtr = &sf.openTopoFile; specFileTag = SpecFile::getOpenTopoFileTag(); break; case 2: typeLabel = "CUT"; fileEntryPtr = &sf.cutTopoFile; specFileTag = SpecFile::getCutTopoFileTag(); break; case 3: typeLabel = "LOBAR CUT"; fileEntryPtr = &sf.lobarCutTopoFile; specFileTag = SpecFile::getLobarCutTopoFileTag(); break; case 4: typeLabel = "UNKNOWN"; fileEntryPtr = &sf.unknownTopoFile; specFileTag = SpecFile::getUnknownTopoFileMatchTag(); break; } for (int j = 0; j < static_cast(fileEntryPtr->getNumberOfFiles()); j++ ) { QCheckBox* cb = NULL; QPushButton* pb = NULL; switch (dialogMode) { case GuiSpecFileDialog::SPEC_DIALOG_MODE_OPEN_SPEC_FILE: cb = new QCheckBox(" "); cb->setFixedSize(cb->sizeHint()); cb->setChecked(fileEntryPtr->files[j].selected); grid->addWidget(cb, rowNumber, BUTTON_COLUMN); break; case GuiSpecFileDialog::SPEC_DIALOG_MODE_OPEN_DATA_FILE: pb = new QPushButton("Open"); pb->setAutoDefault(false); pb->setFixedSize(pb->sizeHint()); grid->addWidget(pb, rowNumber, BUTTON_COLUMN); fastOpenButtonGroup->addButton(pb, fastOpenButtonGroup->buttons().count()); break; case GuiSpecFileDialog::SPEC_DIALOG_MODE_VIEW_CURRENT_FILES: if (fileEntryPtr->files[j].selected == SpecFile::SPEC_FALSE) { continue; } break; } QPushButton* infoButton = new QPushButton("?"); infoButton->setAutoDefault(false); QSize infoButtonSize = infoButton->sizeHint(); infoButtonSize.setWidth(40); infoButton->setFixedSize(infoButtonSize); infoButton->setToolTip("View/Edit Comment Information"); grid->addWidget(infoButton, rowNumber, INFO_COLUMN); infoButtonGroup->addButton(infoButton, infoButtonGroup->buttons().count()); QPushButton* deleteButton = new QPushButton("X"); deleteButton->setAutoDefault(false); QSize deleteButtonSize = deleteButton->sizeHint(); deleteButtonSize.setWidth(40); deleteButton->setFixedSize(deleteButtonSize); deleteButton->setToolTip("Press this button\n" "to remove the file\n" "from the spec file."); grid->addWidget(deleteButton, rowNumber, DELETE_COLUMN); deleteButtonGroup->addButton(deleteButton, deleteButtonGroup->buttons().count()); QLabel* tl = new QLabel(typeLabel); tl->setFixedSize(tl->sizeHint()); grid->addWidget(tl, rowNumber, TYPE_COLUMN); QLabel* fn = new QLabel(prepareFileName(fileEntryPtr->files[j].filename)); fn->setFixedSize(fn->sizeHint()); grid->addWidget(fn, rowNumber, NAME_COLUMN); selectionItems.push_back(SelectionItem(group, cb, pb, infoButton, deleteButton, tl, fn, &fileEntryPtr->files[j].selected, specFileTag, &fileEntryPtr->files[j].filename, NULL, false)); rowNumber++; } } group->setFixedSize(group->sizeHint()); layout->addWidget(group); return group; } /** * List coordinate files for selection by user. */ QGroupBox* GuiSpecFileDialogMainWindow::listCoordinateFiles(QVBoxLayout* layout, SpecFile& sf) { const int numFiles = sf.rawCoordFile.getNumberOfFiles() + sf.fiducialCoordFile.getNumberOfFiles() + sf.inflatedCoordFile.getNumberOfFiles() + sf.veryInflatedCoordFile.getNumberOfFiles() + sf.sphericalCoordFile.getNumberOfFiles() + sf.ellipsoidCoordFile.getNumberOfFiles() + sf.compressedCoordFile.getNumberOfFiles() + sf.flatCoordFile.getNumberOfFiles() + sf.lobarFlatCoordFile.getNumberOfFiles() + sf.hullCoordFile.getNumberOfFiles() + sf.unknownCoordFile.getNumberOfFiles(); if (numFiles == 0) { return NULL; } switch (dialogMode) { case GuiSpecFileDialog::SPEC_DIALOG_MODE_OPEN_SPEC_FILE: break; case GuiSpecFileDialog::SPEC_DIALOG_MODE_OPEN_DATA_FILE: break; case GuiSpecFileDialog::SPEC_DIALOG_MODE_VIEW_CURRENT_FILES: if ((sf.rawCoordFile.getNumberOfFilesSelected() + sf.fiducialCoordFile.getNumberOfFilesSelected() + sf.inflatedCoordFile.getNumberOfFilesSelected() + sf.veryInflatedCoordFile.getNumberOfFilesSelected() + sf.sphericalCoordFile.getNumberOfFilesSelected() + sf.ellipsoidCoordFile.getNumberOfFilesSelected() + sf.compressedCoordFile.getNumberOfFilesSelected() + sf.flatCoordFile.getNumberOfFilesSelected() + sf.lobarFlatCoordFile.getNumberOfFilesSelected() + sf.hullCoordFile.getNumberOfFilesSelected() + sf.unknownCoordFile.getNumberOfFilesSelected()) <= 0) { return NULL; } break; } QGroupBox* group = new QGroupBox("Coordinate Files"); QGridLayout* grid = new QGridLayout(group); int numColumns = 0; const int BUTTON_COLUMN = numColumns++; const int INFO_COLUMN = numColumns++; const int DELETE_COLUMN = numColumns++; const int TYPE_COLUMN = numColumns++; const int NAME_COLUMN = numColumns++; int rowNumber = 0; for (int i = 0; i < 11; i++) { QString typeLabel; SpecFile::Entry* fileEntry = NULL; QString specFileTag; switch(i) { case 0: typeLabel = "RAW"; fileEntry = &sf.rawCoordFile; specFileTag = SpecFile::getRawCoordFileTag(); break; case 1: typeLabel = "FIDUCIAL"; fileEntry = &sf.fiducialCoordFile; specFileTag = SpecFile::getFiducialCoordFileTag(); break; case 2: typeLabel = "INFLATED"; fileEntry = &sf.inflatedCoordFile; specFileTag = SpecFile::getInflatedCoordFileTag(); break; case 3: typeLabel = "VERY INFLATED"; fileEntry = &sf.veryInflatedCoordFile; specFileTag = SpecFile::getVeryInflatedCoordFileTag(); break; case 4: typeLabel = "SPHERICAL"; fileEntry = &sf.sphericalCoordFile; specFileTag = SpecFile::getSphericalCoordFileTag(); break; case 5: typeLabel = "ELLIPSOID"; fileEntry = &sf.ellipsoidCoordFile; specFileTag = SpecFile::getEllipsoidCoordFileTag(); break; case 6: typeLabel = "COMP MED WALL"; fileEntry = &sf.compressedCoordFile; specFileTag = SpecFile::getCompressedCoordFileTag(); break; case 7: typeLabel = "FLAT"; fileEntry = &sf.flatCoordFile; specFileTag = SpecFile::getFlatCoordFileTag(); break; case 8: typeLabel = "LOBAR FLAT"; fileEntry = &sf.lobarFlatCoordFile; specFileTag = SpecFile::getLobarFlatCoordFileTag(); break; case 9: typeLabel = "HULL"; fileEntry = &sf.hullCoordFile; specFileTag = SpecFile::getHullCoordFileTag(); break; case 10: typeLabel = "UNKNOWN"; fileEntry = &sf.unknownCoordFile; specFileTag = SpecFile::getUnknownCoordFileMatchTag(); break; } for (int j = 0; j < static_cast(fileEntry->getNumberOfFiles()); j++ ) { QCheckBox* cb = NULL; QPushButton* pb = NULL; switch (dialogMode) { case GuiSpecFileDialog::SPEC_DIALOG_MODE_OPEN_SPEC_FILE: cb = new QCheckBox(" "); cb->setFixedSize(cb->sizeHint()); cb->setChecked(fileEntry->files[j].selected); grid->addWidget(cb, rowNumber, BUTTON_COLUMN); break; case GuiSpecFileDialog::SPEC_DIALOG_MODE_OPEN_DATA_FILE: pb = new QPushButton("Open"); pb->setAutoDefault(false); pb->setFixedSize(pb->sizeHint()); grid->addWidget(pb, rowNumber, BUTTON_COLUMN); fastOpenButtonGroup->addButton(pb, fastOpenButtonGroup->buttons().count()); break; case GuiSpecFileDialog::SPEC_DIALOG_MODE_VIEW_CURRENT_FILES: if (fileEntry->files[j].selected == SpecFile::SPEC_FALSE) { continue; } break; } QPushButton* infoButton = new QPushButton("?"); infoButton->setAutoDefault(false); QSize infoButtonSize = infoButton->sizeHint(); infoButtonSize.setWidth(40); infoButton->setFixedSize(infoButtonSize); infoButton->setToolTip("View/Edit Comment Information"); grid->addWidget(infoButton, rowNumber, INFO_COLUMN); infoButtonGroup->addButton(infoButton, infoButtonGroup->buttons().count()); QPushButton* deleteButton = new QPushButton("X"); deleteButton->setAutoDefault(false); QSize deleteButtonSize = deleteButton->sizeHint(); deleteButtonSize.setWidth(40); deleteButton->setFixedSize(deleteButtonSize); deleteButton->setToolTip("Press this button\n" "to remove the file\n" "from the spec file."); grid->addWidget(deleteButton, rowNumber, DELETE_COLUMN); deleteButtonGroup->addButton(deleteButton, deleteButtonGroup->buttons().count()); QLabel* tl = new QLabel(typeLabel); tl->setFixedSize(tl->sizeHint()); grid->addWidget(tl, rowNumber, TYPE_COLUMN); QLabel* fn = new QLabel(prepareFileName((fileEntry->files[j].filename))); fn->setFixedSize(fn->sizeHint()); grid->addWidget(fn, rowNumber, NAME_COLUMN); selectionItems.push_back(SelectionItem(group, cb, pb, infoButton, deleteButton, tl, fn, &(fileEntry->files[j].selected), specFileTag, &(fileEntry->files[j].filename), NULL, false)); rowNumber++; } } group->setFixedSize(group->sizeHint()); layout->addWidget(group); return group; } /** * List surface files for selection by user. */ QGroupBox* GuiSpecFileDialogMainWindow::listSurfaceFiles(QVBoxLayout* layout, SpecFile& sf) { const int numFiles = sf.rawSurfaceFile.getNumberOfFiles() + sf.fiducialSurfaceFile.getNumberOfFiles() + sf.inflatedSurfaceFile.getNumberOfFiles() + sf.veryInflatedSurfaceFile.getNumberOfFiles() + sf.sphericalSurfaceFile.getNumberOfFiles() + sf.ellipsoidSurfaceFile.getNumberOfFiles() + sf.compressedSurfaceFile.getNumberOfFiles() + sf.flatSurfaceFile.getNumberOfFiles() + sf.lobarFlatSurfaceFile.getNumberOfFiles() + sf.hullSurfaceFile.getNumberOfFiles() + sf.unknownSurfaceFile.getNumberOfFiles(); if (numFiles == 0) { return NULL; } switch (dialogMode) { case GuiSpecFileDialog::SPEC_DIALOG_MODE_OPEN_SPEC_FILE: break; case GuiSpecFileDialog::SPEC_DIALOG_MODE_OPEN_DATA_FILE: break; case GuiSpecFileDialog::SPEC_DIALOG_MODE_VIEW_CURRENT_FILES: if ((sf.rawSurfaceFile.getNumberOfFilesSelected() + sf.fiducialSurfaceFile.getNumberOfFilesSelected() + sf.inflatedSurfaceFile.getNumberOfFilesSelected() + sf.veryInflatedSurfaceFile.getNumberOfFilesSelected() + sf.sphericalSurfaceFile.getNumberOfFilesSelected() + sf.ellipsoidSurfaceFile.getNumberOfFilesSelected() + sf.compressedSurfaceFile.getNumberOfFilesSelected() + sf.flatSurfaceFile.getNumberOfFilesSelected() + sf.lobarFlatSurfaceFile.getNumberOfFilesSelected() + sf.hullSurfaceFile.getNumberOfFilesSelected() + sf.unknownSurfaceFile.getNumberOfFilesSelected()) <= 0) { return NULL; } break; } QGroupBox* group = new QGroupBox("Surface Files"); QGridLayout* grid = new QGridLayout(group); int numColumns = 0; const int BUTTON_COLUMN = numColumns++; const int INFO_COLUMN = numColumns++; const int DELETE_COLUMN = numColumns++; const int TYPE_COLUMN = numColumns++; const int NAME_COLUMN = numColumns++; int rowNumber = 0; for (int i = 0; i < 11; i++) { QString typeLabel; SpecFile::Entry* fileEntry = NULL; QString specFileTag; switch(i) { case 0: typeLabel = "RAW"; fileEntry = &sf.rawSurfaceFile; specFileTag = SpecFile::getRawSurfaceFileTag(); break; case 1: typeLabel = "FIDUCIAL"; fileEntry = &sf.fiducialSurfaceFile; specFileTag = SpecFile::getFiducialSurfaceFileTag(); break; case 2: typeLabel = "INFLATED"; fileEntry = &sf.inflatedSurfaceFile; specFileTag = SpecFile::getInflatedSurfaceFileTag(); break; case 3: typeLabel = "VERY INFLATED"; fileEntry = &sf.veryInflatedSurfaceFile; specFileTag = SpecFile::getVeryInflatedSurfaceFileTag(); break; case 4: typeLabel = "SPHERICAL"; fileEntry = &sf.sphericalSurfaceFile; specFileTag = SpecFile::getSphericalSurfaceFileTag(); break; case 5: typeLabel = "ELLIPSOID"; fileEntry = &sf.ellipsoidSurfaceFile; specFileTag = SpecFile::getEllipsoidSurfaceFileTag(); break; case 6: typeLabel = "COMP MED WALL"; fileEntry = &sf.compressedSurfaceFile; specFileTag = SpecFile::getCompressedSurfaceFileTag(); break; case 7: typeLabel = "FLAT"; fileEntry = &sf.flatSurfaceFile; specFileTag = SpecFile::getFlatSurfaceFileTag(); break; case 8: typeLabel = "LOBAR FLAT"; fileEntry = &sf.lobarFlatSurfaceFile; specFileTag = SpecFile::getLobarFlatSurfaceFileTag(); break; case 9: typeLabel = "HULL"; fileEntry = &sf.hullSurfaceFile; specFileTag = SpecFile::getHullSurfaceFileTag(); break; case 10: typeLabel = "UNKNOWN"; fileEntry = &sf.unknownSurfaceFile; specFileTag = SpecFile::getUnknownSurfaceFileMatchTag(); break; } for (int j = 0; j < static_cast(fileEntry->getNumberOfFiles()); j++ ) { QCheckBox* cb = NULL; QPushButton* pb = NULL; switch (dialogMode) { case GuiSpecFileDialog::SPEC_DIALOG_MODE_OPEN_SPEC_FILE: cb = new QCheckBox(" "); cb->setFixedSize(cb->sizeHint()); cb->setChecked(fileEntry->files[j].selected); grid->addWidget(cb, rowNumber, BUTTON_COLUMN); break; case GuiSpecFileDialog::SPEC_DIALOG_MODE_OPEN_DATA_FILE: pb = new QPushButton("Open"); pb->setAutoDefault(false); pb->setFixedSize(pb->sizeHint()); grid->addWidget(pb, rowNumber, BUTTON_COLUMN); fastOpenButtonGroup->addButton(pb, fastOpenButtonGroup->buttons().count()); break; case GuiSpecFileDialog::SPEC_DIALOG_MODE_VIEW_CURRENT_FILES: if (fileEntry->files[j].selected == SpecFile::SPEC_FALSE) { continue; } break; } QPushButton* infoButton = new QPushButton("?"); infoButton->setAutoDefault(false); QSize infoButtonSize = infoButton->sizeHint(); infoButtonSize.setWidth(40); infoButton->setFixedSize(infoButtonSize); infoButton->setToolTip("View/Edit Comment Information"); grid->addWidget(infoButton, rowNumber, INFO_COLUMN); infoButtonGroup->addButton(infoButton, infoButtonGroup->buttons().count()); QPushButton* deleteButton = new QPushButton("X"); deleteButton->setAutoDefault(false); QSize deleteButtonSize = deleteButton->sizeHint(); deleteButtonSize.setWidth(40); deleteButton->setFixedSize(deleteButtonSize); deleteButton->setToolTip("Press this button\n" "to remove the file\n" "from the spec file."); grid->addWidget(deleteButton, rowNumber, DELETE_COLUMN); deleteButtonGroup->addButton(deleteButton, deleteButtonGroup->buttons().count()); QLabel* tl = new QLabel(typeLabel); tl->setFixedSize(tl->sizeHint()); grid->addWidget(tl, rowNumber, TYPE_COLUMN); QLabel* fn = new QLabel(prepareFileName((fileEntry->files[j].filename))); fn->setFixedSize(fn->sizeHint()); grid->addWidget(fn, rowNumber, NAME_COLUMN); selectionItems.push_back(SelectionItem(group, cb, pb, infoButton, deleteButton, tl, fn, &(fileEntry->files[j].selected), specFileTag, &(fileEntry->files[j].filename), NULL, false)); rowNumber++; } } group->setFixedSize(group->sizeHint()); layout->addWidget(group); return group; } /** * List border files for selection by user. */ QGroupBox* GuiSpecFileDialogMainWindow::listBorderFiles(QVBoxLayout* layout, SpecFile& sf) { const int numFiles = sf.rawBorderFile.getNumberOfFiles() + sf.fiducialBorderFile.getNumberOfFiles() + sf.inflatedBorderFile.getNumberOfFiles() + sf.veryInflatedBorderFile.getNumberOfFiles() + sf.sphericalBorderFile.getNumberOfFiles() + sf.ellipsoidBorderFile.getNumberOfFiles() + sf.compressedBorderFile.getNumberOfFiles() + sf.flatBorderFile.getNumberOfFiles() + sf.lobarFlatBorderFile.getNumberOfFiles() + sf.hullBorderFile.getNumberOfFiles() + sf.unknownBorderFile.getNumberOfFiles() + sf.volumeBorderFile.getNumberOfFiles(); if (numFiles == 0) { return NULL; } QGroupBox* group = new QGroupBox("Border Files"); QGridLayout* grid = new QGridLayout(group); int numColumns = 0; const int BUTTON_COLUMN = numColumns++; const int INFO_COLUMN = numColumns++; const int DELETE_COLUMN = numColumns++; const int TYPE_COLUMN = numColumns++; const int NAME_COLUMN = numColumns++; int rowNumber = 0; for (int i = 0; i < 12; i++) { QString typeLabel; SpecFile::Entry* fileEntry = NULL; QString specFileTag; switch(i) { case 0: typeLabel = "RAW"; fileEntry = &sf.rawBorderFile; specFileTag = SpecFile::getRawBorderFileTag(); break; case 1: typeLabel = "FIDUCIAL"; fileEntry = &sf.fiducialBorderFile; specFileTag = SpecFile::getFiducialBorderFileTag(); break; case 2: typeLabel = "INFLATED"; fileEntry = &sf.inflatedBorderFile; specFileTag = SpecFile::getInflatedBorderFileTag(); break; case 3: typeLabel = "VERY INFLATED"; fileEntry = &sf.veryInflatedBorderFile; specFileTag = SpecFile::getVeryInflatedBorderFileTag(); break; case 4: typeLabel = "SPHERICAL"; fileEntry = &sf.sphericalBorderFile; specFileTag = SpecFile::getSphericalBorderFileTag(); break; case 5: typeLabel = "ELLIPSOID"; fileEntry = &sf.ellipsoidBorderFile; specFileTag = SpecFile::getEllipsoidBorderFileTag(); break; case 6: typeLabel = "COMP MED WALL"; fileEntry = &sf.compressedBorderFile; specFileTag = SpecFile::getCompressedBorderFileTag(); break; case 7: typeLabel = "FLAT"; fileEntry = &sf.flatBorderFile; specFileTag = SpecFile::getFlatBorderFileTag(); break; case 8: typeLabel = "LOBAR FLAT"; fileEntry = &sf.lobarFlatBorderFile; specFileTag = SpecFile::getLobarFlatBorderFileTag(); break; case 9: typeLabel = "HULL"; fileEntry = &sf.hullBorderFile; specFileTag = SpecFile::getHullBorderFileTag(); break; case 10: typeLabel = "UNKNOWN"; fileEntry = &sf.unknownBorderFile; specFileTag = SpecFile::getUnknownBorderFileMatchTag(); break; case 11: typeLabel = "VOLUME"; fileEntry = &sf.volumeBorderFile; specFileTag = SpecFile::getVolumeBorderFileTag(); } for (int j = 0; j < static_cast(fileEntry->getNumberOfFiles()); j++ ) { QCheckBox* cb = NULL; QPushButton* pb = NULL; switch (dialogMode) { case GuiSpecFileDialog::SPEC_DIALOG_MODE_OPEN_SPEC_FILE: cb = new QCheckBox(" "); cb->setFixedSize(cb->sizeHint()); cb->setChecked(fileEntry->files[j].selected); grid->addWidget(cb, rowNumber, BUTTON_COLUMN); break; case GuiSpecFileDialog::SPEC_DIALOG_MODE_OPEN_DATA_FILE: pb = new QPushButton("Open"); pb->setAutoDefault(false); pb->setFixedSize(pb->sizeHint()); grid->addWidget(pb, rowNumber, BUTTON_COLUMN); fastOpenButtonGroup->addButton(pb, fastOpenButtonGroup->buttons().count()); break; case GuiSpecFileDialog::SPEC_DIALOG_MODE_VIEW_CURRENT_FILES: if (fileEntry->files[j].selected == SpecFile::SPEC_FALSE) { continue; } break; } QPushButton* infoButton = new QPushButton("?"); infoButton->setAutoDefault(false); QSize infoButtonSize = infoButton->sizeHint(); infoButtonSize.setWidth(40); infoButton->setFixedSize(infoButtonSize); infoButton->setToolTip("View/Edit Comment Information"); grid->addWidget(infoButton, rowNumber, INFO_COLUMN); infoButtonGroup->addButton(infoButton, infoButtonGroup->buttons().count()); QPushButton* deleteButton = new QPushButton("X"); deleteButton->setAutoDefault(false); QSize deleteButtonSize = deleteButton->sizeHint(); deleteButtonSize.setWidth(40); deleteButton->setFixedSize(deleteButtonSize); deleteButton->setToolTip("Remove File From Spec File"); grid->addWidget(deleteButton, rowNumber, DELETE_COLUMN); deleteButtonGroup->addButton(deleteButton, deleteButtonGroup->buttons().count()); QLabel* tl = new QLabel(typeLabel); tl->setFixedSize(tl->sizeHint()); grid->addWidget(tl, rowNumber, TYPE_COLUMN); QLabel* fn = new QLabel(prepareFileName(fileEntry->files[j].filename)); fn->setFixedSize(fn->sizeHint()); grid->addWidget(fn, rowNumber, NAME_COLUMN); selectionItems.push_back(SelectionItem(group, cb, pb, infoButton, deleteButton, tl, fn, &(fileEntry->files[j].selected), specFileTag, &(fileEntry->files[j].filename), NULL, false)); rowNumber++; } } group->setFixedSize(group->sizeHint()); layout->addWidget(group); return group; } /** * List files for selection by the user. */ QGroupBox* GuiSpecFileDialogMainWindow::listFiles(QVBoxLayout* layout, const QString& title, AbstractFile* dataFile, const QString& specFileTag, SpecFile::Entry& dataFileEntry, const bool allowCommentEditing, const bool volumeFileFlag) { const int numRows = static_cast(dataFileEntry.getNumberOfFiles()); if (numRows == 0) { return NULL; } switch (dialogMode) { case GuiSpecFileDialog::SPEC_DIALOG_MODE_OPEN_SPEC_FILE: break; case GuiSpecFileDialog::SPEC_DIALOG_MODE_OPEN_DATA_FILE: break; case GuiSpecFileDialog::SPEC_DIALOG_MODE_VIEW_CURRENT_FILES: if (dataFileEntry.getNumberOfFilesSelected() <= 0) { return NULL; } break; } QGroupBox* group = new QGroupBox(title); QGridLayout* grid = new QGridLayout(group); int numColumns = 0; const int BUTTON_COLUMN = numColumns++; const int INFO_COLUMN = numColumns++; const int DELETE_COLUMN = numColumns++; const int NAME_COLUMN = numColumns++; for (int i = 0; i < numRows; i++) { QCheckBox* cb = NULL; QPushButton* pb = NULL; switch (dialogMode) { case GuiSpecFileDialog::SPEC_DIALOG_MODE_OPEN_SPEC_FILE: cb = new QCheckBox(" "); cb->setFixedSize(cb->sizeHint()); cb->setChecked(dataFileEntry.files[i].selected); grid->addWidget(cb, i, BUTTON_COLUMN); break; case GuiSpecFileDialog::SPEC_DIALOG_MODE_OPEN_DATA_FILE: pb = new QPushButton("Open"); pb->setAutoDefault(false); pb->setFixedSize(pb->sizeHint()); grid->addWidget(pb, i, BUTTON_COLUMN); fastOpenButtonGroup->addButton(pb, fastOpenButtonGroup->buttons().count()); break; case GuiSpecFileDialog::SPEC_DIALOG_MODE_VIEW_CURRENT_FILES: if (dataFileEntry.files[i].selected == SpecFile::SPEC_FALSE) { continue; } break; } QPushButton* infoButton = NULL; infoButton = new QPushButton("?"); infoButton->setAutoDefault(false); QSize infoButtonSize = infoButton->sizeHint(); infoButtonSize.setWidth(40); infoButton->setFixedSize(infoButtonSize); infoButton->setToolTip("View/Edit Comment Information"); grid->addWidget(infoButton, i, INFO_COLUMN); infoButtonGroup->addButton(infoButton, infoButtonGroup->buttons().count()); if (allowCommentEditing == false) { infoButton->setEnabled(false); } QPushButton* deleteButton = new QPushButton("X"); deleteButton->setAutoDefault(false); QSize deleteButtonSize = deleteButton->sizeHint(); deleteButtonSize.setWidth(40); deleteButton->setFixedSize(deleteButtonSize); deleteButton->setToolTip("Remove File From Spec File"); grid->addWidget(deleteButton, i, DELETE_COLUMN); deleteButtonGroup->addButton(deleteButton, deleteButtonGroup->buttons().count()); QLabel* fn = new QLabel(prepareFileName(dataFileEntry.files[i].filename)); fn->setFixedSize(fn->sizeHint()); grid->addWidget(fn, i, NAME_COLUMN); selectionItems.push_back(SelectionItem(group, cb, pb, infoButton, deleteButton, NULL, fn, &dataFileEntry.files[i].selected, specFileTag, &dataFileEntry.files[i].filename, dataFile, volumeFileFlag)); } group->setFixedSize(group->sizeHint()); layout->addWidget(group); return group; } /** * Change the file name so that the path is listed after the file. * Ex: "/usr/local/file.data" becomes "file.data (/usr/local)" */ QString GuiSpecFileDialogMainWindow::prepareFileName(const QString& nameIn) { QString name; if (checkForMissingFiles) { if (QFile::exists(nameIn) == false) { name.append("(FILE NOT FOUND) "); } } name.append(FileUtilities::rearrangeFileName(nameIn)); return name; } /** * Called when an info button is pressed */ void GuiSpecFileDialogMainWindow::infoButtonGroupSlot(int buttonNumber) { if (buttonNumber < static_cast(selectionItems.size())) { QString fileName(*(selectionItems[buttonNumber].fileName)); const bool volumeFileFlag = selectionItems[buttonNumber].volumeFlag; if (fileName.length() > 0) { switch (dialogMode) { case GuiSpecFileDialog::SPEC_DIALOG_MODE_OPEN_SPEC_FILE: if (fileName[0] != '/') { QString s(specFile.getFileNamePath()); if (s.isEmpty() == false) { s.append("/"); } s.append(fileName); fileName = s; } break; case GuiSpecFileDialog::SPEC_DIALOG_MODE_OPEN_DATA_FILE: break; case GuiSpecFileDialog::SPEC_DIALOG_MODE_VIEW_CURRENT_FILES: break; } GuiDataFileCommentDialog* dfcd = new GuiDataFileCommentDialog(this, fileName, volumeFileFlag); dfcd->show(); } } } /** * Called when a delete button is pressed */ void GuiSpecFileDialogMainWindow::deleteButtonGroupSlot(int buttonNumber) { if (buttonNumber < static_cast(selectionItems.size())) { SelectionItem& s = selectionItems[buttonNumber]; QString fileName(*(s.fileName)); if (fileName.isEmpty()) { return; } // // If filename was already "removed" but user has pressed the "X" button again // it means the user wants to restore the file. A "removed" file name starts // with a "*". // const bool restoringFile = (fileName[0] == '*'); if (s.checkbox != NULL) { s.checkbox->setEnabled(restoringFile); s.checkbox->setChecked(false); } if (s.pushbutton != NULL) s.pushbutton->setEnabled(restoringFile); if (s.infobutton != NULL) s.infobutton->setEnabled(restoringFile); if (s.typelabel != NULL) s.typelabel->setEnabled(restoringFile); if (s.namelabel != NULL) s.namelabel->setEnabled(restoringFile); // // Set item deselected. // *(s.selected) = SpecFile::SPEC_FALSE; if (restoringFile) { // // Remove the first character which is a "*" // (*(s.fileName)) = fileName.mid(1); // // Update the tooltip // s.deletebutton->setToolTip("Press this button\n" "to remove the file\n" "from the spec file."); } else { // // Prefix the file name with a "*" which tells the spec file class // not to write it to the spec file. // QString newName("*"); newName.append(fileName); (*(s.fileName)) = newName; // // Update the tooltip // s.deletebutton->setToolTip("Press this button\n" "to restore the file\n" "to the spec file."); } // // Spec file has been modified // specFileNeedsToBeWritten = true; } } /** * Called when a fast open button is pressed. */ void GuiSpecFileDialogMainWindow::fastOpenButtonSlot(int buttonNumber) { bool error = false; BrainSet* bs = theMainWindow->getBrainSet(); if (buttonNumber < static_cast(selectionItems.size())) { SelectionItem& s = selectionItems[buttonNumber]; // // Coord/topo always append. Ask about others unless atlas file. // bool askFlag = true; bool appendFile = true; if ((s.specFileTag == SpecFile::getRawCoordFileTag()) || (s.specFileTag == SpecFile::getFiducialCoordFileTag()) || (s.specFileTag == SpecFile::getInflatedCoordFileTag()) || (s.specFileTag == SpecFile::getVeryInflatedCoordFileTag()) || (s.specFileTag == SpecFile::getSphericalCoordFileTag()) || (s.specFileTag == SpecFile::getEllipsoidCoordFileTag()) || (s.specFileTag == SpecFile::getCompressedCoordFileTag()) || (s.specFileTag == SpecFile::getFlatCoordFileTag()) || (s.specFileTag == SpecFile::getLobarFlatCoordFileTag()) || (s.specFileTag == SpecFile::getUnknownCoordFileMatchTag()) || (s.specFileTag == SpecFile::getClosedTopoFileTag()) || (s.specFileTag == SpecFile::getOpenTopoFileTag()) || (s.specFileTag == SpecFile::getCutTopoFileTag()) || (s.specFileTag == SpecFile::getLobarCutTopoFileTag()) || (s.specFileTag == SpecFile::getUnknownTopoFileMatchTag())) { askFlag = false; } // // Paint, Metric, and Surface shape get special dialog for appending // else if ((s.specFileTag == SpecFile::getArealEstimationFileTag()) || (s.specFileTag == SpecFile::getPaintFileTag()) || (s.specFileTag == SpecFile::getMetricFileTag()) || (s.specFileTag == SpecFile::getSurfaceShapeFileTag())) { askFlag = false; } else if (s.specFileTag == SpecFile::getAtlasFileTag()) { askFlag = false; appendFile = false; } else { // // Only ask if the data file contains data // AbstractFile* dataFile = s.dataFile; if (dataFile != NULL) { askFlag = (dataFile->empty() == false); } else if ((s.specFileTag == SpecFile::getBorderProjectionFileTag()) || (s.specFileTag.indexOf(SpecFile::getUnknownBorderFileMatchTag()) >= 0)) { BrainModelBorderSet* bmbs = bs->getBorderSet(); askFlag = (bmbs->getNumberOfBorders()); } else if (s.specFileTag == SpecFile::getCerebralHullFileTag()) { askFlag = (bs->getCerebralHullFileName().isEmpty() == false); } else if (s.specFileTag == SpecFile::getDeformationMapFileTag()) { askFlag = (bs->getDeformationMapFileName().isEmpty() == false); } else if (s.specFileTag == SpecFile::getImageFileTag()) { askFlag = (bs->getNumberOfImageFiles() > 0); } else if (s.specFileTag == SpecFile::getTransformationDataFileTag()) { askFlag = (bs->getNumberOfTransformationDataFiles() > 0); } else if (s.specFileTag == SpecFile::getVolumeAnatomyFileTag()) { askFlag = (bs->getNumberOfVolumeAnatomyFiles() > 0); } else if (s.specFileTag == SpecFile::getVolumeFunctionalFileTag()) { askFlag = (bs->getNumberOfVolumeFunctionalFiles() > 0); } else if (s.specFileTag == SpecFile::getVolumePaintFileTag()) { askFlag = (bs->getNumberOfVolumePaintFiles() > 0); } else if (s.specFileTag == SpecFile::getVolumeProbAtlasFileTag()) { askFlag = (bs->getNumberOfVolumeProbAtlasFiles() > 0); } else if (s.specFileTag == SpecFile::getVolumeRgbFileTag()) { askFlag = (bs->getNumberOfVolumeRgbFiles() > 0); } else if (s.specFileTag == SpecFile::getVolumeSegmentationFileTag()) { askFlag = (bs->getNumberOfVolumeSegmentationFiles() > 0); } else if (s.specFileTag == SpecFile::getVolumeVectorFileTag()) { askFlag = (bs->getNumberOfVolumeVectorFiles() > 0); } } if (askFlag) { QMessageBox msgBox(this); msgBox.setWindowTitle("Append or Replace"); msgBox.setText("Append to currently loaded file ?"); QPushButton* appendPushButton = msgBox.addButton("Append", QMessageBox::AcceptRole); QPushButton* replacePushButton = msgBox.addButton("Replace", QMessageBox::AcceptRole); msgBox.addButton("Cancel", QMessageBox::RejectRole); msgBox.exec(); if (msgBox.clickedButton() == appendPushButton) { appendFile = true; } else if (msgBox.clickedButton() == replacePushButton) { appendFile = false; } else { return; } } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); QString msg1; bool relatedFileWarning; error = GuiDataFileOpenDialog::openDataFile(this, s.specFileTag, *(s.fileName), appendFile, true, msg1, relatedFileWarning); if (error) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "Error Opening File", msg1); return; } else if (relatedFileWarning) { QApplication::restoreOverrideCursor(); return; } } QApplication::restoreOverrideCursor(); emit signalCloseDialogRequested(); } caret-5.6.4~dfsg.1.orig/caret/GuiSpecFileCreationDialog.h0000664000175000017500000000465411572067322023005 0ustar michaelmichael #ifndef __GUI_SPEC_FILE_CREATION_DIALOG_H__ #define __GUI_SPEC_FILE_CREATION_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "WuQDialog.h" class GuiCategoryComboBox; class GuiSpeciesComboBox; class GuiStereotaxicSpaceComboBox; class GuiStructureComboBox; class QLineEdit; class QTextEdit; /// Dialog for creating a spec file class GuiSpecFileCreationDialog : public WuQDialog { Q_OBJECT public: // constructor (dialog is modal) GuiSpecFileCreationDialog(QDialog* parent); // destructor ~GuiSpecFileCreationDialog(); // get the name of the created spec file QString getCreatedSpecFileName() const { return createdSpecFileName; } protected slots: // called to set directory void slotDirectoryPushButton(); protected: // called when OK or Cancel button pressed void done(int r); // directory line edit QLineEdit* directoryLineEdit; // species combo box GuiSpeciesComboBox* speciesComboBox; // subject line edit QLineEdit* subjectLineEdit; // space combo box GuiStereotaxicSpaceComboBox* stereotaxicSpaceComboBox; // category combo box GuiCategoryComboBox* categoryComboBox; // structure combo box GuiStructureComboBox* structureComboBox; // description line edit QLineEdit* descriptionLineEdit; // name of the created spec file QString createdSpecFileName; // comment text edit QTextEdit* commentTextEdit; }; #endif // __GUI_SPEC_FILE_CREATION_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiSpecFileCreationDialog.cxx0000664000175000017500000002676111572067322023363 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include "WuQFileDialog.h" #include #include #include #include #include #include #include #include #include #include #include "BrainSet.h" #include "GuiCategoryComboBox.h" #include "GuiSpeciesComboBox.h" #include "GuiStereotaxicSpaceComboBox.h" #include "GuiStructureComboBox.h" #include "GuiMainWindow.h" #include "GuiSpecFileCreationDialog.h" #include "QtListBoxSelectionDialog.h" #include "QtUtilities.h" #include "Species.h" #include "SpecFile.h" #include "StereotaxicSpace.h" #include "StringUtilities.h" #include "global_variables.h" /** * constructor (dialog is modal). */ GuiSpecFileCreationDialog::GuiSpecFileCreationDialog(QDialog* parent) : WuQDialog(parent) { setModal(true); const int lineEditWidth = 250; setWindowTitle("Create Spec File"); // // Layout for dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setSpacing(3); dialogLayout->setMargin(3); // // Directory push button // QPushButton* directoryButton = new QPushButton("Select..."); directoryButton->setAutoDefault(false); directoryButton->setToolTip( "Press this button to set the directory\n" "in which the new spec file will be placed."); QObject::connect(directoryButton, SIGNAL(clicked()), this, SLOT(slotDirectoryPushButton())); // // Directory line edit // directoryLineEdit = new QLineEdit; directoryLineEdit->setText(QDir::currentPath()); directoryLineEdit->setReadOnly(true); directoryLineEdit->setMinimumWidth(lineEditWidth); // // Group box and layout for directory // QGroupBox* directoryGroup = new QGroupBox("Directory"); dialogLayout->addWidget(directoryGroup); QHBoxLayout* directoryLayout = new QHBoxLayout(directoryGroup); directoryLayout->addWidget(directoryButton); directoryLayout->addWidget(directoryLineEdit); // // Species name line edit // QLabel* speciesLabel = new QLabel("Species"); speciesComboBox = new GuiSpeciesComboBox; Species species = theMainWindow->getBrainSet()->getSpecies(); if (species.isValid() == false) { species.setUsingType(Species::TYPE_HUMAN); } speciesComboBox->setSelectedSpecies(species); // // case name line edit // QLabel* subjectLabel = new QLabel("Subject"); subjectLineEdit = new QLineEdit; subjectLineEdit->setMinimumWidth(lineEditWidth); subjectLineEdit->setText(theMainWindow->getBrainSet()->getSubject()); subjectLineEdit->setToolTip( "Enter the name of\n" "the subject here."); // // structure combo box and line edit // QLabel* structureLabel = new QLabel("Structure"); structureComboBox = new GuiStructureComboBox(0, "structureComboBox", true); structureComboBox->setStructure(theMainWindow->getBrainSet()->getStructure().getType()); // // space // QLabel* spaceLabel = new QLabel("Space"); stereotaxicSpaceComboBox = new GuiStereotaxicSpaceComboBox; stereotaxicSpaceComboBox->setSelectedStereotaxicSpace(theMainWindow->getBrainSet()->getStereotaxicSpace()); // // Category line edit // QLabel* categoryLabel = new QLabel("Category"); categoryComboBox = new GuiCategoryComboBox; // // Group box for spec info // QGroupBox* specInfoGroupBox = new QGroupBox("Subject Information"); dialogLayout->addWidget(specInfoGroupBox); QGridLayout* specInfoLayout = new QGridLayout(specInfoGroupBox); int rowNum = 0; specInfoLayout->addWidget(speciesLabel, rowNum, 0); specInfoLayout->addWidget(speciesComboBox, rowNum, 1); rowNum++; specInfoLayout->addWidget(subjectLabel, rowNum, 0); specInfoLayout->addWidget(subjectLineEdit, rowNum, 1); rowNum++; specInfoLayout->addWidget(structureLabel, rowNum, 0); specInfoLayout->addWidget(structureComboBox, rowNum, 1); rowNum++; specInfoLayout->addWidget(spaceLabel, rowNum, 0); specInfoLayout->addWidget(stereotaxicSpaceComboBox, rowNum, 1); rowNum++; specInfoLayout->addWidget(categoryLabel, rowNum, 0); specInfoLayout->addWidget(categoryComboBox, rowNum, 1); rowNum++; // // Comment text edit // commentTextEdit = new QTextEdit; QGroupBox* commentGroupBox = new QGroupBox("Comment"); dialogLayout->addWidget(commentGroupBox); QVBoxLayout* commentGroupLayout = new QVBoxLayout(commentGroupBox); commentGroupLayout->addWidget(commentTextEdit); // // Layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(3); dialogLayout->addLayout(buttonsLayout); // // OK button // QPushButton* okButton = new QPushButton("OK"); buttonsLayout->addWidget(okButton); okButton->setAutoDefault(true); QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); // // Cancel Button // QPushButton* cancelButton = new QPushButton("Cancel"); buttonsLayout->addWidget(cancelButton); QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); QtUtilities::makeButtonsSameSize(okButton, cancelButton); } /** * destructor. */ GuiSpecFileCreationDialog::~GuiSpecFileCreationDialog() { } /** * called to set directory. */ void GuiSpecFileCreationDialog::slotDirectoryPushButton() { WuQFileDialog fd(this); fd.setModal(true); fd.setFileMode(WuQFileDialog::DirectoryOnly); fd.setWindowTitle("Choose Directory"); fd.setDirectory(QDir::currentPath()); fd.setAcceptMode(WuQFileDialog::AcceptOpen); if (fd.exec() == QDialog::Accepted) { const QString ds = fd.directory().absolutePath(); directoryLineEdit->setText(ds); } } /** * called when OK or Cancel button pressed. */ void GuiSpecFileCreationDialog::done(int r) { if (r == QDialog::Accepted) { QString msg; QString directory = directoryLineEdit->text(); QDir dir(directory); if (dir.exists() == false) { if (dir.mkdir(".") == false) { QMessageBox::critical(this, "ERROR", "Unable to create spec file directory."); return; } } const Structure::STRUCTURE_TYPE hem = structureComboBox->getSelectedStructure(); if (hem == Structure::STRUCTURE_TYPE_INVALID) { msg.append("Structure type of INVALID is not allowed.\n"); } QString hemString = Structure::convertTypeToAbbreviatedString(hem); /* switch (hem) { case Structure::STRUCTURE_TYPE_INVALID: hemString = "U"); break; case Structure::STRUCTURE_TYPE_CORTEX_LEFT: hemString = "L"); break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT: hemString = "R"); break; case Structure::STRUCTURE_TYPE_CEREBELLUM: hemString = "LR"); break; } */ const Species species = speciesComboBox->getSelectedSpecies(); if (species.isValid() == false) { msg.append("Species is invalid.\n"); } QString subject = subjectLineEdit->text(); if (subject.isEmpty()) { msg.append("No Subject was entered.\n"); } if (msg.isEmpty() == false) { QMessageBox::critical(this, "ERROR", msg); return; } subject = StringUtilities::replace(subject, ' ', '_'); std::ostringstream str; str << species.getName().toAscii().constData() << "." << subject.toAscii().constData() << "." << hemString.toAscii().constData(); if (theMainWindow->getBrainSet()->getNumberOfNodes() > 0) { str << "." << theMainWindow->getBrainSet()->getNumberOfNodes(); } str << SpecFile::getSpecFileExtension().toAscii().constData(); QString specFileName = str.str().c_str(); bool valid = false; QApplication::beep(); QString qName = QInputDialog::getText(this, "Spec File Name", "Name of Spec File that will be created. You may change the name.", QLineEdit::Normal, specFileName, &valid); specFileName = ""; if (valid && !qName.isEmpty()) { specFileName = qName; } if (valid) { if (specFileName.isEmpty()) { QMessageBox::critical(this, "ERROR", "Spec File name is empty."); return; } // // Set to the user entered directory // QDir::setCurrent(directory); // // Try to read the spec file but ignore read errors since it might not exist // SpecFile sf; try { sf.readFile(specFileName); } catch (FileException&) { } // // Comment // sf.setFileComment(commentTextEdit->toPlainText()); // // Name with path that can be requested by creator // createdSpecFileName = directory; if (createdSpecFileName.isEmpty() == false) { createdSpecFileName.append("/"); } createdSpecFileName.append(specFileName); // // Set brain parameters // theMainWindow->getBrainSet()->setStereotaxicSpace(stereotaxicSpaceComboBox->getSelectedStereotaxicSpace()); theMainWindow->getBrainSet()->setSubject(subject); theMainWindow->getBrainSet()->setSpecies(species); theMainWindow->getBrainSet()->setStructure(hem); theMainWindow->getBrainSet()->setSpecFileName(createdSpecFileName); // // Set spec file parameters // sf.setSpecies(species); sf.setSubject(subject); sf.setStructure(Structure::convertTypeToString(hem)); sf.setSpace(stereotaxicSpaceComboBox->getSelectedStereotaxicSpace()); sf.setCategory(categoryComboBox->getSelectedCategory().getName()); // // Write the spec file // try { sf.writeFile(specFileName); } catch (FileException& e) { QString s("Unable to create spec file.\n"); s.append(e.whatQString()); QMessageBox::critical(this, "ERROR", s); createdSpecFileName = ""; return; } } else { return; } } QDialog::done(r); } caret-5.6.4~dfsg.1.orig/caret/GuiSpecAndSceneFileCreationDialog.h0000664000175000017500000000372411572067322024403 0ustar michaelmichael #ifndef __GUI_SPEC_AND_SCENE_FILE_CREATION_DIALOG_H__ #define __GUI_SPEC_AND_SCENE_FILE_CREATION_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "WuQDialog.h" class BrainSet; class QLineEdit; /// dialog for creating a spec and scene files from a group of scenes class GuiSpecAndSceneFileCreationDialog : public WuQDialog { Q_OBJECT public: // constructor GuiSpecAndSceneFileCreationDialog(QWidget* parent, BrainSet* brainSet, const std::vector& sceneIndices); // destructor ~GuiSpecAndSceneFileCreationDialog(); protected: // called when OK/Cancel button pressed void done(int r); /// line edit for spec file name QLineEdit* specFileNameLineEdit; /// line edit for scene file name QLineEdit* sceneFileNameLineEdit; /// the brain set BrainSet* brainSet; /// the scene indices std::vector sceneIndices; }; #endif // __GUI_SPEC_AND_SCENE_FILE_CREATION_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiSpecAndSceneFileCreationDialog.cxx0000664000175000017500000001212011572067322024744 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "BrainSet.h" #include "FileFilters.h" #include "GuiFileSelectionButton.h" #include "GuiSpecAndSceneFileCreationDialog.h" /** * constructor. */ GuiSpecAndSceneFileCreationDialog::GuiSpecAndSceneFileCreationDialog(QWidget* parent, BrainSet* brainSetIn, const std::vector& sceneIndicesIn) : WuQDialog(parent) { setWindowTitle("Create Spec and Scene File"); brainSet = brainSetIn; sceneIndices = sceneIndicesIn; // // Button and line edit for spec file // GuiFileSelectionButton* specFileButton = new GuiFileSelectionButton(0, "Spec File...", FileFilters::getSpecFileFilter(), false); specFileNameLineEdit = new QLineEdit; QObject::connect(specFileButton, SIGNAL(fileSelected(const QString&)), specFileNameLineEdit, SLOT(setText(const QString&))); // // Button and line edit for scene file // GuiFileSelectionButton* sceneFileButton = new GuiFileSelectionButton(0, "Scene File...", FileFilters::getSceneFileFilter(), false); sceneFileNameLineEdit = new QLineEdit; QObject::connect(sceneFileButton, SIGNAL(fileSelected(const QString&)), sceneFileNameLineEdit, SLOT(setText(const QString&))); // // layout the selection controls // QGridLayout* fileGridLayout = new QGridLayout; fileGridLayout->addWidget(specFileButton, 0, 0); fileGridLayout->addWidget(specFileNameLineEdit, 0, 1); fileGridLayout->addWidget(sceneFileButton, 1, 0); fileGridLayout->addWidget(sceneFileNameLineEdit, 1, 1); // // Get the dialog's layout and add to it // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->addLayout(fileGridLayout); // // Dialog buttons // QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); dialogLayout->addWidget(buttonBox); QObject::connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); QObject::connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); } /** * destructor. */ GuiSpecAndSceneFileCreationDialog::~GuiSpecAndSceneFileCreationDialog() { } /** * called when OK/Cancel button pressed. */ void GuiSpecAndSceneFileCreationDialog::done(int r) { if (r == QDialog::Rejected) { WuQDialog::done(r); return; } // // Get name of spec file // QString specFileName = specFileNameLineEdit->text(); if (specFileName.isEmpty()) { QMessageBox::critical(this, "ERROR", "You must enter the name for the Spec File."); return; } if (specFileName.endsWith(SpecFile::getSpecFileExtension()) == false) { specFileName.append(SpecFile::getSpecFileExtension()); } // // Get name of scene file // QString sceneFileName = sceneFileNameLineEdit->text(); if (sceneFileName.isEmpty()) { QMessageBox::critical(this, "ERROR", "You must enter the name for the Scene File."); return; } if (sceneFileName.endsWith(SpecFile::getSceneFileExtension()) == false) { sceneFileName.append(SpecFile::getSceneFileExtension()); } // // Create the spec file // QString errorMessage; brainSet->createSpecFromScenes(sceneIndices, specFileName, sceneFileName, errorMessage); // // Was there an error ? // if (errorMessage.isEmpty() == false) { QMessageBox::critical(this, "ERROR", errorMessage); return; } WuQDialog::done(r); } caret-5.6.4~dfsg.1.orig/caret/GuiSmoothingDialog.h0000664000175000017500000001141711572067322021570 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_SECTION_SMOOTHING_DIALOG_H__ #define __GUI_SECTION_SMOOTHING_DIALOG_H__ #include #include "WuQDialog.h" class BrainModelSurface; class QCheckBox; class QGroupBox; class QLabel; class QRadioButton; class QSpinBox; class QDoubleSpinBox; /// Dialog for surface smoothing. class GuiSmoothingDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiSmoothingDialog(QWidget* parent, const bool modal, const bool showLandmarkConstrainedSelection, std::vector* smoothOnlyTheseNodesIn); /// Destructor ~GuiSmoothingDialog(); // set the smoothing surface (if not set, does smooths main window surface) void setSmoothingSurface(BrainModelSurface* smoothingSurfaceIn); private slots: /// callde when apply button pressed void slotApply(); /// called during modal operation virtual void done(int r); /// smoothing type selection void slotSmoothingType(); private: /// types of smoothing mode enum SMOOTHING_MODE { MODE_NOT_SELECTED, MODE_AREAL_SMOOTHING, MODE_CROSSOVER_SMOOTHING, MODE_CURVATURE_SMOOTHING, MODE_FLAT_OVERLAP_SMOOTHING, MODE_LANDMARK_SMOOTHING, MODE_LANDMARK_NEIGHBOR_SMOOTHING, MODE_LINEAR_SMOOTHING }; /// type of smoothing selected SMOOTHING_MODE smoothingMode; /// called to execute the smoothing bool doSmoothing(); /// mark the landmark nodes (returns true if there are landmark nodes) bool markLandmarkNodes(BrainModelSurface* bms, std::vector& landmarkNodes, QString& errorMessage); /// areal smoothing radio button QRadioButton* arealSmoothingRadioButton; /// curvature smoothing radio button QRadioButton* curvatureSmoothingRadioButton; /// linear smoothing radio button QRadioButton* linearSmoothingRadioButton; /// landmark smoothing radio button QRadioButton* landmarkSmoothingRadioButton; /// landmark neighbor smoothing radio button QRadioButton* landmarkNeighborSmoothingRadioButton; /// smooth out crossovers QRadioButton* crossoverSmoothingRadioButton; /// smooth out flat surface overlap QRadioButton* flatOverlapSmoothingRadioButton; /// iterations spin box QSpinBox* iterationsSpinBox; /// edge iterations label QLabel* edgeIterationsLabel; /// edge iterations spin box QSpinBox* edgeIterationsSpinBox; /// strength spin box QDoubleSpinBox* strengthSpinBox; /// threads spin box QSpinBox* threadsSpinBox; /// project to sphere every X Iterations check box QCheckBox* projectToSphereIterationsCheckBox; /// project to sphere every X Iterations spin box QSpinBox* projectToSphereIterationsSpinBox; /// number of cycles label QLabel* numberOfCyclesLabel; /// number of cycles spin box QSpinBox* numberOfCyclesSpinBox; /// depth label QLabel* depthLabel; /// depth spin box QSpinBox* depthSpinBox; /// curvature maximum float spin box QDoubleSpinBox* curvatureMaximumDoubleSpinBox; /// curvature maximum label QLabel* curvatureMaximumLabel; /// limit smoothing to only the selected nodes std::vector* smoothOnlyTheseNodes; /// sphere options group box QGroupBox* sphereOptionsGroupBox; /// update normals check box QCheckBox* updateNormalsCheckBox; /// smoothing surface (if NULL, main window surface is smoothed) BrainModelSurface* smoothingSurface; }; #endif caret-5.6.4~dfsg.1.orig/caret/GuiSmoothingDialog.cxx0000664000175000017500000006614111572067322022147 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include "BrainModelSurface.h" #include "BrainModelSurfaceSmoothing.h" #include "BrainSet.h" #include "DebugControl.h" #include "GuiBrainModelOpenGL.h" #include "GuiMainWindow.h" #include "GuiSmoothingDialog.h" #include "PaintFile.h" #include "PreferencesFile.h" #include #include "QtUtilities.h" #include "global_variables.h" /** * Constructor. */ GuiSmoothingDialog::GuiSmoothingDialog(QWidget* parent, const bool modalFlag, const bool showOtherSmoothingOptions, std::vector* smoothOnlyTheseNodesIn) : WuQDialog(parent) { setModal(modalFlag); smoothingSurface = NULL; setWindowTitle("Smoothing"); smoothOnlyTheseNodes = smoothOnlyTheseNodesIn; smoothingMode = MODE_NOT_SELECTED; // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // Areal smoothing radio button // arealSmoothingRadioButton = new QRadioButton("Normal Smoothing"); // // Smooth Out Crossovers // crossoverSmoothingRadioButton = NULL; if (showOtherSmoothingOptions) { crossoverSmoothingRadioButton = new QRadioButton("Crossover Smoothing"); } // // curvature smoothing // curvatureSmoothingRadioButton = NULL; if (showOtherSmoothingOptions) { curvatureSmoothingRadioButton = new QRadioButton("Curvature Smoothing"); } // // Smooth flat surface overlap // flatOverlapSmoothingRadioButton = NULL; if (showOtherSmoothingOptions) { flatOverlapSmoothingRadioButton = new QRadioButton("Flat Surface Overlap Smoothing"); } // // landmark constrained smoothing radio button // landmarkSmoothingRadioButton = NULL; if (showOtherSmoothingOptions) { landmarkSmoothingRadioButton = new QRadioButton("Landmark Constrained Smoothing"); } // // landmark neighbor constrained smoothing radio button // landmarkNeighborSmoothingRadioButton = NULL; if (showOtherSmoothingOptions) { landmarkNeighborSmoothingRadioButton = new QRadioButton("Landmark Neighbor Constrained Smoothing"); } // // linear smoothing radio button // // linearSmoothingRadioButton = NULL; linearSmoothingRadioButton = new QRadioButton("Linear Smoothing"); // // Group Box and layout for radio buttons // QGroupBox* typeGroupBox = new QGroupBox("Smoothing Type"); QVBoxLayout* typeLayout = new QVBoxLayout(typeGroupBox); typeLayout->addWidget(arealSmoothingRadioButton); if (crossoverSmoothingRadioButton != NULL) { typeLayout->addWidget(crossoverSmoothingRadioButton); } if (curvatureSmoothingRadioButton != NULL) { typeLayout->addWidget(curvatureSmoothingRadioButton); } if (flatOverlapSmoothingRadioButton != NULL) { typeLayout->addWidget(flatOverlapSmoothingRadioButton); } if (landmarkSmoothingRadioButton != NULL) { typeLayout->addWidget(landmarkSmoothingRadioButton); } if (landmarkNeighborSmoothingRadioButton != NULL) { typeLayout->addWidget(landmarkNeighborSmoothingRadioButton); } if (linearSmoothingRadioButton != NULL) { typeLayout->addWidget(linearSmoothingRadioButton); } dialogLayout->addWidget(typeGroupBox); // // Button group to keep radio buttons mutually exclusive // QButtonGroup* typeButtonGroup = new QButtonGroup(this); typeButtonGroup->addButton(arealSmoothingRadioButton, 0); if (crossoverSmoothingRadioButton != NULL) { typeButtonGroup->addButton(crossoverSmoothingRadioButton, 1); } if (curvatureSmoothingRadioButton != NULL) { typeButtonGroup->addButton(curvatureSmoothingRadioButton, 2); } if (flatOverlapSmoothingRadioButton != NULL) { typeButtonGroup->addButton(flatOverlapSmoothingRadioButton, 3); } if (landmarkSmoothingRadioButton != NULL) { typeButtonGroup->addButton(landmarkSmoothingRadioButton, 4); } if (landmarkNeighborSmoothingRadioButton != NULL) { typeButtonGroup->addButton(landmarkNeighborSmoothingRadioButton, 5); } if (linearSmoothingRadioButton != NULL) { typeButtonGroup->addButton(linearSmoothingRadioButton, 6); } QObject::connect(typeButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotSmoothingType())); // // Smoothing strength // QLabel* strengthLabel = new QLabel("Strength"); strengthSpinBox = new QDoubleSpinBox; strengthSpinBox->setMinimum(0.0); strengthSpinBox->setMaximum(1.0); strengthSpinBox->setSingleStep(0.01); strengthSpinBox->setDecimals(2); strengthSpinBox->setValue(1.0); // // Iterations spin box // QLabel* iterationsLabel = new QLabel("Iterations"); iterationsSpinBox = new QSpinBox; iterationsSpinBox->setMinimum(1); iterationsSpinBox->setMaximum(10000); iterationsSpinBox->setSingleStep(10); iterationsSpinBox->setValue(50); // // Edge Iterations spin box // edgeIterationsLabel = new QLabel("Edge Iterations Every X"); edgeIterationsSpinBox = new QSpinBox; edgeIterationsSpinBox->setMinimum(0); edgeIterationsSpinBox->setMaximum(10000); edgeIterationsSpinBox->setSingleStep(1); edgeIterationsSpinBox->setValue(10); // // Cycles spin box // numberOfCyclesLabel = new QLabel("Number of Cycles"); numberOfCyclesSpinBox = new QSpinBox; numberOfCyclesSpinBox->setMinimum(1); numberOfCyclesSpinBox->setMaximum(1000); numberOfCyclesSpinBox->setSingleStep(1); numberOfCyclesSpinBox->setValue(5); // // Depth spin box // depthLabel = new QLabel("Node Depth"); depthSpinBox = new QSpinBox; depthSpinBox->setMinimum(0); depthSpinBox->setMaximum(50); depthSpinBox->setSingleStep(1); depthSpinBox->setValue(5); // // Curvature maximum float spin box // curvatureMaximumLabel = NULL; curvatureMaximumDoubleSpinBox = NULL; if (showOtherSmoothingOptions) { curvatureMaximumLabel = new QLabel("Max Curvature"); curvatureMaximumDoubleSpinBox = new QDoubleSpinBox; curvatureMaximumDoubleSpinBox->setMinimum(0.0); curvatureMaximumDoubleSpinBox->setMaximum(10000.0); curvatureMaximumDoubleSpinBox->setSingleStep(0.25); curvatureMaximumDoubleSpinBox->setDecimals(4); curvatureMaximumDoubleSpinBox->setValue(0.25); } // // Group box for parameters // QGroupBox* parametersGroupBox = new QGroupBox("Smoothing Parameters"); dialogLayout->addWidget(parametersGroupBox); QGridLayout* paramsGridLayout = new QGridLayout(parametersGroupBox); int rowNum = 0; paramsGridLayout->addWidget(strengthLabel, rowNum, 0); paramsGridLayout->addWidget(strengthSpinBox, rowNum, 1); rowNum++; paramsGridLayout->addWidget(iterationsLabel, rowNum, 0); paramsGridLayout->addWidget(iterationsSpinBox, rowNum, 1); rowNum++; paramsGridLayout->addWidget(edgeIterationsLabel, rowNum, 0); paramsGridLayout->addWidget(edgeIterationsSpinBox, rowNum, 1); rowNum++; paramsGridLayout->addWidget(numberOfCyclesLabel, rowNum, 0); paramsGridLayout->addWidget(numberOfCyclesSpinBox, rowNum, 1); rowNum++; paramsGridLayout->addWidget(depthLabel, rowNum, 0); paramsGridLayout->addWidget(depthSpinBox, rowNum, 1); rowNum++; if (curvatureMaximumLabel != NULL) { paramsGridLayout->addWidget(curvatureMaximumLabel, rowNum, 0); paramsGridLayout->addWidget(curvatureMaximumDoubleSpinBox, rowNum, 1); rowNum++; } // // Sphere Options Group Box // projectToSphereIterationsCheckBox = new QCheckBox("Project To Sphere Every X Iterations"); projectToSphereIterationsSpinBox = new QSpinBox; projectToSphereIterationsSpinBox->setMinimum(0); projectToSphereIterationsSpinBox->setMaximum(10000); projectToSphereIterationsSpinBox->setSingleStep(1); projectToSphereIterationsSpinBox->setEnabled(false); projectToSphereIterationsSpinBox->setValue(10); sphereOptionsGroupBox = new QGroupBox("Spherical Options"); QHBoxLayout* sphereOptionsLayout = new QHBoxLayout(sphereOptionsGroupBox); sphereOptionsLayout->addWidget(projectToSphereIterationsCheckBox); sphereOptionsLayout->addWidget(projectToSphereIterationsSpinBox); dialogLayout->addWidget(sphereOptionsGroupBox); // // Enable project to sphere iterations spin box when check box is checked // QObject::connect(projectToSphereIterationsCheckBox, SIGNAL(toggled(bool)), projectToSphereIterationsSpinBox, SLOT(setEnabled(bool))); threadsSpinBox = NULL; if (DebugControl::getDebugOn()) { // // Threads strength // QLabel* threadsLabel = new QLabel("Number to Run"); threadsSpinBox = new QSpinBox; threadsSpinBox->setMinimum(0); threadsSpinBox->setMaximum(1024); threadsSpinBox->setSingleStep(1); threadsSpinBox->setToolTip( "Smoothing will be split into this\n" "number of simultaneous processes."); PreferencesFile* pf = theMainWindow->getBrainSet()->getPreferencesFile(); threadsSpinBox->setValue(pf->getMaximumNumberOfThreads()); // // Group box for threading // QGroupBox* threadsGroupBox = new QGroupBox("Execution Threads"); QHBoxLayout* threadsLayout = new QHBoxLayout(threadsGroupBox); threadsLayout->addWidget(threadsLabel); threadsLayout->addWidget(threadsSpinBox); dialogLayout->addWidget(threadsGroupBox); } // // Note about normals // updateNormalsCheckBox = new QCheckBox("Update Surface Normals After Smoothing"); updateNormalsCheckBox->setChecked(true); QGroupBox* normalsGroup = new QGroupBox("Surface Normals"); QVBoxLayout* normalsLayout = new QVBoxLayout(normalsGroup); normalsLayout->addWidget(updateNormalsCheckBox); dialogLayout->addWidget(normalsGroup); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); dialogLayout->addLayout(buttonsLayout); if (isModal()) { // // OK button // QPushButton* okButton = new QPushButton("OK"); okButton->setAutoDefault(false); buttonsLayout->addWidget(okButton); QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); // // Cancel button // QPushButton* cancelButton = new QPushButton("Cancel"); cancelButton->setAutoDefault(false); buttonsLayout->addWidget(cancelButton); QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); QtUtilities::makeButtonsSameSize(okButton, cancelButton); } else { // // Apply button // QPushButton* applyButton = new QPushButton("Apply"); applyButton->setAutoDefault(false); buttonsLayout->addWidget(applyButton); QObject::connect(applyButton, SIGNAL(clicked()), this, SLOT(slotApply())); // // Close button connects to QDialogs close() slot. // QPushButton* closeButton = new QPushButton("Close"); closeButton->setAutoDefault(false); buttonsLayout->addWidget(closeButton); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); QtUtilities::makeButtonsSameSize(applyButton, closeButton); } // // Default to areal smoothing // arealSmoothingRadioButton->setChecked(true); slotSmoothingType(); } /** * Destructor. */ GuiSmoothingDialog::~GuiSmoothingDialog() { } /** * set the smoothing surface (if not set, does smooths main window surface). */ void GuiSmoothingDialog::setSmoothingSurface(BrainModelSurface* smoothingSurfaceIn) { smoothingSurface = smoothingSurfaceIn; } /** * Slot for OK or Cancel button in modal mode. */ void GuiSmoothingDialog::done(int r) { if (r == QDialog::Accepted) { if (doSmoothing()) { return; } } QDialog::done(r); } /** * smoothing type selection. */ void GuiSmoothingDialog::slotSmoothingType() { smoothingMode = MODE_NOT_SELECTED; if (arealSmoothingRadioButton->isChecked()) { smoothingMode = MODE_AREAL_SMOOTHING; } if (landmarkSmoothingRadioButton != NULL) { if (landmarkSmoothingRadioButton->isChecked()) { smoothingMode = MODE_LANDMARK_SMOOTHING; } } if (linearSmoothingRadioButton != NULL) { if (linearSmoothingRadioButton->isChecked()) { smoothingMode = MODE_LINEAR_SMOOTHING; } } if (landmarkNeighborSmoothingRadioButton != NULL) { if (landmarkNeighborSmoothingRadioButton->isChecked()) { smoothingMode = MODE_LANDMARK_NEIGHBOR_SMOOTHING; } } if (crossoverSmoothingRadioButton != NULL) { if (crossoverSmoothingRadioButton->isChecked()) { smoothingMode = MODE_CROSSOVER_SMOOTHING; } } if (curvatureSmoothingRadioButton != NULL) { if (curvatureSmoothingRadioButton->isChecked()) { smoothingMode = MODE_CURVATURE_SMOOTHING; } } if (flatOverlapSmoothingRadioButton != NULL) { if (flatOverlapSmoothingRadioButton->isChecked()) { smoothingMode = MODE_FLAT_OVERLAP_SMOOTHING; } } bool depthCyclesEnabled = false; bool curvatureEnabled = false; bool sphereOptionsEnabled = true; bool edgeIterationsEnabled = true; edgeIterationsLabel->setText("Edges Every X Iterations"); switch (smoothingMode) { case MODE_NOT_SELECTED: break; case MODE_AREAL_SMOOTHING: break; case MODE_CROSSOVER_SMOOTHING: depthCyclesEnabled = true; break; case MODE_CURVATURE_SMOOTHING: curvatureEnabled = true; edgeIterationsEnabled = false; sphereOptionsEnabled = false; break; case MODE_FLAT_OVERLAP_SMOOTHING: depthCyclesEnabled = true; break; case MODE_LANDMARK_SMOOTHING: edgeIterationsEnabled = false; break; case MODE_LANDMARK_NEIGHBOR_SMOOTHING: edgeIterationsLabel->setText("Neighbors Every X Iterations"); break; case MODE_LINEAR_SMOOTHING: break; } sphereOptionsGroupBox->setEnabled(sphereOptionsEnabled); edgeIterationsLabel->setEnabled(edgeIterationsEnabled); edgeIterationsSpinBox->setEnabled(edgeIterationsEnabled); numberOfCyclesLabel->setEnabled(depthCyclesEnabled); numberOfCyclesSpinBox->setEnabled(depthCyclesEnabled); depthLabel->setEnabled(depthCyclesEnabled); depthSpinBox->setEnabled(depthCyclesEnabled); if (curvatureMaximumLabel != NULL) { curvatureMaximumLabel->setEnabled(curvatureEnabled); } if (curvatureMaximumDoubleSpinBox != NULL) { curvatureMaximumDoubleSpinBox->setEnabled(curvatureEnabled); } } /** * Slot for apply button in non-modal mode. */ void GuiSmoothingDialog::slotApply() { doSmoothing(); } /** * Called to do the actual smoothing. Returns true if an error occurs. */ bool GuiSmoothingDialog::doSmoothing() { const float strength = strengthSpinBox->value(); const int iterations = iterationsSpinBox->value(); const int edgeIters = edgeIterationsSpinBox->value(); int projectToSphereEveryX = projectToSphereIterationsSpinBox->value(); if (projectToSphereIterationsCheckBox->isChecked() == false) { projectToSphereEveryX = 0; } const int nodeDepth = depthSpinBox->value(); const int numberOfCycles = numberOfCyclesSpinBox->value(); PreferencesFile* pf = theMainWindow->getBrainSet()->getPreferencesFile(); int numberOfThreads = pf->getMaximumNumberOfThreads(); if (threadsSpinBox != NULL) { numberOfThreads = threadsSpinBox->value(); } BrainModelSurface* bms = smoothingSurface; if (bms == NULL) { bms = theMainWindow->getBrainModelSurface(); } if (bms != NULL) { // // Check spherical things // switch (bms->getSurfaceType()) { case BrainModelSurface::SURFACE_TYPE_RAW: case BrainModelSurface::SURFACE_TYPE_FIDUCIAL: case BrainModelSurface::SURFACE_TYPE_INFLATED: case BrainModelSurface::SURFACE_TYPE_VERY_INFLATED: case BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL: case BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL: case BrainModelSurface::SURFACE_TYPE_FLAT: case BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR: case BrainModelSurface::SURFACE_TYPE_HULL: case BrainModelSurface::SURFACE_TYPE_UNKNOWN: case BrainModelSurface::SURFACE_TYPE_UNSPECIFIED: if (projectToSphereIterationsCheckBox->isChecked()) { if (QMessageBox::question(this, "Question", "The surface does not appear to be a sphere\n" "but Project to Sphere is selected. Continue?", (QMessageBox::Yes | QMessageBox::No), QMessageBox::No) == QMessageBox::No) { return true; } } break; case BrainModelSurface::SURFACE_TYPE_SPHERICAL: if (projectToSphereIterationsCheckBox->isChecked() == false) { if (QMessageBox::question(this, "Question", "The surface appears to be a sphere but\n" "Project to Sphere is not selected. Continue?", (QMessageBox::Yes | QMessageBox::No), QMessageBox::No) == QMessageBox::No) { return true; } } break; } // // Check flat things // switch (bms->getSurfaceType()) { case BrainModelSurface::SURFACE_TYPE_RAW: case BrainModelSurface::SURFACE_TYPE_FIDUCIAL: case BrainModelSurface::SURFACE_TYPE_INFLATED: case BrainModelSurface::SURFACE_TYPE_VERY_INFLATED: case BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL: case BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL: case BrainModelSurface::SURFACE_TYPE_SPHERICAL: case BrainModelSurface::SURFACE_TYPE_HULL: case BrainModelSurface::SURFACE_TYPE_UNKNOWN: case BrainModelSurface::SURFACE_TYPE_UNSPECIFIED: if (smoothingMode == MODE_FLAT_OVERLAP_SMOOTHING) { if (QMessageBox::question(this, "Question", "The surface does not appear to be a flat but\n" "Flat Surface Overlap Smoothing is selected. Continue?", (QMessageBox::Yes | QMessageBox::No), QMessageBox::No) == QMessageBox::No) { return true; } } break; case BrainModelSurface::SURFACE_TYPE_FLAT: case BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR: break; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); switch (smoothingMode) { case MODE_NOT_SELECTED: QMessageBox::critical(this, "Smoothing Error", "You must select a smoothing type."); return true; break; case MODE_AREAL_SMOOTHING: if (numberOfThreads <= 0) { bms->arealSmoothing(strength, iterations, edgeIters, smoothOnlyTheseNodes, projectToSphereEveryX); } else { BrainModelSurfaceSmoothing smooth(theMainWindow->getBrainSet(), bms, BrainModelSurfaceSmoothing::SMOOTHING_TYPE_AREAL, strength, iterations, edgeIters, 0, smoothOnlyTheseNodes, NULL, projectToSphereEveryX, numberOfThreads); try { smooth.execute(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); return true; } } break; case MODE_CROSSOVER_SMOOTHING: bms->smoothOutSurfaceCrossovers(strength, numberOfCycles, iterations, edgeIters, projectToSphereEveryX, nodeDepth, bms->getSurfaceType()); break; case MODE_CURVATURE_SMOOTHING: bms->smoothSurfaceUsingCurvature(-strength, iterations, curvatureMaximumDoubleSpinBox->value()); break; case MODE_FLAT_OVERLAP_SMOOTHING: bms->smoothOutFlatSurfaceOverlap(strength, numberOfCycles, iterations, edgeIters, nodeDepth); break; case MODE_LANDMARK_SMOOTHING: { std::vector landmarkNodes; QString errorMessage; if (markLandmarkNodes(bms, landmarkNodes, errorMessage)) { // // Do the landmark constrained smoothing // bms->landmarkConstrainedSmoothing(strength, iterations, landmarkNodes, projectToSphereEveryX); } else { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "Error", errorMessage); return true; } } break; case MODE_LANDMARK_NEIGHBOR_SMOOTHING: { std::vector landmarkNodes; QString errorMessage; if (markLandmarkNodes(bms, landmarkNodes, errorMessage)) { // // Do the landmark constrained smoothing // bms->landmarkNeighborConstrainedSmoothing(strength, iterations, landmarkNodes, edgeIters, projectToSphereEveryX); } else { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "Error", errorMessage); return true; } } break; case MODE_LINEAR_SMOOTHING: if (numberOfThreads <= 0) { bms->linearSmoothing(strength, iterations, edgeIters, smoothOnlyTheseNodes, projectToSphereEveryX); } else { BrainModelSurfaceSmoothing smooth(theMainWindow->getBrainSet(), bms, BrainModelSurfaceSmoothing::SMOOTHING_TYPE_LINEAR, strength, iterations, edgeIters, 0, smoothOnlyTheseNodes, NULL, projectToSphereEveryX, numberOfThreads); try { smooth.execute(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); return true; } } break; } if (updateNormalsCheckBox->isChecked()) { bms->computeNormals(); } GuiBrainModelOpenGL::updateAllGL(theMainWindow->getBrainModelOpenGL()); QApplication::restoreOverrideCursor(); QApplication::beep(); } theMainWindow->speakText("Smoothing has completed.", false); return false; } /** * Set landmark nodes. Returns false if no landmark nodes were found. */ bool GuiSmoothingDialog::markLandmarkNodes(BrainModelSurface* bms, std::vector& landmarkNodes, QString& errorMessage) { errorMessage = ""; const int numNodes = bms->getNumberOfNodes(); if (numNodes > 0) { landmarkNodes.resize(numNodes); std::fill(landmarkNodes.begin(), landmarkNodes.end(), false); // // Make sure there is a paint column named "Landmarks" // PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); const int landmarksColumn = pf->getColumnWithName("Landmarks"); if (landmarksColumn < 0) { errorMessage = "There is no paint column named \"Landmarks\""; return false; } // // Make sure there is a paint name "Landmark" // const int landmarkPaintIndex = pf->getPaintIndexFromName("Landmark"); if (landmarkPaintIndex < 0) { errorMessage = "There is no paint name \"Landmark\""; return false; } // // Find nodes with name "Landmark" // bool nodeFound = false; for (int i = 0; i < numNodes; i++) { if (pf->getPaint(i, landmarksColumn) == landmarkPaintIndex) { landmarkNodes[i] = true; nodeFound = true; } } // // Make sure landmark nodes exist // if (nodeFound == false) { errorMessage = "No nodes have the paint name \"Landmark\""; return false; } return true; } else { errorMessage = "There are no nodes."; return false; } } caret-5.6.4~dfsg.1.orig/caret/GuiShellCommandWindow.h0000664000175000017500000000552311572067322022240 0ustar michaelmichael #ifndef __GUI_SHELL_COMMAND_WINDOW_H__ #define __GUI_SHELL_COMMAND_WINDOW_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "WuQDialog.h" class QComboBox; class QTextEdit; /// class for line edit with keys intercepted class GuiShellCommandLineEdit : public QLineEdit { Q_OBJECT public: // constructor GuiShellCommandLineEdit(); // destructor ~GuiShellCommandLineEdit(); signals: /// emitted when up arrow pressed void signalUpArrowKeyPressed(); /// emitted when down arrow key pressed void signalDownArrowKeyPressed(); /// emitted when control K pressed void signalControlKPressed(); protected: // called when a key is pressed virtual void keyPressEvent(QKeyEvent* event); }; /// dialog for executing shell commands class GuiShellCommandWindow : public WuQDialog { Q_OBJECT public: // constructor GuiShellCommandWindow(QWidget* parent); // destructor ~GuiShellCommandWindow(); protected slots: // called when return pressed in command line edit void slotCommandLineReturnPressed(); // called when up arrow is pressed in command line edit void slotCommandLineUpArrowPressed(); // called when down arrow is pressed in command line edit void slotCommandLineDownArrowPressed(); protected: // convert some unix commands to their window's equivalents QString convertUnixToWindows(const QString& s) const; // line edit for entering commands GuiShellCommandLineEdit* commandLineEdit; // combo box for previous commands QComboBox* prevCommandsComboBox; // text edit for command output QTextEdit* commandOutputTextEdit; /// previous commands QStringList previousCommands; /// previous command index int previousCommandIndex; }; #endif // __GUI_SHELL_COMMAND_WINDOW_H__ caret-5.6.4~dfsg.1.orig/caret/GuiShellCommandWindow.cxx0000664000175000017500000002152611572067322022614 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "GuiShellCommandWindow.h" /** * constructor. */ GuiShellCommandWindow::GuiShellCommandWindow(QWidget* parent) : WuQDialog(parent) { setWindowTitle("Shell Command Window"); // // Create the command output section // commandOutputTextEdit = new QTextEdit; commandOutputTextEdit->setReadOnly(true); // // Create the command line edit // QLabel* commandLabel = new QLabel("Command "); commandLineEdit = new GuiShellCommandLineEdit; QObject::connect(commandLineEdit, SIGNAL(returnPressed()), this, SLOT(slotCommandLineReturnPressed())); QObject::connect(commandLineEdit, SIGNAL(signalUpArrowKeyPressed()), this, SLOT(slotCommandLineUpArrowPressed())); QObject::connect(commandLineEdit, SIGNAL(signalDownArrowKeyPressed()), this, SLOT(slotCommandLineDownArrowPressed())); QObject::connect(commandLineEdit, SIGNAL(signalControlKPressed()), commandOutputTextEdit, SLOT(clear())); QHBoxLayout* commandLayout = new QHBoxLayout; commandLayout->addWidget(commandLabel); commandLayout->addWidget(commandLineEdit); commandLayout->setStretchFactor(commandLabel, 0); commandLayout->setStretchFactor(commandLineEdit, 1000); // // layout for dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->addWidget(commandOutputTextEdit); dialogLayout->addLayout(commandLayout); // // Dialog buttons // QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); buttonBox->button(QDialogButtonBox::Close)->setAutoDefault(false); dialogLayout->addWidget(buttonBox); QObject::connect(buttonBox, SIGNAL(rejected()), this, SLOT(close())); // // clear previous commands // previousCommands.clear(); previousCommandIndex = -1; } /** * destructor. */ GuiShellCommandWindow::~GuiShellCommandWindow() { } /** * called when up arrow is pressed in command line edit. */ void GuiShellCommandWindow::slotCommandLineUpArrowPressed() { previousCommandIndex--; if (previousCommandIndex < 0) { previousCommandIndex = 0; } if ((previousCommandIndex >= 0) && (previousCommandIndex < previousCommands.count())) { commandLineEdit->setText(previousCommands.at(previousCommandIndex)); } } /** * called when down arrow is pressed in command line edit. */ void GuiShellCommandWindow::slotCommandLineDownArrowPressed() { previousCommandIndex++; if (previousCommandIndex >= previousCommands.count()) { previousCommandIndex = previousCommands.count(); commandLineEdit->setText(""); } else if ((previousCommandIndex >= 0) && (previousCommandIndex < previousCommands.count())) { commandLineEdit->setText(previousCommands.at(previousCommandIndex)); } } /** * convert some unix commands to their window's equivalents. */ QString GuiShellCommandWindow::convertUnixToWindows(const QString& s) const { #ifdef Q_OS_WIN32 QString s1(s.trimmed()); if (s1.left(3) == "ls ") { s1.replace(0, 2, "dir"); } else if (s1 == "ls") { s1 = "dir"; } else if (s1.left(4) == "cat ") { s1.replace(0, 3, "type"); } else if (s1.left(3) == "cp ") { s1.replace(0, 2, "copy"); } else if (s1.left(3) == "mv ") { s1.replace(0, 2, "rename"); } else if (s1.left(3) == "rm") { s1.replace(0, 2, "del"); } else if (s1 == "pwd") { s1 = "chdir"; // note: chdir without any arguments prints directory } return s1; #else // Q_OS_WIN32 return s; #endif // Q_OS_WIN32 } /** * called when return pressed in command line edit. */ void GuiShellCommandWindow::slotCommandLineReturnPressed() { const QString userCommand(convertUnixToWindows(commandLineEdit->text())); if (userCommand.isEmpty()) { QMessageBox::critical(this, "ERROR", "Command is empty."); return; } // // Setup the command // QString processName; QStringList processArgs; #ifdef Q_OS_WIN32 processName = "cmd.exe"; processArgs << "/C"; processArgs << userCommand; #else // Q_OS_WIN32 processName = "/bin/sh"; processArgs << "-c"; // arg to /bin/sh processArgs << userCommand; #endif // Q_OS_WIN32 // // Insert the command into the window in black text // QString commandForOutputWindow; commandForOutputWindow += ""; commandForOutputWindow += ">"; commandForOutputWindow += userCommand; commandForOutputWindow += "
    "; commandOutputTextEdit->insertHtml(commandForOutputWindow); // // Run the command // QProcess process; process.start(processName, processArgs); if (!process.waitForStarted()) { QMessageBox::critical(this, "ERROR", "Error starting process."); return; } // // When process finishes, place its text in window // if (process.waitForFinished()) { // // Show command output in blue // QString txt(""); txt += process.readAll(); txt += "
    "; txt.replace("\r\n", "
    "); txt.replace(QRegExp("[\n\r]"), "
    "); commandOutputTextEdit->insertHtml(txt); } else { QMessageBox::critical(this, "ERROR", "Error waiting for process to finish."); return; } // // Did user command fail? // if ((process.exitCode() != 0) || (process.exitStatus() != QProcess::NormalExit)) { // // Show error information in red // QString commandForOutputWindow; commandForOutputWindow += ""; commandForOutputWindow += process.readAllStandardError(); commandForOutputWindow += "
    "; commandOutputTextEdit->insertHtml(commandForOutputWindow); } // // Save command for access with up arrow // previousCommands += userCommand; previousCommandIndex = previousCommands.count(); // // Clear the last entered command // commandLineEdit->setText(""); // // Scroll to end of window text // QTextCursor tc = commandOutputTextEdit->textCursor(); tc.movePosition(QTextCursor::End); commandOutputTextEdit->setTextCursor(tc); } //------------------------------------------------------------------------------------- /** * constructor. */ GuiShellCommandLineEdit::GuiShellCommandLineEdit() : QLineEdit() { } /** * destructor. */ GuiShellCommandLineEdit::~GuiShellCommandLineEdit() { } /** * called when a key is pressed. */ void GuiShellCommandLineEdit::keyPressEvent(QKeyEvent* event) { if (event->key() == Qt::Key_Up) { signalUpArrowKeyPressed(); } else if (event->key() == Qt::Key_Down) { signalDownArrowKeyPressed(); } #ifdef Q_OS_MAC_XYZ else if ((event->key() == Qt::Key_A) && (event->modifiers() == Qt::MetaModifier)) { setCursorPosition(0); } else if ((event->key() == Qt::Key_E) && (event->modifiers() == Qt::MetaModifier)) { setCursorPosition(text().length()); } else if ((event->key() == Qt::Key_K) && (event->modifiers() == Qt::MetaModifier)) { signalControlKPressed(); } #else // Q_OS_MAC else if ((event->key() == Qt::Key_A) && (event->modifiers() == Qt::ControlModifier)) { setCursorPosition(0); } else if ((event->key() == Qt::Key_E) && (event->modifiers() == Qt::ControlModifier)) { setCursorPosition(text().length()); } else if ((event->key() == Qt::Key_K) && (event->modifiers() == Qt::ControlModifier)) { signalControlKPressed(); } #endif // Q_OS_MAC QLineEdit::keyPressEvent(event); } caret-5.6.4~dfsg.1.orig/caret/GuiShapeOrVectorsFromCoordinateSubtractionDialog.h0000664000175000017500000000452411572067322027603 0ustar michaelmichael #ifndef __GUI_VECTORS_FROM_COORDINATES_SUBTRACTION_DIALOG_H__ #define __GUI_VECTORS_FROM_COORDINATES_SUBTRACTION_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "WuQDialog.h" class GuiBrainModelSelectionComboBox; class GuiNodeAttributeColumnSelectionComboBox; class QComboBox; class QLineEdit; /// dialog for creating vectors by subracting coordinate files class GuiShapeOrVectorsFromCoordinateSubtractionDialog : public WuQDialog { Q_OBJECT public: /// mode of dialog enum MODE { /// Generating shape data MODE_SHAPE, /// Generating vector data MODE_VECTOR }; // constructor GuiShapeOrVectorsFromCoordinateSubtractionDialog(QWidget* parent, const MODE modeIn); // destructor ~GuiShapeOrVectorsFromCoordinateSubtractionDialog(); protected: // called when OK or Cancel buttons pressed void done(int r); // surface "A" combo box GuiBrainModelSelectionComboBox* surfaceAComboBox; // surface "B" combo box GuiBrainModelSelectionComboBox* surfaceBComboBox; // the vector column name QLineEdit* columnNameLineEdit; // the vector column comment QLineEdit* columnCommentLineEdit; // shape difference mode combo box QComboBox* shapeDiffModeComboBox; // mode of the dialog MODE mode; }; #endif // __GUI_VECTORS_FROM_COORDINATES_SUBTRACTION_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiShapeOrVectorsFromCoordinateSubtractionDialog.cxx0000664000175000017500000002376111572067322030162 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include "BrainModelSurface.h" #include "BrainSet.h" #include "DisplaySettingsVectors.h" #include "GuiBrainModelOpenGL.h" #include "GuiBrainModelSelectionComboBox.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "GuiNodeAttributeColumnSelectionComboBox.h" #include "GuiShapeOrVectorsFromCoordinateSubtractionDialog.h" #include "MathUtilities.h" #include "SurfaceShapeFile.h" #include "TopologyFile.h" #include "TopologyHelper.h" #include "VectorFile.h" #include "global_variables.h" /** * constructor. */ GuiShapeOrVectorsFromCoordinateSubtractionDialog::GuiShapeOrVectorsFromCoordinateSubtractionDialog( QWidget* parent, const MODE modeIn) : WuQDialog(parent) { mode = modeIn; switch (mode) { case MODE_SHAPE: setWindowTitle("Create Surface Shape From Surface Difference"); break; case MODE_VECTOR: setWindowTitle("Create Vectors From Surface Subtraction"); break; } // // Layout for dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); // // surface A // QLabel* surfaceALabel = new QLabel("Surface A "); surfaceAComboBox = new GuiBrainModelSelectionComboBox(false, true, false, "", 0); // // surface B // QLabel* surfaceBLabel = new QLabel("Surface B "); surfaceBComboBox = new GuiBrainModelSelectionComboBox(false, true, false, "", 0); // // Grid for items // QGridLayout* gridLayout = new QGridLayout; dialogLayout->addLayout(gridLayout); gridLayout->addWidget(surfaceALabel, 0, 0); gridLayout->addWidget(surfaceAComboBox, 0, 1); gridLayout->addWidget(surfaceBLabel, 1, 0); gridLayout->addWidget(surfaceBComboBox, 1, 1); // // vector column combo box // switch (mode) { case MODE_SHAPE: { QLabel* columnLabel = new QLabel("Column Name "); columnNameLineEdit = new QLineEdit; QLabel* columnCommentLabel = new QLabel("Column Comment "); columnCommentLineEdit = new QLineEdit; // // Shape difference mode // QLabel* shapeDiffModeLabel = new QLabel("XYZ Difference"); this->shapeDiffModeComboBox = new QComboBox; this->shapeDiffModeComboBox->addItem("Absolute Value", QVariant((int)MetricFile::COORDINATE_DIFFERENCE_MODE_ABSOLUTE)); this->shapeDiffModeComboBox->addItem("Signed", QVariant((int)MetricFile::COORDINATE_DIFFERENCE_MODE_SIGNED)); gridLayout->addWidget(columnLabel, 3, 0); gridLayout->addWidget(columnNameLineEdit, 3, 1); gridLayout->addWidget(columnCommentLabel, 4, 0); gridLayout->addWidget(columnCommentLineEdit, 4, 1); gridLayout->addWidget(shapeDiffModeLabel, 5, 0); gridLayout->addWidget(shapeDiffModeComboBox, 5, 1); } break; case MODE_VECTOR: break; } // // Dialog buttons // QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); dialogLayout->addWidget(buttonBox); QObject::connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); QObject::connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); switch (mode) { case MODE_SHAPE: columnNameLineEdit->setText("Difference"); columnCommentLineEdit->setText(""); break; case MODE_VECTOR: break; } } /** * destructor. */ GuiShapeOrVectorsFromCoordinateSubtractionDialog::~GuiShapeOrVectorsFromCoordinateSubtractionDialog() { } /** * called when OK or Cancel buttons pressed. */ void GuiShapeOrVectorsFromCoordinateSubtractionDialog::done(int r) { if (r == QDialog::Accepted) { const BrainModelSurface* bmsA = surfaceAComboBox->getSelectedBrainModelSurface(); if (bmsA == NULL) { QMessageBox::critical(this, "ERROR", "Surface A is invalid."); return; } const BrainModelSurface* bmsB = surfaceBComboBox->getSelectedBrainModelSurface(); if (bmsB == NULL) { QMessageBox::critical(this, "ERROR", "Surface B is invalid."); return; } if (bmsA->getNumberOfNodes() <= 0) { QMessageBox::critical(this, "ERROR", "Surface A has no nodes."); return; } if (bmsA->getNumberOfNodes() != bmsB->getNumberOfNodes()) { QMessageBox::critical(this, "ERROR", "Surface A and B have a different number of nodes."); return; } if (bmsA == bmsB) { QMessageBox::critical(this, "ERROR", "Surface A and B are the same."); return; } showWaitCursor(); switch (mode) { case MODE_SHAPE: { const QString columnName = columnNameLineEdit->text(); const QString columnComment = columnCommentLineEdit->text(); int diffIndex = this->shapeDiffModeComboBox->currentIndex(); const MetricFile::COORDINATE_DIFFERENCE_MODE diffMode = (MetricFile::COORDINATE_DIFFERENCE_MODE) this->shapeDiffModeComboBox->itemData(diffIndex).toInt(); SurfaceShapeFile* ssf = theMainWindow->getBrainSet()->getSurfaceShapeFile(); try { int diffColNum = ssf->getNumberOfColumns(); ssf->addColumns(4); ssf->addColumnOfCoordinateDifference(diffMode, bmsA->getCoordinateFile(), bmsB->getCoordinateFile(), bmsA->getTopologyFile(), diffColNum, columnName, columnComment, diffColNum + 1, diffColNum + 2, diffColNum + 3); } catch (FileException& e) { showNormalCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); return; } GuiFilesModified fm; fm.setSurfaceShapeModified(); theMainWindow->fileModificationUpdate(fm); } break; case MODE_VECTOR: { VectorFile* vf = new VectorFile(); int numNodes = bmsA->getNumberOfNodes(); const TopologyHelper* th = bmsA->getTopologyFile()->getTopologyHelper(false, true, false); vf->setNumberOfVectors(numNodes); for (int i = 0; i < numNodes; i++) { float xyz[3] = { 0.0, 0.0, 0.0 }; float vector[3] = { 0.0, 0.0, 0.0 }; float magnitude = 0.0; if (th->getNodeHasNeighbors(i)) { const float* xyzA = bmsA->getCoordinateFile()->getCoordinate(i); const float* xyzB = bmsB->getCoordinateFile()->getCoordinate(i); xyz[0] = xyzA[0]; xyz[1] = xyzA[1]; xyz[2] = xyzA[2]; vector[0] = xyzB[0] - xyzA[0]; vector[1] = xyzB[1] - xyzA[1]; vector[2] = xyzB[2] - xyzA[2]; magnitude = MathUtilities::vectorLength(vector); MathUtilities::normalize(vector); } vf->setVectorData(i, xyz, vector, magnitude, i); } theMainWindow->getBrainSet()->addVectorFile(vf); DisplaySettingsVectors* dssv = theMainWindow->getBrainSet()->getDisplaySettingsVectors(); if (dssv->getDisplayModeSurface() == DisplaySettingsVectors::DISPLAY_MODE_NONE) { dssv->setDisplayModeSurface(DisplaySettingsVectors::DISPLAY_MODE_SPARSE); } dssv->update(); GuiFilesModified fm; fm.setVectorModified(); theMainWindow->fileModificationUpdate(fm); } } GuiBrainModelOpenGL::updateAllGL(); showNormalCursor(); beep(); } WuQDialog::done(r); } caret-5.6.4~dfsg.1.orig/caret/GuiSetViewDialog.h0000664000175000017500000000513011572067322021202 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_SET_VIEW_DIALOG_H__ #define __GUI_SET_VIEW_DIALOG_H__ #include "WuQDialog.h" class BrainModel; class QDoubleSpinBox; /// class for setting the view of a surface class GuiSetViewDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiSetViewDialog(QWidget* parent, BrainModel* brainModelIn, const int viewNumberIn); /// Destructor ~GuiSetViewDialog(); private slots: /// called when the view is changed. void slotViewChanged(); private: /// Called when OK or Cancel button is pressed void done(int r); /// load transformation into the dialog void loadTransformation(); /// the brain model BrainModel* brainModel; /// the view number of the brain model int viewNumber; /// x translate float spin box QDoubleSpinBox* xTranslateDoubleSpinBox; /// y translate float spin box QDoubleSpinBox* yTranslateDoubleSpinBox; /// z translate float spin box QDoubleSpinBox* zTranslateDoubleSpinBox; /// x rotate float spin box QDoubleSpinBox* xRotateDoubleSpinBox; /// y rotate float spin box QDoubleSpinBox* yRotateDoubleSpinBox; /// z rotate float spin box QDoubleSpinBox* zRotateDoubleSpinBox; /// x scale float spin box QDoubleSpinBox* xScaleDoubleSpinBox; /// y scale float spin box QDoubleSpinBox* yScaleDoubleSpinBox; /// z scale float spin box QDoubleSpinBox* zScaleDoubleSpinBox; /// creating dialog flag bool creatingDialog; }; #endif // __GUI_SET_VIEW_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiSetViewDialog.cxx0000664000175000017500000002162511572067322021564 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include "vtkTransform.h" #include "BrainModel.h" #include "GuiBrainModelOpenGL.h" #include "GuiMainWindow.h" #include "GuiSetViewDialog.h" #include #include "QtUtilities.h" #include "global_variables.h" /** * Constructor. */ GuiSetViewDialog::GuiSetViewDialog(QWidget* parent, BrainModel* brainModelIn, const int viewNumberIn) : WuQDialog(parent) { setModal(true); creatingDialog = true; brainModel = brainModelIn; viewNumber = viewNumberIn; setWindowTitle("Set Surface View"); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // Translation // xTranslateDoubleSpinBox = new QDoubleSpinBox; xTranslateDoubleSpinBox->setMinimum(-100000.0); xTranslateDoubleSpinBox->setMaximum( 100000.0); xTranslateDoubleSpinBox->setSingleStep(5.0); xTranslateDoubleSpinBox->setDecimals(1); QObject::connect(xTranslateDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(slotViewChanged())); yTranslateDoubleSpinBox = new QDoubleSpinBox; yTranslateDoubleSpinBox->setMinimum(-100000.0); yTranslateDoubleSpinBox->setMaximum( 100000.0); yTranslateDoubleSpinBox->setSingleStep(5.0); yTranslateDoubleSpinBox->setDecimals(1); QObject::connect(yTranslateDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(slotViewChanged())); zTranslateDoubleSpinBox = new QDoubleSpinBox; zTranslateDoubleSpinBox->setMinimum(-100000.0); zTranslateDoubleSpinBox->setMaximum( 100000.0); zTranslateDoubleSpinBox->setSingleStep(5.0); zTranslateDoubleSpinBox->setDecimals(1); QObject::connect(zTranslateDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(slotViewChanged())); QGroupBox* translateGroupBox = new QGroupBox("Translate"); dialogLayout->addWidget(translateGroupBox); QHBoxLayout* translateGroupLayout = new QHBoxLayout(translateGroupBox); translateGroupLayout->addWidget(xTranslateDoubleSpinBox); translateGroupLayout->addWidget(yTranslateDoubleSpinBox); translateGroupLayout->addWidget(zTranslateDoubleSpinBox); // // Rotation // xRotateDoubleSpinBox = new QDoubleSpinBox; xRotateDoubleSpinBox->setMinimum(-180.0); xRotateDoubleSpinBox->setMaximum(180.0); xRotateDoubleSpinBox->setSingleStep(5.0); xRotateDoubleSpinBox->setDecimals(2); QObject::connect(xRotateDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(slotViewChanged())); yRotateDoubleSpinBox = new QDoubleSpinBox; yRotateDoubleSpinBox->setMinimum(-180.0); yRotateDoubleSpinBox->setMaximum(180.0); yRotateDoubleSpinBox->setSingleStep(5.0); yRotateDoubleSpinBox->setDecimals(2); QObject::connect(yRotateDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(slotViewChanged())); zRotateDoubleSpinBox = new QDoubleSpinBox; zRotateDoubleSpinBox->setMinimum(-180.0); zRotateDoubleSpinBox->setMaximum(180.0); zRotateDoubleSpinBox->setSingleStep(5.0); zRotateDoubleSpinBox->setDecimals(2); QObject::connect(zRotateDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(slotViewChanged())); QGroupBox* rotateGroupBox = new QGroupBox("Rotate"); dialogLayout->addWidget(rotateGroupBox); QHBoxLayout* rotateGroupLayout = new QHBoxLayout(rotateGroupBox); rotateGroupLayout->addWidget(xRotateDoubleSpinBox); rotateGroupLayout->addWidget(yRotateDoubleSpinBox); rotateGroupLayout->addWidget(zRotateDoubleSpinBox); // // Scale // xScaleDoubleSpinBox = new QDoubleSpinBox; xScaleDoubleSpinBox->setMinimum(0.001); xScaleDoubleSpinBox->setMaximum(10000.0); xScaleDoubleSpinBox->setSingleStep(0.1); xScaleDoubleSpinBox->setDecimals(3); QObject::connect(xScaleDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(slotViewChanged())); yScaleDoubleSpinBox = new QDoubleSpinBox; yScaleDoubleSpinBox->setMinimum(0.001); yScaleDoubleSpinBox->setMaximum(10000.0); yScaleDoubleSpinBox->setSingleStep(0.1); yScaleDoubleSpinBox->setDecimals(3); QObject::connect(yScaleDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(slotViewChanged())); zScaleDoubleSpinBox = new QDoubleSpinBox; zScaleDoubleSpinBox->setMinimum(0.001); zScaleDoubleSpinBox->setMaximum(10000.0); zScaleDoubleSpinBox->setSingleStep(0.1); zScaleDoubleSpinBox->setDecimals(3); QObject::connect(zScaleDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(slotViewChanged())); QGroupBox* scaleGroupBox = new QGroupBox("Scale"); dialogLayout->addWidget(scaleGroupBox); QHBoxLayout* scaleGroupLayout = new QHBoxLayout(scaleGroupBox); scaleGroupLayout->addWidget(xScaleDoubleSpinBox); scaleGroupLayout->addWidget(yScaleDoubleSpinBox); scaleGroupLayout->addWidget(zScaleDoubleSpinBox); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); dialogLayout->addLayout(buttonsLayout); // // OK button // QPushButton* okButton = new QPushButton("OK"); okButton->setAutoDefault(false); buttonsLayout->addWidget(okButton); QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); // // Close button // QPushButton* cancelButton = new QPushButton("Cancel"); cancelButton->setAutoDefault(false); buttonsLayout->addWidget(cancelButton); QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); QtUtilities::makeButtonsSameSize(okButton, cancelButton); loadTransformation(); creatingDialog = false; } /** * This loads the surface transformations into the dialog. */ void GuiSetViewDialog::loadTransformation() { if (brainModel == NULL) { return; } float t[3]; brainModel->getTranslation(viewNumber, t); xTranslateDoubleSpinBox->setValue(t[0]); yTranslateDoubleSpinBox->setValue(t[1]); zTranslateDoubleSpinBox->setValue(t[2]); float r[3]; vtkTransform* matrix = brainModel->getRotationTransformMatrix(viewNumber); matrix->GetOrientation(r); xRotateDoubleSpinBox->setValue(r[0]); yRotateDoubleSpinBox->setValue(r[1]); zRotateDoubleSpinBox->setValue(r[2]); float scale[3]; brainModel->getScaling(viewNumber, scale); xScaleDoubleSpinBox->setValue(scale[0]); yScaleDoubleSpinBox->setValue(scale[1]); zScaleDoubleSpinBox->setValue(scale[2]); } /** * called when float spin box changed. */ void GuiSetViewDialog::slotViewChanged() { if (creatingDialog) { return; } if (brainModel == NULL) { return; } float t[3] = { xTranslateDoubleSpinBox->value(), yTranslateDoubleSpinBox->value(), zTranslateDoubleSpinBox->value() }; brainModel->setTranslation(viewNumber, t); float r[3] = { xRotateDoubleSpinBox->value(), yRotateDoubleSpinBox->value(), zRotateDoubleSpinBox->value() }; vtkTransform* matrix = brainModel->getRotationTransformMatrix(viewNumber); matrix->Identity(); matrix->RotateZ(r[2]); matrix->RotateX(r[0]); matrix->RotateY(r[1]); brainModel->setScaling(viewNumber, xScaleDoubleSpinBox->value(), yScaleDoubleSpinBox->value(), zScaleDoubleSpinBox->value()); if (viewNumber == BrainModel:: BRAIN_MODEL_VIEW_MAIN_WINDOW) { theMainWindow->updateTransformationMatrixEditor(NULL); } GuiBrainModelOpenGL::updateAllGL(); } /** * Destructor. */ GuiSetViewDialog::~GuiSetViewDialog() { } /** * Called when OK or Cancel button is pressed. */ void GuiSetViewDialog::done(int r) { if (r == QDialog::Accepted) { slotViewChanged(); } QDialog::done(r); } caret-5.6.4~dfsg.1.orig/caret/GuiSetTopologyDialog.h0000664000175000017500000000345411572067322022113 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_SET_TOPOLOGY_DIALOG_H__ #define __GUI_SET_TOPOLOGY_DIALOG_H__ #include #include "WuQDialog.h" class GuiBrainModelSelectionComboBox; class GuiTopologyFileComboBox; /// dialog for setting the topology file for surfaces class GuiSetTopologyDialog : public WuQDialog { Q_OBJECT public: /// constructor GuiSetTopologyDialog(QWidget* parent); /// destructor ~GuiSetTopologyDialog(); /// update the dialog void updateDialog(); private slots: /// called when a surface is selected void slotSurfaceSelection(); /// called when a topology is selected void slotTopologySelection(); private: /// surface selection combo box GuiBrainModelSelectionComboBox* surfaceComboBox; /// topology selection combo box GuiTopologyFileComboBox* topologyComboBox; }; #endif // __GUI_SET_TOPOLOGY_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiSetTopologyDialog.cxx0000664000175000017500000001241611572067322022464 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include "BrainSet.h" #include "FileUtilities.h" #include "GuiBrainModelOpenGL.h" #include "GuiBrainModelSelectionComboBox.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "GuiSetTopologyDialog.h" #include "GuiTopologyFileComboBox.h" #include "global_variables.h" /** * Constructor. */ GuiSetTopologyDialog::GuiSetTopologyDialog(QWidget* parent) : WuQDialog(parent) { setWindowTitle("Set Topology"); // // Grid layout for coord and topology // QGridLayout* grid = new QGridLayout; grid->setSpacing(4); // // Surface selection // grid->addWidget(new QLabel("Surface"), 0, 0, Qt::AlignLeft); surfaceComboBox = new GuiBrainModelSelectionComboBox(false, true, false, "", 0); surfaceComboBox->setMaximumWidth(400); grid->addWidget(surfaceComboBox, 0, 1, Qt::AlignLeft); QObject::connect(surfaceComboBox, SIGNAL(activated(int)), this, SLOT(slotSurfaceSelection())); // // Topology selection // grid->addWidget(new QLabel("Topology"), 1, 0, Qt::AlignLeft); topologyComboBox = new GuiTopologyFileComboBox(0); topologyComboBox->setMaximumWidth(400); grid->addWidget(topologyComboBox, 1, 1, Qt::AlignLeft); QObject::connect(topologyComboBox, SIGNAL(activated(int)), this, SLOT(slotTopologySelection())); // // layout for entire dialog // QVBoxLayout* layout = new QVBoxLayout(this); layout->addLayout(grid); // // Dialog buttons // QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); buttonBox->button(QDialogButtonBox::Close)->setAutoDefault(false); layout->addWidget(buttonBox); QObject::connect(buttonBox, SIGNAL(rejected()), this, SLOT(close())); surfaceComboBox->setSelectedBrainModel(theMainWindow->getBrainModelSurface()); slotSurfaceSelection(); } /** * update the dialog. */ void GuiSetTopologyDialog::updateDialog() { surfaceComboBox->updateComboBox(); topologyComboBox->updateComboBox(); } /** * Called when a surface is selected. */ void GuiSetTopologyDialog::slotSurfaceSelection() { // // Set topology file to one used by this surface. // BrainModelSurface* bms = surfaceComboBox->getSelectedBrainModelSurface(); if (bms != NULL) { const TopologyFile* tf = bms->getTopologyFile(); if (tf != NULL) { for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfTopologyFiles(); i++) { if (tf == theMainWindow->getBrainSet()->getTopologyFile(i)) { topologyComboBox->setCurrentIndex(i); break; } } } } } /** * Called when a topology is selected. */ void GuiSetTopologyDialog::slotTopologySelection() { // // Set the surface's topology file // BrainModelSurface* bms = surfaceComboBox->getSelectedBrainModelSurface(); if (bms != NULL) { if (topologyComboBox->getSelectedTopologyFile() != bms->getTopologyFile()) { TopologyFile* oldTopologyFile = bms->getTopologyFile(); if (bms->setTopologyFile(topologyComboBox->getSelectedTopologyFile())) { std::ostringstream str; str << "Topology File " << FileUtilities::basename(bms->getTopologyFile()->getFileName()).toAscii().constData() << "\n is not for use with coordinate file " << FileUtilities::basename(bms->getCoordinateFile()->getFileName()).toAscii().constData() << ".\n Topo file has tiles with node numbers exceeding \n" << "the number of coordinates in the coordinate file."; bms->setTopologyFile(oldTopologyFile); QMessageBox::critical(this, "ERROR", str.str().c_str()); return; } GuiFilesModified fm; fm.setCoordinateModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(NULL); } } } /** * Destructor. */ GuiSetTopologyDialog::~GuiSetTopologyDialog() { } caret-5.6.4~dfsg.1.orig/caret/GuiSectionControlDialog.h0000664000175000017500000000552611572067322022572 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_SECTION_CONTROL_DIALOG_H__ #define __GUI_SECTION_CONTROL_DIALOG_H__ #include "WuQDialog.h" class QComboBox; class QLabel; class QRadioButton; class QScrollBar; class QSpinBox; class QSlider; class GuiNodeAttributeColumnSelectionComboBox; /// Dialog for controlling selected sections. class GuiSectionControlDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiSectionControlDialog(QWidget* parent); /// Destructor ~GuiSectionControlDialog(); /// Update dialog due to change in sections void updateDialog(); private slots: /// called when minimum spin box value is changed void slotMinimumSpinBox(int value); /// called when maximum spin box value is changed void slotMaximumSpinBox(int value); /// called when a slider is released void sliderReleasedSlot(); /// slot when column selection combo box is changed void fileColumnComboBoxSlot(int item); /// called when minimum slider released void minimumSliderMovedSlot(int value); /// called when maximum slider released void maximumSliderMovedSlot(int value); /// called when a section type radio button is pressed void sectionTypeSlot(int item); private: /// section file column combo box; GuiNodeAttributeColumnSelectionComboBox* sectionFileColumnComboBox; /// single section radio button QRadioButton* singleSectionRadioButton; /// multiple section radio button QRadioButton* multipleSectionRadioButton; /// all section radio button QRadioButton* allSectionRadioButton; /// minimum section slider QSlider* minimumSlider; /// maximum section slider QSlider* maximumSlider; /// minimum section spin box QSpinBox* minimumSpinBox; /// maximum section spin box QSpinBox* maximumSpinBox; }; #endif caret-5.6.4~dfsg.1.orig/caret/GuiSectionControlDialog.cxx0000664000175000017500000003734611572067322023152 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include "BrainSet.h" #include "DisplaySettingsSection.h" #include "GuiBrainModelOpenGL.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "GuiNodeAttributeColumnSelectionComboBox.h" #include "GuiSectionControlDialog.h" #include "SectionFile.h" #include "global_variables.h" /** * Constructor. */ GuiSectionControlDialog::GuiSectionControlDialog(QWidget* parent) : WuQDialog(parent) { setWindowTitle("Section Control"); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // column selection combo box // sectionFileColumnComboBox = new GuiNodeAttributeColumnSelectionComboBox(GUI_NODE_FILE_TYPE_SECTION, false, false, false); QObject::connect(sectionFileColumnComboBox, SIGNAL(itemSelected(int)), this, SLOT(fileColumnComboBoxSlot(int))); dialogLayout->addWidget(sectionFileColumnComboBox); // // Single, Multiple, All Radio buttons // singleSectionRadioButton = new QRadioButton("Single"); multipleSectionRadioButton = new QRadioButton("Multiple"); allSectionRadioButton = new QRadioButton("All"); // // Button Group for number of sections control // QGroupBox* sectionsGroupBox = new QGroupBox("Sections"); QVBoxLayout* sectionsGroupLayout = new QVBoxLayout(sectionsGroupBox); sectionsGroupLayout->addWidget(singleSectionRadioButton); sectionsGroupLayout->addWidget(multipleSectionRadioButton); sectionsGroupLayout->addWidget(allSectionRadioButton); dialogLayout->addWidget(sectionsGroupBox); // // Button group to keep buttons mutually exclusive // QButtonGroup* sectionsButtonGroup = new QButtonGroup(this); sectionsButtonGroup->addButton(singleSectionRadioButton, DisplaySettingsSection::SELECTION_TYPE_SINGLE); sectionsButtonGroup->addButton(multipleSectionRadioButton, DisplaySettingsSection::SELECTION_TYPE_MULTIPLE); sectionsButtonGroup->addButton(allSectionRadioButton, DisplaySettingsSection::SELECTION_TYPE_ALL); QObject::connect(sectionsButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(sectionTypeSlot(int))); // // Horizontal box for labels and labels for minimum slider // QLabel* lowLabel = new QLabel("Low "); lowLabel->setFixedSize(lowLabel->sizeHint()); minimumSpinBox = new QSpinBox; minimumSpinBox->setMinimum(1); minimumSpinBox->setMaximum(100); minimumSpinBox->setSingleStep(1); QObject::connect(minimumSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotMinimumSpinBox(int))); // // // Minimum slider // minimumSlider = new QSlider(Qt::Vertical); minimumSlider->setSingleStep(1); minimumSlider->setPageStep(10); QObject::connect(minimumSlider, SIGNAL(valueChanged(int)), this, SLOT(minimumSliderMovedSlot(int))); QObject::connect(minimumSlider, SIGNAL(sliderReleased()), this, SLOT(sliderReleasedSlot())); // // Horizontal box for labels and labels for maximum slider // QLabel* highLabel = new QLabel("High "); highLabel->setFixedSize(highLabel->sizeHint()); maximumSpinBox = new QSpinBox; maximumSpinBox->setMinimum(1); maximumSpinBox->setMaximum(100); maximumSpinBox->setSingleStep(1); QObject::connect(maximumSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotMaximumSpinBox(int))); // // // Maximum slider // maximumSlider = new QSlider(Qt::Vertical); maximumSlider->setSingleStep(1); maximumSlider->setPageStep(10); QObject::connect(maximumSlider, SIGNAL(valueChanged(int)), this, SLOT(maximumSliderMovedSlot(int))); QObject::connect(maximumSlider, SIGNAL(sliderReleased()), this, SLOT(sliderReleasedSlot())); // // Group Box for sliders // QGroupBox* sliderGroup = new QGroupBox("Section Selection"); dialogLayout->addWidget(sliderGroup); QGridLayout* sliderGridLayout = new QGridLayout(sliderGroup); sliderGridLayout->addWidget(lowLabel, 0, 0); sliderGridLayout->addWidget(minimumSpinBox, 1, 0); sliderGridLayout->addWidget(minimumSlider, 2, 0); sliderGridLayout->addWidget(highLabel, 0, 1); sliderGridLayout->addWidget(maximumSpinBox, 1, 1); sliderGridLayout->addWidget(maximumSlider, 2, 1); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; dialogLayout->addLayout(buttonsLayout); // // Close button connects to QDialogs close() slot. // QPushButton* closeButton = new QPushButton("Close"); closeButton->setFixedSize(closeButton->sizeHint()); closeButton->setAutoDefault(false); buttonsLayout->addWidget(closeButton); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); updateDialog(); } /** * Destructor. */ GuiSectionControlDialog::~GuiSectionControlDialog() { } /** * Slot for column selection. */ void GuiSectionControlDialog::fileColumnComboBoxSlot(int item) { DisplaySettingsSection* dss = theMainWindow->getBrainSet()->getDisplaySettingsSection(); SectionFile* sf = theMainWindow->getBrainSet()->getSectionFile(); if (sf->getNumberOfColumns() == 0) { return; } dss->setSelectedDisplayColumn(-1, -1, item); updateDialog(); //GuiFilesModified fm; //fm.setSectionModified(); //theMainWindow->fileModificationUpdate(fm); theMainWindow->getBrainSet()->clearAllDisplayLists(); GuiBrainModelOpenGL::updateAllGL(NULL); } /** * Slot for release of minimum slider */ void GuiSectionControlDialog::minimumSliderMovedSlot(int value) { // // block signals from spin boxes to prevent display redraw while slider dragged // minimumSpinBox->blockSignals(true); maximumSpinBox->blockSignals(true); DisplaySettingsSection* dss = theMainWindow->getBrainSet()->getDisplaySettingsSection(); SectionFile* sf = theMainWindow->getBrainSet()->getSectionFile(); if (sf->getNumberOfColumns() <= 0) { return; } //const int column = dss->getSelectedColumn(); if (dss->getSelectionType() == DisplaySettingsSection::SELECTION_TYPE_SINGLE) { maximumSlider->setValue(value); maximumSpinBox->setValue(value); } else if (dss->getSelectionType() == DisplaySettingsSection::SELECTION_TYPE_MULTIPLE) { if (value > maximumSlider->value()) { maximumSlider->setValue(value); maximumSpinBox->setValue(value); } } minimumSpinBox->setValue(value); // // enable signals from spin boxes now that the displayed value has been changed // minimumSpinBox->blockSignals(false); maximumSpinBox->blockSignals(false); } /** * Slot for release of maximum slider */ void GuiSectionControlDialog::maximumSliderMovedSlot(int value) { // // block signals from spin boxes to prevent display redraw while slider dragged // minimumSpinBox->blockSignals(true); maximumSpinBox->blockSignals(true); DisplaySettingsSection* dss = theMainWindow->getBrainSet()->getDisplaySettingsSection(); SectionFile* sf = theMainWindow->getBrainSet()->getSectionFile(); if (sf->getNumberOfColumns() <= 0) { return; } //const int column = dss->getSelectedColumn(); if (dss->getSelectionType() == DisplaySettingsSection::SELECTION_TYPE_SINGLE) { minimumSlider->setValue(value); minimumSpinBox->setValue(value); } else if (dss->getSelectionType() == DisplaySettingsSection::SELECTION_TYPE_MULTIPLE) { if (value < minimumSlider->value()) { minimumSlider->setValue(value); minimumSpinBox->setValue(value); } } maximumSpinBox->setValue(value); // // enable signals from spin boxes now that the displayed value has been changed // minimumSpinBox->blockSignals(false); maximumSpinBox->blockSignals(false); } /** * Update due to change in sections. */ void GuiSectionControlDialog::updateDialog() { SectionFile* sf = theMainWindow->getBrainSet()->getSectionFile(); if (sf->getNumberOfColumns() <= 0) { return; } DisplaySettingsSection* dss = theMainWindow->getBrainSet()->getDisplaySettingsSection(); const int column = dss->getSelectedDisplayColumn(-1, -1); // // Load the column selection combo box // sectionFileColumnComboBox->updateComboBox(sf); // // Set the selection type radio buttons // switch(dss->getSelectionType()) { case DisplaySettingsSection::SELECTION_TYPE_MULTIPLE: multipleSectionRadioButton->setChecked(true); break; case DisplaySettingsSection::SELECTION_TYPE_ALL: allSectionRadioButton->setChecked(true); dss->setMinimumSelectedSection(sf->getMinimumSection(column)); dss->setMaximumSelectedSection(sf->getMaximumSection(column)); break; case DisplaySettingsSection::SELECTION_TYPE_SINGLE: default: singleSectionRadioButton->setChecked(true); if (dss->getMinimumSelectedSection() != dss->getMaximumSelectedSection()) { dss->setMaximumSelectedSection(dss->getMinimumSelectedSection()); } break; } // // Enable the sliders and spin boxes if all is NOT selected // minimumSlider->setEnabled( ! allSectionRadioButton->isChecked()); maximumSlider->setEnabled( ! allSectionRadioButton->isChecked()); minimumSpinBox->setEnabled( ! allSectionRadioButton->isChecked()); maximumSpinBox->setEnabled( ! allSectionRadioButton->isChecked()); // // Set the slider and spin box min/max range // minimumSlider->setMinimum(sf->getMinimumSection(column)); minimumSlider->setMaximum(sf->getMaximumSection(column)); maximumSlider->setMinimum(sf->getMinimumSection(column)); maximumSlider->setMaximum(sf->getMaximumSection(column)); minimumSpinBox->setRange(sf->getMinimumSection(column), sf->getMaximumSection(column)); maximumSpinBox->setRange(sf->getMinimumSection(column), sf->getMaximumSection(column)); // // Set the slider and spin box current value // minimumSlider->setValue(dss->getMinimumSelectedSection()); maximumSlider->setValue(dss->getMaximumSelectedSection()); minimumSpinBox->setValue(dss->getMinimumSelectedSection()); maximumSpinBox->setValue(dss->getMaximumSelectedSection()); } /** * Called when one of the selection type radio buttons is pressed. */ void GuiSectionControlDialog::sectionTypeSlot(int item) { SectionFile* sf = theMainWindow->getBrainSet()->getSectionFile(); if (sf->getNumberOfColumns() == 0) { return; } DisplaySettingsSection* dss = theMainWindow->getBrainSet()->getDisplaySettingsSection(); const int column = dss->getSelectedDisplayColumn(-1, -1); DisplaySettingsSection::SELECTION_TYPE selType = static_cast(item); dss->setSelectionType(selType); if (selType == DisplaySettingsSection::SELECTION_TYPE_ALL) { dss->setMinimumSelectedSection(sf->getMinimumSection(column)); dss->setMaximumSelectedSection(sf->getMaximumSection(column)); } else if (selType == DisplaySettingsSection::SELECTION_TYPE_SINGLE) { dss->setMinimumSelectedSection(minimumSlider->value()); dss->setMaximumSelectedSection(minimumSlider->value()); } updateDialog(); //GuiFilesModified fm; //fm.setSectionModified(); //theMainWindow->fileModificationUpdate(fm); theMainWindow->getBrainSet()->clearAllDisplayLists(); GuiBrainModelOpenGL::updateAllGL(NULL); } /** * Called when apply button is pressed. */ void GuiSectionControlDialog::sliderReleasedSlot() { SectionFile* sf = theMainWindow->getBrainSet()->getSectionFile(); if (sf->getNumberOfColumns() == 0) { return; } DisplaySettingsSection* dss = theMainWindow->getBrainSet()->getDisplaySettingsSection(); //const int column = dss->getSelectedColumn(); /* if (singleSectionRadioButton->isChecked()) { sf->setSelectionType(column, SectionFile::SELECTION_TYPE_SINGLE); } else if (multipleSectionRadioButton->isChecked()) { sf->setSelectionType(column, SectionFile::SELECTION_TYPE_MULTIPLE); } else if (allSectionRadioButton->isChecked()) { sf->setSelectionType(column, SectionFile::SELECTION_TYPE_ALL); } */ dss->setMinimumSelectedSection(minimumSlider->value()); dss->setMaximumSelectedSection(maximumSlider->value()); //GuiFilesModified fm; //fm.setSectionModified(); //theMainWindow->fileModificationUpdate(fm); theMainWindow->getBrainSet()->clearAllDisplayLists(); GuiBrainModelOpenGL::updateAllGL(NULL); } /** * Called when minimum spin box value is changed. */ void GuiSectionControlDialog::slotMinimumSpinBox(int value) { SectionFile* sf = theMainWindow->getBrainSet()->getSectionFile(); if (sf->getNumberOfColumns() == 0) { return; } DisplaySettingsSection* dss = theMainWindow->getBrainSet()->getDisplaySettingsSection(); //const int column = dss->getSelectedColumn(); dss->setMinimumSelectedSection(value); if (dss->getSelectionType() == DisplaySettingsSection::SELECTION_TYPE_SINGLE) { dss->setMaximumSelectedSection(value); } else if (dss->getSelectionType() == DisplaySettingsSection::SELECTION_TYPE_MULTIPLE) { if (dss->getMinimumSelectedSection() > dss->getMaximumSelectedSection()) { dss->setMaximumSelectedSection(value); } } updateDialog(); //GuiFilesModified fm; //fm.setSectionModified(); //theMainWindow->fileModificationUpdate(fm); theMainWindow->getBrainSet()->clearAllDisplayLists(); GuiBrainModelOpenGL::updateAllGL(NULL); } /** * Called when maximum spin box value is changed. */ void GuiSectionControlDialog::slotMaximumSpinBox(int value) { DisplaySettingsSection* dss = theMainWindow->getBrainSet()->getDisplaySettingsSection(); SectionFile* sf = theMainWindow->getBrainSet()->getSectionFile(); if (sf->getNumberOfColumns() == 0) { return; } //const int column = dss->getSelectedColumn(); dss->setMaximumSelectedSection(value); if (dss->getSelectionType() == DisplaySettingsSection::SELECTION_TYPE_SINGLE) { dss->setMinimumSelectedSection(value); } else if (dss->getSelectionType() == DisplaySettingsSection::SELECTION_TYPE_MULTIPLE) { if (dss->getMaximumSelectedSection() < dss->getMinimumSelectedSection()) { dss->setMinimumSelectedSection(value); } } updateDialog(); //GuiFilesModified fm; //fm.setSectionModified(); //theMainWindow->fileModificationUpdate(fm); theMainWindow->getBrainSet()->clearAllDisplayLists(); GuiBrainModelOpenGL::updateAllGL(NULL); } caret-5.6.4~dfsg.1.orig/caret/GuiResectionDialog.h0000664000175000017500000000461411572067322021555 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_RESECTION_DIALOG_H__ #define __GUI_RESECTION_DIALOG_H__ #include "WuQDialog.h" class GuiBrainModelSelectionComboBox; class GuiNodeAttributeColumnSelectionComboBox; class QComboBox; class QLineEdit; class QRadioButton; class QSpinBox; class QDoubleSpinBox; /// Dialog for resectioning class GuiResectionDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiResectionDialog(QWidget* parent); /// Destructor ~GuiResectionDialog(); public slots: /// called when OK or Cancel button pressed void done(int r); /// called when a section file column is selected void slotColumnComboBox(int item); /// called when a how to radio button is selected void slotHowToRadioButton(); private: /// surface for sectioning combo box GuiBrainModelSelectionComboBox* surfaceComboBox; /// section file column GuiNodeAttributeColumnSelectionComboBox* columnComboBox; /// section file column name line edit QLineEdit* columnNameLineEdit; /// axis combo box QComboBox* axisComboBox; /// number of sections radio button QRadioButton* numberOfSectionsRadioButton; /// number of sections spin box QSpinBox* numberOfSectionsSpinBox; /// thickness radio button QRadioButton* thicknessRadioButton; /// thickness float spin box QDoubleSpinBox* thicknessDoubleSpinBox; }; #endif // __GUI_RESECTION_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiResectionDialog.cxx0000664000175000017500000002502211572067322022124 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include "BrainModelSurface.h" #include "BrainModelSurfaceResection.h" #include "BrainSet.h" #include "GuiBrainModelSelectionComboBox.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "GuiNodeAttributeColumnSelectionComboBox.h" #include "GuiResectionDialog.h" #include #include "QtUtilities.h" #include "SectionFile.h" #include "global_variables.h" /** * Constructor */ GuiResectionDialog::GuiResectionDialog(QWidget* parent) : WuQDialog(parent) { setModal(true); setWindowTitle("Resectioning"); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // Vertical group box for surface // QGroupBox* surfaceGroupBox = new QGroupBox("Surface"); dialogLayout->addWidget(surfaceGroupBox); QVBoxLayout* surfaceGroupLayout = new QVBoxLayout(surfaceGroupBox); // // surface combo box // surfaceComboBox = new GuiBrainModelSelectionComboBox(false, true, false, "", 0); surfaceComboBox->setSelectedBrainModel(theMainWindow->getBrainModelSurface()); surfaceGroupLayout->addWidget(surfaceComboBox); // // Horizontal Group box for section file // QGroupBox* sectionFileGroupBox = new QGroupBox("Section File"); dialogLayout->addWidget(sectionFileGroupBox); QHBoxLayout* sectionFileGroupLayout = new QHBoxLayout(sectionFileGroupBox); // // Section file column and column name // columnComboBox = new GuiNodeAttributeColumnSelectionComboBox(GUI_NODE_FILE_TYPE_SECTION, true, false, false); QObject::connect(columnComboBox, SIGNAL(itemSelected(int)), this, SLOT(slotColumnComboBox(int))); columnComboBox->setCurrentIndex(GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NEW); sectionFileGroupLayout->addWidget(columnComboBox); columnNameLineEdit = new QLineEdit; sectionFileGroupLayout->addWidget(columnNameLineEdit); // // Squish the section file group box // sectionFileGroupBox->setFixedSize(sectionFileGroupBox->sizeHint()); // // Vertical group box for axis // QGroupBox* axisGroupBox = new QGroupBox("Axis"); dialogLayout->addWidget(axisGroupBox); QVBoxLayout* axisGroupBoxLayout = new QVBoxLayout(axisGroupBox); // // axis combo box // axisComboBox = new QComboBox; axisGroupBoxLayout->addWidget(axisComboBox); axisComboBox->insertItem(BrainModelSurfaceResection::SECTION_AXIS_X, "X Axis (Saggittal)"); axisComboBox->insertItem(BrainModelSurfaceResection::SECTION_AXIS_Y, "Y Axis (Coronal)"); axisComboBox->insertItem(BrainModelSurfaceResection::SECTION_AXIS_Z, "Z Axis (Horizontal)"); axisComboBox->insertItem(BrainModelSurfaceResection::SECTION_AXIS_Z_WITH_ROTATION_MATRIX, "Screen Z Axis"); // // Squish the axis group box // axisGroupBox->setFixedSize(axisGroupBox->sizeHint()); // // Group box for how to section // QGroupBox* howToGroupBox = new QGroupBox("How To Section"); dialogLayout->addWidget(howToGroupBox); QGridLayout* howToGroupGridLayout = new QGridLayout(howToGroupBox); // // Radio button group for how to radio buttons // QButtonGroup* howToButtonGroup = new QButtonGroup(this); QObject::connect(howToButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotHowToRadioButton())); // // Thickness radio button and spin box // numberOfSectionsRadioButton = new QRadioButton("Number of Sections"); howToGroupGridLayout->addWidget(numberOfSectionsRadioButton, 0, 0); howToButtonGroup->addButton(numberOfSectionsRadioButton, 0); numberOfSectionsSpinBox = new QSpinBox; numberOfSectionsSpinBox->setMinimum(1); numberOfSectionsSpinBox->setMaximum(1000000); numberOfSectionsSpinBox->setSingleStep(1); numberOfSectionsSpinBox->setValue(50); howToGroupGridLayout->addWidget(numberOfSectionsSpinBox, 0, 1); // // Thickness radio button and spin box // thicknessRadioButton = new QRadioButton("Thickness"); howToGroupGridLayout->addWidget(thicknessRadioButton, 1, 0); howToButtonGroup->addButton(thicknessRadioButton, 1); thicknessDoubleSpinBox = new QDoubleSpinBox; thicknessDoubleSpinBox->setMinimum(0.001); thicknessDoubleSpinBox->setMaximum(1000.0); thicknessDoubleSpinBox->setSingleStep(0.5); thicknessDoubleSpinBox->setDecimals(3); thicknessDoubleSpinBox->setValue(1.0); howToGroupGridLayout->addWidget(thicknessDoubleSpinBox, 1, 1); // // Squish the how to group box // howToGroupBox->setFixedSize(howToGroupBox->sizeHint()); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); dialogLayout->addLayout(buttonsLayout); // // OK button // QPushButton* okButton = new QPushButton("OK"); buttonsLayout->addWidget(okButton); QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); // // Cancel button // QPushButton* cancelButton = new QPushButton("Cancel"); buttonsLayout->addWidget(cancelButton); QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); QtUtilities::makeButtonsSameSize(okButton, cancelButton); // // Initialize some stuff // slotColumnComboBox(columnComboBox->currentIndex()); slotHowToRadioButton(); } /** * Destructor */ GuiResectionDialog::~GuiResectionDialog() { } /** * Called when a how to radio button is selected. */ void GuiResectionDialog::slotHowToRadioButton() { numberOfSectionsSpinBox->setEnabled(false); thicknessDoubleSpinBox->setEnabled(false); if (numberOfSectionsRadioButton->isChecked()) { numberOfSectionsSpinBox->setEnabled(true); } else if (thicknessRadioButton->isChecked()) { thicknessDoubleSpinBox->setEnabled(true); } } /** * Called when a section file column is selected. */ void GuiResectionDialog::slotColumnComboBox(int item) { SectionFile* sf = theMainWindow->getBrainSet()->getSectionFile(); if ((item >= 0) && (item < sf->getNumberOfColumns())) { columnNameLineEdit->setText(sf->getColumnName(item)); } else { columnNameLineEdit->setText("new column name"); } } /** * called when OK or Cancel button pressed. */ void GuiResectionDialog::done(int r) { // // Was the OK button pressed ? // if (r == QDialog::Accepted) { // // Get name of section file column // const QString columnName(columnNameLineEdit->text()); if (columnName.isEmpty()) { QMessageBox::critical(this, "ERROR", "Column Name is blank."); return; } // // Get the column number // const int columnNumber = columnComboBox->currentIndex(); // // Get the surface // BrainModelSurface* bms = surfaceComboBox->getSelectedBrainModelSurface(); if (bms == NULL) { QMessageBox::critical(this, "ERROR", "There is no surface."); return; } // // Get the section type // BrainModelSurfaceResection::SECTION_TYPE sectionType; if (numberOfSectionsRadioButton->isChecked()) { sectionType = BrainModelSurfaceResection::SECTION_TYPE_NUM_SECTIONS; } else if (thicknessRadioButton->isChecked()) { sectionType = BrainModelSurfaceResection::SECTION_TYPE_THICKNESS; } else { QMessageBox::critical(this, "ERROR", "Select How to Section."); return; } // // Get the axis // const BrainModelSurfaceResection::SECTION_AXIS axis = static_cast(axisComboBox->currentIndex()); QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainModelSurfaceResection bmsr(theMainWindow->getBrainSet(), bms, bms->getRotationTransformMatrix(0), axis, sectionType, theMainWindow->getBrainSet()->getSectionFile(), columnNumber, columnName, thicknessDoubleSpinBox->value(), numberOfSectionsSpinBox->value()); try { bmsr.execute(); GuiFilesModified fm; fm.setSectionModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); return; } QApplication::restoreOverrideCursor(); } QDialog::done(r); } caret-5.6.4~dfsg.1.orig/caret/GuiRecordingDialog.h0000664000175000017500000001476111572067322021542 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_RECORDING_DIALOG_H__ #define __GUI_RECORDING_DIALOG_H__ #include #include #include "WuQDialog.h" class QCheckBox; class QComboBox; class QGroupBox; class QImage; class QLabel; class QLineEdit; class QPushButton; class QRadioButton; class QSpinBox; class vtkAVIWriter; class vtkImageData; class vtkMPEG1Writer; class vtkMPEG2Writer; /// Dialog for recording to movie file. class GuiRecordingDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiRecordingDialog(QWidget* parent); /// Destructor ~GuiRecordingDialog(); /// get the recoding on flag bool getRecordingOn() const { return recordingOnFlag; } /// add an image to the recording void addImageToRecording(const QImage& imageIn); public slots: /// delete any temporary images that have been created void deleteTemporaryImages(); private slots: /// called when manual recording capture push button pressed void slotManualCapturePushButton(); /// called when auto/manual radio button is selected void slotRecordModeSelection(); /// called when an image size selection is made void slotImageSizeComboBox(int item); /// called when create movie button is pressed void slotCreateMovieButton(); /// called when help button is pressed void slotHelpPushButton(); private: /// image size type enum IMAGE_SIZE_TYPE { IMAGE_SIZE_TYPE_CARET_WINDOW, IMAGE_SIZE_TYPE_320x240, IMAGE_SIZE_TYPE_352x240, IMAGE_SIZE_TYPE_640x480, IMAGE_SIZE_TYPE_720x480, IMAGE_SIZE_TYPE_CUSTOM, }; /// Movie file type enum MOVIE_FILE_TYPE { /// MPEG with "mpeg_create" MOVIE_FILE_TYPE_MPEG_CREATE, /// MPEG1 using VTK MOVIE_FILE_TYPE_MPEG1_VTK, /// MPEG2 using VTK MOVIE_FILE_TYPE_MPEG2_VTK, /// AVI using VTK MOVIE_FILE_TYPE_AVI_VTK, /// Sequence of JPEG Images MOVIE_FILE_TYPE_JPEG_IMAGES }; /// get the movie file type MOVIE_FILE_TYPE getMovieFileType() const; /// create the recording section QWidget* createRecordingSection(); /// create the image size section QWidget* createImageSizeSection(); /// create the output movie section QWidget* createOutputMovieSection(); /// create the mpeg create options section QWidget* createMpegCreateOptionsSection(); /// create the movie using mpeg_create void createMovieWithMpegCreate(const QString& movieName); /// create the movie using VTK's MPEG2 void createMovieWithMpeg2VTK(); /// create the movie using VTK's MPEG1 void createMovieWithMpeg1VTK(); /// create the movie using VTK's AVI void createMovieWithAviVTK(); /// add image to movie being created with mpeg_create void addImageToMpegCreate(const QImage& image); /// add image to movie being created with VTK's MPEG2 void addImageToMpeg2VTK(const QImage& image); /// add image to movie being created with VTK's MPEG1 void addImageToMpeg1VTK(const QImage& image); /// add image to movie being created with VTK's AVI void addImageToAviVTK(const QImage& image); /// add image to movie for JPEG images void addImageToJpeg(const QImage& image); /// convert a QImage into VTK's ImageData (user must delete returned vtkImageData object) vtkImageData* convertQImagetoVTKImageData(const QImage& image); /// update the dialog controls void updateControls(); /// automatic recording radio button QRadioButton* recordAutomaticRadioButton; /// manual recording radio button QRadioButton* recordManualRadioButton; /// manual recording capture button QPushButton* manualCapturePushButton; /// image size combo box QComboBox* imageSizeComboBox; /// custom image size X spin box QSpinBox* customImageXSpinBox; /// custom image size Y spin box QSpinBox* customImageYSpinBox; /// custom size label QLabel* customSizeLabel; /// recording on flag bool recordingOnFlag; /// number of images label QLabel* numberOfImagesLabel; /// create movie pushbutton QPushButton* createMovieButton; /// the image size group box QGroupBox* imageSizeGroupBox; /// movie name line edit QLineEdit* movieNameLineEdit; /// names of images std::vector imageNames; /// compress temporary image check box QCheckBox* compressTemporaryImages; /// quality spin box QSpinBox* qualitySpinBox; /// reset push button QPushButton* resetPushButton; /// duplicate image spin box QSpinBox* duplicateSpinBox; /// counts images int imageCounter; /// movie name widget QWidget* movieNameWidget; /// movie file type widget QWidget* movieFileTypeWidget; /// movie file type combo box QComboBox* movieFileTypeComboBox; /// pointer for VTK's AVI writer vtkAVIWriter* vtkAviMovieWriter; /// pointer for caret's modified VTK's MPEG2 writer that writes MPEG1 vtkMPEG1Writer* vtkMpeg1MovieWriter; /// pointer for VTK's MPEG2 writer vtkMPEG2Writer* vtkMpeg2MovieWriter; }; #endif // __GUI_RECORDING_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiRecordingDialog.cxx0000664000175000017500000010147511572067322022114 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 #include #include #include "vtkDataArray.h" #include "vtkImageData.h" #include "vtkJPEGWriter.h" #include "vtkPointData.h" #define HAVE_AVI_WRITER 1 #undef HAVE_AVI_WRITER #ifdef HAVE_MPEG #ifdef HAVE_AVI_WRITER #include "vtkAVIWriter.h" #endif // HAVE_AVI_WRITER #include "vtkMPEG1Writer.h" #include "vtkMPEG2Writer.h" #endif // HAVE_MPEG #include "BrainModelRunExternalProgram.h" #include "BrainSet.h" #include "DebugControl.h" #include "FileUtilities.h" #include "GuiBrainModelOpenGL.h" #include "GuiFileSelectionButton.h" #include "GuiMainWindow.h" #include "GuiRecordingDialog.h" #include "QtUtilities.h" #include "global_variables.h" #include "zlib.h" /** * Constructor. */ GuiRecordingDialog::GuiRecordingDialog(QWidget* parent) : WuQDialog(parent) { setWindowTitle("Recording"); recordingOnFlag = false; imageCounter = 0; // // create the recording section // QWidget* recordingWidget = createRecordingSection(); // // create the image size section // QWidget* imageSizeWidget = createImageSizeSection(); // // create the output movie section // QWidget* outputWidget = createOutputMovieSection(); // // Create the MPEG Create options // QWidget* mpegCreateWidget = createMpegCreateOptionsSection(); // // Widgets and layout for main tab // QWidget* mainWidget = new QWidget; QVBoxLayout* mainLayout = new QVBoxLayout(mainWidget); mainLayout->addWidget(recordingWidget); mainLayout->addWidget(outputWidget); mainLayout->addStretch(); // // Widgets and layout for options tab // QWidget* optionsWidget = new QWidget; QVBoxLayout* optionsLayout = new QVBoxLayout(optionsWidget); optionsLayout->addWidget(imageSizeWidget); optionsLayout->addWidget(mpegCreateWidget); optionsLayout->addStretch(); // // Tab widget // QTabWidget* tabWidget = new QTabWidget; tabWidget->addTab(mainWidget, "Main"); tabWidget->addTab(optionsWidget, "Options"); // // Close button connects to QDialogs close() slot. // QPushButton* closeButton = new QPushButton("Close"); closeButton->setAutoDefault(false); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); // // Help button // QPushButton* helpButton = new QPushButton("Help"); helpButton->setAutoDefault(false); QObject::connect(helpButton, SIGNAL(clicked()), this, SLOT(slotHelpPushButton())); QtUtilities::makeButtonsSameSize(closeButton, helpButton); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->addWidget(closeButton); buttonsLayout->addWidget(helpButton); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->addWidget(tabWidget); dialogLayout->addLayout(buttonsLayout); #ifdef HAVE_MPEG vtkMpeg1MovieWriter = NULL; vtkMpeg2MovieWriter = NULL; #ifdef HAVE_AVI_WRITER vtkAviMovieWriter = NULL; #endif // HAVE_AVI_WRITER #endif // HAVE_MPEG deleteTemporaryImages(); } /** * Destructor. */ GuiRecordingDialog::~GuiRecordingDialog() { #ifdef HAVE_MPEG if (vtkMpeg2MovieWriter != NULL) { vtkMpeg2MovieWriter->Delete(); vtkMpeg2MovieWriter = NULL; } if (vtkMpeg1MovieWriter != NULL) { vtkMpeg1MovieWriter->Delete(); vtkMpeg1MovieWriter = NULL; } #ifdef HAVE_AVI_WRITER if (vtkAviMovieWriter != NULL) { vtkAviMovieWriter->Delete(); vtkAviMovieWriter = NULL; } #endif // HAVE_AVI_WRITER #endif // HAVE_MPEG } /** * Called when help button is pressed. */ void GuiRecordingDialog::slotHelpPushButton() { theMainWindow->showHelpViewerDialog("dialogs/record_as_mpeg_dialog.html"); } /** * create the options section. */ QWidget* GuiRecordingDialog::createMpegCreateOptionsSection() { // // Compress temporary images check box // compressTemporaryImages = new QCheckBox("Compress Temporary Images"); #ifdef Q_OS_WIN32 compressTemporaryImages->setChecked(false); #else compressTemporaryImages->setChecked(true); #endif // // Quality label and spin box // QLabel* qualityLabel = new QLabel("Quality (1=High 31=Compression)"); qualitySpinBox = new QSpinBox; qualitySpinBox->setMinimum(1); qualitySpinBox->setMaximum(31); qualitySpinBox->setSingleStep(1); qualitySpinBox->setValue(8); QHBoxLayout* qualityLayout = new QHBoxLayout; qualityLayout->addWidget(qualityLabel); qualityLayout->addWidget(qualitySpinBox); qualityLayout->addStretch(); // // Group box and layout for recording control // QGroupBox* mpegCreateGroupBox = new QGroupBox("MPEG Create Options"); QVBoxLayout* mpegCreateLayout = new QVBoxLayout(mpegCreateGroupBox); mpegCreateLayout->addWidget(compressTemporaryImages); mpegCreateLayout->addLayout(qualityLayout); return mpegCreateGroupBox; } /** * Create the recording control section. */ QWidget* GuiRecordingDialog::createRecordingSection() { // // automatic recording checkbox // recordAutomaticRadioButton = new QRadioButton("Automatic"); // // manual recording checkbox and capture push button // recordManualRadioButton = new QRadioButton("Manual"); manualCapturePushButton = new QPushButton("Capture"); manualCapturePushButton->setAutoDefault(false); QObject::connect(manualCapturePushButton, SIGNAL(clicked()), this, SLOT(slotManualCapturePushButton())); QHBoxLayout* manualLayout = new QHBoxLayout; manualLayout->addWidget(recordManualRadioButton); manualLayout->addWidget(manualCapturePushButton); manualLayout->addStretch(); // // Button group for automatic and manual radio buttons // QButtonGroup* recordModeButtonGroup = new QButtonGroup(this); QObject::connect(recordModeButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotRecordModeSelection())); recordModeButtonGroup->addButton(recordAutomaticRadioButton, 0); recordModeButtonGroup->addButton(recordManualRadioButton, 1); recordManualRadioButton->setChecked(true); // // Record each image X times // QLabel* xTimesStartLabel = new QLabel("Record each image "); duplicateSpinBox = new QSpinBox; duplicateSpinBox->setMinimum(1); duplicateSpinBox->setMaximum(128); duplicateSpinBox->setSingleStep(1); duplicateSpinBox->setValue(1); QLabel* xTimesEndLabel = new QLabel(" times"); QHBoxLayout* xTimesLayout = new QHBoxLayout; xTimesLayout->addWidget(xTimesStartLabel); xTimesLayout->addWidget(duplicateSpinBox); xTimesLayout->addWidget(xTimesEndLabel); xTimesLayout->addStretch(); // // Group box and layout for recording control // QGroupBox* recordingControlGroupBox = new QGroupBox("Recording Control"); QVBoxLayout* recordingLayout = new QVBoxLayout(recordingControlGroupBox); recordingLayout->addWidget(recordAutomaticRadioButton); recordingLayout->addLayout(manualLayout); recordingLayout->addLayout(xTimesLayout); return recordingControlGroupBox; } /** * called when manual recording capture push button pressed. */ void GuiRecordingDialog::slotManualCapturePushButton() { // // Draw and record the main window display // recordingOnFlag = true; GuiBrainModelOpenGL::updateAllGL(theMainWindow->getBrainModelOpenGL()); recordingOnFlag = false; } /** * called when auto/manual radio button is selected. */ void GuiRecordingDialog::slotRecordModeSelection() { manualCapturePushButton->setEnabled(recordManualRadioButton->isChecked()); recordingOnFlag = (recordAutomaticRadioButton->isChecked()); } /** * Create the image size section. */ QWidget* GuiRecordingDialog::createImageSizeSection() { // // Image size combo box and label // QLabel* imageSizeLabel = new QLabel("Image Size"); imageSizeComboBox = new QComboBox; QObject::connect(imageSizeComboBox, SIGNAL(activated(int)), this, SLOT(slotImageSizeComboBox(int))); imageSizeComboBox->insertItem(IMAGE_SIZE_TYPE_CARET_WINDOW, "Size of Caret Window"); imageSizeComboBox->insertItem(IMAGE_SIZE_TYPE_320x240, "320 x 240"); imageSizeComboBox->insertItem(IMAGE_SIZE_TYPE_352x240, "352 x 240"); imageSizeComboBox->insertItem(IMAGE_SIZE_TYPE_640x480, "640 x 480"); imageSizeComboBox->insertItem(IMAGE_SIZE_TYPE_720x480, "720 x 480"); imageSizeComboBox->insertItem(IMAGE_SIZE_TYPE_CUSTOM, "Custom Size"); QHBoxLayout* imageSizeLayout = new QHBoxLayout; imageSizeLayout->addWidget(imageSizeLabel); imageSizeLayout->addWidget(imageSizeComboBox); imageSizeLayout->addStretch(); // // custom size line edits and labels // customSizeLabel = new QLabel("Custom Size "); customImageXSpinBox = new QSpinBox; customImageXSpinBox->setMinimum(1); customImageXSpinBox->setMaximum(1000000); customImageXSpinBox->setSingleStep(1); customImageXSpinBox->setFixedWidth(130); customImageYSpinBox = new QSpinBox; customImageYSpinBox->setMinimum(1); customImageYSpinBox->setMaximum(1000000); customImageYSpinBox->setSingleStep(1); customImageYSpinBox->setFixedWidth(130); QHBoxLayout* customSizeLayout = new QHBoxLayout; customSizeLayout->addWidget(customSizeLabel); customSizeLayout->addWidget(customImageXSpinBox); customSizeLayout->addWidget(customImageYSpinBox); customSizeLayout->addStretch(); // // Group box and layout // imageSizeGroupBox = new QGroupBox("Image Size Control"); QVBoxLayout* imageGroupLayout = new QVBoxLayout(imageSizeGroupBox); imageGroupLayout->addLayout(imageSizeLayout); imageGroupLayout->addLayout(customSizeLayout); // // Initialize some stuff // slotImageSizeComboBox(IMAGE_SIZE_TYPE_CARET_WINDOW); return imageSizeGroupBox; } /** * Create the output move section. */ QWidget* GuiRecordingDialog::createOutputMovieSection() { // // Movie type and label // QLabel* movieFileTypeLabel = new QLabel("Movie File Type"); movieFileTypeComboBox = new QComboBox; movieFileTypeWidget = new QWidget; QHBoxLayout* movieFileTypeLayout = new QHBoxLayout(movieFileTypeWidget); movieFileTypeLayout->addWidget(movieFileTypeLabel); movieFileTypeLayout->addWidget(movieFileTypeComboBox); movieFileTypeLayout->addStretch(); // // Load the move type combo box // movieFileTypeComboBox->addItem("MPEG (using mpeg_create)", static_cast(MOVIE_FILE_TYPE_MPEG_CREATE)); #ifdef HAVE_MPEG movieFileTypeComboBox->addItem("MPEG1 (using VTK)", static_cast(MOVIE_FILE_TYPE_MPEG1_VTK)); const int mpeg1Index = movieFileTypeComboBox->count() - 1; movieFileTypeComboBox->addItem("MPEG2 (using VTK)", static_cast(MOVIE_FILE_TYPE_MPEG2_VTK)); #ifdef HAVE_AVI_WRITER movieFileTypeComboBox->addItem("AVI (using VTK)", static_cast(MOVIE_FILE_TYPE_AVI_VTK)); #endif // HAVE_AVI_WRITER movieFileTypeComboBox->setCurrentIndex(mpeg1Index); #endif // HAVE_MPEG movieFileTypeComboBox->addItem("JPEG Images", static_cast(MOVIE_FILE_TYPE_JPEG_IMAGES)); // // Movie name label and line edit // GuiFileSelectionButton* movieNamePushButton = new GuiFileSelectionButton(0, "Movie File...", "MPEG File (*.mpg)", false); movieNamePushButton->setAutoDefault(false); movieNamePushButton->setFixedSize(movieNamePushButton->sizeHint()); movieNameLineEdit = new QLineEdit; movieNameLineEdit->setText("output.mpg"); QObject::connect(movieNamePushButton, SIGNAL(fileSelected(const QString&)), movieNameLineEdit, SLOT(setText(const QString&))); movieNameWidget = new QWidget; QHBoxLayout* movieNameLayout = new QHBoxLayout(movieNameWidget); movieNameLayout->addWidget(movieNamePushButton); movieNameLayout->addWidget(movieNameLineEdit); movieNameLayout->setStretchFactor(movieNamePushButton, 0); movieNameLayout->setStretchFactor(movieNameLineEdit, 100); // // total images label // numberOfImagesLabel = new QLabel(""); // // Create movie button // createMovieButton = new QPushButton("Create Movie"); createMovieButton->setAutoDefault(false); createMovieButton->setFixedSize(createMovieButton->sizeHint()); QObject::connect(createMovieButton, SIGNAL(clicked()), this, SLOT(slotCreateMovieButton())); // // Reset button // resetPushButton = new QPushButton("Reset"); resetPushButton->setAutoDefault(false); resetPushButton->setFixedSize(resetPushButton->sizeHint()); QObject::connect(resetPushButton, SIGNAL(clicked()), this, SLOT(deleteTemporaryImages())); // // Layout for create/reset buttons // QHBoxLayout* createResetLayout = new QHBoxLayout; createResetLayout->addWidget(createMovieButton); createResetLayout->addWidget(resetPushButton); createResetLayout->addStretch(); // // Group box for page and layout // QGroupBox* outputGroupBox = new QGroupBox("Output Movie Control"); QVBoxLayout* outputLayout = new QVBoxLayout(outputGroupBox); outputLayout->addWidget(movieFileTypeWidget); outputLayout->addWidget(movieNameWidget); outputLayout->addWidget(numberOfImagesLabel); outputLayout->addLayout(createResetLayout); return outputGroupBox; } /** * */ void GuiRecordingDialog::updateControls() { const bool haveImages = (imageCounter > 0); createMovieButton->setEnabled(haveImages); imageSizeGroupBox->setEnabled((haveImages == false)); numberOfImagesLabel->setText(QString("Image Count: %1").arg(imageCounter)); } /** * Called when create movie button is pressed. */ void GuiRecordingDialog::slotCreateMovieButton() { const QString movieName(movieNameLineEdit->text()); if (movieName.isEmpty()) { QMessageBox::critical(this, "ERROR", "Movie name is blank."); return; } if (imageCounter <= 0) { QMessageBox::critical(this, "ERROR", "No images (frames) have been captured."); return; } // // Create the movie // switch (getMovieFileType()) { case MOVIE_FILE_TYPE_MPEG_CREATE: createMovieWithMpegCreate(movieName); break; case MOVIE_FILE_TYPE_MPEG1_VTK: createMovieWithMpeg1VTK(); break; case MOVIE_FILE_TYPE_MPEG2_VTK: createMovieWithMpeg2VTK(); break; case MOVIE_FILE_TYPE_AVI_VTK: createMovieWithAviVTK(); case MOVIE_FILE_TYPE_JPEG_IMAGES: QMessageBox::information(this, "INFO", "You will need to use a program such as \n" "Apple's iMovie or Microsoft's Media \n" "encoder to create a movie from the \n" "sequence of images."); break; } } /// get the movie file type GuiRecordingDialog::MOVIE_FILE_TYPE GuiRecordingDialog::getMovieFileType() const { // // Determine the movie file type // const int fileTypeIndex = movieFileTypeComboBox->currentIndex(); const MOVIE_FILE_TYPE movieType = static_cast(movieFileTypeComboBox->itemData(fileTypeIndex).toInt()); return movieType; } /** * create the movie using VTK's MPEG1. */ void GuiRecordingDialog::createMovieWithMpeg1VTK() { #ifdef HAVE_MPEG // // Finish the movie // vtkMpeg1MovieWriter->End(); if (DebugControl::getDebugOn()) { std::cout << "MPEG Writer Error Code: " << vtkMpeg1MovieWriter->GetErrorCode() << std::endl; } // // Cannot append images so delete all captured images // deleteTemporaryImages(); #endif // HAVE_MPEG } /** * create the movie using VTK's MPEG2. */ void GuiRecordingDialog::createMovieWithMpeg2VTK() { #ifdef HAVE_MPEG // // Finish the movie // vtkMpeg2MovieWriter->End(); if (DebugControl::getDebugOn()) { std::cout << "MPEG Writer Error Code: " << vtkMpeg2MovieWriter->GetErrorCode() << std::endl; } // // Cannot append images so delete all captured images // deleteTemporaryImages(); #endif // HAVE_MPEG } /** * create the movie using VTK's AVI. */ void GuiRecordingDialog::createMovieWithAviVTK() { #ifdef HAVE_MPEG #ifdef HAVE_AVI_WRITER // // Finish the movie // vtkAviMovieWriter->End(); // // Cannot append images so delete all captured images // deleteTemporaryImages(); #endif // HAVE_AVI_WRITER #endif // HAVE_MPEG } /** * create the movie using mpeg_create. */ void GuiRecordingDialog::createMovieWithMpegCreate(const QString& movieName) { const int numImages = static_cast(imageNames.size()); const int quality = qualitySpinBox->value(); const QString mpegParamsName("mpeg_encode.mpeg_params"); QFile file(mpegParamsName); if (file.open(QIODevice::WriteOnly)) { QTextStream stream(&file); stream << "PATTERN IBBPBBPBBPBBPBBP" << "\n"; stream << "GOP_SIZE 16" << "\n"; stream << "OUTPUT " << movieName << "\n"; stream << "SLICES_PER_FRAME 1" << "\n"; stream << "INPUT_DIR ." << "\n"; stream << "INPUT" << "\n"; for (int i = 0; i < numImages; i++) { stream << imageNames[i] << "\n"; } stream << "END_INPUT" << "\n"; stream << "BASE_FILE_FORMAT PPM" << "\n"; if (compressTemporaryImages->isChecked()) { stream << "INPUT_CONVERT gunzip -c *" << "\n"; } else { stream << "INPUT_CONVERT *" << "\n"; } stream << "BSEARCH_ALG CROSS2" << "\n"; stream << "PIXEL HALF" << "\n"; stream << "IQSCALE " << quality << "\n"; stream << "PQSCALE " << quality << "\n"; stream << "BQSCALE " << quality << "\n"; stream << "REFERENCE_FRAME ORIGINAL" << "\n"; stream << "RANGE 10" << "\n"; stream << "PSEARCH_ALG LOGARITHMIC" << "\n"; stream << "FRAME_RATE 30" << "\n"; file.close(); #ifdef Q_OS_WIN32 QString msg("We have seen a problem on MS Windows systems that causes\n" "this process to hang if there are about 20 or more frames\n" "in the movie. You can choose to continue and see what happens\n" "or choose to create a command file that you can execute\n" "separately from Caret to create the movie."); QMessageBox msgBox(this); msgBox.setWindowTitle("MS Windows Problem"); msgBox.setText(msg); msgBox.addButton("Continue", QMessageBox::ActionRole); QPushButton* createCommandPushButton = msgBox.addButton("Create Command File", QMessageBox::ActionRole); msgBox.exec(); if (msgBox.clickedButton() == createCommandPushButton) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); const QString fileName("create_movie.bat"); QFile file(fileName); if (file.open(QIODevice::WriteOnly)) { QTextStream stream(&file); QString programName(theMainWindow->getBrainSet()->getCaretHomeDirectory()); programName.append("/bin/mpeg_encode.exe"); stream << programName << " " << mpegParamsName << "\n"; file.close(); } else { QMessageBox::critical(this, "ERROR", "Unable to create command file."); return; } QString msg("The command file \""); msg.append(fileName); msg.append("\" has been created in the directory\n"); msg.append(QDir::currentPath()); msg.append("\n"); msg.append("Run it by double-clicking it or run it from the command line."); QMessageBox::information(this, "Command File Created", msg); QApplication::restoreOverrideCursor(); return; } #endif QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); // // Run the program to convert images into an MPEG movie // BrainModelRunExternalProgram cup("mpeg_encode", QStringList(mpegParamsName), true); try { cup.execute(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); return; } QApplication::restoreOverrideCursor(); theMainWindow->speakText("The movie has been created.", false); } else { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", "Error creating command file for creating movie."); return; } } /** * called when an image size selection is made. */ void GuiRecordingDialog::slotImageSizeComboBox(int item) { const IMAGE_SIZE_TYPE st = static_cast(item); customImageXSpinBox->setEnabled(st == IMAGE_SIZE_TYPE_CUSTOM); customImageYSpinBox->setEnabled(st == IMAGE_SIZE_TYPE_CUSTOM); customSizeLabel->setEnabled(st == IMAGE_SIZE_TYPE_CUSTOM); } /** * add an image to the recording. */ void GuiRecordingDialog::addImageToRecording(const QImage& imageIn) { // // Once an image has been captured, disable the movie type until Reset button pressed // movieFileTypeWidget->setEnabled(false); movieNameWidget->setEnabled(false); // // Make a copy of the image since its size might be modified // QImage image = imageIn; // // Adjust the image size if needed // int newWidth = 0; int newHeight = 0; switch(static_cast(imageSizeComboBox->currentIndex())) { case IMAGE_SIZE_TYPE_CARET_WINDOW: break; case IMAGE_SIZE_TYPE_320x240: newWidth = 320; newHeight = 240; break; case IMAGE_SIZE_TYPE_352x240: newWidth = 352; newHeight = 240; break; case IMAGE_SIZE_TYPE_640x480: newWidth = 640; newHeight = 480; break; case IMAGE_SIZE_TYPE_720x480: newWidth = 720; newHeight = 480; break; case IMAGE_SIZE_TYPE_CUSTOM: newWidth = customImageXSpinBox->value(); newHeight = customImageYSpinBox->value(); break; } if ((newWidth > 0) && (newHeight > 0)) { image = image.scaled(newWidth, newHeight); } // // Add the image to the movie // switch(getMovieFileType()) { case MOVIE_FILE_TYPE_MPEG_CREATE: addImageToMpegCreate(image); break; case MOVIE_FILE_TYPE_MPEG1_VTK: addImageToMpeg1VTK(image); break; case MOVIE_FILE_TYPE_MPEG2_VTK: addImageToMpeg2VTK(image); break; case MOVIE_FILE_TYPE_AVI_VTK: addImageToAviVTK(image); break; case MOVIE_FILE_TYPE_JPEG_IMAGES: addImageToJpeg(image); break; } imageCounter++; updateControls(); } /** * convert a QImage into VTK's ImageData (user must delete returned vtkImageData object) */ vtkImageData* GuiRecordingDialog::convertQImagetoVTKImageData(const QImage& image) { const int width = image.width(); const int height = image.height(); vtkImageData* vtkImage = vtkImageData::New(); vtkImage->SetDimensions(width, height, 1); vtkImage->SetScalarType(VTK_UNSIGNED_CHAR); vtkImage->SetNumberOfScalarComponents(3); vtkImage->AllocateScalars(); unsigned char* vtkData = static_cast(vtkImage->GetScalarPointer()); // // Copy the image data // //for (int j = 0; j < height; j++) { for (int j = (height - 1); j >= 0; j--) { for (int i = 0; i < width; i++) { const QColor rgb = QColor(image.pixel(i, j)); const unsigned char r = static_cast(rgb.red()); const unsigned char g = static_cast(rgb.green()); const unsigned char b = static_cast(rgb.blue()); *vtkData++ = r; *vtkData++ = g; *vtkData++ = b; } } return vtkImage; } /** * add image to movie being created with VTK's MPEG1. */ void GuiRecordingDialog::addImageToMpeg1VTK(const QImage& image) { #ifdef HAVE_MPEG const QString fileName(movieNameLineEdit->text()); vtkImageData* vtkImage = convertQImagetoVTKImageData(image); if (vtkMpeg1MovieWriter == NULL) { vtkMpeg1MovieWriter = vtkMPEG1Writer::New(); vtkMpeg1MovieWriter->DebugOn(); vtkMpeg1MovieWriter->SetFileName(movieNameLineEdit->text().toAscii().constData()); vtkMpeg1MovieWriter->SetInput(vtkImage); vtkMpeg1MovieWriter->Start(); } vtkMpeg1MovieWriter->SetInput(vtkImage); vtkMpeg1MovieWriter->Write(); vtkImage->Delete(); if (DebugControl::getDebugOn()) { std::cout << "MPEG Writer Error Code: " << vtkMpeg1MovieWriter->GetErrorCode() << std::endl; } #endif // HAVE_MPEG } /** * add image to movie being created with VTK's MPEG2. */ void GuiRecordingDialog::addImageToMpeg2VTK(const QImage& image) { #ifdef HAVE_MPEG const QString fileName(movieNameLineEdit->text()); vtkImageData* vtkImage = convertQImagetoVTKImageData(image); if (vtkMpeg2MovieWriter == NULL) { vtkMpeg2MovieWriter = vtkMPEG2Writer::New(); vtkMpeg2MovieWriter->DebugOn(); vtkMpeg2MovieWriter->SetFileName(fileName.toAscii().constData()); vtkMpeg2MovieWriter->SetInput(vtkImage); vtkMpeg2MovieWriter->Start(); } vtkMpeg2MovieWriter->SetInput(vtkImage); vtkMpeg2MovieWriter->Write(); vtkImage->Delete(); if (DebugControl::getDebugOn()) { std::cout << "MPEG Writer Error Code: " << vtkMpeg2MovieWriter->GetErrorCode() << std::endl; } #endif // HAVE_MPEG } /** * add image to movie being created with VTK's AVI. */ void GuiRecordingDialog::addImageToAviVTK(const QImage& /*image*/) { #ifdef HAVE_MPEG #ifdef HAVE_AVI_WRITER vtkImageData* vtkImage = convertQImagetoVTKImageData(image); if (vtkAviMovieWriter == NULL) { vtkAviMovieWriter = vtkAVIWriter::New(); vtkAviMovieWriter->DebugOn(); vtkAviMovieWriter->SetFileName(movieNameLineEdit->text().toAscii().constData()); vtkAviMovieWriter->SetInput(vtkImage); vtkAviMovieWriter->Start(); } /* * vtkJPEGWriter* jpeg = vtkJPEGWriter::New(); * jpeg->SetFileName("jpeg.jpg"); * jpeg->SetInput(vtkImage); * jpeg->Write(); */ vtkAviMovieWriter->SetInput(vtkImage); vtkAviMovieWriter->Write(); vtkImage->Delete(); #endif // HAVE_AVI_WRITER #endif // HAVE_MPEG } /** * add image to movie for JPEG images. */ void GuiRecordingDialog::addImageToJpeg(const QImage& image) { // // Create name of image // const QString outputName( QString().sprintf("record_image_%06d.jpg", static_cast(imageCounter))); // // Write the image // QImageWriter writer(outputName); writer.setFormat("JPG"); writer.setQuality(100); if (writer.write(image) == false) { QMessageBox::critical(this, "ERROR", "Error writing " + outputName); return; } imageNames.push_back(outputName); } /** * add image to movie being created with mpeg_create. */ void GuiRecordingDialog::addImageToMpegCreate(const QImage& image) { // // Buffers for normal and compressed images // static char* imageBuffer = NULL; static int imageBufferSize = -1; // // width and height of the image // const int imageWidth = image.width(); const int imageHeight = image.height(); QString widthString(QString::number(imageWidth)); QString heightString(QString::number(imageHeight)); // // Buffer size needed to store the image in ppm format // const int bufferSizeNeeded = (imageWidth * imageHeight * 3) + 1000; // // Adjust buffer size if needed // if ((imageBuffer == NULL) || (bufferSizeNeeded > imageBufferSize)) { if (imageBuffer != NULL) { delete[] imageBuffer; } imageBufferSize = bufferSizeNeeded; imageBuffer = new char[imageBufferSize]; } // // index to buffer // int bufferIndex = 0; // // Add "P6" to indicate binary PPM // imageBuffer[bufferIndex++] = 'P'; imageBuffer[bufferIndex++] = '6'; imageBuffer[bufferIndex++] = '\n'; // // Add image width and height // for (int i = 0; i < widthString.length(); i++) { imageBuffer[bufferIndex++] = widthString[i].toLatin1(); } imageBuffer[bufferIndex++] = ' '; for (int i = 0; i < heightString.length(); i++) { imageBuffer[bufferIndex++] = heightString[i].toLatin1(); } imageBuffer[bufferIndex++] = '\n'; // // Add in max value of pixel // imageBuffer[bufferIndex++] = '2'; imageBuffer[bufferIndex++] = '5'; imageBuffer[bufferIndex++] = '5'; imageBuffer[bufferIndex++] = '\n'; // // Add in the pixels // for (int j = 0; j < imageHeight; j++) { for (int i = 0; i < imageWidth; i++) { QRgb rgb = image.pixel(i, j); imageBuffer[bufferIndex++] = static_cast(qRed(rgb)); imageBuffer[bufferIndex++] = static_cast(qGreen(rgb)); imageBuffer[bufferIndex++] = static_cast(qBlue(rgb)); } } // // Check to see if images should be compressed // const bool useCompressedData = compressTemporaryImages->isChecked(); // // Create name of image // QString outputName; outputName.sprintf("record_image_%06d.ppm", static_cast(imageCounter)); if (useCompressedData) { outputName.append(".gz"); } // // write the image data // if (useCompressedData) { gzFile gzipImageFile = gzopen(outputName.toAscii().constData(), "w"); if (gzipImageFile == NULL) { QString msg("Error writing image "); msg.append(outputName); QMessageBox::critical(this, "ERROR", msg); return; } gzwrite(gzipImageFile, imageBuffer, bufferIndex); gzclose(gzipImageFile); } else { std::ofstream ppmImageFile(outputName.toAscii().constData()); if (!ppmImageFile) { QString msg("Error writing image "); msg.append(outputName); QMessageBox::critical(this, "ERROR", msg); return; } ppmImageFile.write(imageBuffer, bufferIndex); ppmImageFile.close(); } for (int i = 0; i < duplicateSpinBox->value(); i++) { imageNames.push_back(outputName); } } /** * Delete any temporary images. */ void GuiRecordingDialog::deleteTemporaryImages() { #ifdef HAVE_MPEG if (vtkMpeg1MovieWriter != NULL) { vtkMpeg1MovieWriter->Delete(); vtkMpeg1MovieWriter = NULL; } if (vtkMpeg2MovieWriter != NULL) { vtkMpeg2MovieWriter->Delete(); vtkMpeg2MovieWriter = NULL; } #ifdef HAVE_AVI_WRITER if (vtkAviMovieWriter != NULL) { vtkAviMovieWriter->Delete(); vtkAviMovieWriter = NULL; } #endif // HAVE_AVI_WRITER #endif // HAVE_MPEG for (unsigned int i = 0; i < imageNames.size(); i++) { QFile::remove(imageNames[i]); } imageCounter = 0; imageNames.clear(); movieNameWidget->setEnabled(true); movieFileTypeWidget->setEnabled(true); updateControls(); } caret-5.6.4~dfsg.1.orig/caret/GuiPreviousSpecFileComboBox.h0000664000175000017500000000400411572067322023353 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_PREVIOUS_SPEC_FILE_COMBO_BOX_H__ #define __GUI_PREVIOUS_SPEC_FILE_COMBO_BOX_H__ #include #include "PreferencesFile.h" /// combo box for selecting previously loaded spec files class GuiPreviousSpecFileComboBox : public QComboBox { Q_OBJECT public: /// Constructor. GuiPreviousSpecFileComboBox(QWidget*parent, const std::vector& specFilesIn); /// Constructor GuiPreviousSpecFileComboBox(QWidget*parent, const PreferencesFile* pf); /// Destructor ~GuiPreviousSpecFileComboBox(); signals: /// emitted when a previous spec file is selected void specFileSelected(const QString &); protected slots: /// called when a combo box item is selected void slotItemSelected(int item); protected: /// initialize combo box void initializeComboBox(const std::vector& specFileNames); /// names of spec files std::vector previousSpecFiles; }; #endif // __GUI_PREVIOUS_SPEC_FILE_COMBO_BOX_H__ caret-5.6.4~dfsg.1.orig/caret/GuiPreviousSpecFileComboBox.cxx0000664000175000017500000000564611572067322023743 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "GuiPreviousSpecFileComboBox.h" #include "FileUtilities.h" /** * Constructor. */ GuiPreviousSpecFileComboBox::GuiPreviousSpecFileComboBox(QWidget*parent, const std::vector& specFilesIn) : QComboBox(parent) { initializeComboBox(specFilesIn); } /** * Constructor. */ GuiPreviousSpecFileComboBox::GuiPreviousSpecFileComboBox(QWidget*parent, const PreferencesFile* pf) : QComboBox(parent) { std::vector specFileNames; if (pf != NULL) { pf->getRecentSpecFiles(specFileNames); } initializeComboBox(specFileNames); } /** * Destructor. */ GuiPreviousSpecFileComboBox::~GuiPreviousSpecFileComboBox() { } /** * initialize combo box. */ void GuiPreviousSpecFileComboBox::initializeComboBox(const std::vector& specFileNames) { previousSpecFiles = specFileNames; QObject::connect(this, SIGNAL(activated(int)), this, SLOT(slotItemSelected(int))); const int numSpecFiles = static_cast(previousSpecFiles.size()); // // Find longest file name // int longestNameLength = -1; for (int i = 0; i < numSpecFiles; i++) { longestNameLength = std::max(longestNameLength, static_cast(FileUtilities::basename(previousSpecFiles[i]).length())); } // // Load the combo box // addItem("Choose Recent Spec File"); for (int i = 0; i < numSpecFiles; i++) { // // Maximum path length various due to differences in file names // const int maxPathLength = longestNameLength - FileUtilities::basename(previousSpecFiles[i]).length() + 25; addItem(FileUtilities::rearrangeFileName(previousSpecFiles[i], maxPathLength)); } } /** * called when a combo box item is selected. */ void GuiPreviousSpecFileComboBox::slotItemSelected(int item) { if (item > 0) { QString name = previousSpecFiles[item - 1]; emit specFileSelected(name); } } caret-5.6.4~dfsg.1.orig/caret/GuiPreferencesDialog.h0000664000175000017500000001070211572067322022056 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_PREFERENCES_DIALOG_H__ #define __GUI_PREFERENCES_DIALOG_H__ #include #include "WuQDialog.h" class QCheckBox; class QComboBox; class QDoubleSpinBox; class QLineEdit; class QSpinBox; class WuQWidgetGroup; /// Dialog used to set user preferences class GuiPreferencesDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiPreferencesDialog(QWidget* parent); /// Destructor ~GuiPreferencesDialog(); private slots: /// called when apply button is pressed void applyButtonSlot(); /// called by reset display lists push button void slotResetDisplayListsPushButton(); // called to set background color void slotSetBackgroundColor(); // called to set foreground color void slotSetForegroundColor(); private: // load preferences into the dialog void loadPreferences(); // create the debug section QWidget* createDebugSection(); // create the file section QWidget* createFileSection(); // create the misc section QWidget* createMiscSection(); // create the opengl section QWidget* createOpenglSection(); /// surface background color red spin box QSpinBox* surfaceBackgroundRedSpinBox; /// surface background color green spin box QSpinBox* surfaceBackgroundGreenSpinBox; /// surface background color blue spin box QSpinBox* surfaceBackgroundBlueSpinBox; /// surface foreground color red spin box QSpinBox* surfaceForegroundRedSpinBox; /// surface foreground color green spin box QSpinBox* surfaceForegroundGreenSpinBox; /// surface foreground color blue spin box QSpinBox* surfaceForegroundBlueSpinBox; /// light position X double spin box QDoubleSpinBox* lightPositionXDoubleSpinBox; /// light position Y double spin box QDoubleSpinBox* lightPositionYDoubleSpinBox; /// light position Z double spin box QDoubleSpinBox* lightPositionZDoubleSpinBox; /// mouse speed double spin box QDoubleSpinBox* mouseSpeedDoubleSpinBox; /// iterative update check box QSpinBox* iterUpdateSpinBox; /// debug on checkbox QCheckBox* debugOnCheckBox; /// debug node number QSpinBox* debugNodeSpinBox; /// test flag 1 on checkbox QCheckBox* testFlag1CheckBox; /// test flag 2 on checkbox QCheckBox* testFlag2CheckBox; /// web browser line edit QLineEdit* webBrowserLineEdit; /// image capture type combo box QComboBox* imageCaptureTypeComboBox; /// number of threads spin box QSpinBox* numberOfThreadsSpinBox; /// number of spec file read thread QSpinBox* numberOfSpecFileReadThreadsSpinBox; /// floating point precision spin box QSpinBox* floatPrecisionSpinBox; /// file write data type combo box std::vector fileWriteDataTypeComboBox; /// SuMS hosts line edit QLineEdit* sumsHostsLineEdit; /// display lists enabled check box QCheckBox* displayListsOnCheckBox; /// random seed check box QCheckBox* randomSeedCheckBox; /// random seed spin box QSpinBox* randomSeedSpinBox; /// widget group for all widgets WuQWidgetGroup* allWidgetsGroup; /// OpenGL debugging check box QCheckBox* openGLDebugCheckBox; }; #endif caret-5.6.4~dfsg.1.orig/caret/GuiPreferencesDialog.cxx0000664000175000017500000007307011572067322022440 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "BrainSet.h" #include "DebugControl.h" #include "GuiBrainModelOpenGL.h" #include "GuiColorSelectionDialog.h" #include "GuiMainWindow.h" #include "GuiPreferencesDialog.h" #include "QtUtilities.h" #include "SystemUtilities.h" #include "WuQWidgetGroup.h" #include "global_variables.h" /** * Constructor. */ GuiPreferencesDialog::GuiPreferencesDialog(QWidget* parent) : WuQDialog(parent) { setWindowTitle("Caret Preferences"); // // Widget group for all widgets that get updated // allWidgetsGroup = new WuQWidgetGroup(this); // // Create the tab pages // QTabWidget* tabWidget = new QTabWidget; tabWidget->addTab(createDebugSection(), "Debug"); tabWidget->addTab(createFileSection(), "File"); tabWidget->addTab(createMiscSection(), "Misc"); tabWidget->addTab(createOpenglSection(), "OpenGL"); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); // // Apply pushbutton // QPushButton* applyButton = new QPushButton("Apply"); buttonsLayout->addWidget(applyButton); QObject::connect(applyButton, SIGNAL(clicked()), this, SLOT(applyButtonSlot())); // // Close button connects to QDialogs close() slot. // QPushButton* closeButton = new QPushButton("Close"); buttonsLayout->addWidget(closeButton); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); // // Force buttons to be same size // QtUtilities::makeButtonsSameSize(applyButton, closeButton); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->addWidget(tabWidget); dialogLayout->addLayout(buttonsLayout); loadPreferences(); } /** * create the debug section. */ QWidget* GuiPreferencesDialog::createDebugSection() { // // Debug enable // debugOnCheckBox = new QCheckBox("Debug Enabled"); QObject::connect(debugOnCheckBox, SIGNAL(toggled(bool)), this, SLOT(applyButtonSlot())); // // Debug Node // QLabel* debugNodeLabel = new QLabel("DebugNode"); debugNodeSpinBox = new QSpinBox; debugNodeSpinBox->setMinimum(-1); debugNodeSpinBox->setMaximum(std::numeric_limits::max()); debugNodeSpinBox->setSingleStep(1); QObject::connect(debugNodeSpinBox, SIGNAL(valueChanged(int)), this, SLOT(applyButtonSlot())); // // Test Flag 1 // testFlag1CheckBox = new QCheckBox("Test Flag 1"); QObject::connect(testFlag1CheckBox, SIGNAL(toggled(bool)), this, SLOT(applyButtonSlot())); // // Test Flag 2 // testFlag2CheckBox = new QCheckBox("Test Flag 2"); QObject::connect(testFlag2CheckBox, SIGNAL(toggled(bool)), this, SLOT(applyButtonSlot())); // // Enable OpenGL debugging // openGLDebugCheckBox = new QCheckBox("OpenGL Debugging"); QObject::connect(openGLDebugCheckBox, SIGNAL(toggled(bool)), this, SLOT(applyButtonSlot())); // // updatable widget group // allWidgetsGroup->addWidget(debugOnCheckBox); allWidgetsGroup->addWidget(debugNodeSpinBox); allWidgetsGroup->addWidget(testFlag1CheckBox); allWidgetsGroup->addWidget(testFlag2CheckBox); allWidgetsGroup->addWidget(openGLDebugCheckBox); // // Widget and layout // QGridLayout* gridLayout = new QGridLayout; gridLayout->addWidget(debugOnCheckBox, 0, 0, 1, 2, Qt::AlignLeft); gridLayout->addWidget(debugNodeLabel, 1, 0); gridLayout->addWidget(debugNodeSpinBox, 1, 1); gridLayout->addWidget(testFlag1CheckBox, 2, 0, 1, 2, Qt::AlignLeft); gridLayout->addWidget(testFlag2CheckBox, 3, 0, 1, 2, Qt::AlignLeft); gridLayout->addWidget(openGLDebugCheckBox, 4, 0, 1, 2, Qt::AlignLeft); QHBoxLayout* layout = new QHBoxLayout; layout->addLayout(gridLayout); layout->addStretch(); QWidget* w = new QWidget; QVBoxLayout* vertLayout = new QVBoxLayout(w); vertLayout->addLayout(layout); vertLayout->addStretch(); return w; } /** * create the file section. */ QWidget* GuiPreferencesDialog::createFileSection() { // // Number of spec file data file reading threads // QLabel* fileReadThreadsLabel = new QLabel("File Reading Threads"); numberOfSpecFileReadThreadsSpinBox = new QSpinBox; numberOfSpecFileReadThreadsSpinBox->setMinimum(1); numberOfSpecFileReadThreadsSpinBox->setMaximum(4096); numberOfSpecFileReadThreadsSpinBox->setSingleStep(1); QObject::connect(numberOfSpecFileReadThreadsSpinBox, SIGNAL(valueChanged(int)), this, SLOT(applyButtonSlot())); // // Floating point precision for text files // QLabel* floatPrecisionLabel = new QLabel("Text File Float Precision"); floatPrecisionSpinBox = new QSpinBox; floatPrecisionSpinBox->setMinimum(1); floatPrecisionSpinBox->setMaximum(1024); floatPrecisionSpinBox->setSingleStep(1); QObject::connect(floatPrecisionSpinBox, SIGNAL(valueChanged(int)), this, SLOT(applyButtonSlot())); // // Create the file format combo boxes // QGroupBox* fileFormatGroupBox = new QGroupBox("File Write Format"); QGridLayout* formatGridLayout = new QGridLayout(fileFormatGroupBox); std::vector fileFormats; std::vector fileFormatNames; AbstractFile::getFileFormatTypesAndNames(fileFormats, fileFormatNames); const int numberOfFormats = static_cast(fileFormats.size()); for (int i = 0; i < numberOfFormats; i++) { QLabel* label = new QLabel(""); if (i == 0) { label->setText("Highest Priority"); } else if (i == (numberOfFormats - 1)) { label->setText("Lowest Priority"); } QComboBox* comboBox = new QComboBox; QObject::connect(comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(applyButtonSlot())); formatGridLayout->addWidget(label, i, 0); formatGridLayout->addWidget(comboBox, i, 1); comboBox->blockSignals(true); for (int j = 0; j < numberOfFormats; j++) { comboBox->addItem(fileFormatNames[j], QVariant(static_cast(fileFormats[j]))); } comboBox->setToolTip( "Changing this will not have an effect\n" "until the next time Caret is started."); comboBox->blockSignals(false); fileWriteDataTypeComboBox.push_back(comboBox); allWidgetsGroup->addWidget(comboBox); } // // updatable widget group // allWidgetsGroup->addWidget(numberOfSpecFileReadThreadsSpinBox); allWidgetsGroup->addWidget(floatPrecisionSpinBox); // // widget and layout // QWidget* w = new QWidget; QGridLayout* gridLayout = new QGridLayout; gridLayout->addWidget(fileReadThreadsLabel, 0, 0); gridLayout->addWidget(numberOfSpecFileReadThreadsSpinBox, 0, 1); gridLayout->addWidget(floatPrecisionLabel, 1, 0); gridLayout->addWidget(floatPrecisionSpinBox, 1, 1); QHBoxLayout* leftLayout = new QHBoxLayout; leftLayout->addLayout(gridLayout); leftLayout->addStretch(); QVBoxLayout* layout = new QVBoxLayout(w); layout->addLayout(leftLayout); layout->addWidget(fileFormatGroupBox, 0, Qt::AlignLeft); layout->addStretch(); return w; } /** * create the misc section. */ QWidget* GuiPreferencesDialog::createMiscSection() { // // Mouse Speed // QLabel* mouseSpeedLabel = new QLabel("Mouse Speed"); mouseSpeedDoubleSpinBox = new QDoubleSpinBox; mouseSpeedDoubleSpinBox->setMinimum(0.0); mouseSpeedDoubleSpinBox->setMaximum(5000000.0); mouseSpeedDoubleSpinBox->setSingleStep(1); mouseSpeedDoubleSpinBox->setDecimals(3); QObject::connect(mouseSpeedDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(applyButtonSlot())); // // Iterative update // QLabel* iterativeUpdateLabel = new QLabel("Iterative Update"); iterUpdateSpinBox = new QSpinBox; iterUpdateSpinBox->setMinimum(0); iterUpdateSpinBox->setMaximum(5000000); iterUpdateSpinBox->setSingleStep(5); QObject::connect(iterUpdateSpinBox, SIGNAL(valueChanged(int)), this, SLOT(applyButtonSlot())); // // Maximum number of threads // const int numCPU = SystemUtilities::getNumberOfProcessors(); const QString threadStr("Number of Threads (" + QString::number(numCPU) + " CPUs)"); QLabel* numberOfThreadsLabel = new QLabel(threadStr); numberOfThreadsSpinBox = new QSpinBox; numberOfThreadsSpinBox->setMinimum(0); numberOfThreadsSpinBox->setMaximum(numCPU * 4); numberOfThreadsSpinBox->setSingleStep(1); QObject::connect(numberOfThreadsSpinBox, SIGNAL(valueChanged(int)), this, SLOT(applyButtonSlot())); if (DebugControl::getDebugOn()) { numberOfThreadsLabel->show(); numberOfThreadsSpinBox->show(); } else { numberOfThreadsLabel->hide(); numberOfThreadsSpinBox->hide(); } // // Random seed // QString randHelpText = "If the check box is checked, the value in the box to the right will\n" "be used to set the \"seed\" for the random number generator at the \n" "time Caret is started or when the \"Apply\" button on this dialog\n" "is pressed. If not checked, Caret will set the seed to the number\n" "of seconds since 1970 at the time Caret IS started. If you choose\n" "to use a specific seed, that will result in the random number generator\n" "generating the same sequence of numbers when the \"rand()\" function\n" "is called."; randomSeedCheckBox = new QCheckBox("Random Seed"); QObject::connect(randomSeedCheckBox, SIGNAL(toggled(bool)), this, SLOT(applyButtonSlot())); randomSeedCheckBox->setToolTip(randHelpText); randomSeedSpinBox = new QSpinBox; randomSeedSpinBox->setMinimum(1); randomSeedSpinBox->setMaximum(std::numeric_limits::max()); randomSeedSpinBox->setSingleStep(1); QObject::connect(randomSeedSpinBox, SIGNAL(valueChanged(int)), this, SLOT(applyButtonSlot())); randomSeedSpinBox->setToolTip(randHelpText); // // Sums Hosts // QLabel* sumsHostLabel = new QLabel("SuMS Hosts"); sumsHostsLineEdit = new QLineEdit; sumsHostsLineEdit->setToolTip( "Separate multiple\n" "hosts with commas."); QObject::connect(sumsHostsLineEdit, SIGNAL(returnPressed()), this, SLOT(applyButtonSlot())); // // Web browser (do not show for Mac or Windows // QLabel* webBrowserLabel = new QLabel("Web Browser"); webBrowserLineEdit = new QLineEdit; webBrowserLabel->hide(); webBrowserLineEdit->hide(); #ifndef Q_OS_WIN32 #ifndef Q_OS_MACX webBrowserLabel->show(); webBrowserLineEdit->show(); #endif // Q_OS_MACX #endif // Q_OS_WIN32 // // updatable widget group // allWidgetsGroup->addWidget(iterUpdateSpinBox); allWidgetsGroup->addWidget(mouseSpeedDoubleSpinBox); allWidgetsGroup->addWidget(numberOfThreadsSpinBox); allWidgetsGroup->addWidget(randomSeedCheckBox); allWidgetsGroup->addWidget(randomSeedSpinBox); allWidgetsGroup->addWidget(sumsHostsLineEdit); allWidgetsGroup->addWidget(webBrowserLineEdit); // // Widget and label // QGridLayout* gridLayout = new QGridLayout; gridLayout->addWidget(iterativeUpdateLabel, 0, 0); gridLayout->addWidget(iterUpdateSpinBox, 0, 1); gridLayout->addWidget(mouseSpeedLabel, 1, 0); gridLayout->addWidget(mouseSpeedDoubleSpinBox, 1, 1); gridLayout->addWidget(numberOfThreadsLabel, 2, 0); gridLayout->addWidget(numberOfThreadsSpinBox, 2, 1); gridLayout->addWidget(randomSeedCheckBox, 3, 0); gridLayout->addWidget(randomSeedSpinBox, 3, 1); gridLayout->addWidget(sumsHostLabel, 4, 0); gridLayout->addWidget(sumsHostsLineEdit, 4, 1); gridLayout->addWidget(webBrowserLabel, 5, 0); gridLayout->addWidget(webBrowserLineEdit, 5, 1); QHBoxLayout* layout = new QHBoxLayout; layout->addLayout(gridLayout); layout->addStretch(); QWidget* w = new QWidget; QVBoxLayout* vertLayout = new QVBoxLayout(w); vertLayout->addLayout(layout); vertLayout->addStretch(); return w; } /** * called to set background color. */ void GuiPreferencesDialog::slotSetBackgroundColor() { GuiColorSelectionDialog csd(this, "Background Color", false, false, false, false); csd.setColor(static_cast(surfaceBackgroundRedSpinBox->value()), static_cast(surfaceBackgroundGreenSpinBox->value()), static_cast(surfaceBackgroundBlueSpinBox->value()), 255); if (csd.exec() == GuiColorSelectionDialog::Accepted) { unsigned char r, g, b, a; float pointSize, lineSize; ColorFile::ColorStorage::SYMBOL symbol; csd.getColorInformation(r, g, b, a, pointSize, lineSize, symbol); allWidgetsGroup->blockSignals(true); surfaceBackgroundRedSpinBox->setValue(r); surfaceBackgroundGreenSpinBox->setValue(g); surfaceBackgroundBlueSpinBox->setValue(b); allWidgetsGroup->blockSignals(true); applyButtonSlot(); } } /** * called to set foreground color. */ void GuiPreferencesDialog::slotSetForegroundColor() { GuiColorSelectionDialog csd(this, "Background Color", false, false, false, false); csd.setColor(static_cast(surfaceForegroundRedSpinBox->value()), static_cast(surfaceForegroundGreenSpinBox->value()), static_cast(surfaceForegroundBlueSpinBox->value()), 255); if (csd.exec() == GuiColorSelectionDialog::Accepted) { unsigned char r, g, b, a; float pointSize, lineSize; ColorFile::ColorStorage::SYMBOL symbol; csd.getColorInformation(r, g, b, a, pointSize, lineSize, symbol); allWidgetsGroup->blockSignals(true); surfaceForegroundRedSpinBox->setValue(r); surfaceForegroundGreenSpinBox->setValue(g); surfaceForegroundBlueSpinBox->setValue(b); allWidgetsGroup->blockSignals(true); applyButtonSlot(); } } /** * create the opengl section. */ QWidget* GuiPreferencesDialog::createOpenglSection() { // // Surface Background Color // QPushButton* surfaceBackgroundPushButton = new QPushButton("Background Color..."); surfaceBackgroundPushButton->setAutoDefault(false); surfaceBackgroundPushButton->setToolTip("Press this button to set\n" "the background color."); QObject::connect(surfaceBackgroundPushButton, SIGNAL(clicked()), this, SLOT(slotSetBackgroundColor())); surfaceBackgroundRedSpinBox = new QSpinBox; surfaceBackgroundRedSpinBox->setMinimum(0); surfaceBackgroundRedSpinBox->setMaximum(255); surfaceBackgroundRedSpinBox->setSingleStep(1); QObject::connect(surfaceBackgroundRedSpinBox, SIGNAL(valueChanged(int)), this, SLOT(applyButtonSlot())); surfaceBackgroundGreenSpinBox = new QSpinBox; surfaceBackgroundGreenSpinBox->setMinimum(0); surfaceBackgroundGreenSpinBox->setMaximum(255); surfaceBackgroundGreenSpinBox->setSingleStep(1); QObject::connect(surfaceBackgroundGreenSpinBox, SIGNAL(valueChanged(int)), this, SLOT(applyButtonSlot())); surfaceBackgroundBlueSpinBox = new QSpinBox; surfaceBackgroundBlueSpinBox->setMinimum(0); surfaceBackgroundBlueSpinBox->setMaximum(255); surfaceBackgroundBlueSpinBox->setSingleStep(1); QObject::connect(surfaceBackgroundBlueSpinBox, SIGNAL(valueChanged(int)), this, SLOT(applyButtonSlot())); // // Surface Foreground Color // QPushButton* surfaceForegroundPushButton = new QPushButton("Foreground Color..."); surfaceForegroundPushButton->setAutoDefault(false); surfaceForegroundPushButton->setToolTip("Press this button to set\n" "the foreground color."); QObject::connect(surfaceForegroundPushButton, SIGNAL(clicked()), this, SLOT(slotSetForegroundColor())); surfaceForegroundRedSpinBox = new QSpinBox; surfaceForegroundRedSpinBox->setMinimum(0); surfaceForegroundRedSpinBox->setMaximum(255); surfaceForegroundRedSpinBox->setSingleStep(1); surfaceForegroundGreenSpinBox = new QSpinBox; surfaceForegroundGreenSpinBox->setMinimum(0); surfaceForegroundGreenSpinBox->setMaximum(255); surfaceForegroundGreenSpinBox->setSingleStep(1); surfaceForegroundBlueSpinBox = new QSpinBox; surfaceForegroundBlueSpinBox->setMinimum(0); surfaceForegroundBlueSpinBox->setMaximum(255); surfaceForegroundBlueSpinBox->setSingleStep(1); // // Light Position // QLabel* lightPositionLabel = new QLabel("Light Position"); lightPositionXDoubleSpinBox = new QDoubleSpinBox; lightPositionXDoubleSpinBox->setMinimum(-std::numeric_limits::max()); lightPositionXDoubleSpinBox->setMaximum(std::numeric_limits::max()); lightPositionXDoubleSpinBox->setSingleStep(1.0); lightPositionXDoubleSpinBox->setDecimals(3); QObject::connect(lightPositionXDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(applyButtonSlot())); lightPositionYDoubleSpinBox = new QDoubleSpinBox; lightPositionYDoubleSpinBox->setMinimum(-std::numeric_limits::max()); lightPositionYDoubleSpinBox->setMaximum(std::numeric_limits::max()); lightPositionYDoubleSpinBox->setSingleStep(1.0); lightPositionYDoubleSpinBox->setDecimals(3); QObject::connect(lightPositionYDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(applyButtonSlot())); lightPositionZDoubleSpinBox = new QDoubleSpinBox; lightPositionZDoubleSpinBox->setMinimum(-std::numeric_limits::max()); lightPositionZDoubleSpinBox->setMaximum(std::numeric_limits::max()); lightPositionZDoubleSpinBox->setSingleStep(1.0); lightPositionZDoubleSpinBox->setDecimals(3); QObject::connect(lightPositionZDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(applyButtonSlot())); // // Image capture // QLabel* imageCaptureLabel = new QLabel("Image Capture"); imageCaptureTypeComboBox = new QComboBox; imageCaptureTypeComboBox->insertItem(PreferencesFile::IMAGE_CAPTURE_PIXMAP, "Use Pixmap"); imageCaptureTypeComboBox->insertItem(PreferencesFile::IMAGE_CAPTURE_OPENGL_BUFFER, "Use OpenGL Buffer"); // // Display lists // displayListsOnCheckBox = new QCheckBox("Display Lists Enabled"); QObject::connect(displayListsOnCheckBox, SIGNAL(toggled(bool)), this, SLOT(applyButtonSlot())); QPushButton* resetDisplayListsPushButton = new QPushButton("Reset Lists"); resetDisplayListsPushButton->setAutoDefault(false); QObject::connect(resetDisplayListsPushButton, SIGNAL(clicked()), this, SLOT(slotResetDisplayListsPushButton())); // // updatable widget group // allWidgetsGroup->addWidget(surfaceBackgroundRedSpinBox); allWidgetsGroup->addWidget(surfaceBackgroundGreenSpinBox); allWidgetsGroup->addWidget(surfaceBackgroundBlueSpinBox); allWidgetsGroup->addWidget(surfaceForegroundRedSpinBox); allWidgetsGroup->addWidget(surfaceForegroundGreenSpinBox); allWidgetsGroup->addWidget(surfaceForegroundBlueSpinBox); allWidgetsGroup->addWidget(lightPositionXDoubleSpinBox); allWidgetsGroup->addWidget(lightPositionYDoubleSpinBox); allWidgetsGroup->addWidget(lightPositionZDoubleSpinBox); allWidgetsGroup->addWidget(imageCaptureTypeComboBox); allWidgetsGroup->addWidget(displayListsOnCheckBox); // // Widget and line edit // QGridLayout* gridLayout = new QGridLayout; gridLayout->addWidget(surfaceBackgroundPushButton, 0, 0); gridLayout->addWidget(surfaceBackgroundRedSpinBox, 0, 1); gridLayout->addWidget(surfaceBackgroundGreenSpinBox, 0, 2); gridLayout->addWidget(surfaceBackgroundBlueSpinBox, 0, 3); gridLayout->addWidget(surfaceForegroundPushButton, 1, 0); gridLayout->addWidget(surfaceForegroundRedSpinBox, 1, 1); gridLayout->addWidget(surfaceForegroundGreenSpinBox, 1, 2); gridLayout->addWidget(surfaceForegroundBlueSpinBox, 1, 3); gridLayout->addWidget(lightPositionLabel, 2, 0); gridLayout->addWidget(lightPositionXDoubleSpinBox, 2, 1); gridLayout->addWidget(lightPositionYDoubleSpinBox, 2, 2); gridLayout->addWidget(lightPositionZDoubleSpinBox, 2, 3); gridLayout->addWidget(imageCaptureLabel, 3, 0); gridLayout->addWidget(imageCaptureTypeComboBox, 3, 1, 1, 3, Qt::AlignLeft); gridLayout->addWidget(displayListsOnCheckBox, 4, 0); gridLayout->addWidget(resetDisplayListsPushButton, 4, 1, 1, 3, Qt::AlignLeft); QWidget* w = new QWidget; QVBoxLayout* vertLayout = new QVBoxLayout(w); vertLayout->addLayout(gridLayout); vertLayout->addStretch(); return w; } /** * load preferences into dialog */ void GuiPreferencesDialog::loadPreferences() { allWidgetsGroup->blockSignals(true); PreferencesFile* pf = theMainWindow->getBrainSet()->getPreferencesFile(); unsigned char r, g, b; pf->getSurfaceBackgroundColor(r, g, b); surfaceBackgroundRedSpinBox->setValue(static_cast(r)); surfaceBackgroundGreenSpinBox->setValue(static_cast(g)); surfaceBackgroundBlueSpinBox->setValue(static_cast(b)); pf->getSurfaceForegroundColor(r, g, b); surfaceForegroundRedSpinBox->setValue(static_cast(r)); surfaceForegroundGreenSpinBox->setValue(static_cast(g)); surfaceForegroundBlueSpinBox->setValue(static_cast(b)); float x, y, z; pf->getLightPosition(x, y, z); lightPositionXDoubleSpinBox->setValue(x); lightPositionYDoubleSpinBox->setValue(y); lightPositionZDoubleSpinBox->setValue(z); mouseSpeedDoubleSpinBox->setValue(pf->getMouseSpeed()); iterUpdateSpinBox->setValue(pf->getIterativeUpdate()); imageCaptureTypeComboBox->setCurrentIndex(static_cast(pf->getImageCaptureType())); debugOnCheckBox->setChecked(pf->getDebugOn()); debugNodeSpinBox->setValue(pf->getDebugNodeNumber()); testFlag1CheckBox->setChecked(pf->getTestFlag1()); testFlag2CheckBox->setChecked(pf->getTestFlag2()); openGLDebugCheckBox->setChecked(pf->getOpenGLDebug()); displayListsOnCheckBox->setChecked(pf->getDisplayListsEnabled()); if (webBrowserLineEdit->isVisible()) { webBrowserLineEdit->setText(pf->getWebBrowser()); } if (numberOfThreadsSpinBox != NULL) { numberOfThreadsSpinBox->setValue(pf->getMaximumNumberOfThreads()); } numberOfSpecFileReadThreadsSpinBox->setValue(pf->getNumberOfFileReadingThreads()); floatPrecisionSpinBox->setValue(pf->getTextFileDigitsRightOfDecimal()); const std::vector fileFormats = pf->getPreferredWriteDataType(); for (unsigned int j = 0; j < fileWriteDataTypeComboBox.size(); j++) { QComboBox* comboBox = fileWriteDataTypeComboBox[j]; for (int i = 0; i < comboBox->count(); i++) { if (j < fileFormats.size()) { if (static_cast(comboBox->itemData(i).toInt()) == fileFormats[j]) { comboBox->setCurrentIndex(i); break; } } } } sumsHostsLineEdit->setText(pf->getSumsDatabaseHosts()); randomSeedCheckBox->setChecked(pf->getRandomSeedOverride()); randomSeedSpinBox->setValue(pf->getRandomSeedOverrideValue()); randomSeedSpinBox->setEnabled(randomSeedCheckBox->isChecked()); allWidgetsGroup->blockSignals(false); } /** * Destructor. */ GuiPreferencesDialog::~GuiPreferencesDialog() { } /** * called by reset display lists push button. */ void GuiPreferencesDialog::slotResetDisplayListsPushButton() { theMainWindow->getBrainSet()->clearAllDisplayLists(); GuiBrainModelOpenGL::updateAllGL(); } /** * Called when apply button is pressed. */ void GuiPreferencesDialog::applyButtonSlot() { PreferencesFile* pf = theMainWindow->getBrainSet()->getPreferencesFile(); pf->setSurfaceBackgroundColor(static_cast(surfaceBackgroundRedSpinBox->value()), static_cast(surfaceBackgroundGreenSpinBox->value()), static_cast(surfaceBackgroundBlueSpinBox->value())); pf->setSurfaceForegroundColor(static_cast(surfaceForegroundRedSpinBox->value()), static_cast(surfaceForegroundGreenSpinBox->value()), static_cast(surfaceForegroundBlueSpinBox->value())); const bool colorsTheSame = (surfaceBackgroundRedSpinBox->value() == surfaceForegroundRedSpinBox->value()) && (surfaceBackgroundGreenSpinBox->value() == surfaceForegroundGreenSpinBox->value()) && (surfaceBackgroundBlueSpinBox->value() == surfaceForegroundBlueSpinBox->value()); if (colorsTheSame) { QMessageBox::warning(this, "Color Warning", "The foreground and background colors are the same.\n" "This will prevent some items in the main window, such\n" "as color palette numbers, from being seen. You should\n" "change the foreground and background colors to\n" "contrasting colors."); } pf->setLightPosition(lightPositionXDoubleSpinBox->value(), lightPositionYDoubleSpinBox->value(), lightPositionZDoubleSpinBox->value()); pf->setMouseSpeed(mouseSpeedDoubleSpinBox->value()); pf->setIterativeUpdate(iterUpdateSpinBox->value()); pf->setImageCaptureType( static_cast( imageCaptureTypeComboBox->currentIndex())); pf->setDebugOn(debugOnCheckBox->isChecked()); pf->setDebugNodeNumber(debugNodeSpinBox->value()); pf->setTestFlag1(testFlag1CheckBox->isChecked()); pf->setTestFlag2(testFlag2CheckBox->isChecked()); pf->setOpenGLDebug(openGLDebugCheckBox->isChecked()); pf->setDisplayListsEnabled(displayListsOnCheckBox->isChecked()); if (pf->getDisplayListsEnabled() == false) { theMainWindow->getBrainSet()->clearAllDisplayLists(); } if (webBrowserLineEdit->isVisible()) { pf->setWebBrowser(webBrowserLineEdit->text()); } if (numberOfThreadsSpinBox->isVisible()) { pf->setMaximumNumberOfThreads(numberOfThreadsSpinBox->value()); } pf->setNumberOfFileReadingThreads(numberOfSpecFileReadThreadsSpinBox->value()); pf->setTextFileDigitsRightOfDecimal(floatPrecisionSpinBox->value()); AbstractFile::setTextFileDigitsRightOfDecimal(pf->getTextFileDigitsRightOfDecimal()); std::vector fileFormats; for (unsigned int i = 0; i < fileWriteDataTypeComboBox.size(); i++) { const int indx = fileWriteDataTypeComboBox[i]->currentIndex(); fileFormats.push_back( static_cast(fileWriteDataTypeComboBox[i]->itemData(indx).toInt())); } pf->setPreferredWriteDataType(fileFormats); AbstractFile::setPreferredWriteType(fileFormats); pf->setSumsDatabaseHosts(sumsHostsLineEdit->text()); pf->setRandomSeedOverride(randomSeedCheckBox->isChecked()); pf->setRandomSeedOverrideValue(randomSeedSpinBox->value()); if (randomSeedCheckBox->isChecked()) { BrainSet::setRandomSeed(randomSeedSpinBox->value()); } randomSeedSpinBox->setEnabled(randomSeedCheckBox->isChecked()); try { pf->writeFile(pf->getFileName()); } catch (FileException& e) { QString msg("Unable to write preferences file because "); msg.append(e.whatQString()); QMessageBox::warning(this, "Error Writing Preferences", msg); } GuiBrainModelOpenGL::updateAllGL(NULL); } caret-5.6.4~dfsg.1.orig/caret/GuiParamsFileEditorDialog.h0000664000175000017500000000416211572067322023012 0ustar michaelmichael #ifndef __GUI_PARAMS_FILE_EDITOR_DIALOG_H__ #define __GUI_PARAMS_FILE_EDITOR_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "WuQDialog.h" class QGridLayout; class QLineEdit; class QScrollArea; /// Dialog for editing a parameters file class GuiParamsFileEditorDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiParamsFileEditorDialog(QWidget* parent); /// Destructor ~GuiParamsFileEditorDialog(); /// update the dialog void updateDialog(); protected slots: /// called when add new parameter button is pressed void slotAddNewParameterButton(); /// called when apply button is pressed void slotApplyButton(); /// called when close button is pressed void slotCloseButton(); protected: /// widget for the parameters QWidget* paramsWidget; /// grid layout for paramsWidget QGridLayout* paramsGridLayout; /// scrollview for the parameters QScrollArea* paramsEntryScrollView; /// storage for param labels std::vector keyLineEdits; /// storage for param values std::vector valueLineEdits; }; #endif // __GUI_PARAMS_FILE_EDITOR_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiParamsFileEditorDialog.cxx0000664000175000017500000001655311572067322023374 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include "BrainSet.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "GuiParamsFileEditorDialog.h" #include "ParamsFile.h" #include "QtUtilities.h" #include "global_variables.h" /** * Constructor. */ GuiParamsFileEditorDialog::GuiParamsFileEditorDialog(QWidget* parent) : WuQDialog(parent) { setWindowTitle("Parameters File Editor"); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // Grid for name/value line edits // paramsWidget = new QWidget; paramsGridLayout = new QGridLayout(paramsWidget); paramsGridLayout->setSpacing(3); // // Scrollview for entering the parameters // QScrollArea* paramsEntryScrollView = new QScrollArea(this); dialogLayout->addWidget(paramsEntryScrollView); paramsEntryScrollView->setWidget(paramsWidget); // // Column heading labels // paramsGridLayout->addWidget(new QLabel("Name"), 0, 0); paramsGridLayout->addWidget(new QLabel("Value"), 0, 1); // // Button for new parameter // QPushButton* addNewParameterButton = new QPushButton("Add New Parameter", this); addNewParameterButton->setFixedSize(addNewParameterButton->sizeHint()); addNewParameterButton->setAutoDefault(false); QObject::connect(addNewParameterButton, SIGNAL(clicked()), this, SLOT(slotAddNewParameterButton())); dialogLayout->addWidget(addNewParameterButton); // // Horizontal layout apply/close buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; dialogLayout->addLayout(buttonsLayout); buttonsLayout->setSpacing(3); // // Apply button // QPushButton* applyButton = new QPushButton("Apply", this); applyButton->setAutoDefault(false); buttonsLayout->addWidget(applyButton); QObject::connect(applyButton, SIGNAL(clicked()), this, SLOT(slotApplyButton())); // // Close button connects to QDialogs close() slot. // QPushButton* closeButton = new QPushButton("Close", this); closeButton->setAutoDefault(false); buttonsLayout->addWidget(closeButton); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(slotCloseButton())); QtUtilities::makeButtonsSameSize(applyButton, closeButton); updateDialog(); } /** * Destructor. */ GuiParamsFileEditorDialog::~GuiParamsFileEditorDialog() { } /** * called when add new parameter button is pressed. */ void GuiParamsFileEditorDialog::slotAddNewParameterButton() { // // Number of parameters in dialog // const int numInDialog = static_cast(keyLineEdits.size()); // // Find first hidden parameter // int availableIndex = -1; for (int i = 0; i < numInDialog; i++) { if (keyLineEdits[i]->isHidden()) { availableIndex = i; break; } } // // Can we just show a hidden item // if (availableIndex >= 0) { keyLineEdits[availableIndex]->show(); keyLineEdits[availableIndex]->clear(); valueLineEdits[availableIndex]->show(); valueLineEdits[availableIndex]->clear(); } else { QLineEdit* keyLE = new QLineEdit; keyLineEdits.push_back(keyLE); paramsGridLayout->addWidget(keyLE, numInDialog + 1, 0); QLineEdit* valueLE = new QLineEdit; valueLineEdits.push_back(valueLE); paramsGridLayout->addWidget(valueLE, numInDialog + 1, 1); keyLineEdits[numInDialog]->show(); valueLineEdits[numInDialog]->show(); } /* // // Scroll to bottom // QScrollBar* vertScrollBar = paramsEntryScrollView->verticalScrollBar(); vertScrollBar->setValue(vertScrollBar->maxValue()); */ paramsWidget->adjustSize(); } /** * update the dialog. */ void GuiParamsFileEditorDialog::updateDialog() { // // Get the parameters // std::vector keys, values; ParamsFile* pf = theMainWindow->getBrainSet()->getParamsFile(); pf->getAllParameters(keys, values); const int numParams = static_cast(keys.size()); // // Number of parameters in dialog // const int numInDialog = static_cast(keyLineEdits.size()); // // Add new parameters as needed // for (int i = numInDialog; i < numParams; i++) { QLineEdit* keyLE = new QLineEdit; paramsGridLayout->addWidget(keyLE, i + 1, 0); keyLineEdits.push_back(keyLE); QLineEdit* valueLE = new QLineEdit; paramsGridLayout->addWidget(valueLE, i + 1, 1); valueLineEdits.push_back(valueLE); } // // Hide unused items // for (int i = numParams; i < numInDialog; i++) { keyLineEdits[i]->hide(); keyLineEdits[i]->clear(); valueLineEdits[i]->hide(); valueLineEdits[i]->clear(); } // // Update params keys and values // for (int i = 0; i < numParams; i++) { keyLineEdits[i]->setText(keys[i]); keyLineEdits[i]->show(); valueLineEdits[i]->setText(values[i]); valueLineEdits[i]->show(); } paramsWidget->adjustSize(); } /** * called when apply button is pressed. */ void GuiParamsFileEditorDialog::slotApplyButton() { // // Get all items from the dialog and put in a new parameters file // ParamsFile pfTemp; const int newNum = static_cast(keyLineEdits.size()); for (int i = 0; i < newNum; i++) { if (keyLineEdits[i]->isHidden() == false) { const QString key(keyLineEdits[i]->text()); const QString value(valueLineEdits[i]->text()); if (key.isEmpty() == false) { pfTemp.setParameter(key, value); } } } // // Get the current parameters file // ParamsFile* pf = theMainWindow->getBrainSet()->getParamsFile(); // // Have the parameters changed ? // if (pf->getAllParameters() != pfTemp.getAllParameters()) { // // Update the parameters // pf->setAllParameters(pfTemp.getAllParameters()); // // Note theMainWindow->fileModificationUpdate(fm); will call GuiPaletteEditor::updateDialog() // GuiFilesModified fm; fm.setPaletteModified(); theMainWindow->fileModificationUpdate(fm); } } /** * called when close button is pressed. */ void GuiParamsFileEditorDialog::slotCloseButton() { slotApplyButton(); close(); } caret-5.6.4~dfsg.1.orig/caret/GuiPaletteEditorDialog.h0000664000175000017500000000737411572067322022375 0ustar michaelmichael #ifndef __GUI_PALETTE_EDITOR_DIALOG_H__ #define __GUI_PALETTE_EDITOR_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "WuQDialog.h" class Palette; class QComboBox; class QGridLayout; class QPushButton; class QSignalMapper; class QDoubleSpinBox; /// class for dialog used to edit palette files class GuiPaletteEditorDialog : public WuQDialog { Q_OBJECT public: /// constructor GuiPaletteEditorDialog(QWidget* parent); /// destructor ~GuiPaletteEditorDialog(); /// update the dialog void updateDialog(); protected slots: /// called when apply button is pressed void slotApplyButton(); /// called when a palette is selected void slotPaletteSelectionComboBox(int item); /// called when new palette button pressed void slotCreateNewPaletteButton(); /// called when delete palette button pressed void slotDeletePaletteButton(); /// called when rename palette button pressed void slotRenamePaletteButton(); /// called when an add palette entry button is pressed void slotAddPaletteEntry(int item); /// called when a remove palette entry button is pressed void slotRemovePaletteEntry(int item); /// called when palette entry color button is pressed void slotColorPaletteEntry(int item); /// called when edit colors button is pressed void slotEditColorsPushButton(); protected: /// update coloring void updateColoring(); /// signal mapper for add palette entry buttons QSignalMapper* addPaletteEntrySignalMapper; /// signal mapper for remove palette entry buttons QSignalMapper* removePaletteEntrySignalMapper; /// signal mapper for color buttons QSignalMapper* colorPaletteEntrySignalMapper; /// the palette being editied Palette* paletteBeingEdited; /// palette selection combo box QComboBox* paletteSelectionComboBox; /// widget for palette editing QWidget* paletteEntryWidget; /// grid layout for palette editing controls QGridLayout* paletteEntryGridLayout; /// palette numeric entry spin boxes std::vector paletteEntryScalarSpinBoxes; /// palette entry color push buttons std::vector paletteEntryColorPushButtons; /// widgets containing color swatches std::vector paletteEntryColorSwatch; /// palette insert new entry push buttons std::vector paletteEntryInsertPushButtons; /// palette delete new entry push buttons std::vector paletteEntryDeletePushButtons; /// prevent overwriting palette while it is being loaded into dialog bool loadingPalette; }; #endif // __GUI_PALETTE_EDITOR_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiPaletteEditorDialog.cxx0000664000175000017500000005046611572067322022750 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "AreaColorFile.h" #include "BrainModelSurfaceNodeColoring.h" #include "BrainModelVolumeVoxelColoring.h" #include "BrainSet.h" #include "GuiBrainModelOpenGL.h" #include "GuiColorFileEditorDialog.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "GuiPaletteColorSelectionDialog.h" #include "GuiPaletteEditorDialog.h" #include "PaletteFile.h" #include #include "QtRadioButtonSelectionDialog.h" #include "QtUtilities.h" #include "global_variables.h" /** * constructor. */ GuiPaletteEditorDialog::GuiPaletteEditorDialog(QWidget* parent) : WuQDialog(parent) { paletteBeingEdited = NULL; loadingPalette = false; setWindowTitle("Palette Editor"); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // Palette Colors group box // QGroupBox* colorsGroupBox = new QGroupBox("Palette Colors"); dialogLayout->addWidget(colorsGroupBox); QVBoxLayout* colorsGroupBoxLayout = new QVBoxLayout(colorsGroupBox); // // Edit colors button // QPushButton* editColorsPushButton = new QPushButton("Add, Delete, and Edit Colors..."); colorsGroupBoxLayout->addWidget(editColorsPushButton); editColorsPushButton->setAutoDefault(false); QObject::connect(editColorsPushButton, SIGNAL(clicked()), this, SLOT(slotEditColorsPushButton())); // // Palette select, create, delete group box // QGroupBox* selectGroupBox = new QGroupBox("Palette"); dialogLayout->addWidget(selectGroupBox); QVBoxLayout* selectGroupBoxLayout = new QVBoxLayout(selectGroupBox); // // Palette selection // paletteSelectionComboBox = new QComboBox; selectGroupBoxLayout->addWidget(paletteSelectionComboBox); QObject::connect(paletteSelectionComboBox, SIGNAL(activated(int)), this, SLOT(slotPaletteSelectionComboBox(int))); // // Create new palette button // QPushButton* createNewPaletteButton = new QPushButton("New..."); createNewPaletteButton->setAutoDefault(false); QObject::connect(createNewPaletteButton, SIGNAL(clicked()), this, SLOT(slotCreateNewPaletteButton())); // // Rename palette button // QPushButton* renamePaletteButton = new QPushButton("Rename..."); renamePaletteButton->setAutoDefault(false); QObject::connect(renamePaletteButton, SIGNAL(clicked()), this, SLOT(slotRenamePaletteButton())); // // Delete palette button // QPushButton* deletePaletteButton = new QPushButton("Delete..."); deletePaletteButton->setAutoDefault(false); QObject::connect(deletePaletteButton, SIGNAL(clicked()), this, SLOT(slotDeletePaletteButton())); // // Create new and delete palette box // QHBoxLayout* cdHBoxLayout = new QHBoxLayout; selectGroupBoxLayout->addLayout(cdHBoxLayout); cdHBoxLayout->addWidget(createNewPaletteButton); cdHBoxLayout->addWidget(renamePaletteButton); cdHBoxLayout->addWidget(deletePaletteButton); // // Make new and delete same size // QtUtilities::makeButtonsSameSize(createNewPaletteButton, deletePaletteButton); // // Limit size of palette selection group box // selectGroupBox->setFixedSize(selectGroupBox->sizeHint()); // // Group box for editing palettes // QGroupBox* editPaletteGroup = new QGroupBox("Edit Selected Palette"); QVBoxLayout* editPaletteGroupLayout = new QVBoxLayout(editPaletteGroup); dialogLayout->addWidget(editPaletteGroup); // // Grid for palette entries // paletteEntryWidget = new QWidget; paletteEntryGridLayout = new QGridLayout(paletteEntryWidget); paletteEntryGridLayout->setMargin(5); paletteEntryGridLayout->setSpacing(3); // // Scrolling for palette entries // QScrollArea* paletteEntryScrollView = new QScrollArea; paletteEntryScrollView->setWidget(paletteEntryWidget); editPaletteGroupLayout->addWidget(paletteEntryScrollView); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; dialogLayout->addLayout(buttonsLayout); buttonsLayout->setSpacing(3); // // Apply button // QPushButton* applyButton = new QPushButton("Apply"); applyButton->setAutoDefault(false); buttonsLayout->addWidget(applyButton); QObject::connect(applyButton, SIGNAL(clicked()), this, SLOT(slotApplyButton())); // // Close button connects to QDialogs close() slot. // QPushButton* closeButton = new QPushButton("Close"); closeButton->setAutoDefault(false); buttonsLayout->addWidget(closeButton); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); QtUtilities::makeButtonsSameSize(applyButton, closeButton); // // Create the signal mappers for the various palette entry buttons // addPaletteEntrySignalMapper = new QSignalMapper(this); QObject::connect(addPaletteEntrySignalMapper, SIGNAL(mapped(int)), this, SLOT(slotAddPaletteEntry(int))); colorPaletteEntrySignalMapper = new QSignalMapper(this); QObject::connect(colorPaletteEntrySignalMapper, SIGNAL(mapped(int)), this, SLOT(slotColorPaletteEntry(int))); removePaletteEntrySignalMapper = new QSignalMapper(this); QObject::connect(removePaletteEntrySignalMapper, SIGNAL(mapped(int)), this, SLOT(slotRemovePaletteEntry(int))); // // Load palettes into the dialog // updateDialog(); } /** * called when edit colors button is pressed. */ void GuiPaletteEditorDialog::slotEditColorsPushButton() { PaletteFile* pf = theMainWindow->getBrainSet()->getPaletteFile(); // // Place palette colors into a color file // AreaColorFile cf; pf->getPaletteColorsUsingColorFile(cf); // // Show colors in the color file editor dialog // GuiColorFileEditorDialog fed(this, &cf, false, false, false, false, true, 0); fed.exec(); // // Update colors // pf->replacePaletteColorsUsingColorFile(cf); // // Update the dialog // slotPaletteSelectionComboBox(paletteSelectionComboBox->currentIndex()); slotApplyButton(); } /** * called when apply button is pressed. */ void GuiPaletteEditorDialog::slotApplyButton() { if (loadingPalette) { return; } if (paletteBeingEdited != NULL) { const int fileNE = paletteBeingEdited->getNumberOfPaletteEntries(); const int numSpin = static_cast(paletteEntryScalarSpinBoxes.size()); int numEntries = 0; for (int j = 0; j < numSpin; j++) { if (paletteEntryScalarSpinBoxes[j]->isHidden() == false) { numEntries++; } } if (fileNE != numEntries) { std::cout << "PROGRAM ERROR: number of entries in palette does not match that " << "in the palette editor." << std::endl; return; } for (int i = 0; i < numEntries; i++) { PaletteEntry* pe = paletteBeingEdited->getPaletteEntry(i); pe->setValue(paletteEntryScalarSpinBoxes[i]->value()); } } BrainModelSurfaceNodeColoring* bsnc = theMainWindow->getBrainSet()->getNodeColoring(); bsnc->assignColors(); BrainModelVolumeVoxelColoring* bmvvc = theMainWindow->getBrainSet()->getVoxelColoring(); bmvvc->setVolumeFunctionalColoringInvalid(); GuiBrainModelOpenGL::updateAllGL(); } /** * called when a palette is selected. */ void GuiPaletteEditorDialog::slotPaletteSelectionComboBox(int item) { loadingPalette = true; const int spinBoxWidth = 100; paletteBeingEdited = NULL; int numPaletteEntries = 0; PaletteFile* pf = theMainWindow->getBrainSet()->getPaletteFile(); if ((item >= 0) && (item < pf->getNumberOfPalettes())) { paletteBeingEdited = pf->getPalette(item); numPaletteEntries = paletteBeingEdited->getNumberOfPaletteEntries(); } const int numValidRows = static_cast(paletteEntryScalarSpinBoxes.size()); // // Create new items as needed // for (int i = 0; i < numPaletteEntries; i++) { if (i >= numValidRows) { // // Insert push button // QPushButton* insertButton = new QPushButton("+"); insertButton->setAutoDefault(false); insertButton->setFixedSize(insertButton->sizeHint()); paletteEntryInsertPushButtons.push_back(insertButton); addPaletteEntrySignalMapper->setMapping(insertButton, i); QObject::connect(insertButton, SIGNAL(clicked()), addPaletteEntrySignalMapper, SLOT(map())); insertButton->setToolTip( "Press this button to insert\n" "a row below this row."); paletteEntryGridLayout->addWidget(insertButton, i, 0); // // Delete push button // QPushButton* deleteButton = new QPushButton("-"); deleteButton->setAutoDefault(false); deleteButton->setFixedSize(deleteButton->sizeHint()); paletteEntryDeletePushButtons.push_back(deleteButton); removePaletteEntrySignalMapper->setMapping(deleteButton, i); QObject::connect(deleteButton, SIGNAL(clicked()), removePaletteEntrySignalMapper, SLOT(map())); deleteButton->setToolTip( "Press this button\n" "to delete this row."); paletteEntryGridLayout->addWidget(deleteButton, i, 1); // // Spin box for palette scalar // QDoubleSpinBox* fsb = new QDoubleSpinBox; fsb->setMinimum(-1.0); fsb->setMaximum(1.0); fsb->setSingleStep(0.01); fsb->setDecimals(3); fsb->setFixedWidth(spinBoxWidth); QObject::connect(fsb, SIGNAL(valueChanged(double)), this, SLOT(slotApplyButton())); paletteEntryScalarSpinBoxes.push_back(fsb); paletteEntryGridLayout->addWidget(fsb, i, 2); // // Color button // QPushButton* fpb = new QPushButton(" "); fpb->setAutoDefault(false); paletteEntryColorPushButtons.push_back(fpb); colorPaletteEntrySignalMapper->setMapping(fpb, i); QObject::connect(fpb, SIGNAL(clicked()), colorPaletteEntrySignalMapper, SLOT(map())); fpb->setToolTip( "Press this button to change\n" "the color for this row."); paletteEntryGridLayout->addWidget(fpb, i, 3); // // Color swatch // QWidget* swatch = new QWidget; swatch->setFixedSize(QSize(20, 20)); paletteEntryColorSwatch.push_back(swatch); paletteEntryGridLayout->addWidget(swatch, i, 4); } } // // Update all items // for (int i = 0; i < numPaletteEntries; i++) { const PaletteEntry* pe = paletteBeingEdited->getPaletteEntry(i); const float value = pe->getValue(); const int colorIndex = pe->getColorIndex(); const PaletteColor* pc = pf->getPaletteColor(colorIndex); const QString name = pc->getName(); unsigned char rgb[3]; pc->getRGB(rgb); paletteEntryInsertPushButtons[i]->show(); paletteEntryDeletePushButtons[i]->show(); paletteEntryScalarSpinBoxes[i]->setValue(value); paletteEntryColorPushButtons[i]->setText(name); //paletteEntryColorSwatch[i]->setPaletteBackgroundColor(QColor(rgb[0], rgb[1], rgb[2])); QPalette pal; pal.setColor(QPalette::Window, QColor(rgb[0], rgb[1], rgb[2])); paletteEntryColorSwatch[i]->setAutoFillBackground(true); paletteEntryColorSwatch[i]->setBackgroundRole(QPalette::Window); paletteEntryColorSwatch[i]->setPalette(pal); paletteEntryScalarSpinBoxes[i]->show(); paletteEntryColorPushButtons[i]->show(); paletteEntryColorSwatch[i]->show(); } // // Hide unneeded items // for (int i = numPaletteEntries; i < numValidRows; i++) { paletteEntryInsertPushButtons[i]->hide(); paletteEntryDeletePushButtons[i]->hide(); paletteEntryScalarSpinBoxes[i]->hide(); paletteEntryColorPushButtons[i]->hide(); paletteEntryColorSwatch[i]->hide(); } loadingPalette = false; paletteEntryWidget->adjustSize(); } /** * called when an add palette entry button is pressed. */ void GuiPaletteEditorDialog::slotAddPaletteEntry(int item) { if (paletteBeingEdited != NULL) { PaletteEntry pe = *(paletteBeingEdited->getPaletteEntry(item)); paletteBeingEdited->insertPaletteEntry(item, pe); slotPaletteSelectionComboBox(paletteSelectionComboBox->currentIndex()); slotApplyButton(); } } /** * called when a remove palette entry button is pressed. */ void GuiPaletteEditorDialog::slotRemovePaletteEntry(int item) { if (paletteBeingEdited != NULL) { paletteBeingEdited->removePaletteEntry(item); slotPaletteSelectionComboBox(paletteSelectionComboBox->currentIndex()); slotApplyButton(); } } /** * called when palette entry color button is pressed. */ void GuiPaletteEditorDialog::slotColorPaletteEntry(int item) { PaletteEntry* pe = paletteBeingEdited->getPaletteEntry(item); GuiPaletteColorSelectionDialog pcsd(this, theMainWindow->getBrainSet()->getPaletteFile(), pe->getColorIndex()); if (pcsd.exec() == QDialog::Accepted) { const int indx = pcsd.getSelectedColorIndex(); pe->setColorIndex(indx); } slotPaletteSelectionComboBox(paletteSelectionComboBox->currentIndex()); slotApplyButton(); } /** * called when new palette button pressed. */ void GuiPaletteEditorDialog::slotCreateNewPaletteButton() { bool ok = false; const QString name = QInputDialog::getText(this, "New Palette Name", "New Palette Name", QLineEdit::Normal, QString::null, &ok); if (ok) { if (name.isEmpty()) { QMessageBox::critical(this, "ERROR", "Palette name blank. No palette created."); return; } PaletteFile* pf = theMainWindow->getBrainSet()->getPaletteFile(); Palette* copyThisPalette = NULL; const int palIndex = paletteSelectionComboBox->currentIndex(); if (palIndex >= 0) { Palette* pal = pf->getPalette(palIndex); std::vector labels; labels.push_back("New Empty Palette"); QString s("Copy Palette "); s.append(pal->getName()); labels.push_back(s); QtRadioButtonSelectionDialog rbd(this, "Choose New Palette", "Choose initial colors in new palette", labels, 0); if (rbd.exec() == QDialog::Accepted) { if (rbd.getSelectedItemIndex() == 1) { copyThisPalette = pal; } } else { return; } } if (copyThisPalette != NULL) { Palette p = *copyThisPalette; p.setName(name); pf->addPalette(p); } else { // // Add the missing color // const unsigned char rgb[3] = { 0, 0, 0 }; pf->addPaletteColor(PaletteColor::missingColorName, rgb); // // Create the palette with two "missing" colors // Palette pal(pf); pal.addPaletteEntry(1.0, PaletteColor::missingColorName); pal.addPaletteEntry(-1.0, PaletteColor::missingColorName); pal.setName(name); // // Add the palette to the palette file // pf->addPalette(pal); } // // Note theMainWindow->fileModificationUpdate(fm); will call GuiPaletteEditor::updateDialog() // GuiFilesModified fm; fm.setPaletteModified(); theMainWindow->fileModificationUpdate(fm); const int num = pf->getNumberOfPalettes(); slotPaletteSelectionComboBox(num - 1); paletteSelectionComboBox->setCurrentIndex(num - 1); } } /** * called when rename palette button pressed. */ void GuiPaletteEditorDialog::slotRenamePaletteButton() { const int palIndex = paletteSelectionComboBox->currentIndex(); if (palIndex >= 0) { PaletteFile* pf = theMainWindow->getBrainSet()->getPaletteFile(); Palette* pal = pf->getPalette(palIndex); bool ok = false; const QString newName = QInputDialog::getText(this, "Change Palette Name", "Palette Name", QLineEdit::Normal, pal->getName(), &ok); if (ok) { pal->setName(newName); // // Note theMainWindow->fileModificationUpdate(fm); will call GuiPaletteEditor::updateDialog() // GuiFilesModified fm; fm.setPaletteModified(); theMainWindow->fileModificationUpdate(fm); } } } /** * called when delete palette button pressed. */ void GuiPaletteEditorDialog::slotDeletePaletteButton() { const int palIndex = paletteSelectionComboBox->currentIndex(); if (palIndex >= 0) { PaletteFile* pf = theMainWindow->getBrainSet()->getPaletteFile(); QString msg("Are you sure you want to delete palette named "); const Palette* pal = pf->getPalette(palIndex); msg.append(pal->getName()); msg.append(" ?"); if (QMessageBox::question(this, "Are You Sure", msg, (QMessageBox::Yes | QMessageBox::No), QMessageBox::Yes) == QMessageBox::Yes) { pf->removePalette(palIndex); // // Note theMainWindow->fileModificationUpdate(fm); will call GuiPaletteEditor::updateDialog() // GuiFilesModified fm; fm.setPaletteModified(); theMainWindow->fileModificationUpdate(fm); } slotApplyButton(); } } /** * destructor. */ GuiPaletteEditorDialog::~GuiPaletteEditorDialog() { } /** * update the dialog. */ void GuiPaletteEditorDialog::updateDialog() { paletteSelectionComboBox->clear(); PaletteFile* pf = theMainWindow->getBrainSet()->getPaletteFile(); int currentItem = 0; // // Load the combo box // const int num = pf->getNumberOfPalettes(); for (int i = 0; i < num; i++) { const Palette* pal = pf->getPalette(i); paletteSelectionComboBox->addItem(pal->getName()); if (paletteBeingEdited == pal) { currentItem = i; } } paletteSelectionComboBox->setCurrentIndex(currentItem); slotPaletteSelectionComboBox(currentItem); } caret-5.6.4~dfsg.1.orig/caret/GuiPaletteColorSelectionDialog.h0000664000175000017500000000354111572067322024063 0ustar michaelmichael #ifndef __GUI_PALETTE_COLOR_SELECTION_DIALOG_H__ #define __GUI_PALETTE_COLOR_SELECTION_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "WuQDialog.h" class QListWidget; class PaletteFile; /// dialog for selecting a palette color class GuiPaletteColorSelectionDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiPaletteColorSelectionDialog(QWidget* parent, PaletteFile* pf, const int initialColorIndex); /// Destructor ~GuiPaletteColorSelectionDialog(); /// get the index of the selected color int getSelectedColorIndex() const; protected slots: protected: /// called when OK/Cancel button pressed void done(int r); /// the palette file PaletteFile* paletteFile; /// color selection list box QListWidget* colorSelectionListBox; }; #endif // __GUI_PALETTE_COLOR_SELECTION_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiPaletteColorSelectionDialog.cxx0000664000175000017500000001013211572067322024430 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include "GuiPaletteColorSelectionDialog.h" #include "PaletteFile.h" #include "QtUtilities.h" /** * Constructor. */ GuiPaletteColorSelectionDialog::GuiPaletteColorSelectionDialog(QWidget* parent, PaletteFile* pf, const int initialColorIndex) : WuQDialog(parent) { setModal(true); paletteFile = pf; setWindowTitle("Palette Color Selection"); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // Create a list box for selecting the colors // colorSelectionListBox = new QListWidget; dialogLayout->addWidget(colorSelectionListBox); // // Load the list box // const int numColors = paletteFile->getNumberOfPaletteColors(); for (int i = 0; i < numColors; i++) { // // Get the color information // const PaletteColor* pc = paletteFile->getPaletteColor(i); const QString name(pc->getName()); unsigned char rgb[3]; pc->getRGB(rgb); // // Create the pixmap // QPixmap pix(QSize(15, 15)); pix.fill(QColor(rgb[0], rgb[1], rgb[2])); // // Stick the pixmap into the list box // colorSelectionListBox->addItem(new QListWidgetItem(QIcon(pix), name)); } // // Use the initial color // if ((initialColorIndex >= 0) && (initialColorIndex < static_cast(colorSelectionListBox->count()))) { colorSelectionListBox->setCurrentRow(initialColorIndex); } // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); dialogLayout->addLayout(buttonsLayout); // // OK button // QPushButton* okButton = new QPushButton("OK"); okButton->setAutoDefault(false); buttonsLayout->addWidget(okButton); QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); // // Cancel button connects to QDialogs close() slot. // QPushButton* cancelButton = new QPushButton("Cancel"); cancelButton->setAutoDefault(false); buttonsLayout->addWidget(cancelButton); QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); QtUtilities::makeButtonsSameSize(okButton, cancelButton); } /** * Destructor. */ GuiPaletteColorSelectionDialog::~GuiPaletteColorSelectionDialog() { } /** * get the index of the selected color. */ int GuiPaletteColorSelectionDialog::getSelectedColorIndex() const { return colorSelectionListBox->currentRow(); } /** * called when OK/Cancel button pressed. */ void GuiPaletteColorSelectionDialog::done(int r) { if (r == QDialog::Accepted) { if (colorSelectionListBox->count() > 0) { if (getSelectedColorIndex() < 0) { QMessageBox::critical(this, "ERROR", "No color selected."); return; } } } QDialog::done(r); } caret-5.6.4~dfsg.1.orig/caret/GuiPaintNameEditorDialog.h0000664000175000017500000000735311572067322022650 0ustar michaelmichael #ifndef __GUI_PAINT_NAME_EDITOR_DIALOG_H__ #define __GUI_PAINT_NAME_EDITOR_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "WuQDialog.h" class GuiNodeAttributeColumnSelectionComboBox; class QLabel; class QGridLayout; class QSignalMapper; class WuQWidgetGroup; /// class for editing paint names class GuiPaintNameEditorDialog : public WuQDialog { Q_OBJECT public: // constructor GuiPaintNameEditorDialog(QWidget* parent = 0); // destructor ~GuiPaintNameEditorDialog(); // update the dialog void updateDialog(); protected slots: // called when a column is selected void slotColumnSelectionComboBox(int col); // called when a name button is clicked void slotNameButtonClicked(int indx); // called when delete button is clicked void slotDeleteButtonClicked(int indx); // called when deassign button is clicked void slotDeassignButtonClicked(int indx); // called when reassign button is clicked void slotReassignButtonClicked(int indx); // called when edit color button is clicked void slotEditColorButtonClicked(int indx); /// called to add a new paint name void slotAddPaintName(); /// called to remove prefixes from names void slotRemovePrefixesFromPaintNames(); /// called to remove suffixes from names void slotRemoveSuffixesFromPaintNames(); protected: // load the paint names void loadPaintNames(); /// update the GUI void updateGUI(); /// column selection combo box GuiNodeAttributeColumnSelectionComboBox* columnSelectionComboBox; /// grid layout for paint names QGridLayout* paintNameGridLayout; /// paint file index std::vector paintFileIndices; /// paint name actions std::vector paintNameActions; /// paint count labels std::vector paintCountLabels; /// paint index labels std::vector paintIndexLabels; /// paint color widget std::vector paintColorLabels; /// widget groups for each row std::vector rowWidgetGroups; /// paint labels needed bool addColumnTitlesToPaintNameLayoutFlag; /// signal mapper for paint name buttons QSignalMapper* nameButtonsSignalMapper; /// signal mapper for delete buttons QSignalMapper* deleteButtonsSignalMapper; /// signal mapper for deassign buttons QSignalMapper* deassignButtonsSignalMapper; /// signal mapper for reassign buttons QSignalMapper* reassignButtonsSignalMapper; /// signal mapper for edit color buttons QSignalMapper* editColorButtonsSignalMapper; }; #endif // __GUI_PAINT_NAME_EDITOR_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiPaintNameEditorDialog.cxx0000664000175000017500000006261711572067322023227 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "AreaColorFile.h" #include "BrainModelSurfaceNodeColoring.h" #include "BrainSet.h" #include "GuiBrainModelOpenGL.h" #include "GuiColorSelectionDialog.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "GuiNodeAttributeColumnSelectionComboBox.h" #include "GuiPaintNameEditorDialog.h" #include "NameIndexSort.h" #include "PaintFile.h" #include "PreferencesFile.h" #include "WuQDataEntryDialog.h" #include "WuQWidgetGroup.h" #include "global_variables.h" /** * constructor. */ GuiPaintNameEditorDialog::GuiPaintNameEditorDialog(QWidget* parent) : WuQDialog(parent) { addColumnTitlesToPaintNameLayoutFlag = true; setWindowTitle("Paint Name and Attributes Editor"); // // Colunn selection control // columnSelectionComboBox = new GuiNodeAttributeColumnSelectionComboBox(theMainWindow->getBrainSet()->getPaintFile(), false, false, true); QObject::connect(columnSelectionComboBox, SIGNAL(itemSelected(int)), this, SLOT(slotColumnSelectionComboBox(int))); QGroupBox* columnGroupBox = new QGroupBox("Column Selection"); QHBoxLayout* columnSelectionLayout = new QHBoxLayout(columnGroupBox); columnSelectionLayout->addWidget(columnSelectionComboBox); // // widget and grid layout for paint names // Use nested layouts to keep widgets to the left and top // paintNameGridLayout = new QGridLayout; QWidget* paintNameWidget = new QWidget; QVBoxLayout* paintNameLayout = new QVBoxLayout(paintNameWidget); paintNameLayout->addLayout(paintNameGridLayout); paintNameLayout->setAlignment(paintNameGridLayout, Qt::AlignLeft | Qt::AlignTop); // // Scroll area for paint names // QScrollArea* nameScrollArea = new QScrollArea; nameScrollArea->setWidget(paintNameWidget); nameScrollArea->setWidgetResizable(true); // // Groupbox for paint name scroll area // QGroupBox* paintNameGroupBox = new QGroupBox("Paint Names"); QVBoxLayout* paintNameGroupBoxLayout = new QVBoxLayout(paintNameGroupBox); paintNameGroupBoxLayout->addWidget(nameScrollArea); // // Add new Paint Name button // QPushButton* addPaintNameButton = new QPushButton("Add New Paint Name..."); addPaintNameButton->setAutoDefault(false); addPaintNameButton->setFixedSize(addPaintNameButton->sizeHint()); QObject::connect(addPaintNameButton, SIGNAL(clicked()), this, SLOT(slotAddPaintName())); // // Remove prefix from names // QPushButton* removeNamePrefixesButton = new QPushButton("Remove Name Prefixes"); removeNamePrefixesButton->setAutoDefault(false); removeNamePrefixesButton->setFixedSize(removeNamePrefixesButton->sizeHint()); QObject::connect(removeNamePrefixesButton, SIGNAL(clicked()), this, SLOT(slotRemovePrefixesFromPaintNames())); // // Remove suffix from names // QPushButton* removeNameSuffixesButton = new QPushButton("Remove Name Suffixes"); removeNameSuffixesButton->setAutoDefault(false); removeNameSuffixesButton->setFixedSize(removeNameSuffixesButton->sizeHint()); QObject::connect(removeNameSuffixesButton, SIGNAL(clicked()), this, SLOT(slotRemoveSuffixesFromPaintNames())); // // Layout for name buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->addWidget(addPaintNameButton); buttonsLayout->addWidget(removeNamePrefixesButton); buttonsLayout->addWidget(removeNameSuffixesButton); // // Standard Dialog Buttons // QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Close, Qt::Horizontal); QObject::connect(buttonBox, SIGNAL(rejected()), this, SLOT(close())); // // Layout for dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->addWidget(columnGroupBox); dialogLayout->addWidget(paintNameGroupBox); dialogLayout->addLayout(buttonsLayout); dialogLayout->addWidget(buttonBox); // // Create signal mappers // nameButtonsSignalMapper = new QSignalMapper(this); QObject::connect(nameButtonsSignalMapper, SIGNAL(mapped(int)), this, SLOT(slotNameButtonClicked(int))); deleteButtonsSignalMapper = new QSignalMapper(this); QObject::connect(deleteButtonsSignalMapper, SIGNAL(mapped(int)), this, SLOT(slotDeleteButtonClicked(int))); deassignButtonsSignalMapper = new QSignalMapper(this); QObject::connect(deassignButtonsSignalMapper, SIGNAL(mapped(int)), this, SLOT(slotDeassignButtonClicked(int))); reassignButtonsSignalMapper = new QSignalMapper(this); QObject::connect(reassignButtonsSignalMapper, SIGNAL(mapped(int)), this, SLOT(slotReassignButtonClicked(int))); editColorButtonsSignalMapper = new QSignalMapper(this); QObject::connect(editColorButtonsSignalMapper, SIGNAL(mapped(int)), this, SLOT(slotEditColorButtonClicked(int))); // // load names into dialog // loadPaintNames(); } /** * destructor. */ GuiPaintNameEditorDialog::~GuiPaintNameEditorDialog() { PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); pf->removePrefixesAndSuffixesFromNames(true, false); this->loadPaintNames(); } /** * called to remove prefixes from names. */ void GuiPaintNameEditorDialog::slotRemovePrefixesFromPaintNames() { PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); pf->removePrefixesAndSuffixesFromNames(true, false); this->loadPaintNames(); this->updateGUI(); } /** * called to remove suffixes from names. */ void GuiPaintNameEditorDialog::slotRemoveSuffixesFromPaintNames() { PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); pf->removePrefixesAndSuffixesFromNames(false, true); this->loadPaintNames(); this->updateGUI(); } /** * update the dialog. */ void GuiPaintNameEditorDialog::updateDialog() { columnSelectionComboBox->updateComboBox(); loadPaintNames(); } /** * called to add a new paint name. */ void GuiPaintNameEditorDialog::slotAddPaintName() { WuQDataEntryDialog ded(this); QLineEdit* le = ded.addLineEditWidget("New Paint Name"); if (ded.exec() == WuQDataEntryDialog::Accepted) { QString name = le->text().trimmed(); if (name.isEmpty() == false) { PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); if (pf->getPaintIndexFromName(name) >= 0) { QMessageBox::critical(this, "ERROR", "Name \"" + name + "\" is already in paint file."); return; } pf->addPaintName(name); updateGUI(); } } } /** * called when a column is selected. */ void GuiPaintNameEditorDialog::slotColumnSelectionComboBox(int /*col*/) { loadPaintNames(); } /** * load the paint names. */ void GuiPaintNameEditorDialog::loadPaintNames() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); NameIndexSort nameSort; PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); const int numPaints = pf->getNumberOfPaintNames(); // // Get the paint names // if (columnSelectionComboBox->getAllSelected()) { for (int i = 0; i < numPaints; i++) { nameSort.add(i, pf->getPaintNameFromIndex(i)); } } else { const int col = columnSelectionComboBox->currentIndex(); if ((col >= 0) && (col < pf->getNumberOfColumns())) { std::vector indices; pf->getPaintNamesForColumn(col, indices); for (unsigned int i = 0; i < indices.size(); i++) { nameSort.add(indices[i], pf->getPaintNameFromIndex(indices[i])); } } } // // Sort the names alphabetically // nameSort.sortByNameCaseSensitive(); const int numberOfPaintNamesForDisplay = nameSort.getNumberOfItems(); // // Add to grid layout for names // int GRID_COLUMN_COUNT = 0; const int indexCol = GRID_COLUMN_COUNT++; const int nameCol = GRID_COLUMN_COUNT++; const int countCol = GRID_COLUMN_COUNT++; const int colorCol = GRID_COLUMN_COUNT++; const int editColorCol = GRID_COLUMN_COUNT++; const int deassignCol = GRID_COLUMN_COUNT++; const int reassignCol = GRID_COLUMN_COUNT++; const int deleteCol = GRID_COLUMN_COUNT++; if (addColumnTitlesToPaintNameLayoutFlag) { addColumnTitlesToPaintNameLayoutFlag = false; // // Add column titles // paintNameGridLayout->addWidget(new QLabel("Node"), 0, indexCol); paintNameGridLayout->addWidget(new QLabel("Value"), 1, indexCol); paintNameGridLayout->addWidget(new QLabel("Name"), 1, nameCol); paintNameGridLayout->addWidget(new QLabel("Node"), 0, countCol); paintNameGridLayout->addWidget(new QLabel("Count"), 1, countCol); paintNameGridLayout->addWidget(new QLabel("Color"), 1, colorCol); } const int numberOfPaintsInDialog = static_cast(paintFileIndices.size()); // // Create new rows // for (int i = numberOfPaintsInDialog; i < numberOfPaintNamesForDisplay; i++) { const int rowNumber = i + 2; // 1st row is column titles // // Create the widgets for the row // QLabel* countLabel =new QLabel(""); countLabel->setToolTip("This count represents the number \n" "of nodes using the paint name."); QLabel* indexLabel = new QLabel(""); indexLabel->setToolTip("This number is the value assigned\n" "to nodes using this paint name."); QLabel* colorWidget = new QLabel(""); colorWidget->setFixedWidth(50); // // Name button // QAction* nameButtonAction = new QAction("", this); QToolButton* nameToolButton = new QToolButton; nameToolButton->setDefaultAction(nameButtonAction); nameToolButton->setToolTip("Change the name\n" "of the paint."); QObject::connect(nameButtonAction, SIGNAL(triggered(bool)), nameButtonsSignalMapper, SLOT(map())); nameButtonsSignalMapper->setMapping(nameButtonAction, i); // // Delete button // QAction* deleteButtonAction = new QAction("X", this); QToolButton* deleteToolButton = new QToolButton; deleteToolButton->setDefaultAction(deleteButtonAction); deleteToolButton->setToolTip("Delete the paint. All nodes that\n" "were using the paint name are \n" "deassigned for all paint columns."); QObject::connect(deleteButtonAction, SIGNAL(triggered(bool)), deleteButtonsSignalMapper, SLOT(map())); deleteButtonsSignalMapper->setMapping(deleteButtonAction, i); // // Deassign button // QAction* deassignButtonAction = new QAction("D", this); QToolButton* deassignToolButton = new QToolButton; deassignToolButton->setDefaultAction(deassignButtonAction); deassignToolButton->setToolTip("Deassign all nodes using the paint \n" "name in the paint column(s) selected\n" "at the top of this dialog."); QObject::connect(deassignButtonAction, SIGNAL(triggered(bool)), deassignButtonsSignalMapper, SLOT(map())); deassignButtonsSignalMapper->setMapping(deassignButtonAction, i); // // Reassign button // QAction* reassignButtonAction = new QAction("R", this); QToolButton* reassignToolButton = new QToolButton; reassignToolButton->setDefaultAction(reassignButtonAction); reassignToolButton->setToolTip("Reassign all nodes using the paint \n" "name in the paint column(s) selected\n" "at the top of the dialog."); QObject::connect(reassignButtonAction, SIGNAL(triggered(bool)), reassignButtonsSignalMapper, SLOT(map())); reassignButtonsSignalMapper->setMapping(reassignButtonAction, i); // // Edit color button // QAction* editColorButtonAction = new QAction("Edit Color", this); QToolButton* editColorToolButton = new QToolButton; editColorToolButton->setDefaultAction(editColorButtonAction); editColorToolButton->setToolTip("Edit the best matching\n" "color for this paint name."); QObject::connect(editColorButtonAction, SIGNAL(triggered(bool)), editColorButtonsSignalMapper, SLOT(map())); editColorButtonsSignalMapper->setMapping(editColorButtonAction, i); // // keep pointers to the row's widgets // paintFileIndices.push_back(i); paintNameActions.push_back(nameButtonAction); paintIndexLabels.push_back(indexLabel); paintCountLabels.push_back(countLabel); paintColorLabels.push_back(colorWidget); // // Add the widgets to the layout // paintNameGridLayout->addWidget(indexLabel, rowNumber, indexCol); paintNameGridLayout->addWidget(nameToolButton, rowNumber, nameCol); paintNameGridLayout->addWidget(countLabel, rowNumber, countCol); paintNameGridLayout->addWidget(colorWidget, rowNumber, colorCol); paintNameGridLayout->addWidget(editColorToolButton, rowNumber, editColorCol); paintNameGridLayout->addWidget(deassignToolButton, rowNumber, deassignCol); paintNameGridLayout->addWidget(reassignToolButton, rowNumber, reassignCol); paintNameGridLayout->addWidget(deleteToolButton, rowNumber, deleteCol); // // Widget group for all items in row // WuQWidgetGroup* wg = new WuQWidgetGroup(this); wg->addWidget(indexLabel); wg->addWidget(nameToolButton); wg->addWidget(countLabel); wg->addWidget(colorWidget); wg->addWidget(editColorToolButton); wg->addWidget(deassignToolButton); wg->addWidget(reassignToolButton); wg->addWidget(deleteToolButton); rowWidgetGroups.push_back(wg); } const AreaColorFile* colorFile = theMainWindow->getBrainSet()->getAreaColorFile(); // // Paint counts // std::vector paintCounts; pf->getAllPaintCounts(paintCounts); const int numPaintCounts = paintCounts.size(); // // Update existing rows // for (int i = 0; i < numberOfPaintNamesForDisplay; i++) { int indx; QString name; nameSort.getSortedNameAndIndex(i, indx, name); paintFileIndices[i] = indx; paintIndexLabels[i]->setText(QString::number(indx)); paintNameActions[i]->setText(name); paintNameActions[i]->setToolTip("Change the name\n" "of this paint paint."); int paintNameCount = 0; if ((indx >= 0) && (indx < numPaintCounts)) { paintNameCount = paintCounts[indx]; } paintCountLabels[i]->setText(QString::number(paintNameCount)); QColor labelColor(170, 170, 170); bool autoFill = false; QPalette::ColorRole backgroundRole = QPalette::NoRole; bool match = false; unsigned char r, g, b; const int colorIndex = colorFile->getColorByName(name, match, r, g, b); if (colorIndex >= 0) { labelColor.setRgb(r, g, b, 255); backgroundRole = QPalette::Window; autoFill = true; paintColorLabels[i]->setText(" "); } else { paintColorLabels[i]->setText("None"); } QPalette pal; pal.setColor(QPalette::Window, labelColor); paintColorLabels[i]->setAutoFillBackground(autoFill); paintColorLabels[i]->setPalette(pal); paintColorLabels[i]->repaint(); paintColorLabels[i]->setBackgroundRole(backgroundRole); rowWidgetGroups[i]->setVisible(true); } // // Remove rows not needed // for (int i = numberOfPaintNamesForDisplay; i < numberOfPaintsInDialog; i++) { rowWidgetGroups[i]->setVisible(false); } QApplication::restoreOverrideCursor(); } /** * called when a name button is clicked. */ void GuiPaintNameEditorDialog::slotNameButtonClicked(int indx) { if ((indx >= 0) && (indx < static_cast(paintFileIndices.size()))) { PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); const QString oldName = pf->getPaintNameFromIndex(paintFileIndices[indx]); WuQDataEntryDialog ded(this); QLineEdit* le = ded.addLineEditWidget("Edit Paint Name", oldName); if (ded.exec() == WuQDataEntryDialog::Accepted) { const QString newName = le->text().trimmed(); if (newName.isEmpty() == false) { if (newName != oldName) { PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); if (pf->getPaintIndexFromName(newName) >= 0) { QMessageBox::critical(this, "ERROR", "Name \"" + newName + "\" is already in paint file.\n" "Use the reassign \"R\" button to change the name."); return; } pf->setPaintName(paintFileIndices[indx], newName); /* * If needed, copy old color to a new color. */ AreaColorFile* acf = theMainWindow->getBrainSet()->getAreaColorFile(); bool match = false; acf->getColorIndexByName(newName, match); if (match == false) { unsigned char r, g, b, a; acf->getColorByName(oldName, match, r, g, b, a); acf->addColor(newName, r, g, b, a); } updateGUI(); } } } } } /** * called when delete button is clicked. */ void GuiPaintNameEditorDialog::slotDeleteButtonClicked(int indx) { if ((indx >= 0) && (indx < static_cast(paintFileIndices.size()))) { PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); pf->deletePaintName(paintFileIndices[indx]); updateGUI(); } } /** * called when deassign button is clicked. */ void GuiPaintNameEditorDialog::slotDeassignButtonClicked(int indx) { if ((indx >= 0) && (indx < static_cast(paintFileIndices.size()))) { const int columnNumber = columnSelectionComboBox->currentIndex(); PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); pf->deassignPaintName(columnNumber, paintFileIndices[indx]); updateGUI(); } } /** * called when reassign button is clicked. */ void GuiPaintNameEditorDialog::slotReassignButtonClicked(int indx) { if ((indx >= 0) && (indx < static_cast(paintFileIndices.size()))) { // // Get a list of unique paint names // const int columnNumber = columnSelectionComboBox->currentIndex(); PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); std::vector paintNames; std::vector paintNameIndices; pf->getAllPaintNamesAndIndices(paintNames, paintNameIndices); const int numNames = static_cast(paintNames.size()); QStringList names; for (int i = 0; i < numNames; i++) { names << (paintNames[i] + " [" + QString::number(paintNameIndices[i]) + "]"); } // // Let user choose the new paint name for reassignment // WuQDataEntryDialog ed(this); ed.setWindowTitle("Choose Reassignment Name"); ed.setTextAtTop("Choose New Name", false); QListWidget* lw = ed.addListWidget("", names); if (ed.exec() == WuQDataEntryDialog::Accepted) { const int itemIndex = lw->currentRow(); if ((itemIndex >= 0) && (itemIndex < lw->count())) { const int newIndex = paintNameIndices[itemIndex]; if (newIndex >= 0) { pf->reassignPaintName(columnNumber, paintFileIndices[indx], newIndex); updateGUI(); } } } } } /** * called when edit color button is clicked. */ void GuiPaintNameEditorDialog::slotEditColorButtonClicked(int indx) { if ((indx >= 0) && (indx < static_cast(paintFileIndices.size()))) { // // Get index for color // PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); const QString name = pf->getPaintNameFromIndex(paintFileIndices[indx]); AreaColorFile* acf = theMainWindow->getBrainSet()->getAreaColorFile(); bool match = false; unsigned char r, g, b, a; int colorIndex = acf->getColorByName(name, match, r, g, b, a); // // Was the color or partially matching color found // QString colorName; bool createNewColorFlag = false; if (colorIndex >= 0) { if (match) { // // Exact match found // colorName = name; } else { // // Partial match found, allow user to choose to edit the partially // matching color or create a new color that is an exact match // const QString partialMatchColor(acf->getColorNameByIndex(colorIndex)); const QString msg = ("The partially matching color named " + partialMatchColor + "\n" "is being used for " + name + "."); QMessageBox msgBox(this); msgBox.setWindowTitle("Color Name"); msgBox.setText(msg); QPushButton* modifyButton = msgBox.addButton("Modify Color " + partialMatchColor, QMessageBox::AcceptRole); QPushButton* defineButton = msgBox.addButton("Define New Color " + name, QMessageBox::AcceptRole); msgBox.addButton("Cancel", QMessageBox::RejectRole); msgBox.exec(); if (msgBox.clickedButton() == modifyButton) { colorName = partialMatchColor; } else if (msgBox.clickedButton() == defineButton) { createNewColorFlag = true; } else { return; } } } else { // // No exact or partially matching color // createNewColorFlag = true; } if (createNewColorFlag) { colorName = name; PreferencesFile* pref = theMainWindow->getBrainSet()->getPreferencesFile(); pref->getSurfaceForegroundColor(r, g, b); colorIndex = acf->addColor(name, r, g, b); } if (colorName.isEmpty() == false) { GuiColorSelectionDialog csd(this, "Edit Color " + colorName, false, false, false, false); csd.setColor(r, g, b, 255); if (csd.exec() == GuiColorSelectionDialog::Accepted) { float pointSize, lineSize; ColorFile::ColorStorage::SYMBOL symbol; csd.getColorInformation(r, g, b, a, pointSize, lineSize, symbol); acf->setColorByIndex(colorIndex, r, g, b); } updateGUI(); } } } /** * update the GUI. */ void GuiPaintNameEditorDialog::updateGUI() { GuiFilesModified fm; fm.setPaintModified(); theMainWindow->fileModificationUpdate(fm); theMainWindow->getBrainSet()->getNodeColoring()->assignColors(); GuiBrainModelOpenGL::updateAllGL(); } caret-5.6.4~dfsg.1.orig/caret/GuiPaintColumnNamesListBoxSelectionDialog.h0000664000175000017500000000337711572067322026217 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_PAINT_COLUMN_NAMES_LIST_BOX_SELECTION_DIALOG_H__ #define __GUI_PAINT_COLUMN_NAMES_LIST_BOX_SELECTION_DIALOG_H__ #include #include "QtListBoxSelectionDialog.h" /// This class creates a combo box containing the paint names for a specific paint column class GuiPaintColumnNamesListBoxSelectionDialog : public QtListBoxSelectionDialog { Q_OBJECT public: /// Constructor GuiPaintColumnNamesListBoxSelectionDialog(QWidget* parent, const int paintColumn); /// Destructor ~GuiPaintColumnNamesListBoxSelectionDialog(); /// get index of selected paint name int getSelectedItemIndex() const; private: /// indices into paint names std::vector paintNameIndices; }; #endif // __GUI_PAINT_COLUMN_NAMES_LIST_BOX_SELECTION_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiPaintColumnNamesListBoxSelectionDialog.cxx0000664000175000017500000000413511572067322026563 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "GuiPaintColumnNamesListBoxSelectionDialog.h" #include "BrainSet.h" #include "GuiMainWindow.h" #include "PaintFile.h" #include "global_variables.h" /** * Constructor. */ GuiPaintColumnNamesListBoxSelectionDialog::GuiPaintColumnNamesListBoxSelectionDialog(QWidget* parent, const int paintColumn) : QtListBoxSelectionDialog(parent, "Paint Name Selection") { PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); pf->getPaintNamesForColumn(paintColumn, paintNameIndices); const int numNames = static_cast(paintNameIndices.size()); std::vector names; for (int i = 0; i < numNames; i++) { names.push_back(pf->getPaintNameFromIndex(paintNameIndices[i])); } setListBoxContents(names, 0); } /** * Destructor. */ GuiPaintColumnNamesListBoxSelectionDialog::~GuiPaintColumnNamesListBoxSelectionDialog() { } /** * Get index of selected paint name */ int GuiPaintColumnNamesListBoxSelectionDialog::getSelectedItemIndex() const { const int item = QtListBoxSelectionDialog::getSelectedItemIndex(); if ((item >= 0) && (item < static_cast(paintNameIndices.size()))) { return paintNameIndices[item]; } return -1; } caret-5.6.4~dfsg.1.orig/caret/GuiNodeFileType.h0000664000175000017500000000146411572067322021031 0ustar michaelmichael #ifndef __GUI_NODE_FILE_TYPE_H__ #define __GUI_NODE_FILE_TYPE_H__ /// node file types enum GUI_NODE_FILE_TYPE { /// none GUI_NODE_FILE_TYPE_NONE, /// areal estimation GUI_NODE_FILE_TYPE_AREAL_ESTIMATION, /// deformation field GUI_NODE_FILE_TYPE_DEFORMATION_FIELD, /// geodesic distance GUI_NODE_FILE_TYPE_GEODESIC_DISTANCE, /// lat lon GUI_NODE_FILE_TYPE_LAT_LON, /// metric GUI_NODE_FILE_TYPE_METRIC, // gifti /// paint GUI_NODE_FILE_TYPE_PAINT, // gifti /// probabilistic atlas GUI_NODE_PROBABILISTIC_ATLAS, /// rgb paint GUI_NODE_FILE_TYPE_RGB_PAINT, /// section GUI_NODE_FILE_TYPE_SECTION, /// surface shape GUI_NODE_FILE_TYPE_SURFACE_SHAPE, /// topography file GUI_NODE_FILE_TYPE_TOPOGRAPHY }; #endif // __GUI_NODE_FILE_TYPE_H__ caret-5.6.4~dfsg.1.orig/caret/GuiNodeAttributeFileClearResetDialog.h0000664000175000017500000000457711572067322025155 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_NODE_ATTRIBUTE_FILE_CLEAR_RESET_DIALOG_H__ #define __GUI_NODE_ATTRIBUTE_FILE_CLEAR_RESET_DIALOG_H__ #include "WuQDialog.h" #include "GuiFilesModified.h" #include "GuiNodeFileType.h" class GuiNodeAttributeColumnSelectionComboBox; class QRadioButton; /// dialog for clearing a node attribute file, clearing a column, or resetting a column class GuiNodeAttributeFileClearResetDialog : public WuQDialog { Q_OBJECT public: /// constructor GuiNodeAttributeFileClearResetDialog(QWidget* parent, const GUI_NODE_FILE_TYPE nodeFileTypeIn); /// Destructor ~GuiNodeAttributeFileClearResetDialog(); private slots: /// called when apply button pressed void slotApplyButton(); private: /// update the dialog void updateDialog(); /// type of node file GUI_NODE_FILE_TYPE nodeFileType; /// file changed mask GuiFilesModified fileChanged; /// clear column combo box GuiNodeAttributeColumnSelectionComboBox* clearColumnComboBox; /// remove column combo box GuiNodeAttributeColumnSelectionComboBox* removeColumnComboBox; /// clear file radio button QRadioButton* clearFileRadioButton; /// clear column radio button QRadioButton* clearColumnRadioButton; /// remove column radio button QRadioButton* removeColumnRadioButton; }; #endif // __GUI_NODE_ATTRIBUTE_FILE_CLEAR_RESET_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiNodeAttributeFileClearResetDialog.cxx0000664000175000017500000003055611572067322025524 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include "ArealEstimationFile.h" #include "BrainSet.h" #include "BrainModelSurfaceNodeColoring.h" #include "DeformationFieldFile.h" #include "DisplaySettings.h" #include "DisplaySettingsArealEstimation.h" #include "DisplaySettingsDeformationField.h" #include "DisplaySettingsGeodesicDistance.h" #include "DisplaySettingsMetric.h" #include "DisplaySettingsPaint.h" #include "DisplaySettingsProbabilisticAtlas.h" #include "DisplaySettingsRgbPaint.h" #include "DisplaySettingsSection.h" #include "DisplaySettingsSurfaceShape.h" #include "DisplaySettingsTopography.h" #include "GeodesicDistanceFile.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "GuiNodeAttributeColumnSelectionComboBox.h" #include "GuiNodeAttributeFileClearResetDialog.h" #include "LatLonFile.h" #include "MetricFile.h" #include "PaintFile.h" #include "ProbabilisticAtlasFile.h" #include "QtUtilities.h" #include "RgbPaintFile.h" #include "SectionFile.h" #include "SurfaceShapeFile.h" #include "TopographyFile.h" #include "global_variables.h" /** * constructor */ GuiNodeAttributeFileClearResetDialog::GuiNodeAttributeFileClearResetDialog( QWidget* parent, const GUI_NODE_FILE_TYPE nodeFileTypeIn) : WuQDialog(parent) { setModal(true); nodeFileType = nodeFileTypeIn; QString caption; caption.append("Clear/Reset Data File"); setWindowTitle(caption); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // Button group to keep the radio buttons mutually exclusive // QButtonGroup* radioButtonGroup = new QButtonGroup(this); // // Clear file contents radio button // clearFileRadioButton = new QRadioButton("Clear File Contents"); dialogLayout->addWidget(clearFileRadioButton); radioButtonGroup->addButton(clearFileRadioButton); // // Clear file column radio button and combo box // QHBoxLayout* clearColumnHBoxLayout = new QHBoxLayout; dialogLayout->addLayout(clearColumnHBoxLayout); clearColumnRadioButton = new QRadioButton("Clear File Column"); clearColumnHBoxLayout->addWidget(clearColumnRadioButton); radioButtonGroup->addButton(clearColumnRadioButton); clearColumnComboBox = new GuiNodeAttributeColumnSelectionComboBox( nodeFileType, false, false, false); clearColumnHBoxLayout->addWidget(clearColumnComboBox); // // Remove file column radio button // QHBoxLayout* removeColumnHBoxLayout = new QHBoxLayout; dialogLayout->addLayout(removeColumnHBoxLayout); removeColumnRadioButton = new QRadioButton("Remove File Column"); removeColumnHBoxLayout->addWidget(removeColumnRadioButton); radioButtonGroup->addButton(removeColumnRadioButton); removeColumnComboBox = new GuiNodeAttributeColumnSelectionComboBox( nodeFileType, false, false, false); removeColumnHBoxLayout->addWidget(removeColumnComboBox); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); dialogLayout->addLayout(buttonsLayout); // // Apply button // QPushButton* applyButton = new QPushButton("Apply"); applyButton->setAutoDefault(false); buttonsLayout->addWidget(applyButton); QObject::connect(applyButton, SIGNAL(clicked()), this, SLOT(slotApplyButton())); // // Close button connects to QDialogs close() slot. // QPushButton* closeButton = new QPushButton("Close"); closeButton->setAutoDefault(false); buttonsLayout->addWidget(closeButton); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); QtUtilities::makeButtonsSameSize(applyButton, closeButton); updateDialog(); } /** * Destructor */ GuiNodeAttributeFileClearResetDialog::~GuiNodeAttributeFileClearResetDialog() { } /** * called when apply button pressed. */ void GuiNodeAttributeFileClearResetDialog::slotApplyButton() { BrainSet* bs = theMainWindow->getBrainSet(); GuiFilesModified fm; switch (nodeFileType) { case GUI_NODE_FILE_TYPE_NONE: break; case GUI_NODE_FILE_TYPE_AREAL_ESTIMATION: if (clearFileRadioButton->isChecked()) { bs->clearArealEstimationFile(); } else if (clearColumnRadioButton->isChecked()) { bs->getArealEstimationFile()->resetColumn(clearColumnComboBox->currentIndex()); } else if (removeColumnRadioButton->isChecked()) { bs->getArealEstimationFile()->removeColumn(removeColumnComboBox->currentIndex()); } bs->getDisplaySettingsArealEstimation()->update(); fm.setArealEstimationModified(); break; case GUI_NODE_FILE_TYPE_DEFORMATION_FIELD: if (clearFileRadioButton->isChecked()) { bs->clearDeformationFieldFile(); } else if (clearColumnRadioButton->isChecked()) { bs->getDeformationFieldFile()->resetColumn(clearColumnComboBox->currentIndex()); } else if (removeColumnRadioButton->isChecked()) { bs->getDeformationFieldFile()->removeColumn(removeColumnComboBox->currentIndex()); } bs->getDisplaySettingsDeformationField()->update(); fm.setDeformationFieldModified(); break; case GUI_NODE_FILE_TYPE_GEODESIC_DISTANCE: if (clearFileRadioButton->isChecked()) { bs->clearGeodesicDistanceFile(); } else if (clearColumnRadioButton->isChecked()) { bs->getGeodesicDistanceFile()->resetColumn(clearColumnComboBox->currentIndex()); } else if (removeColumnRadioButton->isChecked()) { bs->getGeodesicDistanceFile()->removeColumn(removeColumnComboBox->currentIndex()); } bs->getDisplaySettingsGeodesicDistance()->update(); fm.setGeodesicModified(); break; case GUI_NODE_FILE_TYPE_LAT_LON: if (clearFileRadioButton->isChecked()) { bs->clearLatLonFile(); } else if (clearColumnRadioButton->isChecked()) { bs->getLatLonFile()->resetColumn(clearColumnComboBox->currentIndex()); } else if (removeColumnRadioButton->isChecked()) { bs->getLatLonFile()->removeColumn(removeColumnComboBox->currentIndex()); } fm.setLatLonModified(); break; case GUI_NODE_FILE_TYPE_METRIC: if (clearFileRadioButton->isChecked()) { bs->clearMetricFile(); } else if (clearColumnRadioButton->isChecked()) { bs->getMetricFile()->resetColumn(clearColumnComboBox->currentIndex()); } else if (removeColumnRadioButton->isChecked()) { bs->getMetricFile()->removeColumn(removeColumnComboBox->currentIndex()); } bs->getDisplaySettingsMetric()->update(); fm.setMetricModified(); break; case GUI_NODE_FILE_TYPE_PAINT: if (clearFileRadioButton->isChecked()) { bs->clearPaintFile(); } else if (clearColumnRadioButton->isChecked()) { bs->getPaintFile()->resetColumn(clearColumnComboBox->currentIndex()); } else if (removeColumnRadioButton->isChecked()) { bs->getPaintFile()->removeColumn(removeColumnComboBox->currentIndex()); } bs->getDisplaySettingsPaint()->update(); fm.setPaintModified(); break; case GUI_NODE_PROBABILISTIC_ATLAS: if (clearFileRadioButton->isChecked()) { bs->clearProbabilisticAtlasFile(); } else if (clearColumnRadioButton->isChecked()) { bs->getProbabilisticAtlasSurfaceFile()->resetColumn(clearColumnComboBox->currentIndex()); } else if (removeColumnRadioButton->isChecked()) { bs->getProbabilisticAtlasSurfaceFile()->removeColumn(removeColumnComboBox->currentIndex()); } bs->getDisplaySettingsProbabilisticAtlasSurface()->update(); fm.setProbabilisticAtlasModified(); break; case GUI_NODE_FILE_TYPE_RGB_PAINT: if (clearFileRadioButton->isChecked()) { bs->clearRgbPaintFile(); } else if (clearColumnRadioButton->isChecked()) { bs->getRgbPaintFile()->resetColumn(clearColumnComboBox->currentIndex()); } else if (removeColumnRadioButton->isChecked()) { bs->getRgbPaintFile()->removeColumn(removeColumnComboBox->currentIndex()); } bs->getDisplaySettingsRgbPaint()->update(); fm.setRgbPaintModified(); break; case GUI_NODE_FILE_TYPE_SECTION: if (clearFileRadioButton->isChecked()) { bs->clearSectionFile(); } else if (clearColumnRadioButton->isChecked()) { bs->getSectionFile()->resetColumn(clearColumnComboBox->currentIndex()); } else if (removeColumnRadioButton->isChecked()) { bs->getSectionFile()->removeColumn(removeColumnComboBox->currentIndex()); } bs->getDisplaySettingsSection()->update(); fm.setSectionModified(); break; case GUI_NODE_FILE_TYPE_SURFACE_SHAPE: if (clearFileRadioButton->isChecked()) { bs->clearSurfaceShapeFile(); } else if (clearColumnRadioButton->isChecked()) { bs->getSurfaceShapeFile()->resetColumn(clearColumnComboBox->currentIndex()); } else if (removeColumnRadioButton->isChecked()) { bs->getSurfaceShapeFile()->removeColumn(removeColumnComboBox->currentIndex()); } bs->getDisplaySettingsSurfaceShape()->update(); fm.setSurfaceShapeModified(); break; case GUI_NODE_FILE_TYPE_TOPOGRAPHY: if (clearFileRadioButton->isChecked()) { bs->clearTopographyFile(); } else if (clearColumnRadioButton->isChecked()) { bs->getTopographyFile()->resetColumn(clearColumnComboBox->currentIndex()); } else if (removeColumnRadioButton->isChecked()) { bs->getTopographyFile()->removeColumn(removeColumnComboBox->currentIndex()); } bs->getDisplaySettingsTopography()->update(); fm.setTopographyModified(); break; } theMainWindow->fileModificationUpdate(fm); bs->getNodeColoring()->assignColors(); GuiBrainModelOpenGL::updateAllGL(); updateDialog(); } /** * called to update the dialog. */ void GuiNodeAttributeFileClearResetDialog::updateDialog() { const bool haveColumns = (clearColumnComboBox->count() > 0); clearColumnComboBox->setEnabled(haveColumns); removeColumnComboBox->setEnabled(haveColumns); clearFileRadioButton->setEnabled(haveColumns); clearColumnRadioButton->setEnabled(haveColumns); removeColumnRadioButton->setEnabled(haveColumns); clearColumnComboBox->updateComboBox(); removeColumnComboBox->updateComboBox(); } caret-5.6.4~dfsg.1.orig/caret/GuiNodeAttributeColumnSelectionComboBox.h0000664000175000017500000001321411572067322025724 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_NODE_ATTRIBUTE_COLUMN_SELECTION_COMBO_BOX_H__ #define __GUI_NODE_ATTRIBUTE_COLUMN_SELECTION_COMBO_BOX_H__ #include #include #include #include "GuiNodeFileType.h" class GiftiNodeDataFile; class NodeAttributeFile; /// This class is used to select a column in a node attribute file class GuiNodeAttributeColumnSelectionComboBox : public QComboBox { Q_OBJECT public: enum { CURRENT_ITEM_INVALID = -1, // -1 is current item when combo box is empty CURRENT_ITEM_NEW = -2, CURRENT_ITEM_NONE = -3, CURRENT_ITEM_ALL = -4 }; /// Constructor USE THIS FOR ANY FILE IN THE BRAIN SET GuiNodeAttributeColumnSelectionComboBox(const GUI_NODE_FILE_TYPE nodeFileTypeIn, const bool addNewSelection, const bool addNoneSelection, const bool addAllSelection, QWidget* parent = 0); /// Constructor USE ONLY WITH FILES THAT ARE NOT IN THE BRAIN SET GuiNodeAttributeColumnSelectionComboBox(NodeAttributeFile* nonBrainSetNodeAttributeFileIn, const bool addNewSelection, const bool addNoneSelection, const bool addAllSelection, QWidget* parent = 0); /// Constructor USE ONLY WITH FILES THAT ARE NOT IN THE BRAIN SET GuiNodeAttributeColumnSelectionComboBox(GiftiNodeDataFile* nonBrainSetGiftiNodeDataFileIn, const bool addNewSelection, const bool addNoneSelection, const bool addAllSelection, QWidget* parent = 0); /// Destructor ~GuiNodeAttributeColumnSelectionComboBox(); // get all selected bool getAllSelected() const; // get none selected bool getNoneSelected() const; // get new selected bool getNewSelected() const; /// get the current label QString getCurrentLabel() const; /// get the current item int currentIndex() const; /// set the current item void setCurrentIndex(int item); /// get the new column label QString getNewColumnLabel() const { return newSelectionLabel; } /// set the none selection entry string void setNoneSelectionLabel(const QString& s); /// update the control void updateComboBox(); /// update the control void updateComboBox(NodeAttributeFile* naf); /// update the control void updateComboBox(GiftiNodeDataFile* ndf); /// enable/disable the ALL selection void enableDisableAllSelection(const bool enableIt); signals: /// Emitted when item is selected (catches activated(int) signal and /// passes item selected, or CURRENT_ITEM_NEW or CURRENT_ITEM_NONE) void itemSelected(int); /// Emitted when item is selected emitting the name of the column void itemNameSelected(const QString&); private slots: /// called when an item is selected void slotActivated(); private: /// initialize the dialog void initializeDialog(const GUI_NODE_FILE_TYPE nodeFileTypeIn, NodeAttributeFile* nonBrainSetNodeAttributeFileIn, GiftiNodeDataFile* nonBrainSetGiftiNodeDataFileIn, const bool addNewSelection, const bool addNoneSelection, const bool addAllSelection); /// node attribute file for non-brain set files NodeAttributeFile* nonBrainSetNodeAttributeFile; /// gifti node file for non-brain set files GiftiNodeDataFile* nonBrainSetGiftiNodeDataFile; /// type of node data file GUI_NODE_FILE_TYPE nodeFileType; /// New Column label QString newSelectionLabel; /// all columns label QString allSelectionLabel; /// None selection label QString noneSelectionLabel; /// allow a new column selection bool allowNewColumnSelection; /// allow a none selection bool allowNoneColumnSelection; /// allow an all selection bool allowAllColumnSelection; /// values corresponding to combo box entries, column numbers, neg for special (none, new, all) std::vector itemValues; }; #endif // __GUI_NODE_ATTRIBUTE_COLUMN_SELECTION_COMBO_BOX_H__ caret-5.6.4~dfsg.1.orig/caret/GuiNodeAttributeColumnSelectionComboBox.cxx0000664000175000017500000003040011572067322026273 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "ArealEstimationFile.h" #include "BrainSet.h" #include "DeformationFieldFile.h" #include "DeformationMapFile.h" #include "GeodesicDistanceFile.h" #include "GuiNodeAttributeColumnSelectionComboBox.h" #include "GiftiNodeDataFile.h" #include "GuiMainWindow.h" #include "LatLonFile.h" #include "NodeAttributeFile.h" #include "PaintFile.h" #include "RgbPaintFile.h" #include "SectionFile.h" #include "SurfaceShapeFile.h" #include "ProbabilisticAtlasFile.h" #include "TopographyFile.h" #include "global_variables.h" /** * Constructor. */ GuiNodeAttributeColumnSelectionComboBox::GuiNodeAttributeColumnSelectionComboBox( const GUI_NODE_FILE_TYPE nodeFileTypeIn, const bool addNewSelection, const bool addNoneSelection, const bool addAllSelection, QWidget* parent) : QComboBox(parent) { initializeDialog(nodeFileTypeIn, NULL, NULL, addNewSelection, addNoneSelection, addAllSelection); } /** * Constructor. * USE ONLY WITH FILES THAT ARE NOT IN THE BRAIN SET */ GuiNodeAttributeColumnSelectionComboBox::GuiNodeAttributeColumnSelectionComboBox( NodeAttributeFile* nonBrainSetNodeAttributeFileIn, const bool addNewSelection, const bool addNoneSelection, const bool addAllSelection, QWidget* parent) : QComboBox(parent) { initializeDialog(GUI_NODE_FILE_TYPE_NONE, nonBrainSetNodeAttributeFileIn, NULL, addNewSelection, addNoneSelection, addAllSelection); } /** * Constructor * USE ONLY WITH FILES THAT ARE NOT IN THE BRAIN SET */ GuiNodeAttributeColumnSelectionComboBox::GuiNodeAttributeColumnSelectionComboBox( GiftiNodeDataFile* nonBrainSetGiftiNodeDataFileIn, const bool addNewSelection, const bool addNoneSelection, const bool addAllSelection, QWidget* parent) : QComboBox(parent) { initializeDialog(GUI_NODE_FILE_TYPE_NONE, NULL, nonBrainSetGiftiNodeDataFileIn, addNewSelection, addNoneSelection, addAllSelection); } /** * initialize the dialog. */ void GuiNodeAttributeColumnSelectionComboBox::initializeDialog( const GUI_NODE_FILE_TYPE nodeFileTypeIn, NodeAttributeFile* nonBrainSetNodeAttributeFileIn, GiftiNodeDataFile* nonBrainSetGiftiNodeDataFileIn, const bool addNewSelection, const bool addNoneSelection, const bool addAllSelection) { nodeFileType = nodeFileTypeIn; nonBrainSetNodeAttributeFile = nonBrainSetNodeAttributeFileIn; nonBrainSetGiftiNodeDataFile = nonBrainSetGiftiNodeDataFileIn; QObject::connect(this, SIGNAL(activated(int)), this, SLOT(slotActivated())); allowNewColumnSelection = addNewSelection; allowNoneColumnSelection = addNoneSelection; allowAllColumnSelection = addAllSelection; noneSelectionLabel = "None"; newSelectionLabel = "Create New Column"; allSelectionLabel = "All Columns"; updateComboBox(); } /** * Destructor. */ GuiNodeAttributeColumnSelectionComboBox::~GuiNodeAttributeColumnSelectionComboBox() { } /** * set the none selection entry string. */ void GuiNodeAttributeColumnSelectionComboBox::setNoneSelectionLabel(const QString& s) { noneSelectionLabel = s; updateComboBox(); } /** * called by QComboBox when an item is selected */ void GuiNodeAttributeColumnSelectionComboBox::slotActivated() { const int item = currentIndex(); emit itemSelected(item); QString name; if (item == CURRENT_ITEM_NEW) { name = newSelectionLabel; } else if (item == CURRENT_ITEM_NONE) { name = noneSelectionLabel; } else if (item == CURRENT_ITEM_ALL) { name = allSelectionLabel; } else if (item >= 0) { name = currentText(); } emit itemNameSelected(name); } /** * Get the current selection * Returns CURRENT_ITEM_NEW if a new column is selected. * CURRENT_ITEM_NONE if none is selected * CURRENT_ITEM_ALL if all columns is selected */ int GuiNodeAttributeColumnSelectionComboBox::currentIndex() const { const int item = QComboBox::currentIndex(); if ((item < 0) || (item >= static_cast(itemValues.size()))) { return CURRENT_ITEM_INVALID; } return itemValues[item]; } /** * Get the current label */ QString GuiNodeAttributeColumnSelectionComboBox::getCurrentLabel() const { return currentText(); } /** * Set the current selection * Pass CURRENT_ITEM_NEW for new column. * CURRENT_ITEM_NONE for none. */ void GuiNodeAttributeColumnSelectionComboBox::setCurrentIndex(int itemIn) { int selectedItem = CURRENT_ITEM_INVALID; for (int i = 0; i < static_cast(itemValues.size()); i++) { if (itemValues[i] == itemIn) { selectedItem = i; break; } } if (selectedItem != CURRENT_ITEM_INVALID) { QComboBox::setCurrentIndex(selectedItem); } } /** * Enable/Disable the ALL selection. */ void GuiNodeAttributeColumnSelectionComboBox::enableDisableAllSelection(const bool enableIt) { allowAllColumnSelection = enableIt; updateComboBox(); } /** * Update the combo box */ void GuiNodeAttributeColumnSelectionComboBox::updateComboBox() { NodeAttributeFile* nodeAttFile = NULL; GiftiNodeDataFile* giftiNodeDataFile = NULL; BrainSet* bs = theMainWindow->getBrainSet(); switch (nodeFileType) { case GUI_NODE_FILE_TYPE_NONE: if (nonBrainSetNodeAttributeFile) { nodeAttFile = nonBrainSetNodeAttributeFile; } else if (nonBrainSetGiftiNodeDataFile != NULL) { giftiNodeDataFile = nonBrainSetGiftiNodeDataFile; } break; case GUI_NODE_FILE_TYPE_AREAL_ESTIMATION: nodeAttFile = bs->getArealEstimationFile(); break; case GUI_NODE_FILE_TYPE_DEFORMATION_FIELD: nodeAttFile = bs->getDeformationFieldFile(); break; case GUI_NODE_FILE_TYPE_GEODESIC_DISTANCE: nodeAttFile = bs->getGeodesicDistanceFile(); break; case GUI_NODE_FILE_TYPE_LAT_LON: nodeAttFile = bs->getLatLonFile(); break; case GUI_NODE_FILE_TYPE_METRIC: // gifti giftiNodeDataFile = bs->getMetricFile(); break; case GUI_NODE_FILE_TYPE_PAINT: // gifti giftiNodeDataFile = bs->getPaintFile(); break; case GUI_NODE_PROBABILISTIC_ATLAS: giftiNodeDataFile = bs->getProbabilisticAtlasSurfaceFile(); break; case GUI_NODE_FILE_TYPE_RGB_PAINT: nodeAttFile = bs->getRgbPaintFile(); break; case GUI_NODE_FILE_TYPE_SECTION: nodeAttFile = bs->getSectionFile(); break; case GUI_NODE_FILE_TYPE_SURFACE_SHAPE: giftiNodeDataFile = bs->getSurfaceShapeFile(); break; case GUI_NODE_FILE_TYPE_TOPOGRAPHY: nodeAttFile = bs->getTopographyFile(); break; } if (nodeAttFile != NULL) { updateComboBox(nodeAttFile); } else if (giftiNodeDataFile != NULL) { updateComboBox(giftiNodeDataFile); } else { std::cout << "PROGRAM ERROR in GuiNodeAttributeColumnSelectionComboBox::updateComboBox()\n" << " invalid file type." << std::endl; } update(); } /** * Update the combo box */ void GuiNodeAttributeColumnSelectionComboBox::updateComboBox(NodeAttributeFile* nodeAttFile) { // // get the currently selected item // const int selectedItem = currentIndex(); // // Save text of current selection // QString selectedItemText; if (selectedItem != CURRENT_ITEM_INVALID) { selectedItemText = currentText(); } // // clear the combo box and the item values storage // clear(); itemValues.clear(); const int num = nodeAttFile->getNumberOfColumns(); for (int i = 0; i < num; i++) { addItem(nodeAttFile->getColumnName(i)); itemValues.push_back(i); } if (allowNewColumnSelection) { addItem(newSelectionLabel); itemValues.push_back(CURRENT_ITEM_NEW); } if (allowNoneColumnSelection) { addItem(noneSelectionLabel); itemValues.push_back(CURRENT_ITEM_NONE); } if (allowAllColumnSelection) { addItem(allSelectionLabel); itemValues.push_back(CURRENT_ITEM_ALL); } // // try to find previously selected item // int item = 0; if (selectedItemText.isEmpty() == false) { for (int i = 0; i < count(); i++) { if (itemText(i) == selectedItemText) { item = itemValues[i]; break; } } } // // Set the current item // //if ((item >= 0) && (item < count())) { setCurrentIndex(item); //} } /** * Update the combo box */ void GuiNodeAttributeColumnSelectionComboBox::updateComboBox(GiftiNodeDataFile* giftiNodeDataFile) { // // get the currently selected item // const int selectedItem = currentIndex(); // // Save text of current selection // QString selectedItemText; if (selectedItem != CURRENT_ITEM_INVALID) { selectedItemText = currentText(); } // // clear the combo box and the item values storage // clear(); itemValues.clear(); const int num = giftiNodeDataFile->getNumberOfColumns(); for (int i = 0; i < num; i++) { addItem(giftiNodeDataFile->getColumnName(i)); itemValues.push_back(i); } if (allowNewColumnSelection) { addItem(newSelectionLabel); itemValues.push_back(CURRENT_ITEM_NEW); } if (allowNoneColumnSelection) { addItem(noneSelectionLabel); itemValues.push_back(CURRENT_ITEM_NONE); } if (allowAllColumnSelection) { addItem(allSelectionLabel); itemValues.push_back(CURRENT_ITEM_ALL); } // // try to find previously selected item // int item = 0; if (selectedItemText.isEmpty() == false) { for (int i = 0; i < count(); i++) { if (itemText(i) == selectedItemText) { item = itemValues[i]; break; } } } // // Set the current item // //if ((item >= 0) && (item < count())) { setCurrentIndex(item); //} } /** * get all selected. */ bool GuiNodeAttributeColumnSelectionComboBox::getAllSelected() const { if (allowAllColumnSelection) { return (getCurrentLabel() == allSelectionLabel); } return false; } /** * get none selected. */ bool GuiNodeAttributeColumnSelectionComboBox::getNoneSelected() const { if (allowNoneColumnSelection) { return (getCurrentLabel() == noneSelectionLabel); } return false; } /** * get new selected. */ bool GuiNodeAttributeColumnSelectionComboBox::getNewSelected() const { if (allowNewColumnSelection) { return (getCurrentLabel() == newSelectionLabel); } return false; } caret-5.6.4~dfsg.1.orig/caret/GuiNameSelectionDialog.h0000664000175000017500000002330211572067322022343 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_GUI_NAME_SELECTION_DIALOG_H__ #define __VE_GUI_NAME_SELECTION_DIALOG_H__ #include #include #include "WuQDialog.h" class ColorFile; class QListWidget; class QListWidgetItem; class QComboBox; /// This class displays a dialog that allows the user to choose from a variety /// of data types' names. class GuiNameSelectionDialog : public WuQDialog { Q_OBJECT public: enum LIST_ITEMS_TYPE { LIST_NONE = 0, LIST_AREA_COLORS_ALPHA = 1, // 2^0 LIST_BORDER_NAMES_ALPHA = 2, // 2^1 LIST_BORDER_COLORS_ALPHA = 4, // 2^2 LIST_BORDER_COLORS_FILE = 8, // 2^3 LIST_CELL_COLORS_ALPHA = 16, // 2^4 LIST_CELL_COLORS_FILE = 32, // 2^5 LIST_FOCI_AREAS_ALPHA = 64, // 2^6 LIST_FOCI_CLASSES_ALPHA = 128, // 2^7 LIST_FOCI_COMMENT_ALPHA = 256, // 2^8 LIST_FOCI_GEOGRAPHY_ALPHA = 512, // 2^9 LIST_FOCI_ROI_ALPHA = 1024, // 2^10 LIST_FOCI_NAMES_ALPHA = 2048, // 2^11 LIST_PAINT_NAMES_ALPHA = 4096, // 2^12 LIST_CONTOUR_CELL_COLORS_ALPHA = 8192, // 2^13 LIST_CONTOUR_CELL_COLORS_FILE = 16384, // 2^14 LIST_VOCABULARY_ALPHA = 32768, // 2^15 LIST_SPECIES = 65536, // 2^16 LIST_STEREOTAXIC_SPACES = 131072, // 2^17 LIST_STATISTICS = 262144, // 2^18 LIST_STRUCTURE = 524288, // 2^19 LIST_STUDY_CITATION = 1048576, // 2^20 LIST_STUDY_DATA_FORMAT = 2097152, // 2^21 LIST_STUDY_DATA_TYPE = 4194304, // 2^22 LIST_STUDY_KEYWORDS_ALPHA = 8388608, // 2^23 LIST_STUDY_MESH_ALPHA = 16777216, // 2^24 LIST_STUDY_TABLE_HEADERS = 33554432, // 2^25 LIST_STUDY_TABLE_SUBHEADERS = 67108864, // 2^26 LIST_VOLUME_PAINT_NAMES_ALPHA = 134217728, // 2^27 LIST_ALL = 0xffffffff }; /// Constructor GuiNameSelectionDialog(QWidget* parent, const unsigned int itemsToDisplay = LIST_ALL, const LIST_ITEMS_TYPE defaultItem = LIST_NONE, const bool allowMultipleSelectionsFlagIn = false); /// Destructor ~GuiNameSelectionDialog(); /// Get the names that were selected (use if multiple selections) QStringList getNamesSelected() const; /// Get the name that was selected (use if single selections) QString getNameSelected() const; /// Get the selected item type LIST_ITEMS_TYPE getSelectedItemType() const; private slots: /// called when a file type radio button is pressed void fileTypeSelectionSlot(int buttNum); private: /// Add a color file to this list box void addColorFileToListBox(ColorFile* cf, const bool sortThem); /// Add the names to the list box and possibly sort them void addNamesToListBox(std::vector& names, const bool sortThem); /// load the names for the file type and order void loadAreaColorsAlphaOrder(); /// load the names for the file type and order void loadBorderNamesAlphaOrder(); /// load the names for the file type and order void loadBorderColorsAlphaOrder(); /// load the names for the file type and order void loadBorderColorsFileOrder(); /// load the name for the file type and order void loadFociNamesAlphaOrder(); /// load the name for the file type and order void loadFociClassesAlphaOrder(); /// load the name for the file type and order void loadFociAreasAlphaOrder(); /// load the names for the file type and order void loadFociCommentAlphaOrder(); /// load the name for the file type and order void loadFociGeographyAlphaOrder(); /// load the names for the file type and order void loadFociROIAlphaOrder(); /// load the names for the file type and order void loadCellColorsAlphaOrder(); /// load the names for the file type and order void loadCellColorsFileOrder(); /// load the names for the file type and order void loadPaintNamesAlphaOrder(); /// load the names for the file type and order void loadContourCellColorsAlphaOrder(); /// load the names for the file type and order void loadContourCellColorsFileOrder(); /// load the names for the file type and order void loadVocabularyAlphaOrder(); /// load volume paint name in alpha order void loadVolumePaintNamesAlpha(); /// load the species names void loadSpecies(); /// load the stereotaxic space names void loadStereotaxicSpaces(); /// load the statistics void loadStatistics(); /// load the structures void loadStructures(); /// load the study citations void loadStudyCitation(); /// load the study data format void loadStudyDataFormat(); /// load the study data type void loadStudyDataType(); /// load the name for the file type and order void loadStudyKeywords(); /// load the name for the file type and order void loadStudyMedialSubjectHeadings(); /// load study table headers void loadStudyTableHeaders(); /// load study table subheaders void loadStudyTableSubHeaders(); /// selected name QString name; /// the list box containing names QListWidget* nameListBox; /// allow multiple selections bool allowMultipleSelectionsFlag; /// default selected item static int defaultSelection; /// item number for area colors alphabetical int areaColorsAlphaItemNumber; /// item number for border names alphabetical int borderNamesAlphaItemNumber; /// item number for border colors alphabetical int borderColorsAlphaItemNumber; /// item number for border colors file order int borderColorsFileItemNumber; /// item number for cell colors alphabetical int cellColorsAlphaItemNumber; /// item number for cell colors file order int cellColorsFileItemNumber; /// item number for foci names alphabetical int fociNamesAlphaItemNumber; /// item number for foci areas alphabetical int fociAreasAlphaItemNumber; /// item number for foci classes alphabetical int fociClassesAlphaItemNumber; /// item number for foci comment alphabetical int fociCommentAlphaItemNumber; /// item number for foci geography alphabetical int fociGeographyAlphaItemNumber; /// item number for foci roi alphabetical int fociRegionOfInterestAlphaItemNumber; /// item number for paint names alphabetical int paintNamesAlphaItemNumber; /// item number for contour cell colors alphabetical int contourCellColorsAlphaItemNumber; /// item number for contour cell colors file order int contourCellColorsFileItemNumber; /// item number for vocabulary alpha order int vocabularyAlphaItemNumber; /// item number for volume paint names alpha order int volumePaintNamesAlphaOrderItemNumber; /// item number for species int speciesItemNumber; /// item number for stereotaxic spaces int stereotaxicSpaceItemNumber; /// item number for structures int structuresItemNumber; /// item number for study study citation int studyCitationItemNumber; /// item number for study data format int studyDataFormatItemNumber; /// item number for study data type int studyDataTypeItemNumber; /// item number for study keywords int studyKeywordsItemNumber; /// item number for study medical subject headings int studyMedicalSubjectHeadingsItemNumber; /// item number for study table headers int studyTableHeadersItemNumber; /// item number for study table subheaders int studyTableSubHeadersItemNumber; /// item number for statistics int statisticsItemNumber; /// combo box for file type selection QComboBox* fileTypeComboBox; }; #ifdef __NAME_DIALOG_MAIN__ int GuiNameSelectionDialog::defaultSelection = 2; #endif #endif // __VE_GUI_NAME_SELECTION_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiNameSelectionDialog.cxx0000664000175000017500000006755211572067322022735 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include "AreaColorFile.h" #include "BorderColorFile.h" #include "BorderFile.h" #include "BrainModelBorderSet.h" #include "BrainModelVolume.h" #include "BrainSet.h" #include "CellColorFile.h" #include "CellFile.h" #include "ColorFile.h" #include "ContourCellColorFile.h" #include "GuiMainWindow.h" #include "FociProjectionFile.h" #include "PaintFile.h" #include "QtUtilities.h" #include "Species.h" #include "StatisticTestNames.h" #include "StereotaxicSpace.h" #include "StringUtilities.h" #include "Structure.h" #include "StudyMetaDataFile.h" #include "VocabularyFile.h" #include "VolumeFile.h" #include "global_variables.h" #define __NAME_DIALOG_MAIN__ #include "GuiNameSelectionDialog.h" #undef __NAME_DIALOG_MAIN__ /** * Constructor */ GuiNameSelectionDialog::GuiNameSelectionDialog(QWidget* parent, const unsigned int itemsToDisplay, const LIST_ITEMS_TYPE defaultItem, const bool allowMultipleSelectionsFlagIn) : WuQDialog(parent) { setModal(true); setWindowTitle("Name Selection"); allowMultipleSelectionsFlag = allowMultipleSelectionsFlagIn; // // layout for dialog // QVBoxLayout* rows = new QVBoxLayout(this); rows->setMargin(5); // // Combo box for name types // fileTypeComboBox = new QComboBox(this); rows->addWidget(fileTypeComboBox); QObject::connect(fileTypeComboBox, SIGNAL(activated(int)), this, SLOT(fileTypeSelectionSlot(int))); areaColorsAlphaItemNumber = -1; borderNamesAlphaItemNumber = -1; borderColorsAlphaItemNumber = -1; borderColorsFileItemNumber = -1; cellColorsAlphaItemNumber = -1; cellColorsFileItemNumber = -1; fociAreasAlphaItemNumber = -1; fociClassesAlphaItemNumber = -1; fociCommentAlphaItemNumber = -1; fociGeographyAlphaItemNumber = -1; fociNamesAlphaItemNumber = -1; fociRegionOfInterestAlphaItemNumber = -1; paintNamesAlphaItemNumber = -1; contourCellColorsAlphaItemNumber = -1; contourCellColorsFileItemNumber = -1; vocabularyAlphaItemNumber = -1; speciesItemNumber = -1; stereotaxicSpaceItemNumber = -1; statisticsItemNumber = -1; structuresItemNumber = -1; studyCitationItemNumber = -1; studyDataFormatItemNumber = -1; studyDataTypeItemNumber = -1; studyKeywordsItemNumber = -1; studyMedicalSubjectHeadingsItemNumber = -1; studyTableHeadersItemNumber = -1; studyTableSubHeadersItemNumber = -1; volumePaintNamesAlphaOrderItemNumber = -1; int itemNumber = 0; defaultSelection = 0; if (itemsToDisplay & LIST_AREA_COLORS_ALPHA) { fileTypeComboBox->addItem("Area Colors (alphabetical)"); if (defaultItem == LIST_AREA_COLORS_ALPHA) { defaultSelection = itemNumber; } areaColorsAlphaItemNumber = itemNumber++; } if (itemsToDisplay & LIST_BORDER_NAMES_ALPHA) { fileTypeComboBox->addItem("Border Names (alphabetical)"); if (defaultItem == LIST_BORDER_NAMES_ALPHA) { defaultSelection = itemNumber; } borderNamesAlphaItemNumber = itemNumber++; } if (itemsToDisplay & LIST_BORDER_COLORS_ALPHA) { fileTypeComboBox->addItem("Border Colors (alphabetical)"); if (defaultItem == LIST_BORDER_COLORS_ALPHA) { defaultSelection = itemNumber; } borderColorsAlphaItemNumber = itemNumber++; } if (itemsToDisplay & LIST_BORDER_COLORS_FILE) { fileTypeComboBox->addItem("Border Colors (file order)"); if (defaultItem == LIST_BORDER_COLORS_FILE) { defaultSelection = itemNumber; } borderColorsFileItemNumber = itemNumber++; } if (itemsToDisplay & LIST_CELL_COLORS_ALPHA) { fileTypeComboBox->addItem("Cell Colors (alphabetical)"); if (defaultItem == LIST_CELL_COLORS_ALPHA) { defaultSelection = itemNumber; } cellColorsAlphaItemNumber = itemNumber++; } if (itemsToDisplay & LIST_CELL_COLORS_FILE) { fileTypeComboBox->addItem("Cell Colors (file order)"); if (defaultItem == LIST_CELL_COLORS_FILE) { defaultSelection = itemNumber; } cellColorsFileItemNumber = itemNumber++; } if (itemsToDisplay & LIST_CONTOUR_CELL_COLORS_ALPHA) { fileTypeComboBox->addItem("Contour Cell Colors (alphabetical)"); if (defaultItem == LIST_CONTOUR_CELL_COLORS_ALPHA) { defaultSelection = itemNumber; } contourCellColorsAlphaItemNumber = itemNumber++; } if (itemsToDisplay & LIST_CONTOUR_CELL_COLORS_FILE) { fileTypeComboBox->addItem("Contour Cell Colors (file order)"); if (defaultItem == LIST_CONTOUR_CELL_COLORS_FILE) { defaultSelection = itemNumber; } contourCellColorsFileItemNumber = itemNumber++; } if (itemsToDisplay & LIST_FOCI_AREAS_ALPHA) { fileTypeComboBox->addItem("Foci Areas (alphabetical)"); if (defaultItem == LIST_FOCI_AREAS_ALPHA) { defaultSelection = itemNumber; } fociAreasAlphaItemNumber = itemNumber++; } if (itemsToDisplay & LIST_FOCI_CLASSES_ALPHA) { fileTypeComboBox->addItem("Foci Classes (alphabetical)"); if (defaultItem == LIST_FOCI_CLASSES_ALPHA) { defaultSelection = itemNumber; } fociClassesAlphaItemNumber = itemNumber++; } if (itemsToDisplay & LIST_FOCI_COMMENT_ALPHA) { fileTypeComboBox->addItem("Foci Comments (alphabetical)"); if (defaultItem == LIST_FOCI_COMMENT_ALPHA) { defaultSelection = itemNumber; } fociCommentAlphaItemNumber = itemNumber++; } if (itemsToDisplay & LIST_FOCI_GEOGRAPHY_ALPHA) { fileTypeComboBox->addItem("Foci Geography (alphabetical)"); if (defaultItem == LIST_FOCI_GEOGRAPHY_ALPHA) { defaultSelection = itemNumber; } fociGeographyAlphaItemNumber = itemNumber++; } if (itemsToDisplay & LIST_FOCI_NAMES_ALPHA) { fileTypeComboBox->addItem("Foci Names (alphabetical)"); if (defaultItem == LIST_FOCI_NAMES_ALPHA) { defaultSelection = itemNumber; } fociNamesAlphaItemNumber = itemNumber++; } if (itemsToDisplay & LIST_FOCI_ROI_ALPHA) { fileTypeComboBox->addItem("Foci ROI (alphabetical)"); if (defaultItem == LIST_FOCI_ROI_ALPHA) { defaultSelection = itemNumber; } fociRegionOfInterestAlphaItemNumber = itemNumber++; } if (itemsToDisplay & LIST_PAINT_NAMES_ALPHA) { fileTypeComboBox->addItem("Paint Names (alphabetical)"); if (defaultItem == LIST_PAINT_NAMES_ALPHA) { defaultSelection = itemNumber; } paintNamesAlphaItemNumber = itemNumber++; } if (itemsToDisplay & LIST_SPECIES) { fileTypeComboBox->addItem("Species"); if (defaultItem == LIST_SPECIES) { defaultSelection = itemNumber; } speciesItemNumber = itemNumber++; } if (itemsToDisplay & LIST_STATISTICS) { fileTypeComboBox->addItem("Statistics"); if (defaultItem == LIST_STATISTICS) { defaultSelection = itemNumber; } statisticsItemNumber = itemNumber++; } if (itemsToDisplay & LIST_STEREOTAXIC_SPACES) { fileTypeComboBox->addItem("Stereotaxic Spaces"); if (defaultItem == LIST_STEREOTAXIC_SPACES) { defaultSelection = itemNumber; } stereotaxicSpaceItemNumber = itemNumber++; } if (itemsToDisplay & LIST_STRUCTURE) { fileTypeComboBox->addItem("Structure"); if (defaultItem == LIST_STRUCTURE) { defaultSelection = itemNumber; } structuresItemNumber = itemNumber++; } if (itemsToDisplay & LIST_STUDY_CITATION) { fileTypeComboBox->addItem("Study Citation"); if (defaultItem == LIST_STUDY_CITATION) { defaultSelection = itemNumber; } studyCitationItemNumber = itemNumber++; } if (itemsToDisplay & LIST_STUDY_DATA_FORMAT) { fileTypeComboBox->addItem("Study Data Format"); if (defaultItem == LIST_STUDY_DATA_FORMAT) { defaultSelection = itemNumber; } studyDataFormatItemNumber = itemNumber++; } if (itemsToDisplay & LIST_STUDY_DATA_TYPE) { fileTypeComboBox->addItem("Study Data Type"); if (defaultItem == LIST_STUDY_DATA_TYPE) { defaultSelection = itemNumber; } studyDataTypeItemNumber = itemNumber++; } if (itemsToDisplay & LIST_STUDY_KEYWORDS_ALPHA) { fileTypeComboBox->addItem("Study Keywords (alphabetical)"); if (defaultItem == LIST_STUDY_KEYWORDS_ALPHA) { defaultSelection = itemNumber; } studyKeywordsItemNumber = itemNumber++; } if (itemsToDisplay & LIST_STUDY_MESH_ALPHA) { fileTypeComboBox->addItem("Study Medical Subject Headings (alphabetical)"); if (defaultItem == LIST_STUDY_MESH_ALPHA) { defaultSelection = itemNumber; } studyMedicalSubjectHeadingsItemNumber = itemNumber++; } if (itemsToDisplay & LIST_STUDY_TABLE_HEADERS) { fileTypeComboBox->addItem("Study Table Headers (alphabetical)"); if (defaultItem == LIST_STUDY_TABLE_HEADERS) { defaultSelection = itemNumber; } studyTableHeadersItemNumber = itemNumber++; } if (itemsToDisplay & LIST_STUDY_TABLE_SUBHEADERS) { fileTypeComboBox->addItem("Study Table Tab SubHeaders (alphabetical)"); if (defaultItem == LIST_STUDY_TABLE_SUBHEADERS) { defaultSelection = itemNumber; } studyTableSubHeadersItemNumber = itemNumber++; } if (itemsToDisplay & LIST_VOCABULARY_ALPHA) { fileTypeComboBox->addItem("Vocabulary Abbreviations (alphabetical)"); if (defaultItem == LIST_VOCABULARY_ALPHA) { defaultSelection = itemNumber; } vocabularyAlphaItemNumber = itemNumber++; } if (itemsToDisplay & LIST_VOLUME_PAINT_NAMES_ALPHA) { fileTypeComboBox->addItem("Volume Paint Names (alphabetical)"); if (defaultItem == LIST_VOLUME_PAINT_NAMES_ALPHA) { defaultSelection = itemNumber; } volumePaintNamesAlphaOrderItemNumber = itemNumber++; } // // Listbox for names // nameListBox = new QListWidget(this); nameListBox->setMinimumSize(QSize(300, 300)); if (allowMultipleSelectionsFlag) { nameListBox->setSelectionMode(QListWidget::ExtendedSelection); } else { nameListBox->setSelectionMode(QListWidget::SingleSelection); } rows->addWidget(nameListBox); // // Set initial selections // fileTypeComboBox->setCurrentIndex(defaultSelection); fileTypeSelectionSlot(defaultSelection); // // Dialog Buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; rows->addLayout(buttonsLayout); // // OK button // QPushButton* ok = new QPushButton("OK"); QObject::connect(ok, SIGNAL(clicked()), this, SLOT(accept())); buttonsLayout->addWidget(ok); // // Cancel button // QPushButton* cancel = new QPushButton("Cancel"); QObject::connect(cancel, SIGNAL(clicked()), this, SLOT(reject())); buttonsLayout->addWidget(cancel); QtUtilities::makeButtonsSameSize(ok, cancel); } /** * Get the names that were selected (use if multiple selections). */ QStringList GuiNameSelectionDialog::getNamesSelected() const { QStringList sl; const QList selectedItems = nameListBox->selectedItems(); const int num = selectedItems.size(); for (int i = 0; i < num; i++) { sl << selectedItems.at(i)->text(); } return sl; } /** * Get the name that was selected (use if single selections). */ QString GuiNameSelectionDialog::getNameSelected() const { const QStringList nameList = getNamesSelected(); if (nameList.size() > 0) { return nameList.at(0); } return ""; } /** * Get the selected item type. */ GuiNameSelectionDialog::LIST_ITEMS_TYPE GuiNameSelectionDialog::getSelectedItemType() const { const int item = fileTypeComboBox->currentIndex(); if (item == areaColorsAlphaItemNumber) { return LIST_AREA_COLORS_ALPHA; } else if (item == borderNamesAlphaItemNumber) { return LIST_BORDER_NAMES_ALPHA; } else if (item == borderColorsAlphaItemNumber) { return LIST_BORDER_COLORS_ALPHA; } else if (item == borderColorsFileItemNumber) { return LIST_BORDER_COLORS_FILE; } else if (item == cellColorsAlphaItemNumber) { return LIST_CELL_COLORS_ALPHA; } else if (item == cellColorsFileItemNumber) { return LIST_CELL_COLORS_FILE; } else if (item == fociAreasAlphaItemNumber) { return LIST_FOCI_AREAS_ALPHA; } else if (item == fociClassesAlphaItemNumber) { return LIST_FOCI_CLASSES_ALPHA; } else if (item == fociCommentAlphaItemNumber) { return LIST_FOCI_COMMENT_ALPHA; } else if (item == fociGeographyAlphaItemNumber) { return LIST_FOCI_GEOGRAPHY_ALPHA; } else if (item == fociNamesAlphaItemNumber) { return LIST_FOCI_NAMES_ALPHA; } else if (item == fociRegionOfInterestAlphaItemNumber) { return LIST_FOCI_ROI_ALPHA; } else if (item == paintNamesAlphaItemNumber) { return LIST_PAINT_NAMES_ALPHA; } else if (item == contourCellColorsAlphaItemNumber) { return LIST_CONTOUR_CELL_COLORS_ALPHA; } else if (item == contourCellColorsFileItemNumber) { return LIST_CONTOUR_CELL_COLORS_FILE; } else if (item == speciesItemNumber) { return LIST_SPECIES; } else if (item == stereotaxicSpaceItemNumber) { return LIST_STEREOTAXIC_SPACES; } else if (item == structuresItemNumber) { return LIST_STRUCTURE; } else if (item == statisticsItemNumber) { return LIST_STATISTICS; } else if (item == studyCitationItemNumber) { return LIST_STUDY_CITATION; } else if (item == studyDataFormatItemNumber) { return LIST_STUDY_DATA_FORMAT; } else if (item == studyDataTypeItemNumber) { return LIST_STUDY_DATA_TYPE; } else if (item == studyKeywordsItemNumber) { return LIST_STUDY_KEYWORDS_ALPHA; } else if (item == studyMedicalSubjectHeadingsItemNumber) { return LIST_STUDY_MESH_ALPHA; } else if (item == studyTableHeadersItemNumber) { return LIST_STUDY_TABLE_HEADERS; } else if (item == studyTableSubHeadersItemNumber) { return LIST_STUDY_TABLE_SUBHEADERS; } else if (item == vocabularyAlphaItemNumber) { return LIST_VOCABULARY_ALPHA; } else if (item == volumePaintNamesAlphaOrderItemNumber) { return LIST_VOLUME_PAINT_NAMES_ALPHA; } return LIST_NONE; } /** * Called when a file type radio button is pressed. Load appropriate names. */ void GuiNameSelectionDialog::fileTypeSelectionSlot(int buttNum) { defaultSelection = buttNum; if (buttNum == areaColorsAlphaItemNumber) { loadAreaColorsAlphaOrder(); } else if (buttNum == borderNamesAlphaItemNumber) { loadBorderNamesAlphaOrder(); } else if (buttNum == borderColorsAlphaItemNumber) { loadBorderColorsAlphaOrder(); } else if (buttNum == borderColorsFileItemNumber) { loadBorderColorsFileOrder(); } else if (buttNum == cellColorsAlphaItemNumber) { loadCellColorsAlphaOrder(); } else if (buttNum == cellColorsFileItemNumber) { loadCellColorsFileOrder(); } else if (buttNum == contourCellColorsAlphaItemNumber) { loadContourCellColorsAlphaOrder(); } else if (buttNum == contourCellColorsFileItemNumber) { loadContourCellColorsFileOrder(); } else if (buttNum == fociAreasAlphaItemNumber) { loadFociAreasAlphaOrder(); } else if (buttNum == fociClassesAlphaItemNumber) { loadFociClassesAlphaOrder(); } else if (buttNum == fociCommentAlphaItemNumber) { loadFociCommentAlphaOrder(); } else if (buttNum == fociGeographyAlphaItemNumber) { loadFociGeographyAlphaOrder(); } else if (buttNum == fociNamesAlphaItemNumber) { loadFociNamesAlphaOrder(); } else if (buttNum == fociRegionOfInterestAlphaItemNumber) { loadFociROIAlphaOrder(); } else if (buttNum == paintNamesAlphaItemNumber) { loadPaintNamesAlphaOrder(); } else if (buttNum == speciesItemNumber) { loadSpecies(); } else if (buttNum == statisticsItemNumber) { loadStatistics(); } else if (buttNum == stereotaxicSpaceItemNumber) { loadStereotaxicSpaces(); } else if (buttNum == structuresItemNumber) { loadStructures(); } else if (buttNum == studyCitationItemNumber) { loadStudyCitation(); } else if (buttNum == studyDataFormatItemNumber) { loadStudyDataFormat(); } else if (buttNum == studyDataTypeItemNumber) { loadStudyDataType(); } else if (buttNum == studyKeywordsItemNumber) { loadStudyKeywords(); } else if (buttNum == studyMedicalSubjectHeadingsItemNumber) { loadStudyMedialSubjectHeadings(); } else if (buttNum == studyTableHeadersItemNumber) { loadStudyTableHeaders(); } else if (buttNum == studyTableSubHeadersItemNumber) { loadStudyTableSubHeaders(); } else if (buttNum == vocabularyAlphaItemNumber) { loadVocabularyAlphaOrder(); } else if (buttNum == volumePaintNamesAlphaOrderItemNumber) { loadVolumePaintNamesAlpha(); } else { nameListBox->clear(); } } /** * Add the names to the list box and sort if necessary. */ void GuiNameSelectionDialog::addNamesToListBox(std::vector& names, const bool sortThem) { nameListBox->clear(); // // Remove blanks // std::remove(names.begin(), names.end(), ""); if (sortThem) { // // sort and remove duplicates // StringUtilities::sortCaseInsensitive(names, false, true); //std::set sorted(names.begin(), names.end()); //names.clear(); //names.insert(names.begin(), sorted.begin(), sorted.end()); } const unsigned int num = names.size(); for (unsigned int i = 0; i < num; i++) { nameListBox->addItem(names[i]); } if (num > 0) { QListWidgetItem item(names[0]); nameListBox->setCurrentRow(0); } } /** * Add a color file to the list box. */ void GuiNameSelectionDialog::addColorFileToListBox(ColorFile* cf, const bool sortThem) { std::vector names; const int num = cf->getNumberOfColors(); for (int i = 0; i < num; i++) { names.push_back(cf->getColorNameByIndex(i)); } addNamesToListBox(names, sortThem); } /** * load the names for paints in alphabetical order */ void GuiNameSelectionDialog::loadPaintNamesAlphaOrder() { std::vector names; PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); int num = pf->getNumberOfPaintNames(); for (int i = 0; i < num; i++) { names.push_back(pf->getPaintNameFromIndex(i)); } addNamesToListBox(names, true); } /** * load the names for area colors in alphabetical order */ void GuiNameSelectionDialog::loadAreaColorsAlphaOrder() { addColorFileToListBox(theMainWindow->getBrainSet()->getAreaColorFile(), true); } /** * load the names for the file type and order. */ void GuiNameSelectionDialog::loadVocabularyAlphaOrder() { std::vector names; const VocabularyFile* vf = theMainWindow->getBrainSet()->getVocabularyFile(); const int num = vf->getNumberOfVocabularyEntries(); for (int i = 0; i < num; i++) { const VocabularyFile::VocabularyEntry* ve = vf->getVocabularyEntry(i); names.push_back(ve->getAbbreviation()); } addNamesToListBox(names, true); } /** * load the name for the file type and order. */ void GuiNameSelectionDialog::loadFociAreasAlphaOrder() { std::vector names; FociProjectionFile* fpf = theMainWindow->getBrainSet()->getFociProjectionFile(); fpf->getAllCellAreas(names); addNamesToListBox(names, true); } /** * load the names for the file type and order. */ void GuiNameSelectionDialog::loadFociCommentAlphaOrder() { std::vector names; FociProjectionFile* fpf = theMainWindow->getBrainSet()->getFociProjectionFile(); fpf->getAllCellComments(names); addNamesToListBox(names, true); } /** * load the name for the file type and order. */ void GuiNameSelectionDialog::loadFociGeographyAlphaOrder() { std::vector names; FociProjectionFile* fpf = theMainWindow->getBrainSet()->getFociProjectionFile(); fpf->getAllCellGeography(names); addNamesToListBox(names, true); } /** * load the name for the file type and order. */ void GuiNameSelectionDialog::loadFociROIAlphaOrder() { std::vector names; FociProjectionFile* fpf = theMainWindow->getBrainSet()->getFociProjectionFile(); fpf->getAllCellRegionsOfInterest(names); addNamesToListBox(names, true); } /** * load the study citations. */ void GuiNameSelectionDialog::loadStudyCitation() { std::vector names; StudyMetaDataFile* smdf = theMainWindow->getBrainSet()->getStudyMetaDataFile(); smdf->getAllCitations(names); addNamesToListBox(names, true); } /** * load the study data format. */ void GuiNameSelectionDialog::loadStudyDataFormat() { std::vector names; StudyMetaDataFile* smdf = theMainWindow->getBrainSet()->getStudyMetaDataFile(); smdf->getAllDataFormats(names); addNamesToListBox(names, true); } /** * load the study data type. */ void GuiNameSelectionDialog::loadStudyDataType() { std::vector names; StudyMetaDataFile* smdf = theMainWindow->getBrainSet()->getStudyMetaDataFile(); smdf->getAllDataTypes(names); addNamesToListBox(names, true); } /** * load the name for the file type and order. */ void GuiNameSelectionDialog::loadStudyKeywords() { std::vector names; StudyMetaDataFile* smdf = theMainWindow->getBrainSet()->getStudyMetaDataFile(); smdf->getAllKeywords(names); addNamesToListBox(names, true); } /** * load the name for the file type and order. */ void GuiNameSelectionDialog::loadStudyMedialSubjectHeadings() { std::vector names; StudyMetaDataFile* smdf = theMainWindow->getBrainSet()->getStudyMetaDataFile(); smdf->getAllMedicalSubjectHeadings(names); addNamesToListBox(names, true); } /** * load study table headers. */ void GuiNameSelectionDialog::loadStudyTableHeaders() { std::vector names; StudyMetaDataFile* smdf = theMainWindow->getBrainSet()->getStudyMetaDataFile(); smdf->getAllTableHeaders(names); addNamesToListBox(names, true); } /** * load study table subheaders. */ void GuiNameSelectionDialog::loadStudyTableSubHeaders() { std::vector names; StudyMetaDataFile* smdf = theMainWindow->getBrainSet()->getStudyMetaDataFile(); smdf->getAllTableSubHeaderShortNames(names); addNamesToListBox(names, true); } /** * load the name for the file type and order. */ void GuiNameSelectionDialog::loadFociClassesAlphaOrder() { std::vector names; FociProjectionFile* fpf = theMainWindow->getBrainSet()->getFociProjectionFile(); const int num = fpf->getNumberOfCellProjections(); for (int j = 0; j < num; j++) { names.push_back(fpf->getCellProjection(j)->getClassName()); } addNamesToListBox(names, true); } /** * load the name of foci in alphabetical order */ void GuiNameSelectionDialog::loadFociNamesAlphaOrder() { std::vector names; FociProjectionFile* fpf = theMainWindow->getBrainSet()->getFociProjectionFile(); const int num = fpf->getNumberOfCellProjections(); for (int j = 0; j < num; j++) { names.push_back(fpf->getCellProjection(j)->getName()); } addNamesToListBox(names, true); } /** * load the names for border names in alphabetical order */ void GuiNameSelectionDialog::loadBorderNamesAlphaOrder() { BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); std::vector names; bmbs->getAllBorderNames(names, false); addNamesToListBox(names, true); } /** * load the names for border colors in alphabetical order */ void GuiNameSelectionDialog::loadBorderColorsAlphaOrder() { addColorFileToListBox(theMainWindow->getBrainSet()->getBorderColorFile(), true); } /** * load the names for border colors in file order */ void GuiNameSelectionDialog::loadBorderColorsFileOrder() { addColorFileToListBox(theMainWindow->getBrainSet()->getBorderColorFile(), false); } /** * load the names for cell colors in alphabetical order */ void GuiNameSelectionDialog::loadCellColorsAlphaOrder() { addColorFileToListBox(theMainWindow->getBrainSet()->getCellColorFile(), true); } /** * load the names for cell colors in file order */ void GuiNameSelectionDialog::loadCellColorsFileOrder() { addColorFileToListBox(theMainWindow->getBrainSet()->getCellColorFile(), false); } /** * load the names for cell colors in alphabetical order */ void GuiNameSelectionDialog::loadContourCellColorsAlphaOrder() { addColorFileToListBox(theMainWindow->getBrainSet()->getContourCellColorFile(), true); } /** * load the names for cell colors in file order */ void GuiNameSelectionDialog::loadContourCellColorsFileOrder() { addColorFileToListBox(theMainWindow->getBrainSet()->getContourCellColorFile(), false); } /** * Destructor */ GuiNameSelectionDialog::~GuiNameSelectionDialog() { } /** * load the species names. */ void GuiNameSelectionDialog::loadSpecies() { std::vector speciesTypes; std::vector speciesNames; Species::getAllSpeciesTypesAndNames(speciesTypes, speciesNames); addNamesToListBox(speciesNames, true); } /** * load the stereotaxic space names. */ void GuiNameSelectionDialog::loadStereotaxicSpaces() { std::vector names; std::vector allSpaces; StereotaxicSpace::getAllStereotaxicSpaces(allSpaces); for (unsigned int i = 0; i < allSpaces.size(); i++) { names.push_back(allSpaces[i].getName()); } addNamesToListBox(names, true); } /** * load the structures. */ void GuiNameSelectionDialog::loadStructures() { std::vector types; std::vector names; Structure::getAllTypesAndNames(types, names, true, true); addNamesToListBox(names, true); } /** * load the statistics. */ void GuiNameSelectionDialog::loadStatistics() { std::vector names; StatisticTestNames::getTestNames(names); std::vector names2; for (unsigned int i = 0; i < names.size(); i++) { names2.push_back(StringUtilities::fromStdString(names[i])); } addNamesToListBox(names2, true); } /** * load volume paint name in alpha order. */ void GuiNameSelectionDialog::loadVolumePaintNamesAlpha() { std::vector names; BrainSet* bs = theMainWindow->getBrainSet(); BrainModelVolume* bmv = bs->getBrainModelVolume(); VolumeFile* paintVolume = bmv->getSelectedVolumePaintFile(); if (paintVolume != NULL) { const int numNames = paintVolume->getNumberOfRegionNames(); for (int i = 0; i < numNames; i++) { names.push_back(paintVolume->getRegionNameFromIndex(i)); } } addNamesToListBox(names, true); } caret-5.6.4~dfsg.1.orig/caret/GuiMultiresolutionMorphingDialog.h0000664000175000017500000001211411572067322024536 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_MULTIRESOLUTION_MORPHING_DIALOG_H__ #define __GUI_MULTIRESOLUTION_MORPHING_DIALOG_H__ #include "WuQDialog.h" #include "BrainModelSurfaceMorphing.h" #include "BrainModelSurfaceMultiresolutionMorphing.h" class GuiBrainModelSelectionComboBox; class QComboBox; class QLineEdit; class QCheckBox; class QSpinBox; class QDoubleSpinBox; class QTextEdit; /// Dialog for multiresolution morphing class GuiMultiresolutionMorphingDialog : public WuQDialog { Q_OBJECT public: /// constructor GuiMultiresolutionMorphingDialog(QWidget* parent, BrainModelSurfaceMultiresolutionMorphing* morphObjectIn, const bool parametersOnlyModeIn); /// Destructor ~GuiMultiresolutionMorphingDialog(); private slots: /// called when OK/Cancel buttons pressed void done(int r); /// called when combo box item is selected void slotNumberOfCyclesSpinBox(); /// called when combo box item is selected void slotEditCycleSpinBox(); /// called when edit cycle combo box item is highlighted before selection made void slotEditCycleSpinBoxOldValue(); /// called when save button pressed void slotSaveButton(); /// called when open button pressed void slotOpenButton(); private: /// read parameters from the dialog and place in morphing object void readParametersFromDialog(); /// load parameters from the morphing object into the dialog void loadParametersIntoDialog(); /// create the iterations section QWidget* createCyclesSection(); /// create the levels section QWidget* createLevelsSection(); /// create the iterations section QWidget* createIterationsSection(); /// create the parameters section QWidget* createParametersSection(); /// create the misc section QWidget* createMiscSection(); /// create file open/save section QWidget* createFileOpenSaveSection(); /// create the surface section QWidget* createSurfaceSection(); /// create the smoothing section QWidget* createSmoothingSection(); /// reference surface combo box GuiBrainModelSelectionComboBox* referenceSurfaceComboBox; /// morphing surface combo box GuiBrainModelSelectionComboBox* morphingSurfaceComboBox; /// number of cycles spin box QComboBox* numberOfCyclesComboBox; /// edit cycle spin box QComboBox* editCycleComboBox; /// iterations spin boxes QSpinBox* iterationsSpinBoxes[MultiResolutionMorphingCycle::MAXIMUM_NUMBER_OF_LEVELS]; /// linear force float spin box QDoubleSpinBox* linearForceDoubleSpinBox; /// angular force float spin box QDoubleSpinBox* angularForceDoubleSpinBox; /// step size float spin box QDoubleSpinBox* stepSizeDoubleSpinBox; /// smoothing strength float spin box QDoubleSpinBox* smoothingStrengthDoubleSpinBox; /// smoothing edge iterations spin box QSpinBox* smoothingIterationsSpinBox; /// smoothing iterations spin box QSpinBox* smoothEdgesEverySpinBox; /// delete temporary files check box QCheckBox* deleteTempFilesCheckBox; /// smooth out overlap check box QCheckBox* smoothOutOverlapCheckBox; /// smooth out crossovers check box QCheckBox* smoothOutCrossoversCheckBox; /// point spherical tiles outward check box QCheckBox* pointSphericalTilesOutwardCheckBox; /// align to central sulcus check box QCheckBox* alignSurfaceCheckBox; /// name of central sulcus for alignment QLineEdit* cesLandmarkNameLineEdit; /// only display and process parameters with no morphing bool parametersOnlyMode; /// the multiresolution morphing object BrainModelSurfaceMultiresolutionMorphing* morphObject; /// the type of morphing BrainModelSurfaceMorphing::MORPHING_SURFACE_TYPE morphingSurfaceType; }; #endif // __GUI_MULTIRESOLUTION_MORPHING_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiMultiresolutionMorphingDialog.cxx0000664000175000017500000007217611572067322025127 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "BorderProjectionFile.h" #include "BrainModelBorderSet.h" #include "BrainModelSurfaceMultiresolutionMorphing.h" #include "BrainModelSurfaceNodeColoring.h" #include "BrainSet.h" #include "FileUtilities.h" #include "GuiBatchCommandDialog.h" #include "GuiBrainModelSelectionComboBox.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "GuiMorphingMeasurementsDialog.h" #include "GuiMultiresolutionMorphingDialog.h" #include "WuQFileDialog.h" #include #include "QtUtilities.h" #include "global_variables.h" /** * constructor */ GuiMultiresolutionMorphingDialog::GuiMultiresolutionMorphingDialog(QWidget* parent, BrainModelSurfaceMultiresolutionMorphing* morphObjectIn, const bool parametersOnlyModeIn) : WuQDialog(parent) { setModal(true); morphObject = morphObjectIn; morphingSurfaceType = morphObjectIn->getMorphingSurfaceType(); parametersOnlyMode = parametersOnlyModeIn; switch (morphingSurfaceType) { case BrainModelSurfaceMorphing::MORPHING_SURFACE_FLAT: setWindowTitle("Multiresolution Morphing - Flat"); break; case BrainModelSurfaceMorphing::MORPHING_SURFACE_SPHERICAL: setWindowTitle("Multiresolution Morphing - Sphere"); break; } // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); if (parametersOnlyMode == false) { // // Create the surfaces section // dialogLayout->addWidget(createSurfaceSection()); } // // Horizontal layout for other layouts // QHBoxLayout* horizLayout = new QHBoxLayout; horizLayout->setSpacing(2); dialogLayout->addLayout(horizLayout); // // Vertical layout for cycles and iterations // QVBoxLayout* cyclesAndIterationsLayout = new QVBoxLayout; horizLayout->addLayout(cyclesAndIterationsLayout); // // Create the cycles section // cyclesAndIterationsLayout->addWidget(createCyclesSection()); // // Create the iterations section // cyclesAndIterationsLayout->addWidget(createIterationsSection()); // // Vertical layout for parameters and smoothing // QVBoxLayout* parametersAndSmoothingLayout = new QVBoxLayout; parametersAndSmoothingLayout->setSpacing(2); horizLayout->addLayout(parametersAndSmoothingLayout); // // Create the morphing parameters section // parametersAndSmoothingLayout->addWidget(createParametersSection()); // // Create the smoothing section // parametersAndSmoothingLayout->addWidget(createSmoothingSection()); // // Create the misc section // dialogLayout->addWidget(createMiscSection()); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); dialogLayout->addLayout(buttonsLayout); // // load the saved parameters // loadParametersIntoDialog(); // // OK button // QPushButton* okButton = new QPushButton("OK"); if (parametersOnlyMode == false) { okButton->setText("Run"); okButton->setToolTip("Run multi-resolution morphing."); } else { okButton->setToolTip("Use parameters for morphing."); } okButton->setAutoDefault(false); buttonsLayout->addWidget(okButton); QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); QPushButton* openButton = NULL; QPushButton* saveButton = NULL; if (parametersOnlyMode == false) { openButton = new QPushButton("Open..."); openButton->setAutoDefault(false); QObject::connect(openButton, SIGNAL(clicked()), this, SLOT(slotOpenButton())); openButton->setAutoDefault(false); saveButton = new QPushButton("Save..."); saveButton->setAutoDefault(false); QObject::connect(saveButton, SIGNAL(clicked()), this, SLOT(slotSaveButton())); buttonsLayout->addWidget(openButton); buttonsLayout->addWidget(saveButton); } // // Cancel button // QPushButton* cancelButton = new QPushButton("Cancel"); cancelButton->setToolTip("Close dialog and\n" "do not morph."); cancelButton->setAutoDefault(false); buttonsLayout->addWidget(cancelButton); QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); QtUtilities::makeButtonsSameSize(okButton, openButton, saveButton, cancelButton); loadParametersIntoDialog(); } /** * Destructor */ GuiMultiresolutionMorphingDialog::~GuiMultiresolutionMorphingDialog() { } /** * Create the cycles section */ QWidget* GuiMultiresolutionMorphingDialog::createCyclesSection() { QLabel* totalLabel = new QLabel("Total "); numberOfCyclesComboBox = new QComboBox; for (int i = 0; i < 10; i++) { numberOfCyclesComboBox->addItem(QString::number(i + 1)); } QObject::connect(numberOfCyclesComboBox, SIGNAL(activated(int)), this, SLOT(slotNumberOfCyclesSpinBox())); QLabel* editLabel = new QLabel("Edit "); editCycleComboBox = new QComboBox; for (int i = 0; i < 10; i++) { editCycleComboBox->addItem(QString::number(i + 1)); } QObject::connect(editCycleComboBox, SIGNAL(highlighted(int)), this, SLOT(slotEditCycleSpinBoxOldValue())); QObject::connect(editCycleComboBox, SIGNAL(activated(int)), this, SLOT(slotEditCycleSpinBox())); QGroupBox* cycleGroupBox = new QGroupBox("Cycles"); QHBoxLayout* cycleLayout = new QHBoxLayout(cycleGroupBox); cycleLayout->addWidget(totalLabel); cycleLayout->addWidget(numberOfCyclesComboBox); cycleLayout->addWidget(editLabel); cycleLayout->addWidget(editCycleComboBox); return cycleGroupBox; } /** * called when number of cycles combo box item is selected. */ void GuiMultiresolutionMorphingDialog::slotNumberOfCyclesSpinBox() { readParametersFromDialog(); if (numberOfCyclesComboBox->currentIndex() > editCycleComboBox->currentIndex()) { editCycleComboBox->setCurrentIndex(numberOfCyclesComboBox->currentIndex()); } loadParametersIntoDialog(); } /** * called when edit cycle combo box item is selected. */ void GuiMultiresolutionMorphingDialog::slotEditCycleSpinBox() { loadParametersIntoDialog(); } /** * called when edit cycle combo box item is highlighted before selection made. */ void GuiMultiresolutionMorphingDialog::slotEditCycleSpinBoxOldValue() { readParametersFromDialog(); } /** * Create the surface section */ QWidget* GuiMultiresolutionMorphingDialog::createSurfaceSection() { // // reference surface // QLabel* refLabel = new QLabel("Reference"); referenceSurfaceComboBox = new GuiBrainModelSelectionComboBox(false, true, false, "", 0, "referenceSurfaceComboBox"); referenceSurfaceComboBox->setSelectedBrainModel(theMainWindow->getBrainSet()->getActiveFiducialSurface()); // // morphing surface // QLabel* morphLabel = new QLabel("Morphing"); morphingSurfaceComboBox = new GuiBrainModelSelectionComboBox( false, true, false, "", 0, "morphingSurfaceComboBox"); const BrainModelSurface* mainBMS = theMainWindow->getBrainModelSurface(); morphingSurfaceComboBox->setSelectedBrainModel(mainBMS); switch (morphingSurfaceType) { case BrainModelSurfaceMorphing::MORPHING_SURFACE_FLAT: if (mainBMS->getIsFlatSurface() == false) { morphingSurfaceComboBox->setSelectedBrainModelToFirstSurfaceOfType(BrainModelSurface::SURFACE_TYPE_FLAT); } break; case BrainModelSurfaceMorphing::MORPHING_SURFACE_SPHERICAL: if (mainBMS->getSurfaceType() != BrainModelSurface::SURFACE_TYPE_SPHERICAL) { morphingSurfaceComboBox->setSelectedBrainModelToFirstSurfaceOfType(BrainModelSurface::SURFACE_TYPE_SPHERICAL); } break; } // // Group box and layout // QGroupBox* surfaceGroupBox = new QGroupBox("Surfaces"); QGridLayout* surfaceLayout = new QGridLayout(surfaceGroupBox); surfaceLayout->addWidget(refLabel, 0, 0); surfaceLayout->addWidget(referenceSurfaceComboBox, 0, 1); surfaceLayout->addWidget(morphLabel, 1, 0); surfaceLayout->addWidget(morphingSurfaceComboBox, 1, 1); return surfaceGroupBox; } /** * Create the iterations section */ QWidget* GuiMultiresolutionMorphingDialog::createIterationsSection() { QGroupBox* itersGroupBox = new QGroupBox("Iterations"); QGridLayout* itersLayout = new QGridLayout(itersGroupBox); for (int i = 0; i < MultiResolutionMorphingCycle::MAXIMUM_NUMBER_OF_LEVELS; i++) { QString labelValue(""); if (i == 0) { labelValue = "Fine"; } else if (i == (MultiResolutionMorphingCycle::MAXIMUM_NUMBER_OF_LEVELS - 1)) { labelValue = "Coarse"; } else if (i == 1) { labelValue = "Level 2"; } else if (i == 2) { labelValue = "Level 3"; } else if (i == 3) { labelValue = "Level 4"; } else if (i == 4) { labelValue = "Level 5"; } else if (i == 5) { labelValue = "Level 6"; } itersLayout->addWidget(new QLabel(labelValue), i, 0); iterationsSpinBoxes[i] = new QSpinBox; iterationsSpinBoxes[i]->setMinimum(0); iterationsSpinBoxes[i]->setMaximum(10000); iterationsSpinBoxes[i]->setSingleStep(1); itersLayout->addWidget(iterationsSpinBoxes[i], i, 1); } return itersGroupBox; } /** * Create the parameters section */ QWidget* GuiMultiresolutionMorphingDialog::createParametersSection() { // // Linear Force Float spin box // QLabel* linearLabel = new QLabel("Linear Force"); linearForceDoubleSpinBox = new QDoubleSpinBox; linearForceDoubleSpinBox->setMinimum(0.0); linearForceDoubleSpinBox->setMaximum(1.0); linearForceDoubleSpinBox->setSingleStep(0.1); linearForceDoubleSpinBox->setDecimals(1); // // Angular Float spin box // QLabel* angularLabel = new QLabel("Angular Force"); angularForceDoubleSpinBox = new QDoubleSpinBox; angularForceDoubleSpinBox->setMinimum(0.0); angularForceDoubleSpinBox->setMaximum(1.0); angularForceDoubleSpinBox->setSingleStep(0.10); angularForceDoubleSpinBox->setDecimals(1); // // Step Size Float spin box // QLabel* stepLabel = new QLabel("Step Size"); stepSizeDoubleSpinBox = new QDoubleSpinBox; stepSizeDoubleSpinBox->setMinimum(0.0); stepSizeDoubleSpinBox->setMaximum(1.0); stepSizeDoubleSpinBox->setSingleStep(0.10); stepSizeDoubleSpinBox->setDecimals(1); QGroupBox* paramsGroupBox = new QGroupBox("Morphing Forces"); QGridLayout* paramsLayout = new QGridLayout(paramsGroupBox); paramsLayout->addWidget(linearLabel, 0, 0); paramsLayout->addWidget(linearForceDoubleSpinBox, 0, 1); paramsLayout->addWidget(angularLabel, 1, 0); paramsLayout->addWidget(angularForceDoubleSpinBox, 1, 1); paramsLayout->addWidget(stepLabel, 2, 0); paramsLayout->addWidget(stepSizeDoubleSpinBox, 2, 1); return paramsGroupBox; } /** * Create the smoothing section */ QWidget* GuiMultiresolutionMorphingDialog::createSmoothingSection() { // // Smoothing Strength Float spin box // QLabel* strengthLabel = new QLabel("Strength"); smoothingStrengthDoubleSpinBox = new QDoubleSpinBox; smoothingStrengthDoubleSpinBox->setMinimum(0.0); smoothingStrengthDoubleSpinBox->setMaximum(1.0); smoothingStrengthDoubleSpinBox->setSingleStep(0.10); smoothingStrengthDoubleSpinBox->setDecimals(1); // // Smoothing iterations spin box // QLabel* itersLabel = new QLabel("Iterations"); smoothingIterationsSpinBox = new QSpinBox; smoothingIterationsSpinBox->setMinimum(0); smoothingIterationsSpinBox->setMaximum(10000); smoothingIterationsSpinBox->setSingleStep(10); // // Smoothing Edge iterations spin box // QLabel* smoothLabel = new QLabel("Smooth Edges Every"); smoothEdgesEverySpinBox = new QSpinBox; smoothEdgesEverySpinBox->setMinimum(0); smoothEdgesEverySpinBox->setMaximum(100); smoothEdgesEverySpinBox->setSingleStep(10); QGroupBox* smoothingGroupBox = new QGroupBox("Smoothing"); QGridLayout* smoothingLayout = new QGridLayout(smoothingGroupBox); smoothingLayout->addWidget(strengthLabel, 0, 0); smoothingLayout->addWidget(smoothingStrengthDoubleSpinBox, 0, 1); smoothingLayout->addWidget(itersLabel, 1, 0); smoothingLayout->addWidget(smoothingIterationsSpinBox, 1, 1); smoothingLayout->addWidget(smoothLabel, 2, 0); smoothingLayout->addWidget(smoothEdgesEverySpinBox, 2, 1); return smoothingGroupBox; } /** * Create the misc section */ QWidget* GuiMultiresolutionMorphingDialog::createMiscSection() { // // Central Sulcus Landmark // alignSurfaceCheckBox = new QCheckBox("Align to CeS Landmark"); alignSurfaceCheckBox->setChecked(true); cesLandmarkNameLineEdit = new QLineEdit; cesLandmarkNameLineEdit->setText("LANDMARK.CentralSulcus"); cesLandmarkNameLineEdit->setToolTip("If there is a border with this name,\n" "it will be used to automatically \n" "align the surface at the conclusion\n" "of multi-resolution morphing."); QHBoxLayout* cesLayout = new QHBoxLayout; cesLayout->addWidget(alignSurfaceCheckBox); cesLayout->addWidget(cesLandmarkNameLineEdit); cesLayout->setStretchFactor(alignSurfaceCheckBox, 0); cesLayout->setStretchFactor(cesLandmarkNameLineEdit, 100); // // delete temporary files check box // deleteTempFilesCheckBox = new QCheckBox("Delete Temporary Files"); // // Smooth out crossovers check box // smoothOutCrossoversCheckBox = new QCheckBox("Smooth Out Crossovers Each Cycle"); // // Flat surface smooth out overlap check box // smoothOutOverlapCheckBox = NULL; if (morphingSurfaceType == BrainModelSurfaceMorphing::MORPHING_SURFACE_FLAT) { smoothOutOverlapCheckBox = new QCheckBox("Smooth Out Surface Overlap"); } // // point spherical tiles outward check box // pointSphericalTilesOutwardCheckBox = NULL; if (morphingSurfaceType == BrainModelSurfaceMorphing::MORPHING_SURFACE_SPHERICAL) { pointSphericalTilesOutwardCheckBox = new QCheckBox("Point Spherical Tiles Outward"); } QGroupBox* miscGroupBox = new QGroupBox("Misc"); QVBoxLayout* miscLayout = new QVBoxLayout(miscGroupBox); miscLayout->addWidget(deleteTempFilesCheckBox); miscLayout->addWidget(smoothOutCrossoversCheckBox); if (smoothOutOverlapCheckBox != NULL) { miscLayout->addWidget(smoothOutOverlapCheckBox); } if (pointSphericalTilesOutwardCheckBox != NULL) { miscLayout->addWidget(pointSphericalTilesOutwardCheckBox); } miscLayout->addLayout(cesLayout); return miscGroupBox; } /** * Called when save button pressed. */ void GuiMultiresolutionMorphingDialog::slotSaveButton() { this->readParametersFromDialog(); // // Create a file dialog to select the file. // WuQFileDialog saveParamFileDialog(this); saveParamFileDialog.setModal(true); saveParamFileDialog.setWindowTitle("Choose Multi-Resolution Morphing Parameters File"); saveParamFileDialog.setFileMode(WuQFileDialog::AnyFile); saveParamFileDialog.setAcceptMode(WuQFileDialog::AcceptSave); saveParamFileDialog.setHistory(theMainWindow->getBrainSet()->getPreferencesFile()->getRecentDataFileDirectories()); saveParamFileDialog.setDirectory(QDir::currentPath()); QString filterString("DeformationMapFile (*"); filterString.append(SpecFile::getMultiResMorphFileExtension()); filterString.append(")"); saveParamFileDialog.setFilters(QStringList(filterString)); if (saveParamFileDialog.exec() == QDialog::Accepted) { try { if (saveParamFileDialog.selectedFiles().count() > 0) { this->morphObject->getMultiResMorphParametersFile()->writeFile( saveParamFileDialog.selectedFiles().at(0)); } } catch (FileException& e) { QMessageBox::critical(this, "Save Error", e.whatQString()); return; } } } /** * Called when open button pressed. */ void GuiMultiresolutionMorphingDialog::slotOpenButton() { // // Create a file dialog to select the file. // WuQFileDialog openParamFileDialog(this); openParamFileDialog.setModal(true); openParamFileDialog.setWindowTitle("Choose Multi-Resolution Morphing Parameters File"); openParamFileDialog.setFileMode(WuQFileDialog::ExistingFile); openParamFileDialog.setAcceptMode(WuQFileDialog::AcceptOpen); openParamFileDialog.setHistory(theMainWindow->getBrainSet()->getPreferencesFile()->getRecentDataFileDirectories()); openParamFileDialog.setDirectory(QDir::currentPath()); QString filterString("DeformationMapFile (*"); filterString.append(SpecFile::getMultiResMorphFileExtension()); filterString.append(")"); openParamFileDialog.setFilters(QStringList(filterString)); if (openParamFileDialog.exec() == QDialog::Accepted) { try { if (openParamFileDialog.selectedFiles().count() > 0) { this->morphObject->getMultiResMorphParametersFile()->readFile( openParamFileDialog.selectedFiles().at(0)); this->loadParametersIntoDialog(); } } catch (FileException& e) { QMessageBox::critical(this, "Open Error", e.whatQString()); return; } } } /** * called when OK/Cancel buttons pressed */ void GuiMultiresolutionMorphingDialog::done(int r) { if (r != QDialog::Accepted) { QDialog::done(r); return; } // // read the parameters // readParametersFromDialog(); if (parametersOnlyMode) { QDialog::done(r); return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); // // get the morphing surfaces // BrainModelSurface* referenceSurface = referenceSurfaceComboBox->getSelectedBrainModelSurface(); BrainModelSurface* morphingSurface = morphingSurfaceComboBox->getSelectedBrainModelSurface(); // // Check for flat/spherical surface // if (morphingSurfaceType == BrainModelSurfaceMorphing::MORPHING_SURFACE_FLAT) { if ((morphingSurface->getSurfaceType() != BrainModelSurface::SURFACE_TYPE_FLAT) & (morphingSurface->getSurfaceType() != BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR)) { QApplication::restoreOverrideCursor(); if (QMessageBox::warning(this, "Warning", "Surface for morphing is not a flat surface.", (QMessageBox::Ok | QMessageBox::Cancel), QMessageBox::Cancel) == QMessageBox::Cancel) { return; } } } else { if (morphingSurface->getSurfaceType() != BrainModelSurface::SURFACE_TYPE_SPHERICAL) { QApplication::restoreOverrideCursor(); if (QMessageBox::warning(this, "Warning", "Surface for morphing is not a spherical surface.", (QMessageBox::Ok | QMessageBox::Cancel), QMessageBox::Cancel) == QMessageBox::Cancel) { return; } } } // // Get the border projection file and look for the central sulcus border // BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); BorderProjectionFile bpf; BorderProjection* centralSulcusBorderProjection = NULL; if (alignSurfaceCheckBox->isChecked()) { const QString centralSulcusBorderProjectionName = cesLandmarkNameLineEdit->text().trimmed(); bmbs->copyBordersToBorderProjectionFile(bpf); centralSulcusBorderProjection = bpf.getFirstBorderProjectionByName(centralSulcusBorderProjectionName); } // // Create the morphing object // BrainModelSurfaceMultiresolutionMorphing bsmm(theMainWindow->getBrainSet(), referenceSurface, morphingSurface, morphingSurfaceType, centralSulcusBorderProjection); // // Copy the saved parameters to the morphing object // bsmm.copyParameters(*morphObject); // // Allow the dialog to close // QDialog::done(r); // // Execute the morphing // QTime timer; timer.start(); try { bsmm.execute(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(theMainWindow, "Error", e.whatQString()); return; } const float elapsedTime = timer.elapsed() * 0.001; // // Set the overlay to crossovers (if there are any) // bool haveCrossovers = false; const int numNodes = theMainWindow->getBrainSet()->getNumberOfNodes(); for (int i = 0; i < numNodes; i++) { if (theMainWindow->getBrainSet()->getNodeAttributes(i)->getCrossover()) { haveCrossovers = true; break; } } if (haveCrossovers) { BrainModelSurfaceNodeColoring* bsnc = theMainWindow->getBrainSet()->getNodeColoring(); theMainWindow->getBrainSet()->getPrimarySurfaceOverlay()->setOverlay( -1, BrainModelSurfaceOverlay::OVERLAY_SHOW_CROSSOVERS); bsnc->assignColors(); } // // Display the morphing information // std::vector mm; bsmm.getMorphingMeasurements(mm); GuiMorphingMeasurementsDialog* mmd = new GuiMorphingMeasurementsDialog(mm, elapsedTime, morphingSurfaceType, true, theMainWindow); mmd->show(); // // Clear modification status of borders // bmbs->setAllBordersModifiedStatus(false); bmbs->setProjectionsModified(false); // // Notify about modified files and redraw all displays // GuiFilesModified fm; fm.setCoordinateModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); QApplication::beep(); theMainWindow->speakText("Multi-resolution morphing has completed", false); } /** * load saved parameters into dialog. */ void GuiMultiresolutionMorphingDialog::loadParametersIntoDialog() { MultiResMorphFile* morphFile = morphObject->getMultiResMorphParametersFile(); // // load number of cycles // numberOfCyclesComboBox->setCurrentIndex(morphFile->getNumberOfCycles() - 1); // // Get current cycle being edited // const int editCycleIndex = editCycleComboBox->currentIndex(); MultiResolutionMorphingCycle* editCycle = morphFile->getCycle(editCycleIndex); // // load iterations // int iters[MultiResolutionMorphingCycle::MAXIMUM_NUMBER_OF_LEVELS]; editCycle->getIterationsAll(iters); for (int i = 0; i < MultiResolutionMorphingCycle::MAXIMUM_NUMBER_OF_LEVELS; i++) { iterationsSpinBoxes[i]->setValue(iters[i]); } // // load morphing forces // float linearForce = editCycle->getLinearForce(); float angularForce = editCycle->getAngularForce(); float stepSize = editCycle->getStepSize(); linearForceDoubleSpinBox->setValue(linearForce); angularForceDoubleSpinBox->setValue(angularForce); stepSizeDoubleSpinBox->setValue(stepSize); // // load smoothing parameters // float strength = editCycle->getSmoothingStrength(); int smoothIterations = editCycle->getSmoothingIterations(); int smoothEdgeIterations = editCycle->getSmoothingIterationEdges(); smoothingStrengthDoubleSpinBox->setValue(strength); smoothingIterationsSpinBox->setValue(smoothIterations); smoothEdgesEverySpinBox->setValue(smoothEdgeIterations); // // load delete intermediate files // deleteTempFilesCheckBox->setChecked(morphFile->isDeleteTemporaryFiles()); // // Load smooth out crossovers check box // smoothOutCrossoversCheckBox->setChecked(morphFile->isSmoothOutCrossovers()); // // Load smooth out flat surface overlap chekc box // if (smoothOutOverlapCheckBox != NULL) { smoothOutOverlapCheckBox->setChecked(morphFile->isSmoothOutFlatSurfaceOverlap()); } // // Load point spherical tiles out check box // if (pointSphericalTilesOutwardCheckBox != NULL) { pointSphericalTilesOutwardCheckBox->setChecked(morphFile->isPointSphericalTrianglesOutward()); } this->alignSurfaceCheckBox->setChecked(morphFile->isAlignToCentralSulcalsLandmark()); this->cesLandmarkNameLineEdit->setText(morphFile->getCentralSulcusLandmarkName()); } /** * Save the dialog parameters. */ void GuiMultiresolutionMorphingDialog::readParametersFromDialog() { int indx = 0; if (morphingSurfaceType == BrainModelSurfaceMorphing::MORPHING_SURFACE_SPHERICAL) { indx = 1; } MultiResMorphFile* morphFile = morphObject->getMultiResMorphParametersFile(); // // save number of cycles // morphFile->setNumberOfCycles(numberOfCyclesComboBox->currentIndex() + 1); // // Get the cycle being edited // // // Get current cycle being edited // const int editCycleIndex = editCycleComboBox->currentIndex(); MultiResolutionMorphingCycle* editCycle = morphFile->getCycle(editCycleIndex); // // save iterations // int iters[MultiResolutionMorphingCycle::MAXIMUM_NUMBER_OF_LEVELS]; for (int i = 0; i < MultiResolutionMorphingCycle::MAXIMUM_NUMBER_OF_LEVELS; i++) { iters[i] = iterationsSpinBoxes[i]->value(); } editCycle->setIterationsAll(iters); // // save morphing forces // editCycle->setLinearForce(linearForceDoubleSpinBox->value()); editCycle->setAngularForce(angularForceDoubleSpinBox->value()); editCycle->setStepSize(stepSizeDoubleSpinBox->value()); // // save smoothing parameters // editCycle->setSmoothingStrength(smoothingStrengthDoubleSpinBox->value()); editCycle->setSmoothingIterations(smoothingIterationsSpinBox->value()); editCycle->setSmoothingIterationsEdges(smoothEdgesEverySpinBox->value()); // // save delete intermediate files // morphFile->setDeleteTemporaryFiles(deleteTempFilesCheckBox->isChecked()); // // Save smooth out crossovers // morphFile->setSmoothOutCrossovers(smoothOutCrossoversCheckBox->isChecked()); // // save smooth out overlap // if (smoothOutOverlapCheckBox != NULL) { morphFile->setSmoothOutFlatSurfaceOverlap(smoothOutOverlapCheckBox->isChecked()); } // // save point spherical tiles out // if (pointSphericalTilesOutwardCheckBox != NULL) { morphFile->setPointSphericalTrianglesOutward(pointSphericalTilesOutwardCheckBox->isChecked()); } morphFile->setAlignToCentralSulcusLandmark(this->alignSurfaceCheckBox->isChecked()); morphFile->setCentralSulcusLandmarkName(this->cesLandmarkNameLineEdit->text()); } caret-5.6.4~dfsg.1.orig/caret/GuiMultipleInputDialog.h0000664000175000017500000000444311572067322022435 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_MULTIPLE_INPUT_DIALOG_H__ #define __GUI_MULTIPLE_INPUT_DIALOG_H__ #include #include #include "WuQDialog.h" class QLineEdit; /// This dialog contains multiple rows of label and line edit boxes class GuiMultipleInputDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiMultipleInputDialog(QWidget* parent, const QString& caption, const std::vector& labels); /// Destructor ~GuiMultipleInputDialog(); /// Set a line edit box with an integer void setLineEdit(const int index, const int value); /// Set a line edit box with a float void setLineEdit(const int index, const float value, const int precision = 3); /// Set a line edit box with an string void setLineEdit(const int index, const QString& value); /// get the integer value in a line edit box void getLineEdit(const int index, int& value) const; /// get the float value in a line edit box void getLineEdit(const int index, float& value) const; /// get the string value in a line edit box void getLineEdit(const int index, QString& value) const; private: /// the line edits for all of the rows std::vector lineEdits; }; #endif // __GUI_MULTIPLE_INPUT_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiMultipleInputDialog.cxx0000664000175000017500000000717511572067322023015 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include "WuQDialog.h" #include "QtUtilities.h" #include "GuiMultipleInputDialog.h" /** * Constructor */ GuiMultipleInputDialog::GuiMultipleInputDialog(QWidget* parent, const QString& caption, const std::vector& labels) : WuQDialog(parent) { setModal(true); setWindowTitle(caption); const int numRows = static_cast(labels.size()); QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(5); QGridLayout* gridLayout = new QGridLayout; dialogLayout->addLayout(gridLayout); // // Create the labels an line edits // for (int i = 0; i < numRows; i++) { gridLayout->addWidget(new QLabel(labels[i]), i, 0, Qt::AlignLeft); QLineEdit* le = new QLineEdit; gridLayout->addWidget(le, i, 1, Qt::AlignLeft); lineEdits.push_back(le); } // // Buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(5); dialogLayout->addLayout(buttonsLayout); QPushButton* ok = new QPushButton("OK"); QObject::connect(ok, SIGNAL(clicked()), this, SLOT(accept())); buttonsLayout->addWidget(ok); QPushButton* close = new QPushButton("Cancel"); QObject::connect(close, SIGNAL(clicked()), this, SLOT(reject())); buttonsLayout->addWidget(close); QtUtilities::makeButtonsSameSize(ok, close); } /** * Destructor */ GuiMultipleInputDialog::~GuiMultipleInputDialog() { } /** * Set a line edit to an integer value. */ void GuiMultipleInputDialog::setLineEdit(const int index, const int value) { lineEdits[index]->setText(QString("%1").arg(value)); } /** * Set a line edit to a float value. */ void GuiMultipleInputDialog::setLineEdit(const int index, const float value, const int precision) { lineEdits[index]->setText(QString("%1").arg(value, 0, 'f', precision)); } /** * Set a line edit to a string value. */ void GuiMultipleInputDialog::setLineEdit(const int index, const QString& value) { lineEdits[index]->setText(value); } /** * Get the integer value from a line edit. */ void GuiMultipleInputDialog::getLineEdit(const int index, int& value) const { value = lineEdits[index]->text().toInt(); } /** * Get a float value from a line edit. */ void GuiMultipleInputDialog::getLineEdit(const int index, float& value) const { value = lineEdits[index]->text().toFloat(); } /** * Get a string value from a line edit. */ void GuiMultipleInputDialog::getLineEdit(const int index, QString& value) const { value = lineEdits[index]->text(); } caret-5.6.4~dfsg.1.orig/caret/GuiMouseModePopupMenu.h0000664000175000017500000001115011572067322022241 0ustar michaelmichael #ifndef __GUI_MOUSE_MODE_POPUP_MENU_H__ #define __GUI_MOUSE_MODE_POPUP_MENU_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include class GuiBrainModelOpenGL; /// class for a popup menu that sets the mouse mode class GuiMouseModePopupMenu : public QMenu { Q_OBJECT public: // constructor GuiMouseModePopupMenu(GuiBrainModelOpenGL* brainModelOpenGLIn, const bool showViewModeIn, QWidget* parent = 0); // destructor ~GuiMouseModePopupMenu(); protected slots: // called when menu is about to be displayed void slotAboutToShow(); // called when menu item selected void slotMenuItemSelected(QAction*); protected: // brain model OpenGL for which this is used GuiBrainModelOpenGL* brainModelOpenGL; // show view mode bool showViewMode; // name of action static QString getActionBorderDrawName() { return "Border Draw"; } // name of action static QString getActionBorderDrawUpdateName() { return "Border Draw Update"; } // name of action static QString getActionBorderDeleteName() { return "Border Delete"; } // name of action static QString getActionBorderRenameName() { return "Border Rename"; } // name of action static QString getActionBorderReversePointOrderName() { return "Border Reverse Point Order"; } // name of action static QString getActionBorderPointDeleteName() { return "Border Point Delete"; } // name of action static QString getActionBorderPointMoveName() { return "Border Point Move"; } // name of action static QString getActionCellAddName() { return "Cell Add"; } // name of action static QString getActionCellDeleteName() { return "Cell Delete"; } // name of action static QString getActionContourDrawName() { return "Contour Draw"; } // name of action static QString getActionContourDeleteName() { return "Contour Delete"; } // name of action static QString getActionContourMergeName() { return "Contour Merge"; } // name of action static QString getActionContourReversePointOrderName() { return "Contour Reverse Point Order"; } // name of action static QString getActionContourPointDeleteName() { return "Contour Point Delete"; } // name of action static QString getActionContourPointMoveName() { return "Contour Point Move"; } // name of action static QString getActionContourCellAddName() { return "Contour Cell Add"; } // name of action static QString getActionContourCellDeleteName() { return "Contour Cell Delete"; } // name of action static QString getActionContourCellMoveName() { return "Contour Cell Move"; } // name of action static QString getActionCutDrawName() { return "Cut Draw"; } // name of action static QString getActionCutDeleteName() { return "Cut Delete"; } // name of action static QString getActionFociDeleteName() { return "Foci Delete"; } // name of action static QString getActionVolumePaintEditName() { return "Volume Paint Edit"; } // name of action static QString getActionVolumeSegmentationEditName() { return "Volume Segmentation Edit"; } // name of action static QString getActionViewName() { return "View"; } // name of action static QString getActionTransformationAxesName() { return "Transformation Axes"; } // name of action //static QString getActionName() { return ""; } }; #endif // __GUI_MOUSE_MODE_POPUP_MENU_H__ caret-5.6.4~dfsg.1.orig/caret/GuiMouseModePopupMenu.cxx0000664000175000017500000002754111572067322022627 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BorderFile.h" #include "BrainModelBorderSet.h" #include "BrainModelContours.h" #include "BrainModelVolumeVoxelColoring.h" #include "BrainSet.h" #include "CellProjectionFile.h" #include "ContourCellFile.h" #include "ContourFile.h" #include "CutsFile.h" #include "DisplaySettingsBorders.h" #include "DisplaySettingsCells.h" #include "DisplaySettingsContours.h" #include "DisplaySettingsCuts.h" #include "DisplaySettingsFoci.h" #include "FociProjectionFile.h" #include "GuiBrainModelOpenGL.h" #include "GuiMainWindow.h" #include "GuiMainWindowLayersActions.h" #include "GuiMainWindowVolumeActions.h" #include "GuiMouseModePopupMenu.h" #include "global_variables.h" /** * Constructor */ GuiMouseModePopupMenu::GuiMouseModePopupMenu(GuiBrainModelOpenGL* brainModelOpenGLIn, const bool showViewModeIn, QWidget* parent) : QMenu(parent) { brainModelOpenGL = brainModelOpenGLIn; showViewMode = showViewModeIn; QObject::connect(this, SIGNAL(aboutToShow()), this, SLOT(slotAboutToShow())); QObject::connect(this, SIGNAL(triggered(QAction*)), this, SLOT(slotMenuItemSelected(QAction*))); } /** * destructor. */ GuiMouseModePopupMenu::~GuiMouseModePopupMenu() { } /** * called when menu item selected. */ void GuiMouseModePopupMenu::slotMenuItemSelected(QAction* action) { if (action != NULL) { const QString name = action->text(); //std::cout << "Item Selected: " << name.toAscii().constData() // << std::endl; // // main window actions // GuiMainWindowLayersActions* layersActions = theMainWindow->getLayersActions(); GuiMainWindowVolumeActions* volumeActions = theMainWindow->getVolumeActions(); if (name == getActionBorderDrawName()) { brainModelOpenGL->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_BORDER_DRAW); //brainModelOpenGL->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_BORDER_DRAW_NEW); QAction* action = layersActions->getBordersDrawAction(); action->trigger(); } else if (name == getActionBorderDrawUpdateName()) { brainModelOpenGL->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_BORDER_UPDATE); //brainModelOpenGL->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_BORDER_UPDATE_NEW); QAction* action = layersActions->getBorderDrawUpdateAction(); action->trigger(); } else if (name == getActionBorderDeleteName()) { brainModelOpenGL->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_BORDER_DELETE); } else if (name == getActionBorderRenameName()) { brainModelOpenGL->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_BORDER_RENAME); } else if (name == getActionBorderReversePointOrderName()) { brainModelOpenGL->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_BORDER_REVERSE); } else if (name == getActionBorderPointDeleteName()) { brainModelOpenGL->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_BORDER_DELETE_POINT); } else if (name == getActionBorderPointMoveName()) { brainModelOpenGL->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_BORDER_MOVE_POINT); } else if (name == getActionCellAddName()) { brainModelOpenGL->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_CELL_ADD); QAction* action = layersActions->getCellsAddAction(); action->trigger(); } else if (name == getActionCellDeleteName()) { brainModelOpenGL->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_CELL_DELETE); } else if (name == getActionContourDrawName()) { brainModelOpenGL->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_DRAW); QAction* action = layersActions->getContourDrawAction(); action->trigger(); } else if (name == getActionContourDeleteName()) { brainModelOpenGL->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_DELETE); } else if (name == getActionContourMergeName()) { brainModelOpenGL->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_MERGE); } else if (name == getActionContourReversePointOrderName()) { brainModelOpenGL->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_REVERSE); } else if (name == getActionContourPointDeleteName()) { brainModelOpenGL->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_POINT_DELETE); } else if (name == getActionContourPointMoveName()) { brainModelOpenGL->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_POINT_MOVE); } else if (name == getActionContourCellAddName()) { brainModelOpenGL->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_CELL_ADD); QAction* action = layersActions->getCellsAddAction(); action->trigger(); } else if (name == getActionContourCellDeleteName()) { brainModelOpenGL->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_CELL_DELETE); } else if (name == getActionContourCellMoveName()) { brainModelOpenGL->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_CELL_MOVE); } else if (name == getActionCutDrawName()) { brainModelOpenGL->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_CUT_DRAW); DisplaySettingsCuts* dsc = theMainWindow->getBrainSet()->getDisplaySettingsCuts(); dsc->setDisplayCuts(! dsc->getDisplayCuts()); GuiBrainModelOpenGL::updateAllGL(NULL); } else if (name == getActionCutDeleteName()) { brainModelOpenGL->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_CUT_DELETE); } else if (name == getActionFociDeleteName()) { brainModelOpenGL->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_FOCI_DELETE); } else if (name == getActionTransformationAxesName()) { brainModelOpenGL->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_TRANSFORMATION_MATRIX_AXES); } else if (name == getActionVolumePaintEditName()) { brainModelOpenGL->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_VOLUME_PAINT_EDIT); QAction* action = volumeActions->getEditPaintVolumeAction(); action->trigger(); } else if (name == getActionVolumeSegmentationEditName()) { brainModelOpenGL->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_VOLUME_SEGMENTATION_EDIT); QAction* action = volumeActions->getEditSegmentationAction(); action->trigger(); } else if (name == getActionViewName()) { brainModelOpenGL->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_VIEW); } } } /** * called when menu is about to be displayed. */ void GuiMouseModePopupMenu::slotAboutToShow() { // // Clear menu // clear(); // // Types of data loaded // BrainSet* bs = theMainWindow->getBrainSet(); // // Create menu // BrainModel* bm = brainModelOpenGL->getDisplayedBrainModel(); if (bm != NULL) { switch (bm->getModelType()) { case BrainModel::BRAIN_MODEL_SURFACE: if (showViewMode) { addAction(getActionViewName()); } addAction(getActionBorderDrawName()); if ((bs->getBorderSet()->getNumberOfBorders() > 0) && (bs->getDisplaySettingsBorders()->getDisplayBorders())) { addAction(getActionBorderDrawUpdateName()); addAction(getActionBorderDeleteName()); addAction(getActionBorderRenameName()); addAction(getActionBorderReversePointOrderName()); addAction(getActionBorderPointDeleteName()); addAction(getActionBorderPointMoveName()); } addAction(getActionCellAddName()); if ((bs->getCellProjectionFile()->getNumberOfCellProjections() > 0) && (bs->getDisplaySettingsCells()->getDisplayCells())) { addAction(getActionCellDeleteName()); } addAction(getActionCutDrawName()); if ((bs->getCutsFile()->getNumberOfBorders() > 0) && (bs->getDisplaySettingsCuts()->getDisplayCuts())) { addAction(getActionCutDeleteName()); } if ((bs->getFociProjectionFile()->getNumberOfCellProjections() > 0) && (bs->getDisplaySettingsFoci()->getDisplayCells())) { addAction(getActionFociDeleteName()); } addAction(getActionTransformationAxesName()); break; case BrainModel::BRAIN_MODEL_SURFACE_AND_VOLUME: if (showViewMode) { addAction(getActionViewName()); } break; case BrainModel::BRAIN_MODEL_CONTOURS: { if (showViewMode) { addAction(getActionViewName()); } addAction(getActionContourDrawName()); BrainModelContours* bmc = bs->getBrainModelContours(); if (bmc->getContourFile()->getNumberOfContours() > 0) { addAction(getActionContourDeleteName()); addAction(getActionContourMergeName()); addAction(getActionContourReversePointOrderName()); addAction(getActionContourPointDeleteName()); addAction(getActionContourPointMoveName()); addAction(getActionContourCellAddName()); if ((bs->getContourCellFile()->getNumberOfCells() > 0) && (bs->getDisplaySettingsContours()->getDisplayContourCells())) { addAction(getActionContourCellDeleteName()); addAction(getActionContourCellMoveName()); } } } break; case BrainModel::BRAIN_MODEL_VOLUME: { BrainModelVolumeVoxelColoring* voxelColoring = theMainWindow->getBrainSet()->getVoxelColoring(); if (showViewMode) { addAction(getActionViewName()); } addAction(getActionBorderDrawName()); if ((bs->getVolumeBorderFile()->getNumberOfBorders() > 0) && (bs->getDisplaySettingsBorders()->getDisplayBorders())) { addAction(getActionBorderDeleteName()); addAction(getActionBorderRenameName()); addAction(getActionBorderReversePointOrderName()); addAction(getActionBorderPointDeleteName()); addAction(getActionBorderPointMoveName()); } if (voxelColoring->isUnderlayOrOverlay(BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_PAINT)) { addAction(getActionVolumePaintEditName()); } if (voxelColoring->isUnderlayOrOverlay(BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_SEGMENTATION)) { addAction(getActionVolumeSegmentationEditName()); } } break; } } } caret-5.6.4~dfsg.1.orig/caret/GuiMorphingMeasurementsDialog.h0000664000175000017500000000322011572067322023766 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_MORPHING_MEASUREMENTS_DIALOG_H__ #define __GUI_MORPHING_MEASUREMENTS_DIALOG_H__ #include #include "WuQDialog.h" #include "BrainModelSurfaceMultiresolutionMorphing.h" /// Dialog for displaying morphing measurements class GuiMorphingMeasurementsDialog : public WuQDialog { Q_OBJECT public: /// constructor GuiMorphingMeasurementsDialog(const std::vector& mm, const float totalTime, const BrainModelSurfaceMorphing::MORPHING_SURFACE_TYPE morphingType, const bool deleteDialogWhenClosedFlag, QWidget* parent); /// destructor ~GuiMorphingMeasurementsDialog(); }; #endif // __GUI_MORPHING_MEASUREMENTS_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiMorphingMeasurementsDialog.cxx0000664000175000017500000002703511572067322024353 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include "GuiMorphingMeasurementsDialog.h" /** * constructor */ GuiMorphingMeasurementsDialog::GuiMorphingMeasurementsDialog( const std::vector& mm, const float totalTime, const BrainModelSurfaceMorphing::MORPHING_SURFACE_TYPE morphingType, const bool deleteDialogWhenClosedFlag, QWidget* parent) : WuQDialog(parent) { if (morphingType == BrainModelSurfaceMorphing::MORPHING_SURFACE_SPHERICAL) { setWindowTitle("Spherical Morphing Measurements"); } else { setWindowTitle("Flat Morphing Measurements"); } if (deleteDialogWhenClosedFlag) { setAttribute(Qt::WA_DeleteOnClose); } // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // Grid layout // const int numItems = static_cast(mm.size()); QGridLayout* gridLayout = new QGridLayout; dialogLayout->addLayout(gridLayout); int rowNumber = 0; // // column titles for 100% values // gridLayout->addWidget(new QLabel("Statistics for All"), rowNumber, 0, 1, 11, Qt::AlignHCenter); rowNumber++; gridLayout->addWidget(new QLabel(" "), rowNumber, 0, Qt::AlignRight); gridLayout->addWidget(new QLabel("Node "), rowNumber, 1, Qt::AlignRight); gridLayout->addWidget(new QLabel("Tile "), rowNumber, 2, Qt::AlignRight); gridLayout->addWidget(new QLabel("Areal Dist "), rowNumber, 3, Qt::AlignRight); gridLayout->addWidget(new QLabel("Areal Dist "), rowNumber, 4, Qt::AlignRight); gridLayout->addWidget(new QLabel("Areal Dist "), rowNumber, 5, Qt::AlignRight); gridLayout->addWidget(new QLabel("Areal Dist "), rowNumber, 6, Qt::AlignRight); gridLayout->addWidget(new QLabel("Linear Dist "), rowNumber, 7, Qt::AlignRight); gridLayout->addWidget(new QLabel("Linear Dist "), rowNumber, 8, Qt::AlignRight); gridLayout->addWidget(new QLabel("Linear Dist "), rowNumber, 9, Qt::AlignRight); gridLayout->addWidget(new QLabel("Linear Dist "), rowNumber, 10, Qt::AlignRight); gridLayout->addWidget(new QLabel("Total "), rowNumber, 11, Qt::AlignRight); rowNumber++; gridLayout->addWidget(new QLabel("Cycle "), rowNumber, 0, Qt::AlignLeft); gridLayout->addWidget(new QLabel("Crossovers "), rowNumber, 1, Qt::AlignRight); gridLayout->addWidget(new QLabel("Crossovers "), rowNumber, 2, Qt::AlignRight); gridLayout->addWidget(new QLabel("Average "), rowNumber, 3, Qt::AlignRight); gridLayout->addWidget(new QLabel("Deviation "), rowNumber, 4, Qt::AlignRight); gridLayout->addWidget(new QLabel("Minimum "), rowNumber, 5, Qt::AlignRight); gridLayout->addWidget(new QLabel("Maximum "), rowNumber, 6, Qt::AlignRight); gridLayout->addWidget(new QLabel("Average "), rowNumber, 7, Qt::AlignRight); gridLayout->addWidget(new QLabel("Deviation "), rowNumber, 8, Qt::AlignRight); gridLayout->addWidget(new QLabel("Minimum "), rowNumber, 9, Qt::AlignRight); gridLayout->addWidget(new QLabel("Maximum "), rowNumber, 10, Qt::AlignRight); gridLayout->addWidget(new QLabel("Time "), rowNumber, 11, Qt::AlignRight); rowNumber++; // // Add in the data with stats for all values // for (int i = 0; i < numItems; i++) { QString name; int nodeCrossovers; int tileCrossovers; StatisticsUtilities::DescriptiveStatistics adStats, ldStats; float et; mm[i].get(name, adStats, ldStats, nodeCrossovers, tileCrossovers, et); gridLayout->addWidget(new QLabel(name), rowNumber, 0, Qt::AlignLeft); gridLayout->addWidget(new QLabel(QString::number(nodeCrossovers)), rowNumber, 1, Qt::AlignRight); gridLayout->addWidget(new QLabel(QString::number(tileCrossovers)), rowNumber, 2, Qt::AlignRight); gridLayout->addWidget(new QLabel(QString::number(adStats.average, 'f', 3)), rowNumber, 3, Qt::AlignRight); gridLayout->addWidget(new QLabel(QString::number(adStats.standardDeviation, 'f', 3)), rowNumber, 4, Qt::AlignRight); gridLayout->addWidget(new QLabel(QString::number(adStats.minValue, 'f', 3)), rowNumber, 5, Qt::AlignRight); gridLayout->addWidget(new QLabel(QString::number(adStats.maxValue, 'f', 3)), rowNumber, 6, Qt::AlignRight); gridLayout->addWidget(new QLabel(QString::number(ldStats.average, 'f', 3)), rowNumber, 7, Qt::AlignRight); gridLayout->addWidget(new QLabel(QString::number(ldStats.standardDeviation, 'f', 3)), rowNumber, 8, Qt::AlignRight); gridLayout->addWidget(new QLabel(QString::number(ldStats.minValue, 'f', 3)), rowNumber, 9, Qt::AlignRight); gridLayout->addWidget(new QLabel(QString::number(ldStats.maxValue, 'f', 3)), rowNumber, 10, Qt::AlignRight); gridLayout->addWidget(new QLabel(QString::number(et, 'f', 3)), rowNumber, 11, Qt::AlignRight); rowNumber++; } // // couple of blank rows // gridLayout->addWidget(new QLabel(" "), rowNumber, 0, 1, 11); rowNumber++; gridLayout->addWidget(new QLabel(" "), rowNumber, 0, 1, 11); rowNumber++; // // column titles for 100% values // gridLayout->addWidget(new QLabel("Statistics With Top and Bottom 2% Excluded"), rowNumber, 0, 1, 11, Qt::AlignHCenter); rowNumber++; gridLayout->addWidget(new QLabel(" "), rowNumber, 0, Qt::AlignRight); gridLayout->addWidget(new QLabel("Node "), rowNumber, 1, Qt::AlignRight); gridLayout->addWidget(new QLabel("Tile "), rowNumber, 2, Qt::AlignRight); gridLayout->addWidget(new QLabel("Areal Dist "), rowNumber, 3, Qt::AlignRight); gridLayout->addWidget(new QLabel("Areal Dist "), rowNumber, 4, Qt::AlignRight); gridLayout->addWidget(new QLabel("Areal Dist "), rowNumber, 5, Qt::AlignRight); gridLayout->addWidget(new QLabel("Areal Dist "), rowNumber, 6, Qt::AlignRight); gridLayout->addWidget(new QLabel("Linear Dist "), rowNumber, 7, Qt::AlignRight); gridLayout->addWidget(new QLabel("Linear Dist "), rowNumber, 8, Qt::AlignRight); gridLayout->addWidget(new QLabel("Linear Dist "), rowNumber, 9, Qt::AlignRight); gridLayout->addWidget(new QLabel("Linear Dist "), rowNumber, 10, Qt::AlignRight); gridLayout->addWidget(new QLabel("Total "), rowNumber, 11, Qt::AlignRight); rowNumber++; gridLayout->addWidget(new QLabel("Cycle "), rowNumber, 0, Qt::AlignLeft); gridLayout->addWidget(new QLabel("Crossovers "), rowNumber, 1, Qt::AlignRight); gridLayout->addWidget(new QLabel("Crossovers "), rowNumber, 2, Qt::AlignRight); gridLayout->addWidget(new QLabel("Average "), rowNumber, 3, Qt::AlignRight); gridLayout->addWidget(new QLabel("Deviation "), rowNumber, 4, Qt::AlignRight); gridLayout->addWidget(new QLabel("Minimum "), rowNumber, 5, Qt::AlignRight); gridLayout->addWidget(new QLabel("Maximum "), rowNumber, 6, Qt::AlignRight); gridLayout->addWidget(new QLabel("Average "), rowNumber, 7, Qt::AlignRight); gridLayout->addWidget(new QLabel("Deviation "), rowNumber, 8, Qt::AlignRight); gridLayout->addWidget(new QLabel("Minimum "), rowNumber, 9, Qt::AlignRight); gridLayout->addWidget(new QLabel("Maximum "), rowNumber, 10, Qt::AlignRight); gridLayout->addWidget(new QLabel("Time "), rowNumber, 11, Qt::AlignRight); rowNumber++; // // Add in the data with stats for all values // for (int i = 0; i < numItems; i++) { QString name; int nodeCrossovers; int tileCrossovers; StatisticsUtilities::DescriptiveStatistics adStats, ldStats; float et; mm[i].get(name, adStats, ldStats, nodeCrossovers, tileCrossovers, et); gridLayout->addWidget(new QLabel(name), rowNumber, 0, Qt::AlignLeft); gridLayout->addWidget(new QLabel(QString::number(nodeCrossovers)), rowNumber, 1, Qt::AlignRight); gridLayout->addWidget(new QLabel(QString::number(tileCrossovers)), rowNumber, 2, Qt::AlignRight); gridLayout->addWidget(new QLabel(QString::number(adStats.average96, 'f', 3)), rowNumber, 3, Qt::AlignRight); gridLayout->addWidget(new QLabel(QString::number(adStats.standardDeviation96, 'f', 3)), rowNumber, 4, Qt::AlignRight); gridLayout->addWidget(new QLabel(QString::number(adStats.minValue96, 'f', 3)), rowNumber, 5, Qt::AlignRight); gridLayout->addWidget(new QLabel(QString::number(adStats.maxValue96, 'f', 3)), rowNumber, 6, Qt::AlignRight); gridLayout->addWidget(new QLabel(QString::number(ldStats.average96, 'f', 3)), rowNumber, 7, Qt::AlignRight); gridLayout->addWidget(new QLabel(QString::number(ldStats.standardDeviation96, 'f', 3)), rowNumber, 8, Qt::AlignRight); gridLayout->addWidget(new QLabel(QString::number(ldStats.minValue96, 'f', 3)), rowNumber, 9, Qt::AlignRight); gridLayout->addWidget(new QLabel(QString::number(ldStats.maxValue96, 'f', 3)), rowNumber, 10, Qt::AlignRight); gridLayout->addWidget(new QLabel(QString::number(et, 'f', 3)), rowNumber, 11, Qt::AlignRight); rowNumber++; } // // couple of blank rows // gridLayout->addWidget(new QLabel(" "), rowNumber, 0, 1, 11); rowNumber++; gridLayout->addWidget(new QLabel(" "), rowNumber, 0, 1, 11); rowNumber++; // // Display the total execution time // QString totalTimeText("Total Execution Time (Minutes): "); totalTimeText += QString::number((totalTime / 60.0), 'f', 1); dialogLayout->addWidget(new QLabel(totalTimeText)); // // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; dialogLayout->addLayout(buttonsLayout); // // close button // QPushButton* closeButton = new QPushButton("Close"); buttonsLayout->addWidget(closeButton); closeButton->setFixedSize(closeButton->sizeHint()); closeButton->setAutoDefault(false); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); } /** * destructor */ GuiMorphingMeasurementsDialog::~GuiMorphingMeasurementsDialog() { } caret-5.6.4~dfsg.1.orig/caret/GuiMorphingDialog.h0000664000175000017500000000544411572067322021407 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_MORPHING_DIALOG_H__ #define __GUI_MORPHING_DIALOG_H__ #include "WuQDialog.h" #include "BrainModelSurfaceMorphing.h" class GuiBrainModelSelectionComboBox; class QCheckBox; class QSpinBox; class QDoubleSpinBox; /// Dialog for morphing class GuiMorphingDialog : public WuQDialog { Q_OBJECT public: /// constructor GuiMorphingDialog(QWidget* parent, const BrainModelSurfaceMorphing::MORPHING_SURFACE_TYPE morphingSurfaceTypeIn); /// Destructor ~GuiMorphingDialog(); /// update the dialog void updateDialog(); private slots: /// called when apply button pressed void slotApplyButton(); private: /// create the parameters section QWidget* createParametersSection(); /// create the misc section QWidget* createMiscSection(); /// create the surface section QWidget* createSurfaceSection(); /// type of morphing BrainModelSurfaceMorphing::MORPHING_SURFACE_TYPE morphingSurfaceType; /// reference surface combo box GuiBrainModelSelectionComboBox* referenceSurfaceComboBox; /// morphing surface combo box GuiBrainModelSelectionComboBox* morphingSurfaceComboBox; /// iterations spin box QSpinBox* iterationsSpinBox; /// linear force float spin box QDoubleSpinBox* linearForceDoubleSpinBox; /// angular force float spin box QDoubleSpinBox* angularForceDoubleSpinBox; /// step size float spin box QDoubleSpinBox* stepSizeDoubleSpinBox; /// landmark morphing check box QCheckBox* landmarkMorphingCheckBox; /// measurements each iteration check box QCheckBox* measureEachIterationCheckBox; /// number of threads spin box QSpinBox* threadsSpinBox; }; #endif // __GUI_MULTIRESOLUTION_MORPHING_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiMorphingDialog.cxx0000664000175000017500000003377411572067322021771 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "BrainModelSurfaceNodeColoring.h" #include "BrainSet.h" #include "DebugControl.h" #include "FileUtilities.h" #include "GuiBrainModelSelectionComboBox.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "GuiMorphingDialog.h" #include #include "QtUtilities.h" #include "PaintFile.h" #include "global_variables.h" /** * constructor */ GuiMorphingDialog::GuiMorphingDialog(QWidget* parent, const BrainModelSurfaceMorphing::MORPHING_SURFACE_TYPE morphingSurfaceTypeIn) : WuQDialog(parent) { morphingSurfaceType = morphingSurfaceTypeIn; switch (morphingSurfaceType) { case BrainModelSurfaceMorphing::MORPHING_SURFACE_FLAT: setWindowTitle("Morphing - Flat"); break; case BrainModelSurfaceMorphing::MORPHING_SURFACE_SPHERICAL: setWindowTitle("Morphing - Sphere"); break; } // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // Create the surfaces section // dialogLayout->addWidget(createSurfaceSection()); // // Create the morphing parameters section // dialogLayout->addWidget(createParametersSection()); // // Create the misc section // dialogLayout->addWidget(createMiscSection()); threadsSpinBox = NULL; if (DebugControl::getDebugOn()) { // // Group box for threading // QGroupBox* threadsGroupBox = new QGroupBox("Execution Threads"); dialogLayout->addWidget(threadsGroupBox); QHBoxLayout* threadsLayout = new QHBoxLayout(threadsGroupBox); // // Threads strength // threadsLayout->addWidget(new QLabel("Number to Run")); threadsSpinBox = new QSpinBox; threadsSpinBox->setMinimum(0); threadsSpinBox->setMaximum(1024); threadsSpinBox->setSingleStep(1); threadsLayout->addWidget(threadsSpinBox); threadsSpinBox->setToolTip( "Morphing will be split into this\n" "number of simultaneous processes."); PreferencesFile* pf = theMainWindow->getBrainSet()->getPreferencesFile(); threadsSpinBox->setValue(pf->getMaximumNumberOfThreads()); } // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); dialogLayout->addLayout(buttonsLayout); // // Apply button // QPushButton* applyButton = new QPushButton("Apply"); applyButton->setToolTip( "Run Morphing."); applyButton->setAutoDefault(false); buttonsLayout->addWidget(applyButton); QObject::connect(applyButton, SIGNAL(clicked()), this, SLOT(slotApplyButton())); // // Close button // QPushButton* closeButton = new QPushButton("Close"); closeButton->setToolTip( "Close dialog."); closeButton->setAutoDefault(false); buttonsLayout->addWidget(closeButton); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); QtUtilities::makeButtonsSameSize(applyButton, closeButton); // // Load the default parameters // int iter; float ang, lin, step; BrainModelSurfaceMorphing junk(NULL, NULL, NULL, morphingSurfaceType); junk.getMorphingParameters(iter, lin, ang, step); iterationsSpinBox->setValue(iter); linearForceDoubleSpinBox->setValue(lin); angularForceDoubleSpinBox->setValue(ang); stepSizeDoubleSpinBox->setValue(step); } /** * Destructor */ GuiMorphingDialog::~GuiMorphingDialog() { } /** * Update the dialog */ void GuiMorphingDialog::updateDialog() { referenceSurfaceComboBox->updateComboBox(); morphingSurfaceComboBox->updateComboBox(); } /** * Create the surface section */ QWidget* GuiMorphingDialog::createSurfaceSection() { // // reference surface // QLabel* refLabel = new QLabel("Reference"); referenceSurfaceComboBox = new GuiBrainModelSelectionComboBox(false, true, false, "", 0); referenceSurfaceComboBox->setSelectedBrainModel(theMainWindow->getBrainSet()->getActiveFiducialSurface()); // // morphing surface // QLabel* morphLabel = new QLabel("Morphing"); morphingSurfaceComboBox = new GuiBrainModelSelectionComboBox(false, true, false, "", 0); morphingSurfaceComboBox->setSelectedBrainModel(theMainWindow->getBrainModelSurface()); QGroupBox* surfaceGroupBox = new QGroupBox("Surfaces"); QGridLayout* surfaceLayout = new QGridLayout(surfaceGroupBox); surfaceLayout->addWidget(refLabel, 0, 0); surfaceLayout->addWidget(referenceSurfaceComboBox, 0, 1); surfaceLayout->addWidget(morphLabel, 1, 0); surfaceLayout->addWidget(morphingSurfaceComboBox, 1, 1); return surfaceGroupBox; } /** * Create the parameters section */ QWidget* GuiMorphingDialog::createParametersSection() { // // Linear Force Float spin box // QLabel* linearLabel = new QLabel("Linear Force"); linearForceDoubleSpinBox = new QDoubleSpinBox; linearForceDoubleSpinBox->setMinimum(0.0); linearForceDoubleSpinBox->setMaximum(1.0); linearForceDoubleSpinBox->setSingleStep(0.10); linearForceDoubleSpinBox->setDecimals(1); // // Angular Float spin box // QLabel* angularLabel = new QLabel("Angular Force"); angularForceDoubleSpinBox = new QDoubleSpinBox; angularForceDoubleSpinBox->setMinimum(0.0); angularForceDoubleSpinBox->setMaximum(1.0); angularForceDoubleSpinBox->setSingleStep(0.10); angularForceDoubleSpinBox->setDecimals(1); // // Step Size Float spin box // QLabel* stepLabel = new QLabel("Step Size"); stepSizeDoubleSpinBox = new QDoubleSpinBox; stepSizeDoubleSpinBox->setMinimum(0.0); stepSizeDoubleSpinBox->setMaximum(1.0); stepSizeDoubleSpinBox->setSingleStep(0.1); stepSizeDoubleSpinBox->setDecimals(1); // // Iterations spin box // QLabel* itersLabel = new QLabel("Iterations"); iterationsSpinBox = new QSpinBox; iterationsSpinBox->setMinimum(0); iterationsSpinBox->setMaximum(100000); iterationsSpinBox->setSingleStep(10); // // Group box and layout // QGroupBox* paramsGroupBox = new QGroupBox("Morphing Forces"); QGridLayout* paramsLayout = new QGridLayout(paramsGroupBox); paramsLayout->addWidget(linearLabel, 0, 0); paramsLayout->addWidget(linearForceDoubleSpinBox, 0, 1); paramsLayout->addWidget(angularLabel, 1, 0); paramsLayout->addWidget(angularForceDoubleSpinBox, 1, 1); paramsLayout->addWidget(stepLabel, 2, 0); paramsLayout->addWidget(stepSizeDoubleSpinBox, 2, 1); paramsLayout->addWidget(itersLabel, 3, 0); paramsLayout->addWidget(iterationsSpinBox, 3, 1); return paramsGroupBox; } /** * Create the misc section */ QWidget* GuiMorphingDialog::createMiscSection() { // // delete temporary files check box // landmarkMorphingCheckBox = new QCheckBox("Landmark Morphing"); landmarkMorphingCheckBox->setToolTip( "If checked and there is a paint file column named\n" "\"Landmarks\", any node with a paint value of \"Landmark\"\n" "will not be morphed and special forces are applied to\n" "their neighbors."); // // make measurements each iteration check box // measureEachIterationCheckBox = new QCheckBox("Measure Each Iteration"); measureEachIterationCheckBox->setToolTip( "If checked, distortion and crossovers are measured each\n" "pass and written to the file \"morph_stats.txt\". This\n" "information may be used help choose the best morphing \n" "parameters for use during multi-resolution morphing."); QGroupBox* miscGroupBox = new QGroupBox("Misc"); QVBoxLayout* miscLayout = new QVBoxLayout(miscGroupBox); miscLayout->addWidget(landmarkMorphingCheckBox); miscLayout->addWidget(measureEachIterationCheckBox); return miscGroupBox; } /** * called when Apply button pressed */ void GuiMorphingDialog::slotApplyButton() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); // // get the morphing surfaces // BrainModelSurface* referenceSurface = referenceSurfaceComboBox->getSelectedBrainModelSurface(); BrainModelSurface* morphingSurface = morphingSurfaceComboBox->getSelectedBrainModelSurface(); // // Check for flat/spherical surface // if (morphingSurfaceType == BrainModelSurfaceMorphing::MORPHING_SURFACE_FLAT) { if ((morphingSurface->getSurfaceType() != BrainModelSurface::SURFACE_TYPE_FLAT) & (morphingSurface->getSurfaceType() != BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR)) { if (QMessageBox::warning(this, "Warning", "Surface for morphing is not a flat surface.", (QMessageBox::Ok | QMessageBox::Cancel), QMessageBox::Cancel) == QMessageBox::Cancel) { return; } } } else { if (morphingSurface->getSurfaceType() != BrainModelSurface::SURFACE_TYPE_SPHERICAL) { if (QMessageBox::warning(this, "Warning", "Surface for morphing is not a spherical surface.", (QMessageBox::Ok | QMessageBox::Cancel), QMessageBox::Cancel) == QMessageBox::Cancel) { return; } } } PreferencesFile* pf = theMainWindow->getBrainSet()->getPreferencesFile(); int numberOfThreads = pf->getMaximumNumberOfThreads(); if (threadsSpinBox != NULL) { numberOfThreads = threadsSpinBox->value(); } // // Create the morphing object // BrainModelSurfaceMorphing bsm(theMainWindow->getBrainSet(), referenceSurface, morphingSurface, morphingSurfaceType, numberOfThreads); // // Copy the saved parameters to the morphing object // bsm.setMorphingParameters(iterationsSpinBox->value(), linearForceDoubleSpinBox->value(), angularForceDoubleSpinBox->value(), stepSizeDoubleSpinBox->value()); // // if landmark contrained morphing // if (landmarkMorphingCheckBox->isChecked()) { const int numNodes = morphingSurface->getNumberOfNodes(); if (numNodes > 0) { PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); const int column = pf->getColumnWithName("Landmarks"); if (column >= 0) { const int paintIndex = pf->getPaintIndexFromName("Landmark"); std::vector morphNodes(numNodes, true); int cnt = 0; for (int i = 0; i < numNodes; i++) { if (pf->getPaint(i, column) == paintIndex) { morphNodes[i] = false; cnt++; } } if (DebugControl::getDebugOn()) { std::cout << "There are " << cnt << " landmark nodes." << std::endl; } bsm.setNodesThatShouldBeMorphed(morphNodes, 0.5); } } } // // Do statistics each pass // bsm.setDoStatisticsEachPass(measureEachIterationCheckBox->isChecked()); // // Execute the morphing // QTime timer; timer.start(); try { bsm.execute(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(theMainWindow, "Error", e.whatQString(), "OK"); return; } const float elapsedTime = timer.elapsed() * 0.001; if (DebugControl::getDebugOn()) { std::cout << "Morphing Time: " << elapsedTime << " seconds." << std::endl; } // // Notify about modified files and redraw all displays // GuiFilesModified fm; fm.setCoordinateModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); QApplication::beep(); //theMainWindow->speakText("Morphing has completed", false); } caret-5.6.4~dfsg.1.orig/caret/GuiModelsEditorDialog.h0000664000175000017500000000301511572067322022206 0ustar michaelmichael #ifndef __GUI_MODELS_EDITOR_H__ #define __GUI_MODELS_EDITOR_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "WuQDialog.h" class GuiModelSelectionControl; /// dialog for editing models class GuiModelsEditorDialog : public WuQDialog { Q_OBJECT public: // constructor GuiModelsEditorDialog(QWidget* parent); // destructor ~GuiModelsEditorDialog(); // update the dialog void updateDialog(); protected slots: // called when set color button pressed void slotSetColorButton(); protected: // control for model selection GuiModelSelectionControl* modelControl; }; #endif // __GUI_MODELS_EDITOR_H__ caret-5.6.4~dfsg.1.orig/caret/GuiModelsEditorDialog.cxx0000664000175000017500000000724211572067322022567 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include "BrainSet.h" #include "GuiBrainModelOpenGL.h" #include "GuiColorSelectionDialog.h" #include "GuiMainWindow.h" #include "GuiModelSelectionControl.h" #include "GuiModelsEditorDialog.h" #include "VtkModelFile.h" #include "global_variables.h" /** * constructor. */ GuiModelsEditorDialog::GuiModelsEditorDialog(QWidget* parent) : WuQDialog(parent) { setObjectName("GuiModelsEditor"); setWindowTitle("Models Editor"); // // Layout for dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); // // model control // QLabel* modelLabel = new QLabel("Model: ", this); modelControl = new GuiModelSelectionControl; // // Color push button // QPushButton* colorPushButton = new QPushButton("Set Color...", this); colorPushButton->setObjectName("colorPushButton"); colorPushButton->setAutoDefault(false); colorPushButton->setFixedSize(colorPushButton->sizeHint()); QObject::connect(colorPushButton, SIGNAL(clicked()), this, SLOT(slotSetColorButton())); // // Layout items // QHBoxLayout* modelLayout = new QHBoxLayout; dialogLayout->addLayout(modelLayout); modelLayout->setObjectName("modelLayout"); modelLayout->addWidget(modelLabel); modelLayout->addWidget(modelControl); dialogLayout->addWidget(colorPushButton); // // Dialog buttons // QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); buttonBox->button(QDialogButtonBox::Close)->setAutoDefault(false); dialogLayout->addWidget(buttonBox); QObject::connect(buttonBox, SIGNAL(rejected()), this, SLOT(close())); } /** * destructor. */ GuiModelsEditorDialog::~GuiModelsEditorDialog() { } /** * update the dialog. */ void GuiModelsEditorDialog::updateDialog() { modelControl->updateControl(); } /** * called when set color button pressed. */ void GuiModelsEditorDialog::slotSetColorButton() { VtkModelFile* vmf = modelControl->getSelectedModel(); if (vmf != NULL) { GuiColorSelectionDialog csd(this, "Set VTK Model Color", true, false, false, false); if (csd.exec() == QDialog::Accepted) { unsigned char rgba[4]; float pointSize, lineSize; ColorFile::ColorStorage::SYMBOL symbol; csd.getColorInformation(rgba[0], rgba[1], rgba[2], rgba[3], pointSize, lineSize, symbol); vmf->setToSolidColor(rgba); GuiBrainModelOpenGL::updateAllGL(); } } } caret-5.6.4~dfsg.1.orig/caret/GuiModelSelectionControl.h0000664000175000017500000000361411572067322022750 0ustar michaelmichael #ifndef __GUI_MODEL_SELECTION_CONTROL_H__ #define __GUI_MODEL_SELECTION_CONTROL_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include class VtkModelFile; /// control for selecting models class GuiModelSelectionControl : public QComboBox { Q_OBJECT public: // constructor GuiModelSelectionControl(QWidget* parent = 0); // destructor ~GuiModelSelectionControl(); // get selected model VtkModelFile* getSelectedModel(); // get selected model const VtkModelFile* getSelectedModel() const; // get selected model int getSelectedModelIndex() const; // set the selected model void setSelectedModel(const VtkModelFile* vmf); // set the selected model index void setSelectedModelIndex(const int indx); // update the control void updateControl(); protected: // models in control std::vector models; }; #endif // __GUI_MODEL_SELECTION_CONTROL_H__ caret-5.6.4~dfsg.1.orig/caret/GuiModelSelectionControl.cxx0000664000175000017500000000637011572067322023325 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainSet.h" #include "FileUtilities.h" #include "GuiMainWindow.h" #include "GuiModelSelectionControl.h" #include "VtkModelFile.h" #include "global_variables.h" /** * constructor. */ GuiModelSelectionControl::GuiModelSelectionControl(QWidget* parent) : QComboBox(parent) { setObjectName("GuiModelSelectionControl"); updateControl(); } /** * destructor. */ GuiModelSelectionControl::~GuiModelSelectionControl() { } /** * get selected model. */ VtkModelFile* GuiModelSelectionControl::getSelectedModel() { const int indx = getSelectedModelIndex(); if (indx >= 0) { return models[indx]; } return NULL; } /** * get selected model. */ const VtkModelFile* GuiModelSelectionControl::getSelectedModel() const { const int indx = getSelectedModelIndex(); if (indx >= 0) { return models[indx]; } return NULL; } /** * get selected model. */ int GuiModelSelectionControl::getSelectedModelIndex() const { const int indx = currentIndex(); if ((indx >= 0) && (indx < static_cast(models.size()))) { return indx; } return -1; } /** * set the selected model. */ void GuiModelSelectionControl::setSelectedModel(const VtkModelFile* vmf) { for (int i = 0; i < static_cast(models.size()); i++) { if (models[i] == vmf) { setCurrentIndex(i); break; } } } /** * set the selected model index. */ void GuiModelSelectionControl::setSelectedModelIndex(const int indx) { if ((indx >= 0) && (indx < static_cast(models.size()))) { setCurrentIndex(indx); } } /** * update the control. */ void GuiModelSelectionControl::updateControl() { VtkModelFile* selectedModel = NULL; int selectedIndex = getSelectedModelIndex(); if ((selectedIndex >= 0) && (selectedIndex < static_cast(models.size()))) { selectedModel = models[selectedIndex]; } this->clear(); selectedIndex = -1; models.clear(); const int num = theMainWindow->getBrainSet()->getNumberOfVtkModelFiles(); for (int i = 0; i < num; i++) { VtkModelFile* vmf = theMainWindow->getBrainSet()->getVtkModelFile(i); models.push_back(vmf); addItem(FileUtilities::basename(vmf->getFileName())); if (selectedModel == vmf) { selectedIndex = i; } } if (selectedIndex >= 0) { setSelectedModelIndex(selectedIndex); } } caret-5.6.4~dfsg.1.orig/caret/GuiMetricsToRgbPaintDialog.h0000664000175000017500000001155311572067322023162 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_METRICS_TO_RGB_PAINT_DIALOG_H__ #define __GUI_METRICS_TO_RGB_PAINT_DIALOG_H__ #include "WuQDialog.h" class GuiNodeAttributeColumnSelectionComboBox; class QLineEdit; /// This dialog is used to enter parameters for converting a metric file to RGB paint class GuiMetricsToRgbPaintDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiMetricsToRgbPaintDialog(QWidget* parent); /// Destructor ~GuiMetricsToRgbPaintDialog(); /// Update the dialog if metrics or rgb paint change void updateDialog(); private slots: /// called when an Rgb paint column is selected void slotRgbColumnSelected(int column); /// Called when apply button pressed. void slotApplyButton(); /// Called when red metric column is selected void slotRedMetricSelected(int item); /// Called when green metric column is selected void slotGreenMetricSelected(int item); /// Called when blue metric column is selected void slotBlueMetricSelected(int item); /// Called when red threshold column is selected void slotRedThresholdSelected(int item); /// Called when green threshold column is selected void slotGreenThresholdSelected(int item); /// Called when blue threshold column is selected void slotBlueThresholdSelected(int item); private: /// inhibit update of dislay bool inhibitUpdate; /// Create the metric section QWidget* createMetricSection(); /// Create the threshold section QWidget* createThresholdSection(); /// Create the rgb paint section QWidget* createRgbSection(); /// load metric line edits void loadMetricMinMaxLineEdits(const int metricColumn, QLineEdit* minLineEdit, QLineEdit* maxLineEdit); /// line edit for comment QLineEdit* columnCommentLineEdit; /// column name line edit QLineEdit* columnNameLineEdit; /// rgb paint column selection; GuiNodeAttributeColumnSelectionComboBox* rgbColumnComboBox; /// red metric combo box GuiNodeAttributeColumnSelectionComboBox* redMetricComboBox; /// green metric combo box GuiNodeAttributeColumnSelectionComboBox* greenMetricComboBox; /// blue metric combo box GuiNodeAttributeColumnSelectionComboBox* blueMetricComboBox; // red metric neg max line edit QLineEdit* redMetricNegMaxLineEdit; // green metric neg max line edit QLineEdit* greenMetricNegMaxLineEdit; // blue metric neg max line edit QLineEdit* blueMetricNegMaxLineEdit; // red metric pos max line edit QLineEdit* redMetricPosMaxLineEdit; // green metric pos max line edit QLineEdit* greenMetricPosMaxLineEdit; // blue metric pos max line edit QLineEdit* blueMetricPosMaxLineEdit; /// red threshold combo box GuiNodeAttributeColumnSelectionComboBox* redThresholdComboBox; /// green threshold combo box GuiNodeAttributeColumnSelectionComboBox* greenThresholdComboBox; /// blue threshold combo box GuiNodeAttributeColumnSelectionComboBox* blueThresholdComboBox; // red threshold neg max line edit QLineEdit* redThresholdNegLineEdit; // green threshold neg max line edit QLineEdit* greenThresholdNegLineEdit; // blue threshold neg max line edit QLineEdit* blueThresholdNegLineEdit; // red threshold pos max line edit QLineEdit* redThresholdPosLineEdit; // green threshold pos max line edit QLineEdit* greenThresholdPosLineEdit; // blue threshold pos max line edit QLineEdit* blueThresholdPosLineEdit; }; #endif // __GUI_METRICS_TO_RGB_PAINT_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiMetricsToRgbPaintDialog.cxx0000664000175000017500000004611011572067322023532 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include "BrainSet.h" #include "GuiBrainModelOpenGL.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "GuiMetricsToRgbPaintDialog.h" #include "GuiNodeAttributeColumnSelectionComboBox.h" #include "MetricFile.h" #include "MetricsToRgbPaintConverter.h" #include "QtUtilities.h" #include "RgbPaintFile.h" #include "global_variables.h" /** * Constructor */ GuiMetricsToRgbPaintDialog::GuiMetricsToRgbPaintDialog(QWidget* parent) : WuQDialog(parent) { setWindowTitle("Metrics to RGB Paint"); inhibitUpdate = false; // // Vertical box layout of all items // QVBoxLayout* rows = new QVBoxLayout(this); rows->setMargin(3); rows->setSpacing(3); rows->addWidget(createRgbSection()); rows->addWidget(createMetricSection()); rows->addWidget(createThresholdSection()); // // // Dialog Buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; rows->addLayout(buttonsLayout); // // OK button // QPushButton* applyButton = new QPushButton("Apply"); applyButton->setAutoDefault(false); QObject::connect(applyButton, SIGNAL(clicked()), this, SLOT(slotApplyButton())); buttonsLayout->addWidget(applyButton); // // Close button // QPushButton* closeButton = new QPushButton("Close"); closeButton->setAutoDefault(false); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); buttonsLayout->addWidget(closeButton); QtUtilities::makeButtonsSameSize(applyButton, closeButton); updateDialog(); } /** * Destructor */ GuiMetricsToRgbPaintDialog::~GuiMetricsToRgbPaintDialog() { } /** * Create the rgb paint section. */ QWidget* GuiMetricsToRgbPaintDialog::createRgbSection() { // // Group Box for Threshold Selections // QGroupBox* rgbPaintGB = new QGroupBox("RGB Paint"); QVBoxLayout* rgbPaintLayout = new QVBoxLayout(rgbPaintGB); // // Horizontal box for column selection and name // QHBoxLayout* columnHBoxLayout = new QHBoxLayout; rgbPaintLayout->addLayout(columnHBoxLayout); columnHBoxLayout->addWidget(new QLabel("Column")); rgbColumnComboBox = new GuiNodeAttributeColumnSelectionComboBox( GUI_NODE_FILE_TYPE_RGB_PAINT, true, false, false); columnHBoxLayout->addWidget(rgbColumnComboBox); QObject::connect(rgbColumnComboBox, SIGNAL(itemSelected(int)), this, SLOT(slotRgbColumnSelected(int))); columnNameLineEdit = new QLineEdit; columnHBoxLayout->addWidget(columnNameLineEdit); // // Horizontal box for comment // QHBoxLayout* commentHBoxLayout = new QHBoxLayout; rgbPaintLayout->addLayout(commentHBoxLayout); commentHBoxLayout->addWidget(new QLabel("Comment")); columnCommentLineEdit = new QLineEdit; commentHBoxLayout->addWidget(columnCommentLineEdit); // // initialize column selection // rgbColumnComboBox->setCurrentIndex(GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NONE); return rgbPaintGB; } /** * Create the threshold section. */ QWidget* GuiMetricsToRgbPaintDialog::createThresholdSection() { // // Group Box for Threshold Selections // QGroupBox* thresholdSelectGB = new QGroupBox("Threshold Selection"); // // grid for threshold selections // int numColumns = 0; const int NAME_COLUMN = numColumns++; const int THRESHOLD_COLUMN = numColumns++; const int NEG_MAX_COLUMN = numColumns++; const int POS_MAX_COLUMN = numColumns++; int numRows = 0; const int TITLE_ROW = numRows++; const int RED_ROW = numRows++; const int GREEN_ROW = numRows++; const int BLUE_ROW = numRows++; QGridLayout* thresholdSelectGrid = new QGridLayout(thresholdSelectGB); thresholdSelectGrid->setMargin(5); thresholdSelectGrid->setSpacing(5); // // column titles // thresholdSelectGrid->addWidget(new QLabel("Color"), TITLE_ROW, NAME_COLUMN, Qt::AlignLeft); thresholdSelectGrid->addWidget(new QLabel("Threshold"), TITLE_ROW, THRESHOLD_COLUMN, Qt::AlignHCenter); thresholdSelectGrid->addWidget(new QLabel("Negative"), TITLE_ROW, NEG_MAX_COLUMN, Qt::AlignLeft); thresholdSelectGrid->addWidget(new QLabel("Positive"), TITLE_ROW, POS_MAX_COLUMN, Qt::AlignLeft); // // Red Row // thresholdSelectGrid->addWidget(new QLabel("Red"), RED_ROW, NAME_COLUMN, Qt::AlignLeft); redThresholdComboBox = new GuiNodeAttributeColumnSelectionComboBox( GUI_NODE_FILE_TYPE_METRIC, false, true, false); QObject::connect(redThresholdComboBox, SIGNAL(itemSelected(int)), this, SLOT(slotRedThresholdSelected(int))); thresholdSelectGrid->addWidget(redThresholdComboBox, RED_ROW, THRESHOLD_COLUMN, Qt::AlignLeft); redThresholdNegLineEdit = new QLineEdit; thresholdSelectGrid->addWidget(redThresholdNegLineEdit, RED_ROW, NEG_MAX_COLUMN, Qt::AlignLeft); redThresholdPosLineEdit = new QLineEdit; thresholdSelectGrid->addWidget(redThresholdPosLineEdit, RED_ROW, POS_MAX_COLUMN, Qt::AlignLeft); // // Green Row // thresholdSelectGrid->addWidget(new QLabel("Green"), GREEN_ROW, NAME_COLUMN, Qt::AlignLeft); greenThresholdComboBox = new GuiNodeAttributeColumnSelectionComboBox( GUI_NODE_FILE_TYPE_METRIC, false, true, false); QObject::connect(greenThresholdComboBox, SIGNAL(itemSelected(int)), this, SLOT(slotGreenThresholdSelected(int))); thresholdSelectGrid->addWidget(greenThresholdComboBox, GREEN_ROW, THRESHOLD_COLUMN, Qt::AlignLeft); greenThresholdNegLineEdit = new QLineEdit; thresholdSelectGrid->addWidget(greenThresholdNegLineEdit, GREEN_ROW, NEG_MAX_COLUMN, Qt::AlignLeft); greenThresholdPosLineEdit = new QLineEdit; thresholdSelectGrid->addWidget(greenThresholdPosLineEdit, GREEN_ROW, POS_MAX_COLUMN, Qt::AlignLeft); // // Blue Row // thresholdSelectGrid->addWidget(new QLabel("Blue"), BLUE_ROW, NAME_COLUMN, Qt::AlignLeft); blueThresholdComboBox = new GuiNodeAttributeColumnSelectionComboBox( GUI_NODE_FILE_TYPE_METRIC, false, true, false); QObject::connect(blueThresholdComboBox, SIGNAL(itemSelected(int)), this, SLOT(slotBlueThresholdSelected(int))); thresholdSelectGrid->addWidget(blueThresholdComboBox, BLUE_ROW, THRESHOLD_COLUMN, Qt::AlignLeft); blueThresholdNegLineEdit = new QLineEdit; thresholdSelectGrid->addWidget(blueThresholdNegLineEdit, BLUE_ROW, NEG_MAX_COLUMN, Qt::AlignLeft); blueThresholdPosLineEdit = new QLineEdit; thresholdSelectGrid->addWidget(blueThresholdPosLineEdit, BLUE_ROW, POS_MAX_COLUMN, Qt::AlignLeft); // // Initialize thresholds to NONE // redThresholdComboBox->setCurrentIndex(GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NONE); greenThresholdComboBox->setCurrentIndex(GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NONE); blueThresholdComboBox->setCurrentIndex(GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NONE); redThresholdNegLineEdit->setText("0.0"); redThresholdPosLineEdit->setText("0.0"); greenThresholdNegLineEdit->setText("0.0"); greenThresholdPosLineEdit->setText("0.0"); blueThresholdNegLineEdit->setText("0.0"); blueThresholdPosLineEdit->setText("0.0"); return thresholdSelectGB; } /** * Create the metric section. */ QWidget* GuiMetricsToRgbPaintDialog::createMetricSection() { // // Group Box for Metric Selections // QGroupBox* metricSelectGB = new QGroupBox("Metric Selection"); // // Widget and grid for metric selections // int numColumns = 0; const int NAME_COLUMN = numColumns++; const int METRIC_COLUMN = numColumns++; const int NEG_MAX_COLUMN = numColumns++; const int POS_MAX_COLUMN = numColumns++; int numRows = 0; const int TITLE_ROW = numRows++; const int RED_ROW = numRows++; const int GREEN_ROW = numRows++; const int BLUE_ROW = numRows++; QGridLayout* metricSelectGrid = new QGridLayout(metricSelectGB); metricSelectGrid->setMargin(5); metricSelectGrid->setSpacing(5); // // column titles // metricSelectGrid->addWidget(new QLabel("Color"), TITLE_ROW, NAME_COLUMN, Qt::AlignLeft); metricSelectGrid->addWidget(new QLabel("Metric"), TITLE_ROW, METRIC_COLUMN, Qt::AlignHCenter); metricSelectGrid->addWidget(new QLabel("Neg Max"), TITLE_ROW, NEG_MAX_COLUMN, Qt::AlignLeft); metricSelectGrid->addWidget(new QLabel("Pos Max"), TITLE_ROW, POS_MAX_COLUMN, Qt::AlignLeft); // // Red Row // metricSelectGrid->addWidget(new QLabel("Red"), RED_ROW, NAME_COLUMN, Qt::AlignLeft); redMetricComboBox = new GuiNodeAttributeColumnSelectionComboBox( GUI_NODE_FILE_TYPE_METRIC, false, true, false); QObject::connect(redMetricComboBox, SIGNAL(itemSelected(int)), this, SLOT(slotRedMetricSelected(int))); metricSelectGrid->addWidget(redMetricComboBox, RED_ROW, METRIC_COLUMN, Qt::AlignLeft); redMetricNegMaxLineEdit = new QLineEdit; metricSelectGrid->addWidget(redMetricNegMaxLineEdit, RED_ROW, NEG_MAX_COLUMN, Qt::AlignLeft); redMetricPosMaxLineEdit = new QLineEdit; metricSelectGrid->addWidget(redMetricPosMaxLineEdit, RED_ROW, POS_MAX_COLUMN, Qt::AlignLeft); // // Green Row // metricSelectGrid->addWidget(new QLabel("Green"), GREEN_ROW, NAME_COLUMN, Qt::AlignLeft); greenMetricComboBox = new GuiNodeAttributeColumnSelectionComboBox( GUI_NODE_FILE_TYPE_METRIC, false, true, false); QObject::connect(greenMetricComboBox, SIGNAL(itemSelected(int)), this, SLOT(slotGreenMetricSelected(int))); metricSelectGrid->addWidget(greenMetricComboBox, GREEN_ROW, METRIC_COLUMN, Qt::AlignLeft); greenMetricNegMaxLineEdit = new QLineEdit; metricSelectGrid->addWidget(greenMetricNegMaxLineEdit, GREEN_ROW, NEG_MAX_COLUMN, Qt::AlignLeft); greenMetricPosMaxLineEdit = new QLineEdit; metricSelectGrid->addWidget(greenMetricPosMaxLineEdit, GREEN_ROW, POS_MAX_COLUMN, Qt::AlignLeft); // // Blue Row // metricSelectGrid->addWidget(new QLabel("Blue"), BLUE_ROW, NAME_COLUMN, Qt::AlignLeft); blueMetricComboBox = new GuiNodeAttributeColumnSelectionComboBox( GUI_NODE_FILE_TYPE_METRIC, false, true, false); QObject::connect(blueMetricComboBox, SIGNAL(itemSelected(int)), this, SLOT(slotBlueMetricSelected(int))); metricSelectGrid->addWidget(blueMetricComboBox, BLUE_ROW, METRIC_COLUMN, Qt::AlignLeft); blueMetricNegMaxLineEdit = new QLineEdit; metricSelectGrid->addWidget(blueMetricNegMaxLineEdit, BLUE_ROW, NEG_MAX_COLUMN, Qt::AlignLeft); blueMetricPosMaxLineEdit = new QLineEdit; metricSelectGrid->addWidget(blueMetricPosMaxLineEdit, BLUE_ROW, POS_MAX_COLUMN, Qt::AlignLeft); // // Initialize metrics to NONE // redMetricComboBox->setCurrentIndex(GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NONE); greenMetricComboBox->setCurrentIndex(GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NONE); blueMetricComboBox->setCurrentIndex(GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NONE); return metricSelectGB; } /** * Called to update the dialog when rgb or metrics change. */ void GuiMetricsToRgbPaintDialog::updateDialog() { rgbColumnComboBox->updateComboBox(theMainWindow->getBrainSet()->getRgbPaintFile()); redMetricComboBox->updateComboBox(theMainWindow->getBrainSet()->getMetricFile()); greenMetricComboBox->updateComboBox(theMainWindow->getBrainSet()->getMetricFile()); blueMetricComboBox->updateComboBox(theMainWindow->getBrainSet()->getMetricFile()); redThresholdComboBox->updateComboBox(theMainWindow->getBrainSet()->getMetricFile()); greenThresholdComboBox->updateComboBox(theMainWindow->getBrainSet()->getMetricFile()); blueThresholdComboBox->updateComboBox(theMainWindow->getBrainSet()->getMetricFile()); if (inhibitUpdate == false) { slotRgbColumnSelected(rgbColumnComboBox->currentIndex()); slotRedMetricSelected(redMetricComboBox->currentIndex()); slotGreenMetricSelected(greenMetricComboBox->currentIndex()); slotBlueMetricSelected(blueMetricComboBox->currentIndex()); slotRedThresholdSelected(redThresholdComboBox->currentIndex()); slotGreenThresholdSelected(greenThresholdComboBox->currentIndex()); slotBlueThresholdSelected(blueThresholdComboBox->currentIndex()); } } void GuiMetricsToRgbPaintDialog::slotRgbColumnSelected(int column) { if (column >= 0) { RgbPaintFile* rpf = theMainWindow->getBrainSet()->getRgbPaintFile(); columnNameLineEdit->setText(rpf->getColumnName(column)); columnCommentLineEdit->setText(rpf->getColumnComment(column)); } else { columnNameLineEdit->setText("New Column Name"); columnCommentLineEdit->setText("Comment"); } } /** * */ void GuiMetricsToRgbPaintDialog::loadMetricMinMaxLineEdits(const int metricColumn, QLineEdit* minLineEdit, QLineEdit* maxLineEdit) { float minValue = 0.0; float maxValue = 0.0; if (metricColumn >= 0) { MetricFile* mf = theMainWindow->getBrainSet()->getMetricFile(); mf->getDataColumnMinMax(metricColumn, minValue, maxValue); } minLineEdit->setText(QString::number(minValue, 'f', 6)); maxLineEdit->setText(QString::number(maxValue, 'f', 6)); } /** * Slot called when red metric is selected. */ void GuiMetricsToRgbPaintDialog::slotRedMetricSelected(int item) { loadMetricMinMaxLineEdits(item, redMetricNegMaxLineEdit, redMetricPosMaxLineEdit); } /** * Slot called when green metric is selected. */ void GuiMetricsToRgbPaintDialog::slotGreenMetricSelected(int item) { loadMetricMinMaxLineEdits(item, greenMetricNegMaxLineEdit, greenMetricPosMaxLineEdit); } /** * Slot called when blue metric is selected. */ void GuiMetricsToRgbPaintDialog::slotBlueMetricSelected(int item) { loadMetricMinMaxLineEdits(item, blueMetricNegMaxLineEdit, blueMetricPosMaxLineEdit); } /** * Slot called when red threshold is selected. */ void GuiMetricsToRgbPaintDialog::slotRedThresholdSelected(int /*item*/) { //loadMetricMinMaxLineEdits(item, redThresholdNegLineEdit, redThresholdPosLineEdit); } /** * Slot called when green threshold is selected. */ void GuiMetricsToRgbPaintDialog::slotGreenThresholdSelected(int /*item*/) { //loadMetricMinMaxLineEdits(item, greenThresholdNegLineEdit, greenThresholdPosLineEdit); } /** * Slot called when blue threshold is selected. */ void GuiMetricsToRgbPaintDialog::slotBlueThresholdSelected(int /*item*/) { //loadMetricMinMaxLineEdits(item, blueThresholdNegLineEdit, blueThresholdPosLineEdit); } /** * Called when apply button is pressed. */ void GuiMetricsToRgbPaintDialog::slotApplyButton() { MetricsToRgbPaintConverter converter; const int rgbColumn = rgbColumnComboBox->currentIndex(); const QString columnComment(columnCommentLineEdit->text()); const QString columnName(columnNameLineEdit->text()); const int redMetric = redMetricComboBox->currentIndex(); const int greenMetric = greenMetricComboBox->currentIndex(); const int blueMetric = blueMetricComboBox->currentIndex(); const int redThresh = redThresholdComboBox->currentIndex(); const int greenThresh = greenThresholdComboBox->currentIndex(); const int blueThresh = blueThresholdComboBox->currentIndex(); const float redMetricNegMax = QString(redMetricNegMaxLineEdit->text()).toFloat(); const float greenMetricNegMax = QString(greenMetricNegMaxLineEdit->text()).toFloat(); const float blueMetricNegMax = QString(blueMetricNegMaxLineEdit->text()).toFloat(); const float redMetricPosMax = QString(redMetricPosMaxLineEdit->text()).toFloat(); const float greenMetricPosMax = QString(greenMetricPosMaxLineEdit->text()).toFloat(); const float blueMetricPosMax = QString(blueMetricPosMaxLineEdit->text()).toFloat(); const float redThreshNeg = QString(redThresholdNegLineEdit->text()).toFloat(); const float greenThreshNeg = QString(greenThresholdNegLineEdit->text()).toFloat(); const float blueThreshNeg = QString(blueThresholdNegLineEdit->text()).toFloat(); const float redThreshPos = QString(redThresholdPosLineEdit->text()).toFloat(); const float greenThreshPos = QString(greenThresholdPosLineEdit->text()).toFloat(); const float blueThreshPos = QString(blueThresholdPosLineEdit->text()).toFloat(); converter.setRgbPaintInfo(rgbColumn, columnName, columnComment); converter.setRedMetric(redMetric, redMetricNegMax, redMetricPosMax); converter.setGreenMetric(greenMetric, greenMetricNegMax, greenMetricPosMax); converter.setBlueMetric(blueMetric, blueMetricNegMax, blueMetricPosMax); converter.setRedThresh(redThresh, redThreshNeg, redThreshPos); converter.setGreenThresh(greenThresh, greenThreshNeg, greenThreshPos); converter.setBlueThresh(blueThresh, blueThreshNeg, blueThreshPos); QString errorMessage; QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); if (converter.convert(theMainWindow->getBrainSet()->getMetricFile(), theMainWindow->getBrainSet()->getRgbPaintFile(), errorMessage)) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "Error", errorMessage); return; } inhibitUpdate = true; GuiFilesModified fm; fm.setRgbPaintModified(); theMainWindow->fileModificationUpdate(fm); inhibitUpdate = false; if (rgbColumn < 0) { // // Reset to newest rgb column // rgbColumnComboBox->setCurrentIndex(theMainWindow->getBrainSet()->getRgbPaintFile()->getNumberOfColumns() - 1); slotRgbColumnSelected(theMainWindow->getBrainSet()->getRgbPaintFile()->getNumberOfColumns() - 1); } GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); } caret-5.6.4~dfsg.1.orig/caret/GuiMetricModificationDialog.h0000664000175000017500000001400611572067322023367 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_METRIC_MODIFICATION_DIALOG_H__ #define __GUI_METRIC_MODIFICATION_DIALOG_H__ #include "WuQDialog.h" class QComboBox; class QGroupBox; class QLineEdit; class QRadioButton; class QSpinBox; class QTabWidget; class WuQWidgetGroup; class GuiBrainModelSelectionComboBox; class GuiNodeAttributeColumnSelectionComboBox; class MetricFile; class QDoubleSpinBox; /// dialog for modifying a metric column class GuiMetricModificationDialog : public WuQDialog { Q_OBJECT public: /// mode for working with metric or surface shape enum FILE_TYPE_MODE { FILE_TYPE_MODE_METRIC, FILE_TYPE_MODE_SURFACE_SHAPE }; /// constructor GuiMetricModificationDialog(QWidget* parent, const FILE_TYPE_MODE fileTypeModeIn); /// destructor ~GuiMetricModificationDialog(); /// update the dialog void updateDialog(); private slots: /// called when Apply button is pressed void slotApplyButton(); /// called when help button is pressed void slotHelpButton(); /// called when input metric column is changed void slotInputMetricColumnComboBox(); /// called when output metric column is changed void slotOutputMetricColumnComboBox(); /// Called when a smoothing algorithm is selected. void slotSmoothingAlgorithmComboBox(int item); private: /// type of file to operate upon FILE_TYPE_MODE fileTypeMode; /// get the data file since MetricFile* getNodeDataFile(); /// create the surface part of the dialog QWidget* createSurfacePartOfDialog(); /// create the metric column part of the dialog QWidget* createMetricColumnPartOfDialog(); /// create the smoothing part of the dialog QWidget* createSmoothingPartOfDialog(); /// create the clustering part of the dialog QWidget* createClusteringPartOfDialog(); /// smoothing iterations spin box QSpinBox* iterationsSpinBox; /// surface selection combo box GuiBrainModelSelectionComboBox* surfaceSelectionComboBox; /// input metric column selection combo box GuiNodeAttributeColumnSelectionComboBox* inputMetricColumnComboBox; /// output metric column selection combo box GuiNodeAttributeColumnSelectionComboBox* outputMetricColumnComboBox; /// smoothing strength float spin box QDoubleSpinBox* strengthDoubleSpinBox; /// strength widget groupt WuQWidgetGroup* strengthWidgetGroup; /// output metric column name QLineEdit* outputMetricNameLineEdit; /// smoothing algorithm combo box QComboBox* smoothingAlgorithmComboBox; /// the modification type tab QTabWidget* modificationTypeTab; /// smoothing panel QWidget* smoothingWidget; /// gaussian spherical surface group box QGroupBox* gaussSurfaceGroupBox; /// clustering panel QWidget* clusteringWidget; /// cluster size any radio button QRadioButton* clusterSizeAnyRadioButton; /// cluster size number of nodes radio button QRadioButton* clusterSizeNumberOfNodesRadioButton; /// cluster size surface area radio button QRadioButton* clusterSizeMinimumSurfaceAreaRadioButton; /// cluster size minimum number of nodes QLineEdit* clusterSizeNumberOfNodesLineEdit; /// cluster size surface area QLineEdit* clusterSizeSurfaceAreaLineEdit; /// cluster pos maximum threshold line edit QLineEdit* clusterThresholdPosMaxLineEdit; /// cluster pos minimum threshold line edit QLineEdit* clusterThresholdPosMinLineEdit; /// cluster neg maximum threshold line edit QLineEdit* clusterThresholdNegMaxLineEdit; /// cluster neg minimum threshold line edit QLineEdit* clusterThresholdNegMinLineEdit; /// gaussian smoothing parameters grid QGroupBox* gaussSmoothParametersGroupBox; /// gaussian smoothing norm above cutoff QDoubleSpinBox* gaussSmoothNormAboveDoubleSpinBox; /// gaussian smoothing norm below cutoff QDoubleSpinBox* gaussSmoothNormBelowDoubleSpinBox; /// gaussian smoothing tangent cutoff QDoubleSpinBox* gaussSmoothTangentDoubleSpinBox; /// gaussian smoothing sigma norm QDoubleSpinBox* gaussSmoothSigmaNormDoubleSpinBox; /// gaussian smoothing sigma tang QDoubleSpinBox* gaussSmoothSigmaTangDoubleSpinBox; /// gaussian spherical surface combo box GuiBrainModelSelectionComboBox* gaussSphericalSurfaceComboBox; /// geodesic gaussian parameters group box QGroupBox* geodesicGaussianParametersGroupBox; /// geodesic gaussian sigma QDoubleSpinBox* geodesicGaussianSigmaDoubleSpinBox; /// full width half maximum group box QGroupBox* fullWidthHalfMaximumGroupBox; /// full width half maximum double spin box QDoubleSpinBox* fullWidthHalfMaximumDoubleSpinBox; }; #endif // __GUI_METRIC_MODIFICATION_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiMetricModificationDialog.cxx0000664000175000017500000011042111572067322023740 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "BrainModelSurface.h" #include "BrainModelSurfaceMetricClustering.h" #include "BrainModelSurfaceMetricSmoothing.h" #include "BrainSet.h" #include "GaussianComputation.h" #include "GuiBrainModelOpenGL.h" #include "GuiFilesModified.h" #include "GuiMetricModificationDialog.h" #include "GuiBrainModelSelectionComboBox.h" #include "GuiMainWindow.h" #include "GuiNodeAttributeColumnSelectionComboBox.h" #include "MetricFile.h" #include #include "QtUtilities.h" #include "WuQWidgetGroup.h" #include "SurfaceShapeFile.h" #include "global_variables.h" /** * Constructor. */ GuiMetricModificationDialog::GuiMetricModificationDialog(QWidget* parent, const FILE_TYPE_MODE fileTypeModeIn) : WuQDialog(parent) { fileTypeMode = fileTypeModeIn; switch (fileTypeMode) { case FILE_TYPE_MODE_METRIC: setWindowTitle("Metric Modification"); break; case FILE_TYPE_MODE_SURFACE_SHAPE: setWindowTitle("Surface Shape Modification"); break; } // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // Create the surface part of the dialog // QWidget* surfaceWidget = createSurfacePartOfDialog(); dialogLayout->addWidget(surfaceWidget); // // Create the metric column part of the dialog // QWidget* metricColumnWidget = createMetricColumnPartOfDialog(); dialogLayout->addWidget(metricColumnWidget); // // Create the tab widget for the different modifications // modificationTypeTab = new QTabWidget(this); dialogLayout->addWidget(modificationTypeTab); // // Create the clustering part of the dialog // modificationTypeTab->addTab(createClusteringPartOfDialog(), "Clustering"); // // Create the smoothing part of the dialog // modificationTypeTab->addTab(createSmoothingPartOfDialog(), "Smoothing"); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); dialogLayout->addLayout(buttonsLayout); // // Apply button // QPushButton* applyButton = new QPushButton("Apply"); applyButton->setAutoDefault(false); buttonsLayout->addWidget(applyButton); QObject::connect(applyButton, SIGNAL(clicked()), this, SLOT(slotApplyButton())); // // Close button // QPushButton* closeButton = new QPushButton("Close"); closeButton->setAutoDefault(false); buttonsLayout->addWidget(closeButton); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); // // Help button // QPushButton* helpButton = new QPushButton("Help"); helpButton->setAutoDefault(false); buttonsLayout->addWidget(helpButton); QObject::connect(helpButton, SIGNAL(clicked()), this, SLOT(slotHelpButton())); QtUtilities::makeButtonsSameSize(applyButton, closeButton, helpButton); // // Default to smoothing // modificationTypeTab->setCurrentIndex(modificationTypeTab->indexOf(smoothingWidget)); slotInputMetricColumnComboBox(); updateDialog(); } /** * destructor. */ GuiMetricModificationDialog::~GuiMetricModificationDialog() { } /** * called when Apply button is pressed. */ void GuiMetricModificationDialog::slotApplyButton() { MetricFile* mf = getNodeDataFile(); if (mf == NULL) { QMessageBox::critical(this, "ERROR", "PROGRAM ERROR: metric/shape file invalid (NULL)."); return; } if (mf->getNumberOfColumns() <= 0) { QMessageBox::critical(this, "ERROR", "The file is empty."); return; } BrainModelSurface* bms = surfaceSelectionComboBox->getSelectedBrainModelSurface(); if (bms == NULL) { QMessageBox::critical(this, "ERROR", "No surface is selected."); return; } const int inputColumn = inputMetricColumnComboBox->currentIndex(); int outputColumn = outputMetricColumnComboBox->currentIndex(); if (outputColumn == GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NEW) { outputColumn = -1; } const QString columnName = outputMetricNameLineEdit->text(); if (outputColumn < 0) { if (columnName.isEmpty()) { if (inputColumn != GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_ALL) { QMessageBox::critical(this, "ERROR", "Enter an output column name."); return; } } } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); QString talkingMessage; // // Create a coordinate file that contains the node normals // const int numNodes = bms->getNumberOfNodes(); CoordinateFile nodeNormals; nodeNormals.setNumberOfCoordinates(numNodes); for (int m = 0; m < numNodes; m++) { nodeNormals.setCoordinate(m, bms->getNormal(m)); } if (modificationTypeTab->currentWidget() == smoothingWidget) { const BrainModelSurfaceMetricSmoothing::SMOOTH_ALGORITHM algorithm = static_cast( smoothingAlgorithmComboBox->currentIndex()); if (inputColumn == GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_ALL) { // // // With all selection all columns are smoothed and replaced // const int numColumns = mf->getNumberOfColumns(); for (int i = 0; i < numColumns; i++) { BrainModelSurfaceMetricSmoothing bmsms( theMainWindow->getBrainSet(), bms, gaussSphericalSurfaceComboBox->getSelectedBrainModelSurface(), mf, algorithm, i, i, mf->getColumnName(i), strengthDoubleSpinBox->value(), iterationsSpinBox->value(), fullWidthHalfMaximumDoubleSpinBox->value(), gaussSmoothNormBelowDoubleSpinBox->value(), gaussSmoothNormAboveDoubleSpinBox->value(), gaussSmoothSigmaNormDoubleSpinBox->value(), gaussSmoothSigmaTangDoubleSpinBox->value(), gaussSmoothTangentDoubleSpinBox->value(), geodesicGaussianSigmaDoubleSpinBox->value()); try { //QTime timer; //timer.start(); bmsms.execute(); //std::cout << "Metric smoothing time: " // << (timer.elapsed() / 1000.0) // << std::endl; } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); return; } } } else { BrainModelSurfaceMetricSmoothing bmsms( theMainWindow->getBrainSet(), bms, gaussSphericalSurfaceComboBox->getSelectedBrainModelSurface(), mf, algorithm, inputColumn, outputColumn, columnName, strengthDoubleSpinBox->value(), iterationsSpinBox->value(), fullWidthHalfMaximumDoubleSpinBox->value(), gaussSmoothNormBelowDoubleSpinBox->value(), gaussSmoothNormAboveDoubleSpinBox->value(), gaussSmoothSigmaNormDoubleSpinBox->value(), gaussSmoothSigmaTangDoubleSpinBox->value(), gaussSmoothTangentDoubleSpinBox->value(), geodesicGaussianSigmaDoubleSpinBox->value()); try { QTime timer; timer.start(); bmsms.execute(); std::cout << "Metric smoothing time: " << (timer.elapsed() / 1000.0) << std::endl; switch (algorithm) { case BrainModelSurfaceMetricSmoothing::SMOOTH_ALGORITHM_AVERAGE_NEIGHBORS: break; case BrainModelSurfaceMetricSmoothing::SMOOTH_ALGORITHM_DILATE: break; case BrainModelSurfaceMetricSmoothing::SMOOTH_ALGORITHM_FULL_WIDTH_HALF_MAXIMUM: QApplication::restoreOverrideCursor(); QMessageBox::information(this, "INFO", bmsms.getFullWidthHalfMaximumSmoothingResultsDescription()); break; case BrainModelSurfaceMetricSmoothing::SMOOTH_ALGORITHM_SURFACE_NORMAL_GAUSSIAN: break; case BrainModelSurfaceMetricSmoothing::SMOOTH_ALGORITHM_GEODESIC_GAUSSIAN: break; case BrainModelSurfaceMetricSmoothing::SMOOTH_ALGORITHM_WEIGHTED_AVERAGE_NEIGHBORS: break; case BrainModelSurfaceMetricSmoothing::SMOOTH_ALGORITHM_NONE: break; } } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); return; } } talkingMessage = "Smoothing has completed."; } else { if (inputColumn == GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_ALL) { QApplication::restoreOverrideCursor(); QMessageBox::warning(this, "Error", "Clustering on all metric columns not supported at this time."); return; } // // Get the selected algorithm // BrainModelSurfaceMetricClustering::CLUSTER_ALGORITHM algorithm = BrainModelSurfaceMetricClustering::CLUSTER_ALGORITHM_NONE; if (clusterSizeAnyRadioButton->isChecked()) { algorithm = BrainModelSurfaceMetricClustering::CLUSTER_ALGORITHM_ANY_SIZE; } else if (clusterSizeNumberOfNodesRadioButton->isChecked()) { algorithm = BrainModelSurfaceMetricClustering::CLUSTER_ALGORITHM_MINIMUM_NUMBER_OF_NODES; } else if (clusterSizeMinimumSurfaceAreaRadioButton->isChecked()) { algorithm = BrainModelSurfaceMetricClustering::CLUSTER_ALGORITHM_MINIMUM_SURFACE_AREA; } else { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "Clustering Error", "A clustering minimum size algorithm must be selected."); } // // Get the other parameters // const int minNumNodes = clusterSizeNumberOfNodesLineEdit->text().toInt(); const float minSurfaceArea = clusterSizeSurfaceAreaLineEdit->text().toFloat(); const float clusterNegMinThresh = clusterThresholdNegMinLineEdit->text().toFloat(); const float clusterNegMaxThresh = clusterThresholdNegMaxLineEdit->text().toFloat(); const float clusterPosMinThresh = clusterThresholdPosMinLineEdit->text().toFloat(); const float clusterPosMaxThresh = clusterThresholdPosMaxLineEdit->text().toFloat(); if (inputColumn == GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_ALL) { // // With all selection all columns are smoothed and replaced // const int numColumns = mf->getNumberOfColumns(); for (int i = 0; i < numColumns; i++) { // // Perform clustering // BrainModelSurfaceMetricClustering bmsmc(theMainWindow->getBrainSet(), bms, mf, algorithm, i, i, mf->getColumnName(i), minNumNodes, minSurfaceArea, clusterNegMinThresh, clusterNegMaxThresh, clusterPosMinThresh, clusterPosMaxThresh, true); try { bmsmc.execute(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "Clustering Error", e.whatQString()); return; } } } else { // // Perform clustering // BrainModelSurfaceMetricClustering bmsmc(theMainWindow->getBrainSet(), bms, mf, algorithm, inputColumn, outputColumn, columnName, minNumNodes, minSurfaceArea, clusterNegMinThresh, clusterNegMaxThresh, clusterPosMinThresh, clusterPosMaxThresh, true); try { bmsmc.execute(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "Clustering Error", e.whatQString()); return; } } talkingMessage = "Clustering has completed."; } // // Metric or shape file probably has changed // switch (fileTypeMode) { case FILE_TYPE_MODE_METRIC: { GuiFilesModified fm; fm.setMetricModified(); theMainWindow->fileModificationUpdate(fm); } break; case FILE_TYPE_MODE_SURFACE_SHAPE: { GuiFilesModified fm; fm.setSurfaceShapeModified(); theMainWindow->fileModificationUpdate(fm); } break; } // // Update output column // if (outputColumn < 0) { outputMetricColumnComboBox->setCurrentIndex(mf->getNumberOfColumns() - 1); slotOutputMetricColumnComboBox(); } GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); theMainWindow->speakText(talkingMessage, false); } /** * called when help button is pressed. */ void GuiMetricModificationDialog::slotHelpButton() { theMainWindow->showHelpViewerDialog("dialogs/metric_smoothing_dialog.html");} /** * create the surface part of the dialog. */ QWidget* GuiMetricModificationDialog::createSurfacePartOfDialog() { surfaceSelectionComboBox = new GuiBrainModelSelectionComboBox( false, true, false, "", 0); QGroupBox* surfaceGroup = new QGroupBox("Surface"); QVBoxLayout* surfaceLayout = new QVBoxLayout(surfaceGroup); surfaceLayout->addWidget(surfaceSelectionComboBox); return surfaceGroup; } /** * create the metric column part of the dialog. */ QWidget* GuiMetricModificationDialog::createMetricColumnPartOfDialog() { QString title; GUI_NODE_FILE_TYPE nodeFileType = GUI_NODE_FILE_TYPE_NONE; switch (fileTypeMode) { case FILE_TYPE_MODE_METRIC: title = "Metric Column"; nodeFileType = GUI_NODE_FILE_TYPE_METRIC; break; case FILE_TYPE_MODE_SURFACE_SHAPE: title = "Surface Shape Column"; nodeFileType = GUI_NODE_FILE_TYPE_SURFACE_SHAPE; break; } // // input metric column // QLabel* inputLabel = new QLabel("Input"); inputMetricColumnComboBox = new GuiNodeAttributeColumnSelectionComboBox( nodeFileType, false, false, true); QObject::connect(inputMetricColumnComboBox, SIGNAL(itemSelected(int)), this, SLOT(slotInputMetricColumnComboBox())); // // input metric column // QLabel* outputLabel = new QLabel("Output"); outputMetricColumnComboBox = new GuiNodeAttributeColumnSelectionComboBox( nodeFileType, true, false, false); QObject::connect(outputMetricColumnComboBox, SIGNAL(itemSelected(int)), this, SLOT(slotOutputMetricColumnComboBox())); outputMetricNameLineEdit = new QLineEdit; // // Group box and arrange the widgets // QGroupBox* columnGroup = new QGroupBox(title); QGridLayout* columnLayout = new QGridLayout(columnGroup); columnLayout->addWidget(inputLabel, 0, 0); columnLayout->addWidget(inputMetricColumnComboBox, 0, 1); columnLayout->addWidget(outputLabel, 1, 0); columnLayout->addWidget(outputMetricColumnComboBox, 1, 1); columnLayout->addWidget(outputMetricNameLineEdit, 1, 2); return columnGroup; } /** * Called when input metric column selected. */ void GuiMetricModificationDialog::slotInputMetricColumnComboBox() { const bool enableOutputs = (inputMetricColumnComboBox->currentIndex() != GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_ALL); outputMetricColumnComboBox->setEnabled(enableOutputs); outputMetricNameLineEdit->setEnabled(enableOutputs); outputMetricColumnComboBox->setCurrentIndex(GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NEW); slotOutputMetricColumnComboBox(); } /** * Called when output metric column selected. */ void GuiMetricModificationDialog::slotOutputMetricColumnComboBox() { MetricFile* mf = NULL; switch (fileTypeMode) { case FILE_TYPE_MODE_METRIC: mf = theMainWindow->getBrainSet()->getMetricFile(); break; case FILE_TYPE_MODE_SURFACE_SHAPE: mf = theMainWindow->getBrainSet()->getSurfaceShapeFile(); break; } const int metricColumn = outputMetricColumnComboBox->currentIndex(); if ((metricColumn >= 0) && (metricColumn < mf->getNumberOfColumns())) { outputMetricNameLineEdit->setText(mf->getColumnName(metricColumn)); } else { outputMetricNameLineEdit->setText("New Column Name"); } } /** * create the smoothing part of the dialog. */ QWidget* GuiMetricModificationDialog::createClusteringPartOfDialog() { // // Minimum size Any // clusterSizeAnyRadioButton = new QRadioButton("Any Size"); // // Minimum number of nodes // clusterSizeNumberOfNodesRadioButton = new QRadioButton("Minimum Number of Nodes"); clusterSizeNumberOfNodesLineEdit = new QLineEdit; clusterSizeNumberOfNodesLineEdit->setText("100"); // // Minimum surface area // clusterSizeMinimumSurfaceAreaRadioButton = new QRadioButton("Minimum Surface Area (mm)"); clusterSizeSurfaceAreaLineEdit = new QLineEdit; clusterSizeSurfaceAreaLineEdit->setText("100"); // // Box for cluster minimum size // QGroupBox* clusterSizeGroupBox = new QGroupBox("Cluster Minimum Size"); QGridLayout* clusterSizeLayout = new QGridLayout(clusterSizeGroupBox); clusterSizeLayout->addWidget(clusterSizeAnyRadioButton, 0, 0); clusterSizeLayout->addWidget(clusterSizeNumberOfNodesRadioButton, 1, 0); clusterSizeLayout->addWidget(clusterSizeNumberOfNodesLineEdit, 1, 1); clusterSizeLayout->addWidget(clusterSizeMinimumSurfaceAreaRadioButton, 2, 0); clusterSizeLayout->addWidget(clusterSizeSurfaceAreaLineEdit, 2, 1); // // Button group to keep cluster size radio buttons mutually exclusive // QButtonGroup* clusterSizeButtonGroup = new QButtonGroup(this); clusterSizeButtonGroup->addButton(clusterSizeAnyRadioButton, 0); clusterSizeButtonGroup->addButton(clusterSizeNumberOfNodesRadioButton, 1); clusterSizeButtonGroup->addButton(clusterSizeMinimumSurfaceAreaRadioButton, 2); // // positive minimum and maximum values // QLabel* posMinLabel = new QLabel("Positive Minimum"); clusterThresholdPosMinLineEdit = new QLineEdit; clusterThresholdPosMinLineEdit->setText("0.00001"); QLabel* posMaxLabel = new QLabel("Positive Maximum"); clusterThresholdPosMaxLineEdit = new QLineEdit; clusterThresholdPosMaxLineEdit->setText("1000000.0"); // // negative minimum and maximum values // QLabel* negMinLabel = new QLabel("Negative Minimum"); clusterThresholdNegMinLineEdit = new QLineEdit; clusterThresholdNegMinLineEdit->setText("-0.00001"); QLabel* negMaxLabel = new QLabel("Negative Maximum"); clusterThresholdNegMaxLineEdit = new QLineEdit; clusterThresholdNegMaxLineEdit->setText("-1000000.0"); // // Box/Layout for cluster value threshold // QGroupBox* clusterThresholdGroupBox = new QGroupBox("Cluster Value Threshold"); QGridLayout* clusterThresholdLayout = new QGridLayout(clusterThresholdGroupBox); clusterThresholdLayout->addWidget(posMinLabel); clusterThresholdLayout->addWidget(clusterThresholdPosMinLineEdit); clusterThresholdLayout->addWidget(posMaxLabel); clusterThresholdLayout->addWidget(clusterThresholdPosMaxLineEdit); clusterThresholdLayout->addWidget(negMinLabel); clusterThresholdLayout->addWidget(clusterThresholdNegMinLineEdit); clusterThresholdLayout->addWidget(negMaxLabel); clusterThresholdLayout->addWidget(clusterThresholdNegMaxLineEdit); clusteringWidget = new QWidget; QVBoxLayout* clusteringLayout = new QVBoxLayout(clusteringWidget); clusteringLayout->addWidget(clusterSizeGroupBox); clusteringLayout->addWidget(clusterThresholdGroupBox); return clusteringWidget; } /** * Called when an algorithm is selected. */ void GuiMetricModificationDialog::slotSmoothingAlgorithmComboBox(int item) { bool enableFwhmParams = false; bool enableGaussParams = false; bool enableGeodesicGaussParams = false; bool enableStrengthParams = true; switch (static_cast(item)) { case BrainModelSurfaceMetricSmoothing::SMOOTH_ALGORITHM_AVERAGE_NEIGHBORS: break; case BrainModelSurfaceMetricSmoothing::SMOOTH_ALGORITHM_DILATE: enableStrengthParams = false; break; case BrainModelSurfaceMetricSmoothing::SMOOTH_ALGORITHM_FULL_WIDTH_HALF_MAXIMUM: enableFwhmParams = true; enableStrengthParams = false; break; case BrainModelSurfaceMetricSmoothing::SMOOTH_ALGORITHM_SURFACE_NORMAL_GAUSSIAN: enableGaussParams = true; break; case BrainModelSurfaceMetricSmoothing::SMOOTH_ALGORITHM_GEODESIC_GAUSSIAN: enableGeodesicGaussParams = true; enableStrengthParams = false; break; case BrainModelSurfaceMetricSmoothing::SMOOTH_ALGORITHM_WEIGHTED_AVERAGE_NEIGHBORS: break; case BrainModelSurfaceMetricSmoothing::SMOOTH_ALGORITHM_NONE: break; } fullWidthHalfMaximumGroupBox->setEnabled(enableFwhmParams); gaussSmoothParametersGroupBox->setEnabled(enableGaussParams); geodesicGaussianParametersGroupBox->setEnabled(enableGeodesicGaussParams); gaussSurfaceGroupBox->setEnabled(enableGaussParams); strengthWidgetGroup->setEnabled(enableStrengthParams); } /** * create the smoothing part of the dialog. */ QWidget* GuiMetricModificationDialog::createSmoothingPartOfDialog() { // // Gaussian spherical surface combo box // gaussSphericalSurfaceComboBox = new GuiBrainModelSelectionComboBox( false, true, false, "", 0, "surfaceSelectionComboBox"); for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfBrainModels(); i++) { const BrainModelSurface* bms = theMainWindow->getBrainSet()->getBrainModelSurface(i); if (bms != NULL) { if (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_SPHERICAL) { gaussSphericalSurfaceComboBox->setSelectedBrainModel(bms); break; } } } // // Gaussian spherical surface group box // gaussSurfaceGroupBox = new QGroupBox("Gaussian Spherical Surface"); QHBoxLayout* gaussSurfaceLayout = new QHBoxLayout(gaussSurfaceGroupBox); gaussSurfaceLayout->addWidget(gaussSphericalSurfaceComboBox); gaussSurfaceGroupBox->setFixedHeight(gaussSurfaceGroupBox->sizeHint().height()); // // Algorithm // QLabel* algorithmLabel = new QLabel("Algorithm"); smoothingAlgorithmComboBox = new QComboBox; smoothingAlgorithmComboBox->insertItem(BrainModelSurfaceMetricSmoothing::SMOOTH_ALGORITHM_AVERAGE_NEIGHBORS, "Average Neighbors"); smoothingAlgorithmComboBox->insertItem(BrainModelSurfaceMetricSmoothing::SMOOTH_ALGORITHM_DILATE, "Dilation"); smoothingAlgorithmComboBox->insertItem(BrainModelSurfaceMetricSmoothing::SMOOTH_ALGORITHM_FULL_WIDTH_HALF_MAXIMUM, "Full Width Half Maximum"); smoothingAlgorithmComboBox->insertItem(BrainModelSurfaceMetricSmoothing::SMOOTH_ALGORITHM_SURFACE_NORMAL_GAUSSIAN, "Gaussian"); smoothingAlgorithmComboBox->insertItem(BrainModelSurfaceMetricSmoothing::SMOOTH_ALGORITHM_GEODESIC_GAUSSIAN, "Geodesic Gaussian"); smoothingAlgorithmComboBox->insertItem(BrainModelSurfaceMetricSmoothing::SMOOTH_ALGORITHM_WEIGHTED_AVERAGE_NEIGHBORS, "Weighted Average Neighbors"); QObject::connect(smoothingAlgorithmComboBox, SIGNAL(activated(int)), this, SLOT(slotSmoothingAlgorithmComboBox(int))); // // Smoothing iterations // QLabel* iterationsLabel = new QLabel("Iterations"); iterationsSpinBox = new QSpinBox; iterationsSpinBox->setMinimum(1); iterationsSpinBox->setMaximum(100000); iterationsSpinBox->setSingleStep(5); iterationsSpinBox->setValue(10); // // Smoothing strength // QLabel* strengthLabel = new QLabel("Strength"); strengthDoubleSpinBox = new QDoubleSpinBox; strengthDoubleSpinBox->setMinimum(0.0); strengthDoubleSpinBox->setMaximum(1.0); strengthDoubleSpinBox->setSingleStep(0.1); strengthDoubleSpinBox->setDecimals(2); strengthDoubleSpinBox->setValue(1.0); // // Widget group for strength // strengthWidgetGroup = new WuQWidgetGroup(this); strengthWidgetGroup->addWidget(strengthLabel); strengthWidgetGroup->addWidget(strengthDoubleSpinBox); // // Widget/Layout for Smoothing Parameters // QGroupBox* smoothingGroupBox = new QGroupBox("Smoothing Parameters"); QGridLayout* smoothingGroupLayout = new QGridLayout(smoothingGroupBox); smoothingGroupLayout->addWidget(algorithmLabel, 0, 0); smoothingGroupLayout->addWidget(smoothingAlgorithmComboBox, 0, 1); smoothingGroupLayout->addWidget(iterationsLabel, 1, 0); smoothingGroupLayout->addWidget(iterationsSpinBox, 1, 1); smoothingGroupLayout->addWidget(strengthLabel, 2, 0); smoothingGroupLayout->addWidget(strengthDoubleSpinBox, 2, 1); smoothingGroupBox->setFixedSize(smoothingGroupBox->sizeHint()); // // Get the default values // float normAbove, normBelow, tang, sigmaNorm, sigmaTang; GaussianComputation::getDefaultParameters(normBelow, normAbove, sigmaNorm, sigmaTang, tang); // // label and float spin box for // QLabel* sigmaNormalLabel = new QLabel("Sigma Normal"); gaussSmoothSigmaNormDoubleSpinBox = new QDoubleSpinBox; gaussSmoothSigmaNormDoubleSpinBox->setMinimum(0.0); gaussSmoothSigmaNormDoubleSpinBox->setMaximum(10000.0); gaussSmoothSigmaNormDoubleSpinBox->setSingleStep(1.0); gaussSmoothSigmaNormDoubleSpinBox->setDecimals(2); gaussSmoothSigmaNormDoubleSpinBox->setValue(sigmaNorm); gaussSmoothSigmaNormDoubleSpinBox->setToolTip( GaussianComputation::tooltipTextForSigmaNorm()); // // label and float spin box for // QLabel* sigmaTangentLabel = new QLabel("Sigma Tangent"); gaussSmoothSigmaTangDoubleSpinBox = new QDoubleSpinBox; gaussSmoothSigmaTangDoubleSpinBox->setMinimum(0.0); gaussSmoothSigmaTangDoubleSpinBox->setMaximum(10000.0); gaussSmoothSigmaTangDoubleSpinBox->setSingleStep(1.0); gaussSmoothSigmaTangDoubleSpinBox->setDecimals(2); gaussSmoothSigmaTangDoubleSpinBox->setValue(sigmaTang); gaussSmoothSigmaTangDoubleSpinBox->setToolTip( GaussianComputation::tooltipTextForSigmaTang()); // // label and float spin box for // QLabel* normBelowLabel = new QLabel("Normal Below Cutoff"); gaussSmoothNormBelowDoubleSpinBox = new QDoubleSpinBox; gaussSmoothNormBelowDoubleSpinBox->setMinimum(0.0); gaussSmoothNormBelowDoubleSpinBox->setMaximum(10000.0); gaussSmoothNormBelowDoubleSpinBox->setSingleStep(1.0); gaussSmoothNormBelowDoubleSpinBox->setDecimals(2); gaussSmoothNormBelowDoubleSpinBox->setValue(normBelow); gaussSmoothNormBelowDoubleSpinBox->setToolTip( GaussianComputation::tooltipTextForNormBelowCutoff()); // // label and float spin box for // QLabel* normAboveLabel = new QLabel("Normal Above Cutoff"); gaussSmoothNormAboveDoubleSpinBox = new QDoubleSpinBox; gaussSmoothNormAboveDoubleSpinBox->setMinimum(0.0); gaussSmoothNormAboveDoubleSpinBox->setMaximum(10000.0); gaussSmoothNormAboveDoubleSpinBox->setSingleStep(1.0); gaussSmoothNormAboveDoubleSpinBox->setDecimals(2); gaussSmoothNormAboveDoubleSpinBox->setValue(normAbove); gaussSmoothNormAboveDoubleSpinBox->setToolTip( GaussianComputation::tooltipTextForNormAboveCutoff()); // // label and float spin box for // QLabel* tangentCutoffLabel = new QLabel("Tangent Cutoff"); gaussSmoothTangentDoubleSpinBox = new QDoubleSpinBox; gaussSmoothTangentDoubleSpinBox->setMinimum(0.0); gaussSmoothTangentDoubleSpinBox->setMaximum(10000.0); gaussSmoothTangentDoubleSpinBox->setSingleStep(1.0); gaussSmoothTangentDoubleSpinBox->setDecimals(2); gaussSmoothTangentDoubleSpinBox->setValue(tang); gaussSmoothTangentDoubleSpinBox->setToolTip( GaussianComputation::tooltipTextForTangentCutoff()); // // Gaussian parameters grid // gaussSmoothParametersGroupBox = new QGroupBox("Gaussian Parameters"); QGridLayout* gaussSmoothGridLayout = new QGridLayout(gaussSmoothParametersGroupBox); gaussSmoothGridLayout->addWidget(sigmaNormalLabel, 0, 0); gaussSmoothGridLayout->addWidget(gaussSmoothSigmaNormDoubleSpinBox, 0, 1); gaussSmoothGridLayout->addWidget(sigmaTangentLabel, 1, 0); gaussSmoothGridLayout->addWidget(gaussSmoothSigmaTangDoubleSpinBox, 1, 1); gaussSmoothGridLayout->addWidget(normBelowLabel, 2, 0); gaussSmoothGridLayout->addWidget(gaussSmoothNormBelowDoubleSpinBox, 2, 1); gaussSmoothGridLayout->addWidget(normAboveLabel, 3, 0); gaussSmoothGridLayout->addWidget(gaussSmoothNormAboveDoubleSpinBox, 3, 1); gaussSmoothGridLayout->addWidget(tangentCutoffLabel, 4, 0); gaussSmoothGridLayout->addWidget(gaussSmoothTangentDoubleSpinBox, 4, 1); gaussSmoothParametersGroupBox->setFixedSize(gaussSmoothParametersGroupBox->sizeHint()); // // Full Width Half Maximum Parameters and GroupBox // QLabel* fullWidthHalfMaximumLabel = new QLabel("Desired FWHM"); fullWidthHalfMaximumDoubleSpinBox = new QDoubleSpinBox; fullWidthHalfMaximumDoubleSpinBox->setValue(8.0); fullWidthHalfMaximumGroupBox = new QGroupBox("Full Width Half Maximum Parameter"); QGridLayout* fullWidthHalfMaximumGroupLayout = new QGridLayout(fullWidthHalfMaximumGroupBox); fullWidthHalfMaximumGroupLayout->addWidget(fullWidthHalfMaximumLabel, 0, 0); fullWidthHalfMaximumGroupLayout->addWidget(fullWidthHalfMaximumDoubleSpinBox, 0, 1); fullWidthHalfMaximumGroupBox->setFixedSize(fullWidthHalfMaximumGroupBox->sizeHint()); // // Geodesic Gaussian // QLabel* geodesicGaussSigmaLabel = new QLabel("Sigma"); geodesicGaussianSigmaDoubleSpinBox = new QDoubleSpinBox; geodesicGaussianSigmaDoubleSpinBox->setValue(2.0); geodesicGaussianParametersGroupBox = new QGroupBox("Geodesic Gaussian Parameters"); QGridLayout* geodesicGaussianGroupLayout = new QGridLayout(geodesicGaussianParametersGroupBox); geodesicGaussianGroupLayout->addWidget(geodesicGaussSigmaLabel, 0, 0); geodesicGaussianGroupLayout->addWidget(geodesicGaussianSigmaDoubleSpinBox, 0, 1); geodesicGaussianParametersGroupBox->setFixedSize(geodesicGaussianParametersGroupBox->sizeHint()); // // Enable/disable gaussian parameters // slotSmoothingAlgorithmComboBox(smoothingAlgorithmComboBox->currentIndex()); // // Holds parameters // QVBoxLayout* leftColumnLayout = new QVBoxLayout; leftColumnLayout->addWidget(smoothingGroupBox); leftColumnLayout->addWidget(fullWidthHalfMaximumGroupBox); leftColumnLayout->addWidget(geodesicGaussianParametersGroupBox); QVBoxLayout* rightColumnLayout = new QVBoxLayout; rightColumnLayout->addWidget(gaussSmoothParametersGroupBox); QHBoxLayout* smoothParamsLayout = new QHBoxLayout; smoothParamsLayout->addLayout(leftColumnLayout); smoothParamsLayout->addLayout(rightColumnLayout); // // Widget/Layout for this section // smoothingWidget = new QWidget; // prevents background showing thru QVBoxLayout* smoothingLayout = new QVBoxLayout(smoothingWidget); smoothingLayout->addWidget(gaussSurfaceGroupBox); smoothingLayout->addLayout(smoothParamsLayout); return smoothingWidget; } /** * update the dialog. */ void GuiMetricModificationDialog::updateDialog() { surfaceSelectionComboBox->updateComboBox(); gaussSphericalSurfaceComboBox->updateComboBox(); inputMetricColumnComboBox->updateComboBox(); outputMetricColumnComboBox->updateComboBox(); slotOutputMetricColumnComboBox(); } /** * get the data file since. */ MetricFile* GuiMetricModificationDialog::getNodeDataFile() { BrainSet* bs = theMainWindow->getBrainSet(); MetricFile* mf = NULL; switch (fileTypeMode) { case FILE_TYPE_MODE_METRIC: mf = bs->getMetricFile(); break; case FILE_TYPE_MODE_SURFACE_SHAPE: mf = bs->getSurfaceShapeFile(); break; } return mf; } caret-5.6.4~dfsg.1.orig/caret/GuiMapStereotaxicFocusDialog.h0000664000175000017500000001231511572067322023547 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_GUI_MAP_STEREOTAXIC_FOCUS_DIALOG_H__ #define __VE_GUI_MAP_STEREOTAXIC_FOCUS_DIALOG_H__ #include "WuQDialog.h" class FociFileToPalsProjector; class GuiStudyInfoEditorWidget; class QCheckBox; class QComboBox; class QDoubleSpinBox; class QGroupBox; class QLabel; class QLineEdit; class QPushButton; class QRadioButton; class QSpinBox; class QTabWidget; class QTextEdit; class QVBoxLayout; /// Dialog for entering Foci. class GuiMapStereotaxicFocusDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiMapStereotaxicFocusDialog(QWidget* parent); /// Destructor ~GuiMapStereotaxicFocusDialog(); /// edit a focus by number void editFocus(const int focusNumber); /// update the dialog (typically called when fiducial foci file changed) void updateDialog(); private slots: /// called when apply button is pressed void applyButtonSlot(); /// load a focus into this dialog void loadFocusSlot(); /// delete a focus into this dialog void deleteFocusSlot(); /// called when the focus number is changed void editFocusNumberChanged(); /// called when focus name button pressed void nameButtonSlot(); /// called when class name button pressed void classNameButtonSlot(); /// called when a mode button is selected void slotModeButtonSelected(); /// called when cortical area button selected. void slotCorticalAreaPushButton(); /// called when Geography button selected. void slotGeographyPushButton(); /// called when Region of Interest button selected. void slotRegionOfInterestPushButton(); /// update the study number combo box. void slotUpdateStudyNumberComboBox(); /// called when study meta data button pressed void slotFocusStudyMetaDataPushButton(); private: /// create the enter foci tab page void createEnterFociTabPage(QVBoxLayout* layout); /// process the entry of study information void processFocusEntry(); /// tab widget for foci and studies QTabWidget* tabWidget; /// name line edit QLineEdit* focusNameLineEdit; /// class name line edit QLineEdit* focusClassNameLineEdit; /// X coord line edit QDoubleSpinBox* focusXCoordDoubleSpinBox; /// Y coord line edit QDoubleSpinBox* focusYCoordDoubleSpinBox; /// Z coord line edit QDoubleSpinBox* focusZCoordDoubleSpinBox; /// study meta data line edit QLineEdit* focusStudyMetaDataLineEdit; /// focus area QLineEdit* focusAreaLineEdit; /// focus geography QLineEdit* focusGeographyLineEdit; /// focus region of interest QLineEdit* focusRegionOfInterestLineEdit; /// focus size QDoubleSpinBox* focusSizeDoubleSpinBox; /// focus statistic QLineEdit* focusStatisticLineEdit; /// focus comment QTextEdit* focusCommentTextEdit; /// focus study combo box QComboBox* focusStudyComboBox; /// edit focus line edit QSpinBox* editFocusNumberSpinBox; /// new foci radio button QRadioButton* newRadioButton; /// edit foci number radio button QRadioButton* editRadioButton; /// load focus push button QPushButton* loadFocusPushButton; /// delete focus push button QPushButton* deleteFocusPushButton; /// the study info editor widget GuiStudyInfoEditorWidget* studyInfoEditorWidget; /// study space line edit QLineEdit* studySpaceLineEdit; /// enter foci page QWidget* fociPageVBox; /// project to active fiducial surface QRadioButton* projectionMainWindowFiducialRadioButton; /// project to PALS atlas surfaces QRadioButton* projectionPalsAtlasRadioButton; /// allow PALS cerebellum projection QCheckBox* projectionPalsCerebellumCheckBox; /// projector for PALS atlas FociFileToPalsProjector* palsProjector; /// automatic projection group box QGroupBox* automaticProjectionGroupBox; }; #endif // __VE_GUI_MAP_STEREOTAXIC_FOCUS_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiMapStereotaxicFocusDialog.cxx0000664000175000017500000010543311572067322024126 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "BrainSet.h" #include "CellFileProjector.h" #include "DisplaySettingsFoci.h" #include "FociColorFile.h" #include "FociFileToPalsProjector.h" #include "FociProjectionFile.h" #include "GuiBrainModelOpenGL.h" #include "GuiColorSelectionDialog.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "GuiMapStereotaxicFocusDialog.h" #include "GuiNameSelectionDialog.h" #include "GuiStudyInfoEditorWidget.h" #include "GuiStudyMetaDataLinkCreationDialog.h" #include "QtListBoxSelectionDialog.h" #include "QtUtilities.h" #include "StereotaxicSpace.h" #include "StringUtilities.h" #include "global_variables.h" static const QString noneStudyName("None"); /** * Constructor */ GuiMapStereotaxicFocusDialog::GuiMapStereotaxicFocusDialog(QWidget* parent) : WuQDialog(parent) { palsProjector = NULL; setWindowTitle("Map Stereotaxic Focus"); // // Vertical box layout of all items // QVBoxLayout* rows = new QVBoxLayout(this); rows->setMargin(5); rows->setSpacing(2); // // Tab widget for foci and studies // tabWidget = new QTabWidget; rows->addWidget(tabWidget); // // Create enter foci page // fociPageVBox = new QWidget; QVBoxLayout* fociPageLayout = new QVBoxLayout(fociPageVBox); tabWidget->addTab(fociPageVBox, "Foci"); createEnterFociTabPage(fociPageLayout); // // Create enter studies page // FociProjectionFile* fpf = theMainWindow->getBrainSet()->getFociProjectionFile(); studyInfoEditorWidget = new GuiStudyInfoEditorWidget(fpf->getPointerToStudyInfo()); studyInfoEditorWidget->hidePartitioningSchemeControls(true); tabWidget->addTab(studyInfoEditorWidget, "Studies"); // // update dialog with foci file. // updateDialog(); // // Dialog Buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; rows->addLayout(buttonsLayout); // // Apply button // QPushButton* applyButton = new QPushButton("Apply"); applyButton->setAutoDefault(false); QObject::connect(applyButton, SIGNAL(clicked()), this, SLOT(applyButtonSlot())); buttonsLayout->addWidget(applyButton); // // Close button // QPushButton* closeButton = new QPushButton("Close"); closeButton->setAutoDefault(false); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); buttonsLayout->addWidget(closeButton); QtUtilities::makeButtonsSameSize(applyButton, closeButton); // // If PALS available // if (projectionPalsAtlasRadioButton->isEnabled() == false) { // // Use active fiducial for projection // projectionMainWindowFiducialRadioButton->setChecked(true); } } /** * Destructor */ GuiMapStereotaxicFocusDialog::~GuiMapStereotaxicFocusDialog() { if (palsProjector != NULL) { delete palsProjector; } } /** * create the enter foci tab page. */ void GuiMapStereotaxicFocusDialog::createEnterFociTabPage(QVBoxLayout* fociPageLayout) { // // Radio buttons for projection surface // projectionMainWindowFiducialRadioButton = new QRadioButton("Main Window Surface"); projectionPalsAtlasRadioButton = new QRadioButton("PALS Atlas Surface in Correct Stereotaxic Space"); // // Allow projection to PALS cerebellum // projectionPalsCerebellumCheckBox = new QCheckBox("Allow Projection to Cerebellum"); projectionPalsCerebellumCheckBox->setChecked(true); QHBoxLayout* palsCerebellumLayout = new QHBoxLayout; palsCerebellumLayout->addWidget(new QLabel(" ")); palsCerebellumLayout->addWidget(projectionPalsCerebellumCheckBox); QObject::connect(projectionPalsAtlasRadioButton, SIGNAL(toggled(bool)), projectionPalsCerebellumCheckBox, SLOT(setEnabled(bool))); projectionPalsCerebellumCheckBox->setEnabled(projectionPalsAtlasRadioButton->isChecked()); // // Button group to keep radio buttons mutually exclusive // QButtonGroup* buttGroup = new QButtonGroup(this); buttGroup->addButton(projectionMainWindowFiducialRadioButton); buttGroup->addButton(projectionPalsAtlasRadioButton); // // Group box and layout // automaticProjectionGroupBox = new QGroupBox("Automatic Projection of Foci to"); automaticProjectionGroupBox->setCheckable(true); automaticProjectionGroupBox->setChecked(true); QVBoxLayout* projectionLayout = new QVBoxLayout(automaticProjectionGroupBox); projectionLayout->addWidget(projectionMainWindowFiducialRadioButton); projectionLayout->addWidget(projectionPalsAtlasRadioButton); projectionLayout->addLayout(palsCerebellumLayout); fociPageLayout->addWidget(automaticProjectionGroupBox); // // Vertical Group Box for New/Edit controls // QGroupBox* modeGroup = new QGroupBox("Focus Mode"); fociPageLayout->addWidget(modeGroup); QGridLayout* modeGrid = new QGridLayout(modeGroup); modeGrid->setSpacing(3); // // Button Group for add & edit buttons // QButtonGroup* modeButtonGroup = new QButtonGroup(this); QObject::connect(modeButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotModeButtonSelected())); // // Add radio button // newRadioButton = new QRadioButton("Add"); modeGrid->addWidget(newRadioButton, 0, 0, Qt::AlignLeft); modeButtonGroup->addButton(newRadioButton, 0); // // Edit radio button // editRadioButton = new QRadioButton("Edit Number"); modeGrid->addWidget(editRadioButton, 1, 0, Qt::AlignLeft); modeButtonGroup->addButton(editRadioButton, 1); // // Edit foci number line edit // editFocusNumberSpinBox = new QSpinBox; editFocusNumberSpinBox->setMinimum(0); editFocusNumberSpinBox->setMaximum(std::numeric_limits::max()); editFocusNumberSpinBox->setSingleStep(1); editFocusNumberSpinBox->setMinimumWidth(80); editFocusNumberSpinBox->setMaximumWidth(80); modeGrid->addWidget(editFocusNumberSpinBox, 1, 1, Qt::AlignLeft); QObject::connect(editFocusNumberSpinBox, SIGNAL(valueChanged(const QString&)), this, SLOT(editFocusNumberChanged())); QObject::connect(editFocusNumberSpinBox, SIGNAL(valueChanged(const QString&)), this, SLOT(loadFocusSlot())); loadFocusPushButton = new QPushButton("Load"); loadFocusPushButton->setAutoDefault(false); modeGrid->addWidget(loadFocusPushButton, 1, 2, Qt::AlignLeft); QObject::connect(loadFocusPushButton, SIGNAL(clicked()), this, SLOT(loadFocusSlot())); loadFocusPushButton->setToolTip( "Press this button to load the focus\n" "whose index is in the box on the left."); deleteFocusPushButton = new QPushButton("Delete"); deleteFocusPushButton->setAutoDefault(false); modeGrid->addWidget(deleteFocusPushButton, 1, 3, Qt::AlignLeft); QObject::connect(deleteFocusPushButton, SIGNAL(clicked()), this, SLOT(deleteFocusSlot())); deleteFocusPushButton->setToolTip( "Press this button to delete the focus\n" "whose index is in the box on the left."); // // Squish the mode section and default to new // modeGroup->setFixedSize(modeGroup->sizeHint()); newRadioButton->setChecked(true); slotModeButtonSelected(); const int minWidth = 350; // // Name label, line edit, and choose button // QPushButton* focusNameButton = new QPushButton("Name..."); focusNameButton->setAutoDefault(false); QObject::connect(focusNameButton, SIGNAL(clicked()), this, SLOT(nameButtonSlot())); focusNameLineEdit = new QLineEdit; focusNameLineEdit->setMinimumWidth(minWidth); // // Class label, line edit, and choose button // QPushButton* focusClassNameButton = new QPushButton("Class..."); focusClassNameButton->setAutoDefault(false); QObject::connect(focusClassNameButton, SIGNAL(clicked()), this, SLOT(classNameButtonSlot())); focusClassNameLineEdit = new QLineEdit; focusClassNameLineEdit->setMinimumWidth(minWidth); // // X, Y, and Z Position label and line edit // const int coordWidth = 100; QLabel* focusCoordLabel = new QLabel("Position (mm)"); focusXCoordDoubleSpinBox = new QDoubleSpinBox; focusXCoordDoubleSpinBox->setMinimum(-std::numeric_limits::max()); focusXCoordDoubleSpinBox->setMaximum(std::numeric_limits::max()); focusXCoordDoubleSpinBox->setDecimals(2); focusXCoordDoubleSpinBox->setSingleStep(1.0); focusXCoordDoubleSpinBox->setFixedWidth(coordWidth); focusYCoordDoubleSpinBox = new QDoubleSpinBox; focusYCoordDoubleSpinBox->setMinimum(-std::numeric_limits::max()); focusYCoordDoubleSpinBox->setMaximum(std::numeric_limits::max()); focusYCoordDoubleSpinBox->setDecimals(2); focusYCoordDoubleSpinBox->setSingleStep(1.0); focusYCoordDoubleSpinBox->setFixedWidth(coordWidth); focusZCoordDoubleSpinBox = new QDoubleSpinBox; focusZCoordDoubleSpinBox->setMinimum(-std::numeric_limits::max()); focusZCoordDoubleSpinBox->setMaximum(std::numeric_limits::max()); focusZCoordDoubleSpinBox->setDecimals(2); focusZCoordDoubleSpinBox->setSingleStep(1.0); focusZCoordDoubleSpinBox->setFixedWidth(coordWidth); // // Study label and combo box // QLabel* focusStudyLabel = new QLabel("Study in Focus File"); focusStudyComboBox = new QComboBox; focusStudyComboBox->setMinimumWidth(minWidth); // // Study Meta Data Push Button and line edit // QPushButton* focusStudyMetaDataPushButton = new QPushButton("Study Metadata..."); focusStudyMetaDataPushButton->setAutoDefault(false); QObject::connect(focusStudyMetaDataPushButton, SIGNAL(clicked()), this, SLOT(slotFocusStudyMetaDataPushButton())); focusStudyMetaDataLineEdit = new QLineEdit; focusStudyMetaDataLineEdit->setMinimumWidth(minWidth); focusStudyMetaDataLineEdit->setReadOnly(true); // // area label and line edit // QPushButton* focusAreaPushButton = new QPushButton("Area..."); //"Cortical Area..."); focusAreaPushButton->setAutoDefault(false); QObject::connect(focusAreaPushButton, SIGNAL(clicked()), this, SLOT(slotCorticalAreaPushButton())); focusAreaLineEdit = new QLineEdit; //focusAreaLineEdit->setMinimumWidth(minWidth); // // geography label and line edit // QPushButton* focusGeographyPushButton = new QPushButton("Geography..."); focusGeographyPushButton->setAutoDefault(false); QObject::connect(focusGeographyPushButton, SIGNAL(clicked()), this, SLOT(slotGeographyPushButton())); focusGeographyLineEdit = new QLineEdit; //focusGeographyLineEdit->setMinimumWidth(minWidth); // // region of interest label and line edit // QPushButton* focusRegionOfInterestPushButton = new QPushButton("ROI..."); focusRegionOfInterestPushButton->setAutoDefault(false); QObject::connect(focusRegionOfInterestPushButton, SIGNAL(clicked()), this, SLOT(slotRegionOfInterestPushButton())); focusRegionOfInterestLineEdit = new QLineEdit; focusRegionOfInterestLineEdit->setMinimumWidth(minWidth); // // size label and line edit // QLabel* focusSizeLabel = new QLabel("Extent"); focusSizeDoubleSpinBox = new QDoubleSpinBox; focusSizeDoubleSpinBox->setMinimum(-std::numeric_limits::max()); focusSizeDoubleSpinBox->setMaximum(std::numeric_limits::max()); focusSizeDoubleSpinBox->setDecimals(3); focusSizeDoubleSpinBox->setSingleStep(1.0); focusSizeDoubleSpinBox->setFixedWidth(coordWidth); // // statistic label and line edit // QLabel* focusStatisticLabel = new QLabel("Statistic"); focusStatisticLineEdit = new QLineEdit; //focusStatisticLineEdit->setMinimumWidth(minWidth); // // comment label and text edit // QLabel* focusCommentLabel = new QLabel("Comment"); focusCommentTextEdit = new QTextEdit; focusCommentTextEdit->setMinimumWidth(minWidth); focusCommentTextEdit->setMaximumHeight(60); // // Vertical Group Box for data entry // QGroupBox* dataGroup = new QGroupBox("Focus Data"); fociPageLayout->addWidget(dataGroup); int numRows = 0; const int NAME_ROW = numRows++; const int CLASS_ROW = numRows++; const int COORD_ROW = numRows++; const int STUDY_ROW = numRows++; const int STUDY_METADATA_ROW = numRows++; const int AREA_GEOGRAPHY_ROW = numRows++; const int REGION_OF_INTEREST_ROW = numRows++; const int SIZE_STATISTIC_ROW = numRows++; const int COMMENT_ROW = numRows++; //const int COMMENT_ROW_2 = numRows++; //const int COMMENT_ROW_3 = numRows++; // // Grid Layout for Name and Resampling // QGridLayout* focusGrid = new QGridLayout(dataGroup); focusGrid->addWidget(focusNameButton, NAME_ROW, 0, 1, 1, Qt::AlignRight); focusGrid->addWidget(focusNameLineEdit, NAME_ROW, 1, 1, 3, Qt::AlignLeft); focusGrid->addWidget(focusClassNameButton, CLASS_ROW, 0, 1, 1, Qt::AlignRight); focusGrid->addWidget(focusClassNameLineEdit, CLASS_ROW, 1, 1, 3, Qt::AlignLeft); focusGrid->addWidget(focusCoordLabel, COORD_ROW, 0, 1, 1, Qt::AlignRight); focusGrid->addWidget(focusXCoordDoubleSpinBox, COORD_ROW, 1, 1, 1, Qt::AlignLeft); focusGrid->addWidget(focusYCoordDoubleSpinBox, COORD_ROW, 2, 1, 1, Qt::AlignLeft); focusGrid->addWidget(focusZCoordDoubleSpinBox, COORD_ROW, 3, 1, 1, Qt::AlignLeft); focusGrid->addWidget(focusStudyLabel, STUDY_ROW, 0, 1, 1, Qt::AlignRight); focusGrid->addWidget(focusStudyComboBox, STUDY_ROW, 1, 1, 3, Qt::AlignLeft); focusGrid->addWidget(focusStudyMetaDataPushButton, STUDY_METADATA_ROW, 0, 1, 1, Qt::AlignLeft); focusGrid->addWidget(focusStudyMetaDataLineEdit, STUDY_METADATA_ROW, 1, 1, 3, Qt::AlignLeft); focusGrid->addWidget(focusAreaPushButton, AREA_GEOGRAPHY_ROW, 0, 1, 1, Qt::AlignRight); focusGrid->addWidget(focusAreaLineEdit, AREA_GEOGRAPHY_ROW, 1, 1, 1, Qt::AlignLeft); focusGrid->addWidget(focusGeographyPushButton, AREA_GEOGRAPHY_ROW, 2, 1, 1, Qt::AlignRight); focusGrid->addWidget(focusGeographyLineEdit, AREA_GEOGRAPHY_ROW, 3, 1, 1, Qt::AlignLeft); focusGrid->addWidget(focusRegionOfInterestPushButton, REGION_OF_INTEREST_ROW, 0, 1, 1, Qt::AlignRight); focusGrid->addWidget(focusRegionOfInterestLineEdit, REGION_OF_INTEREST_ROW, 1, 1, 3, Qt::AlignLeft); focusGrid->addWidget(focusSizeLabel, SIZE_STATISTIC_ROW, 0, 1, 1, Qt::AlignRight); focusGrid->addWidget(focusSizeDoubleSpinBox, SIZE_STATISTIC_ROW, 1, 1, 1, Qt::AlignLeft); focusGrid->addWidget(focusStatisticLabel, SIZE_STATISTIC_ROW, 2, 1, 1, Qt::AlignRight); focusGrid->addWidget(focusStatisticLineEdit, SIZE_STATISTIC_ROW, 3, 1, 1, Qt::AlignLeft); focusGrid->addWidget(focusCommentLabel, COMMENT_ROW, 0, Qt::AlignRight | Qt::AlignVCenter); focusGrid->addWidget(focusCommentTextEdit, COMMENT_ROW, 1, 1, 3); } /** * called when study meta data button pressed. */ void GuiMapStereotaxicFocusDialog::slotFocusStudyMetaDataPushButton() { GuiStudyMetaDataLinkCreationDialog smdlcd(this); StudyMetaDataLinkSet smdls; smdls.setLinkSetFromCodedText(focusStudyMetaDataLineEdit->text()); smdlcd.initializeSelectedLinkSet(smdls); if (smdlcd.exec() == GuiStudyMetaDataLinkCreationDialog::Accepted) { focusStudyMetaDataLineEdit->setText(smdlcd.getLinkSetCreated().getLinkSetAsCodedText()); focusStudyMetaDataLineEdit->home(false); } } /** * called when a mode button is selected. */ void GuiMapStereotaxicFocusDialog::slotModeButtonSelected() { const bool enableThem = editRadioButton->isChecked(); editFocusNumberSpinBox->setEnabled(enableThem); loadFocusPushButton->setEnabled(enableThem); deleteFocusPushButton->setEnabled(enableThem); if (enableThem) { loadFocusSlot(); } } /** * called when cortical area button selected. */ void GuiMapStereotaxicFocusDialog::slotCorticalAreaPushButton() { GuiNameSelectionDialog nsd(this, (GuiNameSelectionDialog::LIST_AREA_COLORS_ALPHA | GuiNameSelectionDialog::LIST_PAINT_NAMES_ALPHA | GuiNameSelectionDialog::LIST_VOCABULARY_ALPHA), GuiNameSelectionDialog::LIST_PAINT_NAMES_ALPHA); if (nsd.exec() == QDialog::Accepted) { const QString name(nsd.getNameSelected()); if (name.isEmpty() == false) { focusAreaLineEdit->setText(name); } } } /** * called when Geography button selected. */ void GuiMapStereotaxicFocusDialog::slotGeographyPushButton() { GuiNameSelectionDialog nsd(this, (GuiNameSelectionDialog::LIST_AREA_COLORS_ALPHA | GuiNameSelectionDialog::LIST_PAINT_NAMES_ALPHA | GuiNameSelectionDialog::LIST_VOCABULARY_ALPHA), GuiNameSelectionDialog::LIST_PAINT_NAMES_ALPHA); if (nsd.exec() == QDialog::Accepted) { const QString name(nsd.getNameSelected()); if (name.isEmpty() == false) { focusGeographyLineEdit->setText(name); } } } /** * called when Region of Interest button selected.. */ void GuiMapStereotaxicFocusDialog::slotRegionOfInterestPushButton() { GuiNameSelectionDialog nsd(this, (GuiNameSelectionDialog::LIST_AREA_COLORS_ALPHA | GuiNameSelectionDialog::LIST_PAINT_NAMES_ALPHA | GuiNameSelectionDialog::LIST_VOCABULARY_ALPHA), GuiNameSelectionDialog::LIST_VOCABULARY_ALPHA); if (nsd.exec() == QDialog::Accepted) { const QString name(nsd.getNameSelected()); if (name.isEmpty() == false) { focusRegionOfInterestLineEdit->setText(name); } } } /** * load a focus into the dialog */ void GuiMapStereotaxicFocusDialog::loadFocusSlot() { FociProjectionFile* ff = theMainWindow->getBrainSet()->getFociProjectionFile(); CellProjection dummy; CellProjection* cd = &dummy; if (ff != NULL) { const int focusNumber = editFocusNumberSpinBox->value(); if ((focusNumber >= 0) && (focusNumber < ff->getNumberOfCellProjections())) { QString name, className; cd = ff->getCellProjection(focusNumber); } else { QMessageBox::critical(this, "Focus Error", "Invalid focus number entered."); return; } } // // Load the focus data // float xyz[3]; cd->getXYZ(xyz); focusNameLineEdit->setText(cd->getName()); focusClassNameLineEdit->setText(cd->getClassName()); focusXCoordDoubleSpinBox->setValue(xyz[0]); focusYCoordDoubleSpinBox->setValue(xyz[1]); focusZCoordDoubleSpinBox->setValue(xyz[2]); focusAreaLineEdit->setText(cd->getArea()); focusGeographyLineEdit->setText(cd->getGeography()); focusRegionOfInterestLineEdit->setText(cd->getRegionOfInterest()); focusSizeDoubleSpinBox->setValue(cd->getSize()); focusStatisticLineEdit->setText(cd->getStatistic()); focusCommentTextEdit->setPlainText(cd->getComment()); focusStudyMetaDataLineEdit->setText(cd->getStudyMetaDataLinkSet().getLinkSetAsCodedText()); focusStudyMetaDataLineEdit->home(false); int studyNumber = cd->getStudyNumber(); if ((studyNumber < 0) || (studyNumber >= ff->getNumberOfStudyInfo())) { studyNumber = ff->getNumberOfStudyInfo(); } focusStudyComboBox->setCurrentIndex(studyNumber); } /** * load a focus into the dialog */ void GuiMapStereotaxicFocusDialog::deleteFocusSlot() { if (QMessageBox::question(this, "Confirm", "Delete the selected focus?", (QMessageBox::Yes | QMessageBox::No), QMessageBox::Yes) == QMessageBox::No) { return; } FociProjectionFile* ff = theMainWindow->getBrainSet()->getFociProjectionFile(); if (ff != NULL) { int focusNumber = editFocusNumberSpinBox->value(); if ((focusNumber >= 0) && (focusNumber < ff->getNumberOfCellProjections())) { ff->deleteCellProjection(focusNumber); if (focusNumber >= ff->getNumberOfCellProjections()) { focusNumber--; } if (focusNumber < 0) { focusNumber = 0; } GuiFilesModified fm; fm.setFociModified(); theMainWindow->fileModificationUpdate(fm); ff->setModified(); editFocusNumberSpinBox->setValue(focusNumber); loadFocusSlot(); } else { QMessageBox::critical(this, "Focus Error", "Invalid focus number entered."); return; } } } /** * Edit the focus. */ void GuiMapStereotaxicFocusDialog::editFocus(const int focusNumber) { FociProjectionFile* ff = theMainWindow->getBrainSet()->getFociProjectionFile(); if (ff != NULL) { if ((focusNumber >= 0) && (focusNumber < ff->getNumberOfCellProjections())) { editFocusNumberSpinBox->setValue(focusNumber); loadFocusSlot(); } } } /** * called when the focus number is changed */ void GuiMapStereotaxicFocusDialog::editFocusNumberChanged() { editRadioButton->setChecked(true); } /** * Called when apply button pressed. */ void GuiMapStereotaxicFocusDialog::applyButtonSlot() { if (tabWidget->currentWidget() == fociPageVBox) { processFocusEntry(); } else { studyInfoEditorWidget->slotAcceptEditorContents(); slotUpdateStudyNumberComboBox(); } } /** * process the entry of study information. */ void GuiMapStereotaxicFocusDialog::processFocusEntry() { // // Check automatic projection to surface // bool projectToMainWindowSurface = false; bool projectToPalsSurfaces = false; if (automaticProjectionGroupBox->isChecked()) { projectToMainWindowSurface = projectionMainWindowFiducialRadioButton->isChecked(); projectToPalsSurfaces = ((projectionPalsAtlasRadioButton->isChecked()) && (projectionPalsAtlasRadioButton->isEnabled())); if ((projectToMainWindowSurface == false) && (projectToPalsSurfaces == false)) { QMessageBox::critical(this, "ERROR", "You must select a Projection Surface or \n" "deselect Automatic Projection of Foci."); return; } } // // See if a fiducial surface is in the main window // GuiBrainModelOpenGL* openGL = theMainWindow->getBrainModelOpenGL(); BrainModelSurface* bms = openGL->getDisplayedBrainModelSurface(); if (projectToMainWindowSurface) { if (bms == NULL) { QMessageBox::critical(this, "ERROR", "There is no surface in the main window."); return; } } if (projectToPalsSurfaces) { if (theMainWindow->getBrainSet()->getNumberOfNodes() != 73730) { QMessageBox::critical(this, "ERROR", "Cannot project to PALS since no PALS compatible surface is loaded."); return; } } QString msg; const QString nameValue = focusNameLineEdit->text().trimmed(); if (nameValue.isEmpty()) { msg.append("You must enter a foci name.\n"); } const QString classNameValue = focusClassNameLineEdit->text().trimmed(); if (classNameValue.isEmpty()) { //msg.append("You must enter a class name.\n"); } const float x = focusXCoordDoubleSpinBox->value(); const float y = focusYCoordDoubleSpinBox->value(); const float z = focusZCoordDoubleSpinBox->value(); if ((x == 0.0) && (y == 0.0) && (z == 0.0)) { msg.append("Focus coordinates cannot be all zeros.\n"); } if (msg.isEmpty() == false) { QMessageBox::critical(this, "Data Entry Error", msg); return; } // // Replace any spaces in foci name with underscores // QString fociName(nameValue); //StringUtilities::replace(fociName, ' ', '_'); // // Replace any spaces in foci class name with underscores // QString fociClassName(classNameValue); //StringUtilities::replace(fociClassName, ' ', '_'); // // Find the matching color // bool colorMatch = false; FociColorFile* colorFile = theMainWindow->getBrainSet()->getFociColorFile(); int fociColorIndex = colorFile->getColorIndexByName(fociName, colorMatch); // // Foci color may need to be created // bool createColor = false; if ((fociColorIndex >= 0) && (colorMatch == true)) { createColor = false; } else if ((fociColorIndex >= 0) && (colorMatch == false)) { QString msg("Use foci color \""); msg.append(colorFile->getColorNameByIndex(fociColorIndex)); msg.append("\" for foci "); msg.append(fociName); msg.append(" ?"); const QString noButtonText("No, define color " + fociName); QMessageBox msgBox(this); msgBox.setWindowTitle("Use Partially Matching Color"); msgBox.setText(msg); msgBox.addButton("Yes", QMessageBox::YesRole); QPushButton* noPushButton = msgBox.addButton(noButtonText, QMessageBox::NoRole); msgBox.exec(); if (msgBox.clickedButton() == noPushButton) { createColor = true; } } else { createColor = true; } if (createColor) { QString title("Create Foci Color "); title.append(fociName); GuiColorSelectionDialog* csd = new GuiColorSelectionDialog(this, title, true, true, false, true); csd->exec(); // // Add new foci color // float pointSize = 2.0, lineSize = 1.0; unsigned char r, g, b, a; ColorFile::ColorStorage::SYMBOL symbol; csd->getColorInformation(r, g, b, a, pointSize, lineSize, symbol); colorFile->addColor(fociName, r, g, b, a, pointSize, lineSize, symbol); fociColorIndex = colorFile->getNumberOfColors() - 1; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); // // Get the foci file // FociProjectionFile* ff = theMainWindow->getBrainSet()->getFociProjectionFile(); // // Get the study number // int studyNumber = focusStudyComboBox->currentIndex(); if (focusStudyComboBox->currentText() == noneStudyName) { studyNumber = -1; } else if (studyNumber >= ff->getNumberOfStudyInfo()) { studyNumber = -1; } int focusNumber = -1; StudyMetaDataLinkSet studyMetaDataLinkSet; studyMetaDataLinkSet.setLinkSetFromCodedText(focusStudyMetaDataLineEdit->text()); if (newRadioButton->isChecked()) { // // Create the foci // CellProjection cd; const float xyz[3] = { x, y, z }; cd.setXYZ(xyz); cd.setName(fociName); cd.setClassName(fociClassName); cd.setStudyNumber(studyNumber); cd.setColorIndex(fociColorIndex); cd.setComment(focusCommentTextEdit->toPlainText()); cd.setArea(focusAreaLineEdit->text()); cd.setGeography(focusGeographyLineEdit->text()); cd.setRegionOfInterest(focusRegionOfInterestLineEdit->text()); cd.setSize(focusSizeDoubleSpinBox->text().toFloat()); cd.setStatistic(focusStatisticLineEdit->text()); cd.setStudyMetaDataLinkSet(studyMetaDataLinkSet); ff->addCellProjection(cd); focusNumber = ff->getNumberOfCellProjections() - 1; } else { focusNumber = editFocusNumberSpinBox->value(); if ((focusNumber >= 0) && (focusNumber < ff->getNumberOfCellProjections())) { CellProjection* cd = ff->getCellProjection(focusNumber); cd->setName(fociName); const float xyz[3] = { x, y, z }; cd->setXYZ(xyz); cd->setClassName(fociClassName); cd->setStudyNumber(studyNumber); cd->setComment(focusCommentTextEdit->toPlainText()); cd->setArea(focusAreaLineEdit->text()); cd->setGeography(focusGeographyLineEdit->text()); cd->setRegionOfInterest(focusRegionOfInterestLineEdit->text()); cd->setSize(focusSizeDoubleSpinBox->value()); cd->setStatistic(focusStatisticLineEdit->text()); cd->setStudyMetaDataLinkSet(studyMetaDataLinkSet); } else { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "Focus Number Invalid", "The focus number entered is invalid"); return; } } if (projectToMainWindowSurface) { // // Create the cell file projector (foci same as cells) // CellFileProjector projector(bms); // // Project the new foci // projector.projectFile(theMainWindow->getBrainSet()->getFociProjectionFile(), focusNumber, CellFileProjector::PROJECTION_TYPE_FLIP_TO_MATCH_HEMISPHERE, 0.0, false, NULL); } else if (projectToPalsSurfaces) { // // Project to PALS atlas // if (palsProjector == NULL) { palsProjector = new FociFileToPalsProjector(theMainWindow->getBrainSet(), ff, theMainWindow->getBrainSet()->getStudyMetaDataFile(), focusNumber, focusNumber, 0.0, false, projectionPalsCerebellumCheckBox->isChecked(), 1.0, 2.0); } palsProjector->setFirstFocusIndex(focusNumber, focusNumber); try { palsProjector->execute(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); } } DisplaySettingsFoci* dsf = theMainWindow->getBrainSet()->getDisplaySettingsFoci(); dsf->setDisplayCells(true); GuiFilesModified fm; fm.setFociModified(); fm.setFociColorModified(); theMainWindow->fileModificationUpdate(fm); ff->setModified(); GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); } /** * Update the dialog (typically called when foci file changed). */ void GuiMapStereotaxicFocusDialog::updateDialog() { FociProjectionFile* ff = theMainWindow->getBrainSet()->getFociProjectionFile(); // // Enable projection surface options // projectionPalsAtlasRadioButton->setEnabled(false); const BrainModelSurface* bms = theMainWindow->getBrainSet()->getActiveFiducialSurface(); if (bms != NULL) { projectionMainWindowFiducialRadioButton->setEnabled(true); const bool palsValid = (bms->getNumberOfNodes() == 73730); projectionPalsAtlasRadioButton->setEnabled(palsValid); } studyInfoEditorWidget->updateWidget(ff->getPointerToStudyInfo()); slotUpdateStudyNumberComboBox(); } /** * update the study number combo box. */ void GuiMapStereotaxicFocusDialog::slotUpdateStudyNumberComboBox() { const bool noneFlag = (focusStudyComboBox->currentText() == noneStudyName); const int oldIndx = focusStudyComboBox->currentIndex(); focusStudyComboBox->clear(); FociProjectionFile* fpf = theMainWindow->getBrainSet()->getFociProjectionFile(); const int numStudys = fpf->getNumberOfStudyInfo(); for (int i = 0; i < numStudys; i++) { const CellStudyInfo* csi = fpf->getStudyInfo(i); QString s(csi->getTitle()); if (s.length() > 30) { s.resize(30); } QString qs(QString::number(i)); qs.append(" - "); qs.append(s); focusStudyComboBox->addItem(qs); } const int noneIndex = focusStudyComboBox->count(); focusStudyComboBox->addItem(noneStudyName); if (noneFlag) { focusStudyComboBox->setCurrentIndex(noneIndex); } else if ((oldIndx >= 0) && (oldIndx < numStudys)) { focusStudyComboBox->setCurrentIndex(oldIndx); } else { focusStudyComboBox->setCurrentIndex(noneIndex); } } /** * Called when Focus Name button is pressed. */ void GuiMapStereotaxicFocusDialog::nameButtonSlot() { GuiNameSelectionDialog nsd(this, GuiNameSelectionDialog::LIST_ALL, GuiNameSelectionDialog::LIST_FOCI_NAMES_ALPHA); if (nsd.exec() == QDialog::Accepted) { const QString name(nsd.getNameSelected()); if (name.isEmpty() == false) { focusNameLineEdit->setText(name); } } } /** * Called when Focus ClassName button is pressed. */ void GuiMapStereotaxicFocusDialog::classNameButtonSlot() { FociProjectionFile* ff = theMainWindow->getBrainSet()->getFociProjectionFile(); if (ff != NULL) { const int numClasses = ff->getNumberOfCellClasses(); std::vector classNames; for (int i = 0; i < numClasses; i++) { classNames.push_back(ff->getCellClassNameByIndex(i)); } if (classNames.size() > 0) { QtListBoxSelectionDialog lbsd(this, "Foci Classes", "", classNames, 0); if (lbsd.exec()) { focusClassNameLineEdit->setText(lbsd.getSelectedText()); } } else { QMessageBox::information(this, "No Classes", "Cell File has no classes"); } } else { QMessageBox::information(this, "No Classes", "Cell File has no classes"); } } caret-5.6.4~dfsg.1.orig/caret/GuiMapFmriVolume.h0000664000175000017500000000747111572067322021231 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_MAP_FMRI_VOLUME_H__ #define __GUI_MAP_FMRI_VOLUME_H__ #include #include class VolumeFile; /// This class stores information about an fmri volume class GuiMapFmriVolume { public: /// type of volume enum FMRI_VOLUME_TYPE { FMRI_VOLUME_TYPE_FILE_ON_DISK, FMRI_VOLUME_TYPE_FILE_IN_MEMORY }; /// Constructor for a volume file GuiMapFmriVolume(const QString& fileNameIn, const float negThreshIn, const float posThreshIn); /// Constructor for a volume in memory GuiMapFmriVolume(VolumeFile* volumeFileIn, const float negThreshIn, const float posThreshIn); /// Destructor ~GuiMapFmriVolume(); /// get the name of the volume file QString getVolumeFileName() const { return fileName; } /// get the type of volume FMRI_VOLUME_TYPE getFmriVolumeType() const { return fmriVolumeType; } /// get the descriptive name QString getDescriptiveName() const { return descriptiveName; } /// get number of subvolumes int getNumberOfSubVolumes() const { return subVolumeNames.size(); } /// get a subvolume name QString getSubVolumeName(const int indx) const; /// set a subvolume name void setSubVolumeName(const int indx, const QString& name); /// get thresholds void getThresholds(float& negThreshOut, float& posThreshOut) const; /// set thresholds void setThresholds(const float negThreshIn, const float posThreshIn); /// get volume is valid flag bool getVolumeValid() const { return volumeValid; } /// get the in-memory volume file VolumeFile* getInMemoryVolumeFile() { return volumeFile; } /// get the file's comment QString getFileComment() const { return fileComment; } protected: /// Create sub-volume names (use -1 for num if unknown) void createSubVolumeNames(const VolumeFile* vf, const int num, const float negThreshIn, const float posThreshIn); /// the type of volume FMRI_VOLUME_TYPE fmriVolumeType; /// the name of the volume file used when ( QString fileName; /// the VolumeFile used when () VolumeFile* volumeFile; /// the descriptive name QString descriptiveName; /// names of sub-volumes std::vector subVolumeNames; /// the file's comment QString fileComment; /// negative thresholds per sub-volume float negativeThreshold; /// positive thresholds per sub-volume float positiveThreshold; /// volume is valid bool volumeValid; }; #endif // __GUI_MAP_FMRI_VOLUME_H__ caret-5.6.4~dfsg.1.orig/caret/GuiMapFmriVolume.cxx0000664000175000017500000000756211572067322021605 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "FileUtilities.h" #include "GuiMapFmriVolume.h" #include "VolumeFile.h" /** * Constructor for a volume file. */ GuiMapFmriVolume::GuiMapFmriVolume(const QString& fileNameIn, const float negThreshIn, const float posThreshIn) { fmriVolumeType = FMRI_VOLUME_TYPE_FILE_ON_DISK; fileName = fileNameIn; descriptiveName = "FILE - "; descriptiveName.append(FileUtilities::basename(fileName)); volumeValid = false; VolumeFile vf; try { vf.readFile(fileName, VolumeFile::VOLUME_READ_HEADER_ONLY); if (vf.getNumberOfSubVolumes() > 0) { volumeValid = true; createSubVolumeNames(&vf, -1, negThreshIn, posThreshIn); fileComment = vf.getFileComment(); } } catch (FileException&) { } } /** * Constructor for a volume in memory. */ GuiMapFmriVolume::GuiMapFmriVolume(VolumeFile* volumeFileIn, const float negThreshIn, const float posThreshIn) { fmriVolumeType = FMRI_VOLUME_TYPE_FILE_IN_MEMORY; volumeFile = volumeFileIn; descriptiveName = "VOLUME - "; descriptiveName.append(FileUtilities::basename(volumeFile->getDescriptiveLabel())); volumeValid = (volumeFile != NULL); if (volumeValid) { createSubVolumeNames(volumeFile, 1, negThreshIn, posThreshIn); fileComment = volumeFile->getFileComment(); } } /** * Destructor. */ GuiMapFmriVolume::~GuiMapFmriVolume() { } /** * Create sub-volume names. */ void GuiMapFmriVolume::createSubVolumeNames(const VolumeFile* vf, const int num, const float negThreshIn, const float posThreshIn) { int numSubVol = num; if (num <= 0) { numSubVol = vf->getNumberOfSubVolumes(); } std::vector names; vf->getSubVolumeNames(names); for (int i = 0; i < numSubVol; i++) { subVolumeNames.push_back(names[i]); negativeThreshold = negThreshIn; positiveThreshold = posThreshIn; } } /** * get a subvolume name. */ QString GuiMapFmriVolume::getSubVolumeName(const int indx) const { if ((indx >= 0) && (indx < getNumberOfSubVolumes())) { return subVolumeNames[indx]; } return ""; } /** * set a subvolume name. */ void GuiMapFmriVolume::setSubVolumeName(const int indx, const QString& name) { if ((indx >= 0) && (indx < getNumberOfSubVolumes())) { subVolumeNames[indx] = name; } } /** * get subvolume thresholds. */ void GuiMapFmriVolume::getThresholds(float& negThreshOut, float& posThreshOut) const { negThreshOut = negativeThreshold; posThreshOut = positiveThreshold; } /** * set subvolume thresholds. */ void GuiMapFmriVolume::setThresholds(const float negThreshIn, const float posThreshIn) { negativeThreshold = negThreshIn; positiveThreshold = posThreshIn; } caret-5.6.4~dfsg.1.orig/caret/GuiMapFmriThresholdDialog.h0000664000175000017500000000323611572067322023031 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "WuQDialog.h" class QDoubleSpinBox; /// dialog for obtaining volume thresholding class GuiMapFmriThresholdDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiMapFmriThresholdDialog(QWidget* parent, const QString& volumeFileName); /// Destructor ~GuiMapFmriThresholdDialog(); /// overrides parent and called when OK pressed void done(int r); /// get the threshold values void getThresholds(float& negThresh, float& posThresh) const; protected: /// negative threshold line edit QDoubleSpinBox* negativeDoubleSpinBox; /// positive threshold line edit QDoubleSpinBox* positiveDoubleSpinBox; }; caret-5.6.4~dfsg.1.orig/caret/GuiMapFmriThresholdDialog.cxx0000664000175000017500000001171111572067322023401 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include "GuiMapFmriThresholdDialog.h" #include "FileUtilities.h" #include "StringUtilities.h" /** * Constructor. */ GuiMapFmriThresholdDialog::GuiMapFmriThresholdDialog(QWidget* parent, const QString& volumeFileName) : WuQDialog(parent) { setModal(true); setWindowTitle("Volume Thresholding"); // // Layout for dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(3); dialogLayout->setSpacing(3); QLabel* nameLabel = new QLabel(FileUtilities::basename(volumeFileName)); dialogLayout->addWidget(nameLabel); // // Help text edit // std::ostringstream str; str << "Enter the positive and negative " << "thresholds for the volume.\n" << "These thresholds are used when " << "the data is displayed on the surface " << "in Caret. If you do not know the " << "thresholds, leave them at zero. "; QTextEdit* helpTextEdit = new QTextEdit; helpTextEdit->setPlainText(str.str().c_str()); helpTextEdit->setReadOnly(true); dialogLayout->addWidget(helpTextEdit); // // Pos and neg thresholds // QLabel* posLabel = new QLabel("Positive "); positiveDoubleSpinBox = new QDoubleSpinBox; positiveDoubleSpinBox->setMinimum(0.0); positiveDoubleSpinBox->setMaximum(100000000.0); positiveDoubleSpinBox->setSingleStep(1.0); positiveDoubleSpinBox->setDecimals(4); positiveDoubleSpinBox->setValue(0.0); QLabel* negLabel = new QLabel("Negative "); negativeDoubleSpinBox = new QDoubleSpinBox; negativeDoubleSpinBox->setMinimum(-100000000.0); negativeDoubleSpinBox->setMaximum(0.0); negativeDoubleSpinBox->setSingleStep(1.0); negativeDoubleSpinBox->setDecimals(4); negativeDoubleSpinBox->setValue(0.0); // // Layout for thresholds // QGridLayout* threshGridLayout = new QGridLayout; threshGridLayout->addWidget(posLabel, 0, 0); threshGridLayout->addWidget(positiveDoubleSpinBox, 0, 1); threshGridLayout->addWidget(negLabel, 1, 0); threshGridLayout->addWidget(negativeDoubleSpinBox, 1, 1); threshGridLayout->setColumnStretch(0, 0); threshGridLayout->setColumnStretch(1, 0); threshGridLayout->setColumnStretch(2, 100); dialogLayout->addLayout(threshGridLayout); // // layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; dialogLayout->addLayout(buttonsLayout); // // OK button // QPushButton* okButton = new QPushButton("OK"); okButton->setAutoDefault(false); okButton->setFixedSize(okButton->sizeHint()); buttonsLayout->addWidget(okButton); QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); } /** * Destructor. */ GuiMapFmriThresholdDialog::~GuiMapFmriThresholdDialog() { } /** * get the threshold values. */ void GuiMapFmriThresholdDialog::getThresholds(float& negThresh, float& posThresh) const { negThresh = negativeDoubleSpinBox->value(); posThresh = positiveDoubleSpinBox->value(); } /** * overrides parent and called when OK pressed. */ void GuiMapFmriThresholdDialog::done(int r) { float negThresh, posThresh; getThresholds(negThresh, posThresh); QString msg; if (negThresh > 0.0) { msg.append("Negative threshold is greater than zero."); } if (posThresh < 0.0) { if (msg.isEmpty() == false) { msg.append("\n"); } msg.append("Positive threshold is less than zero."); } if (msg.isEmpty() == false) { msg.append("\nDo you want to continue ?"); if (QMessageBox::warning(this, "WARNING", msg, (QMessageBox::Ok | QMessageBox::Cancel), QMessageBox::Cancel) == QMessageBox::Cancel) { return; } } QDialog::done(r); } caret-5.6.4~dfsg.1.orig/caret/GuiMapFmriSpecFileTopoCoordDialog.h0000664000175000017500000000536511572067322024425 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_SPEC_FILE_TOPO_COORD_DIALOG_H__ #define __GUI_SPEC_FILE_TOPO_COORD_DIALOG_H__ #include #include #include "WuQDialog.h" #include "SpecFile.h" class QListWidget; class QComboBox; class QLineEdit; class QGroupBox; class PreferencesFile; /// Class for selecting topology and coordinate files from a spec file class GuiMapFmriSpecFileTopoCoordDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiMapFmriSpecFileTopoCoordDialog(QWidget* parent, PreferencesFile* pf); /// Destructor ~GuiMapFmriSpecFileTopoCoordDialog(); /// get the name of the topo file QString getTopoFileName() const; /// get number of coordinate files int getNumberOfCoordFileNames() const; /// get the names of a coordinate files void getCoordFileNames(std::vector& names) const; /// Get the name of the selected spec file. QString getSpecFileName() const; protected slots: /// called when select spec file pushbutton pressed void slotSelectSpecPushButton(); /// called when select all coord files pushbutton is pressed void slotSelectAllCoordPushButton(); protected: /// overrides parent's version void done(int r); /// spec file name line edit QLineEdit* specFileLineEdit; /// the spec file SpecFile specFile; /// topo file combo box QComboBox* topoFileComboBox; /// coord file list box QListWidget* coordFileListBox; /// topo file group QGroupBox* topoGroupBox; /// coord file group QGroupBox* coordGroupBox; /// the preferences file PreferencesFile* preferencesFile; }; #endif // __GUI_SPEC_FILE_TOPO_COORD_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiMapFmriSpecFileTopoCoordDialog.cxx0000664000175000017500000002144211572067322024772 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include "FileUtilities.h" #include "GuiChooseSpecFileDialog.h" #include "GuiMapFmriSpecFileTopoCoordDialog.h" #include "QtUtilities.h" #include "SpecFile.h" /** * Constructor. */ GuiMapFmriSpecFileTopoCoordDialog::GuiMapFmriSpecFileTopoCoordDialog(QWidget* parent, PreferencesFile* pf) : WuQDialog(parent) { setModal(true); setWindowTitle("Mapping Surface Selection"); preferencesFile = pf; // // Spec file selection // QPushButton* selectSpecPushButton = new QPushButton("Select..."); selectSpecPushButton->setAutoDefault(false); selectSpecPushButton->setFixedSize(selectSpecPushButton->sizeHint()); QObject::connect(selectSpecPushButton, SIGNAL(clicked()), this, SLOT(slotSelectSpecPushButton())); specFileLineEdit = new QLineEdit; specFileLineEdit->setReadOnly(true); specFileLineEdit->setMinimumWidth(250); // // Group box and layout for spec file selection // QGroupBox* specGroupBox = new QGroupBox("Spec File"); QHBoxLayout* specGroupLayout = new QHBoxLayout(specGroupBox); specGroupLayout->addWidget(selectSpecPushButton); specGroupLayout->addWidget(specFileLineEdit); // // Topology selection // topoFileComboBox = new QComboBox; topoGroupBox = new QGroupBox("Topology Files"); QHBoxLayout* topoGroupLayout = new QHBoxLayout(topoGroupBox); topoGroupLayout->addWidget(topoFileComboBox); // // Coordinate file selection // coordFileListBox = new QListWidget; coordFileListBox->setSelectionMode(QListWidget::ExtendedSelection); coordFileListBox->setMinimumWidth(500); // // Select all coords button // QPushButton* selectAllCoordPushButton = new QPushButton("Select All Coord Files"); selectAllCoordPushButton->setFixedSize(selectAllCoordPushButton->sizeHint()); selectAllCoordPushButton->setAutoDefault(false); QObject::connect(selectAllCoordPushButton, SIGNAL(clicked()), this, SLOT(slotSelectAllCoordPushButton())); // // Coordinate group box and layout // coordGroupBox = new QGroupBox("Fiducial Coordinate Files"); QVBoxLayout* coordGroupLayout = new QVBoxLayout(coordGroupBox); coordGroupLayout->addWidget(coordFileListBox); coordGroupLayout->addWidget(selectAllCoordPushButton); const QString instructions = "Choose a topology file and one or more fiducial coordinate files. " "All coordinate files MUST be in the same stereotaxic space as the " "functional volumes. Hold down the shift key or the CTRL key (Apple " "key on Macintoshes) to select multiple coordinate files."; QTextEdit* textEditor = new QTextEdit; textEditor->setReadOnly(true); textEditor->setPlainText(instructions); // // OK and Cancel buttons // QPushButton* okButton = new QPushButton("OK"); okButton->setAutoDefault(false); QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); QPushButton* cancelButton = new QPushButton("Cancel"); cancelButton->setAutoDefault(false); QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); QtUtilities::makeButtonsSameSize(okButton, cancelButton); QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->addWidget(okButton); buttonsLayout->addWidget(cancelButton); // // Layout for dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->addWidget(specGroupBox); dialogLayout->addWidget(topoGroupBox); dialogLayout->addWidget(coordGroupBox); dialogLayout->addWidget(textEditor); dialogLayout->addLayout(buttonsLayout); } /** * Destructor. */ GuiMapFmriSpecFileTopoCoordDialog::~GuiMapFmriSpecFileTopoCoordDialog() { } /** * called when select spec file pushbutton pressed. */ void GuiMapFmriSpecFileTopoCoordDialog::slotSelectSpecPushButton() { // // Popup the choose spec file dialog // GuiChooseSpecFileDialog sfd(this, preferencesFile, true); if (sfd.exec() == QDialog::Accepted) { const QString specFileName = sfd.getSelectedSpecFile(); specFileLineEdit->setText(specFileName); // // Clear and disable topo and coord selections // topoFileComboBox->clear(); coordFileListBox->clear(); topoGroupBox->setEnabled(false); coordGroupBox->setEnabled(false); // // Clear the topo and coord file // // // Read the spec file // try { specFile.readFile(specFileName); } catch (FileException& e) { QString msg("Unable to read spec file "); msg.append(FileUtilities::basename(specFileName)); QMessageBox::critical(this, "ERROR", msg); return; } // // Load the topo files into combo box // const int numTopo = static_cast(specFile.closedTopoFile.getNumberOfFiles()); for (int i = 0; i < numTopo; i++) { topoFileComboBox->addItem( FileUtilities::basename(specFile.closedTopoFile.getFileName(i))); } QString errorMessage; if (numTopo > 0) { topoGroupBox->setEnabled(true); } else { errorMessage.append("Closed topology files are required and there are none in the selected spec file."); } // // load the coord file list box // const int numCoord = static_cast(specFile.fiducialCoordFile.getNumberOfFiles()); for (int i = 0; i < numCoord; i++) { coordFileListBox->insertItem(i, FileUtilities::basename(specFile.fiducialCoordFile.getFileName(i))); } if (numCoord > 0) { if (numCoord == 1) { coordFileListBox->setCurrentRow(0); } coordGroupBox->setEnabled(true); } else { if (errorMessage.isEmpty() == false) { errorMessage.append("\n"); } errorMessage.append("Fiducial coordinate files are required and there are none in the selected spec file."); } if (errorMessage.isEmpty() == false) { QMessageBox::critical(this, "ERROR", errorMessage); return; } } } /** * called when select all coord files pushbutton is pressed. */ void GuiMapFmriSpecFileTopoCoordDialog::slotSelectAllCoordPushButton() { coordFileListBox->selectAll(); } /** * Called when OK or Cancel button pressed. */ void GuiMapFmriSpecFileTopoCoordDialog::done(int r) { if (r == QDialog::Accepted) { std::vector names; getCoordFileNames(names); if (names.empty()) { QMessageBox::critical(this, "ERROR", "You must select at least one coordinate file."); return; } } QDialog::done(r); } /** * Get the name of the selected spec file. */ QString GuiMapFmriSpecFileTopoCoordDialog::getSpecFileName() const { return specFileLineEdit->text(); } /** * get the name of the topo file. */ QString GuiMapFmriSpecFileTopoCoordDialog::getTopoFileName() const { QString name; if (topoFileComboBox != NULL) { name = specFile.closedTopoFile.getFileName(topoFileComboBox->currentIndex()); } return name; } /** * get the name of the coordinate file. */ void GuiMapFmriSpecFileTopoCoordDialog::getCoordFileNames(std::vector& names) const { names.clear(); if (coordFileListBox == NULL) { return; } for (int i = 0; i < static_cast(specFile.fiducialCoordFile.getNumberOfFiles()); i++) { const QListWidgetItem* item = coordFileListBox->item(i); if (coordFileListBox->isItemSelected(item)) { names.push_back(specFile.fiducialCoordFile.getFileName(i)); } } } caret-5.6.4~dfsg.1.orig/caret/GuiMapFmriMetricInfo.h0000664000175000017500000005224411572067322022017 0ustar michaelmichael #ifndef __GUI_MAP_FMRI_METRIC_INFO_H__ #define __GUI_MAP_FMRI_METRIC_INFO_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include class GuiMapFmriMappingSet; class GuiMapFmriVolume; /// This class is used to store metric naming information for a single volume /// that may be mapped to multiple surfaces. class GuiMapFmriMetricInfo { public: /// Constructor GuiMapFmriMetricInfo(const GuiMapFmriMappingSet* surfaceInfo, const GuiMapFmriVolume* volumeInfo, const int volumeIndexIn, const int subVolumeIndexIn); /// Destructor ~GuiMapFmriMetricInfo(); /// get the number of metric columns int getNumberOfMetricColumns() const { return metricColumnNames.size(); } /// get the surface name for a metric column QString getSurfaceNameForMetricColumn(const int indx) const { return surfaceNameForMetricColumn[indx]; } /// get the name of a metric column QString getMetricColumnName(const int indx) const { return metricColumnNames[indx]; } /// set the name of a metric column void setMetricColumnName(const int indx, const QString& name) { metricColumnNames[indx] = name; } /// get the row number in the metric naming table for a metric column name int getMetricColumnNameRowNumber(const int indx) const { return metricColumnNamesRowNumber[indx]; } /// set the row number in the metric naming table for a metric column name void setMetricColumnNameRowNumber(const int indx, const int rowNumber) { metricColumnNamesRowNumber[indx] = rowNumber; } /// get a comment for a metric column QString getMetricColumnComment(const int indx) const { return metricColumnComments[indx]; } /// set a comment for a metric column void setMetricColumnComment(const int indx, const QString& comment) { metricColumnComments[indx] = comment; } /// get the metric column thresholds void getMetricColumnThresholds(const int indx, float& negThresh, float& posThresh) const; /// set the metric column thresholds void setMetricColumnThresholds(const int indx, const float negThresh, const float posThresh); /// get the average fiducial coord file metric column name QString getMetricAverageFiducialCoordColumnName() const { return metricAverageFiducialCoordColumnName; } /// set the average fiducial coord file metric column name void setMetricAverageFiducialCoordColumnName(const QString& name) { metricAverageFiducialCoordColumnName = name; } /// get the average fiducial coord metric column name row number for metric naming table int getMetricAverageFiducialCoordNameRowNumber() const { return metricAverageFiducialCoordColumnNameRowNumber; } /// set the average fiducial coord metric column name row number for metric naming table void setMetricAverageFiducialCoordNameRowNumber(const int rowNumber) { metricAverageFiducialCoordColumnNameRowNumber = rowNumber; } /// get the metric average fiducial coord comment QString getMetricAverageFiducialCoordComment() const { return metricAverageFiducialCoordComment; } /// set the metric average fiducial coord comment void setMetricAverageFiducialCoordComment(const QString& comment) { metricAverageFiducialCoordComment = comment; } /// get the metric average fiducial coord thresholds void getMetricAverageFiducialCoordThresholds(float& negThresh, float& posThresh) const; /// set the metric average fiducial coord thresholds void setMetricAverageFiducialCoordThresholds(const float negThresh, const float posThresh); /// get the average of all metric column name QString getMetricAverageOfAllColumnName() const { return metricAverageOfAllColumnName; } /// set the average of all metric column name void setMetricAverageOfAllColumnName(const QString& name) { metricAverageOfAllColumnName = name; } /// get the average of all metric column name row number for metric naming table int getMetricAverageOfAllColumnNameRowNumber() const { return metricAverageOfAllColumnNameRowNumber; } /// set the average of all metric column name row number for metric naming table void setMetricAverageOfAllColumnNameRowNumber(const int rowNumber) { metricAverageOfAllColumnNameRowNumber = rowNumber; } /// get the metric average of all comment QString getMetricAverageOfAllComment() const { return metricAverageOfAllComment; } /// set the metric average of all comment void setMetricAverageOfAllComment(const QString& comment) { metricAverageOfAllComment = comment; } /// get the metric average of all thresholds void getMetricAverageOfAllThresholds(float& negThresh, float& posThresh) const; /// set the metric average of all thresholds void setMetricAverageOfAllThresholds(const float negThresh, const float posThresh); /// get the std dev metric column name QString getMetricStdDevColumnName() const { return metricStdDevColumnName; } /// set the std dev metric column name void setMetricStdDevColumnName(const QString& name) { metricStdDevColumnName = name; } /// get the std dev metric column name row number for metric naming table int getMetricStdDevColumnNameRowNumber() const { return metricStdDevColumnNameRowNumber; } /// set the std dev metric column name row number for metric naming table void setMetricStdDevColumnNameRowNumber(const int rowNumber) { metricStdDevColumnNameRowNumber = rowNumber; } /// get the metric std dev comment QString getMetricStdDevComment() const { return metricStdDevComment; } /// set the metric std dev comment void setMetricStdDevComment(const QString& comment) { metricStdDevComment = comment; } /// get the metric std dev thresholds void getMetricStdDevThresholds(float& negThresh, float& posThresh) const; /// set the metric std dev thresholds void setMetricStdDevThresholds(const float negThresh, const float posThresh); /// get the std error metric column name QString getMetricStdErrorColumnName() const { return metricStdErrorColumnName; } /// set the std error metric column name void setMetricStdErrorColumnName(const QString& name) { metricStdErrorColumnName = name; } /// get the std error metric column name row number for metric naming table int getMetricStdErrorColumnNameRowNumber() const { return metricStdErrorColumnNameRowNumber; } /// set the std error metric column name row number for metric naming table void setMetricStdErrorColumnNameRowNumber(const int rowNumber) { metricStdErrorColumnNameRowNumber = rowNumber; } /// get the metric std error comment QString getMetricStdErrorComment() const { return metricStdErrorComment; } /// set the metric std error comment void setMetricStdErrorComment(const QString& comment) { metricStdErrorComment = comment; } /// get the metric std error thresholds void getMetricStdErrorThresholds(float& negThresh, float& posThresh) const; /// set the metric std error thresholds void setMetricStdErrorThresholds(const float negThresh, const float posThresh); /// get the minimum value metric column name QString getMetricMinValueColumnName() const { return metricMinValueColumnName; } /// set the minimum value metric column name void setMetricMinValueColumnName(const QString& name) { metricMinValueColumnName = name; } /// get the minimum value metric column name row number for metric naming table int getMetricMinValueColumnNameRowNumber() const { return metricMinValueColumnNameRowNumber; } /// set the minimum value metric column name row number for metric naming table void setMetricMinValueColumnNameRowNumber(const int rowNumber) { metricMinValueColumnNameRowNumber = rowNumber; } /// get the metric minimum value comment QString getMetricMinValueComment() const { return metricMinValueComment; } /// set the metric minimum value comment void setMetricMinValueComment(const QString& comment) { metricMinValueComment = comment; } /// get the metric minimum value thresholds void getMetricMinValueThresholds(float& negThresh, float& posThresh) const; /// set the metric minimum value thresholds void setMetricMinValueThresholds(const float negThresh, const float posThresh); /// get the maximum value metric column name QString getMetricMaxValueColumnName() const { return metricMaxValueColumnName; } /// set the maximum value metric column name void setMetricMaxValueColumnName(const QString& name) { metricMaxValueColumnName = name; } /// get the maximum value metric column name row number for metric naming table int getMetricMaxValueColumnNameRowNumber() const { return metricMaxValueColumnNameRowNumber; } /// set the maximum value metric column name row number for metric naming table void setMetricMaxValueColumnNameRowNumber(const int rowNumber) { metricMaxValueColumnNameRowNumber = rowNumber; } /// get the metric maximum value comment QString getMetricMaxValueComment() const { return metricMaxValueComment; } /// set the metric maximum value comment void setMetricMaxValueComment(const QString& comment) { metricMaxValueComment = comment; } /// get the metric maximum value thresholds void getMetricMaxValueThresholds(float& negThresh, float& posThresh) const; /// set the metric maximum value thresholds void setMetricMaxValueThresholds(const float negThresh, const float posThresh); /// get the most common value metric column name QString getMetricMostCommonValueColumnName() const { return metricMostCommonValueColumnName; } /// set the most common value metric column name void setMetricMostCommonValueColumnName(const QString& name) { metricMostCommonValueColumnName = name; } /// get the most common value metric column name row number for metric naming table int getMetricMostCommonValueColumnNameRowNumber() const { return metricMostCommonValueColumnNameRowNumber; } /// set the most common value metric column name row number for metric naming table void setMetricMostCommonValueColumnNameRowNumber(const int rowNumber) { metricMostCommonValueColumnNameRowNumber = rowNumber; } /// get the metric most common value comment QString getMetricMostCommonValueComment() const { return metricMostCommonValueComment; } /// set the metric most common value comment void setMetricMostCommonValueComment(const QString& comment) { metricMostCommonValueComment = comment; } /// get the metric most common value thresholds void getMetricMostCommonValueThresholds(float& negThresh, float& posThresh) const; /// set the metric most common value thresholds void setMetricMostCommonValueThresholds(const float negThresh, const float posThresh); /// get the most common no idvalue metric column name QString getMetricMostCommonExcludeUnidentifiedValueColumnName() const { return metricMostCommonExcludeUnidentifiedValueColumnName; } /// set the most common no idvalue metric column name void setMetricMostCommonExcludeUnidentifiedValueColumnName(const QString& name) { metricMostCommonExcludeUnidentifiedValueColumnName = name; } /// get the most common no idvalue metric column name row number for metric naming table int getMetricMostCommonExcludeUnidentifiedValueColumnNameRowNumber() const { return metricMostCommonExcludeUnidentifiedValueColumnNameRowNumber; } /// set the most common no idvalue metric column name row number for metric naming table void setMetricMostCommonExcludeUnidentifiedValueColumnNameRowNumber(const int rowNumber) { metricMostCommonExcludeUnidentifiedValueColumnNameRowNumber = rowNumber; } /// get the metric most common no idvalue comment QString getMetricMostCommonExcludeUnidentifiedValueComment() const { return metricMostCommonExcludeUnidentifiedValueComment; } /// set the metric most common no idvalue comment void setMetricMostCommonExcludeUnidentifiedValueComment(const QString& comment) { metricMostCommonExcludeUnidentifiedValueComment = comment; } /// get the metric most common no idvalue thresholds void getMetricMostCommonExcludeUnidentifiedValueThresholds(float& negThresh, float& posThresh) const; /// set the metric most common no idvalue thresholds void setMetricMostCommonExcludeUnidentifiedValueThresholds(const float negThresh, const float posThresh); /// get the volume's index int getVolumeIndex() const { return volumeIndex; } /// get the sub-volume's index int getSubVolumeIndex() const { return subVolumeIndex; } protected: /// name of metric columns (one per mapping surface) std::vector metricColumnNames; /// negative threshold (one per mapping surface) std::vector metricColumnNegativeThreshold; /// positive threshold (one per mapping surface) std::vector metricColumnPositiveThreshold; /// row number of metric column name in naming table std::vector metricColumnNamesRowNumber; /// name of surface for the corresponding metric column std::vector surfaceNameForMetricColumn; /// comments for metric columns std::vector metricColumnComments; /// name of average fiducial coord metric column name QString metricAverageFiducialCoordColumnName; /// row number of average fiducial coord metric column in naming table int metricAverageFiducialCoordColumnNameRowNumber; /// comment for averge fiducialcoord metric QString metricAverageFiducialCoordComment; /// negative threshold for average fiducial coord float metricAverageFiducialCoordColumnNegativeThreshold; /// positive threshold for average fiducial coord float metricAverageFiducialCoordColumnPositiveThreshold; /// name of average of all metric column name QString metricAverageOfAllColumnName; /// row number of average of all metric column in naming table int metricAverageOfAllColumnNameRowNumber; /// comment for average of all metric QString metricAverageOfAllComment; /// negative threshold for average of all threshold float metricAverageOfAllColumnNegativeThreshold; /// positive threshold for average of all threshold float metricAverageOfAllColumnPositiveThreshold; /// name of std dev metric column name QString metricStdDevColumnName; /// row number of std dev metric column in naming table int metricStdDevColumnNameRowNumber; /// comment for std dev metric QString metricStdDevComment; /// negative threshold for std dev threshold float metricStdDevColumnNegativeThreshold; /// positive threshold for std dev threshold float metricStdDevColumnPositiveThreshold; /// name of std error metric column name QString metricStdErrorColumnName; /// row number of std error metric column in naming table int metricStdErrorColumnNameRowNumber; /// comment for std error metric QString metricStdErrorComment; /// negative threshold for std error threshold float metricStdErrorColumnNegativeThreshold; /// positive threshold for std error threshold float metricStdErrorColumnPositiveThreshold; /// name of minimum value metric column name QString metricMinValueColumnName; /// row number of minimum value metric column in naming table int metricMinValueColumnNameRowNumber; /// comment for minimum value metric QString metricMinValueComment; /// negative threshold for minimum value threshold float metricMinValueColumnNegativeThreshold; /// positive threshold for minimum value threshold float metricMinValueColumnPositiveThreshold; /// name of maximum value metric column name QString metricMaxValueColumnName; /// row number of maximum value metric column in naming table int metricMaxValueColumnNameRowNumber; /// comment for maximum value metric QString metricMaxValueComment; /// negative threshold for maximum value threshold float metricMaxValueColumnNegativeThreshold; /// positive threshold for maximum value threshold float metricMaxValueColumnPositiveThreshold; /// name of most common value metric column name QString metricMostCommonValueColumnName; /// row number of most common value metric column in naming table int metricMostCommonValueColumnNameRowNumber; /// comment for most common value metric QString metricMostCommonValueComment; /// negative threshold for most common value threshold float metricMostCommonValueColumnNegativeThreshold; /// positive threshold for most common value threshold float metricMostCommonValueColumnPositiveThreshold; /// name of most common exclude unidentified value metric column name QString metricMostCommonExcludeUnidentifiedValueColumnName; /// row number of most common exclude unidentified value metric column in naming table int metricMostCommonExcludeUnidentifiedValueColumnNameRowNumber; /// comment for most common exclude unidentified value metric QString metricMostCommonExcludeUnidentifiedValueComment; /// negative threshold for most common exclude unidentified value threshold float metricMostCommonExcludeUnidentifiedValueColumnNegativeThreshold; /// positive threshold for most common exclude unidentified value threshold float metricMostCommonExcludeUnidentifiedValueColumnPositiveThreshold; /// index into volumes int volumeIndex; /// sub volume index int subVolumeIndex; }; #endif // __GUI_MAP_FMRI_METRIC_INFO_H__ caret-5.6.4~dfsg.1.orig/caret/GuiMapFmriMetricInfo.cxx0000664000175000017500000003513711572067322022374 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurface.h" #include "FileUtilities.h" #include "GuiMapFmriMappingSet.h" #include "GuiMapFmriMetricInfo.h" #include "GuiMapFmriVolume.h" #include "StringUtilities.h" /** * Constructor. */ GuiMapFmriMetricInfo::GuiMapFmriMetricInfo(const GuiMapFmriMappingSet* surfaceInfo, const GuiMapFmriVolume* volumeInfo, const int volumeIndexIn, const int subVolumeIndexIn) { volumeIndex = volumeIndexIn; subVolumeIndex = subVolumeIndexIn; QString volumeComment; if (volumeInfo != NULL) { volumeComment = volumeInfo->getFileComment(); if (volumeComment.isEmpty() == false) { QString s("Volume Comment: "); s.append(volumeComment); s.append("; "); volumeComment = s; } } switch (surfaceInfo->getMappingType()) { case GuiMapFmriMappingSet::MAPPING_TYPE_NONE: return; break; case GuiMapFmriMappingSet::MAPPING_TYPE_WITH_CARET_SURFACES: { std::vector surfaces; surfaceInfo->getMappingCaretSurfaces(surfaces); for (unsigned int i = 0; i < surfaces.size(); i++) { surfaceNameForMetricColumn.push_back(surfaces[i]->getDescriptiveName()); } } break; case GuiMapFmriMappingSet::MAPPING_TYPE_WITH_SPEC_FILES: { std::vector names; surfaceInfo->getMappingCoordFileNames(names); for (unsigned int i = 0; i < names.size(); i++) { surfaceNameForMetricColumn.push_back(FileUtilities::basename(names[i])); } if (surfaceInfo->getDoAverageFiducialFileFlag()) { const QString structName = surfaceInfo->getStructureForColumnNaming(); metricAverageFiducialCoordColumnName = "AFM "; if (structName.isEmpty() == false) { metricAverageFiducialCoordColumnName.append(structName); } metricAverageFiducialCoordColumnName.append(" - "); //metricAverageFiducialCoordColumnName.append(surfaceInfo->getAverageFiducialCoordFileName()); metricAverageFiducialCoordColumnName.append(volumeInfo->getSubVolumeName(subVolumeIndex)); metricAverageFiducialCoordColumnNameRowNumber = -1; metricAverageFiducialCoordComment = "Average Fiducial Mapping (AFM); "; metricAverageFiducialCoordComment.append(volumeComment); metricAverageFiducialCoordColumnNegativeThreshold = 0.0; metricAverageFiducialCoordColumnPositiveThreshold = 0.0; float negThresh = 0.0, posThresh = 0.0; volumeInfo->getThresholds(negThresh, posThresh); metricAverageFiducialCoordColumnNegativeThreshold = negThresh; metricAverageFiducialCoordColumnPositiveThreshold = posThresh; } } break; } float negThresh, posThresh; volumeInfo->getThresholds(negThresh, posThresh); for (unsigned int i = 0; i < surfaceNameForMetricColumn.size(); i++) { QString prefix; if (surfaceNameForMetricColumn.size() > 1) { QString s(StringUtilities::makeLowerCase(surfaceNameForMetricColumn[i])); const int caseNameIndex = s.indexOf("case"); if (caseNameIndex != -1) { int periodCount = 0; for (int j = caseNameIndex; j < s.length(); j++) { if (s[j] == '.') { periodCount++; if (periodCount == 2) { prefix = surfaceNameForMetricColumn[i].mid(caseNameIndex, (j - caseNameIndex)); break; } } } } } QString columnName; if (prefix.isEmpty() == false) { columnName.append("Map to "); columnName.append(prefix); columnName.append(" - "); } columnName.append(volumeInfo->getSubVolumeName(subVolumeIndex)); metricColumnNames.push_back(columnName); metricColumnNegativeThreshold.push_back(negThresh); metricColumnPositiveThreshold.push_back(posThresh); metricColumnComments.push_back(""); metricColumnNamesRowNumber.push_back(-1); } QString allSurfaceNames; for (unsigned int i = 0; i < surfaceNameForMetricColumn.size(); i++) { allSurfaceNames.append(surfaceNameForMetricColumn[i]); allSurfaceNames.append(" "); } const QString structName = surfaceInfo->getStructureForColumnNaming(); metricAverageOfAllColumnName = "MFM "; if (structName.isEmpty() == false) { metricAverageOfAllColumnName.append(structName); } metricAverageOfAllColumnName.append(" - "); metricAverageOfAllColumnName.append(volumeInfo->getSubVolumeName(subVolumeIndex)); metricAverageOfAllComment.append("Multi-Fiducial Mapping (MFM); "); metricAverageOfAllComment.append(volumeComment); metricAverageOfAllComment.append("MFM using surface files: "); metricAverageOfAllComment.append(allSurfaceNames); metricAverageOfAllColumnNameRowNumber = -1; metricAverageOfAllColumnNegativeThreshold = negThresh; metricAverageOfAllColumnPositiveThreshold = posThresh; metricStdDevColumnName = "STANDARD DEVIATION (MFM) - "; metricStdDevColumnName.append(volumeInfo->getSubVolumeName(subVolumeIndex)); metricStdDevComment.append("Using surface files: "); metricStdDevComment.append(allSurfaceNames); metricStdDevColumnNameRowNumber = -1; metricStdDevColumnNegativeThreshold = 0.0; //negThresh; metricStdDevColumnPositiveThreshold = 0.0; //posThresh; metricStdErrorColumnName = "STANDARD ERROR (MFM) - "; metricStdErrorColumnName.append(volumeInfo->getSubVolumeName(subVolumeIndex)); metricStdErrorComment.append("Using surface files: "); metricStdErrorComment.append(allSurfaceNames); metricStdErrorColumnNameRowNumber = -1; metricStdErrorColumnNegativeThreshold = 0.0; //negThresh; metricStdErrorColumnPositiveThreshold = 0.0; //posThresh; metricMinValueColumnName = "MINIMUM (MFM) - "; metricMinValueColumnName.append(volumeInfo->getSubVolumeName(subVolumeIndex)); metricMinValueComment.append("Using surface files: "); metricMinValueComment.append(allSurfaceNames); metricMinValueColumnNameRowNumber = -1; metricMinValueColumnNegativeThreshold = 0.0; //negThresh; metricMinValueColumnPositiveThreshold = 0.0; //posThresh; metricMaxValueColumnName = "MAXIMUM (MFM) - "; metricMaxValueColumnName.append(volumeInfo->getSubVolumeName(subVolumeIndex)); metricMaxValueComment.append("Using surface files: "); metricMaxValueComment.append(allSurfaceNames); metricMaxValueColumnNameRowNumber = -1; metricMaxValueColumnNegativeThreshold = 0.0; //negThresh; metricMaxValueColumnPositiveThreshold = 0.0; //posThresh; metricMostCommonValueColumnName = "MFM (Most Common) "; if (structName.isEmpty() == false) { metricMostCommonValueColumnName.append(structName); } metricMostCommonValueColumnName.append(" - "); metricMostCommonValueColumnName.append(volumeInfo->getSubVolumeName(subVolumeIndex)); metricMostCommonValueComment.append("Multi-Fiducial Most Common Mapping (MFM); "); metricMostCommonValueComment.append(volumeComment); metricMostCommonValueComment.append("MFM using surface files: "); metricMostCommonValueComment.append(allSurfaceNames); metricMostCommonValueColumnNameRowNumber = -1; metricMostCommonValueColumnNegativeThreshold = 0.0; //negThresh; metricMostCommonValueColumnPositiveThreshold = 0.0; //posThresh; metricMostCommonExcludeUnidentifiedValueColumnName = "MFM (Most Common Exclude No ID) "; if (structName.isEmpty() == false) { metricMostCommonExcludeUnidentifiedValueColumnName.append(structName); } metricMostCommonExcludeUnidentifiedValueColumnName.append(" - "); metricMostCommonExcludeUnidentifiedValueColumnName.append(volumeInfo->getSubVolumeName(subVolumeIndex)); metricMostCommonExcludeUnidentifiedValueComment.append("Multi-Fiducial Most Common Exclude No ID Mapping (MFM); "); metricMostCommonExcludeUnidentifiedValueComment.append(volumeComment); metricMostCommonExcludeUnidentifiedValueComment.append("MFM using surface files: "); metricMostCommonExcludeUnidentifiedValueComment.append(allSurfaceNames); metricMostCommonExcludeUnidentifiedValueColumnNameRowNumber = -1; metricMostCommonExcludeUnidentifiedValueColumnNegativeThreshold = 0.0; //negThresh; metricMostCommonExcludeUnidentifiedValueColumnPositiveThreshold = 0.0; //posThresh; } /** * Destructor. */ GuiMapFmriMetricInfo::~GuiMapFmriMetricInfo() { } /** * get the metric column thresholds. */ void GuiMapFmriMetricInfo::getMetricColumnThresholds(const int indx, float& negThresh, float& posThresh) const { negThresh = metricColumnNegativeThreshold[indx]; posThresh = metricColumnPositiveThreshold[indx]; } /** * set the metric column thresholds. */ void GuiMapFmriMetricInfo::setMetricColumnThresholds(const int indx, const float negThresh, const float posThresh) { metricColumnNegativeThreshold[indx] = negThresh; metricColumnPositiveThreshold[indx] = posThresh; } /** * get the metric average fiducial coord thresholds. */ void GuiMapFmriMetricInfo::getMetricAverageFiducialCoordThresholds(float& negThresh, float& posThresh) const { negThresh = metricAverageFiducialCoordColumnNegativeThreshold; posThresh = metricAverageFiducialCoordColumnPositiveThreshold; } /** * set the metric average fiducial coord thresholds. */ void GuiMapFmriMetricInfo::setMetricAverageFiducialCoordThresholds(const float negThresh, const float posThresh) { metricAverageFiducialCoordColumnNegativeThreshold = negThresh; metricAverageFiducialCoordColumnPositiveThreshold = posThresh; } /** * get the metric average thresholds. */ void GuiMapFmriMetricInfo::getMetricAverageOfAllThresholds(float& negThresh, float& posThresh) const { negThresh = metricAverageOfAllColumnNegativeThreshold; posThresh = metricAverageOfAllColumnPositiveThreshold; } /** * set the metric average thresholds. */ void GuiMapFmriMetricInfo::setMetricAverageOfAllThresholds(const float negThresh, const float posThresh) { metricAverageOfAllColumnNegativeThreshold = negThresh; metricAverageOfAllColumnPositiveThreshold = posThresh; } /** * get the metric std dev thresholds. */ void GuiMapFmriMetricInfo::getMetricStdDevThresholds(float& negThresh, float& posThresh) const { negThresh = metricStdDevColumnNegativeThreshold; posThresh = metricStdDevColumnPositiveThreshold; } /** * set the metric std dev thresholds. */ void GuiMapFmriMetricInfo::setMetricStdDevThresholds(const float negThresh, const float posThresh) { metricStdDevColumnNegativeThreshold = negThresh; metricStdDevColumnPositiveThreshold = posThresh; } /** * get the metric std error thresholds. */ void GuiMapFmriMetricInfo::getMetricStdErrorThresholds(float& negThresh, float& posThresh) const { negThresh = metricStdErrorColumnNegativeThreshold; posThresh = metricStdErrorColumnPositiveThreshold; } /** * set the metric std error thresholds. */ void GuiMapFmriMetricInfo::setMetricStdErrorThresholds(const float negThresh, const float posThresh) { metricStdErrorColumnNegativeThreshold = negThresh; metricStdErrorColumnPositiveThreshold = posThresh; } /** * get the metric minimum value thresholds. */ void GuiMapFmriMetricInfo::getMetricMinValueThresholds(float& negThresh, float& posThresh) const { negThresh = metricMinValueColumnNegativeThreshold; posThresh = metricMinValueColumnPositiveThreshold; } /** * set the metric minimum value thresholds. */ void GuiMapFmriMetricInfo::setMetricMinValueThresholds(const float negThresh, const float posThresh) { metricMinValueColumnNegativeThreshold = negThresh; metricMinValueColumnPositiveThreshold = posThresh; } /** * get the metric maximum value thresholds. */ void GuiMapFmriMetricInfo::getMetricMaxValueThresholds(float& negThresh, float& posThresh) const { negThresh = metricMaxValueColumnNegativeThreshold; posThresh = metricMaxValueColumnPositiveThreshold; } /** * set the metric maximum value thresholds. */ void GuiMapFmriMetricInfo::setMetricMaxValueThresholds(const float negThresh, const float posThresh) { metricMaxValueColumnNegativeThreshold = negThresh; metricMaxValueColumnPositiveThreshold = posThresh; } /** * get the metric most common value thresholds. */ void GuiMapFmriMetricInfo::getMetricMostCommonValueThresholds(float& negThresh, float& posThresh) const { negThresh = metricMostCommonValueColumnNegativeThreshold; posThresh = metricMostCommonValueColumnPositiveThreshold; } /** * set the metric most common value thresholds. */ void GuiMapFmriMetricInfo::setMetricMostCommonValueThresholds(const float negThresh, const float posThresh) { metricMostCommonValueColumnNegativeThreshold = negThresh; metricMostCommonValueColumnPositiveThreshold = posThresh; } /** * get the metric most common exclude unidentified value thresholds. */ void GuiMapFmriMetricInfo::getMetricMostCommonExcludeUnidentifiedValueThresholds(float& negThresh, float& posThresh) const { negThresh = metricMostCommonExcludeUnidentifiedValueColumnNegativeThreshold; posThresh = metricMostCommonExcludeUnidentifiedValueColumnPositiveThreshold; } /** * set the metric most common exclude unidentified value thresholds. */ void GuiMapFmriMetricInfo::setMetricMostCommonExcludeUnidentifiedValueThresholds(const float negThresh, const float posThresh) { metricMostCommonExcludeUnidentifiedValueColumnNegativeThreshold = negThresh; metricMostCommonExcludeUnidentifiedValueColumnPositiveThreshold = posThresh; } caret-5.6.4~dfsg.1.orig/caret/GuiMapFmriMappingSet.h0000664000175000017500000002524311572067322022026 0ustar michaelmichael #ifndef __GUI_MAP_FMRI_MAPPING_SET_H__ #define __GUI_MAP_FMRI_MAPPING_SET_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "GuiMapFmriMetricInfo.h" #include "MetricFile.h" class BrainModelSurface; class GuiMapFmriVolume; /// class for storing mapping surface information class GuiMapFmriMappingSet { public: /// type of metric output enum METRIC_OUTPUT_TYPE { METRIC_OUTPUT_TYPE_NONE, METRIC_OUTPUT_TYPE_CARET_METRIC, METRIC_OUTPUT_TYPE_SPEC_FILE }; /// type of mapping enum MAPPING_TYPE { MAPPING_TYPE_NONE, MAPPING_TYPE_WITH_CARET_SURFACES, MAPPING_TYPE_WITH_SPEC_FILES }; /// Constructor for mapping to spec files both with and without atlas GuiMapFmriMappingSet(const QString& outputSpecFileNameIn, const QString& mappingFilesPathIn, const QString& topoFileNameIn, const std::vector& coordFileNamesIn, const QString& avgCoordFileNameIn, const std::vector& volumes, const QString& fileNameExtensionIn, const QString& descriptionIn, const QString& metricNameHintIn, const QString& structureNameIn, const bool mappingWithAtlasFlagIn, const bool doAvgCoordFileFlagIn, const bool doAvgOfAllCoordFileFlagIn, const bool doStdDevOfAllCoordFileFlagIn, const bool doStdErrorOfAllCoordFileFlagIn, const bool doMinOfAllCoordFileFlagIn, const bool doMaxOfAllCoordFileFlagIn, const bool doAllCasesCoordFileFlagIn, const bool doMostCommonOfAllCasesFlagIn, const bool doMostCommonExcludeUnidentifiedOfAllCasesFlagIn); /// Constructor for mapping to caret surfaces GuiMapFmriMappingSet(std::vector caretSurfacesIn, const std::vector& volumes, const QString& fileNameExtensionIn, const QString& descriptionIn); /// Constructor for mapping to caret surfaces with an atlas GuiMapFmriMappingSet(const QString& mappingFilesPathIn, const QString& mappingTopoFileNameIn, const std::vector& mappingCoordFileNamesIn, const QString& avgCoordFileNameIn, const std::vector& volumes, const QString& fileNameExtensionIn, const QString& descriptionIn, const QString& structureNameIn, const bool doAvgCoordFileFlagIn, const bool doAvgOfAllCoordFileFlagIn, const bool doStdDevOfAllCoordFileFlagIn, const bool doStdErrorOfAllCoordFileFlagIn, const bool doMinOfAllCoordFileFlagIn, const bool doMaxOfAllCoordFileFlagIn, const bool doAllCasesCoordFileFlagIn, const bool doMostCommonOfAllCasesFlagIn, const bool doMostCommonExcludeUnidentifiedOfAllCasesFlagIn); /// Destructor ~GuiMapFmriMappingSet(); /// get the mapping type MAPPING_TYPE getMappingType() const { return mappingType; } /// get the metric output type METRIC_OUTPUT_TYPE getMetricOutputType() const { return metricOutputType; } /// get the output spec file name QString getOutputSpecFileName() const { return outputSpecFileName; } /// get the location of the mapping files QString getMappingFilesPath() const { return mappingFilesPath; } /// get the topology file name for mapping data QString getMappingTopoFileName() const { return mappingTopoFileName; } /// get the coordinate file names for mapping data void getMappingCoordFileNames(std::vector& names) const { names = mappingCoordFileNames; } /// name of the avg fiducial file QString getAverageFiducialCoordFileName() const { return averageFiducialFileName; } /// get the surfaces for mapping data void getMappingCaretSurfaces(std::vector& surfaces) const { surfaces = mappingCaretSurfaces; } /// Get a descriptive label. QString getDescriptiveLabel() const; /// Get the name of the metric file QString getMetricFileName() const { return metricFileName; } /// Set the name of the metric file void setMetricFileName(const QString& name) { metricFileName = name; } /// get flag indicating mapping with atlas files bool getMappingWithAtlasFlag() const { return mappingWithAtlasFlag; } /// Get the number of metric mapping info (one per (vol * subvols)) int getNumberOfMetricMappingInfo() const { return metricMappingInfo.size(); } /// Get metric mapping info GuiMapFmriMetricInfo* getMetricMappingInfo(const int indx) { return &metricMappingInfo[indx]; } /// Get metric mapping info (const method) const GuiMapFmriMetricInfo* getMetricMappingInfo(const int indx) const { return &metricMappingInfo[indx]; } /// flag for average fiducial file bool getDoAverageFiducialFileFlag() const { return doAverageFiducialFileFlag; } /// flag for average of all coord files bool getDoAvgOfAllCoordFileFlag() const { return doAvgOfAllCoordFileFlag; } /// flag for std dev of all coord files bool getDoStdDevOfAllCoordFileFlag() const { return doStdDevOfAllCoordFileFlag; } /// flag for std error of all coord files bool getDoStdErrorOfAllCoordFileFlag() const { return doStdErrorOfAllCoordFileFlag; } /// flag for min of all coord files bool getDoMinOfAllCoordFileFlag() const { return doMinOfAllCoordFileFlag; } /// flag for max of all coord files bool getDoMaxOfAllCoordFileFlag() const { return doMaxOfAllCoordFileFlag; } /// flag for do all indiv case files bool getDoAllCasesCoordFileFlag() const { return doAllCasesCoordFileFlag; } /// flag for most common of all indiv case files (paint) bool getDoMostCommonOfAllCasesFlag() const { return doMostCommonOfAllCasesFlag; } /// flag for most common exclude unidentified of all indiv case files (paint) bool getDoMostCommonExcludeUnidentifiedOfAllCasesFlag() const { return doMostCommonExcludeUnidentifiedOfAllCasesFlag; } /// get the name for a structure for column naming QString getStructureForColumnNaming() const; protected: /// metric mapping information std::vector metricMappingInfo; /// Initialize the metric file naming void initializeMetricFile(const std::vector& volumes); /// location of the mapping files (topo and coord) QString mappingFilesPath; /// name and path of output spec file (for mappingType == MAPPING_TYPE_TO_SPEC_FILES) QString outputSpecFileName; /// name of topology file (for mappingType == MAPPING_TYPE_TO_SPEC_FILES QString mappingTopoFileName; /// names of coordinate files (for mappingType == MAPPING_TYPE_TO_SPEC_FILES std::vector mappingCoordFileNames; /// name of the average fiducial file QString averageFiducialFileName; /// caret surfaces that are to be mapped (for mappingType == MAPPING_TYPE_TO_CARET_SURFACES) std::vector mappingCaretSurfaces; /// the mapping type MAPPING_TYPE mappingType; /// name of the metric file QString metricFileName; /// counter to ensure that metric files are uniquely named static int uniqueNameCounter; /// the metric output type METRIC_OUTPUT_TYPE metricOutputType; /// metric file name hint QString metricNameHint; /// description of atlas QString description; /// file name extension QString fileNameExtension; /// name of structure QString structureName; /// flag indicating data is being mapped with an atlas bool mappingWithAtlasFlag; /// flag for average coord file bool doAverageFiducialFileFlag; /// flag for average of all coord files bool doAvgOfAllCoordFileFlag; /// flag for std dev of all coord files bool doStdDevOfAllCoordFileFlag; /// flag for std error of all coord files bool doStdErrorOfAllCoordFileFlag; /// flag for min of all coord files bool doMinOfAllCoordFileFlag; /// flag for max of all coord files bool doMaxOfAllCoordFileFlag; /// flag for do all indiv case files bool doAllCasesCoordFileFlag; /// flag for most common of all indiv case files bool doMostCommonOfAllCasesFlag; /// flag for most common of all indiv case files bool doMostCommonExcludeUnidentifiedOfAllCasesFlag; }; #ifdef __GUI_MAP_FMRI_MAPPING_SET_MAIN__ int GuiMapFmriMappingSet::uniqueNameCounter = 0; #endif // __GUI_MAP_FMRI_MAPPING_SET_MAIN__ #endif // __GUI_MAP_FMRI_MAPPING_SET_H__ caret-5.6.4~dfsg.1.orig/caret/GuiMapFmriMappingSet.cxx0000664000175000017500000002363211572067322022401 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainModelSurface.h" #include "DateAndTime.h" #include "FileUtilities.h" #define __GUI_MAP_FMRI_MAPPING_SET_MAIN__ #include "GuiMapFmriMappingSet.h" #undef __GUI_MAP_FMRI_MAPPING_SET_MAIN__ #include "GuiMapFmriVolume.h" #include "StringUtilities.h" /** * Constructor for mapping to spec files. */ GuiMapFmriMappingSet::GuiMapFmriMappingSet(const QString& outputSpecFileNameIn, const QString& mappingFilesPathIn, const QString& topoFileNameIn, const std::vector& coordFileNamesIn, const QString& averageFiducialFileNameIn, const std::vector& volumes, const QString& fileNameExtensionIn, const QString& descriptionIn, const QString& metricNameHintIn, const QString& structureNameIn, const bool mappingWithAtlasFlagIn, const bool doAverageFiducialFileFlagIn, const bool doAvgOfAllCoordFileFlagIn, const bool doStdDevOfAllCoordFileFlagIn, const bool doStdErrorOfAllCoordFileFlagIn, const bool doMinOfAllCoordFileFlagIn, const bool doMaxOfAllCoordFileFlagIn, const bool doAllCasesCoordFileFlagIn, const bool doMostCommonOfAllCasesFlagIn, const bool doMostCommonExcludeUnidentifiedOfAllCasesFlagIn) { mappingType = MAPPING_TYPE_WITH_SPEC_FILES; mappingFilesPath = mappingFilesPathIn; outputSpecFileName = outputSpecFileNameIn; mappingTopoFileName = topoFileNameIn; mappingCoordFileNames = coordFileNamesIn; mappingWithAtlasFlag = mappingWithAtlasFlagIn; metricOutputType = METRIC_OUTPUT_TYPE_SPEC_FILE; metricNameHint = metricNameHintIn; description = descriptionIn; fileNameExtension = fileNameExtensionIn; structureName = structureNameIn; averageFiducialFileName = averageFiducialFileNameIn; doAverageFiducialFileFlag = doAverageFiducialFileFlagIn; doAvgOfAllCoordFileFlag = doAvgOfAllCoordFileFlagIn; doStdDevOfAllCoordFileFlag = doStdDevOfAllCoordFileFlagIn; doStdErrorOfAllCoordFileFlag = doStdErrorOfAllCoordFileFlagIn; doMinOfAllCoordFileFlag = doMinOfAllCoordFileFlagIn; doMaxOfAllCoordFileFlag = doMaxOfAllCoordFileFlagIn; doAllCasesCoordFileFlag = doAllCasesCoordFileFlagIn; doMostCommonOfAllCasesFlag = doMostCommonOfAllCasesFlagIn; doMostCommonExcludeUnidentifiedOfAllCasesFlag = doMostCommonExcludeUnidentifiedOfAllCasesFlagIn; initializeMetricFile(volumes); } /** * Constructor for mapping to caret surfaces. */ GuiMapFmriMappingSet::GuiMapFmriMappingSet( std::vector caretSurfacesIn, const std::vector& volumes, const QString& fileNameExtensionIn, const QString& descriptionIn) { mappingType = MAPPING_TYPE_WITH_CARET_SURFACES; mappingCaretSurfaces = caretSurfacesIn; mappingWithAtlasFlag = false; metricOutputType = METRIC_OUTPUT_TYPE_CARET_METRIC; metricNameHint = ""; description = descriptionIn; fileNameExtension = fileNameExtensionIn; initializeMetricFile(volumes); averageFiducialFileName = ""; doAverageFiducialFileFlag = false; doAvgOfAllCoordFileFlag = false; doStdDevOfAllCoordFileFlag = false; doStdErrorOfAllCoordFileFlag = false; doMinOfAllCoordFileFlag = false; doMaxOfAllCoordFileFlag = false; doAllCasesCoordFileFlag = true; doMostCommonOfAllCasesFlag = false; } /** * Constructor for mapping to caret surfaces with an atlas. */ GuiMapFmriMappingSet::GuiMapFmriMappingSet(const QString& mappingFilesPathIn, const QString& mappingTopoFileNameIn, const std::vector& mappingCoordFileNamesIn, const QString& averageFiducialFileNameIn, const std::vector& volumes, const QString& fileNameExtensionIn, const QString& descriptionIn, const QString& structureNameIn, const bool doAverageFiducialFileFlagIn, const bool doAvgOfAllCoordFileFlagIn, const bool doStdDevOfAllCoordFileFlagIn, const bool doStdErrorOfAllCoordFileFlagIn, const bool doMinOfAllCoordFileFlagIn, const bool doMaxOfAllCoordFileFlagIn, const bool doAllCasesCoordFileFlagIn, const bool doMostCommonOfAllCasesFlagIn, const bool doMostCommonExcludeUnidentifiedOfAllCasesFlagIn) { mappingType = MAPPING_TYPE_WITH_SPEC_FILES; mappingFilesPath = mappingFilesPathIn; mappingTopoFileName = mappingTopoFileNameIn; mappingCoordFileNames = mappingCoordFileNamesIn; mappingWithAtlasFlag = true; metricOutputType = METRIC_OUTPUT_TYPE_CARET_METRIC; metricNameHint = ""; description = descriptionIn; fileNameExtension = fileNameExtensionIn; structureName = structureNameIn; averageFiducialFileName = averageFiducialFileNameIn; doAverageFiducialFileFlag = doAverageFiducialFileFlagIn; doAvgOfAllCoordFileFlag = doAvgOfAllCoordFileFlagIn; doStdDevOfAllCoordFileFlag = doStdDevOfAllCoordFileFlagIn; doStdErrorOfAllCoordFileFlag = doStdErrorOfAllCoordFileFlagIn; doMinOfAllCoordFileFlag = doMinOfAllCoordFileFlagIn; doMaxOfAllCoordFileFlag = doMaxOfAllCoordFileFlagIn; doAllCasesCoordFileFlag = doAllCasesCoordFileFlagIn; doMostCommonOfAllCasesFlag = doMostCommonOfAllCasesFlagIn; doMostCommonExcludeUnidentifiedOfAllCasesFlag = doMostCommonExcludeUnidentifiedOfAllCasesFlagIn; initializeMetricFile(volumes); } /** * Destructor. */ GuiMapFmriMappingSet::~GuiMapFmriMappingSet() { } /** * Initialize the metric file naming */ void GuiMapFmriMappingSet::initializeMetricFile(const std::vector& volumes) { // // Initialize the name of the metric file // //QDateTime dt = QDateTime::currentDateTime(); const QString dts = DateAndTime::getDateAndTimeForNaming(); //dt.toString("dd_MMM_yyyy_hh_mm_ss"); std::ostringstream str; str << "map_data_" << uniqueNameCounter << "_"; if (metricNameHint.isEmpty() == false) { str << metricNameHint.toAscii().constData() << "_"; } str << dts.toAscii().constData() << fileNameExtension.toAscii().constData(); metricFileName = str.str().c_str(); uniqueNameCounter++; // 01 SEP 2004 // // For each volume // for (int j = 0; j < static_cast(volumes.size()); j++) { // // Get the number of sub-volumes // const GuiMapFmriVolume* v = volumes[j]; const int numSubVolumes = v->getNumberOfSubVolumes(); // // For each subvolume // for (int k = 0; k < numSubVolumes; k++) { GuiMapFmriMetricInfo metricInfo(this, v, j, k); metricMappingInfo.push_back(metricInfo); } } } /** * Get a descriptive label. */ QString GuiMapFmriMappingSet::getDescriptiveLabel() const { QString label; switch (metricOutputType) { case GuiMapFmriMappingSet::METRIC_OUTPUT_TYPE_NONE: label.append("Invalid"); break; case GuiMapFmriMappingSet::METRIC_OUTPUT_TYPE_CARET_METRIC: label.append("Caret ("); if (mappingWithAtlasFlag) { label.append(StringUtilities::fromNumber(static_cast(mappingCoordFileNames.size()))); label.append(" atlas coord files"); } else { label.append(StringUtilities::fromNumber(static_cast(mappingCaretSurfaces.size()))); label.append(" surfaces"); } if (description.isEmpty() == false) { label.append(" - "); label.append(description); } label.append(")"); break; case GuiMapFmriMappingSet::METRIC_OUTPUT_TYPE_SPEC_FILE: label.append(FileUtilities::basename(outputSpecFileName)); label.append(" ("); label.append(StringUtilities::fromNumber(static_cast(mappingCoordFileNames.size()))); if (mappingWithAtlasFlag) { label.append(" atlas coord files"); } else { label.append(" coord files"); } if (description.isEmpty() == false) { label.append(" - "); label.append(description); } label.append(")"); break; } return label; } /** * get the name for a structure for column naming. */ QString GuiMapFmriMappingSet::getStructureForColumnNaming() const { Structure s(structureName); if (s.isLeftCortex()) { return "LEFT"; } else if (s.isRightCortex()) { return "RIGHT"; } return ""; } caret-5.6.4~dfsg.1.orig/caret/GuiMapFmriDialog.h0000664000175000017500000003044011572067322021151 0ustar michaelmichael#ifndef __GUI_MAP_FMRI_DIALOG_H__ #define __GUI_MAP_FMRI_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include class BrainModelSurface; class BrainSet; class QCheckBox; class QComboBox; class QLabel; class QLineEdit; class QListWidget; class QProgressDialog; class QPushButton; class QRadioButton; class QSpinBox; class QTableWidget; class QTextBrowser; class QTextEdit; class QStackedWidget; class QDoubleSpinBox; #include "BrainModelVolumeToSurfaceMapperAlgorithmParameters.h" #include "MapFmriAtlasSpecFileInfo.h" #include "GuiMapFmriMappingSet.h" #include "GuiMapFmriVolume.h" #include "WuQDialog.h" /// Dialog for fmri mapping class GuiMapFmriDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiMapFmriDialog(QWidget* parent, const bool runningAsPartOfCaretIn, bool modal = false, Qt::WindowFlags f = 0); /// Destructor ~GuiMapFmriDialog(); // Initialize the dialog (resets to first page and clears everything) void initializeDialog(); signals: // signal that mapping is complete void signalMappingComplete(); protected slots: /// Set the pages that are valid for viewing according to the current selections. void slotSetAppropriatePages(); /// Called to select the next page (overrides parent method) void slotNext(); /// Called to select the previous page (overrides parent method) void slotBack(); /// Called when close/cancel button is pressed. void slotCloseOrCancelButton(); /// Called when Select Volumes From Disk pushbutton pressed. void slotDiskVolumesPushButton(); /// Called when Select Loaded Volumes pushbutton pressed. void slotLoadedVolumesPushButton(); /// Called when Remove Volumes pushbutton pressed. void slotRemoveVolumesPushButton(); /// Called when add caret surfaces pushbutton pressed. void slotAddCaretSurfacesPushButton(); /// Called when add spec files pushbutton pressed. void slotAddSpecFilesPushButton(); /// Called when add spec file map with atlas pushbutton pressed. void slotAddSpecAtlasPushButton(); /// Called when add caret map with spec pushbutton is pressed. void slotAddCaretMapWithAtlasPushButton(); /// Called when remove mapping sets (caret surfaces/spec files) pushbutton pressed. void slotRemoveMappingSetsPushButton(); /// Called when an algorithm is selected. void slotAlgorithmComboBox(int item); /// load the metric naming page void slotLoadMetricNamingPage(); /// read the metric naming page void slotReadMetricNamingPage(); /// called when metric file name select button pressed void slotMetricFilePushButton(); /// called when a data mapping type is selected void slotDataMappingTypeButtGroup(int item); /// called when a cell in the metric naming table is double clicked void slotMetricNamingTableCellDoubleClicked(int row, int col); protected: /// type of data being mapped enum DATA_MAPPING_TYPE { DATA_MAPPING_TYPE_NONE, DATA_MAPPING_TYPE_METRIC, DATA_MAPPING_TYPE_PAINT }; /// override's parent's done method void done(int r); /// add a page to the dialog void addPage(QWidget* pageIn, const QString& pageTitleIn); /// Adds help information in a read only text widget QWidget* addPageInformation(const QString& title, const QString& text, QTextBrowser* textBrowserIn = NULL); /// map functional volumes to surfaces. void mapVolumesToSurfaces(); /// Load the volumes list box. void loadVolumesListBox(); /// Prepare some pages when they are about to be shown void showPage(QWidget* page); /// create the data mapping type page QWidget* createDataMappingTypePage(); /// create the volume selection page QWidget* createVolumeSelectionPage(); /// create the spec file and surface selection page QWidget* createSpecFileAndSurfaceSelectionPage(); /// create the metric naming page QWidget* createMetricNamingPage(); /// create the algorithm page QWidget* createAlgorithmPage(); /// create the summary page QWidget* createSummaryPage(); /// Get the Caret fiducial surfaces. void getFiducialSurfaces(std::vector& surfaces, bool& haveAnySurface) const; /// load the mapping sets list box void loadMappingSetsListBox(); /// reset (erase) the mapping sets void resetMappingSets(); /// Load the algorithm parameters from the preferences file. void loadAlgorithmParametersFromPreferences(); /// Load the metric naming combo box void loadMetricNamingComboBox(); /// Load the summary text edit void loadSummaryTextEdit(); /// Read the atlases void readAtlases(); /// see if atlases are available bool haveAtlases() const { return (atlasSpecFileInfo.empty() == false); } /// map the volumes to metric files void mapDataToMetricFiles(QProgressDialog& progressDialog); /// map the volumes to paint files void mapDataToPaintFiles(QProgressDialog& progressDialog); /// the mapping parameters BrainModelVolumeToSurfaceMapperAlgorithmParameters mappingParameters; /// type of data being mapped DATA_MAPPING_TYPE dataMappingType; /// running as part of caret flag bool runningAsPartOfCaret; /// push button for selecting caret surfaces QPushButton* addCaretSurfacesPushButton; /// push button for mapping to caret with an atlas QPushButton* addCaretMapWithAtlasPushButton; /// push button for map to spec file with atlas QPushButton* addSpecAtlasPushButton; /// the data mapping type page QWidget* pageDataMappingType; /// the volume selection page QWidget* pageVolumeSelection; /// the spec file and surface selection page QWidget* pageSpecFileAndSurfaceSelection; /// the metric naming page QWidget* pageMetricNaming; /// the algorithm page QWidget* pageAlgorithm; /// the summary page QWidget* pageSummary; /// mapping type functional radio button QRadioButton* mappingTypeFunctionalRadioButton; /// mapping type paint radio button QRadioButton* mappingTypePaintRadioButton; /// functional volumes list box QListWidget* volumeListBox; /// volumes that are to be mapped std::vector volumesToBeMapped; /// list box for mapping sets QListWidget* mappingSetListBox; /// surfaces/spec files for mapping std::vector mappingSets; /// metric file name push button QPushButton* metricFilePushButton; /// metric file name line edit QLineEdit* metricFileNameLineEdit; /// the metric naming table QTableWidget* metricNamingTable; /// the metric naming mapping set combo box QComboBox* metricMappingSetComboBox; /// metric naming columns enum { METRIC_NAMING_COLUMN_NAME = 0, METRIC_NAMING_COLUMN_COMMENT = 1, METRIC_NAMING_COLUMN_SURFACE = 2, METRIC_NAMING_COLUMN_VOLUME = 3, METRIC_NAMING_COLUMN_SUB_VOLUME = 4, METRIC_NAMING_COLUMN_NEG_THRESH = 5, METRIC_NAMING_COLUMN_POS_THRESH = 6, METRIC_NAMING_NUMBER_OF_COLUMNS = 7 // MUST BE LAST }; /// algorithm selection combo box QComboBox* algorithmComboBox; /// algorithm information text edit QTextBrowser* algorithmInformationTextEdit; /// algorithm parameters widget stack QStackedWidget* algorithmParameterWidgetStack; /// algorithm average nodes parameters widget QWidget* algorithmMetricAverageNodesParametersBox; /// algorithm average voxel parameters widget QWidget* algorithmMetricAverageVoxelParametersBox; /// algorithm enclosing voxel parameters widget QWidget* algorithmMetricEnclosingVoxelParametersBox; /// algorithm gaussian parameters widget QWidget* algorithmMetricGaussianParametersBox; /// algorithm interpolated voxel parameters widget QWidget* algorithmMetricInterpolatedVoxelParametersBox; /// algorithm maximum voxel parameters widget QWidget* algorithmMetricMaximumVoxelParametersBox; /// algorithm mcw brain fish parameters widget QWidget* algorithmMetricMcwBrainFishParametersBox; /// algorithm strongest voxel parameters widget QWidget* algorithmMetricStrongestVoxelParametersBox; /// algorithm paint enclosing voxel parameters widget QWidget* algorithmPaintEnclosingVoxelParametersBox; /// algorithm average voxel neighbor size float spin box QDoubleSpinBox* algorithmAverageVoxelNeighborDoubleSpinBox; /// algorithm gaussian neighbor size float spin box QDoubleSpinBox* algorithmGaussianNeighborDoubleSpinBox; /// algorithm maximum voxel neighbor size float spin box QDoubleSpinBox* algorithmMaximumVoxelNeighborDoubleSpinBox; /// algorithm gaussian sigma norm float spin box QDoubleSpinBox* algorithmGaussianSigmaNormDoubleSpinBox; /// algorithm gaussian sigma tang float spin box QDoubleSpinBox* algorithmGaussianSigmaTangDoubleSpinBox; /// algorithm gaussian norm below float spin box QDoubleSpinBox* algorithmGaussianNormBelowDoubleSpinBox; /// algorithm gaussian norm above float spin box QDoubleSpinBox* algorithmGaussianNormAboveDoubleSpinBox; /// algorithm gaussian tang cutoff float spin box QDoubleSpinBox* algorithmGaussianTangCutoffDoubleSpinBox; /// algorithm brain fish max distance float spin box QDoubleSpinBox* algorithmBrainFishMaxDistanceDoubleSpinBox; /// algorithm brain fish splat factor spin box QSpinBox* algorithmBrainFishSplatFactorSpinBox; /// algorithm strongest voxel neighbor size float spin box QDoubleSpinBox* algorithmStrongestVoxelNeighborDoubleSpinBox; /// the summary page text edit QTextEdit* summaryTextEdit; /// directory containing the atlas files QString atlasFilesDirectory; /// info about atlas spec files std::vector atlasSpecFileInfo; /// extension for output data file QString outputDataFileExtension; /// the loaded volumes push button QPushButton* loadedVolumesPushButton; /// enable entry of volume thresholds check box QCheckBox* volumeEnterThreshCheckBox; /// widget stack for pages in dialog QStackedWidget* pagesStackedWidget; /// next push button QPushButton* nextPushButton; /// label for title of current page QLabel* currentPageTitleLabel; /// titles for pages std::vector pageTitles; }; #endif // __GUI_MAP_FMRI_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiMapFmriDialog.cxx0000664000175000017500000053445711572067322021545 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include "WuQFileDialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "BrainModelVolumeToSurfaceMapper.h" #include "BrainSet.h" #include "DebugControl.h" #include "FileFilters.h" #include "FileUtilities.h" #include "GaussianComputation.h" #include "GuiCopySpecFileDialog.h" #include "GuiFileDialogWithInstructions.h" #include "GuiMainWindow.h" #include "GuiMapFmriAtlasDialog.h" #include "GuiMapFmriDialog.h" #include "GuiMapFmriSpecFileTopoCoordDialog.h" #include "GuiMapFmriThresholdDialog.h" #include "GuiSumsDialog.h" #include "MetricFile.h" #include "PaintFile.h" #include "StringUtilities.h" #include #include "QtListBoxSelectionDialog.h" #include "QtTextEditDialog.h" #include "QtUtilities.h" #include "global_variables.h" /** * Constructor. */ GuiMapFmriDialog::GuiMapFmriDialog(QWidget* parent, const bool runningAsPartOfCaretIn, bool modalFlag, Qt::WindowFlags f) : WuQDialog(parent, f) { setModal(modalFlag); dataMappingType = DATA_MAPPING_TYPE_NONE; readAtlases(); setWindowTitle("Map Volumes To Surfaces"); runningAsPartOfCaret = runningAsPartOfCaretIn; // // Label for title of current page // currentPageTitleLabel = new QLabel; // // Stacked widget for all pages // pagesStackedWidget = new QStackedWidget; pageDataMappingType = createDataMappingTypePage(); addPage(pageDataMappingType, "Data Mapping Type"); pageVolumeSelection = createVolumeSelectionPage(); addPage(pageVolumeSelection, "Volume Selection"); pageSpecFileAndSurfaceSelection = createSpecFileAndSurfaceSelectionPage(); addPage(pageSpecFileAndSurfaceSelection, "Spec File And Surface Selection"); pageMetricNaming = createMetricNamingPage(); addPage(pageMetricNaming, "Data File Naming"); pageAlgorithm = createAlgorithmPage(); addPage(pageAlgorithm, "Mapping Algorithm"); pageSummary = createSummaryPage(); addPage(pageSummary, "Summary"); // // Back page push button // QPushButton* backPushButton = new QPushButton("Back"); backPushButton->setAutoDefault(false); QObject::connect(backPushButton, SIGNAL(clicked()), this, SLOT(slotBack())); // // Next push button // nextPushButton = new QPushButton("Next"); nextPushButton->setAutoDefault(true); QObject::connect(nextPushButton, SIGNAL(clicked()), this, SLOT(slotNext())); // // Close push button // QPushButton* closePushButton = new QPushButton("Close"); closePushButton->setAutoDefault(true); QObject::connect(closePushButton, SIGNAL(clicked()), this, SLOT(slotCloseOrCancelButton())); QtUtilities::makeButtonsSameSize(backPushButton, nextPushButton, closePushButton); if (runningAsPartOfCaret) { // // Make the Cancel button the Quit button // closePushButton->setText("Close"); } else { // // Make the Cancel button the Quit button // closePushButton->setText("Quit"); } QObject::connect(closePushButton, SIGNAL(clicked()), this, SLOT(slotCloseOrCancelButton())); // // Layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->addWidget(backPushButton); buttonsLayout->addWidget(nextPushButton); buttonsLayout->addWidget(closePushButton); // // Layout for dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->addWidget(currentPageTitleLabel); dialogLayout->addWidget(pagesStackedWidget); dialogLayout->addLayout(buttonsLayout); slotSetAppropriatePages(); // // Start with the data mapping type selection page (skips copy/download spec page) // showPage(pageDataMappingType); } /** * Destructor. */ GuiMapFmriDialog::~GuiMapFmriDialog() { for (int i = 0; i < static_cast(volumesToBeMapped.size()); i++) { delete volumesToBeMapped[i]; volumesToBeMapped[i] = NULL; } resetMappingSets(); } /** * Called when close/cancel button pressed. */ void GuiMapFmriDialog::slotCloseOrCancelButton() { if (runningAsPartOfCaret == false) { if (QMessageBox::warning(this, "Confirm", "Are you sure you want to quit ?", (QMessageBox::Yes | QMessageBox::No), QMessageBox::Yes) == QMessageBox::No) { return; } } WuQDialog::close(); } /** * Overrides parents close method. */ void GuiMapFmriDialog::done(int r) { // // Do nothing - overriding this method prevents the window from closing // when the Finish button is pressed. // WuQDialog::done(r); } /** * Initialize the dialog (resets to first page and clears everything). */ void GuiMapFmriDialog::initializeDialog() { atlasSpecFileInfo.clear(); volumesToBeMapped.clear(); mappingSets.clear(); readAtlases(); mappingTypeFunctionalRadioButton->setChecked(false); mappingTypePaintRadioButton->setChecked(false); mappingTypeFunctionalRadioButton->setChecked(true); dataMappingType = DATA_MAPPING_TYPE_METRIC; slotDataMappingTypeButtGroup(dataMappingType); showPage(pageDataMappingType); } /** * add a page to the dialog. */ void GuiMapFmriDialog::addPage(QWidget* pageIn, const QString& pageTitleIn) { pagesStackedWidget->addWidget(pageIn); pageTitles.push_back(pageTitleIn); } /** * Called to select the next page. */ void GuiMapFmriDialog::slotNext() { // // If the current page is volume selection // if (pagesStackedWidget->currentWidget() == pageVolumeSelection) { } // // If the current page is the metric naming page // if (pagesStackedWidget->currentWidget() == pageMetricNaming) { // // Read the metric naming page // slotReadMetricNamingPage(); } // // If the current page is the algorithm page // if (pagesStackedWidget->currentWidget() == pageAlgorithm) { } // // Determine and show the next page // int nextIndx = pagesStackedWidget->currentIndex() + 1; if (nextIndx < pagesStackedWidget->count()) { QWidget* nextWidget = pagesStackedWidget->widget(nextIndx); if (nextWidget == pageAlgorithm) { switch (dataMappingType) { case DATA_MAPPING_TYPE_NONE: break; case DATA_MAPPING_TYPE_METRIC: break; case DATA_MAPPING_TYPE_PAINT: nextIndx++; nextWidget = pagesStackedWidget->widget(nextIndx); break; } } showPage(nextWidget); } else { mapVolumesToSurfaces(); } } /** * Called to select the previous page. */ void GuiMapFmriDialog::slotBack() { // // If the current page is the metric naming page // if (pagesStackedWidget->currentWidget() == pageMetricNaming) { // // Read the metric naming page // slotReadMetricNamingPage(); } // // If the current page is the algorithm page // if (pagesStackedWidget->currentWidget() == pageAlgorithm) { } // // Determine and show the next page // int backIndx = pagesStackedWidget->currentIndex() - 1; if (backIndx >= 0) { QWidget* backWidget = pagesStackedWidget->widget(backIndx); if (backWidget == pageAlgorithm) { switch (dataMappingType) { case DATA_MAPPING_TYPE_NONE: break; case DATA_MAPPING_TYPE_METRIC: break; case DATA_MAPPING_TYPE_PAINT: backIndx--; backWidget = pagesStackedWidget->widget(backIndx); break; } } showPage(backWidget); } } /** * Prepare some pages when they are about to be shown */ void GuiMapFmriDialog::showPage(QWidget* page) { nextPushButton->setText("Next"); // // If the page about to be shown is the volume selection page // if (page == pageVolumeSelection) { // // Load the selected volumes into the list box // loadVolumesListBox(); } // // If the page about to be shown is the mapping surface selection page // if (page == pageSpecFileAndSurfaceSelection) { // // Disable buttons if atlas or caret surfaces not available // std::vector surfaces; bool haveAnySurface = false; getFiducialSurfaces(surfaces, haveAnySurface); const bool haveCaretFiducialSurfaces = (surfaces.empty() == false); addCaretSurfacesPushButton->setEnabled(haveCaretFiducialSurfaces); addCaretMapWithAtlasPushButton->setEnabled(haveAnySurface && haveAtlases()); addSpecAtlasPushButton->setEnabled(haveAtlases()); // // Load the mapping sets // loadMappingSetsListBox(); } // // If page about to be shown is metric naming // if (page == pageMetricNaming) { // // load the metric naming combo box // loadMetricNamingComboBox(); // // Load the metric naming data // slotLoadMetricNamingPage(); } // // If page about to be shown is the algorithm page // if (page == pageAlgorithm) { // // Load the algorithm parameters into the widgets // loadAlgorithmParametersFromPreferences(); } // // If page about to be shown is the summary page // if (page == pageSummary) { // // Load the text edit in the summary page // loadSummaryTextEdit(); nextPushButton->setText("Finish"); } else { nextPushButton->setEnabled(false); } pagesStackedWidget->setCurrentWidget(page); const int indx = pagesStackedWidget->currentIndex(); currentPageTitleLabel->setText("" + pageTitles[indx] + ""); slotSetAppropriatePages(); } /** * Read the atlases */ void GuiMapFmriDialog::readAtlases() { // // Look for atlas spec files in Caret installation directory. // atlasFilesDirectory = theMainWindow->getBrainSet()->getCaretHomeDirectory(); atlasFilesDirectory.append("/data_files/fmri_mapping_files"); std::vector files; QString fileExt("*"); fileExt.append(SpecFile::getSpecFileExtension()); FileUtilities::findFilesInDirectory(atlasFilesDirectory, QStringList(fileExt), files); // // Process each of the atlas spec files // for (int i = 0; i < static_cast(files.size()); i++) { // // Prepend path to name of atlas spec file // QString name(atlasFilesDirectory); name.append("/"); name.append(files[i]); // // See if spec files is valid // MapFmriAtlasSpecFileInfo asfi(name); if (asfi.getDataValid()) { atlasSpecFileInfo.push_back(asfi); } else { std::cout << "WARNING: invalid atlas spec file: " << name.toAscii().constData() << std::endl; } } // // Sort atlas spec file info // std::sort(atlasSpecFileInfo.begin(), atlasSpecFileInfo.end()); } /** * Set the pages that are valid for viewing according to the current selections. */ void GuiMapFmriDialog::slotSetAppropriatePages() { bool nextButtonEnabled = true; QWidget* currentWidget = pagesStackedWidget->currentWidget(); // // Only allow next on data mapping if a type has been selected // if (currentWidget == pageDataMappingType) { nextButtonEnabled = (dataMappingType != DATA_MAPPING_TYPE_NONE); } // // Functional volume page next button is valid if volumes selected // if (currentWidget == pageVolumeSelection) { nextButtonEnabled = (volumesToBeMapped.empty() == false); } // // Mapping sets page next button is valid if caret surfaces/spec files selected // if (currentWidget == pageSpecFileAndSurfaceSelection) { nextButtonEnabled = (mappingSets.empty() == false); } nextPushButton->setEnabled(nextButtonEnabled); } /** * Called to map functional volume(s) to the surface(s). */ void GuiMapFmriDialog::mapVolumesToSurfaces() { nextPushButton->setEnabled(false); QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); // // Hide this dialog // this->hide(); // // Count number of steps for progress dialog // int progressSteps = 0; for (int i = 0; i < static_cast(mappingSets.size()); i++) { const int num = mappingSets[i].getNumberOfMetricMappingInfo(); for (int j = 0; j < num; j++) { progressSteps += mappingSets[i].getMetricMappingInfo(j)->getNumberOfMetricColumns(); } if (mappingSets[i].getDoAverageFiducialFileFlag()) { progressSteps++; } if (mappingSets[i].getDoAvgOfAllCoordFileFlag() || mappingSets[i].getDoMostCommonOfAllCasesFlag() || mappingSets[i].getDoMostCommonExcludeUnidentifiedOfAllCasesFlag() || mappingSets[i].getDoStdDevOfAllCoordFileFlag() || mappingSets[i].getDoStdErrorOfAllCoordFileFlag() || mappingSets[i].getDoMinOfAllCoordFileFlag() || mappingSets[i].getDoMaxOfAllCoordFileFlag()) { progressSteps++; } } // // Create a progress dialog // QWidget* progressParent = parentWidget(); QProgressDialog progressDialog(progressParent); progressDialog.move(progressParent->pos()); progressDialog.setMaximum(progressSteps + 1); progressDialog.setValue(0); progressDialog.setWindowTitle("Map Volumes"); progressDialog.show(); // // Save the current directory // const QString curDir(QDir::currentPath()); // // Map the data // switch (dataMappingType) { case DATA_MAPPING_TYPE_NONE: break; case DATA_MAPPING_TYPE_METRIC: mapDataToMetricFiles(progressDialog); break; case DATA_MAPPING_TYPE_PAINT: mapDataToPaintFiles(progressDialog); break; } // // Restore the current directory // QDir::setCurrent(curDir); QApplication::restoreOverrideCursor(); progressDialog.cancel(); // // show this dialog // show(); QApplication::beep(); emit signalMappingComplete(); } /** * map the volumes to paint files. */ void GuiMapFmriDialog::mapDataToPaintFiles(QProgressDialog& progressDialog) { // // For each mapping set // for (int i = 0; i < static_cast(mappingSets.size()); i++) { const QString savedDirectory(QDir::currentPath()); // // Get the mapping set // GuiMapFmriMappingSet& mms = mappingSets[i]; // // Get the number of items in the set // const int numMappingInfo = mms.getNumberOfMetricMappingInfo(); // // Create the output paint file // PaintFile outputPaintFile; // // For each set of mapping info // for (int j = 0; j < numMappingInfo; j++) { // // Save the current directory // const QString savedDirectory(QDir::currentPath()); // // Get the topo file name, coord file names, and caret surfaces // const QString mappingTopoFileName(mms.getMappingTopoFileName()); std::vector mappingCoordFileNames; mms.getMappingCoordFileNames(mappingCoordFileNames); std::vector mappingCaretSurfaces; mms.getMappingCaretSurfaces(mappingCaretSurfaces); // // Get the metric info // const GuiMapFmriMetricInfo* metricInfo = mms.getMetricMappingInfo(j); // // Create a metric file for mapping the data // PaintFile mappingPaintFile; // // Do each column in the metric info // const int numberOfColumns = metricInfo->getNumberOfMetricColumns(); for (int metricColumn = 0; metricColumn < numberOfColumns; metricColumn++) { // // There is one metric column for each surface // const int surfaceIndex = metricColumn; // // Get volume information // const int volumeIndex = metricInfo->getVolumeIndex(); const int subVolumeIndex = metricInfo->getSubVolumeIndex(); // // Update the progress dialog // qApp->processEvents(); // note: qApp is global in QApplication if (progressDialog.wasCanceled()) { return; } QString progressMessage("Mapping Volume: "); progressMessage.append(volumesToBeMapped[volumeIndex]->getDescriptiveName()); progressMessage.append("\nSub-Volume: "); progressMessage.append(volumesToBeMapped[volumeIndex]->getSubVolumeName(subVolumeIndex)); progressMessage.append(" to \n"); progressMessage.append(metricInfo->getSurfaceNameForMetricColumn(metricColumn)); progressMessage.append("."); progressDialog.setLabelText(progressMessage); progressDialog.setValue(progressDialog.value() + 1); progressDialog.show(); // // Get the brain set and surface for mapping the data // BrainSet* bs = NULL; BrainModelSurface* bms = NULL; bool createdBrainSet = false; // // Set/Load the brain set and the brain model surface // switch (mms.getMappingType()) { case GuiMapFmriMappingSet::MAPPING_TYPE_NONE: break; case GuiMapFmriMappingSet::MAPPING_TYPE_WITH_CARET_SURFACES: bs = theMainWindow->getBrainSet(); bms = mappingCaretSurfaces[surfaceIndex]; break; case GuiMapFmriMappingSet::MAPPING_TYPE_WITH_SPEC_FILES: { // // Set to the spec file directory // const QString directory(mms.getMappingFilesPath()); if (directory.isEmpty() == false) { QDir::setCurrent(directory); } // // Create a spec file and initialize it for mapping files // SpecFile sf; sf.setTopoAndCoordSelected(mappingTopoFileName, mappingCoordFileNames[surfaceIndex], sf.getStructure()); // // Create the brain set // bs = new BrainSet; createdBrainSet = true; // // Load the brain set // std::vector errorMessages; bs->readSpecFile(BrainSet::SPEC_FILE_READ_MODE_NORMAL, sf, "mapping_spec", errorMessages, NULL, NULL); if (errorMessages.empty() == false) { progressDialog.cancel(); QString msg("Error creating BrainSet for mapping data.\n"); msg.append(StringUtilities::combine(errorMessages, "\n")); QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", msg, "OK"); return; } // // If spec file read correctly, there is one brain model // if (bs->getNumberOfBrainModels() == 1) { // // Get the surface // bms = bs->getBrainModelSurface(0); // // Make sure valid // if (bms == NULL) { progressDialog.cancel(); QString msg("No brain model surface after reading "); msg.append(mappingTopoFileName); msg.append(" and "); msg.append(mappingCoordFileNames[surfaceIndex]); QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", msg); delete bs; return; } } else { progressDialog.cancel(); QString msg("No brain model after reading "); msg.append(mappingTopoFileName); msg.append(" and "); msg.append(mappingCoordFileNames[surfaceIndex]); QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", msg); delete bs; return; } } break; } // // Allocate number of nodes and columns for metric file // if (mappingPaintFile.getNumberOfNodes() == 0) { mappingPaintFile.setNumberOfNodesAndColumns(bs->getNumberOfNodes(), numberOfColumns); } // // Volume data that is to be mapped // VolumeFile* vf = NULL; bool createdVolumeFile = false; // // Get info about volume that is to be mapped // GuiMapFmriVolume* fmriVolume = volumesToBeMapped[volumeIndex]; switch(fmriVolume->getFmriVolumeType()) { case GuiMapFmriVolume::FMRI_VOLUME_TYPE_FILE_ON_DISK: // // Read in the volume data // vf = new VolumeFile; createdVolumeFile = true; try { vf->readFile(fmriVolume->getVolumeFileName(), subVolumeIndex); } catch (FileException& e) { } break; case GuiMapFmriVolume::FMRI_VOLUME_TYPE_FILE_IN_MEMORY: vf = fmriVolume->getInMemoryVolumeFile(); break; } // // Create the mapper class // mappingParameters.setAlgorithm( BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_PAINT_ENCLOSING_VOXEL); BrainModelVolumeToSurfaceMapper bmvsmm( bs, bms, vf, &mappingPaintFile, mappingParameters, metricColumn, metricInfo->getMetricColumnName(metricColumn)); // // Run the mapper // try { bmvsmm.execute(); } catch (BrainModelAlgorithmException& e) { progressDialog.cancel(); QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); if (createdBrainSet) { delete bs; } return; } // // Prepend user's column comment since mapper overwrites with mapping parameters // QString columnComment(metricInfo->getMetricColumnComment(metricColumn)); if (columnComment.isEmpty() == false) { columnComment.append("\n"); mappingPaintFile.prependToColumnComment(metricColumn, columnComment); } // // Free up the volume file if needed // if (createdVolumeFile) { delete vf; vf = NULL; } // // Free up the brain set if it was created // if (createdBrainSet) { delete bs; bs = NULL; } } // for (int metricColumn // // Do most common if needed // if (mms.getDoMostCommonOfAllCasesFlag() || mms.getDoMostCommonExcludeUnidentifiedOfAllCasesFlag()) { // // Update progress dialog // QString progressMessage("Generating "); QString mostCommonName; if (mms.getDoMostCommonOfAllCasesFlag()) { mostCommonName = metricInfo->getMetricMostCommonValueColumnName(); progressMessage.append("\nMost Common "); } progressDialog.setLabelText(progressMessage); progressDialog.show(); QString mostCommonExcludeUnidentifiedName; if (mms.getDoMostCommonExcludeUnidentifiedOfAllCasesFlag()) { mostCommonExcludeUnidentifiedName = metricInfo->getMetricMostCommonExcludeUnidentifiedValueColumnName(); progressMessage.append("\nMost Common Exclude No ID"); } progressDialog.setLabelText(progressMessage); progressDialog.show(); // // Find most common // mappingPaintFile.appendMostCommon(mostCommonName, mostCommonExcludeUnidentifiedName); // // Add comments // if (mostCommonName.isEmpty() == false) { const int mostCommonColumn = mappingPaintFile.getColumnWithName(mostCommonName); if (mostCommonColumn >= 0) { mappingPaintFile.prependToColumnComment(mostCommonColumn, metricInfo->getMetricMostCommonValueComment()); } } if (mostCommonExcludeUnidentifiedName.isEmpty() == false) { const int mostCommonExcludeUnidentifiedColumn = mappingPaintFile.getColumnWithName(mostCommonExcludeUnidentifiedName); if (mostCommonExcludeUnidentifiedColumn >= 0) { mappingPaintFile.prependToColumnComment(mostCommonExcludeUnidentifiedColumn, metricInfo->getMetricMostCommonExcludeUnidentifiedValueComment()); } } } // map most common // // Map to Average Fiducial Surface // PaintFile averageFiducialPaintFile; if (mms.getDoAverageFiducialFileFlag()) { // // Get volume information // const int volumeIndex = metricInfo->getVolumeIndex(); const int subVolumeIndex = metricInfo->getSubVolumeIndex(); // // Update the progress dialog // qApp->processEvents(); // note: qApp is global in QApplication if (progressDialog.wasCanceled()) { return; } QString progressMessage("Mapping Volume: "); progressMessage.append(volumesToBeMapped[volumeIndex]->getDescriptiveName()); progressMessage.append("\nSub-Volume: "); progressMessage.append(volumesToBeMapped[volumeIndex]->getSubVolumeName(subVolumeIndex)); progressMessage.append(" to \n"); progressMessage.append(metricInfo->getMetricAverageFiducialCoordColumnName()); progressMessage.append("."); progressDialog.setLabelText(progressMessage); progressDialog.setValue(progressDialog.value() + 1); progressDialog.show(); // // Set to the spec file directory // const QString directory(mms.getMappingFilesPath()); if (directory.isEmpty() == false) { QDir::setCurrent(directory); } // // Create a spec file and initialize it for mapping files // SpecFile sf; sf.setTopoAndCoordSelected(mappingTopoFileName, mms.getAverageFiducialCoordFileName(), sf.getStructure()); // // Create the brain set // BrainSet* bs = new BrainSet; BrainModelSurface* bms = NULL; // // Load the brain set // std::vector errorMessages; bs->readSpecFile(BrainSet::SPEC_FILE_READ_MODE_NORMAL, sf, "mapping_spec", errorMessages, NULL, NULL); if (errorMessages.empty() == false) { progressDialog.cancel(); QString msg("Error creating BrainSet for mapping data.\n"); msg.append(StringUtilities::combine(errorMessages, "\n")); QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", msg); return; } // // If spec file read correctly, there is one brain model // if (bs->getNumberOfBrainModels() == 1) { // // Get the surface // bms = bs->getBrainModelSurface(0); // // Make sure valid // if (bms == NULL) { progressDialog.cancel(); QString msg("No brain model surface after reading "); msg.append(mappingTopoFileName); msg.append(" and "); msg.append(mms.getAverageFiducialCoordFileName()); QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", msg); delete bs; return; } } else { progressDialog.cancel(); QString msg("No brain model after reading "); msg.append(mappingTopoFileName); msg.append(" and "); msg.append(mms.getAverageFiducialCoordFileName()); QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", msg); delete bs; return; } // // Allocate number of nodes and columns for paint file // averageFiducialPaintFile.setNumberOfNodesAndColumns(bs->getNumberOfNodes(), 1); // // Volume data that is to be mapped // VolumeFile* vf = NULL; bool createdVolumeFile = false; // // Get info about volume that is to be mapped // GuiMapFmriVolume* fmriVolume = volumesToBeMapped[volumeIndex]; switch(fmriVolume->getFmriVolumeType()) { case GuiMapFmriVolume::FMRI_VOLUME_TYPE_FILE_ON_DISK: // // Read in the volume data // vf = new VolumeFile; createdVolumeFile = true; try { vf->readFile(fmriVolume->getVolumeFileName(), subVolumeIndex); } catch (FileException& e) { } break; case GuiMapFmriVolume::FMRI_VOLUME_TYPE_FILE_IN_MEMORY: vf = fmriVolume->getInMemoryVolumeFile(); break; } // // Create the mapper class // mappingParameters.setAlgorithm( BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_PAINT_ENCLOSING_VOXEL); BrainModelVolumeToSurfaceMapper bmvsmm( bs, bms, vf, &averageFiducialPaintFile, mappingParameters, 0, metricInfo->getMetricAverageFiducialCoordColumnName()); // // Run the mapper // try { bmvsmm.execute(); } catch (BrainModelAlgorithmException& e) { progressDialog.cancel(); QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); delete bs; return; } // // Prepend user's column comment since mapper overwrites with mapping parameters // QString columnComment(metricInfo->getMetricAverageFiducialCoordComment()); if (columnComment.isEmpty() == false) { columnComment.append("\n"); averageFiducialPaintFile.prependToColumnComment(0, columnComment); } // // Free up the volume file if needed // if (createdVolumeFile) { delete vf; vf = NULL; } // // Free up the brain set // delete bs; bs = NULL; // // Add onto output paint file // outputPaintFile.append(averageFiducialPaintFile); } // // Append most common columns first so that they are before indiv cases // bool haveMostCommonCases = false; std::vector paintColumnDestination(mappingPaintFile.getNumberOfColumns(), MetricFile::APPEND_COLUMN_NEW); for (int n = 0; n < mappingPaintFile.getNumberOfColumns(); n++) { if (n >= metricInfo->getNumberOfMetricColumns()) { paintColumnDestination[n] = PaintFile::APPEND_COLUMN_NEW; haveMostCommonCases = true; } else { paintColumnDestination[n] = PaintFile::APPEND_COLUMN_DO_NOT_LOAD; } } if (haveMostCommonCases) { outputPaintFile.append(mappingPaintFile, paintColumnDestination, PaintFile::FILE_COMMENT_MODE_APPEND); } // // Append indiv cases. // if (mms.getDoAllCasesCoordFileFlag()) { for (int n = 0; n < mappingPaintFile.getNumberOfColumns(); n++) { if (n < metricInfo->getNumberOfMetricColumns()) { paintColumnDestination[n] = PaintFile::APPEND_COLUMN_NEW; } else { paintColumnDestination[n] = PaintFile::APPEND_COLUMN_DO_NOT_LOAD; } } NodeAttributeFile::FILE_COMMENT_MODE fcm = PaintFile::FILE_COMMENT_MODE_APPEND; if (haveMostCommonCases) { fcm = MetricFile::FILE_COMMENT_MODE_LEAVE_AS_IS; } outputPaintFile.append(mappingPaintFile, paintColumnDestination, fcm); } } // number of metric mapping info // // Update Caret/Spec file with new metric data // switch (mms.getMetricOutputType()) { case GuiMapFmriMappingSet::METRIC_OUTPUT_TYPE_NONE: break; case GuiMapFmriMappingSet::METRIC_OUTPUT_TYPE_CARET_METRIC: // // Append to existing metrics // { PaintFile* currentPaintFile = theMainWindow->getBrainSet()->getPaintFile(); try { currentPaintFile->append(outputPaintFile); } catch (FileException& e) { progressDialog.cancel(); QString msg("Data mapped but unable to append to current paint file.\n"); msg.append(e.whatQString()); QMessageBox::critical(this, "ERROR", msg); return; } } break; case GuiMapFmriMappingSet::METRIC_OUTPUT_TYPE_SPEC_FILE: { // // Change to the spec file's directory // const QString directory(FileUtilities::dirname(mms.getOutputSpecFileName())); if (directory.isEmpty() == false) { QDir::setCurrent(directory); } // // Metric file is always written in same directory as spec file // so chop off path // const QString metricName(FileUtilities::basename(mms.getMetricFileName())); // // Save the metric file // try { outputPaintFile.writeFile(metricName); } catch (FileException& e) { progressDialog.cancel(); QString msg("Unable to save paint file "); msg.append(metricName); msg.append("\n"); msg.append(e.whatQString()); QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", msg); return; } // // Update the spec file // SpecFile sf; try { // // Read the spec file for updating // sf.readFile(mms.getOutputSpecFileName()); // // Add the metric file to the spec file // sf.addToSpecFile(SpecFile::getPaintFileTag(), metricName, "", false); // // Write the spec file // sf.writeFile(mms.getOutputSpecFileName()); // // Add the spec file to the recent spec files in preferences // PreferencesFile* pf = theMainWindow->getBrainSet()->getPreferencesFile(); pf->addToRecentSpecFiles(mms.getOutputSpecFileName(), true); } catch (FileException& e) { progressDialog.cancel(); QString msg("Unable to update spec file: "); msg.append(mms.getOutputSpecFileName()); msg.append("\n"); msg.append(e.whatQString()); QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", msg); return; } } break; } // // Restore directory // QDir::setCurrent(savedDirectory); } // for each mapping set } /** * map the volumes to metric files. */ void GuiMapFmriDialog::mapDataToMetricFiles(QProgressDialog& progressDialog) { // // For each mapping set // for (int i = 0; i < static_cast(mappingSets.size()); i++) { const QString savedDirectory(QDir::currentPath()); // // Get the mapping set // GuiMapFmriMappingSet& mms = mappingSets[i]; // // Get the number of items in the set // const int numMappingInfo = mms.getNumberOfMetricMappingInfo(); // // Create the output metric file // MetricFile outputMetricFile; // // For each set of mapping info // for (int j = 0; j < numMappingInfo; j++) { // // Save the current directory // const QString savedDirectory(QDir::currentPath()); // // Get the topo file name, coord file names, and caret surfaces // const QString mappingTopoFileName(mms.getMappingTopoFileName()); std::vector mappingCoordFileNames; mms.getMappingCoordFileNames(mappingCoordFileNames); std::vector mappingCaretSurfaces; mms.getMappingCaretSurfaces(mappingCaretSurfaces); // // Get the metric info // const GuiMapFmriMetricInfo* metricInfo = mms.getMetricMappingInfo(j); // // Create a metric file for mapping the data // MetricFile mappingMetricFile; // // Do each column in the metric info // const int numberOfColumns = metricInfo->getNumberOfMetricColumns(); for (int metricColumn = 0; metricColumn < numberOfColumns; metricColumn++) { // // There is one metric column for each surface // const int surfaceIndex = metricColumn; // // Get volume information // const int volumeIndex = metricInfo->getVolumeIndex(); const int subVolumeIndex = metricInfo->getSubVolumeIndex(); // // Update the progress dialog // qApp->processEvents(); // note: qApp is global in QApplication if (progressDialog.wasCanceled()) { return; } QString progressMessage("Mapping Volume: "); progressMessage.append(volumesToBeMapped[volumeIndex]->getDescriptiveName()); progressMessage.append("\nSub-Volume: "); progressMessage.append(volumesToBeMapped[volumeIndex]->getSubVolumeName(subVolumeIndex)); progressMessage.append(" to \n"); progressMessage.append(metricInfo->getSurfaceNameForMetricColumn(metricColumn)); progressMessage.append("."); progressDialog.setLabelText(progressMessage); progressDialog.setValue(progressDialog.value() + 1); progressDialog.show(); // // Get the brain set and surface for mapping the data // BrainSet* bs = NULL; BrainModelSurface* bms = NULL; bool createdBrainSet = false; // // Set/Load the brain set and the brain model surface // switch (mms.getMappingType()) { case GuiMapFmriMappingSet::MAPPING_TYPE_NONE: break; case GuiMapFmriMappingSet::MAPPING_TYPE_WITH_CARET_SURFACES: bs = theMainWindow->getBrainSet(); bms = mappingCaretSurfaces[surfaceIndex]; break; case GuiMapFmriMappingSet::MAPPING_TYPE_WITH_SPEC_FILES: { // // Set to the spec file directory // const QString directory(mms.getMappingFilesPath()); if (directory.isEmpty() == false) { QDir::setCurrent(directory); } // // Create a spec file and initialize it for mapping files // SpecFile sf; sf.setTopoAndCoordSelected(mappingTopoFileName, mappingCoordFileNames[surfaceIndex], sf.getStructure()); // // Create the brain set // bs = new BrainSet; createdBrainSet = true; // // Load the brain set // std::vector errorMessages; bs->readSpecFile(BrainSet::SPEC_FILE_READ_MODE_NORMAL, sf, "mapping_spec", errorMessages, NULL, NULL); if (errorMessages.empty() == false) { progressDialog.cancel(); QString msg("Error creating BrainSet for mapping data.\n"); msg.append(StringUtilities::combine(errorMessages, "\n")); QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", msg); return; } // // If spec file read correctly, there is one brain model // if (bs->getNumberOfBrainModels() == 1) { // // Get the surface // bms = bs->getBrainModelSurface(0); // // Make sure valid // if (bms == NULL) { progressDialog.cancel(); QString msg("No brain model surface after reading "); msg.append(mappingTopoFileName); msg.append(" and "); msg.append(mappingCoordFileNames[surfaceIndex]); QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", msg); delete bs; return; } } else { progressDialog.cancel(); QString msg("No brain model after reading "); msg.append(mappingTopoFileName); msg.append(" and "); msg.append(mappingCoordFileNames[surfaceIndex]); QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", msg); delete bs; return; } } break; } // // Allocate number of nodes and columns for metric file // if (mappingMetricFile.getNumberOfColumns() == 0) { mappingMetricFile.setNumberOfNodesAndColumns(bs->getNumberOfNodes(), numberOfColumns); } // // Volume data that is to be mapped // VolumeFile* vf = NULL; bool createdVolumeFile = false; // // Get info about volume that is to be mapped // GuiMapFmriVolume* fmriVolume = volumesToBeMapped[volumeIndex]; switch(fmriVolume->getFmriVolumeType()) { case GuiMapFmriVolume::FMRI_VOLUME_TYPE_FILE_ON_DISK: // // Read in the volume data // vf = new VolumeFile; createdVolumeFile = true; try { vf->readFile(fmriVolume->getVolumeFileName(), subVolumeIndex); } catch (FileException& e) { } break; case GuiMapFmriVolume::FMRI_VOLUME_TYPE_FILE_IN_MEMORY: vf = fmriVolume->getInMemoryVolumeFile(); break; } // // Update mapping algorithm parameters // mappingParameters.setAlgorithm( static_cast( algorithmComboBox->currentIndex())); mappingParameters.setAlgorithmMetricAverageVoxelParameters(algorithmAverageVoxelNeighborDoubleSpinBox->value()); mappingParameters.setAlgorithmMetricMaximumVoxelParameters(algorithmMaximumVoxelNeighborDoubleSpinBox->value()); mappingParameters.setAlgorithmMetricStrongestVoxelParameters(algorithmStrongestVoxelNeighborDoubleSpinBox->value()); mappingParameters.setAlgorithmMetricGaussianParameters(algorithmGaussianNeighborDoubleSpinBox->value(), algorithmGaussianSigmaNormDoubleSpinBox->value(), algorithmGaussianSigmaTangDoubleSpinBox->value(), algorithmGaussianNormBelowDoubleSpinBox->value(), algorithmGaussianNormAboveDoubleSpinBox->value(), algorithmGaussianTangCutoffDoubleSpinBox->value()); mappingParameters.setAlgorithmMetricMcwBrainFishParameters(algorithmBrainFishMaxDistanceDoubleSpinBox->value(), algorithmBrainFishSplatFactorSpinBox->value()); // // Create the mapper class // BrainModelVolumeToSurfaceMapper bmvsmm( bs, bms, vf, &mappingMetricFile, mappingParameters, metricColumn, metricInfo->getMetricColumnName(metricColumn)); // // Run the mapper // try { bmvsmm.execute(); } catch (BrainModelAlgorithmException& e) { progressDialog.cancel(); QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); if (createdBrainSet) { delete bs; } return; } // // Prepend user's column comment since mapper overwrites with mapping parameters // QString columnComment(metricInfo->getMetricColumnComment(metricColumn)); if (columnComment.isEmpty() == false) { columnComment.append("\n"); mappingMetricFile.prependToColumnComment(metricColumn, columnComment); } // // Set the thresholds // float negThresh, posThresh; metricInfo->getMetricColumnThresholds(metricColumn, negThresh, posThresh); mappingMetricFile.setColumnThresholding(metricColumn, negThresh, posThresh); // // Free up the volume file if needed // if (createdVolumeFile) { delete vf; vf = NULL; } // // Free up the brain set if it was created // if (createdBrainSet) { delete bs; bs = NULL; } } // for (int metricColumn // // Do metric average/deviation/error if requested // if (mms.getDoAvgOfAllCoordFileFlag() || mms.getDoStdDevOfAllCoordFileFlag() || mms.getDoStdErrorOfAllCoordFileFlag() || mms.getDoMinOfAllCoordFileFlag() || mms.getDoMaxOfAllCoordFileFlag()) { QString progressMessage("Generating "); // // Get names of stats (note that stats not generated for blank names) // QString avgName, devName, errorName, minName, maxName; if (mms.getDoAvgOfAllCoordFileFlag()) { avgName = metricInfo->getMetricAverageOfAllColumnName(); progressMessage.append("Average "); } if (mms.getDoStdDevOfAllCoordFileFlag()) { devName = metricInfo->getMetricStdDevColumnName(); progressMessage.append(" Sample Standard Deviation "); } if (mms.getDoStdErrorOfAllCoordFileFlag()) { errorName = metricInfo->getMetricStdErrorColumnName(); progressMessage.append(" Standard Error "); } if (mms.getDoMinOfAllCoordFileFlag()) { minName = metricInfo->getMetricMinValueColumnName(); progressMessage.append(" Minimum Value"); } if (mms.getDoMaxOfAllCoordFileFlag()) { maxName = metricInfo->getMetricMaxValueColumnName(); progressMessage.append(" Maximum Value"); } progressDialog.setLabelText(progressMessage); progressDialog.show(); // // Generate stats // mappingMetricFile.computeStatistics(avgName, devName, errorName, minName, maxName); // // Add comments and thresholds // if (avgName.isEmpty() == false) { const int avgCol = mappingMetricFile.getColumnWithName(avgName); if (avgCol >= 0) { mappingMetricFile.prependToColumnComment(avgCol, metricInfo->getMetricAverageOfAllComment()); float negThresh, posThresh; metricInfo->getMetricAverageOfAllThresholds(negThresh, posThresh); mappingMetricFile.setColumnThresholding(avgCol, negThresh, posThresh); // // Number of nodes above the thresholds // std::vector negCount, posCount; for (int iCol = 0; iCol < avgCol; iCol++) { int nc, pc; mappingMetricFile.getThresholdExceededCounts(iCol, negThresh, posThresh, nc, pc); negCount.push_back(nc); posCount.push_back(pc); } const int numColCount = static_cast(posCount.size()); // // Get the average nodes exceeding thresholds // int posCountAvgNum = 0, negCountAvgNum= 0; for (int iCol = 0; iCol < numColCount; iCol++) { posCountAvgNum += posCount[iCol]; negCountAvgNum += negCount[iCol]; } if (posCountAvgNum > 0) { posCountAvgNum = posCountAvgNum / numColCount; } if (negCountAvgNum > 0) { negCountAvgNum = negCountAvgNum / numColCount; } if (DebugControl::getDebugOn()) { std::cout << "Pos/Neg counts: " << negCountAvgNum << " " << posCountAvgNum << std::endl; } // // Get all values in the average column // std::vector avgValues; mappingMetricFile.getColumnForAllNodes(avgCol, avgValues); // // Sort the average column // std::sort(avgValues.begin(), avgValues.end()); // // Set the average thresholds // float avgPosThresh = 0.0, avgNegThresh = 0.0; const int num = mappingMetricFile.getNumberOfNodes(); const int posIndex = num - posCountAvgNum; if ((posIndex >= 0) && (posIndex < num)) { avgPosThresh = avgValues[posIndex]; } if ((negCountAvgNum >= 0) && (negCountAvgNum < num)) { avgNegThresh = avgValues[negCountAvgNum]; } for (int iCol = 0; iCol <= avgCol; iCol++) { mappingMetricFile.setColumnAverageThresholding(iCol, avgNegThresh, avgPosThresh); } } } if (devName.isEmpty() == false) { const int col = mappingMetricFile.getColumnWithName(devName); if (col >= 0) { mappingMetricFile.prependToColumnComment(col, metricInfo->getMetricStdDevComment()); float negThresh, posThresh; metricInfo->getMetricStdDevThresholds(negThresh, posThresh); mappingMetricFile.setColumnThresholding(col, negThresh, posThresh); } } if (errorName.isEmpty() == false) { const int col = mappingMetricFile.getColumnWithName(errorName); if (col >= 0) { mappingMetricFile.prependToColumnComment(col, metricInfo->getMetricStdErrorComment()); float negThresh, posThresh; metricInfo->getMetricStdErrorThresholds(negThresh, posThresh); mappingMetricFile.setColumnThresholding(col, negThresh, posThresh); } } if (minName.isEmpty() == false) { const int col = mappingMetricFile.getColumnWithName(minName); if (col >= 0) { mappingMetricFile.prependToColumnComment(col, metricInfo->getMetricMinValueComment()); float negThresh, posThresh; metricInfo->getMetricMinValueThresholds(negThresh, posThresh); mappingMetricFile.setColumnThresholding(col, negThresh, posThresh); } } if (maxName.isEmpty() == false) { const int col = mappingMetricFile.getColumnWithName(maxName); if (col >= 0) { mappingMetricFile.prependToColumnComment(col, metricInfo->getMetricMaxValueComment()); float negThresh, posThresh; metricInfo->getMetricMaxValueThresholds(negThresh, posThresh); mappingMetricFile.setColumnThresholding(col, negThresh, posThresh); } } } // // Map to the average fiducial surface (average fiducial only used when map to atlas) // MetricFile averageFiducialMetricFile; if (mms.getDoAverageFiducialFileFlag()) { // // Get volume information // const int volumeIndex = metricInfo->getVolumeIndex(); const int subVolumeIndex = metricInfo->getSubVolumeIndex(); // // Update the progress dialog // qApp->processEvents(); // note: qApp is global in QApplication if (progressDialog.wasCanceled()) { return; } QString progressMessage("Mapping Volume: "); progressMessage.append(volumesToBeMapped[volumeIndex]->getDescriptiveName()); progressMessage.append("\nSub-Volume: "); progressMessage.append(volumesToBeMapped[volumeIndex]->getSubVolumeName(subVolumeIndex)); progressMessage.append(" to \n"); progressMessage.append(metricInfo->getMetricAverageFiducialCoordColumnName()); progressMessage.append("."); progressDialog.setLabelText(progressMessage); progressDialog.setValue(progressDialog.value() + 1); progressDialog.show(); // // Set to the spec file directory // const QString directory(mms.getMappingFilesPath()); if (directory.isEmpty() == false) { QDir::setCurrent(directory); } // // Create a spec file and initialize it for mapping files // SpecFile sf; sf.setTopoAndCoordSelected(mappingTopoFileName, mms.getAverageFiducialCoordFileName(), sf.getStructure()); // // Create the brain set // BrainSet* bs = new BrainSet; BrainModelSurface* bms = NULL; // // Load the brain set // std::vector errorMessages; bs->readSpecFile(BrainSet::SPEC_FILE_READ_MODE_NORMAL, sf, "mapping_spec", errorMessages, NULL, NULL); if (errorMessages.empty() == false) { progressDialog.cancel(); QString msg("Error creating BrainSet for mapping average fiducial data.\n"); msg.append(StringUtilities::combine(errorMessages, "\n")); QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", msg); return; } // // If spec file read correctly, there is one brain model // if (bs->getNumberOfBrainModels() == 1) { // // Get the surface // bms = bs->getBrainModelSurface(0); // // Make sure valid // if (bms == NULL) { progressDialog.cancel(); QString msg("No brain model surface after reading "); msg.append(mappingTopoFileName); msg.append(" and "); msg.append(mms.getAverageFiducialCoordFileName()); QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", msg); delete bs; return; } } else { progressDialog.cancel(); QString msg("No brain model after reading "); msg.append(mappingTopoFileName); msg.append(" and "); msg.append(mms.getAverageFiducialCoordFileName()); QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", msg); delete bs; return; } // // Allocate number of nodes and columns for metric file // averageFiducialMetricFile.setNumberOfNodesAndColumns(bs->getNumberOfNodes(), 1); // // Volume data that is to be mapped // VolumeFile* vf = NULL; bool createdVolumeFile = false; // // Get info about volume that is to be mapped // GuiMapFmriVolume* fmriVolume = volumesToBeMapped[volumeIndex]; switch(fmriVolume->getFmriVolumeType()) { case GuiMapFmriVolume::FMRI_VOLUME_TYPE_FILE_ON_DISK: // // Read in the volume data // vf = new VolumeFile; createdVolumeFile = true; try { vf->readFile(fmriVolume->getVolumeFileName(), subVolumeIndex); } catch (FileException& e) { } break; case GuiMapFmriVolume::FMRI_VOLUME_TYPE_FILE_IN_MEMORY: vf = fmriVolume->getInMemoryVolumeFile(); break; } // // Update mapping algorithm parameters // mappingParameters.setAlgorithm( static_cast( algorithmComboBox->currentIndex())); mappingParameters.setAlgorithmMetricAverageVoxelParameters(algorithmAverageVoxelNeighborDoubleSpinBox->value()); mappingParameters.setAlgorithmMetricMaximumVoxelParameters(algorithmMaximumVoxelNeighborDoubleSpinBox->value()); mappingParameters.setAlgorithmMetricStrongestVoxelParameters(algorithmStrongestVoxelNeighborDoubleSpinBox->value()); mappingParameters.setAlgorithmMetricGaussianParameters(algorithmGaussianNeighborDoubleSpinBox->value(), algorithmGaussianSigmaNormDoubleSpinBox->value(), algorithmGaussianSigmaTangDoubleSpinBox->value(), algorithmGaussianNormBelowDoubleSpinBox->value(), algorithmGaussianNormAboveDoubleSpinBox->value(), algorithmGaussianTangCutoffDoubleSpinBox->value()); mappingParameters.setAlgorithmMetricMcwBrainFishParameters(algorithmBrainFishMaxDistanceDoubleSpinBox->value(), algorithmBrainFishSplatFactorSpinBox->value()); // // Create the mapper class // BrainModelVolumeToSurfaceMapper bmvsmm( bs, bms, vf, &averageFiducialMetricFile, mappingParameters, 0, metricInfo->getMetricAverageFiducialCoordColumnName()); // // Run the mapper // try { bmvsmm.execute(); } catch (BrainModelAlgorithmException& e) { progressDialog.cancel(); QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); delete bs; bs = NULL; return; } // // Prepend user's column comment since mapper overwrites with mapping parameters // QString columnComment(metricInfo->getMetricAverageFiducialCoordComment()); if (columnComment.isEmpty() == false) { columnComment.append("\n"); averageFiducialMetricFile.prependToColumnComment(0, columnComment); } // // Set the thresholds // float negThresh, posThresh; metricInfo->getMetricAverageFiducialCoordThresholds(negThresh, posThresh); averageFiducialMetricFile.setColumnThresholding(0, negThresh, posThresh); // // Free up the volume file if needed // if (createdVolumeFile) { delete vf; vf = NULL; } // // Free up the brain set if it was created // delete bs; bs = NULL; // // Add onto output metric file // outputMetricFile.append(averageFiducialMetricFile); } // // Append average, dev, etc columns first so that they are before indiv cases // The average, dev, etc are after the individual cases // bool haveGroupStat = false; std::vector metricColumnDestination(mappingMetricFile.getNumberOfColumns(), MetricFile::APPEND_COLUMN_NEW); for (int n = 0; n < mappingMetricFile.getNumberOfColumns(); n++) { if (n >= metricInfo->getNumberOfMetricColumns()) { metricColumnDestination[n] = MetricFile::APPEND_COLUMN_NEW; haveGroupStat = true; } else { metricColumnDestination[n] = MetricFile::APPEND_COLUMN_DO_NOT_LOAD; } } if (haveGroupStat) { outputMetricFile.append(mappingMetricFile, metricColumnDestination, MetricFile::FILE_COMMENT_MODE_APPEND); } // // Append indiv cases. // if (mms.getDoAllCasesCoordFileFlag()) { for (int n = 0; n < mappingMetricFile.getNumberOfColumns(); n++) { if (n < metricInfo->getNumberOfMetricColumns()) { metricColumnDestination[n] = MetricFile::APPEND_COLUMN_NEW; } else { metricColumnDestination[n] = MetricFile::APPEND_COLUMN_DO_NOT_LOAD; } } NodeAttributeFile::FILE_COMMENT_MODE fcm = MetricFile::FILE_COMMENT_MODE_APPEND; if (haveGroupStat) { fcm = MetricFile::FILE_COMMENT_MODE_LEAVE_AS_IS; } outputMetricFile.append(mappingMetricFile, metricColumnDestination, fcm); } } // number of metric mapping info // // Update Caret/Spec file with new metric data // switch (mms.getMetricOutputType()) { case GuiMapFmriMappingSet::METRIC_OUTPUT_TYPE_NONE: break; case GuiMapFmriMappingSet::METRIC_OUTPUT_TYPE_CARET_METRIC: // // Append to existing metrics // { MetricFile* currentMetricFile = theMainWindow->getBrainSet()->getMetricFile(); try { currentMetricFile->append(outputMetricFile); } catch (FileException& e) { progressDialog.cancel(); QString msg("Data mapped but unable to append to current metric file.\n"); msg.append(e.whatQString()); QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", msg); return; } } break; case GuiMapFmriMappingSet::METRIC_OUTPUT_TYPE_SPEC_FILE: { // // Change to the spec file's directory // const QString directory(FileUtilities::dirname(mms.getOutputSpecFileName())); if (directory.isEmpty() == false) { QDir::setCurrent(directory); } // // Metric file is always written in same directory as spec file // so chop off path // const QString metricName(FileUtilities::basename(mms.getMetricFileName())); // // Save the metric file // try { outputMetricFile.writeFile(metricName); } catch (FileException& e) { progressDialog.cancel(); QString msg("Unable to save metric file "); msg.append(metricName); msg.append("\n"); msg.append(e.whatQString()); QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", msg); return; } // // Update the spec file // SpecFile sf; try { // // Read the spec file for updating // sf.readFile(mms.getOutputSpecFileName()); // // Add the metric file to the spec file // sf.addToSpecFile(SpecFile::getMetricFileTag(), metricName, "", false); // // Write the spec file // sf.writeFile(mms.getOutputSpecFileName()); // // Add the spec file to the recent spec files in preferences // PreferencesFile* pf = theMainWindow->getBrainSet()->getPreferencesFile(); pf->addToRecentSpecFiles(mms.getOutputSpecFileName(), true); } catch (FileException& e) { progressDialog.cancel(); QString msg("Unable to update spec file: "); msg.append(mms.getOutputSpecFileName()); msg.append("\n"); msg.append(e.whatQString()); QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", msg); return; } } break; } // // Restore directory // QDir::setCurrent(savedDirectory); } } /** * create the data mapping type page. */ QWidget* GuiMapFmriDialog::createDataMappingTypePage() { const QString infoMessage = "Choose the type of volume(s) that are to be mapped."; QWidget* infoWidget = addPageInformation("Choose Data Mapping Type", infoMessage); // // Mapping data file types // mappingTypeFunctionalRadioButton = new QRadioButton("Metric (Functional) or Surface Shape Data"); mappingTypePaintRadioButton = new QRadioButton("Paint (ROI) or Probabilistic Atlas Data"); // // Button group to keep buttons exclusive // QButtonGroup* mappingTypeButtonGroup = new QButtonGroup(this); QObject::connect(mappingTypeButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotDataMappingTypeButtGroup(int))); mappingTypeButtonGroup->addButton(mappingTypeFunctionalRadioButton); mappingTypeButtonGroup->addButton(mappingTypePaintRadioButton); // // Mapping type group box and layout // QGroupBox* mappingTypeGroupBox = new QGroupBox("Data Mapping Type"); QVBoxLayout* mappingTypeLayout = new QVBoxLayout(mappingTypeGroupBox); mappingTypeLayout->addWidget(mappingTypeFunctionalRadioButton); mappingTypeLayout->addWidget(mappingTypePaintRadioButton); mappingTypeGroupBox->setFixedHeight(mappingTypeGroupBox->sizeHint().height()); // // Layout for page // QWidget* mapTypePageWidget = new QWidget; QVBoxLayout* mapTypeLayout = new QVBoxLayout(mapTypePageWidget); mapTypeLayout->addWidget(mappingTypeGroupBox); mapTypeLayout->addWidget(infoWidget); return mapTypePageWidget; } /** * called when a data mapping type is selected. */ void GuiMapFmriDialog::slotDataMappingTypeButtGroup(int /*item*/) { dataMappingType = DATA_MAPPING_TYPE_NONE; if (mappingTypeFunctionalRadioButton->isChecked()) { dataMappingType = DATA_MAPPING_TYPE_METRIC; } else if (mappingTypePaintRadioButton->isChecked()) { dataMappingType = DATA_MAPPING_TYPE_PAINT; } slotSetAppropriatePages(); outputDataFileExtension = ""; switch (dataMappingType) { case DATA_MAPPING_TYPE_NONE: break; case DATA_MAPPING_TYPE_METRIC: setWindowTitle("Map Functional Volumes To Surfaces"); outputDataFileExtension = SpecFile::getMetricFileExtension(); break; case DATA_MAPPING_TYPE_PAINT: setWindowTitle("Map Paint Volumes To Surfaces"); outputDataFileExtension = SpecFile::getPaintFileExtension(); break; } if (runningAsPartOfCaret) { bool enableIt = false; switch (dataMappingType) { case DATA_MAPPING_TYPE_NONE: break; case DATA_MAPPING_TYPE_METRIC: if (theMainWindow->getBrainSet()->getNumberOfVolumeFunctionalFiles() > 0) { enableIt = true; } break; case DATA_MAPPING_TYPE_PAINT: if (theMainWindow->getBrainSet()->getNumberOfVolumePaintFiles() > 0) { enableIt = true; } break; } if (enableIt) { loadedVolumesPushButton->setEnabled(true); } } } /** * create the volume selection page. */ QWidget* GuiMapFmriDialog::createVolumeSelectionPage() { // // List box for displaying functional volumes that are to be mapped // volumeListBox = new QListWidget; volumeListBox->setMinimumWidth(400); volumeListBox->setMinimumHeight(100); volumeListBox->setSelectionMode(QListWidget::ExtendedSelection); // // Pushbutton for selecting volumes from disk // QPushButton* diskVolumesPushButton = new QPushButton("Add Volumes From Disk..."); diskVolumesPushButton->setAutoDefault(false); QObject::connect(diskVolumesPushButton, SIGNAL(clicked()), this, SLOT(slotDiskVolumesPushButton())); // // Pushbutton for removing volumes in dialog // QPushButton* removeVolumePushButton = new QPushButton("Remove Selected Volumes"); removeVolumePushButton->setAutoDefault(false); QObject::connect(removeVolumePushButton, SIGNAL(clicked()), this, SLOT(slotRemoveVolumesPushButton())); // // Pushbutton for selecting loaded volumes // loadedVolumesPushButton = new QPushButton("Add Loaded Volumes..."); loadedVolumesPushButton->setAutoDefault(false); QObject::connect(loadedVolumesPushButton, SIGNAL(clicked()), this, SLOT(slotLoadedVolumesPushButton())); loadedVolumesPushButton->setEnabled(false); QtUtilities::makeButtonsSameSize(loadedVolumesPushButton, diskVolumesPushButton, removeVolumePushButton); // // Grid for volume selection push buttons // QGridLayout* selectionButtonGridLayout = new QGridLayout; selectionButtonGridLayout->addWidget(diskVolumesPushButton, 0, 0); selectionButtonGridLayout->addWidget(removeVolumePushButton, 0, 1); selectionButtonGridLayout->addWidget(loadedVolumesPushButton, 1, 0); // // Group box for volume selection // QGroupBox* selectionGroupBox = new QGroupBox("Volume Selection"); QVBoxLayout* selectionLayout = new QVBoxLayout(selectionGroupBox); selectionLayout->addWidget(volumeListBox); selectionLayout->addLayout(selectionButtonGridLayout); // // Threshold entry selection // volumeEnterThreshCheckBox = new QCheckBox("Enable Entry of Volume Threshold"); volumeEnterThreshCheckBox->setChecked(false); QGroupBox* threshGroupBox = new QGroupBox("Volume Thresholding"); QVBoxLayout* threshGroupLayout = new QVBoxLayout(threshGroupBox); threshGroupLayout->addWidget(volumeEnterThreshCheckBox); QString text =""; text += "Add Data Volumes From Disk Press this button to select data volume " "files.

    "; if (runningAsPartOfCaret) { text += "Add Loaded Volumes Press this button to select data " "volumes that are currently loaded in Caret.

    "; } text += "Remove Selected Volumes Press this button to remove all selected volumes.

    "; text += "In the file selection dialog, multiple files may be selected by holding " "down the CTRL key (Apple key on Macintosh).

    "; QWidget* infoWidget = addPageInformation("Functional Volume Selection Information", text); QWidget* w = new QWidget; QVBoxLayout* layout = new QVBoxLayout(w); layout->addWidget(selectionGroupBox); layout->addWidget(threshGroupBox); layout->addWidget(infoWidget); return w; } /** * Called when Remove Volumes pushbutton pressed. */ void GuiMapFmriDialog::slotRemoveVolumesPushButton() { bool volumeRemoved = false; for (int i = static_cast(volumesToBeMapped.size()) - 1; i >= 0; i--) { const QListWidgetItem* item = volumeListBox->item(i); if (volumeListBox->isItemSelected(item)) { volumesToBeMapped.erase(volumesToBeMapped.begin() + i); volumeRemoved = true; } } if (volumeRemoved) { // // Clear mapping sets since volumes have changed // resetMappingSets(); } loadVolumesListBox(); } /** * Called when Select Loaded Volumes pushbutton pressed. */ void GuiMapFmriDialog::slotLoadedVolumesPushButton() { int num = 0; QString typeName; switch (dataMappingType) { case DATA_MAPPING_TYPE_NONE: break; case DATA_MAPPING_TYPE_METRIC: num = theMainWindow->getBrainSet()->getNumberOfVolumeFunctionalFiles(); if (num == 0) { QMessageBox::warning(this, "Warning", "There are no loaded functional volumes"); return; } typeName = "func"; break; case DATA_MAPPING_TYPE_PAINT: num = theMainWindow->getBrainSet()->getNumberOfVolumePaintFiles(); if (num == 0) { QMessageBox::warning(this, "Warning", "There are no loaded paint volumes"); return; } typeName = "paint"; break; } std::vector dataVolumes; std::vector names; for (int i = 0; i < num; i++) { VolumeFile* vf = NULL; switch (dataMappingType) { case DATA_MAPPING_TYPE_NONE: break; case DATA_MAPPING_TYPE_METRIC: vf = theMainWindow->getBrainSet()->getVolumeFunctionalFile(i); break; case DATA_MAPPING_TYPE_PAINT: vf = theMainWindow->getBrainSet()->getVolumePaintFile(i); break; } if (vf != NULL) { dataVolumes.push_back(vf); QString name(FileUtilities::basename(vf->getDescriptiveLabel())); if (name.isEmpty()) { name.append(typeName); name.append(" volume "); name.append(StringUtilities::fromNumber(i)); } names.push_back(name); } } QtListBoxSelectionDialog lbsd(this, "Select Volumes", "", names, -1); lbsd.setAllowMultipleItemSelection(true); if (lbsd.exec() == QDialog::Accepted) { std::vector selectedIndices; lbsd.getSelectedItemsIndices(selectedIndices); const int num = static_cast(selectedIndices.size()); for (int i = 0; i < num; i++) { VolumeFile* vf = dataVolumes[selectedIndices[i]]; float negThresh = 0.0, posThresh = 0.0; switch (dataMappingType) { case DATA_MAPPING_TYPE_NONE: break; case DATA_MAPPING_TYPE_METRIC: // // Get the thresholds for metric data // if (volumeEnterThreshCheckBox->isChecked()) { QApplication::beep(); GuiMapFmriThresholdDialog td(this, vf->getFileName()); if (td.exec() == QDialog::Accepted) { td.getThresholds(negThresh, posThresh); } } break; case DATA_MAPPING_TYPE_PAINT: break; } GuiMapFmriVolume* vol = new GuiMapFmriVolume(vf, negThresh, posThresh); volumesToBeMapped.push_back(vol); } if (num > 0) { // // Clear mapping sets since volumes have changed // resetMappingSets(); } } loadVolumesListBox(); } /** * Called when Select Volumes From Disk pushbutton pressed. */ void GuiMapFmriDialog::slotDiskVolumesPushButton() { static QString lastVolumeDirectory; static bool hdrWarningHasBeenDisplayed = false; QString instructions = "To select multiple volumes, hold down the CTRL key while selecting " "volume file names with the mouse (Macintosh users should hold down " "the Apple key)."; /* std::ostringstream str; << "AFNI " << "NIFTI " << "SPM " << "WuNIL (" << "*" << SpecFile::getAfniVolumeFileExtension().toAscii().constData() << " " << "*" << SpecFile::getNiftiVolumeFileExtension().toAscii().constData() << " " << "*" << SpecFile::getAnalyzeVolumeFileExtension().toAscii().constData() << " " << "*" << SpecFile::getWustlVolumeFileExtension().toAscii().constData() << ")"; */ GuiFileDialogWithInstructions openVolumeFileDialog(this, instructions, "openVolSpec", true); openVolumeFileDialog.setWindowTitle("Choose Volume File"); openVolumeFileDialog.setFileMode(GuiFileDialogWithInstructions::ExistingFiles); openVolumeFileDialog.setFilters(QStringList(FileFilters::getVolumeGenericFileFilter())); openVolumeFileDialog.selectFilter(FileFilters::getVolumeGenericFileFilter()); if (lastVolumeDirectory.isEmpty() == false) { openVolumeFileDialog.setDirectory(lastVolumeDirectory); } openVolumeFileDialog.rereadDir(); if (openVolumeFileDialog.exec() == QDialog::Accepted) { // // Check for HDR files // if (hdrWarningHasBeenDisplayed == false) { bool haveHDR = false; QStringList listHDR = openVolumeFileDialog.selectedFiles(); QStringList::Iterator itHDR = listHDR.begin(); while (itHDR != listHDR.end()) { if (itHDR->endsWith(SpecFile::getAnalyzeVolumeFileExtension())) { haveHDR = true; break; } ++itHDR; } if (haveHDR) { hdrWarningHasBeenDisplayed = true; const QString msg("You have selected a \".hdr\" file. If this \".hdr\" file does\n" "not contain an SPM originator, it is unlikely that it will get\n" "mapped to the surface correctly."); if (QMessageBox::warning(this, "WARNING", msg, (QMessageBox::Ok | QMessageBox::Cancel), QMessageBox::Cancel) == QMessageBox::Cancel) { return; } } } // // process files // QStringList list = openVolumeFileDialog.selectedFiles(); QStringList::Iterator it = list.begin(); bool firstFileFlag = true; bool volumeAdded = false; while( it != list.end() ) { QString filename((*it)); if (firstFileFlag) { lastVolumeDirectory = FileUtilities::dirname(filename); firstFileFlag = false; } float negThresh = 0.0, posThresh = 0.0; switch (dataMappingType) { case DATA_MAPPING_TYPE_NONE: break; case DATA_MAPPING_TYPE_METRIC: // // Get the thresholds for metric data // if (volumeEnterThreshCheckBox->isChecked()) { // // Get the thresholds // QApplication::beep(); GuiMapFmriThresholdDialog td(this, filename); if (td.exec() == QDialog::Accepted) { td.getThresholds(negThresh, posThresh); } } break; case DATA_MAPPING_TYPE_PAINT: break; } GuiMapFmriVolume* vol = new GuiMapFmriVolume(filename, negThresh, posThresh); volumesToBeMapped.push_back(vol); ++it; volumeAdded = true; } if (volumeAdded) { // // Clear mapping sets since volumes have changed // resetMappingSets(); } } loadVolumesListBox(); } /** * Load the volumes list box. */ void GuiMapFmriDialog::loadVolumesListBox() { // // Remove everything from the list box // volumeListBox->clear(); for (int i = 0; i < static_cast(volumesToBeMapped.size()); i++) { volumeListBox->addItem(volumesToBeMapped[i]->getDescriptiveName()); } slotSetAppropriatePages(); } /** * create the spec file and surface selection page. */ QWidget* GuiMapFmriDialog::createSpecFileAndSurfaceSelectionPage() { // // Add list box for mapping sets // mappingSetListBox = new QListWidget; mappingSetListBox->setMinimumWidth(400); mappingSetListBox->setMinimumHeight(100); mappingSetListBox->setSelectionMode(QListWidget::ExtendedSelection); // // Pushbutton for selecting caret surfaces // addCaretSurfacesPushButton = new QPushButton("Map to Caret..."); addCaretSurfacesPushButton->setAutoDefault(false); QObject::connect(addCaretSurfacesPushButton, SIGNAL(clicked()), this, SLOT(slotAddCaretSurfacesPushButton())); addCaretSurfacesPushButton->setToolTip( "Press this button if you would like to map the\n" "volume using surface(s) currently loaded in\n" "Caret and place the output into the data file\n" "currently loaded into Caret. After doing so you\n" "will need to save the metric file."); // // Pushbutton for adding spec files // QPushButton* addSpecFilesPushButton = new QPushButton("Map to Spec File..."); addSpecFilesPushButton->setAutoDefault(false); QObject::connect(addSpecFilesPushButton, SIGNAL(clicked()), this, SLOT(slotAddSpecFilesPushButton())); addSpecFilesPushButton->setToolTip( "Press this button if you would like to map the \n" "volume using surface(s) in a spec file and add\n" "the output metric file to the spec file."); // // Map to Caret using Atlas // addCaretMapWithAtlasPushButton = new QPushButton("Map to Caret With Atlas..."); addCaretMapWithAtlasPushButton->setAutoDefault(false); QObject::connect(addCaretMapWithAtlasPushButton, SIGNAL(clicked()), this, SLOT(slotAddCaretMapWithAtlasPushButton())); addCaretMapWithAtlasPushButton->setToolTip( "Press this button if you would like to map the \n" "volume using an atlas but add the output\n" "into the data file currently loaded in Caret.\n" "After doing so, you will need to save the data\n" "file."); // // Pushbutton for adding spec files but mapping with an atlas // addSpecAtlasPushButton = new QPushButton("Map to Spec File With Atlas..."); addSpecAtlasPushButton->setAutoDefault(false); QObject::connect(addSpecAtlasPushButton, SIGNAL(clicked()), this, SLOT(slotAddSpecAtlasPushButton())); addSpecAtlasPushButton->setToolTip( "Press this button if you would like to map the\n" "volume using an atlas but place the output into\n" "a data file and add the data file to a spec file."); // // Pushbutton for removing items in dialog // QPushButton* removeMappingSetsPushButton = new QPushButton("Remove Selected Items"); removeMappingSetsPushButton->setAutoDefault(false); QObject::connect(removeMappingSetsPushButton, SIGNAL(clicked()), this, SLOT(slotRemoveMappingSetsPushButton())); QtUtilities::makeButtonsSameSize(addCaretSurfacesPushButton, addSpecFilesPushButton, removeMappingSetsPushButton, addSpecAtlasPushButton, addCaretMapWithAtlasPushButton); // // Grid layout for buttons // QGridLayout* buttonsGridLayout = new QGridLayout; buttonsGridLayout->addWidget(addCaretSurfacesPushButton, 0, 0); buttonsGridLayout->addWidget(addSpecFilesPushButton, 0, 1); buttonsGridLayout->addWidget(addCaretMapWithAtlasPushButton, 1, 0); buttonsGridLayout->addWidget(addSpecAtlasPushButton, 1, 1); buttonsGridLayout->addWidget(removeMappingSetsPushButton, 2, 0); // // Group box and layout for spec file and surface selection // QGroupBox* groupBox = new QGroupBox("Spec File and Surface Selection"); QVBoxLayout* groupBoxLayout = new QVBoxLayout(groupBox); groupBoxLayout->addWidget(mappingSetListBox); groupBoxLayout->addLayout(buttonsGridLayout); const QString infoMessage = "Map to Caret - Press this button to map volumes to the metric file currently " "loaded in Caret using surfaces loaded in Caret.

    " "Map To Caret With Atlas - Press this button to map volumes to the metric file " "currently loaded in Caret using Atlas surface(s).

    " "Map to Spec File - Press this button to map volumes to a metric file that will " "be added to the selected spec file using topology and coordinate files listed in the spec " "file.

    " "Map to Spec File With Atlas - Press this button to map volumes to a metric file " "that will be added to the selected spec file using Atlas surface(s)."; QWidget* infoWidget = addPageInformation("Spec File and Surface Selection Information", infoMessage); QWidget* w = new QWidget; QVBoxLayout* layout = new QVBoxLayout(w); layout->addWidget(groupBox); layout->addWidget(infoWidget); return w; } /** * Called when add spec file map with atlas pushbutton pressed. */ void GuiMapFmriDialog::slotAddSpecAtlasPushButton() { bool enableMetricMultiFidOptions = false; bool enablePaintMultiFidOptions = false; switch (dataMappingType) { case DATA_MAPPING_TYPE_NONE: break; case DATA_MAPPING_TYPE_METRIC: enableMetricMultiFidOptions = true; break; case DATA_MAPPING_TYPE_PAINT: enablePaintMultiFidOptions = true; break; } // // Choose output spec file and atlas files // GuiMapFmriAtlasDialog fad(this, &atlasSpecFileInfo, theMainWindow->getBrainSet()->getPreferencesFile(), "", "", true, enableMetricMultiFidOptions, enablePaintMultiFidOptions); if (fad.exec() == QDialog::Accepted) { QString atlasPath, atlasTopoFileName, description, metricNameHint, atlasAvgCoordFileName; QString structureName; std::vector atlasCoordFileNames; bool mapToAvgCoordFileFlag = false, mapToAvgOfAllFlag = false, mapToStdDevOfAllFlag = false, mapToStdErrorOfAllFlag = false, mapToMinOfAllFlag = false, mapToMaxOfAllFlag = false, mapToAllCasesFlag = false, mapToMostCommonOfAllFlag = false, mapToMostCommonExcludeUnidentifiedOfAllFlag = false; if (enableMetricMultiFidOptions) { fad.getSelectedMetricAtlasData(atlasPath, atlasTopoFileName, description, atlasCoordFileNames, atlasAvgCoordFileName, metricNameHint, structureName, mapToAvgCoordFileFlag, mapToAvgOfAllFlag, mapToStdDevOfAllFlag, mapToStdErrorOfAllFlag, mapToMinOfAllFlag, mapToMaxOfAllFlag, mapToAllCasesFlag); } else if (enablePaintMultiFidOptions) { fad.getSelectedPaintAtlasData(atlasPath, atlasTopoFileName, description, atlasCoordFileNames, atlasAvgCoordFileName, metricNameHint, structureName, mapToAvgCoordFileFlag, mapToMostCommonOfAllFlag, mapToMostCommonExcludeUnidentifiedOfAllFlag, mapToAllCasesFlag); } const QString outputSpecFileName(fad.getOutputSpecFileName()); if ((atlasCoordFileNames.empty() == false) || (atlasAvgCoordFileName.isEmpty() == false)) { // // Create the mapping set // mappingSets.push_back(GuiMapFmriMappingSet(outputSpecFileName, atlasPath, atlasTopoFileName, atlasCoordFileNames, atlasAvgCoordFileName, volumesToBeMapped, outputDataFileExtension, description, metricNameHint, structureName, true, mapToAvgCoordFileFlag, mapToAvgOfAllFlag, mapToStdDevOfAllFlag, mapToStdErrorOfAllFlag, mapToMinOfAllFlag, mapToMaxOfAllFlag, mapToAllCasesFlag, mapToMostCommonOfAllFlag, mapToMostCommonExcludeUnidentifiedOfAllFlag)); } } loadMappingSetsListBox(); } /** * Called when add caret map with spec pushbutton is pressed. */ void GuiMapFmriDialog::slotAddCaretMapWithAtlasPushButton() { bool enableMetricMultiFidOptions = false; bool enablePaintMultiFidOptions = false; switch (dataMappingType) { case DATA_MAPPING_TYPE_NONE: break; case DATA_MAPPING_TYPE_METRIC: enableMetricMultiFidOptions = true; break; case DATA_MAPPING_TYPE_PAINT: enablePaintMultiFidOptions = true; break; } // // Choose atlas files // GuiMapFmriAtlasDialog fad(this, &atlasSpecFileInfo, theMainWindow->getBrainSet()->getPreferencesFile(), theMainWindow->getBrainSet()->getSpecies().getName(), theMainWindow->getBrainSet()->getStructure().getTypeAsString(), false, enableMetricMultiFidOptions, enablePaintMultiFidOptions); if (fad.exec() == QDialog::Accepted) { QString atlasPath, atlasTopoFileName, description, metricNameHint, atlasAvgCoordFileName; QString structureName; std::vector atlasCoordFileNames; bool mapToAvgCoordFileFlag = false, mapToAvgOfAllFlag = false, mapToStdDevOfAllFlag = false, mapToStdErrorOfAllFlag = false, mapToMinOfAllFlag = false, mapToMaxOfAllFlag = false, mapToAllCasesFlag = false, mapToMostCommonOfAllFlag = false, mapToMostCommonExcludeUnidentifiedOfAllFlag = false; if (enableMetricMultiFidOptions) { fad.getSelectedMetricAtlasData(atlasPath, atlasTopoFileName, description, atlasCoordFileNames, atlasAvgCoordFileName, metricNameHint, structureName, mapToAvgCoordFileFlag, mapToAvgOfAllFlag, mapToStdDevOfAllFlag, mapToStdErrorOfAllFlag, mapToMinOfAllFlag, mapToMaxOfAllFlag, mapToAllCasesFlag); } else if (enablePaintMultiFidOptions) { fad.getSelectedPaintAtlasData(atlasPath, atlasTopoFileName, description, atlasCoordFileNames, atlasAvgCoordFileName, metricNameHint, structureName, mapToAvgCoordFileFlag, mapToMostCommonOfAllFlag, mapToMostCommonExcludeUnidentifiedOfAllFlag, mapToAllCasesFlag); } if ((atlasCoordFileNames.empty() == false) || (atlasAvgCoordFileName.isEmpty() == false)) { // // Create the mapping set for use atlas to map to caret metric file // mappingSets.push_back(GuiMapFmriMappingSet(atlasPath, atlasTopoFileName, atlasCoordFileNames, atlasAvgCoordFileName, volumesToBeMapped, outputDataFileExtension, description, structureName, mapToAvgCoordFileFlag, mapToAvgOfAllFlag, mapToStdDevOfAllFlag, mapToStdErrorOfAllFlag, mapToMinOfAllFlag, mapToMaxOfAllFlag, mapToAllCasesFlag, mapToMostCommonOfAllFlag, mapToMostCommonExcludeUnidentifiedOfAllFlag)); } } loadMappingSetsListBox(); } /** * Called when add caret surfaces pushbutton pressed. */ void GuiMapFmriDialog::slotAddCaretSurfacesPushButton() { bool haveAnySurface = false; std::vector surfaces; getFiducialSurfaces(surfaces, haveAnySurface); std::vector names; for (int i = 0; i < static_cast(surfaces.size()); i++) { names.push_back(surfaces[i]->getDescriptiveName()); } int defaultIndex = -1; if (names.size() == 1) { defaultIndex = 0; } QtListBoxSelectionDialog lbsd(this, "Select Caret Surface(s)", "", names, "Select All Surfaces", defaultIndex); lbsd.setAllowMultipleItemSelection(true); if (lbsd.exec() == QDialog::Accepted) { std::vector indices; lbsd.getSelectedItemsIndices(indices); std::vector surfacesSelected; for (int i = 0; i < static_cast(indices.size()); i++) { surfacesSelected.push_back(surfaces[indices[i]]); } if (surfacesSelected.empty() == false) { mappingSets.push_back(GuiMapFmriMappingSet(surfacesSelected, volumesToBeMapped, outputDataFileExtension, "")); } } loadMappingSetsListBox(); } /** * Get the Caret fiducial surfaces. */ void GuiMapFmriDialog::getFiducialSurfaces(std::vector& surfaces, bool& haveAnySurface) const { haveAnySurface = false; surfaces.clear(); for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfBrainModels(); i++) { BrainModelSurface* bms = theMainWindow->getBrainSet()->getBrainModelSurface(i); if (bms != NULL) { haveAnySurface = true; if ((bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_RAW) || (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FIDUCIAL)) { surfaces.push_back(bms); } } } } /** * reset (erase) the mapping sets. */ void GuiMapFmriDialog::resetMappingSets() { mappingSets.clear(); } /** * load the mapping sets list box. */ void GuiMapFmriDialog::loadMappingSetsListBox() { // // Remove everything from the list box // mappingSetListBox->clear(); for (int i = 0; i < static_cast(mappingSets.size()); i++) { QString label; mappingSetListBox->addItem(mappingSets[i].getDescriptiveLabel()); } slotSetAppropriatePages(); } /** * Called when add spec files pushbutton pressed. */ void GuiMapFmriDialog::slotAddSpecFilesPushButton() { // // List the topo and coord files for selection // GuiMapFmriSpecFileTopoCoordDialog sftcd(this, theMainWindow->getBrainSet()->getPreferencesFile()); if (sftcd.exec() == QDialog::Accepted) { // // Create a new mapping set // const QString topoName(sftcd.getTopoFileName()); std::vector coordNames; sftcd.getCoordFileNames(coordNames); const QString specFileName = sftcd.getSpecFileName(); mappingSets.push_back(GuiMapFmriMappingSet(specFileName, FileUtilities::dirname(specFileName), topoName, coordNames, "", volumesToBeMapped, outputDataFileExtension, "", "", "", false, false, false, false, false, false, false, true, false, false)); } loadMappingSetsListBox(); } /** * Called when remove mapping sets (caret surfaces/spec files) pushbutton pressed. */ void GuiMapFmriDialog::slotRemoveMappingSetsPushButton() { for (int i = static_cast(mappingSets.size()) - 1; i >= 0; i--) { const QListWidgetItem* item = mappingSetListBox->item(i); if (mappingSetListBox->isItemSelected(item)) { mappingSets.erase(mappingSets.begin() + i); } } loadMappingSetsListBox(); } /** * create the metric naming page. */ QWidget* GuiMapFmriDialog::createMetricNamingPage() { // // label and combo box for mapping set selection // QLabel* surfaceFamilyLabel = new QLabel("Surface Family "); metricMappingSetComboBox = new QComboBox; QObject::connect(metricMappingSetComboBox, SIGNAL(activated(int)), this, SLOT(slotLoadMetricNamingPage())); QObject::connect(metricMappingSetComboBox, SIGNAL(highlighted(int)), this, SLOT(slotReadMetricNamingPage())); // // label and data file selection // metricFilePushButton = new QPushButton("Data File..."); metricFilePushButton->setFixedSize(metricFilePushButton->sizeHint()); metricFilePushButton->setAutoDefault(false); QObject::connect(metricFilePushButton, SIGNAL(clicked()), this, SLOT(slotMetricFilePushButton())); metricFileNameLineEdit = new QLineEdit; // // Grid for surface family and data file selections // QGridLayout* surfaceAndDataFileGridLayout = new QGridLayout; surfaceAndDataFileGridLayout->addWidget(surfaceFamilyLabel, 0, 0); surfaceAndDataFileGridLayout->addWidget(metricMappingSetComboBox, 0, 1); surfaceAndDataFileGridLayout->addWidget(metricFilePushButton, 1, 0); surfaceAndDataFileGridLayout->addWidget(metricFileNameLineEdit, 1, 1); surfaceAndDataFileGridLayout->setColumnStretch(0, 0); surfaceAndDataFileGridLayout->setColumnStretch(1, 100); // // Metric naming table // metricNamingTable = new QTableWidget; metricNamingTable->setColumnCount(METRIC_NAMING_NUMBER_OF_COLUMNS); //QT4 metricNamingTable->setColumnReadOnly(METRIC_NAMING_COLUMN_SURFACE, true); // metricNamingTable->setColumnReadOnly(METRIC_NAMING_COLUMN_VOLUME, true); // metricNamingTable->setColumnReadOnly(METRIC_NAMING_COLUMN_SUB_VOLUME, true); // // Preset some column widths // metricNamingTable->setColumnWidth(METRIC_NAMING_COLUMN_NAME, 200); metricNamingTable->setColumnWidth(METRIC_NAMING_COLUMN_COMMENT, 150); metricNamingTable->setColumnWidth(METRIC_NAMING_COLUMN_SURFACE, 400); metricNamingTable->setColumnWidth(METRIC_NAMING_COLUMN_VOLUME, 400); metricNamingTable->setColumnWidth(METRIC_NAMING_COLUMN_SUB_VOLUME, 200); metricNamingTable->setColumnWidth(METRIC_NAMING_COLUMN_NEG_THRESH, 100); metricNamingTable->setColumnWidth(METRIC_NAMING_COLUMN_POS_THRESH, 100); // // Signal if a metric naming table cell is double clicked // QObject::connect(metricNamingTable, SIGNAL(cellDoubleClicked(int,int)), this, SLOT(slotMetricNamingTableCellDoubleClicked(int,int))); // // Metric naming table headers // QStringList headerLabels; headerLabels << "Data Column Name"; headerLabels << "Data Column Comment"; headerLabels << "Surface File"; headerLabels << "Volume File"; headerLabels << "Sub Volume"; headerLabels << "Neg Thresh"; headerLabels << "Pos Thresh"; metricNamingTable->setHorizontalHeaderLabels(headerLabels); /* QHeaderView* header = metricNamingTable->horizontalHeader(); header->setLabel(METRIC_NAMING_COLUMN_NAME, "Data Column Name"); header->setLabel(METRIC_NAMING_COLUMN_COMMENT, "Data Column Comment"); header->setLabel(METRIC_NAMING_COLUMN_SURFACE, "Surface File"); header->setLabel(METRIC_NAMING_COLUMN_VOLUME, "Volume File"); header->setLabel(METRIC_NAMING_COLUMN_SUB_VOLUME, "Sub Volume"); header->setLabel(METRIC_NAMING_COLUMN_NEG_THRESH, "Neg Thresh"); header->setLabel(METRIC_NAMING_COLUMN_POS_THRESH, "Pos Thresh"); */ QGroupBox* namingGroupBox = new QGroupBox("Data File Naming"); QVBoxLayout* namingGroupLayout = new QVBoxLayout(namingGroupBox); namingGroupLayout->addLayout(surfaceAndDataFileGridLayout); namingGroupLayout->addWidget(metricNamingTable); namingGroupLayout->addWidget(new QLabel("Double-click a cell to edit the cell's contents in a text editor")); const QString infoMessage = "If mapping to more than one spec file, use the Surface Family control to choose " "the spec file so that its metric column names and comments may be set.

    " "Note: When avolume is mapped, a description of the surface, volume, " "mapping parameters will be added to the column comment information."; QWidget* infoWidget = addPageInformation("Data File Naming Information", infoMessage); QWidget* w = new QWidget; QVBoxLayout* layout = new QVBoxLayout(w); layout->addWidget(namingGroupBox); layout->addWidget(infoWidget); return w; } /** * called when a cell in the metric naming table is double clicked. */ void GuiMapFmriDialog::slotMetricNamingTableCellDoubleClicked(int row, int col) { // // Get the table widget item that was clicked // QTableWidgetItem* twi = metricNamingTable->item(row, col); // // Load the text from the table's cell into a text editor // QtTextEditDialog te(this, false, // NOT read-only true); // modal te.setText(twi->text()); if (te.exec() == QtTextEditDialog::Accepted) { twi->setText(te.getText()); } } /** * called when metric file name select button pressed. */ void GuiMapFmriDialog::slotMetricFilePushButton() { WuQFileDialog fd(this); fd.setModal(true); fd.setDirectory(QDir::currentPath()); fd.setAcceptMode(WuQFileDialog::AcceptSave); fd.setWindowTitle("Choose Data File"); fd.setFileMode(WuQFileDialog::AnyFile); QStringList fileFilters; switch (dataMappingType) { case DATA_MAPPING_TYPE_NONE: break; case DATA_MAPPING_TYPE_METRIC: fileFilters << FileFilters::getMetricFileFilter(); fileFilters << FileFilters::getSurfaceShapeFileFilter(); break; case DATA_MAPPING_TYPE_PAINT: fileFilters << FileFilters::getPaintFileFilter(); fileFilters << FileFilters::getProbAtlasFileFilter(); break; } fd.setFilters(fileFilters); fd.selectFilter(fileFilters.at(0)); fd.selectFile(metricFileNameLineEdit->text()); if (fd.exec() == QDialog::Accepted) { if (fd.selectedFiles().count() > 0) { metricFileNameLineEdit->setText(fd.selectedFiles().at(0)); } } } /** * Load the metric naming combo box. */ void GuiMapFmriDialog::loadMetricNamingComboBox() { metricMappingSetComboBox->clear(); for (int i = 0; i < static_cast(mappingSets.size()); i++) { metricMappingSetComboBox->addItem(mappingSets[i].getDescriptiveLabel()); } } /** * Read the metric naming page */ void GuiMapFmriDialog::slotReadMetricNamingPage() { // // Is there anything in the combo box ? // if (metricMappingSetComboBox->count() > 0) { // // Get the current item of the combo box // const int mappingSetIndex = metricMappingSetComboBox->currentIndex(); if ((mappingSetIndex >= 0) && (mappingSetIndex < static_cast(mappingSets.size()))) { // // Get the mapping set and its metric file // GuiMapFmriMappingSet& ms = mappingSets[mappingSetIndex]; // // Read the metric file name // ms.setMetricFileName(metricFileNameLineEdit->text()); // // Get the number of metric mapping info // const int numMetricInfo = ms.getNumberOfMetricMappingInfo(); // // Loop through metric info // for (int i = 0; i < numMetricInfo; i++) { // // Get the metric info // GuiMapFmriMetricInfo* metricInfo = ms.getMetricMappingInfo(i); // // Get number of metric columns (one per surface) // const int numCols = metricInfo->getNumberOfMetricColumns(); // // Info about functional volume // const int volumeIndex = metricInfo->getVolumeIndex(); const int subVolumeIndex = metricInfo->getSubVolumeIndex(); const QString volumeName(volumesToBeMapped[volumeIndex]->getDescriptiveName()); const QString subVolumeName(volumesToBeMapped[volumeIndex]->getSubVolumeName(subVolumeIndex)); // // Process each metric column // for (int j = 0; j < numCols; j++) { // // If columns are being output // const int rowNumber = metricInfo->getMetricColumnNameRowNumber(j); if (rowNumber >= 0) { // // Set the table data // metricInfo->setMetricColumnName(j, metricNamingTable->item(rowNumber, METRIC_NAMING_COLUMN_NAME)->text()); metricInfo->setMetricColumnComment(j, metricNamingTable->item(rowNumber, METRIC_NAMING_COLUMN_COMMENT)->text()); metricInfo->setMetricColumnThresholds(j, metricNamingTable->item(rowNumber, METRIC_NAMING_COLUMN_NEG_THRESH)->text().toFloat(), metricNamingTable->item(rowNumber, METRIC_NAMING_COLUMN_POS_THRESH)->text().toFloat()); } } // // Add a row for average fiducial if needed // const int avgFiducialRowNumber = metricInfo->getMetricAverageFiducialCoordNameRowNumber(); if (avgFiducialRowNumber >= 0) { // // Set the table data // metricInfo->setMetricAverageFiducialCoordColumnName( metricNamingTable->item(avgFiducialRowNumber, METRIC_NAMING_COLUMN_NAME)->text()); metricInfo->setMetricAverageFiducialCoordComment( metricNamingTable->item(avgFiducialRowNumber, METRIC_NAMING_COLUMN_COMMENT)->text()); metricInfo->setMetricAverageFiducialCoordThresholds( metricNamingTable->item(avgFiducialRowNumber, METRIC_NAMING_COLUMN_NEG_THRESH)->text().toFloat(), metricNamingTable->item(avgFiducialRowNumber, METRIC_NAMING_COLUMN_POS_THRESH)->text().toFloat()); } // // Add a row for average if needed // const int avgRowNumber = metricInfo->getMetricAverageOfAllColumnNameRowNumber(); if (avgRowNumber >= 0) { // // Set the table data // metricInfo->setMetricAverageOfAllColumnName( metricNamingTable->item(avgRowNumber, METRIC_NAMING_COLUMN_NAME)->text()); metricInfo->setMetricAverageOfAllComment( metricNamingTable->item(avgRowNumber, METRIC_NAMING_COLUMN_COMMENT)->text()); metricInfo->setMetricAverageOfAllThresholds( metricNamingTable->item(avgRowNumber, METRIC_NAMING_COLUMN_NEG_THRESH)->text().toFloat(), metricNamingTable->item(avgRowNumber, METRIC_NAMING_COLUMN_POS_THRESH)->text().toFloat()); } // // Add a row for most common if needed // const int mostCommonRowNumber = metricInfo->getMetricMostCommonValueColumnNameRowNumber(); if (mostCommonRowNumber >= 0) { // // Set the table data // metricInfo->setMetricMostCommonValueColumnName( metricNamingTable->item(mostCommonRowNumber, METRIC_NAMING_COLUMN_NAME)->text()); metricInfo->setMetricMostCommonValueComment( metricNamingTable->item(mostCommonRowNumber, METRIC_NAMING_COLUMN_COMMENT)->text()); metricInfo->setMetricMostCommonValueThresholds( metricNamingTable->item(mostCommonRowNumber, METRIC_NAMING_COLUMN_NEG_THRESH)->text().toFloat(), metricNamingTable->item(mostCommonRowNumber, METRIC_NAMING_COLUMN_POS_THRESH)->text().toFloat()); } // // Add a row for most common exclude unidentified if needed // const int mostCommonExcludeUnidentifiedRowNumber = metricInfo->getMetricMostCommonExcludeUnidentifiedValueColumnNameRowNumber(); if (mostCommonExcludeUnidentifiedRowNumber >= 0) { // // Set the table data // metricInfo->setMetricMostCommonExcludeUnidentifiedValueColumnName( metricNamingTable->item(mostCommonExcludeUnidentifiedRowNumber, METRIC_NAMING_COLUMN_NAME)->text()); metricInfo->setMetricMostCommonExcludeUnidentifiedValueComment( metricNamingTable->item(mostCommonExcludeUnidentifiedRowNumber, METRIC_NAMING_COLUMN_COMMENT)->text()); metricInfo->setMetricMostCommonExcludeUnidentifiedValueThresholds( metricNamingTable->item(mostCommonExcludeUnidentifiedRowNumber, METRIC_NAMING_COLUMN_NEG_THRESH)->text().toFloat(), metricNamingTable->item(mostCommonRowNumber, METRIC_NAMING_COLUMN_POS_THRESH)->text().toFloat()); } // // Add a row for deviation if needed // const int stdDevRowNumber = metricInfo->getMetricStdDevColumnNameRowNumber(); if (stdDevRowNumber >= 0) { // // Set the table data // metricInfo->setMetricStdDevColumnName( metricNamingTable->item(stdDevRowNumber, METRIC_NAMING_COLUMN_NAME)->text()); metricInfo->setMetricStdDevComment( metricNamingTable->item(stdDevRowNumber, METRIC_NAMING_COLUMN_COMMENT)->text()); metricInfo->setMetricStdDevThresholds( metricNamingTable->item(stdDevRowNumber, METRIC_NAMING_COLUMN_NEG_THRESH)->text().toFloat(), metricNamingTable->item(stdDevRowNumber, METRIC_NAMING_COLUMN_POS_THRESH)->text().toFloat()); } // // Add a row for standard error if needed // const int stdErrorRowNumber = metricInfo->getMetricStdErrorColumnNameRowNumber(); if (stdErrorRowNumber >= 0) { // // Set the table data // metricInfo->setMetricStdErrorColumnName( metricNamingTable->item(stdErrorRowNumber, METRIC_NAMING_COLUMN_NAME)->text()); metricInfo->setMetricStdErrorComment( metricNamingTable->item(stdErrorRowNumber, METRIC_NAMING_COLUMN_COMMENT)->text()); metricInfo->setMetricStdErrorThresholds( metricNamingTable->item(stdErrorRowNumber, METRIC_NAMING_COLUMN_NEG_THRESH)->text().toFloat(), metricNamingTable->item(stdErrorRowNumber, METRIC_NAMING_COLUMN_POS_THRESH)->text().toFloat()); } // // Add a row for minimum value if needed // const int minValueRowNumber = metricInfo->getMetricMinValueColumnNameRowNumber(); if (minValueRowNumber >= 0) { // // Set the table data // metricInfo->setMetricMinValueColumnName( metricNamingTable->item(minValueRowNumber, METRIC_NAMING_COLUMN_NAME)->text()); metricInfo->setMetricMinValueComment( metricNamingTable->item(minValueRowNumber, METRIC_NAMING_COLUMN_COMMENT)->text()); metricInfo->setMetricMinValueThresholds( metricNamingTable->item(minValueRowNumber, METRIC_NAMING_COLUMN_NEG_THRESH)->text().toFloat(), metricNamingTable->item(minValueRowNumber, METRIC_NAMING_COLUMN_POS_THRESH)->text().toFloat()); } // // Add a row for maximum value if needed // const int maxValueRowNumber = metricInfo->getMetricMaxValueColumnNameRowNumber(); if (maxValueRowNumber >= 0) { // // Set the table data // metricInfo->setMetricMaxValueColumnName( metricNamingTable->item(maxValueRowNumber, METRIC_NAMING_COLUMN_NAME)->text()); metricInfo->setMetricMaxValueComment( metricNamingTable->item(maxValueRowNumber, METRIC_NAMING_COLUMN_COMMENT)->text()); metricInfo->setMetricMaxValueThresholds( metricNamingTable->item(maxValueRowNumber, METRIC_NAMING_COLUMN_NEG_THRESH)->text().toFloat(), metricNamingTable->item(maxValueRowNumber, METRIC_NAMING_COLUMN_POS_THRESH)->text().toFloat()); } } } } } /** * load the metric naming page */ void GuiMapFmriDialog::slotLoadMetricNamingPage() { const int mappingSetIndex = metricMappingSetComboBox->currentIndex(); if (mappingSetIndex < static_cast(mappingSets.size())) { // // Get the mapping set and its metric file // GuiMapFmriMappingSet& ms = mappingSets[mappingSetIndex]; // // Total number of rows in the table // int totalRows = 0; // // Metric File name // metricFileNameLineEdit->setText(ms.getMetricFileName()); // // Hide metric file items if mapping within caret // metricFilePushButton->setHidden(ms.getMappingType() != GuiMapFmriMappingSet::MAPPING_TYPE_WITH_SPEC_FILES); metricFileNameLineEdit->setHidden(ms.getMappingType() != GuiMapFmriMappingSet::MAPPING_TYPE_WITH_SPEC_FILES); // // Get the number of metric mapping info // const int numMetricInfo = ms.getNumberOfMetricMappingInfo(); // // Loop through metric info // for (int i = 0; i < numMetricInfo; i++) { // // Get the metric info // GuiMapFmriMetricInfo* metricInfo = ms.getMetricMappingInfo(i); // // Get number of metric columns (one per surface) // const int numCols = metricInfo->getNumberOfMetricColumns(); // // Add a row for average fiducial if needed // if (ms.getDoAverageFiducialFileFlag()) { metricInfo->setMetricAverageFiducialCoordNameRowNumber(totalRows); totalRows++; } else { metricInfo->setMetricAverageFiducialCoordNameRowNumber(-1); } // // Count number of case (indiv) columns // int numColumnsBeingMapped = 0; for (int j = 0; j < numCols; j++) { numColumnsBeingMapped++; } // // Add a row for average if needed // if (ms.getDoAvgOfAllCoordFileFlag() && (numColumnsBeingMapped > 1)) { metricInfo->setMetricAverageOfAllColumnNameRowNumber(totalRows); totalRows++; } else { metricInfo->setMetricAverageOfAllColumnNameRowNumber(-1); } // // Add a row for most common if needed // if (ms.getDoMostCommonOfAllCasesFlag() && (numColumnsBeingMapped > 1)) { metricInfo->setMetricMostCommonValueColumnNameRowNumber(totalRows); totalRows++; } else { metricInfo->setMetricMostCommonValueColumnNameRowNumber(-1); } // // Add a row for most common exclude unidentified if needed // if (ms.getDoMostCommonExcludeUnidentifiedOfAllCasesFlag() && (numColumnsBeingMapped > 1)) { metricInfo->setMetricMostCommonExcludeUnidentifiedValueColumnNameRowNumber(totalRows); totalRows++; } else { metricInfo->setMetricMostCommonExcludeUnidentifiedValueColumnNameRowNumber(-1); } // // Add a row for deviation if needed // if (ms.getDoStdDevOfAllCoordFileFlag() && (numColumnsBeingMapped > 1)) { metricInfo->setMetricStdDevColumnNameRowNumber(totalRows); totalRows++; } else { metricInfo->setMetricStdDevColumnNameRowNumber(-1); } // // Add a row for standard error if needed // if (ms.getDoStdErrorOfAllCoordFileFlag() && (numColumnsBeingMapped > 1)) { metricInfo->setMetricStdErrorColumnNameRowNumber(totalRows); totalRows++; } else { metricInfo->setMetricStdErrorColumnNameRowNumber(-1); } // // Add a row for minimum value if needed // if (ms.getDoMinOfAllCoordFileFlag() && (numColumnsBeingMapped > 1)) { metricInfo->setMetricMinValueColumnNameRowNumber(totalRows); totalRows++; } else { metricInfo->setMetricMinValueColumnNameRowNumber(-1); } // // Add a row for maximum value if needed // if (ms.getDoMaxOfAllCoordFileFlag() && (numColumnsBeingMapped > 1)) { metricInfo->setMetricMaxValueColumnNameRowNumber(totalRows); totalRows++; } else { metricInfo->setMetricMaxValueColumnNameRowNumber(-1); } // // Process each metric column // for (int j = 0; j < numCols; j++) { // // If columns are being output // if (ms.getDoAllCasesCoordFileFlag()) { metricInfo->setMetricColumnNameRowNumber(j, totalRows); totalRows++; } else { metricInfo->setMetricColumnNameRowNumber(j, -1); } } // // Add a blank row between sets // totalRows++; } // // Set the number of rows for the table // metricNamingTable->setRowCount(totalRows); // // Set all rows to blanks // for (int i = 0; i < totalRows; i++) { metricNamingTable->setItem(i, METRIC_NAMING_COLUMN_NAME, new QTableWidgetItem("")); metricNamingTable->setItem(i, METRIC_NAMING_COLUMN_COMMENT, new QTableWidgetItem("")); metricNamingTable->setItem(i, METRIC_NAMING_COLUMN_SURFACE, new QTableWidgetItem("")); metricNamingTable->setItem(i, METRIC_NAMING_COLUMN_VOLUME, new QTableWidgetItem("")); metricNamingTable->setItem(i, METRIC_NAMING_COLUMN_SUB_VOLUME, new QTableWidgetItem("")); metricNamingTable->setItem(i, METRIC_NAMING_COLUMN_NEG_THRESH, new QTableWidgetItem("")); metricNamingTable->setItem(i, METRIC_NAMING_COLUMN_POS_THRESH, new QTableWidgetItem("")); } // // Loop through metric info // for (int i = 0; i < numMetricInfo; i++) { // // Get the metric info // GuiMapFmriMetricInfo* metricInfo = ms.getMetricMappingInfo(i); // // Get number of metric columns (one per surface) // const int numCols = metricInfo->getNumberOfMetricColumns(); // // Info about functional volume // const int volumeIndex = metricInfo->getVolumeIndex(); const int subVolumeIndex = metricInfo->getSubVolumeIndex(); const QString volumeName(volumesToBeMapped[volumeIndex]->getDescriptiveName()); const QString subVolumeName(volumesToBeMapped[volumeIndex]->getSubVolumeName(subVolumeIndex)); // // Process each metric column // for (int j = 0; j < numCols; j++) { // // If columns are being output // const int rowNumber = metricInfo->getMetricColumnNameRowNumber(j); if (rowNumber >= 0) { // // Set the table data // metricNamingTable->setItem(rowNumber, METRIC_NAMING_COLUMN_NAME, new QTableWidgetItem(metricInfo->getMetricColumnName(j))); metricNamingTable->setItem(rowNumber, METRIC_NAMING_COLUMN_COMMENT, new QTableWidgetItem(metricInfo->getMetricColumnComment(j))); metricNamingTable->setItem(rowNumber, METRIC_NAMING_COLUMN_SURFACE, new QTableWidgetItem(metricInfo->getSurfaceNameForMetricColumn(j))); metricNamingTable->setItem(rowNumber, METRIC_NAMING_COLUMN_VOLUME, new QTableWidgetItem(volumeName)); metricNamingTable->setItem(rowNumber, METRIC_NAMING_COLUMN_SUB_VOLUME, new QTableWidgetItem(subVolumeName)); float negThresh, posThresh; metricInfo->getMetricColumnThresholds(j, negThresh, posThresh); metricNamingTable->setItem(rowNumber, METRIC_NAMING_COLUMN_NEG_THRESH, new QTableWidgetItem(QString::number(negThresh, 'f', 3))); metricNamingTable->setItem(rowNumber, METRIC_NAMING_COLUMN_POS_THRESH, new QTableWidgetItem(QString::number(posThresh, 'f', 3))); } } // // Add a row for average fiducial if needed // const int avgFiducialRowNumber = metricInfo->getMetricAverageFiducialCoordNameRowNumber(); if (avgFiducialRowNumber >= 0) { // // Set the table data // metricNamingTable->setItem(avgFiducialRowNumber, METRIC_NAMING_COLUMN_NAME, new QTableWidgetItem(metricInfo->getMetricAverageFiducialCoordColumnName())); metricNamingTable->setItem(avgFiducialRowNumber, METRIC_NAMING_COLUMN_COMMENT, new QTableWidgetItem(metricInfo->getMetricAverageFiducialCoordComment())); metricNamingTable->setItem(avgFiducialRowNumber, METRIC_NAMING_COLUMN_SURFACE, new QTableWidgetItem(ms.getAverageFiducialCoordFileName())); metricNamingTable->setItem(avgFiducialRowNumber, METRIC_NAMING_COLUMN_VOLUME, new QTableWidgetItem(volumeName)); metricNamingTable->setItem(avgFiducialRowNumber, METRIC_NAMING_COLUMN_SUB_VOLUME, new QTableWidgetItem(subVolumeName)); float negThresh, posThresh; metricInfo->getMetricAverageFiducialCoordThresholds(negThresh, posThresh); metricNamingTable->setItem(avgFiducialRowNumber, METRIC_NAMING_COLUMN_NEG_THRESH, new QTableWidgetItem(QString::number(negThresh, 'f', 3))); metricNamingTable->setItem(avgFiducialRowNumber, METRIC_NAMING_COLUMN_POS_THRESH, new QTableWidgetItem(QString::number(posThresh, 'f', 3))); } // // Add a row for average if needed // const int avgRowNumber = metricInfo->getMetricAverageOfAllColumnNameRowNumber(); if (avgRowNumber >= 0) { // // Set the table data // metricNamingTable->setItem(avgRowNumber, METRIC_NAMING_COLUMN_NAME, new QTableWidgetItem(metricInfo->getMetricAverageOfAllColumnName())); metricNamingTable->setItem(avgRowNumber, METRIC_NAMING_COLUMN_COMMENT, new QTableWidgetItem(metricInfo->getMetricAverageOfAllComment())); metricNamingTable->setItem(avgRowNumber, METRIC_NAMING_COLUMN_SURFACE, new QTableWidgetItem("All Surfaces")); metricNamingTable->setItem(avgRowNumber, METRIC_NAMING_COLUMN_VOLUME, new QTableWidgetItem(volumeName)); metricNamingTable->setItem(avgRowNumber, METRIC_NAMING_COLUMN_SUB_VOLUME, new QTableWidgetItem(subVolumeName)); float negThresh, posThresh; metricInfo->getMetricAverageOfAllThresholds(negThresh, posThresh); metricNamingTable->setItem(avgRowNumber, METRIC_NAMING_COLUMN_NEG_THRESH, new QTableWidgetItem(QString::number(negThresh, 'f', 3))); metricNamingTable->setItem(avgRowNumber, METRIC_NAMING_COLUMN_POS_THRESH, new QTableWidgetItem(QString::number(posThresh, 'f', 3))); } // // Add a row for most common if needed // const int mostCommonRowNumber = metricInfo->getMetricMostCommonValueColumnNameRowNumber(); if (mostCommonRowNumber >= 0) { // // Set the table data // metricNamingTable->setItem(mostCommonRowNumber, METRIC_NAMING_COLUMN_NAME, new QTableWidgetItem(metricInfo->getMetricMostCommonValueColumnName())); metricNamingTable->setItem(mostCommonRowNumber, METRIC_NAMING_COLUMN_COMMENT, new QTableWidgetItem(metricInfo->getMetricMostCommonValueComment())); metricNamingTable->setItem(mostCommonRowNumber, METRIC_NAMING_COLUMN_SURFACE, new QTableWidgetItem("All Surfaces")); metricNamingTable->setItem(mostCommonRowNumber, METRIC_NAMING_COLUMN_VOLUME, new QTableWidgetItem(volumeName)); metricNamingTable->setItem(mostCommonRowNumber, METRIC_NAMING_COLUMN_SUB_VOLUME, new QTableWidgetItem(subVolumeName)); float negThresh, posThresh; metricInfo->getMetricMostCommonValueThresholds(negThresh, posThresh); metricNamingTable->setItem(mostCommonRowNumber, METRIC_NAMING_COLUMN_NEG_THRESH, new QTableWidgetItem(QString::number(negThresh, 'f', 3))); metricNamingTable->setItem(mostCommonRowNumber, METRIC_NAMING_COLUMN_POS_THRESH, new QTableWidgetItem(QString::number(posThresh, 'f', 3))); } // // Add a row for most common exclude unidentified if needed // const int mostCommonExcludeUnidentifiedRowNumber = metricInfo->getMetricMostCommonExcludeUnidentifiedValueColumnNameRowNumber(); if (mostCommonExcludeUnidentifiedRowNumber >= 0) { // // Set the table data // metricNamingTable->setItem(mostCommonExcludeUnidentifiedRowNumber, METRIC_NAMING_COLUMN_NAME, new QTableWidgetItem(metricInfo->getMetricMostCommonExcludeUnidentifiedValueColumnName())); metricNamingTable->setItem(mostCommonExcludeUnidentifiedRowNumber, METRIC_NAMING_COLUMN_COMMENT, new QTableWidgetItem(metricInfo->getMetricMostCommonExcludeUnidentifiedValueComment())); metricNamingTable->setItem(mostCommonExcludeUnidentifiedRowNumber, METRIC_NAMING_COLUMN_SURFACE, new QTableWidgetItem("All Surfaces")); metricNamingTable->setItem(mostCommonExcludeUnidentifiedRowNumber, METRIC_NAMING_COLUMN_VOLUME, new QTableWidgetItem(volumeName)); metricNamingTable->setItem(mostCommonExcludeUnidentifiedRowNumber, METRIC_NAMING_COLUMN_SUB_VOLUME, new QTableWidgetItem(subVolumeName)); float negThresh, posThresh; metricInfo->getMetricMostCommonExcludeUnidentifiedValueThresholds(negThresh, posThresh); metricNamingTable->setItem(mostCommonExcludeUnidentifiedRowNumber, METRIC_NAMING_COLUMN_NEG_THRESH, new QTableWidgetItem(QString::number(negThresh, 'f', 3))); metricNamingTable->setItem(mostCommonExcludeUnidentifiedRowNumber, METRIC_NAMING_COLUMN_POS_THRESH, new QTableWidgetItem(QString::number(posThresh, 'f', 3))); } // // Add a row for deviation if needed // const int stdDevRowNumber = metricInfo->getMetricStdDevColumnNameRowNumber(); if (stdDevRowNumber >= 0) { // // Set the table data // metricNamingTable->setItem(stdDevRowNumber, METRIC_NAMING_COLUMN_NAME, new QTableWidgetItem(metricInfo->getMetricStdDevColumnName())); metricNamingTable->setItem(stdDevRowNumber, METRIC_NAMING_COLUMN_COMMENT, new QTableWidgetItem(metricInfo->getMetricStdDevComment())); metricNamingTable->setItem(stdDevRowNumber, METRIC_NAMING_COLUMN_SURFACE, new QTableWidgetItem("All Surfaces")); metricNamingTable->setItem(stdDevRowNumber, METRIC_NAMING_COLUMN_VOLUME, new QTableWidgetItem(volumeName)); metricNamingTable->setItem(stdDevRowNumber, METRIC_NAMING_COLUMN_SUB_VOLUME, new QTableWidgetItem(subVolumeName)); float negThresh, posThresh; metricInfo->getMetricStdDevThresholds(negThresh, posThresh); metricNamingTable->setItem(stdDevRowNumber, METRIC_NAMING_COLUMN_NEG_THRESH, new QTableWidgetItem(QString::number(negThresh, 'f', 3))); metricNamingTable->setItem(stdDevRowNumber, METRIC_NAMING_COLUMN_POS_THRESH, new QTableWidgetItem(QString::number(posThresh, 'f', 3))); } // // Add a row for standard error if needed // const int stdErrorRowNumber = metricInfo->getMetricStdErrorColumnNameRowNumber(); if (stdErrorRowNumber >= 0) { // // Set the table data // metricNamingTable->setItem(stdErrorRowNumber, METRIC_NAMING_COLUMN_NAME, new QTableWidgetItem(metricInfo->getMetricStdErrorColumnName())); metricNamingTable->setItem(stdErrorRowNumber, METRIC_NAMING_COLUMN_COMMENT, new QTableWidgetItem(metricInfo->getMetricStdErrorComment())); metricNamingTable->setItem(stdErrorRowNumber, METRIC_NAMING_COLUMN_SURFACE, new QTableWidgetItem("All Surfaces")); metricNamingTable->setItem(stdErrorRowNumber, METRIC_NAMING_COLUMN_VOLUME, new QTableWidgetItem(volumeName)); metricNamingTable->setItem(stdErrorRowNumber, METRIC_NAMING_COLUMN_SUB_VOLUME, new QTableWidgetItem(subVolumeName)); float negThresh, posThresh; metricInfo->getMetricStdErrorThresholds(negThresh, posThresh); metricNamingTable->setItem(stdErrorRowNumber, METRIC_NAMING_COLUMN_NEG_THRESH, new QTableWidgetItem(QString::number(negThresh, 'f', 3))); metricNamingTable->setItem(stdErrorRowNumber, METRIC_NAMING_COLUMN_POS_THRESH, new QTableWidgetItem(QString::number(posThresh, 'f', 3))); } // // Add a row for minimum value if needed // const int minValueRowNumber = metricInfo->getMetricMinValueColumnNameRowNumber(); if (minValueRowNumber >= 0) { // // Set the table data // metricNamingTable->setItem(minValueRowNumber, METRIC_NAMING_COLUMN_NAME, new QTableWidgetItem(metricInfo->getMetricMinValueColumnName())); metricNamingTable->setItem(minValueRowNumber, METRIC_NAMING_COLUMN_COMMENT, new QTableWidgetItem(metricInfo->getMetricMinValueComment())); metricNamingTable->setItem(minValueRowNumber, METRIC_NAMING_COLUMN_SURFACE, new QTableWidgetItem("All Surfaces")); metricNamingTable->setItem(minValueRowNumber, METRIC_NAMING_COLUMN_VOLUME, new QTableWidgetItem(volumeName)); metricNamingTable->setItem(minValueRowNumber, METRIC_NAMING_COLUMN_SUB_VOLUME, new QTableWidgetItem(subVolumeName)); float negThresh, posThresh; metricInfo->getMetricMinValueThresholds(negThresh, posThresh); metricNamingTable->setItem(minValueRowNumber, METRIC_NAMING_COLUMN_NEG_THRESH, new QTableWidgetItem(QString::number(negThresh, 'f', 3))); metricNamingTable->setItem(minValueRowNumber, METRIC_NAMING_COLUMN_POS_THRESH, new QTableWidgetItem(QString::number(posThresh, 'f', 3))); } // // Add a row for maximum value if needed // const int maxValueRowNumber = metricInfo->getMetricMaxValueColumnNameRowNumber(); if (maxValueRowNumber >= 0) { // // Set the table data // metricNamingTable->setItem(maxValueRowNumber, METRIC_NAMING_COLUMN_NAME, new QTableWidgetItem(metricInfo->getMetricMaxValueColumnName())); metricNamingTable->setItem(maxValueRowNumber, METRIC_NAMING_COLUMN_COMMENT, new QTableWidgetItem(metricInfo->getMetricMaxValueComment())); metricNamingTable->setItem(maxValueRowNumber, METRIC_NAMING_COLUMN_SURFACE, new QTableWidgetItem("All Surfaces")); metricNamingTable->setItem(maxValueRowNumber, METRIC_NAMING_COLUMN_VOLUME, new QTableWidgetItem(volumeName)); metricNamingTable->setItem(maxValueRowNumber, METRIC_NAMING_COLUMN_SUB_VOLUME, new QTableWidgetItem(subVolumeName)); float negThresh, posThresh; metricInfo->getMetricMaxValueThresholds(negThresh, posThresh); metricNamingTable->setItem(maxValueRowNumber, METRIC_NAMING_COLUMN_NEG_THRESH, new QTableWidgetItem(QString::number(negThresh, 'f', 3))); metricNamingTable->setItem(maxValueRowNumber, METRIC_NAMING_COLUMN_POS_THRESH, new QTableWidgetItem(QString::number(posThresh, 'f', 3))); } } } else { metricNamingTable->setRowCount(0); } bool showThreshColumns = false; switch (dataMappingType) { case DATA_MAPPING_TYPE_NONE: break; case DATA_MAPPING_TYPE_METRIC: showThreshColumns = true; break; case DATA_MAPPING_TYPE_PAINT: break; } if (showThreshColumns) { metricNamingTable->showColumn(METRIC_NAMING_COLUMN_NEG_THRESH); metricNamingTable->showColumn(METRIC_NAMING_COLUMN_POS_THRESH); } else { metricNamingTable->hideColumn(METRIC_NAMING_COLUMN_NEG_THRESH); metricNamingTable->hideColumn(METRIC_NAMING_COLUMN_POS_THRESH); } } /** * create the algorithm page. */ QWidget* GuiMapFmriDialog::createAlgorithmPage() { std::vector algNames; std::vector algValues; BrainModelVolumeToSurfaceMapperAlgorithmParameters::getAlgorithmNamesAndValues( algNames, algValues); algorithmComboBox = new QComboBox; for (unsigned int i = 0; i < algNames.size(); i++) { algorithmComboBox->insertItem(algValues[i], algNames[i]); } QObject::connect(algorithmComboBox, SIGNAL(activated(int)), this, SLOT(slotAlgorithmComboBox(int))); // // Widget stack for algorithm parameters // algorithmParameterWidgetStack = new QStackedWidget; // // Parameters for average nodes algorithm // algorithmMetricAverageNodesParametersBox = new QWidget; algorithmParameterWidgetStack->addWidget(algorithmMetricAverageNodesParametersBox); // // Parameters for average voxel algorithm // QLabel* avgVoxLabel = new QLabel("Neighbor Box Size"); algorithmAverageVoxelNeighborDoubleSpinBox = new QDoubleSpinBox; algorithmAverageVoxelNeighborDoubleSpinBox->setMinimum(0.0); algorithmAverageVoxelNeighborDoubleSpinBox->setMaximum(10000.0); algorithmAverageVoxelNeighborDoubleSpinBox->setSingleStep(1.0); algorithmAverageVoxelNeighborDoubleSpinBox->setDecimals(2); algorithmMetricAverageVoxelParametersBox = new QWidget; QHBoxLayout* avgVoxLayout = new QHBoxLayout(algorithmMetricAverageVoxelParametersBox); avgVoxLayout->addWidget(avgVoxLabel); avgVoxLayout->addWidget(algorithmAverageVoxelNeighborDoubleSpinBox); avgVoxLayout->addStretch(); algorithmMetricAverageVoxelParametersBox->setFixedSize(algorithmMetricAverageVoxelParametersBox->sizeHint()); algorithmParameterWidgetStack->addWidget(algorithmMetricAverageVoxelParametersBox); // // Parameters for enclosing voxel algorithm // algorithmMetricEnclosingVoxelParametersBox = new QWidget; algorithmParameterWidgetStack->addWidget(algorithmMetricEnclosingVoxelParametersBox); // // Parameters for gaussian algorithm // QLabel* gaussBoxLabel = new QLabel("Neighbor Box Size"); algorithmGaussianNeighborDoubleSpinBox = new QDoubleSpinBox; algorithmGaussianNeighborDoubleSpinBox->setMinimum(0.0); algorithmGaussianNeighborDoubleSpinBox->setMaximum(10000.0); algorithmGaussianNeighborDoubleSpinBox->setSingleStep(1.0); algorithmGaussianNeighborDoubleSpinBox->setDecimals(3); QLabel* gaussSNLabel = new QLabel("Sigma Normal"); algorithmGaussianSigmaNormDoubleSpinBox = new QDoubleSpinBox; algorithmGaussianSigmaNormDoubleSpinBox->setMinimum(0.01); algorithmGaussianSigmaNormDoubleSpinBox->setMaximum(10000.0); algorithmGaussianSigmaNormDoubleSpinBox->setSingleStep(1.0); algorithmGaussianSigmaNormDoubleSpinBox->setDecimals(3); QLabel* gaussSTLabel = new QLabel("Sigma Tangent"); algorithmGaussianSigmaTangDoubleSpinBox = new QDoubleSpinBox; algorithmGaussianSigmaTangDoubleSpinBox->setMinimum(0.01); algorithmGaussianSigmaTangDoubleSpinBox->setMaximum(10000.0); algorithmGaussianSigmaTangDoubleSpinBox->setSingleStep(1.0); algorithmGaussianSigmaTangDoubleSpinBox->setDecimals(3); QLabel* gaussNBCLabel = new QLabel("Normal Below Cutoff"); algorithmGaussianNormBelowDoubleSpinBox = new QDoubleSpinBox; algorithmGaussianNormBelowDoubleSpinBox->setMinimum(0.01); algorithmGaussianNormBelowDoubleSpinBox->setMaximum(10000.0); algorithmGaussianNormBelowDoubleSpinBox->setSingleStep(1.0); algorithmGaussianNormBelowDoubleSpinBox->setDecimals(3); QLabel* gaussNACLabel = new QLabel("Normal Above Cutoff"); algorithmGaussianNormAboveDoubleSpinBox = new QDoubleSpinBox; algorithmGaussianNormAboveDoubleSpinBox->setMinimum(0.01); algorithmGaussianNormAboveDoubleSpinBox->setMaximum(10000.0); algorithmGaussianNormAboveDoubleSpinBox->setSingleStep(1.0); algorithmGaussianNormAboveDoubleSpinBox->setDecimals(3); QLabel* gaussTCLabel = new QLabel("Tangent Cutoff"); algorithmGaussianTangCutoffDoubleSpinBox = new QDoubleSpinBox; algorithmGaussianTangCutoffDoubleSpinBox->setMinimum(0.01); algorithmGaussianTangCutoffDoubleSpinBox->setMaximum(10000.0); algorithmGaussianTangCutoffDoubleSpinBox->setSingleStep(1.0); algorithmGaussianTangCutoffDoubleSpinBox->setDecimals(3); algorithmMetricGaussianParametersBox = new QWidget; QGridLayout* gaussLayout = new QGridLayout(algorithmMetricGaussianParametersBox); gaussLayout->addWidget(gaussBoxLabel, 0, 0); gaussLayout->addWidget(algorithmGaussianNeighborDoubleSpinBox, 0, 1); gaussLayout->addWidget(gaussSNLabel, 1, 0); gaussLayout->addWidget(algorithmGaussianSigmaNormDoubleSpinBox, 1, 1); gaussLayout->addWidget(gaussSTLabel, 2, 0); gaussLayout->addWidget(algorithmGaussianSigmaTangDoubleSpinBox, 2, 1); gaussLayout->addWidget(gaussNBCLabel, 3, 0); gaussLayout->addWidget(algorithmGaussianNormBelowDoubleSpinBox, 3, 1); gaussLayout->addWidget(gaussNACLabel, 4, 0); gaussLayout->addWidget(algorithmGaussianNormAboveDoubleSpinBox, 4, 1); gaussLayout->addWidget(gaussTCLabel, 5, 0); gaussLayout->addWidget(algorithmGaussianTangCutoffDoubleSpinBox, 5, 1); algorithmMetricGaussianParametersBox->setFixedSize(algorithmMetricGaussianParametersBox->sizeHint()); algorithmParameterWidgetStack->addWidget(algorithmMetricGaussianParametersBox); // // Parameters for interpolated voxel algorithm // algorithmMetricInterpolatedVoxelParametersBox = new QWidget; algorithmParameterWidgetStack->addWidget(algorithmMetricInterpolatedVoxelParametersBox); // // Parameters for maximum voxel algorithm // QLabel* maxLabel = new QLabel("Neighbor Box Size"); algorithmMaximumVoxelNeighborDoubleSpinBox = new QDoubleSpinBox; algorithmMaximumVoxelNeighborDoubleSpinBox->setMinimum(0.0); algorithmMaximumVoxelNeighborDoubleSpinBox->setMaximum(10000.0); algorithmMaximumVoxelNeighborDoubleSpinBox->setSingleStep(1.0); algorithmMaximumVoxelNeighborDoubleSpinBox->setDecimals(2); algorithmMetricMaximumVoxelParametersBox = new QWidget; QHBoxLayout* maxVoxLayout = new QHBoxLayout(algorithmMetricMaximumVoxelParametersBox); maxVoxLayout->addWidget(maxLabel); maxVoxLayout->addWidget(algorithmMaximumVoxelNeighborDoubleSpinBox); maxVoxLayout->addStretch(); algorithmMetricMaximumVoxelParametersBox->setFixedSize(algorithmMetricMaximumVoxelParametersBox->sizeHint()); algorithmParameterWidgetStack->addWidget(algorithmMetricMaximumVoxelParametersBox); // // Parameters for MCW BrainFish algorithm // QLabel* mcwDistLabel = new QLabel("Max Distance"); algorithmBrainFishMaxDistanceDoubleSpinBox = new QDoubleSpinBox; algorithmBrainFishMaxDistanceDoubleSpinBox->setMinimum(0.0); algorithmBrainFishMaxDistanceDoubleSpinBox->setMaximum(10000.0); algorithmBrainFishMaxDistanceDoubleSpinBox->setSingleStep(1.0); algorithmBrainFishMaxDistanceDoubleSpinBox->setDecimals(3); QLabel* mcwSplatLabel = new QLabel("Splat Factor"); algorithmBrainFishSplatFactorSpinBox = new QSpinBox; algorithmBrainFishSplatFactorSpinBox->setMinimum(0); algorithmBrainFishSplatFactorSpinBox->setMaximum(10000); algorithmBrainFishSplatFactorSpinBox->setSingleStep(1); algorithmMetricMcwBrainFishParametersBox = new QWidget; QGridLayout* mcwLayout = new QGridLayout(algorithmMetricMcwBrainFishParametersBox); mcwLayout->addWidget(mcwDistLabel, 0, 0); mcwLayout->addWidget(algorithmBrainFishMaxDistanceDoubleSpinBox, 0, 1); mcwLayout->addWidget(mcwSplatLabel, 1, 0); mcwLayout->addWidget(algorithmBrainFishSplatFactorSpinBox, 1, 1); algorithmMetricMcwBrainFishParametersBox->setFixedSize(algorithmMetricMcwBrainFishParametersBox->sizeHint()); algorithmParameterWidgetStack->addWidget(algorithmMetricMcwBrainFishParametersBox); // // Parameters for strongest voxel algorithm // QLabel* strongestLabel = new QLabel("Neighbor Box Size"); algorithmStrongestVoxelNeighborDoubleSpinBox = new QDoubleSpinBox; algorithmStrongestVoxelNeighborDoubleSpinBox->setMinimum(0.0); algorithmStrongestVoxelNeighborDoubleSpinBox->setMaximum(10000.0); algorithmStrongestVoxelNeighborDoubleSpinBox->setSingleStep(1.0); algorithmStrongestVoxelNeighborDoubleSpinBox->setDecimals(2); algorithmMetricStrongestVoxelParametersBox = new QWidget; QHBoxLayout* strongestVoxLayout = new QHBoxLayout(algorithmMetricStrongestVoxelParametersBox); strongestVoxLayout->addWidget(strongestLabel); strongestVoxLayout->addWidget(algorithmStrongestVoxelNeighborDoubleSpinBox); strongestVoxLayout->addStretch(); algorithmMetricStrongestVoxelParametersBox->setFixedSize(algorithmMetricStrongestVoxelParametersBox->sizeHint()); algorithmParameterWidgetStack->addWidget(algorithmMetricStrongestVoxelParametersBox); // // Parameters for enclosing voxel algorithm // algorithmPaintEnclosingVoxelParametersBox = new QWidget; algorithmParameterWidgetStack->addWidget(algorithmPaintEnclosingVoxelParametersBox); // // Group box for mapping selection and parameters // QGroupBox* mappingGroupBox = new QGroupBox("Mapping Algorithm"); QVBoxLayout* mappingGroupLayout = new QVBoxLayout(mappingGroupBox); mappingGroupLayout->addWidget(algorithmComboBox); mappingGroupLayout->addWidget(algorithmParameterWidgetStack); // // Help Text // algorithmInformationTextEdit = new QTextBrowser; QWidget* infoWidget = addPageInformation("Mapping Algorithm Information", "", algorithmInformationTextEdit); // // widget for page and layout // QWidget* w = new QWidget; QVBoxLayout* algLayout = new QVBoxLayout(w); algLayout->addWidget(mappingGroupBox); algLayout->addWidget(infoWidget); return w; } /** * Load the algorithm parameters from the preferences file. */ void GuiMapFmriDialog::loadAlgorithmParametersFromPreferences() { static bool loadedFlag = false; if (loadedFlag) { return; } loadedFlag = true; // // Algorithm // algorithmComboBox->setCurrentIndex(mappingParameters.getAlgorithm()); slotAlgorithmComboBox(algorithmComboBox->currentIndex()); // // Average voxel parameters // float avgVoxNeighbor = 1.0; mappingParameters.getAlgorithmMetricAverageVoxelParameters(avgVoxNeighbor); algorithmAverageVoxelNeighborDoubleSpinBox->setValue(avgVoxNeighbor); // // Maximum voxel parameters // float maxVoxNeighbor = 1.0; mappingParameters.getAlgorithmMetricMaximumVoxelParameters(maxVoxNeighbor); algorithmMaximumVoxelNeighborDoubleSpinBox->setValue(maxVoxNeighbor); // // Strongest voxel parameters // float strongestVoxNeighbor = 1.0; mappingParameters.getAlgorithmMetricStrongestVoxelParameters(strongestVoxNeighbor); algorithmStrongestVoxelNeighborDoubleSpinBox->setValue(strongestVoxNeighbor); // // Gaussian parameters // float gaussNeighbor; float gaussSigmaTang; float gaussSigmaNorm; float gaussNormBelow; float gaussNormAbove; float gaussTang; mappingParameters.getAlgorithmMetricGaussianParameters(gaussNeighbor, gaussSigmaTang, gaussSigmaNorm, gaussNormBelow, gaussNormAbove, gaussTang); algorithmGaussianNeighborDoubleSpinBox->setValue(gaussNeighbor); algorithmGaussianSigmaNormDoubleSpinBox->setValue(gaussSigmaNorm); algorithmGaussianSigmaTangDoubleSpinBox->setValue(gaussSigmaTang); algorithmGaussianNormBelowDoubleSpinBox->setValue(gaussNormBelow); algorithmGaussianNormAboveDoubleSpinBox->setValue(gaussNormAbove); algorithmGaussianTangCutoffDoubleSpinBox->setValue(gaussTang); // // MCW BrainFish Parameters // float bfMaxDist; int bfSplat; mappingParameters.getAlgorithmMetricMcwBrainFishParameters(bfMaxDist, bfSplat); algorithmBrainFishMaxDistanceDoubleSpinBox->setValue(bfMaxDist); algorithmBrainFishSplatFactorSpinBox->setValue(bfSplat); } /** * Called when an algorithm is selected. */ void GuiMapFmriDialog::slotAlgorithmComboBox(int item) { const BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM alg = static_cast(item); mappingParameters.setAlgorithm(alg); QString infoText = "For all algorithms, the node's stereotaxic position identifies " "a voxel in the volume.

    "; switch(alg) { case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_METRIC_AVERAGE_NODES: algorithmParameterWidgetStack->setCurrentWidget(algorithmMetricAverageNodesParametersBox); infoText += "Average Nodes Algorithm:

    " "Each node is set to the average of the voxel it falls within and " "the voxels containing the node's connected neighbors."; break; case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_METRIC_AVERAGE_VOXEL: algorithmParameterWidgetStack->setCurrentWidget(algorithmMetricAverageVoxelParametersBox); infoText += "Average Voxel Algorithm:

    " "A cube with each edge NEIGHBORHOOD SIZE millimeters long is " "centered at the node. The node is assigned the average of " "all voxels that are contained in the cube."; break; case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_METRIC_ENCLOSING_VOXEL: algorithmParameterWidgetStack->setCurrentWidget(algorithmMetricEnclosingVoxelParametersBox); infoText += "Enclosing Voxel Algorithm:

    " "The node is assigned the voxel that contains the node."; break; case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_METRIC_GAUSSIAN: algorithmParameterWidgetStack->setCurrentWidget(algorithmMetricGaussianParametersBox); infoText += "Gaussian Algorithm:

    " "The gaussian is defined by the equation e(-(norm*norm)/(sigma*sigma))

    " "A cube whose sides are of length NEIGHBOR BOX SIZE is placed around " "each node. All voxels within this box contribute to the node's value.

    " "SIGMA NORMAL "; infoText += StringUtilities::replace( GaussianComputation::tooltipTextForSigmaNorm(), '\n', ' '); infoText += "

    "; infoText += "SIGMA TANGENT "; infoText += StringUtilities::replace( GaussianComputation::tooltipTextForSigmaTang(), '\n', ' '); infoText += "

    "; infoText += "NORMAL BELOW CUTOFF "; infoText += StringUtilities::replace( GaussianComputation::tooltipTextForNormBelowCutoff(), '\n', ' '); infoText += "

    "; infoText += "NORMAL ABOVE CUTOFF "; infoText += StringUtilities::replace( GaussianComputation::tooltipTextForNormAboveCutoff(), '\n', ' '); infoText += "

    "; infoText += "TANGENT CUTOFF "; infoText += StringUtilities::replace( GaussianComputation::tooltipTextForTangentCutoff(), '\n', ' '); break; case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_METRIC_INTERPOLATED_VOXEL: algorithmParameterWidgetStack->setCurrentWidget(algorithmMetricInterpolatedVoxelParametersBox); infoText += "Interpolated Voxel Algorithm:

    " "The node containing the voxel is determined. A cube the " "size of the volume's voxel size is centered at the node. " "This cube intersects the voxel containing the node and " "parts of neighboring voxels. A weighted average is assigned " "to the node based upon the cubes intersection with the neighboring " "voxels. If the node is at the exact center of a voxel, the value " "assigned to the node would be the same as the Enclosing Voxel " "Algorithm"; break; case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_METRIC_MAXIMUM_VOXEL: algorithmParameterWidgetStack->setCurrentWidget(algorithmMetricMaximumVoxelParametersBox); infoText += "Maximum Voxel Algorithm:

    " "A cube with each edge NEIGHBORHOOD SIZE millimeters long is " "centered at the node. The node is assigned the maximum of " "all voxels that are contained in the cube. If the cube " "contains only voxels with negative values, the node will be " "assigned the most negative value. If the cube contains any " "positive values, the node will be assigned the most positive value."; break; case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_METRIC_MCW_BRAINFISH: algorithmParameterWidgetStack->setCurrentWidget(algorithmMetricMcwBrainFishParametersBox); infoText += "MCW BrainFish Algorithm:

    " "This algorithm loops through the voxels. For each voxel that " "is non-zero, the algorithm find the closest node that is within " "MAX DISTANCE millimeters. If the node's current value is less " "than that of the current voxel, the voxel is assigned to the node " "The splat factor essentially smooths the nodes for SPLAT FACTOR " "iterations."; break; case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_METRIC_STRONGEST_VOXEL: algorithmParameterWidgetStack->setCurrentWidget(algorithmMetricStrongestVoxelParametersBox); infoText += "Strongest Voxel Algorithm:

    " "A cube with each edge NEIGHBORHOOD SIZE millimeters long is " "centered at the node. The node is assigned the value of the " "voxel that is furthest from zero. "; break; case BrainModelVolumeToSurfaceMapperAlgorithmParameters::ALGORITHM_PAINT_ENCLOSING_VOXEL: algorithmParameterWidgetStack->setCurrentWidget(algorithmPaintEnclosingVoxelParametersBox); infoText += "Enclosing Voxel Algorithm:

    " "The node is assigned the voxel that contains the node."; break; } algorithmInformationTextEdit->setHtml(infoText); } /** * create the summary page. */ QWidget* GuiMapFmriDialog::createSummaryPage() { // // Text edit for summary // summaryTextEdit = new QTextEdit; summaryTextEdit->setReadOnly(true); // // Group box and layout for summary // QGroupBox* summaryGroupBox = new QGroupBox("Summary"); QVBoxLayout* summaryLayout = new QVBoxLayout(summaryGroupBox); summaryLayout->addWidget(summaryTextEdit); QWidget* w = new QWidget; QVBoxLayout* pageLayout = new QVBoxLayout(w); pageLayout->addWidget(summaryGroupBox); return w; } /** * Load the summary text edit */ void GuiMapFmriDialog::loadSummaryTextEdit() { QString text; // // For each mapping set // for (int i = 0; i < static_cast(mappingSets.size()); i++) { if (i > 0) { text.append("---------------------------------------------------------------------\n"); } // // Get mapping set // const GuiMapFmriMappingSet& mms = mappingSets[i]; for (int m = 0; m < mms.getNumberOfMetricMappingInfo(); m++) { // // List the destination surface // switch (mms.getMetricOutputType()) { case GuiMapFmriMappingSet::METRIC_OUTPUT_TYPE_NONE: break; case GuiMapFmriMappingSet::METRIC_OUTPUT_TYPE_CARET_METRIC: if (mms.getMappingWithAtlasFlag()) { text.append("Map to Caret5 With Atlas"); } else { text.append("Map to Surface(s) in Caret5"); } text.append("\n"); break; case GuiMapFmriMappingSet::METRIC_OUTPUT_TYPE_SPEC_FILE: text.append("Map to Spec File: "); text.append(FileUtilities::basename(mms.getOutputSpecFileName())); if (mms.getMappingWithAtlasFlag()) { text.append(" With Atlas"); } text.append("\n"); text.append("Metric File: "); text.append(mms.getMetricFileName()); text.append("\n"); break; } text.append("\n"); // // Get the metric info // const GuiMapFmriMetricInfo* mi = mms.getMetricMappingInfo(m); const int volumeNumber = mi->getVolumeIndex(); const int subVolumeNumber = mi->getSubVolumeIndex(); const QString volumeName(volumesToBeMapped[volumeNumber]->getDescriptiveName()); const QString subVolumeName(volumesToBeMapped[volumeNumber]->getSubVolumeName(subVolumeNumber)); if (mms.getDoAverageFiducialFileFlag() && (mi->getMetricAverageFiducialCoordNameRowNumber() >= 0)) { text.append("Average Fiducial: "); text.append(mi->getMetricAverageFiducialCoordColumnName()); text.append("\n"); // // Surface and Volume name // text.append(" using surface: "); text.append(FileUtilities::basename(mms.getAverageFiducialCoordFileName())); text.append("\n"); text.append(" from volume: "); text.append(volumeName); text.append("\n"); text.append(" sub-volume: "); text.append(subVolumeName); text.append("\n\n"); } // // List average if applicable // if (mms.getDoAvgOfAllCoordFileFlag() && (mi->getMetricAverageOfAllColumnNameRowNumber() >= 0)) { text.append("Average Column: "); text.append(mi->getMetricAverageOfAllColumnName()); text.append("\n\n"); } // // List most common if applicable // if (mms.getDoMostCommonOfAllCasesFlag() && (mi->getMetricMostCommonValueColumnNameRowNumber() >= 0)) { text.append("Most Common Column: "); text.append(mi->getMetricMostCommonValueColumnName()); text.append("\n\n"); } // // List most common exclude unidentified if applicable // if (mms.getDoMostCommonExcludeUnidentifiedOfAllCasesFlag() && (mi->getMetricMostCommonExcludeUnidentifiedValueColumnNameRowNumber() >= 0)) { text.append("Most Common Exclude No ID Column: "); text.append(mi->getMetricMostCommonExcludeUnidentifiedValueColumnName()); text.append("\n\n"); } // // List Standard Deviation if applicable // if (mms.getDoStdDevOfAllCoordFileFlag() && (mi->getMetricStdDevColumnNameRowNumber() >= 0)) { text.append("Sample Standard Deviation Column: "); text.append(mi->getMetricStdDevColumnName()); text.append("\n"); } // // List Standard Error if applicable // if (mms.getDoStdErrorOfAllCoordFileFlag() && (mi->getMetricStdErrorColumnNameRowNumber() >= 0)) { text.append("Standard Error Column: "); text.append(mi->getMetricStdErrorColumnName()); text.append("\n\n"); } // // List Min Value if applicable // if (mms.getDoMinOfAllCoordFileFlag() && (mi->getMetricMinValueColumnNameRowNumber() >= 0)) { text.append("Minimum Value Column: "); text.append(mi->getMetricMinValueColumnName()); text.append("\n\n"); } // // List Max Value if applicable // if (mms.getDoMaxOfAllCoordFileFlag() && (mi->getMetricMaxValueColumnNameRowNumber() >= 0)) { text.append("Maximum Value Column: "); text.append(mi->getMetricMaxValueColumnName()); text.append("\n\n"); } // // are columns being generated // if (mms.getDoAllCasesCoordFileFlag()) { // // List metric naming information // for (int j = 0; j < mi->getNumberOfMetricColumns(); j++) { // // Column name // text.append("Data Column "); text.append(StringUtilities::fromNumber(j)); text.append(" Name : \""); text.append(mi->getMetricColumnName(j)); text.append("\"\n"); // // Surface and Volume name // text.append(" using surface: "); text.append(mi->getSurfaceNameForMetricColumn(j)); text.append("\n"); text.append(" from volume: "); text.append(volumeName); text.append("\n"); text.append(" sub-volume: "); text.append(subVolumeName); text.append("\n"); } } text.append("\n"); } } bool showAlgorithm = false; switch (dataMappingType) { case DATA_MAPPING_TYPE_NONE: break; case DATA_MAPPING_TYPE_METRIC: showAlgorithm = true; break; case DATA_MAPPING_TYPE_PAINT: break; } if (showAlgorithm) { text += "Algorithm: "; text += BrainModelVolumeToSurfaceMapperAlgorithmParameters::getAlgorithmName(mappingParameters.getAlgorithm()); } text += "\n\n"; summaryTextEdit->setPlainText(text); } /** * Adds help information in a read only text widget. */ QWidget* GuiMapFmriDialog::addPageInformation(const QString& title, const QString& text, QTextBrowser* textBrowserIn) { const int maxHeight = 150; QTextBrowser* textEditor = textBrowserIn; if (textEditor == NULL) { textEditor = new QTextBrowser; } textEditor->setReadOnly(true); textEditor->setHtml(text); QGroupBox* group = new QGroupBox(title); QVBoxLayout* layout = new QVBoxLayout(group); layout->addWidget(textEditor); int height = group->sizeHint().height(); if (height > maxHeight) { height = maxHeight; } group->setMaximumHeight(height); return group; } caret-5.6.4~dfsg.1.orig/caret/GuiMapFmriAtlasDialog.h0000664000175000017500000001464111572067322022143 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_MAP_FMRI_ATLAS_DIALOG_H__ #define __GUI_MAP_FMRI_ATLAS_DIALOG_H__ #include #include #include "MapFmriAtlasSpecFileInfo.h" #include "WuQDialog.h" class PreferencesFile; class QCheckBox; class QComboBox; class QLineEdit; class QGroupBox; /// Class for selecting coordinate files from an atlas spec file class GuiMapFmriAtlasDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiMapFmriAtlasDialog(QWidget* parent, std::vector* atlasesIn, PreferencesFile* pf, const QString& speciesIn, const QString& structureNameIn, const bool showOutputSpecFileSelectionIn, const bool enableMetricFiducialOptionsIn, const bool enablePaintFiducialOptionsIn); /// Destructor ~GuiMapFmriAtlasDialog(); /// get the output spec file QString getOutputSpecFileName() const; /// get the selected atlas information. void getSelectedMetricAtlasData(QString& atlasPath, QString& topoFileName, QString& description, std::vector& coordFileNames, QString& averageCoordFile, QString& metricNameHint, QString& structureName, bool& mapToAvgCoordFileFlag, bool& mapToAvgOfAllFlag, bool& mapToStdDevOfAllFlag, bool& mapToStdErrorOfAllFlag, bool& mapToMinOfAllFlag, bool& mapToMaxOfAllFlag, bool& mapToAllCasesFlag) const; /// get the selected paint atlas information. void getSelectedPaintAtlasData(QString& atlasPath, QString& topoFileName, QString& description, std::vector& coordFileNames, QString& averageCoordFile, QString& paintNameHint, QString& structureName, bool& mapToAvgCoordFileFlag, bool& mapToMostCommonOfAllFlag, bool& mapToMostCommonExcludeUnidentifiedOfAllFlag, bool& mapToAllCasesFlag) const; protected slots: /// called when select spec file pushbutton pressed. void slotSelectSpecPushButton(); /// called when an atlas space is selected void slotAtlasSpaceComboBox(int item); /// called when an atlas is selected void slotAtlasComboBox(int item); protected: /// overrides parent's version void done(int r); /// load atlas list box void loadAtlasListBox(); /// Load the atlas space combo box. void loadAtlasSpaceComboBox(); /// atlas space combo box QComboBox* atlasSpaceComboBox; /// atlas combo box QComboBox* atlasComboBox; /// the metric multi-fiducial group box QGroupBox* metricMultiFiducialGroupBox; /// metric multi-fid show map to average fiducial check box QCheckBox* metricMultiFidAvgFidCheckBox; /// metric multi-fid show average of all cases check box QCheckBox* metricMultiFidAvgAllCasesCheckBox; /// metric multi-fid show std dev of all cases check box QCheckBox* metricMultiFidStdDevAllCheckBox; /// metric multi-fid show std error of all cases check box QCheckBox* metricMultiFidStdErrorAllCheckBox; /// metric multi-fid show minimum of all cases check box QCheckBox* metricMultiFidMinAllCheckBox; /// metric multi-fid show maximum of all cases check box QCheckBox* metricMultiFidMaxAllCheckBox; /// metric multi-fid show all indiv cases check box QCheckBox* metricMultiFidAllCasesCheckBox; /// the paint multi-fiducial group box QGroupBox* paintMultiFiducialGroupBox; /// paint multi-fid show map to average fiducial check box QCheckBox* paintMultiFidAvgFidCheckBox; /// paint multi-fid show all indiv cases check box QCheckBox* paintMultiFidAllCasesCheckBox; /// paint multi-fid most common of all cases check box QCheckBox* paintMultiFidMostCommonCheckBox; /// paint multi-fid most common exclude unidentified of all cases check box QCheckBox* paintMultiFidMostCommonExcludeUnidentifiedCheckBox; /// the atlases that match species/hem std::vector matchingAtlases; /// all of the atlases std::vector* allAtlases; /// the spec file name line edit QLineEdit* specFileLineEdit; /// the preferences file PreferencesFile* preferencesFile; /// the desired species QString species; /// the desired structure QString structureName; /// the desired space QString space; }; #endif // __GUI_MAP_FMRI_ATLAS_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiMapFmriAtlasDialog.cxx0000664000175000017500000005452411572067322022522 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include "FileUtilities.h" #include "GuiChooseSpecFileDialog.h" #include "GuiMapFmriAtlasDialog.h" #include "PreferencesFile.h" #include "QtUtilities.h" #include "StringUtilities.h" #include "SpecFile.h" /** * Constructor. */ GuiMapFmriAtlasDialog::GuiMapFmriAtlasDialog(QWidget* parent, std::vector* atlasesIn, PreferencesFile* pf, const QString& speciesIn, const QString& structureNameIn, const bool showOutputSpecFileSelection, const bool enableMetricFiducialOptionsIn, const bool enablePaintFiducialOptionsIn) : WuQDialog(parent) { setModal(true); preferencesFile = pf; allAtlases = atlasesIn; space = ""; species = StringUtilities::makeLowerCase(speciesIn); structureName = StringUtilities::makeLowerCase(structureNameIn); setWindowTitle("Atlas Surface Selection"); // // Spec File selection // QPushButton* selectSpecPushButton = new QPushButton("Select..."); selectSpecPushButton->setAutoDefault(false); selectSpecPushButton->setFixedSize(selectSpecPushButton->sizeHint()); QObject::connect(selectSpecPushButton, SIGNAL(clicked()), this, SLOT(slotSelectSpecPushButton())); specFileLineEdit = new QLineEdit; specFileLineEdit->setReadOnly(true); specFileLineEdit->setMinimumWidth(250); // // Spec File group box and layout // QGroupBox* specGroupBox = new QGroupBox("Output Spec File"); QHBoxLayout* specGroupLayout = new QHBoxLayout(specGroupBox); specGroupLayout->addWidget(selectSpecPushButton); specGroupLayout->addWidget(specFileLineEdit); specGroupBox->setHidden(showOutputSpecFileSelection == false); // // Atlas space selection // QLabel* spaceLabel = new QLabel("Space "); atlasSpaceComboBox = new QComboBox; QObject::connect(atlasSpaceComboBox, SIGNAL(activated(int)), this, SLOT(slotAtlasSpaceComboBox(int))); // // List atlases with matching characteristics // QLabel* atlasLabel = new QLabel("Atlas "); atlasComboBox = new QComboBox; QObject::connect(atlasComboBox, SIGNAL(activated(int)), this, SLOT(slotAtlasComboBox(int))); // // Atlas group box and layout // QGroupBox* atlasGroupBox = new QGroupBox("Mapping Atlas"); QGridLayout* atlasGridLayout = new QGridLayout(atlasGroupBox); atlasGridLayout->addWidget(spaceLabel, 0, 0); atlasGridLayout->addWidget(atlasSpaceComboBox, 0, 1); atlasGridLayout->addWidget(atlasLabel, 1, 0); atlasGridLayout->addWidget(atlasComboBox, 1, 1); atlasGridLayout->setColumnStretch(0, 0); atlasGridLayout->setColumnStretch(1, 100); // // metric multi-fid option check boxes // metricMultiFidAvgFidCheckBox = new QCheckBox("Show Mapping to Average Fiducial Surface"); metricMultiFidAvgFidCheckBox->setChecked(true); metricMultiFidAvgAllCasesCheckBox = new QCheckBox("Show Average of Mapping to All Multi-Fiducial Cases"); metricMultiFidAvgAllCasesCheckBox->setChecked(true); metricMultiFidStdDevAllCheckBox = new QCheckBox("Show Sample Standard Deviation of Mapping to All Multi-Fiducial Cases"); metricMultiFidStdErrorAllCheckBox = new QCheckBox("Show Standard Error of Mapping to All Multi-Fiducial Cases"); metricMultiFidMinAllCheckBox = new QCheckBox("Show Minimum of Mapping to All Multi-Fiducial Cases"); metricMultiFidMaxAllCheckBox = new QCheckBox("Show Maximum of Mapping to All Multi-Fiducial Cases"); metricMultiFidAllCasesCheckBox = new QCheckBox("Show Mapping to Each Multi-Fiducial Case"); // // Group box and layout for metric multi-fiducial options // metricMultiFiducialGroupBox = new QGroupBox("Multi-Fiducial Mapping Metric Output"); metricMultiFiducialGroupBox->setEnabled(false); QVBoxLayout* metricMultiFiducialLayout = new QVBoxLayout(metricMultiFiducialGroupBox); metricMultiFiducialLayout->addWidget(metricMultiFidAvgFidCheckBox); metricMultiFiducialLayout->addWidget(metricMultiFidAvgAllCasesCheckBox); metricMultiFiducialLayout->addWidget(metricMultiFidStdDevAllCheckBox); metricMultiFiducialLayout->addWidget(metricMultiFidStdErrorAllCheckBox); metricMultiFiducialLayout->addWidget(metricMultiFidMinAllCheckBox); metricMultiFiducialLayout->addWidget(metricMultiFidMaxAllCheckBox); metricMultiFiducialLayout->addWidget(metricMultiFidAllCasesCheckBox); // // paint multi-fid option check boxes // paintMultiFidAvgFidCheckBox = new QCheckBox("Show Mapping to Average Fiducial Surface"); paintMultiFidAvgFidCheckBox->setChecked(true); paintMultiFidMostCommonCheckBox = new QCheckBox("Show Most Common of Mapping to All Multi-Fiducial Cases"); paintMultiFidMostCommonCheckBox->setChecked(true); paintMultiFidMostCommonExcludeUnidentifiedCheckBox = new QCheckBox("Show Most Common (Exclude Unidentified) of Mapping to All Multi-Fiducial Cases"); paintMultiFidMostCommonExcludeUnidentifiedCheckBox->setChecked(true); paintMultiFidAllCasesCheckBox = new QCheckBox("Show Mapping to Each Multi-Fiducial Case"); // // Group box and layout for paint multi-fiducial options // paintMultiFiducialGroupBox = new QGroupBox("Multi-Fiducial Mapping Paint Output"); paintMultiFiducialGroupBox->setEnabled(false); QVBoxLayout* paintMultiFiducialLayout = new QVBoxLayout(paintMultiFiducialGroupBox); paintMultiFiducialLayout->addWidget(paintMultiFidAvgFidCheckBox); paintMultiFiducialLayout->addWidget(paintMultiFidMostCommonCheckBox); paintMultiFiducialLayout->addWidget(paintMultiFidMostCommonExcludeUnidentifiedCheckBox); paintMultiFiducialLayout->addWidget(paintMultiFidAllCasesCheckBox); // // User instructions shown in text editor // QString instructions = "First, choose the Spec File in which the generated metric files " "should be placed. Second, choose the appropriate stereotaxic " "space. Third, choose one atlas. "; if (enableMetricFiducialOptionsIn || enablePaintFiducialOptionsIn) { instructions += "If the atlas contains more than one fiducial coordinate " "file, the multi-fiducial mapping options will be displayed."; } QTextEdit* textEditor = new QTextEdit; textEditor->setReadOnly(true); textEditor->setPlainText(instructions); // // OK and Cancel buttons // QPushButton* okButton = new QPushButton("OK"); okButton->setAutoDefault(false); QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); QPushButton* cancelButton = new QPushButton("Cancel"); cancelButton->setAutoDefault(false); QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); QtUtilities::makeButtonsSameSize(okButton, cancelButton); // // Layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->addWidget(okButton); buttonsLayout->addWidget(cancelButton); // // Layout for dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->addWidget(specGroupBox); dialogLayout->addWidget(atlasGroupBox); dialogLayout->addWidget(metricMultiFiducialGroupBox); dialogLayout->addWidget(paintMultiFiducialGroupBox); dialogLayout->addWidget(textEditor); dialogLayout->addLayout(buttonsLayout); if (showOutputSpecFileSelection == false) { loadAtlasSpaceComboBox(); slotAtlasSpaceComboBox(0); } if (enableMetricFiducialOptionsIn == false) { metricMultiFiducialGroupBox->hide(); } if (enablePaintFiducialOptionsIn == false) { paintMultiFiducialGroupBox->hide(); } } /** * Destructor. */ GuiMapFmriAtlasDialog::~GuiMapFmriAtlasDialog() { } /** * Load the atlas space combo box. */ void GuiMapFmriAtlasDialog::loadAtlasSpaceComboBox() { std::set sortedSpaces; for (int i = 0; i < static_cast(allAtlases->size()); i++) { const MapFmriAtlasSpecFileInfo& asfi = (*allAtlases)[i]; // // Check space // //const QString atlasSpace(StringUtilities::makeLowerCase(asfi.getSpace())); const QString atlasSpace(asfi.getSpace()); if (atlasSpace.isEmpty() == false) { sortedSpaces.insert(atlasSpace); } } int defaultItem = -1; atlasSpaceComboBox->clear(); int ctr = 0; for (std::set::iterator iter = sortedSpaces.begin(); iter != sortedSpaces.end(); iter++) { atlasSpaceComboBox->addItem(*iter); if (StringUtilities::makeLowerCase(*iter) == StringUtilities::makeLowerCase(space)) { defaultItem = ctr; } ctr++; } if (defaultItem >= 0) { atlasSpaceComboBox->setCurrentIndex(defaultItem); } } /** * called when an atlas space is selected. */ void GuiMapFmriAtlasDialog::slotAtlasSpaceComboBox(int item) { space = ""; if (item >= 0) { space = StringUtilities::makeLowerCase(atlasSpaceComboBox->currentText()); } loadAtlasListBox(); } /** * called when an atlas is selected. */ void GuiMapFmriAtlasDialog::slotAtlasComboBox(int item) { if (metricMultiFiducialGroupBox->isVisible()) { metricMultiFiducialGroupBox->setEnabled(false); metricMultiFidAvgFidCheckBox->setEnabled(false); metricMultiFidAvgAllCasesCheckBox->setEnabled(false); metricMultiFidStdDevAllCheckBox->setEnabled(false); metricMultiFidStdErrorAllCheckBox->setEnabled(false); metricMultiFidMinAllCheckBox->setEnabled(false); metricMultiFidMaxAllCheckBox->setEnabled(false); metricMultiFidAllCasesCheckBox->setEnabled(false); if ((item >= 0) && (item < static_cast(matchingAtlases.size()))) { const MapFmriAtlasSpecFileInfo& asfi = matchingAtlases[item]; if (asfi.getCoordinateFiles().size() > 1) { metricMultiFiducialGroupBox->setEnabled(true); metricMultiFidAvgAllCasesCheckBox->setEnabled(true); metricMultiFidStdDevAllCheckBox->setEnabled(true); metricMultiFidStdErrorAllCheckBox->setEnabled(true); metricMultiFidMinAllCheckBox->setEnabled(true); metricMultiFidMaxAllCheckBox->setEnabled(true); metricMultiFidAllCasesCheckBox->setEnabled(true); if (asfi.getAverageCoordinateFile().isEmpty() == false) { metricMultiFidAvgFidCheckBox->setEnabled(true); } } } } if (paintMultiFiducialGroupBox->isVisible()) { paintMultiFiducialGroupBox->setEnabled(false); paintMultiFidAvgFidCheckBox->setEnabled(false); paintMultiFidAllCasesCheckBox->setEnabled(false); paintMultiFidMostCommonCheckBox->setEnabled(false); paintMultiFidMostCommonExcludeUnidentifiedCheckBox->setEnabled(false); if ((item >= 0) && (item < static_cast(matchingAtlases.size()))) { const MapFmriAtlasSpecFileInfo& asfi = matchingAtlases[item]; if (asfi.getCoordinateFiles().size() > 1) { paintMultiFiducialGroupBox->setEnabled(true); paintMultiFidAllCasesCheckBox->setEnabled(true); paintMultiFidMostCommonCheckBox->setEnabled(true); paintMultiFidMostCommonExcludeUnidentifiedCheckBox->setEnabled(true); if (asfi.getAverageCoordinateFile().isEmpty() == false) { paintMultiFidAvgFidCheckBox->setEnabled(true); } } } } } /** * load atlas combo box */ void GuiMapFmriAtlasDialog::loadAtlasListBox() { matchingAtlases.clear(); atlasComboBox->clear(); matchingAtlases.push_back(MapFmriAtlasSpecFileInfo("")); atlasComboBox->addItem("Press This to Choose Atlas"); for (int i = 0; i < static_cast(allAtlases->size()); i++) { const MapFmriAtlasSpecFileInfo& asfi = (*allAtlases)[i]; bool matches = true; // // Check space // const QString atlasSpace(StringUtilities::makeLowerCase(asfi.getSpace())); if ((space.isEmpty() == false) && (atlasSpace.isEmpty() == false)) { if (space != atlasSpace) { matches = false; } } if (matches) { matchingAtlases.push_back(asfi); atlasComboBox->addItem(asfi.getDescription()); } } if (atlasComboBox->count() > 0) { atlasComboBox->setCurrentIndex(0); slotAtlasComboBox(0); } } /** * Get the name of the selected spec file. */ QString GuiMapFmriAtlasDialog::getOutputSpecFileName() const { return specFileLineEdit->text(); } /** * called when select spec file pushbutton pressed. */ void GuiMapFmriAtlasDialog::slotSelectSpecPushButton() { // // Popup the choose spec file dialog // GuiChooseSpecFileDialog sfd(this, preferencesFile, true); if (sfd.exec() == QDialog::Accepted) { const QString specFileName = sfd.getSelectedSpecFile(); specFileLineEdit->setText(specFileName); // // Read the spec file to get the species and the structure // try { SpecFile sf; sf.readFile(specFileName); space = StringUtilities::makeLowerCase(sf.getSpace().getName()); species = StringUtilities::makeLowerCase(sf.getSpecies().getName()); structureName = StringUtilities::makeLowerCase(sf.getStructure().getTypeAsString()); } catch (FileException& e) { } loadAtlasSpaceComboBox(); slotAtlasSpaceComboBox(0); } } /** * Called when OK or Cancel button pressed. */ void GuiMapFmriAtlasDialog::done(int r) { if (r == QDialog::Accepted) { if (atlasComboBox->currentIndex() == 0) { QMessageBox::critical(this, "ERROR", "You must choose an atlas."); return; } // // Make sure an atlas is selected. // QString atlasPath, topoFileName, description, metricNameHint, avgCoord, structureName; std::vectorcoordNames; bool b1, b2, b3, b4, b5, b6, b7; getSelectedMetricAtlasData(atlasPath, topoFileName, description, coordNames, avgCoord, metricNameHint, structureName, b1, b2, b3, b4, b5, b6, b7); if (coordNames.empty() && avgCoord.isEmpty()) { QMessageBox::critical(this, "ERROR", "No atlas is selected."); return; } } QDialog::done(r); } /** * get the metric selected atlas information. */ void GuiMapFmriAtlasDialog::getSelectedMetricAtlasData(QString& atlasPath, QString& topoFileName, QString& description, std::vector& coordFileNames, QString& averageCoordFile, QString& metricNameHint, QString& structureName, bool& mapToAvgCoordFileFlag, bool& mapToAvgOfAllFlag, bool& mapToStdDevOfAllFlag, bool& mapToStdErrorOfAllFlag, bool& mapToMinOfAllFlag, bool& mapToMaxOfAllFlag, bool& mapToAllCasesFlag) const { atlasPath = ""; description = ""; topoFileName = ""; coordFileNames.clear(); averageCoordFile = ""; metricNameHint = ""; structureName = ""; mapToAvgCoordFileFlag = false; mapToAvgOfAllFlag = false; mapToStdDevOfAllFlag = false; mapToStdErrorOfAllFlag = false; mapToMinOfAllFlag = false; mapToMaxOfAllFlag = false; mapToAllCasesFlag = false; // // Get the selected atlas // const int num = static_cast(matchingAtlases.size()); const int atlasNum = atlasComboBox->currentIndex(); if ((atlasNum > 0) && (atlasNum < num)) { // // get selected atlas // const MapFmriAtlasSpecFileInfo& asfi = matchingAtlases[atlasNum]; // // Get atlas path and topo file // atlasPath = asfi.getSpecFilePath(); topoFileName = asfi.getTopologyFile(); // // Get allcoordinate files // coordFileNames = asfi.getCoordinateFiles(); // // Get avg fiducial coord file // averageCoordFile = asfi.getAverageCoordinateFile(); // // Get metric name hint // metricNameHint = asfi.getMetricNameHint(); // // Add description of atlas // QString s(asfi.getStructure()); s.append(" "); s.append(asfi.getSpace()); description = s; // // name of structure // structureName = asfi.getStructure(); // // Set multi-fiducial selections // if (metricMultiFiducialGroupBox->isEnabled()) { if (metricMultiFidAvgFidCheckBox->isEnabled()) { mapToAvgCoordFileFlag = metricMultiFidAvgFidCheckBox->isChecked(); } mapToAvgOfAllFlag = metricMultiFidAvgAllCasesCheckBox->isChecked(); mapToStdDevOfAllFlag = metricMultiFidStdDevAllCheckBox->isChecked(); mapToStdErrorOfAllFlag = metricMultiFidStdErrorAllCheckBox->isChecked(); mapToMinOfAllFlag = metricMultiFidMinAllCheckBox->isChecked(); mapToMaxOfAllFlag = metricMultiFidMaxAllCheckBox->isChecked(); mapToAllCasesFlag = metricMultiFidAllCasesCheckBox->isChecked(); // // If the individual case coord files are not needed // if ((mapToAvgOfAllFlag == false) && (mapToStdDevOfAllFlag == false) && (mapToStdErrorOfAllFlag == false) && (mapToMinOfAllFlag == false) && (mapToMaxOfAllFlag == false) && (mapToAllCasesFlag == false)) { coordFileNames.clear(); } } else { mapToAllCasesFlag = true; } } } /** * get the paint selected atlas information. */ void GuiMapFmriAtlasDialog::getSelectedPaintAtlasData(QString& atlasPath, QString& topoFileName, QString& description, std::vector& coordFileNames, QString& averageCoordFile, QString& paintNameHint, QString& structureName, bool& mapToAvgCoordFileFlag, bool& mapToMostCommonOfAllFlag, bool& mapToMostCommonExcludeUnidentifiedOfAllFlag, bool& mapToAllCasesFlag) const { atlasPath = ""; description = ""; topoFileName = ""; coordFileNames.clear(); averageCoordFile = ""; paintNameHint = ""; structureName = ""; mapToAvgCoordFileFlag = false; mapToMostCommonOfAllFlag = false; mapToMostCommonExcludeUnidentifiedOfAllFlag = false; mapToAllCasesFlag = false; // // Get the selected atlas // const int num = static_cast(matchingAtlases.size()); const int atlasNum = atlasComboBox->currentIndex(); if ((atlasNum > 0) && (atlasNum < num)) { // // get selected atlas // const MapFmriAtlasSpecFileInfo& asfi = matchingAtlases[atlasNum]; // // Get atlas path and topo file // atlasPath = asfi.getSpecFilePath(); topoFileName = asfi.getTopologyFile(); // // Get allcoordinate files // coordFileNames = asfi.getCoordinateFiles(); // // Get avg fiducial coord file // averageCoordFile = asfi.getAverageCoordinateFile(); // // Get paint name hint // paintNameHint = asfi.getMetricNameHint(); // // Add description of atlas // QString s(asfi.getStructure()); s.append(" "); s.append(asfi.getSpace()); description = s; // // name of structure // structureName = asfi.getStructure(); // // Set multi-fiducial selections // if (paintMultiFiducialGroupBox->isEnabled()) { if (paintMultiFidAvgFidCheckBox->isEnabled()) { mapToAvgCoordFileFlag = paintMultiFidAvgFidCheckBox->isChecked(); } mapToMostCommonOfAllFlag = paintMultiFidMostCommonCheckBox->isChecked(); mapToMostCommonExcludeUnidentifiedOfAllFlag = paintMultiFidMostCommonExcludeUnidentifiedCheckBox->isChecked(); mapToAllCasesFlag = paintMultiFidAllCasesCheckBox->isChecked(); // // If the individual case coord files are not needed // if ((mapToMostCommonOfAllFlag == false) && (mapToAllCasesFlag == false)) { coordFileNames.clear(); } } else { mapToAllCasesFlag = true; } } } caret-5.6.4~dfsg.1.orig/caret/GuiMainWindowWindowMenu.h0000664000175000017500000000243111572067322022566 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_MAIN_WINDOW_WINDOW_MENU_H__ #define __GUI_MAIN_WINDOW_WINDOW_MENU_H__ #include class GuiMainWindow; /// This class creates the Main Window's Window Menu. class GuiMainWindowWindowMenu : public QMenu { Q_OBJECT public: /// constructor GuiMainWindowWindowMenu(GuiMainWindow* parent); /// destructor ~GuiMainWindowWindowMenu(); private: }; #endif caret-5.6.4~dfsg.1.orig/caret/GuiMainWindowWindowMenu.cxx0000664000175000017500000000541111572067322023142 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "GuiMainWindow.h" #include "GuiMainWindowWindowActions.h" #include "GuiMainWindowWindowMenu.h" /** * Constructor. */ GuiMainWindowWindowMenu::GuiMainWindowWindowMenu(GuiMainWindow* parent) : QMenu("Window", parent) { GuiMainWindowWindowActions* windowActions = parent->getWindowActions(); #ifdef Q_OS_MACX addAction(windowActions->getBringAllToFrontAction()); //addAction(windowActions->getNextWindowAction()); #endif addAction(windowActions->getStackWindowsAction()); addSeparator(); // // NOTE: Actions for D/C, ID, Image windows are available for QT 4 // addAction(windowActions->getDisplayControlAction()); addAction(windowActions->getIdWindowAction()); addAction(windowActions->getTransformationMatrixEditorAction()); addSeparator(); addAction(windowActions->getCaretCommandExecutorAction()); addAction(windowActions->getCaretCommandScriptBuilderAction()); addAction(windowActions->getDisplayImageEditorAction()); //addAction(windowActions->getShellCommandWindowAction()); addAction(windowActions->getTextFileEditorAction()); addSeparator(); addAction(windowActions->getWindow2Action()); addAction(windowActions->getWindow3Action()); addAction(windowActions->getWindow4Action()); addAction(windowActions->getWindow5Action()); addAction(windowActions->getWindow6Action()); addAction(windowActions->getWindow7Action()); addAction(windowActions->getWindow8Action()); addAction(windowActions->getWindow9Action()); addAction(windowActions->getWindow10Action()); addAction(windowActions->getResizeViewWindowsAction()); addSeparator(); addAction(windowActions->getImageViewingWindowAction()); QObject::connect(this, SIGNAL(aboutToShow()), windowActions, SLOT(updateActions())); } /** * Destructor. */ GuiMainWindowWindowMenu::~GuiMainWindowWindowMenu() { } caret-5.6.4~dfsg.1.orig/caret/GuiMainWindowWindowActions.h0000664000175000017500000001622011572067322023263 0ustar michaelmichael#ifndef __GUI_MAIN_WINDOW_WINDOW_ACTIONS_H__ #define __GUI_MAIN_WINDOW_WINDOW_ACTIONS_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include class GuiMainWindow; class QAction; /// the main window's window actions class GuiMainWindowWindowActions : public QObject { Q_OBJECT public: // constructor GuiMainWindowWindowActions(GuiMainWindow* mainWindowParent); // destructor ~GuiMainWindowWindowActions(); /// window 2 action QAction* getWindow2Action() { return window2Action; } /// window 3 action QAction* getWindow3Action() { return window3Action; } /// window 4 action QAction* getWindow4Action() { return window4Action; } /// window 5 action QAction* getWindow5Action() { return window5Action; } /// window 6 action QAction* getWindow6Action() { return window6Action; } /// window 7 action QAction* getWindow7Action() { return window7Action; } /// window 8 action QAction* getWindow8Action() { return window8Action; } /// window 9 action QAction* getWindow9Action() { return window9Action; } /// window 10 action QAction* getWindow10Action() { return window10Action; } /// resize viewing windows action QAction* getResizeViewWindowsAction() { return resizeViewWindowsAction; } /// display control window action QAction* getDisplayControlAction() { return displayControlAction; } /// id window action QAction* getIdWindowAction() { return idWindowAction; } /// image viewing window action QAction* getImageViewingWindowAction() { return imageViewingWindowAction; } /// display image editor action QAction* getDisplayImageEditorAction() { return displayImageEditorAction; } /// text file editor action QAction* getTextFileEditorAction() { return textFileEditorAction; } /// shell command window action QAction* getShellCommandWindowAction() { return shellCommandWindowAction; } /// transformation matrix editor action QAction* getTransformationMatrixEditorAction() { return transformationMatrixEditorAction; } /// caret command executor action QAction* getCaretCommandExecutorAction() { return caretCommandExecutorAction; } /// caret command script builder action QAction* getCaretCommandScriptBuilderAction() { return caretCommandScriptBuilderAction; } /// get stack windows action QAction* getStackWindowsAction() { return stackWindowsAction; } /// get the next window action QAction* getNextWindowAction() { return nextWindowAction; } /// bring all to front action QAction* getBringAllToFrontAction() { return bringAllToFrontAction; } public slots: /// update the actions (typically called when menu is about to show) void updateActions(); /// Called when window 2 action selected void window2Popup(); /// Called when window 3 action selected void window3Popup(); /// Called when window 4 action selected void window4Popup(); /// Called when window 5 action selected void window5Popup(); /// Called when window 6 action selected void window6Popup(); /// Called when window 7 action selected void window7Popup(); /// Called when window 8 action selected void window8Popup(); /// Called when window 9 action selected void window9Popup(); /// Called when window 10 action selected void window10Popup(); /// Called when resize viewing window action selected void slotResizeViewingWindowsAction(); /// text editor action void slotTextFileEditor(); /// called when shell command action triggered void slotShellCommandWindow(); /// called when stack windows action triggered void slotStackWindowsAction(); /// called when next window action triggered void slotNextWindowAction(); /// called when bring all to front is triggered void slotBringAllToFrontAction(); protected: /// get all open windows that are children of main window static void getOpenWindowsThatAreChildrenOfMainWindow(std::vector& windows, const bool includeMainWindow); /// window 2 action QAction* window2Action; /// window 3 action QAction* window3Action; /// window 4 action QAction* window4Action; /// window 5 action QAction* window5Action; /// window 6 action QAction* window6Action; /// window 7 action QAction* window7Action; /// window 8 action QAction* window8Action; /// window 9 action QAction* window9Action; /// window 10 action QAction* window10Action; /// resize viewing windows action QAction* resizeViewWindowsAction; /// display control window action QAction* displayControlAction; /// id window action QAction* idWindowAction; /// image viewing window action QAction* imageViewingWindowAction; /// display image editor action QAction* displayImageEditorAction; /// text file editor action QAction* textFileEditorAction; /// shell command window action QAction* shellCommandWindowAction; /// transformation matrix editor action QAction* transformationMatrixEditorAction; /// caret command builder action QAction* caretCommandExecutorAction; /// caret command script builder action QAction* caretCommandScriptBuilderAction; /// stack windows action QAction* stackWindowsAction; /// next window action QAction* nextWindowAction; /// bring all to front action QAction* bringAllToFrontAction; /// last window from previous next window action QWidget* lastWindowFromPreviousNextAction; }; #endif // __GUI_MAIN_WINDOW_WINDOW_ACTIONS_H__ caret-5.6.4~dfsg.1.orig/caret/GuiMainWindowWindowActions.cxx0000664000175000017500000004342311572067322023643 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "BrainSet.h" #include "DebugControl.h" #include "FileFilters.h" #include "GuiBrainModelOpenGL.h" #include "GuiMainWindow.h" #include "GuiMainWindowWindowActions.h" #include "GuiShellCommandWindow.h" #include "QtTextFileEditorDialog.h" #include "global_variables.h" /** * constructor. */ GuiMainWindowWindowActions::GuiMainWindowWindowActions(GuiMainWindow* mainWindowParent) : QObject(mainWindowParent) { setObjectName("GuiMainWindowWindowActions"); window2Action = new QAction(mainWindowParent); window2Action->setText("Viewing Window 2..."); window2Action->setObjectName("window2Action"); window2Action->setShortcut( Qt::CTRL+Qt::Key_2); QObject::connect(window2Action, SIGNAL(triggered(bool)), this, SLOT(window2Popup())); window3Action = new QAction(mainWindowParent); window3Action->setText("Viewing Window 3..."); window3Action->setObjectName("window3Action"); window3Action->setShortcut( Qt::CTRL+Qt::Key_3); QObject::connect(window3Action, SIGNAL(triggered(bool)), this, SLOT(window3Popup())); window4Action = new QAction(mainWindowParent); window4Action->setText("Viewing Window 4..."); window4Action->setObjectName("window4Action"); window4Action->setShortcut( Qt::CTRL+Qt::Key_4); QObject::connect(window4Action, SIGNAL(triggered(bool)), this, SLOT(window4Popup())); window5Action = new QAction(mainWindowParent); window5Action->setText("Viewing Window 5..."); window5Action->setObjectName("window5Action"); window5Action->setShortcut( Qt::CTRL+Qt::Key_5); QObject::connect(window5Action, SIGNAL(triggered(bool)), this, SLOT(window5Popup())); window6Action = new QAction(mainWindowParent); window6Action->setText("Viewing Window 6..."); window6Action->setObjectName("window6Action"); window6Action->setShortcut( Qt::CTRL+Qt::Key_6); QObject::connect(window6Action, SIGNAL(triggered(bool)), this, SLOT(window6Popup())); window7Action = new QAction(mainWindowParent); window7Action->setText("Viewing Window 7..."); window7Action->setObjectName("window7Action"); window7Action->setShortcut( Qt::CTRL+Qt::Key_7); QObject::connect(window7Action, SIGNAL(triggered(bool)), this, SLOT(window7Popup())); window8Action = new QAction(mainWindowParent); window8Action->setText("Viewing Window 8..."); window8Action->setObjectName("window8Action"); window8Action->setShortcut( Qt::CTRL+Qt::Key_8); QObject::connect(window8Action, SIGNAL(triggered(bool)), this, SLOT(window8Popup())); window9Action = new QAction(mainWindowParent); window9Action->setText("Viewing Window 9..."); window9Action->setObjectName("window9Action"); window9Action->setShortcut( Qt::CTRL+Qt::Key_9); QObject::connect(window9Action, SIGNAL(triggered(bool)), this, SLOT(window9Popup())); window10Action = new QAction(mainWindowParent); window10Action->setText("Viewing Window 10..."); window10Action->setObjectName("window10Action"); window10Action->setShortcut( Qt::CTRL+Qt::Key_0); QObject::connect(window10Action, SIGNAL(triggered(bool)), this, SLOT(window10Popup())); resizeViewWindowsAction = new QAction(mainWindowParent); resizeViewWindowsAction->setText("Resize Viewing Windows..."); resizeViewWindowsAction->setObjectName("resizeViewWindowsAction"); QObject::connect(resizeViewWindowsAction, SIGNAL(triggered(bool)), this, SLOT(slotResizeViewingWindowsAction())); displayControlAction = new QAction(mainWindowParent); displayControlAction->setText("Display Control Window..."); displayControlAction->setObjectName("displayControlAction"); displayControlAction->setShortcut(Qt::CTRL+Qt::Key_D); QObject::connect(displayControlAction, SIGNAL(triggered(bool)), mainWindowParent, SLOT(displayDisplayControlDialog())); idWindowAction = new QAction(mainWindowParent); idWindowAction->setText("Identify Window..."); idWindowAction->setObjectName("idWindowAction"); idWindowAction->setShortcut(Qt::CTRL+Qt::Key_I); QObject::connect(idWindowAction, SIGNAL(triggered(bool)), mainWindowParent, SLOT(displayIdentifyDialog())); imageViewingWindowAction = new QAction(mainWindowParent); imageViewingWindowAction->setText("New Image Viewing Window"); imageViewingWindowAction->setObjectName("imageViewingWindowAction"); QObject::connect(imageViewingWindowAction, SIGNAL(triggered(bool)), mainWindowParent, SLOT(displayImageViewingWindow())); displayImageEditorAction = new QAction(mainWindowParent); displayImageEditorAction->setText("Image Editor..."); displayImageEditorAction->setObjectName("displayImageEditorAction"); QObject::connect(displayImageEditorAction, SIGNAL(triggered(bool)), mainWindowParent, SLOT(displayImageEditorWindow())); textFileEditorAction = new QAction(mainWindowParent); textFileEditorAction->setText("Text File Editor..."); textFileEditorAction->setObjectName("textFileEditorAction"); QObject::connect(textFileEditorAction, SIGNAL(triggered(bool)), this, SLOT(slotTextFileEditor())); transformationMatrixEditorAction = new QAction(mainWindowParent); transformationMatrixEditorAction->setText("Transformation Matrix Editor..."); transformationMatrixEditorAction->setObjectName("transformationMatrixEditorAction"); transformationMatrixEditorAction->setShortcut(Qt::CTRL+Qt::Key_T); QObject::connect(transformationMatrixEditorAction, SIGNAL(triggered(bool)), mainWindowParent, SLOT(displayTransformMatrixEditor())); caretCommandExecutorAction = new QAction(mainWindowParent); caretCommandExecutorAction->setText("Caret Command Executor..."); caretCommandExecutorAction->setObjectName("caretCommandExecutorAction"); QObject::connect(caretCommandExecutorAction, SIGNAL(triggered(bool)), mainWindowParent, SLOT(displayCaretCommandExecutorDialog())); caretCommandScriptBuilderAction = new QAction(mainWindowParent); caretCommandScriptBuilderAction->setText("Caret Command Script Builder..."); caretCommandScriptBuilderAction->setObjectName("caretCommandScriptBuilderAction"); QObject::connect(caretCommandScriptBuilderAction, SIGNAL(triggered(bool)), mainWindowParent, SLOT(displayCaretCommandScriptBuilderDialog())); shellCommandWindowAction = new QAction(mainWindowParent); shellCommandWindowAction->setText("Shell Command Window..."); shellCommandWindowAction->setObjectName("shellCommandWindowAction"); QObject::connect(shellCommandWindowAction, SIGNAL(triggered(bool)), this, SLOT(slotShellCommandWindow())); stackWindowsAction = new QAction(mainWindowParent); stackWindowsAction->setText("Stack Windows"); stackWindowsAction->setObjectName("stackWindowsAction"); QObject::connect(stackWindowsAction, SIGNAL(triggered(bool)), this, SLOT(slotStackWindowsAction())); lastWindowFromPreviousNextAction = NULL; nextWindowAction = new QAction(mainWindowParent); nextWindowAction->setText("Next Window"); nextWindowAction->setShortcut(Qt::CTRL+Qt::Key_F12); nextWindowAction->setObjectName("nextWindowAction"); QObject::connect(nextWindowAction, SIGNAL(triggered(bool)), this, SLOT(slotNextWindowAction())); bringAllToFrontAction = new QAction(mainWindowParent); bringAllToFrontAction->setText("Bring All to Front"); bringAllToFrontAction->setObjectName("bringAllToFrontAction"); QObject::connect(bringAllToFrontAction, SIGNAL(triggered(bool)), this, SLOT(slotBringAllToFrontAction())); } /** * destructor. */ GuiMainWindowWindowActions::~GuiMainWindowWindowActions() { } /** * Popup surface 2 window */ void GuiMainWindowWindowActions::window2Popup() { theMainWindow->showViewingWindow(BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_2); } /** * Popup surface 3 window */ void GuiMainWindowWindowActions::window3Popup() { theMainWindow->showViewingWindow(BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_3); } /** * Popup surface 4 window */ void GuiMainWindowWindowActions::window4Popup() { theMainWindow->showViewingWindow(BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_4); } /** * Popup surface 5 window */ void GuiMainWindowWindowActions::window5Popup() { theMainWindow->showViewingWindow(BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_5); } /** * Popup surface 6 window */ void GuiMainWindowWindowActions::window6Popup() { theMainWindow->showViewingWindow(BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_6); } /** * Popup surface 7 window */ void GuiMainWindowWindowActions::window7Popup() { theMainWindow->showViewingWindow(BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_7); } /** * Popup surface 8 window */ void GuiMainWindowWindowActions::window8Popup() { theMainWindow->showViewingWindow(BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_8); } /** * Popup surface 9 window */ void GuiMainWindowWindowActions::window9Popup() { theMainWindow->showViewingWindow(BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_9); } /** * Popup surface 10 window */ void GuiMainWindowWindowActions::window10Popup() { theMainWindow->showViewingWindow(BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_10); } /** * Called when resize viewing window action selected. */ void GuiMainWindowWindowActions::slotResizeViewingWindowsAction() { theMainWindow->resizeViewingWindows(); } /** * Called to launch text editor. */ void GuiMainWindowWindowActions::slotTextFileEditor() { QtTextFileEditorDialog* tfed = new QtTextFileEditorDialog(theMainWindow); QStringList caretFileFilters; FileFilters::getAllCaretFileFilters(caretFileFilters); tfed->addAdditionalFileFilters(caretFileFilters); tfed->setPreferencesFile(theMainWindow->getBrainSet()->getPreferencesFile()); tfed->show(); } /** * called when shell command action triggered. */ void GuiMainWindowWindowActions::slotShellCommandWindow() { static GuiShellCommandWindow* shellWindow = NULL; if (shellWindow == NULL) { shellWindow = new GuiShellCommandWindow(theMainWindow); } shellWindow->show(); shellWindow->activateWindow(); } /** * update the actions (typically called when menu is about to show) */ void GuiMainWindowWindowActions::updateActions() { for (int i = BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_2; i < BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS; i++) { const BrainModel::BRAIN_MODEL_VIEW_NUMBER windowNum = static_cast(i); std::ostringstream str; str << "Viewing Window " << (windowNum + 1); GuiBrainModelOpenGL* bmo = GuiBrainModelOpenGL::getBrainModelOpenGLForWindow(windowNum); if (bmo != NULL) { BrainModel* bm = bmo->getDisplayedBrainModel(); if (bm != NULL) { str << " " << bm->getDescriptiveName().toAscii().constData(); } } str << "..."; QAction* action = NULL; switch (static_cast(i)) { case BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW: action = NULL; break; case BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_2: action = window2Action; break; case BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_3: action = window3Action; break; case BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_4: action = window4Action; break; case BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_5: action = window5Action; break; case BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_6: action = window6Action; break; case BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_7: action = window7Action; break; case BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_8: action = window8Action; break; case BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_9: action = window9Action; break; case BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_10: action = window10Action; break; case BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS: action = NULL; break; } if (action != NULL) { action->setText(str.str().c_str()); } } imageViewingWindowAction->setEnabled(theMainWindow->getBrainSet()->getNumberOfImageFiles() > 0); } /** * called when stack windows action triggered. */ void GuiMainWindowWindowActions::slotStackWindowsAction() { // // Screen width and height // QDesktopWidget* dt = QApplication::desktop(); const int screenWidth = dt->width(); const int screenHeight = dt->height(); // // Position off of main window // const int increment = 25; int x = theMainWindow->x() + increment; int y = theMainWindow->y() + increment; // // Get the children of the main window // std::vector dialogsAndWindows; getOpenWindowsThatAreChildrenOfMainWindow(dialogsAndWindows, false); // // Stack the windows with some offset // for (int i = 0; i < static_cast(dialogsAndWindows.size()); i++) { // // Limit to valid screen position // x = std::min(x, screenWidth - increment); y = std::min(y, screenHeight - increment); // // Need to get rid of "constness" and set window location // QWidget* w = dialogsAndWindows[i]; w->setGeometry(x, y, w->width(), w->height()); w->show(); w->activateWindow(); // // Offset for next window // x += increment; y += increment; } } /** * get all open windows that are children of main window. */ void GuiMainWindowWindowActions::getOpenWindowsThatAreChildrenOfMainWindow(std::vector& windowsOut, const bool includeMainWindow) { windowsOut.clear(); if (includeMainWindow) { windowsOut.push_back(theMainWindow); } // // Get the children of the main window // const QObjectList listOfChildren = theMainWindow->children(); for (int i = 0; i < listOfChildren.size(); i++) { const QObject* object = listOfChildren.at(i); const QWidget* widget = dynamic_cast(object); if (widget != NULL) { const bool isWindow = (dynamic_cast(widget) != NULL); const bool isDialog = (dynamic_cast(widget) != NULL); if (isWindow || isDialog) { if (DebugControl::getDebugOn()) { const QString hiddenString = (widget->isHidden() ? " hidden" : " displayed"); std::cout << "Child of main window " << hiddenString.toAscii().constData() << ": " << widget->windowTitle().toAscii().constData() << std::endl; } // // If not hidden (ie: closed) // if (widget->isHidden() == false) { QWidget* w = (QWidget*)widget; windowsOut.push_back(w); } } } } } /** * called when next window action triggered. */ void GuiMainWindowWindowActions::slotNextWindowAction() { // // Get all open windows including main window // std::vector windows; getOpenWindowsThatAreChildrenOfMainWindow(windows, true); // // Find the next window to activate // QWidget* windowToActivate = theMainWindow; for (int i = 0; i < static_cast(windows.size()); i++) { if (windows[i] == lastWindowFromPreviousNextAction) { if (DebugControl::getDebugOn()) { std::cout << "Previous window: " << lastWindowFromPreviousNextAction->windowTitle().toAscii().constData() << std::endl; } int next = i + 1; if (next >= static_cast(windows.size())) { next = 0; } windowToActivate = windows[next]; break; } } if (DebugControl::getDebugOn()) { std::cout << "Activating window: " << windowToActivate->windowTitle().toAscii().constData() << std::endl; } windowToActivate->show(); windowToActivate->activateWindow(); lastWindowFromPreviousNextAction = windowToActivate; } /** * called when bring all to front is triggered. */ void GuiMainWindowWindowActions::slotBringAllToFrontAction() { // // Get all open windows including main window // std::vector windows; getOpenWindowsThatAreChildrenOfMainWindow(windows, true); // // Show all windows // for (int i = 0; i < static_cast(windows.size()); i++) { windows[i]->show(); windows[i]->activateWindow(); } } caret-5.6.4~dfsg.1.orig/caret/GuiMainWindowVolumeMenu.h0000664000175000017500000000462511572067322022575 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_MAIN_WINDOW_VOLUME_MENU_H__ #define __GUI_MAIN_WINDOW_VOLUME_MENU_H__ #include class GuiBrainModelOpenGL; class GuiMainWindow; class GuiMainWindowVolumeActions; /// This class creates the Main Window's Volume Menu. class GuiMainWindowVolumeMenu : public QMenu { Q_OBJECT public: /// constructor GuiMainWindowVolumeMenu(GuiMainWindow* parent); /// destructor ~GuiMainWindowVolumeMenu(); /// update the dialog void updateDialog(); private: /// create the anatomy sub menu void createAnatomySubMenu(); /// create the functional sub menu void createFunctionalSubMenu(); /// create the prob atlas sub menu void createProbAtlasSubMenu(); /// create the paint sub menu void createPaintSubMenu(); /// create the segmentation sub menu void createSegmentationSubMenu(); /// Create the the tranform volume sub menu void createTransformSubMenu(); /// anatomy sub menu QMenu* anatomySubMenu; /// functional sub menu QMenu* functionalSubMenu; /// segmentation sub menu QMenu* segmentationSubMenu; /// transform sub menu QMenu* transformSubMenu; /// paint sub menu QMenu* paintSubMenu; /// prob atlas sub menu QMenu* probAtlasSubMenu; /// actions for volume menu GuiMainWindowVolumeActions* volumeActions; }; #endif // __GUI_MAIN_WINDOW_VOLUME_MENU_H__ caret-5.6.4~dfsg.1.orig/caret/GuiMainWindowVolumeMenu.cxx0000664000175000017500000001072511572067322023146 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainSet.h" #include "GuiMainWindow.h" #include "GuiMainWindowVolumeActions.h" #include "GuiMainWindowVolumeMenu.h" #include "global_variables.h" /** * Constructor. */ GuiMainWindowVolumeMenu::GuiMainWindowVolumeMenu(GuiMainWindow* parent) : QMenu("Volume", parent) { setObjectName("GuiMainWindowVolumeMenu"); volumeActions = parent->getVolumeActions(); createAnatomySubMenu(); addAction(volumeActions->getCreateEmptyVolumeAction()); addAction(volumeActions->getEditVolumeAttributesAction()); addAction(volumeActions->getMathOperationsVolumeAction()); //createFunctionalSubMenu(); createPaintSubMenu(); createProbAtlasSubMenu(); addAction(volumeActions->getRegionOfInterestAction()); addAction(volumeActions->getResizeUnderlayVolumeAction()); createSegmentationSubMenu(); addAction(volumeActions->getShowVoxelExtentAction()); addAction(volumeActions->getSurefitSegmentationAction()); //addAction(volumeActions->getSurefitMultiHemSegmentationAction()); createTransformSubMenu(); QObject::connect(this, SIGNAL(aboutToShow()), volumeActions, SLOT(updateActions())); } /** * Destructor. */ GuiMainWindowVolumeMenu::~GuiMainWindowVolumeMenu() { } /** * Create the the functional volume sub menu */ void GuiMainWindowVolumeMenu::createFunctionalSubMenu() { functionalSubMenu = addMenu("Functional"); } /** * Create the the tranform volume sub menu */ void GuiMainWindowVolumeMenu::createTransformSubMenu() { transformSubMenu = addMenu("Transform"); transformSubMenu->addAction(volumeActions->getApplyRotationAction()); transformSubMenu->addAction(volumeActions->getEnableRotationAction()); } /** * Create the the anatomy volume sub menu */ void GuiMainWindowVolumeMenu::createAnatomySubMenu() { anatomySubMenu = addMenu("Anatomy"); anatomySubMenu->addAction(volumeActions->getAnatomyBiasCorrectionAction()); anatomySubMenu->addAction(volumeActions->getAnatomyThresholdAction()); } /** * Create the the paint volume sub menu */ void GuiMainWindowVolumeMenu::createPaintSubMenu() { paintSubMenu = addMenu("Paint"); paintSubMenu->addAction(volumeActions->getEditPaintVolumeAction()); paintSubMenu->addAction(volumeActions->getPaintVolumeGenerateColorsAction()); } /** * Create the the prob atlas volume sub menu */ void GuiMainWindowVolumeMenu::createProbAtlasSubMenu() { probAtlasSubMenu = addMenu("Probabilistic Atlas"); probAtlasSubMenu->addAction(volumeActions->getProbAtlasToVolumeAction()); } /** * Create the the segmentation volume sub menu */ void GuiMainWindowVolumeMenu::createSegmentationSubMenu() { segmentationSubMenu = addMenu("Segmentation"); //segmentationSubMenu->addAction(volumeActions->getSegmentCorrectTopologyAction()); segmentationSubMenu->addAction(volumeActions->getEditSegmentationAction()); segmentationSubMenu->addAction(volumeActions->getFindHandlesAction()); segmentationSubMenu->addAction(volumeActions->getFillCavitiesAction()); segmentationSubMenu->addAction(volumeActions->getCerebralHullAction()); segmentationSubMenu->addAction(volumeActions->getPadSegmentationAction()); segmentationSubMenu->addAction(volumeActions->getReconstructAction()); segmentationSubMenu->addAction(volumeActions->getRemoveIslandsAction()); segmentationSubMenu->addAction(volumeActions->getTopologyReportAction()); } caret-5.6.4~dfsg.1.orig/caret/GuiMainWindowVolumeActions.h0000664000175000017500000001600311572067322023262 0ustar michaelmichael #ifndef __GUI_MAIN_WINDOW_VOLUME_ACTIONS_H__ #define __GUI_MAIN_WINDOW_VOLUME_ACTIONS_H__ #include #include class GuiMainWindow; /// actions for volume menu class GuiMainWindowVolumeActions : public QObject { Q_OBJECT public: // Constructor GuiMainWindowVolumeActions(GuiMainWindow* mainWindowParent); // Destructor ~GuiMainWindowVolumeActions(); /// create empty volume action QAction* getCreateEmptyVolumeAction() { return createEmptyVolumeAction; } /// resize underlay volume action QAction* getResizeUnderlayVolumeAction() { return resizeUnderlayVolumeAction; } /// show voxel extent action QAction* getShowVoxelExtentAction() { return showVoxelExtentAction; } /// edit volume attributes action QAction* getEditVolumeAttributesAction() { return editVolumeAttributesAction; } /// find handles action QAction* getFindHandlesAction() { return findHandlesAction; } /// reconstruct action QAction* getReconstructAction() { return reconstructAction; } /// edit segmentation action QAction* getEditSegmentationAction() { return editSegmentationAction; } /// surefit segmentation action QAction* getSurefitSegmentationAction() { return surefitSegmentationAction; } /// pad segmentation action QAction* getPadSegmentationAction() { return padSegmentationAction; } /// remove islands action QAction* getRemoveIslandsAction() { return removeIslandsAction; } /// topology report action QAction* getTopologyReportAction() { return topologyReportAction; } /// cerebral hull action QAction* getCerebralHullAction() { return cerebralHullAction; } /// fill cavities action QAction* getFillCavitiesAction() { return fillCavitiesAction; } /// apply rotation action QAction* getApplyRotationAction() { return applyRotationAction; } /// enable rotation action QAction* getEnableRotationAction() { return enableRotationAction; } /// region of interest action QAction* getRegionOfInterestAction() { return regionOfInterestAction; } /// prob atlas to volume action QAction* getProbAtlasToVolumeAction() { return probAtlasToVolumeAction; } /// anatomy threshold action QAction* getAnatomyThresholdAction() { return anatomyThresholdAction; } /// anatomy bias correction QAction* getAnatomyBiasCorrectionAction() { return anatomyBiasCorrectionAction; } /// edit paint volume action QAction* getEditPaintVolumeAction() { return editPaintVolumeAction; } /// generate colors for paint action QAction* getPaintVolumeGenerateColorsAction() { return paintVolumeGenerateColorsAction; } /// create math operations action QAction* getMathOperationsVolumeAction() { return mathOperationsVolumeAction; } /// is transform rotation checked bool getTranformRotationChecked() const { return enableRotationAction->isChecked(); } public slots: /// update the actions (typically called when menu is about to show) void updateActions(); // called to create a new empty volume void slotCreateNewEmptyVolume(); // called to resize the underlay volume void slotResizeUnderlayVolume(); // called when show voxel dimension extent selected void slotShowVoxelDimensionExtent(); // called to edit volume attributes void slotEditAttributes(); // called to find handles in a segmentation volume void slotSegmentationFindHandles(); // called to reconstruct a segmentation volume into a surface void slotSegmentationReconstruct(); // called to edit a segmentation volume voxels void slotSegmentationEditVoxels(); // Segment the selected anatomical volume. void slotSureFitSegmentation(); // Called to pad the segmentation volume void slotSegmentPad(); // Called to remove islands from segmentation volume void slotSegmentRemoveIslands(); // Called to display topology information void slotSegmentationTopologyReport(); // Called to generate the cerebral hull volume from the segmentation volume void slotSegmentationCerebralHull(); // Called to fill cavities void slotSegmentationFillCavities(); // Called to display apply rotation dialog. void slotTransformApplyRotation(); // Called to display enable rotation dialog. void slotTransformEnableRotation(); // called to display volume region of interest dialog void slotRegionOfInterestDialog(); // called to convert prob atlas volume to a functional volume void slotProbAtlasConvertToFunctional(); // Called when anatomy threshold menu item selected void slotAnatomyThreshold(); // called to edit paint volume voxels void slotPaintEditVoxels(); // called to generate colors for paint names void slotGenerateColorsForPaints(); protected: /// create math operations action QAction* mathOperationsVolumeAction; /// create empty volume action QAction* createEmptyVolumeAction; /// resize underlay volume action QAction* resizeUnderlayVolumeAction; /// show voxel extent action QAction* showVoxelExtentAction; /// edit volume attributes action QAction* editVolumeAttributesAction; /// find handles action QAction* findHandlesAction; /// reconstruct action QAction* reconstructAction; /// edit segmentation action QAction* editSegmentationAction; /// surefit segmentation action QAction* surefitSegmentationAction; /// pad segmentation action QAction* padSegmentationAction; /// remove islands action QAction* removeIslandsAction; /// topology report action QAction* topologyReportAction; /// cerebral hull action QAction* cerebralHullAction; /// fill cavities action QAction* fillCavitiesAction; /// apply rotation action QAction* applyRotationAction; /// enable rotation action QAction* enableRotationAction; /// region of interest action QAction* regionOfInterestAction; /// prob atlas to volume action QAction* probAtlasToVolumeAction; /// anatomy threshold action QAction* anatomyThresholdAction; /// anatomy bias correction action QAction* anatomyBiasCorrectionAction; /// edit paint volume action QAction* editPaintVolumeAction; /// generaet colors for paint volume actiono QAction* paintVolumeGenerateColorsAction; }; #endif // __GUI_MAIN_WINDOW_VOLUME_ACTIONS_H__ caret-5.6.4~dfsg.1.orig/caret/GuiMainWindowVolumeActions.cxx0000664000175000017500000006457011572067322023651 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include "AreaColorFile.h" #include "AtlasSpaceFile.h" #include "BrainSet.h" #include "BrainModelVolume.h" #include "BrainModelVolumeProbAtlasToFunctional.h" #include "BrainModelVolumeSureFitErrorCorrection.h" #include "BrainModelVolumeSureFitSegmentation.h" #include "BrainModelVolumeVoxelColoring.h" #include "DisplaySettingsVolume.h" #include "FileUtilities.h" #include "GuiBrainModelOpenGL.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "GuiMainWindowVolumeActions.h" #include "GuiVolumeCreateDialog.h" #include "GuiVolumeHandleFinderDialog.h" #include "GuiVolumeReconstructionDialog.h" #include "GuiVolumeSegmentationEditorDialog.h" #include "GuiVolumeSelectionDialog.h" #include "GuiVolumeSureFitSegmentationDialog.h" #include "GuiVolumeTopologyReportDialog.h" #include "QtTextEditDialog.h" #include "VolumeFile.h" #include "WuQDataEntryDialog.h" #include "global_variables.h" #include "vtkTransform.h" /** * Constructor. */ GuiMainWindowVolumeActions::GuiMainWindowVolumeActions(GuiMainWindow* mainWindowParent) : QObject(mainWindowParent) { setObjectName("GuiMainWindowVolumeActions"); createEmptyVolumeAction = new QAction(mainWindowParent); createEmptyVolumeAction->setText("Create New Volume..."); createEmptyVolumeAction->setObjectName("createEmptyVolumeAction"); QObject::connect(createEmptyVolumeAction, SIGNAL(triggered(bool)), this, SLOT(slotCreateNewEmptyVolume())); resizeUnderlayVolumeAction = new QAction(mainWindowParent); resizeUnderlayVolumeAction->setText("Resize Underlay Volume..."); resizeUnderlayVolumeAction->setObjectName("resizeUnderlayVolumeAction"); QObject::connect(resizeUnderlayVolumeAction, SIGNAL(triggered(bool)), this, SLOT(slotResizeUnderlayVolume())); showVoxelExtentAction = new QAction(mainWindowParent); showVoxelExtentAction->setText("Show Voxel Dimensional Extent..."); showVoxelExtentAction->setObjectName("showVoxelExtentAction"); QObject::connect(showVoxelExtentAction, SIGNAL(triggered(bool)), this, SLOT(slotShowVoxelDimensionExtent())); editVolumeAttributesAction = new QAction(mainWindowParent); editVolumeAttributesAction->setText("Edit Volume Attributes..."); editVolumeAttributesAction->setObjectName("editVolumeAttributesAction"); QObject::connect(editVolumeAttributesAction, SIGNAL(triggered(bool)), this, SLOT(slotEditAttributes())); findHandlesAction = new QAction(mainWindowParent); findHandlesAction->setText("Find Handles..."); findHandlesAction->setObjectName("findHandlesAction"); QObject::connect(findHandlesAction, SIGNAL(triggered(bool)), this, SLOT(slotSegmentationFindHandles())); reconstructAction = new QAction(mainWindowParent); reconstructAction->setText("Reconstruct Into Surface..."); reconstructAction->setObjectName("reconstructAction"); QObject::connect(reconstructAction, SIGNAL(triggered(bool)), this, SLOT(slotSegmentationReconstruct())); editSegmentationAction = new QAction(mainWindowParent); editSegmentationAction->setText("Edit Voxels..."); editSegmentationAction->setObjectName("editSegmentationAction"); QObject::connect(editSegmentationAction, SIGNAL(triggered(bool)), this, SLOT(slotSegmentationEditVoxels())); surefitSegmentationAction = new QAction(mainWindowParent); surefitSegmentationAction->setText("SureFit Operations (Segmentation)..."); surefitSegmentationAction->setObjectName("surefitSegmentationAction"); QObject::connect(surefitSegmentationAction, SIGNAL(triggered(bool)), this, SLOT(slotSureFitSegmentation())); padSegmentationAction = new QAction(mainWindowParent); padSegmentationAction->setText("Pad Volume..."); padSegmentationAction->setObjectName("padSegmentationAction"); QObject::connect(padSegmentationAction, SIGNAL(triggered(bool)), this, SLOT(slotSegmentPad())); removeIslandsAction = new QAction(mainWindowParent); removeIslandsAction->setText("Remove Islands"); removeIslandsAction->setObjectName("removeIslandsAction"); QObject::connect(removeIslandsAction, SIGNAL(triggered(bool)), this, SLOT(slotSegmentRemoveIslands())); topologyReportAction = new QAction(mainWindowParent); topologyReportAction->setText("Topology Error Report..."); topologyReportAction->setObjectName("topologyReportAction"); QObject::connect(topologyReportAction, SIGNAL(triggered(bool)), this, SLOT(slotSegmentationTopologyReport())); cerebralHullAction = new QAction(mainWindowParent); cerebralHullAction->setText("Generate Cerebral Hull Volume"); cerebralHullAction->setObjectName("cerebralHullAction"); QObject::connect(cerebralHullAction, SIGNAL(triggered(bool)), this, SLOT(slotSegmentationCerebralHull())); fillCavitiesAction = new QAction(mainWindowParent); fillCavitiesAction->setText("Fill Cavities"); fillCavitiesAction->setObjectName("fillCavitiesAction"); QObject::connect(fillCavitiesAction, SIGNAL(triggered(bool)), this, SLOT(slotSegmentationFillCavities())); applyRotationAction = new QAction(mainWindowParent); applyRotationAction->setText("Apply Rotation..."); applyRotationAction->setObjectName("applyRotationAction"); QObject::connect(applyRotationAction, SIGNAL(triggered(bool)), this, SLOT(slotTransformApplyRotation())); enableRotationAction = new QAction(mainWindowParent); enableRotationAction->setText("Enable Rotation"); enableRotationAction->setObjectName("enableRotationAction"); enableRotationAction->setCheckable(true); QObject::connect(enableRotationAction, SIGNAL(triggered(bool)), this, SLOT(slotTransformEnableRotation())); regionOfInterestAction = new QAction(mainWindowParent); regionOfInterestAction->setText("Region of Interest Operations..."); regionOfInterestAction->setObjectName("regionOfInterestAction"); QObject::connect(regionOfInterestAction, SIGNAL(triggered(bool)), this, SLOT(slotRegionOfInterestDialog())); probAtlasToVolumeAction = new QAction(mainWindowParent); probAtlasToVolumeAction->setText("Convert Probabilistic Atlas to Functional Volume..."); probAtlasToVolumeAction->setObjectName("probAtlasToVolumeAction"); QObject::connect(probAtlasToVolumeAction, SIGNAL(triggered(bool)), this, SLOT(slotProbAtlasConvertToFunctional())); anatomyBiasCorrectionAction = new QAction(mainWindowParent); anatomyBiasCorrectionAction->setText("Bias Correction..."); anatomyBiasCorrectionAction->setObjectName("anatomyBiasCorrectionAction"); QObject::connect(anatomyBiasCorrectionAction, SIGNAL(triggered(bool)), mainWindowParent, SLOT(displayVolumeBiasCorrectionDialog())); anatomyThresholdAction = new QAction(mainWindowParent); anatomyThresholdAction->setText("Threshold Into Segmentation..."); anatomyThresholdAction->setObjectName("anatomyThresholdAction"); QObject::connect(anatomyThresholdAction, SIGNAL(triggered(bool)), this, SLOT(slotAnatomyThreshold())); editPaintVolumeAction = new QAction(mainWindowParent); editPaintVolumeAction->setText("Edit Voxels..."); editPaintVolumeAction->setObjectName("editPaintVolumeAction"); QObject::connect(editPaintVolumeAction, SIGNAL(triggered(bool)), this, SLOT(slotPaintEditVoxels())); paintVolumeGenerateColorsAction = new QAction(mainWindowParent); paintVolumeGenerateColorsAction->setText("Generate Colors for Paints without Colors"); paintVolumeGenerateColorsAction->setObjectName("paintVolumeGenerateColorsAction"); QObject::connect(paintVolumeGenerateColorsAction, SIGNAL(triggered(bool)), this, SLOT(slotGenerateColorsForPaints())); mathOperationsVolumeAction = new QAction(mainWindowParent); mathOperationsVolumeAction->setText("Mathematical Operations..."); mathOperationsVolumeAction->setObjectName("mathOperationsVolumeAction"); QObject::connect(mathOperationsVolumeAction, SIGNAL(triggered(bool)), mainWindowParent, SLOT(displayVolumeMathDialog())); } /** * Destructor. */ GuiMainWindowVolumeActions::~GuiMainWindowVolumeActions() { } /** * called to create a new empty volume. */ void GuiMainWindowVolumeActions::slotCreateNewEmptyVolume() { GuiVolumeCreateDialog cd(theMainWindow); cd.exec(); } /** * called to display volume region of interest dialog. */ void GuiMainWindowVolumeActions::slotRegionOfInterestDialog() { theMainWindow->getVolumeRegionOfInterestDialog(true); } /** * called to crop the underlay volume. */ void GuiMainWindowVolumeActions::slotResizeUnderlayVolume() { theMainWindow->getVolumeResizingDialog(true); } /** * Called to view/edit volume attributes. */ void GuiMainWindowVolumeActions::slotEditAttributes() { theMainWindow->getVolumeAttributesDialog(true); } /** * Called to show voxel dimensional extent */ void GuiMainWindowVolumeActions::slotShowVoxelDimensionExtent() { BrainModelVolume* bmv = theMainWindow->getBrainModelVolume(); if (bmv != NULL) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); int extent[6]; VolumeFile* vf = bmv->getMasterVolumeFile(); if (vf != NULL) { float coordExtent[6]; vf->getNonZeroVoxelExtent(extent, coordExtent); QString str = ("Non-zero voxel dimensional extent: \n" " Parasagittal: (" + QString::number(extent[0]) + ", " + QString::number(extent[1]) + ")\n" " Coronal: (" + QString::number(extent[2]) + ", " + QString::number(extent[3]) + ")\n" " Horizontal: (" + QString::number(extent[4]) + ", " + QString::number(extent[5]) + ")\n" ); str += ( "\nCoordinate range (centers of voxels):\n" " X: (" + QString::number(coordExtent[0], 'f', 2) + ", " + QString::number(coordExtent[1], 'f', 2) + ")\n" " Y: (" + QString::number(coordExtent[2], 'f', 2) + ", " + QString::number(coordExtent[3], 'f', 2) + ")\n" " Z: (" + QString::number(coordExtent[4], 'f', 2) + ", " + QString::number(coordExtent[5], 'f', 2) + ")\n"); QMessageBox* mb = new QMessageBox("Voxel Dimensional Extent", str, QMessageBox::NoIcon, QMessageBox::Ok, Qt::NoButton, Qt::NoButton, theMainWindow, Qt::MSWindowsFixedSizeDialogHint); mb->setModal(false); mb->show(); mb->setAttribute(Qt::WA_DeleteOnClose); QApplication::restoreOverrideCursor(); } } } /** * Called to display apply rotation dialog. */ void GuiMainWindowVolumeActions::slotTransformEnableRotation() { // // Toggle // //enableRotationAction->setChecked(!enableRotationAction->isChecked()); // // If enabling rotation and volume in main window, change mouse mode to VIEW // if (enableRotationAction->isChecked()) { if (theMainWindow->getBrainModelOpenGL()->getDisplayedBrainModelVolume() != NULL) { theMainWindow->getBrainModelOpenGL()->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_VIEW); } } // // Update main window status bar // theMainWindow->updateStatusBarLabel(); } /** * Called to display apply rotation dialog. */ void GuiMainWindowVolumeActions::slotTransformApplyRotation() { BrainModelVolume* bmv = theMainWindow->getBrainModelVolume(); if (bmv != NULL) { // // Dialog for choosing volume to which apply rotation is applied // WuQDataEntryDialog ded(theMainWindow); ded.setWindowTitle("Apply Rotation"); // // Primary overlay // QCheckBox* primaryOverlayCheckBox = NULL; VolumeFile* primaryOverlay = bmv->getOverlayPrimaryVolumeFile(); if (primaryOverlay != NULL) { QString name("Primary Overlay: "); name.append(FileUtilities::basename(primaryOverlay->getFileName())); primaryOverlayCheckBox = ded.addCheckBox(name, true); } // // Secondary overlay // QCheckBox* secondaryOverlayCheckBox = NULL; VolumeFile* secondaryOverlay = bmv->getOverlaySecondaryVolumeFile(); if (secondaryOverlay != NULL) { QString name("Secondary Overlay: "); name.append(FileUtilities::basename(secondaryOverlay->getFileName())); secondaryOverlayCheckBox = ded.addCheckBox(name, true); } // // Underlay // QCheckBox* underlayCheckBox = NULL; VolumeFile* underlay = bmv->getUnderlayVolumeFile(); if (underlay != NULL) { QString name("Underlay: "); name.append(FileUtilities::basename(underlay->getFileName())); underlayCheckBox = ded.addCheckBox(name, true); } // // Did user press OK ? // if (ded.exec() == QDialog::Accepted) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); vtkTransform* transform = vtkTransform::New(); switch (bmv->getSelectedAxis(0)) { case VolumeFile::VOLUME_AXIS_X: transform->RotateX(-bmv->getDisplayRotation(0)); break; case VolumeFile::VOLUME_AXIS_Y: transform->RotateY(bmv->getDisplayRotation(0)); break; case VolumeFile::VOLUME_AXIS_Z: transform->RotateZ(-bmv->getDisplayRotation(0)); break; case VolumeFile::VOLUME_AXIS_ALL: case VolumeFile::VOLUME_AXIS_OBLIQUE: case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } // // Apply to primary overlay volume // if (primaryOverlayCheckBox != NULL) { if (primaryOverlayCheckBox->isChecked()) { primaryOverlay->applyTransformationMatrix(transform); } } // // Apply to secondary overlay volume // if (secondaryOverlayCheckBox != NULL) { if (secondaryOverlayCheckBox->isChecked()) { secondaryOverlay->applyTransformationMatrix(transform); } } // // Apply to underlay volume // if (underlayCheckBox != NULL) { if (underlayCheckBox->isChecked()) { underlay->applyTransformationMatrix(transform); } } transform->Delete(); // // Reset the transformations // bmv->resetViewingTransform(0); GuiFilesModified fm; fm.setVolumeModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } } } /** * Called when anatomy threshold menu item selected. */ void GuiMainWindowVolumeActions::slotAnatomyThreshold() { theMainWindow->getVolumeThresholdSegmentationDialog(true); } /** * called to edit paint volume voxels. */ void GuiMainWindowVolumeActions::slotPaintEditVoxels() { theMainWindow->getVolumePaintEditorDialog(true); } /** * slot for generating colors for non-matching paint names. */ void GuiMainWindowVolumeActions::slotGenerateColorsForPaints() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); std::set uniquePaintNames; for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfVolumePaintFiles(); i++) { VolumeFile* vf = theMainWindow->getBrainSet()->getVolumePaintFile(i); vf->createRegionNamesForVoxelsThatDoNotIndexIntoRegionNames(); const int num = vf->getNumberOfRegionNames(); for (int j = 0; j < num; j++) { uniquePaintNames.insert(vf->getRegionNameFromIndex(j)); } vf->setVoxelColoringInvalid(); } std::vector paintNames(uniquePaintNames.begin(), uniquePaintNames.end()); ColorFile* cf = theMainWindow->getBrainSet()->getAreaColorFile(); cf->generateColorsForNamesWithoutColors(paintNames, true); GuiBrainModelOpenGL::updateAllGL(NULL); GuiFilesModified fm; fm.setAreaColorModified(); theMainWindow->fileModificationUpdate(fm); QApplication::restoreOverrideCursor(); } /** * called to convert prob atlas volume to a functional volume. */ void GuiMainWindowVolumeActions::slotProbAtlasConvertToFunctional() { GuiVolumeSelectionDialog vsd(theMainWindow, false, true, false, false, false, false, false, GuiVolumeSelectionControl::LABEL_MODE_FILE_LABEL_AND_NAME, "selectFuncForProbAtlasDialog", true, true, true); if (vsd.exec() == QDialog::Accepted) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainModelVolumeProbAtlasToFunctional bmvpatf(theMainWindow->getBrainSet(), vsd.getSelectedVolumeFile(), vsd.getSelectedVolumeFileName(), vsd.getSelectedVolumeDescriptiveLabel()); try { bmvpatf.execute(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(theMainWindow, "ERROR", e.whatQString()); return; } GuiFilesModified fm; fm.setVolumeModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); QApplication::beep(); QApplication::restoreOverrideCursor(); } } /** * Called to remove islands from segmentation volume. */ void GuiMainWindowVolumeActions::slotSegmentRemoveIslands() { BrainModelVolume* bmv = theMainWindow->getBrainSet()->getBrainModelVolume(-1); if (bmv != NULL) { VolumeFile* vf = bmv->getSelectedVolumeSegmentationFile(); if (vf != NULL) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); vf->removeIslandsFromSegmentation(); GuiFilesModified fm; fm.setVolumeModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } } } /** * Called to generate the cerebral hull volume from the segmentation volume. */ void GuiMainWindowVolumeActions::slotSegmentationCerebralHull() { BrainModelVolume* bmv = theMainWindow->getBrainSet()->getBrainModelVolume(-1); if (bmv != NULL) { VolumeFile* vf = bmv->getSelectedVolumeSegmentationFile(); if (vf != NULL) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); // // Expand around edges with empty slices // VolumeFile segmentVolumeExpanded(*vf); int expDim[3]; segmentVolumeExpanded.getDimensions(expDim); const int expSlices = 7; const int resizeCrop[6] = { -expSlices, expDim[0] + expSlices, -expSlices, expDim[1] + expSlices, -expSlices, expDim[2] + expSlices }; segmentVolumeExpanded.resize(resizeCrop); try { theMainWindow->getBrainSet()->generateCerebralHullVtkFile(&segmentVolumeExpanded, true); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(theMainWindow, "ERROR", e.whatQString()); return; } DisplaySettingsVolume* dsv = theMainWindow->getBrainSet()->getDisplaySettingsVolume(); dsv->setSelectedSegmentationVolume(theMainWindow->getBrainSet()->getNumberOfVolumeSegmentationFiles() - 1); GuiFilesModified fm; fm.setVolumeModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } } } /** * Called to display topology information. */ void GuiMainWindowVolumeActions::slotSegmentationTopologyReport() { static GuiVolumeTopologyReportDialog* trd = NULL; if (trd == NULL) { trd = new GuiVolumeTopologyReportDialog(theMainWindow); } trd->show(); trd->activateWindow(); } /** * Called to fill cavities. */ void GuiMainWindowVolumeActions::slotSegmentationFillCavities() { BrainModelVolume* bmv = theMainWindow->getBrainSet()->getBrainModelVolume(-1); if (bmv != NULL) { VolumeFile* vf = bmv->getSelectedVolumeSegmentationFile(); if (vf != NULL) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); vf->fillSegmentationCavities(); GuiFilesModified fm; fm.setVolumeModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } } } /** * Called to pad the segmentation volume. */ void GuiMainWindowVolumeActions::slotSegmentPad() { BrainModelVolume* bmv = theMainWindow->getBrainSet()->getBrainModelVolume(-1); if (bmv != NULL) { VolumeFile* vf = bmv->getSelectedVolumeSegmentationFile(); if (vf != NULL) { WuQDataEntryDialog ded(theMainWindow); ded.setWindowTitle("Padding Options"); QSpinBox* xLeftSpinBox = ded.addSpinBox("X Left", 0, 10000, 1); QSpinBox* xRightSpinBox = ded.addSpinBox("X Right", 0, 10000, 1); QSpinBox* yPosteriorSpinBox = ded.addSpinBox("Y Posterior", 0, 10000, 1); QSpinBox* yAnteriorSpinBox = ded.addSpinBox("Y Anterior", 0, 10000, 1); QSpinBox* zInferiorSpinBox = ded.addSpinBox("Z Inferior", 0, 10000, 1); QSpinBox* zSuperiorSpinBox = ded.addSpinBox("Z Superior", 0, 10000, 1); QCheckBox* erodePaddingCheckBox = ded.addCheckBox("Erode Padding", true); if (ded.exec() == QDialog::Accepted) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); const int padding[6] = { xLeftSpinBox->value(), xRightSpinBox->value(), yPosteriorSpinBox->value(), yAnteriorSpinBox->value(), zInferiorSpinBox->value(), zSuperiorSpinBox->value() }; vf->padSegmentation(padding, erodePaddingCheckBox->isChecked()); GuiFilesModified fm; fm.setVolumeModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } } } } /** * Segment the selected anatomical volume. */ void GuiMainWindowVolumeActions::slotSureFitSegmentation() { GuiVolumeSureFitSegmentationDialog* sd = new GuiVolumeSureFitSegmentationDialog(theMainWindow); sd->show(); sd->activateWindow(); } /** * Called to display the segmentation volume editor */ void GuiMainWindowVolumeActions::slotSegmentationEditVoxels() { theMainWindow->getVolumeSegmentationEditorDialog(true); } /** * Called to find handles in segmentation volume. */ void GuiMainWindowVolumeActions::slotSegmentationFindHandles() { static GuiVolumeHandleFinderDialog* hdf = NULL; if (hdf == NULL) { hdf = new GuiVolumeHandleFinderDialog(theMainWindow); } hdf->show(); hdf->activateWindow(); } /** * Called to reconstruct a segmentation volume into a surface.. */ void GuiMainWindowVolumeActions::slotSegmentationReconstruct() { BrainModelVolume* bmv = theMainWindow->getBrainSet()->getBrainModelVolume(-1); if (bmv != NULL) { VolumeFile* vf = bmv->getSelectedVolumeSegmentationFile(); if (vf != NULL) { GuiVolumeReconstructionDialog vrd(theMainWindow, vf, true); vrd.exec(); } } } /** * update the actions (typically called when menu is about to show) */ void GuiMainWindowVolumeActions::updateActions() { bool haveUnderlayVolume = false; BrainModelVolume* bmv = theMainWindow->getBrainModelVolume(); if (bmv != NULL) { haveUnderlayVolume = (bmv->getUnderlayVolumeFile() != NULL); } resizeUnderlayVolumeAction->setEnabled(haveUnderlayVolume); anatomyThresholdAction->setEnabled(theMainWindow->getBrainSet()->getNumberOfVolumeAnatomyFiles() > 0); applyRotationAction->setEnabled(enableRotationAction->isChecked()); editPaintVolumeAction->setEnabled(theMainWindow->getBrainSet()->getNumberOfVolumePaintFiles() > 0); probAtlasToVolumeAction->setEnabled(theMainWindow->getBrainSet()->getNumberOfVolumeProbAtlasFiles() > 0); } caret-5.6.4~dfsg.1.orig/caret/GuiMainWindowTimingMenu.h0000664000175000017500000000246311572067322022553 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_MAIN_WINDOW_TIMING_MENU_H__ #define __GUI_MAIN_WINDOW_TIMING_MENU_H__ #include class GuiMainWindow; /// This class creates the Main Window's Timing Menu. class GuiMainWindowTimingMenu : public QMenu { Q_OBJECT public: /// constructor GuiMainWindowTimingMenu(GuiMainWindow* parent); /// destructor ~GuiMainWindowTimingMenu(); }; #endif // __GUI_MAIN_WINDOW_TIMING_MENU_H__ caret-5.6.4~dfsg.1.orig/caret/GuiMainWindowTimingMenu.cxx0000664000175000017500000000246611572067322023131 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "GuiMainWindow.h" #include "GuiMainWindowTimingActions.h" #include "GuiMainWindowTimingMenu.h" /** * Constructor. */ GuiMainWindowTimingMenu::GuiMainWindowTimingMenu(GuiMainWindow* parent) : QMenu("Timing", parent) { GuiMainWindowTimingActions* timingActions = parent->getTimingActions(); addAction(timingActions->getViewTimingTestAction()); } /** * Destructor. */ GuiMainWindowTimingMenu::~GuiMainWindowTimingMenu() { } caret-5.6.4~dfsg.1.orig/caret/GuiMainWindowTimingActions.h0000664000175000017500000000340411572067322023243 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_MAIN_WINDOW_TIMING_ACTIONS_H__ #define __GUI_MAIN_WINDOW_TIMING_ACTIONS_H__ #include class GuiMainWindow; class QAction; /// This class creates the Main Window's Timing Actions class GuiMainWindowTimingActions : public QObject { Q_OBJECT public: /// constructor GuiMainWindowTimingActions(GuiMainWindow* parent); /// destructor ~GuiMainWindowTimingActions(); /// get the timing test action QAction* getViewTimingTestAction() { return viewTimingTestAction; } public slots: /// update the actions (typically called when menu is about to show) void updateActions(); protected slots: /// Called when timing test selected void viewMenuTimingTest(); protected: /// the timing test action QAction* viewTimingTestAction; }; #endif // __GUI_MAIN_WINDOW_TIMING_ACTIONS_H__ caret-5.6.4~dfsg.1.orig/caret/GuiMainWindowTimingActions.cxx0000664000175000017500000000550011572067322023615 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "BrainModelSurface.h" #include "GuiBrainModelOpenGL.h" #include "GuiMainWindow.h" #include "GuiMainWindowTimingActions.h" #include "TopologyFile.h" #include "global_variables.h" /** * Constructor. */ GuiMainWindowTimingActions::GuiMainWindowTimingActions(GuiMainWindow* parent) : QObject(parent) { viewTimingTestAction = new QAction(parent); viewTimingTestAction->setObjectName("viewTimingTestAction"); viewTimingTestAction->setText("Timing Test"); QObject::connect(viewTimingTestAction, SIGNAL(triggered(bool)), this, SLOT(viewMenuTimingTest())); } /** * Destructor. */ GuiMainWindowTimingActions::~GuiMainWindowTimingActions() { } /** * Called for running a timing test. */ void GuiMainWindowTimingActions::viewMenuTimingTest() { const int numTimes = 20; QTime timer; QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); timer.start(); for (int i = 0; i < numTimes; i++) { GuiBrainModelOpenGL::updateAllGL(theMainWindow->getBrainModelOpenGL()); } const float milliseconds = static_cast(timer.elapsed()) / static_cast(numTimes); const float fps = 1000.0 / milliseconds; std::ostringstream str; str << "Average time: " << milliseconds << " milliseconds per frame\n" << "Frames per second: " << fps << "\n"; const BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { const TopologyFile* tf = bms->getTopologyFile(); if (tf != NULL) { str << "Number of triangles: " << tf->getNumberOfTiles() << "\n"; } } str << std::ends; QApplication::restoreOverrideCursor(); QMessageBox::information(theMainWindow, "Timing", str.str().c_str()); } /** * update the actions (typically called when menu is about to show) */ void GuiMainWindowTimingActions::updateActions() { } caret-5.6.4~dfsg.1.orig/caret/GuiMainWindowSurfaceMenu.h0000664000175000017500000001037211572067322022712 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_MAIN_WINDOW_SURFACE_MENU_H__ #define __GUI_MAIN_WINDOW_SURFACE_MENU_H__ #include #include class GuiMainWindow; class GuiMainWindowSurfaceActions; /// This class creates the Main Window's Surface Menu. class GuiMainWindowSurfaceMenu : public QMenu { Q_OBJECT public: /// constructor GuiMainWindowSurfaceMenu(GuiMainWindow* parent); /// destructor ~GuiMainWindowSurfaceMenu(); /// load the user view switch view sub menu void loadUserViewSwitchViewSubMenu(); private slots: /// slot called when user view menu is about to show void slotUserViewMenuAboutToShow(); /// called when a user view is selected void slotUserViewSelected(QAction*); private: /// create the edit sub menu void createEditSubMenu(GuiMainWindowSurfaceActions* surfaceActions); /// create the cuts sub menu void createCutsSubMenu(GuiMainWindowSurfaceActions* surfaceActions); /// create the geometry sub menu void createGeometrySubMenu(GuiMainWindowSurfaceActions* surfaceActions); /// create the deformation sub menu void createDeformationSubMenu(GuiMainWindowSurfaceActions* surfaceActions); /// create the identify sub menu void createIdentifySubMenu(GuiMainWindowSurfaceActions* surfaceActions); /// create the normals sub menu void createNormalsSubMenu(GuiMainWindowSurfaceActions* surfaceActions); /// create the measurements sub menu void createMeasurementsSubMenu(GuiMainWindowSurfaceActions* surfaceActions); /// create the morphing sub menu void createMorphingSubMenu(GuiMainWindowSurfaceActions* surfaceActions); /// create the sections sub menu void createSectionsSubMenu(GuiMainWindowSurfaceActions* surfaceActions); /// create the transform sub menu void createTransformSubMenu(GuiMainWindowSurfaceActions* surfaceActions); /// create the topology sub menu void createTopologySubMenu(GuiMainWindowSurfaceActions* surfaceActions); /// create the topology correction sub menu void createTopologyCorrectionSubMenu(GuiMainWindowSurfaceActions* surfaceActions, QMenu* parentMenu); /// create the user view sub menu void createUserViewSubMenu(GuiMainWindowSurfaceActions* surfaceActions); /// cuts sub menu QMenu* cutsSubMenu; /// edit sub menu QMenu* editSubMenu; /// deformation sub menu QMenu* deformationSubMenu; /// geometry sub menu QMenu* geometrySubMenu; /// identify sub menu QMenu* identifySubMenu; /// morphing sub menu QMenu* morphingSubMenu; /// normals sub menu QMenu* normalsSubMenu; /// measurements sub menu QMenu* measurementsSubMenu; /// transform sub menu QMenu* transformSubMenu; /// topology sub menu QMenu* topologySubMenu; /// topology correction sub menu QMenu* topologyCorrectionSubMenu; /// section sub menu QMenu* sectionsSubMenu; /// user view sub menu QMenu* userViewSubMenu; /// user view switch to view sub menu QMenu* userViewSwitchViewSubMenu; }; #endif caret-5.6.4~dfsg.1.orig/caret/GuiMainWindowSurfaceMenu.cxx0000664000175000017500000003375611572067322023300 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainSet.h" #include "DebugControl.h" #include "GuiMainWindow.h" #include "GuiMainWindowSurfaceActions.h" #include "GuiMainWindowSurfaceMenu.h" #include "global_variables.h" /** * Constructor. */ GuiMainWindowSurfaceMenu::GuiMainWindowSurfaceMenu(GuiMainWindow* parent) : QMenu("Surface", parent) { setObjectName("GuiMainWindowSurfaceMenu"); GuiMainWindowSurfaceActions* surfaceActions = parent->getSurfaceActions(); addAction(surfaceActions->getAlignSurfacesToStandardOrientationAction()); addAction(surfaceActions->getAutomaticRotationAction()); addAction(surfaceActions->getSurfaceToSegmentationVolumeAction()); if (DebugControl::getTestFlag1()) { addAction(surfaceActions->getStandardMeshDialogAction()); } addAction(surfaceActions->getCopyMainWindowSurfaceAction()); addAction(surfaceActions->getAverageCoordinateFileAction()); createCutsSubMenu(surfaceActions); createDeformationSubMenu(surfaceActions); addAction(surfaceActions->getFlattenHemisphereAction()); addAction(surfaceActions->getFlattenFullHemisphereAction()); createEditSubMenu(surfaceActions); createGeometrySubMenu(surfaceActions); createIdentifySubMenu(surfaceActions); addAction(surfaceActions->getSurfaceInformationAction()); addAction(surfaceActions->getInterpolateSurfacesAction()); createMeasurementsSubMenu(surfaceActions); createMorphingSubMenu(surfaceActions); createNormalsSubMenu(surfaceActions); addAction(surfaceActions->getProjectToPlaneAction()); //addAction(surfaceActions->getRegionOfInterestActionOLD()); addAction(surfaceActions->getRegionOfInterestAction()); createSectionsSubMenu(surfaceActions); addAction(surfaceActions->getSimplifySurfaceAction()); createTopologySubMenu(surfaceActions); createTransformSubMenu(surfaceActions); createUserViewSubMenu(surfaceActions); QObject::connect(this, SIGNAL(aboutToShow()), surfaceActions, SLOT(updateActions())); } /** * Destructor. */ GuiMainWindowSurfaceMenu::~GuiMainWindowSurfaceMenu() { } /** * Create the the normals sub menu */ void GuiMainWindowSurfaceMenu::createNormalsSubMenu(GuiMainWindowSurfaceActions* surfaceActions) { normalsSubMenu = addMenu("Normals"); normalsSubMenu->addAction(surfaceActions->getNormalsFlipAction()); normalsSubMenu->addAction(surfaceActions->getNormalsGenerateAction()); } /** * Create the measurements sub menu. */ void GuiMainWindowSurfaceMenu::createMeasurementsSubMenu(GuiMainWindowSurfaceActions* surfaceActions) { measurementsSubMenu = addMenu("Measurements"); measurementsSubMenu->addAction(surfaceActions->getMeasurementsCrossoverCheckAction()); measurementsSubMenu->addAction(surfaceActions->getMeasurementsCurvatureAction()); measurementsSubMenu->addAction(surfaceActions->getMeasurementsShapeFromCoordinateSubtraction()); measurementsSubMenu->addAction(surfaceActions->getMeasurementsDistortionAction()); measurementsSubMenu->addAction(surfaceActions->getMeasurementsSulcalDepthAction()); } /** * Create the measurements sub menu. */ void GuiMainWindowSurfaceMenu::createCutsSubMenu(GuiMainWindowSurfaceActions* surfaceActions) { cutsSubMenu = addMenu("Cuts"); cutsSubMenu->addAction(surfaceActions->getCutsShowAction()); cutsSubMenu->addAction(surfaceActions->getCutsApplyAction()); cutsSubMenu->addAction(surfaceActions->getCutsDeleteWithMouseAction()); cutsSubMenu->addAction(surfaceActions->getCutsDeleteAllAction()); cutsSubMenu->addAction(surfaceActions->getCutsDrawAction()); } /** * Create the morphing sub menu. */ void GuiMainWindowSurfaceMenu::createMorphingSubMenu(GuiMainWindowSurfaceActions* surfaceActions) { morphingSubMenu = addMenu("Morphing"); morphingSubMenu->addAction(surfaceActions->getMorphFlatAction()); morphingSubMenu->addAction(surfaceActions->getMorphSphereAction()); morphingSubMenu->addSeparator(); morphingSubMenu->addAction(surfaceActions->getMultiresolutionMorphFlatAction()); morphingSubMenu->addAction(surfaceActions->getMultiresolutionMorphSphereAction()); } /** * Create the morphing sub menu. */ void GuiMainWindowSurfaceMenu::createDeformationSubMenu(GuiMainWindowSurfaceActions* surfaceActions) { deformationSubMenu = addMenu("Deformation"); deformationSubMenu->addAction(surfaceActions->getDeformationApplyDialogAction()); deformationSubMenu->addSeparator(); deformationSubMenu->addAction(surfaceActions->getDeformationRunFlatDialogAction()); deformationSubMenu->addAction(surfaceActions->getDeformationRunSphericalDialogAction()); } /** * Create the morphing sub menu. */ void GuiMainWindowSurfaceMenu::createTransformSubMenu(GuiMainWindowSurfaceActions* surfaceActions) { transformSubMenu = addMenu("Transform"); transformSubMenu->addSeparator(); transformSubMenu->addAction(surfaceActions->getTransformApplyCurrentViewAction()); transformSubMenu->addAction(surfaceActions->getTransformSpmAction()); transformSubMenu->addSeparator(); transformSubMenu->addAction(surfaceActions->getTransformDisconnectedNodesToOriginAction()); transformSubMenu->addSeparator(); transformSubMenu->addAction(surfaceActions->getTransformScaleAction()); transformSubMenu->addAction(surfaceActions->getTransformTranslateAction()); transformSubMenu->addAction(surfaceActions->getTransformSubtractACAction()); transformSubMenu->addAction(surfaceActions->getTransformCenterOfMassAction()); } /** * Create the topology sub menu. */ void GuiMainWindowSurfaceMenu::createTopologySubMenu(GuiMainWindowSurfaceActions* surfaceActions) { topologySubMenu = addMenu("Topology"); if (DebugControl::getTestFlag1()) { createTopologyCorrectionSubMenu(surfaceActions, topologySubMenu); topologySubMenu->addSeparator(); } topologySubMenu->addAction(surfaceActions->getTopologyCorrectFiducialAction()); topologySubMenu->addSeparator(); topologySubMenu->addAction(surfaceActions->getTopologyClassifyEdgesAction()); topologySubMenu->addAction(surfaceActions->getTopologyOrientTilesConsistentlyAction()); topologySubMenu->addSeparator(); topologySubMenu->addAction(surfaceActions->getTopologyCheckForIslandsAction()); topologySubMenu->addAction(surfaceActions->getTopologyDisconnectIslandsAction()); topologySubMenu->addAction(surfaceActions->getTopologyDeleteCornersAction()); topologySubMenu->addSeparator(); topologySubMenu->addAction(surfaceActions->getTopologySetAction()); topologySubMenu->addSeparator(); topologySubMenu->addAction(surfaceActions->getTopologyReportAction()); } /** * Create the topology correction sub menu. */ void GuiMainWindowSurfaceMenu::createTopologyCorrectionSubMenu(GuiMainWindowSurfaceActions* surfaceActions, QMenu* parentMenu) { topologyCorrectionSubMenu = parentMenu->addMenu("Correction"); /* topologyCorrectionSubMenu->addAction(surfaceActions->getTopologyReplaceWithStandardSurfaceAction()); */ topologyCorrectionSubMenu->addAction(surfaceActions->getTopologyRetessellateSphereAction()); } /** * Create the geometry sub menu. */ void GuiMainWindowSurfaceMenu::createGeometrySubMenu(GuiMainWindowSurfaceActions* surfaceActions) { geometrySubMenu = addMenu("Geometry"); geometrySubMenu->addAction(surfaceActions->getGeometryCompressFrontFaceAction()); geometrySubMenu->addAction(surfaceActions->getGeometryCompressMedialWallAction()); geometrySubMenu->addSeparator(); geometrySubMenu->addAction(surfaceActions->getGeometryToSphereAction()); geometrySubMenu->addAction(surfaceActions->getGeometryEllipseToSphereAction()); geometrySubMenu->addAction(surfaceActions->getGeometryInflatedAndEllipsoidFromFiducialAction()); geometrySubMenu->addSeparator(); geometrySubMenu->addAction(surfaceActions->getGeometryExpandAction()); geometrySubMenu->addAction(surfaceActions->getGeometryInflateAction()); geometrySubMenu->addAction(surfaceActions->getGeometryInflateAndSmoothFingersAction()); //geometrySubMenu->addSeparator(); //geometrySubMenu->addAction(surfaceActions->getGeometrySphereBorderDistanceAction()); geometrySubMenu->addSeparator(); geometrySubMenu->addAction(surfaceActions->getGeometrySphereToFlatAction()); geometrySubMenu->addAction(surfaceActions->getGeometrySphereToFlatThroughHoleAction()); geometrySubMenu->addAction(surfaceActions->getGeometryScaleSphereToFiducialAreaAction()); geometrySubMenu->addSeparator(); geometrySubMenu->addAction(surfaceActions->getGeometrySmoothingAction()); if (DebugControl::getTestFlag1()) { geometrySubMenu->addAction(surfaceActions->getGeometryReliefAction()); } } /** * Create the identify sub menu. */ void GuiMainWindowSurfaceMenu::createIdentifySubMenu(GuiMainWindowSurfaceActions* surfaceActions) { identifySubMenu = addMenu("Identify"); identifySubMenu->addAction(surfaceActions->getIdentifyClearSymbolsAction()); identifySubMenu->addSeparator(); identifySubMenu->addAction(surfaceActions->getIdentifyHighlightNodeAction()); identifySubMenu->addAction(surfaceActions->getIdentifyHighlightTileAction()); } /** * Create the sections sub menu. */ void GuiMainWindowSurfaceMenu::createSectionsSubMenu(GuiMainWindowSurfaceActions* surfaceActions) { sectionsSubMenu = addMenu("Sections"); sectionsSubMenu->addAction(surfaceActions->getSectionClearAllOrPartAction()); sectionsSubMenu->addAction(surfaceActions->getSectionResectionAction()); sectionsSubMenu->addAction(surfaceActions->getSectionControlAction()); } /** * Create the user view sub menu. */ void GuiMainWindowSurfaceMenu::createUserViewSubMenu(GuiMainWindowSurfaceActions* surfaceActions) { userViewSubMenu = addMenu("View"); QObject::connect(userViewSubMenu, SIGNAL(aboutToShow()), this, SLOT(slotUserViewMenuAboutToShow())); userViewSubMenu->addAction(surfaceActions->getViewAdjustAction()); userViewSubMenu->addSeparator(); if (DebugControl::getTestFlag1()) { userViewSubMenu->addAction(surfaceActions->getViewPlaceNodeAtCenterOfScreenAction()); } userViewSubMenu->addAction(surfaceActions->getViewScaleSurfaceToFitWindowAction()); userViewSubMenu->addSeparator(); userViewSubMenu->addAction(surfaceActions->getViewUserSaveViewAction()); userViewSwitchViewSubMenu = userViewSubMenu->addMenu("Switch to User View"); QObject::connect(userViewSwitchViewSubMenu, SIGNAL(triggered(QAction*)), this, SLOT(slotUserViewSelected(QAction*))); loadUserViewSwitchViewSubMenu(); } /** * called when a user view is selected. */ void GuiMainWindowSurfaceMenu::slotUserViewSelected(QAction* action) { GuiMainWindowSurfaceActions* surfaceActions = theMainWindow->getSurfaceActions(); const int item = action->data().toInt(); surfaceActions->slotUserViewSwitchToView(item); } /** * Called when user view menu is about to show */ void GuiMainWindowSurfaceMenu::slotUserViewMenuAboutToShow() { loadUserViewSwitchViewSubMenu(); PreferencesFile* pf = theMainWindow->getBrainSet()->getPreferencesFile(); userViewSwitchViewSubMenu->setEnabled(pf->getNumberOfUserViews() > 0); } /** * Load the user view switch view menu. */ void GuiMainWindowSurfaceMenu::loadUserViewSwitchViewSubMenu() { userViewSwitchViewSubMenu->clear(); if (theMainWindow == NULL) { return; } PreferencesFile* pf = theMainWindow->getBrainSet()->getPreferencesFile(); const int num = pf->getNumberOfUserViews(); for (int i = 0; i < num; i++) { const PreferencesFile::UserView* uv = pf->getUserView(i); const QString name = uv->getViewName(); QAction* action = userViewSwitchViewSubMenu->addAction(name); action->setData(i); } } /** * Create the edit sub menu */ void GuiMainWindowSurfaceMenu::createEditSubMenu(GuiMainWindowSurfaceActions* surfaceActions) { editSubMenu = addMenu("Edit"); editSubMenu->addAction(surfaceActions->getEditAddNodeAction()); editSubMenu->addAction(surfaceActions->getEditAddTileAction()); editSubMenu->addAction(surfaceActions->getEditDeleteTileByLinkAction()); editSubMenu->addAction(surfaceActions->getEditDisconnectNodeAction()); editSubMenu->addAction(surfaceActions->getEditMoveNodeAction()); } caret-5.6.4~dfsg.1.orig/caret/GuiMainWindowSurfaceActions.h0000664000175000017500000007404711572067322023417 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_MAIN_WINDOW_SURFACE_ACTIONS_H__ #define __GUI_MAIN_WINDOW_SURFACE_ACTIONS_H__ #include class BrainModelSurface; class BrainModelSurfaceMultiresolutionMorphing; class GuiMainWindow; class GuiMorphingDialog; class QAction; class QtMultipleInputDialog; class TransformationMatrix; /// This class creates the Main Window's Surface Actions class GuiMainWindowSurfaceActions : public QObject { Q_OBJECT public: /// constructor GuiMainWindowSurfaceActions(GuiMainWindow* parent); /// destructor ~GuiMainWindowSurfaceActions(); /// get the flat surface multiresolution morphing object BrainModelSurfaceMultiresolutionMorphing* getFlatMultiresolutionMorphingObject() { return flatMultiResMorphObject; } /// get the spherical surface multiresolution morphing object BrainModelSurfaceMultiresolutionMorphing* getSphericalMultiresolutionMorphingObject() { return sphericalMultiResMorphObject; } /// called when align surface(s) to standard orientation is selected QAction* getAlignSurfacesToStandardOrientationAction() { return alignSurfacesToStandardOrientationAction; } /// called to show create average coordinate file dialog QAction* getAverageCoordinateFileAction() { return averageCoordinateFileAction; } /// action for automatic rotation QAction* getAutomaticRotationAction() { return automaticRotationAction; } /// action for convert surface to segmentation volume QAction* getSurfaceToSegmentationVolumeAction() { return surfaceToSegmentationVolumeAction; } /// action for simplify surface QAction* getSimplifySurfaceAction() { return simplifySurfaceAction; } /// called to interpolate surfaces QAction* getInterpolateSurfacesAction() { return interpolateSurfacesAction; } /// called to copy the surface in the main window QAction* getCopyMainWindowSurfaceAction() { return copyMainWindowSurfaceAction; } /// called when show cuts is selected QAction* getCutsShowAction() { return cutsShowAction; } /// called when apply cuts is selected QAction* getCutsApplyAction() { return cutsApplyAction; } /// called when delete cuts with mouse is selected QAction* getCutsDeleteWithMouseAction() { return cutsDeleteWithMouseAction; } /// called when delete all cuts is selected QAction* getCutsDeleteAllAction() { return cutsDeleteAllAction; } /// called when draw cuts is selected QAction* getCutsDrawAction() { return cutsDrawAction; } /// called when Nearest Spherical Border Distance is selected QAction* getGeometrySphereBorderDistanceAction() { return geometrySphereBorderDistanceAction; } /// called when run deformation dialog is selected QAction* getDeformationRunFlatDialogAction() { return deformationRunFlatDialogAction; } /// called when run deformation dialog is selected QAction* getDeformationRunSphericalDialogAction() { return deformationRunSphericalDialogAction; } /// called when apply deformation dialog is selected QAction* getDeformationApplyDialogAction() { return deformationApplyDialogAction; } /// called when standard mesh dialog is selected QAction* getStandardMeshDialogAction() { return standardMeshDialogAction; } /// called when flatten full hemisphere is selected QAction* getFlattenFullHemisphereAction() { return flattenFullHemisphereAction; } /// called when flatten hemisphere is selected QAction* getFlattenHemisphereAction() { return flattenHemisphereAction; } /// called when crossover check is selected QAction* getMeasurementsCrossoverCheckAction() { return measurementsCrossoverCheckAction; } /// called when curvature generation is selected QAction* getMeasurementsCurvatureAction() { return measurementsCurvatureAction; } /// called when distortion generation is selected QAction* getMeasurementsDistortionAction() { return measurementsDistortionAction; } /// called when sulcal depth generation is selected QAction* getMeasurementsSulcalDepthAction() { return measurementsSulcalDepthAction; } /// called when shape from coordinate subtraction is selected QAction* getMeasurementsShapeFromCoordinateSubtraction() { return measurementsShapeFromCoordinateSubtraction; } /// called to compute normals QAction* getNormalsGenerateAction() { return normalsGenerateAction; } /// called when flip normals menu items is selected QAction* getNormalsFlipAction() { return normalsFlipAction; } /// slot for region of interest dialog QAction* getRegionOfInterestAction() { return regionOfInterestAction; } /// slot for region of interest dialog OLD QAction* getRegionOfInterestActionOLD() { return regionOfInterestActionOLD; } /// called when surface information menu item is selected QAction* getSurfaceInformationAction() { return surfaceInformationAction; } /// called when spm transform selected QAction* getTransformSpmAction() { return transformSpmAction; } /// called to translate surface to center of mass QAction* getTransformCenterOfMassAction() { return transformCenterOfMassAction; } /// called to subtract AC from main window surface QAction* getTransformSubtractACAction() { return transformSubtractACAction; } /// called to move disconnected nodes to the origin QAction* getTransformDisconnectedNodesToOriginAction() { return transformDisconnectedNodesToOriginAction; } /// called to apply current view to the surface QAction* getTransformApplyCurrentViewAction() { return transformApplyCurrentViewAction; } /// called to translate the surface by a user entered amount QAction* getTransformTranslateAction() { return transformTranslateAction; } /// called to translate the surface by a user entered amount QAction* getTransformScaleAction() { return transformScaleAction; } /// get sphere morph action QAction* getMorphSphereAction() { return morphSphereAction; } /// get flat morph action QAction* getMorphFlatAction() { return morphFlatAction; } /// slot for multiresolution morphing flat QAction* getMultiresolutionMorphFlatAction() { return multiresolutionMorphFlatAction; } /// slot for multiresolution morphing spherical QAction* getMultiresolutionMorphSphereAction() { return multiresolutionMorphSphereAction; } /// slot for deleting corner tiles QAction* getTopologyDeleteCornersAction() { return topologyDeleteCornersAction; } /// slot for topology set topology menu QAction* getTopologySetAction() { return topologySetAction; } /// slot for topology check for islands QAction* getTopologyCheckForIslandsAction() { return topologyCheckForIslandsAction; } /// slot for topology disconnect islands QAction* getTopologyDisconnectIslandsAction() { return topologyDisconnectIslandsAction; } /// called when classify edges is selected QAction* getTopologyClassifyEdgesAction() { return topologyClassifyEdgesAction; } /// called when orient tiles consistently QAction* getTopologyOrientTilesConsistentlyAction() { return topologyOrientTilesConsistentlyAction; } /// replace topology with standard topology QAction* getTopologyReplaceWithStandardSurfaceAction() { return topologyReplaceWithStandardSurfaceAction; } /// called when retessellate sphere selected QAction* getTopologyRetessellateSphereAction() { return topologyRetessellateSphereAction; } /// action when correct fiducial selected QAction* getTopologyCorrectFiducialAction() { return topologyCorrectFiducialAction; } /// called when topology report selected QAction* getTopologyReportAction() { return topologyReportAction; } /// slot for identify menu item QAction* getIdentifyHighlightTileAction() { return identifyHighlightTileAction; } /// slot for identify menu item QAction* getIdentifyHighlightNodeAction() { return identifyHighlightNodeAction; } /// slot for identify menu item QAction* getIdentifyClearSymbolsAction() { return identifyClearSymbolsAction; } /// action for section control dialog QAction* getSectionControlAction() { return sectionControlAction; } /// called when clear all or part of section file selected QAction* getSectionClearAllOrPartAction() { return sectionClearAllOrPartAction; } /// called to display resectioning dialog QAction* getSectionResectionAction() { return sectionResectionAction; } /// called to add relief to a flat or spherical surface QAction* getGeometryReliefAction() { return geometryReliefAction; } /// called by geometry compress medial wall menu item QAction* getGeometryCompressMedialWallAction() { return geometryCompressMedialWallAction; } /// called by geometry compress front face menu item QAction* getGeometryCompressFrontFaceAction() { return geometryCompressFrontFaceAction; } /// called by geometry convert to sphere menu item QAction* getGeometryToSphereAction() { return geometryToSphereAction; } /// called by geometry convert to ellipsoid menu item QAction* getGeometryToEllipsoidAction() { return geometryToEllipsoidAction; } /// called by geometry convert ellipse to sphere menu item QAction* getGeometryEllipseToSphereAction() { return geometryEllipseToSphereAction; } /// called by geometry inflate menu item QAction* getGeometryInflateAction() { return geometryInflateAction; } /// called to expand surface along its normals QAction* getGeometryExpandAction() { return geometryExpandAction; } /// called by geometry inflate and smooth fingers menu item QAction* getGeometryInflateAndSmoothFingersAction() { return geometryInflateAndSmoothFingersAction; } /// called by geometry sphere to flat menu item QAction* getGeometrySphereToFlatAction() { return geometrySphereToFlatAction; } /// called by geometry sphere to flat through hole menu item QAction* getGeometrySphereToFlatThroughHoleAction() { return geometrySphereToFlatThroughHoleAction; } /// called by scale sphere to surface area of fiducial QAction* getGeometryScaleSphereToFiducialAreaAction() { return geometryScaleSphereToFiducialAreaAction; } /// called when geometry smoothing menu item is selected QAction* getGeometrySmoothingAction() { return geometrySmoothingAction; } /// called when generate inflated and ellipsoid from fiducial is selected QAction* getGeometryInflatedAndEllipsoidFromFiducialAction() { return geometryInflatedAndEllipsoidFromFiducialAction; } /// action to project to plane QAction* getProjectToPlaneAction() { return projectToPlaneAction; } /// called to add node QAction* getEditAddNodeAction() { return editAddNodeAction; } /// called to add tile QAction* getEditAddTileAction() { return editAddTileAction; } /// called to delete tile by link QAction* getEditDeleteTileByLinkAction() { return editDeleteTileByLinkAction; } /// called to disconnect node QAction* getEditDisconnectNodeAction() { return editDisconnectNodeAction; } /// called to move node QAction* getEditMoveNodeAction() { return editMoveNodeAction; } /// view adjust action QAction* getViewAdjustAction() { return viewAdjustAction; } /// view place node at center of screen action QAction* getViewPlaceNodeAtCenterOfScreenAction() { return viewPlaceNodeAtCenterOfScreenAction; } /// view scale surface to fit window action QAction* getViewScaleSurfaceToFitWindowAction() { return viewScaleSurfaceToFitWindowAction; } /// view save user action QAction* getViewUserSaveViewAction() { return viewUserSaveViewAction; } /// generate inflated and other surfaces from fiducial void generateInflatedAndOtherSurfaces(const BrainModelSurface* fiducialSurface, const bool enableEllipsoidFlag = true, const bool enableFingerSmoothingFlag = true, const bool checkInflatedFlag = true, const bool checkVeryInflatedFlag = true, const bool checkSphericalFlag = true, const bool checkCompMedWallFlag = true); public slots: /// update the actions (typically called when menu is about to show) void updateActions(); /// called when align surface(s) to standard orientation is selected void slotAlignSurfacesToStandardOrientation(); /// called to show create average coordinate file dialog void slotAverageCoordinateFile(); /// called to convert surface to a segmentation volume void slotSurfaceToSegmentationVolume(); /// called to interpolate surfaces void slotInterpolateSurfaces(); /// called to copy the surface in the main window void slotCopyMainWindowSurface(); /// called when show cuts is selected void slotCutsShow(); /// called when apply cuts is selected void slotCutsApply(); /// called when delete cuts with mouse is selected void slotCutsDeleteWithMouse(); /// called when delete all cuts is selected void slotCutsDeleteAll(); /// called when draw cuts is selected void slotCutsDraw(); /// called when run deformation dialog is selected void slotDeformationRunFlatDialog(); /// called when run deformation dialog is selected void slotDeformationRunSphericalDialog(); /// called when apply deformation dialog is selected void slotDeformationApplyDialog(); /// called when flatten hemisphere is selected void slotFlattenHemisphere(); /// called when crossover check is selected void slotMeasurementsCrossoverCheck(); /// called when curvature generation is selected void slotMeasurementsCurvature(); /// called when distortion generation is selected void slotMeasurementsDistortion(); /// called when sulcal depth generation is selected void slotMeasurementsSulcalDepth(); /// called when shape from coordinate subtraction is selected void slotMeasurementsShapeFromCoordinateSubtraction(); /// called to compute normals void slotNormalsGenerate(); /// called when flip normals menu items is selected void slotNormalsFlip(); /// slot for region of interest dialog void slotRegionOfInterest(); /// slot for region of interest dialog OLD void slotRegionOfInterestOLD(); /// called when surface information menu item is selected void slotSurfaceInformation(); /// called when spm transform selected void slotTransformSpm(); /// called to translate surface to center of mass void slotTransformCenterOfMass(); /// called to subtract AC from main window surface void slotTransformSubtractAC(); /// called to move disconnected nodes to the origin void slotTransformDisconnectedNodesToOrigin(); /// called to apply current view to the surface void slotTransformApplyCurrentView(); /// called to translate the surface by a user entered amount void slotTransformTranslate(); /// called to translate the surface by a user entered amount void slotTransformScale(); /// slot for multiresolution morphing flat void slotMultiresolutionMorphFlat(); /// slot for multiresolution morphing spherical void slotMultiresolutionMorphSphere(); /// slot for deleting corner tiles void slotTopologyDeleteCorners(); /// slot for topology check for islands void slotTopologyCheckForIslands(); /// slot for topology disconnect islands void slotTopologyDisconnectIslands(); /// called when classify edges is selected void slotTopologyClassifyEdges(); /// called when orient tiles consistently void slotTopologyOrientTilesConsistently(); /// replace topology with standard topology void slotTopologyReplaceWithStandardSurface(); /// called when retessellate sphere selected void slotTopologyRetessellateSphere(); /// called when correct fiducial selected void slotTopologyCorrectFiducial(); /// called when topology report selected void slotTopologyReport(); /// slot for identify menu item void slotIdentifyHighlightTile(); /// slot for identify menu item void slotIdentifyHighlightNode(); /// slot for identify menu item void slotIdentifyClearSymbols(); /// called when clear all or part of section file selected void slotSectionClearAllOrPart(); /// called to display resectioning dialog void slotSectionResection(); /// called when Nearest Spherical Border Distance is selected void slotGeometrySphereBorderDistance(); /// called to add relief to a flat or spherical surface void slotGeometryRelief(); /// called by geometry compress medial wall menu item void slotGeometryCompressMedialWall(); /// called by geometry compress front face menu item void slotGeometryCompressFrontFace(); /// called by geometry convert to sphere menu item void slotGeometryToSphere(); /// called by geometry convert to ellispoid menu item void slotGeometryToEllipsoid(); /// called by geometry convert ellipse to sphere menu item void slotGeometryEllipseToSphere(); /// called by geometry inflate menu item void slotGeometryInflate(); /// called to expand surface along its normals void slotGeometryExpand(); /// called by geometry inflate and smooth fingers menu item void slotGeometryInflateAndSmoothFingers(); /// called by geometry sphere to flat menu item void slotGeometrySphereToFlat(); /// called by geometry sphere to flat through hole menu item void slotGeometrySphereToFlatThroughHole(); /// called by scale sphere to surface area of fiducial void slotGeometryScaleSphereToFiducialArea(); /// called when geometry smoothing menu item is selected void slotGeometrySmoothing(); /// called when generate inflated and ellipsoid from fiducial is selected void slotGeometryInflatedAndEllipsoidFromFiducial(); /// called when project to plane selected void slotProjectToPlane(); /// called to add node void slotEditAddNode(); /// called to add tile void slotEditAddTile(); /// called to delete tile by link void slotEditDeleteTileByLink(); /// called to disconnect node void slotEditDisconnectNode(); /// called to move node void slotEditMoveNode(); /// slot called to save a user view void slotUserViewSaveView(); /// slot to switch to a user view void slotUserViewSwitchToView(int item); /// slot called when adjust view selected void slotViewAdjust(); /// slot called to orient surface so node placed at screen center void slotViewPlaceNodeAtCenterOfScreen(); /// slot called to scale the surface to fit the window void slotViewScaleSurfaceToFitWindow(); /// slot called to simplify the surface void slotSimplifySurface(); protected slots: /// Called when apply button hit on scale dialog void slotTransformScaleApply(); /// Called when apply button hit on translate dialog void slotTransformTranslateApply(); protected: /// apply a matrix to the main window surface void applyMatrixToMainWindowSurface(TransformationMatrix& tm); /// translate dialog QtMultipleInputDialog* translateDialog; /// scale dialog QtMultipleInputDialog* scaleDialog; /// the flat morphing dialog GuiMorphingDialog* flatMorphDialog; /// the sphere morphing dialog GuiMorphingDialog* sphereMorphDialog; /// the flat surface multiresolution morphing object BrainModelSurfaceMultiresolutionMorphing* flatMultiResMorphObject; /// the spherical surface multiresolution morphing object BrainModelSurfaceMultiresolutionMorphing* sphericalMultiResMorphObject; /// action when align surface(s) to standard orientation is selected QAction* alignSurfacesToStandardOrientationAction; /// action to show create average coordinate file dialog QAction* averageCoordinateFileAction; /// action for automatic rotation QAction* automaticRotationAction; /// action for simplify surface QAction* simplifySurfaceAction; /// action to interpolate surfaces QAction* interpolateSurfacesAction; /// action to copy the surface in the main window QAction* copyMainWindowSurfaceAction; /// action when show cuts is selected QAction* cutsShowAction; /// action when apply cuts is selected QAction* cutsApplyAction; /// action when delete cuts with mouse is selected QAction* cutsDeleteWithMouseAction; /// action when delete all cuts is selected QAction* cutsDeleteAllAction; /// action when draw cuts is selected QAction* cutsDrawAction; /// action when run deformation dialog is selected QAction* deformationRunFlatDialogAction; /// action when run deformation dialog is selected QAction* deformationRunSphericalDialogAction; /// action when apply deformation dialog is selected QAction* deformationApplyDialogAction; /// action when standard mesh dialog is selected QAction* standardMeshDialogAction; /// action when flatten hemisphere is selected QAction* flattenHemisphereAction; /// action when flatten full hemisphere is selected QAction* flattenFullHemisphereAction; /// action when crossover check is selected QAction* measurementsCrossoverCheckAction; /// action when curvature generation is selected QAction* measurementsCurvatureAction; /// action when distortion generation is selected QAction* measurementsDistortionAction; /// action when sulcal depth generation is selected QAction* measurementsSulcalDepthAction; /// action when shape from coordinate subtraction is selected QAction* measurementsShapeFromCoordinateSubtraction; /// action to compute normals QAction* normalsGenerateAction; /// action when flip normals menu items is selected QAction* normalsFlipAction; /// action for region of interest dialog QAction* regionOfInterestAction; /// action for region of interest dialog OLD QAction* regionOfInterestActionOLD; /// action when surface information menu item is selected QAction* surfaceInformationAction; /// action when spm transform selected QAction* transformSpmAction; /// action to translate surface to center of mass QAction* transformCenterOfMassAction; /// action to subtract AC from main window surface QAction* transformSubtractACAction; /// action to move disconnected nodes to the origin QAction* transformDisconnectedNodesToOriginAction; /// action to apply current view to the surface QAction* transformApplyCurrentViewAction; /// action to translate the surface by a user entered amount QAction* transformTranslateAction; /// action to translate the surface by a user entered amount QAction* transformScaleAction; /// morph flat action QAction* morphFlatAction; /// morph sphere action QAction* morphSphereAction; /// action for multiresolution morphing flat QAction* multiresolutionMorphFlatAction; /// action for multiresolution morphing spherical QAction* multiresolutionMorphSphereAction; /// action for deleting corner tiles QAction* topologyDeleteCornersAction; /// action for topology set topology menu QAction* topologySetAction; /// action for topology check for islands QAction* topologyCheckForIslandsAction; /// action for topology disconnect islands QAction* topologyDisconnectIslandsAction; /// action when classify edges is selected QAction* topologyClassifyEdgesAction; /// action when orient tiles consistently QAction* topologyOrientTilesConsistentlyAction; /// replace topology with standard topology QAction* topologyReplaceWithStandardSurfaceAction; /// action when retessellate sphere selected QAction* topologyRetessellateSphereAction; /// action when correct fiducial selected QAction* topologyCorrectFiducialAction; /// action when topology report selected QAction* topologyReportAction; /// action for identify menu item QAction* identifyHighlightTileAction; /// action for identify menu item QAction* identifyHighlightNodeAction; /// action for identify menu item QAction* identifyClearSymbolsAction; /// action for section control dialog QAction* sectionControlAction; /// action when clear all or part of section file selected QAction* sectionClearAllOrPartAction; /// action to display resectioning dialog QAction* sectionResectionAction; /// action when Nearest Spherical Border Distance is selected QAction* geometrySphereBorderDistanceAction; /// action to add relief to a flat or spherical surface QAction* geometryReliefAction; /// action by geometry compress medial wall menu item QAction* geometryCompressMedialWallAction; /// action by geometry compress front face menu item QAction* geometryCompressFrontFaceAction; /// action by geometry convert to sphere menu item QAction* geometryToSphereAction; /// action by geometry convert to ellipsoid menu item QAction* geometryToEllipsoidAction; /// action by geometry convert ellipse to sphere menu item QAction* geometryEllipseToSphereAction; /// action by geometry inflate menu item QAction* geometryInflateAction; /// action to expand surface along its normals QAction* geometryExpandAction; /// action by geometry inflate and smooth fingers menu item QAction* geometryInflateAndSmoothFingersAction; /// action by geometry sphere to flat menu item QAction* geometrySphereToFlatAction; /// action by geometry sphere to flat through hole menu item QAction* geometrySphereToFlatThroughHoleAction; /// action by scale sphere to surface area of fiducial QAction* geometryScaleSphereToFiducialAreaAction; /// action when geometry smoothing menu item is selected QAction* geometrySmoothingAction; /// action when generate inflated and ellipsoid from fiducial is selected QAction* geometryInflatedAndEllipsoidFromFiducialAction; /// action to project to plane QAction* projectToPlaneAction; /// action to add node QAction* editAddNodeAction; /// action to add tile QAction* editAddTileAction; /// action to delete tile by link QAction* editDeleteTileByLinkAction; /// action to disconnect node QAction* editDisconnectNodeAction; /// action to move node QAction* editMoveNodeAction; /// view adjust action QAction* viewAdjustAction; /// view place node at center of screen action QAction* viewPlaceNodeAtCenterOfScreenAction; /// view scale surface to fit window action QAction* viewScaleSurfaceToFitWindowAction; /// view save user action QAction* viewUserSaveViewAction; /// convert surface to segmentation volume QAction* surfaceToSegmentationVolumeAction; }; #endif // __GUI_MAIN_WINDOW_SURFACE_ACTIONS_H__ caret-5.6.4~dfsg.1.orig/caret/GuiMainWindowSurfaceActions.cxx0000664000175000017500000030441411572067322023764 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include "BorderFile.h" #include "BrainModelBorderSet.h" #include "BrainModelIdentification.h" #include "BrainModelStandardSurfaceReplacement.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceDeformationMeasurement.h" #include "BrainModelSurfaceFlatHexagonalSubsample.h" #include "BrainModelSurfaceMultiresolutionMorphing.h" #include "BrainModelSurfaceNodeColoring.h" #include "BrainModelSurfaceCutter.h" #include "BrainModelSurfaceDeformationMeasurement.h" #include "BrainModelSurfaceSphericalTessellator.h" #include "BrainModelSurfaceToVolumeConverter.h" #include "BrainModelSurfaceTopologyCorrector.h" #include "BrainSet.h" #include "CellProjectionFile.h" #include "CutsFile.h" #include "DebugControl.h" #include "DisplaySettingsCuts.h" #include "DisplaySettingsSurface.h" #include "FociProjectionFile.h" #include "GuiAlignSurfaceToStandardOrientationDialog.h" #include "GuiApplyDeformationMapDialog.h" #include "GuiAverageCoordinateDialog.h" #include "GuiBrainModelOpenGL.h" #include "GuiDistortionDialog.h" #include "GuiFilesModified.h" #include "GuiFlattenFullHemisphereDialog.h" #include "GuiFlattenHemisphereDialog.h" #include "GuiGenerateSulcalDepthDialog.h" #include "GuiGenerateSurfaceCurvatureDialog.h" #include "GuiIdentifyDialog.h" #include "GuiInflateAndSmoothFingersDialog.h" #include "GuiInflateSurfaceDialog.h" #include "GuiInterpolateSurfacesDialog.h" #include "GuiMainWindow.h" #include "GuiMainWindowSurfaceActions.h" #include "GuiMainWindowSurfaceMenu.h" #include "GuiMorphingDialog.h" #include "GuiMultiresolutionMorphingDialog.h" #include "GuiNodeAttributeFileClearResetDialog.h" #include "GuiPaintColumnNamesListBoxSelectionDialog.h" #include "GuiResectionDialog.h" #include "GuiSetTopologyDialog.h" #include "GuiSetViewDialog.h" #include "GuiShapeOrVectorsFromCoordinateSubtractionDialog.h" #include "GuiSurfaceInformationDialog.h" #include "GuiSurfaceDeformationDialog.h" #include "GuiSurfaceSpmTransformDialog.h" #include "GuiSurfaceToVolumeDialog.h" #include "GuiSurfaceTopologyReportDialog.h" #include "GuiUserViewSaveDialog.h" #include "MetricFile.h" #include "PaintFile.h" #include "ParamsFile.h" #include "QtMultipleInputDialog.h" #include "QtRadioButtonSelectionDialog.h" #include "SectionFile.h" #include "StringUtilities.h" #include "TopologyHelper.h" #include "TransformationMatrixFile.h" #include "WuQDataEntryDialog.h" #include "global_variables.h" /** * Constructor. */ GuiMainWindowSurfaceActions::GuiMainWindowSurfaceActions(GuiMainWindow* parent) : QObject(parent) { setObjectName("GuiMainWindowSurfaceActions"); flatMultiResMorphObject = new BrainModelSurfaceMultiresolutionMorphing(NULL, NULL, NULL, BrainModelSurfaceMorphing::MORPHING_SURFACE_FLAT); sphericalMultiResMorphObject = new BrainModelSurfaceMultiresolutionMorphing(NULL, NULL, NULL, BrainModelSurfaceMorphing::MORPHING_SURFACE_SPHERICAL); flatMorphDialog = NULL; sphereMorphDialog = NULL; scaleDialog = NULL; translateDialog = NULL; alignSurfacesToStandardOrientationAction = new QAction(parent); alignSurfacesToStandardOrientationAction->setObjectName("alignSurfacesToStandardOrientationAction"); alignSurfacesToStandardOrientationAction->setText("Align Surface(s) to Standard Orientation..."); QObject::connect(alignSurfacesToStandardOrientationAction, SIGNAL(triggered(bool)), this, SLOT(slotAlignSurfacesToStandardOrientation())); averageCoordinateFileAction = new QAction(parent); averageCoordinateFileAction->setObjectName("averageCoordinateFileAction"); averageCoordinateFileAction->setText("Create Average Coordinate File..."); QObject::connect(averageCoordinateFileAction, SIGNAL(triggered(bool)), this, SLOT(slotAverageCoordinateFile())); automaticRotationAction = new QAction(parent); automaticRotationAction->setObjectName("automaticRotationAction"); automaticRotationAction->setText("Automatic Rotation..."); QObject::connect(automaticRotationAction, SIGNAL(triggered(bool)), parent, SLOT(displayAutomaticRotationDialog())); interpolateSurfacesAction = new QAction(parent); interpolateSurfacesAction->setObjectName("interpolateSurfacesAction"); interpolateSurfacesAction->setText("Interpolate Surfaces..."); QObject::connect(interpolateSurfacesAction, SIGNAL(triggered(bool)), this, SLOT(slotInterpolateSurfaces())); copyMainWindowSurfaceAction = new QAction(parent); copyMainWindowSurfaceAction->setObjectName("copyMainWindowSurfaceAction"); copyMainWindowSurfaceAction->setText("Copy Main Window Surface to New Surface"); QObject::connect(copyMainWindowSurfaceAction, SIGNAL(triggered(bool)), this, SLOT(slotCopyMainWindowSurface())); simplifySurfaceAction = new QAction(parent); simplifySurfaceAction->setObjectName("simplifySurfaceAction"); simplifySurfaceAction->setText("Simplify Surface (Fewer Polygons)..."); QObject::connect(simplifySurfaceAction, SIGNAL(triggered(bool)), this, SLOT(slotSimplifySurface())); cutsShowAction = new QAction(parent); cutsShowAction->setObjectName("cutsShowAction"); cutsShowAction->setText("Show Cuts"); QObject::connect(cutsShowAction, SIGNAL(triggered(bool)), this, SLOT(slotCutsShow())); cutsApplyAction = new QAction(parent); cutsApplyAction->setObjectName("cutsApplyAction"); cutsApplyAction->setText("Apply All Cuts"); QObject::connect(cutsApplyAction, SIGNAL(triggered(bool)), this, SLOT(slotCutsApply())); cutsDeleteWithMouseAction = new QAction(parent); cutsDeleteWithMouseAction->setObjectName("cutsDeleteWithMouseAction"); cutsDeleteWithMouseAction->setText("Delete Cut With Mouse"); QObject::connect(cutsDeleteWithMouseAction, SIGNAL(triggered(bool)), this, SLOT(slotCutsDeleteWithMouse())); cutsDeleteAllAction = new QAction(parent); cutsDeleteAllAction->setObjectName("cutsDeleteAllAction"); cutsDeleteAllAction->setText("Delete All Cuts"); QObject::connect(cutsDeleteAllAction, SIGNAL(triggered(bool)), this, SLOT(slotCutsDeleteAll())); cutsDrawAction = new QAction(parent); cutsDrawAction->setObjectName("cutsDrawAction"); cutsDrawAction->setText("Draw Cuts"); QObject::connect(cutsDrawAction, SIGNAL(triggered(bool)), this, SLOT(slotCutsDraw())); deformationRunFlatDialogAction = new QAction(parent); deformationRunFlatDialogAction->setObjectName("deformationRunFlatDialogAction"); deformationRunFlatDialogAction->setText("Run Flat Surface Deformation..."); QObject::connect(deformationRunFlatDialogAction, SIGNAL(triggered(bool)), this, SLOT(slotDeformationRunFlatDialog())); deformationRunSphericalDialogAction = new QAction(parent); deformationRunSphericalDialogAction->setObjectName("deformationRunSphericalDialogAction"); deformationRunSphericalDialogAction->setText("Run Spherical Surface Deformation..."); QObject::connect(deformationRunSphericalDialogAction, SIGNAL(triggered(bool)), this, SLOT(slotDeformationRunSphericalDialog())); deformationApplyDialogAction = new QAction(parent); deformationApplyDialogAction->setObjectName("deformationApplyDialogAction"); deformationApplyDialogAction->setText("Apply Deformation Map..."); QObject::connect(deformationApplyDialogAction, SIGNAL(triggered(bool)), this, SLOT(slotDeformationApplyDialog())); standardMeshDialogAction = new QAction(parent); standardMeshDialogAction->setObjectName("standardMeshDialogAction"); standardMeshDialogAction->setText("Convert to Standard Mesh (In Developement!)..."); QObject::connect(standardMeshDialogAction, SIGNAL(triggered(bool)), parent, SLOT(displayStandardMeshDialog())); flattenHemisphereAction = new QAction(parent); flattenHemisphereAction->setObjectName("flattenHemisphereAction"); flattenHemisphereAction->setText("Flatten Full or Partial Hemisphere..."); QObject::connect(flattenHemisphereAction, SIGNAL(triggered(bool)), this, SLOT(slotFlattenHemisphere())); flattenFullHemisphereAction = new QAction(parent); flattenFullHemisphereAction->setObjectName("flattenFullHemisphereAction"); flattenFullHemisphereAction->setText("Flatten Full Hemisphere (In Development)..."); QObject::connect(flattenFullHemisphereAction, SIGNAL(triggered(bool)), parent, SLOT(displayFlattenFullHemisphereDialog())); measurementsCrossoverCheckAction = new QAction(parent); measurementsCrossoverCheckAction->setObjectName("measurementsCrossoverCheckAction"); measurementsCrossoverCheckAction->setText("Crossover Check"); QObject::connect(measurementsCrossoverCheckAction, SIGNAL(triggered(bool)), this, SLOT(slotMeasurementsCrossoverCheck())); measurementsCurvatureAction = new QAction(parent); measurementsCurvatureAction->setObjectName("measurementsCurvatureAction"); measurementsCurvatureAction->setText("Generate Curvature..."); QObject::connect(measurementsCurvatureAction, SIGNAL(triggered(bool)), this, SLOT(slotMeasurementsCurvature())); measurementsDistortionAction = new QAction(parent); measurementsDistortionAction->setObjectName("measurementsDistortionAction"); measurementsDistortionAction->setText("Generate Distortion..."); QObject::connect(measurementsDistortionAction, SIGNAL(triggered(bool)), this, SLOT(slotMeasurementsDistortion())); measurementsSulcalDepthAction = new QAction(parent); measurementsSulcalDepthAction->setObjectName("measurementsSulcalDepthAction"); measurementsSulcalDepthAction->setText("Generate Sulcal Depth..."); QObject::connect(measurementsSulcalDepthAction, SIGNAL(triggered(bool)), this, SLOT(slotMeasurementsSulcalDepth())); measurementsShapeFromCoordinateSubtraction = new QAction(parent); measurementsShapeFromCoordinateSubtraction->setObjectName("measurementsShapeFromCoordinateSubtraction"); measurementsShapeFromCoordinateSubtraction->setText("Generate Distance: Surface A to Surface B..."); QObject::connect(measurementsShapeFromCoordinateSubtraction, SIGNAL(triggered(bool)), this, SLOT(slotMeasurementsShapeFromCoordinateSubtraction())); normalsGenerateAction = new QAction(parent); normalsGenerateAction->setObjectName("normalsGenerateAction"); normalsGenerateAction->setText("Generate Normals"); QObject::connect(normalsGenerateAction, SIGNAL(triggered(bool)), this, SLOT(slotNormalsGenerate())); normalsFlipAction = new QAction(parent); normalsFlipAction->setObjectName("normalsFlipAction"); normalsFlipAction->setText("Flip Normals"); QObject::connect(normalsFlipAction, SIGNAL(triggered(bool)), this, SLOT(slotNormalsFlip())); regionOfInterestAction = new QAction(parent); regionOfInterestAction->setObjectName("regionOfInterestAction"); regionOfInterestAction->setText("Region Of Interest Operations..."); QObject::connect(regionOfInterestAction, SIGNAL(triggered(bool)), this, SLOT(slotRegionOfInterest())); regionOfInterestActionOLD = new QAction(parent); regionOfInterestActionOLD->setObjectName("regionOfInterestAction"); regionOfInterestActionOLD->setText("Region Of Interest Operations (OLD)..."); QObject::connect(regionOfInterestActionOLD, SIGNAL(triggered(bool)), this, SLOT(slotRegionOfInterestOLD())); surfaceInformationAction = new QAction(parent); surfaceInformationAction->setObjectName("surfaceInformationAction"); surfaceInformationAction->setText("Information..."); QObject::connect(surfaceInformationAction, SIGNAL(triggered(bool)), this, SLOT(slotSurfaceInformation())); transformSpmAction = new QAction(parent); transformSpmAction->setObjectName("transformSpmAction"); transformSpmAction->setText("Apply SPM Inverse Transform..."); QObject::connect(transformSpmAction, SIGNAL(triggered(bool)), this, SLOT(slotTransformSpm())); transformCenterOfMassAction = new QAction(parent); transformCenterOfMassAction->setObjectName("transformCenterOfMassAction"); transformCenterOfMassAction->setText("Translate to Center of Mass"); QObject::connect(transformCenterOfMassAction, SIGNAL(triggered(bool)), this, SLOT(slotTransformCenterOfMass())); transformSubtractACAction = new QAction(parent); transformSubtractACAction->setObjectName("transformSubtractACAction"); transformSubtractACAction->setText("Translate - Subtract Params File AC"); QObject::connect(transformSubtractACAction, SIGNAL(triggered(bool)), this, SLOT(slotTransformSubtractAC())); transformDisconnectedNodesToOriginAction = new QAction(parent); transformDisconnectedNodesToOriginAction->setObjectName("transformDisconnectedNodesToOriginAction"); transformDisconnectedNodesToOriginAction->setText("Move Disconnected Nodes to Origin"); QObject::connect(transformDisconnectedNodesToOriginAction, SIGNAL(triggered(bool)), this, SLOT(slotTransformDisconnectedNodesToOrigin())); transformApplyCurrentViewAction = new QAction(parent); transformApplyCurrentViewAction->setObjectName("transformApplyCurrentViewAction"); transformApplyCurrentViewAction->setText("Apply Current View..."); QObject::connect(transformApplyCurrentViewAction, SIGNAL(triggered(bool)), this, SLOT(slotTransformApplyCurrentView())); transformTranslateAction = new QAction(parent); transformTranslateAction->setObjectName("transformTranslateAction"); transformTranslateAction->setText("Translate..."); QObject::connect(transformTranslateAction, SIGNAL(triggered(bool)), this, SLOT(slotTransformTranslate())); transformScaleAction = new QAction(parent); transformScaleAction->setObjectName("transformScaleAction"); transformScaleAction->setText("Scale..."); QObject::connect(transformScaleAction, SIGNAL(triggered(bool)), this, SLOT(slotTransformScale())); morphFlatAction = new QAction(parent); morphFlatAction->setObjectName("morphFlatAction"); morphFlatAction->setText("Morph Flat Surface..."); QObject::connect(morphFlatAction, SIGNAL(triggered(bool)), parent, SLOT(showFlatMorphingDialog())); morphSphereAction = new QAction(parent); morphSphereAction->setObjectName("morphSphereAction"); morphSphereAction->setText("Morph Spherical Surface..."); QObject::connect(morphSphereAction, SIGNAL(triggered(bool)), parent, SLOT(showSphereMorphingDialog())); multiresolutionMorphFlatAction = new QAction(parent); multiresolutionMorphFlatAction->setObjectName("multiresolutionMorphFlatAction"); multiresolutionMorphFlatAction->setText("Multiresolution Morphing Flat Surface..."); QObject::connect(multiresolutionMorphFlatAction, SIGNAL(triggered(bool)), this, SLOT(slotMultiresolutionMorphFlat())); multiresolutionMorphSphereAction = new QAction(parent); multiresolutionMorphSphereAction->setObjectName("multiresolutionMorphSphereAction"); multiresolutionMorphSphereAction->setText("Multiresolution Morphing Spherical Surface..."); QObject::connect(multiresolutionMorphSphereAction, SIGNAL(triggered(bool)), this, SLOT(slotMultiresolutionMorphSphere())); topologyDeleteCornersAction = new QAction(parent); topologyDeleteCornersAction->setObjectName("topologyDeleteCornersAction"); topologyDeleteCornersAction->setText("Remove Corner and Straggler Tiles..."); QObject::connect(topologyDeleteCornersAction, SIGNAL(triggered(bool)), this, SLOT(slotTopologyDeleteCorners())); topologySetAction = new QAction(parent); topologySetAction->setObjectName("topologySetAction"); topologySetAction->setText("Set Topology Assigned to Surfaces..."); QObject::connect(topologySetAction, SIGNAL(triggered(bool)), parent, SLOT(displaySetTopologyDialog())); topologyCheckForIslandsAction = new QAction(parent); topologyCheckForIslandsAction->setObjectName("topologyCheckForIslandsAction"); topologyCheckForIslandsAction->setText("Check For Islands"); QObject::connect(topologyCheckForIslandsAction, SIGNAL(triggered(bool)), this, SLOT(slotTopologyCheckForIslands())); topologyDisconnectIslandsAction = new QAction(parent); topologyDisconnectIslandsAction->setObjectName("topologyDisconnectIslandsAction"); topologyDisconnectIslandsAction->setText("Remove Islands"); QObject::connect(topologyDisconnectIslandsAction, SIGNAL(triggered(bool)), this, SLOT(slotTopologyDisconnectIslands())); topologyClassifyEdgesAction = new QAction(parent); topologyClassifyEdgesAction->setObjectName("topologyClassifyEdgesAction"); topologyClassifyEdgesAction->setText("Classify Nodes"); QObject::connect(topologyClassifyEdgesAction, SIGNAL(triggered(bool)), this, SLOT(slotTopologyClassifyEdges())); topologyOrientTilesConsistentlyAction = new QAction(parent); topologyOrientTilesConsistentlyAction->setObjectName("topologyOrientTilesConsistentlyAction"); topologyOrientTilesConsistentlyAction->setText("Orient Tiles Consistently"); QObject::connect(topologyOrientTilesConsistentlyAction, SIGNAL(triggered(bool)), this, SLOT(slotTopologyOrientTilesConsistently())); topologyReplaceWithStandardSurfaceAction = new QAction(parent); topologyReplaceWithStandardSurfaceAction->setObjectName("topologyReplaceWithStandardSurfaceAction"); topologyReplaceWithStandardSurfaceAction->setText("Replace Surfaces With Standard Surface"); QObject::connect(topologyReplaceWithStandardSurfaceAction, SIGNAL(triggered(bool)), this, SLOT(slotTopologyReplaceWithStandardSurface())); topologyCorrectFiducialAction = new QAction(parent); topologyCorrectFiducialAction->setObjectName("topologyCorrectFiducialAction"); topologyCorrectFiducialAction->setText("Correct Fiducial Surface Topology (Remove Handles)"); QObject::connect(topologyCorrectFiducialAction, SIGNAL(triggered(bool)), this, SLOT(slotTopologyCorrectFiducial())); topologyRetessellateSphereAction = new QAction(parent); topologyRetessellateSphereAction->setObjectName("topologyRetessellateSphereAction"); topologyRetessellateSphereAction->setText("Retessellate Sphere"); QObject::connect(topologyRetessellateSphereAction, SIGNAL(triggered(bool)), this, SLOT(slotTopologyRetessellateSphere())); topologyReportAction = new QAction(parent); topologyReportAction->setObjectName("topologyReportAction"); topologyReportAction->setText("Topology Error Report..."); QObject::connect(topologyReportAction, SIGNAL(triggered(bool)), this, SLOT(slotTopologyReport())); identifyHighlightTileAction = new QAction(parent); identifyHighlightTileAction->setObjectName("identifyHighlightTileAction"); identifyHighlightTileAction->setText("Identify Tile By Number..."); QObject::connect(identifyHighlightTileAction, SIGNAL(triggered(bool)), this, SLOT(slotIdentifyHighlightTile())); identifyHighlightNodeAction = new QAction(parent); identifyHighlightNodeAction->setObjectName("identifyHighlightNodeAction"); identifyHighlightNodeAction->setText("Identify Node By Number..."); QObject::connect(identifyHighlightNodeAction, SIGNAL(triggered(bool)), this, SLOT(slotIdentifyHighlightNode())); identifyClearSymbolsAction = new QAction(parent); identifyClearSymbolsAction->setObjectName("identifyClearSymbolsAction"); identifyClearSymbolsAction->setText("Clear Node Identify Symbols"); QObject::connect(identifyClearSymbolsAction, SIGNAL(triggered(bool)), this, SLOT(slotIdentifyClearSymbols())); sectionControlAction = new QAction(parent); sectionControlAction->setObjectName("sectionControlAction"); sectionControlAction->setText("Section Control..."); QObject::connect(sectionControlAction, SIGNAL(triggered(bool)), parent, SLOT(displaySectionControlDialog())); sectionClearAllOrPartAction = new QAction(parent); sectionClearAllOrPartAction->setObjectName("sectionClearAllOrPartAction"); sectionClearAllOrPartAction->setText("Clear All or Part of Section File..."); QObject::connect(sectionClearAllOrPartAction, SIGNAL(triggered(bool)), this, SLOT(slotSectionClearAllOrPart())); sectionResectionAction = new QAction(parent); sectionResectionAction->setObjectName("sectionResectionAction"); sectionResectionAction->setText("Resection..."); QObject::connect(sectionResectionAction, SIGNAL(triggered(bool)), this, SLOT(slotSectionResection())); geometrySphereBorderDistanceAction = new QAction(parent); geometrySphereBorderDistanceAction->setObjectName("geometrySphereBorderDistanceAction"); geometrySphereBorderDistanceAction->setText("Nearest Spherical Border Distance"); QObject::connect(geometrySphereBorderDistanceAction, SIGNAL(triggered(bool)), this, SLOT(slotGeometrySphereBorderDistance())); geometryReliefAction = new QAction(parent); geometryReliefAction->setObjectName("geometryReliefAction"); geometryReliefAction->setText("Add Relief to Sphere/Flat"); QObject::connect(geometryReliefAction, SIGNAL(triggered(bool)), this, SLOT(slotGeometryRelief())); geometryCompressMedialWallAction = new QAction(parent); geometryCompressMedialWallAction->setObjectName("geometryCompressMedialWallAction"); geometryCompressMedialWallAction->setText("Compress Sphere Medial Wall..."); QObject::connect(geometryCompressMedialWallAction, SIGNAL(triggered(bool)), this, SLOT(slotGeometryCompressMedialWall())); geometryCompressFrontFaceAction = new QAction(parent); geometryCompressFrontFaceAction->setObjectName("geometryCompressFrontFaceAction"); geometryCompressFrontFaceAction->setText("Compress Front Face..."); QObject::connect(geometryCompressFrontFaceAction, SIGNAL(triggered(bool)), this, SLOT(slotGeometryCompressFrontFace())); geometryToSphereAction = new QAction(parent); geometryToSphereAction->setObjectName("geometryToSphereAction"); geometryToSphereAction->setText("Convert to Sphere"); QObject::connect(geometryToSphereAction, SIGNAL(triggered(bool)), this, SLOT(slotGeometryToSphere())); geometryToEllipsoidAction = new QAction(parent); geometryToEllipsoidAction->setObjectName("geometryToEllipsoidAction"); geometryToEllipsoidAction->setText("Convert to Ellipsoid"); QObject::connect(geometryToEllipsoidAction, SIGNAL(triggered(bool)), this, SLOT(slotGeometryToEllipsoid())); geometryEllipseToSphereAction = new QAction(parent); geometryEllipseToSphereAction->setObjectName("geometryEllipseToSphereAction"); geometryEllipseToSphereAction->setText("Convert Ellipsoid to Sphere"); QObject::connect(geometryEllipseToSphereAction, SIGNAL(triggered(bool)), this, SLOT(slotGeometryEllipseToSphere())); geometryInflateAction = new QAction(parent); geometryInflateAction->setObjectName("geometryInflateAction"); geometryInflateAction->setText("Inflate Surface..."); QObject::connect(geometryInflateAction, SIGNAL(triggered(bool)), this, SLOT(slotGeometryInflate())); geometryExpandAction = new QAction(parent); geometryExpandAction->setObjectName("geometryExpandAction"); geometryExpandAction->setText("Expand or Shrink Surface..."); QObject::connect(geometryExpandAction, SIGNAL(triggered(bool)), this, SLOT(slotGeometryExpand())); geometryInflateAndSmoothFingersAction = new QAction(parent); geometryInflateAndSmoothFingersAction->setObjectName("geometryInflateAndSmoothFingersAction"); geometryInflateAndSmoothFingersAction->setText("Inflate Surface And Smooth Fingers..."); QObject::connect(geometryInflateAndSmoothFingersAction, SIGNAL(triggered(bool)), this, SLOT(slotGeometryInflateAndSmoothFingers())); geometrySphereToFlatAction = new QAction(parent); geometrySphereToFlatAction->setObjectName("geometrySphereToFlatAction"); geometrySphereToFlatAction->setText("Project Sphere to Flat"); QObject::connect(geometrySphereToFlatAction, SIGNAL(triggered(bool)), this, SLOT(slotGeometrySphereToFlat())); geometrySphereToFlatThroughHoleAction = new QAction(parent); geometrySphereToFlatThroughHoleAction->setObjectName("geometrySphereToFlatThroughHoleAction"); geometrySphereToFlatThroughHoleAction->setText("Project Sphere to Flat Through Hole..."); QObject::connect(geometrySphereToFlatThroughHoleAction, SIGNAL(triggered(bool)), this, SLOT(slotGeometrySphereToFlatThroughHole())); geometryScaleSphereToFiducialAreaAction = new QAction(parent); geometryScaleSphereToFiducialAreaAction->setObjectName("geometryScaleSphereToFiducialAreaAction"); geometryScaleSphereToFiducialAreaAction->setText("Scale Sphere to Fiducial Surface Area"); QObject::connect(geometryScaleSphereToFiducialAreaAction, SIGNAL(triggered(bool)), this, SLOT(slotGeometryScaleSphereToFiducialArea())); geometrySmoothingAction = new QAction(parent); geometrySmoothingAction->setObjectName("geometrySmoothingAction"); geometrySmoothingAction->setText("Smoothing..."); QObject::connect(geometrySmoothingAction, SIGNAL(triggered(bool)), this, SLOT(slotGeometrySmoothing())); geometryInflatedAndEllipsoidFromFiducialAction = new QAction(parent); geometryInflatedAndEllipsoidFromFiducialAction->setObjectName("geometryInflatedAndEllipsoidFromFiducialAction"); geometryInflatedAndEllipsoidFromFiducialAction->setText("Generate Inflated and Ellipsoid From Fiducial..."); QObject::connect(geometryInflatedAndEllipsoidFromFiducialAction, SIGNAL(triggered(bool)), this, SLOT(slotGeometryInflatedAndEllipsoidFromFiducial())); projectToPlaneAction = new QAction(parent); projectToPlaneAction->setObjectName("projectToPlaneAction"); projectToPlaneAction->setText("Project to Plane..."); QObject::connect(projectToPlaneAction, SIGNAL(triggered(bool)), this, SLOT(slotProjectToPlane())); editAddNodeAction = new QAction(parent); editAddNodeAction->setObjectName("editAddNodeAction"); editAddNodeAction->setText("Add Node"); QObject::connect(editAddNodeAction, SIGNAL(triggered(bool)), this, SLOT(slotEditAddNode())); editAddTileAction = new QAction(parent); editAddTileAction->setObjectName("editAddTileAction"); editAddTileAction->setText("Add Tile"); QObject::connect(editAddTileAction, SIGNAL(triggered(bool)), this, SLOT(slotEditAddTile())); editDeleteTileByLinkAction = new QAction(parent); editDeleteTileByLinkAction->setObjectName("editDeleteTileByLinkAction"); editDeleteTileByLinkAction->setText("Delete Link"); QObject::connect(editDeleteTileByLinkAction, SIGNAL(triggered(bool)), this, SLOT(slotEditDeleteTileByLink())); editDisconnectNodeAction = new QAction(parent); editDisconnectNodeAction->setObjectName("editDisconnectNodeAction"); editDisconnectNodeAction->setText("Disconnect Node"); QObject::connect(editDisconnectNodeAction, SIGNAL(triggered(bool)), this, SLOT(slotEditDisconnectNode())); editMoveNodeAction = new QAction(parent); editMoveNodeAction->setObjectName("editMoveNodeAction"); editMoveNodeAction->setText("Move Node"); QObject::connect(editMoveNodeAction, SIGNAL(triggered(bool)), this, SLOT(slotEditMoveNode())); viewAdjustAction = new QAction(parent); viewAdjustAction->setObjectName("viewAdjustAction"); viewAdjustAction->setText("Adjust View..."); QObject::connect(viewAdjustAction, SIGNAL(triggered(bool)), this, SLOT(slotViewAdjust())); viewPlaceNodeAtCenterOfScreenAction = new QAction(parent); viewPlaceNodeAtCenterOfScreenAction->setObjectName("viewPlaceNodeAtCenterOfScreenAction"); viewPlaceNodeAtCenterOfScreenAction->setText("Place Node at Center of Screen..."); QObject::connect(viewPlaceNodeAtCenterOfScreenAction, SIGNAL(triggered(bool)), this, SLOT(slotViewPlaceNodeAtCenterOfScreen())); viewScaleSurfaceToFitWindowAction = new QAction(parent); viewScaleSurfaceToFitWindowAction->setObjectName("viewScaleSurfaceToFitWindowAction"); viewScaleSurfaceToFitWindowAction->setText("Scale Surface to Fit Window"); QObject::connect(viewScaleSurfaceToFitWindowAction, SIGNAL(triggered(bool)), this, SLOT(slotViewScaleSurfaceToFitWindow())); viewUserSaveViewAction = new QAction(parent); viewUserSaveViewAction->setObjectName("viewUserSaveViewAction"); viewUserSaveViewAction->setText("Save User View..."); QObject::connect(viewUserSaveViewAction, SIGNAL(triggered(bool)), this, SLOT(slotUserViewSaveView())); surfaceToSegmentationVolumeAction = new QAction(parent); surfaceToSegmentationVolumeAction->setObjectName("surfaceToSegmentationVolumeAction"); surfaceToSegmentationVolumeAction->setText("Convert Main Window Surface To Segmentation Volume..."); QObject::connect(surfaceToSegmentationVolumeAction, SIGNAL(triggered(bool)), this, SLOT(slotSurfaceToSegmentationVolume())); } /** * Destructor. */ GuiMainWindowSurfaceActions::~GuiMainWindowSurfaceActions() { delete flatMultiResMorphObject; delete sphericalMultiResMorphObject; } /** * called to convert surface to a segmentation volume. */ void GuiMainWindowSurfaceActions::slotSurfaceToSegmentationVolume() { GuiSurfaceToVolumeDialog svd(theMainWindow, GuiSurfaceToVolumeDialog::DIALOG_MODE_SEGMENT_VOLUME, "Convert Surface to Segmentation Volume"); if (svd.exec() == QDialog::Accepted) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); float offset[3]; float voxelSize[3]; float origin[3]; int dim[3]; svd.getSurfaceOffset(offset); svd.getVolumeDimensions(dim); svd.getVolumeVoxelSizes(voxelSize); svd.getVolumeOrigin(origin); BrainModelSurfaceToVolumeConverter stv(theMainWindow->getBrainSet(), svd.getSelectedSurface(), svd.getStandardVolumeSpace(), offset, dim, voxelSize, origin, svd.getSurfaceInnerBoundary(), svd.getSurfaceOuterBoundary(), svd.getSurfaceThicknessStep(), BrainModelSurfaceToVolumeConverter::CONVERT_TO_SEGMENTATION_VOLUME_USING_NODES); stv.setNodeToVoxelMappingEnabled(svd.getNodeToVoxelMappingEnabled(), svd.getNodeToVoxelMappingFileName()); try { stv.execute(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(theMainWindow, "Error", e.whatQString()); return; } theMainWindow->speakText("The metric data has been converted to a volume.", false); GuiBrainModelOpenGL* openGL = theMainWindow->getBrainModelOpenGL(); openGL->displayBrainModelVolume(); GuiFilesModified fm; fm.setVolumeModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); } } /** * Slot called to simplify the surface. */ void GuiMainWindowSurfaceActions::slotSimplifySurface() { BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms == NULL) { QMessageBox::critical(theMainWindow, "ERROR", "There is no surface in the main window."); return; } if (theMainWindow->getBrainSet()->getNumberOfBrainModels() > 1) { if (QMessageBox::question(theMainWindow, "Continue", "Contours/surfaces/volumes other than the surface in the main\n" "window are loaded. They will be discarded if you continue.", (QMessageBox::Ok | QMessageBox::Cancel), QMessageBox::Ok) != QMessageBox::Ok) { return; } } QString msg; msg.append("Current number of polygons: "); msg.append(QString::number(bms->getTopologyFile()->getNumberOfTiles())); msg.append(".\n\nEnter Maximum Number of Polygons.\n"); bool ok = false; const int maxPolygons = QInputDialog::getInteger(theMainWindow, "Simplify Surface", msg, 150000, 1, 1000000000, 1000, &ok); if (ok) { try { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); theMainWindow->getBrainSet()->simplifySurface(bms, maxPolygons); QApplication::beep(); QApplication::restoreOverrideCursor(); } catch (FileException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(theMainWindow, "ERROR", e.whatQString()); } } } /** * Called to create an average coordinate file */ void GuiMainWindowSurfaceActions::slotAverageCoordinateFile() { static GuiAverageCoordinateDialog* acd = NULL; if (acd == NULL) { acd = new GuiAverageCoordinateDialog(theMainWindow); } acd->show(); acd->activateWindow(); } /** * called to copy the surface in the main window. */ void GuiMainWindowSurfaceActions::slotCopyMainWindowSurface() { BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); QString name("copy_of_"); name.append(bms->getFileName()); BrainModelSurface* bms2 = new BrainModelSurface(*bms); CoordinateFile* cf = bms2->getCoordinateFile(); cf->setFileName(name); theMainWindow->getBrainSet()->addBrainModel(bms2); GuiFilesModified fm; fm.setCoordinateModified(); theMainWindow->fileModificationUpdate(fm); theMainWindow->displayNewestSurfaceInMainWindow(); GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); } } /** * Called to interpolate surfaces. */ void GuiMainWindowSurfaceActions::slotInterpolateSurfaces() { theMainWindow->getInterpolateSurfaceDialog(true); } /** * Called when align surfaces to standard orientation is selected. */ void GuiMainWindowSurfaceActions::slotAlignSurfacesToStandardOrientation() { GuiAlignSurfaceToStandardOrientationDialog* assod = theMainWindow->getAlignSurfaceToStandardOrientationDialog(); if (assod == NULL) { assod = new GuiAlignSurfaceToStandardOrientationDialog(theMainWindow); } assod->show(); assod->activateWindow(); } /** * Display generate surface curvature dialog. */ void GuiMainWindowSurfaceActions::slotMeasurementsCurvature() { GuiGenerateSurfaceCurvatureDialog gscd(theMainWindow); gscd.exec(); } /** * Display generate sulcal depth dialog. */ void GuiMainWindowSurfaceActions::slotMeasurementsSulcalDepth() { GuiGenerateSulcalDepthDialog gsdd(theMainWindow); gsdd.exec(); } /** * Generate shape from coordinate difference. */ void GuiMainWindowSurfaceActions::slotMeasurementsShapeFromCoordinateSubtraction() { GuiShapeOrVectorsFromCoordinateSubtractionDialog csd(theMainWindow, GuiShapeOrVectorsFromCoordinateSubtractionDialog::MODE_SHAPE); csd.exec(); } /** * Display flatten full hemisphere dialog. */ void GuiMainWindowSurfaceActions::slotFlattenHemisphere() { GuiFlattenHemisphereDialog gfhd(theMainWindow); gfhd.exec(); } /** * Called to perform a crossover check */ void GuiMainWindowSurfaceActions::slotMeasurementsCrossoverCheck() { BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { int defaultItem = 2; switch (bms->getSurfaceType()) { case BrainModelSurface::SURFACE_TYPE_RAW: defaultItem = 2; break; case BrainModelSurface::SURFACE_TYPE_FIDUCIAL: defaultItem = 2; break; case BrainModelSurface::SURFACE_TYPE_INFLATED: defaultItem = 2; break; case BrainModelSurface::SURFACE_TYPE_VERY_INFLATED: defaultItem = 2; break; case BrainModelSurface::SURFACE_TYPE_SPHERICAL: defaultItem = 1; break; case BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL: defaultItem = 1; break; case BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL: defaultItem = 2; break; case BrainModelSurface::SURFACE_TYPE_FLAT: defaultItem = 0; break; case BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR: defaultItem = 0; break; case BrainModelSurface::SURFACE_TYPE_HULL: defaultItem = 2; break; case BrainModelSurface::SURFACE_TYPE_UNKNOWN: defaultItem = 2; break; case BrainModelSurface::SURFACE_TYPE_UNSPECIFIED: defaultItem = 2; break; } std::vector labels; labels.push_back("Flat Surface"); labels.push_back("Spherical Surface"); labels.push_back("Other Type of Surface"); if (DebugControl::getTestFlag1()) { labels.push_back("SureFit Ellipsoid Crossover Check"); } QApplication::beep(); QtRadioButtonSelectionDialog rd(theMainWindow, "Crossover Check", "", labels, defaultItem); if (rd.exec() == QDialog::Accepted) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainModelSurface::SURFACE_TYPES surfaceType = BrainModelSurface::SURFACE_TYPE_UNKNOWN; switch (rd.getSelectedItemIndex()) { case 0: surfaceType = BrainModelSurface::SURFACE_TYPE_FLAT; break; case 1: surfaceType = BrainModelSurface::SURFACE_TYPE_SPHERICAL; break; case 2: surfaceType = BrainModelSurface::SURFACE_TYPE_UNKNOWN; break; case 3: // SureFit crossover check break; } int numTileCrossovers, numNodeCrossovers; if (rd.getSelectedItemIndex() == 3) { numNodeCrossovers = bms->crossoverCheckSureFitEllipsoid(); } else { bms->crossoverCheck(numTileCrossovers, numNodeCrossovers, surfaceType); } /* // // Set the overlay to crossovers (if there are any) // bool haveCrossovers = false; const int numNodes = theMainWindow->getBrainSet()->getNumberOfNodes(); for (int i = 0; i < numNodes; i++) { if (theMainWindow->getBrainSet()->getNodeAttributes(i)->getCrossover()) { haveCrossovers = true; break; } } if (haveCrossovers) { */ BrainModelSurfaceNodeColoring* bsnc = theMainWindow->getBrainSet()->getNodeColoring(); if ((numNodeCrossovers > 0) || (numTileCrossovers > 0)) { theMainWindow->getBrainSet()->getPrimarySurfaceOverlay()->setOverlay(-1, BrainModelSurfaceOverlay::OVERLAY_SHOW_CROSSOVERS); theMainWindow->updateDisplayControlDialog(); } bsnc->assignColors(); GuiBrainModelOpenGL::updateAllGL(NULL); std::ostringstream str; str << "There are " << numNodeCrossovers << " node crossovers.\n" << "There are " << numTileCrossovers << " tile crossovers." << std::ends; QApplication::restoreOverrideCursor(); QMessageBox::information(theMainWindow, "Crossover Check Results", str.str().c_str()); } } } /** * Called to generate distortion */ void GuiMainWindowSurfaceActions::slotMeasurementsDistortion() { BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { GuiDistortionDialog gdd(theMainWindow, bms); gdd.exec(); } } /** * Called to set toplogy file for surfaces */ void GuiMainWindowSurfaceActions::slotSurfaceInformation() { GuiSurfaceInformationDialog* std = new GuiSurfaceInformationDialog(theMainWindow); std->exec(); } /** * Called when compute normals is selected. */ void GuiMainWindowSurfaceActions::slotNormalsGenerate() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainModelSurface* bms = theMainWindow->getBrainModelOpenGL()->getDisplayedBrainModelSurface(); if (bms != NULL) { bms->computeNormals(); GuiBrainModelOpenGL::updateAllGL(NULL); } QApplication::restoreOverrideCursor(); } /** * Called when flip normals is selected. */ void GuiMainWindowSurfaceActions::slotNormalsFlip() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainModelSurface* bms = theMainWindow->getBrainModelOpenGL()->getDisplayedBrainModelSurface(); if (bms != NULL) { TopologyFile* tf = bms->getTopologyFile(); if (tf != NULL) { // // flip the order of the tile's nodes // tf->flipTileOrientation(); // // compute normals for all surfaces using this topology file // const int num = theMainWindow->getBrainSet()->getNumberOfBrainModels(); for (int i = 0; i < num; i++) { BrainModel* bm = theMainWindow->getBrainSet()->getBrainModel(i); if (bm->getModelType() == BrainModel::BRAIN_MODEL_SURFACE) { BrainModelSurface* bms = dynamic_cast(bm); if (bms->getTopologyFile() == tf) { bms->computeNormals(); } } } GuiBrainModelOpenGL::updateAllGL(NULL); } } QApplication::restoreOverrideCursor(); } /** * Called to display the region of interest dialog */ void GuiMainWindowSurfaceActions::slotRegionOfInterest() { theMainWindow->getSurfaceRegionOfInterestDialog(true); } /** * Called to display the region of interest dialog */ void GuiMainWindowSurfaceActions::slotRegionOfInterestOLD() { theMainWindow->getSurfaceRegionOfInterestDialogOLD(true); } /** * Called when show cuts is selected */ void GuiMainWindowSurfaceActions::slotCutsShow() { DisplaySettingsCuts* dsc = theMainWindow->getBrainSet()->getDisplaySettingsCuts(); dsc->setDisplayCuts(! dsc->getDisplayCuts()); GuiBrainModelOpenGL::updateAllGL(NULL); } /** * Called when apply cuts is selected */ void GuiMainWindowSurfaceActions::slotCutsApply() { BrainModelSurface* bms = theMainWindow->getBrainModelOpenGL()->getDisplayedBrainModelSurface(); if (bms != NULL) { CutsFile* cutsFile = theMainWindow->getBrainSet()->getCutsFile(); if (cutsFile != NULL) { if (cutsFile->getNumberOfBorders() <= 0) { QMessageBox::warning(theMainWindow, "No Cuts", "There are no cuts."); return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainModelSurfaceCutter bsc(bms, theMainWindow->getBrainSet()->getCutsFile(), BrainModelSurfaceCutter::CUTTING_MODE_NORMAL); try { bsc.execute(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(theMainWindow, "Apply Cuts Error", e.whatQString()); } TopologyFile* tf = bms->getTopologyFile(); if (tf != NULL) { const int numIslands = tf->disconnectIslands(); if (numIslands > 0) { // // Move any disconnected nodes in surfaces that use the topology file // for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfBrainModels(); i++) { BrainModelSurface* bms = theMainWindow->getBrainSet()->getBrainModelSurface(i); if (bms != NULL) { if (bms->getTopologyFile() == tf) { bms->moveDisconnectedNodesToOrigin(); } } } } GuiFilesModified fm; fm.setTopologyModified(); fm.setCoordinateModified(); theMainWindow->fileModificationUpdate(fm); } GuiFilesModified fm; fm.setTopologyModified(); fm.setCoordinateModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); theMainWindow->speakText("Cuts have been applied.", false); } } } /** * Called when delete cuts with mouse is selected */ void GuiMainWindowSurfaceActions::slotCutsDeleteWithMouse() { theMainWindow->getBrainModelOpenGL()->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_CUT_DELETE); } /** * Called when delete all cuts is selected */ void GuiMainWindowSurfaceActions::slotCutsDeleteAll() { if (QMessageBox::warning(theMainWindow, "Delete All Cuts", "Are you sure you want to delete all cuts?", (QMessageBox::Yes | QMessageBox::No), QMessageBox::Yes) == QMessageBox::Yes) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); theMainWindow->getBrainSet()->clearCutsFile(); GuiFilesModified fm; fm.setCutModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); } } /** * Called when draw cuts is selected */ void GuiMainWindowSurfaceActions::slotCutsDraw() { DisplaySettingsCuts* dsc = theMainWindow->getBrainSet()->getDisplaySettingsCuts(); if (dsc->getDisplayCuts() == false) { dsc->setDisplayCuts(true); GuiBrainModelOpenGL::updateAllGL(NULL); } theMainWindow->getBrainModelOpenGL()->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_CUT_DRAW); } /** * Called to multiresolution morph a flat surface. */ void GuiMainWindowSurfaceActions::slotMultiresolutionMorphFlat() { if (theMainWindow->getBrainModelSurface() != NULL) { GuiMultiresolutionMorphingDialog mmd(theMainWindow, getFlatMultiresolutionMorphingObject(), false); mmd.exec(); } } /** * Called to multiresolution morph a sphere surface. */ void GuiMainWindowSurfaceActions::slotMultiresolutionMorphSphere() { if (theMainWindow->getBrainModelSurface() != NULL) { GuiMultiresolutionMorphingDialog mmd(theMainWindow, getSphericalMultiresolutionMorphingObject(), false); mmd.exec(); } } /** * called when run deformation flat dialog is selected. */ void GuiMainWindowSurfaceActions::slotDeformationRunFlatDialog() { #ifdef Q_OS_WIN32 QMessageBox::information(theMainWindow, "Not Available", "Flat registration is not availble for the Windows version of Caret."); return; #endif static GuiSurfaceDeformationDialog* sdd = NULL; if (sdd == NULL) { sdd = new GuiSurfaceDeformationDialog(theMainWindow, DeformationMapFile::DEFORMATION_TYPE_FLAT); } sdd->show(); } /** * called when run deformation spherical dialog is selected. */ void GuiMainWindowSurfaceActions::slotDeformationRunSphericalDialog() { static GuiSurfaceDeformationDialog* sdd = NULL; if (sdd == NULL) { sdd = new GuiSurfaceDeformationDialog(theMainWindow, DeformationMapFile::DEFORMATION_TYPE_SPHERE); } sdd->show(); } /** * called when apply deformation dialog is selected */ void GuiMainWindowSurfaceActions::slotDeformationApplyDialog() { GuiApplyDeformationMapDialog* admd = new GuiApplyDeformationMapDialog(theMainWindow); admd->setAttribute(Qt::WA_DeleteOnClose); admd->show(); } /** * Called to subtract the params file AC from the surface. */ void GuiMainWindowSurfaceActions::slotTransformSubtractAC() { ParamsFile* pf = theMainWindow->getBrainSet()->getParamsFile(); BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { float acx, acy, acz; if (pf->getParameter(ParamsFile::keyACx, acx) && pf->getParameter(ParamsFile::keyACy, acy) && pf->getParameter(ParamsFile::keyACz, acz)) { TransformationMatrix tm; tm.translate(-acx, -acy, -acz); applyMatrixToMainWindowSurface(tm); } } } /** * Called to translate the surface by a user entered amount. */ void GuiMainWindowSurfaceActions::slotTransformTranslate() { BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { if (translateDialog == NULL) { std::vector labels; std::vector values; labels.push_back("Translate X"); values.push_back("0.0"); labels.push_back("Translate Y"); values.push_back("0.0"); labels.push_back("Translate Z"); values.push_back("0.0"); translateDialog = new QtMultipleInputDialog( theMainWindow, "Translate Surface", "", labels, values, true, false); QObject::connect(translateDialog, SIGNAL(signalApplyPressed()), this, SLOT(slotTransformTranslateApply())); } translateDialog->show(); translateDialog->activateWindow(); } } /** * Called when apply button hit on translate dialog. */ void GuiMainWindowSurfaceActions::slotTransformTranslateApply() { BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { std::vector t; translateDialog->getValues(t); TransformationMatrix tm; tm.translate(t[0], t[1], t[2]); applyMatrixToMainWindowSurface(tm); } } /** * Called to scale the surface by a user entered amount. */ void GuiMainWindowSurfaceActions::slotTransformScale() { BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { if (scaleDialog == NULL) { std::vector labels; std::vector values; labels.push_back("Scale "); values.push_back("1.0"); scaleDialog = new QtMultipleInputDialog(theMainWindow, "Scale Surface", "", labels, values, true, false); QObject::connect(scaleDialog, SIGNAL(signalApplyPressed()), this, SLOT(slotTransformScaleApply())); } } scaleDialog->show(); scaleDialog->activateWindow(); } /** * Called when apply button hit on scale dialog. */ void GuiMainWindowSurfaceActions::slotTransformScaleApply() { BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { std::vector floatValues; scaleDialog->getValues(floatValues); const float scale = floatValues[0]; TransformationMatrix tm; tm.scale(scale, scale, scale); applyMatrixToMainWindowSurface(tm); } } /** * apply a matrix to the main window surface. */ void GuiMainWindowSurfaceActions::applyMatrixToMainWindowSurface(TransformationMatrix& tm) { BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); /* cells/foci should be projections so do not transform // // Transform cells/foci before surface since cells/foci are projected to surface // const bool fiducialFlag = ((bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_RAW) || (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FIDUCIAL)); CellProjectionFile* cf = theMainWindow->getBrainSet()->getCellProjectionFile(); if (cf != NULL) { cf->applyTransformationMatrix(bms->getCoordinateFile(), bms->getTopologyFile(), fiducialFlag, std::numeric_limits::min(), std::numeric_limits::max(), tm, false); } FociProjectionFile* ff = theMainWindow->getBrainSet()->getFociProjectionFile(); if (ff != NULL) { ff->applyTransformationMatrix(bms->getCoordinateFile(), bms->getTopologyFile(), fiducialFlag, std::numeric_limits::min(), std::numeric_limits::max(), tm, false); } */ // // Transform surface // bms->applyTransformationMatrix(tm); // // Transform borders // BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); bmbs->applyTransformationMatrix(bms, tm); theMainWindow->getBrainSet()->applyAllProjectedFiles(); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } } /** * Called to translate surface to its center of mass. */ void GuiMainWindowSurfaceActions::slotTransformCenterOfMass() { BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { float com[3]; bms->getCenterOfMass(com); TransformationMatrix tm; tm.translate(-com[0], -com[1], -com[2]); applyMatrixToMainWindowSurface(tm); } } /** * called when spm transform selected. */ void GuiMainWindowSurfaceActions::slotTransformSpm() { GuiSurfaceSpmTransformDialog spm(theMainWindow); spm.exec(); } /** * called when transform apply current view is selected. */ void GuiMainWindowSurfaceActions::slotTransformApplyCurrentView() { BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { WuQDataEntryDialog at(theMainWindow); at.setWindowTitle("Apply Current View"); QCheckBox* applyTranslationCheckBox = at.addCheckBox("Apply Translation", true); QCheckBox* applyRotationCheckBox = at.addCheckBox("Apply Rotation", true); QCheckBox* applyScalingCheckBox = at.addCheckBox("Apply Scaling", true); if (at.exec() == QDialog::Accepted) { bms->applyCurrentView(BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW, applyTranslationCheckBox->isChecked(), applyRotationCheckBox->isChecked(), applyScalingCheckBox->isChecked()); theMainWindow->getBrainSet()->applyAllProjectedFiles(); GuiBrainModelOpenGL::updateAllGL(); } } } /** * called when transform move disconnected nodes to the origin. */ void GuiMainWindowSurfaceActions::slotTransformDisconnectedNodesToOrigin() { BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { bms->moveDisconnectedNodesToOrigin(); GuiBrainModelOpenGL::updateAllGL(); } } /** * called when topology report selected. */ void GuiMainWindowSurfaceActions::slotTopologyReport() { static GuiSurfaceTopologyReportDialog* trd = NULL; if (trd == NULL) { trd = new GuiSurfaceTopologyReportDialog(theMainWindow); } trd->show(); trd->activateWindow(); } /** * replace topology with standard topology */ void GuiMainWindowSurfaceActions::slotTopologyReplaceWithStandardSurface() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainModelSurface* bms = theMainWindow->getBrainModelOpenGL()->getDisplayedBrainModelSurface(); if (bms != NULL) { BrainModelStandardSurfaceReplacement bmssr(theMainWindow->getBrainSet(), bms); try { bmssr.execute(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(theMainWindow, "ERROR", e.whatQString()); return; } GuiFilesModified fm; fm.setStatusForAll(true); theMainWindow->fileModificationUpdate(fm); theMainWindow->displayNewestSurfaceInMainWindow(); GuiBrainModelOpenGL::updateAllGL(); } QApplication::restoreOverrideCursor(); } /** * called when correct fiducial selected. */ void GuiMainWindowSurfaceActions::slotTopologyCorrectFiducial() { BrainModelSurface* bms = theMainWindow->getBrainModelOpenGL()->getDisplayedBrainModelSurface(); if (bms == NULL) { return; } if (bms->getSurfaceType() != BrainModelSurface::SURFACE_TYPE_FIDUCIAL) { if (QMessageBox::question(theMainWindow, "ERROR", "Surface in the main window does not appear to be a fiducial.", (QMessageBox::Ok | QMessageBox::Cancel), QMessageBox::Cancel) == QMessageBox::Cancel) { return; } } if (bms->isTopologicallyCorrect()) { QMessageBox::information(theMainWindow, "INFO", "Surface is already topologically correct."); return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainModelSurfaceTopologyCorrector bmstc(theMainWindow->getBrainSet(), bms); try { bmstc.execute(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(theMainWindow, "ERROR", e.whatQString()); } theMainWindow->postSpecFileReadInitializations(); GuiFilesModified fm; fm.setCoordinateModified(); fm.setTopologyModified(); theMainWindow->fileModificationUpdate(fm); theMainWindow->displayNewestSurfaceInMainWindow(); GuiBrainModelOpenGL::updateAllGL(); QApplication::beep(); QApplication::restoreOverrideCursor(); } /** * called when retessellate sphere selected. */ void GuiMainWindowSurfaceActions::slotTopologyRetessellateSphere() { BrainModelSurface* bms = theMainWindow->getBrainModelOpenGL()->getDisplayedBrainModelSurface(); if (bms != NULL) { if (bms->getSurfaceType() != BrainModelSurface::SURFACE_TYPE_SPHERICAL) { if (QMessageBox::question(theMainWindow, "ERROR", "Surface in the main window does not appear to be a sphere.", (QMessageBox::Ok | QMessageBox::Cancel), QMessageBox::Cancel) == QMessageBox::Cancel) { return; } } const int numNodes = bms->getNumberOfNodes(); const TopologyFile* tf = bms->getTopologyFile(); const TopologyHelper* th = tf->getTopologyHelper(false, true, false); std::vector useNodeInTessellationFlag(numNodes); for (int i = 0; i < numNodes; i++) { useNodeInTessellationFlag[i] = th->getNodeHasNeighbors(i); } BrainModelSurfaceSphericalTessellator bmsst(theMainWindow->getBrainSet(), bms, useNodeInTessellationFlag); QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); try { bmsst.execute(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(theMainWindow, "ERROR", e.whatQString()); } theMainWindow->postSpecFileReadInitializations(); GuiFilesModified fm; fm.setCoordinateModified(); fm.setTopologyModified(); theMainWindow->fileModificationUpdate(fm); theMainWindow->displayNewestSurfaceInMainWindow(); GuiBrainModelOpenGL::updateAllGL(); QApplication::beep(); QApplication::restoreOverrideCursor(); } } /** * Called when orient tiles consistently is selected. */ void GuiMainWindowSurfaceActions::slotTopologyOrientTilesConsistently() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainModelSurface* bms = theMainWindow->getBrainModelOpenGL()->getDisplayedBrainModelSurface(); if (bms != NULL) { bms->orientTilesConsistently(); bms->computeNormals(); GuiBrainModelOpenGL::updateAllGL(NULL); } QApplication::restoreOverrideCursor(); } /** * Called to classify nodes into edges and interior using topology */ void GuiMainWindowSurfaceActions::slotTopologyClassifyEdges() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { theMainWindow->getBrainSet()->classifyNodes(bms->getTopologyFile()); GuiFilesModified fm; theMainWindow->fileModificationUpdate(fm); theMainWindow->getBrainSet()->getNodeColoring()->assignColors(); GuiBrainModelOpenGL::updateAllGL(NULL); } QApplication::restoreOverrideCursor(); } /** * Called to check for islands using topology. */ void GuiMainWindowSurfaceActions::slotTopologyCheckForIslands() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { TopologyFile* tf = bms->getTopologyFile(); if (tf != NULL) { std::vector v1, v2, v3; int numIslands = tf->findIslands(v1, v2, v3); if (numIslands > 0) { numIslands--; } QString msg(StringUtilities::fromNumber(numIslands)); msg.append(" islands were found."); QApplication::restoreOverrideCursor(); QMessageBox::information(theMainWindow, "Islands", msg); } } QApplication::restoreOverrideCursor(); } /** * Called to delete corner tiles */ void GuiMainWindowSurfaceActions::slotTopologyDeleteCorners() { BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { TopologyFile* tf = bms->getTopologyFile(); if (tf != NULL) { std::vector labels; labels.push_back("Delete Stragglers Only"); labels.push_back("Delete Corners and Stragglers"); QtRadioButtonSelectionDialog rbsd(theMainWindow, "Delete Corners and Stragglers", "", labels, 0); if (rbsd.exec() == QDialog::Accepted) { int cornerSelection = 0; if (rbsd.getSelectedItemIndex() == 0) { cornerSelection = 2; } else { cornerSelection = 1; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); const int numCorners = tf->removeCornerTiles(cornerSelection); if (numCorners > 0) { // // Move any disconnected nodes in surfaces that use the topology file // for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfBrainModels(); i++) { BrainModelSurface* bms = theMainWindow->getBrainSet()->getBrainModelSurface(i); if (bms != NULL) { if (bms->getTopologyFile() == tf) { bms->moveDisconnectedNodesToOrigin(); } } } } QString msg(StringUtilities::fromNumber(numCorners)); msg.append(" corner tiles were deleted."); GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); QMessageBox::information(theMainWindow, "Corners Info", msg); } } } } /** * Called to disconnect islands using topology. */ void GuiMainWindowSurfaceActions::slotTopologyDisconnectIslands() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { TopologyFile* tf = bms->getTopologyFile(); if (tf != NULL) { const int numIslands = tf->disconnectIslands(); if (numIslands > 0) { // // Move any disconnected nodes in surfaces that use the topology file // for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfBrainModels(); i++) { BrainModelSurface* bms = theMainWindow->getBrainSet()->getBrainModelSurface(i); if (bms != NULL) { if (bms->getTopologyFile() == tf) { bms->moveDisconnectedNodesToOrigin(); } } } GuiBrainModelOpenGL::updateAllGL(NULL); } QString msg(StringUtilities::fromNumber(numIslands)); msg.append(" islands were removed."); QApplication::restoreOverrideCursor(); QMessageBox::information(theMainWindow, "Islands", msg); GuiFilesModified fm; fm.setTopologyModified(); fm.setCoordinateModified(); theMainWindow->fileModificationUpdate(fm); } } QApplication::restoreOverrideCursor(); } /** * Called when Nearest Spherical Border Distance is selected. */ void GuiMainWindowSurfaceActions::slotGeometrySphereBorderDistance() { /* bool ok = false; int sphereNumber = QInputDialog::getInteger("Deformation Measurement", "Sphere Number", 3, 1, std::numeric_limits::max(), 1, &ok, theMainWindow, "defNodesSkip"); if (ok) { */ BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); BorderFile borderFile; if (bms != NULL) { BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); bmbs->copyBordersToBorderFile(bms, borderFile); } BrainModelSurfaceDeformationMeasurement bmsdm(theMainWindow->getBrainSet(), bms, &borderFile, theMainWindow->getBrainSet()->getMetricFile(), 0); try { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); bmsdm.execute(); GuiFilesModified fm; fm.setMetricModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); QApplication::beep(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(theMainWindow, "ERROR", e.whatQString()); } /* } */ } /** * called by scale sphere to surface area of fiducial. */ void GuiMainWindowSurfaceActions::slotGeometryScaleSphereToFiducialArea() { BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms == NULL) { QMessageBox::critical(theMainWindow, "ERROR", "There is no surface in the main window."); } const BrainModelSurface* fiducial = theMainWindow->getBrainSet()->getActiveFiducialSurface(); if (fiducial == NULL) { QMessageBox::critical(theMainWindow, "ERROR", "There is no active fiducial surface."); } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); const float fiducialArea = fiducial->getSurfaceArea(); bms->convertToSphereWithSurfaceArea(fiducialArea); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } /** * Add relief to a flat or spherical surface. */ void GuiMainWindowSurfaceActions::slotGeometryRelief() { BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { bms->applyShapeToSurface(*theMainWindow->getBrainSet()->getSurfaceShapeFile(), 0, 0.5); GuiBrainModelOpenGL::updateAllGL(); } } /** * Expand or shrink a surface along its node's normals. */ void GuiMainWindowSurfaceActions::slotGeometryExpand() { BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { bool valid = false; const float factor = QInputDialog::getDouble(theMainWindow, "Expand or Shrink Surface", "Amount to Shrink (negative) or Expand(positive)", 1.0, -100000.0, 100000.0, 4, &valid); if (valid) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); bms->expandSurface(factor); theMainWindow->getBrainSet()->applyAllProjectedFiles(); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } } } /** * called when generate inflated and ellipsoid from fiducial is selected. */ void GuiMainWindowSurfaceActions::slotGeometryInflatedAndEllipsoidFromFiducial() { const BrainModelSurface* fiducial = theMainWindow->getBrainModelSurface(); if (fiducial == NULL) { QMessageBox::critical(theMainWindow, "ERROR", "There is not a FIDUCIAL surface in the Main Window."); return; } generateInflatedAndOtherSurfaces(fiducial); } /** * generate inflated and other surfaces from fiducial. */ void GuiMainWindowSurfaceActions::generateInflatedAndOtherSurfaces( const BrainModelSurface* fiducialSurface, const bool enableEllipsoidFlag, const bool enableFingerSmoothingFlag, const bool checkInflatedFlag, const bool checkVeryInflatedFlag, const bool checkSphericalFlag, const bool checkCompMedWallFlag) { if (fiducialSurface->getIsFiducialSurface() == false) { QMessageBox::critical(theMainWindow, "ERROR", "Surface is not a fiducial surface."); return; } WuQDataEntryDialog ded(theMainWindow); ded.setWindowTitle("Choose Surfaces To Create"); QCheckBox* createInflatedSurfaceCheckBox = ded.addCheckBox("Create Inflated Surface", checkInflatedFlag); QCheckBox* createVeryInflatedSurfaceCheckBox = ded.addCheckBox("Create Very Inflated Surface", checkVeryInflatedFlag); QCheckBox* createEllipsoidSurfaceCheckBox = NULL; if (enableEllipsoidFlag) { createEllipsoidSurfaceCheckBox = ded.addCheckBox("Create Ellipsoid Surface", true); } QCheckBox* createSphericalSurfaceCheckBox = ded.addCheckBox("Create Spherical Surface", checkSphericalFlag); QCheckBox* createCompMedWallSurfaceCheckBox = ded.addCheckBox("Create Compressed Medial Wall Surface", checkCompMedWallFlag); QCheckBox* enableFingerSmoothingCheckBox = NULL; if (enableFingerSmoothingFlag) { enableFingerSmoothingCheckBox = ded.addCheckBox("Enable Finger Smoothing (Use if Topological Defects)", false); } QCheckBox* scaleSurfaceCheckBox = ded.addCheckBox("Scale Surface to Match Area of Fiducial Surface", true); QDoubleSpinBox* iterationScaleDoubleSpinBox = ded.addDoubleSpinBox("Iterations Scale", 1.0); iterationScaleDoubleSpinBox->setToolTip( "Use the \"Iterations Scale\" to scale the iterations\n" "during the inflation processes. In most cases, it is\n" "not necessary to use this option such as when the \n" "surface has been generated using Caret. However, \n" "surfaces produced by FreeSurfer often contain a large\n" "number of nodes, 150,000 or more. In this case, try\n" "an \"Iterations Scale\" of 2.5."); QCheckBox* generateMetricMeasurementsCheckBox = NULL; if (enableFingerSmoothingFlag) { generateMetricMeasurementsCheckBox = ded.addCheckBox("Generate Metric Measurements", false); } if (ded.exec() == QDialog::Accepted) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); QApplication::processEvents(); MetricFile* mf = NULL; if (generateMetricMeasurementsCheckBox != NULL) { if (generateMetricMeasurementsCheckBox->isChecked()) { mf = theMainWindow->getBrainSet()->getMetricFile(); } } bool doEllipsoidFlag = false; if (createEllipsoidSurfaceCheckBox != NULL) { doEllipsoidFlag = createEllipsoidSurfaceCheckBox->isChecked(); } bool doFingerSmoothingFlag = false; if (enableFingerSmoothingCheckBox != NULL) { doFingerSmoothingFlag = enableFingerSmoothingCheckBox->isChecked(); } fiducialSurface->createInflatedAndEllipsoidFromFiducial(createInflatedSurfaceCheckBox->isChecked(), createVeryInflatedSurfaceCheckBox->isChecked(), doEllipsoidFlag, createSphericalSurfaceCheckBox->isChecked(), createCompMedWallSurfaceCheckBox->isChecked(), doFingerSmoothingFlag, scaleSurfaceCheckBox->isChecked(), iterationScaleDoubleSpinBox->value(), mf); GuiFilesModified fm; fm.setCoordinateModified(); theMainWindow->fileModificationUpdate(fm); if (enableEllipsoidFlag) { theMainWindow->displayNewestSurfaceInMainWindow(); } GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); theMainWindow->speakText("Inflated and or ellipsoid surfaces have been created.", false); } } /** * called by geometry compress front face menu item. */ void GuiMainWindowSurfaceActions::slotGeometryCompressFrontFace() { BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { bool valid = false; const float factor = QInputDialog::getDouble(theMainWindow, "Compress Medial Wall", "Compression Factor", 0.5, 0.01, 1000.0, 2, &valid); if (valid) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); bms->compressFrontFace(factor, 0); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } } } /** * Called when geometry compress medial wall sub menu is selected */ void GuiMainWindowSurfaceActions::slotGeometryCompressMedialWall() { BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { bool valid = false; const float factor = QInputDialog::getDouble(theMainWindow, "Compress Medial Wall", "Compression Factor", 0.5, 0.01, 1000.0, 2, &valid); if (valid) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); bms->convertSphereToCompressedMedialWall(factor); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } } } /** * Called when geometry covert to sphere sub menu is selected */ void GuiMainWindowSurfaceActions::slotGeometryToSphere() { BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); bms->convertToSphereWithSurfaceArea(); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } } /** * Called when geometry covert to ellispoid sub menu is selected */ void GuiMainWindowSurfaceActions::slotGeometryToEllipsoid() { BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); bms->convertToSphereWithSurfaceArea(); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } } /** * Called when geometry convert ellipse to sphere sub menu is selected */ void GuiMainWindowSurfaceActions::slotGeometryEllipseToSphere() { BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); bms->convertEllipsoidToSphereWithSurfaceArea(); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } } /** * Called when geometry inflate sub menu is selected */ void GuiMainWindowSurfaceActions::slotGeometryInflate() { static GuiInflateSurfaceDialog* isd = NULL; if (isd == NULL) { isd = new GuiInflateSurfaceDialog(theMainWindow); } isd->show(); isd->activateWindow(); } /** * Called when geometry inflate sub menu is selected */ void GuiMainWindowSurfaceActions::slotGeometryInflateAndSmoothFingers() { static GuiInflateAndSmoothFingersDialog* isd = NULL; if (isd == NULL) { isd = new GuiInflateAndSmoothFingersDialog(theMainWindow, false); } isd->show(); isd->activateWindow(); } /** * Called when geometry sphere to flat sub menu is selected */ void GuiMainWindowSurfaceActions::slotGeometrySphereToFlat() { BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); bms->convertSphereToFlat(); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } } /** * Called when geometry sphere to flat through hole sub menu is selected */ void GuiMainWindowSurfaceActions::slotGeometrySphereToFlatThroughHole() { BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { // // Find the geography column in the paint file // PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); const int geographyColumn = pf->getGeographyColumnNumber(); if (geographyColumn >= 0) { // // Let user choose the name of the hole // GuiPaintColumnNamesListBoxSelectionDialog pnld(theMainWindow, geographyColumn); if (pnld.exec()) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); const int paintIndex = pnld.getSelectedItemIndex(); std::vector names; names.push_back(pf->getPaintNameFromIndex(paintIndex)); // // orient the surface so that the hole is on the negative Z axis // QString msg; bms->orientPaintedNodesToNegativeZAxis(pf, names, geographyColumn, msg); // // disconnect the nodes that identify the hole // theMainWindow->getBrainSet()->disconnectNodes(bms->getTopologyFile(), names, geographyColumn); // // Make the sphere flat // bms->convertSphereToFlat(); // // Update the graphics windows // GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } } else { QApplication::restoreOverrideCursor(); QMessageBox::critical(theMainWindow, "ERROR", "There is no geography column in the paint file."); return; } } } /** * Called when geometry smoothing menu item is selected. */ void GuiMainWindowSurfaceActions::slotGeometrySmoothing() { theMainWindow->displaySmoothingDialog(); } /** * slot for identify menu highlight tile item. */ void GuiMainWindowSurfaceActions::slotIdentifyHighlightTile() { const BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { const TopologyFile* tf = bms->getTopologyFile(); if (tf->getNumberOfTiles() > 0) { bool valid = false; const int tileNumber = QInputDialog::getInteger(theMainWindow, "Highlight Tile", "Tile Number", 0, 0, tf->getNumberOfTiles() - 1, 1, &valid); if (valid) { int n1, n2, n3; tf->getTile(tileNumber, n1, n2, n3); BrainSet* bs = theMainWindow->getBrainSet(); GuiIdentifyDialog* id = theMainWindow->getIdentifyDialog(true); if (id != NULL) { BrainModelIdentification* bmi = bs->getBrainModelIdentification(); const QString id1 = bmi->getIdentificationTextForNode(bs, n1, true, true); id->appendHtml(id1); const QString id2 = bmi->getIdentificationTextForNode(bs, n2, true, true); id->appendHtml(id2); const QString id3 = bmi->getIdentificationTextForNode(bs, n3, true, true); id->appendHtml(id3); bs->setDisplayCrossForNode(n3, NULL); // // Highlight symbols // bs->getNodeAttributes(n1)->setHighlighting(BrainSetNodeAttribute::HIGHLIGHT_NODE_LOCAL); bs->getNodeAttributes(n2)->setHighlighting(BrainSetNodeAttribute::HIGHLIGHT_NODE_LOCAL); bs->getNodeAttributes(n3)->setHighlighting(BrainSetNodeAttribute::HIGHLIGHT_NODE_LOCAL); GuiBrainModelOpenGL::updateAllGL(); } } } } } /** * slot for identify menu highlight node item */ void GuiMainWindowSurfaceActions::slotIdentifyHighlightNode() { if (theMainWindow->getBrainSet()->getNumberOfNodes() > 0) { bool valid = false; const QString nodeText = QInputDialog::getText(theMainWindow, "Highlight Node", "Node number(s). Separate with spaces.", QLineEdit::Normal, "", &valid); if (valid) { BrainSet* bs = theMainWindow->getBrainSet(); std::vector nodes; StringUtilities::token(nodeText, " ", nodes); if (nodes.empty() == false) { GuiIdentifyDialog* id = theMainWindow->getIdentifyDialog(true); BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); if (id != NULL) { for (unsigned int i = 0; i < nodes.size(); i++) { if (i == 0) { bs->setDisplayCrossForNode(nodes[i], NULL); } const QString id1 = bmi->getIdentificationTextForNode(bs, nodes[i], true, true); id->appendHtml(id1); // // Highlight symbol // bs->getNodeAttributes(nodes[i])->setHighlighting(BrainSetNodeAttribute::HIGHLIGHT_NODE_LOCAL); } } GuiBrainModelOpenGL::updateAllGL(); } } } } /** * slot for identify menu clear symbols item */ void GuiMainWindowSurfaceActions::slotIdentifyClearSymbols() { theMainWindow->getBrainSet()->clearNodeHighlightSymbols(); GuiBrainModelOpenGL::updateAllGL(); } /** * Called to display resectioning dialog. */ void GuiMainWindowSurfaceActions::slotSectionResection() { GuiResectionDialog rd(theMainWindow); rd.exec(); } /** * Clear all or part of the section file. */ void GuiMainWindowSurfaceActions::slotSectionClearAllOrPart() { GuiFilesModified fm; fm.setSectionModified(); GuiNodeAttributeFileClearResetDialog d(theMainWindow, GUI_NODE_FILE_TYPE_SECTION); d.exec(); } /** * Project surface to plane. */ void GuiMainWindowSurfaceActions::slotProjectToPlane() { WuQDataEntryDialog ded(theMainWindow); ded.setWindowTitle("Project to Plane"); ded.setTextAtTop("If coordinates are projected more than once without " "restoring, the original coordinates will be lost.", true); QRadioButton* positiveXRadioButton = ded.addRadioButton("Positive X"); positiveXRadioButton->setToolTip("All Positive X-coordinates become zero."); QRadioButton* negativeXRadioButton = ded.addRadioButton("Negative X"); negativeXRadioButton->setToolTip("All Negative X-coordinates become zero."); QRadioButton* positiveYRadioButton = ded.addRadioButton("Positive Y"); positiveYRadioButton->setToolTip("All Positive Y-coordinates become zero."); QRadioButton* negativeYRadioButton = ded.addRadioButton("Negative Y"); negativeYRadioButton->setToolTip("All Negative Y-coordinates become zero."); QRadioButton* positiveZRadioButton = ded.addRadioButton("Positive Z"); positiveZRadioButton->setToolTip("All Positive Z-coordinates become zero."); QRadioButton* negativeZRadioButton = ded.addRadioButton("Negative Z"); negativeZRadioButton->setToolTip("All Negative Z-coordinates become zero."); QRadioButton* restoreRadioButton = ded.addRadioButton("Restore"); restoreRadioButton->setToolTip("Restore projected coordinates."); positiveZRadioButton->setChecked(true); if (ded.exec() == WuQDataEntryDialog::Accepted) { BrainModelSurface::COORDINATE_PLANE coordinatePlane = BrainModelSurface::COORDINATE_PLANE_NONE; if (positiveXRadioButton->isChecked()) { coordinatePlane = BrainModelSurface::COORDINATE_PLANE_MOVE_POSITIVE_X_TO_ZERO; } else if (negativeXRadioButton->isChecked()) { coordinatePlane = BrainModelSurface::COORDINATE_PLANE_MOVE_NEGATIVE_X_TO_ZERO; } else if (positiveYRadioButton->isChecked()) { coordinatePlane = BrainModelSurface::COORDINATE_PLANE_MOVE_POSITIVE_Y_TO_ZERO; } else if (negativeYRadioButton->isChecked()) { coordinatePlane = BrainModelSurface::COORDINATE_PLANE_MOVE_NEGATIVE_Y_TO_ZERO; } else if (positiveZRadioButton->isChecked()) { coordinatePlane = BrainModelSurface::COORDINATE_PLANE_MOVE_POSITIVE_Z_TO_ZERO; } else if (negativeZRadioButton->isChecked()) { coordinatePlane = BrainModelSurface::COORDINATE_PLANE_MOVE_NEGATIVE_Z_TO_ZERO; } else if (restoreRadioButton->isChecked()) { coordinatePlane = BrainModelSurface::COORDINATE_PLANE_RESTORE; } else { QMessageBox::critical(theMainWindow, "ERROR", "No projection option was selected."); return; } BrainModelSurface* bms = theMainWindow->getBrainModelOpenGL()->getDisplayedBrainModelSurface(); if (bms != NULL) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); bms->projectCoordinatesToPlane(coordinatePlane); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } } } /** * called to add node. */ void GuiMainWindowSurfaceActions::slotEditAddNode() { theMainWindow->getBrainModelOpenGL()->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_EDIT_ADD_NODE); } /** * called to add tile. */ void GuiMainWindowSurfaceActions::slotEditAddTile() { theMainWindow->getBrainModelOpenGL()->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_EDIT_ADD_TILE); } /** * called to delete tile by link. */ void GuiMainWindowSurfaceActions::slotEditDeleteTileByLink() { theMainWindow->getBrainModelOpenGL()->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_EDIT_DELETE_TILE_BY_LINK); } /** * called to disconnect node. */ void GuiMainWindowSurfaceActions::slotEditDisconnectNode() { theMainWindow->getBrainModelOpenGL()->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_EDIT_DISCONNECT_NODE); } /** * called to move node. */ void GuiMainWindowSurfaceActions::slotEditMoveNode() { theMainWindow->getBrainModelOpenGL()->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_EDIT_MOVE_NODE); } /** * slot called to orient surface so node placed at screen center. */ void GuiMainWindowSurfaceActions::slotViewPlaceNodeAtCenterOfScreen() { BrainModelSurface* bms = theMainWindow->getBrainModelOpenGL()->getDisplayedBrainModelSurface(); if (bms != NULL) { bool ok = false; const int node = QInputDialog::getInteger(theMainWindow, "Orient to Node", "Node Number", 0, 0, 2147483647, 1, &ok); if (ok) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); bms->orientNodeToPositiveScreenZ(node, 0); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } } } /** * Called to scale the surface to fit the window. */ void GuiMainWindowSurfaceActions::slotViewScaleSurfaceToFitWindow() { BrainModelSurface* bms = theMainWindow->getBrainModelOpenGL()->getDisplayedBrainModelSurface(); if (bms != NULL) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); double left, right, bottom, top, nearOrtho, farOrtho; theMainWindow->getBrainModelOpenGL()->getOrthographicBox(left, right, bottom, top, nearOrtho, farOrtho); bms->setDefaultScaling(right, top); bms->setToStandardView(0, BrainModelSurface::VIEW_RESET); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } } /** * Called when adjust view selected. */ void GuiMainWindowSurfaceActions::slotViewAdjust() { BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { GuiSetViewDialog svd(theMainWindow, bms, 0); svd.exec(); } } /** * Called to save a user view */ void GuiMainWindowSurfaceActions::slotUserViewSaveView() { GuiUserViewSaveDialog uvsd(theMainWindow); uvsd.exec(); GuiMainWindowSurfaceMenu* surfaceMenu = theMainWindow->getMainWindowSurfaceMenu(); surfaceMenu->loadUserViewSwitchViewSubMenu(); } /** * Called to switch to a user view */ void GuiMainWindowSurfaceActions::slotUserViewSwitchToView(int item) { BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { PreferencesFile* pf = theMainWindow->getBrainSet()->getPreferencesFile(); const PreferencesFile::UserView* uv = pf->getUserView(item); if (uv != NULL) { QString name; float trans[3], scale[3], matrix[16]; bool transValid, scaleValid, matrixValid; uv->getViewInfo(name, matrix, trans, scale, matrixValid, transValid, scaleValid); if (matrixValid) { bms->setRotationMatrix(0, matrix); } if (transValid) { bms->setTranslation(0, trans); } if (scaleValid) { bms->setScaling(0, scale); } GuiBrainModelOpenGL::updateAllGL(); } } } /** * update the actions (typically called when menu is about to show) */ void GuiMainWindowSurfaceActions::updateActions() { // // Cuts sub menu items // DisplaySettingsCuts* dsc = theMainWindow->getBrainSet()->getDisplaySettingsCuts(); cutsShowAction->setChecked(dsc->getDisplayCuts()); ParamsFile* pf = theMainWindow->getBrainSet()->getParamsFile(); // // Edit sub menu items // DisplaySettingsSurface* dss = theMainWindow->getBrainSet()->getDisplaySettingsSurface(); bool nodesDisplayed = false; bool linksDisplayed = false; bool tilesDisplayed = false; switch (dss->getDrawMode()) { case DisplaySettingsSurface::DRAW_MODE_NODES: nodesDisplayed = true; break; case DisplaySettingsSurface::DRAW_MODE_LINKS: linksDisplayed = true; break; case DisplaySettingsSurface::DRAW_MODE_LINK_HIDDEN_LINE_REMOVAL: linksDisplayed = true; break; case DisplaySettingsSurface::DRAW_MODE_LINKS_EDGES_ONLY: linksDisplayed = true; break; case DisplaySettingsSurface::DRAW_MODE_NODES_AND_LINKS: nodesDisplayed = true; linksDisplayed = true; break; case DisplaySettingsSurface::DRAW_MODE_TILES: tilesDisplayed = true; break; case DisplaySettingsSurface::DRAW_MODE_TILES_WITH_LIGHT: tilesDisplayed = true; break; case DisplaySettingsSurface::DRAW_MODE_TILES_WITH_LIGHT_NO_BACK: tilesDisplayed = true; break; case DisplaySettingsSurface::DRAW_MODE_TILES_LINKS_NODES: tilesDisplayed = true; nodesDisplayed = true; linksDisplayed = true; break; case DisplaySettingsSurface::DRAW_MODE_NONE: break; } editAddNodeAction->setEnabled(nodesDisplayed); editAddTileAction->setEnabled(nodesDisplayed); editMoveNodeAction->setEnabled(nodesDisplayed); editDisconnectNodeAction->setEnabled(nodesDisplayed); // // Section sub menu items // SectionFile* sf = theMainWindow->getBrainSet()->getSectionFile(); const bool haveSections = (sf->getNumberOfColumns() > 0); sectionClearAllOrPartAction->setEnabled(haveSections); sectionControlAction->setEnabled(haveSections); // // Transform sub menu items // float acx, acy, acz; transformSubtractACAction->setEnabled( (pf->getParameter(ParamsFile::keyACx, acx) && pf->getParameter(ParamsFile::keyACy, acy) && pf->getParameter(ParamsFile::keyACz, acz))); } caret-5.6.4~dfsg.1.orig/caret/GuiMainWindowLayersMenu.h0000664000175000017500000000707511572067322022567 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_MAIN_WINDOW_LAYERS_MENU_H__ #define __GUI_MAIN_WINDOW_LAYERS_MENU_H__ #include #include "GuiMainWindowLayersActions.h" class GuiMainWindow; /// This class constructs the layers menu class GuiMainWindowLayersMenu : public QMenu { Q_OBJECT public: /// Constructor GuiMainWindowLayersMenu(GuiMainWindow* parent); /// Destructor ~GuiMainWindowLayersMenu(); protected: /// Create the border sub menu void createBordersSubMenu(GuiMainWindowLayersActions* layersActions); /// Create the foci sub menu void createFociSubMenu(GuiMainWindowLayersActions* layersActions); /// Create the cells sub menu void createCellsSubMenu(GuiMainWindowLayersActions* layersActions); /// Create the contours sub menu void createContoursSubMenu(GuiMainWindowLayersActions* layersActions); /// Create the contour cells sub menu void createContourCellsSubMenu(GuiMainWindowLayersActions* layersActions); /// Borders sub menu QMenu* bordersSubMenu; /// Cells sub menu QMenu* cellsSubMenu; /// Foci sub menu QMenu* fociSubMenu; /// Contours sub menu QMenu* contoursSubMenu; /// contours new set menu id int contourNewSetID; /// contours set scale menu id int contourSetScaleID; /// contours section menu id int contourSectionID; /// contours spacing menu id int contoursSpacingID; /// contours draw menu id int contoursDrawID; /// contours apply view menu id int contoursApplyViewID; /// contours align menu id int contoursAlignID; /// contours merge menu id int contourMergeID; /// contours move point menu id int contoursMovePointID; /// contours delete all menu id int contoursDeleteAllID; /// contours delete menu id int contoursDeleteID; /// contours delete point menu id int contoursDeletePointID; /// contours reconstruct menu id int contoursReconstructID; /// contour cells add menu id int contourCellsAddID; /// contour cells delete all menu id int contourCellsDeleteAllID; /// contour cells delete menu id int contourCellsDeleteWithMouseID; /// contour cells edit colors menu id int contourCellsEditColorsID; /// contour cells move menu id int contourCellsMoveWithMouseID; /// contour cells sub menu QMenu* contourCellsSubMenu; }; #endif // __GUI_MAIN_WINDOW_LAYERS_MENU_H__ caret-5.6.4~dfsg.1.orig/caret/GuiMainWindowLayersMenu.cxx0000664000175000017500000002342411572067322023136 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "DebugControl.h" #include "GuiMainWindow.h" #include "GuiMainWindowLayersActions.h" #include "GuiMainWindowLayersMenu.h" /** * Constructor. */ GuiMainWindowLayersMenu::GuiMainWindowLayersMenu(GuiMainWindow* parent) : QMenu("Layers", parent) { setObjectName("GuiMainWindowLayersMenu"); GuiMainWindowLayersActions* layersActions = parent->getLayersActions(); createBordersSubMenu(layersActions); createCellsSubMenu(layersActions); createContoursSubMenu(layersActions); createContourCellsSubMenu(layersActions); createFociSubMenu(layersActions); QObject::connect(this, SIGNAL(aboutToShow()), layersActions, SLOT(updateActions())); } /** * Destructor. */ GuiMainWindowLayersMenu::~GuiMainWindowLayersMenu() { } /** * Create the cell sub-menu. */ void GuiMainWindowLayersMenu::createCellsSubMenu(GuiMainWindowLayersActions* layersActions) { cellsSubMenu = addMenu("Cells"); cellsSubMenu->addAction(layersActions->getCellsAddAction()); cellsSubMenu->addSeparator(); cellsSubMenu->addAction(layersActions->getCellReportAction()); cellsSubMenu->addSeparator(); cellsSubMenu->addAction(layersActions->getCellsDensityToMetricAction()); cellsSubMenu->addAction(layersActions->getCellsConvertToVtkModelAction()); cellsSubMenu->addSeparator(); cellsSubMenu->addAction(layersActions->getCellsEditAttributesAction()); cellsSubMenu->addAction(layersActions->getCellsEditColorsAction()); cellsSubMenu->addAction(layersActions->getCellsProjectAction()); cellsSubMenu->addSeparator(); cellsSubMenu->addAction(layersActions->getCellsDeleteAllAction()); cellsSubMenu->addAction(layersActions->getCellsDeleteUsingMouseAction()); } /** * Create the foci sub-menu. */ void GuiMainWindowLayersMenu::createFociSubMenu(GuiMainWindowLayersActions* layersActions) { fociSubMenu = addMenu("Foci"); fociSubMenu->addAction(layersActions->getFociAssignClassToDisplayedFoci()); fociSubMenu->addAction(layersActions->getFociAttributeAssignmentAction()); fociSubMenu->addSeparator(); fociSubMenu->addAction(layersActions->getFociDensityToMetricAction()); fociSubMenu->addAction(layersActions->getFociDensityToVolumeAction()); fociSubMenu->addAction(layersActions->getFociUncertaintyLimitsAction()); fociSubMenu->addAction(layersActions->getFociConvertToVtkModelAction()); fociSubMenu->addSeparator(); fociSubMenu->addAction(layersActions->getFociClearHighlightingAction()); fociSubMenu->addSeparator(); fociSubMenu->addAction(layersActions->getFociReportAction()); fociSubMenu->addAction(layersActions->getFociAttributeReportAction()); fociSubMenu->addSeparator(); fociSubMenu->addAction(layersActions->getFociMapStereotaxicFocusAction()); fociSubMenu->addSeparator(); fociSubMenu->addAction(layersActions->getFociEditColorsAction()); fociSubMenu->addAction(layersActions->getFociDeleteNonMatchingColorsAction()); fociSubMenu->addSeparator(); fociSubMenu->addAction(layersActions->getFociProjectAction()); fociSubMenu->addAction(layersActions->getFociPalsProjectAction()); fociSubMenu->addAction(layersActions->getFociProjectToVolumeAction()); fociSubMenu->addSeparator(); fociSubMenu->addAction(layersActions->getFociDeleteAllAction()); fociSubMenu->addAction(layersActions->getFociDeleteNonDisplayedAction()); fociSubMenu->addAction(layersActions->getFociDeleteUsingMouseAction()); fociSubMenu->addSeparator(); fociSubMenu->addAction(layersActions->getFociUpdateClassesWithTableSubheaderShortNamesAction()); fociSubMenu->addAction(layersActions->getFociUpdatePubMedIDIfFocusNameMatchesStudyNameAction()); fociSubMenu->addAction(layersActions->getFociStudyInfoToStudyMetaDataFileAction()); } /** * Create the borders sub-menu */ void GuiMainWindowLayersMenu::createBordersSubMenu(GuiMainWindowLayersActions* layersActions) { bordersSubMenu = addMenu("Borders"); //if (DebugControl::getTestFlag1()) { bordersSubMenu->addAction(layersActions->getBorderOperationsDialogAction()); //} //bordersSubMenu->addAction(layersActions->getBordersCompareAction()); bordersSubMenu->addAction(layersActions->getBordersVolumeToBordersFiducialAction()); bordersSubMenu->addAction(layersActions->getBordersVolumeToFiducialCellsAction()); bordersSubMenu->addAction(layersActions->getBordersConvertToVtkModelAction()); bordersSubMenu->addSeparator(); bordersSubMenu->addAction(layersActions->getBordersAverageAction()); bordersSubMenu->addAction(layersActions->getBorderCreatedFromPaintAction()); bordersSubMenu->addAction(layersActions->getBordersCreateGridAction()); bordersSubMenu->addAction(layersActions->getBordersCreateAnalysisGridAction()); bordersSubMenu->addAction(layersActions->getBordersCreateInterpolatedAction()); bordersSubMenu->addAction(layersActions->getBordersCreateSphericalAction()); bordersSubMenu->addAction(layersActions->getBordersDrawAction()); bordersSubMenu->addAction(layersActions->getBorderDrawUpdateAction()); bordersSubMenu->addAction(layersActions->getCopyBorderByNameAction()); bordersSubMenu->addSeparator(); bordersSubMenu->addAction(layersActions->getBordersEditAttributesAction()); bordersSubMenu->addAction(layersActions->getBordersEditColorsAction()); bordersSubMenu->addSeparator(); bordersSubMenu->addAction(layersActions->getBordersClearHighlightingAction()); bordersSubMenu->addSeparator(); bordersSubMenu->addAction(layersActions->getBordersMovePointWithMouseAction()); bordersSubMenu->addAction(layersActions->getBordersRenameWithMouseAction()); bordersSubMenu->addAction(layersActions->getBordersReverseWithMouseAction()); bordersSubMenu->addSeparator(); bordersSubMenu->addAction(layersActions->getBordersOrientDisplayedClockwiseAction()); bordersSubMenu->addAction(layersActions->getBordersResampleDisplayedAction()); bordersSubMenu->addAction(layersActions->getBordersReverseDisplayedAction()); bordersSubMenu->addSeparator(); bordersSubMenu->addAction(layersActions->getBordersProjectAction()); bordersSubMenu->addSeparator(); bordersSubMenu->addAction(layersActions->getBordersDeleteAllAction()); bordersSubMenu->addAction(layersActions->getDeleteBordersByNameAction()); bordersSubMenu->addAction(layersActions->getBordersDeletePointWithMouseAction()); bordersSubMenu->addAction(layersActions->getBordersDeleteWithMouseAction()); bordersSubMenu->addAction(layersActions->getBordersDeletePointsOutsideSurfaceAction()); } /** * Create the contour cells sub-menu. */ void GuiMainWindowLayersMenu::createContourCellsSubMenu(GuiMainWindowLayersActions* layersActions) { contourCellsSubMenu = addMenu("Contour Cells"); contourCellsSubMenu->addAction(layersActions->getContourCellsAddAction()); contourCellsSubMenu->addSeparator(); contourCellsSubMenu->addAction(layersActions->getContourCellsDeleteAllAction()); contourCellsSubMenu->addAction(layersActions->getContourCellsDeleteWithMouseAction()); contourCellsSubMenu->addAction(layersActions->getContourCellsEditColorsAction()); contourCellsSubMenu->addAction(layersActions->getContourCellsMoveWithMouseAction()); } /** * Create the contours sub-menu. */ void GuiMainWindowLayersMenu::createContoursSubMenu(GuiMainWindowLayersActions* layersActions) { contoursSubMenu = addMenu("Contours"); contoursSubMenu->addAction(layersActions->getContourNewSetAction()); contoursSubMenu->addSeparator(); contoursSubMenu->addAction(layersActions->getContourInformationAction()); contoursSubMenu->addSeparator(); contoursSubMenu->addAction(layersActions->getContourSetScaleAction()); contoursSubMenu->addAction(layersActions->getContourSectionsAction()); contoursSubMenu->addAction(layersActions->getContourSpacingAction()); contoursSubMenu->addSeparator(); contoursSubMenu->addAction(layersActions->getContourDrawAction()); contoursSubMenu->addSeparator(); contoursSubMenu->addAction(layersActions->getContourApplyCurrentViewAction()); contoursSubMenu->addAction(layersActions->getContourAlignAction()); contoursSubMenu->addAction(layersActions->getContourMergeAction()); contoursSubMenu->addAction(layersActions->getContourMovePointAction()); contoursSubMenu->addAction(layersActions->getContourResampleAction()); contoursSubMenu->addAction(layersActions->getContourReverseAction()); contoursSubMenu->addSeparator(); contoursSubMenu->addAction(layersActions->getContourCleanUpAction()); contoursSubMenu->addAction(layersActions->getContourDeleteAllAction()); contoursSubMenu->addAction(layersActions->getContourDeleteAction()); contoursSubMenu->addAction(layersActions->getContourDeletePointAction()); contoursSubMenu->addSeparator(); contoursSubMenu->addAction(layersActions->getContourReconstructAction()); } caret-5.6.4~dfsg.1.orig/caret/GuiMainWindowLayersActions.h0000664000175000017500000006572611572067322023272 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_MAIN_WINDOW_LAYERS_ACTIONS_H__ #define __GUI_MAIN_WINDOW_LAYERS_ACTIONS_H__ #include class GuiMainWindow; class QAction; /// This class constructs the layers actions class GuiMainWindowLayersActions : public QObject { Q_OBJECT public: /// Constructor GuiMainWindowLayersActions(GuiMainWindow* parent); /// Destructor ~GuiMainWindowLayersActions(); /// action for border operations dialog QAction* getBorderOperationsDialogAction() { return borderOperationsDialogAction; } /// action for drawing borders QAction* getBordersDrawAction() { return bordersDrawAction; } /// action for converting volume borders to fiducial cells QAction* getBordersVolumeToFiducialCellsAction() { return bordersVolumeToFiducialCellsAction; } /// action for converting volume borders to fiducial borders QAction* getBordersVolumeToBordersFiducialAction() { return bordersVolumeToBordersFiducialAction; } /// action for creating average borders QAction* getBordersAverageAction() { return bordersAverageAction; } /// action for comparing borders QAction* getBordersCompareAction() { return bordersCompareAction; } /// action for creating borders from paint column QAction* getBorderCreatedFromPaintAction() { return bordersFromPaintAction; } /// action for creating grid borders QAction* getBordersCreateGridAction() { return bordersCreateGridAction; } /// action for creating analysis grid borders QAction* getBordersCreateAnalysisGridAction() { return bordersCreateAnalysisGridAction; } /// action for creating spherical borders QAction* getBordersCreateSphericalAction() { return bordersCreateSphericalAction; } /// action for converting borders to a VTK model QAction* getBordersConvertToVtkModelAction() { return bordersConvertToVtkModelAction; } /// action for editing border colors QAction* getBordersEditColorsAction() { return bordersEditColorsAction; } /// action for resampling displayed borders QAction* getBordersResampleDisplayedAction() { return bordersResampleDisplayedAction; } /// action for renaming borders selected with mouse QAction* getBordersRenameWithMouseAction() { return bordersRenameWithMouseAction; } /// action for reversing borders selected with mouse QAction* getBordersReverseWithMouseAction() { return bordersReverseWithMouseAction; } /// action for reversing displayed borders QAction* getBordersReverseDisplayedAction() { return bordersReverseDisplayedAction; } /// action for orient displayed borders clockwise QAction* getBordersOrientDisplayedClockwiseAction() { return bordersOrientDisplayedClockwiseAction; } /// action for projecting borders QAction* getBordersProjectAction() { return bordersProjectAction; } /// action for delete border point with mouse QAction* getBordersDeletePointWithMouseAction() { return bordersDeletePointWithMouseAction; } /// action for delete border with mouse QAction* getBordersDeleteWithMouseAction() { return bordersDeleteWithMouseAction; } /// action for deleting borders by name QAction* getDeleteBordersByNameAction() { return bordersDeleteByNameAction; } /// action for copy border by name QAction* getCopyBorderByNameAction() { return bordersCopyByNameAction; } /// action for draw border update QAction* getBorderDrawUpdateAction() { return borderDrawUpdateAction; } /// action for delete all borders QAction* getBordersDeleteAllAction() { return bordersDeleteAllAction; } /// action for move border point with mouse QAction* getBordersMovePointWithMouseAction() { return bordersMovePointWithMouseAction; } /// action for delete border points outside surface QAction* getBordersDeletePointsOutsideSurfaceAction() { return bordersDeletePointsOutsideSurfaceAction; } /// action for edit border attributes QAction* getBordersEditAttributesAction() { return bordersEditAttributesAction; } /// action for clear border highlights QAction* getBordersClearHighlightingAction() { return bordersClearHighlightingAction; } /// action for borders interpolate QAction* getBordersCreateInterpolatedAction() { return bordersCreateInterpolatedAction; } /// action for foci map stereotaxic focus QAction* getFociMapStereotaxicFocusAction() { return fociMapStereotaxicFocusAction; } /// action for converting foci to VTK model QAction* getFociConvertToVtkModelAction() { return fociConvertToVtkModelAction; } /// action for foci edit colors QAction* getFociEditColorsAction() { return fociEditColorsAction; } /// action for foci project QAction* getFociProjectAction() { return fociProjectAction; } /// action for foci project to volume QAction* getFociProjectToVolumeAction() { return fociProjectToVolumeAction; } /// action for foci PALS project QAction* getFociPalsProjectAction() { return fociPalsProjectAction; } /// action for foci delete all QAction* getFociDeleteAllAction() { return fociDeleteAllAction; } /// action for foci delete non-displayed QAction* getFociDeleteNonDisplayedAction() { return fociDeleteNonDisplayedAction; } /// action for foci non-matching color removal QAction* getFociDeleteNonMatchingColorsAction() { return fociDeleteNonMatchingColors; } /// action for foci delete using mouse QAction* getFociDeleteUsingMouseAction() { return fociDeleteUsingMouseAction; } /// action for foci assign class to displayed foci QAction* getFociAssignClassToDisplayedFoci() { return fociAssignClassToDisplayedFoci; } /// action for uncertainty limits to RGB paint dialog QAction* getFociUncertaintyLimitsAction() { return fociUncertaintyLimitsAction; } /// action for foci report QAction* getFociReportAction() { return fociReportAction; } /// action for foci attribute report QAction* getFociAttributeReportAction() { return fociAttributeReportAction; } /// action for converting foci density to metric QAction* getFociDensityToMetricAction() { return fociDensityToMetricAction; } /// action for converting foci density to volume QAction* getFociDensityToVolumeAction() { return fociDensityToVolumeAction; } /// action for foci attribute assignment QAction* getFociAttributeAssignmentAction() { return fociAttributeAssignmentAction; } /// action for foci clear highlighting QAction* getFociClearHighlightingAction() { return fociClearHighlightingAction; } /// foci convert foci file study info to study meta data file QAction* getFociStudyInfoToStudyMetaDataFileAction() { return fociStudyInfoToStudyMetaDataFileAction; } /// action for updating foci PubMed ID if focus name same as study name QAction* getFociUpdatePubMedIDIfFocusNameMatchesStudyNameAction() { return fociUpdatePubMedIDIfFocusNameMatchesStudyNameAction; } /// action for updating foci classes with table subheader short names QAction* getFociUpdateClassesWithTableSubheaderShortNamesAction() {return fociUpdateClassesWithTableSubheaderShortNamesAction; } /// action for converting cells to vtk model QAction* getCellsConvertToVtkModelAction() { return cellsConvertToVtkModelAction; } /// action for add cells QAction* getCellsAddAction() { return cellsAddAction; } /// action for cells QAction* getCellsEditColorsAction() { return cellsEditColorsAction; } /// action for cells QAction* getCellsProjectAction() { return cellsProjectAction; } /// action for cells QAction* getCellsDeleteAllAction() { return cellsDeleteAllAction; } /// action for cells QAction* getCellsEditAttributesAction() { return cellsEditAttributesAction; } /// action for cells QAction* getCellsDeleteUsingMouseAction() { return cellsDeleteUsingMouseAction; } /// action for converting cell density to metric QAction* getCellsDensityToMetricAction() { return cellsDensityToMetricAction; } /// action for cell report QAction* getCellReportAction() { return cellReportAction; } /// action for contour new set QAction* getContourNewSetAction() { return contourNewSetAction; } /// action for applying current view QAction* getContourApplyCurrentViewAction() { return contourApplyCurrentViewAction; } /// action for contour set scale QAction* getContourSetScaleAction() { return contourSetScaleAction; } /// action for contour select sections QAction* getContourSectionsAction() { return contourSectionsAction; } /// action for contour set spacing QAction* getContourSpacingAction() { return contourSpacingAction; } /// action for contour draw QAction* getContourDrawAction() { return contourDrawAction; } /// action for contour align QAction* getContourAlignAction() { return contourAlignAction; } /// action for contour merge QAction* getContourMergeAction() { return contourMergeAction; } /// action for contour move point QAction* getContourMovePointAction() { return contourMovePointAction; } /// action for contour delete all QAction* getContourDeleteAllAction() { return contourDeleteAllAction; } /// action for contour delete point QAction* getContourDeletePointAction() { return contourDeletePointAction; } /// action for contour delete contour QAction* getContourDeleteAction() { return contourDeleteAction; } /// action for contour reverse contour QAction* getContourReverseAction() { return contourReverseAction; } /// action for contour cleanup QAction* getContourCleanUpAction() { return contourCleanUpAction; } /// action for contour reconstruct into surface QAction* getContourReconstructAction() { return contourReconstructAction; } /// action for contour resample QAction* getContourResampleAction() { return contourResampleAction; } /// action for to add contour cells QAction* getContourCellsAddAction() { return contourCellsAddAction; } /// action for to delete contour cells with mouse QAction* getContourCellsDeleteWithMouseAction() { return contourCellsDeleteWithMouseAction; } /// action for to delete all contour cells QAction* getContourCellsDeleteAllAction() { return contourCellsDeleteAllAction; } /// action for to edit contour cell colors QAction* getContourCellsEditColorsAction() { return contourCellsEditColorsAction; } /// action for when contour move cell selected QAction* getContourCellsMoveWithMouseAction() { return contourCellsMoveWithMouseAction; } /// action for when contour information action selected QAction* getContourInformationAction() { return contourInformationAction; } public slots: /// update the actions (typically called when menu is about to show) void updateActions(); /// slot for converting volume borders to fiducial cells void slotBordersVolumeToFiducialCells(); /// slot for converting volume borders to fiducial borders void slotBordersVolumeToBordersFiducial(); /// slot for creating average borders void slotBordersAverage(); /// slot for comparing borders void slotBordersCompare(); /// slot for creating grid borders void slotBordersCreateGrid(); /// slot for creating analysis grid borders void slotBordersCreateAnalysisGrid(); /// slot for creating spherical borders void slotBordersCreateSpherical(); /// slot for converting borders to a VTK model void slotBordersConvertToVtkModel(); /// slot for editing border colors void slotBordersEditColors(); /// slot for resampling displayed borders void slotBordersResampleDisplayed(); /// slot for renaming borders selected with mouse void slotBordersRenameWithMouse(); /// slot for reversing borders selected with mouse void slotBordersReverseWithMouse(); /// slot for reversing displayed borders void slotBordersReverseDisplayed(); /// slot for orient displayed borders clockwise void slotBordersOrientDisplayedClockwise(); /// slot for projecting borders void slotBordersProject(); /// slot for delete border point with mouse void slotBordersDeletePointWithMouse(); /// slot for delete border with mouse void slotBordersDeleteWithMouse(); /// slot for deleting borders by name void slotDeleteBordersByName(); /// slot for copy borders by name void slotCopyBordersByName(); /// slot for delete all borders void slotBordersDeleteAll(); /// slot for borders from paint void slotBordersFromPaintAction(); /// slot for move border point with mouse void slotBordersMovePointWithMouse(); /// slot for delete border points outside surface void slotBordersDeletePointsOutsideSurface(); /// slot for edit border attributes void slotBordersEditAttributes(); /// slot for clear border highlighting void slotBordersClearHighlighting(); /// slot for creating interpolated borders void slotBordersCreateInterpolated(); /// slot for foci map stereotaxic focus void slotFociMapStereotaxicFocus(); /// slot for converting foci to VTK model void slotFociConvertToVtkModel(); /// slot for foci edit colors void slotFociEditColors(); /// slot for foci project void slotFociProject(); /// slot for foci project to volume void slotFociProjectToVolume(); /// slot for foci PALS project void slotFociPalsProject(); /// slot for foci delete all void slotFociDeleteAll(); /// slot for foci assign class name void slotFociAssignClassToDisplayedFoci(); /// slot for foci delete non-displayed void slotFociDeleteNonDisplayed(); /// slot for foci non-matching color deletion void slotFociDeleteNonMatchingColors(); /// slot for foci delete using mouse void slotFociDeleteUsingMouse(); /// slot for uncertainty limits to RGB paint dialog void slotFociUncertaintyLimits(); /// slot for foci report void slotFociReport(); /// slot for foci attribute report void slotFociAttributeReport(); /// slot for foci clear highlighting action void slotFociClearHighlighting(); /// slot for converting foci study info to study metadata void slotFociStudyInfoToStudyMetaDataFile(); /// slot for updating foci PubMed ID if focus name same as study name void slotFociUpdatePubMedIDIfFocusNameMatchesStudyName(); /// slot for updating foci classes with linked table subheader short names void slotFociUpdateClassWithTableSubheaderShortName(); /// slot for converting foci density to metric void slotFociDensityToMetric(); /// slot for converting foci density to functional volume void slotFociDensityToFunctionalVolume(); /// slot for converting cells to vtk model void slotCellsConvertToVtkModel(); /// slot for add cells void slotCellsAdd(); /// slot for cells void slotCellsEditColors(); /// slot for cells void slotCellsProject(); /// slot for cells void slotCellsDeleteAll(); /// slot for cells void slotCellsEditAttributes(); /// slot for cells void slotCellsDeleteUsingMouse(); /// slot for converting cell density to metric void slotCellsDensityToMetric(); /// slot for cell report void slotCellReport(); /// slot for contour new set void slotContourNewSet(); /// slot for contour clean up void slotContourCleanUp(); /// slot for applying current view void slotContourApplyCurrentView(); /// slot for contour set scale void slotContourSetScale(); /// slot for contour select sections void slotContourSections(); /// slot for contour set spacing void slotContourSpacing(); /// slot for contour draw void slotContourDraw(); /// slot for contour align void slotContourAlign(); /// slot for contour merge void slotContourMerge(); /// slot for contour move point void slotContourMovePoint(); /// slot for contour delete all void slotContourDeleteAll(); /// slot for contour delete point void slotContourDeletePoint(); /// slot for contour delete contour void slotContourDelete(); /// slot for contour point reversal void slotContourReverse(); /// slot for contour resampling void slotContourResample(); /// slot for contour reconstruct into surface void slotContourReconstruct(); /// slot called to add contour cells void slotContourCellsAdd(); /// slot called to delete contour cells with mouse void slotContourCellsDeleteWithMouse(); /// slot called to delete all contour cells void slotContourCellsDeleteAll(); /// slot called to edit contour cell colors void slotContourCellsEditColors(); /// slot called when contour move cell selected void slotContourCellsMoveWithMouse(); /// slot called when contour information selected void slotContourInformation(); protected slots: /// slot called when contour cell colors are changed void slotContourCellsColorsChanged(); /// slot used by border color editor void slotBorderColorsChanged(); /// slot called by foci color editor when colors are changed void slotFociColorsChanged(); /// slot for cells void slotCellsColorsChanged(); protected: /// action for border operations dialog QAction* borderOperationsDialogAction; /// action for drawing borders QAction* bordersDrawAction; /// slot for converting volume borders to fiducial cells QAction* bordersVolumeToFiducialCellsAction; /// slot for converting volume borders to fiducial borders QAction* bordersVolumeToBordersFiducialAction; /// slot for creating average borders QAction* bordersAverageAction; /// slot for comparing borders QAction* bordersCompareAction; /// slot for creating grid borders QAction* bordersCreateGridAction; /// slot for creating analysis grid borders QAction* bordersCreateAnalysisGridAction; /// slot for creating spherical borders QAction* bordersCreateSphericalAction; /// slot for converting borders to a VTK model QAction* bordersConvertToVtkModelAction; /// slot for borders from paint QAction* bordersFromPaintAction; /// slot for editing border colors QAction* bordersEditColorsAction; /// slot for resampling displayed borders QAction* bordersResampleDisplayedAction; /// slot for renaming borders selected with mouse QAction* bordersRenameWithMouseAction; /// slot for reversing borders selected with mouse QAction* bordersReverseWithMouseAction; /// slot for reversing displayed borders QAction* bordersReverseDisplayedAction; /// slot for orient displayed borders clockwise QAction* bordersOrientDisplayedClockwiseAction; /// slot for projecting borders QAction* bordersProjectAction; /// slot for delete border point with mouse QAction* bordersDeletePointWithMouseAction; /// slot for delete border with mouse QAction* bordersDeleteWithMouseAction; /// slot for deleting borders by name QAction* bordersDeleteByNameAction; /// slot for copying borders by name QAction* bordersCopyByNameAction; /// slot for delete all borders QAction* bordersDeleteAllAction; /// slot for border draw update QAction* borderDrawUpdateAction; /// slot for move border point with mouse QAction* bordersMovePointWithMouseAction; /// slot for delete border points outside surface QAction* bordersDeletePointsOutsideSurfaceAction; /// slot for edit border attributes QAction* bordersEditAttributesAction; /// slot for clear border highlighting QAction* bordersClearHighlightingAction; /// slot for borders interpolate QAction* bordersCreateInterpolatedAction; /// slot for foci map stereotaxic focus QAction* fociMapStereotaxicFocusAction; /// slot for converting foci to VTK model QAction* fociConvertToVtkModelAction; /// slot for foci edit colors QAction* fociEditColorsAction; /// slot for foci project QAction* fociProjectAction; /// slot for foci project to volume QAction* fociProjectToVolumeAction; /// slot for foci PALS projection QAction* fociPalsProjectAction; /// slot for foci delete all QAction* fociDeleteAllAction; /// for foci delete non displayed QAction* fociDeleteNonDisplayedAction; /// for foci assign class to displayed foci QAction* fociAssignClassToDisplayedFoci; /// for foci delete colors non-matching foci QAction* fociDeleteNonMatchingColors; /// slot for foci delete using mouse QAction* fociDeleteUsingMouseAction; /// slot for uncertainty limits to RGB paint dialog QAction* fociUncertaintyLimitsAction; /// slot for foci report QAction* fociReportAction; /// slot for foci attribute report QAction* fociAttributeReportAction; /// slot for converting foci density to metric QAction* fociDensityToMetricAction; /// slot for converting foci density to volume QAction* fociDensityToVolumeAction; /// foci attribute assignment action QAction* fociAttributeAssignmentAction; /// foci clear highlighting action QAction* fociClearHighlightingAction; /// foci convert foci file study info to study meta data file QAction* fociStudyInfoToStudyMetaDataFileAction; /// action for updating foci PubMed ID if focus name same as study name QAction* fociUpdatePubMedIDIfFocusNameMatchesStudyNameAction; /// action for updating foci classes with table subheader short names QAction* fociUpdateClassesWithTableSubheaderShortNamesAction; /// slot for converting cells to vtk model QAction* cellsConvertToVtkModelAction; /// slot for add cells QAction* cellsAddAction; /// slot for cells QAction* cellsEditColorsAction; /// slot for cells QAction* cellsProjectAction; /// slot for cells QAction* cellsDeleteAllAction; /// slot for cells QAction* cellsEditAttributesAction; /// slot for cells QAction* cellsDeleteUsingMouseAction; /// slot for converting cell density to metric QAction* cellsDensityToMetricAction; /// slot for cell report QAction* cellReportAction; /// slot for contour new set QAction* contourNewSetAction; /// slot for applying current view QAction* contourApplyCurrentViewAction; /// slot for contour set scale QAction* contourSetScaleAction; /// slot for contour select sections QAction* contourSectionsAction; /// slot for contour set spacing QAction* contourSpacingAction; /// slot for contour cleanup QAction* contourCleanUpAction; /// slot for contour draw QAction* contourDrawAction; /// slot for contour align QAction* contourAlignAction; /// slot for contour merge QAction* contourMergeAction; /// slot for contour move point QAction* contourMovePointAction; /// slot for contour delete all QAction* contourDeleteAllAction; /// slot for contour delete point QAction* contourDeletePointAction; /// slot for contour delete contour QAction* contourDeleteAction; /// slot for contour reverse contour QAction* contourReverseAction; /// slot for contour reconstruct into surface QAction* contourReconstructAction; /// contour resample action QAction* contourResampleAction; /// slot called to add contour cells QAction* contourCellsAddAction; /// slot called to delete contour cells with mouse QAction* contourCellsDeleteWithMouseAction; /// slot called to delete all contour cells QAction* contourCellsDeleteAllAction; /// slot called to edit contour cell colors QAction* contourCellsEditColorsAction; /// slot called when contour move cell selected QAction* contourCellsMoveWithMouseAction; /// contour information action QAction* contourInformationAction; }; #endif // __GUI_MAIN_WINDOW_LAYERS_ACTIONS_H__ caret-5.6.4~dfsg.1.orig/caret/GuiMainWindowLayersActions.cxx0000664000175000017500000031550411572067322023635 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include "BorderColorFile.h" #include "BrainModelBorderSet.h" #include "BrainModelContours.h" #include "BrainModelSurfacePointProjector.h" #include "BrainModelSurfacePaintToBorderConverter.h" #include "BrainSet.h" #include "BrainModelSurfaceCellDensityToMetric.h" #include "BrainModelVolumeFociDensity.h" #include "BrainModelVolumeFociUnprojector.h" #include "CellColorFile.h" #include "CellFile.h" #include "CellFileProjector.h" #include "CellProjectionFile.h" #include "ContourCellColorFile.h" #include "ContourCellFile.h" #include "DisplaySettingsBorders.h" #include "DisplaySettingsFoci.h" #include "DisplaySettingsPaint.h" #include "DisplaySettingsStudyMetaData.h" #include "FociColorFile.h" #include "FociFile.h" #include "FociProjectionFile.h" #include "GuiAverageBorderDialog.h" #include "GuiBorderAttributesDialog.h" #include "GuiBorderComparisonDialog.h" #include "GuiBorderProjectionDialog.h" #include "GuiBrainModelSelectionComboBox.h" #include "GuiCellAndFociAttributeAssignmentDialog.h" #include "GuiCellAndFociReportDialog.h" #include "GuiCellAttributesDialog.h" #include "GuiChooseNodeAttributeColumnDialog.h" #include "GuiColorFileEditorDialog.h" #include "GuiColorSelectionDialog.h" #include "GuiContourAlignmentDialog.h" #include "GuiContourDrawDialog.h" #include "GuiContourReconstructionDialog.h" #include "GuiContourSetScaleDialog.h" #include "GuiFilesModified.h" #include "GuiFociPalsProjectionDialog.h" #include "GuiFociUncertaintyLimitsDialog.h" #include "GuiBrainModelOpenGL.h" #include "GuiDeleteBordersByNameDialog.h" #include "GuiMainWindow.h" #include "GuiMainWindowLayersActions.h" #include "GuiMultipleInputDialog.h" #include "GuiCellsOrFociProjectionDialog.h" #include "GuiVolumeFileSelectionComboBox.h" #include "PaintFile.h" #include "QtTableDialog.h" #include "StringTable.h" #include "StudyMetaDataFile.h" #include "WuQDataEntryDialog.h" #include "WuQMessageBox.h" #include "global_variables.h" /** * Constructor. */ GuiMainWindowLayersActions::GuiMainWindowLayersActions(GuiMainWindow* parent) : QObject(parent) { setObjectName("GuiMainWindowLayersActions"); borderOperationsDialogAction = new QAction(parent); borderOperationsDialogAction->setText("Border Operations (In Development)..."); borderOperationsDialogAction->setObjectName("borderOperationsDialogAction"); QObject::connect(borderOperationsDialogAction, SIGNAL(triggered(bool)), parent, SLOT(displayBorderOperationsDialog())); bordersDrawAction = new QAction(parent); bordersDrawAction->setText("Draw Borders..."); bordersDrawAction->setObjectName("bordersDrawAction"); QObject::connect(bordersDrawAction, SIGNAL(triggered(bool)), parent, SLOT(displayDrawBorderDialog())); bordersVolumeToFiducialCellsAction = new QAction(parent); bordersVolumeToFiducialCellsAction->setText("Convert Volume Borders to Fiducial Cells"); bordersVolumeToFiducialCellsAction->setObjectName("bordersVolumeToFiducialCellsAction"); QObject::connect(bordersVolumeToFiducialCellsAction, SIGNAL(triggered(bool)), this, SLOT(slotBordersVolumeToFiducialCells())); bordersVolumeToBordersFiducialAction = new QAction(parent); bordersVolumeToBordersFiducialAction->setText("Convert Volume Borders to Fiducial Borders"); bordersVolumeToBordersFiducialAction->setObjectName("bordersVolumeToBordersFiducialAction"); QObject::connect(bordersVolumeToBordersFiducialAction, SIGNAL(triggered(bool)), this, SLOT(slotBordersVolumeToBordersFiducial())); bordersAverageAction = new QAction(parent); bordersAverageAction->setText("Create Average Borders..."); bordersAverageAction->setObjectName("bordersAverageAction"); QObject::connect(bordersAverageAction, SIGNAL(triggered(bool)), this, SLOT(slotBordersAverage())); bordersCompareAction = new QAction(parent); bordersCompareAction->setText("Compute Average Separation Between Border Point Pairs..."); bordersCompareAction->setObjectName("bordersCompareAction"); QObject::connect(bordersCompareAction, SIGNAL(triggered(bool)), this, SLOT(slotBordersCompare())); bordersFromPaintAction = new QAction(parent); bordersFromPaintAction->setText("Create Borders From Paint Regions..."); bordersFromPaintAction->setObjectName("bordersFromPaintAction"); QObject::connect(bordersFromPaintAction, SIGNAL(triggered(bool)), this, SLOT(slotBordersFromPaintAction())); bordersCreateGridAction = new QAction(parent); bordersCreateGridAction->setText("Create Cartesian Flat Grid Borders..."); bordersCreateGridAction->setObjectName("bordersCreateGridAction"); QObject::connect(bordersCreateGridAction, SIGNAL(triggered(bool)), this, SLOT(slotBordersCreateGrid())); bordersCreateAnalysisGridAction = new QAction(parent); bordersCreateAnalysisGridAction->setText("Create Cartesian Flat Analysis Grid Borders..."); bordersCreateAnalysisGridAction->setObjectName("bordersCreateAnalysisGridAction"); QObject::connect(bordersCreateAnalysisGridAction, SIGNAL(triggered(bool)), this, SLOT(slotBordersCreateAnalysisGrid())); bordersCreateSphericalAction = new QAction(parent); bordersCreateSphericalAction->setText("Create Lat/Lon Spherical Borders"); bordersCreateSphericalAction->setObjectName("bordersCreateSphericalAction"); QObject::connect(bordersCreateSphericalAction, SIGNAL(triggered(bool)), this, SLOT(slotBordersCreateSpherical())); bordersConvertToVtkModelAction = new QAction(parent); bordersConvertToVtkModelAction->setText("Convert Displayed Borders to VTK Model"); bordersConvertToVtkModelAction->setObjectName("bordersConvertToVtkModelAction"); QObject::connect(bordersConvertToVtkModelAction, SIGNAL(triggered(bool)), this, SLOT(slotBordersConvertToVtkModel())); bordersEditColorsAction = new QAction(parent); bordersEditColorsAction->setText("Edit Border Colors..."); bordersEditColorsAction->setObjectName("bordersEditColorsAction"); QObject::connect(bordersEditColorsAction, SIGNAL(triggered(bool)), this, SLOT(slotBordersEditColors())); bordersResampleDisplayedAction = new QAction(parent); bordersResampleDisplayedAction->setText("Resample Displayed Borders..."); bordersResampleDisplayedAction->setObjectName("bordersResampleDisplayedAction"); QObject::connect(bordersResampleDisplayedAction, SIGNAL(triggered(bool)), this, SLOT(slotBordersResampleDisplayed())); bordersRenameWithMouseAction = new QAction(parent); bordersRenameWithMouseAction->setText("Rename Borders With Mouse"); bordersRenameWithMouseAction->setObjectName("bordersRenameWithMouseAction"); QObject::connect(bordersRenameWithMouseAction, SIGNAL(triggered(bool)), this, SLOT(slotBordersRenameWithMouse())); bordersReverseWithMouseAction = new QAction(parent); bordersReverseWithMouseAction->setText("Reverse Borders With Mouse"); bordersReverseWithMouseAction->setObjectName("bordersReverseWithMouseAction"); QObject::connect(bordersReverseWithMouseAction, SIGNAL(triggered(bool)), this, SLOT(slotBordersReverseWithMouse())); bordersReverseDisplayedAction = new QAction(parent); bordersReverseDisplayedAction->setText("Reverse Displayed Borders"); bordersReverseDisplayedAction->setObjectName("bordersReverseDisplayedAction"); QObject::connect(bordersReverseDisplayedAction, SIGNAL(triggered(bool)), this, SLOT(slotBordersReverseDisplayed())); bordersOrientDisplayedClockwiseAction = new QAction(parent); bordersOrientDisplayedClockwiseAction->setText("Orient Displayed Borders Clockwise"); bordersOrientDisplayedClockwiseAction->setObjectName("bordersOrientDisplayedClockwiseAction"); QObject::connect(bordersOrientDisplayedClockwiseAction, SIGNAL(triggered(bool)), this, SLOT(slotBordersOrientDisplayedClockwise())); bordersProjectAction = new QAction(parent); bordersProjectAction->setText("Project Borders..."); bordersProjectAction->setObjectName("bordersProjectAction"); QObject::connect(bordersProjectAction, SIGNAL(triggered(bool)), this, SLOT(slotBordersProject())); bordersDeletePointWithMouseAction = new QAction(parent); bordersDeletePointWithMouseAction->setText("Delete Border Point With Mouse"); bordersDeletePointWithMouseAction->setObjectName("bordersDeletePointWithMouseAction"); QObject::connect(bordersDeletePointWithMouseAction, SIGNAL(triggered(bool)), this, SLOT(slotBordersDeletePointWithMouse())); bordersDeleteWithMouseAction = new QAction(parent); bordersDeleteWithMouseAction->setText("Delete Border With Mouse"); bordersDeleteWithMouseAction->setObjectName("bordersDeleteWithMouseAction"); QObject::connect(bordersDeleteWithMouseAction, SIGNAL(triggered(bool)), this, SLOT(slotBordersDeleteWithMouse())); bordersDeleteByNameAction = new QAction(parent); bordersDeleteByNameAction->setText("Delete Borders By Name..."); bordersDeleteByNameAction->setObjectName("bordersDeleteByNameAction"); QObject::connect(bordersDeleteByNameAction, SIGNAL(triggered(bool)), this, SLOT(slotDeleteBordersByName())); bordersCopyByNameAction = new QAction(parent); bordersCopyByNameAction->setText("Duplicate Border By Name..."); bordersCopyByNameAction->setObjectName("bordersCopyByNameAction"); QObject::connect(bordersCopyByNameAction, SIGNAL(triggered(bool)), this, SLOT(slotCopyBordersByName())); bordersDeleteAllAction = new QAction(parent); bordersDeleteAllAction->setText("Delete All Borders..."); bordersDeleteAllAction->setObjectName("bordersDeleteAllAction"); QObject::connect(bordersDeleteAllAction, SIGNAL(triggered(bool)), this, SLOT(slotBordersDeleteAll())); bordersMovePointWithMouseAction = new QAction(parent); bordersMovePointWithMouseAction->setText("Move Border Point With Mouse"); bordersMovePointWithMouseAction->setObjectName("bordersMovePointWithMouseAction"); QObject::connect(bordersMovePointWithMouseAction, SIGNAL(triggered(bool)), this, SLOT(slotBordersMovePointWithMouse())); bordersDeletePointsOutsideSurfaceAction = new QAction(parent); bordersDeletePointsOutsideSurfaceAction->setText("Delete Border Points Outside Surface"); bordersDeletePointsOutsideSurfaceAction->setObjectName("bordersDeletePointsOutsideSurfaceAction"); QObject::connect(bordersDeletePointsOutsideSurfaceAction, SIGNAL(triggered(bool)), this, SLOT(slotBordersDeletePointsOutsideSurface())); bordersEditAttributesAction = new QAction(parent); bordersEditAttributesAction->setText("Edit Border Attributes..."); bordersEditAttributesAction->setObjectName("bordersEditAttributesAction"); QObject::connect(bordersEditAttributesAction, SIGNAL(triggered(bool)), this, SLOT(slotBordersEditAttributes())); bordersClearHighlightingAction = new QAction(parent); bordersClearHighlightingAction->setText("Clear Border Highlighting"); bordersClearHighlightingAction->setObjectName("bordersClearHighlightingAction"); QObject::connect(bordersClearHighlightingAction, SIGNAL(triggered(bool)), this, SLOT(slotBordersClearHighlighting())); bordersCreateInterpolatedAction = new QAction(parent); bordersCreateInterpolatedAction->setText("Create Interpolated Borders..."); bordersCreateInterpolatedAction->setObjectName("bordersCreateInterpolatedAction"); QObject::connect(bordersCreateInterpolatedAction, SIGNAL(triggered(bool)), this, SLOT(slotBordersCreateInterpolated())); borderDrawUpdateAction = new QAction(parent); borderDrawUpdateAction->setText("Draw Border Update..."); borderDrawUpdateAction->setObjectName("borderDrawUpdateAction"); QObject::connect(borderDrawUpdateAction, SIGNAL(triggered(bool)), parent, SLOT(displayBorderDrawUpdateDialog())); fociMapStereotaxicFocusAction = new QAction(parent); fociMapStereotaxicFocusAction->setText("Map Stereotaxic Focus..."); fociMapStereotaxicFocusAction->setObjectName("fociMapStereotaxicFocusAction"); QObject::connect(fociMapStereotaxicFocusAction, SIGNAL(triggered(bool)), this, SLOT(slotFociMapStereotaxicFocus())); fociConvertToVtkModelAction = new QAction(parent); fociConvertToVtkModelAction->setText("Convert Displayed Foci to VTK Model"); fociConvertToVtkModelAction->setObjectName("fociConvertToVtkModelAction"); QObject::connect(fociConvertToVtkModelAction, SIGNAL(triggered(bool)), this, SLOT(slotFociConvertToVtkModel())); fociEditColorsAction = new QAction(parent); fociEditColorsAction->setText("Edit Foci Colors..."); fociEditColorsAction->setObjectName("fociEditColorsAction"); QObject::connect(fociEditColorsAction, SIGNAL(triggered(bool)), this, SLOT(slotFociEditColors())); fociProjectAction = new QAction(parent); fociProjectAction->setText("Project Fiducial Foci..."); fociProjectAction->setObjectName("fociProjectAction"); QObject::connect(fociProjectAction, SIGNAL(triggered(bool)), this, SLOT(slotFociProject())); fociProjectToVolumeAction = new QAction(parent); fociProjectToVolumeAction->setText("Unproject Foci to Volume..."); fociProjectToVolumeAction->setObjectName("fociProjectToVolumeAction"); QObject::connect(fociProjectToVolumeAction, SIGNAL(triggered(bool)), this, SLOT(slotFociProjectToVolume())); fociPalsProjectAction = new QAction(parent); fociPalsProjectAction->setText("Project Foci To PALS Atlas..."); fociPalsProjectAction->setObjectName("fociPalsProjectAction"); QObject::connect(fociPalsProjectAction, SIGNAL(triggered(bool)), this, SLOT(slotFociPalsProject())); fociDeleteAllAction = new QAction(parent); fociDeleteAllAction->setText("Delete All Foci..."); fociDeleteAllAction->setObjectName("fociDeleteAllAction"); QObject::connect(fociDeleteAllAction, SIGNAL(triggered(bool)), this, SLOT(slotFociDeleteAll())); fociAssignClassToDisplayedFoci = new QAction(parent); fociAssignClassToDisplayedFoci->setText("Assign Class to Displayed Foci..."); fociAssignClassToDisplayedFoci->setObjectName("fociAssignClassToDisplayedFoci"); QObject::connect(fociAssignClassToDisplayedFoci, SIGNAL(triggered(bool)), this, SLOT(slotFociAssignClassToDisplayedFoci())); fociDeleteNonDisplayedAction = new QAction(parent); fociDeleteNonDisplayedAction->setText("Delete Foci Not Displayed due to Display Control Selections..."); fociDeleteNonDisplayedAction->setObjectName("fociDeleteNonDisplayedAction"); QObject::connect(fociDeleteNonDisplayedAction, SIGNAL(triggered(bool)), this, SLOT(slotFociDeleteNonDisplayed())); fociDeleteNonMatchingColors = new QAction(parent); fociDeleteNonMatchingColors->setText("Delete Foci Colors Not Matching Foci..."); fociDeleteNonMatchingColors->setObjectName("fociDeleteNonMatchingColors"); QObject::connect(fociDeleteNonMatchingColors, SIGNAL(triggered(bool)), this, SLOT(slotFociDeleteNonMatchingColors())); fociDeleteUsingMouseAction = new QAction(parent); fociDeleteUsingMouseAction->setText("Delete Focus Using Mouse"); fociDeleteUsingMouseAction->setObjectName("fociDeleteUsingMouseAction"); QObject::connect(fociDeleteUsingMouseAction, SIGNAL(triggered(bool)), this, SLOT(slotFociDeleteUsingMouse())); fociUncertaintyLimitsAction = new QAction(parent); fociUncertaintyLimitsAction->setText("Convert Uncertainty Limits to RGB Paint..."); fociUncertaintyLimitsAction->setObjectName("fociUncertaintyLimitsAction"); QObject::connect(fociUncertaintyLimitsAction, SIGNAL(triggered(bool)), this, SLOT(slotFociUncertaintyLimits())); fociReportAction = new QAction(parent); fociReportAction->setText("Foci Report..."); fociReportAction->setObjectName("fociReportAction"); QObject::connect(fociReportAction, SIGNAL(triggered(bool)), this, SLOT(slotFociReport())); fociAttributeReportAction = new QAction(parent); fociAttributeReportAction->setText("Foci Attribute Report..."); fociAttributeReportAction->setObjectName("fociAttributeReportAction"); QObject::connect(fociAttributeReportAction, SIGNAL(triggered(bool)), this, SLOT(slotFociAttributeReport())); fociAttributeAssignmentAction = new QAction(parent); fociAttributeAssignmentAction->setText("Attribute Assignment..."); fociAttributeAssignmentAction->setObjectName("fociAttributeAssigmentAction"); QObject::connect(fociAttributeAssignmentAction, SIGNAL(triggered(bool)), parent, SLOT(displayFociAttributeAssignmentDialog())); fociStudyInfoToStudyMetaDataFileAction = new QAction(parent); fociStudyInfoToStudyMetaDataFileAction->setText("Move Foci Study Info to Study Metadata File"); fociStudyInfoToStudyMetaDataFileAction->setObjectName("fociStudyInfoToStudyMetaDataFileAction"); QObject::connect(fociStudyInfoToStudyMetaDataFileAction, SIGNAL(triggered(bool)), this, SLOT(slotFociStudyInfoToStudyMetaDataFile())); fociUpdatePubMedIDIfFocusNameMatchesStudyNameAction = new QAction(parent); fociUpdatePubMedIDIfFocusNameMatchesStudyNameAction->setText("Update Focus' PubMed ID if Focus Name Matches Study Name"); fociUpdatePubMedIDIfFocusNameMatchesStudyNameAction->setObjectName("fociUpdatePubMedIDIfFocusNameMatchesStudyNameAction"); QObject::connect(fociUpdatePubMedIDIfFocusNameMatchesStudyNameAction, SIGNAL(triggered(bool)), this, SLOT(slotFociUpdatePubMedIDIfFocusNameMatchesStudyName())); fociUpdateClassesWithTableSubheaderShortNamesAction = new QAction(parent); fociUpdateClassesWithTableSubheaderShortNamesAction->setText("Update Focus' Class Name With Table/Fig/Page Short Names"); fociUpdateClassesWithTableSubheaderShortNamesAction->setObjectName("fociUpdateClassesWithTableSubheaderShortNames"); QObject::connect(fociUpdateClassesWithTableSubheaderShortNamesAction, SIGNAL(triggered(bool)), this, SLOT(slotFociUpdateClassWithTableSubheaderShortName())); fociClearHighlightingAction = new QAction(parent); fociClearHighlightingAction->setText("Clear Foci Highlighting"); fociClearHighlightingAction->setObjectName("fociClearHighlightingAction"); QObject::connect(fociClearHighlightingAction, SIGNAL(triggered(bool)), this, SLOT(slotFociClearHighlighting())); cellsConvertToVtkModelAction = new QAction(parent); cellsConvertToVtkModelAction->setText("Convert Displayed Cells to VTK Model"); cellsConvertToVtkModelAction->setObjectName("cellsConvertToVtkModelAction"); QObject::connect(cellsConvertToVtkModelAction, SIGNAL(triggered(bool)), this, SLOT(slotCellsConvertToVtkModel())); cellsAddAction = new QAction(parent); cellsAddAction->setText("Add Cells With Mouse..."); cellsAddAction->setObjectName("cellsAddAction"); QObject::connect(cellsAddAction, SIGNAL(triggered(bool)), this, SLOT(slotCellsAdd())); cellsEditColorsAction = new QAction(parent); cellsEditColorsAction->setText("Edit Cell Colors..."); cellsEditColorsAction->setObjectName("cellsEditColorsAction"); QObject::connect(cellsEditColorsAction, SIGNAL(triggered(bool)), this, SLOT(slotCellsEditColors())); fociDensityToMetricAction = new QAction(parent); fociDensityToMetricAction->setText("Convert Foci Density to Metric..."); fociDensityToMetricAction->setObjectName("fociDensityToMetricAction"); QObject::connect(fociDensityToMetricAction, SIGNAL(triggered(bool)), this, SLOT(slotFociDensityToMetric())); fociDensityToVolumeAction = new QAction(parent); fociDensityToVolumeAction->setText("Convert Foci Density to Functional Volume..."); fociDensityToVolumeAction->setObjectName("fociDensityToVolumeAction"); QObject::connect(fociDensityToVolumeAction, SIGNAL(triggered(bool)), this, SLOT(slotFociDensityToFunctionalVolume())); cellsProjectAction = new QAction(parent); cellsProjectAction->setText("Project Fiducial Cells..."); cellsProjectAction->setObjectName("cellsProjectAction"); QObject::connect(cellsProjectAction, SIGNAL(triggered(bool)), this, SLOT(slotCellsProject())); cellsDeleteAllAction = new QAction(parent); cellsDeleteAllAction->setText("Delete All Cells..."); cellsDeleteAllAction->setObjectName("cellsDeleteAllAction"); QObject::connect(cellsDeleteAllAction, SIGNAL(triggered(bool)), this, SLOT(slotCellsDeleteAll())); cellsEditAttributesAction = new QAction(parent); cellsEditAttributesAction->setText("Edit Cell Attributes"); cellsEditAttributesAction->setObjectName("cellsEditAttributesAction"); QObject::connect(cellsEditAttributesAction, SIGNAL(triggered(bool)), this, SLOT(slotCellsEditAttributes())); cellsDeleteUsingMouseAction = new QAction(parent); cellsDeleteUsingMouseAction->setText("Delete Cells Using Mouse"); cellsDeleteUsingMouseAction->setObjectName("cellsDeleteUsingMouseAction"); QObject::connect(cellsDeleteUsingMouseAction, SIGNAL(triggered(bool)), this, SLOT(slotCellsDeleteUsingMouse())); cellsDensityToMetricAction = new QAction(parent); cellsDensityToMetricAction->setText("Convert Cell Density to Metric..."); cellsDensityToMetricAction->setObjectName("cellsDensityToMetricAction"); QObject::connect(cellsDensityToMetricAction, SIGNAL(triggered(bool)), this, SLOT(slotCellsDensityToMetric())); cellReportAction = new QAction(parent); cellReportAction->setText("Cell Report..."); cellReportAction->setObjectName("cellReportAction"); QObject::connect(cellReportAction, SIGNAL(triggered(bool)), this, SLOT(slotCellReport())); contourNewSetAction = new QAction(parent); contourNewSetAction->setText("Create New Contour Set"); contourNewSetAction->setObjectName("contourNewSetAction"); QObject::connect(contourNewSetAction, SIGNAL(triggered(bool)), this, SLOT(slotContourNewSet())); contourApplyCurrentViewAction = new QAction(parent); contourApplyCurrentViewAction->setText("Apply Current View"); contourApplyCurrentViewAction->setObjectName("contourApplyCurrentViewAction"); QObject::connect(contourApplyCurrentViewAction, SIGNAL(triggered(bool)), this, SLOT(slotContourApplyCurrentView())); contourSetScaleAction = new QAction(parent); contourSetScaleAction->setText("Set Contour Scale..."); contourSetScaleAction->setObjectName("contourSetScaleAction"); QObject::connect(contourSetScaleAction, SIGNAL(triggered(bool)), this, SLOT(slotContourSetScale())); contourSectionsAction = new QAction(parent); contourSectionsAction->setText("Select Contour Sections..."); contourSectionsAction->setObjectName("contourSectionsAction"); QObject::connect(contourSectionsAction, SIGNAL(triggered(bool)), this, SLOT(slotContourSections())); contourSpacingAction = new QAction(parent); contourSpacingAction->setText("Set Contour Section Spacing..."); contourSpacingAction->setObjectName("contourSpacingAction"); QObject::connect(contourSpacingAction, SIGNAL(triggered(bool)), this, SLOT(slotContourSpacing())); contourDrawAction = new QAction(parent); contourDrawAction->setText("Draw Contours..."); contourDrawAction->setObjectName("contourDrawAction"); QObject::connect(contourDrawAction, SIGNAL(triggered(bool)), this, SLOT(slotContourDraw())); contourAlignAction = new QAction(parent); contourAlignAction->setText("Align Contours..."); contourAlignAction->setObjectName("contourAlignAction"); QObject::connect(contourAlignAction, SIGNAL(triggered(bool)), this, SLOT(slotContourAlign())); contourMergeAction = new QAction(parent); contourMergeAction->setText("Merge Contours"); contourMergeAction->setObjectName("contourMergeAction"); QObject::connect(contourMergeAction, SIGNAL(triggered(bool)), this, SLOT(slotContourMerge())); contourMovePointAction = new QAction(parent); contourMovePointAction->setText("Move Contour Point With Mouse"); contourMovePointAction->setObjectName("contourMovePointAction"); QObject::connect(contourMovePointAction, SIGNAL(triggered(bool)), this, SLOT(slotContourMovePoint())); contourDeleteAllAction = new QAction(parent); contourDeleteAllAction->setText("Delete All Contours..."); contourDeleteAllAction->setObjectName("contourDeleteAllAction"); QObject::connect(contourDeleteAllAction, SIGNAL(triggered(bool)), this, SLOT(slotContourDeleteAll())); contourReverseAction = new QAction(parent); contourReverseAction->setText("Reverse Contour With Mouse"); contourReverseAction->setObjectName("contourReverseAction"); QObject::connect(contourReverseAction, SIGNAL(triggered(bool)), this, SLOT(slotContourReverse())); contourDeletePointAction = new QAction(parent); contourDeletePointAction->setText("Delete Contour Point With Mouse"); contourDeletePointAction->setObjectName("contourDeletePointAction"); QObject::connect(contourDeletePointAction, SIGNAL(triggered(bool)), this, SLOT(slotContourDeletePoint())); contourDeleteAction = new QAction(parent); contourDeleteAction->setText("Delete Contour With Mouse"); contourDeleteAction->setObjectName("contourDeleteAction"); QObject::connect(contourDeleteAction, SIGNAL(triggered(bool)), this, SLOT(slotContourDelete())); contourReconstructAction = new QAction(parent); contourReconstructAction->setText("Reconstruct Into Surface..."); contourReconstructAction->setObjectName("contourReconstructAction"); QObject::connect(contourReconstructAction, SIGNAL(triggered(bool)), this, SLOT(slotContourReconstruct())); contourResampleAction = new QAction(parent); contourResampleAction->setText("Resample All Contours..."); contourResampleAction->setObjectName("contourResampleAction"); QObject::connect(contourResampleAction, SIGNAL(triggered(bool)), this, SLOT(slotContourResample())); contourCleanUpAction = new QAction(parent); contourCleanUpAction->setText("Cleanup Contours"); contourCleanUpAction->setObjectName("contourCleanUpAction"); QObject::connect(contourCleanUpAction, SIGNAL(triggered(bool)), this, SLOT(slotContourCleanUp())); contourCellsAddAction = new QAction(parent); contourCellsAddAction->setText("Add Contour Cells..."); contourCellsAddAction->setObjectName("contourCellsAddAction"); QObject::connect(contourCellsAddAction, SIGNAL(triggered(bool)), this, SLOT(slotContourCellsAdd())); contourCellsDeleteWithMouseAction = new QAction(parent); contourCellsDeleteWithMouseAction->setText("Delete Contour Cells With Mouse"); contourCellsDeleteWithMouseAction->setObjectName("contourCellsDeleteWithMouseAction"); QObject::connect(contourCellsDeleteWithMouseAction, SIGNAL(triggered(bool)), this, SLOT(slotContourCellsDeleteWithMouse())); contourCellsDeleteAllAction = new QAction(parent); contourCellsDeleteAllAction->setText("Delete All Contour Cells..."); contourCellsDeleteAllAction->setObjectName("contourCellsDeleteAllAction"); QObject::connect(contourCellsDeleteAllAction, SIGNAL(triggered(bool)), this, SLOT(slotContourCellsDeleteAll())); contourCellsEditColorsAction = new QAction(parent); contourCellsEditColorsAction->setText("Edit Contour Cell Colors..."); contourCellsEditColorsAction->setObjectName("contourCellsEditColorsAction"); QObject::connect(contourCellsEditColorsAction, SIGNAL(triggered(bool)), this, SLOT(slotContourCellsEditColors())); contourCellsMoveWithMouseAction = new QAction(parent); contourCellsMoveWithMouseAction->setText("Move Contour Cells With Mouse"); contourCellsMoveWithMouseAction->setObjectName("contourCellsMoveWithMouseAction"); QObject::connect(contourCellsMoveWithMouseAction, SIGNAL(triggered(bool)), this, SLOT(slotContourCellsMoveWithMouse())); contourInformationAction = new QAction(parent); contourInformationAction->setText("Contour Information..."); contourInformationAction->setObjectName("contourInformationAction"); QObject::connect(contourInformationAction, SIGNAL(triggered(bool)), this, SLOT(slotContourInformation())); } /** * Destructor. */ GuiMainWindowLayersActions::~GuiMainWindowLayersActions() { } /** * slot for cell report. */ void GuiMainWindowLayersActions::slotCellReport() { GuiCellAndFociReportDialog cfrd(theMainWindow, false); cfrd.exec(); cfrd.close(); QtTableDialog* tableDialog = cfrd.getResultsTableDialog(); if (tableDialog != NULL) { tableDialog->show(); tableDialog->activateWindow(); } } /** * slot for converting cells to vtk model. */ void GuiMainWindowLayersActions::slotCellsConvertToVtkModel() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainModelSurface* bms = theMainWindow->getBrainModelOpenGL()->getDisplayedBrainModelSurface(); if (bms != NULL) { theMainWindow->getBrainSet()->convertDisplayedCellsToVtkModel(bms); GuiFilesModified fm; fm.setVtkModelModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } QApplication::restoreOverrideCursor(); } /** * Slot to display add cells dialog. */ void GuiMainWindowLayersActions::slotCellsAdd() { theMainWindow->getAddCellsDialog(true); } /** * Slot for converting cell density to metric. */ void GuiMainWindowLayersActions::slotCellsDensityToMetric() { BrainSet* bs = theMainWindow->getBrainSet(); BrainModelSurface* flatSurface = theMainWindow->getBrainModelSurface(); if (flatSurface->getIsFlatSurface() == false) { QMessageBox::critical(theMainWindow, "ERROR", "The surface in the main window must be flat."); } static float gridSpacing = 5.0; bool valid = false; gridSpacing = QInputDialog::getDouble(theMainWindow, "Cell Density", "Grid Spacing", gridSpacing, 0.001, 10000000.0, 3, &valid); if (valid) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainModelSurfaceCellDensityToMetric cdm(bs, flatSurface, bs->getCellProjectionFile(), bs->getMetricFile(), gridSpacing, true); try { cdm.execute(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(theMainWindow, "ERROR", e.whatQString()); } // // Notify that metrics have changed and update display // GuiFilesModified fm; fm.setMetricModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); theMainWindow->speakText("Cell density has been created.", false); } } /** * Slot for Edit Cell Colors Dialog */ void GuiMainWindowLayersActions::slotCellsEditColors() { GuiColorFileEditorDialog* gfed = new GuiColorFileEditorDialog(theMainWindow, theMainWindow->getBrainSet()->getCellColorFile(), true, true, false, true, false); QObject::connect(gfed, SIGNAL(redrawRequested()), this, SLOT(slotCellsColorsChanged())); gfed->show(); } /** * This slot is called by the color editor when user pressed apply or dialog is closed. */ void GuiMainWindowLayersActions::slotCellsColorsChanged() { GuiFilesModified fm; fm.setCellColorModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } /** * Slot for Project Cells */ void GuiMainWindowLayersActions::slotCellsProject() { GuiCellsOrFociProjectionDialog pd(theMainWindow, GuiCellsOrFociProjectionDialog::FILE_TYPE_CELL); pd.exec(); } /** * Slot for Delete Cells By Name */ void GuiMainWindowLayersActions::slotCellsEditAttributes() { GuiCellAttributesDialog* cad = new GuiCellAttributesDialog(theMainWindow); cad->show(); } /** * Slot for Delete All Cells */ void GuiMainWindowLayersActions::slotCellsDeleteAll() { if (QMessageBox::warning(theMainWindow, "Delete All Cells", "Are you sure you want to delete all cells?", (QMessageBox::Yes | QMessageBox::No), QMessageBox::Yes) == QMessageBox::Yes) { theMainWindow->getBrainSet()->deleteAllCells(true, true); GuiFilesModified fm; fm.setCellModified(); fm.setCellProjectionModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } } /** * Slot for Delete Cells Using Mouse */ void GuiMainWindowLayersActions::slotCellsDeleteUsingMouse() { theMainWindow->getBrainModelOpenGL()->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_CELL_DELETE); } /** * slot for updating foci classes with linked table subheader short names. */ void GuiMainWindowLayersActions::slotFociUpdateClassWithTableSubheaderShortName() { if (QMessageBox::question(theMainWindow, "Confirm", "Update foci classes with linked figure/page ref/table?", (QMessageBox::Yes | QMessageBox::No), QMessageBox::Yes) == QMessageBox::Yes) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainSet* bs = theMainWindow->getBrainSet(); FociProjectionFile* fpf = bs->getFociProjectionFile(); StudyMetaDataFile* smdf = bs->getStudyMetaDataFile(); fpf->updateCellClassWithLinkedTableFigureOrPageReference(smdf); GuiFilesModified fm; fm.setFociModified(); theMainWindow->fileModificationUpdate(fm); QApplication::restoreOverrideCursor(); } } /** * slot for updating foci PubMed ID if focus name same as study name. */ void GuiMainWindowLayersActions::slotFociUpdatePubMedIDIfFocusNameMatchesStudyName() { if (QMessageBox::question(theMainWindow, "Confirm", "Update foci's PubMed IDs if the focus\nname matches the name of a study?", (QMessageBox::Yes | QMessageBox::No), QMessageBox::Yes) == QMessageBox::Yes) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainSet* bs = theMainWindow->getBrainSet(); FociProjectionFile* fpf = bs->getFociProjectionFile(); StudyMetaDataFile* smdf = bs->getStudyMetaDataFile(); fpf->updatePubMedIDIfCellNameMatchesStudyName(smdf); GuiFilesModified fm; fm.setFociModified(); theMainWindow->fileModificationUpdate(fm); QApplication::restoreOverrideCursor(); } } /** * slot for converting foci study info to study metadata. */ void GuiMainWindowLayersActions::slotFociStudyInfoToStudyMetaDataFile() { theMainWindow->getBrainSet()->moveFociStudyInfoToStudyMetaDataFile(); GuiFilesModified fm; fm.setFociModified(); fm.setStudyMetaDataModified(); theMainWindow->fileModificationUpdate(fm); const QString msg("The StudyInfo from the Foci Projection File has been moved\n" "to the Study Metadata File. As a result, both the \n" "StudyMetaData and Foci Projection Files need to be saved."); QMessageBox::information(theMainWindow, "INFO", msg); } /** * slot for foci clear highlighting action. */ void GuiMainWindowLayersActions::slotFociClearHighlighting() { FociProjectionFile* fpf = theMainWindow->getBrainSet()->getFociProjectionFile(); fpf->clearAllHighlightFlags(); GuiBrainModelOpenGL::updateAllGL(); } /** * slot for converting foci density to functional volume. */ void GuiMainWindowLayersActions::slotFociDensityToFunctionalVolume() { QStringList unitLabels; QList unitValues; unitLabels.append("Foci per Cubic Centimeter"); unitValues.append(static_cast(BrainModelVolumeFociDensity::DENSITY_UNITS_FOCI_PER_CUBIC_CENTIMETER)); unitLabels.append("Foci per Cubic Millimeter"); unitValues.append(static_cast(BrainModelVolumeFociDensity::DENSITY_UNITS_FOCI_PER_CUBIC_MILLIMETER)); WuQDataEntryDialog ded(theMainWindow); ded.setWindowTitle("Foci Density to Volume"); GuiVolumeFileSelectionComboBox* volumeSelectionComboBox = new GuiVolumeFileSelectionComboBox(VolumeFile::VOLUME_TYPE_FUNCTIONAL); ded.addWidget("Functional Volume", volumeSelectionComboBox); QDoubleSpinBox* roiSizeDoubleSpinBox = ded.addDoubleSpinBox("ROI Size for Density (MM)", 3.0); roiSizeDoubleSpinBox->setSingleStep(2.0); QComboBox* unitsComboBox = ded.addComboBox("Units", unitLabels, &unitValues); if (ded.exec() == WuQDataEntryDialog::Accepted) { try { const BrainModelVolumeFociDensity::DENSITY_UNITS units = static_cast( unitsComboBox->itemData(unitsComboBox->currentIndex()).toInt()); BrainSet* brainSet = theMainWindow->getBrainSet(); QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainModelVolumeFociDensity bmvfd(brainSet, brainSet->getFociProjectionFile(), roiSizeDoubleSpinBox->value(), units, volumeSelectionComboBox->getSelectedVolumeFile()); bmvfd.execute(); QApplication::restoreOverrideCursor(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(theMainWindow, "ERROR", e.whatQString()); } GuiFilesModified fm; fm.setVolumeModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } } /** * Slot for converting foci density to metric. */ void GuiMainWindowLayersActions::slotFociDensityToMetric() { BrainSet* bs = theMainWindow->getBrainSet(); BrainModelSurface* flatSurface = theMainWindow->getBrainModelSurface(); if (flatSurface->getIsFlatSurface() == false) { QMessageBox::critical(theMainWindow, "ERROR", "The surface in the main window must be flat."); return; } static float gridSpacing = 5.0; bool valid = false; gridSpacing = QInputDialog::getDouble(theMainWindow, "Foci Density", "Grid Spacing", gridSpacing, 0.001, 10000000.0, 3, &valid); if (valid) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainModelSurfaceCellDensityToMetric cdm(bs, flatSurface, bs->getFociProjectionFile(), bs->getMetricFile(), gridSpacing, true); try { cdm.execute(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(theMainWindow, "ERROR", e.whatQString()); } // // Notify that metrics have changed and update display // GuiFilesModified fm; fm.setMetricModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } } /** * slot for foci report. */ void GuiMainWindowLayersActions::slotFociReport() { GuiCellAndFociReportDialog cfrd(theMainWindow, true); cfrd.exec(); cfrd.close(); QtTableDialog* tableDialog = cfrd.getResultsTableDialog(); if (tableDialog != NULL) { tableDialog->show(); tableDialog->activateWindow(); } } /** * slot for foci attribute report. */ void GuiMainWindowLayersActions::slotFociAttributeReport() { WuQDataEntryDialog ded(theMainWindow); ded.setWindowTitle("Foci Attribute Report"); QRadioButton* fociClassRadioButton = ded.addRadioButton("Class"); QRadioButton* fociColorRadioButton = ded.addRadioButton("Color"); QRadioButton* fociKeywordRadioButton = ded.addRadioButton("Keyword"); QRadioButton* fociNameRadioButton = ded.addRadioButton("Name"); QRadioButton* fociTableRadioButton = ded.addRadioButton("Table"); fociClassRadioButton->setChecked(true); if (ded.exec() == WuQDataEntryDialog::Accepted) { bool displayedFociOnlyFlag = true; std::vector names; QString noneMessage("There are no "); QString title; std::vector numberOfFociAssociatedWithItem; FociProjectionFile* fpf = theMainWindow->getBrainSet()->getFociProjectionFile(); if (fociClassRadioButton->isChecked()) { std::vector sortedFociClassIndices; fpf->getCellClassIndicesSortedByName(sortedFociClassIndices, false, displayedFociOnlyFlag); const int numValidFociClasses = static_cast(sortedFociClassIndices.size()); if (numValidFociClasses > 0) { for (int i = 0; i < numValidFociClasses; i++) { const int classIndex = sortedFociClassIndices[i]; names.push_back(fpf->getCellClassNameByIndex(classIndex)); } // // Count the foci using each class // numberOfFociAssociatedWithItem.resize(numValidFociClasses, 0); const int numFoci = fpf->getNumberOfCellProjections(); for (int i = 0; i < numFoci; i++) { bool useIt = true; const CellProjection* focus = fpf->getCellProjection(i); if (displayedFociOnlyFlag) { useIt = focus->getDisplayFlag(); } if (useIt) { const int classIndex = focus->getClassIndex(); for (int j = 0; j < numValidFociClasses; j++) { if (sortedFociClassIndices[j] == classIndex) { numberOfFociAssociatedWithItem[j]++; break; } } } } } noneMessage += "foci classes."; title = "Foci Classes"; } else if (fociColorRadioButton->isChecked()) { FociColorFile* fcf = theMainWindow->getBrainSet()->getFociColorFile(); std::vector sortedFociColorIndices; fcf->getColorIndicesSortedByName(theMainWindow->getBrainSet()->getFociProjectionFile(), sortedFociColorIndices, false, displayedFociOnlyFlag); const int numValidFociColors = static_cast(sortedFociColorIndices.size()); if (numValidFociColors > 0) { for (int i = 0; i < numValidFociColors; i++) { const int colorIndex = sortedFociColorIndices[i]; names.push_back(fcf->getColorNameByIndex(colorIndex)); } // // Count the foci using each color // numberOfFociAssociatedWithItem.resize(numValidFociColors, 0); const int numFoci = fpf->getNumberOfCellProjections(); for (int i = 0; i < numFoci; i++) { bool useIt = true; const CellProjection* focus = fpf->getCellProjection(i); if (displayedFociOnlyFlag) { useIt = focus->getDisplayFlag(); } if (useIt) { const int colorIndex = focus->getColorIndex(); for (int j = 0; j < numValidFociColors; j++) { if (sortedFociColorIndices[j] == colorIndex) { numberOfFociAssociatedWithItem[j]++; break; } } } } } noneMessage += "foci colors."; title = "Foci Colors"; } else if (fociKeywordRadioButton->isChecked()) { DisplaySettingsStudyMetaData* dssmd = theMainWindow->getBrainSet()->getDisplaySettingsStudyMetaData(); std::vector keywords; std::vector numberOfFociUsingKeyword; dssmd->getKeywordsAndUsageByFoci(keywords, numberOfFociUsingKeyword); names = keywords; numberOfFociAssociatedWithItem = numberOfFociUsingKeyword; /* const int numValidKeywords = static_cast(keywords.size()); if (numValidKeywords > 0) { for (int i = 0; i < numValidKeywords; i++) { const int keywordIndex = sortedFociKeywordIndices[i]; names.push_back(dssmd->getKeywordNameByIndex(keywordIndex)); } // SLOW!!! // // Count the foci using each keyword // numberOfFociAssociatedWithItem.resize(numValidKeywords, 0); const int numFoci = fpf->getNumberOfCellProjections(); for (int m = 0; m < numValidKeywords; m++) { const QString keyword = names[m]; for (int i = 0; i < numFoci; i++) { bool useIt = true; const CellProjection* focus = fpf->getCellProjection(i); if (displayedFociOnlyFlag) { useIt = focus->getDisplayFlag(); } if (useIt) { StudyMetaDataLinkSet smdls = focus->getStudyMetaDataLinkSet(); for (int j = 0; j < smdls.getNumberOfStudyMetaDataLinks(); j++) { StudyMetaDataLink smdl = smdls.getStudyMetaDataLink(j); const int studyIndex = smdf->getStudyIndexFromLink(smdl); StudyMetaData* smd = smdf->getStudyMetaData(studyIndex); if (smd->containsKeyword(keyword)) { numberOfFociAssociatedWithItem[m]++; break; } } } } } } */ noneMessage += "study keywords."; title = "Study Keywords"; } else if (fociNameRadioButton->isChecked()) { std::vector sortedFociUniqueNameIndices; fpf->getCellUniqueNameIndicesSortedByName(sortedFociUniqueNameIndices, false, displayedFociOnlyFlag); const int numValidNames = static_cast(sortedFociUniqueNameIndices.size()); if (numValidNames > 0) { for (int i = 0; i < numValidNames; i++) { const int nameIndex = sortedFociUniqueNameIndices[i]; names.push_back(fpf->getCellUniqueNameByIndex(nameIndex)); } // // Count the foci using each name // numberOfFociAssociatedWithItem.resize(numValidNames, 0); const int numFoci = fpf->getNumberOfCellProjections(); for (int i = 0; i < numFoci; i++) { bool useIt = true; const CellProjection* focus = fpf->getCellProjection(i); if (displayedFociOnlyFlag) { useIt = focus->getDisplayFlag(); } if (useIt) { const QString name = focus->getName(); for (int j = 0; j < numValidNames; j++) { if (name == names[j]) { numberOfFociAssociatedWithItem[j]++; break; } } } } } noneMessage += "foci."; title = "Foci Names"; } else if (fociTableRadioButton->isChecked()) { DisplaySettingsStudyMetaData* dssmd = theMainWindow->getBrainSet()->getDisplaySettingsStudyMetaData(); std::vector subheaders; std::vector numberOfFociUsingKeyword; dssmd->getSubheadersAndUsageByFoci(subheaders, numberOfFociUsingKeyword); names = subheaders; numberOfFociAssociatedWithItem = numberOfFociUsingKeyword; noneMessage += "tables with subheaders."; title = "Table Subheaders"; } const int numNames = names.size(); if (numNames > 0) { StringTable st(numNames, 2, (title + " Report")); st.setColumnTitle(0, "Focus\nCount"); st.setColumnTitle(1, title); const int num = static_cast(names.size()); const bool doCountsFlag = (num == static_cast(numberOfFociAssociatedWithItem.size())); for (int i = 0; i < num; i++) { if (doCountsFlag) { st.setElement(i, 0, numberOfFociAssociatedWithItem[i]); } st.setElement(i, 1, names[i]); } QtTableDialog* td = new QtTableDialog(theMainWindow, "Foci Attribute Report.", st, true); td->show(); } else { WuQMessageBox::critical(theMainWindow, "ERROR", noneMessage); return; } } } /** * slot for converting foci to VTK model. */ void GuiMainWindowLayersActions::slotFociConvertToVtkModel() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainModelSurface* bms = theMainWindow->getBrainModelOpenGL()->getDisplayedBrainModelSurface(); if (bms != NULL) { theMainWindow->getBrainSet()->convertDisplayedFociToVtkModel(bms); GuiFilesModified fm; fm.setVtkModelModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } QApplication::restoreOverrideCursor(); } /** * Slot for Map Stereotaxic Focus Dialog */ void GuiMainWindowLayersActions::slotFociMapStereotaxicFocus() { theMainWindow->getMapStereotaxicFocusDialog(true); } /** * Slot for uncertainty limits to rgb paint dialog. */ void GuiMainWindowLayersActions::slotFociUncertaintyLimits() { GuiFociUncertaintyLimitsDialog* fuld = new GuiFociUncertaintyLimitsDialog(theMainWindow); fuld->exec(); } /** * Slot for Edit Foci Colors Dialog */ void GuiMainWindowLayersActions::slotFociEditColors() { GuiColorFileEditorDialog* gfed = new GuiColorFileEditorDialog(theMainWindow, theMainWindow->getBrainSet()->getFociColorFile(), true, true, false, true, false); QObject::connect(gfed, SIGNAL(redrawRequested()), this, SLOT(slotFociColorsChanged())); gfed->show(); } /** * This slot is called by the color editor when user pressed apply or dialog is closed. */ void GuiMainWindowLayersActions::slotFociColorsChanged() { GuiFilesModified fm; fm.setFociColorModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } /** * Slot for Project Foci */ void GuiMainWindowLayersActions::slotFociProject() { GuiCellsOrFociProjectionDialog pd(theMainWindow, GuiCellsOrFociProjectionDialog::FILE_TYPE_FOCI); pd.exec(); } /** * Slot for Project Foci */ void GuiMainWindowLayersActions::slotFociPalsProject() { GuiFociPalsProjectionDialog pd(theMainWindow); pd.exec(); } /** * slot for foci project to volume. */ void GuiMainWindowLayersActions::slotFociProjectToVolume() { // // Right, left, and cerebellum surface selection combo boxes // GuiBrainModelSelectionComboBox* leftSurfaceComboBox = new GuiBrainModelSelectionComboBox( GuiBrainModelSelectionComboBox::OPTION_SHOW_SURFACES_ALL | GuiBrainModelSelectionComboBox::OPTION_SHOW_ADD_NEW, "NONE"); leftSurfaceComboBox->setSelectedBrainModelToFirstSurfaceOfType( BrainModelSurface::SURFACE_TYPE_FIDUCIAL, Structure::STRUCTURE_TYPE_CORTEX_LEFT); GuiBrainModelSelectionComboBox* rightSurfaceComboBox = new GuiBrainModelSelectionComboBox( GuiBrainModelSelectionComboBox::OPTION_SHOW_SURFACES_ALL | GuiBrainModelSelectionComboBox::OPTION_SHOW_ADD_NEW, "NONE"); rightSurfaceComboBox->setSelectedBrainModelToFirstSurfaceOfType( BrainModelSurface::SURFACE_TYPE_FIDUCIAL, Structure::STRUCTURE_TYPE_CORTEX_RIGHT); GuiBrainModelSelectionComboBox* cerebellumSurfaceComboBox = new GuiBrainModelSelectionComboBox( GuiBrainModelSelectionComboBox::OPTION_SHOW_SURFACES_ALL | GuiBrainModelSelectionComboBox::OPTION_SHOW_ADD_NEW, "NONE"); cerebellumSurfaceComboBox->setSelectedBrainModelToFirstSurfaceOfType( BrainModelSurface::SURFACE_TYPE_FIDUCIAL, Structure::STRUCTURE_TYPE_CEREBELLUM); // // Create dialog for projecting the foci to the volume // WuQDataEntryDialog ftv(theMainWindow); ftv.setTextAtTop("The selected surfaces will be used to unproject " "the foci and determine the coordinates for " "display of foci in the volume. For this to " "function correctly, the foci must have been " "projected to the surfaces.", true); ftv.setWindowTitle("Unproject Foci to Volume"); ftv.addWidget("Left ", leftSurfaceComboBox); ftv.addWidget("Right ", rightSurfaceComboBox); ftv.addWidget("Cerebellum ", cerebellumSurfaceComboBox); if (ftv.exec() == WuQDataEntryDialog::Accepted) { // // Get the selected surfaces // BrainModelSurface* leftBMS = leftSurfaceComboBox->getSelectedBrainModelSurface(); BrainModelSurface* rightBMS = rightSurfaceComboBox->getSelectedBrainModelSurface(); BrainModelSurface* cerebellumBMS = cerebellumSurfaceComboBox->getSelectedBrainModelSurface(); // // Project foci to volume // BrainModelVolumeFociUnprojector bmvfu(theMainWindow->getBrainSet(), leftBMS, rightBMS, cerebellumBMS, theMainWindow->getBrainSet()->getFociProjectionFile()); try { bmvfu.execute(); } catch (BrainModelAlgorithmException& e) { QMessageBox::critical(theMainWindow, "ERROR", e.whatQString()); } // // Update GUI // GuiFilesModified fm; fm.setFociModified(); fm.setFociProjectionModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } } /** * Slot for Delete All Foci */ void GuiMainWindowLayersActions::slotFociDeleteAll() { if (QMessageBox::warning(theMainWindow, "Delete All Foci", "Are you sure you want to delete all foci?", (QMessageBox::Yes | QMessageBox::No), QMessageBox::No) == QMessageBox::Yes) { theMainWindow->getBrainSet()->deleteAllFociProjections(); GuiFilesModified fm; fm.setFociModified(); fm.setFociProjectionModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } } /** * slot for foci assign class name. */ void GuiMainWindowLayersActions::slotFociAssignClassToDisplayedFoci() { bool ok = false; const QString name = QInputDialog::getText(theMainWindow, "Assign Class Name to Displayed Foci", "Class Name", QLineEdit::Normal, "", &ok); if (ok) { FociProjectionFile* fpf = theMainWindow->getBrainSet()->getFociProjectionFile(); fpf->assignClassToDisplayedFoci(name); // // Find the matching color // bool fociColorMatch = false; FociColorFile* fociColorFile = theMainWindow->getBrainSet()->getFociColorFile(); const int fociColorIndex = fociColorFile->getColorIndexByName(name, fociColorMatch); // // Foci color may need to be created // bool createFociColor = false; if ((fociColorIndex >= 0) && (fociColorMatch == true)) { createFociColor = false; } else if ((fociColorIndex >= 0) && (fociColorMatch == false)) { QString msg("Use foci color \""); msg.append(fociColorFile->getColorNameByIndex(fociColorIndex)); msg.append("\" for focus "); msg.append(name); msg.append(" ?"); const QString noButtonText("No, define color " + name); QMessageBox msgBox(theMainWindow); msgBox.setWindowTitle("Use Partially Matching Color"); msgBox.setText(msg); msgBox.addButton("Yes", QMessageBox::YesRole); QPushButton* noPushButton = msgBox.addButton(noButtonText, QMessageBox::NoRole); msgBox.exec(); if (msgBox.clickedButton() == noPushButton) { createFociColor = true; } } else { createFociColor = true; } if (createFociColor) { QString title("Create Focus Color: "); title.append(name); GuiColorSelectionDialog* csd = new GuiColorSelectionDialog(theMainWindow, title, false, false, false, false); csd->exec(); // // Add new foci color // float pointSize = 2.0, lineSize = 1.0; unsigned char r, g, b, a; ColorFile::ColorStorage::SYMBOL symbol; csd->getColorInformation(r, g, b, a, pointSize, lineSize, symbol); fociColorFile->addColor(name, r, g, b, a, pointSize, lineSize, symbol); } GuiFilesModified fm; fm.setFociModified(); fm.setFociColorModified(); fm.setFociProjectionModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } } /** * Slot for Delete Non-Dispalyed Foci */ void GuiMainWindowLayersActions::slotFociDeleteNonDisplayed() { Structure structure; BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { structure = bms->getStructure(); } QMessageBox msgBox(theMainWindow); QString msg("Delete foci not displayed due to Display Control Settings."); QPushButton* yesPushButton = msgBox.addButton("Yes", QMessageBox::YesRole); QPushButton* yesStructurePushButton = NULL; if ((structure.getType() == Structure::STRUCTURE_TYPE_CORTEX_LEFT) || (structure.getType() == Structure::STRUCTURE_TYPE_CORTEX_RIGHT) || (structure.getType() == Structure::STRUCTURE_TYPE_CEREBELLUM)) { yesStructurePushButton = msgBox.addButton("Yes, Not on Main Window Surface", QMessageBox::YesRole); msg += ("\n" "You may also remove those not associated with main window surface."); } QPushButton* noPushButton = msgBox.addButton("No", QMessageBox::YesRole); msgBox.setText(msg); msgBox.setWindowTitle("Confirm Foci Deletion"); msgBox.exec(); if (msgBox.clickedButton() != noPushButton) { if (msgBox.clickedButton() == yesPushButton) { structure = Structure::STRUCTURE_TYPE_INVALID; } FociProjectionFile* fpf = theMainWindow->getBrainSet()->getFociProjectionFile(); fpf->deleteAllNonDisplayedCellProjections(structure); GuiFilesModified fm; fm.setFociModified(); fm.setFociProjectionModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } } /** * slot for foci non-matching color deletion. */ void GuiMainWindowLayersActions::slotFociDeleteNonMatchingColors() { if (QMessageBox::warning(theMainWindow, "Delete Non-Matching Foci Colors", "Are you sure you want to delete\n" "all foci colors that do not match\n" "the names of any foci?", (QMessageBox::Yes | QMessageBox::No), QMessageBox::Yes) == QMessageBox::Yes) { const FociProjectionFile* fpf = theMainWindow->getBrainSet()->getFociProjectionFile(); FociColorFile* fcf = theMainWindow->getBrainSet()->getFociColorFile(); fcf->removeNonMatchingColors(fpf); GuiFilesModified fm; fm.setFociColorModified(); fm.setFociProjectionModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } } /** * Slot for Delete Foci Using Mouse */ void GuiMainWindowLayersActions::slotFociDeleteUsingMouse() { theMainWindow->getBrainModelOpenGL()->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_FOCI_DELETE); } /** * slot for borders from paint. */ void GuiMainWindowLayersActions::slotBordersFromPaintAction() { BrainSet* bs = theMainWindow->getBrainSet(); GuiChooseNodeAttributeColumnDialog cnacd(theMainWindow, GUI_NODE_FILE_TYPE_PAINT, "", false, false); DisplaySettingsPaint* dsp = bs->getDisplaySettingsPaint(); const int columnNumber = dsp->getFirstSelectedColumnForBrainModel(0); cnacd.setSelectedColumnNumber(columnNumber); if (cnacd.exec() == GuiChooseNodeAttributeColumnDialog::Accepted) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainModelSurfacePaintToBorderConverter ptb(bs, theMainWindow->getBrainModelSurface(), bs->getPaintFile(), cnacd.getSelectedColumnNumber()); try { ptb.execute(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(theMainWindow, "ERROR", e.whatQString()); } DisplaySettingsBorders* dsb = bs->getDisplaySettingsBorders(); dsb->setDisplayBorders(true); GuiFilesModified fm; fm.setBorderModified(); fm.setBorderColorModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } } /** * slot for converting borders to a VTK model. */ void GuiMainWindowLayersActions::slotBordersConvertToVtkModel() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainModelSurface* bms = theMainWindow->getBrainModelOpenGL()->getDisplayedBrainModelSurface(); if (bms != NULL) { theMainWindow->getBrainSet()->convertDisplayedBordersToVtkModel(bms); GuiFilesModified fm; fm.setVtkModelModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } QApplication::restoreOverrideCursor(); } /** * slot for comparing borders. */ void GuiMainWindowLayersActions::slotBordersCompare() { static GuiBorderComparisonDialog* bcd = NULL; if (bcd == NULL) { bcd = new GuiBorderComparisonDialog(theMainWindow); } bcd->show(); bcd->activateWindow(); } /** * slot for converting volume borders to fiducial borders. */ void GuiMainWindowLayersActions::slotBordersVolumeToBordersFiducial() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); bmbs->copyVolumeBordersToFiducialBorders(); theMainWindow->getBrainSet()->assignBorderColors(); GuiFilesModified fm; fm.setBorderModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } /** * slot for converting volume borders to fiducial cells. */ void GuiMainWindowLayersActions::slotBordersVolumeToFiducialCells() { theMainWindow->getBrainSet()->convertVolumeBordersToFiducialCells(); GuiFilesModified fm; fm.setCellModified(); fm.setCellColorModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } /** * slot for creating average borders. */ void GuiMainWindowLayersActions::slotBordersAverage() { static GuiAverageBorderDialog* abd = NULL; if (abd == NULL) { abd = new GuiAverageBorderDialog(theMainWindow); } abd->show(); abd->activateWindow(); } /** * slot for deleting borders by name. */ void GuiMainWindowLayersActions::slotDeleteBordersByName() { GuiDeleteBordersByNameDialog dbn(theMainWindow); dbn.exec(); } /** * slot for copy borders by name. */ void GuiMainWindowLayersActions::slotCopyBordersByName() { // // Get names of all borders // BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); std::vector allNames; bmbs->getAllBorderNames(allNames, false); if (allNames.empty()) { QMessageBox::critical(theMainWindow, "ERROR", "There are no borders loaded."); return; } QStringList namesSL; for (unsigned int i = 0; i < allNames.size(); i++) { namesSL += allNames[i]; } // // Create dialog for copying a border // WuQDataEntryDialog ded(theMainWindow); QComboBox* nameComboBox = ded.addComboBox("Name to Copy", namesSL); QLineEdit* newNameLineEdit = ded.addLineEditWidget("New Name"); QObject::connect(nameComboBox, SIGNAL(activated(const QString&)), newNameLineEdit, SLOT(setText(const QString&))); if (ded.exec() == WuQDataEntryDialog::Accepted) { const QString oldName = nameComboBox->currentText(); const QString newName = newNameLineEdit->text().trimmed(); if (newName.isEmpty()) { QMessageBox::critical(theMainWindow, "ERROR", "New Name is empty."); return; } if (oldName == newName) { QMessageBox::critical(theMainWindow, "ERROR", "The old and new names are the same."); return; } std::vector borderIndices; bmbs->getAllBordersWithName(oldName, borderIndices); const int numOldNames = static_cast(borderIndices.size()); if (numOldNames == 0) { QMessageBox::critical(theMainWindow, "ERROR", "No border name selected for copying."); return; } if (numOldNames > 1) { if (QMessageBox::question(theMainWindow, "Confirm", "There is more than one border named \"" + oldName + ". Do you want to copy all of them?" " If no, you will need to delete the duplcates that already exist " "and then select this menu item.", (QMessageBox::Yes | QMessageBox::No), QMessageBox::Yes) == QMessageBox::No) { return; } } for (int i = 0; i < numOldNames; i++) { bmbs->copyBorder(borderIndices[i], newName); } theMainWindow->getBrainSet()->assignBorderColors(); GuiFilesModified fm; fm.setBorderModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } } /** * slot for projecting borders */ void GuiMainWindowLayersActions::slotBordersProject() { GuiBorderProjectionDialog bpd(theMainWindow); bpd.exec(); } /** * slot for create cartesian grid borders */ void GuiMainWindowLayersActions::slotBordersCreateGrid() { BrainModelSurface* bms = theMainWindow->getBrainModelOpenGL()->getDisplayedBrainModelSurface(); if (bms != NULL) { // // See if a flat surface is in the main window // BrainModelSurface::SURFACE_TYPES st = bms->getSurfaceType(); if ((st != BrainModelSurface::SURFACE_TYPE_FLAT) && (st != BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR)) { QMessageBox::critical(theMainWindow, "Surface Type", "The surface in the main window must be flat for this operation !!!"); return; } BorderFile borderFile; std::vector labels; labels.push_back("Grid Spacing (mm)"); labels.push_back("Points per Grid Square"); GuiMultipleInputDialog mid(theMainWindow, "Create Cartesian Grid Borders", labels); mid.setLineEdit(0, 50.0f); mid.setLineEdit(1, 5); if (mid.exec() == QDialog::Accepted) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); float gridSpace; int pointsPerSquare; mid.getLineEdit(0, gridSpace); mid.getLineEdit(1, pointsPerSquare); bms->createFlatGridBorders(borderFile, gridSpace, pointsPerSquare); theMainWindow->getBrainSet()->deleteAllBorders(); BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); bmbs->copyBordersFromBorderFile(bms, &borderFile); theMainWindow->getBrainSet()->assignBorderColors(); GuiFilesModified fm; fm.setBorderModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } } } /** * slot for create cartesian grid borders */ void GuiMainWindowLayersActions::slotBordersCreateAnalysisGrid() { BrainModelSurface* bms = theMainWindow->getBrainModelOpenGL()->getDisplayedBrainModelSurface(); if (bms != NULL) { // // See if a flat surface is in the main window // BrainModelSurface::SURFACE_TYPES st = bms->getSurfaceType(); if ((st != BrainModelSurface::SURFACE_TYPE_FLAT) && (st != BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR)) { if (QMessageBox::critical(theMainWindow, "Surface Type", "The surface in the main window must be flat for this operation.\n" "Do you want to continue?", QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) { return; } } // // Get the bounds of the surface // float bounds[6]; bms->getBounds(bounds); // // Create a dialog for the parameters // WuQDataEntryDialog ded(theMainWindow); ded.setWindowTitle("Create Analysis Grid Borders"); QDoubleSpinBox* xMinSpinBox = ded.addDoubleSpinBox("X-Min", bounds[0]); QDoubleSpinBox* xMaxSpinBox = ded.addDoubleSpinBox("X-Max", bounds[1]); QDoubleSpinBox* yMinSpinBox = ded.addDoubleSpinBox("Y-Min", bounds[2]); QDoubleSpinBox* yMaxSpinBox = ded.addDoubleSpinBox("Y-Max", bounds[3]); QDoubleSpinBox* spacingSpinBox = ded.addDoubleSpinBox("Spacing", 10.0, 0.01, 1000000.0, 1.0); BorderFile borderFile; if (ded.exec() == QDialog::Accepted) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); bounds[0] = xMinSpinBox->value(); bounds[1] = xMaxSpinBox->value(); bounds[2] = yMinSpinBox->value(); bounds[3] = yMaxSpinBox->value(); const float spacing = spacingSpinBox->value(); bms->createFlatGridBordersForAnalysis(borderFile, bounds, spacing); theMainWindow->getBrainSet()->deleteAllBorders(); BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); bmbs->copyBordersFromBorderFile(bms, &borderFile); theMainWindow->getBrainSet()->assignBorderColors(); DisplaySettingsBorders* dsb = theMainWindow->getBrainSet()->getDisplaySettingsBorders(); dsb->setDisplayBorders(true); GuiFilesModified fm; fm.setBorderModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } } } /** * slot for create spherical lat/lon borders */ void GuiMainWindowLayersActions::slotBordersCreateSpherical() { BrainModelSurface* bms = theMainWindow->getBrainModelOpenGL()->getDisplayedBrainModelSurface(); if (bms != NULL) { // // See if a spherical surface is in the main window // BrainModelSurface::SURFACE_TYPES st = bms->getSurfaceType(); if (st != BrainModelSurface::SURFACE_TYPE_SPHERICAL) { QMessageBox::critical(theMainWindow, "Surface Type", "The surface in the main window must be a sphere for this operation !!!"); return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BorderFile borderFile; bms->createSphericalLatLonBorders(borderFile, true); BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); bmbs->copyBordersFromBorderFile(bms, &borderFile); theMainWindow->getBrainSet()->assignBorderColors(); GuiFilesModified fm; fm.setBorderModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } } /** * slot for edit border colors */ void GuiMainWindowLayersActions::slotBordersEditColors() { GuiColorFileEditorDialog* gfed = new GuiColorFileEditorDialog(theMainWindow, theMainWindow->getBrainSet()->getBorderColorFile(), false, true, true, false, false); QObject::connect(gfed, SIGNAL(redrawRequested()), this, SLOT(slotBorderColorsChanged())); gfed->show(); } /** * This slot is called by the color editor when user pressed apply or dialog is closed. */ void GuiMainWindowLayersActions::slotBorderColorsChanged() { GuiFilesModified fm; fm.setBorderColorModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } /** * slot for resample displayed borders */ void GuiMainWindowLayersActions::slotBordersResampleDisplayed() { bool ok = false; const float sampling = QInputDialog::getDouble(theMainWindow, "Border Resampling", "Border Resampling", 2.0, 0.1, 1000.0, 1, &ok); QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); BrainModelSurface* bms = theMainWindow->getBrainModelOpenGL()->getDisplayedBrainModelSurface(); if (bms != NULL) { bmbs->resampleDisplayedBorders(bms, sampling); bmbs->assignColors(); } else { BrainModelVolume* bmv = theMainWindow->getBrainModelVolume(); if (bmv != NULL) { bmbs->resampleDisplayedBorders(bmv, sampling); bmbs->assignColors(); } } GuiFilesModified fm; fm.setBorderModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } /** * slot for rename borders selected with mouse */ void GuiMainWindowLayersActions::slotBordersRenameWithMouse() { theMainWindow->getBrainModelOpenGL()->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_BORDER_RENAME); } /** * slot for reverse borders selected with mouse */ void GuiMainWindowLayersActions::slotBordersReverseWithMouse() { theMainWindow->getBrainModelOpenGL()->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_BORDER_REVERSE); } /** * slot for move borders selected with mouse */ void GuiMainWindowLayersActions::slotBordersMovePointWithMouse() { GuiBrainModelOpenGL* mainOpenGL = theMainWindow->getBrainModelOpenGL(); BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { bool verify = false; switch (bms->getSurfaceType()) { case BrainModelSurface::SURFACE_TYPE_RAW: verify = true; break; case BrainModelSurface::SURFACE_TYPE_FIDUCIAL: verify = true; break; case BrainModelSurface::SURFACE_TYPE_INFLATED: verify = true; break; case BrainModelSurface::SURFACE_TYPE_VERY_INFLATED: verify = true; break; case BrainModelSurface::SURFACE_TYPE_SPHERICAL: verify = true; break; case BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL: verify = true; break; case BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL: verify = true; break; case BrainModelSurface::SURFACE_TYPE_FLAT: verify = false; break; case BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR: verify = false; break; case BrainModelSurface::SURFACE_TYPE_HULL: verify = true; break; case BrainModelSurface::SURFACE_TYPE_UNKNOWN: verify = true; break; case BrainModelSurface::SURFACE_TYPE_UNSPECIFIED: verify = true; break; } if (verify) { const QString msg("Border points move in the XY plane which means that\n" "border points may only be moved on flat surfaces."); if (QMessageBox::warning(theMainWindow, "Danger", msg, (QMessageBox::Ok | QMessageBox::Cancel), QMessageBox::Cancel) == QMessageBox::Cancel) { return; } } } mainOpenGL->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_BORDER_MOVE_POINT); } /** * slot for reverse displayed borders */ void GuiMainWindowLayersActions::slotBordersReverseDisplayed() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); BrainModelSurface* bms = theMainWindow->getBrainModelOpenGL()->getDisplayedBrainModelSurface(); if (bms != NULL) { bmbs->reverseDisplayedBorders(bms); } else { BrainModelVolume* bmv = theMainWindow->getBrainModelVolume(); if (bmv != NULL) { bmbs->reverseDisplayedBorders(bmv); } } GuiFilesModified fm; fm.setBorderModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } /** * slot for orient displayed borders clockwise */ void GuiMainWindowLayersActions::slotBordersOrientDisplayedClockwise() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainModelSurface* bms = theMainWindow->getBrainModelOpenGL()->getDisplayedBrainModelSurface(); if (bms != NULL) { // // See if a flat surface is in the main window // const BrainModelSurface::SURFACE_TYPES st = bms->getSurfaceType(); if ((st != BrainModelSurface::SURFACE_TYPE_FLAT) && (st != BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR)) { QApplication::restoreOverrideCursor(); QMessageBox::critical(theMainWindow, "Surface Type", "The surface in the main window must be flat for this operation !!!"); return; } BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); bmbs->orientDisplayedBordersClockwise(bms); } else { BrainModelVolume* bmv = theMainWindow->getBrainModelVolume(); if (bmv != NULL) { BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); bmbs->orientDisplayedBordersClockwise(bmv); } } GuiFilesModified fm; fm.setBorderModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } /** * slot for delete border point with mouse */ void GuiMainWindowLayersActions::slotBordersDeletePointWithMouse() { theMainWindow->getBrainModelOpenGL()->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_BORDER_DELETE_POINT); } /** * slot for delete border with mouse */ void GuiMainWindowLayersActions::slotBordersDeleteWithMouse() { theMainWindow->getBrainModelOpenGL()->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_BORDER_DELETE); } /** * slot for delete all borders */ void GuiMainWindowLayersActions::slotBordersDeleteAll() { if (QMessageBox::warning(theMainWindow, "Delete All Borders", "Are you sure you want to delete all borders?", (QMessageBox::Yes | QMessageBox::No), QMessageBox::Yes) == QMessageBox::Yes) { theMainWindow->getBrainSet()->deleteAllBorders(); GuiFilesModified fm; fm.setBorderModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } } /** * slot for deleting border points outside surface */ void GuiMainWindowLayersActions::slotBordersDeletePointsOutsideSurface() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainModelSurface* bms = theMainWindow->getBrainModelOpenGL()->getDisplayedBrainModelSurface(); if (bms != NULL) { const int brainModelIndex = theMainWindow->getBrainSet()->getBrainModelIndex(bms); if (brainModelIndex < 0) { std::cout << "PROGRAM ERROR: Invalid brain model index at " << __LINE__ << " in file " << __FILE__ << std::endl; return; } // // Create a point projector with barycentric mode on. // BrainModelSurfacePointProjector* pointProjector = new BrainModelSurfacePointProjector(bms, BrainModelSurfacePointProjector::SURFACE_TYPE_HINT_OTHER, false); BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); const int numBorders = bmbs->getNumberOfBorders(); for (int j = 0; j < numBorders; j++) { BrainModelBorder* b = bmbs->getBorder(j); if (b->getValidForBrainModel(brainModelIndex)) { const int numLinks = b->getNumberOfBorderLinks(); for (int k = numLinks - 1; k >= 0; k--) { const BrainModelBorderLink* link = b->getBorderLink(k); int nearestNode; int tileNodes[3]; float barycentric[3]; // // If the border link does not project to a tile then it must be outside // the surface. // const int tileNumber = pointProjector->projectBarycentric( link->getLinkPosition(brainModelIndex), nearestNode, tileNodes, barycentric); if (tileNumber < 0) { b->deleteBorderLink(k); } } } } } GuiFilesModified fm; fm.setBorderModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } /** * slot for edit border attributes dialog. */ void GuiMainWindowLayersActions::slotBordersEditAttributes() { GuiBorderAttributesDialog bad(theMainWindow); bad.exec(); } /** * slot for clear border highlighting. */ void GuiMainWindowLayersActions::slotBordersClearHighlighting() { BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); bmbs->clearBorderHighlighting(); GuiBrainModelOpenGL::updateAllGL(); } /** * slot for creating interpolated borders. */ void GuiMainWindowLayersActions::slotBordersCreateInterpolated() { theMainWindow->getBordersCreateInterpolatedDialog(true); theMainWindow->getBrainModelOpenGL()->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_BORDER_INTERPOLATE); } /** * slot called to add contour cells. */ void GuiMainWindowLayersActions::slotContourCellsAdd() { theMainWindow->getAddContourCellsDialog(true); } /** * slot called to delete contour cells with mouse. */ void GuiMainWindowLayersActions::slotContourCellsDeleteWithMouse() { theMainWindow->getBrainModelOpenGL()->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_CELL_DELETE); } /** * slot called to delete contour cells with mouse. */ void GuiMainWindowLayersActions::slotContourCellsMoveWithMouse() { theMainWindow->getBrainModelOpenGL()->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_CELL_MOVE); } /** * slot called to delete all contour cells. */ void GuiMainWindowLayersActions::slotContourCellsDeleteAll() { if (QMessageBox::warning(theMainWindow, "Delete All Contour Cells", "Are you sure you want to delete all contour cells?", (QMessageBox::Yes | QMessageBox::No), QMessageBox::Yes) == QMessageBox::Yes) { theMainWindow->getBrainSet()->clearContourCellFile(); GuiFilesModified fm; fm.setContourModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } } /** * Slot for Edit Cell Colors Dialog */ void GuiMainWindowLayersActions::slotContourCellsEditColors() { GuiColorFileEditorDialog* gfed = new GuiColorFileEditorDialog(theMainWindow, theMainWindow->getBrainSet()->getContourCellColorFile(), false, true, false, false, false); QObject::connect(gfed, SIGNAL(redrawRequested()), this, SLOT(slotContourCellsColorsChanged())); gfed->show(); } /** * This slot is called by the color editor when user pressed apply or dialog is closed. */ void GuiMainWindowLayersActions::slotContourCellsColorsChanged() { GuiFilesModified fm; fm.setContourModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } /** * slot for contour apply current view */ void GuiMainWindowLayersActions::slotContourApplyCurrentView() { BrainModelContours* bmc = theMainWindow->getBrainModelContours(); if (bmc != NULL) { bmc->applyTransformationsToAllContours(); GuiFilesModified fm; fm.setContourModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } } /** * slot for contour new set. */ void GuiMainWindowLayersActions::slotContourNewSet() { // // Create a new contour model and display it in the main window // BrainModelContours* bmc = new BrainModelContours(theMainWindow->getBrainSet()); theMainWindow->getBrainSet()->addBrainModel(bmc); // // Notify about new contours // GuiFilesModified fm; fm.setContourModified(); theMainWindow->fileModificationUpdate(fm); theMainWindow->displayBrainModelInMainWindow(theMainWindow->getBrainSet()->getBrainModelContours()); GuiBrainModelOpenGL::updateAllGL(); } /** * slot for contour set scale. */ void GuiMainWindowLayersActions::slotContourSetScale() { theMainWindow->getContourSetScaleDialog(true); theMainWindow->getBrainModelOpenGL()->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_SET_SCALE); } /** * slot for contour select sections. */ void GuiMainWindowLayersActions::slotContourSections() { // // Popup the contour section control dialog // theMainWindow->getContourSectionControlDialog(true); } /** * slot for contour set spacing. */ void GuiMainWindowLayersActions::slotContourSpacing() { BrainModelContours* bmc = theMainWindow->getBrainModelContours(); if (bmc == NULL) { return; } ContourFile* cf = bmc->getContourFile(); bool ok = false; const float spacing = QInputDialog::getDouble(theMainWindow, "Contour Section Spacing", "Spacing (mm)", cf->getSectionSpacing(), -214748367, 2147483647, 2, &ok); if (ok) { cf->setSectionSpacing(spacing); } GuiBrainModelOpenGL::updateAllGL(); } /** * slot for contour draw. */ void GuiMainWindowLayersActions::slotContourDraw() { theMainWindow->getContourDrawDialog(true); } /** * slot for contour align. */ void GuiMainWindowLayersActions::slotContourAlign() { theMainWindow->getContourAlignmentDialog(true); theMainWindow->getBrainModelOpenGL()->setMouseMode( GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_ALIGN); } /** * slot for contour merge. */ void GuiMainWindowLayersActions::slotContourMerge() { theMainWindow->getBrainModelOpenGL()->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_MERGE); } /** * slot for contour move point. */ void GuiMainWindowLayersActions::slotContourMovePoint() { theMainWindow->getBrainModelOpenGL()->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_POINT_MOVE); } /** * slot for contour delete all. */ void GuiMainWindowLayersActions::slotContourDeleteAll() { BrainModelContours* bmc = theMainWindow->getBrainModelContours(); if (bmc == NULL) { return; } if (QMessageBox::warning(theMainWindow, "Delete All Contours", "Are you sure you want to delete all contours?", (QMessageBox::Yes | QMessageBox::No), QMessageBox::Yes) == QMessageBox::Yes) { theMainWindow->getBrainSet()->clearContourFile(); GuiFilesModified fm; fm.setContourModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } } /** * slot for contour delete point. */ void GuiMainWindowLayersActions::slotContourDeletePoint() { theMainWindow->getBrainModelOpenGL()->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_POINT_DELETE); } /** * slot for contour delete contour. */ void GuiMainWindowLayersActions::slotContourCleanUp() { BrainModelContours* bmc = theMainWindow->getBrainModelContours(); if (bmc == NULL) { return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); ContourFile* cf = bmc->getContourFile(); const bool problemsCleanedFlag = cf->cleanupContours(); QString message("No problems were found during cleaning."); if (problemsCleanedFlag) { message = "Problems were found and cleaned."; } GuiFilesModified fm; fm.setContourModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); QMessageBox::information(theMainWindow, "INFO", message); } /** * slot for contour point reversal. */ void GuiMainWindowLayersActions::slotContourReverse() { theMainWindow->getBrainModelOpenGL()->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_REVERSE); } /** * slot for contour delete contour. */ void GuiMainWindowLayersActions::slotContourDelete() { theMainWindow->getBrainModelOpenGL()->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_DELETE); } /** * slot for contour resampling. */ void GuiMainWindowLayersActions::slotContourResample() { bool ok = false; const float value = QInputDialog::getDouble(theMainWindow, "Resample Contours", "New Point Spacing", 1.0, 0.00001, 2147483647.0, 2, &ok); if (ok) { BrainModelContours* bmc = theMainWindow->getBrainModelContours(); if (bmc != NULL) { ContourFile* cf = bmc->getContourFile(); cf->resampleAllContours(value); } } } /** * slot for contour reconstruct into surface. */ void GuiMainWindowLayersActions::slotContourReconstruct() { const QString msg = "You should run \"Clean Up Contours\" prior to reconstruction which will remove\n" "invalid contours that may cause problems during reconstruction. Clean Up Contours\n" "will remove consecutive, duplicate points from contours and will remove contours\n" "containing less than three points.\n\n" "In addition, you should show the contours as lines to verify that all contours are\n" "properly closed (no unusual lines cutting across a contour). To show contours as\n" "lines, press the D/C pushbutton in the Main Window's Toolbar. Set Page Selection to\n" "Contours and Contour Cells and set the Draw Mode to Points and Lines. In addition,\n" "select Show First Point in Each Contour in Red to verify that each contour is a \n" "single contour and not composed of multiple contours segments."; QMessageBox msgBox(theMainWindow); msgBox.setWindowTitle("Clean Up Contours?"); msgBox.setText(msg); msgBox.addButton("Proceed With Reconstruction", QMessageBox::AcceptRole); QPushButton* cancelPushButton = msgBox.addButton("Cancel", QMessageBox::RejectRole); msgBox.exec(); if (msgBox.clickedButton() == cancelPushButton) { return; } GuiContourReconstructionDialog crd(theMainWindow, true); crd.exec(); theMainWindow->displayNewestSurfaceInMainWindow(); } /** * update the actions (typically called when menu is about to show) */ void GuiMainWindowLayersActions::updateActions() { // // See if a contour model is in the main window and if // there are any contours // bool haveContourModel = false; bool haveContours = false; bool haveContourCells = false; BrainModelContours* bmc = theMainWindow->getBrainModelContours(); if (bmc != NULL) { haveContourModel = true; ContourFile* cf = bmc->getContourFile(); if (cf->getNumberOfContours() > 0) { haveContours = true; ContourCellFile* cf = theMainWindow->getBrainSet()->getContourCellFile(); if (cf != NULL) { haveContourCells = (cf->getNumberOfCells() > 0); } } } // // Items that require contours or contour model // contourNewSetAction->setEnabled(haveContourModel == false); contourSetScaleAction->setEnabled(haveContourModel); contourSectionsAction->setEnabled(haveContours); contourSpacingAction->setEnabled(haveContourModel); contourDrawAction->setEnabled(haveContourModel); contourApplyCurrentViewAction->setEnabled(haveContours); contourAlignAction->setEnabled(haveContours); contourMergeAction->setEnabled(haveContours); contourMovePointAction->setEnabled(haveContours); contourDeleteAllAction->setEnabled(haveContours); contourDeleteAction->setEnabled(haveContours); contourDeletePointAction->setEnabled(haveContours); contourReconstructAction->setEnabled(haveContours); contourResampleAction->setEnabled(haveContours); contourReverseAction->setEnabled(haveContours); contourCleanUpAction->setEnabled(haveContours); contourCellsAddAction->setEnabled(haveContours); // // Items that require contour cells // contourCellsDeleteAllAction->setEnabled(haveContourCells); contourCellsDeleteWithMouseAction->setEnabled(haveContourCells); contourCellsMoveWithMouseAction->setEnabled(haveContourCells); const bool palsCompatibleFlag = (theMainWindow->getBrainSet()->getNumberOfNodes() == 73730); fociPalsProjectAction->setEnabled(palsCompatibleFlag); const FociProjectionFile* fpf = theMainWindow->getBrainSet()->getFociProjectionFile(); fociStudyInfoToStudyMetaDataFileAction->setEnabled(fpf->getNumberOfStudyInfo() > 0); } /** * slot called when contour information selected. */ void GuiMainWindowLayersActions::slotContourInformation() { BrainModelContours* bmc = theMainWindow->getBrainModelContours(); if (bmc != NULL) { ContourFile* cf = bmc->getContourFile(); const int numContours = cf->getNumberOfContours(); QString msg; msg += ("Number of Contours: " + QString::number(numContours) + "\n"); if (numContours > 0) { msg += ("Section Number Range: " + QString::number(cf->getMinimumSection()) + " to " + QString::number(cf->getMaximumSection()) + "\n"); msg += ("Section Spacing: " + QString::number(cf->getSectionSpacing(), 'f', 3) + "\n"); float xmin, xmax, ymin, ymax; cf->getExtent(xmin, xmax, ymin, ymax); msg += ("X-Range: " + QString::number(xmin, 'f', 3) + " to " + QString::number(xmax, 'f', 3) + "\n"); msg += ("Y-Range: " + QString::number(ymin, 'f', 3) + " to " + QString::number(ymax, 'f', 3) + "\n"); msg += ("Z-Range: " + QString::number(cf->getSectionSpacing() * cf->getMinimumSection(), 'f', 3) + " to " + QString::number(cf->getSectionSpacing() * cf->getMaximumSection(), 'f', 3) + "\n"); QMessageBox::information(theMainWindow, "Contour Information", msg); } } } caret-5.6.4~dfsg.1.orig/caret/GuiMainWindowHelpMenu.h0000664000175000017500000000237511572067322022216 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_MAIN_WINDOW_HELP_MENU_H__ #define __GUI_MAIN_WINDOW_HELP_MENU_H__ #include class GuiMainWindow; /// This class creates the Main Window's Help Menu. class GuiMainWindowHelpMenu : public QMenu { Q_OBJECT public: /// constructor GuiMainWindowHelpMenu(GuiMainWindow* parent); /// destructor ~GuiMainWindowHelpMenu(); }; #endif caret-5.6.4~dfsg.1.orig/caret/GuiMainWindowHelpMenu.cxx0000664000175000017500000000430711572067322022566 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include "GuiMainWindow.h" #include "GuiMainWindowHelpActions.h" #include "GuiMainWindowHelpMenu.h" /** * Constructor. */ GuiMainWindowHelpMenu::GuiMainWindowHelpMenu(GuiMainWindow* parent) : QMenu("Help", parent) { setObjectName("GuiMainWindowHelpMenu"); GuiMainWindowHelpActions* helpActions = parent->getHelpActions(); QObject::connect(this, SIGNAL(aboutToShow()), helpActions, SLOT(updateActions())); addAction(helpActions->getAboutAction()); addAction(helpActions->getAboutQtAction()); addAction(helpActions->getAboutOpenGLAction()); addSeparator(); addAction(helpActions->getCaretHelpAction()); ///addAction(helpActions->getCaretHelpAssistantAction()); addAction(helpActions->getOnlineCaretHelpAction()); addAction(helpActions->getCaretTipsAction()); addAction(helpActions->getCaretUsersListArchiveAction()); addAction(helpActions->getCaretWebSiteAction()); addAction(helpActions->getCaretSearchWebSiteAction()); addSeparator(); addAction(helpActions->getSumbsWebSiteAction()); //addAction(helpActions->getSumsAtlasAction()); //addAction(helpActions->getSumsTutorialsAction()); } /** * Destructor. */ GuiMainWindowHelpMenu::~GuiMainWindowHelpMenu() { } caret-5.6.4~dfsg.1.orig/caret/GuiMainWindowHelpActions.h0000664000175000017500000001201311572067322022700 0ustar michaelmichael #ifndef __GUI_MAIN_WINDOW_HELP_ACTIONS_H__ #define __GUI_MAIN_WINDOW_HELP_ACTIONS_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include class GuiHelpAssistantWindow; class QAction; class QWidget; /// the main window's help actions class GuiMainWindowHelpActions : public QObject { Q_OBJECT public: // constructor GuiMainWindowHelpActions(QWidget* parent); // destructor ~GuiMainWindowHelpActions(); /// about caret action QAction* getAboutAction() { return aboutAction; } /// about QT action QAction* getAboutQtAction() { return aboutQtAction; } /// about OpenGL action QAction* getAboutOpenGLAction() { return aboutOpenGLAction; } /// caret help action QAction* getCaretHelpAction() { return caretHelpAction; } /// caret help action QAction* getCaretHelpAssistantAction() { return caretHelpAssistantAction; } /// caret online help action QAction* getOnlineCaretHelpAction() { return caretOnlineHelpAction; } /// caret users list email archive help action QAction* getCaretUsersListArchiveAction() { return caretUsersListArchiveAction; } /// caret tips action QAction* getCaretTipsAction() { return caretTipsAction; } /// caret web site action QAction* getCaretWebSiteAction() { return caretWebSiteAction; } /// search caret web site action QAction* getCaretSearchWebSiteAction() { return caretSearchWebSiteAction; } /// sums web site action QAction* getSumbsWebSiteAction() { return sumbsWebSiteAction; } /// sums atlas action QAction* getSumsAtlasAction() { return sumsAtlasAction; } /// sums tutorial action QAction* getSumsTutorialsAction() { return sumsTutorialsAction; } public slots: /// update the actions (typically called when menu is about to show) void updateActions(); /// Called when About chosen from Help menu. void helpMenuAbout(); /// display information about the qt version void helpMenuAboutQT(); /// display information about the OpenGL version void helpMenuAboutOpenGL(); /// display caret help browser void helpMenuCaretHelp(); /// display caret help assistant void helpMenuCaretHelpAssistant(); /// display online caret help void helpMenuOnlineCaretHelp(); /// display caret users email archive void slotCaretUsersListArchiveAction(); /// display caret tips dialog void helpMenuCaretTips(); /// display caret web site in a browser void helpMenuCaretWebSite(); /// display caret search web site in a browser void helpMenuCaretSearchWebSite(); /// search SuMS database web site in a browser void helpMenuSumsWebSite(); /// display SuMS atalses database web site in a browser void helpMenuSumsAtlases(); /// display SuMS tutorials database web site in a browser void helpMenuSumsTutorials(); protected: /// about caret action QAction* aboutAction; /// about QT action QAction* aboutQtAction; /// about OpenGL action QAction* aboutOpenGLAction; /// caret help action QAction* caretHelpAction; /// caret help assistant action QAction* caretHelpAssistantAction; /// caret users list archive action QAction* caretUsersListArchiveAction; /// caret online help action QAction* caretOnlineHelpAction; /// caret tips action QAction* caretTipsAction; /// caret web site action QAction* caretWebSiteAction; /// caret search web site action QAction* caretSearchWebSiteAction; /// sums web site action QAction* sumbsWebSiteAction; /// sums atlas action QAction* sumsAtlasAction; /// sums tutorial action QAction* sumsTutorialsAction; /// Qt Assistant Client for Helpl GuiHelpAssistantWindow* assistantWindow; }; #endif // __GUI_MAIN_WINDOW_HELP_ACTIONS_H__ caret-5.6.4~dfsg.1.orig/caret/GuiMainWindowHelpActions.cxx0000664000175000017500000003230611572067322023262 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include "CaretVersion.h" #include "GuiBrainModelOpenGL.h" #include "GuiCaretTipsDialog.h" #include "GuiHelpAssistantWindow.h" #include "GuiMainWindow.h" #include "GuiMainWindowHelpActions.h" #include "QtTextEditDialog.h" #include "SystemUtilities.h" #include "global_variables.h" #include "vtkVersion.h" #include "zlib.h" #ifdef HAVE_ITK #include "itkVersion.h" #endif /** * constructor. */ GuiMainWindowHelpActions::GuiMainWindowHelpActions(QWidget* parent) : QObject(parent) { assistantWindow = NULL; setObjectName("GuiMainWindowHelpActions"); aboutAction = new QAction(parent); aboutAction->setText("About Caret 5..."); aboutAction->setObjectName("aboutAction"); QObject::connect(aboutAction, SIGNAL(triggered(bool)), this, SLOT(helpMenuAbout())); aboutQtAction = new QAction(parent); aboutQtAction->setText("About QT..."); aboutQtAction->setObjectName("aboutQtAction"); QObject::connect(aboutQtAction, SIGNAL(triggered(bool)), this, SLOT(helpMenuAboutQT())); aboutOpenGLAction = new QAction(parent); aboutOpenGLAction->setText("About OpenGL..."); aboutOpenGLAction->setObjectName("aboutOpenGLAction"); QObject::connect(aboutOpenGLAction, SIGNAL(triggered(bool)), this, SLOT(helpMenuAboutOpenGL())); caretHelpAction = new QAction(parent); caretHelpAction->setText("Caret Help..."); caretHelpAction->setObjectName("caretHelpAction"); QObject::connect(caretHelpAction, SIGNAL(triggered(bool)), this, SLOT(helpMenuCaretHelp())); caretHelpAssistantAction = new QAction(parent); caretHelpAssistantAction->setText("Caret Help Assistant..."); caretHelpAssistantAction->setObjectName("caretHelpAssistantAction"); QObject::connect(caretHelpAssistantAction, SIGNAL(triggered(bool)), this, SLOT(helpMenuCaretHelpAssistant())); caretOnlineHelpAction = new QAction(parent); caretOnlineHelpAction->setText("Caret Help (Online)..."); caretOnlineHelpAction->setObjectName("caretOnlineHelpAction"); QObject::connect(caretOnlineHelpAction, SIGNAL(triggered(bool)), this, SLOT(helpMenuOnlineCaretHelp())); caretUsersListArchiveAction = new QAction(parent); caretUsersListArchiveAction->setText("Caret User's Email Archive (Online)..."); caretUsersListArchiveAction->setObjectName("caretUsersListArchiveAction"); QObject::connect(caretUsersListArchiveAction, SIGNAL(triggered(bool)), this, SLOT(slotCaretUsersListArchiveAction())); caretTipsAction = new QAction(parent); caretTipsAction->setText("Caret Tips..."); caretTipsAction->setObjectName("caretTipsAction"); QObject::connect(caretTipsAction, SIGNAL(triggered(bool)), this, SLOT(helpMenuCaretTips())); caretWebSiteAction = new QAction(parent); caretWebSiteAction->setText("Go To Caret Web Site..."); caretWebSiteAction->setObjectName("caretWebSiteAction"); QObject::connect(caretWebSiteAction, SIGNAL(triggered(bool)), this, SLOT(helpMenuCaretWebSite())); caretSearchWebSiteAction = new QAction(parent); caretSearchWebSiteAction->setText("Search Caret Web Site..."); caretSearchWebSiteAction->setObjectName("caretSearchWebSiteAction"); QObject::connect(caretSearchWebSiteAction, SIGNAL(triggered(bool)), this, SLOT(helpMenuCaretSearchWebSite())); sumbsWebSiteAction = new QAction(parent); sumbsWebSiteAction->setText("Go To SuMS Database Web Site..."); sumbsWebSiteAction->setObjectName("sumbsWebSiteAction"); QObject::connect(sumbsWebSiteAction, SIGNAL(triggered(bool)), this, SLOT(helpMenuSumsWebSite())); sumsAtlasAction = new QAction(parent); sumsAtlasAction->setText("Go To SuMS Database Atlases..."); sumsAtlasAction->setObjectName("sumsAtlasAction"); QObject::connect(sumsAtlasAction, SIGNAL(triggered(bool)), this, SLOT(helpMenuSumsAtlases())); sumsTutorialsAction = new QAction(parent); sumsTutorialsAction->setText("Go To SuMS Database Tutorials..."); sumsTutorialsAction->setObjectName("sumsTutorialsAction"); QObject::connect(sumsTutorialsAction, SIGNAL(triggered(bool)), this, SLOT(helpMenuSumsTutorials())); } /** * destructor. */ GuiMainWindowHelpActions::~GuiMainWindowHelpActions() { } /** * Called when caret help selected */ void GuiMainWindowHelpActions::helpMenuCaretHelp() { theMainWindow->showHelpViewerDialog(); } /** * Called when caret help selected */ void GuiMainWindowHelpActions::helpMenuCaretHelpAssistant() { //assistantWindow = new GuiHelpAssistantWindow("/usr/local/caret_libraries/qt-software/qt/bin/"); //assistantWindow->showPage(""); } /** * display caret users email archive. */ void GuiMainWindowHelpActions::slotCaretUsersListArchiveAction() { theMainWindow->displayWebPage("http://www.mail-archive.com/caret-users@brainvis.wustl.edu/index.html"); } /** * display online caret help. */ void GuiMainWindowHelpActions::helpMenuOnlineCaretHelp() { theMainWindow->displayWebPage("http://brainvis.wustl.edu/CaretHelpAccount/caret5_help/"); } /** * called when Help Menu About selected. */ void GuiMainWindowHelpActions::helpMenuAbout() { QString msg; msg.append("CARET v"); msg.append(CaretVersion::getCaretVersionAsString()); msg.append("\n"); msg.append("Computerized Anatomical Reconstruction and Editing Toolkit\n"); msg.append("John Harwell, Heather Drury, Donna Hanlon, and David Van Essen\n"); msg.append("Copyright 1995-2006 Washington University\n"); msg.append("\n"); msg.append("Washington University School of Medicine\n"); msg.append("660 S. Euclid Ave\n"); msg.append("St. Louis, MO 63110 USA\n"); msg.append("\n"); msg.append("http://brainmap.wustl.edu/caret.html\n"); msg.append("\n"); msg.append("Use the Caret Mailing List for questions about Caret.\n"); msg.append(" http://brainmap.wustl.edu/resources/caretnew.html#Help\n"); msg.append("\n"); msg.append("This program is free software; you can redistribute it and/or\n"); msg.append("modify it under the terms of the GNU General Public License\n"); msg.append("as published by the Free Software Foundation; either version 2\n"); msg.append("of the License, or (at your option) any later version.\n"); msg.append("\n"); msg.append("This program is distributed in the hope that it will be useful,\n"); msg.append("but WITHOUT ANY WARRANTY; without even the implied warranty of\n"); msg.append("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"); msg.append("GNU General Public License for more details.\n"); msg.append("\n"); msg.append("You should have received a copy of the GNU General Public License\n"); msg.append("along with this program; if not, write to the Free Software\n"); msg.append("Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"); msg.append("\n"); msg.append("\n"); msg.append("CARET may also contain the following software:\n"); msg.append("\n"); msg.append("AFNI\n"); msg.append(" Copyright 1994-2000 Medical College of Wisconsin\n"); msg.append(" http://afni.nimh.nih.gov\n"); msg.append("\n"); msg.append("\n"); #ifdef HAVE_ITK msg.append("ITK - Insight Segmentation & Registration Toolkit\n"); msg.append("Copyright (c) Insight Software Consortium. All rights reserved.\n"); msg.append(" http://www.itk.org\n"); msg.append(" version: "); msg.append(itk::Version::GetITKVersion()); msg.append("\n"); msg.append("\n"); #endif // HAVE_ITK msg.append("QT\n"); msg.append(" Copyright (C) 1992-2000 Trolltech AS. All rights reserved.\n"); msg.append(" http://www.trolltech.com\n"); msg.append(" version: "); msg.append(qVersion()); msg.append("\n"); msg.append("\n"); msg.append("VTK - Visualization Toolkit\n"); msg.append(" Copyright (c) 1993-2001 Ken Martin, Will Schroeder, Bill Lorensen\n"); msg.append(" http://www.vtk.org\n"); msg.append(" version: "); msg.append(vtkVersion::GetVTKVersion()); msg.append("\n"); msg.append("\n"); msg.append("ZLIB\n"); msg.append(" Copyright (c) 1995-2002 Jean-loup Gailly and Mark Adler\n"); msg.append(" http://www.gzip.org/zlib/\n"); msg.append(" header file version: "); msg.append(ZLIB_VERSION); msg.append(" library version: "); msg.append(zlibVersion()); msg.append("\n"); msg.append("\n"); std::ostringstream str; str << "Number of CPUs: " << SystemUtilities::getNumberOfProcessors() << "\n"; msg.append(str.str().c_str()); msg.append("\n"); QtTextEditDialog te(theMainWindow, true, true); te.setWindowTitle("Caret5"); te.setText(msg); te.exec(); } /** * */ void GuiMainWindowHelpActions::helpMenuAboutQT() { QMessageBox::aboutQt(theMainWindow, "About QT"); } /** * */ void GuiMainWindowHelpActions::helpMenuAboutOpenGL() { QString msg; #ifdef GL_VERSION_1_9 msg.append("OpenGL header is 1.9\n"); #elif GL_VERSION_1_8 msg.append("OpenGL header is 1.8\n"); #elif GL_VERSION_1_7 msg.append("OpenGL header is 1.7\n"); #elif GL_VERSION_1_6 msg.append("OpenGL header is 1.6\n"); #elif GL_VERSION_1_5 msg.append("OpenGL header is 1.5\n"); #elif GL_VERSION_1_4 msg.append("OpenGL header is 1.4\n"); #elif GL_VERSION_1_3 msg.append("OpenGL header is 1.3\n"); #elif GL_VERSION_1_2 msg.append("OpenGL header is 1.2\n"); #elif GL_VERSION_1_1 msg.append("OpenGL header is 1.1\n"); #else msg.append("OpenGL header is 1.0\n"); #endif msg.append("OpenGL version from library is "); msg.append((char*)(glGetString(GL_VERSION))); msg.append("\n"); msg.append("OpenGL vendor from library is "); msg.append((char*)(glGetString(GL_VENDOR))); msg.append("\n"); QGLFormat format = theMainWindow->getBrainModelOpenGL()->format(); if (format.directRendering()) { msg.append("OpenGL Direct rendering: ON\n"); } else { msg.append("Open Direct rendering: OFF\n"); } msg.append("Double Buffer: "); if (format.doubleBuffer()) msg.append("on\n"); else msg.append("off\n"); QMessageBox::information(theMainWindow, "OpenGL Information", msg); } /** * Load the caret web site in a browser window */ void GuiMainWindowHelpActions::helpMenuCaretWebSite() { theMainWindow->displayWebPage("http://brainmap.wustl.edu/resources/caretnew.html"); } /** * search the caret web site in a browser window */ void GuiMainWindowHelpActions::helpMenuCaretSearchWebSite() { bool valid = false; QString s = QInputDialog::getText(theMainWindow, "Search Caret Website", QString("Search For These Words (separate with blanks)").leftJustified(100, ' '), QLineEdit::Normal, "", &valid); if (valid) { if (s.isEmpty() == false) { s = s.split(QRegExp("\\s+")).join("+"); QString url("http://www.google.com/search?as_q="); url += s; url += "&num=10&hl=en&client=safari&rls=en-us&btnG=Google+Search&as_epq=&as_oq=&as_eq=&lr=&as_ft=i&as_filetype=&as_qdr=all&as_nlo=&as_nhi=&as_occt=any&as_dt=i&as_sitesearch=brainvis.wustl.edu&as_rights=&safe=images"; theMainWindow->displayWebPage(url); } } } /** * Load the sums web site in a browser window */ void GuiMainWindowHelpActions::helpMenuSumsWebSite() { theMainWindow->displayWebPage("http://sumsdb.wustl.edu/sums/index.jsp"); } /** * Load the sums atlases web site in a browser window */ void GuiMainWindowHelpActions::helpMenuSumsAtlases() { theMainWindow->displayWebPage("http://sumsdb.wustl.edu/sums/directory.do?dir_id=636032"); } /** * Load the sums tutorials web site in a browser window */ void GuiMainWindowHelpActions::helpMenuSumsTutorials() { theMainWindow->displayWebPage("http://sumsdb.wustl.edu/sums/directory.do?dir_id=707139"); } /** * display caret tips dialog. */ void GuiMainWindowHelpActions::helpMenuCaretTips() { static GuiCaretTipsDialog* ctd = NULL; if (ctd == NULL) { ctd = new GuiCaretTipsDialog(theMainWindow); } ctd->show(); } /** * update the actions (typically called when menu is about to show) */ void GuiMainWindowHelpActions::updateActions() { } caret-5.6.4~dfsg.1.orig/caret/GuiMainWindowFileMenu.h0000664000175000017500000000364411572067322022205 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_MAIN_WINDOW_FILE_MENU_H__ #define __GUI_MAIN_WINDOW_FILE_MENU_H__ #include #include class GuiBrainModelOpenGL; class GuiMainWindow; class GuiMainWindowFileActions; /// This class creates the Main Window's File Menu. class GuiMainWindowFileMenu : public QMenu { Q_OBJECT public: // constructor GuiMainWindowFileMenu(GuiMainWindow* parent, GuiBrainModelOpenGL* brainModelOpenGLIn); // destructor ~GuiMainWindowFileMenu(); protected slots: // recent spec file menu about to show void recentSpecFileMenuAboutToBeDisplayedSlot(); // called for recent spec file menu selection void recentSpecFileMenuSlot(QAction* action); protected: /// The main window this menu is attached to GuiMainWindow* mainWindow; /// The brain model OpenGL displayed in the main window GuiBrainModelOpenGL* brainModelOpenGL; /// recent spec files menu QMenu* recentSpecFileMenu; }; #endif // __GUI_MAIN_WINDOW_FILE_MENU_H__ caret-5.6.4~dfsg.1.orig/caret/GuiMainWindowFileMenu.cxx0000664000175000017500000001010311572067322022544 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include "BrainSet.h" #include "FileUtilities.h" #include "GuiBrainModelOpenGL.h" #include "GuiMainWindow.h" #include "GuiMainWindowFileActions.h" #include "GuiMainWindowFileMenu.h" #include "global_variables.h" /** * Constructor. */ GuiMainWindowFileMenu::GuiMainWindowFileMenu(GuiMainWindow* parent, GuiBrainModelOpenGL* brainModelOpenGLIn) : QMenu("File", parent) { mainWindow = parent; brainModelOpenGL = brainModelOpenGLIn; clear(); GuiMainWindowFileActions* fileActions = mainWindow->getFileActions(); QObject::connect(this, SIGNAL(aboutToShow()), fileActions, SLOT(updateActions())); // preferences (On Macs, QT will place this on the "caret" menu). addAction(fileActions->getShowPreferencesDialogAction()); #ifndef Q_OS_MACX addSeparator(); #endif addAction(fileActions->getSetCurrentDirectoryAction()); addSeparator(); addAction(fileActions->getConvertDataFileAction()); addAction(fileActions->getCopySpecFileAction()); addAction(fileActions->getValidateSpecFileAction()); addAction(fileActions->getZipSpecFileAction()); addSeparator(); addAction(fileActions->getLoadedFileManagementAction()); addSeparator(); addAction(fileActions->getAddDocumentToSpecFileAction()); addAction(fileActions->getOpenSpecFileAction()); // // Recent spec file menu // recentSpecFileMenu = addMenu("Open Recent Spec File"); QObject::connect(recentSpecFileMenu, SIGNAL(aboutToShow()), this, SLOT(recentSpecFileMenuAboutToBeDisplayedSlot())); QObject::connect(recentSpecFileMenu, SIGNAL(triggered(QAction*)), this, SLOT(recentSpecFileMenuSlot(QAction*))); addAction(fileActions->getCloseSpecFileAction()); addSeparator(); addAction(fileActions->getFastOpenDataFileAction()); addAction(fileActions->getDataFileOpenAction()); addAction(fileActions->getDataFileSaveAction()); addSeparator(); addAction(fileActions->getCaptureMainWindowImageAction()); addAction(fileActions->getRecordAsMpegAction()); #ifndef Q_OS_MACX addSeparator(); #endif addAction(fileActions->getExitCaretAction()); } /** * Destructor. */ GuiMainWindowFileMenu::~GuiMainWindowFileMenu() { } /** * Create recent spec files menu *recent spec file menu about to show. */ void GuiMainWindowFileMenu::recentSpecFileMenuAboutToBeDisplayedSlot() { recentSpecFileMenu->clear(); PreferencesFile* pf = theMainWindow->getBrainSet()->getPreferencesFile(); pf->getRecentSpecFiles(mainWindow->recentSpecFiles); for (int i = 0; i < static_cast(mainWindow->recentSpecFiles.size()); i++) { QAction* action = recentSpecFileMenu->addAction( FileUtilities::rearrangeFileName(mainWindow->recentSpecFiles[i])); action->setData(i); } } /** * called for recent spec file menu selection. */ void GuiMainWindowFileMenu::recentSpecFileMenuSlot(QAction* action) { const int item = action->data().toInt(); mainWindow->recentSpecFileMenuSelection(item); } caret-5.6.4~dfsg.1.orig/caret/GuiMainWindowFileActions.h0000664000175000017500000001373711572067322022705 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_MAIN_WINDOW_FILE_ACTIONS_H__ #define __GUI_MAIN_WINDOW_FILE_ACTIONS_H__ #include class GuiMainWindow; class QAction; class QWidget; /// Actions for the file menu. class GuiMainWindowFileActions : public QObject { Q_OBJECT public: /// constructor GuiMainWindowFileActions(GuiMainWindow* parent); /// destructor ~GuiMainWindowFileActions(); /// fast open data file dialog action QAction* getFastOpenDataFileAction() { return fastOpenDataFileAction; } /// preferences dialog action QAction* getShowPreferencesDialogAction() { return showPreferencesDialogAction; } /// set current directory action QAction* getSetCurrentDirectoryAction() { return setCurrentDirectoryAction; } /// convert data file action QAction* getConvertDataFileAction() { return convertDataFileAction; } /// copy spec file action QAction* getCopySpecFileAction() { return copySpecFileAction; } /// validate spec file action QAction* getValidateSpecFileAction() { return validateSpecFileAction; } /// zip spec file action QAction* getZipSpecFileAction() { return zipSpecFileAction; } /// record as mpeg action QAction* getRecordAsMpegAction() { return recordAsMpegAction; } /// data file open action QAction* getDataFileOpenAction() { return dataFileOpenAction; } /// data file save action QAction* getDataFileSaveAction() { return dataFileSaveAction; } /// copy main window to clipboard action QAction* getCopyMainWindowToClipboardAction() { return copyMainWindowToClipboardAction; } /// print main window action QAction* getPrintMainWindowAction() { return printMainWindowAction; } /// open spec file action QAction* getOpenSpecFileAction() { return openSpecFileAction; } /// close spec file action QAction* getCloseSpecFileAction() { return closeSpecFileAction; } /// add document to spec file action QAction* getAddDocumentToSpecFileAction() { return addDocumentToSpecFileAction; } ///loaded file management action QAction* getLoadedFileManagementAction() { return loadedFileManagementAction; } /// exit caret action QAction* getExitCaretAction() { return exitCaretAction; } /// capture image of main window action QAction* getCaptureMainWindowImageAction() { return captureMainWindowImageAction; } public slots: /// update the actions (typically called when menu is about to show) void updateActions(); /// add document to spec file action void addDocumentToSpecFileSlot(); /// data file open slot void dataFileOpenSlot(); /// data file save slot void dataFileSaveSlot(); /// open spec file action void openSpecFileSlot(); /// set current directory action void slotSetCurrentDirectory(); /// copy main window to clipboard action void copyMainWindowToClipboard(); /// print main window action void printMainWindowImage(); /// loaded file management action void loadedFileManagementSlot(); /// record as mpeg action void recordAsMpegSlot(); /// copy spec file action void copySpecFileSlot(); /// zip spec file action void zipSpecFileSlot(); /// validate spec file action void validateSpecFileSlot(); /// convert data files action void convertDataFileSlot(); protected: /// exit caret action QAction* exitCaretAction; /// add document to spec file action QAction* addDocumentToSpecFileAction; /// close spec file action QAction* closeSpecFileAction; /// fast open data file dialog action QAction* fastOpenDataFileAction; /// preferences dialog action QAction* showPreferencesDialogAction; /// set current directory action QAction* setCurrentDirectoryAction; /// convert data file action QAction* convertDataFileAction; /// copy spec file action QAction* copySpecFileAction; /// validate spec file action QAction* validateSpecFileAction; /// zip spec file action QAction* zipSpecFileAction; /// record as mpeg action QAction* recordAsMpegAction; /// data file open action QAction* dataFileOpenAction; /// data file save action QAction* dataFileSaveAction; /// copy main window to clipboard action QAction* copyMainWindowToClipboardAction; /// capture image of main window action QAction* captureMainWindowImageAction; /// print main window action QAction* printMainWindowAction; /// open spec file action QAction* openSpecFileAction; /// loaded file management action QAction* loadedFileManagementAction; }; #endif // __GUI_MAIN_WINDOW_FILE_ACTIONS_H__ caret-5.6.4~dfsg.1.orig/caret/GuiMainWindowFileActions.cxx0000664000175000017500000004111311572067322023245 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include "WuQFileDialog.h" #include #include #include #include #include #include #include "BrainSet.h" #include "BrainModelSurface.h" #include "DebugControl.h" #include "FileFilters.h" #include "FileUtilities.h" #include "GuiBrainModelOpenGL.h" #include "GuiBrainModelViewingWindow.h" #include "GuiCaptureWindowImageDialog.h" #include "GuiChooseSpecFileDialog.h" #include "GuiConvertDataFileDialog.h" #include "GuiCopySpecFileDialog.h" #include "GuiDataFileOpenDialog.h" #include "GuiDataFileSaveDialog.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "GuiMainWindowFileActions.h" #include "GuiPreferencesDialog.h" #include "GuiSpecFileDialog.h" #include "GuiLoadedFileManagementDialog.h" #include "GuiZipSpecFileDialog.h" #include "QtUtilities.h" #include "StringUtilities.h" #include "global_variables.h" /** * Constructor. */ GuiMainWindowFileActions::GuiMainWindowFileActions(GuiMainWindow* parent) : QObject(parent) { setObjectName("GuiMainWindowFileActions"); fastOpenDataFileAction = new QAction(parent); fastOpenDataFileAction->setText("Fast Open Data File..."); fastOpenDataFileAction->setShortcut(Qt::CTRL+Qt::Key_F); fastOpenDataFileAction->setObjectName("fastOpenDataFileAction"); QObject::connect(fastOpenDataFileAction, SIGNAL(triggered(bool)), parent, SLOT(displayFastOpenDataFileDialog())); showPreferencesDialogAction = new QAction(parent); showPreferencesDialogAction->setText("Preferences..."); showPreferencesDialogAction->setObjectName("showPreferencesDialogAction"); QObject::connect(showPreferencesDialogAction, SIGNAL(triggered(bool)), parent, SLOT(displayPreferencesDialog())); setCurrentDirectoryAction = new QAction(parent); setCurrentDirectoryAction->setText("Set Current Directory..."); setCurrentDirectoryAction->setObjectName("setCurrentDirectoryAction"); QObject::connect(setCurrentDirectoryAction, SIGNAL(triggered(bool)), this, SLOT(slotSetCurrentDirectory())); convertDataFileAction = new QAction(parent); convertDataFileAction->setText("Convert Data File Formats..."); convertDataFileAction->setObjectName("convertDataFileAction"); QObject::connect(convertDataFileAction, SIGNAL(triggered(bool)), this, SLOT(convertDataFileSlot())); copySpecFileAction = new QAction(parent); copySpecFileAction->setText("Copy Spec File..."); copySpecFileAction->setObjectName("copySpecFileAction"); QObject::connect(copySpecFileAction, SIGNAL(triggered(bool)), this, SLOT(copySpecFileSlot())); validateSpecFileAction = new QAction(parent); validateSpecFileAction->setText("Validate a Spec File..."); validateSpecFileAction->setObjectName("validateSpecFileAction"); QObject::connect(validateSpecFileAction, SIGNAL(triggered(bool)), this, SLOT(validateSpecFileSlot())); zipSpecFileAction = new QAction(parent); zipSpecFileAction->setText("Zip a Spec File..."); zipSpecFileAction->setObjectName("zipSpecFileAction"); QObject::connect(zipSpecFileAction, SIGNAL(triggered(bool)), this, SLOT(zipSpecFileSlot())); recordAsMpegAction = new QAction(parent); recordAsMpegAction->setText("Record Main Window Images as Movie..."); recordAsMpegAction->setObjectName("recordAsMpegAction"); QObject::connect(recordAsMpegAction, SIGNAL(triggered(bool)), this, SLOT(recordAsMpegSlot())); dataFileOpenAction = new QAction(parent); dataFileOpenAction->setText("Open Data File..."); dataFileOpenAction->setShortcut(Qt::CTRL+Qt::Key_O); dataFileOpenAction->setObjectName("dataFileOpenAction"); QObject::connect(dataFileOpenAction, SIGNAL(triggered(bool)), this, SLOT(dataFileOpenSlot())); dataFileSaveAction = new QAction(parent); dataFileSaveAction->setText("Save Data File..."); dataFileSaveAction->setShortcut(Qt::CTRL+Qt::Key_S); dataFileSaveAction->setObjectName("dataFileSaveAction"); QObject::connect(dataFileSaveAction, SIGNAL(triggered(bool)), this, SLOT(dataFileSaveSlot())); copyMainWindowToClipboardAction = new QAction(parent); copyMainWindowToClipboardAction->setText("Copy Main Window Image to Clipboard"); copyMainWindowToClipboardAction->setObjectName("copyMainWindowToClipboardAction"); QObject::connect(copyMainWindowToClipboardAction, SIGNAL(triggered(bool)), this, SLOT(copyMainWindowToClipboard())); printMainWindowAction = new QAction(parent); printMainWindowAction->setText("Print Main Window..."); printMainWindowAction->setObjectName("printMainWindowAction"); QObject::connect(printMainWindowAction, SIGNAL(triggered(bool)), this, SLOT(printMainWindowImage())); captureMainWindowImageAction = new QAction(parent); captureMainWindowImageAction->setText("Capture Image of Window..."); captureMainWindowImageAction->setObjectName("captureMainWindowImageAction"); QObject::connect(captureMainWindowImageAction, SIGNAL(triggered(bool)), parent, SLOT(displayCaptureWindowImageDialog())); openSpecFileAction = new QAction(parent); openSpecFileAction->setText("Open Spec File..."); openSpecFileAction->setShortcut(Qt::CTRL+Qt::Key_N); openSpecFileAction->setObjectName("openSpecFileAction"); QObject::connect(openSpecFileAction, SIGNAL(triggered(bool)), this, SLOT(openSpecFileSlot())); addDocumentToSpecFileAction = new QAction(parent); addDocumentToSpecFileAction->setText("Add Document File to Spec File..."); addDocumentToSpecFileAction->setObjectName("addDocumentToSpecFileAction"); QObject::connect(addDocumentToSpecFileAction, SIGNAL(triggered(bool)), this, SLOT(addDocumentToSpecFileSlot())); closeSpecFileAction = new QAction(parent); closeSpecFileAction->setText("Close Current Spec File"); closeSpecFileAction->setObjectName("closeSpecFileAction"); QObject::connect(closeSpecFileAction, SIGNAL(triggered(bool)), parent, SLOT(slotCloseSpecFile())); loadedFileManagementAction = new QAction(parent); loadedFileManagementAction->setText("Manage Loaded Files..."); loadedFileManagementAction->setShortcut(Qt::CTRL+Qt::Key_M); loadedFileManagementAction->setObjectName("loadedFileManagementAction"); QObject::connect(loadedFileManagementAction, SIGNAL(triggered(bool)), this, SLOT(loadedFileManagementSlot())); exitCaretAction = new QAction(parent); exitCaretAction->setText("Exit..."); exitCaretAction->setShortcut(Qt::CTRL+Qt::Key_Q); exitCaretAction->setObjectName("exitCaretAction"); QObject::connect(exitCaretAction, SIGNAL(triggered(bool)), parent, SLOT(slotCloseProgram())); //SLOT(close())); } /** * Destructor. */ GuiMainWindowFileActions::~GuiMainWindowFileActions() { } /** * Called to set the current directory. */ void GuiMainWindowFileActions::slotSetCurrentDirectory() { WuQFileDialog fd(theMainWindow); fd.setModal(true); fd.setAcceptMode(WuQFileDialog::AcceptOpen); fd.setDirectory(QDir::currentPath()); fd.setWindowTitle("Choose Directory"); fd.setFileMode(WuQFileDialog::DirectoryOnly); if (fd.exec() == QDialog::Accepted) { const QString path(fd.directory().absolutePath()); QDir::setCurrent(path); // selectedFiles().at(0)); } } /** * convert data files slot. */ void GuiMainWindowFileActions::convertDataFileSlot() { static GuiConvertDataFileDialog* convertDialog = NULL; if (convertDialog == NULL) { convertDialog = new GuiConvertDataFileDialog(theMainWindow); } convertDialog->show(); convertDialog->activateWindow(); } /** * copy spec file slot. */ void GuiMainWindowFileActions::copySpecFileSlot() { static GuiCopySpecFileDialog* copySpecDialog = NULL; if (copySpecDialog == NULL) { copySpecDialog = new GuiCopySpecFileDialog(theMainWindow, theMainWindow->getBrainSet()->getPreferencesFile()); } copySpecDialog->show(); copySpecDialog->activateWindow(); } /** * validate spec file slot. */ void GuiMainWindowFileActions::validateSpecFileSlot() { GuiChooseSpecFileDialog csfd(theMainWindow, theMainWindow->getBrainSet()->getPreferencesFile(), true); if (csfd.exec() == QDialog::Accepted) { SpecFile sf; try { sf.readFile(csfd.getSelectedSpecFile()); QString msg; if (sf.validate(msg)) { QMessageBox::information(theMainWindow, "SUCCESS", "Spec File is Valid."); } else { QMessageBox::critical(theMainWindow, "ERROR", msg); } } catch (FileException& e) { QMessageBox::critical(theMainWindow, "ERROR", e.whatQString()); } } } /** * zip spec file slot. */ void GuiMainWindowFileActions::zipSpecFileSlot() { static GuiZipSpecFileDialog* zipSpecDialog = NULL; if (zipSpecDialog == NULL) { zipSpecDialog = new GuiZipSpecFileDialog(theMainWindow, theMainWindow->getBrainSet()->getPreferencesFile()); } zipSpecDialog->show(); zipSpecDialog->activateWindow(); } /** * Record as MPEG slot. */ void GuiMainWindowFileActions::recordAsMpegSlot() { theMainWindow->getRecordingDialog(true); } /** * data file open slot. */ void GuiMainWindowFileActions::dataFileOpenSlot() { PreferencesFile* pf = theMainWindow->getBrainSet()->getPreferencesFile(); static GuiDataFileOpenDialog* fd = NULL; if (fd == NULL) { fd = new GuiDataFileOpenDialog(theMainWindow); } fd->setHistory(pf->getRecentDataFileDirectories()); fd->setDirectory(QDir::currentPath()); fd->show(); fd->raise(); fd->activateWindow(); } /** * data file save slot. */ void GuiMainWindowFileActions::dataFileSaveSlot() { static QString lastFileFilter; GuiDataFileSaveDialog fd(theMainWindow); if (lastFileFilter.isEmpty() == false) { fd.selectFileType(lastFileFilter); } fd.exec(); lastFileFilter = fd.getFileTypeFilter(); } /** * copy main window image to clipboard. */ void GuiMainWindowFileActions::copyMainWindowToClipboard() { QImage image; theMainWindow->getBrainModelOpenGL()->captureImage(image); QApplication::clipboard()->setImage(image, QClipboard::Clipboard); } /** * print main window image. */ void GuiMainWindowFileActions::printMainWindowImage() { #ifdef Q_OS_WIN32 QTime timer; timer.start(); #endif // Q_OS_WIN32 QPrinter printer; QPrintDialog pd(&printer, theMainWindow); if (pd.exec() == QDialog::Accepted) { QImage image; theMainWindow->getBrainModelOpenGL()->captureImage(image); QPainter painter(&printer); painter.drawImage(0, 0, image); } #ifdef Q_OS_WIN32 if (timer.elapsed() < 2000) { QString msg = "If you did not see the Print Dialog, then printing\n" "will not work on your computer. This is a problem\n" "seen on Windows versions of Caret5 and there is no\n" "solution to this problem."; QMessageBox::critical(theMainWindow, "ERROR", msg); } #endif // Q_OS_WIN32 } /** * add document to spec file action. */ void GuiMainWindowFileActions::addDocumentToSpecFileSlot() { QStringList allFileFilters; FileFilters::getAllFileFilters(allFileFilters); WuQFileDialog fd(theMainWindow); fd.setAcceptMode(WuQFileDialog::AcceptOpen); fd.setDirectory("."); fd.setFileMode(WuQFileDialog::ExistingFile); fd.setFilters(allFileFilters); fd.setLabelText(WuQFileDialog::Accept, "Add"); if (fd.exec() == WuQFileDialog::Accepted) { if (fd.selectedFiles().size() > 0) { const QString name = fd.selectedFiles().at(0); theMainWindow->getBrainSet()->addDocumentFile(name); } } } /** * Launch a file selection dialog to choose a spec file. */ void GuiMainWindowFileActions::openSpecFileSlot() { GuiChooseSpecFileDialog csfd(theMainWindow, theMainWindow->getBrainSet()->getPreferencesFile(), true, true); if (csfd.exec() == QDialog::Accepted) { std::vector specFileNames = csfd.getSelectedSpecFiles(); const int numSpecFiles = static_cast(specFileNames.size()); if (numSpecFiles == 1) { theMainWindow->readSpecFile(specFileNames[0]); } else { // // If data files loaed allow append or replace // QMessageBox msgBox(theMainWindow); msgBox.setWindowTitle("Spec File Open"); msgBox.setText("You have selected multiple spec files. Do " "you want to load all files in each of the " "spec files or pick and choose files in each" "of the spec files?"); QPushButton* loadAllPushButton = msgBox.addButton("Load All", QMessageBox::ActionRole); QPushButton* pickAndChoosePushButton = msgBox.addButton("Pick and Choose", QMessageBox::ActionRole); QPushButton* cancelPushButton = msgBox.addButton("Cancel", QMessageBox::ActionRole); msgBox.exec(); int answer = 0; if (msgBox.clickedButton() == loadAllPushButton) { answer = 0; } else if (msgBox.clickedButton() == pickAndChoosePushButton) { answer = 1; } else if (msgBox.clickedButton() == cancelPushButton) { answer = 2; } if (answer == 0) { QString msg; for (int i = 0; i < numSpecFiles; i++) { try { SpecFile sf; QString path(FileUtilities::dirname(specFileNames[i])); if (QDir::isRelativePath(path)) { path = QDir::currentPath(); path.append("/"); path.append(specFileNames[i]); specFileNames[i] = QDir::cleanPath(path); } sf.readFile(specFileNames[i]); sf.setAllFileSelections(SpecFile::SPEC_TRUE); theMainWindow->loadSpecFilesDataFiles(sf, NULL, true); } catch (FileException& e) { msg += e.whatQString() + "\n"; } } if (msg.isEmpty() == false) { QMessageBox::warning(theMainWindow, "ERROR", msg); } } else if (answer == 1) { for (int i = 0; i < numSpecFiles; i++) { theMainWindow->readSpecFile(specFileNames[i]); } } } } } /** * Popup the view current files dialog. */ void GuiMainWindowFileActions::loadedFileManagementSlot() { GuiLoadedFileManagementDialog* lfmd = new GuiLoadedFileManagementDialog(theMainWindow); lfmd->show(); } /** * update the actions (typically called when menu is about to show) */ void GuiMainWindowFileActions::updateActions() { QString name("Close Spec File"); if (theMainWindow != NULL) { BrainSet* activeBrainSet = theMainWindow->getBrainSet(); if (activeBrainSet != NULL) { QString specName(activeBrainSet->getSpecFileName()); if (specName.length() > 1) { name.append(" "); name.append(FileUtilities::basename(specName)); } } } closeSpecFileAction->setText(name); } caret-5.6.4~dfsg.1.orig/caret/GuiMainWindowCommMenu.h0000664000175000017500000000245111572067322022214 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_MAIN_WINDOW_COMM_MENU_H__ #define __GUI_MAIN_WINDOW_COMM_MENU_H__ #include class GuiMainWindow; class GuiSumsDialog; /// This class creates the Main Window's Comm Menu class GuiMainWindowCommMenu : public QMenu { Q_OBJECT public: /// constructor GuiMainWindowCommMenu(GuiMainWindow* parent); /// destructor ~GuiMainWindowCommMenu(); private: }; #endif caret-5.6.4~dfsg.1.orig/caret/GuiMainWindowCommMenu.cxx0000664000175000017500000000327211572067322022571 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "DebugControl.h" #include "GuiMainWindow.h" #include "GuiMainWindowCommActions.h" #include "GuiMainWindowCommMenu.h" /** * Constructor */ GuiMainWindowCommMenu::GuiMainWindowCommMenu(GuiMainWindow* parent) : QMenu("Comm", parent) { GuiMainWindowCommActions* commActions = parent->getCommActions(); addAction(commActions->getAfniConnectAction()); addAction(commActions->getAfniDisconnectAction()); addSeparator(); addAction(commActions->getFivConnectAction()); addAction(commActions->getFivDisconnectAction()); addSeparator(); addAction(commActions->getSumsDatabaseAction()); QObject::connect(this, SIGNAL(aboutToShow()), commActions, SLOT(updateActions())); } /** * Destructor */ GuiMainWindowCommMenu::~GuiMainWindowCommMenu() { } caret-5.6.4~dfsg.1.orig/caret/GuiMainWindowCommActions.h0000664000175000017500000000534111572067322022711 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_MAIN_WINDOW_COMM_ACTIONS_H__ #define __GUI_MAIN_WINDOW_COMM_ACTIONS_H__ #include class GuiMainWindow; class GuiSumsDialog; class QAction; /// This class creates the Main Window's Comm Actions class GuiMainWindowCommActions : public QObject { Q_OBJECT public: /// constructor GuiMainWindowCommActions(GuiMainWindow* parent); /// destructor ~GuiMainWindowCommActions(); /// afni connect action QAction* getAfniConnectAction() { return afniConnectAction; } /// afni disconnect action QAction* getAfniDisconnectAction() { return afniDisconnectAction; } /// fiv connect action QAction* getFivConnectAction() { return fivConnectAction; } /// fiv disconnect action QAction* getFivDisconnectAction() { return fivDisconnectAction; } /// sums database action QAction* getSumsDatabaseAction() { return sumsDatabaseAction; } public slots: /// update the actions (typically called when menu is about to show) void updateActions(); private slots: /// this slot is called if the user chooses to connect to afni void slotAfniConnect(); /// this slot is called if the user chooses to connect to fiv void slotFivConnect(); /// SuMS database void sumsDatabaseSlot(); private: /// the SuMS database dialog GuiSumsDialog* sumsDialog; /// afni connect action QAction* afniConnectAction; /// afni disconnect action QAction* afniDisconnectAction; /// fiv connect action QAction* fivConnectAction; /// fiv disconnect action QAction* fivDisconnectAction; /// sums database action QAction* sumsDatabaseAction; }; #endif // __GUI_MAIN_WINDOW_COMM_ACTIONS_H__ caret-5.6.4~dfsg.1.orig/caret/GuiMainWindowCommActions.cxx0000664000175000017500000000767111572067322023274 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainSet.h" #include "CommunicatorClientAFNI.h" #include "CommunicatorClientFIV.h" #include "GuiMainWindow.h" #include "GuiMainWindowCommActions.h" #include "GuiSumsDialog.h" #include "global_variables.h" /** * Constructor */ GuiMainWindowCommActions::GuiMainWindowCommActions(GuiMainWindow* parent) : QObject(parent) { setObjectName("GuiMainWindowCommActions"); sumsDialog = NULL; afniConnectAction = new QAction(parent); afniConnectAction->setText("Connect to AFNI..."); afniConnectAction->setObjectName("afniConnectAction"); QObject::connect(afniConnectAction, SIGNAL(triggered(bool)), this, SLOT(slotAfniConnect())); afniDisconnectAction = new QAction(parent); afniDisconnectAction->setText("Close AFNI Connection"); afniDisconnectAction->setObjectName("afniDisconnectAction"); QObject::connect(afniDisconnectAction, SIGNAL(triggered(bool)), parent->getAfniClientCommunicator(), SLOT(closeConnection())); fivConnectAction = new QAction(parent); fivConnectAction->setText("Connect to FIV..."); fivConnectAction->setObjectName("fivConnectAction"); QObject::connect(fivConnectAction, SIGNAL(triggered(bool)), this, SLOT(slotFivConnect())); fivDisconnectAction = new QAction(parent); fivDisconnectAction->setText("Close FIV Connection"); fivDisconnectAction->setObjectName("fivDisconnectAction"); QObject::connect(fivDisconnectAction, SIGNAL(triggered(bool)), parent->getFivClientCommunicator(), SLOT(closeConnection())); sumsDatabaseAction = new QAction(parent); sumsDatabaseAction->setText("Connect to SumsDB Database..."); sumsDatabaseAction->setObjectName("sumsDatabaseAction"); QObject::connect(sumsDatabaseAction, SIGNAL(triggered(bool)), this, SLOT(sumsDatabaseSlot())); } /** * Destructor */ GuiMainWindowCommActions::~GuiMainWindowCommActions() { } /** * Called if connect to AFNI is selected. */ void GuiMainWindowCommActions::slotAfniConnect() { TransformationMatrixFile* tmf = theMainWindow->getBrainSet()->getTransformationMatrixFile(); if (tmf->getNumberOfMatrices() == 0) { QMessageBox::critical(theMainWindow, "Communication Error", "There are no transformation matrix files loaded which \n" "are necessary for successful communication with AFNI."); return; } theMainWindow->getAfniClientCommunicator()->openConnection(); } /** * Called if connect to FIV is selected. */ void GuiMainWindowCommActions::slotFivConnect() { theMainWindow->getFivClientCommunicator()->openConnection(); } /** * SuMS database. */ void GuiMainWindowCommActions::sumsDatabaseSlot() { if (sumsDialog == NULL) { sumsDialog = new GuiSumsDialog(theMainWindow, theMainWindow->getBrainSet()->getPreferencesFile()); } sumsDialog->show(); sumsDialog->activateWindow(); } /** * update the actions (typically called when menu is about to show) */ void GuiMainWindowCommActions::updateActions() { } caret-5.6.4~dfsg.1.orig/caret/GuiMainWindowAttributesMenu.h0000664000175000017500000000770311572067322023454 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_MAIN_WINDOW_ATTRIBUTES_MENU_H__ #define __GUI_MAIN_WINDOW_ATTRIBUTES_MENU_H__ #include class GuiMainWindow; class GuiMainWindowAttributesActions; /// the main windows attributes menu class GuiMainWindowAttributesMenu : public QMenu { Q_OBJECT public: /// Constructor GuiMainWindowAttributesMenu(GuiMainWindow* parent); /// Constructor ~GuiMainWindowAttributesMenu(); private: /// create the area colors menu void createAreaColorsSubMenu(GuiMainWindowAttributesActions* attributesActions); /// create the areal estimation menu void createArealEstimationSubMenu(GuiMainWindowAttributesActions* attributesActions); /// create the lat/lon sub menu void createLatLonSubMenu(GuiMainWindowAttributesActions* attributesActions); /// create the metric sub menu void createMetricSubMenu(GuiMainWindowAttributesActions* attributesActions); /// create the models sub menu void createModelsSubMenu(GuiMainWindowAttributesActions* attributesActions); /// create the paint sub menu void createPaintSubMenu(GuiMainWindowAttributesActions* attributesActions); /// create the prob atlas sub menu void createProbAtlasSubMenu(GuiMainWindowAttributesActions* attributesActions); /// create the palette sub menu void createPaletteSubMenu(GuiMainWindowAttributesActions* attributesActions); /// create the parameters sub menu void createParametersSubMenu(GuiMainWindowAttributesActions* attributesActions); /// create the study metadata sub menu void createStudyMetaDataSubMenu(GuiMainWindowAttributesActions* attributesActions); /// create the surface shape sub menu void createSurfaceShapeSubMenu(GuiMainWindowAttributesActions* attributesActions); /// create the vectors sub menu void createVectorsSubMenu(GuiMainWindowAttributesActions* attributesActions); /// Create the vocabulary sub menu. void createVocabularySubMenu(GuiMainWindowAttributesActions* attributesActions); /// area colors menu QMenu* areaColorsSubMenu; /// areal estimation menu QMenu* arealEstimationSubMenu; /// lat/lon sub menu QMenu* latLonSubMenu; /// Metric sub menu QMenu* metricSubMenu; /// Models sub menu QMenu* modelsSubMenu; /// Paint sub menu QMenu* paintSubMenu; /// Prob atlas sub menu QMenu* probAtlasSubMenu; /// Palette sub menu QMenu* paletteSubMenu; /// Parameters sub menu QMenu* parametersSubMenu; /// Rgb paint sub menu QMenu* rgbPaintSubMenu; /// study meta data sub menu QMenu* studyMetaDataMenu; /// surface shape sub menu QMenu* surfaceShapeSubMenu; /// vectors sub menu QMenu* vectorsSubMenu; /// vocabulary sub menu QMenu* vocabularySubMenu; }; #endif // __GUI_MAIN_WINDOW_ATTRIBUTES_MENU_H__ caret-5.6.4~dfsg.1.orig/caret/GuiMainWindowAttributesMenu.cxx0000664000175000017500000002031311572067322024017 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "GuiMainWindow.h" #include "GuiMainWindowAttributesActions.h" #include "GuiMainWindowAttributesMenu.h" #include "global_variables.h" /** * Constructor. */ GuiMainWindowAttributesMenu::GuiMainWindowAttributesMenu(GuiMainWindow* parent) : QMenu("Attributes", parent) { setObjectName("GuiMainWindowAttributesMenu"); GuiMainWindowAttributesActions* attributesActions = parent->getAttributesActions(); createAreaColorsSubMenu(attributesActions); createArealEstimationSubMenu(attributesActions); addAction(attributesActions->getConnectivityAction()); createLatLonSubMenu(attributesActions); createMetricSubMenu(attributesActions); createModelsSubMenu(attributesActions); createPaintSubMenu(attributesActions); createPaletteSubMenu(attributesActions); createParametersSubMenu(attributesActions); createProbAtlasSubMenu(attributesActions); createStudyMetaDataSubMenu(attributesActions); createSurfaceShapeSubMenu(attributesActions); createVectorsSubMenu(attributesActions); createVocabularySubMenu(attributesActions); addSeparator(); addAction(attributesActions->getGenerateDeformationFieldAction()); addAction(attributesActions->getGenerateTopographyAction()); addAction(attributesActions->getCopyColoringToRgbPaintAction()); //addAction(attributesActions->getCopyNormalsToRgbPaintAction()); addAction(attributesActions->getCopyColoringToVolumeAction()); addSeparator(); addAction(attributesActions->getVolumeToSurfaceMapperAction()); QObject::connect(this, SIGNAL(aboutToShow()), attributesActions, SLOT(updateActions())); } /** * Destructor. */ GuiMainWindowAttributesMenu::~GuiMainWindowAttributesMenu() { } /** * Create the vocabulary sub menu. */ void GuiMainWindowAttributesMenu::createVocabularySubMenu(GuiMainWindowAttributesActions* attributesActions) { vocabularySubMenu = addMenu("Vocabulary"); vocabularySubMenu->addAction(attributesActions->getVocabularyFileEditorDialogAction()); vocabularySubMenu->addAction(attributesActions->getVocabularyMoveStudyInfoToStudyMetaDataAction()); } /** * create the areal estimation menu. */ void GuiMainWindowAttributesMenu::createArealEstimationSubMenu(GuiMainWindowAttributesActions* attributesActions) { arealEstimationSubMenu = addMenu("Areal Estimation"); //arealEstimationSubMenu->addAction(attributesActions->getArealEstimationClearAllOrPartAction()); arealEstimationSubMenu->addAction(attributesActions->getGenerateArealEstimationMapAction()); } /** * Create the area colors sub menu. */ void GuiMainWindowAttributesMenu::createAreaColorsSubMenu(GuiMainWindowAttributesActions* attributesActions) { areaColorsSubMenu = addMenu("Area Colors"); areaColorsSubMenu->addAction(attributesActions->getAreaColorsEditAction()); } /** * create the models sub menu */ void GuiMainWindowAttributesMenu::createModelsSubMenu(GuiMainWindowAttributesActions* attributesActions) { modelsSubMenu = addMenu("Models"); modelsSubMenu->addAction(attributesActions->getModelsEditorAction()); } /** * create the metrics sub menu */ void GuiMainWindowAttributesMenu::createMetricSubMenu(GuiMainWindowAttributesActions* attributesActions) { metricSubMenu = addMenu("Metric"); //metricSubMenu->addAction(attributesActions->getMetricClearAllOrPartAction()); //metricSubMenu->addSeparator(); metricSubMenu->addAction(attributesActions->getMetricModificationAction()); metricSubMenu->addAction(attributesActions->getMetricAverageDeviationAction()); metricSubMenu->addAction(attributesActions->getMetricMathAction()); metricSubMenu->addSeparator(); metricSubMenu->addAction(attributesActions->getMetricToVolumeAction()); metricSubMenu->addAction(attributesActions->getMetricToRgbPaintAction()); } /** * create the palette sub menu. */ void GuiMainWindowAttributesMenu::createPaletteSubMenu(GuiMainWindowAttributesActions* attributesActions) { paletteSubMenu = addMenu("Palette"); paletteSubMenu->addAction(attributesActions->getDisplayPaletteEditor()); } /** * create the parameters file sub menu. */ void GuiMainWindowAttributesMenu::createParametersSubMenu(GuiMainWindowAttributesActions* attributesActions) { parametersSubMenu = addMenu("Parameters"); parametersSubMenu->addAction(attributesActions->getDisplayParamsFileEditor()); } /** * create the prob atlas sub menu. */ void GuiMainWindowAttributesMenu::createProbAtlasSubMenu(GuiMainWindowAttributesActions* attributesActions) { probAtlasSubMenu = addMenu("Probabilistic Atlas"); probAtlasSubMenu->addAction(attributesActions->getProbAtlasThresholdToPaintAction()); } /** * create the paint sub menu. */ void GuiMainWindowAttributesMenu::createPaintSubMenu(GuiMainWindowAttributesActions* attributesActions) { paintSubMenu = addMenu("Paint"); paintSubMenu->addAction(attributesActions->getPaintAssignWithinDisplayedBordersAction()); paintSubMenu->addAction(attributesActions->getPaintCleanNamesAction()); //paintSubMenu->addAction(attributesActions->getPaintClearAllOrPartAction()); paintSubMenu->addAction(attributesActions->getPaintToVolumeAction()); paintSubMenu->addAction(attributesActions->getPaintNamesEditAction()); paintSubMenu->addAction(attributesActions->getGenerateColorsForPaints()); } /** * create the study metadata sub menu. */ void GuiMainWindowAttributesMenu::createStudyMetaDataSubMenu(GuiMainWindowAttributesActions* attributesActions) { studyMetaDataMenu = addMenu("Study Metadata"); studyMetaDataMenu->addAction(attributesActions->getStudyCollectionEditorDialogAction()); studyMetaDataMenu->addAction(attributesActions->getStudyMetaDataEditorDialogAction()); } /** * create the surface shape sub menu. */ void GuiMainWindowAttributesMenu::createSurfaceShapeSubMenu(GuiMainWindowAttributesActions* attributesActions) { surfaceShapeSubMenu = addMenu("Surface Shape"); //surfaceShapeSubMenu->addAction(attributesActions->getSurfaceShapeClearAllOrPartAction()); //surfaceShapeSubMenu->addSeparator(); surfaceShapeSubMenu->addAction(attributesActions->getShapeModificationAction()); surfaceShapeSubMenu->addAction(attributesActions->getShapeMathAction()); surfaceShapeSubMenu->addSeparator(); surfaceShapeSubMenu->addAction(attributesActions->getSurfaceShapeAverageDeviationAction()); surfaceShapeSubMenu->addSeparator(); surfaceShapeSubMenu->addAction(attributesActions->getSurfaceShapeToVolumeAction()); } /** * create the lat/lon sub menu. */ void GuiMainWindowAttributesMenu::createLatLonSubMenu(GuiMainWindowAttributesActions* attributesActions) { latLonSubMenu = addMenu("Lat/Long"); //latLonSubMenu->addAction(attributesActions->getLatLonClearAllOrPartAction()); latLonSubMenu->addAction(attributesActions->getLatLonGenerateOnSphereAction()); } /** * create the vectors sub menu. */ void GuiMainWindowAttributesMenu::createVectorsSubMenu(GuiMainWindowAttributesActions* attributesActions) { vectorsSubMenu = addMenu("Vectors"); vectorsSubMenu->addAction(attributesActions->getCoordsToVectorsAction()); vectorsSubMenu->addAction(attributesActions->getNormalsToVectorsAction()); } caret-5.6.4~dfsg.1.orig/caret/GuiMainWindowAttributesActions.h0000664000175000017500000003261711572067322024152 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_MAIN_WINDOW_ATTRIBUTES_ACTIONS_H__ #define __GUI_MAIN_WINDOW_ATTRIBUTES_ACTIONS_H__ #include class GuiMainWindow; class QAction; /// the main windows attributes actions class GuiMainWindowAttributesActions : public QObject { Q_OBJECT public: /// Constructor GuiMainWindowAttributesActions(GuiMainWindow* parent); /// Destructor ~GuiMainWindowAttributesActions(); /// for generating topology QAction* getGenerateTopographyAction() { return generateTopographyAction; } /// for generating an areal estimation map QAction* getGenerateArealEstimationMapAction() { return generateArealEstimationMapAction; } /// for area color editing QAction* getAreaColorsEditAction() { return areaColorsEditAction; } /// for display palette editor QAction* getDisplayPaletteEditor() { return displayPaletteEditorAction; } /// for display params file editor QAction* getDisplayParamsFileEditor() { return displayParamsFileEditorAction; } /// for metric math QAction* getMetricMathAction() { return metricMathAction; } /// for metric to rgb paint QAction* getMetricToRgbPaintAction() { return metricToRgbPaintAction; } /// for metric average and deviation QAction* getMetricAverageDeviationAction() { return metricAverageDeviationAction; } /// for converting metric column to a functional volume QAction* getMetricToVolumeAction() { return metricToVolumeAction; } /// for clearing all or part of the metric file QAction* getMetricClearAllOrPartAction() { return metricClearAllOrPartAction; } /// for volume to surface mapper QAction* getVolumeToSurfaceMapperAction() { return volumeToSurfaceMapperAction; } /// for modifying metric data QAction* getMetricModificationAction() { return metricModificationAction; } /// for converting surface shape to a functional volume QAction* getSurfaceShapeToVolumeAction() { return surfaceShapeToVolumeAction; } /// for clearing all or part of the surface shape file QAction* getSurfaceShapeClearAllOrPartAction() { return surfaceShapeClearAllOrPartAction; } /// compute average and deviation of surface shape QAction* getSurfaceShapeAverageDeviationAction() { return surfaceShapeAverageDeviationAction; } /// for shape math dialog QAction* getShapeMathAction() { return shapeMathAction; } /// for modifying shape data QAction* getShapeModificationAction() { return shapeModificationAction; } /// for cleaning paint file names QAction* getPaintCleanNamesAction() { return paintCleanNamesAction; } /// for generates names for paints QAction* getGenerateColorsForPaints() { return generateColorsForPaints; } /// for converting paint to volume QAction* getPaintToVolumeAction() { return paintToVolumeAction; } /// for editing paint names QAction* getPaintNamesEditAction() { return paintNamesEditAction; } /// for assigning paints within displayed borders QAction* getPaintAssignWithinDisplayedBordersAction() { return paintAssignWithinDisplayedBordersAction; } /// for clearing all or part of the paint file QAction* getPaintClearAllOrPartAction() { return paintClearAllOrPartAction; } /// for clearing all or part of areal estimationo file QAction* getArealEstimationClearAllOrPartAction() { return arealEstimationClearAllOrPartAction; } /// for copying current coloring to rgb paint QAction* getCopyColoringToRgbPaintAction() { return copyColoringToRgbPaintAction; } /// Called to copy surface normals to RGB Paint. QAction* getCopyNormalsToRgbPaintAction() { return copyNormalsToRgbPaintAction; } /// for copying current coloring to a volume QAction* getCopyColoringToVolumeAction() { return copyColoringToVolumeAction; } /// clear all or part of a lat/long file QAction* getLatLonClearAllOrPartAction() { return latLonClearAllOrPartAction; } /// generate lat/long on a spherical surface QAction* getLatLonGenerateOnSphereAction() { return latLonGenerateOnSphereAction; } /// generate a deformation field QAction* getGenerateDeformationFieldAction() { return generateDeformationFieldAction; } /// convert prob atlas threshold coloring to paint QAction* getProbAtlasThresholdToPaintAction() { return probAtlasThresholdToPaintAction; } /// convert coord files to vectors QAction* getCoordsToVectorsAction() { return coordsToVectorsAction; } /// place normals in the vectors QAction* getNormalsToVectorsAction() { return normalsToVectorsAction; } /// get the models editor action QAction* getModelsEditorAction() { return modelsEditorAction; } /// get the study meta data editor action QAction* getStudyMetaDataEditorDialogAction() { return studyMetaDataEditorDialogAction; } /// get the study collection editor action QAction* getStudyCollectionEditorDialogAction() { return studyCollectionEditorDialogAction; } /// get the vocabulary file editor action QAction* getVocabularyFileEditorDialogAction() { return vocabularyFileEditorDialogAction; } /// get the vocabulary study info to study metadata file action QAction* getVocabularyMoveStudyInfoToStudyMetaDataAction() { return vocabularyMoveStudyInfoToStudyMetaDataAction; } /// connectivity action QAction* getConnectivityAction() { return connectivityAction; } public slots: /// update the actions (typically called when menu is about to show) void updateActions(); private slots: /// slot for generating topology void slotGenerateTopography(); /// slot for generating an areal estimation map void slotGenerateArealEstimationMap(); /// slot for area color editing void slotAreaColorsEdit(); /// slot called when area colors are changed in color editor void slotAreaColorsChanged(); /// slot for metric to rgb paint void slotMetricToRgbPaint(); /// slot for metric average and deviation void slotMetricAverageDeviation(); /// slot for converting metric column to a functional volume void slotMetricToVolume(); /// slot for clearing all or part of the metric file void slotMetricClearAllOrPart(); /// slot for volume to surface mapper void slotVolumeToSurfaceMapper(); /// slot for volume to surface mapper complete void slotVolumeToSurfaceMapperComplete(); /// slot for modifying metric data void slotMetricModification(); /// slot for converting surface shape to a functional volume void slotSurfaceShapeToVolume(); /// slot for clearing all or part of the surface shape file void slotSurfaceShapeClearAllOrPart(); /// compute average and deviation of surface shape void slotSurfaceShapeAverageDeviation(); /// slot for modifying shape data void slotShapeModification(); /// slot for cleaning paint file names void slotPaintCleanNames(); /// slot for generating colors for non-matching paint names void slotGenerateColorsForPaints(); /// slot for converting paint to volume void slotPaintToVolume(); /// slot for assigning paints within displayed borders void slotPaintAssignWithinDisplayedBorders(); /// slot for clearing all or part of the paint file void slotPaintClearAllOrPart(); /// slot for clearing all or part of the areal estimation file void slotArealEstimationClearAllOrPart(); /// slot for copying current coloring to rgb paint void slotCopyColoringToRgbPaint(); /// Called to copy surface normals to RGB Paint. void slotCopyNormalsToRgbPaint(); /// slot for copying current coloring to a volume void slotCopyColoringToVolume(); /// clear all or part of a lat/long file void slotLatLonClearAllOrPart(); /// generate lat/long on a spherical surface void slotLatLonGenerateOnSphere(); /// generate a deformation field void slotGenerateDeformationField(); /// convert prob atlas threshold coloring to paint void slotProbAtlasThresholdToPaint(); /// convert coord files to vectors void slotCoordsToVectors(); /// convert normals to vectors void slotNormalsToVectors(); /// convert vocabulary study info to study metadata file void slotVocabularyMoveStudyInfoToStudyMetaData(); protected: /// for generating topology QAction* generateTopographyAction; /// for generating an areal estimation map QAction* generateArealEstimationMapAction; /// for area color editing QAction* areaColorsEditAction; /// for display palette editor QAction* displayPaletteEditorAction; /// for display params file editor QAction* displayParamsFileEditorAction; /// for metric math QAction* metricMathAction; /// for metric to rgb paint QAction* metricToRgbPaintAction; /// for metric average and deviation QAction* metricAverageDeviationAction; /// for converting metric column to a functional volume QAction* metricToVolumeAction; /// for clearing all or part of the metric file QAction* metricClearAllOrPartAction; /// for volume to surface mapper QAction* volumeToSurfaceMapperAction; /// for modifying metric data QAction* metricModificationAction; /// for converting surface shape to a functional volume QAction* surfaceShapeToVolumeAction; /// for clearing all or part of the surface shape file QAction* surfaceShapeClearAllOrPartAction; /// compute average and deviation of surface shape QAction* surfaceShapeAverageDeviationAction; /// for shape math dialog QAction* shapeMathAction; /// for modifying shape data QAction* shapeModificationAction; /// for cleaning paint file names QAction* paintCleanNamesAction; /// for generate colors for paints QAction* generateColorsForPaints; /// for converting paint to volume QAction* paintToVolumeAction; /// for editing paint names QAction* paintNamesEditAction; /// for assigning paints within displayed borders QAction* paintAssignWithinDisplayedBordersAction; /// for clearing all or part of the paint file QAction* paintClearAllOrPartAction; /// for clearing all or part of areal estimation file QAction* arealEstimationClearAllOrPartAction; /// for copying current coloring to rgb paint QAction* copyColoringToRgbPaintAction; /// Called to copy surface normals to RGB Paint. QAction* copyNormalsToRgbPaintAction; /// for copying current coloring to a volume QAction* copyColoringToVolumeAction; /// clear all or part of a lat/long file QAction* latLonClearAllOrPartAction; /// generate lat/long on a spherical surface QAction* latLonGenerateOnSphereAction; /// generate a deformation field QAction* generateDeformationFieldAction; /// convert prob atlas threshold coloring to paint QAction* probAtlasThresholdToPaintAction; /// convert coord files to vectors QAction* coordsToVectorsAction; /// convert normals to vectors action QAction* normalsToVectorsAction; /// models editor action QAction* modelsEditorAction; /// study meta data action QAction* studyMetaDataEditorDialogAction; /// study collection action QAction* studyCollectionEditorDialogAction; /// vocabulary file editor action QAction* vocabularyFileEditorDialogAction; /// vocabulary study info to study metadata action QAction* vocabularyMoveStudyInfoToStudyMetaDataAction; /// connectivity action QAction* connectivityAction; }; #endif // __GUI_MAIN_WINDOW_ATTRIBUTES_ACTIONS_H__ caret-5.6.4~dfsg.1.orig/caret/GuiMainWindowAttributesActions.cxx0000664000175000017500000014062511572067322024524 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "AreaColorFile.h" #include "BorderToTopographyConverter.h" #include "BrainModelBorderSet.h" #include "BrainModelSurfaceToVolumeConverter.h" #include "BrainModelSurfaceNodeColoring.h" #include "BrainSet.h" #include "DisplaySettingsProbabilisticAtlas.h" #include "GuiBrainModelOpenGL.h" #include "GuiChooseNodeAttributeColumnDialog.h" #include "GuiColorFileEditorDialog.h" #include "GuiCurrentColoringToRgbPaintDialog.h" #include "GuiDeformationFieldDialog.h" #include "GuiGenerateArealEstimationDialog.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "GuiMainWindowAttributesActions.h" #include "GuiMapFmriDialog.h" #include "GuiChooseNodeAttributeColumnDialog.h" #include "GuiNodeAttributeColumnSelectionComboBox.h" #include "GuiNodeAttributeFileClearResetDialog.h" #include "GuiPaintNameEditorDialog.h" #include "GuiSurfaceToVolumeDialog.h" #include "GuiShapeOrVectorsFromCoordinateSubtractionDialog.h" #include "LatLonFile.h" #include "MetricFile.h" #include "PaintFile.h" #include "ProbabilisticAtlasFile.h" #include "QtTableDialog.h" #include "RgbPaintFile.h" #include "StudyMetaDataFile.h" #include "SurfaceShapeFile.h" #include "VectorFile.h" #include "VocabularyFile.h" #include "WuQDataEntryDialog.h" #include "global_variables.h" /** * Constructor. */ GuiMainWindowAttributesActions::GuiMainWindowAttributesActions(GuiMainWindow* parent) : QObject(parent) { setObjectName("GuiMainWindowAttributesActions"); generateTopographyAction = new QAction(parent); generateTopographyAction->setText("Generate Topography From Borders and Paint"); //generateTopographyAction->setName("generateTopographyAction"); QObject::connect(generateTopographyAction, SIGNAL(triggered(bool)), this, SLOT(slotGenerateTopography())); generateArealEstimationMapAction = new QAction(parent); generateArealEstimationMapAction->setText("Generate Areal Estimation Map..."); //generateArealEstimationMapAction->setName("generateArealEstimationMapAction"); QObject::connect(generateArealEstimationMapAction, SIGNAL(triggered(bool)), this, SLOT(slotGenerateArealEstimationMap())); displayParamsFileEditorAction = new QAction(parent); displayParamsFileEditorAction->setText("Edit..."); //displayParamsFileEditorAction->setName("displayParamsFileEditorAction"); QObject::connect(displayParamsFileEditorAction, SIGNAL(triggered(bool)), parent, SLOT(displayParamsFileEditorDialog())); displayPaletteEditorAction = new QAction(parent); displayPaletteEditorAction->setText("Edit..."); //displayPaletteEditorAction->setName("displayPaletteEditorAction"); QObject::connect(displayPaletteEditorAction, SIGNAL(triggered(bool)), parent, SLOT(displayPaletteEditorDialog())); areaColorsEditAction = new QAction(parent); areaColorsEditAction->setText("Edit..."); //areaColorsEditAction->setName("areaColorsEditAction"); QObject::connect(areaColorsEditAction, SIGNAL(triggered(bool)), this, SLOT(slotAreaColorsEdit())); metricMathAction = new QAction(parent); metricMathAction->setText("Mathematical Operations..."); //metricMathAction->setName("metricMathAction"); QObject::connect(metricMathAction, SIGNAL(triggered(bool)), parent, SLOT(displayMetricMathDialog())); metricToRgbPaintAction = new QAction(parent); metricToRgbPaintAction->setText("Convert Metric to RGB Paint..."); //metricToRgbPaintAction->setName("metricToRgbPaintAction"); QObject::connect(metricToRgbPaintAction, SIGNAL(triggered(bool)), this, SLOT(slotMetricToRgbPaint())); metricAverageDeviationAction = new QAction(parent); metricAverageDeviationAction->setText("Compute Average and Sample Standard Deviation of All Columns..."); //metricAverageDeviationAction->setName("metricAverageDeviationAction"); QObject::connect(metricAverageDeviationAction, SIGNAL(triggered(bool)), this, SLOT(slotMetricAverageDeviation())); metricToVolumeAction = new QAction(parent); metricToVolumeAction->setText("Convert Metric Column to Functional Volume..."); //metricToVolumeAction->setName("metricToVolumeAction"); QObject::connect(metricToVolumeAction, SIGNAL(triggered(bool)), this, SLOT(slotMetricToVolume())); metricClearAllOrPartAction = new QAction(parent); metricClearAllOrPartAction->setText("Clear All or Part of Metric File..."); //metricClearAllOrPartAction->setName("metricClearAllOrPartAction"); QObject::connect(metricClearAllOrPartAction, SIGNAL(triggered(bool)), this, SLOT(slotMetricClearAllOrPart())); volumeToSurfaceMapperAction = new QAction(parent); volumeToSurfaceMapperAction->setText("Map Volume(s) to Surface(s)..."); //volumeToSurfaceMapperAction->setName("volumeToSurfaceMapperAction"); QObject::connect(volumeToSurfaceMapperAction, SIGNAL(triggered(bool)), this, SLOT(slotVolumeToSurfaceMapper())); metricModificationAction = new QAction(parent); metricModificationAction->setText("Clustering and Smoothing..."); //metricModificationAction->setName("metricModificationAction"); QObject::connect(metricModificationAction, SIGNAL(triggered(bool)), this, SLOT(slotMetricModification())); surfaceShapeToVolumeAction = new QAction(parent); surfaceShapeToVolumeAction->setText("Convert Surface Shape Column to Functional Volume..."); //surfaceShapeToVolumeAction->setName("surfaceShapeToVolumeAction"); QObject::connect(surfaceShapeToVolumeAction, SIGNAL(triggered(bool)), this, SLOT(slotSurfaceShapeToVolume())); surfaceShapeClearAllOrPartAction = new QAction(parent); surfaceShapeClearAllOrPartAction->setText("Clear All or Part of Surface Shape File..."); //surfaceShapeClearAllOrPartAction->setName("surfaceShapeClearAllOrPartAction"); QObject::connect(surfaceShapeClearAllOrPartAction, SIGNAL(triggered(bool)), this, SLOT(slotSurfaceShapeClearAllOrPart())); surfaceShapeAverageDeviationAction = new QAction(parent); surfaceShapeAverageDeviationAction->setText("Compute Average and Sample Standard Deviation of All Columns..."); //surfaceShapeAverageDeviationAction->setName("surfaceShapeAverageDeviationAction"); QObject::connect(surfaceShapeAverageDeviationAction, SIGNAL(triggered(bool)), this, SLOT(slotSurfaceShapeAverageDeviation())); shapeMathAction = new QAction(parent); shapeMathAction->setText("Mathematical Operations..."); //shapeMathAction->setName("shapeMathAction"); QObject::connect(shapeMathAction, SIGNAL(triggered(bool)), parent, SLOT(displayShapeMathDialog())); shapeModificationAction = new QAction(parent); shapeModificationAction->setText("Clustering and Smoothing..."); //shapeModificationAction->setName("shapeModificationAction"); QObject::connect(shapeModificationAction, SIGNAL(triggered(bool)), this, SLOT(slotShapeModification())); paintCleanNamesAction = new QAction(parent); paintCleanNamesAction->setText("Cleanup Paint Names"); //paintCleanNamesAction->setName("paintCleanNamesAction"); QObject::connect(paintCleanNamesAction, SIGNAL(triggered(bool)), this, SLOT(slotPaintCleanNames())); generateColorsForPaints = new QAction(parent); generateColorsForPaints->setText("Generate Colors for Paints Without Colors"); QObject::connect(generateColorsForPaints, SIGNAL(triggered(bool)), this, SLOT(slotGenerateColorsForPaints())); paintToVolumeAction = new QAction(parent); paintToVolumeAction->setText("Convert Paint Column to Paint Volume..."); //paintToVolumeAction->setName("paintToVolumeAction"); QObject::connect(paintToVolumeAction, SIGNAL(triggered(bool)), this, SLOT(slotPaintToVolume())); paintNamesEditAction = new QAction(parent); paintNamesEditAction->setText("Edit Paint Names and Properties..."); //paintNamesEditAction->setName("paintNamesEditAction"); QObject::connect(paintNamesEditAction, SIGNAL(triggered(bool)), parent, SLOT(displayPaintEditorDialog())); paintAssignWithinDisplayedBordersAction = new QAction(parent); paintAssignWithinDisplayedBordersAction->setText("Assign Nodes Within Displayed Borders..."); //paintAssignWithinDisplayedBordersAction->setName("paintAssignWithinDisplayedBordersAction"); QObject::connect(paintAssignWithinDisplayedBordersAction, SIGNAL(triggered(bool)), this, SLOT(slotPaintAssignWithinDisplayedBorders())); paintClearAllOrPartAction = new QAction(parent); paintClearAllOrPartAction->setText("Clear All or Part of Paint File..."); //paintClearAllOrPartAction->setName("paintClearAllOrPartAction"); QObject::connect(paintClearAllOrPartAction, SIGNAL(triggered(bool)), this, SLOT(slotPaintClearAllOrPart())); arealEstimationClearAllOrPartAction = new QAction(parent); arealEstimationClearAllOrPartAction->setText("Clear All or Part of Areal Estimation File..."); QObject::connect(arealEstimationClearAllOrPartAction, SIGNAL(triggered(bool)), this, SLOT(slotArealEstimationClearAllOrPart())); copyColoringToRgbPaintAction = new QAction(parent); copyColoringToRgbPaintAction->setText("Copy Current Coloring to RGB Paint..."); //copyColoringToRgbPaintAction->setName("copyColoringToRgbPaintAction"); QObject::connect(copyColoringToRgbPaintAction, SIGNAL(triggered(bool)), this, SLOT(slotCopyColoringToRgbPaint())); copyNormalsToRgbPaintAction = new QAction(parent); copyNormalsToRgbPaintAction->setText("Copy Surface Normals to RGB Paint"); //copyNormalsToRgbPaintAction->setName("copyNormalsToRgbPaintAction"); QObject::connect(copyNormalsToRgbPaintAction, SIGNAL(triggered(bool)), this, SLOT(slotCopyNormalsToRgbPaint())); copyColoringToVolumeAction = new QAction(parent); copyColoringToVolumeAction->setText("Copy Current Coloring to RGB Volume..."); //copyColoringToVolumeAction->setName("copyColoringToVolumeAction"); QObject::connect(copyColoringToVolumeAction, SIGNAL(triggered(bool)), this, SLOT(slotCopyColoringToVolume())); latLonClearAllOrPartAction = new QAction(parent); latLonClearAllOrPartAction->setText("Clear All or Part of Lat/Long File..."); //latLonClearAllOrPartAction->setName("latLonClearAllOrPartAction"); QObject::connect(latLonClearAllOrPartAction, SIGNAL(triggered(bool)), this, SLOT(slotLatLonClearAllOrPart())); latLonGenerateOnSphereAction = new QAction(parent); latLonGenerateOnSphereAction->setText("Generate Lat/Long on Spherical Surface..."); //latLonGenerateOnSphereAction->setName("latLonGenerateOnSphereAction"); QObject::connect(latLonGenerateOnSphereAction, SIGNAL(triggered(bool)), this, SLOT(slotLatLonGenerateOnSphere())); generateDeformationFieldAction = new QAction(parent); generateDeformationFieldAction->setText("Generate Deformation Field..."); //generateDeformationFieldAction->setName("generateDeformationFieldAction"); QObject::connect(generateDeformationFieldAction, SIGNAL(triggered(bool)), this, SLOT(slotGenerateDeformationField())); probAtlasThresholdToPaintAction = new QAction(parent); probAtlasThresholdToPaintAction->setText("Convert Threshold Coloring to Paint..."); //probAtlasThresholdToPaintAction->setName("probAtlasThresholdToPaintAction"); QObject::connect(probAtlasThresholdToPaintAction, SIGNAL(triggered(bool)), this, SLOT(slotProbAtlasThresholdToPaint())); coordsToVectorsAction = new QAction(parent); coordsToVectorsAction->setText("Create Vectors From Surface Subtraction..."); //coordsToVectorsAction->setName("coordsToVectorsAction"); QObject::connect(coordsToVectorsAction, SIGNAL(triggered(bool)), this, SLOT(slotCoordsToVectors())); normalsToVectorsAction = new QAction(parent); normalsToVectorsAction->setText("Create Vectors From Surface Normals"); QObject::connect(normalsToVectorsAction, SIGNAL(triggered(bool)), this, SLOT(slotNormalsToVectors())); modelsEditorAction = new QAction(parent); modelsEditorAction->setText("Edit..."); //modelsEditorAction->setName("modelsEditorAction"); QObject::connect(modelsEditorAction, SIGNAL(triggered(bool)), parent, SLOT(displayModelsEditorDialog())); studyMetaDataEditorDialogAction = new QAction(parent); studyMetaDataEditorDialogAction->setText("Edit Studies..."); QObject::connect(studyMetaDataEditorDialogAction, SIGNAL(triggered(bool)), parent, SLOT(displayStudyMetaDataFileEditorDialog())); studyCollectionEditorDialogAction = new QAction(parent); studyCollectionEditorDialogAction->setText("Edit Collections..."); QObject::connect(studyCollectionEditorDialogAction, SIGNAL(triggered(bool)), parent, SLOT(displayStudyCollectionFileEditorDialog())); vocabularyFileEditorDialogAction = new QAction(parent); vocabularyFileEditorDialogAction->setText("Edit..."); QObject::connect(vocabularyFileEditorDialogAction, SIGNAL(triggered(bool)), parent, SLOT(displayVocabularyFileEditorDialog())); vocabularyMoveStudyInfoToStudyMetaDataAction = new QAction(parent); vocabularyMoveStudyInfoToStudyMetaDataAction->setText("Move Vocabulary Study Info to Study Metadata File"); QObject::connect(vocabularyMoveStudyInfoToStudyMetaDataAction, SIGNAL(triggered(bool)), this, SLOT(slotVocabularyMoveStudyInfoToStudyMetaData())); connectivityAction = new QAction(parent); connectivityAction->setText("Connectivity..."); //connectivityAction->setShortcut(Qt::CTRL+Qt::Key_L); QObject::connect(connectivityAction, SIGNAL(triggered(bool)), parent, SLOT(displayConnectivityDialog())); } /** * Destructor. */ GuiMainWindowAttributesActions::~GuiMainWindowAttributesActions() { } /** * convert vocabulary study info to study metadata file. */ void GuiMainWindowAttributesActions::slotVocabularyMoveStudyInfoToStudyMetaData() { StudyMetaDataFile* smdf = theMainWindow->getBrainSet()->getStudyMetaDataFile(); VocabularyFile* vf = theMainWindow->getBrainSet()->getVocabularyFile(); smdf->append(*vf); GuiFilesModified fm; fm.setFociModified(); fm.setVocabularyModified(); theMainWindow->fileModificationUpdate(fm); const QString msg("The StudyInfo from the Vocabulary File has been moved\n" "to the Study Metadata File. As a result, both the \n" "StudyMetaData and Vocabulary Files need to be saved."); QMessageBox::information(theMainWindow, "INFO", msg); } /** * Called to map volume data to a surface data file. */ void GuiMainWindowAttributesActions::slotVolumeToSurfaceMapper() { static GuiMapFmriDialog* mfd = NULL; if (mfd == NULL) { mfd = new GuiMapFmriDialog(theMainWindow, theMainWindow->getBrainSet(), true, false); QObject::connect(mfd, SIGNAL(signalMappingComplete()), this, SLOT(slotVolumeToSurfaceMapperComplete())); } mfd->initializeDialog(); mfd->show(); } /** * slot for volume to surface mapper complete. */ void GuiMainWindowAttributesActions::slotVolumeToSurfaceMapperComplete() { GuiFilesModified fm; fm.setStatusForAll(true); fm.setInhibitSurfaceDefaultScaling(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(NULL); } /** * generate a deformation field. */ void GuiMainWindowAttributesActions::slotGenerateDeformationField() { GuiDeformationFieldDialog gdfd(theMainWindow); gdfd.exec(); } /** * Generate topography. */ void GuiMainWindowAttributesActions::slotGenerateTopography() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); BorderFile borders; bmbs->copyBordersToBorderFile(bms, borders); BorderToTopographyConverter btc(theMainWindow->getBrainSet(), bms, &borders, theMainWindow->getBrainSet()->getPaintFile(), theMainWindow->getBrainSet()->getTopographyFile(), -1, "Topography"); try { btc.execute(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(theMainWindow, "Error", e.whatQString()); } QApplication::restoreOverrideCursor(); } /** * Generate an areal estimation map. */ void GuiMainWindowAttributesActions::slotGenerateArealEstimationMap() { GuiGenerateArealEstimationDialog aed(theMainWindow); aed.exec(); } /** * Edit and Add area colors */ void GuiMainWindowAttributesActions::slotAreaColorsEdit() { GuiColorFileEditorDialog* gfed = new GuiColorFileEditorDialog(theMainWindow, theMainWindow->getBrainSet()->getAreaColorFile(), false, false, false, false, false); QObject::connect(gfed, SIGNAL(redrawRequested()), this, SLOT(slotAreaColorsChanged())); gfed->show(); } /** * This slot is called by the color editor when user pressed apply or dialog isclosed. */ void GuiMainWindowAttributesActions::slotAreaColorsChanged() { GuiFilesModified fm; fm.setAreaColorModified(); theMainWindow->fileModificationUpdate(fm); theMainWindow->getBrainSet()->getNodeColoring()->assignColors(); GuiBrainModelOpenGL::updateAllGL(NULL); } /** * Called to modify metric data. */ void GuiMainWindowAttributesActions::slotMetricModification() { theMainWindow->getMetricModificationDialog(true); } /** * Clear all or part of the file. */ void GuiMainWindowAttributesActions::slotMetricClearAllOrPart() { GuiFilesModified fm; fm.setMetricModified(); GuiNodeAttributeFileClearResetDialog d(theMainWindow, GUI_NODE_FILE_TYPE_METRIC); d.exec(); } /** * Called to create a volume using a metric column. */ void GuiMainWindowAttributesActions::slotMetricToVolume() { GuiSurfaceToVolumeDialog svd(theMainWindow, GuiSurfaceToVolumeDialog::DIALOG_MODE_METRIC, "Copy Surface Metric Column to Functional Volume"); if (svd.exec() == QDialog::Accepted) { const int metricColumn = svd.getSelectedNodeAttributeColumn(); if ((metricColumn < 0) || (metricColumn >= theMainWindow->getBrainSet()->getMetricFile()->getNumberOfColumns())) { QMessageBox::critical(theMainWindow, "Error", "Invalid metric Column"); return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); float offset[3]; float voxelSize[3]; float origin[3]; int dim[3]; svd.getSurfaceOffset(offset); svd.getVolumeDimensions(dim); svd.getVolumeVoxelSizes(voxelSize); svd.getVolumeOrigin(origin); BrainModelSurfaceToVolumeConverter stv(theMainWindow->getBrainSet(), svd.getSelectedSurface(), svd.getStandardVolumeSpace(), offset, dim, voxelSize, origin, svd.getSurfaceInnerBoundary(), svd.getSurfaceOuterBoundary(), svd.getSurfaceThicknessStep(), svd.getMetricConversionMode()); stv.setNodeAttributeColumn(metricColumn); stv.setNodeToVoxelMappingEnabled(svd.getNodeToVoxelMappingEnabled(), svd.getNodeToVoxelMappingFileName()); try { stv.execute(); } catch (BrainModelAlgorithmException& e) { QMessageBox::critical(theMainWindow, "Error", e.whatQString()); return; } theMainWindow->speakText("The metric data has been converted to a volume.", false); GuiBrainModelOpenGL* openGL = theMainWindow->getBrainModelOpenGL(); openGL->displayBrainModelVolume(); GuiFilesModified fm; fm.setVolumeModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); } } /** * Called to display metric to rgb paint dialog */ void GuiMainWindowAttributesActions::slotMetricToRgbPaint() { theMainWindow->getMetricsToRgbPaintDialog(true); } /** * Called to compute average and deviation of metrics. */ void GuiMainWindowAttributesActions::slotMetricAverageDeviation() { QCheckBox* meanCheckBox = new QCheckBox(""); QLineEdit* meanLineEdit = new QLineEdit; meanLineEdit->setText("Mean"); QObject::connect(meanCheckBox, SIGNAL(toggled(bool)), meanLineEdit, SLOT(setEnabled(bool))); meanCheckBox->setChecked(true); meanLineEdit->setEnabled(true); QCheckBox* stdDevCheckBox = new QCheckBox(""); QLineEdit* stdDevLineEdit = new QLineEdit; stdDevLineEdit->setText("Sample Standard Deviation"); QObject::connect(stdDevCheckBox, SIGNAL(toggled(bool)), stdDevLineEdit, SLOT(setEnabled(bool))); stdDevCheckBox->setChecked(true); stdDevLineEdit->setEnabled(true); QCheckBox* stdErrorCheckBox = new QCheckBox(""); QLineEdit* stdErrorLineEdit = new QLineEdit; stdErrorLineEdit->setText("Standard Error"); QObject::connect(stdErrorCheckBox, SIGNAL(toggled(bool)), stdErrorLineEdit, SLOT(setEnabled(bool))); stdErrorCheckBox->setChecked(false); stdErrorLineEdit->setEnabled(false); QCheckBox* minAbsCheckBox = new QCheckBox(""); QLineEdit* minAbsLineEdit = new QLineEdit; minAbsLineEdit->setText("Minimum Absolute Value"); QObject::connect(minAbsCheckBox, SIGNAL(toggled(bool)), minAbsLineEdit, SLOT(setEnabled(bool))); minAbsCheckBox->setChecked(false); minAbsLineEdit->setEnabled(false); QCheckBox* maxAbsCheckBox = new QCheckBox(""); QLineEdit* maxAbsLineEdit = new QLineEdit; maxAbsLineEdit->setText("Maximum Absolute Value"); QObject::connect(maxAbsCheckBox, SIGNAL(toggled(bool)), maxAbsLineEdit, SLOT(setEnabled(bool))); maxAbsCheckBox->setChecked(false); maxAbsLineEdit->setEnabled(false); WuQDataEntryDialog ded(theMainWindow); ded.setWindowTitle("Metric Statistics"); ded.setTextAtTop("Choose Statistical Measurements", false); ded.addWidgetsToNextRow(meanCheckBox, meanLineEdit); ded.addWidgetsToNextRow(stdDevCheckBox, stdDevLineEdit); ded.addWidgetsToNextRow(stdErrorCheckBox, stdErrorLineEdit); ded.addWidgetsToNextRow(minAbsCheckBox, minAbsLineEdit); ded.addWidgetsToNextRow(maxAbsCheckBox, maxAbsLineEdit); if (ded.exec() == WuQDataEntryDialog::Accepted) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); QString meanName, devName, errorName, minAbsName, maxAbsName; if (meanCheckBox->isChecked()) { meanName = meanLineEdit->text(); } if (stdDevCheckBox->isChecked()) { devName = stdDevLineEdit->text(); } if (stdErrorCheckBox->isChecked()) { errorName = stdErrorLineEdit->text(); } if (minAbsCheckBox->isChecked()) { minAbsName = minAbsLineEdit->text(); } if (maxAbsCheckBox->isChecked()) { maxAbsName = maxAbsLineEdit->text(); } MetricFile* mf = theMainWindow->getBrainSet()->getMetricFile(); mf->computeStatistics(meanName, devName, errorName, minAbsName, maxAbsName); theMainWindow->getBrainSet()->getNodeColoring()->assignColors(); GuiBrainModelOpenGL::updateAllGL(NULL); GuiFilesModified fm; fm.setMetricModified(); theMainWindow->fileModificationUpdate(fm); QApplication::restoreOverrideCursor(); } } /** * convert prob atlas threshold coloring to paint. */ void GuiMainWindowAttributesActions::slotProbAtlasThresholdToPaint() { ProbabilisticAtlasFile* probAtlasFile = theMainWindow->getBrainSet()->getProbabilisticAtlasSurfaceFile(); if (probAtlasFile->getNumberOfColumns() < 1) { QMessageBox::critical(theMainWindow, "ERROR", "Probabilistic Atlas File is Empty."); return; } // // Get node coloring // BrainModelSurfaceNodeColoring* bsnc = theMainWindow->getBrainSet()->getNodeColoring(); // // An overlay or underlay must be prob atlas // bool error = false; if (theMainWindow->getBrainSet()->isASurfaceOverlay(0, BrainModelSurfaceOverlay::OVERLAY_PROBABILISTIC_ATLAS)) { error = true; } // // Threshold display mode must be set for prob atlas // DisplaySettingsProbabilisticAtlas* dspa = theMainWindow->getBrainSet()->getDisplaySettingsProbabilisticAtlasSurface(); if (dspa->getDisplayType() != DisplaySettingsProbabilisticAtlas::PROBABILISTIC_DISPLAY_TYPE_THRESHOLD) { error = true; } if (error) { QMessageBox::critical(theMainWindow, "ERROR", "The overlay or underlay must be set to Probabilistic\n" "Atlas with the Display Mode set to Threshold."); return; } // // Use dialog to choose paint column and its name // GuiChooseNodeAttributeColumnDialog cacd(theMainWindow, GUI_NODE_FILE_TYPE_PAINT, "", true, false); if (cacd.exec() == QDialog::Accepted) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); // // Modify paint file for new column or update // PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); int columnNumber = cacd.getSelectedColumnNumber(); if (pf->getNumberOfNodes() == 0) { pf->setNumberOfNodesAndColumns(theMainWindow->getBrainSet()->getNumberOfNodes(), 1); columnNumber = 0; } else if (columnNumber < 0) { pf->addColumns(1); columnNumber = pf->getNumberOfColumns() - 1; } pf->setColumnName(columnNumber, cacd.getColumnName()); // // Update paint file with colors // bsnc->addProbAtlasThresholdingToPaintFile(pf, columnNumber); GuiFilesModified fm; fm.setPaintModified(); theMainWindow->fileModificationUpdate(fm); bsnc->assignColors(); GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); } } /** * slot for assigning paints within displayed borders. */ void GuiMainWindowAttributesActions::slotPaintAssignWithinDisplayedBorders() { // // Get the surface in the main window and its brain model index // BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { const int modelIndex = theMainWindow->getBrainSet()->getBrainModelIndex(bms); if (modelIndex >= 0) { // // Get the coordinates // CoordinateFile* cf = bms->getCoordinateFile(); const float* coords = cf->getCoordinate(0); const int numCoords = bms->getNumberOfNodes(); // // Allocate the inside flags // std::vector nodeInsideFlag(numCoords); // // Get the paint file // PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); // // Popup a dialog to choose the paint column that is to be assigned // GuiChooseNodeAttributeColumnDialog nacd(theMainWindow, GUI_NODE_FILE_TYPE_PAINT, "", true, false); nacd.setWindowTitle("Choose Paint Column"); if (nacd.exec() == QDialog::Accepted) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); // // Modify paint file for column change // int paintColumn = nacd.getSelectedColumnNumber(); if (paintColumn == GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NEW) { if (pf->getNumberOfColumns() <= 0) { pf->setNumberOfNodesAndColumns(numCoords, 1); } else { pf->addColumns(1); } paintColumn = pf->getNumberOfColumns() - 1; } pf->setColumnName(paintColumn, nacd.getColumnName()); // // Find borders that are valid for this surface and displayed // BrainModelBorderSet* borderSet = theMainWindow->getBrainSet()->getBorderSet(); const int numBorders = borderSet->getNumberOfBorders(); for (int i = 0; i < numBorders; i++) { BrainModelBorder* border = borderSet->getBorder(i); if (border->getDisplayFlag() && border->getValidForBrainModel(modelIndex)) { // // Find nodes within the border // border->pointsInsideBorder(bms, coords, numCoords, nodeInsideFlag, false); // // Assign paint nodes for nodes that are within the border // int paintIndex = -1; for (int j = 0; j < numCoords; j++) { if (nodeInsideFlag[j]) { if (paintIndex < 0) { paintIndex = pf->addPaintName(border->getName()); } pf->setPaint(j, paintColumn, paintIndex); } } } } // // Assign colors and update graphics // GuiFilesModified fm; fm.setPaintModified(); theMainWindow->fileModificationUpdate(fm); theMainWindow->getBrainSet()->getNodeColoring()->assignColors(); GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); } } } } /** * Clear all or part of the paint file. */ void GuiMainWindowAttributesActions::slotPaintClearAllOrPart() { GuiFilesModified fm; fm.setPaintModified(); GuiNodeAttributeFileClearResetDialog d(theMainWindow, GUI_NODE_FILE_TYPE_PAINT); d.exec(); } /** * Clear all or part of the areal estimation file. */ void GuiMainWindowAttributesActions::slotArealEstimationClearAllOrPart() { GuiFilesModified fm; fm.setArealEstimationModified(); GuiNodeAttributeFileClearResetDialog d(theMainWindow, GUI_NODE_FILE_TYPE_AREAL_ESTIMATION); d.exec(); } /** * Called to create a volume using a paint column. */ void GuiMainWindowAttributesActions::slotPaintToVolume() { GuiSurfaceToVolumeDialog svd(theMainWindow, GuiSurfaceToVolumeDialog::DIALOG_MODE_PAINT, "Copy Surface Paint Column to Paint Volume"); if (svd.exec() == QDialog::Accepted) { const int paintColumn = svd.getSelectedNodeAttributeColumn(); if ((paintColumn < 0) || (paintColumn >= theMainWindow->getBrainSet()->getPaintFile()->getNumberOfColumns())) { QMessageBox::critical(theMainWindow, "Error", "Invalid paint Column"); return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); float offset[3]; float voxelSize[3]; float origin[3]; int dim[3]; svd.getSurfaceOffset(offset); svd.getVolumeDimensions(dim); svd.getVolumeVoxelSizes(voxelSize); svd.getVolumeOrigin(origin); BrainModelSurfaceToVolumeConverter stv(theMainWindow->getBrainSet(), svd.getSelectedSurface(), svd.getStandardVolumeSpace(), offset, dim, voxelSize, origin, svd.getSurfaceInnerBoundary(), svd.getSurfaceOuterBoundary(), svd.getSurfaceThicknessStep(), BrainModelSurfaceToVolumeConverter::CONVERT_TO_ROI_VOLUME_USING_PAINT); stv.setNodeAttributeColumn(paintColumn); stv.setNodeToVoxelMappingEnabled(svd.getNodeToVoxelMappingEnabled(), svd.getNodeToVoxelMappingFileName()); try { stv.execute(); } catch (BrainModelAlgorithmException& e) { QMessageBox::critical(theMainWindow, "Error", e.whatQString()); return; } theMainWindow->speakText("The paint data has been converted to a volume.", false); GuiBrainModelOpenGL* openGL = theMainWindow->getBrainModelOpenGL(); openGL->displayBrainModelVolume(); GuiFilesModified fm; fm.setVolumeModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); } } /** * Called to copy current coloring to a volume. */ void GuiMainWindowAttributesActions::slotCopyColoringToVolume() { GuiSurfaceToVolumeDialog svd(theMainWindow, GuiSurfaceToVolumeDialog::DIALOG_MODE_NORMAL, "Copy Coloring to RGB Volume..."); if (svd.exec() == QDialog::Accepted) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); float offset[3]; float voxelSize[3]; float origin[3]; int dim[3]; svd.getSurfaceOffset(offset); svd.getVolumeDimensions(dim); svd.getVolumeVoxelSizes(voxelSize); svd.getVolumeOrigin(origin); BrainModelSurfaceToVolumeConverter stv(theMainWindow->getBrainSet(), svd.getSelectedSurface(), svd.getStandardVolumeSpace(), offset, dim, voxelSize, origin, svd.getSurfaceInnerBoundary(), svd.getSurfaceOuterBoundary(), svd.getSurfaceThicknessStep(), BrainModelSurfaceToVolumeConverter::CONVERT_TO_RGB_VOLUME_USING_NODE_COLORING); stv.setNodeToVoxelMappingEnabled(svd.getNodeToVoxelMappingEnabled(), svd.getNodeToVoxelMappingFileName()); try { stv.execute(); } catch (BrainModelAlgorithmException& e) { QMessageBox::critical(theMainWindow, "Error", e.whatQString()); return; } theMainWindow->speakText("The R G B data has been converted to a volume.", false); GuiBrainModelOpenGL* openGL = theMainWindow->getBrainModelOpenGL(); openGL->displayBrainModelVolume(); GuiFilesModified fm; fm.setVolumeModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); } } /** * Called to copy current coloring to RGB Paint. */ void GuiMainWindowAttributesActions::slotCopyColoringToRgbPaint() { GuiCurrentColoringToRgbPaintDialog* d = new GuiCurrentColoringToRgbPaintDialog(theMainWindow); d->exec(); } /** * Called to copy surface normals to RGB Paint. */ void GuiMainWindowAttributesActions::slotCopyNormalsToRgbPaint() { BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); bms->convertNormalsToRgbPaint(theMainWindow->getBrainSet()->getRgbPaintFile()); GuiFilesModified fm; fm.setRgbPaintModified(); theMainWindow->fileModificationUpdate(fm); } /** * Called to clean paint file names */ void GuiMainWindowAttributesActions::slotPaintCleanNames() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); pf->cleanUpPaintNames(); GuiFilesModified fm; fm.setPaintModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); } /** * slot for generating colors for non-matching paint names. */ void GuiMainWindowAttributesActions::slotGenerateColorsForPaints() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); const int numNames = pf->getNumberOfPaintNames(); std::vector paintNames; for (int i = 0; i < numNames; i++) { paintNames.push_back(pf->getPaintNameFromIndex(i)); } ColorFile* cf = theMainWindow->getBrainSet()->getAreaColorFile(); cf->generateColorsForNamesWithoutColors(paintNames, true); theMainWindow->getBrainSet()->getNodeColoring()->assignColors(); GuiBrainModelOpenGL::updateAllGL(NULL); GuiFilesModified fm; fm.setAreaColorModified(); theMainWindow->fileModificationUpdate(fm); QApplication::restoreOverrideCursor(); } /** * Called to modify metric data. */ void GuiMainWindowAttributesActions::slotShapeModification() { theMainWindow->getShapeModificationDialog(true); } /** * Called to compute average and deviation of metrics. */ void GuiMainWindowAttributesActions::slotSurfaceShapeAverageDeviation() { QCheckBox* meanCheckBox = new QCheckBox(""); QLineEdit* meanLineEdit = new QLineEdit; meanLineEdit->setText("Mean"); QObject::connect(meanCheckBox, SIGNAL(toggled(bool)), meanLineEdit, SLOT(setEnabled(bool))); meanCheckBox->setChecked(true); meanLineEdit->setEnabled(true); QCheckBox* stdDevCheckBox = new QCheckBox(""); QLineEdit* stdDevLineEdit = new QLineEdit; stdDevLineEdit->setText("Sample Standard Deviation"); QObject::connect(stdDevCheckBox, SIGNAL(toggled(bool)), stdDevLineEdit, SLOT(setEnabled(bool))); stdDevCheckBox->setChecked(true); stdDevLineEdit->setEnabled(true); QCheckBox* stdErrorCheckBox = new QCheckBox(""); QLineEdit* stdErrorLineEdit = new QLineEdit; stdErrorLineEdit->setText("Standard Error"); QObject::connect(stdErrorCheckBox, SIGNAL(toggled(bool)), stdErrorLineEdit, SLOT(setEnabled(bool))); stdErrorCheckBox->setChecked(false); stdErrorLineEdit->setEnabled(false); QCheckBox* minAbsCheckBox = new QCheckBox(""); QLineEdit* minAbsLineEdit = new QLineEdit; minAbsLineEdit->setText("Minimum Absolute Value"); QObject::connect(minAbsCheckBox, SIGNAL(toggled(bool)), minAbsLineEdit, SLOT(setEnabled(bool))); minAbsCheckBox->setChecked(false); minAbsLineEdit->setEnabled(false); QCheckBox* maxAbsCheckBox = new QCheckBox(""); QLineEdit* maxAbsLineEdit = new QLineEdit; maxAbsLineEdit->setText("Maximum Absolute Value"); QObject::connect(maxAbsCheckBox, SIGNAL(toggled(bool)), maxAbsLineEdit, SLOT(setEnabled(bool))); maxAbsCheckBox->setChecked(false); maxAbsLineEdit->setEnabled(false); WuQDataEntryDialog ded(theMainWindow); ded.setWindowTitle("Surface Shape Statistics"); ded.setTextAtTop("Choose Statistical Measurements", false); ded.addWidgetsToNextRow(meanCheckBox, meanLineEdit); ded.addWidgetsToNextRow(stdDevCheckBox, stdDevLineEdit); ded.addWidgetsToNextRow(stdErrorCheckBox, stdErrorLineEdit); ded.addWidgetsToNextRow(minAbsCheckBox, minAbsLineEdit); ded.addWidgetsToNextRow(maxAbsCheckBox, maxAbsLineEdit); if (ded.exec() == WuQDataEntryDialog::Accepted) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); QString meanName, devName, errorName, minAbsName, maxAbsName; if (meanCheckBox->isChecked()) { meanName = meanLineEdit->text(); } if (stdDevCheckBox->isChecked()) { devName = stdDevLineEdit->text(); } if (stdErrorCheckBox->isChecked()) { errorName = stdErrorLineEdit->text(); } if (minAbsCheckBox->isChecked()) { minAbsName = minAbsLineEdit->text(); } if (maxAbsCheckBox->isChecked()) { maxAbsName = maxAbsLineEdit->text(); } SurfaceShapeFile* ssf = theMainWindow->getBrainSet()->getSurfaceShapeFile(); ssf->computeStatistics(meanName, devName, errorName, minAbsName, maxAbsName); theMainWindow->getBrainSet()->getNodeColoring()->assignColors(); GuiBrainModelOpenGL::updateAllGL(NULL); GuiFilesModified fm; fm.setSurfaceShapeModified(); theMainWindow->fileModificationUpdate(fm); QApplication::restoreOverrideCursor(); } } /** * Clear all or part of the surface shape file. */ void GuiMainWindowAttributesActions::slotSurfaceShapeClearAllOrPart() { GuiFilesModified fm; fm.setSurfaceShapeModified(); GuiNodeAttributeFileClearResetDialog d(theMainWindow, GUI_NODE_FILE_TYPE_SURFACE_SHAPE); d.exec(); } /** * Called to create a volume using a surface shape column. */ void GuiMainWindowAttributesActions::slotSurfaceShapeToVolume() { GuiSurfaceToVolumeDialog svd(theMainWindow, GuiSurfaceToVolumeDialog::DIALOG_MODE_SURFACE_SHAPE, "Copy Surface Shape Column to Functional Volume"); if (svd.exec() == QDialog::Accepted) { const int shapeColumn = svd.getSelectedNodeAttributeColumn(); if ((shapeColumn < 0) || (shapeColumn >= theMainWindow->getBrainSet()->getSurfaceShapeFile()->getNumberOfColumns())) { QMessageBox::critical(theMainWindow, "Error", "Invalid surface shape Column"); return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); float offset[3]; float voxelSize[3]; float origin[3]; int dim[3]; svd.getSurfaceOffset(offset); svd.getVolumeDimensions(dim); svd.getVolumeVoxelSizes(voxelSize); svd.getVolumeOrigin(origin); BrainModelSurfaceToVolumeConverter stv(theMainWindow->getBrainSet(), svd.getSelectedSurface(), svd.getStandardVolumeSpace(), offset, dim, voxelSize, origin, svd.getSurfaceInnerBoundary(), svd.getSurfaceOuterBoundary(), svd.getSurfaceThicknessStep(), BrainModelSurfaceToVolumeConverter::CONVERT_TO_ROI_VOLUME_USING_SURFACE_SHAPE); stv.setNodeAttributeColumn(shapeColumn); stv.setNodeToVoxelMappingEnabled(svd.getNodeToVoxelMappingEnabled(), svd.getNodeToVoxelMappingFileName()); try { stv.execute(); } catch (BrainModelAlgorithmException& e) { QMessageBox::critical(theMainWindow, "Error", e.whatQString()); return; } theMainWindow->speakText("The surface shape data has been converted to a volume.", false); GuiBrainModelOpenGL* openGL = theMainWindow->getBrainModelOpenGL(); openGL->displayBrainModelVolume(); GuiFilesModified fm; fm.setVolumeModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); } } /** * Clear all or part of the surface shape file. */ void GuiMainWindowAttributesActions::slotLatLonClearAllOrPart() { GuiFilesModified fm; fm.setLatLonModified(); GuiNodeAttributeFileClearResetDialog d(theMainWindow, GUI_NODE_FILE_TYPE_LAT_LON); d.exec(); } /** * Called to create a volume using a surface shape column. */ void GuiMainWindowAttributesActions::slotLatLonGenerateOnSphere() { BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms == NULL) { QMessageBox::critical(theMainWindow, "Error", "There is no surface in the main window."); return; } if (bms->getSurfaceType() != BrainModelSurface::SURFACE_TYPE_SPHERICAL) { if (QMessageBox::warning(theMainWindow, "Warning", "The surface in the main window does\n" "not appear to be a sphere.", (QMessageBox::Ok | QMessageBox::Cancel), QMessageBox::Cancel) == QMessageBox::Cancel) { return; } } GuiChooseNodeAttributeColumnDialog cnacd(theMainWindow, GUI_NODE_FILE_TYPE_LAT_LON, "", true, false); if (cnacd.exec() == QDialog::Accepted) { const int columnNumber = cnacd.getSelectedColumnNumber(); const QString columnName = cnacd.getColumnName(); bms->createLatitudeLongitude(theMainWindow->getBrainSet()->getLatLonFile(), columnNumber, columnName, false, true); GuiFilesModified fm; fm.setLatLonModified(); theMainWindow->fileModificationUpdate(fm); } } /** * convert coord files to vectors. */ void GuiMainWindowAttributesActions::slotCoordsToVectors() { GuiShapeOrVectorsFromCoordinateSubtractionDialog csd(theMainWindow, GuiShapeOrVectorsFromCoordinateSubtractionDialog::MODE_VECTOR); csd.exec(); } /** * convert normals to vectors. */ void GuiMainWindowAttributesActions::slotNormalsToVectors() { BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { VectorFile* vf = new VectorFile(); bms->copyNormalsToVectorFile(vf); theMainWindow->getBrainSet()->addVectorFile(vf); GuiFilesModified fm; fm.setVectorModified(); theMainWindow->fileModificationUpdate(fm); } } /** * update the actions (typically called when menu is about to show) */ void GuiMainWindowAttributesActions::updateActions() { const VocabularyFile* vf = theMainWindow->getBrainSet()->getVocabularyFile(); vocabularyMoveStudyInfoToStudyMetaDataAction->setEnabled(vf->getNumberOfStudyInfo() > 0); } caret-5.6.4~dfsg.1.orig/caret/GuiMainWindow.h0000664000175000017500000010130711572067322020553 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_GUI_MAIN_WINDOW_H__ #define __VE_GUI_MAIN_WINDOW_H__ class QCloseEvent; class QLabel; class GuiToolBar; #include #include "GuiBrainModelOpenGL.h" #include "SceneFile.h" #include "SpecFile.h" // // Forward declarations avoid having to include lots // of include files. // class CommunicatorClientAFNI; class CommunicatorClientFIV; class CommunicatorServerCaret; class CommunicatorServerCaretSocket; class GuiAddCellsDialog; class GuiAlignSurfaceToStandardOrientationDialog; class GuiAutomaticRotationDialog; class GuiBorderDrawUpdateDialog; class GuiBorderOperationsDialog; class GuiBordersCreateInterpolatedDialog; class GuiCaptureWindowImageDialog; class GuiCaretCommandDialog; class GuiCaretCommandScriptBuilderDialog; class GuiCellAndFociAttributeAssignmentDialog; class GuiContourAlignmentDialog; class GuiContourDrawDialog; class GuiContourSectionControlDialog; class GuiContourSetScaleDialog; class GuiDrawBorderDialog; class GuiIdentifyDialog; class GuiDisplayControlDialog; class GuiBordersCreateInterpolatedDialog; class GuiBrainModelViewingWindow; class GuiColorKeyDialog; class GuiDataFileMathDialog; class GuiConnectivityDialog; class GuiFilesModified; class GuiFlattenFullHemisphereDialog; class GuiImageEditorWindow; class GuiImageViewingWindow; class GuiInterpolateSurfacesDialog; class GuiMainWindowAttributesActions; class GuiMainWindowAttributesMenu; class GuiMainWindowCommActions; class GuiMainWindowCommMenu; class GuiMainWindowFileActions; class GuiMainWindowFileMenu; class GuiMainWindowHelpActions; class GuiMainWindowHelpMenu; class GuiMainWindowLayersActions; class GuiMainWindowLayersMenu; class GuiMainWindowSurfaceActions; class GuiMainWindowSurfaceMenu; class GuiMainWindowTimingActions; class GuiMainWindowTimingMenu; class GuiMainWindowVolumeActions; class GuiMainWindowVolumeMenu; class GuiMainWindowWindowActions; class GuiMainWindowWindowMenu; class GuiMapStereotaxicFocusDialog; class GuiMetricModificationDialog; class GuiMetricsToRgbPaintDialog; class GuiModelsEditorDialog; class GuiMorphingDialog; class GuiPaintNameEditorDialog; class GuiPaletteEditorDialog; class GuiParamsFileEditorDialog; class GuiSectionControlDialog; class GuiStandardMeshDialog; class GuiSurfaceRegionOfInterestDialog; class GuiSurfaceRegionOfInterestDialogOLD; class GuiPreferencesDialog; class GuiRecordingDialog; class GuiSetTopologyDialog; class GuiSmoothingDialog; //class GuiSpeechGenerator; class GuiStudyCollectionFileEditorDialog; class GuiStudyMetaDataFileEditorDialog; class GuiTransformationMatrixDialog; class GuiVocabularyFileEditorDialog; class GuiVolumeBiasCorrectionDialog; class GuiVolumeResizingDialog; class GuiVolumeThresholdSegmentationDialog; class GuiVolumeAttributesDialog; class GuiVolumePaintEditorDialog; class GuiVolumeSegmentationEditorDialog; class GuiVolumeRegionOfInterestDialog; class GuiHelpViewerWindow; class TransformationMatrix; /// GuiMainWindow class /** * MainWindow for the graphical user-interface */ class GuiMainWindow : public QMainWindow { Q_OBJECT public: /// Constructor GuiMainWindow(const bool enableTimingMenu, const int openGLsizeX, const int openGLsizeY); /// Destructor ~GuiMainWindow(); /// add a brain set void addBrainSet(BrainSet* bs); /// get the number of brain set int getNumberOfBrainSets() const { return loadedBrainSets.size(); } /// get a brain set BrainSet* getBrainSetByIndex(const int indx) { return loadedBrainSets[indx]; } /// get the available brain sets void getAllBrainSets(std::vector& brainSetsOut) { brainSetsOut = loadedBrainSets; } /// get the active brain structure for specified window BrainSet* getBrainSet(const BrainModel::BRAIN_MODEL_VIEW_NUMBER windowNumber = BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW); /// get the active brain structure (const method) const BrainSet* getBrainSet(const BrainModel::BRAIN_MODEL_VIEW_NUMBER windowNumber = BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) const; /// set the active brain structure for specified window void setBrainSet(const BrainModel::BRAIN_MODEL_VIEW_NUMBER windowNumber, BrainSet* newActiveBrainSet); /// identify a node provided by a remote program void identifyNodeFromRemoteProgram(const int nodeNumber); /// Update gui due to file changes void fileModificationUpdate(const GuiFilesModified& fm); /// get the file menu GuiMainWindowFileMenu* getMainWindowFileMenu() { return fileMenu; } /// get the layers menu GuiMainWindowLayersMenu* getMainWindowLayersMenu() { return layersMenu; } /// get the surface popup menu GuiMainWindowSurfaceMenu* getMainWindowSurfaceMenu() { return surfaceMenu; } /// get the volume popup menu GuiMainWindowVolumeMenu* getMainWindowVolumeMenu() { return volumeMenu; } /// Get the Brain Model OpenGL widget in the main window GuiBrainModelOpenGL* getBrainModelOpenGL() { return mainOpenGL; } /// Get the Brain Model Contours in the main window (NULL if not a contours) BrainModelContours* getBrainModelContours(); /// Get the Brain Model Surface in the main window (NULL if not a surface) BrainModelSurface* getBrainModelSurface(); /// Get the Brain Model Surface Volume in the main window (NULL if not a surf&vol) BrainModelSurfaceAndVolume* getBrainModelSurfaceAndVolume(); /// Get the Brain Model Volume in the main window (NULL if not a volume) BrainModelVolume* getBrainModelVolume(); /// Get the Brain Model in the main window (NULL if no model) BrainModel* getBrainModel(); /// Get the index of the Brain Model Volume in the main window (-1 if invalid) int getBrainModelIndex() const; /// Get the toolbar GuiToolBar* getToolBar() { return toolBar; } /// create, possibly show, and return the add cells dialog GuiAddCellsDialog* getAddCellsDialog(const bool showIt); /// create, possibly show, and return the add contour cells dialog GuiAddCellsDialog* getAddContourCellsDialog(const bool showIt); /// create, possibly show, and return the contour alignment dialog GuiContourAlignmentDialog* getContourAlignmentDialog(const bool showIt); /// create, possibly show, and return the contour draw dialog GuiContourDrawDialog* getContourDrawDialog(const bool showIt); /// create, possibly show, and return the contour set scale dialog GuiContourSetScaleDialog* getContourSetScaleDialog(const bool showIt); /// create, possibly show, and return the contour section control dialog GuiContourSectionControlDialog* getContourSectionControlDialog(const bool showIt); /// create, possibly show, and return the draw border dialog GuiDrawBorderDialog* getDrawBorderDialog(const bool showIt); /// create, possibly show, and return the border operations dialog GuiBorderOperationsDialog* getBorderOperationsDialog(const bool showIt); /// create, possibly show, and return the flatten full hemisphere dialog GuiFlattenFullHemisphereDialog* getFlattenFullHemisphereDialog(const bool showIt); /// create, possibly show, and return the standard mesh dialog GuiStandardMeshDialog* getStandardMeshDialog(const bool showIt); /// get the draw border updated dialog GuiBorderDrawUpdateDialog* getDrawBorderUpdateDialog() { return borderDrawUpdateDialog; } /// show the help viewer dialog void showHelpViewerDialog(const QString& helpPage = ""); /// show a page in the help viewer dialog over a modal dialog void showHelpPageOverModalDialog(QDialog* modalParent, const QString& helpPage); /// create, (possibly show), and return the identify dialog GuiIdentifyDialog* getIdentifyDialog(const bool showIt); /// create, (possibly show), and return the border created interpolated dialog GuiBordersCreateInterpolatedDialog* getBordersCreateInterpolatedDialog(const bool showIt); /// create, (possibly show), and return the map stereotaxic focus dialog GuiMapStereotaxicFocusDialog* getMapStereotaxicFocusDialog(const bool showIt); /// create, (possibly show), and return the metrics to rgb paint dialog GuiMetricsToRgbPaintDialog* getMetricsToRgbPaintDialog(const bool showIt); /// create, (possibly show), and return the recording dialog GuiRecordingDialog* getRecordingDialog(const bool showIt); /// create, (possibly show), and return the surface region of interest dialog GuiSurfaceRegionOfInterestDialog* getSurfaceRegionOfInterestDialog(const bool showIt); /// create, (possibly show), and return the surface region of interest dialog GuiSurfaceRegionOfInterestDialogOLD* getSurfaceRegionOfInterestDialogOLD(const bool showIt); /// create, (possibly show), and return the volume region of interest dialog GuiVolumeRegionOfInterestDialog* getVolumeRegionOfInterestDialog(const bool showIt); /// create, (possibly show), and return the threshold segmentation dialog GuiVolumeThresholdSegmentationDialog* getVolumeThresholdSegmentationDialog(const bool showIt); /// create, (possibly show), and return the metric modification dialog GuiMetricModificationDialog* getMetricModificationDialog(const bool showIt); /// create, (possibly show), and return the shape modification dialog GuiMetricModificationDialog* getShapeModificationDialog(const bool showIt); /// create, (possibly show), and return the interpolate surface dialog GuiInterpolateSurfacesDialog* getInterpolateSurfaceDialog(const bool showIt); /// get the align surface to standard orientation dialog GuiAlignSurfaceToStandardOrientationDialog* getAlignSurfaceToStandardOrientationDialog() { return alignSurfaceToStandardOrientationDialog; } /// create, (possibly show), and return the volume attributes dialog GuiVolumeAttributesDialog* getVolumeAttributesDialog(const bool showIt); /// Return the volume resizing dialog. Dialog will be created only if parameter is true GuiVolumeResizingDialog* getVolumeResizingDialog(const bool createIt); /// Return the segmentation volume editor dialog GuiVolumeSegmentationEditorDialog* getVolumeSegmentationEditorDialog(const bool showIt); /// Return the paint volume editor dialog GuiVolumePaintEditorDialog* getVolumePaintEditorDialog(const bool showIt); /// set the align surface to standard orientation dialog void setAlignSurfaceToStandardOrientationDialog(GuiAlignSurfaceToStandardOrientationDialog* aod) { alignSurfaceToStandardOrientationDialog = aod; } /// load the spec file's data files void loadSpecFilesDataFiles(SpecFile sf, const TransformationMatrix* tm, const bool appendToExistingLoadedSpecFiles = false); /// read the spec file with the specified name and place in spec file dialog void readSpecFile(const QString& filename); /// update the section dialog void updateSectionControlDialog(); /// Update the status bar label void updateStatusBarLabel(); /// Update the display control dialog void updateDisplayControlDialog(); /// display the brain model in the main window void displayBrainModelInMainWindow(BrainModel* bm); /// Display a volume in the main window void displayVolumeInMainWindow(); /// Display contours in the main window void displayContoursInMainWindow(); /// Display the newest surface in the main window. void displayNewestSurfaceInMainWindow(); /// display a web page in the user's web browser void displayWebPage(const QString& webPage); /// get the afni communicator CommunicatorClientAFNI* getAfniClientCommunicator() { return afniClientCommunicator; } /// get the FIV communicator CommunicatorClientFIV* getFivClientCommunicator() { return fivClientCommunicator; } /// speak some text void speakText(const QString& text, const bool verboseSpeech); /// apply a scene (set display settings) void showScene(const SceneFile::Scene* scene, const bool checkSpecFlag, QString& errorMessage) ; /// create a scene (save window info) void saveScene(std::vector& mainWindowSceneClasses); /// Check for modified files. void checkForModifiedFiles(BrainSet* bs, QString& msg, const bool checkSceneFileFlag); /// remove an image viewing window void removeImageViewingWindow(const GuiImageViewingWindow* ivw); /// remove all image viewing windows void removeAllImageViewingWindows(); /// remove all model viewing windows void removeAllModelViewingWindows(); /// close the spec file void closeSpecFile(const bool keepSceneAndSpec, const bool checkForModifiedFiles = true); /// close all spec files void closeAllSpecFiles(); /// see if communicator with other Caret's valid bool getCaretCommunicatorServerValid() const { return (communicatorServerCaret != NULL); } /// get the main window file actions GuiMainWindowFileActions* getFileActions() { return fileActions; } /// get the main window attribute actions GuiMainWindowAttributesActions* getAttributesActions() { return attributeActions; } /// get the main window layers actions GuiMainWindowLayersActions* getLayersActions() { return layersActions; } /// get the main window help actions GuiMainWindowHelpActions* getHelpActions() { return helpActions; } /// get the main window surface actions GuiMainWindowSurfaceActions* getSurfaceActions() { return surfaceActions; } /// get the main window timing actions GuiMainWindowTimingActions* getTimingActions() { return timingActions; } /// get the main window volume actions GuiMainWindowVolumeActions* getVolumeActions() { return volumeActions; } /// get the main window window actions GuiMainWindowWindowActions* getWindowActions() { return windowActions; } /// get the main window comm actions GuiMainWindowCommActions* getCommActions() { return commActions; } protected: /// Called when application wants to close. void closeEvent(QCloseEvent* event); public slots: /// close the program void slotCloseProgram(); /// display the models editor void displayModelsEditorDialog(); /// display the vocabulary editor dialog void displayVocabularyFileEditorDialog(); /// display an image viewing window void displayImageViewingWindow(); /// display the capture window as image dialog void displayCaptureWindowImageDialog(); /// display the border draw update dialog void displayBorderDrawUpdateDialog(); /// display the areal estimation color key void displayArealEstimationColorKey(); /// display the border color key void displayBorderColorKey(); /// display the cell color key void displayCellColorKey(); /// display the foci color key void displayFociColorKey(); /// display the paint color key void displayPaintColorKey(); /// display the foci attribute assignment dialog void displayFociAttributeAssignmentDialog(); /// display the probabilistic atlas color key void displayProbabilisticAtlasColorKey(); /// display the study meta data file editor dialog void displayStudyMetaDataFileEditorDialog(); /// display the study collection file editor dialog void displayStudyCollectionFileEditorDialog(); /// display the volume paint color key void displayVolumePaintColorKey(); /// display the volume probabilistic atlas color key void displayVolumeProbabilisticAtlasColorKey(); /// create (if necessary) and show the automatic rotation dialog void displayAutomaticRotationDialog(); /// create (if necessary) and show the draw border dialog void displayDrawBorderDialog(); /// create (if necessary) and show the border operations dialog void displayBorderOperationsDialog(); /// create (if necessary) and show the caret command executor dialog void displayCaretCommandExecutorDialog(); /// create (if necessary) and show the caret command script builder dialog void displayCaretCommandScriptBuilderDialog(); /// create (if necessary) and show the standard mesh dialog void displayStandardMeshDialog(); /// create (if necessary) and show the flatten full hemisphere dialog void displayFlattenFullHemisphereDialog(); /// create (if necessary) and show the section control dialog void displaySectionControlDialog(); /// create (if necessary) and show the smoothing dialog void displaySmoothingDialog(); /// create (if necessary) and show the identify dialog void displayIdentifyDialog(); /// create (if necessary) and show the preferences dialog void displayPreferencesDialog(); /// create (if necessary) and show the display control dialog void displayDisplayControlDialog(); /// create and display the palette editor dialog void displayPaletteEditorDialog(); /// display the set topology dialog void displaySetTopologyDialog(); /// display the paint editor dialog void displayPaintEditorDialog(); /// display the tranformation editor dialog void displayTransformMatrixEditor(); /// display the params file editor dialog void displayParamsFileEditorDialog(); /// Display the fast open data file dialog void displayFastOpenDataFileDialog(); /// display metric math dialog void displayMetricMathDialog(); /// display surface shape math dialog void displayShapeMathDialog(); /// display volume math dialog void displayVolumeMathDialog(); /// display volume bias correction dialog void displayVolumeBiasCorrectionDialog(); /// Close the current spec file. void slotCloseSpecFile(); /// Close the current spec file but keep the scene and spec file. void slotCloseSpecFileKeepSceneAndSpec(); /// display the image editor window void displayImageEditorWindow(); /// show the flat morphing dialog void showFlatMorphingDialog(); /// show the sphere morphing dialog void showSphereMorphingDialog(); /// update the displayed menus based upon loaded contours/surface/volume in main window void updateDisplayedMenus(); /// display the brain model in the main window (negative displays newest) void displayBrainModelInMainWindow(int modelNumberIn); /// Makes updates when the spec file is changed. void postSpecFileReadInitializations(); /// redraw all windows using the brain set void slotRedrawWindowsUsingBrainSet(BrainSet* bs); /// display the connectivity dialog void displayConnectivityDialog(); public: /// update the transformation matrix Editor void updateTransformationMatrixEditor(const TransformationMatrix* tm = NULL); /// get the transformation matrix editor dialog GuiTransformationMatrixDialog* getTransformMatrixEditor() { return transformMatrixEditorDialog; } /// Called when an item is selected from the recent spec file menu void recentSpecFileMenuSelection(int menuItem); /// save a color key dialog to a scene void saveSceneColorKeyDialog(std::vector& mainWindowSceneClasses, GuiColorKeyDialog* colorKeyDialog); /// load color key dialog from a scene void showSceneColorKeyDialog(const SceneFile::Scene* scene, const int screenMaxX, const int screenMaxY, const int mainWindowSceneX, const int mainWindowSceneY, const int mainWindowX, const int mainWindowY); /// Called to pop up viewing window void showViewingWindow(const BrainModel::BRAIN_MODEL_VIEW_NUMBER item); /// Remove a viewing window void removeViewingWindow(const BrainModel::BRAIN_MODEL_VIEW_NUMBER item); /// resize the viewing windows void resizeViewingWindows(); private: /// the available brain set std::vector loadedBrainSets; /// the directory for the brain set //std::vector loadedBrainSetDirectory; /// the brain sets associated with each viewing window BrainSet* brainSetInWindow[BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS]; /// communicator with other Caret's CommunicatorServerCaret* communicatorServerCaret; /// Recent spec files std::vector recentSpecFiles; /// update recent spec files for recent spec file menu void addToRecentSpecFiles(const QString& name); /// Fixed size policy QSizePolicy* sizePolicyFixed; /// OpenGL window for drawing brain surface GuiBrainModelOpenGL* mainOpenGL; /// Display Control Dialog GuiDisplayControlDialog* displayControlDialog; /// Surface Windows GuiBrainModelViewingWindow* modelWindow[BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS]; /// Tool Bar GuiToolBar* toolBar; /// Attributes Menu GuiMainWindowAttributesMenu* attributesMenu; /// Comm Menu GuiMainWindowCommMenu* commMenu; /// File Menu GuiMainWindowFileMenu* fileMenu; /// Layers Menu GuiMainWindowLayersMenu* layersMenu; /// Help Menu GuiMainWindowHelpMenu* helpMenu; /// surface popup menu GuiMainWindowSurfaceMenu* surfaceMenu; /// timing popup menu GuiMainWindowTimingMenu* timingMenu; /// volume menu GuiMainWindowVolumeMenu* volumeMenu; /// window menu GuiMainWindowWindowMenu* windowMenu; /// align surface to standard orientation dialog GuiAlignSurfaceToStandardOrientationDialog* alignSurfaceToStandardOrientationDialog; /// automatic rotation dialog GuiAutomaticRotationDialog* automaticRotationDialog; /// add cells dialog GuiAddCellsDialog* addCellsDialog; /// add contour cells dialog GuiAddCellsDialog* addContourCellsDialog; /// capture window image dialog GuiCaptureWindowImageDialog* captureWindowImageDialog; /// contour alignment dialog GuiContourAlignmentDialog* contourAlignmentDialog; /// contour draw dialog GuiContourDrawDialog* contourDrawDialog; /// contour set scale dialog GuiContourSetScaleDialog* contourSetScaleDialog; /// contour section control dialog GuiContourSectionControlDialog* contourSectionControlDialog; /// flatten full hemisphere dialog GuiFlattenFullHemisphereDialog* flattenFullHemisphereDialog; /// standard mesh dialog GuiStandardMeshDialog* standardMeshDialog; /// border operations dialog GuiBorderOperationsDialog* borderOperationsDialog; /// draw border dialog GuiDrawBorderDialog* drawBorderDialog; /// connectivity dialog GuiConnectivityDialog* connectivityDialog; /// help viewer dialog GuiHelpViewerWindow* helpViewerDialog; /// Identify window GuiIdentifyDialog* identifyDialog; /// recording dialog GuiRecordingDialog* recordingDialog; /// smoothing dialog GuiSmoothingDialog* smoothingDialog; /// borders create interpolated dialog GuiBordersCreateInterpolatedDialog* bordersCreateInterpolatedDialog; /// border draw update dialog GuiBorderDrawUpdateDialog* borderDrawUpdateDialog; /// map talairach focus dialog GuiMapStereotaxicFocusDialog* mapStereotaxicFocusDialog; /// metrics to rgb paint dialog GuiMetricsToRgbPaintDialog* metricsToRgbPaintDialog; /// surface region of interest dialog GuiSurfaceRegionOfInterestDialog* surfaceRegionOfInterestDialog; /// surface region of interest dialog GuiSurfaceRegionOfInterestDialogOLD* surfaceRegionOfInterestDialogOLD; /// volume region of interest dialog GuiVolumeRegionOfInterestDialog* volumeRegionOfInterestDialog; /// volume threshold segmentation dialog GuiVolumeThresholdSegmentationDialog* volumeThresholdSegmentationDialog; /// the edit transformation matrix dialog GuiTransformationMatrixDialog* transformMatrixEditorDialog; /// metric modification dialog GuiMetricModificationDialog* metricModificationDialog; /// shape modification dialog GuiMetricModificationDialog* shapeModificationDialog; /// paint name and attributes dialog GuiPaintNameEditorDialog* paintNameEditorDialog; /// metric math dialog GuiDataFileMathDialog* metricMathDialog; /// models editor dialog GuiModelsEditorDialog* modelsEditorDialog; /// palette editor dialog GuiPaletteEditorDialog* paletteEditorDialog; /// surface shape math dialog GuiDataFileMathDialog* shapeMathDialog; /// study meta data editor dialog GuiStudyMetaDataFileEditorDialog* studyMetaDataFileEditorDialog; /// study collection editor dialog GuiStudyCollectionFileEditorDialog* studyCollectionFileEditorDialog; /// volume math dialog GuiDataFileMathDialog* volumeMathDialog; /// interpolate surface dialog GuiInterpolateSurfacesDialog* interpolateSurfaceDialog; /// set topology dialog GuiSetTopologyDialog* setTopologyDialog; /// flat morphing dialog GuiMorphingDialog* flatMorphingDialog; /// sphere morphing dialog GuiMorphingDialog* sphereMorphingDialog; /// preferences dialog GuiPreferencesDialog* preferencesDialog; /// caret command executor dialog GuiCaretCommandDialog* caretCommandExecutorDialog; /// caret command script builder dialog GuiCaretCommandScriptBuilderDialog* caretCommandScriptBuilderDialog; /// section control dialog GuiSectionControlDialog* sectionControlDialog; /// volume attributes dialog GuiVolumeAttributesDialog* volumeAttributesDialog; /// volume resizing dialog GuiVolumeResizingDialog* volumeResizingDialog; /// volume segmentation editor dialog GuiVolumeSegmentationEditorDialog* volumeSegmentationEditorDialog; /// volume paint editor dialog GuiVolumePaintEditorDialog* volumePaintEditorDialog; /// params file editor dialog GuiParamsFileEditorDialog* paramsFileEditorDialog; /// vocabulary editor dialog GuiVocabularyFileEditorDialog* vocabularyFileEditorDialog; /// areal estimation color key dialog GuiColorKeyDialog* arealEstimationColorKeyDialog; /// border color key dialog GuiColorKeyDialog* borderColorKeyDialog; /// cell color key dialog GuiColorKeyDialog* cellColorKeyDialog; /// foci color key dialog GuiColorKeyDialog* fociColorKeyDialog; /// paint color key dialog GuiColorKeyDialog* paintColorKeyDialog; /// probabilistic atlas color key dialog GuiColorKeyDialog* probAtlasColorKeyDialog; /// volume paint color key dialog GuiColorKeyDialog* volumePaintColorKeyDialog; /// volume probabilistic atlas color key dialog GuiColorKeyDialog* volumeProbAtlasColorKeyDialog; /// foci attribute assignemnt dialog GuiCellAndFociAttributeAssignmentDialog* fociAttributeAssignmentDialog; /// volume bias correction dialog GuiVolumeBiasCorrectionDialog* volumeBiasCorrectionDialog; /// status bar mouse mode label QLabel* statusBarMouseModeLabel; /// status bar section low label QLabel* statusBarSectionLowLabel; /// status bar section high label QLabel* statusBarSectionHighLabel; /// status bar mouse left button function label QLabel* statusBarMouseLeftLabel; /// status bar mouse shift left button function label QLabel* statusBarMouseShiftLeftLabel; /// status bar mouse alt left button function label QLabel* statusBarMouseAltLeftLabel; /// status bar mouse ctrl left button function label QLabel* statusBarMouseCtrlLeftLabel; /// status bar mouse click left button function label QLabel* statusBarMouseClickLeftLabel; /// the afni communicator CommunicatorClientAFNI* afniClientCommunicator; /// the FIV communicator CommunicatorClientFIV* fivClientCommunicator; /// the speech generator //GuiSpeechGenerator *speechGenerator; /// the image editing window GuiImageEditorWindow* imageEditorWindow; /// main window file actions GuiMainWindowFileActions* fileActions; /// main window attribute actions GuiMainWindowAttributesActions* attributeActions; /// main window layers actions GuiMainWindowLayersActions* layersActions; /// main window help actions GuiMainWindowHelpActions* helpActions; /// main window surface actions GuiMainWindowSurfaceActions* surfaceActions; /// main window window actions GuiMainWindowWindowActions* windowActions; /// main window comm actions GuiMainWindowCommActions* commActions; /// main window timing actions GuiMainWindowTimingActions* timingActions; /// main window volume actions GuiMainWindowVolumeActions* volumeActions; /// keeps track of image viewing windows std::vector imageViewingWindows; /// Check data file modified when quitting void checkFileModified(const QString typeName, const AbstractFile* af, QString& msg); /// check volume file modified when quitting void checkVolumeFileModified(const QString& typeName, const VolumeFile* vf, QString& msg); /// create the status bar void createStatusBar(); friend class GuiCaptureWindowImageDialog; friend class GuiMainWindowFileMenu; friend class GuiMainWindowLayersMenu; friend class GuiMainWindowWindowMenu; friend class GuiOpenDataFileDialog; friend class GuiToolBar; }; #endif caret-5.6.4~dfsg.1.orig/caret/GuiMainWindow.cxx0000664000175000017500000041024111572067322021126 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ // // This file contains the class methods that create the main window. // #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "AreaColorFile.h" #include "ArealEstimationFile.h" #include "BrainModelBorderSet.h" #include "BrainModelVolumeVoxelColoring.h" #include "BorderColorFile.h" #include "BorderFile.h" #include "BorderProjectionFile.h" #include "BrainModelContours.h" #include "BrainModelIdentification.h" #include "BrainModelSurfaceAndVolume.h" #include "BrainModelSurfaceNodeColoring.h" #include "BrainSet.h" #include "GuiCaretCommandDialog.h" #include "GuiCaretCommandScriptBuilderDialog.h" #include "CaretVersion.h" #include "GuiCellAndFociAttributeAssignmentDialog.h" #include "CellColorFile.h" #include "CellProjectionFile.h" #include "CocomacConnectivityFile.h" #include "CommunicatorClientAFNI.h" #include "CommunicatorClientFIV.h" #include "ContourCellColorFile.h" #include "ContourCellFile.h" #include "CutsFile.h" #include "DebugControl.h" #include "DeformationFieldFile.h" #include "DisplaySettingsBorders.h" #include "DisplaySettingsCells.h" #include "DisplaySettingsContours.h" #include "DisplaySettingsFoci.h" #include "DisplaySettingsScene.h" #include "DisplaySettingsSection.h" #include "DisplaySettingsSurface.h" #include "FileUtilities.h" #include "FociColorFile.h" #include "FociProjectionFile.h" #include "FociSearchFile.h" #include "GeodesicDistanceFile.h" #include "GuiBrainModelViewingWindow.h" #include "GuiAddCellsDialog.h" #include "GuiAutomaticRotationDialog.h" #include "GuiBordersCreateInterpolatedDialog.h" #include "GuiBorderDrawUpdateDialog.h" #include "GuiBorderOperationsDialog.h" #include "GuiCaptureWindowImageDialog.h" #include "GuiColorKeyDialog.h" #include "GuiContourAlignmentDialog.h" #include "GuiContourDrawDialog.h" #include "GuiContourSectionControlDialog.h" #include "GuiContourSetScaleDialog.h" #include "GuiDataFileMathDialog.h" #include "GuiDrawBorderDialog.h" #include "GuiConnectivityDialog.h" #include "GuiFilesModified.h" #include "GuiFlattenFullHemisphereDialog.h" #include "GuiImageEditorWindow.h" #include "GuiImageViewingWindow.h" #include "GuiIdentifyDialog.h" #include "GuiInterpolateSurfacesDialog.h" #include "GuiMainWindow.h" #include "GuiMainWindowAttributesActions.h" #include "GuiMainWindowAttributesMenu.h" #include "GuiMainWindowCommActions.h" #include "GuiMainWindowCommMenu.h" #include "GuiMainWindowFileActions.h" #include "GuiMainWindowFileMenu.h" #include "GuiMainWindowHelpActions.h" #include "GuiMainWindowHelpMenu.h" #include "GuiMainWindowLayersActions.h" #include "GuiMainWindowLayersMenu.h" #include "GuiMainWindowSurfaceActions.h" #include "GuiMainWindowSurfaceMenu.h" #include "GuiMainWindowTimingActions.h" #include "GuiMainWindowTimingMenu.h" #include "GuiMainWindowVolumeActions.h" #include "GuiMainWindowVolumeMenu.h" #include "GuiMainWindowWindowActions.h" #include "GuiMainWindowWindowMenu.h" #include "GuiMapStereotaxicFocusDialog.h" #include "GuiMetricModificationDialog.h" #include "GuiMetricsToRgbPaintDialog.h" #include "GuiModelsEditorDialog.h" #include "GuiMorphingDialog.h" #include "GuiBrainModelOpenGL.h" #include "GuiDisplayControlDialog.h" #include "GuiPaintNameEditorDialog.h" #include "GuiPaletteEditorDialog.h" #include "GuiParamsFileEditorDialog.h" #include "GuiPreferencesDialog.h" #include "GuiRecordingDialog.h" #include "GuiSectionControlDialog.h" #include "GuiSetTopologyDialog.h" #include "GuiSmoothingDialog.h" #include "GuiSpecFileDialog.h" //#include "GuiSpeechGenerator.h" #include "GuiStandardMeshDialog.h" #include "GuiStudyCollectionFileEditorDialog.h" #include "GuiStudyMetaDataFileEditorDialog.h" #include "GuiSurfaceRegionOfInterestDialog.h" #include "GuiSurfaceRegionOfInterestDialogOLD.h" #include "GuiTransformationMatrixDialog.h" #include "GuiVocabularyFileEditorDialog.h" #include "GuiVolumeBiasCorrectionDialog.h" #include "GuiVolumeResizingDialog.h" #include "GuiVolumeThresholdSegmentationDialog.h" #include "GuiVolumeAttributesDialog.h" #include "GuiVolumeRegionOfInterestDialog.h" #include "GuiVolumeSegmentationEditorDialog.h" #include "GuiVolumePaintEditorDialog.h" #include "GuiToolBar.h" #include "ImageFile.h" #include "LatLonFile.h" #include "MetricFile.h" #include "PaintFile.h" #include "PaletteFile.h" #include "ParamsFile.h" #include "ProbabilisticAtlasFile.h" #include "GuiHelpViewerWindow.h" #include "QtUtilities.h" #include "RgbPaintFile.h" #include "SceneFile.h" #include "SectionFile.h" #include "StringUtilities.h" #include "StudyCollectionFile.h" #include "StudyMetaDataFile.h" #include "SurfaceShapeFile.h" #include "VectorFile.h" #include "SystemUtilities.h" #include "TopographyFile.h" #include "VocabularyFile.h" #include "VtkModelFile.h" #include "WustlRegionFile.h" #include "WuQDataEntryDialog.h" #include "WuQMessageBox.h" /** * Constructor. */ GuiMainWindow::GuiMainWindow(const bool enableTimingMenu, const int openGLsizeX, const int openGLsizeY) : QMainWindow(0) { setAttribute(Qt::WA_DeleteOnClose); // // Create the main brain surface. // BrainSet* bs = new BrainSet(true); addBrainSet(bs); //loadedBrainSetDirectory.push_back(QDir::currentPath()); for (int i = 0; i < BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS; i++) { brainSetInWindow[i] = bs; } // // Create the AFNI communicator // afniClientCommunicator = new CommunicatorClientAFNI; // // Create the FIV communicator // fivClientCommunicator = new CommunicatorClientFIV; // // Initialize caret communicator invalid // communicatorServerCaret = NULL; // // Create the speech generator // //speechGenerator = new GuiSpeechGenerator(getBrainSet()->getPreferencesFile()); sizePolicyFixed = new QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); // // Desired width and size of OpenGL widget // const int desiredWidth = 500; const int desiredHeight = 500; // // Is a specific size OpenGL window requested (typically used when recording MPEG) // if ((openGLsizeX > 0) && (openGLsizeY > 0)) { // // Create the OpenGL widget // mainOpenGL = new GuiBrainModelOpenGL(0, NULL, "mainWidgetOpenGL", BrainModel:: BRAIN_MODEL_VIEW_MAIN_WINDOW); mainOpenGL->setFixedSize(QSize(openGLsizeX, openGLsizeY)); // // Space on right side // const int rightWidth = desiredWidth - openGLsizeX; // // Dummy widgets on bottom and right side of OpenGL widget // QWidget* rightWidget = NULL; if (rightWidth > 0) { rightWidget = new QWidget; rightWidget->setFixedSize(rightWidth, 10); } // // OpenGL for brain surface // QWidget* openGLBox = new QWidget(this); QHBoxLayout* openGLLayout = new QHBoxLayout(openGLBox); openGLLayout->addWidget(mainOpenGL); openGLLayout->setStretchFactor(mainOpenGL, 0); if (rightWidget != NULL) { openGLLayout->addWidget(rightWidget); openGLLayout->setStretchFactor(rightWidget, 0); } setCentralWidget(openGLBox); } else { // // OpenGL for brain surface // mainOpenGL = new GuiBrainModelOpenGL(this, NULL, "mainWidgetOpenGL", BrainModel:: BRAIN_MODEL_VIEW_MAIN_WINDOW); setCentralWidget(mainOpenGL); mainOpenGL->setMinimumSize(desiredWidth, desiredHeight); } // // Create the actions // attributeActions = new GuiMainWindowAttributesActions(this); commActions = new GuiMainWindowCommActions(this); fileActions = new GuiMainWindowFileActions(this); helpActions = new GuiMainWindowHelpActions(this); layersActions = new GuiMainWindowLayersActions(this); surfaceActions = new GuiMainWindowSurfaceActions(this); timingActions = new GuiMainWindowTimingActions(this); volumeActions = new GuiMainWindowVolumeActions(this); windowActions = new GuiMainWindowWindowActions(this); // // Create the menus // fileMenu = new GuiMainWindowFileMenu(this, mainOpenGL); menuBar()->addMenu(fileMenu); attributesMenu = new GuiMainWindowAttributesMenu(this); menuBar()->addMenu(attributesMenu); layersMenu = new GuiMainWindowLayersMenu(this); menuBar()->addMenu(layersMenu); surfaceMenu = new GuiMainWindowSurfaceMenu(this); menuBar()->addMenu(surfaceMenu); volumeMenu = new GuiMainWindowVolumeMenu(this); menuBar()->addMenu(volumeMenu); commMenu = new GuiMainWindowCommMenu(this); menuBar()->addMenu(commMenu); windowMenu = new GuiMainWindowWindowMenu(this); menuBar()->addMenu(windowMenu); helpMenu = new GuiMainWindowHelpMenu(this); menuBar()->addMenu(helpMenu); if (enableTimingMenu) { timingMenu = new GuiMainWindowTimingMenu(this); menuBar()->addMenu(timingMenu); } // // Create toolbar after GuiBrainModelOpenGL since the toolbar connects // to slots in it. // toolBar = new GuiToolBar(this, this, mainOpenGL, BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW); addToolBar(toolBar); QObject::connect(toolBar, SIGNAL(modelSelection(int)), this, SLOT(updateDisplayedMenus())); // // Create the status bar // createStatusBar(); // // Initialize other dialog/windows // displayControlDialog = NULL; for (int i = 0; i < BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS; i++) { modelWindow[i] = NULL; } addCellsDialog = NULL; addContourCellsDialog = NULL; alignSurfaceToStandardOrientationDialog = NULL; automaticRotationDialog = NULL; borderDrawUpdateDialog = NULL; bordersCreateInterpolatedDialog = NULL; captureWindowImageDialog = NULL; caretCommandExecutorDialog = NULL; caretCommandScriptBuilderDialog = NULL; contourAlignmentDialog = NULL; contourDrawDialog = NULL; contourSectionControlDialog = NULL; contourSetScaleDialog = NULL; borderOperationsDialog = NULL; drawBorderDialog = NULL; flatMorphingDialog = NULL; flattenFullHemisphereDialog = NULL; fociAttributeAssignmentDialog = NULL; connectivityDialog = NULL; helpViewerDialog = NULL; imageEditorWindow = NULL; identifyDialog = NULL; interpolateSurfaceDialog = NULL; mapStereotaxicFocusDialog = NULL; metricMathDialog = NULL; metricModificationDialog = NULL; metricsToRgbPaintDialog = NULL; modelsEditorDialog = NULL; paletteEditorDialog = NULL; paintNameEditorDialog = NULL; paramsFileEditorDialog = NULL; preferencesDialog = NULL; recordingDialog = NULL; sectionControlDialog = NULL; setTopologyDialog = NULL; smoothingDialog = NULL; shapeModificationDialog = NULL; shapeMathDialog = NULL; sphereMorphingDialog = NULL; standardMeshDialog = NULL; studyCollectionFileEditorDialog = NULL; studyMetaDataFileEditorDialog = NULL; surfaceRegionOfInterestDialog = NULL; surfaceRegionOfInterestDialogOLD = NULL; transformMatrixEditorDialog = NULL; volumeThresholdSegmentationDialog = NULL; volumeResizingDialog = NULL; volumeAttributesDialog = NULL; volumeBiasCorrectionDialog = NULL; volumeMathDialog = NULL; volumeRegionOfInterestDialog = NULL; volumePaintEditorDialog = NULL; volumeSegmentationEditorDialog = NULL; vocabularyFileEditorDialog = NULL; arealEstimationColorKeyDialog = NULL; borderColorKeyDialog = NULL; cellColorKeyDialog = NULL; fociColorKeyDialog = NULL; paintColorKeyDialog = NULL; probAtlasColorKeyDialog = NULL; volumePaintColorKeyDialog = NULL; volumeProbAtlasColorKeyDialog = NULL; QString title("CARET v"); #ifdef UBUNTU title.append("u"); #endif title.append(CaretVersion::getCaretVersionAsString()); title.append(" ("); title.append(__DATE__); title.append(")"); setWindowTitle(title); // // Use the main winodw for parents of progress dialog created // by the "BrainSet". // getBrainSet()->setProgressDialogParent(this); // // The BrainSetwill emit signals when it wants a brain model displayed and/or drawn // QObject::connect(getBrainSet(), SIGNAL(signalDisplayBrainModel(int)), this, SLOT(displayBrainModelInMainWindow(int))); // // The BrainSetwill emit signals the spec file is changed // QObject::connect(getBrainSet(), SIGNAL(signalBrainSetChanged()), this, SLOT(postSpecFileReadInitializations())); } /** * Destructor. */ GuiMainWindow::~GuiMainWindow() { if (afniClientCommunicator != NULL) { delete afniClientCommunicator; afniClientCommunicator = NULL; } if (fivClientCommunicator != NULL) { delete fivClientCommunicator; fivClientCommunicator = NULL; } //if (speechGenerator != NULL) { // delete speechGenerator; // speechGenerator = NULL; //} for (unsigned int i = 0; i < loadedBrainSets.size(); i++) { delete loadedBrainSets[i]; } loadedBrainSets.clear(); //loadedBrainSetDirectory.clear(); } /** * add a brain set. */ void GuiMainWindow::addBrainSet(BrainSet* bs) { loadedBrainSets.push_back(bs); QObject::connect(bs, SIGNAL(signalGraphicsUpdate(BrainSet*)), this, SLOT(slotRedrawWindowsUsingBrainSet(BrainSet*))); } /** * get the active brain structure for specified window. If no argument * is passed the brain set for the main window will be returned. */ BrainSet* GuiMainWindow::getBrainSet(const BrainModel::BRAIN_MODEL_VIEW_NUMBER windowNumber) { return brainSetInWindow[windowNumber]; } /** * get the active brain structure for specified window. If no argument * is passed the brain set for the main window will be returned. */ const BrainSet* GuiMainWindow::getBrainSet(const BrainModel::BRAIN_MODEL_VIEW_NUMBER windowNumber) const { return brainSetInWindow[windowNumber]; } /** * set the active brain structure for specified window. */ void GuiMainWindow::setBrainSet(const BrainModel::BRAIN_MODEL_VIEW_NUMBER windowNumber, BrainSet* newActiveBrainSet) { brainSetInWindow[windowNumber] = newActiveBrainSet; // // Update current directory to that of current spec file and file name prefixing // if (windowNumber == BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) { for (unsigned int i = 0; i < loadedBrainSets.size(); i++) { if (loadedBrainSets[i] == getBrainSet(windowNumber)) { //QDir::setCurrent(loadedBrainSetDirectory[i]); QDir::setCurrent(FileUtilities::dirname(loadedBrainSets[i]->getSpecFileName())); loadedBrainSets[i]->updateDefaultFileNamePrefix(); break; } } } } /** * speak some text. */ void GuiMainWindow::speakText(const QString& /*text*/, const bool /*verboseSpeech*/) { //if (speechGenerator != NULL) { // speechGenerator->speakText(text, verboseSpeech); //} } /** * Slot to display the brain model in the main window */ void GuiMainWindow::displayBrainModelInMainWindow(int modelNumberIn) { // // Verify valid model index for current brain set // const int numModels = getBrainSet()->getNumberOfBrainModels(); if (numModels == 0) { return; } int modelNumber = modelNumberIn; if ((modelNumber < 0) || (modelNumber >= numModels)){ modelNumber = numModels - 1; } // // Since the index is for the currently loaded brain set and multiple brain sets // may be loaded AND the toolbar lists brain models for all brain sets, get the proper // offset into the toolbar. // if (getNumberOfBrainSets() > 1) { int modelOffset = 0; for (int i = 0; i < getNumberOfBrainSets(); i++) { BrainSet* bs = getBrainSetByIndex(i); if (bs == getBrainSet()) { break; } else { modelOffset += bs->getNumberOfBrainModels(); } } modelNumber += modelOffset; } toolBar->setModelSelection(modelNumber); GuiToolBar::updateAllToolBars(true); updateDisplayedMenus(); GuiBrainModelOpenGL::updateAllGL(mainOpenGL); } /** * Display the brain model in the main window */ void GuiMainWindow::displayBrainModelInMainWindow(BrainModel* bm) { if (bm != NULL) { const int numModels = getBrainSet()->getNumberOfBrainModels(); for (int i = 0; i < numModels; i++) { if (getBrainSet()->getBrainModel(i) == bm) { displayBrainModelInMainWindow(i); break; } } } } /** * Display a volume in the main window */ void GuiMainWindow::displayVolumeInMainWindow() { displayBrainModelInMainWindow(getBrainSet()->getBrainModelVolume()); } /** * Display contours in the main window */ void GuiMainWindow::displayContoursInMainWindow() { displayBrainModelInMainWindow(getBrainSet()->getBrainModelContours()); } /** * Display the newest surface in the main window. */ void GuiMainWindow::displayNewestSurfaceInMainWindow() { const BrainModelSurface* bmsv = dynamic_cast(getBrainSet()->getBrainModelSurfaceAndVolume()); const int startIndex = getBrainSet()->getNumberOfBrainModels() - 1; for (int i = startIndex; i >= 0; i--) { BrainModelSurface* bms = getBrainSet()->getBrainModelSurface(i); if ((bms != NULL) && (bms != bmsv)) { displayBrainModelInMainWindow(bms); break; } } } /** * Get the Brain Model in the main window (NULL if no model). */ BrainModel* GuiMainWindow::getBrainModel() { return mainOpenGL->getDisplayedBrainModel(); } /** * Get the Brain Model Contours in the main window (NULL if not a surface) */ BrainModelContours* GuiMainWindow::getBrainModelContours() { return mainOpenGL->getDisplayedBrainModelContours(); } /** * Get the Brain Model Surface in the main window (NULL if not a surface) */ BrainModelSurface* GuiMainWindow::getBrainModelSurface() { return mainOpenGL->getDisplayedBrainModelSurface(); } /** * Get the Brain Model Surface and Volume in the main window (NULL if not a surface) */ BrainModelSurfaceAndVolume* GuiMainWindow::getBrainModelSurfaceAndVolume() { return mainOpenGL->getDisplayedBrainModelSurfaceAndVolume(); } /** * Get the Brain Model Volume in the main window (NULL if not a volume) */ BrainModelVolume* GuiMainWindow::getBrainModelVolume() { return mainOpenGL->getDisplayedBrainModelVolume(); } /** * Get the index of the Brain Model Volume in the main window (-1 if invalid). */ int GuiMainWindow::getBrainModelIndex() const { return mainOpenGL->getDisplayedBrainModelIndex(); } /** * Called when an item is selected from the file:recent spec file menu */ void GuiMainWindow::recentSpecFileMenuSelection(int menuItem) { if (menuItem < static_cast(recentSpecFiles.size())) { readSpecFile(recentSpecFiles[menuItem]); } else { PreferencesFile* pf = getBrainSet()->getPreferencesFile(); recentSpecFiles.clear(); pf->setRecentSpecFiles(recentSpecFiles); if (pf->getFileName().isEmpty() == false) { try { pf->writeFile(pf->getFileName()); } catch(FileException& /*e*/) { } } } } /** * Popup viewing window */ void GuiMainWindow::showViewingWindow(const BrainModel::BRAIN_MODEL_VIEW_NUMBER item) { bool createdWindow = false; if (modelWindow[item] == NULL) { // passing mainOpenGL will used shared context between OpenGL renderers modelWindow[item] = new GuiBrainModelViewingWindow(this, this, item); createdWindow = true; } if (createdWindow) { modelWindow[item]->initializeToolBar(); QtUtilities::positionWindowOffOtherWindow(this, modelWindow[item]); if (item >= BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_3) { if (modelWindow[BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_2] != NULL) { const QSize window2Size = modelWindow[BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_2]->size(); modelWindow[item]->resize(window2Size); //modelWindow[item]->updateGeometry(); } } } modelWindow[item]->show(); modelWindow[item]->activateWindow(); } /** * resize the viewing windows. */ void GuiMainWindow::resizeViewingWindows() { // // Keep list of main and open viewing windows // QStringList windowNames; QList windowNumbers; windowNames.push_back("Main Window"); windowNumbers.push_back(QVariant(BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW)); // // Find open viewing windows // for (int i = BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_2; i < BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS; i++) { const BrainModel::BRAIN_MODEL_VIEW_NUMBER windowNum = static_cast(i); if (modelWindow[windowNum] != NULL) { const QString str("Viewing Window " + QString::number(windowNum + 1)); windowNames << str; windowNumbers << i; } } // // Is a viewing window open ? // if (windowNames.size() > 1) { // // Create dialog for choosing window // WuQDataEntryDialog ded(this); ded.setTextAtTop("Choose the window whose size you would like matched.", true); ded.setWindowTitle("Resize Viewing Windows"); QComboBox* windowComboBox = ded.addComboBox("Resize to Match ", windowNames, &windowNumbers); if (ded.exec() == WuQDataEntryDialog::Accepted) { // // Get the selected window // QWidget* windowWidget = this; const int indx = windowComboBox->currentIndex(); const BrainModel::BRAIN_MODEL_VIEW_NUMBER windowNum = static_cast( windowNumbers.at(indx).toInt()); if (windowNum >= BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_2) { windowWidget = modelWindow[windowNum]; } // // New size for window // const QSize newWindowSize(windowWidget->size()); // // Resize all viewing windows // for (int i = BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_2; i < BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS; i++) { // // If not window resizing is based upon // if (i != windowNum) { if (modelWindow[i] != NULL) { // // New size for window // QSize newSize = newWindowSize; // // If resizing to match the main window // if (windowNum == BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) { // // Get size of main window openGL and // viewing window and openGL // const QSize mainOpenGLSize = mainOpenGL->size(); const QSize viewingWindowOpenGLSize = modelWindow[i]->getBrainModelOpenGL()->size(); const int dH = mainOpenGLSize.height() - viewingWindowOpenGLSize.height(); const int dW = mainOpenGLSize.width() - viewingWindowOpenGLSize.width(); // // Proportionately change window size // const QSize currentSize(modelWindow[i]->size()); newSize.setHeight(currentSize.height() + dH); newSize.setWidth(currentSize.width() + dW); } // // Update the windows size // modelWindow[i]->resize(newSize); modelWindow[i]->updateGeometry(); } } } } } } /** * Destroy a viewing window */ void GuiMainWindow::removeViewingWindow(const BrainModel::BRAIN_MODEL_VIEW_NUMBER item) { modelWindow[item] = NULL; } /** * display the models editor. */ void GuiMainWindow::displayModelsEditorDialog() { if (modelsEditorDialog == NULL) { modelsEditorDialog = new GuiModelsEditorDialog(this); } modelsEditorDialog->show(); modelsEditorDialog->activateWindow(); } /** * create (if necessary) and show the border operations dialog. */ void GuiMainWindow::displayBorderOperationsDialog() { getBorderOperationsDialog(true); } /** * create (if necessary) and show the flatten full hemisphere dialog. */ void GuiMainWindow::displayFlattenFullHemisphereDialog() { getFlattenFullHemisphereDialog(true); } /** * create (if necessary) and show the standard mesh dialog. */ void GuiMainWindow::displayStandardMeshDialog() { getStandardMeshDialog(true); } /** * Create (if necessary) and show the draw border dialog. */ void GuiMainWindow::displayDrawBorderDialog() { getDrawBorderDialog(true); } /** * create and display the palette editor dialog. */ void GuiMainWindow::displayPaletteEditorDialog() { if (paletteEditorDialog == NULL) { paletteEditorDialog = new GuiPaletteEditorDialog(this); } paletteEditorDialog->show(); paletteEditorDialog->activateWindow(); } /** * Create, possibly show, and return the draw border dialog. */ GuiDrawBorderDialog* GuiMainWindow::getDrawBorderDialog(const bool showIt) { bool firstTime = false; if (drawBorderDialog == NULL) { firstTime = true; drawBorderDialog = new GuiDrawBorderDialog(this); } if (showIt) { drawBorderDialog->show(); drawBorderDialog->activateWindow(); } if (firstTime) { QtUtilities::positionWindowOffOtherWindow(this, drawBorderDialog); } return drawBorderDialog; } /** * create, possibly show, and return the border operations dialog. */ GuiBorderOperationsDialog* GuiMainWindow::getBorderOperationsDialog(const bool showIt) { bool firstTime = false; if (borderOperationsDialog == NULL) { firstTime = true; borderOperationsDialog = new GuiBorderOperationsDialog(this); } if (showIt) { borderOperationsDialog->show(); borderOperationsDialog->activateWindow(); } if (firstTime) { QtUtilities::positionWindowOffOtherWindow(this, borderOperationsDialog); } return borderOperationsDialog; } /** * create, possibly show, and return the flatten full hemisphere dialog. */ GuiFlattenFullHemisphereDialog* GuiMainWindow::getFlattenFullHemisphereDialog(const bool showIt) { bool firstTime = false; if (flattenFullHemisphereDialog == NULL) { firstTime = true; flattenFullHemisphereDialog = new GuiFlattenFullHemisphereDialog(this); } if (showIt) { flattenFullHemisphereDialog->showFirstPage(); flattenFullHemisphereDialog->show(); flattenFullHemisphereDialog->activateWindow(); } if (firstTime) { QtUtilities::positionWindowOffOtherWindow(this, flattenFullHemisphereDialog); } return flattenFullHemisphereDialog; } /** * create, possibly show, and return the standard mesh dialog. */ GuiStandardMeshDialog* GuiMainWindow::getStandardMeshDialog(const bool showIt) { bool firstTime = false; if (standardMeshDialog == NULL) { firstTime = true; standardMeshDialog = new GuiStandardMeshDialog(this); } if (showIt) { standardMeshDialog->showFirstPage(); standardMeshDialog->show(); standardMeshDialog->activateWindow(); } if (firstTime) { QtUtilities::positionWindowOffOtherWindow(this, standardMeshDialog); } return standardMeshDialog; } /** * */ void GuiMainWindow::displaySmoothingDialog() { if (smoothingDialog == NULL) { smoothingDialog = new GuiSmoothingDialog(this, false, true, NULL); } smoothingDialog->show(); smoothingDialog->activateWindow(); } /** * Create, possibly show, and return the recording dialog */ GuiRecordingDialog* GuiMainWindow::getRecordingDialog(const bool showIt) { if (recordingDialog == NULL) { recordingDialog = new GuiRecordingDialog(this); } if (showIt) { recordingDialog->show(); recordingDialog->activateWindow(); } return recordingDialog; } /** * Create, possibly show, and return the draw cells dialog */ GuiAddCellsDialog* GuiMainWindow::getAddCellsDialog(const bool showIt) { if (addCellsDialog == NULL) { addCellsDialog = new GuiAddCellsDialog(GuiAddCellsDialog::DIALOG_MODE_ADD_CELLS, this); } if (showIt) { addCellsDialog->show(); addCellsDialog->activateWindow(); } return addCellsDialog; } /** * Create, possibly show, and return the draw cells dialog */ GuiAddCellsDialog* GuiMainWindow::getAddContourCellsDialog(const bool showIt) { if (addContourCellsDialog == NULL) { addContourCellsDialog = new GuiAddCellsDialog(GuiAddCellsDialog::DIALOG_MODE_ADD_CONTOUR_CELLS, this); } if (showIt) { addContourCellsDialog->show(); addContourCellsDialog->activateWindow(); } return addContourCellsDialog; } /** * Create, possibly show, and return the contour alignment dialog. */ GuiContourAlignmentDialog* GuiMainWindow::getContourAlignmentDialog(const bool showIt) { if (contourAlignmentDialog == NULL) { contourAlignmentDialog = new GuiContourAlignmentDialog(this); } if (showIt) { contourAlignmentDialog->show(); contourAlignmentDialog->activateWindow(); } return contourAlignmentDialog; } /** * Create, possibly show, and return the draw contour dialog. */ GuiContourDrawDialog* GuiMainWindow::getContourDrawDialog(const bool showIt) { if (contourDrawDialog == NULL) { contourDrawDialog = new GuiContourDrawDialog(this); } if (showIt) { contourDrawDialog->show(); contourDrawDialog->activateWindow(); } return contourDrawDialog; } /** * Create, possibly show, and return the set scale dialog. */ GuiContourSetScaleDialog* GuiMainWindow::getContourSetScaleDialog(const bool showIt) { if (contourSetScaleDialog == NULL) { contourSetScaleDialog = new GuiContourSetScaleDialog(this); } if (showIt) { contourSetScaleDialog->show(); contourSetScaleDialog->activateWindow(); } return contourSetScaleDialog; } /** * Create, possibly show, and return the contour section dialog. */ GuiContourSectionControlDialog* GuiMainWindow::getContourSectionControlDialog(const bool showIt) { if (contourSectionControlDialog == NULL) { contourSectionControlDialog = new GuiContourSectionControlDialog(this); } if (showIt) { contourSectionControlDialog->show(); contourSectionControlDialog->activateWindow(); } return contourSectionControlDialog; } /** * Create, possiblty show and return the map stereotaxic focus dialog */ GuiMapStereotaxicFocusDialog* GuiMainWindow::getMapStereotaxicFocusDialog(const bool showIt) { if (mapStereotaxicFocusDialog == NULL) { mapStereotaxicFocusDialog = new GuiMapStereotaxicFocusDialog(this); } if (showIt) { mapStereotaxicFocusDialog->show(); mapStereotaxicFocusDialog->activateWindow(); } return mapStereotaxicFocusDialog; } /** * Display the metric math dialog. */ void GuiMainWindow::displayMetricMathDialog() { if (metricMathDialog == NULL) { metricMathDialog = new GuiDataFileMathDialog(this, GuiDataFileMathDialog::DIALOG_MODE_METRIC_FILE); } metricMathDialog->show(); metricMathDialog->activateWindow(); } /** * Display the shape math dialog. */ void GuiMainWindow::displayShapeMathDialog() { if (shapeMathDialog == NULL) { shapeMathDialog = new GuiDataFileMathDialog(this, GuiDataFileMathDialog::DIALOG_MODE_SURFACE_SHAPE_FILE); } shapeMathDialog->show(); shapeMathDialog->activateWindow(); } /** * Display the volume math dialog. */ void GuiMainWindow::displayVolumeMathDialog() { if (volumeMathDialog == NULL) { volumeMathDialog = new GuiDataFileMathDialog(this, GuiDataFileMathDialog::DIALOG_MODE_VOLUME_FILE); } volumeMathDialog->show(); volumeMathDialog->activateWindow(); } /** * Create, possibly show and return the metrics to rgb paint dialog. */ GuiMetricsToRgbPaintDialog* GuiMainWindow::getMetricsToRgbPaintDialog(const bool showIt) { if (metricsToRgbPaintDialog == NULL) { metricsToRgbPaintDialog = new GuiMetricsToRgbPaintDialog(this); } if (showIt) { metricsToRgbPaintDialog->show(); metricsToRgbPaintDialog->activateWindow(); } return metricsToRgbPaintDialog; } /** * Create, possibly show and return the surface region of interest dialog. */ GuiSurfaceRegionOfInterestDialog* GuiMainWindow::getSurfaceRegionOfInterestDialog(const bool showIt) { if (surfaceRegionOfInterestDialog == NULL) { surfaceRegionOfInterestDialog = new GuiSurfaceRegionOfInterestDialog(this); } if (showIt) { surfaceRegionOfInterestDialog->show(); surfaceRegionOfInterestDialog->activateWindow(); } return surfaceRegionOfInterestDialog; } /** * Create, possibly show and return the surface region of interest dialog. */ GuiSurfaceRegionOfInterestDialogOLD* GuiMainWindow::getSurfaceRegionOfInterestDialogOLD(const bool showIt) { if (surfaceRegionOfInterestDialogOLD == NULL) { surfaceRegionOfInterestDialogOLD = new GuiSurfaceRegionOfInterestDialogOLD(this); } if (showIt) { surfaceRegionOfInterestDialogOLD->show(); surfaceRegionOfInterestDialogOLD->activateWindow(); } return surfaceRegionOfInterestDialogOLD; } /** * Create, possibly show and return the volume region of interest dialog. */ GuiVolumeRegionOfInterestDialog* GuiMainWindow::getVolumeRegionOfInterestDialog(const bool showIt) { if (volumeRegionOfInterestDialog == NULL) { volumeRegionOfInterestDialog = new GuiVolumeRegionOfInterestDialog(this); } if (showIt) { volumeRegionOfInterestDialog->show(); volumeRegionOfInterestDialog->activateWindow(); } return volumeRegionOfInterestDialog; } /** * Create, possibly show and return the volume threshold segmentation dialog. */ GuiVolumeThresholdSegmentationDialog* GuiMainWindow::getVolumeThresholdSegmentationDialog(const bool showIt) { if (volumeThresholdSegmentationDialog == NULL) { volumeThresholdSegmentationDialog = new GuiVolumeThresholdSegmentationDialog(this); } if (showIt) { volumeThresholdSegmentationDialog->show(); volumeThresholdSegmentationDialog->activateWindow(); } return volumeThresholdSegmentationDialog; } /** * Create, possibly show and return the metric modification dialog. */ GuiMetricModificationDialog* GuiMainWindow::getMetricModificationDialog(const bool showIt) { if (metricModificationDialog == NULL) { metricModificationDialog = new GuiMetricModificationDialog(this, GuiMetricModificationDialog::FILE_TYPE_MODE_METRIC); } if (showIt) { metricModificationDialog->show(); metricModificationDialog->activateWindow(); } return metricModificationDialog; } /** * Create, possibly show and return the shape modification dialog. */ GuiMetricModificationDialog* GuiMainWindow::getShapeModificationDialog(const bool showIt) { if (shapeModificationDialog == NULL) { shapeModificationDialog = new GuiMetricModificationDialog(this, GuiMetricModificationDialog::FILE_TYPE_MODE_SURFACE_SHAPE); } if (showIt) { shapeModificationDialog->show(); shapeModificationDialog->activateWindow(); } return shapeModificationDialog; } /** * Show the flat morphing dialog */ void GuiMainWindow::showFlatMorphingDialog() { if (flatMorphingDialog == NULL) { flatMorphingDialog = new GuiMorphingDialog(this, BrainModelSurfaceMorphing::MORPHING_SURFACE_FLAT); } flatMorphingDialog->updateDialog(); flatMorphingDialog->show(); flatMorphingDialog->activateWindow(); } /** * Show the sphere morphing dialog */ void GuiMainWindow::showSphereMorphingDialog() { if (sphereMorphingDialog == NULL) { sphereMorphingDialog = new GuiMorphingDialog(this, BrainModelSurfaceMorphing::MORPHING_SURFACE_SPHERICAL); } sphereMorphingDialog->updateDialog(); sphereMorphingDialog->show(); sphereMorphingDialog->activateWindow(); } /** * Create, possibly show and return the interpolate surface dialog. */ GuiInterpolateSurfacesDialog* GuiMainWindow::getInterpolateSurfaceDialog(const bool showIt) { if (interpolateSurfaceDialog == NULL) { interpolateSurfaceDialog = new GuiInterpolateSurfacesDialog(this); } if (showIt) { interpolateSurfaceDialog->show(); interpolateSurfaceDialog->activateWindow(); } return interpolateSurfaceDialog; } /** * Show a page in the help viewer dialog. If the page name is empty the default page is shown. */ void GuiMainWindow::showHelpViewerDialog(const QString& helpPage) { // // See if external web page // if (helpPage.startsWith("http://")) { displayWebPage(helpPage); } else { if (helpViewerDialog == NULL) { helpViewerDialog = new GuiHelpViewerWindow(this); } helpViewerDialog->loadPage(helpPage); helpViewerDialog->show(); helpViewerDialog->activateWindow(); } } /** * show a page in the help viewer dialog over a modal dialog. */ void GuiMainWindow::showHelpPageOverModalDialog(QDialog* modalParent, const QString& helpPage) { GuiHelpViewerWindow hvw(modalParent, helpPage); hvw.exec(); } /** * create, (possibly show), and return the border created interpolated dialog. */ GuiBordersCreateInterpolatedDialog* GuiMainWindow::getBordersCreateInterpolatedDialog(const bool showIt) { if (bordersCreateInterpolatedDialog == NULL) { bordersCreateInterpolatedDialog = new GuiBordersCreateInterpolatedDialog(this); } if (showIt) { bordersCreateInterpolatedDialog->show(); bordersCreateInterpolatedDialog->raise(); } return bordersCreateInterpolatedDialog; } /** * Create, possibly show and return the identify dialog */ GuiIdentifyDialog* GuiMainWindow::getIdentifyDialog(const bool showIt) { bool firstTime = false; if (identifyDialog == NULL) { identifyDialog = new GuiIdentifyDialog(this); firstTime = true; } if (showIt) { identifyDialog->show(); if (firstTime) { QtUtilities::positionWindowOffOtherWindow(this, identifyDialog); } identifyDialog->raise(); //identifyDialog->activateWindow(); } return identifyDialog; } /** * Create (if necessary) and show the identify dialog */ void GuiMainWindow::displayIdentifyDialog() { getIdentifyDialog(true); } /** * Create, possibly show and return the volume attributes dialog */ GuiVolumeAttributesDialog* GuiMainWindow::getVolumeAttributesDialog(const bool showIt) { if (volumeAttributesDialog == NULL) { volumeAttributesDialog = new GuiVolumeAttributesDialog(this); } if (showIt) { volumeAttributesDialog->show(); volumeAttributesDialog->raise(); volumeAttributesDialog->activateWindow(); } return volumeAttributesDialog; } /** * Create, possibly show and return the volume segmentation editor dialog */ GuiVolumeSegmentationEditorDialog* GuiMainWindow::getVolumeSegmentationEditorDialog(const bool showIt) { if (volumeSegmentationEditorDialog == NULL) { volumeSegmentationEditorDialog = new GuiVolumeSegmentationEditorDialog(this); } if (showIt) { volumeSegmentationEditorDialog->show(); volumeSegmentationEditorDialog->raise(); volumeSegmentationEditorDialog->activateWindow(); } return volumeSegmentationEditorDialog; } /** * Create, possibly show and return the volume paint editor dialog */ GuiVolumePaintEditorDialog* GuiMainWindow::getVolumePaintEditorDialog(const bool showIt) { if (volumePaintEditorDialog == NULL) { volumePaintEditorDialog = new GuiVolumePaintEditorDialog(this); } if (showIt) { volumePaintEditorDialog->show(); volumePaintEditorDialog->activateWindow(); } return volumePaintEditorDialog; } /** * display the study meta data file editor dialog. */ void GuiMainWindow::displayStudyMetaDataFileEditorDialog() { if (studyMetaDataFileEditorDialog == NULL) { studyMetaDataFileEditorDialog = new GuiStudyMetaDataFileEditorDialog(this); } studyMetaDataFileEditorDialog->show(); studyMetaDataFileEditorDialog->activateWindow(); } /** * display the study collection file editor dialog. */ void GuiMainWindow::displayStudyCollectionFileEditorDialog() { if (studyCollectionFileEditorDialog == NULL) { studyCollectionFileEditorDialog = new GuiStudyCollectionFileEditorDialog(this); } studyCollectionFileEditorDialog->show(); studyCollectionFileEditorDialog->activateWindow(); } /** * Return the volume resizing dialog. Dialog will be created only if parameter is true */ GuiVolumeResizingDialog* GuiMainWindow::getVolumeResizingDialog(const bool createIt) { if (createIt) { if (volumeResizingDialog == NULL) { volumeResizingDialog = new GuiVolumeResizingDialog(this); } volumeResizingDialog->show(); volumeResizingDialog->activateWindow(); } return volumeResizingDialog; } /** * Create (if necessary) and display the preferences dialog */ void GuiMainWindow::displayPreferencesDialog() { if (preferencesDialog == NULL) { preferencesDialog = new GuiPreferencesDialog(this); } preferencesDialog->show(); preferencesDialog->raise(); preferencesDialog->activateWindow(); } /** * display the paint editor dialog. */ void GuiMainWindow::displayPaintEditorDialog() { if (paintNameEditorDialog == NULL) { paintNameEditorDialog = new GuiPaintNameEditorDialog(this); } paintNameEditorDialog->show(); paintNameEditorDialog->raise(); paintNameEditorDialog->activateWindow(); } /** * Called when Toolbar "Spec" button is pressed. */ void GuiMainWindow::displayFastOpenDataFileDialog() { const QString specFileName(getBrainSet()->getSpecFileName()); if (specFileName.isEmpty()) { QMessageBox::critical(this, "No Spec File", "There is no spec file loaded."); return; } // // Read the spec file. // SpecFile sf; try { sf.readFile(specFileName); sf.setDefaultFilesFiducialAndFlat(); } catch (FileException& e) { QMessageBox::critical(this, "Error reading spec file", e.whatQString()); return; } GuiSpecFileDialog* gsfd = new GuiSpecFileDialog(this, sf, GuiSpecFileDialog::SPEC_DIALOG_MODE_OPEN_DATA_FILE); gsfd->show(); gsfd->raise(); } /** * Create, display, and return the overlay underlay dialog. */ void GuiMainWindow::displayDisplayControlDialog() { bool firstTime = false; if (displayControlDialog == NULL) { displayControlDialog = new GuiDisplayControlDialog(this); firstTime = true; } displayControlDialog->show(); displayControlDialog->raise(); displayControlDialog->activateWindow(); if (firstTime) { QtUtilities::positionWindowOffOtherWindow(this, displayControlDialog); } } /** * Update the display control dialog */ void GuiMainWindow::updateDisplayControlDialog() { if (displayControlDialog != NULL) { displayControlDialog->updateAllItemsInDialog(true, false); } } /** * Create (if necessary) and display the caret command executor dialog. */ void GuiMainWindow::displayCaretCommandExecutorDialog() { if (caretCommandExecutorDialog == NULL) { caretCommandExecutorDialog = new GuiCaretCommandDialog(this, getBrainSet()->getCaretHomeDirectory(), GuiCaretCommandDialog::DIALOG_MODE_EXECUTOR_NON_MODAL); } caretCommandExecutorDialog->show(); caretCommandExecutorDialog->activateWindow(); } /** * Create (if necessary) and display the caret command script builder dialog. */ void GuiMainWindow::displayCaretCommandScriptBuilderDialog() { if (caretCommandScriptBuilderDialog == NULL) { caretCommandScriptBuilderDialog = new GuiCaretCommandScriptBuilderDialog(this, getBrainSet()->getCaretHomeDirectory()); } caretCommandScriptBuilderDialog->show(); caretCommandScriptBuilderDialog->activateWindow(); } /** * Create (if necessary) and display the section control dialog. */ void GuiMainWindow::displaySectionControlDialog() { if (sectionControlDialog == NULL) { sectionControlDialog = new GuiSectionControlDialog(this); } sectionControlDialog->show(); sectionControlDialog->activateWindow(); } /** * Create (if necessary) and display the automatic rotation dialog. */ void GuiMainWindow::displayAutomaticRotationDialog() { if (automaticRotationDialog == NULL) { automaticRotationDialog = new GuiAutomaticRotationDialog(this); } automaticRotationDialog->show(); automaticRotationDialog->activateWindow(); } /** * Update the section control dialog. */ void GuiMainWindow::updateSectionControlDialog() { if (sectionControlDialog != NULL) { sectionControlDialog->updateDialog(); } } /** * See if a data file has been modified before quittting program. */ void GuiMainWindow::checkFileModified(const QString typeName, const AbstractFile* af, QString& msg) { if (af != NULL) { if (af->getModified() != 0) { msg.append(" "); msg.append(typeName); msg.append(" "); if (af->getFileName().isEmpty()) { msg.append("No-Name"); } else { msg.append(FileUtilities::basename(af->getFileName())); } msg.append("\n"); } } } /** * See if a volume file is modified. */ void GuiMainWindow::checkVolumeFileModified(const QString& typeName, const VolumeFile* vf, QString& msg) { if (vf != NULL) { if (vf->getModified()) { msg.append(typeName); msg.append(" Volume File - "); if (vf->getFileName().isEmpty()) { msg.append("No-Name"); } else { msg.append(FileUtilities::basename(vf->getFileName())); } msg.append("\n"); } } } /** * Check for modified files. */ void GuiMainWindow::checkForModifiedFiles(BrainSet* bs, QString& msgOut, const bool checkSceneFileFlag) { QString msg; for (int i = 0; i < bs->getNumberOfTopologyFiles(); i++) { TopologyFile* tf = bs->getTopologyFile(i); QString s("Topology File - "); s.append(tf->getTopologyTypeName()); checkFileModified(s, tf, msg); } const int numBrainModels = bs->getNumberOfBrainModels(); for (int i = 0; i < numBrainModels; i++) { BrainModel* bm = bs->getBrainModel(i); switch(bm->getModelType()) { case BrainModel::BRAIN_MODEL_CONTOURS: { BrainModelContours* bmc = dynamic_cast(bm); QString s("Contour File - "); ContourFile* cf = bmc->getContourFile(); checkFileModified(s, cf, msg); } break; case BrainModel::BRAIN_MODEL_SURFACE: { BrainModelSurface* bms = dynamic_cast(bm); QString s("Coordinate File - "); CoordinateFile* cf = bms->getCoordinateFile(); s.append(bms->getSurfaceTypeName()); checkFileModified(s, cf, msg); } break; case BrainModel::BRAIN_MODEL_VOLUME: break; case BrainModel::BRAIN_MODEL_SURFACE_AND_VOLUME: break; } } for (int i = 0; i < bs->getNumberOfVolumeAnatomyFiles(); i++) { checkVolumeFileModified("Anatomy", bs->getVolumeAnatomyFile(i), msg); } for (int i = 0; i < bs->getNumberOfVolumeFunctionalFiles(); i++) { checkVolumeFileModified("Functional", bs->getVolumeFunctionalFile(i), msg); } for (int i = 0; i < bs->getNumberOfVolumePaintFiles(); i++) { checkVolumeFileModified("Paint", bs->getVolumePaintFile(i), msg); } for (int i = 0; i < bs->getNumberOfVolumeRgbFiles(); i++) { checkVolumeFileModified("RGB", bs->getVolumeRgbFile(i), msg); } for (int i = 0; i < bs->getNumberOfVolumeSegmentationFiles(); i++) { checkVolumeFileModified("Segmentation", bs->getVolumeSegmentationFile(i), msg); } for (int i = 0; i < bs->getNumberOfVolumeVectorFiles(); i++) { checkVolumeFileModified("Vector", bs->getVolumeVectorFile(i), msg); } checkFileModified("Area Color File", bs->getAreaColorFile(), msg); checkFileModified("Areal Estimation File", bs->getArealEstimationFile(), msg); BrainModelBorderSet* bmbs = bs->getBorderSet(); for (int i = 0; i < numBrainModels; i++) { const BrainModelSurface* bms = bs->getBrainModelSurface(i); if (bms != NULL) { if (bmbs->getSurfaceBordersModified(bms)) { msg.append("Border File for Surface "); msg.append(" "); const CoordinateFile* cf = bms->getCoordinateFile(); if (cf->getFileName().isEmpty()) { msg.append("No-Name"); } else { msg.append(FileUtilities::basename(cf->getFileName())); } msg.append("\n"); } } } checkFileModified("Border File (Volume)", bs->getVolumeBorderFile(), msg); checkFileModified("Border Color File", bs->getBorderColorFile(), msg); if (bmbs->getProjectionsModified()) { msg.append("Border Projection File\n"); } checkFileModified("Cell Color File", bs->getCellColorFile(), msg); checkFileModified("Cell Projection File", bs->getCellProjectionFile(), msg); checkFileModified("CoCoMac File", bs->getCocomacFile(), msg); checkFileModified("Contour Cells File", bs->getContourCellFile(), msg); checkFileModified("Contour Cell Color File", bs->getContourCellColorFile(), msg); checkFileModified("Cuts File", bs->getCutsFile(), msg); checkFileModified("Deformation Field File", bs->getDeformationFieldFile(), msg); checkFileModified("Foci Color File", bs->getFociColorFile(), msg); checkFileModified("Foci Projection File", bs->getFociProjectionFile(), msg); checkFileModified("Foci Search File", bs->getFociSearchFile(), msg); checkFileModified("Geodesic Distance File", bs->getGeodesicDistanceFile(), msg); for (int i = 0; i < bs->getNumberOfImageFiles(); i++) { checkFileModified("Image File", bs->getImageFile(i), msg); } checkFileModified("Lat/Lon File", bs->getLatLonFile(), msg); checkFileModified("Metric File", bs->getMetricFile(), msg); checkFileModified("Paint File", bs->getPaintFile(), msg); checkFileModified("Params File", bs->getParamsFile(), msg); checkFileModified("Probabilistic Atlas File", bs->getProbabilisticAtlasSurfaceFile(), msg); checkFileModified("Palette File", bs->getPaletteFile(), msg); checkFileModified("RGB Paint File", bs->getRgbPaintFile(), msg); if (checkSceneFileFlag) { checkFileModified("Scene File", bs->getSceneFile(), msg); } checkFileModified("Section File", bs->getSectionFile(), msg); checkFileModified("Study Collection File", bs->getStudyCollectionFile(), msg); checkFileModified("Study Metadata File", bs->getStudyMetaDataFile(), msg); checkFileModified("Surface Shape File", bs->getSurfaceShapeFile(), msg); checkFileModified("Topography File", bs->getTopographyFile(), msg); checkFileModified("Vocabulary File", bs->getVocabularyFile(), msg); checkFileModified("Transformation Matrix File", bs->getTransformationMatrixFile(), msg); for (int i = 0; i < bs->getNumberOfVectorFiles(); i++) { checkFileModified("Vector File", bs->getVectorFile(i), msg); } for (int i = 0; i < bs->getNumberOfVtkModelFiles(); i++) { checkFileModified("VTK Model File", bs->getVtkModelFile(i), msg); } checkFileModified("Wustl Region File", bs->getWustlRegionFile(), msg); //checkFileModified(" File", bs->(), msg); if (msg.isEmpty() == false) { msgOut.append(FileUtilities::basename(bs->getSpecFileName())); msgOut.append(" has modified files:\n"); msgOut.append(msg); msgOut.append("\n"); } } /** * Close the current spec file. */ void GuiMainWindow::slotCloseSpecFile() { closeSpecFile(false); } /** * Close the current spec file but keep the scene and spec file. */ void GuiMainWindow::slotCloseSpecFileKeepSceneAndSpec() { closeSpecFile(true); } /** * close the spec file. */ void GuiMainWindow::closeSpecFile(const bool keepSceneAndSpec, const bool checkForModifiedFilesFlag) { // // See if files are modified // bool closeSpecFileFlag = false; if (checkForModifiedFilesFlag) { QString msg; checkForModifiedFiles(getBrainSet(), msg, true); if (msg.isEmpty() == false) { // // Return value of zero is YES button. // QString msg2; if (keepSceneAndSpec) { msg2 = "Are you sure that you want to unload all files except\n" "for the spec file and the scenes file?\n\n"; } else { msg2 = "Are you sure that you want to close the spec file ?\n\n"; } msg2.append(msg); if (WuQMessageBox::warning(this, "WARNING", msg2, (QMessageBox::Yes | QMessageBox::No), QMessageBox::Yes) == QMessageBox::Yes) { closeSpecFileFlag = true; } } else { QString msg2; if (keepSceneAndSpec) { msg2 = "Are you sure that you want to unload all files \n" "except for the spec file and the scenes file?"; } else { msg2 = "Are you sure you want to close the spec file ?"; } // // Return value of zero is YES button. // if (WuQMessageBox::warning(this, "WARNING", msg2, (QMessageBox::Yes | QMessageBox::No), QMessageBox::Yes) == QMessageBox::Yes) { closeSpecFileFlag = true; } } } else { closeSpecFileFlag = true; } if (closeSpecFileFlag) { const int numberOfSpecFilesLoaded = loadedBrainSets.size(); const QString specFileName(getBrainSet()->getSpecFileName()); getBrainSet()->reset(keepSceneAndSpec); if (keepSceneAndSpec) { getBrainSet()->setSpecFileName(specFileName); } else{ getBrainSet()->setSpecFileName(""); getBrainSet()->setStructure(Structure::STRUCTURE_TYPE_INVALID); if (loadedBrainSets.size() > 1) { // // Delete the brain set // for (unsigned int i = 0; i < loadedBrainSets.size(); i++) { if (loadedBrainSets[i] == getBrainSet()) { delete loadedBrainSets[i]; loadedBrainSets.erase(loadedBrainSets.begin() + i); //loadedBrainSetDirectory.erase(loadedBrainSetDirectory.begin() + i); break; } } setBrainSet(BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW, loadedBrainSets[0]); //QDir::setCurrent(loadedBrainSetDirectory[0]); QDir::setCurrent(FileUtilities::dirname(loadedBrainSets[0]->getSpecFileName())); } } if (numberOfSpecFilesLoaded > 1) { removeAllImageViewingWindows(); removeAllModelViewingWindows(); } GuiFilesModified fm; fm.setStatusForAll(true); fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } } /** * close all spec files. */ void GuiMainWindow::closeAllSpecFiles() { bool keepClosing = true; while (keepClosing) { keepClosing = (getNumberOfBrainSets() > 1); closeSpecFile(false, false); } } /** * Called when the program should close. */ void GuiMainWindow::closeEvent(QCloseEvent* event) { slotCloseProgram(); event->ignore(); } /** * close the program. */ void GuiMainWindow::slotCloseProgram() { QString msg; // // See if files are modified // for (unsigned int i = 0; i < loadedBrainSets.size(); i++) { checkForModifiedFiles(loadedBrainSets[i], msg, true); } if (msg.isEmpty() == false) { // // Return value of zero is YES button. // QString msg2("Are you sure that you want to quit?\n" "Changes to these files will be lost:\n\n"); msg2.append(msg); WuQDataEntryDialog warningDialog(this); warningDialog.setWindowTitle("Caret 5"); warningDialog.addTextEdit("", msg2, true); if (warningDialog.exec() == WuQDataEntryDialog::Accepted) { qApp->quit(); } /* if (QMessageBox::warning(this, "Caret 5", msg2, (QMessageBox::Ok | QMessageBox::Cancel), QMessageBox::Cancel) == QMessageBox::Ok) { //speakText("Goodbye carrot user."); qApp->quit(); } */ } else { // // Return value of zero is YES button. // if (QMessageBox::warning(this, "Caret 5", "Are you sure you want to quit ?", (QMessageBox::Yes | QMessageBox::No), QMessageBox::Yes) == QMessageBox::Yes) { //speakText("Goodbye carrot user."); qApp->quit(); } } } /** * Add spec file name to preference's recent spec files if * the file is not already in the list */ void GuiMainWindow::addToRecentSpecFiles(const QString& name) { PreferencesFile* pf = getBrainSet()->getPreferencesFile(); pf->addToRecentSpecFiles(name, true); /* std::vector files; pf->getRecentSpecFiles(files); int foundIndex = -1; for (unsigned int i = 0; i < files.size(); i++) { if (files[i] == name) { if (i == 0) { // name is last file - do not need to do anything return; } foundIndex = i; break; } } // // Make file just opened the first file and add allow up to 15 files. // std::vector filesOut; filesOut.push_back(name); for (int j = 0; j < static_cast(files.size()); j++) { if (j != foundIndex) { filesOut.push_back(files[j]); } if (filesOut.size() >= 15) { break; } } pf->setRecentSpecFiles(filesOut); if (pf->getFileName().empty() == false) { try { pf->writeFile(pf->getFileName()); } catch(FileException&) { } } */ } /** * Read a spec file with the specified name */ void GuiMainWindow::readSpecFile(const QString& filename) { removeAllImageViewingWindows(); // // Read the spec file. // SpecFile sf; try { sf.readFile(filename); sf.setDefaultFilesFiducialAndFlat(); } catch (FileException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "Error reading spec file", e.whatQString()); return; } GuiSpecFileDialog* specDialog = new GuiSpecFileDialog(this, sf, GuiSpecFileDialog::SPEC_DIALOG_MODE_OPEN_SPEC_FILE); specDialog->show(); specDialog->raise(); specDialog->activateWindow(); } /** * Load the specified spec file's data files. */ void GuiMainWindow::loadSpecFilesDataFiles(SpecFile sf, const TransformationMatrix* tm, const bool appendToExistingLoadedSpecFiles) { if (getBrainSet()->getNumberOfBrainModels() > 0) { int result = 0; if (appendToExistingLoadedSpecFiles == false) { QString msg("Caret is now able to load and view multiple spec files.\n" "\n" "If you are not sure which button to push, use \"New Spec Only\".\n" "\n" "The model selection control in the main window's toolbar and in" "the viewing window's toolbar will list the brain models (contours," "surfaces, and volumes) for all loaded spec files. The display " "control dialog and all other dialogs operate on the model (and" "its associated data files) in the main window.\n" "\n" "Choose \"New Spec Only\" if you only want to view the new" "spec file that you are loading.\n" "\n" "Choose \"Keep Loaded Spec\" if you want to view both the new" "spec file and the files already loaded into Caret.\n"); WuQMessageBox msgBox(this); msgBox.setText(msg); msgBox.setTheWindowTitle("New Spec?"); QPushButton* keepLoadedSpecPushButton = msgBox.addButton("Keep Loaded Spec", QMessageBox::ActionRole); QPushButton* newSpecOnlyPushButton = msgBox.addButton("New Spec Only", QMessageBox::ActionRole); QPushButton* cancelPushButton = msgBox.addButton("Cancel", QMessageBox::ActionRole); msgBox.exec(); if (msgBox.clickedButton() == keepLoadedSpecPushButton) { result = 0; } else if (msgBox.clickedButton() == newSpecOnlyPushButton) { result = 1; } else if (msgBox.clickedButton() == cancelPushButton) { result = 2; } } switch (result) { case 0: { BrainSet* bs = new BrainSet(false); addBrainSet(bs); //loadedBrainSetDirectory.push_back(QDir::currentPath()); setBrainSet(BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW, bs); } break; case 1: // // Note: Do not need to erase the spec contents from memory // since that will be taken care of when new spec is read. // { QString msg; for (unsigned int i = 0; i < loadedBrainSets.size(); i++) { checkForModifiedFiles(loadedBrainSets[i], msg, true); } if (msg.isEmpty() == false) { // // Return value of zero is YES button. // QString msg2("If you choose \"Yes\" changes to these files will be lost:\n\n"); msg2.append(msg); WuQDataEntryDialog warningDialog(this); warningDialog.setWindowTitle("Caret 5"); warningDialog.addTextEdit("", msg2, true); warningDialog.setOkButtonText("Yes"); warningDialog.setCancelButtonText("No"); if (warningDialog.exec() != WuQDataEntryDialog::Accepted) { return; } if (QMessageBox::warning(this, "WARNING", msg2, (QMessageBox::Yes | QMessageBox::No), QMessageBox::No) == QMessageBox::No) { return; } } // // Delete all but first brain set // for (unsigned int i = 1; i < loadedBrainSets.size(); i++) { delete loadedBrainSets[i]; } BrainSet* bs = loadedBrainSets[0]; loadedBrainSets.clear(); loadedBrainSets.push_back(bs); // do not use addBrainSet because signals already hooked up for (int i = 0; i < BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS; i++) { setBrainSet(static_cast(i), bs); } } break; case 2: return; break; } } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); // // do not allow graphics updates while reading data files since the progress // dialog causes paintGL() calls with coordinate files only partially loaded. // GuiBrainModelOpenGL::setPaintingEnabled(false); const int numFiles = sf.getNumberOfSelectedFiles() + 2; QProgressDialog* progressDialog = NULL; progressDialog = new QProgressDialog( "Reading Spec File", "Cancel", 0, numFiles, this); if (progressDialog != NULL) { progressDialog->setWindowTitle("Reading Data Files"); progressDialog->show(); } std::vector messages; QTime timer; timer.start(); getBrainSet()->blockSignals(true); // so signal "signalBrainSetChanged()" is ignored const bool readingAborted = getBrainSet()->readSpecFile(BrainSet::SPEC_FILE_READ_MODE_NORMAL, sf, sf.getFileName(), messages, tm, progressDialog); getBrainSet()->blockSignals(false); // // Update directory path // for (unsigned int i = 0; i < loadedBrainSets.size(); i++) { if (loadedBrainSets[i] == getBrainSet()) { //loadedBrainSetDirectory[i] = QDir::currentPath(); break; } } if (readingAborted) { messages.clear(); getBrainSet()->reset(); } //if (DebugControl::getDebugOn()) { std::cout << "Time to read all files was " << (static_cast(timer.elapsed()) / 1000.0) << " seconds." << std::endl; // } if ((getBrainSet()->getNumberOfNodes() > 0) || (messages.size() == 0)) { addToRecentSpecFiles(sf.getFileName()); //filename); } if (progressDialog != NULL) { progressDialog->setValue(numFiles); delete progressDialog; } // // Updates since spec file changed // postSpecFileReadInitializations(); // // Turn off highlight crosses // for (int m = 0; m < getNumberOfBrainSets(); m++) { getBrainSet(static_cast(m))->setDisplayCrossForNode(-1, NULL); } if (messages.size() > 0) { QString qs(messages[0]); for (unsigned int j = 1; j < messages.size(); j++) { qs.append("\n"); qs.append(messages[j]); } QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "Error loading files from spec file", qs); return; } GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); speakText("The specification file has been loaded.", false); // // If only scene files are selected // if (sf.onlySceneFilesSelected()) { // // Show the display control dialog and its scene page // displayDisplayControlDialog(); displayControlDialog->showScenePage(); } static bool firstTipsFlag = true; if (firstTipsFlag) { firstTipsFlag = false; // // See if tips dialog should be displayed // int dummy; bool startupFlag; PreferencesFile* preferencesFile = getBrainSet()->getPreferencesFile(); preferencesFile->getCaretTips(dummy, startupFlag); if (startupFlag) { helpActions->helpMenuCaretTips(); QApplication::beep(); } } } /** * Make updates when spec file is changed. */ void GuiMainWindow::postSpecFileReadInitializations() { DisplaySettingsSurface* dsn = getBrainSet()->getDisplaySettingsSurface(); // // Draw as nodes if have coord files but no topo files // if (getBrainSet()->getNumberOfTopologyFiles() <= 0) { bool haveCoordFiles = false; for (int i = 0; i < getBrainSet()->getNumberOfBrainModels(); i++) { if (getBrainSet()->getBrainModelSurface(i) != NULL) { haveCoordFiles = true; } } if (haveCoordFiles) { dsn->setDrawMode(DisplaySettingsSurface::DRAW_MODE_NODES); } } QString title("CARET v"); title.append(CaretVersion::getCaretVersionAsString()); title.append(" ("); title.append(__DATE__); title.append(")"); setWindowTitle(title); title.append(" "); title.append(FileUtilities::basename(getBrainSet()->getSpecFileName())); //sf.getFileName())); setWindowTitle(title); GuiBrainModelOpenGL::setAllDisplayedBrainModelIndices(0); GuiFilesModified fm; fm.setStatusForAll(true); fileModificationUpdate(fm); GuiBrainModelOpenGL::setPaintingEnabled(true); GuiToolBar::clearAllYoking(); GuiToolBar::updateAllToolBars(true); getBrainSet()->setDisplaySplashImage(false); if (displayControlDialog != NULL) { displayControlDialog->newSpecFileLoaded(); } } /** * Create the status bar */ void GuiMainWindow::createStatusBar() { const int labelStyle = QFrame::Panel | QFrame::Sunken; statusBarMouseModeLabel = new QLabel; statusBarMouseModeLabel->setFrameStyle(labelStyle); statusBarMouseModeLabel->setToolTip( "current mouse mode"); statusBarSectionLowLabel = new QLabel; statusBarSectionLowLabel->setFrameStyle(labelStyle); statusBarSectionLowLabel->setToolTip( "lowest section number"); statusBarSectionHighLabel = new QLabel; statusBarSectionHighLabel->setFrameStyle(labelStyle); statusBarSectionHighLabel->setToolTip( "highest section number"); statusBarMouseLeftLabel = new QLabel; statusBarMouseLeftLabel->setFrameStyle(labelStyle); statusBarMouseLeftLabel->setToolTip( "mouse moved with left button down function"); statusBarMouseShiftLeftLabel = new QLabel; statusBarMouseShiftLeftLabel->setFrameStyle(labelStyle); statusBarMouseShiftLeftLabel->setToolTip( "mouse moved with shift and left button down function"); statusBarMouseCtrlLeftLabel = new QLabel; statusBarMouseCtrlLeftLabel->setFrameStyle(labelStyle); #ifdef Q_OS_MACX statusBarMouseCtrlLeftLabel->setToolTip( "mouse moved with control and left button down function"); #else statusBarMouseCtrlLeftLabel->setToolTip( "mouse moved with apple and left button down function"); #endif statusBarMouseAltLeftLabel = new QLabel; statusBarMouseAltLeftLabel->setFrameStyle(labelStyle); statusBarMouseAltLeftLabel->setToolTip("mouse moved with atl button down function"); statusBarMouseClickLeftLabel = new QLabel; statusBarMouseClickLeftLabel->setFrameStyle(labelStyle); statusBarMouseClickLeftLabel->setToolTip( "mouse left button click function"); QStatusBar* sb = statusBar(); sb->addWidget(statusBarMouseModeLabel); sb->addWidget(statusBarSectionLowLabel); sb->addWidget(statusBarSectionHighLabel); sb->addWidget(statusBarMouseLeftLabel); sb->addWidget(statusBarMouseShiftLeftLabel); sb->addWidget(statusBarMouseCtrlLeftLabel); sb->addWidget(statusBarMouseAltLeftLabel); sb->addWidget(statusBarMouseClickLeftLabel); sb->addWidget(new QWidget, 1000); updateStatusBarLabel(); } /** * Update the status bar */ void GuiMainWindow::updateStatusBarLabel() { //statusBar()->removeWidget(statusBarLabel); DisplaySettingsSection* dss = getBrainSet()->getDisplaySettingsSection(); statusBarSectionLowLabel->setHidden(true); statusBarSectionHighLabel->setHidden(true); SectionFile* sf = getBrainSet()->getSectionFile(); if (sf->getNumberOfColumns() > 0) { const int selectedColumn = dss->getSelectedDisplayColumn(-1, -1); if ((selectedColumn >= 0) && (selectedColumn < sf->getNumberOfColumns())) { const int minSection = dss->getMinimumSelectedSection(); const int maxSection = dss->getMaximumSelectedSection(); //statusBarSectionLowLabel->setHidden(false); //statusBarSectionHighLabel->setHidden(false); statusBarSectionLowLabel->setNum(minSection); statusBarSectionHighLabel->setNum(maxSection); } } QString modeLabel; QString leftLabel; QString ctrlLeftLabel; QString shiftLeftLabel; QString clickLeftLabel; QString altLeftLabel; switch(mainOpenGL->getMouseMode()) { case GuiBrainModelOpenGL::MOUSE_MODE_NONE: break; case GuiBrainModelOpenGL::MOUSE_MODE_BORDER_DRAW: modeLabel = "DRAW BORDER"; leftLabel = "Draw"; ctrlLeftLabel = "Augment"; altLeftLabel = "Rotate(3D)"; shiftLeftLabel = "Done"; break; case GuiBrainModelOpenGL::MOUSE_MODE_BORDER_DRAW_NEW: modeLabel = "DRAW BORDER"; leftLabel = "Draw"; ctrlLeftLabel = "Augment"; altLeftLabel = "Rotate(3D)"; shiftLeftLabel = "Done"; break; case GuiBrainModelOpenGL::MOUSE_MODE_BORDER_DELETE: modeLabel = "DELETE BORDER"; clickLeftLabel = "Delete Border"; break; case GuiBrainModelOpenGL::MOUSE_MODE_BORDER_DELETE_POINT: modeLabel = "DELETE BORDER"; clickLeftLabel = "Delete Border Point"; break; case GuiBrainModelOpenGL::MOUSE_MODE_VIEW: modeLabel = "VIEW"; leftLabel = "Rotate"; ctrlLeftLabel = "Zoom"; shiftLeftLabel = "Pan"; clickLeftLabel = "ID"; { BrainModelVolume* bmv = getBrainModelVolume(); if (bmv != NULL) { if (bmv->getSelectedAxis(0) == VolumeFile::VOLUME_AXIS_OBLIQUE) { shiftLeftLabel = ""; } else if (volumeActions->getTranformRotationChecked() == false) { leftLabel = ""; } } } break; case GuiBrainModelOpenGL::MOUSE_MODE_BORDER_INTERPOLATE: modeLabel = "BORDER INTERPOLATE"; leftLabel = "Choose Border 1"; shiftLeftLabel = "Choose Border 2"; break; case GuiBrainModelOpenGL::MOUSE_MODE_BORDER_INTERPOLATE_NEW: modeLabel = "BORDER INTERPOLATE"; leftLabel = "Choose Border 1"; shiftLeftLabel = "Choose Border 2"; break; case GuiBrainModelOpenGL::MOUSE_MODE_BORDER_MOVE_POINT: modeLabel = "MOVE BORDER POINT"; leftLabel = "Move Border Point"; break; case GuiBrainModelOpenGL::MOUSE_MODE_BORDER_REVERSE: modeLabel = "REVERSE BORDER"; clickLeftLabel = "Choose Border"; break; case GuiBrainModelOpenGL::MOUSE_MODE_BORDER_RENAME: modeLabel = "RENAME BORDER"; clickLeftLabel = "Choose Border"; break; case GuiBrainModelOpenGL::MOUSE_MODE_BORDER_UPDATE: modeLabel = "BORDER UPDATE"; leftLabel = "Draw Update"; shiftLeftLabel = "Done"; altLeftLabel = "Rotate(3D)"; break; case GuiBrainModelOpenGL::MOUSE_MODE_BORDER_UPDATE_NEW: modeLabel = "BORDER UPDATE"; leftLabel = "Draw Update"; shiftLeftLabel = "Done"; altLeftLabel = "Rotate(3D)"; break; case GuiBrainModelOpenGL::MOUSE_MODE_FOCI_DELETE: modeLabel = "DELETE FOCI"; clickLeftLabel = "Delete Focus"; break; case GuiBrainModelOpenGL::MOUSE_MODE_CELL_DELETE: modeLabel = "DELETE CELL"; clickLeftLabel = "Delete Cell"; break; case GuiBrainModelOpenGL::MOUSE_MODE_CUT_DRAW: modeLabel = "DRAW CUT"; leftLabel = "Draw"; shiftLeftLabel = "Done"; break; case GuiBrainModelOpenGL::MOUSE_MODE_CUT_DELETE: modeLabel = "DELETE CUT"; clickLeftLabel = "Delete Cut"; break; case GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_BORDER_SELECT: modeLabel = "Surface ROI"; clickLeftLabel = "Select Border"; break; case GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_PAINT_INDEX_SELECT: modeLabel = "Surface ROI"; clickLeftLabel = "Select Node To Get Paint"; break; case GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_METRIC_NODE_SELECT: modeLabel = "Surface ROI"; clickLeftLabel = "Select Node For Metric Query"; break; case GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_GEODESIC_NODE_SELECT: modeLabel = "Surface ROI"; clickLeftLabel = "Select Node For Geodesic Query"; break; case GuiBrainModelOpenGL::MOUSE_MODE_ALIGN_STANDARD_ORIENTATION: modeLabel = "Align to Std Orientation"; leftLabel = "Ventral Tip"; shiftLeftLabel = "Dorsal-Medial Tip"; break; case GuiBrainModelOpenGL::MOUSE_MODE_ALIGN_STANDARD_ORIENTATION_FULL_HEM_FLATTEN: modeLabel = "Set Central Sulcus Tips"; leftLabel = "Ventral Tip"; shiftLeftLabel = "Dorsal-Medial Tip"; break; case GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_SET_SCALE: modeLabel = "Contour Set Scale"; leftLabel = "Start Point"; shiftLeftLabel = "End Point"; break; case GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_DRAW: modeLabel = "Draw Contour"; leftLabel = "Draw the Contour"; shiftLeftLabel = "Close the Contour (Done)"; break; case GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_ALIGN: modeLabel = "Align Contour"; leftLabel = "Rotate"; ctrlLeftLabel = "Zoom"; shiftLeftLabel = "Pan"; break; case GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_ALIGN_REGION: modeLabel = "Contour Region"; leftLabel = "Delineate"; ctrlLeftLabel = "Move Mode"; shiftLeftLabel = "Clear"; break; case GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_POINT_MOVE: modeLabel = "Move Contour Point"; leftLabel = "Drag Contour Point"; break; case GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_POINT_DELETE: modeLabel = "Delete Contour Point"; clickLeftLabel = "Select Contour Point For Deletion"; break; case GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_DELETE: modeLabel = "Delete Contour"; clickLeftLabel = "Select Contour For Deletion"; break; case GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_REVERSE: modeLabel = "Reverse Contour"; clickLeftLabel = "Select Contour For Point Reversal"; break; case GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_MERGE: modeLabel = "Merge Contours"; leftLabel = "Connect Contour"; shiftLeftLabel = "To This Contour"; break; case GuiBrainModelOpenGL::MOUSE_MODE_CELL_ADD: modeLabel = "Add Cell"; clickLeftLabel = "Select Node for Cell Location"; break; case GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_CELL_ADD: modeLabel = "Add Contour Cell"; clickLeftLabel = "Click Cell Location"; break; case GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_CELL_DELETE: modeLabel = "DELETE CONTOUR CELL"; clickLeftLabel = "Delete Contour Cell"; break; case GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_CELL_MOVE: modeLabel = "MOVE CONTOUR CELL"; clickLeftLabel = "Move Contour Cell"; break; case GuiBrainModelOpenGL::MOUSE_MODE_VOLUME_SEGMENTATION_EDIT: modeLabel = "SEGMENTATION EDIT"; leftLabel = "Apply to Voxels"; break; case GuiBrainModelOpenGL::MOUSE_MODE_EDIT_ADD_NODE: modeLabel = "ADD NODE"; clickLeftLabel = "Add Node"; break; case GuiBrainModelOpenGL::MOUSE_MODE_EDIT_ADD_TILE: modeLabel = "ADD TILE"; clickLeftLabel = "Choose Three Nodes"; break; case GuiBrainModelOpenGL::MOUSE_MODE_EDIT_DELETE_TILE_BY_LINK: modeLabel = "DELETE TILE VIA LINK"; clickLeftLabel = "Choose Link"; break; case GuiBrainModelOpenGL::MOUSE_MODE_EDIT_DISCONNECT_NODE: modeLabel = "DISCONNECT NODE"; clickLeftLabel = "Disconnect Node"; break; case GuiBrainModelOpenGL::MOUSE_MODE_EDIT_MOVE_NODE: modeLabel = "MOVE NODE"; leftLabel = "Move Node"; break; case GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_SHAPE_NODE_SELECT: modeLabel = "Surface ROI"; clickLeftLabel = "Select Node For Shape Query"; break; case GuiBrainModelOpenGL::MOUSE_MODE_TRANSFORMATION_MATRIX_AXES: modeLabel = "TRANS AXES"; leftLabel = "Rotate"; shiftLeftLabel = "Pan"; ctrlLeftLabel = "Zoom"; break; case GuiBrainModelOpenGL::MOUSE_MODE_TRANSFORMATION_MATRIX_SET_TRANSLATE: modeLabel = "TRANS MATRIX"; leftLabel = "Set Translation"; break; case GuiBrainModelOpenGL::MOUSE_MODE_VOLUME_PAINT_EDIT: modeLabel = "PAINT EDIT"; leftLabel = "Apply to Voxels"; break; case GuiBrainModelOpenGL::MOUSE_MODE_IMAGE_SUBREGION: modeLabel = "CAPTURE IMAGE REGION"; leftLabel = "Select Region"; break; case GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_SULCAL_BORDER_NODE_START: modeLabel = "Surface Border ROI"; clickLeftLabel = "Select Start Node"; break; case GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_SULCAL_BORDER_NODE_END: modeLabel = "Surface Border ROI"; clickLeftLabel = "Select End Node"; break; } statusBarMouseModeLabel->setText(modeLabel); if (leftLabel.isEmpty() == false) { QString s("Left:"); s.append(leftLabel); statusBarMouseLeftLabel->setText(s); statusBarMouseLeftLabel->setHidden(false); } else { statusBarMouseLeftLabel->setHidden(true); } if (ctrlLeftLabel.isEmpty() == false) { #ifdef Q_OS_MACX QString s("Apple-Left:"); #else QString s("Ctrl-Left:"); #endif s.append(ctrlLeftLabel); statusBarMouseCtrlLeftLabel->setText(s); statusBarMouseCtrlLeftLabel->setHidden(false); } else { statusBarMouseCtrlLeftLabel->setHidden(true); } if (shiftLeftLabel.isEmpty() == false) { QString s("Shift-Left:"); s.append(shiftLeftLabel); statusBarMouseShiftLeftLabel->setText(s); statusBarMouseShiftLeftLabel->setHidden(false); } else { statusBarMouseShiftLeftLabel->setHidden(true); } if (altLeftLabel.isEmpty() == false) { QString s("Alt-Left:"); s.append(altLeftLabel); statusBarMouseAltLeftLabel->setText(s); statusBarMouseAltLeftLabel->setHidden(false); } else { statusBarMouseAltLeftLabel->setHidden(true); } if (clickLeftLabel.isEmpty() == false) { QString s("Click-Left:"); s.append(clickLeftLabel); statusBarMouseClickLeftLabel->setText(s); statusBarMouseClickLeftLabel->setHidden(false); } else { statusBarMouseClickLeftLabel->setHidden(true); } statusBar()->adjustSize(); statusBar()->updateGeometry(); statusBar()->adjustSize(); statusBar()->updateGeometry(); } /** * update the displayed menus based upon loaded contours/surface/volume in main window */ void GuiMainWindow::updateDisplayedMenus() { // menuBar()->setItemEnabled(surfaceMenuID, (getBrainModelSurface() != NULL)); // menuBar()->setItemEnabled(volumeMenuID, (getBrainModelVolume() != NULL) || // (getBrainModelSurfaceAndVolume() != NULL)); } /** * This method should be called when a file is changed or loaded. It will make any * necessary updates to the brain models and all user interface components. It will * not redraw any of the displays. */ void GuiMainWindow::fileModificationUpdate(const GuiFilesModified& fm) { for (int i = 0; i < getBrainSet()->getNumberOfSurfaceOverlays(); i++) { getBrainSet()->getSurfaceOverlay(i)->update(); } bool updateAddCellsDialog = false; bool updateAddContourCellsDialog = false; bool updateArealEstimation = false; bool updateBorders = false; bool updateBorderDisplayFlags = false; bool updateBorderColors = false; bool updateBorderProjections = false; bool updateCellDisplayFlags = false; bool updateCellColors = false; bool updateContourCellDisplayFlags = false; bool updateContourCellColors = false; bool updateCocomac = false; bool updateContours = false; bool updateCoordinates = false; bool updateDeformationMap = false; bool updateDeformationField = false; bool updateFociDisplayFlags = false; bool updateFoci = false; bool updateFociColors = false; bool updateFociSearch = false; bool updateGeodesic = false; bool updateImages = false; bool updateLatLon = false; bool updateMetrics = false; bool updateModels = false; bool updateNodeColoring = false; bool updatePaint = false; bool updateProbAtlas = false; bool updateRegion = false; bool updateRgbPaint = false; bool updateScene = false; bool updateSections = false; bool updateSurfaceShape = false; bool updateVector = false; bool updateStatusBar = false; bool updateStudyCollection = false; bool updateStudyMetaData = false; bool updateToolBar = false; bool updateTopography = false; bool updateTopology = false; bool updateTransformMatrices = false; bool updateTransformData = false; bool updateVocabulary = false; bool updateVolume = false; bool updateVolumeColoring = false; if (fm.areaColor) { updateNodeColoring = true; updateVolumeColoring = true; } if (fm.arealEstimation) { updateArealEstimation = true; updateNodeColoring = true; } if (fm.border) { updateBorders = true; updateBorderColors = true; updateBorderDisplayFlags = true; updateBorderProjections = true; } if (fm.borderColor) { updateBorderColors = true; updateBorderDisplayFlags = true; } if (fm.cell) { updateCellColors = true; updateCellDisplayFlags = true; updateAddCellsDialog = true; } if (fm.cellColor) { updateCellColors = true; updateCellDisplayFlags = true; } if (fm.cellProjection) { updateCellColors = true; updateCellDisplayFlags = true; } if (fm.cocomac) { updateCocomac = true; updateNodeColoring = true; } if (fm.contour) { updateContours = true; updateToolBar = true; } if (fm.contourCell) { updateContourCellDisplayFlags = true; updateAddContourCellsDialog = true; updateContourCellColors = true; } if (fm.contourCellColor) { updateContourCellDisplayFlags = true; updateContourCellColors = true; } if (fm.coordinate) { updateAddCellsDialog = true; updateAddContourCellsDialog = true; updateCoordinates = true; updateToolBar = true; updateBorderProjections = true; if (fm.inhibitDefaultSurfaceScaling == false) { double orthoLeft, orthoRight, orthoBottom, orthoTop, orthoNear, orthoFar; mainOpenGL->getOrthographicBox(orthoLeft, orthoRight, orthoBottom, orthoTop, orthoNear, orthoFar); getBrainSet()->setDefaultScaling(orthoRight, orthoTop); } } if (fm.cut) { } if (fm.deformationField) { updateDeformationField = true; } if (fm.deformationMap) { updateDeformationMap = true; } if (fm.foci) { updateFoci = true; updateFociColors = true; updateFociDisplayFlags = true; updateStudyMetaData = true; } if (fm.fociColor) { updateFociColors = true; updateFociDisplayFlags = true; } if (fm.fociProjection) { updateFociColors = true; updateFociDisplayFlags = true; updateStudyMetaData = true; } if (fm.fociSearch) { updateFociSearch = true; } if (fm.geodesic) { updateGeodesic = true; } if (fm.images) { updateImages = true; } if (fm.latLon) { updateLatLon = true; } if (fm.metric) { updateMetrics = true; updateNodeColoring = true; } if (fm.paint) { updatePaint = true; updateNodeColoring = true; } if (fm.palette) { updateMetrics = true; updateNodeColoring = true; updateSurfaceShape = true; updateVolumeColoring = true; if (paletteEditorDialog != NULL) { paletteEditorDialog->updateDialog(); } } if (fm.parameter) { if (paramsFileEditorDialog != NULL) { paramsFileEditorDialog->updateDialog(); } } if (fm.probabilisticAtlas) { updateProbAtlas = true; updateNodeColoring = true; } if (fm.rgbPaint) { updateNodeColoring = true; updateRgbPaint = true; } if (fm.scene) { updateScene = true; } if (fm.section) { updateSections = true; updateStatusBar = true; updateCellDisplayFlags = true; } if (fm.surfaceShape) { updateNodeColoring = true; updateSurfaceShape = true; } if (fm.vector) { updateVector = true; } if (fm.topography) { updateNodeColoring = true; updateTopography = true; } if (fm.topology) { updateBorderProjections = true; updateTopology = true; } if (fm.transformationMatrix) { updateTransformMatrices = true; updateVolume = true; } if (fm.transformationData) { updateFociColors = true; updateFociDisplayFlags = true; updateCellColors = true; updateCellDisplayFlags = true; updateTransformData = true; updateModels = true; } if (fm.studyCollection) { updateStudyCollection = true; } if (fm.studyMetaData) { updateFoci = true; updateFociColors = true; updateFociDisplayFlags = true; updateStudyCollection = true; updateStudyMetaData = true; } if (fm.vocabulary) { updateVocabulary = true; updateStudyMetaData = true; } if (fm.volume) { updateToolBar = true; updateVector = true; updateVolume = true; } if (fm.vtkModel) { updateModels = true; } if (fm.wustlRegion) { updateRegion = true; } if (updateCoordinates) { if (flatMorphingDialog != NULL) { flatMorphingDialog->updateDialog(); } if (sphereMorphingDialog != NULL) { sphereMorphingDialog->updateDialog(); } } if (updateCoordinates || updateMetrics) { if (metricModificationDialog != NULL) { metricModificationDialog->updateDialog(); } } if (updateBorderProjections) { // This should not be necessary but if it is re-enabled it will // cause all borders to be unmodified. //BrainModelBorderSet* bmbs = getBrainSet()->getBorderSet(); //bmbs->unprojectBordersForAllSurfaces(); } if (updateBorderColors) { getBrainSet()->assignBorderColors(); } if (updateBorders || updateBorderProjections || updateBorderColors || updateCoordinates || updatePaint || updateSurfaceShape || updateVolume) { if (borderOperationsDialog != NULL) { borderOperationsDialog->updateDialog(); } } if (updateBorders || updateBorderProjections || updateCoordinates || updatePaint || updateSurfaceShape) { if (flattenFullHemisphereDialog != NULL) { flattenFullHemisphereDialog->updateDialog(); } if (standardMeshDialog != NULL) { standardMeshDialog->updateDialog(); } } if (updateCellColors) { getBrainSet()->assignCellColors(); } if (updateContours) { if (contourAlignmentDialog != NULL) contourAlignmentDialog->updateDialog(); if (contourSectionControlDialog != NULL) contourSectionControlDialog->updateDialog(); if (contourSetScaleDialog != NULL) contourSetScaleDialog->updateDialog(); } if (updateContourCellColors) { getBrainSet()->assignContourCellColors(); } if (updateCoordinates || updateTopology) { if (interpolateSurfaceDialog != NULL) { interpolateSurfaceDialog->updateDialog(); } if (setTopologyDialog != NULL) { setTopologyDialog->updateDialog(); } } if (updateCoordinates || updateFoci || updatePaint || updateContours || updateVolume) { if (fociAttributeAssignmentDialog != NULL) { fociAttributeAssignmentDialog->updateDialog(); } } if (updateFoci) { if (mapStereotaxicFocusDialog != NULL) { mapStereotaxicFocusDialog->updateDialog(); } } if (updateFociColors) { getBrainSet()->assignFociColors(); } if (updateMetrics) { if (metricsToRgbPaintDialog != NULL) { metricsToRgbPaintDialog->updateDialog(); } if (metricMathDialog != NULL) { metricMathDialog->updateDialog(); } } if (updateNodeColoring) { getBrainSet()->getNodeColoring()->assignColors(); } if (updateNodeColoring) { if (paintNameEditorDialog != NULL) { paintNameEditorDialog->updateDialog(); } } if (updatePaint || updateVolume) { if (drawBorderDialog != NULL) { drawBorderDialog->updateDialog(); } } if (updateRgbPaint) { if (metricsToRgbPaintDialog != NULL) { metricsToRgbPaintDialog->updateDialog(); } } if (updateBorderDisplayFlags) { DisplaySettingsBorders* dsb = getBrainSet()->getDisplaySettingsBorders(); dsb->determineDisplayedBorders(); } if (updateCellDisplayFlags) { DisplaySettingsCells* dsc = getBrainSet()->getDisplaySettingsCells(); dsc->determineDisplayedCells(); } if (updateFociDisplayFlags) { DisplaySettingsFoci* dsf = getBrainSet()->getDisplaySettingsFoci(); dsf->determineDisplayedFoci(); } if (updateContourCellDisplayFlags) { DisplaySettingsContours* dsc = getBrainSet()->getDisplaySettingsContours(); dsc->determineDisplayedContourCells(); } if (updateAddCellsDialog) { if (addCellsDialog != NULL) { addCellsDialog->updateDialog(); } } if (updateAddContourCellsDialog) { if (addContourCellsDialog != NULL) { addContourCellsDialog->updateDialog(); } } if (updateImages) { const int num = getBrainSet()->getNumberOfImageFiles(); if (num <= 0) { removeAllImageViewingWindows(); if (imageEditorWindow != NULL) { imageEditorWindow->close(); } } else { for (unsigned int i = 0; i < imageViewingWindows.size(); i++) { imageViewingWindows[i]->updateWindow(); } if (imageEditorWindow != NULL) { imageEditorWindow->updateWindow(); } } } if (updateModels) { if (modelsEditorDialog != NULL) { modelsEditorDialog->updateDialog(); } } if (updateSections) { updateSectionControlDialog(); } if (updateStatusBar) { updateStatusBarLabel(); } if (updateSurfaceShape) { if (shapeModificationDialog != NULL) { shapeModificationDialog->updateDialog(); } if (shapeMathDialog != NULL) { shapeMathDialog->updateDialog(); } } if (updateStudyMetaData) { if (studyMetaDataFileEditorDialog != NULL) { studyMetaDataFileEditorDialog->updateDialog(); } } if (updateStudyCollection) { if (studyCollectionFileEditorDialog != NULL) { studyCollectionFileEditorDialog->updateDialog(); } } if (updateToolBar) { GuiToolBar::updateAllToolBars(true); updateDisplayedMenus(); } if (updateTransformMatrices || updateTransformData) { if (transformMatrixEditorDialog != NULL) { transformMatrixEditorDialog->updateDialog(); } } if (updateMetrics || updatePaint || updateSurfaceShape || updateBorders || updateBorderProjections || updateTopology || updateToolBar) { if (surfaceRegionOfInterestDialog != NULL) { surfaceRegionOfInterestDialog->updateDialog(); } if (surfaceRegionOfInterestDialogOLD != NULL) { surfaceRegionOfInterestDialogOLD->updateDialog(); } } if (updateVocabulary) { if (vocabularyFileEditorDialog != NULL) { vocabularyFileEditorDialog->updateDialog(); } } if (updateVolume) { if (volumeRegionOfInterestDialog != NULL) { volumeRegionOfInterestDialog->updateDialog(); } if (volumeThresholdSegmentationDialog != NULL) { volumeThresholdSegmentationDialog->updateDialog(); } } if (updateVolume) { if (volumeResizingDialog != NULL) { volumeResizingDialog->updateDialog(true); } if (volumeAttributesDialog != NULL) { volumeAttributesDialog->updateDialog(); } if (volumeMathDialog != NULL) { volumeMathDialog->updateDialog(); } if (volumePaintEditorDialog != NULL) { volumePaintEditorDialog->updateDialog(); } if (volumeSegmentationEditorDialog != NULL) { volumeSegmentationEditorDialog->updateDialog(); } } if (updateVolumeColoring) { BrainModelVolumeVoxelColoring* vvc = getBrainSet()->getVoxelColoring(); vvc->setVolumeFunctionalColoringInvalid(); vvc->setVolumePaintColoringInvalid(); vvc->setVolumeProbAtlasColoringInvalid(); } if (fm.getAllFilesModified()) { updateDisplayControlDialog(); } else { if (displayControlDialog != NULL) { if (updateArealEstimation) { // "updateOverlayUnderlayItems()" called below calls this //displayControlDialog->updateArealEstimationItems(); } if (updateBorderColors) { displayControlDialog->updateBorderItems(true); } if (updateCellColors) { displayControlDialog->updateCellItems(true); } if (updateCocomac || updatePaint) { displayControlDialog->updateCocomacItems(); } if (updateContours) { displayControlDialog->updateContourItems(true); } if (updateCoordinates) { displayControlDialog->updateMiscItems(); } if (updateDeformationField) { displayControlDialog->updateDeformationFieldPage(); } if (updateFociColors || updateFociSearch) { displayControlDialog->updateFociItems(true); } if (updateGeodesic) { displayControlDialog->updateGeodesicItems(); } if (updateImages) { displayControlDialog->updateImagesItems(); } if (updateLatLon) { displayControlDialog->updateLatLonItems(); } if (updateMetrics || updateVolume) { // "updateOverlayUnderlayItems()" called below calls this //displayControlDialog->updateMetricItems(); } if (updateModels || updateTransformMatrices) { displayControlDialog->updateModelItems(); } if (updatePaint) { // "updateOverlayUnderlayItems()" called below calls this //displayControlDialog->updatePaintItems(); } if (updateProbAtlas) { displayControlDialog->updateProbAtlasSurfaceItems(true); } if (updateScene) { displayControlDialog->updateSceneItems(); } if (updateRegion || updateVolume) { displayControlDialog->updateRegionItems(); } if (updateRgbPaint) { displayControlDialog->updateRgbPaintItems(); } if (updateSurfaceShape) { // "updateOverlayUnderlayItems()" called below calls this //displayControlDialog->updateShapeItems(); } if (updateVector) { displayControlDialog->updateVectorItems(); } if (updateTopography) { // "updateOverlayUnderlayItems()" called below calls this //displayControlDialog->updateTopographyItems(); } if (updateVolume || updateCoordinates) { displayControlDialog->updateSurfaceAndVolumeItems(); displayControlDialog->updateVolumeItems(); } displayControlDialog->updateOverlayUnderlayItemsNew(); } } GuiIdentifyDialog* idDialog = getIdentifyDialog(false); if (idDialog != NULL) { idDialog->updateDialog(); } if (connectivityDialog != NULL) { connectivityDialog->updateDialog(); } } /** * display a web page in the user's web browser. */ void GuiMainWindow::displayWebPage(const QString& webPage) { PreferencesFile* pf = getBrainSet()->getPreferencesFile(); const int returnCode = SystemUtilities::displayInWebBrowser(webPage, pf->getWebBrowser()); if (returnCode != 0) { QString msg("Loading the web page appears to have failed. Unix users may \n" "need to set the environment variable CARET_WEB_BROWSER to the\n" "desired web browser."); QMessageBox::warning(this, "Web Browser Error", msg); } } /** * update the transformation matrix Editor. */ void GuiMainWindow::updateTransformationMatrixEditor(const TransformationMatrix* tm) { if (transformMatrixEditorDialog != NULL) { transformMatrixEditorDialog->updateMatrixDisplay(tm); } } /** * display the tranformation editor dialog. */ void GuiMainWindow::displayTransformMatrixEditor() { if (transformMatrixEditorDialog == NULL) { transformMatrixEditorDialog = new GuiTransformationMatrixDialog(this); } transformMatrixEditorDialog->show(); transformMatrixEditorDialog->activateWindow(); } /** * display the params file editor dialog. */ void GuiMainWindow::displayParamsFileEditorDialog() { if (paramsFileEditorDialog == NULL) { paramsFileEditorDialog = new GuiParamsFileEditorDialog(this); } paramsFileEditorDialog->show(); paramsFileEditorDialog->activateWindow(); } /** * apply a scene (set display settings). */ void GuiMainWindow::showScene(const SceneFile::Scene* scene, const bool checkSpecFlag, QString& errorMessage) { //SceneFile* sf = getBrainSet()->getSceneFile(); //if ((sceneNumber < 0) || (sceneNumber >= sf->getNumberOfScenes())) { // return; //} //SceneFile::Scene* scene = sf->getScene(sceneNumber); // // Update the brain set // QString warningMessage; getBrainSet()->showScene(scene, checkSpecFlag, errorMessage, warningMessage); errorMessage += warningMessage; removeAllImageViewingWindows(); //removeAllModelViewingWindows(); // // Get screen size // QDesktopWidget* dt = QApplication::desktop(); const int screenMaxX = std::max(dt->width() - 200, dt->width() / 2); const int screenMaxY = std::max(dt->height() - 200, dt->height() / 2); const QString viewingWindowString("ViewingWindow"); //const int viewingWindowStringLength = viewingWindowString.length(); DisplaySettingsScene* dss = getBrainSet()->getDisplaySettingsScene(); const int screenMinX = 0; #ifdef Q_OS_MACX const int screenMinY = 20; #else // Q_OS_MACX const int screenMinY = 0; #endif // Q_OS_MACX int mainWindowSceneX = 10; int mainWindowSceneY = 10; int mainWindowX = 10; int mainWindowY = 10; int mainWindowSizeX = 400; int mainWindowSizeY = 400; for (int i = 0; i < BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS; i++) { QString msg; int geometry[4]; int glWidgetWidthHeight[2]; bool yokeFlag = false; BrainModel* bm = getBrainSet()->showSceneGetBrainModel(scene, i, geometry, glWidgetWidthHeight, yokeFlag, msg); if (bm != NULL) { if (i == 0) { // // Show the desired brain model in the main window // displayBrainModelInMainWindow(bm); // // If desired size of window is unknown, resize so graphics // is proper size // if (geometry[0] < 0) { geometry[0] = x(); geometry[1] = y(); const int deltaSizeX = glWidgetWidthHeight[0] - mainOpenGL->width(); const int deltaSizeY = glWidgetWidthHeight[1] - mainOpenGL->height(); geometry[2] = width() + deltaSizeX; geometry[3] = height() + deltaSizeY; } geometry[0] = std::min(geometry[0], screenMaxX); geometry[1] = std::min(geometry[1], screenMaxY); switch(dss->getWindowPositionPreference()) { case DisplaySettingsScene::WINDOW_POSITIONS_USE_ALL: geometry[0] = std::max(geometry[0], screenMinX); geometry[1] = std::max(geometry[1], screenMinY); move(geometry[0], geometry[1]); resize(geometry[2], geometry[3]); break; case DisplaySettingsScene::WINDOW_POSITIONS_IGNORE_MAIN_OTHERS_RELATIVE: resize(geometry[2], geometry[3]); break; case DisplaySettingsScene::WINDOW_POSITIONS_IGNORE_ALL: break; } mainWindowX = x(); mainWindowY = y(); mainWindowSceneX = geometry[0]; mainWindowSceneY = geometry[1]; mainWindowSizeX = geometry[2]; mainWindowSizeY = geometry[3]; } else { // // OpenGL for window // GuiBrainModelOpenGL* openGL = GuiBrainModelOpenGL::getBrainModelOpenGLForWindow( static_cast(i)); // // Create window if needed // GuiBrainModelViewingWindow* viewWindow = modelWindow[i]; if (viewWindow == NULL) { showViewingWindow(static_cast(i)); viewWindow = modelWindow[i]; } viewWindow->displayBrainModelInWindow(bm); if (openGL != NULL) { openGL->setYokeView(yokeFlag); } viewWindow->getToolBar()->setYokeStatus(yokeFlag); if (geometry[0] < 0) { geometry[0] = static_cast(mainWindowSceneX + 20.0); geometry[1] = static_cast(mainWindowSceneY + 20.0); if (i == 1) { geometry[0] = mainWindowSceneX + mainWindowSizeX; geometry[1] = mainWindowSceneY; } else if (i == 2) { geometry[0] = mainWindowSceneX; geometry[1] = mainWindowSceneY + mainWindowSizeY; } else if (i == 3) { geometry[0] = mainWindowSceneX + mainWindowSizeX; geometry[1] = mainWindowSceneY + mainWindowSizeY; } if (openGL != NULL) { const int deltaSizeX = glWidgetWidthHeight[0] - openGL->width(); const int deltaSizeY = glWidgetWidthHeight[1] - openGL->height(); geometry[2] = viewWindow->width() + deltaSizeX; geometry[3] = viewWindow->height() + deltaSizeY; } else { geometry[2] = 512; geometry[3] = 512; } } geometry[0] = std::min(geometry[0], screenMaxX); geometry[1] = std::min(geometry[1], screenMaxY); switch(dss->getWindowPositionPreference()) { case DisplaySettingsScene::WINDOW_POSITIONS_USE_ALL: geometry[0] = std::max(geometry[0], screenMinX); geometry[1] = std::max(geometry[1], screenMinY); viewWindow->move(geometry[0], geometry[1]); viewWindow->resize(geometry[2], geometry[3]); break; case DisplaySettingsScene::WINDOW_POSITIONS_IGNORE_MAIN_OTHERS_RELATIVE: geometry[0] = (geometry[0] - mainWindowSceneX) + mainWindowX; geometry[1] = (geometry[1] - mainWindowSceneY) + mainWindowY; geometry[0] = std::max(geometry[0], screenMinX); geometry[1] = std::max(geometry[1], screenMinY); viewWindow->move(geometry[0], geometry[1]); viewWindow->resize(geometry[2], geometry[3]); break; case DisplaySettingsScene::WINDOW_POSITIONS_IGNORE_ALL: break; } } } else if (i > 0) { if (modelWindow[i] != NULL) { modelWindow[i]->close(); qApp->processEvents(); } errorMessage.append(msg); } } // // Process identify dialog // GuiIdentifyDialog* id = getIdentifyDialog(false); id->showScene(*scene, mainWindowX, mainWindowY, mainWindowSceneX, mainWindowSceneY, screenMaxX, screenMaxY, errorMessage); id->updateDialog(); // // popup image viewing windows // const int numClasses = scene->getNumberOfSceneClasses(); for (int nc = 0; nc < numClasses; nc++) { const SceneFile::SceneClass* sc = scene->getSceneClass(nc); const QString className(sc->getName()); if (className == "ImageViewingWindow") { displayImageViewingWindow(); const int num = imageViewingWindows.size() - 1; if (num >= 0) { GuiImageViewingWindow* w = imageViewingWindows[num]; w->showScene(*sc); int x = w->x(); int y = w->y(); x = std::min(x, screenMaxX); y = std::min(y, screenMaxY); switch(dss->getWindowPositionPreference()) { case DisplaySettingsScene::WINDOW_POSITIONS_USE_ALL: w->move(x, y); break; case DisplaySettingsScene::WINDOW_POSITIONS_IGNORE_MAIN_OTHERS_RELATIVE: x = (x - mainWindowSceneX) + mainWindowX; y = (y - mainWindowSceneY) + mainWindowY; w->move(x, y); break; case DisplaySettingsScene::WINDOW_POSITIONS_IGNORE_ALL: break; } } } } // // Color Key Dialogs // showSceneColorKeyDialog(scene, screenMaxX, screenMaxY, mainWindowSceneX, mainWindowSceneY, mainWindowX, mainWindowY); // // Update GUI // GuiToolBar::updateAllToolBars(false); if (displayControlDialog != NULL) { displayControlDialog->showScene(*scene, errorMessage); displayControlDialog->updateAllItemsInDialog(true, true); updateSectionControlDialog(); } if (connectivityDialog != NULL) { connectivityDialog->updateDialog(); } GuiBrainModelOpenGL::updateAllGL(NULL); } /** * create a scene (read display settings). */ void GuiMainWindow::saveScene(std::vector& mainWindowSceneClasses) { for (int i = 0; i < BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS; i++) { if (i == 0) { BrainModel* bm = mainOpenGL->getDisplayedBrainModel(); if (bm != NULL) { //QRect geom = frameGeometry(); const int geometry[4] = { x(), //geom.left(), y(), //geom.top(), width(), //geom.width(), height() //geom.height() }; const int glWidgetWidthHeight[2] = { mainOpenGL->width(), mainOpenGL->height() }; SceneFile::SceneClass sc(""); getBrainSet()->saveSceneForBrainModelWindow(i, geometry, glWidgetWidthHeight, bm, false, sc); mainWindowSceneClasses.push_back(sc); } } else { GuiBrainModelViewingWindow* vw = modelWindow[i]; if (vw != NULL) { GuiBrainModelOpenGL* openGL = GuiBrainModelOpenGL::getBrainModelOpenGLForWindow( static_cast(i)); if (openGL != NULL) { BrainModel* bm = openGL->getDisplayedBrainModel(); if (bm != NULL) { //QRect geom = vw->frameGeometry(); const int geometry[4] = { vw->x(), //geom.left(), vw->y(), //geom.top(), vw->width(), //geom.width(), vw->height() //geom.height() }; const int glWidgetWidthHeight[2] = { openGL->width(), openGL->height() }; SceneFile::SceneClass sc(""); getBrainSet()->saveSceneForBrainModelWindow(i, geometry, glWidgetWidthHeight, bm, openGL->getYokeView(), sc); mainWindowSceneClasses.push_back(sc); } } } } } for (unsigned int i = 0; i < imageViewingWindows.size(); i++) { GuiImageViewingWindow* w = imageViewingWindows[i]; SceneFile::SceneClass sc = w->saveScene(); if (sc.getNumberOfSceneInfo() > 0) { mainWindowSceneClasses.push_back(sc); } } // // Save color key dialogs // saveSceneColorKeyDialog(mainWindowSceneClasses, arealEstimationColorKeyDialog); saveSceneColorKeyDialog(mainWindowSceneClasses, borderColorKeyDialog); saveSceneColorKeyDialog(mainWindowSceneClasses, cellColorKeyDialog); saveSceneColorKeyDialog(mainWindowSceneClasses, fociColorKeyDialog); saveSceneColorKeyDialog(mainWindowSceneClasses, paintColorKeyDialog); saveSceneColorKeyDialog(mainWindowSceneClasses, probAtlasColorKeyDialog); saveSceneColorKeyDialog(mainWindowSceneClasses, volumePaintColorKeyDialog); saveSceneColorKeyDialog(mainWindowSceneClasses, volumeProbAtlasColorKeyDialog); // // Process identify dialog // if (identifyDialog != NULL) { std::vector scs; identifyDialog->saveScene(scs); for (unsigned int i = 0; i < scs.size(); i++) { if (scs[i].getNumberOfSceneInfo() > 0) { mainWindowSceneClasses.push_back(scs[i]); } } } if (displayControlDialog != NULL) { std::vector dcSceneClasses = displayControlDialog->saveScene(); for (unsigned int i = 0; i < dcSceneClasses.size(); i++) { mainWindowSceneClasses.push_back(dcSceneClasses[i]); } } } /** * display the capture window as image dialog. */ void GuiMainWindow::displayCaptureWindowImageDialog() { if (captureWindowImageDialog == NULL) { captureWindowImageDialog = new GuiCaptureWindowImageDialog(this); QtUtilities::positionWindowOffOtherWindow(this, captureWindowImageDialog); } captureWindowImageDialog->show(); captureWindowImageDialog->activateWindow(); } /** * display an image viewing window. */ void GuiMainWindow::displayImageViewingWindow() { GuiImageViewingWindow* vw = new GuiImageViewingWindow(this); vw->show(); vw->activateWindow(); for (unsigned int i = 0; i < imageViewingWindows.size(); i++) { if (imageViewingWindows[i] == NULL) { imageViewingWindows[i] = vw; return; } } imageViewingWindows.push_back(vw); } /** * remove an image viewing window. */ void GuiMainWindow::removeImageViewingWindow(const GuiImageViewingWindow* ivw) { for (unsigned int i = 0; i < imageViewingWindows.size(); i++) { if (imageViewingWindows[i] == ivw) { imageViewingWindows.erase(imageViewingWindows.begin()+i); return; } } } /** * remove all image viewing windows. */ void GuiMainWindow::removeAllImageViewingWindows() { for (unsigned int i = 0; i < imageViewingWindows.size(); i++) { delete imageViewingWindows[i]; } imageViewingWindows.clear(); } /** * remove all model viewing windows. */ void GuiMainWindow::removeAllModelViewingWindows() { const int iStart = BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_2; const int iStop = BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS; for (int i = iStart; i < iStop; i++) { if (modelWindow[i] != NULL) { modelWindow[i]->close(); } } // // This allows the gui system to call the destructors for the windows // argument is the max time (in milliseconds) for the gui to use // qApp->processEvents(); } /** * display the set topology dialog. */ void GuiMainWindow::displaySetTopologyDialog() { if (setTopologyDialog == NULL) { setTopologyDialog = new GuiSetTopologyDialog(this); } setTopologyDialog->show(); setTopologyDialog->activateWindow(); } /** * display the image editor window. */ void GuiMainWindow::displayImageEditorWindow() { if (imageEditorWindow == NULL) { imageEditorWindow = new GuiImageEditorWindow(this); } imageEditorWindow->show(); imageEditorWindow->activateWindow(); } /** * display the border draw update dialog. */ void GuiMainWindow::displayBorderDrawUpdateDialog() { if (borderDrawUpdateDialog == NULL) { borderDrawUpdateDialog = new GuiBorderDrawUpdateDialog(this); } borderDrawUpdateDialog->show(); borderDrawUpdateDialog->activateWindow(); if (borderDrawUpdateDialog->getBorderUpdateMode() != BrainModelBorderSet::UPDATE_BORDER_MODE_NONE) { getBrainModelOpenGL()->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_BORDER_UPDATE); } } /** * save a color key dialog to a scene. */ void GuiMainWindow::saveSceneColorKeyDialog(std::vector& mainWindowSceneClasses, GuiColorKeyDialog* colorKeyDialog) { if (colorKeyDialog != NULL) { if (colorKeyDialog->isVisible()) { mainWindowSceneClasses.push_back(colorKeyDialog->saveScene()); } } } /** * load color key dialog from a scene. */ void GuiMainWindow::showSceneColorKeyDialog(const SceneFile::Scene* scene, const int screenMaxX, const int screenMaxY, const int mainWindowSceneX, const int mainWindowSceneY, const int mainWindowX, const int mainWindowY) { // // close all color key dialogs // if (arealEstimationColorKeyDialog != NULL) { arealEstimationColorKeyDialog->close(); } if (borderColorKeyDialog != NULL) { borderColorKeyDialog->close(); } if (cellColorKeyDialog != NULL) { cellColorKeyDialog->close(); } if (fociColorKeyDialog != NULL) { fociColorKeyDialog->close(); } if (paintColorKeyDialog != NULL) { paintColorKeyDialog->close(); } if (probAtlasColorKeyDialog != NULL) { probAtlasColorKeyDialog->close(); } if (volumePaintColorKeyDialog != NULL) { volumePaintColorKeyDialog->close(); } if (volumeProbAtlasColorKeyDialog != NULL) { volumeProbAtlasColorKeyDialog->close(); } const int numClasses = scene->getNumberOfSceneClasses(); for (int nc = 0; nc < numClasses; nc++) { const SceneFile::SceneClass* sc = scene->getSceneClass(nc); const QString className(sc->getName()); if (className.indexOf("Color Key") >= 0) { if (className == GuiColorKeyDialog::getTitleOfColorKey(GuiColorKeyDialog::COLOR_KEY_AREAL_ESTIMATION)) { displayArealEstimationColorKey(); arealEstimationColorKeyDialog->showScene(*sc, screenMaxX, screenMaxY, mainWindowSceneX, mainWindowSceneY, mainWindowX, mainWindowY); } else if (className == GuiColorKeyDialog::getTitleOfColorKey(GuiColorKeyDialog::COLOR_KEY_BORDERS)) { displayBorderColorKey(); borderColorKeyDialog->showScene(*sc, screenMaxX, screenMaxY, mainWindowSceneX, mainWindowSceneY, mainWindowX, mainWindowY); } else if (className == GuiColorKeyDialog::getTitleOfColorKey(GuiColorKeyDialog::COLOR_KEY_CELLS)) { displayCellColorKey(); cellColorKeyDialog->showScene(*sc, screenMaxX, screenMaxY, mainWindowSceneX, mainWindowSceneY, mainWindowX, mainWindowY); } else if (className == GuiColorKeyDialog::getTitleOfColorKey(GuiColorKeyDialog::COLOR_KEY_FOCI)) { displayFociColorKey(); fociColorKeyDialog->showScene(*sc, screenMaxX, screenMaxY, mainWindowSceneX, mainWindowSceneY, mainWindowX, mainWindowY); } else if (className == GuiColorKeyDialog::getTitleOfColorKey(GuiColorKeyDialog::COLOR_KEY_PAINT)) { displayPaintColorKey(); paintColorKeyDialog->showScene(*sc, screenMaxX, screenMaxY, mainWindowSceneX, mainWindowSceneY, mainWindowX, mainWindowY); } else if (className == GuiColorKeyDialog::getTitleOfColorKey(GuiColorKeyDialog::COLOR_KEY_PROBABILISTIC_ATLAS)) { displayProbabilisticAtlasColorKey(); probAtlasColorKeyDialog->showScene(*sc, screenMaxX, screenMaxY, mainWindowSceneX, mainWindowSceneY, mainWindowX, mainWindowY); } else if (className == GuiColorKeyDialog::getTitleOfColorKey(GuiColorKeyDialog::COLOR_KEY_VOLUME_PAINT)) { displayVolumePaintColorKey(); volumePaintColorKeyDialog->showScene(*sc, screenMaxX, screenMaxY, mainWindowSceneX, mainWindowSceneY, mainWindowX, mainWindowY); } else if (className == GuiColorKeyDialog::getTitleOfColorKey(GuiColorKeyDialog::COLOR_KEY_VOLUME_PROBABILISTIC_ATLAS)) { displayVolumeProbabilisticAtlasColorKey(); volumeProbAtlasColorKeyDialog->showScene(*sc, screenMaxX, screenMaxY, mainWindowSceneX, mainWindowSceneY, mainWindowX, mainWindowY); } } } } /** * display the areal estimation color key. */ void GuiMainWindow::displayArealEstimationColorKey() { if (arealEstimationColorKeyDialog == NULL) { arealEstimationColorKeyDialog = new GuiColorKeyDialog(this, GuiColorKeyDialog::COLOR_KEY_AREAL_ESTIMATION); } arealEstimationColorKeyDialog->updateDialog(); arealEstimationColorKeyDialog->show(); arealEstimationColorKeyDialog->activateWindow(); } /** * display the border color key. */ void GuiMainWindow::displayBorderColorKey() { if (borderColorKeyDialog == NULL) { borderColorKeyDialog = new GuiColorKeyDialog(this, GuiColorKeyDialog::COLOR_KEY_BORDERS); } borderColorKeyDialog->updateDialog(); borderColorKeyDialog->show(); borderColorKeyDialog->activateWindow(); } /** * display the cell color key. */ void GuiMainWindow::displayCellColorKey() { if (cellColorKeyDialog == NULL) { cellColorKeyDialog = new GuiColorKeyDialog(this, GuiColorKeyDialog::COLOR_KEY_CELLS); } cellColorKeyDialog->updateDialog(); cellColorKeyDialog->show(); cellColorKeyDialog->activateWindow(); } /** * display the foci color key. */ void GuiMainWindow::displayFociColorKey() { if (fociColorKeyDialog == NULL) { fociColorKeyDialog = new GuiColorKeyDialog(this, GuiColorKeyDialog::COLOR_KEY_FOCI); } fociColorKeyDialog->updateDialog(); fociColorKeyDialog->show(); fociColorKeyDialog->activateWindow(); } /** * display the paint color key. */ void GuiMainWindow::displayPaintColorKey() { if (paintColorKeyDialog == NULL) { paintColorKeyDialog = new GuiColorKeyDialog(this, GuiColorKeyDialog::COLOR_KEY_PAINT); } paintColorKeyDialog->updateDialog(); paintColorKeyDialog->show(); paintColorKeyDialog->activateWindow(); } /** * display the foci attribute assignment dialog. */ void GuiMainWindow::displayFociAttributeAssignmentDialog() { if (fociAttributeAssignmentDialog == NULL) { fociAttributeAssignmentDialog = new GuiCellAndFociAttributeAssignmentDialog(this, true); } fociAttributeAssignmentDialog->updateDialog(); fociAttributeAssignmentDialog->show(); fociAttributeAssignmentDialog->activateWindow(); } /** * display the probabilistic atlas color key. */ void GuiMainWindow::displayProbabilisticAtlasColorKey() { if (probAtlasColorKeyDialog == NULL) { probAtlasColorKeyDialog = new GuiColorKeyDialog(this, GuiColorKeyDialog::COLOR_KEY_PROBABILISTIC_ATLAS); } probAtlasColorKeyDialog->updateDialog(); probAtlasColorKeyDialog->show(); probAtlasColorKeyDialog->activateWindow(); } /** * display the volume paint color key. */ void GuiMainWindow::displayVolumePaintColorKey() { if (volumePaintColorKeyDialog == NULL) { volumePaintColorKeyDialog = new GuiColorKeyDialog(this, GuiColorKeyDialog::COLOR_KEY_VOLUME_PAINT); } volumePaintColorKeyDialog->updateDialog(); volumePaintColorKeyDialog->show(); volumePaintColorKeyDialog->activateWindow(); } /** * display the volume probabilistic atlas color key. */ void GuiMainWindow::displayVolumeProbabilisticAtlasColorKey() { if (volumeProbAtlasColorKeyDialog == NULL) { volumeProbAtlasColorKeyDialog = new GuiColorKeyDialog(this, GuiColorKeyDialog::COLOR_KEY_VOLUME_PROBABILISTIC_ATLAS); } volumeProbAtlasColorKeyDialog->updateDialog(); volumeProbAtlasColorKeyDialog->show(); volumeProbAtlasColorKeyDialog->activateWindow(); } /** * display the vocabulary editor dialog. */ void GuiMainWindow::displayVocabularyFileEditorDialog() { if (vocabularyFileEditorDialog == NULL) { vocabularyFileEditorDialog = new GuiVocabularyFileEditorDialog(this); } vocabularyFileEditorDialog->updateDialog(); vocabularyFileEditorDialog->show(); vocabularyFileEditorDialog->activateWindow(); } /** * display volume bias correction dialog. */ void GuiMainWindow::displayVolumeBiasCorrectionDialog() { if (volumeBiasCorrectionDialog == NULL) { volumeBiasCorrectionDialog = new GuiVolumeBiasCorrectionDialog(this); } volumeBiasCorrectionDialog->show(); volumeBiasCorrectionDialog->activateWindow(); } /** * identify a node provided by a remote program. */ void GuiMainWindow::identifyNodeFromRemoteProgram(const int nodeNumber) { BrainSet* bs = getBrainSet(BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW); // // Display cross at the node // bs->setDisplayCrossForNode(nodeNumber, NULL); // // Place a symbol at the node // BrainSetNodeAttribute* bna = bs->getNodeAttributes(nodeNumber); bna->setHighlighting(BrainSetNodeAttribute::HIGHLIGHT_NODE_REMOTE); // // Display identification information in the Identify Window // BrainModelIdentification* brainID = bs->getBrainModelIdentification(); const QString idString = brainID->getIdentificationTextForNode(bs, nodeNumber, true, true); if (idString.isEmpty() == false) { GuiIdentifyDialog* id = getIdentifyDialog(true); id->appendHtml(idString); } // // Redraw // GuiBrainModelOpenGL::updateAllGL(); } /** * redraw all windows using the brain set. */ void GuiMainWindow::slotRedrawWindowsUsingBrainSet(BrainSet* bs) { for (int i = 0; i < BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS; i++) { GuiBrainModelOpenGL* gl = mainOpenGL->getBrainModelOpenGLForWindow(static_cast(i)); if (gl != NULL) { if (gl->getBrainSet() == bs) { GuiBrainModelOpenGL::updateAllGL(gl); } } } } /** * Display the connectivity dialog. */ void GuiMainWindow::displayConnectivityDialog() { if (connectivityDialog == NULL) { connectivityDialog = new GuiConnectivityDialog(this); } connectivityDialog->show(); connectivityDialog->activateWindow(); } caret-5.6.4~dfsg.1.orig/caret/GuiMacOSXApplication.h0000664000175000017500000000353111572067322021755 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ /* * XpmApplication.h * appleevents * * Created by Trenton Schulz on 10/31/04. * Copyright 2004 Trolltech AS. All rights reserved. * */ #ifndef __GUI_MAC_OSX_APPLICATION_H__ #define __GUI_MAC_OSX_APPLICATION_H__ #include #ifdef Q_OS_MACX #include class GuiMainWindow; /// This class allows the Mac OSX version of Caret to get the open file event /// that occurs when a ".spec" file is double clicked. class GuiMacOSXApplication : public QApplication { Q_OBJECT public: // constructor GuiMacOSXApplication(int argc, char *argv[]); // destructor ~GuiMacOSXApplication(); // set the main window that is to get the open event void setGuiMainWindow(GuiMainWindow *mw); protected: // handle events bool event(QEvent *ev); // main window that is to get open event GuiMainWindow *caretMainWindow; }; #endif // Q_OS_MACX #endif // __GUI_MAC_OSX_APPLICATION_H__ caret-5.6.4~dfsg.1.orig/caret/GuiMacOSXApplication.cxx0000664000175000017500000000420611572067322022330 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ /* * XpmApplication.cpp * appleevents * * Created by Trenton Schulz on 10/31/04. * Copyright 2004 Trolltech AS. All rights reserved. * */ #include #ifdef Q_OS_MACX #include #include #include #include "GuiMacOSXApplication.h" #include "GuiMainWindow.h" /** * Constructor */ GuiMacOSXApplication::GuiMacOSXApplication(int argc, char *argv[]) : QApplication(argc, argv), caretMainWindow(0) { } /** * Destructor */ GuiMacOSXApplication::~GuiMacOSXApplication() { } /** * handle the custom event */ bool GuiMacOSXApplication::event(QEvent* event) { switch (event->type()) { case QEvent::FileOpen: { QFileOpenEvent* foe = static_cast(event); if (foe != NULL) { const QString fileName(foe->file()); if (caretMainWindow != NULL) { caretMainWindow->readSpecFile(fileName); } } return true; } break; default: return QApplication::event(event); break; } } /** * set the main window that is to get the open event */ void GuiMacOSXApplication::setGuiMainWindow(GuiMainWindow *mw) { caretMainWindow = mw; } #endif // Q_OS_MACX caret-5.6.4~dfsg.1.orig/caret/GuiLoadedFileManagementDialog.h0000664000175000017500000001675111572067322023614 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_LOADED_FILE_MANAGEMENT_DIALOG_H__ #define __GUI_LOADED_FILE_MANAGEMENT_DIALOG_H__ #include #include "WuQDialog.h" #include "BorderProjectionFile.h" #include "BrainModelSurface.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "SpecFile.h" class AbstractFile; class BrainModelBorderFileInfo; class BrainModelBorderSet; class QButtonGroup; class QCheckBox; class QGridLayout; class QLineEdit; class QToolButton; class VolumeFile; /// Dialog to manage loaded files class GuiLoadedFileManagementDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiLoadedFileManagementDialog(QWidget* parent); /// Destructor ~GuiLoadedFileManagementDialog(); private slots: /// called when an info button is pressed void slotInfoButtonGroup(int item); /// called when a save button is pressed void slotSaveButtonGroup(int item); /// called when a view button is pressed void slotViewButtonGroup(int item); /// called when an border info button is pressed void slotBorderInfoButtonGroup(int item); /// called when a remove file button is pressed void slotRemoveFileButtonGroup(int item); /// called when a remove file column button is pressed void slotRemoveFileColumnButtonGroup(int item); /// called when a clear file column button is pressed void slotClearFileColumnButtonGroup(int item); /// called to delete border projections void slotDeleteBorderProjections(); /// called to save border projections void slotSaveBorderProjections(); /// save all checked files void slotSaveAllCheckFiles(); private: /// class for storing data file and pointers to its labels class DataFile { public: /// constructor DataFile(AbstractFile* dataFileIn, GuiFilesModified dataFileTypeMaskIn, QWidget* fileTypeCheckBoxOrLabelIn, QLineEdit* nameLineEditIn, QLabel* modifiedLabelIn, const QString& specFileTagIn); /// destructor ~DataFile(); /// set modified void setModified(); /// clear modified void clearModified(); /// save the file if it is checked QString saveFileIfChecked(); /// the data file AbstractFile* dataFile; /// file type checkbox or label QWidget* fileTypeCheckBoxOrLabel; /// name line edit QLineEdit* nameLineEdit; /// data file type mask GuiFilesModified dataFileTypeMask; /// modified label QLabel* modifiedLabel; /// the spec file tag QString specFileTag; }; /// add a file to the list of files void addFileToGrid(AbstractFile* af, const GuiFilesModified& fileMask, const char* typeName, const QString& specFileTagIn); /// add a file to the list of files void addFileToGrid(AbstractFile* af, const GuiFilesModified& fileMask, const SpecFile::Entry& dataFileInfo, const char* typeName, const QString& specFileTagIn); /// add a border file to the list of files void addBorderFileToGrid(BrainModelBorderSet* bmbs, const BrainModelSurface::SURFACE_TYPES surfaceType, const char* typeName, const QString& specFileTagIn); /// Add a border projection file to the grid. void addBorderProjectionFileToGrid(BrainModelBorderSet* bmbs); /// widget that contains files QWidget* fileGridWidget; /// layout for files QGridLayout* fileGridLayout; /// view button group QButtonGroup* viewButtonGroup; /// save button group QButtonGroup* saveButtonGroup; /// info button group QButtonGroup* infoButtonGroup; /// remove file button group QButtonGroup* removeFileButtonGroup; /// remove file column button group QButtonGroup* removeFileColumnButtonGroup; /// clear file column button group QButtonGroup* clearFileColumnButtonGroup; /// border info button group QButtonGroup* borderInfoButtonGroup; /// pointers to files std::vector dataFiles; /// pointers to border file info std::vector borderInfoFileInfo; /// border projection info button QToolButton* borderProjInfoPB; /// border projection clear button QToolButton* borderProjClearPB; /// border projection save button QToolButton* borderProjSavePB; /// border projection file index int borderProjectionDataFileIndex; /// column for file type int columnFileTypeIndex; /// column for modified int columnModifiedIndex; /// column for view file int columnViewFileIndex; /// column for save file int columnSaveFileIndex; /// column for comment info int columnCommentIndex; /// column for remove file int columnRemoveFileIndex; /// column for remove column int columnRemoveFileColumnIndex; /// column for clear file column int columnClearFileColumnIndex; /// column for file name int columnFileNameIndex; /// width of view/clear/info buttons int buttonWidth; /// text for remove file button QString removeFilePushButtonText; /// text for remove file column button QString removeFileColumnPushButtonText; /// text for clear file column button QString clearFileColumnPushButtonText; /// text for view file button QString viewFilePushButtonText; /// text for comment/header button QString commentHeaderPushButtonText; /// text for save file button QString saveFilePushButtonText; /// border projection file BorderProjectionFile borderProjectionFileForGrid; }; #endif // __GUI_LOADED_FILE_MANAGEMENT_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiLoadedFileManagementDialog.cxx0000664000175000017500000016624411572067322024172 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "AreaColorFile.h" #include "ArealEstimationFile.h" #include "BorderColorFile.h" #include "BorderFile.h" #include "BorderProjectionFile.h" #include "BrainModelBorderSet.h" #include "BrainModelContours.h" #include "BrainModelSurface.h" #include "BrainSet.h" #include "CellColorFile.h" #include "CellFile.h" #include "CellProjectionFile.h" #include "CocomacConnectivityFile.h" #include "CommaSeparatedValueFile.h" #include "ContourCellFile.h" #include "ContourCellColorFile.h" #include "CutsFile.h" #include "DeformationFieldFile.h" #include "DeformationMapFile.h" #include "DisplaySettingsArealEstimation.h" #include "DisplaySettingsDeformationField.h" #include "DisplaySettingsGeodesicDistance.h" #include "DisplaySettingsMetric.h" #include "DisplaySettingsPaint.h" #include "DisplaySettingsRgbPaint.h" #include "DisplaySettingsSection.h" #include "DisplaySettingsSurfaceShape.h" #include "DisplaySettingsVectors.h" #include "DisplaySettingsTopography.h" #include "FileFilters.h" #include "FileUtilities.h" #include "FociColorFile.h" #include "FociFile.h" #include "FociProjectionFile.h" #include "FociSearchFile.h" #include "GeodesicDistanceFile.h" #include "GuiBrainModelOpenGL.h" #include "GuiCommaSeparatedValueFileEditor.h" #include "GuiDataFileCommentDialog.h" #include "GuiDataFileSaveDialog.h" #include "GuiFilesModified.h" #include "GuiLoadedFileManagementDialog.h" #include "ImageFile.h" #include "LatLonFile.h" #include "MetricFile.h" #include "PaintFile.h" #include "PaletteFile.h" #include "ParamsFile.h" #include "ProbabilisticAtlasFile.h" #include "RgbPaintFile.h" #include "SceneFile.h" #include "SectionFile.h" #include "StudyCollectionFile.h" #include "StudyMetaDataFile.h" #include "SurfaceShapeFile.h" #include "VectorFile.h" #include "TopographyFile.h" #include "TopologyFile.h" #include "VocabularyFile.h" #include "VolumeFile.h" #include "VtkModelFile.h" #include "WuQDataEntryDialog.h" #include "WustlRegionFile.h" #include "global_variables.h" // text for modified file label static const QString modifiedFileLabelText = "***"; /** * Constructor */ GuiLoadedFileManagementDialog::GuiLoadedFileManagementDialog(QWidget* parent) : WuQDialog(parent) { setAttribute(Qt::WA_DeleteOnClose); QString captionStr("Manage Loaded Files"); const QString specFileName = theMainWindow->getBrainSet()->getSpecFileName(); if (specFileName.isEmpty() == false) { captionStr.append(": "); captionStr.append(FileUtilities::basename(specFileName)); } setWindowTitle(captionStr); const SpecFile* sf = theMainWindow->getBrainSet()->getLoadedFilesSpecFile(); GuiFilesModified fm; // // Text for various file widgets // removeFilePushButtonText = "XF"; removeFileColumnPushButtonText = "XC"; clearFileColumnPushButtonText = "CC"; viewFilePushButtonText = "V"; commentHeaderPushButtonText = "Edit"; saveFilePushButtonText = "Save"; // // Layout indices // int numCols = 0; columnFileTypeIndex = numCols++; columnModifiedIndex = numCols++; columnSaveFileIndex = numCols++; columnViewFileIndex = numCols++; columnCommentIndex = numCols++; columnRemoveFileIndex = numCols++; columnRemoveFileColumnIndex = numCols++; columnClearFileColumnIndex = numCols++; columnFileNameIndex = numCols++; // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // widget for files widget since there could be many files // fileGridWidget = new QWidget; fileGridLayout = new QGridLayout(fileGridWidget); fileGridLayout->setHorizontalSpacing(10); fileGridLayout->setVerticalSpacing(2); fileGridLayout->setColumnStretch(columnFileNameIndex, 1000); // QVBox* vbox = new QVBox(sv, "vbox"); // prevents background from showing through //fileGrid = new QGrid(2, Qt::Horizontal, vbox, "fileGrid"); //sv->addChild(vbox); // // Button group for data files view push button // viewButtonGroup = new QButtonGroup(this); QObject::connect(viewButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotViewButtonGroup(int))); // // Button group for data files save push button // saveButtonGroup = new QButtonGroup(this); QObject::connect(saveButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotSaveButtonGroup(int))); // // Button group for data files Comment Header push button // infoButtonGroup = new QButtonGroup(this); QObject::connect(infoButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotInfoButtonGroup(int))); // // Button group for border files comment/header edit push button // borderInfoButtonGroup = new QButtonGroup(this); QObject::connect(borderInfoButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotBorderInfoButtonGroup(int))); // // Remove File button group for data files "XF" push button // removeFileButtonGroup = new QButtonGroup(this); QObject::connect(removeFileButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotRemoveFileButtonGroup(int))); // // Remove File Column button group for data files "XC" push button // removeFileColumnButtonGroup = new QButtonGroup(this); QObject::connect(removeFileColumnButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotRemoveFileColumnButtonGroup(int))); // // Clear File Column button group for data files "CC" push button // clearFileColumnButtonGroup = new QButtonGroup(this); QObject::connect(clearFileColumnButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotClearFileColumnButtonGroup(int))); // // column labels // fileGridLayout->addWidget(new QLabel("File Type"), 1, columnFileTypeIndex); fileGridLayout->addWidget(new QLabel(" Mod "), 0, columnModifiedIndex, Qt::AlignHCenter); fileGridLayout->addWidget(new QLabel("Save"), 0, columnSaveFileIndex, Qt::AlignHCenter); fileGridLayout->addWidget(new QLabel("File"), 1, columnSaveFileIndex, Qt::AlignHCenter); fileGridLayout->addWidget(new QLabel("View"), 0, columnViewFileIndex, Qt::AlignHCenter); fileGridLayout->addWidget(new QLabel("Comment"), 0, columnCommentIndex, Qt::AlignHCenter); fileGridLayout->addWidget(new QLabel("Header"), 1, columnCommentIndex, Qt::AlignHCenter); fileGridLayout->addWidget(new QLabel("Remove"), 0, columnRemoveFileIndex, Qt::AlignHCenter); fileGridLayout->addWidget(new QLabel("File"), 1, columnRemoveFileIndex, Qt::AlignHCenter); fileGridLayout->addWidget(new QLabel("Remove"), 0, columnRemoveFileColumnIndex, Qt::AlignHCenter); fileGridLayout->addWidget(new QLabel("Column"), 1, columnRemoveFileColumnIndex, Qt::AlignHCenter); fileGridLayout->addWidget(new QLabel("Clear"), 0, columnClearFileColumnIndex, Qt::AlignHCenter); fileGridLayout->addWidget(new QLabel("Column"), 1, columnClearFileColumnIndex, Qt::AlignHCenter); fileGridLayout->addWidget(new QLabel("File Name"), 1, columnFileNameIndex, Qt::AlignLeft); fm.setStatusForAll(false); fm.setAreaColorModified(); addFileToGrid(theMainWindow->getBrainSet()->getAreaColorFile(), fm, sf->areaColorFile, "Area Color File", SpecFile::getAreaColorFileTag()); fm.setStatusForAll(false); fm.setArealEstimationModified(); addFileToGrid(theMainWindow->getBrainSet()->getArealEstimationFile(), fm, sf->arealEstimationFile, "Areal Estimation File", SpecFile::getArealEstimationFileTag()); BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); addBorderFileToGrid(bmbs, BrainModelSurface::SURFACE_TYPE_RAW, "Border - Raw", SpecFile::getRawBorderFileTag()); addBorderFileToGrid(bmbs, BrainModelSurface::SURFACE_TYPE_FIDUCIAL, "Border - Fiducial", SpecFile::getFiducialBorderFileTag()); addBorderFileToGrid(bmbs, BrainModelSurface::SURFACE_TYPE_INFLATED, "Border - Inflated", SpecFile::getInflatedBorderFileTag()); addBorderFileToGrid(bmbs, BrainModelSurface::SURFACE_TYPE_VERY_INFLATED, "Border - Very Inflated", SpecFile::getVeryInflatedBorderFileTag()); addBorderFileToGrid(bmbs, BrainModelSurface::SURFACE_TYPE_SPHERICAL, "Border - Spherical", SpecFile::getSphericalBorderFileTag()); addBorderFileToGrid(bmbs, BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL, "Border - Ellipsoid", SpecFile::getEllipsoidBorderFileTag()); addBorderFileToGrid(bmbs, BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL, "Border - Comp Med Wall", SpecFile::getCompressedBorderFileTag()); addBorderFileToGrid(bmbs, BrainModelSurface::SURFACE_TYPE_FLAT, "Border - Flat", SpecFile::getFlatBorderFileTag()); addBorderFileToGrid(bmbs, BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR, "Border - Flat Lobar", SpecFile::getLobarFlatBorderFileTag()); addBorderFileToGrid(bmbs, BrainModelSurface::SURFACE_TYPE_UNKNOWN, "Border - Unknown", SpecFile::getUnknownBorderFileMatchTag()); fm.setStatusForAll(false); fm.setBorderColorModified(); addFileToGrid(theMainWindow->getBrainSet()->getBorderColorFile(), fm, "Border Color File", SpecFile::getBorderColorFileTag()); addBorderProjectionFileToGrid(bmbs); fm.setStatusForAll(false); fm.setCellColorModified(); addFileToGrid(theMainWindow->getBrainSet()->getCellColorFile(), fm, sf->cellColorFile, "Cell Color File", SpecFile::getCellColorFileTag()); fm.setStatusForAll(false); fm.setCellProjectionModified(); addFileToGrid(theMainWindow->getBrainSet()->getCellProjectionFile(), fm, sf->cellProjectionFile, "", SpecFile::getCellProjectionFileTag()); fm.setStatusForAll(false); fm.setCellModified(); addFileToGrid(theMainWindow->getBrainSet()->getVolumeCellFile(), fm, sf->volumeCellFile, "Cell File (Volume)", SpecFile::getVolumeCellFileTag()); fm.setStatusForAll(false); fm.setCocomacModified(); addFileToGrid(theMainWindow->getBrainSet()->getCocomacFile(), fm, sf->cocomacConnectivityFile, "", SpecFile::getCocomacConnectivityFileTag()); fm.setStatusForAll(false); fm.setContourCellModified(); addFileToGrid(theMainWindow->getBrainSet()->getContourCellFile(), fm, sf->contourCellFile, "Contour Cells File", SpecFile::getContourCellFileTag()); fm.setStatusForAll(false); fm.setCellColorModified(); addFileToGrid(theMainWindow->getBrainSet()->getContourCellColorFile(), fm, sf->contourCellColorFile, "Contour Cell Color File", SpecFile::getContourCellColorFileTag()); for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfBrainModels(); i++) { BrainModel* bm = theMainWindow->getBrainSet()->getBrainModel(i); switch(bm->getModelType()) { case BrainModel::BRAIN_MODEL_CONTOURS: { BrainModelContours* bmc = dynamic_cast(bm); ContourFile* cf = bmc->getContourFile(); fm.setStatusForAll(false); fm.setContourModified(); addFileToGrid(cf, fm, "", SpecFile::getContourFileTag()); } break; case BrainModel::BRAIN_MODEL_SURFACE: { BrainModelSurface* bms = dynamic_cast(bm); CoordinateFile* cf = bms->getCoordinateFile(); fm.setStatusForAll(false); fm.setCoordinateModified(); addFileToGrid(cf, fm, "", BrainModelSurface::getCoordSpecFileTagFromSurfaceType( bms->getSurfaceType())); } break; case BrainModel::BRAIN_MODEL_VOLUME: break; case BrainModel::BRAIN_MODEL_SURFACE_AND_VOLUME: break; } } fm.setStatusForAll(false); fm.setCutModified(); addFileToGrid(theMainWindow->getBrainSet()->getCutsFile(), fm, sf->cutsFile, "Cuts File", SpecFile::getCutsFileTag()); fm.setStatusForAll(false); fm.setDeformationFieldModified(); addFileToGrid(theMainWindow->getBrainSet()->getDeformationFieldFile(), fm, sf->deformationFieldFile, "Deformation Field File", SpecFile::getDeformationFieldFileTag()); fm.setStatusForAll(false); fm.setFociColorModified(); addFileToGrid(theMainWindow->getBrainSet()->getFociColorFile(), fm, sf->fociColorFile, "Foci Color File", SpecFile::getFociColorFileTag()); fm.setStatusForAll(false); fm.setFociProjectionModified(); addFileToGrid(theMainWindow->getBrainSet()->getFociProjectionFile(), fm, sf->fociProjectionFile, "Foci Projection File", SpecFile::getFociProjectionFileTag()); fm.setStatusForAll(false); fm.setFociSearchModified(); addFileToGrid(theMainWindow->getBrainSet()->getFociSearchFile(), fm, sf->fociSearchFile, "Foci Search File", SpecFile::getFociSearchFileTag()); fm.setStatusForAll(false); fm.setGeodesicModified(); addFileToGrid(theMainWindow->getBrainSet()->getGeodesicDistanceFile(), fm, sf->geodesicDistanceFile, "", SpecFile::getGeodesicDistanceFileTag()); for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfImageFiles(); i++) { fm.setStatusForAll(false); fm.setImagesModified(); addFileToGrid(theMainWindow->getBrainSet()->getImageFile(i), fm, "", SpecFile::getImageFileTag()); } fm.setStatusForAll(false); fm.setLatLonModified(); addFileToGrid(theMainWindow->getBrainSet()->getLatLonFile(), fm, sf->latLonFile, "", SpecFile::getLatLonFileTag()); fm.setStatusForAll(false); fm.setMetricModified(); addFileToGrid(theMainWindow->getBrainSet()->getMetricFile(), fm, sf->metricFile, "", SpecFile::getMetricFileTag()); fm.setStatusForAll(false); fm.setPaintModified(); addFileToGrid(theMainWindow->getBrainSet()->getPaintFile(), fm, sf->paintFile, "", SpecFile::getPaintFileTag()); fm.setStatusForAll(false); fm.setParameterModified(); addFileToGrid(theMainWindow->getBrainSet()->getParamsFile(), fm, sf->paramsFile, "", SpecFile::getParamsFileTag()); fm.setStatusForAll(false); fm.setProbabilisticAtlasModified(); addFileToGrid(theMainWindow->getBrainSet()->getProbabilisticAtlasSurfaceFile(), fm, sf->atlasFile, "Probabilistic Atlas File", SpecFile::getAtlasFileTag()); fm.setStatusForAll(false); fm.setPaletteModified(); addFileToGrid(theMainWindow->getBrainSet()->getPaletteFile(), fm, sf->paletteFile, "", SpecFile::getPaletteFileTag()); fm.setStatusForAll(false); fm.setRgbPaintModified(); addFileToGrid(theMainWindow->getBrainSet()->getRgbPaintFile(), fm, sf->rgbPaintFile, "", SpecFile::getRgbPaintFileTag()); fm.setStatusForAll(false); fm.setSectionModified(); addFileToGrid(theMainWindow->getBrainSet()->getSectionFile(), fm, sf->sectionFile, "", SpecFile::getSectionFileTag()); fm.setStatusForAll(false); fm.setSceneModified(); addFileToGrid(theMainWindow->getBrainSet()->getSceneFile(), fm, sf->sceneFile, "", SpecFile::getSceneFileTag()); fm.setStatusForAll(false); fm.setStudyCollectionModified(); addFileToGrid(theMainWindow->getBrainSet()->getStudyCollectionFile(), fm, sf->studyCollectionFile, "", SpecFile::getStudyCollectionFileTag()); fm.setStatusForAll(false); fm.setStudyMetaDataModified(); addFileToGrid(theMainWindow->getBrainSet()->getStudyMetaDataFile(), fm, sf->studyMetaDataFile, "", SpecFile::getStudyMetaDataFileTag()); fm.setStatusForAll(false); fm.setSurfaceShapeModified(); addFileToGrid(theMainWindow->getBrainSet()->getSurfaceShapeFile(), fm, sf->surfaceShapeFile, "Surface Shape File", SpecFile::getSurfaceShapeFileTag()); for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfVectorFiles(); i++) { fm.setStatusForAll(false); fm.setVectorModified(); addFileToGrid(theMainWindow->getBrainSet()->getVectorFile(i), fm, sf->vectorFile, "Vector File", SpecFile::getVectorFileTag()); } fm.setStatusForAll(false); fm.setTopographyModified(); addFileToGrid(theMainWindow->getBrainSet()->getTopographyFile(), fm, "", SpecFile::getTopographyFileTag()); for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfTopologyFiles(); i++) { TopologyFile* tf = theMainWindow->getBrainSet()->getTopologyFile(i); fm.setStatusForAll(false); fm.setTopologyModified(); addFileToGrid(tf, fm, "", TopologyFile::getSpecFileTagFromTopologyType( tf->getTopologyType())); } for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfTransformationDataFiles(); i++) { AbstractFile* tdf = theMainWindow->getBrainSet()->getTransformationDataFile(i); fm.setStatusForAll(false); fm.setTransformationDataModified(); addFileToGrid(tdf, fm, "Transformation Data File", SpecFile::getTransformationDataFileTag()); } fm.setStatusForAll(false); fm.setTransformationMatrixModified(); addFileToGrid(theMainWindow->getBrainSet()->getTransformationMatrixFile(), fm, sf->transformationMatrixFile, "Transformation Matrix File", SpecFile::getTransformationMatrixFileTag()); fm.setStatusForAll(false); fm.setVocabularyModified(); addFileToGrid(theMainWindow->getBrainSet()->getVocabularyFile(), fm, sf->vocabularyFile, "Vocabulary File", SpecFile::getVocabularyFileTag()); for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfVolumeAnatomyFiles(); i++) { fm.setStatusForAll(false); fm.setVolumeModified(); addFileToGrid(theMainWindow->getBrainSet()->getVolumeAnatomyFile(i), fm, "Volume File - Anatomy", SpecFile::getVolumeAnatomyFileTag()); } for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfVolumeFunctionalFiles(); i++) { fm.setStatusForAll(false); fm.setVolumeModified(); addFileToGrid(theMainWindow->getBrainSet()->getVolumeFunctionalFile(i), fm, "Volume File - Functional", SpecFile::getVolumeFunctionalFileTag()); } for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfVolumePaintFiles(); i++) { fm.setStatusForAll(false); fm.setVolumeModified(); addFileToGrid(theMainWindow->getBrainSet()->getVolumePaintFile(i), fm, "Volume File - Paint", SpecFile::getVolumePaintFileTag()); } for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfVolumeProbAtlasFiles(); i++) { fm.setStatusForAll(false); fm.setVolumeModified(); addFileToGrid(theMainWindow->getBrainSet()->getVolumeProbAtlasFile(i), fm, "Volume File - Prob Atlas", SpecFile::getVolumeProbAtlasFileTag()); } for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfVolumeRgbFiles(); i++) { fm.setStatusForAll(false); fm.setVolumeModified(); addFileToGrid(theMainWindow->getBrainSet()->getVolumeRgbFile(i), fm, "Volume File - RGB", SpecFile::getVolumeRgbFileTag()); } for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfVolumeSegmentationFiles(); i++) { fm.setStatusForAll(false); fm.setVolumeModified(); addFileToGrid(theMainWindow->getBrainSet()->getVolumeSegmentationFile(i), fm, "Volume File - Segmentation", SpecFile::getVolumeSegmentationFileTag()); } for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfVolumeVectorFiles(); i++) { fm.setStatusForAll(false); fm.setVolumeModified(); addFileToGrid(theMainWindow->getBrainSet()->getVolumeVectorFile(i), fm, "Volume File - Vector", SpecFile::getVolumeVectorFileTag()); } for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfVtkModelFiles(); i++) { fm.setStatusForAll(false); fm.setVtkModelModified(); addFileToGrid(theMainWindow->getBrainSet()->getVtkModelFile(i), fm, "", SpecFile::getVtkModelFileTag()); } fm.setStatusForAll(false); fm.setWustlRegionModified(); addFileToGrid(theMainWindow->getBrainSet()->getWustlRegionFile(), fm, sf->wustlRegionFile, "", SpecFile::getWustlRegionFileTag()); // // Scrolled widget for files // QWidget* scrollAreaWidget = new QWidget; QVBoxLayout* scrollAreaWidgetLayout = new QVBoxLayout(scrollAreaWidget); scrollAreaWidgetLayout->addWidget(fileGridWidget); scrollAreaWidgetLayout->addStretch(); QScrollArea* sv = new QScrollArea(this); sv->setWidgetResizable(true); sv->setWidget(scrollAreaWidget); dialogLayout->addWidget(sv); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; dialogLayout->addLayout(buttonsLayout); buttonsLayout->setSpacing(2); // // Save all checked files button // QPushButton* saveButton = new QPushButton("Save All Checked Files"); saveButton->setAutoDefault(false); saveButton->setFixedSize(saveButton->sizeHint()); buttonsLayout->addWidget(saveButton); QObject::connect(saveButton, SIGNAL(clicked()), this, SLOT(slotSaveAllCheckFiles())); // // Close button // QPushButton* closeButton = new QPushButton("Close"); closeButton->setAutoDefault(false); closeButton->setFixedSize(closeButton->sizeHint()); buttonsLayout->addWidget(closeButton); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); QSize minSize = this->minimumSize(); this->setMinimumSize(std::max(minSize.width(), 800), minSize.height()); //resize(std::max(width(), 800), stdheight()); } /** * Destructor */ GuiLoadedFileManagementDialog::~GuiLoadedFileManagementDialog() { } /** * Called when an info button is pressed. */ void GuiLoadedFileManagementDialog::slotInfoButtonGroup(int item) { AbstractFile* af = dataFiles[item].dataFile; if (af != NULL) { GuiDataFileCommentDialog* dfc = new GuiDataFileCommentDialog(this, af); dfc->show(); } } /** * save all checked files. */ void GuiLoadedFileManagementDialog::slotSaveAllCheckFiles() { const int num = static_cast(dataFiles.size()); for (int i = 0; i < num; i++) { dataFiles[i].saveFileIfChecked(); } } /** * called when a save button is pressed. */ void GuiLoadedFileManagementDialog::slotSaveButtonGroup(int item) { AbstractFile* af = dataFiles[item].dataFile; if (af != NULL) { af->setFileName(dataFiles[item].nameLineEdit->text()); GuiDataFileSaveDialog fd(this); fd.selectFile(af); if (fd.exec() == GuiDataFileSaveDialog::Accepted) { if (dataFiles[item].modifiedLabel != NULL) { if (af->getModified() == 0) { dataFiles[item].clearModified(); } dataFiles[item].nameLineEdit->setText(fd.getSelectedFileName()); } } } } /** * Called when a view button is pressed. */ void GuiLoadedFileManagementDialog::slotViewButtonGroup(int item) { AbstractFile* af = dataFiles[item].dataFile; if (af != NULL) { //CommaSeparatedValueFile csv; //af->writeDataIntoCommaSeparatedValueFile(csv); //GuiCommaSeparatedValueFileEditor* csfv = new GuiCommaSeparatedValueFileEditor(this, &csv, af); GuiCommaSeparatedValueFileEditor* csfv = new GuiCommaSeparatedValueFileEditor(this, af, dataFiles[item].dataFileTypeMask); csfv->show(); } } /** * Called when a border info button is pressed. */ void GuiLoadedFileManagementDialog::slotBorderInfoButtonGroup(int item) { BrainModelBorderFileInfo* bfi = borderInfoFileInfo[item]; if (bfi != NULL) { GuiDataFileCommentDialog* dfc = new GuiDataFileCommentDialog(this, bfi); dfc->show(); } } /** * called when a remove file column button is pressed. */ void GuiLoadedFileManagementDialog::slotRemoveFileColumnButtonGroup(int item) { AbstractFile* af = dataFiles[item].dataFile; if (af != NULL) { const GuiFilesModified fm = dataFiles[item].dataFileTypeMask; QStringList columnNames; GiftiNodeDataFile* gndf = dynamic_cast(af); if (gndf != NULL) { for (int i = 0; i < gndf->getNumberOfColumns(); i++) { columnNames += gndf->getColumnName(i); } } NodeAttributeFile* naf = dynamic_cast(af); if (naf != NULL) { for (int i = 0; i < naf->getNumberOfColumns(); i++) { columnNames += naf->getColumnName(i); } } const int numCols = static_cast(columnNames.size()); if (numCols <= 0) { QMessageBox::critical(this, "ERROR", "File contains no data."); return; } std::vector dataColumnCheckBoxes; WuQDataEntryDialog ded(this, true); ded.setTextAtTop("Select columns that you want REMOVED from the file.", true); for (int i = 0; i < numCols; i++) { dataColumnCheckBoxes.push_back(ded.addCheckBox(columnNames[i], false)); } if (ded.exec() == WuQDataEntryDialog::Accepted) { bool columnDeletedFlag = false; for (int i = (numCols - 1); i >= 0; i--) { if (dataColumnCheckBoxes[i]->isChecked()) { if (gndf != NULL) { gndf->removeColumn(i); columnDeletedFlag = true; } if (naf != NULL) { naf->removeColumn(i); columnDeletedFlag = true; } } } if (columnDeletedFlag) { BrainSet* bs = theMainWindow->getBrainSet(); if (gndf != NULL) { if (dynamic_cast(gndf) != NULL) { bs->getDisplaySettingsSurfaceShape()->update(); } else if (dynamic_cast(gndf) != NULL) { bs->getDisplaySettingsMetric()->update(); } else if (dynamic_cast(gndf) != NULL) { bs->getDisplaySettingsPaint()->update(); } else { std::cout << "PROGRAM ERROR: " << "Unrecognized GIFTI file type at " << __LINE__ << " in " << __FILE__ << std::endl; } } if (naf != NULL) { if (dynamic_cast(naf) != NULL) { bs->getDisplaySettingsArealEstimation()->update(); } else if (dynamic_cast(naf) != NULL) { bs->getDisplaySettingsDeformationField()->update(); } else if (dynamic_cast(naf) != NULL) { bs->getDisplaySettingsGeodesicDistance()->update(); } else if (dynamic_cast(naf) != NULL) { //bs->getDisplaySettingsPaint()->update(); } else if (dynamic_cast(naf) != NULL) { bs->getDisplaySettingsRgbPaint()->update(); } else if (dynamic_cast(naf) != NULL) { bs->getDisplaySettingsSection()->update(); } else if (dynamic_cast(naf) != NULL) { bs->getDisplaySettingsVectors()->update(); } else if (dynamic_cast(naf) != NULL) { bs->getDisplaySettingsTopography()->update(); } else { std::cout << "PROGRAM ERROR: " << "Unrecognized Node Attribute file type at " << __LINE__ << " in " << __FILE__ << std::endl; } } } } } theMainWindow->fileModificationUpdate(dataFiles[item].dataFileTypeMask); GuiBrainModelOpenGL::updateAllGL(); } /** * called when a clear file column button is pressed. */ void GuiLoadedFileManagementDialog::slotClearFileColumnButtonGroup(int item) { AbstractFile* af = dataFiles[item].dataFile; if (af != NULL) { const GuiFilesModified fm = dataFiles[item].dataFileTypeMask; QStringList columnNames; GiftiNodeDataFile* gndf = dynamic_cast(af); if (gndf != NULL) { for (int i = 0; i < gndf->getNumberOfColumns(); i++) { columnNames += gndf->getColumnName(i); } } NodeAttributeFile* naf = dynamic_cast(af); if (naf != NULL) { for (int i = 0; i < naf->getNumberOfColumns(); i++) { columnNames += naf->getColumnName(i); } } const int numCols = static_cast(columnNames.size()); if (numCols <= 0) { QMessageBox::critical(this, "ERROR", "File contains no data."); return; } std::vector dataColumnCheckBoxes; WuQDataEntryDialog ded(this, true); ded.setTextAtTop("Select columns for that you want cleared (zeroized) in the file.", true); for (int i = 0; i < numCols; i++) { dataColumnCheckBoxes.push_back(ded.addCheckBox(columnNames[i], false)); } if (ded.exec() == WuQDataEntryDialog::Accepted) { for (int i = (numCols - 1); i >= 0; i--) { if (dataColumnCheckBoxes[i]->isChecked()) { if (gndf != NULL) { gndf->resetColumn(i); } if (naf != NULL) { naf->resetColumn(i); } } } } } theMainWindow->fileModificationUpdate(dataFiles[item].dataFileTypeMask); GuiBrainModelOpenGL::updateAllGL(); } /** * Called when a remove file button is pressed. */ void GuiLoadedFileManagementDialog::slotRemoveFileButtonGroup(int item) { AbstractFile* af = dataFiles[item].dataFile; if (af != NULL) { if (QMessageBox::question(this, "CONFIRM", "Remove from memory: " + FileUtilities::basename(af->getFileName()) + "?", (QMessageBox::Yes | QMessageBox::No), QMessageBox::Yes) != QMessageBox::Yes) { return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); const GuiFilesModified fm = dataFiles[item].dataFileTypeMask; if (fm.getCoordinateModified()) { for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfBrainModels(); i++) { BrainModelSurface* bms = theMainWindow->getBrainSet()->getBrainModelSurface(i); if (bms != NULL) { if (bms->getCoordinateFile() == af) { theMainWindow->getBrainSet()->deleteBrainModelSurface(bms); break; } } } } else if (fm.getVolumeModified()) { theMainWindow->getBrainSet()->deleteVolumeFile(dynamic_cast(af)); } else if(fm.getContourModified()) { BrainModelContours* bmc = theMainWindow->getBrainSet()->getBrainModelContours(); if (bmc != NULL) { theMainWindow->getBrainSet()->deleteBrainModel(bmc); } } else if (fm.getTopologyModified()) { theMainWindow->getBrainSet()->deleteTopologyFile(dynamic_cast(af)); } else if (fm.getTransformationDataModified()) { theMainWindow->getBrainSet()->deleteTransformationDataFile(af); } else if (fm.getVtkModelModified()) { theMainWindow->getBrainSet()->deleteVtkModelFile(dynamic_cast(af)); } else if (fm.getImagesModified()) { theMainWindow->getBrainSet()->deleteImageFile(dynamic_cast(af)); } else if (dynamic_cast(af) != NULL) { theMainWindow->getBrainSet()->clearAreaColorFile(); } else if (dynamic_cast(af) != NULL) { theMainWindow->getBrainSet()->clearArealEstimationFile(); } else if (dynamic_cast(af) != NULL) { theMainWindow->getBrainSet()->clearBorderColorFile(); } else if (dynamic_cast(af) != NULL) { // COULD BE FOCI or CELLS CellFile* cf = dynamic_cast(af); if (cf == theMainWindow->getBrainSet()->getVolumeCellFile()) { theMainWindow->getBrainSet()->deleteAllCells(false, true); } } else if (dynamic_cast(af) != NULL) { CellProjectionFile* cpf = dynamic_cast(af); if (cpf == theMainWindow->getBrainSet()->getCellProjectionFile()) { theMainWindow->getBrainSet()->deleteAllCells(true, false); } else if (cpf == theMainWindow->getBrainSet()->getFociProjectionFile()) { theMainWindow->getBrainSet()->deleteAllFociProjections(); } } else if (dynamic_cast(af) != NULL) { theMainWindow->getBrainSet()->clearCellColorFile(); } else if (dynamic_cast(af) != NULL) { theMainWindow->getBrainSet()->clearCocomacConnectivityFile(); } else if (dynamic_cast(af) != NULL) { theMainWindow->getBrainSet()->clearContourCellColorFile(); } else if (dynamic_cast(af) != NULL) { theMainWindow->getBrainSet()->clearContourCellFile(); } else if (dynamic_cast(af) != NULL) { theMainWindow->getBrainSet()->clearCutsFile(); } else if (dynamic_cast(af) != NULL) { theMainWindow->getBrainSet()->clearDeformationFieldFile(); } else if (dynamic_cast(af) != NULL) { theMainWindow->getBrainSet()->clearDeformationMapFile(); } else if (dynamic_cast(af) != NULL) { theMainWindow->getBrainSet()->clearFociColorFile(); } else if (dynamic_cast(af) != NULL) { theMainWindow->getBrainSet()->clearFociSearchFile(); } else if (dynamic_cast(af) != NULL) { theMainWindow->getBrainSet()->clearGeodesicDistanceFile(); } else if (dynamic_cast(af) != NULL) { theMainWindow->getBrainSet()->clearLatLonFile(); } // shape must be before metric since shape derived from metric else if (dynamic_cast(af) != NULL) { theMainWindow->getBrainSet()->clearSurfaceShapeFile(); } else if (dynamic_cast(af) != NULL) { theMainWindow->getBrainSet()->removeVectorFile(dynamic_cast(af)); } else if (dynamic_cast(af) != NULL) { theMainWindow->getBrainSet()->clearMetricFile(); } else if ((dynamic_cast(af) != NULL) && // not prob atlas derived from paint (dynamic_cast(af) == NULL)) { theMainWindow->getBrainSet()->clearPaintFile(); } else if (dynamic_cast(af) != NULL) { theMainWindow->getBrainSet()->clearPaletteFile(); } else if (dynamic_cast(af) != NULL) { theMainWindow->getBrainSet()->clearParamsFile(); } else if (dynamic_cast(af) != NULL) { theMainWindow->getBrainSet()->clearProbabilisticAtlasFile(); } else if (dynamic_cast(af) != NULL) { theMainWindow->getBrainSet()->clearRgbPaintFile(); } else if (dynamic_cast(af) != NULL) { theMainWindow->getBrainSet()->clearSceneFile(); } else if (dynamic_cast(af) != NULL) { theMainWindow->getBrainSet()->clearSectionFile(); } else if (dynamic_cast(af) != NULL) { theMainWindow->getBrainSet()->clearStudyCollectionFile(); } else if (dynamic_cast(af) != NULL) { theMainWindow->getBrainSet()->clearStudyMetaDataFile(); } else if (dynamic_cast(af) != NULL) { theMainWindow->getBrainSet()->clearTopographyFile(); } else if (dynamic_cast(af) != NULL) { theMainWindow->getBrainSet()->clearTransformationMatrixFile(); } else if (dynamic_cast(af) != NULL) { theMainWindow->getBrainSet()->clearVocabularyFile(); } else if (dynamic_cast(af) != NULL) { theMainWindow->getBrainSet()->clearWustlRegionFile(); } else { std::ostringstream str; str << "PROGRAM ERROR: Unrecognized file type for deleting: " << af->getDescriptiveName().toAscii().constData(); QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "PROGRAM ERROR", str.str().c_str()); //af->clear(); } dataFiles[item].dataFile = NULL; dataFiles[item].fileTypeCheckBoxOrLabel->setEnabled(false); dataFiles[item].nameLineEdit->setEnabled(false); // // Disable info & clear button // QAbstractButton* clearButton = removeFileButtonGroup->button(item); if (clearButton != NULL) { clearButton->setEnabled(false); } QAbstractButton* infoButton = infoButtonGroup->button(item); if (infoButton != NULL) { infoButton->setEnabled(false); } QAbstractButton* removeColumnButton = removeFileColumnButtonGroup->button(item); if (removeColumnButton != NULL) { removeColumnButton->setEnabled(false); } QAbstractButton* clearColumnButton = clearFileColumnButtonGroup->button(item); if (clearColumnButton != NULL) { clearColumnButton->setEnabled(false); } QAbstractButton* viewButton = viewButtonGroup->button(item); if (viewButton != NULL) { viewButton->setEnabled(false); } theMainWindow->fileModificationUpdate(dataFiles[item].dataFileTypeMask); theMainWindow->getBrainSet()->clearAllDisplayLists(); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } } /** * Add a border file to the grid. */ void GuiLoadedFileManagementDialog::addBorderFileToGrid(BrainModelBorderSet* bmbs, const BrainModelSurface::SURFACE_TYPES surfaceType, const char* typeName, const QString& specFileTagIn) { BrainModelBorderFileInfo* bmi = bmbs->getBorderFileInfo(surfaceType); if (bmi != NULL) { const QString fileName(bmi->getFileName()); if (fileName.isEmpty() == false) { const BorderFile* bf = bmbs->copyBordersOfSpecifiedType(surfaceType); if (bf != NULL) { if (bf->getNumberOfBorders() > 0) { const int rowNum = fileGridLayout->rowCount(); // + 1; QLabel* typeNameLabel = new QLabel(typeName); fileGridLayout->addWidget(typeNameLabel, rowNum, columnFileTypeIndex); QLabel* modifyLabel = new QLabel(" "); modifyLabel->setStyleSheet("color: red; font: bold"); // show text in red, bold fileGridLayout->addWidget(modifyLabel, rowNum, columnModifiedIndex); QToolButton* infoPB = new QToolButton; infoPB->setText(commentHeaderPushButtonText); infoPB->setFixedSize(infoPB->sizeHint()); borderInfoButtonGroup->addButton(infoPB, static_cast(borderInfoFileInfo.size())); infoPB->setToolTip("Show file information."); fileGridLayout->addWidget(infoPB, rowNum, columnCommentIndex, Qt::AlignHCenter); borderInfoFileInfo.push_back(bmi); fileGridLayout->addWidget(new QLabel(" "), rowNum, columnRemoveFileIndex); // X button QLineEdit* fileNameLineEdit = new QLineEdit; fileNameLineEdit->setText(fileName); fileGridLayout->addWidget(fileNameLineEdit, rowNum, columnFileNameIndex); GuiFilesModified noMask; dataFiles.push_back(DataFile(NULL, noMask, typeNameLabel, fileNameLineEdit, modifyLabel, specFileTagIn)); } if (bf != NULL) { delete bf; } } } } } /** * Add a border projection file to the grid. */ void GuiLoadedFileManagementDialog::addBorderProjectionFileToGrid(BrainModelBorderSet* bmbs) { BrainModelBorderFileInfo* bmi = bmbs->getBorderProjectionFileInfo(); if (bmi != NULL) { const QString fileName(bmi->getFileName()); if (fileName.isEmpty() == false) { bmbs->copyBordersToBorderProjectionFile(borderProjectionFileForGrid); if (borderProjectionFileForGrid.getNumberOfBorderProjections() > 0) { const int rowNum = fileGridLayout->rowCount(); // + 1; QCheckBox* typeNameCheckBox = new QCheckBox("Border Projection File"); fileGridLayout->addWidget(typeNameCheckBox, rowNum, columnFileTypeIndex); QLabel* modifyLabel = new QLabel(" "); modifyLabel->setStyleSheet("color: red; font: bold"); // show text in red, bold fileGridLayout->addWidget(modifyLabel, rowNum, columnModifiedIndex, Qt::AlignHCenter); if (bmbs->getProjectionsModified()) { modifyLabel->setText("***"); borderProjectionFileForGrid.setModified(); } else { borderProjectionFileForGrid.clearModified(); } borderProjInfoPB = new QToolButton; borderProjInfoPB->setText(commentHeaderPushButtonText); borderProjInfoPB->setFixedSize(borderProjInfoPB->sizeHint()); borderInfoButtonGroup->addButton(borderProjInfoPB, static_cast(borderInfoFileInfo.size())); borderProjInfoPB->setToolTip("Show file information."); fileGridLayout->addWidget(borderProjInfoPB, rowNum, columnCommentIndex, Qt::AlignHCenter); borderInfoFileInfo.push_back(bmi); borderProjSavePB = new QToolButton; borderProjSavePB->setText(saveFilePushButtonText); borderProjSavePB->setFixedSize(borderProjSavePB->sizeHint()); QObject::connect(borderProjSavePB, SIGNAL(clicked()), this, SLOT(slotSaveBorderProjections())); fileGridLayout->addWidget(borderProjSavePB, rowNum, columnSaveFileIndex, Qt::AlignHCenter); borderProjClearPB = new QToolButton; borderProjClearPB->setText(removeFilePushButtonText); borderProjClearPB->setFixedSize(borderProjClearPB->sizeHint()); QObject::connect(borderProjClearPB, SIGNAL(clicked()), this, SLOT(slotDeleteBorderProjections())); borderProjClearPB->setToolTip("Delete this file from memory.\n" "The file is NOT deleted."); fileGridLayout->addWidget(borderProjClearPB, rowNum, columnRemoveFileIndex, Qt::AlignHCenter); QLineEdit* fileNameLineEdit = new QLineEdit; fileNameLineEdit->setText(fileName); fileGridLayout->addWidget(fileNameLineEdit, rowNum, columnFileNameIndex); borderProjectionDataFileIndex = static_cast(dataFiles.size()); GuiFilesModified borderProjModMask; borderProjModMask.setBorderModified(); dataFiles.push_back(DataFile(&borderProjectionFileForGrid, borderProjModMask, typeNameCheckBox, fileNameLineEdit, modifyLabel, SpecFile::getBorderProjectionFileTag())); } } } } /** * called to save border projections. */ void GuiLoadedFileManagementDialog::slotSaveBorderProjections() { BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); BrainModelBorderFileInfo* bmi = bmbs->getBorderProjectionFileInfo(); bmi->setFileName(dataFiles[borderProjectionDataFileIndex].nameLineEdit->text()); bmbs->copyBordersToBorderProjectionFile(borderProjectionFileForGrid); GuiDataFileSaveDialog fd(this); fd.selectFileType(FileFilters::getBorderProjectionFileFilter()); if (fd.exec() == GuiDataFileSaveDialog::Accepted) { if (dataFiles[borderProjectionDataFileIndex].modifiedLabel != NULL) { if (bmbs->getProjectionsModified() == false) { dataFiles[borderProjectionDataFileIndex].clearModified(); bmi->setFileName(fd.getSelectedFileName()); } } } } /** * called to delete border projections. */ void GuiLoadedFileManagementDialog::slotDeleteBorderProjections() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); bmbs->deleteBorderProjections(); GuiFilesModified fm; fm.setBorderModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); dataFiles[borderProjectionDataFileIndex].fileTypeCheckBoxOrLabel->setEnabled(false); dataFiles[borderProjectionDataFileIndex].nameLineEdit->setEnabled(false); borderProjInfoPB->setEnabled(false); borderProjClearPB->setEnabled(false); borderProjSavePB->setEnabled(false); QApplication::restoreOverrideCursor(); } /** * Add a file to the grid. */ void GuiLoadedFileManagementDialog::addFileToGrid(AbstractFile* af, const GuiFilesModified& fileMask, const char* typeName, const QString& specFileTagIn) { SpecFile::Entry dummyEntry; addFileToGrid(af, fileMask, dummyEntry, typeName, specFileTagIn); } /** * add a file to the list of files. */ void GuiLoadedFileManagementDialog::addFileToGrid(AbstractFile* af, const GuiFilesModified& fileMask, const SpecFile::Entry& dataFileInfo, const char* typeName, const QString& specFileTagIn) { if (af != NULL) { if (af->empty() == false) { QString label(af->getDescriptiveName()); if (typeName != NULL) { if (strlen(typeName) > 0) { label = typeName; } } QString modifiedLabelText(" "); if (af->getModified()) { modifiedLabelText = modifiedFileLabelText; } const int rowNum = fileGridLayout->rowCount(); // + 1; QCheckBox* fileTypeCheckBox = new QCheckBox(label); fileGridLayout->addWidget(fileTypeCheckBox, rowNum, columnFileTypeIndex); QLabel* modifiedLabel = new QLabel; modifiedLabel->setStyleSheet("color: red; font: bold"); // show text in red, bold modifiedLabel->setText(modifiedLabelText); fileGridLayout->addWidget(modifiedLabel, rowNum, columnModifiedIndex, Qt::AlignHCenter); QToolButton* savePB = new QToolButton; savePB->setText(saveFilePushButtonText); saveButtonGroup->addButton(savePB, dataFiles.size()); savePB->setToolTip("Save the file."); savePB->setFixedSize(savePB->sizeHint()); fileGridLayout->addWidget(savePB, rowNum, columnSaveFileIndex, Qt::AlignHCenter); QToolButton* viewPB = new QToolButton; viewPB->setText(viewFilePushButtonText); //viewPB->setAutoDefault(false); viewButtonGroup->addButton(viewPB, dataFiles.size()); viewPB->setToolTip("View data file in spreadsheet"); fileGridLayout->addWidget(viewPB, rowNum, columnViewFileIndex, Qt::AlignHCenter); bool readCSV, writeCSV; af->getCommaSeparatedFileSupport(readCSV, writeCSV); if (writeCSV == false) { viewPB->hide(); } viewPB->setFixedSize(viewPB->sizeHint()); QToolButton* infoPB = new QToolButton; infoPB->setText(commentHeaderPushButtonText); //infoPB->setAutoDefault(false); infoButtonGroup->addButton(infoPB, dataFiles.size()); infoPB->setToolTip("Show file information."); fileGridLayout->addWidget(infoPB, rowNum, columnCommentIndex, Qt::AlignHCenter); infoPB->setFixedSize(infoPB->sizeHint()); QToolButton* removeFilePB = new QToolButton; removeFilePB->setText(removeFilePushButtonText); //clearPB->setAutoDefault(false); removeFileButtonGroup->addButton(removeFilePB, dataFiles.size()); removeFilePB->setToolTip("Delete this file from memory.\n" "The file is NOT deleted."); fileGridLayout->addWidget(removeFilePB, rowNum, columnRemoveFileIndex, Qt::AlignHCenter); removeFilePB->setFixedSize(removeFilePB->sizeHint()); // // Is this a node attribute file? // if ((dynamic_cast(af) != NULL) || (dynamic_cast(af) != NULL)) { // // Remove column push button // QToolButton* removeColumnPushButton = new QToolButton; removeColumnPushButton->setText(removeFileColumnPushButtonText); removeColumnPushButton->setFixedSize(removeColumnPushButton->sizeHint()); removeColumnPushButton->setToolTip("Remove data column(s)\n" "from this file."); fileGridLayout->addWidget(removeColumnPushButton, rowNum, columnRemoveFileColumnIndex, Qt::AlignHCenter); removeFileColumnButtonGroup->addButton(removeColumnPushButton, dataFiles.size()); // // Clear column push button // QToolButton* clearColumnPushButton = new QToolButton; clearColumnPushButton->setText(clearFileColumnPushButtonText); clearColumnPushButton->setFixedSize(clearColumnPushButton->sizeHint()); clearColumnPushButton->setToolTip("Clear (zeroize) data column(s)\n" "from this file."); fileGridLayout->addWidget(clearColumnPushButton, rowNum, columnClearFileColumnIndex, Qt::AlignHCenter); clearFileColumnButtonGroup->addButton(clearColumnPushButton, dataFiles.size()); } const QString filename(FileUtilities::basename(af->getFileName())); QLineEdit* fileNameLineEdit = new QLineEdit; fileNameLineEdit->setText(filename); fileGridLayout->addWidget(fileNameLineEdit, rowNum, columnFileNameIndex); dataFiles.push_back(DataFile(af, fileMask, fileTypeCheckBox, fileNameLineEdit, modifiedLabel, specFileTagIn)); if (dynamic_cast(af) == false) { for (int i = 0; i < dataFileInfo.getNumberOfFiles(); i++) { if (dataFileInfo.files[i].selected == SpecFile::SPEC_TRUE) { const QString name(FileUtilities::basename(dataFileInfo.files[i].filename)); if (name != filename) { const int rowNum = fileGridLayout->rowCount(); // + 1; fileGridLayout->addWidget(new QLabel(name), rowNum, columnFileNameIndex); } } } } } } } // //============================================================================= //============================================================================= // /** * constructor. */ GuiLoadedFileManagementDialog::DataFile::DataFile(AbstractFile* dataFileIn, GuiFilesModified dataFileTypeMaskIn, QWidget* fileTypeCheckBoxOrLabelIn, QLineEdit* nameLineEditIn, QLabel* modifiedLabelIn, const QString& specFileTagIn) { dataFile = dataFileIn; fileTypeCheckBoxOrLabel = fileTypeCheckBoxOrLabelIn; nameLineEdit = nameLineEditIn; dataFileTypeMask = dataFileTypeMaskIn; modifiedLabel = modifiedLabelIn; specFileTag = specFileTagIn; if (dataFile != NULL) { if (dataFile->getModified()) { setModified(); } } } /** * destructor. */ GuiLoadedFileManagementDialog::DataFile::~DataFile() { } /** * set modified. */ void GuiLoadedFileManagementDialog::DataFile::setModified() { modifiedLabel->setText(modifiedFileLabelText); QCheckBox* cb = dynamic_cast(fileTypeCheckBoxOrLabel); if (cb != NULL) { cb->setChecked(true); } } /** * save the file if it is checked. */ QString GuiLoadedFileManagementDialog::DataFile::saveFileIfChecked() { QCheckBox* cb = dynamic_cast(fileTypeCheckBoxOrLabel); if (cb != NULL) { if (cb->isChecked()) { const QString name = nameLineEdit->text(); if (name.isEmpty() == false) { // std::cout << "Saving: " << name.toAscii().constData() << std::endl; if (dataFile != NULL) { if (dynamic_cast(dataFile) != NULL) { BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); BrainModelBorderFileInfo* bmi = bmbs->getBorderProjectionFileInfo(); bmi->setFileName(nameLineEdit->text()); try { theMainWindow->getBrainSet()->writeBorderProjectionFile( name, "", ""); } catch (FileException& e) { return e.whatQString(); } if (bmbs->getProjectionsModified() == false) { modifiedLabel->setText(" "); cb->setChecked(false); } } else { dataFile->setFileName(name); try { dataFile->writeFile(name); } catch (FileException& e) { return e.whatQString(); } if (dataFile->getModified() == false) { modifiedLabel->setText(" "); cb->setChecked(false); } } QString name2; VolumeFile* vf = dynamic_cast(dataFile); if (vf != NULL) { name2 = vf->getDataFileName(); } theMainWindow->getBrainSet()->addToSpecFile( specFileTag, name, name2); } } } } return ""; } /** * clear modified. */ void GuiLoadedFileManagementDialog::DataFile::clearModified() { modifiedLabel->setText(" "); QCheckBox* cb = dynamic_cast(fileTypeCheckBoxOrLabel); if (cb != NULL) { cb->setChecked(false); } } caret-5.6.4~dfsg.1.orig/caret/GuiLoadNodeAttributeFileColumnSelectionDialog.h0000664000175000017500000000731111572067322027014 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_LOAD_NODE_ATTRIBUTE_FILE_COLUMN_SELECTION_DIALOG_H__ #define __GUI_LOAD_NODE_ATTRIBUTE_FILE_COLUMN_SELECTION_DIALOG_H__ #include #include "WuQDialog.h" #include "AbstractFile.h" class GuiNodeAttributeColumnSelectionComboBox; class GiftiNodeDataFile; class NodeAttributeFile; class QComboBox; class QCheckBox; class QLineEdit; /// class for selectively loading node attribute file columns class GuiLoadNodeAttributeFileColumnSelectionDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiLoadNodeAttributeFileColumnSelectionDialog(QWidget* parent, NodeAttributeFile* newFileIn, NodeAttributeFile* currentFileIn); /// Constructor GuiLoadNodeAttributeFileColumnSelectionDialog(QWidget* parent, GiftiNodeDataFile* newFileIn, GiftiNodeDataFile* currentFileIn); /// Destructor ~GuiLoadNodeAttributeFileColumnSelectionDialog(); /// Get the destination column in the existing file for a column from std::vector getDestinationColumns() const; /// Get the erase all existing columns flag bool getEraseAllExistingColumns() const; /// Get the new file's updated column names. std::vector getNewFileColumnNames() const; /// get append file comment selection AbstractFile::FILE_COMMENT_MODE getAppendFileCommentSelection() const; protected slots: /// called when set all to do not load button pressed void slotAllToDoNotLoadPushButton(); /// called when erase all columns check box is selected void slotEraseAllExistingColumnsCheckBox(bool b); protected: /// called when OK or Cancel button pressed void done(int r); /// existing file column selection combo boxes std::vector columnComboBoxes; /// new file column names line edits std::vector columnNameLineEdits; /// new file that is to be loaded NodeAttributeFile* newFileNAF; /// file to which new file is append or replaces NodeAttributeFile* currentFileNAF; /// new file that is to be loaded GiftiNodeDataFile* newFileNDF; /// file to which new file is append or replaces GiftiNodeDataFile* currentFileNDF; /// erase all existing columns QCheckBox* eraseAllExistingColumnsCheckBox; /// combo box for file comment append mode QComboBox* appendFileCommentComboBox; }; #endif // __GUI_LOAD_NODE_ATTRIBUTE_FILE_COLUMN_SELECTION_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiLoadNodeAttributeFileColumnSelectionDialog.cxx0000664000175000017500000003451411572067322027374 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include "GuiLoadNodeAttributeFileColumnSelectionDialog.h" #include "GuiNodeAttributeColumnSelectionComboBox.h" #include "GiftiNodeDataFile.h" #include "NodeAttributeFile.h" #include "QtUtilities.h" /** * Constructor. */ GuiLoadNodeAttributeFileColumnSelectionDialog::GuiLoadNodeAttributeFileColumnSelectionDialog( QWidget* parent, NodeAttributeFile* newFileIn, NodeAttributeFile* currentFileIn) : WuQDialog(parent) { setModal(true); newFileNAF = newFileIn; currentFileNAF = currentFileIn; setWindowTitle("Choose Columns to Load"); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // Layout for appending comment // QHBoxLayout* commentLayout = new QHBoxLayout; commentLayout->setSpacing(3); dialogLayout->addLayout(commentLayout); commentLayout->addWidget(new QLabel("File Comment ")); appendFileCommentComboBox = new QComboBox; appendFileCommentComboBox->insertItem(AbstractFile::FILE_COMMENT_MODE_APPEND, "Append"); appendFileCommentComboBox->insertItem(AbstractFile::FILE_COMMENT_MODE_LEAVE_AS_IS, "Leave As Is"); appendFileCommentComboBox->insertItem(AbstractFile::FILE_COMMENT_MODE_REPLACE, "Replace"); commentLayout->addWidget(appendFileCommentComboBox); // // Top of dialog layout // QHBoxLayout* topLayout = new QHBoxLayout; topLayout->setSpacing(3); dialogLayout->addLayout(topLayout); // // Erase all existing columns checkbox // eraseAllExistingColumnsCheckBox = NULL; if (currentFileNAF->getNumberOfColumns() > 0) { eraseAllExistingColumnsCheckBox = new QCheckBox("Erase All Existing Columns"); topLayout->addWidget(eraseAllExistingColumnsCheckBox); QObject::connect(eraseAllExistingColumnsCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotEraseAllExistingColumnsCheckBox(bool))); } // // all to do not load button // QPushButton* allToDoNotLoadPushButton = new QPushButton("Set All Columns to Do Not Load"); topLayout->addWidget(allToDoNotLoadPushButton); allToDoNotLoadPushButton->setFixedSize(allToDoNotLoadPushButton->sizeHint()); allToDoNotLoadPushButton->setAutoDefault(false); QObject::connect(allToDoNotLoadPushButton, SIGNAL(clicked()), this, SLOT(slotAllToDoNotLoadPushButton())); // // Scroll and grid for names widget since there could be many names // QWidget* nameWidget = new QWidget; QGridLayout* nameGridLayout = new QGridLayout(nameWidget); nameGridLayout->setSpacing(3); // // Column names // nameGridLayout->addWidget(new QLabel("Column"), 0, 0); nameGridLayout->addWidget(new QLabel("Load into Column"), 0, 1); const int numCols = newFileNAF->getNumberOfColumns(); for (int i = 0; i < numCols; i++) { // // line edit so new file column names can be changed // QLineEdit* le = new QLineEdit; nameGridLayout->addWidget(le, i + 1, 0); le->setFixedWidth(300); le->setText(newFileNAF->getColumnName(i)); le->home(true); columnNameLineEdits.push_back(le); // // existing file column to overwrite, or NONE, or NEW // GuiNodeAttributeColumnSelectionComboBox* csc = new GuiNodeAttributeColumnSelectionComboBox(currentFileNAF, true, true, false); csc->setMaximumWidth(400); csc->setNoneSelectionLabel("Do Not Load"); csc->setCurrentIndex(GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NEW); columnComboBoxes.push_back(csc); nameGridLayout->addWidget(csc, i + 1, 1); } // // Scroll and for names widget since there could be many names // QScrollArea* sv = new QScrollArea; dialogLayout->addWidget(sv); sv->setWidget(nameWidget); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); dialogLayout->addLayout(buttonsLayout); // // OK button // QPushButton* okButton = new QPushButton("OK"); okButton->setAutoDefault(false); buttonsLayout->addWidget(okButton); QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); // // Cancel button // QPushButton* cancelButton = new QPushButton("Cancel"); cancelButton->setAutoDefault(false); buttonsLayout->addWidget(cancelButton); QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); QtUtilities::makeButtonsSameSize(okButton, cancelButton); } /** * Constructor. */ GuiLoadNodeAttributeFileColumnSelectionDialog::GuiLoadNodeAttributeFileColumnSelectionDialog( QWidget* parent, GiftiNodeDataFile* newFileIn, GiftiNodeDataFile* currentFileIn) : WuQDialog(parent) { setModal(true); newFileNDF = newFileIn; currentFileNDF = currentFileIn; setWindowTitle("Choose Columns to Load"); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // Layout for appending comment // QHBoxLayout* commentLayout = new QHBoxLayout; commentLayout->setSpacing(3); dialogLayout->addLayout(commentLayout); commentLayout->addWidget(new QLabel("File Comment ")); appendFileCommentComboBox = new QComboBox; appendFileCommentComboBox->insertItem(AbstractFile::FILE_COMMENT_MODE_APPEND, "Append"); appendFileCommentComboBox->insertItem(AbstractFile::FILE_COMMENT_MODE_LEAVE_AS_IS, "Leave As Is"); appendFileCommentComboBox->insertItem(AbstractFile::FILE_COMMENT_MODE_REPLACE, "Replace"); commentLayout->addWidget(appendFileCommentComboBox); // // Top of dialog layout // QHBoxLayout* topLayout = new QHBoxLayout; topLayout->setSpacing(3); dialogLayout->addLayout(topLayout); // // Erase all existing columns checkbox // eraseAllExistingColumnsCheckBox = NULL; if (currentFileNDF->getNumberOfColumns() > 0) { eraseAllExistingColumnsCheckBox = new QCheckBox("Erase All Existing Columns"); topLayout->addWidget(eraseAllExistingColumnsCheckBox); QObject::connect(eraseAllExistingColumnsCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotEraseAllExistingColumnsCheckBox(bool))); } // // all to do not load button // QPushButton* allToDoNotLoadPushButton = new QPushButton("Set All Columns to Do Not Load"); topLayout->addWidget(allToDoNotLoadPushButton); allToDoNotLoadPushButton->setFixedSize(allToDoNotLoadPushButton->sizeHint()); allToDoNotLoadPushButton->setAutoDefault(false); QObject::connect(allToDoNotLoadPushButton, SIGNAL(clicked()), this, SLOT(slotAllToDoNotLoadPushButton())); // // grid for names widget since there could be many names // QWidget* nameGrid = new QWidget; QGridLayout* nameGridLayout = new QGridLayout(nameGrid); nameGridLayout->setSpacing(3); // // Column names // nameGridLayout->addWidget(new QLabel("Column"), 0, 0); nameGridLayout->addWidget(new QLabel("Load into Column"), 0, 1); const int numCols = newFileNDF->getNumberOfColumns(); for (int i = 0; i < numCols; i++) { // // line edit so new file column names can be changed // QLineEdit* le = new QLineEdit; le->setFixedWidth(300); le->setText(newFileNDF->getColumnName(i)); le->home(true); columnNameLineEdits.push_back(le); nameGridLayout->addWidget(le, i + 1, 0); // // existing file column to overwrite, or NONE, or NEW // GuiNodeAttributeColumnSelectionComboBox* csc = new GuiNodeAttributeColumnSelectionComboBox(currentFileNDF, true, true, false); csc->setMaximumWidth(400); csc->setNoneSelectionLabel("Do Not Load"); csc->setCurrentIndex(GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NEW); columnComboBoxes.push_back(csc); nameGridLayout->addWidget(csc, i + 1, 1); } // // Scroll and grid for names widget since there could be many names // QScrollArea* sv = new QScrollArea; dialogLayout->addWidget(sv); sv->setWidget(nameGrid); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); dialogLayout->addLayout(buttonsLayout); // // OK button // QPushButton* okButton = new QPushButton("OK"); okButton->setAutoDefault(false); buttonsLayout->addWidget(okButton); QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); // // Cancel button // QPushButton* cancelButton = new QPushButton("Cancel"); cancelButton->setAutoDefault(false); buttonsLayout->addWidget(cancelButton); QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); QtUtilities::makeButtonsSameSize(okButton, cancelButton); } /** * Destructor. */ GuiLoadNodeAttributeFileColumnSelectionDialog::~GuiLoadNodeAttributeFileColumnSelectionDialog() { } /** * called when erase all columns check box is selected. */ void GuiLoadNodeAttributeFileColumnSelectionDialog::slotEraseAllExistingColumnsCheckBox(bool b) { if (b) { appendFileCommentComboBox->setCurrentIndex(AbstractFile::FILE_COMMENT_MODE_REPLACE); } } /** * called when set all to do not load button pressed. */ void GuiLoadNodeAttributeFileColumnSelectionDialog::slotAllToDoNotLoadPushButton() { for (int i = 0; i < static_cast(columnComboBoxes.size()); i++) { columnComboBoxes[i]->setCurrentIndex( GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NONE); } } /** * Get the destination column in the existing file for a column from * the new file that is being loaded. * Note that -1 implies the destination is a new column. * Note that -2 implies that the column should not be loaded. */ std::vector GuiLoadNodeAttributeFileColumnSelectionDialog::getDestinationColumns() const { std::vector selections; for (int i = 0; i < static_cast(columnComboBoxes.size()); i++) { int value = columnComboBoxes[i]->currentIndex(); if (value < 0) { if (value == GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_INVALID) { value = NodeAttributeFile::APPEND_COLUMN_DO_NOT_LOAD; } else if (value == GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NEW) { value = NodeAttributeFile::APPEND_COLUMN_NEW; } else if (value == GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NONE) { value = NodeAttributeFile::APPEND_COLUMN_DO_NOT_LOAD; } else if (value == GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_ALL) { value = NodeAttributeFile::APPEND_COLUMN_DO_NOT_LOAD; } else { value = NodeAttributeFile::APPEND_COLUMN_DO_NOT_LOAD; } } selections.push_back(value); } return selections; } /** * Get the new file's updated column names. */ std::vector GuiLoadNodeAttributeFileColumnSelectionDialog::getNewFileColumnNames() const { std::vector names; for (int i = 0; i < static_cast(columnNameLineEdits.size()); i++) { names.push_back(columnNameLineEdits[i]->text()); } return names; } /** * Get the erase all existing columns flag. */ bool GuiLoadNodeAttributeFileColumnSelectionDialog::getEraseAllExistingColumns() const { if (eraseAllExistingColumnsCheckBox != NULL) { return eraseAllExistingColumnsCheckBox->isChecked(); } return false; } /** * called when OK or Cancel button pressed. */ void GuiLoadNodeAttributeFileColumnSelectionDialog::done(int r) { if (r == QDialog::Accepted) { if (getEraseAllExistingColumns()) { std::vector selections = getDestinationColumns(); for (unsigned int i = 0; i < selections.size(); i++) { if (selections[i] >= 0) { QMessageBox::critical(this, "ERROR", "Since \"Erase All Existing Columns\" is selected,\n" "columns from new file must be loaded into new\n" "columns or not loaded."); return; } } } } QDialog::done(r); } /** * get append file comment selection. */ AbstractFile::FILE_COMMENT_MODE GuiLoadNodeAttributeFileColumnSelectionDialog::getAppendFileCommentSelection() const { AbstractFile::FILE_COMMENT_MODE fcm = static_cast(appendFileCommentComboBox->currentIndex()); return fcm; } caret-5.6.4~dfsg.1.orig/caret/GuiInterpolateSurfacesDialog.h0000664000175000017500000000475211572067322023607 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_INTERPOLATE_SURFACES_DIALOG_H__ #define __GUI_INTERPOLATE_SURFACES_DIALOG_H__ #include #include "WuQDialog.h" class BrainModelSurface; class GuiBrainModelSelectionComboBox; class GuiTopologyFileComboBox; class QCheckBox; class QGridLayout; class QLabel; class QSpinBox; class QDoubleSpinBox; /// dialog for interpolating surfaces class GuiInterpolateSurfacesDialog : public WuQDialog { Q_OBJECT public: /// constructor GuiInterpolateSurfacesDialog(QWidget* parent); /// destructor ~GuiInterpolateSurfacesDialog(); /// update the dialog void updateDialog(); public slots: /// called when apply button pressed void slotApplyButton(); private: /// update projected files void updateProjectedFiles(const BrainModelSurface* bms); /// surface selection combo boxes std::vector surfaceComboBoxes; /// labels for combo boxes std::vector surfaceLabels; /// topology file selection combo box GuiTopologyFileComboBox* topologyComboBox; /// interpolation steps spin box QSpinBox* interpolationStepsSpinBox; /// reproject borders each step QCheckBox* reprojectBordersCheckBox; /// rotate non-flat surfaces check box QCheckBox* rotateSurfacesCheckBox; /// rotation step float spin box QDoubleSpinBox* rotationStepDoubleSpinBox; /// layout for surfaces list QGridLayout* surfaceGridLayout; }; #endif // __GUI_INTERPOLATE_SURFACES_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiInterpolateSurfacesDialog.cxx0000664000175000017500000006361311572067322024163 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include "BrainModelBorderSet.h" #include "BrainModelSurface.h" #include "BrainSet.h" #include "GuiBrainModelOpenGL.h" #include "GuiBrainModelSelectionComboBox.h" #include "GuiFilesModified.h" #include "GuiInterpolateSurfacesDialog.h" #include "GuiMainWindow.h" #include "GuiTopologyFileComboBox.h" #include #include "QtUtilities.h" #include "global_variables.h" #include "vtkTransform.h" /** * Constructor. */ GuiInterpolateSurfacesDialog::GuiInterpolateSurfacesDialog(QWidget* parent) : WuQDialog(parent) { setWindowTitle("Interpolate Surfaces"); // // Vertical box layout of all items // QVBoxLayout* rows = new QVBoxLayout(this); rows->setMargin(3); rows->setSpacing(3); // // Interpolation parameters group box // QGroupBox* parametersGroupBox = new QGroupBox("Interpolation Parameters"); QVBoxLayout* parametersGroupLayout = new QVBoxLayout(parametersGroupBox); rows->addWidget(parametersGroupBox); // // Interpolate steps spin box // QHBoxLayout* stepsBoxLayout = new QHBoxLayout; parametersGroupLayout->addLayout(stepsBoxLayout); stepsBoxLayout->addWidget(new QLabel("Interplation Steps")); interpolationStepsSpinBox = new QSpinBox; interpolationStepsSpinBox->setMinimum(1); interpolationStepsSpinBox->setMaximum(100000); interpolationStepsSpinBox->setSingleStep(1); interpolationStepsSpinBox->setValue(20); stepsBoxLayout->addWidget(interpolationStepsSpinBox); stepsBoxLayout->addStretch(1000); // // Reproject borders, cells, and foci each step check boxes // reprojectBordersCheckBox = new QCheckBox("Reproject Borders Each Step"); reprojectBordersCheckBox->setChecked(true); parametersGroupLayout->addWidget(reprojectBordersCheckBox); // // Topology group box // QGroupBox* topologyGroupBox = new QGroupBox("Topology File"); rows->addWidget(topologyGroupBox); QVBoxLayout* topologyGroupLayout = new QVBoxLayout(topologyGroupBox); // // Topology selection combo box // topologyComboBox = new GuiTopologyFileComboBox(0); topologyGroupLayout->addWidget(topologyComboBox); // // group box and layout for the surfaces // QGroupBox* surfaceGroupBox = new QGroupBox("Surfaces"); rows->addWidget(surfaceGroupBox); surfaceGridLayout = new QGridLayout(surfaceGroupBox); // // rotate group box // QGroupBox* rotateGroupBox = new QGroupBox("Rotation"); QVBoxLayout* rotateLayout = new QVBoxLayout(rotateGroupBox); rows->addWidget(rotateGroupBox); // // Rotate surfaces check box // rotateSurfacesCheckBox = new QCheckBox("Rotate Surfaces (execept flat)"); rotateLayout->addWidget(rotateSurfacesCheckBox); // // rotation step hbox // QHBoxLayout* rotationStepLayout = new QHBoxLayout; rotateLayout->addLayout(rotationStepLayout); rotationStepLayout->addWidget(new QLabel("Degrees Per Step")); rotationStepDoubleSpinBox = new QDoubleSpinBox; rotationStepDoubleSpinBox->setMinimum(0.01); rotationStepDoubleSpinBox->setMaximum(360.0); rotationStepDoubleSpinBox->setSingleStep(1.0); rotationStepDoubleSpinBox->setDecimals(2); rotationStepDoubleSpinBox->setValue(10.0); rotationStepLayout->addWidget(rotationStepDoubleSpinBox); rotationStepLayout->addStretch(1000); // // Dialog Buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(5); rows->addLayout(buttonsLayout); // // Apply button // QPushButton* applyButton = new QPushButton("Apply"); applyButton->setAutoDefault(false); QObject::connect(applyButton, SIGNAL(clicked()), this, SLOT(slotApplyButton())); buttonsLayout->addWidget(applyButton); // // Close button // QPushButton* closeButton = new QPushButton("Close"); closeButton->setAutoDefault(false); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(reject())); buttonsLayout->addWidget(closeButton); QtUtilities::makeButtonsSameSize(applyButton, closeButton); updateDialog(); } /** * Destructor. */ GuiInterpolateSurfacesDialog::~GuiInterpolateSurfacesDialog() { } /** * Called to update the dialog */ void GuiInterpolateSurfacesDialog::updateDialog() { static QDateTime prevSpecLoadTime = QDateTime::currentDateTime(); QDateTime specLoadTime = theMainWindow->getBrainSet()->getSpecFileTimeOfLoading(); topologyComboBox->updateComboBox(); // // Count the number of surfaces (max of 10) // int numSurfaces = 0; std::vector defaultSurfaces; for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfBrainModels(); i++) { if (theMainWindow->getBrainSet()->getBrainModelSurface(i) != NULL) { defaultSurfaces.push_back(theMainWindow->getBrainSet()->getBrainModelSurface(i)); numSurfaces++; } } const int oldNumSurfaces = static_cast(surfaceComboBoxes.size()); // // add new combo boxes // for (int i = oldNumSurfaces; i < numSurfaces; i++) { GuiBrainModelSelectionComboBox* modelComboBox = new GuiBrainModelSelectionComboBox( false, true, false, "None", NULL); modelComboBox->setSelectedBrainModel(defaultSurfaces[i]); QLabel* label = new QLabel(""); surfaceLabels.push_back(label); surfaceComboBoxes.push_back(modelComboBox); surfaceGridLayout->addWidget(label, i, 0); surfaceGridLayout->addWidget(modelComboBox, i, 1); } // // Update/hide combo boxes // for (int i = 0; i < static_cast(surfaceComboBoxes.size()); i++) { // // Update combo box // surfaceComboBoxes[i]->updateComboBox(); if (i < numSurfaces) { // // show labels and combo box // surfaceLabels[i]->show(); surfaceComboBoxes[i]->show(); // // Update labels // if (i == 0) { surfaceLabels[i]->setText("First Surface"); } else if (i == (numSurfaces - 1)) { surfaceLabels[i]->setText("Final Surface"); } else { surfaceLabels[i]->setText(QString("Surface %1").arg(i + 1)); } // // If brain set has changed // if (prevSpecLoadTime != specLoadTime) { if (i < static_cast(defaultSurfaces.size())) { surfaceComboBoxes[i]->setSelectedBrainModel(defaultSurfaces[i]); } } } else { surfaceLabels[i]->hide(); surfaceComboBoxes[i]->hide(); } } // // // save for next time prevSpecLoadTime = specLoadTime; } /** * Called when apply button pressed. */ void GuiInterpolateSurfacesDialog::slotApplyButton() { // // Get the topology file to be used for interpolation // TopologyFile* topologyFile = topologyComboBox->getSelectedTopologyFile(); if (topologyFile == NULL) { QMessageBox::critical(this, "Error", "You must have a topology file."); return; } // // Get the surfaces selected by the user // std::vector inputSurfaces; // DO NOT FREE AS POINT TO BRAIN SET std::vector surfaces; // FREE AT END OF METHOD for (unsigned int i = 0; i < surfaceComboBoxes.size(); i++) { BrainModelSurface* bms = surfaceComboBoxes[i]->getSelectedBrainModelSurface(); if (bms != NULL) { inputSurfaces.push_back(bms); surfaces.push_back(new BrainModelSurface(*bms)); } } // // Must have at least two surfaces // if (surfaces.size() < 2) { // // Free Memory // for (unsigned int k = 0; k < surfaces.size(); k++) { delete surfaces[k]; } surfaces.clear(); QMessageBox::critical(this, "Error", "You must select at least two surfaces."); return; } // // Apply scaling to the surfaces to that they fit the main window // for (unsigned int k = 0; k < surfaces.size(); k++) { // // Copy scaling since not copied as part of copy constructor // //float scale[3]; //inputSurfaces[k]->getScaling(BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW, // scale); //surfaces[k]->setScaling(BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW, // scale); //surfaces[k]->applyCurrentView(BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW, // false, // false, // true); surfaces[k]->copyTransformations(inputSurfaces[k], BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW, BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW); surfaces[k]->applyCurrentView(BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW, true, true, true); } // // Point to first surface and add it to the brain set temporarily // BrainModelSurface* surface = new BrainModelSurface(*(surfaces[0])); theMainWindow->getBrainSet()->addBrainModel(surface); const int numNodes = surface->getNumberOfNodes(); CoordinateFile* surfaceCoords = surface->getCoordinateFile(); // // Set the type of surface to the special type // surface->setSurfaceType(BrainModelSurface::SURFACE_TYPE_UNSPECIFIED); // // Update any projected files // updateProjectedFiles(surface); // // Copy view from the first brain model // //surface->copyTransformations(surfaces[0], // BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW, // BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW); // // Display this surface in the main window // theMainWindow->displayBrainModelInMainWindow(surface); // // Add the topology file to the new surfaces // surface->setTopologyFile(topologyFile); // // Number of interpolation steps // const int numSteps = interpolationStepsSpinBox->value(); const float stepSize = 1.0 / static_cast(numSteps + 1); // // Interpolate between the surfaces // for (int j = 0; j < static_cast(surfaces.size()); j++) { // // surface for start of this iteration // const BrainModelSurface* iterationSurface = surfaces[j]; const CoordinateFile* iterationCoords = iterationSurface->getCoordinateFile(); // // Use transform of first surface for all except flat surfaces // /* if ((surfaces[j]->getSurfaceType() != BrainModelSurface::SURFACE_TYPE_FLAT) && (surfaces[j]->getSurfaceType() != BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR)) { surface->copyTransformations(surfaces[0], BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW, BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW); } else { surface->copyTransformations(surfaces[j], BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW, BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW); } */ // // load the coordinates of the "jTH" surface into the new surface // for (int i = 0; i < numNodes; i++) { surfaceCoords->setCoordinate(i, iterationCoords->getCoordinate(i)); } // // Update any projected files // updateProjectedFiles(surface); // // Get the type of surface // const BrainModelSurface::SURFACE_TYPES surfaceType = iterationSurface->getSurfaceType(); // // Does the user want the surface rotated ? // if (rotateSurfacesCheckBox->isChecked()) { // // Do not rotate a flat surface // if ((surfaceType != BrainModelSurface::SURFACE_TYPE_FLAT) && (surfaceType != BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR)) { // // Determine amount to rotate each increment so that a total // of 360 degrees of rotation is made // const int numRotationSteps = static_cast(360.0 / rotationStepDoubleSpinBox->value()); const float rotationDelta = 360.0 / numRotationSteps; // // Rotate the surface for the needed number of iterations // vtkTransform* matrix = surface->getRotationTransformMatrix( BrainModel:: BRAIN_MODEL_VIEW_MAIN_WINDOW); for (int j = 0; j < numRotationSteps; j++) { matrix->RotateY(rotationDelta); // // Display the surface // GuiBrainModelOpenGL::updateAllGL(theMainWindow->getBrainModelOpenGL()); } } } else { // // Display the surface // GuiBrainModelOpenGL::updateAllGL(theMainWindow->getBrainModelOpenGL()); } // // If not the last surface // if (j < static_cast(surfaces.size() - 1)) { // // Compute the delta coordinates for interpolating // const BrainModelSurface* nextSurface = surfaces[j+1]; const CoordinateFile* nextCoords = nextSurface->getCoordinateFile(); CoordinateFile deltaCoords; deltaCoords.setNumberOfCoordinates(numNodes); for (int i = 0; i < numNodes; i++) { const float* p2 = nextCoords->getCoordinate(i); const float* p1 = surfaceCoords->getCoordinate(i); const float dxyz[3] = { (p2[0] - p1[0]) * stepSize, (p2[1] - p1[1]) * stepSize, (p2[2] - p1[2]) * stepSize }; deltaCoords.setCoordinate(i, dxyz); } // // Interpolate // for (int k = 0; k < numSteps; k++) { // // Update the surface normals // surface->computeNormals(); // // Display the surface // GuiBrainModelOpenGL::updateAllGL(theMainWindow->getBrainModelOpenGL()); // // Add deltas to the surface coordinates // for (int i = 0; i < numNodes; i++) { float xyz[3]; surfaceCoords->getCoordinate(i, xyz); const float* dxyz = deltaCoords.getCoordinate(i); xyz[0] += dxyz[0]; xyz[1] += dxyz[1]; xyz[2] += dxyz[2]; surfaceCoords->setCoordinate(i, xyz); } // // Update projected files // updateProjectedFiles(surface); } } } // // Set the current surface to the last surface // const int lastSurfaceIndex = static_cast(surfaces.size() - 1); // if ((surfaces[lastSurfaceIndex]->getSurfaceType() != BrainModelSurface::SURFACE_TYPE_FLAT) && // (surfaces[lastSurfaceIndex]->getSurfaceType() != BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR)) { // surfaces[lastSurfaceIndex]->copyTransformations(surface, 0, 0); // } theMainWindow->displayBrainModelInMainWindow(inputSurfaces[lastSurfaceIndex]); // // Remove the temporary surface from the brain set and delete it // theMainWindow->getBrainSet()->deleteBrainModel(surface); GuiFilesModified fm; fm.setCoordinateModified(); fm.setInhibitSurfaceDefaultScaling(); // do NOT scale surfaces for default scaling theMainWindow->fileModificationUpdate(fm); // // Update the display // GuiBrainModelOpenGL::updateAllGL(theMainWindow->getBrainModelOpenGL()); // // Free Memory // for (unsigned int k = 0; k < surfaces.size(); k++) { delete surfaces[k]; } surfaces.clear(); } /* void GuiInterpolateSurfacesDialog::slotApplyButton() { // // Get the surfaces selected by the user // std::vector surfaces; for (unsigned int i = 0; i < surfaceComboBoxes.size(); i++) { BrainModelSurface* bms = surfaceComboBoxes[i]->getSelectedBrainModelSurface(); if (bms != NULL) { surfaces.push_back(bms); } } // // Must have at least two surfaces // if (surfaces.size() < 2) { GuiMessageBox::critical(this, "Error", "You must select at least two surfaces.", "OK"); return; } // // Get the topology file to be used for interpolation // TopologyFile* topologyFile = topologyComboBox->getSelectedTopologyFile(); if (topologyFile == NULL) { GuiMessageBox::critical(this, "Error", "You must have a topology file.", "OK"); return; } // // Create a new brain model surface by copying the first surface // BrainModelSurface* surface = new BrainModelSurface(*(surfaces[0])); theMainWindow->getBrainSet()->addBrainModel(surface); const int numNodes = surface->getNumberOfNodes(); CoordinateFile* surfaceCoords = surface->getCoordinateFile(); // // Set the type of surface to the special type // surface->setSurfaceType(BrainModelSurface::SURFACE_TYPE_UNSPECIFIED); // // Update any projected files // updateProjectedFiles(surface); // // Copy view from the first brain model // surface->copyTransformations(surfaces[0], BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW, BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW); // // Display this surface in the main window // theMainWindow->displayBrainModelInMainWindow(surface); // // Add the topology file to the new surfaces // surface->setTopologyFile(topologyFile); // // Number of interpolation steps // const int numSteps = interpolationStepsSpinBox->value(); const float stepSize = 1.0 / static_cast(numSteps + 1); // // Interpolate between the surfaces // for (int j = 0; j < static_cast(surfaces.size()); j++) { // // surface for start of this iteration // const BrainModelSurface* iterationSurface = surfaces[j]; const CoordinateFile* iterationCoords = iterationSurface->getCoordinateFile(); // // Use transform of first surface for all except flat surfaces // if ((surfaces[j]->getSurfaceType() != BrainModelSurface::SURFACE_TYPE_FLAT) && (surfaces[j]->getSurfaceType() != BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR)) { surface->copyTransformations(surfaces[0], BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW, BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW); } else { surface->copyTransformations(surfaces[j], BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW, BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW); } // // load the coordinates of the "jTH" surface into the new surface // for (int i = 0; i < numNodes; i++) { surfaceCoords->setCoordinate(i, iterationCoords->getCoordinate(i)); } // // Update any projected files // updateProjectedFiles(surface); // // Get the type of surface // const BrainModelSurface::SURFACE_TYPES surfaceType = iterationSurface->getSurfaceType(); // // Does the user want the surface rotated ? // if (rotateSurfacesCheckBox->isChecked()) { // // Do not rotate a flat surface // if ((surfaceType != BrainModelSurface::SURFACE_TYPE_FLAT) && (surfaceType != BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR)) { // // Determine amount to rotate each increment so that a total // of 360 degrees of rotation is made // const int numRotationSteps = static_cast(360.0 / rotationStepDoubleSpinBox->value()); const float rotationDelta = 360.0 / numRotationSteps; // // Rotate the surface for the needed number of iterations // vtkTransform* matrix = surface->getRotationTransformMatrix( BrainModel:: BRAIN_MODEL_VIEW_MAIN_WINDOW); for (int j = 0; j < numRotationSteps; j++) { matrix->RotateY(rotationDelta); // // Display the surface // GuiBrainModelOpenGL::updateAllGL(theMainWindow->getBrainModelOpenGL()); } } } else { // // Display the surface // GuiBrainModelOpenGL::updateAllGL(theMainWindow->getBrainModelOpenGL()); } // // If not the last surface // if (j < static_cast(surfaces.size() - 1)) { // // Compute the delta coordinates for interpolating // const BrainModelSurface* nextSurface = surfaces[j+1]; const CoordinateFile* nextCoords = nextSurface->getCoordinateFile(); CoordinateFile deltaCoords; deltaCoords.setNumberOfCoordinates(numNodes); for (int i = 0; i < numNodes; i++) { const float* p2 = nextCoords->getCoordinate(i); const float* p1 = surfaceCoords->getCoordinate(i); const float dxyz[3] = { (p2[0] - p1[0]) * stepSize, (p2[1] - p1[1]) * stepSize, (p2[2] - p1[2]) * stepSize }; deltaCoords.setCoordinate(i, dxyz); } // // Compute delta scaling for interpolating // float scaling[3]; iterationSurface->getScaling(0, scaling); float nextScaling[3]; nextSurface->getScaling(0, nextScaling); const float deltaScaling[3] = { (nextScaling[0] - scaling[0]) * stepSize, (nextScaling[1] - scaling[1]) * stepSize, (nextScaling[2] - scaling[2]) * stepSize, }; // // Interpolate // for (int k = 0; k < numSteps; k++) { // // Update the surface normals // surface->computeNormals(); // // Display the surface // GuiBrainModelOpenGL::updateAllGL(theMainWindow->getBrainModelOpenGL()); // // Add deltas to the surface coordinates // for (int i = 0; i < numNodes; i++) { float xyz[3]; surfaceCoords->getCoordinate(i, xyz); const float* dxyz = deltaCoords.getCoordinate(i); xyz[0] += dxyz[0]; xyz[1] += dxyz[1]; xyz[2] += dxyz[2]; surfaceCoords->setCoordinate(i, xyz); } // // Update default scaling // scaling[0] += deltaScaling[0]; scaling[1] += deltaScaling[1]; scaling[2] += deltaScaling[2]; //surface->setScaling(0, scaling); // // Update projected files // updateProjectedFiles(surface); } } } // // Set the current surface to the last surface // const int lastSurfaceIndex = static_cast(surfaces.size() - 1); if ((surfaces[lastSurfaceIndex]->getSurfaceType() != BrainModelSurface::SURFACE_TYPE_FLAT) && (surfaces[lastSurfaceIndex]->getSurfaceType() != BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR)) { surfaces[lastSurfaceIndex]->copyTransformations(surface, 0, 0); } theMainWindow->displayBrainModelInMainWindow(surfaces[lastSurfaceIndex]); // // Remove the temporary surface from the brain set and delete it // theMainWindow->getBrainSet()->deleteBrainModel(surface); GuiFilesModified fm; fm.setCoordinateModified(); theMainWindow->fileModificationUpdate(fm); // // Update the display // GuiBrainModelOpenGL::updateAllGL(theMainWindow->getBrainModelOpenGL()); } */ void GuiInterpolateSurfacesDialog::updateProjectedFiles(const BrainModelSurface* bms) { if (reprojectBordersCheckBox->isChecked()) { BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); bmbs->unprojectBorders(bms); } } caret-5.6.4~dfsg.1.orig/caret/GuiInflateSurfaceDialog.h0000664000175000017500000000331111572067322022506 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_INFLATE_SURFACE_DIALOG_H__ #define __GUI_INFLATE_SURFACE_DIALOG_H__ #include "WuQDialog.h" class QSpinBox; class QDoubleSpinBox; /// Dialog for surface inflation class GuiInflateSurfaceDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiInflateSurfaceDialog(QWidget* parent); /// Destructor ~GuiInflateSurfaceDialog(); public slots: /// called when Apply button pressed void slotApplyButton(); private: /// number of smoothing iterations spin box QSpinBox* smoothingIterationsSpinBox; /// number of inflate every X iterations spin box QSpinBox* inflateIterationsSpinBox; /// inflation factor float spin box QDoubleSpinBox* inflationFactorDoubleSpinBox; }; #endif // __GUI_INFLATE_SURFACE_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiInflateSurfaceDialog.cxx0000664000175000017500000001133111572067322023062 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include "BrainModelSurface.h" #include "BrainSet.h" #include "GuiBrainModelOpenGL.h" #include "GuiInflateSurfaceDialog.h" #include "GuiMainWindow.h" #include #include "QtUtilities.h" #include "global_variables.h" /** * Constructor */ GuiInflateSurfaceDialog::GuiInflateSurfaceDialog(QWidget* parent) : WuQDialog(parent) { setWindowTitle("Surface Inflation"); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // Smoothing iterations // QLabel* smoothingIterationsLabel = new QLabel("Smoothing Iterations"); smoothingIterationsSpinBox = new QSpinBox; smoothingIterationsSpinBox->setMinimum(1); smoothingIterationsSpinBox->setMaximum(1000000); smoothingIterationsSpinBox->setSingleStep(10); smoothingIterationsSpinBox->setValue(500); // // Inflation iterations // QLabel* inflateIterationsLabel = new QLabel("Inflate Every X Iterations"); inflateIterationsSpinBox = new QSpinBox; inflateIterationsSpinBox->setMinimum(1); inflateIterationsSpinBox->setMaximum(1000000); inflateIterationsSpinBox->setSingleStep(10); inflateIterationsSpinBox->setValue(10); // // Inflation factor // QLabel* inflationFactorLabel = new QLabel("Inflation Factor"); inflationFactorDoubleSpinBox = new QDoubleSpinBox; inflationFactorDoubleSpinBox->setMinimum(1.0); inflationFactorDoubleSpinBox->setMaximum(2.0); inflationFactorDoubleSpinBox->setSingleStep(0.01); inflationFactorDoubleSpinBox->setDecimals(2); inflationFactorDoubleSpinBox->setValue(1.02); // // grid layout for items // QGridLayout* gridLayout = new QGridLayout; gridLayout->setSpacing(5); dialogLayout->addLayout(gridLayout); gridLayout->addWidget(smoothingIterationsLabel, 0, 0); gridLayout->addWidget(smoothingIterationsSpinBox, 0, 1); gridLayout->addWidget(inflateIterationsLabel, 1, 0); gridLayout->addWidget(inflateIterationsSpinBox, 1, 1); gridLayout->addWidget(inflationFactorLabel, 2, 0); gridLayout->addWidget(inflationFactorDoubleSpinBox, 2, 1); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); dialogLayout->addLayout(buttonsLayout); // // Apply button // QPushButton* applyButton = new QPushButton("Apply"); applyButton->setAutoDefault(false); buttonsLayout->addWidget(applyButton); QObject::connect(applyButton, SIGNAL(clicked()), this, SLOT(slotApplyButton())); // // Close button // QPushButton* closeButton = new QPushButton("Close"); closeButton->setAutoDefault(false); buttonsLayout->addWidget(closeButton); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); QtUtilities::makeButtonsSameSize(applyButton, closeButton); } /** * Destructor */ GuiInflateSurfaceDialog::~GuiInflateSurfaceDialog() { } /** * called when OK or Cancel button pressed. */ void GuiInflateSurfaceDialog::slotApplyButton() { BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms == NULL) { QMessageBox::critical(this, "ERROR", "There is no surface in the main window."); return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); bms->inflate(smoothingIterationsSpinBox->value(), inflateIterationsSpinBox->value(), inflationFactorDoubleSpinBox->value()); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); theMainWindow->speakText("Surface inflation has completed.", false); } caret-5.6.4~dfsg.1.orig/caret/GuiInflateAndSmoothFingersDialog.h0000664000175000017500000000506111572067322024334 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_INFLATE_AND_SMOOTH_FINGERS_DIALOG_H__ #define __GUI_INFLATE_AND_SMOOTH_FINGERS_DIALOG_H__ #include #include "WuQDialog.h" class QCheckBox; class QLabel; class QRadioButton; class QSpinBox; class QDoubleSpinBox; /// Dialog for surface smoothing. class GuiInflateAndSmoothFingersDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiInflateAndSmoothFingersDialog(QWidget* parent, const bool modal); /// Destructor ~GuiInflateAndSmoothFingersDialog(); private slots: /// callde when apply button pressed void slotApply(); /// called during modal operation virtual void done(int r); private: /// called to execute the smoothing bool doSmoothing(); /// smoothing cycles spin box QSpinBox* smoothingCyclesSpinBox; /// regular smoothing strength float spin box QDoubleSpinBox* regularSmoothStrengthDoubleSpinBox; /// regular smoothing iterations spin box QSpinBox* regularSmoothIterationsSpinBox; /// inflation factor float spin box QDoubleSpinBox* inflationFactorDoubleSpinBox; /// finger smoothing threshold float spin box QDoubleSpinBox* fingerSmoothingThresholdDoubleSpinBox; /// finger smooothing strength float spin box QDoubleSpinBox* fingerSmoothingStrengthDoubleSpinBox; /// finger smoothing iterations spin box QSpinBox* fingerSmoothingIterationsSpinBox; /// add measurements to metrics check box QCheckBox* addToMetricsCheckBox; }; #endif // __GUI_INFLATE_AND_SMOOTH_FINGERS_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiInflateAndSmoothFingersDialog.cxx0000664000175000017500000002354011572067322024711 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include "BrainModelSurface.h" #include "BrainSet.h" #include "GuiBrainModelOpenGL.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "GuiInflateAndSmoothFingersDialog.h" #include #include "QtUtilities.h" #include "global_variables.h" /** * Constructor. */ GuiInflateAndSmoothFingersDialog::GuiInflateAndSmoothFingersDialog(QWidget* parent, const bool modalFlag) : WuQDialog(parent) { setModal(modalFlag); setWindowTitle("Inflate Surface And Smooth Fingers"); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // Smoothing cycles // QLabel* smoothingCyclesLabel = new QLabel("Number of Smoothing Cycles"); smoothingCyclesSpinBox = new QSpinBox; smoothingCyclesSpinBox->setMinimum(1); smoothingCyclesSpinBox->setMaximum(100000); smoothingCyclesSpinBox->setSingleStep(1); smoothingCyclesSpinBox->setValue(3); // // regular smoothing strength // QLabel* regularSmoothingStrengthLabel = new QLabel("Regular Smoothing Strength"); regularSmoothStrengthDoubleSpinBox = new QDoubleSpinBox; regularSmoothStrengthDoubleSpinBox->setMinimum(0.0); regularSmoothStrengthDoubleSpinBox->setMaximum(1.0); regularSmoothStrengthDoubleSpinBox->setSingleStep(0.01); regularSmoothStrengthDoubleSpinBox->setDecimals(2); regularSmoothStrengthDoubleSpinBox->setValue(1.0); // // regular smoothing iterations spin box // QLabel* regularSmoothingIterationsLabel = new QLabel("Regular Smoothing Iterations"); regularSmoothIterationsSpinBox = new QSpinBox; regularSmoothIterationsSpinBox->setMinimum(1); regularSmoothIterationsSpinBox->setMaximum(100000); regularSmoothIterationsSpinBox->setSingleStep(1); regularSmoothIterationsSpinBox->setValue(50); // // Inflation Factor // QLabel* inflationFactorLabel = new QLabel("Inflation Factor"); inflationFactorDoubleSpinBox = new QDoubleSpinBox; inflationFactorDoubleSpinBox->setMinimum(0.0); inflationFactorDoubleSpinBox->setMaximum(100.0); inflationFactorDoubleSpinBox->setSingleStep(0.1); inflationFactorDoubleSpinBox->setDecimals(2); inflationFactorDoubleSpinBox->setValue(1.02); // // Finger smoothing threshold float spin box // QLabel* fingerSmoothingThresholdLabel = new QLabel("Finger Smoothing Threshold"); fingerSmoothingThresholdDoubleSpinBox = new QDoubleSpinBox; fingerSmoothingThresholdDoubleSpinBox->setMinimum(0.0); fingerSmoothingThresholdDoubleSpinBox->setMaximum(1000.0); fingerSmoothingThresholdDoubleSpinBox->setSingleStep(0.1); fingerSmoothingThresholdDoubleSpinBox->setDecimals(2); fingerSmoothingThresholdDoubleSpinBox->setValue(1.0); // // Finger smoothing strength float spin box // QLabel* fingerSmoothingStrengthLabel = new QLabel("Finger Smoothing Strength"); fingerSmoothingStrengthDoubleSpinBox = new QDoubleSpinBox; fingerSmoothingStrengthDoubleSpinBox->setMinimum(0.0); fingerSmoothingStrengthDoubleSpinBox->setMaximum(1.0); fingerSmoothingStrengthDoubleSpinBox->setSingleStep(0.01); fingerSmoothingStrengthDoubleSpinBox->setDecimals(2); fingerSmoothingStrengthDoubleSpinBox->setValue(1.0); // // Fingers smoothing iterations // QLabel* fingerSmoothingIterationsLabel = new QLabel("Finger Smoothing Iterations"); fingerSmoothingIterationsSpinBox = new QSpinBox; fingerSmoothingIterationsSpinBox->setMinimum(0); fingerSmoothingIterationsSpinBox->setMaximum(100000); fingerSmoothingIterationsSpinBox->setSingleStep(10); fingerSmoothingIterationsSpinBox->setValue(100); // // Grid layout for parameters // QGridLayout* parametersGridLayout = new QGridLayout; parametersGridLayout->setSpacing(5); dialogLayout->addLayout(parametersGridLayout); parametersGridLayout->addWidget(smoothingCyclesLabel, 0, 0); parametersGridLayout->addWidget(smoothingCyclesSpinBox, 0, 1); parametersGridLayout->addWidget(regularSmoothingStrengthLabel, 1, 0); parametersGridLayout->addWidget(regularSmoothStrengthDoubleSpinBox, 1, 1); parametersGridLayout->addWidget(regularSmoothingIterationsLabel, 2, 0); parametersGridLayout->addWidget(regularSmoothIterationsSpinBox, 2, 1); parametersGridLayout->addWidget(inflationFactorLabel, 3, 0); parametersGridLayout->addWidget(inflationFactorDoubleSpinBox, 3, 1); parametersGridLayout->addWidget(fingerSmoothingThresholdLabel, 4, 0); parametersGridLayout->addWidget(fingerSmoothingThresholdDoubleSpinBox, 4, 1); parametersGridLayout->addWidget(fingerSmoothingStrengthLabel, 5, 0); parametersGridLayout->addWidget(fingerSmoothingStrengthDoubleSpinBox, 5, 1); parametersGridLayout->addWidget(fingerSmoothingIterationsLabel, 6, 0); parametersGridLayout->addWidget(fingerSmoothingIterationsSpinBox, 6, 1); // // Add measurements to metrics check box // addToMetricsCheckBox = new QCheckBox("Add Measurements to Metrics", this); dialogLayout->addWidget(addToMetricsCheckBox); addToMetricsCheckBox->setChecked(true); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); dialogLayout->addLayout(buttonsLayout); if (isModal()) { // // OK button // QPushButton* okButton = new QPushButton("OK"); buttonsLayout->addWidget(okButton); QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); // // Cancel button // QPushButton* cancelButton = new QPushButton("Cancel"); buttonsLayout->addWidget(cancelButton); QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); QtUtilities::makeButtonsSameSize(okButton, cancelButton); } else { // // Apply button // QPushButton* applyButton = new QPushButton("Apply"); buttonsLayout->addWidget(applyButton); QObject::connect(applyButton, SIGNAL(clicked()), this, SLOT(slotApply())); // // Close button connects to QDialogs close() slot. // QPushButton* closeButton = new QPushButton("Close"); buttonsLayout->addWidget(closeButton); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); QtUtilities::makeButtonsSameSize(applyButton, closeButton); } } /** * Destructor. */ GuiInflateAndSmoothFingersDialog::~GuiInflateAndSmoothFingersDialog() { } /** * Slot for OK or Cancel button in modal mode. */ void GuiInflateAndSmoothFingersDialog::done(int r) { if (r == QDialog::Accepted) { if (doSmoothing()) { return; } } QDialog::done(r); } /** * Slot for apply button in non-modal mode. */ void GuiInflateAndSmoothFingersDialog::slotApply() { doSmoothing(); } /** * Called to do the actual smoothing. Returns true if an error occurs. */ bool GuiInflateAndSmoothFingersDialog::doSmoothing() { const int numCycles = smoothingCyclesSpinBox->value(); const float regularStrength = regularSmoothStrengthDoubleSpinBox->value(); const int regularIterations = regularSmoothIterationsSpinBox->value(); const float inflationFactor = inflationFactorDoubleSpinBox->value(); const float fingerThreshold = fingerSmoothingThresholdDoubleSpinBox->value(); const float fingerStrength = fingerSmoothingStrengthDoubleSpinBox->value(); const int fingerIterations = fingerSmoothingIterationsSpinBox->value(); BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); MetricFile* mf = NULL; if (addToMetricsCheckBox->isChecked()) { mf = theMainWindow->getBrainSet()->getMetricFile(); } bms->inflateSurfaceAndSmoothFingers(theMainWindow->getBrainSet()->getActiveFiducialSurface(), numCycles, regularStrength, regularIterations, inflationFactor, fingerThreshold, fingerStrength, fingerIterations, mf); GuiFilesModified fm; fm.setMetricModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(theMainWindow->getBrainModelOpenGL()); QApplication::restoreOverrideCursor(); theMainWindow->speakText("Surface inflation and finger smoothing is complete.", false); } return false; } caret-5.6.4~dfsg.1.orig/caret/GuiImageViewingWindow.h0000664000175000017500000000576211572067322022252 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_IMAGE_VIEWING_WINDOW_H__ #define __GUI_IMAGE_VIEWING_WINDOW_H__ #include "WuQDialog.h" #include "SceneFile.h" class QComboBox; class QLabel; /// Dialog used to display images class GuiImageViewingWindow : public WuQDialog { Q_OBJECT public: /// Constructor GuiImageViewingWindow(QWidget* parent); /// Destructor ~GuiImageViewingWindow(); /// update the toolbar void updateWindow(); /// display the image in the window void displayImage(const int imageNumberIn); /// get the displayed image number int getDisplayedImageNumber() const { return imageNumber; } /// save scene SceneFile::SceneClass saveScene(); /// show scene void showScene(const SceneFile::SceneClass sc); protected slots: /// called when an image is selected void slotImageSelectionComboBox(int item); /// called when an image is resized void slotImageSizeComboBox(int item); protected: /// size of image enum IMAGE_SIZE { /// scale image to 25% of its original size IMAGE_SIZE_25, /// scale image to 50% of its original size IMAGE_SIZE_50, /// scale image to 75% of its original size IMAGE_SIZE_75, /// scale image to 100% of its original size IMAGE_SIZE_100, /// scale image to 125% of its original size IMAGE_SIZE_125, /// scale image to 150% of its original size IMAGE_SIZE_150, /// scale image to 200% of its original size IMAGE_SIZE_200, /// scale image to 400% of its original size IMAGE_SIZE_400, /// scale image to 800% of its original size IMAGE_SIZE_800 }; /// image size combo box QComboBox* imageSizeComboBox; /// the image selection combo box QComboBox* imageSelectionComboBox; /// currently viewed image int imageNumber; /// the label that will contain the image QLabel* imageLabel; }; #endif // __GUI_IMAGE_VIEWING_WINDOW_H__ caret-5.6.4~dfsg.1.orig/caret/GuiImageViewingWindow.cxx0000664000175000017500000003005111572067322022612 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include "BrainSet.h" #include "DebugControl.h" #include "FileUtilities.h" #include "GuiImageViewingWindow.h" #include "GuiMainWindow.h" #include "ImageFile.h" #include "StringUtilities.h" #include "global_variables.h" /** * The Constructor. */ GuiImageViewingWindow::GuiImageViewingWindow(QWidget* parent) : WuQDialog(parent) { setAttribute(Qt::WA_DeleteOnClose); setWindowTitle("Image Viewing Window"); // // selection and size // QGroupBox* selHGroupBox = new QGroupBox("Image Selection and Scaling"); imageSelectionComboBox = new QComboBox; imageSelectionComboBox->setFixedHeight(imageSelectionComboBox->sizeHint().height()); imageSelectionComboBox->setToolTip( "Use this control to choose\n" "the displayed image."); QObject::connect(imageSelectionComboBox, SIGNAL(activated(int)), this, SLOT(slotImageSelectionComboBox(int))); imageSizeComboBox = new QComboBox; imageSizeComboBox->setFixedHeight(imageSizeComboBox->sizeHint().height()); imageSizeComboBox->addItem(" 25%"); imageSizeComboBox->addItem(" 50%"); imageSizeComboBox->addItem(" 75%"); imageSizeComboBox->addItem("100%"); imageSizeComboBox->addItem("125%"); imageSizeComboBox->addItem("150%"); imageSizeComboBox->addItem("200%"); imageSizeComboBox->addItem("400%"); imageSizeComboBox->addItem("800%"); imageSizeComboBox->setCurrentIndex(IMAGE_SIZE_100); imageSizeComboBox->setToolTip( "Use this control to change\n" "the image's display size."); QObject::connect(imageSizeComboBox, SIGNAL(activated(int)), this, SLOT(slotImageSizeComboBox(int))); // // the image label // imageLabel = new QLabel; //imageLabel->setFrameStyle(QFrame::StyledPanel + QFrame::Plain); imageLabel->setLineWidth(2); // // Image Group Box // QGroupBox* imageGroupBox = new QGroupBox("Image"); QVBoxLayout* imageLayout = new QVBoxLayout(imageGroupBox); imageLayout->addWidget(imageLabel); // // Close Button // QPushButton* closeButton = new QPushButton("Close"); closeButton->setAutoDefault(false); closeButton->setFixedSize(closeButton->sizeHint()); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); // // Layouts for the dialog // QHBoxLayout* sizeScaleLayout = new QHBoxLayout; sizeScaleLayout->addWidget(imageSelectionComboBox); sizeScaleLayout->addWidget(imageSizeComboBox); sizeScaleLayout->setStretchFactor(imageSelectionComboBox, 100); sizeScaleLayout->setStretchFactor(imageSizeComboBox, 0); selHGroupBox->setLayout(sizeScaleLayout); QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->addWidget(closeButton); QVBoxLayout* dialogLayout = new QVBoxLayout; dialogLayout->setSpacing(5); dialogLayout->addWidget(selHGroupBox); dialogLayout->addWidget(imageGroupBox); dialogLayout->addLayout(buttonsLayout); setLayout(dialogLayout); selHGroupBox->setFixedHeight(selHGroupBox->sizeHint().height()); imageNumber = 0; updateWindow(); } /** * The Destructor. */ GuiImageViewingWindow::~GuiImageViewingWindow() { theMainWindow->removeImageViewingWindow(this); } /** * called when an image is selected. */ void GuiImageViewingWindow::slotImageSelectionComboBox(int item) { imageSizeComboBox->blockSignals(true); //imageSizeComboBox->setCurrentIndex(IMAGE_SIZE_100); imageSizeComboBox->blockSignals(false); displayImage(item); } /** * called when an image is resized. */ void GuiImageViewingWindow::slotImageSizeComboBox(int /*item*/) { displayImage(imageNumber); } /** */ void GuiImageViewingWindow::updateWindow() { const int numImages = theMainWindow->getBrainSet()->getNumberOfImageFiles(); if (imageNumber >= numImages) { imageNumber = 0; } displayImage(imageNumber); imageSelectionComboBox->blockSignals(true); imageSelectionComboBox->clear(); for (int i = 0; i < numImages; i++) { ImageFile* img = theMainWindow->getBrainSet()->getImageFile(i); imageSelectionComboBox->addItem(FileUtilities::basename(img->getFileName())); } if ((imageNumber >= 0) && (imageNumber < imageSelectionComboBox->count())) { imageSelectionComboBox->setCurrentIndex(imageNumber); } imageSelectionComboBox->blockSignals(false); } /** */ void GuiImageViewingWindow::displayImage(const int imageNumberIn) { const int windowX = std::max(x(), 10); const int windowY = std::max(y(), 10); const int numImages = theMainWindow->getBrainSet()->getNumberOfImageFiles(); imageNumber = imageNumberIn; QImage image; if ((imageNumber >= 0) && (imageNumber < numImages)) { ImageFile* img = theMainWindow->getBrainSet()->getImageFile(imageNumber); image = *(img->getImage()); } float w = image.width(); float h = image.height(); switch (static_cast(imageSizeComboBox->currentIndex())) { case IMAGE_SIZE_25: w *= 0.25; h *= 0.25; break; case IMAGE_SIZE_50: w *= 0.50; h *= 0.50; break; case IMAGE_SIZE_75: w *= 0.75; h *= 0.75; break; case IMAGE_SIZE_100: w *= 1.0; h *= 1.0; break; case IMAGE_SIZE_125: w *= 1.25; h *= 1.25; break; case IMAGE_SIZE_150: w *= 1.50; h *= 1.50; break; case IMAGE_SIZE_200: w *= 2.0; h *= 2.0; break; case IMAGE_SIZE_400: w *= 4.0; h *= 4.0; break; case IMAGE_SIZE_800: w *= 8.0; h *= 8.0; break; } if ((w > 0.0) && (h > 0.0)) { image = image.scaled(static_cast(w), static_cast(h), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); } imageLabel->setPixmap(QPixmap::fromImage(image)); //imageLabel->setFixedSize(imageLabel->sizeHint()); // // Allows dialog to resize to fit image and don't let it change position // setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); move(windowX, windowY); setMinimumSize(sizeHint()); setMaximumSize(sizeHint()); updateGeometry(); imageLabel->adjustSize(); resize(sizeHint()); adjustSize(); move(windowX, windowY); if (DebugControl::getDebugOn()) { const QSize qs1 = sizeHint(); const QSize qs2 = size(); const QSize qs3 = maximumSize(); std::cout << "Image View Window Size Hint: " << qs1.width() << ", " << qs1.height() << std::endl; std::cout << "Image View Window Size: " << qs2.width() << ", " << qs2.height() << std::endl; std::cout << "Image View Window Max Size: " << qs3.width() << ", " << qs3.height() << std::endl; } } /** * save scene. */ SceneFile::SceneClass GuiImageViewingWindow::saveScene() { SceneFile::SceneClass sc("ImageViewingWindow"); const ImageFile* img = theMainWindow->getBrainSet()->getImageFile(imageNumber); if (img != NULL) { const int geometry[4] = { x(), y(), width(), height() }; std::ostringstream str; str << geometry[0] << " " << geometry[1] << " " << geometry[2] << " " << geometry[3]; sc.addSceneInfo(SceneFile::SceneInfo("Geometry", str.str().c_str())); sc.addSceneInfo(SceneFile::SceneInfo("ImageName", FileUtilities::basename(img->getFileName()))); QString sizeString; switch (static_cast(imageSizeComboBox->currentIndex())) { case IMAGE_SIZE_25: sizeString = "25"; break; case IMAGE_SIZE_50: sizeString = "50"; break; case IMAGE_SIZE_75: sizeString = "75"; break; case IMAGE_SIZE_100: sizeString = "100"; break; case IMAGE_SIZE_125: sizeString = "125"; break; case IMAGE_SIZE_150: sizeString = "150"; break; case IMAGE_SIZE_200: sizeString = "200"; break; case IMAGE_SIZE_400: sizeString = "400"; break; case IMAGE_SIZE_800: sizeString = "800"; break; } if (sizeString.isEmpty() == false) { sc.addSceneInfo(SceneFile::SceneInfo("ImageScale", sizeString)); } } return sc; } /** * show scene. */ void GuiImageViewingWindow::showScene(const SceneFile::SceneClass sc) { QString imageName; QString sizeString; int geometry[4] = { 0, 0, 0, 0 }; const int num = sc.getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc.getSceneInfo(i); const QString infoName = si->getName(); if (infoName == "ImageName") { imageName = si->getValueAsString(); } else if (infoName == "ImageScale") { sizeString = si->getValueAsString(); } else if (infoName == "Geometry") { std::vector tokens; StringUtilities::token(si->getValueAsString(), " ", tokens); if (tokens.size() >= 4) { geometry[0] = StringUtilities::toInt(tokens[0]); geometry[1] = StringUtilities::toInt(tokens[1]); geometry[2] = StringUtilities::toInt(tokens[2]); geometry[3] = StringUtilities::toInt(tokens[3]); } } } if ((imageName.isEmpty() == false) && (geometry[2] > 0)) { imageNumber = -1; for (int j = 0; j < theMainWindow->getBrainSet()->getNumberOfImageFiles(); j++) { ImageFile* img = theMainWindow->getBrainSet()->getImageFile(j); if (FileUtilities::basename(img->getFileName()) == imageName) { imageNumber = j; break; } } if (imageNumber >= 0) { IMAGE_SIZE sz = IMAGE_SIZE_100; if (sizeString == "25") { sz = IMAGE_SIZE_25; } else if (sizeString == "50") { sz = IMAGE_SIZE_50; } else if (sizeString == "75") { sz = IMAGE_SIZE_75; } else if (sizeString == "100") { sz = IMAGE_SIZE_100; } else if (sizeString == "125") { sz = IMAGE_SIZE_125; } else if (sizeString == "150") { sz = IMAGE_SIZE_150; } else if (sizeString == "200") { sz = IMAGE_SIZE_200; } else if (sizeString == "400") { sz = IMAGE_SIZE_400; } else if (sizeString == "800") { sz = IMAGE_SIZE_800; } imageSizeComboBox->setCurrentIndex(sz); move(geometry[0], geometry[1]); //resize(geometry[2], geometry[3]); updateWindow(); move(geometry[0], geometry[1]); //resize(geometry[2], geometry[3]); } } } caret-5.6.4~dfsg.1.orig/caret/GuiImageResizeDialog.h0000664000175000017500000001105211572067322022020 0ustar michaelmichael #ifndef __GUI_IMAGE_RESIZE_DIALOG_H__ #define __GUI_IMAGE_RESIZE_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "WuQDialog.h" class QCheckBox; class QComboBox; class QDoubleSpinBox; class QImage; class QSpinBox; /// dialog for resizing a QImage class GuiImageResizeDialog : public WuQDialog { Q_OBJECT public: // constructor GuiImageResizeDialog(QWidget* parent, QImage& imageIn); // destructor ~GuiImageResizeDialog(); public slots: // called when OK/Cancel pressed void done(int r); protected slots: /// called when pixel width spin box value changed void slotPixelWidthSpinBox(int); /// called when pixel height spin box value changed void slotPixelHeightSpinBox(int); /// called when image size width double spin box value changes void slotImageSizeWidthDoubleSpinBox(double); /// called when image size height double spin box value changes void slotImageSizeHeightDoubleSpinBox(double); /// called when image resolution spin box value changed void slotImageResolutionSpinBox(int); /// called when image resolution units combo box value changed void slotImageResolutionUnitsComboBox(int); /// called when image width/height units combo box value changed void slotImageWidthHeightUnitsComboBox(int); /// called when main aspect ratio check box toggled void slotMaintainAspectRatioCheckBoxToggled(bool); protected: /// image units enum IMAGE_UNITS { /// image units centimeters IMAGE_UNITS_CM, /// image units inches IMAGE_UNITS_INCHES, /// image units millimeters IMAGE_UNITS_MM }; /// resolution units enum RESOLUTION_UNITS { /// resolution units pixels per centimeter RESOLUTION_UNITS_PIXEL_PERM_CM, /// resolution units pixels per inch RESOLUTION_UNITS_PIXELS_PER_INCH, /// resolution units pixels per millimeter RESOLUTION_UNITS_PIXELS_PER_MM }; // create the pixel dimensions widget QWidget* createPixelDimensionsWidget(); // create the image size widget QWidget* createImageSizeWidget(); // create the options widget QWidget* createOptionsWidget(); // load the image data into the dialog void loadImageData(); // get the resolution in pixels per centimeter float getResolutionInPixelsPerCentimeter() const; // update pixel dimensions due to image size change void updatePixelDimensionsDueToImageSizeChange(); // update image size due to pixel dimensions change void updateImageSizeDueToPixelDimensionsChange(); /// the image being resized QImage& image; /// pixel widget spin box QSpinBox* pixelWidthSpinBox; /// pixel height spin box QSpinBox* pixelHeightSpinBox; /// image size width double spin box QDoubleSpinBox* imageSizeWidthDoubleSpinBox; /// image size height double spin box QDoubleSpinBox* imageSizeHeightDoubleSpinBox; /// image resolution spin box QSpinBox* imageResolutionSpinBox; /// image width/height units combo box QComboBox* imageWidthHeightUnitsComboBox; /// image resolution units combo box QComboBox* imageResolutionUnitsComboBox; /// maintain aspect ratio check box QCheckBox* maintainAspectRatioCheckBox; /// aspect ratio height divided by width; float aspectRatioHeightDividedByWidth; }; #endif // __GUI_IMAGE_RESIZE_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiImageResizeDialog.cxx0000664000175000017500000004624511572067322022407 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include "GuiImageResizeDialog.h" /** * constructor. */ GuiImageResizeDialog::GuiImageResizeDialog(QWidget* parent, QImage& imageIn) : WuQDialog(parent), image(imageIn) { setWindowTitle("Image Size"); // // Create the groups // QWidget* pixelDimWidget = createPixelDimensionsWidget(); QWidget* imageSizeWidget = createImageSizeWidget(); QWidget* optionsWidget = createOptionsWidget(); // // Dialog buttons // QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); QObject::connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); QObject::connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); // // Layout for dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->addWidget(pixelDimWidget); dialogLayout->addWidget(imageSizeWidget); dialogLayout->addWidget(optionsWidget); dialogLayout->addWidget(buttonBox); aspectRatioHeightDividedByWidth = 1.0; loadImageData(); } /** * destructor. */ GuiImageResizeDialog::~GuiImageResizeDialog() { } /** * called when OK/Cancel pressed. */ void GuiImageResizeDialog::done(int r) { if (r == GuiImageResizeDialog::Accepted) { const int width = pixelWidthSpinBox->value(); const int height = pixelHeightSpinBox->value(); if ((width <= 0) || (height <= 0)) { QMessageBox::critical(this, "ERROR", "Pixel width or height is invalid."); return; } image = image.scaled(width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); const int pixelsPerMeter = static_cast(getResolutionInPixelsPerCentimeter() * 100.0); image.setDotsPerMeterX(pixelsPerMeter); image.setDotsPerMeterY(pixelsPerMeter); } WuQDialog::done(r); } /** * create the pixel dimensions widget. */ QWidget* GuiImageResizeDialog::createPixelDimensionsWidget() { // // Width label and spin box // QLabel* widthLabel = new QLabel("Width"); pixelWidthSpinBox = new QSpinBox; pixelWidthSpinBox->setMinimum(1); pixelWidthSpinBox->setMaximum(std::numeric_limits::max()); pixelWidthSpinBox->setSingleStep(1); QObject::connect(pixelWidthSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotPixelWidthSpinBox(int))); // // height label and spin box // QLabel* heightLabel = new QLabel("Height"); pixelHeightSpinBox = new QSpinBox; pixelHeightSpinBox->setMinimum(1); pixelHeightSpinBox->setMaximum(std::numeric_limits::max()); pixelHeightSpinBox->setSingleStep(1); QObject::connect(pixelHeightSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotPixelHeightSpinBox(int))); // // Group box and layout // QGroupBox* gb = new QGroupBox("Pixel Dimensions"); QGridLayout* gridLayout = new QGridLayout(gb); gridLayout->addWidget(widthLabel, 0, 0); gridLayout->addWidget(pixelWidthSpinBox, 0, 1); gridLayout->addWidget(heightLabel, 1, 0); gridLayout->addWidget(pixelHeightSpinBox, 1, 1); gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 0); gridLayout->setColumnStretch(2, 100); // push to left return gb; } /** * create the image size widget. */ QWidget* GuiImageResizeDialog::createImageSizeWidget() { // // Image width label and double spin box // QLabel* widthLabel = new QLabel("Width"); imageSizeWidthDoubleSpinBox = new QDoubleSpinBox; imageSizeWidthDoubleSpinBox->setMinimum(0.0); imageSizeWidthDoubleSpinBox->setMaximum(std::numeric_limits::max()); imageSizeWidthDoubleSpinBox->setSingleStep(1.0); imageSizeWidthDoubleSpinBox->setDecimals(3); QObject::connect(imageSizeWidthDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(slotImageSizeWidthDoubleSpinBox(double))); // // Image height label and double spin box // QLabel* heightLabel = new QLabel("Height"); imageSizeHeightDoubleSpinBox = new QDoubleSpinBox; imageSizeHeightDoubleSpinBox->setMinimum(0.0); imageSizeHeightDoubleSpinBox->setMaximum(std::numeric_limits::max()); imageSizeHeightDoubleSpinBox->setSingleStep(1.0); imageSizeHeightDoubleSpinBox->setDecimals(3); QObject::connect(imageSizeHeightDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(slotImageSizeHeightDoubleSpinBox(double))); // // image width/height units combo box // imageWidthHeightUnitsComboBox = new QComboBox; imageWidthHeightUnitsComboBox->addItem("CM", static_cast(IMAGE_UNITS_CM)); imageWidthHeightUnitsComboBox->addItem("Inches", static_cast(IMAGE_UNITS_INCHES)); imageWidthHeightUnitsComboBox->addItem("MM", static_cast(IMAGE_UNITS_MM)); imageWidthHeightUnitsComboBox->setCurrentIndex(1); QObject::connect(imageWidthHeightUnitsComboBox, SIGNAL(activated(int)), this, SLOT(slotImageWidthHeightUnitsComboBox(int))); // // Image resolution label and spin box // QLabel* resolutionLabel = new QLabel("Resolution"); imageResolutionSpinBox = new QSpinBox; imageResolutionSpinBox->setMinimum(1); imageResolutionSpinBox->setMaximum(std::numeric_limits::max()); imageResolutionSpinBox->setSingleStep(1); QObject::connect(imageResolutionSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotImageResolutionSpinBox(int))); // // Image resolution units combo box // imageResolutionUnitsComboBox = new QComboBox; imageResolutionUnitsComboBox->addItem("Pixels/CM", static_cast(RESOLUTION_UNITS_PIXEL_PERM_CM)); imageResolutionUnitsComboBox->addItem("Pixels/Inch", static_cast(RESOLUTION_UNITS_PIXELS_PER_INCH)); imageResolutionUnitsComboBox->addItem("Pixels/MM", static_cast(RESOLUTION_UNITS_PIXELS_PER_MM)); imageResolutionUnitsComboBox->setCurrentIndex(1); QObject::connect(imageResolutionUnitsComboBox, SIGNAL(activated(int)), this, SLOT(slotImageResolutionUnitsComboBox(int))); // // Group box and layout // QGroupBox* gb = new QGroupBox("Image Size"); QGridLayout* gridLayout = new QGridLayout(gb); gridLayout->addWidget(widthLabel, 0, 0); gridLayout->addWidget(imageSizeWidthDoubleSpinBox, 0, 1); gridLayout->addWidget(heightLabel, 1, 0); gridLayout->addWidget(imageSizeHeightDoubleSpinBox, 1, 1); gridLayout->addWidget(imageWidthHeightUnitsComboBox, 0, 2, 2, 1, Qt::AlignVCenter | Qt::AlignLeft); gridLayout->addWidget(resolutionLabel, 2, 0); gridLayout->addWidget(imageResolutionSpinBox, 2, 1); gridLayout->addWidget(imageResolutionUnitsComboBox, 2, 2); return gb; } /** * create the options widget. */ QWidget* GuiImageResizeDialog::createOptionsWidget() { // // Maintain aspect ratio checkbox // maintainAspectRatioCheckBox = new QCheckBox("Keep Aspect Ratio"); maintainAspectRatioCheckBox->setChecked(true); QObject::connect(maintainAspectRatioCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotMaintainAspectRatioCheckBoxToggled(bool))); // // Group box and layout // QGroupBox* gb = new QGroupBox("Options"); QVBoxLayout* layout = new QVBoxLayout(gb); layout->addWidget(maintainAspectRatioCheckBox); return gb; } /** * called when pixel width spin box value changed. */ void GuiImageResizeDialog::slotPixelWidthSpinBox(int) { if (maintainAspectRatioCheckBox->isChecked()) { const float width = pixelWidthSpinBox->value(); if (width != 0.0) { const float height = width * aspectRatioHeightDividedByWidth; pixelHeightSpinBox->blockSignals(true); pixelHeightSpinBox->setValue(static_cast(height + 0.5)); pixelHeightSpinBox->blockSignals(false); } } updateImageSizeDueToPixelDimensionsChange(); } /** * called when pixel height spin box value changed. */ void GuiImageResizeDialog::slotPixelHeightSpinBox(int) { if (maintainAspectRatioCheckBox->isChecked()) { const float height = pixelHeightSpinBox->value(); if (height != 0.0) { const float width = height / aspectRatioHeightDividedByWidth; pixelWidthSpinBox->blockSignals(true); pixelWidthSpinBox->setValue(static_cast(width + 0.5)); pixelWidthSpinBox->blockSignals(false); } } updateImageSizeDueToPixelDimensionsChange(); } /** * called when image size width double spin box value changes. */ void GuiImageResizeDialog::slotImageSizeWidthDoubleSpinBox(double) { if (maintainAspectRatioCheckBox->isChecked()) { const float width = imageSizeWidthDoubleSpinBox->value(); if (width != 0.0) { const float height = width * aspectRatioHeightDividedByWidth; imageSizeHeightDoubleSpinBox->blockSignals(true); imageSizeHeightDoubleSpinBox->setValue(height); imageSizeHeightDoubleSpinBox->blockSignals(false); } } updatePixelDimensionsDueToImageSizeChange(); } /** * called when image size height double spin box value changes. */ void GuiImageResizeDialog::slotImageSizeHeightDoubleSpinBox(double) { if (maintainAspectRatioCheckBox->isChecked()) { const float height = imageSizeHeightDoubleSpinBox->value(); if (height != 0.0) { const float width = height / aspectRatioHeightDividedByWidth; imageSizeWidthDoubleSpinBox->blockSignals(true); imageSizeWidthDoubleSpinBox->setValue(width); imageSizeWidthDoubleSpinBox->blockSignals(false); } } updatePixelDimensionsDueToImageSizeChange(); } /** * called when image resolution spin box value changed. */ void GuiImageResizeDialog::slotImageResolutionSpinBox(int) { updatePixelDimensionsDueToImageSizeChange(); } /** * called when image resolution units combo box value changed. */ void GuiImageResizeDialog::slotImageResolutionUnitsComboBox(int resolutionIndex) { // // Load resolution // const float resolutionPerMeter = image.dotsPerMeterX(); const RESOLUTION_UNITS resolutionUnits = static_cast( imageResolutionUnitsComboBox->itemData(resolutionIndex).toInt()); double resolutionValue = 1.0; switch (resolutionUnits) { case RESOLUTION_UNITS_PIXEL_PERM_CM: resolutionValue = resolutionPerMeter / 100.0; break; case RESOLUTION_UNITS_PIXELS_PER_INCH: resolutionValue = resolutionPerMeter / 39.37008; break; case RESOLUTION_UNITS_PIXELS_PER_MM: resolutionValue = resolutionPerMeter / 1000.0; break; } // // Add 0.5 so rounding occurs // imageResolutionSpinBox->blockSignals(true); imageResolutionSpinBox->setValue(static_cast(resolutionValue + 0.5)); imageResolutionSpinBox->blockSignals(false); } /** * get the resolution in pixels per centimeter. */ float GuiImageResizeDialog::getResolutionInPixelsPerCentimeter() const { const int resolutionIndex = imageResolutionUnitsComboBox->currentIndex(); const RESOLUTION_UNITS resolutionUnits = static_cast( imageResolutionUnitsComboBox->itemData(resolutionIndex).toInt()); float resolutionPixelsPerCentimeter = 10; const float resValue = imageResolutionSpinBox->value(); switch (resolutionUnits) { case RESOLUTION_UNITS_PIXEL_PERM_CM: resolutionPixelsPerCentimeter = resValue; break; case RESOLUTION_UNITS_PIXELS_PER_INCH: resolutionPixelsPerCentimeter = resValue / 2.54; break; case RESOLUTION_UNITS_PIXELS_PER_MM: resolutionPixelsPerCentimeter = resValue / 10.0; break; } if (resolutionPixelsPerCentimeter <= 0.0) { resolutionPixelsPerCentimeter = 1.0; } return resolutionPixelsPerCentimeter; } /** * called when image width/height units combo box value changed. */ void GuiImageResizeDialog::slotImageWidthHeightUnitsComboBox(int /*imageUnitsIndex*/) { updateImageSizeDueToPixelDimensionsChange(); /* const IMAGE_UNITS imageUnits = static_cast( imageWidthHeightUnitsComboBox->itemData(imageUnitsIndex).toInt()); const float resolutionPixelsPerCentimeter = getResolutionInPixelsPerCentimeter(); const float widthInCM = pixelWidthSpinBox->value() / resolutionPixelsPerCentimeter; const float heightInCM = pixelHeightSpinBox->value() / resolutionPixelsPerCentimeter; switch (imageUnits) { case IMAGE_UNITS_CM: imageSizeWidthDoubleSpinBox->setValue(widthInCM); imageSizeHeightDoubleSpinBox->setValue(heightInCM); break; case IMAGE_UNITS_INCHES: imageSizeWidthDoubleSpinBox->setValue(widthInCM * 0.3937008); imageSizeHeightDoubleSpinBox->setValue(heightInCM * 0.3937008); break; case IMAGE_UNITS_MM: imageSizeWidthDoubleSpinBox->setValue(widthInCM * 10.0); imageSizeHeightDoubleSpinBox->setValue(heightInCM * 10.0); break; } */ } /** * called when main aspect ratio check box toggled. */ void GuiImageResizeDialog::slotMaintainAspectRatioCheckBoxToggled(bool isOn) { if (isOn) { if (pixelWidthSpinBox->value() != 0.0) { aspectRatioHeightDividedByWidth = static_cast(pixelHeightSpinBox->value()) / static_cast(pixelWidthSpinBox->value()); if (aspectRatioHeightDividedByWidth == 0.0) { aspectRatioHeightDividedByWidth = 1.0; } } else { aspectRatioHeightDividedByWidth = 1.0; } } } /** * load the image data into the dialog. */ void GuiImageResizeDialog::loadImageData() { // // Set width and height // pixelWidthSpinBox->blockSignals(true); pixelWidthSpinBox->setValue(image.width()); pixelWidthSpinBox->blockSignals(false); pixelHeightSpinBox->blockSignals(true); pixelHeightSpinBox->setValue(image.height()); pixelHeightSpinBox->blockSignals(false); // // Set aspect ratio using pixel width and height // slotMaintainAspectRatioCheckBoxToggled(maintainAspectRatioCheckBox->isChecked()); // // Set resolution // slotImageResolutionUnitsComboBox(imageResolutionUnitsComboBox->currentIndex()); // // Set image size // slotImageWidthHeightUnitsComboBox(imageWidthHeightUnitsComboBox->currentIndex()); } /** * update pixel dimensions due to image size change. */ void GuiImageResizeDialog::updatePixelDimensionsDueToImageSizeChange() { const int imageUnitsIndex = imageWidthHeightUnitsComboBox->currentIndex(); const IMAGE_UNITS imageUnits = static_cast( imageWidthHeightUnitsComboBox->itemData(imageUnitsIndex).toInt()); const float resolutionPixelsPerCentimeter = getResolutionInPixelsPerCentimeter(); float widthInCM = 1.0; float heightInCM = 1.0; switch (imageUnits) { case IMAGE_UNITS_CM: widthInCM = imageSizeWidthDoubleSpinBox->value() * resolutionPixelsPerCentimeter; heightInCM = imageSizeHeightDoubleSpinBox->value() * resolutionPixelsPerCentimeter; break; case IMAGE_UNITS_INCHES: widthInCM = imageSizeWidthDoubleSpinBox->value() * resolutionPixelsPerCentimeter * 2.54; heightInCM = imageSizeHeightDoubleSpinBox->value() * resolutionPixelsPerCentimeter * 2.54; break; case IMAGE_UNITS_MM: widthInCM = imageSizeWidthDoubleSpinBox->value() * resolutionPixelsPerCentimeter * 10.0; heightInCM = imageSizeHeightDoubleSpinBox->value() * resolutionPixelsPerCentimeter * 10.0; break; } pixelWidthSpinBox->blockSignals(true); pixelWidthSpinBox->setValue(static_cast(widthInCM)); pixelWidthSpinBox->blockSignals(false); pixelHeightSpinBox->blockSignals(true); pixelHeightSpinBox->setValue(static_cast(heightInCM)); pixelHeightSpinBox->blockSignals(false); } /** * update image size due to pixel dimensions change. */ void GuiImageResizeDialog::updateImageSizeDueToPixelDimensionsChange() { const int imageUnitsIndex = imageWidthHeightUnitsComboBox->currentIndex(); const IMAGE_UNITS imageUnits = static_cast( imageWidthHeightUnitsComboBox->itemData(imageUnitsIndex).toInt()); const float resolutionPixelsPerCentimeter = getResolutionInPixelsPerCentimeter(); const float widthInCM = pixelWidthSpinBox->value() / resolutionPixelsPerCentimeter; const float heightInCM = pixelHeightSpinBox->value() / resolutionPixelsPerCentimeter; imageSizeWidthDoubleSpinBox->blockSignals(true); imageSizeHeightDoubleSpinBox->blockSignals(true); switch (imageUnits) { case IMAGE_UNITS_CM: imageSizeWidthDoubleSpinBox->setValue(widthInCM); imageSizeHeightDoubleSpinBox->setValue(heightInCM); break; case IMAGE_UNITS_INCHES: imageSizeWidthDoubleSpinBox->setValue(widthInCM * 0.3937008); imageSizeHeightDoubleSpinBox->setValue(heightInCM * 0.3937008); break; case IMAGE_UNITS_MM: imageSizeWidthDoubleSpinBox->setValue(widthInCM * 10.0); imageSizeHeightDoubleSpinBox->setValue(heightInCM * 10.0); break; } imageSizeWidthDoubleSpinBox->blockSignals(false); imageSizeHeightDoubleSpinBox->blockSignals(false); } caret-5.6.4~dfsg.1.orig/caret/GuiImageFormatComboBox.h0000664000175000017500000000462411572067322022327 0ustar michaelmichael #ifndef __GUI_IMAGE_FORMAT_COMBO_BOX_H__ #define __GUI_IMAGE_FORMAT_COMBO_BOX_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include /// class for choosing an image format class GuiImageFormatComboBox : public QComboBox { Q_OBJECT public: /// image mode enum IMAGE_MODE{ /// open image mode IMAGE_MODE_OPEN, /// save image mode IMAGE_MODE_SAVE }; /// display mode enum DISPLAY_MODE { /// show the image format names DISPLAY_IMAGE_FORMAT_NAMES, /// show the image format file filters DISPLAY_IMAGE_FILE_FILTERS }; // constructor GuiImageFormatComboBox(const IMAGE_MODE im, const DISPLAY_MODE dm, QWidget* parent = 0); // destructor ~GuiImageFormatComboBox(); // get the selected image format name QString getSelectedImageFormatName() const; // get the selected image format file extension QString getSelectedImageFormatExtension() const; // get the selected image filter QString getSelectedImageFormatFilter() const; // get all file filters QStringList getAllFileFilters() const; protected: /// the image format names QStringList imageFormatNames; /// the image formats QStringList imageFormatExtensions; /// the image format file filters QStringList imageFormatFilters; }; #endif // __GUI_IMAGE_FORMAT_COMBO_BOX_H__ caret-5.6.4~dfsg.1.orig/caret/GuiImageFormatComboBox.cxx0000664000175000017500000000702111572067322022674 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include "GuiImageFormatComboBox.h" /** * constructor. */ GuiImageFormatComboBox::GuiImageFormatComboBox(const IMAGE_MODE im, const DISPLAY_MODE dm, QWidget* parent) : QComboBox(parent) { QList formatsList; switch (im) { case IMAGE_MODE_OPEN: formatsList = QImageReader::supportedImageFormats(); break; case IMAGE_MODE_SAVE: formatsList = QImageWriter::supportedImageFormats(); break; } int defaultItem = -1; for (int i = 0; i < formatsList.size(); i++) { const QString name(formatsList.at(i)); imageFormatNames.append(name); QString ext("." + name); imageFormatExtensions.append(ext); QString filter; filter += name; filter += " image file"; filter += " (*"; filter += ext; filter += ")"; imageFormatFilters << filter; switch (dm) { case DISPLAY_IMAGE_FORMAT_NAMES: addItem(name); break; case DISPLAY_IMAGE_FILE_FILTERS: addItem(filter); break; } if (defaultItem == -1) { if (name == "jpg") { defaultItem = i; } else if (name == "jpeg") { defaultItem = i; } else if (name == "ppm") { defaultItem = i; } } if (name == "jpg") { defaultItem = i; } } if ((defaultItem >= 0) && (count() > 0)) { setCurrentIndex(defaultItem); } } /** * destructor. */ GuiImageFormatComboBox::~GuiImageFormatComboBox() { } /** * get the selected image format name. */ QString GuiImageFormatComboBox::getSelectedImageFormatName() const { const int item = currentIndex(); if ((item >= 0) && (item < count())) { return imageFormatNames.at(item); } return ""; } /** * get the selection image format file extension. */ QString GuiImageFormatComboBox::getSelectedImageFormatExtension() const { const int item = currentIndex(); if ((item >= 0) && (item < count())) { return imageFormatExtensions.at(item); } return ""; } /** * get the selected image filter. */ QString GuiImageFormatComboBox::getSelectedImageFormatFilter() const { const int item = currentIndex(); if ((item >= 0) && (item < count())) { return imageFormatFilters.at(item); } return ""; } /** * get all file filters. */ QStringList GuiImageFormatComboBox::getAllFileFilters() const { return imageFormatFilters; } caret-5.6.4~dfsg.1.orig/caret/GuiImageEditorWindow.h0000664000175000017500000002525711572067322022071 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_IMAGE_EDITOR_WINDOW_H__ #define __GUI_IMAGE_EDITOR_WINDOW_H__ #include #include "WuQDialog.h" #include #include "SceneFile.h" class GuiImageEditorWidget; class GuiImageEditorWidgetAddTextDialog; class ImageFile; class QCheckBox; class QComboBox; class QContextMenuEvent; class QImage; class QLabel; class QLineEdit; class QPaintEvent; class QSpinBox; /// Dialog used to display and edit images class GuiImageEditorWindow : public WuQDialog { Q_OBJECT public: /// Constructor GuiImageEditorWindow(QWidget* parent); /// Destructor ~GuiImageEditorWindow(); /// update the toolbar void updateWindow(); /// display the image in the window void displayImage(const int imageNumberIn); /// save scene SceneFile::SceneClass saveScene(); /// show scene void showScene(const SceneFile::SceneClass sc); protected slots: /// called when an image is selected void slotImageSelectionComboBox(int item); /// called to open an image file void slotOpenImageFile(); /// called to save an image file void slotSaveImageFile(); /// called to print an image void slotPrintImage(); /// called when image size changed void slotImageSizeChanged(); /// called to inform editor that an image has been saved void slotImageHasBeenSaved(); /// called to copy image to clipboard void slotCopyImageToClipboard(); protected: /// image size combo box QComboBox* imageSizeComboBox; /// the image selection combo box QComboBox* imageSelectionComboBox; /// the image viewer GuiImageEditorWidget* imageViewer; }; //******************************************************************************** //******************************************************************************** //******************************************************************************** /// image editing widget class GuiImageEditorWidget : public QWidget { Q_OBJECT public: /// viewing size of image enum VIEWING_IMAGE_SIZE { /// scale image to 25% of its original size VIEWING_IMAGE_SIZE_25, /// scale image to 50% of its original size VIEWING_IMAGE_SIZE_50, /// scale image to 75% of its original size VIEWING_IMAGE_SIZE_75, /// scale image to 100% of its original size VIEWING_IMAGE_SIZE_100, /// scale image to 125% of its original size VIEWING_IMAGE_SIZE_125, /// scale image to 150% of its original size VIEWING_IMAGE_SIZE_150, /// scale image to 200% of its original size VIEWING_IMAGE_SIZE_200, /// scale image to 400% of its original size VIEWING_IMAGE_SIZE_400, /// scale image to 800% of its original size VIEWING_IMAGE_SIZE_800 }; /// popup menu style enum POPUP_MENU { /// no popup menu POPUP_MENU_NONE, /// edit popup menu POPUP_MENU_EDIT_ONLY, /// edit, open, and save popup menu POPUP_MENU_EDIT_OPEN_SAVE }; // constructor GuiImageEditorWidget(QWidget *parent, const POPUP_MENU popupMenuStyleIn, Qt::WindowFlags f = 0); // destructor ~GuiImageEditorWidget(); // set the image void setImageFile(ImageFile* img); /// get the image number in the widget ImageFile* getImageFile() { return imageFile; } /// get the image number in the widget (const method) const ImageFile* getImageFile() const { return imageFile; } // set the viewing size void setViewingSize(const VIEWING_IMAGE_SIZE vis); // get the viewing size VIEWING_IMAGE_SIZE getViewingSize() const; // get size hint QSize sizeHint() const; signals: void signalGeometryChanged(); public slots: /// called to load an image void slotLoadImage(); /// called to save an image void slotSaveImage(); /// called to resize the image void slotResizeImage(); /// called to crop the image void slotCropImage(); /// called to add text to the image (text X/Y set to popup menu position) void slotAddTextPopupMenu(); /// called to add text to the image (text X/Y at center of image) void slotAddText(); /// called when a viewing size is selected void slotViewingSizeMenu(int id); protected: // called when mouse pressed void mousePressEvent(QMouseEvent* me); // called when mouse moved void mouseMoveEvent(QMouseEvent* me); // get cropping min/max void getCropping(int& minX, int& maxX, int& minY, int& maxY) const; // add text void addText(const int x, const int y); // get the displayed image file ImageFile* getDisplayedImageFile(); // paint the widget void paintEvent(QPaintEvent* pe); // popup the context menu void contextMenuEvent(QContextMenuEvent* cme); /// Get the image viewing width and height. void getImageViewingWidthAndHeight(int& w, int& h) const; /// window size changed void windowSizeChanged(); /// get the QImage of the ImageFile being displayed QImage* getImageBeingDisplayed(); /// get the QImage of the ImageFile being displayed (const method) const QImage* getImageBeingDisplayed() const; /// the image file being edited ImageFile* imageFile; /// image size combo box //QComboBox* imageSizeComboBox; /// cropping lines int croppingLines[4]; /// cropping lines valid bool croppingLinesValid; /// the add text dialog GuiImageEditorWidgetAddTextDialog* addTextDialog; /// x of menu popup int menuX; /// y of menu popup int menuY; /// popup menu style POPUP_MENU popupMenuStyle; /// viewing image size VIEWING_IMAGE_SIZE viewingImageSize; }; //******************************************************************************** //******************************************************************************** //******************************************************************************** /// dialog for resizing an image class GuiImageEditorWidgetResizeDialog : public WuQDialog { Q_OBJECT public: // constructor GuiImageEditorWidgetResizeDialog(QWidget* parent, const int xSize, const int ySize); // destructor ~GuiImageEditorWidgetResizeDialog(); // get the image sizes void getImageSizes(int& x, int& y) const; protected slots: // called when x spin box value is changed void slotXSizeSpinBox(int value); // called when y spin box value is changed void slotYSizeSpinBox(int value); protected: // called when OK or Cancel button is pressed void done(int r); /// x size spin box QSpinBox* xSizeSpinBox; /// y size spin box QSpinBox* ySizeSpinBox; /// maintain aspect check box QCheckBox* aspectCheckBox; /// original aspect of image float originalAspect; }; //******************************************************************************** //******************************************************************************** //******************************************************************************** /// dialog for adding text to an image class GuiImageEditorWidgetAddTextDialog : public WuQDialog { Q_OBJECT public: // constructor GuiImageEditorWidgetAddTextDialog(QWidget* parent, const int x, const int y); // destructor ~GuiImageEditorWidgetAddTextDialog(); // get the info about the text void getTextInfo(QString& text, int& x, int& y, int& rotation, QFont& textFont, QColor& textColor) const; signals: /// emitted when text is being updated void signalTextUpdated(); protected slots: // called to select the font void slotFontPushButton(); // called to select the font color void slotFontColorPushButton(); protected: // called when OK or Cancel button is pressed void done(int r); /// x spin box QSpinBox* xSpinBox; /// y spin box QSpinBox* ySpinBox; /// rotation box QSpinBox* rotationSpinBox; /// the text line edit QLineEdit* textLineEdit; /// the font push button QPushButton* fontPushButton; /// the font color push button QPushButton* fontColorPushButton; /// the font being used static QFont theFont; /// the font color static QColor fontColor; /// static data initialized flag static bool staticDataInitialized; }; #ifdef __IMAGE_EDITOR_WIDGET_ADD_TEXT_DIALOG_MAIN__ QFont GuiImageEditorWidgetAddTextDialog::theFont; bool GuiImageEditorWidgetAddTextDialog::staticDataInitialized = false; QColor GuiImageEditorWidgetAddTextDialog::fontColor; #endif // __IMAGE_EDITOR_WIDGET_ADD_TEXT_DIALOG_MAIN__ //******************************************************************************** //******************************************************************************** //******************************************************************************** #endif // __GUI_IMAGE_EDITOR_WINDOW_H__ caret-5.6.4~dfsg.1.orig/caret/GuiImageEditorWindow.cxx0000664000175000017500000012607711572067322022446 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 #include #include #include #include #include #include "FileFilters.h" #include "GuiBrainModelOpenGL.h" #include "GuiDataFileOpenDialog.h" #include "GuiDataFileSaveDialog.h" #include "GuiFilesModified.h" #include "GuiImageResizeDialog.h" #include "GuiMainWindow.h" #define __IMAGE_EDITOR_WIDGET_ADD_TEXT_DIALOG_MAIN__ #include "GuiImageEditorWindow.h" #undef __IMAGE_EDITOR_WIDGET_ADD_TEXT_DIALOG_MAIN__ #include "BrainSet.h" #include "FileUtilities.h" #include "GuiMainWindow.h" #include "ImageFile.h" #include "StringUtilities.h" #include "global_variables.h" /** * The Constructor. */ GuiImageEditorWindow::GuiImageEditorWindow(QWidget* parent) : WuQDialog(parent) { setModal(false); //setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); setWindowTitle("Image Editing Window"); // // Layout for the dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); // // box for toolbar row 1 // QHBoxLayout* toolbar1Layout = new QHBoxLayout; dialogLayout->addLayout(toolbar1Layout); // // The selection combo box // imageSelectionComboBox = new QComboBox; toolbar1Layout->addWidget(imageSelectionComboBox); imageSelectionComboBox->setFixedHeight(imageSelectionComboBox->sizeHint().height()); imageSelectionComboBox->setToolTip( "Use this control to choose\n" "the displayed image."); QObject::connect(imageSelectionComboBox, SIGNAL(activated(int)), this, SLOT(slotImageSelectionComboBox(int))); //toolbar1->setFixedHeight(toolbar1->sizeHint().height()); // // box for toolbar row 2 // QHBoxLayout* toolbar2Layout = new QHBoxLayout; dialogLayout->addLayout(toolbar2Layout); // // Open image file button // QToolButton* openToolButton = new QToolButton; toolbar2Layout->addWidget(openToolButton); openToolButton->setText("O"); openToolButton->setToolTip( "Open an Image File"); QObject::connect(openToolButton, SIGNAL(clicked()), this, SLOT(slotOpenImageFile())); // // Save image file button // QToolButton* saveToolButton = new QToolButton; toolbar2Layout->addWidget(saveToolButton); saveToolButton->setText("S"); saveToolButton->setToolTip( "Save an Image File"); QObject::connect(saveToolButton, SIGNAL(clicked()), this, SLOT(slotSaveImageFile())); // // Print image file button // QToolButton* printToolButton = new QToolButton; toolbar2Layout->addWidget(printToolButton); printToolButton->setText("P"); printToolButton->setToolTip( "Print Image"); QObject::connect(printToolButton, SIGNAL(clicked()), this, SLOT(slotPrintImage())); // // Space // QLabel* dumbLabel = new QLabel(" "); dumbLabel->setFixedSize(dumbLabel->sizeHint()); toolbar2Layout->addWidget(dumbLabel); // // Copy to clipboard // QToolButton* copyToClipboardToolButton = new QToolButton; toolbar2Layout->addWidget(copyToClipboardToolButton); copyToClipboardToolButton->setText("C"); copyToClipboardToolButton->setToolTip("Copy Image to\n" "Clipboard"); QObject::connect(copyToClipboardToolButton, SIGNAL(clicked()), this, SLOT(slotCopyImageToClipboard())); // // Space 2 // QLabel* dumb2Label = new QLabel(" "); dumb2Label->setFixedSize(dumb2Label->sizeHint()); toolbar2Layout->addWidget(dumb2Label); // // Annotate tool button // QToolButton* annotateToolButton = new QToolButton; toolbar2Layout->addWidget(annotateToolButton); annotateToolButton->setText("A"); annotateToolButton->setToolTip( "Annotate the Image"); // // Crop tool button // QToolButton* cropToolButton = new QToolButton; toolbar2Layout->addWidget(cropToolButton); cropToolButton->setText("C"); cropToolButton->setToolTip("To crop an image, first move the mouse to\n" "a corner of the desired subregion of the image\n" "and, while holding down the left mouse button,\n" "drag the mouse to the opposite corner of the\n" "image subregion and release the mouse. Next,\n" "press the crop button \"C\" in the toolbar to\n" "crop the image."); // // Resize tool button // QToolButton* resizeToolButton = new QToolButton; toolbar2Layout->addWidget(resizeToolButton); resizeToolButton->setText("R"); resizeToolButton->setToolTip( "Resize the Image"); // // Size combo box // imageSizeComboBox = new QComboBox; toolbar2Layout->addWidget(imageSizeComboBox); imageSizeComboBox->setFixedHeight(imageSizeComboBox->sizeHint().height()); imageSizeComboBox->insertItem(GuiImageEditorWidget::VIEWING_IMAGE_SIZE_25, " 25%"); imageSizeComboBox->insertItem(GuiImageEditorWidget::VIEWING_IMAGE_SIZE_50, " 50%"); imageSizeComboBox->insertItem(GuiImageEditorWidget::VIEWING_IMAGE_SIZE_75, " 75%"); imageSizeComboBox->insertItem(GuiImageEditorWidget::VIEWING_IMAGE_SIZE_100, "100%"); imageSizeComboBox->insertItem(GuiImageEditorWidget::VIEWING_IMAGE_SIZE_125, "125%"); imageSizeComboBox->insertItem(GuiImageEditorWidget::VIEWING_IMAGE_SIZE_150, "150%"); imageSizeComboBox->insertItem(GuiImageEditorWidget::VIEWING_IMAGE_SIZE_200, "200%"); imageSizeComboBox->insertItem(GuiImageEditorWidget::VIEWING_IMAGE_SIZE_400, "400%"); imageSizeComboBox->insertItem(GuiImageEditorWidget::VIEWING_IMAGE_SIZE_800, "800%"); imageSizeComboBox->setFixedSize(imageSizeComboBox->sizeHint()); imageSizeComboBox->setToolTip( "Use this control to change\n" "the image's viewing size."); imageSizeComboBox->hide(); // // pack toolbar together // toolbar2Layout->setSpacing(5); //toolbar2->setFixedHeight(toolbar2->sizeHint().height()); toolbar2Layout->setStretchFactor(annotateToolButton, 0); toolbar2Layout->setStretchFactor(cropToolButton, 0); toolbar2Layout->setStretchFactor(resizeToolButton, 0); toolbar2Layout->setStretchFactor(imageSizeComboBox, 0); QLabel* rightToolbar2Label = new QLabel(" "); toolbar2Layout->addWidget(rightToolbar2Label); toolbar2Layout->setStretchFactor(rightToolbar2Label, 1000); // // the image viewer // imageViewer = new GuiImageEditorWidget(this, GuiImageEditorWidget::POPUP_MENU_EDIT_ONLY); imageSizeComboBox->setCurrentIndex(imageViewer->getViewingSize()); QObject::connect(imageSizeComboBox, SIGNAL(activated(int)), imageViewer, SLOT(slotViewingSizeMenu(int))); //dialogLayout->addWidget(imageViewer); QObject::connect(imageViewer, SIGNAL(signalGeometryChanged()), this, SLOT(slotImageSizeChanged())); // // Connect the toolbar buttons to the image editor // QObject::connect(annotateToolButton, SIGNAL(clicked()), imageViewer, SLOT(slotAddText())); QObject::connect(cropToolButton, SIGNAL(clicked()), imageViewer, SLOT(slotCropImage())); QObject::connect(resizeToolButton, SIGNAL(clicked()), imageViewer, SLOT(slotResizeImage())); // // Scroll view for image viewer // QScrollArea* imageViewerScrollViewer = new QScrollArea; imageViewerScrollViewer->setWidget(imageViewer); imageViewerScrollViewer->setWidgetResizable(true); dialogLayout->addWidget(imageViewerScrollViewer); // // Close Button // QHBoxLayout* buttons = new QHBoxLayout; dialogLayout->addLayout(buttons); QPushButton* close = new QPushButton("Close"); close->setAutoDefault(false); close->setFixedSize(close->sizeHint()); QObject::connect(close, SIGNAL(clicked()), this, SLOT(close())); buttons->addWidget(close); dialogLayout->setStretchFactor(toolbar1Layout, 0); dialogLayout->setStretchFactor(toolbar2Layout, 0); dialogLayout->setStretchFactor(imageViewer, 100); dialogLayout->setStretchFactor(buttons, 0); // dialogLayout->setResizeMode(QLayout::Minimum); updateWindow(); } /** * The Destructor. */ GuiImageEditorWindow::~GuiImageEditorWindow() { // theMainWindow->removeImageViewingWindow(this); } /** * called to open an image file. */ void GuiImageEditorWindow::slotOpenImageFile() { GuiDataFileOpenDialog dfod(this); dfod.setFilters(QStringList(FileFilters::getImageOpenFileFilter())); dfod.selectFilter(FileFilters::getImageOpenFileFilter()); if (dfod.exec() == GuiDataFileOpenDialog::Accepted) { const int numImages = theMainWindow->getBrainSet()->getNumberOfImageFiles(); if (numImages > 0) { imageSelectionComboBox->blockSignals(true); imageSelectionComboBox->setCurrentIndex(numImages - 1); imageSelectionComboBox->blockSignals(false); slotImageSelectionComboBox(numImages - 1); } } /* static GuiImageFileOpenSaveDialog* sd = NULL; if (sd == NULL) { sd = new GuiImageFileOpenSaveDialog(this, GuiImageFileOpenSaveDialog::DIALOG_MODE_OPEN_FILES); //QObject::connect(sd, SIGNAL(signalImageHasBeenSaved()), // this, SLOT(slotImageHasBeenSaved())); } sd->show(); sd->activateWindow(); */ } /** * called to inform editor that an image has been saved. */ void GuiImageEditorWindow::slotImageHasBeenSaved() { const int numImages = theMainWindow->getBrainSet()->getNumberOfImageFiles(); if (numImages > 0) { imageSelectionComboBox->blockSignals(true); imageSelectionComboBox->setCurrentIndex(numImages - 1); imageSelectionComboBox->blockSignals(false); slotImageSelectionComboBox(numImages - 1); } } /** * called to save an image file. */ void GuiImageEditorWindow::slotSaveImageFile() { ImageFile* imageFile = imageViewer->getImageFile(); if (imageFile != NULL) { GuiDataFileSaveDialog dfsd(this); dfsd.selectFileType(FileFilters::getImageSaveFileFilter()); dfsd.selectImageFile(imageFile); dfsd.exec(); } /* ImageFile* imageFile = imageViewer->getImageFile(); if (imageFile != NULL) { static GuiImageFileOpenSaveDialog* sd = NULL; if (sd == NULL) { sd = new GuiImageFileOpenSaveDialog(this, GuiImageFileOpenSaveDialog::DIALOG_MODE_SAVE_LOADED_IMAGE); sd->setDefaultImageForSaving(imageFile); } sd->show(); sd->activateWindow(); } */ } /** * called to copy image to clipboard. */ void GuiImageEditorWindow::slotCopyImageToClipboard() { ImageFile* imageFile = imageViewer->getImageFile(); if (imageFile != NULL) { QApplication::clipboard()->setImage(*(imageFile->getImage()), QClipboard::Clipboard); } } /** * called to print an image. */ void GuiImageEditorWindow::slotPrintImage() { ImageFile* imageFile = imageViewer->getImageFile(); if (imageFile != NULL) { QPrinter printer; QPrintDialog pd(&printer, this); if (pd.exec() == QPrintDialog::Accepted) { QImage image = *(imageFile->getImage()); QPainter painter(&printer); painter.drawImage(0, 0, image); } } } /** * called when an image is selected. */ void GuiImageEditorWindow::slotImageSelectionComboBox(int item) { displayImage(item); imageSizeComboBox->blockSignals(true); imageSizeComboBox->setCurrentIndex(GuiImageEditorWidget::VIEWING_IMAGE_SIZE_100); imageSizeComboBox->blockSignals(false); imageViewer->setViewingSize(GuiImageEditorWidget::VIEWING_IMAGE_SIZE_100); } /** * Update the window as image files may have changed. */ void GuiImageEditorWindow::updateWindow() { const int numImages = theMainWindow->getBrainSet()->getNumberOfImageFiles(); if (numImages <= 0) { close(); } ImageFile* imageFile = imageViewer->getImageFile(); int defaultItem = -1; imageSelectionComboBox->blockSignals(true); imageSelectionComboBox->clear(); for (int i = 0; i < numImages; i++) { ImageFile* img = theMainWindow->getBrainSet()->getImageFile(i); imageSelectionComboBox->addItem(FileUtilities::basename(img->getFileName())); if (img == imageFile) { defaultItem = i; } } if (defaultItem < 0) { imageFile = NULL; if (numImages > 0) { defaultItem = 0; } } if ((defaultItem >= 0) && (defaultItem < imageSelectionComboBox->count())) { imageSelectionComboBox->setCurrentIndex(defaultItem); if (imageFile == NULL) { imageViewer->setImageFile(theMainWindow->getBrainSet()->getImageFile(defaultItem)); } } imageSelectionComboBox->blockSignals(false); } /** * display the image in the window */ void GuiImageEditorWindow::displayImage(const int imageNumberIn) { imageViewer->setImageFile(theMainWindow->getBrainSet()->getImageFile(imageNumberIn)); //const int windowX = std::max(x(), 10); //const int windowY = std::max(y(), 10); // // Allows dialog to resize to fit image and don't let it change position // //move(windowX, windowY); //adjustSize(); //move(windowX, windowY); slotImageSizeChanged(); } /** * called when image size changed. */ void GuiImageEditorWindow::slotImageSizeChanged() { /* // // Allows dialog to resize to fit image and don't let it change position // imageViewer->adjustSize(); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); setMinimumSize(sizeHint()); setMaximumSize(sizeHint()); updateGeometry(); resize(sizeHint()); adjustSize(); */ } /** * save scene. */ SceneFile::SceneClass GuiImageEditorWindow::saveScene() { SceneFile::SceneClass sc("GuiImageEditorWindow"); /* const ImageFile* img = imageViewer->getImageFile(); if (img != NULL) { const int geometry[4] = { x(), y(), width(), height() }; std::ostringstream str; str << geometry[0] << " " << geometry[1] << " " << geometry[2] << " " << geometry[3]; sc.addSceneInfo(SceneFile::SceneInfo("Geometry", str.str().c_str())); sc.addSceneInfo(SceneFile::SceneInfo("ImageName", FileUtilities::basename(img->getFileName()))); QString sizeString; switch (imageViewer->getViewingSize()) { case GuiImageEditorWidget::VIEWING_IMAGE_SIZE_25: sizeString = "25"; break; case GuiImageEditorWidget::VIEWING_IMAGE_SIZE_50: sizeString = "50"; break; case GuiImageEditorWidget::VIEWING_IMAGE_SIZE_75: sizeString = "75"; break; case GuiImageEditorWidget::VIEWING_IMAGE_SIZE_100: sizeString = "100"; break; case GuiImageEditorWidget::VIEWING_IMAGE_SIZE_125: sizeString = "125"; break; case GuiImageEditorWidget::VIEWING_IMAGE_SIZE_150: sizeString = "150"; break; case GuiImageEditorWidget::VIEWING_IMAGE_SIZE_200: sizeString = "200"; break; case GuiImageEditorWidget::VIEWING_IMAGE_SIZE_400: sizeString = "400"; break; case GuiImageEditorWidget::VIEWING_IMAGE_SIZE_800: sizeString = "800"; break; } if (sizeString.empty() == false) { sc.addSceneInfo(SceneFile::SceneInfo("ImageScale", sizeString)); } } */ return sc; } /** * show scene. */ void GuiImageEditorWindow::showScene(const SceneFile::SceneClass /*sc*/) { /* QString imageName; QString sizeString; int geometry[4] = { 0, 0, 0, 0 }; const int num = sc.getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc.getSceneInfo(i); const QString infoName = si->getName(); if (infoName == "ImageName") { imageName = si->getValueAsString(); } else if (infoName == "ImageScale") { sizeString = si->getValueAsString(); } else if (infoName == "Geometry") { std::vector tokens; StringUtilities::token(si->getValueAsString(), " ", tokens); if (tokens.size() >= 4) { geometry[0] = StringUtilities::toInt(tokens[0]); geometry[1] = StringUtilities::toInt(tokens[1]); geometry[2] = StringUtilities::toInt(tokens[2]); geometry[3] = StringUtilities::toInt(tokens[3]); } } } if ((imageName.empty() == false) && (geometry[2] > 0)) { int imageNumber = -1; for (int j = 0; j < theMainWindow->getBrainSet()->getNumberOfImageFiles(); j++) { ImageFile* img = theMainWindow->getBrainSet()->getImageFile(j); if (FileUtilities::basename(img->getFileName()) == imageName) { imageNumber = j; break; } } if (imageNumber >= 0) { GuiImageEditorWidget::VIEWING_IMAGE_SIZE sz = GuiImageEditorWidget::VIEWING_IMAGE_SIZE_100; if (sizeString == "25") { sz = GuiImageEditorWidget::VIEWING_IMAGE_SIZE_25; } else if (sizeString == "50") { sz = GuiImageEditorWidget::VIEWING_IMAGE_SIZE_50; } else if (sizeString == "75") { sz = GuiImageEditorWidget::VIEWING_IMAGE_SIZE_75; } else if (sizeString == "100") { sz = GuiImageEditorWidget::VIEWING_IMAGE_SIZE_100; } else if (sizeString == "125") { sz = GuiImageEditorWidget::VIEWING_IMAGE_SIZE_125; } else if (sizeString == "150") { sz = GuiImageEditorWidget::VIEWING_IMAGE_SIZE_150; } else if (sizeString == "200") { sz = GuiImageEditorWidget::VIEWING_IMAGE_SIZE_200; } else if (sizeString == "400") { sz = GuiImageEditorWidget::VIEWING_IMAGE_SIZE_400; } else if (sizeString == "800") { sz = GuiImageEditorWidget::VIEWING_IMAGE_SIZE_800; } if (imageNumber >= 0) { displayImage(imageNumber); } imageSizeComboBox->setCurrentIndex(sz); imageViewer->setViewingSize(sz); move(geometry[0], geometry[1]); //resize(geometry[2], geometry[3]); updateWindow(); move(geometry[0], geometry[1]); //resize(geometry[2], geometry[3]); } } */ } //******************************************************************************** //******************************************************************************** //******************************************************************************** /** * constructor. */ GuiImageEditorWidget::GuiImageEditorWidget(QWidget *parent, const POPUP_MENU popupMenuStyleIn, Qt::WindowFlags f) : QWidget(parent, f) { // setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); viewingImageSize = VIEWING_IMAGE_SIZE_100; imageFile = NULL; popupMenuStyle = popupMenuStyleIn; addTextDialog = NULL; setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum)); croppingLinesValid = false; if (popupMenuStyle != POPUP_MENU_NONE) { this->setToolTip( "Press the right mouse button\n" "(control key + mouse click\n" "on Macs) for menu."); } } /** * destructor. */ GuiImageEditorWidget::~GuiImageEditorWidget() { } /** * set the image. */ void GuiImageEditorWidget::setImageFile(ImageFile* img) { imageFile = img; windowSizeChanged(); } /** * get size hint. */ QSize GuiImageEditorWidget::sizeHint() const { QSize sz; int w, h; getImageViewingWidthAndHeight(w, h); sz.setWidth(std::max(w, 100)); sz.setHeight(std::max(h, 100)); return sz; } /** * get the QImage of the ImageFile being displayed. */ QImage* GuiImageEditorWidget::getImageBeingDisplayed() { if (theMainWindow->getBrainSet()->getImageFileValid(imageFile)) { return imageFile->getImage(); } return NULL; } /** * get the QImage of the ImageFile being displayed. */ const QImage* GuiImageEditorWidget::getImageBeingDisplayed() const { if (theMainWindow->getBrainSet()->getImageFileValid(imageFile)) { return imageFile->getImage(); } return NULL; } /** * Get the image viewing width and height. */ void GuiImageEditorWidget::getImageViewingWidthAndHeight(int& w, int& h) const { w = 10; h = 10; const QImage* image = getImageBeingDisplayed(); if (image != NULL) { float width = image->width(); float height = image->height(); switch (viewingImageSize) { case VIEWING_IMAGE_SIZE_25: width *= 0.25; height *= 0.25; break; case VIEWING_IMAGE_SIZE_50: width *= 0.50; height *= 0.50; break; case VIEWING_IMAGE_SIZE_75: width *= 0.75; height *= 0.75; break; case VIEWING_IMAGE_SIZE_100: width *= 1.0; height *= 1.0; break; case VIEWING_IMAGE_SIZE_125: width *= 1.25; height *= 1.25; break; case VIEWING_IMAGE_SIZE_150: width *= 1.50; height *= 1.50; break; case VIEWING_IMAGE_SIZE_200: width *= 2.00; height *= 2.00; break; case VIEWING_IMAGE_SIZE_400: width *= 4.00; height *= 4.00; break; case VIEWING_IMAGE_SIZE_800: width *= 8.00; height *= 8.00; break; } w = static_cast(width); h = static_cast(height); } } /** * paint the widget. */ void GuiImageEditorWidget::paintEvent(QPaintEvent* /*pe*/) { QImage* image = getImageBeingDisplayed(); if (image == NULL) { return; } else if (image->isNull()) { return; } QPainter painter(this); // // Draw the image including any viewing scaling // QImage drawnImage = *image; int viewWidth, viewHeight; getImageViewingWidthAndHeight(viewWidth, viewHeight); drawnImage = image->scaled(viewWidth, viewHeight, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); painter.drawImage(0, 0, drawnImage); if (croppingLinesValid) { QPen pen(QColor(255, 0, 255), 1); painter.setPen(pen); int minX, maxX, minY, maxY; getCropping(minX, maxX, minY, maxY); painter.drawLine(minX, minY, maxX, minY); painter.drawLine(maxX, minY, maxX, maxY); painter.drawLine(maxX, maxY, minX, maxY); painter.drawLine(minX, maxY, minX, minY); } if (addTextDialog != NULL) { QString text; int x, y, rotation; QFont theFont; QColor fontColor; addTextDialog->getTextInfo(text, x, y, rotation, theFont, fontColor); QPen pen(fontColor); painter.setPen(pen); painter.setFont(theFont); painter.translate(x, y); painter.rotate(rotation); painter.drawText(0, 0, text); painter.resetMatrix(); } } /** * called when mouse pressed. */ void GuiImageEditorWidget::mousePressEvent(QMouseEvent* me) { croppingLinesValid = false; const int button = me->button(); const int modifiers = me->modifiers(); //std::cout << "Button: " << button << std::endl; //std::cout << "Modifiers: " << modifiers << std::endl; if (button == Qt::LeftButton) { if (modifiers == Qt::NoModifier) { croppingLines[0] = me->x(); croppingLines[1] = me->y(); croppingLines[2] = me->x(); croppingLines[3] = me->y(); croppingLinesValid = true; } } update(); } /** * get cropping min/max. */ void GuiImageEditorWidget::getCropping(int& minX, int& maxX, int& minY, int& maxY) const { minX = std::min(croppingLines[0], croppingLines[2]); maxX = std::max(croppingLines[0], croppingLines[2]); minY = std::min(croppingLines[1], croppingLines[3]); maxY = std::max(croppingLines[1], croppingLines[3]); } /** * called when mouse moved. */ void GuiImageEditorWidget::mouseMoveEvent(QMouseEvent* me) { const int button = me->button(); const int modifiers = me->modifiers(); if (croppingLinesValid) { if (button == Qt::NoButton) { if (modifiers == Qt::NoModifier) { croppingLines[2] = me->x(); croppingLines[3] = me->y(); } } update(); } } /** * popup the context menu. */ void GuiImageEditorWidget::contextMenuEvent(QContextMenuEvent* cme) { bool haveEditOptions = false; bool haveOpenSaveOptions = false; switch (popupMenuStyle) { case POPUP_MENU_NONE: return; break; case POPUP_MENU_EDIT_ONLY: haveEditOptions = true; break; case POPUP_MENU_EDIT_OPEN_SAVE: haveEditOptions = true; haveOpenSaveOptions = true; break; } menuX = cme->x(); menuY = cme->y(); QMenu menu(this); if (haveOpenSaveOptions) { menu.addAction("Load Image...", this, SLOT(slotLoadImage())); menu.addAction("Save Image...", this, SLOT(slotSaveImage())); } if (haveEditOptions) { if (haveOpenSaveOptions) { menu.addSeparator(); } menu.addAction("Add Text...", this, SLOT(slotAddTextPopupMenu())); menu.addAction("Crop Image...", this, SLOT(slotCropImage())); menu.addAction("Scale Image...", this, SLOT(slotResizeImage())); } menu.exec(QCursor::pos()); } /** * called when a viewing size is selected. */ void GuiImageEditorWidget::slotViewingSizeMenu(int id) { setViewingSize(static_cast(id)); } /** * add text. */ void GuiImageEditorWidget::addText(const int x, const int y) { QImage* image = getImageBeingDisplayed(); if (image == NULL) { return; } if (viewingImageSize != VIEWING_IMAGE_SIZE_100) { QApplication::beep(); QMessageBox::critical(this, "ERROR", "The image must be at 100% viewing\n" "scale for adding text."); return; } addTextDialog = new GuiImageEditorWidgetAddTextDialog(this, x, y); QObject::connect(addTextDialog, SIGNAL(signalTextUpdated()), this, SLOT(update())); if (addTextDialog->exec() == QDialog::Accepted) { update(); *image = QPixmap::grabWidget(this).toImage(); imageFile->setModified(); GuiFilesModified fm; fm.setImagesModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } delete addTextDialog; addTextDialog = NULL; update(); } /** * called to add text to the image (text X/Y set to popup menu position). */ void GuiImageEditorWidget::slotAddTextPopupMenu() { addText(menuX, menuY); } /** * called to add text to the image. */ void GuiImageEditorWidget::slotAddText() { QImage* image = getImageBeingDisplayed(); if (image == NULL) { return; } addText((image->width() / 2), (image->height() / 2)); } /** * called to resize the image. */ void GuiImageEditorWidget::slotResizeImage() { if (theMainWindow->getBrainSet()->getImageFileValid(imageFile)) { QImage* image = imageFile->getImage(); if (image == NULL) { return; } GuiImageResizeDialog ird(this, *image); if (ird.exec() == QDialog::Accepted) { imageFile->setModified(); GuiFilesModified fm; fm.setImagesModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } } /* if (theMainWindow->getBrainSet()->getImageFileValid(imageFile)) { QImage* image = imageFile->getImage(); if (image == NULL) { return; } GuiImageEditorWidgetResizeDialog iewrd(this, image->width(), image->height()); if (iewrd.exec() == QDialog::Accepted) { int x, y; iewrd.getImageSizes(x, y); *image = image->scaled(x, y, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); imageFile->setModified(); GuiFilesModified fm; fm.setImagesModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } } */ windowSizeChanged(); } /** * called to crop the image. */ void GuiImageEditorWidget::slotCropImage() { QImage* image = getImageBeingDisplayed(); if (image == NULL) { return; } if (viewingImageSize != VIEWING_IMAGE_SIZE_100) { QApplication::beep(); QMessageBox::critical(this, "ERROR", "The image must be at 100% viewing\n" "scale for cropping."); return; } int minX, maxX, minY, maxY; getCropping(minX, maxX, minY, maxY); if ((croppingLinesValid == false) || (minX == maxX) || (minY == maxY)) { QMessageBox::critical(this, "ERROR", "No part of the image is selected.\n" "\n" "After closing this dialog, move the mouse to\n" "a corner of the desired subregion of the image\n" "and, while holding down the left mouse button,\n" "drag the mouse to the opposite corner of the\n" "image subregion and release the mouse. Next,\n" "press the crop button \"C\" in the toolbar to\n" "crop the image."); return; } *image = image->copy(minX, minY, maxX - minX + 1, maxY - minY + 1); imageFile->setModified(); GuiFilesModified fm; fm.setImagesModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); croppingLinesValid = false; windowSizeChanged(); } /** * called to load an image. */ void GuiImageEditorWidget::slotLoadImage() { /* WuQFileDialog fd(this, "fd" , true); fd.setWindowTitle("Save Image File"); fd.setFileMode(WuQFileDialog::ExistingFile); fd.setFilter("JPEG FILES (*.jpg *.jpeg)"); if (fd.exec() == WuQFileDialog::Accepted) { image->load(fd.selectedFiles().at(0)); } windowSizeChanged(); */ } /** * window size changed. */ void GuiImageEditorWidget::windowSizeChanged() { // // Allows dialog to resize to fit image and don't let it change position // update(); updateGeometry(); adjustSize(); parentWidget()->updateGeometry(); parentWidget()->adjustSize(); emit signalGeometryChanged(); } /** * called to save an image. */ void GuiImageEditorWidget::slotSaveImage() { /* WuQFileDialog fd(this, "fd" , true); fd.setWindowTitle("Save Image File"); fd.setFileMode(WuQFileDialog::AnyFile); fd.setFilter("JPEG FILES (*.jpg *.jpeg)"); if (fd.exec() == WuQFileDialog::Accepted) { image->save(fd.selectedFiles().at(0), "JPEG"); } windowSizeChanged(); */ } /** * set the viewing size. */ void GuiImageEditorWidget::setViewingSize(const VIEWING_IMAGE_SIZE vis) { viewingImageSize = vis; windowSizeChanged(); } /** * get the viewing size. */ GuiImageEditorWidget::VIEWING_IMAGE_SIZE GuiImageEditorWidget::getViewingSize() const { return viewingImageSize; } //******************************************************************************** //******************************************************************************** //******************************************************************************** /** * constructor. */ GuiImageEditorWidgetResizeDialog::GuiImageEditorWidgetResizeDialog(QWidget* parent, const int xSize, const int ySize) : WuQDialog(parent) { setModal(true); setWindowTitle("Scaling"); originalAspect = static_cast(xSize) / static_cast(ySize); // // Layout for dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // Grid for spin boxes // QGridLayout* gridLayout = new QGridLayout; dialogLayout->addLayout(gridLayout); // // X size spin boxes // gridLayout->addWidget(new QLabel("Width "), 0, 0); xSizeSpinBox = new QSpinBox; xSizeSpinBox->setMinimum(1); xSizeSpinBox->setMaximum(std::numeric_limits::max()); xSizeSpinBox->setSingleStep(1); gridLayout->addWidget(xSizeSpinBox, 0, 1); xSizeSpinBox->setValue(xSize); QObject::connect(xSizeSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotXSizeSpinBox(int))); // // Y size spin boxes // gridLayout->addWidget(new QLabel("Height "), 1, 0); ySizeSpinBox = new QSpinBox; ySizeSpinBox->setMinimum(1); ySizeSpinBox->setMaximum(std::numeric_limits::max()); ySizeSpinBox->setSingleStep(1); gridLayout->addWidget(ySizeSpinBox, 1, 1); ySizeSpinBox->setValue(ySize); QObject::connect(ySizeSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotYSizeSpinBox(int))); // // aspect check box // aspectCheckBox = new QCheckBox("Maintain Aspect", this); aspectCheckBox->setChecked(true); dialogLayout->addWidget(aspectCheckBox); // // Layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); dialogLayout->addLayout(buttonsLayout); // // OK button // QPushButton* okButton = new QPushButton("OK"); buttonsLayout->addWidget(okButton); okButton->setAutoDefault(false); QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); // // Cancel button // QPushButton* cancelButton = new QPushButton("Cancel"); buttonsLayout->addWidget(cancelButton); cancelButton->setAutoDefault(false); QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); //QtUtilities::makeButtonsSameSize(okButton, cancelButton); } /** * destructor. */ GuiImageEditorWidgetResizeDialog::~GuiImageEditorWidgetResizeDialog() { } /** * get the image sizes. */ void GuiImageEditorWidgetResizeDialog::getImageSizes(int& x, int&y) const { x = xSizeSpinBox->value(); y = ySizeSpinBox->value(); } /** * called when x spin box value is changed. */ void GuiImageEditorWidgetResizeDialog::slotXSizeSpinBox(int value) { if (aspectCheckBox->isChecked()) { ySizeSpinBox->blockSignals(true); ySizeSpinBox->setValue(static_cast(value / originalAspect)); ySizeSpinBox->blockSignals(false); } } /** * called when y spin box value is changed. */ void GuiImageEditorWidgetResizeDialog::slotYSizeSpinBox(int value) { if (aspectCheckBox->isChecked()) { xSizeSpinBox->blockSignals(true); xSizeSpinBox->setValue(static_cast(value * originalAspect)); xSizeSpinBox->blockSignals(false); } } /** * called when OK or Cancel button is pressed. */ void GuiImageEditorWidgetResizeDialog::done(int r) { QDialog::done(r); } //******************************************************************************** //******************************************************************************** //******************************************************************************** /** * constructor. */ GuiImageEditorWidgetAddTextDialog::GuiImageEditorWidgetAddTextDialog(QWidget* parent, const int x, const int y) : WuQDialog(parent) { setModal(true); if (staticDataInitialized == false) { staticDataInitialized = true; fontColor.setRgb(0, 0, 0); } setWindowTitle("Add Text"); // // Layout for dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // Choose font push button // fontPushButton = new QPushButton("Choose Font..."); fontPushButton->setFont(theFont); dialogLayout->addWidget(fontPushButton); fontPushButton->setAutoDefault(false); QObject::connect(fontPushButton, SIGNAL(clicked()), this, SLOT(slotFontPushButton())); fontPushButton->setToolTip( "Pressing this button will display a\n" "dialog for choosing the font for the text."); // // Choose font color push button // fontColorPushButton = new QPushButton("Choose Font Color..."); dialogLayout->addWidget(fontColorPushButton); fontColorPushButton->setAutoDefault(false); QObject::connect(fontColorPushButton, SIGNAL(clicked()), this, SLOT(slotFontColorPushButton())); fontColorPushButton->setToolTip( "Pressing this button will display a\n" "dialog for choosing the color for the text."); // // Grid for spin boxes // QGridLayout* grid = new QGridLayout; dialogLayout->addLayout(grid); // // Text line edit // grid->addWidget(new QLabel("Text "), 0, 0); textLineEdit = new QLineEdit; grid->addWidget(textLineEdit, 0, 1); QObject::connect(textLineEdit, SIGNAL(textChanged(const QString&)), this, SIGNAL(signalTextUpdated())); // // X size spin boxes // grid->addWidget(new QLabel("X "), 1, 0); xSpinBox = new QSpinBox; xSpinBox->setMinimum(0); xSpinBox->setMaximum(parent->width()); xSpinBox->setSingleStep(1); xSpinBox->setValue(x); grid->addWidget(xSpinBox, 1, 1); QObject::connect(xSpinBox, SIGNAL(valueChanged(int)), this, SIGNAL(signalTextUpdated())); // // Y size spin boxes // grid->addWidget(new QLabel("Y "), 2, 0); ySpinBox = new QSpinBox; ySpinBox->setValue(ySpinBox->maximum() - y); ySpinBox->setMinimum(0); ySpinBox->setMaximum(parent->height()); ySpinBox->setSingleStep(1); grid->addWidget(ySpinBox, 2, 1); QObject::connect(ySpinBox, SIGNAL(valueChanged(int)), this, SIGNAL(signalTextUpdated())); // // Rotation spin boxes // grid->addWidget(new QLabel("Rotation "), 3, 0); rotationSpinBox = new QSpinBox; rotationSpinBox->setValue(0); rotationSpinBox->setMinimum(0); rotationSpinBox->setMaximum(360); rotationSpinBox->setWrapping(true); rotationSpinBox->setSingleStep(1); grid->addWidget(rotationSpinBox, 3, 1); QObject::connect(rotationSpinBox, SIGNAL(valueChanged(int)), this, SIGNAL(signalTextUpdated())); // // Layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); dialogLayout->addLayout(buttonsLayout); // // OK button // QPushButton* okButton = new QPushButton("OK"); buttonsLayout->addWidget(okButton); okButton->setAutoDefault(false); QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); okButton->setToolTip( "Pressing this button will apply\n" "the text to the image. Note: \n" "There is no undo capability."); // // Cancel button // QPushButton* cancelButton = new QPushButton("Cancel"); buttonsLayout->addWidget(cancelButton); cancelButton->setAutoDefault(false); QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); cancelButton->setToolTip( "Pressing this button will close\n" "this dialog and no text will be\n" "added to the image."); //QtUtilities::makeButtonsSameSize(okButton, cancelButton); } /** * destructor. */ GuiImageEditorWidgetAddTextDialog::~GuiImageEditorWidgetAddTextDialog() { } /** * called to select the font color. */ void GuiImageEditorWidgetAddTextDialog::slotFontColorPushButton() { fontColor = QColorDialog::getColor(fontColor, this); //fontColorPushButton->setPaletteForegroundColor(fontColor); QPalette palette; palette.setColor(fontColorPushButton->foregroundRole(), fontColor); fontColorPushButton->setPalette(palette); /* if (fontColorPushButton->eraseColor() == fontColor) { if (fontColor.red() < 128) { fontColorPushButton->setEraseColor(QColor(255, 255, 255)); } else { fontColorPushButton->setEraseColor(QColor(0, 0, 0)); } } */ emit signalTextUpdated(); } /** * called to select the font. */ void GuiImageEditorWidgetAddTextDialog::slotFontPushButton() { bool ok; theFont = QFontDialog::getFont(&ok, theFont, this); fontPushButton->setFont(theFont); emit signalTextUpdated(); } /** * get the info about the text. */ void GuiImageEditorWidgetAddTextDialog::getTextInfo(QString& text, int& x, int& y, int& rotation, QFont& textFont, QColor& textColor) const { text = textLineEdit->text(); x = xSpinBox->value(); y = ySpinBox->maximum() - ySpinBox->value(); rotation = rotationSpinBox->value(); textFont = theFont; textColor = fontColor; } /** * called when OK or Cancel button is pressed. */ void GuiImageEditorWidgetAddTextDialog::done(int r) { QDialog::done(r); } caret-5.6.4~dfsg.1.orig/caret/GuiIdentifyDialog.h0000664000175000017500000005322011572067322021372 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_GUI_IDENTIFY_DIALOG_H__ #define __VE_GUI_IDENTIFY_DIALOG_H__ #include #include #include "BrainModel.h" #include "BrainSet.h" #include "WuQDialog.h" class QCheckBox; class QGroupBox; class GuiHyperLinkTextBrowser; class GuiIdentifyMainWindow; class QSpinBox; class BrainModelOpenGLSelectedItem; /// Dialog that displays a scrolling text area containing identification information class GuiIdentifyDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiIdentifyDialog(QWidget* parent); /// Destructor ~GuiIdentifyDialog(); /// append to the text display void appendText(const QString& s); /// append html void appendHtml(const QString& html); /// apply a scene (update dialog) void showScene(const SceneFile::Scene& scene, const int mainWindowX, const int mainWindowY, const int mainWindowSceneX, const int mainWindowSceneY, const int screenMaxX, const int screenMaxY, QString& errorMessage); /// create a scene (save dialog settings) void saveScene(std::vector& scs); /// display vocabulary name in identify window void displayVocabularyNameData(const QString& name); /// update the dialog void updateDialog(); private: /// display info for the volume void displayVolumeInfo(VolumeFile* vf, const int i, const int j, const int k, const BrainModel::BRAIN_MODEL_VIEW_NUMBER windowNumber); /// the main window placed into the dialog GuiIdentifyMainWindow* idMainWindow; /// significant digits for display int sigDigits; /// cross timer window number BrainModel::BRAIN_MODEL_VIEW_NUMBER crossTimerWindowNumber; }; /// Main Window that is placed in dialog to allow toolbars class GuiIdentifyMainWindow : public QMainWindow { Q_OBJECT public: /// Constructor. GuiIdentifyMainWindow(GuiIdentifyDialog* parent = 0); /// Destructor. ~GuiIdentifyMainWindow(); /// append to the text display void appendText(const QString& s); /// append html void appendHtml(const QString& html); /// update the filtering toggle buttons void updateToolBarButtons(); /// update the filtering selections void updateFilteringSelections(); private slots: /// all on button void slotAllOn(); /// all off button void slotAllOff(); /// clear all node ID symbols void clearNodeID(); /// display border information toolbar button void slotBorderAction(bool val); /// display cell information toolbar button void slotCellAction(bool val); /// display foci information toolbar button void slotFociAction(bool val); /// display foci name information toolbar button void slotFociNameAction(bool val); /// display foci class information toolbar button void slotFociClassAction(bool val); /// display foci original stereotaxic position information toolbar button void slotFociOriginalStereotaxicPositionAction(bool val); /// display foci stereotaxic position information toolbar button void slotFociStereotaxicPositionAction(bool val); /// display foci area information toolbar button void slotFociAreaAction(bool val); /// display foci geography information toolbar button void slotFociGeographyAction(bool val); /// display foci region of interest information toolbar button void slotFociRegionOfInterestAction(bool val); /// display foci size information toolbar button void slotFociSizeAction(bool val); /// display foci Statistic information toolbar button void slotFociStatisticAction(bool val); /// display foci Structure information toolbar button void slotFociStructureAction(bool val); /// display foci comment information toolbar button void slotFociCommentAction(bool val); /// display voxel information toolbar button void slotVoxelAction(bool val); /// display contour action void slotContourAction(bool val); /// display node information void slotNodeAction(bool val); /// display node coordinate information void slotNodeCoordAction(bool val); /// display node lat/lon information void slotNodeLatLonAction(bool val); /// display node paint information void slotNodePaintAction(bool val); /// display node probabilistic atlas information void slotNodeProbAtlasAction(bool val); /// display node rgb paint information void slotNodeRgbPaintAction(bool val); /// display node metric information void slotNodeMetricAction(bool val); /// display node shape information void slotNodeShapeAction(bool val); /// display node section information void slotNodeSectionAction(bool val); /// display node areal estimation information void slotNodeArealEstAction(bool val); /// display node topography information void slotNodeTopographyAction(bool val); /// show study meta-analysis info group box void slotShowMetaAnalysisInfoGroupBox(bool val); /// show study meta-analysis name info check box void slotShowMetaAnalysisNameInfoCheckBox(bool val); /// show study meta-analysis title info check box void slotShowMetaAnalysisTitleInfoCheckBox(bool val); /// show study meta-analysis authors info check box void slotShowMetaAnalysisAuthorsInfoCheckBox(bool val); /// show study meta-analysis citation info check box void slotShowMetaAnalysisCitationInfoCheckBox(bool val); /// show study meta-analysis DOI/URL info check box void slotShowMetaAnalysisDoiUrlInfoCheckBox(bool val); /// display study information void slotStudyAction(bool val); /// show study title info check box; void slotShowStudyTitleInfoCheckBox(bool val); /// show study author info check box; void slotShowStudyAuthorInfoCheckBox(bool val); /// show study citation info check box; void slotShowStudyCitationInfoCheckBox(bool val); /// show study comment info check box; void slotShowStudyCommentInfoCheckBox(bool val); /// show study data format info check box; void slotShowStudyDataFormatInfoCheckBox(bool val); /// show study data type info check box; void slotShowStudyDataTypeInfoCheckBox(bool val); /// show study DOI info check box; void slotShowStudyDOIInfoCheckBox(bool val); /// show study keywords info check box; void slotShowStudyKeywordsInfoCheckBox(bool val); /// show study medical subject headings info check box void slotShowStudyMedicalSubjectHeadingInfoCheckBox(bool val); /// show study name info check box void slotShowStudyNameInfoCheckBox(bool val); /// show study part scheme abbrev info check box; void slotShowStudyPartSchemeAbbrevInfoCheckBox(bool val); /// show study part scheme full info check box; void slotShowStudyPartSchemeFullInfoCheckBox(bool val); /// show study PubMed ID info check box; void slotShowStudyPubMedIDInfoCheckBox(bool val); /// show study project ID info check box; void slotShowStudyProjectIDInfoCheckBox(bool val); /// show study stereotaxic space info check box; void slotShowStudyStereotaxicSpaceInfoCheckBox(bool val); /// show study stereotaxic space details info check box; void slotShowStudyStereotaxicSpaceDetailsInfoCheckBox(bool val); /// show study URL info check box; void slotShowStudyURLInfoCheckBox(bool val); /// show study table info group box; void slotShowStudyTableInfoGroupBox(bool val); /// show study table header info check box; void slotShowStudyTableHeaderInfoCheckBox(bool val); /// show study table footer info check box; void slotShowStudyTableFooterInfoCheckBox(bool val); /// show study table size units info check box; void slotShowStudyTableSizeUnitsInfoCheckBox(bool val); /// show study table voxel size info check box; void slotShowStudyTableVoxelSizeInfoCheckBox(bool val); /// show study table statistic info check box; void slotShowStudyTableStatisticInfoCheckBox(bool val); /// show study table statistic description info check box; void slotShowStudyTableStatisticDescriptionInfoCheckBox(bool val); /// show study figure info group box; void slotShowStudyFigureInfoGroupBox(bool val); /// show study figure legend info check box; void slotShowStudyFigureLegendInfoCheckBox(bool val); /// show study figure panel info group box; void slotShowStudyFigurePanelInfoGroupBox(bool val); /// show study figure panel description info check box; void slotShowStudyFigurePanelDescriptionInfoCheckBox(bool val); /// show study figure panel task description info check box; void slotShowStudyFigurePanelTaskDescriptionInfoCheckBox(bool val); /// show study figure panel task baseline info check box; void slotShowStudyFigurePanelTaskBaselineInfoCheckBox(bool val); /// show study figure panel test attributes info check box; void slotShowStudyFigurePanelTestAttributesInfoCheckBox(bool val); /// show study subheader info group box void slotShowStudySubHeaderInfoGroupBox(bool val); /// show study subheader name info check box void slotShowStudySubHeaderNameInfoCheckBox(bool val); /// show study subheader short name info check box void slotShowStudySubHeaderShortNameInfoCheckBox(bool val); /// show study subheader task description info check box void slotShowStudySubHeaderTaskDescriptionInfoCheckBox(bool val); /// show study subheader task baseline info check box void slotShowStudySubHeaderTaskBaselineInfoCheckBox(bool val); /// show study subheader test attributes info check box void slotShowStudySubHeaderTestAttributesInfoCheckBox(bool val); /// show study page reference info group box; void slotShowStudyPageReferenceInfoGroupBox(bool val); /// show study page reference header info check box; void slotShowStudyPageReferenceHeaderInfoCheckBox(bool val); /// show study page reference comment info check box; void slotShowStudyPageReferenceCommentInfoCheckBox(bool val); /// show study page reference size units info check box; void slotShowStudyPageReferenceSizeUnitsInfoCheckBox(bool val); /// show study page reference voxel size info check box; void slotShowStudyPageReferenceVoxelSizeInfoCheckBox(bool val); /// show study page reference statistic info check box; void slotShowStudyPageReferenceStatisticInfoCheckBox(bool val); /// show study page reference statistic description info check box; void slotShowStudyPageReferenceStatisticDescriptionInfoCheckBox(bool val); /// show study page number info check box; //void slotShowStudyPageNumberInfoCheckBox(bool val); /// show ID symbols on surface void slotShowIDAction(bool val); /// significant digits display void slotSignificantDigitsSpinBox(int val); private: // create the text display widget QWidget* createTextDisplayWidget(); // create the widget for the display filtering QWidget* createDisplayFilterWidget(); // create the tool bar QToolBar* createToolBar(); /// text editor for display of identification information GuiHyperLinkTextBrowser* textDisplayBrowser; /// show ID symbols on surface QAction* showIDAction; /// significant digits display QSpinBox* significantDigitsSpinBox; /// show node info group box QGroupBox* showNodeInfoGroupBox; /// show node areal estimation info check box QCheckBox* showNodeArealEstInfoCheckBox; /// show node coord info check box QCheckBox* showNodeCoordInfoCheckBox; /// show node lat/lon info check box QCheckBox* showNodeLatLonInfoCheckBox; /// show node metric info check box QCheckBox* showNodeMetricInfoCheckBox; /// show node paint info check box QCheckBox* showNodePaintInfoCheckBox; /// show node prob atlas info check box QCheckBox* showNodeProbAtlasInfoCheckBox; /// show node rgb paint info check box QCheckBox* showNodeRgbPaintInfoCheckBox; /// show node section info check box QCheckBox* showNodeSectionInfoCheckBox; /// show node shape info check box QCheckBox* showNodeShapeInfoCheckBox; /// show node topography info check box QCheckBox* showNodeTopographyInfoCheckBox; /// show border info check box; QCheckBox* showBorderInfoCheckBox; /// show cell info check box; QCheckBox* showCellInfoCheckBox; /// show contour info check box; QCheckBox* showContourInfoCheckBox; /// show foci info group box; QGroupBox* showFociInfoGroupBox; /// show foci name info check box; QCheckBox* showFociNameInfoCheckBox; /// show foci class info check box; QCheckBox* showFociClassInfoCheckBox; /// show foci original stereotaxic position info check box; QCheckBox* showFociOriginalStereotaxicPositionInfoCheckBox; /// show foci stereotaxic position info check box; QCheckBox* showFociStereotaxicPositionInfoCheckBox; /// show foci area info check box; QCheckBox* showFociAreaInfoCheckBox; /// show foci geography info check box; QCheckBox* showFociGeographyInfoCheckBox; /// show foci region of interest info check box; QCheckBox* showFociRegionOfInterestInfoCheckBox; /// show foci size info check box; QCheckBox* showFociSizeInfoCheckBox; /// show foci statistic info check box; QCheckBox* showFociStatisticInfoCheckBox; /// show foci structure info check box QCheckBox* showFociStructureInfoCheckBox; /// show foci comment info check box; QCheckBox* showFociCommentInfoCheckBox; /// show voxel info check box; QCheckBox* showVoxelInfoCheckBox; /// show study meta-analysis info group box QGroupBox* showStudyMetaAnalysisInfoGroupBox; /// show study name info check box; QCheckBox* showStudyMetaAnalysisNameInfoCheckBox; /// show study title info check box; QCheckBox* showStudyMetaAnalysisTitleInfoCheckBox; /// show study author info check box; QCheckBox* showStudyMetaAnalysisAuthorInfoCheckBox; /// show study citation info check box; QCheckBox* showStudyMetaAnalysisCitationInfoCheckBox; /// show study DOI info check box; QCheckBox* showStudyMetaAnalysisDOIInfoCheckBox; /// show study info group box; QGroupBox* showStudyInfoGroupBox; /// show study title info check box; QCheckBox* showStudyTitleInfoCheckBox; /// show study author info check box; QCheckBox* showStudyAuthorInfoCheckBox; /// show study citation info check box; QCheckBox* showStudyCitationInfoCheckBox; /// show study comment info check box; QCheckBox* showStudyCommentInfoCheckBox; /// show study data format info check box QCheckBox* showStudyDataFormatInfoCheckBox; /// show study data type info check box QCheckBox* showStudyDataTypeInfoCheckBox; /// show study DOI info check box; QCheckBox* showStudyDOIInfoCheckBox; /// show study keywords info check box; QCheckBox* showStudyKeywordsInfoCheckBox; /// show study medical subject info check box QCheckBox* showStudyMedicalSubjectHeadingInfoCheckBox; /// show study name info check box QCheckBox* showStudyNameInfoCheckBox; /// show study part scheme abbrev info check box; QCheckBox* showStudyPartSchemeAbbrevInfoCheckBox; /// show study part scheme full info check box; QCheckBox* showStudyPartSchemeFullInfoCheckBox; /// show study PubMed ID info check box; QCheckBox* showStudyPubMedIDInfoCheckBox; /// show study project ID info check box; QCheckBox* showStudyProjectIDInfoCheckBox; /// show study stereotaxic space info check box; QCheckBox* showStudyStereotaxicSpaceInfoCheckBox; /// show study stereotaxic space details info check box; QCheckBox* showStudyStereotaxicSpaceDetailsInfoCheckBox; /// show study URL info check box; QCheckBox* showStudyURLInfoCheckBox; /// show study table info group box; QGroupBox* showStudyTableInfoGroupBox; /// show study table header info check box; QCheckBox* showStudyTableHeaderInfoCheckBox; /// show study table footer info check box; QCheckBox* showStudyTableFooterInfoCheckBox; /// show study table size units info check box; QCheckBox* showStudyTableSizeUnitsInfoCheckBox; /// show study table voxel size info check box; QCheckBox* showStudyTableVoxelSizeInfoCheckBox; /// show study table statistic info check box; QCheckBox* showStudyTableStatisticInfoCheckBox; /// show study table statistic description info check box; QCheckBox* showStudyTableStatisticDescriptionInfoCheckBox; /// show study figure info group box; QGroupBox* showStudyFigureInfoGroupBox; /// show study figure legend info check box; QCheckBox* showStudyFigureLegendInfoCheckBox; /// show study figure panel info group box; QGroupBox* showStudyFigurePanelInfoGroupBox; /// show study figure panel description info group box; QCheckBox* showStudyFigurePanelDescriptionInfoCheckBox; /// show study figure panel task description info check box; QCheckBox* showStudyFigurePanelTaskDescriptionInfoCheckBox; /// show study figure panel task baseline info check box; QCheckBox* showStudyFigurePanelTaskBaselineInfoCheckBox; /// show study figure panel test attributes info check box; QCheckBox* showStudyFigurePanelTestAttributesInfoCheckBox; /// show study subheader info group box QGroupBox* showStudySubHeaderInfoGroupBox; /// show study subheader name info check box QCheckBox* showStudySubHeaderNameInfoCheckBox; /// show study subheader short name info check box QCheckBox* showStudySubHeaderShortNameInfoCheckBox; /// show study subheader task description info check box QCheckBox* showStudySubHeaderTaskDescriptionInfoCheckBox; /// show study subheader task baseline info check box QCheckBox* showStudySubHeaderTaskBaselineInfoCheckBox; /// show study subheader test attributes info check box QCheckBox* showStudySubHeaderTestAttributesInfoCheckBox; /// show study page reference info group box; QGroupBox* showStudyPageReferenceInfoGroupBox; /// show study page reference header info check box; QCheckBox* showStudyPageReferenceHeaderInfoCheckBox; /// show study page reference comment info check box; QCheckBox* showStudyPageReferenceCommentInfoCheckBox; /// show study page reference size units info check box; QCheckBox* showStudyPageReferenceSizeUnitsInfoCheckBox; /// show study page reference voxel size info check box; QCheckBox* showStudyPageReferenceVoxelSizeInfoCheckBox; /// show study page reference statistic info check box; QCheckBox* showStudyPageReferenceStatisticInfoCheckBox; /// show study page reference statistic description info check box; QCheckBox* showStudyPageReferenceStatisticDescriptionInfoCheckBox; /// show study page number info check box; //QCheckBox* showStudyPageNumberInfoCheckBox; }; #endif // __VE_GUI_IDENTIFY_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiIdentifyDialog.cxx0000664000175000017500000023057011572067322021752 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ArealEstimationFile.h" #include "BrainModelBorderSet.h" #include "BrainModelContours.h" #include "BrainModelIdentification.h" #include "BrainModelOpenGLSelectedItem.h" #include "BrainModelSurfaceNodeColoring.h" #include "BrainModelVolume.h" #include "BrainSet.h" #include "CellFile.h" #include "CellProjectionFile.h" #include "CommunicatorClientAFNI.h" #include "CommunicatorClientFIV.h" #include "ContourCellFile.h" #include "ContourFile.h" #include "DebugControl.h" #include "DisplaySettingsArealEstimation.h" #include "DisplaySettingsCoCoMac.h" #include "DisplaySettingsDeformationField.h" #include "DisplaySettingsGeodesicDistance.h" #include "DisplaySettingsMetric.h" #include "DisplaySettingsPaint.h" #include "DisplaySettingsRgbPaint.h" #include "DisplaySettingsScene.h" #include "DisplaySettingsSurface.h" #include "DisplaySettingsSurfaceShape.h" #include "DisplaySettingsTopography.h" #include "DisplaySettingsWustlRegion.h" #include "FileUtilities.h" #include "FociFile.h" #include "FociProjectionFile.h" #include "GeodesicDistanceFile.h" #include "GuiBrainModelOpenGL.h" #include "GuiHyperLinkTextBrowser.h" #include "GuiIdentifyDialog.h" #include "GuiMainWindow.h" #include "GuiToolBar.h" #include "MathUtilities.h" #include "MetricFile.h" #include "LatLonFile.h" #include "PaintFile.h" #include "PaletteFile.h" #include "PreferencesFile.h" #include "ProbabilisticAtlasFile.h" #include "RgbPaintFile.h" #include "SectionFile.h" #include "StereotaxicSpace.h" #include "StringUtilities.h" #include "SurfaceShapeFile.h" #include "TopographyFile.h" #include "VocabularyFile.h" #include "VtkModelFile.h" #include "WustlRegionFile.h" #include "global_variables.h" /** * Constructor for Main Window containing text area and toolbars. */ GuiIdentifyMainWindow::GuiIdentifyMainWindow(GuiIdentifyDialog* parent) : QMainWindow(parent) { // // Tab widget for filtering and text display // QTabWidget* mainTabWidget = new QTabWidget; mainTabWidget->addTab(createTextDisplayWidget(), "Display"); mainTabWidget->addTab(createDisplayFilterWidget(), "Filtering"); setCentralWidget(mainTabWidget); // // Add the toolbar // Must be created after text display since it uses a signal from the text display // addToolBar(createToolBar()); updateToolBarButtons(); updateFilteringSelections(); } /** * create the tool bar. */ QToolBar* GuiIdentifyMainWindow::createToolBar() { // // Toolbar for node/border/cell/foci/clear buttons // QToolBar* toolbar = new QToolBar(this); toolbar->setMovable(false); // // Clear Identified Nodes toolbar button. // QAction* clearIDAction = new QAction("CID", this); clearIDAction->setToolTip( "Remove all border, foci,\n" "and node highlighting."); QObject::connect(clearIDAction, SIGNAL(triggered()), this, SLOT(clearNodeID())); QToolButton* clearIDButton = new QToolButton; clearIDButton->setDefaultAction(clearIDAction); toolbar->addWidget(clearIDButton); // // Add a separator to the toolbar // toolbar->addSeparator(); // // clear toolbar button. // QAction* clearAction = new QAction("Clear", this); clearAction->setToolTip( "Clear all identification\n" "information from the \n" "text window."); QObject::connect(clearAction, SIGNAL(triggered()), textDisplayBrowser, SLOT(clear())); QToolButton* clearButton = new QToolButton; clearButton->setDefaultAction(clearAction); toolbar->addWidget(clearButton); // // Copy highlighted text to clipboard // /* QAction* copyAction = new QAction("Copy", this); copyAction->setEnabled(false); QObject::connect(copyAction, SIGNAL(triggered(bool)), textDisplayBrowser, SLOT(copy())); copyAction->setToolTip( "Highlight text with the mouse and\n" "then press this button to copy\n" "the highlighted text to the clipboard."); */ QToolButton* copyButton = new QToolButton; copyButton->setText("Copy"); //copyButton->setDefaultAction(copyAction); QObject::connect(copyButton, SIGNAL(clicked()), textDisplayBrowser, SLOT(copy())); copyButton->setToolTip( "Highlight text with the mouse and\n" "then press this button to copy\n" "the highlighted text to the clipboard."); toolbar->addWidget(copyButton); // // Enable the copy button when text is highlighted // QObject::connect(textDisplayBrowser, SIGNAL(copyAvailable(bool)), copyButton, SLOT(setEnabled(bool))); // // Add a separator to the toolbar // toolbar->addSeparator(); // // Show Identified Nodes // showIDAction = new QAction("SID", this); showIDAction->setCheckable(true); showIDAction->setToolTip( " Enable green ID\n" "symbols on surface."); showIDAction->setChecked(true); QObject::connect(showIDAction, SIGNAL(toggled(bool)), this, SLOT(slotShowIDAction(bool))); QToolButton* showIDButton = new QToolButton; showIDButton->setDefaultAction(showIDAction); toolbar->addWidget(showIDButton); return toolbar; } /** * create the text display widget. */ QWidget* GuiIdentifyMainWindow::createTextDisplayWidget() { // // Text Editor displays identification information // textDisplayBrowser = new GuiHyperLinkTextBrowser(0); //QTextBrowser(vbox, "textDisplayBrowser"); //new QTextEdit(vbox); textDisplayBrowser->setReadOnly(true); textDisplayBrowser->resize(QSize(textDisplayBrowser->sizeHint().width(), 100)); return textDisplayBrowser; } /** * create the widget for the display filtering. */ QWidget* GuiIdentifyMainWindow::createDisplayFilterWidget() { // // all on/off buttons // QPushButton* allOnPushButton = new QPushButton("All On"); allOnPushButton->setAutoDefault(false); QObject::connect(allOnPushButton, SIGNAL(clicked()), this, SLOT(slotAllOn())); QPushButton* allOffPushButton = new QPushButton("All Off"); allOffPushButton->setAutoDefault(false); QObject::connect(allOffPushButton, SIGNAL(clicked()), this, SLOT(slotAllOff())); QHBoxLayout* allOnOffButtonLayout = new QHBoxLayout; allOnOffButtonLayout->addWidget(allOnPushButton); allOnOffButtonLayout->addWidget(allOffPushButton); allOnOffButtonLayout->addStretch(); // // show node info check box // showNodeArealEstInfoCheckBox = new QCheckBox("Areal Estimation"); QObject::connect(showNodeArealEstInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotNodeArealEstAction(bool))); // // show node coord info check box // showNodeCoordInfoCheckBox = new QCheckBox("Coordinate"); QObject::connect(showNodeCoordInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotNodeCoordAction(bool))); // // show node lat/lon info check box // showNodeLatLonInfoCheckBox = new QCheckBox("Latitude/Longitude"); QObject::connect(showNodeLatLonInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotNodeLatLonAction(bool))); // // show node metric info check box // showNodeMetricInfoCheckBox = new QCheckBox("Metric"); QObject::connect(showNodeMetricInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotNodeMetricAction(bool))); // // show node paint info check box // showNodePaintInfoCheckBox = new QCheckBox("Paint"); QObject::connect(showNodePaintInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotNodePaintAction(bool))); // // show node prob atlas info check box // showNodeProbAtlasInfoCheckBox = new QCheckBox("Probabilistic Atlas"); QObject::connect(showNodeProbAtlasInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotNodeProbAtlasAction(bool))); // // show node rgb paint info check box // showNodeRgbPaintInfoCheckBox = new QCheckBox("RGB Paint"); QObject::connect(showNodeRgbPaintInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotNodeRgbPaintAction(bool))); // // show node section info check box // showNodeSectionInfoCheckBox = new QCheckBox("Section"); QObject::connect(showNodeSectionInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotNodeSectionAction(bool))); // // show node shape info check box // showNodeShapeInfoCheckBox = new QCheckBox("Shape"); QObject::connect(showNodeShapeInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotNodeShapeAction(bool))); // // show node topography info check box // showNodeTopographyInfoCheckBox = new QCheckBox("Topography"); QObject::connect(showNodeTopographyInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotNodeTopographyAction(bool))); // // show node info group box // showNodeInfoGroupBox = new QGroupBox("Show Identified Node Information"); showNodeInfoGroupBox->setCheckable(true); QObject::connect(showNodeInfoGroupBox, SIGNAL(toggled(bool)), this, SLOT(slotNodeAction(bool))); QVBoxLayout* nodeGroupLayout = new QVBoxLayout(showNodeInfoGroupBox); nodeGroupLayout->addWidget(showNodeArealEstInfoCheckBox); nodeGroupLayout->addWidget(showNodeCoordInfoCheckBox); nodeGroupLayout->addWidget(showNodeLatLonInfoCheckBox); nodeGroupLayout->addWidget(showNodeMetricInfoCheckBox); nodeGroupLayout->addWidget(showNodePaintInfoCheckBox); nodeGroupLayout->addWidget(showNodeProbAtlasInfoCheckBox); nodeGroupLayout->addWidget(showNodeRgbPaintInfoCheckBox); nodeGroupLayout->addWidget(showNodeSectionInfoCheckBox); nodeGroupLayout->addWidget(showNodeShapeInfoCheckBox); nodeGroupLayout->addWidget(showNodeTopographyInfoCheckBox); // // Show border info check box // showBorderInfoCheckBox = new QCheckBox("Show Identified Border Information"); QObject::connect(showBorderInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotBorderAction(bool))); // // Show cell info check box // showCellInfoCheckBox = new QCheckBox("Show Identified Cell Information"); QObject::connect(showCellInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotCellAction(bool))); // // Show contour info check box // showContourInfoCheckBox = new QCheckBox("Show Identified Contour Information"); QObject::connect(showContourInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotContourAction(bool))); // // show foci name info check box // showFociNameInfoCheckBox = new QCheckBox("Name"); QObject::connect(showFociNameInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotFociNameAction(bool))); // // show foci class info check box // showFociClassInfoCheckBox = new QCheckBox("Class"); QObject::connect(showFociClassInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotFociClassAction(bool))); // // show original stereotaxic position info check box // showFociOriginalStereotaxicPositionInfoCheckBox = new QCheckBox("Stereotaxic Position (Original)"); QObject::connect(showFociOriginalStereotaxicPositionInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotFociOriginalStereotaxicPositionAction(bool))); // // show stereotaxic position info check box // showFociStereotaxicPositionInfoCheckBox = new QCheckBox("Stereotaxic Position"); QObject::connect(showFociStereotaxicPositionInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotFociStereotaxicPositionAction(bool))); // // show foci area info check box // showFociAreaInfoCheckBox = new QCheckBox("Area"); QObject::connect(showFociAreaInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotFociAreaAction(bool))); // // show foci geography info check box // showFociGeographyInfoCheckBox = new QCheckBox("Geography"); QObject::connect(showFociGeographyInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotFociGeographyAction(bool))); // // show foci region of interest info check box // showFociRegionOfInterestInfoCheckBox = new QCheckBox("Region of Interest"); QObject::connect(showFociRegionOfInterestInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotFociRegionOfInterestAction(bool))); // // show foci size info check box // showFociSizeInfoCheckBox = new QCheckBox("Extent"); QObject::connect(showFociSizeInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotFociSizeAction(bool))); // // show foci statistic info check box // showFociStatisticInfoCheckBox = new QCheckBox("Statistic"); QObject::connect(showFociStatisticInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotFociStatisticAction(bool))); // // show foci structure info check box // showFociStructureInfoCheckBox = new QCheckBox("Structure"); QObject::connect(showFociStructureInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotFociStructureAction(bool))); // // show foci comment info check box // showFociCommentInfoCheckBox = new QCheckBox("Comment"); QObject::connect(showFociCommentInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotFociCommentAction(bool))); // Show foci info check box // showFociInfoGroupBox = new QGroupBox("Show Identified Foci Information"); showFociInfoGroupBox->setCheckable(true); QObject::connect(showFociInfoGroupBox, SIGNAL(toggled(bool)), this, SLOT(slotFociAction(bool))); QVBoxLayout* fociGroupLayout = new QVBoxLayout(showFociInfoGroupBox); fociGroupLayout->addWidget(showFociAreaInfoCheckBox); fociGroupLayout->addWidget(showFociClassInfoCheckBox); fociGroupLayout->addWidget(showFociCommentInfoCheckBox); fociGroupLayout->addWidget(showFociGeographyInfoCheckBox); fociGroupLayout->addWidget(showFociNameInfoCheckBox); fociGroupLayout->addWidget(showFociRegionOfInterestInfoCheckBox); fociGroupLayout->addWidget(showFociSizeInfoCheckBox); fociGroupLayout->addWidget(showFociOriginalStereotaxicPositionInfoCheckBox); fociGroupLayout->addWidget(showFociStereotaxicPositionInfoCheckBox); fociGroupLayout->addWidget(showFociStatisticInfoCheckBox); fociGroupLayout->addWidget(showFociStructureInfoCheckBox); // // Show voxel info check box // showVoxelInfoCheckBox = new QCheckBox("Show Identified Voxel Information"); QObject::connect(showVoxelInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotVoxelAction(bool))); // // show study title info check box // showStudyTitleInfoCheckBox = new QCheckBox("Title"); QObject::connect(showStudyTitleInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudyTitleInfoCheckBox(bool))); // // show study author info check box // showStudyAuthorInfoCheckBox = new QCheckBox("Authors"); QObject::connect(showStudyAuthorInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudyAuthorInfoCheckBox(bool))); // // show study citation info check box // showStudyCitationInfoCheckBox = new QCheckBox("Citation"); QObject::connect(showStudyCitationInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudyCitationInfoCheckBox(bool))); // // show study comment info check box // showStudyCommentInfoCheckBox = new QCheckBox("Comment"); QObject::connect(showStudyCommentInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudyCommentInfoCheckBox(bool))); // // show study data format info check box // showStudyDataFormatInfoCheckBox = new QCheckBox("Data Format"); QObject::connect(showStudyDataFormatInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudyDataFormatInfoCheckBox(bool))); // // show study data type info check box // showStudyDataTypeInfoCheckBox = new QCheckBox("Data Type"); QObject::connect(showStudyDataTypeInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudyDataTypeInfoCheckBox(bool))); // // show study DOI info check box // showStudyDOIInfoCheckBox = new QCheckBox("DOI (Document Object Identifier)"); QObject::connect(showStudyDOIInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudyDOIInfoCheckBox(bool))); // // show study keywords info check box // showStudyKeywordsInfoCheckBox = new QCheckBox("Keywords"); QObject::connect(showStudyKeywordsInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudyKeywordsInfoCheckBox(bool))); // // show study medical subject headings info check box // showStudyMedicalSubjectHeadingInfoCheckBox = new QCheckBox("Medical Subject Headings"); QObject::connect(showStudyMedicalSubjectHeadingInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudyMedicalSubjectHeadingInfoCheckBox(bool))); // // show study name info check box // showStudyNameInfoCheckBox = new QCheckBox("Name"); QObject::connect(showStudyNameInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudyNameInfoCheckBox(bool))); // // show study part scheme abbrev info check box // showStudyPartSchemeAbbrevInfoCheckBox = new QCheckBox("Partitioning Scheme Abbreviation"); QObject::connect(showStudyPartSchemeAbbrevInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudyPartSchemeAbbrevInfoCheckBox(bool))); // // show study part scheme full info check box // showStudyPartSchemeFullInfoCheckBox = new QCheckBox("Partitioning Scheme Full Name"); QObject::connect(showStudyPartSchemeFullInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudyPartSchemeFullInfoCheckBox(bool))); // // show study PubMed ID info check box // showStudyPubMedIDInfoCheckBox = new QCheckBox("PubMed ID"); QObject::connect(showStudyPubMedIDInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudyPubMedIDInfoCheckBox(bool))); // // show study project ID info check box // showStudyProjectIDInfoCheckBox = new QCheckBox("Project ID"); QObject::connect(showStudyProjectIDInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudyProjectIDInfoCheckBox(bool))); // // show study stereotaxic space info check box // showStudyStereotaxicSpaceInfoCheckBox = new QCheckBox("Stereotaxic Space"); QObject::connect(showStudyStereotaxicSpaceInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudyStereotaxicSpaceInfoCheckBox(bool))); // // show study stereotaxic space details info check box // showStudyStereotaxicSpaceDetailsInfoCheckBox = new QCheckBox("Stereotaxic Space Details"); QObject::connect(showStudyStereotaxicSpaceDetailsInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudyStereotaxicSpaceDetailsInfoCheckBox(bool))); // // show study URL info check box // showStudyURLInfoCheckBox = new QCheckBox("URL"); QObject::connect(showStudyURLInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudyURLInfoCheckBox(bool))); // // show study table header info check box // showStudyTableHeaderInfoCheckBox = new QCheckBox("Header"); QObject::connect(showStudyTableHeaderInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudyTableHeaderInfoCheckBox(bool))); // // show study table footer info check box // showStudyTableFooterInfoCheckBox = new QCheckBox("Footer"); QObject::connect(showStudyTableFooterInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudyTableFooterInfoCheckBox(bool))); // // show study table size units info check box // showStudyTableSizeUnitsInfoCheckBox = new QCheckBox("Size Units"); QObject::connect(showStudyTableSizeUnitsInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudyTableSizeUnitsInfoCheckBox(bool))); // // show study table voxel size info check box // showStudyTableVoxelSizeInfoCheckBox = new QCheckBox("Voxel Size"); QObject::connect(showStudyTableVoxelSizeInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudyTableVoxelSizeInfoCheckBox(bool))); // // show study table statistic info check box // showStudyTableStatisticInfoCheckBox = new QCheckBox("Statistic Type"); QObject::connect(showStudyTableStatisticInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudyTableStatisticInfoCheckBox(bool))); // // show study table statistic description info check box // showStudyTableStatisticDescriptionInfoCheckBox = new QCheckBox("Statistic Description"); QObject::connect(showStudyTableStatisticDescriptionInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudyTableStatisticDescriptionInfoCheckBox(bool))); // // show study table info group box // showStudyTableInfoGroupBox = new QGroupBox("Tables"); showStudyTableInfoGroupBox->setCheckable(true); QObject::connect(showStudyTableInfoGroupBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudyTableInfoGroupBox(bool))); QVBoxLayout* studyTableLayout = new QVBoxLayout(showStudyTableInfoGroupBox); studyTableLayout->addWidget(showStudyTableFooterInfoCheckBox); studyTableLayout->addWidget(showStudyTableHeaderInfoCheckBox); studyTableLayout->addWidget(showStudyTableSizeUnitsInfoCheckBox); studyTableLayout->addWidget(showStudyTableStatisticInfoCheckBox); studyTableLayout->addWidget(showStudyTableStatisticDescriptionInfoCheckBox); studyTableLayout->addWidget(showStudyTableVoxelSizeInfoCheckBox); // // show study figure legend info check box // showStudyFigureLegendInfoCheckBox = new QCheckBox("Legend"); QObject::connect(showStudyFigureLegendInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudyFigureLegendInfoCheckBox(bool))); // // figure panel description check box // showStudyFigurePanelDescriptionInfoCheckBox = new QCheckBox("Description"); QObject::connect(showStudyFigurePanelDescriptionInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudyFigurePanelDescriptionInfoCheckBox(bool))); // // figure panel task description check box // showStudyFigurePanelTaskDescriptionInfoCheckBox = new QCheckBox("Task Description"); QObject::connect(showStudyFigurePanelTaskDescriptionInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudyFigurePanelTaskDescriptionInfoCheckBox(bool))); // // figure panel task baseline check box // showStudyFigurePanelTaskBaselineInfoCheckBox = new QCheckBox("Task Baseline"); QObject::connect(showStudyFigurePanelTaskBaselineInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudyFigurePanelTaskBaselineInfoCheckBox(bool))); // // figure panel test attributes check box // showStudyFigurePanelTestAttributesInfoCheckBox = new QCheckBox("Test Attributes"); QObject::connect(showStudyFigurePanelTestAttributesInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudyFigurePanelTestAttributesInfoCheckBox(bool))); // // Figure panel group box and layout // showStudyFigurePanelInfoGroupBox = new QGroupBox("Panel"); showStudyFigurePanelInfoGroupBox->setCheckable(true); QObject::connect(showStudyFigurePanelInfoGroupBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudyFigurePanelInfoGroupBox(bool))); QVBoxLayout* studyFigurePanelLayout = new QVBoxLayout(showStudyFigurePanelInfoGroupBox); studyFigurePanelLayout->addWidget(showStudyFigurePanelDescriptionInfoCheckBox); studyFigurePanelLayout->addWidget(showStudyFigurePanelTaskDescriptionInfoCheckBox); studyFigurePanelLayout->addWidget(showStudyFigurePanelTaskBaselineInfoCheckBox); studyFigurePanelLayout->addWidget(showStudyFigurePanelTestAttributesInfoCheckBox); // // show study figure info group box and layout // showStudyFigureInfoGroupBox = new QGroupBox("Figures"); showStudyFigureInfoGroupBox->setCheckable(true); QObject::connect(showStudyFigureInfoGroupBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudyFigureInfoGroupBox(bool))); QVBoxLayout* studyFigureLayout = new QVBoxLayout(showStudyFigureInfoGroupBox); studyFigureLayout->addWidget(showStudyFigureLegendInfoCheckBox); studyFigureLayout->addWidget(showStudyFigurePanelInfoGroupBox); // // show study sub header name check box // showStudySubHeaderNameInfoCheckBox = new QCheckBox("Name"); QObject::connect(showStudySubHeaderNameInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudySubHeaderNameInfoCheckBox(bool))); // // show study sub header short name check box // showStudySubHeaderShortNameInfoCheckBox = new QCheckBox("Short Name"); QObject::connect(showStudySubHeaderShortNameInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudySubHeaderShortNameInfoCheckBox(bool))); // // show study sub header task description check box // showStudySubHeaderTaskDescriptionInfoCheckBox = new QCheckBox("Task Description"); QObject::connect(showStudySubHeaderTaskDescriptionInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudySubHeaderTaskDescriptionInfoCheckBox(bool))); // // show study sub header task baseline check box // showStudySubHeaderTaskBaselineInfoCheckBox = new QCheckBox("Task Baseline"); QObject::connect(showStudySubHeaderTaskBaselineInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudySubHeaderTaskBaselineInfoCheckBox(bool))); // // show study sub header test attributes check box // showStudySubHeaderTestAttributesInfoCheckBox = new QCheckBox("Test Attributes"); QObject::connect(showStudySubHeaderTestAttributesInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudySubHeaderTestAttributesInfoCheckBox(bool))); // // show study sub header group box and layout // showStudySubHeaderInfoGroupBox = new QGroupBox("Study Subheaders"); showStudySubHeaderInfoGroupBox->setCheckable(true); QObject::connect(showStudySubHeaderInfoGroupBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudySubHeaderInfoGroupBox(bool))); QVBoxLayout* studySubHeaderLayout = new QVBoxLayout(showStudySubHeaderInfoGroupBox); studySubHeaderLayout->addWidget(showStudySubHeaderNameInfoCheckBox); studySubHeaderLayout->addWidget(showStudySubHeaderShortNameInfoCheckBox); studySubHeaderLayout->addWidget(showStudySubHeaderTaskDescriptionInfoCheckBox); studySubHeaderLayout->addWidget(showStudySubHeaderTaskBaselineInfoCheckBox); studySubHeaderLayout->addWidget(showStudySubHeaderTestAttributesInfoCheckBox); // // show study page reference header info check box // showStudyPageReferenceHeaderInfoCheckBox = new QCheckBox("Header"); QObject::connect(showStudyPageReferenceHeaderInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudyPageReferenceHeaderInfoCheckBox(bool))); // // show study page reference comment info check box // showStudyPageReferenceCommentInfoCheckBox = new QCheckBox("Comment"); QObject::connect(showStudyPageReferenceCommentInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudyPageReferenceCommentInfoCheckBox(bool))); // // show study page reference size units info check box // showStudyPageReferenceSizeUnitsInfoCheckBox = new QCheckBox("Size Units"); QObject::connect(showStudyPageReferenceSizeUnitsInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudyPageReferenceSizeUnitsInfoCheckBox(bool))); // // show study page reference voxel size info check box // showStudyPageReferenceVoxelSizeInfoCheckBox = new QCheckBox("Voxel Size"); QObject::connect(showStudyPageReferenceVoxelSizeInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudyPageReferenceVoxelSizeInfoCheckBox(bool))); // // show study page reference statistic info check box // showStudyPageReferenceStatisticInfoCheckBox = new QCheckBox("Statistic"); QObject::connect(showStudyPageReferenceStatisticInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudyPageReferenceStatisticInfoCheckBox(bool))); // // show study page reference statistic descriptioninfo check box // showStudyPageReferenceStatisticDescriptionInfoCheckBox = new QCheckBox("Statistic Description"); QObject::connect(showStudyPageReferenceStatisticDescriptionInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudyPageReferenceStatisticDescriptionInfoCheckBox(bool))); // // show study page reference info check box // showStudyPageReferenceInfoGroupBox = new QGroupBox("Page Reference"); showStudyPageReferenceInfoGroupBox->setCheckable(true); QObject::connect(showStudyPageReferenceInfoGroupBox, SIGNAL(toggled(bool)), this, SLOT(slotShowStudyPageReferenceInfoGroupBox(bool))); QVBoxLayout* studyPageReferenceLayout = new QVBoxLayout(showStudyPageReferenceInfoGroupBox); studyPageReferenceLayout->addWidget(showStudyPageReferenceHeaderInfoCheckBox); studyPageReferenceLayout->addWidget(showStudyPageReferenceCommentInfoCheckBox); studyPageReferenceLayout->addWidget(showStudyPageReferenceSizeUnitsInfoCheckBox); studyPageReferenceLayout->addWidget(showStudyPageReferenceVoxelSizeInfoCheckBox); studyPageReferenceLayout->addWidget(showStudyPageReferenceStatisticInfoCheckBox); studyPageReferenceLayout->addWidget(showStudyPageReferenceStatisticDescriptionInfoCheckBox); // // show study page number info check box // //showStudyPageNumberInfoCheckBox = new QCheckBox("Page Number"); //QObject::connect(showStudyPageNumberInfoCheckBox, SIGNAL(toggled(bool)), // this, SLOT(slotShowStudyPageNumberInfoCheckBox(bool))); // // Show study info group box // showStudyInfoGroupBox = new QGroupBox("Show Study Information for Identified Items"); showStudyInfoGroupBox->setCheckable(true); QObject::connect(showStudyInfoGroupBox, SIGNAL(toggled(bool)), this, SLOT(slotStudyAction(bool))); QVBoxLayout* studyInfoGroupLayout = new QVBoxLayout(showStudyInfoGroupBox); studyInfoGroupLayout->addWidget(showStudyTitleInfoCheckBox); studyInfoGroupLayout->addWidget(showStudyAuthorInfoCheckBox); studyInfoGroupLayout->addWidget(showStudyCitationInfoCheckBox); studyInfoGroupLayout->addWidget(showStudyCommentInfoCheckBox); studyInfoGroupLayout->addWidget(showStudyDataFormatInfoCheckBox); studyInfoGroupLayout->addWidget(showStudyDataTypeInfoCheckBox); studyInfoGroupLayout->addWidget(showStudyDOIInfoCheckBox); studyInfoGroupLayout->addWidget(showStudyKeywordsInfoCheckBox); studyInfoGroupLayout->addWidget(showStudyMedicalSubjectHeadingInfoCheckBox); studyInfoGroupLayout->addWidget(showStudyNameInfoCheckBox); studyInfoGroupLayout->addWidget(showStudyPartSchemeAbbrevInfoCheckBox); studyInfoGroupLayout->addWidget(showStudyPartSchemeFullInfoCheckBox); studyInfoGroupLayout->addWidget(showStudyPubMedIDInfoCheckBox); studyInfoGroupLayout->addWidget(showStudyProjectIDInfoCheckBox); studyInfoGroupLayout->addWidget(showStudyStereotaxicSpaceInfoCheckBox); studyInfoGroupLayout->addWidget(showStudyStereotaxicSpaceDetailsInfoCheckBox); studyInfoGroupLayout->addWidget(showStudyURLInfoCheckBox); studyInfoGroupLayout->addWidget(new QLabel(" ")); studyInfoGroupLayout->addWidget(showStudyTableInfoGroupBox); studyInfoGroupLayout->addWidget(new QLabel(" ")); studyInfoGroupLayout->addWidget(showStudyFigureInfoGroupBox); studyInfoGroupLayout->addWidget(new QLabel(" ")); studyInfoGroupLayout->addWidget(showStudySubHeaderInfoGroupBox); studyInfoGroupLayout->addWidget(new QLabel(" ")); studyInfoGroupLayout->addWidget(showStudyPageReferenceInfoGroupBox); //studyInfoGroupLayout->addWidget(new QLabel(" ")); //studyInfoGroupLayout->addWidget(showStudyPageNumberInfoCheckBox); // // Meta-Analysis // showStudyMetaAnalysisNameInfoCheckBox = new QCheckBox("Name"); QObject::connect(showStudyMetaAnalysisNameInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowMetaAnalysisNameInfoCheckBox(bool))); showStudyMetaAnalysisTitleInfoCheckBox = new QCheckBox("Title"); QObject::connect(showStudyMetaAnalysisTitleInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowMetaAnalysisTitleInfoCheckBox(bool))); showStudyMetaAnalysisAuthorInfoCheckBox = new QCheckBox("Authors"); QObject::connect(showStudyMetaAnalysisAuthorInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowMetaAnalysisAuthorsInfoCheckBox(bool))); showStudyMetaAnalysisCitationInfoCheckBox = new QCheckBox("Citation"); QObject::connect(showStudyMetaAnalysisCitationInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowMetaAnalysisCitationInfoCheckBox(bool))); showStudyMetaAnalysisDOIInfoCheckBox = new QCheckBox("DOI/URL"); QObject::connect(showStudyMetaAnalysisDOIInfoCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowMetaAnalysisDoiUrlInfoCheckBox(bool))); showStudyMetaAnalysisInfoGroupBox = new QGroupBox("Show Meta-Analysis for Identified Items"); showStudyMetaAnalysisInfoGroupBox->setCheckable(true); QObject::connect(showStudyMetaAnalysisInfoGroupBox, SIGNAL(toggled(bool)), this, SLOT(slotShowMetaAnalysisInfoGroupBox(bool))); QVBoxLayout* metaAnalysisGroupLayout = new QVBoxLayout(showStudyMetaAnalysisInfoGroupBox); metaAnalysisGroupLayout->addWidget(showStudyMetaAnalysisNameInfoCheckBox); metaAnalysisGroupLayout->addWidget(showStudyMetaAnalysisTitleInfoCheckBox); metaAnalysisGroupLayout->addWidget(showStudyMetaAnalysisAuthorInfoCheckBox); metaAnalysisGroupLayout->addWidget(showStudyMetaAnalysisCitationInfoCheckBox); metaAnalysisGroupLayout->addWidget(showStudyMetaAnalysisDOIInfoCheckBox); // // Display significant digits spin box // QLabel* sigDigitLabel = new QLabel("Digits Right of Decimal "); significantDigitsSpinBox = new QSpinBox; significantDigitsSpinBox->setMinimum(0); significantDigitsSpinBox->setMaximum(128); significantDigitsSpinBox->setSingleStep(1); QObject::connect(significantDigitsSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotSignificantDigitsSpinBox(int))); significantDigitsSpinBox->setToolTip( "Controls number of digits\n" "displayed right of decimal."); QHBoxLayout* sigDigitsLayout = new QHBoxLayout; sigDigitsLayout->addWidget(sigDigitLabel); sigDigitsLayout->addWidget(significantDigitsSpinBox); sigDigitsLayout->addStretch(); // // Widget for filter items // QWidget* w = new QWidget; QVBoxLayout* l = new QVBoxLayout(w); l->setSpacing(15); l->addLayout(allOnOffButtonLayout); l->addLayout(sigDigitsLayout); l->addWidget(showNodeInfoGroupBox); l->addWidget(showBorderInfoCheckBox); l->addWidget(showCellInfoCheckBox); l->addWidget(showContourInfoCheckBox); l->addWidget(showFociInfoGroupBox); l->addWidget(showVoxelInfoCheckBox); l->addWidget(showStudyInfoGroupBox); l->addWidget(showStudyMetaAnalysisInfoGroupBox); // // Scroll area for filter items // QScrollArea* sa = new QScrollArea; sa->setWidget(w); sa->setWidgetResizable(true); return sa; } /** * update the filtering selections. */ void GuiIdentifyMainWindow::updateFilteringSelections() { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); showNodeInfoGroupBox->setChecked(bmi->getDisplayNodeInformation()); showNodeArealEstInfoCheckBox->setChecked(bmi->getDisplayNodeArealEstInformation()); showNodeCoordInfoCheckBox->setChecked(bmi->getDisplayNodeCoordInformation()); showNodeLatLonInfoCheckBox->setChecked(bmi->getDisplayNodeLatLonInformation()); showNodeMetricInfoCheckBox->setChecked(bmi->getDisplayNodeMetricInformation()); showNodePaintInfoCheckBox->setChecked(bmi->getDisplayNodePaintInformation()); showNodeProbAtlasInfoCheckBox->setChecked(bmi->getDisplayNodeProbAtlasInformation()); showNodeRgbPaintInfoCheckBox->setChecked(bmi->getDisplayNodeRgbPaintInformation()); showNodeSectionInfoCheckBox->setChecked(bmi->getDisplayNodeSectionInformation()); showNodeShapeInfoCheckBox->setChecked(bmi->getDisplayNodeShapeInformation()); showNodeTopographyInfoCheckBox->setChecked(bmi->getDisplayNodeTopographyInformation()); showBorderInfoCheckBox->setChecked(bmi->getDisplayBorderInformation()); showCellInfoCheckBox->setChecked(bmi->getDisplayCellInformation()); showContourInfoCheckBox->setChecked(bmi->getDisplayContourInformation()); showFociInfoGroupBox->setChecked(bmi->getDisplayFociInformation()); showFociNameInfoCheckBox->setChecked(bmi->getDisplayFociNameInformation()); showFociClassInfoCheckBox->setChecked(bmi->getDisplayFociClassInformation()); showFociOriginalStereotaxicPositionInfoCheckBox->setChecked(bmi->getDisplayFociOriginalStereotaxicPositionInformation()); showFociStereotaxicPositionInfoCheckBox->setChecked(bmi->getDisplayFociStereotaxicPositionInformation()); showFociAreaInfoCheckBox->setChecked(bmi->getDisplayFociAreaInformation()); showFociGeographyInfoCheckBox->setChecked(bmi->getDisplayFociGeographyInformation()); showFociRegionOfInterestInfoCheckBox->setChecked(bmi->getDisplayFociRegionOfInterestInformation()); showFociSizeInfoCheckBox->setChecked(bmi->getDisplayFociSizeInformation()); showFociStatisticInfoCheckBox->setChecked(bmi->getDisplayFociStatisticInformation()); showFociStructureInfoCheckBox->setChecked(bmi->getDisplayFociStructureInformation()); showFociCommentInfoCheckBox->setChecked(bmi->getDisplayFociCommentInformation()); showVoxelInfoCheckBox->setChecked(bmi->getDisplayVoxelInformation()); showStudyMetaAnalysisInfoGroupBox->setChecked(bmi->getDisplayStudyMetaAnalysisInformation()); showStudyMetaAnalysisNameInfoCheckBox->setChecked(bmi->getDisplayStudyMetaAnalysisNameInformation()); showStudyMetaAnalysisTitleInfoCheckBox->setChecked(bmi->getDisplayStudyMetaAnalysisTitleInformation()); showStudyMetaAnalysisAuthorInfoCheckBox->setChecked(bmi->getDisplayStudyMetaAnalysisAuthorsInformation()); showStudyMetaAnalysisCitationInfoCheckBox->setChecked(bmi->getDisplayStudyMetaAnalysisCitationInformation()); showStudyMetaAnalysisDOIInfoCheckBox->setChecked(bmi->getDisplayStudyMetaAnalysisDoiUrlInformation()); showStudyInfoGroupBox->setChecked(bmi->getDisplayStudyInformation()); showStudyNameInfoCheckBox->setChecked(bmi->getDisplayStudyNameInformation()); showStudyTitleInfoCheckBox->setChecked(bmi->getDisplayStudyTitleInformation()); showStudyAuthorInfoCheckBox->setChecked(bmi->getDisplayStudyAuthorsInformation()); showStudyCitationInfoCheckBox->setChecked(bmi->getDisplayStudyCitationInformation()); showStudyCommentInfoCheckBox->setChecked(bmi->getDisplayStudyCommentInformation()); showStudyDataFormatInfoCheckBox->setChecked(bmi->getDisplayStudyDataFormatInformation()); showStudyDataTypeInfoCheckBox->setChecked(bmi->getDisplayStudyDataTypeInformation()); showStudyDOIInfoCheckBox->setChecked(bmi->getDisplayStudyDOIInformation()); showStudyKeywordsInfoCheckBox->setChecked(bmi->getDisplayStudyKeywordsInformation()); showStudyMedicalSubjectHeadingInfoCheckBox->setChecked(bmi->getDisplayStudyMedicalSubjectHeadingsInformation()); showStudyPartSchemeAbbrevInfoCheckBox->setChecked(bmi->getDisplayStudyPartSchemeAbbrevInformation()); showStudyPartSchemeFullInfoCheckBox->setChecked(bmi->getDisplayStudyPartSchemeFullInformation()); showStudyPubMedIDInfoCheckBox->setChecked(bmi->getDisplayStudyPubMedIDInformation()); showStudyProjectIDInfoCheckBox->setChecked(bmi->getDisplayStudyProjectIDInformation()); showStudyStereotaxicSpaceInfoCheckBox->setChecked(bmi->getDisplayStudyStereotaxicSpaceInformation()); showStudyStereotaxicSpaceDetailsInfoCheckBox->setChecked(bmi->getDisplayStudyStereotaxicSpaceDetailsInformation()); showStudyURLInfoCheckBox->setChecked(bmi->getDisplayStudyURLInformation()); showStudyTableInfoGroupBox->setChecked(bmi->getDisplayStudyTableInformation()); showStudyTableHeaderInfoCheckBox->setChecked(bmi->getDisplayStudyTableHeaderInformation()); showStudyTableFooterInfoCheckBox->setChecked(bmi->getDisplayStudyTableFooterInformation()); showStudyTableSizeUnitsInfoCheckBox->setChecked(bmi->getDisplayStudyTableSizeUnitsInformation()); showStudyTableVoxelSizeInfoCheckBox->setChecked(bmi->getDisplayStudyTableVoxelSizeInformation()); showStudyTableStatisticInfoCheckBox->setChecked(bmi->getDisplayStudyTableStatisticInformation()); showStudyTableStatisticDescriptionInfoCheckBox->setChecked(bmi->getDisplayStudyTableStatisticDescriptionInformation()); showStudyFigureInfoGroupBox->setChecked(bmi->getDisplayStudyFigureInformation()); showStudyFigureLegendInfoCheckBox->setChecked(bmi->getDisplayStudyFigureLegendInformation()); showStudyFigurePanelInfoGroupBox->setChecked(bmi->getDisplayStudyFigurePanelInformation()); showStudyFigurePanelDescriptionInfoCheckBox->setChecked(bmi->getDisplayStudyFigurePanelDescriptionInformation()); showStudyFigurePanelTaskDescriptionInfoCheckBox->setChecked(bmi->getDisplayStudyFigurePanelTaskDescriptionInformation()); showStudyFigurePanelTaskBaselineInfoCheckBox->setChecked(bmi->getDisplayStudyFigurePanelTaskBaselineInformation()); showStudyFigurePanelTestAttributesInfoCheckBox->setChecked(bmi->getDisplayStudyFigurePanelTestAttributesInformation()); showStudySubHeaderInfoGroupBox->setChecked(bmi->getDisplayStudySubHeaderInformation()); showStudySubHeaderNameInfoCheckBox->setChecked(bmi->getDisplayStudySubHeaderNameInformation()); showStudySubHeaderShortNameInfoCheckBox->setChecked(bmi->getDisplayStudySubHeaderShortNameInformation()); showStudySubHeaderTaskDescriptionInfoCheckBox->setChecked(bmi->getDisplayStudySubHeaderTaskDescriptionInformation()); showStudySubHeaderTaskBaselineInfoCheckBox->setChecked(bmi->getDisplayStudySubHeaderTaskBaselineInformation()); showStudySubHeaderTestAttributesInfoCheckBox->setChecked(bmi->getDisplayStudySubHeaderTestAttributesInformation()); showStudyPageReferenceInfoGroupBox->setChecked(bmi->getDisplayStudyPageReferenceInformation()); showStudyPageReferenceHeaderInfoCheckBox->setChecked(bmi->getDisplayStudyPageReferenceHeaderInformation()); showStudyPageReferenceCommentInfoCheckBox->setChecked(bmi->getDisplayStudyPageReferenceCommentInformation()); showStudyPageReferenceSizeUnitsInfoCheckBox->setChecked(bmi->getDisplayStudyPageReferenceSizeUnitsInformation()); showStudyPageReferenceVoxelSizeInfoCheckBox->setChecked(bmi->getDisplayStudyPageReferenceVoxelSizeInformation()); showStudyPageReferenceStatisticInfoCheckBox->setChecked(bmi->getDisplayStudyPageReferenceStatisticInformation()); showStudyPageReferenceStatisticDescriptionInfoCheckBox->setChecked(bmi->getDisplayStudyPageReferenceStatisticDescriptionInformation()); //showStudyPageNumberInfoCheckBox->setChecked(bmi->getDisplayStudyPageNumberInformation()); significantDigitsSpinBox->setValue(bmi->getSignificantDigits()); } /** * clear all node ID symbols */ void GuiIdentifyMainWindow::clearNodeID() { theMainWindow->getBrainSet()->clearNodeHighlightSymbols(); BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); bmbs->clearBorderHighlighting(); FociProjectionFile* fpf = theMainWindow->getBrainSet()->getFociProjectionFile(); fpf->clearAllHighlightFlags(); BrainModelContours* bmc = theMainWindow->getBrainSet()->getBrainModelContours(-1); if (bmc != NULL) { bmc->getContourFile()->clearHighlightFlags(); } GuiBrainModelOpenGL::updateAllGL(NULL); } /** * Destructor. */ GuiIdentifyMainWindow::~GuiIdentifyMainWindow() { } /** * append html. */ void GuiIdentifyMainWindow::appendHtml(const QString& html) { textDisplayBrowser->appendHtml(html); // // Scroll to newest text (at end of scroll bar) // QScrollBar* vsb = textDisplayBrowser->verticalScrollBar(); vsb->setValue(vsb->maximum()); } /** * Append to the text in the text editor. */ void GuiIdentifyMainWindow::appendText(const QString& qs) { textDisplayBrowser->append(qs); // // Scroll to newest text (at end of scroll bar) // QScrollBar* vsb = textDisplayBrowser->verticalScrollBar(); vsb->setValue(vsb->maximum()); } /** * all on button. */ void GuiIdentifyMainWindow::slotAllOn() { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setAllIdentificationOn(); updateToolBarButtons(); updateFilteringSelections(); } /** * all off button. */ void GuiIdentifyMainWindow::slotAllOff() { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setAllIdentificationOff(); updateToolBarButtons(); updateFilteringSelections(); } /** * display border information toolbar button. */ void GuiIdentifyMainWindow::slotBorderAction(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayBorderInformation(val); } /** * display cell information toolbar button. */ void GuiIdentifyMainWindow::slotCellAction(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayCellInformation(val); } /** * display foci information toolbar button. */ void GuiIdentifyMainWindow::slotFociAction(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayFociInformation(val); } /** * display foci name information toolbar button. */ void GuiIdentifyMainWindow::slotFociNameAction(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayFociNameInformation(val); } /** * display foci class information toolbar button. */ void GuiIdentifyMainWindow::slotFociClassAction(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayFociClassInformation(val); } /** * display foci original stereotaxic position information toolbar button. */ void GuiIdentifyMainWindow::slotFociOriginalStereotaxicPositionAction(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayFociOriginalStereotaxicPositionInformation(val); } /** * display foci stereotaxic position information toolbar button. */ void GuiIdentifyMainWindow::slotFociStereotaxicPositionAction(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayFociStereotaxicPositionInformation(val); } /** * display foci area information toolbar button. */ void GuiIdentifyMainWindow::slotFociAreaAction(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayFociAreaInformation(val); } /** * display foci geography information toolbar button. */ void GuiIdentifyMainWindow::slotFociGeographyAction(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayFociGeographyInformation(val); } /** * display foci region of interest information toolbar button. */ void GuiIdentifyMainWindow::slotFociRegionOfInterestAction(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayFociRegionOfInterestInformation(val); } /** * display foci size information toolbar button. */ void GuiIdentifyMainWindow::slotFociSizeAction(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayFociSizeInformation(val); } /** * display foci Statistic information toolbar button. */ void GuiIdentifyMainWindow::slotFociStatisticAction(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayFociStatisticInformation(val); } /** * display foci structure information toolbar button. */ void GuiIdentifyMainWindow::slotFociStructureAction(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayFociStructureInformation(val); } /** * display foci comment information toolbar button. */ void GuiIdentifyMainWindow::slotFociCommentAction(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayFociCommentInformation(val); } /** * display voxel information toolbar button. */ void GuiIdentifyMainWindow::slotVoxelAction(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayVoxelInformation(val); } /** * display contour information. */ void GuiIdentifyMainWindow::slotContourAction(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayContourInformation(val); } /** * display node information. */ void GuiIdentifyMainWindow::slotNodeAction(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayNodeInformation(val); } /** * display node coordinate information. */ void GuiIdentifyMainWindow::slotNodeCoordAction(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayNodeCoordInformation(val); } /** * display node lat/lon information. */ void GuiIdentifyMainWindow::slotNodeLatLonAction(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayNodeLatLonInformation(val); } /** * display node paint information. */ void GuiIdentifyMainWindow::slotNodePaintAction(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayNodePaintInformation(val); } /** * display node probabilistic atlas information. */ void GuiIdentifyMainWindow::slotNodeProbAtlasAction(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayNodeProbAtlasInformation(val); } /** * display node rgb paint information. */ void GuiIdentifyMainWindow::slotNodeRgbPaintAction(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayNodeRgbPaintInformation(val); } /** * display node metric information. */ void GuiIdentifyMainWindow::slotNodeMetricAction(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayNodeMetricInformation(val); } /** * display node shape information. */ void GuiIdentifyMainWindow::slotNodeShapeAction(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayNodeShapeInformation(val); } /** * display node section information. */ void GuiIdentifyMainWindow::slotNodeSectionAction(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayNodeSectionInformation(val); } /** * display node areal estimation information. */ void GuiIdentifyMainWindow::slotNodeArealEstAction(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayNodeArealEstInformation(val); } /** * display node topography information. */ void GuiIdentifyMainWindow::slotNodeTopographyAction(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayNodeTopographyInformation(val); } /** * show ID symbols on surface. */ void GuiIdentifyMainWindow::slotShowIDAction(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayIDSymbol(val); } /** * significant digits display. */ void GuiIdentifyMainWindow::slotSignificantDigitsSpinBox(int val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setSignificantDigits(val); } /** * display study information. */ void GuiIdentifyMainWindow::slotStudyAction(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyInformation(val); } /** * show study name info check box. */ void GuiIdentifyMainWindow::slotShowStudyNameInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyNameInformation(val); } /** * show study title info check box. */ void GuiIdentifyMainWindow::slotShowStudyTitleInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyTitleInformation(val); } /** * show study author info check box. */ void GuiIdentifyMainWindow::slotShowStudyAuthorInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyAuthorsInformation(val); } /** * show study citation info check box. */ void GuiIdentifyMainWindow::slotShowStudyCitationInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyCitationInformation(val); } /** * show study comment info check box. */ void GuiIdentifyMainWindow::slotShowStudyCommentInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyCommentInformation(val); } /** * show study data format info check box. */ void GuiIdentifyMainWindow::slotShowStudyDataFormatInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyDataFormatInformation(val); } /** * show study data type info check box. */ void GuiIdentifyMainWindow::slotShowStudyDataTypeInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyDataTypeInformation(val); } /** * show study DOI info check box. */ void GuiIdentifyMainWindow::slotShowStudyDOIInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyDOIInformation(val); } /** * show study keywords info check box. */ void GuiIdentifyMainWindow::slotShowStudyKeywordsInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyKeywordsInformation(val); } /** * show study medical subject headings info check box. */ void GuiIdentifyMainWindow::slotShowStudyMedicalSubjectHeadingInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyMedicalSubjectHeadingsInformation(val); } /** * show study meta-analysis info check box. */ void GuiIdentifyMainWindow::slotShowMetaAnalysisInfoGroupBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyMetaAnalysisInformation(val); } /** * show study meta-analysis name info check box. */ void GuiIdentifyMainWindow::slotShowMetaAnalysisNameInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyMetaAnalysisNameInformation(val); } /** * show study meta-analysis title info check box. */ void GuiIdentifyMainWindow::slotShowMetaAnalysisTitleInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyMetaAnalysisTitleInformation(val); } /** * show study meta-analysis authors info check box. */ void GuiIdentifyMainWindow::slotShowMetaAnalysisAuthorsInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyMetaAnalysisAuthorsInformation(val); } /** * show study meta-analysis citation info check box. */ void GuiIdentifyMainWindow::slotShowMetaAnalysisCitationInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyMetaAnalysisCitationInformation(val); } /** * show study meta-analysis DOI/URL info check box. */ void GuiIdentifyMainWindow::slotShowMetaAnalysisDoiUrlInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyMetaAnalysisDoiUrlInformation(val); } /** * show study part scheme abbrev info check box. */ void GuiIdentifyMainWindow::slotShowStudyPartSchemeAbbrevInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyPartSchemeAbbrevInformation(val); } /** * show study part scheme full info check box. */ void GuiIdentifyMainWindow::slotShowStudyPartSchemeFullInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyPartSchemeFullInformation(val); } /** * show study PubMed ID info check box. */ void GuiIdentifyMainWindow::slotShowStudyPubMedIDInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyPubMedIDInformation(val); } /** * show study project ID info check box. */ void GuiIdentifyMainWindow::slotShowStudyProjectIDInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyProjectIDInformation(val); } /** * show study stereotaxic space info check box. */ void GuiIdentifyMainWindow::slotShowStudyStereotaxicSpaceInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyStereotaxicSpaceInformation(val); } /** * show study stereotaxic space details info check box. */ void GuiIdentifyMainWindow::slotShowStudyStereotaxicSpaceDetailsInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyStereotaxicSpaceDetailsInformation(val); } /** * show study URL info check box. */ void GuiIdentifyMainWindow::slotShowStudyURLInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyURLInformation(val); } /** * show study table info group box. */ void GuiIdentifyMainWindow::slotShowStudyTableInfoGroupBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyTableInformation(val); } /** * show study table header info check box. */ void GuiIdentifyMainWindow::slotShowStudyTableHeaderInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyTableHeaderInformation(val); } /** * show study table footer info check box. */ void GuiIdentifyMainWindow::slotShowStudyTableFooterInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyTableFooterInformation(val); } /** * show study table size units info check box. */ void GuiIdentifyMainWindow::slotShowStudyTableSizeUnitsInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyTableSizeUnitsInformation(val); } /** * show study table voxel size info check box. */ void GuiIdentifyMainWindow::slotShowStudyTableVoxelSizeInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyTableVoxelSizeInformation(val); } /** * show study table statistic info check box. */ void GuiIdentifyMainWindow::slotShowStudyTableStatisticInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyTableStatisticInformation(val); } /** * show study table statistic description info check box. */ void GuiIdentifyMainWindow::slotShowStudyTableStatisticDescriptionInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyTableStatisticDescriptionInformation(val); } /** * show study figure info group box. */ void GuiIdentifyMainWindow::slotShowStudyFigureInfoGroupBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyFigureInformation(val); } /** * show study figure legend info check box. */ void GuiIdentifyMainWindow::slotShowStudyFigureLegendInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyFigureLegendInformation(val); } /** * show study figure panel info group box. */ void GuiIdentifyMainWindow::slotShowStudyFigurePanelInfoGroupBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyFigurePanelInformation(val); } /** * show study figure panel description info check box. */ void GuiIdentifyMainWindow::slotShowStudyFigurePanelDescriptionInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyFigurePanelDescriptionInformation(val); } /** * show study figure panel task description info check box. */ void GuiIdentifyMainWindow::slotShowStudyFigurePanelTaskDescriptionInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyFigurePanelTaskDescriptionInformation(val); } /** * show study figure panel task baseline info check box. */ void GuiIdentifyMainWindow::slotShowStudyFigurePanelTaskBaselineInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyFigurePanelTaskBaselineInformation(val); } /** * show study figure panel test attributes info check box. */ void GuiIdentifyMainWindow::slotShowStudyFigurePanelTestAttributesInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyFigurePanelTestAttributesInformation(val); } /** * show study subheader info group box. */ void GuiIdentifyMainWindow::slotShowStudySubHeaderInfoGroupBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudySubHeaderInformation(val); } /** * show study subheader name info check box. */ void GuiIdentifyMainWindow::slotShowStudySubHeaderNameInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudySubHeaderNameInformation(val); } /** * show study subheader short name info check box. */ void GuiIdentifyMainWindow::slotShowStudySubHeaderShortNameInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudySubHeaderShortNameInformation(val); } /** * show study subheader task description info check box. */ void GuiIdentifyMainWindow::slotShowStudySubHeaderTaskDescriptionInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudySubHeaderTaskDescriptionInformation(val); } /** * show study subheader task baseline info check box. */ void GuiIdentifyMainWindow::slotShowStudySubHeaderTaskBaselineInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudySubHeaderTaskBaselineInformation(val); } /** * show study subheader test attributes info check box. */ void GuiIdentifyMainWindow::slotShowStudySubHeaderTestAttributesInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudySubHeaderTestAttributesInformation(val); } /** * show study page reference info group box. */ void GuiIdentifyMainWindow::slotShowStudyPageReferenceInfoGroupBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyPageReferenceInformation(val); } /** * show study page reference header info check box. */ void GuiIdentifyMainWindow::slotShowStudyPageReferenceHeaderInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyPageReferenceHeaderInformation(val); } /** * show study page reference comment info check box. */ void GuiIdentifyMainWindow::slotShowStudyPageReferenceCommentInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyPageReferenceCommentInformation(val); } /** * show study page reference size units info check box. */ void GuiIdentifyMainWindow::slotShowStudyPageReferenceSizeUnitsInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyPageReferenceSizeUnitsInformation(val); } /** * show study page reference voxel size info check box. */ void GuiIdentifyMainWindow::slotShowStudyPageReferenceVoxelSizeInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyPageReferenceVoxelSizeInformation(val); } /** * show study page reference statistic info check box */ void GuiIdentifyMainWindow::slotShowStudyPageReferenceStatisticInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyPageReferenceStatisticInformation(val); } /** * show study page reference statistic description info check box. */ void GuiIdentifyMainWindow::slotShowStudyPageReferenceStatisticDescriptionInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyPageReferenceStatisticDescriptionInformation(val); } /** * show study page number info check box. */ /* void GuiIdentifyMainWindow::slotShowStudyPageNumberInfoCheckBox(bool val) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); bmi->setDisplayStudyPageNumberInformation(val); } */ /** * update the filtering toggle buttons. */ void GuiIdentifyMainWindow::updateToolBarButtons() { const BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); showIDAction->setChecked(bmi->getDisplayIDSymbol()); } //================================================================================= /** * The constructor. */ GuiIdentifyDialog::GuiIdentifyDialog(QWidget* parent) : WuQDialog(parent) { //resize(400, 200); setWindowTitle("Identify Window"); QVBoxLayout* dialogLayout = new QVBoxLayout(this); // // main window containing toolbar and text area // idMainWindow = new GuiIdentifyMainWindow; dialogLayout->addWidget(idMainWindow); // // Close Button // QHBoxLayout* buttonsLayout = new QHBoxLayout; dialogLayout->addLayout(buttonsLayout); QPushButton* close = new QPushButton("Close"); QObject::connect(close, SIGNAL(clicked()), this, SLOT(accept())); close->setFixedSize(close->sizeHint()); close->setAutoDefault(false); buttonsLayout->addWidget(close); resize(650, 200); updateDialog(); } /** * The destructor. */ GuiIdentifyDialog::~GuiIdentifyDialog() { } /** * append to the text display. */ void GuiIdentifyDialog::appendText(const QString& s) { idMainWindow->appendText(s); show(); } /** * append html to the text display. */ void GuiIdentifyDialog::appendHtml(const QString& s) { idMainWindow->appendHtml(s); show(); } /** * apply a scene (update dialog). */ void GuiIdentifyDialog::showScene(const SceneFile::Scene& scene, const int mainWindowX, const int mainWindowY, const int mainWindowSceneX, const int mainWindowSceneY, const int screenMaxX, const int screenMaxY, QString& /*errorMessage*/) { bool idDialogFound = false; const int numClasses = scene.getNumberOfSceneClasses(); for (int nc = 0; nc < numClasses; nc++) { const SceneFile::SceneClass* sc = scene.getSceneClass(nc); if (sc->getName() == "GuiIdentifyDialog") { idDialogFound = true; const int num = sc->getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc->getSceneInfo(i); const QString infoName = si->getName(); if (infoName == "Geometry") { std::vector tokens; StringUtilities::token(si->getValueAsString(), " ", tokens); if (tokens.size() >= 4) { int geometry[4] = { StringUtilities::toInt(tokens[0]), StringUtilities::toInt(tokens[1]), StringUtilities::toInt(tokens[2]), StringUtilities::toInt(tokens[3]) }; geometry[0] = std::min(geometry[0], screenMaxX); geometry[1] = std::min(geometry[1], screenMaxY); const DisplaySettingsScene* dss = theMainWindow->getBrainSet()->getDisplaySettingsScene(); switch(dss->getWindowPositionPreference()) { case DisplaySettingsScene::WINDOW_POSITIONS_USE_ALL: move(geometry[0], geometry[1]); resize(geometry[2], geometry[3]); break; case DisplaySettingsScene::WINDOW_POSITIONS_IGNORE_MAIN_OTHERS_RELATIVE: geometry[0] = (geometry[0] - mainWindowSceneX) + mainWindowX; geometry[1] = (geometry[1] - mainWindowSceneY) + mainWindowY; move(geometry[0], geometry[1]); resize(geometry[2], geometry[3]); break; case DisplaySettingsScene::WINDOW_POSITIONS_IGNORE_ALL: break; } } } } show(); } } if (idDialogFound) { // // Get the highlighted nodes but only nodes highlighted by the user // std::vector highlightedNodes; std::vector highlightedType; const int numNodes = theMainWindow->getBrainSet()->getNumberOfNodes(); for (int i = 0; i < numNodes; i++) { BrainSetNodeAttribute* bna = theMainWindow->getBrainSet()->getNodeAttributes(i); if (bna->getHighlighting() == BrainSetNodeAttribute::HIGHLIGHT_NODE_LOCAL) { highlightedNodes.push_back(i); highlightedType.push_back(bna->getHighlighting()); } } // // Need to clear and then set node highlighting. This is because the nodes // have already been highlighted in the BrainSet. Trying to highlight a // node while it is already highlighted will clear its highlight just like // clicking a highlighted node removes it highlighting. // //JWH 01/16/2007 theMainWindow->getBrainSet()->clearNodeHighlightSymbols(); BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); QString idString; int numHighlightedNodes = static_cast(highlightedNodes.size()); for (int i = 0; i < numHighlightedNodes; i++) { idString += bmi->getIdentificationTextForNode(theMainWindow->getBrainSet(), highlightedNodes[i], true, true); } appendHtml(idString); } else { close(); } } /** * create a scene (save dialog settings). */ void GuiIdentifyDialog::saveScene(std::vector& scs) { if (isVisible()) { SceneFile::SceneClass sc("GuiIdentifyDialog"); std::ostringstream str; str << x() << " " << y() << " " << width() << " " << height(); sc.addSceneInfo(SceneFile::SceneInfo("Geometry", str.str().c_str())); scs.push_back(sc); } } /** * display vocabulary name in identify window. */ void GuiIdentifyDialog::displayVocabularyNameData(const QString& name) { BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); const QString txt = bmi->getIdentificationTextForVocabulary(true, name); if (txt.isEmpty() == false) { idMainWindow->appendHtml(txt); show(); activateWindow(); } /* const VocabularyFile* vf = theMainWindow->getBrainSet()->getVocabularyFile(); const VocabularyFile::VocabularyEntry* ve = vf->getBestMatchingVocabularyEntry(name); if (ve != NULL) { idMainWindow->appendText(ve->getFullDescriptionForDisplayToUser(true)); show(); activateWindow(); } */ } /** * update the dialog. */ void GuiIdentifyDialog::updateDialog() { idMainWindow->updateToolBarButtons(); idMainWindow->updateFilteringSelections(); } caret-5.6.4~dfsg.1.orig/caret/GuiHyperLinkTextBrowser.h0000664000175000017500000000373711572067322022625 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include class QKeyEvent; #ifndef __GUI_HYPER_LINK_TEXT_BROWSER_H__ #define __GUI_HYPER_LINK_TEXT_BROWSER_H__ /// Derivative of QTextBrowser with setSource overridden to display clicked hyperlinks in browser class GuiHyperLinkTextBrowser : public QTextBrowser { Q_OBJECT public: /// Constructor GuiHyperLinkTextBrowser(QWidget* parent); /// Destructor ~GuiHyperLinkTextBrowser(); /// set the text void setText(const QString& text); signals: /// called if a key is pressed void keyPressed(); public slots: /// append text and convert any URLs to hyperlinks void append(const QString& text); /// append html void appendHtml(const QString& html); private slots: /// override to get document to be loaded void setSource(const QUrl& url); private: /// called if a key is pressed over the text browser void keyPressEvent(QKeyEvent* e); /// the text for display //QString displayText; }; #endif // __GUI_HYPER_LINK_TEXT_BROWSER_H__ caret-5.6.4~dfsg.1.orig/caret/GuiHyperLinkTextBrowser.cxx0000664000175000017500000000743211572067322023174 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainModelIdentification.h" #include "BrainSet.h" #include "GuiHyperLinkTextBrowser.h" #include "GuiMainWindow.h" #include "StringUtilities.h" #include "VocabularyFile.h" #include "global_variables.h" /** * Constructor */ GuiHyperLinkTextBrowser::GuiHyperLinkTextBrowser(QWidget* parent) : QTextBrowser(parent) { //QT4setTextFormat(QTextBrowser::RichText); } /** * Destructor */ GuiHyperLinkTextBrowser::~GuiHyperLinkTextBrowser() { } /** * Override of QT's QTextBrowser method. * Called when the user clicks a link in this browser. */ void GuiHyperLinkTextBrowser::setSource(const QUrl& url) { const QString s(url.toString()); if (s.startsWith("vocabulary://")) { const QString name = s.mid(13); BrainModelIdentification* bmi = theMainWindow->getBrainSet()->getBrainModelIdentification(); const QString idString(bmi->getIdentificationTextForVocabulary(true, name)); if (idString.isEmpty() == false) { appendHtml(idString); } } else { theMainWindow->displayWebPage(s); } } /** * Override of QT's QTextBrowser method. Find URLs and adds HTML tags to them. */ void GuiHyperLinkTextBrowser::append(const QString& textIn) { // // See if string contains a URL // QString text; if (textIn.indexOf("http://") >= 0) { // // Insert the string with hyperlinks into text browser // text = StringUtilities::convertURLsToHyperlinks(textIn); } else { text = textIn; } text.replace("\n", "
    "); //QTextBrowser::append(text); QString 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. */ void GuiHyperLinkTextBrowser::appendHtml(const QString& html) { QString 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()); } /** * */ void GuiHyperLinkTextBrowser::setText(const QString& textIn) { // // See if string contains a URL // QString displayText; if (textIn.indexOf("http://") != -1) { // // Insert the string with hyperlinks into text browser // displayText = StringUtilities::convertURLsToHyperlinks(textIn); } 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. */ void GuiHyperLinkTextBrowser::keyPressEvent(QKeyEvent* /*e*/) { emit keyPressed(); } caret-5.6.4~dfsg.1.orig/caret/GuiHtmlColorChooserDialog.h0000664000175000017500000000340211572067322023042 0ustar michaelmichael #ifndef __GUI_HTML_COLOR_CHOOSER_DIALOG_H__ #define __GUI_HTML_COLOR_CHOOSER_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "WuQDialog.h" class QListWidget; /// class for a dialog that selects HTML standard colors class GuiHtmlColorChooserDialog : public WuQDialog { public: // constructor GuiHtmlColorChooserDialog(QWidget* parent = 0); // destructor ~GuiHtmlColorChooserDialog(); // get the selected color name and color components void getSelectedColor(QString& name, unsigned char& red, unsigned char& green, unsigned char& blue) const; protected: // list widget for selection QListWidget* colorListWidget; // names of colors std::vector colorNames; }; #endif // __GUI_HTML_COLOR_CHOOSER_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiHtmlColorChooserDialog.cxx0000664000175000017500000000562211572067322023423 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "GuiHtmlColorChooserDialog.h" #include "HtmlColors.h" /** * constructor. */ GuiHtmlColorChooserDialog::GuiHtmlColorChooserDialog(QWidget* parent) : WuQDialog(parent) { // // Get number of HTML colors // const int numColors = HtmlColors::getNumberOfColors(); // // Create the color selection list widget // colorListWidget = new QListWidget; for (int i = 0; i < numColors; i++) { QString name; unsigned char red, green, blue; HtmlColors::getColorInformation(i, name, red, green, blue); QPixmap pix(24, 12); pix.fill(QColor(red, green, blue)); QIcon icon(pix); QListWidgetItem* item = new QListWidgetItem(icon, name); colorListWidget->addItem(item); } // // Layout the dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->addWidget(colorListWidget); // // Dialog buttons // QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); dialogLayout->addWidget(buttonBox); QObject::connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); QObject::connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); } /** * destructor. */ GuiHtmlColorChooserDialog::~GuiHtmlColorChooserDialog() { } /** * get the selected color name and color components. */ void GuiHtmlColorChooserDialog::getSelectedColor(QString& name, unsigned char& red, unsigned char& green, unsigned char& blue) const { const int colorIndex = colorListWidget->currentRow(); HtmlColors::getColorInformation(colorIndex, name, red, green, blue); } caret-5.6.4~dfsg.1.orig/caret/GuiHistogramDisplayDialog.h0000664000175000017500000001045311572067322023103 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_HISTOGRAM_DISPLAY_DIALOG_H__ #define __GUI_HISTOGRAM_DISPLAY_DIALOG_H__ #include #include "WuQDialog.h" class GuiGraphWidget; class StatisticHistogram; class QComboBox; class QGroupBox; class QLabel; class QPushButton; class QSpinBox; class QSlider; /// Dialog for displaying a histogram class GuiHistogramDisplayDialog : public WuQDialog { Q_OBJECT public: /// Constructor (dialog deleted when closed if non-modal) GuiHistogramDisplayDialog(QWidget* parent, const QString& titleCaption, const std::vector& values, const bool showGrayWhitePeaks, Qt::WindowFlags f = 0); /// Destructor ~GuiHistogramDisplayDialog(); /// get the peaks if "CHOOSE_PEAKS" mode void getPeaks(float& minPeak, float& maxPeak); private slots: /// called when apply hit (only if non-modal) void slotApply(); /// called when display mode changed void slotDisplayModeComboBox(int value); ///Called when non-modal dialog is closed. void slotCloseButton(); /// called when show/hide stats push button is pressed void slotShowHideStatsPushButton(); /// called when smooth histogram button pressed void slotSmoothPushButton(); protected: enum HISTO_SELECTION { HISTO_SELECTION_ALL, HISTO_SELECTION_MIDDLE_96 }; /// called when dialog OK/Cancel used if modal void done(int r); /// load the data into graph widget void loadDataIntoGraph(const HISTO_SELECTION selectedHistogram); /// load gray/white peak information void loadGrayWhitePeakInfo(const HISTO_SELECTION selectedHistogram); /// current histogram selection HISTO_SELECTION histogramSelection; /// the histogram widget GuiGraphWidget* histogramWidget; /// combo box for selecting all or middle 96% QComboBox* displayModeComboBox; /// group box for stats QGroupBox* statsGroupBox; /// show/hide stats push button QPushButton* showHideStatsPushButton; /// label QLabel* meanLabel; /// label QLabel* mean96Label; /// label QLabel* stdDevLabel; /// label QLabel* stdDev96Label; /// label QLabel* minLabel; /// label QLabel* min96Label; /// label QLabel* maxLabel; /// label QLabel* max96Label; /// label QLabel* rangeLabel; /// label QLabel* range96Label; /// label QLabel* csfPeakLabel; /// label QLabel* grayMinLabel; /// label QLabel* grayPeakLabel; /// label QLabel* grayWhiteLabel; /// label QLabel* whitePeakLabel; /// label QLabel* whiteMaxLabel; /// widget containing the histogram //QWidget* histogramLayoutWidget; /// the normal histogram StatisticHistogram* histogram; /// the 2% to 98% histogram StatisticHistogram* histogram96; /// index of histogram in graph int histogramGraphIndex; /// index of histogram 96% in graph int histogram96GraphIndex; }; #endif // __GUI_HISTOGRAM_DISPLAY_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiHistogramDisplayDialog.cxx0000664000175000017500000004756311572067322023472 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include "DebugControl.h" #include "GuiGraphWidget.h" #include "GuiHistogramDisplayDialog.h" #include "StatisticHistogram.h" #include "WuQSaveWidgetAsImagePushButton.h" #include "QtUtilities.h" #include "StatisticDataGroup.h" /** * Constructor (dialog deleted when closed if non-modal). */ GuiHistogramDisplayDialog::GuiHistogramDisplayDialog(QWidget* parent, const QString& titleCaption, const std::vector& values, const bool showGrayWhitePeaks, Qt::WindowFlags f) : WuQDialog(parent, f) { /* setModal(true); if (modalFlag == false) { setModal(false); // // Delete this dialog when user presses close button // setAttribute(Qt::WA_DeleteOnClose); } */ histogramGraphIndex = -1; histogram96GraphIndex = -1; histogramSelection = HISTO_SELECTION_ALL; enum { PROGRESS_STEPS_0 = 1, PROGRESS_STEPS_1 = 2, PROGRESS_STEPS_TOTAL = 3 }; QProgressDialog standbyDialog("Determining Histogram, please wait.", "", 0, PROGRESS_STEPS_TOTAL, parent); standbyDialog.setCancelButton(0); standbyDialog.show(); qApp->processEvents(); // note: qApp is global in QApplication // // Determine the normal histogram // histogram = new StatisticHistogram(256); StatisticDataGroup sdg(&values, StatisticDataGroup::DATA_STORAGE_MODE_POINT); histogram->addDataGroup(&sdg); try { histogram->execute(); } catch (StatisticException&) { } standbyDialog.setValue(PROGRESS_STEPS_0); qApp->processEvents(); // note: qApp is global in QApplication if (DebugControl::getDebugOn()) { for (int i = 0; i < 256; i++) { float val, cnt; histogram->getDataForBucket(i, val, cnt); std::cout << "New Hist: " << i << " " << val << " " << cnt << std::endl; } } // // Determine the 2% to 98% histogram // histogram96 = new StatisticHistogram(256, 2.0, 2.0); histogram96->addDataGroup(&sdg); // reuse data from normal histogram try { histogram96->execute(); } catch (StatisticException&) { } standbyDialog.setValue(PROGRESS_STEPS_1); qApp->processEvents(); // note: qApp is global in QApplication QString caption("Histogram"); if (titleCaption.isEmpty() == false) { caption.append(" - "); caption.append(titleCaption); } setWindowTitle(caption); // // Layout for histogram // QVBoxLayout* histogramLayoutWidgetLayout = new QVBoxLayout; histogramLayoutWidgetLayout->setSpacing(2); // // Widget showing histogram // histogramWidget = new GuiGraphWidget(0, "Histogram"); histogramWidget->setFixedHeight(histogramWidget->sizeHint().height()); // // Group box for display mode // QGroupBox* displayModeGroupBox = new QGroupBox("Display Mode"); QVBoxLayout* displayModeLayout = new QVBoxLayout(displayModeGroupBox); displayModeComboBox = new QComboBox; displayModeLayout->addWidget(displayModeComboBox); displayModeComboBox->insertItem(HISTO_SELECTION_ALL, "All"); displayModeComboBox->insertItem(HISTO_SELECTION_MIDDLE_96, "Middle 96%"); QObject::connect(displayModeComboBox, SIGNAL(activated(int)), this, SLOT(slotDisplayModeComboBox(int))); displayModeGroupBox->setFixedSize(displayModeGroupBox->sizeHint()); /* // // Show hide stats push button // showHideStatsPushButton = new QPushButton("Hide Statisitics"); modeStatsHBoxLayout->addWidget(showHideStatsPushButton); showHideStatsPushButton->setAutoDefault(false); showHideStatsPushButton->setFixedSize(showHideStatsPushButton->sizeHint()); QObject::connect(showHideStatsPushButton, SIGNAL(clicked()), this, SLOT(slotShowHideStatsPushButton())); */ // // Display statistics for data // const QString blanks(" "); meanLabel = new QLabel(blanks); mean96Label = new QLabel(blanks); stdDevLabel = new QLabel(blanks); stdDev96Label = new QLabel(blanks); minLabel = new QLabel(blanks); min96Label = new QLabel(blanks); maxLabel = new QLabel(blanks); max96Label = new QLabel(blanks); rangeLabel = new QLabel(blanks); range96Label = new QLabel(blanks); statsGroupBox = new QGroupBox("Statistics"); QGridLayout* statsGroupLayout = new QGridLayout(statsGroupBox); statsGroupLayout->addWidget(new QLabel(" "), 0, 0); statsGroupLayout->addWidget(new QLabel("All "), 0, 1); statsGroupLayout->addWidget(new QLabel(" "), 0, 2); statsGroupLayout->addWidget(new QLabel("Middle 96%"), 0, 3); statsGroupLayout->addWidget(new QLabel("Average "), 1, 0); statsGroupLayout->addWidget(meanLabel, 1, 1);; statsGroupLayout->addWidget(new QLabel(" "), 1, 2); statsGroupLayout->addWidget(mean96Label, 1, 3); statsGroupLayout->addWidget(new QLabel("Sample Deviation "), 2, 0); statsGroupLayout->addWidget(stdDevLabel, 2, 1); statsGroupLayout->addWidget(new QLabel(" "), 2, 2); statsGroupLayout->addWidget(stdDev96Label, 2, 3); statsGroupLayout->addWidget(new QLabel("Minimum "), 4, 0); statsGroupLayout->addWidget(minLabel, 4, 1); statsGroupLayout->addWidget(new QLabel(" "), 4, 2); statsGroupLayout->addWidget(min96Label, 4, 3); statsGroupLayout->addWidget(new QLabel("Maximum "), 5, 0); statsGroupLayout->addWidget(maxLabel, 5, 1); statsGroupLayout->addWidget(new QLabel(" "), 5, 2); statsGroupLayout->addWidget(max96Label, 5, 3); statsGroupLayout->addWidget(new QLabel("Range "), 6, 0); statsGroupLayout->addWidget(rangeLabel, 6, 1); statsGroupLayout->addWidget(new QLabel(" "), 6, 2); statsGroupLayout->addWidget(range96Label, 6, 3); statsGroupBox->setFixedSize(statsGroupBox->sizeHint()); // // Min/Max/Peak Gray/White Values // QGroupBox* whiteGrayGroupBox = NULL; csfPeakLabel = NULL; grayMinLabel = NULL; grayPeakLabel = NULL; grayWhiteLabel = NULL; whitePeakLabel = NULL; whiteMaxLabel = NULL; if (showGrayWhitePeaks) { QLabel* csfPeakTextLabel = new QLabel("CSF Peak"); csfPeakLabel = new QLabel(blanks); QLabel* grayMinTextLabel = new QLabel("Gray Min"); grayMinLabel = new QLabel(blanks); QLabel* grayPeakTextLabel = new QLabel("Gray Peak"); grayPeakLabel = new QLabel(blanks); QLabel* grayWhiteTextLabel = new QLabel("Gray/White"); grayWhiteLabel = new QLabel(blanks); QLabel* whitePeakTextLabel = new QLabel("White Peak"); whitePeakLabel = new QLabel(blanks); QLabel* whiteMaxTextLabel = new QLabel("White Max"); whiteMaxLabel = new QLabel(blanks); whiteGrayGroupBox = new QGroupBox("Gray/White Values"); QGridLayout* whiteGrayGridLayout = new QGridLayout(whiteGrayGroupBox); whiteGrayGridLayout->addWidget(csfPeakTextLabel, 0, 0); whiteGrayGridLayout->addWidget(csfPeakLabel, 0, 1); whiteGrayGridLayout->addWidget(grayMinTextLabel, 1, 0); whiteGrayGridLayout->addWidget(grayMinLabel, 1, 1); whiteGrayGridLayout->addWidget(grayPeakTextLabel, 2, 0); whiteGrayGridLayout->addWidget(grayPeakLabel, 2, 1); whiteGrayGridLayout->addWidget(grayWhiteTextLabel, 3, 0); whiteGrayGridLayout->addWidget(grayWhiteLabel, 3, 1); whiteGrayGridLayout->addWidget(whitePeakTextLabel, 4, 0); whiteGrayGridLayout->addWidget(whitePeakLabel, 4, 1); whiteGrayGridLayout->addWidget(whiteMaxTextLabel, 5, 0); whiteGrayGridLayout->addWidget(whiteMaxLabel, 5, 1); } // // Load the histograms into the graph // loadDataIntoGraph(HISTO_SELECTION_ALL); loadDataIntoGraph(HISTO_SELECTION_MIDDLE_96); // // Histogram smoothing // QPushButton* smoothPushButton = NULL; if (DebugControl::getTestFlag1()) { smoothPushButton = new QPushButton("Smooth Histogram..."); smoothPushButton->setFixedSize(smoothPushButton->sizeHint()); smoothPushButton->setAutoDefault(false); QObject::connect(smoothPushButton, SIGNAL(clicked()), this, SLOT(slotSmoothPushButton())); } // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); // // Save as Image button // WuQSaveWidgetAsImagePushButton* saveAsImageButton = new WuQSaveWidgetAsImagePushButton("Save As Image...", this); saveAsImageButton->setFixedSize(saveAsImageButton->sizeHint()); if (isModal()) { // // OK button // QPushButton* okButton = new QPushButton("OK"); QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); // // Cancel button // QPushButton* cancelButton = new QPushButton("Cancel"); cancelButton->setAutoDefault(false); QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); buttonsLayout->addWidget(okButton); buttonsLayout->addWidget(saveAsImageButton); buttonsLayout->addWidget(cancelButton); QtUtilities::makeButtonsSameSize(okButton, saveAsImageButton, cancelButton); } else { // // Close button // QPushButton* closeButton = new QPushButton("Close"); closeButton->setAutoDefault(false); closeButton->setFixedSize(closeButton->sizeHint()); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(slotCloseButton())); buttonsLayout->addWidget(saveAsImageButton); buttonsLayout->addWidget(closeButton); } // // Stats and white Gray // QHBoxLayout* statsGrayWhiteLayout = new QHBoxLayout; statsGrayWhiteLayout->addWidget(statsGroupBox); if (whiteGrayGroupBox != NULL) { statsGrayWhiteLayout->addWidget(whiteGrayGroupBox); } statsGrayWhiteLayout->addStretch(); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); dialogLayout->addWidget(histogramWidget); dialogLayout->addWidget(displayModeGroupBox); if (smoothPushButton != NULL) { dialogLayout->addWidget(smoothPushButton); } dialogLayout->addLayout(statsGrayWhiteLayout); dialogLayout->addLayout(buttonsLayout); slotDisplayModeComboBox(displayModeComboBox->currentIndex()); standbyDialog.close(); } /** * Destructor. */ GuiHistogramDisplayDialog::~GuiHistogramDisplayDialog() { if (histogram != NULL) { delete histogram; histogram = NULL; } if (histogram96 != NULL) { delete histogram96; histogram96 = NULL; } } /** * load gray/white peak information. */ void GuiHistogramDisplayDialog::loadGrayWhitePeakInfo(const HISTO_SELECTION selectedHistogram) { if (grayMinLabel != NULL) { int grayPeakBucketNumber; int whitePeakBucketNumber; int grayMinimumBucketNumber; int whiteMaximumBucketNumber; int grayWhiteBoundaryBucketNumber; int csfPeakBucketNumber; switch (selectedHistogram) { case HISTO_SELECTION_ALL: histogram->getGrayWhitePeakEstimates(grayPeakBucketNumber, whitePeakBucketNumber, grayMinimumBucketNumber, whiteMaximumBucketNumber, grayWhiteBoundaryBucketNumber, csfPeakBucketNumber); break; case HISTO_SELECTION_MIDDLE_96: histogram96->getGrayWhitePeakEstimates(grayPeakBucketNumber, whitePeakBucketNumber, grayMinimumBucketNumber, whiteMaximumBucketNumber, grayWhiteBoundaryBucketNumber, csfPeakBucketNumber); break; } csfPeakLabel->setText(QString::number(histogram->getDataValueForBucket(csfPeakBucketNumber), 'f', 1)); grayMinLabel->setText(QString::number(histogram->getDataValueForBucket(grayMinimumBucketNumber), 'f', 1)); grayPeakLabel->setText(QString::number(histogram->getDataValueForBucket(grayPeakBucketNumber), 'f', 1)); grayWhiteLabel->setText(QString::number(histogram->getDataValueForBucket(grayWhiteBoundaryBucketNumber), 'f', 1)); whitePeakLabel->setText(QString::number(histogram->getDataValueForBucket(whitePeakBucketNumber), 'f', 1)); whiteMaxLabel->setText(QString::number(histogram->getDataValueForBucket(whiteMaximumBucketNumber), 'f', 1)); } } /** * load the data into graph widget. */ void GuiHistogramDisplayDialog::loadDataIntoGraph(const HISTO_SELECTION selectedHistogram) { switch (selectedHistogram) { case HISTO_SELECTION_ALL: { // // Remove if already in graph // if (histogramGraphIndex >= 0) { histogramWidget->removeData(histogramGraphIndex); } // // Get stats about the histograms // float minValue, maxValue, range, mean, deviation; histogram->getDataStatistics(minValue, maxValue, range, mean, deviation); meanLabel->setText(QString::number(mean, 'f', 6)); stdDevLabel->setText(QString::number(deviation, 'f', 6)); minLabel->setText(QString::number(minValue, 'f', 6)); maxLabel->setText(QString::number(maxValue, 'f', 6)); rangeLabel->setText(QString::number(range, 'f', 6)); // // Add the first histogram data to the graph // std::vector dataX, dataY; for (int i = 0; i < histogram->getNumberOfBuckets(); i++) { float x, y; histogram->getDataForBucket(i, x, y); dataX.push_back(x); dataY.push_back(y); // // Need to get max value since bucket X-Value is at left side of bucket // so maximum value is at right side of last bucket // if ((histogram->getNumberOfBuckets() - 1) == i) { dataX.push_back(maxValue); dataY.push_back(0.0); } } histogramGraphIndex = histogramWidget->addData(dataX, dataY, QColor(255, 0, 0), GuiGraphWidget::DRAW_DATA_TYPE_BARS); } break; case HISTO_SELECTION_MIDDLE_96: { // // Remove if already in graph // if (histogram96GraphIndex >= 0) { histogramWidget->removeData(histogram96GraphIndex); } // // Get stats about the histograms // float minValue96, maxValue96, range96, mean96, deviation96; histogram96->getDataStatistics(minValue96, maxValue96, range96, mean96, deviation96); mean96Label->setText(QString::number(mean96, 'f', 6)); stdDev96Label->setText(QString::number(deviation96, 'f', 6)); min96Label->setText(QString::number(minValue96, 'f', 6)); max96Label->setText(QString::number(maxValue96, 'f', 6)); range96Label->setText(QString::number(range96, 'f', 6)); // // Add the 96% histogram data to the graph // std::vector dataX96, dataY96; for (int i = 0; i < histogram96->getNumberOfBuckets(); i++) { float x, y; histogram96->getDataForBucket(i, x, y); dataX96.push_back(x); dataY96.push_back(y); } histogram96GraphIndex = histogramWidget->addData(dataX96, dataY96, QColor(255, 0, 0), GuiGraphWidget::DRAW_DATA_TYPE_BARS); } break; } } /** * called when smooth histogram button pressed. */ void GuiHistogramDisplayDialog::slotSmoothPushButton() { const float strength = 0.5; const int iterations = 5; const int neighborDepth = 5; showWaitCursor(); const HISTO_SELECTION histSel = static_cast(displayModeComboBox->currentIndex()); switch (histSel) { case HISTO_SELECTION_ALL: histogram->smoothHistogram(strength, iterations, neighborDepth); { int csf, gray, white, grayMin, whiteMax, grayWhite; histogram->getGrayWhitePeakEstimates(gray, white, grayMin, whiteMax, grayWhite, csf); //std::cout << "Gray peak: " << gray // << " white peak: " << white << std::endl; } break; case HISTO_SELECTION_MIDDLE_96: histogram96->smoothHistogram(strength, iterations, neighborDepth); break; } loadDataIntoGraph(histSel); slotDisplayModeComboBox(histSel); showNormalCursor(); } /** * called when show/hide stats push button is pressed. */ void GuiHistogramDisplayDialog::slotShowHideStatsPushButton() { statsGroupBox->setHidden(! statsGroupBox->isHidden()); if (statsGroupBox->isHidden()) { showHideStatsPushButton->setText("Show Statistics"); } else { showHideStatsPushButton->setText("Hide Statistics"); } setMinimumSize(sizeHint()); setMaximumSize(sizeHint()); adjustSize(); } /** * Called when non-modal dialog is closed. */ void GuiHistogramDisplayDialog::slotCloseButton() { close(); } /** * Called when display mode changed */ void GuiHistogramDisplayDialog::slotDisplayModeComboBox(int value) { histogramSelection = static_cast(value); switch (histogramSelection) { case HISTO_SELECTION_ALL: histogramWidget->setDataDisplayed(histogramGraphIndex, true); histogramWidget->setDataDisplayed(histogram96GraphIndex, false); break; case HISTO_SELECTION_MIDDLE_96: histogramWidget->setDataDisplayed(histogramGraphIndex, false); histogramWidget->setDataDisplayed(histogram96GraphIndex, true); break; } loadGrayWhitePeakInfo(histogramSelection); } /** * get the peaks if "CHOOSE_PEAKS" mode. */ void GuiHistogramDisplayDialog::getPeaks(float& minPeak, float& maxPeak) { minPeak = 0; maxPeak = 0; } /** * Slot for OK or Cancel button in modal mode. */ void GuiHistogramDisplayDialog::done(int r) { if (r == QDialog::Accepted) { } QDialog::done(r); } /** * Slot for apply button in non-modal mode. */ void GuiHistogramDisplayDialog::slotApply() { } caret-5.6.4~dfsg.1.orig/caret/GuiHelpViewerWindow.h0000664000175000017500000000643411572067322021746 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_HELP_VIEWER_DIALOG_H__ #define __GUI_HELP_VIEWER_DIALOG_H__ #include #include #include "WuQDialog.h" class GuiTextBrowser; class QLineEdit; class QSplitter; class QToolButton; class QTreeWidget; class QTreeWidgetItem; class GuiHelpViewerMainWindow; /// dialog for showing help in a browser window class GuiHelpViewerWindow : public WuQDialog { Q_OBJECT public: // Constructor (non-modal full navigation controls) GuiHelpViewerWindow(QWidget* parent); // Contructor (modal with a modal parent, use exec()) GuiHelpViewerWindow(QDialog* parent, const QString& helpPageIn); // Destructor ~GuiHelpViewerWindow(); // load a page into the help browser void loadPage(const QString& page = ""); protected slots: // called when an index tree item is clicked void indexTreeItemSelected(QTreeWidgetItem* item, int column); // called when a search tree item is clicked void searchTreeItemSelected(QTreeWidgetItem* item, int column); // called to print currently displayed page void slotPrint(); // called to find in browser window void slotFindInBrowser(); // called to find next in browser window void slotFindNextInBrowser(); // called to search all help pages void slotSearchLineEdit(); protected: // create the help widget QWidget* createHelpBrowser(const bool showNavigationControlsFlag); // load the index tree void loadIndexTree(); // create a tree widget item QTreeWidgetItem* createTreeItem(const QString& label, const QString& helpPage = ""); // get all web page names and titles void getAllWebPages(QVector >& pagesOut) const; /// the help browser GuiTextBrowser* helpBrowser; /// the splitter QSplitter* splitter; /// the index tree widget QTreeWidget* indexTreeWidget; /// the search tree widget QTreeWidget* searchTreeWidget; /// text when searching browser QString findInBrowserText; /// find next toolbutton QToolButton* findNextPushButton; /// line edit for searching web pages QLineEdit* searchLineEdit; }; #endif // __GUI_HELP_VIEWER_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiHelpViewerWindow.cxx0000664000175000017500000005161011572067322022315 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 "BrainSet.h" #include "FileUtilities.h" #include "GuiHelpViewerWindow.h" #include "GuiMainWindow.h" #include "GuiTextBrowser.h" #include "global_variables.h" /** * Constructor (non-modal full navigation controls) */ GuiHelpViewerWindow::GuiHelpViewerWindow(QWidget* parent) : WuQDialog(parent) { setModal(false); setWindowTitle("Caret Help"); // // Layout for dialog. // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setSpacing(3); dialogLayout->setMargin(3); // // main window containing text browser // dialogLayout->addWidget(createHelpBrowser(true)); // // Buttons layout. // QHBoxLayout* buttonsLayout = new QHBoxLayout; dialogLayout->addLayout(buttonsLayout); QPushButton* closeButton = new QPushButton("Close"); closeButton->setAutoDefault(false); closeButton->setFixedSize(closeButton->sizeHint()); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); buttonsLayout->addWidget(closeButton); loadPage(); /* QVector > pages; getAllWebPages(pages); for (int i = 0; i < pages.count(); i++) { std::cout << "Page: " << pages[i].first.toAscii().constData() << ", " << pages[i].second.toAscii().constData() << std::endl; } */ } /** * Contructor (modal with a modal parent). */ GuiHelpViewerWindow::GuiHelpViewerWindow(QDialog* parent, const QString& helpPageIn) : WuQDialog(parent) { setModal(true); setWindowTitle("Caret Help"); // // Layout for dialog. // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setSpacing(3); dialogLayout->setMargin(3); // // main window containing text browser // dialogLayout->addWidget(createHelpBrowser(false)); // // Buttons layout. // QHBoxLayout* buttonsLayout = new QHBoxLayout; dialogLayout->addLayout(buttonsLayout); QPushButton* cancelButton = new QPushButton("Cancel"); cancelButton->setFixedSize(cancelButton->sizeHint()); QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); buttonsLayout->addWidget(cancelButton); loadPage(helpPageIn); } /** * Destructor */ GuiHelpViewerWindow::~GuiHelpViewerWindow() { } /** * Main Window Constructor */ QWidget* GuiHelpViewerWindow::createHelpBrowser(const bool showNavigationControlsFlag) { // // create the help browser // helpBrowser = new GuiTextBrowser; helpBrowser->setMinimumWidth(400); helpBrowser->setMinimumHeight(200); // // Layout for widget // QWidget* theHelpWidget = new QWidget; QVBoxLayout* widgetLayout = new QVBoxLayout(theHelpWidget); if (showNavigationControlsFlag) { // // Create the tree widget for the indices // QStringList indexTreeHeaderLabels; indexTreeHeaderLabels << "Help Page Index" << "Location"; indexTreeWidget = new QTreeWidget; indexTreeWidget->setColumnCount(2); indexTreeWidget->setHeaderLabels(indexTreeHeaderLabels); indexTreeWidget->setColumnHidden(0, false); indexTreeWidget->setColumnHidden(1, true); QObject::connect(indexTreeWidget, SIGNAL(itemClicked(QTreeWidgetItem*,int)), this, SLOT(indexTreeItemSelected(QTreeWidgetItem*,int))); loadIndexTree(); // // Search line edit and list widget // searchLineEdit = new QLineEdit; searchLineEdit->setText("Enter search here"); QObject::connect(searchLineEdit, SIGNAL(returnPressed()), this, SLOT(slotSearchLineEdit())); QStringList searchTreeHeaderLabels; searchTreeHeaderLabels << "Matching Help Pages" << "Location"; searchTreeWidget = new QTreeWidget; searchTreeWidget->setColumnCount(2); searchTreeWidget->setHeaderLabels(searchTreeHeaderLabels); searchTreeWidget->setColumnHidden(0, false); searchTreeWidget->setColumnHidden(1, true); QObject::connect(searchTreeWidget, SIGNAL(itemClicked(QTreeWidgetItem*,int)), this, SLOT(searchTreeItemSelected(QTreeWidgetItem*,int))); QWidget* searchWidget = new QWidget; QVBoxLayout* searchLayout = new QVBoxLayout(searchWidget); searchLayout->addWidget(searchLineEdit); searchLayout->addWidget(searchTreeWidget); // // create the back toolbar button // QAction* backwardAction = new QAction("Back", this); connect(helpBrowser, SIGNAL(backwardAvailable(bool)), backwardAction, SLOT(setEnabled(bool))); connect(backwardAction, SIGNAL(triggered()), helpBrowser, SLOT(backward())); QToolButton* backwardButton = new QToolButton; backwardButton->setDefaultAction(backwardAction); // // Create the forward toolbar button // QAction* forewardAction = new QAction("Fwd", this); connect(helpBrowser, SIGNAL(forwardAvailable(bool)), forewardAction, SLOT(setEnabled(bool))); connect(forewardAction, SIGNAL(triggered()), helpBrowser, SLOT(forward())); QToolButton* forwardButton = new QToolButton; connect(helpBrowser, SIGNAL(forwardAvailable(bool)), forwardButton, SLOT(setEnabled(bool))); forwardButton->setDefaultAction(forewardAction); // // Create the home toolbar button // QAction* homeAction = new QAction("Home", this); connect(homeAction, SIGNAL(triggered()), helpBrowser, SLOT(home())); QToolButton* homeButton = new QToolButton; homeButton->setDefaultAction(homeAction); // // Create the print toolbar button // QAction* printAction = new QAction("Print", this); connect(printAction, SIGNAL(triggered()), this, SLOT(slotPrint())); QToolButton* printButton = new QToolButton; printButton->setDefaultAction(printAction); // // Find button // QToolButton* findPushButton = new QToolButton; findPushButton->setText("Find"); QObject::connect(findPushButton, SIGNAL(clicked()), this, SLOT(slotFindInBrowser())); // // Next button // findNextPushButton = new QToolButton; findNextPushButton->setText("Next"); findNextPushButton->setEnabled(false); QObject::connect(findNextPushButton, SIGNAL(clicked()), this, SLOT(slotFindNextInBrowser())); // // Layout for toolbuttons // QHBoxLayout* toolButtonLayout = new QHBoxLayout; toolButtonLayout->addWidget(homeButton); toolButtonLayout->addWidget(backwardButton); toolButtonLayout->addWidget(forwardButton); toolButtonLayout->addWidget(printButton); toolButtonLayout->addWidget(findPushButton); toolButtonLayout->addWidget(findNextPushButton); toolButtonLayout->addStretch(); // // Layout for help browser and buttons // QWidget* helpBrowserWidgets = new QWidget; QVBoxLayout* helpBrowserLayout = new QVBoxLayout(helpBrowserWidgets); helpBrowserLayout->addLayout(toolButtonLayout); helpBrowserLayout->addWidget(helpBrowser); // // Tab widget for index and search // QTabWidget* indexSearchTabWidget = new QTabWidget; indexSearchTabWidget->addTab(indexTreeWidget, "Index"); indexSearchTabWidget->addTab(searchWidget, "Search"); // // Create the splitter and add the widgets to the splitter // splitter = new QSplitter; splitter->setOrientation(Qt::Horizontal); splitter->addWidget(indexSearchTabWidget); splitter->addWidget(helpBrowserWidgets); QList sizeList; sizeList << 175 << 375; splitter->setSizes(sizeList); widgetLayout->addWidget(splitter); } else { widgetLayout->addWidget(helpBrowser); } // // Load the default page // loadPage(); return theHelpWidget; } /** * called to find in browser window. */ void GuiHelpViewerWindow::slotFindInBrowser() { bool ok = false; const QString txt = QInputDialog::getText(this, "Find", "Find Text", QLineEdit::Normal, findInBrowserText, &ok); if (ok) { findNextPushButton->setEnabled(false); findInBrowserText = txt.trimmed(); if (findInBrowserText.isEmpty() == false) { helpBrowser->moveCursor(QTextCursor::Start); if (helpBrowser->find(findInBrowserText)) { findNextPushButton->setEnabled(true); } } } } /** * called to find next in browser window. */ void GuiHelpViewerWindow::slotFindNextInBrowser() { if (helpBrowser->find(findInBrowserText) == false) { helpBrowser->moveCursor(QTextCursor::Start); helpBrowser->find(findInBrowserText); } } /** * called to print currently displayed page. */ void GuiHelpViewerWindow::slotPrint() { QPrinter printer; QPrintDialog* printDialog = new QPrintDialog(&printer, this); if (printDialog->exec() == QPrintDialog::Accepted) { helpBrowser->document()->print(&printer); } } /** * load the index tree. */ void GuiHelpViewerWindow::loadIndexTree() { QTreeWidgetItem* mainItem = createTreeItem("Main Page", "index.html"); indexTreeWidget->addTopLevelItem(mainItem); QTreeWidgetItem* installationItem = createTreeItem("Installation", "installation/caret5_installation.html"); indexTreeWidget->addTopLevelItem(installationItem); QTreeWidgetItem* sourceCodeItem = createTreeItem("Source Code", "source_code/source_code.html"); indexTreeWidget->addTopLevelItem(sourceCodeItem); QTreeWidgetItem* menusItem = createTreeItem("Menus"); indexTreeWidget->addTopLevelItem(menusItem); menusItem->addChild(createTreeItem("caret5 (Macintosh Only)", "menus/caret5_menu.html")); menusItem->addChild(createTreeItem("File", "menus/file_menu.html")); menusItem->addChild(createTreeItem("Attributes", "menus/attributes_menu.html")); menusItem->addChild(createTreeItem("Layers", "menus/layers_menu.html")); menusItem->addChild(createTreeItem("Surface", "menus/surface_menu.html")); menusItem->addChild(createTreeItem("Volume", "menus/volume_menu.html")); menusItem->addChild(createTreeItem("Comm", "menus/comm_menu.html")); menusItem->addChild(createTreeItem("Window", "menus/window_menu.html")); menusItem->addChild(createTreeItem("Help", "menus/help_menu.html")); QTreeWidgetItem* toolbarItem = createTreeItem("Toolbars"); indexTreeWidget->addTopLevelItem(toolbarItem); toolbarItem->addChild(createTreeItem("Main Window", "toolbars/main_window_toolbar.html")); toolbarItem->addChild(createTreeItem("Viewing Window", "toolbars/viewing_window_toolbar.html")); QTreeWidgetItem* dialogsItem = createTreeItem("Dialogs"); indexTreeWidget->addTopLevelItem(dialogsItem); dialogsItem->addChild(createTreeItem("Capture Image of Window", "dialogs/capture_image_of_window_dialog.html")); dialogsItem->addChild(createTreeItem("Display Control", "dialogs/display_control_dialog.html")); dialogsItem->addChild(createTreeItem("Draw Border", "dialogs/draw_border_dialog.html")); dialogsItem->addChild(createTreeItem("File Dialogs", "dialogs/file_dialogs.html")); dialogsItem->addChild(createTreeItem("Metric Smoothing", "dialogs/metric_smoothing_dialog.html")); dialogsItem->addChild(createTreeItem("Project Cells/Foci", "dialogs/project_cells_foci_dialog.html")); dialogsItem->addChild(createTreeItem("Project Foci to PALS", "dialogs/project_foci_to_pals_dialog.html")); dialogsItem->addChild(createTreeItem("Record Main Window Images as Movie", "dialogs/record_as_mpeg_dialog.html")); dialogsItem->addChild(createTreeItem("Study Metadata", "dialogs/study_metadata.html")); dialogsItem->addChild(createTreeItem("Surface Region of Interest", "dialogs/surface_roi_dialog.html")); dialogsItem->addChild(createTreeItem("Surface to Volume", "dialogs/Surface_To_Volume_Dialog.html")); QTreeWidgetItem* statsItem = createTreeItem("Statistics"); indexTreeWidget->addTopLevelItem(statsItem); statsItem->addChild(createTreeItem("Interhemispheric Clusters", "statistics/interhemispheric_clusters.html")); statsItem->addChild(createTreeItem("Normalize Data", "statistics/normalization.html")); statsItem->addChild(createTreeItem("One-Sample and Paired T-Test", "statistics/one_sample_t_test.html")); statsItem->addChild(createTreeItem("Shuffled Cross-Correlation Maps", "statistics/shuffled_cross_correlation_maps.html")); statsItem->addChild(createTreeItem("Subtract Group Average", "statistics/subtract_group_average.html")); statsItem->addChild(createTreeItem("Two Sample T-Test", "statistics/two_sample_t_test.html")); statsItem->addChild(createTreeItem("T-Map Shuffled", "statistics/t_map_shuffled_columns.html")); statsItem->addChild(createTreeItem("T-Map", "statistics/tmap.html")); statsItem->addChild(createTreeItem("Wilcoxon Rank-Sum", "statistics/wilcoxon_rank_sum.html")); statsItem->addChild(createTreeItem("Z-Map", "statistics/z_map.html")); QTreeWidgetItem* studyItem = createTreeItem("Study Metadata", "dialogs/study_metadata.html"); indexTreeWidget->addTopLevelItem(studyItem); QTreeWidgetItem* faqsItem = createTreeItem("FAQs"); indexTreeWidget->addTopLevelItem(faqsItem); faqsItem->addChild(createTreeItem("Images", "faqs/images.html")); faqsItem->addChild(createTreeItem("Scenes", "faqs/scenes.html")); QTreeWidgetItem* filesItem = createTreeItem("Files"); indexTreeWidget->addTopLevelItem(filesItem); filesItem->addChild(createTreeItem("File Formats", "file_formats/file_formats.html")); filesItem->addChild(createTreeItem("File Types", "file_formats/files.html")); filesItem->addChild(createTreeItem("Spec File Tags", "file_formats/spec_file_tags.html")); QTreeWidgetItem* keysItem = createTreeItem("Keyboard Commands", "misc/keyboard_commands.html"); indexTreeWidget->addTopLevelItem(keysItem); QTreeWidgetItem* changesItem = createTreeItem("Changes Log", "misc/change_log.html"); indexTreeWidget->addTopLevelItem(changesItem); QTreeWidgetItem* tutorialItem = createTreeItem("Caret 5.5 Basics Tutorial", "tutorials/Caret_Tutorial_5.5.html"); indexTreeWidget->addTopLevelItem(tutorialItem); QTreeWidgetItem* introGuideItem = createTreeItem("Caret 5.5 Analysis Tutorial", "tutorials/Caret_Analysis_5.5.html"); indexTreeWidget->addTopLevelItem(introGuideItem); QTreeWidgetItem* segmentGuideItem = createTreeItem("Caret 5.5 Segmentation, Flattening, and Registration", "tutorials/Caret_5.5_Tutorial_Segment.html"); indexTreeWidget->addTopLevelItem(segmentGuideItem); } /** * Create an list tree widget item */ QTreeWidgetItem* GuiHelpViewerWindow::createTreeItem(const QString& label, const QString& helpPage) { QString pageName = helpPage; QFileInfo fileInfo(pageName); if (fileInfo.isAbsolute() == false) { QString defaultPage(theMainWindow->getBrainSet()->getCaretHomeDirectory()); defaultPage.append("/"); defaultPage.append("caret5_help"); defaultPage.append("/"); defaultPage.append(helpPage); pageName = defaultPage; } QTreeWidgetItem* item = new QTreeWidgetItem(QStringList(label)); item->setText(0, label); item->setText(1, pageName); return item; } /** * called when an index tree item is clicked. */ void GuiHelpViewerWindow::indexTreeItemSelected(QTreeWidgetItem* item, int /*column*/) { const QString webPage(item->text(1)); //std::cout << "Item selected is: " << webPage.toAscii().constData() << std::endl; if (webPage.isEmpty() == false) { loadPage(webPage); } } /** * called when a search tree item is clicked. */ void GuiHelpViewerWindow::searchTreeItemSelected(QTreeWidgetItem* item, int /*column*/) { const QString webPage(item->text(1)); //std::cout << "Item selected is: " << webPage.toAscii().constData() << std::endl; if (webPage.isEmpty() == false) { loadPage(webPage); slotFindNextInBrowser(); } } /** * Load a page into the help browser. */ void GuiHelpViewerWindow::loadPage(const QString& pageNameIn) { // // If no page name then default to main page // QString pageName(pageNameIn); if (pageName.isEmpty()) { pageName = "index.html"; } // // If not absolute page, assume that file is in caret help directory // QFileInfo fileInfo(pageName); if (fileInfo.isAbsolute() == false) { QString defaultPage(theMainWindow->getBrainSet()->getCaretHomeDirectory()); defaultPage.append("/"); defaultPage.append("caret5_help"); defaultPage.append("/"); defaultPage.append(pageName); pageName = defaultPage; } static bool firstTime = true; if (firstTime && (QFile::exists(pageName) == false)) { QString msg; msg.append("The file "); msg.append(pageName); msg.append("\n"); msg.append("cannot be found."); QApplication::beep(); QMessageBox::critical(this, "Caret Error", msg, "OK"); return; } firstTime = false; helpBrowser->setSource(QUrl::fromLocalFile(pageName)); } /** * get all web page names and titles. */ void GuiHelpViewerWindow::getAllWebPages(QVector >& pagesOut) const { pagesOut.clear(); // // Search through the tree widget to find all items with URLs // const int numItems = indexTreeWidget->topLevelItemCount(); for (int i = 0; i < numItems; i++) { const QTreeWidgetItem* topItem = indexTreeWidget->topLevelItem(i); if (topItem->text(1).isEmpty() == false) { const QString pageName = topItem->text(0); const QString pageURL = topItem->text(1); pagesOut.push_back(qMakePair(pageName, pageURL)); } // // Search children of this item // const int numSubItems = topItem->childCount(); for (int j = 0; j < numSubItems; j++) { const QTreeWidgetItem* subItem = topItem->child(j); if (subItem->text(1).isEmpty() == false) { const QString pageName = subItem->text(0); const QString pageURL = subItem->text(1); pagesOut.push_back(qMakePair(pageName, pageURL)); } } } } /** * called to search all help pages. */ void GuiHelpViewerWindow::slotSearchLineEdit() { searchTreeWidget->clear(); const QString searchText = searchLineEdit->text(); if (searchText.isEmpty() == false) { QVector > pages; getAllWebPages(pages); for (int i = 0; i < pages.count(); i++) { const QString pageTitle = pages[i].first.toAscii().constData(); const QString pageURL = pages[i].second.toAscii().constData(); //std::cout << "Searching: " // << pageTitle.toAscii().constData() // << std::endl; if (FileUtilities::findTextInFile(pageURL, searchText, false)) { //std::cout << " Page matches " // << std::endl; searchTreeWidget->addTopLevelItem(createTreeItem(pageTitle, pageURL)); } } findInBrowserText = searchText; findNextPushButton->setEnabled(true); } } caret-5.6.4~dfsg.1.orig/caret/GuiHelpAssistantWindow.h0000664000175000017500000000453011572067322022451 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_HELP_ASSISTANT_WINDOW_H__ #define __GUI_HELP_ASSISTANT_WINDOW_H__ #include #if QT_VERSION >= QT_VERSION_CHECK(4,6,0) #include #include /// dialog for showing help in a qt assistant window class GuiHelpAssistantWindow : public QObject { Q_OBJECT public: // conostructor GuiHelpAssistantWindow(const QString& path, QObject* parent = 0); // destructor ~GuiHelpAssistantWindow(); // show help page virtual void showPage(const QString& pageNameIn); QProcess *process; QObject* m_parent; protected slots: // called if error void showError(const QString& message); protected: }; #else #pragma message ("Running out of date version of QT, please update soon.\n") #include /// dialog for showing help in a qt assistant window class GuiHelpAssistantWindow : public QAssistantClient { Q_OBJECT public: // conostructor GuiHelpAssistantWindow(const QString& path, QObject* parent = 0); // destructor ~GuiHelpAssistantWindow(); // show help page virtual void showPage(const QString& pageNameIn); protected slots: // called if error void showError(const QString& message); protected: }; #endif //Q QT_VERSION >= 0x040600 #endif // __GUI_HELP_ASSISTANT_WINDOW_H__ caret-5.6.4~dfsg.1.orig/caret/GuiHelpAssistantWindow.cxx0000664000175000017500000001021211572067322023016 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainSet.h" #include "GuiHelpAssistantWindow.h" #include "GuiMainWindow.h" #include "global_variables.h" #if QT_VERSION >= 0x040600 #include #include #include /** * conostructor. */ GuiHelpAssistantWindow::GuiHelpAssistantWindow(const QString& path, QObject* parent) { m_parent = parent; process = NULL; } /** * destructor. */ GuiHelpAssistantWindow::~GuiHelpAssistantWindow() { } /** * show help page. */ void GuiHelpAssistantWindow::showPage(const QString& pageNameIn) { QString pageName(pageNameIn); if (pageName.isEmpty()) { pageName = "index.html"; } // // If not absolute page, assume that file is in caret help directory // QFileInfo fileInfo(pageName); if (fileInfo.isAbsolute() == false) { QString defaultPage(theMainWindow->getBrainSet()->getCaretHomeDirectory()); defaultPage.append("/"); defaultPage.append("caret5_help"); defaultPage.append("/"); defaultPage.append(pageName); pageName = defaultPage; } if(!process) { process = new QProcess(m_parent); QString app = QLibraryInfo::location(QLibraryInfo::BinariesPath) + QLatin1String("/assistant"); process->start(app, QStringList() << QLatin1String("-enableRemoteControl")); if (!process->waitForStarted()) { QMessageBox::critical((QWidget*)m_parent, tr("Remote Control"), tr("Could not start Qt Assistant from %1.").arg(app)); return; } } // show index page QTextStream str(process); str << pageName << QLatin1Char('\0') << endl; } /** * called if error. */ void GuiHelpAssistantWindow::showError(const QString& message) { if(process) delete process; QMessageBox::critical(theMainWindow, "ERROR", message); } #else // QT_VERSION < 4.6.0 /** * conostructor. */ GuiHelpAssistantWindow::GuiHelpAssistantWindow(const QString& path, QObject* parent) : QAssistantClient(path, parent) { QObject::connect(this, SIGNAL(error(const QString&)), this, SLOT(showError(const QString&))); } /** * destructor. */ GuiHelpAssistantWindow::~GuiHelpAssistantWindow() { } /** * show help page. */ void GuiHelpAssistantWindow::showPage(const QString& pageNameIn) { QString pageName(pageNameIn); if (pageName.isEmpty()) { pageName = "index.html"; } // // If not absolute page, assume that file is in caret help directory // QFileInfo fileInfo(pageName); if (fileInfo.isAbsolute() == false) { QString defaultPage(theMainWindow->getBrainSet()->getCaretHomeDirectory()); defaultPage.append("/"); defaultPage.append("caret5_help"); defaultPage.append("/"); defaultPage.append(pageName); pageName = defaultPage; } if (isOpen() == false) { openAssistant(); } QAssistantClient::showPage(pageName); } /** * called if error. */ void GuiHelpAssistantWindow::showError(const QString& message) { QMessageBox::critical(theMainWindow, "ERROR", message); } #endif // QT_VERSION >= 0x040600caret-5.6.4~dfsg.1.orig/caret/GuiGraphWidgetDialog.h0000664000175000017500000000277711572067322022037 0ustar michaelmichael #ifndef _GUI_GRAPH_WIDGET_DIALOG_H__ #define _GUI_GRAPH_WIDGET_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "WuQDialog.h" class GuiGraphWidget; class GuiGraphWidgetDialog : public WuQDialog { Q_OBJECT public: // constructor GuiGraphWidgetDialog(const QString& title, QWidget* parent = 0, Qt::WindowFlags f = 0); // destructor ~GuiGraphWidgetDialog(); // get the graph widget GuiGraphWidget* getGraphWidget() { return graphWidget; } protected: /// the graph widget GuiGraphWidget* graphWidget; }; #endif // _GUI_GRAPH_WIDGET_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiGraphWidgetDialog.cxx0000664000175000017500000000341211572067322022375 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include "GuiGraphWidget.h" #include "GuiGraphWidgetDialog.h" /** * constructor. */ GuiGraphWidgetDialog::GuiGraphWidgetDialog(const QString& title, QWidget* parent, Qt::WindowFlags f) : WuQDialog(parent, f) { QVBoxLayout* dialogLayout = new QVBoxLayout(this); graphWidget = new GuiGraphWidget(0, title); dialogLayout->addWidget(graphWidget); // // Dialog buttons // QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); buttonBox->button(QDialogButtonBox::Close)->setAutoDefault(false); dialogLayout->addWidget(buttonBox); QObject::connect(buttonBox, SIGNAL(rejected()), this, SLOT(close())); } /** * destructor. */ GuiGraphWidgetDialog::~GuiGraphWidgetDialog() { } caret-5.6.4~dfsg.1.orig/caret/GuiGraphWidget.h0000664000175000017500000001612311572067322020705 0ustar michaelmichael #ifndef __GUI_GRAPH_WIDGET_H__ #define __GUI_GRAPH_WIDGET_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #ifdef HAVE_QWT #include #endif // HAVE_QWT #include class QDoubleSpinBox; class QwtPlotCurve; class QwtPlotMarker; #ifdef HAVE_QWT /// graph based upon Qwt Graph class GuiQwtGraph : public QwtPlot { Q_OBJECT public: /// how to draw data enum DRAW_DATA_TYPE { /// draw data as lines DRAW_DATA_TYPE_LINES, /// draw data as bars DRAW_DATA_TYPE_BARS }; // constructor GuiQwtGraph(QWidget* parent, const QString& title, const char* name = 0); // destructor ~GuiQwtGraph(); // add data to the graph (returns key of curve) QwtPlotCurve* addData(const std::vector& dataX, const std::vector& dataY, const QColor& color, const DRAW_DATA_TYPE ddt); // set the minimum peak void slotSetMinimumPeak(int val); // set the maximum peak void slotSetMaximumPeak(int val); // replot the graph virtual void replot(); // get the scale void getScale(double& xMin, double& xMax, double& yMin, double& yMax); // set the scale void setScale(const double xMin, const double xMax, const double yMin, const double yMax); // set the legends. void setLegends(const QString& topLegendIn, const QString& bottomLegendIn, const QString& leftLegendIn, const QString& rightLegendIn); public slots: // set the minimum for the X-scale void setScaleXMinimum(double val); // set the maximum for the X-scale void setScaleXMaximum(double val); // set the minimum for the Y-scale void setScaleYMinimum(double val); // set the maximum for the Y-scale void setScaleYMaximum(double val); protected: /// marker for minimum peak QwtPlotMarker* minPeakMarker; /// marker for maximum peak QwtPlotMarker* maxPeakMarker; /// the scale minimum for Y double scaleMinimumX; /// the scale maximum for Y double scaleMaximumX; /// the scale minimum for Y double scaleMinimumY; /// the scale maximum for Y double scaleMaximumY; /// legend QString topLegend; /// legend QString bottomLegend; /// legend QString leftLegend; /// legend QString rightLegend; }; #endif // HAVE_QWT /// the graph widget class GuiGraphWidget : public QWidget { Q_OBJECT public: /// how to draw data enum DRAW_DATA_TYPE { /// draw data as lines DRAW_DATA_TYPE_LINES, /// draw data as bars DRAW_DATA_TYPE_BARS }; // constructor GuiGraphWidget(QWidget* parent, const QString& title); // destructor ~GuiGraphWidget(); // add data to the graph widget (returns -1 if invalid data else index of curve) int addData(const std::vector& dataX, const std::vector& dataY, const QColor& color, const DRAW_DATA_TYPE ddt); // enable/disable display of data in graph widget void setDataDisplayed(const int dataIndex, const bool displayIt); // remove data void removeData(const int dataNumber); // remove all data from graph void removeAllData(); // get the graph min/max void getGraphMinMax(double& xMin, double& xMax, double& yMin, double& yMax); // set the graph min/max void setGraphMinMax(const double xMin, const double xMax, const double yMin, const double yMax); // set the legends void setLegends(const QString& topLegend, const QString& bottomLegend, const QString& leftLegend, const QString& rightLegend); public slots: // set the minimum peak void slotSetMinimumPeak(int val); // set the maximum peak void slotSetMaximumPeak(int val); // set the minimum for the X-scale void setScaleXMinimum(double val); // set the maximum for the X-scale void setScaleXMaximum(double val); // set the minimum for the Y-scale void setScaleYMinimum(double val); // set the maximum for the Y-scale void setScaleYMaximum(double val); protected slots: #ifdef HAVE_QWT // called when a point is picked void slotPointPicked(const QwtDoublePoint&); #endif // HAVE_QWT // apply scale push button void slotApplyScalePushButton(); // reset scale push button void slotResetScalePushButton(); protected: #ifdef HAVE_QWT /// the graph GuiQwtGraph* graphWidget; #endif // HAVE_QWT /// pick label showing X coordinates QLabel* pickXLabel; /// pick label showing Y coordinates QLabel* pickYLabel; #ifdef HAVE_QWT /// the curves in the graph widget std::vector curvesInGraphWidget; #endif // HAVE_QWT /// x-minimum float spin box QDoubleSpinBox* xMinimumDoubleSpinBox; /// x-maximum float spin box QDoubleSpinBox* xMaximumDoubleSpinBox; /// x-minimum float spin box QDoubleSpinBox* yMinimumDoubleSpinBox; /// y-maximum float spin box QDoubleSpinBox* yMaximumDoubleSpinBox; /// x-data minimum value double xDataMinimum; /// x-data maximum value double xDataMaximum; }; #endif // __GUI_GRAPH_WIDGET_H__ caret-5.6.4~dfsg.1.orig/caret/GuiGraphWidget.cxx0000664000175000017500000004665211572067322021272 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #ifdef HAVE_QWT #include #include #include #endif // HAVE_QWT #include "GuiGraphWidget.h" #include #ifdef HAVE_QWT /** * Constructor. */ GuiQwtGraph::GuiQwtGraph(QWidget* parent, const QString& title, const char* /*name*/) : QwtPlot(parent) { setTitle(title); scaleMinimumX = std::numeric_limits::max(); scaleMaximumX = -std::numeric_limits::max(); scaleMinimumY = std::numeric_limits::max(); scaleMaximumY = -std::numeric_limits::max(); //setAxisScale(xBottom, 0.0, 5000.0); //setAxisScale(yLeft, 0.0, 5000.0); minPeakMarker = NULL; maxPeakMarker = NULL; replot(); } /** * destructor. */ GuiQwtGraph::~GuiQwtGraph() { } /** * set the scale. */ void GuiQwtGraph::setScale(const double xMin, const double xMax, const double yMin, const double yMax) { scaleMinimumX = xMin; scaleMaximumX = xMax, scaleMinimumY = yMin; scaleMaximumY = yMax; replot(); } /** * get the scale. */ void GuiQwtGraph::getScale(double& xMin, double& xMax, double& yMin, double& yMax) { xMin = scaleMinimumX; xMax = scaleMaximumX; yMin = scaleMinimumY; yMax = scaleMaximumY; } /** * set the minimum for the X-scale. */ void GuiQwtGraph::setScaleXMinimum(double val) { scaleMinimumX = val; replot(); } /** * set the maximum for the X-scale. */ void GuiQwtGraph::setScaleXMaximum(double val) { scaleMaximumX = val; replot(); } /** * set the minimum for the Y-scale. */ void GuiQwtGraph::setScaleYMinimum(double val) { scaleMinimumY = val; replot(); } /** * set the maximum for the Y-scale. */ void GuiQwtGraph::setScaleYMaximum(double val) { scaleMaximumY = val; replot(); } /** * replot the graph. */ void GuiQwtGraph::replot() { if (scaleMaximumX > scaleMinimumX) { setAxisScale(xBottom, scaleMinimumX, scaleMaximumX); } if (scaleMaximumY > scaleMinimumY) { setAxisScale(yLeft, scaleMinimumY, scaleMaximumY); } if (topLegend.isEmpty() == false) setAxisTitle(xTop, topLegend); if (bottomLegend.isEmpty() == false) setAxisTitle(xBottom, bottomLegend); if (leftLegend.isEmpty() == false) setAxisTitle(yLeft, leftLegend); if (rightLegend.isEmpty() == false) setAxisTitle(yRight, rightLegend); QwtPlot::replot(); } /** * set the minimum peak. */ void GuiQwtGraph::slotSetMinimumPeak(int val) { if (minPeakMarker == NULL) { // // Use marker lines for min peak // minPeakMarker = new QwtPlotMarker(); minPeakMarker->attach(this); //insertLineMarker("", xBottom); minPeakMarker->setLineStyle(QwtPlotMarker::VLine); minPeakMarker->setLinePen(QPen(Qt::blue, 3)); } if (minPeakMarker != NULL) { minPeakMarker->show(); minPeakMarker->setXValue(val); } else { minPeakMarker->hide(); } replot(); } /** * set the maximum peak. */ void GuiQwtGraph::slotSetMaximumPeak(int val) { if (maxPeakMarker == NULL) { // // Use maker for max peak // maxPeakMarker = new QwtPlotMarker(); maxPeakMarker->attach(this); maxPeakMarker->setLineStyle(QwtPlotMarker::VLine); maxPeakMarker->setLinePen(QPen(Qt::green, 3)); } if (maxPeakMarker != NULL) { maxPeakMarker->show(); maxPeakMarker->setXValue(val); } else { maxPeakMarker->hide(); } replot(); } /** * add data to the graph. Returns 0 if resulting curve is invalid. */ QwtPlotCurve* GuiQwtGraph::addData(const std::vector& dataX, const std::vector& dataY, const QColor& color, const DRAW_DATA_TYPE ddt) { const unsigned int num = dataX.size(); if (num > 0) { // // Create a new curve // QwtPlotCurve* newCurve = new QwtPlotCurve("histogram"); newCurve->attach(this); // // Set the style of the curve // newCurve->setPen(QPen(color)); switch (ddt) { case DRAW_DATA_TYPE_LINES: break; case DRAW_DATA_TYPE_BARS: newCurve->setBrush(QBrush(color, Qt::SolidPattern)); break; } // // Set the data for the curve // newCurve->setData(&dataX[0], &dataY[0], num); const double minValX = *std::min_element(dataX.begin(), dataX.end()); const double maxValX = *std::max_element(dataX.begin(), dataX.end()); //const double percentX = (maxValX - minValX) * 0.05; scaleMinimumX = std::min(scaleMinimumX, minValX); //(minValX - percentX)); scaleMaximumX = std::max(scaleMaximumX, maxValX); //(maxValX + percentX)); const double minValY = *std::min_element(dataY.begin(), dataY.end()); const double maxValY = *std::max_element(dataY.begin(), dataY.end()); //const double percentY = (maxValY - minValY) * 0.01; scaleMinimumY = std::min(scaleMinimumY, minValY); //(minValY - percentY)); scaleMaximumY = std::max(scaleMaximumY, maxValY); //(maxValY + percentY)); replot(); return newCurve; } return 0; } /** * set the legends. */ void GuiQwtGraph::setLegends(const QString& topLegendIn, const QString& bottomLegendIn, const QString& leftLegendIn, const QString& rightLegendIn) { topLegend = topLegendIn; bottomLegend = bottomLegendIn; leftLegend = leftLegendIn; rightLegend = rightLegendIn; } #endif // HAVE_QWT //============================================================================= /** * constructor. */ GuiGraphWidget::GuiGraphWidget(QWidget* parent, const QString& title) : QWidget(parent) { #ifdef HAVE_QWT xDataMinimum = std::numeric_limits::max(); xDataMaximum = -std::numeric_limits::max(); QVBoxLayout* widgetLayout = new QVBoxLayout(this); // // Box for widget and scale control // QHBoxLayout* graphBoxLayout = new QHBoxLayout; graphBoxLayout->setSpacing(5); widgetLayout->addLayout(graphBoxLayout); // // The graph widget inside a group box // QGroupBox* graphGroupBox = new QGroupBox(title); graphBoxLayout->addWidget(graphGroupBox); graphBoxLayout->setStretchFactor(graphGroupBox, 1000); QVBoxLayout* graphGroupBoxLayout = new QVBoxLayout(graphGroupBox); graphWidget = new GuiQwtGraph(graphGroupBox, ""); graphGroupBoxLayout->addWidget(graphWidget); // // Picker for when graph is clicked with mouse // QwtPlotPicker* plotPicker = new QwtPlotPicker(QwtPlot::xBottom, QwtPlot::yLeft, graphWidget->canvas()); plotPicker->setSelectionFlags(QwtPicker::PointSelection | QwtPicker::ClickSelection); QObject::connect(plotPicker, SIGNAL(selected(const QwtDoublePoint&)), this, SLOT(slotPointPicked(const QwtDoublePoint&))); // // Vertical box for scale control and mouse coordinates // QVBoxLayout* scaleAndMouseVBoxLayout = new QVBoxLayout; graphBoxLayout->addLayout(scaleAndMouseVBoxLayout); graphBoxLayout->setStretchFactor(scaleAndMouseVBoxLayout, 0); // // Axis controls // QGroupBox* axisGroupBox = new QGroupBox("Scale Control"); QVBoxLayout* axisGroupBoxLayout = new QVBoxLayout(axisGroupBox); scaleAndMouseVBoxLayout->addWidget(axisGroupBox); QGridLayout* axisGridLayout = new QGridLayout; axisGroupBoxLayout->addLayout(axisGridLayout); const int minSpinWidth = 120; // // Y-Max // axisGridLayout->addWidget(new QLabel("Y-Max "), 0, 0); yMaximumDoubleSpinBox = new QDoubleSpinBox; yMaximumDoubleSpinBox->setMinimum(-1.0); yMaximumDoubleSpinBox->setMaximum(1.0); yMaximumDoubleSpinBox->setSingleStep(1.0); yMaximumDoubleSpinBox->setDecimals(6); axisGridLayout->addWidget(yMaximumDoubleSpinBox, 0, 1); yMaximumDoubleSpinBox->setMinimumWidth(minSpinWidth); QObject::connect(yMaximumDoubleSpinBox, SIGNAL(valueChanged(double)), graphWidget, SLOT(setScaleYMaximum(double))); // // Y-Min // axisGridLayout->addWidget(new QLabel("Y-Min "), 1, 0); yMinimumDoubleSpinBox = new QDoubleSpinBox; yMinimumDoubleSpinBox->setMinimum(-1.0); yMinimumDoubleSpinBox->setMaximum(1.0); yMinimumDoubleSpinBox->setSingleStep(1.0); yMinimumDoubleSpinBox->setDecimals(6); axisGridLayout->addWidget(yMinimumDoubleSpinBox, 1, 1); yMinimumDoubleSpinBox->setMinimumWidth(minSpinWidth); QObject::connect(yMinimumDoubleSpinBox, SIGNAL(valueChanged(double)), graphWidget, SLOT(setScaleYMinimum(double))); // // X-Max // axisGridLayout->addWidget(new QLabel("X-Max "), 2, 0); xMaximumDoubleSpinBox = new QDoubleSpinBox; xMaximumDoubleSpinBox->setMinimum(-std::numeric_limits::max()); xMaximumDoubleSpinBox->setMaximum(std::numeric_limits::max()); xMaximumDoubleSpinBox->setSingleStep(1.0); xMaximumDoubleSpinBox->setDecimals(6); axisGridLayout->addWidget(xMaximumDoubleSpinBox, 2, 1); xMaximumDoubleSpinBox->setMinimumWidth(minSpinWidth); QObject::connect(xMaximumDoubleSpinBox, SIGNAL(valueChanged(double)), graphWidget, SLOT(setScaleXMaximum(double))); // // X-Min // axisGridLayout->addWidget(new QLabel("X-Min "), 3, 0); xMinimumDoubleSpinBox = new QDoubleSpinBox; xMinimumDoubleSpinBox->setMinimum(-std::numeric_limits::max()); xMinimumDoubleSpinBox->setMaximum(std::numeric_limits::max()); xMinimumDoubleSpinBox->setSingleStep(1.0); xMinimumDoubleSpinBox->setDecimals(6); axisGridLayout->addWidget(xMinimumDoubleSpinBox, 3, 1); xMinimumDoubleSpinBox->setMinimumWidth(minSpinWidth); QObject::connect(xMinimumDoubleSpinBox, SIGNAL(valueChanged(double)), graphWidget, SLOT(setScaleXMinimum(double))); // // Apply push button // QPushButton* applyPushButton = new QPushButton("Apply"); axisGroupBoxLayout->addWidget(applyPushButton); applyPushButton->setAutoDefault(false); QObject::connect(applyPushButton, SIGNAL(clicked()), this, SLOT(slotApplyScalePushButton())); // // Reset push button // QPushButton* resetPushButton = new QPushButton("Reset"); axisGroupBoxLayout->addWidget(resetPushButton); resetPushButton->setAutoDefault(false); QObject::connect(resetPushButton, SIGNAL(clicked()), this, SLOT(slotResetScalePushButton())); axisGroupBox->setFixedHeight(axisGroupBox->sizeHint().height()); // // X and Y pick label // QGroupBox* labelGroupBox = new QGroupBox("Mouse Coordinates"); QVBoxLayout* labelGroupBoxLayout = new QVBoxLayout(labelGroupBox); scaleAndMouseVBoxLayout->addWidget(labelGroupBox); pickXLabel = new QLabel("Click mouse on graph"); labelGroupBoxLayout->addWidget(pickXLabel); pickYLabel = new QLabel("to get coordinates."); labelGroupBoxLayout->addWidget(pickYLabel); labelGroupBox->setFixedHeight(labelGroupBox->sizeHint().height()); #else // HAVE_QWT // // Warning Label // QLabel* warningLabel = new QLabel( "Graphs are not available.
    " "Caret was built without the QWT Graph Library.
    "); QVBoxLayout* widgetLayout = new QVBoxLayout(this); widgetLayout->addWidget(warningLabel); #endif // HAVE_QWT } /** * destructor. */ GuiGraphWidget::~GuiGraphWidget() { } /** * apply scale push button. */ void GuiGraphWidget::slotApplyScalePushButton() { #ifdef HAVE_QWT graphWidget->setScale(xMinimumDoubleSpinBox->value(), xMaximumDoubleSpinBox->value(), yMinimumDoubleSpinBox->value(), yMaximumDoubleSpinBox->value()); #endif HAVE_QWT } /** * reset scale push button. */ void GuiGraphWidget::slotResetScalePushButton() { xMinimumDoubleSpinBox->setValue(xDataMinimum); // xMinimumDoubleSpinBox->minimum()); xMaximumDoubleSpinBox->setValue(xDataMaximum); // xMaximumDoubleSpinBox->maximum()); yMinimumDoubleSpinBox->setValue(yMinimumDoubleSpinBox->minimum()); yMaximumDoubleSpinBox->setValue(yMaximumDoubleSpinBox->maximum()); } /** * get the graph min/max. */ void GuiGraphWidget::getGraphMinMax(double& xMin, double& xMax, double& yMin, double& yMax) { #ifdef HAVE_QWT graphWidget->getScale(xMin, xMax, yMin, yMax); #endif } /** * set the graph min/max. */ void GuiGraphWidget::setGraphMinMax(const double xMin, const double xMax, const double yMin, const double yMax) { #ifdef HAVE_QWT xMinimumDoubleSpinBox->setValue(xMin); xMaximumDoubleSpinBox->setValue(xMax); yMinimumDoubleSpinBox->setValue(yMin); yMaximumDoubleSpinBox->setValue(yMax); slotApplyScalePushButton(); #endif // HAVE_QWT } /** * add data to the graph widget. */ int GuiGraphWidget::addData(const std::vector& dataX, const std::vector& dataY, const QColor& color, const DRAW_DATA_TYPE ddtIn) { #ifdef HAVE_QWT GuiQwtGraph::DRAW_DATA_TYPE ddt = GuiQwtGraph::DRAW_DATA_TYPE_LINES; switch (ddtIn) { case DRAW_DATA_TYPE_LINES: ddt = GuiQwtGraph::DRAW_DATA_TYPE_LINES; break; case DRAW_DATA_TYPE_BARS: ddt = GuiQwtGraph::DRAW_DATA_TYPE_BARS; break; } QwtPlotCurve* curve = graphWidget->addData(dataX, dataY, color, ddt); if (curve > 0) { curvesInGraphWidget.push_back(curve); xDataMinimum = std::min(xDataMinimum, *std::min_element(dataX.begin(), dataX.end())); xDataMaximum = std::max(xDataMaximum, *std::max_element(dataX.begin(), dataX.end())); xMinimumDoubleSpinBox->setValue(xDataMinimum); xMaximumDoubleSpinBox->setValue(xDataMaximum); /* double minX = *std::min_element(dataX.begin(), dataX.end()); double maxX = *std::max_element(dataX.begin(), dataX.end()); if (curvesInGraphWidget.size() > 1) { minX = std::min(minX, xMinimumDoubleSpinBox->minimum()); maxX = std::max(maxX, xMinimumDoubleSpinBox->maximum()); } xMinimumDoubleSpinBox->setMinimum(minX); xMinimumDoubleSpinBox->setMaximum(maxX); xMaximumDoubleSpinBox->setMinimum(minX); xMaximumDoubleSpinBox->setMaximum(maxX); xMinimumDoubleSpinBox->setValue(minX); xMaximumDoubleSpinBox->setValue(maxX); */ double minY = *std::min_element(dataY.begin(), dataY.end()); double maxY = *std::max_element(dataY.begin(), dataY.end()); if (curvesInGraphWidget.size() > 1) { minY = std::min(minY, yMinimumDoubleSpinBox->minimum()); maxY = std::max(maxY, yMinimumDoubleSpinBox->maximum()); } yMinimumDoubleSpinBox->setMinimum(minY); yMinimumDoubleSpinBox->setMaximum(maxY); yMaximumDoubleSpinBox->setMinimum(minY); yMaximumDoubleSpinBox->setMaximum(maxY); yMinimumDoubleSpinBox->setValue(minY); yMaximumDoubleSpinBox->setValue(maxY); return curvesInGraphWidget.size() - 1; } #endif // HAVE_QWT return -1; } /** * called when a point is picked. */ #ifdef HAVE_QWT void GuiGraphWidget::slotPointPicked(const QwtDoublePoint& dp) { pickXLabel->setText("X: " + QString::number(dp.x(), 'f', 6)); pickYLabel->setText("Y: " + QString::number(dp.y(), 'f', 6)); } #endif // HAVE_QWT /** * set the minimum peak. */ void GuiGraphWidget::slotSetMinimumPeak(int val) { #ifdef HAVE_QWT graphWidget->slotSetMinimumPeak(val); #endif // HAVE_QWT } /** * set the maximum peak. */ void GuiGraphWidget::slotSetMaximumPeak(int val) { #ifdef HAVE_QWT graphWidget->slotSetMaximumPeak(val); #endif // HAVE_QWT } /** * set the minimum for the X-scale. */ void GuiGraphWidget::setScaleXMinimum(double val) { #ifdef HAVE_QWT xMinimumDoubleSpinBox->setValue(val); graphWidget->setScaleXMinimum(val); #endif // HAVE_QWT } /** * set the maximum for the X-scale. */ void GuiGraphWidget::setScaleXMaximum(double val) { #ifdef HAVE_QWT xMaximumDoubleSpinBox->setValue(val); graphWidget->setScaleXMaximum(val); #endif // HAVE_QWT } /** * set the minimum for the Y-scale. */ void GuiGraphWidget::setScaleYMinimum(double val) { #ifdef HAVE_QWT yMinimumDoubleSpinBox->setValue(val); graphWidget->setScaleYMinimum(val); #endif // HAVE_QWT } /** * set the maximum for the Y-scale. */ void GuiGraphWidget::setScaleYMaximum(double val) { #ifdef HAVE_QWT yMaximumDoubleSpinBox->setValue(val); graphWidget->setScaleYMaximum(val); #endif // HAVE_QWT } /** * enable/disable display of data in graph widget. */ void GuiGraphWidget::setDataDisplayed(const int dataIndex, const bool displayIt) { #ifdef HAVE_QWT if (dataIndex < static_cast(curvesInGraphWidget.size())) { if (displayIt) { curvesInGraphWidget[dataIndex]->setStyle(QwtPlotCurve::Lines); } else { curvesInGraphWidget[dataIndex]->setStyle(QwtPlotCurve::NoCurve); } graphWidget->replot(); } #endif // HAVE_QWT } /** * remove data . */ void GuiGraphWidget::removeData(const int dataNumber) { #ifdef HAVE_QWT if ((dataNumber >= 0) && (dataNumber < static_cast(curvesInGraphWidget.size()))) { //graphWidget->removeCurve(curvesInGraphWidget[dataNumber]); curvesInGraphWidget[dataNumber]->detach(); } #endif // HAVE_QWT } /** * remove all data from graph. */ void GuiGraphWidget::removeAllData() { #ifdef HAVE_QWT for (int i = 0; i < static_cast(curvesInGraphWidget.size()); i++) { curvesInGraphWidget[i]->detach(); } #endif // HAVE_QWT } /** * set the legends. */ void GuiGraphWidget::setLegends(const QString& topLegend, const QString& bottomLegend, const QString& leftLegend, const QString& rightLegend) { #ifdef HAVE_QWT graphWidget->setLegends(topLegend, bottomLegend, leftLegend, rightLegend); #endif // HAVE_QWT } caret-5.6.4~dfsg.1.orig/caret/GuiGenerateSurfaceCurvatureDialog.h0000664000175000017500000000411511572067322024562 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_GENERATE_SURFACE_CURVATURE_DIALOG_H__ #define __GUI_GENERATE_SURFACE_CURVATURE_DIALOG_H__ #include "WuQDialog.h" class GuiBrainModelSelectionComboBox; class GuiNodeAttributeColumnSelectionComboBox; class QLineEdit; /// Class for dialog that generates surface curvature class GuiGenerateSurfaceCurvatureDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiGenerateSurfaceCurvatureDialog(QWidget* parent); /// Destructor ~GuiGenerateSurfaceCurvatureDialog(); private slots: /// called when Ok or Cancel button pressed void done(int r); private: /// surface combo box GuiBrainModelSelectionComboBox* surfaceComboBox; /// curvature column combo box GuiNodeAttributeColumnSelectionComboBox* meanCurvatureColumnComboBox; /// curvature name line edit QLineEdit* meanCurvatureNameLineEdit; /// curvature column combo box GuiNodeAttributeColumnSelectionComboBox* gaussianCurvatureColumnComboBox; /// curvature name line edit QLineEdit* gaussianCurvatureNameLineEdit; }; #endif // __GUI_GENERATE_SURFACE_CURVATURE_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiGenerateSurfaceCurvatureDialog.cxx0000664000175000017500000002153611572067322025143 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include "BrainModelSurfaceCurvature.h" #include "BrainSet.h" #include "GuiBrainModelOpenGL.h" #include "GuiBrainModelSelectionComboBox.h" #include "GuiFilesModified.h" #include "GuiGenerateSurfaceCurvatureDialog.h" #include "GuiMainWindow.h" #include "GuiNodeAttributeColumnSelectionComboBox.h" #include "QtUtilities.h" #include "SurfaceShapeFile.h" #include "global_variables.h" /** * Constructor */ GuiGenerateSurfaceCurvatureDialog::GuiGenerateSurfaceCurvatureDialog(QWidget* parent) : WuQDialog(parent) { setModal(true); setWindowTitle("Generate Curvature"); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // surface group box // QGroupBox* surfaceGroupBox = new QGroupBox("Surface"); dialogLayout->addWidget(surfaceGroupBox); QVBoxLayout* surfaceGroupLayout = new QVBoxLayout(surfaceGroupBox); // // Fiducial Surface comb box // surfaceComboBox = new GuiBrainModelSelectionComboBox( false, true, false, "", 0); surfaceComboBox->setSelectedBrainModel(theMainWindow->getBrainModelSurface()); surfaceGroupLayout->addWidget(surfaceComboBox); // // Group Box for line edits and combo boxes // QGroupBox* groupBox = new QGroupBox("Surface Shape Columns"); dialogLayout->addWidget(groupBox); QGridLayout* groupGridLayout = new QGridLayout(groupBox); // // Mean Curvature Name line edit // meanCurvatureNameLineEdit = new QLineEdit; meanCurvatureNameLineEdit->setText("Folding (Mean Curvature)"); groupGridLayout->addWidget(meanCurvatureNameLineEdit, 0, 0); // // Mean curvature column combo box // meanCurvatureColumnComboBox = new GuiNodeAttributeColumnSelectionComboBox( GUI_NODE_FILE_TYPE_SURFACE_SHAPE, true, true, false); meanCurvatureColumnComboBox->setCurrentIndex( GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NEW); groupGridLayout->addWidget(meanCurvatureColumnComboBox, 0, 1); // // Gaussian Curvature Name line edit // gaussianCurvatureNameLineEdit = new QLineEdit(groupBox); gaussianCurvatureNameLineEdit->setText("Gaussian Curvature"); groupGridLayout->addWidget(gaussianCurvatureNameLineEdit, 1, 0); // // Gaussian curvature column combo box // gaussianCurvatureColumnComboBox = new GuiNodeAttributeColumnSelectionComboBox( GUI_NODE_FILE_TYPE_SURFACE_SHAPE, true, true, false); gaussianCurvatureColumnComboBox->setCurrentIndex( GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NEW); groupGridLayout->addWidget(gaussianCurvatureColumnComboBox, 1, 1); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); dialogLayout->addLayout(buttonsLayout); // // OK button // QPushButton* okButton = new QPushButton("OK"); buttonsLayout->addWidget(okButton); QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); // // Cancel button // QPushButton* cancelButton = new QPushButton("Cancel"); buttonsLayout->addWidget(cancelButton); QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); QtUtilities::makeButtonsSameSize(okButton, cancelButton); } /** * Destructor */ GuiGenerateSurfaceCurvatureDialog::~GuiGenerateSurfaceCurvatureDialog() { } /** * Called when OK or Cancel button pressed. */ void GuiGenerateSurfaceCurvatureDialog::done(int r) { if (r == QDialog::Accepted) { // // Get the surface for curvature calculation // BrainModelSurface* bms = surfaceComboBox->getSelectedBrainModelSurface(); if (bms == NULL) { QMessageBox::critical(this, "Error", "A surface must be selected."); return; } // // Get mean curvature selections // int meanCurvatureColumn = meanCurvatureColumnComboBox->currentIndex(); if (meanCurvatureColumn == GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NEW) { meanCurvatureColumn = BrainModelSurfaceCurvature::CURVATURE_COLUMN_CREATE_NEW; } else if (meanCurvatureColumn == GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NONE) { meanCurvatureColumn = BrainModelSurfaceCurvature::CURVATURE_COLUMN_DO_NOT_GENERATE; } const QString meanCurvatureName(meanCurvatureNameLineEdit->text()); if (meanCurvatureColumn != BrainModelSurfaceCurvature::CURVATURE_COLUMN_DO_NOT_GENERATE) { if (meanCurvatureName.isEmpty()) { QMessageBox::critical(this, "Error", "Name for mean curvature must be provided."); return; } } // // Get gaussian curvature selections // int gaussianCurvatureColumn = gaussianCurvatureColumnComboBox->currentIndex(); if (gaussianCurvatureColumn == GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NEW) { gaussianCurvatureColumn = BrainModelSurfaceCurvature::CURVATURE_COLUMN_CREATE_NEW; } else if (gaussianCurvatureColumn == GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NONE) { gaussianCurvatureColumn = BrainModelSurfaceCurvature::CURVATURE_COLUMN_DO_NOT_GENERATE; } const QString gaussianCurvatureName(gaussianCurvatureNameLineEdit->text()); if (gaussianCurvatureColumn != BrainModelSurfaceCurvature::CURVATURE_COLUMN_DO_NOT_GENERATE) { if (gaussianCurvatureName.isEmpty()) { QMessageBox::critical(this, "Error", "Name for gaussian curvature must be provided."); return; } } // // Make sure at least one curvature is being generated // if ((meanCurvatureColumn == BrainModelSurfaceCurvature::CURVATURE_COLUMN_DO_NOT_GENERATE) && (gaussianCurvatureColumn == BrainModelSurfaceCurvature::CURVATURE_COLUMN_DO_NOT_GENERATE)) { QMessageBox::critical(this, "Error", "No shape file columns selected"); return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); try { // // Generate curvature // BrainModelSurfaceCurvature bmsc(theMainWindow->getBrainSet(), bms, theMainWindow->getBrainSet()->getSurfaceShapeFile(), meanCurvatureColumn, gaussianCurvatureColumn, meanCurvatureName, gaussianCurvatureName); bmsc.execute(); // // Update surface shape related items and redraw // GuiFilesModified fm; fm.setSurfaceShapeModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "Error", e.whatQString()); return; } QApplication::restoreOverrideCursor(); } QDialog::done(r); } caret-5.6.4~dfsg.1.orig/caret/GuiGenerateSulcalDepthDialog.h0000664000175000017500000000472711572067322023512 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_GENERATE_SULCAL_DEPTH_DIALOG_H__ #define __GUI_GENERATE_SULCAL_DEPTH_DIALOG_H__ #include "WuQDialog.h" class GuiBrainModelSelectionComboBox; class GuiNodeAttributeColumnSelectionComboBox; class QCheckBox; class QLineEdit; class QSpinBox; /// Class for dialog that generates sulcal depth class GuiGenerateSulcalDepthDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiGenerateSulcalDepthDialog(QWidget* parent); /// Destructor ~GuiGenerateSulcalDepthDialog(); private slots: /// called when Ok or Cancel button pressed void done(int r); /// called when hull file select button is pressed void slotHullButton(); private: /// surface combo box GuiBrainModelSelectionComboBox* surfaceComboBox; /// depth column combo box GuiNodeAttributeColumnSelectionComboBox* depthColumnComboBox; /// depth name line edit QLineEdit* depthNameLineEdit; /// smoothed depth column combo box GuiNodeAttributeColumnSelectionComboBox* smoothDepthColumnComboBox; /// smoothed depth name line edit QLineEdit* smoothDepthNameLineEdit; /// hull file name line edit QLineEdit* hullFileNameLineEdit; /// hull smoothing iterations QSpinBox* hullSmoothingSpinBox; /// depth smoothing iterations QSpinBox* depthSmoothingSpinBox; /// create hull surface check box QCheckBox* createHullSurfaceCheckBox; }; #endif // __GUI_GENERATE_SULCAL_DEPTH_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiGenerateSulcalDepthDialog.cxx0000664000175000017500000003144411572067322024061 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "WuQFileDialog.h" #include #include #include #include #include #include #include #include #include #include "BrainModelSurfaceSulcalDepthWithNormals.h" #include "BrainSet.h" #include "FileFilters.h" #include "GuiBrainModelOpenGL.h" #include "GuiBrainModelSelectionComboBox.h" #include "GuiFilesModified.h" #include "GuiGenerateSulcalDepthDialog.h" #include "GuiMainWindow.h" #include "GuiNodeAttributeColumnSelectionComboBox.h" #include "QtUtilities.h" #include "SurfaceShapeFile.h" #include "global_variables.h" /** * Constructor */ GuiGenerateSulcalDepthDialog::GuiGenerateSulcalDepthDialog(QWidget* parent) : WuQDialog(parent) { setModal(true); setWindowTitle("Generate Sulcal Depth"); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // surface group box // QGroupBox* surfaceGroupBox = new QGroupBox("Fiducial Surface"); dialogLayout->addWidget(surfaceGroupBox); QVBoxLayout* surfaceGroupBoxLayout = new QVBoxLayout(surfaceGroupBox); // // Fiducial Surface comb box // surfaceComboBox = new GuiBrainModelSelectionComboBox( false, true, false, "", 0); surfaceComboBox->setSelectedBrainModel(theMainWindow->getBrainModelSurface()); surfaceGroupBoxLayout->addWidget(surfaceComboBox); // // Horizontal group box for hull surface selection // QGroupBox* hullGroupBox = new QGroupBox("Hull File"); dialogLayout->addWidget(hullGroupBox); QVBoxLayout* hullGroupLayout = new QVBoxLayout(hullGroupBox); // // Horiz layout for hull selection // QHBoxLayout* hullHBoxLayout = new QHBoxLayout; hullGroupLayout->addLayout(hullHBoxLayout); // // Button to select hull file // QPushButton* hullButton = new QPushButton("VTK Select..."); QObject::connect(hullButton, SIGNAL(clicked()), this, SLOT(slotHullButton())); hullButton->setFixedSize(hullButton->sizeHint()); hullHBoxLayout->addWidget(hullButton); // // hull file name line edit // hullFileNameLineEdit = new QLineEdit(hullGroupBox); hullFileNameLineEdit->setReadOnly(true); hullFileNameLineEdit->setText(theMainWindow->getBrainSet()->getCerebralHullFileName()); hullHBoxLayout->addWidget(hullFileNameLineEdit); // // Checkbox for create hull surface // createHullSurfaceCheckBox = new QCheckBox("Create Hull Surface"); createHullSurfaceCheckBox->setChecked(true); hullGroupLayout->addWidget(createHullSurfaceCheckBox); createHullSurfaceCheckBox->setToolTip( "Create a hull surface with the same number\n" "number of nodes as surface in main window."); // // Group Box for line edits and combo boxes // QGroupBox* groupBox = new QGroupBox("Surface Shape Columns"); QGridLayout* groupBoxGridLayout = new QGridLayout(groupBox); dialogLayout->addWidget(groupBox); // // Depth Name line edit // depthNameLineEdit = new QLineEdit; depthNameLineEdit->setText("Depth"); groupBoxGridLayout->addWidget(depthNameLineEdit, 0, 0); // // depth column combo box // depthColumnComboBox = new GuiNodeAttributeColumnSelectionComboBox( GUI_NODE_FILE_TYPE_SURFACE_SHAPE, true, true, false); depthColumnComboBox->setCurrentIndex( GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NEW); groupBoxGridLayout->addWidget(depthColumnComboBox, 0, 1); // // smooth depth Name line edit // smoothDepthNameLineEdit = new QLineEdit; smoothDepthNameLineEdit->setText("Smoothed Depth"); groupBoxGridLayout->addWidget(smoothDepthNameLineEdit, 1, 0); // // smoothed depth column combo box // smoothDepthColumnComboBox = new GuiNodeAttributeColumnSelectionComboBox( GUI_NODE_FILE_TYPE_SURFACE_SHAPE, true, true, false); smoothDepthColumnComboBox->setCurrentIndex( GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NEW); groupBoxGridLayout->addWidget(smoothDepthColumnComboBox, 1, 1); // // Group Box for smoothing spin boxes // QGroupBox* smoothingGroupBox = new QGroupBox("Smoothing"); dialogLayout->addWidget(smoothingGroupBox); QGridLayout* smoothingGroupLayout = new QGridLayout(smoothingGroupBox); // // hull smoothing // smoothingGroupLayout->addWidget(new QLabel("Hull Smoothing Iterations"), 0, 0); hullSmoothingSpinBox = new QSpinBox; hullSmoothingSpinBox->setMinimum(0); hullSmoothingSpinBox->setMaximum(100000); hullSmoothingSpinBox->setSingleStep(10); hullSmoothingSpinBox->setValue(5); smoothingGroupLayout->addWidget(hullSmoothingSpinBox, 0, 1); // // depth smoothing // smoothingGroupLayout->addWidget(new QLabel("Depth Smoothing Iterations"), 1, 0); depthSmoothingSpinBox = new QSpinBox; depthSmoothingSpinBox->setMinimum(0); depthSmoothingSpinBox->setMaximum(100000); depthSmoothingSpinBox->setSingleStep(10); depthSmoothingSpinBox->setValue(100); smoothingGroupLayout->addWidget(depthSmoothingSpinBox, 1, 1); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); dialogLayout->addLayout(buttonsLayout); // // OK button // QPushButton* okButton = new QPushButton("OK"); buttonsLayout->addWidget(okButton); QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); // // Cancel button // QPushButton* cancelButton = new QPushButton("Cancel"); buttonsLayout->addWidget(cancelButton); QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); QtUtilities::makeButtonsSameSize(okButton, cancelButton); } /** * called when hull file select button is pressed */ void GuiGenerateSulcalDepthDialog::slotHullButton() { WuQFileDialog fd(this); fd.setModal(true); fd.setDirectory(QDir::currentPath()); fd.setAcceptMode(WuQFileDialog::AcceptOpen); fd.setFileMode(WuQFileDialog::ExistingFile); fd.setFilter(FileFilters::getVtkSurfaceFileFilter()); fd.selectFilter(FileFilters::getVtkSurfaceFileFilter()); fd.setWindowTitle("Select VTK Poly Data File"); if (fd.exec() == QDialog::Accepted) { if (fd.selectedFiles().count() > 0) { hullFileNameLineEdit->setText(fd.selectedFiles().at(0)); } } } /** * Destructor */ GuiGenerateSulcalDepthDialog::~GuiGenerateSulcalDepthDialog() { } /** * Called when OK or Cancel button pressed. */ void GuiGenerateSulcalDepthDialog::done(int r) { if (r == QDialog::Accepted) { // // Get the surface for depth calculation // BrainModelSurface* bms = surfaceComboBox->getSelectedBrainModelSurface(); if (bms == NULL) { QMessageBox::critical(this, "Error", "A surface must be selected."); return; } // // Get the vtk file name // const QString vtkFileName(hullFileNameLineEdit->text()); if (vtkFileName.isEmpty()) { QMessageBox::critical(this, "Error", "VTK file name is missing."); return; } // // Get depth selections // int depthColumn = depthColumnComboBox->currentIndex(); if (depthColumn == GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NEW) { depthColumn = BrainModelSurfaceSulcalDepthWithNormals::DEPTH_COLUMN_CREATE_NEW; } else if (depthColumn == GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NONE) { depthColumn = BrainModelSurfaceSulcalDepthWithNormals::DEPTH_COLUMN_DO_NOT_GENERATE; } const QString depthName(depthNameLineEdit->text()); if (depthColumn != BrainModelSurfaceSulcalDepthWithNormals::DEPTH_COLUMN_DO_NOT_GENERATE) { if (depthName.isEmpty()) { QMessageBox::critical(this, "Error", "Name for depth must be provided."); return; } } // // Get smoothed depth selections // int smoothDepthColumn = smoothDepthColumnComboBox->currentIndex(); if (smoothDepthColumn == GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NEW) { smoothDepthColumn = BrainModelSurfaceSulcalDepthWithNormals::DEPTH_COLUMN_CREATE_NEW; } else if (smoothDepthColumn == GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NONE) { smoothDepthColumn = BrainModelSurfaceSulcalDepthWithNormals::DEPTH_COLUMN_DO_NOT_GENERATE; } const QString smoothDepthName(smoothDepthNameLineEdit->text()); if (smoothDepthColumn != BrainModelSurfaceSulcalDepthWithNormals::DEPTH_COLUMN_DO_NOT_GENERATE) { if (smoothDepthName.isEmpty()) { QMessageBox::critical(this, "Error", "Name for smoothed depth must be provided."); return; } } // // Make sure at least one depth is being generated // if ((depthColumn == BrainModelSurfaceSulcalDepthWithNormals::DEPTH_COLUMN_DO_NOT_GENERATE) && (smoothDepthColumn == BrainModelSurfaceSulcalDepthWithNormals::DEPTH_COLUMN_DO_NOT_GENERATE)) { QMessageBox::critical(this, "Error", "No shape file columns selected"); return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); // // Hull surface // BrainModelSurface* hullSurface = NULL; CoordinateFile* hullCoord = NULL; if (theMainWindow->getBrainModelSurface()) { hullSurface = new BrainModelSurface(*theMainWindow->getBrainModelSurface()); hullSurface->setSurfaceType(BrainModelSurface::SURFACE_TYPE_UNKNOWN); hullCoord = hullSurface->getCoordinateFile(); hullCoord->makeDefaultFileName("CerebralHull"); theMainWindow->getBrainSet()->addBrainModel(hullSurface); } try { // // Generate sulcal depth // BrainModelSurfaceSulcalDepthWithNormals bmssd(theMainWindow->getBrainSet(), bms, vtkFileName, theMainWindow->getBrainSet()->getSurfaceShapeFile(), hullSmoothingSpinBox->value(), depthSmoothingSpinBox->value(), depthColumn, smoothDepthColumn, depthName, smoothDepthName, hullCoord); bmssd.execute(); // // Update surface shape related items and redraw // GuiFilesModified fm; fm.setSurfaceShapeModified(); fm.setCoordinateModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "Error", e.whatQString()); return; } QApplication::restoreOverrideCursor(); } QDialog::done(r); } caret-5.6.4~dfsg.1.orig/caret/GuiGenerateArealEstimationDialog.h0000664000175000017500000000544511572067322024361 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_GENERATE_AREAL_ESTIMATION_DIALOG_H__ #define __GUI_GENERATE_AREAL_ESTIMATION_DIALOG_H__ #include "WuQDialog.h" class QRadioButton; class QLineEdit; class QTextEdit; class QDoubleSpinBox; class GuiNodeAttributeColumnSelectionComboBox; /// dialog for creating areal estimation files class GuiGenerateArealEstimationDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiGenerateArealEstimationDialog(QWidget* parent); /// Destructor ~GuiGenerateArealEstimationDialog(); public slots: /// called when OK or Cancel button pressed void done(int r); /// called when paint name select button pressed void slotPaintNamePushButton(); /// called when an areal estimation file column is selected void slotArealEstComboBox(int item); private: /// areal estimation file column selection GuiNodeAttributeColumnSelectionComboBox* arealEstColumnComboBox; /// areal estimation column name line edit QLineEdit* arealEstColumnNameLineEdit; /// all nodes radio button QRadioButton* nodesAllRadioButton; /// restrict nodes radio button QRadioButton* nodesRestrictRadioButton; /// paint column combo box GuiNodeAttributeColumnSelectionComboBox* paintTypeComboBox; /// paint name line edit QLineEdit* paintNameLineEdit; /// border file uncertainty radio button QRadioButton* borderFileUncertaintyRadioButton; /// border uncertainty override radio button QRadioButton* borderOverrideUncertaintyRadioButton; /// border override float spin box QDoubleSpinBox* borderOverrideDoubleSpinBox; /// long name line edit QLineEdit* longNameLineEdit; /// comment text edit QTextEdit* commentTextEdit; }; #endif // __GUI_GENERATE_AREAL_ESTIMATION_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiGenerateArealEstimationDialog.cxx0000664000175000017500000002720311572067322024730 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include "ArealEstimationFile.h" #include "BorderFile.h" #include "BorderUncertaintyToArealEstimationConverter.h" #include "BrainModelBorderSet.h" #include "BrainSet.h" #include "GuiFilesModified.h" #include "GuiGenerateArealEstimationDialog.h" #include "GuiMainWindow.h" #include "GuiNodeAttributeColumnSelectionComboBox.h" #include "GuiPaintColumnNamesListBoxSelectionDialog.h" #include "PaintFile.h" #include #include "QtListBoxSelectionDialog.h" #include "QtUtilities.h" #include "global_variables.h" /** * Constructor */ GuiGenerateArealEstimationDialog::GuiGenerateArealEstimationDialog(QWidget* parent) : WuQDialog(parent) { setModal(true); setWindowTitle("Create Areal Estimation File"); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // Groupbox for areal estimation file // QGroupBox* arealEstGroupBox = new QGroupBox("Areal Estimation File Column"); dialogLayout->addWidget(arealEstGroupBox); QHBoxLayout* arealEstGroupLayout = new QHBoxLayout(arealEstGroupBox); // // column selection, and column name line edit // arealEstColumnComboBox = new GuiNodeAttributeColumnSelectionComboBox( GUI_NODE_FILE_TYPE_AREAL_ESTIMATION, true, false, false); QObject::connect(arealEstColumnComboBox, SIGNAL(itemSelected(int)), this, SLOT(slotArealEstComboBox(int))); arealEstColumnNameLineEdit = new QLineEdit(arealEstGroupBox); slotArealEstComboBox(arealEstColumnComboBox->currentIndex()); arealEstGroupLayout->addWidget(arealEstColumnComboBox); arealEstGroupLayout->addWidget(arealEstColumnNameLineEdit); // // Groupbox for node selection // QGroupBox* nodeGroupBox = new QGroupBox("Node Selection"); dialogLayout->addWidget(nodeGroupBox); QVBoxLayout* nodeGroupLayout = new QVBoxLayout(nodeGroupBox); // // Button group for node selection // QButtonGroup* nodesButtonGroup = new QButtonGroup(this); // // Apply to all nodes radio button // nodesAllRadioButton = new QRadioButton("Apply to All Nodes"); nodesButtonGroup->addButton(nodesAllRadioButton); nodeGroupLayout->addWidget(nodesAllRadioButton); // // Restrict to nodes button group // nodesRestrictRadioButton = new QRadioButton("Restrict to Nodes With:"); nodesButtonGroup->addButton(nodesRestrictRadioButton); nodeGroupLayout->addWidget(nodesRestrictRadioButton); // // Grid for paint selection // QGridLayout* paintGridLayout = new QGridLayout; nodeGroupLayout->addLayout(paintGridLayout); // // paint type label and combo box // paintGridLayout->addWidget(new QLabel("Paint Type"), 0, 0); paintTypeComboBox = new GuiNodeAttributeColumnSelectionComboBox( GUI_NODE_FILE_TYPE_PAINT, false, false, false); paintGridLayout->addWidget(paintTypeComboBox, 0, 1); // // paint name label, line edit, and push button // paintGridLayout->addWidget(new QLabel("Paint Name"), 1, 0); paintNameLineEdit = new QLineEdit; paintGridLayout->addWidget(paintNameLineEdit, 1, 1); QPushButton* paintNamePushButton = new QPushButton("Select..."); paintGridLayout->addWidget(paintNamePushButton); paintNamePushButton->setAutoDefault(false); QObject::connect(paintNamePushButton, SIGNAL(clicked()), this, SLOT(slotPaintNamePushButton())); // // Groupbox for border uncertainty // QGroupBox* borderGroupBox = new QGroupBox("Border Uncertainty Source"); dialogLayout->addWidget(borderGroupBox); QVBoxLayout* borderGroupLayout = new QVBoxLayout(borderGroupBox); // // Button group for uncertainty selection // QButtonGroup* undertaintyButtonGroup = new QButtonGroup(this); // // border file uncertainty label // borderFileUncertaintyRadioButton = new QRadioButton("Border File"); undertaintyButtonGroup->addButton(borderFileUncertaintyRadioButton); borderGroupLayout->addWidget(borderFileUncertaintyRadioButton); // // border file override label and spin box // QHBoxLayout* overrideLayout = new QHBoxLayout; borderGroupLayout->addLayout(overrideLayout); borderOverrideUncertaintyRadioButton = new QRadioButton("Override "); overrideLayout->addWidget(borderOverrideUncertaintyRadioButton); undertaintyButtonGroup->addButton(borderOverrideUncertaintyRadioButton); borderOverrideDoubleSpinBox = new QDoubleSpinBox; borderOverrideDoubleSpinBox->setMinimum(0.001); borderOverrideDoubleSpinBox->setMaximum(10000.0); borderOverrideDoubleSpinBox->setSingleStep(1.0); borderOverrideDoubleSpinBox->setDecimals(2); overrideLayout->addWidget(borderOverrideDoubleSpinBox); borderOverrideDoubleSpinBox->setValue(4.0); // // Naming group box // QGroupBox* namingGroupBox = new QGroupBox("Naming"); dialogLayout->addWidget(namingGroupBox); QGridLayout* namingGroupLayout = new QGridLayout(namingGroupBox); // // long name label and line edit // namingGroupLayout->addWidget(new QLabel("Long Name"), 0, 0); longNameLineEdit = new QLineEdit(namingGroupBox); namingGroupLayout->addWidget(longNameLineEdit, 0, 1); // // comment label and text box // namingGroupLayout->addWidget(new QLabel("Comment"), 1, 0); commentTextEdit = new QTextEdit(namingGroupBox); namingGroupLayout->addWidget(commentTextEdit, 1, 1); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); dialogLayout->addLayout(buttonsLayout); // // OK button // QPushButton* okButton = new QPushButton("OK"); buttonsLayout->addWidget(okButton); QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); // // Cancel button // QPushButton* cancelButton = new QPushButton("Cancel"); buttonsLayout->addWidget(cancelButton); QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); QtUtilities::makeButtonsSameSize(okButton, cancelButton); } /** * Destructor */ GuiGenerateArealEstimationDialog::~GuiGenerateArealEstimationDialog() { } /** * */ void GuiGenerateArealEstimationDialog::slotArealEstComboBox(int item) { ArealEstimationFile* aef = theMainWindow->getBrainSet()->getArealEstimationFile(); QString name("New Column Name"); if ((item >= 0) && (item < aef->getNumberOfColumns())) { name = aef->getColumnName(item); } arealEstColumnNameLineEdit->setText(name); } /** * called when paint name select button pressed. */ void GuiGenerateArealEstimationDialog::slotPaintNamePushButton() { const int column = paintTypeComboBox->currentIndex(); PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); if ((column >= 0) && (column < pf->getNumberOfColumns())) { GuiPaintColumnNamesListBoxSelectionDialog pnd(this, column); if (pnd.exec() == QDialog::Accepted) { paintNameLineEdit->setText(pnd.getSelectedText()); } } else { QMessageBox::critical(this, "ERROR", "Invalid paint column"); } } /** * called when OK or Cancel button pressed. */ void GuiGenerateArealEstimationDialog::done(int r) { // // Was the OK button pressed ? // if (r == QDialog::Accepted) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms == NULL) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", "There is no surface in the main window."); return; } BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); BorderFile borderFile; bmbs->copyBordersToBorderFile(bms, borderFile); if (borderFile.getNumberOfBorders() <= 0) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", "There are no borders on the main window surface."); return; } if ((borderFileUncertaintyRadioButton->isChecked() == false) && (borderOverrideUncertaintyRadioButton->isChecked() == false)) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", "You must select a border uncertainty source."); return; } if ((nodesAllRadioButton->isChecked() == false) && (nodesRestrictRadioButton->isChecked() == false)) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", "You must make a node selection."); return; } BorderUncertaintyToArealEstimationConverter::MODE mode = BorderUncertaintyToArealEstimationConverter::MODE_ALL_NODES; if (nodesRestrictRadioButton->isChecked()) { mode = BorderUncertaintyToArealEstimationConverter::MODE_NODES_WITH_PAINT; } BorderUncertaintyToArealEstimationConverter aec( theMainWindow->getBrainSet(), bms, theMainWindow->getBrainSet()->getArealEstimationFile(), &borderFile, theMainWindow->getBrainSet()->getPaintFile(), mode, arealEstColumnComboBox->currentIndex(), arealEstColumnNameLineEdit->text(), longNameLineEdit->text(), commentTextEdit->toPlainText(), paintTypeComboBox->currentIndex(), paintNameLineEdit->text(), borderOverrideUncertaintyRadioButton->isChecked(), borderOverrideDoubleSpinBox->value()); try { aec.execute(); GuiFilesModified fm; fm.setArealEstimationModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); return; } QApplication::restoreOverrideCursor(); } QDialog::done(r); } caret-5.6.4~dfsg.1.orig/caret/GuiFociUncertaintyLimitsDialog.h0000664000175000017500000000664211572067322024115 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_GUI_FOCI_UNCERTAINTY_LIMITS_DIALOG_H__ #define __VE_GUI_FOCI_UNCERTAINTY_LIMITS_DIALOG_H__ #include "WuQDialog.h" class GuiBrainModelSelectionComboBox; class GuiNodeAttributeColumnSelectionComboBox; class QDoubleSpinBox; class QGroupBox; class QLineEdit; /// This dialog creates an RGB Paint file from foci proximities to surface. class GuiFociUncertaintyLimitsDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiFociUncertaintyLimitsDialog(QWidget* parent); /// Destructor ~GuiFociUncertaintyLimitsDialog(); private: /// called when OK or Cancel button pressed void done(int r); /// create the left surface widgets QGroupBox* createLeftSurfaceWidgets(); /// create the right surface widgets QGroupBox* createRightSurfaceWidgets(); /// create the limits widgets QWidget* createLimitsWidgets(); /// group box for right surface QGroupBox* rightSurfaceGroupBox; /// group box for left surface QGroupBox* leftSurfaceGroupBox; /// left surface combo box GuiBrainModelSelectionComboBox* leftSurfaceComboBox; /// right surface combo box GuiBrainModelSelectionComboBox* rightSurfaceComboBox; /// lower uncertainty limit QDoubleSpinBox* lowerLimitDoubleSpinBox; /// middle uncertainty limit QDoubleSpinBox* middleLimitDoubleSpinBox; /// upper uncertainty limit QDoubleSpinBox* upperLimitDoubleSpinBox; /// rgb paint left column new name QLineEdit* rgbPaintLeftColumnNewNameLineEdit; /// rgb paint right column new name QLineEdit* rgbPaintRightColumnNewNameLineEdit; /// rgb paint column selection combo box GuiNodeAttributeColumnSelectionComboBox* rgbPaintLeftSelectionComboBox; /// rgb paint column selection combo box GuiNodeAttributeColumnSelectionComboBox* rgbPaintRightSelectionComboBox; /// lower limit saved between dialogs static float lowerLimit; /// middle limit saved between dialogs static float middleLimit; /// upper limit saved between dialogs static float upperLimit; }; #ifdef __GUI_FOCI_UNCERTAINTY_DIALOG_MAIN__ float GuiFociUncertaintyLimitsDialog::lowerLimit = 0.0; float GuiFociUncertaintyLimitsDialog::middleLimit = 0.0; float GuiFociUncertaintyLimitsDialog::upperLimit = 10.0; #endif // __GUI_FOCI_UNCERTAINTY_DIALOG_MAIN__ #endif // __VE_GUI_FOCI_UNCERTAINTY_LIMITS_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiFociUncertaintyLimitsDialog.cxx0000664000175000017500000002754011572067322024470 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include "GuiBrainModelSelectionComboBox.h" #include "BrainModelSurfaceFociUncertaintyToRgbPaint.h" #include "BrainSet.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "GuiNodeAttributeColumnSelectionComboBox.h" #include "QtUtilities.h" #include "RgbPaintFile.h" #include "global_variables.h" #define __GUI_FOCI_UNCERTAINTY_DIALOG_MAIN__ #include "GuiFociUncertaintyLimitsDialog.h" #undef __GUI_FOCI_UNCERTAINTY_DIALOG_MAIN__ /** * Constructor. */ GuiFociUncertaintyLimitsDialog::GuiFociUncertaintyLimitsDialog(QWidget* parent) : WuQDialog(parent) { setModal(true); setWindowTitle("Uncertainty Limits to RGB Paint"); // // Create the surfaces and limits widgets // leftSurfaceGroupBox = createLeftSurfaceWidgets(); rightSurfaceGroupBox = createRightSurfaceWidgets(); QWidget* limitsWidget = createLimitsWidgets(); // // OK button // QPushButton* okButton = new QPushButton("OK", this); okButton->setAutoDefault(true); QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); // // Close button // QPushButton* cancelButton = new QPushButton("Cancel", this); cancelButton->setAutoDefault(false); QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); QtUtilities::makeButtonsSameSize(okButton, cancelButton); // // // Layout Dialog Buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->addWidget(okButton); buttonsLayout->addWidget(cancelButton); // // Layout dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->addWidget(leftSurfaceGroupBox); dialogLayout->addWidget(rightSurfaceGroupBox); dialogLayout->addWidget(limitsWidget); dialogLayout->addLayout(buttonsLayout); } /** * Destructor. */ GuiFociUncertaintyLimitsDialog::~GuiFociUncertaintyLimitsDialog() { } /** * create the limits widgets. */ QWidget* GuiFociUncertaintyLimitsDialog::createLimitsWidgets() { // // lower limit // QLabel* lowerLabel = new QLabel("Lower Limit (mm)"); lowerLimitDoubleSpinBox = new QDoubleSpinBox; lowerLimitDoubleSpinBox->setMinimum(0.0); lowerLimitDoubleSpinBox->setMaximum(std::numeric_limits::max()); lowerLimitDoubleSpinBox->setSingleStep(1.0); lowerLimitDoubleSpinBox->setDecimals(3); lowerLimitDoubleSpinBox->setValue(lowerLimit); // // middle limit // QLabel* middleLabel = new QLabel("Middle Limit (mm)"); middleLimitDoubleSpinBox = new QDoubleSpinBox; middleLimitDoubleSpinBox->setMinimum(0.0); middleLimitDoubleSpinBox->setMaximum(std::numeric_limits::max()); middleLimitDoubleSpinBox->setSingleStep(1.0); middleLimitDoubleSpinBox->setDecimals(3); middleLimitDoubleSpinBox->setValue(middleLimit); // // upper limit // QLabel* upperLabel = new QLabel("Upper Limit (mm)"); upperLimitDoubleSpinBox = new QDoubleSpinBox; upperLimitDoubleSpinBox->setMinimum(0.0); upperLimitDoubleSpinBox->setMaximum(std::numeric_limits::max()); upperLimitDoubleSpinBox->setSingleStep(1.0); upperLimitDoubleSpinBox->setDecimals(3); upperLimitDoubleSpinBox->setValue(upperLimit); // // Groupbox and layouts for limits // QGroupBox* limitsGroupBox = new QGroupBox("Foci Limits"); QGridLayout* limitsLayout = new QGridLayout(limitsGroupBox); limitsLayout->addWidget(lowerLabel, 0, 0); limitsLayout->addWidget(lowerLimitDoubleSpinBox, 0, 1); limitsLayout->addWidget(middleLabel, 1, 0); limitsLayout->addWidget(middleLimitDoubleSpinBox, 1, 1); limitsLayout->addWidget(upperLabel, 2, 0); limitsLayout->addWidget(upperLimitDoubleSpinBox, 2, 1); limitsLayout->setColumnStretch(0, 0); limitsLayout->setColumnStretch(1, 0); limitsLayout->setColumnStretch(1, 100); return limitsGroupBox; } /** * create the left surface widgets. */ QGroupBox* GuiFociUncertaintyLimitsDialog::createLeftSurfaceWidgets() { // // Surface selection // QLabel* surfaceLabel = new QLabel("Left Surface"); leftSurfaceComboBox = new GuiBrainModelSelectionComboBox( GuiBrainModelSelectionComboBox::OPTION_SHOW_SURFACES_ALL | GuiBrainModelSelectionComboBox::OPTION_SHOW_ADD_NEW, "NONE"); leftSurfaceComboBox->setSelectedBrainModelToFirstSurfaceOfType( BrainModelSurface::SURFACE_TYPE_FIDUCIAL, Structure::STRUCTURE_TYPE_CORTEX_LEFT); // // RGB Label and column selection // QLabel* rgbLabel = new QLabel("RGB Paint Column"); rgbPaintLeftSelectionComboBox = new GuiNodeAttributeColumnSelectionComboBox( GUI_NODE_FILE_TYPE_RGB_PAINT, true, false, false); const QString columnName("Left Foci Uncertainty"); rgbPaintLeftColumnNewNameLineEdit = new QLineEdit; rgbPaintLeftColumnNewNameLineEdit->setText(columnName); // // Initialize RGB Paint column selection // rgbPaintLeftSelectionComboBox->setCurrentIndex(rgbPaintLeftSelectionComboBox->count() - 1); for (int i = 0; i < rgbPaintLeftSelectionComboBox->count(); i++) { if (rgbPaintLeftSelectionComboBox->itemText(i) == columnName) { rgbPaintLeftSelectionComboBox->setCurrentIndex(i); break; } } rgbPaintLeftColumnNewNameLineEdit->setText(rgbPaintLeftSelectionComboBox->currentText()); QObject::connect(rgbPaintLeftSelectionComboBox, SIGNAL(activated(const QString&)), rgbPaintLeftColumnNewNameLineEdit, SLOT(setText(const QString&))); // // Group box and layout for left surface // QGroupBox* groupBox = new QGroupBox("Left Surface"); QGridLayout* leftLayout = new QGridLayout(groupBox); leftLayout->addWidget(surfaceLabel, 0, 0); leftLayout->addWidget(leftSurfaceComboBox, 0, 1, 1, 2); leftLayout->addWidget(rgbLabel, 1, 0); leftLayout->addWidget(rgbPaintLeftSelectionComboBox, 1, 1); leftLayout->addWidget(rgbPaintLeftColumnNewNameLineEdit, 1, 2); groupBox->setCheckable(true); groupBox->setChecked(true); return groupBox; } /** * create the right surface widgets. */ QGroupBox* GuiFociUncertaintyLimitsDialog::createRightSurfaceWidgets() { // // Surface selection // QLabel* surfaceLabel = new QLabel("Right Surface"); rightSurfaceComboBox = new GuiBrainModelSelectionComboBox( GuiBrainModelSelectionComboBox::OPTION_SHOW_SURFACES_ALL | GuiBrainModelSelectionComboBox::OPTION_SHOW_ADD_NEW, "NONE"); rightSurfaceComboBox->setSelectedBrainModelToFirstSurfaceOfType( BrainModelSurface::SURFACE_TYPE_FIDUCIAL, Structure::STRUCTURE_TYPE_CORTEX_RIGHT); // // RGB Label and column selection // QLabel* rgbLabel = new QLabel("RGB Paint Column"); rgbPaintRightSelectionComboBox = new GuiNodeAttributeColumnSelectionComboBox( GUI_NODE_FILE_TYPE_RGB_PAINT, true, false, false); const QString columnName("Right Foci Uncertainty"); rgbPaintRightColumnNewNameLineEdit = new QLineEdit; rgbPaintRightColumnNewNameLineEdit->setText(columnName); // // Initialize RGB Paint column selection // rgbPaintRightSelectionComboBox->setCurrentIndex(rgbPaintRightSelectionComboBox->count() - 1); for (int i = 0; i < rgbPaintRightSelectionComboBox->count(); i++) { if (rgbPaintRightSelectionComboBox->itemText(i) == columnName) { rgbPaintRightSelectionComboBox->setCurrentIndex(i); break; } } rgbPaintRightColumnNewNameLineEdit->setText(rgbPaintRightSelectionComboBox->currentText()); QObject::connect(rgbPaintRightSelectionComboBox, SIGNAL(activated(const QString&)), rgbPaintRightColumnNewNameLineEdit, SLOT(setText(const QString&))); // // Group box and layout for right surface // QGroupBox* groupBox = new QGroupBox("Right Surface"); QGridLayout* rightLayout = new QGridLayout(groupBox); rightLayout->addWidget(surfaceLabel, 0, 0); rightLayout->addWidget(rightSurfaceComboBox, 0, 1, 1, 2); rightLayout->addWidget(rgbLabel, 1, 0); rightLayout->addWidget(rgbPaintRightSelectionComboBox, 1, 1); rightLayout->addWidget(rgbPaintRightColumnNewNameLineEdit, 1, 2); groupBox->setCheckable(true); groupBox->setChecked(true); return groupBox; } /** * Called when OK or cancelbutton pressed. */ void GuiFociUncertaintyLimitsDialog::done(int r) { QTime timer; timer.start(); if (r == GuiFociUncertaintyLimitsDialog::Accepted) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainSet* brainSet = theMainWindow->getBrainSet(); lowerLimit = lowerLimitDoubleSpinBox->value(); middleLimit = middleLimitDoubleSpinBox->value(); upperLimit = upperLimitDoubleSpinBox->value(); BrainModelSurface* leftSurface = NULL; if (leftSurfaceGroupBox->isChecked()) { leftSurface = leftSurfaceComboBox->getSelectedBrainModelSurface(); } BrainModelSurface* rightSurface = NULL; if (rightSurfaceGroupBox->isChecked()) { rightSurface = rightSurfaceComboBox->getSelectedBrainModelSurface(); } BrainModelSurfaceFociUncertaintyToRgbPaint furp(brainSet, leftSurface, rightSurface, brainSet->getRgbPaintFile(), rgbPaintLeftSelectionComboBox->currentIndex(), rgbPaintLeftColumnNewNameLineEdit->text(), rgbPaintRightSelectionComboBox->currentIndex(), rgbPaintRightColumnNewNameLineEdit->text(), brainSet->getFociProjectionFile(), brainSet->getFociColorFile(), lowerLimit, middleLimit, upperLimit); QString errorMessage; try { furp.execute(); } catch (BrainModelAlgorithmException& e) { errorMessage = e.whatQString(); } QApplication::restoreOverrideCursor(); GuiFilesModified fm; fm.setRgbPaintModified(); theMainWindow->fileModificationUpdate(fm); if (errorMessage.isEmpty() == false) { QMessageBox::critical(this, "Error", errorMessage); return; } } WuQDialog::done(r); //const float elapsedTime = (static_cast(timer.elapsed()) * 0.001); //std::cout << "Elapsed time: " << elapsedTime << std::endl; } caret-5.6.4~dfsg.1.orig/caret/GuiFociSearchWidget.h0000664000175000017500000001625111572067322021654 0ustar michaelmichael #ifndef __GUI_FOCI_SEARCH_WIDGET_H__ #define __GUI_FOCI_SEARCH_WIDGET_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "SceneFile.h" class FociProjectionFile; class FociSearchFile; class FociSearchSet; class GuiBrainModelSelectionComboBox; class QCheckBox; class QComboBox; class QGridLayout; class QLabel; class QLineEdit; class QScrollArea; class QSignalMapper; class QSpinBox; class QToolButton; class WuQWidgetGroup; /// class for searching foci widget class GuiFociSearchWidget : public QWidget { Q_OBJECT public: // constructor GuiFociSearchWidget(FociProjectionFile* fociProjectionFileIn, FociSearchFile* fociSearchFileIn, const bool useScrollAreaFlag, QWidget* parent = 0); // destructor ~GuiFociSearchWidget(); /// apply a scene (set display settings) void showScene(const SceneFile::Scene& scene, QString& errorMessage); /// create a scene (read display settings) SceneFile::SceneClass saveScene(); // update the widget void updateWidget(FociProjectionFile* fpf, FociSearchFile* fsf); protected slots: // called when search selection spin box value is changed void slotSearchSelectionSpinBox(int); // called when search all button pressed void slotSearchAllPushButton(); // called when search displayed button pressed void slotSearchDisplayedPushButton(); // called when reset button pressed void slotResetPushButton(); // called when insert search tool button pressed void slotInsertSearchToolButtonClicked(int); // called when delete search tool button pressed void slotDeleteSearchToolButtonClicked(int); // called when a search logic is changed void slotSearchLogicChanged(int); // called when a search attribute is changed void slotSearchAttributeChanged(int); // called when a search matching is changed void slotSearchMatchingChanged(int); // called when a search text is changed void slotSearchTextChanged(int); // called when an assistance tool button is clicked void slotAssistanceToolButtonClicked(int); // called when add search button pressed void slotAddSearchPushButton(); // called when delete search button pressed void slotDeleteSearchPushButton(); // called when copy search set button pressed void slotCopySearchSetPushButton(); // called when search number button pressed void slotSearchNumberPushButton(); // called when search name is changed void slotSearchNameLineEdit(const QString&); protected: // add a search set void addSearchSetToFociSearchFile(FociSearchSet* fss); // create the search operations group QWidget* createSearchOperationsGroup(); // create the search set group QWidget* createSearchSetGroup(); // create the search parameters group QWidget* createSearchParametersGroup(const bool useScrollAreaFlag); // create the search surfaces group //QWidget* createSearchSurfacesGroup(); // load the foci searches void loadFociSearches(); // get the selected search set FociSearchSet* getSelectedSearchSet(); // perform the search void performSearch(const bool searchDisplayedOnlyFlag); /// foci projection file that is to be searched FociProjectionFile* fociProjectionFile; /// foci search file FociSearchFile* fociSearchFile; /// search selection spin box QSpinBox* searchSelectionSpinBox; /// scroll area for search widgets QScrollArea* searchScrollArea; /// layout for searches QGridLayout* searchGridLayout; /// search name label QLabel* searchNameLabel; /// search name line edit QLineEdit* searchNameLineEdit; /// widget group for each search std::vector searchWidgetGroups; /// toolbuttons for inserting new searches std::vector insertSearchToolButtons; /// toolbuttons for deleting searches std::vector deleteSearchToolButtons; /// combo boxes for logic selection std::vector logicComboBoxes; /// combo boxes for attribute selection std::vector attributeComboBoxes; /// combo boxes for matching selection std::vector matchingComboBoxes; /// line edits for search text std::vector searchTextLineEdits; /// toolbuttons for assistance std::vector assistanceToolButtons; /// search results label QLabel* searchResultsLabel; /// show foci from matching studies check box QCheckBox* showFociFromMatchingStudiesCheckBox; /// signal mapper for insert search tool buttons QSignalMapper* insertSearchToolButtonSignalMapper; /// signal mapper for delete search tool buttons QSignalMapper* deleteSearchToolButtonSignalMapper; /// signal mapper for search logic combo boxes QSignalMapper* searchLogicComboBoxSignalMapper; /// signal mapper for search attribute combo boxes QSignalMapper* searchAttributeComboBoxSignalMapper; /// signal mapper for search matching combo boxes QSignalMapper* searchMatchingComboBoxSignalMapper; /// signal mapper for search line edit combo boxes QSignalMapper* searchTextLineEditSignalMapper; /// signal mapper for assistance buttons QSignalMapper* assistanceToolButtonSignalMapper; /// left surface selection combo box //GuiBrainModelSelectionComboBox* leftSurfaceSelectionComboBox; /// right surface selection combo box //GuiBrainModelSelectionComboBox* rightSurfaceSelectionComboBox; /// cerebellum surface selection combo box //GuiBrainModelSelectionComboBox* cerebellumSurfaceSelectionComboBox; }; #endif // __GUI_FOCI_SEARCH_WIDGET_H__ caret-5.6.4~dfsg.1.orig/caret/GuiFociSearchWidget.cxx0000664000175000017500000012362711572067322022235 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "BrainModelSurfaceFociSearch.h" #include "BrainSet.h" #include "DisplaySettingsFoci.h" #include "FociProjectionFile.h" #include "FociSearchFile.h" #include "GuiBrainModelOpenGL.h" #include "GuiBrainModelSelectionComboBox.h" #include "GuiFociSearchWidget.h" #include "GuiMainWindow.h" #include "GuiNameSelectionDialog.h" #include "StudyMetaDataFile.h" #include "WuQDataEntryDialog.h" #include "WuQWidgetGroup.h" #include "global_variables.h" /** * constructor. */ GuiFociSearchWidget::GuiFociSearchWidget(FociProjectionFile* fociProjectionFileIn, FociSearchFile* fociSearchFileIn, const bool useScrollAreaFlag, QWidget* parent) : QWidget(parent) { fociProjectionFile = fociProjectionFileIn; fociSearchFile = fociSearchFileIn; // // Create signal mappers // insertSearchToolButtonSignalMapper = new QSignalMapper(this); QObject::connect(insertSearchToolButtonSignalMapper, SIGNAL(mapped(int)), this, SLOT(slotInsertSearchToolButtonClicked(int))); deleteSearchToolButtonSignalMapper = new QSignalMapper(this); QObject::connect(deleteSearchToolButtonSignalMapper, SIGNAL(mapped(int)), this, SLOT(slotDeleteSearchToolButtonClicked(int))); searchLogicComboBoxSignalMapper = new QSignalMapper(this); QObject::connect(searchLogicComboBoxSignalMapper, SIGNAL(mapped(int)), this, SLOT(slotSearchLogicChanged(int))); searchAttributeComboBoxSignalMapper = new QSignalMapper(this); QObject::connect(searchAttributeComboBoxSignalMapper, SIGNAL(mapped(int)), this, SLOT(slotSearchAttributeChanged(int))); searchMatchingComboBoxSignalMapper = new QSignalMapper(this); QObject::connect(searchMatchingComboBoxSignalMapper, SIGNAL(mapped(int)), this, SLOT(slotSearchMatchingChanged(int))); searchTextLineEditSignalMapper = new QSignalMapper(this); QObject::connect(searchTextLineEditSignalMapper, SIGNAL(mapped(int)), this, SLOT(slotSearchTextChanged(int))); assistanceToolButtonSignalMapper = new QSignalMapper(this); QObject::connect(assistanceToolButtonSignalMapper, SIGNAL(mapped(int)), this, SLOT(slotAssistanceToolButtonClicked(int))); // // Create the widget groups // QWidget* searchSelectionWidget = createSearchSetGroup(); QWidget* searchOperationsWidget = createSearchOperationsGroup(); //QWidget* searchSurfacesWidget = createSearchSurfacesGroup(); QWidget* searchParametersWidget = createSearchParametersGroup(useScrollAreaFlag); // // Layout for this widget // QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(searchSelectionWidget); layout->addWidget(searchOperationsWidget); layout->addWidget(searchParametersWidget); //layout->addWidget(searchSurfacesWidget); layout->addStretch(); loadFociSearches(); } /** * destructor. */ GuiFociSearchWidget::~GuiFociSearchWidget() { } /** * create a scene (read display settings). */ SceneFile::SceneClass GuiFociSearchWidget::saveScene() { SceneFile::SceneClass sc("GuiFociSearchWidget"); if (searchNameLineEdit != NULL) { sc.addSceneInfo(SceneFile::SceneInfo("searchNameLineEdit", searchNameLineEdit->text())); } return sc; } /** * apply a scene (set display settings). */ void GuiFociSearchWidget::showScene(const SceneFile::Scene& scene, QString& /*errorMessage*/) { const int numClasses = scene.getNumberOfSceneClasses(); for (int nc = 0; nc < numClasses; nc++) { const SceneFile::SceneClass* sc = scene.getSceneClass(nc); if (sc->getName() == "GuiFociSearchWidget") { const int num = sc->getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc->getSceneInfo(i); const QString infoName = si->getName(); if (infoName == "searchNameLineEdit") { const QString searchName = si->getValueAsString(); const int numSearchSets = fociSearchFile->getNumberOfFociSearchSets(); for (int is = 0; is < numSearchSets; is++) { const FociSearchSet* fss = fociSearchFile->getFociSearchSet(is); if (fss->getName() == searchName) { searchSelectionSpinBox->setValue(is + 1); // indexes 1..N slotSearchSelectionSpinBox(searchSelectionSpinBox->value()); } } } } } } } /** * create the search operation group. */ QWidget* GuiFociSearchWidget::createSearchOperationsGroup() { // // Search All button // QPushButton* searchAllPushButton = new QPushButton("Search All"); searchAllPushButton->setFixedSize(searchAllPushButton->sizeHint()); searchAllPushButton->setAutoDefault(false); QObject::connect(searchAllPushButton, SIGNAL(clicked()), this, SLOT(slotSearchAllPushButton())); searchAllPushButton->setToolTip("Apply the search \n" "parameters to ALL foci."); // // Search Displayed button // QPushButton* searchDisplayedPushButton = new QPushButton("Search Displayed"); searchDisplayedPushButton->setFixedSize(searchDisplayedPushButton->sizeHint()); searchDisplayedPushButton->setAutoDefault(false); QObject::connect(searchDisplayedPushButton, SIGNAL(clicked()), this, SLOT(slotSearchDisplayedPushButton())); searchDisplayedPushButton->setToolTip("Apply the search parameters\n" "to DISPLAYED foci."); // // Reset button // QPushButton* resetPushButton = new QPushButton("Reset"); resetPushButton->setFixedSize(resetPushButton->sizeHint()); resetPushButton->setAutoDefault(false); QObject::connect(resetPushButton, SIGNAL(clicked()), this, SLOT(slotResetPushButton())); resetPushButton->setToolTip("Cease application of search \n" "parameters to the foci."); // // Buttons layout // QHBoxLayout* applySearchLayout = new QHBoxLayout; applySearchLayout->addWidget(searchAllPushButton); applySearchLayout->addWidget(searchDisplayedPushButton); applySearchLayout->addWidget(resetPushButton); applySearchLayout->addStretch(); // // Show foci in matching studies check box // showFociFromMatchingStudiesCheckBox = new QCheckBox("Show Foci From Matching Studies"); // // Search results label // searchResultsLabel = new QLabel(" "); // // Search options group box and layout // QGroupBox* searchOperationsGroupBox = new QGroupBox("Search Foci Operations"); QVBoxLayout* searchOperationsGroupLayout = new QVBoxLayout(searchOperationsGroupBox); searchOperationsGroupLayout->addLayout(applySearchLayout); searchOperationsGroupLayout->addWidget(showFociFromMatchingStudiesCheckBox); searchOperationsGroupLayout->addWidget(searchResultsLabel); return searchOperationsGroupBox; } /** * create the search set group. */ QWidget* GuiFociSearchWidget::createSearchSetGroup() { // // Search number pushbutton // QPushButton* searchNumberPushButton = new QPushButton("Search Number..."); searchNumberPushButton->setFixedSize(searchNumberPushButton->sizeHint()); searchNumberPushButton->setAutoDefault(false); QObject::connect(searchNumberPushButton, SIGNAL(clicked()), this, SLOT(slotSearchNumberPushButton())); // // Search number spin box // searchSelectionSpinBox = new QSpinBox; searchSelectionSpinBox->setSingleStep(1); QObject::connect(searchSelectionSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotSearchSelectionSpinBox(int))); // // Delete search button // QPushButton* deleteSearchPushButton = new QPushButton("Delete Selected Search Set"); deleteSearchPushButton->setAutoDefault(false); deleteSearchPushButton->setFixedSize(deleteSearchPushButton->sizeHint()); QObject::connect(deleteSearchPushButton, SIGNAL(clicked()), this, SLOT(slotDeleteSearchPushButton())); // // Add search button // QPushButton* addSearchPushButton = new QPushButton("Add New Search Set"); addSearchPushButton->setAutoDefault(false); addSearchPushButton->setFixedSize(addSearchPushButton->sizeHint()); QObject::connect(addSearchPushButton, SIGNAL(clicked()), this, SLOT(slotAddSearchPushButton())); // // Copy Search Set button // QPushButton* copySearchPushButton = new QPushButton("Copy Search Set"); copySearchPushButton->setAutoDefault(false); copySearchPushButton->setFixedSize(copySearchPushButton->sizeHint()); QObject::connect(copySearchPushButton, SIGNAL(clicked()), this, SLOT(slotCopySearchSetPushButton())); // // Layout // QHBoxLayout* searchSelectionLayout = new QHBoxLayout; searchSelectionLayout->addWidget(searchNumberPushButton); searchSelectionLayout->addWidget(searchSelectionSpinBox); searchSelectionLayout->addWidget(deleteSearchPushButton); searchSelectionLayout->addStretch(); // // Layout // QHBoxLayout* newSearchLayout = new QHBoxLayout; newSearchLayout->addWidget(addSearchPushButton); newSearchLayout->addWidget(copySearchPushButton); newSearchLayout->addStretch(); // // Search selection group box and layout // QGroupBox* searchSelectionGroupBox = new QGroupBox("Search Set Selection"); QVBoxLayout* searchSelectionGroupLayout = new QVBoxLayout(searchSelectionGroupBox); searchSelectionGroupLayout->addLayout(searchSelectionLayout); searchSelectionGroupLayout->addLayout(newSearchLayout); return searchSelectionGroupBox; } /** * create the search parameters group. */ QWidget* GuiFociSearchWidget::createSearchParametersGroup(const bool useScrollAreaFlag) { // // name of search line edit // searchNameLabel = new QLabel("Search Name "); searchNameLineEdit = new QLineEdit; QObject::connect(searchNameLineEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotSearchNameLineEdit(const QString&))); QHBoxLayout* searchNameLayout = new QHBoxLayout; searchNameLayout->addWidget(searchNameLabel); searchNameLayout->addWidget(searchNameLineEdit); searchNameLayout->setStretchFactor(searchNameLabel, 0); searchNameLayout->setStretchFactor(searchNameLineEdit, 100); // // Widget and layout for searches // QWidget* searchWidget = new QWidget; searchGridLayout = new QGridLayout(searchWidget); // // Set column stretching // searchGridLayout->setColumnStretch(0, 0); searchGridLayout->setColumnStretch(1, 0); searchGridLayout->setColumnStretch(2, 0); searchGridLayout->setColumnStretch(3, 0); searchGridLayout->setColumnStretch(4, 0); searchGridLayout->setColumnStretch(5, 0); searchGridLayout->setColumnStretch(6, 1000); // // Column Titles // searchGridLayout->addWidget(new QLabel("Logic"), 0, 3, Qt::AlignLeft); searchGridLayout->addWidget(new QLabel("Categories"), 0, 4, Qt::AlignLeft); searchGridLayout->addWidget(new QLabel("Matching"), 0, 5, Qt::AlignLeft); // // scroll view and layout for search lines // QWidget* theSearchWidget = searchWidget; searchScrollArea = NULL; if (useScrollAreaFlag) { searchScrollArea = new QScrollArea; searchScrollArea->setWidget(searchWidget); searchScrollArea->setWidgetResizable(true); theSearchWidget = searchScrollArea; } // // Widget and layout for searches // QGroupBox* searchParametersGroupBox = new QGroupBox("Search Parameters"); QVBoxLayout* searchParametersLayout = new QVBoxLayout(searchParametersGroupBox); searchParametersLayout->addLayout(searchNameLayout); searchParametersLayout->addWidget(theSearchWidget); //searchParametersLayout->addStretch(); return searchParametersGroupBox; } /** * create the search surfaces group. */ /* QWidget* GuiFociSearchWidget::createSearchSurfacesGroup() { // // Left surface selection // QLabel* leftLabel = new QLabel("Left"); leftSurfaceSelectionComboBox = new GuiBrainModelSelectionComboBox((GuiBrainModelSelectionComboBox::OPTION_SHOW_SURFACES_FIDUCIAL | GuiBrainModelSelectionComboBox::OPTION_SHOW_ADD_NEW), "None"); leftSurfaceSelectionComboBox->setSurfaceStructureRequirement( Structure::STRUCTURE_TYPE_CORTEX_LEFT); // // Left surface selection // QLabel* rightLabel = new QLabel("Right"); rightSurfaceSelectionComboBox = new GuiBrainModelSelectionComboBox((GuiBrainModelSelectionComboBox::OPTION_SHOW_SURFACES_FIDUCIAL | GuiBrainModelSelectionComboBox::OPTION_SHOW_ADD_NEW), "None"); rightSurfaceSelectionComboBox->setSurfaceStructureRequirement( Structure::STRUCTURE_TYPE_CORTEX_RIGHT); // // Cerebellum surface selection // QLabel* cerebellumLabel = new QLabel("Cerebellum"); cerebellumSurfaceSelectionComboBox = new GuiBrainModelSelectionComboBox((GuiBrainModelSelectionComboBox::OPTION_SHOW_SURFACES_FIDUCIAL | GuiBrainModelSelectionComboBox::OPTION_SHOW_ADD_NEW), "None"); cerebellumSurfaceSelectionComboBox->setSurfaceStructureRequirement( Structure::STRUCTURE_TYPE_CEREBELLUM); // // Widget and layout for searches // QGroupBox* searchSurfacesGroupBox = new QGroupBox("Spatial Search Surfaces"); QGridLayout* searchSurfacesGridLayout = new QGridLayout(searchSurfacesGroupBox); searchSurfacesGridLayout->addWidget(leftLabel, 0, 0); searchSurfacesGridLayout->addWidget(leftSurfaceSelectionComboBox, 0, 1); searchSurfacesGridLayout->addWidget(rightLabel, 1, 0); searchSurfacesGridLayout->addWidget(rightSurfaceSelectionComboBox, 1, 1); searchSurfacesGridLayout->addWidget(cerebellumLabel, 2, 0); searchSurfacesGridLayout->addWidget(cerebellumSurfaceSelectionComboBox, 2, 1); searchSurfacesGridLayout->setColumnStretch(0, 0); searchSurfacesGridLayout->setColumnStretch(1, 100); return searchSurfacesGroupBox; } */ /** * called when add search button pressed. */ void GuiFociSearchWidget::slotAddSearchPushButton() { FociSearchSet* fss = new FociSearchSet; addSearchSetToFociSearchFile(fss); } /** * add a search set. */ void GuiFociSearchWidget::addSearchSetToFociSearchFile(FociSearchSet* fss) { int selectedSearchNumber = 0; if (fociSearchFile->getNumberOfFociSearchSets() <= 0) { fociSearchFile->addFociSearchSet(fss); selectedSearchNumber = fociSearchFile->getNumberOfFociSearchSets(); } else { WuQDataEntryDialog ded(this); ded.setTextAtTop("Insert New Search: ", false); QRadioButton* beginningRadioButton = ded.addRadioButton("At Beginning"); QRadioButton* afterSelectedRadioButton = ded.addRadioButton("After Current"); QRadioButton* endRadioButton = ded.addRadioButton("At End"); endRadioButton->setChecked(true); if (ded.exec() == WuQDataEntryDialog::Accepted) { int afterIndex = 0; if (beginningRadioButton->isChecked()) { afterIndex = -1; selectedSearchNumber = 1; } else if (afterSelectedRadioButton->isChecked()) { afterIndex = searchSelectionSpinBox->value() - 1; selectedSearchNumber = afterIndex + 2; } else if (endRadioButton->isChecked()) { afterIndex = fociSearchFile->getNumberOfFociSearchSets(); selectedSearchNumber = afterIndex + 1; } fociSearchFile->insertFociSearchSet(fss, afterIndex); } else { delete fss; return; } } // // Note that "searchSelectionSpinBox" indexes 1..N // loadFociSearches(); searchSelectionSpinBox->setValue(selectedSearchNumber); slotSearchSelectionSpinBox(searchSelectionSpinBox->value()); } /** * called when delete search button pressed. */ void GuiFociSearchWidget::slotDeleteSearchPushButton() { // // Note that "searchSelectionSpinBox" indexes 1..N // const int searchNumber = searchSelectionSpinBox->value() - 1; if ((searchNumber >= 0) && (searchNumber < fociSearchFile->getNumberOfFociSearchSets())) { if (QMessageBox::question(this, "CONFIRM", "Delete current search set?", (QMessageBox::Ok | QMessageBox::Cancel)) == QMessageBox::Ok) { fociSearchFile->deleteFociSearchSet(searchNumber); } } loadFociSearches(); } /** * called when search number button pressed. */ void GuiFociSearchWidget::slotSearchNumberPushButton() { const int numSearchSets = fociSearchFile->getNumberOfFociSearchSets(); if (numSearchSets <= 0) { return; } // // Get the names of all of the search sets // QStringList searchSetNamesStringList; for (int i = 0; i < numSearchSets; i++) { const FociSearchSet* fss = fociSearchFile->getFociSearchSet(i); searchSetNamesStringList << fss->getName(); } // // Popup a dialog to allow the user to choose a search set // WuQDataEntryDialog ded(this); ded.setWindowTitle("Select Search Set"); QListWidget* lw = ded.addListWidget("", searchSetNamesStringList); if (ded.exec() == WuQDataEntryDialog::Accepted) { const int searchSetNumber = lw->currentRow(); // // Note that "searchSelectionSpinBox" indexes 1..N // searchSelectionSpinBox->setValue(searchSetNumber + 1); slotSearchSelectionSpinBox(searchSelectionSpinBox->value()); } } /** * called when copy search set button pressed. */ void GuiFociSearchWidget::slotCopySearchSetPushButton() { // // Copy search set // const int searchNumber = searchSelectionSpinBox->value() - 1; if ((searchNumber >= 0) && (searchNumber < fociSearchFile->getNumberOfFociSearchSets())) { const FociSearchSet* copySearchSet = fociSearchFile->getFociSearchSet(searchNumber); if (copySearchSet != NULL) { FociSearchSet* fss = new FociSearchSet(*copySearchSet); fss->setName("Copy of " + fss->getName()); addSearchSetToFociSearchFile(fss); } } } /** * update the widget. */ void GuiFociSearchWidget::updateWidget(FociProjectionFile* fpf, FociSearchFile* fsf) { fociProjectionFile = fpf; fociSearchFile = fsf; //leftSurfaceSelectionComboBox->updateComboBox(); //rightSurfaceSelectionComboBox->updateComboBox(); //cerebellumSurfaceSelectionComboBox->updateComboBox(); loadFociSearches(); } /** * called when search selection spin box value is changed. */ void GuiFociSearchWidget::slotSearchSelectionSpinBox(int) { loadFociSearches(); } /** * load the foci searches. */ void GuiFociSearchWidget::loadFociSearches() { // // Get active search // const FociSearchSet* fss = getSelectedSearchSet(); // // If no search sets, hide all searches // const int numSearchesInDialog = static_cast(searchWidgetGroups.size()); if (fss == NULL) { for (int i = 0; i < numSearchesInDialog; i++) { searchWidgetGroups[i]->setHidden(true); } searchNameLabel->setHidden(true); searchNameLineEdit->setHidden(true); return; } // // Set name // searchNameLineEdit->setText(fss->getName()); searchNameLineEdit->setHidden(false); searchNameLabel->setHidden(false); // // Get type and names for search controls // std::vector logicTypes; std::vector logicNames; FociSearch::getLogicTypesAndNames(logicTypes, logicNames); const int numLogicTypes = static_cast(logicTypes.size()); std::vector attributeTypes; std::vector attributeNames; FociSearch::getAttributeTypesAndNames(attributeTypes, attributeNames); const int numAttributeTypes = static_cast(attributeTypes.size()); std::vector matchingTypes; std::vector matchingNames; FociSearch::getMatchingTypesAndNames(matchingTypes, matchingNames); const int numMatchingTypes = static_cast(matchingTypes.size()); // // Add rows to GUI // const int numValidSearches = fss->getNumberOfFociSearches(); for (int i = numSearchesInDialog; i < numValidSearches; i++) { // // Search number label // QLabel* searchNumberLabel = new QLabel(QString::number(i + 1)); // // Create insert search button // QToolButton* insertSearchButton = new QToolButton; insertSearchButton->setText("+"); insertSearchButton->setToolTip("Add an additional\n" "search parameter."); QObject::connect(insertSearchButton, SIGNAL(clicked()), insertSearchToolButtonSignalMapper, SLOT(map())); insertSearchToolButtonSignalMapper->setMapping(insertSearchButton, i); insertSearchToolButtons.push_back(insertSearchButton); // // Create delete search button // QToolButton* deleteSearchButton = new QToolButton; deleteSearchButton->setText("-"); deleteSearchButton->setToolTip("Delete this \n" "search parameter."); QObject::connect(deleteSearchButton, SIGNAL(clicked()), deleteSearchToolButtonSignalMapper, SLOT(map())); deleteSearchToolButtonSignalMapper->setMapping(deleteSearchButton, i); deleteSearchToolButtons.push_back(deleteSearchButton); // // Create the logic selection combo box // QComboBox* logicComboBox = new QComboBox; for (int j = 0; j < numLogicTypes; j++) { logicComboBox->addItem(logicNames[j], static_cast(logicTypes[j])); } logicComboBox->setFixedSize(logicComboBox->sizeHint()); logicComboBoxes.push_back(logicComboBox); QObject::connect(logicComboBox, SIGNAL(activated(int)), searchLogicComboBoxSignalMapper, SLOT(map())); searchLogicComboBoxSignalMapper->setMapping(logicComboBox, i); logicComboBox->setToolTip("The search parameters are applied in their\n" "listed order. Union functions as a logical\n" "OR and broadens the search results to include\n" "more foci. Intersection functions as a logical\n" "AND and narrows the search results."); // // Create the attribute selection combo box // QComboBox* attributeComboBox = new QComboBox; for (int j = 0; j < numAttributeTypes; j++) { attributeComboBox->addItem(attributeNames[j], static_cast(attributeTypes[j])); } attributeComboBox->setFixedSize(attributeComboBox->sizeHint()); attributeComboBoxes.push_back(attributeComboBox); QObject::connect(attributeComboBox, SIGNAL(activated(int)), searchAttributeComboBoxSignalMapper, SLOT(map())); searchAttributeComboBoxSignalMapper->setMapping(attributeComboBox, i); attributeComboBox->setToolTip("Chooses the focus or study \n" "attribute on which to search."); // // Create the matching selection combo box // QComboBox* matchingComboBox = new QComboBox; for (int j = 0; j < numMatchingTypes; j++) { matchingComboBox->addItem(matchingNames[j], static_cast(matchingTypes[j])); } matchingComboBox->setFixedSize(matchingComboBox->sizeHint()); matchingComboBoxes.push_back(matchingComboBox); QObject::connect(matchingComboBox, SIGNAL(activated(int)), searchMatchingComboBoxSignalMapper, SLOT(map())); searchMatchingComboBoxSignalMapper->setMapping(matchingComboBox, i); matchingComboBox->setToolTip("Chooses how the search text is matched. \n" "This choice is ignored during a \n" "spatial search."); // // Create the assistance tool button // QToolButton* assistanceButton = new QToolButton; assistanceButton->setText("Terms..."); assistanceButton->setToolTip("Provides assistance for \n" "for setting the search text."); QObject::connect(assistanceButton, SIGNAL(clicked()), assistanceToolButtonSignalMapper, SLOT(map())); assistanceToolButtonSignalMapper->setMapping(assistanceButton, i); assistanceToolButtons.push_back(assistanceButton); // // Create the search text line edit // QLineEdit* searchLineEdit = new QLineEdit; searchTextLineEdits.push_back(searchLineEdit); QObject::connect(searchLineEdit, SIGNAL(textEdited(const QString&)), searchTextLineEditSignalMapper, SLOT(map())); searchTextLineEditSignalMapper->setMapping(searchLineEdit, i); searchLineEdit->setToolTip("Enter the text for searching here. \n" "Separate multiple items with a semicolon.\n" "\n" "For a spatial search, this field \n" "should contain four consecutive \n" "numbers separated by spaces representing\n" "the X, Y, Z coordinates and radius of \n" "the spatial spherical region."); // // Add to layout // If new widgets are added, may need to adjust column stretching // that is set when the layout is created in "createSearchParametersGroup()" // const int row = searchGridLayout->rowCount(); searchGridLayout->addWidget(searchNumberLabel, row, 0); searchGridLayout->addWidget(insertSearchButton, row, 1); searchGridLayout->addWidget(deleteSearchButton, row, 2); searchGridLayout->addWidget(logicComboBox, row, 3); searchGridLayout->addWidget(attributeComboBox, row, 4); searchGridLayout->addWidget(matchingComboBox, row, 5); searchGridLayout->addWidget(assistanceButton, row + 1, 1, 1, 2, Qt::AlignRight); searchGridLayout->addWidget(searchLineEdit, row + 1, 3, 1, 4); // // Add to widget group for row // WuQWidgetGroup* wg = new WuQWidgetGroup(this); wg->addWidget(searchNumberLabel); wg->addWidget(insertSearchButton); wg->addWidget(deleteSearchButton); wg->addWidget(logicComboBox); wg->addWidget(attributeComboBox); wg->addWidget(matchingComboBox); wg->addWidget(assistanceButton); wg->addWidget(searchLineEdit); searchWidgetGroups.push_back(wg); } // // Update existing GUI // for (int i = 0; i < numValidSearches; i++) { searchWidgetGroups[i]->blockSignals(true); const FociSearch* fs = fss->getFociSearch(i); logicComboBoxes[i]->setCurrentIndex(static_cast(fs->getLogic())); attributeComboBoxes[i]->setCurrentIndex(static_cast(fs->getAttribute())); matchingComboBoxes[i]->setCurrentIndex(static_cast(fs->getMatching())); searchTextLineEdits[i]->setText(fs->getSearchText()); searchWidgetGroups[i]->setHidden(false); searchWidgetGroups[i]->blockSignals(false); } // // Hide rows not needed // for (int i = numValidSearches; i < numSearchesInDialog; i++) { searchWidgetGroups[i]->setHidden(true); } } /** * called when an assistance tool button is clicked. */ void GuiFociSearchWidget::slotAssistanceToolButtonClicked(int item) { FociSearchSet* fss = getSelectedSearchSet(); FociSearch* fs = fss->getFociSearch(item); const FociSearch::ATTRIBUTE attribute = fs->getAttribute(); unsigned int itemsToDisplay = GuiNameSelectionDialog::LIST_ALL; GuiNameSelectionDialog::LIST_ITEMS_TYPE defaultItem = GuiNameSelectionDialog::LIST_NONE; switch (attribute) { case FociSearch::ATTRIBUTE_ALL: break; case FociSearch::ATTRIBUTE_FOCUS_AREA: defaultItem = GuiNameSelectionDialog::LIST_FOCI_AREAS_ALPHA; break; case FociSearch::ATTRIBUTE_FOCUS_CLASS: defaultItem = GuiNameSelectionDialog::LIST_FOCI_CLASSES_ALPHA; break; case FociSearch::ATTRIBUTE_FOCUS_COMMENT: defaultItem = GuiNameSelectionDialog::LIST_FOCI_COMMENT_ALPHA; break; case FociSearch::ATTRIBUTE_FOCUS_GEOGRAPHY: defaultItem = GuiNameSelectionDialog::LIST_FOCI_GEOGRAPHY_ALPHA; break; case FociSearch::ATTRIBUTE_FOCUS_ROI: defaultItem = GuiNameSelectionDialog::LIST_FOCI_ROI_ALPHA; break; case FociSearch::ATTRIBUTE_FOCUS_SPATIAL: { WuQDataEntryDialog ded(this); QDoubleSpinBox* xDSB = ded.addDoubleSpinBox("X", 0.0); QDoubleSpinBox* yDSB = ded.addDoubleSpinBox("Y", 0.0); QDoubleSpinBox* zDSB = ded.addDoubleSpinBox("Z", 0.0); QDoubleSpinBox* distanceDSB = ded.addDoubleSpinBox("Sphere Radius", 10.0); if (ded.exec() == WuQDataEntryDialog::Accepted) { const QString s = QString::number(xDSB->value(), 'f', 3) + " " + QString::number(yDSB->value(), 'f', 3) + " " + QString::number(zDSB->value(), 'f', 3) + " " + QString::number(distanceDSB->value(), 'f', 3); searchTextLineEdits[item]->blockSignals(true); searchTextLineEdits[item]->setText(s); searchTextLineEdits[item]->blockSignals(false); slotSearchTextChanged(item); } return; } break; case FociSearch::ATTRIBUTE_STUDY_SPECIES: defaultItem = GuiNameSelectionDialog::LIST_SPECIES; break; case FociSearch::ATTRIBUTE_FOCUS_STRUCTURE: defaultItem = GuiNameSelectionDialog::LIST_STRUCTURE; break; case FociSearch::ATTRIBUTE_STUDY_AUTHORS: break; case FociSearch::ATTRIBUTE_STUDY_CITATION: defaultItem = GuiNameSelectionDialog::LIST_STUDY_CITATION; break; case FociSearch::ATTRIBUTE_STUDY_COMMENT: break; case FociSearch::ATTRIBUTE_STUDY_DATA_FORMAT: defaultItem = GuiNameSelectionDialog::LIST_STUDY_DATA_FORMAT; break; case FociSearch::ATTRIBUTE_STUDY_DATA_TYPE: defaultItem = GuiNameSelectionDialog::LIST_STUDY_DATA_TYPE; break; case FociSearch::ATTRIBUTE_STUDY_KEYWORDS: defaultItem = GuiNameSelectionDialog::LIST_STUDY_KEYWORDS_ALPHA; break; case FociSearch::ATTRIBUTE_STUDY_MESH_TERMS: defaultItem = GuiNameSelectionDialog::LIST_STUDY_MESH_ALPHA; break; case FociSearch::ATTRIBUTE_STUDY_NAME: break; case FociSearch::ATTRIBUTE_STUDY_STEREOTAXIC_SPACE: defaultItem = GuiNameSelectionDialog::LIST_STEREOTAXIC_SPACES; break; case FociSearch::ATTRIBUTE_STUDY_TABLE_HEADER: defaultItem = GuiNameSelectionDialog::LIST_STUDY_TABLE_HEADERS; break; case FociSearch::ATTRIBUTE_STUDY_TABLE_SUBHEADER: defaultItem = GuiNameSelectionDialog::LIST_STUDY_TABLE_SUBHEADERS; break; case FociSearch::ATTRIBUTE_STUDY_TITLE: break; case FociSearch::ATTRIBUTE_NUMBER_OF: break; } GuiNameSelectionDialog nsd(this, itemsToDisplay, defaultItem, true); if (nsd.exec() == GuiNameSelectionDialog::Accepted) { QString txt = searchTextLineEdits[item]->text(); const QStringList nameList = nsd.getNamesSelected(); if (nameList.size() > 0) { if (txt.isEmpty() == false) { txt += "; "; } txt += nameList.join("; "); } searchTextLineEdits[item]->blockSignals(true); searchTextLineEdits[item]->setText(txt); searchTextLineEdits[item]->blockSignals(false); slotSearchTextChanged(item); } } /** * called when insert search tool button pressed. */ void GuiFociSearchWidget::slotInsertSearchToolButtonClicked(int buttNum) { QMessageBox msgBox(insertSearchToolButtons[buttNum]); msgBox.setWindowTitle("New Search Parameter"); msgBox.setText("Add new search parameter before or after search " + QString::number(buttNum + 1) + "?"); QPushButton* afterPushButton = msgBox.addButton("After", QMessageBox::NoRole); QPushButton* beforePushButton = msgBox.addButton("Before", QMessageBox::NoRole); QPushButton* cancelPushButton = msgBox.addButton("Cancel", QMessageBox::NoRole); msgBox.exec(); if (msgBox.clickedButton() == afterPushButton) { FociSearchSet* fss = getSelectedSearchSet(); FociSearch* fs = new FociSearch(); fss->insertFociSearch(fs, buttNum); } else if (msgBox.clickedButton() == beforePushButton) { FociSearchSet* fss = getSelectedSearchSet(); FociSearch* fs = new FociSearch(); fss->insertFociSearch(fs, buttNum - 1); } else if (msgBox.clickedButton() == cancelPushButton) { } loadFociSearches(); } /** * called when delete search tool button pressed. */ void GuiFociSearchWidget::slotDeleteSearchToolButtonClicked(int buttNum) { FociSearchSet* fss = getSelectedSearchSet(); if (fss->getNumberOfFociSearches() <= 1) { QMessageBox::critical(this, "ERROR", "You may not delete all search parameters."); return; } if (QMessageBox::question(this, "CONFIRM", "Remove search parameter " + QString::number(buttNum + 1), (QMessageBox::Ok | QMessageBox::Cancel)) == QMessageBox::Ok) { fss->deleteFociSearch(buttNum); } loadFociSearches(); } /** * called when a search logic is changed. */ void GuiFociSearchWidget::slotSearchLogicChanged(int indx) { FociSearchSet* fss = getSelectedSearchSet(); FociSearch* fs = fss->getFociSearch(indx); const int logicIndex = logicComboBoxes[indx]->currentIndex(); fs->setLogic(static_cast( logicComboBoxes[indx]->itemData(logicIndex).toInt())); } /** * called when a search attribute is changed. */ void GuiFociSearchWidget::slotSearchAttributeChanged(int indx) { FociSearchSet* fss = getSelectedSearchSet(); FociSearch* fs = fss->getFociSearch(indx); const int attributeIndex = attributeComboBoxes[indx]->currentIndex(); fs->setAttribute(static_cast( attributeComboBoxes[indx]->itemData(attributeIndex).toInt())); } /** * called when a search matching is changed. */ void GuiFociSearchWidget::slotSearchMatchingChanged(int indx) { FociSearchSet* fss = getSelectedSearchSet(); FociSearch* fs = fss->getFociSearch(indx); const int matchingIndex = matchingComboBoxes[indx]->currentIndex(); fs->setMatching(static_cast( matchingComboBoxes[indx]->itemData(matchingIndex).toInt())); } /** * called when a search text is changed. */ void GuiFociSearchWidget::slotSearchTextChanged(int indx) { FociSearchSet* fss = getSelectedSearchSet(); FociSearch* fs = fss->getFociSearch(indx); fs->setSearchText(searchTextLineEdits[indx]->text().trimmed()); } /** * called when search name is changed. */ void GuiFociSearchWidget::slotSearchNameLineEdit(const QString& s) { FociSearchSet* fss = getSelectedSearchSet(); fss->setName(s.trimmed()); } /** * called when reset button pressed. */ void GuiFociSearchWidget::slotResetPushButton() { searchResultsLabel->setText(""); fociProjectionFile->setAllSearchStatus(true); DisplaySettingsFoci* dsf = theMainWindow->getBrainSet()->getDisplaySettingsFoci(); dsf->determineDisplayedFoci(); GuiBrainModelOpenGL::updateAllGL(); } /** * called when search displayed button pressed. */ void GuiFociSearchWidget::slotSearchDisplayedPushButton() { performSearch(true); } /** * called when search all button pressed. */ void GuiFociSearchWidget::slotSearchAllPushButton() { searchResultsLabel->setText(""); fociProjectionFile->setAllSearchStatus(true); performSearch(false); } /** * perform the search. */ void GuiFociSearchWidget::performSearch(const bool searchDisplayedOnlyFlag) { BrainModelSurfaceFociSearch::SEARCH_MODE searchMode = BrainModelSurfaceFociSearch::SEARCH_MODE_ALL_FOCI; if (searchDisplayedOnlyFlag) { searchMode = BrainModelSurfaceFociSearch::SEARCH_MODE_DISPLAYED_FOCI; } searchResultsLabel->setText(""); StudyMetaDataFile* smdf = theMainWindow->getBrainSet()->getStudyMetaDataFile(); FociSearchSet* fss = getSelectedSearchSet(); if (fss != NULL) { BrainModelSurfaceFociSearch fociSearch(theMainWindow->getBrainSet(), theMainWindow->getBrainSet()->getStudyMetaDataFile(), fociProjectionFile, fss, searchMode, showFociFromMatchingStudiesCheckBox->isChecked()); int numberOfMatchingFoci = 0; int numberOfFociFromMatchingStudies = 0; try { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); fociSearch.execute(); numberOfMatchingFoci = fociSearch.getNumberOfMatchingFoci(); numberOfFociFromMatchingStudies = fociSearch.getNumberOfFociFromMatchingStudies(); QApplication::restoreOverrideCursor(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); } QString matchingStudiesString; if (numberOfFociFromMatchingStudies > 0) { matchingStudiesString = "/" + QString::number(numberOfFociFromMatchingStudies); } searchResultsLabel->setText(QString::number(numberOfMatchingFoci) + matchingStudiesString + " of " + QString::number(fociProjectionFile->getNumberOfCellProjections()) + " foci matched from " + QString::number(fociSearch.getNumberOfStudiesUsedByMatchingFoci()) + " of " + QString::number(smdf->getNumberOfStudyMetaData()) + " studies."); DisplaySettingsFoci* dsf = theMainWindow->getBrainSet()->getDisplaySettingsFoci(); dsf->determineDisplayedFoci(); GuiBrainModelOpenGL::updateAllGL(); } } /** * get the selected search set. */ FociSearchSet* GuiFociSearchWidget::getSelectedSearchSet() { // // Get the number of the selected search // Note that "searchSelectionSpinBox" indexes 1..N // int searchNumber = searchSelectionSpinBox->value() - 1; // // Get number of search sets // const int numSearchSets = fociSearchFile->getNumberOfFociSearchSets(); // // Update search set number // if ((searchNumber < 0) || (searchNumber >= numSearchSets)) { searchNumber = 0; } // // Update search selection spin box // if (numSearchSets <= 0) { searchSelectionSpinBox->setEnabled(false); } else { // // Note that "searchSelectionSpinBox" indexes 1..N // searchSelectionSpinBox->blockSignals(true); searchSelectionSpinBox->setEnabled(true); searchSelectionSpinBox->setMinimum(1); searchSelectionSpinBox->setMaximum(numSearchSets); searchSelectionSpinBox->setValue(searchNumber + 1); searchSelectionSpinBox->blockSignals(false); } // // Get active search // FociSearchSet* fss = fociSearchFile->getFociSearchSet(searchNumber); return fss; } caret-5.6.4~dfsg.1.orig/caret/GuiFociPalsProjectionDialog.h0000664000175000017500000000425311572067322023356 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_FOCI_PALS_PROJECTION_DIALOG_H__ #define __GUI_FOCI_PALS_PROJECTION_DIALOG_H__ #include "WuQDialog.h" class QCheckBox; class QGroupBox; class QRadioButton; class QDoubleSpinBox; /// class for dialog used to project cells and foci class GuiFociPalsProjectionDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiFociPalsProjectionDialog(QWidget* parent); /// Destructor ~GuiFociPalsProjectionDialog(); protected slots: /// called when help button is pressed void slotHelpButton(); protected: /// called when OK or Cancel button pressed virtual void done(int r); /// project onto surface check box QRadioButton* projectOntoSurfaceRadioButton; /// keep offset from surface QRadioButton* maintainOffsetFromSurfaceRadioButton; /// above surface distance QDoubleSpinBox* surfaceOffsetDoubleSpinBox; /// allow projection to cerebellum check box QGroupBox* cerebellarOptionsGroupBox; /// cerebral cutoff distance spin box QDoubleSpinBox* cerebralCutoffDistanceDoubleSpinBox; /// cerebellar cutoff distance spin box QDoubleSpinBox* cerebellarCutoffDistanceDoubleSpinBox; }; #endif // __GUI_FOCI_PALS_PROJECTION_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiFociPalsProjectionDialog.cxx0000664000175000017500000002225011572067322023726 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include "GuiFociPalsProjectionDialog.h" #include "BrainModelSurface.h" #include "BrainSet.h" #include "FociFileToPalsProjector.h" #include "FociProjectionFile.h" #include "GuiBrainModelOpenGL.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include #include "QtUtilities.h" #include "global_variables.h" /** * Constructor. */ GuiFociPalsProjectionDialog::GuiFociPalsProjectionDialog(QWidget* parent) : WuQDialog(parent) { setModal(true); setWindowTitle("Foci Projection to PALS Atlas"); // // Project onto surface option // projectOntoSurfaceRadioButton = new QRadioButton("Project Above Surface"); surfaceOffsetDoubleSpinBox = new QDoubleSpinBox; surfaceOffsetDoubleSpinBox->setMinimum(0.0); surfaceOffsetDoubleSpinBox->setMaximum(1000.0); surfaceOffsetDoubleSpinBox->setSingleStep(1.0); surfaceOffsetDoubleSpinBox->setDecimals(2); QHBoxLayout* ontoSurfaceHBoxLayout = new QHBoxLayout; ontoSurfaceHBoxLayout->addWidget(projectOntoSurfaceRadioButton); ontoSurfaceHBoxLayout->addWidget(surfaceOffsetDoubleSpinBox); // // Maintain offset from surface option // maintainOffsetFromSurfaceRadioButton = new QRadioButton("Keep Offset From Surface"); maintainOffsetFromSurfaceRadioButton->setChecked(true); // // Button group for spatial projection // QButtonGroup* projectionButtonGroup = new QButtonGroup(this); projectionButtonGroup->addButton(projectOntoSurfaceRadioButton); projectionButtonGroup->addButton(maintainOffsetFromSurfaceRadioButton); // // Spatial projection type options box // QGroupBox* projectionTypeGroupBox = new QGroupBox("Spatial Projection Type"); QVBoxLayout* projectionTypeLayout = new QVBoxLayout(projectionTypeGroupBox); projectionTypeLayout->addLayout(ontoSurfaceHBoxLayout); projectionTypeLayout->addWidget(maintainOffsetFromSurfaceRadioButton); // // cerebellum cutoff distances // QLabel* cerebellarCutoffLabel = new QLabel("Cerebellum Cutoff (R2)"); cerebellarCutoffDistanceDoubleSpinBox = new QDoubleSpinBox; cerebellarCutoffDistanceDoubleSpinBox->setMinimum(0.0); cerebellarCutoffDistanceDoubleSpinBox->setMaximum(1000000000.0); cerebellarCutoffDistanceDoubleSpinBox->setSingleStep(1.0); cerebellarCutoffDistanceDoubleSpinBox->setDecimals(2); cerebellarCutoffDistanceDoubleSpinBox->setValue( FociFileToPalsProjector::getDefaultCerebellumCutoffDistance()); QLabel* cerebralCutoffLabel = new QLabel("Cerebral Cutoff (R1)"); cerebralCutoffDistanceDoubleSpinBox = new QDoubleSpinBox; cerebralCutoffDistanceDoubleSpinBox->setMinimum(0.0); cerebralCutoffDistanceDoubleSpinBox->setMaximum(1000000000.0); cerebralCutoffDistanceDoubleSpinBox->setSingleStep(1.0); cerebralCutoffDistanceDoubleSpinBox->setDecimals(2); cerebralCutoffDistanceDoubleSpinBox->setValue( FociFileToPalsProjector::getDefaultCerebralCutoffDistance()); // // Cerebellar Options group box // cerebellarOptionsGroupBox = new QGroupBox("Allow Projection to Cerebellum"); cerebellarOptionsGroupBox->setCheckable(true); cerebellarOptionsGroupBox->setChecked(true); QGridLayout* cerebellaOptionsLayout = new QGridLayout(cerebellarOptionsGroupBox); cerebellaOptionsLayout->addWidget(cerebralCutoffLabel, 0, 0); cerebellaOptionsLayout->addWidget(cerebralCutoffDistanceDoubleSpinBox, 0, 1); cerebellaOptionsLayout->addWidget(cerebellarCutoffLabel, 1, 0); cerebellaOptionsLayout->addWidget(cerebellarCutoffDistanceDoubleSpinBox, 1, 1); QLabel* notesLabel = new QLabel( "If Allow Projection to Cerebellum is selected:\n" " ** A ratio of (distance-to-cerebral-cortext divided by\n" " distance-to-cerebellum) is computed.\n" " ** If this ratio is less than \"Cerebral Cutoff (R1)\",\n" " the focus is assigned to the left or right cerebral\n" " cortex based upon the X-coordinate of the focus.\n" " ** If this ratio is greater than \"Cerebellum Cutoff (R2)\"\n" " the focus is assigned to the cerebellum.\n" " ** If the ratio is between the two cutoffs, the focus is\n" " assigned to both the cerebellum and also the left or \n" " right cerebral cortex.\n"); QGroupBox* noteGroupBox = new QGroupBox("Important Information"); QVBoxLayout* notesLayout = new QVBoxLayout(noteGroupBox); notesLayout->addWidget(notesLabel); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); // // OK button // QPushButton* okButton = new QPushButton("OK"); okButton->setAutoDefault(false); buttonsLayout->addWidget(okButton); QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); // // Cancel button // QPushButton* cancelButton = new QPushButton("Cancel"); cancelButton->setAutoDefault(false); buttonsLayout->addWidget(cancelButton); QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); // // Help button // QPushButton* helpButton = new QPushButton("Help"); helpButton->setAutoDefault(false); buttonsLayout->addWidget(helpButton); QObject::connect(helpButton, SIGNAL(clicked()), this, SLOT(slotHelpButton())); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); dialogLayout->addWidget(cerebellarOptionsGroupBox); dialogLayout->addWidget(projectionTypeGroupBox); dialogLayout->addWidget(noteGroupBox); dialogLayout->addLayout(buttonsLayout); QtUtilities::makeButtonsSameSize(okButton, cancelButton, helpButton); } /** * Destructor. */ GuiFociPalsProjectionDialog::~GuiFociPalsProjectionDialog() { } /** * Called when help button is pressed. */ void GuiFociPalsProjectionDialog::slotHelpButton() { theMainWindow->showHelpPageOverModalDialog(this, "dialogs/project_foci_to_pals_dialog.html"); } /** * called when OK or Cancel button pressed. */ void GuiFociPalsProjectionDialog::done(int r) { // // Was OK button pressed // if (r == QDialog::Accepted) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); // // Save name and clear cell/foci projection file and get cell/foci files // FociProjectionFile* fpf = theMainWindow->getBrainSet()->getFociProjectionFile(); // // Get cutoff distances // const float cerebralCutoffDistance = cerebralCutoffDistanceDoubleSpinBox->value(); const float cerebellarCutoffDistance = cerebellarCutoffDistanceDoubleSpinBox->value(); // // Project the foci // FociFileToPalsProjector fociProjector(theMainWindow->getBrainSet(), fpf, theMainWindow->getBrainSet()->getStudyMetaDataFile(), 0, -1, surfaceOffsetDoubleSpinBox->value(), projectOntoSurfaceRadioButton->isChecked(), cerebellarOptionsGroupBox->isChecked(), cerebralCutoffDistance, cerebellarCutoffDistance); try { fociProjector.execute(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); } GuiFilesModified fm; fm.setFociModified(); fm.setFociProjectionModified(); // // Update now that cells/foci are changed // theMainWindow->fileModificationUpdate(fm); // // Update all displayed surfaces // GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } QDialog::done(r); } caret-5.6.4~dfsg.1.orig/caret/GuiFlattenHemisphereInstructionsDialog.h0000664000175000017500000000326111572067322025653 0ustar michaelmichael #ifndef __GUI_FLATTEN_HEMISPHERE_INSTRUCTIONS_DIALOG_H__ #define __GUI_FLATTEN_HEMISPHERE_INSTRUCTIONS_DIALOG_H__ #include "WuQDialog.h" class BrainModelSurface; class BrainModelSurfaceFlattenFullHemisphere; class QTextEdit; /// Dialog for continuing flattening class GuiFlattenHemisphereInstructionsDialog : public WuQDialog { Q_OBJECT public: /// mode of the dialog enum DIALOG_MODE { DIALOG_MODE_FLATTEN_FULL_HEMISPHERE_PART2, DIALOG_MODE_FLATTEN_FULL_HEMISPHERE_MORPH_SPHERE_PART2, DIALOG_MODE_FLATTEN_POST_INITIAL_FLAT_PART_HEM, DIALOG_MODE_FLATTEN_POST_INITIAL_FLAT_FULL_HEM, DIALOG_MODE_FLATTEN_POST_INITIAL_FLAT_FULL_HEM_MORPH_SPHERE }; /// constructor GuiFlattenHemisphereInstructionsDialog(QWidget* parent, BrainModelSurfaceFlattenFullHemisphere* algorithmIn, const DIALOG_MODE dialogModeIn, Qt::WindowFlags f = 0); /// destructor ~GuiFlattenHemisphereInstructionsDialog(); private slots: /// Called when user press OK or Cancel buttons void done(int r); private: /// do second half of flattening void doFlattenFullHemispherePart2(); // show crossovers on surface void showCrossovers(BrainModelSurface* bms = NULL); /// Mode of the dialog DIALOG_MODE dialogMode; /// Full hemisphere algorithm BrainModelSurfaceFlattenFullHemisphere* algorithm; /// the text section QTextEdit* textEdit; }; #endif // __GUI_FLATTEN_HEMISPHERE_INSTRUCTIONS_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiFlattenHemisphereInstructionsDialog.cxx0000664000175000017500000005056311572067322026235 0ustar michaelmichael #include #include #include #include #include #include "BrainSet.h" #include "GuiBrainModelOpenGL.h" #include "BrainModelSurfaceFlattenFullHemisphere.h" #include "BrainModelSurfaceNodeColoring.h" #include "DisplaySettingsBorders.h" #include "GuiFilesModified.h" #include "GuiFlattenHemisphereInstructionsDialog.h" #include "GuiMainWindow.h" #include "GuiMainWindowSurfaceActions.h" #include "GuiMorphingMeasurementsDialog.h" #include "GuiMultiresolutionMorphingDialog.h" #include "QtUtilities.h" #include "global_variables.h" static const QString flattenHemisphereText = "\n" "Examine the border that represents the medial wall boundary and the " "borders that represent the cuts. Selecting Layers:Borders:Show Raised " "Borders may make the borders easier to see. If they are satisfactory, " "press the Continue Flattening button to continue flattening the full " "hemisphere. " "\n\n" "To create a different medial wall boundary, select Layers:Borders:Draw Border. " "\n\n" "In the Draw Border Dialog, select \"Closed Border\".\n" "There are two ways to enter the border's name:\n" " a) Enter the name \"MEDIAL.WALL\" in the text box.\n" " b) Press the \"Select Name\" pushbutton and then the \"Select From\n" " Borders\" button in the dialog that pops up. One more dialog will\n" " pop up and in it, scroll to and select the name \"MEDIAL.WALL\"\n" " and press the \"OK\" button on the Border Name Selection dialog\n" "\n" "Now, press the Apply button on the Draw Border dialog to start border " "drawing. Draw the border by holding down the left mouse button and " "dragging the mouse. Release the mouse button and then press the mouse " "button while holding down the shift key to close the border. " "\n\n" "To create borders that represent the cuts, switch to \"Open Border\" " "in the Draw Border Dialog and enter the name of the cut or use the " "Select Name button as described in the draw medial wall section above. " "Assign an appropriate label for each new cut and draw the border. " "\n\n" "After all of the cuts have been drawn, click the \"Close\" button on " "the Draw Border dialog." "\n\n" "If the medial wall border and/or the cuts have been redrawn, the unwanted " "medial wall and/or cuts will need to be deleted. To do this, select " "the \"Delete Border With Mouse\" item Layers:Borders menu and click " "the left mouse button on each of the unwanted borders." "\n\n" "When you are ready, press the \"Continue Flattening\" button to " "finish flattening the hemisphere. " "\n\n"; const QString preMorphingInstructions = "\n" "Cuts should be made: (i) to reduce distortions in the final flat map, or " "(ii) to excise regions containing \"crossovers\" if these are near the " "perimeter of the map. Crossovers initially appear red, and can be " "toggled on and off using the Display Control Dialog. " "\n\n" "To make cuts, \n" " * Select Surface: Cuts: Draw Cut. \n" " * Draw the cut by holding down the left mouse button. At the end of\n" " the cut release the mouse button then hold down the shift key and\n" " click the left mouse button to terminate the cut.\n" " * To delete undesired cuts, select Surface: Cuts: Delete Cuts and click\n" " the left mouse over undesired cuts.\n" " * Select Surface: Cuts: Apply Cuts to cut the surface.\n" " * Select File: Save Data File to save the topology file. with\n" " an appropriate name.\n" "\n" "Cuts used to reduce distortion should begin outside the map perimeter at " "one end. Cuts used to excise errors should begin and end outside the " "map perimeter." "\n\n" "When the surface is ready for multi-resolution morphing, Press " "the Continue Flattening button." "\n\n" "If there are major clusters of crossovers (red) that cannot be safely " "eliminated by excising regions along the perimeter of the map, it may " "be advisable to make additional corrections of the segmented volume " "in SureFit and to regenerate a new surface." "\n\n"; /** * Constructor. */ GuiFlattenHemisphereInstructionsDialog::GuiFlattenHemisphereInstructionsDialog( QWidget* parent, BrainModelSurfaceFlattenFullHemisphere* algorithmIn, const DIALOG_MODE dialogModeIn, Qt::WindowFlags f) : WuQDialog(parent, f) { setModal(false); dialogMode = dialogModeIn; algorithm = algorithmIn; // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // Create the text display section // textEdit = new QTextEdit; textEdit->setMinimumSize(500, 300); textEdit->setReadOnly(true); dialogLayout->addWidget(textEdit); switch(dialogMode) { case DIALOG_MODE_FLATTEN_FULL_HEMISPHERE_PART2: case DIALOG_MODE_FLATTEN_FULL_HEMISPHERE_MORPH_SPHERE_PART2: setWindowTitle("Continue Flattening Full Hemisphere"); textEdit->setPlainText(flattenHemisphereText); break; case DIALOG_MODE_FLATTEN_POST_INITIAL_FLAT_PART_HEM: case DIALOG_MODE_FLATTEN_POST_INITIAL_FLAT_FULL_HEM: case DIALOG_MODE_FLATTEN_POST_INITIAL_FLAT_FULL_HEM_MORPH_SPHERE: setWindowTitle("Initial Flattening"); theMainWindow->speakText("Initial flat surface is ready.", false); textEdit->setPlainText(preMorphingInstructions); break; } // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); dialogLayout->addLayout(buttonsLayout); // // Continue button // QPushButton* continueButton = new QPushButton("Continue Flattening"); buttonsLayout->addWidget(continueButton); QObject::connect(continueButton, SIGNAL(clicked()), this, SLOT(accept())); // // Cancel button // QPushButton* cancelButton = new QPushButton("Cancel Flattening"); buttonsLayout->addWidget(cancelButton); QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); QtUtilities::makeButtonsSameSize(continueButton, cancelButton); QApplication::restoreOverrideCursor(); } /** * Destructor. */ GuiFlattenHemisphereInstructionsDialog::~GuiFlattenHemisphereInstructionsDialog() { } /** * Called when Continue or stop buttons are pressed */ void GuiFlattenHemisphereInstructionsDialog::done(int r) { if (r == QDialog::Accepted) { switch(dialogMode) { case DIALOG_MODE_FLATTEN_FULL_HEMISPHERE_PART2: { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); // // Do the remaining part of hemisphere flattening // doFlattenFullHemispherePart2(); showCrossovers(); QApplication::restoreOverrideCursor(); // // Popup post initial flattening instructions // GuiFlattenHemisphereInstructionsDialog* gid = new GuiFlattenHemisphereInstructionsDialog(theMainWindow, NULL, DIALOG_MODE_FLATTEN_POST_INITIAL_FLAT_FULL_HEM); gid->setAttribute(Qt::WA_DeleteOnClose); gid->show(); } break; case DIALOG_MODE_FLATTEN_FULL_HEMISPHERE_MORPH_SPHERE_PART2: { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); // // Do the remaining part of hemisphere flattening // doFlattenFullHemispherePart2(); showCrossovers(); QApplication::restoreOverrideCursor(); // // Popup post initial flattening instructions // GuiFlattenHemisphereInstructionsDialog* gid = new GuiFlattenHemisphereInstructionsDialog(theMainWindow, NULL, DIALOG_MODE_FLATTEN_POST_INITIAL_FLAT_FULL_HEM_MORPH_SPHERE); gid->setAttribute(Qt::WA_DeleteOnClose); gid->show(); } break; case DIALOG_MODE_FLATTEN_POST_INITIAL_FLAT_PART_HEM: { // // Popup multiresolution morphing dialog to morph flat surface. // showCrossovers(); QApplication::restoreOverrideCursor(); GuiMultiresolutionMorphingDialog mmd(this, theMainWindow->getSurfaceActions()->getFlatMultiresolutionMorphingObject(), false); mmd.exec(); } break; case DIALOG_MODE_FLATTEN_POST_INITIAL_FLAT_FULL_HEM: { // // Popup multiresolution morphing dialog to morph flat surface. // showCrossovers(); QApplication::restoreOverrideCursor(); GuiMultiresolutionMorphingDialog mmd(this, theMainWindow->getSurfaceActions()->getFlatMultiresolutionMorphingObject(), false); if (mmd.exec() == QDialog::Accepted) { // // Allow user to align flat surface. // theMainWindow->speakText("Ready to align the flat surface.", false); QApplication::restoreOverrideCursor(); GuiMainWindowSurfaceActions* surfaceActions = theMainWindow->getSurfaceActions(); surfaceActions->slotAlignSurfacesToStandardOrientation(); } } break; case DIALOG_MODE_FLATTEN_POST_INITIAL_FLAT_FULL_HEM_MORPH_SPHERE: { QApplication::restoreOverrideCursor(); // // Multiresolution Morph Flat Surface parameters // QApplication::restoreOverrideCursor(); GuiMultiresolutionMorphingDialog flatMorphParameters( this, theMainWindow->getSurfaceActions()->getFlatMultiresolutionMorphingObject(), true); flatMorphParameters.exec(); // // Multiresolution Morph Spherical Surface parameters // QApplication::restoreOverrideCursor(); GuiMultiresolutionMorphingDialog sphereMorphParameters( this, theMainWindow->getSurfaceActions()->getSphericalMultiresolutionMorphingObject(), true); sphereMorphParameters.exec(); // // Get the fiducial surface // BrainModelSurface* fiducialSurface = theMainWindow->getBrainSet()->getActiveFiducialSurface(); if (fiducialSurface == NULL) { QMessageBox::critical(this, "Morph Error", "Unable to find fiducial surface."); return; } // // Get the flat surface // BrainModelSurface* flatSurface = theMainWindow->getBrainSet()->getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_FLAT); if (flatSurface == NULL) { QMessageBox::critical(this, "Morph Error", "Unable to find flat surface."); return; } // // Get the spherical surface // BrainModelSurface* sphericalSurface = theMainWindow->getBrainSet()->getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_SPHERICAL); if (sphericalSurface == NULL) { QMessageBox::critical(this, "Morph Error", "Unable to find spherical surface."); return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); // // Execute flat morphing // BrainModelSurfaceMultiresolutionMorphing flatMRM( theMainWindow->getBrainSet(), fiducialSurface, flatSurface, BrainModelSurfaceMorphing::MORPHING_SURFACE_FLAT); flatMRM.copyParameters( *theMainWindow->getSurfaceActions()->getFlatMultiresolutionMorphingObject()); QTime flatTimer; flatTimer.start(); try { flatMRM.execute(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(theMainWindow, "Error", e.whatQString()); return; } const float flatElapsedTime = flatTimer.elapsed() * 0.001; // // Execute spherical morphing // BrainModelSurfaceMultiresolutionMorphing sphericalMRM( theMainWindow->getBrainSet(), fiducialSurface, sphericalSurface, BrainModelSurfaceMorphing::MORPHING_SURFACE_SPHERICAL); sphericalMRM.copyParameters( *theMainWindow->getSurfaceActions()->getSphericalMultiresolutionMorphingObject()); QTime sphericalTimer; sphericalTimer.start(); try { sphericalMRM.execute(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(theMainWindow, "Error", e.whatQString()); return; } const float sphericalElapsedTime = sphericalTimer.elapsed() * 0.001; QApplication::restoreOverrideCursor(); // // Pop up the flat morphing measurements dialog // std::vector fmm; flatMRM.getMorphingMeasurements(fmm); GuiMorphingMeasurementsDialog* fmmd = new GuiMorphingMeasurementsDialog(fmm, flatElapsedTime, BrainModelSurfaceMorphing::MORPHING_SURFACE_FLAT, true, theMainWindow); fmmd->show(); // // Pop up the spherical morphing measurements dialog // std::vector smm; sphericalMRM.getMorphingMeasurements(smm); GuiMorphingMeasurementsDialog* smmd = new GuiMorphingMeasurementsDialog(smm, sphericalElapsedTime, BrainModelSurfaceMorphing::MORPHING_SURFACE_SPHERICAL, true, theMainWindow); smmd->show(); // // Notify about modified files and redraw all displays // GuiFilesModified fm; fm.setCoordinateModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(NULL); // // Display the flat surface // flatSurface = theMainWindow->getBrainSet()->getBrainModelSurfaceOfType(BrainModelSurface::SURFACE_TYPE_FLAT); theMainWindow->displayBrainModelInMainWindow(flatSurface); showCrossovers(flatSurface); QApplication::restoreOverrideCursor(); theMainWindow->speakText("Ready to align surfaces.", false); // // Show dialog to align flat and spherical surfaces // QApplication::restoreOverrideCursor(); GuiMainWindowSurfaceActions* surfaceActions = theMainWindow->getSurfaceActions(); surfaceActions->slotAlignSurfacesToStandardOrientation(); } break; } } // // update display control dialog and update graphics // theMainWindow->updateDisplayControlDialog(); GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); QDialog::done(r); } /** * show crossovers on surface. */ void GuiFlattenHemisphereInstructionsDialog::showCrossovers(BrainModelSurface* bmsIn) { // // Do crossover check and set overlay node coloring to crossovers // BrainModelSurface* bms = bmsIn; if (bms == NULL) { bms = theMainWindow->getBrainSet()->getBrainModelSurface( theMainWindow->getBrainSet()->getNumberOfBrainModels() - 1); } if (bms != NULL) { int numTileCrossovers, numNodeCrossovers; bms->crossoverCheck(numTileCrossovers, numNodeCrossovers, BrainModelSurface::SURFACE_TYPE_FLAT); } int modelIndex = -1; // -1 -> all models BrainModelSurfaceNodeColoring* bsnc = theMainWindow->getBrainSet()->getNodeColoring(); theMainWindow->getBrainSet()->getSecondarySurfaceOverlay()->setOverlay(modelIndex, BrainModelSurfaceOverlay::OVERLAY_NONE); theMainWindow->getBrainSet()->getPrimarySurfaceOverlay()->setOverlay(modelIndex, BrainModelSurfaceOverlay::OVERLAY_SHOW_CROSSOVERS); bsnc->assignColors(); // // update display control dialog and update graphics // theMainWindow->updateDisplayControlDialog(); GuiBrainModelOpenGL::updateAllGL(NULL); } void GuiFlattenHemisphereInstructionsDialog::doFlattenFullHemispherePart2() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); try { algorithm->executePart2(); DisplaySettingsBorders* dsb = theMainWindow->getBrainSet()->getDisplaySettingsBorders(); dsb->setDisplayBorders(false); theMainWindow->updateDisplayControlDialog(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "Flatten Error", e.whatQString()); } delete algorithm; // // Notify about file changes // GuiFilesModified fm; fm.setCoordinateModified(); fm.setTopologyModified(); theMainWindow->fileModificationUpdate(fm); theMainWindow->displayBrainModelInMainWindow(-1); // // Do crossover check and set overlay node coloring to crossovers // BrainModelSurface* bms = theMainWindow->getBrainSet()->getBrainModelSurface( theMainWindow->getBrainSet()->getNumberOfBrainModels() - 1); int modelIndex = -1; if (bms != NULL) { int numTileCrossovers, numNodeCrossovers; bms->crossoverCheck(numTileCrossovers, numNodeCrossovers, BrainModelSurface::SURFACE_TYPE_FLAT); modelIndex = bms->getBrainModelIndex(); } BrainModelSurfaceNodeColoring* bsnc = theMainWindow->getBrainSet()->getNodeColoring(); bsnc->assignColors(); if (theMainWindow->getBrainSet()->isASurfaceOverlay(modelIndex, BrainModelSurfaceOverlay::OVERLAY_SHOW_CROSSOVERS) == false) { theMainWindow->getBrainSet()->getSecondarySurfaceOverlay()->setOverlay(modelIndex, theMainWindow->getBrainSet()->getPrimarySurfaceOverlay()->getOverlay(modelIndex)); theMainWindow->getBrainSet()->getPrimarySurfaceOverlay()->setOverlay(modelIndex, BrainModelSurfaceOverlay::OVERLAY_SHOW_CROSSOVERS); } // // update display control dialog and update graphics // theMainWindow->updateDisplayControlDialog(); GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); } caret-5.6.4~dfsg.1.orig/caret/GuiFlattenHemisphereDialog.h0000664000175000017500000000445211572067322023231 0ustar michaelmichael #ifndef __GUI_FLATTEN_HEMISPHERE_DIALOG_H__ #define __GUI_FLATTEN_HEMISPHERE_DIALOG_H__ #include #include #include "WuQDialog.h" class GuiBrainModelSelectionComboBox; class QCheckBox; class QComboBox; class QGroupBox; class QLabel; class QLineEdit; /// Dialog for flattening hemispheres class GuiFlattenHemisphereDialog : public WuQDialog { Q_OBJECT public: /// type of flattening enum FLATTEN_TYPE { FLATTEN_TYPE_NONE, FLATTEN_TYPE_FULL_HEMISPHERE, FLATTEN_TYPE_FULL_HEMISPHERE_AND_MORPH_SPHERE, FLATTEN_TYPE_ELLIPSOID_PARTIAL_HEMISPHERE, FLATTEN_TYPE_FIDUCIAL_PARTIAL_HEMISPHERE }; /// Constructor GuiFlattenHemisphereDialog(QWidget* parent); /// Destructor ~GuiFlattenHemisphereDialog(); private slots: /// Called when user press OK or Cancel buttons void done(int r); /// called when a flatten type is selected void slotFlatTypeComboBox(int item); /// load the anterior commissure information from the params file void loadAnteriorCommissureInformation(); private: /// load the template border combo box void loadTemplateBorderComboBox(); /// type of flattening FLATTEN_TYPE flattenType; /// fiducial surface selection combo box GuiBrainModelSelectionComboBox* fiducialSurfaceComboBox; /// flattening surface selection combo box GuiBrainModelSelectionComboBox* flattenSurfaceComboBox; /// flatten type combo box QComboBox* flatTypeComboBox; /// full hemisphere parameters group box QGroupBox* fullHemisphereParamsGroupBox; /// Anterior commissure offset QLineEdit* acOffsetLineEdit[3]; /// Anterior commissure position QLineEdit* acPositionLineEdit[3]; /// template border type selection QComboBox* templateBorderComboBox; /// the template border files std::vector templateBorderFiles; /// the template border color files std::vector templateBorderColorFiles; /// smooth fiducial's medial wall check box QCheckBox* smoothFiducialMedialWallCheckBox; }; #endif // __GUI_FLATTEN_HEMISPHERE_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiFlattenHemisphereDialog.cxx0000664000175000017500000006153111572067322023605 0ustar michaelmichael #include #include #include #include #include #include #include #include #include #include #include "BrainSet.h" #include "GuiBrainModelOpenGL.h" #include "GuiBrainModelSelectionComboBox.h" #include "BrainModelBorderSet.h" #include "BrainModelSurfaceFlattenFullHemisphere.h" #include "BrainModelSurfaceFlattenPartialHemisphere.h" #include "BrainModelSurfaceNodeColoring.h" #include "FileUtilities.h" #include "GuiFilesModified.h" #include "GuiFlattenHemisphereDialog.h" #include "GuiFlattenHemisphereInstructionsDialog.h" #include "GuiMainWindow.h" #include "PaintFile.h" #include "ParamsFile.h" #include "QtUtilities.h" #include "TopologyFile.h" #include "global_variables.h" /** * Constructor */ GuiFlattenHemisphereDialog::GuiFlattenHemisphereDialog(QWidget* parent) : WuQDialog(parent) { setModal(true); setWindowTitle("Flatten Full or Partial Hemisphere"); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // Group box for flattening type // QGroupBox* flatTypeGroupBox = new QGroupBox("Flattening Type"); dialogLayout->addWidget(flatTypeGroupBox); QVBoxLayout* flatTypeGroupLayout = new QVBoxLayout(flatTypeGroupBox); // // Combo box for flattening type selection // flatTypeComboBox = new QComboBox; flatTypeGroupLayout->addWidget(flatTypeComboBox); flatTypeComboBox->addItem("Select Type", FLATTEN_TYPE_NONE); flatTypeComboBox->addItem("Full Hemisphere (Ellipsoid)", FLATTEN_TYPE_FULL_HEMISPHERE); flatTypeComboBox->addItem("Full Hemisphere (Ellipsoid) and Morph Sphere", FLATTEN_TYPE_FULL_HEMISPHERE_AND_MORPH_SPHERE); flatTypeComboBox->addItem("Partial Hemsiphere (Ellipsoid)", FLATTEN_TYPE_ELLIPSOID_PARTIAL_HEMISPHERE); flatTypeComboBox->addItem("Partial Hemisphere (Fiducial)", FLATTEN_TYPE_FIDUCIAL_PARTIAL_HEMISPHERE); QObject::connect(flatTypeComboBox, SIGNAL(activated(int)), this, SLOT(slotFlatTypeComboBox(int))); // // Group box for surfaces // QGroupBox* surfaceGroupBox = new QGroupBox("Surfaces"); dialogLayout->addWidget(surfaceGroupBox); QGridLayout* surfaceGroupGridLayout = new QGridLayout(surfaceGroupBox); // // Fiducial surface // surfaceGroupGridLayout->addWidget(new QLabel("Fiducial Surface"), 0, 0); fiducialSurfaceComboBox = new GuiBrainModelSelectionComboBox( false, true, false, "", 0); QObject::connect(fiducialSurfaceComboBox, SIGNAL(activated(int)), this, SLOT(loadAnteriorCommissureInformation())); fiducialSurfaceComboBox->setSelectedBrainModel(theMainWindow->getBrainSet()->getActiveFiducialSurface()); surfaceGroupGridLayout->addWidget(fiducialSurfaceComboBox, 0, 1); // // flatten surface // surfaceGroupGridLayout->addWidget(new QLabel("Surface To Flatten"), 1, 0); flattenSurfaceComboBox = new GuiBrainModelSelectionComboBox(false, true, false, "", 0); surfaceGroupGridLayout->addWidget(flattenSurfaceComboBox); surfaceGroupBox->setFixedSize(surfaceGroupBox->sizeHint()); // // Vertical group for full hemisphere parameters // fullHemisphereParamsGroupBox = new QGroupBox("Full Hemisphere Parameters"); dialogLayout->addWidget(fullHemisphereParamsGroupBox); QVBoxLayout* fullHemisphereParamsLayout = new QVBoxLayout(fullHemisphereParamsGroupBox); // // grid for surfaces // QWidget* acGrid = new QWidget; QGridLayout* acGridLayout = new QGridLayout(acGrid); // // AC position // acPositionLineEdit[0] = new QLineEdit; acPositionLineEdit[0]->setFixedWidth(70); acPositionLineEdit[1] = new QLineEdit; acPositionLineEdit[1]->setFixedWidth(70); acPositionLineEdit[2] = new QLineEdit; acPositionLineEdit[2]->setFixedWidth(70); acGridLayout->addWidget(new QLabel("Anterior Commissure Position"), 0, 0); acGridLayout->addWidget(acPositionLineEdit[0], 0, 1); acGridLayout->addWidget(acPositionLineEdit[1], 0, 2); acGridLayout->addWidget(acPositionLineEdit[2], 0, 3); // // AC offset // acOffsetLineEdit[0] = new QLineEdit; acOffsetLineEdit[0]->setFixedWidth(70); acOffsetLineEdit[1] = new QLineEdit; acOffsetLineEdit[1]->setFixedWidth(70); acOffsetLineEdit[2] = new QLineEdit; acOffsetLineEdit[2]->setFixedWidth(70); acGridLayout->addWidget(new QLabel("Anterior Commissure Offset"), 1, 0); acGridLayout->addWidget(acOffsetLineEdit[0], 1, 1); acGridLayout->addWidget(acOffsetLineEdit[1], 1, 2); acGridLayout->addWidget(acOffsetLineEdit[2], 1, 3); // // squish the stuff together // acGrid->setFixedSize(acGrid->sizeHint()); // // Horizontal box for border label and combo box QHBoxLayout* borderHBoxLayout = new QHBoxLayout; fullHemisphereParamsLayout->addLayout(borderHBoxLayout); // // Label & Combo box for border selection // borderHBoxLayout->addWidget(new QLabel("Border Template Cuts")); templateBorderComboBox = new QComboBox; borderHBoxLayout->addWidget(templateBorderComboBox); borderHBoxLayout->setStretchFactor(templateBorderComboBox, 100); loadTemplateBorderComboBox(); // // Smooth fiducial medial wall check box // smoothFiducialMedialWallCheckBox = new QCheckBox("Smooth Fiducial Medial Wall"); fullHemisphereParamsLayout->addWidget(smoothFiducialMedialWallCheckBox); smoothFiducialMedialWallCheckBox->setChecked(true); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); dialogLayout->addLayout(buttonsLayout); // // OK button // QPushButton* okButton = new QPushButton("OK"); buttonsLayout->addWidget(okButton); QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); // // Cancel button // QPushButton* cancelButton = new QPushButton("Cancel"); buttonsLayout->addWidget(cancelButton); QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); QtUtilities::makeButtonsSameSize(okButton, cancelButton); // // Initialize some items // flattenType = FLATTEN_TYPE_NONE; slotFlatTypeComboBox(static_cast(FLATTEN_TYPE_NONE)); loadAnteriorCommissureInformation(); } /** * Destructor */ GuiFlattenHemisphereDialog::~GuiFlattenHemisphereDialog() { } /** * Load the full hemisphere border selection combo box with * the template border files from the caret home directory. */ void GuiFlattenHemisphereDialog::loadTemplateBorderComboBox() { // // First and second entries correspond to "Choose Template Borders" and // and use currently loaded borders. // templateBorderFiles.push_back(""); templateBorderFiles.push_back(""); templateBorderColorFiles.push_back(""); templateBorderColorFiles.push_back(""); templateBorderComboBox->addItem("Choose Template Borders"); templateBorderComboBox->addItem("Use Currently Loaded Ellipsoidal Borders"); // // Look for template borders in Caret installation directory. // QString templateBorderDirectory(theMainWindow->getBrainSet()->getCaretHomeDirectory()); templateBorderDirectory.append("/data_files/flatten_borders"); std::vector files; FileUtilities::findFilesInDirectory(templateBorderDirectory, QStringList("*.border"), files); // // Load template border information into combo box // for (unsigned int i = 0; i < files.size(); i++) { BorderFile bf; try { QString borderName(templateBorderDirectory); borderName.append("/"); borderName.append(files[i]); templateBorderFiles.push_back(borderName); bf.readFile(borderName); const QString descriptiveName(bf.getHeaderTag("descriptive_name")); if (descriptiveName.isEmpty() == false) { templateBorderComboBox->addItem(descriptiveName); } else { templateBorderComboBox->addItem(files[i]); } const QString colorName(bf.getHeaderTag("matching_color_file")); if (colorName.isEmpty() == false) { QString colorFileName(templateBorderDirectory); colorFileName.append("/"); colorFileName.append(colorName); templateBorderColorFiles.push_back(colorFileName); } else { templateBorderColorFiles.push_back(""); } } catch (FileException& /*e*/) { } } } /** * load the anterior commissure information from the params file. */ void GuiFlattenHemisphereDialog::loadAnteriorCommissureInformation() { ParamsFile* pf = theMainWindow->getBrainSet()->getParamsFile(); float ac[3]; if (pf->getParameter(ParamsFile::keyACx, ac[0]) && pf->getParameter(ParamsFile::keyACy, ac[1]) && pf->getParameter(ParamsFile::keyACz, ac[2])) { acPositionLineEdit[0]->setText(QString::number(ac[0], 'f', 1)); acPositionLineEdit[1]->setText(QString::number(ac[1], 'f', 1)); acPositionLineEdit[2]->setText(QString::number(ac[2], 'f', 1)); } acOffsetLineEdit[0]->setText("0.0"); acOffsetLineEdit[1]->setText("-10.0"); acOffsetLineEdit[2]->setText("10.0"); const BrainModelSurface* fid = fiducialSurfaceComboBox->getSelectedBrainModelSurface(); if (fid != NULL) { float bounds[6]; fid->getBounds(bounds); // // Check min/max Y coordinates // if ((bounds[2] < 0.0) && (bounds[3] > 0.0)) { // // Surface appears to have the Anterior Commissure as its origin // acPositionLineEdit[0]->setText("0"); acPositionLineEdit[1]->setText("0"); acPositionLineEdit[2]->setText("0"); } } } /** * Called when a flatten type is selected. */ void GuiFlattenHemisphereDialog::slotFlatTypeComboBox(int item) { flattenType = static_cast(item); fullHemisphereParamsGroupBox->setEnabled(false); switch(flattenType) { case FLATTEN_TYPE_NONE: break; case FLATTEN_TYPE_FULL_HEMISPHERE: case FLATTEN_TYPE_FULL_HEMISPHERE_AND_MORPH_SPHERE: flattenSurfaceComboBox->setSelectedBrainModel( theMainWindow->getBrainSet()->getBrainModelSurfaceOfType( BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL)); fullHemisphereParamsGroupBox->setEnabled(true); break; case FLATTEN_TYPE_ELLIPSOID_PARTIAL_HEMISPHERE: flattenSurfaceComboBox->setSelectedBrainModel( theMainWindow->getBrainSet()->getBrainModelSurfaceOfType( BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL)); break; case FLATTEN_TYPE_FIDUCIAL_PARTIAL_HEMISPHERE: flattenSurfaceComboBox->setSelectedBrainModel(theMainWindow->getBrainSet()->getActiveFiducialSurface()); break; } loadAnteriorCommissureInformation(); } /** * Called when OK or Cancel buttons pressed */ void GuiFlattenHemisphereDialog::done(int r) { if (r == QDialog::Accepted) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); // // border file used during full hemisphere flattening // BorderFile* flattenBorderFile = NULL; bool flattenBordersUseTemplateFile = false; // // Get the selected surfaces // BrainModelSurface* fiducialSurface = fiducialSurfaceComboBox->getSelectedBrainModelSurface(); BrainModelSurface* flattenSurface = flattenSurfaceComboBox->getSelectedBrainModelSurface(); // // declare the border file here so that it is in scope when execute is called // BorderFile borderFile; // // Create the algorithm // BrainModelAlgorithm* bma = NULL; switch(flattenType) { case FLATTEN_TYPE_NONE: { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "Flatten Error", "You must select a flattening type."); return; } break; case FLATTEN_TYPE_ELLIPSOID_PARTIAL_HEMISPHERE: bma = new BrainModelSurfaceFlattenPartialHemisphere( fiducialSurface, flattenSurface, BrainModelSurfaceFlattenPartialHemisphere::FLATTEN_TYPE_ELLIPSOID); break; case FLATTEN_TYPE_FIDUCIAL_PARTIAL_HEMISPHERE: bma = new BrainModelSurfaceFlattenPartialHemisphere( fiducialSurface, flattenSurface, BrainModelSurfaceFlattenPartialHemisphere::FLATTEN_TYPE_FIDUCIAL); break; case FLATTEN_TYPE_FULL_HEMISPHERE: case FLATTEN_TYPE_FULL_HEMISPHERE_AND_MORPH_SPHERE: { PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); if (pf->getNumberOfColumns() <= 0) { QApplication::restoreOverrideCursor(); if (QMessageBox::question(this, "Paint File Query", "There is no paint file loaded. The paint file may assist " "you in identifying cortical areas. Do you want to continue " "or do you want to cancel and load a paint file ?", (QMessageBox::Ok | QMessageBox::Cancel), QMessageBox::Ok) == QMessageBox::Cancel) { return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); } const int templateBorderIndex = templateBorderComboBox->currentIndex(); if (templateBorderIndex <= 0) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "Missing Borders", "You must selecte template borders."); return; } else if (templateBorderIndex == 1) { BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); flattenBorderFile = bmbs->copyBordersOfSpecifiedType(BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL); if (flattenBorderFile == NULL) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "Missing Borders", "There are no ellipsoidal borders loaded."); return; } } else { flattenBorderFile = new BorderFile; try { flattenBorderFile->readFile(templateBorderFiles[templateBorderIndex]); flattenBordersUseTemplateFile = true; } catch (FileException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "Missing Borders", e.whatQString()); return; } try { theMainWindow->getBrainSet()->readBorderColorFile(templateBorderColorFiles[templateBorderIndex], false, false); } catch (FileException& /*e*/) { } } // // Check for topological errors // if (flattenSurface != NULL) { const TopologyFile* tf = flattenSurface->getTopologyFile(); if (tf != NULL) { int faces, vertices, edges, eulerCount, numberOfHoles, numberOfObjects; tf->getEulerCount(false, faces, vertices, edges, eulerCount, numberOfHoles, numberOfObjects); if (numberOfHoles > 0) { const QString msg = (QString("There appear to be ") + QString::number(numberOfHoles) + " handles (topological errors) in the surface." " These handles may cause problems " " during surface flattening.\n\n" "Do you want to continue?"); QApplication::restoreOverrideCursor(); if (QMessageBox::warning(this, "Toplogical Errors", msg, (QMessageBox::Yes | QMessageBox::No), QMessageBox::No) == QMessageBox::No) { return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); } } } // // Get the Anterior Commissure position and offset // float acPosition[3]; float acOffset[3]; acPosition[0] = acPositionLineEdit[0]->text().toFloat(); acPosition[1] = acPositionLineEdit[1]->text().toFloat(); acPosition[2] = acPositionLineEdit[2]->text().toFloat(); acOffset[0] = acOffsetLineEdit[0]->text().toFloat(); acOffset[1] = acOffsetLineEdit[1]->text().toFloat(); acOffset[2] = acOffsetLineEdit[2]->text().toFloat(); if ((acPosition[0] == 0.0) && (acPosition[1] == 0.0) && (acPosition[2] == 0.0)) { QApplication::restoreOverrideCursor(); if (QMessageBox::warning(this, "Missing AC", "The Anterior Commissure position is (0.0, 0.0, 0.0).\n" "Is this correct?", (QMessageBox::Yes | QMessageBox::No), QMessageBox::No) == QMessageBox::No) { return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); } // // Create the flattening algorithm // bma = new BrainModelSurfaceFlattenFullHemisphere( fiducialSurface, flattenSurface, flattenBorderFile, acPosition, acOffset, smoothFiducialMedialWallCheckBox->isChecked()); } break; } try { bma->execute(); if (flattenBordersUseTemplateFile) { if (flattenBorderFile != NULL) { delete flattenBorderFile; } } // // Do crossover check and set overlay node coloring to crossovers // BrainModelSurface* bms = theMainWindow->getBrainSet()->getBrainModelSurface( theMainWindow->getBrainSet()->getNumberOfBrainModels() - 1); if (bms != NULL) { int numTileCrossovers, numNodeCrossovers; bms->crossoverCheck(numTileCrossovers, numNodeCrossovers, BrainModelSurface::SURFACE_TYPE_FLAT); } int modelIndex = -1; // -1 -> all models BrainModelSurfaceNodeColoring* bsnc = theMainWindow->getBrainSet()->getNodeColoring(); theMainWindow->getBrainSet()->getSecondarySurfaceOverlay()->setOverlay(modelIndex, BrainModelSurfaceOverlay::OVERLAY_NONE); theMainWindow->getBrainSet()->getPrimarySurfaceOverlay()->setOverlay(modelIndex, BrainModelSurfaceOverlay::OVERLAY_SHOW_CROSSOVERS); bsnc->assignColors(); // // update display control dialog and update graphics // theMainWindow->updateDisplayControlDialog(); GuiBrainModelOpenGL::updateAllGL(NULL); // // Do not delete the flattening algorithm for the full // hemisphere since there is more to do. // switch(flattenType) { case FLATTEN_TYPE_NONE: break; case FLATTEN_TYPE_ELLIPSOID_PARTIAL_HEMISPHERE: case FLATTEN_TYPE_FIDUCIAL_PARTIAL_HEMISPHERE: { // // Popup instructions for post initial flattening // GuiFlattenHemisphereInstructionsDialog* hid = new GuiFlattenHemisphereInstructionsDialog(theMainWindow, NULL, GuiFlattenHemisphereInstructionsDialog::DIALOG_MODE_FLATTEN_POST_INITIAL_FLAT_PART_HEM); hid->setAttribute(Qt::WA_DeleteOnClose); hid->show(); delete bma; } break; case FLATTEN_TYPE_FULL_HEMISPHERE: { // // Popup instructions for second half of full // hemisphere initial flattening // GuiFlattenHemisphereInstructionsDialog* hid = new GuiFlattenHemisphereInstructionsDialog(theMainWindow, dynamic_cast(bma), GuiFlattenHemisphereInstructionsDialog::DIALOG_MODE_FLATTEN_FULL_HEMISPHERE_PART2); hid->setAttribute(Qt::WA_DeleteOnClose); hid->show(); } break; case FLATTEN_TYPE_FULL_HEMISPHERE_AND_MORPH_SPHERE: { // // Popup instructions for second half of full // hemisphere initial flattening // GuiFlattenHemisphereInstructionsDialog* hid = new GuiFlattenHemisphereInstructionsDialog(theMainWindow, dynamic_cast(bma), GuiFlattenHemisphereInstructionsDialog::DIALOG_MODE_FLATTEN_FULL_HEMISPHERE_MORPH_SPHERE_PART2); hid->setAttribute(Qt::WA_DeleteOnClose); hid->show(); } break; } } catch (BrainModelAlgorithmException& e) { delete bma; QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "Error", e.whatQString()); return; } // // Notify about file changes // GuiFilesModified fm; fm.setCoordinateModified(); fm.setTopologyModified(); theMainWindow->fileModificationUpdate(fm); theMainWindow->displayBrainModelInMainWindow(-1); // // Do crossover check and set overlay node coloring to crossovers // BrainModelSurface* bms = theMainWindow->getBrainSet()->getBrainModelSurface( theMainWindow->getBrainSet()->getNumberOfBrainModels() - 1); if (bms != NULL) { int numTileCrossovers, numNodeCrossovers; bms->crossoverCheck(numTileCrossovers, numNodeCrossovers, BrainModelSurface::SURFACE_TYPE_FLAT); } int modelIndex = -1; // -1 -> all models BrainModelSurfaceNodeColoring* bsnc = theMainWindow->getBrainSet()->getNodeColoring(); theMainWindow->getBrainSet()->getSecondarySurfaceOverlay()->setOverlay(modelIndex, BrainModelSurfaceOverlay::OVERLAY_NONE); theMainWindow->getBrainSet()->getPrimarySurfaceOverlay()->setOverlay(modelIndex, BrainModelSurfaceOverlay::OVERLAY_SHOW_CROSSOVERS); bsnc->assignColors(); // // update display control dialog and update graphics // theMainWindow->updateDisplayControlDialog(); GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); } QDialog::done(r); } caret-5.6.4~dfsg.1.orig/caret/GuiFlattenFullHemisphereDialog.h0000664000175000017500000004202711572067322024054 0ustar michaelmichael #ifndef __GUI_FLATTEN_FULL_HEMISPHERE_DIALOG_H__ #define __GUI_FLATTEN_FULL_HEMISPHERE_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "WuQWizard.h" class BrainModelSurface; class BrainModelSurfaceMultiresolutionMorphing; class GuiBrainModelSurfaceSelectionComboBox; class GuiFlattenFullHemisphereBorderUpdatePage; class GuiFlattenFullHemisphereFiducialPage; class GuiFlattenFullHemisphereFinishedPage; class GuiFlattenFullHemisphereInitialFlatPage; class GuiFlattenFullHemisphereIntroPage; class GuiFlattenFullHemisphereMultiresolutionMorphingPage; class GuiFlattenFullHemisphereSettingsPage; class GuiFlattenFullHemisphereStartFlatteningPage; class GuiFlattenFullHemisphereSurfaceAlignmentPage; class GuiFlattenFullHemisphereSphericalPage; class GuiFlattenFullHemisphereTemplateCutsPage; class QCheckBox; class QLabel; /// class for dialog that flattens a full hemisphere class GuiFlattenFullHemisphereDialog : public WuQWizard { Q_OBJECT public: // constructor GuiFlattenFullHemisphereDialog(QWidget* parent = 0); // destructor ~GuiFlattenFullHemisphereDialog(); // update the dialog void updateDialog(); // get the fiducial surface BrainModelSurface* getFiducialSurface(); // get the inflated surface BrainModelSurface* getInflatedSurface(); // get the very inflated surface BrainModelSurface* getVeryInflatedSurface(); // get the spherical surface BrainModelSurface* getSphericalSurface(); // get the auto save files status bool getAutoSaveFilesSelected() const; // called to validate the current page bool validateCurrentPage(); // save new surfaces void saveSurfaces(const int indexOfFirstCoordinateFileToSave, const int indexOfFirstTopologyFileToSave = -1); // set the central sulcus ventral tip node number void setCentralSulcusVentralTip(const int nodeNum); // set the central sulcus dorsal-medial tip node number void setCentralSulcusDorsalMedialTip(const int nodeNum); // show the first page void showFirstPage(); public slots: /// called when cancel button pressed void reject(); protected: // save borders, if needed void saveNewBorders(); /// intro page GuiFlattenFullHemisphereIntroPage* introPage; /// settings page GuiFlattenFullHemisphereSettingsPage* settingsPage; /// topology page GuiFlattenFullHemisphereFiducialPage* fiducialSurfacePage; /// surface page GuiFlattenFullHemisphereSphericalPage* sphericalSurfacePage; /// template cuts page GuiFlattenFullHemisphereTemplateCutsPage* templateCutsPage; /// border draw and update page GuiFlattenFullHemisphereBorderUpdatePage* borderDrawAndUpdatePage; /// surface alignment page GuiFlattenFullHemisphereSurfaceAlignmentPage* surfaceAlignmentPage; /// start flattening page GuiFlattenFullHemisphereStartFlatteningPage* startFlatteningPage; /// initial flat page GuiFlattenFullHemisphereInitialFlatPage* initialFlatPage; /// multiresolution morph page GuiFlattenFullHemisphereMultiresolutionMorphingPage* multiMorphPage; /// finished page GuiFlattenFullHemisphereFinishedPage* finishedPage; /// flat multi-resolution morphing parameters BrainModelSurfaceMultiresolutionMorphing* flatParameters; /// spherical multi-resolution morphing parameters BrainModelSurfaceMultiresolutionMorphing* sphericalParameters; }; /// class for introduction page class GuiFlattenFullHemisphereIntroPage : public QWizardPage { Q_OBJECT public: // constructor GuiFlattenFullHemisphereIntroPage(QWidget* parent = 0); // destructor ~GuiFlattenFullHemisphereIntroPage(); // cleanup page (called when showing page after "Back" pressed) void cleanupPage(); // initialize the page (called when showing page after "Next" pressed) void initializePage(); // page is complete bool isComplete(); // validate a page bool validatePage(); protected: }; /// class for settings class GuiFlattenFullHemisphereSettingsPage : public QWizardPage { Q_OBJECT public: // constructor GuiFlattenFullHemisphereSettingsPage(QWidget* parent = 0); // destructor ~GuiFlattenFullHemisphereSettingsPage(); // get the auto save files checkbox status bool getAutoSaveFilesSelected() const; // get the create fiducial with smoothed medial wall checkbox status bool getCreateFiducialWithSmoothedMedialWallSelected() const; // cleanup page (called when showing page after "Back" pressed) void cleanupPage(); // initialize the page (called when showing page after "Next" pressed) void initializePage(); // page is complete bool isComplete(); // validate a page bool validatePage(); signals: /// emitted when "complete" status of page changes void completeChanged(); protected: /// auto save files check box QCheckBox* autoSaveFilesCheckBox; // smooth medial wall check box QCheckBox* smoothMedialWallCheckBox; }; /// class for topology class GuiFlattenFullHemisphereFiducialPage : public QWizardPage { Q_OBJECT public: // constructor GuiFlattenFullHemisphereFiducialPage(QWidget* parent = 0); // destructor ~GuiFlattenFullHemisphereFiducialPage(); // cleanup page (called when showing page after "Back" pressed) void cleanupPage(); // initialize the page (called when showing page after "Next" pressed) void initializePage(); // page is complete bool isComplete(); // validate a page bool validatePage(); // get the fiducial surface BrainModelSurface* getFiducialSurface(); signals: /// emitted when "complete" status of page changes void completeChanged(); protected: /// surface selection combo box GuiBrainModelSurfaceSelectionComboBox* fiducialSurfaceComboBox; }; /// class for verifying surfaces class GuiFlattenFullHemisphereSphericalPage : public QWizardPage { Q_OBJECT public: // constructor GuiFlattenFullHemisphereSphericalPage(QWidget* parent = 0); // destructor ~GuiFlattenFullHemisphereSphericalPage(); // get the spherical surface BrainModelSurface* getSphericalSurface(); // get the inflated surface BrainModelSurface* getInflatedSurface(); // get the very inflated surface BrainModelSurface* getVeryInflatedSurface(); // cleanup page (called when showing page after "Back" pressed) void cleanupPage(); // initialize the page (called when showing page after "Next" pressed) void initializePage(); // page is complete bool isComplete(); // validate a page bool validatePage(); signals: /// emitted when "complete" status of page changes void completeChanged(); protected slots: // called when generate surfaces button clicked void slotGenerateSurfacesPushButton(); protected: /// surface selection combo box GuiBrainModelSurfaceSelectionComboBox* inflatedSurfaceComboBox; /// surface selection combo box GuiBrainModelSurfaceSelectionComboBox* veryInflatedSurfaceComboBox; /// surface selection combo box GuiBrainModelSurfaceSelectionComboBox* sphericalSurfaceComboBox; }; /// class for generating template cuts class GuiFlattenFullHemisphereTemplateCutsPage : public QWizardPage { Q_OBJECT public: // constructor GuiFlattenFullHemisphereTemplateCutsPage(QWidget* parent = 0); // destructor ~GuiFlattenFullHemisphereTemplateCutsPage(); // cleanup page (called when showing page after "Back" pressed) void cleanupPage(); // initialize the page (called when showing page after "Next" pressed) void initializePage(); // page is complete bool isComplete(); // validate a page bool validatePage(); signals: /// emitted when "complete" status of page changes void completeChanged(); protected slots: // called to add border template cuts void slotAddTemplateCutBordersPushButton(); // called to add landmark border cuts void slotAddLandmarkBordersPushButton(); protected: }; /// class for drawing updating medial wall and cuts class GuiFlattenFullHemisphereBorderUpdatePage : public QWizardPage { Q_OBJECT public: // constructor GuiFlattenFullHemisphereBorderUpdatePage(QWidget* parent = 0); // destructor ~GuiFlattenFullHemisphereBorderUpdatePage(); // cleanup page (called when showing page after "Back" pressed) void cleanupPage(); // initialize the page (called when showing page after "Next" pressed) void initializePage(); // page is complete bool isComplete(); // validate a page bool validatePage(); signals: /// emitted when "complete" status of page changes void completeChanged(); protected slots: // called when draw borders button pressed void slotDrawBordersPushButton(); // called when update borders button pressed void slotUpdateBordersPushButton(); // called when example images button pressed void slotBorderExampleImages(); // called when show only flattening borders selected void slotShowOnlyFlattenBordersPushButton(); protected: }; /// class for cleaning up initial flat surface class GuiFlattenFullHemisphereInitialFlatPage : public QWizardPage { Q_OBJECT public: // constructor GuiFlattenFullHemisphereInitialFlatPage(QWidget* parent = 0); // destructor ~GuiFlattenFullHemisphereInitialFlatPage(); // cleanup page (called when showing page after "Back" pressed) void cleanupPage(); // initialize the page (called when showing page after "Next" pressed) void initializePage(); // page is complete bool isComplete(); // validate a page bool validatePage(); signals: /// emitted when "complete" status of page changes void completeChanged(); protected: }; /// class for starting flattening surface class GuiFlattenFullHemisphereStartFlatteningPage : public QWizardPage { Q_OBJECT public: // constructor GuiFlattenFullHemisphereStartFlatteningPage(QWidget* parent = 0); // destructor ~GuiFlattenFullHemisphereStartFlatteningPage(); // cleanup page (called when showing page after "Back" pressed) void cleanupPage(); // initialize the page (called when showing page after "Next" pressed) void initializePage(); // page is complete bool isComplete(); // validate a page bool validatePage(); // get loaded flattening borders void getLoadedFlatteningBorders(std::vector& flattenBorderNamesOut) const; signals: /// emitted when "complete" status of page changes void completeChanged(); protected: /// names of borders that will be used QLabel* bordersListLabel; }; /// class for multi-resolution morphing class GuiFlattenFullHemisphereMultiresolutionMorphingPage : public QWizardPage { Q_OBJECT public: // constructor GuiFlattenFullHemisphereMultiresolutionMorphingPage( BrainModelSurfaceMultiresolutionMorphing* flatParametersIn, BrainModelSurfaceMultiresolutionMorphing* sphericalParametersIn, QWidget* parent = 0); // destructor ~GuiFlattenFullHemisphereMultiresolutionMorphingPage(); // cleanup page (called when showing page after "Back" pressed) void cleanupPage(); // initialize the page (called when showing page after "Next" pressed) void initializePage(); // page is complete bool isComplete(); // validate a page bool validatePage(); // is flat multi-res morphing selected bool getDoFlatMultiResMorphing() const; // is spherical multi-res morphing selected bool getDoSphericalMultiResMorphing() const; signals: /// emitted when "complete" status of page changes void completeChanged(); protected slots: // called to adjust flat multi-res morph parameters void slotFlatParamsPushButton(); // called to adjust spherical multi-res morph parameters void slotSphericalParamsPushButton(); protected: /// perform flat multi-res morphing check box QCheckBox* flatMultiMorphCheckBox; /// perform spherical multi-res morphing check box QCheckBox* sphericalMultiMorphCheckBox; /// flat multi-resolution morphing parameters BrainModelSurfaceMultiresolutionMorphing* flatParameters; /// spherical multi-resolution morphing parameters BrainModelSurfaceMultiresolutionMorphing* sphericalParameters; }; /// class for standard surface alignment page class GuiFlattenFullHemisphereSurfaceAlignmentPage : public QWizardPage { Q_OBJECT public: // constructor GuiFlattenFullHemisphereSurfaceAlignmentPage(QWidget* parent = 0); // destructor ~GuiFlattenFullHemisphereSurfaceAlignmentPage(); // cleanup page (called when showing page after "Back" pressed) void cleanupPage(); // initialize the page (called when showing page after "Next" pressed) void initializePage(); // page is complete bool isComplete(); // validate a page bool validatePage(); // get the central suclus ventral and dorsal-medial tips void getCentralSulcusTips(int& ventralTipNodeNumberOut, int& dorsalMedialTipNodeNumberOut) const; // set the central sulcus ventral tip void setCentralSulcusVentralTip(const int nodeNum); // set the central sulcus dorsal-medial tip void setCentralSulcusDorsalMedialTip(const int nodeNum); signals: /// emitted when "complete" status of page changes void completeChanged(); protected slots: // called when enable mouse button pressed void slotEnableMousePushButton(); // called when Use LANDMARK.CentralSulcus button pressed void slotUseLandmarkCentralSulcusPushButton(); protected: // update the ces node numbers void updateCentralSulcusLabels(); /// Use LANDMARK.CentralSulcus button QPushButton* useLandmarkCentralSulcusPushButton; /// ventral node label QLabel* ventralNodeLabel; /// dorsal-medial node Label QLabel* dorsalMedialNodeLabel; /// ventral tip node number int ventralTipNodeNumber; /// dorsal-medial tip node number int dorsalMedialTipNodeNumber; }; /// class for finished page class GuiFlattenFullHemisphereFinishedPage : public QWizardPage { Q_OBJECT public: // constructor GuiFlattenFullHemisphereFinishedPage(QWidget* parent = 0); // destructor ~GuiFlattenFullHemisphereFinishedPage(); // cleanup page (called when showing page after "Back" pressed) void cleanupPage(); // initialize the page (called when showing page after "Next" pressed) void initializePage(); // page is complete bool isComplete(); // validate a page bool validatePage(); signals: /// emitted when "complete" status of page changes void completeChanged(); }; #endif // __GUI_FLATTEN_FULL_HEMISPHERE_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiFlattenFullHemisphereDialog.cxx0000664000175000017500000023317511572067322024435 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "AreaColorFile.h" #include "BorderColorFile.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceBorderLandmarkIdentification.h" #include "BrainModelSurfaceFlattenHemisphere.h" #include "BrainModelSurfaceMultiresolutionMorphing.h" #include "BrainModelSurfaceNodeColoring.h" #include "BrainModelSurfaceOverlay.h" #include "BrainSet.h" #include "DisplaySettingsBorders.h" #include "GuiBorderOperationsDialog.h" #include "GuiBrainModelOpenGL.h" #include "GuiBrainModelSurfaceSelectionComboBox.h" #include "GuiFilesModified.h" #include "GuiFlattenFullHemisphereDialog.h" #include "GuiMainWindow.h" #include "GuiMainWindowSurfaceActions.h" #include "GuiMorphingMeasurementsDialog.h" #include "GuiMultiresolutionMorphingDialog.h" #include "PaintFile.h" #include "QtUtilities.h" #include "TopologyFile.h" #include "VocabularyFile.h" #include "WuQDataEntryDialog.h" #include "WuQMessageBox.h" #include "global_variables.h" /** * constructor. */ GuiFlattenFullHemisphereDialog::GuiFlattenFullHemisphereDialog(QWidget* parent) : WuQWizard(parent) { setWindowTitle("Flatten Full Hemisphere"); flatParameters = new BrainModelSurfaceMultiresolutionMorphing( NULL, NULL, NULL, BrainModelSurfaceMorphing::MORPHING_SURFACE_FLAT, NULL); sphericalParameters = new BrainModelSurfaceMultiresolutionMorphing( NULL, NULL, NULL, BrainModelSurfaceMorphing::MORPHING_SURFACE_SPHERICAL, NULL); setOption(QWizard::NoCancelButton, false); setWizardStyle(ModernStyle); introPage = new GuiFlattenFullHemisphereIntroPage; addPage(introPage); settingsPage = new GuiFlattenFullHemisphereSettingsPage; addPage(settingsPage); fiducialSurfacePage = new GuiFlattenFullHemisphereFiducialPage; addPage(fiducialSurfacePage); sphericalSurfacePage = new GuiFlattenFullHemisphereSphericalPage; addPage(sphericalSurfacePage); templateCutsPage = new GuiFlattenFullHemisphereTemplateCutsPage; addPage(templateCutsPage); borderDrawAndUpdatePage = new GuiFlattenFullHemisphereBorderUpdatePage; addPage(borderDrawAndUpdatePage); surfaceAlignmentPage = new GuiFlattenFullHemisphereSurfaceAlignmentPage; addPage(surfaceAlignmentPage); startFlatteningPage = new GuiFlattenFullHemisphereStartFlatteningPage; addPage(startFlatteningPage); initialFlatPage = new GuiFlattenFullHemisphereInitialFlatPage; addPage(initialFlatPage); multiMorphPage = new GuiFlattenFullHemisphereMultiresolutionMorphingPage( flatParameters, sphericalParameters); addPage(multiMorphPage); finishedPage = new GuiFlattenFullHemisphereFinishedPage; addPage(finishedPage); } /** * destructor. */ GuiFlattenFullHemisphereDialog::~GuiFlattenFullHemisphereDialog() { if (flatParameters != NULL) { delete flatParameters; } if (sphericalParameters != NULL) { delete sphericalParameters; } } /** * show the first page. */ void GuiFlattenFullHemisphereDialog::showFirstPage() { restart(); } /** * called when cancel button pressed. */ void GuiFlattenFullHemisphereDialog::reject() { if ((currentPage() != introPage) && (currentPage() != finishedPage)) { if (WuQMessageBox::question(this, "ERROR", "Flattening is not complete. Stop Flattening?", WuQMessageBox::Yes | WuQMessageBox::No, WuQMessageBox::No) == WuQMessageBox::Yes) { QWizard::reject(); } else { return; } } QWizard::reject(); } /** * set the central sulcus ventral tip node number. */ void GuiFlattenFullHemisphereDialog::setCentralSulcusVentralTip(const int nodeNum) { surfaceAlignmentPage->setCentralSulcusVentralTip(nodeNum); } /** * set the central sulcus dorsal-medial tip node number. */ void GuiFlattenFullHemisphereDialog::setCentralSulcusDorsalMedialTip(const int nodeNum) { surfaceAlignmentPage->setCentralSulcusDorsalMedialTip(nodeNum); } /** * get the spherical surface. */ BrainModelSurface* GuiFlattenFullHemisphereDialog::getSphericalSurface() { return sphericalSurfacePage->getSphericalSurface(); } /** * get the inflated surface. */ BrainModelSurface* GuiFlattenFullHemisphereDialog::getInflatedSurface() { return sphericalSurfacePage->getInflatedSurface(); } /** * get the very inflated surface. */ BrainModelSurface* GuiFlattenFullHemisphereDialog::getVeryInflatedSurface() { return sphericalSurfacePage->getVeryInflatedSurface(); } /** * get the fiducial surface. */ BrainModelSurface* GuiFlattenFullHemisphereDialog::getFiducialSurface() { return fiducialSurfacePage->getFiducialSurface(); } /** * get the auto save files status. */ bool GuiFlattenFullHemisphereDialog::getAutoSaveFilesSelected() const { return settingsPage->getAutoSaveFilesSelected(); } /** * called to validate the current page. */ bool GuiFlattenFullHemisphereDialog::validateCurrentPage() { BrainSet* bs = theMainWindow->getBrainSet(); const QWizardPage* p = currentPage(); if (p == fiducialSurfacePage) { // // Verify fiducial surface with topology // BrainModelSurface* fiducialSurface = getFiducialSurface(); if (fiducialSurface== NULL) { WuQMessageBox::critical(this, "ERROR", "There must be a fiducial surface to continue."); return false; } const TopologyFile* tf = fiducialSurface->getTopologyFile(); if (tf == NULL) { WuQMessageBox::critical(this, "ERROR", "The fiducial surface has no topology."); return false; } // // Check topology // showWaitCursor(); int faces, vertices, edges, eulerCount, numberOfHoles, numberOfObjects; tf->getEulerCount(false, faces, vertices, edges, eulerCount, numberOfHoles, numberOfObjects); showNormalCursor(); QString msg; if (eulerCount != 2) { msg += "The surface is not topologically correct.\n"; } if (numberOfHoles > 0) { msg += "The surface contains " + QString::number(numberOfHoles) + " holes.\n"; } if (numberOfObjects > 1) { msg += "The surface contains " + QString::number(numberOfObjects) + " unconnected pieces.\n"; } if (msg.isEmpty() == false) { msg += "These problems should be corrected before continuing.\n\n" "Do you want to continue?"; if (WuQMessageBox::question(this, "INFO", msg, WuQMessageBox::Yes | WuQMessageBox::No, WuQMessageBox::No) == WuQMessageBox::No) { return false; } } } if (p == sphericalSurfacePage) { QString msg; if (getFiducialSurface() == NULL) { msg += "A Fiducial Surface is required.\n"; } if (getSphericalSurface() == NULL) { msg += "A Spherical Surface is required.\n"; } if (msg.isEmpty() == false) { WuQMessageBox::critical(this, "ERROR", msg); return false; } } if (p == templateCutsPage) { saveNewBorders(); } if (p == borderDrawAndUpdatePage) { saveNewBorders(); std::vector flattenBorderNames; startFlatteningPage->getLoadedFlatteningBorders(flattenBorderNames); bool haveMedialWallFlag = false; int numberOfCuts = 0; for (std::vector::iterator iter = flattenBorderNames.begin(); iter != flattenBorderNames.end(); iter++) { if (*iter == BrainModelSurfaceBorderLandmarkIdentification::getFlattenMedialWallBorderName()) { haveMedialWallFlag = true; } else if (iter->startsWith( BrainModelSurfaceBorderLandmarkIdentification::getFlattenStandardCutsBorderNamePrefix())) { numberOfCuts++; } } QString msg; if (haveMedialWallFlag == false) { msg += ("There is no medial wall border named \"" + BrainModelSurfaceBorderLandmarkIdentification::getFlattenMedialWallBorderName() + "\".\n"); } if (numberOfCuts < 1) { msg += ("There must be at least one cut border whose name begins with \"" + BrainModelSurfaceBorderLandmarkIdentification::getFlattenStandardCutsBorderNamePrefix() + "\".\n"); } if (msg.isEmpty() == false) { WuQMessageBox::critical(this, "ERROR", msg); return false; } } if (p == surfaceAlignmentPage) { int ventralNodeNumber = -1; int dorsalMedialNodeNumber = -1; surfaceAlignmentPage->getCentralSulcusTips(ventralNodeNumber, dorsalMedialNodeNumber); if ((ventralNodeNumber < 0) || (dorsalMedialNodeNumber < 0)) { WuQMessageBox::critical(this, "ERROR", "The nodes at the ventral and dorsal-medial ends of the Central Sulcus must be set."); return false; } } if (p == startFlatteningPage) { BorderProjectionFile flattenBorderProjections; bs->getBorderSet()->copyBordersToBorderProjectionFile( flattenBorderProjections); BrainModelSurfaceFlattenHemisphere flatten(bs, fiducialSurfacePage->getFiducialSurface(), sphericalSurfacePage->getSphericalSurface(), &flattenBorderProjections, bs->getPaintFile(), bs->getAreaColorFile(), settingsPage->getCreateFiducialWithSmoothedMedialWallSelected(), getAutoSaveFilesSelected()); try { showWaitCursor(); flatten.execute(); } catch (BrainModelAlgorithmException& e) { showNormalCursor(); WuQMessageBox::critical(this, "ERROR", e.whatQString()); return false; } theMainWindow->displayNewestSurfaceInMainWindow(); BrainModelSurface* initialFlatSurface = theMainWindow->getBrainModelSurface(); if (initialFlatSurface != NULL) { if (initialFlatSurface->getIsFlatSurface()) { int numTileCrossovers = 0, numNodeCrossovers = 0; initialFlatSurface->crossoverCheck(numTileCrossovers, numNodeCrossovers, initialFlatSurface->getSurfaceType()); if ((numNodeCrossovers > 0) || (numTileCrossovers > 0)) { bs->getPrimarySurfaceOverlay()->setOverlay(-1, BrainModelSurfaceOverlay::OVERLAY_SHOW_CROSSOVERS); theMainWindow->updateDisplayControlDialog(); BrainModelSurfaceNodeColoring* bsnc = theMainWindow->getBrainSet()->getNodeColoring(); bsnc->assignColors(); } } } DisplaySettingsBorders* dsb = bs->getDisplaySettingsBorders(); dsb->setDisplayBorders(false); GuiFilesModified fm; fm.setPaintModified(); fm.setAreaColorModified(); fm.setCoordinateModified(); fm.setTopologyModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); showNormalCursor(); } if (p == initialFlatPage) { saveSurfaces(0, 0); saveNewBorders(); } if (p == multiMorphPage) { showWaitCursor(); // // Create a central sulcus border for surface alignment // int ventralNodeNumber, dorsalNodeNumber; surfaceAlignmentPage->getCentralSulcusTips(ventralNodeNumber, dorsalNodeNumber); BorderProjection centralSulcusBorderProjection( BrainModelSurfaceBorderLandmarkIdentification::getCentralSulcusRegistrationLandmarkName()); BorderProjection* centralSulcusPointer = NULL; if ((ventralNodeNumber >= 0) && (dorsalNodeNumber >= 0)) { const int ventralVertices[3] = { ventralNodeNumber, ventralNodeNumber, ventralNodeNumber }; const float ventralAreas[3] = { 1.0, 0.0, 0.0 }; const int dorsalVertices[3] = { dorsalNodeNumber, dorsalNodeNumber, dorsalNodeNumber }; const float dorsalAreas[3] = { 1.0, 0.0, 0.0 }; BorderProjectionLink ventralLink(0, ventralVertices, ventralAreas, 1.0); BorderProjectionLink dorsalLink(0, dorsalVertices, dorsalAreas, 1.0); centralSulcusBorderProjection.addBorderProjectionLink(ventralLink); centralSulcusBorderProjection.addBorderProjectionLink(dorsalLink); centralSulcusPointer = ¢ralSulcusBorderProjection; } // // Measurements output by flat and spherical multi-res morph // std::vector flatMeasurements; std::vector sphericalMeasurements; float flatTime = 0.0, sphereTime = 0.0; // // Flat morphing // BrainModelSurface* surfaceToDisplay = NULL; if (multiMorphPage->getDoFlatMultiResMorphing()) { try { BrainModelSurfaceMultiresolutionMorphing morph(bs, fiducialSurfacePage->getFiducialSurface(), bs->getBrainModelSurfaceOfType( BrainModelSurface::SURFACE_TYPE_FLAT), BrainModelSurfaceMorphing::MORPHING_SURFACE_FLAT, centralSulcusPointer); morph.copyParameters(*flatParameters); morph.setAutoSaveAllFiles(getAutoSaveFilesSelected()); QTime flatTimer; flatTimer.start(); morph.execute(); flatTime = flatTimer.elapsed() * 0.001; morph.getMorphingMeasurements(flatMeasurements); surfaceToDisplay = bs->getBrainModelSurfaceOfType( BrainModelSurface::SURFACE_TYPE_FLAT); saveSurfaces(0, 0); } catch (BrainModelAlgorithmException& e) { showNormalCursor(); WuQMessageBox::critical(this, "ERROR", e.whatQString()); return false; } } // // spherical morphing // if (multiMorphPage->getDoSphericalMultiResMorphing()) { try { BrainModelSurfaceMultiresolutionMorphing morph(bs, fiducialSurfacePage->getFiducialSurface(), sphericalSurfacePage->getSphericalSurface(), BrainModelSurfaceMorphing::MORPHING_SURFACE_SPHERICAL, centralSulcusPointer); morph.copyParameters(*sphericalParameters); morph.setAutoSaveAllFiles(getAutoSaveFilesSelected()); QTime sphereTimer; sphereTimer.start(); morph.execute(); sphereTime = sphereTimer.elapsed() * 0.001; morph.getMorphingMeasurements(sphericalMeasurements); if (surfaceToDisplay == NULL) { surfaceToDisplay = bs->getBrainModelSurfaceOfType( BrainModelSurface::SURFACE_TYPE_SPHERICAL); } saveSurfaces(0, 0); } catch (BrainModelAlgorithmException& e) { showNormalCursor(); WuQMessageBox::critical(this, "ERROR", e.whatQString()); return false; } } if (surfaceToDisplay != NULL) { theMainWindow->displayBrainModelInMainWindow(surfaceToDisplay); } GuiFilesModified fm; fm.setCoordinateModified(); fm.setTopologyModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); if (flatMeasurements.empty() == false) { GuiMorphingMeasurementsDialog* flatMD = new GuiMorphingMeasurementsDialog(flatMeasurements, flatTime, BrainModelSurfaceMorphing::MORPHING_SURFACE_FLAT, true, this); flatMD->show(); } if (sphericalMeasurements.empty() == false) { GuiMorphingMeasurementsDialog* sphereMD = new GuiMorphingMeasurementsDialog(sphericalMeasurements, sphereTime, BrainModelSurfaceMorphing::MORPHING_SURFACE_SPHERICAL, true, this); sphereMD->show(); } saveNewBorders(); showNormalCursor(); } return true; } /** * update the dialog. */ void GuiFlattenFullHemisphereDialog::updateDialog() { const QWizardPage* p = currentPage(); if (p == introPage) { introPage->initializePage(); } else if (p == settingsPage) { settingsPage->initializePage(); } else if (p == fiducialSurfacePage) { fiducialSurfacePage->initializePage(); } else if (p == sphericalSurfacePage) { sphericalSurfacePage->initializePage(); } else if (p == templateCutsPage) { templateCutsPage->initializePage(); } else if (p == borderDrawAndUpdatePage) { borderDrawAndUpdatePage->initializePage(); } else if (p == surfaceAlignmentPage) { surfaceAlignmentPage->initializePage(); } else if (p == startFlatteningPage) { startFlatteningPage->initializePage(); } else if (p == initialFlatPage) { initialFlatPage->initializePage(); } else if (p == multiMorphPage) { multiMorphPage->initializePage(); } else if (p == finishedPage) { finishedPage->initializePage(); } else if (p != NULL) { std::cout << "PROGRAM ERROR: unknown page in " "GuiFlattenFullHemisphereDialog::updateDialog()" << std::endl; } } /** * save borders, if needed. */ void GuiFlattenFullHemisphereDialog::saveNewBorders() { // // Clear modification status of surface borders that may occur // after unprojecting borders // BrainSet* bs = theMainWindow->getBrainSet(); BrainModelBorderSet* bmbs = bs->getBorderSet(); bmbs->setAllBordersModifiedStatus(false); if (getAutoSaveFilesSelected() == false) { return; } if (bmbs->getProjectionsModified()) { try { QString projFileName; BrainModelBorderFileInfo* projInfo = bmbs->getBorderProjectionFileInfo(); if (projInfo->getFileName().isEmpty()) { BorderProjectionFile bpf; projFileName = bpf.makeDefaultFileName("TemplateBorders"); } else { projFileName = projInfo->getFileName(); } bs->writeBorderProjectionFile(projFileName, "", ""); } catch (FileException& e) { WuQMessageBox::critical(this, "ERROR", e.whatQString()); } } if (bs->getBorderColorFile()->getModified()) { try { bs->writeBorderColorFile(bs->getBorderColorFile()->getFileName()); } catch (FileException& e) { WuQMessageBox::critical(this, "ERROR", e.whatQString()); } } if (bs->getAreaColorFile()->getModified()) { try { bs->writeAreaColorFile(bs->getAreaColorFile()->getFileName()); } catch (FileException& e) { WuQMessageBox::critical(this, "ERROR", e.whatQString()); } } if (bs->getPaintFile()->getModified()) { try { bs->writePaintFile(bs->getPaintFile()->getFileName()); } catch (FileException& e) { WuQMessageBox::critical(this, "ERROR", e.whatQString()); } } if (bs->getVocabularyFile()->getModified()) { try { bs->writeVocabularyFile(bs->getVocabularyFile()->getFileName()); } catch (FileException& e) { WuQMessageBox::critical(this, "ERROR", e.whatQString()); } } } /** * save new surfaces. */ void GuiFlattenFullHemisphereDialog::saveSurfaces(const int indexOfFirstCoordinateFileToSave, const int indexOfFirstTopologyFileToSave) { if (getAutoSaveFilesSelected() == false) { return; } BrainSet* bs = theMainWindow->getBrainSet(); if (indexOfFirstCoordinateFileToSave >= 0) { for (int i = indexOfFirstCoordinateFileToSave; i < bs->getNumberOfBrainModels(); i++) { BrainModelSurface* bms = bs->getBrainModelSurface(i); if (bms != NULL) { CoordinateFile* cf = bms->getCoordinateFile(); if (cf->getModified()) { try { bs->writeCoordinateFile(cf->getFileName(), bms->getSurfaceType(), cf); } catch (FileException& e) { WuQMessageBox::critical(this, "ERROR", e.whatQString()); } } } } } if (indexOfFirstTopologyFileToSave >= 0) { for (int i = indexOfFirstTopologyFileToSave; i < bs->getNumberOfTopologyFiles(); i++) { TopologyFile* tf = bs->getTopologyFile(i); if (tf != NULL) { if (tf->getModified()) { try { bs->writeTopologyFile(tf->getFileName(), tf->getTopologyType(), tf); } catch (FileException& e) { WuQMessageBox::critical(this, "ERROR", e.whatQString()); } } } } } } //========================================================================= //========================================================================= //========================================================================= /** * constructor. */ GuiFlattenFullHemisphereIntroPage::GuiFlattenFullHemisphereIntroPage(QWidget* parent) : QWizardPage(parent) { setTitle("Introduction to Full Hemisphere Flattening"); const QString instructionsText = "This flattening process requires a topologically correct spherical surface, " "a closed border that " "encloses the medial wall, and several open borders that indicate where " "cuts are to be made. If the spherical surface or any of the borders are " "not present at this time, subsequent pages will allow you to generate " "these missing items."; QLabel* instructionsLabel = new QLabel; instructionsLabel->setText(instructionsText); instructionsLabel->setTextFormat(Qt::RichText); instructionsLabel->setWordWrap(true); QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(instructionsLabel); layout->addStretch(); } /** * destructor. */ GuiFlattenFullHemisphereIntroPage::~GuiFlattenFullHemisphereIntroPage() { } /** * cleanup page (called when showing page after "Back" pressed). */ void GuiFlattenFullHemisphereIntroPage::cleanupPage() { } /** * initialize the page (called when showing page after "Next" pressed). */ void GuiFlattenFullHemisphereIntroPage::initializePage() { } /** * page is complete. */ bool GuiFlattenFullHemisphereIntroPage::isComplete() { return true; } /** * validate a page. */ bool GuiFlattenFullHemisphereIntroPage::validatePage() { return true; } //========================================================================= //========================================================================= //========================================================================= /** * constructor. */ GuiFlattenFullHemisphereSettingsPage::GuiFlattenFullHemisphereSettingsPage(QWidget* parent) : QWizardPage(parent) { setTitle("Flattening Options"); const QString settingsText = "New data files will be generated during this process. If you would like " "these new data files saved, select the Auto Save Files option below.

    " ""; QLabel* settingsLabel = new QLabel; settingsLabel->setText(settingsText); settingsLabel->setTextFormat(Qt::RichText); settingsLabel->setWordWrap(true); autoSaveFilesCheckBox = new QCheckBox("Auto Save Files"); autoSaveFilesCheckBox->setChecked(true); smoothMedialWallCheckBox = new QCheckBox("Create Fiducial Surface with Smoothed Medial Wall"); smoothMedialWallCheckBox->setChecked(true); QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(settingsLabel); layout->addWidget(autoSaveFilesCheckBox); layout->addWidget(smoothMedialWallCheckBox); layout->addStretch(); } /** * destructor. */ GuiFlattenFullHemisphereSettingsPage::~GuiFlattenFullHemisphereSettingsPage() { } /** * get the auto save files checkbox status. */ bool GuiFlattenFullHemisphereSettingsPage::getAutoSaveFilesSelected() const { return autoSaveFilesCheckBox->isChecked(); } /** * get the create fiducial with smoothed medial wall checkbox status. */ bool GuiFlattenFullHemisphereSettingsPage::getCreateFiducialWithSmoothedMedialWallSelected() const { return smoothMedialWallCheckBox->isChecked(); } /** * cleanup page (called when showing page after "Back" pressed). */ void GuiFlattenFullHemisphereSettingsPage::cleanupPage() { } /** * initialize the page (called when showing page after "Next" pressed). */ void GuiFlattenFullHemisphereSettingsPage::initializePage() { } /** * page is complete. */ bool GuiFlattenFullHemisphereSettingsPage::isComplete() { return true; } /** * validate a page. */ bool GuiFlattenFullHemisphereSettingsPage::validatePage() { return true; } //========================================================================= //========================================================================= //========================================================================= /** * constructor. */ GuiFlattenFullHemisphereFiducialPage::GuiFlattenFullHemisphereFiducialPage(QWidget* parent) : QWizardPage(parent) { setTitle("Fiducial Surface"); const QString topologyText = "If the Fiducial Surface is not topologically correct, it will cause " "problems, possibly severe, during the flattening process. The " "topology will be checked when the Next button is pressed. If " "there are topolgical problems, you will have the option to cancel and " "correct the problems.

    " "A surface that is topologically correct contains no holes (also " "referred to as handles or topological defects) and one connected " "piece of surface. The best way to correct a topologically " "incorrect surface is to correct the errors in the segmentation volume " "and regenerate the surface. If the segmentation volume is not " "available or the errors are small, Surface Menu->Topology->Correct " " Fiducial Surface Topology should be able to correct the topological " "errors. If there are multiple unconnected pieces of surface (islands), " "Surface Menu->Topology->Remove Islands can remove the islands."; QLabel* topologyLabel = new QLabel; topologyLabel->setText(topologyText); topologyLabel->setTextFormat(Qt::RichText); topologyLabel->setWordWrap(true); // // Fiducial Surface selection // QLabel* fiducialSurfaceLabel = new QLabel("Fiducial"); fiducialSurfaceComboBox = new GuiBrainModelSurfaceSelectionComboBox( BrainModelSurface::SURFACE_TYPE_FIDUCIAL); QHBoxLayout* surfaceLayout = new QHBoxLayout; surfaceLayout->addWidget(fiducialSurfaceLabel); surfaceLayout->addWidget(fiducialSurfaceComboBox); surfaceLayout->addStretch(); QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(topologyLabel); layout->addLayout(surfaceLayout); layout->addStretch(); } /** * destructor. */ GuiFlattenFullHemisphereFiducialPage::~GuiFlattenFullHemisphereFiducialPage() { } /** * cleanup page (called when showing page after "Back" pressed). */ void GuiFlattenFullHemisphereFiducialPage::cleanupPage() { } /** * initialize the page (called when showing page after "Next" pressed). */ void GuiFlattenFullHemisphereFiducialPage::initializePage() { fiducialSurfaceComboBox->updateComboBox(); } /** * get the fiducial surface. */ BrainModelSurface* GuiFlattenFullHemisphereFiducialPage::getFiducialSurface() { return fiducialSurfaceComboBox->getSelectedBrainModelSurface(); } /** * page is complete. */ bool GuiFlattenFullHemisphereFiducialPage::isComplete() { return true; } /** * validate a page. */ bool GuiFlattenFullHemisphereFiducialPage::validatePage() { return true; } //========================================================================= //========================================================================= //========================================================================= /** * constructor. */ GuiFlattenFullHemisphereTemplateCutsPage::GuiFlattenFullHemisphereTemplateCutsPage(QWidget* parent) : QWizardPage(parent) { setTitle("Flattening Borders Generation"); QPushButton* addTemplateCutBordersPushButton = new QPushButton("Add Template Border Medial Wall and Cuts..."); addTemplateCutBordersPushButton->setFixedSize(addTemplateCutBordersPushButton->sizeHint()); addTemplateCutBordersPushButton->setAutoDefault(false); QObject::connect(addTemplateCutBordersPushButton, SIGNAL(clicked()), this, SLOT(slotAddTemplateCutBordersPushButton())); QPushButton* addLandmarkBordersPushButton = new QPushButton("Add Landmark Border Medial Wall and Cuts..."); addLandmarkBordersPushButton->setFixedSize(addLandmarkBordersPushButton->sizeHint()); addLandmarkBordersPushButton->setAutoDefault(false); QObject::connect(addLandmarkBordersPushButton, SIGNAL(clicked()), this, SLOT(slotAddLandmarkBordersPushButton())); const QString text = "Borders are needed that identify the medial wall and where cuts should " "be made. Pressing the \"Add Landmark Border Medial Wall and Cuts\" " "pushbutton will display controls for generating landmark borders. The " "landmark borders process examines the surfaces to determine the locations " "of the medial wall and cuts. Pressing the \"Add Template Border Medial " "Wall and Cuts\" pushbutton will create borders that roughly identify " "the location of the medial wall and cuts. \n\n" "" "Subsequent pages provide controls for drawing replacement borders and " "updating existing borders for the medial wall and cuts."; QLabel* textLabel = new QLabel(text); textLabel->setWordWrap(true); QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(addLandmarkBordersPushButton); layout->addWidget(addTemplateCutBordersPushButton); layout->addWidget(textLabel); layout->addStretch(); } /** * destructor. */ GuiFlattenFullHemisphereTemplateCutsPage::~GuiFlattenFullHemisphereTemplateCutsPage() { } /** * called to add landmark border cuts. */ void GuiFlattenFullHemisphereTemplateCutsPage::slotAddLandmarkBordersPushButton() { GuiFlattenFullHemisphereDialog* fd = dynamic_cast(wizard()); GuiBorderOperationsDialog* borderOperationsDialog = theMainWindow->getBorderOperationsDialog(true); borderOperationsDialog->showPageCreateLandmarkBorders(true, true, fd->getFiducialSurface(), fd->getInflatedSurface(), fd->getVeryInflatedSurface(), fd->getSphericalSurface()); } /** * called to add border template cuts. */ void GuiFlattenFullHemisphereTemplateCutsPage::slotAddTemplateCutBordersPushButton() { BrainSet* bs = theMainWindow->getBrainSet(); // // Get directory containing template borders // const QString templateDirectoryName = (BrainSet::getCaretHomeDirectory() + QDir::separator() + "data_files/flatten_landmarks"); QDir templateDirectory(templateDirectoryName); if (templateDirectory.exists() == false) { WuQMessageBox::critical(this, "ERROR", "Unable to find template border files. is Caret " "installed correctly?\n" "Looking in " + templateDirectoryName); return; } // // Get all border files in directory // QFileInfoList infoList = templateDirectory.entryInfoList(QStringList("*.border"), (QDir::Files | QDir::Readable | QDir::CaseSensitive)); QListIterator iter(infoList); QStringList borderFileNames; QStringList borderColorFileNames; QStringList borderFileDescriptions; while (iter.hasNext()) { QString borderFileName = iter.next().absoluteFilePath(); BorderFile borderFile; try { borderFile.readFile(borderFileName); const QString description = borderFile.getHeaderTag("descriptive_name"); if (description.isEmpty() == false) { borderFileNames += borderFileName; borderFileDescriptions += description; borderColorFileNames += (BrainSet::getCaretHomeDirectory() + QDir::separator() + "data_files/flatten_landmarks" + QDir::separator() + borderFile.getHeaderTag("matching_color_file")); } } catch (FileException&) { } } borderFileDescriptions.sort(); const QString speciesString = bs->getSpecies().getName().toLower(); const QString structureString = bs->getStructure().getTypeAsString().toLower(); int defaultIndex = -1; for (int i = 0; i < borderFileDescriptions.count(); i++) { const QString descrip(borderFileDescriptions.at(i).toLower()); if ((descrip.indexOf("standard") >= 0) && (descrip.indexOf(speciesString) >= 0) && (descrip.indexOf(structureString) >= 0)) { defaultIndex = i; break; } } if (borderFileNames.isEmpty()) { WuQMessageBox::critical(this, "ERROR", "Unable to find template border files. is Caret " "installed correctly?\n" "Looking in " + templateDirectoryName); return; } // // Allow user to choose borders // WuQDataEntryDialog ded(this); ded.setWindowTitle("Choose Template Borders"); QListWidget* lw = ded.addListWidget("", borderFileDescriptions); if (defaultIndex >= 0) { lw->setCurrentRow(defaultIndex); } if (ded.exec() == WuQDataEntryDialog::Accepted) { const QString description = lw->currentItem()->text(); QString templateBorderFileName; QString templateColorFileName; for (int i = 0; i < borderFileDescriptions.count(); i++) { if (description == borderFileDescriptions.at(i)) { templateBorderFileName = borderFileNames.at(i); templateColorFileName = borderColorFileNames.at(i); break; } } // // Load template borders // if (templateBorderFileName.isEmpty() == false) { BrainModelBorderSet* bmbs = bs->getBorderSet(); try { bs->readBorderFile(templateBorderFileName, BrainModelSurface::SURFACE_TYPE_SPHERICAL, true, false); } catch (FileException& e) { WuQMessageBox::critical(this, "ERROR", e.whatQString()); return; } try { bs->readBorderColorFile(templateColorFileName, true, false); bs->getBorderColorFile()->setModified(); } catch (FileException&) { } GuiFlattenFullHemisphereDialog* flattenDialog = dynamic_cast(wizard()); BrainModelSurface* sphericalSurface = flattenDialog->getSphericalSurface(); if (sphericalSurface != NULL) { bmbs->projectBorders(sphericalSurface, true); } DisplaySettingsBorders* dsb = bs->getDisplaySettingsBorders(); dsb->setDisplayBorders(true); GuiFilesModified fm; fm.setBorderModified(); fm.setBorderColorModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } } } /** * cleanup page (called when showing page after "Back" pressed). */ void GuiFlattenFullHemisphereTemplateCutsPage::cleanupPage() { } /** * initialize the page (called when showing page after "Next" pressed). */ void GuiFlattenFullHemisphereTemplateCutsPage::initializePage() { DisplaySettingsBorders* dsb = theMainWindow->getBrainSet()->getDisplaySettingsBorders(); dsb->setDisplayBorders(true); dsb->determineDisplayedBorders(); GuiBrainModelOpenGL::updateAllGL(); } /** * page is complete. */ bool GuiFlattenFullHemisphereTemplateCutsPage::isComplete() { return true; } /** * validate a page. */ bool GuiFlattenFullHemisphereTemplateCutsPage::validatePage() { return true; } //========================================================================= //========================================================================= //========================================================================= /** * constructor. */ GuiFlattenFullHemisphereSphericalPage::GuiFlattenFullHemisphereSphericalPage(QWidget* parent) : QWizardPage(parent) { setTitle("Spherical Surface"); // // Inflated Surface selection // QLabel* inflatedSurfaceLabel = new QLabel("Inflated"); inflatedSurfaceComboBox = new GuiBrainModelSurfaceSelectionComboBox( BrainModelSurface::SURFACE_TYPE_INFLATED); // // Very Inflated Surface selection // QLabel* veryInflatedSurfaceLabel = new QLabel("Very Inflated"); veryInflatedSurfaceComboBox = new GuiBrainModelSurfaceSelectionComboBox( BrainModelSurface::SURFACE_TYPE_VERY_INFLATED); // // Spherical Surface selection // QLabel* sphericalSurfaceLabel = new QLabel("Spherical"); sphericalSurfaceComboBox = new GuiBrainModelSurfaceSelectionComboBox( BrainModelSurface::SURFACE_TYPE_SPHERICAL); // // Layout for surface selection // QGridLayout* surfaceGridLayout = new QGridLayout; surfaceGridLayout->addWidget(sphericalSurfaceLabel, 0, 0); surfaceGridLayout->addWidget(sphericalSurfaceComboBox, 0, 1); surfaceGridLayout->addWidget(inflatedSurfaceLabel, 1, 0); surfaceGridLayout->addWidget(inflatedSurfaceComboBox, 1, 1); surfaceGridLayout->addWidget(veryInflatedSurfaceLabel, 2, 0); surfaceGridLayout->addWidget(veryInflatedSurfaceComboBox, 2, 1); surfaceGridLayout->setColumnStretch(0, 0); surfaceGridLayout->setColumnStretch(1, 100); const QString instructionsText = "A spherical surface is required. Inflated and very inflated surfaces " "are very helpful for drawing borders.

    " "" "If you need to generate surfaces, click the Generate Surfaces " "button below."; QLabel* instructionsLabel = new QLabel; instructionsLabel->setText(instructionsText); instructionsLabel->setTextFormat(Qt::RichText); instructionsLabel->setWordWrap(true); // // Button for generating surfaces // QPushButton* generateSurfacesPushButton = new QPushButton("Generate Surfaces..."); generateSurfacesPushButton->setAutoDefault(false); generateSurfacesPushButton->setFixedSize(generateSurfacesPushButton->sizeHint()); QObject::connect(generateSurfacesPushButton, SIGNAL(clicked()), this, SLOT(slotGenerateSurfacesPushButton())); // // Layout for page // QVBoxLayout* layout = new QVBoxLayout(this); layout->addLayout(surfaceGridLayout); layout->addWidget(instructionsLabel); layout->addWidget(generateSurfacesPushButton); layout->addStretch(); } /** * destructor. */ GuiFlattenFullHemisphereSphericalPage::~GuiFlattenFullHemisphereSphericalPage() { } /** * get the spherical surface. */ BrainModelSurface* GuiFlattenFullHemisphereSphericalPage::getSphericalSurface() { return sphericalSurfaceComboBox->getSelectedBrainModelSurface(); } /** * get the inflated surface. */ BrainModelSurface* GuiFlattenFullHemisphereSphericalPage::getInflatedSurface() { return inflatedSurfaceComboBox->getSelectedBrainModelSurface(); } /** * get the very inflated surface. */ BrainModelSurface* GuiFlattenFullHemisphereSphericalPage::getVeryInflatedSurface() { return veryInflatedSurfaceComboBox->getSelectedBrainModelSurface(); } /** * called when generate surfaces button clicked. */ void GuiFlattenFullHemisphereSphericalPage::slotGenerateSurfacesPushButton() { const int oldNumberOfBrainModels = theMainWindow->getBrainSet()->getNumberOfBrainModels(); BrainModelSurface* fiducialSurface = dynamic_cast(wizard())->getFiducialSurface(); if (fiducialSurface == NULL) { WuQMessageBox::critical(this, "ERROR", "There must be a fiducial surface."); return; } GuiMainWindowSurfaceActions* surfaceActions = theMainWindow->getSurfaceActions(); surfaceActions->generateInflatedAndOtherSurfaces( fiducialSurface, false, false, (inflatedSurfaceComboBox->getSelectedBrainModelSurface() == NULL), (veryInflatedSurfaceComboBox->getSelectedBrainModelSurface() == NULL), (sphericalSurfaceComboBox->getSelectedBrainModelSurface() == NULL)); GuiFlattenFullHemisphereDialog* dialog = dynamic_cast(wizard()); dialog->saveSurfaces(oldNumberOfBrainModels); } /** * cleanup page (called when showing page after "Back" pressed). */ void GuiFlattenFullHemisphereSphericalPage::cleanupPage() { initializePage(); } /** * initialize the page (called when showing page after "Next" pressed). */ void GuiFlattenFullHemisphereSphericalPage::initializePage() { inflatedSurfaceComboBox->updateComboBox(); veryInflatedSurfaceComboBox->updateComboBox(); sphericalSurfaceComboBox->updateComboBox(); } /** * page is complete. */ bool GuiFlattenFullHemisphereSphericalPage::isComplete() { return true; } /** * validate a page. */ bool GuiFlattenFullHemisphereSphericalPage::validatePage() { return true; } //========================================================================= //========================================================================= //========================================================================= /** * constructor. */ GuiFlattenFullHemisphereBorderUpdatePage::GuiFlattenFullHemisphereBorderUpdatePage(QWidget* parent) : QWizardPage(parent) { setTitle("Draw and Update Borders"); QPushButton* drawBordersPushButton = new QPushButton("Draw Borders..."); drawBordersPushButton->setToolTip("Press this button to\n" "draw a new border."); drawBordersPushButton->setAutoDefault(false); drawBordersPushButton->setFixedSize(drawBordersPushButton->sizeHint()); QObject::connect(drawBordersPushButton, SIGNAL(clicked()), this, SLOT(slotDrawBordersPushButton())); QPushButton* updateBordersPushButton = new QPushButton("Update Borders..."); updateBordersPushButton->setToolTip("Press this button to\n" "modify one of the\n" "existing borders."); updateBordersPushButton->setAutoDefault(false); updateBordersPushButton->setFixedSize(updateBordersPushButton->sizeHint()); QObject::connect(updateBordersPushButton, SIGNAL(clicked()), this, SLOT(slotUpdateBordersPushButton())); QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->addWidget(drawBordersPushButton); buttonsLayout->addWidget(updateBordersPushButton); buttonsLayout->addStretch(); QPushButton* exampleImagesPushButton = new QPushButton("Images of Medial Wall and Cuts..."); exampleImagesPushButton->setAutoDefault(false); exampleImagesPushButton->setToolTip("View examples of Medial Wall and Cut Borders"); exampleImagesPushButton->setFixedSize(exampleImagesPushButton->sizeHint()); QObject::connect(exampleImagesPushButton, SIGNAL(clicked()), this, SLOT(slotBorderExampleImages())); QPushButton* showOnlyFlattenBordersPushButton = new QPushButton("Show Only Flattening Borders"); showOnlyFlattenBordersPushButton->setAutoDefault(false); showOnlyFlattenBordersPushButton->setFixedSize(showOnlyFlattenBordersPushButton->sizeHint()); QObject::connect(showOnlyFlattenBordersPushButton, SIGNAL(clicked()), this, SLOT(slotShowOnlyFlattenBordersPushButton())); const QString infoText = "For proper flattening, the medial wall must to be accurately identified " "so that no non-cortical material remains in the flattened surface. " "The accuracy required of the cuts is less than that of the medial wall and " "if the cuts were automatically generated, their locations are sufficiently " "correct. However, cuts MUST intersect the Medial Wall.

    " "The Medial Wall border must be named FLATTEN.HOLE.MedialWall. All " "of the cuts border names must begin with FLATTEN.CUT. Borders " "whose name does not begin with \"FLATTEN\" are ignored by the flattening " "process.

    " "The 3D border drawing mode enabled the drawing of borders on any surface " "and the drawn borders is automatically projected.

    ." "The Medial Wall border is drawn as an closed border and the cuts are " "drawn as open borders.

    " "It may be helpful to display the surface shape column named " "Folding (Mean Curvature to aid in border drawing.

    " "FLATTEN.HOLE.MedialWall This closed border is drawn so that it " "encloses the Medial Wall. The dorsal medial wall landmark runs along the " "corpus callosum, from a starting point just posterior to the olfactory " "sulcus to a termination just anterior to the calcarine sulcus. The " "ventral medial wall landmark runs from the same termination points, " "but in the opposite direction and along the medial margin of the " "hippocampal sulcus (15 mm medial to the parahippocampal gyrus at its " "maximum), and across the margins of cortex with the basal forebrain.

    " "FLATTEN.CUT.Std.Calcarine This cut starts inside the medial wall, " "is drawn along the calcarine sulcus to the occipital pole, and then " "continues in a lateral direction for several millimeters.

    " "FLATTEN.CUT.Std.Cingulate This cut starts inside the medial wall " "and is drawn to the dorsal/medial tip of the central sulcus.

    " "FLATTEN.CUT.Std.Frontal This cut starts inside the medial wall, " "is drawn in an anterior direction along the inferior frontal cortex, and " "concludes at the most posterior location in the Inferior Frontal Sulcus. " "

    " "FLATTEN.CUT.Std.Sylvian This cut starts inside the medial wall " "and is drawn so that it ends approximately one-third of the way into " "the Sylvian Fissure.

    " "FLATTEN.CUT.Std.Temporal This cut starts inside the medial wall, " "is drawn in an inferior direction so that it passes through the most " "inferior node in the temporal lobe, and then terminates about 15 to 20 " "millimeters below the Superior Temporal Sulcus."; QTextEdit* borderInfoTextEdit = new QTextEdit; borderInfoTextEdit->setHtml(infoText); QVBoxLayout* layout = new QVBoxLayout(this); layout->addLayout(buttonsLayout); layout->addWidget(exampleImagesPushButton); layout->addWidget(showOnlyFlattenBordersPushButton); layout->addWidget(borderInfoTextEdit); layout->addStretch(); } /** * destructor. */ GuiFlattenFullHemisphereBorderUpdatePage::~GuiFlattenFullHemisphereBorderUpdatePage() { } /** * called when draw borders button pressed. */ void GuiFlattenFullHemisphereBorderUpdatePage::slotDrawBordersPushButton() { GuiBorderOperationsDialog* borderOperationsDialog = theMainWindow->getBorderOperationsDialog(true); borderOperationsDialog->showPageDrawBorders(); } /** * called when update borders button pressed. */ void GuiFlattenFullHemisphereBorderUpdatePage::slotUpdateBordersPushButton() { GuiBorderOperationsDialog* borderOperationsDialog = theMainWindow->getBorderOperationsDialog(true); borderOperationsDialog->showPageUpdateBorders(); } /** * called when show only flattening borders selected. */ void GuiFlattenFullHemisphereBorderUpdatePage::slotShowOnlyFlattenBordersPushButton() { BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); const int num = bmbs->getNumberOfBorders(); for (int i = 0; i < num; i++) { BrainModelBorder* b = bmbs->getBorder(i); if (b->getName().startsWith("FLATTEN")) { b->setNameDisplayFlag(true); } else { b->setNameDisplayFlag(false); } } DisplaySettingsBorders* dsb = theMainWindow->getBrainSet()->getDisplaySettingsBorders(); dsb->determineDisplayedBorders(); GuiFilesModified fm; fm.setBorderModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } /** * called when example images button pressed. */ void GuiFlattenFullHemisphereBorderUpdatePage::slotBorderExampleImages() { static WuQDialog* d = NULL; if (d == NULL) { // // Get directory containing borders images // const QString templateDirectoryName = (BrainSet::getCaretHomeDirectory() + QDir::separator() + "data_files/flatten_landmarks/example_images"); QDir templateDirectory(templateDirectoryName); if (templateDirectory.exists() == false) { WuQMessageBox::critical(this, "ERROR", "Unable to find example border images. is Caret " "installed correctly?\n" "Looking in " + templateDirectoryName); return; } // // Get all border files in directory // QFileInfoList infoList = templateDirectory.entryInfoList(QStringList("*.jpg"), (QDir::Files | QDir::Readable | QDir::CaseSensitive), QDir::Name); if (infoList.count() <= 0) { WuQMessageBox::critical(this, "ERROR", "Unable to find example border images. \n" "No images found in " + templateDirectoryName); return; } QListIterator iter(infoList); QWidget* imagesWidget = new QWidget; QVBoxLayout* imagesLayout = new QVBoxLayout(imagesWidget); while (iter.hasNext()) { const QString imageFileName(iter.next().absoluteFilePath()); QPixmap p; if (p.load(imageFileName)) { QLabel* imageLabel = new QLabel(""); imageLabel->setPixmap(p); imagesLayout->addWidget(imageLabel); } } QScrollArea* scrollArea = new QScrollArea; scrollArea->setWidget(imagesWidget); d = new WuQDialog(this); d->setWindowTitle("Example Images of Medial Wall and Cuts"); QDialogButtonBox* bb = new QDialogButtonBox(QDialogButtonBox::Close); QObject::connect(bb, SIGNAL(rejected()), d, SLOT(close())); QVBoxLayout* layout = new QVBoxLayout(d); layout->addWidget(scrollArea); layout->addWidget(bb); } d->show(); } /** * cleanup page (called when showing page after "Back" pressed). */ void GuiFlattenFullHemisphereBorderUpdatePage::cleanupPage() { } /** * initialize the page (called when showing page after "Next" pressed). */ void GuiFlattenFullHemisphereBorderUpdatePage::initializePage() { if (theMainWindow->getBrainModelOpenGL()->getMouseMode() == GuiBrainModelOpenGL::MOUSE_MODE_ALIGN_STANDARD_ORIENTATION_FULL_HEM_FLATTEN) { theMainWindow->getBrainModelOpenGL()->setMouseMode( GuiBrainModelOpenGL::MOUSE_MODE_VIEW); } } /** * page is complete. */ bool GuiFlattenFullHemisphereBorderUpdatePage::isComplete() { return true; } /** * validate a page. */ bool GuiFlattenFullHemisphereBorderUpdatePage::validatePage() { return true; } //========================================================================= //========================================================================= //========================================================================= /** * constructor. */ GuiFlattenFullHemisphereStartFlatteningPage::GuiFlattenFullHemisphereStartFlatteningPage(QWidget* parent) : QWizardPage(parent) { setTitle("Start Flattening"); bordersListLabel = new QLabel(""); bordersListLabel->setTextFormat(Qt::RichText); bordersListLabel->setWordWrap(true); QLabel* startLabel = new QLabel("Pressing the Next button will start the " "flattening process."); startLabel->setTextFormat(Qt::RichText); startLabel->setWordWrap(true); QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(bordersListLabel); layout->addWidget(startLabel); layout->addStretch(); } /** * destructor. */ GuiFlattenFullHemisphereStartFlatteningPage::~GuiFlattenFullHemisphereStartFlatteningPage() { } /** * cleanup page (called when showing page after "Back" pressed). */ void GuiFlattenFullHemisphereStartFlatteningPage::cleanupPage() { } /** * get loaded flattening borders. */ void GuiFlattenFullHemisphereStartFlatteningPage::getLoadedFlatteningBorders(std::vector& flattenBorderNamesOut) const { flattenBorderNamesOut.clear(); std::vector sortedNames; const BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); for (int i = 0; i < bmbs->getNumberOfBorders(); i++) { const BrainModelBorder* border = bmbs->getBorder(i); if (border->getType() == BrainModelBorder::BORDER_TYPE_PROJECTION) { const QString name = border->getName(); if (name.startsWith(BrainModelSurfaceBorderLandmarkIdentification::getFlattenStandardCutsBorderNamePrefix()) || name.startsWith(BrainModelSurfaceBorderLandmarkIdentification::getFlattenMedialWallBorderName())) { flattenBorderNamesOut.push_back(border->getName()); } } } std::sort(flattenBorderNamesOut.begin(), flattenBorderNamesOut.end()); } /** * initialize the page (called when showing page after "Next" pressed). */ void GuiFlattenFullHemisphereStartFlatteningPage::initializePage() { if (theMainWindow->getBrainModelOpenGL()->getMouseMode() == GuiBrainModelOpenGL::MOUSE_MODE_ALIGN_STANDARD_ORIENTATION_FULL_HEM_FLATTEN) { theMainWindow->getBrainModelOpenGL()->setMouseMode( GuiBrainModelOpenGL::MOUSE_MODE_VIEW); } std::vector flattenBorderNames; getLoadedFlatteningBorders(flattenBorderNames); QString msg = "The following borders will be used to remove the medial wall and to " "make cuts. If the name of a border is listed more than once, the " "duplicate borders should be deleted prior to continuing.
    "; for (std::vector::iterator iter = flattenBorderNames.begin(); iter != flattenBorderNames.end(); iter++) { msg += ("   " + *iter + "
    "); } bordersListLabel->setText(msg); } /** * page is complete. */ bool GuiFlattenFullHemisphereStartFlatteningPage::isComplete() { return true; } /** * validate a page. */ bool GuiFlattenFullHemisphereStartFlatteningPage::validatePage() { return true; } //========================================================================= //========================================================================= //========================================================================= /** * constructor. */ GuiFlattenFullHemisphereInitialFlatPage::GuiFlattenFullHemisphereInitialFlatPage(QWidget* parent) : QWizardPage(parent) { setTitle("Initial Flat"); const QString initialFlatText = "The initial flat surface is shown in the Main Window. If there are " "any crossovers, they are shown in red. If the crossovers are near " "the perimeter of the surface they can be removed by drawing and " "applying cuts. When drawing a cut, the cut should start outside " "the surface, go over the surface near the cut, and then end outside " "of the surface.

    " "" "Cuts are drawn similar to borders. Move the mouse to the start of the " "cut, hold down the left mouse button and move the mouse to the end of the " "cut, release the mouse button, hold down the shift key a click the mouse." "

    " "" "To draw and apply cuts:
    " "   Press the Draw Cuts Button.
    " "   Draw one or more cuts as needed.
    " "   Press the Apply Cuts Button.
    " "   Delete All Cuts.
    "; QLabel* initialFlatLabel = new QLabel(""); initialFlatLabel->setTextFormat(Qt::RichText); initialFlatLabel->setWordWrap(true); initialFlatLabel->setText(initialFlatText); GuiMainWindowSurfaceActions* surfaceActions = theMainWindow->getSurfaceActions(); // // Draw Cuts push button // QPushButton* drawCutsPushButton = new QPushButton("Draw Cuts"); drawCutsPushButton->setAutoDefault(false); QObject::connect(drawCutsPushButton, SIGNAL(clicked()), surfaceActions, SLOT(slotCutsDraw())); // // Apply Cuts push button // QPushButton* applyCutsPushButton = new QPushButton("Apply Cuts"); applyCutsPushButton->setAutoDefault(false); QObject::connect(applyCutsPushButton, SIGNAL(clicked()), surfaceActions, SLOT(slotCutsApply())); // // Delete All Cuts push button // QPushButton* deleteAllCutsPushButton = new QPushButton("Delete All Cuts"); deleteAllCutsPushButton->setAutoDefault(false); QObject::connect(deleteAllCutsPushButton, SIGNAL(clicked()), surfaceActions, SLOT(slotCutsDeleteAll())); // // Delete Cuts with mouse // QPushButton* deleteCutsWithMousePushButton = new QPushButton("Delete Cuts With Mouse"); deleteCutsWithMousePushButton->setAutoDefault(false); QObject::connect(deleteCutsWithMousePushButton, SIGNAL(clicked()), surfaceActions, SLOT(slotCutsDeleteWithMouse())); // // Make buttons same size // QtUtilities::makeButtonsSameSize(drawCutsPushButton, applyCutsPushButton, deleteAllCutsPushButton, deleteCutsWithMousePushButton); // // Layout for cuts push buttons // QGridLayout* cutsGridLayout = new QGridLayout; cutsGridLayout->addWidget(drawCutsPushButton, 0, 0); cutsGridLayout->addWidget(applyCutsPushButton, 1, 0); cutsGridLayout->addWidget(deleteAllCutsPushButton, 0, 1); cutsGridLayout->addWidget(deleteCutsWithMousePushButton, 1, 1); cutsGridLayout->setColumnStretch(0, 0); cutsGridLayout->setColumnStretch(1, 0); QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(initialFlatLabel); layout->addLayout(cutsGridLayout); layout->addStretch(); } /** * destructor. */ GuiFlattenFullHemisphereInitialFlatPage::~GuiFlattenFullHemisphereInitialFlatPage() { } /** * cleanup page (called when showing page after "Back" pressed). */ void GuiFlattenFullHemisphereInitialFlatPage::cleanupPage() { } /** * initialize the page (called when showing page after "Next" pressed). */ void GuiFlattenFullHemisphereInitialFlatPage::initializePage() { } /** * page is complete. */ bool GuiFlattenFullHemisphereInitialFlatPage::isComplete() { return true; } /** * validate a page. */ bool GuiFlattenFullHemisphereInitialFlatPage::validatePage() { return true; } //========================================================================= //========================================================================= //========================================================================= /** * constructor. */ GuiFlattenFullHemisphereMultiresolutionMorphingPage::GuiFlattenFullHemisphereMultiresolutionMorphingPage( BrainModelSurfaceMultiresolutionMorphing* flatParametersIn, BrainModelSurfaceMultiresolutionMorphing* sphericalParametersIn, QWidget* parent) : QWizardPage(parent) { flatParameters = flatParametersIn; sphericalParameters = sphericalParametersIn; setTitle("Multi-resolution Morphing"); const QString morphtText = "Multi-resolution morphing will reduces the distortion in the flat " "and spherical surfaces."; QLabel* morphInfoLabel = new QLabel(""); morphInfoLabel->setTextFormat(Qt::RichText); morphInfoLabel->setWordWrap(true); morphInfoLabel->setText(morphtText); // // flat multi-res morph // flatMultiMorphCheckBox = new QCheckBox("Perform Flat Multi-resolution Morphing"); QPushButton* flatParamsPushButton = new QPushButton("Edit Parameters..."); flatParamsPushButton->setAutoDefault(false); QObject::connect(flatParamsPushButton, SIGNAL(clicked()), this, SLOT(slotFlatParamsPushButton())); // // flat multi-res morph // sphericalMultiMorphCheckBox = new QCheckBox("Perform Spherical Multi-resolution Morphing"); QPushButton* sphericalParamsPushButton = new QPushButton("Edit Parameters..."); sphericalParamsPushButton->setAutoDefault(false); QObject::connect(sphericalParamsPushButton, SIGNAL(clicked()), this, SLOT(slotSphericalParamsPushButton())); // // Disable edit buttons when morphing not selected // QObject::connect(flatMultiMorphCheckBox, SIGNAL(toggled(bool)), flatParamsPushButton, SLOT(setEnabled(bool))); QObject::connect(sphericalMultiMorphCheckBox, SIGNAL(toggled(bool)), sphericalParamsPushButton, SLOT(setEnabled(bool))); flatMultiMorphCheckBox->setChecked(true); sphericalMultiMorphCheckBox->setChecked(true); // // Layout for mrm // QGridLayout* mrmGridLayout = new QGridLayout; mrmGridLayout->addWidget(flatMultiMorphCheckBox, 0, 0); mrmGridLayout->addWidget(flatParamsPushButton, 0, 1); mrmGridLayout->addWidget(sphericalMultiMorphCheckBox, 1, 0); mrmGridLayout->addWidget(sphericalParamsPushButton, 1, 1); mrmGridLayout->setColumnStretch(0, 0); mrmGridLayout->setColumnStretch(1, 0); // // Layout for page // QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(morphInfoLabel); layout->addLayout(mrmGridLayout); layout->addStretch(); } /** * destructor. */ GuiFlattenFullHemisphereMultiresolutionMorphingPage::~GuiFlattenFullHemisphereMultiresolutionMorphingPage() { } /** * is flat multi-res morphing selected. */ bool GuiFlattenFullHemisphereMultiresolutionMorphingPage::getDoFlatMultiResMorphing() const { return flatMultiMorphCheckBox->isChecked(); } /** * is spherical multi-res morphing selected. */ bool GuiFlattenFullHemisphereMultiresolutionMorphingPage::getDoSphericalMultiResMorphing() const { return sphericalMultiMorphCheckBox->isChecked(); } /** * called to adjust flat multi-res morph parameters. */ void GuiFlattenFullHemisphereMultiresolutionMorphingPage::slotFlatParamsPushButton() { GuiMultiresolutionMorphingDialog mmd(this, flatParameters, true); mmd.exec(); } /** * called to adjust spherical multi-res morph parameters. */ void GuiFlattenFullHemisphereMultiresolutionMorphingPage::slotSphericalParamsPushButton() { GuiMultiresolutionMorphingDialog mmd(this, sphericalParameters, true); mmd.exec(); } /** * cleanup page (called when showing page after "Back" pressed). */ void GuiFlattenFullHemisphereMultiresolutionMorphingPage::cleanupPage() { } /** * initialize the page (called when showing page after "Next" pressed). */ void GuiFlattenFullHemisphereMultiresolutionMorphingPage::initializePage() { } /** * page is complete. */ bool GuiFlattenFullHemisphereMultiresolutionMorphingPage::isComplete() { return true; } /** * validate a page. */ bool GuiFlattenFullHemisphereMultiresolutionMorphingPage::validatePage() { return true; } //========================================================================= //========================================================================= //========================================================================= /** * constructor. */ GuiFlattenFullHemisphereSurfaceAlignmentPage::GuiFlattenFullHemisphereSurfaceAlignmentPage(QWidget* parent) : QWizardPage(parent) { ventralTipNodeNumber = -1; dorsalMedialTipNodeNumber = -1; setTitle("Surface Alignment Presets"); const QString alignmentText = "At the conclusion of the flattening process, the final flat and spherical " "surfaces will be automatically aligned to Standard Orientation. " "If there is a border named " + BrainModelSurfaceBorderLandmarkIdentification::getCentralSulcusRegistrationLandmarkName() + " (one of the " "registration landmarks), the Use " + BrainModelSurfaceBorderLandmarkIdentification::getCentralSulcusRegistrationLandmarkName() + " For Alignment button will be enabled and can be used to preset the " "ventral and dorsal-medial tips of the central sulcus.

    " "" "To set the nodes used for standard surface alignment, display the very " "inflated (or other) surface in the Main Window. Click the mouse over " "the ventral (inferior) tip of the central sulcus. Next, hold down the " "shift key and click the mouse over the dorsal-medial (superior) tip " "of the central sulcus. If necessary, press the Enable Mouse " "button so that mouse clicks update the central sulcus tips."; QLabel* alignmentLabel = new QLabel(""); alignmentLabel->setTextFormat(Qt::RichText); alignmentLabel->setWordWrap(true); alignmentLabel->setText(alignmentText); // // Central Sulcus Tips column titles // QLabel* tipEndColumnLabel = new QLabel("Central Sulcus Tip"); QLabel* nodeLabel = new QLabel("X"); QLabel* ventralLabel = new QLabel("Ventral (click)"); QLabel* dorsalMedialLabel = new QLabel("Dorsal-Medial (shift-click)"); const QString spaces(10, ' '); ventralNodeLabel = new QLabel(spaces); dorsalMedialNodeLabel = new QLabel(spaces); // // Layout and group box for central sulcus // QGroupBox* cesGroupBox = new QGroupBox("Central Sulcus Tips"); QGridLayout* cesGridLayout = new QGridLayout(cesGroupBox); cesGridLayout->addWidget(tipEndColumnLabel, 0, 0); cesGridLayout->addWidget(nodeLabel, 0, 1); cesGridLayout->addWidget(ventralLabel, 1, 0); cesGridLayout->addWidget(ventralNodeLabel, 1, 1); cesGridLayout->addWidget(dorsalMedialLabel, 2, 0); cesGridLayout->addWidget(dorsalMedialNodeLabel, 2, 1); // // Use Central Sulcus to set tips // useLandmarkCentralSulcusPushButton = new QPushButton("Use " + BrainModelSurfaceBorderLandmarkIdentification::getCentralSulcusRegistrationLandmarkName() + " For Alignment"); useLandmarkCentralSulcusPushButton->setAutoDefault(false); useLandmarkCentralSulcusPushButton->setFixedSize(useLandmarkCentralSulcusPushButton->sizeHint()); QObject::connect(useLandmarkCentralSulcusPushButton, SIGNAL(clicked()), this, SLOT(slotUseLandmarkCentralSulcusPushButton())); // // Enable mouse push button // QPushButton* enableMousePushButton = new QPushButton("Enable Mouse"); enableMousePushButton->setAutoDefault(false); enableMousePushButton->setFixedSize(enableMousePushButton->sizeHint()); QObject::connect(enableMousePushButton, SIGNAL(clicked()), this, SLOT(slotEnableMousePushButton())); // // Layout for page // QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(alignmentLabel); layout->addWidget(cesGroupBox); layout->addWidget(useLandmarkCentralSulcusPushButton); layout->addWidget(enableMousePushButton); layout->addStretch(); updateCentralSulcusLabels(); } /** * destructor. */ GuiFlattenFullHemisphereSurfaceAlignmentPage::~GuiFlattenFullHemisphereSurfaceAlignmentPage() { } /** * called when enable mouse button pressed. */ void GuiFlattenFullHemisphereSurfaceAlignmentPage::slotEnableMousePushButton() { theMainWindow->getBrainModelOpenGL()->setMouseMode( GuiBrainModelOpenGL::MOUSE_MODE_ALIGN_STANDARD_ORIENTATION_FULL_HEM_FLATTEN); } /** * cleanup page (called when showing page after "Back" pressed). */ void GuiFlattenFullHemisphereSurfaceAlignmentPage::cleanupPage() { initializePage(); } /** * initialize the page (called when showing page after "Next" pressed). */ void GuiFlattenFullHemisphereSurfaceAlignmentPage::initializePage() { BorderProjectionFile borderProjFile; BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); bmbs->copyBordersToBorderProjectionFile(borderProjFile); const BorderProjection* bp = borderProjFile.getLastBorderProjectionByName( BrainModelSurfaceBorderLandmarkIdentification::getCentralSulcusRegistrationLandmarkName()); useLandmarkCentralSulcusPushButton->setEnabled(bp != NULL); slotEnableMousePushButton(); updateCentralSulcusLabels(); } /** * page is complete. */ bool GuiFlattenFullHemisphereSurfaceAlignmentPage::isComplete() { return true; } /** * validate a page. */ bool GuiFlattenFullHemisphereSurfaceAlignmentPage::validatePage() { return true; } /** * called when Use LANDMARK.CentralSulcus button pressed. */ void GuiFlattenFullHemisphereSurfaceAlignmentPage::slotUseLandmarkCentralSulcusPushButton() { BorderProjectionFile borderProjFile; BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); bmbs->copyBordersToBorderProjectionFile(borderProjFile); const BorderProjection* bp = borderProjFile.getLastBorderProjectionByName( BrainModelSurfaceBorderLandmarkIdentification::getCentralSulcusRegistrationLandmarkName()); if (bp == NULL) { WuQMessageBox::critical(this, "ERROR", "Unable to find border named: " + BrainModelSurfaceBorderLandmarkIdentification::getCentralSulcusRegistrationLandmarkName() ); return; } const BrainModelSurface* fiducialSurface = dynamic_cast(wizard())->getFiducialSurface(); if (fiducialSurface == NULL) { return; } const CoordinateFile* cf = fiducialSurface->getCoordinateFile(); // // Find first and last links // const int numLinks = bp->getNumberOfLinks(); if (numLinks >= 2) { const BorderProjectionLink* bpFirst = bp->getBorderProjectionLink(0); float firstXYZ[3]; bpFirst->unprojectLink(cf, firstXYZ); int firstSection, firstVertices[3]; float firstAreas[3], firstRadius; bpFirst->getData(firstSection, firstVertices, firstAreas, firstRadius); const BorderProjectionLink* bpLast = bp->getBorderProjectionLink(numLinks - 1); float lastXYZ[3]; bpLast->unprojectLink(cf, lastXYZ); int lastSection, lastVertices[3]; float lastAreas[3], lastRadius; bpLast->getData(lastSection, lastVertices, lastAreas, lastRadius); // // Link with largest Z is dorsal-medial // if (lastXYZ[2] > firstXYZ[2]) { ventralTipNodeNumber = firstVertices[0]; dorsalMedialTipNodeNumber = lastVertices[0]; updateCentralSulcusLabels(); } } } /** * update the ces node numbers. */ void GuiFlattenFullHemisphereSurfaceAlignmentPage::updateCentralSulcusLabels() { const int numNodes = theMainWindow->getBrainSet()->getNumberOfNodes(); if (ventralTipNodeNumber >= numNodes) { ventralTipNodeNumber = -1; } if (dorsalMedialTipNodeNumber >= numNodes) { dorsalMedialTipNodeNumber = -1; } if (ventralTipNodeNumber >= 0) { ventralNodeLabel->setNum(ventralTipNodeNumber); } else { ventralNodeLabel->setText("Invalid"); } if (dorsalMedialTipNodeNumber >= 0) { dorsalMedialNodeLabel->setNum(dorsalMedialTipNodeNumber); } else { dorsalMedialNodeLabel->setText("Invalid"); } } /** * get the central suclus ventral and dorsal-medial tips. */ void GuiFlattenFullHemisphereSurfaceAlignmentPage::getCentralSulcusTips( int& ventralTipNodeNumberOut, int& dorsalMedialTipNodeNumberOut) const { ventralTipNodeNumberOut = ventralTipNodeNumber; dorsalMedialTipNodeNumberOut = dorsalMedialTipNodeNumber; } /** * set the central sulcus ventral tip. */ void GuiFlattenFullHemisphereSurfaceAlignmentPage::setCentralSulcusVentralTip(const int nodeNum) { ventralTipNodeNumber = nodeNum; updateCentralSulcusLabels(); } /** * set the central sulcus dorsal-medial tip. */ void GuiFlattenFullHemisphereSurfaceAlignmentPage::setCentralSulcusDorsalMedialTip(const int nodeNum) { dorsalMedialTipNodeNumber = nodeNum; updateCentralSulcusLabels(); } //========================================================================= //========================================================================= //========================================================================= /** * constructor. */ GuiFlattenFullHemisphereFinishedPage::GuiFlattenFullHemisphereFinishedPage(QWidget* parent) : QWizardPage(parent) { setTitle("Finished"); const QString finishedText = "Flattening has been completed."; QLabel* finishedLabel = new QLabel(""); finishedLabel->setTextFormat(Qt::RichText); finishedLabel->setWordWrap(true); finishedLabel->setText(finishedText); // // Layout for page // QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(finishedLabel); layout->addStretch(); } /** * destructor. */ GuiFlattenFullHemisphereFinishedPage::~GuiFlattenFullHemisphereFinishedPage() { } /** * cleanup page (called when showing page after "Back" pressed). */ void GuiFlattenFullHemisphereFinishedPage::cleanupPage() { } /** * initialize the page (called when showing page after "Next" pressed). */ void GuiFlattenFullHemisphereFinishedPage::initializePage() { } /** * page is complete. */ bool GuiFlattenFullHemisphereFinishedPage::isComplete() { return true; } /** * validate a page. */ bool GuiFlattenFullHemisphereFinishedPage::validatePage() { return true; } caret-5.6.4~dfsg.1.orig/caret/GuiFilesModified.h0000664000175000017500000001760311572067322021207 0ustar michaelmichael #ifndef __GUI_FILES_MODIFIED_H__ #define __GUI_FILES_MODIFIED_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * ualong with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ /// This class is used to assist with updating the GUI when data files are modified. class GuiFilesModified { public: /// Constructor GuiFilesModified(); /// Destructor ~GuiFilesModified(); /// get all files were modified bool getAllFilesModified() const; /// set the status for all files void setStatusForAll(const bool status); /// set area color has been modified /// set has been modified void setAreaColorModified() { areaColor = true; } /// set areal estimation has been modified void setArealEstimationModified() { arealEstimation = true; } /// set border has been modified void setBorderModified() { border = true; } /// set border color has been modified void setBorderColorModified() { borderColor = true; } /// set cell has been modified void setCellModified() { cell = true; } /// set cell color has been modified void setCellColorModified() { cellColor = true; } /// set cell projection has been modified void setCellProjectionModified() { cellProjection = true; } /// set cocomac has been modified void setCocomacModified() { cocomac = true; } /// get contour has been modified bool getContourModified() const { return contour; } /// set contour has been modified void setContourModified() { contour = true; } /// set contour cell has been modified void setContourCellModified() { contourCell = true; } /// set contour cell color has been modified void setContourCellColorModified() { contourCellColor = true; } /// get the coordinate has been modified bool getCoordinateModified() const { return coordinate; } /// set coordinate has been modified void setCoordinateModified() { coordinate = true; } /// set cut has been modified void setCutModified() { cut = true; } /// set deformation map has been modified void setDeformationMapModified() { deformationMap = true; } /// set deformation field has been modified void setDeformationFieldModified() { deformationField = true; } /// set foci has been modified void setFociModified() { foci = true; } /// set foci color has been modified void setFociColorModified() { fociColor = true; } /// set foci projection has been modified void setFociProjectionModified() { fociProjection = true; } /// set foci search has been modified void setFociSearchModified() { fociSearch = true; } /// set geodesic has been modified void setGeodesicModified() { geodesic = true; } /// set images has been modified void setImagesModified() { images = true; } /// get images has been modified bool getImagesModified() const { return images; } /// set lat lon has been modified void setLatLonModified() { latLon = true; } /// set metric has been modified void setMetricModified() { metric = true; } /// set paint has been modified void setPaintModified() { paint = true; } /// set palette has been modified void setPaletteModified() { palette = true; } /// set parameters has been modified void setParameterModified() { parameter = true; } /// set probabilisitic atlas has been modified void setProbabilisticAtlasModified() { probabilisticAtlas = true; } /// set rgb paint has been modified void setRgbPaintModified() { rgbPaint = true; } /// set scene has been modified void setSceneModified() { scene = true; } /// set section has been modified void setSectionModified() { section = true; } /// set study collection has been modified void setStudyCollectionModified() { studyCollection = true; } /// set study metadata has been modified void setStudyMetaDataModified() { studyMetaData = true; } /// set surface shape has been modified void setSurfaceShapeModified() { surfaceShape = true; } /// set vector has been modified void setVectorModified() { vector = true; } /// set topography has been modified void setTopographyModified() { topography = true; } /// get topology has been modified bool getTopologyModified() const { return topology; } /// set topology has been modified void setTopologyModified() { topology = true; } /// set transformation matrix has been modified void setTransformationMatrixModified() { transformationMatrix = true; } /// set transformation data file has been modified void setTransformationDataModified() { transformationData = true; } /// get transformation data file has been modified bool getTransformationDataModified() const { return transformationData; } /// get volume has been modified bool getVolumeModified() const { return volume; } /// set volume has been modified void setVolumeModified() { volume = true; } /// get vtk model has been modified bool getVtkModelModified() const { return vtkModel; } /// set vtk model has been modified void setVtkModelModified() { vtkModel = true; } /// set vocabulary modified void setVocabularyModified() { vocabulary = true; } /// get vocabulary modfiied bool getVocabularyModified() { return vocabulary; } /// set wustl region has been modified void setWustlRegionModified() { wustlRegion = true; } /// set inhibit coordinate file surface default scaling void setInhibitSurfaceDefaultScaling() { inhibitDefaultSurfaceScaling = true; } protected: bool areaColor; bool arealEstimation; bool border; bool borderColor; bool cell; bool cellColor; bool cellProjection; bool cocomac; bool contour; bool contourCell; bool contourCellColor; bool coordinate; bool cut; bool deformationField; bool deformationMap; bool foci; bool fociColor; bool fociProjection; bool fociSearch; bool geodesic; bool images; bool latLon; bool metric; bool paint; bool palette; bool parameter; bool probabilisticAtlas; bool rgbPaint; bool scene; bool section; bool studyCollection; bool studyMetaData; bool surfaceShape; bool vector; bool topography; bool topology; bool transformationMatrix; bool transformationData; bool vocabulary; bool volume; bool vtkModel; bool wustlRegion; bool inhibitDefaultSurfaceScaling; friend class GuiMainWindow; }; #endif // __GUI_FILES_MODIFIED_H__ caret-5.6.4~dfsg.1.orig/caret/GuiFilesModified.cxx0000664000175000017500000000623311572067322021557 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "GuiFilesModified.h" /** * Constructor. */ GuiFilesModified::GuiFilesModified() { inhibitDefaultSurfaceScaling = false; setStatusForAll(false); } /** * Destructor. */ GuiFilesModified::~GuiFilesModified() { } /** * get all files were modified. */ bool GuiFilesModified::getAllFilesModified() const { const bool allModified = areaColor && arealEstimation && border && borderColor && cell && cellColor && cellProjection && cocomac && contour && contourCell && contourCellColor && coordinate && cut && deformationField && deformationMap && foci && fociColor && fociProjection && fociSearch && geodesic && images && latLon && metric && paint && palette && parameter && probabilisticAtlas && rgbPaint && scene && section && studyCollection && studyMetaData && surfaceShape && vector && topography && topology && transformationMatrix && transformationData && vocabulary && volume && vtkModel && wustlRegion; return allModified; } /** * set the status for all files. */ void GuiFilesModified::setStatusForAll(const bool status) { areaColor = status; arealEstimation = status; border = status; borderColor = status; cell = status; cellColor = status; cellProjection = status; cocomac = status; contour = status; contourCell = status; contourCellColor = status; coordinate = status; cut = status; deformationField = status; deformationMap = status; foci = status; fociColor = status; fociProjection = status; fociSearch = status; geodesic = status; images = status; latLon = status; metric = status; paint = status; palette = status; parameter = status; probabilisticAtlas = status; rgbPaint = status; scene = status; section = status; studyCollection = studyCollection; studyMetaData = studyMetaData; surfaceShape = status; vector = status; topography = status; topology = status; transformationMatrix = status; transformationData = status; vocabulary = status; volume = status; vtkModel = status; wustlRegion = status; } caret-5.6.4~dfsg.1.orig/caret/GuiFileSelectionListWidget.h0000664000175000017500000000467611572067322023237 0ustar michaelmichael #ifndef __GUI_FILE_SELECTION_LIST_WIDGET_H__ #define __GUI_FILE_SELECTION_LIST_WIDGET_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include class QListWidget; /// widget that contains a list widget and buttons for selecting a group of files class GuiFileSelectionListWidget : public QGroupBox { Q_OBJECT public: // constructor GuiFileSelectionListWidget(const QString& groupBoxTitle, QWidget* parent = 0); // destructor ~GuiFileSelectionListWidget(); // set the file selection filters void setFileSelectionFilters(const QStringList& fileSelectionFiltersIn); // add files void addFiles(const QStringList& sl); // remove all files void removeAllFiles(); // get the files from the list widget void getFileNames(QStringList& fileNames) const; // get the files from the list widget void getFileNames(std::vector& fileNames) const; // see if there are files in the list widget bool containsFiles() const; signals: // emitted when a file is add/removed void signalFilesChanged(); protected slots: // slot for adding files void slotAddFilesPushButton(); // slot for removing files void slotRemoveFilesPushButton(); protected: /// the list widget QListWidget* listWidget; /// the file selection filters QStringList fileSelectionFilters; }; #endif // __GUI_FILE_SELECTION_LIST_WIDGET_H__ caret-5.6.4~dfsg.1.orig/caret/GuiFileSelectionListWidget.cxx0000664000175000017500000001177411572067322023607 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "WuQFileDialog.h" #include #include #include #include #include "GuiFileSelectionListWidget.h" #include "QtUtilities.h" /** * constructor. */ GuiFileSelectionListWidget::GuiFileSelectionListWidget(const QString& groupBoxTitle, QWidget* parent) : QGroupBox(groupBoxTitle, parent) { // // List Widget for files // listWidget = new QListWidget; listWidget->setSelectionMode(QListWidget::ExtendedSelection); // // Add files push button // QPushButton* addFilesPushButton = new QPushButton("Add Files..."); addFilesPushButton->setAutoDefault(false); QObject::connect(addFilesPushButton, SIGNAL(clicked()), this, SLOT(slotAddFilesPushButton())); // // Remove files push button // QPushButton* removeFilesPushButton = new QPushButton("Remove Selected Files"); removeFilesPushButton->setAutoDefault(false); QObject::connect(removeFilesPushButton, SIGNAL(clicked()), this, SLOT(slotRemoveFilesPushButton())); // // Make the buttons the same size // QtUtilities::makeButtonsSameSize(addFilesPushButton, removeFilesPushButton); // // Layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->addWidget(addFilesPushButton); buttonsLayout->addWidget(removeFilesPushButton); // // Layout for this widget // QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(listWidget); layout->addLayout(buttonsLayout); } /** * destructor. */ GuiFileSelectionListWidget::~GuiFileSelectionListWidget() { } /** * set the file selection filters. */ void GuiFileSelectionListWidget::setFileSelectionFilters(const QStringList& fileSelectionFiltersIn) { fileSelectionFilters = fileSelectionFiltersIn; } /** * slot for adding files. */ void GuiFileSelectionListWidget::slotAddFilesPushButton() { WuQFileDialog fd(this); fd.setModal(true); fd.setAcceptMode(WuQFileDialog::AcceptOpen); fd.setFileMode(WuQFileDialog::ExistingFiles); fd.setDirectory(QDir::currentPath()); if (fileSelectionFilters.count() <= 0) { fd.setFilters(QStringList("All Files (*)")); } else { fd.setFilters(fileSelectionFilters); } if (fd.exec() == WuQFileDialog::Accepted) { const QStringList& files = fd.selectedFiles(); for (int i = 0; i < files.size(); i++) { listWidget->addItem(files.at(i)); } } emit signalFilesChanged(); } /** * slot for removing files. */ void GuiFileSelectionListWidget::slotRemoveFilesPushButton() { QStringList itemsToKeep; for (int i = 0; i < listWidget->count(); i++) { QListWidgetItem* lwi = listWidget->item(i); if (listWidget->isItemSelected(lwi) == false) { itemsToKeep << lwi->text(); } } listWidget->clear(); for (int i = 0; i < itemsToKeep.size(); i++) { listWidget->addItem(itemsToKeep.at(i)); } emit signalFilesChanged(); } /** * add files. */ void GuiFileSelectionListWidget::addFiles(const QStringList& sl) { for (int i = 0; i < sl.count(); i++) { listWidget->addItem(sl.at(i)); } emit signalFilesChanged(); } /** * see if there are files in the list widget. */ bool GuiFileSelectionListWidget::containsFiles() const { return (listWidget->count() > 0); } /** * remove all files. */ void GuiFileSelectionListWidget::removeAllFiles() { listWidget->clear(); emit signalFilesChanged(); } /** * get the files from the list widget. */ void GuiFileSelectionListWidget::getFileNames(QStringList& fileNames) const { fileNames.clear(); for (int i = 0; i < listWidget->count(); i++) { fileNames << listWidget->item(i)->text(); } } /** * get the files from the list widget. */ void GuiFileSelectionListWidget::getFileNames(std::vector& fileNames) const { fileNames.clear(); for (int i = 0; i < listWidget->count(); i++) { fileNames.push_back(listWidget->item(i)->text()); } } caret-5.6.4~dfsg.1.orig/caret/GuiFileSelectionButtonAndLineEditWidget.h0000664000175000017500000000505311572067322025626 0ustar michaelmichael #ifndef __GUI_FILE_SELECTION_BUTTON_AND_LINE_EDIT_WIDGET_H__ #define __GUI_FILE_SELECTION_BUTTON_AND_LINE_EDIT_WIDGET_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include class GuiFileSelectionButton; class QLineEdit; /// class creates horizontally layout of file selection button and a line edit class GuiFileSelectionButtonAndLineEditWidget : public QWidget { Q_OBJECT public: // constructor GuiFileSelectionButtonAndLineEditWidget(const QString& buttonText, const QString& fileFilter, const bool fileMustExistIn, QWidget* parent = 0); // destructor ~GuiFileSelectionButtonAndLineEditWidget(); // get the file name QString getFileName() const; // set the file name void setFileName(const QString& name); // set the button label's text void setButtonLabelText(const QString& text); /// get the line edit QLineEdit* getLineEdit() { return fileNameLineEdit; } /// get the file selection button GuiFileSelectionButton* getFileSelectionButton() { return fileSelectionButton; } protected slots: /// called when return pressed in the line edit void slotLineEditReturnPressed(); signals: // a filename was selected void fileSelected(const QString&); protected: /// the file selection button GuiFileSelectionButton* fileSelectionButton; /// the line edit QLineEdit* fileNameLineEdit; }; #endif // __GUI_FILE_SELECTION_BUTTON_AND_LINE_EDIT_WIDGET_H__ caret-5.6.4~dfsg.1.orig/caret/GuiFileSelectionButtonAndLineEditWidget.cxx0000664000175000017500000000640311572067322026201 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "GuiFileSelectionButton.h" #include "GuiFileSelectionButtonAndLineEditWidget.h" /** * constructor. */ GuiFileSelectionButtonAndLineEditWidget::GuiFileSelectionButtonAndLineEditWidget( const QString& buttonText, const QString& fileFilter, const bool fileMustExistIn, QWidget* parent) : QWidget(parent) { // // Create the file selection button // fileSelectionButton = new GuiFileSelectionButton(0, buttonText, fileFilter, fileMustExistIn); // // The file name line edit // fileNameLineEdit = new QLineEdit; fileNameLineEdit->setReadOnly(fileMustExistIn); // // Layout the widgets // QHBoxLayout* layout = new QHBoxLayout(this); layout->addWidget(fileSelectionButton); layout->addWidget(fileNameLineEdit); layout->setStretchFactor(fileSelectionButton, 0); layout->setStretchFactor(fileNameLineEdit, 100); // // Connect signals // QObject::connect(fileSelectionButton, SIGNAL(fileSelected(const QString&)), fileNameLineEdit, SLOT(setText(const QString&))); QObject::connect(fileSelectionButton, SIGNAL(fileSelected(const QString&)), this, SIGNAL(fileSelected(const QString&))); } /** * destructor. */ GuiFileSelectionButtonAndLineEditWidget::~GuiFileSelectionButtonAndLineEditWidget() { } /** * get the file name. */ QString GuiFileSelectionButtonAndLineEditWidget::getFileName() const { return fileNameLineEdit->text(); } /** * set the file name. */ void GuiFileSelectionButtonAndLineEditWidget::setFileName(const QString& name) { fileNameLineEdit->setText(name); } /** * set the button label's text. */ void GuiFileSelectionButtonAndLineEditWidget::setButtonLabelText(const QString& text) { fileSelectionButton->setText(text); } /** * called when return pressed in the line edit. */ void GuiFileSelectionButtonAndLineEditWidget::slotLineEditReturnPressed() { emit fileSelected(fileNameLineEdit->text()); } caret-5.6.4~dfsg.1.orig/caret/GuiFileSelectionButton.h0000664000175000017500000000335111572067322022420 0ustar michaelmichael #ifndef __GUI_FILE_SELECTION_BUTTON_H__ #define __GUI_FILE_SELECTION_BUTTON_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include /// button for selecting a file class GuiFileSelectionButton : public QPushButton { Q_OBJECT public: // constructor GuiFileSelectionButton(QWidget* parent, const QString& buttonText, const QString& fileFilter, const bool fileMustExistIn); // destructor ~GuiFileSelectionButton(); signals: /// file selected signal void fileSelected(const QString&); protected slots: // called when file selected void slotFileSelected(); protected: /// the file filter QString fileFilter; /// file must existflag bool fileMustExist; }; #endif // __GUI_FILE_SELECTION_BUTTON_H__ caret-5.6.4~dfsg.1.orig/caret/GuiFileSelectionButton.cxx0000664000175000017500000000437411572067322023001 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "WuQFileDialog.h" #include "GuiFileSelectionButton.h" /** * constructor */ GuiFileSelectionButton::GuiFileSelectionButton(QWidget* parent, const QString& buttonText, const QString& fileFilterIn, const bool fileMustExistIn) : QPushButton(buttonText, parent) { setAutoDefault(false); fileFilter = fileFilterIn; fileMustExist = fileMustExistIn; QObject::connect(this, SIGNAL(clicked()), this, SLOT(slotFileSelected())); } /** * destructor*/ GuiFileSelectionButton::~GuiFileSelectionButton() { } /** * called when file selected */ void GuiFileSelectionButton::slotFileSelected() { WuQFileDialog fd(this); fd.setDirectory(QDir::currentPath()); fd.setModal(true); fd.setWindowTitle("Choose File"); if (fileMustExist) { fd.setFileMode(WuQFileDialog::ExistingFile); fd.setAcceptMode(WuQFileDialog::AcceptOpen); } else { fd.setFileMode(WuQFileDialog::AnyFile); fd.setAcceptMode(WuQFileDialog::AcceptSave); } fd.setFilters(QStringList(fileFilter)); fd.selectFilter(fileFilter); if (fd.exec() == QDialog::Accepted) { QString name(fd.selectedFiles().at(0)); if (name.isEmpty() == false) { emit fileSelected(name); } } } caret-5.6.4~dfsg.1.orig/caret/GuiFileDialogWithInstructions.h0000664000175000017500000000276711572067322023771 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_FILE_DIALOG_WITH_INSTRUCTIONS_H__ #define __GUI_FILE_DIALOG_WITH_INSTRUCTIONS_H__ #include "WuQFileDialog.h" /// class for file dialog with instructions class GuiFileDialogWithInstructions : public WuQFileDialog { Q_OBJECT public: /// Constructor GuiFileDialogWithInstructions(QWidget* parent, const QString& instructions, const char* name = 0, bool modal = false); /// Destructor ~GuiFileDialogWithInstructions(); }; #endif // __GUI_FILE_DIALOG_WITH_INSTRUCTIONS_H__ caret-5.6.4~dfsg.1.orig/caret/GuiFileDialogWithInstructions.cxx0000664000175000017500000000324411572067322024333 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "GuiFileDialogWithInstructions.h" #include "QtUtilities.h" /** * Constructor. */ GuiFileDialogWithInstructions::GuiFileDialogWithInstructions(QWidget* parent, const QString& instructions, const char* name, bool modalIn) : WuQFileDialog(parent) { setObjectName(name); setModal(modalIn); QTextEdit* textEdit = new QTextEdit; textEdit->setLineWrapMode(QTextEdit::WidgetWidth); textEdit->setReadOnly(true); textEdit->setPlainText(instructions); addWidgets(textEdit, textEdit, textEdit); QtUtilities::setMaximumHeightToNinetyPercentOfScreenHeight(this); } /** * Destructor. */ GuiFileDialogWithInstructions::~GuiFileDialogWithInstructions() { } caret-5.6.4~dfsg.1.orig/caret/GuiDrawBorderDialog.h0000664000175000017500000001304411572067322021652 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_GUI_DRAW_BORDER_DIALOG_H__ #define __VE_GUI_DRAW_BORDER_DIALOG_H__ #include #include "WuQDialog.h" #include "BorderFile.h" class BrainModel; class GuiNodeAttributeColumnSelectionComboBox; class GuiVolumeSelectionControl; class QCheckBox; class QComboBox; class QGroupBox; class QLabel; class QLineEdit; class QPushButton; class QRadioButton; class QTabWidget; /// class for dialog used to draw borders class GuiDrawBorderDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiDrawBorderDialog(QWidget* parent); /// Destructor ~GuiDrawBorderDialog(); /// get the name of the border QString getBorderName() const; /// get the closed border flag bool getClosedBorderFlag() const; /// get the resampling density float getResampling() const; /// get the 3D flag bool getThreeDimensional() const; /// get the auto project border flag bool getAutoProjectBorder() const; /// new border just drawn - create it void createNewBorder(BrainModel* bm, Border& border); /// update the dialog void updateDialog(); /// Called when dialog is shown virtual void show(); private slots: /// called when apply button is pressed void slotApplyButton(); /// called when close button is pressed void slotCloseButton(); /// enable/disable items in the dialog based upon current selections void slotEnableDisableItems(); /// called when a paint column assignment is selected void slotAssignPaintColumnSelection(int col); /// called when reassign node name pushbutton is pressed void slotReassignNodeNamePushButton(); /// called when select name button is pressed void slotSelectNameButton(); private: /// create the assign nodes widget void createAssignNodesWidget(); /// create the assign voxels widget void createAssignVoxelsWidget(); /// create the main page QWidget* createMainPage(); /// border name line edit QLineEdit* nameLineEdit; /// resampling line edit QLineEdit* resamplingLineEdit; /// closed border radio button QRadioButton* closedBorderRadioButton; /// open border radio button QRadioButton* openBorderRadioButton; /// 2D radio button QRadioButton* twoDimensionalRadioButton; /// 3D radio button QRadioButton* threeDimensionalRadioButton; /// auto project yes radio button QRadioButton* autoProjectYesRadioButton; /// auto project no radio button QRadioButton* autoProjectNoRadioButton; /// color index for the border int borderColorIndex; /// assign tab widget QTabWidget* assignTabWidget; /// Vertical group box for node assignment QGroupBox* assignVGroup; /// assign nodes check box QCheckBox* assignNodesCheckBox; /// Horizontal box for node paint assignment //QWidget* assignNodesPaintQHBox; /// assign paint column label QLabel* assignPaintColumnLabel; /// paint column assignment combo box GuiNodeAttributeColumnSelectionComboBox* assignPaintColumnComboBox; /// paint column name assign line edit QLineEdit* assignPaintColumnNameLineEdit; /// reassign name push button QPushButton* reassignNamePushButton; /// qvbox containing reassignment items //QWidget* reassignNodesQVBox; /// reassign nodes paint column row //QWidget* reassignColumnQHBox; /// reassign nodes check box QCheckBox* reassignNodesCheckBox; /// reassign nodes name qhbox //QWidget* reassignNameQHBox; /// label for the reassignment name QLabel* reassignNameLabel; /// paint column for node reassignment GuiNodeAttributeColumnSelectionComboBox* reassignNodesPaintColumnComboBox; /// assign voxels vbox QWidget* assignVoxelsVBox; /// assign voxels within border check box QCheckBox* assignVoxelsWithinBorderCheckBox; /// assign voxels to volume control GuiVolumeSelectionControl* assignVoxelsVolumeSelectionControl; /// assign node widget QWidget* assignNodesVBox; /// assign voxels thickness label QLabel* assignVoxelsThicknessLabel; /// assign voxels slice thickness combo box QComboBox* assignVoxelsSliceThicknessComboBox; }; #endif // __VE_GUI_DRAW_BORDER_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiDrawBorderDialog.cxx0000664000175000017500000012063411572067322022231 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "AreaColorFile.h" #include "BorderColorFile.h" #include "BrainModelBorderSet.h" #include "BrainSet.h" #include "ColorFile.h" #include "DisplaySettingsBorders.h" #include "GuiBrainModelOpenGL.h" #include "GuiColorSelectionDialog.h" #include "GuiDrawBorderDialog.h" #include "GuiFilesModified.h" #include "GuiNameSelectionDialog.h" #include "GuiNodeAttributeColumnSelectionComboBox.h" #include "GuiMainWindow.h" #include "GuiVolumeSelectionControl.h" #include "QtUtilities.h" #include "PaintFile.h" #include "StringUtilities.h" #include "global_variables.h" /** * Constructor */ GuiDrawBorderDialog::GuiDrawBorderDialog(QWidget* parent) : WuQDialog(parent) { setWindowTitle("Draw Borders"); // // Vertical box layout of all items // QVBoxLayout* rows = new QVBoxLayout(this); rows->setMargin(2); rows->setSpacing(3); // // Create the tabbed pages // rows->addWidget(createMainPage()); // // // Dialog Buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; rows->addLayout(buttonsLayout); // // Apply button // QPushButton* applyButton = new QPushButton("Apply"); applyButton->setAutoDefault(false); QObject::connect(applyButton, SIGNAL(clicked()), this, SLOT(slotApplyButton())); buttonsLayout->addWidget(applyButton); // // Close button // QPushButton* closeButton = new QPushButton("Close"); closeButton->setAutoDefault(false); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(slotCloseButton())); buttonsLayout->addWidget(closeButton); QtUtilities::makeButtonsSameSize(applyButton, closeButton); updateDialog(); slotEnableDisableItems(); assignPaintColumnComboBox->setCurrentIndex(GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NEW); slotAssignPaintColumnSelection(GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NEW); } /** * Destructor */ GuiDrawBorderDialog::~GuiDrawBorderDialog() { } /** * Called when dialog is shown */ void GuiDrawBorderDialog::show() { if (theMainWindow->getBrainModelSurface() != NULL) { assignTabWidget->setCurrentIndex(assignTabWidget->indexOf(assignNodesVBox)); } else if (theMainWindow->getBrainModelVolume() != NULL) { assignTabWidget->setCurrentIndex(assignTabWidget->indexOf(assignVoxelsVBox)); } WuQDialog::show(); } /** * Create the main border drawing page. */ QWidget* GuiDrawBorderDialog::createMainPage() { QWidget* mainPageWidget = new QWidget; QVBoxLayout* mainPageLayout = new QVBoxLayout(mainPageWidget); // // Grid Layout for Attributes // QGroupBox* attributesGroup = new QGroupBox("Attributes"); mainPageLayout->addWidget(attributesGroup); QGridLayout* attributesGrid = new QGridLayout(attributesGroup); attributesGrid->setSpacing(3); // // Label and text box for border name // attributesGrid->addWidget(new QLabel("Name"), 0, 0, Qt::AlignLeft); nameLineEdit = new QLineEdit; nameLineEdit->setMinimumWidth(200); attributesGrid->addWidget(nameLineEdit, 0, 1, Qt::AlignLeft); // // Pushbutton for border name selection // QPushButton* nameButton = new QPushButton("Select..."); nameButton->setAutoDefault(false); nameButton->setFixedSize(nameButton->sizeHint()); attributesGrid->addWidget(nameButton, 0, 2, Qt::AlignLeft); QObject::connect(nameButton, SIGNAL(clicked()), this, SLOT(slotSelectNameButton())); // // Label and text box for border resampling // attributesGrid->addWidget(new QLabel("Resampling (mm)"), 1, 0, Qt::AlignLeft); resamplingLineEdit = new QLineEdit; resamplingLineEdit->setFixedWidth(100); resamplingLineEdit->setText("2.0"); attributesGrid->addWidget(resamplingLineEdit, 1, 1, Qt::AlignLeft); //------------------------------------------------------------------------------------- // // Horizontal box for type and dimensions // QHBoxLayout* typeDimHBoxLayout = new QHBoxLayout; mainPageLayout->addLayout(typeDimHBoxLayout); //-------------------------------------------------------------------------------------- // // Button Group for open and closed buttons // QGroupBox* typeGroupBox = new QGroupBox("Type"); QVBoxLayout* typeGroupLayout = new QVBoxLayout(typeGroupBox); QButtonGroup* typeButtonGroup = new QButtonGroup(this); typeDimHBoxLayout->addWidget(typeGroupBox); QObject::connect(typeButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotEnableDisableItems())); // // Closed Border Radio Button // closedBorderRadioButton = new QRadioButton("Closed (Boundary)"); typeGroupLayout->addWidget(closedBorderRadioButton); typeButtonGroup->addButton(closedBorderRadioButton); // // Open Border Radio Button // openBorderRadioButton = new QRadioButton("Open"); typeGroupLayout->addWidget(openBorderRadioButton); typeButtonGroup->addButton(openBorderRadioButton); //-------------------------------------------------------------------------------------- // // Button Group for 2D and 3D buttons // QGroupBox* dimensionGroupBox = new QGroupBox("Dimensions"); QVBoxLayout* dimensionLayout = new QVBoxLayout(dimensionGroupBox); QButtonGroup* dimensionButtonGroup = new QButtonGroup(this); typeDimHBoxLayout->addWidget(dimensionGroupBox); QObject::connect(dimensionButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotEnableDisableItems())); // // 2D radio button // twoDimensionalRadioButton = new QRadioButton("2D (Flat)"); dimensionLayout->addWidget(twoDimensionalRadioButton); dimensionButtonGroup->addButton(twoDimensionalRadioButton); // // 3D radio button // threeDimensionalRadioButton = new QRadioButton("3D"); dimensionLayout->addWidget(threeDimensionalRadioButton); dimensionButtonGroup->addButton(threeDimensionalRadioButton); // // Default to 2D // twoDimensionalRadioButton->setChecked(true); //-------------------------------------------------------------------------------------- // // Auto Project Yes/No radio buttons // autoProjectYesRadioButton = new QRadioButton("Yes"); autoProjectNoRadioButton = new QRadioButton("No"); // // Button Group for Auto Project Yes/No // QButtonGroup* autoProjectButtonGroup = new QButtonGroup(this); autoProjectButtonGroup->addButton(autoProjectYesRadioButton); autoProjectButtonGroup->addButton(autoProjectNoRadioButton); // // Group Box and Layout for Auto Project // QGroupBox* autoProjectGroupBox = new QGroupBox("Auto Project"); QVBoxLayout* autoProjectLayout = new QVBoxLayout(autoProjectGroupBox); autoProjectLayout->addWidget(autoProjectYesRadioButton); autoProjectLayout->addWidget(autoProjectNoRadioButton); typeDimHBoxLayout->addWidget(autoProjectGroupBox); // // Default proj off // autoProjectNoRadioButton->setChecked(true); // // Add stretch on right of type/dim/auto proj // typeDimHBoxLayout->addStretch(); //-------------------------------------------------------------------------------------- // // Assign nodes within closed border section // assignVGroup = new QGroupBox("Closed Border Assignment"); QVBoxLayout* assignLayout = new QVBoxLayout(assignVGroup); mainPageLayout->addWidget(assignVGroup); // // Assign tab widget // assignTabWidget = new QTabWidget; assignLayout->addWidget(assignTabWidget); // // add assign widgets // createAssignNodesWidget(); createAssignVoxelsWidget(); assignTabWidget->addTab(assignNodesVBox, "Surface Nodes"); assignTabWidget->addTab(assignVoxelsVBox, "Voxels"); assignTabWidget->setFixedSize(assignTabWidget->sizeHint()); return mainPageWidget; } /** * create the assign nodes widget. */ void GuiDrawBorderDialog::createAssignNodesWidget() { //QVBoxLayout* assignNodesLayout = new QVBoxLayout(assignNodesVBox); assignNodesCheckBox = new QCheckBox("Assign Paint Identifiers to Nodes Within Border"); //assignNodesLayout->addWidget(assignNodesCheckBox); QObject::connect(assignNodesCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotEnableDisableItems())); // // Paint column selection // //assignNodesPaintQHBox = new QWidget; //assignNodesLayout->addWidget(assignNodesPaintQHBox); assignPaintColumnLabel = new QLabel("Paint Column "); assignPaintColumnComboBox = new GuiNodeAttributeColumnSelectionComboBox( GUI_NODE_FILE_TYPE_PAINT, true, false, false); assignPaintColumnComboBox->setMaximumWidth(250); QObject::connect(assignPaintColumnComboBox, SIGNAL(itemSelected(int)), this, SLOT(slotAssignPaintColumnSelection(int))); assignPaintColumnNameLineEdit = new QLineEdit; assignPaintColumnNameLineEdit->setMaximumWidth(250); //QHBoxLayout* assignNodesPaintLayout = new QHBoxLayout(assignNodesPaintQHBox); //assignNodesPaintLayout->addWidget(new QLabel(" Paint Column ")); //assignNodesPaintLayout->addWidget(assignPaintColumnComboBox); //assignNodesPaintLayout->addWidget(assignPaintColumnNameLineEdit); //-------------------------------------------------------------------------------------- // // Reassign nodes within closed border section // //reassignNodesQVBox = new QWidget; //assignNodesLayout->addWidget(reassignNodesQVBox); //reassignColumnQHBox = new QWidget; reassignNodesCheckBox = new QCheckBox("Reassign Nodes With "); QObject::connect(reassignNodesCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotEnableDisableItems())); reassignNodesPaintColumnComboBox = new GuiNodeAttributeColumnSelectionComboBox( GUI_NODE_FILE_TYPE_PAINT, false, false, false); reassignNodesPaintColumnComboBox->setFixedWidth(250); //QHBoxLayout* reassignColumnLayout = new QHBoxLayout(reassignColumnQHBox); //reassignColumnLayout->addWidget(new QLabel(" ")); //reassignColumnLayout->addWidget(reassignNodesCheckBox); //reassignColumnLayout->addWidget(reassignNodesPaintColumnComboBox); //reassignColumnLayout->setStretchFactor(reassignNodesPaintColumnComboBox, 100); // //reassignColumnQHBox->setMaximumWidth(500); //reassignNameQHBox = new QWidget; reassignNamePushButton = new QPushButton("Named..."); QObject::connect(reassignNamePushButton, SIGNAL(clicked()), this, SLOT(slotReassignNodeNamePushButton())); //reassignNamePushButton->setFixedSize(reassignNamePushButton->sizeHint()); reassignNamePushButton->setAutoDefault(false); reassignNameLabel = new QLabel(" "); //reassignNameLabel->setFixedWidth(300); //reassignNameQHBox->setFixedSize(reassignNameQHBox->sizeHint()); //QHBoxLayout* reassignNameLayout = new QHBoxLayout(reassignNameQHBox); //reassignNameLayout->addWidget(new QLabel(" ")); //reassignNameLayout->addWidget(reassignNamePushButton); //reassignNameLayout->addWidget(reassignNameLabel); //reassignNameLayout->setStretchFactor(reassignNameLabel, 100); //QVBoxLayout* reassignNodesLayout = new QVBoxLayout(reassignNodesQVBox); //reassignNodesLayout->addWidget(reassignColumnQHBox); //reassignNodesLayout->addWidget(reassignNameQHBox); assignNodesVBox = new QWidget; QVBoxLayout* assignNodesLayout = new QVBoxLayout(assignNodesVBox); assignNodesLayout->addWidget(assignNodesCheckBox); QGridLayout* assignGrid = new QGridLayout; assignNodesLayout->addLayout(assignGrid); assignGrid->addWidget(assignPaintColumnLabel, 0, 0); assignGrid->addWidget(assignPaintColumnComboBox, 0, 1); assignGrid->addWidget(assignPaintColumnNameLineEdit, 0, 2); assignGrid->addWidget(reassignNodesCheckBox, 1, 0); assignGrid->addWidget(reassignNodesPaintColumnComboBox, 1, 1, 1, 2); assignGrid->addWidget(reassignNamePushButton, 2, 0); assignGrid->addWidget(reassignNameLabel, 2, 1, 1, 2); //assignGrid->setMaximumColumnWidth(1, 200); //assignGrid->setMaximumColumnWidth(2, 200); } /** * create the assign voxels widget. */ void GuiDrawBorderDialog::createAssignVoxelsWidget() { assignVoxelsWithinBorderCheckBox = new QCheckBox("Assign Voxels Within Closed Border"); QObject::connect(assignVoxelsWithinBorderCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotEnableDisableItems())); assignVoxelsVolumeSelectionControl = new GuiVolumeSelectionControl(0, false, false, true, false, false, false, false, GuiVolumeSelectionControl::LABEL_MODE_FILE_LABEL_AND_NAME, "assignVoxelsVolumeSelectionControl", false, false, false); assignVoxelsVolumeSelectionControl->setMaximumWidth(450); // // slice thickness // QWidget* thickHBox = new QWidget; assignVoxelsSliceThicknessComboBox = new QComboBox; assignVoxelsSliceThicknessComboBox->addItem("Current Slice"); assignVoxelsSliceThicknessComboBox->addItem("+/- 1 Slice"); assignVoxelsSliceThicknessComboBox->addItem("+/- 2 Slices"); assignVoxelsSliceThicknessComboBox->addItem("+/- 3 Slices"); assignVoxelsSliceThicknessComboBox->addItem("+/- 4 Slices"); assignVoxelsSliceThicknessComboBox->addItem("+/- 5 Slices"); QHBoxLayout* thickHBoxLayout = new QHBoxLayout(thickHBox); assignVoxelsThicknessLabel = new QLabel("Thickness "); thickHBoxLayout->addWidget(assignVoxelsThicknessLabel); thickHBoxLayout->addWidget(assignVoxelsSliceThicknessComboBox); thickHBox->setFixedSize(thickHBox->sizeHint()); assignVoxelsVBox = new QWidget; QVBoxLayout* assignVoxelsLayout = new QVBoxLayout(assignVoxelsVBox); assignVoxelsLayout->addWidget(assignVoxelsWithinBorderCheckBox); assignVoxelsLayout->addWidget(assignVoxelsVolumeSelectionControl); assignVoxelsLayout->addWidget(thickHBox); assignVoxelsVBox->setMaximumHeight(assignVoxelsVBox->sizeHint().height()); } /** * Called when Reassign nodes name pushbutton is pressed. */ void GuiDrawBorderDialog::slotReassignNodeNamePushButton() { GuiNameSelectionDialog nsd(this, GuiNameSelectionDialog::LIST_PAINT_NAMES_ALPHA); if (nsd.exec() == QDialog::Accepted) { QString name(nsd.getNameSelected()); if (name.isEmpty() == false) { reassignNameLabel->setText(name); } } } /** * Enable and disable items in dialog based upon current selections */ void GuiDrawBorderDialog::slotEnableDisableItems() { assignVGroup->setEnabled(false); assignNodesCheckBox->setEnabled(false); assignPaintColumnLabel->setEnabled(false); assignPaintColumnComboBox->setEnabled(false); assignPaintColumnNameLineEdit->setEnabled(false); reassignNodesCheckBox->setEnabled(false); reassignNodesPaintColumnComboBox->setEnabled(false); reassignNamePushButton->setEnabled(false); reassignNameLabel->setEnabled(false); assignVoxelsVBox->setEnabled(false); assignVoxelsWithinBorderCheckBox->setEnabled(false); assignVoxelsVolumeSelectionControl->setEnabled(false); assignVoxelsThicknessLabel->setEnabled(false); assignVoxelsSliceThicknessComboBox->setEnabled(false); if (closedBorderRadioButton->isChecked()) { assignNodesCheckBox->setEnabled(true); assignVGroup->setEnabled(true); if (assignNodesCheckBox->isChecked()) { assignPaintColumnLabel->setEnabled(true); assignPaintColumnComboBox->setEnabled(true); assignPaintColumnNameLineEdit->setEnabled(true); PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); const bool havePaints = (pf->getNumberOfColumns() > 0); if (havePaints) { reassignNodesCheckBox->setEnabled(true); if (reassignNodesCheckBox->isChecked()) { reassignNodesPaintColumnComboBox->setEnabled(true); reassignNamePushButton->setEnabled(true); reassignNameLabel->setEnabled(true); } } } assignVoxelsVBox->setEnabled(true); assignVoxelsWithinBorderCheckBox->setEnabled(true); if (assignVoxelsWithinBorderCheckBox->isChecked()) { assignVoxelsVolumeSelectionControl->setEnabled(true); assignVoxelsThicknessLabel->setEnabled(true); assignVoxelsSliceThicknessComboBox->setEnabled(true); } } } /** * Called when assignment paint column is selected. */ void GuiDrawBorderDialog::slotAssignPaintColumnSelection(int col) { PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); if (col == GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NEW) { assignPaintColumnNameLineEdit->setText("New Column Name"); } else if ((col >= 0) && (col < pf->getNumberOfColumns())) { assignPaintColumnNameLineEdit->setText(pf->getColumnName(col)); } } /** * Called when select name button is pressed. */ void GuiDrawBorderDialog::slotSelectNameButton() { static GuiNameSelectionDialog::LIST_ITEMS_TYPE itemForDisplay = GuiNameSelectionDialog::LIST_BORDER_COLORS_ALPHA; GuiNameSelectionDialog nsd(this, GuiNameSelectionDialog::LIST_ALL, itemForDisplay); if (nsd.exec() == QDialog::Accepted) { itemForDisplay = nsd.getSelectedItemType(); QString name(nsd.getNameSelected()); if (name.isEmpty() == false) { nameLineEdit->setText(name); if (StringUtilities::makeUpperCase(name) == "MEDIAL.WALL") { closedBorderRadioButton->setChecked(true); } else { const int len = name.length(); if (len > 3) { const QString last3(StringUtilities::makeLowerCase(name.mid(len - 3, 3))); if (last3 == "cut") { openBorderRadioButton->setChecked(true); } } if (name.indexOf("LANDMARK") != -1) { openBorderRadioButton->setChecked(true); } } } } } /** * Get the resampling density. */ float GuiDrawBorderDialog::getResampling() const { float resamplingDensity = resamplingLineEdit->text().toFloat(); if (resamplingDensity <= 0.0) { resamplingDensity = 2.0; resamplingLineEdit->setText(QString::number(resamplingDensity, 'f', 2)); } return resamplingDensity; } /** * Get the name of the border */ QString GuiDrawBorderDialog::getBorderName() const { return nameLineEdit->text(); } /** * Get closed border flag */ bool GuiDrawBorderDialog::getClosedBorderFlag() const { return closedBorderRadioButton->isChecked(); } /** * get the auto project border flag. */ bool GuiDrawBorderDialog::getAutoProjectBorder() const { return autoProjectYesRadioButton->isChecked(); } /** * Get the 3D flag */ bool GuiDrawBorderDialog::getThreeDimensional() const { return threeDimensionalRadioButton->isChecked(); } /** * Called when apply button is pressed */ void GuiDrawBorderDialog::slotApplyButton() { bool surfaceFlag = false; bool volumeFlag = false; if (theMainWindow->getBrainModelSurfaceAndVolume() != NULL) { return; } else if (theMainWindow->getBrainModelSurface() != NULL) { assignTabWidget->setCurrentIndex(assignTabWidget->indexOf(assignNodesVBox)); surfaceFlag = true; } else if (theMainWindow->getBrainModelVolume() != NULL) { BrainModelVolume* bmv = theMainWindow->getBrainModelVolume(); if (bmv->getMasterVolumeFile() == NULL) { QMessageBox::critical(this, "ERROR", "At least one volume must be displayed as\n" "an overlay or underlay to draw a border."); return; } assignTabWidget->setCurrentIndex(assignTabWidget->indexOf(assignVoxelsVBox)); volumeFlag = true; } QString errorMessage; bool errorFlag = false; bool closedBorder = false; if ((closedBorderRadioButton->isChecked() == false) && (openBorderRadioButton->isChecked() == false)) { errorFlag = true; if (errorMessage.isEmpty() == false) errorMessage.append("\n"); errorMessage.append("You must select closed or open border !"); } else { closedBorder = getClosedBorderFlag(); } const QString borderName = getBorderName(); if (borderName.isEmpty()) { errorFlag = true; if (errorMessage.isEmpty() == false) errorMessage.append("\n"); errorMessage.append("You must enter the border name !"); } const float resamplingDensity = getResampling(); if (resamplingDensity <= 0.0) { errorFlag = true; if (errorMessage.isEmpty() == false) errorMessage.append("\n"); errorMessage.append("Border Resampling must be greater than 0.0 !"); } if (surfaceFlag) { if (getClosedBorderFlag() && assignNodesCheckBox->isChecked() && (reassignNodesPaintColumnComboBox->count() > 0) && reassignNodesCheckBox->isChecked()) { QString name(StringUtilities::trimWhitespace(reassignNameLabel->text())); if (name.isEmpty()) { errorFlag = true; if (errorMessage.isEmpty() == false) errorMessage.append("\n"); errorMessage.append("Name for reassignment is missing.!"); } } } if (errorFlag) { QMessageBox::critical(this, "Error", errorMessage); return; } // // Find the matching color // bool borderColorMatch = false; BorderColorFile* borderColorFile = theMainWindow->getBrainSet()->getBorderColorFile(); borderColorIndex = borderColorFile->getColorIndexByName(borderName, borderColorMatch); // // Border color may need to be created // bool createBorderColor = false; if ((borderColorIndex >= 0) && (borderColorMatch == true)) { createBorderColor = false; } else if ((borderColorIndex >= 0) && (borderColorMatch == false)) { QString msg("Use border color \""); msg.append(borderColorFile->getColorNameByIndex(borderColorIndex)); msg.append("\" for border "); msg.append(borderName); msg.append(" ?"); QString noButton("No, define color "); noButton.append(borderName); /* if (GuiMessageBox::information(this, "Use Partially Matching Color", msg, "Yes", noButton, QString::null, 0) != 0) { createBorderColor = true; } */ QMessageBox msgBox(this); msgBox.setWindowTitle("Use Partially Matching Color"); msgBox.setText(msg); QPushButton* yesPushButton = msgBox.addButton("Yes", QMessageBox::ActionRole); QPushButton* noPushButton = msgBox.addButton(noButton, QMessageBox::ActionRole); msgBox.exec(); if (msgBox.clickedButton() == yesPushButton) { createBorderColor = false; } else if (msgBox.clickedButton() == noPushButton) { createBorderColor = true; } } else { createBorderColor = true; } if (createBorderColor) { QString title("Create Border Color: "); title.append(borderName); GuiColorSelectionDialog* csd = new GuiColorSelectionDialog(this, title, false, false, false, false); csd->exec(); // // Add new border color // float pointSize = 2.0, lineSize = 1.0; unsigned char r, g, b, a; ColorFile::ColorStorage::SYMBOL symbol; csd->getColorInformation(r, g, b, a, pointSize, lineSize, symbol); borderColorFile->addColor(borderName, r, g, b, a, pointSize, lineSize, symbol); borderColorIndex = borderColorFile->getNumberOfColors() - 1; // // Border Color File has changed // GuiFilesModified fm; fm.setBorderColorModified(); theMainWindow->fileModificationUpdate(fm); } // // Assigning nodes within a closed border // if (getClosedBorderFlag() && ((assignNodesCheckBox->isChecked() && surfaceFlag) || (assignVoxelsWithinBorderCheckBox->isChecked() && volumeFlag))) { // // Find the matching color // bool areaColorMatch = false; AreaColorFile* areaColorFile = theMainWindow->getBrainSet()->getAreaColorFile(); const int areaColorIndex = areaColorFile->getColorIndexByName(borderName, areaColorMatch); // // Area color may need to be created // if (areaColorMatch == false) { QString msg("Matching area color \""); msg.append(borderName); msg.append("\" not found"); QString borderButton("Use Border Color"); QString defineButton("Define Area Color "); int result = -1; if (areaColorIndex >= 0) { QString partialMatchButton("Use "); partialMatchButton.append(areaColorFile->getColorNameByIndex(areaColorIndex)); QMessageBox msgBox(this); msgBox.setWindowTitle("Set Area Color"); msgBox.setText(msg); QPushButton* useColorPushButton = msgBox.addButton(borderButton, QMessageBox::ActionRole); QPushButton* defineColorPushButton = msgBox.addButton(defineButton, QMessageBox::ActionRole); QPushButton* usePartialColorPushButton = msgBox.addButton(partialMatchButton, QMessageBox::ActionRole); msgBox.exec(); if (msgBox.clickedButton() == useColorPushButton) { result = 0; } else if (msgBox.clickedButton() == defineColorPushButton) { result = 1; } else if (msgBox.clickedButton() == usePartialColorPushButton) { result = 2; } /* result = QMessageBox::information(this, "Set Area Color", msg, borderButton, defineButton, partialMatchButton); */ } else { QMessageBox msgBox(this); msgBox.setWindowTitle("Set Area Color"); msgBox.setText(msg); QPushButton* useColorPushButton = msgBox.addButton(borderButton, QMessageBox::ActionRole); QPushButton* defineColorPushButton = msgBox.addButton(defineButton, QMessageBox::ActionRole); msgBox.exec(); if (msgBox.clickedButton() == useColorPushButton) { result = 0; } else if (msgBox.clickedButton() == defineColorPushButton) { result = 1; } /* result = GuiMessageBox::information(this, "Set Area Color", msg, borderButton, defineButton); */ } if (result == 0) { // // Copy border color to area color // unsigned char r, g, b, a; borderColorFile->getColorByIndex(borderColorIndex, r, g, b, a); float pointSize, lineSize; borderColorFile->getPointLineSizeByIndex(borderColorIndex, pointSize, lineSize); areaColorFile->addColor(borderName, r, g, b, a, pointSize, lineSize); // // Area Color File has changed // GuiFilesModified fm; fm.setAreaColorModified(); theMainWindow->fileModificationUpdate(fm); } else if (result == 1) { // // define the area color // QString title("Create Area Color: "); title.append(borderName); GuiColorSelectionDialog* csd = new GuiColorSelectionDialog(this, title, false, false, false, false); csd->exec(); // // Add new area color // float pointSize = 2.0, lineSize = 1.0; unsigned char r, g, b, a; ColorFile::ColorStorage::SYMBOL symbol; csd->getColorInformation(r, g, b, a, pointSize, lineSize, symbol); areaColorFile->addColor(borderName, r, g, b, a, pointSize, lineSize, symbol); // // Area Color File has changed // GuiFilesModified fm; fm.setAreaColorModified(); theMainWindow->fileModificationUpdate(fm); } else if (result == 2) { // // do nothing so that partially matching color is used // } } } if (surfaceFlag) { // // Make sure a flat or compressed medial wall surface is not rotated // if (twoDimensionalRadioButton->isChecked()) { BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { bool haveFlatSurface = false; switch (bms->getSurfaceType()) { case BrainModelSurface::SURFACE_TYPE_RAW: case BrainModelSurface::SURFACE_TYPE_FIDUCIAL: case BrainModelSurface::SURFACE_TYPE_INFLATED: case BrainModelSurface::SURFACE_TYPE_VERY_INFLATED: case BrainModelSurface::SURFACE_TYPE_SPHERICAL: case BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL: break; case BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL: case BrainModelSurface::SURFACE_TYPE_FLAT: case BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR: haveFlatSurface = true; break; case BrainModelSurface::SURFACE_TYPE_HULL: case BrainModelSurface::SURFACE_TYPE_UNKNOWN: case BrainModelSurface::SURFACE_TYPE_UNSPECIFIED: break; } if (haveFlatSurface) { float matrix[16]; bms->getRotationMatrix(0, matrix); if ((matrix[0] != 1.0) || (matrix[5] != 1.0) || (matrix[10] != 1.0)) { if (QMessageBox::warning(this, "WARNING", "The flat surface appears to be rotated which will\n" "prevent the border from being drawn correctly.\n" "Would you like to remove the rotation?", (QMessageBox::Yes | QMessageBox::No), QMessageBox::Yes) == QMessageBox::Yes) { // // Setting the view to dorsal resets the rotation matrix without // affecting the translate and scaling. // bms->setToStandardView(0, BrainModelSurface::VIEW_DORSAL); GuiBrainModelOpenGL::updateAllGL(theMainWindow->getBrainModelOpenGL()); } } } } } } theMainWindow->getBrainModelOpenGL()->resetLinearObjectBeingDrawn(); theMainWindow->getBrainModelOpenGL()->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_BORDER_DRAW); } /** * Create a new border for the brain model. */ void GuiDrawBorderDialog::createNewBorder(BrainModel* bm, Border& border) { QString borderName = getBorderName(); if (borderName.isEmpty()) { borderName = "No-Name"; } border.setName(borderName); border.setBorderColorIndex(borderColorIndex); if (getClosedBorderFlag()) { border.addBorderLink(border.getLinkXYZ(0)); } int dummy = 0; border.resampleBorderToDensity(getResampling(), 2, dummy); BrainModelVolume* bmv = dynamic_cast(bm); BrainModelSurface* bms = dynamic_cast(bm); if (bmv != NULL) { BorderFile* bf = theMainWindow->getBrainSet()->getVolumeBorderFile(); bf->addBorder(border); // // Assigning voxels within closed border // if (getClosedBorderFlag() && assignVoxelsWithinBorderCheckBox->isChecked()) { // // Get the selected volume // VolumeFile* vf = assignVoxelsVolumeSelectionControl->getSelectedVolumeFile(); if (vf != NULL) { vf->assignVoxelsWithinBorder(bmv->getSelectedAxis(0), borderName, &border, assignVoxelsSliceThicknessComboBox->currentIndex()); } } } else if (bms != NULL) { BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); BrainModelBorder* b = new BrainModelBorder(theMainWindow->getBrainSet(), &border, bms->getSurfaceType()); bmbs->addBorder(b); int newPaintColumnCreated = -1; // // drawing a closed border and assigning nodes within the border ? // if (getClosedBorderFlag() && assignNodesCheckBox->isChecked()) { PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); int column = assignPaintColumnComboBox->currentIndex(); const int paintIndex = pf->addPaintName(borderName); // // Does a new column need to be created ? // if (column < 0) { column = pf->getNumberOfColumns(); if (pf->getNumberOfColumns() == 0) { pf->setNumberOfNodesAndColumns(theMainWindow->getBrainSet()->getNumberOfNodes(), 1); } else { pf->addColumns(1); } newPaintColumnCreated = pf->getNumberOfColumns() - 1; } // // Set the paint column name // pf->setColumnName(column, assignPaintColumnNameLineEdit->text()); // // Assign the nodes within the closed border. // GuiBrainModelOpenGL* mainOpenGL = theMainWindow->getBrainModelOpenGL(); const BrainModelSurface* bms = mainOpenGL->getDisplayedBrainModelSurface(); if (bms != NULL) { const int numNodes = theMainWindow->getBrainSet()->getNumberOfNodes(); std::vector insideFlags(numNodes, false); const CoordinateFile* cf = bms->getCoordinateFile(); const float* coords = cf->getCoordinate(0); // // Drawing a 3D border ? // if (getThreeDimensional()) { GuiBrainModelOpenGL::updateAllGL(); BrainModelOpenGL* openGL = GuiBrainModelOpenGL::getOpenGLDrawing(); border.pointsInsideBorder3D(openGL->getSelectionModelviewMatrix(0), openGL->getSelectionProjectionMatrix(0), openGL->getSelectionViewport(0), coords, numNodes, insideFlags); } else { border.pointsInsideBorder2D(coords, numNodes, insideFlags); } // // Are nodes being reassigned ? // if (reassignNodesCheckBox->isChecked()) { const int reassignColumn = reassignNodesPaintColumnComboBox->currentIndex(); if ((reassignColumn >= 0) && (reassignColumn < pf->getNumberOfColumns())) { const int reassignPaintIndex = pf->getPaintIndexFromName( reassignNameLabel->text()); for (int j = 0; j < numNodes; j++) { if (insideFlags[j]) { if (pf->getPaint(j, reassignColumn) == reassignPaintIndex) { pf->setPaint(j, column, paintIndex); } } } } } else { for (int j = 0; j < numNodes; j++) { if (insideFlags[j]) { pf->setPaint(j, column, paintIndex); } } } } } if (newPaintColumnCreated >= 0) { // // Make paint column selection the new column // assignPaintColumnComboBox->updateComboBox(theMainWindow->getBrainSet()->getPaintFile()); assignPaintColumnComboBox->setCurrentIndex(newPaintColumnCreated); slotAssignPaintColumnSelection(newPaintColumnCreated); } if (getAutoProjectBorder()) { const int borderNumber = bmbs->getNumberOfBorders() - 1; if (borderNumber >= 0) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); bmbs->projectBorders(bms, true, borderNumber, borderNumber); QApplication::restoreOverrideCursor(); } } } // // Border File has changed // DisplaySettingsBorders* dsb = theMainWindow->getBrainSet()->getDisplaySettingsBorders(); dsb->setDisplayBorders(true); GuiFilesModified fm; fm.setBorderModified(); fm.setPaintModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(NULL); } /** * Called when close button is pressed */ void GuiDrawBorderDialog::slotCloseButton() { theMainWindow->getBrainModelOpenGL()->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_VIEW); reject(); } /** * Update the dialog. */ void GuiDrawBorderDialog::updateDialog() { assignPaintColumnComboBox->updateComboBox(theMainWindow->getBrainSet()->getPaintFile()); reassignNodesPaintColumnComboBox->updateComboBox(theMainWindow->getBrainSet()->getPaintFile()); slotAssignPaintColumnSelection(assignPaintColumnComboBox->currentIndex()); assignVoxelsVolumeSelectionControl->updateControl(); slotEnableDisableItems(); } caret-5.6.4~dfsg.1.orig/caret/GuiDistortionDialog.h0000664000175000017500000000460011572067322021753 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_DISTORTION_DIALOG_H__ #define __GUI_DISTORTION_DIALOG_H__ #include "WuQDialog.h" class GuiBrainModelSelectionComboBox; class BrainModelSurface; class GuiNodeAttributeColumnSelectionComboBox; class QLineEdit; /// Dialog for generating surface distortion measurements class GuiDistortionDialog : public WuQDialog { Q_OBJECT public: /// constructor GuiDistortionDialog(QWidget* parent, BrainModelSurface* bmsIn); /// destructor ~GuiDistortionDialog(); private slots: /// called when OK/Cancel buttons pressed void done(int r); /// called when linear distortion column selected void slotLinearDistortion(int item); /// called when areal distortion column selected void slotArealDistortion(int item); private: /// brain model surface for which distortion is being calculated BrainModelSurface* bms; /// reference surface selection combo box GuiBrainModelSelectionComboBox* referenceSurfaceComboBox; /// areal distortion column name QLineEdit* arealDistortionNameLineEdit; /// areal distortion surface shape column GuiNodeAttributeColumnSelectionComboBox* arealDistortionColumnComboBox; /// linear distortion column name QLineEdit* linearDistortionNameLineEdit; /// linear distortion surface shape column GuiNodeAttributeColumnSelectionComboBox* linearDistortionColumnComboBox; }; #endif // __GUI_DISTORTION_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiDistortionDialog.cxx0000664000175000017500000002401511572067322022330 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include "BrainModelSurfaceDistortion.h" #include "BrainSet.h" #include "GuiBrainModelSelectionComboBox.h" #include "GuiDistortionDialog.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "GuiNodeAttributeColumnSelectionComboBox.h" #include "QtUtilities.h" #include "SurfaceShapeFile.h" #include "global_variables.h" /** * Constructor */ GuiDistortionDialog::GuiDistortionDialog(QWidget* parent, BrainModelSurface* bmsIn) : WuQDialog(parent) { setModal(true); bms = bmsIn; setWindowTitle("Distortion Measurement"); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // Group box for surfaces // QGroupBox* surfaceGroupBox = new QGroupBox("Surfaces"); QGridLayout* surfaceGroupGridLayout = new QGridLayout(surfaceGroupBox); dialogLayout->addWidget(surfaceGroupBox); // // current surface // surfaceGroupGridLayout->addWidget(new QLabel("Surface"), 0, 0); surfaceGroupGridLayout->addWidget(new QLabel(bms->getDescriptiveName()), 0, 1); // // Reference surface // surfaceGroupGridLayout->addWidget(new QLabel("Reference Surface"), 1, 0); referenceSurfaceComboBox = new GuiBrainModelSelectionComboBox(false, true, false, "", 0); surfaceGroupGridLayout->addWidget(referenceSurfaceComboBox, 1, 1); // // Group box for distortion name and selection // QGroupBox* distortionGroupBox = new QGroupBox("Distortion"); QGridLayout* distortionGridLayout = new QGridLayout(distortionGroupBox); dialogLayout->addWidget(distortionGroupBox); // // Names of columns // distortionGridLayout->addWidget(new QLabel("Distortion Type"), 0, 0); distortionGridLayout->addWidget(new QLabel("Column Name"), 0, 1); distortionGridLayout->addWidget(new QLabel("Surface Shape Column"), 0, 2); SurfaceShapeFile* ssf = theMainWindow->getBrainSet()->getSurfaceShapeFile(); // // Areal distortion // distortionGridLayout->addWidget(new QLabel("Areal Distortion"), 1, 0); arealDistortionNameLineEdit = new QLineEdit; distortionGridLayout->addWidget(arealDistortionNameLineEdit, 1, 1); arealDistortionColumnComboBox = new GuiNodeAttributeColumnSelectionComboBox( GUI_NODE_FILE_TYPE_SURFACE_SHAPE, true, true, false); distortionGridLayout->addWidget(arealDistortionColumnComboBox, 1, 2); QObject::connect(arealDistortionColumnComboBox, SIGNAL(itemSelected(int)), this, SLOT(slotArealDistortion(int))); int arealDistortionColumnNumber = ssf->getArealDistortionColumnNumber(); if (arealDistortionColumnNumber < 0) { arealDistortionColumnNumber= GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NEW; } arealDistortionColumnComboBox->setCurrentIndex(arealDistortionColumnNumber); slotArealDistortion(arealDistortionColumnNumber); // // Linear distortion // distortionGridLayout->addWidget(new QLabel("Linear Distortion"), 2, 0); linearDistortionNameLineEdit = new QLineEdit; distortionGridLayout->addWidget(linearDistortionNameLineEdit, 2, 1); linearDistortionColumnComboBox = new GuiNodeAttributeColumnSelectionComboBox( GUI_NODE_FILE_TYPE_SURFACE_SHAPE, true, true, false); distortionGridLayout->addWidget(linearDistortionColumnComboBox); QObject::connect(linearDistortionColumnComboBox, SIGNAL(itemSelected(int)), this, SLOT(slotLinearDistortion(int))); int linearDistortionColumnNumber = ssf->getLinearDistortionColumnNumber(); if (linearDistortionColumnNumber < 0) { linearDistortionColumnNumber= GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NEW; } linearDistortionColumnComboBox->setCurrentIndex(linearDistortionColumnNumber); slotLinearDistortion(linearDistortionColumnNumber); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); dialogLayout->addLayout(buttonsLayout); // // OK button // QPushButton* okButton = new QPushButton("OK"); buttonsLayout->addWidget(okButton); QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); // // Cancel button // QPushButton* cancelButton = new QPushButton("Cancel"); buttonsLayout->addWidget(cancelButton); QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); QtUtilities::makeButtonsSameSize(okButton, cancelButton); } /** * */ GuiDistortionDialog::~GuiDistortionDialog() { } /** * called when linear distortion column selected. */ void GuiDistortionDialog::slotLinearDistortion(int item) { SurfaceShapeFile* ssf = theMainWindow->getBrainSet()->getSurfaceShapeFile(); if (item >= 0) { linearDistortionNameLineEdit->setText(ssf->getColumnName(item)); } else { linearDistortionNameLineEdit->setText("Linear Distortion"); } } /** * called when areal distortion column selected. */ void GuiDistortionDialog::slotArealDistortion(int item) { SurfaceShapeFile* ssf = theMainWindow->getBrainSet()->getSurfaceShapeFile(); if (item >= 0) { arealDistortionNameLineEdit->setText(ssf->getColumnName(item)); } else { arealDistortionNameLineEdit->setText("Areal Distortion"); } } /** * Called when OK or Cancel buttons pressed */ void GuiDistortionDialog::done(int r) { if (r == QDialog::Accepted) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); QString arealName(arealDistortionNameLineEdit->text()); // // Area Distortion selections // int arealDistortionColumn = arealDistortionColumnComboBox->currentIndex(); if (arealDistortionColumn == GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NEW) { arealDistortionColumn = BrainModelSurfaceDistortion::DISTORTION_COLUMN_CREATE_NEW; } else if (arealDistortionColumn == GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NONE) { arealDistortionColumn = BrainModelSurfaceDistortion::DISTORTION_COLUMN_DO_NOT_GENERATE; } const QString arealDistortionName(arealDistortionNameLineEdit->text()); if (arealDistortionColumn != BrainModelSurfaceDistortion::DISTORTION_COLUMN_DO_NOT_GENERATE) { if (arealDistortionName.isEmpty()) { QMessageBox::critical(this, "Error", "Name for areal distortion must be provided."); return; } } // // Linear Distortion selections // int linearDistortionColumn = linearDistortionColumnComboBox->currentIndex(); if (linearDistortionColumn == GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NEW) { linearDistortionColumn = BrainModelSurfaceDistortion::DISTORTION_COLUMN_CREATE_NEW; } else if (linearDistortionColumn == GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NONE) { linearDistortionColumn = BrainModelSurfaceDistortion::DISTORTION_COLUMN_DO_NOT_GENERATE; } const QString linearDistortionName(linearDistortionNameLineEdit->text()); if (linearDistortionColumn != BrainModelSurfaceDistortion::DISTORTION_COLUMN_DO_NOT_GENERATE) { if (linearDistortionName.isEmpty()) { QMessageBox::critical(this, "Error", "Name for linear distortion must be provided."); return; } } BrainModelSurfaceDistortion bmsd(theMainWindow->getBrainSet(), bms, referenceSurfaceComboBox->getSelectedBrainModelSurface(), bms->getTopologyFile(), theMainWindow->getBrainSet()->getSurfaceShapeFile(), arealDistortionColumn, linearDistortionColumn, arealDistortionName, linearDistortionName); try { bmsd.execute(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "Error", e.whatQString()); return; } GuiFilesModified fm; fm.setSurfaceShapeModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); } QDialog::done(r); } caret-5.6.4~dfsg.1.orig/caret/GuiDisplayControlSurfaceOverlayWidget.h0000664000175000017500000000713111572067322025464 0ustar michaelmichael #ifndef __GUI_DISPLAY_CONTROL_SURFACE_OVERLAY_WIDGET_H__ #define __GUI_DISPLAY_CONTROL_SURFACE_OVERLAY_WIDGET_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include class BrainModelSurfaceOverlay; class GuiDisplayControlDialog; class QCheckBox; class QComboBox; class QDoubleSpinBox; class WuQWidgetGroup; /// widget for controlling a surface overlay class GuiDisplayControlSurfaceOverlayWidget : public QGroupBox { Q_OBJECT public: // constructor GuiDisplayControlSurfaceOverlayWidget(const int overlayNumberIn, GuiDisplayControlDialog* displayControlDialogIn); // destructor ~GuiDisplayControlSurfaceOverlayWidget(); // update the widget void updateWidget(); protected slots: // called when data type selected void slotDataTypeComboBox(int item); // called when display column selected void slotDisplayColumnComboBox(int item); // called when threshold column selected void slotThresholdColumnComboBox(int item); // called when lighting checkbox toggled void slotLightingCheckBox(bool toggled); // called when opacity spin box value changed void slotOpacityDoubleSpinBox(double value); // called when display column metadata button clicked void slotDisplayColumnMetaDataToolButton(); // called when threshold column metadata button clicked void slotThresholdColumnMetaDataToolButton(); protected: /// get the surface model index from display control dialog int getSurfaceModelIndexFromDisplayControlDialog() const; /// update Display Control and redraw the surfaces void updateDisplayControlAndRedrawSurfaces(); /// edit column metadata void editColumnMetaData(const int columnNumber); /// the display control dialog this widget is part of GuiDisplayControlDialog* displayControlDialog; /// the overlay number int overlayNumber; /// lighting check box QCheckBox* lightingCheckBox; /// opacity double spin box QDoubleSpinBox* opacityDoubleSpinBox; /// data type combo box QComboBox* dataTypeComboBox; /// display column combo box QComboBox* displayColumnComboBox; /// threshold combo box QComboBox* thresholdColumnComboBox; /// data type widget group WuQWidgetGroup* dataTypeWidgetGroup; /// display column widget group WuQWidgetGroup* displayColumnWidgetGroup; /// threshold column widget group WuQWidgetGroup* thresholdColumnWidgetGroup; }; #endif // __GUI_DISPLAY_CONTROL_SURFACE_OVERLAY_WIDGET_H__ caret-5.6.4~dfsg.1.orig/caret/GuiDisplayControlSurfaceOverlayWidget.cxx0000664000175000017500000004251511572067322026044 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include "ArealEstimationFile.h" #include "BrainModelSurfaceNodeColoring.h" #include "BrainModelSurfaceOverlay.h" #include "BrainSet.h" #include "GuiBrainModelOpenGL.h" #include "GuiDisplayControlDialog.h" #include "GuiDisplayControlSurfaceOverlayWidget.h" #include "GuiMainWindow.h" #include "GuiDataFileCommentDialog.h" #include "MetricFile.h" #include "PaintFile.h" #include "RgbPaintFile.h" #include "SurfaceShapeFile.h" #include "TopographyFile.h" #include "WuQWidgetGroup.h" #include "global_variables.h" /** * constructor. */ GuiDisplayControlSurfaceOverlayWidget::GuiDisplayControlSurfaceOverlayWidget( const int overlayNumberIn, GuiDisplayControlDialog* displayControlDialogIn) : QGroupBox(0) { // // Set member variables // overlayNumber = overlayNumberIn; displayControlDialog = displayControlDialogIn; // // Set title // bool underlayFlag = false; const QString groupBoxTitle = theMainWindow->getBrainSet()->getSurfaceOverlay(overlayNumber)->getName(); if (overlayNumber == 0) { underlayFlag = true; } this->setTitle(groupBoxTitle); // // Data type selection control // QLabel* dataTypeLabel = new QLabel("Data Type"); dataTypeComboBox = new QComboBox; QObject::connect(dataTypeComboBox, SIGNAL(activated(int)), this, SLOT(slotDataTypeComboBox(int))); dataTypeWidgetGroup = new WuQWidgetGroup(this); dataTypeWidgetGroup->addWidget(dataTypeLabel); dataTypeWidgetGroup->addWidget(dataTypeComboBox); // // Display Column // QLabel* displayColumnLabel = new QLabel("Display Column"); QToolButton* displayColumnMetaDataToolButton = new QToolButton; displayColumnMetaDataToolButton->setText("?"); QObject::connect(displayColumnMetaDataToolButton, SIGNAL(clicked()), this, SLOT(slotDisplayColumnMetaDataToolButton())); displayColumnComboBox = new QComboBox; QObject::connect(displayColumnComboBox, SIGNAL(activated(int)), this, SLOT(slotDisplayColumnComboBox(int))); displayColumnWidgetGroup = new WuQWidgetGroup(this); displayColumnWidgetGroup->addWidget(displayColumnLabel); displayColumnWidgetGroup->addWidget(displayColumnMetaDataToolButton); displayColumnWidgetGroup->addWidget(displayColumnComboBox); // // Threshold Column // QLabel* thresholdColumnLabel = new QLabel("Threshold Column"); QToolButton* thresholdColumnMetaDataToolButton = new QToolButton; thresholdColumnMetaDataToolButton->setText("?"); QObject::connect(thresholdColumnMetaDataToolButton, SIGNAL(clicked()), this, SLOT(slotThresholdColumnMetaDataToolButton())); thresholdColumnComboBox = new QComboBox; QObject::connect(thresholdColumnComboBox, SIGNAL(activated(int)), this, SLOT(slotThresholdColumnComboBox(int))); thresholdColumnWidgetGroup = new WuQWidgetGroup(this); thresholdColumnWidgetGroup->addWidget(thresholdColumnLabel); thresholdColumnWidgetGroup->addWidget(thresholdColumnMetaDataToolButton); thresholdColumnWidgetGroup->addWidget(thresholdColumnComboBox); // // lighting // lightingCheckBox = new QCheckBox("Lighting"); QObject::connect(lightingCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotLightingCheckBox(bool))); // // Opacity // QLabel* opacityLabel = new QLabel("Opacity "); opacityDoubleSpinBox = new QDoubleSpinBox; opacityDoubleSpinBox->setMinimum(0.0); opacityDoubleSpinBox->setMaximum(1.0); opacityDoubleSpinBox->setDecimals(2); opacityDoubleSpinBox->setSingleStep(0.1); QObject::connect(opacityDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(slotOpacityDoubleSpinBox(double))); QWidget* opacityWidget = new QWidget; QHBoxLayout* opacityLayout = new QHBoxLayout(opacityWidget); opacityLayout->addWidget(opacityLabel); opacityLayout->addWidget(opacityDoubleSpinBox); opacityLayout->addStretch(); opacityLayout->setSpacing(0); if (underlayFlag) { opacityWidget->setHidden(true); } // // Layout // QGridLayout* gridLayout = new QGridLayout(this); gridLayout->addWidget(dataTypeLabel, 0, 0); gridLayout->addWidget(dataTypeComboBox, 0, 2); gridLayout->addWidget(displayColumnLabel, 1, 0); gridLayout->addWidget(displayColumnMetaDataToolButton, 1, 1); gridLayout->addWidget(displayColumnComboBox, 1, 2); gridLayout->addWidget(thresholdColumnLabel, 2, 0); gridLayout->addWidget(thresholdColumnMetaDataToolButton, 2, 1); gridLayout->addWidget(thresholdColumnComboBox, 2, 2); gridLayout->addWidget(lightingCheckBox, 3, 0); gridLayout->addWidget(opacityWidget, 3, 2); gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 0); gridLayout->setColumnStretch(2, 1000); gridLayout->setVerticalSpacing(0); updateWidget(); } /** * destructor. */ GuiDisplayControlSurfaceOverlayWidget::~GuiDisplayControlSurfaceOverlayWidget() { } /** * update the widget. */ void GuiDisplayControlSurfaceOverlayWidget::updateWidget() { // // Get the surface overlay and update it // const BrainModelSurfaceOverlay* bmsOverlay = theMainWindow->getBrainSet()->getSurfaceOverlay(overlayNumber); // // Load the data type combo box // dataTypeWidgetGroup->blockSignals(true); std::vector dataTypes; std::vector dataTypeNames; bmsOverlay->getDataTypesAndNames(dataTypes, dataTypeNames); const BrainModelSurfaceOverlay::OVERLAY_SELECTIONS selectedOverlay = bmsOverlay->getOverlay(getSurfaceModelIndexFromDisplayControlDialog()); const int numDataTypes = static_cast(dataTypes.size()); dataTypeComboBox->clear(); int selectedIndex = -1; for (int i = 0; i < numDataTypes; i++) { dataTypeComboBox->addItem(dataTypeNames[i], QVariant(static_cast(dataTypes[i]))); if (selectedOverlay == dataTypes[i]) { selectedIndex = i; } } if (selectedIndex >= 0) { dataTypeComboBox->setCurrentIndex(selectedIndex); } else { std::cout << "PROGRAM ERROR: Selected Overlay[" << overlayNumber << "] is not a valid overlay." << std::endl; } dataTypeWidgetGroup->blockSignals(false); // // Update the display column combo box // displayColumnWidgetGroup->blockSignals(true); displayColumnComboBox->clear(); displayColumnComboBox->addItems( bmsOverlay->getDisplayColumnNames( getSurfaceModelIndexFromDisplayControlDialog())); const int displayColumnSelected = bmsOverlay->getDisplayColumnSelected( getSurfaceModelIndexFromDisplayControlDialog()); if ((displayColumnSelected >= 0) && (displayColumnSelected < static_cast(displayColumnComboBox->count()))) { displayColumnComboBox->setCurrentIndex(displayColumnSelected); } const bool displayValidFlag = bmsOverlay->getDisplayColumnValid( getSurfaceModelIndexFromDisplayControlDialog()); displayColumnWidgetGroup->setEnabled(displayValidFlag); displayColumnWidgetGroup->blockSignals(false); // // Hide display controls if disabled // displayColumnWidgetGroup->setHidden(displayValidFlag == false); // // Update the threshold column combo box // thresholdColumnWidgetGroup->blockSignals(true); thresholdColumnComboBox->clear(); thresholdColumnComboBox->addItems( bmsOverlay->getThresholdColumnNames( getSurfaceModelIndexFromDisplayControlDialog())); const int thresholdColumnSelected = bmsOverlay->getThresholdColumnSelected( getSurfaceModelIndexFromDisplayControlDialog()); if ((thresholdColumnSelected >= 0) && (thresholdColumnSelected < static_cast(thresholdColumnComboBox->count()))) { thresholdColumnComboBox->setCurrentIndex(thresholdColumnSelected); } const bool thresholdValidFlag = bmsOverlay->getThresholdColumnValid( getSurfaceModelIndexFromDisplayControlDialog()); thresholdColumnWidgetGroup->setEnabled(thresholdValidFlag); thresholdColumnWidgetGroup->blockSignals(false); // // Hide threshold controls if disabled // thresholdColumnWidgetGroup->setHidden(thresholdValidFlag == false); // // Update lighting // lightingCheckBox->blockSignals(true); lightingCheckBox->setChecked(bmsOverlay->getLightingEnabled()); lightingCheckBox->blockSignals(false); // // Update opacity // opacityDoubleSpinBox->blockSignals(true); opacityDoubleSpinBox->setValue(bmsOverlay->getOpacity()); opacityDoubleSpinBox->blockSignals(false); } /** * called when data type selected. */ void GuiDisplayControlSurfaceOverlayWidget::slotDataTypeComboBox(int item) { // // Get the surface overlay // BrainModelSurfaceOverlay* bmsOverlay = theMainWindow->getBrainSet()->getSurfaceOverlay(overlayNumber); bmsOverlay->setOverlay(getSurfaceModelIndexFromDisplayControlDialog(), static_cast( dataTypeComboBox->itemData(item).toInt())); updateDisplayControlAndRedrawSurfaces(); } /** * update Display Control and redraw the surfaces. */ void GuiDisplayControlSurfaceOverlayWidget::updateDisplayControlAndRedrawSurfaces() { updateWidget(); // // Get the surface overlay // BrainModelSurfaceOverlay* bmsOverlay = theMainWindow->getBrainSet()->getSurfaceOverlay(overlayNumber); switch (bmsOverlay->getOverlay(getSurfaceModelIndexFromDisplayControlDialog())) { case BrainModelSurfaceOverlay::OVERLAY_NONE: break; case BrainModelSurfaceOverlay::OVERLAY_AREAL_ESTIMATION: displayControlDialog->updateArealEstimationItems(); break; case BrainModelSurfaceOverlay::OVERLAY_COCOMAC: displayControlDialog->updateCocomacItems(); break; case BrainModelSurfaceOverlay::OVERLAY_METRIC: displayControlDialog->updateMetricSelectionPage(); break; case BrainModelSurfaceOverlay::OVERLAY_PAINT: displayControlDialog->updatePaintColumnPage(); break; case BrainModelSurfaceOverlay::OVERLAY_PROBABILISTIC_ATLAS: break; case BrainModelSurfaceOverlay::OVERLAY_RGB_PAINT: displayControlDialog->updateRgbPaintItems(); break; case BrainModelSurfaceOverlay::OVERLAY_SECTIONS: displayControlDialog->updateSectionMainPage(); break; case BrainModelSurfaceOverlay::OVERLAY_SHOW_CROSSOVERS: break; case BrainModelSurfaceOverlay::OVERLAY_SHOW_EDGES: break; case BrainModelSurfaceOverlay::OVERLAY_SURFACE_SHAPE: displayControlDialog->updateShapeSelections(); break; case BrainModelSurfaceOverlay::OVERLAY_TOPOGRAPHY: displayControlDialog->updateTopographyItems(); break; case BrainModelSurfaceOverlay::OVERLAY_GEOGRAPHY_BLENDING: break; } theMainWindow->getBrainSet()->getNodeColoring()->assignColors(); GuiBrainModelOpenGL::updateAllGL(); } /** * called when display column selected. */ void GuiDisplayControlSurfaceOverlayWidget::slotDisplayColumnComboBox(int item) { // // Get the surface overlay // BrainModelSurfaceOverlay* bmsOverlay = theMainWindow->getBrainSet()->getSurfaceOverlay(overlayNumber); bmsOverlay->setDisplayColumnSelected(getSurfaceModelIndexFromDisplayControlDialog(), item); if (displayColumnComboBox->count() == thresholdColumnComboBox->count()) { bmsOverlay->setThresholdColumnSelected(getSurfaceModelIndexFromDisplayControlDialog(), item); thresholdColumnComboBox->blockSignals(true); thresholdColumnComboBox->setCurrentIndex(item); thresholdColumnComboBox->blockSignals(false); } updateDisplayControlAndRedrawSurfaces(); } /** * called when threshold column selected. */ void GuiDisplayControlSurfaceOverlayWidget::slotThresholdColumnComboBox(int item) { // // Get the surface overlay // BrainModelSurfaceOverlay* bmsOverlay = theMainWindow->getBrainSet()->getSurfaceOverlay(overlayNumber); bmsOverlay->setThresholdColumnSelected(getSurfaceModelIndexFromDisplayControlDialog(), item); updateDisplayControlAndRedrawSurfaces(); } /** * called when lighting checkbox toggled. */ void GuiDisplayControlSurfaceOverlayWidget::slotLightingCheckBox(bool toggled) { // // Get the surface overlay // BrainModelSurfaceOverlay* bmsOverlay = theMainWindow->getBrainSet()->getSurfaceOverlay(overlayNumber); bmsOverlay->setLightingEnabled(toggled); updateDisplayControlAndRedrawSurfaces(); } /** * called when opacity spin box value changed. */ void GuiDisplayControlSurfaceOverlayWidget::slotOpacityDoubleSpinBox(double value) { // // Get the surface overlay // BrainModelSurfaceOverlay* bmsOverlay = theMainWindow->getBrainSet()->getSurfaceOverlay(overlayNumber); bmsOverlay->setOpacity(value); updateDisplayControlAndRedrawSurfaces(); } /** * get the surface model index from display control dialog. */ int GuiDisplayControlSurfaceOverlayWidget::getSurfaceModelIndexFromDisplayControlDialog() const { const int indx = displayControlDialog->getSurfaceModelIndex(); return indx; } /** * edit column metadata. */ void GuiDisplayControlSurfaceOverlayWidget::editColumnMetaData(const int columnNumber) { // // Get the surface overlay // BrainModelSurfaceOverlay* bmsOverlay = theMainWindow->getBrainSet()->getSurfaceOverlay(overlayNumber); // // Get the data file // BrainSet* bs = theMainWindow->getBrainSet(); GiftiNodeDataFile* gndf = NULL; NodeAttributeFile* naf = NULL; switch (bmsOverlay->getOverlay(getSurfaceModelIndexFromDisplayControlDialog())) { case BrainModelSurfaceOverlay::OVERLAY_NONE: break; case BrainModelSurfaceOverlay::OVERLAY_AREAL_ESTIMATION: naf = bs->getArealEstimationFile(); break; case BrainModelSurfaceOverlay::OVERLAY_COCOMAC: break; case BrainModelSurfaceOverlay::OVERLAY_METRIC: gndf = bs->getMetricFile(); break; case BrainModelSurfaceOverlay::OVERLAY_PAINT: gndf = bs->getPaintFile(); break; case BrainModelSurfaceOverlay::OVERLAY_PROBABILISTIC_ATLAS: break; case BrainModelSurfaceOverlay::OVERLAY_RGB_PAINT: naf = bs->getRgbPaintFile(); break; case BrainModelSurfaceOverlay::OVERLAY_SECTIONS: break; case BrainModelSurfaceOverlay::OVERLAY_SHOW_CROSSOVERS: break; case BrainModelSurfaceOverlay::OVERLAY_SHOW_EDGES: break; case BrainModelSurfaceOverlay::OVERLAY_SURFACE_SHAPE: gndf = bs->getSurfaceShapeFile(); break; case BrainModelSurfaceOverlay::OVERLAY_TOPOGRAPHY: naf = bs->getTopographyFile(); break; case BrainModelSurfaceOverlay::OVERLAY_GEOGRAPHY_BLENDING: break; } // // Display help dialog // if (gndf != NULL) { if ((columnNumber >= 0) && (columnNumber < gndf->getNumberOfColumns())) { GuiDataFileCommentDialog* dfcd = new GuiDataFileCommentDialog(theMainWindow, gndf, columnNumber); dfcd->show(); } } if (naf != NULL) { if ((columnNumber >= 0) && (columnNumber < naf->getNumberOfColumns())) { GuiDataFileCommentDialog* dfcd = new GuiDataFileCommentDialog(theMainWindow, naf, columnNumber); dfcd->show(); } } } /** * called when display column metadata button clicked. */ void GuiDisplayControlSurfaceOverlayWidget::slotDisplayColumnMetaDataToolButton() { editColumnMetaData(displayColumnComboBox->currentIndex()); } /** * called when threshold column metadata button clicked. */ void GuiDisplayControlSurfaceOverlayWidget::slotThresholdColumnMetaDataToolButton() { editColumnMetaData(thresholdColumnComboBox->currentIndex()); } caret-5.6.4~dfsg.1.orig/caret/GuiDisplayControlDialog.h0000664000175000017500000031131011572067322022562 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_DISPLAY_CONTROL_DIALOG_H__ #define __GUI_DISPLAY_CONTROL_DIALOG_H__ #include #include #include "BrainSet.h" #include "DisplaySettingsVolume.h" #include "WuQDialog.h" // forward declarations help avoid lots of include files class QAction; class QButtonGroup; class QCheckBox; class QComboBox; class QDoubleSpinBox; class QGridLayout; class QGroupBox; class QLabel; class QLineEdit; class QListWidget; class QListWidgetItem; class QPushButton; class QRadioButton; class QScrollArea; class QSlider; class QSpinBox; class QStackedWidget; class QTextEdit; class QToolButton; class QVBoxLayout; class GuiBrainModelSelectionComboBox; class GuiBrainModelSurfaceSelectionComboBox; class GuiDisplayControlSurfaceOverlayWidget; class GuiFociSearchWidget; class GuiNodeAttributeColumnSelectionComboBox; class GuiTransformationMatrixSelectionControl; class GuiVolumeFileSelectionComboBox; class FociSearchFile; class QDoubleSpinBox; class QtTextEditDialog; class WuQWidgetGroup; /// Dialog for controlling display of data class GuiDisplayControlDialog : public WuQDialog { Q_OBJECT public: /// constructor GuiDisplayControlDialog(QWidget* parent); /// destructor ~GuiDisplayControlDialog(); /// show the scene page void showScenePage(); /// apply a scene (set display settings) void showScene(const SceneFile::Scene& scene, QString& errorMessage); /// create a scene (read display settings) std::vector saveScene(); /// Called when a new spec file is loaded void newSpecFileLoaded(); /// Update all items in the dialog void updateAllItemsInDialog(const bool filesChanged /* = false*/, const bool updateResultOfSceneChange); /// Update the toggles and combo boxes based upon overlay/underlay selections void updateOverlayUnderlayItemsNew(); /// update surface overlay widgets void updateSurfaceOverlayWidgets(); /// update the surface and volume selections void updateSurfaceAndVolumeItems(); /// update the volume selections void updateVolumeItems(); /// update the volume tooltips void updateVolumeToolTips(); /// update all border items in dialog. If the number of borders has changed /// pass true. void updateBorderItems(const bool bordersWereChanged = false); /// update border main page void updateBorderMainPage(); /// update border colors page void updateBorderColorPage(const bool filesChanged); /// update border name page void updateBorderNamePage(const bool filesChanged); /// update all cell items in dialog. If the number of cells has changed /// pass true. void updateCellItems(const bool cellsWereChanged = false); /// upate cell main page void updateCellMainPage(); /// update cell class page void updateCellClassPage(const bool cellsWereChanged); /// update cell color page void updateCellColorPage(const bool cellsWereChanged); /// update all cocomac items in dialog. void updateCocomacItems(); /// update the cocomac display page void updateCocomacDisplayPage(); /// update the cocomac information page void updateCocomacInformationPage(); /// update all contour items in dialog. void updateContourItems(const bool filesChanged = false); /// update all contour main page in dialog. void updateContourMainPage(); /// update all contour class page in dialog. void updateContourClassPage(const bool filesChanged); /// update all contour color page in dialog. void updateContourColorPage(const bool filesChanged); /// update the deformation field page void updateDeformationFieldPage(); /// update foci main page void updateFociMainPage(); /// update foci class page void updateFociClassPage(const bool filesChanged); /// update foci color page void updateFociColorPage(const bool filesChanged); /// update foci keyword page void updateFociKeywordPage(const bool filesChanged); /// update foci name page void updateFociNamePage(const bool filesChanged); /// update foci search page void updateFociSearchPage(const bool filesChanged); /// update foci page void updateFociTablePage(const bool filesChanged); /// update all foci items in dialog. If the number of foci has changed /// pass true. void updateFociItems(const bool fociWereChanged = false); /// update lat lon items void updateLatLonItems(); /// update geodesic items void updateGeodesicItems(); /// update the image items void updateImagesItems(); /// update all metric items in dialog void updateMetricItems(); /// update the metric misc page void updateMetricMiscellaneousPage(); /// update the metric selection page void updateMetricSelectionPage(); /// update the metric settings page void updateMetricSettingsPage(); /// update metric settings threshold column combo box. void updateMetricSettingsThresholdColumnComboBox(); /// update the misc items void updateMiscItems(); /// update model main page void updateModelMainPage(); /// update model settings page void updateModelSettingsPage(); /// update the model items in the dialog void updateModelItems(); /// update paint overlay/underlay selection void updatePaintOverlayUnderlaySelection(); /// update the paint items in the dialog void updatePaintItems(); /// update paint main page void updatePaintMainPage(); /// update paint column name page void updatePaintColumnPage(); /// update paint name page void updatePaintNamePage(); /// update the section main page void updateSectionMainPage(); /// update prob atlas surface overlay/underlay selection void updateProbAtlasSurfaceOverlayUnderlaySelection(); /// update all prob atlas surface items in dialog void updateProbAtlasSurfaceItems(const bool filesWereChanged = false); /// update prob atlas surface main page void updateProbAtlasSurfaceMainPage(); /// update prob atlas surface channel page void updateProbAtlasSurfaceChannelPage(const bool filesWereChanged); /// update prob atlas surface area page void updateProbAtlasSurfaceAreaPage(const bool filesWereChanged); /// update all prob atlas volume main page void updateProbAtlasVolumeMainPage(); /// update all prob atlas volume area page void updateProbAtlasVolumeAreaPage(const bool filesChanged); /// update all prob atlas volume channel page void updateProbAtlasVolumeChannelPage(const bool filesChanged); /// update all prob atlas volume items in dialog void updateProbAtlasVolumeItems(const bool filesWereChanged = false); /// update region items void updateRegionItems(); /// update scene items void updateSceneItems(); /// update rgb paint overlay/underlay selections void updateRgbPaintOverlayUnderlaySelection(); /// update rgb paint main page void updateRgbPaintMainPage(); /// update rgb paint selection page void updateRgbPaintSelectionPage(); /// update all rgb paint items in dialog void updateRgbPaintItems(); /// update shape overlay/underlay selection void updateShapeOverlayUnderlaySelection(); /// update all surface shape selections in dialog void updateShapeSelections(); /// update the shape items void updateShapeItems(); /// update all surface shape settings in dialog void updateShapeSettings(); /// update the shape settings color mapping combo box void updateShapeSettingsColorMappingComboBox(); /// update vector items in dialog void updateVectorItems(); /// update vector settings page void updateVectorSettingsPage(); /// update vector selection page void updateVectorSelectionPage(); /// update all topography items in dialog void updateTopographyItems(); /// update areal estimation items. void updateArealEstimationItems(); /// current brain model surface index that is being controlled /// If negative then controlling all surfaces int getSurfaceModelIndex() const { return surfaceModelIndex; } /// update surface coloring mode section void updateSurfaceColoringModeSection(); private slots: /// called by OK (relabeled "Apply") button press. Overriding qtabdialog's /// accept prevents Ok button from closing the dialog. //void accept() {} /// called when surface model combo box is changed void slotSurfaceModelIndexComboBox(int item); /// called when overlay selection combo box is changed void slotOverlayNumberComboBox(int item); /// called when surface coloring mode is changed void slotSurfaceColoringModeComboBox(); /// called when page combo box selection is made void pageComboBoxSelection(int item); /// called when page back tool button pressed void slotPageBackToolButtonPressed(QAction*); /// called when page forward tool button pressed void slotPageForwardToolButtonPressed(QAction*); /// called when popup menu page selection is made void slotPageSelectionPopupMenu(QAction*); /// called when popup menu overlay selection is made void slotOverlaySelectionPopupMenu(QAction*); /// called when return is pressed in a line edit and by other methods to update graphics void applySelected(); /// called when help button pressed void slotHelpButton(); /// called to show a scene void slotShowScenePushButton(); /// called to append a new scene void slotAppendScenePushButton(); /// called to insert a new scene void slotInsertScenePushButton(); /// called to replace a scene void slotReplaceScenePushButton(); /// called to delete a scene void slotDeleteScenePushButton(); /// called when a scene is selected void slotSceneListBox(int item); /// called when a scene is selected void slotSceneListBox(QListWidgetItem* item); /// called to check all scenes void slotCheckAllScenesPushButton(); /// called to create a spec file from files used in selected scenes void slotCreateSpecFromSelectedScenesPushButton(); /// called to transfer identity window filters void slotTransferIdentityWindowFiltersPushButton(); /// called to display a histogram of the selecteed anatomy volume void slotAnatomyVolumeHistogram(); /// called when a volume primary overlay is selected void volumePrimaryOverlaySelection(int n); /// called when a volume secondary overlay is selected void volumeSecondaryOverlaySelection(int n); /// called when a volume underlay is selected void volumeUnderlaySelection(int n); /// called when a anatomy volume column is selected void volumeAnatomySelection(int n); /// called when a functional view volume viewing column is selected void volumeFunctionalViewSelection(int n); /// called when a volume threshold column is selected void volumeFunctionalThresholdSelection(int n); /// called when a paint volume column is selected void volumePaintSelection(int n); /// called when an rgb volume column is selected void volumeRgbSelection(int n); /// called when a segmentation volume column is selected void volumeSegmentationSelection(int n); /// called when a vector volume column is selected void volumeVectorSelection(int n); /// called to display comment info for volume void volumeAnatomyInfoPushButtonSelection(); /// called to display comment info for volume void volumeFunctionalViewInfoPushButtonSelection(); /// called to display comment info for volume void volumeFunctionalThreshInfoPushButtonSelection(); /// called to display comment info for volume void volumePaintInfoPushButtonSelection(); /// called to display comment info for volume void volumeProbAtlasInfoPushButtonSelection(); /// called to set prob atlas volume study metadata link void volumeProbAtlasVolumeStudyMetaDataPushButton(); /// called to display comment info for volume void volumeRgbInfoPushButtonSelection(); /// called to display comment info for volume void volumeSegmentationInfoPushButtonSelection(); /// called to display comment info for volume void volumeVectorInfoPushButtonSelection(); /// called to display metadata for anatomy volume void volumeAnatomyMetaDataPushButtonSelection(); /// called to display metadata for functional view volume void volumeFunctionalViewMetaDataPushButtonSelection(); /// called to display metadata for functional thresh volume void volumeFunctionalThreshMetaDataPushButtonSelection(); /// called to display metadata for paint volume void volumePaintMetaDataPushButtonSelection(); /// called to display metadata for rgb volume void volumeRgbMetaDataPushButtonSelection(); /// called to display metadata for segmentation volume void volumeSegmentationMetaDataPushButtonSelection(); /// called to display metadata for vector volume void volumeVectorMetaDataPushButtonSelection(); /// called to start the volume animation void slotVolumeAnimateStartPushButton(); /// called to stop the volume animation void slotVolumeAnimateStopPushButton(); /// called to set default brightness/contrast void slotDefaultVolumeContrastBrightness(); /// Called to display comment information about an areal estimation column. void arealEstimationCommentColumnSelection(int column); /// Called to display metadata information about an areal estimation column. void arealEstimationMetaDataColumnSelection(int column); /// read the areal estimation page. void readArealEstimationSelections(); /// called when a areal est file column is selected void arealEstFileSelection(int col); /// called when a metric file column is selected void metricDisplayColumnSelection(int col); /// called when a metric file column is selected void metricThresholdColumnSelection(int col); /// called when a metric file column comment is selected void metricCommentColumnSelection(int col); /// called when a metric metadata column is selected void metricMetaDataColumnSelection(int col); /// called when a metric histogram column is selected void metricHistogramColumnSelection(int col); /// called when a metric palette is selected void metricPaletteSelection(int itemNum); /// called when animate push button is selected void metricAnimatePushButtonSelection(); /// called when a paint file column is selected void paintColumnSelection(int col); /// called when a paint page ? button is clicked void paintCommentColumnSelection(int num); /// called when a paint page meta data button is clicked void paintMetaDataColumnSelection(int num); /// called when a lat lon page ? button is clicked void latLonCommentColumnSelection(int num); /// called when a geodesic page ? button is clicked void geodesicCommentColumnSelection(int num); // /// called when prob atlas file selected // void probAtlasFileSelection(); /// called when an rgb paint file column is selected void rgbPaintFileSelection(int col); /// called for RGB Paint Red comment display void rgbPaintRedCommentSelection(int col); /// called for RGB Paint Green comment display void rgbPaintGreenCommentSelection(int col); /// called for RGB Paint Blue comment display void rgbPaintBlueCommentSelection(int col); /// called for RGB Paint Red histogram display void rgbPaintRedHistogramSelection(int col); /// called for RGB Paint Green histogram display void rgbPaintGreenHistogramSelection(int col); /// called for RGB Paint Blue histogram display void rgbPaintBlueHistogramSelection(int col); /// called when an RGB Paint display mode selected void rgbDisplayModeSelection(int itemNumber); /// called when a surface shape file column is selected void shapeColumnSelection(int col); /// update shape min/max mapping settings void updateShapeMinMaxMappingSettings(); /// called when a surface shape column ? is selected void surfaceShapeCommentColumnSelection(int item); /// called when a surface shape column metadata M is selected void surfaceShapeMetaDataColumnSelection(int item); /// called when a surface shape column histogram H is selected void surfaceShapeHistogramColumnSelection(int item); /// reads the volume selections void readVolumeSelections(); /// reads the volume settings void readVolumeSettings(); /// reads the volume surface outline void readVolumeSurfaceOutline(); /// read the cocomac display page void readCocomacDisplayPage(); /// read the contour main page void readContourMainPage(); /// read the contour class page void readContourClassPage(); /// read the contour color page void readContourColorPage(); /// slot to turn all contour cell classes on void contourCellClassAllOn(); /// slot to turn all contour cell classes off void contourCellClassAllOff(); /// slot to turn all contour cell colors on void contourCellColorAllOn(); /// slot to turn all contour cell colors off void contourCellColorAllOff(); /// read the deformation field page void readDeformationFieldPage(); /// called when borders selected on borders or overlay/underlay surface page void showBordersToggleSlot(bool b); /// read border main page void readBorderMainPage(); /// read border color page void readBorderColorPage(); /// read border name page void readBorderNamePage(); /// called when border colors All On button is pressed void borderColorAllOn(); /// called when border colors All Off button is pressed void borderColorAllOff(); /// called when border name All On button is pressed void borderNameAllOn(); /// called when border name All Off button is pressed void borderNameAllOff(); /// called when cells selected on cells page or overlay/underlay surface page void showCellsToggleSlot(bool b); /// read the cell main page void readCellMainPage(); /// read the cell color page void readCellColorPage(); /// read the cell class page void readCellClassPage(); /// read the misc selections void readMiscSelections(); /// read the surface and volume selections void readSurfaceAndVolumeSelections(); /// called when cell class All On button is pressed void cellClassAllOn(); /// called when cell class All Off button is pressed void cellClassAllOff(); /// called when cell colors All On button is pressed void cellColorAllOn(); /// called when cell colors All Off button is pressed void cellColorAllOff(); /// called when foci selected on foci page or overlay/underlay surface page void showFociToggleSlot(bool b); /// called when foci in search toggled void showFociInSearchToggleSlot(bool); /// called when foci color mode changed void slotFociColorModeComboBox(int i); /// read the foci main page void readFociMainPage(const bool updateDisplay = true); /// read the foci class page void readFociClassPage(const bool updateDisplay = true); /// read the foci color page void readFociColorPage(const bool updateDisplay = true); /// read the foci keyword page void readFociKeywordPage(const bool updateDisplay = true); /// read the foci name page void readFociNamePage(const bool updateDisplay = true); /// read the foci search page void readFociSearchPage(const bool updateDisplay = true); /// read the foci table page void readFociTablePage(const bool updateDisplay = true); /// called when foci class All On button is pressed void fociClassAllOn(); /// called when foci class All Off button is pressed void fociClassAllOff(); /// called when foci class update button is pressed void fociClassUpdateButtonPressed(); /// called when foci colors All On button is pressed void fociColorAllOn(); /// called when foci colors All Off button is pressed void fociColorAllOff(); /// called when foci color update button is pressed void fociColorUpdateButtonPressed(); /// called when foci names All On button is pressed void fociNamesAllOn(); /// called when foci names All Off button is pressed void fociNamesAllOff(); /// called when foci name update button is pressed void fociNamesUpdateButtonPressed(); /// called when foci keywords All On button is pressed void fociKeywordsAllOn(); /// called when foci keywords All Off button is pressed void fociKeywordsAllOff(); /// called when foci keywords or tables Update button is pressed void fociKeywordsAndTablesUpdate(); /// called when foci tables All On button is pressed void fociTablesAllOn(); /// called when foci tables All Off button is pressed void fociTablesAllOff(); /// read the geodesic page void readGeodesicSelections(); /// read the lat lon page void readLatLonSelections(); /// read the metric misc page void readMetricMiscellaneousPage(); /// read the metric selection page void readMetricSelectionPage(); /// read metric L-to-L, R-to-R void readMetricL2LR2R(); /// read the metric settings page void readMetricSettingsPage(); /// called when metric threshold setting column combo box value changed void slotUpateMetricThresholdSettingValues(); /// read the region selections void readRegionSelections(); /// read rgb paint L-to-L, R-to-R void readRgbPaintL2LR2R(); /// read the rgb paint main page void readRgbPaintPageMain(); /// read the rgb paint selection page void readRgbPaintPageSelection(); /// read the surface shape selections void readShapeSelections(); /// read the surface shape settings void readShapeSettings(); /// read the shape L-to-L, R-to-R void readShapeL2LR2R(); /// read the scene selections void readSceneSelections(); /// called when surface shape color map selected void shapeColorMapSelection(int mapNumber); /// called when surface shape histogram button pressed void surfaceShapeHistogram(); /// create and update the surface shape selections void createAndUpdateSurfaceShapeSelections(); /// read the topography selections void readTopographySelections(); /// called when a type of topography is selected void topographyTypeSelection(int typeSelected); /// read the vector settings page void readVectorSettingsPage(); /// read the vector selection page void readVectorSelectionPage(); /// read the probabilistic atlas surface main page void readProbAtlasSurfaceMainPage(); /// read the probabilistic atlas surface channel page void readProbAtlasSurfaceChannelPage(); /// called to set prob atlas surface study metadata link void volumeProbAtlasSurfaceStudyMetaDataPushButton(); /// read the probabilistic atlas surface area page void readProbAtlasSurfaceAreaPage(); /// read the prob atlas L-to-L, R-to-R void readProbAtlasSurfaceL2LR2R(); /// called when a prob atlas surface display mode selection is made void probAtlasSurfaceModeSelection(int num); /// called when prob atlas surface all on channel button is pressed void probAtlasSurfaceChannelAllOn(); /// called when prob atlas surface all off channel button is pressed void probAtlasSurfaceChannelAllOff(); /// called when prob atlas surface all on areas button is pressed void probAtlasSurfaceAreasAllOn(); /// called when prob atlas surface all off areas button is pressed void probAtlasSurfaceAreasAllOff(); /// read the probabilistic Volume main page void readProbAtlasVolumeMainPage(); /// read the probabilistic Volume area page void readProbAtlasVolumeAreaPage(); /// read the probabilistic Volumechannel page void readProbAtlasVolumeChannelPage(); /// called when a prob atlas Volume display mode selection is made void probAtlasVolumeModeSelection(int num); /// called when prob atlas Volume all on channel button is pressed void probAtlasVolumeChannelAllOn(); /// called when prob atlas Volume all off channel button is pressed void probAtlasVolumeChannelAllOff(); /// called when prob atlas Volume all on areas button is pressed void probAtlasVolumeAreasAllOn(); /// called when prob atlas volume all off areas button is pressed void probAtlasVolumeAreasAllOff(); /// read the image selections void readImagesSelections(); /// called to read model main page items from dialog void readModelMainPage(); /// called to read model main page items from dialog void readModelSettingsPage(); /// called when all models on pushbutton pressed void slotModelsAllOn(); /// called when all models off pushbutton pressed void slotModelsAllOff(); /// read section page void readSectionMainPage(); /// read paint main page void readPaintMainPageSelections(); /// called to read paint items in the dialog void readPaintColumnSelections(); /// called to read paint L-to-L, R-to-R void readPaintL2LR2R(); /// called to read paint name selections void readPaintNameSelections(); /// called when paint name all on button is pressed void slotPaintNamesAllOnPushButton(); /// called when paint name all off button is pressed void slotPaintNamesAllOffPushButton(); /// read surface clipping page void readSurfaceClippingPage(); private: /// volume animate direction enum VOLUME_ANIMATE_DIRECTION { /// increment slices VOLUME_ANIMATE_DIRECTION_INCREMENT, /// decrement slices VOLUME_ANIMATE_DIRECTION_DECREMENT }; /// override of parent method virtual void resizeEvent(QResizeEvent* re); /// context menu event void contextMenuEvent(QContextMenuEvent* e); /// override of sizeHint (limits width of dialog but user can stretch) //virtual QSize sizeHint() const; /// update the data validity flag void updateDataValidityFlags(); /// update volume selection page void updateVolumeSelectionPage(); /// update volume settings page void updateVolumeSettingsPage(); /// update volume surface outline page void updateVolumeSurfaceOutlinePage(); /// Update the page selection combo box based upon enabled pages. void updatePageSelectionComboBox(); /// create overlay/underlay surface page new void createOverlayUnderlaySurfacePageNew(); /// create the cocomac display sub page void createCocomacDisplayPage(); /// create the cocomac file info sub page void createCocomacFileInformationPage(); /// create the contour main page void createContourMainPage(); /// create the contour class page void createContourClassPage(); /// create the contour color page void createContourColorPage(); /// create and update contour cell class buttons void createAndUpdateContourCellClassCheckBoxes(); /// create and update contour color class buttons void createAndUpdateContourCellColorCheckBoxes(); /// create the surface and volume page void createSurfaceAndVolumePage(); /// create the surface misc page void createSurfaceMiscPage(); /// create the probabilistic atlas surface main sub page void createProbAtlasSurfaceMainPage(); /// create the probabilistic atlas surface area sub page void createProbAtlasSurfaceAreaPage(); /// create the probabilistic atlas surface channel sub page void createProbAtlasSurfaceChannelPage(); /// create and update the check boxes for prob atlas surface channels void createAndUpdateProbAtlasSurfaceChannelCheckBoxes(); /// create and update the check boxes for prob atlas surface void createAndUpdateProbAtlasSurfaceAreaNameCheckBoxes(); /// create the probabilistic atlas volume main sub page void createProbAtlasVolumeMainPage(); /// create the probabilistic atlas volume area sub page void createProbAtlasVolumeAreaPage(); /// create the probabilistic atlas volume channel sub page void createProbAtlasVolumeChannelPage(); /// create and update the check boxes for prob atlas volume channels void createAndUpdateProbAtlasVolumeChannelCheckBoxes(); /// create and update the check boxes for prob atlas volume void createAndUpdateProbAtlasVolumeAreaNameCheckBoxes(); /// create the topography page void createTopographyPage(); /// create the rgb paint main page void createRgbPaintMainPage(); /// create the rgb paint selection page void createRgbPaintSelectionPage(); /// create the geodesic page void createGeodesicPage(); /// create and update the geodesic page void createAndUpdateGeodesicPage(); /// create the vector selection page void createVectorSelectionPage(); /// create the vector settings page void createVectorSettingsPage(); /// create the lat/lon page void createLatLonPage(); /// create and update the lat/lon page void createAndUpdateLatLonPage(); /// create the scene page void createScenePage(); /// get the selected scenes std::vector getSelectedScenes() const; /// set the selected scene void setSelectedSceneItem(const int item); /// create the region page void createRegionPage(); /// create the metric selections page void createMetricSelectionPage(); /// create the metric settings page void createMetricSettingsPage(); /// create and update metric selection page void createAndUpdateMetricSelectionPage(); /// create the metric miscellaneous page void createMetricMiscellaneousPage(); /// create the shape settings page void createShapeSettingsPage(); /// create the shape selection page void createShapeSelectionPage(); /// read shape color mapping min/max void readShapeColorMapping(); /// create the border main sub page void createBorderMainPage(); /// create the border name sub page void createBorderNamePage(); /// create the border color sub page void createBorderColorPage(); /// create and update border color toggles section void createAndUpdateBorderColorCheckBoxes(); /// create and update border name toggles section void createAndUpdateBorderNameCheckBoxes(); /// create the cell main sub page void createCellMainPage(); /// create the cell class page void createCellClassPage(); /// create the cell color page void createCellColorPage(); /// create and update cell class toggles section void createAndUpdateCellClassCheckBoxes(); /// create and update cell color toggles section void createAndUpdateCellColorCheckBoxes(); /// create the deformation field page void createDeformationFieldPage(); /// create the foci main sub page void createFociMainPage(); /// create the foci class page void createFociClassPage(); /// create the foci color page void createFociColorPage(); /// create the foci name page void createFociNamePage(); /// create the foci keywords page void createFociKeywordPage(); /// create foci search page void createFociSearchPage(); /// create the foci tables page void createFociTablePage(); /// create and update foci class toggles section void createAndUpdateFociClassCheckBoxes(); /// create and update foci color toggles section void createAndUpdateFociColorCheckBoxes(); /// create and update foci keywords toggles section void createAndUpdateFociKeywordCheckBoxes(); /// create and update foci names toggles section void createAndUpdateFociNamesCheckBoxes(); /// create and update foci table toggles section void createAndUpdateFociTableCheckBoxes(); /// create the overlay underlay volume setttings page void createOverlayUnderlayVolumeSettingsPage(); /// create the overlay underlay volume selection page void createOverlayUnderlayVolumeSelectionPage(); /// create the overlay underlay volume surface outline page void createOverlayUnderlayVolumeSurfaceOutlinePage(); /// create the images page void createImagesPage(); /// create the models main page void createModelsMainPage(); /// create and update the models main page void createAndUpdateModelsMainPage(); /// create the model settings page void createModelsSettingsPage(); /// create the section main page void createSectionMainPage(); /// create the paint column page void createPaintColumnPage(); /// create and update the paint columns void createAndUpdatePaintColumnPage(); /// create the paint name page void createPaintNamePage(); /// create and update the paint names void createAndUpdatePaintNamePage(); /// create the paint main page void createPaintMainPage(); /// Create a surface model combo box void createSurfaceModelIndexComboBox(); /// create the areal estimation page. void createArealEstimationPage(); /// Create and update the areal estimation page. void createAndUpdateArealEstimationPage(); /// Create the surface clipping page void createSurfaceClippingPage(); /// update the surface clipping page void updateSurfaceClippingPage(); /// Update the surface model combo box void updateSurfaceModelComboBoxes(); // display left-to-left right-to-right message void displayOverlayLeftToLeftRightToRightMessage(); /// enumerated types for pages enum PAGE_NAME { PAGE_NAME_AREAL_ESTIMATION, PAGE_NAME_BORDER_MAIN, PAGE_NAME_BORDER_COLOR, PAGE_NAME_BORDER_NAME, PAGE_NAME_CELL_MAIN, PAGE_NAME_CELL_CLASS, PAGE_NAME_CELL_COLOR, PAGE_NAME_COCOMAC_DISPLAY, PAGE_NAME_COCOMAC_INFORMATION, PAGE_NAME_CONTOUR_MAIN, PAGE_NAME_CONTOUR_CLASS, PAGE_NAME_CONTOUR_COLOR, PAGE_NAME_DEFORMATION_FIELD, PAGE_NAME_FOCI_MAIN, PAGE_NAME_FOCI_CLASS, PAGE_NAME_FOCI_COLOR, PAGE_NAME_FOCI_KEYWORD, PAGE_NAME_FOCI_NAME, PAGE_NAME_FOCI_SEARCH, PAGE_NAME_FOCI_TABLE, PAGE_NAME_GEODESIC, PAGE_NAME_IMAGES, PAGE_NAME_LATLON, PAGE_NAME_METRIC_MISCELLANEOUS, PAGE_NAME_METRIC_SELECTION, PAGE_NAME_METRIC_SETTINGS, PAGE_NAME_MODELS_MAIN, PAGE_NAME_MODELS_SETTINGS, PAGE_NAME_PAINT_COLUMN, PAGE_NAME_PAINT_MAIN, PAGE_NAME_PAINT_NAMES, PAGE_NAME_PROB_ATLAS_SURFACE_MAIN, PAGE_NAME_PROB_ATLAS_SURFACE_AREA, PAGE_NAME_PROB_ATLAS_SURFACE_CHANNEL, PAGE_NAME_PROB_ATLAS_VOLUME_MAIN, PAGE_NAME_PROB_ATLAS_VOLUME_AREA, PAGE_NAME_PROB_ATLAS_VOLUME_CHANNEL, PAGE_NAME_REGION, PAGE_NAME_RGB_PAINT_MAIN, PAGE_NAME_RGB_PAINT_SELECTION, PAGE_NAME_SCENE, PAGE_NAME_SECTION_MAIN, PAGE_NAME_SHAPE_SELECTION, PAGE_NAME_SHAPE_SETTINGS, PAGE_NAME_SURFACE_AND_VOLUME, PAGE_NAME_SURFACE_CLIPPING, PAGE_NAME_SURFACE_MISC, PAGE_NAME_SURFACE_OVERLAY_UNDERLAY_NEW, PAGE_NAME_VECTOR_SELECTION, PAGE_NAME_VECTOR_SETTINGS, PAGE_NAME_TOPOGRAPHY, PAGE_NAME_VOLUME_SELECTION, PAGE_NAME_VOLUME_SETTINGS, PAGE_NAME_VOLUME_SURFACE_OUTLINE, PAGE_NAME_INVALID }; /// get the name of a page QString getPageName(const PAGE_NAME pageName) const; /// show a display control page void showDisplayControlPage(const PAGE_NAME pageName, const bool updatePagesVisited); /// initialize the overlay for control be a page void initializeSelectedOverlay(const PAGE_NAME pageName); /// update the overlay number combo box void updateOverlayNumberComboBox(); /// default size for this dialog QSize dialogDefaultSize; /// page selection combo box QComboBox* pageComboBox; /// page back tool button QToolButton* pageBackToolButton; /// page forward tool button QToolButton* pageForwardToolButton; /// tracks pages as they are visited std::vector pagesVisited; /// current index in pages visited int pagesVisitedIndex; /// items for page combo box std::vector pageComboBoxItems; /// page widget stack QStackedWidget* pageWidgetStack; /// scroll area for widget stack QScrollArea* widgetStackScrollArea; /// pop up a text area dialog about a data type void displayDataInfoDialog(const QString& title, const QString& info); /// text area dialog for data info QtTextEditDialog* dataInfoDialog; /// flag used when creating the dialog to prevent some problems bool creatingDialog; /// new overlay/underlay surface page QWidget* pageOverlayUnderlaySurfaceNew; /// overlay/underlay surface widgets std::vector surfaceOverlayUnderlayWidgets; /// misc page QWidget* pageSurfaceMisc; /// prob atlas surface coloring to corresponding structures QCheckBox* probAtlasSurfaceApplySelectionToLeftAndRightStructuresFlagCheckBox; /// prob atlas surface main page QWidget* pageProbAtlasSurfaceMain; /// prob atlas surface channel page QWidget* pageProbAtlasSurfaceChannel; /// prob atlas surface channel sub page layout QVBoxLayout* probAtlasSurfaceSubPageChannelLayout; /// prob atlas surface area page QWidget* pageProbAtlasSurfaceArea; /// prob atlas surface area sub page layout QVBoxLayout* probAtlasSurfaceSubPageAreaLayout; /// prob atlas surface normal mode button QRadioButton* probAtlasSurfaceNormalButton; /// prob atlas surface threshold mode button QRadioButton* probAtlasSurfaceThresholdButton; /// prob atlas surface ??? as Unassigned button QCheckBox* probAtlasSurfaceUnassignedButton; /// number of prob atlas surface channel checkboxes being used int numValidProbAtlasSurfaceChannels; /// layout for probAtlasSurfaceChannelQVBox QGridLayout* probAtlasSurfaceChannelGridLayout; /// prob atlas surface channel button group QButtonGroup* probAtlasSurfaceChannelButtonGroup; /// prob atlas surface channel checkboxes std::vector probAtlasSurfaceChannelCheckBoxes; /// number of prob atlas surface areas checkboxes being used int numValidProbAtlasSurfaceAreas; /// layout for probAtlasSurfaceAreasQVBox QGridLayout* probAtlasSurfaceAreasGridLayout; /// prob atlas surface areas button group QButtonGroup* probAtlasSurfaceAreasButtonGroup; /// prob atlas surface areas checkboxes std::vector probAtlasSurfaceAreasCheckBoxes; /// prob atlas surface threshold display type ratio float spin box QDoubleSpinBox* probAtlasSurfaceThresholdRatioDoubleSpinBox; /// prob atlas volume main page QWidget* pageProbAtlasVolumeMain; /// prob atlas volume channel page QWidget* pageProbAtlasVolumeChannel; /// prob atlas volume channel sub page layout QVBoxLayout* probAtlasVolumeSubPageChannelLayout; /// prob atlas volume area sub page QWidget* pageProbAtlasVolumeArea; /// prob atlas volume area sub page QVBoxLayout* probAtlasVolumeSubPageAreaLayout; /// prob atlas volume normal mode button QRadioButton* probAtlasVolumeNormalButton; /// prob atlas volume threshold mode button QRadioButton* probAtlasVolumeThresholdButton; /// prob atlas volume ??? as Unassigned button QCheckBox* probAtlasVolumeUnassignedButton; /// number of prob atlas volume channel checkboxes being used int numValidProbAtlasVolumeChannels; /// layout for probAtlasVolumeChannelQVBox QGridLayout* probAtlasVolumeChannelGridLayout; /// prob atlas volume channel button group QButtonGroup* probAtlasVolumeChannelButtonGroup; /// prob atlas volume channel checkboxes std::vector probAtlasVolumeChannelCheckBoxes; /// number of prob atlas volume areas checkboxes being used int numValidProbAtlasVolumeAreas; /// layout for probAtlasVolumeAreasQVBox QGridLayout* probAtlasVolumeAreasGridLayout; /// prob atlas volume areas button group QButtonGroup* probAtlasVolumeAreasButtonGroup; /// prob atlas volume areas checkboxes std::vector probAtlasVolumeAreasCheckBoxes; /// prob atlas volume threshold display type ratio float spin box QDoubleSpinBox* probAtlasVolumeThresholdRatioDoubleSpinBox; /// topography page QWidget* pageTopography; /// rgb paint main page QWidget* pageRgbPaintMain; /// widget group for rgb paint main page WuQWidgetGroup* pageRgbPaintMainWidgetGroup; /// rgb selection page grid layout QGridLayout* rgbSelectionPageGridLayout; /// widget group for each row in RGB selection std::vector rgbSelectionRowWidgetGroup; /// rgb selection page radio buttons std::vector rgbSelectionRadioButtons; /// rgb selection column name line edits std::vector rgbSelectionNameLineEdits; /// rgb selection button group for column selection QButtonGroup* rgbSelectionRadioButtonsButtonGroup; /// rgb selection red comment button group QButtonGroup* rgbSelectionRedCommentButtonGroup; /// rgb selection green comment button group QButtonGroup* rgbSelectionGreenCommentButtonGroup; /// rgb selection blue comment button group QButtonGroup* rgbSelectionBlueCommentButtonGroup; /// rgb selection red histogram button group QButtonGroup* rgbSelectionRedHistogramButtonGroup; /// rgb selection green histogram button group QButtonGroup* rgbSelectionGreenHistogramButtonGroup; /// rgb selection blue histogram button group QButtonGroup* rgbSelectionBlueHistogramButtonGroup; /// rgb paint selection page QWidget* pageRgbPaintSelection; /// rgb red selection checkbox QCheckBox* rgbRedCheckBox; /// rgb red threshold double spin box QDoubleSpinBox* rgbRedThreshDoubleSpinBox; /// rgb green selection checkbox QCheckBox* rgbGreenCheckBox; /// rgb green threshold double spin box QDoubleSpinBox* rgbGreenThreshDoubleSpinBox; /// rgb blue selection checkbox QCheckBox* rgbBlueCheckBox; /// rgb blue threshold double spin box QDoubleSpinBox* rgbBlueThreshDoubleSpinBox; /// rgb positive only radio button QRadioButton* rgbPositiveOnlyRadioButton; /// rgb negative only radio button QRadioButton* rgbNegativeOnlyRadioButton; /// rgb apply coloring to corresponding structures QCheckBox* rgbApplySelectionToLeftAndRightStructuresFlagCheckBox; /// topography display type eccentricity radio button; QRadioButton* topographyTypeEccentricityRadioButton; /// topography display type polar angle radio button; QRadioButton* topographyPolarAngleRadioButton; /// shape min/max column selection label GuiNodeAttributeColumnSelectionComboBox* shapeMinMaxColumnSelectionComboBox; /// surface shape minimum label QLabel* shapeViewMinimumLabel; /// surface shape maximum lable QLabel* shapeViewMaximumLabel; /// surface shape minimum color mapping QDoubleSpinBox* shapeMinimumMappingDoubleSpinBox; /// surface shape maximum color mapping QDoubleSpinBox* shapeMaximumMappingDoubleSpinBox; /// surfaced shape gray color map radio button QRadioButton* shapeColorMapGrayRadioButton; /// surfaced shape orange-yellow color map radio button QRadioButton* shapeColorMapOrangeYellowRadioButton; /// surfaced shape palette color map radio button QRadioButton* shapeColorMapPaletteRadioButton; /// shape apply coloring to corresponding structures QCheckBox* shapeApplySelectionToLeftAndRightStructuresFlagCheckBox; /// combo box for palette selection QComboBox* shapeColorMapPaletteComboBox; /// shape interpolate palette colors QCheckBox* shapeColorMapInterpolatePaletteCheckBox; /// button group for color map selections QButtonGroup* palColorMapButtonGroup; /// surface shape display color bar QCheckBox* shapeDisplayColorBarCheckBox; /// shape node id uncertainty combo box GuiNodeAttributeColumnSelectionComboBox* shapeNodeIdDeviationComboBox; /// shape Node ID Deviation Group Box QGroupBox* shapeNodeIdDeviationGroupBox; /// number of valid surface shape columns int numValidSurfaceShape; /// shape page for selections QWidget* pageSurfaceShapeSelections; /// shape page for settings QWidget* pageSurfaceShapeSettings; /// widget group for shape settings page WuQWidgetGroup* pageSurfaceShapeSettingsWidgetGroup; /// layout for shape sub page selections QVBoxLayout* surfaceShapeSubSelectionsLayout; /// layout for surface shape selection QGridLayout* surfaceShapeSelectionGridLayout; /// surface shape view radio button group QButtonGroup* surfaceShapeViewButtonGroup; /// surface shape comment push button group QButtonGroup* surfaceShapeCommentButtonGroup; /// surface shape metadata push button group QButtonGroup* surfaceShapeMetaDataButtonGroup; /// surface shape histogram push button group QButtonGroup* surfaceShapeHistogramButtonGroup; /// surface shape column number labels std::vector surfaceShapeColumnNumberLabels; //// surface shape view radio buttons std::vector surfaceShapeViewRadioButtons; /// surface shape comment push buttons std::vector surfaceShapeColumnCommentPushButtons; /// surface shape selection metadata push buttons std::vector surfaceShapeColumnMetaDataPushButtons; /// surface shape selection histogram push buttons std::vector surfaceShapeColumnHistogramPushButtons; /// surface shape name line edits std::vector surfaceShapeColumnNameLineEdits; /// metric misc page QWidget* pageMetricMiscellaneous; /// updating metric misc page bool updatingMetricMiscPageFlag; /// metric selection page QWidget* pageMetricSelection; /// layout for metric sub page selections QVBoxLayout* metricSubPageSelectionsLayout; /// metric settings page QWidget* pageMetricSettings; /// widget group for metric settings page WuQWidgetGroup* pageMetricSettingsWidgetGroup; /// layout for metric selections QGridLayout* metricSelectionGridLayout; /// metric apply coloring to corresponding structures QCheckBox* metricApplySelectionToLeftAndRightStructuresFlagCheckBox; /// metric selection column labels std::vector metricColumnNumberLabels; /// metric selection view radio buttons std::vector metricViewRadioButtons; /// metric selection threshold radio buttons std::vector metricThresholdRadioButtons; /// metric selection comment push buttons std::vector metricColumnCommentPushButtons; /// metric selection metadata push buttons std::vector metricColumnMetaDataPushButtons; /// metric selection histogram push buttons std::vector metricColumnHistogramPushButtons; /// metric selection line edits std::vector metricColumnNameLineEdits; /// number of valid metrics int numValidMetrics; /// metric view radio button group QButtonGroup* metricViewButtonGroup; /// metric threshold radio button group QButtonGroup* metricThresholdButtonGroup; /// metric comment push button group QButtonGroup* metricCommentButtonGroup; /// metric metadata push button group QButtonGroup* metricMetaDataButtonGroup; /// metric histogram push button group QButtonGroup* metricHistogramButtonGroup; /// metric display mode positiveradio button QRadioButton* metricDisplayModePositiveRadioButton; /// metric display mode negative radio button QRadioButton* metricDisplayModeNegativeRadioButton; /// metric display mode both radio button QRadioButton* metricDisplayModeBothRadioButton; /// metric positive threshold value QDoubleSpinBox* metricThresholdColumnPositiveDoubleSpinBox; /// metric negative threshold value QDoubleSpinBox* metricThresholdColumnNegativeDoubleSpinBox; /// metric average positive threshold value QDoubleSpinBox* metricThresholdAveragePositiveDoubleSpinBox; /// metric average negative threshold value QDoubleSpinBox* metricThresholdAverageNegativeDoubleSpinBox; /// metric user positive threshold value QDoubleSpinBox* metricThresholdUserPositiveDoubleSpinBox; /// metric user negative threshold value QDoubleSpinBox* metricThresholdUserNegativeDoubleSpinBox; /// metric threshold type combo box QComboBox* metricThresholdTypeComboBox; /// show thresholded regions check box QCheckBox* metricShowThresholdedRegionsCheckBox; /// metric threshold setting column selection combo box GuiNodeAttributeColumnSelectionComboBox* metricThresholdSettingColumnSelectionComboBox; /// metric animate spin box QSpinBox* metricAnimateSpinBox; /// metric popup graph on node ID QComboBox* metricGraphPopupComboBox; /// metric popup graph manual scaling QCheckBox* metricGraphManualScaleCheckBox; /// metric popup graph manual scaling min value float spin box QDoubleSpinBox* metricGraphManualScaleMinDoubleSpinBox; /// metric popup graph manual scaling max value float spin box QDoubleSpinBox* metricGraphManualScaleMaxDoubleSpinBox; /// metric color mapping positive max QDoubleSpinBox* metricColorPositiveMaxDoubleSpinBox; /// metric color mapping positive min QDoubleSpinBox* metricColorPositiveMinDoubleSpinBox; /// metric color mapping negative max QDoubleSpinBox* metricColorNegativeMaxDoubleSpinBox; /// metric color mapping negative min QDoubleSpinBox* metricColorNegativeMinDoubleSpinBox; /// metric color mapping percentage positive max QDoubleSpinBox* metricColorPercentagePositiveMaxDoubleSpinBox; /// metric color mapping percentage positive min QDoubleSpinBox* metricColorPercentagePositiveMinDoubleSpinBox; /// metric color mapping percentage negative max QDoubleSpinBox* metricColorPercentageNegativeMaxDoubleSpinBox; /// metric color mapping percentage negative min QDoubleSpinBox* metricColorPercentageNegativeMinDoubleSpinBox; /// metric specified column scaling selection control GuiNodeAttributeColumnSelectionComboBox* metricFileAutoScaleSpecifiedColumnSelectionComboBox; /// metric color mapping metric file auto scale radio button QRadioButton* metricFileAutoScaleRadioButton; /// metric color mapping metric file auto scale percentage radio button QRadioButton* metricFileAutoScalePercentageRadioButton; /// metric color mapping metric file specified column radio button QRadioButton* metricFileAutoScaleSpecifiedColumnRadioButton; /// metric file color mapping function volume auto scale radio button QRadioButton* metricFuncVolumeAutoScaleRadioButton; /// metric color mapping user scale radio button QRadioButton* metricUserScaleRadioButton; /// metric interpolate checkbox QCheckBox* metricColorInterpolateCheckBox; /// metric palette combo box QComboBox* metricPaletteComboBox; /// metric palette display color bar QCheckBox* metricDisplayColorBarCheckBox; /// border main page QWidget* pageBorderMain; /// border main page widget group (all widgets on foci main page) WuQWidgetGroup* pageBorderMainWidgetGroup; /// border color page QWidget* pageBorderColor; /// border color page widget group (all widgets on foci main page) WuQWidgetGroup* pageBorderColorWidgetGroup; /// border color sub page layout QVBoxLayout* borderSubPageColorLayout; /// border name page QWidget* pageBorderName; /// border name page widget group (all widgets on foci main page) WuQWidgetGroup* pageBorderNameWidgetGroup; /// layout for border name sub page QVBoxLayout* borderSubPageNameLayout; /// border name button group QButtonGroup* borderNameButtonGroup; /// layout for borderNameQVBox QGridLayout* borderNameGridLayout; /// border name checkboxes std::vector borderNameCheckBoxes; /// border names associated with checkboxes std::vector borderNames; /// number of border names/checkboxes being used int numValidBorderNames; /// border color button group QButtonGroup* borderColorButtonGroup; /// layout for borderColorQVBox QGridLayout* borderColorGridLayout; /// border color checkboxes std::vector borderColorCheckBoxes; /// border color checkboxes color indices std::vector borderColorCheckBoxesColorIndex; /// number of border color check boxes being used int numValidBorderColors; /// cell main page QWidget* pageCellsMain; /// cell main page widget group WuQWidgetGroup* pageCellsMainWidgetGroup; /// cell color page QWidget* pageCellsColor; /// cell color page widget group WuQWidgetGroup* pageCellsColorWidgetGroup; /// cell color sub page layout QVBoxLayout* cellSubPageColorLayout; /// cell class page QWidget* pageCellsClass; /// cell class page widget group WuQWidgetGroup* pageCellsClassWidgetGroup; /// cell class sub page layout QVBoxLayout* cellSubPageClassLayout; /// cell class button group QButtonGroup* cellClassButtonGroup; /// layout for cellClassQVBox QGridLayout* cellColorGridLayout; /// cell class checkboxes std::vector cellClassCheckBoxes; /// cell class checkboxes class index std::vector cellClassCheckBoxesClassIndex; /// cell color button group QButtonGroup* cellColorButtonGroup; /// cell color checkboxes std::vector cellColorCheckBoxes; /// cell color checkboxes color indices std::vector cellColorCheckBoxesColorIndex; /// layout for cellClassQVBox QGridLayout* cellClassGridLayout; /// number of valid cell color checkboxes int numValidCellColors; /// number of valid cell classes int numValidCellClasses; /// foci main page QWidget* pageFociMain; /// foci main page widget group (all widgets on foci main page) WuQWidgetGroup* pageFociMainWidgetGroup; /// foci color page QWidget* pageFociColor; /// foci color page widget group (all widgets on foci color page) WuQWidgetGroup* pageFociColorWidgetGroup; /// foci color sub page layout QVBoxLayout* fociSubPageColorLayout; /// foci class page QWidget* pageFociClass; /// foci class page widget group (all widgets on foci class page) WuQWidgetGroup* pageFociClassWidgetGroup; /// foci class sub page QVBoxLayout* fociSubPageClassLayout; /// foci class button group QButtonGroup* fociClassButtonGroup; /// foci keywords page QWidget* pageFociKeyword; /// foci keywords sub page layout QVBoxLayout* fociSubPageKeywordsLayout; /// foci main keyword widget group (all widgets on foci keywords page) WuQWidgetGroup* pageFociKeywordsWidgetGroup; /// foci keywords grid layout QGridLayout* fociKeywordGridLayout; /// button group for foci keyword checkboxes QButtonGroup* fociKeywordButtonGroup; /// foci keyword checkboxes std::vector fociKeywordCheckBoxes; /// foci keyword checkboxes keyword index std::vector fociKeywordCheckBoxesKeywordIndex; /// number of foci keyword checkboxes show in GUI int numberOfFociKeywordCheckBoxesShownInGUI; /// checkbox to show keywords only for displayed foci QCheckBox* fociShowKeywordsOnlyForDisplayedFociCheckBox; /// foci names page QWidget* pageFociName; /// foci name page widget group (all widgets on foci name page) WuQWidgetGroup* pageFociNameWidgetGroup; /// foci names sub page layout QVBoxLayout* fociSubPageNamesLayout; /// foci names grid layout QGridLayout* fociNamesGridLayout; /// button gropu for foci names checkboxes QButtonGroup* fociNamesButtonGroup; /// foci names checkboxes std::vector fociNamesCheckBoxes; /// foci names checkboxes name indices std::vector fociNamesCheckBoxesNameIndex; /// number of foci name checkboxes show in GUI int numberOfFociNameCheckBoxesShownInGUI; /// checkbox to show names only for displayed foci QCheckBox* fociShowNamesOnlyForDisplayedFociCheckBox; /// foci tables page QWidget* pageFociTable; /// foci tables page widget group (all widgets on foci table page) WuQWidgetGroup* pageFociTableWidgetGroup; /// foci tables sub page layout QVBoxLayout* fociSubPageTablesLayout; /// foci tables grid layout QGridLayout* fociTablesGridLayout; /// button group for foci tables checkboxes QButtonGroup* fociTablesButtonGroup; /// foci table checkboxes std::vector fociTablesCheckBoxes; /// foci table checkboxes table index std::vector fociTablesCheckBoxesTableIndex; /// number of foci table checkboxes show in GUI int numberOfFociTableCheckBoxesShownInGUI; /// checkbox to show tables only for displayed foci QCheckBox* fociShowTablesOnlyForDisplayedFociCheckBox; /// layout for fociColorQVBox QGridLayout* fociColorGridLayout; /// foci class checkboxes std::vector fociClassCheckBoxes; /// foci class checkboxes class index std::vector fociClassCheckBoxesColorIndex; /// number of foci class checkboxes show in GUI int numberOfFociClassCheckBoxesShownInGUI; /// checkbox to show classes only for displayed foci QCheckBox* fociShowClassesOnlyForDisplayedFociCheckBox; /// foci color button group QButtonGroup* fociColorButtonGroup; /// foci color checkboxes std::vector fociColorCheckBoxes; /// foci color checkboxes color index std::vector fociColorCheckBoxesColorIndex; /// number of foci colors checkboxes show in GUI int numberOfFociColorCheckBoxesShownInGUI; /// checkbox to show colors only for displayed foci QCheckBox* fociShowColorsOnlyForDisplayedFociCheckBox; /// layout for fociClassQVBox QGridLayout* fociClassGridLayout; /// number of valid foci color checkboxes //int numValidFociColors; /// number of valid foci classes int numValidFociClasses; /// display cells without class assignments check box QCheckBox* fociWithoutClassAssignmentsCheckBox; /// display cells without matching color check box QCheckBox* fociWithoutMatchingColorCheckBox; /// display cells without a link to a study with keywords check box QCheckBox* fociWithoutLinkToStudyWithKeywordsCheckBox; /// display cells without a link to a table subheader check box QCheckBox* fociWithoutLinkToStudyWithTableSubHeaderCheckBox; /// the foci search page QWidget* pageFociSearch; /// the foci search widget GuiFociSearchWidget* fociSearchWidget; /// show only foci in search check box QCheckBox* showFociInSearchCheckBox; /// show borders check box QCheckBox* showBordersCheckBox; /// show raised borders check box QCheckBox* showRaisedBordersCheckBox; /// show border uncertainty vectors check box QCheckBox* showUncertaintyBordersCheckBox; /// show border's first link in red check box QCheckBox* showFirstLinkRedBordersCheckBox; /// border draw type combo box QComboBox* bordersDrawTypeComboBox; /// border size spin box QDoubleSpinBox* borderSizeSpinBox; /// border symbol combo box QComboBox* borderSymbolComboBox; /// border opacity QDoubleSpinBox* borderOpacityDoubleSpinBox; /// border stretched lines stretch factor QDoubleSpinBox* unstretchedBordersDoubleSpinBox; /// override border colors with area colors check box QCheckBox* overrideBorderWithAreaColorsCheckBox; /// show foci check box; QCheckBox* showFociCheckBox; /// show volume foci check box QCheckBox* showVolumeFociCheckBox; /// show raised foci check box QCheckBox* showRaisedFociCheckBox; /// show pasted onto 3D foci check box QCheckBox* showPastedOnto3DFociCheckBox; /// foci symbol override combo box QComboBox* fociSymbolOverrideComboBox; /// foci opacity double spin box QDoubleSpinBox* fociOpacityDoubleSpinBox; /// foci size spin box QDoubleSpinBox* fociSizeSpinBox; /// foci distance spin box QDoubleSpinBox* fociDistSpinBox; /// foci coloring mode combo box QComboBox* fociColorModeComboBox; // show right hemisphere foci //QCheckBox* showRightHemisphereFociCheckBox; // show left hemisphere foci //QCheckBox* showLeftHemisphereFociCheckBox; /// show cells on correct hem only QCheckBox* showCorrectHemisphereCellsCheckBox; /// show cells check box; QCheckBox* showCellsCheckBox; /// show volume cells check box; QCheckBox* showVolumeCellsCheckBox; /// show raised cell check box QCheckBox* showRaisedCellCheckBox; /// cell symbol override combo box QComboBox* cellSymbolOverrideComboBox; /// cell opacity QDoubleSpinBox* cellOpacityDoubleSpinBox; /// cell display modes combo box QComboBox* cellDisplayModeComboBox; /// cell size spin box QDoubleSpinBox* cellSizeSpinBox; /// cell distance spin box QDoubleSpinBox* cellDistSpinBox; // show right hemisphere cell //QCheckBox* showRightHemisphereCellCheckBox; // show left hemisphere cell //QCheckBox* showLeftHemisphereCellCheckBox; /// show foci on correct hem only QCheckBox* showCorrectHemisphereFociCheckBox; /// active fiducial combo box GuiBrainModelSelectionComboBox* miscActiveFiducialComboBox; /// left fiducial volume interaction fiducial combo box GuiBrainModelSelectionComboBox* miscLeftFiducialVolumeInteractionComboBox; /// right fiducial volume interaction fiducial combo box GuiBrainModelSelectionComboBox* miscRightFiducialVolumeInteractionComboBox; /// cerebellum fiducial volume interaction fiducial combo box GuiBrainModelSelectionComboBox* miscCerebellumFiducialVolumeInteractionComboBox; /// draw mode combo box QComboBox* miscDrawModeComboBox; /// brightness double spin box QDoubleSpinBox* miscBrightnessDoubleSpinBox; /// contrast double spin box QDoubleSpinBox* miscContrastDoubleSpinBox; /// opacity double spin box QDoubleSpinBox* opacityDoubleSpinBox; /// node size spin box QDoubleSpinBox* miscNodeSizeSpinBox; /// link size spin box QDoubleSpinBox* miscLinkSizeSpinBox; /// identify node color combo box QComboBox* miscIdentifyNodeColorComboBox; /// show normals check box QCheckBox* miscShowNormalsCheckBox; /// show total forces check box QCheckBox* miscTotalForcesCheckBox; /// show angular forces check box QCheckBox* miscAngularForcesCheckBox; /// show linear forces check box QCheckBox* miscLinearForcesCheckBox; /// force length float spin box QDoubleSpinBox* miscForceVectorLengthDoubleSpinBox; /// surface axes group box QGroupBox* miscAxesGroupBox; /// surfac misc page widget group WuQWidgetGroup* surfaceMiscWidgetGroup; /// surface axes QCheckBox* miscAxesShowLettersCheckBox; /// surface axes QCheckBox* miscAxesShowTickMarksCheckBox; /// surface axes QDoubleSpinBox* miscAxesLengthDoubleSpinBox; /// surface axes offset QDoubleSpinBox* miscAxesOffsetDoubleSpinBox[3]; /// projection combo box QComboBox* miscProjectionComboBox; /// deformation field page QWidget* pageDeformationField; /// deformation field mode combo box QComboBox* deformationFieldModeComboBox; /// deformation field show vectors on identified nodes check box QCheckBox* deformationFieldShowIdNodesCheckBox; /// deformation field sparse distance spin box QSpinBox* deformationFieldSparseDistanceSpinBox; /// deformation field select column combo box GuiNodeAttributeColumnSelectionComboBox* deformationFieldComboBox; /// deformation field show unstretched on flat surface QCheckBox* deformationFieldShowUnstretchedCheckBox; /// deformation field unstretched factor QDoubleSpinBox* deformationFieldUnstretchedDoubleSpinBox; /// Cocomac display page QWidget* pageCocomacDisplay; /// Cocomac file info sub page QWidget* pageCocomacInformation; /// Cocoamc afferent connection radio button QRadioButton* cocomacAfferentRadioButton; /// Cocoamc efferent connection radio button QRadioButton* cocomacEfferentRadioButton; /// Cocoamc afferent and efferent connection radio button QRadioButton* cocomacAfferentAndEfferentRadioButton; /// Cocoamc afferent or efferent connection radio button QRadioButton* cocomacAfferentOrEfferentRadioButton; /// Cocomac paint column combo box QComboBox* cocomacPaintColumnComboBox; /// Cocomac version label QLabel* cocomacVersionLabel; /// Cocomac export date label QLabel* cocomacExportDate; /// Cocomac data type label QLabel* cocomacDataType; /// Cocomac text area QTextEdit* cocomacCommentsTextEdit; /// Cocomac text area QTextEdit* cocomacProjectionsTextEdit; /// Contour main page QWidget* pageContourMain; /// contour cell class sub page QWidget* pageContourClass; /// contour cell class sub page layout QVBoxLayout* contourSubPageClassLayout; /// contour color class sub page QWidget* pageContourColor; /// contour color class sub page layout QVBoxLayout* contourSubPageColorLayout; /// contour draw mode combo box QComboBox* contourDrawModeComboBox; /// contour origin cross check box QCheckBox* contourOriginCrossCheckBox; /// Contour show end points check box QCheckBox* contourShowEndPointsCheckBox; /// Contour point size spin box QDoubleSpinBox* contourPointSizeSpinBox; /// Contour line size spin box QDoubleSpinBox* contourLineThicknessSpinBox; /// contour cell color button group QButtonGroup* contourCellColorButtonGroup; /// layout for contourCellColorQVBox QGridLayout* contourCellColorGridLayout; /// contour cell class button group QButtonGroup* contourCellClassButtonGroup; /// layout for contourCellClassQVBox QGridLayout* contourCellClassGridLayout; /// number of valid contour cell classes int numValidContourCellClasses; /// number of valid contour cell colors int numValidContourCellColors; /// show contour cells check box QCheckBox* contourShowCellsCheckBox; /// contour cell size spin box QSpinBox* contourCellSizeSpinBox; /// contour cell class check boxes std::vector contourCellClassCheckBoxes; /// contour cell color check boxes std::vector contourCellColorCheckBoxes; /// the volume selection page QWidget* pageVolumeSelection; /// the volume settings page QWidget* pageVolumeSettings; /// widget group for volume settings page WuQWidgetGroup* pageVolumeSettingsWidgetGroup; /// the volume surface outline page QWidget* pageVolumeSurfaceOutline; /// widget group for volume surface outline page WuQWidgetGroup* pageVolumeSurfaceOutlineWidgetGroup; /// volume primary overlay none button QRadioButton* volumePrimaryOverlayNoneButton; /// volume secondary overlay none button QRadioButton* volumeSecondaryOverlayNoneButton; /// volume underlay none button QRadioButton* volumeUnderlayNoneButton; /// volume primary overlay anatomy radio button QRadioButton* volumePrimaryOverlayAnatomyRadioButton; /// volume secondary overlay anatomy radio button QRadioButton* volumeSecondaryOverlayAnatomyRadioButton; /// volume underlay radio anatomy button QRadioButton* volumeUnderlayAnatomyRadioButton; /// volume anatomy combo box QComboBox* volumeAnatomyComboBox; /// volume anatomy label QLabel* volumeAnatomyLabel; /// volume functional primary overlay radio button QRadioButton* volumePrimaryOverlayFunctionalRadioButton; /// volume functional overlay secondary overlay radio button QRadioButton* volumeSecondaryOverlayFunctionalRadioButton; /// volume functional underlay radio button QRadioButton* volumeUnderlayFunctionalRadioButton; /// volume functional view combo box QComboBox* volumeFunctionalViewComboBox; /// volume functional threshold combo box QComboBox* volumeFunctionalThresholdComboBox; /// volume functional view label QLabel* volumeFunctionalViewLabel; /// volume functional threshold label QLabel* volumeFunctionalThresholdLabel; /// volume paint primary overlay radio button QRadioButton* volumePrimaryOverlayPaintRadioButton; /// volume paint secondary overlay radio button QRadioButton* volumeSecondaryOverlayPaintRadioButton; /// volume paint underlay radio button QRadioButton* volumeUnderlayPaintRadioButton; /// volume paint combo box QComboBox* volumePaintComboBox; /// volume paint label QLabel* volumePaintLabel; /// volume prob atlas primary overlay radio button QRadioButton* volumePrimaryOverlayProbAtlasRadioButton; /// volume prob atlas secondary overlay radio button QRadioButton* volumeSecondaryOverlayProbAtlasRadioButton; /// volume prob atlas underlay radio button QRadioButton* volumeUnderlayProbAtlasRadioButton; /// volume prob atlas label QLabel* volumeProbAtlasLabel; /// volume rgb primary overlay radio button QRadioButton* volumePrimaryOverlayRgbRadioButton; /// volume rgb secondary overlay radio button QRadioButton* volumeSecondaryOverlayRgbRadioButton; /// volume rgb underlay radio button QRadioButton* volumeUnderlayRgbRadioButton; /// volume rgb combo box QComboBox* volumeRgbComboBox; /// volume rgb label QLabel* volumeRgbLabel; /// volume segementation primary overlay radio button QRadioButton* volumePrimaryOverlaySegmentationRadioButton; /// volume segementation secondary overlay radio button QRadioButton* volumeSecondaryOverlaySegmentationRadioButton; /// volume segementation underlay radio button QRadioButton* volumeUnderlaySegmentationRadioButton; /// volume segementation combo box QComboBox* volumeSegmentationComboBox; /// volume segmentation transparency QDoubleSpinBox* volumeSegmentationTranslucencyDoubleSpinBox; /// volume segmentation label QLabel* volumeSegmentationLabel; /// volume vector primary overlay radio button QRadioButton* volumePrimaryOverlayVectorRadioButton; /// volume vector secondary overlay radio button QRadioButton* volumeSecondaryOverlayVectorRadioButton; /// volume vector underlay radio button QRadioButton* volumeUnderlayVectorRadioButton; /// volume vector combo box QComboBox* volumeVectorComboBox; /// volume vector label QLabel* volumeVectorLabel; /// volume functional display color bar QCheckBox* volumeFunctionalDisplayColorBarCheckBox; /// volume overlay opacity float spin box QDoubleSpinBox* volumeOverlayOpacityDoubleSpinBox; /// volume anatomy info push button QPushButton* volumeAnatomyInfoPushButton; /// volume functional view info push button QPushButton* volumeFunctionalViewInfoPushButton; /// volume functional thresh info push button QPushButton* volumeFunctionalThreshInfoPushButton; /// volume paint info push button QPushButton* volumePaintInfoPushButton; /// volume prob atlas info push button QPushButton* volumeProbAtlasInfoPushButton; /// volume rgb info push button QPushButton* volumeRgbInfoPushButton; /// volume segmentation info push button QPushButton* volumeSegmentationInfoPushButton; /// volume vector info push button QPushButton* volumeVectorInfoPushButton; /// volume anatomy metadata push button QPushButton* volumeAnatomyMetaDataPushButton; /// volume functional view metadata push button QPushButton* volumeFunctionalViewMetaDataPushButton; /// volume functional thresh metadata push button QPushButton* volumeFunctionalThreshMetaDataPushButton; /// volume paint metadata push button QPushButton* volumePaintMetaDataPushButton; /// volume prob atlas metadata push button QPushButton* volumeProbAtlasMetaDataPushButton; /// volume rgb metadata push button QPushButton* volumeRgbMetaDataPushButton; /// volume segmentation metadata push button QPushButton* volumeSegmentationMetaDataPushButton; /// volume vector metadata push button QPushButton* volumeVectorMetaDataPushButton; /// segmentation volume drawing type combo box QComboBox* volumeSegmentationDrawTypeComboBox; /// anatomy volume drawing type combo box QComboBox* volumeAnatomyDrawTypeComboBox; /// anatomy volume brightness control QSlider* volumeAnatomyBrightnessSlider; /// anatomy volume brightness label QLabel* volumeAnatomyBrightnessLabel; /// anatomy volume contrast label QLabel* volumeAnatomyContrastLabel; /// anatomy volume contrast control QSlider* volumeAnatomyContrastSlider; /// vector volume group box QGroupBox* vectorVolumeGroupBox; /// vector volume sparsity spin box QSpinBox* vectorVolumeSparsitySpinBox; /// volume montage group box QGroupBox* volumeMontageGroupBox; /// volume montage rows spin box QSpinBox* volumeMontageRowsSpinBox; /// volume montage columns spin box QSpinBox* volumeMontageColumnsSpinBox; /// volume montage slice increment spin box QSpinBox* volumeMontageSliceIncrementSpinBox; /// brain model combo box for volume overlay surface GuiBrainModelSelectionComboBox* volumeOverlaySurfaceSelectionComboBox[DisplaySettingsVolume::MAXIMUM_OVERLAY_SURFACES]; /// checkbox for volume overlay surface outline QCheckBox* volumeShowOverlaySurfaceOutlineCheckBox[DisplaySettingsVolume::MAXIMUM_OVERLAY_SURFACES]; /// show volume overlay surface outline color combo box QComboBox* volumeOverlaySurfaceOutlineColorComboBox[DisplaySettingsVolume::MAXIMUM_OVERLAY_SURFACES]; /// show volume overlay surface outline thickness float spin box QDoubleSpinBox* volumeOverlaySurfaceOutlineThicknessDoubleSpinBox[DisplaySettingsVolume::MAXIMUM_OVERLAY_SURFACES]; /// show the coordinates of the volume crosshairs QCheckBox* volumeShowCrosshairCoordinatesCheckBox; /// oblique slices view matrix control GuiTransformationMatrixSelectionControl* obliqueVolumeSliceMatrixControl; /// oblique slices sampling size float spin box QDoubleSpinBox* obliqueSlicesSamplingSizeDoubleSpinBox; /// show the volume crosshairs QCheckBox* volumeShowCrosshairsCheckBox; /// surface and volume page QWidget* pageSurfaceAndVolume; /// surface and volume page widget group WuQWidgetGroup* pageSurfaceAndVolumeWidgetGroup; /// surface and volume draw black anatomy voxels QCheckBox* surfaceAndVolumeAnatomyBlackCheckBox; /// surface and volume display horizontal slice check box QCheckBox* surfaceAndVolumeHorizontalSliceCheckBox; /// surface and volume display parasagittal slice check box QCheckBox* surfaceAndVolumeParasagittalSliceCheckBox; /// surface and volume display coronal slice check box QCheckBox* surfaceAndVolumeCoronalSliceCheckBox; /// surface and volume horizontal slice spin box QSpinBox* surfaceAndVolumeHorizontalSliceSpinBox; /// surface and volume parasagittal slice spin box QSpinBox* surfaceAndVolumeParasagittalSliceSpinBox; /// surface and volume coronal slice spin box QSpinBox* surfaceAndVolumeCoronalSliceSpinBox; /// surface and volume show surface check box QCheckBox* surfaceAndVolumeShowSurfaceCheckBox; /// surface and volume show functional volume on slices QCheckBox* surfaceAndVolumeShowFunctionalCloudCheckBox; /// surface and volume functional volume group box QGroupBox* surfaceAndVolumeFunctionalGroupBox; /// surface and volume show primary overlay on slices QCheckBox* surfaceAndVolumeShowPrimaryCheckBox; /// surface and volume show secondary overlay on slices QCheckBox* surfaceAndVolumeShowSecondaryCheckBox; /// surface and volume functional volume opacity float spin box QDoubleSpinBox* surfaceAndVolumeFunctionalCloudOpacitySpinBox; /// surface and volume functional volume opacity check box QCheckBox* surfaceAndVolumeFunctionalCloudOpacityCheckBox; /// surface and volume functional distance threshold QDoubleSpinBox* surfaceAndVolumeFunctionalDistanceSpinBox; /// surface and volume segmentation volume group box QGroupBox* surfaceAndVolumeSegmentationGroupBox; /// surface and volume show segmentation volume on slices QCheckBox* surfaceAndVolumeShowSegmentationCloudCheckBox; /// box for vector items QGroupBox* surfaceAndVolumeVectorVBox; /// surface and volume show vector volume cloud QCheckBox* surfaceAndVolumeShowVectorCloudCheckBox; /// the images page QWidget* pageImages; /// show image in main window checkbox QCheckBox* showImageInMainWindowCheckBox; /// images button group QButtonGroup* imagesButtonGroup; /// layout for iamges QVBoxLayout* imagesLayout; /// images selection buttons std::vector imagesRadioButtons; /// models main page QWidget* pageModelsMain; /// models settings page QWidget* pageModelsSettings; /// models main sub page layout QVBoxLayout* modelsSubPageMainLayout; /// models opacity float spin box QDoubleSpinBox* modelsOpacityDoubleSpinBox; /// models line size float spin box QDoubleSpinBox* modelsLineSizeDoubleSpinBox; /// models vertex size float spin box QDoubleSpinBox* modelsVertexSizeDoubleSpinBox; /// minimum line size float minLineSize; /// maximum line size float maxLineSize; /// minimum point size float minPointSize; /// maximum point size float maxPointSize; /// current number of models in brain set int numValidModels; /// checkbuttons for controlling display of models std::vector modelCheckBoxes; /// transform selection for display of models std::vector modelTransformControls; /// layout for modelSelectionGridWidget QGridLayout* modelSelectionGridWidgetLayout; /// model vertices lighting check box QCheckBox* modelVerticesLightingCheckBox; /// model lines lighting check box QCheckBox* modelLinesLightingCheckBox; /// model polygons lighting check box QCheckBox* modelPolygonsLightingCheckBox; /// model show polygons check box QCheckBox* modelShowPolygonsCheckBox; /// model show triangles check box QCheckBox* modelShowTrianglesCheckBox; /// model show lines check box QCheckBox* modelShowLinesCheckBox; /// model show vertices check box QCheckBox* modelShowVerticesCheckBox; /// widget group for model items WuQWidgetGroup* modelSettingsWidgetGroup; /// section main page QWidget* pageSectionMain; /// widget group for section main page WuQWidgetGroup* pageSectionMainWidgetGroup; /// section line edit QLineEdit* sectionNumberLineEdit; /// paint main page QWidget* pagePaintMain; /// widget group for paint main page WuQWidgetGroup* pagePaintMainWidgetGroup; /// geography blending double spin box QDoubleSpinBox* geographyBlendingDoubleSpinBox; /// paint name page QWidget* pagePaintName; /// paint name checkbox layout QGridLayout* paintNameCheckBoxGridLayout; /// paint name checkboxes std::vector paintNameCheckBoxes; /// paint name checkbox paint file indices std::vector paintNameCheckBoxPaintFileNameIndices; /// paint name checkbox widget groupt WuQWidgetGroup* paintNameCheckBoxWidgetGroup; /// top level paint page QWidget* pagePaintColumn; /// widget group for paint column page WuQWidgetGroup* pagePaintColumnWidgetGroup; /// paint page layout QVBoxLayout* paintPageLayout; /// number of valid paint int numValidPaints; /// labels for paint column numbers std::vector paintColumnNameLabels; /// radio buttons for paint selection std::vector paintColumnRadioButtons; /// line edits for paint names std::vector paintColumnNameLineEdits; /// layout for paint radio button and text boxes QGridLayout* paintColumnSelectionGridLayout; /// button group for paint radio buttons QButtonGroup* paintColumnButtonGroup; /// button group for paint comment buttons QButtonGroup* paintColumnCommentButtonGroup; /// button group for paint metadata buttons QButtonGroup* paintColumnMetaDataButtonGroup; /// paint apply coloring to corresponding structures QCheckBox* paintApplySelectionToLeftAndRightStructuresFlagCheckBox; /// paint column comment push buttons std::vector paintColumnCommentPushButtons; /// paint column metadat push buttons std::vector paintColumnMetaDataPushButtons; /// combo box for surface overlay mode QComboBox* surfaceColoringModeComboBox; /// radio button on overlay underlay surface page QCheckBox* layersBorderCheckBox; /// radio button on overlay underlay surface page QCheckBox* layersCellsCheckBox; /// radio button on overlay underlay surface page QCheckBox* layersFociCheckBox; /// current surface being controlled QComboBox* surfaceModelIndexComboBox; /// current overlay being controlled QComboBox* overlayNumberComboBox; /// widget group for overlay number WuQWidgetGroup* overlayNumberWidgetGroup; /// surface model combo box to brain model surface indices std::vector surfaceModelIndexComboBoxValues; /// current brain model surface index that is being controlled /// If negative then controlling all surfaces int surfaceModelIndex; /// horizontal box containing surface model index selection QGroupBox* surfaceModelGroupBox; /// volume animate direction combo box QComboBox* volumeAnimateDirectionComboBox; /// animate volume flag bool continueVolumeAnimation; /// scene main page QWidget* pageSceneMain; /// skip updating of scene page bool skipScenePageUpdate; /// scene list box QListWidget* sceneListBox; /// scene preserve foci, foci colors, and study metadata checkbox QCheckBox* scenePreserveFociCheckBox; /// scene window position combo box QComboBox* sceneWindowPositionComboBox; /// region main page QWidget* pageRegionMain; /// region all time courses check box QRadioButton* regionAllTimeCoursesCheckBox; /// region single time course check box QRadioButton* regionSingleTimeCourseCheckBox; /// region time course combo box QComboBox* regionTimeCourseComboBox; /// region case combo box QComboBox* regionCaseComboBox; /// region paint volume QComboBox* regionPaintVolumeComboBox; /// region popup graph check box QCheckBox* regionPopupGraphCheckBox; /// region popup graph auto scale radio button QRadioButton* regionGraphAutoScaleRadioButton; /// region popup graph user scale radio button QRadioButton* regionGraphUserScaleRadioButton; /// region popup graph user scale minimum line edit QLineEdit* regionGraphUserScaleMinLineEdit; /// region popup graph user scale maximum line edit QLineEdit* regionGraphUserScaleMaxLineEdit; /// paint medial wall override check box QCheckBox* paintMedWallCheckBox; /// paint medial wall column combo box GuiNodeAttributeColumnSelectionComboBox* paintMedWallColumnComboBox; /// lat/lon main page QWidget* pageLatLonMain; /// layout for lat/lon main page QVBoxLayout* latLonMainPageLayout; /// lat/lon comment button group QButtonGroup* latLonCommentButtonGroup; /// lat/lon grid layout QGridLayout* latLonSelectionGridLayout; /// number of valid lat/lon columns int numValidLatLon; /// lat lon comment push buttons std::vector latLonColumnCommentPushButtons; /// lat lon name line edits std::vector latLonNameLineEdits; /// surface clipping page QWidget* pageSurfaceClipping; /// surface clipping page widget group WuQWidgetGroup* surfaceClippingPageWidgetGroup; /// surface clipping apply clipping combo box QComboBox* surfaceClippingApplyComboBox; /// enable surface clipping check boxes QCheckBox* surfaceClippingEnabledCheckBox[6]; /// surface clipping coordinate double spin box QDoubleSpinBox* surfaceClippingCoordSpinBox[6]; /// vector selection page QWidget* pageVectorSelection; /// layout for vector selection page QVBoxLayout* pageVectorSelectionLayout; /// checkboxes for selecting vector files for display std::vector vectorSelectionCheckBoxes; /// vector settings page QWidget* pageVectorSettings; /// vector settings page widget group WuQWidgetGroup* vectorSettingsPageWidgetGroup; /// vector selection page widget group WuQWidgetGroup* vectorSelectionPageWidgetGroup; /// vector type mode combo box QComboBox* vectorTypeModeComboBox; /// vector surface symbol combo box QComboBox* vectorSurfaceSymbolComboBox; /// vector draw with magnitude check box QCheckBox* vectorDrawWithMagnitudeCheckBox; /// vector surface display mode combo box QComboBox* vectorDisplayModeSurfaceComboBox; /// vector volume display mode combo box QComboBox* vectorDisplayModeVolumeComboBox; /// vector sparse distance spin box QSpinBox* vectorSparseDistanceSpinBox; /// vector length multiplier float spin box QDoubleSpinBox* vectorLengthMultiplierDoubleSpinBox; /// vector surface line width float spin box QDoubleSpinBox* vectorSurfaceLineWidthSpinBox; /// vector volume slice above limit float spin box QDoubleSpinBox* vectorVolumeSliceAboveLimitSpinBox; /// vector volume slice below limit float spin box QDoubleSpinBox* vectorVolumeSliceBelowLimitSpinBox; /// vector magnitude threshold float spin box QDoubleSpinBox* vectorMagnitudeThresholdSpinBox; /// vector segmentation mask volume file group box QGroupBox* vectorSegmentationGroupBox; /// vector segmentation mask volume file combo box GuiVolumeFileSelectionComboBox* vectorSegmentationMaskVolumeComboBox; /// vector functional mask volume file group box QGroupBox* vectorFunctionalVolumeMaskGroupBox; /// vector functional mask volume file combo box GuiVolumeFileSelectionComboBox* vectorFunctionalMaskVolumeComboBox; /// vector functional mask volume negative threshold value QDoubleSpinBox* vectorFunctionalMaskVolumeNegThreshSpinBox; /// vector functional mask volume positive threshold value QDoubleSpinBox* vectorFunctionalMaskVolumePosThreshSpinBox; /// vector color mode combo box QComboBox* vectorColorModeComboBox; /// vector display orientation combo box QComboBox* vectorDisplayOrientationComboBox; /// vector display orientation angle spin box QDoubleSpinBox* vectorDisplayOrientationAngleSpinBox; /// geodesic main page QWidget* pageGeodesicMain; /// geodesic main page layout QVBoxLayout* geodesicMainPageLayout; /// enable geodesic path check box QCheckBox* geodesicDistanceEnableCheckBox; /// geodesic comment button group QButtonGroup* geodesicCommentButtonGroup; /// geodesic grid layout QGridLayout* geodesicSelectionGridLayout; /// number of valid geodesic columns int numValidGeodesic; /// geodesic selection radio button group QButtonGroup* geodesicSelectionButtonGroup; /// geodesic comment push buttons std::vector geodesicColumnCommentPushButtons; /// geodesic selection radio buttons std::vector geodesicSelectionRadioButtons; /// geodesic name line edits std::vector geodesicNameLineEdits; /// geodesic path line width spin box QSpinBox* geodesicPathLineWidthSpinBox; /// geodesic show root node symbol check box QCheckBox* geodesicShowRootNodeCheckBox; /// areal estimation main page QWidget* pageArealEstimation; /// layout for areal estimation main page QVBoxLayout* arealEstimationMainPageLayout; /// areal estimation comment button group QButtonGroup* arealEstimationCommentButtonGroup; /// areal estimation metadata button group QButtonGroup* arealEstimationMetaDataButtonGroup; /// areal estimation selection button group QButtonGroup* arealEstimationSelectionButtonGroup; /// areal estimation grid layout QGridLayout* arealEstimationSelectionGridLayout; /// number of valid areal estimation columns int numValidArealEstimation; /// areal estimation comment push buttons std::vector arealEstimationColumnCommentPushButtons; /// areal estimation metadata push buttons std::vector arealEstimationColumnMetaDataPushButtons; /// areal estimation selection radio button std::vector arealEstimationSelectionRadioButtons; /// areal estimation name line edits std::vector arealEstimationNameLineEdits; /// surface data valid bool validSurfaceData; /// volume data valid bool validVolumeData; /// volume functional data valid bool validVolumeFunctionalData; /// areal estimation data valid bool validArealEstimationData; /// border data valid bool validBorderData; /// cell data valid bool validCellData; /// Cocomac data valid bool validCocomacData; /// contour data valid bool validContourData; /// deformation field data valid bool validDeformationFieldData; /// foci data valid bool validFociData; /// geodesic data valid bool validGeodesicData; /// image data valid bool validImageData; /// latlon data valid bool validLatLonData; /// metric data valid bool validMetricData; /// model data valid bool validModelData; /// paint data valid bool validPaintData; /// prob atlas surface data valid bool validProbAtlasSurfaceData; /// prob atlas volume data valid bool validProbAtlasVolumeData; /// region data valid bool validRegionData; /// rgb paint data valid bool validRgbPaintData; /// scene data valid bool validSceneData; /// section data valid bool validSectionData; /// shape data valid bool validShapeData; /// surface and volume data valid bool validSurfaceAndVolumeData; /// vector data valid bool validVectorData; /// topography data valid bool validTopographyData; }; #endif // __GUI_DISPLAY_CONTROL_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiDisplayControlDialog.cxx0000664000175000017500000243437711572067322023162 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #ifdef Q_OS_WIN32 #define NOMINMAX #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "AreaColorFile.h" #include "ArealEstimationFile.h" #include "BorderColorFile.h" #include "BorderFile.h" #include "BrainModelBorderSet.h" #include "BrainModelSurfaceAndVolume.h" #include "BrainModelSurfaceNodeColoring.h" #include "BrainModelVolume.h" #include "BrainModelVolumeVoxelColoring.h" #include "BrainSet.h" #include "CellProjectionFile.h" #include "CellColorFile.h" #include "ContourCellColorFile.h" #include "ContourCellFile.h" #include "CocomacConnectivityFile.h" #include "DebugControl.h" #include "DeformationFieldFile.h" #include "DisplaySettingsArealEstimation.h" #include "DisplaySettingsBorders.h" #include "DisplaySettingsCells.h" #include "DisplaySettingsCoCoMac.h" #include "DisplaySettingsContours.h" #include "DisplaySettingsCuts.h" #include "DisplaySettingsDeformationField.h" #include "DisplaySettingsFoci.h" #include "DisplaySettingsGeodesicDistance.h" #include "DisplaySettingsImages.h" #include "DisplaySettingsMetric.h" #include "DisplaySettingsModels.h" #include "DisplaySettingsSurface.h" #include "DisplaySettingsPaint.h" #include "DisplaySettingsProbabilisticAtlas.h" #include "DisplaySettingsRgbPaint.h" #include "DisplaySettingsScene.h" #include "DisplaySettingsSection.h" #include "DisplaySettingsStudyMetaData.h" #include "DisplaySettingsSurfaceShape.h" #include "DisplaySettingsVectors.h" #include "DisplaySettingsTopography.h" #include "DisplaySettingsVolume.h" #include "DisplaySettingsWustlRegion.h" #include "FileUtilities.h" #include "FociColorFile.h" #include "FociFile.h" #include "FociProjectionFile.h" #include "FociSearchFile.h" #include "GeodesicDistanceFile.h" #include "GuiBrainModelOpenGL.h" #include "GuiBrainModelSelectionComboBox.h" #include "GuiBrainModelSurfaceSelectionComboBox.h" #include "GuiDataFileCommentDialog.h" #include "GuiDisplayControlDialog.h" #include "GuiDisplayControlSurfaceOverlayWidget.h" #include "GuiFilesModified.h" #include "GuiFociSearchWidget.h" #include "GuiHistogramDisplayDialog.h" #include "GuiIdentifyDialog.h" #include "GuiMainWindow.h" #include "GuiSpecAndSceneFileCreationDialog.h" #include "GuiStudyMetaDataLinkCreationDialog.h" #include "GuiToolBar.h" #include "GuiTransformationMatrixSelectionControl.h" #include "GuiVolumeFileSelectionComboBox.h" #include "GuiVolumeResizingDialog.h" #include "GuiNodeAttributeColumnSelectionComboBox.h" #include "ImageFile.h" #include "LatLonFile.h" #include "MetricFile.h" #include "PaintFile.h" #include "ProbabilisticAtlasFile.h" #include "QtListBoxSelectionDialog.h" #include "QtMultipleInputDialog.h" #include "QtRadioButtonSelectionDialog.h" #include "WuQSaveWidgetAsImagePushButton.h" #include "QtUtilities.h" #include "QtTextEditDialog.h" #include "RgbPaintFile.h" #include "SceneFile.h" #include "SectionFile.h" #include "StringUtilities.h" #include "SurfaceShapeFile.h" #include "VectorFile.h" #include "SystemUtilities.h" #include "TopographyFile.h" #include "TransformationMatrixFile.h" #include "VtkModelFile.h" #include "WuQDataEntryDialog.h" #include "WuQFileDialog.h" #include "WuQMessageBox.h" #include "WuQWidgetGroup.h" #include "WustlRegionFile.h" #include "global_variables.h" /** * The Constructor */ GuiDisplayControlDialog::GuiDisplayControlDialog(QWidget* parent) : WuQDialog(parent) { GuiBrainModelOpenGL::getPointSizeRange(minPointSize, maxPointSize); maxPointSize = 100000.0; GuiBrainModelOpenGL::getLineWidthRange(minLineSize, maxLineSize); pageOverlayUnderlaySurfaceNew = NULL; surfaceModelIndex = -1; creatingDialog = true; dataInfoDialog = NULL; setSizeGripEnabled(true); setWindowTitle("Display Control"); // // Actions for back and forward tool buttons // QAction* pageBackToolButtonAction = new QAction(this); QAction* pageForwardToolButtonAction = new QAction(this); // // Create the combo box for selecting the individual pages // QLabel* pageSelLabel = new QLabel("Page Selection"); pageBackToolButton = new QToolButton; pageBackToolButton->setToolTip("Go back to the \n" "previous page."); pageBackToolButton->setArrowType(Qt::LeftArrow); pageBackToolButton->setDefaultAction(pageBackToolButtonAction); QObject::connect(pageBackToolButton, SIGNAL(triggered(QAction*)), this, SLOT(slotPageBackToolButtonPressed(QAction*))); pageForwardToolButton = new QToolButton; pageForwardToolButton->setToolTip("Go forward to the \n" "next page as a \n" "result of using \n" "the back arrow."); pageForwardToolButton->setArrowType(Qt::RightArrow); pageForwardToolButton->setDefaultAction(pageForwardToolButtonAction); QObject::connect(pageForwardToolButton, SIGNAL(triggered(QAction*)), this, SLOT(slotPageForwardToolButtonPressed(QAction*))); pageComboBox = new QComboBox; QObject::connect(pageComboBox, SIGNAL(activated(int)), this, SLOT(pageComboBoxSelection(int))); QHBoxLayout* pageSelLayout = new QHBoxLayout; pageSelLayout->addWidget(pageSelLabel); pageSelLayout->addWidget(pageBackToolButton); pageSelLayout->addWidget(pageForwardToolButton); pageSelLayout->addWidget(pageComboBox); pageSelLayout->setStretchFactor(pageSelLabel, 0); pageSelLayout->setStretchFactor(pageBackToolButton, 0); pageSelLayout->setStretchFactor(pageForwardToolButton, 0); pageSelLayout->setStretchFactor(pageComboBox, 100); // // Create the surface selection page // QLabel* surfaceModelLabel = new QLabel("Surface"); surfaceModelIndexComboBox = new QComboBox; QObject::connect(surfaceModelIndexComboBox, SIGNAL(activated(int)), this, SLOT(slotSurfaceModelIndexComboBox(int))); // // Overlay selection combo box // QLabel* overlayNumberLabel = new QLabel("Overlay"); overlayNumberComboBox = new QComboBox; for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfSurfaceOverlays(); i++) { overlayNumberComboBox->addItem(theMainWindow->getBrainSet()->getSurfaceOverlay(i)->getName()); } QObject::connect(overlayNumberComboBox, SIGNAL(activated(int)), this, SLOT(slotOverlayNumberComboBox(int))); overlayNumberWidgetGroup = new WuQWidgetGroup(this); overlayNumberWidgetGroup->addWidget(overlayNumberLabel); overlayNumberWidgetGroup->addWidget(overlayNumberComboBox); updateOverlayNumberComboBox(); // // Shape apply left/right named columns // shapeApplySelectionToLeftAndRightStructuresFlagCheckBox = new QCheckBox("Apply Shape L-to-L, R-to-R Matching to Coord Files"); shapeApplySelectionToLeftAndRightStructuresFlagCheckBox->setToolTip("If checked and a surface shape column\n" "is selected for display and the column\n" "name contains left (right), the column\n" "is assigned to all left surfaces and\n" "if a column with right (left) in its\n" "exists, it is applied to right (left)\n" "surfaces."); QObject::connect(shapeApplySelectionToLeftAndRightStructuresFlagCheckBox, SIGNAL(toggled(bool)), this, SLOT(readShapeL2LR2R())); // // Metric apply left/right named columns // metricApplySelectionToLeftAndRightStructuresFlagCheckBox = new QCheckBox("Apply Metric L-to-L, R-to-R Matching to Coord Files"); metricApplySelectionToLeftAndRightStructuresFlagCheckBox->setToolTip("If checked and a metric column\n" "is selected for display and the column\n" "name contains left (right), the column\n" "is assigned to all left surfaces and\n" "if a column with right (left) in its\n" "exists, it is applied to right (left)\n" "surfaces."); QObject::connect(metricApplySelectionToLeftAndRightStructuresFlagCheckBox, SIGNAL(toggled(bool)), this, SLOT(readMetricL2LR2R())); // // paint apply left/right named columns // paintApplySelectionToLeftAndRightStructuresFlagCheckBox = new QCheckBox("Apply Paint L-to-L, R-to-R Matching to Coord Files"); paintApplySelectionToLeftAndRightStructuresFlagCheckBox->setToolTip("If checked and a paint column\n" "is selected for display and the column\n" "name contains left (right), the column\n" "is assigned to all left surfaces and\n" "if a column with right (left) in its\n" "exists, it is applied to right (left)\n" "surfaces."); QObject::connect(paintApplySelectionToLeftAndRightStructuresFlagCheckBox, SIGNAL(toggled(bool)), this, SLOT(readPaintL2LR2R())); // // RGB Paint apply left/right named columns // rgbApplySelectionToLeftAndRightStructuresFlagCheckBox = new QCheckBox("Apply RGB Paint L-to-L, R-to-R Matching to Coord Files"); rgbApplySelectionToLeftAndRightStructuresFlagCheckBox->setToolTip("If checked and an RGB paint column\n" "is selected for display and the column\n" "name contains left (right), the column\n" "is assigned to all left surfaces and\n" "if a column with right (left) in its\n" "exists, it is applied to right (left)\n" "surfaces."); QObject::connect(rgbApplySelectionToLeftAndRightStructuresFlagCheckBox, SIGNAL(toggled(bool)), this, SLOT(readRgbPaintL2LR2R())); // // prob atlas apply left/right named columns // probAtlasSurfaceApplySelectionToLeftAndRightStructuresFlagCheckBox = new QCheckBox("Apply Prob Atlas L-to-L, R-to-R Matching to Coord Files"); probAtlasSurfaceApplySelectionToLeftAndRightStructuresFlagCheckBox->setToolTip("If checked and a probabilistic atlas colum\n" "name contains left (right), the column\n" "is assigned to all left surfaces and\n" "if a column with right (left) in its\n" "exists, it is applied to right (left)\n" "surfaces."); QObject::connect(probAtlasSurfaceApplySelectionToLeftAndRightStructuresFlagCheckBox, SIGNAL(toggled(bool)), this, SLOT(readProbAtlasSurfaceL2LR2R())); // // Group box for surface and overlay selection // surfaceModelGroupBox = new QGroupBox("Coloration Applies To"); QGridLayout* surfaceModelGridLayout = new QGridLayout(surfaceModelGroupBox); surfaceModelGridLayout->addWidget(surfaceModelLabel, 0, 0); surfaceModelGridLayout->addWidget(surfaceModelIndexComboBox, 0, 1); surfaceModelGridLayout->addWidget(overlayNumberLabel, 1, 0); surfaceModelGridLayout->addWidget(overlayNumberComboBox, 1, 1); surfaceModelGridLayout->addWidget(shapeApplySelectionToLeftAndRightStructuresFlagCheckBox, 2, 0, 1, 2); surfaceModelGridLayout->addWidget(metricApplySelectionToLeftAndRightStructuresFlagCheckBox, 3, 0, 1, 2); surfaceModelGridLayout->addWidget(paintApplySelectionToLeftAndRightStructuresFlagCheckBox, 4, 0, 1, 2); surfaceModelGridLayout->addWidget(rgbApplySelectionToLeftAndRightStructuresFlagCheckBox, 5, 0, 1, 2); surfaceModelGridLayout->addWidget(probAtlasSurfaceApplySelectionToLeftAndRightStructuresFlagCheckBox, 6, 0, 1, 2); //surfaceModelGroupBox->setMaximumHeight(surfaceModelGroupBox->sizeHint().height()); surfaceModelGridLayout->setColumnStretch(0, 0); surfaceModelGridLayout->setColumnStretch(1, 1000); // // Scroll widget for widget stack containing all sub pages // widgetStackScrollArea = new QScrollArea; widgetStackScrollArea->setWidgetResizable(true); widgetStackScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); widgetStackScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); // // Widget stack for all sub pages // pageWidgetStack = new QStackedWidget; widgetStackScrollArea->setWidget(pageWidgetStack); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(5); dialogLayout->addLayout(pageSelLayout); dialogLayout->addWidget(surfaceModelGroupBox); dialogLayout->addWidget(widgetStackScrollArea); dialogLayout->setStretchFactor(pageSelLayout, 0); dialogLayout->setStretchFactor(surfaceModelGroupBox, 0); dialogLayout->setStretchFactor(widgetStackScrollArea, 100); //dialogLayout->addStretch(); // // Volume Pages // pageVolumeSelection = NULL; pageVolumeSettings = NULL; pageVolumeSurfaceOutline = NULL; pageArealEstimation = NULL; arealEstimationSelectionButtonGroup = NULL; arealEstimationSelectionGridLayout = NULL; borderNameButtonGroup = NULL; borderNameGridLayout = NULL; borderColorButtonGroup = NULL; borderColorGridLayout = NULL; numValidBorderNames = 0; numValidBorderColors = 0; pageBorderMain = NULL; pageBorderColor = NULL; pageBorderName = NULL; cellColorButtonGroup = NULL; cellColorGridLayout = NULL; cellClassButtonGroup = NULL; cellClassGridLayout = NULL; numValidCellClasses = 0; numValidCellColors = 0; pageCellsMain = NULL; pageCellsClass = NULL; pageCellsColor = NULL; pageCocomacDisplay = NULL; pageCocomacInformation = NULL; contourCellColorButtonGroup = NULL; contourCellColorGridLayout = NULL; contourCellClassButtonGroup = NULL; contourCellClassGridLayout = NULL; numValidContourCellClasses = 0; numValidContourCellColors = 0; pageContourMain = NULL; pageContourClass = NULL; pageContourColor = NULL; pageDeformationField = NULL; fociColorButtonGroup = NULL; fociColorGridLayout = NULL; fociClassButtonGroup = NULL; fociClassGridLayout = NULL; //numValidFociClasses = 0; //numValidFociColors = 0; pageFociMain = NULL; pageFociClass = NULL; pageFociColor = NULL; pageFociKeyword = NULL; pageFociName = NULL; pageFociSearch = NULL; fociSearchWidget = NULL; pageFociTable = NULL; numberOfFociKeywordCheckBoxesShownInGUI = 0; numberOfFociTableCheckBoxesShownInGUI = 0; numberOfFociNameCheckBoxesShownInGUI = 0; numberOfFociClassCheckBoxesShownInGUI = 0; numberOfFociColorCheckBoxesShownInGUI = 0; fociShowKeywordsOnlyForDisplayedFociCheckBox = NULL; fociShowNamesOnlyForDisplayedFociCheckBox = NULL; fociShowTablesOnlyForDisplayedFociCheckBox = NULL; fociShowClassesOnlyForDisplayedFociCheckBox = NULL; fociShowColorsOnlyForDisplayedFociCheckBox = NULL; pageGeodesicMain = NULL; geodesicSelectionGridLayout = NULL; pageImages = NULL; latLonSelectionGridLayout = NULL; pageLatLonMain = NULL; metricViewButtonGroup = NULL; metricThresholdButtonGroup = NULL; metricCommentButtonGroup = NULL; metricSubPageSelectionsLayout = NULL; metricMetaDataButtonGroup = NULL; metricHistogramButtonGroup = NULL; numValidMetrics = 0; pageMetricMiscellaneous = NULL; pageMetricSettings = NULL; pageMetricSelection = NULL; modelSelectionGridWidgetLayout = NULL; numValidModels = 0; pageModelsMain = NULL; pageModelsSettings = NULL; paintColumnMetaDataButtonGroup = NULL; paintColumnSelectionGridLayout = NULL; pagePaintColumn = NULL; pagePaintMain = NULL; pagePaintName = NULL; pageSectionMain = NULL; numValidProbAtlasSurfaceChannels = 0; probAtlasSurfaceSubPageChannelLayout = NULL; probAtlasSurfaceChannelGridLayout = NULL; probAtlasSurfaceChannelButtonGroup = NULL; numValidProbAtlasSurfaceAreas = 0; probAtlasSurfaceAreasGridLayout = NULL; probAtlasSurfaceSubPageAreaLayout = NULL; probAtlasSurfaceAreasButtonGroup = NULL; pageProbAtlasSurfaceMain = NULL; pageProbAtlasSurfaceChannel = NULL; pageProbAtlasSurfaceArea = NULL; numValidProbAtlasVolumeChannels = 0; probAtlasVolumeChannelGridLayout = NULL; probAtlasVolumeChannelButtonGroup = NULL; numValidProbAtlasVolumeAreas = 0; probAtlasVolumeAreasGridLayout = NULL; probAtlasVolumeAreasButtonGroup = NULL; pageProbAtlasVolumeMain = NULL; pageProbAtlasVolumeArea = NULL; pageProbAtlasVolumeChannel = NULL; pageRegionMain = NULL; pageRgbPaintMain = NULL; pageRgbPaintSelection = NULL; pageSceneMain = NULL; skipScenePageUpdate = false; surfaceShapeViewButtonGroup = NULL; surfaceShapeCommentButtonGroup = NULL; pageSurfaceShapeSelections = NULL; pageSurfaceShapeSettings = NULL; surfaceShapeSubSelectionsLayout = NULL; surfaceShapeMetaDataButtonGroup = NULL; surfaceShapeHistogramButtonGroup = NULL; numValidSurfaceShape = 0; pageSurfaceAndVolume = NULL; pageSurfaceMisc = NULL; pageVectorSelection = NULL; pageVectorSettings = NULL; pageTopography = NULL; pageSurfaceClipping = NULL; // // Layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(5); dialogLayout->addLayout(buttonsLayout); // // Apply button // QPushButton* applyButton = new QPushButton("Apply"); applyButton->setAutoDefault(false); buttonsLayout->addWidget(applyButton); QObject::connect(applyButton, SIGNAL(clicked()), this, SLOT(applySelected())); // // Save as image button // WuQSaveWidgetAsImagePushButton* saveAsImageButton = new WuQSaveWidgetAsImagePushButton("Save As Image...", this); saveAsImageButton->setAutoDefault(false); buttonsLayout->addWidget(saveAsImageButton); saveAsImageButton->hide(); // HIDE SAVE AS IMAGE BUTTON *************** // // Help button // QPushButton* helpButton = new QPushButton("Help"); buttonsLayout->addWidget(helpButton); helpButton->setAutoDefault(false); QObject::connect(helpButton, SIGNAL(clicked()), this, SLOT(slotHelpButton())); // // Close button connects to QDialogs close() slot. // QPushButton* closeButton = new QPushButton("Close"); buttonsLayout->addWidget(closeButton); closeButton->setAutoDefault(false); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); QtUtilities::makeButtonsSameSize(applyButton, saveAsImageButton, helpButton, closeButton); dialogDefaultSize = QDialog::sizeHint(); if (DebugControl::getDebugOn()) { std::cout << "Initial D/C Size Hint: (" << dialogDefaultSize.width() << " " << dialogDefaultSize.height() << ")" << std::endl; } //07/06/2005setMinimumSize(dialogDefaultSize); //setMaximumSize(dialogDefaultSize); updateAllItemsInDialog(true, false); pagesVisitedIndex = -1; updatePageSelectionComboBox(); if (pageComboBoxItems.empty() == false) { pageComboBoxSelection(0); } //surfaceModelGroupBox->setFixedWidth(pageOverlayUnderlaySurface->sizeHint().width()); creatingDialog = false; // // Default to O/U Volume page if there are volumes and no surfaces // if (validSurfaceData) { showDisplayControlPage(PAGE_NAME_SURFACE_OVERLAY_UNDERLAY_NEW, false); } else if (validVolumeData) { showDisplayControlPage(PAGE_NAME_VOLUME_SELECTION, false); } else if (validContourData) { showDisplayControlPage(PAGE_NAME_CONTOUR_MAIN, false); } else { showDisplayControlPage(PAGE_NAME_SCENE, false); } /* // // Show scene page if no brain models but have scenes // if (theMainWindow->getBrainSet()->getNumberOfBrainModels() <= 0) { SceneFile* sf = theMainWindow->getBrainSet()->getSceneFile(); if (sf->getNumberOfScenes() > 0) { showScenePage(); } } */ //07/06/05widgetStackScrollView->setMinimumHeight(pageWidgetStack->sizeHint().height()); resize(585, 740); } /** * called when help button pressed. */ void GuiDisplayControlDialog::slotHelpButton() { theMainWindow->showHelpViewerDialog("dialogs/display_control_dialog.html"); } /** * show the scene page. */ void GuiDisplayControlDialog::showScenePage() { showDisplayControlPage(PAGE_NAME_SCENE, true); } /** * override of parent method. */ void GuiDisplayControlDialog::resizeEvent(QResizeEvent* re) { QDialog::resizeEvent(re); if (DebugControl::getDebugOn()) { std::cout << "Display Control Dialog Resized: " << std::endl; std::cout << std::endl; } } /** * context menu event. */ void GuiDisplayControlDialog::contextMenuEvent(QContextMenuEvent* /*e*/) { // // Popup menu for selection of pages // QMenu menu(this); // // Add capture image of dialog to clipboard // addImageCaptureToMenu(&menu); menu.addSeparator(); // // Page selection // QMenu* pageSelectionMenu = new QMenu("Page"); QObject::connect(pageSelectionMenu, SIGNAL(triggered(QAction*)), this, SLOT(slotPageSelectionPopupMenu(QAction*))); for (int i = 0; i < pageComboBox->count(); i++) { QAction* action = pageSelectionMenu->addAction(pageComboBox->itemText(i)); action->setData(QVariant(i)); } menu.addMenu(pageSelectionMenu); // // Add the overlay selection menus // BrainSet* brainSet = theMainWindow->getBrainSet(); for (int m = (brainSet->getNumberOfSurfaceOverlays() -1); m >= 0; m--) { // // Get the overlay and its valid data types // const BrainModelSurfaceOverlay* bmsOverlay = brainSet->getSurfaceOverlay(m); std::vector dataTypes; std::vector dataTypeNames; bmsOverlay->getDataTypesAndNames(dataTypes, dataTypeNames); const BrainModelSurfaceOverlay::OVERLAY_SELECTIONS selectedOverlay = bmsOverlay->getOverlay(getSurfaceModelIndex()); const int numDataTypes = static_cast(dataTypes.size()); // // Create the menu // QMenu* overlayMenu = new QMenu(bmsOverlay->getName()); QObject::connect(overlayMenu, SIGNAL(triggered(QAction*)), this, SLOT(slotOverlaySelectionPopupMenu(QAction*))); for (int i = 0; i < numDataTypes; i++) { QAction* action = overlayMenu->addAction(dataTypeNames[i]); const int dataOverlayNumberAndItem = (m * 1000) + static_cast(dataTypes[i]); action->setData(QVariant(dataOverlayNumberAndItem)); if (selectedOverlay == dataTypes[i]) { action->setCheckable(true); action->setChecked(true); } } // // Add overlay selection to popup menu // menu.addMenu(overlayMenu); } // // Popup the menu // menu.exec(QCursor::pos()); } /** * override of sizeHint (limits width of dialog but user can stretch). */ /* QSize GuiDisplayControlDialog::sizeHint() const { // // Default size was set after dialog created but before data loaded // QSize sz(500, dialogDefaultSize.height()); return sz; } */ /** * get the name of a page. */ QString GuiDisplayControlDialog::getPageName(const PAGE_NAME pageName) const { QString s("Unknown"); switch (pageName) { case PAGE_NAME_SURFACE_OVERLAY_UNDERLAY_NEW: s = "Overlay/Underlay - Surface"; break; case PAGE_NAME_VOLUME_SETTINGS: s = "Volume Settings"; break; case PAGE_NAME_VOLUME_SURFACE_OUTLINE: s = "Volume Surface Outline"; break; case PAGE_NAME_VOLUME_SELECTION: s = "Overlay/Underlay - Volume"; break; case PAGE_NAME_AREAL_ESTIMATION: s = "Areal Estimation"; break; case PAGE_NAME_BORDER_MAIN: s = "Border Main"; break; case PAGE_NAME_BORDER_COLOR: s = "Border Color"; break; case PAGE_NAME_BORDER_NAME: s = "Border Name"; break; case PAGE_NAME_CELL_MAIN: s = "Cell Main"; break; case PAGE_NAME_CELL_CLASS: s = "Cell Class"; break; case PAGE_NAME_CELL_COLOR: s = "Cell Color"; break; case PAGE_NAME_COCOMAC_DISPLAY: s = "CoCoMac Display"; break; case PAGE_NAME_COCOMAC_INFORMATION: s = "CoCoMac Information"; break; case PAGE_NAME_CONTOUR_MAIN: s = "Contours"; break; case PAGE_NAME_CONTOUR_CLASS: s = "Contour Cell Class"; break; case PAGE_NAME_CONTOUR_COLOR: s = "Contour Cell Color"; break; case PAGE_NAME_DEFORMATION_FIELD: s = "Deformation Field"; break; case PAGE_NAME_FOCI_MAIN: s = "Foci Main"; break; case PAGE_NAME_FOCI_CLASS: s = "Foci Class"; break; case PAGE_NAME_FOCI_COLOR: s = "Foci Color"; break; case PAGE_NAME_FOCI_KEYWORD: s = "Foci Keyword"; break; case PAGE_NAME_FOCI_NAME: s = "Foci Name"; break; case PAGE_NAME_FOCI_SEARCH: s = "Foci Search"; break; case PAGE_NAME_FOCI_TABLE: s = "Foci Table"; break; case PAGE_NAME_GEODESIC: s = "Geodesic"; break; case PAGE_NAME_IMAGES: s = "Images"; break; case PAGE_NAME_LATLON: s = "Lat/Lon"; break; case PAGE_NAME_METRIC_MISCELLANEOUS: s = "Metric Miscellaneous"; break; case PAGE_NAME_METRIC_SELECTION: s = "Metric Selection"; break; case PAGE_NAME_METRIC_SETTINGS: s = "Metric Settings"; break; case PAGE_NAME_MODELS_MAIN: s = "Models Main"; break; case PAGE_NAME_MODELS_SETTINGS: s = "Models Settings"; break; case PAGE_NAME_PAINT_COLUMN: s = "Paint Selection"; break; case PAGE_NAME_PAINT_MAIN: s = "Paint Main"; break; case PAGE_NAME_PAINT_NAMES: s = "Paint Names"; break; case PAGE_NAME_PROB_ATLAS_SURFACE_MAIN: s = "Probabilistic Atlas - Surface Main"; break; case PAGE_NAME_PROB_ATLAS_SURFACE_AREA: s = "Probabilistic Atlas - Surface Areas"; break; case PAGE_NAME_PROB_ATLAS_SURFACE_CHANNEL: s = "Probabilistic Atlas - Surface Channels"; break; case PAGE_NAME_PROB_ATLAS_VOLUME_MAIN: s = "Probabilistic Atlas - Volume Main"; break; case PAGE_NAME_PROB_ATLAS_VOLUME_AREA: s = "Probabilistic Atlas - Volume Area"; break; case PAGE_NAME_PROB_ATLAS_VOLUME_CHANNEL: s = "Probabilistic Atlas - Volume Channel"; break; case PAGE_NAME_REGION: s = "Region"; break; case PAGE_NAME_RGB_PAINT_MAIN: s = "RGB Paint Settings"; break; case PAGE_NAME_RGB_PAINT_SELECTION: s = "RGB Paint Selection"; break; case PAGE_NAME_SCENE: s = "Scene"; break; case PAGE_NAME_SECTION_MAIN: s = "Section Main"; break; case PAGE_NAME_SHAPE_SELECTION: s = "Surface Shape Selection"; break; case PAGE_NAME_SHAPE_SETTINGS: s = "Surface Shape Settings"; break; case PAGE_NAME_SURFACE_AND_VOLUME: s = "Surface and Volume"; break; case PAGE_NAME_SURFACE_CLIPPING: s = "Surface Clipping"; break; case PAGE_NAME_SURFACE_MISC: s = "Surface Miscellaneous"; break; case PAGE_NAME_TOPOGRAPHY: s = "Topography"; break; case PAGE_NAME_VECTOR_SELECTION: s = "Vector Selection"; break; case PAGE_NAME_VECTOR_SETTINGS: s = "Vector Settings"; break; case PAGE_NAME_INVALID: s = "Invalid"; break; } return s; } /** * update the data validity flag. */ void GuiDisplayControlDialog::updateDataValidityFlags() { BrainSet* brainSet = theMainWindow->getBrainSet(); bool haveSurfaceFlag = false; for (int i = 0; i < brainSet->getNumberOfBrainModels(); i++) { if (brainSet->getBrainModelSurface(i) != NULL) { haveSurfaceFlag = true; break; } } BrainModelBorderSet* bmbs = brainSet->getBorderSet(); validSurfaceData = haveSurfaceFlag; validVolumeData = (brainSet->getBrainModelVolume() != NULL); validVolumeFunctionalData = (brainSet->getNumberOfVolumeFunctionalFiles() > 0); validArealEstimationData = (brainSet->getArealEstimationFile()->getNumberOfColumns() > 0); validBorderData = ((bmbs->getNumberOfBorders() > 0) || (theMainWindow->getBrainSet()->getVolumeBorderFile()->getNumberOfBorders() > 0)); validCellData = ((theMainWindow->getBrainSet()->getCellProjectionFile()->getNumberOfCellProjections() > 0) || (theMainWindow->getBrainSet()->getVolumeCellFile()->empty() == false) || theMainWindow->getBrainSet()->getHaveTransformationDataCellFiles()); validCocomacData = (brainSet->getCocomacFile()->empty() == false); validContourData = (brainSet->getBrainModelContours() != NULL); validDeformationFieldData = (brainSet->getDeformationFieldFile()->getNumberOfColumns() > 0); validFociData = ((theMainWindow->getBrainSet()->getFociProjectionFile()->getNumberOfCellProjections() > 0)); validGeodesicData = (brainSet->getGeodesicDistanceFile()->getNumberOfColumns() > 0); validImageData = (brainSet->getNumberOfImageFiles() > 0); validLatLonData = (brainSet->getLatLonFile()->getNumberOfColumns() > 0); validMetricData = (brainSet->getMetricFile()->getNumberOfColumns() > 0); validModelData = (brainSet->getNumberOfVtkModelFiles() > 0); validPaintData = (brainSet->getPaintFile()->getNumberOfColumns() > 0); validProbAtlasSurfaceData = (brainSet->getProbabilisticAtlasSurfaceFile()->getNumberOfColumns() > 0); validProbAtlasVolumeData = (brainSet->getNumberOfVolumeProbAtlasFiles() > 0); const WustlRegionFile* wrf = theMainWindow->getBrainSet()->getWustlRegionFile(); validRegionData = ((wrf->getNumberOfTimeCourses() > 0) && (brainSet->getNumberOfVolumePaintFiles() > 0)); validRgbPaintData = (brainSet->getRgbPaintFile()->getNumberOfColumns() > 0); validSceneData = true; // always valid validSectionData = (brainSet->getSectionFile()->getNumberOfColumns() > 0); validShapeData = (brainSet->getSurfaceShapeFile()->getNumberOfColumns() > 0); validSurfaceAndVolumeData = (brainSet->getBrainModelSurfaceAndVolume() != NULL); validVectorData = (brainSet->getNumberOfVectorFiles() > 0); validTopographyData = (brainSet->getTopographyFile()->getNumberOfColumns() > 0); } /** * Update the page selection combo box based upon enabled pages. */ void GuiDisplayControlDialog::updatePageSelectionComboBox() { updateDataValidityFlags(); PAGE_NAME currentPageName = PAGE_NAME_INVALID; if (pageComboBoxItems.empty() == false) { const int item = pageComboBox->currentIndex(); if ((item >= 0) && (item < static_cast(pageComboBoxItems.size()))) { currentPageName = pageComboBoxItems[item]; } } pageComboBox->clear(); pageComboBoxItems.clear(); if (validSurfaceData) { pageComboBox->addItem(getPageName(PAGE_NAME_SURFACE_OVERLAY_UNDERLAY_NEW)); pageComboBoxItems.push_back(PAGE_NAME_SURFACE_OVERLAY_UNDERLAY_NEW); } if (validVolumeData) { pageComboBox->addItem(getPageName(PAGE_NAME_VOLUME_SELECTION)); pageComboBoxItems.push_back(PAGE_NAME_VOLUME_SELECTION); } if (validArealEstimationData) { pageComboBox->addItem(getPageName(PAGE_NAME_AREAL_ESTIMATION)); pageComboBoxItems.push_back(PAGE_NAME_AREAL_ESTIMATION); } if (validBorderData) { pageComboBox->addItem(getPageName(PAGE_NAME_BORDER_MAIN)); pageComboBoxItems.push_back(PAGE_NAME_BORDER_MAIN); } if (validBorderData) { pageComboBox->addItem(getPageName(PAGE_NAME_BORDER_COLOR)); pageComboBoxItems.push_back(PAGE_NAME_BORDER_COLOR); } if (validBorderData) { pageComboBox->addItem(getPageName(PAGE_NAME_BORDER_NAME)); pageComboBoxItems.push_back(PAGE_NAME_BORDER_NAME); } if (validCellData) { pageComboBox->addItem(getPageName(PAGE_NAME_CELL_MAIN)); pageComboBoxItems.push_back(PAGE_NAME_CELL_MAIN); } if (validCellData) { pageComboBox->addItem(getPageName(PAGE_NAME_CELL_CLASS)); pageComboBoxItems.push_back(PAGE_NAME_CELL_CLASS); } if (validCellData) { pageComboBox->addItem(getPageName(PAGE_NAME_CELL_COLOR)); pageComboBoxItems.push_back(PAGE_NAME_CELL_COLOR); } if (validCocomacData) { pageComboBox->addItem(getPageName(PAGE_NAME_COCOMAC_DISPLAY)); pageComboBoxItems.push_back(PAGE_NAME_COCOMAC_DISPLAY); } if (validCocomacData) { pageComboBox->addItem(getPageName(PAGE_NAME_COCOMAC_INFORMATION)); pageComboBoxItems.push_back(PAGE_NAME_COCOMAC_INFORMATION); } if (validContourData) { pageComboBox->addItem(getPageName(PAGE_NAME_CONTOUR_MAIN)); pageComboBoxItems.push_back(PAGE_NAME_CONTOUR_MAIN); } if (validContourData) { pageComboBox->addItem(getPageName(PAGE_NAME_CONTOUR_CLASS)); pageComboBoxItems.push_back(PAGE_NAME_CONTOUR_CLASS); } if (validContourData) { pageComboBox->addItem(getPageName(PAGE_NAME_CONTOUR_COLOR)); pageComboBoxItems.push_back(PAGE_NAME_CONTOUR_COLOR); } if (validDeformationFieldData) { pageComboBox->addItem(getPageName(PAGE_NAME_DEFORMATION_FIELD)); pageComboBoxItems.push_back(PAGE_NAME_DEFORMATION_FIELD); } if (validFociData) { pageComboBox->addItem(getPageName(PAGE_NAME_FOCI_MAIN)); pageComboBoxItems.push_back(PAGE_NAME_FOCI_MAIN); } if (validFociData) { pageComboBox->addItem(getPageName(PAGE_NAME_FOCI_CLASS)); pageComboBoxItems.push_back(PAGE_NAME_FOCI_CLASS); } if (validFociData) { pageComboBox->addItem(getPageName(PAGE_NAME_FOCI_COLOR)); pageComboBoxItems.push_back(PAGE_NAME_FOCI_COLOR); } if (validFociData) { pageComboBox->addItem(getPageName(PAGE_NAME_FOCI_KEYWORD)); pageComboBoxItems.push_back(PAGE_NAME_FOCI_KEYWORD); } if (validFociData) { pageComboBox->addItem(getPageName(PAGE_NAME_FOCI_NAME)); pageComboBoxItems.push_back(PAGE_NAME_FOCI_NAME); } if (validFociData) { pageComboBox->addItem(getPageName(PAGE_NAME_FOCI_SEARCH)); pageComboBoxItems.push_back(PAGE_NAME_FOCI_SEARCH); } if (validFociData) { pageComboBox->addItem(getPageName(PAGE_NAME_FOCI_TABLE)); pageComboBoxItems.push_back(PAGE_NAME_FOCI_TABLE); } if (validGeodesicData) { pageComboBox->addItem(getPageName(PAGE_NAME_GEODESIC)); pageComboBoxItems.push_back(PAGE_NAME_GEODESIC); } if (validImageData) { pageComboBox->addItem(getPageName(PAGE_NAME_IMAGES)); pageComboBoxItems.push_back(PAGE_NAME_IMAGES); } if (validLatLonData) { pageComboBox->addItem(getPageName(PAGE_NAME_LATLON)); pageComboBoxItems.push_back(PAGE_NAME_LATLON); } if (validMetricData) { pageComboBox->addItem(getPageName(PAGE_NAME_METRIC_MISCELLANEOUS)); pageComboBoxItems.push_back(PAGE_NAME_METRIC_MISCELLANEOUS); } if (validMetricData) { pageComboBox->addItem(getPageName(PAGE_NAME_METRIC_SELECTION)); pageComboBoxItems.push_back(PAGE_NAME_METRIC_SELECTION); } if (validMetricData || validVolumeFunctionalData) { pageComboBox->addItem(getPageName(PAGE_NAME_METRIC_SETTINGS)); pageComboBoxItems.push_back(PAGE_NAME_METRIC_SETTINGS); } if (validModelData) { pageComboBox->addItem(getPageName(PAGE_NAME_MODELS_MAIN)); pageComboBoxItems.push_back(PAGE_NAME_MODELS_MAIN); } if (validModelData) { pageComboBox->addItem(getPageName(PAGE_NAME_MODELS_SETTINGS)); pageComboBoxItems.push_back(PAGE_NAME_MODELS_SETTINGS); } if (validPaintData) { pageComboBox->addItem(getPageName(PAGE_NAME_PAINT_MAIN)); pageComboBoxItems.push_back(PAGE_NAME_PAINT_MAIN); pageComboBox->addItem(getPageName(PAGE_NAME_PAINT_COLUMN)); pageComboBoxItems.push_back(PAGE_NAME_PAINT_COLUMN); pageComboBox->addItem(getPageName(PAGE_NAME_PAINT_NAMES)); pageComboBoxItems.push_back(PAGE_NAME_PAINT_NAMES); } if (validProbAtlasSurfaceData) { pageComboBox->addItem(getPageName(PAGE_NAME_PROB_ATLAS_SURFACE_MAIN)); pageComboBoxItems.push_back(PAGE_NAME_PROB_ATLAS_SURFACE_MAIN); } if (validProbAtlasSurfaceData) { pageComboBox->addItem(getPageName(PAGE_NAME_PROB_ATLAS_SURFACE_AREA)); pageComboBoxItems.push_back(PAGE_NAME_PROB_ATLAS_SURFACE_AREA); } if (validProbAtlasSurfaceData) { pageComboBox->addItem(getPageName(PAGE_NAME_PROB_ATLAS_SURFACE_CHANNEL)); pageComboBoxItems.push_back(PAGE_NAME_PROB_ATLAS_SURFACE_CHANNEL); } if (validProbAtlasVolumeData) { pageComboBox->addItem(getPageName(PAGE_NAME_PROB_ATLAS_VOLUME_MAIN)); pageComboBoxItems.push_back(PAGE_NAME_PROB_ATLAS_VOLUME_MAIN); } if (validProbAtlasVolumeData) { pageComboBox->addItem(getPageName(PAGE_NAME_PROB_ATLAS_VOLUME_AREA)); pageComboBoxItems.push_back(PAGE_NAME_PROB_ATLAS_VOLUME_AREA); } if (validProbAtlasVolumeData) { pageComboBox->addItem(getPageName(PAGE_NAME_PROB_ATLAS_VOLUME_CHANNEL)); pageComboBoxItems.push_back(PAGE_NAME_PROB_ATLAS_VOLUME_CHANNEL); } if (validRegionData) { pageComboBox->addItem(getPageName(PAGE_NAME_REGION)); pageComboBoxItems.push_back(PAGE_NAME_REGION); } if (validRgbPaintData) { pageComboBox->addItem(getPageName(PAGE_NAME_RGB_PAINT_MAIN)); pageComboBoxItems.push_back(PAGE_NAME_RGB_PAINT_MAIN); pageComboBox->addItem(getPageName(PAGE_NAME_RGB_PAINT_SELECTION)); pageComboBoxItems.push_back(PAGE_NAME_RGB_PAINT_SELECTION); } if (validSceneData) { pageComboBox->addItem(getPageName(PAGE_NAME_SCENE)); pageComboBoxItems.push_back(PAGE_NAME_SCENE); } if (validSectionData) { pageComboBox->addItem(getPageName(PAGE_NAME_SECTION_MAIN)); pageComboBoxItems.push_back(PAGE_NAME_SECTION_MAIN); } if (validShapeData) { pageComboBox->addItem(getPageName(PAGE_NAME_SHAPE_SELECTION)); pageComboBoxItems.push_back(PAGE_NAME_SHAPE_SELECTION); } if (validShapeData) { pageComboBox->addItem(getPageName(PAGE_NAME_SHAPE_SETTINGS)); pageComboBoxItems.push_back(PAGE_NAME_SHAPE_SETTINGS); } if (validSurfaceAndVolumeData) { pageComboBox->addItem(getPageName(PAGE_NAME_SURFACE_AND_VOLUME)); pageComboBoxItems.push_back(PAGE_NAME_SURFACE_AND_VOLUME); } if (validSurfaceData) { pageComboBox->addItem(getPageName(PAGE_NAME_SURFACE_CLIPPING)); pageComboBoxItems.push_back(PAGE_NAME_SURFACE_CLIPPING); } if (validSurfaceData) { pageComboBox->addItem(getPageName(PAGE_NAME_SURFACE_MISC)); pageComboBoxItems.push_back(PAGE_NAME_SURFACE_MISC); } if (validTopographyData) { pageComboBox->addItem(getPageName(PAGE_NAME_TOPOGRAPHY)); pageComboBoxItems.push_back(PAGE_NAME_TOPOGRAPHY); } if (validVectorData) { pageComboBox->addItem(getPageName(PAGE_NAME_VECTOR_SELECTION)); pageComboBoxItems.push_back(PAGE_NAME_VECTOR_SELECTION); pageComboBox->addItem(getPageName(PAGE_NAME_VECTOR_SETTINGS)); pageComboBoxItems.push_back(PAGE_NAME_VECTOR_SETTINGS); } if (validVolumeData) { pageComboBox->addItem(getPageName(PAGE_NAME_VOLUME_SETTINGS)); pageComboBoxItems.push_back(PAGE_NAME_VOLUME_SETTINGS); } if (validVolumeData) { pageComboBox->addItem(getPageName(PAGE_NAME_VOLUME_SURFACE_OUTLINE)); pageComboBoxItems.push_back(PAGE_NAME_VOLUME_SURFACE_OUTLINE); } int defaultItem = 0; for (int i = 0; i < static_cast(pageComboBoxItems.size()); i++) { if (pageComboBoxItems[i] == currentPageName) { defaultItem = i; break; } } if (pageComboBoxItems.empty() == false) { pageComboBox->blockSignals(true); pageComboBox->setCurrentIndex(defaultItem); pageComboBox->blockSignals(false); } } /** * called when popup menu overlay selection is made. */ void GuiDisplayControlDialog::slotOverlaySelectionPopupMenu(QAction* action) { // // Get overlay number and selection // const int item = action->data().toInt(); const int overlayNumber = item / 1000; const int dataTypeValue = item % 1000; // // Set the overlay // BrainModelSurfaceOverlay* bmsOverlay = theMainWindow->getBrainSet()->getSurfaceOverlay(overlayNumber); const BrainModelSurfaceOverlay::OVERLAY_SELECTIONS dataType = static_cast(dataTypeValue); bmsOverlay->setOverlay(getSurfaceModelIndex(), dataType); // // Update the dialog // switch (bmsOverlay->getOverlay(dataType)) { case BrainModelSurfaceOverlay::OVERLAY_NONE: break; case BrainModelSurfaceOverlay::OVERLAY_AREAL_ESTIMATION: updateArealEstimationItems(); break; case BrainModelSurfaceOverlay::OVERLAY_COCOMAC: updateCocomacItems(); break; case BrainModelSurfaceOverlay::OVERLAY_METRIC: updateMetricSelectionPage(); break; case BrainModelSurfaceOverlay::OVERLAY_PAINT: updatePaintColumnPage(); break; case BrainModelSurfaceOverlay::OVERLAY_PROBABILISTIC_ATLAS: break; case BrainModelSurfaceOverlay::OVERLAY_RGB_PAINT: updateRgbPaintItems(); break; case BrainModelSurfaceOverlay::OVERLAY_SECTIONS: updateSectionMainPage(); break; case BrainModelSurfaceOverlay::OVERLAY_SHOW_CROSSOVERS: break; case BrainModelSurfaceOverlay::OVERLAY_SHOW_EDGES: break; case BrainModelSurfaceOverlay::OVERLAY_SURFACE_SHAPE: updateShapeSelections(); break; case BrainModelSurfaceOverlay::OVERLAY_TOPOGRAPHY: updateTopographyItems(); break; case BrainModelSurfaceOverlay::OVERLAY_GEOGRAPHY_BLENDING: break; } updateSurfaceOverlayWidgets(); const int indx = pageComboBox->currentIndex(); initializeSelectedOverlay(static_cast(pageComboBoxItems[indx])); //updateOverlayNumberComboBox(); theMainWindow->getBrainSet()->getNodeColoring()->assignColors(); GuiBrainModelOpenGL::updateAllGL(); } /** * called when popup menu selection is made. */ void GuiDisplayControlDialog::slotPageSelectionPopupMenu(QAction* action) { // get integer from action->data const int item = action->data().toInt(); pageComboBoxSelection(item); } /** * called when page back tool button pressed. */ void GuiDisplayControlDialog::slotPageBackToolButtonPressed(QAction*) { pagesVisitedIndex--; if ((pagesVisitedIndex >= 0) && (pagesVisitedIndex < static_cast(pagesVisited.size()))) { showDisplayControlPage(pagesVisited[pagesVisitedIndex], false); } } /** * called when page forward tool button pressed. */ void GuiDisplayControlDialog::slotPageForwardToolButtonPressed(QAction*) { pagesVisitedIndex++; if ((pagesVisitedIndex >= 0) && (pagesVisitedIndex < static_cast(pagesVisited.size()))) { showDisplayControlPage(pagesVisited[pagesVisitedIndex], false); } } /** * show a display control page. */ void GuiDisplayControlDialog::showDisplayControlPage(const PAGE_NAME pageName, const bool updatePagesVisited) { bool enableSurfaceModelIndexComboBox = false; bool enableSurfaceModelOverlayNumberComboBox = false; pageComboBox->blockSignals(true); for (int i = 0; i < static_cast(pageComboBoxItems.size()); i++) { if (pageComboBoxItems[i] == pageName) { pageComboBox->blockSignals(true); pageComboBox->setCurrentIndex(i); pageComboBox->blockSignals(false); } } pageComboBox->blockSignals(false); metricApplySelectionToLeftAndRightStructuresFlagCheckBox->setHidden(true); shapeApplySelectionToLeftAndRightStructuresFlagCheckBox->setHidden(true); paintApplySelectionToLeftAndRightStructuresFlagCheckBox->setHidden(true); rgbApplySelectionToLeftAndRightStructuresFlagCheckBox->setHidden(true); probAtlasSurfaceApplySelectionToLeftAndRightStructuresFlagCheckBox->setHidden(true); switch(pageName) { case PAGE_NAME_SURFACE_OVERLAY_UNDERLAY_NEW: if (pageOverlayUnderlaySurfaceNew == NULL) { createOverlayUnderlaySurfacePageNew(); updateAllItemsInDialog(true, false); } pageWidgetStack->setCurrentWidget(pageOverlayUnderlaySurfaceNew); enableSurfaceModelIndexComboBox = true; break; case PAGE_NAME_AREAL_ESTIMATION: if (pageArealEstimation == NULL) { createArealEstimationPage(); updateArealEstimationItems(); } pageWidgetStack->setCurrentWidget(pageArealEstimation); enableSurfaceModelIndexComboBox = true; enableSurfaceModelOverlayNumberComboBox = true; break; case PAGE_NAME_BORDER_MAIN: if (pageBorderMain == NULL) { createBorderMainPage(); updateBorderMainPage(); } pageWidgetStack->setCurrentWidget(pageBorderMain); break; case PAGE_NAME_BORDER_COLOR: if (pageBorderColor == NULL) { createBorderColorPage(); updateBorderColorPage(true); } pageWidgetStack->setCurrentWidget(pageBorderColor); break; case PAGE_NAME_BORDER_NAME: if (pageBorderName == NULL) { createBorderNamePage(); updateBorderNamePage(true); } pageWidgetStack->setCurrentWidget(pageBorderName); break; case PAGE_NAME_CELL_MAIN: if (pageCellsMain == NULL) { createCellMainPage(); updateCellMainPage(); } pageWidgetStack->setCurrentWidget(pageCellsMain); break; case PAGE_NAME_CELL_CLASS: if (pageCellsClass == NULL) { createCellClassPage(); updateCellClassPage(true); } pageWidgetStack->setCurrentWidget(pageCellsClass); break; case PAGE_NAME_CELL_COLOR: if (pageCellsColor == NULL) { createCellColorPage(); updateCellColorPage(true); } pageWidgetStack->setCurrentWidget(pageCellsColor); break; case PAGE_NAME_COCOMAC_DISPLAY: if (pageCocomacDisplay == NULL) { createCocomacDisplayPage(); updateCocomacDisplayPage(); } pageWidgetStack->setCurrentWidget(pageCocomacDisplay); break; case PAGE_NAME_COCOMAC_INFORMATION: if (pageCocomacInformation == NULL) { createCocomacFileInformationPage(); updateCocomacInformationPage(); } pageWidgetStack->setCurrentWidget(pageCocomacInformation); break; case PAGE_NAME_CONTOUR_MAIN: if (pageContourMain == NULL) { createContourMainPage(); updateContourMainPage(); } pageWidgetStack->setCurrentWidget(pageContourMain); break; case PAGE_NAME_CONTOUR_CLASS: if (pageContourClass == NULL) { createContourClassPage(); updateContourClassPage(true); } pageWidgetStack->setCurrentWidget(pageContourClass); break; case PAGE_NAME_CONTOUR_COLOR: if (pageContourColor == NULL) { createContourColorPage(); updateContourColorPage(true); } pageWidgetStack->setCurrentWidget(pageContourColor); break; case PAGE_NAME_DEFORMATION_FIELD: if (pageDeformationField == NULL) { createDeformationFieldPage(); updateDeformationFieldPage(); } pageWidgetStack->setCurrentWidget(pageDeformationField); break; case PAGE_NAME_FOCI_MAIN: if (pageFociMain == NULL) { createFociMainPage(); updateFociMainPage(); } pageWidgetStack->setCurrentWidget(pageFociMain); break; case PAGE_NAME_FOCI_CLASS: if (pageFociClass == NULL) { createFociClassPage(); updateFociClassPage(true); } pageWidgetStack->setCurrentWidget(pageFociClass); break; case PAGE_NAME_FOCI_COLOR: if (pageFociColor == NULL) { createFociColorPage(); updateFociColorPage(true); } pageWidgetStack->setCurrentWidget(pageFociColor); break; case PAGE_NAME_FOCI_KEYWORD: if (pageFociKeyword == NULL) { createFociKeywordPage(); updateFociKeywordPage(true); } pageWidgetStack->setCurrentWidget(pageFociKeyword); break; case PAGE_NAME_FOCI_NAME: if (pageFociName == NULL) { createFociNamePage(); updateFociNamePage(true); } pageWidgetStack->setCurrentWidget(pageFociName); break; case PAGE_NAME_FOCI_SEARCH: if (pageFociSearch == NULL) { createFociSearchPage(); updateFociSearchPage(true); } pageFociSearch->updateGeometry(); pageWidgetStack->setCurrentWidget(pageFociSearch); break; case PAGE_NAME_FOCI_TABLE: if (pageFociTable == NULL) { createFociTablePage(); updateFociTablePage(true); } pageWidgetStack->setCurrentWidget(pageFociTable); break; case PAGE_NAME_GEODESIC: if (pageGeodesicMain == NULL) { createGeodesicPage(); updateGeodesicItems(); } pageWidgetStack->setCurrentWidget(pageGeodesicMain); break; case PAGE_NAME_IMAGES: if (pageImages == NULL) { createImagesPage(); updateImagesItems(); } pageWidgetStack->setCurrentWidget(pageImages); break; case PAGE_NAME_LATLON: if (pageLatLonMain == NULL) { createLatLonPage(); updateLatLonItems(); } pageWidgetStack->setCurrentWidget(pageLatLonMain); break; case PAGE_NAME_METRIC_MISCELLANEOUS: if (pageMetricMiscellaneous == NULL) { createMetricMiscellaneousPage(); updateMetricMiscellaneousPage(); } pageWidgetStack->setCurrentWidget(pageMetricMiscellaneous); break; case PAGE_NAME_METRIC_SELECTION: if (pageMetricSelection == NULL) { createMetricSelectionPage(); updateMetricSelectionPage(); } pageWidgetStack->setCurrentWidget(pageMetricSelection); enableSurfaceModelIndexComboBox = true; enableSurfaceModelOverlayNumberComboBox = true; metricApplySelectionToLeftAndRightStructuresFlagCheckBox->setHidden(false); break; case PAGE_NAME_METRIC_SETTINGS: if (pageMetricSettings == NULL) { createMetricSettingsPage(); updateMetricSettingsPage(); } updateMetricSettingsThresholdColumnComboBox(); pageWidgetStack->setCurrentWidget(pageMetricSettings); break; case PAGE_NAME_MODELS_MAIN: if (pageModelsMain == NULL) { createModelsMainPage(); updateModelMainPage(); } pageWidgetStack->setCurrentWidget(pageModelsMain); break; case PAGE_NAME_MODELS_SETTINGS: if (pageModelsSettings == NULL) { createModelsSettingsPage(); updateModelSettingsPage(); } pageWidgetStack->setCurrentWidget(pageModelsSettings); break; case PAGE_NAME_PAINT_MAIN: if (pagePaintMain == NULL) { createPaintMainPage(); updatePaintMainPage(); } pageWidgetStack->setCurrentWidget(pagePaintMain); break; case PAGE_NAME_PAINT_COLUMN: if (pagePaintColumn == NULL) { createPaintColumnPage(); updatePaintColumnPage(); } pageWidgetStack->setCurrentWidget(pagePaintColumn); enableSurfaceModelIndexComboBox = true; enableSurfaceModelOverlayNumberComboBox = true; paintApplySelectionToLeftAndRightStructuresFlagCheckBox->setHidden(false); break; case PAGE_NAME_PAINT_NAMES: if (pagePaintName == NULL) { createPaintNamePage(); updatePaintNamePage(); } pageWidgetStack->setCurrentWidget(pagePaintName); break; case PAGE_NAME_PROB_ATLAS_SURFACE_MAIN: if (pageProbAtlasSurfaceMain == NULL) { createProbAtlasSurfaceMainPage(); updateProbAtlasSurfaceMainPage(); } pageWidgetStack->setCurrentWidget(pageProbAtlasSurfaceMain); enableSurfaceModelIndexComboBox = true; probAtlasSurfaceApplySelectionToLeftAndRightStructuresFlagCheckBox->setHidden(false); break; case PAGE_NAME_PROB_ATLAS_SURFACE_AREA: if (pageProbAtlasSurfaceArea == NULL) { createProbAtlasSurfaceAreaPage(); updateProbAtlasSurfaceAreaPage(true); } pageWidgetStack->setCurrentWidget(pageProbAtlasSurfaceArea); break; case PAGE_NAME_PROB_ATLAS_SURFACE_CHANNEL: if (pageProbAtlasSurfaceChannel == NULL) { createProbAtlasSurfaceChannelPage(); updateProbAtlasSurfaceChannelPage(true); } pageWidgetStack->setCurrentWidget(pageProbAtlasSurfaceChannel); break; case PAGE_NAME_PROB_ATLAS_VOLUME_MAIN: if (pageProbAtlasVolumeMain == NULL) { createProbAtlasVolumeMainPage(); updateProbAtlasVolumeMainPage(); } pageWidgetStack->setCurrentWidget(pageProbAtlasVolumeMain); break; case PAGE_NAME_PROB_ATLAS_VOLUME_AREA: if (pageProbAtlasVolumeArea == NULL) { createProbAtlasVolumeAreaPage(); updateProbAtlasVolumeAreaPage(true); } pageWidgetStack->setCurrentWidget(pageProbAtlasVolumeArea); break; case PAGE_NAME_PROB_ATLAS_VOLUME_CHANNEL: if (pageProbAtlasVolumeChannel == NULL) { createProbAtlasVolumeChannelPage(); updateProbAtlasVolumeChannelPage(true); } pageWidgetStack->setCurrentWidget(pageProbAtlasVolumeChannel); break; case PAGE_NAME_REGION: if (pageRegionMain == NULL) { createRegionPage(); updateRegionItems(); } pageWidgetStack->setCurrentWidget(pageRegionMain); break; case PAGE_NAME_RGB_PAINT_MAIN: if (pageRgbPaintMain == NULL) { createRgbPaintMainPage(); updateRgbPaintMainPage(); } pageWidgetStack->setCurrentWidget(pageRgbPaintMain); break; case PAGE_NAME_RGB_PAINT_SELECTION: if (pageRgbPaintSelection == NULL) { createRgbPaintSelectionPage(); updateRgbPaintSelectionPage(); } pageWidgetStack->setCurrentWidget(pageRgbPaintSelection); enableSurfaceModelIndexComboBox = true; enableSurfaceModelOverlayNumberComboBox = true; rgbApplySelectionToLeftAndRightStructuresFlagCheckBox->setHidden(false); break; case PAGE_NAME_SCENE: if (pageSceneMain == NULL) { createScenePage(); updateSceneItems(); } sceneListBox->blockSignals(true); pageWidgetStack->setCurrentWidget(pageSceneMain); sceneListBox->blockSignals(false); break; case PAGE_NAME_SECTION_MAIN: if (pageSectionMain == NULL) { createSectionMainPage(); updateSectionMainPage(); } pageWidgetStack->setCurrentWidget(pageSectionMain); break; case PAGE_NAME_SHAPE_SELECTION: if (pageSurfaceShapeSelections == NULL) { createShapeSelectionPage(); updateShapeSelections(); } pageWidgetStack->setCurrentWidget(pageSurfaceShapeSelections); enableSurfaceModelIndexComboBox = true; enableSurfaceModelOverlayNumberComboBox = true; shapeApplySelectionToLeftAndRightStructuresFlagCheckBox->setHidden(false); break; case PAGE_NAME_SHAPE_SETTINGS: if (pageSurfaceShapeSettings == NULL) { createShapeSettingsPage(); updateShapeSettings(); } updateShapeSettingsColorMappingComboBox(); pageWidgetStack->setCurrentWidget(pageSurfaceShapeSettings); break; case PAGE_NAME_SURFACE_AND_VOLUME: if (pageSurfaceAndVolume == NULL) { createSurfaceAndVolumePage(); updateSurfaceAndVolumeItems(); } pageWidgetStack->setCurrentWidget(pageSurfaceAndVolume); break; case PAGE_NAME_SURFACE_CLIPPING: if (pageSurfaceClipping == NULL) { createSurfaceClippingPage(); updateSurfaceClippingPage(); } pageWidgetStack->setCurrentWidget(pageSurfaceClipping); break; case PAGE_NAME_SURFACE_MISC: if (pageSurfaceMisc == NULL) { createSurfaceMiscPage(); updateMiscItems(); } pageWidgetStack->setCurrentWidget(pageSurfaceMisc); break; case PAGE_NAME_VECTOR_SELECTION: if (pageVectorSelection == NULL) { createVectorSelectionPage(); updateVectorSelectionPage(); } pageWidgetStack->setCurrentWidget(pageVectorSelection); break; case PAGE_NAME_VECTOR_SETTINGS: if (pageVectorSettings == NULL) { createVectorSettingsPage(); updateVectorSettingsPage(); } pageWidgetStack->setCurrentWidget(pageVectorSettings); break; case PAGE_NAME_TOPOGRAPHY: if (pageTopography == NULL) { createTopographyPage(); updateTopographyItems(); } pageWidgetStack->setCurrentWidget(pageTopography); enableSurfaceModelIndexComboBox = true; break; case PAGE_NAME_VOLUME_SELECTION: if (pageVolumeSelection == NULL) { createOverlayUnderlayVolumeSelectionPage(); updateVolumeSelectionPage(); } pageWidgetStack->setCurrentWidget(pageVolumeSelection); break; case PAGE_NAME_VOLUME_SETTINGS: if (pageVolumeSettings == NULL) { createOverlayUnderlayVolumeSettingsPage(); updateVolumeSettingsPage(); } pageWidgetStack->setCurrentWidget(pageVolumeSettings); break; case PAGE_NAME_VOLUME_SURFACE_OUTLINE: if (pageVolumeSurfaceOutline == NULL) { createOverlayUnderlayVolumeSurfaceOutlinePage(); updateVolumeSurfaceOutlinePage(); } pageWidgetStack->setCurrentWidget(pageVolumeSurfaceOutline); break; case PAGE_NAME_INVALID: break; } // // Should pages visited be updated // if (updatePagesVisited) { // // Remove any pages "forward" of the current page index // const int numPages = static_cast(pagesVisited.size()); if ((pagesVisitedIndex >= 0) && (pagesVisitedIndex < (numPages - 1))) { pagesVisited.erase(pagesVisited.begin() + pagesVisitedIndex + 1, pagesVisited.end()); } // // Add new pages // pagesVisited.push_back(pageName); pagesVisitedIndex = static_cast(pagesVisited.size() - 1); } if (DebugControl::getDebugOn()) { std::cout << "PAGES VISITED TRACKING" << std::endl; for (int i = 0; i < static_cast(pagesVisited.size()); i++) { std::cout << i << ": " << getPageName(pagesVisited[i]).toAscii().constData(); if (pagesVisitedIndex == i) { std::cout << " <==== current page visited index"; } std::cout << std::endl; } std::cout << std::endl; } surfaceModelGroupBox->setHidden((enableSurfaceModelIndexComboBox == false) && (enableSurfaceModelOverlayNumberComboBox == false)); overlayNumberWidgetGroup->setHidden(enableSurfaceModelOverlayNumberComboBox == false); // // Scroll to top of page and left // QScrollBar* vertScrollBar = widgetStackScrollArea->verticalScrollBar(); vertScrollBar->setValue(vertScrollBar->minimum()); QScrollBar* horizScrollBar = widgetStackScrollArea->horizontalScrollBar(); horizScrollBar->setValue(horizScrollBar->minimum()); // // Enable/Disable back and forward buttons // pageBackToolButton->setEnabled(pagesVisitedIndex > 0); pageForwardToolButton->setEnabled(pagesVisitedIndex < static_cast((pagesVisited.size() - 1))); if (enableSurfaceModelOverlayNumberComboBox) { initializeSelectedOverlay(pageName); } } /** * initialize the overlay for control be a page. */ void GuiDisplayControlDialog::initializeSelectedOverlay(const PAGE_NAME pageName) { BrainModelSurfaceOverlay::OVERLAY_SELECTIONS surfaceOverlay = BrainModelSurfaceOverlay::OVERLAY_NONE; switch (pageName) { case PAGE_NAME_AREAL_ESTIMATION: surfaceOverlay = BrainModelSurfaceOverlay::OVERLAY_AREAL_ESTIMATION; break; case PAGE_NAME_BORDER_MAIN: case PAGE_NAME_BORDER_COLOR: case PAGE_NAME_BORDER_NAME: case PAGE_NAME_CELL_MAIN: case PAGE_NAME_CELL_CLASS: case PAGE_NAME_CELL_COLOR: break; case PAGE_NAME_COCOMAC_DISPLAY: case PAGE_NAME_COCOMAC_INFORMATION: surfaceOverlay = BrainModelSurfaceOverlay::OVERLAY_COCOMAC; break; case PAGE_NAME_CONTOUR_MAIN: case PAGE_NAME_CONTOUR_CLASS: case PAGE_NAME_CONTOUR_COLOR: case PAGE_NAME_DEFORMATION_FIELD: case PAGE_NAME_FOCI_MAIN: case PAGE_NAME_FOCI_CLASS: case PAGE_NAME_FOCI_COLOR: case PAGE_NAME_FOCI_KEYWORD: case PAGE_NAME_FOCI_NAME: case PAGE_NAME_FOCI_SEARCH: case PAGE_NAME_FOCI_TABLE: case PAGE_NAME_GEODESIC: case PAGE_NAME_IMAGES: case PAGE_NAME_LATLON: break; case PAGE_NAME_METRIC_MISCELLANEOUS: case PAGE_NAME_METRIC_SELECTION: case PAGE_NAME_METRIC_SETTINGS: surfaceOverlay = BrainModelSurfaceOverlay::OVERLAY_METRIC; break; case PAGE_NAME_MODELS_MAIN: case PAGE_NAME_MODELS_SETTINGS: break; case PAGE_NAME_PAINT_COLUMN: case PAGE_NAME_PAINT_MAIN: case PAGE_NAME_PAINT_NAMES: surfaceOverlay = BrainModelSurfaceOverlay::OVERLAY_PAINT; break; case PAGE_NAME_PROB_ATLAS_SURFACE_MAIN: case PAGE_NAME_PROB_ATLAS_SURFACE_AREA: case PAGE_NAME_PROB_ATLAS_SURFACE_CHANNEL: surfaceOverlay = BrainModelSurfaceOverlay::OVERLAY_PROBABILISTIC_ATLAS; break; case PAGE_NAME_PROB_ATLAS_VOLUME_MAIN: case PAGE_NAME_PROB_ATLAS_VOLUME_AREA: case PAGE_NAME_PROB_ATLAS_VOLUME_CHANNEL: case PAGE_NAME_REGION: break; case PAGE_NAME_RGB_PAINT_MAIN: case PAGE_NAME_RGB_PAINT_SELECTION: surfaceOverlay = BrainModelSurfaceOverlay::OVERLAY_RGB_PAINT; break; case PAGE_NAME_SCENE: break; case PAGE_NAME_SECTION_MAIN: surfaceOverlay = BrainModelSurfaceOverlay::OVERLAY_SECTIONS; break; case PAGE_NAME_SHAPE_SELECTION: case PAGE_NAME_SHAPE_SETTINGS: surfaceOverlay = BrainModelSurfaceOverlay::OVERLAY_SURFACE_SHAPE; break; case PAGE_NAME_SURFACE_CLIPPING: case PAGE_NAME_SURFACE_AND_VOLUME: case PAGE_NAME_SURFACE_MISC: case PAGE_NAME_SURFACE_OVERLAY_UNDERLAY_NEW: break; case PAGE_NAME_TOPOGRAPHY: surfaceOverlay = BrainModelSurfaceOverlay::OVERLAY_TOPOGRAPHY; break; case PAGE_NAME_VECTOR_SELECTION: case PAGE_NAME_VECTOR_SETTINGS: case PAGE_NAME_VOLUME_SELECTION: case PAGE_NAME_VOLUME_SETTINGS: case PAGE_NAME_VOLUME_SURFACE_OUTLINE: case PAGE_NAME_INVALID: break; } updateOverlayNumberComboBox(); if (surfaceOverlay != BrainModelSurfaceOverlay::OVERLAY_NONE) { BrainSet* brainSet = theMainWindow->getBrainSet(); int defaultItem = -1; for (int m = 0; m < brainSet->getNumberOfSurfaceOverlays(); m++) { const BrainModelSurfaceOverlay* bmsOverlay = brainSet->getSurfaceOverlay(m); if (bmsOverlay->getOverlay(getSurfaceModelIndex()) == surfaceOverlay) { defaultItem = m; } } if (defaultItem >= 0) { overlayNumberComboBox->setCurrentIndex(defaultItem); slotOverlayNumberComboBox(defaultItem); } } } /** * update the overlay number combo box. */ void GuiDisplayControlDialog::updateOverlayNumberComboBox() { for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfSurfaceOverlays(); i++) { BrainModelSurfaceOverlay* bmsOverlay = theMainWindow->getBrainSet()->getSurfaceOverlay(i); const QString text = (bmsOverlay->getName() + " ==> " + bmsOverlay->getDataTypeName(getSurfaceModelIndex())); overlayNumberComboBox->setItemText(i, text); } } /** * Called when a page is selected using the page combo box */ void GuiDisplayControlDialog::pageComboBoxSelection(int itemIn) { if ((itemIn >= 0) && (itemIn < static_cast(pageComboBoxItems.size()))) { const int item = pageComboBoxItems[itemIn]; showDisplayControlPage(static_cast(item), true); } else { std::cout << "PROGRAM ERROR: Display Control Dialog pageComboBox not properly set up." << std::endl; } } /** * create the overlay underlay volume selection page. */ void GuiDisplayControlDialog::createOverlayUnderlayVolumeSelectionPage() { QWidget* volSelQVBox = new QWidget; QVBoxLayout* volSelLayout = new QVBoxLayout(volSelQVBox); const int PRIMARY_COLUMN = 0; const int SECONDARY_COLUMN = PRIMARY_COLUMN + 1; const int UNDERLAY_COLUMN = SECONDARY_COLUMN + 1; const int NAME_COLUMN = UNDERLAY_COLUMN + 1; const int INFO_COLUMN = NAME_COLUMN + 1; const int METADATA_COLUMN = INFO_COLUMN + 1; const int COMBO_COLUMN = METADATA_COLUMN + 1; //const int NUM_COLUMNS = COMBO_COLUMN + 1; // // Widget and grid layout for volume selections // QGroupBox* uoGroup = new QGroupBox("Overlay Underlay"); volSelLayout->addWidget(uoGroup); QGridLayout* grid = new QGridLayout(uoGroup); int rowNumber = 0; // // column titles // grid->addWidget(new QLabel("Primary\nOverlay"), rowNumber, PRIMARY_COLUMN, Qt::AlignHCenter); grid->addWidget(new QLabel("Secondary\nOverlay"), rowNumber, SECONDARY_COLUMN, Qt::AlignHCenter); grid->addWidget(new QLabel("Underlay"), rowNumber, UNDERLAY_COLUMN, Qt::AlignHCenter); grid->addWidget(new QLabel("Coloring"), rowNumber, NAME_COLUMN, Qt::AlignLeft); rowNumber++; // // Button groups to keep radio buttons set correctly // QButtonGroup* volumePrimaryOverlayButtonGroup = new QButtonGroup(this); volumePrimaryOverlayButtonGroup->setExclusive(true); QObject::connect(volumePrimaryOverlayButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(volumePrimaryOverlaySelection(int))); QButtonGroup* volumeSecondaryOverlayButtonGroup = new QButtonGroup(this); volumeSecondaryOverlayButtonGroup->setExclusive(true); QObject::connect(volumeSecondaryOverlayButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(volumeSecondaryOverlaySelection(int))); QButtonGroup* volumeUnderlayButtonGroup = new QButtonGroup(this); volumeUnderlayButtonGroup->setExclusive(true); QObject::connect(volumeUnderlayButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(volumeUnderlaySelection(int))); // // None selections // volumePrimaryOverlayNoneButton = new QRadioButton(""); grid->addWidget(volumePrimaryOverlayNoneButton, rowNumber, PRIMARY_COLUMN, Qt::AlignHCenter); volumePrimaryOverlayButtonGroup->addButton(volumePrimaryOverlayNoneButton, BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_NONE); volumeSecondaryOverlayNoneButton = new QRadioButton(""); grid->addWidget(volumeSecondaryOverlayNoneButton, rowNumber, SECONDARY_COLUMN, Qt::AlignHCenter); volumeSecondaryOverlayButtonGroup->addButton(volumeSecondaryOverlayNoneButton, BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_NONE); volumeUnderlayNoneButton = new QRadioButton(""); grid->addWidget(volumeUnderlayNoneButton, rowNumber, UNDERLAY_COLUMN, Qt::AlignHCenter); volumeUnderlayButtonGroup->addButton(volumeUnderlayNoneButton, BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_NONE); grid->addWidget(new QLabel("No Coloring"), rowNumber, NAME_COLUMN); grid->addWidget(new QLabel(" "), rowNumber, COMBO_COLUMN); rowNumber++; // // This QString is added to each combo box prior to setting its fixed size so // that it will display the number of characters in comboSize. Changing the // number of characters in "comboSize" will change the sizes of the combo boxes // for the different data files. // //#ifdef Q_OS_WIN32 // const QString comboSize(" "); //#else // const QString comboSize(" "); //#endif const int columnWidth = 500; // // Anatomy Selections // volumePrimaryOverlayAnatomyRadioButton = new QRadioButton; grid->addWidget(volumePrimaryOverlayAnatomyRadioButton, rowNumber, PRIMARY_COLUMN, Qt::AlignHCenter); volumePrimaryOverlayButtonGroup->addButton(volumePrimaryOverlayAnatomyRadioButton, BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_ANATOMY); volumeSecondaryOverlayAnatomyRadioButton = new QRadioButton; grid->addWidget(volumeSecondaryOverlayAnatomyRadioButton, rowNumber, SECONDARY_COLUMN, Qt::AlignHCenter); volumeSecondaryOverlayButtonGroup->addButton(volumeSecondaryOverlayAnatomyRadioButton, BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_ANATOMY); volumeUnderlayAnatomyRadioButton = new QRadioButton; grid->addWidget(volumeUnderlayAnatomyRadioButton, rowNumber, UNDERLAY_COLUMN, Qt::AlignHCenter); volumeUnderlayButtonGroup->addButton(volumeUnderlayAnatomyRadioButton, BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_ANATOMY); volumeAnatomyLabel = new QLabel("Anatomy"); grid->addWidget(volumeAnatomyLabel, rowNumber, NAME_COLUMN); volumeAnatomyInfoPushButton = new QPushButton("?"); QSize infoButtonSize = volumeAnatomyInfoPushButton->sizeHint(); infoButtonSize.setWidth(40); volumeAnatomyInfoPushButton->setAutoDefault(false); volumeAnatomyInfoPushButton->setFixedSize(infoButtonSize); grid->addWidget(volumeAnatomyInfoPushButton, rowNumber, INFO_COLUMN); volumeAnatomyInfoPushButton->setToolTip( "Press for Info About Anatomy Volume"); QObject::connect(volumeAnatomyInfoPushButton, SIGNAL(clicked()), this, SLOT(volumeAnatomyInfoPushButtonSelection())); volumeAnatomyMetaDataPushButton = new QPushButton("M"); volumeAnatomyMetaDataPushButton->setAutoDefault(false); volumeAnatomyMetaDataPushButton->setFixedSize(infoButtonSize); grid->addWidget(volumeAnatomyMetaDataPushButton, rowNumber, METADATA_COLUMN); volumeAnatomyMetaDataPushButton->setToolTip( "Press to Edit Anatomy Volume Metadata."); QObject::connect(volumeAnatomyMetaDataPushButton, SIGNAL(clicked()), this, SLOT(volumeAnatomyMetaDataPushButtonSelection())); volumeAnatomyComboBox = new QComboBox; //volumeAnatomyComboBox->insertItem(comboSize); //volumeAnatomyComboBox->setFixedSize(volumeAnatomyComboBox->sizeHint()); volumeAnatomyComboBox->setMinimumWidth(columnWidth); grid->addWidget(volumeAnatomyComboBox, rowNumber, COMBO_COLUMN); volumeAnatomyComboBox->setToolTip( "Choose Anatomy File"); QObject::connect(volumeAnatomyComboBox, SIGNAL(activated(int)), this, SLOT(volumeAnatomySelection(int))); rowNumber++; // // Functional Selections // volumePrimaryOverlayFunctionalRadioButton = new QRadioButton; grid->addWidget(volumePrimaryOverlayFunctionalRadioButton, rowNumber, PRIMARY_COLUMN, Qt::AlignHCenter); volumePrimaryOverlayButtonGroup->addButton(volumePrimaryOverlayFunctionalRadioButton, BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_FUNCTIONAL); volumeSecondaryOverlayFunctionalRadioButton = new QRadioButton; grid->addWidget(volumeSecondaryOverlayFunctionalRadioButton, rowNumber, SECONDARY_COLUMN, Qt::AlignHCenter); volumeSecondaryOverlayButtonGroup->addButton(volumeSecondaryOverlayFunctionalRadioButton, BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_FUNCTIONAL); volumeUnderlayFunctionalRadioButton = new QRadioButton; grid->addWidget(volumeUnderlayFunctionalRadioButton, rowNumber, UNDERLAY_COLUMN, Qt::AlignHCenter); volumeUnderlayButtonGroup->addButton(volumeUnderlayFunctionalRadioButton, BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_FUNCTIONAL); volumeFunctionalViewLabel = new QLabel("Functional-View"); grid->addWidget(volumeFunctionalViewLabel, rowNumber, NAME_COLUMN); volumeFunctionalViewInfoPushButton = new QPushButton("?"); volumeFunctionalViewInfoPushButton->setAutoDefault(false); volumeFunctionalViewInfoPushButton->setFixedSize(infoButtonSize); grid->addWidget(volumeFunctionalViewInfoPushButton, rowNumber, INFO_COLUMN); volumeFunctionalViewInfoPushButton->setToolTip( "Press for Info About Functional View Volume"); QObject::connect(volumeFunctionalViewInfoPushButton, SIGNAL(clicked()), this, SLOT(volumeFunctionalViewInfoPushButtonSelection())); volumeFunctionalViewMetaDataPushButton = new QPushButton("M"); volumeFunctionalViewMetaDataPushButton->setAutoDefault(false); volumeFunctionalViewMetaDataPushButton->setFixedSize(infoButtonSize); grid->addWidget(volumeFunctionalViewMetaDataPushButton, rowNumber, METADATA_COLUMN); volumeFunctionalViewMetaDataPushButton->setToolTip( "Press to Edit Functional-View Volume Metadata."); QObject::connect(volumeFunctionalViewMetaDataPushButton, SIGNAL(clicked()), this, SLOT(volumeFunctionalViewMetaDataPushButtonSelection())); volumeFunctionalViewComboBox = new QComboBox; //volumeFunctionalViewComboBox->insertItem(comboSize); //volumeFunctionalViewComboBox->setFixedSize(volumeFunctionalViewComboBox->sizeHint()); volumeFunctionalViewComboBox->setMinimumWidth(columnWidth); grid->addWidget(volumeFunctionalViewComboBox, rowNumber, COMBO_COLUMN); volumeFunctionalViewComboBox->setToolTip("Choose Functional Viewing Volume"); QObject::connect(volumeFunctionalViewComboBox, SIGNAL(activated(int)), this, SLOT(volumeFunctionalViewSelection(int))); rowNumber++; volumeFunctionalThresholdLabel = new QLabel("Functional-Thresh"); grid->addWidget(volumeFunctionalThresholdLabel, rowNumber, NAME_COLUMN); volumeFunctionalThreshInfoPushButton = new QPushButton("?"); volumeFunctionalThreshInfoPushButton->setAutoDefault(false); volumeFunctionalThreshInfoPushButton->setFixedSize(infoButtonSize); grid->addWidget(volumeFunctionalThreshInfoPushButton, rowNumber, INFO_COLUMN); volumeFunctionalThreshInfoPushButton->setToolTip( "Press for Info About Functional Thresh Volume"); QObject::connect(volumeFunctionalThreshInfoPushButton, SIGNAL(clicked()), this, SLOT(volumeFunctionalThreshInfoPushButtonSelection())); volumeFunctionalThreshMetaDataPushButton = new QPushButton("M"); volumeFunctionalThreshMetaDataPushButton->setAutoDefault(false); volumeFunctionalThreshMetaDataPushButton->setFixedSize(infoButtonSize); grid->addWidget(volumeFunctionalThreshMetaDataPushButton, rowNumber, METADATA_COLUMN); volumeFunctionalThreshMetaDataPushButton->setToolTip( "Press to Edit Functional-Thresh Volume Metadata."); QObject::connect(volumeFunctionalThreshMetaDataPushButton, SIGNAL(clicked()), this, SLOT(volumeFunctionalThreshMetaDataPushButtonSelection())); volumeFunctionalThresholdComboBox = new QComboBox; //volumeFunctionalThresholdComboBox->insertItem(comboSize); //volumeFunctionalThresholdComboBox->setFixedSize(volumeFunctionalThresholdComboBox->sizeHint()); volumeFunctionalThresholdComboBox->setMinimumWidth(columnWidth); grid->addWidget(volumeFunctionalThresholdComboBox, rowNumber, COMBO_COLUMN); volumeFunctionalThresholdComboBox->setToolTip( "Choose Functional Thresholding Volume"); QObject::connect(volumeFunctionalThresholdComboBox, SIGNAL(activated(int)), this, SLOT(volumeFunctionalThresholdSelection(int))); rowNumber++; // // Paint Selections // volumePrimaryOverlayPaintRadioButton = new QRadioButton; grid->addWidget(volumePrimaryOverlayPaintRadioButton, rowNumber, PRIMARY_COLUMN, Qt::AlignHCenter); volumePrimaryOverlayButtonGroup->addButton(volumePrimaryOverlayPaintRadioButton, BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_PAINT); volumeSecondaryOverlayPaintRadioButton = new QRadioButton; grid->addWidget(volumeSecondaryOverlayPaintRadioButton, rowNumber, SECONDARY_COLUMN, Qt::AlignHCenter); volumeSecondaryOverlayButtonGroup->addButton(volumeSecondaryOverlayPaintRadioButton, BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_PAINT); volumeUnderlayPaintRadioButton = new QRadioButton; grid->addWidget(volumeUnderlayPaintRadioButton, rowNumber, UNDERLAY_COLUMN, Qt::AlignHCenter); volumeUnderlayButtonGroup->addButton(volumeUnderlayPaintRadioButton, BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_PAINT); volumePaintLabel = new QLabel("Paint"); grid->addWidget(volumePaintLabel, rowNumber, NAME_COLUMN); volumePaintInfoPushButton = new QPushButton("?"); volumePaintInfoPushButton->setAutoDefault(false); volumePaintInfoPushButton->setFixedSize(infoButtonSize); grid->addWidget(volumePaintInfoPushButton, rowNumber, INFO_COLUMN); volumePaintInfoPushButton->setToolTip( "Press for Info About Paint Volume"); QObject::connect(volumePaintInfoPushButton, SIGNAL(clicked()), this, SLOT(volumePaintInfoPushButtonSelection())); volumePaintMetaDataPushButton = new QPushButton("M"); volumePaintMetaDataPushButton->setAutoDefault(false); volumePaintMetaDataPushButton->setFixedSize(infoButtonSize); grid->addWidget(volumePaintMetaDataPushButton, rowNumber, METADATA_COLUMN); volumePaintMetaDataPushButton->setToolTip( "Press to Edit Paint Volume Metadata."); QObject::connect(volumePaintMetaDataPushButton, SIGNAL(clicked()), this, SLOT(volumePaintMetaDataPushButtonSelection())); volumePaintComboBox = new QComboBox; //volumePaintComboBox->insertItem(comboSize); //volumePaintComboBox->setFixedSize(volumePaintComboBox->sizeHint()); volumePaintComboBox->setMinimumWidth(columnWidth); grid->addWidget(volumePaintComboBox, rowNumber, COMBO_COLUMN); volumePaintComboBox->setToolTip( "Choose Paint Volume"); QObject::connect(volumePaintComboBox, SIGNAL(activated(int)), this, SLOT(volumePaintSelection(int))); rowNumber++; // // Prob atlas Selections // volumePrimaryOverlayProbAtlasRadioButton = new QRadioButton; grid->addWidget(volumePrimaryOverlayProbAtlasRadioButton, rowNumber, PRIMARY_COLUMN, Qt::AlignHCenter); volumePrimaryOverlayButtonGroup->addButton(volumePrimaryOverlayProbAtlasRadioButton, BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_PROB_ATLAS); volumeSecondaryOverlayProbAtlasRadioButton = new QRadioButton; grid->addWidget(volumeSecondaryOverlayProbAtlasRadioButton, rowNumber, SECONDARY_COLUMN, Qt::AlignHCenter); volumeSecondaryOverlayButtonGroup->addButton(volumeSecondaryOverlayProbAtlasRadioButton, BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_PROB_ATLAS); volumeUnderlayProbAtlasRadioButton = new QRadioButton; grid->addWidget(volumeUnderlayProbAtlasRadioButton, rowNumber, UNDERLAY_COLUMN, Qt::AlignHCenter); volumeUnderlayButtonGroup->addButton(volumeUnderlayProbAtlasRadioButton, BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_PROB_ATLAS); volumeProbAtlasLabel = new QLabel("Prob Atlas"); grid->addWidget(volumeProbAtlasLabel, rowNumber, NAME_COLUMN); volumeProbAtlasInfoPushButton = new QPushButton("?"); volumeProbAtlasInfoPushButton->setAutoDefault(false); volumeProbAtlasInfoPushButton->setFixedSize(infoButtonSize); grid->addWidget(volumeProbAtlasInfoPushButton, rowNumber, INFO_COLUMN); volumeProbAtlasInfoPushButton->setToolTip( "Press for Info About Prob Atlas Volume"); QObject::connect(volumeProbAtlasInfoPushButton, SIGNAL(clicked()), this, SLOT(volumeProbAtlasInfoPushButtonSelection())); volumeProbAtlasInfoPushButton->hide(); // LOOK !! BUTTON IS HIDDEN volumeProbAtlasMetaDataPushButton = new QPushButton("M"); volumeProbAtlasMetaDataPushButton->setAutoDefault(false); volumeProbAtlasMetaDataPushButton->setFixedSize(infoButtonSize); grid->addWidget(volumeProbAtlasMetaDataPushButton, rowNumber, METADATA_COLUMN); volumeProbAtlasMetaDataPushButton->setToolTip( "Press to Edit Prob Atlas Volume Metadata."); QObject::connect(volumeProbAtlasMetaDataPushButton, SIGNAL(clicked()), this, SLOT(volumeProbAtlasVolumeStudyMetaDataPushButton())); volumeProbAtlasMetaDataPushButton->hide(); // LOOK !! BUTTON IS HIDDEN // Uses button on Vol-Prob Atlas Main Page rowNumber++; // // RGB Selections // volumePrimaryOverlayRgbRadioButton = new QRadioButton; grid->addWidget(volumePrimaryOverlayRgbRadioButton, rowNumber, PRIMARY_COLUMN, Qt::AlignHCenter); volumePrimaryOverlayButtonGroup->addButton(volumePrimaryOverlayRgbRadioButton, BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_RGB); volumeSecondaryOverlayRgbRadioButton = new QRadioButton; grid->addWidget(volumeSecondaryOverlayRgbRadioButton, rowNumber, SECONDARY_COLUMN, Qt::AlignHCenter); volumeSecondaryOverlayButtonGroup->addButton(volumeSecondaryOverlayRgbRadioButton, BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_RGB); volumeUnderlayRgbRadioButton = new QRadioButton; grid->addWidget(volumeUnderlayRgbRadioButton, rowNumber, UNDERLAY_COLUMN, Qt::AlignHCenter); volumeUnderlayButtonGroup->addButton(volumeUnderlayRgbRadioButton, BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_RGB); volumeRgbLabel = new QLabel("RGB"); grid->addWidget(volumeRgbLabel, rowNumber, NAME_COLUMN); volumeRgbInfoPushButton = new QPushButton("?"); volumeRgbInfoPushButton->setAutoDefault(false); volumeRgbInfoPushButton->setFixedSize(infoButtonSize); grid->addWidget(volumeRgbInfoPushButton, rowNumber, INFO_COLUMN); volumeRgbInfoPushButton->setToolTip( "Press for Info About RGB Volume"); QObject::connect(volumeRgbInfoPushButton, SIGNAL(clicked()), this, SLOT(volumeRgbInfoPushButtonSelection())); volumeRgbMetaDataPushButton = new QPushButton("M"); volumeRgbMetaDataPushButton->setAutoDefault(false); volumeRgbMetaDataPushButton->setFixedSize(infoButtonSize); grid->addWidget(volumeRgbMetaDataPushButton, rowNumber, METADATA_COLUMN); volumeRgbMetaDataPushButton->setToolTip( "Press to Edit RGB Volume Metadata."); QObject::connect(volumeRgbMetaDataPushButton, SIGNAL(clicked()), this, SLOT(volumeRgbMetaDataPushButtonSelection())); volumeRgbComboBox = new QComboBox; //volumeRgbComboBox->insertItem(comboSize); //volumeRgbComboBox->setFixedSize(volumeRgbComboBox->sizeHint()); volumeRgbComboBox->setMinimumWidth(columnWidth); grid->addWidget(volumeRgbComboBox, rowNumber, COMBO_COLUMN); volumeRgbComboBox->setToolTip( "Choose RGB Volume"); QObject::connect(volumeRgbComboBox, SIGNAL(activated(int)), this, SLOT(volumeRgbSelection(int))); rowNumber++; // // Segmentation Selections // volumePrimaryOverlaySegmentationRadioButton = new QRadioButton; grid->addWidget(volumePrimaryOverlaySegmentationRadioButton, rowNumber, PRIMARY_COLUMN, Qt::AlignHCenter); volumePrimaryOverlayButtonGroup->addButton(volumePrimaryOverlaySegmentationRadioButton, BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_SEGMENTATION); volumeSecondaryOverlaySegmentationRadioButton = new QRadioButton; grid->addWidget(volumeSecondaryOverlaySegmentationRadioButton, rowNumber, SECONDARY_COLUMN, Qt::AlignHCenter); volumeSecondaryOverlayButtonGroup->addButton(volumeSecondaryOverlaySegmentationRadioButton, BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_SEGMENTATION); volumeUnderlaySegmentationRadioButton = new QRadioButton; grid->addWidget(volumeUnderlaySegmentationRadioButton, rowNumber, UNDERLAY_COLUMN, Qt::AlignHCenter); volumeUnderlayButtonGroup->addButton(volumeUnderlaySegmentationRadioButton, BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_SEGMENTATION); volumeSegmentationLabel = new QLabel("Segmentation"); grid->addWidget(volumeSegmentationLabel, rowNumber, NAME_COLUMN); volumeSegmentationInfoPushButton = new QPushButton("?"); volumeSegmentationInfoPushButton->setAutoDefault(false); volumeSegmentationInfoPushButton->setFixedSize(infoButtonSize); grid->addWidget(volumeSegmentationInfoPushButton, rowNumber, INFO_COLUMN); volumeSegmentationInfoPushButton->setToolTip( "Press for Info About Segmentation Volume"); QObject::connect(volumeSegmentationInfoPushButton, SIGNAL(clicked()), this, SLOT(volumeSegmentationInfoPushButtonSelection())); volumeSegmentationMetaDataPushButton = new QPushButton("M"); volumeSegmentationMetaDataPushButton->setAutoDefault(false); volumeSegmentationMetaDataPushButton->setFixedSize(infoButtonSize); grid->addWidget(volumeSegmentationMetaDataPushButton, rowNumber, METADATA_COLUMN); volumeSegmentationMetaDataPushButton->setToolTip( "Press to Edit Segmentation Volume Metadata."); QObject::connect(volumeSegmentationMetaDataPushButton, SIGNAL(clicked()), this, SLOT(volumeSegmentationMetaDataPushButtonSelection())); volumeSegmentationComboBox = new QComboBox; volumeSegmentationComboBox->setMinimumWidth(columnWidth); grid->addWidget(volumeSegmentationComboBox, rowNumber, COMBO_COLUMN); volumeSegmentationComboBox->setToolTip( "Choose Segmentation Volume"); QObject::connect(volumeSegmentationComboBox, SIGNAL(activated(int)), this, SLOT(volumeSegmentationSelection(int))); rowNumber++; // // Vector Selections // volumePrimaryOverlayVectorRadioButton = new QRadioButton; grid->addWidget(volumePrimaryOverlayVectorRadioButton, rowNumber, PRIMARY_COLUMN, Qt::AlignHCenter); volumePrimaryOverlayButtonGroup->addButton(volumePrimaryOverlayVectorRadioButton, BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_VECTOR); volumeSecondaryOverlayVectorRadioButton = new QRadioButton; grid->addWidget(volumeSecondaryOverlayVectorRadioButton, rowNumber, SECONDARY_COLUMN, Qt::AlignHCenter); volumeSecondaryOverlayButtonGroup->addButton(volumeSecondaryOverlayVectorRadioButton, BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_VECTOR); volumeUnderlayVectorRadioButton = new QRadioButton; grid->addWidget(volumeUnderlayVectorRadioButton, rowNumber, UNDERLAY_COLUMN, Qt::AlignHCenter); volumeUnderlayButtonGroup->addButton(volumeUnderlayVectorRadioButton, BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_VECTOR); volumeVectorLabel = new QLabel("Vector"); grid->addWidget(volumeVectorLabel, rowNumber, NAME_COLUMN); volumeVectorInfoPushButton = new QPushButton("?"); volumeVectorInfoPushButton->setAutoDefault(false); volumeVectorInfoPushButton->setFixedSize(infoButtonSize); grid->addWidget(volumeVectorInfoPushButton, rowNumber, INFO_COLUMN); volumeVectorInfoPushButton->setToolTip( "Press for Info About Vector Volume"); QObject::connect(volumeVectorInfoPushButton, SIGNAL(clicked()), this, SLOT(volumeVectorInfoPushButtonSelection())); volumeVectorMetaDataPushButton = new QPushButton("M"); volumeVectorMetaDataPushButton->setAutoDefault(false); volumeVectorMetaDataPushButton->setFixedSize(infoButtonSize); grid->addWidget(volumeVectorMetaDataPushButton, rowNumber, METADATA_COLUMN); volumeVectorMetaDataPushButton->setToolTip( "Press to Edit Vector Volume Metadata."); QObject::connect(volumeVectorMetaDataPushButton, SIGNAL(clicked()), this, SLOT(volumeVectorMetaDataPushButtonSelection())); volumeVectorComboBox = new QComboBox; volumeVectorComboBox->setMinimumWidth(columnWidth); grid->addWidget(volumeVectorComboBox, rowNumber, COMBO_COLUMN); volumeVectorComboBox->setToolTip( "Choose Vector Volume"); QObject::connect(volumeVectorComboBox, SIGNAL(activated(int)), this, SLOT(volumeVectorSelection(int))); rowNumber++; uoGroup->setFixedSize(uoGroup->sizeHint()); // // Pushes selections to top of page // volSelLayout->addStretch(); //volSelQVBox->setStretchFactor(new QLabel(" ", volSelQVBox), 100); pageVolumeSelection = volSelQVBox; pageWidgetStack->addWidget(pageVolumeSelection); } /** * create the overlay underlay volume setttings page. */ void GuiDisplayControlDialog::createOverlayUnderlayVolumeSettingsPage() { // // Anatomy draw type // QHBoxLayout* anatomyDrawBoxLayout = new QHBoxLayout; anatomyDrawBoxLayout->addWidget(new QLabel("Draw Type ")); volumeAnatomyDrawTypeComboBox = new QComboBox; anatomyDrawBoxLayout->addWidget(volumeAnatomyDrawTypeComboBox); volumeAnatomyDrawTypeComboBox->setToolTip( "0 to 255: \n" " Assumes voxels are within 0 to 255.\n" "Min to Max\n" " Maps smallest voxel to black and\n" " the largest voxel to white.\n" "2% to 98%\n" " Computes histogram of voxels.\n" " Voxels at 2% in histogram are mapped\n" " to black. Voxels at 98% in histogram\n" " are mapped to white.\n"); volumeAnatomyDrawTypeComboBox->insertItem(DisplaySettingsVolume::ANATOMY_COLORING_TYPE_0_255, "0 to 255"); volumeAnatomyDrawTypeComboBox->insertItem(DisplaySettingsVolume::ANATOMY_COLORING_TYPE_MIN_MAX, "Min to Max"); volumeAnatomyDrawTypeComboBox->insertItem(DisplaySettingsVolume::ANATOMY_COLORING_TYPE_2_98, "2% to 98%"); QObject::connect(volumeAnatomyDrawTypeComboBox, SIGNAL(activated(int)), this, SLOT(readVolumeSettings())); anatomyDrawBoxLayout->addStretch(); // // Brighness/Contrast // QLabel* brightnessLabel = new QLabel("Brightness "); volumeAnatomyBrightnessLabel = new QLabel(" "); volumeAnatomyBrightnessLabel->setFixedSize(volumeAnatomyBrightnessLabel->sizeHint()); volumeAnatomyBrightnessSlider = new QSlider(Qt::Horizontal); volumeAnatomyBrightnessSlider->setMinimum(-150); volumeAnatomyBrightnessSlider->setMaximum(150); volumeAnatomyBrightnessSlider->setPageStep(1); volumeAnatomyBrightnessSlider->setValue(1); volumeAnatomyBrightnessSlider->setFixedWidth(251); QObject::connect(volumeAnatomyBrightnessSlider, SIGNAL(sliderReleased()), this, SLOT(readVolumeSettings())); QObject::connect(volumeAnatomyBrightnessSlider, SIGNAL(sliderMoved(int)), volumeAnatomyBrightnessLabel, SLOT(setNum(int))); QLabel* contrastLabel = new QLabel("Contrast "); volumeAnatomyContrastLabel = new QLabel(" "); volumeAnatomyContrastLabel->setFixedSize(volumeAnatomyContrastLabel->sizeHint()); volumeAnatomyContrastSlider = new QSlider(Qt::Horizontal); volumeAnatomyContrastSlider->setMinimum(-99); volumeAnatomyContrastSlider->setMaximum(99); volumeAnatomyContrastSlider->setPageStep(1); volumeAnatomyContrastSlider->setValue(1); volumeAnatomyContrastSlider->setFixedWidth(251); QObject::connect(volumeAnatomyContrastSlider, SIGNAL(sliderReleased()), this, SLOT(readVolumeSettings())); QObject::connect(volumeAnatomyContrastSlider, SIGNAL(sliderMoved(int)), volumeAnatomyContrastLabel, SLOT(setNum(int))); QGridLayout* brightContrastGridLayout = new QGridLayout; brightContrastGridLayout->addWidget(brightnessLabel, 0, 0); brightContrastGridLayout->addWidget(volumeAnatomyBrightnessLabel, 0, 1); brightContrastGridLayout->addWidget(volumeAnatomyBrightnessSlider, 0, 2); brightContrastGridLayout->addWidget(contrastLabel, 1, 0); brightContrastGridLayout->addWidget(volumeAnatomyContrastLabel, 1, 1); brightContrastGridLayout->addWidget(volumeAnatomyContrastSlider, 1, 2); QPushButton* makeDefaultPushButton = new QPushButton("Make Default"); makeDefaultPushButton->setAutoDefault(false); makeDefaultPushButton->setFixedSize(makeDefaultPushButton->sizeHint()); makeDefaultPushButton->setToolTip( "Set default brightness/contrast\n" "to current entries."); QObject::connect(makeDefaultPushButton, SIGNAL(clicked()), this, SLOT(slotDefaultVolumeContrastBrightness())); QPushButton* histoPushButton = new QPushButton("Histogram..."); histoPushButton->setAutoDefault(false); histoPushButton->setFixedSize(histoPushButton->sizeHint()); QObject::connect(histoPushButton, SIGNAL(clicked()), this, SLOT(slotAnatomyVolumeHistogram())); QHBoxLayout* anatButtonLayout = new QHBoxLayout; anatButtonLayout->addWidget(makeDefaultPushButton); anatButtonLayout->addWidget(histoPushButton); // // Anatomy group box // QGroupBox* anatomyGroupBox = new QGroupBox("Anatomy Volume"); QVBoxLayout* anatomyGroupLayout = new QVBoxLayout(anatomyGroupBox); anatomyGroupLayout->addLayout(anatomyDrawBoxLayout); anatomyGroupLayout->addLayout(brightContrastGridLayout); anatomyGroupLayout->addLayout(anatButtonLayout); anatomyGroupBox->setFixedSize(anatomyGroupBox->sizeHint()); // // Display color bar check box // volumeFunctionalDisplayColorBarCheckBox = new QCheckBox("Display Color Bar"); QObject::connect(volumeFunctionalDisplayColorBarCheckBox, SIGNAL(toggled(bool)), this, SLOT(readVolumeSettings())); // // Functional volume group box // QGroupBox* functionalGroupBox = new QGroupBox("Functional Volume"); QVBoxLayout* functionalGroupLayout = new QVBoxLayout(functionalGroupBox); functionalGroupLayout->addWidget(volumeFunctionalDisplayColorBarCheckBox); functionalGroupBox->setFixedSize(functionalGroupBox->sizeHint()); // // Segmenation Volume draw type // volumeSegmentationDrawTypeComboBox = new QComboBox; volumeSegmentationDrawTypeComboBox->insertItem(DisplaySettingsVolume::SEGMENTATION_DRAW_TYPE_BLEND, "Translucent"); volumeSegmentationDrawTypeComboBox->insertItem(DisplaySettingsVolume::SEGMENTATION_DRAW_TYPE_SOLID, "Opaque"); volumeSegmentationDrawTypeComboBox->insertItem(DisplaySettingsVolume::SEGMENTATION_DRAW_TYPE_BOX, "Outline"); volumeSegmentationDrawTypeComboBox->insertItem(DisplaySettingsVolume::SEGMENTATION_DRAW_TYPE_CROSS, "Cross"); QObject::connect(volumeSegmentationDrawTypeComboBox, SIGNAL(activated(int)), this, SLOT(readVolumeSettings())); volumeSegmentationDrawTypeComboBox->setToolTip( "Selects drawing method \n" "for segmentation voxels."); // // Segmentation Volume Translucency // QHBoxLayout* segTransHBoxLayout = new QHBoxLayout; segTransHBoxLayout->addWidget(new QLabel("Translucency")); volumeSegmentationTranslucencyDoubleSpinBox = new QDoubleSpinBox; volumeSegmentationTranslucencyDoubleSpinBox->setMinimum(0.0); volumeSegmentationTranslucencyDoubleSpinBox->setMaximum(1.0); volumeSegmentationTranslucencyDoubleSpinBox->setSingleStep(0.1); volumeSegmentationTranslucencyDoubleSpinBox->setDecimals(2); segTransHBoxLayout->addWidget(volumeSegmentationTranslucencyDoubleSpinBox); QObject::connect(volumeSegmentationTranslucencyDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readVolumeSettings())); // // Segmentation group box // QGroupBox* segmentGroupBox = new QGroupBox("Segmentation Volume"); QVBoxLayout* segmentGroupLayout = new QVBoxLayout(segmentGroupBox); segmentGroupLayout->addWidget(volumeSegmentationDrawTypeComboBox); segmentGroupLayout->addLayout(segTransHBoxLayout); segmentGroupBox->setFixedSize(segmentGroupBox->sizeHint()); // // Overlay opacity // volumeOverlayOpacityDoubleSpinBox = new QDoubleSpinBox; volumeOverlayOpacityDoubleSpinBox->setMinimum(0.0); volumeOverlayOpacityDoubleSpinBox->setMaximum(1.0); volumeOverlayOpacityDoubleSpinBox->setSingleStep(0.1); volumeOverlayOpacityDoubleSpinBox->setDecimals(2); volumeOverlayOpacityDoubleSpinBox->setToolTip( "Values less than 1.0 will blend\n" "the overlay and the underlay."); QObject::connect(volumeOverlayOpacityDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readVolumeSettings())); QGroupBox* overlayOpacityGroupBox = new QGroupBox("Overlay Opacity"); QVBoxLayout* overlayOpacityGroupLayout = new QVBoxLayout(overlayOpacityGroupBox); overlayOpacityGroupLayout->addWidget(volumeOverlayOpacityDoubleSpinBox); overlayOpacityGroupBox->setFixedSize(overlayOpacityGroupBox->sizeHint()); // // start button // QPushButton* animateStartPushButton = new QPushButton("Start"); animateStartPushButton->setFixedSize(animateStartPushButton->sizeHint()); animateStartPushButton->setAutoDefault(false); QObject::connect(animateStartPushButton, SIGNAL(clicked()), this, SLOT(slotVolumeAnimateStartPushButton())); // // stop button // QPushButton* animateStopPushButton = new QPushButton("Stop"); animateStopPushButton->setFixedSize(animateStopPushButton->sizeHint()); animateStopPushButton->setAutoDefault(false); QObject::connect(animateStopPushButton, SIGNAL(clicked()), this, SLOT(slotVolumeAnimateStopPushButton())); // // Horizontal box for direction // QLabel* volumeAnimateDirectionLabel = new QLabel("Direction "); volumeAnimateDirectionComboBox = new QComboBox; volumeAnimateDirectionComboBox->insertItem(VOLUME_ANIMATE_DIRECTION_INCREMENT, "Positive"); volumeAnimateDirectionComboBox->insertItem(VOLUME_ANIMATE_DIRECTION_DECREMENT, "Negative"); QHBoxLayout* animateDirectionLayout = new QHBoxLayout; animateDirectionLayout->addWidget(volumeAnimateDirectionLabel); animateDirectionLayout->addWidget(volumeAnimateDirectionComboBox); animateDirectionLayout->addStretch(); // // Animation section // QGroupBox* animateGroupBox = new QGroupBox("Animation"); QVBoxLayout* animateGroupLayout = new QVBoxLayout(animateGroupBox); animateGroupLayout->addWidget(animateStartPushButton); animateGroupLayout->addWidget(animateStopPushButton); animateGroupLayout->addLayout(animateDirectionLayout); animateGroupBox->setFixedSize(animateGroupBox->sizeHint()); // // paint color key button // QPushButton* paintColorKeyPushButton = new QPushButton("Paint Color Key..."); paintColorKeyPushButton->setFixedSize(paintColorKeyPushButton->sizeHint()); paintColorKeyPushButton->setAutoDefault(false); QObject::connect(paintColorKeyPushButton, SIGNAL(clicked()), theMainWindow, SLOT(displayVolumePaintColorKey())); // // prob atlas color key button // QPushButton* probAtlasColorKeyPushButton = new QPushButton("Prob Atlas Color Key..."); probAtlasColorKeyPushButton->setFixedSize(probAtlasColorKeyPushButton->sizeHint()); probAtlasColorKeyPushButton->setAutoDefault(false); QObject::connect(probAtlasColorKeyPushButton, SIGNAL(clicked()), theMainWindow, SLOT(displayVolumeProbabilisticAtlasColorKey())); // // Color Key buttons // QGroupBox* colorKeyGroupBox = new QGroupBox("Color Keys"); QVBoxLayout* colorKeyLayout = new QVBoxLayout(colorKeyGroupBox); colorKeyLayout->addWidget(paintColorKeyPushButton); colorKeyLayout->addWidget(probAtlasColorKeyPushButton); colorKeyGroupBox->setFixedSize(colorKeyGroupBox->sizeHint()); // // Sparsity spin box // QLabel* sparsityLabel = new QLabel("Sparsity "); vectorVolumeSparsitySpinBox = new QSpinBox; vectorVolumeSparsitySpinBox->setMinimum(1); vectorVolumeSparsitySpinBox->setMaximum(100000); vectorVolumeSparsitySpinBox->setSingleStep(1); vectorVolumeSparsitySpinBox->setToolTip( "Draw Vectors for\n" "Every N Voxels"); QObject::connect(vectorVolumeSparsitySpinBox, SIGNAL(valueChanged(int)), this, SLOT(readVolumeSettings())); // // vector volume group box // vectorVolumeGroupBox = new QGroupBox("Vector Volume"); QHBoxLayout* vectorVolumeGroupLayout = new QHBoxLayout(vectorVolumeGroupBox); vectorVolumeGroupLayout->addWidget(sparsityLabel); vectorVolumeGroupLayout->addWidget(vectorVolumeSparsitySpinBox); vectorVolumeGroupBox->setFixedSize(vectorVolumeGroupBox->sizeHint()); // // montage rows spin box // QLabel* montageRowsLabel = new QLabel("Rows"); volumeMontageRowsSpinBox = new QSpinBox; volumeMontageRowsSpinBox->setMinimum(1); volumeMontageRowsSpinBox->setMaximum(100); volumeMontageRowsSpinBox->setSingleStep(1); volumeMontageRowsSpinBox->setToolTip( "Number of rows in\n" "the montage."); QObject::connect(volumeMontageRowsSpinBox, SIGNAL(valueChanged(int)), this, SLOT(readVolumeSettings())); // // columns spin box // QLabel* montageColumnsLabel = new QLabel("Columns"); volumeMontageColumnsSpinBox = new QSpinBox; volumeMontageColumnsSpinBox->setMinimum(1); volumeMontageColumnsSpinBox->setMaximum(100); volumeMontageColumnsSpinBox->setSingleStep(1); volumeMontageColumnsSpinBox->setToolTip( "Number of columns\n" "in the montage."); QObject::connect(volumeMontageColumnsSpinBox, SIGNAL(valueChanged(int)), this, SLOT(readVolumeSettings())); // // slices spin box // QLabel* montageIncrementLabel = new QLabel("Increment"); volumeMontageSliceIncrementSpinBox = new QSpinBox; volumeMontageSliceIncrementSpinBox->setMinimum(1); volumeMontageSliceIncrementSpinBox->setMaximum(100); volumeMontageSliceIncrementSpinBox->setSingleStep(1); volumeMontageSliceIncrementSpinBox->setToolTip( "Slices to skip between\n" "each montage image."); QObject::connect(volumeMontageSliceIncrementSpinBox, SIGNAL(valueChanged(int)), this, SLOT(readVolumeSettings())); // // Montage group box // volumeMontageGroupBox = new QGroupBox("Montage"); volumeMontageGroupBox->setCheckable(true); QObject::connect(volumeMontageGroupBox, SIGNAL(toggled(bool)), this, SLOT(readVolumeSettings())); QGridLayout* volumeMontageGroupLayout = new QGridLayout(volumeMontageGroupBox); volumeMontageGroupLayout->addWidget(montageRowsLabel, 0, 0); volumeMontageGroupLayout->addWidget(volumeMontageRowsSpinBox, 0, 1); volumeMontageGroupLayout->addWidget(montageColumnsLabel, 1, 0); volumeMontageGroupLayout->addWidget(volumeMontageColumnsSpinBox, 1, 1); volumeMontageGroupLayout->addWidget(montageIncrementLabel, 2, 0); volumeMontageGroupLayout->addWidget(volumeMontageSliceIncrementSpinBox, 2, 1); volumeMontageGroupBox->setFixedSize(volumeMontageGroupBox->sizeHint()); // // Show crosshairs check box // volumeShowCrosshairsCheckBox = new QCheckBox("Show Crosshairs"); QObject::connect(volumeShowCrosshairsCheckBox, SIGNAL(toggled(bool)), this, SLOT(readVolumeSettings())); // // Show crosshair coordinates check box // volumeShowCrosshairCoordinatesCheckBox = new QCheckBox("Show Crosshair Coordinates"); QObject::connect(volumeShowCrosshairCoordinatesCheckBox, SIGNAL(toggled(bool)), this, SLOT(readVolumeSettings())); // // crosshairs group box // QGroupBox* crosshairsGroupBox = new QGroupBox("Crosshairs"); QVBoxLayout* crosshairsGroupLayout = new QVBoxLayout(crosshairsGroupBox); crosshairsGroupLayout->addWidget(volumeShowCrosshairsCheckBox); crosshairsGroupLayout->addWidget(volumeShowCrosshairCoordinatesCheckBox); crosshairsGroupBox->setFixedSize(crosshairsGroupBox->sizeHint()); // // Oblique slice viewing // QLabel* obliqueViewLabel = new QLabel("View Matrix"); obliqueVolumeSliceMatrixControl = new GuiTransformationMatrixSelectionControl( 0, theMainWindow->getBrainSet()->getTransformationMatrixFile(), true); obliqueVolumeSliceMatrixControl->setNoneLabel("Main Window Oblique View Matrix"); QObject::connect(obliqueVolumeSliceMatrixControl, SIGNAL(activated(int)), this, SLOT(readVolumeSettings())); QLabel* obliqueSampleLabel = new QLabel("Slice Sampling"); obliqueSlicesSamplingSizeDoubleSpinBox = new QDoubleSpinBox; obliqueSlicesSamplingSizeDoubleSpinBox->setMinimum(0.01); obliqueSlicesSamplingSizeDoubleSpinBox->setMaximum(100.0); obliqueSlicesSamplingSizeDoubleSpinBox->setSingleStep(0.1); obliqueSlicesSamplingSizeDoubleSpinBox->setDecimals(2); QObject::connect(obliqueSlicesSamplingSizeDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readVolumeSettings())); // Oblique View Matrix Selection // QGroupBox* obliqueGroupBox = new QGroupBox("Oblique Slices Viewing"); QGridLayout* obliqueViewGrid = new QGridLayout(obliqueGroupBox); obliqueViewGrid->addWidget(obliqueViewLabel, 0, 0, Qt::AlignLeft); obliqueViewGrid->addWidget(obliqueVolumeSliceMatrixControl, 0, 1, Qt::AlignLeft); obliqueViewGrid->addWidget(obliqueSampleLabel, 1, 0, Qt::AlignLeft); obliqueViewGrid->addWidget(obliqueSlicesSamplingSizeDoubleSpinBox, 1, 1, Qt::AlignLeft); obliqueGroupBox->setFixedSize(obliqueGroupBox->sizeHint()); // // Left column layout // QVBoxLayout* leftLayout = new QVBoxLayout; leftLayout->addWidget(functionalGroupBox); leftLayout->addWidget(segmentGroupBox); leftLayout->addWidget(colorKeyGroupBox); leftLayout->addWidget(animateGroupBox); // // Right column layout // QVBoxLayout* rightLayout = new QVBoxLayout; rightLayout->addWidget(volumeMontageGroupBox); rightLayout->addWidget(overlayOpacityGroupBox); rightLayout->addWidget(crosshairsGroupBox); rightLayout->addWidget(vectorVolumeGroupBox); // // left and right columns layout // QHBoxLayout* columnsLayout = new QHBoxLayout; columnsLayout->addLayout(leftLayout); columnsLayout->addLayout(rightLayout); columnsLayout->addStretch(); // // The volume page and layout // QWidget* volumeSettingsWidget = new QWidget; QVBoxLayout* volumeSettingsLayout = new QVBoxLayout(volumeSettingsWidget); volumeSettingsLayout->addWidget(anatomyGroupBox); volumeSettingsLayout->addWidget(obliqueGroupBox); volumeSettingsLayout->addLayout(columnsLayout); volumeSettingsWidget->setFixedHeight(volumeSettingsWidget->sizeHint().height()); pageVolumeSettings = volumeSettingsWidget; pageWidgetStack->addWidget(pageVolumeSettings); pageVolumeSettingsWidgetGroup = new WuQWidgetGroup(this); pageVolumeSettingsWidgetGroup->addWidget(volumeAnatomyDrawTypeComboBox); pageVolumeSettingsWidgetGroup->addWidget(volumeAnatomyBrightnessSlider); pageVolumeSettingsWidgetGroup->addWidget(volumeAnatomyContrastSlider); pageVolumeSettingsWidgetGroup->addWidget(volumeFunctionalDisplayColorBarCheckBox); pageVolumeSettingsWidgetGroup->addWidget(volumeSegmentationDrawTypeComboBox); pageVolumeSettingsWidgetGroup->addWidget(volumeSegmentationTranslucencyDoubleSpinBox); pageVolumeSettingsWidgetGroup->addWidget(volumeOverlayOpacityDoubleSpinBox); pageVolumeSettingsWidgetGroup->addWidget(vectorVolumeSparsitySpinBox); pageVolumeSettingsWidgetGroup->addWidget(volumeMontageGroupBox); pageVolumeSettingsWidgetGroup->addWidget(volumeMontageRowsSpinBox); pageVolumeSettingsWidgetGroup->addWidget(volumeMontageColumnsSpinBox); pageVolumeSettingsWidgetGroup->addWidget(volumeMontageSliceIncrementSpinBox); pageVolumeSettingsWidgetGroup->addWidget(volumeShowCrosshairsCheckBox); pageVolumeSettingsWidgetGroup->addWidget(volumeShowCrosshairCoordinatesCheckBox); pageVolumeSettingsWidgetGroup->addWidget(obliqueVolumeSliceMatrixControl); pageVolumeSettingsWidgetGroup->addWidget(obliqueSlicesSamplingSizeDoubleSpinBox); } /** * create the overlay underlay volume surface outline page. */ void GuiDisplayControlDialog::createOverlayUnderlayVolumeSurfaceOutlinePage() { pageVolumeSurfaceOutlineWidgetGroup = new WuQWidgetGroup(this); // // outline for fiducial surface Color combo box // for (int i = 0; i < DisplaySettingsVolume::MAXIMUM_OVERLAY_SURFACES; i++) { volumeOverlaySurfaceOutlineColorComboBox[i] = new QComboBox; volumeOverlaySurfaceOutlineColorComboBox[i]->insertItem(DisplaySettingsVolume::SURFACE_OUTLINE_COLOR_BLACK, "Black"); volumeOverlaySurfaceOutlineColorComboBox[i]->insertItem(DisplaySettingsVolume::SURFACE_OUTLINE_COLOR_BLUE, "Blue"); volumeOverlaySurfaceOutlineColorComboBox[i]->insertItem(DisplaySettingsVolume::SURFACE_OUTLINE_COLOR_GREEN, "Green"); volumeOverlaySurfaceOutlineColorComboBox[i]->insertItem(DisplaySettingsVolume::SURFACE_OUTLINE_COLOR_RED, "Red"); volumeOverlaySurfaceOutlineColorComboBox[i]->insertItem(DisplaySettingsVolume::SURFACE_OUTLINE_COLOR_WHITE, "White"); QObject::connect(volumeOverlaySurfaceOutlineColorComboBox[i], SIGNAL(activated(int)), this, SLOT(readVolumeSurfaceOutline())); pageVolumeSurfaceOutlineWidgetGroup->addWidget(volumeOverlaySurfaceOutlineColorComboBox[i]); // // Fiducial Thickness float spin box // volumeOverlaySurfaceOutlineThicknessDoubleSpinBox[i] = new QDoubleSpinBox; volumeOverlaySurfaceOutlineThicknessDoubleSpinBox[i]->setMinimum(0.0); volumeOverlaySurfaceOutlineThicknessDoubleSpinBox[i]->setMaximum(1000.0); volumeOverlaySurfaceOutlineThicknessDoubleSpinBox[i]->setSingleStep(0.1); volumeOverlaySurfaceOutlineThicknessDoubleSpinBox[i]->setDecimals(2); QObject::connect(volumeOverlaySurfaceOutlineThicknessDoubleSpinBox[i], SIGNAL(valueChanged(double)), this, SLOT(readVolumeSurfaceOutline())); pageVolumeSurfaceOutlineWidgetGroup->addWidget(volumeOverlaySurfaceOutlineThicknessDoubleSpinBox[i]); // // Show fiducial surface outline check box // volumeShowOverlaySurfaceOutlineCheckBox[i] = new QCheckBox(""); QObject::connect(volumeShowOverlaySurfaceOutlineCheckBox[i], SIGNAL(toggled(bool)), this, SLOT(readVolumeSurfaceOutline())); pageVolumeSurfaceOutlineWidgetGroup->addWidget(volumeShowOverlaySurfaceOutlineCheckBox[i]); // // overlay surface selection // if (i > 0) { volumeOverlaySurfaceSelectionComboBox[i] = new GuiBrainModelSelectionComboBox(false, true, false, ""); QObject::connect(volumeOverlaySurfaceSelectionComboBox[i], SIGNAL(activated(int)), this, SLOT(readVolumeSurfaceOutline())); pageVolumeSurfaceOutlineWidgetGroup->addWidget(volumeOverlaySurfaceSelectionComboBox[i]); } else { volumeOverlaySurfaceSelectionComboBox[i] = NULL; } } // // Surface outline section // QGroupBox* volumeShowSurfaceOutlineGroupBox = new QGroupBox("Surface Outline"); QObject::connect(volumeShowSurfaceOutlineGroupBox, SIGNAL(toggled(bool)), this, SLOT(readVolumeSurfaceOutline())); QGridLayout* volumeShowSurfaceOutlineGroupLayout = new QGridLayout(volumeShowSurfaceOutlineGroupBox); volumeShowSurfaceOutlineGroupLayout->addWidget(new QLabel("Show"), 0, 0); volumeShowSurfaceOutlineGroupLayout->addWidget(new QLabel("Color"), 0, 1); volumeShowSurfaceOutlineGroupLayout->addWidget(new QLabel("Thickness"), 0, 2); volumeShowSurfaceOutlineGroupLayout->addWidget(new QLabel("Surface"), 0, 3); for (int i = 0; i < DisplaySettingsVolume::MAXIMUM_OVERLAY_SURFACES; i++) { volumeShowSurfaceOutlineGroupLayout->addWidget(volumeShowOverlaySurfaceOutlineCheckBox[i], i+1, 0); volumeShowSurfaceOutlineGroupLayout->addWidget(volumeOverlaySurfaceOutlineColorComboBox[i], i+1, 1); volumeShowSurfaceOutlineGroupLayout->addWidget(volumeOverlaySurfaceOutlineThicknessDoubleSpinBox[i], i+1, 2); if (i > 0) { volumeShowSurfaceOutlineGroupLayout->addWidget(volumeOverlaySurfaceSelectionComboBox[i]); } else { volumeShowSurfaceOutlineGroupLayout->addWidget(new QLabel("Active Fiducial Surface")); } // // Connect some signals // //QObject::connect(volumeShowOverlaySurfaceOutlineCheckBox[i], SIGNAL(toggled(bool)), // volumeOverlaySurfaceOutlineColorComboBox[i], SLOT(setEnabled(bool))); //QObject::connect(volumeShowOverlaySurfaceOutlineCheckBox[i], SIGNAL(toggled(bool)), // volumeOverlaySurfaceOutlineThicknessDoubleSpinBox[i], SLOT(setEnabled(bool))); if (i > 0) { //QObject::connect(volumeShowOverlaySurfaceOutlineCheckBox[i], SIGNAL(toggled(bool)), // volumeOverlaySurfaceSelectionComboBox[i], SLOT(setEnabled(bool))); } } volumeShowSurfaceOutlineGroupLayout->setColumnStretch(0, 0); volumeShowSurfaceOutlineGroupLayout->setColumnStretch(1, 0); volumeShowSurfaceOutlineGroupLayout->setColumnStretch(2, 0); volumeShowSurfaceOutlineGroupLayout->setColumnStretch(3, 100); volumeShowSurfaceOutlineGroupBox->setFixedHeight(volumeShowSurfaceOutlineGroupBox->sizeHint().height()); QWidget* volumeSurfaceOutlineWidget = new QWidget; QVBoxLayout* volumeSurfaceOutlineLayout = new QVBoxLayout(volumeSurfaceOutlineWidget); volumeSurfaceOutlineLayout->addWidget(volumeShowSurfaceOutlineGroupBox); volumeSurfaceOutlineWidget->setFixedHeight(volumeSurfaceOutlineWidget->sizeHint().height()); pageVolumeSurfaceOutline = volumeSurfaceOutlineWidget; pageWidgetStack->addWidget(pageVolumeSurfaceOutline); } /** * Called to use current brightness/contrast default for anatomy volume. */ void GuiDisplayControlDialog::slotDefaultVolumeContrastBrightness() { PreferencesFile* pf = BrainSet::getPreferencesFile(); pf->setAnatomyVolumeBrightness(volumeAnatomyBrightnessSlider->value()); pf->setAnatomyVolumeContrast(volumeAnatomyContrastSlider->value()); try { if (pf->getFileName().isEmpty() == false) { pf->writeFile(pf->getFileName()); } } catch (FileException& /*e*/) { } } /** * Called to start the volume animation. */ void GuiDisplayControlDialog::slotVolumeAnimateStartPushButton() { // // Make sure there is a brain model volume in the main window // BrainModelVolume* bmv = theMainWindow->getBrainModelVolume(); if (bmv == NULL) { QMessageBox::warning(this, "No Volume in Main Window", "There must be a volume slice displayed in the main window"); return; } // // Find number of slices to animate through // const VolumeFile::VOLUME_AXIS axis = bmv->getSelectedAxis(0); int firstSlice = 0; int lastSlice = 0; int sliceIndex = -1; switch(axis) { case VolumeFile::VOLUME_AXIS_X: sliceIndex = 0; break; case VolumeFile::VOLUME_AXIS_Y: sliceIndex = 1; break; case VolumeFile::VOLUME_AXIS_Z: sliceIndex = 2; break; case VolumeFile::VOLUME_AXIS_ALL: case VolumeFile::VOLUME_AXIS_OBLIQUE: case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: case VolumeFile::VOLUME_AXIS_UNKNOWN: QMessageBox::critical(this, "ERROR", "Animation of all or oblique slices not supported."); return; break; } // // Get the volume file // VolumeFile* vf = bmv->getMasterVolumeFile(); if (vf != NULL) { // // Enable the animation // // // Get the main windows OpenGL widget // GuiBrainModelOpenGL* openGL = theMainWindow->getBrainModelOpenGL(); // Get the volume's dimensions // int dim[3]; vf->getDimensions(dim); // // Get the slices that have data // int extent[6]; float voxelExtent[6]; vf->getNonZeroVoxelExtent(extent, voxelExtent); // // Get the currently selected slices of the volume // int slices[3]; bmv->getSelectedOrthogonalSlices(0, slices); // // First and last slices to show // firstSlice = extent[sliceIndex*2]; lastSlice = extent[sliceIndex*2 + 1]; // // while animation should be performed // continueVolumeAnimation = true; while (continueVolumeAnimation) { // // set slices and update // if ((slices[sliceIndex] >= firstSlice) && (slices[sliceIndex] <= lastSlice)) { bmv->setSelectedOrthogonalSlices(0, slices); } GuiToolBar::updateAllToolBars(false); GuiBrainModelOpenGL::updateAllGL(openGL); // // Get slice increment // int sliceDelta = 1; switch (static_cast(volumeAnimateDirectionComboBox->currentIndex())) { case VOLUME_ANIMATE_DIRECTION_INCREMENT: sliceDelta = 1; break; case VOLUME_ANIMATE_DIRECTION_DECREMENT: sliceDelta = -1; break; } // // Update the slice // slices[sliceIndex] += sliceDelta; // // Switch directions if needed // if (slices[sliceIndex] > lastSlice) { slices[sliceIndex] = lastSlice; volumeAnimateDirectionComboBox->setCurrentIndex(VOLUME_ANIMATE_DIRECTION_DECREMENT); } else if (slices[sliceIndex] < firstSlice) { volumeAnimateDirectionComboBox->setCurrentIndex(VOLUME_ANIMATE_DIRECTION_INCREMENT); } // // Allow events to process // qApp->processEvents(); } } } /** * Called to stop the volume animation. */ void GuiDisplayControlDialog::slotVolumeAnimateStopPushButton() { continueVolumeAnimation = false; } /** * Called to display a histogram of the anatomy volume */ void GuiDisplayControlDialog::slotAnatomyVolumeHistogram() { BrainModelVolume* bmv = theMainWindow->getBrainSet()->getBrainModelVolume(); if (bmv != NULL) { VolumeFile* vf = bmv->getSelectedVolumeAnatomyFile(); if (vf != NULL) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); const int numVoxels = vf->getTotalNumberOfVoxels(); std::vector values; for (int i = 0; i < numVoxels; i++) { values.push_back(vf->getVoxelWithFlatIndex(i)); } GuiHistogramDisplayDialog* ghd = new GuiHistogramDisplayDialog(theMainWindow, FileUtilities::basename(vf->getFileName()), values, true, static_cast(Qt::WA_DeleteOnClose)); ghd->show(); QApplication::restoreOverrideCursor(); } } } /** * Reads the volume selections */ void GuiDisplayControlDialog::readVolumeSelections() { if (pageVolumeSelection == NULL) { return; } if (creatingDialog) { return; } } /** * reads the volume settings. */ void GuiDisplayControlDialog::readVolumeSettings() { if (pageVolumeSettings == NULL) { return; } if (creatingDialog) { return; } DisplaySettingsVolume* dsv = theMainWindow->getBrainSet()->getDisplaySettingsVolume(); dsv->setAnatomyVolumeBrightness(volumeAnatomyBrightnessSlider->value()); dsv->setAnatomyVolumeContrast(volumeAnatomyContrastSlider->value()); dsv->setVectorVolumeSparsity(vectorVolumeSparsitySpinBox->value()); dsv->setMontageViewSelected(volumeMontageGroupBox->isChecked()); dsv->setMontageViewSettings(volumeMontageRowsSpinBox->value(), volumeMontageColumnsSpinBox->value(), volumeMontageSliceIncrementSpinBox->value()); dsv->setDisplayCrosshairCoordinates(volumeShowCrosshairCoordinatesCheckBox->isChecked()); dsv->setDisplayCrosshairs(volumeShowCrosshairsCheckBox->isChecked()); dsv->setAnatomyVolumeColoringType( static_cast( volumeAnatomyDrawTypeComboBox->currentIndex())); dsv->setSegmentationDrawType( static_cast( volumeSegmentationDrawTypeComboBox->currentIndex())); dsv->setSegmentationTranslucency(volumeSegmentationTranslucencyDoubleSpinBox->value()); dsv->setOverlayOpacity(volumeOverlayOpacityDoubleSpinBox->value()); dsv->setDisplayColorBar(volumeFunctionalDisplayColorBarCheckBox->isChecked()); dsv->setObliqueSlicesTransformationMatrix(obliqueVolumeSliceMatrixControl->getSelectedMatrix()); dsv->setObliqueSlicesSamplingSize(obliqueSlicesSamplingSizeDoubleSpinBox->value()); BrainModelVolumeVoxelColoring* voxelColoring = theMainWindow->getBrainSet()->getVoxelColoring(); voxelColoring->setVolumeAnatomyColoringInvalid(); GuiBrainModelOpenGL::updateAllGL(); } /** * reads the volume surface outline. */ void GuiDisplayControlDialog::readVolumeSurfaceOutline() { if (pageVolumeSurfaceOutline == NULL) { return; } if (creatingDialog) { return; } DisplaySettingsVolume* dsv = theMainWindow->getBrainSet()->getDisplaySettingsVolume(); for (int i = 0; i < DisplaySettingsVolume::MAXIMUM_OVERLAY_SURFACES; i++) { dsv->setDisplayOverlaySurfaceOutline(i, volumeShowOverlaySurfaceOutlineCheckBox[i]->isChecked()); dsv->setOverlaySurfaceOutlineColor(i, static_cast( volumeOverlaySurfaceOutlineColorComboBox[i]->currentIndex())); dsv->setOverlaySurfaceOutlineThickness(i, volumeOverlaySurfaceOutlineThicknessDoubleSpinBox[i]->value()); if (i > 0) { dsv->setOverlaySurface(i, dynamic_cast(volumeOverlaySurfaceSelectionComboBox[i]->getSelectedBrainModel())); } } GuiBrainModelOpenGL::updateAllGL(); } /** * Update the selected volume tooltips. */ void GuiDisplayControlDialog::updateVolumeToolTips() { DisplaySettingsVolume* dsv = theMainWindow->getBrainSet()->getDisplaySettingsVolume(); if (theMainWindow->getBrainSet()->getNumberOfVolumeAnatomyFiles() > 0) { volumeAnatomyComboBox->setToolTip( theMainWindow->getBrainSet()->getVolumeAnatomyFile( dsv->getSelectedAnatomyVolume())->getDescriptiveLabel()); } if (theMainWindow->getBrainSet()->getNumberOfVolumeFunctionalFiles() > 0) { volumeFunctionalViewComboBox->setToolTip( theMainWindow->getBrainSet()->getVolumeFunctionalFile( dsv->getSelectedFunctionalVolumeView())->getDescriptiveLabel()); volumeFunctionalThresholdComboBox->setToolTip( theMainWindow->getBrainSet()->getVolumeFunctionalFile( dsv->getSelectedFunctionalVolumeThreshold())->getDescriptiveLabel()); } if (theMainWindow->getBrainSet()->getNumberOfVolumePaintFiles() > 0) { volumePaintComboBox->setToolTip( theMainWindow->getBrainSet()->getVolumePaintFile( dsv->getSelectedPaintVolume())->getDescriptiveLabel()); } if (theMainWindow->getBrainSet()->getNumberOfVolumeRgbFiles() > 0) { volumeRgbComboBox->setToolTip( theMainWindow->getBrainSet()->getVolumeRgbFile( dsv->getSelectedRgbVolume())->getDescriptiveLabel()); } if (theMainWindow->getBrainSet()->getNumberOfVolumeSegmentationFiles() > 0) { volumeSegmentationComboBox->setToolTip( theMainWindow->getBrainSet()->getVolumeSegmentationFile( dsv->getSelectedSegmentationVolume())->getDescriptiveLabel()); } } /** * Update the volume items */ void GuiDisplayControlDialog::updateVolumeItems() { updatePageSelectionComboBox(); updateVolumeSelectionPage(); updateVolumeSettingsPage(); updateVolumeSurfaceOutlinePage(); } /** * update volume selection page. */ void GuiDisplayControlDialog::updateVolumeSelectionPage() { if (pageVolumeSelection == NULL) { return; } pageVolumeSelection->setEnabled(validVolumeData); BrainModelVolumeVoxelColoring* vvc = theMainWindow->getBrainSet()->getVoxelColoring(); DisplaySettingsVolume* dsv = theMainWindow->getBrainSet()->getDisplaySettingsVolume(); // // Set the primary overlay radio buttons // switch(vvc->getPrimaryOverlay()) { case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_ANATOMY: volumePrimaryOverlayAnatomyRadioButton->setChecked(true); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_FUNCTIONAL: volumePrimaryOverlayFunctionalRadioButton->setChecked(true); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_PAINT: volumePrimaryOverlayPaintRadioButton->setChecked(true); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_PROB_ATLAS: volumePrimaryOverlayProbAtlasRadioButton->setChecked(true); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_RGB: volumePrimaryOverlayRgbRadioButton->setChecked(true); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_SEGMENTATION: volumePrimaryOverlaySegmentationRadioButton->setChecked(true); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_VECTOR: volumePrimaryOverlayVectorRadioButton->setChecked(true); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_NONE: volumePrimaryOverlayNoneButton->setChecked(true); break; } // // set the secondary overlay radio buttons // switch(vvc->getSecondaryOverlay()) { case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_ANATOMY: volumeSecondaryOverlayAnatomyRadioButton->setChecked(true); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_FUNCTIONAL: volumeSecondaryOverlayFunctionalRadioButton->setChecked(true); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_PAINT: volumeSecondaryOverlayPaintRadioButton->setChecked(true); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_PROB_ATLAS: volumeSecondaryOverlayProbAtlasRadioButton->setChecked(true); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_RGB: volumeSecondaryOverlayRgbRadioButton->setChecked(true); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_SEGMENTATION: volumeSecondaryOverlaySegmentationRadioButton->setChecked(true); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_VECTOR: volumeSecondaryOverlayVectorRadioButton->setChecked(true); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_NONE: volumeSecondaryOverlayNoneButton->setChecked(true); break; } // // set the underlay radio buttons // switch(vvc->getUnderlay()) { case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_ANATOMY: volumeUnderlayAnatomyRadioButton->setChecked(true); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_FUNCTIONAL: volumeUnderlayFunctionalRadioButton->setChecked(true); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_PAINT: volumeUnderlayPaintRadioButton->setChecked(true); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_PROB_ATLAS: volumeUnderlayProbAtlasRadioButton->setChecked(true); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_RGB: volumeUnderlayRgbRadioButton->setChecked(true); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_SEGMENTATION: volumeUnderlaySegmentationRadioButton->setChecked(true); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_VECTOR: volumeUnderlayVectorRadioButton->setChecked(true); break; case BrainModelVolumeVoxelColoring::UNDERLAY_OVERLAY_NONE: volumeUnderlayNoneButton->setChecked(true); break; } // // update anatomy volume combo box // volumePrimaryOverlayAnatomyRadioButton->setEnabled(false); volumeSecondaryOverlayAnatomyRadioButton->setEnabled(false); volumeUnderlayAnatomyRadioButton->setEnabled(false); volumeAnatomyComboBox->setEnabled(false); volumeAnatomyLabel->setEnabled(false); volumeAnatomyInfoPushButton->setEnabled(false); volumeAnatomyMetaDataPushButton->setEnabled(false); volumeAnatomyComboBox->clear(); if (theMainWindow->getBrainSet()->getNumberOfVolumeAnatomyFiles() > 0) { for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfVolumeAnatomyFiles(); i++) { volumeAnatomyComboBox->addItem( theMainWindow->getBrainSet()->getVolumeAnatomyFile(i)->getDescriptiveLabel()); } volumeAnatomyComboBox->setCurrentIndex(dsv->getSelectedAnatomyVolume()); volumePrimaryOverlayAnatomyRadioButton->setEnabled(true); volumeSecondaryOverlayAnatomyRadioButton->setEnabled(true); volumeUnderlayAnatomyRadioButton->setEnabled(true); volumeAnatomyComboBox->setEnabled(true); volumeAnatomyLabel->setEnabled(true); volumeAnatomyInfoPushButton->setEnabled(true); volumeAnatomyMetaDataPushButton->setEnabled(true); } // // update functional volume combo box // volumePrimaryOverlayFunctionalRadioButton->setEnabled(false); volumeSecondaryOverlayFunctionalRadioButton->setEnabled(false); volumeUnderlayFunctionalRadioButton->setEnabled(false); volumeFunctionalViewComboBox->setEnabled(false); volumeFunctionalThresholdComboBox->setEnabled(false); volumeFunctionalViewLabel->setEnabled(false); volumeFunctionalViewInfoPushButton->setEnabled(false); volumeFunctionalThreshInfoPushButton->setEnabled(false); volumeFunctionalViewMetaDataPushButton->setEnabled(false); volumeFunctionalThreshMetaDataPushButton->setEnabled(false); volumeFunctionalThresholdLabel->setEnabled(false); volumeFunctionalViewComboBox->clear(); volumeFunctionalThresholdComboBox->clear(); if (theMainWindow->getBrainSet()->getNumberOfVolumeFunctionalFiles() > 0) { for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfVolumeFunctionalFiles(); i++) { volumeFunctionalViewComboBox->addItem( theMainWindow->getBrainSet()->getVolumeFunctionalFile(i)->getDescriptiveLabel()); volumeFunctionalThresholdComboBox->addItem( theMainWindow->getBrainSet()->getVolumeFunctionalFile(i)->getDescriptiveLabel()); } volumeFunctionalViewComboBox->setCurrentIndex(dsv->getSelectedFunctionalVolumeView()); volumeFunctionalThresholdComboBox->setCurrentIndex(dsv->getSelectedFunctionalVolumeThreshold()); volumePrimaryOverlayFunctionalRadioButton->setEnabled(true); volumeSecondaryOverlayFunctionalRadioButton->setEnabled(true); volumeUnderlayFunctionalRadioButton->setEnabled(true); volumeFunctionalViewComboBox->setEnabled(true); volumeFunctionalViewLabel->setEnabled(true); volumeFunctionalThresholdComboBox->setEnabled(true); volumeFunctionalThresholdLabel->setEnabled(true); volumeFunctionalViewInfoPushButton->setEnabled(true); volumeFunctionalThreshInfoPushButton->setEnabled(true); volumeFunctionalViewMetaDataPushButton->setEnabled(true); volumeFunctionalThreshMetaDataPushButton->setEnabled(true); } // // update paint volume combo box // volumePrimaryOverlayPaintRadioButton->setEnabled(false); volumeSecondaryOverlayPaintRadioButton->setEnabled(false); volumeUnderlayPaintRadioButton->setEnabled(false); volumePaintComboBox->setEnabled(false); volumePaintLabel->setEnabled(false); volumePaintInfoPushButton->setEnabled(false); volumePaintMetaDataPushButton->setEnabled(false); volumePaintComboBox->clear(); if (theMainWindow->getBrainSet()->getNumberOfVolumePaintFiles() > 0) { for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfVolumePaintFiles(); i++) { volumePaintComboBox->addItem( theMainWindow->getBrainSet()->getVolumePaintFile(i)->getDescriptiveLabel()); } volumePaintComboBox->setCurrentIndex(dsv->getSelectedPaintVolume()); volumePrimaryOverlayPaintRadioButton->setEnabled(true); volumeSecondaryOverlayPaintRadioButton->setEnabled(true); volumeUnderlayPaintRadioButton->setEnabled(true); volumePaintComboBox->setEnabled(true); volumePaintLabel->setEnabled(true); volumePaintInfoPushButton->setEnabled(true); volumePaintMetaDataPushButton->setEnabled(true); } // // update prob atlas volume combo box // volumePrimaryOverlayProbAtlasRadioButton->setEnabled(false); volumeSecondaryOverlayProbAtlasRadioButton->setEnabled(false); volumeUnderlayProbAtlasRadioButton->setEnabled(false); volumeProbAtlasLabel->setEnabled(false); volumeProbAtlasInfoPushButton->setEnabled(false); volumeProbAtlasMetaDataPushButton->setEnabled(false); if (theMainWindow->getBrainSet()->getNumberOfVolumeProbAtlasFiles() > 0) { volumePrimaryOverlayProbAtlasRadioButton->setEnabled(true); volumeSecondaryOverlayProbAtlasRadioButton->setEnabled(true); volumeUnderlayProbAtlasRadioButton->setEnabled(true); volumeProbAtlasLabel->setEnabled(true); volumeProbAtlasInfoPushButton->setEnabled(true); volumeProbAtlasMetaDataPushButton->setEnabled(true); } // // update rgb volume combo box // volumePrimaryOverlayRgbRadioButton->setEnabled(false); volumeSecondaryOverlayRgbRadioButton->setEnabled(false); volumeUnderlayRgbRadioButton->setEnabled(false); volumeRgbComboBox->setEnabled(false); volumeRgbLabel->setEnabled(false); volumeRgbComboBox->clear(); volumeRgbInfoPushButton->setEnabled(false); volumeRgbMetaDataPushButton->setEnabled(false); if (theMainWindow->getBrainSet()->getNumberOfVolumeRgbFiles() > 0) { for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfVolumeRgbFiles(); i++) { volumeRgbComboBox->addItem( theMainWindow->getBrainSet()->getVolumeRgbFile(i)->getDescriptiveLabel()); } volumeRgbComboBox->setCurrentIndex(dsv->getSelectedRgbVolume()); volumePrimaryOverlayRgbRadioButton->setEnabled(true); volumeSecondaryOverlayRgbRadioButton->setEnabled(true); volumeUnderlayRgbRadioButton->setEnabled(true); volumeRgbComboBox->setEnabled(true); volumeRgbLabel->setEnabled(true); volumeRgbInfoPushButton->setEnabled(true); volumeRgbMetaDataPushButton->setEnabled(true); } // // update segmentation volume combo box // volumePrimaryOverlaySegmentationRadioButton->setEnabled(false); volumeSecondaryOverlaySegmentationRadioButton->setEnabled(false); volumeUnderlaySegmentationRadioButton->setEnabled(false); volumeSegmentationComboBox->setEnabled(false); volumeSegmentationLabel->setEnabled(false); volumeSegmentationInfoPushButton->setEnabled(false); volumeSegmentationMetaDataPushButton->setEnabled(false); volumeSegmentationComboBox->clear(); if (theMainWindow->getBrainSet()->getNumberOfVolumeSegmentationFiles() > 0) { for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfVolumeSegmentationFiles(); i++) { volumeSegmentationComboBox->addItem( theMainWindow->getBrainSet()->getVolumeSegmentationFile(i)->getDescriptiveLabel()); } volumeSegmentationComboBox->setCurrentIndex(dsv->getSelectedSegmentationVolume()); volumePrimaryOverlaySegmentationRadioButton->setEnabled(true); volumeSecondaryOverlaySegmentationRadioButton->setEnabled(true); volumeUnderlaySegmentationRadioButton->setEnabled(true); volumeSegmentationComboBox->setEnabled(true); volumeSegmentationLabel->setEnabled(true); volumeSegmentationInfoPushButton->setEnabled(true); volumeSegmentationMetaDataPushButton->setEnabled(true); } // // update vector volume combo box // volumePrimaryOverlayVectorRadioButton->setEnabled(false); volumeSecondaryOverlayVectorRadioButton->setEnabled(false); volumeUnderlayVectorRadioButton->setEnabled(false); volumeVectorComboBox->setEnabled(false); volumeVectorLabel->setEnabled(false); volumeVectorInfoPushButton->setEnabled(false); volumeVectorMetaDataPushButton->setEnabled(false); volumeVectorComboBox->clear(); if (theMainWindow->getBrainSet()->getNumberOfVolumeVectorFiles() > 0) { for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfVolumeVectorFiles(); i++) { volumeVectorComboBox->addItem( theMainWindow->getBrainSet()->getVolumeVectorFile(i)->getDescriptiveLabel()); } volumeVectorComboBox->setCurrentIndex(dsv->getSelectedVectorVolume()); volumePrimaryOverlayVectorRadioButton->setEnabled(true); volumeSecondaryOverlayVectorRadioButton->setEnabled(true); volumeUnderlayVectorRadioButton->setEnabled(true); volumeVectorComboBox->setEnabled(true); volumeVectorLabel->setEnabled(true); volumeVectorInfoPushButton->setEnabled(true); volumeVectorMetaDataPushButton->setEnabled(true); //vectorVolumeSparsitySpinBox->setValue(dsv->getVectorVolumeSparsity()); } updateVolumeToolTips(); updateProbAtlasVolumeItems(true); } /** * update volume settings page. */ void GuiDisplayControlDialog::updateVolumeSettingsPage() { if (pageVolumeSettings == NULL) { return; } pageVolumeSettingsWidgetGroup->blockSignals(true); pageVolumeSettings->setEnabled(validVolumeData); DisplaySettingsVolume* dsv = theMainWindow->getBrainSet()->getDisplaySettingsVolume(); volumeSegmentationDrawTypeComboBox->setCurrentIndex(dsv->getSegmentationDrawType()); volumeAnatomyDrawTypeComboBox->setCurrentIndex(dsv->getAnatomyVolumeColoringType()); volumeSegmentationTranslucencyDoubleSpinBox->setValue(dsv->getSegmentationTranslucency()); volumeOverlayOpacityDoubleSpinBox->setValue(dsv->getOverlayOpacity()); volumeAnatomyBrightnessSlider->setValue(dsv->getAnatomyVolumeBrightness()); volumeAnatomyContrastSlider->setValue(dsv->getAnatomyVolumeContrast()); volumeAnatomyBrightnessLabel->setNum(volumeAnatomyBrightnessSlider->value()); volumeAnatomyContrastLabel->setNum(volumeAnatomyContrastSlider->value()); volumeFunctionalDisplayColorBarCheckBox->setChecked(dsv->getDisplayColorBar()); volumeMontageGroupBox->setChecked(dsv->getMontageViewSelected()); int rows, cols, slices; dsv->getMontageViewSettings(rows, cols, slices); volumeMontageRowsSpinBox->setValue(rows); volumeMontageColumnsSpinBox->setValue(cols); volumeMontageSliceIncrementSpinBox->setValue(slices); volumeShowCrosshairCoordinatesCheckBox->blockSignals(true); volumeShowCrosshairCoordinatesCheckBox->setChecked(dsv->getDisplayCrosshairCoordinates()); volumeShowCrosshairCoordinatesCheckBox->blockSignals(false); volumeShowCrosshairsCheckBox->blockSignals(true); volumeShowCrosshairsCheckBox->setChecked(dsv->getDisplayCrosshairs()); volumeShowCrosshairsCheckBox->blockSignals(false); obliqueVolumeSliceMatrixControl->updateControl(); obliqueVolumeSliceMatrixControl->setSelectedMatrix(dsv->getObliqueSlicesTransformationMatrix()); obliqueSlicesSamplingSizeDoubleSpinBox->setValue(dsv->getObliqueSlicesSamplingSize()); continueVolumeAnimation = false; vectorVolumeSparsitySpinBox->setValue(dsv->getVectorVolumeSparsity()); vectorVolumeGroupBox->setEnabled(theMainWindow->getBrainSet()->getNumberOfVolumeVectorFiles() > 0); pageVolumeSettingsWidgetGroup->blockSignals(false); } /** * update volume surface outline page. */ void GuiDisplayControlDialog::updateVolumeSurfaceOutlinePage() { if (pageVolumeSurfaceOutline == NULL) { return; } pageVolumeSurfaceOutlineWidgetGroup->blockSignals(true); pageVolumeSurfaceOutline->setEnabled(validVolumeData); DisplaySettingsVolume* dsv = theMainWindow->getBrainSet()->getDisplaySettingsVolume(); for (int i = 0; i < DisplaySettingsVolume::MAXIMUM_OVERLAY_SURFACES; i++) { volumeShowOverlaySurfaceOutlineCheckBox[i]->blockSignals(true); volumeShowOverlaySurfaceOutlineCheckBox[i]->setChecked(dsv->getDisplayOverlaySurfaceOutline(i)); volumeShowOverlaySurfaceOutlineCheckBox[i]->blockSignals(false); volumeOverlaySurfaceOutlineThicknessDoubleSpinBox[i]->blockSignals(true); volumeOverlaySurfaceOutlineThicknessDoubleSpinBox[i]->setValue(dsv->getOverlaySurfaceOutlineThickness(i)); volumeOverlaySurfaceOutlineThicknessDoubleSpinBox[i]->blockSignals(false); volumeOverlaySurfaceOutlineColorComboBox[i]->blockSignals(true); volumeOverlaySurfaceOutlineColorComboBox[i]->setCurrentIndex(dsv->getOverlaySurfaceOutlineColor(i)); volumeOverlaySurfaceOutlineColorComboBox[i]->blockSignals(false); if (i > 0) { volumeOverlaySurfaceSelectionComboBox[i]->blockSignals(true); volumeOverlaySurfaceSelectionComboBox[i]->updateComboBox(); volumeOverlaySurfaceSelectionComboBox[i]->setSelectedBrainModel(dsv->getOverlaySurface(i)); volumeOverlaySurfaceSelectionComboBox[i]->blockSignals(false); } } pageVolumeSurfaceOutlineWidgetGroup->blockSignals(false); } /** * called when a volume primary overlay is selected */ void GuiDisplayControlDialog::volumePrimaryOverlaySelection(int n) { BrainModelVolumeVoxelColoring* vvc = theMainWindow->getBrainSet()->getVoxelColoring(); vvc->setPrimaryOverlay(static_cast(n)); GuiBrainModelOpenGL::updateAllGL(); GuiToolBar::updateAllToolBars(false); } /** * called when a volume secondary overlay is selected */ void GuiDisplayControlDialog::volumeSecondaryOverlaySelection(int n) { BrainModelVolumeVoxelColoring* vvc = theMainWindow->getBrainSet()->getVoxelColoring(); vvc->setSecondaryOverlay(static_cast(n)); GuiBrainModelOpenGL::updateAllGL(); GuiToolBar::updateAllToolBars(false); } /** * called when a volume underlay is selected */ void GuiDisplayControlDialog::volumeUnderlaySelection(int n) { BrainModelVolumeVoxelColoring* vvc = theMainWindow->getBrainSet()->getVoxelColoring(); vvc->setUnderlay(static_cast(n)); GuiVolumeResizingDialog* volResizeDialog = theMainWindow->getVolumeResizingDialog(false); if (volResizeDialog != NULL) { volResizeDialog->updateDialog(false); } GuiBrainModelOpenGL::updateAllGL(); GuiToolBar::updateAllToolBars(false); } /** * called to display comment info for volume. */ void GuiDisplayControlDialog::volumeAnatomyInfoPushButtonSelection() { if (theMainWindow->getBrainSet()->getNumberOfVolumeAnatomyFiles() > 0) { BrainModelVolume* bmv = theMainWindow->getBrainSet()->getBrainModelVolume(); VolumeFile* vf = bmv->getSelectedVolumeAnatomyFile(); GuiDataFileCommentDialog* dfcd = new GuiDataFileCommentDialog(theMainWindow, vf); dfcd->show(); } } /** * called to display comment info for volume. */ void GuiDisplayControlDialog::volumeFunctionalViewInfoPushButtonSelection() { if (theMainWindow->getBrainSet()->getNumberOfVolumeFunctionalFiles() > 0) { BrainModelVolume* bmv = theMainWindow->getBrainSet()->getBrainModelVolume(); VolumeFile* vf = bmv->getSelectedVolumeFunctionalViewFile(); GuiDataFileCommentDialog* dfcd = new GuiDataFileCommentDialog(theMainWindow, vf); dfcd->show(); } } /** * called to display comment info for volume. */ void GuiDisplayControlDialog::volumeFunctionalThreshInfoPushButtonSelection() { if (theMainWindow->getBrainSet()->getNumberOfVolumeFunctionalFiles() > 0) { BrainModelVolume* bmv = theMainWindow->getBrainSet()->getBrainModelVolume(); VolumeFile* vf = bmv->getSelectedVolumeFunctionalThresholdFile(); GuiDataFileCommentDialog* dfcd = new GuiDataFileCommentDialog(theMainWindow, vf); dfcd->show(); } } /** * called to display comment info for volume. */ void GuiDisplayControlDialog::volumePaintInfoPushButtonSelection() { if (theMainWindow->getBrainSet()->getNumberOfVolumePaintFiles() > 0) { BrainModelVolume* bmv = theMainWindow->getBrainSet()->getBrainModelVolume(); VolumeFile* vf = bmv->getSelectedVolumePaintFile(); GuiDataFileCommentDialog* dfcd = new GuiDataFileCommentDialog(theMainWindow, vf); dfcd->show(); } } /** * called to display comment info for volume. */ void GuiDisplayControlDialog::volumeProbAtlasInfoPushButtonSelection() { if (theMainWindow->getBrainSet()->getNumberOfVolumeProbAtlasFiles() > 0) { if (theMainWindow->getBrainSet()->getNumberOfVolumeProbAtlasFiles() > 0) { VolumeFile* vf = theMainWindow->getBrainSet()->getVolumeProbAtlasFile(0); GuiDataFileCommentDialog* dfcd = new GuiDataFileCommentDialog(theMainWindow, vf); dfcd->show(); } } } /** * called to display comment info for volume. */ void GuiDisplayControlDialog::volumeRgbInfoPushButtonSelection() { if (theMainWindow->getBrainSet()->getNumberOfVolumeRgbFiles() > 0) { BrainModelVolume* bmv = theMainWindow->getBrainSet()->getBrainModelVolume(); VolumeFile* vf = bmv->getSelectedVolumeRgbFile(); GuiDataFileCommentDialog* dfcd = new GuiDataFileCommentDialog(theMainWindow, vf); dfcd->show(); } } /** * called to display comment info for segmentation volume. */ void GuiDisplayControlDialog::volumeSegmentationInfoPushButtonSelection() { if (theMainWindow->getBrainSet()->getNumberOfVolumeSegmentationFiles() > 0) { BrainModelVolume* bmv = theMainWindow->getBrainSet()->getBrainModelVolume(); VolumeFile* vf = bmv->getSelectedVolumeSegmentationFile(); GuiDataFileCommentDialog* dfcd = new GuiDataFileCommentDialog(theMainWindow, vf); dfcd->show(); } } /** * called to display comment info for vector volume. */ void GuiDisplayControlDialog::volumeVectorInfoPushButtonSelection() { if (theMainWindow->getBrainSet()->getNumberOfVolumeVectorFiles() > 0) { BrainModelVolume* bmv = theMainWindow->getBrainSet()->getBrainModelVolume(); VolumeFile* vf = bmv->getSelectedVolumeVectorFile(); GuiDataFileCommentDialog* dfcd = new GuiDataFileCommentDialog(theMainWindow, vf); dfcd->show(); } } /** * called to display metadata info for anatomy volume. */ void GuiDisplayControlDialog::volumeAnatomyMetaDataPushButtonSelection() { if (theMainWindow->getBrainSet()->getNumberOfVolumeAnatomyFiles() > 0) { BrainModelVolume* bmv = theMainWindow->getBrainSet()->getBrainModelVolume(); VolumeFile* vf = bmv->getSelectedVolumeAnatomyFile(); StudyMetaDataLinkSet smdls = vf->getStudyMetaDataLinkSet(); GuiStudyMetaDataLinkCreationDialog smdlcd(this); smdlcd.initializeSelectedLinkSet(smdls); if (smdlcd.exec() == GuiStudyMetaDataLinkCreationDialog::Accepted) { smdls = smdlcd.getLinkSetCreated(); vf->setStudyMetaDataLinkSet(smdls); } } } /** * called to display metadata info for functional view volume. */ void GuiDisplayControlDialog::volumeFunctionalViewMetaDataPushButtonSelection() { if (theMainWindow->getBrainSet()->getNumberOfVolumeFunctionalFiles() > 0) { BrainModelVolume* bmv = theMainWindow->getBrainSet()->getBrainModelVolume(); VolumeFile* vf = bmv->getSelectedVolumeFunctionalViewFile(); StudyMetaDataLinkSet smdls = vf->getStudyMetaDataLinkSet(); GuiStudyMetaDataLinkCreationDialog smdlcd(this); smdlcd.initializeSelectedLinkSet(smdls); if (smdlcd.exec() == GuiStudyMetaDataLinkCreationDialog::Accepted) { smdls = smdlcd.getLinkSetCreated(); vf->setStudyMetaDataLinkSet(smdls); } } } /** * called to display metadata info for function threshold volume. */ void GuiDisplayControlDialog::volumeFunctionalThreshMetaDataPushButtonSelection() { if (theMainWindow->getBrainSet()->getNumberOfVolumeFunctionalFiles() > 0) { BrainModelVolume* bmv = theMainWindow->getBrainSet()->getBrainModelVolume(); VolumeFile* vf = bmv->getSelectedVolumeFunctionalThresholdFile(); StudyMetaDataLinkSet smdls = vf->getStudyMetaDataLinkSet(); GuiStudyMetaDataLinkCreationDialog smdlcd(this); smdlcd.initializeSelectedLinkSet(smdls); if (smdlcd.exec() == GuiStudyMetaDataLinkCreationDialog::Accepted) { smdls = smdlcd.getLinkSetCreated(); vf->setStudyMetaDataLinkSet(smdls); } } } /** * called to display metadata info for paint volume. */ void GuiDisplayControlDialog::volumePaintMetaDataPushButtonSelection() { if (theMainWindow->getBrainSet()->getNumberOfVolumePaintFiles() > 0) { BrainModelVolume* bmv = theMainWindow->getBrainSet()->getBrainModelVolume(); VolumeFile* vf = bmv->getSelectedVolumePaintFile(); StudyMetaDataLinkSet smdls = vf->getStudyMetaDataLinkSet(); GuiStudyMetaDataLinkCreationDialog smdlcd(this); smdlcd.initializeSelectedLinkSet(smdls); if (smdlcd.exec() == GuiStudyMetaDataLinkCreationDialog::Accepted) { smdls = smdlcd.getLinkSetCreated(); vf->setStudyMetaDataLinkSet(smdls); } } } /** * called to display metadata info for prob atlas volume. */ void GuiDisplayControlDialog::volumeProbAtlasVolumeStudyMetaDataPushButton() { if (theMainWindow->getBrainSet()->getNumberOfVolumeProbAtlasFiles() > 0) { const int numFiles = theMainWindow->getBrainSet()->getNumberOfVolumeProbAtlasFiles(); if (numFiles > 0) { VolumeFile* vf = theMainWindow->getBrainSet()->getVolumeProbAtlasFile(0); StudyMetaDataLinkSet smdls = vf->getStudyMetaDataLinkSet(); GuiStudyMetaDataLinkCreationDialog smdlcd(this); smdlcd.initializeSelectedLinkSet(smdls); if (smdlcd.exec() == GuiStudyMetaDataLinkCreationDialog::Accepted) { smdls = smdlcd.getLinkSetCreated(); for (int i = 0; i < numFiles; i++) { VolumeFile* vf = theMainWindow->getBrainSet()->getVolumeProbAtlasFile(i); vf->setStudyMetaDataLinkSet(smdls); } } } } } /** * called to display metadata info for rgb volume. */ void GuiDisplayControlDialog::volumeRgbMetaDataPushButtonSelection() { if (theMainWindow->getBrainSet()->getNumberOfVolumeRgbFiles() > 0) { BrainModelVolume* bmv = theMainWindow->getBrainSet()->getBrainModelVolume(); VolumeFile* vf = bmv->getSelectedVolumeRgbFile(); StudyMetaDataLinkSet smdls = vf->getStudyMetaDataLinkSet(); GuiStudyMetaDataLinkCreationDialog smdlcd(this); smdlcd.initializeSelectedLinkSet(smdls); if (smdlcd.exec() == GuiStudyMetaDataLinkCreationDialog::Accepted) { smdls = smdlcd.getLinkSetCreated(); vf->setStudyMetaDataLinkSet(smdls); } } } /** * called to display metadata info for segmentation volume. */ void GuiDisplayControlDialog::volumeSegmentationMetaDataPushButtonSelection() { if (theMainWindow->getBrainSet()->getNumberOfVolumeSegmentationFiles() > 0) { BrainModelVolume* bmv = theMainWindow->getBrainSet()->getBrainModelVolume(); VolumeFile* vf = bmv->getSelectedVolumeSegmentationFile(); StudyMetaDataLinkSet smdls = vf->getStudyMetaDataLinkSet(); GuiStudyMetaDataLinkCreationDialog smdlcd(this); smdlcd.initializeSelectedLinkSet(smdls); if (smdlcd.exec() == GuiStudyMetaDataLinkCreationDialog::Accepted) { smdls = smdlcd.getLinkSetCreated(); vf->setStudyMetaDataLinkSet(smdls); } } } /** * called to display metadata info for vector volume. */ void GuiDisplayControlDialog::volumeVectorMetaDataPushButtonSelection() { if (theMainWindow->getBrainSet()->getNumberOfVolumeVectorFiles() > 0) { BrainModelVolume* bmv = theMainWindow->getBrainSet()->getBrainModelVolume(); VolumeFile* vf = bmv->getSelectedVolumeVectorFile(); StudyMetaDataLinkSet smdls = vf->getStudyMetaDataLinkSet(); GuiStudyMetaDataLinkCreationDialog smdlcd(this); smdlcd.initializeSelectedLinkSet(smdls); if (smdlcd.exec() == GuiStudyMetaDataLinkCreationDialog::Accepted) { smdls = smdlcd.getLinkSetCreated(); vf->setStudyMetaDataLinkSet(smdls); } } } /** * Called when a volume anatomy column is selected. */ void GuiDisplayControlDialog::volumeAnatomySelection(int n) { DisplaySettingsVolume* dsv = theMainWindow->getBrainSet()->getDisplaySettingsVolume(); dsv->setSelectedAnatomyVolume(n); GuiBrainModelOpenGL::updateAllGL(); GuiToolBar::updateAllToolBars(false); updateVolumeToolTips(); } /** * Called when a volume functional view column is functional selected. */ void GuiDisplayControlDialog::volumeFunctionalViewSelection(int n) { DisplaySettingsVolume* dsv = theMainWindow->getBrainSet()->getDisplaySettingsVolume(); dsv->setSelectedFunctionalVolumeView(n); dsv->setSelectedFunctionalVolumeThreshold(n); volumeFunctionalThresholdComboBox->setCurrentIndex(n); BrainModelSurfaceNodeColoring* bsnc = theMainWindow->getBrainSet()->getNodeColoring(); bsnc->assignColors(); GuiBrainModelOpenGL::updateAllGL(); GuiToolBar::updateAllToolBars(false); updateVolumeToolTips(); } /** * Called when a volume functional theshold column is functional selected. */ void GuiDisplayControlDialog::volumeFunctionalThresholdSelection(int n) { DisplaySettingsVolume* dsv = theMainWindow->getBrainSet()->getDisplaySettingsVolume(); dsv->setSelectedFunctionalVolumeThreshold(n); GuiBrainModelOpenGL::updateAllGL(); GuiToolBar::updateAllToolBars(false); updateVolumeToolTips(); } /** * Called when a volume paint column is selected. */ void GuiDisplayControlDialog::volumePaintSelection(int n) { DisplaySettingsVolume* dsv = theMainWindow->getBrainSet()->getDisplaySettingsVolume(); dsv->setSelectedPaintVolume(n); GuiBrainModelOpenGL::updateAllGL(); GuiToolBar::updateAllToolBars(false); updateVolumeToolTips(); } /** * Called when a volume rgb column is selected. */ void GuiDisplayControlDialog::volumeRgbSelection(int n) { DisplaySettingsVolume* dsv = theMainWindow->getBrainSet()->getDisplaySettingsVolume(); dsv->setSelectedRgbVolume(n); GuiBrainModelOpenGL::updateAllGL(); GuiToolBar::updateAllToolBars(false); updateVolumeToolTips(); } /** * Called when a volume segmentation column is selected. */ void GuiDisplayControlDialog::volumeSegmentationSelection(int n) { DisplaySettingsVolume* dsv = theMainWindow->getBrainSet()->getDisplaySettingsVolume(); dsv->setSelectedSegmentationVolume(n); GuiBrainModelOpenGL::updateAllGL(); GuiToolBar::updateAllToolBars(false); updateVolumeToolTips(); } /** * Called when a volume vector column is selected. */ void GuiDisplayControlDialog::volumeVectorSelection(int n) { DisplaySettingsVolume* dsv = theMainWindow->getBrainSet()->getDisplaySettingsVolume(); dsv->setSelectedVectorVolume(n); GuiBrainModelOpenGL::updateAllGL(); GuiToolBar::updateAllToolBars(false); updateVolumeToolTips(); } /** * Create the contour main page */ void GuiDisplayControlDialog::createContourClassPage() { // // Vertical Box Layout for all contour items // pageContourClass = new QWidget; contourSubPageClassLayout = new QVBoxLayout(pageContourClass); // // All off and all on pushbuttons // QPushButton* contourClassAllOnButton = new QPushButton("All On"); contourClassAllOnButton->setAutoDefault(false); QObject::connect(contourClassAllOnButton, SIGNAL(clicked()), this, SLOT(contourCellClassAllOn())); QPushButton* contourClassAllOffButton = new QPushButton("All Off"); contourClassAllOffButton->setAutoDefault(false); QObject::connect(contourClassAllOffButton, SIGNAL(clicked()), this, SLOT(contourCellClassAllOff())); QHBoxLayout* allOnOffLayout = new QHBoxLayout; allOnOffLayout->addWidget(contourClassAllOnButton); allOnOffLayout->addWidget(contourClassAllOffButton); allOnOffLayout->addStretch(); contourSubPageClassLayout->addLayout(allOnOffLayout); createAndUpdateContourCellClassCheckBoxes(); pageWidgetStack->addWidget(pageContourClass); } /** * Create and update contour class checkboxes. Because the number of contour cells may change, * this method may update and change the label on existing checkboxes, add new * checkboxes, and hide existing checkboxes if the number of checkboxes is greater * than the number of contour cell classes. */ void GuiDisplayControlDialog::createAndUpdateContourCellClassCheckBoxes() { ContourCellFile* cf = theMainWindow->getBrainSet()->getContourCellFile(); numValidContourCellClasses = cf->getNumberOfCellClasses(); const int numExistingCheckBoxes = static_cast(contourCellClassCheckBoxes.size()); if (contourCellClassGridLayout == NULL) { // // Scroll View for contour cell color checkboxes // QWidget* classWidget = new QWidget; contourCellClassGridLayout = new QGridLayout(classWidget); const int rowStretchNumber = 15000; contourCellClassGridLayout->addWidget(new QLabel(""), rowStretchNumber, 0, Qt::AlignLeft); contourCellClassGridLayout->setRowStretch(rowStretchNumber, 1000); contourSubPageClassLayout->addWidget(classWidget); } if (contourCellClassButtonGroup == NULL) { contourCellClassButtonGroup = new QButtonGroup(this); contourCellClassButtonGroup->setExclusive(false); QObject::connect(contourCellClassButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(readContourClassPage())); } // // Update exising checkboxes // for (int i = 0; i < numExistingCheckBoxes; i++) { if (i < numValidContourCellClasses) { contourCellClassCheckBoxes[i]->setText(cf->getCellClassNameByIndex(i)); contourCellClassCheckBoxes[i]->show(); } } // // Add new checkboxes as needed // for (int j = numExistingCheckBoxes; j < numValidContourCellClasses; j++) { QCheckBox* cb = new QCheckBox(cf->getCellClassNameByIndex(j)); contourCellClassCheckBoxes.push_back(cb); contourCellClassButtonGroup->addButton(cb, j); contourCellClassGridLayout->addWidget(cb, j, 0, 1, 1, Qt::AlignLeft); cb->show(); } // // Hide existing checkboxes that are not needed. // for (int k = numValidContourCellClasses; k < numExistingCheckBoxes; k++) { contourCellClassCheckBoxes[k]->hide(); } } /** * This slot is called when the contour class all on button is pressed. */ void GuiDisplayControlDialog::contourCellClassAllOn() { ContourCellFile* cf = theMainWindow->getBrainSet()->getContourCellFile(); if (cf != NULL) { cf->setAllCellClassStatus(true); } updateContourItems(); readContourClassPage(); } /** * This slot is called when the contour class all off button is pressed. */ void GuiDisplayControlDialog::contourCellClassAllOff() { ContourCellFile* cf = theMainWindow->getBrainSet()->getContourCellFile(); if (cf != NULL) { cf->setAllCellClassStatus(false); } updateContourItems(); readContourClassPage(); } /** * Create the contour main page */ void GuiDisplayControlDialog::createContourColorPage() { // // Vertical Box Layout for all contour items // pageContourColor = new QWidget; contourSubPageColorLayout = new QVBoxLayout(pageContourColor); // // All off and all on pushbuttons // QPushButton* contourColorAllOnButton = new QPushButton("All On"); contourColorAllOnButton->setAutoDefault(false); QObject::connect(contourColorAllOnButton, SIGNAL(clicked()), this, SLOT(contourCellColorAllOn())); QPushButton* contourColorAllOffButton = new QPushButton("All Off"); contourColorAllOffButton->setAutoDefault(false); QObject::connect(contourColorAllOffButton, SIGNAL(clicked()), this, SLOT(contourCellColorAllOff())); QHBoxLayout* allOnOffLayout = new QHBoxLayout; allOnOffLayout->addWidget(contourColorAllOnButton); allOnOffLayout->addWidget(contourColorAllOffButton); allOnOffLayout->addStretch(); contourSubPageColorLayout->addLayout(allOnOffLayout); createAndUpdateContourCellColorCheckBoxes(); pageWidgetStack->addWidget(pageContourColor); } /** * Create and update contour color checkboxes. Because the number of colors may change, * this method may update and change the label on existing checkboxes, add new * checkboxes, and hide existing checkboxes if the number of checkboxes is greater * than the number of contour cell colors. */ void GuiDisplayControlDialog::createAndUpdateContourCellColorCheckBoxes() { ContourCellColorFile* contourCellColors = theMainWindow->getBrainSet()->getContourCellColorFile(); numValidContourCellColors = contourCellColors->getNumberOfColors(); const int numExistingCheckBoxes = static_cast(contourCellColorCheckBoxes.size()); if (contourCellColorGridLayout == NULL) { QWidget* colorWidget = new QWidget; contourCellColorGridLayout = new QGridLayout(colorWidget); const int rowStretchNumber = 15000; contourCellColorGridLayout->addWidget(new QLabel(""), rowStretchNumber, 0, Qt::AlignLeft); contourCellColorGridLayout->setRowStretch(rowStretchNumber, 1000); contourSubPageColorLayout->addWidget(colorWidget); } if (contourCellColorButtonGroup == NULL) { contourCellColorButtonGroup = new QButtonGroup(this); contourCellColorButtonGroup->setExclusive(false); QObject::connect(contourCellColorButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(readContourColorPage())); } // // Update exising checkboxes // for (int i = 0; i < numExistingCheckBoxes; i++) { if (i < numValidContourCellColors) { contourCellColorCheckBoxes[i]->setText(contourCellColors->getColorNameByIndex(i)); contourCellColorCheckBoxes[i]->show(); } } // // Add new checkboxes as needed // for (int j = numExistingCheckBoxes; j < numValidContourCellColors; j++) { QCheckBox* cb = new QCheckBox(contourCellColors->getColorNameByIndex(j)); contourCellColorCheckBoxes.push_back(cb); contourCellColorButtonGroup->addButton(cb, j); contourCellColorGridLayout->addWidget(cb, j, 0, 1, 1, Qt::AlignLeft); cb->show(); } // // Hide existing checkboxes that are not needed. // for (int k = numValidContourCellColors; k < numExistingCheckBoxes; k++) { contourCellColorCheckBoxes[k]->hide(); } } /** * This slot is called when the contour cell color all on button is pressed. */ void GuiDisplayControlDialog::contourCellColorAllOn() { ContourCellColorFile* contourCellColors = theMainWindow->getBrainSet()->getContourCellColorFile(); contourCellColors->setAllSelectedStatus(true); updateContourItems(); readContourColorPage(); } /** * This slot is called when the contour color all off button is pressed. */ void GuiDisplayControlDialog::contourCellColorAllOff() { ContourCellColorFile* contourCellColors = theMainWindow->getBrainSet()->getContourCellColorFile(); contourCellColors->setAllSelectedStatus(false); updateContourItems(); readContourColorPage(); } /** * Create the contour main page */ void GuiDisplayControlDialog::createContourMainPage() { // // origin cross // contourOriginCrossCheckBox = new QCheckBox("Show Cross at Origin"); QObject::connect(contourOriginCrossCheckBox, SIGNAL(toggled(bool)), this, SLOT(readContourMainPage())); // // draw as lines check box // QLabel* drawModeLabel = new QLabel("Draw Mode "); contourDrawModeComboBox = new QComboBox; contourDrawModeComboBox->insertItem(DisplaySettingsContours::DRAW_MODE_POINTS, "Points"); contourDrawModeComboBox->insertItem(DisplaySettingsContours::DRAW_MODE_LINES, "Lines"); contourDrawModeComboBox->insertItem(DisplaySettingsContours::DRAW_MODE_POINTS_AND_LINES, "Points and Lines"); QObject::connect(contourDrawModeComboBox, SIGNAL(activated(int)), this, SLOT(readContourMainPage())); QHBoxLayout* drawModeLayout = new QHBoxLayout; drawModeLayout->addWidget(drawModeLabel); drawModeLayout->addWidget(contourDrawModeComboBox); drawModeLayout->addStretch(); // // Show end points check box // contourShowEndPointsCheckBox = new QCheckBox("Show First Point In Each Contour In Red"); QObject::connect(contourShowEndPointsCheckBox, SIGNAL(toggled(bool)), this, SLOT(readContourMainPage())); // // point size // QLabel* pointSizeLabel = new QLabel("Point Size"); contourPointSizeSpinBox = new QDoubleSpinBox; contourPointSizeSpinBox->setMinimum(0.5); contourPointSizeSpinBox->setMaximum(20.0); contourPointSizeSpinBox->setSingleStep(1.0); contourPointSizeSpinBox->setDecimals(2); QObject::connect(contourPointSizeSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readContourMainPage())); QHBoxLayout* pointSizeLayout = new QHBoxLayout; pointSizeLayout->addWidget(pointSizeLabel); pointSizeLayout->addWidget(contourPointSizeSpinBox); pointSizeLayout->addStretch(); // // line size // QLabel* lineSizeLabel = new QLabel("Line Size"); contourLineThicknessSpinBox = new QDoubleSpinBox; contourLineThicknessSpinBox->setMinimum(0.5); contourLineThicknessSpinBox->setMaximum(20.0); contourLineThicknessSpinBox->setSingleStep(1.0); contourLineThicknessSpinBox->setDecimals(2); QObject::connect(contourLineThicknessSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readContourMainPage())); QHBoxLayout* lineSizeLayout = new QHBoxLayout; lineSizeLayout->addWidget(lineSizeLabel); lineSizeLayout->addWidget(contourLineThicknessSpinBox); lineSizeLayout->addStretch(); // // Show Contour Cells check box // contourShowCellsCheckBox = new QCheckBox("Show Contour Cells"); QObject::connect(contourShowCellsCheckBox, SIGNAL(toggled(bool)), this, SLOT(readContourMainPage())); // // Contour Cell Size // QLabel* cellSizeLabel = new QLabel("Cell Size "); contourCellSizeSpinBox = new QSpinBox; contourCellSizeSpinBox->setMinimum(1); contourCellSizeSpinBox->setMaximum(10); contourCellSizeSpinBox->setSingleStep(1); QObject::connect(contourCellSizeSpinBox, SIGNAL(valueChanged(int)), this, SLOT(readContourMainPage())); QHBoxLayout* cellSizeLayout = new QHBoxLayout; cellSizeLayout->addWidget(cellSizeLabel); cellSizeLayout->addWidget(contourCellSizeSpinBox); cellSizeLayout->addStretch(); // // Widget for Contour items // pageContourMain = new QWidget; QVBoxLayout* contourMainPageLayout = new QVBoxLayout(pageContourMain); contourMainPageLayout->addWidget(contourOriginCrossCheckBox); contourMainPageLayout->addLayout(drawModeLayout); contourMainPageLayout->addLayout(pointSizeLayout); contourMainPageLayout->addLayout(lineSizeLayout); contourMainPageLayout->addWidget(contourShowEndPointsCheckBox); contourMainPageLayout->addWidget(contourShowCellsCheckBox); contourMainPageLayout->addLayout(cellSizeLayout); contourMainPageLayout->addStretch(); pageWidgetStack->addWidget(pageContourMain); } /** * read the contour main page. */ void GuiDisplayControlDialog::readContourMainPage() { if (creatingDialog) { return; } if (pageContourMain == NULL) { return; } DisplaySettingsContours* dsc = theMainWindow->getBrainSet()->getDisplaySettingsContours(); dsc->setDisplayCrossAtOrigin(contourOriginCrossCheckBox->isChecked()); dsc->setDrawMode(static_cast(contourDrawModeComboBox->currentIndex())); dsc->setShowEndPoints(contourShowEndPointsCheckBox->isChecked()); dsc->setPointSize(contourPointSizeSpinBox->value()); dsc->setLineThickness(contourLineThicknessSpinBox->value()); dsc->setDisplayContourCells(contourShowCellsCheckBox->isChecked()); dsc->setContourCellSize(contourCellSizeSpinBox->value()); dsc->determineDisplayedContourCells(); GuiBrainModelOpenGL::updateAllGL(NULL); } /** * read the contour class page. */ void GuiDisplayControlDialog::readContourClassPage() { if (creatingDialog) { return; } if (pageContourClass == NULL) { return; } ContourCellFile* cellFile = theMainWindow->getBrainSet()->getContourCellFile(); const int numClasses = cellFile->getNumberOfCellClasses(); if (numClasses == numValidContourCellClasses) { for (int i = 0; i < numValidContourCellClasses; i++) { cellFile->setCellClassSelectedByIndex(i, contourCellClassCheckBoxes[i]->isChecked()); } } else { std::cerr << "Number of contour cell class checkboxes does not equal number of contour cell classes." << std::endl; } DisplaySettingsContours* dsc = theMainWindow->getBrainSet()->getDisplaySettingsContours(); dsc->determineDisplayedContourCells(); GuiBrainModelOpenGL::updateAllGL(NULL); } /** * read the contour color page. */ void GuiDisplayControlDialog::readContourColorPage() { if (creatingDialog) { return; } if (pageContourColor == NULL) { return; } ContourCellColorFile* contourCellColors = theMainWindow->getBrainSet()->getContourCellColorFile(); const int numColors = contourCellColors->getNumberOfColors(); if (numColors == numValidContourCellColors) { for (int i = 0; i < numValidContourCellColors; i++) { contourCellColors->setSelected(i, contourCellColorCheckBoxes[i]->isChecked()); } } else { std::cerr << "Number of contour cell color checkboxes does not equal number of contour cell classes." << std::endl; } DisplaySettingsContours* dsc = theMainWindow->getBrainSet()->getDisplaySettingsContours(); dsc->determineDisplayedContourCells(); GuiBrainModelOpenGL::updateAllGL(NULL); } /** * update all contour main page in dialog. */ void GuiDisplayControlDialog::updateContourMainPage() { if (pageContourMain == NULL) { return; } pageContourMain->setEnabled(validContourData); DisplaySettingsContours* dsc = theMainWindow->getBrainSet()->getDisplaySettingsContours(); contourOriginCrossCheckBox->setChecked(dsc->getDisplayCrossAtOrigin()); contourDrawModeComboBox->setCurrentIndex(dsc->getDrawMode()); contourShowEndPointsCheckBox->setChecked(dsc->getShowEndPoints()); contourPointSizeSpinBox->setValue(dsc->getPointSize()); contourLineThicknessSpinBox->setValue(dsc->getLineThickness()); contourShowCellsCheckBox->setChecked(dsc->getDisplayContourCells()); contourCellSizeSpinBox->setValue(static_cast(dsc->getContourCellSize())); } /** * update all contour class page in dialog. */ void GuiDisplayControlDialog::updateContourClassPage(const bool filesChanged) { if (pageContourClass == NULL) { return; } pageContourClass->setEnabled(validContourData); if (filesChanged) { createAndUpdateContourCellClassCheckBoxes(); } ContourCellFile* contourCellFile = theMainWindow->getBrainSet()->getContourCellFile(); const int numClasses = contourCellFile->getNumberOfCellClasses(); if (numClasses == numValidContourCellClasses) { for (int i = 0; i < numValidContourCellClasses; i++) { contourCellClassCheckBoxes[i]->setChecked(contourCellFile->getCellClassSelectedByIndex(i)); } } else { std::cerr << "Number of contour cell class checkboxes does not equal number of contour cell classes." << std::endl; } } /** * update all contour color page in dialog. */ void GuiDisplayControlDialog::updateContourColorPage(const bool filesChanged) { if (pageContourColor == NULL) { return; } pageContourColor->setEnabled(validContourData); if (filesChanged) { createAndUpdateContourCellColorCheckBoxes(); } ContourCellColorFile* contourCellColorFile = theMainWindow->getBrainSet()->getContourCellColorFile(); const int numColors = contourCellColorFile->getNumberOfColors(); if (numColors == numValidContourCellColors) { for (int i = 0; i < numValidContourCellColors; i++) { contourCellColorCheckBoxes[i]->setChecked(contourCellColorFile->getSelected(i)); } } else { std::cerr << "Number of contour cell color checkboxes does not equal number of contour cell colors." << std::endl; } } /** * Update the contour items */ void GuiDisplayControlDialog::updateContourItems(const bool filesChanged) { updatePageSelectionComboBox(); updateContourMainPage(); updateContourClassPage(filesChanged); updateContourColorPage(filesChanged); } /** * Create the CoCoMac Display control sub page. */ void GuiDisplayControlDialog::createCocomacDisplayPage() { // // Connection radio buttons // cocomacAfferentRadioButton = new QRadioButton("Afferent"); cocomacEfferentRadioButton = new QRadioButton("Efferent"); cocomacAfferentAndEfferentRadioButton = new QRadioButton("Afferent and Efferent"); cocomacAfferentOrEfferentRadioButton = new QRadioButton("Afferent or Efferent"); // // button group for connection display type // QButtonGroup* connBG = new QButtonGroup(this); QObject::connect(connBG, SIGNAL(buttonClicked(int)), this, SLOT(readCocomacDisplayPage())); connBG->addButton(cocomacAfferentRadioButton); connBG->addButton(cocomacEfferentRadioButton); connBG->addButton(cocomacAfferentAndEfferentRadioButton); connBG->addButton(cocomacAfferentOrEfferentRadioButton); // // Group box and layout for connection type buttons // QGroupBox* connGroupBox = new QGroupBox("View Connection"); QVBoxLayout* connGroupLayout = new QVBoxLayout(connGroupBox); connGroupLayout->addWidget(cocomacAfferentRadioButton); connGroupLayout->addWidget(cocomacEfferentRadioButton); connGroupLayout->addWidget(cocomacAfferentAndEfferentRadioButton); connGroupLayout->addWidget(cocomacAfferentOrEfferentRadioButton); // // Paint column label and combo box // QLabel* paintLabel = new QLabel("Paint Column "); cocomacPaintColumnComboBox = new QComboBox; cocomacPaintColumnComboBox->setMinimumWidth(400); QObject::connect(cocomacPaintColumnComboBox, SIGNAL(activated(int)), this, SLOT(readCocomacDisplayPage())); QHBoxLayout* paintLayout = new QHBoxLayout; paintLayout->addWidget(paintLabel); paintLayout->addWidget(cocomacPaintColumnComboBox); paintLayout->setStretchFactor(paintLabel, 0); paintLayout->setStretchFactor(cocomacPaintColumnComboBox, 100); // // Create the page and layout its widgets // pageCocomacDisplay = new QWidget; QVBoxLayout* cocoLayout = new QVBoxLayout(pageCocomacDisplay); cocoLayout->addWidget(connGroupBox); cocoLayout->addLayout(paintLayout); cocoLayout->addStretch(); pageWidgetStack->addWidget(pageCocomacDisplay); } /** * Create the CoCoMac File Info sub page. */ void GuiDisplayControlDialog::createCocomacFileInformationPage() { // // CoCoMac version label // QString spaces(" "); cocomacVersionLabel = new QLabel(spaces); // // CoCoMac export date // cocomacExportDate = new QLabel(spaces); // // CoCoMac data type // cocomacDataType = new QLabel(spaces); // // comments text area // cocomacCommentsTextEdit = new QTextEdit; cocomacCommentsTextEdit->setFixedSize(QSize(500, 150)); // // Projections text area // cocomacProjectionsTextEdit = new QTextEdit; cocomacProjectionsTextEdit->setFixedSize(QSize(500, 300)); // // Page and layout // pageCocomacInformation = new QWidget; QVBoxLayout* cocoLayout = new QVBoxLayout(pageCocomacInformation); cocoLayout->addWidget(cocomacVersionLabel); cocoLayout->addWidget(cocomacExportDate); cocoLayout->addWidget(cocomacDataType); cocoLayout->addWidget(cocomacCommentsTextEdit); cocoLayout->addWidget(cocomacProjectionsTextEdit); cocoLayout->addStretch(); pageWidgetStack->addWidget(pageCocomacInformation); } /** * Read the CoCoMac selections. */ void GuiDisplayControlDialog::readCocomacDisplayPage() { if (pageCocomacDisplay == NULL) { return; } DisplaySettingsCoCoMac* dsc = theMainWindow->getBrainSet()->getDisplaySettingsCoCoMac(); if (cocomacAfferentRadioButton->isChecked()) { dsc->setConnectionDisplayType(DisplaySettingsCoCoMac::CONNECTION_DISPLAY_AFFERENT); } else if (cocomacEfferentRadioButton->isChecked()) { dsc->setConnectionDisplayType(DisplaySettingsCoCoMac::CONNECTION_DISPLAY_EFFERENT); } else if (cocomacAfferentAndEfferentRadioButton->isChecked()) { dsc->setConnectionDisplayType(DisplaySettingsCoCoMac::CONNECTION_DISPLAY_AFFERENT_AND_EFFERENT); } else if (cocomacAfferentOrEfferentRadioButton->isChecked()) { dsc->setConnectionDisplayType(DisplaySettingsCoCoMac::CONNECTION_DISPLAY_AFFERENT_OR_EFFERENT); } dsc->setSelectedPaintColumn(cocomacPaintColumnComboBox->currentIndex()); } /** * update the cocomac display page. */ void GuiDisplayControlDialog::updateCocomacDisplayPage() { if (pageCocomacDisplay == NULL) { return; } DisplaySettingsCoCoMac* dsc = theMainWindow->getBrainSet()->getDisplaySettingsCoCoMac(); CocomacConnectivityFile* cocomacFile = theMainWindow->getBrainSet()->getCocomacFile(); switch(dsc->getConnectionDisplayType()) { case DisplaySettingsCoCoMac::CONNECTION_DISPLAY_AFFERENT: cocomacAfferentRadioButton->setChecked(true); break; case DisplaySettingsCoCoMac::CONNECTION_DISPLAY_EFFERENT: cocomacEfferentRadioButton->setChecked(true); break; case DisplaySettingsCoCoMac::CONNECTION_DISPLAY_AFFERENT_AND_EFFERENT: cocomacAfferentAndEfferentRadioButton->setChecked(true); break; case DisplaySettingsCoCoMac::CONNECTION_DISPLAY_AFFERENT_OR_EFFERENT: cocomacAfferentOrEfferentRadioButton->setChecked(true); break; } cocomacPaintColumnComboBox->clear(); PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); for (int i = 0; i < pf->getNumberOfColumns(); i++) { cocomacPaintColumnComboBox->addItem(pf->getColumnName(i)); } if (cocomacPaintColumnComboBox->count() > 0) { int num = dsc->getSelectedPaintColumn(); if (num >= cocomacPaintColumnComboBox->count()) { num = 0; dsc->setSelectedPaintColumn(num); } cocomacPaintColumnComboBox->setCurrentIndex(num); } pageCocomacDisplay->setEnabled(cocomacFile->empty() == false); } /** * update the cocomac information page. */ void GuiDisplayControlDialog::updateCocomacInformationPage() { if (pageCocomacInformation == NULL) { return; } CocomacConnectivityFile* cocomacFile = theMainWindow->getBrainSet()->getCocomacFile(); QString version("Version: "); version.append(cocomacFile->getVersion()); cocomacVersionLabel->setText(version); QString exportDate("Export Date: "); exportDate.append(cocomacFile->getExportDate()); cocomacExportDate->setText(exportDate); QString dataType("Data Type: "); dataType.append(cocomacFile->getDataType()); cocomacDataType->setText(dataType); cocomacCommentsTextEdit->setPlainText(cocomacFile->getComments()); QString projections; const int numProj = cocomacFile->getNumberOfCocomacProjections(); for (int i = 0; i < numProj; i++) { CocomacProjection* proj = cocomacFile->getCocomacProjection(i); projections.append(proj->getSourceSite()); projections.append(" "); projections.append(proj->getDensity()); projections.append(" "); projections.append(proj->getTargetSite()); projections.append("\n"); } cocomacProjectionsTextEdit->setPlainText(projections); pageCocomacInformation->setEnabled(cocomacFile->empty() == false); } /** * Update the CoCoMac items in the dialog. */ void GuiDisplayControlDialog::updateCocomacItems() { updatePageSelectionComboBox(); updateCocomacDisplayPage(); updateCocomacInformationPage(); } /** * Create the surface and volume page */ void GuiDisplayControlDialog::createSurfaceAndVolumePage() { // // Show surface check box // surfaceAndVolumeShowSurfaceCheckBox = new QCheckBox("Show Surface"); QObject::connect(surfaceAndVolumeShowSurfaceCheckBox, SIGNAL(toggled(bool)), this, SLOT(readSurfaceAndVolumeSelections())); // // Group box for surface control // QGroupBox* surfaceGroupBox = new QGroupBox("Surface"); QVBoxLayout* surfaceGroupLayout = new QVBoxLayout(surfaceGroupBox); surfaceGroupLayout->addWidget(surfaceAndVolumeShowSurfaceCheckBox); surfaceGroupBox->setFixedSize(surfaceGroupBox->sizeHint()); // // check box and spin box for horizontal slice // surfaceAndVolumeHorizontalSliceCheckBox = new QCheckBox("Horizontal Slice"); QObject::connect(surfaceAndVolumeHorizontalSliceCheckBox, SIGNAL(toggled(bool)), this, SLOT(readSurfaceAndVolumeSelections())); surfaceAndVolumeHorizontalSliceSpinBox = new QSpinBox; surfaceAndVolumeHorizontalSliceSpinBox->setMinimum(1); surfaceAndVolumeHorizontalSliceSpinBox->setMaximum(10000); surfaceAndVolumeHorizontalSliceSpinBox->setSingleStep(1); QObject::connect(surfaceAndVolumeHorizontalSliceSpinBox, SIGNAL(valueChanged(int)), this, SLOT(readSurfaceAndVolumeSelections())); // // check box and spin box for parasagittal slice // surfaceAndVolumeParasagittalSliceCheckBox = new QCheckBox("Parasagittal Slice"); QObject::connect(surfaceAndVolumeParasagittalSliceCheckBox, SIGNAL(toggled(bool)), this, SLOT(readSurfaceAndVolumeSelections())); surfaceAndVolumeParasagittalSliceSpinBox = new QSpinBox; surfaceAndVolumeParasagittalSliceSpinBox->setMinimum(1); surfaceAndVolumeParasagittalSliceSpinBox->setMaximum(10000); surfaceAndVolumeParasagittalSliceSpinBox->setSingleStep(1); QObject::connect(surfaceAndVolumeParasagittalSliceSpinBox, SIGNAL(valueChanged(int)), this, SLOT(readSurfaceAndVolumeSelections())); // // check box and spin box for coronal slice // surfaceAndVolumeCoronalSliceCheckBox = new QCheckBox("Coronal Slice"); QObject::connect(surfaceAndVolumeCoronalSliceCheckBox, SIGNAL(toggled(bool)), this, SLOT(readSurfaceAndVolumeSelections())); surfaceAndVolumeCoronalSliceSpinBox = new QSpinBox; surfaceAndVolumeCoronalSliceSpinBox->setMinimum(1); surfaceAndVolumeCoronalSliceSpinBox->setMaximum(10000); surfaceAndVolumeCoronalSliceSpinBox->setSingleStep(1); QObject::connect(surfaceAndVolumeCoronalSliceSpinBox, SIGNAL(valueChanged(int)), this, SLOT(readSurfaceAndVolumeSelections())); surfaceAndVolumeAnatomyBlackCheckBox = new QCheckBox("Draw Black Voxels"); QObject::connect(surfaceAndVolumeAnatomyBlackCheckBox, SIGNAL(toggled(bool)), this, SLOT(readSurfaceAndVolumeSelections())); // // Group box for anatomical slices // QGroupBox* anatomyGroupBox = new QGroupBox("Anatomy Volume"); QGridLayout* anatomyGridLayout = new QGridLayout(anatomyGroupBox); anatomyGridLayout->addWidget(surfaceAndVolumeHorizontalSliceCheckBox, 0, 0); anatomyGridLayout->addWidget(surfaceAndVolumeHorizontalSliceSpinBox, 0, 1); anatomyGridLayout->addWidget(surfaceAndVolumeParasagittalSliceCheckBox, 1, 0); anatomyGridLayout->addWidget(surfaceAndVolumeParasagittalSliceSpinBox, 1, 1); anatomyGridLayout->addWidget(surfaceAndVolumeCoronalSliceCheckBox, 2, 0); anatomyGridLayout->addWidget(surfaceAndVolumeCoronalSliceSpinBox, 2, 1); anatomyGridLayout->addWidget(surfaceAndVolumeAnatomyBlackCheckBox, 3, 0); anatomyGroupBox->setFixedSize(anatomyGroupBox->sizeHint()); // // show primary overlay on slices // surfaceAndVolumeShowPrimaryCheckBox = new QCheckBox("Show Primary Overlay"); QObject::connect(surfaceAndVolumeShowPrimaryCheckBox, SIGNAL(toggled(bool)), this, SLOT(readSurfaceAndVolumeSelections())); // // show secondary overlay on slices // surfaceAndVolumeShowSecondaryCheckBox = new QCheckBox("Show Secondary Overlay"); QObject::connect(surfaceAndVolumeShowSecondaryCheckBox, SIGNAL(toggled(bool)), this, SLOT(readSurfaceAndVolumeSelections())); // // Group box for overlay volume control // QGroupBox* surfaceAndVolumeOverlaysGroupBox = new QGroupBox("Volume Overlays"); QVBoxLayout* surfaceAndVolumeOverlaysGroupBoxLayout = new QVBoxLayout(surfaceAndVolumeOverlaysGroupBox); surfaceAndVolumeOverlaysGroupBoxLayout->addWidget(surfaceAndVolumeShowPrimaryCheckBox); surfaceAndVolumeOverlaysGroupBoxLayout->addWidget(surfaceAndVolumeShowSecondaryCheckBox); surfaceAndVolumeOverlaysGroupBox->setFixedSize(surfaceAndVolumeOverlaysGroupBox->sizeHint()); // // Show functional data cloud checkbox // surfaceAndVolumeShowFunctionalCloudCheckBox = new QCheckBox("Show Volume Cloud"); QObject::connect(surfaceAndVolumeShowFunctionalCloudCheckBox, SIGNAL(toggled(bool)), this, SLOT(readSurfaceAndVolumeSelections())); // // Functional data cloud opacity check box and spin box // surfaceAndVolumeFunctionalCloudOpacityCheckBox = new QCheckBox("Opacity"); QObject::connect(surfaceAndVolumeFunctionalCloudOpacityCheckBox, SIGNAL(toggled(bool)), this, SLOT(readSurfaceAndVolumeSelections())); surfaceAndVolumeFunctionalCloudOpacitySpinBox = new QDoubleSpinBox; surfaceAndVolumeFunctionalCloudOpacitySpinBox->setMinimum(0.0); surfaceAndVolumeFunctionalCloudOpacitySpinBox->setMaximum(1.0); surfaceAndVolumeFunctionalCloudOpacitySpinBox->setSingleStep(0.05); surfaceAndVolumeFunctionalCloudOpacitySpinBox->setDecimals(3); QObject::connect(surfaceAndVolumeFunctionalCloudOpacitySpinBox, SIGNAL(valueChanged(double)), this, SLOT(readSurfaceAndVolumeSelections())); QHBoxLayout* functionalVolumeLayout = new QHBoxLayout; functionalVolumeLayout->addWidget(surfaceAndVolumeFunctionalCloudOpacityCheckBox); functionalVolumeLayout->addWidget(surfaceAndVolumeFunctionalCloudOpacitySpinBox); // // Group box for functional volume control // surfaceAndVolumeFunctionalGroupBox = new QGroupBox("Functional Volume"); QVBoxLayout* surfaceAndVolumeFunctionalGroupLayout = new QVBoxLayout(surfaceAndVolumeFunctionalGroupBox); surfaceAndVolumeFunctionalGroupLayout->addWidget(surfaceAndVolumeShowFunctionalCloudCheckBox); surfaceAndVolumeFunctionalGroupLayout->addLayout(functionalVolumeLayout); // // Distance threshold // surfaceAndVolumeFunctionalDistanceSpinBox = new QDoubleSpinBox; surfaceAndVolumeFunctionalDistanceSpinBox->setMinimum(0.0); surfaceAndVolumeFunctionalDistanceSpinBox->setMaximum(1000.0); surfaceAndVolumeFunctionalDistanceSpinBox->setSingleStep(10.0); surfaceAndVolumeFunctionalDistanceSpinBox->setDecimals(1); QObject::connect(surfaceAndVolumeFunctionalDistanceSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readSurfaceAndVolumeSelections())); surfaceAndVolumeFunctionalGroupBox->setFixedSize(surfaceAndVolumeFunctionalGroupBox->sizeHint()); QGroupBox* distanceGroupBox = new QGroupBox("Distance Threshold"); QVBoxLayout* distanceGroupLayout = new QVBoxLayout(distanceGroupBox); distanceGroupLayout->addWidget(surfaceAndVolumeFunctionalDistanceSpinBox); distanceGroupBox->setFixedSize(distanceGroupBox->sizeHint()); distanceGroupBox->hide(); // // Show segmentation data cloud checkbox // surfaceAndVolumeShowSegmentationCloudCheckBox = new QCheckBox("Show Volume Cloud"); QObject::connect(surfaceAndVolumeShowSegmentationCloudCheckBox, SIGNAL(toggled(bool)), this, SLOT(readSurfaceAndVolumeSelections())); // // Group box for segmentation volume control // surfaceAndVolumeSegmentationGroupBox = new QGroupBox("Segmentation Volume"); QVBoxLayout* surfaceAndVolumeSegmentationGroupLayout = new QVBoxLayout(surfaceAndVolumeSegmentationGroupBox); surfaceAndVolumeSegmentationGroupLayout->addWidget(surfaceAndVolumeShowSegmentationCloudCheckBox); surfaceAndVolumeSegmentationGroupBox->setFixedSize(surfaceAndVolumeSegmentationGroupBox->sizeHint()); // // Show vector data cloud check box // surfaceAndVolumeShowVectorCloudCheckBox = new QCheckBox("Show Volume Cloud"); QObject::connect(surfaceAndVolumeShowVectorCloudCheckBox, SIGNAL(toggled(bool)), this, SLOT(readSurfaceAndVolumeSelections())); surfaceAndVolumeVectorVBox = new QGroupBox("Vector Volume"); QVBoxLayout* surfaceAndVolumeVectorLayout = new QVBoxLayout(surfaceAndVolumeVectorVBox); surfaceAndVolumeVectorLayout->addWidget(surfaceAndVolumeShowVectorCloudCheckBox); surfaceAndVolumeVectorVBox->setFixedSize(surfaceAndVolumeVectorVBox->sizeHint()); // // Create page ang its layout // pageSurfaceAndVolume = new QWidget; pageWidgetStack->addWidget(pageSurfaceAndVolume); //, PAGE_NAME_SURFACE_AND_VOLUME); QVBoxLayout* surfaceAndVolumeLayout = new QVBoxLayout(pageSurfaceAndVolume); surfaceAndVolumeLayout->addWidget(surfaceGroupBox); surfaceAndVolumeLayout->addWidget(anatomyGroupBox); surfaceAndVolumeLayout->addWidget(surfaceAndVolumeOverlaysGroupBox); surfaceAndVolumeLayout->addWidget(surfaceAndVolumeFunctionalGroupBox); surfaceAndVolumeLayout->addWidget(distanceGroupBox); surfaceAndVolumeLayout->addWidget(surfaceAndVolumeSegmentationGroupBox); surfaceAndVolumeLayout->addWidget(surfaceAndVolumeVectorVBox); surfaceAndVolumeLayout->addStretch(); pageSurfaceAndVolumeWidgetGroup = new WuQWidgetGroup(this); pageSurfaceAndVolumeWidgetGroup->addWidget(surfaceAndVolumeShowSurfaceCheckBox); pageSurfaceAndVolumeWidgetGroup->addWidget(surfaceAndVolumeHorizontalSliceCheckBox); pageSurfaceAndVolumeWidgetGroup->addWidget(surfaceAndVolumeParasagittalSliceCheckBox); pageSurfaceAndVolumeWidgetGroup->addWidget(surfaceAndVolumeCoronalSliceCheckBox); pageSurfaceAndVolumeWidgetGroup->addWidget(surfaceAndVolumeCoronalSliceSpinBox); pageSurfaceAndVolumeWidgetGroup->addWidget(surfaceAndVolumeAnatomyBlackCheckBox); pageSurfaceAndVolumeWidgetGroup->addWidget(surfaceAndVolumeShowPrimaryCheckBox); pageSurfaceAndVolumeWidgetGroup->addWidget(surfaceAndVolumeShowSecondaryCheckBox); pageSurfaceAndVolumeWidgetGroup->addWidget(surfaceAndVolumeShowFunctionalCloudCheckBox); pageSurfaceAndVolumeWidgetGroup->addWidget(surfaceAndVolumeFunctionalCloudOpacityCheckBox); pageSurfaceAndVolumeWidgetGroup->addWidget(surfaceAndVolumeFunctionalCloudOpacitySpinBox); pageSurfaceAndVolumeWidgetGroup->addWidget(surfaceAndVolumeShowSegmentationCloudCheckBox); pageSurfaceAndVolumeWidgetGroup->addWidget(surfaceAndVolumeShowVectorCloudCheckBox); } /** * Read the selections on the surface and volume page. */ void GuiDisplayControlDialog::readSurfaceAndVolumeSelections() { BrainModelSurfaceAndVolume* bmsv = theMainWindow->getBrainSet()->getBrainModelSurfaceAndVolume(); if (bmsv != NULL) { // // Setting the checkboxes of volume slices in "updateSurfaceAndVolumeItems()" // triggers QT signals which then call this method. So see if items are // being updated in the dialog. // bmsv->setDisplaySurface(surfaceAndVolumeShowSurfaceCheckBox->isChecked()); bmsv->setDisplayHorizontalSlice(surfaceAndVolumeHorizontalSliceCheckBox->isChecked()); bmsv->setDisplayParasagittalSlice(surfaceAndVolumeParasagittalSliceCheckBox->isChecked()); bmsv->setDisplayCoronalSlice(surfaceAndVolumeCoronalSliceCheckBox->isChecked()); const int slices[3] = { surfaceAndVolumeParasagittalSliceSpinBox->value(), surfaceAndVolumeCoronalSliceSpinBox->value(), surfaceAndVolumeHorizontalSliceSpinBox->value() }; bmsv->setSelectedSlices(slices); bmsv->setDisplayPrimaryOverlayVolumeOnSlices(surfaceAndVolumeShowPrimaryCheckBox->isChecked()); bmsv->setDisplaySecondaryOverlayVolumeOnSlices(surfaceAndVolumeShowSecondaryCheckBox->isChecked()); bmsv->setDisplayFunctionalVolumeCloud(surfaceAndVolumeShowFunctionalCloudCheckBox->isChecked()); bmsv->setFunctionalVolumeCloudOpacityEnabled(surfaceAndVolumeFunctionalCloudOpacityCheckBox->isChecked()); bmsv->setFunctionalVolumeCloudOpacity(surfaceAndVolumeFunctionalCloudOpacitySpinBox->value()); bmsv->setFunctionalVolumeDistanceThreshold(surfaceAndVolumeFunctionalDistanceSpinBox->value()); bmsv->setDisplaySegmentationVolumeCloud(surfaceAndVolumeShowSegmentationCloudCheckBox->isChecked()); bmsv->setDisplayVectorVolumeCloud(surfaceAndVolumeShowVectorCloudCheckBox->isChecked()); bmsv->setDrawAnatomyBlackVoxels(surfaceAndVolumeAnatomyBlackCheckBox->isChecked()); } GuiBrainModelOpenGL::updateAllGL(); } /** * update the surface and volume selections. */ void GuiDisplayControlDialog::updateSurfaceAndVolumeItems() { updatePageSelectionComboBox(); if (pageSurfaceAndVolume == NULL) { return; } pageSurfaceAndVolumeWidgetGroup->blockSignals(true); BrainModelSurfaceAndVolume* bmsv = theMainWindow->getBrainSet()->getBrainModelSurfaceAndVolume(); if (bmsv != NULL) { pageSurfaceAndVolume->setEnabled(validSurfaceAndVolumeData); surfaceAndVolumeShowSurfaceCheckBox->setChecked(bmsv->getDisplaySurface()); surfaceAndVolumeHorizontalSliceCheckBox->setChecked(bmsv->getDisplayHorizontalSlice()); surfaceAndVolumeParasagittalSliceCheckBox->setChecked(bmsv->getDisplayParasagittalSlice()); surfaceAndVolumeCoronalSliceCheckBox->setChecked(bmsv->getDisplayCoronalSlice()); int dim[3] = { 0, 0, 0 }; VolumeFile* anatomyVolumeFile = bmsv->getAnatomyVolumeFile(); if (anatomyVolumeFile != NULL) { anatomyVolumeFile->getDimensions(dim); } surfaceAndVolumeParasagittalSliceSpinBox->setMaximum(dim[0]); surfaceAndVolumeCoronalSliceSpinBox->setMaximum(dim[1]); surfaceAndVolumeHorizontalSliceSpinBox->setMaximum(dim[2]); int slices[3]; bmsv->getSelectedSlices(slices); surfaceAndVolumeParasagittalSliceSpinBox->setValue(slices[0]); surfaceAndVolumeCoronalSliceSpinBox->setValue(slices[1]); surfaceAndVolumeHorizontalSliceSpinBox->setValue(slices[2]); surfaceAndVolumeShowPrimaryCheckBox->setChecked(bmsv->getDisplayPrimaryOverlayVolumeOnSlices()); surfaceAndVolumeShowSecondaryCheckBox->setChecked(bmsv->getDisplaySecondaryOverlayVolumeOnSlices()); if (bmsv->getFunctionalVolumeFile() != NULL) { surfaceAndVolumeFunctionalGroupBox->setEnabled(true); surfaceAndVolumeShowFunctionalCloudCheckBox->setChecked(bmsv->getDisplayFunctionalVolumeCloud()); surfaceAndVolumeFunctionalCloudOpacityCheckBox->setChecked(bmsv->getFunctionalVolumeCloudOpacityEnabled()); surfaceAndVolumeFunctionalCloudOpacitySpinBox->setValue(bmsv->getFunctionalVolumeCloudOpacity()); } else { surfaceAndVolumeFunctionalGroupBox->setEnabled(false); } surfaceAndVolumeFunctionalDistanceSpinBox->setValue(bmsv->getFunctionalVolumeDistanceThreshold()); if (bmsv->getSegmentationVolumeFile() != NULL) { surfaceAndVolumeSegmentationGroupBox->setEnabled(true); surfaceAndVolumeShowSegmentationCloudCheckBox->setChecked(bmsv->getDisplaySegmentationVolumeCloud()); } else { surfaceAndVolumeSegmentationGroupBox->setEnabled(false); } surfaceAndVolumeAnatomyBlackCheckBox->setChecked(bmsv->getDrawAnatomyBlackVoxels()); if (bmsv->getVectorVolumeFile() != NULL) { surfaceAndVolumeVectorVBox->setEnabled(true); surfaceAndVolumeShowVectorCloudCheckBox->setChecked(bmsv->getDisplayVectorVolumeCloud()); } else { surfaceAndVolumeVectorVBox->setEnabled(false); } } else { pageSurfaceAndVolume->setEnabled(false); } updatePageSelectionComboBox(); pageSurfaceAndVolumeWidgetGroup->blockSignals(false); } /** * create the surface vector settings page. */ void GuiDisplayControlDialog::createVectorSettingsPage() { const int spinBoxMaxWidth = 200; // // Color Mode // QLabel* colorModeLabel = new QLabel("Coloring Mode"); vectorColorModeComboBox = new QComboBox; vectorColorModeComboBox->insertItem(DisplaySettingsVectors::COLOR_MODE_VECTOR_COLORS, "Use Vector Colors"); vectorColorModeComboBox->insertItem(DisplaySettingsVectors::COLOR_MODE_XYZ_AS_RGB, "Use XYZ as Red, Green, Blue"); QObject::connect(vectorColorModeComboBox, SIGNAL(activated(int)), this, SLOT(readVectorSettingsPage())); // // Vector Type // QLabel* vectorTypeLabel = new QLabel("Vector Type"); vectorTypeModeComboBox = new QComboBox; vectorTypeModeComboBox->insertItem(DisplaySettingsVectors::VECTOR_TYPE_BIDIRECTIONAL, "Bidirectional"); vectorTypeModeComboBox->insertItem(DisplaySettingsVectors::VECTOR_TYPE_UNIDIRECTIONAL_ARROW, "Unidirectional (Arrow)"); vectorTypeModeComboBox->insertItem(DisplaySettingsVectors::VECTOR_TYPE_UNIDIRECTIONAL_CYLINDER, "Unidirectional (Cylinder)"); QObject::connect(vectorTypeModeComboBox, SIGNAL(activated(int)), this, SLOT(readVectorSettingsPage())); // // Sparse distance spin box // QLabel* sparseDistanceLabel = new QLabel("Sparse Index Skip"); vectorSparseDistanceSpinBox = new QSpinBox; vectorSparseDistanceSpinBox->setMaximumWidth(spinBoxMaxWidth); vectorSparseDistanceSpinBox->setMinimum(0); vectorSparseDistanceSpinBox->setMaximum(100000); vectorSparseDistanceSpinBox->setSingleStep(1); QObject::connect(vectorSparseDistanceSpinBox, SIGNAL(valueChanged(int)), this, SLOT(readVectorSettingsPage())); vectorSparseDistanceSpinBox->setToolTip("Number of indices skipped when \n" "drawing vectors in a sparse mode."); // // Length multiplier // QLabel* lengthLabel = new QLabel("Length Multiplier "); vectorLengthMultiplierDoubleSpinBox = new QDoubleSpinBox; vectorLengthMultiplierDoubleSpinBox->setMaximumWidth(spinBoxMaxWidth); vectorLengthMultiplierDoubleSpinBox->setMinimum(0.0001); vectorLengthMultiplierDoubleSpinBox->setMaximum(1000.0); vectorLengthMultiplierDoubleSpinBox->setSingleStep(1.0); vectorLengthMultiplierDoubleSpinBox->setDecimals(3); vectorLengthMultiplierDoubleSpinBox->setValue(1.0); QObject::connect(vectorLengthMultiplierDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readVectorSettingsPage())); vectorLengthMultiplierDoubleSpinBox->setToolTip("Scales the length of\n" "vectors for display."); // // Drawing group box and layout // QGroupBox* drawingGroupBox = new QGroupBox("Drawing"); QGridLayout* drawGridLayout = new QGridLayout(drawingGroupBox); drawGridLayout->addWidget(colorModeLabel, 0, 0); drawGridLayout->addWidget(vectorColorModeComboBox, 0, 1); drawGridLayout->addWidget(vectorTypeLabel, 1, 0); drawGridLayout->addWidget(vectorTypeModeComboBox, 1, 1); drawGridLayout->addWidget(sparseDistanceLabel, 2, 0); drawGridLayout->addWidget(vectorSparseDistanceSpinBox, 2, 1); drawGridLayout->addWidget(lengthLabel, 3, 0); drawGridLayout->addWidget(vectorLengthMultiplierDoubleSpinBox, 3, 1); drawingGroupBox->setFixedSize(drawingGroupBox->sizeHint()); //=========================================================================== // // Surface Symbol // QLabel* surfaceSymbolLabel = new QLabel("Symbol"); vectorSurfaceSymbolComboBox = new QComboBox; vectorSurfaceSymbolComboBox->insertItem(DisplaySettingsVectors::SURFACE_SYMBOL_3D, "3D Symbol"); vectorSurfaceSymbolComboBox->insertItem(DisplaySettingsVectors::SURFACE_SYMBOL_2D_LINE, "2D Line"); QObject::connect(vectorSurfaceSymbolComboBox, SIGNAL(activated(int)), this, SLOT(readVectorSettingsPage())); // // Display mode surface // QLabel* displayModeSurfaceLabel = new QLabel("Display Mode"); vectorDisplayModeSurfaceComboBox = new QComboBox; vectorDisplayModeSurfaceComboBox->insertItem(DisplaySettingsVectors::DISPLAY_MODE_ALL, "All"); vectorDisplayModeSurfaceComboBox->insertItem(DisplaySettingsVectors::DISPLAY_MODE_NONE, "None"); vectorDisplayModeSurfaceComboBox->insertItem(DisplaySettingsVectors::DISPLAY_MODE_SPARSE, "Sparse"); QObject::connect(vectorDisplayModeSurfaceComboBox, SIGNAL(activated(int)), this, SLOT(readVectorSettingsPage())); // // Surface line width // float minLineWidth = 0.0, maxLineWidth = 10.0; BrainModelOpenGL::getMinMaxLineWidth(minLineWidth, maxLineWidth); QLabel* surfaceLineWidthLabel = new QLabel("Line Width"); vectorSurfaceLineWidthSpinBox = new QDoubleSpinBox; vectorSurfaceLineWidthSpinBox->setMaximumWidth(spinBoxMaxWidth); vectorSurfaceLineWidthSpinBox->setMinimum(minLineWidth); vectorSurfaceLineWidthSpinBox->setMaximum(maxLineWidth); vectorSurfaceLineWidthSpinBox->setSingleStep(1.0); vectorSurfaceLineWidthSpinBox->setDecimals(2); QObject::connect(vectorSurfaceLineWidthSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readVectorSettingsPage())); vectorSurfaceLineWidthSpinBox->setToolTip("Controls width of vectors drawn\n" "as lines in 2D on a surface."); // // Surface Display Layout // QGroupBox* surfaceDisplayGroupBox = new QGroupBox("Surface Display"); QGridLayout* surfaceGridLayout = new QGridLayout(surfaceDisplayGroupBox); surfaceGridLayout->addWidget(displayModeSurfaceLabel, 0, 0); surfaceGridLayout->addWidget(vectorDisplayModeSurfaceComboBox, 0, 1); surfaceGridLayout->addWidget(surfaceSymbolLabel, 1, 0); surfaceGridLayout->addWidget(vectorSurfaceSymbolComboBox, 1, 1); surfaceGridLayout->addWidget(surfaceLineWidthLabel, 2, 0); surfaceGridLayout->addWidget(vectorSurfaceLineWidthSpinBox, 2, 1); surfaceDisplayGroupBox->setFixedSize(surfaceDisplayGroupBox->sizeHint()); //=========================================================================== // // Volume Display mode // QLabel* displayModeVolumeLabel = new QLabel("Display Mode"); vectorDisplayModeVolumeComboBox = new QComboBox; vectorDisplayModeVolumeComboBox->insertItem(DisplaySettingsVectors::DISPLAY_MODE_ALL, "All"); vectorDisplayModeVolumeComboBox->insertItem(DisplaySettingsVectors::DISPLAY_MODE_NONE, "None"); vectorDisplayModeVolumeComboBox->insertItem(DisplaySettingsVectors::DISPLAY_MODE_SPARSE, "Sparse"); QObject::connect(vectorDisplayModeVolumeComboBox, SIGNAL(activated(int)), this, SLOT(readVectorSettingsPage())); // // Volume slice above limit // QLabel* volumeSliceAboveLimitLabel = new QLabel("Slice Above Limit"); vectorVolumeSliceAboveLimitSpinBox = new QDoubleSpinBox; vectorVolumeSliceAboveLimitSpinBox->setMaximumWidth(spinBoxMaxWidth); vectorVolumeSliceAboveLimitSpinBox->setMinimum(0.0); vectorVolumeSliceAboveLimitSpinBox->setMaximum(1000000.0); vectorVolumeSliceAboveLimitSpinBox->setSingleStep(0.1); vectorVolumeSliceAboveLimitSpinBox->setDecimals(2); QObject::connect(vectorVolumeSliceAboveLimitSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readVectorSettingsPage())); vectorVolumeSliceAboveLimitSpinBox->setToolTip("Vectors within this distance above\n" "a volume slice are drawn."); // // Volume slice below limit // QLabel* volumeSliceBelowLimitLabel = new QLabel("Slice Below Limit"); vectorVolumeSliceBelowLimitSpinBox = new QDoubleSpinBox; vectorVolumeSliceBelowLimitSpinBox->setMaximumWidth(spinBoxMaxWidth); vectorVolumeSliceBelowLimitSpinBox->setMinimum(-1000000.0); vectorVolumeSliceBelowLimitSpinBox->setMaximum(0.0); vectorVolumeSliceBelowLimitSpinBox->setSingleStep(0.1); vectorVolumeSliceBelowLimitSpinBox->setDecimals(2); QObject::connect(vectorVolumeSliceBelowLimitSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readVectorSettingsPage())); vectorVolumeSliceBelowLimitSpinBox->setToolTip("Vectors within this distance below\n" "a volume slice are drawn."); QGroupBox* volumeDisplayGroupBox = new QGroupBox("Volume Display"); QGridLayout* volumeDisplayGridLayout = new QGridLayout(volumeDisplayGroupBox); volumeDisplayGridLayout->addWidget(displayModeVolumeLabel, 0, 0); volumeDisplayGridLayout->addWidget(vectorDisplayModeVolumeComboBox, 0, 1); volumeDisplayGridLayout->addWidget(volumeSliceAboveLimitLabel, 1, 0); volumeDisplayGridLayout->addWidget(vectorVolumeSliceAboveLimitSpinBox, 1, 1); volumeDisplayGridLayout->addWidget(volumeSliceBelowLimitLabel, 2, 0); volumeDisplayGridLayout->addWidget(vectorVolumeSliceBelowLimitSpinBox, 2, 1); volumeDisplayGroupBox->setFixedSize(volumeDisplayGroupBox->sizeHint()); //=========================================================================== // // Magnitude Threshold // QLabel* magnitudeThresholdLabel = new QLabel("Threshold"); vectorMagnitudeThresholdSpinBox = new QDoubleSpinBox; vectorMagnitudeThresholdSpinBox->setMaximumWidth(spinBoxMaxWidth); vectorMagnitudeThresholdSpinBox->setMinimum(0.0); vectorMagnitudeThresholdSpinBox->setMaximum(1000000.0); vectorMagnitudeThresholdSpinBox->setSingleStep(0.05); vectorMagnitudeThresholdSpinBox->setDecimals(3); QObject::connect(vectorMagnitudeThresholdSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readVectorSettingsPage())); vectorMagnitudeThresholdSpinBox->setToolTip("Vectors with a magnitude less\n" "than this value are not displayed."); // // Draw with magnitude check box // vectorDrawWithMagnitudeCheckBox = new QCheckBox("Draw With Magnitude"); QObject::connect(vectorDrawWithMagnitudeCheckBox, SIGNAL(toggled(bool)), this, SLOT(readVectorSettingsPage())); vectorDrawWithMagnitudeCheckBox->setToolTip("If selected, vectors are drawn using their\n" "magnitude as the vector length. Otherwise, \n" "vectors are drawn with a length of 1.0."); // // Group box and layout for magnitude // QGroupBox* magnitudeGroupBox = new QGroupBox("Magnitude"); QGridLayout* magnitudeGridLayout = new QGridLayout(magnitudeGroupBox); magnitudeGridLayout->addWidget(vectorDrawWithMagnitudeCheckBox, 0, 0, 1, 2); magnitudeGridLayout->addWidget(magnitudeThresholdLabel, 1, 0); magnitudeGridLayout->addWidget(vectorMagnitudeThresholdSpinBox, 1, 1); magnitudeGroupBox->setFixedSize(magnitudeGroupBox->sizeHint()); //=========================================================================== // // Segmentation mask controls // QLabel* segmentationVolumeLabel = new QLabel("Volume"); vectorSegmentationMaskVolumeComboBox = new GuiVolumeFileSelectionComboBox(VolumeFile::VOLUME_TYPE_SEGMENTATION); QObject::connect(vectorSegmentationMaskVolumeComboBox, SIGNAL(activated(int)), this, SLOT(readVectorSettingsPage())); // // Segmentation mask group box and layout // vectorSegmentationGroupBox = new QGroupBox("Segmentation Volume Masking"); vectorSegmentationGroupBox->setCheckable(true); QObject::connect(vectorSegmentationGroupBox, SIGNAL(toggled(bool)), this, SLOT(readVectorSettingsPage())); QGridLayout* segmentationGridLayout = new QGridLayout(vectorSegmentationGroupBox); segmentationGridLayout->setColumnStretch(0, 0); segmentationGridLayout->setColumnStretch(1, 100); segmentationGridLayout->addWidget(segmentationVolumeLabel, 0, 0); segmentationGridLayout->addWidget(vectorSegmentationMaskVolumeComboBox, 0, 1); //=========================================================================== // // Functional mask controls // QLabel* vectorFunctionalMaskVolumeLabel = new QLabel("Volume"); vectorFunctionalMaskVolumeComboBox = new GuiVolumeFileSelectionComboBox(VolumeFile::VOLUME_TYPE_FUNCTIONAL); QObject::connect(vectorFunctionalMaskVolumeComboBox, SIGNAL(activated(int)), this, SLOT(readVectorSettingsPage())); vectorFunctionalMaskVolumeNegThreshSpinBox = new QDoubleSpinBox; vectorFunctionalMaskVolumeNegThreshSpinBox->setMaximumWidth(spinBoxMaxWidth); vectorFunctionalMaskVolumeNegThreshSpinBox->setMinimum(-1.0E10); vectorFunctionalMaskVolumeNegThreshSpinBox->setMaximum(1.0E10); vectorFunctionalMaskVolumeNegThreshSpinBox->setSingleStep(1.0); vectorFunctionalMaskVolumeNegThreshSpinBox->setDecimals(3); QObject::connect(vectorFunctionalMaskVolumeNegThreshSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readVectorSettingsPage())); vectorFunctionalMaskVolumePosThreshSpinBox = new QDoubleSpinBox; vectorFunctionalMaskVolumePosThreshSpinBox->setMaximumWidth(spinBoxMaxWidth); vectorFunctionalMaskVolumePosThreshSpinBox->setMinimum(-1.0E10); vectorFunctionalMaskVolumePosThreshSpinBox->setMaximum(1.0E10); vectorFunctionalMaskVolumePosThreshSpinBox->setSingleStep(1.0); vectorFunctionalMaskVolumePosThreshSpinBox->setDecimals(3); QObject::connect(vectorFunctionalMaskVolumePosThreshSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readVectorSettingsPage())); QLabel* functionalMaskValueLabel = new QLabel("Neg/Pos Threshold"); vectorFunctionalVolumeMaskGroupBox = new QGroupBox("Functional Volume Masking"); vectorFunctionalVolumeMaskGroupBox->setCheckable(true); QObject::connect(vectorFunctionalVolumeMaskGroupBox, SIGNAL(toggled(bool)), this, SLOT(readVectorSettingsPage())); QGridLayout* functionalMaskGridLayout = new QGridLayout(vectorFunctionalVolumeMaskGroupBox); functionalMaskGridLayout->setColumnStretch(0, 0); functionalMaskGridLayout->setColumnStretch(1, 0); functionalMaskGridLayout->setColumnStretch(2, 0); functionalMaskGridLayout->setColumnStretch(3, 100); functionalMaskGridLayout->addWidget(vectorFunctionalMaskVolumeLabel, 0, 0); functionalMaskGridLayout->addWidget(vectorFunctionalMaskVolumeComboBox, 0, 1, 1, 3); functionalMaskGridLayout->addWidget(functionalMaskValueLabel, 1, 0); functionalMaskGridLayout->addWidget(vectorFunctionalMaskVolumeNegThreshSpinBox, 1, 1); functionalMaskGridLayout->addWidget(vectorFunctionalMaskVolumePosThreshSpinBox, 1, 2); //=========================================================================== // // Orientation combo box // QLabel* displayOrientationAxisLabel = new QLabel("Axis"); vectorDisplayOrientationComboBox = new QComboBox; vectorDisplayOrientationComboBox->insertItem(DisplaySettingsVectors::DISPLAY_ORIENTATION_ANY, "Any"); vectorDisplayOrientationComboBox->insertItem(DisplaySettingsVectors::DISPLAY_ORIENTATION_LEFT_RIGHT, "Left/Right"); vectorDisplayOrientationComboBox->insertItem(DisplaySettingsVectors::DISPLAY_ORIENTATION_POSTERIOR_ANTERIOR, "Posterior/Anterior");; vectorDisplayOrientationComboBox->insertItem(DisplaySettingsVectors::DISPLAY_ORIENTATION_INFERIOR_SUPERIOR, "Inferior/Superior"); QObject::connect(vectorDisplayOrientationComboBox, SIGNAL(activated(int)), this, SLOT(readVectorSettingsPage())); // // Orientation angle // QLabel* orientationAngleLabel = new QLabel("Angle"); vectorDisplayOrientationAngleSpinBox = new QDoubleSpinBox; vectorDisplayOrientationAngleSpinBox->setMaximumWidth(spinBoxMaxWidth); vectorDisplayOrientationAngleSpinBox->setMinimum(-90.0); vectorDisplayOrientationAngleSpinBox->setMaximum(90.0); vectorDisplayOrientationAngleSpinBox->setSingleStep(1.0); vectorDisplayOrientationAngleSpinBox->setDecimals(1); QObject::connect(vectorDisplayOrientationAngleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readVectorSettingsPage())); vectorDisplayOrientationAngleSpinBox->setToolTip("Angle of vectors from orientation."); // // Orientation layout // QGroupBox* vectorDisplayOrientationGroupBox = new QGroupBox("Orientation Filtering"); QGridLayout* vectorDisplayOrientationGridLayout = new QGridLayout(vectorDisplayOrientationGroupBox); vectorDisplayOrientationGridLayout->addWidget(displayOrientationAxisLabel, 0, 0); vectorDisplayOrientationGridLayout->addWidget(vectorDisplayOrientationComboBox, 0, 1); vectorDisplayOrientationGridLayout->addWidget(orientationAngleLabel, 1, 0); vectorDisplayOrientationGridLayout->addWidget(vectorDisplayOrientationAngleSpinBox, 1, 1); vectorDisplayOrientationGroupBox->setFixedSize(vectorDisplayOrientationGroupBox->sizeHint()); //=========================================================================== // // Layout for surface and volume display // QHBoxLayout* displayLayouts = new QHBoxLayout; displayLayouts->addWidget(surfaceDisplayGroupBox); displayLayouts->addWidget(volumeDisplayGroupBox); displayLayouts->addStretch(); // // Layout for orientation and magnitude // QHBoxLayout* orientationMagnitudeLayouts = new QHBoxLayout; orientationMagnitudeLayouts->addWidget(vectorDisplayOrientationGroupBox); orientationMagnitudeLayouts->addWidget(magnitudeGroupBox); orientationMagnitudeLayouts->addStretch(); // // Box for settings page // pageVectorSettings = new QWidget; QVBoxLayout* vectorSettingsPageLayout = new QVBoxLayout(pageVectorSettings); vectorSettingsPageLayout->setSpacing(1); vectorSettingsPageLayout->addLayout(displayLayouts); vectorSettingsPageLayout->addWidget(drawingGroupBox); vectorSettingsPageLayout->addLayout(orientationMagnitudeLayouts); vectorSettingsPageLayout->addWidget(vectorFunctionalVolumeMaskGroupBox); vectorSettingsPageLayout->addWidget(vectorSegmentationGroupBox); vectorSettingsPageLayout->addStretch(); pageVectorSettings->setFixedSize(pageVectorSettings->sizeHint()); pageWidgetStack->addWidget(pageVectorSettings); // // Widget group for vector page items // vectorSettingsPageWidgetGroup = new WuQWidgetGroup(this); vectorSettingsPageWidgetGroup->addWidget(vectorColorModeComboBox); vectorSettingsPageWidgetGroup->addWidget(vectorTypeModeComboBox); vectorSettingsPageWidgetGroup->addWidget(vectorSurfaceSymbolComboBox); vectorSettingsPageWidgetGroup->addWidget(vectorDisplayModeSurfaceComboBox); vectorSettingsPageWidgetGroup->addWidget(vectorDisplayModeVolumeComboBox); vectorSettingsPageWidgetGroup->addWidget(vectorSparseDistanceSpinBox); vectorSettingsPageWidgetGroup->addWidget(vectorLengthMultiplierDoubleSpinBox); vectorSettingsPageWidgetGroup->addWidget(vectorSurfaceLineWidthSpinBox); vectorSettingsPageWidgetGroup->addWidget(vectorVolumeSliceAboveLimitSpinBox); vectorSettingsPageWidgetGroup->addWidget(vectorVolumeSliceBelowLimitSpinBox); vectorSettingsPageWidgetGroup->addWidget(vectorDrawWithMagnitudeCheckBox); vectorSettingsPageWidgetGroup->addWidget(vectorMagnitudeThresholdSpinBox); vectorSettingsPageWidgetGroup->addWidget(vectorSegmentationGroupBox); vectorSettingsPageWidgetGroup->addWidget(vectorSegmentationMaskVolumeComboBox); vectorSettingsPageWidgetGroup->addWidget(vectorDisplayOrientationComboBox); vectorSettingsPageWidgetGroup->addWidget(vectorDisplayOrientationAngleSpinBox); vectorSettingsPageWidgetGroup->addWidget(vectorFunctionalVolumeMaskGroupBox); vectorSettingsPageWidgetGroup->addWidget(vectorFunctionalMaskVolumeComboBox); vectorSettingsPageWidgetGroup->addWidget(vectorFunctionalMaskVolumeNegThreshSpinBox); vectorSettingsPageWidgetGroup->addWidget(vectorFunctionalMaskVolumePosThreshSpinBox); } /** * update surface vector settings page. */ void GuiDisplayControlDialog::updateVectorSettingsPage() { if (pageVectorSettings == NULL) { return; } vectorSettingsPageWidgetGroup->blockSignals(true); DisplaySettingsVectors* dssv = theMainWindow->getBrainSet()->getDisplaySettingsVectors(); vectorColorModeComboBox->setCurrentIndex(dssv->getColorMode()); vectorTypeModeComboBox->setCurrentIndex(dssv->getVectorType()); vectorSurfaceSymbolComboBox->setCurrentIndex(dssv->getSurfaceSymbol()); vectorDisplayModeSurfaceComboBox->setCurrentIndex(dssv->getDisplayModeSurface()); vectorDisplayModeVolumeComboBox->setCurrentIndex(dssv->getDisplayModeVolume()); vectorSparseDistanceSpinBox->setValue(dssv->getSparseDisplayDistance()); vectorLengthMultiplierDoubleSpinBox->setValue(dssv->getLengthMultiplier()); vectorSurfaceLineWidthSpinBox->setValue(dssv->getSurfaceVectorLineWidth()); vectorVolumeSliceAboveLimitSpinBox->setValue(dssv->getVolumeSliceDistanceAboveLimit()); vectorVolumeSliceBelowLimitSpinBox->setValue(dssv->getVolumeSliceDistanceBelowLimit()); vectorDrawWithMagnitudeCheckBox->setChecked(dssv->getDrawWithMagnitude()); vectorMagnitudeThresholdSpinBox->setValue(dssv->getMagnitudeThreshold()); vectorSegmentationGroupBox->setChecked(dssv->getSegmentationMaskingVolumeEnabled()); vectorSegmentationMaskVolumeComboBox->updateComboBox(); vectorSegmentationMaskVolumeComboBox->setSelectedVolumeFile(dssv->getSegmentationMaskingVolumeFile()); vectorDisplayOrientationAngleSpinBox->setValue(dssv->getDisplayOrientationAngle()); vectorDisplayOrientationComboBox->setCurrentIndex(dssv->getDisplayOrientation()); vectorFunctionalVolumeMaskGroupBox->setChecked(dssv->getFunctionalMaskingVolumeEnabled()); vectorFunctionalMaskVolumeComboBox->updateComboBox(); vectorFunctionalMaskVolumeComboBox->setSelectedVolumeFile(dssv->getFunctionalMaskingVolumeFile()); vectorFunctionalMaskVolumeNegThreshSpinBox->setValue(dssv->getFunctionalMaskingVolumeNegativeThreshold()); vectorFunctionalMaskVolumePosThreshSpinBox->setValue(dssv->getFunctionalMaskingVolumePositiveThreshold()); pageVectorSettings->setEnabled(validVectorData); vectorSettingsPageWidgetGroup->blockSignals(false); } /** * update surface vector items in dialog. */ void GuiDisplayControlDialog::updateVectorItems() { updatePageSelectionComboBox(); updateVectorSelectionPage(); updateVectorSettingsPage(); } /** * read the surface vector settings page. */ void GuiDisplayControlDialog::readVectorSettingsPage() { if (pageVectorSettings == NULL) { return; } DisplaySettingsVectors* dssv = theMainWindow->getBrainSet()->getDisplaySettingsVectors(); //dssv->setSelectedColumn(surfaceModelIndex, vectorButtonGroup->checkedId()); dssv->setColorMode(static_cast( vectorColorModeComboBox->currentIndex())); dssv->setVectorType(static_cast( vectorTypeModeComboBox->currentIndex())); dssv->setSurfaceSymbol(static_cast( vectorSurfaceSymbolComboBox->currentIndex())); dssv->setDisplayModeSurface(static_cast( vectorDisplayModeSurfaceComboBox->currentIndex())); dssv->setDisplayModeVolume(static_cast( vectorDisplayModeVolumeComboBox->currentIndex())); dssv->setSurfaceVectorLineWidth(vectorSurfaceLineWidthSpinBox->value()); dssv->setVolumeSliceDistanceAboveLimit(vectorVolumeSliceAboveLimitSpinBox->value()); dssv->setVolumeSliceDistanceBelowLimit(vectorVolumeSliceBelowLimitSpinBox->value()); dssv->setSparseDisplayDistance(vectorSparseDistanceSpinBox->value()); dssv->setLengthMultiplier(vectorLengthMultiplierDoubleSpinBox->value()); dssv->setDrawWithMagnitude(vectorDrawWithMagnitudeCheckBox->isChecked()); dssv->setMagnitudeThreshold(vectorMagnitudeThresholdSpinBox->value()); dssv->setSegmentationMaskingVolumeFile(vectorSegmentationMaskVolumeComboBox->getSelectedVolumeFile()); dssv->setSegmentationMaskingVolumeEnabled(vectorSegmentationGroupBox->isChecked()); dssv->setDisplayOrientationAngle(vectorDisplayOrientationAngleSpinBox->value()); dssv->setDisplayOrientation(static_cast( vectorDisplayOrientationComboBox->currentIndex())); dssv->setFunctionalMaskingVolumeEnabled(vectorFunctionalVolumeMaskGroupBox->isChecked()); dssv->setFunctionalMaskingVolumeFile(vectorFunctionalMaskVolumeComboBox->getSelectedVolumeFile()); dssv->setFunctionalMaskingVolumeNegativeThreshold(vectorFunctionalMaskVolumeNegThreshSpinBox->value()); dssv->setFunctionalMaskingVolumePositiveThreshold(vectorFunctionalMaskVolumePosThreshSpinBox->value()); theMainWindow->getBrainSet()->clearAllDisplayLists(); GuiBrainModelOpenGL::updateAllGL(); } /** * update vector selection page. */ void GuiDisplayControlDialog::updateVectorSelectionPage() { if (pageVectorSelection == NULL) { return; } vectorSelectionPageWidgetGroup->blockSignals(true); BrainSet* bs = theMainWindow->getBrainSet(); const int numVectorFiles = bs->getNumberOfVectorFiles(); const int numCheckBoxes = static_cast(vectorSelectionCheckBoxes.size()); // // Add new check boxes // for (int i = numCheckBoxes; i < numVectorFiles; i++) { QCheckBox* cb = new QCheckBox(""); cb->blockSignals(true); QObject::connect(cb, SIGNAL(toggled(bool)), this, SLOT(readVectorSelectionPage())); vectorSelectionCheckBoxes.push_back(cb); vectorSelectionPageWidgetGroup->addWidget(cb); pageVectorSelectionLayout->addWidget(cb); } // // Hide unused checkboxes // for (int i = numVectorFiles; i < numCheckBoxes; i++) { vectorSelectionCheckBoxes[i]->hide(); } // // Update valid checkboxes // DisplaySettingsVectors* dsv = bs->getDisplaySettingsVectors(); for (int i = 0; i < numVectorFiles; i++) { vectorSelectionCheckBoxes[i]->show(); vectorSelectionCheckBoxes[i]->setText( FileUtilities::basename(bs->getVectorFile(i)->getFileName())); vectorSelectionCheckBoxes[i]->setChecked(dsv->getDisplayVectorFile(i)); } pageVectorSelection->setEnabled(validVectorData); pageVectorSelection->setFixedHeight(pageVectorSelection->sizeHint().height()); vectorSelectionPageWidgetGroup->blockSignals(false); } /** * create the vector selection page. */ void GuiDisplayControlDialog::createVectorSelectionPage() { pageVectorSelection = new QWidget; pageWidgetStack->addWidget(pageVectorSelection); pageVectorSelectionLayout = new QVBoxLayout(pageVectorSelection); // // Widget group for vector page items // vectorSelectionPageWidgetGroup = new WuQWidgetGroup(this); } /** * read the vector selection page. */ void GuiDisplayControlDialog::readVectorSelectionPage() { if (pageVectorSelection == NULL) { return; } BrainSet* bs = theMainWindow->getBrainSet(); int numVectorFiles = bs->getNumberOfVectorFiles(); // // Determine files that are displayed // DisplaySettingsVectors* dsv = bs->getDisplaySettingsVectors(); for (int i = 0; i < numVectorFiles; i++) { dsv->setDisplayVectorFile(i, vectorSelectionCheckBoxes[i]->isChecked()); } bs->clearAllDisplayLists(); GuiBrainModelOpenGL::updateAllGL(); } /** * Create the misc tab page */ void GuiDisplayControlDialog::createSurfaceMiscPage() { // // Display settings for nodes // DisplaySettingsSurface* dsn = theMainWindow->getBrainSet()->getDisplaySettingsSurface(); // // Widget for misc items // pageSurfaceMisc = new QWidget; pageWidgetStack->addWidget(pageSurfaceMisc); //, PAGE_NAME_SURFACE_MISC); QVBoxLayout* miscVBoxLayout = new QVBoxLayout(pageSurfaceMisc); miscVBoxLayout->setSpacing(3); // // Grid layout for brighness, contrast, node size, link size // // int numRows = 0; const int LEFT_VOLUME_INTERACTION_ROW = numRows++; const int RIGHT_VOLUME_INTERACTION_ROW = numRows++; const int CEREBELLUM_VOLUME_INTERACTION_ROW = numRows++; const int FIDUCIAL_ROW = numRows++; const int DRAW_MODE_ROW = numRows++; const int PROJECTION_ROW = numRows++; const int BRIGHTNESS_ROW = numRows++; const int CONTRAST_ROW = numRows++; const int OPACITY_ROW = numRows++; const int NODE_SIZE_ROW = numRows++; const int LINK_SIZE_ROW = numRows++; const int IDENTIFY_COLOR_ROW = numRows++; const int maxWidth = 250; QGridLayout* gridLayout = new QGridLayout; gridLayout->setSpacing(2); miscVBoxLayout->addLayout(gridLayout); //gridLayout->setColumnMaximumWidth(1, 200); // // Fiducial volume interaction surface selection // gridLayout->addWidget(new QLabel("Left Fiducial Volume Interaction"), LEFT_VOLUME_INTERACTION_ROW, 0, Qt::AlignLeft); miscLeftFiducialVolumeInteractionComboBox = new GuiBrainModelSelectionComboBox(false, true, false, "", 0, "miscLeftFiducialVolumeInteractionComboBox", false, true); miscLeftFiducialVolumeInteractionComboBox->setSurfaceStructureRequirement(Structure::STRUCTURE_TYPE_CORTEX_LEFT); gridLayout->addWidget(miscLeftFiducialVolumeInteractionComboBox, LEFT_VOLUME_INTERACTION_ROW, 1, 1, 2, Qt::AlignLeft); QObject::connect(miscLeftFiducialVolumeInteractionComboBox, SIGNAL(activated(int)), this, SLOT(readMiscSelections())); gridLayout->addWidget(new QLabel("Right Fiducial Volume Interaction"), RIGHT_VOLUME_INTERACTION_ROW, 0, Qt::AlignLeft); miscRightFiducialVolumeInteractionComboBox = new GuiBrainModelSelectionComboBox(false, true, false, "", 0, "miscRightFiducialVolumeInteractionComboBox", false, true); miscRightFiducialVolumeInteractionComboBox->setSurfaceStructureRequirement(Structure::STRUCTURE_TYPE_CORTEX_RIGHT); gridLayout->addWidget(miscRightFiducialVolumeInteractionComboBox, RIGHT_VOLUME_INTERACTION_ROW, 1, 1, 2, Qt::AlignLeft); QObject::connect(miscRightFiducialVolumeInteractionComboBox, SIGNAL(activated(int)), this, SLOT(readMiscSelections())); gridLayout->addWidget(new QLabel("Cerebellum Fiducial Volume Interaction"), CEREBELLUM_VOLUME_INTERACTION_ROW, 0, Qt::AlignLeft); miscCerebellumFiducialVolumeInteractionComboBox = new GuiBrainModelSelectionComboBox(false, true, false, "", 0, "miscCerebellumFiducialVolumeInteractionComboBox", false, true); miscCerebellumFiducialVolumeInteractionComboBox->setSurfaceStructureRequirement(Structure::STRUCTURE_TYPE_CEREBELLUM); gridLayout->addWidget(miscCerebellumFiducialVolumeInteractionComboBox, CEREBELLUM_VOLUME_INTERACTION_ROW, 1, 1, 2, Qt::AlignLeft); QObject::connect(miscCerebellumFiducialVolumeInteractionComboBox, SIGNAL(activated(int)), this, SLOT(readMiscSelections())); // // Active fiducial surface selection // gridLayout->addWidget(new QLabel("Active Fiducial"), FIDUCIAL_ROW, 0, Qt::AlignLeft); miscActiveFiducialComboBox = new GuiBrainModelSelectionComboBox(false, true, false, "", 0, "miscActiveFiducialComboBox", false, true); gridLayout->addWidget(miscActiveFiducialComboBox, FIDUCIAL_ROW, 1, 1, 2, Qt::AlignLeft); QObject::connect(miscActiveFiducialComboBox, SIGNAL(activated(int)), this, SLOT(readMiscSelections())); // // Combo box for drawing mode // gridLayout->addWidget(new QLabel("Drawing Mode "), DRAW_MODE_ROW, 0, Qt::AlignLeft); miscDrawModeComboBox = new QComboBox; miscDrawModeComboBox->setMaximumWidth(maxWidth); miscDrawModeComboBox->insertItem(DisplaySettingsSurface::DRAW_MODE_NODES, "Nodes"); miscDrawModeComboBox->insertItem(DisplaySettingsSurface::DRAW_MODE_LINKS, "Links"); miscDrawModeComboBox->insertItem(DisplaySettingsSurface::DRAW_MODE_LINK_HIDDEN_LINE_REMOVAL, "Links (No Backside)"); miscDrawModeComboBox->insertItem(DisplaySettingsSurface::DRAW_MODE_LINKS_EDGES_ONLY, "Links (Edges Only)"); miscDrawModeComboBox->insertItem(DisplaySettingsSurface::DRAW_MODE_NODES_AND_LINKS, "Nodes and Links"); miscDrawModeComboBox->insertItem(DisplaySettingsSurface::DRAW_MODE_TILES, "Tiles without Lighting"); miscDrawModeComboBox->insertItem(DisplaySettingsSurface::DRAW_MODE_TILES_WITH_LIGHT, "Tiles with Lighting (Default)"); miscDrawModeComboBox->insertItem(DisplaySettingsSurface::DRAW_MODE_TILES_WITH_LIGHT_NO_BACK, "Tiles with Lighting No Backfacing Tiles"); miscDrawModeComboBox->insertItem(DisplaySettingsSurface::DRAW_MODE_TILES_LINKS_NODES, "Tiles, Links, and Nodes (surface editing)"); miscDrawModeComboBox->insertItem(DisplaySettingsSurface::DRAW_MODE_NONE, "Hide Surface"); miscDrawModeComboBox->setFixedSize(miscDrawModeComboBox->sizeHint()); gridLayout->addWidget(miscDrawModeComboBox, DRAW_MODE_ROW, 1, Qt::AlignLeft); miscDrawModeComboBox->setToolTip("Choose Drawing Mode"); QObject::connect(miscDrawModeComboBox, SIGNAL(activated(int)), this, SLOT(readMiscSelections())); // // Projection // gridLayout->addWidget(new QLabel("Projection"), PROJECTION_ROW, 0, Qt::AlignLeft); miscProjectionComboBox = new QComboBox; miscProjectionComboBox->setMaximumWidth(maxWidth); gridLayout->addWidget(miscProjectionComboBox, PROJECTION_ROW, 1, Qt::AlignLeft); QObject::connect(miscProjectionComboBox, SIGNAL(activated(int)), this, SLOT(readMiscSelections())); miscProjectionComboBox->insertItem(DisplaySettingsSurface::VIEWING_PROJECTION_ORTHOGRAPHIC, "Orthographic"); miscProjectionComboBox->insertItem(DisplaySettingsSurface::VIEWING_PROJECTION_PERSPECTIVE, "Perspective"); // // Brightness line edit and label // gridLayout->addWidget(new QLabel("Brightness"), BRIGHTNESS_ROW, 0, Qt::AlignLeft); miscBrightnessDoubleSpinBox = new QDoubleSpinBox; miscBrightnessDoubleSpinBox->setMinimum(-10000); miscBrightnessDoubleSpinBox->setMaximum(10000); miscBrightnessDoubleSpinBox->setSingleStep(10.0); miscBrightnessDoubleSpinBox->setDecimals(2); miscBrightnessDoubleSpinBox->setMaximumWidth(maxWidth); gridLayout->addWidget(miscBrightnessDoubleSpinBox, BRIGHTNESS_ROW, 1, Qt::AlignLeft); miscBrightnessDoubleSpinBox->setValue(dsn->getNodeBrightness()); QObject::connect(miscBrightnessDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readMiscSelections())); // // Contrast line edit and label // gridLayout->addWidget(new QLabel("Contrast"), CONTRAST_ROW, 0, Qt::AlignLeft); miscContrastDoubleSpinBox = new QDoubleSpinBox; miscContrastDoubleSpinBox->setMaximumWidth(maxWidth); miscContrastDoubleSpinBox->setMinimum(-10000); miscContrastDoubleSpinBox->setMaximum(10000); miscContrastDoubleSpinBox->setSingleStep(0.1); miscContrastDoubleSpinBox->setDecimals(2); gridLayout->addWidget(miscContrastDoubleSpinBox, CONTRAST_ROW, 1, Qt::AlignLeft); miscContrastDoubleSpinBox->setValue(dsn->getNodeContrast()); QObject::connect(miscContrastDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readMiscSelections())); // // Opacity spin box and label // gridLayout->addWidget(new QLabel("Opacity"), OPACITY_ROW, 0, Qt::AlignLeft); opacityDoubleSpinBox = new QDoubleSpinBox; opacityDoubleSpinBox->setMinimum(0.0); opacityDoubleSpinBox->setMaximum(1.0); opacityDoubleSpinBox->setSingleStep(0.1); opacityDoubleSpinBox->setDecimals(2); opacityDoubleSpinBox->setMaximumWidth(maxWidth); gridLayout->addWidget(opacityDoubleSpinBox, OPACITY_ROW, 1, Qt::AlignLeft); QObject::connect(opacityDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readMiscSelections())); // // Node Size spin box and label // gridLayout->addWidget(new QLabel("Node Size"), NODE_SIZE_ROW, 0, Qt::AlignLeft); miscNodeSizeSpinBox = new QDoubleSpinBox; miscNodeSizeSpinBox->setMinimum(minPointSize); miscNodeSizeSpinBox->setMaximum(maxPointSize); miscNodeSizeSpinBox->setSingleStep(1.0); miscNodeSizeSpinBox->setDecimals(1); miscNodeSizeSpinBox->setMaximumWidth(maxWidth); gridLayout->addWidget(miscNodeSizeSpinBox, NODE_SIZE_ROW, 1, Qt::AlignLeft); miscNodeSizeSpinBox->setValue(dsn->getNodeSize()); QObject::connect(miscNodeSizeSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readMiscSelections())); // // Link Size spin box and label // gridLayout->addWidget(new QLabel("Link Size"), LINK_SIZE_ROW, 0, Qt::AlignLeft); miscLinkSizeSpinBox = new QDoubleSpinBox; miscLinkSizeSpinBox->setMinimum(minLineSize); miscLinkSizeSpinBox->setMaximum(maxLineSize); miscLinkSizeSpinBox->setSingleStep(1.0); miscLinkSizeSpinBox->setDecimals(1); miscLinkSizeSpinBox->setMaximumWidth(maxWidth); gridLayout->addWidget(miscLinkSizeSpinBox, LINK_SIZE_ROW, 1, Qt::AlignLeft); miscLinkSizeSpinBox->setValue(dsn->getLinkSize()); QObject::connect(miscLinkSizeSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readMiscSelections())); // // identify node color combo box // gridLayout->addWidget(new QLabel("Identify Color"), IDENTIFY_COLOR_ROW, 0, Qt::AlignLeft); miscIdentifyNodeColorComboBox = new QComboBox; miscIdentifyNodeColorComboBox->setMaximumWidth(maxWidth); gridLayout->addWidget(miscIdentifyNodeColorComboBox, IDENTIFY_COLOR_ROW, 1, Qt::AlignLeft); QObject::connect(miscIdentifyNodeColorComboBox, SIGNAL(activated(int)), this, SLOT(readMiscSelections())); miscIdentifyNodeColorComboBox->insertItem(DisplaySettingsSurface::IDENTIFY_NODE_COLOR_BLACK, "Black"); miscIdentifyNodeColorComboBox->insertItem(DisplaySettingsSurface::IDENTIFY_NODE_COLOR_BLUE, "Blue"); miscIdentifyNodeColorComboBox->insertItem(DisplaySettingsSurface::IDENTIFY_NODE_COLOR_GREEN, "Green"); miscIdentifyNodeColorComboBox->insertItem(DisplaySettingsSurface::IDENTIFY_NODE_COLOR_RED, "Red"); miscIdentifyNodeColorComboBox->insertItem(DisplaySettingsSurface::IDENTIFY_NODE_COLOR_WHITE, "White"); // // show normals check box // miscShowNormalsCheckBox = new QCheckBox("Show Normals"); miscVBoxLayout->addWidget(miscShowNormalsCheckBox, 0, Qt::AlignLeft); miscShowNormalsCheckBox->setChecked(dsn->getShowNormals()); QObject::connect(miscShowNormalsCheckBox, SIGNAL(toggled(bool)), this, SLOT(readMiscSelections())); // // total forces check box // miscTotalForcesCheckBox = new QCheckBox("Show Morphing Total Forces"); miscVBoxLayout->addWidget(miscTotalForcesCheckBox, 0, Qt::AlignLeft); miscTotalForcesCheckBox->setChecked(dsn->getShowMorphingTotalForces()); QObject::connect(miscTotalForcesCheckBox, SIGNAL(toggled(bool)), this, SLOT(readMiscSelections())); // // angular forces check box // miscAngularForcesCheckBox = new QCheckBox("Show Morphing Angular Forces"); miscVBoxLayout->addWidget(miscAngularForcesCheckBox, 0, Qt::AlignLeft); miscAngularForcesCheckBox->setChecked(dsn->getShowMorphingAngularForces()); QObject::connect(miscAngularForcesCheckBox, SIGNAL(toggled(bool)), this, SLOT(readMiscSelections())); // // linear forces check box // miscLinearForcesCheckBox = new QCheckBox("Show Morphing Linear Forces"); miscVBoxLayout->addWidget(miscLinearForcesCheckBox, 0, Qt::AlignLeft); miscLinearForcesCheckBox->setChecked(dsn->getShowMorphingLinearForces()); QObject::connect(miscLinearForcesCheckBox, SIGNAL(toggled(bool)), this, SLOT(readMiscSelections())); // // force vector length float spin box // QLabel* forceVectorLabel = new QLabel("Force Vector Length "); miscForceVectorLengthDoubleSpinBox = new QDoubleSpinBox; miscForceVectorLengthDoubleSpinBox->setMinimum(0.0); miscForceVectorLengthDoubleSpinBox->setMaximum(5000.0); miscForceVectorLengthDoubleSpinBox->setSingleStep(10.0); miscForceVectorLengthDoubleSpinBox->setDecimals(2); miscForceVectorLengthDoubleSpinBox->setValue(dsn->getForceVectorDisplayLength()); QObject::connect(miscForceVectorLengthDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readMiscSelections())); QHBoxLayout* forceHBoxLayout = new QHBoxLayout; miscVBoxLayout->addLayout(forceHBoxLayout); forceHBoxLayout->addWidget(forceVectorLabel); forceHBoxLayout->addWidget(miscForceVectorLengthDoubleSpinBox); forceHBoxLayout->addStretch(); // // cartesian axes show letters check box // miscAxesShowLettersCheckBox = new QCheckBox("Show Orientation Labels"); QObject::connect(miscAxesShowLettersCheckBox, SIGNAL(toggled(bool)), this, SLOT(readMiscSelections())); // // cartesian axesShow tick marks // miscAxesShowTickMarksCheckBox = new QCheckBox("Show Tick Marks"); QObject::connect(miscAxesShowTickMarksCheckBox, SIGNAL(toggled(bool)), this, SLOT(readMiscSelections())); // // axes length // QLabel* miscSurfAxesLabel = new QLabel("Axes Length "); miscAxesLengthDoubleSpinBox = new QDoubleSpinBox; miscAxesLengthDoubleSpinBox->setMinimum(0.0); miscAxesLengthDoubleSpinBox->setMaximum(50000.0); miscAxesLengthDoubleSpinBox->setSingleStep(10.0); miscAxesLengthDoubleSpinBox->setDecimals(1); QObject::connect(miscAxesLengthDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readMiscSelections())); QHBoxLayout* miscSurfAxesLayout = new QHBoxLayout; miscSurfAxesLayout->addWidget(miscSurfAxesLabel); miscSurfAxesLayout->addWidget(miscAxesLengthDoubleSpinBox); miscSurfAxesLayout->addStretch(); // // Axes offset // QLabel* miscSurfAxesOffsetLabel = new QLabel("Axes Offset "); miscAxesOffsetDoubleSpinBox[0] = new QDoubleSpinBox; miscAxesOffsetDoubleSpinBox[0]->setMinimum(-1000000.0); miscAxesOffsetDoubleSpinBox[0]->setMaximum( 1000000.0); miscAxesOffsetDoubleSpinBox[0]->setSingleStep(10.0); miscAxesOffsetDoubleSpinBox[0]->setDecimals(2); QObject::connect(miscAxesOffsetDoubleSpinBox[0], SIGNAL(valueChanged(double)), this, SLOT(readMiscSelections())); miscAxesOffsetDoubleSpinBox[1] = new QDoubleSpinBox; miscAxesOffsetDoubleSpinBox[1]->setMinimum(-1000000.0); miscAxesOffsetDoubleSpinBox[1]->setMaximum( 1000000.0); miscAxesOffsetDoubleSpinBox[1]->setSingleStep(10.0); miscAxesOffsetDoubleSpinBox[1]->setDecimals(2); QObject::connect(miscAxesOffsetDoubleSpinBox[1], SIGNAL(valueChanged(double)), this, SLOT(readMiscSelections())); miscAxesOffsetDoubleSpinBox[2] = new QDoubleSpinBox; miscAxesOffsetDoubleSpinBox[2]->setMinimum(-1000000.0); miscAxesOffsetDoubleSpinBox[2]->setMaximum( 1000000.0); miscAxesOffsetDoubleSpinBox[2]->setSingleStep(10.0); miscAxesOffsetDoubleSpinBox[2]->setDecimals(2); QObject::connect(miscAxesOffsetDoubleSpinBox[2], SIGNAL(valueChanged(double)), this, SLOT(readMiscSelections())); QHBoxLayout* miscSurfAxesOffsetLayout = new QHBoxLayout; miscSurfAxesOffsetLayout->addWidget(miscSurfAxesOffsetLabel); miscSurfAxesOffsetLayout->addWidget(miscAxesOffsetDoubleSpinBox[0]); miscSurfAxesOffsetLayout->addWidget(miscAxesOffsetDoubleSpinBox[1]); miscSurfAxesOffsetLayout->addWidget(miscAxesOffsetDoubleSpinBox[2]); miscSurfAxesOffsetLayout->addStretch(); // // Surface axes group box // miscAxesGroupBox = new QGroupBox("Surface Cartesian Axes"); miscAxesGroupBox->setCheckable(true); miscVBoxLayout->addWidget(new QLabel(" ")); miscVBoxLayout->addWidget(miscAxesGroupBox); QVBoxLayout* miscAxesGroupLayout = new QVBoxLayout(miscAxesGroupBox); miscAxesGroupLayout->addWidget(miscAxesShowLettersCheckBox); miscAxesGroupLayout->addWidget(miscAxesShowTickMarksCheckBox); miscAxesGroupLayout->addLayout(miscSurfAxesLayout); miscAxesGroupLayout->addLayout(miscSurfAxesOffsetLayout); QObject::connect(miscAxesGroupBox, SIGNAL(toggled(bool)), this, SLOT(readMiscSelections())); miscAxesGroupBox->setFixedSize(miscAxesGroupBox->sizeHint()); // // Limit size of page // pageSurfaceMisc->setFixedSize(pageSurfaceMisc->sizeHint()); // // Widget group for all items in surf misc page // surfaceMiscWidgetGroup = new WuQWidgetGroup(this); surfaceMiscWidgetGroup->addWidget(miscLeftFiducialVolumeInteractionComboBox); surfaceMiscWidgetGroup->addWidget(miscRightFiducialVolumeInteractionComboBox); surfaceMiscWidgetGroup->addWidget(miscCerebellumFiducialVolumeInteractionComboBox); surfaceMiscWidgetGroup->addWidget(miscActiveFiducialComboBox); surfaceMiscWidgetGroup->addWidget(miscDrawModeComboBox); surfaceMiscWidgetGroup->addWidget(miscProjectionComboBox); surfaceMiscWidgetGroup->addWidget(miscBrightnessDoubleSpinBox); surfaceMiscWidgetGroup->addWidget(miscContrastDoubleSpinBox); surfaceMiscWidgetGroup->addWidget(opacityDoubleSpinBox); surfaceMiscWidgetGroup->addWidget(miscNodeSizeSpinBox); surfaceMiscWidgetGroup->addWidget(miscLinkSizeSpinBox); surfaceMiscWidgetGroup->addWidget(miscIdentifyNodeColorComboBox); surfaceMiscWidgetGroup->addWidget(miscShowNormalsCheckBox); surfaceMiscWidgetGroup->addWidget(miscTotalForcesCheckBox); surfaceMiscWidgetGroup->addWidget(miscAngularForcesCheckBox); surfaceMiscWidgetGroup->addWidget(miscLinearForcesCheckBox); surfaceMiscWidgetGroup->addWidget(miscForceVectorLengthDoubleSpinBox); surfaceMiscWidgetGroup->addWidget(miscAxesShowLettersCheckBox); surfaceMiscWidgetGroup->addWidget(miscAxesShowTickMarksCheckBox); surfaceMiscWidgetGroup->addWidget(miscAxesLengthDoubleSpinBox); surfaceMiscWidgetGroup->addWidget(miscAxesOffsetDoubleSpinBox[0]); surfaceMiscWidgetGroup->addWidget(miscAxesOffsetDoubleSpinBox[1]); surfaceMiscWidgetGroup->addWidget(miscAxesOffsetDoubleSpinBox[2]); surfaceMiscWidgetGroup->addWidget(miscAxesGroupBox); } /** * Update the items on the misc page */ void GuiDisplayControlDialog::updateMiscItems() { updatePageSelectionComboBox(); if (pageSurfaceMisc == NULL) { return; } surfaceMiscWidgetGroup->blockSignals(true); // // Display settings for nodes // DisplaySettingsSurface* dsn = theMainWindow->getBrainSet()->getDisplaySettingsSurface(); miscLeftFiducialVolumeInteractionComboBox->updateComboBox(); miscLeftFiducialVolumeInteractionComboBox->setSelectedBrainModel(theMainWindow->getBrainSet()->getLeftFiducialVolumeInteractionSurface()); miscRightFiducialVolumeInteractionComboBox->updateComboBox(); miscRightFiducialVolumeInteractionComboBox->setSelectedBrainModel(theMainWindow->getBrainSet()->getRightFiducialVolumeInteractionSurface()); miscCerebellumFiducialVolumeInteractionComboBox->updateComboBox(); miscCerebellumFiducialVolumeInteractionComboBox->setSelectedBrainModel(theMainWindow->getBrainSet()->getCerebellumFiducialVolumeInteractionSurface()); miscActiveFiducialComboBox->updateComboBox(); miscActiveFiducialComboBox->setSelectedBrainModel(theMainWindow->getBrainSet()->getActiveFiducialSurface()); miscDrawModeComboBox->setCurrentIndex(dsn->getDrawMode()); miscProjectionComboBox->setCurrentIndex(dsn->getViewingProjection()); miscBrightnessDoubleSpinBox->setValue(dsn->getNodeBrightness()); miscContrastDoubleSpinBox->setValue(dsn->getNodeContrast()); opacityDoubleSpinBox->setValue(dsn->getOpacity()); miscNodeSizeSpinBox->setValue(dsn->getNodeSize()); miscLinkSizeSpinBox->setValue(dsn->getLinkSize()); miscShowNormalsCheckBox->setChecked(dsn->getShowNormals()); miscTotalForcesCheckBox->setChecked(dsn->getShowMorphingTotalForces()); miscAngularForcesCheckBox->setChecked(dsn->getShowMorphingAngularForces()); miscLinearForcesCheckBox->setChecked(dsn->getShowMorphingLinearForces()); miscForceVectorLengthDoubleSpinBox->setValue(dsn->getForceVectorDisplayLength()); miscIdentifyNodeColorComboBox->setCurrentIndex(dsn->getIdentifyNodeColor()); bool showAxes, showLetters, showHashMarks; float axesLength, offset[3]; dsn->getSurfaceAxesInfo(showAxes, showLetters, showHashMarks, axesLength, offset); miscAxesGroupBox->setChecked(showAxes); miscAxesShowLettersCheckBox->setChecked(showLetters); miscAxesShowTickMarksCheckBox->setChecked(showHashMarks); miscAxesLengthDoubleSpinBox->setValue(axesLength); miscAxesOffsetDoubleSpinBox[0]->setValue(offset[0]); miscAxesOffsetDoubleSpinBox[1]->setValue(offset[1]); miscAxesOffsetDoubleSpinBox[2]->setValue(offset[2]); surfaceMiscWidgetGroup->blockSignals(false); } /** * Read the selections on the misc page */ void GuiDisplayControlDialog::readMiscSelections() { if (creatingDialog) { return; } // // Update fiducial/volume interaction surfaces // theMainWindow->getBrainSet()->setLeftFiducialVolumeInteractionSurface( miscLeftFiducialVolumeInteractionComboBox->getSelectedBrainModelSurface()); theMainWindow->getBrainSet()->setRightFiducialVolumeInteractionSurface( miscRightFiducialVolumeInteractionComboBox->getSelectedBrainModelSurface()); theMainWindow->getBrainSet()->setCerebellumFiducialVolumeInteractionSurface( miscCerebellumFiducialVolumeInteractionComboBox->getSelectedBrainModelSurface()); // // Update active fiducial surface // BrainModelSurface* active = miscActiveFiducialComboBox->getSelectedBrainModelSurface(); if (active != NULL) { BrainModelSurface* currentActive = theMainWindow->getBrainSet()->getActiveFiducialSurface(); if (currentActive != active) { theMainWindow->getBrainSet()->setActiveFiducialSurface(active); } } // // Display settings for nodes // DisplaySettingsSurface* dsn = theMainWindow->getBrainSet()->getDisplaySettingsSurface(); dsn->setDrawMode( static_cast(miscDrawModeComboBox->currentIndex())); dsn->setViewingProjection(static_cast( miscProjectionComboBox->currentIndex())); dsn->setNodeBrightness(miscBrightnessDoubleSpinBox->value()); dsn->setNodeContrast(miscContrastDoubleSpinBox->value()); dsn->setOpacity(opacityDoubleSpinBox->value()); dsn->setNodeSize(miscNodeSizeSpinBox->value()); dsn->setLinkSize(miscLinkSizeSpinBox->value()); dsn->setShowNormals(miscShowNormalsCheckBox->isChecked()); dsn->setShowMorphingTotalForces(miscTotalForcesCheckBox->isChecked()); dsn->setShowMorphingAngularForces(miscAngularForcesCheckBox->isChecked()); dsn->setShowMorphingLinearForces(miscLinearForcesCheckBox->isChecked()); dsn->setForceVectorDisplayLength(miscForceVectorLengthDoubleSpinBox->value()); dsn->setIdentifyNodeColor(static_cast( miscIdentifyNodeColorComboBox->currentIndex())); const float offset[3] = { miscAxesOffsetDoubleSpinBox[0]->value(), miscAxesOffsetDoubleSpinBox[1]->value(), miscAxesOffsetDoubleSpinBox[2]->value() }; dsn->setSurfaceAxesInfo(miscAxesGroupBox->isChecked(), miscAxesShowLettersCheckBox->isChecked(), miscAxesShowTickMarksCheckBox->isChecked(), miscAxesLengthDoubleSpinBox->value(), offset); theMainWindow->getBrainSet()->getNodeColoring()->assignColors(); GuiBrainModelOpenGL::updateAllGL(NULL); } /** * Create the probabilistic atlas surface main page */ void GuiDisplayControlDialog::createProbAtlasSurfaceMainPage() { // // Normal/Threshold buttons // probAtlasSurfaceNormalButton = new QRadioButton("Normal"); probAtlasSurfaceThresholdButton = new QRadioButton("Threshold"); // // Button group for probabilistic display type // QButtonGroup* probButtonGroup = new QButtonGroup(this); QObject::connect(probButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(probAtlasSurfaceModeSelection(int))); probButtonGroup->addButton(probAtlasSurfaceNormalButton, 0); probButtonGroup->addButton(probAtlasSurfaceThresholdButton, 1); // // Group box for display mode // QGroupBox* displayModeGroupBox = new QGroupBox("Display Mode"); QVBoxLayout* displayModeGroupLayout = new QVBoxLayout(displayModeGroupBox); displayModeGroupLayout->addWidget(probAtlasSurfaceNormalButton); displayModeGroupLayout->addWidget(probAtlasSurfaceThresholdButton); displayModeGroupBox->setFixedSize(displayModeGroupBox->sizeHint()); // // Treat button // probAtlasSurfaceUnassignedButton = new QCheckBox("Treat name \"???\" as if it was name \"Unassigned\""); QObject::connect(probAtlasSurfaceUnassignedButton, SIGNAL(clicked()), this, SLOT(readProbAtlasSurfaceMainPage())); // // Threshold ratio // QLabel* ratioLabel = new QLabel("Threshold Ratio "); probAtlasSurfaceThresholdRatioDoubleSpinBox = new QDoubleSpinBox; probAtlasSurfaceThresholdRatioDoubleSpinBox->setMinimum(0.0); probAtlasSurfaceThresholdRatioDoubleSpinBox->setMaximum(1.0); probAtlasSurfaceThresholdRatioDoubleSpinBox->setSingleStep(0.1); probAtlasSurfaceThresholdRatioDoubleSpinBox->setDecimals(2); QObject::connect(probAtlasSurfaceThresholdRatioDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readProbAtlasSurfaceMainPage())); QHBoxLayout* ratioLayout = new QHBoxLayout; ratioLayout->addWidget(ratioLabel); ratioLayout->addWidget(probAtlasSurfaceThresholdRatioDoubleSpinBox); ratioLayout->addStretch(); QLabel* questLabel = new QLabel("\nNote: Names \"???\", \"GYRAL\", and \"GYRUS\" are\n" "ignored when Threshold Display Mode is selected."); // // Display color key button // QPushButton* colorKeyPushButton = new QPushButton("Display Color Key..."); colorKeyPushButton->setFixedSize(colorKeyPushButton->sizeHint()); colorKeyPushButton->setAutoDefault(false); QObject::connect(colorKeyPushButton, SIGNAL(clicked()), theMainWindow, SLOT(displayProbabilisticAtlasColorKey())); // // Set study metadata link button // QPushButton* studyMetaDataLinkPushButton = new QPushButton("Study Metadata Link..."); studyMetaDataLinkPushButton->setFixedSize(studyMetaDataLinkPushButton->sizeHint()); studyMetaDataLinkPushButton->setAutoDefault(false); QObject::connect(studyMetaDataLinkPushButton, SIGNAL(clicked()), this, SLOT(volumeProbAtlasSurfaceStudyMetaDataPushButton())); // // Widget and layout // pageProbAtlasSurfaceMain = new QWidget; QVBoxLayout* probAtlasSurfaceLayout = new QVBoxLayout(pageProbAtlasSurfaceMain); probAtlasSurfaceLayout->addWidget(displayModeGroupBox); probAtlasSurfaceLayout->addWidget(probAtlasSurfaceUnassignedButton); probAtlasSurfaceLayout->addLayout(ratioLayout); probAtlasSurfaceLayout->addWidget(questLabel); probAtlasSurfaceLayout->addWidget(colorKeyPushButton); probAtlasSurfaceLayout->addWidget(studyMetaDataLinkPushButton); probAtlasSurfaceLayout->addStretch(); pageWidgetStack->addWidget(pageProbAtlasSurfaceMain); } /** * called to set prob atlas surface study metadata link. */ void GuiDisplayControlDialog::volumeProbAtlasSurfaceStudyMetaDataPushButton() { ProbabilisticAtlasFile* paf = theMainWindow->getBrainSet()->getProbabilisticAtlasSurfaceFile(); StudyMetaDataLinkSet smdls = paf->getStudyMetaDataLinkSet(); GuiStudyMetaDataLinkCreationDialog smdlcd(this); smdlcd.initializeSelectedLinkSet(smdls); if (smdlcd.exec() == GuiStudyMetaDataLinkCreationDialog::Accepted) { smdls = smdlcd.getLinkSetCreated(); paf->setStudyMetaDataLinkSet(smdls); } } /** * Slot for prob atlas mode selection. */ void GuiDisplayControlDialog::probAtlasSurfaceModeSelection(int num) { DisplaySettingsProbabilisticAtlas* dspa = theMainWindow->getBrainSet()->getDisplaySettingsProbabilisticAtlasSurface(); dspa->setDisplayType( static_cast(num)); readProbAtlasSurfaceMainPage(); } /** * Create prob atlas surface channel selection page */ void GuiDisplayControlDialog::createProbAtlasSurfaceChannelPage() { // // widget and layout for chanel sub page // pageProbAtlasSurfaceChannel = new QWidget; pageProbAtlasSurfaceChannel->setFixedWidth(450); probAtlasSurfaceSubPageChannelLayout = new QVBoxLayout(pageProbAtlasSurfaceChannel); // // All off and all on pushbuttons // QPushButton* probAtlasSurfaceChannelAllOnButton = new QPushButton("All On"); probAtlasSurfaceChannelAllOnButton->setAutoDefault(false); QObject::connect(probAtlasSurfaceChannelAllOnButton, SIGNAL(clicked()), this, SLOT(probAtlasSurfaceChannelAllOn())); QPushButton* probAtlasSurfaceChannelAllOffButton = new QPushButton("All Off"); probAtlasSurfaceChannelAllOffButton->setAutoDefault(false); QObject::connect(probAtlasSurfaceChannelAllOffButton, SIGNAL(clicked()), this, SLOT(probAtlasSurfaceChannelAllOff())); QHBoxLayout* allOnOffButtonsLayout = new QHBoxLayout; allOnOffButtonsLayout->addWidget(probAtlasSurfaceChannelAllOnButton); allOnOffButtonsLayout->addWidget(probAtlasSurfaceChannelAllOffButton); allOnOffButtonsLayout->addStretch(); probAtlasSurfaceSubPageChannelLayout->addLayout(allOnOffButtonsLayout); createAndUpdateProbAtlasSurfaceChannelCheckBoxes(); pageWidgetStack->addWidget(pageProbAtlasSurfaceChannel); } /** * This slot is called when the prob atlas surface channel all on button is pressed */ void GuiDisplayControlDialog::probAtlasSurfaceChannelAllOn() { DisplaySettingsProbabilisticAtlas* dspa = theMainWindow->getBrainSet()->getDisplaySettingsProbabilisticAtlasSurface(); dspa->setAllChannelsSelectedStatus(true); updateProbAtlasSurfaceItems(); readProbAtlasSurfaceChannelPage(); } /** * This slot is called when the prob atlas surfacechannel all off button is pressed */ void GuiDisplayControlDialog::probAtlasSurfaceChannelAllOff() { DisplaySettingsProbabilisticAtlas* dspa = theMainWindow->getBrainSet()->getDisplaySettingsProbabilisticAtlasSurface(); dspa->setAllChannelsSelectedStatus(false); updateProbAtlasSurfaceItems(); readProbAtlasSurfaceChannelPage(); } /** * caret prob atlas surface area selection page */ void GuiDisplayControlDialog::createProbAtlasSurfaceAreaPage() { // // Vertical Box Layout for all items // pageProbAtlasSurfaceArea = new QWidget; pageProbAtlasSurfaceArea->setFixedWidth(450); probAtlasSurfaceSubPageAreaLayout = new QVBoxLayout(pageProbAtlasSurfaceArea); // // All off and all on pushbuttons // QPushButton* probAtlasSurfaceAreasAllOnButton = new QPushButton("All On"); probAtlasSurfaceAreasAllOnButton->setAutoDefault(false); QObject::connect(probAtlasSurfaceAreasAllOnButton, SIGNAL(clicked()), this, SLOT(probAtlasSurfaceAreasAllOn())); QPushButton* probAtlasSurfaceAreasAllOffButton = new QPushButton("All Off"); probAtlasSurfaceAreasAllOffButton->setAutoDefault(false); QObject::connect(probAtlasSurfaceAreasAllOffButton, SIGNAL(clicked()), this, SLOT(probAtlasSurfaceAreasAllOff())); QHBoxLayout* allOnOffButtonsLayout = new QHBoxLayout; allOnOffButtonsLayout->addWidget(probAtlasSurfaceAreasAllOnButton); allOnOffButtonsLayout->addWidget(probAtlasSurfaceAreasAllOffButton); allOnOffButtonsLayout->addStretch(); probAtlasSurfaceSubPageAreaLayout->addLayout(allOnOffButtonsLayout); createAndUpdateProbAtlasSurfaceAreaNameCheckBoxes(); pageWidgetStack->addWidget(pageProbAtlasSurfaceArea); } /** * This slot is called when the prob atlas surfce areas all on button is pressed */ void GuiDisplayControlDialog::probAtlasSurfaceAreasAllOn() { DisplaySettingsProbabilisticAtlas* dspa = theMainWindow->getBrainSet()->getDisplaySettingsProbabilisticAtlasSurface(); dspa->setAllAreasSelectedStatus(true); updateProbAtlasSurfaceItems(); readProbAtlasSurfaceAreaPage(); } /** * This slot is called when the prob atlas surface areas all off button is pressed */ void GuiDisplayControlDialog::probAtlasSurfaceAreasAllOff() { DisplaySettingsProbabilisticAtlas* dspa = theMainWindow->getBrainSet()->getDisplaySettingsProbabilisticAtlasSurface(); dspa->setAllAreasSelectedStatus(false); updateProbAtlasSurfaceItems(); readProbAtlasSurfaceAreaPage(); } /** * read the probabilistic atlas surface main page. */ void GuiDisplayControlDialog::readProbAtlasSurfaceMainPage() { if (pageProbAtlasSurfaceMain == NULL) { return; } DisplaySettingsProbabilisticAtlas* dspa = theMainWindow->getBrainSet()->getDisplaySettingsProbabilisticAtlasSurface(); dspa->setTreatQuestColorAsUnassigned(probAtlasSurfaceUnassignedButton->isChecked()); dspa->setThresholdDisplayTypeRatio(probAtlasSurfaceThresholdRatioDoubleSpinBox->value()); theMainWindow->getBrainSet()->getNodeColoring()->assignColors(); GuiBrainModelOpenGL::updateAllGL(NULL); theMainWindow->getBrainSet()->getNodeColoring()->assignColors(); GuiBrainModelOpenGL::updateAllGL(NULL); } /** * read the probabilistic atlas surface channel page. */ void GuiDisplayControlDialog::readProbAtlasSurfaceChannelPage() { if (pageProbAtlasSurfaceChannel == NULL) { return; } ProbabilisticAtlasFile* paf = theMainWindow->getBrainSet()->getProbabilisticAtlasSurfaceFile(); DisplaySettingsProbabilisticAtlas* dspa = theMainWindow->getBrainSet()->getDisplaySettingsProbabilisticAtlasSurface(); const int numChannels = paf->getNumberOfColumns(); if (numChannels == numValidProbAtlasSurfaceChannels) { for (int i = 0; i < numChannels; i++) { dspa->setChannelSelected(i, probAtlasSurfaceChannelCheckBoxes[i]->isChecked()); } } else { std::cerr << "Number of prob atlas surfce channel checkboxes does not equal number of " << "prob atlas channels." << std::endl; } theMainWindow->getBrainSet()->getNodeColoring()->assignColors(); GuiBrainModelOpenGL::updateAllGL(NULL); } /** * read the probabilistic atlas surface area page. */ void GuiDisplayControlDialog::readProbAtlasSurfaceAreaPage() { if (pageProbAtlasSurfaceArea == NULL) { return; } ProbabilisticAtlasFile* paf = theMainWindow->getBrainSet()->getProbabilisticAtlasSurfaceFile(); DisplaySettingsProbabilisticAtlas* dspa = theMainWindow->getBrainSet()->getDisplaySettingsProbabilisticAtlasSurface(); const int numAreas = paf->getNumberOfPaintNames(); if (numAreas == numValidProbAtlasSurfaceAreas) { for (int i = 0; i < numAreas; i++) { dspa->setAreaSelected(i, probAtlasSurfaceAreasCheckBoxes[i]->isChecked()); } } else { std::cerr << "Number of prob atlas surface area checkboxes does not equal number of " << "prob atlas surface areas." << std::endl; } theMainWindow->getBrainSet()->getNodeColoring()->assignColors(); GuiBrainModelOpenGL::updateAllGL(NULL); } /** * Read the prob atlas surface selections. */ void GuiDisplayControlDialog::readProbAtlasSurfaceL2LR2R() { if (creatingDialog) { return; } DisplaySettingsProbabilisticAtlas* dspa = theMainWindow->getBrainSet()->getDisplaySettingsProbabilisticAtlasSurface(); dspa->setApplySelectionToLeftAndRightStructuresFlag(probAtlasSurfaceApplySelectionToLeftAndRightStructuresFlagCheckBox->isChecked()); theMainWindow->getBrainSet()->getNodeColoring()->assignColors(); GuiBrainModelOpenGL::updateAllGL(NULL); displayOverlayLeftToLeftRightToRightMessage(); } /** * create and update the check boxes for prob atlas surface channels */ void GuiDisplayControlDialog::createAndUpdateProbAtlasSurfaceChannelCheckBoxes() { ProbabilisticAtlasFile* paf = theMainWindow->getBrainSet()->getProbabilisticAtlasSurfaceFile(); numValidProbAtlasSurfaceChannels = paf->getNumberOfColumns(); const int numExistingCheckBoxes = static_cast(probAtlasSurfaceChannelCheckBoxes.size()); if (probAtlasSurfaceChannelGridLayout == NULL) { // // Create the page and layout // QWidget* channelPage = new QWidget; probAtlasSurfaceChannelGridLayout = new QGridLayout(channelPage); const int rowStretchNumber = 15000; probAtlasSurfaceChannelGridLayout->addWidget(new QLabel(""), rowStretchNumber, 0, 1, 1, Qt::AlignLeft); probAtlasSurfaceChannelGridLayout->setRowStretch(rowStretchNumber, 1000); probAtlasSurfaceSubPageChannelLayout->addWidget(channelPage); } if (probAtlasSurfaceChannelButtonGroup == NULL) { probAtlasSurfaceChannelButtonGroup = new QButtonGroup(this); probAtlasSurfaceChannelButtonGroup->setExclusive(false); QObject::connect(probAtlasSurfaceChannelButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(readProbAtlasSurfaceChannelPage())); } // // update existing checkboxes // for (int i = 0; i < numExistingCheckBoxes; i++) { if (i < numValidProbAtlasSurfaceChannels) { probAtlasSurfaceChannelCheckBoxes[i]->setText(paf->getColumnName(i)); probAtlasSurfaceChannelCheckBoxes[i]->show(); } } // // Add new checkboxes as needed // for (int j = numExistingCheckBoxes; j < numValidProbAtlasSurfaceChannels; j++) { QCheckBox* cb = new QCheckBox(paf->getColumnName(j)); probAtlasSurfaceChannelCheckBoxes.push_back(cb); probAtlasSurfaceChannelButtonGroup->addButton(cb, j); probAtlasSurfaceChannelGridLayout->addWidget(cb, j, 0, 1, 1, Qt::AlignLeft); cb->show(); } // // Hide existing checkboxes that are not needed // for (int k = numValidProbAtlasSurfaceChannels; k < numExistingCheckBoxes; k++) { probAtlasSurfaceChannelCheckBoxes[k]->hide(); } } /** * create and update the check boxes for prob atlas surface area names */ void GuiDisplayControlDialog::createAndUpdateProbAtlasSurfaceAreaNameCheckBoxes() { ProbabilisticAtlasFile* paf = theMainWindow->getBrainSet()->getProbabilisticAtlasSurfaceFile(); numValidProbAtlasSurfaceAreas = paf->getNumberOfPaintNames(); const int numExistingCheckBoxes = static_cast(probAtlasSurfaceAreasCheckBoxes.size()); if (probAtlasSurfaceAreasGridLayout == NULL) { // QWidget* areasWidget = new QWidget; probAtlasSurfaceAreasGridLayout = new QGridLayout(areasWidget); const int rowStretchNumber = 15000; probAtlasSurfaceAreasGridLayout->addWidget(new QLabel(""), rowStretchNumber, 0, 1, 1, Qt::AlignLeft); probAtlasSurfaceAreasGridLayout->setRowStretch(rowStretchNumber, 1000); probAtlasSurfaceSubPageAreaLayout->addWidget(areasWidget); } if (probAtlasSurfaceAreasButtonGroup == NULL) { probAtlasSurfaceAreasButtonGroup = new QButtonGroup(this); probAtlasSurfaceAreasButtonGroup->setExclusive(false); QObject::connect(probAtlasSurfaceAreasButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(readProbAtlasSurfaceAreaPage())); } // // update existing checkboxes // for (int i = 0; i < numExistingCheckBoxes; i++) { if (i < numValidProbAtlasSurfaceAreas) { probAtlasSurfaceAreasCheckBoxes[i]->setText(paf->getPaintNameFromIndex(i)); probAtlasSurfaceAreasCheckBoxes[i]->show(); } } // // Add new checkboxes as needed // for (int j = numExistingCheckBoxes; j < numValidProbAtlasSurfaceAreas; j++) { QCheckBox* cb = new QCheckBox(paf->getPaintNameFromIndex(j)); probAtlasSurfaceAreasCheckBoxes.push_back(cb); probAtlasSurfaceAreasButtonGroup->addButton(cb, j); probAtlasSurfaceAreasGridLayout->addWidget(cb, j, 0, 1, 1, Qt::AlignLeft); cb->show(); } // // Hide existing checkboxes that are not needed // for (int k = numValidProbAtlasSurfaceAreas; k < numExistingCheckBoxes; k++) { probAtlasSurfaceAreasCheckBoxes[k]->hide(); } } /** * update prob atlas surface main page. */ void GuiDisplayControlDialog::updateProbAtlasSurfaceMainPage() { if (pageProbAtlasSurfaceMain == NULL) { return; } DisplaySettingsProbabilisticAtlas* dspa = theMainWindow->getBrainSet()->getDisplaySettingsProbabilisticAtlasSurface(); probAtlasSurfaceUnassignedButton->setChecked(dspa->getTreatQuestColorAsUnassigned()); switch(dspa->getDisplayType()) { case DisplaySettingsProbabilisticAtlas::PROBABILISTIC_DISPLAY_TYPE_NORMAL: probAtlasSurfaceNormalButton->setChecked(true); break; case DisplaySettingsProbabilisticAtlas::PROBABILISTIC_DISPLAY_TYPE_THRESHOLD: probAtlasSurfaceThresholdButton->setChecked(true); break; } probAtlasSurfaceThresholdRatioDoubleSpinBox->setValue(dspa->getThresholdDisplayTypeRatio()); pageProbAtlasSurfaceMain->setEnabled(validProbAtlasSurfaceData); } /** * update prob atlas surface channel page. */ void GuiDisplayControlDialog::updateProbAtlasSurfaceChannelPage(const bool filesWereChanged) { if (pageProbAtlasSurfaceChannel == NULL) { return; } ProbabilisticAtlasFile* paf = theMainWindow->getBrainSet()->getProbabilisticAtlasSurfaceFile(); DisplaySettingsProbabilisticAtlas* dspa = theMainWindow->getBrainSet()->getDisplaySettingsProbabilisticAtlasSurface(); if (filesWereChanged) { createAndUpdateProbAtlasSurfaceChannelCheckBoxes(); } const int numChannels = paf->getNumberOfColumns(); if (numChannels == numValidProbAtlasSurfaceChannels) { for (int i = 0; i < numValidProbAtlasSurfaceChannels; i++) { probAtlasSurfaceChannelCheckBoxes[i]->setChecked(dspa->getChannelSelected(i)); } } else { std::cerr << "Number of prob atlas surface channel checkboxes " << numValidProbAtlasSurfaceChannels << " does not equal number of prob " << "atlas surface channels" << numChannels << "." << std::endl; } pageProbAtlasSurfaceChannel->setEnabled(validProbAtlasSurfaceData); } /** * update prob atlas surface area page. */ void GuiDisplayControlDialog::updateProbAtlasSurfaceAreaPage(const bool filesWereChanged) { if (pageProbAtlasSurfaceArea == NULL) { return; } ProbabilisticAtlasFile* paf = theMainWindow->getBrainSet()->getProbabilisticAtlasSurfaceFile(); DisplaySettingsProbabilisticAtlas* dspa = theMainWindow->getBrainSet()->getDisplaySettingsProbabilisticAtlasSurface(); if (filesWereChanged) { createAndUpdateProbAtlasSurfaceAreaNameCheckBoxes(); } const int numAreas = paf->getNumberOfPaintNames(); if (numAreas == numValidProbAtlasSurfaceAreas) { for (int i = 0; i < numValidProbAtlasSurfaceAreas; i++) { probAtlasSurfaceAreasCheckBoxes[i]->setChecked(dspa->getAreaSelected(i)); } } else { std::cerr << "Number of prob atlas surface area checkboxes " << numValidProbAtlasSurfaceAreas << " does not equal number of prob " << "atlas surface areas" << numAreas << "." << std::endl; } pageProbAtlasSurfaceArea->setEnabled(validProbAtlasSurfaceData); } /** * update prob atlas surface overlay/underlay selection. */ void GuiDisplayControlDialog::updateProbAtlasSurfaceOverlayUnderlaySelection() { } /** * Update prob atlas surface items in dialog */ void GuiDisplayControlDialog::updateProbAtlasSurfaceItems(const bool filesChanged) { updatePageSelectionComboBox(); updateProbAtlasSurfaceOverlayUnderlaySelection(); DisplaySettingsProbabilisticAtlas* dspa = theMainWindow->getBrainSet()->getDisplaySettingsProbabilisticAtlasSurface(); probAtlasSurfaceApplySelectionToLeftAndRightStructuresFlagCheckBox->blockSignals(true); probAtlasSurfaceApplySelectionToLeftAndRightStructuresFlagCheckBox->setChecked(dspa->getApplySelectionToLeftAndRightStructuresFlag()); probAtlasSurfaceApplySelectionToLeftAndRightStructuresFlagCheckBox->blockSignals(false); updateProbAtlasSurfaceMainPage(); updateProbAtlasSurfaceChannelPage(filesChanged); updateProbAtlasSurfaceAreaPage(filesChanged); } /** * Create the topography page. */ void GuiDisplayControlDialog::createTopographyPage() { // // Eccentricity/Polar Angle. // topographyTypeEccentricityRadioButton = new QRadioButton("Eccentricity"); topographyPolarAngleRadioButton = new QRadioButton("Polar Angle"); // // Button group for eccentricity/polar angle buttons // QButtonGroup* topographyButtonGroup = new QButtonGroup(this); QObject::connect(topographyButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(topographyTypeSelection(int))); topographyButtonGroup->addButton(topographyTypeEccentricityRadioButton, static_cast(DisplaySettingsTopography::TOPOGRAPHY_DISPLAY_ECCENTRICITY)); topographyButtonGroup->addButton(topographyPolarAngleRadioButton, static_cast(DisplaySettingsTopography::TOPOGRAPHY_DISPLAY_POLAR_ANGLE)); // // Group box for display mode // QGroupBox* topographyGroup = new QGroupBox("Display Mode"); QVBoxLayout* topographyGroupLayout = new QVBoxLayout(topographyGroup); topographyGroupLayout->addWidget(topographyTypeEccentricityRadioButton); topographyGroupLayout->addWidget(topographyPolarAngleRadioButton); topographyGroup->setFixedSize(topographyGroup->sizeHint()); // // Topography page and layout // pageTopography = new QWidget; pageWidgetStack->addWidget(pageTopography); // adds to dialog QVBoxLayout* topographyLayout = new QVBoxLayout(pageTopography); topographyLayout->addWidget(topographyGroup); topographyLayout->addStretch(); } /** * Read the topography selections. */ void GuiDisplayControlDialog::readTopographySelections() { updateSurfaceOverlayWidgets(); theMainWindow->getBrainSet()->getNodeColoring()->assignColors(); GuiBrainModelOpenGL::updateAllGL(NULL); } /** * Update topography items in dialog */ void GuiDisplayControlDialog::updateTopographyItems() { updatePageSelectionComboBox(); if (pageTopography == NULL) { return; } DisplaySettingsTopography* dst = theMainWindow->getBrainSet()->getDisplaySettingsTopography(); switch(dst->getDisplayType()) { case DisplaySettingsTopography::TOPOGRAPHY_DISPLAY_ECCENTRICITY: topographyTypeEccentricityRadioButton->setChecked(true); break; case DisplaySettingsTopography::TOPOGRAPHY_DISPLAY_POLAR_ANGLE: topographyPolarAngleRadioButton->setChecked(true); break; } pageTopography->setEnabled(validTopographyData); } void GuiDisplayControlDialog::topographyTypeSelection(int typeSelected) { DisplaySettingsTopography* dst = theMainWindow->getBrainSet()->getDisplaySettingsTopography(); dst->setDisplayType(static_cast( typeSelected)); readTopographySelections(); } /** * create the geodesic page. */ void GuiDisplayControlDialog::createGeodesicPage() { // // Widget for geodesic items // pageGeodesicMain = new QWidget; pageWidgetStack->addWidget(pageGeodesicMain); // adds to dialog geodesicMainPageLayout = new QVBoxLayout(pageGeodesicMain); // // Enable geodesic check box // geodesicDistanceEnableCheckBox = new QCheckBox("Enable Geodesic Path For Identified Nodes"); QObject::connect(geodesicDistanceEnableCheckBox, SIGNAL(toggled(bool)), this, SLOT(readGeodesicSelections())); geodesicMainPageLayout->addWidget(geodesicDistanceEnableCheckBox); // // Show root node check box // geodesicShowRootNodeCheckBox = new QCheckBox("Show Root Node"); QObject::connect(geodesicShowRootNodeCheckBox, SIGNAL(toggled(bool)), this, SLOT(readGeodesicSelections())); geodesicMainPageLayout->addWidget(geodesicShowRootNodeCheckBox); // // Path width spin box // QLabel* pathLabel = new QLabel("Path Line Width "); float minWF, maxWF; GuiBrainModelOpenGL::getLineWidthRange(minWF, maxWF); const int minW = static_cast(minWF); const int maxW = static_cast(maxWF); geodesicPathLineWidthSpinBox = new QSpinBox; geodesicPathLineWidthSpinBox->setMinimum(minW); geodesicPathLineWidthSpinBox->setMaximum(maxW); geodesicPathLineWidthSpinBox->setSingleStep(1); QObject::connect(geodesicPathLineWidthSpinBox, SIGNAL(valueChanged(int)), this, SLOT(readGeodesicSelections())); QHBoxLayout* pathLayout = new QHBoxLayout; pathLayout->addWidget(pathLabel); pathLayout->addWidget(geodesicPathLineWidthSpinBox); pathLayout->addStretch(); geodesicMainPageLayout->addLayout(pathLayout); // // Selection button group // geodesicSelectionButtonGroup = new QButtonGroup(this); geodesicSelectionButtonGroup->setExclusive(true); QObject::connect(geodesicSelectionButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(readGeodesicSelections())); // // comment button group // geodesicCommentButtonGroup = new QButtonGroup(this); QObject::connect(geodesicCommentButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(geodesicCommentColumnSelection(int))); } /** * Called to display comment information about a geodesic column. */ void GuiDisplayControlDialog::geodesicCommentColumnSelection(int column) { GeodesicDistanceFile* gdf = theMainWindow->getBrainSet()->getGeodesicDistanceFile(); if ((column >= 0) && (column < gdf->getNumberOfColumns())) { GuiDataFileCommentDialog* dfcd = new GuiDataFileCommentDialog(theMainWindow, gdf, column); dfcd->show(); } } /** * Create and update the geodesic page. */ void GuiDisplayControlDialog::createAndUpdateGeodesicPage() { GeodesicDistanceFile* gdf = theMainWindow->getBrainSet()->getGeodesicDistanceFile(); numValidGeodesic = gdf->getNumberOfColumns(); const int numExistingGeodesic = static_cast(geodesicNameLineEdits.size()); const int nameMinimumWidth = 400; if (geodesicSelectionGridLayout == NULL) { QWidget* geodesicSelectionWidget = new QWidget; geodesicSelectionGridLayout = new QGridLayout(geodesicSelectionWidget); geodesicSelectionGridLayout->setMargin(3); geodesicSelectionGridLayout->setSpacing(3); geodesicSelectionGridLayout->setColumnMinimumWidth(2, nameMinimumWidth+20); const int rowStretchNumber = 15000; geodesicSelectionGridLayout->addWidget(new QLabel(""), rowStretchNumber, 3, 1, 1, Qt::AlignLeft); geodesicSelectionGridLayout->setColumnStretch(0, 1); geodesicSelectionGridLayout->setColumnStretch(1, 1); geodesicSelectionGridLayout->setColumnStretch(2, 1); //1000); geodesicSelectionGridLayout->setRowStretch(rowStretchNumber, 1000); geodesicMainPageLayout->addWidget(geodesicSelectionWidget, 10, Qt::AlignLeft); } // // Add radio buttons and text boxes // for (int i = numExistingGeodesic; i < numValidGeodesic; i++) { // // Selection button // QRadioButton* selectButton = new QRadioButton(""); geodesicSelectionButtonGroup->addButton(selectButton, i); geodesicSelectionRadioButtons.push_back(selectButton); geodesicSelectionGridLayout->addWidget(selectButton, i, 0, Qt::AlignHCenter); // // Comment push button // QPushButton* commentPushButton = new QPushButton("?"); commentPushButton->setAutoDefault(false); commentPushButton->setFixedWidth(40); geodesicColumnCommentPushButtons.push_back(commentPushButton); geodesicCommentButtonGroup->addButton(commentPushButton, i); geodesicSelectionGridLayout->addWidget(commentPushButton, i, 1, Qt::AlignHCenter); QLineEdit* le = new QLineEdit; le->setMinimumWidth(nameMinimumWidth); le->setMaximumWidth(1000); geodesicNameLineEdits.push_back(le); QObject::connect(le, SIGNAL(returnPressed()), this, SLOT(readGeodesicSelections())); geodesicSelectionGridLayout->addWidget(le, i, 2, Qt::AlignLeft); } // // Update items already in the dialog // for (int i = 0; i < numValidGeodesic; i++) { geodesicSelectionRadioButtons[i]->show(); geodesicColumnCommentPushButtons[i]->show(); geodesicNameLineEdits[i]->setText(gdf->getColumnName(i)); geodesicNameLineEdits[i]->home(false); geodesicNameLineEdits[i]->show(); } // // Hide geodesic that are not needed // for (int i = numValidGeodesic; i < numExistingGeodesic; i++) { geodesicSelectionRadioButtons[i]->hide(); geodesicColumnCommentPushButtons[i]->hide(); geodesicNameLineEdits[i]->hide(); } } /** * read the geodesic page. */ void GuiDisplayControlDialog::readGeodesicSelections() { if (creatingDialog) { return; } DisplaySettingsGeodesicDistance* dsgd = theMainWindow->getBrainSet()->getDisplaySettingsGeodesicDistance(); GeodesicDistanceFile* gdf = theMainWindow->getBrainSet()->getGeodesicDistanceFile(); if (gdf->getNumberOfColumns() > 0) { for (int i = 0; i < gdf->getNumberOfColumns(); i++) { const QString name(geodesicNameLineEdits[i]->text()); if (name != gdf->getColumnName(i)) { gdf->setColumnName(i, name); } } dsgd->setDisplayColumn(geodesicSelectionButtonGroup->checkedId()); } dsgd->setPathLineWidth(geodesicPathLineWidthSpinBox->value()); dsgd->setShowRootNode(geodesicShowRootNodeCheckBox->isChecked()); dsgd->setPathDisplayEnabled(geodesicDistanceEnableCheckBox->isChecked()); GuiFilesModified fm; fm.setGeodesicModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } /** * update geodesic items. */ void GuiDisplayControlDialog::updateGeodesicItems() { updatePageSelectionComboBox(); if (pageGeodesicMain == NULL) { return; } createAndUpdateGeodesicPage(); DisplaySettingsGeodesicDistance* dsgd = theMainWindow->getBrainSet()->getDisplaySettingsGeodesicDistance(); pageGeodesicMain->setEnabled(validGeodesicData); geodesicDistanceEnableCheckBox->setChecked(dsgd->getPathDisplayEnabled()); if ((dsgd->getDisplayColumn() >= 0) && (dsgd->getDisplayColumn() < static_cast(geodesicSelectionRadioButtons.size()))) { geodesicSelectionRadioButtons[dsgd->getDisplayColumn()]->setChecked(true); } geodesicShowRootNodeCheckBox->setChecked(dsgd->getShowRootNode()); geodesicPathLineWidthSpinBox->setValue(dsgd->getPathLineWidth()); } /** * create the lat/lon page. */ void GuiDisplayControlDialog::createLatLonPage() { // // Widget for region items // pageLatLonMain = new QWidget; pageWidgetStack->addWidget(pageLatLonMain); latLonMainPageLayout = new QVBoxLayout(pageLatLonMain); // // comment button group // latLonCommentButtonGroup = new QButtonGroup(this); QObject::connect(latLonCommentButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(latLonCommentColumnSelection(int))); } /** * Called to display comment information about a lat lon column. */ void GuiDisplayControlDialog::latLonCommentColumnSelection(int column) { LatLonFile* llf = theMainWindow->getBrainSet()->getLatLonFile(); if ((column >= 0) && (column < llf->getNumberOfColumns())) { GuiDataFileCommentDialog* dfcd = new GuiDataFileCommentDialog(theMainWindow, llf, column); dfcd->show(); } } /** * Create and update the lat lon page. */ void GuiDisplayControlDialog::createAndUpdateLatLonPage() { LatLonFile* llf = theMainWindow->getBrainSet()->getLatLonFile(); numValidLatLon = llf->getNumberOfColumns(); const int numExistingLatLon = static_cast(latLonNameLineEdits.size()); const int nameMinimumWidth = 400; if (latLonSelectionGridLayout == NULL) { QWidget* latLonSelectionWidget = new QWidget; latLonSelectionGridLayout = new QGridLayout(latLonSelectionWidget); latLonSelectionGridLayout->setMargin(3); latLonSelectionGridLayout->setSpacing(3); latLonSelectionGridLayout->setColumnMinimumWidth(2, nameMinimumWidth+20); const int rowStretchNumber = 15000; latLonSelectionGridLayout->addWidget(new QLabel(" "), rowStretchNumber, 2, 1, 1, Qt::AlignLeft); latLonSelectionGridLayout->setColumnStretch(0, 1); latLonSelectionGridLayout->setColumnStretch(1, 1); latLonSelectionGridLayout->setColumnStretch(2, 1); latLonSelectionGridLayout->setRowStretch(rowStretchNumber, 100); latLonMainPageLayout->addWidget(latLonSelectionWidget); } // // Add radio buttons and text boxes // for (int i = numExistingLatLon; i < numValidLatLon; i++) { // // Comment push button // QPushButton* commentPushButton = new QPushButton("?"); commentPushButton->setAutoDefault(false); commentPushButton->setFixedWidth(40); latLonColumnCommentPushButtons.push_back(commentPushButton); latLonCommentButtonGroup->addButton(commentPushButton, i); latLonSelectionGridLayout->addWidget(commentPushButton, i, 0, Qt::AlignHCenter); QLineEdit* le = new QLineEdit; le->setMinimumWidth(nameMinimumWidth); le->setMaximumWidth(1000); latLonNameLineEdits.push_back(le); QObject::connect(le, SIGNAL(returnPressed()), this, SLOT(readLatLonSelections())); latLonSelectionGridLayout->addWidget(le, i, 1, Qt::AlignLeft); } // // Update items already in the dialog // for (int i = 0; i < numValidLatLon; i++) { latLonColumnCommentPushButtons[i]->show(); latLonNameLineEdits[i]->setText(llf->getColumnName(i)); latLonNameLineEdits[i]->home(false); latLonNameLineEdits[i]->show(); } // // Hide lat lon that are not needed // for (int i = numValidLatLon; i < numExistingLatLon; i++) { latLonColumnCommentPushButtons[i]->hide(); latLonNameLineEdits[i]->hide(); } } /** * read the lat lon page. */ void GuiDisplayControlDialog::readLatLonSelections() { if (creatingDialog) { return; } LatLonFile* llf = theMainWindow->getBrainSet()->getLatLonFile(); if (llf->getNumberOfColumns() > 0) { for (int i = 0; i < llf->getNumberOfColumns(); i++) { const QString name(latLonNameLineEdits[i]->text()); if (name != llf->getColumnName(i)) { llf->setColumnName(i, name); } } } GuiFilesModified fm; fm.setLatLonModified(); theMainWindow->fileModificationUpdate(fm); } /** * update lat lon items. */ void GuiDisplayControlDialog::updateLatLonItems() { updatePageSelectionComboBox(); if (pageLatLonMain == NULL) { return; } latLonCommentButtonGroup->blockSignals(true); createAndUpdateLatLonPage(); latLonCommentButtonGroup->blockSignals(false); pageLatLonMain->setEnabled(validLatLonData); } /** * Create the region page. */ void GuiDisplayControlDialog::createScenePage() { // // Widget for scene items // pageSceneMain = new QWidget; pageWidgetStack->addWidget(pageSceneMain); //, PAGE_NAME_SCENE); // adds to dialog QVBoxLayout* sceneLayout = new QVBoxLayout(pageSceneMain); // // List box for scenes // sceneListBox = new QListWidget; sceneListBox->setMinimumWidth(700); sceneListBox->setFixedHeight(350); sceneListBox->setSelectionMode(QListWidget::ExtendedSelection); QObject::connect(sceneListBox, SIGNAL(itemActivated(QListWidgetItem*)), this, SLOT(slotSceneListBox(QListWidgetItem*))); sceneLayout->addWidget(sceneListBox); // // Show scene push button // QPushButton* showScenePushButton = new QPushButton("Show Selected Scene..."); showScenePushButton->setAutoDefault(false); showScenePushButton->setToolTip( "Show the selected scene."); QObject::connect(showScenePushButton, SIGNAL(clicked()), this, SLOT(slotShowScenePushButton())); // // Append scene push button // QPushButton* appendScenePushButton = new QPushButton("Append New Scene..."); appendScenePushButton->setAutoDefault(false); appendScenePushButton->setToolTip( "Create and add a new scene at\n" "the end of the list of scenes."); QObject::connect(appendScenePushButton, SIGNAL(clicked()), this, SLOT(slotAppendScenePushButton())); // // Insert scene push button // QPushButton* insertScenePushButton = new QPushButton("Insert New Scene..."); insertScenePushButton->setAutoDefault(false); insertScenePushButton->setToolTip( "Create and insert a new scene\n" "into the list of scenes after\n" "the selected scene."); QObject::connect(insertScenePushButton, SIGNAL(clicked()), this, SLOT(slotInsertScenePushButton())); // // Replace scene push button // QPushButton* replaceScenePushButton = new QPushButton("Replace Selected Scene..."); replaceScenePushButton->setAutoDefault(false); replaceScenePushButton->setToolTip( "Replace the selected\n" "scene with the current\n" "display settings."); QObject::connect(replaceScenePushButton, SIGNAL(clicked()), this, SLOT(slotReplaceScenePushButton())); // // Delete scene push button // QPushButton* deleteScenePushButton = new QPushButton("Delete Selected Scene..."); deleteScenePushButton->setAutoDefault(false); deleteScenePushButton->setToolTip( "Delete the selected scene(s)."); QObject::connect(deleteScenePushButton, SIGNAL(clicked()), this, SLOT(slotDeleteScenePushButton())); // // Check all scenes button // QPushButton* checkAllScenesPushButton = new QPushButton("Check All Scenes..."); checkAllScenesPushButton->setAutoDefault(false); checkAllScenesPushButton->setToolTip( "This will verify that all\n" "scenes successfully display."); QObject::connect(checkAllScenesPushButton, SIGNAL(clicked()), this, SLOT(slotCheckAllScenesPushButton())); // // Unload all files (except scene) // QPushButton* unloadFilesPushButton = new QPushButton("Unload All Files Except Scene..."); unloadFilesPushButton->setAutoDefault(false); unloadFilesPushButton->setToolTip( "Remove all loaded data\n" "except the scenes."); QObject::connect(unloadFilesPushButton, SIGNAL(clicked()), theMainWindow, SLOT(slotCloseSpecFileKeepSceneAndSpec())); // // Create a spec file from selected scenes // QPushButton* createSpecFromSelectedScenesPushButton = new QPushButton("Create Spec From Selected Scenes..."); createSpecFromSelectedScenesPushButton->setAutoDefault(false); createSpecFromSelectedScenesPushButton->setToolTip("Create a Spec File from\n" "the data files listed in\n" "the selected scenes."); QObject::connect(createSpecFromSelectedScenesPushButton, SIGNAL(clicked()), this, SLOT(slotCreateSpecFromSelectedScenesPushButton())); // // Transfer Identify Window Filters // QPushButton* transferIdentityWindowFiltersPushButton = new QPushButton("Transfer Identify Window Filters..."); transferIdentityWindowFiltersPushButton->setAutoDefault(false); transferIdentityWindowFiltersPushButton->setToolTip("Choose a scene from a dialog\n" "that will be popped-up and its\n" "identity window filters will be\n" "transferred to the selected scenes."); QObject::connect(transferIdentityWindowFiltersPushButton, SIGNAL(clicked()), this, SLOT(slotTransferIdentityWindowFiltersPushButton())); // // Make all of the buttons the same size // std::vector buttVect; buttVect.push_back(showScenePushButton); buttVect.push_back(appendScenePushButton); buttVect.push_back(insertScenePushButton); buttVect.push_back(replaceScenePushButton); QtUtilities::makeButtonsSameSize(buttVect); buttVect.clear(); buttVect.push_back(deleteScenePushButton); buttVect.push_back(checkAllScenesPushButton); buttVect.push_back(unloadFilesPushButton); buttVect.push_back(createSpecFromSelectedScenesPushButton); buttVect.push_back(transferIdentityWindowFiltersPushButton); QtUtilities::makeButtonsSameSize(buttVect); // // Grid for buttons // QGridLayout* buttonsLayout = new QGridLayout; sceneLayout->addLayout(buttonsLayout, 0); sceneLayout->setAlignment(buttonsLayout, Qt::AlignLeft); sceneLayout->setSpacing(0); buttonsLayout->addWidget(showScenePushButton, 0, 0); buttonsLayout->addWidget(appendScenePushButton, 1, 0); buttonsLayout->addWidget(insertScenePushButton, 2, 0); buttonsLayout->addWidget(replaceScenePushButton, 3, 0); buttonsLayout->addWidget(deleteScenePushButton, 0, 1); buttonsLayout->addWidget(checkAllScenesPushButton, 1, 1); buttonsLayout->addWidget(unloadFilesPushButton, 2, 1); buttonsLayout->addWidget(createSpecFromSelectedScenesPushButton, 3, 1); buttonsLayout->addWidget(transferIdentityWindowFiltersPushButton, 4, 1); /* QVBoxLayout* buttonsLayout = new QVBoxLayout; sceneLayout->addLayout(buttonsLayout); sceneLayout->setSpacing(0); buttonsLayout->addWidget(showScenePushButton, 0, Qt::AlignHCenter); buttonsLayout->addWidget(appendScenePushButton, 0, Qt::AlignHCenter); buttonsLayout->addWidget(insertScenePushButton, 0, Qt::AlignHCenter); buttonsLayout->addWidget(replaceScenePushButton, 0, Qt::AlignHCenter); buttonsLayout->addWidget(deleteScenePushButton, 0, Qt::AlignHCenter); if (sendScenePushButton != NULL) { buttonsLayout->addWidget(sendScenePushButton, 0, Qt::AlignHCenter); } if (sendSettingsPushButton != NULL) { buttonsLayout->addWidget(sendSettingsPushButton, 0, Qt::AlignHCenter); } buttonsLayout->addWidget(checkAllScenesPushButton, 0, Qt::AlignHCenter); buttonsLayout->addWidget(unloadFilesPushButton, 0, Qt::AlignHCenter); */ /* QtUtilities::makeButtonsSameSize(showScenePushButton, createScenePushButton, replaceScenePushButton, deleteScenePushButton, unloadFilesPushButton, sendScenePushButton); */ // // Preserve foci, foci colors, study metadata option // scenePreserveFociCheckBox = new QCheckBox("Preserve Foci, Foci Colors, and Study Metadata"); QObject::connect(scenePreserveFociCheckBox, SIGNAL(toggled(bool)), this, SLOT(readSceneSelections())); sceneLayout->addWidget(scenePreserveFociCheckBox); // // window positions // sceneWindowPositionComboBox = new QComboBox; sceneWindowPositionComboBox->insertItem(DisplaySettingsScene::WINDOW_POSITIONS_USE_ALL, "Use All Window Positions From Scene"); sceneWindowPositionComboBox->insertItem(DisplaySettingsScene::WINDOW_POSITIONS_IGNORE_MAIN_OTHERS_RELATIVE, "Do Not Move Main Window, All Other Windows Relative to Main Window"); sceneWindowPositionComboBox->insertItem(DisplaySettingsScene::WINDOW_POSITIONS_IGNORE_ALL, "Ignore All Window Positions in Scene"); QObject::connect(sceneWindowPositionComboBox, SIGNAL(activated(int)), this, SLOT(readSceneSelections())); QGroupBox* windowPosGroupBox = new QGroupBox("Window Positioning"); QVBoxLayout* windowPosGroupLayout = new QVBoxLayout(windowPosGroupBox); windowPosGroupLayout->addWidget(sceneWindowPositionComboBox); sceneLayout->addWidget(windowPosGroupBox); // // Put extra space at bottom of dialog // sceneLayout->addStretch(); pageSceneMain->setFixedSize(pageSceneMain->sizeHint()); } /** * called to transfer identity window filters. */ void GuiDisplayControlDialog::slotTransferIdentityWindowFiltersPushButton() { SceneFile* sf = theMainWindow->getBrainSet()->getSceneFile(); if (sf->getNumberOfScenes() <= 0) { QMessageBox::critical(this, "ERROR", "There are no scenes."); return; } const std::vector selectedScenes = getSelectedScenes(); if (selectedScenes.empty()) { QMessageBox::critical(this, "ERROR", "There are no selected scenes."); return; } // // Get scene names // QStringList sceneNames; for (int i = 0; i < sf->getNumberOfScenes(); i++) { const SceneFile::Scene* scene = sf->getScene(i); sceneNames << scene->getName(); } // // Get scene for source of identify filters // WuQDataEntryDialog ded(this); ded.setWindowTitle("Choose Scene for Filters"); ded.setTextAtTop("Choose scene from which the\n" "Identify Filters will be copied.", false); QListWidget* lw = ded.addListWidget("", sceneNames); QCheckBox* windowCB = ded.addCheckBox("Apply to Identify Window", true); QCheckBox* sceneCB = ded.addCheckBox("Apply to Scenes Selected on Display Control", false); if (ded.exec() == WuQDataEntryDialog::Accepted) { const int sceneNumber = lw->currentRow(); if ((sceneNumber >= 0) && (sceneNumber < sf->getNumberOfScenes())) { if (sceneCB->isChecked()) { sf->transferSceneClass(sceneNumber, selectedScenes, "BrainModelIdentification"); } if (windowCB->isChecked()) { QString msg; theMainWindow->getBrainSet()->showSceneIdentificationFilters( sf->getScene(sceneNumber), msg); GuiIdentifyDialog* idWindow = theMainWindow->getIdentifyDialog(false); idWindow->updateDialog(); if (msg.isEmpty() == false) { WuQMessageBox::critical(this, "ERROR", msg); } } } else { WuQMessageBox::critical(this, "ERROR", "No scene was selected."); } } } /** * called to create a spec file from files used in selected scenes. */ void GuiDisplayControlDialog::slotCreateSpecFromSelectedScenesPushButton() { const std::vector selectedScenes = getSelectedScenes(); if (selectedScenes.empty()) { QMessageBox::critical(this, "ERROR", "There are no selected scenes."); return; } // // Display dialog to create new spec and scene files // GuiSpecAndSceneFileCreationDialog d(this, theMainWindow->getBrainSet(), selectedScenes); d.exec(); } /** * get the selected scenes. */ std::vector GuiDisplayControlDialog::getSelectedScenes() const { std::vector sel; for (int i = 0; i < sceneListBox->count(); i++) { QListWidgetItem* item = sceneListBox->item(i); if (sceneListBox->isItemSelected(item)) { sel.push_back(i); } } return sel; } /** * set the selected scene. */ void GuiDisplayControlDialog::setSelectedSceneItem(const int item) { sceneListBox->setCurrentRow(item); /* for (unsigned int i = 0; i < sceneListBox->count(); i++) { sceneListBox->setSelected(i, (i == static_cast(item))); } */ } /** * called when a scene is selected. */ void GuiDisplayControlDialog::slotSceneListBox(QListWidgetItem* item) { for (int i = 0; i < sceneListBox->count(); i++) { if (sceneListBox->item(i) == item) { slotSceneListBox(i); break; } } } /** * called when a scene is selected. */ void GuiDisplayControlDialog::slotSceneListBox(int item) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); SceneFile* sf = theMainWindow->getBrainSet()->getSceneFile(); if ((item >= 0) && (item < sf->getNumberOfScenes())) { SceneFile::Scene* scene = sf->getScene(item); // // Clear all Left-to-Left and Right-to-Right items // shapeApplySelectionToLeftAndRightStructuresFlagCheckBox->blockSignals(true); shapeApplySelectionToLeftAndRightStructuresFlagCheckBox->setChecked(false); shapeApplySelectionToLeftAndRightStructuresFlagCheckBox->blockSignals(false); metricApplySelectionToLeftAndRightStructuresFlagCheckBox->blockSignals(true); metricApplySelectionToLeftAndRightStructuresFlagCheckBox->setChecked(false); metricApplySelectionToLeftAndRightStructuresFlagCheckBox->blockSignals(false); paintApplySelectionToLeftAndRightStructuresFlagCheckBox->blockSignals(true); paintApplySelectionToLeftAndRightStructuresFlagCheckBox->setChecked(false); paintApplySelectionToLeftAndRightStructuresFlagCheckBox->blockSignals(false); rgbApplySelectionToLeftAndRightStructuresFlagCheckBox->blockSignals(true); rgbApplySelectionToLeftAndRightStructuresFlagCheckBox->setChecked(false); rgbApplySelectionToLeftAndRightStructuresFlagCheckBox->blockSignals(false); probAtlasSurfaceApplySelectionToLeftAndRightStructuresFlagCheckBox->blockSignals(true); probAtlasSurfaceApplySelectionToLeftAndRightStructuresFlagCheckBox->setChecked(false); probAtlasSurfaceApplySelectionToLeftAndRightStructuresFlagCheckBox->blockSignals(false); QString errorMessage; theMainWindow->showScene(scene, false, errorMessage); if (errorMessage.isEmpty() == false) { //if (DebugControl::getDebugOn()) { QApplication::beep(); QtTextEditDialog* te = new QtTextEditDialog(this, true); QString msg("The following errors occurred while applying the scene:\n\n"); msg.append(errorMessage); te->setText(msg); te->show(); //} } setSelectedSceneItem(item); } QApplication::restoreOverrideCursor(); } /** * called to check all scenes. */ void GuiDisplayControlDialog::slotCheckAllScenesPushButton() { QString msg1("Press \"Continue\" to sequence through and validate\n" "all of the scenes. This may take a while."); if (QMessageBox::information(this, "Confirm Check Scenes", msg1, (QMessageBox::Ok | QMessageBox::Cancel), QMessageBox::Ok) == QMessageBox::Cancel) { return; } bool ok = false; const int pauseBetweenScenes = QInputDialog::getInteger(this, "Verify Scenes", "Pause for Seconds Between Scenes", 0, 0, 60, 1, &ok); if (ok == false) { return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); QString errorMessage; SceneFile* sf = theMainWindow->getBrainSet()->getSceneFile(); const int numScenes = sf->getNumberOfScenes(); QProgressDialog pd("Verifying Scenes", "Cancel", 0, numScenes, this); pd.setWindowTitle("Verifying Scenes"); for (int i = 0; i < numScenes; i++) { SceneFile::Scene* scene = sf->getScene(i); pd.setValue(i); pd.setLabelText(scene->getName()); pd.show(); qApp->processEvents(); if (pd.wasCanceled()) { break; } QString msg; theMainWindow->closeSpecFile(true, false); theMainWindow->showScene(scene, true, msg); if (msg.isEmpty() == false) { errorMessage.append("--------------------------------------------------------------\n"); errorMessage.append(scene->getName()); errorMessage.append("\n"); errorMessage.append(msg); errorMessage.append("\n"); errorMessage.append("\n"); } if (pauseBetweenScenes > 0) { SystemUtilities::sleepForSeconds(pauseBetweenScenes); } } pd.setValue(numScenes + 1); pd.close(); QApplication::restoreOverrideCursor(); if (errorMessage.isEmpty() == false) { QApplication::beep(); QtTextEditDialog* te = new QtTextEditDialog(this, true, false); te->setText(errorMessage); te->show(); } else { QMessageBox::information(this, "INFO", "All scenes successfully displayed."); } } /** * called to show a scene. */ void GuiDisplayControlDialog::slotShowScenePushButton() { const std::vector selectedScenes = getSelectedScenes(); if (selectedScenes.empty()) { QMessageBox::critical(this, "ERROR", "There is no selected scene."); return; } else if (selectedScenes.size() > 1) { QMessageBox::critical(this, "ERROR", "There is more than one selected scene."); return; } const int selectedIndex = selectedScenes[0]; slotSceneListBox(selectedIndex); } /** * called to delete a scene. */ void GuiDisplayControlDialog::slotDeleteScenePushButton() { const std::vector selectedScenes = getSelectedScenes(); if (selectedScenes.empty()) { QMessageBox::critical(this, "ERROR", "There are no selected scenes."); return; } SceneFile* sf = theMainWindow->getBrainSet()->getSceneFile(); if (QMessageBox::question(this, "Confirm", "Delete Selected Scene(s) ?", (QMessageBox::Ok | QMessageBox::Cancel), QMessageBox::Ok) == QMessageBox::Ok) { for (int i = selectedScenes.size() - 1; i >= 0; i--) { sf->deleteScene(selectedScenes[i]); } updateSceneItems(); const int item = selectedScenes[0]; if (item < sf->getNumberOfScenes()) { setSelectedSceneItem(item); } else if (sf->getNumberOfScenes() > 0) { setSelectedSceneItem(sf->getNumberOfScenes()); } } } /** * called to replace a scene. */ void GuiDisplayControlDialog::slotReplaceScenePushButton() { // // Check for multiple brain sets // if (theMainWindow->getNumberOfBrainSets() > 1) { QMessageBox::critical(this, "ERROR", "There is MORE than one Spec File loaded.\n" "At this time, Caret can only create scenes with one spec file loaded."); return; } const std::vector selectedScenes = getSelectedScenes(); if (selectedScenes.empty()) { QMessageBox::critical(this, "ERROR", "There is no selected scene."); return; } else if (selectedScenes.size() > 1) { QMessageBox::critical(this, "ERROR", "There is more than one selected scene."); return; } const int selectedIndex = selectedScenes[0]; SceneFile* sf = theMainWindow->getBrainSet()->getSceneFile(); // // See if data files are modified // QString msg; theMainWindow->checkForModifiedFiles(theMainWindow->getBrainSet(), msg, false); if (msg.isEmpty() == false) { // // Return value of zero is YES button. // QString msg2("It appears that data files have been modified. Since\n" "data file names are inserted into the scene file, the\n" "data files should be saved prior to saving the scene.\n\n" "\n"); msg2.append(msg); msg2.append("\n"); msg2.append("Are you sure you want to save the scene?\n"); if (QMessageBox::warning(this, "WARNING", msg2, (QMessageBox::Yes | QMessageBox::No), QMessageBox::No) == QMessageBox::No) { return; } } bool ok = false; const QString defName = sf->getScene(selectedIndex)->getName(); const QString labelValue = QString("Name of Scene").leftJustified(100, ' '); const QString qname = QInputDialog::getText(this, "Scene Name", labelValue, QLineEdit::Normal, defName, &ok); if (ok) { QString name(qname); // // Save window information // std::vector mainWindowSceneClasses; theMainWindow->saveScene(mainWindowSceneClasses); // // Save all display settings // QString errorMessage, warningMessage; theMainWindow->getBrainSet()->replaceScene(sf, selectedIndex, mainWindowSceneClasses, name, false, errorMessage, warningMessage); errorMessage += warningMessage; updateSceneItems(); setSelectedSceneItem(selectedIndex); if (errorMessage.isEmpty() == false) { QApplication::beep(); QtTextEditDialog* te = new QtTextEditDialog(this, true); QString msg(errorMessage); te->setText(msg); te->show(); } } } /** * called to append a new scene. */ void GuiDisplayControlDialog::slotAppendScenePushButton() { // // Check for multiple brain sets // if (theMainWindow->getNumberOfBrainSets() > 1) { QMessageBox::critical(this, "ERROR", "There is MORE than one Spec File loaded.\n" "At this time, Caret can only create scenes with one spec file loaded."); return; } // // See if data files are modified // QString msg; theMainWindow->checkForModifiedFiles(theMainWindow->getBrainSet(), msg, false); if (msg.isEmpty() == false) { // // Return value of zero is YES button. // QString msg2("It appears that data files have been modified. Since\n" "data file names are inserted into the scene file, the\n" "data files should be saved prior to saving the scene.\n" "\n"); msg2.append(msg); msg2.append("\n"); msg2.append("Are you sure you want to save the scene?\n"); if (QMessageBox::warning(this, "WARNING", msg2, (QMessageBox::Yes | QMessageBox::No), QMessageBox::No) == QMessageBox::No) { return; } } bool ok = false; const QString labelValue = QString("Enter Name of New Scene").leftJustified(100, ' '); const QString qname = QInputDialog::getText(this, "Scene Name", labelValue, QLineEdit::Normal, "", &ok); if (ok) { QString name(qname); // // Save window information // std::vector mainWindowSceneClasses; theMainWindow->saveScene(mainWindowSceneClasses); // // Save all display settings // QString errorMessage, warningMessage; theMainWindow->getBrainSet()->saveScene(theMainWindow->getBrainSet()->getSceneFile(), mainWindowSceneClasses, name, false, errorMessage, warningMessage); errorMessage += warningMessage; updateSceneItems(); setSelectedSceneItem(sceneListBox->count() - 1); if (errorMessage.isEmpty() == false) { QApplication::beep(); QtTextEditDialog* te = new QtTextEditDialog(this, true); QString msg(errorMessage); te->setText(msg); te->show(); } } } /** * called to insert a new scene. */ void GuiDisplayControlDialog::slotInsertScenePushButton() { // // Check for multiple brain sets // if (theMainWindow->getNumberOfBrainSets() > 1) { QMessageBox::critical(this, "ERROR", "There is MORE than one Spec File loaded.\n" "At this time, Caret can only create scenes with one spec file loaded."); return; } const std::vector selectedScenes = getSelectedScenes(); if (selectedScenes.empty()) { QMessageBox::critical(this, "ERROR", "There is no selected scene."); return; } else if (selectedScenes.size() > 1) { QMessageBox::critical(this, "ERROR", "There is more than one selected scene."); return; } const int selectedIndex = selectedScenes[0]; SceneFile* sf = theMainWindow->getBrainSet()->getSceneFile(); // // See if data files are modified // QString msg; theMainWindow->checkForModifiedFiles(theMainWindow->getBrainSet(), msg, false); if (msg.isEmpty() == false) { // // Return value of zero is YES button. // QString msg2("It appears that data files have been modified. Since\n" "data file names are inserted into the scene file, the\n" "data files should be saved prior to saving the scene.\n\n" "\n"); msg2.append(msg); msg2.append("\n"); msg2.append("Are you sure you want to save the scene?\n"); if (QMessageBox::warning(this, "WARNING", msg2, (QMessageBox::Yes | QMessageBox::No), QMessageBox::No) == QMessageBox::No) { return; } } bool ok = false; const QString labelValue = QString("Enter Name of New Scene").leftJustified(100, ' '); const QString qname = QInputDialog::getText(this, "Scene Name", labelValue, QLineEdit::Normal, "", &ok); if (ok) { QString name(qname); // // Save window information // std::vector mainWindowSceneClasses; theMainWindow->saveScene(mainWindowSceneClasses); // // Save all display settings // QString errorMessage, warningMessage; theMainWindow->getBrainSet()->insertScene(sf, selectedIndex, mainWindowSceneClasses, name, false, errorMessage, warningMessage); errorMessage += warningMessage; updateSceneItems(); setSelectedSceneItem(selectedIndex + 1); if (errorMessage.isEmpty() == false) { QApplication::beep(); QtTextEditDialog* te = new QtTextEditDialog(this, true); QString msg(errorMessage); te->setText(msg); te->show(); } } } /** * read the scene selections. */ void GuiDisplayControlDialog::readSceneSelections() { DisplaySettingsScene* dss = theMainWindow->getBrainSet()->getDisplaySettingsScene(); dss->setWindowPositionPreference( static_cast(sceneWindowPositionComboBox->currentIndex())); dss->setPreserveFociAndFociColorsAndStudyMetaDataFlag( scenePreserveFociCheckBox->isChecked()); } /** * update scene items. */ void GuiDisplayControlDialog::updateSceneItems() { updatePageSelectionComboBox(); if (pageSceneMain == NULL) { return; } // // Updating of scene page is usually skipped when a scene is being loaded // if (skipScenePageUpdate) { return; } DisplaySettingsScene* dss = theMainWindow->getBrainSet()->getDisplaySettingsScene(); sceneWindowPositionComboBox->blockSignals(true); sceneWindowPositionComboBox->setCurrentIndex(dss->getWindowPositionPreference()); sceneWindowPositionComboBox->blockSignals(false); scenePreserveFociCheckBox->blockSignals(true); scenePreserveFociCheckBox->setChecked(dss->getPreserveFociAndFociColorsAndStudyMetaDataFlag()); scenePreserveFociCheckBox->blockSignals(false); const int item = sceneListBox->currentRow(); sceneListBox->clear(); sceneListBox->blockSignals(true); SceneFile* sf = theMainWindow->getBrainSet()->getSceneFile(); for (int i = 0; i < sf->getNumberOfScenes(); i++) { const SceneFile::Scene* ss = sf->getScene(i); const QString name(ss->getName()); sceneListBox->addItem(name); } if ((item >= 0) && (item < static_cast(sceneListBox->count()))) { setSelectedSceneItem(item); } else if (sceneListBox->count() > 0) { setSelectedSceneItem(0); } sceneListBox->blockSignals(false); pageSceneMain->setEnabled(validSceneData); } /** * apply a scene (set display settings). */ void GuiDisplayControlDialog::showScene(const SceneFile::Scene& scene, QString& errorMessage) { bool haveFociSearchInSceneFlag = false; const int numClasses = scene.getNumberOfSceneClasses(); for (int nc = 0; nc < numClasses; nc++) { const SceneFile::SceneClass* sc = scene.getSceneClass(nc); if (sc->getName() == "GuiDisplayControlDialog") { const int num = sc->getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc->getSceneInfo(i); const QString infoName = si->getName(); if (infoName == "fociShowKeywordsOnlyForDisplayedFociCheckBox") { if (fociShowKeywordsOnlyForDisplayedFociCheckBox != NULL) { fociShowKeywordsOnlyForDisplayedFociCheckBox->setChecked(si->getValueAsBool()); } } else if (infoName == "fociShowNamesOnlyForDisplayedFociCheckBox") { if (fociShowNamesOnlyForDisplayedFociCheckBox != NULL) { fociShowNamesOnlyForDisplayedFociCheckBox->setChecked(si->getValueAsBool()); } } else if (infoName == "fociShowTablesOnlyForDisplayedFociCheckBox") { if (fociShowTablesOnlyForDisplayedFociCheckBox != NULL) { fociShowTablesOnlyForDisplayedFociCheckBox->setChecked(si->getValueAsBool()); } } else if (infoName == "fociShowClassesOnlyForDisplayedFociCheckBox") { if (fociShowClassesOnlyForDisplayedFociCheckBox != NULL) { fociShowClassesOnlyForDisplayedFociCheckBox->setChecked(si->getValueAsBool()); } } else if (infoName == "fociShowColorsOnlyForDisplayedFociCheckBox") { if (fociShowColorsOnlyForDisplayedFociCheckBox != NULL) { fociShowColorsOnlyForDisplayedFociCheckBox->setChecked(si->getValueAsBool()); } } } } else if (sc->getName() == "GuiFociSearchWidget") { haveFociSearchInSceneFlag = true; } } // // May need to create the foci search page // if (haveFociSearchInSceneFlag) { if (pageFociSearch == NULL) { createFociSearchPage(); updateFociSearchPage(true); pageFociSearch->updateGeometry(); } if (fociSearchWidget != NULL) { fociSearchWidget->showScene(scene, errorMessage); } } } /** * create a scene (read display settings). */ std::vector GuiDisplayControlDialog::saveScene() { SceneFile::SceneClass sc("GuiDisplayControlDialog"); if (fociShowKeywordsOnlyForDisplayedFociCheckBox != NULL) { sc.addSceneInfo(SceneFile::SceneInfo("fociShowKeywordsOnlyForDisplayedFociCheckBox", fociShowKeywordsOnlyForDisplayedFociCheckBox->isChecked())); } else { sc.addSceneInfo(SceneFile::SceneInfo("fociShowKeywordsOnlyForDisplayedFociCheckBox", false)); } if (fociShowNamesOnlyForDisplayedFociCheckBox != NULL) { sc.addSceneInfo(SceneFile::SceneInfo("fociShowNamesOnlyForDisplayedFociCheckBox", fociShowNamesOnlyForDisplayedFociCheckBox->isChecked())); } else { sc.addSceneInfo(SceneFile::SceneInfo("fociShowNamesOnlyForDisplayedFociCheckBox", false)); } if (fociShowTablesOnlyForDisplayedFociCheckBox != NULL) { sc.addSceneInfo(SceneFile::SceneInfo("fociShowTablesOnlyForDisplayedFociCheckBox", fociShowTablesOnlyForDisplayedFociCheckBox->isChecked())); } else { sc.addSceneInfo(SceneFile::SceneInfo("fociShowTablesOnlyForDisplayedFociCheckBox", false)); } if (fociShowClassesOnlyForDisplayedFociCheckBox != NULL) { sc.addSceneInfo(SceneFile::SceneInfo("fociShowClassesOnlyForDisplayedFociCheckBox", fociShowClassesOnlyForDisplayedFociCheckBox->isChecked())); } else { sc.addSceneInfo(SceneFile::SceneInfo("fociShowClassesOnlyForDisplayedFociCheckBox", false)); } if (fociShowColorsOnlyForDisplayedFociCheckBox != NULL) { sc.addSceneInfo(SceneFile::SceneInfo("fociShowColorsOnlyForDisplayedFociCheckBox", fociShowColorsOnlyForDisplayedFociCheckBox->isChecked())); } else { sc.addSceneInfo(SceneFile::SceneInfo("fociShowColorsOnlyForDisplayedFociCheckBox", false)); } std::vector sceneClasses; sceneClasses.push_back(sc); std::vector scenseClasses; if (fociSearchWidget != NULL) { sceneClasses.push_back(fociSearchWidget->saveScene()); } return sceneClasses; } /** * Create the region page. */ void GuiDisplayControlDialog::createRegionPage() { const int maxWidth = 350; // // Popup graph check box // regionPopupGraphCheckBox = new QCheckBox("Popup Time Course Graph When Node Identified"); QObject::connect(regionPopupGraphCheckBox, SIGNAL(toggled(bool)), this, SLOT(readRegionSelections())); // // All time courses // regionAllTimeCoursesCheckBox = new QRadioButton(""); QObject::connect(regionAllTimeCoursesCheckBox, SIGNAL(toggled(bool)), this, SLOT(readRegionSelections())); QLabel* allLabel = new QLabel("All "); // // Single Time Course // regionSingleTimeCourseCheckBox = new QRadioButton(""); QObject::connect(regionSingleTimeCourseCheckBox, SIGNAL(toggled(bool)), this, SLOT(readRegionSelections())); QLabel* singleLabel = new QLabel("Single "); regionTimeCourseComboBox = new QComboBox; regionTimeCourseComboBox->setMaximumWidth(maxWidth); regionTimeCourseComboBox->setFixedWidth(250); QObject::connect(regionTimeCourseComboBox, SIGNAL(activated(int)), this, SLOT(readRegionSelections())); // // Time Course Group Box // QGroupBox* timeGroupBox = new QGroupBox("Time Course"); QGridLayout* timeGroupLayout = new QGridLayout(timeGroupBox); timeGroupLayout->addWidget(regionAllTimeCoursesCheckBox, 0, 0); timeGroupLayout->addWidget(allLabel, 0, 1); timeGroupLayout->addWidget(regionSingleTimeCourseCheckBox, 1, 0); timeGroupLayout->addWidget(singleLabel, 1, 1); timeGroupLayout->addWidget(regionTimeCourseComboBox, 1, 2); timeGroupBox->setFixedSize(timeGroupBox->sizeHint()); // // Button group to keep radio buttons mutually exclusive // QButtonGroup* timeButtGroup = new QButtonGroup(this); timeButtGroup->addButton(regionAllTimeCoursesCheckBox, 0); timeButtGroup->addButton(regionSingleTimeCourseCheckBox, 1); // // Region Case // QLabel* caseLabel = new QLabel("Case"); regionCaseComboBox = new QComboBox; regionCaseComboBox->setFixedWidth(maxWidth); QObject::connect(regionCaseComboBox, SIGNAL(activated(int)), this, SLOT(readRegionSelections())); // // Paint volume // QLabel* paintVolumeLabel = new QLabel("Paint Volume"); regionPaintVolumeComboBox = new QComboBox; regionPaintVolumeComboBox->setFixedWidth(maxWidth); QObject::connect(regionPaintVolumeComboBox, SIGNAL(activated(int)), this, SLOT(readRegionSelections())); // // Grid for other items // QWidget* regionWidget = new QWidget; QGridLayout* regionGridLayout = new QGridLayout(regionWidget); regionGridLayout->setSpacing(5); regionGridLayout->addWidget(caseLabel, 0, 0); regionGridLayout->addWidget(regionCaseComboBox, 0, 1); regionGridLayout->addWidget(paintVolumeLabel, 1, 0); regionGridLayout->addWidget(regionPaintVolumeComboBox, 1, 1); regionWidget->setFixedSize(regionWidget->sizeHint()); // // Selection group box // QGroupBox* selectGroupBox = new QGroupBox("Selection"); QVBoxLayout* selectGroupLayout = new QVBoxLayout(selectGroupBox); selectGroupLayout->addWidget(regionPopupGraphCheckBox); selectGroupLayout->addWidget(timeGroupBox); selectGroupLayout->addWidget(regionWidget); selectGroupBox->setFixedSize(selectGroupBox->sizeHint()); // // Auto Scale // regionGraphAutoScaleRadioButton = new QRadioButton("Auto Scale"); // // User Scale // regionGraphUserScaleRadioButton = new QRadioButton("User Scale"); regionGraphUserScaleMinLineEdit = new QLineEdit; regionGraphUserScaleMinLineEdit->setFixedWidth(125); QObject::connect(regionGraphUserScaleMinLineEdit, SIGNAL(returnPressed()), this, SLOT(readRegionSelections())); regionGraphUserScaleMinLineEdit->setToolTip( "Minimum Value on Graph"); regionGraphUserScaleMaxLineEdit = new QLineEdit; regionGraphUserScaleMaxLineEdit->setFixedWidth(125); QObject::connect(regionGraphUserScaleMaxLineEdit, SIGNAL(returnPressed()), this, SLOT(readRegionSelections())); regionGraphUserScaleMaxLineEdit->setToolTip( "Minimum Value on Graph"); // // Button group for keeping buttons mutually exclusive // QButtonGroup* buttGroup = new QButtonGroup(this); buttGroup->addButton(regionGraphAutoScaleRadioButton, 0); buttGroup->addButton(regionGraphUserScaleRadioButton, 1); QObject::connect(buttGroup, SIGNAL(buttonClicked(int)), this, SLOT(readRegionSelections())); // // Auto/manual scale // QGroupBox* scaleGroupBox = new QGroupBox("Graph Scale"); QGridLayout* scaleGroupLayout = new QGridLayout(scaleGroupBox); scaleGroupLayout->addWidget(regionGraphAutoScaleRadioButton, 0, 0); scaleGroupLayout->addWidget(regionGraphUserScaleRadioButton, 1, 0); scaleGroupLayout->addWidget(regionGraphUserScaleMinLineEdit, 1, 1); scaleGroupLayout->addWidget(regionGraphUserScaleMaxLineEdit, 1, 2); scaleGroupBox->setFixedSize(scaleGroupBox->sizeHint()); // // Widget for region items // pageRegionMain = new QWidget; pageWidgetStack->addWidget(pageRegionMain); // adds to dialog QVBoxLayout* regionMainPageLayout = new QVBoxLayout(pageRegionMain); regionMainPageLayout->addWidget(selectGroupBox); regionMainPageLayout->addWidget(scaleGroupBox); regionMainPageLayout->addStretch(); } /** * read the region selections. */ void GuiDisplayControlDialog::readRegionSelections() { if (creatingDialog) { return; } DisplaySettingsWustlRegion* dswr = theMainWindow->getBrainSet()->getDisplaySettingsWustlRegion(); if (regionAllTimeCoursesCheckBox->isChecked()) { dswr->setTimeCourseSelection(DisplaySettingsWustlRegion::TIME_COURSE_SELECTION_ALL); } else if (regionSingleTimeCourseCheckBox->isChecked()) { dswr->setTimeCourseSelection(DisplaySettingsWustlRegion::TIME_COURSE_SELECTION_SINGLE); } dswr->setSelectedTimeCourse(regionTimeCourseComboBox->currentIndex()); const int item = regionCaseComboBox->currentIndex(); if (item >= 0) { dswr->setSelectedCaseName(regionCaseComboBox->currentText()); } dswr->setSelectedPaintVolume(regionPaintVolumeComboBox->currentIndex()); dswr->setPopupGraphEnabled(regionPopupGraphCheckBox->isChecked()); if (regionGraphAutoScaleRadioButton->isChecked()) { dswr->setGraphMode(DisplaySettingsWustlRegion::GRAPH_MODE_AUTO_SCALE); } else if (regionGraphUserScaleRadioButton->isChecked()) { dswr->setGraphMode(DisplaySettingsWustlRegion::GRAPH_MODE_USER_SCALE); } dswr->setUserScale(regionGraphUserScaleMinLineEdit->text().toFloat(), regionGraphUserScaleMaxLineEdit->text().toFloat()); } /** * update region items. */ void GuiDisplayControlDialog::updateRegionItems() { updatePageSelectionComboBox(); if (pageRegionMain == NULL) { return; } DisplaySettingsWustlRegion* dswr = theMainWindow->getBrainSet()->getDisplaySettingsWustlRegion(); const WustlRegionFile* wrf = theMainWindow->getBrainSet()->getWustlRegionFile(); switch (dswr->getTimeCourseSelection()) { case DisplaySettingsWustlRegion::TIME_COURSE_SELECTION_ALL: regionAllTimeCoursesCheckBox->setChecked(true); break; case DisplaySettingsWustlRegion::TIME_COURSE_SELECTION_SINGLE: regionSingleTimeCourseCheckBox->setChecked(true); break; } const int numTimeCourses = wrf->getNumberOfTimeCourses(); const int numPaintVolumes = theMainWindow->getBrainSet()->getNumberOfVolumePaintFiles(); bool valid = (numTimeCourses > 0) && (numPaintVolumes > 0); pageRegionMain->setEnabled(validRegionData); if (valid) { regionTimeCourseComboBox->clear(); for (int i = 0; i < numTimeCourses; i++) { regionTimeCourseComboBox->addItem(wrf->getTimeCourse(i)->getName()); } regionTimeCourseComboBox->setCurrentIndex(dswr->getSelectedTimeCourse()); int item = -1; regionCaseComboBox->clear(); const int selectedTimeCourse = dswr->getSelectedTimeCourse(); if ((selectedTimeCourse >= 0) && (selectedTimeCourse < wrf->getNumberOfTimeCourses())) { const WustlRegionFile::TimeCourse* tc = wrf->getTimeCourse(selectedTimeCourse); std::vector caseNames; tc->getAllRegionCaseNames(caseNames); for (int j = 0; j < static_cast(caseNames.size()); j++) { regionCaseComboBox->addItem(caseNames[j]); if (caseNames[j] == dswr->getSelectedCaseName()) { item = j; } } } if (item < 0) { item = 0; } regionCaseComboBox->setCurrentIndex(item); dswr->setSelectedCaseName(regionCaseComboBox->currentText()); regionPaintVolumeComboBox->clear(); for (int i = 0; i < numPaintVolumes; i++) { const QString name = FileUtilities::basename( theMainWindow->getBrainSet()->getVolumePaintFile(i)->getFileName()); regionPaintVolumeComboBox->addItem(name); } regionPaintVolumeComboBox->setCurrentIndex(dswr->getSelectedPaintVolume()); regionPopupGraphCheckBox->setChecked(dswr->getPopupGraphEnabled()); switch (dswr->getGraphMode()) { case DisplaySettingsWustlRegion::GRAPH_MODE_AUTO_SCALE: regionGraphAutoScaleRadioButton->setChecked(true); break; case DisplaySettingsWustlRegion::GRAPH_MODE_USER_SCALE: regionGraphUserScaleRadioButton->setChecked(true); break; } float minScale, maxScale; dswr->getUserScale(minScale, maxScale); regionGraphUserScaleMinLineEdit->setText(QString::number(minScale)); regionGraphUserScaleMaxLineEdit->setText(QString::number(maxScale)); } } /** * called for RGB Paint Red comment display. */ void GuiDisplayControlDialog::rgbPaintRedCommentSelection(int col) { RgbPaintFile* rpf = theMainWindow->getBrainSet()->getRgbPaintFile(); GuiDataFileCommentDialog* dfcd = new GuiDataFileCommentDialog(theMainWindow, rpf, col, 0); dfcd->show(); //displayDataInfoDialog(rpf->getFileTitle(), rpf->getCommentRed(col)); } /** * called for RGB Paint Green comment display. */ void GuiDisplayControlDialog::rgbPaintGreenCommentSelection(int col) { RgbPaintFile* rpf = theMainWindow->getBrainSet()->getRgbPaintFile(); GuiDataFileCommentDialog* dfcd = new GuiDataFileCommentDialog(theMainWindow, rpf, col, 1); dfcd->show(); // displayDataInfoDialog(rpf->getFileTitle(), rpf->getCommentGreen(col)); } /** * called for RGB Paint Blue comment display. */ void GuiDisplayControlDialog::rgbPaintBlueCommentSelection(int col) { RgbPaintFile* rpf = theMainWindow->getBrainSet()->getRgbPaintFile(); GuiDataFileCommentDialog* dfcd = new GuiDataFileCommentDialog(theMainWindow, rpf, col, 2); dfcd->show(); // displayDataInfoDialog(rpf->getFileTitle(), rpf->getCommentBlue(col)); } /** * called for RGB Paint Red histogram display. */ void GuiDisplayControlDialog::rgbPaintRedHistogramSelection(int col) { RgbPaintFile* rpf = theMainWindow->getBrainSet()->getRgbPaintFile(); if ((col >= 0) && (col <= rpf->getNumberOfColumns())) { const int numNodes = rpf->getNumberOfNodes(); std::vector values(numNodes); for (int i = 0; i < numNodes; i++) { float r, g, b; rpf->getRgb(i, col, r, g, b); values[i] = r; } GuiHistogramDisplayDialog* ghd = new GuiHistogramDisplayDialog(theMainWindow, rpf->getColumnName(col), values, false, static_cast(Qt::WA_DeleteOnClose)); ghd->show(); } } /** * called for RGB Paint Green histogram display. */ void GuiDisplayControlDialog::rgbPaintGreenHistogramSelection(int col) { RgbPaintFile* rpf = theMainWindow->getBrainSet()->getRgbPaintFile(); if ((col >= 0) && (col <= rpf->getNumberOfColumns())) { const int numNodes = rpf->getNumberOfNodes(); std::vector values(numNodes); for (int i = 0; i < numNodes; i++) { float r, g, b; rpf->getRgb(i, col, r, g, b); values[i] = g; } GuiHistogramDisplayDialog* ghd = new GuiHistogramDisplayDialog(theMainWindow, rpf->getColumnName(col), values, false, static_cast(Qt::WA_DeleteOnClose)); ghd->show(); } } /** * called for RGB Paint Blue histogram display. */ void GuiDisplayControlDialog::rgbPaintBlueHistogramSelection(int col) { RgbPaintFile* rpf = theMainWindow->getBrainSet()->getRgbPaintFile(); if ((col >= 0) && (col <= rpf->getNumberOfColumns())) { const int numNodes = rpf->getNumberOfNodes(); std::vector values(numNodes); for (int i = 0; i < numNodes; i++) { float r, g, b; rpf->getRgb(i, col, r, g, b); values[i] = b; } GuiHistogramDisplayDialog* ghd = new GuiHistogramDisplayDialog(theMainWindow, rpf->getColumnName(col), values, false, static_cast(Qt::WA_DeleteOnClose)); ghd->show(); } } /** * update rgb paint selection page. */ void GuiDisplayControlDialog::updateRgbPaintSelectionPage() { if (pageRgbPaintSelection == NULL) { return; } const DisplaySettingsRgbPaint* dsrgb = theMainWindow->getBrainSet()->getDisplaySettingsRgbPaint(); const RgbPaintFile* rpf = theMainWindow->getBrainSet()->getRgbPaintFile(); const int numRowsInDialog = static_cast(rgbSelectionRadioButtons.size()); const int numCols = rpf->getNumberOfColumns(); // // Create new items as needed // for (int i = numRowsInDialog; i < numCols; i++) { QRadioButton* rb = new QRadioButton(" "); rgbSelectionRadioButtonsButtonGroup->addButton(rb, i); rgbSelectionRadioButtons.push_back(rb); QToolButton* redCommentButton = new QToolButton; redCommentButton->setText("?"); redCommentButton->setToolTip("Show comment for this color."); rgbSelectionRedCommentButtonGroup->addButton(redCommentButton, i); QToolButton* redHistogramButton = new QToolButton; redHistogramButton->setToolTip("Show histogram for this color."); redHistogramButton->setText("H"); rgbSelectionRedHistogramButtonGroup->addButton(redHistogramButton, i); QToolButton* greenCommentButton = new QToolButton; greenCommentButton->setToolTip("Show comment for this color."); greenCommentButton->setText("?"); rgbSelectionGreenCommentButtonGroup->addButton(greenCommentButton, i); QToolButton* greenHistogramButton = new QToolButton; greenHistogramButton->setToolTip("Show histogram for this color."); greenHistogramButton->setText("H"); rgbSelectionGreenHistogramButtonGroup->addButton(greenHistogramButton, i); QToolButton* blueCommentButton = new QToolButton; blueCommentButton->setToolTip("Show comment for this color."); blueCommentButton->setText("?"); rgbSelectionBlueCommentButtonGroup->addButton(blueCommentButton, i); QToolButton* blueHistogramButton = new QToolButton; blueHistogramButton->setToolTip("Show histogram for this color."); blueHistogramButton->setText("H"); rgbSelectionBlueHistogramButtonGroup->addButton(blueHistogramButton, i); QLineEdit* nameLineEdit = new QLineEdit; nameLineEdit->setMinimumWidth(350); QObject::connect(nameLineEdit, SIGNAL(returnPressed()), this, SLOT(readRgbPaintPageSelection())); rgbSelectionNameLineEdits.push_back(nameLineEdit); QLabel* colLabel = new QLabel(QString::number(i + 1)); rgbSelectionPageGridLayout->addWidget(colLabel, i + 1, 0, Qt::AlignHCenter); rgbSelectionPageGridLayout->addWidget(rb, i + 1, 1, Qt::AlignHCenter); rgbSelectionPageGridLayout->addWidget(redCommentButton, i + 1, 2, Qt::AlignHCenter); rgbSelectionPageGridLayout->addWidget(redHistogramButton, i + 1, 3, Qt::AlignHCenter); rgbSelectionPageGridLayout->addWidget(greenCommentButton, i + 1, 4, Qt::AlignHCenter); rgbSelectionPageGridLayout->addWidget(greenHistogramButton, i + 1, 5, Qt::AlignHCenter); rgbSelectionPageGridLayout->addWidget(blueCommentButton, i + 1, 6, Qt::AlignHCenter); rgbSelectionPageGridLayout->addWidget(blueHistogramButton, i + 1, 7, Qt::AlignHCenter); rgbSelectionPageGridLayout->addWidget(nameLineEdit, i + 1, 8, Qt::AlignLeft); WuQWidgetGroup* wg = new WuQWidgetGroup(this); wg->addWidget(colLabel); wg->addWidget(rb); wg->addWidget(redCommentButton); wg->addWidget(greenCommentButton); wg->addWidget(blueCommentButton); wg->addWidget(redHistogramButton); wg->addWidget(greenHistogramButton); wg->addWidget(blueHistogramButton); wg->addWidget(nameLineEdit); rgbSelectionRowWidgetGroup.push_back(wg); } // // Update all items // for (int i = 0; i < numCols; i++) { rgbSelectionNameLineEdits[i]->setText(rpf->getColumnName(i)); rgbSelectionRowWidgetGroup[i]->setHidden(false); } // // Hide unneeded items // for (int i = numCols; i < numRowsInDialog; i++) { rgbSelectionRowWidgetGroup[i]->setHidden(true); } // // Update selection check box // rgbSelectionRadioButtonsButtonGroup->blockSignals(true); const int num = dsrgb->getSelectedDisplayColumn(surfaceModelIndex, overlayNumberComboBox->currentIndex()); if ((num >= 0) && (num < rpf->getNumberOfColumns())) { rgbSelectionRadioButtons[num]->setChecked(true); } rgbSelectionRadioButtonsButtonGroup->blockSignals(false); pageRgbPaintSelection->setEnabled(validRgbPaintData); } /** * create the rgb paint selection page. */ void GuiDisplayControlDialog::createRgbPaintSelectionPage() { // // widget for rgb paint items // pageRgbPaintSelection = new QWidget; pageWidgetStack->addWidget(pageRgbPaintSelection); // adds to dialog // // Layout for selection // rgbSelectionPageGridLayout = new QGridLayout; rgbSelectionPageGridLayout->addWidget(new QLabel("Col"), 0, 0); rgbSelectionPageGridLayout->addWidget(new QLabel("Sel"), 0, 1); rgbSelectionPageGridLayout->addWidget(new QLabel("Red"), 0, 2, 1, 2, Qt::AlignHCenter); rgbSelectionPageGridLayout->addWidget(new QLabel("Green"), 0, 4, 1, 2, Qt::AlignHCenter); rgbSelectionPageGridLayout->addWidget(new QLabel("Blue"), 0, 6, 1, 2, Qt::AlignHCenter); rgbSelectionPageGridLayout->addWidget(new QLabel("Column Name"), 0, 8); rgbSelectionPageGridLayout->setColumnStretch(0, 0); rgbSelectionPageGridLayout->setColumnStretch(1, 0); rgbSelectionPageGridLayout->setColumnStretch(2, 0); rgbSelectionPageGridLayout->setColumnStretch(3, 0); rgbSelectionPageGridLayout->setColumnStretch(4, 0); rgbSelectionPageGridLayout->setColumnStretch(5, 0); rgbSelectionPageGridLayout->setColumnStretch(6, 0); rgbSelectionPageGridLayout->setColumnStretch(7, 0); rgbSelectionPageGridLayout->setColumnStretch(8, 1000); // // Selection button groups // rgbSelectionRadioButtonsButtonGroup = new QButtonGroup(this); QObject::connect(rgbSelectionRadioButtonsButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(rgbPaintFileSelection(int))); rgbSelectionRedCommentButtonGroup = new QButtonGroup(this); QObject::connect(rgbSelectionRedCommentButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(rgbPaintRedCommentSelection(int))); rgbSelectionGreenCommentButtonGroup = new QButtonGroup(this); QObject::connect(rgbSelectionGreenCommentButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(rgbPaintGreenCommentSelection(int))); rgbSelectionBlueCommentButtonGroup = new QButtonGroup(this); QObject::connect(rgbSelectionBlueCommentButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(rgbPaintBlueCommentSelection(int))); rgbSelectionRedHistogramButtonGroup = new QButtonGroup(this); QObject::connect(rgbSelectionRedHistogramButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(rgbPaintRedHistogramSelection(int))); rgbSelectionGreenHistogramButtonGroup = new QButtonGroup(this); QObject::connect(rgbSelectionGreenHistogramButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(rgbPaintGreenHistogramSelection(int))); rgbSelectionBlueHistogramButtonGroup = new QButtonGroup(this); QObject::connect(rgbSelectionBlueHistogramButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(rgbPaintBlueHistogramSelection(int))); // // Vertical Box Layout for all rgb paint items // QVBoxLayout* rgbLayout = new QVBoxLayout(pageRgbPaintSelection); rgbLayout->addLayout(rgbSelectionPageGridLayout); rgbLayout->addStretch(); } /** * Create the RGB Paint page */ void GuiDisplayControlDialog::createRgbPaintMainPage() { const int NAME_COLUMN = 0; const int THRESH_COLUMN = NAME_COLUMN + 1; const int TITLE_ROW = 0; const int RED_ROW = TITLE_ROW + 1; const int GREEN_ROW = RED_ROW + 1; const int BLUE_ROW = GREEN_ROW + 1; //const int NUM_ROWS = BLUE_ROW + 1; // // Grid Layout for R/G/B items // QGridLayout* rgbGridLayout = new QGridLayout; // // Grid Column titles // rgbGridLayout->addWidget(new QLabel("Name"), TITLE_ROW, NAME_COLUMN, Qt::AlignLeft); rgbGridLayout->addWidget(new QLabel("Threshold"), TITLE_ROW, THRESH_COLUMN, Qt::AlignHCenter); // // Red row // rgbRedCheckBox = new QCheckBox("Red"); rgbGridLayout->addWidget(rgbRedCheckBox, RED_ROW, NAME_COLUMN); QObject::connect(rgbRedCheckBox, SIGNAL(clicked()), this, SLOT(readRgbPaintPageMain())); rgbRedThreshDoubleSpinBox = new QDoubleSpinBox; rgbRedThreshDoubleSpinBox->setMinimum(-99999999.0); rgbRedThreshDoubleSpinBox->setMaximum(999999999.0); rgbRedThreshDoubleSpinBox->setSingleStep(1.0); rgbRedThreshDoubleSpinBox->setDecimals(3); rgbGridLayout->addWidget(rgbRedThreshDoubleSpinBox, RED_ROW, THRESH_COLUMN); QObject::connect(rgbRedThreshDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readRgbPaintPageMain())); // // Green row // rgbGreenCheckBox = new QCheckBox("Green"); rgbGridLayout->addWidget(rgbGreenCheckBox, GREEN_ROW, NAME_COLUMN); QObject::connect(rgbGreenCheckBox, SIGNAL(clicked()), this, SLOT(readRgbPaintPageMain())); rgbGreenThreshDoubleSpinBox = new QDoubleSpinBox; rgbGreenThreshDoubleSpinBox->setMinimum(-99999999.0); rgbGreenThreshDoubleSpinBox->setMaximum(999999999.0); rgbGreenThreshDoubleSpinBox->setSingleStep(1.0); rgbGreenThreshDoubleSpinBox->setDecimals(3); rgbGridLayout->addWidget(rgbGreenThreshDoubleSpinBox, GREEN_ROW, THRESH_COLUMN); QObject::connect(rgbGreenThreshDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readRgbPaintPageMain())); // // Blue row // rgbBlueCheckBox = new QCheckBox("Blue"); rgbGridLayout->addWidget(rgbBlueCheckBox, BLUE_ROW, NAME_COLUMN); QObject::connect(rgbBlueCheckBox, SIGNAL(clicked()), this, SLOT(readRgbPaintPageMain())); rgbBlueThreshDoubleSpinBox = new QDoubleSpinBox; rgbBlueThreshDoubleSpinBox->setMinimum(-99999999.0); rgbBlueThreshDoubleSpinBox->setMaximum(999999999.0); rgbBlueThreshDoubleSpinBox->setSingleStep(1.0); rgbBlueThreshDoubleSpinBox->setDecimals(3); rgbGridLayout->addWidget(rgbBlueThreshDoubleSpinBox, BLUE_ROW, THRESH_COLUMN); QObject::connect(rgbBlueThreshDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readRgbPaintPageMain())); // // Button group for positive and negative only buttons // QButtonGroup* displayModeButtonGroup = new QButtonGroup(this); displayModeButtonGroup->setExclusive(true); QObject::connect(displayModeButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(rgbDisplayModeSelection(int))); // // Positive and Negative only buttons // rgbPositiveOnlyRadioButton = new QRadioButton("Positive Only"); displayModeButtonGroup->addButton(rgbPositiveOnlyRadioButton, DisplaySettingsRgbPaint::RGB_DISPLAY_MODE_POSITIVE); rgbNegativeOnlyRadioButton = new QRadioButton("Negative Only"); displayModeButtonGroup->addButton(rgbNegativeOnlyRadioButton, DisplaySettingsRgbPaint::RGB_DISPLAY_MODE_NEGATIVE); // // Group Box for RGB File selection and parameters (a QWidget is placed in it so that // a layout can be added). // QGroupBox* rgbFileGroupBox = new QGroupBox("RGB Color Control"); QVBoxLayout* rgbFileLayout = new QVBoxLayout(rgbFileGroupBox); rgbFileLayout->addLayout(rgbGridLayout); // // Group Box for RGB display mode positive and negative only buttons. // QGroupBox* rgbDisplayModeGroupBox = new QGroupBox("Display Mode"); QVBoxLayout* rgbDisplayModeLayout = new QVBoxLayout(rgbDisplayModeGroupBox); rgbDisplayModeLayout->addWidget(rgbPositiveOnlyRadioButton); rgbDisplayModeLayout->addWidget(rgbNegativeOnlyRadioButton); pageRgbPaintMainWidgetGroup = new WuQWidgetGroup(this); pageRgbPaintMainWidgetGroup->addWidget(rgbRedCheckBox); pageRgbPaintMainWidgetGroup->addWidget(rgbRedThreshDoubleSpinBox); pageRgbPaintMainWidgetGroup->addWidget(rgbGreenCheckBox); pageRgbPaintMainWidgetGroup->addWidget(rgbGreenThreshDoubleSpinBox); pageRgbPaintMainWidgetGroup->addWidget(rgbBlueCheckBox); pageRgbPaintMainWidgetGroup->addWidget(rgbBlueThreshDoubleSpinBox); pageRgbPaintMainWidgetGroup->addWidget(rgbPositiveOnlyRadioButton); pageRgbPaintMainWidgetGroup->addWidget(rgbNegativeOnlyRadioButton); // // widget for rgb paint items // pageRgbPaintMain = new QWidget; pageWidgetStack->addWidget(pageRgbPaintMain); //, PAGE_NAME_RGB_PAINT); // adds to dialog // // Vertical Box Layout for all rgb paint items // QVBoxLayout* rgbLayout = new QVBoxLayout(pageRgbPaintMain); rgbLayout->addWidget(rgbFileGroupBox, 0, Qt::AlignLeft); rgbLayout->addWidget(rgbDisplayModeGroupBox, 0, Qt::AlignLeft); rgbLayout->addStretch(); } /** * Called when display mode selected on RGB panel. */ void GuiDisplayControlDialog::rgbDisplayModeSelection(int itemNumber) { DisplaySettingsRgbPaint* dsrp = theMainWindow->getBrainSet()->getDisplaySettingsRgbPaint(); dsrp->setDisplayMode(static_cast(itemNumber)); readRgbPaintPageMain(); } /** * read rgb paint L-to-L, R-to-R. */ void GuiDisplayControlDialog::readRgbPaintL2LR2R() { DisplaySettingsRgbPaint* dsrp = theMainWindow->getBrainSet()->getDisplaySettingsRgbPaint(); dsrp->setApplySelectionToLeftAndRightStructuresFlag(rgbApplySelectionToLeftAndRightStructuresFlagCheckBox->isChecked()); theMainWindow->getBrainSet()->getNodeColoring()->assignColors(); GuiBrainModelOpenGL::updateAllGL(NULL); displayOverlayLeftToLeftRightToRightMessage(); } /** * read the rgb paint selection page. */ void GuiDisplayControlDialog::readRgbPaintPageSelection() { RgbPaintFile* rpf = theMainWindow->getBrainSet()->getRgbPaintFile(); const int numCols = rpf->getNumberOfColumns(); const int numLineEdits = static_cast(rgbSelectionNameLineEdits.size()); bool changeMadeFlag = false; for (int i = 0; i < numCols; i++) { if (i < numLineEdits) { if (rgbSelectionNameLineEdits[i]->text() != rpf->getColumnName(i)) { rpf->setColumnName(i, rgbSelectionNameLineEdits[i]->text()); changeMadeFlag = true; } } } if (changeMadeFlag) { updateSurfaceOverlayWidgets(); } } /** * Read the RGB paint selections from the dialog. */ void GuiDisplayControlDialog::readRgbPaintPageMain() { if (pageRgbPaintMain == NULL) { return; } if (creatingDialog) { return; } DisplaySettingsRgbPaint* dsrp = theMainWindow->getBrainSet()->getDisplaySettingsRgbPaint(); dsrp->setRedEnabled(rgbRedCheckBox->isChecked()); dsrp->setGreenEnabled(rgbGreenCheckBox->isChecked()); dsrp->setBlueEnabled(rgbBlueCheckBox->isChecked()); dsrp->setThresholds(rgbRedThreshDoubleSpinBox->value(), rgbGreenThreshDoubleSpinBox->value(), rgbBlueThreshDoubleSpinBox->value()); theMainWindow->getBrainSet()->getNodeColoring()->assignColors(); GuiBrainModelOpenGL::updateAllGL(NULL); } /** * update rgb paint overlay/underlay selections. */ void GuiDisplayControlDialog::updateRgbPaintOverlayUnderlaySelection() { updatePageSelectionComboBox(); } /** * update rgb paint main page. */ void GuiDisplayControlDialog::updateRgbPaintMainPage() { if (pageRgbPaintMain == NULL) { return; } pageRgbPaintMainWidgetGroup->blockSignals(true); DisplaySettingsRgbPaint* dsrp = theMainWindow->getBrainSet()->getDisplaySettingsRgbPaint(); rgbApplySelectionToLeftAndRightStructuresFlagCheckBox->blockSignals(true); rgbApplySelectionToLeftAndRightStructuresFlagCheckBox->setChecked(dsrp->getApplySelectionToLeftAndRightStructuresFlag()); rgbApplySelectionToLeftAndRightStructuresFlagCheckBox->blockSignals(false); //RgbPaintFile* rpf = theMainWindow->getBrainSet()->getRgbPaintFile(); switch(dsrp->getDisplayMode()) { case DisplaySettingsRgbPaint::RGB_DISPLAY_MODE_POSITIVE: rgbPositiveOnlyRadioButton->setChecked(true); break; case DisplaySettingsRgbPaint::RGB_DISPLAY_MODE_NEGATIVE: rgbNegativeOnlyRadioButton->setChecked(true); break; } rgbRedCheckBox->setChecked(dsrp->getRedEnabled()); rgbGreenCheckBox->setChecked(dsrp->getGreenEnabled()); rgbBlueCheckBox->setChecked(dsrp->getBlueEnabled()); float redThresh, greenThresh, blueThresh; dsrp->getThresholds(redThresh, greenThresh, blueThresh); rgbRedThreshDoubleSpinBox->setValue(redThresh); rgbGreenThreshDoubleSpinBox->setValue(greenThresh); rgbBlueThreshDoubleSpinBox->setValue(blueThresh); pageRgbPaintMain->setEnabled(validRgbPaintData); pageRgbPaintMainWidgetGroup->blockSignals(false); } /** * Update all rgb paint items in the dialog. */ void GuiDisplayControlDialog::updateRgbPaintItems() { updateRgbPaintOverlayUnderlaySelection(); updateRgbPaintMainPage(); updateRgbPaintSelectionPage(); } /** * Cell page containing main items. */ void GuiDisplayControlDialog::createCellMainPage() { showCellsCheckBox = new QCheckBox("Show Cells"); QObject::connect(showCellsCheckBox, SIGNAL(toggled(bool)), this, SLOT(showCellsToggleSlot(bool))); showVolumeCellsCheckBox = new QCheckBox("Show Volume Cells"); QObject::connect(showVolumeCellsCheckBox, SIGNAL(toggled(bool)), this, SLOT(readCellMainPage())); showRaisedCellCheckBox = new QCheckBox("Show Raised Cells (flat surfaces only)"); QObject::connect(showRaisedCellCheckBox, SIGNAL(toggled(bool)), this, SLOT(readCellMainPage())); showCorrectHemisphereCellsCheckBox = new QCheckBox("Show Cells on Correct Hemisphere Only"); QObject::connect(showCorrectHemisphereCellsCheckBox, SIGNAL(toggled(bool)), this, SLOT(readCellMainPage())); cellDisplayModeComboBox = new QComboBox; cellDisplayModeComboBox->insertItem(DisplaySettingsCells::CELL_DISPLAY_MODE_SHOW_ALL, "Show Deep and Superficial Cells"); cellDisplayModeComboBox->insertItem(DisplaySettingsCells::CELL_DISPLAY_MODE_SHOW_DEEP_ONLY, "Show Deep Cells Only"); cellDisplayModeComboBox->insertItem(DisplaySettingsCells::CELL_DISPLAY_MODE_SHOW_SUPERFICIAL_ONLY, "Show Superficial Cells Only"); cellDisplayModeComboBox->setFixedSize(cellDisplayModeComboBox->sizeHint()); QObject::connect(cellDisplayModeComboBox, SIGNAL(activated(int)), this, SLOT(readCellMainPage())); QLabel* symbolLabel = new QLabel("Symbol Override "); cellSymbolOverrideComboBox = new QComboBox; std::vector cellOverrideLabels; ColorFile::ColorStorage::getAllSymbolTypesAsStrings(cellOverrideLabels); for (unsigned int i = 0; i < cellOverrideLabels.size(); i++) { cellSymbolOverrideComboBox->addItem(cellOverrideLabels[i]); } QObject::connect(cellSymbolOverrideComboBox, SIGNAL(activated(int)), this, SLOT(readCellMainPage())); QHBoxLayout* symbolLayout = new QHBoxLayout; symbolLayout->addWidget(symbolLabel); symbolLayout->addWidget(cellSymbolOverrideComboBox); symbolLayout->addStretch(); QLabel* opacityLabel = new QLabel("Opacity"); cellOpacityDoubleSpinBox = new QDoubleSpinBox; cellOpacityDoubleSpinBox->setMinimum(0.0); cellOpacityDoubleSpinBox->setMaximum(1.0); cellOpacityDoubleSpinBox->setSingleStep(0.01); cellOpacityDoubleSpinBox->setDecimals(3); QObject::connect(cellOpacityDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readCellMainPage())); QHBoxLayout* opacityLayout = new QHBoxLayout; opacityLayout->addWidget(opacityLabel); opacityLayout->addWidget(cellOpacityDoubleSpinBox); opacityLayout->addStretch(); QLabel* spinLabel = new QLabel("Cell Size"); cellSizeSpinBox = new QDoubleSpinBox; cellSizeSpinBox->setMinimum(0.001); cellSizeSpinBox->setMaximum(maxPointSize); cellSizeSpinBox->setSingleStep(0.5); cellSizeSpinBox->setDecimals(3); cellSizeSpinBox->setSizePolicy(QtUtilities::fixedSizePolicy()); QObject::connect(cellSizeSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readCellMainPage())); QHBoxLayout* sizeLayout = new QHBoxLayout; sizeLayout->addWidget(spinLabel); sizeLayout->addWidget(cellSizeSpinBox); sizeLayout->addStretch(); QLabel* distanceLabel = new QLabel("Distance"); cellDistSpinBox = new QDoubleSpinBox; cellDistSpinBox->setMinimum(0.0); cellDistSpinBox->setMaximum(1000.0); cellDistSpinBox->setSingleStep(10.0); cellDistSpinBox->setDecimals(1); cellDistSpinBox->setValue(1000.0); QObject::connect(cellDistSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readCellMainPage())); cellDistSpinBox->setToolTip("Cells whose distances to the surface are\n" "less than this value will be displayed.\n" "The cells must have been projected."); QHBoxLayout* distanceLayout = new QHBoxLayout; distanceLayout->addWidget(distanceLabel); distanceLayout->addWidget(cellDistSpinBox); distanceLayout->addStretch(); // // Display color key button // QPushButton* colorKeyPushButton = new QPushButton("Display Color Key..."); colorKeyPushButton->setFixedSize(colorKeyPushButton->sizeHint()); colorKeyPushButton->setAutoDefault(false); QObject::connect(colorKeyPushButton, SIGNAL(clicked()), theMainWindow, SLOT(displayCellColorKey())); // // Vertical Box Layout for all cell items // pageCellsMain = new QWidget; QVBoxLayout* cellSubPageMainLayout = new QVBoxLayout(pageCellsMain); cellSubPageMainLayout->addWidget(showCellsCheckBox); cellSubPageMainLayout->addWidget(showVolumeCellsCheckBox); cellSubPageMainLayout->addWidget(showRaisedCellCheckBox); //cellSubPageMainLayout->addWidget(showLeftHemisphereCellCheckBox); //cellSubPageMainLayout->addWidget(showRightHemisphereCellCheckBox); cellSubPageMainLayout->addWidget(showCorrectHemisphereCellsCheckBox); cellSubPageMainLayout->addWidget(cellDisplayModeComboBox); cellSubPageMainLayout->addLayout(symbolLayout); cellSubPageMainLayout->addLayout(sizeLayout); cellSubPageMainLayout->addLayout(opacityLayout); cellSubPageMainLayout->addLayout(distanceLayout); cellSubPageMainLayout->addWidget(colorKeyPushButton); cellSubPageMainLayout->addStretch(); pageWidgetStack->addWidget(pageCellsMain); pageCellsMainWidgetGroup = new WuQWidgetGroup(this); pageCellsMainWidgetGroup->addWidget(showCellsCheckBox); pageCellsMainWidgetGroup->addWidget(showVolumeCellsCheckBox); pageCellsMainWidgetGroup->addWidget(showRaisedCellCheckBox); pageCellsMainWidgetGroup->addWidget(showCorrectHemisphereCellsCheckBox); pageCellsMainWidgetGroup->addWidget(cellDisplayModeComboBox); pageCellsMainWidgetGroup->addWidget(cellSymbolOverrideComboBox); pageCellsMainWidgetGroup->addWidget(cellOpacityDoubleSpinBox); pageCellsMainWidgetGroup->addWidget(cellSizeSpinBox); pageCellsMainWidgetGroup->addWidget(cellDistSpinBox); pageCellsMainWidgetGroup->addWidget(colorKeyPushButton); } /** * Cell page containing class selections. */ void GuiDisplayControlDialog::createCellClassPage() { // // Vertical Box Layout for all cell items // pageCellsClass = new QWidget; cellSubPageClassLayout = new QVBoxLayout(pageCellsClass); // // All off and all on pushbuttons // QPushButton* cellClassAllOnButton = new QPushButton("All On"); cellClassAllOnButton->setAutoDefault(false); QObject::connect(cellClassAllOnButton, SIGNAL(clicked()), this, SLOT(cellClassAllOn())); QPushButton* cellClassAllOffButton = new QPushButton("All Off"); cellClassAllOffButton->setAutoDefault(false); QObject::connect(cellClassAllOffButton, SIGNAL(clicked()), this, SLOT(cellClassAllOff())); QHBoxLayout* allOnOffLayout = new QHBoxLayout; allOnOffLayout->addWidget(cellClassAllOnButton); allOnOffLayout->addWidget(cellClassAllOffButton); allOnOffLayout->addStretch(); cellSubPageClassLayout->addLayout(allOnOffLayout); pageCellsClassWidgetGroup = new WuQWidgetGroup(this); pageCellsClassWidgetGroup->addWidget(cellClassAllOnButton); pageCellsClassWidgetGroup->addWidget(cellClassAllOffButton); createAndUpdateCellClassCheckBoxes(); pageWidgetStack->addWidget(pageCellsClass); } /** * Create and update cell class checkboxes. Because the number of cell may change, * this method may update and change the label on existing checkboxes, add new * checkboxes, and hide existing checkboxes if the number of checkboxes is greater * than the number of cell classes. */ void GuiDisplayControlDialog::createAndUpdateCellClassCheckBoxes() { CellProjectionFile* cf = theMainWindow->getBrainSet()->getCellProjectionFile(); //if (cf != NULL) { // numValidCellClasses = cf->getNumberOfCellClasses(); //} //else { // numValidCellClasses = 0; //} const int numExistingCheckBoxes = static_cast(cellClassCheckBoxes.size()); std::vector sortedCellClassIndices; cf->getCellClassIndicesSortedByName(sortedCellClassIndices, false, false); numValidCellClasses = static_cast(sortedCellClassIndices.size()); if (cellClassGridLayout == NULL) { QWidget* classWidget = new QWidget; cellClassGridLayout = new QGridLayout(classWidget); const int rowStretchNumber = 15000; cellClassGridLayout->addWidget(new QLabel(""), rowStretchNumber, 0, Qt::AlignLeft); cellClassGridLayout->setRowStretch(rowStretchNumber, 1000); cellSubPageClassLayout->addWidget(classWidget); } if (cellClassButtonGroup == NULL) { cellClassButtonGroup = new QButtonGroup(this); cellClassButtonGroup->setExclusive(false); QObject::connect(cellClassButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(readCellClassPage())); } // // Update exising checkboxes // for (int i = 0; i < numExistingCheckBoxes; i++) { if (i < numValidCellClasses) { const int classIndex = sortedCellClassIndices[i]; cellClassCheckBoxes[i]->setText(cf->getCellClassNameByIndex(classIndex)); cellClassCheckBoxes[i]->show(); } } // // Add new checkboxes as needed // for (int j = numExistingCheckBoxes; j < numValidCellClasses; j++) { const int classIndex = sortedCellClassIndices[j]; cellClassCheckBoxesClassIndex.push_back(classIndex); QCheckBox* cb = new QCheckBox(cf->getCellClassNameByIndex(classIndex)); cellClassCheckBoxes.push_back(cb); cellClassButtonGroup->addButton(cb, j); cellClassGridLayout->addWidget(cb, j, 0, 1, 1, Qt::AlignLeft); cb->show(); pageCellsClassWidgetGroup->addWidget(cb); } // // Hide existing checkboxes that are not needed. // for (int k = numValidCellClasses; k < numExistingCheckBoxes; k++) { cellClassCheckBoxes[k]->hide(); } } /** * This slot is called when the cell class all on button is pressed. */ void GuiDisplayControlDialog::cellClassAllOn() { CellProjectionFile* cf = theMainWindow->getBrainSet()->getCellProjectionFile(); if (cf != NULL) { cf->setAllCellClassStatus(true); } updateCellItems(); readCellClassPage(); } /** * This slot is called when the cell class all off button is pressed. */ void GuiDisplayControlDialog::cellClassAllOff() { CellProjectionFile* cf = theMainWindow->getBrainSet()->getCellProjectionFile(); if (cf != NULL) { cf->setAllCellClassStatus(false); } updateCellItems(); readCellClassPage(); } /** * Cell page containing color selections. */ void GuiDisplayControlDialog::createCellColorPage() { // // Vertical Box Layout for all cell items // pageCellsColor = new QWidget; cellSubPageColorLayout = new QVBoxLayout(pageCellsColor); // // All off and all on pushbuttons // QPushButton* cellColorAllOnButton = new QPushButton("All On"); cellColorAllOnButton->setAutoDefault(false); QObject::connect(cellColorAllOnButton, SIGNAL(clicked()), this, SLOT(cellColorAllOn())); QPushButton* cellColorAllOffButton = new QPushButton("All Off"); cellColorAllOffButton->setAutoDefault(false); QObject::connect(cellColorAllOffButton, SIGNAL(clicked()), this, SLOT(cellColorAllOff())); QHBoxLayout* allOnOffLayout = new QHBoxLayout; allOnOffLayout->addWidget(cellColorAllOnButton); allOnOffLayout->addWidget(cellColorAllOffButton); allOnOffLayout->addStretch(); cellSubPageColorLayout->addLayout(allOnOffLayout); pageCellsColorWidgetGroup = new WuQWidgetGroup(this); pageCellsColorWidgetGroup->addWidget(cellColorAllOnButton); pageCellsColorWidgetGroup->addWidget(cellColorAllOffButton); createAndUpdateCellColorCheckBoxes(); pageWidgetStack->addWidget(pageCellsColor); } /** * Create and update cell color checkboxes. Because the number of colors may change, * this method may update and change the label on existing checkboxes, add new * checkboxes, and hide existing checkboxes if the number of checkboxes is greater * than the number of cell colors. */ void GuiDisplayControlDialog::createAndUpdateCellColorCheckBoxes() { CellColorFile* cellColors = theMainWindow->getBrainSet()->getCellColorFile(); //numValidCellColors = cellColors->getNumberOfColors(); std::vector sortedCellColorIndices; cellColors->getColorIndicesSortedByName(sortedCellColorIndices, false); numValidCellColors = static_cast(sortedCellColorIndices.size()); const int numExistingCheckBoxes = static_cast(cellColorCheckBoxes.size()); if (cellColorGridLayout == NULL) { QWidget* colorWidget = new QWidget; cellColorGridLayout = new QGridLayout(colorWidget); const int rowStretchNumber = 15000; cellColorGridLayout->addWidget(new QLabel(""), rowStretchNumber, 0, Qt::AlignLeft); cellColorGridLayout->setRowStretch(rowStretchNumber, 1000); cellSubPageColorLayout->addWidget(colorWidget); } if (cellColorButtonGroup == NULL) { cellColorButtonGroup = new QButtonGroup(this); cellColorButtonGroup->setExclusive(false); QObject::connect(cellColorButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(readCellColorPage())); } // // Update exising checkboxes // for (int i = 0; i < numExistingCheckBoxes; i++) { if (i < numValidCellColors) { const int colorIndex = sortedCellColorIndices[i]; cellColorCheckBoxesColorIndex[i] = colorIndex; cellColorCheckBoxes[i]->setText(cellColors->getColorNameByIndex(colorIndex)); cellColorCheckBoxes[i]->show(); } } // // Add new checkboxes as needed // for (int j = numExistingCheckBoxes; j < numValidCellColors; j++) { const int colorIndex = sortedCellColorIndices[j]; cellColorCheckBoxesColorIndex.push_back(colorIndex); QCheckBox* cb = new QCheckBox(cellColors->getColorNameByIndex(colorIndex)); cellColorCheckBoxes.push_back(cb); cellColorButtonGroup->addButton(cb, j); cellColorGridLayout->addWidget(cb, j, 0, 1, 1, Qt::AlignLeft); cb->show(); pageCellsColorWidgetGroup->addWidget(cb); } // // Hide existing checkboxes that are not needed. // for (int k = numValidCellColors; k < numExistingCheckBoxes; k++) { cellColorCheckBoxes[k]->hide(); } } /** * This slot is called when the cell color all on button is pressed. */ void GuiDisplayControlDialog::cellColorAllOn() { CellColorFile* cellColors = theMainWindow->getBrainSet()->getCellColorFile(); cellColors->setAllSelectedStatus(true); updateCellItems(); readCellColorPage(); } /** * This slot is called when the cell color all off button is pressed. */ void GuiDisplayControlDialog::cellColorAllOff() { CellColorFile* cellColors = theMainWindow->getBrainSet()->getCellColorFile(); cellColors->setAllSelectedStatus(false); updateCellItems(); readCellColorPage(); } /** * upate cell main page. */ void GuiDisplayControlDialog::updateCellMainPage() { if (pageCellsMain == NULL) { return; } pageCellsMainWidgetGroup->blockSignals(true); DisplaySettingsCells* dsc = theMainWindow->getBrainSet()->getDisplaySettingsCells(); showCellsCheckBox->setChecked(dsc->getDisplayCells()); showVolumeCellsCheckBox->setChecked(dsc->getDisplayVolumeCells()); showRaisedCellCheckBox->setChecked(dsc->getDisplayFlatCellsRaised()); cellOpacityDoubleSpinBox->setValue(dsc->getOpacity()); showCorrectHemisphereCellsCheckBox->setChecked(dsc->getDisplayCellsOnCorrectHemisphereOnly()); cellDisplayModeComboBox->setCurrentIndex(dsc->getDisplayMode()); cellSymbolOverrideComboBox->setCurrentIndex(dsc->getSymbolOverride()); cellSizeSpinBox->setValue(dsc->getDrawSize()); cellDistSpinBox->setValue(dsc->getDistanceToSurfaceLimit()); pageCellsMain->setEnabled(validCellData); pageCellsMainWidgetGroup->blockSignals(false); } /** * update cell class page. */ void GuiDisplayControlDialog::updateCellClassPage(const bool cellsWereChanged) { if (pageCellsClass == NULL) { return; } if (cellsWereChanged) { createAndUpdateCellClassCheckBoxes(); } pageCellsClassWidgetGroup->blockSignals(true); CellProjectionFile* cf = theMainWindow->getBrainSet()->getCellProjectionFile(); if (cf != NULL) { const int numClasses = cf->getNumberOfCellClasses(); if (numClasses == numValidCellClasses) { for (int i = 0; i < numValidCellClasses; i++) { const int classIndex = cellClassCheckBoxesClassIndex[i]; cellClassCheckBoxes[i]->setChecked(cf->getCellClassSelectedByIndex(classIndex)); } } else { std::cerr << "Number of cell class checkboxes does not equal number of cell classes." << std::endl; } } pageCellsClass->setEnabled(validCellData); pageCellsClassWidgetGroup->blockSignals(false); } /** * update cell color page. */ void GuiDisplayControlDialog::updateCellColorPage(const bool cellsWereChanged) { if (pageCellsColor == NULL) { return; } if (cellsWereChanged) { createAndUpdateCellColorCheckBoxes(); } pageCellsColorWidgetGroup->blockSignals(true); CellColorFile* cellColors = theMainWindow->getBrainSet()->getCellColorFile(); const int numColors = cellColors->getNumberOfColors(); if (numColors == numValidCellColors) { for (int i = 0; i < numValidCellColors; i++) { const int colorIndex = cellColorCheckBoxesColorIndex[i]; cellColorCheckBoxes[i]->setChecked(cellColors->getSelected(colorIndex)); } } else { std::cerr << "Number of cell color checkboxes does not equal number of cell colors." << std::endl; } pageCellsColor->setEnabled(validCellData); pageCellsColorWidgetGroup->blockSignals(false); } /** * Update all of the cell items in the dialog */ void GuiDisplayControlDialog::updateCellItems(const bool filesChanged) { updatePageSelectionComboBox(); if (pageOverlayUnderlaySurfaceNew != NULL) { DisplaySettingsCells* dsc = theMainWindow->getBrainSet()->getDisplaySettingsCells(); layersCellsCheckBox->setChecked(dsc->getDisplayCells()); layersCellsCheckBox->setEnabled(validCellData); } updateCellMainPage(); updateCellClassPage(filesChanged); updateCellColorPage(filesChanged); updatePageSelectionComboBox(); } /** * called when cells selected on cells page or overlay/underlay surface page. */ void GuiDisplayControlDialog::showCellsToggleSlot(bool b) { if (pageCellsMain != NULL) { showCellsCheckBox->blockSignals(true); showCellsCheckBox->setChecked(b); showCellsCheckBox->blockSignals(false); } if (pageOverlayUnderlaySurfaceNew != NULL) { layersCellsCheckBox->blockSignals(true); layersCellsCheckBox->setChecked(b); layersCellsCheckBox->blockSignals(false); } DisplaySettingsCells* dsc = theMainWindow->getBrainSet()->getDisplaySettingsCells(); dsc->setDisplayCells(b); dsc->determineDisplayedCells(); GuiBrainModelOpenGL::updateAllGL(NULL); //readCellMainPage(); //readCellColorPage(); //readCellClassPage(); } /** * read the cell main page. */ void GuiDisplayControlDialog::readCellMainPage() { if (pageCellsMain == NULL) { return; } if (creatingDialog) { return; } DisplaySettingsCells* dsc = theMainWindow->getBrainSet()->getDisplaySettingsCells(); dsc->setDisplayCells(showCellsCheckBox->isChecked()); dsc->setDisplayVolumeCells(showVolumeCellsCheckBox->isChecked()); dsc->setDisplayFlatCellsRaised(showRaisedCellCheckBox->isChecked()); //dsc->setDisplayLeftHemisphereCells(showLeftHemisphereCellCheckBox->isChecked()); //dsc->setDisplayRightHemisphereCells(showRightHemisphereCellCheckBox->isChecked()); dsc->setDisplayCellsOnCorrectHemisphereOnly(showCorrectHemisphereCellsCheckBox->isChecked()); dsc->setDisplayMode(static_cast( cellDisplayModeComboBox->currentIndex())); dsc->setSymbolOverride(static_cast( cellSymbolOverrideComboBox->currentIndex())); dsc->setOpacity(cellOpacityDoubleSpinBox->value()); dsc->setDrawSize(cellSizeSpinBox->value()); dsc->setDistanceToSurfaceLimit(cellDistSpinBox->value()); dsc->determineDisplayedCells(); GuiBrainModelOpenGL::updateAllGL(NULL); } /** * read the cell color page. */ void GuiDisplayControlDialog::readCellColorPage() { if (pageCellsColor == NULL) { return; } if (creatingDialog) { return; } CellColorFile* cellColors = theMainWindow->getBrainSet()->getCellColorFile(); const int numColors = cellColors->getNumberOfColors(); if (numColors == numValidCellColors) { for (int i = 0; i < numValidCellColors; i++) { const int colorIndex = cellColorCheckBoxesColorIndex[i]; cellColors->setSelected(colorIndex, cellColorCheckBoxes[i]->isChecked()); } } else { std::cerr << "Number of cell color checkboxes does not equal number of cell colors." << std::endl; } DisplaySettingsCells* dsc = theMainWindow->getBrainSet()->getDisplaySettingsCells(); dsc->determineDisplayedCells(); GuiBrainModelOpenGL::updateAllGL(NULL); } /** * read the cell class page. */ void GuiDisplayControlDialog::readCellClassPage() { if (pageCellsClass == NULL) { return; } if (creatingDialog) { return; } CellProjectionFile* cf = theMainWindow->getBrainSet()->getCellProjectionFile(); int numClasses = 0; if (cf != NULL) { numClasses = cf->getNumberOfCellClasses(); } if (numClasses == numValidCellClasses) { for (int i = 0; i < numValidCellClasses; i++) { const int classIndex = cellClassCheckBoxesClassIndex[i]; cf->setCellClassSelectedByIndex(classIndex, cellClassCheckBoxes[i]->isChecked()); } } else { std::cerr << "Number of cell class checkboxes does not equal number of cell classes." << std::endl; } DisplaySettingsCells* dsc = theMainWindow->getBrainSet()->getDisplaySettingsCells(); dsc->determineDisplayedCells(); GuiBrainModelOpenGL::updateAllGL(NULL); } /** * Update all items in the dialog. Typically called after loading * a spec file. */ void GuiDisplayControlDialog::updateAllItemsInDialog(const bool filesChanged, const bool updateResultOfSceneChange) { updatePageSelectionComboBox(); skipScenePageUpdate = updateResultOfSceneChange; updateOverlayUnderlayItemsNew(); updateArealEstimationItems(); updateBorderItems(filesChanged); updateCellItems(filesChanged); updateCocomacItems(); updateContourItems(filesChanged); updateDeformationFieldPage(); updateGeodesicItems(); updateLatLonItems(); updateRegionItems(); updateRgbPaintItems(); updateSceneItems(); updateShapeItems(); updateFociItems(filesChanged); updateImagesItems(); updateMetricItems(); updateMiscItems(); updateModelItems(); updatePaintItems(); updateProbAtlasSurfaceItems(filesChanged); updateProbAtlasVolumeItems(filesChanged); updateSectionMainPage(); updateSurfaceAndVolumeItems(); updateVectorItems(); updateTopographyItems(); updateVolumeItems(); updatePageSelectionComboBox(); skipScenePageUpdate = false; QString title("Display Control"); const QString specName(theMainWindow->getBrainSet()->getSpecFileName()); if (specName.isEmpty() == false) { title.append(" - "); title.append(FileUtilities::basename(specName)); } setWindowTitle(title); } /** * create the shape selection page. */ void GuiDisplayControlDialog::createShapeSelectionPage() { pageSurfaceShapeSelections = new QWidget; pageWidgetStack->addWidget(pageSurfaceShapeSelections); createAndUpdateSurfaceShapeSelections(); } /** * create the shape settings page. */ void GuiDisplayControlDialog::createShapeSettingsPage() { //----------------------------------------------------------------------------- // // Selected column information. // QLabel* shapeMinMaxColumnSelectionLabel = new QLabel("Column"); shapeMinMaxColumnSelectionComboBox = new GuiNodeAttributeColumnSelectionComboBox( GUI_NODE_FILE_TYPE_SURFACE_SHAPE, false, false, false); QObject::connect(shapeMinMaxColumnSelectionComboBox, SIGNAL(activated(int)), this, SLOT(updateShapeMinMaxMappingSettings())); QLabel* minMaxLabel = new QLabel("Min/Max "); shapeViewMinimumLabel = new QLabel(""); shapeViewMaximumLabel = new QLabel(""); QLabel* mappingLabel = new QLabel("Mapping "); shapeMinimumMappingDoubleSpinBox = new QDoubleSpinBox; shapeMinimumMappingDoubleSpinBox->setMinimum(-1000000.0); shapeMinimumMappingDoubleSpinBox->setMaximum( 1000000.0); shapeMinimumMappingDoubleSpinBox->setSingleStep(1.0); shapeMinimumMappingDoubleSpinBox->setDecimals(6); QObject::connect(shapeMinimumMappingDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readShapeSettings())); shapeMaximumMappingDoubleSpinBox = new QDoubleSpinBox; shapeMaximumMappingDoubleSpinBox->setMinimum(-1000000.0); shapeMaximumMappingDoubleSpinBox->setMaximum( 1000000.0); shapeMaximumMappingDoubleSpinBox->setSingleStep(1.0); shapeMaximumMappingDoubleSpinBox->setDecimals(6); QObject::connect(shapeMaximumMappingDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readShapeSettings())); QGridLayout* selectionGridLayout = new QGridLayout; selectionGridLayout->addWidget(shapeMinMaxColumnSelectionLabel, 0, 0); selectionGridLayout->addWidget(shapeMinMaxColumnSelectionComboBox, 0, 1, 1, 2); selectionGridLayout->addWidget(minMaxLabel, 1, 0); selectionGridLayout->addWidget(shapeViewMinimumLabel, 1, 1); selectionGridLayout->addWidget(shapeViewMaximumLabel, 1, 2); selectionGridLayout->addWidget(mappingLabel, 2, 0); selectionGridLayout->addWidget(shapeMinimumMappingDoubleSpinBox, 2, 1); selectionGridLayout->addWidget(shapeMaximumMappingDoubleSpinBox, 2, 2); // // Histogram button // QPushButton* histoPushButton = new QPushButton("Histogram..."); histoPushButton->setAutoDefault(false); histoPushButton->setFixedSize(histoPushButton->sizeHint()); QObject::connect(histoPushButton, SIGNAL(clicked()), this, SLOT(surfaceShapeHistogram())); // // Group box and layouts // QVBoxLayout* selectionLeftLayout = new QVBoxLayout; selectionLeftLayout->addLayout(selectionGridLayout); selectionLeftLayout->addWidget(histoPushButton); QGroupBox* selectionGroupBox = new QGroupBox("Min Max Mapping"); QHBoxLayout* selectionGroupLayout = new QHBoxLayout(selectionGroupBox); selectionGroupLayout->addLayout(selectionLeftLayout); selectionGroupLayout->addStretch(); //----------------------------------------------------------------------------- // // Color map selections // shapeColorMapGrayRadioButton = new QRadioButton("Gray"); shapeColorMapOrangeYellowRadioButton = new QRadioButton("Orange-Yellow"); shapeColorMapPaletteRadioButton = new QRadioButton("Palette"); shapeColorMapPaletteComboBox = new QComboBox; QObject::connect(shapeColorMapPaletteComboBox, SIGNAL(activated(int)), this, SLOT(readShapeSettings())); // // Button group to keep radio buttons mutually exclusive // palColorMapButtonGroup = new QButtonGroup(this); palColorMapButtonGroup->setExclusive(true); palColorMapButtonGroup->addButton(shapeColorMapGrayRadioButton, DisplaySettingsSurfaceShape::SURFACE_SHAPE_COLOR_MAP_GRAY); palColorMapButtonGroup->addButton(shapeColorMapOrangeYellowRadioButton, DisplaySettingsSurfaceShape::SURFACE_SHAPE_COLOR_MAP_ORANGE_YELLOW); palColorMapButtonGroup->addButton(shapeColorMapPaletteRadioButton, DisplaySettingsSurfaceShape::SURFACE_SHAPE_COLOR_MAP_PALETTE); QObject::connect(palColorMapButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(shapeColorMapSelection(int))); // // Interpolate palette colors // shapeColorMapInterpolatePaletteCheckBox = new QCheckBox("Interpolate Palette Colors"); QObject::connect(shapeColorMapInterpolatePaletteCheckBox, SIGNAL(toggled(bool)), this, SLOT(readShapeSettings())); // // Display color bar // shapeDisplayColorBarCheckBox = new QCheckBox("Display Color Bar"); QObject::connect(shapeDisplayColorBarCheckBox, SIGNAL(clicked()), this, SLOT(readShapeSettings())); // // Color mapping items // QHBoxLayout* paletteBoxLayout = new QHBoxLayout; QLabel* paletteDummy = new QLabel(" "); paletteBoxLayout->addWidget(shapeColorMapPaletteRadioButton); paletteBoxLayout->addWidget(shapeColorMapPaletteComboBox); paletteBoxLayout->addWidget(paletteDummy); paletteBoxLayout->setStretchFactor(paletteDummy, 1000); QGroupBox* colorMappingGroupBox = new QGroupBox("Color Mapping"); QVBoxLayout* colorMappingGroupLayout = new QVBoxLayout(colorMappingGroupBox); colorMappingGroupLayout->addWidget(shapeColorMapGrayRadioButton); colorMappingGroupLayout->addWidget(shapeColorMapOrangeYellowRadioButton); colorMappingGroupLayout->addLayout(paletteBoxLayout); colorMappingGroupLayout->addWidget(shapeColorMapInterpolatePaletteCheckBox); colorMappingGroupLayout->addWidget(shapeDisplayColorBarCheckBox); //----------------------------------------------------------------------------- // // Uncertainty column // shapeNodeIdDeviationComboBox = new GuiNodeAttributeColumnSelectionComboBox( GUI_NODE_FILE_TYPE_SURFACE_SHAPE, false, false, false); shapeNodeIdDeviationComboBox->setNoneSelectionLabel("Disabled"); QObject::connect(shapeNodeIdDeviationComboBox, SIGNAL(activated(int)), this, SLOT(readShapeSettings())); shapeNodeIdDeviationGroupBox = new QGroupBox("Node ID Deviation"); shapeNodeIdDeviationGroupBox->setCheckable(true); QObject::connect(shapeNodeIdDeviationGroupBox, SIGNAL(toggled(bool)), shapeNodeIdDeviationComboBox, SLOT(setEnabled(bool))); QObject::connect(shapeNodeIdDeviationGroupBox, SIGNAL(toggled(bool)), this, SLOT(readShapeSettings())); QVBoxLayout* shapeNodeLayout = new QVBoxLayout(shapeNodeIdDeviationGroupBox); shapeNodeLayout->addWidget(shapeNodeIdDeviationComboBox); // // Place all items in a vertical box // pageSurfaceShapeSettings = new QWidget; pageWidgetStack->addWidget(pageSurfaceShapeSettings); QVBoxLayout* shapeSettingsLayout = new QVBoxLayout(pageSurfaceShapeSettings); shapeSettingsLayout->addWidget(selectionGroupBox); shapeSettingsLayout->addWidget(colorMappingGroupBox); shapeSettingsLayout->addWidget(shapeNodeIdDeviationGroupBox); pageSurfaceShapeSettings->setFixedHeight(pageSurfaceShapeSettings->sizeHint().height()); pageSurfaceShapeSettings->setMaximumWidth(400); pageSurfaceShapeSettingsWidgetGroup = new WuQWidgetGroup(this); pageSurfaceShapeSettingsWidgetGroup->addWidget(shapeMinMaxColumnSelectionLabel); pageSurfaceShapeSettingsWidgetGroup->addWidget(shapeMinMaxColumnSelectionComboBox); pageSurfaceShapeSettingsWidgetGroup->addWidget(shapeMinimumMappingDoubleSpinBox); pageSurfaceShapeSettingsWidgetGroup->addWidget(shapeMaximumMappingDoubleSpinBox); pageSurfaceShapeSettingsWidgetGroup->addWidget(shapeColorMapPaletteComboBox); pageSurfaceShapeSettingsWidgetGroup->addWidget(shapeColorMapGrayRadioButton); pageSurfaceShapeSettingsWidgetGroup->addWidget(shapeColorMapOrangeYellowRadioButton); pageSurfaceShapeSettingsWidgetGroup->addWidget(shapeColorMapPaletteRadioButton); pageSurfaceShapeSettingsWidgetGroup->addWidget(shapeColorMapInterpolatePaletteCheckBox); pageSurfaceShapeSettingsWidgetGroup->addWidget(shapeDisplayColorBarCheckBox); pageSurfaceShapeSettingsWidgetGroup->addWidget(shapeNodeIdDeviationComboBox); pageSurfaceShapeSettingsWidgetGroup->addWidget(shapeNodeIdDeviationGroupBox); } /** * Create and update surface shape selections. Because the number of columns may change, * this method may update and change the labels on existing checkboxes, add new * checkboxes, and hide existing checkboxes. */ void GuiDisplayControlDialog::createAndUpdateSurfaceShapeSelections() { SurfaceShapeFile* ssf = theMainWindow->getBrainSet()->getSurfaceShapeFile(); numValidSurfaceShape = ssf->getNumberOfColumns(); const int numExistingSurfaceShape = static_cast(surfaceShapeViewRadioButtons.size()); const int nameMinimumWidth = 500; if (surfaceShapeSubSelectionsLayout == NULL) { // // Grid layout for surfaceShape selections // QWidget* shapeSelectionsGridWidget = new QWidget; surfaceShapeSelectionGridLayout = new QGridLayout(shapeSelectionsGridWidget); //surfaceShapeSelectionGridLayout->setMargin(3); surfaceShapeSelectionGridLayout->setSpacing(3); surfaceShapeSelectionGridLayout->setColumnMinimumWidth(5, nameMinimumWidth+20); surfaceShapeSelectionGridLayout->addWidget(new QLabel("#"), 0, 0, Qt::AlignRight); surfaceShapeSelectionGridLayout->addWidget(new QLabel("View"), 0, 1, Qt::AlignHCenter); surfaceShapeSelectionGridLayout->addWidget(new QLabel("Cmt"), 0, 2, Qt::AlignHCenter); surfaceShapeSelectionGridLayout->addWidget(new QLabel("MD"), 0, 3, Qt::AlignHCenter); surfaceShapeSelectionGridLayout->addWidget(new QLabel("Hist"), 0, 4, Qt::AlignHCenter); surfaceShapeSelectionGridLayout->addWidget(new QLabel("Name"), 0, 5, Qt::AlignLeft); // // For stretching on bottom // //const int rowStretchNumber = 15000; //surfaceShapeSelectionGridLayout->addWidget(new QLabel(""), // rowStretchNumber, 4, 1, 1, Qt::AlignLeft); surfaceShapeSelectionGridLayout->setColumnStretch(0, 0); surfaceShapeSelectionGridLayout->setColumnStretch(1, 0); surfaceShapeSelectionGridLayout->setColumnStretch(2, 0); surfaceShapeSelectionGridLayout->setColumnStretch(3, 0); surfaceShapeSelectionGridLayout->setColumnStretch(4, 0); surfaceShapeSelectionGridLayout->setColumnStretch(5, 0); //surfaceShapeSelectionGridLayout->setRowStretch(rowStretchNumber, 1000); // // Create the shape selections layout and push selections to the left // surfaceShapeSubSelectionsLayout = new QVBoxLayout(pageSurfaceShapeSelections); surfaceShapeSubSelectionsLayout->addWidget(shapeSelectionsGridWidget, 100, Qt::AlignLeft | Qt::AlignTop); } // // Create the button group for the surfaceShape view buttons. // if (surfaceShapeViewButtonGroup == NULL) { surfaceShapeViewButtonGroup = new QButtonGroup(this); surfaceShapeViewButtonGroup->setExclusive(true); QObject::connect(surfaceShapeViewButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(shapeColumnSelection(int))); } // // Create the button group for the surfaceShape buttons. // if (surfaceShapeCommentButtonGroup == NULL) { surfaceShapeCommentButtonGroup = new QButtonGroup(this); QObject::connect(surfaceShapeCommentButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(surfaceShapeCommentColumnSelection(int))); } // // Create the button group for the surface shape metadata buttons // if (surfaceShapeMetaDataButtonGroup == NULL) { surfaceShapeMetaDataButtonGroup = new QButtonGroup(this); QObject::connect(surfaceShapeMetaDataButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(surfaceShapeMetaDataColumnSelection(int))); } // // Create the button group for the surface shape histogram buttons // if (surfaceShapeHistogramButtonGroup == NULL) { surfaceShapeHistogramButtonGroup = new QButtonGroup(this); QObject::connect(surfaceShapeHistogramButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(surfaceShapeHistogramColumnSelection(int))); } // // Add new widgets as needed // for (int i = numExistingSurfaceShape; i < numValidSurfaceShape; i++) { // // Column number // QLabel* columnNumberLabel = new QLabel(QString::number(i + 1)); surfaceShapeColumnNumberLabels.push_back(columnNumberLabel); surfaceShapeSelectionGridLayout->addWidget(columnNumberLabel, i + 1, 0, Qt::AlignRight); // // View radio button // QRadioButton* viewRadioButton = new QRadioButton(""); surfaceShapeViewRadioButtons.push_back(viewRadioButton); surfaceShapeViewButtonGroup->addButton(viewRadioButton, i); surfaceShapeSelectionGridLayout->addWidget(viewRadioButton, i + 1, 1, Qt::AlignHCenter); // // Comment push button // QToolButton* commentPushButton = new QToolButton; commentPushButton->setText("?"); //commentPushButton->setFixedWidth(40); //commentPushButton->setAutoDefault(false); surfaceShapeColumnCommentPushButtons.push_back(commentPushButton); surfaceShapeCommentButtonGroup->addButton(commentPushButton, i); surfaceShapeSelectionGridLayout->addWidget(commentPushButton, i + 1, 2, Qt::AlignHCenter); // // Metadata push button // QToolButton* metaDataPushButton = new QToolButton; metaDataPushButton->setText("M"); metaDataPushButton->setToolTip("Press the button to set the\n" "metadata link for this column"); //metaDataPushButton->setFixedWidth(40); //metaDataPushButton->setAutoDefault(false); surfaceShapeColumnMetaDataPushButtons.push_back(metaDataPushButton); surfaceShapeMetaDataButtonGroup->addButton(metaDataPushButton, i); surfaceShapeSelectionGridLayout->addWidget(metaDataPushButton, i + 1, 3, Qt::AlignHCenter); // // Histogram push button // QToolButton* histogramPushButton = new QToolButton; histogramPushButton->setText("H"); histogramPushButton->setToolTip("Press this button to display\n" "a histogram for this column."); surfaceShapeColumnHistogramPushButtons.push_back(histogramPushButton); surfaceShapeHistogramButtonGroup->addButton(histogramPushButton, i); surfaceShapeSelectionGridLayout->addWidget(histogramPushButton, i + 1, 4, Qt::AlignHCenter); // // Name line edit // QLineEdit* surfaceShapeLineEdit = new QLineEdit; surfaceShapeLineEdit->setText(ssf->getColumnName(i)); surfaceShapeLineEdit->setMinimumWidth(nameMinimumWidth); surfaceShapeColumnNameLineEdits.push_back(surfaceShapeLineEdit); surfaceShapeSelectionGridLayout->addWidget(surfaceShapeLineEdit, i + 1, 5, Qt::AlignLeft); } // // Show and update all valid surfaceShapes // for (int i = 0; i < numValidSurfaceShape; i++) { surfaceShapeColumnNameLineEdits[i]->blockSignals(true); surfaceShapeColumnNameLineEdits[i]->setText(ssf->getColumnName(i)); surfaceShapeColumnNameLineEdits[i]->blockSignals(false); if (i < numExistingSurfaceShape) { if (surfaceShapeColumnNumberLabels[i]->isVisible() == false) { surfaceShapeColumnNumberLabels[i]->show(); surfaceShapeViewRadioButtons[i]->show(); surfaceShapeColumnCommentPushButtons[i]->show(); surfaceShapeColumnMetaDataPushButtons[i]->show(); surfaceShapeColumnHistogramPushButtons[i]->show(); surfaceShapeColumnNameLineEdits[i]->show(); surfaceShapeColumnNameLineEdits[i]->home(true); } } } // // Hide widgets that are not needed // for (int i = numValidSurfaceShape; i < numExistingSurfaceShape; i++) { surfaceShapeColumnNumberLabels[i]->hide(); surfaceShapeViewRadioButtons[i]->hide(); surfaceShapeColumnCommentPushButtons[i]->hide(); surfaceShapeColumnMetaDataPushButtons[i]->hide(); surfaceShapeColumnHistogramPushButtons[i]->hide(); surfaceShapeColumnNameLineEdits[i]->hide(); } } /** * called when a metric metadata column is selected. */ void GuiDisplayControlDialog::surfaceShapeMetaDataColumnSelection(int col) { SurfaceShapeFile* ssf = theMainWindow->getBrainSet()->getSurfaceShapeFile(); if ((col >= 0) && (col < ssf->getNumberOfColumns())) { StudyMetaDataLinkSet smdls = ssf->getColumnStudyMetaDataLinkSet(col); GuiStudyMetaDataLinkCreationDialog smdlcd(this); smdlcd.initializeSelectedLinkSet(smdls); if (smdlcd.exec() == GuiStudyMetaDataLinkCreationDialog::Accepted) { smdls = smdlcd.getLinkSetCreated(); ssf->setColumnStudyMetaDataLinkSet(col, smdls); } } } /** * called when a surface shape column histogram H is selected. */ void GuiDisplayControlDialog::surfaceShapeHistogramColumnSelection(int col) { SurfaceShapeFile* ssf = theMainWindow->getBrainSet()->getSurfaceShapeFile(); if ((col >= 0) && (col < ssf->getNumberOfColumns())) { const int numNodes = ssf->getNumberOfNodes(); std::vector values(numNodes); for (int i = 0; i < numNodes; i++) { values[i] = ssf->getValue(i, col); } GuiHistogramDisplayDialog* ghd = new GuiHistogramDisplayDialog(theMainWindow, ssf->getColumnName(col), values, false, static_cast(Qt::WA_DeleteOnClose)); ghd->show(); } } /** * Called when a surface shape column comment is selected. */ void GuiDisplayControlDialog::surfaceShapeCommentColumnSelection(int column) { SurfaceShapeFile* ssf = theMainWindow->getBrainSet()->getSurfaceShapeFile(); if ((column >= 0) && (column < ssf->getNumberOfColumns())) { GuiDataFileCommentDialog* dfcd = new GuiDataFileCommentDialog(theMainWindow, ssf, column); dfcd->show(); } } /** * called when surface shape histogram pushbutton is pressed. */ void GuiDisplayControlDialog::surfaceShapeHistogram() { //DisplaySettingsSurfaceShape* dss = theMainWindow->getBrainSet()->getDisplaySettingsSurfaceShape(); SurfaceShapeFile* ssf = theMainWindow->getBrainSet()->getSurfaceShapeFile(); const int column = shapeMinMaxColumnSelectionComboBox->currentIndex(); if ((column >= 0) && (column < ssf->getNumberOfColumns())) { const int numNodes = ssf->getNumberOfNodes(); std::vector values(numNodes); for (int i = 0; i < numNodes; i++) { values[i] = ssf->getValue(i, column); } GuiHistogramDisplayDialog* ghd = new GuiHistogramDisplayDialog(theMainWindow, ssf->getColumnName(column), values, false, static_cast(Qt::WA_DeleteOnClose)); ghd->show(); } } /** * Called when surface shape color map selected. */ void GuiDisplayControlDialog::shapeColorMapSelection(int mapNumber) { DisplaySettingsSurfaceShape* dsss = theMainWindow->getBrainSet()->getDisplaySettingsSurfaceShape(); dsss->setColorMap(static_cast(mapNumber)); readShapeSettings(); } /** * update shape overlay/underlay selection. */ void GuiDisplayControlDialog::updateShapeOverlayUnderlaySelection() { } /** * update the shape items. */ void GuiDisplayControlDialog::updateShapeItems() { updatePageSelectionComboBox(); updateShapeSettings(); updateShapeSettingsColorMappingComboBox(); updateShapeSelections(); updateShapeOverlayUnderlaySelection(); } /** * update shape min/max mapping settings. */ void GuiDisplayControlDialog::updateShapeMinMaxMappingSettings() { SurfaceShapeFile* ssf = theMainWindow->getBrainSet()->getSurfaceShapeFile(); if (ssf->getNumberOfColumns() > 0) { const int minMaxCol = shapeMinMaxColumnSelectionComboBox->currentIndex(); float colMin, colMax; ssf->getDataColumnMinMax(minMaxCol, colMin, colMax); shapeViewMinimumLabel->setText(QString::number(colMin, 'f', 6)); shapeViewMaximumLabel->setText(QString::number(colMax, 'f', 6)); ssf->getColumnColorMappingMinMax(minMaxCol, colMin, colMax); shapeMinimumMappingDoubleSpinBox->blockSignals(true); shapeMinimumMappingDoubleSpinBox->setValue(colMin); shapeMinimumMappingDoubleSpinBox->blockSignals(false); shapeMaximumMappingDoubleSpinBox->blockSignals(true); shapeMaximumMappingDoubleSpinBox->setValue(colMax); shapeMaximumMappingDoubleSpinBox->blockSignals(false); } } /** * update the shape settings color mapping combo box. */ void GuiDisplayControlDialog::updateShapeSettingsColorMappingComboBox() { if (pageSurfaceShapeSettings == NULL) { return; } int columnNumber = -1; BrainSet* brainSet = theMainWindow->getBrainSet(); for (int i = 0; i < brainSet->getNumberOfSurfaceOverlays(); i++) { BrainModelSurfaceOverlay* bmsOverlay = brainSet->getSurfaceOverlay(i); if (bmsOverlay->getOverlay(surfaceModelIndex) == BrainModelSurfaceOverlay::OVERLAY_SURFACE_SHAPE) { columnNumber = bmsOverlay->getDisplayColumnSelected(surfaceModelIndex); } } if ((columnNumber >= 0) && (columnNumber < brainSet->getSurfaceShapeFile()->getNumberOfColumns())) { shapeMinMaxColumnSelectionComboBox->setCurrentIndex(columnNumber); updateShapeMinMaxMappingSettings(); } } /** * update shape settings items in dialog. */ void GuiDisplayControlDialog::updateShapeSettings() { if (pageSurfaceShapeSettings == NULL) { return; } pageSurfaceShapeSettingsWidgetGroup->blockSignals(true); DisplaySettingsSurfaceShape* dsss = theMainWindow->getBrainSet()->getDisplaySettingsSurfaceShape(); shapeMinMaxColumnSelectionComboBox->updateComboBox(theMainWindow->getBrainSet()->getSurfaceShapeFile()); updateShapeMinMaxMappingSettings(); shapeDisplayColorBarCheckBox->setChecked(dsss->getDisplayColorBar()); shapeNodeIdDeviationComboBox->updateComboBox(theMainWindow->getBrainSet()->getSurfaceShapeFile()); shapeNodeIdDeviationGroupBox->setChecked(dsss->getNodeUncertaintyEnabled()); shapeNodeIdDeviationComboBox->setCurrentIndex(dsss->getNodeUncertaintyColumn()); shapeDisplayColorBarCheckBox->setEnabled(validShapeData); shapeColorMapPaletteComboBox->clear(); PaletteFile* pf = theMainWindow->getBrainSet()->getPaletteFile(); const int numPalettes = pf->getNumberOfPalettes(); for (int i = 0; i < numPalettes; i++) { const Palette* p = pf->getPalette(i); QString name(p->getName()); if (p->getPositiveOnly()) { name.append("+"); } shapeColorMapPaletteComboBox->addItem(name); } shapeColorMapPaletteComboBox->setCurrentIndex(dsss->getSelectedPaletteIndex()); shapeColorMapInterpolatePaletteCheckBox->setChecked(dsss->getInterpolatePaletteColors()); const QList colorMapButtons = palColorMapButtonGroup->buttons(); const int numColorMapButtons = colorMapButtons.count(); if ((dsss->getColorMap() >= 0) && (dsss->getColorMap() < numColorMapButtons)) { const int buttonNum = dsss->getColorMap(); QAbstractButton* ab = palColorMapButtonGroup->button(buttonNum); QRadioButton* rb = dynamic_cast(ab); if (rb != NULL) { rb->setChecked(true); } } pageSurfaceShapeSettings->setEnabled(validShapeData); updatePageSelectionComboBox(); pageSurfaceShapeSettingsWidgetGroup->blockSignals(false); } /** * Update surface shape selections in dialog. */ void GuiDisplayControlDialog::updateShapeSelections() { if (pageSurfaceShapeSelections == NULL) { return; } DisplaySettingsSurfaceShape* dsss = theMainWindow->getBrainSet()->getDisplaySettingsSurfaceShape(); shapeApplySelectionToLeftAndRightStructuresFlagCheckBox->blockSignals(true); shapeApplySelectionToLeftAndRightStructuresFlagCheckBox->setChecked(dsss->getApplySelectionToLeftAndRightStructuresFlag()); shapeApplySelectionToLeftAndRightStructuresFlagCheckBox->blockSignals(false); pageSurfaceShapeSelections->setEnabled(validShapeData); createAndUpdateSurfaceShapeSelections(); if (surfaceShapeViewButtonGroup != NULL) { QRadioButton* rb = dynamic_cast( surfaceShapeViewButtonGroup->button( dsss->getSelectedDisplayColumn(surfaceModelIndex, overlayNumberComboBox->currentIndex()))); if (rb != NULL) { rb->setChecked(true); } } updatePageSelectionComboBox(); } /** * Read surface shape color mapping line edits. */ void GuiDisplayControlDialog::readShapeColorMapping() { if (creatingDialog) { return; } if (pageWidgetStack->currentWidget() == pageSurfaceShapeSettings) { SurfaceShapeFile* ssf = theMainWindow->getBrainSet()->getSurfaceShapeFile(); const int col = shapeMinMaxColumnSelectionComboBox->currentIndex(); if ((col >= 0) && (col < ssf->getNumberOfColumns())) { ssf->setColumnColorMappingMinMax(col, shapeMinimumMappingDoubleSpinBox->value(), shapeMaximumMappingDoubleSpinBox->value()); } } } /** * read the surface shape settings. */ void GuiDisplayControlDialog::readShapeSettings() { if (pageSurfaceShapeSettings == NULL) { return; } if (creatingDialog) { return; } DisplaySettingsSurfaceShape* dsss = theMainWindow->getBrainSet()->getDisplaySettingsSurfaceShape(); dsss->setSelectedPaletteIndex(shapeColorMapPaletteComboBox->currentIndex()); dsss->setInterpolatePaletteColors(shapeColorMapInterpolatePaletteCheckBox->isChecked()); dsss->setNodeUncertaintyColumn(shapeNodeIdDeviationComboBox->currentIndex()); dsss->setNodeUncertaintyEnabled(shapeNodeIdDeviationGroupBox->isChecked()); dsss->setDisplayColorBar(shapeDisplayColorBarCheckBox->isChecked()); readShapeColorMapping(); theMainWindow->getBrainSet()->getNodeColoring()->assignColors(); GuiBrainModelOpenGL::updateAllGL(NULL); } /** * read the shape atlas L-to-L, R-to-R. */ void GuiDisplayControlDialog::readShapeL2LR2R() { DisplaySettingsSurfaceShape* dsss = theMainWindow->getBrainSet()->getDisplaySettingsSurfaceShape(); dsss->setApplySelectionToLeftAndRightStructuresFlag(shapeApplySelectionToLeftAndRightStructuresFlagCheckBox->isChecked()); theMainWindow->getBrainSet()->getNodeColoring()->assignColors(); GuiBrainModelOpenGL::updateAllGL(NULL); displayOverlayLeftToLeftRightToRightMessage(); } /** * Read the surface shape selections. */ void GuiDisplayControlDialog::readShapeSelections() { if (pageSurfaceShapeSelections == NULL) { return; } if (creatingDialog) { return; } SurfaceShapeFile* ssf = theMainWindow->getBrainSet()->getSurfaceShapeFile(); if (ssf->getNumberOfColumns() > 0) { for (int i = 0; i < ssf->getNumberOfColumns(); i++) { const QString name(surfaceShapeColumnNameLineEdits[i]->text()); if (name != ssf->getColumnName(i)) { ssf->setColumnName(i, name); updateSurfaceOverlayWidgets(); } } } GuiFilesModified fm; fm.setSurfaceShapeModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(NULL); } /** * create the section page. */ void GuiDisplayControlDialog::createSectionMainPage() { QLabel* sectionNumberLabel = new QLabel("Section Number"); sectionNumberLineEdit = new QLineEdit; sectionNumberLineEdit->setFixedWidth(100); QRegExp sectionRX("\\d+[xX]?"); sectionNumberLineEdit->setValidator(new QRegExpValidator(sectionRX, sectionNumberLineEdit)); QObject::connect(sectionNumberLineEdit, SIGNAL(returnPressed()), this, SLOT(readSectionMainPage())); sectionNumberLineEdit->setToolTip( "Enter a number to display a specific section.\n" "Enter a number followed by \"X\" to view every\n" "\"number\" sections.\n" "Example: \n" " 10 displays only section ten.\n" " 10X displays every 10th section.\n" "Press the return key when finished."); QHBoxLayout* sectionNumberLayout = new QHBoxLayout; sectionNumberLayout->addWidget(sectionNumberLabel); sectionNumberLayout->addWidget(sectionNumberLineEdit); sectionNumberLayout->addStretch(); pageSectionMain = new QWidget; pageWidgetStack->addWidget(pageSectionMain); QVBoxLayout* pageSectionMainLayout = new QVBoxLayout(pageSectionMain); pageSectionMainLayout->addLayout(sectionNumberLayout); pageSectionMainLayout->addStretch(); pageSectionMainWidgetGroup = new WuQWidgetGroup(this); pageSectionMainWidgetGroup->addWidget(sectionNumberLineEdit); } /** * update the section page. */ void GuiDisplayControlDialog::updateSectionMainPage() { DisplaySettingsSection* dss = theMainWindow->getBrainSet()->getDisplaySettingsSection(); if (pageSectionMain != NULL) { pageSectionMainWidgetGroup->blockSignals(true); int sectionNumber; bool sectionEveryX; dss->getSectionHighlighting(sectionNumber, sectionEveryX); QString sectionText = QString::number(sectionNumber); if (sectionEveryX) { sectionText.append("X"); } sectionNumberLineEdit->setText(sectionText); pageSectionMainWidgetGroup->blockSignals(false); } } /** * read section page. */ void GuiDisplayControlDialog::readSectionMainPage() { DisplaySettingsSection* dss = theMainWindow->getBrainSet()->getDisplaySettingsSection(); const QString sectionText = sectionNumberLineEdit->text(); const int xPos = sectionText.indexOf('x', 0, Qt::CaseInsensitive); int sectionNumber = 0; if (xPos >= 0) { sectionNumber = sectionText.left(xPos).toInt(); } else { sectionNumber = sectionText.toInt(); } dss->setSectionHighlighting(sectionNumber, (xPos >= 0)); theMainWindow->getBrainSet()->getNodeColoring()->assignColors(); GuiBrainModelOpenGL::updateAllGL(NULL); } /** * create the paint main page. */ void GuiDisplayControlDialog::createPaintMainPage() { // // Medial wall override // paintMedWallCheckBox = new QCheckBox("Enable Medial Wall Override"); QObject::connect(paintMedWallCheckBox, SIGNAL(toggled(bool)), this, SLOT(readPaintMainPageSelections())); paintMedWallColumnComboBox = new GuiNodeAttributeColumnSelectionComboBox( GUI_NODE_FILE_TYPE_PAINT, false, false, false); QObject::connect(paintMedWallColumnComboBox, SIGNAL(itemSelected(int)), this, SLOT(readPaintMainPageSelections())); QGroupBox* medWallBox = new QGroupBox("Medial Wall Override"); QVBoxLayout* medWallBoxLayout = new QVBoxLayout(medWallBox); medWallBoxLayout->addWidget(paintMedWallCheckBox); medWallBoxLayout->addWidget(paintMedWallColumnComboBox); QLabel* geoBlendLabel = new QLabel("Geography Blending"); geographyBlendingDoubleSpinBox = new QDoubleSpinBox; geographyBlendingDoubleSpinBox->setMinimum(0.0); geographyBlendingDoubleSpinBox->setMaximum(1.0); geographyBlendingDoubleSpinBox->setSingleStep(0.1); geographyBlendingDoubleSpinBox->setDecimals(3); geographyBlendingDoubleSpinBox->setFixedWidth(100); geographyBlendingDoubleSpinBox->setToolTip( "Geography blending factor: \n" "color = factor * overlay-color +\n" " (1.0 - factor) * underlay-color"); QObject::connect(geographyBlendingDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readPaintMainPageSelections())); QHBoxLayout* geoBlendLayout = new QHBoxLayout; geoBlendLayout->addWidget(geoBlendLabel); geoBlendLayout->addWidget(geographyBlendingDoubleSpinBox); geoBlendLayout->addStretch(); // // Display color key button // QPushButton* colorKeyPushButton = new QPushButton("Display Color Key..."); colorKeyPushButton->setFixedSize(colorKeyPushButton->sizeHint()); colorKeyPushButton->setAutoDefault(false); QObject::connect(colorKeyPushButton, SIGNAL(clicked()), theMainWindow, SLOT(displayPaintColorKey())); pagePaintMain = new QWidget; pageWidgetStack->addWidget(pagePaintMain); QVBoxLayout* pagePaintMainLayout = new QVBoxLayout(pagePaintMain); pagePaintMainLayout->addLayout(geoBlendLayout); pagePaintMainLayout->addWidget(medWallBox); pagePaintMainLayout->addWidget(colorKeyPushButton); pagePaintMainLayout->addStretch(); pagePaintMainWidgetGroup = new WuQWidgetGroup(this); pagePaintMainWidgetGroup->addWidget(geographyBlendingDoubleSpinBox); pagePaintMainWidgetGroup->addWidget(paintMedWallCheckBox); pagePaintMainWidgetGroup->addWidget(paintMedWallColumnComboBox); pagePaintMainWidgetGroup->addWidget(colorKeyPushButton); } /** * create the paint name page. */ void GuiDisplayControlDialog::createPaintNamePage() { // // All on/off push button // QPushButton* allOnPushButton = new QPushButton("All On"); allOnPushButton->setAutoDefault(false); QObject::connect(allOnPushButton, SIGNAL(clicked()), this, SLOT(slotPaintNamesAllOnPushButton())); QPushButton* allOffPushButton = new QPushButton("All Off"); allOffPushButton->setAutoDefault(false); QObject::connect(allOffPushButton, SIGNAL(clicked()), this, SLOT(slotPaintNamesAllOffPushButton())); QHBoxLayout* allButtonLayout = new QHBoxLayout; allButtonLayout->addWidget(allOnPushButton); allButtonLayout->addWidget(allOffPushButton); allButtonLayout->addStretch(); // // For name checkboxes // paintNameCheckBoxGridLayout = new QGridLayout; paintNameCheckBoxWidgetGroup = new WuQWidgetGroup(this); // // Create the paint page and its layout // pagePaintName = new QWidget; pageWidgetStack->addWidget(pagePaintName); QVBoxLayout* pagePaintNameLayout = new QVBoxLayout(pagePaintName); pagePaintNameLayout->addLayout(allButtonLayout); pagePaintNameLayout->addLayout(paintNameCheckBoxGridLayout); pagePaintNameLayout->setAlignment(paintNameCheckBoxGridLayout, Qt::AlignTop | Qt::AlignLeft); } /** * create and update the paint names. */ void GuiDisplayControlDialog::createAndUpdatePaintNamePage() { PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); const int numNamesInDialog = static_cast(paintNameCheckBoxes.size()); std::vector paintNames; std::vector paintNameIndices; pf->getAllPaintNamesAndIndices(paintNames, paintNameIndices); const int numValidNames = static_cast(paintNames.size()); // // Add new paint name checkboxes // for (int i = numNamesInDialog; i < numValidNames; i++) { QCheckBox* cb = new QCheckBox(""); QObject::connect(cb, SIGNAL(toggled(bool)), this, SLOT(readPaintNameSelections())); paintNameCheckBoxGridLayout->addWidget(cb, paintNameCheckBoxGridLayout->rowCount(), 0); paintNameCheckBoxes.push_back(cb); paintNameCheckBoxWidgetGroup->addWidget(cb); paintNameCheckBoxPaintFileNameIndices.push_back(i); } // // Update items in dialog // paintNameCheckBoxWidgetGroup->blockSignals(true); for (int i = 0; i < numValidNames; i++) { paintNameCheckBoxes[i]->show(); paintNameCheckBoxes[i]->setText(paintNames[i]); paintNameCheckBoxes[i]->setChecked(pf->getPaintNameEnabled(paintNameIndices[i])); paintNameCheckBoxPaintFileNameIndices[i] = paintNameIndices[i]; } paintNameCheckBoxWidgetGroup->blockSignals(false); // // Hide unused checkboxes // for (int i = numValidNames; i < numNamesInDialog; i++) { paintNameCheckBoxes[i]->hide(); } } /** * Page containing paints. */ void GuiDisplayControlDialog::createPaintColumnPage() { paintColumnButtonGroup = new QButtonGroup(this); paintColumnButtonGroup->setExclusive(true); QObject::connect(paintColumnButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(paintColumnSelection(int))); // // Create the paint page and its layout // pagePaintColumn = new QWidget; pageWidgetStack->addWidget(pagePaintColumn); paintPageLayout = new QVBoxLayout(pagePaintColumn); // // comment button group // paintColumnCommentButtonGroup = new QButtonGroup(this); QObject::connect(paintColumnCommentButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(paintCommentColumnSelection(int))); // // metadata button group // paintColumnMetaDataButtonGroup = new QButtonGroup(this); QObject::connect(paintColumnMetaDataButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(paintMetaDataColumnSelection(int))); // // Widget group for paint column page // pagePaintColumnWidgetGroup = new WuQWidgetGroup(this); } /** * called when a metric metadata column is selected. */ void GuiDisplayControlDialog::paintMetaDataColumnSelection(int col) { PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); if ((col >= 0) && (col < pf->getNumberOfColumns())) { StudyMetaDataLinkSet smdls = pf->getColumnStudyMetaDataLinkSet(col); GuiStudyMetaDataLinkCreationDialog smdlcd(this); smdlcd.initializeSelectedLinkSet(smdls); if (smdlcd.exec() == GuiStudyMetaDataLinkCreationDialog::Accepted) { smdls = smdlcd.getLinkSetCreated(); pf->setColumnStudyMetaDataLinkSet(col, smdls); } } } /** * Create and update the paint page. */ void GuiDisplayControlDialog::createAndUpdatePaintColumnPage() { PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); numValidPaints = pf->getNumberOfColumns(); const int numExistingPaints = static_cast(paintColumnRadioButtons.size()); const int nameMinimumWidth = 500; if (paintColumnSelectionGridLayout == NULL) { QWidget* paintSelectionWidget = new QWidget; paintColumnSelectionGridLayout = new QGridLayout(paintSelectionWidget); //paintSelectionGridLayout->setMargin(3); paintColumnSelectionGridLayout->setSpacing(3); paintColumnSelectionGridLayout->setColumnMinimumWidth(4, nameMinimumWidth+20); paintColumnSelectionGridLayout->addWidget(new QLabel("#"), 0, 0, Qt::AlignRight); paintColumnSelectionGridLayout->addWidget(new QLabel("View"), 0, 1, Qt::AlignHCenter); paintColumnSelectionGridLayout->addWidget(new QLabel("Cmt"), 0, 2, Qt::AlignHCenter); paintColumnSelectionGridLayout->addWidget(new QLabel("MD"), 0, 3, Qt::AlignHCenter); paintColumnSelectionGridLayout->addWidget(new QLabel("Name"), 0, 4, Qt::AlignLeft); // // For stretching on bottom // // const int rowStretchNumber = 15000; // paintSelectionGridLayout->addWidget(new QLabel(""), // rowStretchNumber, 4, 1, 1, Qt::AlignLeft); paintColumnSelectionGridLayout->setColumnStretch(0, 0); paintColumnSelectionGridLayout->setColumnStretch(1, 0); paintColumnSelectionGridLayout->setColumnStretch(2, 0); paintColumnSelectionGridLayout->setColumnStretch(3, 0); paintColumnSelectionGridLayout->setColumnStretch(4, 0); // paintSelectionGridLayout->setRowStretch(rowStretchNumber, 1000); paintPageLayout->addWidget(paintSelectionWidget, 100, Qt::AlignLeft | Qt::AlignTop); } // // Add radio buttons and text boxes // for (int i = numExistingPaints; i < numValidPaints; i++) { QLabel* colLabel = new QLabel(QString::number(i + 1)); paintColumnNameLabels.push_back(colLabel); paintColumnSelectionGridLayout->addWidget(colLabel, i + 1, 0, Qt::AlignLeft); QRadioButton* rb = new QRadioButton(""); paintColumnRadioButtons.push_back(rb); paintColumnButtonGroup->addButton(rb, i); paintColumnSelectionGridLayout->addWidget(rb, i + 1, 1, Qt::AlignLeft); // // Comment push button // QToolButton* commentPushButton = new QToolButton; commentPushButton->setText("?"); //commentPushButton->setFixedWidth(40); //commentPushButton->setAutoDefault(false); paintColumnCommentPushButtons.push_back(commentPushButton); paintColumnCommentButtonGroup->addButton(commentPushButton, i); paintColumnSelectionGridLayout->addWidget(commentPushButton, i + 1, 2, Qt::AlignHCenter); // // metadata push button // QToolButton* metaDataPushButton = new QToolButton; metaDataPushButton->setText("M"); metaDataPushButton->setToolTip("Press the button to set the\n" "metadata link for this column"); //metaDataPushButton->setFixedWidth(40); //metaDataPushButton->setAutoDefault(false); paintColumnMetaDataPushButtons.push_back(metaDataPushButton); paintColumnMetaDataButtonGroup->addButton(metaDataPushButton, i); paintColumnSelectionGridLayout->addWidget(metaDataPushButton, i + 1, 3, Qt::AlignHCenter); // // Name line edit // QLineEdit* le = new QLineEdit; le->setMinimumWidth(nameMinimumWidth); paintColumnNameLineEdits.push_back(le); QObject::connect(le, SIGNAL(returnPressed()), this, SLOT(readPaintColumnSelections())); paintColumnSelectionGridLayout->addWidget(le, i + 1, 4, Qt::AlignLeft); pagePaintColumnWidgetGroup->addWidget(rb); pagePaintColumnWidgetGroup->addWidget(le); } // // Update items already in the dialog // for (int i = 0; i < numValidPaints; i++) { paintColumnNameLabels[i]->show(); paintColumnRadioButtons[i]->show(); paintColumnCommentPushButtons[i]->show(); paintColumnMetaDataPushButtons[i]->show(); paintColumnNameLineEdits[i]->setText(pf->getColumnName(i)); paintColumnNameLineEdits[i]->home(true); paintColumnNameLineEdits[i]->show(); } // // Hide paints that are not needed // for (int i = numValidPaints; i < numExistingPaints; i++) { paintColumnNameLabels[i]->hide(); paintColumnRadioButtons[i]->hide(); paintColumnMetaDataPushButtons[i]->hide(); paintColumnCommentPushButtons[i]->hide(); paintColumnNameLineEdits[i]->hide(); } } /** * update paint overlay/underlay selection. */ void GuiDisplayControlDialog::updatePaintOverlayUnderlaySelection() { } /** * Update paint items in the dialog. */ void GuiDisplayControlDialog::updatePaintItems() { updatePageSelectionComboBox(); updatePaintOverlayUnderlaySelection(); updatePaintMainPage(); updatePaintColumnPage(); updatePaintNamePage(); } /** * update paint main page. */ void GuiDisplayControlDialog::updatePaintMainPage() { if (pagePaintMain != NULL) { DisplaySettingsPaint* dsp = theMainWindow->getBrainSet()->getDisplaySettingsPaint(); pagePaintMainWidgetGroup->blockSignals(true); paintMedWallCheckBox->setChecked(dsp->getMedialWallOverrideColumnEnabled()); paintMedWallColumnComboBox->setEnabled(dsp->getMedialWallOverrideColumnEnabled()); paintMedWallColumnComboBox->updateComboBox(theMainWindow->getBrainSet()->getPaintFile()); paintMedWallColumnComboBox->setCurrentIndex(dsp->getMedialWallOverrideColumn()); geographyBlendingDoubleSpinBox->setValue(dsp->getGeographyBlending()); pagePaintMainWidgetGroup->blockSignals(false); } } /** * read paint main page. */ void GuiDisplayControlDialog::readPaintMainPageSelections() { DisplaySettingsPaint* dsp = theMainWindow->getBrainSet()->getDisplaySettingsPaint(); dsp->setGeographyBlending(geographyBlendingDoubleSpinBox->value()); dsp->setMedialWallOverrideColumnEnabled(paintMedWallCheckBox->isChecked()); dsp->setMedialWallOverrideColumn(paintMedWallColumnComboBox->currentIndex()); paintMedWallColumnComboBox->setEnabled(dsp->getMedialWallOverrideColumnEnabled()); theMainWindow->getBrainSet()->getNodeColoring()->assignColors(); GuiBrainModelOpenGL::updateAllGL(NULL); } /** * update paint name page. */ void GuiDisplayControlDialog::updatePaintNamePage() { if (pagePaintName == NULL) { return; } createAndUpdatePaintNamePage(); } /** * update paint column name page. */ void GuiDisplayControlDialog::updatePaintColumnPage() { if (pagePaintColumn == NULL) { return; } createAndUpdatePaintColumnPage(); pagePaintColumnWidgetGroup->blockSignals(true); DisplaySettingsPaint* dsp = theMainWindow->getBrainSet()->getDisplaySettingsPaint(); paintApplySelectionToLeftAndRightStructuresFlagCheckBox->blockSignals(true); paintApplySelectionToLeftAndRightStructuresFlagCheckBox->setChecked(dsp->getApplySelectionToLeftAndRightStructuresFlag()); paintApplySelectionToLeftAndRightStructuresFlagCheckBox->blockSignals(false); PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); if (pf->getNumberOfColumns() > 0) { const int selCol = dsp->getSelectedDisplayColumn(surfaceModelIndex, overlayNumberComboBox->currentIndex()); //if (pageOverlayUnderlaySurface != NULL) { // paintSelectionComboBox->setCurrentIndex(selCol); //} if ((selCol >= 0) && (selCol < paintColumnButtonGroup->buttons().count())) { QRadioButton* rb = dynamic_cast(paintColumnButtonGroup->button(selCol)); if (rb != NULL) { rb->setChecked(true); } } } if (paintColumnButtonGroup != NULL) { QRadioButton* rb = dynamic_cast( paintColumnButtonGroup->button( dsp->getSelectedDisplayColumn(surfaceModelIndex, overlayNumberComboBox->currentIndex()))); if (rb != NULL) { rb->setChecked(true); } } pagePaintColumn->setEnabled(validPaintData); pagePaintColumnWidgetGroup->blockSignals(false); } /** * called to read paint L-to-L, R-to-R. */ void GuiDisplayControlDialog::readPaintL2LR2R() { DisplaySettingsPaint* dsp = theMainWindow->getBrainSet()->getDisplaySettingsPaint(); dsp->setApplySelectionToLeftAndRightStructuresFlag(paintApplySelectionToLeftAndRightStructuresFlagCheckBox->isChecked()); theMainWindow->getBrainSet()->getNodeColoring()->assignColors(); GuiBrainModelOpenGL::updateAllGL(NULL); displayOverlayLeftToLeftRightToRightMessage(); } /** * called when paint name all on button is pressed. */ void GuiDisplayControlDialog::slotPaintNamesAllOnPushButton() { paintNameCheckBoxWidgetGroup->blockSignals(true); const int num = static_cast(paintNameCheckBoxes.size()); for (int i = 0; i < num; i++) { paintNameCheckBoxes[i]->setChecked(true); } paintNameCheckBoxWidgetGroup->blockSignals(false); readPaintNameSelections(); } /** * called when paint name all off button is pressed. */ void GuiDisplayControlDialog::slotPaintNamesAllOffPushButton() { paintNameCheckBoxWidgetGroup->blockSignals(true); const int num = static_cast(paintNameCheckBoxes.size()); for (int i = 0; i < num; i++) { paintNameCheckBoxes[i]->setChecked(false); } paintNameCheckBoxWidgetGroup->blockSignals(false); readPaintNameSelections(); } /** * called to read paint name items in the dialog. */ void GuiDisplayControlDialog::readPaintNameSelections() { if (creatingDialog) { return; } if (pagePaintName == NULL) { return; } PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); const int num = std::min(pf->getNumberOfPaintNames(), static_cast(paintNameCheckBoxes.size())); for (int i = 0; i < num; i++) { pf->setPaintNameEnabled(paintNameCheckBoxPaintFileNameIndices[i], paintNameCheckBoxes[i]->isChecked()); } theMainWindow->getBrainSet()->getNodeColoring()->assignColors(); GuiBrainModelOpenGL::updateAllGL(NULL); } /** * Read all paint items in the dialog. */ void GuiDisplayControlDialog::readPaintColumnSelections() { if (creatingDialog) { return; } if (pagePaintColumn != NULL) { PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); if (pf->getNumberOfColumns() > 0) { //pf->setSelectedColumn(paintButtonGroup->selectedId()); for (int i = 0; i < pf->getNumberOfColumns(); i++) { const QString name(paintColumnNameLineEdits[i]->text()); if (name != pf->getColumnName(i)) { pf->setColumnName(i, name); } } } updateSurfaceOverlayWidgets(); } GuiFilesModified fm; fm.setPaintModified(); theMainWindow->fileModificationUpdate(fm); theMainWindow->getBrainSet()->getNodeColoring()->assignColors(); GuiBrainModelOpenGL::updateAllGL(NULL); } /** * Called to display comment information about a paint column. */ void GuiDisplayControlDialog::paintCommentColumnSelection(int column) { PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); if ((column >= 0) && (column < pf->getNumberOfColumns())) { GuiDataFileCommentDialog* dfcd = new GuiDataFileCommentDialog(theMainWindow, pf, column); dfcd->show(); } } /** * Page containing images. */ void GuiDisplayControlDialog::createImagesPage() { pageImages = new QWidget; pageWidgetStack->addWidget(pageImages); //, PAGE_NAME_IMAGES); // adds to dialog QVBoxLayout* imagesPageLayout = new QVBoxLayout(pageImages); showImageInMainWindowCheckBox = new QCheckBox("Show Image in Main Window"); imagesPageLayout->addWidget(showImageInMainWindowCheckBox); QObject::connect(showImageInMainWindowCheckBox, SIGNAL(toggled(bool)), this, SLOT(readImagesSelections())); QWidget* imagesWidget = new QWidget; imagesPageLayout->addWidget(imagesWidget); QVBoxLayout* imageWidgetLayout = new QVBoxLayout(imagesWidget); imagesLayout = new QVBoxLayout; imageWidgetLayout->addLayout(imagesLayout); imageWidgetLayout->addStretch(100); // pushes images radio buttons to the top imagesButtonGroup = new QButtonGroup(this); //("Images", imageSelectionScrollView); QObject::connect(imagesButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(readImagesSelections())); } /** * Update all image items in the dialog. */ void GuiDisplayControlDialog::updateImagesItems() { updatePageSelectionComboBox(); if (pageImages == NULL) { return; } DisplaySettingsImages* dsi = theMainWindow->getBrainSet()->getDisplaySettingsImages(); const int numImages = theMainWindow->getBrainSet()->getNumberOfImageFiles(); showImageInMainWindowCheckBox->blockSignals(true); showImageInMainWindowCheckBox->setChecked(dsi->getShowImageInMainWindow()); showImageInMainWindowCheckBox->blockSignals(false); // // Update already created radio buttons // int numRadioButtons = static_cast(imagesRadioButtons.size()); for (int i = 0; i < numRadioButtons; i++) { if (i < numImages) { const ImageFile* img = theMainWindow->getBrainSet()->getImageFile(i); const QString name(FileUtilities::basename(img->getFileName())); imagesRadioButtons[i]->setText(name); } } // // Create new radio buttons // for (int i = numRadioButtons; i < numImages; i++) { const ImageFile* img = theMainWindow->getBrainSet()->getImageFile(i); const QString name(FileUtilities::basename(img->getFileName())); QRadioButton* butt = new QRadioButton(name); imagesLayout->addWidget(butt); imagesButtonGroup->addButton(butt, i); imagesRadioButtons.push_back(butt); } // // Hide unneeded radio buttons // numRadioButtons = static_cast(imagesRadioButtons.size()); for (int i = 0; i < numRadioButtons; i++) { if (i < numImages) { imagesRadioButtons[i]->show(); } else { imagesRadioButtons[i]->hide(); } } if (numImages > 0) { imagesButtonGroup->blockSignals(true); //imagesButtonGroup->setButton(dsi->getMainWindowImageNumber()); int imageNum = dsi->getMainWindowImageNumber(); if (imageNum <= 0) { imageNum = 0; } if (imageNum < static_cast(imagesRadioButtons.size())) { imagesRadioButtons[imageNum]->setChecked(true); } imagesButtonGroup->blockSignals(false); } pageImages->setEnabled(validImageData); } /** * Read all images items in the dialog. */ void GuiDisplayControlDialog::readImagesSelections() { if (creatingDialog) { return; } DisplaySettingsImages* dsi = theMainWindow->getBrainSet()->getDisplaySettingsImages(); dsi->setMainWindowImageNumber(imagesButtonGroup->checkedId()); dsi->setShowImageInMainWindow(showImageInMainWindowCheckBox->isChecked()); GuiBrainModelOpenGL::updateAllGL(); } /** * Create the main page for models. */ void GuiDisplayControlDialog::createModelsMainPage() { // // Vertical Box Layout for all selection items // pageModelsMain = new QWidget; modelsSubPageMainLayout = new QVBoxLayout(pageModelsMain); // // All On/Off buttons // QPushButton* allOnPushButton = new QPushButton("All On"); allOnPushButton->setAutoDefault(false); QObject::connect(allOnPushButton, SIGNAL(clicked()), this, SLOT(slotModelsAllOn())); QPushButton* allOffPushButton = new QPushButton("All Off"); allOffPushButton->setAutoDefault(false); QObject::connect(allOffPushButton, SIGNAL(clicked()), this, SLOT(slotModelsAllOff())); QHBoxLayout* allOnOffLayout = new QHBoxLayout; allOnOffLayout->addWidget(allOnPushButton); allOnOffLayout->addWidget(allOffPushButton); allOnOffLayout->addStretch(); modelsSubPageMainLayout->addLayout(allOnOffLayout); createAndUpdateModelsMainPage(); pageWidgetStack->addWidget(pageModelsMain); } /** * create and update the models main page as models added/deleted */ void GuiDisplayControlDialog::createAndUpdateModelsMainPage() { numValidModels = theMainWindow->getBrainSet()->getNumberOfVtkModelFiles(); const int numExistingModels = static_cast(modelCheckBoxes.size()); if (modelSelectionGridWidgetLayout == NULL) { QWidget* modelsWidget = new QWidget; modelSelectionGridWidgetLayout = new QGridLayout(modelsWidget); modelSelectionGridWidgetLayout->addWidget(new QLabel("Model"), 0, 0); modelSelectionGridWidgetLayout->addWidget(new QLabel(" Transform"), 0, 1); modelSelectionGridWidgetLayout->addWidget(new QLabel(""), 0, 2); const int rowStretchNumber = 15000; modelSelectionGridWidgetLayout->addWidget(new QLabel(""), rowStretchNumber, 0); modelSelectionGridWidgetLayout->setRowStretch(rowStretchNumber, 1000); modelSelectionGridWidgetLayout->setColumnStretch(0, 1); modelSelectionGridWidgetLayout->setColumnStretch(1, 1); modelSelectionGridWidgetLayout->setColumnStretch(2, 100); modelsSubPageMainLayout->addWidget(modelsWidget); } // // Add row of checkbox and transform matrix selection // for (int i = numExistingModels; i < numValidModels; i++) { QCheckBox* cb = new QCheckBox("adding"); modelCheckBoxes.push_back(cb); QObject::connect(cb, SIGNAL(toggled(bool)), this, SLOT(readModelMainPage())); GuiTransformationMatrixSelectionControl* msc = new GuiTransformationMatrixSelectionControl(0, theMainWindow->getBrainSet()->getTransformationMatrixFile(), true); const VtkModelFile* vmf = theMainWindow->getBrainSet()->getVtkModelFile(i); const TransformationMatrix* tm = vmf->getAssociatedTransformationMatrix(); msc->setSelectedMatrix(tm); modelTransformControls.push_back(msc); QObject::connect(msc, SIGNAL(activated(int)), this, SLOT(readModelMainPage())); modelSelectionGridWidgetLayout->addWidget(cb, i + 1, 0, 1, 1, Qt::AlignLeft); modelSelectionGridWidgetLayout->addWidget(msc, i + 1, 1, 1, 1, Qt::AlignLeft); } // // update items already in dialog // TransformationMatrixFile* tmf = theMainWindow->getBrainSet()->getTransformationMatrixFile(); for (int i = 0; i < numValidModels; i++) { VtkModelFile* vmf = theMainWindow->getBrainSet()->getVtkModelFile(i); const TransformationMatrix* tm = vmf->getAssociatedTransformationMatrix(); const QString name(FileUtilities::basename( FileUtilities::filenameWithoutExtension(vmf->getFileName()))); modelCheckBoxes[i]->blockSignals(true); modelCheckBoxes[i]->setText(name); modelCheckBoxes[i]->show(); modelCheckBoxes[i]->setChecked(vmf->getDisplayFlag()); modelCheckBoxes[i]->blockSignals(false); modelTransformControls[i]->blockSignals(true); modelTransformControls[i]->updateControl(); modelTransformControls[i]->setSelectedMatrixIndex(tmf->getMatrixIndex(tm)); modelTransformControls[i]->show(); modelTransformControls[i]->blockSignals(false); } // // Hide widgets that are not needed // for (int i = numValidModels; i < numExistingModels; i++) { modelCheckBoxes[i]->hide(); modelTransformControls[i]->hide(); } } /** * Create the settings page for models. */ void GuiDisplayControlDialog::createModelsSettingsPage() { QLabel* opacityLabel = new QLabel("Opacity "); modelsOpacityDoubleSpinBox = new QDoubleSpinBox; modelsOpacityDoubleSpinBox->setMinimum(0.0); modelsOpacityDoubleSpinBox->setMaximum(1.0); modelsOpacityDoubleSpinBox->setSingleStep(0.1); modelsOpacityDoubleSpinBox->setDecimals(2); QObject::connect(modelsOpacityDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readModelSettingsPage())); QLabel* lineSizeLabel = new QLabel("Line Size "); modelsLineSizeDoubleSpinBox = new QDoubleSpinBox; modelsLineSizeDoubleSpinBox->setMinimum(minLineSize); modelsLineSizeDoubleSpinBox->setMaximum(maxLineSize); modelsLineSizeDoubleSpinBox->setSingleStep(0.1); modelsLineSizeDoubleSpinBox->setDecimals(1); QObject::connect(modelsLineSizeDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readModelSettingsPage())); QLabel* vertexSizeLabel = new QLabel("Vertex Size"); modelsVertexSizeDoubleSpinBox = new QDoubleSpinBox; modelsVertexSizeDoubleSpinBox->setMinimum(0.1); modelsVertexSizeDoubleSpinBox->setMaximum(50.0); modelsVertexSizeDoubleSpinBox->setSingleStep(0.1); modelsVertexSizeDoubleSpinBox->setDecimals(1); QObject::connect(modelsVertexSizeDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readModelSettingsPage())); // // Grid for size controls // QWidget* sizeWidget = new QWidget; QGridLayout* sizeLayout = new QGridLayout(sizeWidget); sizeLayout->addWidget(opacityLabel, 0, 0); sizeLayout->addWidget(modelsOpacityDoubleSpinBox, 0, 1); sizeLayout->addWidget(lineSizeLabel, 1, 0); sizeLayout->addWidget(modelsLineSizeDoubleSpinBox, 1, 1); sizeLayout->addWidget(vertexSizeLabel, 2, 0); sizeLayout->addWidget(modelsVertexSizeDoubleSpinBox, 2, 1); sizeWidget->setFixedSize(sizeWidget->sizeHint()); modelLinesLightingCheckBox = new QCheckBox("Light Lines"); QObject::connect(modelLinesLightingCheckBox, SIGNAL(toggled(bool)), this, SLOT(readModelSettingsPage())); modelPolygonsLightingCheckBox = new QCheckBox("Light Polygons"); QObject::connect(modelPolygonsLightingCheckBox, SIGNAL(toggled(bool)), this, SLOT(readModelSettingsPage())); modelVerticesLightingCheckBox = new QCheckBox("Light Vertices"); QObject::connect(modelVerticesLightingCheckBox, SIGNAL(toggled(bool)), this, SLOT(readModelSettingsPage())); // // Checkboxes for showing attributes of models // modelShowPolygonsCheckBox = new QCheckBox("Show Polygons"); QObject::connect(modelShowPolygonsCheckBox, SIGNAL(toggled(bool)), this, SLOT(readModelSettingsPage())); modelShowTrianglesCheckBox = new QCheckBox("Show Triangles"); QObject::connect(modelShowTrianglesCheckBox, SIGNAL(toggled(bool)), this, SLOT(readModelSettingsPage())); modelShowLinesCheckBox = new QCheckBox("Show Lines"); QObject::connect(modelShowLinesCheckBox, SIGNAL(toggled(bool)), this, SLOT(readModelSettingsPage())); modelShowVerticesCheckBox = new QCheckBox("Show Vertices"); QObject::connect(modelShowVerticesCheckBox, SIGNAL(toggled(bool)), this, SLOT(readModelSettingsPage())); // // Page and layouts // pageModelsSettings = new QWidget; QVBoxLayout* modelSettingsLayout = new QVBoxLayout(pageModelsSettings); modelSettingsLayout->addWidget(modelShowPolygonsCheckBox); modelSettingsLayout->addWidget(modelShowTrianglesCheckBox); modelSettingsLayout->addWidget(modelShowLinesCheckBox); modelSettingsLayout->addWidget(modelShowVerticesCheckBox); modelSettingsLayout->addWidget(sizeWidget, 0, Qt::AlignLeft); modelSettingsLayout->addWidget(modelLinesLightingCheckBox); modelSettingsLayout->addWidget(modelPolygonsLightingCheckBox); modelSettingsLayout->addWidget(modelVerticesLightingCheckBox); modelSettingsLayout->addStretch(); pageWidgetStack->addWidget(pageModelsSettings); modelSettingsWidgetGroup = new WuQWidgetGroup(this); modelSettingsWidgetGroup->addWidget(modelsOpacityDoubleSpinBox); modelSettingsWidgetGroup->addWidget(modelsLineSizeDoubleSpinBox); modelSettingsWidgetGroup->addWidget(modelsVertexSizeDoubleSpinBox); modelSettingsWidgetGroup->addWidget(modelLinesLightingCheckBox); modelSettingsWidgetGroup->addWidget(modelPolygonsLightingCheckBox); modelSettingsWidgetGroup->addWidget(modelVerticesLightingCheckBox); modelSettingsWidgetGroup->addWidget(modelShowPolygonsCheckBox); modelSettingsWidgetGroup->addWidget(modelShowTrianglesCheckBox); modelSettingsWidgetGroup->addWidget(modelShowLinesCheckBox); modelSettingsWidgetGroup->addWidget(modelShowVerticesCheckBox); } /** * update model main page. */ void GuiDisplayControlDialog::updateModelMainPage() { if (pageModelsMain == NULL) { return; } createAndUpdateModelsMainPage(); pageModelsMain->setEnabled(validModelData); } /** * update model settings page. */ void GuiDisplayControlDialog::updateModelSettingsPage() { if (pageModelsSettings == NULL) { return; } modelSettingsWidgetGroup->blockSignals(true); DisplaySettingsModels* dsm = theMainWindow->getBrainSet()->getDisplaySettingsModels(); modelsOpacityDoubleSpinBox->setValue(dsm->getOpacity()); modelsLineSizeDoubleSpinBox->setValue(dsm->getLineWidth()); modelsVertexSizeDoubleSpinBox->setValue(dsm->getVertexSize()); modelLinesLightingCheckBox->setChecked(dsm->getLightLinesEnabled()); modelPolygonsLightingCheckBox->setChecked(dsm->getLightPolygonsEnabled()); modelVerticesLightingCheckBox->setChecked(dsm->getLightVerticesEnabled()); modelShowPolygonsCheckBox->setChecked(dsm->getShowPolygons()); modelShowTrianglesCheckBox->setChecked(dsm->getShowTriangles()); modelShowLinesCheckBox->setChecked(dsm->getShowLines()); modelShowVerticesCheckBox->setChecked(dsm->getShowVertices()); pageModelsSettings->setEnabled(validModelData); modelSettingsWidgetGroup->blockSignals(false); } /** * Update all model items in the dialog. */ void GuiDisplayControlDialog::updateModelItems() { updatePageSelectionComboBox(); updateModelMainPage(); updateModelSettingsPage(); updatePageSelectionComboBox(); } /** * called to read model main page items from dialog. */ void GuiDisplayControlDialog::readModelMainPage() { if (pageModelsMain == NULL) { return; } if (creatingDialog) { return; } int numModels = theMainWindow->getBrainSet()->getNumberOfVtkModelFiles(); if (numModels != numValidModels) { std::cout << "PROGRAM ERROR at " << __LINE__ << " in " << __FILE__ << ". " << "Model number mismatch." << std::endl; numModels = std::min(numModels, numValidModels); } TransformationMatrixFile* tmf = theMainWindow->getBrainSet()->getTransformationMatrixFile(); for (int i = 0; i < numModels; i++) { VtkModelFile* vmf = theMainWindow->getBrainSet()->getVtkModelFile(i); vmf->setDisplayFlag(modelCheckBoxes[i]->isChecked()); const int matrixIndex = modelTransformControls[i]->getSelectedMatrixIndex(); vmf->setAssociatedTransformationMatrix(tmf->getTransformationMatrix(matrixIndex)); } GuiBrainModelOpenGL::updateAllGL(); } /** * called to read model main page items from dialog. */ void GuiDisplayControlDialog::readModelSettingsPage() { if (pageModelsSettings == NULL) { return; } if (creatingDialog) { return; } DisplaySettingsModels* dsm = theMainWindow->getBrainSet()->getDisplaySettingsModels(); dsm->setOpacity(modelsOpacityDoubleSpinBox->value()); dsm->setLineWidth(modelsLineSizeDoubleSpinBox->value()); dsm->setVertexSize(modelsVertexSizeDoubleSpinBox->value()); dsm->setLightLinesEnabled(modelLinesLightingCheckBox->isChecked()); dsm->setLightPolygonsEnabled(modelPolygonsLightingCheckBox->isChecked()); dsm->setLightVerticesEnabled(modelVerticesLightingCheckBox->isChecked()); dsm->setShowPolygons(modelShowPolygonsCheckBox->isChecked()); dsm->setShowTriangles(modelShowTrianglesCheckBox->isChecked()); dsm->setShowLines(modelShowLinesCheckBox->isChecked()); dsm->setShowVertices(modelShowVerticesCheckBox->isChecked()); GuiBrainModelOpenGL::updateAllGL(); } /** * called when all models on pushbutton pressed. */ void GuiDisplayControlDialog::slotModelsAllOn() { for (int i = 0; i < static_cast(modelCheckBoxes.size()); i++) { modelCheckBoxes[i]->setChecked(true); } readModelMainPage(); } /** * called when all models off pushbutton pressed. */ void GuiDisplayControlDialog::slotModelsAllOff() { for (int i = 0; i < static_cast(modelCheckBoxes.size()); i++) { modelCheckBoxes[i]->setChecked(false); } readModelMainPage(); } /** * Create the metric selections page. */ void GuiDisplayControlDialog::createMetricSelectionPage() { // // Vertical Box Layout for all selection items // pageMetricSelection = new QWidget; createAndUpdateMetricSelectionPage(); pageWidgetStack->addWidget(pageMetricSelection); } /** * Create and update metric selections. Because the number of metrics may change, * this method may update and change the labels on existing checkboxes, add new * checkboxes, and hide existing checkboxes. */ void GuiDisplayControlDialog::createAndUpdateMetricSelectionPage() { MetricFile* mf = theMainWindow->getBrainSet()->getMetricFile(); numValidMetrics = mf->getNumberOfColumns(); const int numExistingMetrics = static_cast(metricViewRadioButtons.size()); const int nameMinimumWidth = 500; if (metricSubPageSelectionsLayout == NULL) { // // Grid layout for metric selections // QWidget* metricSelectionGridWidget = new QWidget; metricSelectionGridLayout = new QGridLayout(metricSelectionGridWidget); metricSelectionGridLayout->setSpacing(3); metricSelectionGridLayout->setColumnMinimumWidth(6, nameMinimumWidth+20); metricSelectionGridLayout->addWidget(new QLabel("#"), 0, 0, Qt::AlignRight); metricSelectionGridLayout->addWidget(new QLabel("View"), 0, 1, Qt::AlignHCenter); metricSelectionGridLayout->addWidget(new QLabel("Thresh"), 0, 2, Qt::AlignHCenter); metricSelectionGridLayout->addWidget(new QLabel("Cmt"), 0, 3, Qt::AlignHCenter); metricSelectionGridLayout->addWidget(new QLabel("MD"), 0, 4, Qt::AlignHCenter); metricSelectionGridLayout->addWidget(new QLabel("Hist"), 0, 5, Qt::AlignHCenter); metricSelectionGridLayout->addWidget(new QLabel("Name"), 0, 6, Qt::AlignLeft); // // For stretching on bottom // //const int rowStretchNumber = 15000; //metricSelectionGridLayout->addWidget(new QLabel(""), // rowStretchNumber, 5, 1, 1, Qt::AlignLeft); // // Only allow the name column to stretch // metricSelectionGridLayout->setColumnStretch(0, 0); metricSelectionGridLayout->setColumnStretch(1, 0); metricSelectionGridLayout->setColumnStretch(2, 0); metricSelectionGridLayout->setColumnStretch(3, 0); metricSelectionGridLayout->setColumnStretch(4, 0); metricSelectionGridLayout->setColumnStretch(5, 0); metricSelectionGridLayout->setColumnStretch(6, 0); //metricSelectionGridLayout->setRowStretch(rowStretchNumber, 1000); // // Create the metric selections layout and push selections to the left // metricSubPageSelectionsLayout = new QVBoxLayout(pageMetricSelection); metricSubPageSelectionsLayout->addWidget(metricSelectionGridWidget, 100, Qt::AlignLeft | Qt::AlignTop); } // // Create the button group for the metric view buttons. // if (metricViewButtonGroup == NULL) { metricViewButtonGroup = new QButtonGroup(this); metricViewButtonGroup->setExclusive(true); QObject::connect(metricViewButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(metricDisplayColumnSelection(int))); } // // Create the button group for the metric threshold buttons. // if (metricThresholdButtonGroup == NULL) { metricThresholdButtonGroup = new QButtonGroup(this); metricThresholdButtonGroup->setExclusive(true); QObject::connect(metricThresholdButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(metricThresholdColumnSelection(int))); } // // Create the button group for the metric comment buttons. // if (metricCommentButtonGroup == NULL) { metricCommentButtonGroup = new QButtonGroup(this); QObject::connect(metricCommentButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(metricCommentColumnSelection(int))); } // // Create the button group for the metric metadata buttons. // if (metricMetaDataButtonGroup == NULL) { metricMetaDataButtonGroup = new QButtonGroup(this); QObject::connect(metricMetaDataButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(metricMetaDataColumnSelection(int))); } // // Create the button group for the metric histogram buttons // if (metricHistogramButtonGroup == NULL) { metricHistogramButtonGroup = new QButtonGroup(this); QObject::connect(metricHistogramButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(metricHistogramColumnSelection(int))); } // // Add new widgets as needed // for (int i = numExistingMetrics; i < numValidMetrics; i++) { // // Column number // QLabel* columnNumberLabel = new QLabel(QString::number(i + 1)); metricColumnNumberLabels.push_back(columnNumberLabel); metricSelectionGridLayout->addWidget(columnNumberLabel, i + 1, 0, Qt::AlignRight); // // View radio button // QRadioButton* viewRadioButton = new QRadioButton(""); metricViewRadioButtons.push_back(viewRadioButton); metricViewButtonGroup->addButton(viewRadioButton, i); metricSelectionGridLayout->addWidget(viewRadioButton, i + 1, 1, Qt::AlignHCenter); // // Threshold radio button // QRadioButton* threshRadioButton = new QRadioButton(""); metricThresholdRadioButtons.push_back(threshRadioButton); metricThresholdButtonGroup->addButton(threshRadioButton, i); metricSelectionGridLayout->addWidget(threshRadioButton, i + 1, 2, Qt::AlignHCenter); // // Comment push button // QToolButton* commentPushButton = new QToolButton; commentPushButton->setText("?"); //commentPushButton->setFixedWidth(40); //commentPushButton->setAutoDefault(false); metricColumnCommentPushButtons.push_back(commentPushButton); metricCommentButtonGroup->addButton(commentPushButton, i); metricSelectionGridLayout->addWidget(commentPushButton, i + 1, 3, Qt::AlignHCenter); // // Metadata push button // QToolButton* metaDataPushButton = new QToolButton; metaDataPushButton->setText("M"); metaDataPushButton->setToolTip("Press the button to set the\n" "metadata link for this column"); //metaDataPushButton->setFixedWidth(40); //metaDataPushButton->setAutoDefault(false); metricColumnMetaDataPushButtons.push_back(metaDataPushButton); metricMetaDataButtonGroup->addButton(metaDataPushButton, i); metricSelectionGridLayout->addWidget(metaDataPushButton, i + 1, 4, Qt::AlignHCenter); // // Histogram push button QToolButton* histogramPushButton = new QToolButton; histogramPushButton->setText("H"); histogramPushButton->setToolTip("Press the button to view \n" "a histogram of this metric\n" "column's data."); metricColumnHistogramPushButtons.push_back(histogramPushButton); metricHistogramButtonGroup->addButton(histogramPushButton, i); metricSelectionGridLayout->addWidget(histogramPushButton, i + 1, 5, Qt::AlignHCenter); // // // Name line edit // QLineEdit* metricLineEdit = new QLineEdit; metricLineEdit->setText(mf->getColumnName(i)); metricLineEdit->setMinimumWidth(nameMinimumWidth); metricColumnNameLineEdits.push_back(metricLineEdit); metricSelectionGridLayout->addWidget(metricLineEdit, i + 1, 6, Qt::AlignLeft); } // // Show and update all valid metrics // for (int i = 0; i < numValidMetrics; i++) { metricColumnNameLineEdits[i]->setText(mf->getColumnName(i)); metricColumnNumberLabels[i]->show(); metricViewRadioButtons[i]->show(); metricThresholdRadioButtons[i]->show(); metricColumnCommentPushButtons[i]->show(); metricColumnMetaDataPushButtons[i]->show(); metricColumnHistogramPushButtons[i]->show(); metricColumnNameLineEdits[i]->show(); metricColumnNameLineEdits[i]->home(true); } // // Hide widgets that are not needed // for (int i = numValidMetrics; i < numExistingMetrics; i++) { metricColumnNumberLabels[i]->hide(); metricViewRadioButtons[i]->hide(); metricThresholdRadioButtons[i]->hide(); metricColumnCommentPushButtons[i]->hide(); metricColumnMetaDataPushButtons[i]->hide(); metricColumnHistogramPushButtons[i]->hide(); metricColumnNameLineEdits[i]->hide(); } if (numValidMetrics > 0) { if (DebugControl::getDebugOn()) { std::cout << " " << std::endl; std::cout << "Metric created " << std::endl; std::cout << " " << std::endl; } } } /** * update the metric misc page. */ void GuiDisplayControlDialog::updateMetricMiscellaneousPage() { if (pageMetricMiscellaneous == NULL) { return; } updatingMetricMiscPageFlag = true; DisplaySettingsMetric* dsm = theMainWindow->getBrainSet()->getDisplaySettingsMetric(); metricGraphPopupComboBox->setCurrentIndex(dsm->getMDataPlotOnNodeID()); float manMin, manMax; const bool manFlag = dsm->getDataPlotManualScaling(manMin, manMax); metricGraphManualScaleCheckBox->setChecked(manFlag); metricGraphManualScaleMinDoubleSpinBox->setValue(manMin); metricGraphManualScaleMaxDoubleSpinBox->setValue(manMax); updatingMetricMiscPageFlag = false; } /** * read the metric misc page. */ void GuiDisplayControlDialog::readMetricMiscellaneousPage() { if (pageMetricMiscellaneous == NULL) { return; } if (updatingMetricMiscPageFlag) { return; } DisplaySettingsMetric* dsm = theMainWindow->getBrainSet()->getDisplaySettingsMetric(); dsm->setDataPlotOnNodeID(static_cast( metricGraphPopupComboBox->currentIndex())); dsm->setDataPlotManualScaling(metricGraphManualScaleCheckBox->isChecked(), metricGraphManualScaleMinDoubleSpinBox->value(), metricGraphManualScaleMaxDoubleSpinBox->value()); } /** * create the metric miscellaneous page. */ void GuiDisplayControlDialog::createMetricMiscellaneousPage() { updatingMetricMiscPageFlag = true; // // Animation section // QPushButton* animatePushButton = new QPushButton("Animate"); animatePushButton->setAutoDefault(false); animatePushButton->setFixedSize(animatePushButton->sizeHint()); QObject::connect(animatePushButton, SIGNAL(clicked()), this, SLOT(metricAnimatePushButtonSelection())); QLabel* animateLabel = new QLabel(" Interpolate Frames "); metricAnimateSpinBox = new QSpinBox; metricAnimateSpinBox->setMinimum(0); metricAnimateSpinBox->setMaximum(1000); metricAnimateSpinBox->setSingleStep(1); QGroupBox* animateGroupBox = new QGroupBox("Animation"); QHBoxLayout* animageGroupLayout = new QHBoxLayout(animateGroupBox); animageGroupLayout->addWidget(animatePushButton); animageGroupLayout->addWidget(animateLabel); animageGroupLayout->addWidget(metricAnimateSpinBox); animateGroupBox->setFixedSize(animateGroupBox->sizeHint()); // // Popup graph when node identified // QLabel* popupGraphLabel = new QLabel("Show"); metricGraphPopupComboBox = new QComboBox; metricGraphPopupComboBox->insertItem(DisplaySettingsMetric::METRIC_DATA_PLOT_OFF, "Off"); metricGraphPopupComboBox->insertItem(DisplaySettingsMetric::METRIC_DATA_PLOT_NODE, "Node"); metricGraphPopupComboBox->insertItem(DisplaySettingsMetric::METRIC_DATA_PLOT_NODE_AND_NEIGHBORS, "Node and Neighbors"); QObject::connect(metricGraphPopupComboBox, SIGNAL(activated(int)), this, SLOT(readMetricMiscellaneousPage())); metricGraphManualScaleCheckBox = new QCheckBox("Manual Scaling "); QObject::connect(metricGraphManualScaleCheckBox, SIGNAL(toggled(bool)), this, SLOT(readMetricMiscellaneousPage())); const float big = 10000.0; metricGraphManualScaleMinDoubleSpinBox = new QDoubleSpinBox; metricGraphManualScaleMinDoubleSpinBox->setMinimum(-big); metricGraphManualScaleMinDoubleSpinBox->setMaximum(big); metricGraphManualScaleMinDoubleSpinBox->setSingleStep(1.0); metricGraphManualScaleMinDoubleSpinBox->setDecimals(3); QObject::connect(metricGraphManualScaleMinDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readMetricMiscellaneousPage())); metricGraphManualScaleMaxDoubleSpinBox = new QDoubleSpinBox; metricGraphManualScaleMaxDoubleSpinBox->setMinimum(-big); metricGraphManualScaleMaxDoubleSpinBox->setMaximum(big); metricGraphManualScaleMaxDoubleSpinBox->setSingleStep(1.0); metricGraphManualScaleMaxDoubleSpinBox->setDecimals(3); QObject::connect(metricGraphManualScaleMaxDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readMetricMiscellaneousPage())); QHBoxLayout* popupGraphShowLayout = new QHBoxLayout; popupGraphShowLayout->addWidget(popupGraphLabel); popupGraphShowLayout->addWidget(metricGraphPopupComboBox); popupGraphShowLayout->addStretch(); QHBoxLayout* popupGraphScaleLayout = new QHBoxLayout; popupGraphScaleLayout->addWidget(metricGraphManualScaleCheckBox); popupGraphScaleLayout->addWidget(metricGraphManualScaleMinDoubleSpinBox); popupGraphScaleLayout->addWidget(metricGraphManualScaleMaxDoubleSpinBox); popupGraphScaleLayout->addStretch(); QGroupBox* popupGraphGroup = new QGroupBox("Popup Graph When Node Identified"); QVBoxLayout* popupGraphLayout = new QVBoxLayout(popupGraphGroup); popupGraphLayout->addLayout(popupGraphShowLayout); popupGraphLayout->addLayout(popupGraphScaleLayout); popupGraphGroup->setFixedSize(popupGraphGroup->sizeHint()); std::vector surfaceTypes; std::vector surfaceNames; BrainModelSurface::getSurfaceTypesAndNames(surfaceTypes, surfaceNames); // // Metric misc page and layout // pageMetricMiscellaneous = new QWidget; pageWidgetStack->addWidget(pageMetricMiscellaneous); QVBoxLayout* pageMetricMiscLayout = new QVBoxLayout(pageMetricMiscellaneous); pageMetricMiscLayout->addWidget(animateGroupBox); pageMetricMiscLayout->addWidget(popupGraphGroup); pageMetricMiscLayout->addStretch(); pageMetricSettingsWidgetGroup = new WuQWidgetGroup(this); pageMetricSettingsWidgetGroup->addWidget(metricGraphPopupComboBox); pageMetricSettingsWidgetGroup->addWidget(metricGraphManualScaleMinDoubleSpinBox); pageMetricSettingsWidgetGroup->addWidget(metricGraphManualScaleMaxDoubleSpinBox); updatingMetricMiscPageFlag = false; } /** * Page containing metric control. */ void GuiDisplayControlDialog::createMetricSettingsPage() { const int floatSpinBoxWidth = 120; // // Color Mapping // QButtonGroup* scaleButtonGroup = new QButtonGroup(this); QObject::connect(scaleButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(readMetricSettingsPage())); metricFileAutoScaleRadioButton = new QRadioButton("Auto Scale"); metricFileAutoScaleRadioButton->setToolTip( "This selection will map the most negative\n" "and positive values in the view metric to \n" "the -1.0 and 1.0 values in the selected \n" "palette. If you are displaying multiple \n" "metrics on a surface, identical colors will \n" "not represent identical values in the \n" "multiple metrics displayed. For identical \n" "colors to represent identical values in \n" "different metrics, switch to \"Auto Scale - \n" "Metric Column\"."); scaleButtonGroup->addButton(metricFileAutoScaleRadioButton, DisplaySettingsMetric::METRIC_OVERLAY_SCALE_AUTO); metricFileAutoScalePercentageRadioButton = new QRadioButton("Auto Scale - Percentage"); metricFileAutoScalePercentageRadioButton->setToolTip(""); scaleButtonGroup->addButton(metricFileAutoScalePercentageRadioButton); metricFileAutoScaleSpecifiedColumnRadioButton = new QRadioButton("Auto Scale - Metric Column"); metricFileAutoScaleSpecifiedColumnRadioButton->setToolTip( "This selection will map the most negative\n" "and positive values in the selected metric\n" "column to the -1.0 and 1.0 values in the\n" "selected palette. If multiple metrics are \n" "displayed, identical colors represent \n" "identical values."); scaleButtonGroup->addButton(metricFileAutoScaleSpecifiedColumnRadioButton, DisplaySettingsMetric::METRIC_OVERLAY_SCALE_AUTO_SPECIFIED_COLUMN); metricFileAutoScaleSpecifiedColumnSelectionComboBox = new GuiNodeAttributeColumnSelectionComboBox(GUI_NODE_FILE_TYPE_METRIC, false, false, false); QObject::connect(metricFileAutoScaleSpecifiedColumnSelectionComboBox, SIGNAL(itemSelected(int)), this, SLOT(readMetricSettingsPage())); metricFuncVolumeAutoScaleRadioButton = new QRadioButton("Auto Scale - Functional Volume"); metricFuncVolumeAutoScaleRadioButton->setToolTip( "This selection will map the most negative\n" "and positive values in the selected functional\n" "volume to the -1.0 and 1.0 values in the\n" "selected palette."); scaleButtonGroup->addButton(metricFuncVolumeAutoScaleRadioButton, DisplaySettingsMetric::METRIC_OVERLAY_SCALE_AUTO_FUNC_VOLUME); metricUserScaleRadioButton = new QRadioButton("User Scale"); metricUserScaleRadioButton->setToolTip( "This selection will map the Pos Max value\n" "to the 1.0 value in the palette, the Pos\n" "Min value to the 0.0 value in the palettte,\n" "the Neg Min value to the 0.0 value in the \n" "palette, and the Neg Max value to the -1.0\n" "value in the palette."); scaleButtonGroup->addButton(metricUserScaleRadioButton, DisplaySettingsMetric::METRIC_OVERLAY_SCALE_USER); QLabel* colorMapPosMinMaxLabel = new QLabel("Pos Min/Max"); metricColorPositiveMaxDoubleSpinBox = new QDoubleSpinBox; metricColorPositiveMaxDoubleSpinBox->setMinimum(0); metricColorPositiveMaxDoubleSpinBox->setMaximum(10000000.0); metricColorPositiveMaxDoubleSpinBox->setSingleStep(1.0); metricColorPositiveMaxDoubleSpinBox->setDecimals(6); metricColorPositiveMaxDoubleSpinBox->setToolTip( "This positive metric value is mapped to\n" "the 1.0 value in the color palette."); QObject::connect(metricColorPositiveMaxDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readMetricSettingsPage())); metricColorPositiveMinDoubleSpinBox = new QDoubleSpinBox; metricColorPositiveMinDoubleSpinBox->setMinimum(0); metricColorPositiveMinDoubleSpinBox->setMaximum(10000000.0); metricColorPositiveMinDoubleSpinBox->setSingleStep(1.0); metricColorPositiveMinDoubleSpinBox->setDecimals(6); metricColorPositiveMinDoubleSpinBox->setToolTip( "This positive metric value is mapped to\n" "the 0.0 value in the color palette."); QObject::connect(metricColorPositiveMinDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readMetricSettingsPage())); QLabel* colorMapNegMinMaxLabel = new QLabel("Neg Max/Min"); metricColorNegativeMinDoubleSpinBox = new QDoubleSpinBox; metricColorNegativeMinDoubleSpinBox->setMinimum(-10000000.0); metricColorNegativeMinDoubleSpinBox->setMaximum(0.0); metricColorNegativeMinDoubleSpinBox->setSingleStep(1.0); metricColorNegativeMinDoubleSpinBox->setDecimals(6); metricColorNegativeMinDoubleSpinBox->setToolTip( "This negative metric value is mapped to\n" "the 0.0 value in the color palette."); QObject::connect(metricColorNegativeMinDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readMetricSettingsPage())); metricColorNegativeMaxDoubleSpinBox = new QDoubleSpinBox; metricColorNegativeMaxDoubleSpinBox->setMinimum(-10000000.0); metricColorNegativeMaxDoubleSpinBox->setMaximum(0.0); metricColorNegativeMaxDoubleSpinBox->setSingleStep(1.0); metricColorNegativeMaxDoubleSpinBox->setDecimals(6); metricColorNegativeMaxDoubleSpinBox->setToolTip( "This negative metric value is mapped to\n" "the -1.0 value in the color palette."); QObject::connect(metricColorNegativeMaxDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readMetricSettingsPage())); metricColorInterpolateCheckBox = new QCheckBox("Interpolate"); QObject::connect(metricColorInterpolateCheckBox, SIGNAL(clicked()), this, SLOT(readMetricSettingsPage())); QGridLayout* colorMapGridLayout = new QGridLayout; colorMapGridLayout->setColumnMinimumWidth(0, 25); colorMapGridLayout->setContentsMargins(0, 0, 0, 0); colorMapGridLayout->addWidget(colorMapPosMinMaxLabel, 0, 1); colorMapGridLayout->addWidget(metricColorPositiveMinDoubleSpinBox, 0, 2); colorMapGridLayout->addWidget(metricColorPositiveMaxDoubleSpinBox, 0, 3); colorMapGridLayout->addWidget(colorMapNegMinMaxLabel, 1, 1); colorMapGridLayout->addWidget(metricColorNegativeMaxDoubleSpinBox, 1, 2); colorMapGridLayout->addWidget(metricColorNegativeMinDoubleSpinBox, 1, 3); QLabel* colorMapPercentagePosMinMaxLabel = new QLabel("Pos Min/Max"); metricColorPercentagePositiveMaxDoubleSpinBox = new QDoubleSpinBox; metricColorPercentagePositiveMaxDoubleSpinBox->setMinimum(0); metricColorPercentagePositiveMaxDoubleSpinBox->setMaximum(100.0); metricColorPercentagePositiveMaxDoubleSpinBox->setSingleStep(1.0); metricColorPercentagePositiveMaxDoubleSpinBox->setDecimals(0); metricColorPercentagePositiveMaxDoubleSpinBox->setSuffix("%"); metricColorPercentagePositiveMaxDoubleSpinBox->setToolTip( "This positive percentile metric value is mapped to\n" "the 1.0 value in the color palette."); QObject::connect(metricColorPercentagePositiveMaxDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readMetricSettingsPage())); metricColorPercentagePositiveMinDoubleSpinBox = new QDoubleSpinBox; metricColorPercentagePositiveMinDoubleSpinBox->setMinimum(0); metricColorPercentagePositiveMinDoubleSpinBox->setMaximum(100.0); metricColorPercentagePositiveMinDoubleSpinBox->setSingleStep(1.0); metricColorPercentagePositiveMinDoubleSpinBox->setDecimals(0); metricColorPercentagePositiveMinDoubleSpinBox->setSuffix("%"); metricColorPercentagePositiveMinDoubleSpinBox->setToolTip( "This positive percentile metric value is mapped to\n" "the 0.0 value in the color palette."); QObject::connect(metricColorPercentagePositiveMinDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readMetricSettingsPage())); QLabel* colorMapPercentageNegMinMaxLabel = new QLabel("Neg Max/Min"); metricColorPercentageNegativeMinDoubleSpinBox = new QDoubleSpinBox; metricColorPercentageNegativeMinDoubleSpinBox->setMinimum(0.0); metricColorPercentageNegativeMinDoubleSpinBox->setMaximum(100.0); metricColorPercentageNegativeMinDoubleSpinBox->setSingleStep(1.0); metricColorPercentageNegativeMinDoubleSpinBox->setDecimals(0); metricColorPercentageNegativeMinDoubleSpinBox->setSuffix("%"); metricColorPercentageNegativeMinDoubleSpinBox->setToolTip( "This negative percentile metric value is mapped to\n" "the 0.0 value in the color palette."); QObject::connect(metricColorPercentageNegativeMinDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readMetricSettingsPage())); metricColorPercentageNegativeMaxDoubleSpinBox = new QDoubleSpinBox; metricColorPercentageNegativeMaxDoubleSpinBox->setMinimum(0); metricColorPercentageNegativeMaxDoubleSpinBox->setMaximum(100.0); metricColorPercentageNegativeMaxDoubleSpinBox->setSingleStep(1.0); metricColorPercentageNegativeMaxDoubleSpinBox->setDecimals(0); metricColorPercentageNegativeMaxDoubleSpinBox->setSuffix("%"); metricColorPercentageNegativeMaxDoubleSpinBox->setToolTip( "This negative percentile metric value is mapped to\n" "the -1.0 value in the color palette."); QObject::connect(metricColorPercentageNegativeMaxDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readMetricSettingsPage())); QWidget* colorMapPercentageWidget = new QWidget; QGridLayout* colorMapPercentageGridLayout = new QGridLayout(colorMapPercentageWidget); colorMapPercentageGridLayout->setContentsMargins(0, 0, 0, 0); colorMapPercentageGridLayout->setColumnMinimumWidth(0, 25); colorMapPercentageGridLayout->addWidget(colorMapPercentagePosMinMaxLabel, 0, 1); colorMapPercentageGridLayout->addWidget(metricColorPercentagePositiveMinDoubleSpinBox, 0, 2); colorMapPercentageGridLayout->addWidget(metricColorPercentagePositiveMaxDoubleSpinBox, 0, 3); colorMapPercentageGridLayout->addWidget(colorMapPercentageNegMinMaxLabel, 1, 1); colorMapPercentageGridLayout->addWidget(metricColorPercentageNegativeMaxDoubleSpinBox, 1, 2); colorMapPercentageGridLayout->addWidget(metricColorPercentageNegativeMinDoubleSpinBox, 1, 3); colorMapPercentageWidget->setFixedSize(colorMapPercentageWidget->sizeHint()); QGridLayout* colorScaleGridLayout = new QGridLayout; colorScaleGridLayout->addWidget(metricFileAutoScaleRadioButton, 0, 0, 1, 2); colorScaleGridLayout->addWidget(metricFileAutoScalePercentageRadioButton, 1, 0, 1, 1); colorScaleGridLayout->addWidget(colorMapPercentageWidget, 2, 0, 1, 2); colorScaleGridLayout->addWidget(metricFileAutoScaleSpecifiedColumnRadioButton, 3, 0, 1, 1); colorScaleGridLayout->addWidget(metricFileAutoScaleSpecifiedColumnSelectionComboBox, 3, 1); colorScaleGridLayout->addWidget(metricFuncVolumeAutoScaleRadioButton, 4, 0, 1, 2); colorScaleGridLayout->addWidget(metricUserScaleRadioButton, 5, 0, 1, 2); QGroupBox* colorGroupBox = new QGroupBox("Color Mapping"); QVBoxLayout* colorGroupLayout = new QVBoxLayout(colorGroupBox); colorGroupLayout->addLayout(colorScaleGridLayout); colorGroupLayout->setAlignment(colorScaleGridLayout, Qt::AlignLeft); colorGroupLayout->addLayout(colorMapGridLayout); colorGroupLayout->setAlignment(colorMapGridLayout, Qt::AlignLeft); colorGroupLayout->addWidget(metricColorInterpolateCheckBox); colorGroupLayout->setAlignment(metricColorInterpolateCheckBox, Qt::AlignLeft); //colorGroupBox->setFixedSize(colorGroupBox->sizeHint()); // // Display Mode Buttons // metricDisplayModeBothRadioButton = new QRadioButton("Both"); metricDisplayModePositiveRadioButton = new QRadioButton("Positive"); metricDisplayModeNegativeRadioButton = new QRadioButton("Negative"); QButtonGroup* displayModeButtonGroup = new QButtonGroup(this); QObject::connect(displayModeButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(readMetricSettingsPage())); displayModeButtonGroup->addButton(metricDisplayModeBothRadioButton, DisplaySettingsMetric::METRIC_DISPLAY_MODE_POSITIVE_AND_NEGATIVE); displayModeButtonGroup->addButton(metricDisplayModePositiveRadioButton, DisplaySettingsMetric::METRIC_DISPLAY_MODE_POSITIVE_ONLY); displayModeButtonGroup->addButton(metricDisplayModeNegativeRadioButton, DisplaySettingsMetric::METRIC_DISPLAY_MODE_NEGATIVE_ONLY); QGroupBox* displayModeGroupBox = new QGroupBox("Display Mode"); QVBoxLayout* displayModeGroupLayout = new QVBoxLayout(displayModeGroupBox); displayModeGroupLayout->addWidget(metricDisplayModePositiveRadioButton); displayModeGroupLayout->addWidget(metricDisplayModeNegativeRadioButton); displayModeGroupLayout->addWidget(metricDisplayModeBothRadioButton); displayModeGroupBox->setFixedSize(displayModeGroupBox->sizeHint()); // // Palette Selection // metricPaletteComboBox = new QComboBox; QObject::connect(metricPaletteComboBox, SIGNAL(activated(int)), this, SLOT(metricPaletteSelection(int))); metricDisplayColorBarCheckBox = new QCheckBox("Display Color Bar"); QObject::connect(metricDisplayColorBarCheckBox, SIGNAL(clicked()), this, SLOT(readMetricSettingsPage())); QGroupBox* paletteGroupBox = new QGroupBox("Palette"); QVBoxLayout* paletteLayout = new QVBoxLayout(paletteGroupBox); paletteLayout->addWidget(metricPaletteComboBox); paletteLayout->addWidget(metricDisplayColorBarCheckBox); paletteGroupBox->setFixedHeight(paletteGroupBox->sizeHint().height()); // // Threshold line edits // QLabel* threshColLabel = new QLabel("Column"); QLabel* threshAvgAreaLabel = new QLabel("Average Area"); QLabel* threshUserLabel = new QLabel("User"); QLabel* threshPosLabel = new QLabel("Pos"); QLabel* threshNegLabel = new QLabel("Neg"); metricThresholdColumnPositiveDoubleSpinBox = new QDoubleSpinBox; metricThresholdColumnPositiveDoubleSpinBox->setMinimum(-10000000.0); metricThresholdColumnPositiveDoubleSpinBox->setMaximum( 10000000.0); metricThresholdColumnPositiveDoubleSpinBox->setSingleStep(1.0); metricThresholdColumnPositiveDoubleSpinBox->setDecimals(6); metricThresholdColumnPositiveDoubleSpinBox->setMaximumWidth(floatSpinBoxWidth); metricThresholdColumnPositiveDoubleSpinBox->setToolTip( "Positive metric values less positive\n" "than this amount are not shown when\n" "threshold type COLUMN is selected. This\n" "value comes from and is stored in the\n" "metric file."); QObject::connect(metricThresholdColumnPositiveDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readMetricSettingsPage())); metricThresholdAveragePositiveDoubleSpinBox = new QDoubleSpinBox; metricThresholdAveragePositiveDoubleSpinBox->setMinimum(-10000000.0); metricThresholdAveragePositiveDoubleSpinBox->setMaximum( 10000000.0); metricThresholdAveragePositiveDoubleSpinBox->setSingleStep(1.0); metricThresholdAveragePositiveDoubleSpinBox->setDecimals(6); metricThresholdAveragePositiveDoubleSpinBox->setMaximumWidth(floatSpinBoxWidth); metricThresholdAveragePositiveDoubleSpinBox->setToolTip( "Positive metric values less positive\n" "than this amount are not shown when\n" "threshold type AVERAGE AREA is selected.\n" "This value comes from and is stored in the\n" "the metric file."); QObject::connect(metricThresholdAveragePositiveDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readMetricSettingsPage())); metricThresholdUserPositiveDoubleSpinBox = new QDoubleSpinBox; metricThresholdUserPositiveDoubleSpinBox->setMinimum(-10000000.0); metricThresholdUserPositiveDoubleSpinBox->setMaximum( 10000000.0); metricThresholdUserPositiveDoubleSpinBox->setSingleStep(0.05); metricThresholdUserPositiveDoubleSpinBox->setDecimals(6); metricThresholdUserPositiveDoubleSpinBox->setMaximumWidth(floatSpinBoxWidth); metricThresholdUserPositiveDoubleSpinBox->setToolTip( "Positive metric values less positive\n" "than this amount are not shown when\n" "threshold type USER is selected."); QObject::connect(metricThresholdUserPositiveDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readMetricSettingsPage())); metricThresholdColumnNegativeDoubleSpinBox = new QDoubleSpinBox; metricThresholdColumnNegativeDoubleSpinBox->setMinimum(-10000000.0); metricThresholdColumnNegativeDoubleSpinBox->setMaximum( 10000000.0); metricThresholdColumnNegativeDoubleSpinBox->setSingleStep(1.0); metricThresholdColumnNegativeDoubleSpinBox->setDecimals(6); metricThresholdColumnNegativeDoubleSpinBox->setMaximumWidth(floatSpinBoxWidth); metricThresholdColumnNegativeDoubleSpinBox->setToolTip( "Negative metric values less negative\n" "than this amount are not shown when\n" "threshold type COLUMN is selected. This\n" "value comes from and is stored in the\n" "metric file."); QObject::connect(metricThresholdColumnNegativeDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readMetricSettingsPage())); metricThresholdAverageNegativeDoubleSpinBox = new QDoubleSpinBox; metricThresholdAverageNegativeDoubleSpinBox->setMinimum(-10000000.0); metricThresholdAverageNegativeDoubleSpinBox->setMaximum( 10000000.0); metricThresholdAverageNegativeDoubleSpinBox->setSingleStep(1.0); metricThresholdAverageNegativeDoubleSpinBox->setDecimals(6); metricThresholdAverageNegativeDoubleSpinBox->setMaximumWidth(floatSpinBoxWidth); metricThresholdAverageNegativeDoubleSpinBox->setToolTip( "Negative metric values less negative\n" "than this amount are not shown when\n" "threshold type AVERAGE AREA is selected.\n" "This value comes from and is stored in\n" "the metric file."); QObject::connect(metricThresholdAverageNegativeDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readMetricSettingsPage())); metricThresholdUserNegativeDoubleSpinBox = new QDoubleSpinBox; metricThresholdUserNegativeDoubleSpinBox->setMinimum(-10000000.0); metricThresholdUserNegativeDoubleSpinBox->setMaximum( 10000000.0); metricThresholdUserNegativeDoubleSpinBox->setSingleStep(0.05); metricThresholdUserNegativeDoubleSpinBox->setDecimals(6); metricThresholdUserNegativeDoubleSpinBox->setMaximumWidth(floatSpinBoxWidth); metricThresholdUserNegativeDoubleSpinBox->setToolTip( "Negative metric values less negative\n" "than this amount are not shown when\n" "threshold type USER is selected."); QObject::connect(metricThresholdUserNegativeDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readMetricSettingsPage())); metricShowThresholdedRegionsCheckBox = new QCheckBox("Show Subthresh Region Green"); metricShowThresholdedRegionsCheckBox->setToolTip( "When checked, nodes/voxels that fail\n" "the threshold test are colored in green.\n" "Nodes/voxels with zero values are not\n" "colored."); QObject::connect(metricShowThresholdedRegionsCheckBox, SIGNAL(toggled(bool)), this, SLOT(readMetricSettingsPage())); QLabel* threshTypeLabel = new QLabel("Threshold Type "); metricThresholdTypeComboBox = new QComboBox; QObject::connect(metricThresholdTypeComboBox, SIGNAL(activated(int)), this, SLOT(readMetricSettingsPage())); metricThresholdTypeComboBox->insertItem(DisplaySettingsMetric::METRIC_THRESHOLDING_TYPE_FILE_COLUMN, "Column"); metricThresholdTypeComboBox->insertItem(DisplaySettingsMetric::METRIC_THRESHOLDING_TYPE_FILE_COLUMN_AVERAGE, "Average Area"); metricThresholdTypeComboBox->insertItem(DisplaySettingsMetric::METRIC_THRESHOLDING_TYPE_USER_VALUES, "User"); QLabel* threshColumnLabel = new QLabel("Column "); metricThresholdSettingColumnSelectionComboBox = new GuiNodeAttributeColumnSelectionComboBox(GUI_NODE_FILE_TYPE_METRIC, false, false, false); QObject::connect(metricThresholdSettingColumnSelectionComboBox, SIGNAL(activated(int)), this, SLOT(slotUpateMetricThresholdSettingValues())); QHBoxLayout* threshColumnLayout = new QHBoxLayout; threshColumnLayout->addWidget(threshColumnLabel); threshColumnLayout->addWidget(metricThresholdSettingColumnSelectionComboBox); threshColumnLayout->addStretch(); QGridLayout* threshLayout = new QGridLayout; threshLayout->addWidget(threshColLabel, 0, 1); threshLayout->addWidget(threshAvgAreaLabel, 0, 2); threshLayout->addWidget(threshUserLabel, 0, 3); threshLayout->addWidget(threshPosLabel, 1, 0); threshLayout->addWidget(metricThresholdColumnPositiveDoubleSpinBox, 1, 1); threshLayout->addWidget(metricThresholdAveragePositiveDoubleSpinBox, 1, 2); threshLayout->addWidget(metricThresholdUserPositiveDoubleSpinBox, 1, 3); threshLayout->addWidget(threshNegLabel, 2, 0); threshLayout->addWidget(metricThresholdColumnNegativeDoubleSpinBox, 2, 1); threshLayout->addWidget(metricThresholdAverageNegativeDoubleSpinBox, 2, 2); threshLayout->addWidget(metricThresholdUserNegativeDoubleSpinBox, 2, 3); QHBoxLayout* threshTypeLayout = new QHBoxLayout; threshTypeLayout->addWidget(threshTypeLabel); threshTypeLayout->addWidget(metricThresholdTypeComboBox); threshTypeLayout->addWidget(new QLabel(" ")); threshTypeLayout->addWidget(metricShowThresholdedRegionsCheckBox); threshTypeLayout->addStretch(); QGroupBox* thresholdGroupBox = new QGroupBox("Threshold Adjustment"); QVBoxLayout* thresholdGroupLayout = new QVBoxLayout(thresholdGroupBox); thresholdGroupLayout->addLayout(threshColumnLayout); thresholdGroupLayout->addLayout(threshTypeLayout); thresholdGroupLayout->addLayout(threshLayout); thresholdGroupLayout->setAlignment(threshColumnLayout, Qt::AlignLeft); thresholdGroupLayout->setAlignment(threshTypeLayout, Qt::AlignLeft); thresholdGroupLayout->setAlignment(threshLayout, Qt::AlignLeft); thresholdGroupBox->setFixedSize(thresholdGroupBox->sizeHint()); // // Metric page and all layouts // QHBoxLayout* displayModePaletteLayout = new QHBoxLayout; displayModePaletteLayout->addWidget(displayModeGroupBox); displayModePaletteLayout->addWidget(paletteGroupBox); displayModePaletteLayout->addStretch(); pageMetricSettings = new QWidget; QVBoxLayout* metricLayout = new QVBoxLayout(pageMetricSettings); metricLayout->addWidget(colorGroupBox); metricLayout->addLayout(displayModePaletteLayout); metricLayout->addWidget(thresholdGroupBox); metricLayout->addStretch(); //pageMetricSettings->setFixedSize(pageMetricSettings->sizeHint()); pageWidgetStack->addWidget(pageMetricSettings); pageMetricSettingsWidgetGroup = new WuQWidgetGroup(this); pageMetricSettingsWidgetGroup->addWidget(threshColumnLabel); pageMetricSettingsWidgetGroup->addWidget(metricThresholdSettingColumnSelectionComboBox); pageMetricSettingsWidgetGroup->addWidget(metricFileAutoScaleRadioButton); pageMetricSettingsWidgetGroup->addWidget(metricFileAutoScalePercentageRadioButton); pageMetricSettingsWidgetGroup->addWidget(metricColorPercentagePositiveMaxDoubleSpinBox); pageMetricSettingsWidgetGroup->addWidget(metricColorPercentagePositiveMinDoubleSpinBox); pageMetricSettingsWidgetGroup->addWidget(metricColorPercentageNegativeMaxDoubleSpinBox); pageMetricSettingsWidgetGroup->addWidget(metricColorPercentageNegativeMinDoubleSpinBox); pageMetricSettingsWidgetGroup->addWidget(metricFileAutoScaleSpecifiedColumnRadioButton); pageMetricSettingsWidgetGroup->addWidget(metricFileAutoScaleSpecifiedColumnSelectionComboBox); pageMetricSettingsWidgetGroup->addWidget(metricFuncVolumeAutoScaleRadioButton); pageMetricSettingsWidgetGroup->addWidget(metricUserScaleRadioButton); pageMetricSettingsWidgetGroup->addWidget(metricColorPositiveMaxDoubleSpinBox); pageMetricSettingsWidgetGroup->addWidget(metricColorPositiveMinDoubleSpinBox); pageMetricSettingsWidgetGroup->addWidget(metricColorNegativeMinDoubleSpinBox); pageMetricSettingsWidgetGroup->addWidget(metricColorNegativeMaxDoubleSpinBox); pageMetricSettingsWidgetGroup->addWidget(metricColorInterpolateCheckBox); pageMetricSettingsWidgetGroup->addWidget(metricDisplayModeBothRadioButton); pageMetricSettingsWidgetGroup->addWidget(metricDisplayModePositiveRadioButton); pageMetricSettingsWidgetGroup->addWidget(metricDisplayModeNegativeRadioButton); pageMetricSettingsWidgetGroup->addWidget(metricPaletteComboBox); pageMetricSettingsWidgetGroup->addWidget(metricDisplayColorBarCheckBox); pageMetricSettingsWidgetGroup->addWidget(metricThresholdColumnPositiveDoubleSpinBox); pageMetricSettingsWidgetGroup->addWidget(metricThresholdAveragePositiveDoubleSpinBox); pageMetricSettingsWidgetGroup->addWidget(metricThresholdUserPositiveDoubleSpinBox); pageMetricSettingsWidgetGroup->addWidget(metricThresholdColumnNegativeDoubleSpinBox); pageMetricSettingsWidgetGroup->addWidget(metricThresholdAverageNegativeDoubleSpinBox); pageMetricSettingsWidgetGroup->addWidget(metricThresholdUserNegativeDoubleSpinBox); pageMetricSettingsWidgetGroup->addWidget(metricShowThresholdedRegionsCheckBox); pageMetricSettingsWidgetGroup->addWidget(metricThresholdTypeComboBox); } /** * Called when a metric palette is selected using the metric palette combo box. */ void GuiDisplayControlDialog::metricPaletteSelection(int itemNum) { DisplaySettingsMetric* dsm = theMainWindow->getBrainSet()->getDisplaySettingsMetric(); dsm->setSelectedPaletteIndex(itemNum); readMetricSettingsPage(); updateMetricSettingsPage(); } /** * Called when animate pushbutton is pressed. */ void GuiDisplayControlDialog::metricAnimatePushButtonSelection() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); // // Save main window caption // const QString savedMainWindowCaption = GuiBrainModelOpenGL::getMainWindowCaption(); // // Turn off display lists during animation // PreferencesFile* pf = theMainWindow->getBrainSet()->getPreferencesFile(); const bool displayListStatusFlag = pf->getDisplayListsEnabled(); pf->setDisplayListsEnabled(false); theMainWindow->getBrainSet()->clearAllDisplayLists(); MetricFile* mf = theMainWindow->getBrainSet()->getMetricFile(); const int numMetrics = mf->getNumberOfColumns(); DisplaySettingsMetric* dsm = theMainWindow->getBrainSet()->getDisplaySettingsMetric(); const int numInterpolateFrames = metricAnimateSpinBox->value(); BrainModelSurfaceNodeColoring* bsnc = theMainWindow->getBrainSet()->getNodeColoring(); if (numInterpolateFrames > 0) { for (int i = 0; i < (numMetrics - 1); i++) { // // Set current metrics // dsm->setSelectedDisplayColumn(surfaceModelIndex, -1, i); dsm->setSelectedThresholdColumn(surfaceModelIndex, -1, i); updateSurfaceOverlayWidgets(); if (pageMetricSelection != NULL) { QRadioButton* rb = dynamic_cast(metricViewButtonGroup->button(i)); rb->setChecked(true); QRadioButton* rbt = dynamic_cast(metricThresholdButtonGroup->button( dsm->getSelectedThresholdColumn(surfaceModelIndex, 0))); rbt->setChecked(true); } // // Assign colors with current metric and save the colors // bsnc->assignColors(); const int numNodes = mf->getNumberOfNodes(); const int colorSize = numNodes * 3; float* colors = new float[colorSize]; for (int k = 0; k < numNodes; k++) { const unsigned char* c = bsnc->getNodeColor(surfaceModelIndex, k); colors[k * 3] = c[0]; colors[k * 3 + 1] = c[1]; colors[k * 3 + 2] = c[2]; } // // Debugging information // if (DebugControl::getDebugOn()) { const int nodeNum = DebugControl::getDebugNodeNumber(); if ((nodeNum >= 0) && (nodeNum < numNodes)) { const unsigned char* c = bsnc->getNodeColor(surfaceModelIndex, nodeNum); std::cout << "Node " << nodeNum << " color (" << static_cast(c[0]) << "," << static_cast(c[1]) << "," << static_cast(c[2]) << ")" << std::endl; } } // // Assign colors with next metric and save the colors // dsm->setSelectedDisplayColumn(surfaceModelIndex, -1, i + 1); dsm->setSelectedThresholdColumn(surfaceModelIndex, -1, i + 1); bsnc->assignColors(); float* colors2 = new float[colorSize]; for (int k = 0; k < numNodes; k++) { const unsigned char* c = bsnc->getNodeColor(surfaceModelIndex, k); colors2[k * 3] = c[0]; colors2[k * 3 + 1] = c[1]; colors2[k * 3 + 2] = c[2]; } // // Compute the delta of the colors // const float steps = numInterpolateFrames + 1.0; float* colorDelta = new float[colorSize]; for (int k = 0; k < colorSize; k++) { colorDelta[k] = (colors2[k] - colors[k]) / steps; } for (int j = 0; j <= numInterpolateFrames; j++) { for (int m = 0; m < numNodes; m++) { // // Interpolate color deltas // const int m3 = m * 3; const float fj = j; const float rd = colorDelta[m3] * fj; const float gd = colorDelta[m3 + 1] * fj; const float bd = colorDelta[m3 + 2] * fj; // // Assign colors to the nodes // const float n255 = 255.0; unsigned char rgb[3]; rgb[0] = static_cast(std::min(colors[m3] + rd, n255)); rgb[1] = static_cast(std::min(colors[m3 + 1] + gd, n255)); rgb[2] = static_cast(std::min(colors[m3 + 2] + bd, n255)); bsnc->setNodeColor(surfaceModelIndex, m, rgb); // // Debugging information // if (DebugControl::getDebugOn()) { const int nodeNum = DebugControl::getDebugNodeNumber(); if (nodeNum == m) { const unsigned char* c = bsnc->getNodeColor(surfaceModelIndex, nodeNum); std::cout << "Node " << nodeNum << " color iteration " << j << " (" << static_cast(c[0]) << "," << static_cast(c[1]) << "," << static_cast(c[2]) << ")" << std::endl; } } } if (DebugControl::getDebugOn()) { const QString caption = ("column (1..N) = " + (QString::number(i + 1)) + " of " + QString::number(numMetrics) + " interpolation = " + QString::number(j)); GuiBrainModelOpenGL::setMainWindowCaption(caption); } // // Draw the surfaces // GuiBrainModelOpenGL::updateAllGL(NULL); } delete[] colors; delete[] colors2; delete[] colorDelta; } // // Set to last metric and draw it // dsm->setSelectedDisplayColumn(surfaceModelIndex, -1, numMetrics - 1); dsm->setSelectedThresholdColumn(surfaceModelIndex, -1, numMetrics - 1); bsnc->assignColors(); updateSurfaceOverlayWidgets(); if (pageMetricSelection != NULL) { QRadioButton* rb = dynamic_cast(metricViewButtonGroup->button(numMetrics - 1)); rb->setChecked(true); QRadioButton* rb2 = dynamic_cast(metricThresholdButtonGroup->button(dsm->getSelectedThresholdColumn(surfaceModelIndex, 0))); rb2->setChecked(true); } GuiBrainModelOpenGL::updateAllGL(NULL); } else { for (int i = 0; i < numMetrics; i++) { dsm->setSelectedDisplayColumn(surfaceModelIndex, -1, i); dsm->setSelectedThresholdColumn(surfaceModelIndex, -1, i); updateSurfaceOverlayWidgets(); if (pageMetricSelection != NULL) { QRadioButton* rb = dynamic_cast(metricViewButtonGroup->button(i)); rb->setChecked(true); QRadioButton* rb2 = dynamic_cast(metricThresholdButtonGroup->button(dsm->getSelectedThresholdColumn(surfaceModelIndex, 0))); rb2->setChecked(true); } bsnc->assignColors(); GuiBrainModelOpenGL::updateAllGL(NULL); } } // // Restore main window caption // GuiBrainModelOpenGL::setMainWindowCaption(savedMainWindowCaption); // // Draw the surfaces // GuiBrainModelOpenGL::updateAllGL(NULL); // // Restore display list status // pf->setDisplayListsEnabled(displayListStatusFlag); QApplication::restoreOverrideCursor(); } /** * update the metric selection page. */ void GuiDisplayControlDialog::updateMetricSelectionPage() { if (pageMetricSelection == NULL) { return; } createAndUpdateMetricSelectionPage(); DisplaySettingsMetric* dsm = theMainWindow->getBrainSet()->getDisplaySettingsMetric(); MetricFile* mf = theMainWindow->getBrainSet()->getMetricFile(); if (mf->getNumberOfColumns() > 0) { const int numView = metricViewButtonGroup->buttons().count(); const int viewCol = dsm->getSelectedDisplayColumn(surfaceModelIndex, overlayNumberComboBox->currentIndex()); if ((viewCol >= 0) && (viewCol < numView)) { QRadioButton* rb = dynamic_cast(metricViewButtonGroup->button(viewCol)); rb->setChecked(true); } const int numThresh = metricThresholdButtonGroup->buttons().count(); const int threshCol = dsm->getSelectedThresholdColumn(surfaceModelIndex, overlayNumberComboBox->currentIndex()); if ((threshCol >= 0) && (threshCol < numThresh)) { QRadioButton* rb2 = dynamic_cast(metricThresholdButtonGroup->button(threshCol)); rb2->setChecked(true); } } pageMetricSelection->setEnabled(validMetricData); } /** * update metric settings threshold column combo box. */ void GuiDisplayControlDialog::updateMetricSettingsThresholdColumnComboBox() { if (pageMetricSettings == NULL) { return; } int columnNumber = -1; BrainSet* brainSet = theMainWindow->getBrainSet(); for (int i = 0; i < brainSet->getNumberOfSurfaceOverlays(); i++) { BrainModelSurfaceOverlay* bmsOverlay = brainSet->getSurfaceOverlay(i); if (bmsOverlay->getOverlay(surfaceModelIndex) == BrainModelSurfaceOverlay::OVERLAY_METRIC) { columnNumber = bmsOverlay->getThresholdColumnSelected(surfaceModelIndex); } } if ((columnNumber >= 0) && (columnNumber < brainSet->getSurfaceShapeFile()->getNumberOfColumns())) { metricThresholdSettingColumnSelectionComboBox->setCurrentIndex(columnNumber); slotUpateMetricThresholdSettingValues(); } } /** * update the metric settings page. */ void GuiDisplayControlDialog::updateMetricSettingsPage() { if (pageMetricSettings == NULL) { return; } pageMetricSettingsWidgetGroup->blockSignals(true); DisplaySettingsMetric* dsm = theMainWindow->getBrainSet()->getDisplaySettingsMetric(); MetricFile* mf = theMainWindow->getBrainSet()->getMetricFile(); if (mf->getNumberOfColumns() > 0) { metricThresholdSettingColumnSelectionComboBox->updateComboBox(); // // Threshold settings // slotUpateMetricThresholdSettingValues(); } float negThresh, posThresh; dsm->getUserThresholdingValues(negThresh, posThresh); metricThresholdUserPositiveDoubleSpinBox->setValue(posThresh); metricThresholdUserNegativeDoubleSpinBox->setValue(negThresh); metricThresholdTypeComboBox->setCurrentIndex(dsm->getMetricThresholdingType()); // // Color Mapping auto scale radio buttons, pos/neg max line edits, and interpolate radio button // switch(dsm->getSelectedOverlayScale()) { case DisplaySettingsMetric::METRIC_OVERLAY_SCALE_AUTO: metricFileAutoScaleRadioButton->setChecked(true); break; case DisplaySettingsMetric::METRIC_OVERLAY_SCALE_AUTO_PERCENTAGE: metricFileAutoScalePercentageRadioButton->setChecked(true); break; case DisplaySettingsMetric::METRIC_OVERLAY_SCALE_AUTO_SPECIFIED_COLUMN: metricFileAutoScaleSpecifiedColumnRadioButton->setChecked(true); break; case DisplaySettingsMetric::METRIC_OVERLAY_SCALE_AUTO_FUNC_VOLUME: metricFuncVolumeAutoScaleRadioButton->setChecked(true); break; case DisplaySettingsMetric::METRIC_OVERLAY_SCALE_USER: metricUserScaleRadioButton->setChecked(true); break; } metricFileAutoScaleSpecifiedColumnSelectionComboBox->updateComboBox(); metricFileAutoScaleSpecifiedColumnSelectionComboBox->setCurrentIndex( dsm->getOverlayScaleSpecifiedColumnNumber()); float posMinMetric = 0.0, posMaxMetric = 0.0, negMinMetric = 0.0, negMaxMetric = 0.0; dsm->getUserScaleMinMax(posMinMetric, posMaxMetric, negMinMetric, negMaxMetric); metricColorPositiveMinDoubleSpinBox->setValue(posMinMetric); metricColorPositiveMaxDoubleSpinBox->setValue(posMaxMetric); metricColorNegativeMinDoubleSpinBox->setValue(negMinMetric); metricColorNegativeMaxDoubleSpinBox->setValue(negMaxMetric); metricColorPercentagePositiveMaxDoubleSpinBox->setValue( dsm->getAutoScalePercentagePositiveMaximum()); metricColorPercentagePositiveMinDoubleSpinBox->setValue( dsm->getAutoScalePercentagePositiveMinimum()); metricColorPercentageNegativeMinDoubleSpinBox->setValue( dsm->getAutoScalePercentageNegativeMinimum()); metricColorPercentageNegativeMaxDoubleSpinBox->setValue( dsm->getAutoScalePercentageNegativeMaximum()); metricColorInterpolateCheckBox->setChecked(dsm->getInterpolateColors()); // // Threshold positive and negative // metricShowThresholdedRegionsCheckBox->setChecked(dsm->getShowSpecialColorForThresholdedNodes()); // // Display mode positive, negative, or both // switch(dsm->getDisplayMode()) { case DisplaySettingsMetric::METRIC_DISPLAY_MODE_POSITIVE_ONLY: metricDisplayModePositiveRadioButton->setChecked(true); break; case DisplaySettingsMetric::METRIC_DISPLAY_MODE_NEGATIVE_ONLY: metricDisplayModeNegativeRadioButton->setChecked(true); break; case DisplaySettingsMetric::METRIC_DISPLAY_MODE_POSITIVE_AND_NEGATIVE: metricDisplayModeBothRadioButton->setChecked(true); break; } // // Palette selection and display color bar // metricDisplayColorBarCheckBox->setChecked(dsm->getDisplayColorBar()); metricPaletteComboBox->clear(); PaletteFile* pf = theMainWindow->getBrainSet()->getPaletteFile(); const int numPalettes = pf->getNumberOfPalettes(); for (int i = 0; i < numPalettes; i++) { const Palette* p = pf->getPalette(i); QString name(p->getName()); if (p->getPositiveOnly()) { name.append("+"); } metricPaletteComboBox->addItem(name); } metricPaletteComboBox->setCurrentIndex(dsm->getSelectedPaletteIndex()); const bool volumeValid = (theMainWindow->getBrainSet()->getNumberOfVolumeFunctionalFiles() > 0); pageMetricSettings->setEnabled(validMetricData | volumeValid); pageMetricSettingsWidgetGroup->blockSignals(false); } /** * Update all metric items in the dialog. */ void GuiDisplayControlDialog::updateMetricItems() { updatePageSelectionComboBox(); DisplaySettingsMetric* dsm = theMainWindow->getBrainSet()->getDisplaySettingsMetric(); metricApplySelectionToLeftAndRightStructuresFlagCheckBox->blockSignals(true); metricApplySelectionToLeftAndRightStructuresFlagCheckBox->setChecked(dsm->getApplySelectionToLeftAndRightStructuresFlag()); metricApplySelectionToLeftAndRightStructuresFlagCheckBox->blockSignals(false); updateSurfaceOverlayWidgets(); updateMetricSelectionPage(); updateMetricSettingsPage(); updateMetricSettingsThresholdColumnComboBox(); updateMetricMiscellaneousPage(); } /** * called when metric threshold setting column combo box value changed. */ void GuiDisplayControlDialog::slotUpateMetricThresholdSettingValues() { MetricFile* mf = theMainWindow->getBrainSet()->getMetricFile(); const int threshColumnNumber = metricThresholdSettingColumnSelectionComboBox->currentIndex(); if ((threshColumnNumber >= 0) && (threshColumnNumber < mf->getNumberOfColumns())) { float negThresh, posThresh; mf->getColumnThresholding(threshColumnNumber, negThresh, posThresh); metricThresholdColumnPositiveDoubleSpinBox->blockSignals(true); metricThresholdColumnPositiveDoubleSpinBox->setValue(posThresh); metricThresholdColumnPositiveDoubleSpinBox->blockSignals(false); metricThresholdColumnNegativeDoubleSpinBox->blockSignals(true); metricThresholdColumnNegativeDoubleSpinBox->setValue(negThresh); metricThresholdColumnNegativeDoubleSpinBox->blockSignals(false); mf->getColumnAverageThresholding(threshColumnNumber, negThresh, posThresh); metricThresholdAveragePositiveDoubleSpinBox->blockSignals(true); metricThresholdAveragePositiveDoubleSpinBox->setValue(posThresh); metricThresholdAveragePositiveDoubleSpinBox->blockSignals(false); metricThresholdAverageNegativeDoubleSpinBox->blockSignals(true); metricThresholdAverageNegativeDoubleSpinBox->setValue(negThresh); metricThresholdAverageNegativeDoubleSpinBox->blockSignals(false); } } /** * read the metric settings page. */ void GuiDisplayControlDialog::readMetricSettingsPage() { if (creatingDialog) { return; } if (pageMetricSettings == NULL) { return; } DisplaySettingsMetric* dsm = theMainWindow->getBrainSet()->getDisplaySettingsMetric(); // // Get display mode // if (metricDisplayModePositiveRadioButton->isChecked()) { dsm->setDisplayMode(DisplaySettingsMetric::METRIC_DISPLAY_MODE_POSITIVE_ONLY); } else if (metricDisplayModeNegativeRadioButton->isChecked()) { dsm->setDisplayMode(DisplaySettingsMetric::METRIC_DISPLAY_MODE_NEGATIVE_ONLY); } else { dsm->setDisplayMode(DisplaySettingsMetric::METRIC_DISPLAY_MODE_POSITIVE_AND_NEGATIVE); } // // Get auto/user scale, pos/neg max, and interpolate color mapping // if (metricFileAutoScaleRadioButton->isChecked()) { dsm->setSelectedOverlayScale(DisplaySettingsMetric::METRIC_OVERLAY_SCALE_AUTO); } else if (metricFileAutoScalePercentageRadioButton->isChecked()) { dsm->setSelectedOverlayScale(DisplaySettingsMetric::METRIC_OVERLAY_SCALE_AUTO_PERCENTAGE); } else if (metricFileAutoScaleSpecifiedColumnRadioButton->isChecked()) { dsm->setSelectedOverlayScale(DisplaySettingsMetric::METRIC_OVERLAY_SCALE_AUTO_SPECIFIED_COLUMN); } else if (metricFuncVolumeAutoScaleRadioButton->isChecked()) { dsm->setSelectedOverlayScale(DisplaySettingsMetric::METRIC_OVERLAY_SCALE_AUTO_FUNC_VOLUME); } else { dsm->setSelectedOverlayScale(DisplaySettingsMetric::METRIC_OVERLAY_SCALE_USER); } dsm->setOverlayScaleSpecifiedColumnNumber(metricFileAutoScaleSpecifiedColumnSelectionComboBox->currentIndex()); dsm->setUserScaleMinMax(metricColorPositiveMinDoubleSpinBox->value(), metricColorPositiveMaxDoubleSpinBox->value(), metricColorNegativeMinDoubleSpinBox->value(), metricColorNegativeMaxDoubleSpinBox->value()); dsm->setAutoScalePercentageNegativeMinimum( metricColorPercentageNegativeMinDoubleSpinBox->value()); dsm->setAutoScalePercentageNegativeMaximum( metricColorPercentageNegativeMaxDoubleSpinBox->value()); dsm->setAutoScalePercentagePositiveMinimum( metricColorPercentagePositiveMinDoubleSpinBox->value()); dsm->setAutoScalePercentagePositiveMaximum( metricColorPercentagePositiveMaxDoubleSpinBox->value()); dsm->setInterpolateColors(metricColorInterpolateCheckBox->isChecked()); // // Get negative and positive threshold // dsm->setShowSpecialColorForThresholdedNodes(metricShowThresholdedRegionsCheckBox->isChecked()); // // Get palette index and display color bar flag // dsm->setSelectedPaletteIndex(metricPaletteComboBox->currentIndex()); dsm->setDisplayColorBar(metricDisplayColorBarCheckBox->isChecked()); MetricFile* mf = theMainWindow->getBrainSet()->getMetricFile(); const int threshColumnNumber = metricThresholdSettingColumnSelectionComboBox->currentIndex(); if ((threshColumnNumber >= 0) && (threshColumnNumber < mf->getNumberOfColumns())) { mf->setColumnThresholding(threshColumnNumber, metricThresholdColumnNegativeDoubleSpinBox->value(), metricThresholdColumnPositiveDoubleSpinBox->value()); mf->setColumnAverageThresholding(threshColumnNumber, metricThresholdAverageNegativeDoubleSpinBox->value(), metricThresholdAveragePositiveDoubleSpinBox->value()); } dsm->setUserThresholdingValues(metricThresholdUserNegativeDoubleSpinBox->value(), metricThresholdUserPositiveDoubleSpinBox->value()); dsm->setMetricThresholdingType( static_cast( metricThresholdTypeComboBox->currentIndex())); theMainWindow->getBrainSet()->getNodeColoring()->assignColors(); theMainWindow->getBrainSet()->getVoxelColoring()->setVolumeFunctionalColoringInvalid(); GuiBrainModelOpenGL::updateAllGL(NULL); } /** * read metric L-to-L, R-to-R. */ void GuiDisplayControlDialog::readMetricL2LR2R() { DisplaySettingsMetric* dsm = theMainWindow->getBrainSet()->getDisplaySettingsMetric(); dsm->setApplySelectionToLeftAndRightStructuresFlag(metricApplySelectionToLeftAndRightStructuresFlagCheckBox->isChecked()); theMainWindow->getBrainSet()->getNodeColoring()->assignColors(); GuiBrainModelOpenGL::updateAllGL(NULL); displayOverlayLeftToLeftRightToRightMessage(); } /** * Read the selections from the metric dialog. */ void GuiDisplayControlDialog::readMetricSelectionPage() { if (creatingDialog) { return; } if (pageMetricSelection != NULL) { MetricFile* mf = theMainWindow->getBrainSet()->getMetricFile(); if (mf->getNumberOfColumns() > 0) { for (int i = 0; i < mf->getNumberOfColumns(); i++) { const QString name(metricColumnNameLineEdits[i]->text()); if (name != mf->getColumnName(i)) { mf->setColumnName(i, name); } } } } updateSurfaceOverlayWidgets(); GuiFilesModified fm; fm.setMetricModified(); theMainWindow->fileModificationUpdate(fm); theMainWindow->getBrainSet()->getNodeColoring()->assignColors(); theMainWindow->getBrainSet()->getVoxelColoring()->setVolumeFunctionalColoringInvalid(); GuiBrainModelOpenGL::updateAllGL(); } /** * Page containing selection of borders by color */ void GuiDisplayControlDialog::createBorderColorPage() { // // Vertical Box Layout for all border items // pageBorderColor = new QWidget; borderSubPageColorLayout = new QVBoxLayout(pageBorderColor); // // All off and all on pushbuttons // QPushButton* borderColorAllOnButton = new QPushButton("All On"); borderColorAllOnButton->setAutoDefault(false); QObject::connect(borderColorAllOnButton, SIGNAL(clicked()), this, SLOT(borderColorAllOn())); QPushButton* borderColorAllOffButton = new QPushButton("All Off"); borderColorAllOffButton->setAutoDefault(false); QObject::connect(borderColorAllOffButton, SIGNAL(clicked()), this, SLOT(borderColorAllOff())); QHBoxLayout* allOnOffLayout = new QHBoxLayout; allOnOffLayout->addWidget(borderColorAllOnButton); allOnOffLayout->addWidget(borderColorAllOffButton); allOnOffLayout->addStretch(); borderSubPageColorLayout->addLayout(allOnOffLayout); pageBorderColorWidgetGroup = new WuQWidgetGroup(this); pageBorderColorWidgetGroup->addWidget(borderColorAllOnButton); pageBorderColorWidgetGroup->addWidget(borderColorAllOffButton); createAndUpdateBorderColorCheckBoxes(); pageWidgetStack->addWidget(pageBorderColor); } /** * Create and update border color checkboxes. Because the number of border colors may change, * this method may update and change the label on existing checkboxes, add new * checkboxes, and hide existing checkboxes if the number of checkboxes is greater * than the number of border colors. */ void GuiDisplayControlDialog::createAndUpdateBorderColorCheckBoxes() { BorderColorFile* borderColors = theMainWindow->getBrainSet()->getBorderColorFile(); //numValidBorderColors = borderColors->getNumberOfColors(); std::vector sortedBorderColorIndices; borderColors->getColorIndicesSortedByName(sortedBorderColorIndices, false); numValidBorderColors = static_cast(sortedBorderColorIndices.size()); const int numExistingCheckBoxes = static_cast(borderColorCheckBoxes.size()); if (borderColorGridLayout == NULL) { QWidget* colorsWidget = new QWidget; borderColorGridLayout = new QGridLayout(colorsWidget); const int rowStretchNumber = 15000; borderColorGridLayout->addWidget(new QLabel(""), rowStretchNumber, 0, Qt::AlignLeft); borderColorGridLayout->setRowStretch(rowStretchNumber, 1000); borderSubPageColorLayout->addWidget(colorsWidget); } if (borderColorButtonGroup == NULL) { borderColorButtonGroup = new QButtonGroup(this); borderColorButtonGroup->setExclusive(false); QObject::connect(borderColorButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(readBorderColorPage())); } // // Update exising checkboxes // for (int i = 0; i < numExistingCheckBoxes; i++) { if (i < numValidBorderColors) { const int colorIndex = sortedBorderColorIndices[i]; borderColorCheckBoxesColorIndex[i] = colorIndex; borderColorCheckBoxes[i]->setText(borderColors->getColorNameByIndex(colorIndex)); borderColorCheckBoxes[i]->show(); } } // // Add new checkboxes as needed // for (int j = numExistingCheckBoxes; j < numValidBorderColors; j++) { const int colorIndex = sortedBorderColorIndices[j]; borderColorCheckBoxesColorIndex.push_back(colorIndex); QCheckBox* cb = new QCheckBox(borderColors->getColorNameByIndex(colorIndex)); borderColorCheckBoxes.push_back(cb); borderColorButtonGroup->addButton(cb, j); borderColorGridLayout->addWidget(cb, j, 0, 1, 1, Qt::AlignLeft); cb->show(); pageBorderColorWidgetGroup->addWidget(cb); } // // Hide existing checkboxes that are not needed. // for (int k = numValidBorderColors; k < numExistingCheckBoxes; k++) { borderColorCheckBoxes[k]->hide(); } } /** * This slot is called when the border color all on button is pressed */ void GuiDisplayControlDialog::borderColorAllOn() { BorderColorFile* borderColors = theMainWindow->getBrainSet()->getBorderColorFile(); borderColors->setAllSelectedStatus(true); updateBorderItems(); readBorderColorPage(); } /** * This slot is called when the border color all on button is pressed */ void GuiDisplayControlDialog::borderColorAllOff() { BorderColorFile* borderColors = theMainWindow->getBrainSet()->getBorderColorFile(); borderColors->setAllSelectedStatus(false); updateBorderItems(); readBorderColorPage(); } /** * Page containing selection of borders by name */ void GuiDisplayControlDialog::createBorderNamePage() { // // Vertical Box Layout for all border items // pageBorderName = new QWidget; borderSubPageNameLayout = new QVBoxLayout(pageBorderName); // // All off and all on pushbuttons // QPushButton* borderNameAllOnButton = new QPushButton("All On"); borderNameAllOnButton->setAutoDefault(false); QObject::connect(borderNameAllOnButton, SIGNAL(clicked()), this, SLOT(borderNameAllOn())); QPushButton* borderNameAllOffButton = new QPushButton("All Off"); borderNameAllOffButton->setAutoDefault(false); QObject::connect(borderNameAllOffButton, SIGNAL(clicked()), this, SLOT(borderNameAllOff())); QHBoxLayout* allOnOffLayout = new QHBoxLayout; allOnOffLayout->addWidget(borderNameAllOnButton); allOnOffLayout->addWidget(borderNameAllOffButton); allOnOffLayout->addStretch(); borderSubPageNameLayout->addLayout(allOnOffLayout); pageBorderNameWidgetGroup = new WuQWidgetGroup(this); pageBorderNameWidgetGroup->addWidget(borderNameAllOnButton); pageBorderNameWidgetGroup->addWidget(borderNameAllOffButton); createAndUpdateBorderNameCheckBoxes(); pageWidgetStack->addWidget(pageBorderName); } /** * Create and update border name checkboxes. Because the number of border names may change, * this method may update and change the label on existing checkboxes, add new * checkboxes, and hide existing checkboxes if the number of checkboxes is greater * than the number of border names. */ void GuiDisplayControlDialog::createAndUpdateBorderNameCheckBoxes() { borderNames.clear(); BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); bmbs->getAllBorderNames(borderNames, false); numValidBorderNames = static_cast(borderNames.size()); const int numExistingCheckBoxes = static_cast(borderNameCheckBoxes.size()); if (borderNameGridLayout == NULL) { QWidget* namesWidget = new QWidget; namesWidget->setMaximumWidth(450); borderNameGridLayout = new QGridLayout(namesWidget); const int rowStretchNumber = 15000; borderNameGridLayout->addWidget(new QLabel(""), rowStretchNumber, 0, Qt::AlignLeft); borderNameGridLayout->setRowStretch(rowStretchNumber, 1000); borderSubPageNameLayout->addWidget(namesWidget); } if (borderNameButtonGroup == NULL) { borderNameButtonGroup = new QButtonGroup(this); borderNameButtonGroup->setExclusive(false); QObject::connect(borderNameButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(readBorderNamePage())); } // // Update exising checkboxes // for (int i = 0; i < numExistingCheckBoxes; i++) { if (i < numValidBorderNames) { borderNameCheckBoxes[i]->setText(borderNames[i]); borderNameCheckBoxes[i]->show(); } } // // Add new checkboxes as needed // for (int j = numExistingCheckBoxes; j < numValidBorderNames; j++) { QCheckBox* cb = new QCheckBox(borderNames[j]); borderNameCheckBoxes.push_back(cb); borderNameButtonGroup->addButton(cb, j); borderNameGridLayout->addWidget(cb, j, 0, 1, 1, Qt::AlignLeft); cb->show(); pageBorderNameWidgetGroup->addWidget(cb); } // // Hide existing checkboxes that are not needed. // for (int k = numValidBorderNames; k < numExistingCheckBoxes; k++) { borderNameCheckBoxes[k]->hide(); } } /** * This slot is called when the border name all on button is pressed */ void GuiDisplayControlDialog::borderNameAllOn() { BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); const int numBorders = bmbs->getNumberOfBorders(); for (int j = 0; j < numBorders; j++) { BrainModelBorder* border = bmbs->getBorder(j); border->setNameDisplayFlag(true); } BorderFile* volumeBorders = theMainWindow->getBrainSet()->getVolumeBorderFile(); for (int j = 0; j < volumeBorders->getNumberOfBorders(); j++) { Border* b = volumeBorders->getBorder(j); b->setNameDisplayFlag(true); } updateBorderItems(); readBorderNamePage(); } /** * This slot is called when the border name all on button is pressed */ void GuiDisplayControlDialog::borderNameAllOff() { BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); const int numBorders = bmbs->getNumberOfBorders(); for (int j = 0; j < numBorders; j++) { BrainModelBorder* border = bmbs->getBorder(j); border->setNameDisplayFlag(false); } BorderFile* volumeBorders = theMainWindow->getBrainSet()->getVolumeBorderFile(); for (int j = 0; j < volumeBorders->getNumberOfBorders(); j++) { Border* b = volumeBorders->getBorder(j); b->setNameDisplayFlag(false); } updateBorderItems(); readBorderNamePage(); } /** * Border page containing main selections */ void GuiDisplayControlDialog::createBorderMainPage() { showBordersCheckBox = new QCheckBox("Show Borders"); QObject::connect(showBordersCheckBox, SIGNAL(toggled(bool)), this, SLOT(showBordersToggleSlot(bool))); showRaisedBordersCheckBox = new QCheckBox("Show Raised Borders (flat surfaces only)"); QObject::connect(showRaisedBordersCheckBox, SIGNAL(toggled(bool)), this, SLOT(readBorderMainPage())); showUncertaintyBordersCheckBox = new QCheckBox("Show Uncertainty Vectors (flat surfaces only)"); QObject::connect(showUncertaintyBordersCheckBox, SIGNAL(toggled(bool)), this, SLOT(readBorderMainPage())); showFirstLinkRedBordersCheckBox = new QCheckBox("Show First Link Red"); QObject::connect(showFirstLinkRedBordersCheckBox, SIGNAL(toggled(bool)), this, SLOT(readBorderMainPage())); bordersDrawTypeComboBox = new QComboBox; bordersDrawTypeComboBox->insertItem(DisplaySettingsBorders::BORDER_DRAW_AS_SYMBOLS, "Draw Borders as Symbols"); bordersDrawTypeComboBox->insertItem(DisplaySettingsBorders::BORDER_DRAW_AS_LINES, "Draw Borders as Lines"); bordersDrawTypeComboBox->insertItem(DisplaySettingsBorders::BORDER_DRAW_AS_SYMBOLS_AND_LINES, "Draw Borders as Symbols And Lines"); bordersDrawTypeComboBox->insertItem(DisplaySettingsBorders::BORDER_DRAW_AS_UNSTRETCHED_LINES, "Draw Borders as Unstretched Lines"); bordersDrawTypeComboBox->insertItem(DisplaySettingsBorders::BORDER_DRAW_AS_VARIABILITY, "Draw Borders Showing Variability"); bordersDrawTypeComboBox->insertItem(DisplaySettingsBorders::BORDER_DRAW_AS_VARIABILITY_AND_LINES, "Draw Borders Showing Variability and Lines"); bordersDrawTypeComboBox->setFixedSize(bordersDrawTypeComboBox->sizeHint()); QObject::connect(bordersDrawTypeComboBox, SIGNAL(activated(int)), this, SLOT(readBorderMainPage())); QLabel* symbolLabel = new QLabel("Symbol Type "); borderSymbolComboBox = new QComboBox; std::vector borderOverrideLabels; ColorFile::ColorStorage::getAllSymbolTypesAsStrings(borderOverrideLabels); for (unsigned int i = 0; i < borderOverrideLabels.size(); i++) { borderSymbolComboBox->addItem(borderOverrideLabels[i]); } QObject::connect(borderSymbolComboBox, SIGNAL(activated(int)), this, SLOT(readBorderMainPage())); QHBoxLayout* symbolLayout = new QHBoxLayout; symbolLayout->addWidget(symbolLabel); symbolLayout->addWidget(borderSymbolComboBox); symbolLayout->addStretch(); QLabel* opacityLabel = new QLabel("Opacity"); borderOpacityDoubleSpinBox = new QDoubleSpinBox; borderOpacityDoubleSpinBox->setMinimum(0.0); borderOpacityDoubleSpinBox->setMaximum(1.0); borderOpacityDoubleSpinBox->setSingleStep(0.01); borderOpacityDoubleSpinBox->setDecimals(3); QObject::connect(borderOpacityDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readBorderMainPage())); QHBoxLayout* opacityLayout = new QHBoxLayout; opacityLayout->addWidget(opacityLabel); opacityLayout->addWidget(borderOpacityDoubleSpinBox); opacityLayout->addStretch(); QLabel* spinLabel = new QLabel("Border Line Width / Point Size"); borderSizeSpinBox = new QDoubleSpinBox; borderSizeSpinBox->setMinimum(minPointSize); borderSizeSpinBox->setMaximum(maxPointSize); borderSizeSpinBox->setSingleStep(1.0); borderSizeSpinBox->setDecimals(1); QObject::connect(borderSizeSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readBorderMainPage())); QHBoxLayout* sizeLayout = new QHBoxLayout; sizeLayout->addWidget(spinLabel); sizeLayout->addWidget(borderSizeSpinBox); sizeLayout->addStretch(); QLabel* stretchLabel = new QLabel("Unstretched Lines Factor"); unstretchedBordersDoubleSpinBox = new QDoubleSpinBox; unstretchedBordersDoubleSpinBox->setMinimum(0.001); unstretchedBordersDoubleSpinBox->setMaximum(100000.0); unstretchedBordersDoubleSpinBox->setSingleStep(1.0); unstretchedBordersDoubleSpinBox->setDecimals(2); QObject::connect(unstretchedBordersDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readBorderMainPage())); QHBoxLayout* stretchLayout = new QHBoxLayout; stretchLayout->addWidget(stretchLabel); stretchLayout->addWidget(unstretchedBordersDoubleSpinBox); stretchLayout->addStretch(); // // Display color key button // QPushButton* colorKeyPushButton = new QPushButton("Display Color Key..."); colorKeyPushButton->setFixedSize(colorKeyPushButton->sizeHint()); colorKeyPushButton->setAutoDefault(false); QObject::connect(colorKeyPushButton, SIGNAL(clicked()), theMainWindow, SLOT(displayBorderColorKey())); // // Override border with area colors check box // overrideBorderWithAreaColorsCheckBox = new QCheckBox("Override Border Colors with Area Colors"); QObject::connect(overrideBorderWithAreaColorsCheckBox, SIGNAL(toggled(bool)), this, SLOT(readBorderMainPage())); // // Vertical Box Layout for all border items // pageBorderMain = new QWidget; QVBoxLayout* bordersSubPageMainLayout = new QVBoxLayout(pageBorderMain); bordersSubPageMainLayout->addWidget(showBordersCheckBox); bordersSubPageMainLayout->addWidget(showRaisedBordersCheckBox); bordersSubPageMainLayout->addWidget(showUncertaintyBordersCheckBox); bordersSubPageMainLayout->addWidget(showFirstLinkRedBordersCheckBox); bordersSubPageMainLayout->addWidget(overrideBorderWithAreaColorsCheckBox); bordersSubPageMainLayout->addWidget(bordersDrawTypeComboBox); bordersSubPageMainLayout->addLayout(symbolLayout); bordersSubPageMainLayout->addLayout(sizeLayout); bordersSubPageMainLayout->addLayout(opacityLayout); bordersSubPageMainLayout->addLayout(stretchLayout); bordersSubPageMainLayout->addWidget(colorKeyPushButton); bordersSubPageMainLayout->addStretch(); pageBorderMainWidgetGroup = new WuQWidgetGroup(this); pageBorderMainWidgetGroup->addWidget(showBordersCheckBox); pageBorderMainWidgetGroup->addWidget(showRaisedBordersCheckBox); pageBorderMainWidgetGroup->addWidget(showUncertaintyBordersCheckBox); pageBorderMainWidgetGroup->addWidget(showFirstLinkRedBordersCheckBox); pageBorderMainWidgetGroup->addWidget(bordersDrawTypeComboBox); pageBorderMainWidgetGroup->addWidget(borderSymbolComboBox); pageBorderMainWidgetGroup->addWidget(borderOpacityDoubleSpinBox); pageBorderMainWidgetGroup->addWidget(borderSizeSpinBox); pageBorderMainWidgetGroup->addWidget(unstretchedBordersDoubleSpinBox); pageBorderMainWidgetGroup->addWidget(overrideBorderWithAreaColorsCheckBox); pageWidgetStack->addWidget(pageBorderMain); } /** * update border main page. */ void GuiDisplayControlDialog::updateBorderMainPage() { if (pageBorderMain == NULL) { return; } pageBorderMainWidgetGroup->blockSignals(true); DisplaySettingsBorders* dsb = theMainWindow->getBrainSet()->getDisplaySettingsBorders(); showBordersCheckBox->setChecked(dsb->getDisplayBorders()); borderSymbolComboBox->setCurrentIndex(dsb->getSymbolType()); overrideBorderWithAreaColorsCheckBox->setChecked(dsb->getOverrideBorderColorsWithAreaColors()); borderOpacityDoubleSpinBox->setValue(dsb->getOpacity()); showRaisedBordersCheckBox->setChecked(dsb->getDisplayFlatBordersRaised()); showUncertaintyBordersCheckBox->setChecked(dsb->getDisplayUncertaintyVectors()); showFirstLinkRedBordersCheckBox->setChecked(dsb->getDisplayFirstLinkRed()); showBordersCheckBox->setEnabled(validBorderData); bordersDrawTypeComboBox->setCurrentIndex(dsb->getDrawMode()); borderSizeSpinBox->setValue(dsb->getDrawSize()); unstretchedBordersDoubleSpinBox->setValue(dsb->getDrawAsStretchedLinesStretchFactor()); pageBorderMain->setEnabled(validBorderData); pageBorderMainWidgetGroup->blockSignals(false); } /** * update border colors page. */ void GuiDisplayControlDialog::updateBorderColorPage(const bool filesChanged) { if (pageBorderColor == NULL) { return; } if (filesChanged) { createAndUpdateBorderColorCheckBoxes(); } pageBorderColorWidgetGroup->blockSignals(true); BorderColorFile* borderColors = theMainWindow->getBrainSet()->getBorderColorFile(); const int numColors = borderColors->getNumberOfColors(); if (numColors == numValidBorderColors) { for (int i = 0; i < numValidBorderColors; i++) { const int colorIndex = borderColorCheckBoxesColorIndex[i]; borderColorCheckBoxes[i]->setChecked(borderColors->getSelected(colorIndex)); } } else { std::cerr << "Number of border color checkboxes does not equal number of border colors." << std::endl; } pageBorderColor->setEnabled(validBorderData); pageBorderColorWidgetGroup->blockSignals(false); } /** * update border name page. */ void GuiDisplayControlDialog::updateBorderNamePage(const bool filesChanged) { if (pageBorderName == NULL) { return; } if (filesChanged) { createAndUpdateBorderNameCheckBoxes(); } pageBorderNameWidgetGroup->blockSignals(true); BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); const int numBorders = bmbs->getNumberOfBorders(); for (int j = 0; j < numBorders; j++) { BrainModelBorder* border = bmbs->getBorder(j); const QString name = border->getName(); for (int k = 0; k < numValidBorderNames; k++) { if (name == borderNames[k]) { borderNameCheckBoxes[k]->setChecked(border->getNameDisplayFlag()); break; } } } BorderFile* volumeBorderFile = theMainWindow->getBrainSet()->getVolumeBorderFile(); const int numVolumeBorders = volumeBorderFile->getNumberOfBorders(); for (int j = 0; j < numVolumeBorders; j++) { Border* b = volumeBorderFile->getBorder(j); const QString name = b->getName(); for (int k = 0; k < numValidBorderNames; k++) { if (name == borderNames[k]) { borderNameCheckBoxes[k]->setChecked(b->getNameDisplayFlag()); break; } } } pageBorderName->setEnabled(validBorderData); pageBorderNameWidgetGroup->blockSignals(false); } /** * Update border items in dialog */ void GuiDisplayControlDialog::updateBorderItems(const bool filesChanged) { updatePageSelectionComboBox(); DisplaySettingsBorders* dsb = theMainWindow->getBrainSet()->getDisplaySettingsBorders(); if (pageOverlayUnderlaySurfaceNew != NULL) { layersBorderCheckBox->setChecked(dsb->getDisplayBorders()); layersBorderCheckBox->setEnabled(validBorderData); } updateBorderMainPage(); updateBorderColorPage(filesChanged); updateBorderNamePage(filesChanged); updatePageSelectionComboBox(); } /** * Called when either the show borders on border page check box selected or the * borders check box on the Surface - Overlay/Underlay page is selected. */ void GuiDisplayControlDialog::showBordersToggleSlot(bool b) { if (pageBorderMain != NULL) { showBordersCheckBox->blockSignals(true); showBordersCheckBox->setChecked(b); showBordersCheckBox->blockSignals(false); } if (pageOverlayUnderlaySurfaceNew != NULL) { layersBorderCheckBox->blockSignals(true); layersBorderCheckBox->setChecked(b); layersBorderCheckBox->blockSignals(false); } //if (pageBorderMain == NULL) { DisplaySettingsBorders* dsb = theMainWindow->getBrainSet()->getDisplaySettingsBorders(); dsb->setDisplayBorders(b); dsb->determineDisplayedBorders(); GuiBrainModelOpenGL::updateAllGL(NULL); //} //readBorderMainPage(); //readBorderColorPage(); //readBorderNamePage(); } /** * read border main page. */ void GuiDisplayControlDialog::readBorderMainPage() { if (pageBorderMain == NULL) { return; } if (creatingDialog) { return; } DisplaySettingsBorders* dsb = theMainWindow->getBrainSet()->getDisplaySettingsBorders(); dsb->setDisplayBorders(showBordersCheckBox->isChecked()); dsb->setDisplayFlatBordersRaised(showRaisedBordersCheckBox->isChecked()); dsb->setDisplayUncertaintyVector(showUncertaintyBordersCheckBox->isChecked()); dsb->setDisplayFirstLinkRed(showFirstLinkRedBordersCheckBox->isChecked()); dsb->setOverrideBorderColorsWithAreaColors(overrideBorderWithAreaColorsCheckBox->isChecked()); dsb->setDrawMode(static_cast( bordersDrawTypeComboBox->currentIndex())); dsb->setDrawSize(borderSizeSpinBox->value()); dsb->setSymbolType(static_cast(borderSymbolComboBox->currentIndex())); dsb->setOpacity(borderOpacityDoubleSpinBox->value()); dsb->setDrawAsStretchedLinesStretchFactor(unstretchedBordersDoubleSpinBox->value()); dsb->determineDisplayedBorders(); GuiBrainModelOpenGL::updateAllGL(NULL); } /** * read border color page. */ void GuiDisplayControlDialog::readBorderColorPage() { if (pageBorderColor == NULL) { return; } if (creatingDialog) { return; } BorderColorFile* borderColors = theMainWindow->getBrainSet()->getBorderColorFile(); const int numColors = borderColors->getNumberOfColors(); if (numColors == numValidBorderColors) { for (int i = 0; i < numValidBorderColors; i++) { const int colorIndex = borderColorCheckBoxesColorIndex[i]; borderColors->setSelected(colorIndex, borderColorCheckBoxes[i]->isChecked()); } } else { std::cerr << "Number of border color checkboxes does not equal number of border colors." << std::endl; } DisplaySettingsBorders* dsb = theMainWindow->getBrainSet()->getDisplaySettingsBorders(); dsb->determineDisplayedBorders(); GuiBrainModelOpenGL::updateAllGL(NULL); } /** * read border name page. */ void GuiDisplayControlDialog::readBorderNamePage() { if (pageBorderName == NULL) { return; } if (creatingDialog) { return; } BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); for (int j = 0; j < numValidBorderNames; j++) { bmbs->setNameDisplayFlagForBordersWithName(borderNames[j], borderNameCheckBoxes[j]->isChecked()); } DisplaySettingsBorders* dsb = theMainWindow->getBrainSet()->getDisplaySettingsBorders(); dsb->determineDisplayedBorders(); GuiBrainModelOpenGL::updateAllGL(NULL); } /** * Create the deformation field page. */ void GuiDisplayControlDialog::createDeformationFieldPage() { // // Display mode combo box // QLabel* columnLabel = new QLabel("Column "); deformationFieldComboBox = new GuiNodeAttributeColumnSelectionComboBox( GUI_NODE_FILE_TYPE_DEFORMATION_FIELD, false, false, false); QObject::connect(deformationFieldComboBox, SIGNAL(itemSelected(int)), this, SLOT(readDeformationFieldPage())); QLabel* displayModeLabel = new QLabel("Display Mode"); deformationFieldModeComboBox = new QComboBox; deformationFieldModeComboBox->insertItem(DisplaySettingsDeformationField::DISPLAY_MODE_ALL, "All"); deformationFieldModeComboBox->insertItem(DisplaySettingsDeformationField::DISPLAY_MODE_NONE, "None"); deformationFieldModeComboBox->insertItem(DisplaySettingsDeformationField::DISPLAY_MODE_SPARSE, "Sparse"); QObject::connect(deformationFieldModeComboBox, SIGNAL(activated(int)), this, SLOT(readDeformationFieldPage())); // // Sparse distance spin box // QLabel* sparseLabel = new QLabel("Sparse Distance"); deformationFieldSparseDistanceSpinBox = new QSpinBox; deformationFieldSparseDistanceSpinBox->setMinimum(0); deformationFieldSparseDistanceSpinBox->setMaximum(100000); deformationFieldSparseDistanceSpinBox->setSingleStep(1); // // Place items into a grid // QGroupBox* optionsGroupBox = new QGroupBox("Options"); QGridLayout* optionsGroupLayout = new QGridLayout(optionsGroupBox); optionsGroupLayout->addWidget(columnLabel, 0, 0); optionsGroupLayout->addWidget(deformationFieldComboBox, 0, 1, 1, 1, Qt::AlignLeft); optionsGroupLayout->addWidget(displayModeLabel, 1, 0); optionsGroupLayout->addWidget(deformationFieldModeComboBox, 1, 1, 1, 1, Qt::AlignLeft); optionsGroupLayout->addWidget(sparseLabel, 2, 0); optionsGroupLayout->addWidget(deformationFieldSparseDistanceSpinBox, 2, 1, 1, 1, Qt::AlignLeft); optionsGroupLayout->setColumnStretch(0, 0); optionsGroupLayout->setColumnStretch(1, 1); optionsGroupLayout->setColumnStretch(2, 100); optionsGroupBox->setFixedHeight(optionsGroupBox->sizeHint().height()); // // Show on identified nodes // deformationFieldShowIdNodesCheckBox = new QCheckBox("Show Vectors On Identified Nodes"); QObject::connect(deformationFieldShowIdNodesCheckBox, SIGNAL(toggled(bool)), this, SLOT(readDeformationFieldPage())); // // Unstretched on flag check box // deformationFieldShowUnstretchedCheckBox = new QCheckBox("Show Unstretched on Flat Surface "); QObject::connect(deformationFieldShowUnstretchedCheckBox, SIGNAL(toggled(bool)), this, SLOT(readDeformationFieldPage())); deformationFieldUnstretchedDoubleSpinBox = new QDoubleSpinBox; deformationFieldUnstretchedDoubleSpinBox->setMinimum(0.01); deformationFieldUnstretchedDoubleSpinBox->setMaximum(100.0); deformationFieldUnstretchedDoubleSpinBox->setSingleStep(0.5); deformationFieldUnstretchedDoubleSpinBox->setDecimals(2); QObject::connect(deformationFieldUnstretchedDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readDeformationFieldPage())); QHBoxLayout* unstrechLayout = new QHBoxLayout; unstrechLayout->addWidget(deformationFieldShowUnstretchedCheckBox); unstrechLayout->addWidget(deformationFieldUnstretchedDoubleSpinBox); unstrechLayout->addStretch(); // // Page and layout // pageDeformationField = new QWidget; pageWidgetStack->addWidget(pageDeformationField); //, PAGE_NAME_DEFORMATION_FIELD); QVBoxLayout* deformationFieldLayout = new QVBoxLayout(pageDeformationField); deformationFieldLayout->addWidget(optionsGroupBox); deformationFieldLayout->addWidget(deformationFieldShowIdNodesCheckBox); deformationFieldLayout->addLayout(unstrechLayout); deformationFieldLayout->addStretch(); } /** * Read the contents of the deformation field page. */ void GuiDisplayControlDialog::readDeformationFieldPage() { if (creatingDialog) { return; } DisplaySettingsDeformationField* dsdf = theMainWindow->getBrainSet()->getDisplaySettingsDeformationField(); dsdf->setSelectedDisplayColumn(deformationFieldComboBox->currentIndex()); dsdf->setShowUnstretchedOnFlat(deformationFieldUnstretchedDoubleSpinBox->value(), deformationFieldShowUnstretchedCheckBox->isChecked()); dsdf->setDisplayMode(static_cast( deformationFieldModeComboBox->currentIndex())); dsdf->setDisplayIdentifiedNodes(deformationFieldShowIdNodesCheckBox->isChecked()); dsdf->setSparseDisplayDistance(deformationFieldSparseDistanceSpinBox->value()); GuiBrainModelOpenGL::updateAllGL(); } /** * Update the deformation field page. */ void GuiDisplayControlDialog::updateDeformationFieldPage() { updatePageSelectionComboBox(); if (pageDeformationField == NULL) { return; } DisplaySettingsDeformationField* dsdf = theMainWindow->getBrainSet()->getDisplaySettingsDeformationField(); deformationFieldComboBox->updateComboBox(theMainWindow->getBrainSet()->getDeformationFieldFile()); deformationFieldComboBox->setCurrentIndex(dsdf->getSelectedDisplayColumn()); deformationFieldModeComboBox->setCurrentIndex(dsdf->getDisplayMode()); deformationFieldShowIdNodesCheckBox->setChecked(dsdf->getDisplayIdentifiedNodes()); deformationFieldSparseDistanceSpinBox->setValue(dsdf->getSparseDisplayDistance()); bool showUnstretched; float stretchFactor; dsdf->getShowUnstretchedOnFlat(stretchFactor, showUnstretched); deformationFieldShowUnstretchedCheckBox->setChecked(showUnstretched); deformationFieldUnstretchedDoubleSpinBox->setValue(stretchFactor); pageDeformationField->setEnabled(validDeformationFieldData); } /** * Foci page containing main items. */ void GuiDisplayControlDialog::createFociMainPage() { showFociCheckBox = new QCheckBox("Show Foci"); QObject::connect(showFociCheckBox, SIGNAL(toggled(bool)), this, SLOT(showFociToggleSlot(bool))); showVolumeFociCheckBox = new QCheckBox("Show Volume Foci"); QObject::connect(showVolumeFociCheckBox, SIGNAL(toggled(bool)), this, SLOT(readFociMainPage())); showRaisedFociCheckBox = new QCheckBox("Show Raised Foci on Flat Surfaces"); QObject::connect(showRaisedFociCheckBox, SIGNAL(toggled(bool)), this, SLOT(readFociMainPage())); showPastedOnto3DFociCheckBox = new QCheckBox("Show Foci Pasted Onto 3D Surfaces"); QObject::connect(showPastedOnto3DFociCheckBox, SIGNAL(toggled(bool)), this, SLOT(readFociMainPage())); showCorrectHemisphereFociCheckBox = new QCheckBox("Show Foci on Correct Hemisphere Only"); QObject::connect(showCorrectHemisphereFociCheckBox, SIGNAL(toggled(bool)), this, SLOT(readFociMainPage())); QLabel* symbolLabel = new QLabel("Symbol Override "); fociSymbolOverrideComboBox = new QComboBox; std::vector cellOverrideLabels; ColorFile::ColorStorage::getAllSymbolTypesAsStrings(cellOverrideLabels); for (unsigned int i = 0; i < cellOverrideLabels.size(); i++) { fociSymbolOverrideComboBox->addItem(cellOverrideLabels[i]); } QObject::connect(fociSymbolOverrideComboBox, SIGNAL(activated(int)), this, SLOT(readFociMainPage())); QHBoxLayout* symbolLayout = new QHBoxLayout; symbolLayout->addWidget(symbolLabel); symbolLayout->addWidget(fociSymbolOverrideComboBox); symbolLayout->addStretch(); QLabel* spinLabel = new QLabel("Foci Size"); fociSizeSpinBox = new QDoubleSpinBox; fociSizeSpinBox->setMinimum(0.001); fociSizeSpinBox->setMaximum(maxPointSize); fociSizeSpinBox->setSingleStep(0.5); fociSizeSpinBox->setDecimals(3); QObject::connect(fociSizeSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readFociMainPage())); QHBoxLayout* sizeLayout = new QHBoxLayout; sizeLayout->addWidget(spinLabel); sizeLayout->addWidget(fociSizeSpinBox); sizeLayout->addStretch(); QLabel* opacityLabel = new QLabel("Opacity"); fociOpacityDoubleSpinBox = new QDoubleSpinBox; fociOpacityDoubleSpinBox->setMinimum(0.0); fociOpacityDoubleSpinBox->setMaximum(1.0); fociOpacityDoubleSpinBox->setSingleStep(0.01); fociOpacityDoubleSpinBox->setDecimals(3); QObject::connect(fociOpacityDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readFociMainPage())); QHBoxLayout* opacityLayout = new QHBoxLayout; opacityLayout->addWidget(opacityLabel); opacityLayout->addWidget(fociOpacityDoubleSpinBox); opacityLayout->addStretch(); QLabel* distanceLabel = new QLabel("Distance"); fociDistSpinBox = new QDoubleSpinBox; fociDistSpinBox->setMinimum(0.0); fociDistSpinBox->setMaximum(1000.0); fociDistSpinBox->setSingleStep(10.0); fociDistSpinBox->setDecimals(1); fociDistSpinBox->setValue(1000.0); QObject::connect(fociDistSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readFociMainPage())); fociDistSpinBox->setToolTip("Foci whose distances to the surface are\n" "less than this value will be displayed.\n" "The foci must have been projected."); QHBoxLayout* distanceLayout = new QHBoxLayout; distanceLayout->addWidget(distanceLabel); distanceLayout->addWidget(fociDistSpinBox); distanceLayout->addStretch(); // // Display color key button // QPushButton* colorKeyPushButton = new QPushButton("Display Color Key..."); colorKeyPushButton->setFixedSize(colorKeyPushButton->sizeHint()); colorKeyPushButton->setAutoDefault(false); QObject::connect(colorKeyPushButton, SIGNAL(clicked()), theMainWindow, SLOT(displayFociColorKey())); // // Color mode // QLabel* colorModeLabel = new QLabel("Coloring Mode"); fociColorModeComboBox = new QComboBox; fociColorModeComboBox->insertItem(CellBase::CELL_COLOR_MODE_NAME, "Focus Name", static_cast(CellBase::CELL_COLOR_MODE_NAME)); fociColorModeComboBox->insertItem(CellBase::CELL_COLOR_MODE_CLASS, "Focus Class", static_cast(CellBase::CELL_COLOR_MODE_CLASS)); QObject::connect(fociColorModeComboBox, SIGNAL(activated(int)), this, SLOT(slotFociColorModeComboBox(int))); QHBoxLayout* colorModeLayout = new QHBoxLayout; colorModeLayout->addWidget(colorModeLabel); colorModeLayout->addWidget(fociColorModeComboBox); colorModeLayout->addStretch(); // // Widget to hold all foci main itmes // pageFociMain = new QWidget; QVBoxLayout* fociSubPageMainLayout = new QVBoxLayout(pageFociMain); fociSubPageMainLayout->addWidget(showFociCheckBox); fociSubPageMainLayout->addWidget(showVolumeFociCheckBox); fociSubPageMainLayout->addWidget(showRaisedFociCheckBox); fociSubPageMainLayout->addWidget(showPastedOnto3DFociCheckBox); fociSubPageMainLayout->addWidget(showCorrectHemisphereFociCheckBox); fociSubPageMainLayout->addLayout(symbolLayout); fociSubPageMainLayout->addLayout(colorModeLayout); fociSubPageMainLayout->addLayout(sizeLayout); fociSubPageMainLayout->addLayout(opacityLayout); fociSubPageMainLayout->addLayout(distanceLayout); fociSubPageMainLayout->addWidget(colorKeyPushButton); fociSubPageMainLayout->addStretch(); pageWidgetStack->addWidget(pageFociMain); // // Control signals // pageFociMainWidgetGroup = new WuQWidgetGroup(this); pageFociMainWidgetGroup->addWidget(showFociCheckBox); pageFociMainWidgetGroup->addWidget(showVolumeFociCheckBox); pageFociMainWidgetGroup->addWidget(showRaisedFociCheckBox); pageFociMainWidgetGroup->addWidget(showPastedOnto3DFociCheckBox); pageFociMainWidgetGroup->addWidget(showCorrectHemisphereFociCheckBox); pageFociMainWidgetGroup->addWidget(fociSymbolOverrideComboBox); pageFociMainWidgetGroup->addWidget(fociSizeSpinBox); pageFociMainWidgetGroup->addWidget(fociOpacityDoubleSpinBox); pageFociMainWidgetGroup->addWidget(fociDistSpinBox); pageFociMainWidgetGroup->addWidget(fociColorModeComboBox); } /** * called when foci color mode changed. */ void GuiDisplayControlDialog::slotFociColorModeComboBox(int /*i*/) { DisplaySettingsFoci* dsf = theMainWindow->getBrainSet()->getDisplaySettingsFoci(); dsf->setColorMode(static_cast(fociColorModeComboBox->currentIndex())); theMainWindow->getBrainSet()->assignFociColors(); readFociColorPage(); } /** * called when foci name update button is pressed. */ void GuiDisplayControlDialog::fociNamesUpdateButtonPressed() { updateFociNamePage(true); } /** * create the foci name page. */ void GuiDisplayControlDialog::createFociNamePage() { pageFociName = new QWidget; fociSubPageNamesLayout = new QVBoxLayout(pageFociName); pageFociNameWidgetGroup = new WuQWidgetGroup(this); // // Show only foci for displayed names checkbox // fociShowNamesOnlyForDisplayedFociCheckBox = new QCheckBox("List Names Only for Displayed Foci"); fociShowNamesOnlyForDisplayedFociCheckBox->setToolTip( "You must press the \"Update\" button\n" "for this option to take effect."); // // All off and all on pushbuttons // QPushButton* fociNamesAllOnButton = new QPushButton("All On"); fociNamesAllOnButton->setAutoDefault(false); QObject::connect(fociNamesAllOnButton, SIGNAL(clicked()), this, SLOT(fociNamesAllOn())); QPushButton* fociNamesAllOffButton = new QPushButton("All Off"); fociNamesAllOffButton->setAutoDefault(false); QObject::connect(fociNamesAllOffButton, SIGNAL(clicked()), this, SLOT(fociNamesAllOff())); QPushButton* fociNameUpdateButton = new QPushButton("Update"); fociNameUpdateButton->setAutoDefault(false); QObject::connect(fociNameUpdateButton, SIGNAL(clicked()), this, SLOT(fociNamesUpdateButtonPressed())); QHBoxLayout* allOnOffLayout = new QHBoxLayout; allOnOffLayout->addWidget(fociNamesAllOnButton); allOnOffLayout->addWidget(fociNamesAllOffButton); allOnOffLayout->addWidget(fociNameUpdateButton); allOnOffLayout->addWidget(fociShowNamesOnlyForDisplayedFociCheckBox); allOnOffLayout->addStretch(); // // Names check box layout // fociNamesGridLayout = new QGridLayout; const int rowStretchNumber = 15000; fociNamesGridLayout->addWidget(new QLabel(""), rowStretchNumber, 0, Qt::AlignLeft); fociNamesGridLayout->setRowStretch(rowStretchNumber, 1000); fociSubPageNamesLayout->addLayout(allOnOffLayout); fociSubPageNamesLayout->addLayout(fociNamesGridLayout); // // Button group for foci names // fociNamesButtonGroup = new QButtonGroup(this); fociNamesButtonGroup->setExclusive(false); QObject::connect(fociNamesButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(readFociNamePage())); createAndUpdateFociNamesCheckBoxes(); pageWidgetStack->addWidget(pageFociName); } /** * create and update foci names toggles section. */ void GuiDisplayControlDialog::createAndUpdateFociNamesCheckBoxes() { const CellProjectionFile* cpf = theMainWindow->getBrainSet()->getFociProjectionFile(); const int numExistingCheckBoxes = fociNamesCheckBoxes.size(); //const int numValidNames = cpf->getNumberOfCellUniqueNames(); std::vector sortedFociUniqueNameIndices; cpf->getCellUniqueNameIndicesSortedByName(sortedFociUniqueNameIndices, false, fociShowNamesOnlyForDisplayedFociCheckBox->isChecked()); const int numValidNames = static_cast(sortedFociUniqueNameIndices.size()); // // Update existing check boxes // for (int i = 0; i < numExistingCheckBoxes; i++) { if (i < numValidNames) { const int nameIndex = sortedFociUniqueNameIndices[i]; fociNamesCheckBoxesNameIndex[i] = nameIndex; fociNamesCheckBoxes[i]->setText(cpf->getCellUniqueNameByIndex(nameIndex)); fociNamesCheckBoxes[i]->show(); } } // // Add new checkboxes as needed // for (int j = numExistingCheckBoxes; j < numValidNames; j++) { const int nameIndex = sortedFociUniqueNameIndices[j]; fociNamesCheckBoxesNameIndex.push_back(nameIndex); QCheckBox* cb = new QCheckBox(cpf->getCellUniqueNameByIndex(nameIndex)); fociNamesCheckBoxes.push_back(cb); fociNamesGridLayout->addWidget(cb, j, 0, 1, 1, Qt::AlignLeft); fociNamesButtonGroup->addButton(cb); cb->show(); pageFociNameWidgetGroup->addWidget(cb); } // // Set number of displayed checkboxes // numberOfFociNameCheckBoxesShownInGUI = numValidNames; // // Hide existing checkboxes that are not needed // for (int k = numValidNames; k < numExistingCheckBoxes; k++) { fociNamesCheckBoxes[k]->hide(); } } /** * called when foci names All On button is pressed. */ void GuiDisplayControlDialog::fociNamesAllOn() { fociNamesButtonGroup->blockSignals(true); //const int numNames = fociNamesCheckBoxes.size(); for (int n = 0; n < numberOfFociNameCheckBoxesShownInGUI; n++) { fociNamesCheckBoxes[n]->setChecked(true); } fociNamesButtonGroup->blockSignals(false); readFociNamePage(); } /** * called when foci names All Off button is pressed. */ void GuiDisplayControlDialog::fociNamesAllOff() { fociNamesButtonGroup->blockSignals(true); //const int numNames = fociNamesCheckBoxes.size(); for (int n = 0; n < numberOfFociNameCheckBoxesShownInGUI; n++) { fociNamesCheckBoxes[n]->setChecked(false); } fociNamesButtonGroup->blockSignals(false); readFociNamePage(); } /** * create the foci keywords page. */ void GuiDisplayControlDialog::createFociKeywordPage() { pageFociKeyword = new QWidget; fociSubPageKeywordsLayout = new QVBoxLayout(pageFociKeyword); pageFociKeywordsWidgetGroup = new WuQWidgetGroup(this); // // Show keywords only for displayed foci // DO NOT CONNECT TO READ PAGE // fociShowKeywordsOnlyForDisplayedFociCheckBox = new QCheckBox("List Keywords Only for Displayed Foci"); fociShowKeywordsOnlyForDisplayedFociCheckBox->setToolTip( "You must press the \"Update\" button\n" "for this option to take effect."); // // All off and all on pushbuttons // QPushButton* fociKeywordsAllOnButton = new QPushButton("All On"); fociKeywordsAllOnButton->setAutoDefault(false); QObject::connect(fociKeywordsAllOnButton, SIGNAL(clicked()), this, SLOT(fociKeywordsAllOn())); QPushButton* fociKeywordsAllOffButton = new QPushButton("All Off"); fociKeywordsAllOffButton->setAutoDefault(false); QObject::connect(fociKeywordsAllOffButton, SIGNAL(clicked()), this, SLOT(fociKeywordsAllOff())); QPushButton* fociKeywordsUpdateButton = new QPushButton("Update"); fociKeywordsUpdateButton->setAutoDefault(false); QObject::connect(fociKeywordsUpdateButton, SIGNAL(clicked()), this, SLOT(fociKeywordsAndTablesUpdate())); fociKeywordsUpdateButton->setToolTip("Update the list of keywords. This may sometimes\n" "be necessary after editing keywords in the study\n" "metadata editor dialog."); QHBoxLayout* allOnOffLayout = new QHBoxLayout; allOnOffLayout->addWidget(fociKeywordsAllOnButton); allOnOffLayout->addWidget(fociKeywordsAllOffButton); allOnOffLayout->addWidget(fociKeywordsUpdateButton); allOnOffLayout->addWidget(fociShowKeywordsOnlyForDisplayedFociCheckBox); allOnOffLayout->addStretch(); fociWithoutLinkToStudyWithKeywordsCheckBox = new QCheckBox("Show Foci Without Link to Study With Keywords"); fociWithoutLinkToStudyWithKeywordsCheckBox->setToolTip("If this item is checked, foci wthout\n" "a link to study metadata with keyword\n" "will be displayed."); QObject::connect(fociWithoutLinkToStudyWithKeywordsCheckBox, SIGNAL(toggled(bool)), this, SLOT(readFociKeywordPage())); pageFociKeywordsWidgetGroup->addWidget(fociWithoutLinkToStudyWithKeywordsCheckBox); // // Keywords check box layout // fociKeywordGridLayout = new QGridLayout; const int rowStretchNumber = 15000; fociKeywordGridLayout->addWidget(new QLabel(""), rowStretchNumber, 0, Qt::AlignLeft); fociKeywordGridLayout->setRowStretch(rowStretchNumber, 1000); fociSubPageKeywordsLayout->addLayout(allOnOffLayout); fociSubPageKeywordsLayout->addWidget(fociWithoutLinkToStudyWithKeywordsCheckBox); fociSubPageKeywordsLayout->addLayout(fociKeywordGridLayout); // // Button group for foci keywords // fociKeywordButtonGroup = new QButtonGroup(this); fociKeywordButtonGroup->setExclusive(false); QObject::connect(fociKeywordButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(readFociKeywordPage())); createAndUpdateFociKeywordCheckBoxes(); pageWidgetStack->addWidget(pageFociKeyword); } /** * called when foci keywords Update button is pressed. */ void GuiDisplayControlDialog::fociKeywordsAndTablesUpdate() { BrainSet* bs = theMainWindow->getBrainSet(); bs->getDisplaySettingsStudyMetaData()->update(); bs->getDisplaySettingsFoci()->update(); bs->assignFociColors(); GuiFilesModified fm; fm.setFociModified(); fm.setStudyMetaDataModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } /** * called when foci keywords All On button is pressed. */ void GuiDisplayControlDialog::fociKeywordsAllOn() { fociKeywordButtonGroup->blockSignals(true); //const int numKeywords = fociKeywordCheckBoxes.size(); for (int k = 0; k < numberOfFociKeywordCheckBoxesShownInGUI; k++) { fociKeywordCheckBoxes[k]->setChecked(true); } fociKeywordButtonGroup->blockSignals(false); readFociKeywordPage(); } /** * called when foci keywords All Off button is pressed. */ void GuiDisplayControlDialog::fociKeywordsAllOff() { fociKeywordButtonGroup->blockSignals(true); //const int numKeywords = fociKeywordCheckBoxes.size(); for (int k = 0; k < numberOfFociKeywordCheckBoxesShownInGUI; k++) { fociKeywordCheckBoxes[k]->setChecked(false); } fociKeywordButtonGroup->blockSignals(false); readFociKeywordPage(); } /** * create and update foci keywords toggles section. */ void GuiDisplayControlDialog::createAndUpdateFociKeywordCheckBoxes() { const int numExistingCheckBoxes = fociKeywordCheckBoxes.size(); const DisplaySettingsStudyMetaData* dssmd = theMainWindow->getBrainSet()->getDisplaySettingsStudyMetaData(); //const int numValidKeywords = dssmd->getNumberOfKeywords(); std::vector sortedFociKeywordIndices; dssmd->getKeywordIndicesSortedByName(sortedFociKeywordIndices, false, fociShowKeywordsOnlyForDisplayedFociCheckBox->isChecked()); const int numValidKeywords = static_cast(sortedFociKeywordIndices.size()); // // Update existing check boxes // for (int i = 0; i < numExistingCheckBoxes; i++) { if (i < numValidKeywords) { const int nameIndex = sortedFociKeywordIndices[i]; fociKeywordCheckBoxesKeywordIndex[i] = nameIndex; fociKeywordCheckBoxes[i]->setText(dssmd->getKeywordNameByIndex(nameIndex)); fociKeywordCheckBoxes[i]->show(); } } // // Add new checkboxes as needed // for (int j = numExistingCheckBoxes; j < numValidKeywords; j++) { const int keywordIndex = sortedFociKeywordIndices[j]; fociKeywordCheckBoxesKeywordIndex.push_back(keywordIndex); QCheckBox* cb = new QCheckBox(dssmd->getKeywordNameByIndex(keywordIndex)); fociKeywordCheckBoxes.push_back(cb); fociKeywordGridLayout->addWidget(cb, j, 0, 1, 1, Qt::AlignLeft); fociKeywordButtonGroup->addButton(cb); cb->show(); pageFociKeywordsWidgetGroup->addWidget(cb); } // // Update number of displayed checkboxes // numberOfFociKeywordCheckBoxesShownInGUI = numValidKeywords; // // Hide existing checkboxes that are not needed. // for (int k = numValidKeywords; k < numExistingCheckBoxes; k++) { fociKeywordCheckBoxes[k]->hide(); } } /** * create the foci tables page. */ void GuiDisplayControlDialog::createFociTablePage() { pageFociTable = new QWidget; fociSubPageTablesLayout = new QVBoxLayout(pageFociTable); pageFociTableWidgetGroup = new WuQWidgetGroup(this); // // Show keywords only for displayed foci // DO NOT CONNECT TO READ PAGE // fociShowTablesOnlyForDisplayedFociCheckBox = new QCheckBox("List Tables Only for Displayed Foci"); fociShowTablesOnlyForDisplayedFociCheckBox->setToolTip( "You must press the \"Update\" button\n" "for this option to take effect."); // // All off and all on pushbuttons // QPushButton* fociTablesAllOnButton = new QPushButton("All On"); fociTablesAllOnButton->setAutoDefault(false); QObject::connect(fociTablesAllOnButton, SIGNAL(clicked()), this, SLOT(fociTablesAllOn())); QPushButton* fociTablesAllOffButton = new QPushButton("All Off"); fociTablesAllOffButton->setAutoDefault(false); QObject::connect(fociTablesAllOffButton, SIGNAL(clicked()), this, SLOT(fociTablesAllOff())); QPushButton* fociTablesUpdateButton = new QPushButton("Update"); fociTablesUpdateButton->setAutoDefault(false); QObject::connect(fociTablesUpdateButton, SIGNAL(clicked()), this, SLOT(fociKeywordsAndTablesUpdate())); fociTablesUpdateButton->setToolTip("Update the list of tables. This may sometimes\n" "be necessary after editing tables in the study\n" "metadata editor dialog."); QHBoxLayout* allOnOffLayout = new QHBoxLayout; allOnOffLayout->addWidget(fociTablesAllOnButton); allOnOffLayout->addWidget(fociTablesAllOffButton); allOnOffLayout->addWidget(fociTablesUpdateButton); allOnOffLayout->addWidget(fociShowTablesOnlyForDisplayedFociCheckBox); allOnOffLayout->addStretch(); fociWithoutLinkToStudyWithTableSubHeaderCheckBox = new QCheckBox("Show Foci Without Link to Table Subheader"); fociWithoutLinkToStudyWithTableSubHeaderCheckBox->setToolTip("If this item is checked, foci wthout\n" "a link to study metadata table subheader\n" "will be displayed."); QObject::connect(fociWithoutLinkToStudyWithTableSubHeaderCheckBox, SIGNAL(toggled(bool)), this, SLOT(readFociTablePage())); // // Tables check box layout // fociTablesGridLayout = new QGridLayout; const int rowStretchNumber = 15000; fociTablesGridLayout->addWidget(new QLabel(""), rowStretchNumber, 0, Qt::AlignLeft); fociTablesGridLayout->setRowStretch(rowStretchNumber, 1000); fociSubPageTablesLayout->addLayout(allOnOffLayout); fociSubPageTablesLayout->addWidget(fociWithoutLinkToStudyWithTableSubHeaderCheckBox); fociSubPageTablesLayout->addLayout(fociTablesGridLayout); // // Button group for foci tables // fociTablesButtonGroup = new QButtonGroup(this); fociTablesButtonGroup->setExclusive(false); QObject::connect(fociTablesButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(readFociTablePage())); createAndUpdateFociTableCheckBoxes(); pageWidgetStack->addWidget(pageFociTable); } /** * called when foci tables All On button is pressed. */ void GuiDisplayControlDialog::fociTablesAllOn() { fociTablesButtonGroup->blockSignals(true); //const int numTables = fociTablesCheckBoxes.size(); for (int k = 0; k < numberOfFociTableCheckBoxesShownInGUI; k++) { fociTablesCheckBoxes[k]->setChecked(true); } fociTablesButtonGroup->blockSignals(false); readFociTablePage(); } /** * called when foci tables All Off button is pressed. */ void GuiDisplayControlDialog::fociTablesAllOff() { fociTablesButtonGroup->blockSignals(true); //const int numTables = fociTablesCheckBoxes.size(); for (int k = 0; k < numberOfFociTableCheckBoxesShownInGUI; k++) { fociTablesCheckBoxes[k]->setChecked(false); } fociTablesButtonGroup->blockSignals(false); readFociTablePage(); } /** * create and update foci table toggles section. */ void GuiDisplayControlDialog::createAndUpdateFociTableCheckBoxes() { const int numExistingCheckBoxes = fociTablesCheckBoxes.size(); const DisplaySettingsStudyMetaData* dssmd = theMainWindow->getBrainSet()->getDisplaySettingsStudyMetaData(); //const int numValidTables = dssmd->getNumberOfSubHeaderNames(); std::vector sortedFociTableNameIndices; dssmd->getSubHeaderIndicesSortedByName(sortedFociTableNameIndices, false, fociShowTablesOnlyForDisplayedFociCheckBox->isChecked()); const int numValidTables = static_cast(sortedFociTableNameIndices.size()); // // Update existing check boxes // for (int i = 0; i < numExistingCheckBoxes; i++) { if (i < numValidTables) { const int tableIndex = sortedFociTableNameIndices[i]; fociTablesCheckBoxesTableIndex[i] = tableIndex; fociTablesCheckBoxes[i]->setText(dssmd->getSubHeaderNameByIndex(tableIndex)); fociTablesCheckBoxes[i]->show(); } } // // Add new checkboxes as needed // for (int j = numExistingCheckBoxes; j < numValidTables; j++) { const int tableIndex = sortedFociTableNameIndices[j]; fociTablesCheckBoxesTableIndex.push_back(tableIndex); QCheckBox* cb = new QCheckBox(dssmd->getSubHeaderNameByIndex(tableIndex)); fociTablesCheckBoxes.push_back(cb); fociTablesGridLayout->addWidget(cb, j, 0, 1, 1, Qt::AlignLeft); fociTablesButtonGroup->addButton(cb); cb->show(); pageFociTableWidgetGroup->addWidget(cb); } // // Number of displayed checkboxes // numberOfFociTableCheckBoxesShownInGUI = numValidTables; // // Hide existing checkboxes that are not needed. // for (int k = numValidTables; k < numExistingCheckBoxes; k++) { fociTablesCheckBoxes[k]->hide(); } } /** * Foci page containing class selections. */ void GuiDisplayControlDialog::createFociClassPage() { // // Vertical Box Layout for all foci items // pageFociClass = new QWidget; fociSubPageClassLayout = new QVBoxLayout(pageFociClass); pageFociClassWidgetGroup = new WuQWidgetGroup(this); // // Show only foci for displayed classes checkbox // fociShowClassesOnlyForDisplayedFociCheckBox = new QCheckBox("List Classes Only for Displayed Foci"); fociShowClassesOnlyForDisplayedFociCheckBox->setToolTip( "You must press the \"Update\" button\n" "for this option to take effect."); // // All off and all on pushbuttons // QPushButton* fociClassAllOnButton = new QPushButton("All On"); fociClassAllOnButton->setAutoDefault(false); QObject::connect(fociClassAllOnButton, SIGNAL(clicked()), this, SLOT(fociClassAllOn())); QPushButton* fociClassAllOffButton = new QPushButton("All Off"); fociClassAllOffButton->setAutoDefault(false); QObject::connect(fociClassAllOffButton, SIGNAL(clicked()), this, SLOT(fociClassAllOff())); QPushButton* fociClassUpdateButton = new QPushButton("Update"); fociClassUpdateButton->setAutoDefault(false); QObject::connect(fociClassUpdateButton, SIGNAL(clicked()), this, SLOT(fociClassUpdateButtonPressed())); QHBoxLayout* allOnOffLayout = new QHBoxLayout; allOnOffLayout->addWidget(fociClassAllOnButton); allOnOffLayout->addWidget(fociClassAllOffButton); allOnOffLayout->addWidget(fociClassUpdateButton); allOnOffLayout->addWidget(fociShowClassesOnlyForDisplayedFociCheckBox); allOnOffLayout->addStretch(); fociWithoutClassAssignmentsCheckBox = new QCheckBox("Show Foci Without Class Assignments"); fociWithoutClassAssignmentsCheckBox->setToolTip("If this item is checked, foci wthout\n" "a class assignment will be displayed."); QObject::connect(fociWithoutClassAssignmentsCheckBox, SIGNAL(toggled(bool)), this, SLOT(readFociClassPage())); pageFociClassWidgetGroup->addWidget(fociWithoutClassAssignmentsCheckBox); fociSubPageClassLayout->addLayout(allOnOffLayout); fociSubPageClassLayout->addWidget(fociWithoutClassAssignmentsCheckBox); createAndUpdateFociClassCheckBoxes(); pageWidgetStack->addWidget(pageFociClass); } /** * Create and update foci class checkboxes. Because the number of foci may change, * this method may update and change the label on existing checkboxes, add new * checkboxes, and hide existing checkboxes if the number of checkboxes is greater * than the number of foci classes. */ void GuiDisplayControlDialog::createAndUpdateFociClassCheckBoxes() { FociProjectionFile* ff = theMainWindow->getBrainSet()->getFociProjectionFile(); //numValidFociClasses = ff->getNumberOfCellClasses(); std::vector sortedFociClassIndices; ff->getCellClassIndicesSortedByName(sortedFociClassIndices, false, fociShowClassesOnlyForDisplayedFociCheckBox->isChecked()); const int numValidFociClasses = static_cast(sortedFociClassIndices.size()); const int numExistingCheckBoxes = static_cast(fociClassCheckBoxes.size()); if (fociClassGridLayout == NULL) { QWidget* classWidget = new QWidget; fociClassGridLayout = new QGridLayout(classWidget); const int rowStretchNumber = 15000; fociClassGridLayout->addWidget(new QLabel(""), rowStretchNumber, 0, Qt::AlignLeft); fociClassGridLayout->setRowStretch(rowStretchNumber, 1000); fociSubPageClassLayout->addWidget(classWidget); } if (fociClassButtonGroup == NULL) { fociClassButtonGroup = new QButtonGroup(this); fociClassButtonGroup->setExclusive(false); QObject::connect(fociClassButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(readFociClassPage())); } // // Update exising checkboxes // for (int i = 0; i < numExistingCheckBoxes; i++) { if (i < numValidFociClasses) { const int classIndex = sortedFociClassIndices[i]; QString name(ff->getCellClassNameByIndex(classIndex)); if (name.isEmpty()) { name = "\"Foci that are NOT members of any class\""; } fociClassCheckBoxesColorIndex[i] = classIndex; fociClassCheckBoxes[i]->setText(name); fociClassCheckBoxes[i]->show(); } } // // Add new checkboxes as needed // for (int j = numExistingCheckBoxes; j < numValidFociClasses; j++) { const int classIndex = sortedFociClassIndices[j]; fociClassCheckBoxesColorIndex.push_back(classIndex); QCheckBox* cb = new QCheckBox(ff->getCellClassNameByIndex(classIndex)); fociClassCheckBoxes.push_back(cb); fociClassButtonGroup->addButton(cb, j); fociClassGridLayout->addWidget(cb, j, 0, 1, 1, Qt::AlignLeft); cb->show(); pageFociClassWidgetGroup->addWidget(cb); } // // Set number of classes displayed // numberOfFociClassCheckBoxesShownInGUI = numValidFociClasses; // // Hide existing checkboxes that are not needed. // for (int k = numValidFociClasses; k < numExistingCheckBoxes; k++) { fociClassCheckBoxes[k]->hide(); } } /** * This slot is called when the foci class all on button is pressed. */ void GuiDisplayControlDialog::fociClassAllOn() { //FociProjectionFile* ff = theMainWindow->getBrainSet()->getFociProjectionFile(); //if (ff != NULL) { //ff->setAllCellClassStatus(true); //} //updateFociItems(); fociClassButtonGroup->blockSignals(true); for (int i = 0; i < numberOfFociClassCheckBoxesShownInGUI; i++) { fociClassCheckBoxes[i]->setChecked(true); } fociClassButtonGroup->blockSignals(false); readFociClassPage(); } /** * called when foci class update button is pressed. */ void GuiDisplayControlDialog::fociClassUpdateButtonPressed() { updateFociClassPage(true); } /** * This slot is called when the foci class all off button is pressed. */ void GuiDisplayControlDialog::fociClassAllOff() { //FociProjectionFile* ff = theMainWindow->getBrainSet()->getFociProjectionFile(); //if (ff != NULL) { // //ff->setAllCellClassStatus(false); // for (int i = 0; i < numberOfFociClassCheckBoxesShownInGUI; i++) { // fociClassCheckBoxes[i]->setChecked(false); // } //} //updateFociItems(); fociClassButtonGroup->blockSignals(true); for (int i = 0; i < numberOfFociClassCheckBoxesShownInGUI; i++) { fociClassCheckBoxes[i]->setChecked(false); } fociClassButtonGroup->blockSignals(false); readFociClassPage(); } /** * create foci search page. */ void GuiDisplayControlDialog::createFociSearchPage() { // // Control of searched foci // showFociInSearchCheckBox = new QCheckBox("Show Only Foci Meeting Search Parameters"); QObject::connect(showFociInSearchCheckBox, SIGNAL(toggled(bool)), this, SLOT(showFociInSearchToggleSlot(bool))); // // The search widget // fociSearchWidget = new GuiFociSearchWidget(theMainWindow->getBrainSet()->getFociProjectionFile(), theMainWindow->getBrainSet()->getFociSearchFile(), false); // // Widget and layout for page // pageFociSearch = new QWidget; QVBoxLayout* layout = new QVBoxLayout(pageFociSearch); layout->addWidget(showFociInSearchCheckBox); layout->addWidget(fociSearchWidget); layout->addStretch(); pageWidgetStack->addWidget(pageFociSearch); updateFociSearchPage(true); } /** * called when foci in search toggled. */ void GuiDisplayControlDialog::showFociInSearchToggleSlot(bool) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); DisplaySettingsFoci* dsf = theMainWindow->getBrainSet()->getDisplaySettingsFoci(); try { dsf->setDisplayCellsOnlyIfInSearch(showFociInSearchCheckBox->isChecked()); QApplication::restoreOverrideCursor(); } catch (FileException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); } dsf->determineDisplayedFoci(); GuiBrainModelOpenGL::updateAllGL(); } /** * update foci search page. */ void GuiDisplayControlDialog::updateFociSearchPage(const bool /*filesChanged*/) { if (pageFociSearch == NULL) { return; } DisplaySettingsFoci* dsf = theMainWindow->getBrainSet()->getDisplaySettingsFoci(); showFociInSearchCheckBox->blockSignals(true); showFociInSearchCheckBox->setChecked(dsf->getDislayCellsOnlyIfInSearch()); showFociInSearchCheckBox->blockSignals(false); fociSearchWidget->updateWidget(theMainWindow->getBrainSet()->getFociProjectionFile(), theMainWindow->getBrainSet()->getFociSearchFile()); } /** * read the foci search page. */ void GuiDisplayControlDialog::readFociSearchPage(const bool /*updateDisplay*/) { if (pageFociSearch == NULL) { return; } } /** * called when foci color update button is pressed. */ void GuiDisplayControlDialog::fociColorUpdateButtonPressed() { updateFociColorPage(true); } /** * Foci page containing color selections. */ void GuiDisplayControlDialog::createFociColorPage() { // // Vertical Box Layout for all foci items // pageFociColor = new QWidget; fociSubPageColorLayout = new QVBoxLayout(pageFociColor); // // Show only foci for displayed names checkbox // fociShowColorsOnlyForDisplayedFociCheckBox = new QCheckBox("List Colors Only for Displayed Foci"); fociShowColorsOnlyForDisplayedFociCheckBox->setToolTip( "You must press the \"Update\" button\n" "for this option to take effect."); // // All off and all on pushbuttons // QPushButton* fociColorAllOnButton = new QPushButton("All On"); fociColorAllOnButton->setAutoDefault(false); QObject::connect(fociColorAllOnButton, SIGNAL(clicked()), this, SLOT(fociColorAllOn())); QPushButton* fociColorAllOffButton = new QPushButton("All Off"); fociColorAllOffButton->setAutoDefault(false); QObject::connect(fociColorAllOffButton, SIGNAL(clicked()), this, SLOT(fociColorAllOff())); QPushButton* fociColorUpdateButton = new QPushButton("Update"); fociColorUpdateButton->setAutoDefault(false); QObject::connect(fociColorUpdateButton, SIGNAL(clicked()), this, SLOT(fociColorUpdateButtonPressed())); QHBoxLayout* allOnOffLayout = new QHBoxLayout; allOnOffLayout->addWidget(fociColorAllOnButton); allOnOffLayout->addWidget(fociColorAllOffButton); allOnOffLayout->addWidget(fociColorUpdateButton); allOnOffLayout->addWidget(fociShowColorsOnlyForDisplayedFociCheckBox); allOnOffLayout->addStretch(); pageFociColorWidgetGroup = new WuQWidgetGroup(this); fociWithoutMatchingColorCheckBox = new QCheckBox("Show Foci Without Color Assigments"); fociWithoutMatchingColorCheckBox->setToolTip("If this item is checked, foci wthout\n" "a color assignment will be displayed."); QObject::connect(fociWithoutMatchingColorCheckBox, SIGNAL(toggled(bool)), this, SLOT(readFociColorPage())); pageFociColorWidgetGroup->addWidget(fociWithoutMatchingColorCheckBox); fociSubPageColorLayout->addLayout(allOnOffLayout); fociSubPageColorLayout->addWidget(fociWithoutMatchingColorCheckBox); createAndUpdateFociColorCheckBoxes(); pageWidgetStack->addWidget(pageFociColor); } /** * Create and update foci color checkboxes. Because the number of colors may change, * this method may update and change the label on existing checkboxes, add new * checkboxes, and hide existing checkboxes if the number of checkboxes is greater * than the number of foci colors. */ void GuiDisplayControlDialog::createAndUpdateFociColorCheckBoxes() { FociColorFile* fociColors = theMainWindow->getBrainSet()->getFociColorFile(); //numValidFociColors = fociColors->getNumberOfColors(); std::vector sortedFociColorIndices; fociColors->getColorIndicesSortedByName(theMainWindow->getBrainSet()->getFociProjectionFile(), sortedFociColorIndices, false, fociShowColorsOnlyForDisplayedFociCheckBox->isChecked()); const int numValidFociColors = static_cast(sortedFociColorIndices.size()); const int numExistingCheckBoxes = static_cast(fociColorCheckBoxes.size()); if (fociColorGridLayout == NULL) { QWidget* colorWidget = new QWidget; fociColorGridLayout = new QGridLayout(colorWidget); const int rowStretchNumber = 15000; fociColorGridLayout->addWidget(new QLabel(""), rowStretchNumber, 0, Qt::AlignLeft); fociColorGridLayout->setRowStretch(rowStretchNumber, 1000); fociSubPageColorLayout->addWidget(colorWidget); } if (fociColorButtonGroup == NULL) { fociColorButtonGroup = new QButtonGroup(this); fociColorButtonGroup->setExclusive(false); QObject::connect(fociColorButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(readFociColorPage())); } // // Update exising checkboxes // for (int i = 0; i < numExistingCheckBoxes; i++) { if (i < numValidFociColors) { const int colorIndex = sortedFociColorIndices[i]; fociColorCheckBoxesColorIndex[i] = colorIndex; fociColorCheckBoxes[i]->setText(fociColors->getColorNameByIndex(colorIndex)); fociColorCheckBoxes[i]->show(); } } // // Add new checkboxes as needed // for (int j = numExistingCheckBoxes; j < numValidFociColors; j++) { const int colorIndex = sortedFociColorIndices[j]; fociColorCheckBoxesColorIndex.push_back(colorIndex); QCheckBox* cb = new QCheckBox(fociColors->getColorNameByIndex(colorIndex)); fociColorCheckBoxes.push_back(cb); fociColorButtonGroup->addButton(cb, j); fociColorGridLayout->addWidget(cb, j, 0, 1, 1, Qt::AlignLeft); cb->show(); pageFociColorWidgetGroup->addWidget(cb); } // // Set number of checkboxes displayed // numberOfFociColorCheckBoxesShownInGUI = numValidFociColors; // // Hide existing checkboxes that are not needed. // for (int k = numValidFociColors; k < numExistingCheckBoxes; k++) { fociColorCheckBoxes[k]->hide(); } } /** * This slot is called when the foci color all on button is pressed. */ void GuiDisplayControlDialog::fociColorAllOn() { //FociColorFile* fociColors = theMainWindow->getBrainSet()->getFociColorFile(); //fociColors->setAllSelectedStatus(true); //updateFociItems(); fociColorButtonGroup->blockSignals(true); for (int i = 0; i < numberOfFociColorCheckBoxesShownInGUI; i++) { fociColorCheckBoxes[i]->setChecked(true); } fociColorButtonGroup->blockSignals(false); readFociColorPage(); } /** * This slot is called when the foci color all off button is pressed. */ void GuiDisplayControlDialog::fociColorAllOff() { //FociColorFile* fociColors = theMainWindow->getBrainSet()->getFociColorFile(); //fociColors->setAllSelectedStatus(false); //updateFociItems(); fociColorButtonGroup->blockSignals(true); for (int i = 0; i < numberOfFociColorCheckBoxesShownInGUI; i++) { fociColorCheckBoxes[i]->setChecked(false); } fociColorButtonGroup->blockSignals(false); readFociColorPage(); } /** * update foci main page. */ void GuiDisplayControlDialog::updateFociMainPage() { if (pageFociMain == NULL) { return; } pageFociMainWidgetGroup->blockSignals(true); DisplaySettingsCells* dsc = theMainWindow->getBrainSet()->getDisplaySettingsFoci(); showFociCheckBox->setChecked(dsc->getDisplayCells()); showVolumeFociCheckBox->setChecked(dsc->getDisplayVolumeCells()); showRaisedFociCheckBox->setChecked(dsc->getDisplayFlatCellsRaised()); showPastedOnto3DFociCheckBox->setChecked(dsc->getDisplayPasteCellsOnto3D()); showCorrectHemisphereFociCheckBox->setChecked(dsc->getDisplayCellsOnCorrectHemisphereOnly()); fociSymbolOverrideComboBox->setCurrentIndex(dsc->getSymbolOverride()); fociSizeSpinBox->setValue(dsc->getDrawSize()); fociDistSpinBox->setValue(dsc->getDistanceToSurfaceLimit()); fociOpacityDoubleSpinBox->setValue(dsc->getOpacity()); fociColorModeComboBox->setCurrentIndex(static_cast(dsc->getColorMode())); pageFociMain->setEnabled(validFociData); pageFociMainWidgetGroup->blockSignals(false); } /** * update foci class page. */ void GuiDisplayControlDialog::updateFociClassPage(const bool filesChanged) { if (pageFociClass == NULL) { return; } pageFociClassWidgetGroup->blockSignals(true); if (filesChanged) { createAndUpdateFociClassCheckBoxes(); } FociProjectionFile* ff = theMainWindow->getBrainSet()->getFociProjectionFile(); DisplaySettingsCells* dsc = theMainWindow->getBrainSet()->getDisplaySettingsFoci(); fociWithoutClassAssignmentsCheckBox->setChecked(dsc->getDisplayCellsWithoutClassAssignments()); fociClassButtonGroup->blockSignals(true); int numClasses = 0; if (ff != NULL) { numClasses = ff->getNumberOfCellClasses(); } for (int i = 0; i < numberOfFociClassCheckBoxesShownInGUI; i++) { const int classIndex = fociClassCheckBoxesColorIndex[i]; if (classIndex < numClasses) { fociClassCheckBoxes[i]->setChecked(ff->getCellClassSelectedByIndex(classIndex)); } } /* if (numClasses == numValidFociClasses) { for (int i = 0; i < numValidFociClasses; i++) { const int classIndex = fociClassCheckBoxesColorIndex[i]; fociClassCheckBoxes[i]->setChecked(ff->getCellClassSelectedByIndex(classIndex)); } } else { std::cerr << "Number of foci class checkboxes does not equal number of foci classes." << std::endl; } */ fociClassButtonGroup->blockSignals(false); pageFociClass->setEnabled(validFociData); pageFociClassWidgetGroup->blockSignals(false); } /** * update foci color page. */ void GuiDisplayControlDialog::updateFociColorPage(const bool filesChanged) { if (pageFociColor == NULL) { return; } pageFociColorWidgetGroup->blockSignals(true); if (filesChanged) { createAndUpdateFociColorCheckBoxes(); } DisplaySettingsCells* dsc = theMainWindow->getBrainSet()->getDisplaySettingsFoci(); fociWithoutMatchingColorCheckBox->setChecked(dsc->getDisplayCellsWithoutMatchingColor()); fociColorButtonGroup->blockSignals(true); FociColorFile* fociColors = theMainWindow->getBrainSet()->getFociColorFile(); const int numColors = fociColors->getNumberOfColors(); for (int i = 0; i < numberOfFociColorCheckBoxesShownInGUI; i++) { const int colorIndex = fociColorCheckBoxesColorIndex[i]; if (colorIndex < numColors) { fociColorCheckBoxes[i]->setChecked(fociColors->getSelected(colorIndex)); } } /* if (numColors == numValidFociColors) { for (int i = 0; i < numValidFociColors; i++) { const int colorIndex = fociColorCheckBoxesColorIndex[i]; fociColorCheckBoxes[i]->setChecked(fociColors->getSelected(colorIndex)); } } else { std::cerr << "Number of foci color checkboxes does not equal number of foci colors." << std::endl; } */ fociColorButtonGroup->blockSignals(false); pageFociColor->setEnabled(validFociData); pageFociColorWidgetGroup->blockSignals(false); } /** * update foci keyword page. */ void GuiDisplayControlDialog::updateFociKeywordPage(const bool filesChanged) { if (pageFociKeyword == NULL) { return; } if (filesChanged) { createAndUpdateFociKeywordCheckBoxes(); } fociKeywordButtonGroup->blockSignals(true); DisplaySettingsCells* dsc = theMainWindow->getBrainSet()->getDisplaySettingsFoci(); fociWithoutLinkToStudyWithKeywordsCheckBox->blockSignals(true); fociWithoutLinkToStudyWithKeywordsCheckBox->setChecked(dsc->getDisplayCellsWithoutLinkToStudyWithKeywords()); fociWithoutLinkToStudyWithKeywordsCheckBox->blockSignals(false); //const int numKeywordsInGUI = fociKeywordCheckBoxes.size(); const DisplaySettingsStudyMetaData* dssmd = theMainWindow->getBrainSet()->getDisplaySettingsStudyMetaData(); const int numValidKeywords = dssmd->getNumberOfKeywords(); for (int k = 0; k < numberOfFociKeywordCheckBoxesShownInGUI; k++) { const int keywordIndex = fociKeywordCheckBoxesKeywordIndex[k]; if (keywordIndex < numValidKeywords) { fociKeywordCheckBoxes[k]->setChecked(dssmd->getKeywordSelected(keywordIndex)); } } /* if (numValidKeywords <= numKeywordsInGUI) { for (int k = 0; k < numValidKeywords; k++) { const int keywordIndex = fociKeywordCheckBoxesKeywordIndex[k]; fociKeywordCheckBoxes[k]->setChecked(dssmd->getKeywordSelected(keywordIndex)); } } else { std::cout << "Number of foci keyword checkboxes is less than number of study metadata keywords." << std::endl; } */ fociKeywordButtonGroup->blockSignals(false); pageFociKeyword->setEnabled(validFociData); } /** * update foci name page. */ void GuiDisplayControlDialog::updateFociNamePage(const bool filesChanged) { if (pageFociName == NULL) { return; } if (filesChanged) { createAndUpdateFociNamesCheckBoxes(); } FociProjectionFile* ff = theMainWindow->getBrainSet()->getFociProjectionFile(); fociNamesButtonGroup->blockSignals(true); // const int numNamesInGUI = fociNamesCheckBoxes.size(); const int numUniqueNames = ff->getNumberOfCellUniqueNames(); for (int k = 0; k < numberOfFociNameCheckBoxesShownInGUI; k++) { const int nameIndex = fociNamesCheckBoxesNameIndex[k]; if (nameIndex < numUniqueNames) { fociNamesCheckBoxes[k]->setChecked(ff->getCellUniqueNameSelectedByIndex(nameIndex)); } } /* if (numUniqueNames <= numNamesInGUI) { for (int k = 0; k < numUniqueNames; k++) { const int nameIndex = fociNamesCheckBoxesNameIndex[k]; fociNamesCheckBoxes[k]->setChecked(ff->getCellUniqueNameSelectedByIndex(nameIndex)); } } else { std::cout << "Number of foci name checkboxes is less than number of unique names if foci file." << std::endl; } */ fociNamesButtonGroup->blockSignals(false); pageFociName->setEnabled(validFociData); } /** * update foci page. */ void GuiDisplayControlDialog::updateFociTablePage(const bool filesChanged) { if (pageFociTable == NULL) { return; } if (filesChanged) { createAndUpdateFociTableCheckBoxes(); } DisplaySettingsCells* dsc = theMainWindow->getBrainSet()->getDisplaySettingsFoci(); fociWithoutLinkToStudyWithTableSubHeaderCheckBox->blockSignals(true); fociWithoutLinkToStudyWithTableSubHeaderCheckBox->setChecked(dsc->getDisplayCellsWithoutLinkToStudyWithTableSubHeader()); fociWithoutLinkToStudyWithTableSubHeaderCheckBox->blockSignals(false); const DisplaySettingsStudyMetaData* dssmd = theMainWindow->getBrainSet()->getDisplaySettingsStudyMetaData(); fociTablesButtonGroup->blockSignals(true); const int numValidSubHeaders = dssmd->getNumberOfSubHeaderNames(); for (int k = 0; k < numberOfFociTableCheckBoxesShownInGUI; k++) { const int tableIndex = fociTablesCheckBoxesTableIndex[k]; if (tableIndex < numValidSubHeaders) { fociTablesCheckBoxes[k]->setChecked(dssmd->getSubHeaderNameSelected(tableIndex)); } } /* const int numSubHeadersInGUI = fociTablesCheckBoxes.size(); if (numValidSubHeaders <= numSubHeadersInGUI) { for (int k = 0; k < numValidSubHeaders; k++) { const int tableIndex = fociTablesCheckBoxesTableIndex[k]; fociTablesCheckBoxes[k]->setChecked(dssmd->getSubHeaderNameSelected(tableIndex)); } } else { std::cout << "Number of foci subheader checkboxes is less than number of study metadata subheaders." << std::endl; } */ fociTablesButtonGroup->blockSignals(false); pageFociTable->setEnabled(validFociData); } /** * Update all of the foci items in the dialog */ void GuiDisplayControlDialog::updateFociItems(const bool filesChanged) { updatePageSelectionComboBox(); if (pageOverlayUnderlaySurfaceNew != NULL) { DisplaySettingsCells* dsf = theMainWindow->getBrainSet()->getDisplaySettingsFoci(); layersFociCheckBox->setEnabled(validFociData); layersFociCheckBox->setChecked(dsf->getDisplayCells()); } updateFociMainPage(); updateFociClassPage(filesChanged); updateFociColorPage(filesChanged); updateFociKeywordPage(filesChanged); updateFociNamePage(filesChanged); updateFociSearchPage(filesChanged); updateFociTablePage(filesChanged); updatePageSelectionComboBox(); } /** * called when foci selected on foci page or overlay/underlay surface page. */ void GuiDisplayControlDialog::showFociToggleSlot(bool b) { if (pageFociMain != NULL) { showFociCheckBox->blockSignals(true); showFociCheckBox->setChecked(b); showFociCheckBox->blockSignals(false); } if (pageOverlayUnderlaySurfaceNew != NULL) { layersFociCheckBox->blockSignals(true); layersFociCheckBox->setChecked(b); layersFociCheckBox->blockSignals(false); } /* readFociMainPage(false); readFociClassPage(false); readFociColorPage(false); readFociKeywordPage(false); readFociNamePage(false); readFociTablePage(false); */ DisplaySettingsFoci* dsf = theMainWindow->getBrainSet()->getDisplaySettingsFoci(); dsf->setDisplayCells(b); dsf->determineDisplayedFoci(); GuiBrainModelOpenGL::updateAllGL(); } /** * read the foci main page. */ void GuiDisplayControlDialog::readFociMainPage(const bool updateDisplay) { if (pageFociMain == NULL) { return; } if (creatingDialog) { return; } DisplaySettingsFoci* dsf = theMainWindow->getBrainSet()->getDisplaySettingsFoci(); dsf->setDisplayCells(showFociCheckBox->isChecked()); dsf->setDisplayVolumeCells(showVolumeFociCheckBox->isChecked()); dsf->setDisplayFlatCellsRaised(showRaisedFociCheckBox->isChecked()); dsf->setDisplayPasteCellsOnto3D(showPastedOnto3DFociCheckBox->isChecked()); dsf->setDisplayCellsOnCorrectHemisphereOnly(showCorrectHemisphereFociCheckBox->isChecked()); dsf->setSymbolOverride(static_cast( fociSymbolOverrideComboBox->currentIndex())); dsf->setDrawSize(fociSizeSpinBox->value()); dsf->setDistanceToSurfaceLimit(fociDistSpinBox->value()); dsf->setOpacity(fociOpacityDoubleSpinBox->value()); dsf->setColorMode(static_cast(fociColorModeComboBox->currentIndex())); if (updateDisplay) { dsf->determineDisplayedFoci(); GuiBrainModelOpenGL::updateAllGL(); } } /** * read the foci class page. */ void GuiDisplayControlDialog::readFociClassPage(const bool updateDisplay) { if (pageFociClass == NULL) { return; } if (creatingDialog) { return; } FociProjectionFile* ff = theMainWindow->getBrainSet()->getFociProjectionFile(); const int numClasses = ff->getNumberOfCellClasses(); for (int i = 0; i < numberOfFociClassCheckBoxesShownInGUI; i++) { const int classIndex = fociClassCheckBoxesColorIndex[i]; if (classIndex < numClasses) { ff->setCellClassSelectedByIndex(classIndex, fociClassCheckBoxes[i]->isChecked()); } } /* if (numClasses == numValidFociClasses) { for (int i = 0; i < numValidFociClasses; i++) { const int classIndex = fociClassCheckBoxesColorIndex[i]; ff->setCellClassSelectedByIndex(classIndex, fociClassCheckBoxes[i]->isChecked()); } } else { std::cerr << "Number of foci class checkboxes does not equal number of foci classes." << std::endl; } */ DisplaySettingsFoci* dsf = theMainWindow->getBrainSet()->getDisplaySettingsFoci(); dsf->setDisplayCellsWithoutClassAssignments(fociWithoutClassAssignmentsCheckBox->isChecked()); if (updateDisplay) { dsf->determineDisplayedFoci(); GuiBrainModelOpenGL::updateAllGL(); } } /** * read the foci color page. */ void GuiDisplayControlDialog::readFociColorPage(const bool updateDisplay) { if (pageFociColor == NULL) { return; } if (creatingDialog) { return; } FociColorFile* fociColors = theMainWindow->getBrainSet()->getFociColorFile(); const int numColors = fociColors->getNumberOfColors(); for (int i = 0; i < numberOfFociColorCheckBoxesShownInGUI; i++) { const int colorIndex = fociColorCheckBoxesColorIndex[i]; if (colorIndex < numColors) { fociColors->setSelected(colorIndex, fociColorCheckBoxes[i]->isChecked()); } } /* if (numColors == numValidFociColors) { for (int i = 0; i < numValidFociColors; i++) { const int colorIndex = fociColorCheckBoxesColorIndex[i]; fociColors->setSelected(colorIndex, fociColorCheckBoxes[i]->isChecked()); } } else { std::cerr << "Number of foci color checkboxes does not equal number of foci colors." << std::endl; } */ DisplaySettingsFoci* dsf = theMainWindow->getBrainSet()->getDisplaySettingsFoci(); dsf->setDisplayCellsWithoutMatchingColor(fociWithoutMatchingColorCheckBox->isChecked()); if (updateDisplay) { dsf->determineDisplayedFoci(); GuiBrainModelOpenGL::updateAllGL(); } } /** * read the foci keyword page. */ void GuiDisplayControlDialog::readFociKeywordPage(const bool updateDisplay) { if (pageFociKeyword == NULL) { return; } if (creatingDialog) { return; } pageFociKeywordsWidgetGroup->blockSignals(true); //const int numKeywordsInGUI = fociKeywordCheckBoxes.size(); DisplaySettingsStudyMetaData* dssmd = theMainWindow->getBrainSet()->getDisplaySettingsStudyMetaData(); const int numValidKeywords = dssmd->getNumberOfKeywords(); for (int k = 0; k < numberOfFociKeywordCheckBoxesShownInGUI; k++) { const int keywordIndex = fociKeywordCheckBoxesKeywordIndex[k]; if (keywordIndex < numValidKeywords) { dssmd->setKeywordSelected(keywordIndex, fociKeywordCheckBoxes[k]->isChecked()); } } /* if (numValidKeywords <= numKeywordsInGUI) { for (int k = 0; k < numValidKeywords; k++) { const int keywordIndex = fociKeywordCheckBoxesKeywordIndex[k]; dssmd->setKeywordSelected(keywordIndex, fociKeywordCheckBoxes[k]->isChecked()); } } else { std::cout << "Number of foci keyword checkboxes is less than number of study metadata keywords." << std::endl; } */ DisplaySettingsFoci* dsf = theMainWindow->getBrainSet()->getDisplaySettingsFoci(); dsf->setDisplayCellsWithoutLinkToStudyWithKeywords(fociWithoutLinkToStudyWithKeywordsCheckBox->isChecked()); if (updateDisplay) { dsf->determineDisplayedFoci(); GuiBrainModelOpenGL::updateAllGL(); } pageFociKeywordsWidgetGroup->blockSignals(false); } /** * read the foci name page. */ void GuiDisplayControlDialog::readFociNamePage(const bool updateDisplay) { if (pageFociName == NULL) { return; } if (creatingDialog) { return; } pageFociNameWidgetGroup->blockSignals(true); FociProjectionFile* ff = theMainWindow->getBrainSet()->getFociProjectionFile(); const int numNames = ff->getNumberOfCellUniqueNames(); for (int i = 0; i < numberOfFociNameCheckBoxesShownInGUI; i++) { const int nameIndex = fociNamesCheckBoxesNameIndex[i]; if (nameIndex < numNames) { ff->setCellUniqueNameSelectedByIndex(nameIndex, fociNamesCheckBoxes[i]->isChecked()); } } /* if (numNames <= static_cast(fociNamesCheckBoxes.size())) { for (int i = 0; i < numNames; i++) { const int nameIndex = fociNamesCheckBoxesNameIndex[i]; ff->setCellUniqueNameSelectedByIndex(nameIndex, fociNamesCheckBoxes[i]->isChecked()); } } else { std::cerr << "Number of foci unique name checkboxes is too small when reading foci selections" << std::endl; } */ DisplaySettingsFoci* dsf = theMainWindow->getBrainSet()->getDisplaySettingsFoci(); if (updateDisplay) { dsf->determineDisplayedFoci(); GuiBrainModelOpenGL::updateAllGL(); } pageFociNameWidgetGroup->blockSignals(false); } /** * read the foci table page. */ void GuiDisplayControlDialog::readFociTablePage(const bool updateDisplay) { if (pageFociTable == NULL) { return; } if (creatingDialog) { return; } pageFociTableWidgetGroup->blockSignals(true); DisplaySettingsStudyMetaData* dssmd = theMainWindow->getBrainSet()->getDisplaySettingsStudyMetaData(); const int numValidSubHeaders = dssmd->getNumberOfSubHeaderNames(); for (int k = 0; k < numberOfFociTableCheckBoxesShownInGUI; k++) { const int tableIndex = fociTablesCheckBoxesTableIndex[k]; if (tableIndex < numValidSubHeaders) { dssmd->setSubHeaderNameSelected(tableIndex, fociTablesCheckBoxes[k]->isChecked()); } } /* const int numSubHeadersInGUI = fociTablesCheckBoxes.size(); const int numValidSubHeaders = dssmd->getNumberOfSubHeaderNames(); if (numValidSubHeaders <= numSubHeadersInGUI) { for (int k = 0; k < numValidSubHeaders; k++) { const int tableIndex = fociTablesCheckBoxesTableIndex[k]; dssmd->setSubHeaderNameSelected(tableIndex, fociTablesCheckBoxes[k]->isChecked()); } } else { std::cout << "Number of foci subheader checkboxes is less than number of study metadata subheaders." << std::endl; } */ DisplaySettingsFoci* dsf = theMainWindow->getBrainSet()->getDisplaySettingsFoci(); dsf->setDisplayCellsWithoutLinkToStudyWithTableSubHeader(fociWithoutLinkToStudyWithTableSubHeaderCheckBox->isChecked()); if (updateDisplay) { dsf->determineDisplayedFoci(); GuiBrainModelOpenGL::updateAllGL(); } pageFociTableWidgetGroup->blockSignals(false); } /** * update surface coloring mode section. */ void GuiDisplayControlDialog::updateSurfaceColoringModeSection() { if (pageOverlayUnderlaySurfaceNew != NULL) { BrainModelSurfaceNodeColoring* bsnc = theMainWindow->getBrainSet()->getNodeColoring(); const BrainModelSurfaceNodeColoring::COLORING_MODE coloringMode = bsnc->getColoringMode(); const int indx = surfaceColoringModeComboBox->findData( static_cast(coloringMode)); if (indx >= 0) { surfaceColoringModeComboBox->blockSignals(true); surfaceColoringModeComboBox->setCurrentIndex(indx); surfaceColoringModeComboBox->blockSignals(false); } } } /** * called when surface coloring mode is changed. */ void GuiDisplayControlDialog::slotSurfaceColoringModeComboBox() { const int indx = surfaceColoringModeComboBox->currentIndex(); const BrainModelSurfaceNodeColoring::COLORING_MODE coloringMode = static_cast( surfaceColoringModeComboBox->itemData(indx).toInt()); BrainModelSurfaceNodeColoring* bsnc = theMainWindow->getBrainSet()->getNodeColoring(); bsnc->setColoringMode(coloringMode); bsnc->assignColors(); GuiBrainModelOpenGL::updateAllGL(); } /** * called when overlay selection combo box is changed. */ void GuiDisplayControlDialog::slotOverlayNumberComboBox(int /*item*/) { // // Update pages that use the overlay selection combo box // updateArealEstimationItems(); updateMetricSelectionPage(); updatePaintColumnPage(); updateRgbPaintSelectionPage(); updateShapeSelections(); } /** * Called when a new spec file is loaded */ void GuiDisplayControlDialog::newSpecFileLoaded() { slotSurfaceModelIndexComboBox(0); } /** * called when surface model combo box is changed. */ void GuiDisplayControlDialog::slotSurfaceModelIndexComboBox(int item) { if ((item >= 0) && (item < static_cast(surfaceModelIndexComboBoxValues.size()))) { const int prevSurfaceIndex = surfaceModelIndex; surfaceModelIndex = surfaceModelIndexComboBoxValues[item]; // // If switched to all surfaces // if (surfaceModelIndex == -1) { // // Need to copy current selections to ALL // theMainWindow->getBrainSet()->copyOverlaysFromSurface(prevSurfaceIndex); updateAllItemsInDialog(false, false); } surfaceModelIndexComboBox->blockSignals(true); updateOverlayUnderlayItemsNew(); surfaceModelIndexComboBox->blockSignals(false); BrainModelSurfaceNodeColoring* bsnc = theMainWindow->getBrainSet()->getNodeColoring(); bsnc->assignColors(); GuiBrainModelOpenGL::updateAllGL(); } } /** * Update the surface model combo box */ void GuiDisplayControlDialog::updateSurfaceModelComboBoxes() { bool previousSurfaceFound = false; int previousSurfaceIndex = -1; surfaceModelIndexComboBox->clear(); surfaceModelIndexComboBoxValues.clear(); surfaceModelIndexComboBox->addItem("All Surfaces"); surfaceModelIndexComboBoxValues.push_back(-1); for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfBrainModels(); i++) { if (theMainWindow->getBrainSet()->getBrainModelSurface(i) != NULL) { const BrainModel* bm = theMainWindow->getBrainSet()->getBrainModel(i); const QString name(bm->getDescriptiveName()); surfaceModelIndexComboBox->addItem(name); surfaceModelIndexComboBoxValues.push_back(i); if (i == surfaceModelIndex) { previousSurfaceFound = true; previousSurfaceIndex = surfaceModelIndexComboBoxValues.size() - 1; } } } if (previousSurfaceFound) { surfaceModelIndexComboBox->setCurrentIndex(previousSurfaceIndex); } else { surfaceModelIndex = -1; surfaceModelIndexComboBox->setCurrentIndex(0); } } /** * Create a surface model combo box */ void GuiDisplayControlDialog::createSurfaceModelIndexComboBox() { } /** * Page containing overlay/underlay control. */ void GuiDisplayControlDialog::createOverlayUnderlaySurfacePageNew() { pageOverlayUnderlaySurfaceNew = new QWidget; pageWidgetStack->addWidget(pageOverlayUnderlaySurfaceNew); QVBoxLayout* overlayUnderlayMainPageLayout = new QVBoxLayout(pageOverlayUnderlaySurfaceNew); BrainSet* brainSet = theMainWindow->getBrainSet(); for (int i = (brainSet->getNumberOfSurfaceOverlays() - 1); i >= 0; i--) { GuiDisplayControlSurfaceOverlayWidget* sow = new GuiDisplayControlSurfaceOverlayWidget(i, this); surfaceOverlayUnderlayWidgets.push_back(sow); overlayUnderlayMainPageLayout->addWidget(sow); } // // Coloring mode selections // surfaceColoringModeComboBox = new QComboBox; surfaceColoringModeComboBox->addItem("NORMAL", static_cast(BrainModelSurfaceNodeColoring::COLORING_MODE_NORMAL)); surfaceColoringModeComboBox->addItem("BLEND OVERLAYS", static_cast(BrainModelSurfaceNodeColoring::COLORING_MODE_OVERLAY_BLENDING)); QObject::connect(surfaceColoringModeComboBox, SIGNAL(activated(int)), this, SLOT(slotSurfaceColoringModeComboBox())); surfaceColoringModeComboBox->setToolTip( "BLENDING OVERLAYS blends the colors of the primary, secondary,\n" "and tertiary overlays. In this mode, opacities are ignored."); // // Group box for coloring mode // QGroupBox* coloringModeGroupBox = new QGroupBox("Coloring Mode"); QVBoxLayout* coloringModeLayout = new QVBoxLayout(coloringModeGroupBox); coloringModeLayout->addWidget(surfaceColoringModeComboBox); overlayUnderlayMainPageLayout->addWidget(coloringModeGroupBox); // // Layers selections // layersBorderCheckBox = new QCheckBox("Borders "); QObject::connect(layersBorderCheckBox, SIGNAL(toggled(bool)), this, SLOT(showBordersToggleSlot(bool))); layersBorderCheckBox->setToolTip("Enable/disable\n" "display of borders,"); layersCellsCheckBox = new QCheckBox("Cells "); QObject::connect(layersCellsCheckBox, SIGNAL(toggled(bool)), this, SLOT(showCellsToggleSlot(bool))); layersCellsCheckBox->setToolTip("Enable/disable\n" "display of cells."); layersFociCheckBox = new QCheckBox("Foci "); QObject::connect(layersFociCheckBox, SIGNAL(toggled(bool)), this, SLOT(showFociToggleSlot(bool))); layersFociCheckBox->setToolTip("Enable/disable\n" "display of foci."); // // Group box for layers // QGroupBox* layersGroupBox = new QGroupBox("Layers"); QHBoxLayout* layersGroupLayout = new QHBoxLayout(layersGroupBox); layersGroupLayout->addWidget(layersBorderCheckBox); layersGroupLayout->addWidget(layersCellsCheckBox); layersGroupLayout->addWidget(layersFociCheckBox); layersGroupLayout->addStretch(); overlayUnderlayMainPageLayout->addWidget(layersGroupBox); overlayUnderlayMainPageLayout->addStretch(); } /** * Called when return is pressed in a line edit and by other methods to update graphics. */ void GuiDisplayControlDialog::applySelected() { PAGE_NAME currentPageName = PAGE_NAME_INVALID; if (pageComboBoxItems.empty() == false) { const int item = pageComboBox->currentIndex(); if ((item >= 0) && (item < static_cast(pageComboBoxItems.size()))) { currentPageName = pageComboBoxItems[item]; } } switch (currentPageName) { case PAGE_NAME_SURFACE_OVERLAY_UNDERLAY_NEW: break; case PAGE_NAME_AREAL_ESTIMATION: readArealEstimationSelections(); break; case PAGE_NAME_BORDER_MAIN: readBorderMainPage(); break; case PAGE_NAME_BORDER_COLOR: readBorderColorPage(); break; case PAGE_NAME_BORDER_NAME: readBorderNamePage(); break; case PAGE_NAME_CELL_MAIN: readCellMainPage(); break; case PAGE_NAME_CELL_CLASS: readCellClassPage(); break; case PAGE_NAME_CELL_COLOR: readCellColorPage(); break; case PAGE_NAME_COCOMAC_DISPLAY: readCocomacDisplayPage(); break; case PAGE_NAME_COCOMAC_INFORMATION: // nothing to read break; case PAGE_NAME_CONTOUR_MAIN: readContourMainPage(); break; case PAGE_NAME_CONTOUR_CLASS: readContourClassPage(); break; case PAGE_NAME_CONTOUR_COLOR: readContourColorPage(); break; case PAGE_NAME_DEFORMATION_FIELD: readDeformationFieldPage(); break; case PAGE_NAME_FOCI_MAIN: readFociMainPage(); break; case PAGE_NAME_FOCI_CLASS: readFociClassPage(); break; case PAGE_NAME_FOCI_COLOR: readFociColorPage(); break; case PAGE_NAME_FOCI_KEYWORD: readFociKeywordPage(); break; case PAGE_NAME_FOCI_NAME: readFociNamePage(); break; case PAGE_NAME_FOCI_SEARCH: readFociSearchPage(); break; case PAGE_NAME_FOCI_TABLE: readFociTablePage(); break; case PAGE_NAME_GEODESIC: readGeodesicSelections(); break; case PAGE_NAME_IMAGES: readImagesSelections(); break; case PAGE_NAME_LATLON: readLatLonSelections(); break; case PAGE_NAME_METRIC_MISCELLANEOUS: readMetricMiscellaneousPage(); break; case PAGE_NAME_METRIC_SELECTION: readMetricSelectionPage(); break; case PAGE_NAME_METRIC_SETTINGS: readMetricSettingsPage(); break; case PAGE_NAME_MODELS_MAIN: readModelMainPage(); break; case PAGE_NAME_MODELS_SETTINGS: readModelSettingsPage(); break; case PAGE_NAME_SHAPE_SELECTION: readShapeSelections(); break; case PAGE_NAME_SHAPE_SETTINGS: readShapeSettings(); break; case PAGE_NAME_PAINT_COLUMN: readPaintColumnSelections(); break; case PAGE_NAME_PAINT_MAIN: readPaintMainPageSelections(); break; case PAGE_NAME_PAINT_NAMES: readPaintNameSelections(); break; case PAGE_NAME_SECTION_MAIN: readSectionMainPage(); break; case PAGE_NAME_SURFACE_AND_VOLUME: readSurfaceAndVolumeSelections(); break; case PAGE_NAME_SURFACE_CLIPPING: readSurfaceClippingPage(); break; case PAGE_NAME_SURFACE_MISC: readMiscSelections(); break; case PAGE_NAME_PROB_ATLAS_SURFACE_MAIN: readProbAtlasSurfaceMainPage(); break; case PAGE_NAME_PROB_ATLAS_SURFACE_AREA: readProbAtlasSurfaceAreaPage(); break; case PAGE_NAME_PROB_ATLAS_SURFACE_CHANNEL: readProbAtlasSurfaceChannelPage(); break; case PAGE_NAME_PROB_ATLAS_VOLUME_MAIN: readProbAtlasVolumeMainPage(); break; case PAGE_NAME_PROB_ATLAS_VOLUME_AREA: readProbAtlasVolumeAreaPage(); break; case PAGE_NAME_PROB_ATLAS_VOLUME_CHANNEL: readProbAtlasVolumeChannelPage(); break; case PAGE_NAME_REGION: readRegionSelections(); break; case PAGE_NAME_RGB_PAINT_MAIN: readRgbPaintPageMain(); break; case PAGE_NAME_RGB_PAINT_SELECTION: readRgbPaintPageSelection(); break; case PAGE_NAME_SCENE: slotSceneListBox(sceneListBox->currentRow()); break; case PAGE_NAME_TOPOGRAPHY: readTopographySelections(); break; case PAGE_NAME_VECTOR_SELECTION: readVectorSelectionPage(); break; case PAGE_NAME_VECTOR_SETTINGS: readVectorSettingsPage(); break; case PAGE_NAME_VOLUME_SELECTION: readVolumeSelections(); break; case PAGE_NAME_VOLUME_SETTINGS: readVolumeSettings(); break; case PAGE_NAME_VOLUME_SURFACE_OUTLINE: readVolumeSurfaceOutline(); break; case PAGE_NAME_INVALID: break; } } /** * update surface overlay widgets. */ void GuiDisplayControlDialog::updateSurfaceOverlayWidgets() { if (pageOverlayUnderlaySurfaceNew != NULL) { const int num = static_cast(surfaceOverlayUnderlayWidgets.size()); for (int i = 0; i < num; i++) { surfaceOverlayUnderlayWidgets[i]->updateWidget(); } } } /** * Update overlay/underlay toggles buttons and combo boxes. Uusually called after loading * a spec file, a data file, or when the program wants to change an overlay underlay selection. */ void GuiDisplayControlDialog::updateOverlayUnderlayItemsNew() { updatePageSelectionComboBox(); updateSurfaceModelComboBoxes(); updateSurfaceOverlayWidgets(); updateSurfaceColoringModeSection(); updateArealEstimationItems(); updateMetricItems(); updatePaintItems(); updateShapeItems(); updateTopographyItems(); } /** * The destructor */ GuiDisplayControlDialog::~GuiDisplayControlDialog() { } /** * Called when an areal estimation file is selected. */ void GuiDisplayControlDialog::arealEstFileSelection(int col) { DisplaySettingsArealEstimation* dsae = theMainWindow->getBrainSet()->getDisplaySettingsArealEstimation(); dsae->setSelectedDisplayColumn(surfaceModelIndex, overlayNumberComboBox->currentIndex(), col); readArealEstimationSelections(); updateArealEstimationItems(); updateSurfaceOverlayWidgets(); /* if (arealEstimationSelectionButtonGroup != NULL) { arealEstimationSelectionButtonGroup->blockSignals(true); const int num = arealEstimationSelectionButtonGroup->buttons().count(); if ((col >= 0) && (col < num)) { QRadioButton* rb = dynamic_cast(arealEstimationSelectionButtonGroup->button(col)); rb->setChecked(true); } arealEstimationSelectionButtonGroup->blockSignals(false); updateSurfaceOverlayWidgets(); } theMainWindow->getBrainSet()->getNodeColoring()->assignColors(); GuiBrainModelOpenGL::updateAllGL(NULL); */ } /** * This pops up a text area dialog providing information about a data type. */ void GuiDisplayControlDialog::displayDataInfoDialog(const QString& title, const QString& info) { if (dataInfoDialog == NULL) { dataInfoDialog = new QtTextEditDialog(this); } dataInfoDialog->setWindowTitle(title); dataInfoDialog->setText(info); dataInfoDialog->exec(); } /** * create the areal estimation page. */ void GuiDisplayControlDialog::createArealEstimationPage() { // // Widget for items // pageArealEstimation = new QWidget; pageWidgetStack->addWidget(pageArealEstimation); arealEstimationMainPageLayout = new QVBoxLayout(pageArealEstimation); // // Display color key button // QPushButton* colorKeyPushButton = new QPushButton("Display Color Key..."); colorKeyPushButton->setFixedSize(colorKeyPushButton->sizeHint()); colorKeyPushButton->setAutoDefault(false); QObject::connect(colorKeyPushButton, SIGNAL(clicked()), theMainWindow, SLOT(displayArealEstimationColorKey())); arealEstimationMainPageLayout->addWidget(colorKeyPushButton); // // comment button group // arealEstimationCommentButtonGroup = new QButtonGroup(this); QObject::connect(arealEstimationCommentButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(arealEstimationCommentColumnSelection(int))); // // metadata button group // arealEstimationMetaDataButtonGroup = new QButtonGroup(this); QObject::connect(arealEstimationMetaDataButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(arealEstimationMetaDataColumnSelection(int))); // // selection button group // arealEstimationSelectionButtonGroup = new QButtonGroup(this); QObject::connect(arealEstimationSelectionButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(arealEstFileSelection(int))); } /** * Called to display metadata information about an areal estimation column. */ void GuiDisplayControlDialog::arealEstimationMetaDataColumnSelection(int col) { ArealEstimationFile* aef = theMainWindow->getBrainSet()->getArealEstimationFile(); if ((col >= 0) && (col < aef->getNumberOfColumns())) { StudyMetaDataLinkSet smdls = aef->getColumnStudyMetaDataLinkSet(col); GuiStudyMetaDataLinkCreationDialog smdlcd(this); smdlcd.initializeSelectedLinkSet(smdls); if (smdlcd.exec() == GuiStudyMetaDataLinkCreationDialog::Accepted) { smdls = smdlcd.getLinkSetCreated(); aef->setColumnStudyMetaDataLinkSet(col, smdls); } } } /** * Called to display comment information about an areal estimation column. */ void GuiDisplayControlDialog::arealEstimationCommentColumnSelection(int column) { ArealEstimationFile* aef = theMainWindow->getBrainSet()->getArealEstimationFile(); if ((column >= 0) && (column < aef->getNumberOfColumns())) { GuiDataFileCommentDialog* dfcd = new GuiDataFileCommentDialog(theMainWindow, aef, column); dfcd->show(); } } /** * Create and update the areal estimation page. */ void GuiDisplayControlDialog::createAndUpdateArealEstimationPage() { ArealEstimationFile* aef = theMainWindow->getBrainSet()->getArealEstimationFile(); numValidArealEstimation = aef->getNumberOfColumns(); const int numExistingArealEstimation = static_cast(arealEstimationNameLineEdits.size()); const int nameMinimumWidth = 400; if (arealEstimationSelectionGridLayout == NULL) { QWidget* arealEstimationSelectionWidget = new QWidget; arealEstimationSelectionGridLayout = new QGridLayout(arealEstimationSelectionWidget); arealEstimationSelectionGridLayout->setMargin(3); arealEstimationSelectionGridLayout->setSpacing(3); arealEstimationSelectionGridLayout->setColumnMinimumWidth(3, nameMinimumWidth+20); //const int rowStretchNumber = 15000; //arealEstimationSelectionGridLayout->addWidget(new QLabel(" "), // rowStretchNumber, 2, 1, 1, Qt::AlignLeft); arealEstimationSelectionGridLayout->setColumnStretch(0, 0); arealEstimationSelectionGridLayout->setColumnStretch(1, 0); arealEstimationSelectionGridLayout->setColumnStretch(2, 0); arealEstimationSelectionGridLayout->setColumnStretch(3, 0); //arealEstimationSelectionGridLayout->setRowStretch(rowStretchNumber, 100); arealEstimationMainPageLayout->addWidget(arealEstimationSelectionWidget, 100, Qt::AlignLeft | Qt::AlignTop); } // // Add radio buttons and text boxes // for (int i = numExistingArealEstimation; i < numValidArealEstimation; i++) { // // Selection radio button // QRadioButton* selRadioButton = new QRadioButton(""); arealEstimationSelectionRadioButtons.push_back(selRadioButton); arealEstimationSelectionGridLayout->addWidget(selRadioButton, i, 0, Qt::AlignLeft); arealEstimationSelectionButtonGroup->addButton(selRadioButton, i); // // Comment push button // QToolButton* commentPushButton = new QToolButton; //("?"); commentPushButton->setText("?"); //commentPushButton->setAutoDefault(false); //commentPushButton->setFixedWidth(40); arealEstimationColumnCommentPushButtons.push_back(commentPushButton); arealEstimationCommentButtonGroup->addButton(commentPushButton, i); arealEstimationSelectionGridLayout->addWidget(commentPushButton, i, 1, Qt::AlignHCenter); // // Metadata push button // QToolButton* metaDataPushButton = new QToolButton; //("M"); metaDataPushButton->setText("M"); //metaDataPushButton->setAutoDefault(false); //metaDataPushButton->setFixedWidth(40); arealEstimationColumnMetaDataPushButtons.push_back(metaDataPushButton); arealEstimationMetaDataButtonGroup->addButton(metaDataPushButton, i); arealEstimationSelectionGridLayout->addWidget(metaDataPushButton, i, 2, Qt::AlignHCenter); QLineEdit* le = new QLineEdit; le->setMinimumWidth(nameMinimumWidth); le->setMaximumWidth(1000); arealEstimationNameLineEdits.push_back(le); QObject::connect(le, SIGNAL(returnPressed()), this, SLOT(readArealEstimationSelections())); arealEstimationSelectionGridLayout->addWidget(le, i, 3, Qt::AlignLeft); } // // Update items already in the dialog // for (int i = 0; i < numValidArealEstimation; i++) { arealEstimationSelectionRadioButtons[i]->show(); arealEstimationColumnCommentPushButtons[i]->show(); arealEstimationColumnMetaDataPushButtons[i]->show(); arealEstimationNameLineEdits[i]->setText(aef->getColumnName(i)); arealEstimationNameLineEdits[i]->home(false); arealEstimationNameLineEdits[i]->show(); } // // Hide columns that are not needed // for (int i = numValidArealEstimation; i < numExistingArealEstimation; i++) { arealEstimationSelectionRadioButtons[i]->hide(); arealEstimationColumnCommentPushButtons[i]->hide(); arealEstimationColumnMetaDataPushButtons[i]->hide(); arealEstimationNameLineEdits[i]->hide(); } } /** * read the areal estimation page. */ void GuiDisplayControlDialog::readArealEstimationSelections() { if (pageArealEstimation == NULL) { return; } if (creatingDialog) { return; } ArealEstimationFile* aef = theMainWindow->getBrainSet()->getArealEstimationFile(); if (aef->getNumberOfColumns() > 0) { for (int i = 0; i < aef->getNumberOfColumns(); i++) { const QString name(arealEstimationNameLineEdits[i]->text()); if (name != aef->getColumnName(i)) { aef->setColumnName(i, name); } } } updateArealEstimationItems(); updateSurfaceOverlayWidgets(); GuiFilesModified fm; fm.setArealEstimationModified(); theMainWindow->fileModificationUpdate(fm); theMainWindow->getBrainSet()->getNodeColoring()->assignColors(); GuiBrainModelOpenGL::updateAllGL(NULL); } /** * update areal estimation items. */ void GuiDisplayControlDialog::updateArealEstimationItems() { updatePageSelectionComboBox(); if (pageArealEstimation == NULL) { return; } createAndUpdateArealEstimationPage(); pageArealEstimation->setEnabled(validArealEstimationData); arealEstimationSelectionButtonGroup->blockSignals(true); const int num = arealEstimationSelectionButtonGroup->buttons().count(); DisplaySettingsArealEstimation* dsae = theMainWindow->getBrainSet()->getDisplaySettingsArealEstimation(); const int col = dsae->getSelectedDisplayColumn(surfaceModelIndex, overlayNumberComboBox->currentIndex()); if ((col >= 0) && (col < num)) { QRadioButton* rb = dynamic_cast(arealEstimationSelectionButtonGroup->button(col)); rb->setChecked(true); } arealEstimationSelectionButtonGroup->blockSignals(false); } /** * Called when a metric file display column is selected. */ void GuiDisplayControlDialog::metricDisplayColumnSelection(int col) { /* const QObject* obj = sender(); std::cout << "Sender name " << obj->name() << std::endl; std::cout << "Sender class name " << obj->className() << std::endl; const QObject* parent = obj->parent(); std::cout << "Parent name " << parent->name() << std::endl; std::cout << std::endl; */ DisplaySettingsMetric* dsm = theMainWindow->getBrainSet()->getDisplaySettingsMetric(); dsm->setApplySelectionToLeftAndRightStructuresFlag(metricApplySelectionToLeftAndRightStructuresFlagCheckBox->isChecked()); dsm->setSelectedDisplayColumn(surfaceModelIndex, overlayNumberComboBox->currentIndex(), col); dsm->setSelectedThresholdColumn(surfaceModelIndex, overlayNumberComboBox->currentIndex(), col); if (pageMetricSelection != NULL) { metricViewButtonGroup->blockSignals(true); metricThresholdButtonGroup->blockSignals(true); } updateMetricSelectionPage(); if (pageMetricSelection != NULL) { metricViewButtonGroup->blockSignals(false); metricThresholdButtonGroup->blockSignals(false); } updateSurfaceOverlayWidgets(); readMetricSelectionPage(); } /** * Called when a metric column comment is selected. */ void GuiDisplayControlDialog::metricCommentColumnSelection(int column) { MetricFile* mf = theMainWindow->getBrainSet()->getMetricFile(); if ((column >= 0) && (column < mf->getNumberOfColumns())) { GuiDataFileCommentDialog* dfcd = new GuiDataFileCommentDialog(theMainWindow, mf, column); dfcd->show(); } } /** * called when a metric histogram column is selected. */ void GuiDisplayControlDialog::metricHistogramColumnSelection(int column) { MetricFile* mf = theMainWindow->getBrainSet()->getMetricFile(); if ((column >= 0) && (column < mf->getNumberOfColumns())) { const int numNodes = mf->getNumberOfNodes(); std::vector values(numNodes); for (int i = 0; i < numNodes; i++) { values[i] = mf->getValue(i, column); } GuiHistogramDisplayDialog* ghd = new GuiHistogramDisplayDialog(theMainWindow, mf->getColumnName(column), values, false, static_cast(Qt::WA_DeleteOnClose)); ghd->show(); } } /** * called when a metric metadata column is selected. */ void GuiDisplayControlDialog::metricMetaDataColumnSelection(int col) { MetricFile* mf = theMainWindow->getBrainSet()->getMetricFile(); if ((col >= 0) && (col < mf->getNumberOfColumns())) { StudyMetaDataLinkSet smdls = mf->getColumnStudyMetaDataLinkSet(col); GuiStudyMetaDataLinkCreationDialog smdlcd(this); smdlcd.initializeSelectedLinkSet(smdls); if (smdlcd.exec() == GuiStudyMetaDataLinkCreationDialog::Accepted) { smdls = smdlcd.getLinkSetCreated(); mf->setColumnStudyMetaDataLinkSet(col, smdls); } } } /** * Called when a metric file threshold column is selected. */ void GuiDisplayControlDialog::metricThresholdColumnSelection(int col) { DisplaySettingsMetric* dsm = theMainWindow->getBrainSet()->getDisplaySettingsMetric(); dsm->setSelectedThresholdColumn(surfaceModelIndex, -1, col); dsm->setApplySelectionToLeftAndRightStructuresFlag(metricApplySelectionToLeftAndRightStructuresFlagCheckBox->isChecked()); updateMetricSelectionPage(); updateSurfaceOverlayWidgets(); readMetricSelectionPage(); } /** * Called when a paint column is selected. */ void GuiDisplayControlDialog::paintColumnSelection(int col) { DisplaySettingsPaint* dsp = theMainWindow->getBrainSet()->getDisplaySettingsPaint(); dsp->setSelectedDisplayColumn(surfaceModelIndex, overlayNumberComboBox->currentIndex(), col); readPaintColumnSelections(); updatePaintItems(); updateSurfaceOverlayWidgets(); // not needed since readPaintSelections makes these calls //theMainWindow->getBrainSet()->getNodeColoring()->assignColors(); //GuiBrainModelOpenGL::updateAllGL(NULL); } /** * Called when a rgb paint file is selected. */ void GuiDisplayControlDialog::rgbPaintFileSelection(int col) { DisplaySettingsRgbPaint* dsrp = theMainWindow->getBrainSet()->getDisplaySettingsRgbPaint(); dsrp->setSelectedDisplayColumn(surfaceModelIndex, overlayNumberComboBox->currentIndex(), col); updateRgbPaintItems(); updateSurfaceOverlayWidgets(); theMainWindow->getBrainSet()->getNodeColoring()->assignColors(); GuiBrainModelOpenGL::updateAllGL(NULL); } /** * Called when a surface shape column is selected. */ void GuiDisplayControlDialog::shapeColumnSelection(int col) { DisplaySettingsSurfaceShape* dsss = theMainWindow->getBrainSet()->getDisplaySettingsSurfaceShape(); dsss->setApplySelectionToLeftAndRightStructuresFlag(shapeApplySelectionToLeftAndRightStructuresFlagCheckBox->isChecked()); readShapeColorMapping(); // dsss->setSelectedDisplayColumn(surfaceModelIndex, overlayNumberComboBox->currentIndex(), col); //shapeSelectionComboBox->setCurrentIndex(dsss->getSelectedDisplayColumn()); updateShapeItems(); updateSurfaceOverlayWidgets(); theMainWindow->getBrainSet()->getNodeColoring()->assignColors(); GuiBrainModelOpenGL::updateAllGL(NULL); } /** * Create the probabilistic atlas volume main page */ void GuiDisplayControlDialog::createProbAtlasVolumeMainPage() { // // Display mode radio buttons // probAtlasVolumeNormalButton = new QRadioButton("Normal"); probAtlasVolumeThresholdButton = new QRadioButton("Threshold"); // // Button group for probabilistic display type // QButtonGroup* probButtonGroup = new QButtonGroup(this); QObject::connect(probButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(probAtlasVolumeModeSelection(int))); probButtonGroup->addButton(probAtlasVolumeNormalButton, 0); probButtonGroup->addButton(probAtlasVolumeThresholdButton, 1); // // Group box and layout for display mode // QGroupBox* displayModeGroupBox = new QGroupBox("DisplayMode"); QVBoxLayout* displayModeGroupBoxLayout = new QVBoxLayout(displayModeGroupBox); displayModeGroupBoxLayout->addWidget(probAtlasVolumeNormalButton); displayModeGroupBoxLayout->addWidget(probAtlasVolumeThresholdButton); // // Treat ??? as unassiged check box // probAtlasVolumeUnassignedButton = new QCheckBox("Treat name \"???\" as if it was name \"Unassigned\""); QObject::connect(probAtlasVolumeUnassignedButton, SIGNAL(clicked()), this, SLOT(readProbAtlasVolumeMainPage())); // // Threshold ratio // QLabel* ratioLabel = new QLabel("Threshold Ratio "); probAtlasVolumeThresholdRatioDoubleSpinBox = new QDoubleSpinBox; probAtlasVolumeThresholdRatioDoubleSpinBox->setMinimum(0.0); probAtlasVolumeThresholdRatioDoubleSpinBox->setMaximum(1.0); probAtlasVolumeThresholdRatioDoubleSpinBox->setSingleStep(0.1); probAtlasVolumeThresholdRatioDoubleSpinBox->setDecimals(2); QObject::connect(probAtlasVolumeThresholdRatioDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(readProbAtlasVolumeMainPage())); QHBoxLayout* ratioLayout = new QHBoxLayout; ratioLayout->addWidget(ratioLabel); ratioLayout->addWidget(probAtlasVolumeThresholdRatioDoubleSpinBox); ratioLayout->addStretch(); // // Note label // QLabel* noteLabel = new QLabel("\nNote: Names \"???\", \"GYRAL\", and \"GYRUS\" are\n" "ignored when Threshold Display Mode is selected."); // // Study Metadata link // QPushButton* studyMetaDataLinkPushButton = new QPushButton("Study Metadata Link..."); studyMetaDataLinkPushButton->setAutoDefault(false); studyMetaDataLinkPushButton->setFixedSize(studyMetaDataLinkPushButton->sizeHint()); QObject::connect(studyMetaDataLinkPushButton, SIGNAL(clicked()), this, SLOT(volumeProbAtlasVolumeStudyMetaDataPushButton())); // // prob atlas main page and layout // pageProbAtlasVolumeMain = new QWidget; QVBoxLayout* probAtlasVolumeSubPageMainLayout = new QVBoxLayout(pageProbAtlasVolumeMain); probAtlasVolumeSubPageMainLayout->addWidget(displayModeGroupBox); probAtlasVolumeSubPageMainLayout->addWidget(probAtlasVolumeUnassignedButton); probAtlasVolumeSubPageMainLayout->addLayout(ratioLayout); probAtlasVolumeSubPageMainLayout->addWidget(noteLabel); probAtlasVolumeSubPageMainLayout->addWidget(studyMetaDataLinkPushButton); probAtlasVolumeSubPageMainLayout->addStretch(); pageWidgetStack->addWidget(pageProbAtlasVolumeMain); } /** * Slot for prob atlas mode selection. */ void GuiDisplayControlDialog::probAtlasVolumeModeSelection(int num) { DisplaySettingsProbabilisticAtlas* dspa = theMainWindow->getBrainSet()->getDisplaySettingsProbabilisticAtlasVolume(); dspa->setDisplayType( static_cast(num)); readProbAtlasVolumeMainPage(); } /** * Create prob atlas volume channel selection page */ void GuiDisplayControlDialog::createProbAtlasVolumeChannelPage() { // // Vertical Box Layout for all items // pageProbAtlasVolumeChannel = new QWidget; pageProbAtlasVolumeChannel->setFixedWidth(450); probAtlasVolumeSubPageChannelLayout = new QVBoxLayout(pageProbAtlasVolumeChannel); // // All off and all on pushbuttons // QPushButton* probAtlasVolumeChannelAllOnButton = new QPushButton("All On"); probAtlasVolumeChannelAllOnButton->setAutoDefault(false); QObject::connect(probAtlasVolumeChannelAllOnButton, SIGNAL(clicked()), this, SLOT(probAtlasVolumeChannelAllOn())); QPushButton* probAtlasVolumeChannelAllOffButton = new QPushButton("All Off"); probAtlasVolumeChannelAllOffButton->setAutoDefault(false); QObject::connect(probAtlasVolumeChannelAllOffButton, SIGNAL(clicked()), this, SLOT(probAtlasVolumeChannelAllOff())); QHBoxLayout* allOnOffLayout = new QHBoxLayout; allOnOffLayout->addWidget(probAtlasVolumeChannelAllOnButton); allOnOffLayout->addWidget(probAtlasVolumeChannelAllOffButton); allOnOffLayout->addStretch(); probAtlasVolumeSubPageChannelLayout->addLayout(allOnOffLayout); createAndUpdateProbAtlasVolumeChannelCheckBoxes(); pageWidgetStack->addWidget(pageProbAtlasVolumeChannel); } /** * This slot is called when the prob atlas volume channel all on button is pressed */ void GuiDisplayControlDialog::probAtlasVolumeChannelAllOn() { DisplaySettingsProbabilisticAtlas* dspa = theMainWindow->getBrainSet()->getDisplaySettingsProbabilisticAtlasVolume(); dspa->setAllChannelsSelectedStatus(true); updateProbAtlasVolumeItems(); readProbAtlasVolumeChannelPage(); } /** * This slot is called when the prob atlas volumechannel all off button is pressed */ void GuiDisplayControlDialog::probAtlasVolumeChannelAllOff() { DisplaySettingsProbabilisticAtlas* dspa = theMainWindow->getBrainSet()->getDisplaySettingsProbabilisticAtlasVolume(); dspa->setAllChannelsSelectedStatus(false); updateProbAtlasVolumeItems(); readProbAtlasVolumeChannelPage(); } /** * caret prob atlas volume area selection page */ void GuiDisplayControlDialog::createProbAtlasVolumeAreaPage() { // // Vertical Box Layout for all items // pageProbAtlasVolumeArea = new QWidget; pageProbAtlasVolumeArea->setFixedWidth(450); probAtlasVolumeSubPageAreaLayout = new QVBoxLayout(pageProbAtlasVolumeArea); // // All off and all on pushbuttons // QPushButton* probAtlasVolumeAreasAllOnButton = new QPushButton("All On"); QObject::connect(probAtlasVolumeAreasAllOnButton, SIGNAL(clicked()), this, SLOT(probAtlasVolumeAreasAllOn())); probAtlasVolumeAreasAllOnButton->setAutoDefault(false); QPushButton* probAtlasVolumeAreasAllOffButton = new QPushButton("All Off"); probAtlasVolumeAreasAllOffButton->setAutoDefault(false); QObject::connect(probAtlasVolumeAreasAllOffButton, SIGNAL(clicked()), this, SLOT(probAtlasVolumeAreasAllOff())); QHBoxLayout* allOnOffLayout = new QHBoxLayout; allOnOffLayout->addWidget(probAtlasVolumeAreasAllOnButton); allOnOffLayout->addWidget(probAtlasVolumeAreasAllOffButton); allOnOffLayout->addStretch(); probAtlasVolumeSubPageAreaLayout->addLayout(allOnOffLayout); createAndUpdateProbAtlasVolumeAreaNameCheckBoxes(); pageWidgetStack->addWidget(pageProbAtlasVolumeArea); } /** * This slot is called when the prob atlas surfce areas all on button is pressed */ void GuiDisplayControlDialog::probAtlasVolumeAreasAllOn() { DisplaySettingsProbabilisticAtlas* dspa = theMainWindow->getBrainSet()->getDisplaySettingsProbabilisticAtlasVolume(); dspa->setAllAreasSelectedStatus(true); updateProbAtlasVolumeItems(); readProbAtlasVolumeAreaPage(); } /** * This slot is called when the prob atlas volume areas all off button is pressed */ void GuiDisplayControlDialog::probAtlasVolumeAreasAllOff() { DisplaySettingsProbabilisticAtlas* dspa = theMainWindow->getBrainSet()->getDisplaySettingsProbabilisticAtlasVolume(); dspa->setAllAreasSelectedStatus(false); updateProbAtlasVolumeItems(); readProbAtlasVolumeAreaPage(); } /** * read the probabilistic Volume main page. */ void GuiDisplayControlDialog::readProbAtlasVolumeMainPage() { if (pageProbAtlasVolumeMain == NULL) { return; } if (creatingDialog) { return; } BrainModelVolume* bmv = theMainWindow->getBrainSet()->getBrainModelVolume(); if (bmv == NULL) { return; } DisplaySettingsProbabilisticAtlas* dspa = theMainWindow->getBrainSet()->getDisplaySettingsProbabilisticAtlasVolume(); dspa->setTreatQuestColorAsUnassigned(probAtlasVolumeUnassignedButton->isChecked()); dspa->setThresholdDisplayTypeRatio(probAtlasVolumeThresholdRatioDoubleSpinBox->value()); BrainModelVolumeVoxelColoring* vvc = theMainWindow->getBrainSet()->getVoxelColoring(); vvc->setVolumeProbAtlasColoringInvalid(); GuiBrainModelOpenGL::updateAllGL(NULL); } /** * read the probabilistic Volume area page. */ void GuiDisplayControlDialog::readProbAtlasVolumeAreaPage() { if (pageProbAtlasVolumeArea == NULL) { return; } if (creatingDialog) { return; } BrainModelVolume* bmv = theMainWindow->getBrainSet()->getBrainModelVolume(); if (bmv == NULL) { return; } if (theMainWindow->getBrainSet()->getNumberOfVolumeProbAtlasFiles() <= 0) { return; } const VolumeFile* firstVolumeFile = theMainWindow->getBrainSet()->getVolumeProbAtlasFile(0); const int numAreas = firstVolumeFile->getNumberOfRegionNames(); DisplaySettingsProbabilisticAtlas* dspa = theMainWindow->getBrainSet()->getDisplaySettingsProbabilisticAtlasVolume(); if (numAreas == numValidProbAtlasVolumeAreas) { for (int i = 0; i < numAreas; i++) { dspa->setAreaSelected(i, probAtlasVolumeAreasCheckBoxes[i]->isChecked()); } } else { std::cerr << "Number of prob atlas volume area checkboxes does not equal number of " << "prob atlas volume areas." << std::endl; } BrainModelVolumeVoxelColoring* vvc = theMainWindow->getBrainSet()->getVoxelColoring(); vvc->setVolumeProbAtlasColoringInvalid(); GuiBrainModelOpenGL::updateAllGL(NULL); } /** * read the probabilistic Volumechannel page. */ void GuiDisplayControlDialog::readProbAtlasVolumeChannelPage() { if (pageProbAtlasVolumeChannel == NULL) { return; } if (creatingDialog) { return; } BrainModelVolume* bmv = theMainWindow->getBrainSet()->getBrainModelVolume(); if (bmv == NULL) { return; } DisplaySettingsProbabilisticAtlas* dspa = theMainWindow->getBrainSet()->getDisplaySettingsProbabilisticAtlasVolume(); const int numChannels = theMainWindow->getBrainSet()->getNumberOfVolumeProbAtlasFiles(); if (numChannels == numValidProbAtlasVolumeChannels) { for (int i = 0; i < numChannels; i++) { dspa->setChannelSelected(i, probAtlasVolumeChannelCheckBoxes[i]->isChecked()); } } else { std::cerr << "Number of prob atlas volume channel checkboxes does not equal number of " << "prob atlas volume channels." << std::endl; } if (pageProbAtlasSurfaceMain != NULL) { dspa->setThresholdDisplayTypeRatio(probAtlasVolumeThresholdRatioDoubleSpinBox->value()); } BrainModelVolumeVoxelColoring* vvc = theMainWindow->getBrainSet()->getVoxelColoring(); vvc->setVolumeProbAtlasColoringInvalid(); GuiBrainModelOpenGL::updateAllGL(NULL); } /** * create and update the check boxes for prob atlas volume channels */ void GuiDisplayControlDialog::createAndUpdateProbAtlasVolumeChannelCheckBoxes() { numValidProbAtlasVolumeChannels = theMainWindow->getBrainSet()->getNumberOfVolumeProbAtlasFiles(); const int numExistingCheckBoxes = static_cast(probAtlasVolumeChannelCheckBoxes.size()); if (probAtlasVolumeChannelGridLayout == NULL) { QWidget* channelsWidget = new QWidget; probAtlasVolumeChannelGridLayout = new QGridLayout(channelsWidget); const int rowStretchNumber = 15000; probAtlasVolumeChannelGridLayout->addWidget(new QLabel(""), rowStretchNumber, 0, 1, 1, Qt::AlignLeft); probAtlasVolumeChannelGridLayout->setRowStretch(rowStretchNumber, 1000); probAtlasVolumeSubPageChannelLayout->addWidget(channelsWidget); } if (probAtlasVolumeChannelButtonGroup == NULL) { probAtlasVolumeChannelButtonGroup = new QButtonGroup(this); probAtlasVolumeChannelButtonGroup->setExclusive(false); QObject::connect(probAtlasVolumeChannelButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(readProbAtlasVolumeChannelPage())); } // // update existing checkboxes // for (int i = 0; i < numExistingCheckBoxes; i++) { if (i < numValidProbAtlasVolumeChannels) { VolumeFile* vf = theMainWindow->getBrainSet()->getVolumeProbAtlasFile(i); probAtlasVolumeChannelCheckBoxes[i]->setText(vf->getDescriptiveLabel()); probAtlasVolumeChannelCheckBoxes[i]->show(); } } // // Add new checkboxes as needed // for (int j = numExistingCheckBoxes; j < numValidProbAtlasVolumeChannels; j++) { VolumeFile* vf = theMainWindow->getBrainSet()->getVolumeProbAtlasFile(j); QCheckBox* cb = new QCheckBox(vf->getDescriptiveLabel()); probAtlasVolumeChannelCheckBoxes.push_back(cb); probAtlasVolumeChannelButtonGroup->addButton(cb, j); probAtlasVolumeChannelGridLayout->addWidget(cb, j, 0, 1, 1, Qt::AlignLeft); cb->show(); } // // Hide existing checkboxes that are not needed // for (int k = numValidProbAtlasVolumeChannels; k < numExistingCheckBoxes; k++) { probAtlasVolumeChannelCheckBoxes[k]->hide(); } } /** * create and update the check boxes for prob atlas volume area names */ void GuiDisplayControlDialog::createAndUpdateProbAtlasVolumeAreaNameCheckBoxes() { numValidProbAtlasVolumeAreas = 0; BrainModelVolume* bmv = theMainWindow->getBrainSet()->getBrainModelVolume(); if (bmv == NULL) { return; } if (theMainWindow->getBrainSet()->getNumberOfVolumeProbAtlasFiles() <= 0) { return; } const VolumeFile* firstVolumeFile = theMainWindow->getBrainSet()->getVolumeProbAtlasFile(0); numValidProbAtlasVolumeAreas = firstVolumeFile->getNumberOfRegionNames(); const int numExistingCheckBoxes = static_cast(probAtlasVolumeAreasCheckBoxes.size()); if (probAtlasVolumeAreasGridLayout == NULL) { QWidget* areasWidget = new QWidget; //(probAtlasVolumeAreasScrollView->viewport(), "probAtlasVolumeAreasQVBox"); //probAtlasSubPageArea); probAtlasVolumeAreasGridLayout = new QGridLayout(areasWidget); const int rowStretchNumber = 15000; probAtlasVolumeAreasGridLayout->addWidget(new QLabel(""), rowStretchNumber, 0, 1, 1, Qt::AlignLeft); probAtlasVolumeAreasGridLayout->setRowStretch(rowStretchNumber, 1000); probAtlasVolumeSubPageAreaLayout->addWidget(areasWidget); } if (probAtlasVolumeAreasButtonGroup == NULL) { probAtlasVolumeAreasButtonGroup = new QButtonGroup(this); probAtlasVolumeAreasButtonGroup->setExclusive(false); QObject::connect(probAtlasVolumeAreasButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(readProbAtlasVolumeAreaPage())); } // // update existing checkboxes // for (int i = 0; i < numExistingCheckBoxes; i++) { if (i < numValidProbAtlasVolumeAreas) { probAtlasVolumeAreasCheckBoxes[i]->setText(firstVolumeFile->getRegionNameFromIndex(i)); probAtlasVolumeAreasCheckBoxes[i]->show(); } } // // Add new checkboxes as needed // for (int j = numExistingCheckBoxes; j < numValidProbAtlasVolumeAreas; j++) { QCheckBox* cb = new QCheckBox(firstVolumeFile->getRegionNameFromIndex(j)); probAtlasVolumeAreasCheckBoxes.push_back(cb); probAtlasVolumeAreasButtonGroup->addButton(cb, j); probAtlasVolumeAreasGridLayout->addWidget(cb, j, 0, 1, 1, Qt::AlignLeft); cb->show(); } // // Hide existing checkboxes that are not needed // for (int k = numValidProbAtlasVolumeAreas; k < numExistingCheckBoxes; k++) { probAtlasVolumeAreasCheckBoxes[k]->hide(); } } /** * update all prob atlas volume main page. */ void GuiDisplayControlDialog::updateProbAtlasVolumeMainPage() { if (pageProbAtlasVolumeMain == NULL) { return; } DisplaySettingsProbabilisticAtlas* dspa = theMainWindow->getBrainSet()->getDisplaySettingsProbabilisticAtlasVolume(); probAtlasVolumeUnassignedButton->setChecked(dspa->getTreatQuestColorAsUnassigned()); switch(dspa->getDisplayType()) { case DisplaySettingsProbabilisticAtlas::PROBABILISTIC_DISPLAY_TYPE_NORMAL: probAtlasVolumeNormalButton->setChecked(true); break; case DisplaySettingsProbabilisticAtlas::PROBABILISTIC_DISPLAY_TYPE_THRESHOLD: probAtlasVolumeThresholdButton->setChecked(true); break; } probAtlasVolumeThresholdRatioDoubleSpinBox->setValue(dspa->getThresholdDisplayTypeRatio()); pageProbAtlasVolumeMain->setEnabled(validProbAtlasVolumeData); } /** * update all prob atlas volume area page. */ void GuiDisplayControlDialog::updateProbAtlasVolumeAreaPage(const bool filesChanged) { if (pageProbAtlasVolumeArea == NULL) { return; } if (filesChanged) { createAndUpdateProbAtlasVolumeAreaNameCheckBoxes(); } int numAreas = 0; BrainModelVolume* bmv = theMainWindow->getBrainSet()->getBrainModelVolume(); DisplaySettingsProbabilisticAtlas* dspa = theMainWindow->getBrainSet()->getDisplaySettingsProbabilisticAtlasVolume(); if (bmv != NULL) { if (theMainWindow->getBrainSet()->getNumberOfVolumeProbAtlasFiles() > 0) { const VolumeFile* firstVolumeFile = theMainWindow->getBrainSet()->getVolumeProbAtlasFile(0); numAreas = firstVolumeFile->getNumberOfRegionNames(); } } if (numAreas == numValidProbAtlasVolumeAreas) { for (int i = 0; i < numValidProbAtlasVolumeAreas; i++) { probAtlasVolumeAreasCheckBoxes[i]->setChecked(dspa->getAreaSelected(i)); } } else { std::cerr << "Number of prob atlas volume area checkboxes " << numValidProbAtlasVolumeAreas << " does not equal number of prob " << "atlas volume areas" << numAreas << "." << std::endl; } pageProbAtlasVolumeArea->setEnabled(validProbAtlasVolumeData); } /** * update all prob atlas volume channel page. */ void GuiDisplayControlDialog::updateProbAtlasVolumeChannelPage(const bool filesChanged) { if (pageProbAtlasVolumeChannel == NULL) { return; } if (filesChanged) { createAndUpdateProbAtlasVolumeChannelCheckBoxes(); } DisplaySettingsProbabilisticAtlas* dspa = theMainWindow->getBrainSet()->getDisplaySettingsProbabilisticAtlasVolume(); const int numChannels = theMainWindow->getBrainSet()->getNumberOfVolumeProbAtlasFiles(); if (numChannels == numValidProbAtlasVolumeChannels) { for (int i = 0; i < numValidProbAtlasVolumeChannels; i++) { probAtlasVolumeChannelCheckBoxes[i]->setChecked(dspa->getChannelSelected(i)); } } else { std::cerr << "Number of prob atlas volume channel checkboxes " << numValidProbAtlasVolumeChannels << " does not equal number of prob " << "atlas volume channels" << numChannels << "." << std::endl; } pageProbAtlasVolumeChannel->setEnabled(validProbAtlasVolumeData); } /** * Update prob atlas volume items in dialog */ void GuiDisplayControlDialog::updateProbAtlasVolumeItems(const bool filesChanged) { updatePageSelectionComboBox(); updateProbAtlasVolumeMainPage(); updateProbAtlasVolumeAreaPage(filesChanged); updateProbAtlasVolumeChannelPage(filesChanged); updatePageSelectionComboBox(); } /** * display left-to-left right-to-right message. */ void GuiDisplayControlDialog::displayOverlayLeftToLeftRightToRightMessage() { const QString msg = "The 'Apply Shape L-to-L, R-to-R Matching to Coord Files' option affects only newly made overlay/underlay selections. To " "activate, select the desired surface (or All Surfaces), then press the View button for the desired column. If the selected column " "name contains 'Left' [or 'Right'], this column will be assigned to all surfaces identified as left [right] hemispheres. Also, a " "corresponding 'Right' [ or 'Left'] column (if it exists) will be assigned to all surfaces identified as right [left] hemispheres."; QtTextEditDialog te(this, true, true); te.setText(msg); te.exec(); } /** * read surface clipping page. */ void GuiDisplayControlDialog::readSurfaceClippingPage() { if (pageSurfaceClipping == NULL) { return; } DisplaySettingsSurface* dss = theMainWindow->getBrainSet()->getDisplaySettingsSurface(); dss->setClippingPlaneApplication(static_cast( this->surfaceClippingApplyComboBox->currentIndex())); for (int i = 0; i < 6; i++) { DisplaySettingsSurface::CLIPPING_PLANE_AXIS cpa = static_cast(i); dss->setClippingPlaneEnabled(cpa, this->surfaceClippingEnabledCheckBox[i]->isChecked()); dss->setClippingPlaneCoordinate(cpa, this->surfaceClippingCoordSpinBox[i]->value()); } theMainWindow->getBrainSet()->clearAllDisplayLists(); GuiBrainModelOpenGL::updateAllGL(); } /** * Create the surface clipping page. */ void GuiDisplayControlDialog::createSurfaceClippingPage() { QLabel* applyLabel = new QLabel("Apply Clipping "); surfaceClippingApplyComboBox = new QComboBox; QObject::connect(surfaceClippingApplyComboBox, SIGNAL(activated(int)), this, SLOT(readSurfaceClippingPage())); surfaceClippingApplyComboBox->insertItem( static_cast(DisplaySettingsSurface::CLIPPING_PLANE_APPLICATION_MAIN_WINDOW_ONLY), "Main Window"); surfaceClippingApplyComboBox->insertItem( static_cast(DisplaySettingsSurface::CLIPPING_PLANE_APPLICATION_FIDUCIAL_SURFACES_ONLY), "Fiducial Surfaces"); surfaceClippingApplyComboBox->insertItem( static_cast(DisplaySettingsSurface::CLIPPING_PLANE_APPLICATION_ALL_SURFACES), "All Surfaces"); this->surfaceClippingEnabledCheckBox[0] = new QCheckBox("Negative X"); this->surfaceClippingEnabledCheckBox[1] = new QCheckBox("Positive X"); this->surfaceClippingEnabledCheckBox[2] = new QCheckBox("Negative Y"); this->surfaceClippingEnabledCheckBox[3] = new QCheckBox("Positive Y"); this->surfaceClippingEnabledCheckBox[4] = new QCheckBox("Negative Z"); this->surfaceClippingEnabledCheckBox[5] = new QCheckBox("Positive Z"); for (int i = 0; i < 6; i++) { QObject::connect(this->surfaceClippingEnabledCheckBox[i], SIGNAL(toggled(bool)), this, SLOT(readSurfaceClippingPage())); this->surfaceClippingCoordSpinBox[i] = new QDoubleSpinBox; this->surfaceClippingCoordSpinBox[i]->setMinimum(-1000000.0); this->surfaceClippingCoordSpinBox[i]->setMaximum( 1000000.0); this->surfaceClippingCoordSpinBox[i]->setSingleStep(1); this->surfaceClippingCoordSpinBox[i]->setDecimals(2); QObject::connect(this->surfaceClippingCoordSpinBox[i], SIGNAL(valueChanged(double)), this, SLOT(readSurfaceClippingPage())); } surfaceClippingPageWidgetGroup = new WuQWidgetGroup(this); surfaceClippingPageWidgetGroup->addWidget(applyLabel); surfaceClippingPageWidgetGroup->addWidget(surfaceClippingApplyComboBox); pageSurfaceClipping = new QWidget; QGridLayout* gridLayout = new QGridLayout(pageSurfaceClipping); gridLayout->addWidget(applyLabel, 0, 0); gridLayout->addWidget(surfaceClippingApplyComboBox, 0, 1); for (int i = 0; i < 6; i++) { const int rowCount = gridLayout->rowCount(); gridLayout->addWidget(this->surfaceClippingEnabledCheckBox[i], rowCount, 0); gridLayout->addWidget(this->surfaceClippingCoordSpinBox[i], rowCount, 1); surfaceClippingPageWidgetGroup->addWidget(this->surfaceClippingEnabledCheckBox[i]); surfaceClippingPageWidgetGroup->addWidget(this->surfaceClippingCoordSpinBox[i]); } pageSurfaceClipping->setFixedSize(pageSurfaceClipping->sizeHint()); pageWidgetStack->addWidget(pageSurfaceClipping); } /** * update the surface clipping page. */ void GuiDisplayControlDialog::updateSurfaceClippingPage() { if (pageSurfaceClipping == NULL) { return; } surfaceClippingPageWidgetGroup->blockSignals(true); DisplaySettingsSurface* dss = theMainWindow->getBrainSet()->getDisplaySettingsSurface(); this->surfaceClippingApplyComboBox->setCurrentIndex(dss->getClippingPlaneApplication()); for (int i = 0; i < 6; i++) { DisplaySettingsSurface::CLIPPING_PLANE_AXIS cpa = static_cast(i); this->surfaceClippingEnabledCheckBox[i]->setChecked(dss->getClippingPlaneEnabled(cpa)); this->surfaceClippingCoordSpinBox[i]->setValue(dss->getClippingPlaneCoordinate(cpa)); } surfaceClippingPageWidgetGroup->blockSignals(false); } caret-5.6.4~dfsg.1.orig/caret/GuiDeleteBordersByNameDialog.h0000664000175000017500000000333011572067322023433 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_DELETE_BORDERS_BY_NAME_DIALOG_H__ #define __GUI_DELETE_BORDERS_BY_NAME_DIALOG_H__ #include #include #include "WuQDialog.h" class QListWidget; /// class to delete borders by name class GuiDeleteBordersByNameDialog : public WuQDialog { Q_OBJECT public: /// constructor GuiDeleteBordersByNameDialog(QWidget* parent); /// Destructor ~GuiDeleteBordersByNameDialog(); private slots: /// called when delete selected borders button pressed void slotDeleteButton(); private: /// load the border name list box void loadBorderNameListBox(); /// listbox containing border names QListWidget* borderListWidget; /// the border names std::vector borderNames; }; #endif // __GUI_DELETE_BORDERS_BY_NAME_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiDeleteBordersByNameDialog.cxx0000664000175000017500000000774311572067322024022 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "BrainModelBorderSet.h" #include "BrainSet.h" #include "GuiBrainModelOpenGL.h" #include "GuiDeleteBordersByNameDialog.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "global_variables.h" /** * Constructor */ GuiDeleteBordersByNameDialog::GuiDeleteBordersByNameDialog(QWidget* parent) : WuQDialog(parent) { setModal(true); setWindowTitle("Delete borders by name"); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // List box for border names // borderListWidget = new QListWidget; dialogLayout->addWidget(borderListWidget); borderListWidget->setSelectionMode(QListWidget::ExtendedSelection); // // Delete Selected Borders button // QPushButton* deleteBordersButton = new QPushButton("Delete Selected Borders"); dialogLayout->addWidget(deleteBordersButton); deleteBordersButton->setFixedSize(deleteBordersButton->sizeHint()); deleteBordersButton->setAutoDefault(false); QObject::connect(deleteBordersButton, SIGNAL(clicked()), this, SLOT(slotDeleteButton())); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; dialogLayout->addLayout(buttonsLayout); buttonsLayout->setSpacing(2); // // close button // QPushButton* closeButton = new QPushButton("Close"); closeButton->setFixedSize(closeButton->sizeHint()); closeButton->setAutoDefault(false); buttonsLayout->addWidget(closeButton); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); loadBorderNameListBox(); } /** * Destructor */ GuiDeleteBordersByNameDialog::~GuiDeleteBordersByNameDialog() { } /** * Load the border list box */ void GuiDeleteBordersByNameDialog::loadBorderNameListBox() { borderListWidget->clear(); BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); bmbs->getAllBorderNames(borderNames, false); const int numNames = static_cast(borderNames.size()); for (int i = 0; i < numNames; i++) { borderListWidget->addItem(borderNames[i]); } } /** * */ void GuiDeleteBordersByNameDialog::slotDeleteButton() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); std::vector bordersToDelete; const int numNames = static_cast(borderNames.size()); for (int i = 0; i < numNames; i++) { if (borderListWidget->isItemSelected(borderListWidget->item(i))) { bordersToDelete.push_back(borderNames[i]); } } if (bordersToDelete.empty() == false) { BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); bmbs->deleteBordersWithNames(bordersToDelete); } loadBorderNameListBox(); GuiFilesModified fm; fm.setBorderModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } caret-5.6.4~dfsg.1.orig/caret/GuiDeformationFieldDialog.h0000664000175000017500000000633311572067322023035 0ustar michaelmichael #ifndef __GUI_DEFORMATION_FIELD_DIALOG_H__ #define __GUI_DEFORMATION_FIELD_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "WuQDialog.h" class GuiBrainModelSelectionComboBox; class GuiNodeAttributeColumnSelectionComboBox; class QGroupBox; class QLineEdit; class QRadioButton; /// dialog for creating deformation fields class GuiDeformationFieldDialog : public WuQDialog { Q_OBJECT public: /// constructor GuiDeformationFieldDialog(QWidget* parent); /// destructor ~GuiDeformationFieldDialog(); protected slots: /// called when dialog is closed void done(int r); /// called when a column is selected void slotDeformationFileColumnComboBox(int item); /// called when pushbutton is pressed void slotIndivTopoFilePushButton(); /// called when pushbutton is pressed void slotIndivCoordFilePushButton(); /// called when pushbutton is pressed void slotIndivDeformedCoordFilePushButton(); /// called when a mode button is selected void slotModeButtonGroup(); protected: /// mode type enum MODE_TYPE { MODE_TYPE_NONE, MODE_TYPE_INDIV_TO_ATLAS, MODE_TYPE_ATLAS_TO_INDIV }; /// the dialog mode MODE_TYPE dialogMode; /// atlas surface combo box GuiBrainModelSelectionComboBox* atlasSurfaceComboBox; /// line edit QLineEdit* indivTopoFileLineEdit; /// line edit QLineEdit* indivCoordFileLineEdit; /// line edit QLineEdit* indivDeformedCoordFileLineEdit; /// surface combo box GuiBrainModelSelectionComboBox* surfaceComboBox; /// deformed surface combo box GuiBrainModelSelectionComboBox* deformedSurfaceComboBox; /// column combo box GuiNodeAttributeColumnSelectionComboBox* deformationFileColumnComboBox; /// column name line edit QLineEdit* columnNameLineEdit; /// atlas to indiv radio button QRadioButton* dialogModeAtlasIndivRadioButton; /// indiv to atlas radio button QRadioButton* dialogModeIndivAtlasRadioButton; /// atlas to indiv items QGroupBox* atlasIndivGroupBox; /// indiv to atlas items QGroupBox* indivAtlasGroupBox; }; #endif // __GUI_DEFORMATION_FIELD_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiDeformationFieldDialog.cxx0000664000175000017500000004730711572067322023416 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include "WuQFileDialog.h" #include #include #include #include #include #include #include #include #include "BrainModelSurface.h" #include "BrainSet.h" #include "DeformationFieldFile.h" #include "FileFilters.h" #include "FileUtilities.h" #include "GuiBrainModelOpenGL.h" #include "GuiBrainModelSelectionComboBox.h" #include "GuiDeformationFieldDialog.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "GuiNodeAttributeColumnSelectionComboBox.h" #include "QtUtilities.h" #include "StringUtilities.h" #include "global_variables.h" /** * Constructor. */ GuiDeformationFieldDialog::GuiDeformationFieldDialog(QWidget* parent) : WuQDialog(parent) { setModal(true); dialogMode = MODE_TYPE_NONE; setWindowTitle("Create Deformation Field"); // // Layout for dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // Mode vertical button group and radio buttons // QGroupBox* modeButtonGroupBox = new QGroupBox("Mode"); QVBoxLayout* modeLayout = new QVBoxLayout(modeButtonGroupBox); dialogLayout->addWidget(modeButtonGroupBox); dialogModeAtlasIndivRadioButton = new QRadioButton("Atlas To Indiv"); dialogModeIndivAtlasRadioButton = new QRadioButton("Indiv To Atlas"); modeLayout->addWidget(dialogModeAtlasIndivRadioButton); modeLayout->addWidget(dialogModeIndivAtlasRadioButton); QButtonGroup* modeButtonGroup = new QButtonGroup(this); modeButtonGroup->addButton(dialogModeAtlasIndivRadioButton, 0); modeButtonGroup->addButton(dialogModeIndivAtlasRadioButton, 1); QObject::connect(modeButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotModeButtonGroup())); // // Atlas to Indiv Group Box // atlasIndivGroupBox = new QGroupBox("Atlas to Indiv"); dialogLayout->addWidget(atlasIndivGroupBox); QGridLayout* atlasIndivGridLayout = new QGridLayout(atlasIndivGroupBox); // // atlas surface // atlasIndivGridLayout->addWidget(new QLabel("Atlas Spherical Surface "), 0, 0); atlasSurfaceComboBox = new GuiBrainModelSelectionComboBox( false, true, false, "Select Surface", 0); atlasSurfaceComboBox->setSelectedBrainModelIndex(GuiBrainModelSelectionComboBox::ADD_NEW_INDEX); atlasIndivGridLayout->addWidget(atlasSurfaceComboBox, 0, 1); // // indiv source topo file // QPushButton* indivTopoFilePushButton = new QPushButton("Indiv Closed Topo File..."); indivTopoFilePushButton->setAutoDefault(false); QObject::connect(indivTopoFilePushButton, SIGNAL(clicked()), this, SLOT(slotIndivTopoFilePushButton())); indivTopoFileLineEdit = new QLineEdit; indivTopoFileLineEdit->setReadOnly(true); atlasIndivGridLayout->addWidget(indivTopoFilePushButton, 1, 0); atlasIndivGridLayout->addWidget(indivTopoFileLineEdit, 1, 1); // // indiv source coord file // QPushButton* indivCoordFilePushButton = new QPushButton("Indiv Spherical Coord File..."); indivCoordFilePushButton->setAutoDefault(false); QObject::connect(indivCoordFilePushButton, SIGNAL(clicked()), this, SLOT(slotIndivCoordFilePushButton())); indivCoordFileLineEdit = new QLineEdit; indivCoordFileLineEdit->setReadOnly(true); atlasIndivGridLayout->addWidget(indivCoordFilePushButton, 2, 0); atlasIndivGridLayout->addWidget(indivCoordFileLineEdit, 2, 1); // // indiv target coord file // QPushButton* indivDeformedCoordFilePushButton = new QPushButton("Indiv Deformed Spherical Coord File..."); indivDeformedCoordFilePushButton->setAutoDefault(false); QObject::connect(indivDeformedCoordFilePushButton, SIGNAL(clicked()), this, SLOT(slotIndivDeformedCoordFilePushButton())); indivDeformedCoordFileLineEdit = new QLineEdit; indivDeformedCoordFileLineEdit->setReadOnly(true); atlasIndivGridLayout->addWidget(indivDeformedCoordFilePushButton, 3, 0); atlasIndivGridLayout->addWidget(indivDeformedCoordFileLineEdit, 3, 1); // // Indiv to Atlas Group Box // indivAtlasGroupBox = new QGroupBox("Indiv To Atlas"); dialogLayout->addWidget(indivAtlasGroupBox); QGridLayout* indivAtlasGridLayout = new QGridLayout(indivAtlasGroupBox); // // Source surface // indivAtlasGridLayout->addWidget(new QLabel("Source Spherical Surface"), 0, 0); surfaceComboBox = new GuiBrainModelSelectionComboBox( false, true, false, "Select Surface", indivAtlasGroupBox); surfaceComboBox->setSelectedBrainModelIndex(GuiBrainModelSelectionComboBox::ADD_NEW_INDEX); indivAtlasGridLayout->addWidget(surfaceComboBox, 0, 1); // // deformed surface // indivAtlasGridLayout->addWidget(new QLabel("Deformed Spherical Surface"), 1, 0); deformedSurfaceComboBox = new GuiBrainModelSelectionComboBox( false, true, false, "Select Surface", indivAtlasGroupBox); deformedSurfaceComboBox->setSelectedBrainModelIndex(GuiBrainModelSelectionComboBox::ADD_NEW_INDEX); indivAtlasGridLayout->addWidget(deformedSurfaceComboBox, 1, 1); // // Deformation Field File Group Box // QGroupBox* defFileGroupBox = new QGroupBox("Deformation Field File"); dialogLayout->addWidget(defFileGroupBox); QGridLayout* defFileGridLayout = new QGridLayout(defFileGroupBox); // // deformation field file column // defFileGridLayout->addWidget(new QLabel("Def Field File Column "), 0, 0); deformationFileColumnComboBox = new GuiNodeAttributeColumnSelectionComboBox( GUI_NODE_FILE_TYPE_DEFORMATION_FIELD, true, false, false); QObject::connect(deformationFileColumnComboBox, SIGNAL(itemSelected(int)), this, SLOT(slotDeformationFileColumnComboBox(int))); defFileGridLayout->addWidget(deformationFileColumnComboBox, 0, 1); // // deformation field file column name // defFileGridLayout->addWidget(new QLabel("Column Name "), 1, 0); columnNameLineEdit = new QLineEdit(defFileGroupBox); columnNameLineEdit->setText("New Column Name"); defFileGridLayout->addWidget(columnNameLineEdit, 1, 1); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; dialogLayout->addLayout(buttonsLayout); buttonsLayout->setSpacing(2); // OK button // QPushButton* okButton = new QPushButton("OK"); okButton->setAutoDefault(false); buttonsLayout->addWidget(okButton); QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); // Cancel button // QPushButton* cancelButton = new QPushButton("Cancel"); cancelButton->setAutoDefault(false); buttonsLayout->addWidget(cancelButton); QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); QtUtilities::makeButtonsSameSize(okButton, cancelButton); deformationFileColumnComboBox->setCurrentIndex( GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NEW); slotModeButtonGroup(); } /** * destructor. */ GuiDeformationFieldDialog::~GuiDeformationFieldDialog() { } /** * called when a mode button is selected. */ void GuiDeformationFieldDialog::slotModeButtonGroup() { dialogMode = MODE_TYPE_NONE; if (dialogModeAtlasIndivRadioButton->isChecked()) { dialogMode = MODE_TYPE_ATLAS_TO_INDIV; } else if (dialogModeIndivAtlasRadioButton->isChecked()) { dialogMode = MODE_TYPE_INDIV_TO_ATLAS; } atlasIndivGroupBox->setEnabled(false); indivAtlasGroupBox->setEnabled(false); switch (dialogMode) { case MODE_TYPE_NONE: break; case MODE_TYPE_INDIV_TO_ATLAS: indivAtlasGroupBox->setEnabled(true); break; case MODE_TYPE_ATLAS_TO_INDIV: atlasIndivGroupBox->setEnabled(true); break; } } /** * called when pushbutton is pressed. */ void GuiDeformationFieldDialog::slotIndivTopoFilePushButton() { // // Create a file dialog and get the file. // WuQFileDialog fd(this); fd.setDirectory(QDir::currentPath()); fd.setModal(true); fd.setAcceptMode(WuQFileDialog::AcceptOpen); fd.setWindowTitle("Choose Closed Topology File"); fd.setFileMode(WuQFileDialog::ExistingFile); fd.setFilter(FileFilters::getTopologyClosedFileFilter()); fd.selectFilter(FileFilters::getTopologyClosedFileFilter()); if (fd.exec() == QDialog::Accepted) { QStringList sl = fd.selectedFiles(); if (sl.isEmpty() == false) { indivTopoFileLineEdit->setText(sl.at(0)); } } } /** * called when pushbutton is pressed. */ void GuiDeformationFieldDialog::slotIndivCoordFilePushButton() { // // Create a file dialog and get the file. // WuQFileDialog fd(this); fd.setModal(true); fd.setDirectory(QDir::currentPath()); fd.setAcceptMode(WuQFileDialog::AcceptOpen); fd.setWindowTitle("Choose Spherical Coordinate File"); fd.setFileMode(WuQFileDialog::ExistingFile); fd.setFilter(FileFilters::getCoordinateSphericalFileFilter()); fd.selectFilter(FileFilters::getCoordinateSphericalFileFilter()); if (fd.exec() == QDialog::Accepted) { if (fd.selectedFiles().count() > 0) { indivCoordFileLineEdit->setText(fd.selectedFiles().at(0)); } } } /** * called when pushbutton is pressed. */ void GuiDeformationFieldDialog::slotIndivDeformedCoordFilePushButton() { // // Create a file dialog and get the file. // WuQFileDialog fd(this); fd.setModal(true); fd.setDirectory(QDir::currentPath()); fd.setAcceptMode(WuQFileDialog::AcceptOpen); fd.setWindowTitle("Choose Deformed Spherical Coordinate File"); fd.setFileMode(WuQFileDialog::ExistingFile); fd.setFilter(FileFilters::getCoordinateSphericalFileFilter()); fd.selectFilter(FileFilters::getCoordinateSphericalFileFilter()); if (fd.exec() == QDialog::Accepted) { if (fd.selectedFiles().count() > 0) { indivDeformedCoordFileLineEdit->setText(fd.selectedFiles().at(0)); } } } /** * called when dialog is closed. */ void GuiDeformationFieldDialog::done(int r) { if (r == QDialog::Accepted) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); switch (dialogMode) { case MODE_TYPE_NONE: break; case MODE_TYPE_INDIV_TO_ATLAS: { const BrainModelSurface* bms = surfaceComboBox->getSelectedBrainModelSurface(); if (bms == NULL) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", "No Surface is selected."); return; } if (bms->getSurfaceType() != BrainModelSurface::SURFACE_TYPE_SPHERICAL) { QMessageBox::critical(this, "ERROR", "The source surface must be spherical."); return; } const BrainModelSurface* defBms = deformedSurfaceComboBox->getSelectedBrainModelSurface(); if (defBms == NULL) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", "No Deformed Surface is selected."); return; } if (defBms->getSurfaceType() != BrainModelSurface::SURFACE_TYPE_SPHERICAL) { QMessageBox::critical(this, "ERROR", "The deformed surface must be spherical."); return; } bms->createDeformationField(defBms, deformationFileColumnComboBox->currentIndex(), columnNameLineEdit->text(), *(theMainWindow->getBrainSet()->getDeformationFieldFile())); } break; case MODE_TYPE_ATLAS_TO_INDIV: { // // Make sure inputs are there // QString indivTopoFileName(indivTopoFileLineEdit->text()); QString indivCoordFileName(indivCoordFileLineEdit->text()); QString indivDeformedCoordFileName(indivDeformedCoordFileLineEdit->text()); if (indivTopoFileName.isEmpty()) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", "Indiv Topo File Name is missing."); return; } if (indivCoordFileName.isEmpty()) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", "Indiv Coord File Name is missing."); return; } if (indivDeformedCoordFileName.isEmpty()) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", "Indiv Deformed Coord File Name is missing."); return; } const BrainModelSurface* bms = atlasSurfaceComboBox->getSelectedBrainModelSurface(); if (bms == NULL) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", "No Atlas Surface is selected."); return; } // // Create a spec file for the indiv // QString specFileName(FileUtilities::dirname(indivTopoFileName)); specFileName.append("/temp_spec"); specFileName.append(SpecFile::getSpecFileExtension()); SpecFile indivSpecFile; indivSpecFile.setFileName(specFileName); indivSpecFile.addToSpecFile(SpecFile::getClosedTopoFileTag(), indivTopoFileName, "", false); indivSpecFile.addToSpecFile(SpecFile::getSphericalCoordFileTag(), indivCoordFileName, "", false); indivSpecFile.addToSpecFile(SpecFile::getSphericalCoordFileTag(), indivDeformedCoordFileName, "", false); indivSpecFile.setAllFileSelections(SpecFile::SPEC_TRUE); // // Create a brain set for the indiv // BrainSet indivBrainSet; // // load the indiv spec file into the indiv brain set // std::vector errorMessages; QString currentDirectory(QDir::currentPath()); indivBrainSet.readSpecFile(BrainSet::SPEC_FILE_READ_MODE_NORMAL, indivSpecFile, "indivSpecFile", errorMessages, NULL, NULL); QDir::setCurrent(currentDirectory); // // Did an error occur while reading the files // if (errorMessages.empty() == false) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR reading indiv files", StringUtilities::combine(errorMessages, "\n")); return; } // // Should be two brain models // if (indivBrainSet.getNumberOfBrainModels() < 2) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", "Problems reading indiv files (less than 2 brain models)"); return; } // // Get the indiv and indiv deformed surfaces // const BrainModelSurface* indivSurface = indivBrainSet.getBrainModelSurface(0); if (indivSurface == NULL) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", "Indiv surface missing."); return; } const BrainModelSurface* indivDeformSurface = indivBrainSet.getBrainModelSurface(1); if (indivDeformSurface == NULL) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", "Indiv deformed surface missing."); return; } // // Create the deformation field // bms->createDeformationField(indivSurface, indivDeformSurface, deformationFileColumnComboBox->currentIndex(), columnNameLineEdit->text(), *(theMainWindow->getBrainSet()->getDeformationFieldFile())); } break; } GuiFilesModified fm; fm.setDeformationFieldModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); QApplication::beep(); QApplication::restoreOverrideCursor(); } QDialog::done(r); } /** * called when a column is selected. */ void GuiDeformationFieldDialog::slotDeformationFileColumnComboBox(int item) { const DeformationFieldFile* dff = theMainWindow->getBrainSet()->getDeformationFieldFile(); columnNameLineEdit->setText("New Column"); if ((item >= 0) && (item < dff->getNumberOfColumns())) { columnNameLineEdit->setText(dff->getColumnName(item)); } } caret-5.6.4~dfsg.1.orig/caret/GuiDataFileSaveDialog.h0000664000175000017500000003573311572067322022120 0ustar michaelmichael#ifndef __GUI_DATA_FILE_SAVE_DIALOG_H__ #define __GUI_DATA_FILE_SAVE_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "AbstractFile.h" #include "WuQDialog.h" class GuiBrainModelSelectionComboBox; class GuiNodeAttributeColumnSelectionComboBox; class GuiStructureComboBox; class GuiSurfaceTypeComboBox; class GuiTopologyFileComboBox; class GuiTopologyTypeComboBox; class GuiVectorFileComboBox; class GuiVolumeFileSelectionComboBox; class GuiVolumeSelectionControl; class GuiVolumeVoxelDataTypeComboBox; class ImageFile; class QCheckBox; class QComboBox; class QGroupBox; class QLineEdit; class QPushButton; class QRadioButton; class QTextEdit; class WuQWidgetGroup; /// dialog for saving Caret data files. class GuiDataFileSaveDialog : public WuQDialog { Q_OBJECT public: // constructor GuiDataFileSaveDialog(QWidget* parent = 0); // destructor ~GuiDataFileSaveDialog(); // select the file type for saving void selectFileType(const QString& fileFilterName); // select the image file for saving void selectImageFile(const ImageFile* imageFile); // select a file void selectFile(AbstractFile* af); // get the file filter QString getFileTypeFilter() const; // get the selected file name QString getSelectedFileName() const; protected slots: // called when file name line edit changed void slotFileNameLineEditChanged(const QString&); // called when a file type combo box selection is made void slotFileTypeComboBox(const QString&); // called when file name push button pressed void slotFileNamePushButton(); // load parameters for the selected file type void slotLoadParametersForFileType(); protected: // called when accept/reject pressed void done(int r); // create the file information section QWidget* createFileInformationSection(); // create the metadata section QWidget* createMetadataSection(); // create the surface border options section QGroupBox* createBorderSurfaceOptionsSection(); // create the border projection options section QGroupBox* createBorderProjectionOptionsSection(); // create the cell options section QGroupBox* createCellOptionsSection(); // create the coordinate options section QGroupBox* createCoordinateOptionsSection(); // create the foci options section QGroupBox* createFociOptionsSection(); // create the image options section QGroupBox* createImageOptionsSection(); // create the topology options section QGroupBox* createTopologyOptionsSection(); // create the vector options section QGroupBox* createVectorOptionsSection(); // create the volume anatomy options section QGroupBox* createVolumeAnatomyOptionsSection(); // create the volume functional options section QGroupBox* createVolumeFunctionalOptionsSection(); // create the volume paint options section QGroupBox* createVolumePaintOptionsSection(); // create the volume prob atlas options section QGroupBox* createVolumeProbAtlasOptionsSection(); // create the volume rgb options section QGroupBox* createVolumeRgbOptionsSection(); // create the volume segmentation options section QGroupBox* createVolumeSegmentationOptionsSection(); // create the volume vector options section QGroupBox* createVolumeVectorOptionsSection(); // create the vtk model options section QGroupBox* createVtkModelOptionsSection(); // create the export volume section QGroupBox* createExportVolumeOptionsSection(); // create the export surface section QGroupBox* createExportSurfaceOptionsSection(); // create paint export options section QGroupBox* createPaintExportOptionsSection(); // create shape export options section QGroupBox* createShapeExportOptionsSection(); // create metric export options section QGroupBox* createMetricExportOptionsSection(); // create gifti options section QGroupBox* createGiftiOptionsSection(); // get supported encodings from a file void getSupportedEncodings(const AbstractFile& af, std::vector& encodingsOut, AbstractFile::FILE_FORMAT& preferredEncodingOut); // get supported XML encodings from a file void getSupportedXmlEncodings(const AbstractFile& af, std::vector& encodingsOut, AbstractFile::FILE_FORMAT& preferredEncodingOut); // update file extension void updateFileNamesFileExtension(QString& fileName, const QString& fileExtension); // update metadata and name. void updateMetadataAndName(AbstractFile* af, QString& fileName, const QString& fileExtension); /// file name line edit QLineEdit* fileNameLineEdit; /// file type combo box QComboBox* fileTypeComboBox; /// save push button QPushButton* savePushButton; /// metadata PubMed ID line edit QLineEdit* metadataPubMedIDLineEdit; /// metadat comment text edit QTextEdit* metadataCommentTextEdit; /// file encoding combo box QComboBox* fileEncodingComboBox; /// add file extension check box QCheckBox* addFileExtensionCheckBox; /// surface border options group box QGroupBox* borderSurfaceOptionsGroupBox; /// border projection options group box QGroupBox* borderProjectionOptionsGroupBox; /// cell options group box QGroupBox* cellOptionsGroupBox; /// coordinate options group box QGroupBox* coordinateOptionsGroupBox; /// foci options group box QGroupBox* fociOptionsGroupBox; /// image options group box QGroupBox* imageOptionsGroupBox; /// topology options group box QGroupBox* topologyOptionsGroupBox; /// vector options group box QGroupBox* vectorOptionsGroupBox; /// vector file selection combo box GuiVectorFileComboBox* vectorFileSelectionComboBox; /// volume anatomy options group box QGroupBox* volumeAnatomyOptionsGroupBox; /// volume functional options group box QGroupBox* volumeFunctionalOptionsGroupBox; /// volume paint options group box QGroupBox* volumePaintOptionsGroupBox; /// volume prob atlas options group box QGroupBox* volumeProbAtlasOptionsGroupBox; /// volume rgb options group box QGroupBox* volumeRgbOptionsGroupBox; /// volume segmentation options group box QGroupBox* volumeSegmentationOptionsGroupBox; /// volume vector options group box QGroupBox* volumeVectorOptionsGroupBox; /// vtk model options group box QGroupBox* vtkModelOptionsGroupBox; /// export surface options group box QGroupBox* exportSurfaceOptionsGroupBox; /// export volume options group box QGroupBox* exportVolumeOptionsGroupBox; /// export metric options group box QGroupBox* exportMetricOptionsGroupBox; /// export paint options group box QGroupBox* exportPaintOptionsGroupBox; /// export shape options group box QGroupBox* exportShapeOptionsGroupBox; /// gifti surface selection control QGroupBox* giftiSurfaceOptionsGroupBox; /// widget group for file options WuQWidgetGroup* fileOptionsWidgetGroup; /// surface border associated surface combo box GuiBrainModelSelectionComboBox* borderSurfaceSelectionComboBox; /// surface border type combo box GuiSurfaceTypeComboBox* borderSurfaceTypeComboBox; /// surface border remove duplicates check box QCheckBox* borderSurfaceRemoveDuplicatesCheckBox; /// cell surface combo box GuiBrainModelSelectionComboBox* cellSurfaceSelectionComboBox; /// border projections remove duplicates check box QCheckBox* borderProjectionsRemoveDuplicatesCheckBox; /// coordinate surface selection combo box GuiBrainModelSelectionComboBox* coordinateSurfaceSelectionComboBox; /// coordinate surface type combo combo box GuiSurfaceTypeComboBox* coordinateTypeComboBox; /// coordinate structure combo box GuiStructureComboBox* coordinateStructureComboBox; /// coordinate stereotaxic space combo box QComboBox* coordinateStereotaxicSpaceComboBox; /// foci save original coordinate radio button QRadioButton* fociSaveOriginalCoordinatesRadioButton; /// foci save projected coordinate radio button QRadioButton* fociSaveProjectedCoordinatesRadioButton; /// foci left surface selection combo box GuiBrainModelSelectionComboBox* fociLeftSurfaceSelectionComboBox; /// foci right surface selection combo box GuiBrainModelSelectionComboBox* fociRightSurfaceSelectionComboBox; /// foci cerebellum surface selection combo box GuiBrainModelSelectionComboBox* fociCerebellumSurfaceSelectionComboBox; /// image selection combo box QComboBox* imageSelectionComboBox; /// topology selection combo box GuiTopologyFileComboBox* topologySelectionComboBox; /// topology type selection combo box GuiTopologyTypeComboBox* topologyTypeComboBox; /// vtk model selection combo box QComboBox* vtkModelSelectionComboBox; /// volume anatomy file selection GuiVolumeFileSelectionComboBox* volumeAnatomyFileSelectionComboBox; /// volume anatomy file label QLineEdit* volumeAnatomyLabelLineEdit; /// volume anatomy voxel data type GuiVolumeVoxelDataTypeComboBox* volumeAnatomyVolumeDataTypeComboBox; /// volume anatomy write compressed QCheckBox* volumeAnatomyWriteCompressedCheckBox; /// volume functional file selection GuiVolumeFileSelectionComboBox* volumeFunctionalFileSelectionComboBox; /// volume functional file label QLineEdit* volumeFunctionalLabelLineEdit; /// volume functional voxel data type GuiVolumeVoxelDataTypeComboBox* volumeFunctionalVolumeDataTypeComboBox; /// volume functional write compressed QCheckBox* volumeFunctionalWriteCompressedCheckBox; /// volume paint file selection GuiVolumeFileSelectionComboBox* volumePaintFileSelectionComboBox; /// volume paint file label QLineEdit* volumePaintLabelLineEdit; /// volume paint voxel data type GuiVolumeVoxelDataTypeComboBox* volumePaintVolumeDataTypeComboBox; /// volume paint write compressed QCheckBox* volumePaintWriteCompressedCheckBox; /// volume prob atlas file selection GuiVolumeFileSelectionComboBox* volumeProbAtlasFileSelectionComboBox; /// volume prob atlas file label QLineEdit* volumeProbAtlasLabelLineEdit; /// volume prob atlas voxel data type GuiVolumeVoxelDataTypeComboBox* volumeProbAtlasVolumeDataTypeComboBox; /// volume prob atlas write compressed QCheckBox* volumeProbAtlasWriteCompressedCheckBox; /// volume rgb file selection GuiVolumeFileSelectionComboBox* volumeRgbFileSelectionComboBox; /// volume rgb file label QLineEdit* volumeRgbLabelLineEdit; /// volume rgb voxel data type GuiVolumeVoxelDataTypeComboBox* volumeRgbVolumeDataTypeComboBox; /// volume rgb write compressed QCheckBox* volumeRgbWriteCompressedCheckBox; /// volume segmentation file selection GuiVolumeFileSelectionComboBox* volumeSegmentationFileSelectionComboBox; /// volume segmentation file label QLineEdit* volumeSegmentationLabelLineEdit; /// volume segmentation voxel data type GuiVolumeVoxelDataTypeComboBox* volumeSegmentationVolumeDataTypeComboBox; /// volume segmentation write compressed QCheckBox* volumeSegmentationWriteCompressedCheckBox; /// volume vector file selection GuiVolumeFileSelectionComboBox* volumeVectorFileSelectionComboBox; /// volume vector file label QLineEdit* volumeVectorLabelLineEdit; /// volume vector voxel data type GuiVolumeVoxelDataTypeComboBox* volumeVectorVolumeDataTypeComboBox; /// volume vector write compressed QCheckBox* volumeVectorWriteCompressedCheckBox; /// export volume selection control GuiVolumeSelectionControl* exportVolumeSelectionControl; /// export surface selection control GuiBrainModelSelectionComboBox* exportSurfaceSelectionControl; /// export paint surface selection control GuiBrainModelSelectionComboBox* exportPaintSurfaceSelectionControl; /// export paint column selection control GuiNodeAttributeColumnSelectionComboBox* exportPaintColumnSelectionControl; /// export shape surface selection control GuiBrainModelSelectionComboBox* exportShapeSurfaceSelectionControl; /// export shape column selection control GuiNodeAttributeColumnSelectionComboBox* exportShapeColumnSelectionControl; /// export metric surface selection control GuiBrainModelSelectionComboBox* exportMetricSurfaceSelectionControl; /// export metric column selection control GuiNodeAttributeColumnSelectionComboBox* exportMetricColumnSelectionControl; /// GIFTI surface selection control GuiBrainModelSelectionComboBox* giftiSurfaceSelectionControl; }; #endif // __GUI_DATA_FILE_SAVE_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiDataFileSaveDialog.cxx0000664000175000017500000042171511572067322022472 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "AreaColorFile.h" #include "ArealEstimationFile.h" #include "BorderColorFile.h" #include "BorderProjectionFile.h" #include "BrainModelBorderSet.h" #include "BrainModelContours.h" #include "BrainSet.h" #include "CellColorFile.h" #include "CellFile.h" #include "CellProjectionFile.h" #include "CocomacConnectivityFile.h" #include "ContourCellColorFile.h" #include "ContourCellFile.h" #include "ContourFile.h" #include "CutsFile.h" #include "DeformationFieldFile.h" #include "DeformationMapFile.h" #include "FileFilters.h" #include "FileUtilities.h" #include "FociColorFile.h" #include "FociFile.h" #include "FociProjectionFile.h" #include "FociSearchFile.h" #include "GeodesicDistanceFile.h" #include "GiftiDataArrayFile.h" #include "GuiBrainModelSelectionComboBox.h" #include "GuiDataFileSaveDialog.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "GuiNodeAttributeColumnSelectionComboBox.h" #include "GuiSpecFileCreationDialog.h" #include "GuiStructureComboBox.h" #include "GuiSurfaceTypeComboBox.h" #include "GuiTopologyFileComboBox.h" #include "GuiTopologyTypeComboBox.h" #include "GuiVectorFileComboBox.h" #include "GuiVolumeFileSelectionComboBox.h" #include "GuiVolumeSelectionControl.h" #include "GuiVolumeVoxelDataTypeComboBox.h" #include "ImageFile.h" #include "LatLonFile.h" #include "MetricFile.h" #include "PaletteFile.h" #include "ParamsFile.h" #include "PreferencesFile.h" #include "ProbabilisticAtlasFile.h" #include "RgbPaintFile.h" #include "SectionFile.h" #include "StereotaxicSpace.h" #include "StudyCollectionFile.h" #include "StudyMetaDataFile.h" #include "SurfaceShapeFile.h" #include "VectorFile.h" #include "TopographyFile.h" #include "TopologyFile.h" #include "QtMultipleInputDialog.h" #include "QtUtilities.h" #include "VocabularyFile.h" #include "VtkModelFile.h" #include "WuQFileDialog.h" #include "WuQWidgetGroup.h" #include "WustlRegionFile.h" #include "global_variables.h" static const bool alwaysSaveAllProbAtlasVolumes = true; /** * constructor. */ GuiDataFileSaveDialog::GuiDataFileSaveDialog(QWidget* parent) : WuQDialog(parent) { fileOptionsWidgetGroup = NULL; setWindowTitle("Save Data File"); // // Create the widgets for the different sections // QWidget* fileInfoWidget = createFileInformationSection(); QWidget* metadataWidget = createMetadataSection(); // // create group boxes for each of the file types // borderSurfaceOptionsGroupBox = createBorderSurfaceOptionsSection(); borderProjectionOptionsGroupBox = createBorderProjectionOptionsSection(); cellOptionsGroupBox = createCellOptionsSection(); coordinateOptionsGroupBox = createCoordinateOptionsSection(); fociOptionsGroupBox = createFociOptionsSection(); imageOptionsGroupBox = createImageOptionsSection(); topologyOptionsGroupBox = createTopologyOptionsSection(); vectorOptionsGroupBox = createVectorOptionsSection(); volumeAnatomyOptionsGroupBox = createVolumeAnatomyOptionsSection(); volumeFunctionalOptionsGroupBox = createVolumeFunctionalOptionsSection(); volumePaintOptionsGroupBox = createVolumePaintOptionsSection(); volumeProbAtlasOptionsGroupBox = createVolumeProbAtlasOptionsSection(); volumeRgbOptionsGroupBox = createVolumeRgbOptionsSection(); volumeSegmentationOptionsGroupBox = createVolumeSegmentationOptionsSection(); volumeVectorOptionsGroupBox = createVolumeVectorOptionsSection(); vtkModelOptionsGroupBox = createVtkModelOptionsSection(); exportSurfaceOptionsGroupBox = createExportSurfaceOptionsSection(); exportVolumeOptionsGroupBox = createExportVolumeOptionsSection(); exportMetricOptionsGroupBox = createMetricExportOptionsSection(); exportPaintOptionsGroupBox = createPaintExportOptionsSection(); exportShapeOptionsGroupBox = createShapeExportOptionsSection(); giftiSurfaceOptionsGroupBox = createGiftiOptionsSection(); // // Place all of the file option boxes into a widget group // fileOptionsWidgetGroup = new WuQWidgetGroup(this); fileOptionsWidgetGroup->addWidget(borderSurfaceOptionsGroupBox); fileOptionsWidgetGroup->addWidget(borderProjectionOptionsGroupBox); fileOptionsWidgetGroup->addWidget(cellOptionsGroupBox); fileOptionsWidgetGroup->addWidget(coordinateOptionsGroupBox); fileOptionsWidgetGroup->addWidget(fociOptionsGroupBox); fileOptionsWidgetGroup->addWidget(imageOptionsGroupBox); fileOptionsWidgetGroup->addWidget(topologyOptionsGroupBox); fileOptionsWidgetGroup->addWidget(vectorOptionsGroupBox); fileOptionsWidgetGroup->addWidget(volumeAnatomyOptionsGroupBox); fileOptionsWidgetGroup->addWidget(volumeFunctionalOptionsGroupBox); fileOptionsWidgetGroup->addWidget(volumePaintOptionsGroupBox); fileOptionsWidgetGroup->addWidget(volumeProbAtlasOptionsGroupBox); fileOptionsWidgetGroup->addWidget(volumeRgbOptionsGroupBox); fileOptionsWidgetGroup->addWidget(volumeSegmentationOptionsGroupBox); fileOptionsWidgetGroup->addWidget(volumeVectorOptionsGroupBox); fileOptionsWidgetGroup->addWidget(vtkModelOptionsGroupBox); fileOptionsWidgetGroup->addWidget(exportSurfaceOptionsGroupBox); fileOptionsWidgetGroup->addWidget(exportVolumeOptionsGroupBox); fileOptionsWidgetGroup->addWidget(exportMetricOptionsGroupBox); fileOptionsWidgetGroup->addWidget(exportPaintOptionsGroupBox); fileOptionsWidgetGroup->addWidget(exportShapeOptionsGroupBox); fileOptionsWidgetGroup->addWidget(giftiSurfaceOptionsGroupBox); // // Save button // savePushButton = new QPushButton("Save"); savePushButton->setAutoDefault(true); savePushButton->setEnabled(false); QObject::connect(savePushButton, SIGNAL(clicked()), this, SLOT(accept())); // // Cancel button // QPushButton* cancelPushButton = new QPushButton("Cancel"); cancelPushButton->setAutoDefault(false); QObject::connect(cancelPushButton, SIGNAL(clicked()), this, SLOT(reject())); QtUtilities::makeButtonsSameSize(savePushButton, cancelPushButton); // // Layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->addWidget(savePushButton); buttonsLayout->addWidget(cancelPushButton); // // Layout for dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->addWidget(fileInfoWidget); dialogLayout->addWidget(metadataWidget); dialogLayout->addWidget(borderSurfaceOptionsGroupBox); dialogLayout->addWidget(borderProjectionOptionsGroupBox); dialogLayout->addWidget(cellOptionsGroupBox); dialogLayout->addWidget(coordinateOptionsGroupBox); dialogLayout->addWidget(fociOptionsGroupBox); dialogLayout->addWidget(imageOptionsGroupBox); dialogLayout->addWidget(topologyOptionsGroupBox); dialogLayout->addWidget(vectorOptionsGroupBox); dialogLayout->addWidget(volumeAnatomyOptionsGroupBox); dialogLayout->addWidget(volumeFunctionalOptionsGroupBox); dialogLayout->addWidget(volumePaintOptionsGroupBox); dialogLayout->addWidget(volumeProbAtlasOptionsGroupBox); dialogLayout->addWidget(volumeRgbOptionsGroupBox); dialogLayout->addWidget(volumeSegmentationOptionsGroupBox); dialogLayout->addWidget(volumeVectorOptionsGroupBox); dialogLayout->addWidget(vtkModelOptionsGroupBox); dialogLayout->addWidget(exportSurfaceOptionsGroupBox); dialogLayout->addWidget(exportVolumeOptionsGroupBox); dialogLayout->addWidget(exportMetricOptionsGroupBox); dialogLayout->addWidget(exportPaintOptionsGroupBox); dialogLayout->addWidget(exportShapeOptionsGroupBox); dialogLayout->addWidget(giftiSurfaceOptionsGroupBox); dialogLayout->addLayout(buttonsLayout); // // Add file filters to file type combo box // QStringList filterNames; filterNames << FileFilters::getAreaColorFileFilter(); filterNames << FileFilters::getArealEstimationFileFilter(); filterNames << FileFilters::getBorderGenericFileFilter(); filterNames << FileFilters::getBorderVolumeFileFilter(); filterNames << FileFilters::getBorderColorFileFilter(); filterNames << FileFilters::getBorderProjectionFileFilter(); filterNames << FileFilters::getCellFileFilter(); filterNames << FileFilters::getCellColorFileFilter(); filterNames << FileFilters::getCellProjectionFileFilter(); filterNames << FileFilters::getCellVolumeFileFilter(); filterNames << FileFilters::getCocomacFileFilter(); filterNames << FileFilters::getContourFileFilter(); filterNames << FileFilters::getContourCellFileFilter(); filterNames << FileFilters::getContourCellColorFileFilter(); filterNames << FileFilters::getCoordinateGenericFileFilter(); filterNames << FileFilters::getCutsFileFilter(); filterNames << FileFilters::getDeformationFieldFileFilter(); filterNames << FileFilters::getFociFileFilter(); filterNames << FileFilters::getFociColorFileFilter(); filterNames << FileFilters::getFociProjectionFileFilter(); filterNames << FileFilters::getFociSearchFileFilter(); filterNames << FileFilters::getGeodesicDistanceFileFilter(); if (GiftiDataArrayFile::getGiftiXMLEnabled()) { filterNames << FileFilters::getGiftiCoordinateFileFilter(); filterNames << FileFilters::getGiftiFunctionalFileFilter(); filterNames << FileFilters::getGiftiLabelFileFilter(); filterNames << FileFilters::getGiftiShapeFileFilter(); filterNames << FileFilters::getGiftiSurfaceFileFilter(); filterNames << FileFilters::getGiftiTopologyFileFilter(); filterNames << FileFilters::getGiftiVectorFileFilter(); } filterNames << FileFilters::getImageSaveFileFilter(); filterNames << FileFilters::getLatitudeLongitudeFileFilter(); filterNames << FileFilters::getMetricFileFilter(); filterNames << FileFilters::getPaintFileFilter(); filterNames << FileFilters::getPaletteFileFilter(); filterNames << FileFilters::getParamsFileFilter(); filterNames << FileFilters::getProbAtlasFileFilter(); filterNames << FileFilters::getRgbPaintFileFilter(); filterNames << FileFilters::getSceneFileFilter(); filterNames << FileFilters::getSectionFileFilter(); filterNames << FileFilters::getStudyCollectionFileFilter(); filterNames << FileFilters::getStudyMetaDataFileFilter(); filterNames << FileFilters::getSurfaceShapeFileFilter(); filterNames << FileFilters::getTopographyFileFilter(); filterNames << FileFilters::getTopologyGenericFileFilter(); filterNames << FileFilters::getTransformationMatrixFileFilter(); filterNames << FileFilters::getVocabularyFileFilter(); filterNames << FileFilters::getVolumeAnatomyFileFilter(); filterNames << FileFilters::getVolumeFunctionalFileFilter(); filterNames << FileFilters::getVolumePaintFileFilter(); filterNames << FileFilters::getVolumeProbAtlasFileFilter(); filterNames << FileFilters::getVolumeRgbFileFilter(); filterNames << FileFilters::getVolumeSegmentationFileFilter(); filterNames << FileFilters::getVolumeVectorFileFilter(); filterNames << FileFilters::getVtkModelFileFilter(); filterNames << FileFilters::getWustlRegionFileFilter(); filterNames << FileFilters::getAnalyzeVolumeFileFilter(); filterNames << FileFilters::getByuSurfaceFileFilter(); filterNames << FileFilters::getFreeSurferAsciiSurfaceFileFilter(); filterNames << FileFilters::getFreeSurferAsciiCurvatureFileFilter(); filterNames << FileFilters::getFreeSurferAsciiFunctionalFileFilter(); filterNames << FileFilters::getFreeSurferAsciiLabelFileFilter(); filterNames << FileFilters::getMincVolumeFileFilter(); filterNames << FileFilters::getOpenInventorSurfaceFileFilter(); filterNames << FileFilters::getStlSurfaceFileFilter(); filterNames << FileFilters::getVrmlSurfaceFileFilter(); filterNames << FileFilters::getVtkSurfaceFileFilter(); filterNames << FileFilters::getVtkXmlSurfaceFileFilter(); filterNames << FileFilters::getVtkVolumeFileFilter(); fileTypeComboBox->addItems(filterNames); slotFileTypeComboBox(fileTypeComboBox->currentText()); //updateGeometry(); } /** * destructor. */ GuiDataFileSaveDialog::~GuiDataFileSaveDialog() { } /** * get the selected file name. */ QString GuiDataFileSaveDialog::getSelectedFileName() const { return fileNameLineEdit->text(); } /** * get the file filter. */ QString GuiDataFileSaveDialog::getFileTypeFilter() const { const QString s(fileTypeComboBox->currentText()); return s; } /** * select the file type for saving. */ void GuiDataFileSaveDialog::selectFileType(const QString& fileFilterName) { bool found = false; for (int i = 0; i < fileTypeComboBox->count(); i++) { if (fileTypeComboBox->itemText(i) == fileFilterName) { fileTypeComboBox->setCurrentIndex(i); found = true; break; } } if (found == false) { fileTypeComboBox->addItem(fileFilterName); fileTypeComboBox->setCurrentIndex(fileTypeComboBox->count() - 1); } } /** * called when file name push button pressed. */ void GuiDataFileSaveDialog::slotFileNamePushButton() { PreferencesFile* pf = theMainWindow->getBrainSet()->getPreferencesFile(); WuQFileDialog fd(this); fd.setHistory(pf->getRecentDataFileDirectories()); fd.setWindowTitle("Select File Name"); fd.setDirectory(QDir::currentPath()); fd.setFilters(QStringList(fileTypeComboBox->currentText())); fd.setFileMode(WuQFileDialog::AnyFile); fd.setAcceptMode(WuQFileDialog::AcceptSave); fd.setConfirmOverwrite(false); if (fd.exec() == Accepted) { if (fd.selectedFiles().count() > 0) { const QString name = fd.selectedFiles().at(0); fileNameLineEdit->setText(name); } } } /** * create the border options section. */ QGroupBox* GuiDataFileSaveDialog::createBorderSurfaceOptionsSection() { // // Associated surface // QLabel* surfaceSelectionLabel = new QLabel("Associated Surface"); borderSurfaceSelectionComboBox = new GuiBrainModelSelectionComboBox(false, true, false, ""); borderSurfaceSelectionComboBox->setSelectedBrainModel(theMainWindow->getBrainModelSurface()); QObject::connect(borderSurfaceSelectionComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotLoadParametersForFileType())); // // Surface type // QLabel* surfaceTypeLabel = new QLabel("Save As Type"); borderSurfaceTypeComboBox = new GuiSurfaceTypeComboBox(false); // // Remove duplicates check box // borderSurfaceRemoveDuplicatesCheckBox = new QCheckBox("Remove Duplicates"); borderSurfaceRemoveDuplicatesCheckBox->setChecked(true); // // Create group box and layout // QGroupBox* groupBox = new QGroupBox("Border (Surface) Options"); QGridLayout* gridLayout = new QGridLayout(groupBox); gridLayout->addWidget(surfaceSelectionLabel, 0, 0, Qt::AlignLeft); gridLayout->addWidget(borderSurfaceSelectionComboBox, 0, 1); gridLayout->addWidget(surfaceTypeLabel, 1, 0, Qt::AlignLeft); gridLayout->addWidget(borderSurfaceTypeComboBox, 1, 1); gridLayout->addWidget(borderSurfaceRemoveDuplicatesCheckBox, 2, 0, 1, 2, Qt::AlignLeft); gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 100); return groupBox; } /** * create the border projection options section. */ QGroupBox* GuiDataFileSaveDialog::createBorderProjectionOptionsSection() { // // Remove duplicates check box // borderProjectionsRemoveDuplicatesCheckBox = new QCheckBox("Remove Duplicates"); borderProjectionsRemoveDuplicatesCheckBox->setChecked(true); QGroupBox* groupBox = new QGroupBox("Border Projection Options"); QGridLayout* gridLayout = new QGridLayout(groupBox); gridLayout->addWidget(borderProjectionsRemoveDuplicatesCheckBox, 0, 0, Qt::AlignLeft); return groupBox; } /** * create the cell options section. */ QGroupBox* GuiDataFileSaveDialog::createCellOptionsSection() { // // Surface type // QLabel* cellTypeLabel = new QLabel("Cells Associated With Surface"); cellSurfaceSelectionComboBox = new GuiBrainModelSelectionComboBox(false, true, false, ""); cellSurfaceSelectionComboBox->setSelectedBrainModel(theMainWindow->getBrainModelSurface()); QGroupBox* groupBox = new QGroupBox("Cell Options"); QGridLayout* gridLayout = new QGridLayout(groupBox); gridLayout->addWidget(cellTypeLabel, 0, 0, Qt::AlignLeft); gridLayout->addWidget(cellSurfaceSelectionComboBox, 0, 1); gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 100); return groupBox; } /** * create the coordinate options section. */ QGroupBox* GuiDataFileSaveDialog::createCoordinateOptionsSection() { // // Associated surface // QLabel* surfaceSelectionLabel = new QLabel("Associated Surface"); coordinateSurfaceSelectionComboBox = new GuiBrainModelSelectionComboBox(false, true, false, ""); coordinateSurfaceSelectionComboBox->setSelectedBrainModel(theMainWindow->getBrainModelSurface()); QObject::connect(coordinateSurfaceSelectionComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotLoadParametersForFileType())); // // Surface type // QLabel* surfaceTypeLabel = new QLabel("Save As Type"); coordinateTypeComboBox = new GuiSurfaceTypeComboBox(false); // // Structure // QLabel* structureLabel = new QLabel("Structure"); coordinateStructureComboBox = new GuiStructureComboBox(0, 0, true); // // Stereotaxic space // QLabel* stereotaxicSpaceLabel = new QLabel("Stereotaxic Space"); coordinateStereotaxicSpaceComboBox = new QComboBox(); coordinateStereotaxicSpaceComboBox->addItem("AC-PC"); coordinateStereotaxicSpaceComboBox->addItem("Anterior Commissure"); coordinateStereotaxicSpaceComboBox->addItem("Cartesian Standard"); coordinateStereotaxicSpaceComboBox->addItem("Cartesian Non-Standard"); coordinateStereotaxicSpaceComboBox->addItem("Center of Gravity"); coordinateStereotaxicSpaceComboBox->addItem("Native"); coordinateStereotaxicSpaceComboBox->addItem("Spherical Standard"); coordinateStereotaxicSpaceComboBox->addItem("Talairach"); coordinateStereotaxicSpaceComboBox->addItem("Unspecified"); std::vector allSpaces; StereotaxicSpace::getAllStereotaxicSpaces(allSpaces); for (unsigned int j = 0; j < allSpaces.size(); j++) { coordinateStereotaxicSpaceComboBox->addItem(allSpaces[j].getName()); } coordinateStereotaxicSpaceComboBox->setToolTip( "This selects the the coordinate frame for\n" "the coordinate file that is being saved."); // // Create group box and layout // QGroupBox* groupBox = new QGroupBox("Coordinate Options"); QGridLayout* gridLayout = new QGridLayout(groupBox); gridLayout->addWidget(surfaceSelectionLabel, 0, 0, Qt::AlignLeft); gridLayout->addWidget(coordinateSurfaceSelectionComboBox, 0, 1); gridLayout->addWidget(surfaceTypeLabel, 1, 0, Qt::AlignLeft); gridLayout->addWidget(coordinateTypeComboBox, 1, 1); gridLayout->addWidget(structureLabel, 2, 0, Qt::AlignLeft); gridLayout->addWidget(coordinateStructureComboBox, 2, 1); gridLayout->addWidget(stereotaxicSpaceLabel, 3, 0, Qt::AlignLeft); gridLayout->addWidget(coordinateStereotaxicSpaceComboBox, 3, 1); gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 100); return groupBox; } /** * create the foci options section. */ QGroupBox* GuiDataFileSaveDialog::createFociOptionsSection() { // // Save Coordinates // fociSaveOriginalCoordinatesRadioButton = new QRadioButton("Save Original Coordinates"); fociSaveProjectedCoordinatesRadioButton = new QRadioButton("Save Projected Coordinates"); QButtonGroup* buttGroup = new QButtonGroup(this); buttGroup->addButton(fociSaveOriginalCoordinatesRadioButton); buttGroup->addButton(fociSaveProjectedCoordinatesRadioButton); fociSaveOriginalCoordinatesRadioButton->setChecked(true); // // left surface // QLabel* leftSurfaceSelectionLabel = new QLabel("Left Surface"); fociLeftSurfaceSelectionComboBox = new GuiBrainModelSelectionComboBox(false, true, false, ""); fociLeftSurfaceSelectionComboBox->setSelectedBrainModel(theMainWindow->getBrainModelSurface()); // // right surface // QLabel* rightSurfaceSelectionLabel = new QLabel("Right Surface"); fociRightSurfaceSelectionComboBox = new GuiBrainModelSelectionComboBox(false, true, false, ""); fociRightSurfaceSelectionComboBox->setSelectedBrainModel(theMainWindow->getBrainModelSurface()); // // right surface // QLabel* cerebellumSurfaceSelectionLabel = new QLabel("Cerebellum Surface"); fociCerebellumSurfaceSelectionComboBox = new GuiBrainModelSelectionComboBox(false, true, false, ""); fociCerebellumSurfaceSelectionComboBox->setSelectedBrainModel(theMainWindow->getBrainModelSurface()); QGroupBox* groupBox = new QGroupBox("Foci Options"); QGridLayout* gridLayout = new QGridLayout(groupBox); gridLayout->addWidget(fociSaveOriginalCoordinatesRadioButton, 0, 0, 1, 1, Qt::AlignLeft); gridLayout->addWidget(fociSaveProjectedCoordinatesRadioButton, 1, 0, 1, 1, Qt::AlignLeft); gridLayout->addWidget(leftSurfaceSelectionLabel, 2, 0, Qt::AlignLeft); gridLayout->addWidget(fociLeftSurfaceSelectionComboBox, 2, 1); gridLayout->addWidget(rightSurfaceSelectionLabel, 3, 0, Qt::AlignLeft); gridLayout->addWidget(fociRightSurfaceSelectionComboBox, 3, 1); gridLayout->addWidget(cerebellumSurfaceSelectionLabel, 4, 0, Qt::AlignLeft); gridLayout->addWidget(fociCerebellumSurfaceSelectionComboBox, 4, 1); gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 100); return groupBox; } /** * select the image file for saving. */ void GuiDataFileSaveDialog::selectImageFile(const ImageFile* imageFile) { BrainSet* brainSet = theMainWindow->getBrainSet(); const int numImages = brainSet->getNumberOfImageFiles(); for (int i = 0; i < numImages; i++) { if (brainSet->getImageFile(i) == imageFile) { if (i < imageSelectionComboBox->count()) { imageSelectionComboBox->setCurrentIndex(i); break; } } } } /** * select a file. */ void GuiDataFileSaveDialog::selectFile(AbstractFile* af) { BrainSet* bs = theMainWindow->getBrainSet(); QString fileFilterName; if (dynamic_cast(af) != NULL) { fileFilterName = FileFilters::getAreaColorFileFilter(); } else if (dynamic_cast(af) != NULL) { fileFilterName = FileFilters::getArealEstimationFileFilter(); } else if (dynamic_cast(af) != NULL) { fileFilterName = FileFilters::getBorderColorFileFilter(); } else if (dynamic_cast(af) != NULL) { fileFilterName = FileFilters::getBorderGenericFileFilter(); } else if (dynamic_cast(af) != NULL) { fileFilterName = FileFilters::getBorderProjectionFileFilter(); } else if (dynamic_cast(af) != NULL) { fileFilterName = FileFilters::getCellColorFileFilter(); } else if (dynamic_cast(af) != NULL) { // // CUTS MUST BE BEFORE CELL SINCE CUTS DERIVED FROM CELL // fileFilterName = FileFilters::getCutsFileFilter(); } else if (dynamic_cast(af) != NULL) { // // FOCI MUST BE BEFORE CELL SINCE FOCI DERIVED FROM CELL // fileFilterName = FileFilters::getFociFileFilter(); } else if (dynamic_cast(af) != NULL) { // // CONTOUR CELL MUST BE BEFORE CELL SINCE CONTOUR CELL DERIVED FROM CELL // fileFilterName = FileFilters::getContourCellFileFilter(); } else if (dynamic_cast(af) != NULL) { fileFilterName = FileFilters::getCellFileFilter(); } else if (dynamic_cast(af) != NULL) { // // FOCI MUST BE BEFORE CELL SINCE FOCI DERIVED FROM CELL // fileFilterName = FileFilters::getFociProjectionFileFilter(); } else if (dynamic_cast(af) != NULL) { fileFilterName = FileFilters::getCellProjectionFileFilter(); } else if (dynamic_cast(af) != NULL) { fileFilterName = FileFilters::getCocomacFileFilter(); } else if (dynamic_cast(af) != NULL) { fileFilterName = FileFilters::getContourCellColorFileFilter(); } else if (dynamic_cast(af) != NULL) { fileFilterName = FileFilters::getContourFileFilter(); } else if (dynamic_cast(af) != NULL) { fileFilterName = FileFilters::getCoordinateGenericFileFilter(); for (int i = 0; i < bs->getNumberOfBrainModels(); i++) { BrainModelSurface* bms = bs->getBrainModelSurface(i); if (bms != NULL) { if (bms->getCoordinateFile() == af) { coordinateSurfaceSelectionComboBox->setSelectedBrainModel(bms); break; } } } } else if (dynamic_cast(af) != NULL) { fileFilterName = FileFilters::getDeformationFieldFileFilter(); } else if (dynamic_cast(af) != NULL) { fileFilterName = FileFilters::getDeformationMapFileFilter(); } else if (dynamic_cast(af) != NULL) { fileFilterName = FileFilters::getFociColorFileFilter(); } else if (dynamic_cast(af) != NULL) { fileFilterName = FileFilters::getFociSearchFileFilter(); } else if (dynamic_cast(af) != NULL) { fileFilterName = FileFilters::getGeodesicDistanceFileFilter(); } else if (dynamic_cast(af) != NULL) { fileFilterName = FileFilters::getImageSaveFileFilter(); selectImageFile(dynamic_cast(af)); } else if (dynamic_cast(af) != NULL) { fileFilterName = FileFilters::getLatitudeLongitudeFileFilter(); } else if (dynamic_cast(af) != NULL) { // // SHAPE MUST BE BEFORE METRIC SINCE SHAPE DERIVED FROM METRIC // fileFilterName = FileFilters::getSurfaceShapeFileFilter(); } else if (dynamic_cast(af) != NULL) { fileFilterName = FileFilters::getMetricFileFilter(); } else if (dynamic_cast(af) != NULL) { // // PROB ATLAS MUST BE BEFORE PAINT SINCE PROB ATLAS DERIVED FROM PAINT // fileFilterName = FileFilters::getProbAtlasFileFilter(); } else if (dynamic_cast(af) != NULL) { fileFilterName = FileFilters::getPaintFileFilter(); } else if (dynamic_cast(af) != NULL) { fileFilterName = FileFilters::getPaletteFileFilter(); } else if (dynamic_cast(af) != NULL) { fileFilterName = FileFilters::getParamsFileFilter(); } else if (dynamic_cast(af) != NULL) { fileFilterName = FileFilters::getRgbPaintFileFilter(); } else if (dynamic_cast(af) != NULL) { fileFilterName = FileFilters::getSceneFileFilter(); } else if (dynamic_cast(af) != NULL) { fileFilterName = FileFilters::getSectionFileFilter(); } else if (dynamic_cast(af) != NULL) { fileFilterName = FileFilters::getStudyCollectionFileFilter(); } else if (dynamic_cast(af) != NULL) { fileFilterName = FileFilters::getStudyMetaDataFileFilter(); } else if (dynamic_cast(af) != NULL) { fileFilterName = FileFilters::getGiftiVectorFileFilter(); VectorFile* vf = dynamic_cast(af); vectorFileSelectionComboBox->setSelectedVectorFile(vf); } else if (dynamic_cast(af) != NULL) { fileFilterName = FileFilters::getTopographyFileFilter(); } else if (dynamic_cast(af) != NULL) { fileFilterName = FileFilters::getTopologyGenericFileFilter(); topologySelectionComboBox->setSelectedTopologyFile(dynamic_cast(af)); } else if (dynamic_cast(af) != NULL) { fileFilterName = FileFilters::getTransformationMatrixFileFilter(); } else if (dynamic_cast(af) != NULL) { fileFilterName = FileFilters::getVocabularyFileFilter(); } else if (dynamic_cast(af) != NULL) { fileFilterName = FileFilters::getVolumeGenericFileFilter(); bool gotItFlag = false; VolumeFile* vf = dynamic_cast(af); for (int i = 0; i < bs->getNumberOfVolumeAnatomyFiles(); i++) { if (bs->getVolumeAnatomyFile(i) == vf) { volumeAnatomyFileSelectionComboBox->setSelectedVolumeFile(vf); fileFilterName = FileFilters::getVolumeAnatomyFileFilter(); gotItFlag = true; break; } } if (gotItFlag == false) { for (int i = 0; i < bs->getNumberOfVolumeFunctionalFiles(); i++) { if (bs->getVolumeFunctionalFile(i) == vf) { volumeFunctionalFileSelectionComboBox->setSelectedVolumeFile(vf); fileFilterName = FileFilters::getVolumeFunctionalFileFilter(); gotItFlag = true; break; } } } if (gotItFlag == false) { for (int i = 0; i < bs->getNumberOfVolumePaintFiles(); i++) { if (bs->getVolumePaintFile(i) == vf) { volumePaintFileSelectionComboBox->setSelectedVolumeFile(vf); fileFilterName = FileFilters::getVolumePaintFileFilter(); gotItFlag = true; break; } } } if (gotItFlag == false) { for (int i = 0; i < bs->getNumberOfVolumeProbAtlasFiles(); i++) { if (bs->getVolumeProbAtlasFile(i) == vf) { volumeProbAtlasFileSelectionComboBox->setSelectedVolumeFile(vf); fileFilterName = FileFilters::getVolumeProbAtlasFileFilter(); gotItFlag = true; break; } } } if (gotItFlag == false) { for (int i = 0; i < bs->getNumberOfVolumeRgbFiles(); i++) { if (bs->getVolumeRgbFile(i) == vf) { volumeRgbFileSelectionComboBox->setSelectedVolumeFile(vf); fileFilterName = FileFilters::getVolumeRgbFileFilter(); gotItFlag = true; break; } } } if (gotItFlag == false) { for (int i = 0; i < bs->getNumberOfVolumeSegmentationFiles(); i++) { if (bs->getVolumeSegmentationFile(i) == vf) { volumeSegmentationFileSelectionComboBox->setSelectedVolumeFile(vf); fileFilterName = FileFilters::getVolumeSegmentationFileFilter(); gotItFlag = true; break; } } } if (gotItFlag == false) { for (int i = 0; i < bs->getNumberOfVolumeVectorFiles(); i++) { if (bs->getVolumeVectorFile(i) == vf) { volumeVectorFileSelectionComboBox->setSelectedVolumeFile(vf); fileFilterName = FileFilters::getVolumeVectorFileFilter(); gotItFlag = true; break; } } } } else if (dynamic_cast(af) != NULL) { fileFilterName = FileFilters::getVtkModelFileFilter(); } else if (dynamic_cast(af) != NULL) { fileFilterName = FileFilters::getWustlRegionFileFilter(); } else { QMessageBox::critical(this, "ERROR", "PROGRAM ERROR: Unrecongnized file type for selection: " + QString(af->getDescriptiveName())); return; } // // Select the file type // selectFileType(fileFilterName); slotLoadParametersForFileType(); } /** * create the image options section. */ QGroupBox* GuiDataFileSaveDialog::createImageOptionsSection() { BrainSet* brainSet = theMainWindow->getBrainSet(); // // image combo box and label // QLabel* imageLabel = new QLabel("Image"); imageSelectionComboBox = new QComboBox; QObject::connect(imageSelectionComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotLoadParametersForFileType())); for (int i = 0; i < brainSet->getNumberOfImageFiles(); i++) { imageSelectionComboBox->addItem( FileUtilities::basename(brainSet->getImageFile(i)->getFileName())); } QGroupBox* groupBox = new QGroupBox("Image Options"); QGridLayout* gridLayout = new QGridLayout(groupBox); gridLayout->addWidget(imageLabel, 0, 0, Qt::AlignLeft); gridLayout->addWidget(imageSelectionComboBox, 0, 1); gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 100); return groupBox; } /** * create the topology options section. */ QGroupBox* GuiDataFileSaveDialog::createTopologyOptionsSection() { // // Topology selection // QLabel* topologySelectionLabel = new QLabel("Topology File"); topologySelectionComboBox = new GuiTopologyFileComboBox; BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { topologySelectionComboBox->setSelectedTopologyFile(bms->getTopologyFile()); } QObject::connect(topologySelectionComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotLoadParametersForFileType())); // // Topology Type // QLabel* topologyTypeLabel = new QLabel("Save As Type"); topologyTypeComboBox = new GuiTopologyTypeComboBox(false); // // Group box and layout // QGroupBox* groupBox = new QGroupBox("Topology Options"); QGridLayout* gridLayout = new QGridLayout(groupBox); gridLayout->addWidget(topologySelectionLabel, 0, 0, Qt::AlignLeft); gridLayout->addWidget(topologySelectionComboBox, 0, 1); gridLayout->addWidget(topologyTypeLabel, 1, 0, Qt::AlignLeft); gridLayout->addWidget(topologyTypeComboBox, 1, 1); gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 100); return groupBox; } /** * Create the vector options section. */ QGroupBox* GuiDataFileSaveDialog::createVectorOptionsSection() { // // Vector File Selection // QLabel* vectorSelectionLabel = new QLabel("Vector File"); vectorFileSelectionComboBox = new GuiVectorFileComboBox; QObject::connect(vectorFileSelectionComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotLoadParametersForFileType())); QGroupBox* groupBox = new QGroupBox("Vector Options"); QGridLayout* gridLayout = new QGridLayout(groupBox); gridLayout->addWidget(vectorSelectionLabel, 0, 0, Qt::AlignLeft); gridLayout->addWidget(vectorFileSelectionComboBox, 0, 1, Qt::AlignLeft); gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 100); return groupBox; } /** * create the volume anatomy options section. */ QGroupBox* GuiDataFileSaveDialog::createVolumeAnatomyOptionsSection() { // // File selection label and combo box // QLabel* fileSelectionLabel = new QLabel("Volume File"); volumeAnatomyFileSelectionComboBox = new GuiVolumeFileSelectionComboBox(VolumeFile::VOLUME_TYPE_ANATOMY, true); QObject::connect(volumeAnatomyFileSelectionComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotLoadParametersForFileType())); // // volume label // QLabel* volumeLabelLabel = new QLabel("Volume Label"); volumeAnatomyLabelLineEdit = new QLineEdit; // // Voxel data type // QLabel* voxelDataTypeLabel = new QLabel("Voxel Data Type"); volumeAnatomyVolumeDataTypeComboBox = new GuiVolumeVoxelDataTypeComboBox; // // Write compressed // volumeAnatomyWriteCompressedCheckBox = new QCheckBox("Write Volume Data GZipped (compressed)"); // // Group box and layout // QGroupBox* groupBox = new QGroupBox("Anatomy Volume Options"); QGridLayout* gridLayout = new QGridLayout(groupBox); gridLayout->addWidget(fileSelectionLabel, 0, 0, Qt::AlignLeft); gridLayout->addWidget(volumeAnatomyFileSelectionComboBox, 0, 1); gridLayout->addWidget(volumeLabelLabel, 1, 0, Qt::AlignLeft); gridLayout->addWidget(volumeAnatomyLabelLineEdit, 1, 1); gridLayout->addWidget(voxelDataTypeLabel, 2, 0, Qt::AlignLeft); gridLayout->addWidget(volumeAnatomyVolumeDataTypeComboBox, 2, 1); gridLayout->addWidget(volumeAnatomyWriteCompressedCheckBox, 3, 0, 1, 2, Qt::AlignLeft); return groupBox; } /** * create the volume functional options section. */ QGroupBox* GuiDataFileSaveDialog::createVolumeFunctionalOptionsSection() { // // File selection label and combo box // QLabel* fileSelectionLabel = new QLabel("Volume File"); volumeFunctionalFileSelectionComboBox = new GuiVolumeFileSelectionComboBox(VolumeFile::VOLUME_TYPE_FUNCTIONAL, true); QObject::connect(volumeFunctionalFileSelectionComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotLoadParametersForFileType())); // // volume label // QLabel* volumeLabelLabel = new QLabel("Volume Label"); volumeFunctionalLabelLineEdit = new QLineEdit; // // Voxel data type // QLabel* voxelDataTypeLabel = new QLabel("Voxel Data Type"); volumeFunctionalVolumeDataTypeComboBox = new GuiVolumeVoxelDataTypeComboBox; // // Write compressed // volumeFunctionalWriteCompressedCheckBox = new QCheckBox("Write Volume Data GZipped (compressed)"); // // Group box and layout // QGroupBox* groupBox = new QGroupBox("Functional Volume Options"); QGridLayout* gridLayout = new QGridLayout(groupBox); gridLayout->addWidget(fileSelectionLabel, 0, 0, Qt::AlignLeft); gridLayout->addWidget(volumeFunctionalFileSelectionComboBox, 0, 1); gridLayout->addWidget(volumeLabelLabel, 1, 0, Qt::AlignLeft); gridLayout->addWidget(volumeFunctionalLabelLineEdit, 1, 1); gridLayout->addWidget(voxelDataTypeLabel, 2, 0, Qt::AlignLeft); gridLayout->addWidget(volumeFunctionalVolumeDataTypeComboBox, 2, 1); gridLayout->addWidget(volumeFunctionalWriteCompressedCheckBox, 3, 0, 1, 2, Qt::AlignLeft); return groupBox; } /** * create the volume paint options section. */ QGroupBox* GuiDataFileSaveDialog::createVolumePaintOptionsSection() { // // File selection label and combo box // QLabel* fileSelectionLabel = new QLabel("Volume File"); volumePaintFileSelectionComboBox = new GuiVolumeFileSelectionComboBox(VolumeFile::VOLUME_TYPE_PAINT, true); QObject::connect(volumePaintFileSelectionComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotLoadParametersForFileType())); // // volume label // QLabel* volumeLabelLabel = new QLabel("Volume Label"); volumePaintLabelLineEdit = new QLineEdit; // // Voxel data type // QLabel* voxelDataTypeLabel = new QLabel("Voxel Data Type"); volumePaintVolumeDataTypeComboBox = new GuiVolumeVoxelDataTypeComboBox; // // Write compressed // volumePaintWriteCompressedCheckBox = new QCheckBox("Write Volume Data GZipped (compressed)"); // // Group box and layout // QGroupBox* groupBox = new QGroupBox("Paint Volume Options"); QGridLayout* gridLayout = new QGridLayout(groupBox); gridLayout->addWidget(fileSelectionLabel, 0, 0, Qt::AlignLeft); gridLayout->addWidget(volumePaintFileSelectionComboBox, 0, 1); gridLayout->addWidget(volumeLabelLabel, 1, 0, Qt::AlignLeft); gridLayout->addWidget(volumePaintLabelLineEdit, 1, 1); gridLayout->addWidget(voxelDataTypeLabel, 2, 0, Qt::AlignLeft); gridLayout->addWidget(volumePaintVolumeDataTypeComboBox, 2, 1); gridLayout->addWidget(volumePaintWriteCompressedCheckBox, 3, 0, 1, 2, Qt::AlignLeft); return groupBox; } /** * create the prob atlas volume options section. */ QGroupBox* GuiDataFileSaveDialog::createVolumeProbAtlasOptionsSection() { // // File selection label and combo box // QLabel* fileSelectionLabel = new QLabel("Volume File"); volumeProbAtlasFileSelectionComboBox = new GuiVolumeFileSelectionComboBox(VolumeFile::VOLUME_TYPE_PROB_ATLAS, true); QObject::connect(volumeProbAtlasFileSelectionComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotLoadParametersForFileType())); if (alwaysSaveAllProbAtlasVolumes) { fileSelectionLabel->hide(); volumeProbAtlasFileSelectionComboBox->hide(); } // // volume label // QLabel* volumeLabelLabel = new QLabel("Volume Label"); volumeProbAtlasLabelLineEdit = new QLineEdit; // // Voxel data type // QLabel* voxelDataTypeLabel = new QLabel("Voxel Data Type"); volumeProbAtlasVolumeDataTypeComboBox = new GuiVolumeVoxelDataTypeComboBox; // // Write compressed // volumeProbAtlasWriteCompressedCheckBox = new QCheckBox("Write Volume Data GZipped (compressed)"); // // Group box and layout // QGroupBox* groupBox = new QGroupBox("ProbAtlas Volume Options"); QGridLayout* gridLayout = new QGridLayout(groupBox); gridLayout->addWidget(fileSelectionLabel, 0, 0, Qt::AlignLeft); gridLayout->addWidget(volumeProbAtlasFileSelectionComboBox, 0, 1); gridLayout->addWidget(volumeLabelLabel, 1, 0, Qt::AlignLeft); gridLayout->addWidget(volumeProbAtlasLabelLineEdit, 1, 1); gridLayout->addWidget(voxelDataTypeLabel, 2, 0, Qt::AlignLeft); gridLayout->addWidget(volumeProbAtlasVolumeDataTypeComboBox, 2, 1); gridLayout->addWidget(volumeProbAtlasWriteCompressedCheckBox, 3, 0, 1, 2, Qt::AlignLeft); return groupBox; } /** * create the volume rgb options section. */ QGroupBox* GuiDataFileSaveDialog::createVolumeRgbOptionsSection() { // // File selection label and combo box // QLabel* fileSelectionLabel = new QLabel("Volume File"); volumeRgbFileSelectionComboBox = new GuiVolumeFileSelectionComboBox(VolumeFile::VOLUME_TYPE_RGB, true); QObject::connect(volumeRgbFileSelectionComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotLoadParametersForFileType())); // // volume label // QLabel* volumeLabelLabel = new QLabel("Volume Label"); volumeRgbLabelLineEdit = new QLineEdit; // // Voxel data type // QLabel* voxelDataTypeLabel = new QLabel("Voxel Data Type"); volumeRgbVolumeDataTypeComboBox = new GuiVolumeVoxelDataTypeComboBox; // // Write compressed // volumeRgbWriteCompressedCheckBox = new QCheckBox("Write Volume Data GZipped (compressed)"); // // Group box and layout // QGroupBox* groupBox = new QGroupBox("Rgb Volume Options"); QGridLayout* gridLayout = new QGridLayout(groupBox); gridLayout->addWidget(fileSelectionLabel, 0, 0, Qt::AlignLeft); gridLayout->addWidget(volumeRgbFileSelectionComboBox, 0, 1); gridLayout->addWidget(volumeLabelLabel, 1, 0, Qt::AlignLeft); gridLayout->addWidget(volumeRgbLabelLineEdit, 1, 1); gridLayout->addWidget(voxelDataTypeLabel, 2, 0, Qt::AlignLeft); gridLayout->addWidget(volumeRgbVolumeDataTypeComboBox, 2, 1); gridLayout->addWidget(volumeRgbWriteCompressedCheckBox, 3, 0, 1, 2, Qt::AlignLeft); return groupBox; } /** * create the volume segmentation options section. */ QGroupBox* GuiDataFileSaveDialog::createVolumeSegmentationOptionsSection() { // // File selection label and combo box // QLabel* fileSelectionLabel = new QLabel("Volume File"); volumeSegmentationFileSelectionComboBox = new GuiVolumeFileSelectionComboBox(VolumeFile::VOLUME_TYPE_SEGMENTATION, true); QObject::connect(volumeSegmentationFileSelectionComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotLoadParametersForFileType())); // // volume label // QLabel* volumeLabelLabel = new QLabel("Volume Label"); volumeSegmentationLabelLineEdit = new QLineEdit; // // Voxel data type // QLabel* voxelDataTypeLabel = new QLabel("Voxel Data Type"); volumeSegmentationVolumeDataTypeComboBox = new GuiVolumeVoxelDataTypeComboBox; // // Write compressed // volumeSegmentationWriteCompressedCheckBox = new QCheckBox("Write Volume Data GZipped (compressed)"); // // Group box and layout // QGroupBox* groupBox = new QGroupBox("Segmentation Volume Options"); QGridLayout* gridLayout = new QGridLayout(groupBox); gridLayout->addWidget(fileSelectionLabel, 0, 0, Qt::AlignLeft); gridLayout->addWidget(volumeSegmentationFileSelectionComboBox, 0, 1); gridLayout->addWidget(volumeLabelLabel, 1, 0, Qt::AlignLeft); gridLayout->addWidget(volumeSegmentationLabelLineEdit, 1, 1); gridLayout->addWidget(voxelDataTypeLabel, 2, 0, Qt::AlignLeft); gridLayout->addWidget(volumeSegmentationVolumeDataTypeComboBox, 2, 1); gridLayout->addWidget(volumeSegmentationWriteCompressedCheckBox, 3, 0, 1, 2, Qt::AlignLeft); return groupBox; } /** * create the volume options section. */ QGroupBox* GuiDataFileSaveDialog::createVolumeVectorOptionsSection() { // // File selection label and combo box // QLabel* fileSelectionLabel = new QLabel("Volume File"); volumeVectorFileSelectionComboBox = new GuiVolumeFileSelectionComboBox(VolumeFile::VOLUME_TYPE_VECTOR, true); QObject::connect(volumeVectorFileSelectionComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotLoadParametersForFileType())); // // volume label // QLabel* volumeLabelLabel = new QLabel("Volume Label"); volumeVectorLabelLineEdit = new QLineEdit; // // Voxel data type // QLabel* voxelDataTypeLabel = new QLabel("Voxel Data Type"); volumeVectorVolumeDataTypeComboBox = new GuiVolumeVoxelDataTypeComboBox; // // Write compressed // volumeVectorWriteCompressedCheckBox = new QCheckBox("Write Volume Data GZipped (compressed)"); // // Group box and layout // QGroupBox* groupBox = new QGroupBox("Vector Volume Options"); QGridLayout* gridLayout = new QGridLayout(groupBox); gridLayout->addWidget(fileSelectionLabel, 0, 0, Qt::AlignLeft); gridLayout->addWidget(volumeVectorFileSelectionComboBox, 0, 1); gridLayout->addWidget(volumeLabelLabel, 1, 0, Qt::AlignLeft); gridLayout->addWidget(volumeVectorLabelLineEdit, 1, 1); gridLayout->addWidget(voxelDataTypeLabel, 2, 0, Qt::AlignLeft); gridLayout->addWidget(volumeVectorVolumeDataTypeComboBox, 2, 1); gridLayout->addWidget(volumeVectorWriteCompressedCheckBox, 3, 0, 1, 2, Qt::AlignLeft); return groupBox; } /** * create the vtk model options section. */ QGroupBox* GuiDataFileSaveDialog::createVtkModelOptionsSection() { BrainSet* brainSet = theMainWindow->getBrainSet(); // // VTK model selection and label // QLabel* vtkModelLabel = new QLabel("VTK Model"); vtkModelSelectionComboBox = new QComboBox; for (int i = 0; i < brainSet->getNumberOfVtkModelFiles(); i++) { vtkModelSelectionComboBox->addItem( FileUtilities::basename(brainSet->getVtkModelFile(i)->getFileName())); } QGroupBox* groupBox = new QGroupBox("VTK Model Options"); QGridLayout* gridLayout = new QGridLayout(groupBox); gridLayout->addWidget(vtkModelLabel, 0, 0, Qt::AlignLeft); gridLayout->addWidget(vtkModelSelectionComboBox, 0, 1); gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 100); return groupBox; } /** * create the export volume section. */ QGroupBox* GuiDataFileSaveDialog::createExportVolumeOptionsSection() { // // Volume selection // exportVolumeSelectionControl = new GuiVolumeSelectionControl(0, true, true, true, true, true, true, true, GuiVolumeSelectionControl::LABEL_MODE_FILE_LABEL_AND_NAME, 0, false, false, false); QGroupBox* groupBox = new QGroupBox("Export Volume Options"); QGridLayout* gridLayout = new QGridLayout(groupBox); gridLayout->addWidget(exportVolumeSelectionControl, 0, 0, Qt::AlignLeft); return groupBox; } /** * create the export surface section. */ QGroupBox* GuiDataFileSaveDialog::createExportSurfaceOptionsSection() { // // Surface Selection // QLabel* surfaceLabel = new QLabel("Surface"); exportSurfaceSelectionControl = new GuiBrainModelSelectionComboBox(false, true, false, ""); exportSurfaceSelectionControl->setSelectedBrainModel(theMainWindow->getBrainModelSurface()); QGroupBox* groupBox = new QGroupBox("Export Surface Options"); QGridLayout* gridLayout = new QGridLayout(groupBox); gridLayout->addWidget(surfaceLabel, 0, 0, Qt::AlignLeft); gridLayout->addWidget(exportSurfaceSelectionControl, 0, 1); gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 100); return groupBox; } /** * create paint export options section. */ QGroupBox* GuiDataFileSaveDialog::createPaintExportOptionsSection() { // // Surface Selection // QLabel* surfaceLabel = new QLabel("Surface"); exportPaintSurfaceSelectionControl = new GuiBrainModelSelectionComboBox(false, true, false, ""); exportPaintSurfaceSelectionControl->setSelectedBrainModel(theMainWindow->getBrainModelSurface()); // // Paint column // QLabel* paintColumLabel = new QLabel("Paint Column"); exportPaintColumnSelectionControl = new GuiNodeAttributeColumnSelectionComboBox(GUI_NODE_FILE_TYPE_PAINT, false, false, false); QGroupBox* groupBox = new QGroupBox("Export Paint Options"); QGridLayout* gridLayout = new QGridLayout(groupBox); gridLayout->addWidget(surfaceLabel, 0, 0, Qt::AlignLeft); gridLayout->addWidget(exportPaintSurfaceSelectionControl, 0, 1); gridLayout->addWidget(paintColumLabel, 1, 0, Qt::AlignLeft); gridLayout->addWidget(exportPaintColumnSelectionControl, 1, 1); gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 100); return groupBox; } /** * create shape export options section. */ QGroupBox* GuiDataFileSaveDialog::createShapeExportOptionsSection() { // // Surface Selection // QLabel* surfaceLabel = new QLabel("Surface"); exportShapeSurfaceSelectionControl = new GuiBrainModelSelectionComboBox(false, true, false, ""); exportShapeSurfaceSelectionControl->setSelectedBrainModel(theMainWindow->getBrainModelSurface()); // // Shape column // QLabel* shapeColumLabel = new QLabel("Shape Column"); exportShapeColumnSelectionControl = new GuiNodeAttributeColumnSelectionComboBox(GUI_NODE_FILE_TYPE_SURFACE_SHAPE, false, false, false); QGroupBox* groupBox = new QGroupBox("Export Shape Options"); QGridLayout* gridLayout = new QGridLayout(groupBox); gridLayout->addWidget(surfaceLabel, 0, 0, Qt::AlignLeft); gridLayout->addWidget(exportShapeSurfaceSelectionControl, 0, 1); gridLayout->addWidget(shapeColumLabel, 1, 0, Qt::AlignLeft); gridLayout->addWidget(exportShapeColumnSelectionControl, 1, 1); gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 100); return groupBox; } /** * create metric export options section. */ QGroupBox* GuiDataFileSaveDialog::createMetricExportOptionsSection() { // // Surface Selection // QLabel* surfaceLabel = new QLabel("Surface"); exportMetricSurfaceSelectionControl = new GuiBrainModelSelectionComboBox(false, true, false, ""); exportMetricSurfaceSelectionControl->setSelectedBrainModel(theMainWindow->getBrainModelSurface()); // // Metric column // QLabel* metricColumLabel = new QLabel("Metric Column"); exportMetricColumnSelectionControl = new GuiNodeAttributeColumnSelectionComboBox(GUI_NODE_FILE_TYPE_METRIC, false, false, false); QGroupBox* groupBox = new QGroupBox("Export Metric Options"); QGridLayout* gridLayout = new QGridLayout(groupBox); gridLayout->addWidget(surfaceLabel, 0, 0, Qt::AlignLeft); gridLayout->addWidget(exportMetricSurfaceSelectionControl, 0, 1); gridLayout->addWidget(metricColumLabel, 1, 0, Qt::AlignLeft); gridLayout->addWidget(exportMetricColumnSelectionControl, 1, 1); gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 100); return groupBox; } /** * create gifti options section. */ QGroupBox* GuiDataFileSaveDialog::createGiftiOptionsSection() { // // Surface Selection // QLabel* surfaceLabel = new QLabel("Surface"); giftiSurfaceSelectionControl = new GuiBrainModelSelectionComboBox(false, true, false, ""); QObject::connect(giftiSurfaceSelectionControl, SIGNAL(currentIndexChanged(int)), this, SLOT(slotLoadParametersForFileType())); giftiSurfaceSelectionControl->setSelectedBrainModel(theMainWindow->getBrainModelSurface()); QGroupBox* groupBox = new QGroupBox("GIFTI Surface Options"); QGridLayout* gridLayout = new QGridLayout(groupBox); gridLayout->addWidget(surfaceLabel, 0, 0, Qt::AlignLeft); gridLayout->addWidget(giftiSurfaceSelectionControl, 0, 1); gridLayout->setColumnStretch(0, 0); gridLayout->setColumnStretch(1, 100); return groupBox; } /** * create the metadata section. */ QWidget* GuiDataFileSaveDialog::createMetadataSection() { // // PubMed ID // QLabel* pubMedIdLabel = new QLabel("PubMed ID"); metadataPubMedIDLineEdit = new QLineEdit; // // Comment // QLabel* commentLabel = new QLabel("Comment"); metadataCommentTextEdit = new QTextEdit; // // Group box and layout for metadata // QGroupBox* metadataGroupBox = new QGroupBox("Metadata"); QGridLayout* metadataGridLayout = new QGridLayout(metadataGroupBox); metadataGridLayout->addWidget(pubMedIdLabel, 1, 0); metadataGridLayout->addWidget(metadataPubMedIDLineEdit, 1, 1); metadataGridLayout->addWidget(commentLabel, 3, 0); metadataGridLayout->addWidget(metadataCommentTextEdit, 3, 1); return metadataGroupBox; } /** * create the file information section. */ QWidget* GuiDataFileSaveDialog::createFileInformationSection() { // // file name push button and line edit // QPushButton* fileNamePushButton = new QPushButton("File Name..."); fileNamePushButton->setAutoDefault(false); fileNamePushButton->setFixedSize(fileNamePushButton->sizeHint()); QObject::connect(fileNamePushButton, SIGNAL(clicked()), this, SLOT(slotFileNamePushButton())); fileNameLineEdit = new QLineEdit; QObject::connect(fileNameLineEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotFileNameLineEditChanged(const QString&))); // // file type label and combo box // QLabel* fileTypeLabel = new QLabel("File Type "); fileTypeComboBox = new QComboBox; QObject::connect(fileTypeComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(slotFileTypeComboBox(const QString&))); // // Encoding // QLabel* fileEncodingLabel = new QLabel("Encoding"); fileEncodingComboBox = new QComboBox; // // add file extension check box // addFileExtensionCheckBox = new QCheckBox("Add File Name Extension (if needed)"); addFileExtensionCheckBox->setChecked(true); // // Layout the options // QGroupBox* fileInfoGroupBox = new QGroupBox("File Information"); QGridLayout* fileInfoGridLayout = new QGridLayout(fileInfoGroupBox); fileInfoGridLayout->addWidget(fileNamePushButton, 0, 0, Qt::AlignHCenter); fileInfoGridLayout->addWidget(fileNameLineEdit, 0, 1); fileInfoGridLayout->addWidget(fileTypeLabel, 1, 0, Qt::AlignHCenter); fileInfoGridLayout->addWidget(fileTypeComboBox, 1, 1); fileInfoGridLayout->addWidget(fileEncodingLabel, 2, 0, Qt::AlignHCenter); fileInfoGridLayout->addWidget(fileEncodingComboBox, 2, 1); fileInfoGridLayout->addWidget(addFileExtensionCheckBox, 3, 0, 1, 2, Qt::AlignLeft); return fileInfoGroupBox; } /** * called when a file type combo box selection is made. */ void GuiDataFileSaveDialog::slotFileTypeComboBox(const QString&) { slotLoadParametersForFileType(); } /** * get supported encodings from a file. */ void GuiDataFileSaveDialog::getSupportedEncodings(const AbstractFile& af, std::vector& encodingsOut, AbstractFile::FILE_FORMAT& preferredEncodingOut) { encodingsOut.clear(); if (af.getCanWrite(AbstractFile::FILE_FORMAT_ASCII)) { encodingsOut.push_back(AbstractFile::FILE_FORMAT_ASCII); } if (af.getCanWrite(AbstractFile::FILE_FORMAT_BINARY)) { encodingsOut.push_back(AbstractFile::FILE_FORMAT_BINARY); } if (af.getCanWrite(AbstractFile::FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE)) { encodingsOut.push_back(AbstractFile::FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE); } if (af.getCanWrite(AbstractFile::FILE_FORMAT_XML)) { encodingsOut.push_back(AbstractFile::FILE_FORMAT_XML); } if (af.getCanWrite(AbstractFile::FILE_FORMAT_XML_BASE64)) { encodingsOut.push_back(AbstractFile::FILE_FORMAT_XML_BASE64); } if (af.getCanWrite(AbstractFile::FILE_FORMAT_XML_GZIP_BASE64)) { encodingsOut.push_back(AbstractFile::FILE_FORMAT_XML_GZIP_BASE64); } if (af.getCanWrite(AbstractFile::FILE_FORMAT_OTHER)) { encodingsOut.push_back(AbstractFile::FILE_FORMAT_OTHER); } preferredEncodingOut = AbstractFile::FILE_FORMAT_ASCII; std::vector prefFormats = AbstractFile::getPreferredWriteType(); for (unsigned int i = 0; i < prefFormats.size(); i++) { if (af.getCanWrite(prefFormats[i])) { preferredEncodingOut = prefFormats[i]; break; } } } /** * get supported Xml encodings from a file. */ void GuiDataFileSaveDialog::getSupportedXmlEncodings(const AbstractFile& af, std::vector& encodingsOut, AbstractFile::FILE_FORMAT& preferredEncodingOut) { encodingsOut.clear(); encodingsOut.push_back(AbstractFile::FILE_FORMAT_XML); encodingsOut.push_back(AbstractFile::FILE_FORMAT_XML_BASE64); encodingsOut.push_back(AbstractFile::FILE_FORMAT_XML_GZIP_BASE64); preferredEncodingOut = AbstractFile::FILE_FORMAT_XML; std::vector prefFormats = AbstractFile::getPreferredWriteType(); for (unsigned int i = 0; i < prefFormats.size(); i++) { if (std::find(encodingsOut.begin(), encodingsOut.end(), prefFormats[i]) != encodingsOut.end()) { if (af.getCanWrite(prefFormats[i])) { preferredEncodingOut = prefFormats[i]; break; } } } } /** * load parameters for the selected file type. */ void GuiDataFileSaveDialog::slotLoadParametersForFileType() { if (fileOptionsWidgetGroup == NULL) { return; } // // Hide all file options groups // fileOptionsWidgetGroup->setHidden(true); BrainSet* brainSet = theMainWindow->getBrainSet(); AbstractFile* af = NULL; const QString filterName = fileTypeComboBox->currentText(); QString fileName; QString fileComment; QString filePubMedID; std::vector fileAvailableEncodings; AbstractFile::FILE_FORMAT preferredEncoding = AbstractFile::FILE_FORMAT_OTHER; if (filterName == FileFilters::getAreaColorFileFilter()) { af = brainSet->getAreaColorFile(); } else if (filterName == FileFilters::getArealEstimationFileFilter()) { af = brainSet->getArealEstimationFile(); } else if (filterName == FileFilters::getBorderGenericFileFilter()) { borderSurfaceOptionsGroupBox->show(); const BrainModelSurface* bms = borderSurfaceSelectionComboBox->getSelectedBrainModelSurface(); if (bms != NULL) { BrainModelBorderSet* bmbs = brainSet->getBorderSet(); BrainModelBorderFileInfo* bmi = bmbs->getBorderFileInfo(bms->getSurfaceType()); fileComment = bmi->getFileComment(); filePubMedID = bmi->getPubMedID(); fileName = bmi->getFileName(); borderSurfaceTypeComboBox->setSurfaceType(bms->getSurfaceType()); BorderFile bf; getSupportedEncodings(bf, fileAvailableEncodings, preferredEncoding); } } else if (filterName == FileFilters::getBorderVolumeFileFilter()) { af = brainSet->getVolumeBorderFile(); } else if (filterName == FileFilters::getBorderColorFileFilter()) { af = brainSet->getBorderColorFile(); } else if (filterName == FileFilters::getBorderProjectionFileFilter()) { borderProjectionOptionsGroupBox->show(); BrainModelBorderSet* bmbs = brainSet->getBorderSet(); BrainModelBorderFileInfo* bmi = bmbs->getBorderProjectionFileInfo(); fileComment = bmi->getFileComment(); filePubMedID = bmi->getPubMedID(); fileName = bmi->getFileName(); BorderProjectionFile bpf; getSupportedEncodings(bpf, fileAvailableEncodings, preferredEncoding); } else if (filterName == FileFilters::getCellFileFilter()) { cellOptionsGroupBox->show(); CellProjectionFile* cpf = brainSet->getCellProjectionFile(); fileComment = cpf->getFileComment(); filePubMedID = cpf->getFilePubMedID(); CellFile cf; getSupportedEncodings(cf, fileAvailableEncodings, preferredEncoding); } else if (filterName == FileFilters::getCellColorFileFilter()) { af = brainSet->getCellColorFile(); } else if (filterName == FileFilters::getCellProjectionFileFilter()) { af = brainSet->getCellProjectionFile(); } else if (filterName == FileFilters::getCellVolumeFileFilter()) { af = brainSet->getVolumeCellFile(); } else if (filterName == FileFilters::getCocomacFileFilter()) { af = brainSet->getCocomacFile(); } else if (filterName == FileFilters::getContourFileFilter()) { BrainModelContours* bmc = brainSet->getBrainModelContours(); if (bmc != NULL) { af = bmc->getContourFile(); } } else if (filterName == FileFilters::getContourCellFileFilter()) { af = brainSet->getContourCellFile(); } else if (filterName == FileFilters::getContourCellColorFileFilter()) { af = brainSet->getContourCellColorFile(); } else if (filterName == FileFilters::getCoordinateGenericFileFilter()) { coordinateOptionsGroupBox->show(); BrainModelSurface* bms = coordinateSurfaceSelectionComboBox->getSelectedBrainModelSurface(); if (bms != NULL) { coordinateTypeComboBox->setSurfaceType(bms->getSurfaceType()); coordinateStructureComboBox->setStructure(bms->getStructure().getType()); CoordinateFile* cf = bms->getCoordinateFile(); const QString spaceName = cf->getHeaderTag(AbstractFile::headerTagCoordFrameID); for (int i = 0; i < coordinateStereotaxicSpaceComboBox->count(); i++) { if (spaceName == coordinateStereotaxicSpaceComboBox->itemText(i)) { coordinateStereotaxicSpaceComboBox->setCurrentIndex(i); break; } } af = cf; } } else if (filterName == FileFilters::getCutsFileFilter()) { af = brainSet->getCutsFile(); } else if (filterName == FileFilters::getDeformationFieldFileFilter()) { af = brainSet->getDeformationFieldFile(); } else if (filterName == FileFilters::getFociFileFilter()) { fociOptionsGroupBox->show(); const FociProjectionFile* fpf = brainSet->getFociProjectionFile(); fileComment = fpf->getFileComment(); filePubMedID = fpf->getFilePubMedID(); FociFile ff; getSupportedEncodings(ff, fileAvailableEncodings, preferredEncoding); } else if (filterName == FileFilters::getFociColorFileFilter()) { af = brainSet->getFociColorFile(); } else if (filterName == FileFilters::getFociProjectionFileFilter()) { af = brainSet->getFociProjectionFile(); } else if (filterName == FileFilters::getFociSearchFileFilter()) { af = brainSet->getFociSearchFile(); } else if (filterName == FileFilters::getGeodesicDistanceFileFilter()) { af = brainSet->getGeodesicDistanceFile(); } else if (filterName == FileFilters::getGiftiCoordinateFileFilter()) { coordinateOptionsGroupBox->show(); BrainModelSurface* bms = coordinateSurfaceSelectionComboBox->getSelectedBrainModelSurface(); if (bms != NULL) { coordinateTypeComboBox->setSurfaceType(bms->getSurfaceType()); coordinateStructureComboBox->setStructure(bms->getStructure().getType()); CoordinateFile* cf = bms->getCoordinateFile(); const QString spaceName = cf->getHeaderTag(AbstractFile::headerTagCoordFrameID); for (int i = 0; i < coordinateStereotaxicSpaceComboBox->count(); i++) { if (spaceName == coordinateStereotaxicSpaceComboBox->itemText(i)) { coordinateStereotaxicSpaceComboBox->setCurrentIndex(i); break; } } af = cf; } } else if (filterName == FileFilters::getGiftiFunctionalFileFilter()) { MetricFile* mf = brainSet->getMetricFile(); fileComment = mf->getFileComment(); filePubMedID = mf->getFilePubMedID(); fileName = mf->getFileName(); getSupportedXmlEncodings(*mf, fileAvailableEncodings, preferredEncoding); } else if (filterName == FileFilters::getGiftiLabelFileFilter()) { PaintFile* pf = brainSet->getPaintFile(); fileComment = pf->getFileComment(); filePubMedID = pf->getFilePubMedID(); fileName = pf->getFileName(); getSupportedXmlEncodings(*pf, fileAvailableEncodings, preferredEncoding); } else if (filterName == FileFilters::getGiftiShapeFileFilter()) { SurfaceShapeFile* ssf = brainSet->getSurfaceShapeFile(); fileComment = ssf->getFileComment(); filePubMedID = ssf->getFilePubMedID(); fileName = ssf->getFileName(); getSupportedXmlEncodings(*ssf, fileAvailableEncodings, preferredEncoding); } else if (filterName == FileFilters::getGiftiSurfaceFileFilter()) { giftiSurfaceOptionsGroupBox->show(); BrainModelSurface* bms = giftiSurfaceSelectionControl->getSelectedBrainModelSurface(); if (bms != NULL) { CoordinateFile* cf = bms->getCoordinateFile(); fileComment = cf->getFileComment(); filePubMedID = cf->getFilePubMedID(); fileName = cf->getFileName(); getSupportedXmlEncodings(*cf, fileAvailableEncodings, preferredEncoding); } } else if (filterName == FileFilters::getGiftiTopologyFileFilter()) { topologyOptionsGroupBox->show(); TopologyFile* tf = topologySelectionComboBox->getSelectedTopologyFile(); if (tf != NULL) { topologyTypeComboBox->setTopologyType(tf->getTopologyType()); af = tf; } } else if (filterName == FileFilters::getImageSaveFileFilter()) { imageOptionsGroupBox->show(); const int indx = imageSelectionComboBox->currentIndex(); if ((indx >= 0) && (indx < brainSet->getNumberOfImageFiles())) { af = brainSet->getImageFile(indx); } } else if (filterName == FileFilters::getLatitudeLongitudeFileFilter()) { af = brainSet->getLatLonFile(); } else if (filterName == FileFilters::getMetricFileFilter()) { af = brainSet->getMetricFile(); } else if (filterName == FileFilters::getPaintFileFilter()) { af = brainSet->getPaintFile(); } else if (filterName == FileFilters::getPaletteFileFilter()) { af = brainSet->getPaletteFile(); } else if (filterName == FileFilters::getParamsFileFilter()) { af = brainSet->getParamsFile(); } else if (filterName == FileFilters::getProbAtlasFileFilter()) { af = brainSet->getProbabilisticAtlasSurfaceFile(); } else if (filterName == FileFilters::getRgbPaintFileFilter()) { af = brainSet->getRgbPaintFile(); } else if (filterName == FileFilters::getSceneFileFilter()) { af = brainSet->getSceneFile(); } else if (filterName == FileFilters::getSectionFileFilter()) { af = brainSet->getSectionFile(); } else if (filterName == FileFilters::getStudyCollectionFileFilter()) { af = brainSet->getStudyCollectionFile(); } else if (filterName == FileFilters::getStudyMetaDataFileFilter()) { af = brainSet->getStudyMetaDataFile(); } else if (filterName == FileFilters::getSurfaceShapeFileFilter()) { af = brainSet->getSurfaceShapeFile(); } else if (filterName == FileFilters::getGiftiVectorFileFilter()) { vectorOptionsGroupBox->show(); af = vectorFileSelectionComboBox->getSelectedVectorFile(); } else if (filterName == FileFilters::getTopographyFileFilter()) { af = brainSet->getTopographyFile(); } else if (filterName == FileFilters::getTopologyGenericFileFilter()) { topologyOptionsGroupBox->show(); TopologyFile* tf = topologySelectionComboBox->getSelectedTopologyFile(); if (tf != NULL) { topologyTypeComboBox->setTopologyType(tf->getTopologyType()); af = tf; } } else if (filterName == FileFilters::getTransformationMatrixFileFilter()) { af = brainSet->getTransformationMatrixFile(); } else if (filterName == FileFilters::getVocabularyFileFilter()) { af = brainSet->getVocabularyFile(); } else if (filterName == FileFilters::getVolumeAnatomyFileFilter()) { volumeAnatomyOptionsGroupBox->show(); VolumeFile* vf = 0; if (volumeAnatomyFileSelectionComboBox->getAllVolumesSelected()) { if (brainSet->getNumberOfVolumeAnatomyFiles() > 0) { VolumeFile* temp = brainSet->getVolumeAnatomyFile(0); af = temp; fileName = temp->getFileName(); volumeAnatomyVolumeDataTypeComboBox->setVolumeVoxelDataType(temp->getVoxelDataType()); volumeAnatomyWriteCompressedCheckBox->setChecked(temp->getDataFileWasZipped()); VolumeFile vf; getSupportedEncodings(vf, fileAvailableEncodings, preferredEncoding); } } else { vf = volumeAnatomyFileSelectionComboBox->getSelectedVolumeFile(); } if (vf != NULL) { volumeAnatomyLabelLineEdit->setText(vf->getDescriptiveLabel()); volumeAnatomyVolumeDataTypeComboBox->setVolumeVoxelDataType(vf->getVoxelDataType()); volumeAnatomyWriteCompressedCheckBox->setChecked(vf->getDataFileWasZipped()); af = vf; } } else if (filterName == FileFilters::getVolumeFunctionalFileFilter()) { volumeFunctionalOptionsGroupBox->show(); VolumeFile* vf = 0; if (volumeFunctionalFileSelectionComboBox->getAllVolumesSelected()) { if (brainSet->getNumberOfVolumeFunctionalFiles() > 0) { VolumeFile* temp = brainSet->getVolumeFunctionalFile(0); af = temp; fileName = temp->getFileName(); volumeFunctionalVolumeDataTypeComboBox->setVolumeVoxelDataType(temp->getVoxelDataType()); volumeFunctionalWriteCompressedCheckBox->setChecked(temp->getDataFileWasZipped()); VolumeFile vf; getSupportedEncodings(vf, fileAvailableEncodings, preferredEncoding); } } else { vf = volumeFunctionalFileSelectionComboBox->getSelectedVolumeFile(); } if (vf != NULL) { volumeFunctionalLabelLineEdit->setText(vf->getDescriptiveLabel()); volumeFunctionalVolumeDataTypeComboBox->setVolumeVoxelDataType(vf->getVoxelDataType()); volumeFunctionalWriteCompressedCheckBox->setChecked(vf->getDataFileWasZipped()); af = vf; } } else if (filterName == FileFilters::getVolumePaintFileFilter()) { volumePaintOptionsGroupBox->show(); VolumeFile* vf = 0; if (volumePaintFileSelectionComboBox->getAllVolumesSelected()) { if (brainSet->getNumberOfVolumePaintFiles() > 0) { VolumeFile* temp = brainSet->getVolumePaintFile(0); af = temp; fileName = temp->getFileName(); volumePaintVolumeDataTypeComboBox->setVolumeVoxelDataType(temp->getVoxelDataType()); volumePaintWriteCompressedCheckBox->setChecked(temp->getDataFileWasZipped()); VolumeFile vf; getSupportedEncodings(vf, fileAvailableEncodings, preferredEncoding); } } else { vf = volumePaintFileSelectionComboBox->getSelectedVolumeFile(); } if (vf != NULL) { volumePaintLabelLineEdit->setText(vf->getDescriptiveLabel()); volumePaintVolumeDataTypeComboBox->setVolumeVoxelDataType(vf->getVoxelDataType()); volumePaintWriteCompressedCheckBox->setChecked(vf->getDataFileWasZipped()); af = vf; } } else if (filterName == FileFilters::getVolumeProbAtlasFileFilter()) { volumeProbAtlasOptionsGroupBox->show(); VolumeFile* vf = 0; if (volumeProbAtlasFileSelectionComboBox->getAllVolumesSelected() || alwaysSaveAllProbAtlasVolumes) { if (brainSet->getNumberOfVolumeProbAtlasFiles() > 0) { VolumeFile* temp = brainSet->getVolumeProbAtlasFile(0); af = temp; fileName = temp->getFileName(); volumeProbAtlasVolumeDataTypeComboBox->setVolumeVoxelDataType(temp->getVoxelDataType()); volumeProbAtlasWriteCompressedCheckBox->setChecked(temp->getDataFileWasZipped()); VolumeFile vf; getSupportedEncodings(vf, fileAvailableEncodings, preferredEncoding); } } else { vf = volumeProbAtlasFileSelectionComboBox->getSelectedVolumeFile(); } if (vf != NULL) { volumeProbAtlasLabelLineEdit->setText(vf->getDescriptiveLabel()); volumeProbAtlasVolumeDataTypeComboBox->setVolumeVoxelDataType(vf->getVoxelDataType()); volumeProbAtlasWriteCompressedCheckBox->setChecked(vf->getDataFileWasZipped()); af = vf; } } else if (filterName == FileFilters::getVolumeRgbFileFilter()) { volumeRgbOptionsGroupBox->show(); VolumeFile* vf = 0; if (volumeRgbFileSelectionComboBox->getAllVolumesSelected()) { if (brainSet->getNumberOfVolumeRgbFiles() > 0) { VolumeFile* temp = brainSet->getVolumeRgbFile(0); af = temp; fileName = temp->getFileName(); volumeRgbVolumeDataTypeComboBox->setVolumeVoxelDataType(temp->getVoxelDataType()); volumeRgbWriteCompressedCheckBox->setChecked(temp->getDataFileWasZipped()); VolumeFile vf; getSupportedEncodings(vf, fileAvailableEncodings, preferredEncoding); } } else { vf = volumeRgbFileSelectionComboBox->getSelectedVolumeFile(); } if (vf != NULL) { volumeRgbLabelLineEdit->setText(vf->getDescriptiveLabel()); volumeRgbVolumeDataTypeComboBox->setVolumeVoxelDataType(vf->getVoxelDataType()); volumeRgbWriteCompressedCheckBox->setChecked(vf->getDataFileWasZipped()); af = vf; } } else if (filterName == FileFilters::getVolumeSegmentationFileFilter()) { volumeSegmentationOptionsGroupBox->show(); VolumeFile* vf = 0; if (volumeSegmentationFileSelectionComboBox->getAllVolumesSelected()) { if (brainSet->getNumberOfVolumeSegmentationFiles() > 0) { VolumeFile* temp = brainSet->getVolumeSegmentationFile(0); af = temp; fileName = temp->getFileName(); volumeSegmentationVolumeDataTypeComboBox->setVolumeVoxelDataType(temp->getVoxelDataType()); volumeSegmentationWriteCompressedCheckBox->setChecked(temp->getDataFileWasZipped()); VolumeFile vf; getSupportedEncodings(vf, fileAvailableEncodings, preferredEncoding); } } else { vf = volumeSegmentationFileSelectionComboBox->getSelectedVolumeFile(); } if (vf != NULL) { volumeSegmentationLabelLineEdit->setText(vf->getDescriptiveLabel()); volumeSegmentationVolumeDataTypeComboBox->setVolumeVoxelDataType(vf->getVoxelDataType()); volumeSegmentationWriteCompressedCheckBox->setChecked(vf->getDataFileWasZipped()); af = vf; } } else if (filterName == FileFilters::getVolumeVectorFileFilter()) { volumeVectorOptionsGroupBox->show(); VolumeFile* vf = 0; if (volumeVectorFileSelectionComboBox->getAllVolumesSelected()) { if (brainSet->getNumberOfVolumeVectorFiles() > 0) { VolumeFile* temp = brainSet->getVolumeVectorFile(0); af = temp; fileName = temp->getFileName(); volumeVectorVolumeDataTypeComboBox->setVolumeVoxelDataType(temp->getVoxelDataType()); volumeVectorWriteCompressedCheckBox->setChecked(temp->getDataFileWasZipped()); VolumeFile vf; getSupportedEncodings(vf, fileAvailableEncodings, preferredEncoding); } } else { vf = volumeVectorFileSelectionComboBox->getSelectedVolumeFile(); } if (vf != NULL) { volumeVectorLabelLineEdit->setText(vf->getDescriptiveLabel()); volumeVectorVolumeDataTypeComboBox->setVolumeVoxelDataType(vf->getVoxelDataType()); volumeVectorWriteCompressedCheckBox->setChecked(vf->getDataFileWasZipped()); af = vf; } } else if (filterName == FileFilters::getVtkModelFileFilter()) { vtkModelOptionsGroupBox->show(); const int indx = vtkModelSelectionComboBox->currentIndex(); if ((indx >= 0) && (indx < brainSet->getNumberOfVtkModelFiles())) { af = brainSet->getVtkModelFile(indx); } } else if (filterName == FileFilters::getWustlRegionFileFilter()) { af = brainSet->getWustlRegionFile(); } else if (filterName == FileFilters::getAnalyzeVolumeFileFilter()) { exportVolumeOptionsGroupBox->show(); } else if (filterName == FileFilters::getByuSurfaceFileFilter()) { exportSurfaceOptionsGroupBox->show(); } else if (filterName == FileFilters::getFreeSurferAsciiSurfaceFileFilter()) { exportSurfaceOptionsGroupBox->show(); } else if (filterName == FileFilters::getFreeSurferAsciiCurvatureFileFilter()) { exportShapeOptionsGroupBox->show(); } else if (filterName == FileFilters::getFreeSurferAsciiFunctionalFileFilter()) { exportMetricOptionsGroupBox->show(); } else if (filterName == FileFilters::getFreeSurferAsciiLabelFileFilter()) { exportPaintOptionsGroupBox->show(); } else if (filterName == FileFilters::getMincVolumeFileFilter()) { exportVolumeOptionsGroupBox->show(); } else if (filterName == FileFilters::getOpenInventorSurfaceFileFilter()) { exportSurfaceOptionsGroupBox->show(); } else if (filterName == FileFilters::getStlSurfaceFileFilter()) { exportSurfaceOptionsGroupBox->show(); } else if (filterName == FileFilters::getVrmlSurfaceFileFilter()) { exportSurfaceOptionsGroupBox->show(); } else if (filterName == FileFilters::getVtkSurfaceFileFilter()) { exportSurfaceOptionsGroupBox->show(); } else if (filterName == FileFilters::getVtkXmlSurfaceFileFilter()) { exportSurfaceOptionsGroupBox->show(); } else if (filterName == FileFilters::getVtkVolumeFileFilter()) { exportSurfaceOptionsGroupBox->show(); } else { std::cerr << "PROGRAM ERROR: unhandled file type " << filterName.toAscii().constData() << " at " << __LINE__ << " in " << __FILE__ << std::endl; return; } // // Get comment, pubmed, name, and encodings from file // if (af != NULL) { //SpecFile* sf = theMainWindow->getBrainSet()->getSpecFile(); //if (sf->getFileNamePath().empty() == false) { // sf->setCurrentDirectoryToSpecFileDirectory(); //} fileComment = af->getFileComment(); filePubMedID = af->getFilePubMedID(); fileName = af->getFileName(); getSupportedEncodings(*af, fileAvailableEncodings, preferredEncoding); preferredEncoding = af->getFileWriteType(); } // // Update name, comment and pubmed id in dialog // fileNameLineEdit->setText(fileName); metadataCommentTextEdit->setText(fileComment); metadataPubMedIDLineEdit->setText(filePubMedID); // // Update the encoding combo box // int fileEncodingComboBoxCurrentItem = 0; fileEncodingComboBox->clear(); if (fileAvailableEncodings.empty()) { fileAvailableEncodings.push_back(AbstractFile::FILE_FORMAT_OTHER); } for (unsigned int i = 0; i < fileAvailableEncodings.size(); i++) { const AbstractFile::FILE_FORMAT encoding = fileAvailableEncodings[i]; QString text = ""; switch (encoding) { case AbstractFile::FILE_FORMAT_ASCII: text = "ASCII (Text)"; break; case AbstractFile::FILE_FORMAT_BINARY: text = "Binary"; break; case AbstractFile::FILE_FORMAT_XML: text = "XML"; break; case AbstractFile::FILE_FORMAT_XML_BASE64: text = "XML Base64 Encoded Binary"; break; case AbstractFile::FILE_FORMAT_XML_GZIP_BASE64: text = "XML GZip Base64 Encoded Binary"; break; case AbstractFile::FILE_FORMAT_XML_EXTERNAL_BINARY: text = "XML External Binary"; break; case AbstractFile::FILE_FORMAT_OTHER: text = "Other"; break; case AbstractFile::FILE_FORMAT_COMMA_SEPARATED_VALUE_FILE: text = "Comma Separated Value File"; break; } if (preferredEncoding == encoding) { fileEncodingComboBoxCurrentItem = i; } fileEncodingComboBox->addItem(text, QVariant(int(encoding))); } if ((fileEncodingComboBoxCurrentItem >= 0) && (fileEncodingComboBoxCurrentItem < fileEncodingComboBox->count())) { fileEncodingComboBox->setCurrentIndex(fileEncodingComboBoxCurrentItem); } // // Dialog has been resized (maybe) // updateGeometry(); } /** * called when name line edit changed. */ void GuiDataFileSaveDialog::slotFileNameLineEditChanged(const QString& text) { savePushButton->setEnabled(text.isEmpty() == false); } /** * update file extension. */ void GuiDataFileSaveDialog::updateFileNamesFileExtension(QString& fileName, const QString& fileExtension) { // // Add extension ? // if (addFileExtensionCheckBox->isChecked()) { if (fileExtension.isEmpty() == false) { if (fileName.endsWith(fileExtension) == false) { fileName += fileExtension; } } } } /** * update metadata and name. */ void GuiDataFileSaveDialog::updateMetadataAndName(AbstractFile* af, QString& fileName, const QString& fileExtension) { // // Set file encoding // const int indx = fileEncodingComboBox->currentIndex(); af->setFileWriteType(static_cast( fileEncodingComboBox->itemData(indx).toInt())); // // Set PubMed ID // af->setFilePubMedID(metadataPubMedIDLineEdit->text()); // // Set comment // af->setFileComment(metadataCommentTextEdit->toPlainText()); // // Update file name extension // updateFileNamesFileExtension(fileName, fileExtension); } /** * called when accept/reject pressed. */ void GuiDataFileSaveDialog::done(int r) { if (r == GuiDataFileSaveDialog::Accepted) { BrainSet* brainSet = theMainWindow->getBrainSet(); QString fileName = fileNameLineEdit->text(); if (fileName.isEmpty()) { QMessageBox::critical(this, "ERROR", "File name is empty.", QMessageBox::Ok); return; } const QString fileNameNoPath = FileUtilities::basename(fileName); QFileInfo fi(fileName); if (fi.isDir()) { QMessageBox::critical(this, "ERROR", fileNameNoPath + " is a directory.", QMessageBox::Ok); return; } if (fi.exists()) { const QString message(fileName + QString(" already exists.\n") + QString("Do you want to replace it?")); if (QMessageBox::question(this, "Confirm Overwrite", message, QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) { return; } } // // Allow user to set the spec file name if not already set // if (brainSet->getSpecFileName().isEmpty()) { if (QMessageBox::information(this, "Spec File", "Would you like to create a Spec File ?", QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { // // Create spec file dialog will set the directory and create the spec file // GuiSpecFileCreationDialog sfcd(this); sfcd.exec(); PreferencesFile* pf = brainSet->getPreferencesFile(); pf->addToRecentSpecFiles(sfcd.getCreatedSpecFileName(), true); } } // // Type of file being saved // const QString filterName = fileTypeComboBox->currentText(); const AbstractFile::FILE_FORMAT fileFormat = static_cast( fileEncodingComboBox->itemData(fileEncodingComboBox->currentIndex()).toInt()); /* * = brainSet->get(); updateMetadataAndName(, fileName, SpecFile::getExtension()); brainSet->write(fileName); */ try { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); if (filterName == FileFilters::getAreaColorFileFilter()) { AreaColorFile* acf = brainSet->getAreaColorFile(); updateMetadataAndName(acf, fileName, SpecFile::getAreaColorFileExtension()); brainSet->writeAreaColorFile(fileName); } else if (filterName == FileFilters::getArealEstimationFileFilter()) { ArealEstimationFile* aef = brainSet->getArealEstimationFile(); updateMetadataAndName(aef, fileName, SpecFile::getArealEstimationFileExtension()); brainSet->writeArealEstimationFile(fileName); } else if (filterName == FileFilters::getBorderGenericFileFilter()) { BrainModelSurface* borderSurface = borderSurfaceSelectionComboBox->getSelectedBrainModelSurface(); if (borderSurface != NULL) { if (addFileExtensionCheckBox->isChecked()) { if (fileName.endsWith(SpecFile::getBorderFileExtension()) == false) { fileName += SpecFile::getBorderFileExtension(); } } brainSet->writeBorderFile( fileName, borderSurface, borderSurfaceTypeComboBox->getSurfaceType(), metadataCommentTextEdit->toPlainText(), metadataPubMedIDLineEdit->text(), borderSurfaceRemoveDuplicatesCheckBox->isChecked()); } } else if (filterName == FileFilters::getBorderVolumeFileFilter()) { BorderFile* bf = brainSet->getVolumeBorderFile(); updateMetadataAndName(bf, fileName, SpecFile::getBorderFileExtension()); theMainWindow->getBrainSet()->writeVolumeBorderFile(fileName); } else if (filterName == FileFilters::getBorderColorFileFilter()) { BorderColorFile* bcf = brainSet->getBorderColorFile(); updateMetadataAndName(bcf, fileName, SpecFile::getBorderColorFileExtension()); brainSet->writeBorderColorFile(fileName); } else if (filterName == FileFilters::getBorderProjectionFileFilter()) { if (addFileExtensionCheckBox->isChecked()) { if (fileName.endsWith(SpecFile::getBorderProjectionFileExtension()) == false) { fileName += SpecFile::getBorderProjectionFileExtension(); } } brainSet->writeBorderProjectionFile(fileName, metadataCommentTextEdit->toPlainText(), metadataPubMedIDLineEdit->text(), borderProjectionsRemoveDuplicatesCheckBox->isChecked()); } else if (filterName == FileFilters::getCellFileFilter()) { const BrainModelSurface* bms = cellSurfaceSelectionComboBox->getSelectedBrainModelSurface(); if (bms == NULL) { const QString msg("There is no surface for which cells should be saved."); QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", msg, QMessageBox::Ok); return; } if (addFileExtensionCheckBox->isChecked()) { if (fileName.endsWith(SpecFile::getCellFileExtension()) == false) { fileName += SpecFile::getCellFileExtension(); } } brainSet->writeCellFile(fileName, bms, fileFormat, metadataCommentTextEdit->toPlainText()); } else if (filterName == FileFilters::getCellColorFileFilter()) { CellColorFile* ccf = brainSet->getCellColorFile(); updateMetadataAndName(ccf, fileName, SpecFile::getCellColorFileExtension()); brainSet->writeCellColorFile(fileName); } else if (filterName == FileFilters::getCellProjectionFileFilter()) { CellProjectionFile* cpf = brainSet->getCellProjectionFile(); updateMetadataAndName(cpf, fileName, SpecFile::getCellProjectionFileExtension()); brainSet->writeCellProjectionFile(fileName); } else if (filterName == FileFilters::getCellVolumeFileFilter()) { CellFile* cf = brainSet->getVolumeCellFile(); updateMetadataAndName(cf, fileName, SpecFile::getCellFileExtension()); brainSet->writeVolumeCellFile(fileName); } else if (filterName == FileFilters::getCocomacFileFilter()) { CocomacConnectivityFile* cf = brainSet->getCocomacFile(); updateMetadataAndName(cf, fileName, SpecFile::getCocomacConnectivityFileExtension()); brainSet->writeCocomacConnectivityFile(fileName); } else if (filterName == FileFilters::getContourFileFilter()) { BrainModelContours* bmc = brainSet->getBrainModelContours(); if (bmc != NULL) { ContourFile* cf = bmc->getContourFile(); updateMetadataAndName(cf, fileName, SpecFile::getContourFileExtension()); brainSet->writeContourFile(fileName, cf); } } else if (filterName == FileFilters::getContourCellFileFilter()) { ContourCellFile* ccf = brainSet->getContourCellFile(); updateMetadataAndName(ccf, fileName, SpecFile::getContourCellFileExtension()); brainSet->writeContourCellFile(fileName); } else if (filterName == FileFilters::getContourCellColorFileFilter()) { ContourCellColorFile* cccf = brainSet->getContourCellColorFile(); updateMetadataAndName(cccf, fileName, SpecFile::getContourCellColorFileExtension()); brainSet->writeContourCellColorFile(fileName); } else if (filterName == FileFilters::getCoordinateGenericFileFilter()) { BrainModelSurface* bms = coordinateSurfaceSelectionComboBox->getSelectedBrainModelSurface(); if (bms == NULL) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", "No surface selected.", QMessageBox::Ok); return; } bms->setStructure(coordinateStructureComboBox->getSelectedStructure()); CoordinateFile* cf = bms->getCoordinateFile(); cf->setHeaderTag(AbstractFile::headerTagConfigurationID, coordinateStereotaxicSpaceComboBox->currentText()); updateMetadataAndName(cf, fileName, SpecFile::getCoordinateFileExtension()); brainSet->writeCoordinateFile(fileName, coordinateTypeComboBox->getSurfaceType(), cf); GuiFilesModified fm; fm.setCoordinateModified(); theMainWindow->fileModificationUpdate(fm); } else if (filterName == FileFilters::getCutsFileFilter()) { CutsFile* cf = brainSet->getCutsFile(); updateMetadataAndName(cf, fileName, SpecFile::getCutsFileExtension()); brainSet->writeCutsFile(fileName); } else if (filterName == FileFilters::getDeformationFieldFileFilter()) { DeformationFieldFile* dff = brainSet->getDeformationFieldFile(); updateMetadataAndName(dff, fileName, SpecFile::getDeformationFieldFileExtension()); brainSet->writeDeformationFieldFile(fileName); } else if (filterName == FileFilters::getFociFileFilter()) { if (addFileExtensionCheckBox->isChecked()) { if (fileName.endsWith(SpecFile::getFociFileExtension()) == false) { fileName += SpecFile::getFociFileExtension(); } } if (fociSaveOriginalCoordinatesRadioButton->isChecked()) { theMainWindow->getBrainSet()->writeFociFileOriginalCoordinates(fileName, fileFormat, metadataCommentTextEdit->toPlainText()); } else if (fociSaveProjectedCoordinatesRadioButton->isChecked()) { const BrainModelSurface* leftBms = fociLeftSurfaceSelectionComboBox->getSelectedBrainModelSurface(); const BrainModelSurface* rightBms = fociRightSurfaceSelectionComboBox->getSelectedBrainModelSurface(); const BrainModelSurface* cerebellumBms = fociCerebellumSurfaceSelectionComboBox->getSelectedBrainModelSurface(); if ((leftBms == NULL) && (rightBms == NULL) && (cerebellumBms == NULL)) { QString msg("There is no surface selected for which foci should be saved."); QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", msg, QMessageBox::Ok); return; } brainSet->writeFociFile(fileName, leftBms, rightBms, cerebellumBms, fileFormat, metadataCommentTextEdit->toPlainText()); } } else if (filterName == FileFilters::getFociColorFileFilter()) { FociColorFile* fcf = brainSet->getFociColorFile(); updateMetadataAndName(fcf, fileName, SpecFile::getFociColorFileExtension()); brainSet->writeFociColorFile(fileName); } else if (filterName == FileFilters::getFociProjectionFileFilter()) { FociProjectionFile* fpf = brainSet->getFociProjectionFile(); updateMetadataAndName(fpf, fileName, SpecFile::getFociProjectionFileExtension()); brainSet->writeFociProjectionFile(fileName); } else if (filterName == FileFilters::getFociSearchFileFilter()) { FociSearchFile* fsf = brainSet->getFociSearchFile(); updateMetadataAndName(fsf, fileName, SpecFile::getFociSearchFileExtension()); brainSet->writeFociSearchFile(fileName); } else if (filterName == FileFilters::getGeodesicDistanceFileFilter()) { GeodesicDistanceFile* gdf = brainSet->getGeodesicDistanceFile(); updateMetadataAndName(gdf, fileName, SpecFile::getGeodesicDistanceFileExtension()); brainSet->writeGeodesicDistanceFile(fileName); } else if (filterName == FileFilters::getGiftiCoordinateFileFilter()) { BrainModelSurface* bms = coordinateSurfaceSelectionComboBox->getSelectedBrainModelSurface(); if (bms == NULL) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", "No surface selected.", QMessageBox::Ok); return; } bms->setStructure(coordinateStructureComboBox->getSelectedStructure()); CoordinateFile* cf = bms->getCoordinateFile(); cf->setHeaderTag(AbstractFile::headerTagConfigurationID, coordinateStereotaxicSpaceComboBox->currentText()); updateMetadataAndName(cf, fileName, SpecFile::getGiftiCoordinateFileExtension()); brainSet->writeCoordinateFile(fileName, coordinateTypeComboBox->getSurfaceType(), cf); GuiFilesModified fm; fm.setCoordinateModified(); theMainWindow->fileModificationUpdate(fm); } else if (filterName == FileFilters::getGiftiFunctionalFileFilter()) { MetricFile* mf = brainSet->getMetricFile(); updateMetadataAndName(mf, fileName, SpecFile::getGiftiFunctionalFileExtension()); mf->setFileWriteType(fileFormat); brainSet->writeMetricFile(fileName); } else if (filterName == FileFilters::getGiftiLabelFileFilter()) { PaintFile* pf = brainSet->getPaintFile(); updateMetadataAndName(pf, fileName, SpecFile::getGiftiLabelFileExtension()); pf->assignColors(*brainSet->getAreaColorFile()); pf->setFileWriteType(fileFormat); brainSet->writePaintFile(fileName); } else if (filterName == FileFilters::getGiftiShapeFileFilter()) { SurfaceShapeFile* ssf = brainSet->getSurfaceShapeFile(); updateMetadataAndName(ssf, fileName, SpecFile::getGiftiShapeFileExtension()); ssf->setFileWriteType(fileFormat); brainSet->writeSurfaceShapeFile(fileName); } else if (filterName == FileFilters::getGiftiSurfaceFileFilter()) { BrainModelSurface* bms = giftiSurfaceSelectionControl->getSelectedBrainModelSurface(); if (bms != NULL) { updateMetadataAndName(bms->getCoordinateFile(), fileName, ""); updateFileNamesFileExtension(fileName, SpecFile::getGiftiSurfaceFileExtension()); brainSet->writeSurfaceFile(fileName, bms->getSurfaceType(), bms, true, fileFormat); } } else if (filterName == FileFilters::getGiftiTopologyFileFilter()) { TopologyFile* tf = topologySelectionComboBox->getSelectedTopologyFile(); if (tf != NULL) { updateMetadataAndName(tf, fileName, SpecFile::getGiftiTopologyFileExtension()); brainSet->writeTopologyFile(fileName, topologyTypeComboBox->getTopologyType(), tf); } } else if (filterName == FileFilters::getImageSaveFileFilter()) { const int indx = imageSelectionComboBox->currentIndex(); if ((indx >= 0) && (indx < brainSet->getNumberOfImageFiles())) { ImageFile* img = brainSet->getImageFile(indx); updateMetadataAndName(img, fileName, ""); brainSet->writeImageFile(fileName, img); } } else if (filterName == FileFilters::getLatitudeLongitudeFileFilter()) { LatLonFile* llf = brainSet->getLatLonFile(); updateMetadataAndName(llf, fileName, SpecFile::getLatLonFileExtension()); brainSet->writeLatLonFile(fileName); } else if (filterName == FileFilters::getMetricFileFilter()) { MetricFile* mf = brainSet->getMetricFile(); updateMetadataAndName(mf, fileName, SpecFile::getMetricFileExtension()); brainSet->writeMetricFile(fileName); } else if (filterName == FileFilters::getPaintFileFilter()) { PaintFile* pf = brainSet->getPaintFile(); updateMetadataAndName(pf, fileName, SpecFile::getPaintFileExtension()); brainSet->writePaintFile(fileName); } else if (filterName == FileFilters::getPaletteFileFilter()) { PaletteFile* pf = brainSet->getPaletteFile(); updateMetadataAndName(pf, fileName, SpecFile::getPaletteFileExtension()); brainSet->writePaletteFile(fileName); } else if (filterName == FileFilters::getParamsFileFilter()) { ParamsFile* pf = brainSet->getParamsFile(); updateMetadataAndName(pf, fileName, SpecFile::getParamsFileExtension()); brainSet->writeParamsFile(fileName); } else if (filterName == FileFilters::getProbAtlasFileFilter()) { ProbabilisticAtlasFile* paf = brainSet->getProbabilisticAtlasSurfaceFile(); updateMetadataAndName(paf, fileName, SpecFile::getProbabilisticAtlasFileExtension()); brainSet->writeProbabilisticAtlasFile(fileName); } else if (filterName == FileFilters::getRgbPaintFileFilter()) { RgbPaintFile* rpf = brainSet->getRgbPaintFile(); updateMetadataAndName(rpf, fileName, SpecFile::getRgbPaintFileExtension()); brainSet->writeRgbPaintFile(fileName); } else if (filterName == FileFilters::getSceneFileFilter()) { SceneFile* sf = brainSet->getSceneFile(); updateMetadataAndName(sf, fileName, SpecFile::getSceneFileExtension()); brainSet->writeSceneFile(fileName); } else if (filterName == FileFilters::getSectionFileFilter()) { SectionFile* sf = brainSet->getSectionFile(); updateMetadataAndName(sf, fileName, SpecFile::getSectionFileExtension()); brainSet->writeSectionFile(fileName); } else if (filterName == FileFilters::getStudyCollectionFileFilter()) { StudyCollectionFile* scf = brainSet->getStudyCollectionFile(); updateMetadataAndName(scf, fileName, SpecFile::getStudyCollectionFileExtension()); brainSet->writeStudyCollectionFile(fileName); } else if (filterName == FileFilters::getStudyMetaDataFileFilter()) { StudyMetaDataFile* smdf = brainSet->getStudyMetaDataFile(); const int count = smdf->getNumberOfStudyMetaDatWithoutProvenceEntries(); if (count > 0) { QApplication::restoreOverrideCursor(); const QString msg("There are " + QString::number(count) + " studies lacking provenance entries.\n" "Please enter the provenance data below.\n"); // "If you press \"Cancel\" the file will NOT be saved."); StudyMetaData::Provenance p; std::vector rowLabels, rowValues; rowLabels.push_back("Name"); rowValues.push_back(p.getName()); rowLabels.push_back("Date"); rowValues.push_back(p.getDate()); rowLabels.push_back("Comment"); rowValues.push_back(p.getComment()); QtMultipleInputDialog mid(this, "Add Provenance", msg, rowLabels, rowValues, false, true); if (mid.exec() == QtMultipleInputDialog::Accepted) { std::vector values; mid.getValues(values); smdf->addProvenanceToStudiesWithoutProvenanceEntries(values[0], values[1], values[2]); GuiFilesModified fm; fm.setStudyMetaDataModified(); theMainWindow->fileModificationUpdate(fm); } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); } updateMetadataAndName(smdf, fileName, SpecFile::getStudyMetaDataFileExtension()); brainSet->writeStudyMetaDataFile(fileName); } else if (filterName == FileFilters::getSurfaceShapeFileFilter()) { SurfaceShapeFile* ssf = brainSet->getSurfaceShapeFile(); updateMetadataAndName(ssf, fileName, SpecFile::getSurfaceShapeFileExtension()); brainSet->writeSurfaceShapeFile(fileName); } else if (filterName == FileFilters::getGiftiVectorFileFilter()) { VectorFile* vf = vectorFileSelectionComboBox->getSelectedVectorFile(); if (vf != NULL) { updateMetadataAndName(vf, fileName, SpecFile::getGiftiVectorFileExtension()); brainSet->writeVectorFile(vf, fileName); } } else if (filterName == FileFilters::getTopographyFileFilter()) { TopographyFile* tf = brainSet->getTopographyFile(); updateMetadataAndName(tf, fileName, SpecFile::getTopographyFileExtension()); brainSet->writeTopographyFile(fileName); } else if (filterName == FileFilters::getTopologyGenericFileFilter()) { TopologyFile* tf = topologySelectionComboBox->getSelectedTopologyFile(); if (tf != NULL) { updateMetadataAndName(tf, fileName, SpecFile::getTopoFileExtension()); brainSet->writeTopologyFile(fileName, topologyTypeComboBox->getTopologyType(), tf); } } else if (filterName == FileFilters::getTransformationMatrixFileFilter()) { TransformationMatrixFile* tmf = brainSet->getTransformationMatrixFile(); updateMetadataAndName(tmf, fileName, SpecFile::getTransformationMatrixFileExtension()); brainSet->writeTransformationMatrixFile(fileName); } else if (filterName == FileFilters::getVocabularyFileFilter()) { VocabularyFile* vf = brainSet->getVocabularyFile(); updateMetadataAndName(vf, fileName, SpecFile::getVocabularyFileExtension()); brainSet->writeVocabularyFile(fileName); } else if (filterName == FileFilters::getVolumeAnatomyFileFilter()) { VolumeFile::VOXEL_DATA_TYPE voxelDataType = volumeAnatomyVolumeDataTypeComboBox->getVolumeVoxelDataType(); if (volumeAnatomyFileSelectionComboBox->getAllVolumesSelected()) { std::vector volumes; for (int i = 0; i < brainSet->getNumberOfVolumeAnatomyFiles(); i++) { volumes.push_back(brainSet->getVolumeAnatomyFile(i)); } if (volumes.empty() == false) { brainSet->writeMultiVolumeFile(fileName, VolumeFile::VOLUME_TYPE_ANATOMY, metadataCommentTextEdit->toPlainText(), volumes, voxelDataType, volumeAnatomyWriteCompressedCheckBox->isChecked()); GuiFilesModified fm; fm.setVolumeModified(); theMainWindow->fileModificationUpdate(fm); } } else { VolumeFile* vf = volumeAnatomyFileSelectionComboBox->getSelectedVolumeFile(); if (vf != NULL) { vf->setDescriptiveLabel(volumeAnatomyLabelLineEdit->text()); updateMetadataAndName(vf, fileName, ""); brainSet->writeVolumeFile(fileName, VolumeFile::FILE_READ_WRITE_TYPE_UNKNOWN, VolumeFile::VOLUME_TYPE_ANATOMY, vf, voxelDataType, volumeAnatomyWriteCompressedCheckBox->isChecked()); GuiFilesModified fm; fm.setVolumeModified(); theMainWindow->fileModificationUpdate(fm); } } } else if (filterName == FileFilters::getVolumeFunctionalFileFilter()) { VolumeFile::VOXEL_DATA_TYPE voxelDataType = volumeFunctionalVolumeDataTypeComboBox->getVolumeVoxelDataType(); if (volumeFunctionalFileSelectionComboBox->getAllVolumesSelected()) { std::vector volumes; for (int i = 0; i < brainSet->getNumberOfVolumeFunctionalFiles(); i++) { volumes.push_back(brainSet->getVolumeFunctionalFile(i)); } if (volumes.empty() == false) { brainSet->writeMultiVolumeFile(fileName, VolumeFile::VOLUME_TYPE_FUNCTIONAL, metadataCommentTextEdit->toPlainText(), volumes, voxelDataType, volumeFunctionalWriteCompressedCheckBox->isChecked()); GuiFilesModified fm; fm.setVolumeModified(); theMainWindow->fileModificationUpdate(fm); } } else { VolumeFile* vf = volumeFunctionalFileSelectionComboBox->getSelectedVolumeFile(); if (vf != NULL) { vf->setDescriptiveLabel(volumeFunctionalLabelLineEdit->text()); updateMetadataAndName(vf, fileName, ""); brainSet->writeVolumeFile(fileName, VolumeFile::FILE_READ_WRITE_TYPE_UNKNOWN, VolumeFile::VOLUME_TYPE_FUNCTIONAL, vf, voxelDataType, volumeFunctionalWriteCompressedCheckBox->isChecked()); GuiFilesModified fm; fm.setVolumeModified(); theMainWindow->fileModificationUpdate(fm); } } } else if (filterName == FileFilters::getVolumePaintFileFilter()) { VolumeFile::VOXEL_DATA_TYPE voxelDataType = volumePaintVolumeDataTypeComboBox->getVolumeVoxelDataType(); if (volumePaintFileSelectionComboBox->getAllVolumesSelected()) { std::vector volumes; for (int i = 0; i < brainSet->getNumberOfVolumePaintFiles(); i++) { volumes.push_back(brainSet->getVolumePaintFile(i)); } if (volumes.empty() == false) { brainSet->writeMultiVolumeFile(fileName, VolumeFile::VOLUME_TYPE_PAINT, metadataCommentTextEdit->toPlainText(), volumes, voxelDataType, volumePaintWriteCompressedCheckBox->isChecked()); GuiFilesModified fm; fm.setVolumeModified(); theMainWindow->fileModificationUpdate(fm); } } else { VolumeFile* vf = volumePaintFileSelectionComboBox->getSelectedVolumeFile(); if (vf != NULL) { vf->setDescriptiveLabel(volumePaintLabelLineEdit->text()); updateMetadataAndName(vf, fileName, ""); brainSet->writeVolumeFile(fileName, VolumeFile::FILE_READ_WRITE_TYPE_UNKNOWN, VolumeFile::VOLUME_TYPE_PAINT, vf, voxelDataType, volumePaintWriteCompressedCheckBox->isChecked()); GuiFilesModified fm; fm.setVolumeModified(); theMainWindow->fileModificationUpdate(fm); } } } else if (filterName == FileFilters::getVolumeProbAtlasFileFilter()) { VolumeFile::VOXEL_DATA_TYPE voxelDataType = volumeProbAtlasVolumeDataTypeComboBox->getVolumeVoxelDataType(); if (volumeProbAtlasFileSelectionComboBox->getAllVolumesSelected() || alwaysSaveAllProbAtlasVolumes) { std::vector volumes; for (int i = 0; i < brainSet->getNumberOfVolumeProbAtlasFiles(); i++) { volumes.push_back(brainSet->getVolumeProbAtlasFile(i)); } if (volumes.empty() == false) { brainSet->writeMultiVolumeFile(fileName, VolumeFile::VOLUME_TYPE_PROB_ATLAS, metadataCommentTextEdit->toPlainText(), volumes, voxelDataType, volumeProbAtlasWriteCompressedCheckBox->isChecked()); GuiFilesModified fm; fm.setVolumeModified(); theMainWindow->fileModificationUpdate(fm); } } else { VolumeFile* vf = volumeProbAtlasFileSelectionComboBox->getSelectedVolumeFile(); if (vf != NULL) { vf->setDescriptiveLabel(volumeProbAtlasLabelLineEdit->text()); updateMetadataAndName(vf, fileName, ""); brainSet->writeVolumeFile(fileName, VolumeFile::FILE_READ_WRITE_TYPE_UNKNOWN, VolumeFile::VOLUME_TYPE_PROB_ATLAS, vf, voxelDataType, volumeProbAtlasWriteCompressedCheckBox->isChecked()); GuiFilesModified fm; fm.setVolumeModified(); theMainWindow->fileModificationUpdate(fm); } } } else if (filterName == FileFilters::getVolumeRgbFileFilter()) { VolumeFile::VOXEL_DATA_TYPE voxelDataType = volumeRgbVolumeDataTypeComboBox->getVolumeVoxelDataType(); if (volumeRgbFileSelectionComboBox->getAllVolumesSelected()) { std::vector volumes; for (int i = 0; i < brainSet->getNumberOfVolumeRgbFiles(); i++) { volumes.push_back(brainSet->getVolumeRgbFile(i)); } if (volumes.empty() == false) { brainSet->writeMultiVolumeFile(fileName, VolumeFile::VOLUME_TYPE_RGB, metadataCommentTextEdit->toPlainText(), volumes, voxelDataType, volumeRgbWriteCompressedCheckBox->isChecked()); GuiFilesModified fm; fm.setVolumeModified(); theMainWindow->fileModificationUpdate(fm); } } else { VolumeFile* vf = volumeRgbFileSelectionComboBox->getSelectedVolumeFile(); if (vf != NULL) { vf->setDescriptiveLabel(volumeRgbLabelLineEdit->text()); updateMetadataAndName(vf, fileName, ""); brainSet->writeVolumeFile(fileName, VolumeFile::FILE_READ_WRITE_TYPE_UNKNOWN, VolumeFile::VOLUME_TYPE_RGB, vf, voxelDataType, volumeRgbWriteCompressedCheckBox->isChecked()); GuiFilesModified fm; fm.setVolumeModified(); theMainWindow->fileModificationUpdate(fm); } } } else if (filterName == FileFilters::getVolumeSegmentationFileFilter()) { VolumeFile::VOXEL_DATA_TYPE voxelDataType = volumeSegmentationVolumeDataTypeComboBox->getVolumeVoxelDataType(); if (volumeSegmentationFileSelectionComboBox->getAllVolumesSelected()) { std::vector volumes; for (int i = 0; i < brainSet->getNumberOfVolumeSegmentationFiles(); i++) { volumes.push_back(brainSet->getVolumeSegmentationFile(i)); } if (volumes.empty() == false) { brainSet->writeMultiVolumeFile(fileName, VolumeFile::VOLUME_TYPE_SEGMENTATION, metadataCommentTextEdit->toPlainText(), volumes, voxelDataType, volumeSegmentationWriteCompressedCheckBox->isChecked()); GuiFilesModified fm; fm.setVolumeModified(); theMainWindow->fileModificationUpdate(fm); } } else { VolumeFile* vf = volumeSegmentationFileSelectionComboBox->getSelectedVolumeFile(); if (vf != NULL) { vf->setDescriptiveLabel(volumeSegmentationLabelLineEdit->text()); updateMetadataAndName(vf, fileName, ""); brainSet->writeVolumeFile(fileName, VolumeFile::FILE_READ_WRITE_TYPE_UNKNOWN, VolumeFile::VOLUME_TYPE_SEGMENTATION, vf, voxelDataType, volumeSegmentationWriteCompressedCheckBox->isChecked()); GuiFilesModified fm; fm.setVolumeModified(); theMainWindow->fileModificationUpdate(fm); } } } else if (filterName == FileFilters::getVolumeVectorFileFilter()) { VolumeFile::VOXEL_DATA_TYPE voxelDataType = volumeVectorVolumeDataTypeComboBox->getVolumeVoxelDataType(); if (volumeVectorFileSelectionComboBox->getAllVolumesSelected()) { std::vector volumes; for (int i = 0; i < brainSet->getNumberOfVolumeVectorFiles(); i++) { volumes.push_back(brainSet->getVolumeVectorFile(i)); } if (volumes.empty() == false) { brainSet->writeMultiVolumeFile(fileName, VolumeFile::VOLUME_TYPE_VECTOR, metadataCommentTextEdit->toPlainText(), volumes, voxelDataType, volumeVectorWriteCompressedCheckBox->isChecked()); GuiFilesModified fm; fm.setVolumeModified(); theMainWindow->fileModificationUpdate(fm); } } else { VolumeFile* vf = volumeVectorFileSelectionComboBox->getSelectedVolumeFile(); if (vf != NULL) { vf->setDescriptiveLabel(volumeVectorLabelLineEdit->text()); updateMetadataAndName(vf, fileName, ""); brainSet->writeVolumeFile(fileName, VolumeFile::FILE_READ_WRITE_TYPE_UNKNOWN, VolumeFile::VOLUME_TYPE_VECTOR, vf, voxelDataType, volumeVectorWriteCompressedCheckBox->isChecked()); GuiFilesModified fm; fm.setVolumeModified(); theMainWindow->fileModificationUpdate(fm); } } } else if (filterName == FileFilters::getVtkModelFileFilter()) { const int indx = vtkModelSelectionComboBox->currentIndex(); if ((indx >= 0) && (indx < brainSet->getNumberOfVtkModelFiles())) { VtkModelFile* vmf = brainSet->getVtkModelFile(indx); updateMetadataAndName(vmf, fileName, SpecFile::getVtkModelFileExtension()); brainSet->writeVtkModelFile(fileName, vmf); } } else if (filterName == FileFilters::getWustlRegionFileFilter()) { WustlRegionFile* wrf = brainSet->getWustlRegionFile(); updateMetadataAndName(wrf, fileName, SpecFile::getWustlRegionFileExtension()); brainSet->writeWustlRegionFile(fileName); } else if (filterName == FileFilters::getAnalyzeVolumeFileFilter()) { VolumeFile* vf = exportVolumeSelectionControl->getSelectedVolumeFile(); if (vf == NULL) { QApplication::restoreOverrideCursor(); throw FileException("No Volume File is selected."); } updateFileNamesFileExtension(fileName, SpecFile::getAnalyzeVolumeFileExtension()); brainSet->exportAnalyzeVolumeFile(vf, fileName); } else if (filterName == FileFilters::getByuSurfaceFileFilter()) { BrainModelSurface* bms = exportSurfaceSelectionControl->getSelectedBrainModelSurface(); if (bms == NULL) { QApplication::restoreOverrideCursor(); throw FileException("No Surface is selected."); } updateFileNamesFileExtension(fileName, ".byu"); brainSet->exportByuSurfaceFile(bms, fileName); } else if (filterName == FileFilters::getFreeSurferAsciiSurfaceFileFilter()) { BrainModelSurface* bms = exportSurfaceSelectionControl->getSelectedBrainModelSurface(); if (bms == NULL) { QApplication::restoreOverrideCursor(); throw FileException("No Surface is selected."); } updateFileNamesFileExtension(fileName, ".asc"); brainSet->exportFreeSurferAsciiSurfaceFile(bms, fileName); } else if (filterName == FileFilters::getFreeSurferAsciiCurvatureFileFilter()) { BrainModelSurface* bms = exportShapeSurfaceSelectionControl->getSelectedBrainModelSurface(); if (bms == NULL) { throw FileException("No Surface is selected."); } updateFileNamesFileExtension(fileName, SpecFile::getFreeSurferAsciiCurvatureFileExtension()); SurfaceShapeFile* ssf = brainSet->getSurfaceShapeFile(); const int column = exportShapeColumnSelectionControl->currentIndex(); if ((column >= 0) && (column < ssf->getNumberOfColumns())) { ssf->exportFreeSurferAsciiCurvatureFile(column, bms->getCoordinateFile(), fileName); } else { throw FileException("No Shape column is selected."); } } else if (filterName == FileFilters::getFreeSurferAsciiFunctionalFileFilter()) { BrainModelSurface* bms = exportMetricSurfaceSelectionControl->getSelectedBrainModelSurface(); if (bms == NULL) { throw FileException("No Surface is selected."); } updateFileNamesFileExtension(fileName, SpecFile::getFreeSurferAsciiFunctionalFileExtension()); MetricFile* mf = brainSet->getMetricFile(); const int column = exportMetricColumnSelectionControl->currentIndex(); if ((column >= 0) && (column < mf->getNumberOfColumns())) { mf->exportFreeSurferAsciiFunctionalFile(column, fileName); } else { throw FileException("No Metric column is selected."); } } else if (filterName == FileFilters::getFreeSurferAsciiLabelFileFilter()) { BrainModelSurface* bms = exportPaintSurfaceSelectionControl->getSelectedBrainModelSurface(); if (bms == NULL) { throw FileException("No Surface is selected."); } QFileInfo fi(fileName); const QString prefixName(fi.absolutePath()); PaintFile* pf = brainSet->getPaintFile(); const int column = exportPaintColumnSelectionControl->currentIndex(); if ((column >= 0) && (column < pf->getNumberOfColumns())) { pf->exportFreeSurferAsciiLabelFile(column, prefixName, bms->getCoordinateFile()); } else { throw FileException("No Paint column is selected."); } } else if (filterName == FileFilters::getMincVolumeFileFilter()) { VolumeFile* vf = exportVolumeSelectionControl->getSelectedVolumeFile(); if (vf == NULL) { throw FileException("No Volume File is selected."); } updateFileNamesFileExtension(fileName, SpecFile::getMincVolumeFileExtension()); brainSet->exportMincVolumeFile(vf, fileName); } else if (filterName == FileFilters::getOpenInventorSurfaceFileFilter()) { BrainModelSurface* bms = exportSurfaceSelectionControl->getSelectedBrainModelSurface(); if (bms == NULL) { throw FileException("No Surface is selected."); } updateFileNamesFileExtension(fileName, ".iv"); brainSet->exportInventorSurfaceFile(bms, fileName); } else if (filterName == FileFilters::getStlSurfaceFileFilter()) { BrainModelSurface* bms = exportSurfaceSelectionControl->getSelectedBrainModelSurface(); if (bms == NULL) { throw FileException("No Surface is selected."); } updateFileNamesFileExtension(fileName, ".stl"); brainSet->exportStlSurfaceFile(bms, fileName); } else if (filterName == FileFilters::getVrmlSurfaceFileFilter()) { BrainModelSurface* bms = exportSurfaceSelectionControl->getSelectedBrainModelSurface(); if (bms == NULL) { throw FileException("No Surface is selected."); } updateFileNamesFileExtension(fileName, ".wrl"); brainSet->exportVrmlSurfaceFile(bms, fileName); } else if (filterName == FileFilters::getVtkSurfaceFileFilter()) { BrainModelSurface* bms = exportSurfaceSelectionControl->getSelectedBrainModelSurface(); if (bms == NULL) { throw FileException("No Surface is selected."); } updateFileNamesFileExtension(fileName, ".vtk"); brainSet->exportVtkSurfaceFile(bms, fileName, true); } else if (filterName == FileFilters::getVtkXmlSurfaceFileFilter()) { BrainModelSurface* bms = exportSurfaceSelectionControl->getSelectedBrainModelSurface(); if (bms == NULL) { throw FileException("No Surface is selected."); } updateFileNamesFileExtension(fileName, ".vtkp"); brainSet->exportVtkXmlSurfaceFile(bms, fileName, true); } else if (filterName == FileFilters::getVtkVolumeFileFilter()) { VolumeFile* vf = exportVolumeSelectionControl->getSelectedVolumeFile(); if (vf == NULL) { throw FileException("No Volume File is selected."); } updateFileNamesFileExtension(fileName, ".vtk"); brainSet->exportVtkStructuredPointsVolumeFile(vf, fileName); } else { const QString msg(QString("PROGRAM ERROR: unhandled file type ") + filterName.toAscii().constData() + QString(" at ") + QString(__LINE__) + QString(" in ") + QString(__FILE__)); throw FileException(msg); } PreferencesFile* pf = theMainWindow->getBrainSet()->getPreferencesFile(); pf->addToRecentDataFileDirectories(FileUtilities::dirname(fileName), true); QApplication::restoreOverrideCursor(); } catch (FileException& e) { QApplication::restoreOverrideCursor(); QApplication::beep(); QMessageBox::critical(this, "SAVE ERROR", e.whatQString(), QMessageBox::Ok); return; } } WuQDialog::done(r); } caret-5.6.4~dfsg.1.orig/caret/GuiDataFileOpenDialog.h0000664000175000017500000000604011572067322022110 0ustar michaelmichael#ifndef __GUI_DATA_FILE_OPEN_DIALOG_H__ #define __GUI_DATA_FILE_OPEN_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "WuQFileDialog.h" class QCheckBox; class QPushButton; /// dialog for opening Caret data files. class GuiDataFileOpenDialog : public WuQFileDialog { Q_OBJECT public: // constructor GuiDataFileOpenDialog(QWidget* parent = 0, Qt::WindowFlags flags = 0); // destructor ~GuiDataFileOpenDialog(); /// static method to open a data file and make necessary updates as a result. /// returns true if an error occurred. static bool openDataFile(QWidget* parentWidget, const QString specFileTag, const QString& name, const bool append, const bool updateSpecFile, QString& errorMessage, bool& relatedFileWarningFlag); protected slots: // called when view/edit comment button pressed void slotViewEditCommentPushButton(); // called when the file selection is changed void slotFilesSelected(const QStringList&); protected: // called when dialog is closed void done(int r); // returns file filters that match the name virtual QStringList matchingFilters(const QString& name); // copy a file to the current directory, returns true if successful bool copyFile(const QString& name); // process import files (returns true if filter matched an import file) bool importFile(const QString& fileName, const QString& filterName); // read the file void readFile(const QString& fileName, const QString& filterName, const bool addToSpecFileFlag, const bool appendToCurrentFileFlag); /// add to specification file check box QCheckBox* addToSpecFileCheckBox; /// append to current data flag QCheckBox* appendToCurrentFileCheckBox; /// view edit comment push button QPushButton* viewEditCommentPushButton; }; #endif // __GUI_DATA_FILE_OPEN_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiDataFileOpenDialog.cxx0000664000175000017500000032146711572067322022500 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include "AreaColorFile.h" #include "ArealEstimationFile.h" #include "BorderColorFile.h" #include "BorderFile.h" #include "BrainModelContours.h" #include "BrainModelSurfaceNodeColoring.h" #include "BrainSet.h" #include "CellColorFile.h" #include "ContourCellColorFile.h" #include "ContourCellFile.h" #include "CoordinateFile.h" #include "DisplaySettingsBorders.h" #include "FileFilters.h" #include "FileUtilities.h" #include "FociColorFile.h" #include "FociFile.h" #include "GeodesicDistanceFile.h" #include "GuiBrainModelOpenGL.h" #include "GuiDataFileCommentDialog.h" #include "GuiDataFileImportOptionsDialog.h" #include "GuiDataFileOpenDialog.h" #include "GuiFilesModified.h" #include "GuiLoadNodeAttributeFileColumnSelectionDialog.h" #include "GuiMainWindow.h" #include "GuiSpecFileCreationDialog.h" #include "LatLonFile.h" #include "MetricFile.h" #include "PaintFile.h" #include "QtRadioButtonSelectionDialog.h" #include "RgbPaintFile.h" #include "SpecFile.h" #include "SurfaceFile.h" #include "SurfaceShapeFile.h" #include "VectorFile.h" #include "TopologyFile.h" #include "VolumeFile.h" #include "global_variables.h" static const QString GENERIC_BORDER("GENERIC_BORDER"); static const QString GENERIC_COORDINATE("GENERIC_COORDINATE"); static const QString GENERIC_SURFACE("GENERIC_SURFACE"); static const QString GENERIC_TOPOLOGY("GENERIC_TOPOLOGY"); /** * constructor. */ GuiDataFileOpenDialog::GuiDataFileOpenDialog(QWidget* parent, Qt::WindowFlags flags) : WuQFileDialog(parent, flags) { setWindowTitle("Open Data File"); setAcceptMode(AcceptOpen); setFileMode(ExistingFiles); setDirectory(QDir::currentPath()); // // Caret files // QStringList filterNames; filterNames << FileFilters::getAnyFileFilter(); filterNames << FileFilters::getAreaColorFileFilter(); filterNames << FileFilters::getArealEstimationFileFilter(); filterNames << FileFilters::getBorderGenericFileFilter(); filterNames << FileFilters::getBorderVolumeFileFilter(); filterNames << FileFilters::getBorderColorFileFilter(); filterNames << FileFilters::getBorderProjectionFileFilter(); filterNames << FileFilters::getCellFileFilter(); filterNames << FileFilters::getCellColorFileFilter(); filterNames << FileFilters::getCellProjectionFileFilter(); filterNames << FileFilters::getCellVolumeFileFilter(); filterNames << FileFilters::getCocomacFileFilter(); filterNames << FileFilters::getContourFileFilter(); filterNames << FileFilters::getContourCellFileFilter(); filterNames << FileFilters::getContourCellColorFileFilter(); filterNames << FileFilters::getCoordinateGenericFileFilter(); filterNames << FileFilters::getCutsFileFilter(); filterNames << FileFilters::getDeformationFieldFileFilter(); filterNames << FileFilters::getDeformationMapFileFilter(); filterNames << FileFilters::getFociFileFilter(); filterNames << FileFilters::getFociColorFileFilter(); filterNames << FileFilters::getFociProjectionFileFilter(); filterNames << FileFilters::getFociSearchFileFilter(); filterNames << FileFilters::getGeodesicDistanceFileFilter(); if (GiftiDataArrayFile::getGiftiXMLEnabled()) { filterNames << FileFilters::getGiftiCoordinateFileFilter(); filterNames << FileFilters::getGiftiFunctionalFileFilter(); filterNames << FileFilters::getGiftiLabelFileFilter(); filterNames << FileFilters::getGiftiShapeFileFilter(); filterNames << FileFilters::getGiftiSurfaceFileFilter(); filterNames << FileFilters::getGiftiTimeSeriesFileFilter(); filterNames << FileFilters::getGiftiTopologyFileFilter(); filterNames << FileFilters::getGiftiVectorFileFilter(); } filterNames << FileFilters::getImageOpenFileFilter(); filterNames << FileFilters::getLatitudeLongitudeFileFilter(); filterNames << FileFilters::getMetricOrShapeAsMetricFileFilter(); filterNames << FileFilters::getPaintFileFilter(); filterNames << FileFilters::getPaletteFileFilter(); filterNames << FileFilters::getParamsFileFilter(); filterNames << FileFilters::getProbAtlasFileFilter(); filterNames << FileFilters::getRgbPaintFileFilter(); filterNames << FileFilters::getSceneFileFilter(); filterNames << FileFilters::getSectionFileFilter(); filterNames << FileFilters::getStudyCollectionFileFilter(); filterNames << FileFilters::getStudyMetaDataFileFilter(); filterNames << FileFilters::getSurfaceShapeOrMetricAsShapeFileFilter(); filterNames << FileFilters::getTopographyFileFilter(); filterNames << FileFilters::getTopologyGenericFileFilter(); filterNames << FileFilters::getTransformationMatrixFileFilter(); filterNames << FileFilters::getTransformationDataFileFilter(); filterNames << FileFilters::getVocabularyFileFilter(); filterNames << FileFilters::getVolumeAnatomyFileFilter(); filterNames << FileFilters::getVolumeFunctionalFileFilter(); filterNames << FileFilters::getVolumePaintFileFilter(); filterNames << FileFilters::getVolumeProbAtlasFileFilter(); filterNames << FileFilters::getVolumeRgbFileFilter(); filterNames << FileFilters::getVolumeSegmentationFileFilter(); filterNames << FileFilters::getVolumeVectorFileFilter(); filterNames << FileFilters::getVtkModelFileFilter(); filterNames << FileFilters::getWustlRegionFileFilter(); // // Import Files // filterNames << FileFilters::getAnalyzeVolumeFileFilter(); filterNames << FileFilters::getBrainVoyagerFileFilter(); filterNames << FileFilters::getByuSurfaceFileFilter(); filterNames << FileFilters::getFreeSurferAsciiSurfaceFileFilter(); filterNames << FileFilters::getFreeSurferBinarySurfaceFileFilter(); filterNames << FileFilters::getFreeSurferAsciiCurvatureFileFilter(); filterNames << FileFilters::getFreeSurferBinaryCurvatureFileFilter(); filterNames << FileFilters::getFreeSurferAsciiFunctionalFileFilter(); filterNames << FileFilters::getFreeSurferBinaryFunctionalFileFilter(); filterNames << FileFilters::getFreeSurferAsciiLabelFileFilter(); filterNames << FileFilters::getMdPlotFileFilter(); #ifdef HAVE_MINC filterNames << FileFilters::getMincVolumeFileFilter(); #endif // HAVE_MINC filterNames << FileFilters::getMniObjSurfaceFileFilter(); filterNames << FileFilters::getNeurolucidaFileFilter(); filterNames << FileFilters::getRawVolumeFileFilter(); filterNames << FileFilters::getStlSurfaceFileFilter(); filterNames << FileFilters::getSumaRgbFileFilter(); filterNames << FileFilters::getVtkSurfaceFileFilter(); filterNames << FileFilters::getVtkXmlSurfaceFileFilter(); filterNames << FileFilters::getVtkVolumeFileFilter(); // // Add the filters to the dialog // setFilters(filterNames); // // Connect signals // QObject::connect(this, SIGNAL(filesSelected(const QStringList&)), this, SLOT(slotFilesSelected(const QStringList&))); // // View/Edit comment button // viewEditCommentPushButton = new QPushButton("View/Edit Comment..."); viewEditCommentPushButton->setEnabled(false); QObject::connect(viewEditCommentPushButton, SIGNAL(clicked()), this, SLOT(slotViewEditCommentPushButton())); // // Add to spec file check box // addToSpecFileCheckBox = new QCheckBox("Add to Specification File"); addToSpecFileCheckBox->setChecked(true); // // Append to current file check box // appendToCurrentFileCheckBox = new QCheckBox("Append to Current File"); appendToCurrentFileCheckBox->setChecked(true); // // Group box for options // QGroupBox* optionsGroupBox = new QGroupBox("Open File Options"); QVBoxLayout* optionsLayout = new QVBoxLayout(optionsGroupBox); optionsLayout->addWidget(addToSpecFileCheckBox); optionsLayout->addWidget(appendToCurrentFileCheckBox); // // Add widgets to dialog // addWidgets(optionsGroupBox, optionsGroupBox, viewEditCommentPushButton); } /** * destructor. */ GuiDataFileOpenDialog::~GuiDataFileOpenDialog() { } /** * called when view/edit comment button pressed. */ void GuiDataFileOpenDialog::slotViewEditCommentPushButton() { const QStringList files = selectedFiles(); if (files.count() == 1) { const QString highlightedFileName = files.at(0); if (highlightedFileName.isEmpty() == false) { const QString filterName = selectedFilter(); // // See if a volume file that needs to be handles specially // bool volumeFileFlag = (filterName == FileFilters::getVolumeAnatomyFileFilter()) || (filterName == FileFilters::getVolumeFunctionalFileFilter()) || (filterName == FileFilters::getVolumePaintFileFilter()) || (filterName == FileFilters::getVolumeProbAtlasFileFilter()) || (filterName == FileFilters::getVolumeRgbFileFilter()) || (filterName == FileFilters::getVolumeSegmentationFileFilter()) || (filterName == FileFilters::getVolumeVectorFileFilter()); if (selectedFilter() == FileFilters::getAnyFileFilter()) { const QStringList mf = matchingFilters(highlightedFileName); for (int i = 0; i < mf.count(); i++) { if (mf.at(i) == FileFilters::getVolumeAnatomyFileFilter()) { volumeFileFlag = true; break; } } } GuiDataFileCommentDialog* dfcd = new GuiDataFileCommentDialog(this, highlightedFileName, volumeFileFlag); dfcd->show(); } } } /** * called when the file selection is changed. */ void GuiDataFileOpenDialog::slotFilesSelected(const QStringList& fileNames) { viewEditCommentPushButton->setEnabled(fileNames.count() == 1); if (fileNames.count() == 1) { const QStringList mf = matchingFilters(fileNames.at(0)); for (int i = 0; i < mf.count(); i++) { //std::cout << "Matching Filters: " << mf.at(i).toAscii().constData() << std::endl; } } } /** * returns file filters that match the name but exludes any file filter */ QStringList GuiDataFileOpenDialog::matchingFilters(const QString& name) { // // Try a list of all but ANY and filters that have no extension // QStringList filterList = WuQFileDialog::matchingFilters(name); filterList.removeAll(FileFilters::getAnyFileFilter()); filterList.removeAll(FileFilters::getFreeSurferBinarySurfaceFileFilter()); filterList.removeAll(FileFilters::getRawVolumeFileFilter()); if (filterList.count() == 0) { // // Get a list of all but ANY // filterList = WuQFileDialog::matchingFilters(name); filterList.removeAll(FileFilters::getAnyFileFilter()); } return filterList; } /** * called when dialog is closed. */ void GuiDataFileOpenDialog::done(int r) { if (r == QDialog::Accepted) { // // Create priority of files - read first: colors, study, topo // read later: all other files // const QStringList unsortedFiles(selectedFiles()); QStringList priorityLow, priorityHigh; for (int i = 0; i < unsortedFiles.count(); i++) { const QString fn(unsortedFiles.at(i)); if (fn.endsWith("color") || fn.endsWith(SpecFile::getStudyMetaDataFileExtension()) || fn.endsWith(SpecFile::getTopoFileExtension())) { priorityHigh << fn; } else { priorityLow << fn; } } const QStringList filesChosen(priorityHigh + priorityLow); // // Get the selected files // const int numFiles = filesChosen.count(); if (numFiles > 0) { // // Update previous directories // PreferencesFile* pf = theMainWindow->getBrainSet()->getPreferencesFile(); pf->addToRecentDataFileDirectories(FileUtilities::dirname(filesChosen.at(0)), true); // // Add to spec file status and append status // const bool addToSpecFlag = addToSpecFileCheckBox->isChecked(); const bool appendToCurrentFileFlag = appendToCurrentFileCheckBox->isChecked(); // // Allow user to set the spec file name if not already set // const QString specFileName(theMainWindow->getBrainSet()->getSpecFileName()); if (addToSpecFlag && specFileName.isEmpty()) { const int result = QMessageBox::question(this, "Spec File", "Would you like to create a Spec File ?", (QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel), QMessageBox::No); if (result == QMessageBox::Yes) { // // Create spec file dialog will set the directory and create the spec file // GuiSpecFileCreationDialog sfcd(this); sfcd.exec(); PreferencesFile* pf = theMainWindow->getBrainSet()->getPreferencesFile(); pf->addToRecentSpecFiles(sfcd.getCreatedSpecFileName(), true); } else if (result == QMessageBox::No) { } else if (result == QMessageBox::Cancel) { return; } } // // See if file(s) may need to be copied to current directory // bool copyFlag = false; if (addToSpecFlag && (specFileName.isEmpty() == false)) { // // Is data file in a directory different than that of spec file // QFileInfo dataFileInfo(filesChosen.at(0)); QFileInfo specFileInfo(specFileName); if (dataFileInfo.absolutePath() != specFileInfo.absolutePath()) { const int result = QMessageBox::question(this, "Copy File", "Would you like to copy the " "file(s) to the current directory.", (QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel), QMessageBox::No); if (result == QMessageBox::Yes) { copyFlag = true; } else if (result == QMessageBox::No) { } else if (result == QMessageBox::Cancel) { return; } } } // // Get the name of the file filter // const QString selectedFilterName(selectedFilter()); // // Loop through the selected files // for (int i = 0; i < numFiles; i++) { // // Get the file // QString fileName = filesChosen.at(i); const QString nameNoPath(FileUtilities::basename(fileName)); //std::cout << "Loading: " << fileName.toAscii().constData() << std::endl; // // Should file be copied? // if (copyFlag) { if (copyFile(fileName) == false) { return; } // // Remove path since file copied // fileName = FileUtilities::basename(fileName); } // // Get the file filter // QString filterName = selectedFilterName; // // If filter is any file filter, find matching filter // if (filterName == FileFilters::getAnyFileFilter()) { // // Get filter that match the file name // QStringList filtersThatMatch = matchingFilters(fileName); // // If only one filter, then use it, otherwise ask user // if (filtersThatMatch.count() == 1) { filterName = filtersThatMatch.at(0); } else if (filtersThatMatch.count() <= 0) { const QString msg(FileUtilities::basename(fileName) + " is not a supported Caret file type."); QMessageBox::critical(this, "ERROR", msg); return; } else { // // Ask user which file type to use // std::vector labels; for (int i = 0; i < filtersThatMatch.count(); i++) { QString name = filtersThatMatch.at(i); const int indx = name.indexOf('('); if (indx > 0) { name = name.left(indx); } labels.push_back(name); } QtRadioButtonSelectionDialog rbsd(this, "Choose File Type", "Type of File for " + nameNoPath, labels, 0); if (rbsd.exec() == QtRadioButtonSelectionDialog::Accepted) { filterName = filtersThatMatch.at(rbsd.getSelectedItemIndex()); } else { return; } } } // // Read the file // readFile(fileName, filterName, addToSpecFlag, appendToCurrentFileFlag); } } } WuQFileDialog::done(r); } /** * read the file. */ void GuiDataFileOpenDialog::readFile(const QString& fileName, const QString& filterName, const bool addToSpecFileFlag, const bool appendToCurrentFileFlag) { // // SPM Volume use Analyze file extension and sometimes // are left/right flipped // bool spmLeftOnRightFlag = false; const bool volumeFileFlag = (filterName == FileFilters::getVolumeAnatomyFileFilter()) || (filterName == FileFilters::getVolumeFunctionalFileFilter()) || (filterName == FileFilters::getVolumePaintFileFilter()) || (filterName == FileFilters::getVolumeProbAtlasFileFilter()) || (filterName == FileFilters::getVolumeRgbFileFilter()) || (filterName == FileFilters::getVolumeSegmentationFileFilter()) || (filterName == FileFilters::getVolumeVectorFileFilter()); if (volumeFileFlag) { if (fileName.endsWith(SpecFile::getAnalyzeVolumeFileExtension())) { const QString msg("If the volume being loaded an SPM volume that\n" "is left/right flipped (radiological orientation)?"); spmLeftOnRightFlag = (QMessageBox::question(this, "SPM Flipped", msg, (QMessageBox::Yes | QMessageBox::No)) == QMessageBox::Yes); } } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); theMainWindow->getBrainSet()->setDisplaySplashImage(false); QString msg; bool error = false; bool warning = false; if (filterName == FileFilters::getAreaColorFileFilter()) { error = openDataFile(this, SpecFile::getAreaColorFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getArealEstimationFileFilter()) { error = openDataFile(this, SpecFile::getArealEstimationFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getBorderRawFileFilter()) { error = openDataFile(this, SpecFile::getRawBorderFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getBorderFiducialFileFilter()) { error = openDataFile(this, SpecFile::getFiducialBorderFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getBorderInflatedFileFilter()) { error = openDataFile(this, SpecFile::getInflatedBorderFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getBorderVeryInflatedFileFilter()) { error = openDataFile(this, SpecFile::getVeryInflatedBorderFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getBorderSphericalFileFilter()) { error = openDataFile(this, SpecFile::getSphericalBorderFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getBorderEllipsoidalFileFilter()) { error = openDataFile(this, SpecFile::getEllipsoidBorderFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getBorderCompressedFileFilter()) { error = openDataFile(this, SpecFile::getCompressedBorderFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getBorderFlatFileFilter()) { error = openDataFile(this, SpecFile::getFlatBorderFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getBorderFlatLobarFileFilter()) { error = openDataFile(this, SpecFile::getLobarFlatBorderFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getBorderHullFileFilter()) { error = openDataFile(this, SpecFile::getHullBorderFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getBorderUnknownFileFilter()) { error = openDataFile(this, SpecFile::getUnknownBorderFileMatchTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getBorderVolumeFileFilter()) { error = openDataFile(this, SpecFile::getVolumeBorderFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getBorderGenericFileFilter()) { error = openDataFile(this, GENERIC_BORDER, fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getBorderColorFileFilter()) { error = openDataFile(this, SpecFile::getBorderColorFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getBorderProjectionFileFilter()) { error = openDataFile(this, SpecFile::getBorderProjectionFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getCellFileFilter()) { error = openDataFile(this, SpecFile::getCellFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getCellColorFileFilter()) { error = openDataFile(this, SpecFile::getCellColorFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getCellProjectionFileFilter()) { error = openDataFile(this, SpecFile::getCellProjectionFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getCellVolumeFileFilter()) { error = openDataFile(this, SpecFile::getVolumeCellFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getCocomacFileFilter()) { error = openDataFile(this, SpecFile::getCocomacConnectivityFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getContourFileFilter()) { error = openDataFile(this, SpecFile::getContourFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getContourCellFileFilter()) { error = openDataFile(this, SpecFile::getContourCellFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getContourCellColorFileFilter()) { error = openDataFile(this, SpecFile::getContourCellColorFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getCoordinateRawFileFilter()) { error = openDataFile(this, SpecFile::getRawCoordFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getCoordinateFiducialFileFilter()) { error = openDataFile(this, SpecFile::getFiducialCoordFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getCoordinateInflatedFileFilter()) { error = openDataFile(this, SpecFile::getInflatedCoordFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getCoordinateVeryInflatedFileFilter()) { error = openDataFile(this, SpecFile::getVeryInflatedCoordFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getCoordinateSphericalFileFilter()) { error = openDataFile(this, SpecFile::getSphericalCoordFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getCoordinateEllipsoidalFileFilter()) { error = openDataFile(this, SpecFile::getEllipsoidCoordFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getCoordinateCompressedFileFilter()) { error = openDataFile(this, SpecFile::getCompressedCoordFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getCoordinateFlatFileFilter()) { error = openDataFile(this, SpecFile::getFlatCoordFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getCoordinateFlatLobarFileFilter()) { error = openDataFile(this, SpecFile::getLobarFlatCoordFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getCoordinateHullFileFilter()) { error = openDataFile(this, SpecFile::getHullCoordFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getCoordinateUnknownFileFilter()) { error = openDataFile(this, SpecFile::getUnknownCoordFileMatchTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getCoordinateGenericFileFilter()) { error = openDataFile(this, GENERIC_COORDINATE, fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getCutsFileFilter()) { error = openDataFile(this, SpecFile::getCutsFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getDeformationFieldFileFilter()) { error = openDataFile(this, SpecFile::getDeformationFieldFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getDeformationMapFileFilter()) { error = openDataFile(this, SpecFile::getDeformationMapFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getFociFileFilter()) { error = openDataFile(this, SpecFile::getFociFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getFociColorFileFilter()) { error = openDataFile(this, SpecFile::getFociColorFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getFociProjectionFileFilter()) { error = openDataFile(this, SpecFile::getFociProjectionFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getFociSearchFileFilter()) { error = openDataFile(this, SpecFile::getFociSearchFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getGeodesicDistanceFileFilter()) { error = openDataFile(this, SpecFile::getGeodesicDistanceFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getGiftiCoordinateFileFilter()) { error = openDataFile(this, GENERIC_COORDINATE, fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if ((filterName == FileFilters::getGiftiFunctionalFileFilter()) || (filterName == FileFilters::getGiftiTimeSeriesFileFilter())) { error = openDataFile(this, SpecFile::getMetricFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getGiftiLabelFileFilter()) { error = openDataFile(this, SpecFile::getPaintFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getGiftiShapeFileFilter()) { error = openDataFile(this, SpecFile::getSurfaceShapeFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getGiftiSurfaceFileFilter()) { error = openDataFile(this, GENERIC_SURFACE, fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getGiftiTopologyFileFilter()) { error = openDataFile(this, GENERIC_TOPOLOGY, fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getGiftiVectorFileFilter()) { error = openDataFile(this, SpecFile::getVectorFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getImageOpenFileFilter()) { error = openDataFile(this, SpecFile::getImageFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getLatitudeLongitudeFileFilter()) { error = openDataFile(this, SpecFile::getLatLonFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if ((filterName == FileFilters::getMetricFileFilter()) || (filterName == FileFilters::getMetricOrShapeAsMetricFileFilter())) { error = openDataFile(this, SpecFile::getMetricFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getPaintFileFilter()) { error = openDataFile(this, SpecFile::getPaintFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getPaletteFileFilter()) { error = openDataFile(this, SpecFile::getPaletteFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getParamsFileFilter()) { error = openDataFile(this, SpecFile::getParamsFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getProbAtlasFileFilter()) { error = openDataFile(this, SpecFile::getAtlasFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getRgbPaintFileFilter()) { error = openDataFile(this, SpecFile::getRgbPaintFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getSceneFileFilter()) { error = openDataFile(this, SpecFile::getSceneFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getSectionFileFilter()) { error = openDataFile(this, SpecFile::getSectionFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if ((filterName == FileFilters::getSurfaceShapeFileFilter()) || (filterName == FileFilters::getSurfaceShapeOrMetricAsShapeFileFilter())) { error = openDataFile(this, SpecFile::getSurfaceShapeFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getTopographyFileFilter()) { error = openDataFile(this, SpecFile::getTopographyFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getTopologyClosedFileFilter()) { error = openDataFile(this, SpecFile::getClosedTopoFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getTopologyOpenFileFilter()) { error = openDataFile(this, SpecFile::getOpenTopoFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getTopologyCutFileFilter()) { error = openDataFile(this, SpecFile::getCutTopoFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getTopologyCutLobarFileFilter()) { error = openDataFile(this, SpecFile::getLobarCutTopoFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getTopologyUnknownFileFilter()) { error = openDataFile(this, SpecFile::getUnknownTopoFileMatchTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getTopologyGenericFileFilter()) { error = openDataFile(this, GENERIC_TOPOLOGY, fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getVolumeAnatomyFileFilter()) { error = openDataFile(this, SpecFile::getVolumeAnatomyFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); if (spmLeftOnRightFlag) { const int volumeIndex = theMainWindow->getBrainSet()->getNumberOfVolumeAnatomyFiles(); if (volumeIndex > 0) { VolumeFile* vf = theMainWindow->getBrainSet()->getVolumeAnatomyFile(volumeIndex - 1); vf->flip(VolumeFile::VOLUME_AXIS_X, false); vf->clearModified(); } } } else if (filterName == FileFilters::getVolumeFunctionalFileFilter()) { error = openDataFile(this, SpecFile::getVolumeFunctionalFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); if (spmLeftOnRightFlag) { const int volumeIndex = theMainWindow->getBrainSet()->getNumberOfVolumeFunctionalFiles(); if (volumeIndex > 0) { VolumeFile* vf = theMainWindow->getBrainSet()->getVolumeFunctionalFile(volumeIndex - 1); vf->flip(VolumeFile::VOLUME_AXIS_X, false); vf->clearModified(); } } } else if (filterName == FileFilters::getVolumePaintFileFilter()) { error = openDataFile(this, SpecFile::getVolumePaintFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); if (spmLeftOnRightFlag) { const int volumeIndex = theMainWindow->getBrainSet()->getNumberOfVolumePaintFiles(); if (volumeIndex > 0) { VolumeFile* vf = theMainWindow->getBrainSet()->getVolumePaintFile(volumeIndex - 1); vf->flip(VolumeFile::VOLUME_AXIS_X, false); vf->clearModified(); } } } else if (filterName == FileFilters::getVolumeProbAtlasFileFilter()) { error = openDataFile(this, SpecFile::getVolumeProbAtlasFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); if (spmLeftOnRightFlag) { const int volumeIndex = theMainWindow->getBrainSet()->getNumberOfVolumeProbAtlasFiles(); if (volumeIndex > 0) { VolumeFile* vf = theMainWindow->getBrainSet()->getVolumeProbAtlasFile(volumeIndex - 1); vf->flip(VolumeFile::VOLUME_AXIS_X, false); vf->clearModified(); } } } else if (filterName == FileFilters::getVolumeRgbFileFilter()) { error = openDataFile(this, SpecFile::getVolumeRgbFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); if (spmLeftOnRightFlag) { const int volumeIndex = theMainWindow->getBrainSet()->getNumberOfVolumeRgbFiles(); if (volumeIndex > 0) { VolumeFile* vf = theMainWindow->getBrainSet()->getVolumeRgbFile(volumeIndex - 1); vf->flip(VolumeFile::VOLUME_AXIS_X, false); vf->clearModified(); } } } else if (filterName == FileFilters::getVolumeSegmentationFileFilter()) { error = openDataFile(this, SpecFile::getVolumeSegmentationFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); if (spmLeftOnRightFlag) { const int volumeIndex = theMainWindow->getBrainSet()->getNumberOfVolumeSegmentationFiles(); if (volumeIndex > 0) { VolumeFile* vf = theMainWindow->getBrainSet()->getVolumeSegmentationFile(volumeIndex - 1); vf->flip(VolumeFile::VOLUME_AXIS_X, false); vf->clearModified(); } } } else if (filterName == FileFilters::getVolumeVectorFileFilter()) { error = openDataFile(this, SpecFile::getVolumeVectorFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); if (spmLeftOnRightFlag) { const int volumeIndex = theMainWindow->getBrainSet()->getNumberOfVolumeVectorFiles(); if (volumeIndex > 0) { VolumeFile* vf = theMainWindow->getBrainSet()->getVolumeVectorFile(volumeIndex - 1); vf->flip(VolumeFile::VOLUME_AXIS_X, false); vf->clearModified(); } } } else if (filterName == FileFilters::getStudyCollectionFileFilter()) { error = openDataFile(this, SpecFile::getStudyCollectionFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getStudyMetaDataFileFilter()) { error = openDataFile(this, SpecFile::getStudyMetaDataFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getTransformationMatrixFileFilter()) { error = openDataFile(this, SpecFile::getTransformationMatrixFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getTransformationDataFileFilter()) { error = openDataFile(this, SpecFile::getTransformationDataFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getVtkModelFileFilter()) { error = openDataFile(this, SpecFile::getVtkModelFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getVocabularyFileFilter()) { error = openDataFile(this, SpecFile::getVocabularyFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (filterName == FileFilters::getWustlRegionFileFilter()) { error = openDataFile(this, SpecFile::getWustlRegionFileTag(), fileName, appendToCurrentFileFlag, addToSpecFileFlag, msg, warning); } else if (importFile(fileName, filterName)) { // do nothing here } else { std::cerr << "PROGRAM ERROR: unhandled file type at " << __LINE__ << " in " << __FILE__ << std::endl; std::cerr << " File: " << fileName.toAscii().constData() << std::endl; std::cerr << " Filter: " << filterName.toAscii().constData() << std::endl; QApplication::restoreOverrideCursor(); return; } QApplication::restoreOverrideCursor(); if (error) { QMessageBox::critical(this, "Error Reading File", msg); return; } } /** * process import files (returns true if filter matched an import file). */ bool GuiDataFileOpenDialog::importFile(const QString& fileName, const QString& filterName) { GuiFilesModified fm; BrainSet* brainSet = theMainWindow->getBrainSet(); QApplication::restoreOverrideCursor(); try { if (filterName == FileFilters::getAnalyzeVolumeFileFilter()) { GuiDataFileImportOptionsDialog iod(this, filterName); if (iod.exec() == GuiDataFileImportOptionsDialog::Accepted) { VolumeFile::VOLUME_TYPE volumeType; int dimensions[3]; VolumeFile::VOXEL_DATA_TYPE voxelDataType; bool byteSwap; iod.getVolumeOptions(volumeType, dimensions, voxelDataType, byteSwap); QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); brainSet->importAnalyzeVolumeFile(fileName, volumeType); fm.setVolumeModified(); } } else if (filterName == FileFilters::getBrainVoyagerFileFilter()) { GuiDataFileImportOptionsDialog iod(this, filterName); if (iod.exec() == GuiDataFileImportOptionsDialog::Accepted) { Structure::STRUCTURE_TYPE structureType; bool importTopology; TopologyFile::TOPOLOGY_TYPES topologyType; bool importCoordinates; BrainModelSurface::SURFACE_TYPES coordinateType; bool importColorsAsPaint; bool importColorsAsRgbPaint; iod.getSurfaceOptions(structureType, importTopology, topologyType, importCoordinates, coordinateType, importColorsAsPaint, importColorsAsRgbPaint); if (brainSet->getStructure().getType() == Structure::STRUCTURE_TYPE_INVALID) { brainSet->setStructure(structureType); } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); brainSet->importBrainVoyagerFile(fileName, importCoordinates, importTopology, importColorsAsPaint, coordinateType, topologyType); fm.setCoordinateModified(); fm.setPaintModified(); fm.setAreaColorModified(); fm.setTopologyModified(); } } else if (filterName == FileFilters::getByuSurfaceFileFilter()) { GuiDataFileImportOptionsDialog iod(this, filterName); if (iod.exec() == GuiDataFileImportOptionsDialog::Accepted) { Structure::STRUCTURE_TYPE structureType; bool importTopology; TopologyFile::TOPOLOGY_TYPES topologyType; bool importCoordinates; BrainModelSurface::SURFACE_TYPES coordinateType; bool importColorsAsPaint; bool importColorsAsRgbPaint; iod.getSurfaceOptions(structureType, importTopology, topologyType, importCoordinates, coordinateType, importColorsAsPaint, importColorsAsRgbPaint); if (brainSet->getStructure().getType() == Structure::STRUCTURE_TYPE_INVALID) { brainSet->setStructure(structureType); } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); brainSet->importByuSurfaceFile(fileName, importCoordinates, importTopology, coordinateType, topologyType); fm.setCoordinateModified(); fm.setTopologyModified(); } } else if (filterName == FileFilters::getFreeSurferAsciiSurfaceFileFilter()) { GuiDataFileImportOptionsDialog iod(this, filterName); if (iod.exec() == GuiDataFileImportOptionsDialog::Accepted) { Structure::STRUCTURE_TYPE structureType; bool importTopology; TopologyFile::TOPOLOGY_TYPES topologyType; bool importCoordinates; BrainModelSurface::SURFACE_TYPES coordinateType; bool importColorsAsPaint; bool importColorsAsRgbPaint; iod.getSurfaceOptions(structureType, importTopology, topologyType, importCoordinates, coordinateType, importColorsAsPaint, importColorsAsRgbPaint); if (brainSet->getStructure().getType() == Structure::STRUCTURE_TYPE_INVALID) { brainSet->setStructure(structureType); } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); brainSet->importFreeSurferSurfaceFile(fileName, importCoordinates, importTopology, AbstractFile::FILE_FORMAT_ASCII, coordinateType, topologyType); fm.setCoordinateModified(); fm.setTopologyModified(); } } else if (filterName == FileFilters::getFreeSurferBinarySurfaceFileFilter()) { GuiDataFileImportOptionsDialog iod(this, filterName); if (iod.exec() == GuiDataFileImportOptionsDialog::Accepted) { Structure::STRUCTURE_TYPE structureType; bool importTopology; TopologyFile::TOPOLOGY_TYPES topologyType; bool importCoordinates; BrainModelSurface::SURFACE_TYPES coordinateType; bool importColorsAsPaint; bool importColorsAsRgbPaint; iod.getSurfaceOptions(structureType, importTopology, topologyType, importCoordinates, coordinateType, importColorsAsPaint, importColorsAsRgbPaint); if (brainSet->getStructure().getType() == Structure::STRUCTURE_TYPE_INVALID) { brainSet->setStructure(structureType); } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); brainSet->importFreeSurferSurfaceFile(fileName, importCoordinates, importTopology, AbstractFile::FILE_FORMAT_BINARY, coordinateType, topologyType); fm.setCoordinateModified(); fm.setTopologyModified(); } } else if (filterName == FileFilters::getFreeSurferAsciiCurvatureFileFilter()) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); SurfaceShapeFile* ssf = brainSet->getSurfaceShapeFile(); ssf->importFreeSurferCurvatureFile(brainSet->getNumberOfNodes(), fileName, AbstractFile::FILE_FORMAT_ASCII); fm.setSurfaceShapeModified(); } else if (filterName == FileFilters::getFreeSurferBinaryCurvatureFileFilter()) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); SurfaceShapeFile* ssf = brainSet->getSurfaceShapeFile(); ssf->importFreeSurferCurvatureFile(brainSet->getNumberOfNodes(), fileName, AbstractFile::FILE_FORMAT_BINARY); fm.setSurfaceShapeModified(); } else if (filterName == FileFilters::getFreeSurferAsciiFunctionalFileFilter()) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); MetricFile* mf = brainSet->getMetricFile(); mf->importFreeSurferFunctionalFile(brainSet->getNumberOfNodes(), fileName, AbstractFile::FILE_FORMAT_ASCII); fm.setMetricModified(); } else if (filterName == FileFilters::getFreeSurferBinaryFunctionalFileFilter()) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); MetricFile* mf = brainSet->getMetricFile(); mf->importFreeSurferFunctionalFile(brainSet->getNumberOfNodes(), fileName, AbstractFile::FILE_FORMAT_BINARY); fm.setMetricModified(); } else if (filterName == FileFilters::getFreeSurferAsciiLabelFileFilter()) { bool importAll = false; if (QMessageBox::question(this, "Import All", "Import all label files in directory ?", (QMessageBox::Yes | QMessageBox::No)) == QMessageBox::Yes) { importAll = true; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); PaintFile* pf = brainSet->getPaintFile(); pf->importFreeSurferAsciiLabelFile(brainSet->getNumberOfNodes(), fileName, brainSet->getAreaColorFile(), importAll); fm.setPaintModified(); fm.setAreaColorModified(); } else if (filterName == FileFilters::getMdPlotFileFilter()) { GuiDataFileImportOptionsDialog iod(this, filterName); if (iod.exec() == GuiDataFileImportOptionsDialog::Accepted) { bool importContourCells; bool importContours; iod.getContourOptions(importContours, importContourCells); const BrainModelContours* bmc = brainSet->getBrainModelContours(); bool appendContoursFlag = false; bool appendCellsFlag = false; if (importContours) { if (bmc != NULL) { const ContourFile* cf = bmc->getContourFile(); if (cf->empty() == false) { appendContoursFlag = (QMessageBox::question(this, "Import MD Plot", "Append to existing contours?", (QMessageBox::Yes | QMessageBox::No)) == QMessageBox::Yes); } } } if (importContourCells) { const ContourCellFile* cf = brainSet->getContourCellFile(); if (cf->empty() == false) { appendCellsFlag = (QMessageBox::question(this, "Import MD Plot", "Append to existing contour cells?", (QMessageBox::Yes | QMessageBox::No)) == QMessageBox::Yes); } } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); brainSet->importMDPlotFile(fileName, importContourCells, importContours, appendContoursFlag, appendCellsFlag); fm.setContourModified(); fm.setContourCellModified(); fm.setContourCellColorModified(); } } #ifdef HAVE_MINC else if (filterName == FileFilters::getMincVolumeFileFilter()) { GuiDataFileImportOptionsDialog iod(this, filterName); if (iod.exec() == GuiDataFileImportOptionsDialog::Accepted) { VolumeFile::VOLUME_TYPE volumeType; int dimensions[3]; VolumeFile::VOXEL_DATA_TYPE voxelDataType; bool byteSwap; iod.getVolumeOptions(volumeType, dimensions, voxelDataType, byteSwap); QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); brainSet->importMincVolumeFile(fileName, volumeType); fm.setVolumeModified(); } } #endif // HAVE_MINC else if (filterName == FileFilters::getMniObjSurfaceFileFilter()) { GuiDataFileImportOptionsDialog iod(this, filterName); if (iod.exec() == GuiDataFileImportOptionsDialog::Accepted) { Structure::STRUCTURE_TYPE structureType; bool importTopology; TopologyFile::TOPOLOGY_TYPES topologyType; bool importCoordinates; BrainModelSurface::SURFACE_TYPES coordinateType; bool importColorsAsPaint; bool importColorsAsRgbPaint; iod.getSurfaceOptions(structureType, importTopology, topologyType, importCoordinates, coordinateType, importColorsAsPaint, importColorsAsRgbPaint); if (brainSet->getStructure().getType() == Structure::STRUCTURE_TYPE_INVALID) { brainSet->setStructure(structureType); } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); brainSet->importMniObjSurfaceFile(fileName, importCoordinates, importTopology, importColorsAsRgbPaint, coordinateType, topologyType); fm.setCoordinateModified(); fm.setRgbPaintModified(); fm.setTopologyModified(); } } else if (filterName == FileFilters::getNeurolucidaFileFilter()) { GuiDataFileImportOptionsDialog iod(this, filterName); if (iod.exec() == GuiDataFileImportOptionsDialog::Accepted) { bool importContourCells; bool importContours; iod.getContourOptions(importContours, importContourCells); const BrainModelContours* bmc = brainSet->getBrainModelContours(); bool appendContoursFlag = false; bool appendCellsFlag = false; if (importContours) { if (bmc != NULL) { const ContourFile* cf = bmc->getContourFile(); if (cf->empty() == false) { appendContoursFlag = (QMessageBox::question(this, "Import Neurolucida", "Append to existing contours?", (QMessageBox::Yes | QMessageBox::No)) == QMessageBox::Yes); } } } if (importContourCells) { const ContourCellFile* cf = brainSet->getContourCellFile(); if (cf->empty() == false) { appendCellsFlag = (QMessageBox::question(this, "Import Neurolucida", "Append to existing contour cells?", (QMessageBox::Yes | QMessageBox::No)) == QMessageBox::Yes); } } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); brainSet->importNeurolucidaFile(fileName, importContourCells, importContours, appendContoursFlag, appendCellsFlag); fm.setContourModified(); fm.setContourCellModified(); fm.setContourCellColorModified(); } } else if (filterName == FileFilters::getRawVolumeFileFilter()) { GuiDataFileImportOptionsDialog iod(this, filterName); if (iod.exec() == GuiDataFileImportOptionsDialog::Accepted) { VolumeFile::VOLUME_TYPE volumeType; int dimensions[3]; VolumeFile::VOXEL_DATA_TYPE voxelDataType; bool byteSwap; iod.getVolumeOptions(volumeType, dimensions, voxelDataType, byteSwap); QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); brainSet->importRawVolumeFile(fileName, volumeType, dimensions, voxelDataType, byteSwap); fm.setVolumeModified(); } } else if (filterName == FileFilters::getStlSurfaceFileFilter()) { GuiDataFileImportOptionsDialog iod(this, filterName); if (iod.exec() == GuiDataFileImportOptionsDialog::Accepted) { Structure::STRUCTURE_TYPE structureType; bool importTopology; TopologyFile::TOPOLOGY_TYPES topologyType; bool importCoordinates; BrainModelSurface::SURFACE_TYPES coordinateType; bool importColorsAsPaint; bool importColorsAsRgbPaint; iod.getSurfaceOptions(structureType, importTopology, topologyType, importCoordinates, coordinateType, importColorsAsPaint, importColorsAsRgbPaint); if (brainSet->getStructure().getType() == Structure::STRUCTURE_TYPE_INVALID) { brainSet->setStructure(structureType); } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); brainSet->importStlSurfaceFile(fileName, importCoordinates, importTopology, coordinateType, topologyType); fm.setCoordinateModified(); fm.setTopologyModified(); } } else if (filterName == FileFilters::getSumaRgbFileFilter()) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); RgbPaintFile* rgb = brainSet->getRgbPaintFile(); rgb->importFromSuma(fileName); fm.setRgbPaintModified(); } else if (filterName == FileFilters::getVtkSurfaceFileFilter()) { GuiDataFileImportOptionsDialog iod(this, filterName); if (iod.exec() == GuiDataFileImportOptionsDialog::Accepted) { Structure::STRUCTURE_TYPE structureType; bool importTopology; TopologyFile::TOPOLOGY_TYPES topologyType; bool importCoordinates; BrainModelSurface::SURFACE_TYPES coordinateType; bool importColorsAsPaint; bool importColorsAsRgbPaint; iod.getSurfaceOptions(structureType, importTopology, topologyType, importCoordinates, coordinateType, importColorsAsPaint, importColorsAsRgbPaint); if (brainSet->getStructure().getType() == Structure::STRUCTURE_TYPE_INVALID) { brainSet->setStructure(structureType); } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); brainSet->importVtkSurfaceFile(fileName, importCoordinates, importTopology, importColorsAsRgbPaint, coordinateType, topologyType); fm.setCoordinateModified(); fm.setRgbPaintModified(); fm.setTopologyModified(); } } else if (filterName == FileFilters::getVtkXmlSurfaceFileFilter()) { GuiDataFileImportOptionsDialog iod(this, filterName); if (iod.exec() == GuiDataFileImportOptionsDialog::Accepted) { Structure::STRUCTURE_TYPE structureType; bool importTopology; TopologyFile::TOPOLOGY_TYPES topologyType; bool importCoordinates; BrainModelSurface::SURFACE_TYPES coordinateType; bool importColorsAsPaint; bool importColorsAsRgbPaint; iod.getSurfaceOptions(structureType, importTopology, topologyType, importCoordinates, coordinateType, importColorsAsPaint, importColorsAsRgbPaint); if (brainSet->getStructure().getType() == Structure::STRUCTURE_TYPE_INVALID) { brainSet->setStructure(structureType); } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); brainSet->importVtkXmlSurfaceFile(fileName, importCoordinates, importTopology, importColorsAsRgbPaint, coordinateType, topologyType); fm.setCoordinateModified(); fm.setRgbPaintModified(); fm.setTopologyModified(); } } else if (filterName == FileFilters::getVtkVolumeFileFilter()) { GuiDataFileImportOptionsDialog iod(this, filterName); if (iod.exec() == GuiDataFileImportOptionsDialog::Accepted) { VolumeFile::VOLUME_TYPE volumeType; int dimensions[3]; VolumeFile::VOXEL_DATA_TYPE voxelDataType; bool byteSwap; iod.getVolumeOptions(volumeType, dimensions, voxelDataType, byteSwap); QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); brainSet->importVtkStructuredPointsVolumeFile(fileName, volumeType); fm.setVolumeModified(); } } else { return false; } } catch (FileException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); } // // Remove splash image // brainSet->setDisplaySplashImage(false); // // Update controls and redraw // theMainWindow->fileModificationUpdate(fm); if (fm.getCoordinateModified()) { theMainWindow->displayNewestSurfaceInMainWindow(); } brainSet->getNodeColoring()->assignColors(); GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); return true; } /** * This static method provides one place to open data files and make the necessary * updates as a result. Returns true if an error occurs. */ bool GuiDataFileOpenDialog::openDataFile(QWidget* parentWidget, const QString specFileTag, const QString& name, const bool append, const bool update, QString& errorMessage, bool& relatedFileWarningFlag) { const QString nameNoPath(FileUtilities::basename(name)); errorMessage = ""; relatedFileWarningFlag = false; const bool needAreaColors = (theMainWindow->getBrainSet()->getAreaColorFile()->getNumberOfColors() <= 0); const bool needBorderColors = (theMainWindow->getBrainSet()->getBorderColorFile()->getNumberOfColors() <= 0); const bool needCellColors = (theMainWindow->getBrainSet()->getCellColorFile()->getNumberOfColors() <= 0); const bool needContourCellColors = (theMainWindow->getBrainSet()->getContourCellColorFile()->getNumberOfColors() <= 0); const bool needFociColors = (theMainWindow->getBrainSet()->getFociColorFile()->getNumberOfColors() <= 0); bool areaColorWarning = false; bool borderColorWarning = false; bool cellColorWarning = false; bool contourCellColorWarning = false; bool fociColorWarning = false; bool bordersLoaded = false; // // See if file exists // QFileInfo fileInfo(name); if (fileInfo.exists() == false) { if (fileInfo.isReadable() == false) { errorMessage = "File "; errorMessage.append(name); errorMessage.append(" does not exist!"); return true; } } else { if (fileInfo.isReadable() == false) { errorMessage.append("File "); errorMessage.append(name); errorMessage.append(" does not have read permission!"); return true; } } GuiFilesModified fm;; try { if (specFileTag == SpecFile::getAreaColorFileTag()) { theMainWindow->getBrainSet()->readAreaColorFile(name, append, update); fm.setAreaColorModified(); } else if (specFileTag == SpecFile::getArealEstimationFileTag()) { ArealEstimationFile* aef = theMainWindow->getBrainSet()->getArealEstimationFile(); ArealEstimationFile newFile; newFile.readFileMetaDataOnly(name); QApplication::restoreOverrideCursor(); GuiLoadNodeAttributeFileColumnSelectionDialog fcsd(theMainWindow, &newFile, aef); const int result = fcsd.exec(); newFile.clear(); // frees memory QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); if (result == QDialog::Accepted) { if (fcsd.getEraseAllExistingColumns()) { theMainWindow->getBrainSet()->clearArealEstimationFile(); } theMainWindow->getBrainSet()->readArealEstimationFile(name, fcsd.getDestinationColumns(), fcsd.getNewFileColumnNames(), fcsd.getAppendFileCommentSelection(), update); fm.setArealEstimationModified();; areaColorWarning = needAreaColors; } } else if (specFileTag == SpecFile::getRawBorderFileTag()) { theMainWindow->getBrainSet()->readBorderFile(name, BrainModelSurface::SURFACE_TYPE_RAW, append, update); fm.setBorderModified(); borderColorWarning = needBorderColors; bordersLoaded = true; } else if (specFileTag == SpecFile::getFiducialBorderFileTag()) { theMainWindow->getBrainSet()->readBorderFile(name, BrainModelSurface::SURFACE_TYPE_FIDUCIAL, append, update); fm.setBorderModified(); borderColorWarning = needBorderColors; bordersLoaded = true; } else if (specFileTag == SpecFile::getInflatedBorderFileTag()) { theMainWindow->getBrainSet()->readBorderFile(name, BrainModelSurface::SURFACE_TYPE_INFLATED, append, update); fm.setBorderModified(); borderColorWarning = needBorderColors; bordersLoaded = true; } else if (specFileTag == SpecFile::getVeryInflatedBorderFileTag()) { theMainWindow->getBrainSet()->readBorderFile(name, BrainModelSurface::SURFACE_TYPE_VERY_INFLATED, append, update); fm.setBorderModified(); borderColorWarning = needBorderColors; bordersLoaded = true; } else if (specFileTag == SpecFile::getSphericalBorderFileTag()) { theMainWindow->getBrainSet()->readBorderFile(name, BrainModelSurface::SURFACE_TYPE_SPHERICAL, append, update); fm.setBorderModified(); borderColorWarning = needBorderColors; bordersLoaded = true; } else if (specFileTag == SpecFile::getEllipsoidBorderFileTag()) { theMainWindow->getBrainSet()->readBorderFile(name, BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL, append, update); fm.setBorderModified(); borderColorWarning = needBorderColors; bordersLoaded = true; } else if (specFileTag == SpecFile::getCompressedBorderFileTag()) { theMainWindow->getBrainSet()->readBorderFile(name, BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL, append, update); fm.setBorderModified(); borderColorWarning = needBorderColors; bordersLoaded = true; } else if (specFileTag == SpecFile::getFlatBorderFileTag()) { theMainWindow->getBrainSet()->readBorderFile(name, BrainModelSurface::SURFACE_TYPE_FLAT, append, update); fm.setBorderModified(); borderColorWarning = needBorderColors; bordersLoaded = true; } else if (specFileTag == SpecFile::getLobarFlatBorderFileTag()) { theMainWindow->getBrainSet()->readBorderFile(name, BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR, append, update); fm.setBorderModified(); borderColorWarning = needBorderColors; bordersLoaded = true; } else if (specFileTag == SpecFile::getVolumeBorderFileTag()) { theMainWindow->getBrainSet()->readVolumeBorderFile(name, append, update); fm.setBorderModified(); bordersLoaded = true; borderColorWarning = needBorderColors; } else if (specFileTag == GENERIC_BORDER) { BorderFile bf; try { bf.readFileMetaDataOnly(name); } catch (FileException& e) { throw FileException(name, "Unable to read border file to check type.\n" + e.whatQString()); } BrainModelSurface::SURFACE_TYPES st = BrainModelSurface::SURFACE_TYPE_UNSPECIFIED; /* AbstractFileHeaderUpdater afhu; afhu.readFile(name); const QString typeTag = afhu.getHeaderTag(AbstractFile::headerTagConfigurationID); */ const QString typeTag = bf.getHeaderTag(AbstractFile::headerTagConfigurationID); if (typeTag.isEmpty() == false) { st = BrainModelSurface::getSurfaceTypeFromConfigurationID(typeTag); } QApplication::restoreOverrideCursor(); if ((st == BrainModelSurface::SURFACE_TYPE_UNSPECIFIED) || (st == BrainModelSurface::SURFACE_TYPE_UNKNOWN)) { std::vector labels; labels.push_back("RAW"); labels.push_back("FIDUCIAL"); labels.push_back("INFLATED"); labels.push_back("VERY_INFLATED"); labels.push_back("SPHERICAL"); labels.push_back("ELLIPSOIDAL"); labels.push_back("COMPRESSED_MEDIAL_WALL"); labels.push_back("FLAT"); labels.push_back("FLAT_LOBAR"); labels.push_back("HULL"); QApplication::beep(); QtRadioButtonSelectionDialog rbsd(parentWidget, "Choose Border Type", "Type of Borders for " + nameNoPath, labels, -1); if (rbsd.exec() == QDialog::Accepted) { st = static_cast(rbsd.getSelectedItemIndex()); } else { throw FileException(name, "You must select the type of border"); } } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); theMainWindow->getBrainSet()->readBorderFile(name, st, append, update); fm.setBorderModified(); borderColorWarning = needBorderColors; bordersLoaded = true; } else if (specFileTag.indexOf(SpecFile::getUnknownBorderFileMatchTag()) >= 0) { theMainWindow->getBrainSet()->readBorderFile(name, BrainModelSurface::SURFACE_TYPE_UNKNOWN, append, update); fm.setBorderModified(); bordersLoaded = true; borderColorWarning = needBorderColors; } else if (specFileTag == SpecFile::getBorderColorFileTag()) { theMainWindow->getBrainSet()->readBorderColorFile(name, append, update); fm.setBorderColorModified(); } else if (specFileTag == SpecFile::getBorderProjectionFileTag()) { theMainWindow->getBrainSet()->readBorderProjectionFile(name, append, update); fm.setBorderModified(); borderColorWarning = needBorderColors; bordersLoaded = true; } else if (specFileTag == SpecFile::getCellFileTag()) { theMainWindow->getBrainSet()->readCellFile(name, append, update); fm.setCellModified(); cellColorWarning = needCellColors; } else if (specFileTag == SpecFile::getCellColorFileTag()) { theMainWindow->getBrainSet()->readCellColorFile(name, append, update); fm.setCellColorModified(); } else if (specFileTag == SpecFile::getCellProjectionFileTag()) { theMainWindow->getBrainSet()->readCellProjectionFile(name, append, update); fm.setCellProjectionModified(); cellColorWarning = needCellColors; } else if (specFileTag == SpecFile::getVolumeCellFileTag()) { theMainWindow->getBrainSet()->readVolumeCellFile(name, append, update); fm.setCellModified(); cellColorWarning = needCellColors; } else if (specFileTag == SpecFile::getCocomacConnectivityFileTag()) { theMainWindow->getBrainSet()->readCocomacConnectivityFile(name, append, update); fm.setCocomacModified(); } else if (specFileTag == SpecFile::getContourFileTag()) { theMainWindow->getBrainSet()->readContourFile(name, append, update); fm.setContourModified(); } else if (specFileTag == SpecFile::getContourCellFileTag()) { theMainWindow->getBrainSet()->readContourCellFile(name, append, update); fm.setContourCellModified(); contourCellColorWarning = needContourCellColors; } else if (specFileTag == SpecFile::getContourCellColorFileTag()) { theMainWindow->getBrainSet()->readContourCellColorFile(name, append, update); fm.setContourCellModified(); } else if (specFileTag == SpecFile::getRawCoordFileTag()) { theMainWindow->getBrainSet()->readCoordinateFile(name, BrainModelSurface::SURFACE_TYPE_RAW, false, append, update); fm.setCoordinateModified(); } else if (specFileTag == SpecFile::getFiducialCoordFileTag()) { theMainWindow->getBrainSet()->readCoordinateFile(name, BrainModelSurface::SURFACE_TYPE_FIDUCIAL, false, append, update); fm.setCoordinateModified(); } else if (specFileTag == SpecFile::getInflatedCoordFileTag()) { theMainWindow->getBrainSet()->readCoordinateFile(name, BrainModelSurface::SURFACE_TYPE_INFLATED, false, append, update); fm.setCoordinateModified(); } else if (specFileTag == SpecFile::getVeryInflatedCoordFileTag()) { theMainWindow->getBrainSet()->readCoordinateFile(name, BrainModelSurface::SURFACE_TYPE_VERY_INFLATED, false, append, update); fm.setCoordinateModified(); } else if (specFileTag == SpecFile::getSphericalCoordFileTag()) { theMainWindow->getBrainSet()->readCoordinateFile(name, BrainModelSurface::SURFACE_TYPE_SPHERICAL, false, append, update); fm.setCoordinateModified(); } else if (specFileTag == SpecFile::getEllipsoidCoordFileTag()) { theMainWindow->getBrainSet()->readCoordinateFile(name, BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL, false, append, update); fm.setCoordinateModified(); } else if (specFileTag == SpecFile::getCompressedCoordFileTag()) { theMainWindow->getBrainSet()->readCoordinateFile(name, BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL, false, append, update); fm.setCoordinateModified(); } else if (specFileTag == SpecFile::getFlatCoordFileTag()) { theMainWindow->getBrainSet()->readCoordinateFile(name, BrainModelSurface::SURFACE_TYPE_FLAT, false, append, update); fm.setCoordinateModified(); } else if (specFileTag == SpecFile::getLobarFlatCoordFileTag()) { theMainWindow->getBrainSet()->readCoordinateFile(name, BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR, false, append, update); fm.setCoordinateModified(); } else if (specFileTag == SpecFile::getHullCoordFileTag()) { theMainWindow->getBrainSet()->readCoordinateFile(name, BrainModelSurface::SURFACE_TYPE_HULL, false, append, update); fm.setCoordinateModified(); } else if (specFileTag.indexOf(SpecFile::getUnknownCoordFileMatchTag()) >= 0) { theMainWindow->getBrainSet()->readCoordinateFile(name, BrainModelSurface::SURFACE_TYPE_UNKNOWN, false, append, update); fm.setCoordinateModified(); } else if (specFileTag == GENERIC_COORDINATE) { CoordinateFile cf; try { cf.readFileMetaDataOnly(name); } catch (FileException& e) { throw FileException(name, "Unable to open coord file to check type.\n" + e.whatQString()); } BrainModelSurface::SURFACE_TYPES st = BrainModelSurface::SURFACE_TYPE_UNSPECIFIED; /* AbstractFileHeaderUpdater afhu; afhu.readFile(name); const QString typeTag = afhu.getHeaderTag(AbstractFile::headerTagConfigurationID); */ const QString typeTag = cf.getHeaderTag(AbstractFile::headerTagConfigurationID); if (typeTag.isEmpty() == false) { st = BrainModelSurface::getSurfaceTypeFromConfigurationID(typeTag); } QApplication::restoreOverrideCursor(); if ((st == BrainModelSurface::SURFACE_TYPE_UNSPECIFIED) || (st == BrainModelSurface::SURFACE_TYPE_UNKNOWN)) { std::vector labels; labels.push_back("RAW"); labels.push_back("FIDUCIAL"); labels.push_back("INFLATED"); labels.push_back("VERY_INFLATED"); labels.push_back("SPHERICAL"); labels.push_back("ELLIPSOIDAL"); labels.push_back("COMPRESSED_MEDIAL_WALL"); labels.push_back("FLAT"); labels.push_back("FLAT_LOBAR"); labels.push_back("HULL"); QApplication::restoreOverrideCursor(); QApplication::beep(); QtRadioButtonSelectionDialog rbsd(parentWidget, "Choose Coordinate Type", "Type of Coordinates for " + nameNoPath, labels, -1); if (rbsd.exec() == QDialog::Accepted) { st = static_cast(rbsd.getSelectedItemIndex()); } else { throw FileException(name, "You must select the type of coordinate file."); } } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); theMainWindow->getBrainSet()->readCoordinateFile(name, st, false, append, update); fm.setCoordinateModified(); QApplication::restoreOverrideCursor(); } else if (specFileTag == SpecFile::getCutsFileTag()) { theMainWindow->getBrainSet()->readCutsFile(name, append, update); fm.setCutModified(); } else if (specFileTag == SpecFile::getDeformationFieldFileTag()) { theMainWindow->getBrainSet()->readDeformationFieldFile(name, append, update); fm.setDeformationFieldModified(); } else if (specFileTag == SpecFile::getDeformationMapFileTag()) { theMainWindow->getBrainSet()->setDeformationMapFileName(name, update); fm.setDeformationMapModified(); } else if (specFileTag == SpecFile::getFociFileTag()) { theMainWindow->getBrainSet()->readFociFile(name, append, update); fm.setFociModified(); fociColorWarning = needFociColors; } else if (specFileTag == SpecFile::getFociColorFileTag()) { theMainWindow->getBrainSet()->readFociColorFile(name, append, update); fm.setFociColorModified(); } else if (specFileTag == SpecFile::getFociProjectionFileTag()) { theMainWindow->getBrainSet()->readFociProjectionFile(name, append, update); fm.setFociProjectionModified(); fociColorWarning = needFociColors; } else if (specFileTag == SpecFile::getFociSearchFileTag()) { theMainWindow->getBrainSet()->readFociSearchFile(name, append, update); fm.setFociSearchModified(); } else if (specFileTag == SpecFile::getGeodesicDistanceFileTag()) { GeodesicDistanceFile* gdf = theMainWindow->getBrainSet()->getGeodesicDistanceFile(); GeodesicDistanceFile newFile; newFile.readFileMetaDataOnly(name); QApplication::restoreOverrideCursor(); GuiLoadNodeAttributeFileColumnSelectionDialog fcsd(theMainWindow, &newFile, gdf); const int result = fcsd.exec(); newFile.clear(); // frees memory QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); if (result == QDialog::Accepted) { if (fcsd.getEraseAllExistingColumns()) { theMainWindow->getBrainSet()->clearGeodesicDistanceFile(); } theMainWindow->getBrainSet()->readGeodesicDistanceFile(name, fcsd.getDestinationColumns(), fcsd.getNewFileColumnNames(), fcsd.getAppendFileCommentSelection(), update); fm.setGeodesicModified(); } } else if (specFileTag == SpecFile::getImageFileTag()) { theMainWindow->getBrainSet()->readImageFile(name, append, update); fm.setImagesModified(); } else if (specFileTag == SpecFile::getLatLonFileTag()) { LatLonFile* llf = theMainWindow->getBrainSet()->getLatLonFile(); LatLonFile newFile; newFile.readFileMetaDataOnly(name); QApplication::restoreOverrideCursor(); GuiLoadNodeAttributeFileColumnSelectionDialog fcsd(theMainWindow, &newFile, llf); const int result = fcsd.exec(); newFile.clear(); // frees memory QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); if (result == QDialog::Accepted) { if (fcsd.getEraseAllExistingColumns()) { theMainWindow->getBrainSet()->clearLatLonFile(); } theMainWindow->getBrainSet()->readLatLonFile(name, fcsd.getDestinationColumns(), fcsd.getNewFileColumnNames(), fcsd.getAppendFileCommentSelection(), update); fm.setLatLonModified(); } } else if (specFileTag == SpecFile::getMetricFileTag()) { MetricFile* mf = theMainWindow->getBrainSet()->getMetricFile(); MetricFile newFile; newFile.readFileMetaDataOnly(name); QApplication::restoreOverrideCursor(); GuiLoadNodeAttributeFileColumnSelectionDialog fcsd(theMainWindow, &newFile, mf); const int result = fcsd.exec(); newFile.clear(); // frees memory QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); if (result == QDialog::Accepted) { if (fcsd.getEraseAllExistingColumns()) { theMainWindow->getBrainSet()->clearMetricFile(); } theMainWindow->getBrainSet()->readMetricFile(name, fcsd.getDestinationColumns(), fcsd.getNewFileColumnNames(), fcsd.getAppendFileCommentSelection(), update); fm.setMetricModified(); } } else if (specFileTag == SpecFile::getPaintFileTag()) { PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); PaintFile newFile; newFile.readFileMetaDataOnly(name); QApplication::restoreOverrideCursor(); GuiLoadNodeAttributeFileColumnSelectionDialog fcsd(theMainWindow, &newFile, pf); const int result = fcsd.exec(); newFile.clear(); // frees memory QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); if (result == QDialog::Accepted) { if (fcsd.getEraseAllExistingColumns()) { theMainWindow->getBrainSet()->clearPaintFile(); } theMainWindow->getBrainSet()->readPaintFile(name, fcsd.getDestinationColumns(), fcsd.getNewFileColumnNames(), fcsd.getAppendFileCommentSelection(), update); fm.setPaintModified(); } areaColorWarning = needAreaColors; } else if (specFileTag == SpecFile::getPaletteFileTag()) { theMainWindow->getBrainSet()->readPaletteFile(name, append, update); fm.setPaletteModified(); } else if (specFileTag == SpecFile::getParamsFileTag()) { theMainWindow->getBrainSet()->readParamsFile(name, append, update); fm.setParameterModified(); } else if (specFileTag == SpecFile::getAtlasFileTag()) { theMainWindow->getBrainSet()->readProbabilisticAtlasFile(name, append, update); fm.setProbabilisticAtlasModified(); areaColorWarning = needAreaColors; } else if (specFileTag == SpecFile::getRgbPaintFileTag()) { theMainWindow->getBrainSet()->readRgbPaintFile(name, append, update); fm.setRgbPaintModified(); } else if (specFileTag == SpecFile::getSceneFileTag()) { theMainWindow->getBrainSet()->readSceneFile(name, append, update); fm.setSceneModified(); } else if (specFileTag == SpecFile::getSectionFileTag()) { theMainWindow->getBrainSet()->readSectionFile(name, append, update); fm.setSectionModified(); } else if (specFileTag == SpecFile::getRawSurfaceFileTag()) { theMainWindow->getBrainSet()->readSurfaceFile(name, BrainModelSurface::SURFACE_TYPE_RAW, false, append, update); fm.setCoordinateModified(); fm.setTopologyModified(); } else if (specFileTag == SpecFile::getFiducialSurfaceFileTag()) { theMainWindow->getBrainSet()->readSurfaceFile(name, BrainModelSurface::SURFACE_TYPE_FIDUCIAL, false, append, update); fm.setCoordinateModified(); fm.setTopologyModified(); } else if (specFileTag == SpecFile::getInflatedSurfaceFileTag()) { theMainWindow->getBrainSet()->readSurfaceFile(name, BrainModelSurface::SURFACE_TYPE_INFLATED, false, append, update); fm.setCoordinateModified(); fm.setTopologyModified(); } else if (specFileTag == SpecFile::getVeryInflatedSurfaceFileTag()) { theMainWindow->getBrainSet()->readSurfaceFile(name, BrainModelSurface::SURFACE_TYPE_VERY_INFLATED, false, append, update); fm.setCoordinateModified(); fm.setTopologyModified(); } else if (specFileTag == SpecFile::getSphericalSurfaceFileTag()) { theMainWindow->getBrainSet()->readSurfaceFile(name, BrainModelSurface::SURFACE_TYPE_SPHERICAL, false, append, update); fm.setCoordinateModified(); fm.setTopologyModified(); } else if (specFileTag == SpecFile::getEllipsoidSurfaceFileTag()) { theMainWindow->getBrainSet()->readSurfaceFile(name, BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL, false, append, update); fm.setCoordinateModified(); fm.setTopologyModified(); } else if (specFileTag == SpecFile::getCompressedSurfaceFileTag()) { theMainWindow->getBrainSet()->readSurfaceFile(name, BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL, false, append, update); fm.setCoordinateModified(); fm.setTopologyModified(); } else if (specFileTag == SpecFile::getFlatSurfaceFileTag()) { theMainWindow->getBrainSet()->readSurfaceFile(name, BrainModelSurface::SURFACE_TYPE_FLAT, false, append, update); fm.setCoordinateModified(); fm.setTopologyModified(); } else if (specFileTag == SpecFile::getLobarFlatSurfaceFileTag()) { theMainWindow->getBrainSet()->readSurfaceFile(name, BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR, false, append, update); fm.setCoordinateModified(); fm.setTopologyModified(); } else if (specFileTag == SpecFile::getHullSurfaceFileTag()) { theMainWindow->getBrainSet()->readSurfaceFile(name, BrainModelSurface::SURFACE_TYPE_HULL, false, append, update); fm.setCoordinateModified(); fm.setTopologyModified(); } else if (specFileTag.indexOf(SpecFile::getUnknownSurfaceFileMatchTag()) >= 0) { theMainWindow->getBrainSet()->readSurfaceFile(name, BrainModelSurface::SURFACE_TYPE_UNKNOWN, false, append, update); fm.setCoordinateModified(); fm.setTopologyModified(); } else if (specFileTag == GENERIC_SURFACE) { SurfaceFile sf; try { sf.readFileMetaDataOnly(name); } catch (FileException& e) { throw FileException(name, "Unable to open surface file to check type.\n" + e.whatQString()); } BrainModelSurface::SURFACE_TYPES st = BrainModelSurface::SURFACE_TYPE_UNSPECIFIED; const QString typeTag = sf.getHeaderTag(AbstractFile::headerTagConfigurationID); if (typeTag.isEmpty() == false) { st = BrainModelSurface::getSurfaceTypeFromConfigurationID(typeTag); } if ((st == BrainModelSurface::SURFACE_TYPE_UNSPECIFIED) || (st == BrainModelSurface::SURFACE_TYPE_UNKNOWN)) { std::vector labels; labels.push_back("RAW"); labels.push_back("FIDUCIAL"); labels.push_back("INFLATED"); labels.push_back("VERY_INFLATED"); labels.push_back("SPHERICAL"); labels.push_back("ELLIPSOIDAL"); labels.push_back("COMPRESSED_MEDIAL_WALL"); labels.push_back("FLAT"); labels.push_back("FLAT_LOBAR"); labels.push_back("HULL"); QApplication::restoreOverrideCursor(); QApplication::beep(); QtRadioButtonSelectionDialog rbsd(parentWidget, "Choose Surface Type", "Type of Surface for " + nameNoPath, labels, -1); if (rbsd.exec() == QDialog::Accepted) { st = static_cast(rbsd.getSelectedItemIndex()); } else { throw FileException(name, "You must select the type of surface file."); } } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); theMainWindow->getBrainSet()->readSurfaceFile(name, st, false, append, update); fm.setCoordinateModified(); fm.setTopologyModified(); QApplication::restoreOverrideCursor(); } else if (specFileTag == SpecFile::getStudyCollectionFileTag()) { theMainWindow->getBrainSet()->readStudyCollectionFile(name, append, update); fm.setStudyCollectionModified(); } else if (specFileTag == SpecFile::getStudyMetaDataFileTag()) { theMainWindow->getBrainSet()->readStudyMetaDataFile(name, append, update); fm.setStudyMetaDataModified(); } else if (specFileTag == SpecFile::getSurfaceShapeFileTag()) { SurfaceShapeFile* ssf = theMainWindow->getBrainSet()->getSurfaceShapeFile(); SurfaceShapeFile newFile; newFile.readFileMetaDataOnly(name); QApplication::restoreOverrideCursor(); GuiLoadNodeAttributeFileColumnSelectionDialog fcsd(theMainWindow, &newFile, ssf); const int result = fcsd.exec(); newFile.clear(); // frees memory QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); if (result == QDialog::Accepted) { if (fcsd.getEraseAllExistingColumns()) { theMainWindow->getBrainSet()->clearSurfaceShapeFile(); } theMainWindow->getBrainSet()->readSurfaceShapeFile(name, fcsd.getDestinationColumns(), fcsd.getNewFileColumnNames(), fcsd.getAppendFileCommentSelection(), update); fm.setSurfaceShapeModified(); } } else if (specFileTag == SpecFile::getVectorFileTag()) { theMainWindow->getBrainSet()->readVectorFile(name, append, update); fm.setVectorModified(); } else if (specFileTag == SpecFile::getTopographyFileTag()) { theMainWindow->getBrainSet()->readTopographyFile(name, append, update); fm.setTopographyModified(); } else if (specFileTag == SpecFile::getClosedTopoFileTag()) { theMainWindow->getBrainSet()->readTopologyFile(name, TopologyFile::TOPOLOGY_TYPE_CLOSED, append, update); fm.setTopologyModified(); } else if (specFileTag == SpecFile::getOpenTopoFileTag()) { theMainWindow->getBrainSet()->readTopologyFile(name, TopologyFile::TOPOLOGY_TYPE_OPEN, append, update); fm.setTopologyModified(); } else if (specFileTag == SpecFile::getCutTopoFileTag()) { theMainWindow->getBrainSet()->readTopologyFile(name, TopologyFile::TOPOLOGY_TYPE_CUT, append, update); fm.setTopologyModified(); } else if (specFileTag == SpecFile::getLobarCutTopoFileTag()) { theMainWindow->getBrainSet()->readTopologyFile(name, TopologyFile::TOPOLOGY_TYPE_LOBAR_CUT, append, update); fm.setTopologyModified(); } else if (specFileTag.indexOf(SpecFile::getUnknownTopoFileMatchTag()) >= 0) { theMainWindow->getBrainSet()->readTopologyFile(name, TopologyFile::TOPOLOGY_TYPE_UNKNOWN, append, update); fm.setTopologyModified(); } else if (specFileTag == GENERIC_TOPOLOGY) { TopologyFile::TOPOLOGY_TYPES tt = TopologyFile::TOPOLOGY_TYPE_UNKNOWN; TopologyFile tf; try { tf.readFileMetaDataOnly(name); } catch (FileException& e) { throw FileException(name, "Unable to read topology file to check type.\n" + e.whatQString()); } /* AbstractFileHeaderUpdater afhu; afhu.readFile(name); const QString typeTag = afhu.getHeaderTag(AbstractFile::headerTagPerimeterID); */ const QString typeTag = tf.getHeaderTag(AbstractFile::headerTagPerimeterID); if (typeTag.isEmpty() == false) { tt = TopologyFile::getTopologyTypeFromPerimeterID(typeTag); } if ((tt == TopologyFile::TOPOLOGY_TYPE_UNKNOWN) || (tt == TopologyFile::TOPOLOGY_TYPE_UNSPECIFIED)) { std::vector labels; labels.push_back("CLOSED"); labels.push_back("OPEN"); labels.push_back("CUT"); labels.push_back("LOBAR_CUT"); QApplication::restoreOverrideCursor(); QApplication::beep(); QtRadioButtonSelectionDialog rbsd(parentWidget, "Choose Topology Type", "Type of Topology for " + nameNoPath, labels, -1); if (rbsd.exec() == QDialog::Accepted) { tt = static_cast(rbsd.getSelectedItemIndex()); } else { throw FileException(name, "You must select the type of topology."); } } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); theMainWindow->getBrainSet()->readTopologyFile(name, tt, append, update); fm.setTopologyModified(); QApplication::restoreOverrideCursor(); } else if (specFileTag == SpecFile::getTransformationMatrixFileTag()) { theMainWindow->getBrainSet()->readTransformationMatrixFile(name, append, update); fm.setTransformationMatrixModified(); } else if (specFileTag == SpecFile::getTransformationDataFileTag()) { theMainWindow->getBrainSet()->readTransformationDataFile(name, append, update); theMainWindow->getBrainSet()->assignTransformationDataFileColors(); fm.setTransformationDataModified(); } else if (specFileTag == SpecFile::getVolumeAnatomyFileTag()) { theMainWindow->getBrainSet()->readVolumeFile(name, VolumeFile::VOLUME_TYPE_ANATOMY, append, update); fm.setVolumeModified(); } else if (specFileTag == SpecFile::getVolumeFunctionalFileTag()) { theMainWindow->getBrainSet()->readVolumeFile(name, VolumeFile::VOLUME_TYPE_FUNCTIONAL, append, update); fm.setVolumeModified(); } else if (specFileTag == SpecFile::getVolumePaintFileTag()) { theMainWindow->getBrainSet()->readVolumeFile(name, VolumeFile::VOLUME_TYPE_PAINT, append, update); fm.setVolumeModified(); areaColorWarning = needAreaColors; } else if (specFileTag == SpecFile::getVolumeProbAtlasFileTag()) { theMainWindow->getBrainSet()->readVolumeFile(name, VolumeFile::VOLUME_TYPE_PROB_ATLAS, append, update); fm.setVolumeModified(); areaColorWarning = needAreaColors; } else if (specFileTag == SpecFile::getVolumeRgbFileTag()) { theMainWindow->getBrainSet()->readVolumeFile(name, VolumeFile::VOLUME_TYPE_RGB, append, update); fm.setVolumeModified(); } else if (specFileTag == SpecFile::getVolumeSegmentationFileTag()) { theMainWindow->getBrainSet()->readVolumeFile(name, VolumeFile::VOLUME_TYPE_SEGMENTATION, append, update); fm.setVolumeModified(); } else if (specFileTag == SpecFile::getVolumeVectorFileTag()) { theMainWindow->getBrainSet()->readVolumeFile(name, VolumeFile::VOLUME_TYPE_VECTOR, append, update); fm.setVolumeModified(); } else if (specFileTag == SpecFile::getVtkModelFileTag()) { theMainWindow->getBrainSet()->readVtkModelFile(name, append, update); fm.setVtkModelModified(); } else if (specFileTag == SpecFile::getVocabularyFileTag()) { theMainWindow->getBrainSet()->readVocabularyFile(name, append, update); fm.setVocabularyModified(); } else if (specFileTag == SpecFile::getWustlRegionFileTag()) { theMainWindow->getBrainSet()->readWustlRegionFile(name, append, update); fm.setWustlRegionModified(); } else { std::cerr << "PROGRAM ERROR: unhandled file type " << specFileTag.toAscii().constData() << " at " << __LINE__ << " in " << __FILE__ << std::endl; } } catch (FileException& e) { errorMessage = e.whatQString(); return true; } if (bordersLoaded) { DisplaySettingsBorders* dsb = theMainWindow->getBrainSet()->getDisplaySettingsBorders(); if (dsb->getDisplayBorders() == false) { dsb->setDisplayBorders(true); theMainWindow->updateDisplayControlDialog(); } } fm.setInhibitSurfaceDefaultScaling(); theMainWindow->fileModificationUpdate(fm); if (fm.getCoordinateModified()) { theMainWindow->displayNewestSurfaceInMainWindow(); } GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); if (areaColorWarning) { QMessageBox::warning(theMainWindow, "Warning", "The file just opened requires area colors\n" "but there are no area colors loaded."); relatedFileWarningFlag = true; } if (borderColorWarning) { QMessageBox::warning(theMainWindow, "Warning", "The file just opened requires border colors\n" "but there are no border colors loaded."); relatedFileWarningFlag = true; } if (cellColorWarning) { QMessageBox::warning(theMainWindow, "Warning", "The file just opened requires cell colors\n" "but there are no cell colors loaded."); relatedFileWarningFlag = true; } if (contourCellColorWarning) { QMessageBox::warning(theMainWindow, "Warning", "The file just opened requires contour cell colors\n" "but there are no contour cell colors loaded."); relatedFileWarningFlag = true; } if (fociColorWarning) { QMessageBox::warning(theMainWindow, "Warning", "The file just opened requires foci colors\n" "but there are no foci colors loaded."); relatedFileWarningFlag = true; } return false; } /** * copy a file to the current directory, returns true if successful. */ bool GuiDataFileOpenDialog::copyFile(const QString& name) { const QString nameNoExt(FileUtilities::filenameWithoutExtension(name)); QString volumeDataFileName; if (name.endsWith(SpecFile::getAnalyzeVolumeFileExtension())) { volumeDataFileName = nameNoExt + ".img"; } else if (name.endsWith(SpecFile::getAfniVolumeFileExtension())) { volumeDataFileName = nameNoExt + ".BRIK"; } else if (name.endsWith(SpecFile::getWustlVolumeFileExtension())) { volumeDataFileName = nameNoExt + ".img"; } if (volumeDataFileName.isEmpty() == false) { if (QFile::exists(volumeDataFileName) == false) { volumeDataFileName += ".gz"; } } if (FileUtilities::copyFile(name, FileUtilities::basename(name))) { QString msg("Error copying:\n"); msg.append(name); msg.append("\nDoes the file exist ?"); QMessageBox::critical(this, "ERROR", msg); return false; } if (volumeDataFileName.isEmpty() == false) { if (FileUtilities::copyFile(volumeDataFileName, FileUtilities::basename(volumeDataFileName))) { QString msg("Error copying:\n"); msg.append(volumeDataFileName); msg.append("\nDoes the file exist ?"); QMessageBox::critical(this, "ERROR", msg); return false; } } return true; } caret-5.6.4~dfsg.1.orig/caret/GuiDataFileMathDialog.h0000664000175000017500000001541711572067322022110 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_METRIC_MATH_DIALOG_H__ #define __GUI_METRIC_MATH_DIALOG_H__ #include "WuQDialog.h" class GuiNodeAttributeColumnSelectionComboBox; class GuiVolumeSelectionControl; class MetricFile; class QGroupBox; class QLabel; class QLineEdit; class QRadioButton; class QDoubleSpinBox; /// dialog for performing mathematical operations on metric files class GuiDataFileMathDialog : public WuQDialog { Q_OBJECT public: /// dialog mode enum DIALOG_MODE { DIALOG_MODE_METRIC_FILE, DIALOG_MODE_SURFACE_SHAPE_FILE, DIALOG_MODE_VOLUME_FILE }; /// Constructor GuiDataFileMathDialog(QWidget* parent, const DIALOG_MODE modeIn); /// Constructor ~GuiDataFileMathDialog(); /// update the dialog void updateDialog(); protected slots: /// called when apply button pressed void slotApplyButton(); /// called when output column selected void slotOutputMetricColumnComboBox(); /// called when an operations radio button is selected void slotOperationsButtonGroup(); protected: /// perform metric math operations void performMetricMathOperations(QString& errorMessage); /// perform volume math operations void performVolumeMathOperations(QString& errorMessage); /// update metric part of dialog void updateMetricPartOfDialog(); /// update volume part of dialog void updateVolumePartOfDialog(); /// create the metric column part of the dialog. QWidget* createMetricColumnPartOfDialog(); /// create the volume part of the dialog QWidget* createVolumePartOfDialog(); /// create the operations part of the dialog. QWidget* createOperationsPartOfDialog(); /// get the data file since MetricFile* getNodeDataFile(); /// input column A GuiNodeAttributeColumnSelectionComboBox* inputMetricColumnComboBoxA; /// input column B GuiNodeAttributeColumnSelectionComboBox* inputMetricColumnComboBoxB; /// input colum B label QLabel* inputMetricColumnLabelB; /// output column GuiNodeAttributeColumnSelectionComboBox* outputMetricColumnComboBox; /// output metric name line edit QLineEdit* outputMetricNameLineEdit; /// combine columns radio button QRadioButton* combineColumnsRadioButton; /// add columns radio button QRadioButton* addColumnsRadioButton; /// subtract columns radio button QRadioButton* subtractColumnsRadioButton; /// multiply columns radio button QRadioButton* multiplyColumnsRadioButton; /// divide columns radio button QRadioButton* divideColumnsRadioButton; /// average columns radio button QRadioButton* averageColumnsRadioButton; /// multiply single column by scalar radio button QRadioButton* multiplyColumnByScalarRadioButton; /// add scalar to single column radio button QRadioButton* addScalarToColumnRadioButton; /// ceiling by scalar radio button QRadioButton* ceilingColumnByScalarRadioButton; /// floor by scalar radio button QRadioButton* floorColumnByScalarRadioButton; /// AND columns radio button QRadioButton* andColumnsRadioButton; /// OR columns radio button QRadioButton* orColumnsRadioButton; /// fix NaN radio button QRadioButton* fixNaNRadioButton; /// square root radio button QRadioButton* squareRootRadioButton; /// log radio button QRadioButton* logRadioButton; /// log base line edit QLineEdit* logBaseLineEdit; /// copy volume radio button QRadioButton* copyVolumeRadioButton; /// absolute value radio button QRadioButton* absValueRadioButton; /// multiply by scalar float spin box QDoubleSpinBox* multiplyScalarDoubleSpinBox; /// add by scalar float spin box QDoubleSpinBox* addScalarDoubleSpinBox; /// ceiling scalar float spin box QDoubleSpinBox* ceilingScalarDoubleSpinBox; /// floor scalar float spin box QDoubleSpinBox* floorScalarDoubleSpinBox; /// inclusive set range to zero radio button QRadioButton* inclusiveSetRangeToZeroRadioButton; /// inclusive set range to zero min value float spin box QDoubleSpinBox* inclusiveSetRangeToZeroMinValueDoubleSpinBox; /// inclusive set range to zero max value float spin box QDoubleSpinBox* inclusiveSetRangeToZeroMaxValueDoubleSpinBox; /// exclusive set range to zero radio button QRadioButton* exclusiveSetRangeToZeroRadioButton; /// exclusive set range to zero min value float spin box QDoubleSpinBox* exclusiveSetRangeToZeroMinValueDoubleSpinBox; /// exclusive set range to zero max value float spin box QDoubleSpinBox* exclusiveSetRangeToZeroMaxValueDoubleSpinBox; /// fit values to a normal distribution QRadioButton* normalizeValuesRadioButton; /// normalize mean flaot spin box QDoubleSpinBox* normalizeMeanDoubleSpinBox; /// normalize deviation float spin box QDoubleSpinBox* normalizeDeviationDoubleSpinBox; /// 1.0 - value check box QRadioButton* oneMinusValueRadioButton; /// the dialog's mode DIALOG_MODE dialogMode; /// volume A GuiVolumeSelectionControl* volumeASelectionControl; /// volume B GuiVolumeSelectionControl* volumeBSelectionControl; /// ouptut volume GuiVolumeSelectionControl* volumeOutputSelectionControl; /// group box for volume B QGroupBox* volumeBGroupBox; }; #endif // __GUI_METRIC_MATH_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiDataFileMathDialog.cxx0000664000175000017500000013345111572067322022462 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "BrainModelVolumeVoxelColoring.h" #include "BrainSet.h" #include "GuiBrainModelOpenGL.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "GuiDataFileMathDialog.h" #include "GuiNodeAttributeColumnSelectionComboBox.h" #include "GuiVolumeSelectionControl.h" #include "MetricFile.h" #include "QtUtilities.h" #include "SurfaceShapeFile.h" #include "VolumeFile.h" #include "global_variables.h" /** * Constructor. */ GuiDataFileMathDialog::GuiDataFileMathDialog(QWidget* parent, const DIALOG_MODE modeIn) : WuQDialog(parent) { dialogMode = modeIn; // // Set caption // switch (dialogMode) { case DIALOG_MODE_METRIC_FILE: setWindowTitle("Metric File Mathematical Operations"); break; case DIALOG_MODE_SURFACE_SHAPE_FILE: setWindowTitle("Surface Shape File Mathematical Operations"); break; case DIALOG_MODE_VOLUME_FILE: setWindowTitle("Volume File Mathematical Operations"); break; } // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); switch (dialogMode) { case DIALOG_MODE_METRIC_FILE: case DIALOG_MODE_SURFACE_SHAPE_FILE: // // Create the metric column part of the dialog // dialogLayout->addWidget(createMetricColumnPartOfDialog()); break; case DIALOG_MODE_VOLUME_FILE: // // Create the volume part of the dialog // dialogLayout->addWidget(createVolumePartOfDialog()); break; } // // Create the operations part of the dialog // QWidget* operationsWidget = createOperationsPartOfDialog(); QScrollArea* scrollArea = new QScrollArea; scrollArea->setWidget(operationsWidget); scrollArea->setWidgetResizable(true); dialogLayout->addWidget(scrollArea); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; dialogLayout->addLayout(buttonsLayout); buttonsLayout->setSpacing(2); // // Apply button // QPushButton* applyButton = new QPushButton("Apply"); applyButton->setAutoDefault(false); buttonsLayout->addWidget(applyButton); QObject::connect(applyButton, SIGNAL(clicked()), this, SLOT(slotApplyButton())); // // Close button connects to QDialogs close() slot. // QPushButton* closeButton = new QPushButton("Close"); closeButton->setAutoDefault(false); buttonsLayout->addWidget(closeButton); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); QtUtilities::makeButtonsSameSize(applyButton, closeButton); updateDialog(); } /** * Destructor. */ GuiDataFileMathDialog::~GuiDataFileMathDialog() { } /** * Called when apply button pressed. */ void GuiDataFileMathDialog::slotApplyButton() { QString errorMessage; switch (dialogMode) { case DIALOG_MODE_METRIC_FILE: { performMetricMathOperations(errorMessage); GuiFilesModified fm; fm.setMetricModified(); theMainWindow->fileModificationUpdate(fm); } break; case DIALOG_MODE_SURFACE_SHAPE_FILE: { performMetricMathOperations(errorMessage); GuiFilesModified fm; fm.setSurfaceShapeModified(); theMainWindow->fileModificationUpdate(fm); } break; case DIALOG_MODE_VOLUME_FILE: { performVolumeMathOperations(errorMessage); GuiFilesModified fm; fm.setVolumeModified(); theMainWindow->fileModificationUpdate(fm); } break; } if (errorMessage.isEmpty() == false) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", errorMessage); return; } GuiBrainModelOpenGL::updateAllGL(); QApplication::beep(); QApplication::restoreOverrideCursor(); } /** * perform metric math operations. */ void GuiDataFileMathDialog::performMetricMathOperations(QString& errorMessage) { int columnA = inputMetricColumnComboBoxA->currentIndex(); int columnB = inputMetricColumnComboBoxB->currentIndex(); int outputColumn = outputMetricColumnComboBox->currentIndex(); if ((columnA < 0) || (columnA > getNodeDataFile()->getNumberOfColumns())) { errorMessage.append("Input column A is invalid.\n"); } if ((columnB < 0) || (columnB > getNodeDataFile()->getNumberOfColumns())) { errorMessage.append("Input column B is invalid.\n"); } if (errorMessage.isEmpty() == false) { return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); const bool creatingNewOutputColumn = (outputColumn < 0); const QString outputColumnName(outputMetricNameLineEdit->text()); try { if (addColumnsRadioButton->isChecked()) { getNodeDataFile()->performBinaryOperation(MetricFile::BINARY_OPERATION_ADD, columnA, columnB, outputColumn, outputColumnName); } else if (subtractColumnsRadioButton->isChecked()) { getNodeDataFile()->performBinaryOperation(MetricFile::BINARY_OPERATION_SUBTRACT, columnA, columnB, outputColumn, outputColumnName); } else if (multiplyColumnsRadioButton->isChecked()) { getNodeDataFile()->performBinaryOperation(MetricFile::BINARY_OPERATION_MULTIPLY, columnA, columnB, outputColumn, outputColumnName); } else if (divideColumnsRadioButton->isChecked()) { getNodeDataFile()->performBinaryOperation(MetricFile::BINARY_OPERATION_DIVIDE, columnA, columnB, outputColumn, outputColumnName); } else if (averageColumnsRadioButton->isChecked()) { getNodeDataFile()->performBinaryOperation(MetricFile::BINARY_OPERATION_AVERAGE, columnA, columnB, outputColumn, outputColumnName); } else if (addScalarToColumnRadioButton->isChecked()) { getNodeDataFile()->performUnaryOperation(MetricFile::UNARY_OPERATION_ADD, columnA, outputColumn, outputColumnName, addScalarDoubleSpinBox->value()); } else if (multiplyColumnByScalarRadioButton->isChecked()) { getNodeDataFile()->performUnaryOperation(MetricFile::UNARY_OPERATION_MULTIPLY, columnA, outputColumn, outputColumnName, multiplyScalarDoubleSpinBox->value()); } else if (ceilingColumnByScalarRadioButton->isChecked()) { getNodeDataFile()->performUnaryOperation(MetricFile::UNARY_OPERATION_CEILING, columnA, outputColumn, outputColumnName, ceilingScalarDoubleSpinBox->value()); } else if (floorColumnByScalarRadioButton->isChecked()) { getNodeDataFile()->performUnaryOperation(MetricFile::UNARY_OPERATION_FLOOR, columnA, outputColumn, outputColumnName, floorScalarDoubleSpinBox->value()); } else if (fixNaNRadioButton->isChecked()) { getNodeDataFile()->performUnaryOperation(MetricFile::UNARY_OPERATION_FIX_NOT_A_NUMBER, columnA, outputColumn, outputColumnName, 0.0); } else if (squareRootRadioButton->isChecked()) { getNodeDataFile()->performUnaryOperation(MetricFile::UNARY_OPERATION_SQUARE_ROOT, columnA, outputColumn, outputColumnName, 0.0); } else if (logRadioButton->isChecked()) { getNodeDataFile()->performUnaryOperation(MetricFile::UNARY_OPERATION_LOG2, columnA, outputColumn, outputColumnName, logBaseLineEdit->text().toDouble()); } else if (absValueRadioButton->isChecked()) { getNodeDataFile()->performUnaryOperation(MetricFile::UNARY_OPERATION_ABS_VALUE, columnA, outputColumn, outputColumnName, 0.0); } else if (inclusiveSetRangeToZeroRadioButton->isChecked()) { getNodeDataFile()->setRangeOfValuesToZero(columnA, outputColumn, outputColumnName, inclusiveSetRangeToZeroMinValueDoubleSpinBox->value(), inclusiveSetRangeToZeroMaxValueDoubleSpinBox->value(), true); } else if (exclusiveSetRangeToZeroRadioButton->isChecked()) { getNodeDataFile()->setRangeOfValuesToZero(columnA, outputColumn, outputColumnName, exclusiveSetRangeToZeroMinValueDoubleSpinBox->value(), exclusiveSetRangeToZeroMaxValueDoubleSpinBox->value(), false); } else if (normalizeValuesRadioButton->isChecked()) { getNodeDataFile()->remapColumnToNormalDistribution(columnA, outputColumn, outputColumnName, normalizeMeanDoubleSpinBox->value(), normalizeDeviationDoubleSpinBox->value()); } else if (oneMinusValueRadioButton->isChecked()) { getNodeDataFile()->performUnaryOperation(MetricFile::UNARY_OPERATION_SUBTRACT_FROM_ONE, columnA, outputColumn, outputColumnName, 0.0); } else { errorMessage = "No Operation Selected."; return; } } catch (FileException& e) { errorMessage = e.whatQString(); return; } if (creatingNewOutputColumn) { const int col = getNodeDataFile()->getNumberOfColumns() - 1; outputMetricColumnComboBox->setCurrentIndex(col); outputMetricNameLineEdit->setText(getNodeDataFile()->getColumnName(col)); } } /** * perform volume math operations. */ void GuiDataFileMathDialog::performVolumeMathOperations(QString& errorMessage) { // // Get the input volumes // VolumeFile* volumeA = volumeASelectionControl->getSelectedVolumeFile(); VolumeFile* volumeB = volumeBSelectionControl->getSelectedVolumeFile(); // // Make sure volume A is valid // if (volumeA == NULL) { errorMessage = "Volume A is invalid."; return; } // // Get the output volume // VolumeFile* volumeOutput = volumeOutputSelectionControl->getSelectedVolumeFile(); bool createdNewVolume = false; if (volumeOutput == NULL) { if (volumeOutputSelectionControl->getNewVolumeSelected()) { // // Make output volume same as volume A // volumeOutput = new VolumeFile(*volumeA); volumeOutput->setVolumeType(volumeOutputSelectionControl->getSelectedVolumeType()); createdNewVolume = true; } } volumeOutput->setFileName(volumeOutputSelectionControl->getSelectedVolumeFileName()); volumeOutput->setDescriptiveLabel(volumeOutputSelectionControl->getSelectedVolumeDescriptiveLabel()); QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); try { if (combineColumnsRadioButton->isChecked()) { if (volumeB == NULL) { errorMessage = "Volume B is invalid."; return; } VolumeFile::performMathematicalOperation(VolumeFile::VOLUME_MATH_OPERATION_COMBINE_PAINT, volumeA, volumeB, NULL, volumeOutput); } else if (addColumnsRadioButton->isChecked()) { if (volumeB == NULL) { errorMessage = "Volume B is invalid."; return; } VolumeFile::performMathematicalOperation(VolumeFile::VOLUME_MATH_OPERATION_ADD, volumeA, volumeB, NULL, volumeOutput); } else if (subtractColumnsRadioButton->isChecked()) { if (volumeB == NULL) { errorMessage = "Volume B is invalid."; return; } VolumeFile::performMathematicalOperation(VolumeFile::VOLUME_MATH_OPERATION_SUBTRACT, volumeA, volumeB, NULL, volumeOutput); } else if (multiplyColumnsRadioButton->isChecked()) { if (volumeB == NULL) { errorMessage = "Volume B is invalid."; return; } VolumeFile::performMathematicalOperation(VolumeFile::VOLUME_MATH_OPERATION_MULTIPLY, volumeA, volumeB, NULL, volumeOutput); } else if (divideColumnsRadioButton->isChecked()) { if (volumeB == NULL) { errorMessage = "Volume B is invalid."; return; } VolumeFile::performMathematicalOperation(VolumeFile::VOLUME_MATH_OPERATION_DIVIDE, volumeA, volumeB, NULL, volumeOutput); } else if (averageColumnsRadioButton->isChecked()) { if (volumeB == NULL) { errorMessage = "Volume B is invalid."; return; } VolumeFile::performMathematicalOperation(VolumeFile::VOLUME_MATH_OPERATION_AVERAGE, volumeA, volumeB, NULL, volumeOutput); } else if (andColumnsRadioButton->isChecked()) { if (volumeB == NULL) { errorMessage = "Volume B is invalid."; return; } VolumeFile::performMathematicalOperation(VolumeFile::VOLUME_MATH_OPERATION_AND, volumeA, volumeB, NULL, volumeOutput); } else if (orColumnsRadioButton->isChecked()) { if (volumeB == NULL) { errorMessage = "Volume B is invalid."; return; } VolumeFile::performMathematicalOperation(VolumeFile::VOLUME_MATH_OPERATION_OR, volumeA, volumeB, NULL, volumeOutput); } else if (copyVolumeRadioButton->isChecked()) { *volumeOutput = *volumeA; volumeOutput->setFileName(volumeOutputSelectionControl->getSelectedVolumeFileName()); volumeOutput->setDescriptiveLabel(volumeOutputSelectionControl->getSelectedVolumeDescriptiveLabel()); volumeOutput->setVolumeType(volumeOutputSelectionControl->getSelectedVolumeType()); } else if (addScalarToColumnRadioButton->isChecked()) { VolumeFile::performUnaryOperation(VolumeFile::UNARY_OPERATION_ADD, volumeA, volumeOutput, addScalarDoubleSpinBox->value()); } else if (multiplyColumnByScalarRadioButton->isChecked()) { VolumeFile::performUnaryOperation(VolumeFile::UNARY_OPERATION_MULTIPLY, volumeA, volumeOutput, multiplyScalarDoubleSpinBox->value()); } else if (ceilingColumnByScalarRadioButton->isChecked()) { VolumeFile::performUnaryOperation(VolumeFile::UNARY_OPERATION_CEILING, volumeA, volumeOutput, ceilingScalarDoubleSpinBox->value()); } else if (floorColumnByScalarRadioButton->isChecked()) { VolumeFile::performUnaryOperation(VolumeFile::UNARY_OPERATION_FLOOR, volumeA, volumeOutput, floorScalarDoubleSpinBox->value()); } else if (fixNaNRadioButton->isChecked()) { VolumeFile::performUnaryOperation(VolumeFile::UNARY_OPERATION_FIX_NOT_A_NUMBER, volumeA, volumeOutput, 0.0); } else if (absValueRadioButton->isChecked()) { VolumeFile::performUnaryOperation(VolumeFile::UNARY_OPERATION_ABS_VALUE, volumeA, volumeOutput, 0.0); } else if (inclusiveSetRangeToZeroRadioButton->isChecked()) { VolumeFile::setRangeOfValuesToZero(volumeA, volumeOutput, inclusiveSetRangeToZeroMinValueDoubleSpinBox->value(), inclusiveSetRangeToZeroMaxValueDoubleSpinBox->value(), true); } else if (exclusiveSetRangeToZeroRadioButton->isChecked()) { VolumeFile::setRangeOfValuesToZero(volumeA, volumeOutput, exclusiveSetRangeToZeroMinValueDoubleSpinBox->value(), exclusiveSetRangeToZeroMaxValueDoubleSpinBox->value(), false); } else if (squareRootRadioButton->isChecked()) { VolumeFile::performUnaryOperation(VolumeFile::UNARY_OPERATION_SQUARE_ROOT, volumeA, volumeOutput, 0.0); } else if (logRadioButton->isChecked()) { VolumeFile::performUnaryOperation(VolumeFile::UNARY_OPERATION_LOG2, volumeA, volumeOutput, logBaseLineEdit->text().toDouble()); } else if (oneMinusValueRadioButton->isChecked()) { VolumeFile::performUnaryOperation(VolumeFile::UNARY_OPERATION_SUBTRACT_FROM_ONE, volumeA, volumeOutput, 0.0); } else { errorMessage = "No Operation Selected."; return; } // // Add the new volume if necessary // if (createdNewVolume) { theMainWindow->getBrainSet()->addVolumeFile(volumeOutput->getVolumeType(), volumeOutput, "", true, false); volumeOutputSelectionControl->updateControl(); volumeOutputSelectionControl->setSelectedVolumeFile(volumeOutput); if (volumeOutput->getVolumeType() == VolumeFile::VOLUME_TYPE_PROB_ATLAS) { theMainWindow->getBrainSet()->synchronizeProbAtlasVolumeRegionNames(); } } // // Update the volume's coloring // //BrainModelVolumeVoxelColoring* bmvvc = theMainWindow->getBrainSet()->getVoxelColoring(); //bmvvc->updateVolumeFileColoring(volumeOutput); volumeOutput->setVoxelColoringInvalid(); } catch (FileException& e) { errorMessage = e.whatQString(); if (createdNewVolume) { delete volumeOutput; } return; } } /** * update the dialog. */ void GuiDataFileMathDialog::updateDialog() { switch (dialogMode) { case DIALOG_MODE_METRIC_FILE: case DIALOG_MODE_SURFACE_SHAPE_FILE: updateMetricPartOfDialog(); break; case DIALOG_MODE_VOLUME_FILE: updateVolumePartOfDialog(); break; } } /** * update metric part of dialog. */ void GuiDataFileMathDialog::updateMetricPartOfDialog() { inputMetricColumnComboBoxA->updateComboBox(); inputMetricColumnComboBoxB->updateComboBox(); outputMetricColumnComboBox->updateComboBox(); slotOutputMetricColumnComboBox(); } /** * update volume part of dialog. */ void GuiDataFileMathDialog::updateVolumePartOfDialog() { volumeASelectionControl->updateControl(); volumeBSelectionControl->updateControl(); volumeOutputSelectionControl->updateControl(); } /** * create the operations part of the dialog. */ QWidget* GuiDataFileMathDialog::createOperationsPartOfDialog() { bool volumeFlag = false; QString idName; switch (dialogMode) { case DIALOG_MODE_METRIC_FILE: case DIALOG_MODE_SURFACE_SHAPE_FILE: idName = "Column"; break; case DIALOG_MODE_VOLUME_FILE: idName = "Volume"; volumeFlag = true; break; } QWidget* operationsWidget = new QWidget; QGridLayout* operationsGridLayout = new QGridLayout(operationsWidget); int rowCount = 0; // // Button group used to keep operation buttons mutually exclusive // QButtonGroup* operationsButtonGroup = new QButtonGroup(this); int opNum = 0; QObject::connect(operationsButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotOperationsButtonGroup())); // // combine paint volume // if (volumeFlag) { combineColumnsRadioButton = new QRadioButton("Combine Paint " + idName + " A and Paint " + idName + " B"); operationsButtonGroup->addButton(combineColumnsRadioButton, opNum++); operationsGridLayout->addWidget(combineColumnsRadioButton, rowCount, 0); rowCount++; } else { combineColumnsRadioButton = NULL; } // // columnA + columnB // addColumnsRadioButton = new QRadioButton("Add " + idName + " A to " + idName + " B"); if (volumeFlag == false) { addColumnsRadioButton->setText("A+B"); } operationsButtonGroup->addButton(addColumnsRadioButton, opNum++); operationsGridLayout->addWidget(addColumnsRadioButton, rowCount, 0); rowCount++; // // columnA - columnB // subtractColumnsRadioButton = new QRadioButton("Subtract " + idName + " B from " + idName + " A"); if (volumeFlag == false) { subtractColumnsRadioButton->setText("A-B"); } operationsButtonGroup->addButton(subtractColumnsRadioButton, opNum++); operationsGridLayout->addWidget(subtractColumnsRadioButton, rowCount, 0); rowCount++; // // columnA * columnB // multiplyColumnsRadioButton = new QRadioButton("Multiply " + idName + " A by " + idName + " B"); if (volumeFlag == false) { multiplyColumnsRadioButton->setText("A*B"); } operationsButtonGroup->addButton(multiplyColumnsRadioButton, opNum++); operationsGridLayout->addWidget(multiplyColumnsRadioButton, rowCount, 0); rowCount++; // // columnA / columnB // divideColumnsRadioButton = new QRadioButton("Divide " + idName + " A by " + idName + " B"); if (volumeFlag == false) { divideColumnsRadioButton->setText("A/B"); } operationsButtonGroup->addButton(divideColumnsRadioButton, opNum++); operationsGridLayout->addWidget(divideColumnsRadioButton, rowCount, 0); rowCount++; // // average of columnA & columnB // averageColumnsRadioButton = new QRadioButton("Average of " + idName + " and " + idName + " B"); if (volumeFlag == false) { averageColumnsRadioButton->setText("Average(A,B)"); } operationsButtonGroup->addButton(averageColumnsRadioButton, opNum++); operationsGridLayout->addWidget(averageColumnsRadioButton, rowCount, 0); rowCount++; // // AND Segmentation volumes // if (volumeFlag) { andColumnsRadioButton = new QRadioButton("AND Segmentation " + idName + " A and Segmentation " + idName + " B"); operationsButtonGroup->addButton(andColumnsRadioButton, opNum++); operationsGridLayout->addWidget(andColumnsRadioButton, rowCount, 0); rowCount++; } else { andColumnsRadioButton = NULL; } // // OR Segmentation volumes // if (volumeFlag) { orColumnsRadioButton = new QRadioButton("OR Segmentation " + idName + " A and Segmentation " + idName + " B"); operationsButtonGroup->addButton(orColumnsRadioButton, opNum++); operationsGridLayout->addWidget(orColumnsRadioButton, rowCount, 0); rowCount++; } else { orColumnsRadioButton = NULL; } // // Absolute value // absValueRadioButton = new QRadioButton("Absolute value in " + idName + " A"); operationsButtonGroup->addButton(absValueRadioButton, opNum++); operationsGridLayout->addWidget(absValueRadioButton, rowCount, 0); rowCount++; // // Log // logRadioButton = new QRadioButton("Log of " + idName + " A, enter base"); operationsButtonGroup->addButton(logRadioButton, opNum++); logBaseLineEdit = new QLineEdit; logBaseLineEdit->setObjectName("logBaseLineEdit"); logBaseLineEdit->setText("2.0"); logBaseLineEdit->setToolTip( "Enter logarithm\n" "base here."); operationsGridLayout->addWidget(logRadioButton, rowCount, 0); operationsGridLayout->addWidget(logBaseLineEdit, rowCount, 1); rowCount++; // // Square Root // squareRootRadioButton = new QRadioButton("Square Root in " + idName + " A"); operationsButtonGroup->addButton(squareRootRadioButton, opNum++); operationsGridLayout->addWidget(squareRootRadioButton, rowCount, 0); rowCount++; // // columnA + scalar // addScalarToColumnRadioButton = new QRadioButton("Add Scalar to " + idName + " A"); operationsButtonGroup->addButton(addScalarToColumnRadioButton, opNum++); addScalarDoubleSpinBox = new QDoubleSpinBox; addScalarDoubleSpinBox->setMinimum(-100000.0); addScalarDoubleSpinBox->setMaximum(100000.0); addScalarDoubleSpinBox->setSingleStep(1.0); addScalarDoubleSpinBox->setDecimals(3); addScalarDoubleSpinBox->setValue(0.0); operationsGridLayout->addWidget(addScalarToColumnRadioButton, rowCount, 0); operationsGridLayout->addWidget(addScalarDoubleSpinBox, rowCount, 1); rowCount++; copyVolumeRadioButton = NULL; if (volumeFlag) { copyVolumeRadioButton = new QRadioButton("Copy " + idName + " A"); operationsButtonGroup->addButton(copyVolumeRadioButton, opNum++); operationsGridLayout->addWidget(copyVolumeRadioButton, rowCount, 0); rowCount++; } // // columnA * scalar // multiplyColumnByScalarRadioButton = new QRadioButton("Multiply " + idName + " A by Scalar"); operationsButtonGroup->addButton(multiplyColumnByScalarRadioButton, opNum++); multiplyScalarDoubleSpinBox = new QDoubleSpinBox; multiplyScalarDoubleSpinBox->setMinimum(-100000.0); multiplyScalarDoubleSpinBox->setMaximum( 100000.0); multiplyScalarDoubleSpinBox->setSingleStep(1.0); multiplyScalarDoubleSpinBox->setDecimals(3); multiplyScalarDoubleSpinBox->setValue(1.0); operationsGridLayout->addWidget(multiplyColumnByScalarRadioButton, rowCount, 0); operationsGridLayout->addWidget(multiplyScalarDoubleSpinBox, rowCount, 1); rowCount++; // // columnA ceiling // ceilingColumnByScalarRadioButton = new QRadioButton("Limit Maximum Value in " + idName + " A"); operationsButtonGroup->addButton(ceilingColumnByScalarRadioButton, opNum++); ceilingScalarDoubleSpinBox = new QDoubleSpinBox; ceilingScalarDoubleSpinBox->setMinimum(-100000.0); ceilingScalarDoubleSpinBox->setMaximum( 100000.0); ceilingScalarDoubleSpinBox->setSingleStep(1.0); ceilingScalarDoubleSpinBox->setDecimals(3); ceilingScalarDoubleSpinBox->setValue(10000.0); operationsGridLayout->addWidget(ceilingColumnByScalarRadioButton, rowCount, 0); operationsGridLayout->addWidget(ceilingScalarDoubleSpinBox, rowCount, 1); rowCount++; // // columnA floor // floorColumnByScalarRadioButton = new QRadioButton("Limit Minimum Value in " + idName + " A"); operationsButtonGroup->addButton(floorColumnByScalarRadioButton, opNum++); floorScalarDoubleSpinBox = new QDoubleSpinBox; floorScalarDoubleSpinBox->setMinimum(-100000.0); floorScalarDoubleSpinBox->setMaximum( 100000.0); floorScalarDoubleSpinBox->setSingleStep(1.0); floorScalarDoubleSpinBox->setDecimals(3); floorScalarDoubleSpinBox->setValue(-10000.0); operationsGridLayout->addWidget(floorColumnByScalarRadioButton, rowCount, 0); operationsGridLayout->addWidget(floorScalarDoubleSpinBox, rowCount, 1); rowCount++; // // Fix NaN // fixNaNRadioButton = new QRadioButton("Fix NaN (Not a Number) in " + idName + " A"); operationsButtonGroup->addButton(fixNaNRadioButton, opNum++); operationsGridLayout->addWidget(fixNaNRadioButton, rowCount, 0); rowCount++; // // Inclusive set range to zero // inclusiveSetRangeToZeroRadioButton = new QRadioButton("Set Inclusive Range to Zero"); operationsButtonGroup->addButton(inclusiveSetRangeToZeroRadioButton, opNum++); inclusiveSetRangeToZeroMinValueDoubleSpinBox = new QDoubleSpinBox; inclusiveSetRangeToZeroMinValueDoubleSpinBox->setMinimum(-100000.0); inclusiveSetRangeToZeroMinValueDoubleSpinBox->setMaximum( 100000.0); inclusiveSetRangeToZeroMinValueDoubleSpinBox->setSingleStep(1.0); inclusiveSetRangeToZeroMinValueDoubleSpinBox->setDecimals(3); inclusiveSetRangeToZeroMinValueDoubleSpinBox->setValue(0.0); inclusiveSetRangeToZeroMinValueDoubleSpinBox->setToolTip( "Minimum value for range."); inclusiveSetRangeToZeroMaxValueDoubleSpinBox = new QDoubleSpinBox; inclusiveSetRangeToZeroMaxValueDoubleSpinBox->setMinimum(-100000.0); inclusiveSetRangeToZeroMaxValueDoubleSpinBox->setMaximum( 100000.0); inclusiveSetRangeToZeroMaxValueDoubleSpinBox->setSingleStep(1.0); inclusiveSetRangeToZeroMaxValueDoubleSpinBox->setDecimals(3); inclusiveSetRangeToZeroMaxValueDoubleSpinBox->setValue(0.0); inclusiveSetRangeToZeroMaxValueDoubleSpinBox->setToolTip( "Maximum value for range."); operationsGridLayout->addWidget(inclusiveSetRangeToZeroRadioButton, rowCount, 0); operationsGridLayout->addWidget(inclusiveSetRangeToZeroMinValueDoubleSpinBox, rowCount, 1); operationsGridLayout->addWidget(inclusiveSetRangeToZeroMaxValueDoubleSpinBox, rowCount, 2); rowCount++; // // Inclusive set range to zero // exclusiveSetRangeToZeroRadioButton = new QRadioButton("Set Exclusive Range to Zero"); operationsButtonGroup->addButton(exclusiveSetRangeToZeroRadioButton, opNum++); exclusiveSetRangeToZeroMinValueDoubleSpinBox = new QDoubleSpinBox; exclusiveSetRangeToZeroMinValueDoubleSpinBox->setMinimum(-100000.0); exclusiveSetRangeToZeroMinValueDoubleSpinBox->setMaximum( 100000.0); exclusiveSetRangeToZeroMinValueDoubleSpinBox->setSingleStep(1.0); exclusiveSetRangeToZeroMinValueDoubleSpinBox->setDecimals(3); exclusiveSetRangeToZeroMinValueDoubleSpinBox->setValue(0.0); exclusiveSetRangeToZeroMinValueDoubleSpinBox->setToolTip( "Minimum value for range."); exclusiveSetRangeToZeroMaxValueDoubleSpinBox = new QDoubleSpinBox; exclusiveSetRangeToZeroMaxValueDoubleSpinBox->setMinimum(-100000.0); exclusiveSetRangeToZeroMaxValueDoubleSpinBox->setMaximum( 100000.0); exclusiveSetRangeToZeroMaxValueDoubleSpinBox->setSingleStep(1.0); exclusiveSetRangeToZeroMaxValueDoubleSpinBox->setDecimals(3); exclusiveSetRangeToZeroMaxValueDoubleSpinBox->setValue(0.0); exclusiveSetRangeToZeroMaxValueDoubleSpinBox->setToolTip( "Maximum value for range."); operationsGridLayout->addWidget(exclusiveSetRangeToZeroRadioButton, rowCount, 0); operationsGridLayout->addWidget(exclusiveSetRangeToZeroMinValueDoubleSpinBox, rowCount, 1); operationsGridLayout->addWidget(exclusiveSetRangeToZeroMaxValueDoubleSpinBox, rowCount, 2); rowCount++; normalizeValuesRadioButton = NULL; if (volumeFlag == false) { normalizeValuesRadioButton = new QRadioButton("Normalize " + idName + " A"); operationsButtonGroup->addButton(normalizeValuesRadioButton, opNum++); normalizeValuesRadioButton->setToolTip( "Redistributes values so that they fit\n" "a normal distribution. The data's median\n" "value is mapped to the mean value of the\n" "normal distribution."); normalizeMeanDoubleSpinBox = new QDoubleSpinBox; normalizeMeanDoubleSpinBox->setMinimum(-10000.0); normalizeMeanDoubleSpinBox->setMaximum( 10000.0); normalizeMeanDoubleSpinBox->setSingleStep(1.0); normalizeMeanDoubleSpinBox->setDecimals(3); normalizeMeanDoubleSpinBox->setValue(0.0); normalizeMeanDoubleSpinBox->setToolTip( "Mean of Normal Distribution"); normalizeDeviationDoubleSpinBox = new QDoubleSpinBox; normalizeDeviationDoubleSpinBox->setMinimum(-10000.0); normalizeDeviationDoubleSpinBox->setMaximum( 10000.0); normalizeDeviationDoubleSpinBox->setSingleStep(1.0); normalizeDeviationDoubleSpinBox->setDecimals(3); normalizeDeviationDoubleSpinBox->setValue(1.0); normalizeDeviationDoubleSpinBox->setToolTip( "Deviation of Normal Distribution"); operationsGridLayout->addWidget(normalizeValuesRadioButton, rowCount, 0); operationsGridLayout->addWidget(normalizeMeanDoubleSpinBox, rowCount, 1); operationsGridLayout->addWidget(normalizeDeviationDoubleSpinBox, rowCount, 2); rowCount++; } // // 1.0 - value // oneMinusValueRadioButton = new QRadioButton("1.0 - value in " + idName + " A"); operationsButtonGroup->addButton(oneMinusValueRadioButton, opNum++); operationsGridLayout->addWidget(oneMinusValueRadioButton, rowCount, 0); rowCount++; operationsWidget->setFixedSize(operationsWidget->sizeHint()); QGroupBox* operationsGroupBox = new QGroupBox("Operations"); QVBoxLayout* operationsLayout = new QVBoxLayout(operationsGroupBox); QScrollArea* scrollArea = new QScrollArea; scrollArea->setWidget(operationsWidget); scrollArea->setWidgetResizable(true); operationsLayout->addWidget(scrollArea); return operationsGroupBox; } /** * called when an operations radio button is selected. */ void GuiDataFileMathDialog::slotOperationsButtonGroup() { bool enableColumnB = true; if (multiplyColumnByScalarRadioButton->isChecked() || addScalarToColumnRadioButton->isChecked() || ceilingColumnByScalarRadioButton->isChecked() || floorColumnByScalarRadioButton->isChecked() || fixNaNRadioButton->isChecked() || absValueRadioButton->isChecked() || inclusiveSetRangeToZeroRadioButton->isChecked() || exclusiveSetRangeToZeroRadioButton->isChecked()) { enableColumnB = false; } else if (copyVolumeRadioButton != NULL) { if (copyVolumeRadioButton->isChecked()) { enableColumnB = false; } } else if (normalizeValuesRadioButton != NULL) { if (normalizeValuesRadioButton->isChecked()) { enableColumnB = false; } } switch (dialogMode) { case DIALOG_MODE_METRIC_FILE: case DIALOG_MODE_SURFACE_SHAPE_FILE: inputMetricColumnComboBoxB->setEnabled(enableColumnB); inputMetricColumnLabelB->setEnabled(enableColumnB); break; case DIALOG_MODE_VOLUME_FILE: volumeBGroupBox->setEnabled(enableColumnB); break; } } /** * create the volume part of the dialog. */ QWidget* GuiDataFileMathDialog::createVolumePartOfDialog() { QWidget* volumeWidget = new QWidget; QVBoxLayout* volumeLayout = new QVBoxLayout(volumeWidget); // // Volume A // QGroupBox* volumeAGroupBox = new QGroupBox("Volume A"); QVBoxLayout* volumeALayout = new QVBoxLayout(volumeAGroupBox); volumeASelectionControl = new GuiVolumeSelectionControl(0, true, true, true, true, true, true, true, GuiVolumeSelectionControl::LABEL_MODE_FILE_LABEL_AND_NAME, "volumeASelectionControl", false, false, false); volumeALayout->addWidget(volumeASelectionControl); volumeLayout->addWidget(volumeAGroupBox); // // Volume B // volumeBGroupBox = new QGroupBox("Volume B"); QVBoxLayout* volumeBLayout = new QVBoxLayout(volumeBGroupBox); volumeBSelectionControl = new GuiVolumeSelectionControl(0, true, true, true, true, true, true, true, GuiVolumeSelectionControl::LABEL_MODE_FILE_LABEL_AND_NAME, "volumeASelectionControl", false, false, false); volumeBLayout->addWidget(volumeBSelectionControl); volumeLayout->addWidget(volumeBGroupBox); // // Output Volume // QGroupBox* volumeCGroupBox = new QGroupBox("Volume Output"); QVBoxLayout* volumeCLayout = new QVBoxLayout(volumeCGroupBox); volumeOutputSelectionControl = new GuiVolumeSelectionControl(0, true, true, true, true, true, true, true, GuiVolumeSelectionControl::LABEL_MODE_FILE_LABEL_AND_NAME, "volumeOutputSelectionControl", true, true, true); volumeCLayout->addWidget(volumeOutputSelectionControl); volumeLayout->addWidget(volumeCGroupBox); return volumeWidget; } /** * create the metric column part of the dialog. */ QWidget* GuiDataFileMathDialog::createMetricColumnPartOfDialog() { GUI_NODE_FILE_TYPE nodeFileType = GUI_NODE_FILE_TYPE_NONE; QString title; switch (dialogMode) { case DIALOG_MODE_METRIC_FILE: nodeFileType = GUI_NODE_FILE_TYPE_METRIC; title = "Metric Columns"; break; case DIALOG_MODE_SURFACE_SHAPE_FILE: nodeFileType = GUI_NODE_FILE_TYPE_SURFACE_SHAPE; title = "Shape Columns"; break; case DIALOG_MODE_VOLUME_FILE: title = ""; break; } QGroupBox* columnGroupBox = new QGroupBox(title); QGridLayout* columnGridLayout = new QGridLayout(columnGroupBox); int rowCount = 0; // // input metric column "A" // columnGridLayout->addWidget(new QLabel("Column A"), rowCount, 0); inputMetricColumnComboBoxA = new GuiNodeAttributeColumnSelectionComboBox( nodeFileType, false, false, false); columnGridLayout->addWidget(inputMetricColumnComboBoxA, rowCount, 1); rowCount++; // // input metric column "B" // inputMetricColumnLabelB = new QLabel("Column B"); columnGridLayout->addWidget(inputMetricColumnLabelB, rowCount, 0); inputMetricColumnComboBoxB = new GuiNodeAttributeColumnSelectionComboBox( nodeFileType, false, false, false); columnGridLayout->addWidget(inputMetricColumnComboBoxB, rowCount, 1); rowCount++; // // output metric column // columnGridLayout->addWidget(new QLabel("Result"), rowCount, 0); outputMetricColumnComboBox = new GuiNodeAttributeColumnSelectionComboBox( nodeFileType, true, false, false); columnGridLayout->addWidget(outputMetricColumnComboBox, rowCount, 1); QObject::connect(outputMetricColumnComboBox, SIGNAL(itemSelected(int)), this, SLOT(slotOutputMetricColumnComboBox())); outputMetricColumnComboBox->setCurrentIndex( GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NEW); outputMetricNameLineEdit = new QLineEdit; columnGridLayout->addWidget(outputMetricNameLineEdit, rowCount, 2); return columnGroupBox; } /** * get the data file since. */ MetricFile* GuiDataFileMathDialog::getNodeDataFile() { BrainSet* bs = theMainWindow->getBrainSet(); MetricFile* mf = NULL; switch (dialogMode) { case DIALOG_MODE_METRIC_FILE: mf = bs->getMetricFile(); break; case DIALOG_MODE_SURFACE_SHAPE_FILE: mf = bs->getSurfaceShapeFile(); break; case DIALOG_MODE_VOLUME_FILE: break; } return mf; } /** * called when output column selected. */ void GuiDataFileMathDialog::slotOutputMetricColumnComboBox() { const int metricColumn = outputMetricColumnComboBox->currentIndex(); if ((metricColumn >= 0) && (metricColumn < getNodeDataFile()->getNumberOfColumns())) { outputMetricNameLineEdit->setText(getNodeDataFile()->getColumnName(metricColumn)); } else { outputMetricNameLineEdit->setText("New Column Name"); } } caret-5.6.4~dfsg.1.orig/caret/GuiDataFileImportOptionsDialog.h0000664000175000017500000001047011572067322024037 0ustar michaelmichael #ifndef __GUI_DATA_FILE_IMPORT_OPTIONS_DIALOG_H__ #define __GUI_DATA_FILE_IMPORT_OPTIONS_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelSurface.h" #include "Structure.h" #include "TopologyFile.h" #include "VolumeFile.h" #include "WuQDialog.h" class GuiStructureComboBox; class GuiSurfaceTypeComboBox; class GuiTopologyTypeComboBox; class GuiVolumeTypeComboBox; class GuiVolumeVoxelDataTypeComboBox; class QCheckBox; class QComboBox; class QSpinBox; /// dialog for setting options for importing files class GuiDataFileImportOptionsDialog : public WuQDialog { Q_OBJECT public: // constructor GuiDataFileImportOptionsDialog(QWidget* parent, const QString& filterName); // destructor ~GuiDataFileImportOptionsDialog(); // get the contour options void getContourOptions(bool& importContours, bool& importCells) const; // get the surface options void getSurfaceOptions(Structure::STRUCTURE_TYPE& structureType, bool& importTopology, TopologyFile::TOPOLOGY_TYPES& topologyType, bool& importCoordinates, BrainModelSurface::SURFACE_TYPES& coordinateType, bool& importColorsAsPaint, bool& importColorsAsRgbPaint); // get the volume options void getVolumeOptions(VolumeFile::VOLUME_TYPE& volumeType, int dimensions[3], VolumeFile::VOXEL_DATA_TYPE& voxelDataType, bool& byteSwap); protected: // create the contours options widget QWidget* createContourOptionsWidget(const QString& filterName); // create the surface options widget QWidget* createSurfaceOptionsWidget(const QString& filterName); // create the volume options widget QWidget* createVolumeOptionsWidget(const QString& filterName); /// import as structure combo box GuiStructureComboBox* structureComboBox; /// import topology check box QCheckBox* importTopologyCheckBox; /// import coordinates check box QCheckBox* importCoordinatesCheckBox; /// import colors as paint/area colors QCheckBox* importPaintAreaColorsCheckBox; /// import colors as RGB Paint QCheckBox* importRgbColorsCheckBox; /// combo box for volume type GuiVolumeTypeComboBox* volumeTypeComboBox; /// raw volume dimension X spin box QSpinBox* volumeDimXSpinBox; /// raw volume dimension Y spin box QSpinBox* volumeDimYSpinBox; /// raw volume dimension Z spin box QSpinBox* volumeDimZSpinBox; // raw volume voxel data type combo box GuiVolumeVoxelDataTypeComboBox* volumeVoxelDataTypeComboBox; /// raw volume byte swap combo box QComboBox* volumeByteSwapComboBox; /// import contours check box QCheckBox* importContoursCheckBox; /// import contour cells check box QCheckBox* importContourCellsCheckBox; /// surface type combo box GuiSurfaceTypeComboBox* surfaceTypeComboBox; /// topology type combo box GuiTopologyTypeComboBox* topologyTypeComboBox; }; #endif // __GUI_DATA_FILE_IMPORT_OPTIONS_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiDataFileImportOptionsDialog.cxx0000664000175000017500000003561411572067322024421 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include "FileFilters.h" #include "GuiDataFileImportOptionsDialog.h" #include "GuiStructureComboBox.h" #include "GuiSurfaceTypeComboBox.h" #include "GuiTopologyTypeComboBox.h" #include "GuiVolumeTypeComboBox.h" #include "GuiVolumeVoxelDataTypeComboBox.h" /** * constructor. */ GuiDataFileImportOptionsDialog::GuiDataFileImportOptionsDialog(QWidget* parent, const QString& filterName) : WuQDialog(parent) { QVBoxLayout* layout = new QVBoxLayout(this); if (filterName == FileFilters::getAnalyzeVolumeFileFilter()) { layout->addWidget(createVolumeOptionsWidget(filterName)); } else if (filterName == FileFilters::getBrainVoyagerFileFilter()) { layout->addWidget(createSurfaceOptionsWidget(filterName)); } else if (filterName == FileFilters::getByuSurfaceFileFilter()) { layout->addWidget(createSurfaceOptionsWidget(filterName)); } else if (filterName == FileFilters::getFreeSurferAsciiSurfaceFileFilter()) { layout->addWidget(createSurfaceOptionsWidget(filterName)); } else if (filterName == FileFilters::getFreeSurferBinarySurfaceFileFilter()) { layout->addWidget(createSurfaceOptionsWidget(filterName)); } else if (filterName == FileFilters::getMdPlotFileFilter()) { layout->addWidget(createContourOptionsWidget(filterName)); } #ifdef HAVE_MINC else if (filterName == FileFilters::getMincVolumeFileFilter()) { layout->addWidget(createVolumeOptionsWidget(filterName)); } #endif // HAVE_MINC else if (filterName == FileFilters::getMniObjSurfaceFileFilter()) { layout->addWidget(createSurfaceOptionsWidget(filterName)); } else if (filterName == FileFilters::getNeurolucidaFileFilter()) { layout->addWidget(createContourOptionsWidget(filterName)); } else if (filterName == FileFilters::getRawVolumeFileFilter()) { layout->addWidget(createVolumeOptionsWidget(filterName)); } else if (filterName == FileFilters::getStlSurfaceFileFilter()) { layout->addWidget(createSurfaceOptionsWidget(filterName)); } else if (filterName == FileFilters::getSumaRgbFileFilter()) { layout->addWidget(createSurfaceOptionsWidget(filterName)); } else if (filterName == FileFilters::getVtkSurfaceFileFilter()) { layout->addWidget(createSurfaceOptionsWidget(filterName)); } else if (filterName == FileFilters::getVtkXmlSurfaceFileFilter()) { layout->addWidget(createSurfaceOptionsWidget(filterName)); } else if (filterName == FileFilters::getVtkVolumeFileFilter()) { layout->addWidget(createVolumeOptionsWidget(filterName)); } else { std::cout << "PROGRAM ERROR: invalid filter (" << filterName.toAscii().constData() << ") passed to GuiDataFileImportOptionsDialog()." << std::endl; } QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); layout->addWidget(buttonBox); QObject::connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); QObject::connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); } /** * destructor. */ GuiDataFileImportOptionsDialog::~GuiDataFileImportOptionsDialog() { } /** * create the contours options widget. */ QWidget* GuiDataFileImportOptionsDialog::createContourOptionsWidget(const QString& filterName) { QString contourLabelName("Import Contours"); QString contourCellLabelName("Import Contour Cells"); if (filterName == FileFilters::getMdPlotFileFilter()) { contourLabelName = "Import MD Plot Lines as Contours"; contourCellLabelName = "Import MD Plot Points as Contour Cells"; } if (filterName == FileFilters::getNeurolucidaFileFilter()) { contourLabelName = "Import Contours"; contourCellLabelName = "Import Markers as Contour Cells"; } // // Contour selections // importContoursCheckBox = new QCheckBox(contourLabelName); importContoursCheckBox->setChecked(true); importContourCellsCheckBox = new QCheckBox(contourCellLabelName); importContourCellsCheckBox->setChecked(true); // // Layout items // QWidget* contourOptionsWidget = new QWidget; QVBoxLayout* layout = new QVBoxLayout(contourOptionsWidget); layout->addWidget(importContoursCheckBox); layout->addWidget(importContourCellsCheckBox); return contourOptionsWidget; } /** * get the contour options. */ void GuiDataFileImportOptionsDialog::getContourOptions(bool& importContours, bool& importCells) const { importContours = importContoursCheckBox->isChecked(); importCells = importContourCellsCheckBox->isChecked(); } /** * create the surface options widget. */ QWidget* GuiDataFileImportOptionsDialog::createSurfaceOptionsWidget(const QString& filterName) { // // Structure selection // QLabel* structureLabel = new QLabel("Structure "); structureComboBox = new GuiStructureComboBox; QWidget* structureWidget = new QWidget; QHBoxLayout* structureLayout = new QHBoxLayout(structureWidget); structureLayout->addWidget(structureLabel); structureLayout->addWidget(structureComboBox); structureLayout->addStretch(); // // Import type selections // importTopologyCheckBox = new QCheckBox("Import Topology"); importTopologyCheckBox->setChecked(true); topologyTypeComboBox = new GuiTopologyTypeComboBox; QWidget* topologyTypeWidget = new QWidget; QHBoxLayout* topologyTypeLayout = new QHBoxLayout(topologyTypeWidget); topologyTypeLayout->addWidget(importTopologyCheckBox); topologyTypeLayout->addWidget(topologyTypeComboBox); topologyTypeLayout->addStretch(); importCoordinatesCheckBox = new QCheckBox("Import Coordinates"); importCoordinatesCheckBox->setChecked(true); surfaceTypeComboBox = new GuiSurfaceTypeComboBox; QWidget* surfaceTypeWidget = new QWidget; QHBoxLayout* surfaceTypeLayout = new QHBoxLayout(surfaceTypeWidget); surfaceTypeLayout->addWidget(importCoordinatesCheckBox); surfaceTypeLayout->addWidget(surfaceTypeComboBox); surfaceTypeLayout->addStretch(); importPaintAreaColorsCheckBox = new QCheckBox("Import Colors as Paint and Area Colors"); importPaintAreaColorsCheckBox->setChecked(true); importRgbColorsCheckBox = new QCheckBox("Import Colors as RGB Paint"); importRgbColorsCheckBox->setChecked(true); QWidget* surfaceOptionsWidget = new QWidget; QVBoxLayout* surfaceGroupLayout = new QVBoxLayout(surfaceOptionsWidget); surfaceGroupLayout->addWidget(structureWidget); surfaceGroupLayout->addWidget(topologyTypeWidget); surfaceGroupLayout->addWidget(surfaceTypeWidget); surfaceGroupLayout->addWidget(importPaintAreaColorsCheckBox); surfaceGroupLayout->addWidget(importRgbColorsCheckBox); bool showStructure = false; bool showTopologyType = false; bool showSurfaceType = false; bool showPaint = false; bool showRgb = false; if (filterName == FileFilters::getBrainVoyagerFileFilter()) { showStructure = true; showTopologyType = true; showSurfaceType = true; showPaint = true; } else if (filterName == FileFilters::getByuSurfaceFileFilter()) { showStructure = true; showTopologyType = true; showSurfaceType = true; } else if (filterName == FileFilters::getFreeSurferAsciiSurfaceFileFilter()) { showStructure = true; showTopologyType = true; showSurfaceType = true; } else if (filterName == FileFilters::getFreeSurferBinarySurfaceFileFilter()) { showStructure = true; showTopologyType = true; showSurfaceType = true; } else if (filterName == FileFilters::getMniObjSurfaceFileFilter()) { showStructure = true; showTopologyType = true; showSurfaceType = true; showRgb = true; } else if (filterName == FileFilters::getStlSurfaceFileFilter()) { showStructure = true; showTopologyType = true; showSurfaceType = true; } else if (filterName == FileFilters::getSumaRgbFileFilter()) { showRgb = true; } else if (filterName == FileFilters::getVtkSurfaceFileFilter()) { showStructure = true; showTopologyType = true; showSurfaceType = true; showRgb = true; } else if (filterName == FileFilters::getVtkXmlSurfaceFileFilter()) { showStructure = true; showTopologyType = true; showSurfaceType = true; showRgb = true; } structureWidget->setVisible(showStructure); topologyTypeWidget->setVisible(showTopologyType); surfaceTypeWidget->setVisible(showSurfaceType); importPaintAreaColorsCheckBox->setVisible(showPaint); importRgbColorsCheckBox->setVisible(showRgb); return surfaceOptionsWidget; } /** * get the surface options. */ void GuiDataFileImportOptionsDialog::getSurfaceOptions(Structure::STRUCTURE_TYPE& structureType, bool& importTopology, TopologyFile::TOPOLOGY_TYPES& topologyType, bool& importCoordinates, BrainModelSurface::SURFACE_TYPES& coordinateType, bool& importColorsAsPaint, bool& importColorsAsRgbPaint) { structureType = structureComboBox->getSelectedStructure(); importTopology = importTopologyCheckBox->isChecked(); topologyType = topologyTypeComboBox->getTopologyType(); importCoordinates = importCoordinatesCheckBox->isChecked(); coordinateType = surfaceTypeComboBox->getSurfaceType(); importColorsAsPaint = importPaintAreaColorsCheckBox->isChecked(); importColorsAsRgbPaint = importRgbColorsCheckBox->isChecked(); } /** * create the volume options widget. */ QWidget* GuiDataFileImportOptionsDialog::createVolumeOptionsWidget(const QString& filterName) { // // Volume selections // QLabel* volumeTypeLabel = new QLabel("Volume Type"); volumeTypeComboBox = new GuiVolumeTypeComboBox; QHBoxLayout* volumeTypeLayout = new QHBoxLayout; volumeTypeLayout->addWidget(volumeTypeLabel); volumeTypeLayout->addWidget(volumeTypeComboBox); volumeTypeLayout->addStretch(); // // Raw volume dimensions // const int rawDimSize = 100; QLabel* volumeDimensionsLabel = new QLabel("Dimensions "); volumeDimXSpinBox = new QSpinBox; volumeDimXSpinBox->setMinimum(0); volumeDimXSpinBox->setMaximum(100000); volumeDimXSpinBox->setSingleStep(1); volumeDimXSpinBox->setFixedWidth(rawDimSize); volumeDimYSpinBox = new QSpinBox; volumeDimYSpinBox->setMinimum(0); volumeDimYSpinBox->setMaximum(100000); volumeDimYSpinBox->setSingleStep(1); volumeDimYSpinBox->setFixedWidth(rawDimSize); volumeDimZSpinBox = new QSpinBox; volumeDimZSpinBox->setFixedWidth(rawDimSize); volumeDimZSpinBox->setMinimum(0); volumeDimZSpinBox->setMaximum(100000); volumeDimZSpinBox->setSingleStep(1); QWidget* volumeDimensionsWidget = new QWidget; QHBoxLayout* volumeDimensionsLayout = new QHBoxLayout(volumeDimensionsWidget); volumeDimensionsLayout->setSpacing(5); volumeDimensionsLayout->addWidget(volumeDimensionsLabel); volumeDimensionsLayout->addWidget(volumeDimXSpinBox); volumeDimensionsLayout->addWidget(volumeDimYSpinBox); volumeDimensionsLayout->addWidget(volumeDimZSpinBox); volumeDimensionsLayout->addStretch(); // // Raw volume data type // QLabel* volumeVoxelDataTypeLabel = new QLabel("Voxel Data Type"); volumeVoxelDataTypeComboBox = new GuiVolumeVoxelDataTypeComboBox; QWidget* volumeVoxelDataTypeWidget = new QWidget; QHBoxLayout* volumeVoxelDataTypeLayout = new QHBoxLayout(volumeVoxelDataTypeWidget); volumeVoxelDataTypeLayout->addWidget(volumeVoxelDataTypeLabel); volumeVoxelDataTypeLayout->addWidget(volumeVoxelDataTypeComboBox); volumeVoxelDataTypeLayout->addStretch(); // // Raw volume byte swap // QLabel* volumeByteSwapLabel = new QLabel("Byte Swap "); volumeByteSwapComboBox = new QComboBox; volumeByteSwapComboBox->addItem("No"); volumeByteSwapComboBox->addItem("Yes"); QWidget* volumeByteSwapWidget = new QWidget; QHBoxLayout* volumeByteSwapLayout = new QHBoxLayout(volumeByteSwapWidget); volumeByteSwapLayout->addWidget(volumeByteSwapLabel); volumeByteSwapLayout->addWidget(volumeByteSwapComboBox); volumeByteSwapLayout->addStretch(); // // Widget and layout for raw volume options // QWidget* volumeOptionsWidget = new QWidget; QVBoxLayout* volumeLayout = new QVBoxLayout(volumeOptionsWidget); volumeLayout->addLayout(volumeTypeLayout); volumeLayout->addWidget(volumeDimensionsWidget); volumeLayout->addWidget(volumeVoxelDataTypeWidget); volumeLayout->addWidget(volumeByteSwapWidget); const bool showDimensionsDataTypeByteSwap = (filterName == FileFilters::getRawVolumeFileFilter()); volumeDimensionsWidget->setVisible(showDimensionsDataTypeByteSwap); volumeVoxelDataTypeWidget->setVisible(showDimensionsDataTypeByteSwap); volumeByteSwapWidget->setVisible(showDimensionsDataTypeByteSwap); return volumeOptionsWidget; } /** * get the volume options. */ void GuiDataFileImportOptionsDialog::getVolumeOptions(VolumeFile::VOLUME_TYPE& volumeType, int dimensions[3], VolumeFile::VOXEL_DATA_TYPE& voxelDataType, bool& byteSwap) { volumeType = volumeTypeComboBox->getVolumeType(); dimensions[0] = volumeDimXSpinBox->value(); dimensions[1] = volumeDimYSpinBox->value(); dimensions[2] = volumeDimZSpinBox->value(); voxelDataType = volumeVoxelDataTypeComboBox->getVolumeVoxelDataType(); byteSwap = (volumeByteSwapComboBox->currentIndex() != 0); } caret-5.6.4~dfsg.1.orig/caret/GuiDataFileCommentDialog.h0000664000175000017500000001336311572067322022617 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_DATA_FILE_COMMENT_DIALOG_H__ #define __GUI_DATA_FILE_COMMENT_DIALOG_H__ #include #include "AbstractFile.h" #include "WuQDialog.h" class AbstractFileHeaderUpdater; class BrainModelBorderFileInfo; class GuiHyperLinkTextBrowser; class GiftiNodeDataFile; class NodeAttributeFile; class QGridLayout; class QLineEdit; class QTabWidget; class QTextEdit; class RgbPaintFile; class VolumeFile; /// Dialog that displays a scrolling text widget class GuiDataFileCommentDialog : public WuQDialog { Q_OBJECT public: /// Constructor for an Abstract File subclass in memory GuiDataFileCommentDialog(QWidget* parent, AbstractFile* af); /// Constructor for an RGB Paint File Column Color in memory GuiDataFileCommentDialog(QWidget* parent, RgbPaintFile* rgbPaintFileIn, const int rgbPaintColumnIn, const int rgbColorComponentIn); /// The constructor for an AbstractFile subclass in a file. GuiDataFileCommentDialog(QWidget* parent, const QString& fileNameIn); /// The constructor for an VolumeFile in a file. GuiDataFileCommentDialog(QWidget* parent, const QString& fileNameIn, const bool volumeFileFlag); /// Constructor for a Node Attribute File Column subclass in memory GuiDataFileCommentDialog(QWidget* parent, NodeAttributeFile* naf, int nodeAttributeFileColumnIn); /// Constructor for a Node Attribute File Column subclass in memory GuiDataFileCommentDialog(QWidget* parent, GiftiNodeDataFile* naf, int nodeAttributeFileColumnIn); /// Constructor for a BrainModelBorderFileInfo class in memory GuiDataFileCommentDialog(QWidget* parent, BrainModelBorderFileInfo* bfi); /// Destructor ~GuiDataFileCommentDialog(); private slots: /// called to close the dialog void slotCloseDialog(); /// called to edit comment void slotTabWidgetPageChanged(int indx); /// called if a key is pressed in the text browser void slotTextBrowserKeyPress(); private: /// dialog modes enum DIALOG_MODE { DIALOG_MODE_ABSTRACT_FILE_IN_MEMORY, DIALOG_MODE_ABSTRACT_FILE_NAME, DIALOG_MODE_VOLUME_FILE_NAME, DIALOG_MODE_VOLUME_FILE_IN_MEMORY, DIALOG_MODE_NODE_ATTRIBUTE_FILE_COLUMN_IN_MEMORY, DIALOG_MODE_BORDER_FILE_INFO_IN_MEMORY, DIALOG_MODE_RGB_PAINT_FILE_IN_MEMORY }; /// create the dialog in the specified mode void createDialog(const DIALOG_MODE modeIn, const QString& fileName, const std::vector& namesList, const bool viewCommentOnly); /// initialize the dialog void initialize(); /// load the header tag grid void loadHeaderTagGrid(const AbstractFile::AbstractFileHeaderContainer& hc); /// the dialog's mode DIALOG_MODE dialogMode; /// the text display GuiHyperLinkTextBrowser* textBrowser; /// the text editor QTextEdit* textEditor; /// data file being edited AbstractFile* dataFile; /// the tab widget QTabWidget* tabWidget; /// the file being edited //AbstractFileHeaderUpdater* fileHeaderUpdater; AbstractFile* fileHeaderUpdater; /// the gifti node data file being edited GiftiNodeDataFile* giftiNodeDataFile; /// the node attribute file being edited NodeAttributeFile* nodeAttributeFile; /// the node attribute file column int nodeAttributeFileColumn; /// header tags grid QGridLayout* headerTagGridLayout; /// node attribute column name line edit QLineEdit* nodeAttributeColumnNameLineEdit; /// brain model border file info in memory BrainModelBorderFileInfo* borderFileInfo; /// volume file for editing volume file on disk VolumeFile* volumeFileOnDisk; /// volume file for editing volume file in memory VolumeFile* volumeFileInMemory; /// volume file label for a volume file in memory QLineEdit* volumeFileLabelLineEdit; /// the rgb paint file RgbPaintFile* rgbPaintFile; /// the rgb paint file column int rgbPaintColumn; /// the rgb paint file column color component int rgbColorComponent; }; #endif // __GUI_DATA_FILE_COMMENT_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiDataFileCommentDialog.cxx0000664000175000017500000007472411572067322023202 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include "AreaColorFile.h" #include "BorderFile.h" #include "BorderColorFile.h" #include "BorderProjectionFile.h" #include "BrainModelBorderSet.h" #include "BrainSet.h" #include "CellColorFile.h" #include "ContourCellColorFile.h" #include "FileUtilities.h" #include "FociColorFile.h" #include "GuiDataFileCommentDialog.h" #include "GuiFilesModified.h" #include "GuiHyperLinkTextBrowser.h" #include "GuiMainWindow.h" #include "NodeAttributeFile.h" #include "PaintFile.h" #include "ParamsFile.h" #include "RgbPaintFile.h" #include "StringUtilities.h" #include "VolumeFile.h" #include "global_variables.h" /** * The constructor for an AbstractFile subclass in memory. */ GuiDataFileCommentDialog::GuiDataFileCommentDialog(QWidget* parent, AbstractFile* af) : WuQDialog(parent) { setAttribute(Qt::WA_DeleteOnClose); initialize(); std::set names; PaintFile* paintFile = dynamic_cast(af); ParamsFile* paramsFile = dynamic_cast(af); volumeFileInMemory = dynamic_cast(af); if (paintFile != NULL) { const int num = paintFile->getNumberOfPaintNames(); for (int i = 0; i < num; i++) { names.insert(paintFile->getPaintNameFromIndex(i)); } } else if (paramsFile != NULL) { std::vector keys, values; paramsFile->getAllParameters(keys, values); const int num = static_cast(keys.size()); for (int i = 0; i < num; i++) { QString s(keys[i]); s.append("="); s.append(values[i]); names.insert(s); } } else if (volumeFileInMemory != NULL) { const int num = volumeFileInMemory->getNumberOfRegionNames(); for (int i = 0; i < num; i++) { names.insert(volumeFileInMemory->getRegionNameFromIndex(i)); } } // // Create the dialog // std::vector namesVector(names.begin(), names.end()); if (volumeFileInMemory != NULL) { createDialog(DIALOG_MODE_VOLUME_FILE_IN_MEMORY, af->getFileName(), namesVector, false); } else { createDialog(DIALOG_MODE_ABSTRACT_FILE_IN_MEMORY, af->getFileName(), namesVector, false); } // // Add volume file label // if (volumeFileInMemory != NULL) { volumeFileLabelLineEdit->setText(volumeFileInMemory->getDescriptiveLabel()); } // // Add comment to the text browser // dataFile = af; if (dataFile != NULL) { textBrowser->setText(dataFile->getFileComment()); textEditor->setPlainText(dataFile->getFileComment()); textEditor->document()->setModified(false); AbstractFile::AbstractFileHeaderContainer afhc = dataFile->getHeader(); loadHeaderTagGrid(afhc); } else { textBrowser->setText("ERROR: Invalid file."); textEditor->setPlainText("ERROR: Invalid file."); } } /** * Constructor for an RGB Paint File Column Color in memory. */ GuiDataFileCommentDialog::GuiDataFileCommentDialog(QWidget* parent, RgbPaintFile* rgbPaintFileIn, const int rgbPaintColumnIn, const int rgbColorComponentIn) : WuQDialog(parent) { setAttribute(Qt::WA_DeleteOnClose); initialize(); rgbPaintFile = rgbPaintFileIn; rgbPaintColumn = rgbPaintColumnIn; rgbColorComponent = rgbColorComponentIn; dataFile = rgbPaintFile; // // Create the dialog // std::vector namesVector; createDialog(DIALOG_MODE_RGB_PAINT_FILE_IN_MEMORY, rgbPaintFile->getFileName(), namesVector, false); // // Add comment to the text browser // QString commentText; switch (rgbColorComponent) { case 0: commentText = rgbPaintFile->getCommentRed(rgbPaintColumn); break; case 1: commentText = rgbPaintFile->getCommentGreen(rgbPaintColumn); break; case 2: commentText = rgbPaintFile->getCommentBlue(rgbPaintColumn); break; } textBrowser->setText(commentText); textEditor->setPlainText(commentText); textEditor->document()->setModified(false); } /** * Constructor for a BrainModelBorderFileInfo class in memory. */ GuiDataFileCommentDialog::GuiDataFileCommentDialog(QWidget* parent, BrainModelBorderFileInfo* bfi) : WuQDialog(parent) { setAttribute(Qt::WA_DeleteOnClose); initialize(); // // list the border names // BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); QString numBorderString("Number of Borders: "); numBorderString.append(StringUtilities::fromNumber(bmbs->getNumberOfBorders())); std::vector nameSet; bmbs->getAllBorderNames(nameSet, false); nameSet.insert(nameSet.begin(), numBorderString); // // Create the dialog // createDialog(DIALOG_MODE_BORDER_FILE_INFO_IN_MEMORY, bfi->getFileName(), nameSet, false); // // Add comment to the text browser // borderFileInfo = bfi; if (borderFileInfo != NULL) { textBrowser->setText(borderFileInfo->getFileComment()); textEditor->setPlainText(borderFileInfo->getFileComment()); textEditor->document()->setModified(false); loadHeaderTagGrid(borderFileInfo->getFileHeader()); } else { borderFileInfo = NULL; textBrowser->setText("ERROR: Invalid border file."); textEditor->setPlainText("ERROR: Invalid border file."); } } /** * Constructor for a Node Attribute File Column subclass in memory. */ GuiDataFileCommentDialog::GuiDataFileCommentDialog(QWidget* parent, NodeAttributeFile* naf, int nodeAttributeFileColumnIn) : WuQDialog(parent) { setAttribute(Qt::WA_DeleteOnClose); initialize(); // // Create the dialog // std::vector dummy; createDialog(DIALOG_MODE_NODE_ATTRIBUTE_FILE_COLUMN_IN_MEMORY, naf->getFileName(), dummy, false); // // Add comment to the text browser // nodeAttributeFile = naf; nodeAttributeFileColumn = nodeAttributeFileColumnIn; if (nodeAttributeFile != NULL) { if ((nodeAttributeFileColumn >= 0) && (nodeAttributeFileColumn < naf->getNumberOfColumns())) { textBrowser->setText(nodeAttributeFile->getColumnComment(nodeAttributeFileColumn)); textEditor->setPlainText(nodeAttributeFile->getColumnComment(nodeAttributeFileColumn)); textEditor->document()->setModified(false); nodeAttributeColumnNameLineEdit->setText( nodeAttributeFile->getColumnName(nodeAttributeFileColumn)); } else { nodeAttributeFile = NULL; nodeAttributeFileColumn = -1; textBrowser->setText("ERROR: Invalid column."); textEditor->setPlainText("ERROR: Invalid column."); } } else { textBrowser->setText("ERROR: Invalid file."); textEditor->setPlainText("ERROR: Invalid file."); } } /** * Constructor for a Node Attribute File Column subclass in memory. */ GuiDataFileCommentDialog::GuiDataFileCommentDialog(QWidget* parent, GiftiNodeDataFile* naf, int nodeAttributeFileColumnIn) : WuQDialog(parent) { initialize(); // // Create the dialog // std::vector dummy; createDialog(DIALOG_MODE_NODE_ATTRIBUTE_FILE_COLUMN_IN_MEMORY, naf->getFileName(), dummy, false); // // Add comment to the text browser // giftiNodeDataFile = naf; nodeAttributeFileColumn = nodeAttributeFileColumnIn; if (giftiNodeDataFile != NULL) { if ((nodeAttributeFileColumn >= 0) && (nodeAttributeFileColumn < naf->getNumberOfColumns())) { textBrowser->setText(giftiNodeDataFile->getColumnComment(nodeAttributeFileColumn)); textEditor->setPlainText(giftiNodeDataFile->getColumnComment(nodeAttributeFileColumn)); textEditor->document()->setModified(false); nodeAttributeColumnNameLineEdit->setText( giftiNodeDataFile->getColumnName(nodeAttributeFileColumn)); } else { giftiNodeDataFile = NULL; nodeAttributeFileColumn = -1; textBrowser->setText("ERROR: Invalid column."); textEditor->setPlainText("ERROR: Invalid column."); } } else { textBrowser->setText("ERROR: Invalid file."); textEditor->setPlainText("ERROR: Invalid file."); } } /** * The constructor for an AbstractFile subclass in a file. */ GuiDataFileCommentDialog::GuiDataFileCommentDialog(QWidget* parent, const QString& fileName, const bool volumeFileFlag) : WuQDialog(parent) { initialize(); // // Get the file's extension to see if it is a file that should have its data names listed // int numBorders = -1; std::set dataNames; QString ext("."); ext.append(FileUtilities::filenameExtension(fileName)); if (ext.length() > 1) { if (ext == SpecFile::getAreaColorFileExtension()) { AreaColorFile cf; try { cf.readFile(fileName); const int num = cf.getNumberOfColors(); for (int i = 0; i < num; i++) { const ColorFile::ColorStorage* cs = cf.getColor(i); dataNames.insert(cs->getName()); } } catch (FileException& /*e*/) { } } else if (ext == SpecFile::getBorderColorFileExtension()) { BorderColorFile cf; try { cf.readFile(fileName); const int num = cf.getNumberOfColors(); for (int i = 0; i < num; i++) { const ColorFile::ColorStorage* cs = cf.getColor(i); dataNames.insert(cs->getName()); } } catch (FileException& /*e*/) { } } else if (ext == SpecFile::getCellColorFileExtension()) { CellColorFile cf; try { cf.readFile(fileName); const int num = cf.getNumberOfColors(); for (int i = 0; i < num; i++) { const ColorFile::ColorStorage* cs = cf.getColor(i); dataNames.insert(cs->getName()); } } catch (FileException& /*e*/) { } } else if (ext == SpecFile::getContourCellColorFileExtension()) { ContourCellColorFile cf; try { cf.readFile(fileName); const int num = cf.getNumberOfColors(); for (int i = 0; i < num; i++) { const ColorFile::ColorStorage* cs = cf.getColor(i); dataNames.insert(cs->getName()); } } catch (FileException& /*e*/) { } } else if (ext == SpecFile::getFociColorFileExtension()) { FociColorFile cf; try { cf.readFile(fileName); const int num = cf.getNumberOfColors(); for (int i = 0; i < num; i++) { const ColorFile::ColorStorage* cs = cf.getColor(i); dataNames.insert(cs->getName()); } } catch (FileException& /*e*/) { } } else if (ext == SpecFile::getBorderFileExtension()) { BorderFile bf; try { bf.readFile(fileName); numBorders = bf.getNumberOfBorders(); for (int i = 0; i < numBorders; i++) { const Border* b = bf.getBorder(i); dataNames.insert(b->getName()); } } catch (FileException& /*e*/) { } } else if (ext == SpecFile::getBorderProjectionFileExtension()) { BorderProjectionFile bpf; try { bpf.readFile(fileName); numBorders = bpf.getNumberOfBorderProjections(); for (int i = 0; i < numBorders; i++) { const BorderProjection* bp = bpf.getBorderProjection(i); dataNames.insert(bp->getName()); } } catch (FileException& /*e*/) { } } else if (ext == SpecFile::getPaintFileExtension()) { PaintFile pf; try { pf.readFile(fileName); const int num = pf.getNumberOfPaintNames(); for (int i = 0; i < num; i++) { dataNames.insert(pf.getPaintNameFromIndex(i)); } } catch (FileException& /*e*/) { } } else if (ext == SpecFile::getParamsFileExtension()) { ParamsFile pf; try { pf.readFile(fileName); std::vector keys, values; pf.getAllParameters(keys, values); const int num = static_cast(keys.size()); for (int i = 0; i < num; i++) { QString s(keys[i]); s.append("="); s.append(values[i]); dataNames.insert(s); } } catch (FileException& e) { } } } // // Create the dialog // std::vector dataVector(dataNames.begin(), dataNames.end()); if (numBorders >= 0) { QString numString("Number of Borders: " ); numString.append(StringUtilities::fromNumber(numBorders)); dataVector.insert(dataVector.begin(), numString); } if (volumeFileFlag) { createDialog(DIALOG_MODE_VOLUME_FILE_NAME, fileName, dataVector, false); } else { createDialog(DIALOG_MODE_ABSTRACT_FILE_NAME, fileName, dataVector, false); } QFileInfo fileInfo(fileName); bool invalidFile = false; QString invalidFileMessage; // // Make sure the file exists // if (fileInfo.exists() == false) { invalidFile = true; invalidFileMessage = fileName; invalidFileMessage.append(" not found!"); } // // Make sure the file is readable // else if (fileInfo.isReadable() == false) { invalidFile = true; invalidFileMessage = fileName; invalidFileMessage.append(" is not readable.\nCheck file permissions!"); } else if (volumeFileFlag == false) { if (fileInfo.isWritable() == false) { invalidFile = true; invalidFileMessage = fileName; invalidFileMessage.append(" is not writable."); } } // // Add comment to the text browser // if (invalidFile == false) { if (volumeFileFlag) { try { volumeFileOnDisk = new VolumeFile; volumeFileOnDisk->readFile(fileName, VolumeFile::VOLUME_READ_HEADER_ONLY); textBrowser->setText(volumeFileOnDisk->getFileComment()); textEditor->setPlainText(volumeFileOnDisk->getFileComment()); textEditor->document()->setModified(false); } catch (FileException& e) { textBrowser->setText(e.whatQString()); textEditor->setPlainText(e.whatQString()); delete volumeFileOnDisk; volumeFileOnDisk = NULL; } } else { /* fileHeaderUpdater = new AbstractFileHeaderUpdater(); try { fileHeaderUpdater->readFile(fileName); textBrowser->setText(fileHeaderUpdater->getFileComment()); textEditor->setPlainText(fileHeaderUpdater->getFileComment()); textEditor->document()->setModified(false); AbstractFile::AbstractFileHeaderContainer afhc = fileHeaderUpdater->getHeader(); loadHeaderTagGrid(afhc); } catch (FileException& e) { delete fileHeaderUpdater; fileHeaderUpdater = NULL; textBrowser->setText(e.whatQString()); textEditor->setPlainText(e.whatQString()); } */ QString msg; fileHeaderUpdater = AbstractFile::readAnySubClassDataFile(fileName, true, msg); if (fileHeaderUpdater != NULL) { textBrowser->setText(fileHeaderUpdater->getFileComment()); textEditor->setPlainText(fileHeaderUpdater->getFileComment()); textEditor->document()->setModified(false); AbstractFile::AbstractFileHeaderContainer afhc = fileHeaderUpdater->getHeader(); loadHeaderTagGrid(afhc); } } } else { textBrowser->setText(invalidFileMessage); textEditor->setPlainText(invalidFileMessage); } } /** * initialize the dialog. */ void GuiDataFileCommentDialog::initialize() { dataFile = NULL; fileHeaderUpdater = NULL; nodeAttributeFile = NULL; nodeAttributeFileColumn = -1; volumeFileOnDisk = NULL; volumeFileInMemory = NULL; volumeFileLabelLineEdit = NULL; } /** * Create the dialog. */ void GuiDataFileCommentDialog::createDialog(const DIALOG_MODE modeIn, const QString& fileName, const std::vector& namesList, const bool viewCommentOnly) { dialogMode = modeIn; resize(400, 200); QString caption("Comment Editor - "); caption.append(FileUtilities::basename(fileName)); setWindowTitle(caption); QVBoxLayout* rows = new QVBoxLayout(this); rows->setMargin(5); nodeAttributeColumnNameLineEdit = NULL; volumeFileLabelLineEdit = NULL; switch (dialogMode) { case DIALOG_MODE_ABSTRACT_FILE_IN_MEMORY: break; case DIALOG_MODE_ABSTRACT_FILE_NAME: break; case DIALOG_MODE_VOLUME_FILE_NAME: break; case DIALOG_MODE_VOLUME_FILE_IN_MEMORY: { QHBoxLayout* labelLayout = new QHBoxLayout; labelLayout->setSpacing(3); rows->addLayout(labelLayout); labelLayout->addWidget(new QLabel("Label: "), 0); volumeFileLabelLineEdit = new QLineEdit; labelLayout->addWidget(volumeFileLabelLineEdit, 100); } break; case DIALOG_MODE_NODE_ATTRIBUTE_FILE_COLUMN_IN_MEMORY: { QHBoxLayout* columnNameLayout = new QHBoxLayout; columnNameLayout->setSpacing(3); rows->addLayout(columnNameLayout); columnNameLayout->addWidget(new QLabel("Column Name: "), 0); nodeAttributeColumnNameLineEdit = new QLineEdit; columnNameLayout->addWidget(nodeAttributeColumnNameLineEdit, 100); } break; case DIALOG_MODE_BORDER_FILE_INFO_IN_MEMORY: break; case DIALOG_MODE_RGB_PAINT_FILE_IN_MEMORY: break; } // // Tab widget to hold viewer and editor // tabWidget = new QTabWidget; rows->addWidget(tabWidget); QObject::connect(tabWidget, SIGNAL(currentChanged(int)), this, SLOT(slotTabWidgetPageChanged(int))); // // Create the text browser that allows hyperlinks (read only) // textBrowser = new GuiHyperLinkTextBrowser(0); tabWidget->blockSignals(true); tabWidget->addTab(textBrowser, "View Comment"); tabWidget->blockSignals(false); textBrowser->setReadOnly(true); QObject::connect(textBrowser, SIGNAL(keyPressed()), this, SLOT(slotTextBrowserKeyPress())); // // Create the text editor for editing the comment // textEditor = new QTextEdit; tabWidget->blockSignals(true); tabWidget->addTab(textEditor, "Edit Comment"); tabWidget->blockSignals(false); if (viewCommentOnly) { tabWidget->setTabEnabled(tabWidget->indexOf(textEditor), false); } // // Create the grid for viewing header tags // headerTagGridLayout = NULL; switch (dialogMode) { case DIALOG_MODE_ABSTRACT_FILE_IN_MEMORY: case DIALOG_MODE_ABSTRACT_FILE_NAME: case DIALOG_MODE_VOLUME_FILE_NAME: case DIALOG_MODE_VOLUME_FILE_IN_MEMORY: case DIALOG_MODE_BORDER_FILE_INFO_IN_MEMORY: { QWidget* vbox = new QWidget; headerTagGridLayout = new QGridLayout(vbox); tabWidget->blockSignals(true); tabWidget->addTab(vbox, "Header"); tabWidget->blockSignals(false); if (viewCommentOnly) { tabWidget->setTabEnabled(tabWidget->indexOf(vbox), false); } } break; case DIALOG_MODE_NODE_ATTRIBUTE_FILE_COLUMN_IN_MEMORY: break; case DIALOG_MODE_RGB_PAINT_FILE_IN_MEMORY: break; } if (namesList.empty() == false) { QListWidget* lb = new QListWidget; tabWidget->blockSignals(true); tabWidget->addTab(lb, "Names"); tabWidget->blockSignals(false); for (std::vector::const_iterator iter = namesList.begin(); iter != namesList.end(); iter++) { lb->addItem(*iter); } } // // Close Button // QHBoxLayout* buttonsLayout = new QHBoxLayout; rows->addLayout(buttonsLayout); QPushButton* closeButton = new QPushButton("Close"); closeButton->setFixedSize(closeButton->sizeHint()); buttonsLayout->addWidget(closeButton); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(slotCloseDialog())); } /** * The destructor. */ GuiDataFileCommentDialog::~GuiDataFileCommentDialog() { if (fileHeaderUpdater != NULL) { delete fileHeaderUpdater; } if (volumeFileOnDisk != NULL) { delete volumeFileOnDisk; volumeFileOnDisk = NULL; } } /** * Load the header tag grid */ void GuiDataFileCommentDialog::loadHeaderTagGrid(const AbstractFile::AbstractFileHeaderContainer& hc) { if (headerTagGridLayout != NULL) { for (AbstractFile::AbstractFileHeaderContainer::const_iterator iter = hc.begin(); iter != hc.end(); iter++) { if (iter->first != AbstractFile::getHeaderTagComment()) { const int rowNum = headerTagGridLayout->rowCount(); headerTagGridLayout->addWidget(new QLabel(iter->first), rowNum, 0); headerTagGridLayout->addWidget(new QLabel(iter->second), rowNum, 1); } } //headerTagGridLayout->setFixedSize(headerTagGridLayout->sizeHint()); } } /** * Called when edit button pressed. */ void GuiDataFileCommentDialog::slotCloseDialog() { switch (dialogMode) { case DIALOG_MODE_ABSTRACT_FILE_IN_MEMORY: if (dataFile != NULL) { if (textEditor->document()->isModified()) { dataFile->setFileComment(textEditor->toPlainText()); } } break; case DIALOG_MODE_ABSTRACT_FILE_NAME: if (textEditor->document()->isModified()) { if (fileHeaderUpdater != NULL) { const QString name = fileHeaderUpdater->getFileName(); QString msg; AbstractFile* file = AbstractFile::readAnySubClassDataFile(name, false, msg); if (file != NULL) { file->setFileComment(textEditor->toPlainText()); file->setFileWriteType(file->getFileReadType()); try { file->writeFile(name); } catch (FileException& e) { throw FileException(name, "Unable to write"); } } } } break; case DIALOG_MODE_VOLUME_FILE_IN_MEMORY: if (volumeFileInMemory != NULL) { bool modified = false; if (textEditor->document()->isModified()) { volumeFileInMemory->setFileComment(textEditor->toPlainText()); modified = true; } if (volumeFileLabelLineEdit->isModified()) { volumeFileInMemory->setDescriptiveLabel(volumeFileLabelLineEdit->text()); modified = true; } if (modified) { GuiFilesModified fm; fm.setVolumeModified(); theMainWindow->fileModificationUpdate(fm); } } break; case DIALOG_MODE_VOLUME_FILE_NAME: if (volumeFileOnDisk != NULL) { if (textEditor->document()->isModified()) { std::vector volumes; try { //volumeFileOnDisk->setFileComment(textEditor->toPlainText()); //volumeFileOnDisk->writeVolumeHeader(volumeFileOnDisk->getFileName()); //VolumeFile vf; //vf.readFile(volumeFileOnDisk->getFileName(), // VolumeFile::VOLUME_READ_SELECTION_ALL); //vf.setFileComment(textEditor->toPlainText()); //vf.writeFile(volumeFileOnDisk->getFileName()); // // Read as multi-brick since it may be a multi-brick volume // VolumeFile::readFile(volumeFileOnDisk->getFileName(), VolumeFile::VOLUME_READ_SELECTION_ALL, volumes); if (volumes.size() > 0) { volumes[0]->setFileComment(textEditor->toPlainText()); VolumeFile::writeFile(volumeFileOnDisk->getFileName(), volumeFileOnDisk->getVolumeType(), volumeFileOnDisk->getVoxelDataType(), volumes, volumeFileOnDisk->getDataFileWasZipped()); } else { QString msg("No volume data read from "); msg.append(FileUtilities::basename(volumeFileOnDisk->getFileName())); QMessageBox::critical(this, "ERROR", msg); } } catch (FileException& e) { QString msg("Unable to save "); msg.append(FileUtilities::basename(volumeFileOnDisk->getFileName())); msg.append("\n"); msg.append(e.whatQString()); QMessageBox::critical(this, "ERROR", msg); } for (unsigned int i = 0; i < volumes.size(); i++) { delete volumes[i]; } } } break; case DIALOG_MODE_NODE_ATTRIBUTE_FILE_COLUMN_IN_MEMORY: if (nodeAttributeFile != NULL) { if (nodeAttributeColumnNameLineEdit->isModified()) { nodeAttributeFile->setColumnName(nodeAttributeFileColumn, nodeAttributeColumnNameLineEdit->text()); GuiFilesModified fm; fm.setArealEstimationModified(); fm.setLatLonModified(); fm.setMetricModified(); fm.setProbabilisticAtlasModified(); fm.setRgbPaintModified(); fm.setSectionModified(); fm.setSurfaceShapeModified(); fm.setTopographyModified(); theMainWindow->fileModificationUpdate(fm); } if (textEditor->document()->isModified()) { nodeAttributeFile->setColumnComment(nodeAttributeFileColumn, textEditor->toPlainText()); } } else if (giftiNodeDataFile != NULL) { if (nodeAttributeColumnNameLineEdit->isModified()) { giftiNodeDataFile->setColumnName(nodeAttributeFileColumn, nodeAttributeColumnNameLineEdit->text()); GuiFilesModified fm; fm.setArealEstimationModified(); fm.setLatLonModified(); fm.setMetricModified(); fm.setProbabilisticAtlasModified(); fm.setRgbPaintModified(); fm.setSectionModified(); fm.setSurfaceShapeModified(); fm.setTopographyModified(); theMainWindow->fileModificationUpdate(fm); } if (textEditor->document()->isModified()) { giftiNodeDataFile->setColumnComment(nodeAttributeFileColumn, textEditor->toPlainText()); } } break; case DIALOG_MODE_BORDER_FILE_INFO_IN_MEMORY: if (borderFileInfo != NULL) { if (textEditor->document()->isModified()) { borderFileInfo->setFileComment(textEditor->toPlainText()); } } break; case DIALOG_MODE_RGB_PAINT_FILE_IN_MEMORY: if (rgbPaintFile != NULL) { if (rgbPaintColumn >= 0) { switch (rgbColorComponent) { case 0: rgbPaintFile->setCommentRed(rgbPaintColumn, textEditor->toPlainText()); break; case 1: rgbPaintFile->setCommentGreen(rgbPaintColumn, textEditor->toPlainText()); break; case 2: rgbPaintFile->setCommentBlue(rgbPaintColumn, textEditor->toPlainText()); break; } } } break; } QDialog::close(); } /** * Called when edit button pressed. */ void GuiDataFileCommentDialog::slotTabWidgetPageChanged(int indx) { QWidget* page = tabWidget->widget(indx); if (page == textBrowser) { if (textEditor->document()->isModified()) { textBrowser->clear(); textBrowser->setText(textEditor->toPlainText()); } } } /** * Called if a key is pressed. */ void GuiDataFileCommentDialog::slotTextBrowserKeyPress() { QMessageBox::information(this, "Information", "Press the \"Edit Comment\" tab to edit the comment."); } caret-5.6.4~dfsg.1.orig/caret/GuiCurrentColoringToRgbPaintDialog.h0000664000175000017500000000357411572067322024677 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_CURRENT_COLORING_TO_RGB_PAINT_DIALOG_H__ #define __GUI_CURRENT_COLORING_TO_RGB_PAINT_DIALOG_H__ #include "WuQDialog.h" class GuiNodeAttributeColumnSelectionComboBox; class QLineEdit; /// Dialog for copying current coloring to RGB paint class GuiCurrentColoringToRgbPaintDialog : public WuQDialog { Q_OBJECT public: /// constructor GuiCurrentColoringToRgbPaintDialog(QWidget* parent); /// destructor ~GuiCurrentColoringToRgbPaintDialog(); private slots: /// called when an rgb paint column is selected void slotRgbPaintColumnSelection(int col); /// called when dialog is being closed void done(int r); private: /// column name line edit QLineEdit* columnNameLineEdit; /// rgb paint column selection; GuiNodeAttributeColumnSelectionComboBox* rgbColumnComboBox; /// comment line edit QLineEdit* commentLineEdit; }; #endif // __GUI_CURRENT_COLORING_TO_RGB_PAINT_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiCurrentColoringToRgbPaintDialog.cxx0000664000175000017500000001356611572067322025254 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "BrainModelSurfaceNodeColoring.h" #include "BrainSet.h" #include "DisplaySettingsRgbPaint.h" #include "GuiBrainModelOpenGL.h" #include "GuiCurrentColoringToRgbPaintDialog.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "GuiNodeAttributeColumnSelectionComboBox.h" #include "QtUtilities.h" #include "RgbPaintFile.h" #include "global_variables.h" /** * Constructor. */ GuiCurrentColoringToRgbPaintDialog::GuiCurrentColoringToRgbPaintDialog(QWidget* parent) : WuQDialog(parent) { setModal(true); setWindowTitle("Copy Current Coloring to RGB Paint"); // // Vertical box layout of all items // QVBoxLayout* rows = new QVBoxLayout(this); rows->setMargin(2); rows->setSpacing(3); // // Horizontal box for column selection and name // QHBoxLayout* columnLayout = new QHBoxLayout; rows->addLayout(columnLayout); columnLayout->setSpacing(5); columnLayout->addWidget(new QLabel("Column", this)); rgbColumnComboBox = new GuiNodeAttributeColumnSelectionComboBox( GUI_NODE_FILE_TYPE_RGB_PAINT, true, false, false); QObject::connect(rgbColumnComboBox, SIGNAL(itemSelected(int)), this, SLOT(slotRgbPaintColumnSelection(int))); columnLayout->addWidget(rgbColumnComboBox); columnNameLineEdit = new QLineEdit(this); columnNameLineEdit->setText("New Column Name"); columnLayout->addWidget(columnNameLineEdit); // // Horizontal box for comment // QHBoxLayout* commentLayout = new QHBoxLayout; rows->addLayout(commentLayout); commentLayout->setSpacing(5); commentLayout->addWidget(new QLabel("Comment", this)); commentLineEdit = new QLineEdit(this); commentLayout->addWidget(commentLineEdit); // // initialize column selection // rgbColumnComboBox->setCurrentIndex(GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NONE); // // // Dialog Buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; rows->addLayout(buttonsLayout); // // OK button // QPushButton* okButton = new QPushButton("OK"); okButton->setAutoDefault(false); QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); buttonsLayout->addWidget(okButton); // // Close button // QPushButton* cancelButton = new QPushButton("Cancel"); cancelButton->setAutoDefault(false); QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); buttonsLayout->addWidget(cancelButton); QtUtilities::makeButtonsSameSize(okButton, cancelButton); } /** * Destructor. */ GuiCurrentColoringToRgbPaintDialog::~GuiCurrentColoringToRgbPaintDialog() { } /** * Called when an RGB paint column is selected. */ void GuiCurrentColoringToRgbPaintDialog::slotRgbPaintColumnSelection(int col) { if (col >= 0) { RgbPaintFile* rpf = theMainWindow->getBrainSet()->getRgbPaintFile(); columnNameLineEdit->setText(rpf->getColumnName(col)); commentLineEdit->setText(rpf->getColumnComment(col)); } else { columnNameLineEdit->setText("New Column Name"); commentLineEdit->setText(""); } } /** * Called when dialog is being closed. */ void GuiCurrentColoringToRgbPaintDialog::done(int r) { if (r == QDialog::Accepted) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); const int numNodes = theMainWindow->getBrainSet()->getNumberOfNodes(); RgbPaintFile *rpf = theMainWindow->getBrainSet()->getRgbPaintFile(); int columnNumber = rgbColumnComboBox->currentIndex(); if (columnNumber < 0) { columnNumber = rpf->getNumberOfColumns(); if (rpf->getNumberOfColumns() <= 0) { rpf->setNumberOfNodesAndColumns(numNodes, 1); } else { rpf->addColumns(1); } } rpf->setColumnName(columnNumber, columnNameLineEdit->text()); rpf->setColumnComment(columnNumber, commentLineEdit->text()); rpf->setScaleRed(columnNumber, 0, 255.0); rpf->setScaleGreen(columnNumber, 0, 255.0); rpf->setScaleBlue(columnNumber, 0, 255.0); BrainModelSurfaceNodeColoring* bsnc = theMainWindow->getBrainSet()->getNodeColoring(); const int modelIndex = theMainWindow->getBrainModelIndex(); for (int i = 0; i < numNodes; i++) { const unsigned char* rgb = bsnc->getNodeColor(modelIndex, i); const float rgbf[3] = { rgb[0], rgb[1], rgb[2] }; rpf->setRgb(i, columnNumber, rgbf[0], rgbf[1], rgbf[2]); } DisplaySettingsRgbPaint* dsrgb = theMainWindow->getBrainSet()->getDisplaySettingsRgbPaint(); dsrgb->setSelectedDisplayColumn(-1, -1, columnNumber); GuiFilesModified fm; fm.setRgbPaintModified(); theMainWindow->fileModificationUpdate(fm); bsnc->assignColors(); GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); } QDialog::done(r); } caret-5.6.4~dfsg.1.orig/caret/GuiCopySpecFileDialog.h0000664000175000017500000000500711572067322022144 0ustar michaelmichael #ifndef __GUI_COPY_SPEC_FILE_DIALOG_H__ #define __GUI_COPY_SPEC_FILE_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "WuQDialog.h" class PreferencesFile; class QRadioButton; class QLineEdit; /// Dialog for copying a spec file class GuiCopySpecFileDialog : public WuQDialog { Q_OBJECT public: /// constructor GuiCopySpecFileDialog(QWidget* parent, PreferencesFile* pref); /// destructor ~GuiCopySpecFileDialog(); protected slots: /// called when apply button is pressed void slotApplyButton(); /// called when copy spec file button is pressed void slotCopySpecFilePushButton(); /// called when copy into directory button is pressed void slotCopyIntoDirectoryPushButton(); /// called when a previous directory is selected void slotPreviousDirectory(int); protected: /// copy spec file line edit QLineEdit* copySpecFileLineEdit; /// copy into directory line edit QLineEdit* copyIntoDirectoryLineEdit; /// new spec file name line edit QLineEdit* newSpecFileNameLineEdit; /// copy data files radio button QRadioButton* copyDataFilesRadioButton; /// point to data files abs path radio button QRadioButton* pointToDataFilesAbsPathRadioButton; /// point to data files rel path radio button QRadioButton* pointToDataFilesRelPathRadioButton; /// user's preferences files PreferencesFile* preferencesFile; /// the previous directories std::vector previousDirectories; }; #endif // __GUI_COPY_SPEC_FILE_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiCopySpecFileDialog.cxx0000664000175000017500000003765011572067322022530 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "WuQFileDialog.h" #include #include #include #include #include #include #include #include #include #include #include "DebugControl.h" #include "FileUtilities.h" #include "GuiChooseSpecFileDialog.h" #include "GuiCopySpecFileDialog.h" #include "PreferencesFile.h" #include "QtUtilities.h" #include "SpecFile.h" #include "SpecFileUtilities.h" /** * constructor. */ GuiCopySpecFileDialog::GuiCopySpecFileDialog(QWidget* parent, PreferencesFile* pref) : WuQDialog(parent) { preferencesFile = pref; const int minimumLineEditWidth = 400; // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // Copy spec button and line edit // QPushButton* copySpecFilePushButton = new QPushButton("Copy This Spec File..."); copySpecFilePushButton->setAutoDefault(false); copySpecFilePushButton->setToolTip( "Press this button to display a\n" "dialog for selecting the spec\n" "file that is to be copied."); QObject::connect(copySpecFilePushButton, SIGNAL(clicked()), this, SLOT(slotCopySpecFilePushButton())); copySpecFileLineEdit = new QLineEdit; copySpecFileLineEdit->setReadOnly(true); copySpecFileLineEdit->setMinimumWidth(minimumLineEditWidth); // // Copy into directory button and line edit // QPushButton* copyIntoDirectoryPushButton = new QPushButton("Into This Directory..."); copyIntoDirectoryPushButton->setAutoDefault(false); copyIntoDirectoryPushButton->setToolTip( "Press this button to display a\n" "dialog for choosing the directory in\n" "which to place the copied spec file."); QObject::connect(copyIntoDirectoryPushButton, SIGNAL(clicked()), this, SLOT(slotCopyIntoDirectoryPushButton())); copyIntoDirectoryLineEdit = new QLineEdit; copyIntoDirectoryLineEdit->setReadOnly(false); copyIntoDirectoryLineEdit->setText(QDir::currentPath()); copyIntoDirectoryLineEdit->setToolTip( "Enter or edit the directory in which to place\n" "the copied spec file. If the directory does\n" "not exist, it will be created."); copyIntoDirectoryLineEdit->setMinimumWidth(minimumLineEditWidth); // // Previous directories list // QLabel* previousDirectoryLabel = new QLabel("Previous Directories"); QComboBox* previousDirectoryComboBox = new QComboBox; previousDirectoryComboBox->setToolTip("The directory selected using this\n" "control will be copied into the \n" "\"Into This Directory\" line edit above."); preferencesFile->getRecentDataFileDirectories(previousDirectories); for (int i = 0; i < static_cast(previousDirectories.size()); i++) { QString dirName(previousDirectories[i]); const int dirNameLength = static_cast(dirName.length()); if (dirNameLength > 50) { QString s("..."); s.append(dirName.mid(dirNameLength - 50)); dirName = s; } previousDirectoryComboBox->addItem(dirName); } QObject::connect(previousDirectoryComboBox, SIGNAL(activated(int)), this, SLOT(slotPreviousDirectory(int))); // // New spec file label and name line edit // QLabel* newNameLabel = new QLabel("Name of New Spec File"); newNameLabel->setFont(copyIntoDirectoryPushButton->font()); newSpecFileNameLineEdit = new QLineEdit; newSpecFileNameLineEdit->setMinimumWidth(minimumLineEditWidth); // // Group Box for file items // QGroupBox* fileGroupBox = new QGroupBox("Spec File"); dialogLayout->addWidget(fileGroupBox); QGridLayout* fileGroupGrid = new QGridLayout(fileGroupBox); fileGroupGrid->addWidget(copySpecFilePushButton, 0, 0); fileGroupGrid->addWidget(copySpecFileLineEdit, 0, 1); fileGroupGrid->addWidget(copyIntoDirectoryPushButton, 1, 0); fileGroupGrid->addWidget(copyIntoDirectoryLineEdit, 1, 1); fileGroupGrid->addWidget(previousDirectoryLabel, 2, 0); fileGroupGrid->addWidget(previousDirectoryComboBox, 2, 1); fileGroupGrid->addWidget(newNameLabel, 3, 0); fileGroupGrid->addWidget(newSpecFileNameLineEdit, 3, 1); // // Copy data files push button // copyDataFilesRadioButton = new QRadioButton("Copy Data Files"); copyDataFilesRadioButton->setToolTip( "If this option is selected, the data\n" "data files associated with the spec\n" "file will also be copied."); // // Point to data files abs path push button // pointToDataFilesAbsPathRadioButton = new QRadioButton("Point To Data Files (Absolute Path)"); pointToDataFilesAbsPathRadioButton->setToolTip( "If this option is selected, the data\n" "data files associated with the spec\n" "file will NOT be copied. When the\n" "spec file is loaded, the files will\n" "be read from their original location.\n" "Each data file will be specified with\n" "an absolute path."); // // Point to data files relative path push button // pointToDataFilesRelPathRadioButton = new QRadioButton("Point To Data Files (Relative Path)"); pointToDataFilesRelPathRadioButton->setToolTip( "If this option is selected, the data\n" "data files associated with the spec\n" "file will NOT be copied. When the\n" "spec file is loaded, the files will\n" "be read from their original location.\n" "Each data file will be specified with\n" "a relative path."); // // Button group for data file copying // QGroupBox* dataFileButtonGroupBox = new QGroupBox("Data File Copying"); dialogLayout->addWidget(dataFileButtonGroupBox); QVBoxLayout* dataFileLayout = new QVBoxLayout(dataFileButtonGroupBox); QButtonGroup* dataFileButtonGroup = new QButtonGroup(this); dataFileLayout->addWidget(copyDataFilesRadioButton); dataFileButtonGroup->addButton(copyDataFilesRadioButton); dataFileLayout->addWidget(pointToDataFilesAbsPathRadioButton); dataFileButtonGroup->addButton(pointToDataFilesAbsPathRadioButton); dataFileLayout->addWidget(pointToDataFilesRelPathRadioButton); dataFileButtonGroup->addButton(pointToDataFilesRelPathRadioButton); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); dialogLayout->addLayout(buttonsLayout); // // Apply button // QPushButton* applyButton = new QPushButton("Apply"); applyButton->setAutoDefault(false); buttonsLayout->addWidget(applyButton); QObject::connect(applyButton, SIGNAL(clicked()), this, SLOT(slotApplyButton())); // // Close button // QPushButton* closeButton = new QPushButton("Close"); closeButton->setAutoDefault(false); buttonsLayout->addWidget(closeButton); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); QtUtilities::makeButtonsSameSize(applyButton, closeButton); } /** * destructor. */ GuiCopySpecFileDialog::~GuiCopySpecFileDialog() { } /** * called when a previous directory is selected. */ void GuiCopySpecFileDialog::slotPreviousDirectory(int item) { if ((item >= 0) && (item < static_cast(previousDirectories.size()))) { copyIntoDirectoryLineEdit->setText(previousDirectories[item]); } } /** * called when apply button is pressed. */ void GuiCopySpecFileDialog::slotApplyButton() { // // Check spec file that is to be copied // QString specFileToCopy(copySpecFileLineEdit->text()); if (specFileToCopy.isEmpty()) { QMessageBox::critical(this, "ERROR", "Name of spec file for copying is empty."); return; } if (QFile::exists(specFileToCopy) == false) { QMessageBox::critical(this, "ERROR", "Name of spec file for copying does not exist."); return; } // // Verify that the data files exist and are readable // try { SpecFile sf; sf.readFile(specFileToCopy); QString msg1; if (sf.validate(msg1) == false) { QString msg("Missing data files so unable to copy "); msg.append(FileUtilities::basename(specFileToCopy)); msg.append(":\n"); msg.append(msg1); QMessageBox::critical(this, "ERROR", msg); return; } } catch (FileException&) { QString msg("Unable to read: "); msg.append(FileUtilities::basename(specFileToCopy)); QMessageBox::critical(this, "ERROR", msg); return; } // // Check destination directory // const QString directory(copyIntoDirectoryLineEdit->text()); if (directory.isEmpty()) { QMessageBox::critical(this, "ERROR", "Name of directory is empty."); return; } // // Check output file name // QString outputFileName(newSpecFileNameLineEdit->text()); if (outputFileName.isEmpty()) { QMessageBox::critical(this, "ERROR", "Name of new spec file is empty."); return; } // // Check data file selection // if ((copyDataFilesRadioButton->isChecked() == false) && (pointToDataFilesAbsPathRadioButton->isChecked() == false) && (pointToDataFilesRelPathRadioButton->isChecked() == false)) { QMessageBox::critical(this, "ERROR", "There is no data file copying selection."); return; } // // Create the output directory if needed // if (QFile::exists(directory) == false) { FileUtilities::createDirectory(directory); // // Make sure output directory was successfully created // if (QFile::exists(directory) == false) { QMessageBox::critical(this, "ERROR", "Unable to create output directory."); return; } } // // Switch to the output directory // const QString savedDirectory(QDir::currentPath()); QDir::setCurrent(directory); /* // // Create the output spec file // QString outputSpecFileName(directory); outputSpecFileName.append("/"); // FileUtilities::directorySeparator()); outputSpecFileName.append(outputFileName); */ QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); // // Set the spec file copy mode // SpecFileUtilities::MODE_COPY_SPEC_FILE copySpecMode = SpecFileUtilities::MODE_COPY_SPEC_FILE_POINT_TO_DATA_FILES; if (copyDataFilesRadioButton->isChecked()) { copySpecMode = SpecFileUtilities::MODE_COPY_SPEC_FILE_COPY_ALL; } // // Create the output spec file with path and name // QString outputSpecFileName(directory); outputSpecFileName.append("/"); //FileUtilities::directorySeparator()); outputSpecFileName.append(outputFileName); // // If relative paths are desired // if (pointToDataFilesRelPathRadioButton->isChecked()) { // // If input path is absolute // QFileInfo fi(specFileToCopy); if (fi.isRelative() == false) { const QString inputPath(FileUtilities::dirname(specFileToCopy)); if ((inputPath != ".") && (inputPath == directory)) { specFileToCopy = FileUtilities::basename(specFileToCopy); } else { // // Convert input spec file to have a relative path // QString relativeDirectory; FileUtilities::relativePath(inputPath, directory, relativeDirectory); if (DebugControl::getDebugOn()) { std::cout << "Copy Path: " << inputPath.toAscii().constData() << std::endl; std::cout << "Output Path: " << directory.toAscii().constData() << std::endl; std::cout << "Relative Path: " << relativeDirectory.toAscii().constData() << std::endl; } if (relativeDirectory.isEmpty() == false) { QString newPath(relativeDirectory); newPath.append("/"); //FileUtilities::directorySeparator()); newPath.append(FileUtilities::basename(specFileToCopy)); specFileToCopy = newPath; } } } } // // See if the output spec file exists // if (QFile::exists(outputSpecFileName)) { QString msg("The output spec file "); msg.append(outputFileName); msg.append(" exists.\n"); msg.append("Press \"Continue\" to overwrite it, else press \"Cancel\""); QApplication::restoreOverrideCursor(); if (QMessageBox::question(this, "Overwrite Spec File", msg, (QMessageBox::Ok | QMessageBox::Cancel), QMessageBox::Ok) == QMessageBox::Cancel) { return; } } // // copy the spec file // QString errorMessage; const bool error = SpecFileUtilities::copySpecFile(specFileToCopy, outputFileName, copySpecMode, errorMessage, false, false); // // Restore current directory // QDir::setCurrent(savedDirectory); QApplication::restoreOverrideCursor(); // // Did the copy fail ? // if (error) { QMessageBox::critical(this, "ERROR", errorMessage); return; } else { QMessageBox::information(this, "SUCCESS", "Spec file has been copied."); } // // Add to previous spec files // if (preferencesFile != NULL) { preferencesFile->addToRecentSpecFiles(outputSpecFileName, true); } } /** * called when copy spec file button is pressed. */ void GuiCopySpecFileDialog::slotCopySpecFilePushButton() { // // Choose the spec file to be copied // GuiChooseSpecFileDialog csfd(this, preferencesFile, true); if (csfd.exec() == GuiChooseSpecFileDialog::Accepted) { copySpecFileLineEdit->setText(csfd.getSelectedSpecFile()); newSpecFileNameLineEdit->setText(FileUtilities::basename(csfd.getSelectedSpecFile())); } } /** * called when copy into directory button is pressed. */ void GuiCopySpecFileDialog::slotCopyIntoDirectoryPushButton() { WuQFileDialog fd(this); fd.setModal(true); fd.setAcceptMode(WuQFileDialog::AcceptOpen); fd.setWindowTitle("Choose Output Directory"); fd.setDirectory(QDir::currentPath()); fd.setFileMode(WuQFileDialog::DirectoryOnly); if (fd.exec() == WuQFileDialog::Accepted) { copyIntoDirectoryLineEdit->setText(fd.directory().absolutePath()); } } caret-5.6.4~dfsg.1.orig/caret/GuiConvertDataFileDialog.h0000664000175000017500000000410111572067322022623 0ustar michaelmichael #ifndef __GUI_CONVERT_DATA_FILE_DIALOG_H__ #define __GUI_CONVERT_DATA_FILE_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "WuQDialog.h" class QComboBox; class QListWidget; /// dialog for converting data files between various formats class GuiConvertDataFileDialog : public WuQDialog { Q_OBJECT public: /// constructor GuiConvertDataFileDialog(QWidget* parent); /// destructor ~GuiConvertDataFileDialog(); protected slots: /// called when add files button is pressed void slotAddFilesButton(); /// called when remove files button is pressed void slotRemoveFilesButton(); /// called when apply button is pressed. void slotApplyButton(); /// called when close button is pressed. void slotCloseButton(); protected: /// load file names into list box void loadFileNamesIntoListBox(); /// list box for data files QListWidget* dataFilesListBox; /// combo boxes for file format std::vector formatComboBoxes; /// names of data files std::vector dataFileNames; }; #endif // __GUI_CONVERT_DATA_FILE_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiConvertDataFileDialog.cxx0000664000175000017500000002744311572067322023214 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include "AbstractFile.h" #include "FileFilters.h" #include "FileUtilities.h" #include "GuiConvertDataFileDialog.h" #include "GuiFileDialogWithInstructions.h" #include "QtUtilities.h" #include "StringUtilities.h" /** * constructor. */ GuiConvertDataFileDialog::GuiConvertDataFileDialog(QWidget* parent) : WuQDialog(parent) { setWindowTitle("Convert Data Files"); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // Group box for data files // QGroupBox* dataFileGroupBox = new QGroupBox("Data Files"); dialogLayout->addWidget(dataFileGroupBox); QVBoxLayout* dataFileLayout = new QVBoxLayout(dataFileGroupBox); // // List box for data files // dataFilesListBox = new QListWidget; dataFilesListBox->setSelectionMode(QListWidget::ExtendedSelection); dataFileLayout->addWidget(dataFilesListBox); // // Horizontal box for add/remove buttons // QHBoxLayout* dataButtonLayout = new QHBoxLayout; dataFileLayout->addLayout(dataButtonLayout); // // Add data files push button // QPushButton* addFilesButton = new QPushButton("Add Files..."); addFilesButton->setAutoDefault(false); QObject::connect(addFilesButton, SIGNAL(clicked()), this, SLOT(slotAddFilesButton())); dataButtonLayout->addWidget(addFilesButton); // // Remove data files push button // QPushButton* removeFilesButton = new QPushButton("Remove Selected Files"); removeFilesButton->setAutoDefault(false); QObject::connect(removeFilesButton, SIGNAL(clicked()), this, SLOT(slotRemoveFilesButton())); dataButtonLayout->addWidget(removeFilesButton); // // Make add/remove buttons same size // QtUtilities::makeButtonsSameSize(addFilesButton, removeFilesButton); // // File formats and names // std::vector fileFormats; std::vector fileFormatNames; AbstractFile::getFileFormatTypesAndNames(fileFormats, fileFormatNames); const int numberOfFormats = static_cast(fileFormats.size()); // // Button group for format buttons // QGroupBox* formatGroup = new QGroupBox("Convert to Format"); QGridLayout* formatGridLayout = new QGridLayout(formatGroup); dialogLayout->addWidget(formatGroup); // // Create the file format combo boxes // for (int i = 0; i < numberOfFormats; i++) { QLabel* label = new QLabel(""); if (i == 0) { label->setText("Highest Priority"); } else if (i == (numberOfFormats - 1)) { label->setText("Lowest Priority"); } QComboBox* comboBox = new QComboBox; formatGridLayout->addWidget(label, i, 0); formatGridLayout->addWidget(comboBox, i, 1); for (int j = 0; j < numberOfFormats; j++) { comboBox->addItem(fileFormatNames[j], QVariant(static_cast(fileFormats[j]))); } formatComboBoxes.push_back(comboBox); } // // Horizontal layout for dialog buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; dialogLayout->addLayout(buttonsLayout); buttonsLayout->setSpacing(2); // // Apply button // QPushButton* applyButton = new QPushButton("Apply"); applyButton->setAutoDefault(false); buttonsLayout->addWidget(applyButton); QObject::connect(applyButton, SIGNAL(clicked()), this, SLOT(slotApplyButton())); // // Close button // QPushButton* closeButton = new QPushButton("Close"); closeButton->setAutoDefault(false); buttonsLayout->addWidget(closeButton); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(slotCloseButton())); QtUtilities::makeButtonsSameSize(applyButton, closeButton); } /** * destructor. */ GuiConvertDataFileDialog::~GuiConvertDataFileDialog() { } /** * called when close button is pressed. */ void GuiConvertDataFileDialog::slotCloseButton() { // // Remove all files from dialog // dataFileNames.clear(); loadFileNamesIntoListBox(); // // Close the dialog // close(); } /** * called when apply button is pressed. */ void GuiConvertDataFileDialog::slotApplyButton() { if (dataFileNames.empty()) { QMessageBox::critical(this, "ERROR", "No data files selected."); return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); QString errorMessage; int convertedCount = 0; const int numFiles = static_cast(dataFileNames.size()); QProgressDialog progressDialog(this); progressDialog.setMaximum(numFiles + 1); progressDialog.setValue(0); progressDialog.setWindowTitle("Convert Data Files"); progressDialog.setLabelText(""); progressDialog.show(); // // Get the desired formats // std::vector requestedFormats; for (unsigned int i = 0; i < formatComboBoxes.size(); i++) { const int indx = formatComboBoxes[i]->currentIndex(); requestedFormats.push_back(static_cast( formatComboBoxes[i]->itemData(indx).toInt())); } for (int i = 0; i < numFiles; i++) { const QString filename(dataFileNames[i]); // // Update the progress dialog // qApp->processEvents(); // note: qApp is global in QApplication if (progressDialog.wasCanceled()) { break; } progressDialog.setValue(i); progressDialog.setLabelText("Checking: " + QString(FileUtilities::basename(filename))); progressDialog.show(); // // Read the header of the file // AbstractFile* af = AbstractFile::readAnySubClassDataFile(filename, true, errorMessage); QString progressLabel(FileUtilities::basename(filename) + " "); if (af != NULL) { if (af->getFileHasHeader()) { // // Get files current encoding // const QString formatString(af->getHeaderTag(AbstractFile::headerTagEncoding)); bool validFormatNameFlag = false; const AbstractFile::FILE_FORMAT currentFormat = AbstractFile::convertFormatNameToType(formatString, &validFormatNameFlag); if (validFormatNameFlag) { bool doneFlag = false; for (unsigned int j = 0; j < requestedFormats.size(); j++) { const AbstractFile::FILE_FORMAT newFormat = requestedFormats[j]; const QString newFormatName(AbstractFile::convertFormatTypeToName(newFormat)); if (currentFormat == newFormat) { progressLabel += ("already in " + newFormatName + " file format."); doneFlag = true; } else if (af->getCanWrite(newFormat)) { try { af->readFile(filename); af->setFileWriteType(newFormat); af->writeFile(filename); progressLabel += ("converted to " + newFormatName + "."); convertedCount++; } catch (FileException& e) { progressLabel += ("error converting or writing."); } doneFlag = true; } if (doneFlag) { break; } } if (doneFlag == false) { progressLabel += ("does not support the requested format(s)."); } } else { progressLabel += ("is of an unknown format."); } } else { progressLabel += ("is of an unknown format (has no header)"); } delete af; // can't delete ?? compiler bug ?? } else { progressLabel += ("read error: " + errorMessage); } progressDialog.setLabelText(progressLabel); progressDialog.show(); } // // Remove the progress dialog // progressDialog.cancel(); QApplication::restoreOverrideCursor(); if (errorMessage.isEmpty()) { QString msg(StringUtilities::fromNumber(convertedCount)); msg.append(" files were converted."); QMessageBox::information(this, "INFO", msg); } else { QMessageBox::critical(this, "ERROR", errorMessage); } } /** * called when add files button is pressed. */ void GuiConvertDataFileDialog::slotAddFilesButton() { QString instructions = "To select multiple files, hold down the CTRL key while selecting " "file names with the mouse (Macintosh users should hold down " "the Apple key)."; GuiFileDialogWithInstructions dwi(this, instructions, "addDataFiles", true); QStringList caretFileFilters; FileFilters::getAllCaretFileFilters(caretFileFilters); const QString allFilesFilter("All Files (*)"); QStringList filterList; filterList.append(allFilesFilter); for (QStringList::Iterator it = caretFileFilters.begin(); it != caretFileFilters.end(); ++it) { filterList.append(*it); } dwi.setFilters(filterList); dwi.selectFilter(allFilesFilter); dwi.setWindowTitle("Choose Data File"); dwi.setFileMode(GuiFileDialogWithInstructions::ExistingFiles); if (dwi.exec() == QDialog::Accepted) { QStringList list = dwi.selectedFiles(); QStringList::Iterator it = list.begin(); while( it != list.end() ) { QString filename((*it)); dataFileNames.push_back(filename); ++it; } loadFileNamesIntoListBox(); } } /** * called when remove files button is pressed. */ void GuiConvertDataFileDialog::slotRemoveFilesButton() { std::vector names; for (int i = 0; i < static_cast(dataFileNames.size()); i++) { QListWidgetItem* lwi = dataFilesListBox->item(i); if (dataFilesListBox->isItemSelected(lwi)) { names.push_back(dataFileNames[i]); } } dataFileNames = names; loadFileNamesIntoListBox(); } /** * load file names into list box. */ void GuiConvertDataFileDialog::loadFileNamesIntoListBox() { dataFilesListBox->clear(); for (int i = 0; i < static_cast(dataFileNames.size()); i++) { dataFilesListBox->addItem(FileUtilities::basename(dataFileNames[i])); } } caret-5.6.4~dfsg.1.orig/caret/GuiContourSetScaleDialog.h0000664000175000017500000000453111572067322022675 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_CONTOUR_SET_SCALE_DIALOG_H__ #define __GUI_CONTOUR_SET_SCALE_DIALOG_H__ #include "WuQDialog.h" class QLabel; class QDoubleSpinBox; /// Dialog for setting contour scaling class GuiContourSetScaleDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiContourSetScaleDialog(QWidget* parent = 0, bool modalFlag = false, Qt::WindowFlags f = 0); /// Destructor ~GuiContourSetScaleDialog(); /// set the scale start point void setScaleStartPoint(const float x, const float y); /// set the scale end point void setScaleEndPoint(const float x, const float y); /// update the dialog due to contour changes void updateDialog(); private slots: /// Called when apply button is pressed void slotApplyButton(); /// Called when reset button is pressed void slotResetButton(); private: /// scale start point x label QLabel* scaleStartPointXLabel; /// scale start point y label QLabel* scaleStartPointYLabel; /// scale end point x label QLabel* scaleEndPointXLabel; /// scale end point y label QLabel* scaleEndPointYLabel; /// distance line edit QDoubleSpinBox* distanceDoubleSpinBox; /// scale start point float scaleStartPoint[2]; /// scale end point float scaleEndPoint[2]; }; #endif // __GUI_CONTOUR_SET_SCALE_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiContourSetScaleDialog.cxx0000664000175000017500000001666511572067322023263 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include "BrainModelContours.h" #include "GuiBrainModelOpenGL.h" #include "GuiContourSetScaleDialog.h" #include "GuiMainWindow.h" #include #include "QtUtilities.h" #include "global_variables.h" /** * Constructor */ GuiContourSetScaleDialog::GuiContourSetScaleDialog(QWidget* parent, bool modalFlag, Qt::WindowFlags f) : WuQDialog(parent, f) { setModal(modalFlag); scaleStartPoint[0] = 0.0; scaleStartPoint[1] = 0.0; scaleEndPoint[0] = 0.0; scaleEndPoint[1] = 0.0; setWindowTitle("Contour Set Scale"); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // GridLayout for start and end point labels and distance line edit // QGridLayout* gridLayout = new QGridLayout; dialogLayout->addLayout(gridLayout); gridLayout->setSpacing(3); // // Start point x and y labels // gridLayout->addWidget(new QLabel("Scale Start (Left-Click)"), 0, 0, Qt::AlignLeft); scaleStartPointXLabel = new QLabel("0.0"); gridLayout->addWidget(scaleStartPointXLabel, 0, 1, Qt::AlignLeft); scaleStartPointYLabel = new QLabel("0.0"); gridLayout->addWidget(scaleStartPointYLabel, 0, 2, Qt::AlignLeft); // // Start end x and y labels // gridLayout->addWidget(new QLabel("Scale End (Shift Left-Click)"), 1, 0, Qt::AlignLeft); scaleEndPointXLabel = new QLabel("0.0"); gridLayout->addWidget(scaleEndPointXLabel, 1, 1, Qt::AlignLeft); scaleEndPointYLabel = new QLabel("0.0"); gridLayout->addWidget(scaleEndPointYLabel, 1, 2, Qt::AlignLeft); // // Distance float spin box // gridLayout->addWidget(new QLabel("Distance"), 2, 0, Qt::AlignLeft); distanceDoubleSpinBox = new QDoubleSpinBox; distanceDoubleSpinBox->setMinimum(0.0); distanceDoubleSpinBox->setMaximum(1000.0); distanceDoubleSpinBox->setSingleStep(1.0); distanceDoubleSpinBox->setDecimals(2); gridLayout->addWidget(distanceDoubleSpinBox, 2, 1, 1, 2, Qt::AlignLeft); distanceDoubleSpinBox->setValue(1.0); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; dialogLayout->addLayout(buttonsLayout); buttonsLayout->setSpacing(2); // // Apply button // QPushButton* applyButton = new QPushButton("Apply"); applyButton->setAutoDefault(false); buttonsLayout->addWidget(applyButton); QObject::connect(applyButton, SIGNAL(clicked()), this, SLOT(slotApplyButton())); // // Reset button // QPushButton* resetButton = new QPushButton("Reset"); resetButton->setAutoDefault(false); buttonsLayout->addWidget(resetButton); QObject::connect(resetButton, SIGNAL(clicked()), this, SLOT(slotResetButton())); // // Close button connects to QDialogs close() slot. // QPushButton* closeButton = new QPushButton("Close"); closeButton->setAutoDefault(false); buttonsLayout->addWidget(closeButton); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); QtUtilities::makeButtonsSameSize(applyButton, resetButton, closeButton); theMainWindow->getBrainModelOpenGL()->setMouseMode( GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_SET_SCALE); } /** * Destructor */ GuiContourSetScaleDialog::~GuiContourSetScaleDialog() { } /** * set the scale start point. */ void GuiContourSetScaleDialog::setScaleStartPoint(const float x, const float y) { scaleStartPoint[0] = x; scaleStartPoint[1] = y; scaleStartPointXLabel->setNum(x); scaleStartPointYLabel->setNum(y); } /** * set the scale end point. */ void GuiContourSetScaleDialog::setScaleEndPoint(const float x, const float y) { scaleEndPoint[0] = x; scaleEndPoint[1] = y; scaleEndPointXLabel->setNum(x); scaleEndPointYLabel->setNum(y); } /** * update the dialog due to contour changes. */ void GuiContourSetScaleDialog::updateDialog() { } /** * Called when apply button is pressed. */ void GuiContourSetScaleDialog::slotApplyButton() { // // Get and check the scale points // const float dx = scaleEndPoint[0] - scaleStartPoint[0]; const float dy = scaleEndPoint[1] - scaleStartPoint[1]; const float dist = std::sqrt(dx*dx + dy*dy); if (dist == 0.0) { QMessageBox::critical(this, "Contour Set Scale Error", "Start and End Points must not be the same."); return; } // // Get and check the contour distance // const float contourDistance = distanceDoubleSpinBox->value(); if (contourDistance <= 0.0) { QMessageBox::critical(this, "Contour Set Scale Error", "Distance must be greater than zero."); return; } // // Get and check the contour model in the main window // BrainModelContours* bmc = theMainWindow->getBrainModelContours(); if (bmc == NULL) { QMessageBox::critical(this, "Contour Set Scale Error", "A contour model must be in the main window."); return; } // // Get the current scaling // float currentScaling[3]; bmc->getScaling(BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW, currentScaling); // // set the new scaling // float newScaling[3]; for (int j = 0; j < 3; j++) { newScaling[j] = dist / contourDistance; if (currentScaling[j] != 0.0) { newScaling[j] *= currentScaling[j]; } } // // Update the contour scaling // bmc->setScaling(BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW, newScaling); // // Redraw // GuiBrainModelOpenGL::updateAllGL(NULL); } /** * Called when reset button is pressed. */ void GuiContourSetScaleDialog::slotResetButton() { // // Get and check the contour model in the main window // BrainModelContours* bmc = theMainWindow->getBrainModelContours(); if (bmc == NULL) { QMessageBox::critical(this, "Contour Set Scale Error", "A contour model must be in the main window."); return; } const float ones[3] = { 1.0, 1.0, 1.0 }; bmc->setScaling(BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW, ones); theMainWindow->getBrainModelOpenGL()->setMouseMode( GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_SET_SCALE); // // Redraw // GuiBrainModelOpenGL::updateAllGL(NULL); } caret-5.6.4~dfsg.1.orig/caret/GuiContourSectionControlDialog.h0000664000175000017500000000547111572067322024143 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_CONTOUR_SECTION_CONTROL_DIALOG_H__ #define __GUI_CONTOUR_SECTION_CONTROL_DIALOG_H__ #include "WuQDialog.h" class QRadioButton; class QSpinBox; class QSlider; class WuQWidgetGroup; /// Dialog for controlling selected sections. class GuiContourSectionControlDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiContourSectionControlDialog(QWidget* parent); /// Destructor ~GuiContourSectionControlDialog(); /// Update dialog due to change in sections void updateDialog(); private slots: /// called when minimum spin box value is changed void slotMinimumSpinBox(int value); /// called when maximum spin box value is changed void slotMaximumSpinBox(int value); /// called when a slider is released void sliderReleasedSlot(); /// called when minimum slider released void minimumSliderMovedSlot(int value); /// called when maximum slider released void maximumSliderMovedSlot(int value); /// called when a section type radio button is pressed void sectionTypeSlot(int item); private: /// single section radio button QRadioButton* singleSectionRadioButton; /// multiple section radio button QRadioButton* multipleSectionRadioButton; /// all section radio button QRadioButton* allSectionRadioButton; /// hide section radio button QRadioButton* hideSectionRadioButton; /// widget group for slider and spin box widgets WuQWidgetGroup* adjustSectionsWidgetGroup; /// minimum section slider QSlider* minimumSlider; /// maximum section slider QSlider* maximumSlider; /// minimum section spin box QSpinBox* minimumSpinBox; /// maximum section spin box QSpinBox* maximumSpinBox; }; #endif //__GUI_CONTOUR_SECTION_CONTROL_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiContourSectionControlDialog.cxx0000664000175000017500000003333011572067322024511 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include "BrainModelContours.h" #include "GuiBrainModelOpenGL.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "GuiContourSectionControlDialog.h" #include "WuQWidgetGroup.h" #include "global_variables.h" /** * Constructor. */ GuiContourSectionControlDialog::GuiContourSectionControlDialog(QWidget* parent) : WuQDialog(parent) { setWindowTitle("Contour Section Control"); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // Button Group for number of sections control // QGroupBox* sectionButtonBox = new QGroupBox("Sections"); dialogLayout->addWidget(sectionButtonBox); QButtonGroup* sectionButtonGroup= new QButtonGroup(this); QVBoxLayout* sectionButtonsLayout = new QVBoxLayout(sectionButtonBox); QObject::connect(sectionButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(sectionTypeSlot(int))); // // Single, Multiple, All Radio buttons // singleSectionRadioButton = new QRadioButton("Single"); multipleSectionRadioButton = new QRadioButton("Multiple"); allSectionRadioButton = new QRadioButton("Show All"); hideSectionRadioButton = new QRadioButton("Hide All"); sectionButtonsLayout->addWidget(singleSectionRadioButton); sectionButtonsLayout->addWidget(multipleSectionRadioButton); sectionButtonsLayout->addWidget(allSectionRadioButton); sectionButtonsLayout->addWidget(hideSectionRadioButton); sectionButtonGroup->addButton(singleSectionRadioButton, 0); sectionButtonGroup->addButton(multipleSectionRadioButton, 1); sectionButtonGroup->addButton(allSectionRadioButton, 2); sectionButtonGroup->addButton(hideSectionRadioButton, 3); // // Group Box for sliders // QGroupBox* sliderGroup = new QGroupBox("Section Selection"); QHBoxLayout* sliderLayout = new QHBoxLayout(sliderGroup); dialogLayout->addWidget(sliderGroup); // // // Vertical Box for minimum slider and labels // QVBoxLayout* minimumQVBoxLayout = new QVBoxLayout; sliderLayout->addLayout(minimumQVBoxLayout); // // Horizontal box for labels and labels for minimum slider // QLabel* lowLabel = new QLabel("Low "); minimumQVBoxLayout->addWidget(lowLabel); lowLabel->setFixedSize(lowLabel->sizeHint()); minimumSpinBox = new QSpinBox; minimumSpinBox->setMinimum(2); minimumSpinBox->setMaximum(100); minimumSpinBox->setSingleStep(1); QObject::connect(minimumSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotMinimumSpinBox(int))); minimumQVBoxLayout->addWidget(minimumSpinBox); // // // Minimum slider // minimumSlider = new QSlider(Qt::Vertical); minimumSlider->setMinimum(1); minimumSlider->setMaximum(100); minimumSlider->setSingleStep(1); QObject::connect(minimumSlider, SIGNAL(valueChanged(int)), this, SLOT(minimumSliderMovedSlot(int))); QObject::connect(minimumSlider, SIGNAL(sliderReleased()), this, SLOT(sliderReleasedSlot())); minimumQVBoxLayout->addWidget(minimumSlider); // // Vertical Box for maximum slider and labels // QVBoxLayout* maximumQVBoxLayout = new QVBoxLayout; sliderLayout->addLayout(maximumQVBoxLayout); // // Horizontal box for labels and labels for maximum slider // QLabel* highLabel = new QLabel("High "); maximumQVBoxLayout->addWidget(highLabel); highLabel->setFixedSize(highLabel->sizeHint()); maximumSpinBox = new QSpinBox; maximumSpinBox->setMinimum(1); maximumSpinBox->setMaximum(100); maximumSpinBox->setSingleStep(1); QObject::connect(maximumSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotMaximumSpinBox(int))); maximumQVBoxLayout->addWidget(maximumSpinBox); // // // Maximum slider // maximumSlider = new QSlider(Qt::Vertical); maximumSlider->setMinimum(1); maximumSlider->setMaximum(100); maximumSlider->setSingleStep(1); QObject::connect(maximumSlider, SIGNAL(valueChanged(int)), this, SLOT(maximumSliderMovedSlot(int))); QObject::connect(maximumSlider, SIGNAL(sliderReleased()), this, SLOT(sliderReleasedSlot())); maximumQVBoxLayout->addWidget(maximumSlider); // // Keep track of the section adjustment widgets // adjustSectionsWidgetGroup = new WuQWidgetGroup(this); adjustSectionsWidgetGroup->addWidget(minimumSlider); adjustSectionsWidgetGroup->addWidget(maximumSlider); adjustSectionsWidgetGroup->addWidget(minimumSpinBox); adjustSectionsWidgetGroup->addWidget(maximumSpinBox); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); dialogLayout->addLayout(buttonsLayout); // // Close button connects to QDialogs close() slot. // QPushButton* closeButton = new QPushButton("Close"); closeButton->setFixedSize(closeButton->sizeHint()); closeButton->setAutoDefault(false); buttonsLayout->addWidget(closeButton); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); updateDialog(); } /** * Destructor. */ GuiContourSectionControlDialog::~GuiContourSectionControlDialog() { } /** * Slot for release of minimum slider */ void GuiContourSectionControlDialog::minimumSliderMovedSlot(int value) { // // block signals from spin boxes to prevent display redraw while slider dragged // minimumSpinBox->blockSignals(true); maximumSpinBox->blockSignals(true); BrainModelContours* bmc = theMainWindow->getBrainModelContours(); if (bmc == NULL) { return; } ContourFile* cf = bmc->getContourFile(); if (cf->getSectionType() == ContourFile::SECTION_TYPE_SINGLE) { maximumSlider->setValue(value); maximumSpinBox->setValue(value); } else if (cf->getSectionType() == ContourFile::SECTION_TYPE_MULTIPLE) { if (value > maximumSlider->value()) { maximumSlider->setValue(value); maximumSpinBox->setValue(value); } } minimumSpinBox->setValue(value); // // enable signals from spin boxes now that the displayed value has been changed // minimumSpinBox->blockSignals(false); maximumSpinBox->blockSignals(false); } /** * Slot for release of maximum slider */ void GuiContourSectionControlDialog::maximumSliderMovedSlot(int value) { // // block signals from spin boxes to prevent display redraw while slider dragged // minimumSpinBox->blockSignals(true); maximumSpinBox->blockSignals(true); BrainModelContours* bmc = theMainWindow->getBrainModelContours(); if (bmc == NULL) { return; } ContourFile* cf = bmc->getContourFile(); if (cf->getSectionType() == ContourFile::SECTION_TYPE_SINGLE) { minimumSlider->setValue(value); minimumSpinBox->setValue(value); } else if (cf->getSectionType() == ContourFile::SECTION_TYPE_MULTIPLE) { if (value < minimumSlider->value()) { minimumSlider->setValue(value); minimumSpinBox->setValue(value); } } maximumSpinBox->setValue(value); // // enable signals from spin boxes now that the displayed value has been changed // minimumSpinBox->blockSignals(false); maximumSpinBox->blockSignals(false); } /** * Update due to change in sections. */ void GuiContourSectionControlDialog::updateDialog() { BrainModelContours* bmc = theMainWindow->getBrainModelContours(); if (bmc == NULL) { return; } ContourFile* cf = bmc->getContourFile(); // // Set the selection type radio buttons // bool slidersEnabled = true; switch(cf->getSectionType()) { case ContourFile::SECTION_TYPE_MULTIPLE: multipleSectionRadioButton->setChecked(true); break; case ContourFile::SECTION_TYPE_ALL: allSectionRadioButton->setChecked(true); slidersEnabled = false; break; case ContourFile::SECTION_TYPE_HIDE: hideSectionRadioButton->setChecked(true); slidersEnabled = false; break; case ContourFile::SECTION_TYPE_SINGLE: default: singleSectionRadioButton->setChecked(true); if (cf->getMinimumSelectedSection() != cf->getMaximumSelectedSection()) { cf->setMaximumSelectedSection(cf->getMinimumSelectedSection()); } break; } // // block signals to adjustment widgets // adjustSectionsWidgetGroup->blockSignals(true); // // Enable the sliders and spin boxes if all is NOT selected // minimumSlider->setEnabled(slidersEnabled); maximumSlider->setEnabled(slidersEnabled); minimumSpinBox->setEnabled(slidersEnabled); maximumSpinBox->setEnabled(slidersEnabled); // // Set the slider and spin box min/max range // minimumSlider->setMinimum(cf->getMinimumSection()); minimumSlider->setMaximum(cf->getMaximumSection()); maximumSlider->setMinimum(cf->getMinimumSection()); maximumSlider->setMaximum(cf->getMaximumSection()); minimumSpinBox->setMinimum(cf->getMinimumSection()); minimumSpinBox->setMaximum(cf->getMaximumSection()); maximumSpinBox->setMinimum(cf->getMinimumSection()); maximumSpinBox->setMaximum(cf->getMaximumSection()); // // Set the slider and spin box current value // minimumSlider->setValue(cf->getMinimumSelectedSection()); maximumSlider->setValue(cf->getMaximumSelectedSection()); minimumSpinBox->setValue(cf->getMinimumSelectedSection()); maximumSpinBox->setValue(cf->getMaximumSelectedSection()); // // unblock signals to adjustment widgets // adjustSectionsWidgetGroup->blockSignals(false); } /** * Called when one of the selection type radio buttons is pressed. */ void GuiContourSectionControlDialog::sectionTypeSlot(int item) { BrainModelContours* bmc = theMainWindow->getBrainModelContours(); if (bmc == NULL) { return; } ContourFile* cf = bmc->getContourFile(); ContourFile::SECTION_TYPE selType = static_cast(item); cf->setSectionType(selType); if (selType == ContourFile::SECTION_TYPE_ALL) { cf->setMinimumSelectedSection(cf->getMinimumSection()); cf->setMaximumSelectedSection(cf->getMaximumSection()); } else if (selType == ContourFile::SECTION_TYPE_SINGLE) { cf->setMinimumSelectedSection(minimumSlider->value()); cf->setMaximumSelectedSection(minimumSlider->value()); } updateDialog(); GuiFilesModified fm; fm.setContourModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } /** * Called when apply button is pressed. */ void GuiContourSectionControlDialog::sliderReleasedSlot() { BrainModelContours* bmc = theMainWindow->getBrainModelContours(); if (bmc == NULL) { return; } ContourFile* cf = bmc->getContourFile(); cf->setMinimumSelectedSection(minimumSlider->value()); cf->setMaximumSelectedSection(maximumSlider->value()); GuiFilesModified fm; fm.setContourModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } /** * Called when minimum spin box value is changed. */ void GuiContourSectionControlDialog::slotMinimumSpinBox(int value) { BrainModelContours* bmc = theMainWindow->getBrainModelContours(); if (bmc == NULL) { return; } ContourFile* cf = bmc->getContourFile(); cf->setMinimumSelectedSection(value); if (cf->getSectionType() == ContourFile::SECTION_TYPE_SINGLE) { cf->setMaximumSelectedSection(value); } else if (cf->getSectionType() == ContourFile::SECTION_TYPE_MULTIPLE) { if (cf->getMinimumSelectedSection() > cf->getMaximumSelectedSection()) { cf->setMaximumSelectedSection(value); } } updateDialog(); GuiFilesModified fm; fm.setContourModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } /** * Called when maximum spin box value is changed. */ void GuiContourSectionControlDialog::slotMaximumSpinBox(int value) { BrainModelContours* bmc = theMainWindow->getBrainModelContours(); if (bmc == NULL) { return; } ContourFile* cf = bmc->getContourFile(); cf->setMaximumSelectedSection(value); if (cf->getSectionType() == ContourFile::SECTION_TYPE_SINGLE) { cf->setMinimumSelectedSection(value); } else if (cf->getSectionType() == ContourFile::SECTION_TYPE_MULTIPLE) { if (cf->getMaximumSelectedSection() < cf->getMinimumSelectedSection()) { cf->setMinimumSelectedSection(value); } } updateDialog(); GuiFilesModified fm; fm.setContourModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } caret-5.6.4~dfsg.1.orig/caret/GuiContourReconstructionDialog.h0000664000175000017500000000472611572067322024221 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_CONTOUR_RECONSTRUCTION_DIALOG_H__ #define __GUI_CONTOUR_RECONSTRUCTION_DIALOG_H__ #include "WuQDialog.h" class GuiStructureComboBox; class QCheckBox; class QSpinBox; /// Dialog for constructing a surface from contours class GuiContourReconstructionDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiContourReconstructionDialog(QWidget* parent, bool modal = true, Qt::WindowFlags f = 0); /// Destructor ~GuiContourReconstructionDialog(); private slots: /// Called when OK or Cancel button is pressed void done(int r); private: /// load saved values void loadSavedValues(); /// structure selection combo box GuiStructureComboBox* structureComboBox; /// convert cells hemisphere check box QCheckBox* convertContourCellsCheckBox; /// voxel dimension spin box QSpinBox* voxelDimensionSpinBox; /// polygon limit spin box QSpinBox* polygonLimitSpinBox; /// saved convert cells static bool savedConvertCells; /// saved voxel dimensions static int savedVoxelDimensions; /// saved polygon limit static int savedPolygonLimit; }; #ifdef __GUI_CONTOUR_RECONSTRUCTION_DIALOG_MAIN__ bool GuiContourReconstructionDialog::savedConvertCells = true; int GuiContourReconstructionDialog::savedVoxelDimensions = 128; int GuiContourReconstructionDialog::savedPolygonLimit = 100000; #endif // __GUI_CONTOUR_RECONSTRUCTION_DIALOG_MAIN__ #endif // __GUI_CONTOUR_RECONSTRUCTION_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiContourReconstructionDialog.cxx0000664000175000017500000001553411572067322024573 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #define __GUI_CONTOUR_RECONSTRUCTION_DIALOG_MAIN__ #include "GuiContourReconstructionDialog.h" #undef __GUI_CONTOUR_RECONSTRUCTION_DIALOG_MAIN__ #include #include #include #include #include #include #include #include #include #include "BrainModelContourToSurfaceConverter.h" #include "BrainModelContours.h" #include "BrainSet.h" #include "GuiBrainModelOpenGL.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "GuiStructureComboBox.h" #include "QtUtilities.h" #include "global_variables.h" /// Constructor GuiContourReconstructionDialog::GuiContourReconstructionDialog(QWidget* parent, bool modalFlag, Qt::WindowFlags f) : WuQDialog(parent, f) { setModal(modalFlag); setWindowTitle("Contour Reconstruction Into Surface"); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // Group box for structure // QGroupBox* structureGroup = new QGroupBox("Structure"); QVBoxLayout* structureLayout = new QVBoxLayout(structureGroup); dialogLayout->addWidget(structureGroup); // // left and right hemisphere checkboxes // structureComboBox = new GuiStructureComboBox; structureComboBox->setStructure(theMainWindow->getBrainSet()->getStructure().getType()); structureLayout->addWidget(structureComboBox); // // Group box for contour cells // QGroupBox* cellGroup = new QGroupBox("Contour Cells"); QVBoxLayout* cellLayout = new QVBoxLayout(cellGroup); dialogLayout->addWidget(cellGroup); // // convert contour cells // convertContourCellsCheckBox = new QCheckBox("Convert Contour Cells"); cellLayout->addWidget(convertContourCellsCheckBox); // // Group box for reconstruction parameters // QGroupBox* reconstructionGroupBox = new QGroupBox("Reconstruction Parameters"); dialogLayout->addWidget(reconstructionGroupBox); QGridLayout* reconstructionLayout = new QGridLayout(reconstructionGroupBox); // // reconstruction voxel dimensions // reconstructionLayout->addWidget(new QLabel("Voxel Dimension"), 0, 0); voxelDimensionSpinBox = new QSpinBox; voxelDimensionSpinBox->setMinimum(1); voxelDimensionSpinBox->setMaximum(2048); voxelDimensionSpinBox->setSingleStep(1); reconstructionLayout->addWidget(voxelDimensionSpinBox, 0, 1); // // reconstruction max polygons // reconstructionLayout->addWidget(new QLabel("Polygon Limit"), 1, 0); polygonLimitSpinBox = new QSpinBox; polygonLimitSpinBox->setMinimum(1); polygonLimitSpinBox->setMaximum(std::numeric_limits::max()); polygonLimitSpinBox->setSingleStep(1000); reconstructionLayout->addWidget(polygonLimitSpinBox, 1, 1); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; dialogLayout->addLayout(buttonsLayout); buttonsLayout->setSpacing(2); // // OK button // QPushButton* okButton = new QPushButton("OK"); okButton->setAutoDefault(false); buttonsLayout->addWidget(okButton); QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); // // Cancel button // QPushButton* cancelButton = new QPushButton("Cancel"); cancelButton->setAutoDefault(false); buttonsLayout->addWidget(cancelButton); QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); QtUtilities::makeButtonsSameSize(okButton, cancelButton); loadSavedValues(); } /** * Destructor. */ GuiContourReconstructionDialog::~GuiContourReconstructionDialog() { } /** * Load the saved values into the dialog */ void GuiContourReconstructionDialog::loadSavedValues() { convertContourCellsCheckBox->setChecked(savedConvertCells); voxelDimensionSpinBox->setValue(savedVoxelDimensions); polygonLimitSpinBox->setValue(savedPolygonLimit); } /** * Called when OK or Cancel button pressed. */ void GuiContourReconstructionDialog::done(int r) { if (r == QDialog::Accepted) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); savedConvertCells = convertContourCellsCheckBox->isChecked(); savedVoxelDimensions = voxelDimensionSpinBox->value(); savedPolygonLimit = polygonLimitSpinBox->value(); BrainModelContours* bmc = theMainWindow->getBrainSet()->getBrainModelContours(-1); if (bmc == NULL) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "Convert to Surface Error", "There are no contours in the main window."); return; } BrainModelContourToSurfaceConverter c2s(theMainWindow->getBrainSet(), bmc->getContourFile(), savedVoxelDimensions, savedPolygonLimit, structureComboBox->getSelectedStructure(), savedConvertCells); try { c2s.execute(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "Convert to Surface Error", e.whatQString()); return; } GuiFilesModified fm; fm.setCellModified(); fm.setCellColorModified(); fm.setCoordinateModified(); fm.setTopologyModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); theMainWindow->speakText("Contour reconstruction complete.", false); } QDialog::done(r); } caret-5.6.4~dfsg.1.orig/caret/GuiContourDrawDialog.h0000664000175000017500000000364111572067322022070 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_CONTOUR_DRAW_DIALOG_H__ #define __GUI_CONTOUR_DRAW_DIALOG_H__ #include "WuQDialog.h" class QSpinBox; class QDoubleSpinBox; /// Dialog for drawing contours class GuiContourDrawDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiContourDrawDialog(QWidget* parent = 0, bool modalFlag = false, Qt::WindowFlags f = 0); /// Destructor ~GuiContourDrawDialog(); // get the point spacing float getPointSpacing() const; /// get the section number int getSectionNumber() const; private slots: /// Called when apply button is pressed void slotApplyButton(); /// called when close button is pressed void slotCloseButton(); /// called when section changed void slotSectionNumberSpinBox(); private: /// point spacing float spin box QDoubleSpinBox* pointSpacingDoubleSpinBox; /// section number spin box QSpinBox* sectionNumberSpinBox; }; #endif // __GUI_CONTOUR_DRAW_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiContourDrawDialog.cxx0000664000175000017500000001064411572067322022444 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "GuiBrainModelOpenGL.h" #include "GuiContourDrawDialog.h" #include "GuiMainWindow.h" #include #include "QtUtilities.h" #include "global_variables.h" /** * Constructor */ GuiContourDrawDialog::GuiContourDrawDialog(QWidget* parent, bool modalFlag, Qt::WindowFlags f) : WuQDialog(parent, f) { setModal(modalFlag); setWindowTitle("Contour Drawing"); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // Grid box // QGridLayout* grid = new QGridLayout; dialogLayout->addLayout(grid); // // Point spacing label and float spin box // grid->addWidget(new QLabel("Point Spacing (mm) "), 0, 0); pointSpacingDoubleSpinBox = new QDoubleSpinBox; pointSpacingDoubleSpinBox->setMinimum(0.0); pointSpacingDoubleSpinBox->setMaximum(100.0); pointSpacingDoubleSpinBox->setSingleStep(0.5); pointSpacingDoubleSpinBox->setDecimals(2); pointSpacingDoubleSpinBox->setValue(0.5); grid->addWidget(pointSpacingDoubleSpinBox, 0, 1); // // Section number spin box and label // grid->addWidget(new QLabel("Section Number "), 1, 0); sectionNumberSpinBox = new QSpinBox; sectionNumberSpinBox->setMinimum(-1000000); sectionNumberSpinBox->setMaximum( 1000000); sectionNumberSpinBox->setSingleStep(1); sectionNumberSpinBox->setValue(0); grid->addWidget(sectionNumberSpinBox, 1, 1); QObject::connect(sectionNumberSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotSectionNumberSpinBox())); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); dialogLayout->addLayout(buttonsLayout); // // Apply button // QPushButton* applyButton = new QPushButton("Apply"); applyButton->setAutoDefault(false); buttonsLayout->addWidget(applyButton); QObject::connect(applyButton, SIGNAL(clicked()), this, SLOT(slotApplyButton())); // // Close button connects to QDialogs close() slot. // QPushButton* closeButton = new QPushButton("Close"); closeButton->setAutoDefault(false); buttonsLayout->addWidget(closeButton); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(slotCloseButton())); QtUtilities::makeButtonsSameSize(applyButton, closeButton); } /** * Destructor */ GuiContourDrawDialog::~GuiContourDrawDialog() { } /** * called when section changed. */ void GuiContourDrawDialog::slotSectionNumberSpinBox() { theMainWindow->getBrainModelOpenGL()->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_DRAW); } /** * get the point spacing */ float GuiContourDrawDialog::getPointSpacing() const { return pointSpacingDoubleSpinBox->value(); } /** * get the section number */ int GuiContourDrawDialog::getSectionNumber() const { return sectionNumberSpinBox->value(); } /** * Called when apply button is pressed. */ void GuiContourDrawDialog::slotApplyButton() { theMainWindow->getBrainModelOpenGL()->setMouseMode( GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_DRAW); } /** * Called when apply button is pressed. */ void GuiContourDrawDialog::slotCloseButton() { theMainWindow->getBrainModelOpenGL()->setMouseMode( GuiBrainModelOpenGL::MOUSE_MODE_VIEW); close(); } caret-5.6.4~dfsg.1.orig/caret/GuiContourAlignmentDialog.h0000664000175000017500000000434011572067322023106 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_CONTOUR_ALIGNMENT_DIALOG_H__ #define __GUI_CONTOUR_ALIGNMENT_DIALOG_H__ #include "WuQDialog.h" class QSpinBox; /// Dialog for drawing contours class GuiContourAlignmentDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiContourAlignmentDialog(QWidget* parent = 0, bool modalFlag = false, Qt::WindowFlags f = 0); /// Destructor ~GuiContourAlignmentDialog(); /// get the alignment section int getAlignmentSectionNumber() const; /// update the dialog due to contour changes void updateDialog(); // show the dialog void show(); private slots: /// Called when apply alignment button is pressed void slotApplyAlignmentButton(); /// Called when close button is pressed void slotCloseButton(); /// Called reset view button is pressed void slotResetViewButton(); /// Called when value of section number spin box is changed void slotSectionNumberSpinBox(); /// Called when select region button is pressed void slotSelectRegionButton(); /// Called when clear region button is pressed void slotClearRegionButton(); private: /// section number spin box QSpinBox* sectionNumberSpinBox; }; #endif // __GUI_CONTOUR_ALIGNMENT_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiContourAlignmentDialog.cxx0000664000175000017500000002173211572067322023465 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "BrainModelContours.h" #include "BrainSet.h" #include "ContourCellFile.h" #include "DisplaySettingsContours.h" #include "GuiBrainModelOpenGL.h" #include "GuiContourAlignmentDialog.h" #include "GuiMainWindow.h" #include "QtUtilities.h" #include "global_variables.h" /** * Constructor */ GuiContourAlignmentDialog::GuiContourAlignmentDialog(QWidget* parent, bool modalFlag, Qt::WindowFlags f) : WuQDialog(parent, f) { setModal(modalFlag); setWindowTitle("Contour Alignment"); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // Section number spin box // QHBoxLayout* sectionNumberLayout = new QHBoxLayout; dialogLayout->addLayout(sectionNumberLayout); sectionNumberLayout->addWidget(new QLabel("Section " )); sectionNumberSpinBox = new QSpinBox; sectionNumberSpinBox->setMinimum(0); sectionNumberSpinBox->setMaximum(10); sectionNumberSpinBox->setSingleStep(1); QObject::connect(sectionNumberSpinBox, SIGNAL(valueChanged(int)), this, SLOT(slotSectionNumberSpinBox())); sectionNumberLayout->addWidget(sectionNumberSpinBox); // // Apply alignment button // QPushButton* applyAlignmentButton = new QPushButton("Apply Alignment"); dialogLayout->addWidget(applyAlignmentButton); applyAlignmentButton->setAutoDefault(false); applyAlignmentButton->setFixedSize(applyAlignmentButton->sizeHint()); QObject::connect(applyAlignmentButton, SIGNAL(clicked()), this, SLOT(slotApplyAlignmentButton())); // // Reset view button // QPushButton* resetViewButton = new QPushButton("Reset View"); dialogLayout->addWidget(resetViewButton); resetViewButton->setAutoDefault(false); resetViewButton->setFixedSize(resetViewButton->sizeHint()); QObject::connect(resetViewButton, SIGNAL(clicked()), this, SLOT(slotResetViewButton())); // // Select region button // QPushButton* selectRegionButton = new QPushButton("Select Region"); dialogLayout->addWidget(selectRegionButton); selectRegionButton->setAutoDefault(false); selectRegionButton->setFixedSize(selectRegionButton->sizeHint()); QObject::connect(selectRegionButton, SIGNAL(clicked()), this, SLOT(slotSelectRegionButton())); // // Clear region button // QPushButton* clearRegionButton = new QPushButton("Clear Region"); dialogLayout->addWidget(clearRegionButton); clearRegionButton->setAutoDefault(false); clearRegionButton->setFixedSize(clearRegionButton->sizeHint()); QObject::connect(clearRegionButton, SIGNAL(clicked()), this, SLOT(slotClearRegionButton())); // // Horizontal layout for dialog buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; dialogLayout->addLayout(buttonsLayout); // // Close button connects to QDialogs close() slot. // QPushButton* closeButton = new QPushButton("Close"); closeButton->setAutoDefault(false); buttonsLayout->addWidget(closeButton); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(slotCloseButton())); closeButton->setFixedSize(closeButton->sizeHint()); updateDialog(); } /** * show the dialog. */ void GuiContourAlignmentDialog::show() { slotSectionNumberSpinBox(); WuQDialog::show(); } /** * Destructor */ GuiContourAlignmentDialog::~GuiContourAlignmentDialog() { } /** * Called when select region button is pressed. */ void GuiContourAlignmentDialog::slotSelectRegionButton() { static bool firstTime = true; if (firstTime) { const QString msg("Region alignment will not function\n" "if the contours are rotated."); QMessageBox::information(this, "Information", msg); firstTime = false; } theMainWindow->getBrainModelOpenGL()->setMouseMode( GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_ALIGN_REGION); BrainModelContours* bmc = theMainWindow->getBrainModelContours(); bmc->setAligningRegionFlag(true); bmc->resetAlignmentRegionBox(); ContourFile* contourFile = bmc->getContourFile(); contourFile->clearSpecialFlags(); ContourCellFile* contourCells = theMainWindow->getBrainSet()->getContourCellFile(); contourCells->clearAllSpecialFlags(); GuiBrainModelOpenGL::updateAllGL(); } /** * Called when clear region button is pressed. */ void GuiContourAlignmentDialog::slotClearRegionButton() { BrainModelContours* bmc = theMainWindow->getBrainModelContours(); GuiBrainModelOpenGL* bmo = theMainWindow->getBrainModelOpenGL(); if (bmo->getMouseMode() == GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_ALIGN_REGION) { bmo->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_ALIGN); } bmc->setAligningRegionFlag(false); ContourFile* contourFile = bmc->getContourFile(); contourFile->clearSpecialFlags(); ContourCellFile* contourCells = theMainWindow->getBrainSet()->getContourCellFile(); contourCells->clearAllSpecialFlags(); GuiBrainModelOpenGL::updateAllGL(); } /** * Get the alignment section number. */ int GuiContourAlignmentDialog::getAlignmentSectionNumber() const { return sectionNumberSpinBox->value(); } /** * update the dialog due to contour changes. */ void GuiContourAlignmentDialog::updateDialog() { BrainModelContours* bmc = theMainWindow->getBrainModelContours(); if (bmc != NULL) { ContourFile* cf = bmc->getContourFile(); sectionNumberSpinBox->blockSignals(true); sectionNumberSpinBox->setMinimum(cf->getMinimumSection()); sectionNumberSpinBox->setMaximum(cf->getMaximumSection()); sectionNumberSpinBox->blockSignals(false); } } /** * Called when apply alignment button is pressed. */ void GuiContourAlignmentDialog::slotApplyAlignmentButton() { BrainModelContours* bmc = theMainWindow->getBrainModelContours(); if (bmc != NULL) { // // Note: OpenGL transform is transposed compared to VTK // bmc->applyAlignmentToSection(sectionNumberSpinBox->value()); bmc->resetAlignmentTransformations(); GuiBrainModelOpenGL::updateAllGL(); } } /** * Called when close button is pressed. */ void GuiContourAlignmentDialog::slotCloseButton() { GuiBrainModelOpenGL* bmo = theMainWindow->getBrainModelOpenGL(); if ((bmo->getMouseMode() == GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_ALIGN) || (bmo->getMouseMode() == GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_ALIGN_REGION)) { bmo->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_VIEW); } DisplaySettingsContours* dsc = theMainWindow->getBrainSet()->getDisplaySettingsContours(); dsc->setAlignmentContourValid(false); GuiBrainModelOpenGL::updateAllGL(); close(); } /** * Called when reset view button is pressed. */ void GuiContourAlignmentDialog::slotResetViewButton() { BrainModelContours* bmc = theMainWindow->getBrainModelContours(); if (bmc != NULL) { bmc->resetAlignmentTransformations(); theMainWindow->getBrainModelOpenGL()->setMouseMode( GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_ALIGN); bmc->setAligningRegionFlag(false); GuiBrainModelOpenGL::updateAllGL(); } } /** * Called when value of section number spin box is changed. */ void GuiContourAlignmentDialog::slotSectionNumberSpinBox() { DisplaySettingsContours* dsc = theMainWindow->getBrainSet()->getDisplaySettingsContours(); dsc->setAlignmentContourNumber(sectionNumberSpinBox->value()); dsc->setAlignmentContourValid(true); theMainWindow->getBrainModelOpenGL()->setMouseMode( GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_ALIGN); BrainModelContours* bmc = theMainWindow->getBrainModelContours(); bmc->setAligningRegionFlag(false); ContourFile* contourFile = bmc->getContourFile(); contourFile->clearSpecialFlags(); ContourCellFile* contourCells = theMainWindow->getBrainSet()->getContourCellFile(); contourCells->clearAllSpecialFlags(); GuiBrainModelOpenGL::updateAllGL(); } caret-5.6.4~dfsg.1.orig/caret/GuiConnectivityDialog.h0000664000175000017500000002030011572067322022266 0ustar michaelmichael#ifndef __GUI_CONNECTIVITY_DIALOG_H__ #define __GUI_CONNECTIVITY_DIALOG_H__ #include "BrainSetAutoLoaderManager.h" #include "WuQDialog.h" class QCheckBox; class QComboBox; class QGroupBox; class QLabel; class QLineEdit; class QStackedWidget; class GuiBrainModelSurfaceSelectionComboBox; class GuiNodeAttributeColumnSelectionComboBox; class GuiVolumeFileSelectionComboBox; /// dialog for connectivity operations class GuiConnectivityDialog : public WuQDialog { Q_OBJECT public: // constructor GuiConnectivityDialog(QWidget* parent = 0, Qt::WindowFlags f = 0); // destructor ~GuiConnectivityDialog(); // update this dialog void updateDialog(); private slots: /// called when metric auto load directory button pressed void slotMetricAutoLoadDirectoryPushButton(int indx); /// called to read metric auto load controls void readMetricAutoLoadControls(); /// called when metric node auto load directory button pressed void slotMetricNodeAutoLoadDirectoryPushButton(int indx); /// called to read metric not auto load controls void readMetricNodeAutoLoadControls(); /// called when functional volume auto load directory button pressed void slotFunctionalVolumeAutoLoadDirectoryPushButton(int indx); /// called to read functional volume auto load controls void readFunctionalVolumeAutoLoadControls(); /// called when a page selection is made void slotPageSelectionComboBox(); /// called when cluster auto load metric directory button pressed void slotClusterAutoLoadMetricDirectoryPushButton(int indx); /// called when cluster auto load functional volume directory button pressed void slotClusterAutoLoadFunctionalVolumeDirectoryPushButton(int indx); /// called to read cluster auto load controls void readClusterAutoLoadControls(); private: enum PAGES { PAGE_CLUSTER_AUTO_LOADER, PAGE_FUNCTIONAL_VOLUME_AUTO_LOADER, PAGE_METRIC_AUTO_LOADER, PAGE_METRIC_NODE_AUTO_LOADER }; /// update the metric auto loadcontrols void updateMetricAutoLoadControls(); /// update the metric node auto loadcontrols void updateMetricNodeAutoLoadControls(); /// update the functional volume auto loadcontrols void updateFunctionalVolumeAutoLoadControls(); /// update the cluster auto loadcontrols void updateClusterAutoLoadControls(); /// create the metric auto loader widget QWidget* createMetricAutoLoadersWidget(); /// create the metric node auto loader widget QWidget* createMetricNodeAutoLoadersWidget(); /// create the functional volume loader widget QWidget* createFunctionalVolumeAutoLoaderWidget(); /// create the cluster auto loaders widget QWidget* createClusterAutoLoaderWidget(); /// metric auto load replace column check box QCheckBox* metricAutoLoadReplaceColumnCheckBox[BrainSetAutoLoaderManager::NUMBER_OF_METRIC_AUTO_LOADERS]; /// metric auto load group box QGroupBox* metricAutoLoadGroupBox[BrainSetAutoLoaderManager::NUMBER_OF_METRIC_AUTO_LOADERS]; /// metric auto load directory line edit QLineEdit* metricAutoLoadDirectoryLineEdit[BrainSetAutoLoaderManager::NUMBER_OF_METRIC_AUTO_LOADERS]; /// metric auto load anatomical volume selection control GuiVolumeFileSelectionComboBox* metricAutoLoadVolumeSelectionControl[BrainSetAutoLoaderManager::NUMBER_OF_METRIC_AUTO_LOADERS]; /// metric auto load volume intersection surface selection control GuiBrainModelSurfaceSelectionComboBox* metricAutoLoadVolumeIntersectionSurfaceSelectionControl[BrainSetAutoLoaderManager::NUMBER_OF_METRIC_AUTO_LOADERS]; /// metric auto load display surface selection control GuiBrainModelSurfaceSelectionComboBox* metricAutoLoadDisplaySurfaceSelectionControl[BrainSetAutoLoaderManager::NUMBER_OF_METRIC_AUTO_LOADERS]; /// metric auto load last voxel indices label QLabel* metricAutoLoadLastVoxelLabel[BrainSetAutoLoaderManager::NUMBER_OF_METRIC_AUTO_LOADERS]; /// an update of the metric controls is in progress bool updatingMetricAutoLoadControlsFlag; /// metric node auto load replace column check box QCheckBox* metricNodeAutoLoadReplaceColumnCheckBox[BrainSetAutoLoaderManager::NUMBER_OF_METRIC_NODE_AUTO_LOADERS]; /// metric node auto load group box QGroupBox* metricNodeAutoLoadGroupBox[BrainSetAutoLoaderManager::NUMBER_OF_METRIC_NODE_AUTO_LOADERS]; /// metric node auto load directory line edit QLineEdit* metricNodeAutoLoadDirectoryLineEdit[BrainSetAutoLoaderManager::NUMBER_OF_METRIC_NODE_AUTO_LOADERS]; /// metric auto load display surface selection control GuiBrainModelSurfaceSelectionComboBox* metricNodeAutoLoadDisplaySurfaceSelectionControl[BrainSetAutoLoaderManager::NUMBER_OF_METRIC_NODE_AUTO_LOADERS]; /// an update of the metric node controls is in progress bool updatingMetricNodeAutoLoadControlsFlag; /// functional volume auto load replace file check box QCheckBox* functionalVolumeAutoLoadReplaceFileCheckBox[BrainSetAutoLoaderManager::NUMBER_OF_FUNCTIONAL_VOLUME_AUTO_LOADERS]; /// functional volume auto load group box QGroupBox* functionalVolumeAutoLoadGroupBox[BrainSetAutoLoaderManager::NUMBER_OF_FUNCTIONAL_VOLUME_AUTO_LOADERS]; /// functional volume auto load directory line edit QLineEdit* functionalVolumeAutoLoadDirectoryLineEdit[BrainSetAutoLoaderManager::NUMBER_OF_FUNCTIONAL_VOLUME_AUTO_LOADERS]; /// functional volume auto load anatomical volume selection control GuiVolumeFileSelectionComboBox* functionalVolumeAutoLoadVolumeSelectionControl[BrainSetAutoLoaderManager::NUMBER_OF_FUNCTIONAL_VOLUME_AUTO_LOADERS]; /// functional volume auto load volume intersection surface selection control GuiBrainModelSurfaceSelectionComboBox* functionalVolumeAutoLoadVolumeIntersectionSurfaceSelectionControl[BrainSetAutoLoaderManager::NUMBER_OF_FUNCTIONAL_VOLUME_AUTO_LOADERS]; /// functional volume auto load last voxel label QLabel* functionalVolumeAutoLoadLastVoxelLabel[BrainSetAutoLoaderManager::NUMBER_OF_FUNCTIONAL_VOLUME_AUTO_LOADERS]; /// an update of the functional volume controls is in progress bool updatingFunctionalVolumeAutoLoadControlsFlag; /// cluster auto load replace files check box QCheckBox* clusterAutoLoadReplaceFilesCheckBox[BrainSetAutoLoaderManager::NUMBER_OF_CLUSTER_AUTO_LOADERS]; /// cluster auto load group box QGroupBox* clusterAutoLoadGroupBox[BrainSetAutoLoaderManager::NUMBER_OF_CLUSTER_AUTO_LOADERS]; /// cluster auto load metric directory line edit QLineEdit* clusterAutoLoadMetricDirectoryLineEdit[BrainSetAutoLoaderManager::NUMBER_OF_CLUSTER_AUTO_LOADERS]; /// cluster auto load functional volume directory line edit QLineEdit* clusterAutoLoadFunctionalVolumeDirectoryLineEdit[BrainSetAutoLoaderManager::NUMBER_OF_CLUSTER_AUTO_LOADERS]; /// cluster auto load display surface selection control GuiBrainModelSurfaceSelectionComboBox* clusterAutoLoadDisplaySurfaceSelectionControl[BrainSetAutoLoaderManager::NUMBER_OF_CLUSTER_AUTO_LOADERS]; /// cluster auto load last node number label QLabel* clusterAutoLoadLastNodeNumberLabel[BrainSetAutoLoaderManager::NUMBER_OF_CLUSTER_AUTO_LOADERS]; /// cluster auto load paint column selection combo box GuiNodeAttributeColumnSelectionComboBox* clusterAutoLoadPaintSelectionComboBox[BrainSetAutoLoaderManager::NUMBER_OF_CLUSTER_AUTO_LOADERS]; /// an update of the cluster controls is in progress bool updatingClusterAutoLoadControlsFlag; /// metric auto loaders widget QWidget* pageMetricAutoLoaders; /// metric node auto loaders widget QWidget* pageMetricNodeAutoLoaders; /// functional volumes widget QWidget* pageFunctionalVolumeAutoLoaders; /// cluster auto loaders widget QWidget* pageClusterAutoLoaders; /// page selection combo box QComboBox* pageSelectionComboBox; /// stacked widget for pages QStackedWidget* pageStackedWidget; }; #endif /* __GUI_CONNECTIVITY_DIALOG_H__ */ caret-5.6.4~dfsg.1.orig/caret/GuiConnectivityDialog.cxx0000664000175000017500000010165511572067322022656 0ustar michaelmichael#include #include #include #include #include #include #include #include #include #include #include #include "BrainModelSurface.h" #include "BrainSet.h" #include "BrainSetAutoLoaderManager.h" #include "BrainSetAutoLoaderFileFunctionalVolume.h" #include "BrainSetAutoLoaderFileMetric.h" #include "BrainSetAutoLoaderFileMetricByNode.h" #include "BrainSetAutoLoaderFilePaintCluster.h" #include "GuiBrainModelSurfaceSelectionComboBox.h" #include "GuiConnectivityDialog.h" #include "GuiMainWindow.h" #include "GuiNodeAttributeColumnSelectionComboBox.h" #include "GuiVolumeFileSelectionComboBox.h" #include "WuQFileDialog.h" #include "global_variables.h" /** * Constructor. */ GuiConnectivityDialog::GuiConnectivityDialog(QWidget* parent, Qt::WindowFlags f) : WuQDialog(parent, f) { updatingMetricAutoLoadControlsFlag = true; updatingMetricNodeAutoLoadControlsFlag = true; updatingFunctionalVolumeAutoLoadControlsFlag = true; updatingClusterAutoLoadControlsFlag = true; this->setWindowTitle("Connectivity"); // // Create the auto loaders // pageClusterAutoLoaders = createClusterAutoLoaderWidget(); pageMetricAutoLoaders = createMetricAutoLoadersWidget(); pageMetricNodeAutoLoaders = createMetricNodeAutoLoadersWidget(); pageFunctionalVolumeAutoLoaders = createFunctionalVolumeAutoLoaderWidget(); // // Combo box for selecting pages // QLabel* pageLabel = new QLabel("Page"); pageSelectionComboBox = new QComboBox; pageSelectionComboBox->addItem("Cluster Auto Loaders", PAGE_CLUSTER_AUTO_LOADER); pageSelectionComboBox->addItem("Functional Volume Auto Loaders", PAGE_FUNCTIONAL_VOLUME_AUTO_LOADER); pageSelectionComboBox->addItem("Metric Auto Loaders", PAGE_METRIC_AUTO_LOADER); pageSelectionComboBox->addItem("Metric Node Auto Loaders", PAGE_METRIC_NODE_AUTO_LOADER); QObject::connect(pageSelectionComboBox, SIGNAL(activated(int)), this, SLOT(slotPageSelectionComboBox())); QHBoxLayout* pageControlLayout = new QHBoxLayout(); pageControlLayout->addWidget(pageLabel); pageControlLayout->addWidget(pageSelectionComboBox); pageControlLayout->addStretch(); // // Stacked widget for displaying pages // pageStackedWidget = new QStackedWidget; pageStackedWidget->addWidget(pageClusterAutoLoaders); pageStackedWidget->addWidget(pageFunctionalVolumeAutoLoaders); pageStackedWidget->addWidget(pageMetricAutoLoaders); pageStackedWidget->addWidget(pageMetricNodeAutoLoaders); // // Scroll area for pages // QScrollArea* scrollArea = new QScrollArea(); scrollArea->setWidget(pageStackedWidget); scrollArea->setWidgetResizable(true); // // Close button connects to QDialogs close() slot. // QPushButton* closeButton = new QPushButton("Close"); closeButton->setFixedSize(closeButton->sizeHint()); closeButton->setAutoDefault(false); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); buttonsLayout->addWidget(closeButton); // // Layout for dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->addLayout(pageControlLayout); dialogLayout->addWidget(scrollArea); dialogLayout->addLayout(buttonsLayout); updatingMetricAutoLoadControlsFlag = false; updatingFunctionalVolumeAutoLoadControlsFlag = false; updatingClusterAutoLoadControlsFlag = false; slotPageSelectionComboBox(); updateDialog(); } /** * Called when a page selection is made. */ void GuiConnectivityDialog::slotPageSelectionComboBox() { const int indx = this->pageSelectionComboBox->currentIndex(); const PAGES page = static_cast( this->pageSelectionComboBox->itemData(indx).toInt()); QWidget* newPage = NULL; switch (page) { case PAGE_CLUSTER_AUTO_LOADER: newPage = pageClusterAutoLoaders; break; case PAGE_FUNCTIONAL_VOLUME_AUTO_LOADER: newPage = pageFunctionalVolumeAutoLoaders; break; case PAGE_METRIC_AUTO_LOADER: newPage = pageMetricAutoLoaders; break; case PAGE_METRIC_NODE_AUTO_LOADER: newPage = pageMetricNodeAutoLoaders; break; } if (newPage != NULL) { pageStackedWidget->setCurrentWidget(newPage); } } /** * Destructor. */ GuiConnectivityDialog::~GuiConnectivityDialog() { } /** * update this dialog. */ void GuiConnectivityDialog::updateDialog() { this->updateClusterAutoLoadControls(); this->updateMetricAutoLoadControls(); this->updateMetricNodeAutoLoadControls(); this->updateFunctionalVolumeAutoLoadControls(); } /** * Called to read metric controls. */ void GuiConnectivityDialog::readMetricAutoLoadControls() { if (updatingMetricAutoLoadControlsFlag) { return; } BrainSet* bs = theMainWindow->getBrainSet(); BrainSetAutoLoaderManager* autoLoaderManager = bs->getAutoLoaderManager(); for (int i = 0; i < BrainSetAutoLoaderManager::NUMBER_OF_METRIC_AUTO_LOADERS; i++) { BrainSetAutoLoaderFileMetric* alm = autoLoaderManager->getMetricAutoLoader(i); alm->setAutoLoadMetricDisplaySurface( this->metricAutoLoadDisplaySurfaceSelectionControl[i]->getSelectedBrainModelSurface()); alm->setAutoLoadAnatomyVolumeFile( this->metricAutoLoadVolumeSelectionControl[i]->getSelectedVolumeFile()); alm->setAutoLoadVolumeIntersectionSurface( this->metricAutoLoadVolumeIntersectionSurfaceSelectionControl[i]->getSelectedBrainModelSurface()); alm->setAutoLoadDirectoryName(this->metricAutoLoadDirectoryLineEdit[i]->text()); alm->setAutoLoadEnabled(this->metricAutoLoadGroupBox[i]->isChecked()); alm->setAutoLoadReplaceLastFileEnabled(this->metricAutoLoadReplaceColumnCheckBox[i]->isChecked()); } } /** * Update the metric controls. */ void GuiConnectivityDialog::updateMetricAutoLoadControls() { updatingMetricAutoLoadControlsFlag = true; BrainSet* bs = theMainWindow->getBrainSet(); BrainSetAutoLoaderManager* autoLoaderManager = bs->getAutoLoaderManager(); for (int i = 0; i < BrainSetAutoLoaderManager::NUMBER_OF_METRIC_AUTO_LOADERS; i++) { BrainSetAutoLoaderFileMetric* alm = autoLoaderManager->getMetricAutoLoader(i); this->metricAutoLoadDisplaySurfaceSelectionControl[i]->updateComboBox(); this->metricAutoLoadDisplaySurfaceSelectionControl[i]->setSelectedBrainModelSurface( alm->getAutoLoadMetricDisplaySurface()); this->metricAutoLoadVolumeSelectionControl[i]->updateComboBox(); this->metricAutoLoadVolumeSelectionControl[i]->setSelectedVolumeFile( alm->getAutoLoadAnatomyVolumeFile()); this->metricAutoLoadVolumeIntersectionSurfaceSelectionControl[i]->updateComboBox(); this->metricAutoLoadVolumeIntersectionSurfaceSelectionControl[i]->setSelectedBrainModelSurface( alm->getAutoLoadVolumeIntersectionSurface()); this->metricAutoLoadDirectoryLineEdit[i]->setText( alm->getAutoLoadDirectoryName()); this->metricAutoLoadGroupBox[i]->setChecked(alm->getAutoLoadEnabled()); this->metricAutoLoadReplaceColumnCheckBox[i]->setChecked(alm->getAutoLoadReplaceLastFileEnabled()); VoxelIJK lastVoxel = alm->getLastAutoLoadAnatomyVoxelIndices(); QString indicesString = "(" + QString::number(lastVoxel.getI()) + ", " + QString::number(lastVoxel.getJ()) + ", " + QString::number(lastVoxel.getK()) + ")"; this->metricAutoLoadLastVoxelLabel[i]->setText(indicesString); } updatingMetricAutoLoadControlsFlag = false; } /** * Called when metric auto load directory button pressed. */ void GuiConnectivityDialog::slotMetricAutoLoadDirectoryPushButton(int indx) { QString dirName = WuQFileDialog::getExistingDirectory(this, "Choose Metric File Directory", QDir::currentPath()); if (dirName.isEmpty() == false) { this->metricAutoLoadDirectoryLineEdit[indx]->setText(dirName); readMetricAutoLoadControls(); } } /** * Create the metric auto loader widget. */ QWidget* GuiConnectivityDialog::createMetricAutoLoadersWidget() { // // Metric auto load controls // QWidget* autoLoadWidget = new QWidget; QVBoxLayout* autoLoadLayouts = new QVBoxLayout(autoLoadWidget); QButtonGroup* autoLoadButtonGroup = new QButtonGroup(this); QObject::connect(autoLoadButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotMetricAutoLoadDirectoryPushButton(int))); std::vector surfaceTypes; std::vector surfaceNames; BrainModelSurface::getSurfaceTypesAndNames(surfaceTypes, surfaceNames); for (int i = 0; i < BrainSetAutoLoaderManager::NUMBER_OF_METRIC_AUTO_LOADERS; i++) { this->metricAutoLoadReplaceColumnCheckBox[i] = new QCheckBox("Replace Previously Loaded Column"); QObject::connect(this->metricAutoLoadReplaceColumnCheckBox[i], SIGNAL(toggled(bool)), this, SLOT(readMetricAutoLoadControls())); QPushButton* autoLoadDirectoryPushButton = new QPushButton("Metric Directory..."); autoLoadButtonGroup->addButton(autoLoadDirectoryPushButton, i); this->metricAutoLoadDirectoryLineEdit[i] = new QLineEdit; this->metricAutoLoadDirectoryLineEdit[i]->setEnabled(false); QLabel* autoLoadVolumeLabel = new QLabel("Anatomy Volume"); this->metricAutoLoadVolumeSelectionControl[i] = new GuiVolumeFileSelectionComboBox(VolumeFile::VOLUME_TYPE_ANATOMY); QObject::connect(this->metricAutoLoadVolumeSelectionControl[i], SIGNAL(activated(int)), this, SLOT(readMetricAutoLoadControls())); QLabel* displaySurfaceLabel = new QLabel("Display Surface"); this->metricAutoLoadDisplaySurfaceSelectionControl[i] = new GuiBrainModelSurfaceSelectionComboBox(surfaceTypes); QObject::connect(this->metricAutoLoadDisplaySurfaceSelectionControl[i], SIGNAL(activated(int)), this, SLOT(readMetricAutoLoadControls())); QLabel* autoLoadVolumeSurfaceLabel = new QLabel("Volume Intersect Surface"); this->metricAutoLoadVolumeIntersectionSurfaceSelectionControl[i] = new GuiBrainModelSurfaceSelectionComboBox(BrainModelSurface::SURFACE_TYPE_FIDUCIAL); QObject::connect(this->metricAutoLoadVolumeIntersectionSurfaceSelectionControl[i], SIGNAL(activated(int)), this, SLOT(readMetricAutoLoadControls())); QLabel* lastVoxelLabel = new QLabel("Last Voxel"); metricAutoLoadLastVoxelLabel[i] = new QLabel(" "); this->metricAutoLoadGroupBox[i] = new QGroupBox("Auto Load Metric " + QString::number(i + 1)); this->metricAutoLoadGroupBox[i]->setCheckable(true); QObject::connect(this->metricAutoLoadGroupBox[i], SIGNAL(toggled(bool)), this, SLOT(readMetricAutoLoadControls())); QGridLayout* metricAutoLoadLayout = new QGridLayout(metricAutoLoadGroupBox[i]); metricAutoLoadLayout->addWidget(metricAutoLoadReplaceColumnCheckBox[i], 0, 0, 1, 2); metricAutoLoadLayout->addWidget(autoLoadDirectoryPushButton, 1, 0); metricAutoLoadLayout->addWidget(this->metricAutoLoadDirectoryLineEdit[i], 1, 1); metricAutoLoadLayout->addWidget(displaySurfaceLabel, 2, 0); metricAutoLoadLayout->addWidget(this->metricAutoLoadDisplaySurfaceSelectionControl[i], 2, 1); metricAutoLoadLayout->addWidget(autoLoadVolumeLabel, 3, 0); metricAutoLoadLayout->addWidget(this->metricAutoLoadVolumeSelectionControl[i], 3, 1); metricAutoLoadLayout->addWidget(autoLoadVolumeSurfaceLabel, 4, 0); metricAutoLoadLayout->addWidget(this->metricAutoLoadVolumeIntersectionSurfaceSelectionControl[i], 4, 1); metricAutoLoadLayout->addWidget(lastVoxelLabel, 5, 0); metricAutoLoadLayout->addWidget(metricAutoLoadLastVoxelLabel[i], 5, 1); autoLoadLayouts->addWidget(this->metricAutoLoadGroupBox[i]); } autoLoadLayouts->addStretch(); return autoLoadWidget; } /** * Create the metric node auto loader widget. */ QWidget* GuiConnectivityDialog::createMetricNodeAutoLoadersWidget() { // // Metric auto load controls // QWidget* autoLoadWidget = new QWidget; QVBoxLayout* autoLoadLayouts = new QVBoxLayout(autoLoadWidget); QButtonGroup* autoLoadButtonGroup = new QButtonGroup(this); QObject::connect(autoLoadButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotMetricNodeAutoLoadDirectoryPushButton(int))); std::vector surfaceTypes; std::vector surfaceNames; BrainModelSurface::getSurfaceTypesAndNames(surfaceTypes, surfaceNames); for (int i = 0; i < BrainSetAutoLoaderManager::NUMBER_OF_METRIC_NODE_AUTO_LOADERS; i++) { this->metricNodeAutoLoadReplaceColumnCheckBox[i] = new QCheckBox("Replace Previously Loaded Column"); QObject::connect(this->metricNodeAutoLoadReplaceColumnCheckBox[i], SIGNAL(toggled(bool)), this, SLOT(readMetricNodeAutoLoadControls())); QPushButton* autoLoadDirectoryPushButton = new QPushButton("Metric Directory..."); autoLoadButtonGroup->addButton(autoLoadDirectoryPushButton, i); this->metricNodeAutoLoadDirectoryLineEdit[i] = new QLineEdit; this->metricNodeAutoLoadDirectoryLineEdit[i]->setEnabled(false); QLabel* displaySurfaceLabel = new QLabel("Display Surface"); this->metricNodeAutoLoadDisplaySurfaceSelectionControl[i] = new GuiBrainModelSurfaceSelectionComboBox(surfaceTypes); QObject::connect(this->metricNodeAutoLoadDisplaySurfaceSelectionControl[i], SIGNAL(activated(int)), this, SLOT(readMetricNodeAutoLoadControls())); this->metricNodeAutoLoadGroupBox[i] = new QGroupBox("Auto Load Metric By Node " + QString::number(i + 1)); this->metricNodeAutoLoadGroupBox[i]->setCheckable(true); QObject::connect(this->metricNodeAutoLoadGroupBox[i], SIGNAL(toggled(bool)), this, SLOT(readMetricNodeAutoLoadControls())); QGridLayout* metricAutoLoadLayout = new QGridLayout(metricNodeAutoLoadGroupBox[i]); metricAutoLoadLayout->addWidget(metricNodeAutoLoadReplaceColumnCheckBox[i], 0, 0, 1, 2); metricAutoLoadLayout->addWidget(autoLoadDirectoryPushButton, 1, 0); metricAutoLoadLayout->addWidget(this->metricNodeAutoLoadDirectoryLineEdit[i], 1, 1); metricAutoLoadLayout->addWidget(displaySurfaceLabel, 2, 0); metricAutoLoadLayout->addWidget(this->metricNodeAutoLoadDisplaySurfaceSelectionControl[i], 2, 1); autoLoadLayouts->addWidget(this->metricNodeAutoLoadGroupBox[i]); } autoLoadLayouts->addStretch(); return autoLoadWidget; } /** * Called when metric node auto load directory button pressed. */ void GuiConnectivityDialog::slotMetricNodeAutoLoadDirectoryPushButton(int indx) { QString dirName = WuQFileDialog::getExistingDirectory(this, "Choose Metric File Directory", QDir::currentPath()); if (dirName.isEmpty() == false) { this->metricNodeAutoLoadDirectoryLineEdit[indx]->setText(dirName); readMetricNodeAutoLoadControls(); } } /** * Called to read metric not auto load controls. */ void GuiConnectivityDialog::readMetricNodeAutoLoadControls() { if (updatingMetricNodeAutoLoadControlsFlag) { return; } BrainSet* bs = theMainWindow->getBrainSet(); BrainSetAutoLoaderManager* autoLoaderManager = bs->getAutoLoaderManager(); for (int i = 0; i < BrainSetAutoLoaderManager::NUMBER_OF_METRIC_NODE_AUTO_LOADERS; i++) { BrainSetAutoLoaderFileMetricByNode* alm = autoLoaderManager->getMetricNodeAutoLoader(i); alm->setAutoLoadDirectoryName(this->metricNodeAutoLoadDirectoryLineEdit[i]->text()); alm->setAutoLoadEnabled(this->metricNodeAutoLoadGroupBox[i]->isChecked()); alm->setAutoLoadReplaceLastFileEnabled(this->metricNodeAutoLoadReplaceColumnCheckBox[i]->isChecked()); alm->setAutoLoadMetricDisplaySurface( this->metricNodeAutoLoadDisplaySurfaceSelectionControl[i]->getSelectedBrainModelSurface()); } } /** * Update the metric node auto loadcontrols. */ void GuiConnectivityDialog::updateMetricNodeAutoLoadControls() { updatingMetricNodeAutoLoadControlsFlag = true; BrainSet* bs = theMainWindow->getBrainSet(); BrainSetAutoLoaderManager* autoLoaderManager = bs->getAutoLoaderManager(); for (int i = 0; i < BrainSetAutoLoaderManager::NUMBER_OF_METRIC_NODE_AUTO_LOADERS; i++) { BrainSetAutoLoaderFileMetricByNode* alm = autoLoaderManager->getMetricNodeAutoLoader(i); this->metricNodeAutoLoadReplaceColumnCheckBox[i]->setChecked(alm->getAutoLoadReplaceLastFileEnabled()); this->metricNodeAutoLoadDirectoryLineEdit[i]->setText( alm->getAutoLoadDirectoryName()); this->metricNodeAutoLoadGroupBox[i]->setChecked(alm->getAutoLoadEnabled()); this->metricNodeAutoLoadDisplaySurfaceSelectionControl[i]->updateComboBox(); this->metricNodeAutoLoadDisplaySurfaceSelectionControl[i]->setSelectedBrainModelSurface( alm->getAutoLoadMetricDisplaySurface()); } updatingMetricNodeAutoLoadControlsFlag = false; } /** * Create the cluster auto loaders widget. */ QWidget* GuiConnectivityDialog::createClusterAutoLoaderWidget() { // // Cluster auto load controls // QWidget* autoLoadWidget = new QWidget; QVBoxLayout* autoLoadLayouts = new QVBoxLayout(autoLoadWidget); QButtonGroup* autoLoadMetricButtonGroup = new QButtonGroup(this); QObject::connect(autoLoadMetricButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotClusterAutoLoadMetricDirectoryPushButton(int))); QButtonGroup* autoLoadFunctionalVolumeButtonGroup = new QButtonGroup(this); QObject::connect(autoLoadFunctionalVolumeButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotClusterAutoLoadFunctionalVolumeDirectoryPushButton(int))); std::vector surfaceTypes; std::vector surfaceNames; BrainModelSurface::getSurfaceTypesAndNames(surfaceTypes, surfaceNames); for (int i = 0; i < BrainSetAutoLoaderManager::NUMBER_OF_CLUSTER_AUTO_LOADERS; i++) { this->clusterAutoLoadReplaceFilesCheckBox[i] = new QCheckBox("Replace Previously Loaded Files"); QObject::connect(this->clusterAutoLoadReplaceFilesCheckBox[i], SIGNAL(toggled(bool)), this, SLOT(readClusterAutoLoadControls())); QPushButton* autoLoadMetricDirectoryPushButton = new QPushButton("Metric Directory..."); autoLoadMetricButtonGroup->addButton(autoLoadMetricDirectoryPushButton, i); this->clusterAutoLoadMetricDirectoryLineEdit[i] = new QLineEdit; this->clusterAutoLoadMetricDirectoryLineEdit[i]->setEnabled(false); QPushButton* autoLoadFunctionalVolumeDirectoryPushButton = new QPushButton("Functional Volume Directory..."); autoLoadFunctionalVolumeButtonGroup->addButton(autoLoadFunctionalVolumeDirectoryPushButton, i); this->clusterAutoLoadFunctionalVolumeDirectoryLineEdit[i] = new QLineEdit; this->clusterAutoLoadFunctionalVolumeDirectoryLineEdit[i]->setEnabled(false); QLabel* paintColumnLabel = new QLabel("Paint Column"); this->clusterAutoLoadPaintSelectionComboBox[i] = new GuiNodeAttributeColumnSelectionComboBox(GUI_NODE_FILE_TYPE_PAINT, false, false, false); QObject::connect(this->clusterAutoLoadPaintSelectionComboBox[i], SIGNAL(itemSelected(int)), this, SLOT(readClusterAutoLoadControls())); QLabel* displaySurfaceLabel = new QLabel("Display Surface"); this->clusterAutoLoadDisplaySurfaceSelectionControl[i] = new GuiBrainModelSurfaceSelectionComboBox(surfaceTypes); QObject::connect(this->clusterAutoLoadDisplaySurfaceSelectionControl[i], SIGNAL(activated(int)), this, SLOT(readClusterAutoLoadControls())); QLabel* lastNodeLabel = new QLabel("Last Node"); clusterAutoLoadLastNodeNumberLabel[i] = new QLabel(" "); this->clusterAutoLoadGroupBox[i] = new QGroupBox("Auto Load Cluster " + QString::number(i + 1)); this->clusterAutoLoadGroupBox[i]->setCheckable(true); QObject::connect(this->clusterAutoLoadGroupBox[i], SIGNAL(toggled(bool)), this, SLOT(readClusterAutoLoadControls())); QGridLayout* clusterAutoLoadLayout = new QGridLayout(clusterAutoLoadGroupBox[i]); clusterAutoLoadLayout->addWidget(clusterAutoLoadReplaceFilesCheckBox[i], 0, 0, 1, 2); clusterAutoLoadLayout->addWidget(autoLoadMetricDirectoryPushButton, 1, 0); clusterAutoLoadLayout->addWidget(this->clusterAutoLoadMetricDirectoryLineEdit[i], 1, 1); clusterAutoLoadLayout->addWidget(autoLoadFunctionalVolumeDirectoryPushButton, 2, 0); clusterAutoLoadLayout->addWidget(this->clusterAutoLoadFunctionalVolumeDirectoryLineEdit[i], 2, 1); clusterAutoLoadLayout->addWidget(paintColumnLabel, 3, 0); clusterAutoLoadLayout->addWidget(this->clusterAutoLoadPaintSelectionComboBox[i], 3, 1); clusterAutoLoadLayout->addWidget(displaySurfaceLabel, 4, 0); clusterAutoLoadLayout->addWidget(this->clusterAutoLoadDisplaySurfaceSelectionControl[i], 4, 1); clusterAutoLoadLayout->addWidget(lastNodeLabel, 5, 0); clusterAutoLoadLayout->addWidget(clusterAutoLoadLastNodeNumberLabel[i], 5, 1); autoLoadLayouts->addWidget(this->clusterAutoLoadGroupBox[i]); } autoLoadLayouts->addStretch(); return autoLoadWidget; } /** * Called when cluster auto load metric directory button pressed. */ void GuiConnectivityDialog::slotClusterAutoLoadMetricDirectoryPushButton(int indx) { QString dirName = WuQFileDialog::getExistingDirectory(this, "Choose Metric Data File Directory", QDir::currentPath()); if (dirName.isEmpty() == false) { this->clusterAutoLoadMetricDirectoryLineEdit[indx]->setText(dirName); readClusterAutoLoadControls(); } } /** * Called when cluster auto load functional volumedirectory button pressed. */ void GuiConnectivityDialog::slotClusterAutoLoadFunctionalVolumeDirectoryPushButton(int indx) { QString dirName = WuQFileDialog::getExistingDirectory(this, "Choose Functional Volume Data File Directory", QDir::currentPath()); if (dirName.isEmpty() == false) { this->clusterAutoLoadFunctionalVolumeDirectoryLineEdit[indx]->setText(dirName); readClusterAutoLoadControls(); } } /** * Called to read cluster auto load controls. */ void GuiConnectivityDialog::readClusterAutoLoadControls() { if (updatingClusterAutoLoadControlsFlag) { return; } BrainSet* bs = theMainWindow->getBrainSet(); BrainSetAutoLoaderManager* autoLoaderManager = bs->getAutoLoaderManager(); for (int i = 0; i < BrainSetAutoLoaderManager::NUMBER_OF_CLUSTER_AUTO_LOADERS; i++) { BrainSetAutoLoaderFilePaintCluster* alc = autoLoaderManager->getClusterAutoLoader(i); alc->setAutoLoadDisplaySurface( this->clusterAutoLoadDisplaySurfaceSelectionControl[i]->getSelectedBrainModelSurface()); alc->setAutoLoadDirectoryName(this->clusterAutoLoadMetricDirectoryLineEdit[i]->text()); alc->setAutoLoadSecondaryDirectoryName(this->clusterAutoLoadFunctionalVolumeDirectoryLineEdit[i]->text()); alc->setAutoLoadEnabled(this->clusterAutoLoadGroupBox[i]->isChecked()); alc->setAutoLoadReplaceLastFileEnabled(this->clusterAutoLoadReplaceFilesCheckBox[i]->isChecked()); alc->setPaintColumnNumber(this->clusterAutoLoadPaintSelectionComboBox[i]->currentIndex()); } } /** * Update the cluster auto loadcontrols. */ void GuiConnectivityDialog::updateClusterAutoLoadControls() { updatingClusterAutoLoadControlsFlag = true; BrainSet* bs = theMainWindow->getBrainSet(); BrainSetAutoLoaderManager* autoLoaderManager = bs->getAutoLoaderManager(); for (int i = 0; i < BrainSetAutoLoaderManager::NUMBER_OF_CLUSTER_AUTO_LOADERS; i++) { BrainSetAutoLoaderFilePaintCluster* alc = autoLoaderManager->getClusterAutoLoader(i); this->clusterAutoLoadDisplaySurfaceSelectionControl[i]->updateComboBox(); this->clusterAutoLoadDisplaySurfaceSelectionControl[i]->setSelectedBrainModelSurface( alc->getAutoLoadDisplaySurface()); this->clusterAutoLoadMetricDirectoryLineEdit[i]->setText( alc->getAutoLoadDirectoryName()); this->clusterAutoLoadFunctionalVolumeDirectoryLineEdit[i]->setText( alc->getAutoLoadSecondaryDirectoryName()); this->clusterAutoLoadGroupBox[i]->setChecked(alc->getAutoLoadEnabled()); this->clusterAutoLoadReplaceFilesCheckBox[i]->setChecked(alc->getAutoLoadReplaceLastFileEnabled()); this->clusterAutoLoadPaintSelectionComboBox[i]->updateComboBox(); this->clusterAutoLoadPaintSelectionComboBox[i]->setCurrentIndex(alc->getPaintColumnNumber()); const int lastNodeNumber = alc->getLastAutoLoadNodeNumber(); QString nodeString = QString::number(lastNodeNumber); this->clusterAutoLoadLastNodeNumberLabel[i]->setText(nodeString); } updatingClusterAutoLoadControlsFlag = false; } /** * Create the functional volume loader widget. */ QWidget* GuiConnectivityDialog::createFunctionalVolumeAutoLoaderWidget() { // // functional volume auto load controls // QWidget* autoLoadWidget = new QWidget; QVBoxLayout* autoLoadLayouts = new QVBoxLayout(autoLoadWidget); QButtonGroup* autoLoadButtonGroup = new QButtonGroup(this); QObject::connect(autoLoadButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotFunctionalVolumeAutoLoadDirectoryPushButton(int))); std::vector surfaceTypes; std::vector surfaceNames; BrainModelSurface::getSurfaceTypesAndNames(surfaceTypes, surfaceNames); for (int i = 0; i < BrainSetAutoLoaderManager::NUMBER_OF_FUNCTIONAL_VOLUME_AUTO_LOADERS; i++) { this->functionalVolumeAutoLoadReplaceFileCheckBox[i] = new QCheckBox("Replace Previously Loaded Functional Volume File"); QObject::connect(this->functionalVolumeAutoLoadReplaceFileCheckBox[i], SIGNAL(toggled(bool)), this, SLOT(readFunctionalVolumeAutoLoadControls())); QPushButton* autoLoadDirectoryPushButton = new QPushButton("Functional Volume Directory..."); autoLoadButtonGroup->addButton(autoLoadDirectoryPushButton, i); this->functionalVolumeAutoLoadDirectoryLineEdit[i] = new QLineEdit; this->functionalVolumeAutoLoadDirectoryLineEdit[i]->setEnabled(false); QLabel* autoLoadVolumeLabel = new QLabel("Anatomy Volume"); this->functionalVolumeAutoLoadVolumeSelectionControl[i] = new GuiVolumeFileSelectionComboBox(VolumeFile::VOLUME_TYPE_ANATOMY); QObject::connect(this->functionalVolumeAutoLoadVolumeSelectionControl[i], SIGNAL(activated(int)), this, SLOT(readFunctionalVolumeAutoLoadControls())); QLabel* autoLoadVolumeSurfaceLabel = new QLabel("Volume Intersect Surface"); this->functionalVolumeAutoLoadVolumeIntersectionSurfaceSelectionControl[i] = new GuiBrainModelSurfaceSelectionComboBox(BrainModelSurface::SURFACE_TYPE_FIDUCIAL); QObject::connect(this->functionalVolumeAutoLoadVolumeIntersectionSurfaceSelectionControl[i], SIGNAL(activated(int)), this, SLOT(readFunctionalVolumeAutoLoadControls())); QLabel* lastFileLabel = new QLabel("Last File"); functionalVolumeAutoLoadLastVoxelLabel[i] = new QLabel(" "); this->functionalVolumeAutoLoadGroupBox[i] = new QGroupBox("Auto Load FunctionalVolume " + QString::number(i + 1)); this->functionalVolumeAutoLoadGroupBox[i]->setCheckable(true); QObject::connect(this->functionalVolumeAutoLoadGroupBox[i], SIGNAL(toggled(bool)), this, SLOT(readFunctionalVolumeAutoLoadControls())); QGridLayout* functionalVolumeAutoLoadLayout = new QGridLayout(functionalVolumeAutoLoadGroupBox[i]); functionalVolumeAutoLoadLayout->addWidget(functionalVolumeAutoLoadReplaceFileCheckBox[i], 0, 0, 1, 2); functionalVolumeAutoLoadLayout->addWidget(autoLoadDirectoryPushButton, 1, 0); functionalVolumeAutoLoadLayout->addWidget(this->functionalVolumeAutoLoadDirectoryLineEdit[i], 1, 1); functionalVolumeAutoLoadLayout->addWidget(autoLoadVolumeLabel, 3, 0); functionalVolumeAutoLoadLayout->addWidget(this->functionalVolumeAutoLoadVolumeSelectionControl[i], 3, 1); functionalVolumeAutoLoadLayout->addWidget(autoLoadVolumeSurfaceLabel, 4, 0); functionalVolumeAutoLoadLayout->addWidget(this->functionalVolumeAutoLoadVolumeIntersectionSurfaceSelectionControl[i], 4, 1); functionalVolumeAutoLoadLayout->addWidget(lastFileLabel, 5, 0); functionalVolumeAutoLoadLayout->addWidget(functionalVolumeAutoLoadLastVoxelLabel[i], 5, 1); autoLoadLayouts->addWidget(this->functionalVolumeAutoLoadGroupBox[i]); } autoLoadLayouts->addStretch(); return autoLoadWidget; } /** * Called when functional volume auto load directory button pressed. */ void GuiConnectivityDialog::slotFunctionalVolumeAutoLoadDirectoryPushButton(int indx) { QString dirName = WuQFileDialog::getExistingDirectory(this, "Choose Functional Volume File Directory", QDir::currentPath()); if (dirName.isEmpty() == false) { this->functionalVolumeAutoLoadDirectoryLineEdit[indx]->setText(dirName); readFunctionalVolumeAutoLoadControls(); } } /** * Called to read functional volume auto load controls. */ void GuiConnectivityDialog::readFunctionalVolumeAutoLoadControls() { if (updatingFunctionalVolumeAutoLoadControlsFlag) { return; } BrainSet* bs = theMainWindow->getBrainSet(); BrainSetAutoLoaderManager* autoLoaderManager = bs->getAutoLoaderManager(); for (int i = 0; i < BrainSetAutoLoaderManager::NUMBER_OF_FUNCTIONAL_VOLUME_AUTO_LOADERS; i++) { BrainSetAutoLoaderFileFunctionalVolume* alm = autoLoaderManager->getFunctionalVolumeAutoLoader(i); alm->setAutoLoadAnatomyVolumeFile( this->functionalVolumeAutoLoadVolumeSelectionControl[i]->getSelectedVolumeFile()); alm->setAutoLoadVolumeIntersectionSurface( this->functionalVolumeAutoLoadVolumeIntersectionSurfaceSelectionControl[i]->getSelectedBrainModelSurface()); alm->setAutoLoadDirectoryName(this->functionalVolumeAutoLoadDirectoryLineEdit[i]->text()); alm->setAutoLoadEnabled(this->functionalVolumeAutoLoadGroupBox[i]->isChecked()); alm->setAutoLoadReplaceLastFileEnabled(this->functionalVolumeAutoLoadReplaceFileCheckBox[i]->isChecked()); } } /** * Update the functional volume auto loadcontrols. */ void GuiConnectivityDialog::updateFunctionalVolumeAutoLoadControls() { updatingFunctionalVolumeAutoLoadControlsFlag = true; BrainSet* bs = theMainWindow->getBrainSet(); BrainSetAutoLoaderManager* autoLoaderManager = bs->getAutoLoaderManager(); for (int i = 0; i < BrainSetAutoLoaderManager::NUMBER_OF_FUNCTIONAL_VOLUME_AUTO_LOADERS; i++) { BrainSetAutoLoaderFileFunctionalVolume* alm = autoLoaderManager->getFunctionalVolumeAutoLoader(i); this->functionalVolumeAutoLoadVolumeSelectionControl[i]->updateComboBox(); this->functionalVolumeAutoLoadVolumeSelectionControl[i]->setSelectedVolumeFile( alm->getAutoLoadAnatomyVolumeFile()); this->functionalVolumeAutoLoadVolumeIntersectionSurfaceSelectionControl[i]->updateComboBox(); this->functionalVolumeAutoLoadVolumeIntersectionSurfaceSelectionControl[i]->setSelectedBrainModelSurface( alm->getAutoLoadVolumeIntersectionSurface()); this->functionalVolumeAutoLoadDirectoryLineEdit[i]->setText( alm->getAutoLoadDirectoryName()); this->functionalVolumeAutoLoadGroupBox[i]->setChecked(alm->getAutoLoadEnabled()); this->functionalVolumeAutoLoadReplaceFileCheckBox[i]->setChecked(alm->getAutoLoadReplaceLastFileEnabled()); VoxelIJK lastVoxel = alm->getLastAutoLoadAnatomyVoxelIndices(); QString indicesString = "(" + QString::number(lastVoxel.getI()) + ", " + QString::number(lastVoxel.getJ()) + ", " + QString::number(lastVoxel.getK()) + ")"; this->functionalVolumeAutoLoadLastVoxelLabel[i]->setText(indicesString); } updatingFunctionalVolumeAutoLoadControlsFlag = false; } caret-5.6.4~dfsg.1.orig/caret/GuiCommunicatorClientConnectDialog.h0000664000175000017500000000474211572067322024735 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_GUI_COMMUNICATOR_CONNECT_DIALOG_H__ #define __VE_GUI_COMMUNICATOR_CONNECT_DIALOG_H__ #include #include "WuQDialog.h" class QCheckBox; class QLineEdit; class QSpinBox; /// This class is used to connect to other programs via sockets. class GuiCommunicatorClientConnectDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiCommunicatorClientConnectDialog(QWidget* parent, const QString& programName, const QString& defaultHostName, const int defaultControlPort, const int defaultDataPort, const bool defaultRequestUpdates, const bool allowUserToEditDataPort, const bool allowUserToEditRequestUpdates); /// Destructor ~GuiCommunicatorClientConnectDialog(); /// get the host name in the dialog QString getHostName() const; /// get the control port in the dialog int getControlPort() const; /// get the data port in the dialog int getDataPort() const; /// get the request updates checkbox bool getRequestUpdates() const; private: /// hostname line edit QLineEdit* hostNameLineEdit; /// control port spin box QSpinBox* controlPortSpinBox; /// data port spin box QSpinBox* dataPortSpinBox; /// request update from AFNI checkbox QCheckBox* requestUpdatesCheckBox; }; #endif caret-5.6.4~dfsg.1.orig/caret/GuiCommunicatorClientConnectDialog.cxx0000664000175000017500000001251711572067322025307 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "GuiCommunicatorClientConnectDialog.h" #include "QtUtilities.h" #include #include #include #include #include #include #include /** * Constructor */ GuiCommunicatorClientConnectDialog::GuiCommunicatorClientConnectDialog(QWidget* parent, const QString& programName, const QString& defaultHostName, const int defaultControlPort, const int defaultDataPort, const bool defaultRequestUpdates, const bool allowUserToEditDataPort, const bool allowUserToEditRequestUpdates) : WuQDialog(parent) { setModal(true); QString caption("Connect to "); caption.append(programName); setWindowTitle(caption); // // Layout for entire dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); int numRows = 0; const int HOST_NAME_ROW = numRows++; const int CONTROL_PORT_ROW = numRows++; const int DATA_PORT_ROW = numRows++; // // Grid Layout for line edits and labels // QGridLayout* gridLayout = new QGridLayout; dialogLayout->addLayout(gridLayout); gridLayout->setSpacing(3); // // Label and Line Edit for host name // gridLayout->addWidget(new QLabel("Host Name"), HOST_NAME_ROW, 0, Qt::AlignLeft); hostNameLineEdit = new QLineEdit; gridLayout->addWidget(hostNameLineEdit, HOST_NAME_ROW, 1, Qt::AlignLeft); hostNameLineEdit->setText(defaultHostName); // // Label and Spin Box for control port // gridLayout->addWidget(new QLabel("Control Port"), CONTROL_PORT_ROW, 0, Qt::AlignLeft); controlPortSpinBox = new QSpinBox; controlPortSpinBox->setMinimum(0); controlPortSpinBox->setMaximum(65536); controlPortSpinBox->setSingleStep(1); gridLayout->addWidget(controlPortSpinBox, CONTROL_PORT_ROW, 1, Qt::AlignLeft); controlPortSpinBox->setValue(defaultControlPort); // // Label and Line Edit for data port // if (allowUserToEditDataPort) { gridLayout->addWidget(new QLabel("Data Port"), DATA_PORT_ROW, 0, Qt::AlignLeft); dataPortSpinBox = new QSpinBox; dataPortSpinBox->setMinimum(0); dataPortSpinBox->setMaximum(65536); dataPortSpinBox->setSingleStep(1); gridLayout->addWidget(dataPortSpinBox, DATA_PORT_ROW, 1, Qt::AlignLeft); dataPortSpinBox->setValue(defaultDataPort); } else { dataPortSpinBox = NULL; } // // Request updates check box // if (allowUserToEditRequestUpdates) { requestUpdatesCheckBox = new QCheckBox("Request Updates"); dialogLayout->addWidget(requestUpdatesCheckBox, Qt::AlignLeft); requestUpdatesCheckBox->setChecked(defaultRequestUpdates); } else { requestUpdatesCheckBox = NULL; } // // OK and Cancel Buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; dialogLayout->addLayout(buttonsLayout); QPushButton* ok = new QPushButton("OK"); QObject::connect(ok, SIGNAL(clicked()), this, SLOT(accept())); buttonsLayout->addWidget(ok); QPushButton* cancel = new QPushButton("Cancel"); QObject::connect(cancel, SIGNAL(clicked()), this, SLOT(reject())); buttonsLayout->addWidget(cancel); // // Make the OK and Cancel buttons the same size // QtUtilities::makeButtonsSameSize(ok, cancel); } /** * Destructor. */ GuiCommunicatorClientConnectDialog::~GuiCommunicatorClientConnectDialog() { } /** * Get the hostname. */ QString GuiCommunicatorClientConnectDialog::getHostName() const { return hostNameLineEdit->text(); } /** * Get the control port. */ int GuiCommunicatorClientConnectDialog::getControlPort() const { return controlPortSpinBox->value(); } /** * Get the data port. */ int GuiCommunicatorClientConnectDialog::getDataPort() const { if (dataPortSpinBox != NULL) { return dataPortSpinBox->value(); } return -1; } /** * Get the request updates selection. */ bool GuiCommunicatorClientConnectDialog::getRequestUpdates() const { if (requestUpdatesCheckBox != NULL) { return requestUpdatesCheckBox->isChecked(); } return true; } caret-5.6.4~dfsg.1.orig/caret/GuiCommaSeparatedValueFileEditor.h0000664000175000017500000001004311572067322024324 0ustar michaelmichael#ifndef __GUI_COMMA_SEPARATED_VALUES_FILE_EDITOR__ #define __GUI_COMMA_SEPARATED_VALUES_FILE_EDITOR__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "CommaSeparatedValueFile.h" #include "GuiFilesModified.h" #include "WuQDialog.h" class QComboBox; class QStackedWidget; class QTableWidget; class StringTable; class QToolButton; /// main window for editing comma separated files class GuiCommaSeparatedValueFileEditorMainWindow : public QMainWindow { Q_OBJECT public: // constructor GuiCommaSeparatedValueFileEditorMainWindow(AbstractFile* dataFileIn, const GuiFilesModified& filesModified, QWidget* parent = 0); // destructor ~GuiCommaSeparatedValueFileEditorMainWindow(); // enable/disable row addition and deletion void setRowAdditionDeletionEnabled(const bool enabled); // check for data file changes void checkForFileChanges(); protected slots: // called if a cell is double clicked. void slotTableCellDoubleClicked(int row,int col); // called if a cell's contents are changed void slotCellChanged(int row, int col); // header selected void rowSelected(int row); // called to add a row void addRow(); // called to delete a row void deleteRows(); protected: // add a data section to the dialog void addDataSection(const StringTable* dataSection); /// data section combo box selection QComboBox* dataSectionComboBox; /// stacked widget for data sections QStackedWidget* dataSectionsStackedWidget; /// the file being edited AbstractFile* dataFile; /// for file modification update GuiFilesModified filesModified; /// the comma separated values version of the input file CommaSeparatedValueFile csvFile; /// the file data file beging edited /// the table widgets QVector tableWidgets; /// the table has been modified QVector tableHasBeenModified; /// add rows tool button QToolButton* addRowToolButton; /// delete rows tool button QToolButton* deleteRowToolButton; /// file editing is allowed bool fileEditingAllowed; }; /// dialog for editing a comma separated values file class GuiCommaSeparatedValueFileEditor : public WuQDialog { Q_OBJECT public: // constructor GuiCommaSeparatedValueFileEditor(QWidget* parent, AbstractFile* dataFileIn, const GuiFilesModified& filesModified); // destructor ~GuiCommaSeparatedValueFileEditor(); // enable/disable row addition and deletion void setRowAdditionDeletionEnabled(const bool enabled); protected slots: // called when close button pressed void slotCloseButtonPressed(); protected: // editor main window GuiCommaSeparatedValueFileEditorMainWindow* editorMainWindow; }; #endif // __GUI_COMMA_SEPARATED_VALUES_FILE_EDITOR__ caret-5.6.4~dfsg.1.orig/caret/GuiCommaSeparatedValueFileEditor.cxx0000664000175000017500000003630011572067322024703 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "CellFile.h" #include "CellProjectionFile.h" #include "FileUtilities.h" #include "GuiCommaSeparatedValueFileEditor.h" #include "GuiBrainModelOpenGL.h" #include "GuiMainWindow.h" #include "QtTextEditDialog.h" #include "StringTable.h" #include "global_variables.h" /** * constructor. */ GuiCommaSeparatedValueFileEditor::GuiCommaSeparatedValueFileEditor(QWidget* parent, AbstractFile* dataFileIn, const GuiFilesModified& filesModified) : WuQDialog(parent) { // // Request that this dialog be deleted when closed // setAttribute(Qt::WA_DeleteOnClose); setWindowTitle("Edit File " + FileUtilities::basename(dataFileIn->getFileName())); // // The editor main window // editorMainWindow = new GuiCommaSeparatedValueFileEditorMainWindow(dataFileIn, filesModified); // // Get the layout for the dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); // // Layout dialog items // dialogLayout->addWidget(editorMainWindow); // // Dialog buttons // QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); buttonBox->button(QDialogButtonBox::Close)->setAutoDefault(false); dialogLayout->addWidget(buttonBox); QObject::connect(buttonBox, SIGNAL(rejected()), this, SLOT(slotCloseButtonPressed())); } /** * destructor. */ GuiCommaSeparatedValueFileEditor::~GuiCommaSeparatedValueFileEditor() { } /** * enable/disable row addition and deletion. */ void GuiCommaSeparatedValueFileEditor::setRowAdditionDeletionEnabled(const bool enabled) { editorMainWindow->setRowAdditionDeletionEnabled(enabled); } /** * called when close button pressed. */ void GuiCommaSeparatedValueFileEditor::slotCloseButtonPressed() { editorMainWindow->checkForFileChanges(); WuQDialog::close(); } //-------------------------------------------------------------------------------- /** * constructor. */ GuiCommaSeparatedValueFileEditorMainWindow::GuiCommaSeparatedValueFileEditorMainWindow( AbstractFile* dataFileIn, const GuiFilesModified& filesModifiedIn, QWidget* parent) : QMainWindow(parent) { filesModified = filesModifiedIn; dataFile = dataFileIn; dataFile->writeDataIntoCommaSeparatedValueFile(csvFile); // // the toolbar // QToolBar* toolBar = new QToolBar; addToolBar(toolBar); // // Add Row(s) toolbar button // QAction* addRowAction = new QAction("Add\nRow", this); addRowAction->setToolTip("Add a row after the\n" "last selected row."); QObject::connect(addRowAction, SIGNAL(triggered()), this, SLOT(addRow())); addRowToolButton = new QToolButton; addRowToolButton->setDefaultAction(addRowAction); toolBar->addWidget(addRowToolButton); // // Delete Row(s) toolbar button // QAction* deleteRowAction = new QAction("Delete\nRow(s)", this); deleteRowAction->setToolTip("Delete the\n" "selected row(s)"); QObject::connect(deleteRowAction, SIGNAL(triggered()), this, SLOT(deleteRows())); deleteRowToolButton = new QToolButton; deleteRowToolButton->setDefaultAction(deleteRowAction); toolBar->addWidget(deleteRowToolButton); // // Widget stack for data sections // dataSectionsStackedWidget = new QStackedWidget; // // data section selections // QLabel* dataSectionLabel = new QLabel("Data Section"); dataSectionComboBox = new QComboBox; QObject::connect(dataSectionComboBox, SIGNAL(activated(int)), dataSectionsStackedWidget, SLOT(setCurrentIndex(int))); QHBoxLayout* dataSectionLayout = new QHBoxLayout; dataSectionLayout->addWidget(dataSectionLabel); dataSectionLayout->addWidget(dataSectionComboBox); dataSectionLayout->setStretchFactor(dataSectionLabel, 0); dataSectionLayout->setStretchFactor(dataSectionComboBox, 100); // // Add data sections to dialog // for (int i = 0; i < csvFile.getNumberOfDataSections(); i++) { addDataSection(csvFile.getDataSection(i)); } // // Layout for main window // QWidget* w = new QWidget; QVBoxLayout* layout = new QVBoxLayout(w); layout->addLayout(dataSectionLayout); layout->addWidget(dataSectionsStackedWidget); // // Set widget for the main window // setCentralWidget(w); // // See if data file can be read from comma separated file // bool readFromCSV, writeToCSV; dataFile->getCommaSeparatedFileSupport(readFromCSV, writeToCSV); // // enable/disable editing // fileEditingAllowed = false; if (readFromCSV) { //if ((dynamic_cast(dataFile) != NULL) || // (dynamic_cast(dataFile) != NULL)) { fileEditingAllowed = true; //} } setRowAdditionDeletionEnabled(fileEditingAllowed); } /** * destructor. */ GuiCommaSeparatedValueFileEditorMainWindow::~GuiCommaSeparatedValueFileEditorMainWindow() { } /** * check for data file changes. */ void GuiCommaSeparatedValueFileEditorMainWindow::checkForFileChanges() { if (fileEditingAllowed) { const int num = static_cast(tableWidgets.size()); bool modifiedFlag = false; for (int i = 0; i < num; i++) { if (tableHasBeenModified[i]) { modifiedFlag = true; } } if (modifiedFlag) { if (QMessageBox::question(this, "Apply Changes", "Data has been modified. Apply Changes?", (QMessageBox::Yes | QMessageBox::No), QMessageBox::Yes) == QMessageBox::Yes) { for (int i = 0; i < num; i++) { if (tableHasBeenModified[i]) { QTableWidget* tw = tableWidgets[i]; const int rows = tw->rowCount(); const int cols = tw->columnCount(); StringTable* st = csvFile.getDataSection(i); QVector columnTitles; for (int j = 0; j < cols; j++) { columnTitles.push_back(st->getColumnTitle(j)); } st->setNumberOfRowsAndColumns(rows, cols, st->getTableTitle()); for (int j = 0; j < cols; j++) { st->setColumnTitle(j, columnTitles.at(j)); } for (int k = 0; k < rows; k++) { for (int j = 0; j < cols; j++) { st->setElement(k, j, tw->item(k, j)->text()); } } } } dataFile->readDataFromCommaSeparatedValuesTable(csvFile); theMainWindow->fileModificationUpdate(filesModified); GuiBrainModelOpenGL::updateAllGL(); } } } } /** * enable/disable row addition and deletion. */ void GuiCommaSeparatedValueFileEditorMainWindow::setRowAdditionDeletionEnabled(const bool enabled) { addRowToolButton->setEnabled(enabled); deleteRowToolButton->setEnabled(enabled); } /** * called to add a row. */ void GuiCommaSeparatedValueFileEditorMainWindow::addRow() { QTableWidget* tw = dynamic_cast(dataSectionsStackedWidget->currentWidget()); if (tw != NULL) { int lastRow = -1; QList sel = tw->selectedRanges(); for (int i = 0; i < sel.size(); i++) { QTableWidgetSelectionRange twsr = sel.at(i); lastRow = std::max(lastRow, twsr.bottomRow()); } if (lastRow >= 0) { tw->insertRow(lastRow+1); slotCellChanged(lastRow+1, 0); } else { QMessageBox::information(this, "INFO", "A row must be selected before pressing the Add Row button. \n" "Select a row by clicking on the row number in the left column."); } } } /** * called to delete a row. */ void GuiCommaSeparatedValueFileEditorMainWindow::deleteRows() { QTableWidget* tw = dynamic_cast(dataSectionsStackedWidget->currentWidget()); if (tw != NULL) { std::set > rowsToDelete; // DESCENDING ORDER QList sel = tw->selectedRanges(); for (int i = 0; i < sel.size(); i++) { QTableWidgetSelectionRange twsr = sel.at(i); if (twsr.columnCount() == tw->columnCount()) { for (int j = twsr.topRow(); j <= twsr.bottomRow(); j++) { rowsToDelete.insert(j); } } } if (rowsToDelete.empty() == false) { for (std::set >::iterator iter = rowsToDelete.begin(); iter != rowsToDelete.end(); iter++) { //std::cout << "Deleting row: " << *iter << std::endl; slotCellChanged(*iter, 0); tw->removeRow(*iter); } } else { QMessageBox::information(this, "INFO", "One or more rows must be selected before pressing the Delete Row(s)\n" "button. Select a row by clicking on the row number in the left column."); } } } /** * called if a cell's contents are changed. */ void GuiCommaSeparatedValueFileEditorMainWindow::slotCellChanged(int /*row*/, int /*col*/) { const int indx = dataSectionsStackedWidget->currentIndex(); if ((indx >= 0) && (indx < tableHasBeenModified.size())) { tableHasBeenModified[indx] = true; } //std::cout << "Table modified" << std::endl; } /** * called if a cell is double clicked. */ void GuiCommaSeparatedValueFileEditorMainWindow::slotTableCellDoubleClicked(int row,int col) { QTableWidget* tw = dynamic_cast(dataSectionsStackedWidget->currentWidget()); if (tw != NULL) { // // Get the table widget item that was clicked // QTableWidgetItem* twi = tw->item(row, col); // // Load the text from the table's cell into a text editor // QtTextEditDialog te(this, (fileEditingAllowed == false), // NOT read-only true); // modal const QString cellText(twi->text()); te.setText(cellText); if (te.exec() == QtTextEditDialog::Accepted) { const QString newText(te.getText()); if (cellText != newText) { twi->setText(newText); } } } } /** * header selected. */ void GuiCommaSeparatedValueFileEditorMainWindow::rowSelected(int /*row*/) { //std::cout << "Selected row: " << row << std::endl; /* QTableWidget* tw = dynamic_cast(dataSectionsStackedWidget->currentWidget()); if (tw != NULL) { QHeaderView* vertHeader = tw->verticalHeader(); for (int i = 0; i < vertHeader->count(); i++) { const QTableWidgetItem* twi = tw->verticalHeaderItem(i); if (tw->isItemSelected(twi)) { std::cout << "Row " << i << " is selected." << std::endl; } else { std::cout << "Row " << i << " is NOT selected." << std::endl; } } std::cout << "Current Row: " << tw->currentRow() << std::endl; QList sel = tw->selectedRanges(); for (int i = 0; i < sel.size(); i++) { QTableWidgetSelectionRange twsr = sel.at(i); std::cout << "Selection range: " << std::endl; std::cout << "bottom row: " << twsr.bottomRow() << std::endl; std::cout << "column count: " << twsr.columnCount() << std::endl; std::cout << "left column: " << twsr.leftColumn() << std::endl; std::cout << "right column: " << twsr.rightColumn() << std::endl; std::cout << "row count: " << twsr.rowCount() << std::endl; std::cout << "top row: " << twsr.topRow() << std::endl; } } */ } /** * add a data section to the dialog. */ void GuiCommaSeparatedValueFileEditorMainWindow::addDataSection(const StringTable* dataSection) { // // Verify data in table // const int numRows = dataSection->getNumberOfRows(); const int numCols = dataSection->getNumberOfColumns(); if ((numRows <= 0) || (numCols <= 0)) { return; } // // Create a QTableWidget for the data // QTableWidget* tableWidget = new QTableWidget(numRows, numCols); tableWidgets.push_back(tableWidget); tableHasBeenModified.push_back(false); // // Display editor for double clicks // QObject::connect(tableWidget, SIGNAL(cellDoubleClicked(int,int)), this, SLOT(slotTableCellDoubleClicked(int,int))); // // Track changes to table widgets // QObject::connect(tableWidget, SIGNAL(cellChanged(int,int)), this, SLOT(slotCellChanged(int,int))); // // row selected // QObject::connect(tableWidget->verticalHeader(), SIGNAL(sectionClicked(int)), this, SLOT(rowSelected(int))); // // Set the column titles // QStringList columnLabels; for (int i = 0; i < numCols; i++) { columnLabels << dataSection->getColumnTitle(i); } tableWidget->setHorizontalHeaderLabels(columnLabels); // // Load the table // tableWidget->blockSignals(true); for (int i = 0; i < numRows; i++) { for (int j = 0; j < numCols; j++) { tableWidget->setItem(i, j, new QTableWidgetItem(dataSection->getElement(i, j))); } } tableWidget->blockSignals(false); // // Add to widget stack // dataSectionsStackedWidget->addWidget(tableWidget); // // add to combo box // QString name(dataSection->getTableTitle()); if (name.isEmpty()) { name = "Data Item " + QString::number(dataSectionComboBox->count()); } dataSectionComboBox->addItem(name); } caret-5.6.4~dfsg.1.orig/caret/GuiColorSelectionDialog.h0000664000175000017500000001007711572067322022546 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_GUI_COLOR_SELECTION_DIALOG_H__ #define __VE_GUI_COLOR_SELECTION_DIALOG_H__ #include #include #include "WuQDialog.h" #include "ColorFile.h" class QComboBox; class QSlider; class QSpinBox; class QDoubleSpinBox; /// This modal dialog is used to select a single color. class GuiColorSelectionDialog : public WuQDialog { Q_OBJECT public: // Constructor GuiColorSelectionDialog(QWidget* parent, const QString& title, const bool showAlpha, const bool showPointSize, const bool showLineSize, const bool showSymbol); // Destructor ~GuiColorSelectionDialog(); // get the color information void getColorInformation(unsigned char& r, unsigned char& g, unsigned char& b, unsigned char& a, float& pointSize, float& lineSize, ColorFile::ColorStorage::SYMBOL& symbol); // set the color void setColor(const unsigned char r, const unsigned char g, const unsigned char b, const unsigned char a); private slots: /// called when the red slider is moved void redSliderMovedSlot(int value); /// called when the green slider is moved void greenSliderMovedSlot(int value); /// called when the blue slider is moved void blueSliderMovedSlot(int value); /// called when the alpha slider is moved void alphaSliderMovedSlot(int value); /// called when dialog closed void done(int r); /// called when color chooser button is pressed. void slotColorChooserButton(); /// called when web name push button pressed void slotWebHtmlColorNamesPushButton(); private: /// initialize the controls using the current "color" void initializeControls(); /// update the color of the color swatch void updateColorSwatch(); /// the color swatch QWidget* colorSwatch; /// the red spin box QSpinBox* redSpinBox; /// the red slider QSlider* redSlider; /// the green spin box QSpinBox* greenSpinBox; /// the green slider QSlider* greenSlider; /// the blue spin box QSpinBox* blueSpinBox; /// the blue slider QSlider* blueSlider; /// the alpha spin box QSpinBox* alphaSpinBox; /// the alpha slider QSlider* alphaSlider; /// the line size spin box QDoubleSpinBox* lineSizeDoubleSpinBox; /// the point size spin box QDoubleSpinBox* pointSizeDoubleSpinBox; /// the symbol combo box QComboBox* symbolComboBox; /// the color of the color swatch QColor color; /// the alpha value unsigned char colorAlpha; /// point size float pointSize; /// line size float lineSize; }; #endif // __VE_GUI_COLOR_SELECTION_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiColorSelectionDialog.cxx0000664000175000017500000003545111572067322023124 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include "BrainSet.h" #include "GuiBrainModelOpenGL.h" #include "GuiColorSelectionDialog.h" #include "GuiHtmlColorChooserDialog.h" #include "GuiMainWindow.h" #include #include "global_variables.h" /** * Constructor */ GuiColorSelectionDialog::GuiColorSelectionDialog(QWidget* parent, const QString& title, const bool showAlpha, const bool showPointSize, const bool showLineSize, const bool showSymbol) : WuQDialog(parent) { setModal(true); setWindowTitle(title); // // Initialize color to foreground color // unsigned char red, green, blue; PreferencesFile* pref = theMainWindow->getBrainSet()->getPreferencesFile(); pref->getSurfaceForegroundColor(red, green, blue); color.setRgb(red, green, blue); colorAlpha = 255; // // layout for dialog // QVBoxLayout* rows = new QVBoxLayout(this); rows->setMargin(5); // // "Color swatch" widget // QGroupBox* swatchGroup = new QGroupBox("Color Swatch"); rows->addWidget(swatchGroup); QVBoxLayout* swatchGroupLayout = new QVBoxLayout(swatchGroup); colorSwatch = new QWidget; swatchGroupLayout->addWidget(colorSwatch); colorSwatch->setMinimumSize(QSize(50, 50)); colorSwatch->setMaximumHeight(50); // // Grid Layout for Colors Sliders // QGridLayout* sliderGrid = new QGridLayout; rows->addLayout(sliderGrid); sliderGrid->setMargin(3); sliderGrid->setSpacing(5); // // Red control // sliderGrid->addWidget(new QLabel("Red"), 0, 0, Qt::AlignLeft); redSpinBox = new QSpinBox; redSpinBox->setMinimum(0); redSpinBox->setMaximum(255); redSpinBox->setSingleStep(1); sliderGrid->addWidget(redSpinBox, 0, 1, Qt::AlignRight); redSlider = new QSlider(Qt::Horizontal); redSlider->setMinimumWidth(300); redSlider->setMinimum(0); redSlider->setMaximum(255); redSlider->setPageStep(5); redSlider->setValue(red); QObject::connect(redSlider, SIGNAL(valueChanged(int)), redSpinBox, SLOT(setValue(int))); QObject::connect(redSlider, SIGNAL(valueChanged(int)), this, SLOT(redSliderMovedSlot(int))); QObject::connect(redSpinBox, SIGNAL(valueChanged(int)), redSlider, SLOT(setValue(int))); QObject::connect(redSpinBox, SIGNAL(valueChanged(int)), this, SLOT(redSliderMovedSlot(int))); sliderGrid->addWidget(redSlider, 0, 2, Qt::AlignLeft); // // Green control // sliderGrid->addWidget(new QLabel("Green"), 1, 0, Qt::AlignLeft); greenSpinBox = new QSpinBox; greenSpinBox->setMinimum(0); greenSpinBox->setMaximum(255); greenSpinBox->setSingleStep(1); sliderGrid->addWidget(greenSpinBox, 1, 1, Qt::AlignRight); greenSlider = new QSlider(Qt::Horizontal); greenSlider->setMinimum(0); greenSlider->setMaximum(255); greenSlider->setPageStep(5); greenSlider->setMinimumWidth(300); greenSlider->setValue(green); QObject::connect(greenSlider, SIGNAL(valueChanged(int)), greenSpinBox, SLOT(setValue(int))); QObject::connect(greenSlider, SIGNAL(valueChanged(int)), this, SLOT(greenSliderMovedSlot(int))); QObject::connect(greenSpinBox, SIGNAL(valueChanged(int)), greenSlider, SLOT(setValue(int))); QObject::connect(greenSpinBox, SIGNAL(valueChanged(int)), this, SLOT(greenSliderMovedSlot(int))); sliderGrid->addWidget(greenSlider, 1, 2, Qt::AlignLeft); // // Blue control // sliderGrid->addWidget(new QLabel("Blue"), 2, 0, Qt::AlignLeft); blueSpinBox = new QSpinBox; blueSpinBox->setMinimum(0); blueSpinBox->setMaximum(255); blueSpinBox->setSingleStep(1); sliderGrid->addWidget(blueSpinBox, 2, 1, Qt::AlignRight); blueSlider = new QSlider(Qt::Horizontal); blueSlider->setMinimum(0); blueSlider->setMaximum(255); blueSlider->setPageStep(5); blueSlider->setMinimumWidth(300); blueSlider->setValue(blue); QObject::connect(blueSlider, SIGNAL(valueChanged(int)), blueSpinBox, SLOT(setValue(int))); QObject::connect(blueSlider, SIGNAL(valueChanged(int)), this, SLOT(blueSliderMovedSlot(int))); QObject::connect(blueSpinBox, SIGNAL(valueChanged(int)), blueSlider, SLOT(setValue(int))); QObject::connect(blueSpinBox, SIGNAL(valueChanged(int)), this, SLOT(blueSliderMovedSlot(int))); sliderGrid->addWidget(blueSlider, 2, 2, Qt::AlignLeft); // // Alpha control // QLabel* alphaLabel = new QLabel("Alpha"); sliderGrid->addWidget(alphaLabel, 3, 0, Qt::AlignLeft); alphaSpinBox = new QSpinBox; alphaSpinBox->setMinimum(0); alphaSpinBox->setMaximum(255); alphaSpinBox->setSingleStep(1); sliderGrid->addWidget(alphaSpinBox, 3, 1, Qt::AlignRight); alphaSlider = new QSlider(Qt::Horizontal); alphaSlider->setMinimum(0); alphaSlider->setMaximum(255); alphaSlider->setPageStep(5); alphaSlider->setMinimumWidth(300); alphaSlider->setValue(colorAlpha); QObject::connect(alphaSlider, SIGNAL(valueChanged(int)), alphaSpinBox, SLOT(setValue(int))); QObject::connect(alphaSlider, SIGNAL(valueChanged(int)), this, SLOT(alphaSliderMovedSlot(int))); QObject::connect(alphaSpinBox, SIGNAL(valueChanged(int)), alphaSlider, SLOT(setValue(int))); QObject::connect(alphaSpinBox, SIGNAL(valueChanged(int)), this, SLOT(alphaSliderMovedSlot(int))); sliderGrid->addWidget(alphaSlider, 3, 2, Qt::AlignLeft); if (showAlpha == false) { alphaLabel->hide(); alphaSpinBox->hide(); alphaSlider->hide(); } // // Pushbutton for color chooser // QPushButton* colorChooserButton = new QPushButton("Advanced Color Selection..."); colorChooserButton->setAutoDefault(false); colorChooserButton->setToolTip( "Press this button to pop up a dialog\n" "with more powerful color selection."); colorChooserButton->setFixedSize(colorChooserButton->sizeHint()); QObject::connect(colorChooserButton, SIGNAL(clicked()), this, SLOT(slotColorChooserButton())); // // Pushbutton for web (html) colors // QPushButton* webHtmlColorPushButton = new QPushButton("List of Common Colors..."); webHtmlColorPushButton->setAutoDefault(false); webHtmlColorPushButton->setToolTip( "Press this button to select colors\n" "defined by the World Wide Web Consortium"); webHtmlColorPushButton->setFixedSize(webHtmlColorPushButton->sizeHint()); QObject::connect(webHtmlColorPushButton, SIGNAL(clicked()), this, SLOT(slotWebHtmlColorNamesPushButton())); // // Layout for color buttons // QHBoxLayout* colorPushButtonsLayout = new QHBoxLayout; colorPushButtonsLayout->addWidget(colorChooserButton); colorPushButtonsLayout->addWidget(webHtmlColorPushButton); colorPushButtonsLayout->addStretch(); rows->addLayout(colorPushButtonsLayout); // // Grid Layout for Line and Point Size // QGridLayout* linePointSizeGrid = new QGridLayout; rows->addLayout(linePointSizeGrid); linePointSizeGrid->setMargin(2); linePointSizeGrid->setSpacing(5); float minLineSize, maxLineSize; GuiBrainModelOpenGL::getLineWidthRange(minLineSize, maxLineSize); QLabel* lineSizeLabel = new QLabel("Line Size"); linePointSizeGrid->addWidget(lineSizeLabel, 0, 0, Qt::AlignLeft); lineSizeDoubleSpinBox = new QDoubleSpinBox; lineSizeDoubleSpinBox->setMinimum(minLineSize); lineSizeDoubleSpinBox->setMaximum(maxLineSize); lineSizeDoubleSpinBox->setSingleStep(1.0); lineSizeDoubleSpinBox->setDecimals(1); lineSizeDoubleSpinBox->setValue(1); linePointSizeGrid->addWidget(lineSizeDoubleSpinBox, 0, 1, Qt::AlignLeft); if (showLineSize == false) { lineSizeLabel->hide(); lineSizeDoubleSpinBox->hide(); } float minPointSize, maxPointSize; GuiBrainModelOpenGL::getPointSizeRange(minPointSize, maxPointSize); maxPointSize = 100000.0; QLabel* pointSizeLabel = new QLabel("Point Size"); linePointSizeGrid->addWidget(pointSizeLabel, 1, 0, Qt::AlignLeft); pointSizeDoubleSpinBox = new QDoubleSpinBox; pointSizeDoubleSpinBox->setMinimum(minPointSize); pointSizeDoubleSpinBox->setMaximum(maxPointSize); pointSizeDoubleSpinBox->setSingleStep(1.0); pointSizeDoubleSpinBox->setDecimals(1); pointSizeDoubleSpinBox->setValue(2); linePointSizeGrid->addWidget(pointSizeDoubleSpinBox, 1, 1, Qt::AlignLeft); if (showPointSize == false) { pointSizeLabel->hide(); pointSizeDoubleSpinBox->hide(); } // // Symbol // QLabel* symbolLabel = new QLabel("Symbol"); linePointSizeGrid->addWidget(symbolLabel, 2, 0, Qt::AlignLeft); symbolComboBox = new QComboBox; linePointSizeGrid->addWidget(symbolComboBox, 2, 1, Qt::AlignLeft); std::vector symbolLabels; ColorFile::ColorStorage::getAllSymbolTypesAsStrings(symbolLabels); for (unsigned int i = 0; i < symbolLabels.size(); i++) { symbolComboBox->addItem(symbolLabels[i]); } symbolComboBox->setCurrentIndex(ColorFile::ColorStorage::SYMBOL_OPENGL_POINT); if (showSymbol == false) { symbolLabel->hide(); symbolComboBox->hide(); } initializeControls(); // // Dialog Buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; rows->addLayout(buttonsLayout); // // OK button // QPushButton* ok = new QPushButton("OK", this); ok->setFixedSize(ok->sizeHint()); QObject::connect(ok, SIGNAL(clicked()), this, SLOT(accept())); ok->setAutoDefault(false); buttonsLayout->addWidget(ok); } /** * Destructor */ GuiColorSelectionDialog::~GuiColorSelectionDialog() { } /** * set the color. */ void GuiColorSelectionDialog::setColor(const unsigned char r, const unsigned char g, const unsigned char b, const unsigned char a) { color.setRgb(r, g, b, a); initializeControls(); } /** * called when color chooser button is pressed. */ void GuiColorSelectionDialog::slotColorChooserButton() { // // Popup QT's color chooser dialog // QColor outputColor = QColorDialog::getColor(color, this); if (outputColor.isValid()) { color = outputColor; initializeControls(); } } /** * Initialize the controls */ void GuiColorSelectionDialog::initializeControls() { redSlider->setValue(color.red()); redSpinBox->setValue(color.red()); greenSlider->setValue(color.green()); greenSpinBox->setValue(color.green()); blueSlider->setValue(color.blue()); blueSpinBox->setValue(color.blue()); alphaSlider->setValue(colorAlpha); alphaSpinBox->setValue(colorAlpha); updateColorSwatch(); } /** * Update the color swatch */ void GuiColorSelectionDialog::updateColorSwatch() { //colorSwatch->setPaletteBackgroundColor(color); QPalette pal; pal.setColor(QPalette::Window, color); colorSwatch->setAutoFillBackground(true); colorSwatch->setBackgroundRole(QPalette::Window); colorSwatch->setPalette(pal); } /** * Slot called when the red slider is moved. */ void GuiColorSelectionDialog::redSliderMovedSlot(int value) { color.setRgb(value, color.green(), color.blue()); updateColorSwatch(); } /** * Slot called when the green slider is moved. */ void GuiColorSelectionDialog::greenSliderMovedSlot(int value) { color.setRgb(color.red(), value, color.blue()); updateColorSwatch(); } /** * Slot called when the blue slider is moved. */ void GuiColorSelectionDialog::blueSliderMovedSlot(int value) { color.setRgb(color.red(), color.green(), value); updateColorSwatch(); } /** * Slot called when the alpha slider is moved. */ void GuiColorSelectionDialog::alphaSliderMovedSlot(int value) { colorAlpha = value; updateColorSwatch(); } /** * Called when dialog closed. */ void GuiColorSelectionDialog::done(int r) { color.setRgb(redSpinBox->value(), greenSpinBox->value(), blueSpinBox->value()); colorAlpha = alphaSpinBox->value(); if (pointSizeDoubleSpinBox != NULL) { pointSize = pointSizeDoubleSpinBox->value(); } else { pointSize = 2.0; } if (lineSizeDoubleSpinBox != NULL) { lineSize = lineSizeDoubleSpinBox->value(); } else { lineSize = 1.0; } QDialog::done(r); } /** * Get the color information */ void GuiColorSelectionDialog::getColorInformation(unsigned char& r, unsigned char& g, unsigned char& b, unsigned char& a, float& pointSizeOut, float& lineSizeOut, ColorFile::ColorStorage::SYMBOL& symbol) { r = static_cast(color.red()); g = static_cast(color.green()); b = static_cast(color.blue()); a = static_cast(colorAlpha); pointSizeOut = pointSize; lineSizeOut = lineSize; symbol = static_cast(symbolComboBox->currentIndex()); } /** * called when web name push button pressed. */ void GuiColorSelectionDialog::slotWebHtmlColorNamesPushButton() { GuiHtmlColorChooserDialog ghccd(this); if (ghccd.exec() == GuiHtmlColorChooserDialog::Accepted) { QString name; unsigned char r, g, b; ghccd.getSelectedColor(name, r, g, b); color.setRed(static_cast(r)); color.setGreen(static_cast(g)); color.setBlue(static_cast(b)); color.setAlpha(255); initializeControls(); } } caret-5.6.4~dfsg.1.orig/caret/GuiColorKeyDialog.h0000664000175000017500000001453411572067322021353 0ustar michaelmichael#ifndef __GUI_COLOR_KEY_DIALOG_H__ #define __GUI_COLOR_KEY_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "WuQDialog.h" #include "SceneFile.h" class BrainSet; class GuiColorKeyLabel; class QGridLayout; class QMouseEvent; /// dialog for viewing colors assigned to names class GuiColorKeyDialog : public WuQDialog { Q_OBJECT public: /// types for color keys enum COLOR_KEY { /// areal estimation COLOR_KEY_AREAL_ESTIMATION, /// borders COLOR_KEY_BORDERS, /// cells COLOR_KEY_CELLS, /// foci COLOR_KEY_FOCI, /// paint file COLOR_KEY_PAINT, /// probabilistic atlas COLOR_KEY_PROBABILISTIC_ATLAS, /// volume paint COLOR_KEY_VOLUME_PAINT, /// volume probabilistic atlas COLOR_KEY_VOLUME_PROBABILISTIC_ATLAS }; // constructor GuiColorKeyDialog(QWidget* parent, const COLOR_KEY colorKeyIn); // destructor ~GuiColorKeyDialog(); /// save scene SceneFile::SceneClass saveScene(); /// show scene void showScene(const SceneFile::SceneClass sc, const int screenMaxX, const int screenMaxY, const int mainWindowSceneX, const int mainWindowSceneY, const int mainWindowX, const int mainWindowY); /// get the title for the window static QString getTitleOfColorKey(const COLOR_KEY cc); public slots: // update the dialog void updateDialog(); protected slots: // called when a color label is clicked void slotColorLabelClicked(const int); // called when a name label is clicked void slotNameLabelClicked(const QString& name); // clear highlighting void slotClearHighlighting(); protected: /// name and color holder class NameAndColor { public: /// constructor NameAndColor(const QString& nameIn, const int redIn, const int greenIn, const int blueIn); /// destructor ~NameAndColor(); /// less than operator bool operator<(const NameAndColor& nac) const; /// equality operator bool operator==(const NameAndColor& nac) const; /// name QString name; /// red value int red; /// green value int green; /// blue value int blue; /// highlighted flag bool highlightedFlag; }; // update areal estimation key void updateArealEstimationKey(BrainSet* bs, std::vector& names); // update border key void updateBorderKey(BrainSet* bs, std::vector& names); // update cell key void updateCellKey(BrainSet* bs, std::vector& names); // update foci key void updateFociKey(BrainSet* bs, std::vector& names); // update paint key void updatePaintKey(BrainSet* bs, std::vector& names); // update prob atlas key void updateProbAtlasKey(BrainSet* bs, std::vector& names); // update volume paint key void updateVolumePaintKey(BrainSet* bs, std::vector& names); // update volume prob atlas key void updateVolumeProbAtlasKey(BrainSet* bs, std::vector& names); // display study matching a foci color void displayStudyMatchingFociColor(const QString& colorName); /// the names and colors in the dialog std::vector nameTable; /// update a color label void updateColorLabel(const int indx); /// type of color key in the dialog COLOR_KEY colorKey; /// layout for color grid QGridLayout* colorGridLayout; /// color labels in the color grid std::vector colorLabelsInColorGrid; /// name labels in the color grid std::vector nameLabelsInColorGrid; }; /// class for a color key label class GuiColorKeyLabel : public QLabel { Q_OBJECT public: // constructor GuiColorKeyLabel(QWidget* parent = 0); // destructor ~GuiColorKeyLabel(); // set the area name void setAreaName(const QString& areaNameIn); // set name table index void setNameTableIndex(const int indx); signals: // emitted when the mouse is pressed void signalShowAreaName(const QString&); // emitted when the mouse is pressed void signalNameTableIndex(const int); protected: // called when a mouse button is pressed over this widget void mousePressEvent(QMouseEvent* me); // name of area associated with this label QString areaName; // index in name table int nameTableIndex; }; #endif // __GUI_COLOR_KEY_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiColorKeyDialog.cxx0000664000175000017500000012513011572067322021721 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include "AreaColorFile.h" #include "ArealEstimationFile.h" #include "BorderColorFile.h" #include "BorderProjectionFile.h" #include "BrainSet.h" #include "BrainModelBorderSet.h" #include "BrainModelIdentification.h" #include "BrainModelSurface.h" #include "BrainModelVolume.h" #include "CellColorFile.h" #include "CellFile.h" #include "CellProjectionFile.h" #include "ColorFile.h" #include "DisplaySettingsArealEstimation.h" #include "DisplaySettingsBorders.h" #include "DisplaySettingsFoci.h" #include "DisplaySettingsPaint.h" #include "DisplaySettingsProbabilisticAtlas.h" #include "DisplaySettingsScene.h" #include "FociColorFile.h" #include "FociProjectionFile.h" #include "GuiBrainModelOpenGL.h" #include "GuiColorKeyDialog.h" #include "GuiIdentifyDialog.h" #include "GuiMainWindow.h" #include "NameIndexSort.h" #include "PaintFile.h" #include "ProbabilisticAtlasFile.h" #include "StringUtilities.h" #include "StudyMetaDataFile.h" #include "VocabularyFile.h" #include "VolumeFile.h" #include "global_variables.h" /** * constructor. */ GuiColorKeyDialog::GuiColorKeyDialog(QWidget* parent, const COLOR_KEY colorKeyIn) : WuQDialog(parent) { colorKey = colorKeyIn; // // Dialog buttons // QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); buttonBox->button(QDialogButtonBox::Close)->setAutoDefault(false); QObject::connect(buttonBox, SIGNAL(rejected()), this, SLOT(close())); QPushButton* updatePushButton = new QPushButton("Update"); buttonBox->addButton(updatePushButton, QDialogButtonBox::ActionRole); QObject::connect(updatePushButton, SIGNAL(clicked()), this, SLOT(updateDialog())); QPushButton* clearPushButton = new QPushButton("Clear Highlighting"); clearPushButton->setAutoDefault(false); QObject::connect(clearPushButton, SIGNAL(clicked()), this, SLOT(slotClearHighlighting())); // // Place the names and a color swatch into the layout // QWidget* gridWidget = new QWidget; colorGridLayout = new QGridLayout(gridWidget); // // Place color key into a scroll view // QScrollArea* scrollArea = new QScrollArea; scrollArea->setWidget(gridWidget); scrollArea->setWidgetResizable(true); // // Add the scroll area to the dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->addWidget(scrollArea); dialogLayout->addWidget(clearPushButton); dialogLayout->addWidget(buttonBox); } /** * destructor. */ GuiColorKeyDialog::~GuiColorKeyDialog() { } /// get the title for the window QString GuiColorKeyDialog::getTitleOfColorKey(const COLOR_KEY cc) { QString title; switch (cc) { case COLOR_KEY_AREAL_ESTIMATION: title = "Areal Estimation Color Key"; break; case COLOR_KEY_BORDERS: title = "Border Color Key"; break; case COLOR_KEY_CELLS: title = "Cell Color Key"; break; case COLOR_KEY_FOCI: title = "Foci Color Key"; break; case COLOR_KEY_PAINT: title = "Paint Color Key"; break; case COLOR_KEY_PROBABILISTIC_ATLAS: title = "Probabilistic Atlas Color Key"; break; case COLOR_KEY_VOLUME_PAINT: title = "Volume Paint Color Key"; break; case COLOR_KEY_VOLUME_PROBABILISTIC_ATLAS: title = "Volume Probabilistic Atlas Color Key"; break; } return title; } /** * update the dialog. */ void GuiColorKeyDialog::updateDialog() { BrainSet* bs = theMainWindow->getBrainSet(); VocabularyFile* vf = bs->getVocabularyFile(); nameTable.clear(); // // Get the color key for the data type displayed // switch (colorKey) { case COLOR_KEY_AREAL_ESTIMATION: updateArealEstimationKey(bs, nameTable); break; case COLOR_KEY_BORDERS: updateBorderKey(bs, nameTable); break; case COLOR_KEY_CELLS: updateCellKey(bs, nameTable); break; case COLOR_KEY_FOCI: updateFociKey(bs, nameTable); break; case COLOR_KEY_PAINT: updatePaintKey(bs, nameTable); break; case COLOR_KEY_PROBABILISTIC_ATLAS: updateProbAtlasKey(bs, nameTable); break; case COLOR_KEY_VOLUME_PAINT: updateVolumePaintKey(bs, nameTable); break; case COLOR_KEY_VOLUME_PROBABILISTIC_ATLAS: updateVolumeProbAtlasKey(bs, nameTable); break; } // // Set the window title // setWindowTitle(getTitleOfColorKey(colorKey)); // // Sort and remove any duplicates // std::sort(nameTable.begin(), nameTable.end()); std::unique(nameTable.begin(), nameTable.end()); // // Load color labels // const int numTableNames = static_cast(nameTable.size()); for (int i = 0; i < numTableNames; i++) { // // Use existing label or create new label if it is needed // GuiColorKeyLabel* colorLabel = NULL; GuiColorKeyLabel* nameLabel = NULL; if (i < static_cast(colorLabelsInColorGrid.size())) { colorLabel = colorLabelsInColorGrid[i]; nameLabel = nameLabelsInColorGrid[i]; } else { // // Create new labels // colorLabel = new GuiColorKeyLabel; QObject::connect(colorLabel, SIGNAL(signalNameTableIndex(const int)), this, SLOT(slotColorLabelClicked(const int))); nameLabel = new GuiColorKeyLabel; QObject::connect(nameLabel, SIGNAL(signalShowAreaName(const QString&)), this, SLOT(slotNameLabelClicked(const QString&))); colorGridLayout->addWidget(colorLabel, i, 0); colorGridLayout->addWidget(nameLabel, i, 1); colorLabelsInColorGrid.push_back(colorLabel); nameLabelsInColorGrid.push_back(nameLabel); switch (colorKey) { case COLOR_KEY_AREAL_ESTIMATION: break; case COLOR_KEY_BORDERS: colorLabel->setToolTip("Click the left mouse button\n" "on this color swatch to \n" "highlight borders using \n" "with this name."); nameLabel->setToolTip("Click the left mouse button\n" "on this control to see vocabulary\n" "information about this name\n" "(if available)."); break; case COLOR_KEY_CELLS: break; case COLOR_KEY_FOCI: break; case COLOR_KEY_PAINT: colorLabel->setToolTip("Click the left mouse button\n" "on this color swatch to \n" "highlight nodes identified \n" "with this name."); nameLabel->setToolTip("Click the left mouse button\n" "on this control to see vocabulary\n" "information about this name\n" "(if available)."); break; case COLOR_KEY_PROBABILISTIC_ATLAS: break; case COLOR_KEY_VOLUME_PAINT: break; case COLOR_KEY_VOLUME_PROBABILISTIC_ATLAS: break; } } // // Set the color label background with color or text if no color available // updateColorLabel(i); /* QColor labelColor(170, 170, 170, 0); bool autoFill = false; bool colorSelected = false; QPalette::ColorRole backgroundRole = QPalette::NoRole; if (nameTable[i].red >= 0) { labelColor.setRgb(nameTable[i].red, nameTable[i].green, nameTable[i].blue, 255); colorLabel->setText(" "); backgroundRole = QPalette::Window; autoFill = true; colorSelected = true; } else { colorLabel->setText("no color"); } QPalette pal; pal.setColor(QPalette::Window, labelColor); if (colorSelected) { QBrush brush(labelColor, Qt::Dense3Pattern); pal.setBrush(QPalette::Window, brush); } colorLabel->setAutoFillBackground(autoFill); colorLabel->setBackgroundRole(backgroundRole); colorLabel->setPalette(pal); colorLabel->setAreaName(nameTable[i].name); */ // // load the name label // if (vf->getBestMatchingVocabularyEntry(nameTable[i].name) != NULL) { nameLabel->setTextFormat(Qt::RichText); nameLabel->setText("" + nameTable[i].name + ""); } else { nameLabel->setTextFormat(Qt::PlainText); nameLabel->setText(nameTable[i].name); } nameLabel->setAreaName(nameTable[i].name); // // Show the labels // colorLabel->setHidden(false); nameLabel->setHidden(false); // // Fix width of color labels // colorLabel->setFixedWidth(100); } // // Hide unneeded labels // const int numDisplayedLabels = colorLabelsInColorGrid.size(); for (int i = 0; i < numDisplayedLabels; i++) { if (i < numTableNames) { colorLabelsInColorGrid[i]->setNameTableIndex(i); colorLabelsInColorGrid[i]->show(); nameLabelsInColorGrid[i]->show(); } else { colorLabelsInColorGrid[i]->hide(); nameLabelsInColorGrid[i]->hide(); } } } /** * update a color label. */ void GuiColorKeyDialog::updateColorLabel(const int indx) { // // Get the label // GuiColorKeyLabel* colorLabel = colorLabelsInColorGrid[indx]; // // Set the color label background with color or text if no color available // QColor labelColor(170, 170, 170, 0); bool autoFill = false; QPalette::ColorRole backgroundRole = QPalette::NoRole; if (nameTable[indx].red >= 0) { labelColor.setRgb(nameTable[indx].red, nameTable[indx].green, nameTable[indx].blue, 255); colorLabel->setText(" "); backgroundRole = QPalette::Window; autoFill = true; } else { colorLabel->setText("no color"); } // // Draw in a pattern if highlighted // QPalette pal; pal.setColor(QPalette::Window, labelColor); if (nameTable[indx].highlightedFlag) { pal.setColor(QPalette::Window, labelColor); } colorLabel->setAutoFillBackground(autoFill); colorLabel->setBackgroundRole(backgroundRole); colorLabel->setPalette(pal); colorLabel->setAreaName(nameTable[indx].name); colorLabel->repaint(); } /** * update areal estimation key. */ void GuiColorKeyDialog::updateArealEstimationKey(BrainSet* bs, std::vector& names) { // // Get files and settings // ArealEstimationFile* aef = bs->getArealEstimationFile(); DisplaySettingsArealEstimation* dsea = bs->getDisplaySettingsArealEstimation(); const int numNodes = aef->getNumberOfNodes(); //const int numColumns = aef->getNumberOfColumns(); const int brainModelIndex = theMainWindow->getBrainModelIndex(); //const int aefColumn = dsea->getFirstSelectedColumnForBrainModel(brainModelIndex); AreaColorFile* acf = bs->getAreaColorFile(); const int numberOfAreaNames = aef->getNumberOfAreaNames(); std::vector areaNamesUsed(numberOfAreaNames, false); std::vector selectedColumnFlags; dsea->getSelectedColumnFlags(brainModelIndex, selectedColumnFlags); for (int ic = 0; ic < static_cast(selectedColumnFlags.size()); ic++) { if ((selectedColumnFlags[ic]) && (numNodes > 0) && (numberOfAreaNames > 0)) { // // Get the colors used by the paint file and column and place them in a set so no duplicates // const int numNodes = aef->getNumberOfNodes(); for (int i = 0; i < numNodes; i++) { int nameIndices[4]; float areas[4]; aef->getNodeData(i, ic, nameIndices, areas); areaNamesUsed[nameIndices[0]] = true; areaNamesUsed[nameIndices[1]] = true; areaNamesUsed[nameIndices[2]] = true; areaNamesUsed[nameIndices[3]] = true; } } } // // Update name table // for (int i = 0; i < numberOfAreaNames; i++) { if (areaNamesUsed[i]) { int red = -1; int green = -1; int blue = -1; unsigned char r, g, b; const QString name(aef->getAreaName(i)); bool exactMatch = false; const int colorFileIndex = acf->getColorByName(name, exactMatch, r, g, b); if (colorFileIndex >= 0) { red = r; green = g; blue = b; } names.push_back(NameAndColor(name, red, green, blue)); } } } /** * update border key. */ void GuiColorKeyDialog::updateBorderKey(BrainSet* bs, std::vector& names) { // // Get files and settings // DisplaySettingsBorders* dsb = bs->getDisplaySettingsBorders(); BrainModelBorderSet* bmbs = bs->getBorderSet(); AreaColorFile* acf = bs->getAreaColorFile(); const int numAreaColors = acf->getNumberOfColors(); BorderColorFile* bcf = bs->getBorderColorFile(); const int numBorderColors = bcf->getNumberOfColors(); const int brainModelIndex = theMainWindow->getBrainModelIndex(); // // Find a unique set of border names and their corresponding colors // std::set uniqueBorderNames; const int num = bmbs->getNumberOfBorders(); for (int i = 0; i < num; i++) { const BrainModelBorder* border = bmbs->getBorder(i); if (border->getDisplayFlag()) { if (border->getValidForBrainModel(brainModelIndex)) { const QString name = border->getName(); if (uniqueBorderNames.find(name) == uniqueBorderNames.end()) { const int areaColorFileIndex = border->getAreaColorFileIndex(); const int borderColorFileIndex = border->getBorderColorFileIndex(); int red = -1; int green = -1; int blue = -1; if (dsb->getOverrideBorderColorsWithAreaColors() && (areaColorFileIndex >= 0) && (areaColorFileIndex < numAreaColors)) { unsigned char r, g, b; acf->getColorByIndex(areaColorFileIndex, r, g, b); red = r; green = g; blue = b; } else if ((borderColorFileIndex >= 0) && (borderColorFileIndex < numBorderColors)) { unsigned char r, g, b; bcf->getColorByIndex(borderColorFileIndex, r, g, b); red = r; green = g; blue = b; } names.push_back(NameAndColor(name, red, green, blue)); uniqueBorderNames.insert(name); } } } } } /** * update cell key. */ void GuiColorKeyDialog::updateCellKey(BrainSet* bs, std::vector& names) { // // Files and settings // CellProjectionFile* cpf = bs->getCellProjectionFile(); CellColorFile* ccf = bs->getCellColorFile(); std::set uniqueCellNames; { const int num = cpf->getNumberOfCellProjections(); for (int i = 0; i < num; i++) { const CellProjection* cp = cpf->getCellProjection(i); if (cp->getDisplayFlag()) { const QString name = cp->getName(); uniqueCellNames.insert(name); } } } { CellFile* cf = bs->getVolumeCellFile(); const int num = cf->getNumberOfCells(); for (int i = 0; i < num; i++) { const CellData* cd = cf->getCell(i); if (cd->getDisplayFlag()) { const QString name = cd->getName(); uniqueCellNames.insert(name); } } } { const int numFiles = bs->getNumberOfTransformationDataFiles(); for (int j = 0; j < numFiles; j++) { AbstractFile* tdf = bs->getTransformationDataFile(j); CellFile* cf = dynamic_cast(tdf); if (cf != NULL) { const int num = cf->getNumberOfCells(); for (int i = 0; i < num; i++) { const CellData* cd = cf->getCell(i); const QString name = cd->getName(); uniqueCellNames.insert(name); } } } } for (std::set::iterator iter = uniqueCellNames.begin(); iter != uniqueCellNames.end(); iter++) { const QString name = *iter; int red = -1; int green = -1; int blue = -1; unsigned char r, g, b, a; bool exactMatch = false; const int cellColorFileIndex = ccf->getColorByName(name, exactMatch, r, g, b, a); if (cellColorFileIndex >= 0) { red = r; green = g; blue = b; } names.push_back(NameAndColor(name, red, green, blue)); uniqueCellNames.insert(name); } } /** * update foci key. */ void GuiColorKeyDialog::updateFociKey(BrainSet* bs, std::vector& names) { // // Files and settings // FociProjectionFile* fpf = bs->getFociProjectionFile(); FociColorFile* fcf = bs->getFociColorFile(); const int numberOfFociColors = fcf->getNumberOfColors(); const DisplaySettingsFoci* dsf = bs->getDisplaySettingsFoci(); const CellBase::CELL_COLOR_MODE colorMode = dsf->getColorMode(); std::set uniqueCellNames; const int num = fpf->getNumberOfCellProjections(); for (int i = 0; i < num; i++) { const CellProjection* cp = fpf->getCellProjection(i); if (cp->getDisplayFlag()) { // // Foci are colored by either focus name or class name // QString name; switch (colorMode) { case CellBase::CELL_COLOR_MODE_NAME: name = cp->getName(); break; case CellBase::CELL_COLOR_MODE_CLASS: name = cp->getClassName(); break; } if (name.isEmpty()) { name = "NO_NAME"; } if (uniqueCellNames.find(name) == uniqueCellNames.end()) { int red = -1; int green = -1; int blue = -1; const int cellColorFileIndex = cp->getColorIndex(); if ((cellColorFileIndex >= 0) && (cellColorFileIndex < numberOfFociColors)) { unsigned char r, g, b; fcf->getColorByIndex(cellColorFileIndex, r, g, b); red = r; green = g; blue = b; } names.push_back(NameAndColor(name, red, green, blue)); uniqueCellNames.insert(name); } } } } /** * update paint key. */ void GuiColorKeyDialog::updatePaintKey(BrainSet* bs, std::vector& names) { // // Files and settings // AreaColorFile* acf = bs->getAreaColorFile(); PaintFile* pf = bs->getPaintFile(); DisplaySettingsPaint* dsp = bs->getDisplaySettingsPaint(); const int brainModelIndex = theMainWindow->getBrainModelIndex(); //const int paintColumn = dsp->getFirstSelectedColumnForBrainModel(brainModelIndex); const GiftiLabelTable* labelTable = pf->getLabelTable(); const int numLabels = labelTable->getNumberOfLabels(); if (numLabels <= 0) { return; } // // Get the colors used by the paint file and column and place them in a set so no duplicates // std::vector paintIndicesUsed(numLabels, false); std::vector selectedColumnFlags; dsp->getSelectedColumnFlags(brainModelIndex, selectedColumnFlags); for (unsigned int ic = 0; ic < selectedColumnFlags.size(); ic++) { if (selectedColumnFlags[ic]) { const int numNodes = pf->getNumberOfNodes(); for (int i = 0; i < numNodes; i++) { const int paintNum = pf->getPaint(i, ic); paintIndicesUsed[paintNum] = true; } } } // // Update name table // for (int i = 0; i < numLabels; i++) { if (paintIndicesUsed[i]) { const QString name(labelTable->getLabel(i)); int red = -1; int green = -1; int blue = -1; unsigned char r, g, b; bool exactMatch; const int colorIndex = acf->getColorByName(name, exactMatch, r, g, b); if (colorIndex >= 0) { red = r; green = g; blue = b; } names.push_back(NameAndColor(name, red, green, blue)); } } } /** * update prob atlas key. */ void GuiColorKeyDialog::updateProbAtlasKey(BrainSet* bs, std::vector& names) { // // Files and settings // AreaColorFile* acf = bs->getAreaColorFile(); ProbabilisticAtlasFile* pf = bs->getProbabilisticAtlasSurfaceFile(); const GiftiLabelTable* labelTable = pf->getLabelTable(); const int numLabels = labelTable->getNumberOfLabels(); const int numColumns = pf->getNumberOfColumns(); const int numNodes = pf->getNumberOfNodes(); if ((numLabels > 0) && (numNodes > 0) && (numColumns > 0)) { // // Get the colors used by the paint file and column and place them in a set so no duplicates // std::vector paintIndicesUsed(numLabels, false); for (int i = 0; i < numNodes; i++) { for (int j = 0; j < numColumns; j++) { const int paintNum = pf->getPaint(i, j); paintIndicesUsed[paintNum] = true; } } // // Update name table // for (int i = 0; i < numLabels; i++) { if (paintIndicesUsed[i]) { const QString name(labelTable->getLabel(i)); int red = -1; int green = -1; int blue = -1; unsigned char r, g, b; bool exactMatch; const int colorIndex = acf->getColorByName(name, exactMatch, r, g, b); if (colorIndex >= 0) { red = r; green = g; blue = b; } names.push_back(NameAndColor(name, red, green, blue)); } } } } /** * update volume paint key. */ void GuiColorKeyDialog::updateVolumePaintKey(BrainSet* bs, std::vector& names) { const BrainModelVolume* bmv = bs->getBrainModelVolume(); if (bmv != NULL) { const VolumeFile* vf = bmv->getSelectedVolumePaintFile(); if (vf != NULL) { const int numVoxels = vf->getTotalNumberOfVoxelElements(); const float* voxelData = vf->getVoxelData(); const int numRegionNames = vf->getNumberOfRegionNames(); AreaColorFile* acf = bs->getAreaColorFile(); const int numberOfColors = acf->getNumberOfColors(); if ((numVoxels > 0) && (numRegionNames > 0) && (numberOfColors > 0)) { // // Get the colors used by the paint volume // std::vector regionNamesUsed(numRegionNames, false); for (int i = 0; i < numVoxels; i++) { const int voxel = static_cast(voxelData[i]); if ((voxel >= 0) && (voxel < numRegionNames)) { regionNamesUsed[voxel] = true; } } // // Update name table // for (int i = 0; i < numRegionNames; i++) { if (regionNamesUsed[i]) { int red = -1; int green = -1; int blue = -1; unsigned char r, g, b; const QString name(vf->getRegionNameFromIndex(i)); bool exactMatch = false; const int colorFileIndex = acf->getColorByName(name, exactMatch, r, g, b); if (colorFileIndex >= 0) { red = r; green = g; blue = b; } names.push_back(NameAndColor(name, red, green, blue)); } } } } } } /** * update volume prob atlas key. */ void GuiColorKeyDialog::updateVolumeProbAtlasKey(BrainSet* bs, std::vector& names) { const BrainModelVolume* bmv = bs->getBrainModelVolume(); if (bmv != NULL) { std::set regionNames; // // Loop through all of the prob atlas volumes // const int numProbAtlasVolumeFiles = bs->getNumberOfVolumeProbAtlasFiles(); for (int m = 0; m < numProbAtlasVolumeFiles; m++) { const VolumeFile* vf = bs->getVolumeProbAtlasFile(m); if (vf != NULL) { const int numVoxels = vf->getTotalNumberOfVoxelElements(); const float* voxelData = vf->getVoxelData(); const int numRegionNames = vf->getNumberOfRegionNames(); AreaColorFile* acf = bs->getAreaColorFile(); const int numberOfColors = acf->getNumberOfColors(); if ((numVoxels > 0) && (numRegionNames > 0) && (numberOfColors > 0)) { // // Get the colors used by the paint volume // std::vector regionNamesUsed(numRegionNames, false); for (int i = 0; i < numVoxels; i++) { const int voxel = static_cast(voxelData[i]); if ((voxel >= 0) && (voxel < numRegionNames)) { regionNamesUsed[voxel] = true; } } // // Update name table // for (int i = 0; i < numRegionNames; i++) { if (regionNamesUsed[i]) { regionNames.insert(vf->getRegionNameFromIndex(i)); } } } } } AreaColorFile* acf = bs->getAreaColorFile(); for (std::set::iterator iter = regionNames.begin(); iter != regionNames.end(); iter++) { int red = -1; int green = -1; int blue = -1; unsigned char r, g, b; const QString name(*iter); bool exactMatch = false; const int colorFileIndex = acf->getColorByName(name, exactMatch, r, g, b); if (colorFileIndex >= 0) { red = r; green = g; blue = b; } names.push_back(NameAndColor(name, red, green, blue)); } } } /** * save scene. */ SceneFile::SceneClass GuiColorKeyDialog::saveScene() { SceneFile::SceneClass sc(getTitleOfColorKey(colorKey)); const int geometry[4] = { x(), y(), width(), height() }; std::ostringstream str; str << geometry[0] << " " << geometry[1] << " " << geometry[2] << " " << geometry[3]; sc.addSceneInfo(SceneFile::SceneInfo("Geometry", str.str().c_str())); return sc; } /** * show scene. */ void GuiColorKeyDialog::showScene(const SceneFile::SceneClass sc, const int screenMaxX, const int screenMaxY, const int mainWindowSceneX, const int mainWindowSceneY, const int mainWindowX, const int mainWindowY) { int geometry[4] = { x(), y(), width(), height() }; const int num = sc.getNumberOfSceneInfo(); for (int i = 0; i < num; i++) { const SceneFile::SceneInfo* si = sc.getSceneInfo(i); const QString infoName = si->getName(); if (infoName == "Geometry") { std::vector tokens; StringUtilities::token(si->getValueAsString(), " ", tokens); if (tokens.size() >= 4) { geometry[0] = StringUtilities::toInt(tokens[0]); geometry[1] = StringUtilities::toInt(tokens[1]); geometry[2] = StringUtilities::toInt(tokens[2]); geometry[3] = StringUtilities::toInt(tokens[3]); } } } const DisplaySettingsScene* dss = theMainWindow->getBrainSet()->getDisplaySettingsScene(); if (geometry[0] > 0) { int x = geometry[0]; int y = geometry[1]; x = std::min(x, screenMaxX); y = std::min(y, screenMaxY); switch(dss->getWindowPositionPreference()) { case DisplaySettingsScene::WINDOW_POSITIONS_USE_ALL: move(x, y); break; case DisplaySettingsScene::WINDOW_POSITIONS_IGNORE_MAIN_OTHERS_RELATIVE: x = (x - mainWindowSceneX) + mainWindowX; y = (y - mainWindowSceneY) + mainWindowY; move(x, y); break; case DisplaySettingsScene::WINDOW_POSITIONS_IGNORE_ALL: break; } move(x, y); resize(geometry[2], geometry[3]); } updateDialog(); } /** * called when a color label is clicked. */ void GuiColorKeyDialog::slotColorLabelClicked(const int nameTableIndex) { if ((nameTableIndex < 0) || (nameTableIndex >= static_cast(nameTable.size()))) { return; } const QString name = nameTable[nameTableIndex].name; nameTable[nameTableIndex].highlightedFlag = (! nameTable[nameTableIndex].highlightedFlag); const bool highlightFlag = nameTable[nameTableIndex].highlightedFlag; BrainSet* bs = theMainWindow->getBrainSet(); BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); const int modelIndex = theMainWindow->getBrainModelIndex(); if ((modelIndex >= 0) && (modelIndex < bs->getNumberOfBrainModels())) { switch (colorKey) { case COLOR_KEY_AREAL_ESTIMATION: break; case COLOR_KEY_BORDERS: { BrainModelBorderSet* bmbs = bs->getBorderSet(); const int numBorders = bmbs->getNumberOfBorders(); for (int i = 0; i < numBorders; i++) { BrainModelBorder* b = bmbs->getBorder(i); if (b->getName() == name) { b->setHighlightFlag(highlightFlag); } } } break; case COLOR_KEY_CELLS: break; case COLOR_KEY_FOCI: { const DisplaySettingsFoci* dsf = bs->getDisplaySettingsFoci(); const CellBase::CELL_COLOR_MODE colorMode = dsf->getColorMode(); FociProjectionFile* fpf = bs->getFociProjectionFile(); const int numFoci = fpf->getNumberOfCellProjections(); for (int i = 0; i < numFoci; i++) { CellProjection* cp = fpf->getCellProjection(i); // // Foci are colored by either focus name or class name // QString focusName; switch (colorMode) { case CellBase::CELL_COLOR_MODE_NAME: focusName = cp->getName(); break; case CellBase::CELL_COLOR_MODE_CLASS: focusName = cp->getClassName(); break; } if (focusName.isEmpty()) { focusName = "NO_NAME"; } if (focusName == name) { cp->setHighlightFlag(highlightFlag); } } } break; case COLOR_KEY_PAINT: if (bms != NULL) { const PaintFile* pf = bs->getPaintFile(); const DisplaySettingsPaint* dsp = bs->getDisplaySettingsPaint(); const int numNodes = pf->getNumberOfNodes(); std::vector selectedColumnFlags; const int brainModelIndex = theMainWindow->getBrainModelIndex(); dsp->getSelectedColumnFlags(brainModelIndex, selectedColumnFlags); //const int columnNumber = dsp->getFirstSelectedColumnForBrainModel(modelIndex); for (unsigned int ic = 0; ic < selectedColumnFlags.size(); ic++) { if (selectedColumnFlags[ic]) { const int paintIndex = pf->getPaintIndexFromName(name); if (paintIndex >= 0) { for (int i = 0; i < numNodes; i++) { if (pf->getPaint(i, ic) == paintIndex) { BrainSetNodeAttribute* bna = bs->getNodeAttributes(i); if (highlightFlag) { bna->setHighlighting(BrainSetNodeAttribute::HIGHLIGHT_NODE_LOCAL); } else { bna->setHighlighting(BrainSetNodeAttribute::HIGHLIGHT_NODE_NONE); } } } } } } } break; case COLOR_KEY_PROBABILISTIC_ATLAS: if (bms != NULL) { const PaintFile* pf = bs->getProbabilisticAtlasSurfaceFile(); const int numCols = pf->getNumberOfColumns(); const DisplaySettingsProbabilisticAtlas* dsp = bs->getDisplaySettingsProbabilisticAtlasSurface(); const int numNodes = pf->getNumberOfNodes(); std::vector selectedColumnFlags; const int paintIndex = pf->getPaintIndexFromName(name); if (paintIndex >= 0) { for (int i = 0; i < numNodes; i++) { for (int ic = 0; ic < numCols; ic++) { if (dsp->getChannelSelected(ic)) { if (pf->getPaint(i, ic) == paintIndex) { BrainSetNodeAttribute* bna = bs->getNodeAttributes(i); if (highlightFlag) { bna->setHighlighting(BrainSetNodeAttribute::HIGHLIGHT_NODE_LOCAL); } else { bna->setHighlighting(BrainSetNodeAttribute::HIGHLIGHT_NODE_NONE); } break; // go to next node } } } } } } break; case COLOR_KEY_VOLUME_PAINT: { const int numVolumes = bs->getNumberOfVolumePaintFiles(); for (int i = 0; i < numVolumes; i++) { VolumeFile* vf = bs->getVolumePaintFile(i); if (i == 0) { vf->setHighlightRegionName(name, highlightFlag); } vf->setVoxelColoringInvalid(); } } break; case COLOR_KEY_VOLUME_PROBABILISTIC_ATLAS: { const int numVolumes = bs->getNumberOfVolumeProbAtlasFiles(); for (int i = 0; i < numVolumes; i++) { VolumeFile* vf = bs->getVolumeProbAtlasFile(i); if (i == 0) { vf->setHighlightRegionName(name, highlightFlag); } vf->setVoxelColoringInvalid(); } } break; } updateColorLabel(nameTableIndex); } theMainWindow->getBrainSet()->clearAllDisplayLists(); GuiBrainModelOpenGL::updateAllGL(); } /** * called when a name label is clicked. */ void GuiColorKeyDialog::slotNameLabelClicked(const QString& name) { //std::cout << "name label: " << name.toAscii().constData() << std::endl; switch (colorKey) { case COLOR_KEY_AREAL_ESTIMATION: break; case COLOR_KEY_BORDERS: break; case COLOR_KEY_CELLS: break; case COLOR_KEY_FOCI: displayStudyMatchingFociColor(name); break; case COLOR_KEY_PAINT: break; case COLOR_KEY_PROBABILISTIC_ATLAS: break; case COLOR_KEY_VOLUME_PAINT: break; case COLOR_KEY_VOLUME_PROBABILISTIC_ATLAS: break; } GuiIdentifyDialog* id = theMainWindow->getIdentifyDialog(false); id->displayVocabularyNameData(name); } /** * clear highlighting. */ void GuiColorKeyDialog::slotClearHighlighting() { bool clearNodesFlag = false; BrainSet* bs = theMainWindow->getBrainSet(); switch (colorKey) { case COLOR_KEY_AREAL_ESTIMATION: clearNodesFlag = true; break; case COLOR_KEY_BORDERS: { BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); bmbs->clearBorderHighlighting(); } break; case COLOR_KEY_CELLS: break; case COLOR_KEY_FOCI: { FociProjectionFile* fpf = theMainWindow->getBrainSet()->getFociProjectionFile(); fpf->clearAllHighlightFlags(); } break; case COLOR_KEY_PAINT: clearNodesFlag = true; break; case COLOR_KEY_PROBABILISTIC_ATLAS: clearNodesFlag = true; break; case COLOR_KEY_VOLUME_PAINT: if (bs->getNumberOfVolumePaintFiles() > 0) { bs->getVolumePaintFile(0)->clearRegionHighlighting(); GuiBrainModelOpenGL::updateAllGL(); } break; case COLOR_KEY_VOLUME_PROBABILISTIC_ATLAS: if (bs->getNumberOfVolumeProbAtlasFiles() > 0) { bs->getVolumeProbAtlasFile(0)->clearRegionHighlighting(); } break; } if (clearNodesFlag) { theMainWindow->getBrainSet()->clearNodeHighlightSymbols(); } GuiBrainModelOpenGL::updateAllGL(); } /** * display study matching a foci color. */ void GuiColorKeyDialog::displayStudyMatchingFociColor(const QString& colorName) { BrainSet* bs = theMainWindow->getBrainSet(); // // Get index of color in foci // const StudyMetaDataFile* smdf = bs->getStudyMetaDataFile(); const ColorFile* cf = bs->getFociColorFile(); bool match = false; const int colorIndex = cf->getColorIndexByName(colorName, match); if (colorIndex > 0) { const FociProjectionFile* fpf = bs->getFociProjectionFile(); const int numFoci = fpf->getNumberOfCellProjections(); for (int i = 0; i < numFoci; i++) { const CellProjection* cp = fpf->getCellProjection(i); if (cp->getColorIndex() == colorIndex) { StudyMetaDataLinkSet smdls = cp->getStudyMetaDataLinkSet(); for (int j = 0; j < smdls.getNumberOfStudyMetaDataLinks(); j++) { StudyMetaDataLink* smdl = smdls.getStudyMetaDataLinkPointer(j); smdl->setTableNumber(""); smdl->setFigureNumber(""); smdl->setPageReferencePageNumber(""); //smdl->setPageNumber(""); } BrainModelIdentification* bmi = bs->getBrainModelIdentification(); const QString studyMessage = bmi->getIdentificationTextForStudies(true, smdf, smdls); if (studyMessage.isEmpty() == false) { GuiIdentifyDialog* idDialog = theMainWindow->getIdentifyDialog(true); idDialog->appendHtml(studyMessage); break; } } } } } //----------------------------------------------------------------------------------- /** * constructor. */ GuiColorKeyLabel::GuiColorKeyLabel(QWidget* parent) : QLabel(parent) { nameTableIndex = -1; } /** * destructor. */ GuiColorKeyLabel::~GuiColorKeyLabel() { } /** * called when a mouse button is pressed over this widget. */ void GuiColorKeyLabel::mousePressEvent(QMouseEvent* me) { if (me->button() == Qt::LeftButton) { if (me->modifiers() == Qt::NoButton) { if (areaName.isEmpty() == false) { emit signalShowAreaName(areaName); } if (nameTableIndex >= 0) { emit signalNameTableIndex(nameTableIndex); } } } } /** * set the area name. */ void GuiColorKeyLabel::setAreaName(const QString& areaNameIn) { areaName = areaNameIn; } /** * set name table index. */ void GuiColorKeyLabel::setNameTableIndex(const int indx) { nameTableIndex = indx; } //----------------------------------------------------------------------------------- /** * constructor. */ GuiColorKeyDialog::NameAndColor::NameAndColor(const QString& nameIn, const int redIn, const int greenIn, const int blueIn) { name = nameIn; red = redIn; green = greenIn; blue = blueIn; highlightedFlag = false; } /** * destructor. */ GuiColorKeyDialog::NameAndColor::~NameAndColor() { } /** * less than operator. */ bool GuiColorKeyDialog::NameAndColor::operator<(const NameAndColor& nac) const { return (name < nac.name); } /** * equality operator. */ bool GuiColorKeyDialog::NameAndColor::operator==(const NameAndColor& nac) const { return (name == nac.name); } caret-5.6.4~dfsg.1.orig/caret/GuiColorFileEditorWidget.h0000664000175000017500000001206611572067322022673 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_GUI_COLOR_FILE_EDITOR_WIDGET_H__ #define __VE_GUI_COLOR_FILE_EDITOR_WIDGET_H__ #include #include #include class ColorFile; class QComboBox; class QListWidget; class QSlider; class QSpinBox; class QDoubleSpinBox; ///Class used for sorting colors alphabetically. class ColorSorter2 { public: /// Constructor ColorSorter2(const QString& nameIn, const int indexIn) { colorName = nameIn; colorFileIndex = indexIn; } /// name of color QString colorName; /// index into color file int colorFileIndex; }; #ifdef __COLOR_FILE_EDITOR_WIDGET_MAIN__ bool operator<(const ColorSorter2& c1, const ColorSorter2& c2) { return (c1.colorName < c2.colorName); } #endif // __COLOR_FILE_EDITOR_WIDGET_MAIN__ /// This widget is used edit a ColorFile. class GuiColorFileEditorWidget : public QWidget { Q_OBJECT public: /// Constructor GuiColorFileEditorWidget(QWidget* parent, ColorFile* cf, const bool showAlpha, const bool showPointSize, const bool showLineSize, const bool showSymbol); /// Destructor ~GuiColorFileEditorWidget(); /// update the editor void updateColorEditor(); signals: /// display should be redrawn (apply button was pressed) void redrawRequested(); public slots: /// called when apply button is pressed void applySlot(); private slots: /// called when an item is selected in the name list box void nameListSelectionSlot(int index); /// called when the red slider is moved void redSliderMovedSlot(int value); /// called when the green slider is moved void greenSliderMovedSlot(int value); /// called when the blue slider is moved void blueSliderMovedSlot(int value); /// called when the alpha slider is moved void alphaSliderMovedSlot(int value); /// called when line size is changed void lineSizeChangedSlot(double value); /// called when line size is changed void pointSizeChangedSlot(double value); /// called when new color button is pressed void newColorButtonSlot(); /// called when symbol combo box is selected void symbolComboBoxSlot(int value); /// called when change color name button is pressed void changeColorNameButtonSlot(); /// called when delete color button is pressed void deleteColorButtonSlot(); /// called whne button is pressed void slotColorChooserButton(); /// called when web name push button pressed void slotWebHtmlColorNamesPushButton(); private: /// load the name list box void loadColorsIntoListBox(); /// update the color of the color swatch void updateColorSwatch(); /// the color swatch QWidget* colorSwatch; /// the value label QSpinBox* redValueSpinBox; /// the color slider QSlider* redSlider; /// the value label QSpinBox* greenValueSpinBox; /// the color slider QSlider* greenSlider; /// the value label QSpinBox* blueValueSpinBox; /// the color slider QSlider* blueSlider; /// the alpha value spin box QSpinBox* alphaValueSpinBox; /// the alpha color slider QSlider* alphaSlider; /// the line size spin box QDoubleSpinBox* lineSizeSpinBox; /// the point size spin box QDoubleSpinBox* pointSizeSpinBox; /// listbox for name selection QListWidget* nameSelectionListBox; /// combo box for symbol selection QComboBox* symbolComboBox; /// the color file being edited ColorFile* colorFile; /// sorted colors std::vector colors; /// color being edited int currentColorFileIndex; }; #endif // __VE_GUI_COLOR_FILE_EDITOR_WIDGET_H__ caret-5.6.4~dfsg.1.orig/caret/GuiColorFileEditorWidget.cxx0000664000175000017500000006366511572067322023261 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "BrainSet.h" #include "ColorFile.h" #include #include "GuiBrainModelOpenGL.h" #include "GuiHtmlColorChooserDialog.h" #include "GuiMainWindow.h" #define __COLOR_FILE_EDITOR_WIDGET_MAIN__ #include "GuiColorFileEditorWidget.h" #undef __COLOR_FILE_EDITOR_WIDGET_MAIN__ #include "QtUtilities.h" #include "WuQDataEntryDialog.h" #include "global_variables.h" /** * Constructor. * For non modal dialog, leave "modalFlag" and "f" at their defaults. Call "show()" to display. * For modal dialog, set "modalFlag" to true and "f" to zero. Call "exec()" to display. */ GuiColorFileEditorWidget::GuiColorFileEditorWidget(QWidget* parent, ColorFile* cf, const bool showAlpha, const bool showPointSize, const bool showLineSize, const bool showSymbol) : QWidget(parent) { // // color file being edited // colorFile = cf; currentColorFileIndex = -1; // // layout for widget // QVBoxLayout* rows = new QVBoxLayout(this); rows->setMargin(5); // // Group box for color naming // QGroupBox* colorNameGroupBox = new QGroupBox("Color Name"); rows->addWidget(colorNameGroupBox); QVBoxLayout* colorNameGroupBoxLayout = new QVBoxLayout(colorNameGroupBox); // // Name selection list box // nameSelectionListBox = new QListWidget; nameSelectionListBox->setMaximumHeight(125); nameSelectionListBox->setSelectionMode(QListWidget::SingleSelection); colorNameGroupBoxLayout->addWidget(nameSelectionListBox); QObject::connect(nameSelectionListBox, SIGNAL(currentRowChanged(int)), this, SLOT(nameListSelectionSlot(int))); //QObject::connect(nameSelectionListBox, SIGNAL(selected(int)), // this, SLOT(nameListSelectionSlot(int))); // // Horizontal box for new color and delete buttons // QHBoxLayout* newDeleteButtonBoxLayout = new QHBoxLayout; colorNameGroupBoxLayout->addLayout(newDeleteButtonBoxLayout); // // Create new color button // QPushButton* newColorButton = new QPushButton("New Color..."); newDeleteButtonBoxLayout->addWidget(newColorButton); newColorButton->setAutoDefault(false); QObject::connect(newColorButton, SIGNAL(clicked()), this, SLOT(newColorButtonSlot())); // // Change color name button // QPushButton* changeColorNameButton = new QPushButton("Change Name..."); newDeleteButtonBoxLayout->addWidget(changeColorNameButton); changeColorNameButton->setAutoDefault(false); QObject::connect(changeColorNameButton, SIGNAL(clicked()), this, SLOT(changeColorNameButtonSlot())); // // Delete color button // QPushButton* deleteColorButton = new QPushButton("Delete Selected Color"); newDeleteButtonBoxLayout->addWidget(deleteColorButton); deleteColorButton->setAutoDefault(false); QObject::connect(deleteColorButton, SIGNAL(clicked()), this, SLOT(deleteColorButtonSlot())); // // Group box for color parameters // QGroupBox* colorParamGroupBox = new QGroupBox("Color Parameters"); rows->addWidget(colorParamGroupBox); QVBoxLayout* colorParamGroupBoxLayout = new QVBoxLayout(colorParamGroupBox); // // "Color swatch" widget // colorSwatch = new QWidget; colorParamGroupBoxLayout->addWidget(colorSwatch); colorSwatch->setMinimumSize(QSize(50, 50)); colorSwatch->setMaximumHeight(50); //colorSwatch->setFixedSize(QSize(200, 50)); // // Grid Layout for Colors Sliders // QGridLayout* sliderGridLayout = new QGridLayout; colorParamGroupBoxLayout->addLayout(sliderGridLayout); sliderGridLayout->setMargin(5); sliderGridLayout->setSpacing(5); // // Red control // sliderGridLayout->addWidget(new QLabel("Red"), 0, 0, Qt::AlignLeft); redValueSpinBox = new QSpinBox; redValueSpinBox->setMinimum(0); redValueSpinBox->setMaximum(255); redValueSpinBox->setSingleStep(1); sliderGridLayout->addWidget(redValueSpinBox, 0, 1, Qt::AlignRight); redSlider = new QSlider(Qt::Horizontal); redSlider->setMinimum(0); redSlider->setMaximum(255); redSlider->setPageStep(5); redSlider->setValue(0); redSlider->setMinimumWidth(300); QObject::connect(redSlider, SIGNAL(valueChanged(int)), redValueSpinBox, SLOT(setValue(int))); QObject::connect(redSlider, SIGNAL(valueChanged(int)), this, SLOT(redSliderMovedSlot(int))); QObject::connect(redValueSpinBox, SIGNAL(valueChanged(int)), redSlider, SLOT(setValue(int))); QObject::connect(redValueSpinBox, SIGNAL(valueChanged(int)), this, SLOT(redSliderMovedSlot(int))); sliderGridLayout->addWidget(redSlider, 0, 2, Qt::AlignLeft); // // Green control // sliderGridLayout->addWidget(new QLabel("Green"), 1, 0, Qt::AlignLeft); greenValueSpinBox = new QSpinBox; greenValueSpinBox->setMinimum(0); greenValueSpinBox->setMaximum(255); greenValueSpinBox->setSingleStep(1); sliderGridLayout->addWidget(greenValueSpinBox, 1, 1, Qt::AlignRight); greenSlider = new QSlider(Qt::Horizontal); greenSlider->setMinimum(0); greenSlider->setMaximum(255); greenSlider->setPageStep(5); greenSlider->setValue(0); greenSlider->setMinimumWidth(300); QObject::connect(greenSlider, SIGNAL(valueChanged(int)), greenValueSpinBox, SLOT(setValue(int))); QObject::connect(greenSlider, SIGNAL(valueChanged(int)), this, SLOT(greenSliderMovedSlot(int))); QObject::connect(greenValueSpinBox, SIGNAL(valueChanged(int)), greenSlider, SLOT(setValue(int))); QObject::connect(greenValueSpinBox, SIGNAL(valueChanged(int)), this, SLOT(greenSliderMovedSlot(int))); sliderGridLayout->addWidget(greenSlider, 1, 2, Qt::AlignLeft); // // Blue control // sliderGridLayout->addWidget(new QLabel("Blue"), 2, 0, Qt::AlignLeft); blueValueSpinBox = new QSpinBox; blueValueSpinBox->setMinimum(0); blueValueSpinBox->setMaximum(255); blueValueSpinBox->setSingleStep(1); sliderGridLayout->addWidget(blueValueSpinBox, 2, 1, Qt::AlignRight); blueSlider = new QSlider(Qt::Horizontal); blueSlider->setMinimum(0); blueSlider->setMaximum(255); blueSlider->setPageStep(5); blueSlider->setValue(0); blueSlider->setMinimumWidth(300); QObject::connect(blueSlider, SIGNAL(valueChanged(int)), blueValueSpinBox, SLOT(setValue(int))); QObject::connect(blueSlider, SIGNAL(valueChanged(int)), this, SLOT(blueSliderMovedSlot(int))); QObject::connect(blueValueSpinBox, SIGNAL(valueChanged(int)), blueSlider, SLOT(setValue(int))); QObject::connect(blueValueSpinBox, SIGNAL(valueChanged(int)), this, SLOT(blueSliderMovedSlot(int))); sliderGridLayout->addWidget(blueSlider, 2, 2, Qt::AlignLeft); // // Alpha control // QLabel* alphaLabel = new QLabel("Alpha"); sliderGridLayout->addWidget(alphaLabel, 3, 0, Qt::AlignLeft); alphaValueSpinBox = new QSpinBox; alphaValueSpinBox->setMinimum(0); alphaValueSpinBox->setMaximum(255); alphaValueSpinBox->setSingleStep(1); sliderGridLayout->addWidget(alphaValueSpinBox, 3, 1, Qt::AlignRight); alphaSlider = new QSlider(Qt::Horizontal); alphaSlider->setMinimumWidth(300); alphaSlider->setMinimum(0); alphaSlider->setMaximum(255); alphaSlider->setPageStep(5); alphaSlider->setValue(0); QObject::connect(alphaSlider, SIGNAL(valueChanged(int)), alphaValueSpinBox, SLOT(setValue(int))); QObject::connect(alphaSlider, SIGNAL(valueChanged(int)), this, SLOT(alphaSliderMovedSlot(int))); QObject::connect(alphaValueSpinBox, SIGNAL(valueChanged(int)), alphaSlider, SLOT(setValue(int))); QObject::connect(alphaValueSpinBox, SIGNAL(valueChanged(int)), this, SLOT(alphaSliderMovedSlot(int))); sliderGridLayout->addWidget(alphaSlider, 3, 2, Qt::AlignLeft); if (showAlpha == false) { alphaLabel->hide(); alphaValueSpinBox->hide(); alphaSlider->hide(); } // // Pushbutton for color chooser // QPushButton* colorChooserButton = new QPushButton("Advanced Color Selection..."); colorChooserButton->setAutoDefault(false); colorChooserButton->setToolTip( "Press this button to pop up a dialog\n" "with more powerful color selection."); colorChooserButton->setFixedSize(colorChooserButton->sizeHint()); QObject::connect(colorChooserButton, SIGNAL(clicked()), this, SLOT(slotColorChooserButton())); // // Pushbutton for web (html) colors // QPushButton* webHtmlColorPushButton = new QPushButton("List of Common Colors..."); webHtmlColorPushButton->setAutoDefault(false); webHtmlColorPushButton->setToolTip( "Press this button to select colors\n" "defined by the World Wide Web Consortium"); webHtmlColorPushButton->setFixedSize(webHtmlColorPushButton->sizeHint()); QObject::connect(webHtmlColorPushButton, SIGNAL(clicked()), this, SLOT(slotWebHtmlColorNamesPushButton())); // // Layout for color buttons // QHBoxLayout* colorPushButtonsLayout = new QHBoxLayout; colorPushButtonsLayout->addWidget(colorChooserButton); colorPushButtonsLayout->addWidget(webHtmlColorPushButton); colorPushButtonsLayout->addStretch(); colorParamGroupBoxLayout->addLayout(colorPushButtonsLayout); // // QGrid for Line and Point Size and symbol // QGridLayout* attsGridLayout = new QGridLayout; colorParamGroupBoxLayout->addLayout(attsGridLayout); float minLineSize, maxLineSize; GuiBrainModelOpenGL::getLineWidthRange(minLineSize, maxLineSize); QLabel* lineSizeLabel = new QLabel("Line Size"); attsGridLayout->addWidget(lineSizeLabel, 0, 0); lineSizeSpinBox = new QDoubleSpinBox; lineSizeSpinBox->setMinimum(minLineSize); lineSizeSpinBox->setMaximum(maxLineSize); lineSizeSpinBox->setSingleStep(1.0); lineSizeSpinBox->setDecimals(1); attsGridLayout->addWidget(lineSizeSpinBox, 0, 1); lineSizeSpinBox->setValue(1.0); QObject::connect(lineSizeSpinBox, SIGNAL(valueChanged(double)), this, SLOT(lineSizeChangedSlot(double))); if (showLineSize == false) { lineSizeLabel->hide(); lineSizeSpinBox->hide(); } float minPointSize, maxPointSize; GuiBrainModelOpenGL::getPointSizeRange(minPointSize, maxPointSize); maxPointSize = 100000.0; QLabel* pointSizeLabel = new QLabel("Point Size"); attsGridLayout->addWidget(pointSizeLabel, 1, 0); pointSizeSpinBox = new QDoubleSpinBox; pointSizeSpinBox->setMinimum(minPointSize); pointSizeSpinBox->setMaximum(maxPointSize); pointSizeSpinBox->setSingleStep(1.0); pointSizeSpinBox->setDecimals(1); attsGridLayout->addWidget(pointSizeSpinBox, 1, 1); pointSizeSpinBox->setValue(2.0); QObject::connect(pointSizeSpinBox, SIGNAL(valueChanged(double)), this, SLOT(pointSizeChangedSlot(double))); if (showPointSize == false) { pointSizeLabel->hide(); pointSizeSpinBox->hide(); } // // Symbol // QLabel* symbolLabel = new QLabel("Symbol"); attsGridLayout->addWidget(symbolLabel, 2, 0); symbolComboBox = new QComboBox; attsGridLayout->addWidget(symbolComboBox, 2, 1); std::vector symbolLabels; ColorFile::ColorStorage::getAllSymbolTypesAsStrings(symbolLabels); for (unsigned int i = 0; i < symbolLabels.size(); i++) { symbolComboBox->addItem(symbolLabels[i]); } QObject::connect(symbolComboBox, SIGNAL(activated(int)), this, SLOT(symbolComboBoxSlot(int))); if (showSymbol == false) { symbolLabel->hide(); symbolComboBox->hide(); } // // Squeeze Grid // //attsGridLayout->setFixedSize(attsGridLayout->sizeHint()); // // Load and initialize the color list box // loadColorsIntoListBox(); nameListSelectionSlot(0); } /** * Destructor */ GuiColorFileEditorWidget::~GuiColorFileEditorWidget() { } /** * update the editor. */ void GuiColorFileEditorWidget::updateColorEditor() { // // Load and initialize the color list box // loadColorsIntoListBox(); nameListSelectionSlot(0); } /** * called when color chooser button is pressed. */ void GuiColorFileEditorWidget::slotColorChooserButton() { // // Popup QT's color chooser dialog // QColor inputColor(redValueSpinBox->value(), greenValueSpinBox->value(), blueValueSpinBox->value()); QColor outputColor = QColorDialog::getColor(inputColor, this); if (outputColor.isValid()) { if ((currentColorFileIndex >= 0) && (currentColorFileIndex < static_cast(colors.size()))) { colorFile->setColorByIndex(currentColorFileIndex, outputColor.red(), outputColor.green(), outputColor.blue()); redValueSpinBox->setValue(outputColor.red()); greenValueSpinBox->setValue(outputColor.green()); blueValueSpinBox->setValue(outputColor.blue()); updateColorSwatch(); } } } /** * Called when new color button is pressed */ void GuiColorFileEditorWidget::newColorButtonSlot() { // // Initialize color to foreground color // unsigned char red, green, blue; unsigned char alpha = 255; PreferencesFile* pref = theMainWindow->getBrainSet()->getPreferencesFile(); pref->getSurfaceForegroundColor(red, green, blue); float pointSize = 2.0, lineSize = 1.0; // // Default to currently selected color // QString defaultName = ""; if (currentColorFileIndex >= 0) { colorFile->getColorByIndex(currentColorFileIndex, red, green, blue, alpha); colorFile->getPointLineSizeByIndex(currentColorFileIndex, pointSize, lineSize); defaultName = colorFile->getColorNameByIndex(currentColorFileIndex); } // // Get the new color name using a qt input dialog for text // bool ok = false; const QString nameInput = QInputDialog::getText(this, "New Color Name", "Color Name", QLineEdit::Normal, defaultName, &ok); // // Name entered and ok button was pressed // if (ok && (nameInput.isEmpty() == false)) { const QString name(nameInput); // // See if color with name exists, if so switch to it and popup message // bool match = false; int colorIndex = colorFile->getColorIndexByName(name, match); if ((colorIndex >= 0) && match) { for (int i = 0; i < static_cast(colors.size()); i++) { if (colors[i].colorFileIndex == colorIndex) { nameSelectionListBox->setCurrentRow(i); nameListSelectionSlot(i); break; } } QString msg("Color "); msg.append(name); msg.append(" already exists."); QMessageBox::warning(this, "Color Exists", msg); return; } // // Create a new color // colorFile->addColor(name, red, green, blue, alpha, pointSize, lineSize); loadColorsIntoListBox(); // // Select the new color // nameSelectionListBox->setCurrentRow(0); nameListSelectionSlot(0); colorIndex = colorFile->getColorIndexByName(name, match); if ((colorIndex >= 0) && match) { for (int i = 0; i < static_cast(colors.size()); i++) { if (colors[i].colorFileIndex == colorIndex) { nameSelectionListBox->setCurrentRow(i); nameListSelectionSlot(i); break; } } } } // // Redraw since color file has changed // emit redrawRequested(); } /** * called when change color name button is pressed. */ void GuiColorFileEditorWidget::changeColorNameButtonSlot() { if (currentColorFileIndex >= 0) { const QString name = colorFile->getColorNameByIndex(currentColorFileIndex); // // Get the new name // WuQDataEntryDialog ded(this); ded.setWindowTitle("Edit Color Name"); QLineEdit* nameLineEdit = ded.addLineEditWidget("Color Name", name); if (ded.exec() == WuQDataEntryDialog::Accepted) { const QString newName = nameLineEdit->text(); if ((newName.isEmpty() == false) && (newName != name)) { // // Change the name // colorFile->setColorNameByIndex(currentColorFileIndex, newName); // // Reload list box // loadColorsIntoListBox(); // // Find new name // int listBoxIndex = -1; for (int i = 0; i < nameSelectionListBox->count(); i++) { if (nameSelectionListBox->item(i)->text() == newName) { listBoxIndex = i; break; } } if (listBoxIndex >= 0) { nameSelectionListBox->setCurrentRow(listBoxIndex); nameListSelectionSlot(listBoxIndex); } // // Redraw since color file has changed // emit redrawRequested(); } } } } /** * Called when delete color button is pressed */ void GuiColorFileEditorWidget::deleteColorButtonSlot() { int listBoxIndex = nameSelectionListBox->currentRow(); if (listBoxIndex >= 0) { const int colorIndex = colors[listBoxIndex].colorFileIndex; // // Remove the color // colorFile->removeColorByIndex(colorIndex); loadColorsIntoListBox(); // // Reset items in list box // if (listBoxIndex >= static_cast(colors.size())) { listBoxIndex = colors.size() - 1; } if (listBoxIndex >= 0) { nameSelectionListBox->setCurrentRow(listBoxIndex); nameListSelectionSlot(listBoxIndex); } // // Redraw since color file has changed // emit redrawRequested(); } } /** * Called when apply button is pressed. */ void GuiColorFileEditorWidget::applySlot() { // // Redraw since color file has changed // emit redrawRequested(); } /** * Initialize the controls */ void GuiColorFileEditorWidget::loadColorsIntoListBox() { currentColorFileIndex = -1; QString oldName; const int indx = nameSelectionListBox->currentRow(); if ((indx >= 0) && (indx < nameSelectionListBox->count())) { oldName = nameSelectionListBox->item(indx)->text(); } // // Load and Sort the colors // colors.clear(); int num = colorFile->getNumberOfColors(); for (int i = 0; i < num; i++) { colors.push_back(ColorSorter2(colorFile->getColorNameByIndex(i), i)); } std::sort(colors.begin(), colors.end()); // // Load the color names into the list selection box // int defaultIndex = 0; nameSelectionListBox->clear(); num = colors.size(); for (int i = 0; i < num; i++) { nameSelectionListBox->addItem(colors[i].colorName); if (oldName == colors[i].colorName) { defaultIndex = i; } } if ((defaultIndex >= 0) && (defaultIndex < nameSelectionListBox->count())) { currentColorFileIndex = colors[defaultIndex].colorFileIndex; nameSelectionListBox->setCurrentRow(defaultIndex); } } /** * Update the color swatch */ void GuiColorFileEditorWidget::updateColorSwatch() { QColor color; if (currentColorFileIndex >= 0) { unsigned char r, g, b; colorFile->getColorByIndex(currentColorFileIndex, r, g, b); color.setRgb(r, g, b); } QPalette pal; pal.setColor(QPalette::Window, color); colorSwatch->setAutoFillBackground(true); colorSwatch->setBackgroundRole(QPalette::Window); colorSwatch->setPalette(pal); //colorSwatch->setPaletteBackgroundColor(color); //colorSwatch->setPaletteForegroundColor(color); } /** * Slot called when a name is selected in the name list box. */ void GuiColorFileEditorWidget::nameListSelectionSlot(int indx) { if ((indx >= 0) && (indx < static_cast(colors.size()))) { currentColorFileIndex = colors[indx].colorFileIndex; } else { currentColorFileIndex = -1; } if (currentColorFileIndex >= 0) { unsigned char r, g, b, a; colorFile->getColorByIndex(currentColorFileIndex, r, g, b, a); redSlider->setValue(r); redValueSpinBox->setValue(r); greenSlider->setValue(g); greenValueSpinBox->setValue(g); blueSlider->setValue(b); blueValueSpinBox->setValue(b); alphaSlider->setValue(a); alphaValueSpinBox->setValue(a); float pointSize, lineSize; colorFile->getPointLineSizeByIndex(currentColorFileIndex, pointSize, lineSize); if (lineSizeSpinBox != NULL) { lineSizeSpinBox->setValue(lineSize); } if (pointSizeSpinBox != NULL) { pointSizeSpinBox->setValue(pointSize); } symbolComboBox->setCurrentIndex(colorFile->getSymbolByIndex(currentColorFileIndex)); } updateColorSwatch(); } /** * called when symbol combo box is selected. */ void GuiColorFileEditorWidget::symbolComboBoxSlot(int value) { if (currentColorFileIndex >= 0) { ColorFile::ColorStorage::SYMBOL s = static_cast(value); if (s != colorFile->getSymbolByIndex(currentColorFileIndex)) { colorFile->setSymbolByIndex(currentColorFileIndex, s); } } } /** * Slot called when the red slider is moved. */ void GuiColorFileEditorWidget::redSliderMovedSlot(int value) { if (currentColorFileIndex >= 0) { unsigned char r, g, b, a; colorFile->getColorByIndex(currentColorFileIndex, r, g, b, a); const unsigned char red = static_cast(value); if (red != r) { colorFile->setColorByIndex(currentColorFileIndex, red, g, b, a); } } updateColorSwatch(); } /** * Slot called when the green slider is moved. */ void GuiColorFileEditorWidget::greenSliderMovedSlot(int value) { if (currentColorFileIndex >= 0) { unsigned char r, g, b, a; colorFile->getColorByIndex(currentColorFileIndex, r, g, b, a); const unsigned char green = static_cast(value); if (green != g) { colorFile->setColorByIndex(currentColorFileIndex, r, green, b, a); } } updateColorSwatch(); } /** * Slot called when the blue slider is moved. */ void GuiColorFileEditorWidget::blueSliderMovedSlot(int value) { if (currentColorFileIndex >= 0) { unsigned char r, g, b, a; colorFile->getColorByIndex(currentColorFileIndex, r, g, b, a); const unsigned char blue = static_cast(value); if (blue != b) { colorFile->setColorByIndex(currentColorFileIndex, r, g, blue, a); } } updateColorSwatch(); } /** * Slot called when the alpha slider is moved. */ void GuiColorFileEditorWidget::alphaSliderMovedSlot(int value) { if (currentColorFileIndex >= 0) { unsigned char r, g, b, a; colorFile->getColorByIndex(currentColorFileIndex, r, g, b, a); const unsigned char alpha = static_cast(value); if (alpha != a) { colorFile->setColorByIndex(currentColorFileIndex, r, g, b, alpha); } } updateColorSwatch(); } /** * Called when line size is changed. */ void GuiColorFileEditorWidget::lineSizeChangedSlot(double value) { if (currentColorFileIndex >= 0) { float pointSize, lineSize; colorFile->getPointLineSizeByIndex(currentColorFileIndex, pointSize, lineSize); if (value != lineSize) { colorFile->setPointLineSizeByIndex(currentColorFileIndex, pointSize, value); } } } /** * Called when point size is changed. */ void GuiColorFileEditorWidget::pointSizeChangedSlot(double value) { if (currentColorFileIndex >= 0) { float pointSize, lineSize; colorFile->getPointLineSizeByIndex(currentColorFileIndex, pointSize, lineSize); if (value != pointSize) { colorFile->setPointLineSizeByIndex(currentColorFileIndex, value, lineSize); } } } /** * called when web name push button pressed. */ void GuiColorFileEditorWidget::slotWebHtmlColorNamesPushButton() { GuiHtmlColorChooserDialog ghccd(this); if (ghccd.exec() == GuiHtmlColorChooserDialog::Accepted) { QString name; unsigned char r, g, b; ghccd.getSelectedColor(name, r, g, b); redValueSpinBox->setValue(r); greenValueSpinBox->setValue(g); blueValueSpinBox->setValue(b); alphaValueSpinBox->setValue(255); updateColorSwatch(); } } caret-5.6.4~dfsg.1.orig/caret/GuiColorFileEditorDialog.h0000664000175000017500000001224411572067322022645 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_GUI_COLOR_FILE_EDITOR_DIALOG_H__ #define __VE_GUI_COLOR_FILE_EDITOR_DIALOG_H__ #include #include #include "WuQDialog.h" class ColorFile; class QComboBox; class QListWidget; class QSlider; class QSpinBox; class QDoubleSpinBox; ///Class used for sorting colors alphabetically. class ColorSorter { public: /// Constructor ColorSorter(const QString& nameIn, const int indexIn) { colorName = nameIn; colorFileIndex = indexIn; } /// name of color QString colorName; /// index into color file int colorFileIndex; }; #ifdef __COLOR_FILE_EDITOR_MAIN__ bool operator<(const ColorSorter& c1, const ColorSorter& c2) { return (c1.colorName < c2.colorName); } #endif // __COLOR_FILE_EDITOR_MAIN__ /// This dialog is used edit a ColorFile. class GuiColorFileEditorDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiColorFileEditorDialog(QWidget* parent, ColorFile* cf, const bool showAlpha, const bool showPointSize, const bool showLineSize, const bool showSymbol, const bool modalFlag /*= false*/, const bool deleteWhenClosed = true); /// Destructor ~GuiColorFileEditorDialog(); signals: /// display should be redrawn (apply button was pressed) void redrawRequested(); private slots: /// called when OK/Canel pressed if dialog is modal void done(int r); /// called when apply button is pressed void applySlot(); /// called when an item is selected in the name list box void nameListSelectionSlot(int index); /// called when the red slider is moved void redSliderMovedSlot(int value); /// called when the green slider is moved void greenSliderMovedSlot(int value); /// called when the blue slider is moved void blueSliderMovedSlot(int value); /// called when the alpha slider is moved void alphaSliderMovedSlot(int value); /// called when line size is changed void lineSizeChangedSlot(double value); /// called when line size is changed void pointSizeChangedSlot(double value); /// called when new color button is pressed void newColorButtonSlot(); /// called when symbol combo box is selected void symbolComboBoxSlot(int value); /// called when change color name button is pressed void changeColorNameButtonSlot(); /// called when delete color button is pressed void deleteColorButtonSlot(); /// called whne button is pressed void slotColorChooserButton(); /// called when web name push button pressed void slotWebHtmlColorNamesPushButton(); private: /// load the name list box void loadColorsIntoListBox(); /// update the color of the color swatch void updateColorSwatch(); /// the color swatch QWidget* colorSwatch; /// the value label QSpinBox* redValueSpinBox; /// the color slider QSlider* redSlider; /// the value label QSpinBox* greenValueSpinBox; /// the color slider QSlider* greenSlider; /// the value label QSpinBox* blueValueSpinBox; /// the color slider QSlider* blueSlider; /// the alpha value spin box QSpinBox* alphaValueSpinBox; /// the alpha color slider QSlider* alphaSlider; /// the line size spin box QDoubleSpinBox* lineSizeSpinBox; /// the point size spin box QDoubleSpinBox* pointSizeSpinBox; /// listbox for name selection QListWidget* nameSelectionListBox; /// combo box for symbol selection QComboBox* symbolComboBox; /// the color file being edited ColorFile* colorFile; /// sorted colors std::vector colors; /// color being edited int currentColorFileIndex; }; #endif // __VE_GUI_COLOR_FILE_EDITOR_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiColorFileEditorDialog.cxx0000664000175000017500000006536011572067322023227 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "BrainSet.h" #include "ColorFile.h" #include #include "GuiBrainModelOpenGL.h" #include "GuiHtmlColorChooserDialog.h" #include "GuiMainWindow.h" #define __COLOR_FILE_EDITOR_MAIN__ #include "GuiColorFileEditorDialog.h" #undef __COLOR_FILE_EDITOR_MAIN__ #include "QtUtilities.h" #include "WuQDataEntryDialog.h" #include "global_variables.h" /** * Constructor. * For non modal dialog, leave "modalFlag" and "f" at their defaults. Call "show()" to display. * For modal dialog, set "modalFlag" to true and "f" to zero. Call "exec()" to display. */ GuiColorFileEditorDialog::GuiColorFileEditorDialog(QWidget* parent, ColorFile* cf, const bool showAlpha, const bool showPointSize, const bool showLineSize, const bool showSymbol, const bool modalFlag, const bool deleteWhenClosed) : WuQDialog(parent) { setModal(modalFlag); if (deleteWhenClosed) { setAttribute(Qt::WA_DeleteOnClose); } // // color file being edited // colorFile = cf; currentColorFileIndex = -1; setWindowTitle("Color File Editor"); // // layout for dialog // QVBoxLayout* rows = new QVBoxLayout(this); rows->setMargin(5); // // Group box for color naming // QGroupBox* colorNameGroupBox = new QGroupBox("Color Name"); rows->addWidget(colorNameGroupBox); QVBoxLayout* colorNameGroupBoxLayout = new QVBoxLayout(colorNameGroupBox); // // Name selection list box // nameSelectionListBox = new QListWidget; nameSelectionListBox->setSelectionMode(QListWidget::SingleSelection); colorNameGroupBoxLayout->addWidget(nameSelectionListBox); QObject::connect(nameSelectionListBox, SIGNAL(currentRowChanged(int)), this, SLOT(nameListSelectionSlot(int))); //QObject::connect(nameSelectionListBox, SIGNAL(selected(int)), // this, SLOT(nameListSelectionSlot(int))); // // Horizontal box for new color and delete buttons // QHBoxLayout* newDeleteButtonBoxLayout = new QHBoxLayout; colorNameGroupBoxLayout->addLayout(newDeleteButtonBoxLayout); // // Create new color button // QPushButton* newColorButton = new QPushButton("New Color..."); newDeleteButtonBoxLayout->addWidget(newColorButton); newColorButton->setAutoDefault(false); QObject::connect(newColorButton, SIGNAL(clicked()), this, SLOT(newColorButtonSlot())); // // Change color name button // QPushButton* changeColorNameButton = new QPushButton("Change Name..."); newDeleteButtonBoxLayout->addWidget(changeColorNameButton); changeColorNameButton->setAutoDefault(false); QObject::connect(changeColorNameButton, SIGNAL(clicked()), this, SLOT(changeColorNameButtonSlot())); // // Delete color button // QPushButton* deleteColorButton = new QPushButton("Delete Selected Color"); newDeleteButtonBoxLayout->addWidget(deleteColorButton); deleteColorButton->setAutoDefault(false); QObject::connect(deleteColorButton, SIGNAL(clicked()), this, SLOT(deleteColorButtonSlot())); // // Group box for color parameters // QGroupBox* colorParamGroupBox = new QGroupBox("Color Parameters"); rows->addWidget(colorParamGroupBox); QVBoxLayout* colorParamGroupBoxLayout = new QVBoxLayout(colorParamGroupBox); // // "Color swatch" widget // colorSwatch = new QWidget; colorParamGroupBoxLayout->addWidget(colorSwatch); colorSwatch->setMinimumSize(QSize(50, 50)); colorSwatch->setMaximumHeight(50); //colorSwatch->setFixedSize(QSize(200, 50)); // // Grid Layout for Colors Sliders // QGridLayout* sliderGridLayout = new QGridLayout; colorParamGroupBoxLayout->addLayout(sliderGridLayout); sliderGridLayout->setMargin(5); sliderGridLayout->setSpacing(5); // // Red control // sliderGridLayout->addWidget(new QLabel("Red"), 0, 0, Qt::AlignLeft); redValueSpinBox = new QSpinBox; redValueSpinBox->setMinimum(0); redValueSpinBox->setMaximum(255); redValueSpinBox->setSingleStep(1); sliderGridLayout->addWidget(redValueSpinBox, 0, 1, Qt::AlignRight); redSlider = new QSlider(Qt::Horizontal); redSlider->setMinimum(0); redSlider->setMaximum(255); redSlider->setPageStep(5); redSlider->setValue(0); redSlider->setMinimumWidth(300); QObject::connect(redSlider, SIGNAL(valueChanged(int)), redValueSpinBox, SLOT(setValue(int))); QObject::connect(redSlider, SIGNAL(valueChanged(int)), this, SLOT(redSliderMovedSlot(int))); QObject::connect(redValueSpinBox, SIGNAL(valueChanged(int)), redSlider, SLOT(setValue(int))); QObject::connect(redValueSpinBox, SIGNAL(valueChanged(int)), this, SLOT(redSliderMovedSlot(int))); sliderGridLayout->addWidget(redSlider, 0, 2, Qt::AlignLeft); // // Green control // sliderGridLayout->addWidget(new QLabel("Green"), 1, 0, Qt::AlignLeft); greenValueSpinBox = new QSpinBox; greenValueSpinBox->setMinimum(0); greenValueSpinBox->setMaximum(255); greenValueSpinBox->setSingleStep(1); sliderGridLayout->addWidget(greenValueSpinBox, 1, 1, Qt::AlignRight); greenSlider = new QSlider(Qt::Horizontal); greenSlider->setMinimum(0); greenSlider->setMaximum(255); greenSlider->setPageStep(5); greenSlider->setValue(0); greenSlider->setMinimumWidth(300); QObject::connect(greenSlider, SIGNAL(valueChanged(int)), greenValueSpinBox, SLOT(setValue(int))); QObject::connect(greenSlider, SIGNAL(valueChanged(int)), this, SLOT(greenSliderMovedSlot(int))); QObject::connect(greenValueSpinBox, SIGNAL(valueChanged(int)), greenSlider, SLOT(setValue(int))); QObject::connect(greenValueSpinBox, SIGNAL(valueChanged(int)), this, SLOT(greenSliderMovedSlot(int))); sliderGridLayout->addWidget(greenSlider, 1, 2, Qt::AlignLeft); // // Blue control // sliderGridLayout->addWidget(new QLabel("Blue"), 2, 0, Qt::AlignLeft); blueValueSpinBox = new QSpinBox; blueValueSpinBox->setMinimum(0); blueValueSpinBox->setMaximum(255); blueValueSpinBox->setSingleStep(1); sliderGridLayout->addWidget(blueValueSpinBox, 2, 1, Qt::AlignRight); blueSlider = new QSlider(Qt::Horizontal); blueSlider->setMinimum(0); blueSlider->setMaximum(255); blueSlider->setPageStep(5); blueSlider->setValue(0); blueSlider->setMinimumWidth(300); QObject::connect(blueSlider, SIGNAL(valueChanged(int)), blueValueSpinBox, SLOT(setValue(int))); QObject::connect(blueSlider, SIGNAL(valueChanged(int)), this, SLOT(blueSliderMovedSlot(int))); QObject::connect(blueValueSpinBox, SIGNAL(valueChanged(int)), blueSlider, SLOT(setValue(int))); QObject::connect(blueValueSpinBox, SIGNAL(valueChanged(int)), this, SLOT(blueSliderMovedSlot(int))); sliderGridLayout->addWidget(blueSlider, 2, 2, Qt::AlignLeft); // // Alpha control // QLabel* alphaLabel = new QLabel("Alpha"); sliderGridLayout->addWidget(alphaLabel, 3, 0, Qt::AlignLeft); alphaValueSpinBox = new QSpinBox; alphaValueSpinBox->setMinimum(0); alphaValueSpinBox->setMaximum(255); alphaValueSpinBox->setSingleStep(1); sliderGridLayout->addWidget(alphaValueSpinBox, 3, 1, Qt::AlignRight); alphaSlider = new QSlider(Qt::Horizontal); alphaSlider->setMinimumWidth(300); alphaSlider->setMinimum(0); alphaSlider->setMaximum(255); alphaSlider->setPageStep(5); alphaSlider->setValue(0); QObject::connect(alphaSlider, SIGNAL(valueChanged(int)), alphaValueSpinBox, SLOT(setValue(int))); QObject::connect(alphaSlider, SIGNAL(valueChanged(int)), this, SLOT(alphaSliderMovedSlot(int))); QObject::connect(alphaValueSpinBox, SIGNAL(valueChanged(int)), alphaSlider, SLOT(setValue(int))); QObject::connect(alphaValueSpinBox, SIGNAL(valueChanged(int)), this, SLOT(alphaSliderMovedSlot(int))); sliderGridLayout->addWidget(alphaSlider, 3, 2, Qt::AlignLeft); if (showAlpha == false) { alphaLabel->hide(); alphaValueSpinBox->hide(); alphaSlider->hide(); } // // Pushbutton for color chooser // QPushButton* colorChooserButton = new QPushButton("Advanced Color Selection..."); colorChooserButton->setAutoDefault(false); colorChooserButton->setToolTip( "Press this button to pop up a dialog\n" "with more powerful color selection."); colorChooserButton->setFixedSize(colorChooserButton->sizeHint()); QObject::connect(colorChooserButton, SIGNAL(clicked()), this, SLOT(slotColorChooserButton())); // // Pushbutton for web (html) colors // QPushButton* webHtmlColorPushButton = new QPushButton("List of Common Colors..."); webHtmlColorPushButton->setAutoDefault(false); webHtmlColorPushButton->setToolTip( "Press this button to select colors\n" "defined by the World Wide Web Consortium"); webHtmlColorPushButton->setFixedSize(webHtmlColorPushButton->sizeHint()); QObject::connect(webHtmlColorPushButton, SIGNAL(clicked()), this, SLOT(slotWebHtmlColorNamesPushButton())); // // Layout for color buttons // QHBoxLayout* colorPushButtonsLayout = new QHBoxLayout; colorPushButtonsLayout->addWidget(colorChooserButton); colorPushButtonsLayout->addWidget(webHtmlColorPushButton); colorPushButtonsLayout->addStretch(); colorParamGroupBoxLayout->addLayout(colorPushButtonsLayout); // // QGrid for Line and Point Size and symbol // QGridLayout* attsGridLayout = new QGridLayout; colorParamGroupBoxLayout->addLayout(attsGridLayout); float minLineSize, maxLineSize; GuiBrainModelOpenGL::getLineWidthRange(minLineSize, maxLineSize); QLabel* lineSizeLabel = new QLabel("Line Size"); attsGridLayout->addWidget(lineSizeLabel, 0, 0); lineSizeSpinBox = new QDoubleSpinBox; lineSizeSpinBox->setMinimum(minLineSize); lineSizeSpinBox->setMaximum(maxLineSize); lineSizeSpinBox->setSingleStep(1.0); lineSizeSpinBox->setDecimals(1); attsGridLayout->addWidget(lineSizeSpinBox, 0, 1); lineSizeSpinBox->setValue(1.0); QObject::connect(lineSizeSpinBox, SIGNAL(valueChanged(double)), this, SLOT(lineSizeChangedSlot(double))); if (showLineSize == false) { lineSizeLabel->hide(); lineSizeSpinBox->hide(); } float minPointSize, maxPointSize; GuiBrainModelOpenGL::getPointSizeRange(minPointSize, maxPointSize); maxPointSize = 100000.0; QLabel* pointSizeLabel = new QLabel("Point Size"); attsGridLayout->addWidget(pointSizeLabel, 1, 0); pointSizeSpinBox = new QDoubleSpinBox; pointSizeSpinBox->setMinimum(minPointSize); pointSizeSpinBox->setMaximum(maxPointSize); pointSizeSpinBox->setSingleStep(1.0); pointSizeSpinBox->setDecimals(1); attsGridLayout->addWidget(pointSizeSpinBox, 1, 1); pointSizeSpinBox->setValue(2.0); QObject::connect(pointSizeSpinBox, SIGNAL(valueChanged(double)), this, SLOT(pointSizeChangedSlot(double))); if (showPointSize == false) { pointSizeLabel->hide(); pointSizeSpinBox->hide(); } // // Symbol // QLabel* symbolLabel = new QLabel("Symbol"); attsGridLayout->addWidget(symbolLabel, 2, 0); symbolComboBox = new QComboBox; attsGridLayout->addWidget(symbolComboBox, 2, 1); std::vector symbolLabels; ColorFile::ColorStorage::getAllSymbolTypesAsStrings(symbolLabels); for (unsigned int i = 0; i < symbolLabels.size(); i++) { symbolComboBox->addItem(symbolLabels[i]); } QObject::connect(symbolComboBox, SIGNAL(activated(int)), this, SLOT(symbolComboBoxSlot(int))); if (showSymbol == false) { symbolLabel->hide(); symbolComboBox->hide(); } // // Squeeze Grid // //attsGridLayout->setFixedSize(attsGridLayout->sizeHint()); // // Load and initialize the color list box // loadColorsIntoListBox(); nameListSelectionSlot(0); // // Dialog Buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; rows->addLayout(buttonsLayout); // // Apply button // QPushButton* applyButton = NULL; if (isModal() == false) { applyButton = new QPushButton("Apply"); applyButton->setAutoDefault(false); QObject::connect(applyButton, SIGNAL(clicked()), this, SLOT(applySlot())); QObject::connect(applyButton, SIGNAL(clicked()), this, SIGNAL(redrawRequested())); buttonsLayout->addWidget(applyButton); } // // Close button // QPushButton* closeButton = new QPushButton("Close"); if (isModal()) { closeButton->setText("OK"); } closeButton->setAutoDefault(false); QObject::connect(closeButton, SIGNAL(clicked()), this, SIGNAL(redrawRequested())); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); buttonsLayout->addWidget(closeButton); // // Make buttons the same size // QtUtilities::makeButtonsSameSize(applyButton, closeButton); } /** * Destructor */ GuiColorFileEditorDialog::~GuiColorFileEditorDialog() { } /** * called when color chooser button is pressed. */ void GuiColorFileEditorDialog::slotColorChooserButton() { // // Popup QT's color chooser dialog // QColor inputColor(redValueSpinBox->value(), greenValueSpinBox->value(), blueValueSpinBox->value()); QColor outputColor = QColorDialog::getColor(inputColor, this); if (outputColor.isValid()) { if ((currentColorFileIndex >= 0) && (currentColorFileIndex < static_cast(colors.size()))) { colorFile->setColorByIndex(currentColorFileIndex, outputColor.red(), outputColor.green(), outputColor.blue()); redValueSpinBox->setValue(outputColor.red()); greenValueSpinBox->setValue(outputColor.green()); blueValueSpinBox->setValue(outputColor.blue()); updateColorSwatch(); } } } /** * Called when new color button is pressed */ void GuiColorFileEditorDialog::newColorButtonSlot() { // // Initialize color to foreground color // unsigned char red, green, blue; unsigned char alpha = 255; PreferencesFile* pref = theMainWindow->getBrainSet()->getPreferencesFile(); pref->getSurfaceForegroundColor(red, green, blue); float pointSize = 2.0, lineSize = 1.0; // // Default to currently selected color // QString defaultName = ""; if (currentColorFileIndex >= 0) { colorFile->getColorByIndex(currentColorFileIndex, red, green, blue, alpha); colorFile->getPointLineSizeByIndex(currentColorFileIndex, pointSize, lineSize); defaultName = colorFile->getColorNameByIndex(currentColorFileIndex); } // // Get the new color name using a qt input dialog for text // bool ok = false; const QString nameInput = QInputDialog::getText(this, "New Color Name", "Color Name", QLineEdit::Normal, defaultName, &ok); // // Name entered and ok button was pressed // if (ok && (nameInput.isEmpty() == false)) { const QString name(nameInput); // // See if color with name exists, if so switch to it and popup message // bool match = false; int colorIndex = colorFile->getColorIndexByName(name, match); if ((colorIndex >= 0) && match) { for (int i = 0; i < static_cast(colors.size()); i++) { if (colors[i].colorFileIndex == colorIndex) { nameSelectionListBox->setCurrentRow(i); nameListSelectionSlot(i); break; } } QString msg("Color "); msg.append(name); msg.append(" already exists."); QMessageBox::warning(this, "Color Exists", msg); return; } // // Create a new color // colorFile->addColor(name, red, green, blue, alpha, pointSize, lineSize); loadColorsIntoListBox(); // // Select the new color // nameSelectionListBox->setCurrentRow(0); nameListSelectionSlot(0); colorIndex = colorFile->getColorIndexByName(name, match); if ((colorIndex >= 0) && match) { for (int i = 0; i < static_cast(colors.size()); i++) { if (colors[i].colorFileIndex == colorIndex) { nameSelectionListBox->setCurrentRow(i); nameListSelectionSlot(i); break; } } } } // // Redraw since color file has changed // emit redrawRequested(); } /** * called when change color name button is pressed. */ void GuiColorFileEditorDialog::changeColorNameButtonSlot() { if (currentColorFileIndex >= 0) { const QString name = colorFile->getColorNameByIndex(currentColorFileIndex); // // Get the new name // WuQDataEntryDialog ded(this); ded.setWindowTitle("Edit Color Name"); QLineEdit* nameLineEdit = ded.addLineEditWidget("Color Name", name); if (ded.exec() == WuQDataEntryDialog::Accepted) { const QString newName = nameLineEdit->text(); if ((newName.isEmpty() == false) && (newName != name)) { // // Change the name // colorFile->setColorNameByIndex(currentColorFileIndex, newName); // // Reload list box // loadColorsIntoListBox(); // // Find new name // int listBoxIndex = -1; for (int i = 0; i < nameSelectionListBox->count(); i++) { if (nameSelectionListBox->item(i)->text() == newName) { listBoxIndex = i; break; } } if (listBoxIndex >= 0) { nameSelectionListBox->setCurrentRow(listBoxIndex); nameListSelectionSlot(listBoxIndex); } // // Redraw since color file has changed // emit redrawRequested(); } } } } /** * Called when delete color button is pressed */ void GuiColorFileEditorDialog::deleteColorButtonSlot() { int listBoxIndex = nameSelectionListBox->currentRow(); if (listBoxIndex >= 0) { const int colorIndex = colors[listBoxIndex].colorFileIndex; // // Remove the color // colorFile->removeColorByIndex(colorIndex); loadColorsIntoListBox(); // // Reset items in list box // if (listBoxIndex >= static_cast(colors.size())) { listBoxIndex = colors.size() - 1; } if (listBoxIndex >= 0) { nameSelectionListBox->setCurrentRow(listBoxIndex); nameListSelectionSlot(listBoxIndex); } // // Redraw since color file has changed // emit redrawRequested(); } } /** * Called when apply button is pressed. */ void GuiColorFileEditorDialog::applySlot() { } /** * called when OK/Canel pressed if dialog is modal. */ void GuiColorFileEditorDialog::done(int r) { applySlot(); QDialog::done(r); } /** * Initialize the controls */ void GuiColorFileEditorDialog::loadColorsIntoListBox() { // // Load and Sort the colors // colors.clear(); int num = colorFile->getNumberOfColors(); for (int i = 0; i < num; i++) { colors.push_back(ColorSorter(colorFile->getColorNameByIndex(i), i)); } std::sort(colors.begin(), colors.end()); // // Load the color names into the list selection box // nameSelectionListBox->clear(); num = colors.size(); for (int i = 0; i < num; i++) { nameSelectionListBox->addItem(colors[i].colorName); } if (num > 0) { currentColorFileIndex = colors[0].colorFileIndex; nameSelectionListBox->setCurrentRow(0); } else { currentColorFileIndex = -1; } } /** * Update the color swatch */ void GuiColorFileEditorDialog::updateColorSwatch() { QColor color; if (currentColorFileIndex >= 0) { unsigned char r, g, b; colorFile->getColorByIndex(currentColorFileIndex, r, g, b); color.setRgb(r, g, b); } QPalette pal; pal.setColor(QPalette::Window, color); colorSwatch->setAutoFillBackground(true); colorSwatch->setBackgroundRole(QPalette::Window); colorSwatch->setPalette(pal); //colorSwatch->setPaletteBackgroundColor(color); //colorSwatch->setPaletteForegroundColor(color); } /** * Slot called when a name is selected in the name list box. */ void GuiColorFileEditorDialog::nameListSelectionSlot(int indx) { if ((indx >= 0) && (indx < static_cast(colors.size()))) { currentColorFileIndex = colors[indx].colorFileIndex; } else { currentColorFileIndex = -1; } if (currentColorFileIndex >= 0) { unsigned char r, g, b, a; colorFile->getColorByIndex(currentColorFileIndex, r, g, b, a); redSlider->setValue(r); redValueSpinBox->setValue(r); greenSlider->setValue(g); greenValueSpinBox->setValue(g); blueSlider->setValue(b); blueValueSpinBox->setValue(b); alphaSlider->setValue(a); alphaValueSpinBox->setValue(a); float pointSize, lineSize; colorFile->getPointLineSizeByIndex(currentColorFileIndex, pointSize, lineSize); if (lineSizeSpinBox != NULL) { lineSizeSpinBox->setValue(lineSize); } if (pointSizeSpinBox != NULL) { pointSizeSpinBox->setValue(pointSize); } symbolComboBox->setCurrentIndex(colorFile->getSymbolByIndex(currentColorFileIndex)); } updateColorSwatch(); } /** * called when symbol combo box is selected. */ void GuiColorFileEditorDialog::symbolComboBoxSlot(int value) { if (currentColorFileIndex >= 0) { ColorFile::ColorStorage::SYMBOL s = static_cast(value); if (s != colorFile->getSymbolByIndex(currentColorFileIndex)) { colorFile->setSymbolByIndex(currentColorFileIndex, s); } } } /** * Slot called when the red slider is moved. */ void GuiColorFileEditorDialog::redSliderMovedSlot(int value) { if (currentColorFileIndex >= 0) { unsigned char r, g, b, a; colorFile->getColorByIndex(currentColorFileIndex, r, g, b, a); const unsigned char red = static_cast(value); if (red != r) { colorFile->setColorByIndex(currentColorFileIndex, red, g, b, a); } } updateColorSwatch(); } /** * Slot called when the green slider is moved. */ void GuiColorFileEditorDialog::greenSliderMovedSlot(int value) { if (currentColorFileIndex >= 0) { unsigned char r, g, b, a; colorFile->getColorByIndex(currentColorFileIndex, r, g, b, a); const unsigned char green = static_cast(value); if (green != g) { colorFile->setColorByIndex(currentColorFileIndex, r, green, b, a); } } updateColorSwatch(); } /** * Slot called when the blue slider is moved. */ void GuiColorFileEditorDialog::blueSliderMovedSlot(int value) { if (currentColorFileIndex >= 0) { unsigned char r, g, b, a; colorFile->getColorByIndex(currentColorFileIndex, r, g, b, a); const unsigned char blue = static_cast(value); if (blue != b) { colorFile->setColorByIndex(currentColorFileIndex, r, g, blue, a); } } updateColorSwatch(); } /** * Slot called when the alpha slider is moved. */ void GuiColorFileEditorDialog::alphaSliderMovedSlot(int value) { if (currentColorFileIndex >= 0) { unsigned char r, g, b, a; colorFile->getColorByIndex(currentColorFileIndex, r, g, b, a); const unsigned char alpha = static_cast(value); if (alpha != a) { colorFile->setColorByIndex(currentColorFileIndex, r, g, b, alpha); } } updateColorSwatch(); } /** * Called when line size is changed. */ void GuiColorFileEditorDialog::lineSizeChangedSlot(double value) { if (currentColorFileIndex >= 0) { float pointSize, lineSize; colorFile->getPointLineSizeByIndex(currentColorFileIndex, pointSize, lineSize); if (value != lineSize) { colorFile->setPointLineSizeByIndex(currentColorFileIndex, pointSize, value); } } } /** * Called when point size is changed. */ void GuiColorFileEditorDialog::pointSizeChangedSlot(double value) { if (currentColorFileIndex >= 0) { float pointSize, lineSize; colorFile->getPointLineSizeByIndex(currentColorFileIndex, pointSize, lineSize); if (value != pointSize) { colorFile->setPointLineSizeByIndex(currentColorFileIndex, value, lineSize); } } } /** * called when web name push button pressed. */ void GuiColorFileEditorDialog::slotWebHtmlColorNamesPushButton() { GuiHtmlColorChooserDialog ghccd(this); if (ghccd.exec() == GuiHtmlColorChooserDialog::Accepted) { QString name; unsigned char r, g, b; ghccd.getSelectedColor(name, r, g, b); redValueSpinBox->setValue(r); greenValueSpinBox->setValue(g); blueValueSpinBox->setValue(b); alphaValueSpinBox->setValue(255); updateColorSwatch(); } } caret-5.6.4~dfsg.1.orig/caret/GuiChooseSpecFileDialog.h0000664000175000017500000000605411572067322022455 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_CHOOSE_SPEC_FILE_DIALOG_H__ #define __GUI_CHOOSE_SPEC_FILE_DIALOG_H__ #include #include #include "WuQFileDialog.h" class GuiPreviousSpecFileComboBox; class QPushButton; class QGroupBox; class PreferencesFile; class QtTextEditDialog; /// class for a file dialog specialized for choosing spec files class GuiChooseSpecFileDialog : public WuQFileDialog { Q_OBJECT public: /// Constructor GuiChooseSpecFileDialog(QWidget* parent, const std::vector& previousSpecFilesIn, const bool modal, const bool allowMultipleSelectionsFlag = false); /// Constructor GuiChooseSpecFileDialog(QWidget* parent, const PreferencesFile* pf, const bool modal, const bool allowMultipleSelectionsFlag = false); /// Destructor ~GuiChooseSpecFileDialog(); /// get the selected spec file QString getSelectedSpecFile() const; /// get the selected spec files std::vector getSelectedSpecFiles() const; protected slots: /// called when a previous spec file is selected void slotPreviousSpecFileComboBox(const QString& name); /// called when view pushbutton is pressed void slotViewPushButton(); /// Called when a file is highlighted void slotFilesSelected(const QStringList& name); protected: /// create the dialog void createDialog(const std::vector& specFileNames, const bool allowMultipleSpecFilesFlag); /// previous spec files combo box GuiPreviousSpecFileComboBox* previousSpecFilesComboBox; /// previous spec files group box QGroupBox* previousSpecFilesGroupBox; /// view push button QPushButton* viewPushButton; /// highlighted file name for viewing QString highlightedFileName; /// view contents of spec file QtTextEditDialog* viewContentsDialog; }; #endif // __GUI_CHOOSE_SPEC_FILE_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiChooseSpecFileDialog.cxx0000664000175000017500000001331711572067322023030 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include "FileFilters.h" #include "FileUtilities.h" #include "GuiChooseSpecFileDialog.h" #include "GuiDataFileCommentDialog.h" #include "GuiPreviousSpecFileComboBox.h" #include "SpecFile.h" #include "PreferencesFile.h" #include "QtTextEditDialog.h" #include "QtUtilities.h" /** * Constructor. */ GuiChooseSpecFileDialog::GuiChooseSpecFileDialog(QWidget* parent, const std::vector& previousSpecFilesIn, const bool modalIn, const bool allowMultipleSelectionsFlag) : WuQFileDialog(parent) { setModal(modalIn); createDialog(previousSpecFilesIn, allowMultipleSelectionsFlag); } /** * Constructor. */ GuiChooseSpecFileDialog::GuiChooseSpecFileDialog(QWidget* parent, const PreferencesFile* pf, const bool modalIn, const bool allowMultipleSelectionsFlag) : WuQFileDialog(parent) { setModal(modalIn); std::vector specFileNames; pf->getRecentSpecFiles(specFileNames); setHistory(pf->getRecentDataFileDirectories()); createDialog(specFileNames, allowMultipleSelectionsFlag); } /** * Create the dialog. */ void GuiChooseSpecFileDialog::createDialog(const std::vector& specFileNames, const bool allowMultipleSpecFilesFlag) { viewContentsDialog = NULL; setDirectory(QDir::currentPath()); setWindowTitle("Choose Spec File"); setAcceptMode(WuQFileDialog::AcceptOpen); if (allowMultipleSpecFilesFlag) { setFileMode(WuQFileDialog::ExistingFiles); } else { setFileMode(WuQFileDialog::ExistingFile); } setFilters(QStringList(FileFilters::getSpecFileFilter())); selectFilter(FileFilters::getSpecFileFilter()); // // Combo box for selecting previous spec files // previousSpecFilesComboBox = new GuiPreviousSpecFileComboBox(0, specFileNames); QObject::connect(previousSpecFilesComboBox, SIGNAL(specFileSelected(const QString&)), this, SLOT(slotPreviousSpecFileComboBox(const QString&))); // // Create group box for previous spec files // previousSpecFilesGroupBox = new QGroupBox("Previous Spec Files"); QVBoxLayout* prevSpecFileLayout = new QVBoxLayout(previousSpecFilesGroupBox); prevSpecFileLayout->addWidget(previousSpecFilesComboBox); // // View contents button // viewPushButton = new QPushButton("View/Edit Comment...", this); viewPushButton->setAutoDefault(false); QObject::connect(viewPushButton, SIGNAL(clicked()), this, SLOT(slotViewPushButton())); viewPushButton->setEnabled(false); // // Called when a file is highlighted // QObject::connect(this, SIGNAL(filesSelected(const QStringList&)), this, SLOT(slotFilesSelected(const QStringList&))); addWidgets(previousSpecFilesGroupBox, previousSpecFilesGroupBox, viewPushButton); QtUtilities::setMaximumHeightToNinetyPercentOfScreenHeight(this); } /** * get the selected spec file. */ QString GuiChooseSpecFileDialog::getSelectedSpecFile() const { QString name; const QStringList fileList = selectedFiles(); if (fileList.count() > 0) { name = fileList.at(0); } return name; } /** * get the selected spec files. */ std::vector GuiChooseSpecFileDialog::getSelectedSpecFiles() const { std::vector names; const QStringList fileList = selectedFiles(); int numFiles = fileList.count(); if ((numFiles > 1) && (fileMode() == WuQFileDialog::ExistingFile)) { numFiles = 1; } for (int i = 0; i < numFiles; i++) { names.push_back(fileList.at(i)); } return names; } /** * Destructor. */ GuiChooseSpecFileDialog::~GuiChooseSpecFileDialog() { } /** * Called when a file is highlighted */ void GuiChooseSpecFileDialog::slotFilesSelected(const QStringList& names) { highlightedFileName = ""; viewPushButton->setEnabled(false); if (names.count() == 1) { highlightedFileName = names.at(0); viewPushButton->setEnabled(true); } } /** * called when view pushbutton is pressed. */ void GuiChooseSpecFileDialog::slotViewPushButton() { GuiDataFileCommentDialog* dfcd = new GuiDataFileCommentDialog(this, highlightedFileName, false); dfcd->show(); } /** * called when a previous spec file is selected. */ void GuiChooseSpecFileDialog::slotPreviousSpecFileComboBox(const QString& name) { selectFile(name); } caret-5.6.4~dfsg.1.orig/caret/GuiChooseNodeAttributeColumnDialog.h0000664000175000017500000000462111572067322024710 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_CHOOSE_NODE_ATTRIBUTE_COLUMN_DIALOG_H__ #define __GUI_CHOOSE_NODE_ATTRIBUTE_COLUMN_DIALOG_H__ #include #include "GuiNodeFileType.h" #include "WuQDialog.h" class GuiNodeAttributeColumnSelectionComboBox; class GiftiNodeDataFile; class NodeAttributeFile; class QLineEdit; /// class for dialog for choosing a node attribute file column and column name class GuiChooseNodeAttributeColumnDialog : public WuQDialog { Q_OBJECT public: /// constructor GuiChooseNodeAttributeColumnDialog(QWidget* parent, GUI_NODE_FILE_TYPE nft, const QString& noneColumnLabel, const bool addNewSelection = false, const bool addNoneSelection = false); /// destructor ~GuiChooseNodeAttributeColumnDialog(); /// get the selected column number int getSelectedColumnNumber() const; /// set the selected column number void setSelectedColumnNumber(const int col) const; /// get the name for the column QString getColumnName() const; protected slots: /// called when a column is selected void slotNodeAttributeComboBox(); protected: /// column selection combo box GuiNodeAttributeColumnSelectionComboBox* nodeAttributeComboBox; /// column name line edit QLineEdit* columnNameLineEdit; }; #endif // __GUI_CHOOSE_NODE_ATTRIBUTE_COLUMN_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiChooseNodeAttributeColumnDialog.cxx0000664000175000017500000001100511572067322025255 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include "GuiChooseNodeAttributeColumnDialog.h" #include "GuiNodeAttributeColumnSelectionComboBox.h" #include "GiftiNodeDataFile.h" #include "NodeAttributeFile.h" #include "QtUtilities.h" /** * constructor. */ GuiChooseNodeAttributeColumnDialog::GuiChooseNodeAttributeColumnDialog( QWidget* parent, GUI_NODE_FILE_TYPE nft, const QString& noneColumnLabel, const bool addNewSelection, const bool addNoneSelection) : WuQDialog(parent) { setModal(true); setWindowTitle("Choose Column"); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // column to assign labe, combo box, and line edit // QHBoxLayout* columnHBoxLayout = new QHBoxLayout; dialogLayout->addLayout(columnHBoxLayout); columnHBoxLayout->addWidget(new QLabel("Column")); nodeAttributeComboBox = new GuiNodeAttributeColumnSelectionComboBox( nft, addNewSelection, addNoneSelection, false); columnHBoxLayout->addWidget(nodeAttributeComboBox); nodeAttributeComboBox->setNoneSelectionLabel(noneColumnLabel); QObject::connect(nodeAttributeComboBox, SIGNAL(itemSelected(int)), this, SLOT(slotNodeAttributeComboBox())); columnNameLineEdit = new QLineEdit; columnHBoxLayout->addWidget(columnNameLineEdit); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); dialogLayout->addLayout(buttonsLayout); // // OK pushbutton // QPushButton* okButton = new QPushButton("OK"); okButton->setAutoDefault(false); buttonsLayout->addWidget(okButton); QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); // // Cancel button. // QPushButton* cancelButton = new QPushButton("Cancel"); cancelButton->setAutoDefault(false); buttonsLayout->addWidget(cancelButton); QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); // // Force buttons to be same size // QtUtilities::makeButtonsSameSize(okButton, cancelButton); slotNodeAttributeComboBox(); } /** * destructor. */ GuiChooseNodeAttributeColumnDialog::~GuiChooseNodeAttributeColumnDialog() { } /** * called when a column is selected. */ void GuiChooseNodeAttributeColumnDialog::slotNodeAttributeComboBox() { columnNameLineEdit->setText(nodeAttributeComboBox->getCurrentLabel()); } /** * set the selected column number. */ void GuiChooseNodeAttributeColumnDialog::setSelectedColumnNumber(const int col) const { if ((col >= 0) && (col < nodeAttributeComboBox->count())) { nodeAttributeComboBox->setCurrentIndex(col); } } /** * get the selected column number. * Returns GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NEW for new * Returns GuiNodeAttributeColumnSelectionComboBox::CURRENT_ITEM_NONE for none */ int GuiChooseNodeAttributeColumnDialog::getSelectedColumnNumber() const { return nodeAttributeComboBox->currentIndex(); } /** * get the name for the column. */ QString GuiChooseNodeAttributeColumnDialog::getColumnName() const { return columnNameLineEdit->text(); } caret-5.6.4~dfsg.1.orig/caret/GuiCellsOrFociProjectionDialog.h0000664000175000017500000000452111572067322024020 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_PROJECT_CELLS_OR_FOCI_DIALOG_H__ #define __GUI_PROJECT_CELLS_OR_FOCI_DIALOG_H__ #include "WuQDialog.h" class QRadioButton; class QDoubleSpinBox; /// class for dialog used to project cells and foci class GuiCellsOrFociProjectionDialog : public WuQDialog { Q_OBJECT public: /// type of file to project enum FILE_TYPE { FILE_TYPE_CELL, FILE_TYPE_FOCI }; /// Constructor GuiCellsOrFociProjectionDialog(QWidget* parent, FILE_TYPE fileTypeIn); /// Destructor ~GuiCellsOrFociProjectionDialog(); private slots: /// called when help button is pressed void slotHelpButton(); private: /// called when OK or Cancel button pressed virtual void done(int r); /// type of file being projected FILE_TYPE fileType; /// project all radio button QRadioButton* projectAllRadioButton; /// project hemisphere only radio button QRadioButton* projectHemisphereOnlyRadioButton; /// project flip to match radio button QRadioButton* projectFlipToMatchRadioButton; /// project onto surface check box QRadioButton* projectOntoSurfaceRadioButton; /// keep offset from surface QRadioButton* maintainOffsetFromSurfaceRadioButton; /// above surface distance QDoubleSpinBox* surfaceOffsetDoubleSpinBox; }; #endif // __GUI_PROJECT_CELLS_OR_FOCI_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiCellsOrFociProjectionDialog.cxx0000664000175000017500000002161111572067322024372 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include "BrainModelSurface.h" #include "BrainSet.h" #include "CellFile.h" #include "CellFileProjector.h" #include "CellProjectionFile.h" #include "FociFile.h" #include "FociProjectionFile.h" #include "GuiBrainModelOpenGL.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "GuiCellsOrFociProjectionDialog.h" #include #include "QtUtilities.h" #include "WuQDialog.h" #include "global_variables.h" /** * Constructor. */ GuiCellsOrFociProjectionDialog::GuiCellsOrFociProjectionDialog(QWidget* parent, FILE_TYPE fileTypeIn) : WuQDialog(parent) { setModal(true); fileType = fileTypeIn; switch (fileType) { case FILE_TYPE_CELL: setWindowTitle("Cell Projection"); break; case FILE_TYPE_FOCI: setWindowTitle("Foci Projection"); break; } // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // The radio buttons // projectAllRadioButton = new QRadioButton("All (no sign flips to match hemisphere)"); projectFlipToMatchRadioButton = new QRadioButton("All (Flip signs to match Hemisphere; Surface MUST be AC centered)"); projectHemisphereOnlyRadioButton = new QRadioButton("Hemisphere Only (Surface MUST be AC centered)"); // // Button group for data to project // QButtonGroup* dataButtonGroup = new QButtonGroup(this); dataButtonGroup->addButton(projectAllRadioButton); dataButtonGroup->addButton(projectFlipToMatchRadioButton); dataButtonGroup->addButton(projectHemisphereOnlyRadioButton); // // Projection type group box // QGroupBox* projectionGroupBox = new QGroupBox("Data For Projection"); dialogLayout->addWidget(projectionGroupBox); QVBoxLayout* projectionGroupLayout = new QVBoxLayout(projectionGroupBox); projectionGroupLayout->addWidget(projectAllRadioButton); projectionGroupLayout->addWidget(projectFlipToMatchRadioButton); projectionGroupLayout->addWidget(projectHemisphereOnlyRadioButton); // // Project onto surface option // projectOntoSurfaceRadioButton = new QRadioButton("Project Above Surface"); surfaceOffsetDoubleSpinBox = new QDoubleSpinBox; surfaceOffsetDoubleSpinBox->setMinimum(0.0); surfaceOffsetDoubleSpinBox->setMaximum(1000.0); surfaceOffsetDoubleSpinBox->setSingleStep(1.0); surfaceOffsetDoubleSpinBox->setDecimals(2); QHBoxLayout* ontoSurfaceHBoxLayout = new QHBoxLayout; ontoSurfaceHBoxLayout->addWidget(projectOntoSurfaceRadioButton); ontoSurfaceHBoxLayout->addWidget(surfaceOffsetDoubleSpinBox); // // Maintain offset from surface option // maintainOffsetFromSurfaceRadioButton = new QRadioButton("Keep Offset From Surface"); maintainOffsetFromSurfaceRadioButton->setChecked(true); // // Button group for spatial projection // QButtonGroup* projectionButtonGroup = new QButtonGroup(this); projectionButtonGroup->addButton(projectOntoSurfaceRadioButton); projectionButtonGroup->addButton(maintainOffsetFromSurfaceRadioButton); // // Spatial projection type options box // QGroupBox* projectionTypeGroupBox = new QGroupBox("Spatial Projection Type"); dialogLayout->addWidget(projectionTypeGroupBox); QVBoxLayout* projectionTypeLayout = new QVBoxLayout(projectionTypeGroupBox); projectionTypeLayout->addLayout(ontoSurfaceHBoxLayout); projectionTypeLayout->addWidget(maintainOffsetFromSurfaceRadioButton); QLabel* notesLabel = new QLabel( "Caret determines the hemisphere of cells/foci using the\n" "sign of the X-coordinate. Negative implies left\n" "hemisphere, positive implies right hemisphere."); QGroupBox* noteGroupBox = new QGroupBox("Important Information"); QVBoxLayout* notesLayout = new QVBoxLayout(noteGroupBox); notesLayout->addWidget(notesLabel); dialogLayout->addWidget(noteGroupBox); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); dialogLayout->addLayout(buttonsLayout); // // OK button // QPushButton* okButton = new QPushButton("OK"); okButton->setAutoDefault(false); buttonsLayout->addWidget(okButton); QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); // // Cancel button // QPushButton* cancelButton = new QPushButton("Cancel"); cancelButton->setAutoDefault(false); buttonsLayout->addWidget(cancelButton); QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); // // Help button // QPushButton* helpButton = new QPushButton("Help"); helpButton->setAutoDefault(false); buttonsLayout->addWidget(helpButton); QObject::connect(helpButton, SIGNAL(clicked()), this, SLOT(slotHelpButton())); QtUtilities::makeButtonsSameSize(okButton, cancelButton, helpButton); } /** * Destructor. */ GuiCellsOrFociProjectionDialog::~GuiCellsOrFociProjectionDialog() { } /** * Called when help button is pressed. */ void GuiCellsOrFociProjectionDialog::slotHelpButton() { theMainWindow->showHelpPageOverModalDialog(this, "dialogs/project_cells_foci_dialog.html"); } /** * called when OK or Cancel button pressed. */ void GuiCellsOrFociProjectionDialog::done(int r) { // // Was OK button pressed // if (r == QDialog::Accepted) { // // Get projection type // CellFileProjector::PROJECTION_TYPE projType = CellFileProjector::PROJECTION_TYPE_ALL; if (projectAllRadioButton->isChecked()) { projType = CellFileProjector::PROJECTION_TYPE_ALL; } else if (projectHemisphereOnlyRadioButton->isChecked()) { projType = CellFileProjector::PROJECTION_TYPE_HEMISPHERE_ONLY; } else if (projectFlipToMatchRadioButton->isChecked()) { projType = CellFileProjector::PROJECTION_TYPE_FLIP_TO_MATCH_HEMISPHERE; } else { QMessageBox::critical(this, "ERROR", "You must select a projection type."); return; } // // Find the fiducial surface // BrainModelSurface* bms = theMainWindow->getBrainSet()->getActiveFiducialSurface(); if (bms == NULL) { QMessageBox::critical(this, "ERROR", "There is no fiducial surface."); return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); // // Save name and clear cell/foci projection file and get cell/foci files // CellProjectionFile* cpf = NULL; switch (fileType) { case FILE_TYPE_CELL: cpf = theMainWindow->getBrainSet()->getCellProjectionFile(); break; case FILE_TYPE_FOCI: cpf = theMainWindow->getBrainSet()->getFociProjectionFile(); break; } // // Project all of the cell/foci files // CellFileProjector projector(bms); projector.projectFile(cpf, 0, projType, surfaceOffsetDoubleSpinBox->value(), projectOntoSurfaceRadioButton->isChecked(), theMainWindow); GuiFilesModified fm; switch (fileType) { case FILE_TYPE_CELL: fm.setCellModified(); fm.setCellProjectionModified(); break; case FILE_TYPE_FOCI: fm.setFociModified(); fm.setFociProjectionModified(); break; } // // Update now that cells/foci are changed // theMainWindow->fileModificationUpdate(fm); // // Update all displayed surfaces // GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } QDialog::done(r); } caret-5.6.4~dfsg.1.orig/caret/GuiCellAttributesDialog.h0000664000175000017500000000475511572067322022556 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_GUI_CELL_ATTRIBUTES_DIALOG_H__ #define __VE_GUI_CELL_ATTRIBUTES_DIALOG_H__ #include #include #include "WuQDialog.h" class QCheckBox; class QLineEdit; /// This class creates the cell attributes editor dialog class GuiCellAttributesDialog : public WuQDialog { Q_OBJECT public: /// storage for unique cell attributes class CellAttributes { public: /// name of cell QString name; /// retain this cell bool retain; /// constructor CellAttributes(const QString& nameIn) { name = nameIn; retain = true; } bool operator=(const CellAttributes& ba) const { return (name == ba.name); } }; /// Constructor GuiCellAttributesDialog(QWidget* parent); /// Destructor ~GuiCellAttributesDialog(); private slots: /// Apply button slot void slotApplyButton(); private: /// storage for the unique cells std::vector attributes; /// retain check boxes std::vector retainCheckBoxes; /// names or cells std::vector originalNames; /// name line edits std::vector nameLineEdits; /// get the index for this original name int getIndexFromOriginalName(const QString& name) const; /// setup the cell attributes void setupCellAttributes(); }; #endif // __VE_GUI_CELL_ATTRIBUTES_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiCellAttributesDialog.cxx0000664000175000017500000001534111572067322023122 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include "BrainSet.h" #include "CellProjectionFile.h" #include "GuiCellAttributesDialog.h" #include "GuiBrainModelOpenGL.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "QtUtilities.h" #include "global_variables.h" static int operator<(const GuiCellAttributesDialog::CellAttributes& b1, const GuiCellAttributesDialog::CellAttributes& b2) { return (b1.name < b2.name); } /** * Constructor. */ GuiCellAttributesDialog::GuiCellAttributesDialog(QWidget* parent) : WuQDialog(parent) { setAttribute(Qt::WA_DeleteOnClose); setWindowTitle("Edit Cell Attributes"); // // Layout for dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setSpacing(5); dialogLayout->setMargin(5); // // Consolidate the cell attributes // setupCellAttributes(); const int numAttributes = static_cast(attributes.size()); int numColumns = 0; const int RETAIN_COLUMN = numColumns++; const int NAME_COLUMN = numColumns++; int rowNumber = 0; // // widget and layout in the scrollview // QWidget* svWidget = new QWidget; QGridLayout* grid = new QGridLayout(svWidget); grid->setMargin(3); grid->setSpacing(3); // // column titles // grid->addWidget(new QLabel("Keep"), rowNumber, RETAIN_COLUMN, Qt::AlignLeft); grid->addWidget(new QLabel("Name"), rowNumber, NAME_COLUMN, Qt::AlignLeft); rowNumber++; // // Cell data // for (int i = 0; i < numAttributes; i++) { // // Retain checkbox // QCheckBox* checkBox = new QCheckBox(""); checkBox->setChecked(true); grid->addWidget(checkBox, rowNumber, RETAIN_COLUMN, Qt::AlignLeft); retainCheckBoxes.push_back(checkBox); // // Name line edit // QLineEdit* nameLE = new QLineEdit; nameLE->setMinimumWidth(300); nameLE->setText(attributes[i].name); grid->addWidget(nameLE, rowNumber, NAME_COLUMN, Qt::AlignLeft); nameLineEdits.push_back(nameLE); originalNames.push_back(attributes[i].name); rowNumber++; } // // Scroll View for all selections // QScrollArea* sv = new QScrollArea(this); sv->setWidget(svWidget); dialogLayout->addWidget(sv); // // Set the minimum size for the scroll area // int minWidth = svWidget->sizeHint().width() + 10; if (minWidth > 600) minWidth = 600; sv->setMinimumWidth(minWidth); int minHeight = svWidget->sizeHint().height(); if (minHeight > 200) minHeight = 200; sv->setMinimumHeight(minHeight); // // Buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(5); dialogLayout->addLayout(buttonsLayout); QPushButton* applyButton = new QPushButton("Apply"); QObject::connect(applyButton, SIGNAL(clicked()), this, SLOT(slotApplyButton())); buttonsLayout->addWidget(applyButton); QPushButton* closeButton = new QPushButton("Close"); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); buttonsLayout->addWidget(closeButton); QtUtilities::makeButtonsSameSize(applyButton, closeButton); } /** * Destructor. */ GuiCellAttributesDialog::~GuiCellAttributesDialog() { } /** * Setup the cell attributes. */ void GuiCellAttributesDialog::setupCellAttributes() { // // Set to keep cell names sorted // std::set sortedCellAttributes; CellProjectionFile* cpf = theMainWindow->getBrainSet()->getCellProjectionFile(); const int numCells = cpf->getNumberOfCellProjections(); for (int j = 0; j < numCells; j++) { CellProjection* c = cpf->getCellProjection(j); CellAttributes ba(c->getName()); sortedCellAttributes.insert(ba); } attributes.insert(attributes.end(), sortedCellAttributes.begin(), sortedCellAttributes.end()); } /** * Get the index into the dialog arrays for the cell's original name. */ int GuiCellAttributesDialog::getIndexFromOriginalName(const QString& name) const { const int num = static_cast(originalNames.size()); for (int i = 0; i < num; i++) { if (originalNames[i] == name) { return i; } } return -1; } /** * Apply button slot. */ void GuiCellAttributesDialog::slotApplyButton() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); CellProjectionFile* cpf = theMainWindow->getBrainSet()->getCellProjectionFile(); const int numCells = cpf->getNumberOfCellProjections(); for (int j = numCells - 1; j >= 0; j--) { CellProjection* c = cpf->getCellProjection(j); // // Find index of this cell // const int index = getIndexFromOriginalName(c->getName()); if (index >= 0) { if (retainCheckBoxes[index]->isChecked()) { // // Update the cell // c->setName(nameLineEdits[index]->text()); } else { // // Delete the cell // cpf->deleteCellProjection(j); } } else { std::cerr << "Program Error: original name " << c->getName().toAscii().constData() << " not found at " << __LINE__ << " in " << __FILE__ << std::endl; } } // // Since names may have changed change the original names // const int num = static_cast(originalNames.size()); for (int i = 0; i < num; i++) { originalNames[i] = nameLineEdits[i]->text(); } GuiFilesModified fm; fm.setCellModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); } caret-5.6.4~dfsg.1.orig/caret/GuiCellAndFociReportDialog.h0000664000175000017500000001531411572067322023120 0ustar michaelmichael #ifndef __GUI_CELL_AND_FOCI_REPORT_DIALOG_H__ #define __GUI_CELL_AND_FOCI_REPORT_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "WuQDialog.h" class GuiBrainModelSelectionComboBox; class CellFile; class QCheckBox; class QToolButton; class QtTableDialog; class WuQWidgetGroup; /// dialog for cell and foci reports class GuiCellAndFociReportDialog : public WuQDialog { Q_OBJECT public: // constructor GuiCellAndFociReportDialog(QWidget* parent, const bool fociFlag); // destructor ~GuiCellAndFociReportDialog(); /// get the table dialog containing the results QtTableDialog* getResultsTableDialog() { return resultsTableDialog; } protected slots: // called when attributes all on button clicked void slotAttributesAllOnToolButton(); // called when attributes all off button clicked void slotAttributesAllOffToolButton(); // called when attributes core on button clicked void slotAttributesCoreOnToolButton(); // called when paint attributes all on button clicked void slotPaintAttributesAllOnToolButton(); // called when paint attributes all off button clicked void slotPaintAttributesAllOffToolButton(); // called when sums attributes all on button clicked void slotSumsAttributesAllOnToolButton(); // called when sums attributes all off button clicked void slotSumsAttributesAllOffToolButton(); protected: // called when ok/cancel button pressed virtual void done(int r); // creat cell selection section QWidget* createCellSelectionSection(); // create the surface section QWidget* createSurfaceSection(); // create the cell/foci section QWidget* createCellFociSection(); // create the paint section QWidget* createPaintSection(); // create the sums section QWidget* createSumsSection(); // determine if a check box is shown and checked bool checked(const QCheckBox* cb) const; /// table dialog containing results QtTableDialog* resultsTableDialog; /// include only displayed cell/foci checkbox QCheckBox* includeDisplayedCellsOnlyCheckBox; /// number check box QCheckBox* numberCheckBox; /// name check box QCheckBox* nameCheckBox; /// position check box QCheckBox* positionCheckBox; /// geography check box QCheckBox* geographyCheckBox; /// area check box QCheckBox* areaCheckBox; /// region of interest check box QCheckBox* regionOfInterestCheckBox; /// size check box QCheckBox* sizeCheckBox; /// statistic check box QCheckBox* statisticCheckBox; /// comment check box QCheckBox* commentCheckBox; /// hemisphere check box QCheckBox* structureCheckBox; /// class check box QCheckBox* classCheckBox; /// study name check box QCheckBox* studyNameCheckBox; /// study PMID check box QCheckBox* studyPMIDCheckBox; /// study format check box QCheckBox* studyDataFormatCheckBox; /// study data type check box QCheckBox* studyDataTypeCheckBox; /// study stereotaxic space QCheckBox* studyStereotaxicSpaceCheckBox; /// study table number check box QCheckBox* studyTableNumberCheckBox; /// study table sub header check box QCheckBox* studyTableSubHeaderCheckBox; /// study figure number check box QCheckBox* studyFigureNumberCheckBox; /// study figure panel check box QCheckBox* studyFigurePanelCheckBox; /// study page reference number check box QCheckBox* studyPageReferenceNumberCheckBox; /// study page reference subheader check box QCheckBox* studyPageReferenceSubHeaderCheckBox; /// study page number check box //QCheckBox* studyPageNumberCheckBox; /// paint data type check boxes std::vector paintNameCheckBoxes; /// sums check boxes std::vector sumsCheckBoxes; /// sums ID Number check box QCheckBox* sumsIDNumberCheckBox; /// sums repeat number check box QCheckBox* sumsRepeatNumberCheckBox; /// sums parent cell base ID check box QCheckBox* sumsParentCellBaseIDCheckBox; /// sums version number check box QCheckBox* sumsVersionNumberCheckBox; /// sums MSL ID check box QCheckBox* sumsMSLIDCheckBox; /// sums attribute id check box QCheckBox* sumsAttributeIDCheckBox; /// file type string (cell or foci) QString typeString; /// foci flag bool fociFlag; /// combo box for left hem surface selection GuiBrainModelSelectionComboBox* leftHemSelectionComboBox; /// combo box for right hem surface selection GuiBrainModelSelectionComboBox* rightHemSelectionComboBox; /// combo box for cerebellum surface selection GuiBrainModelSelectionComboBox* cerebellumSelectionComboBox; /// all attributes on tool button QToolButton *allAttributesOnToolButton; /// all attributes off tool button QToolButton *allAttributesOffToolButton; /// core attributes on tool button QToolButton *coreAttributesOnToolButton; /// widget group for all attributes WuQWidgetGroup* allAttributesWidgetGroup; /// widget group for all attributes WuQWidgetGroup* coreAttributesWidgetGroup; }; #endif // __GUI_CELL_AND_FOCI_REPORT_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiCellAndFociReportDialog.cxx0000664000175000017500000015154411572067322023501 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include "BrainModelSurfacePointLocator.h" #include "BrainSet.h" #include "CellProjectionFile.h" #include "FileUtilities.h" #include "FociProjectionFile.h" #include "GuiBrainModelSelectionComboBox.h" #include "GuiCellAndFociReportDialog.h" #include "GuiMainWindow.h" #include "PaintFile.h" #include "StringTable.h" #include "StudyMetaDataFile.h" #include "QtTableDialog.h" #include "QtUtilities.h" #include "WuQDataEntryDialog.h" #include "WuQWidgetGroup.h" #include "global_variables.h" /** * constructor. */ GuiCellAndFociReportDialog::GuiCellAndFociReportDialog(QWidget* parent, const bool fociFlagIn) : WuQDialog(parent) { setModal(true); resultsTableDialog = NULL; fociFlag = fociFlagIn; typeString = "Cell"; if (fociFlag) { typeString = "Foci"; } setWindowTitle(typeString + " Report"); // // Create surface section // QWidget* surfaceWidget = createSurfaceSection(); // // Selection section // QWidget* selectionSection = createCellSelectionSection(); // // Create cell/foci section // QWidget* attributeWidget = createCellFociSection(); // // Create the paint section // QWidget* paintWidget = createPaintSection(); // // Create the sums section // QWidget* sumsWidget = createSumsSection(); // // Layout for dialog // QWidget* widget = new QWidget; QVBoxLayout* widgetLayout = new QVBoxLayout(widget); widgetLayout->setSpacing(5); widgetLayout->setMargin(5); widgetLayout->addWidget(selectionSection); widgetLayout->addWidget(surfaceWidget); widgetLayout->addWidget(attributeWidget); if (paintWidget != NULL) { widgetLayout->addWidget(paintWidget); } if (sumsWidget != NULL) { widgetLayout->addWidget(sumsWidget); } // // Scroll Area for Dialog // QScrollArea* scrollArea = new QScrollArea; scrollArea->setWidgetResizable(true); scrollArea->setWidget(widget); // // Layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(5); // // OK button // QPushButton* okButton = new QPushButton("OK"); buttonsLayout->addWidget(okButton); okButton->setAutoDefault(false); QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); // // Cancel button // QPushButton* cancelButton = new QPushButton("Cancel"); buttonsLayout->addWidget(cancelButton); cancelButton->setAutoDefault(false); QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); QtUtilities::makeButtonsSameSize(okButton, cancelButton); // // Dialog Layout // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->addWidget(scrollArea); dialogLayout->addLayout(buttonsLayout); } /** * destructor. */ GuiCellAndFociReportDialog::~GuiCellAndFociReportDialog() { } /** * creat cell selection section. */ QWidget* GuiCellAndFociReportDialog::createCellSelectionSection() { // // Limit report to just displayed cells/foci // includeDisplayedCellsOnlyCheckBox = new QCheckBox("Show Only Displayed " + typeString); // // GroupBox and Layout for section // QGroupBox* selectionGroupBox = new QGroupBox(typeString + " Selection"); QVBoxLayout* selectionLayout = new QVBoxLayout(selectionGroupBox); selectionLayout->addWidget(includeDisplayedCellsOnlyCheckBox); return selectionGroupBox; } /** * create the surface section. */ QWidget* GuiCellAndFociReportDialog::createSurfaceSection() { // // left hem selection combo box // QLabel* leftLabel = new QLabel("Left"); leftHemSelectionComboBox = new GuiBrainModelSelectionComboBox(false, true, false, "", 0, "left-hem", false, true, false); // // right hem selection combo box // QLabel* rightLabel = new QLabel("Right"); rightHemSelectionComboBox = new GuiBrainModelSelectionComboBox(false, true, false, "", 0, "left-hem", false, true, false); // // right hem selection combo box // QLabel* cerebellumLabel = new QLabel("Cerebellum"); cerebellumSelectionComboBox = new GuiBrainModelSelectionComboBox(false, true, false, "", 0, "cerebellum", false, true, false); BrainModelSurface* leftBMS = NULL; BrainModelSurface* rightBMS = NULL; BrainModelSurface* cerebellumBMS = NULL; const int numModels = theMainWindow->getBrainSet()->getNumberOfBrainModels(); for (int i = 0; i < numModels; i++) { BrainModelSurface* bms = theMainWindow->getBrainSet()->getBrainModelSurface(i); if (bms != NULL) { if (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FIDUCIAL) { if (bms->getStructure().getType() == Structure::STRUCTURE_TYPE_CORTEX_LEFT) { if (leftBMS == NULL) { leftBMS = bms; } } if (bms->getStructure().getType() == Structure::STRUCTURE_TYPE_CORTEX_RIGHT) { if (rightBMS == NULL) { rightBMS = bms; } } if (bms->getStructure().getType() == Structure::STRUCTURE_TYPE_CEREBELLUM) { if (cerebellumBMS == NULL) { cerebellumBMS = bms; } } } } } if (leftBMS != NULL) { leftHemSelectionComboBox->setSelectedBrainModel(leftBMS); } if (rightBMS != NULL) { rightHemSelectionComboBox->setSelectedBrainModel(rightBMS); } if (cerebellumBMS != NULL) { cerebellumSelectionComboBox->setSelectedBrainModel(cerebellumBMS); } QGroupBox* gb = new QGroupBox("Surface Selection"); QGridLayout* gridLayout = new QGridLayout(gb); gridLayout->addWidget(leftLabel, 0, 0); gridLayout->addWidget(leftHemSelectionComboBox, 0, 1); gridLayout->addWidget(rightLabel, 1, 0); gridLayout->addWidget(rightHemSelectionComboBox, 1, 1); gridLayout->addWidget(cerebellumLabel, 2, 0); gridLayout->addWidget(cerebellumSelectionComboBox, 2, 1); return gb; } /** * create the cell/foci section. */ QWidget* GuiCellAndFociReportDialog::createCellFociSection() { // // All On button // allAttributesOnToolButton = new QToolButton; allAttributesOnToolButton->setText("All On"); QObject::connect(allAttributesOnToolButton, SIGNAL(clicked()), this, SLOT(slotAttributesAllOnToolButton())); // // All Off button // allAttributesOffToolButton = new QToolButton; allAttributesOffToolButton->setText("All Off"); QObject::connect(allAttributesOffToolButton, SIGNAL(clicked()), this, SLOT(slotAttributesAllOffToolButton())); // // Core On button // coreAttributesOnToolButton = new QToolButton; coreAttributesOnToolButton->setText("Core On"); QObject::connect(coreAttributesOnToolButton, SIGNAL(clicked()), this, SLOT(slotAttributesCoreOnToolButton())); // // Layout for tool buttons // QHBoxLayout* toolButtonLayout = new QHBoxLayout; toolButtonLayout->addWidget(allAttributesOnToolButton); toolButtonLayout->addWidget(allAttributesOffToolButton); toolButtonLayout->addWidget(coreAttributesOnToolButton); toolButtonLayout->addStretch(); // // check box // numberCheckBox = new QCheckBox("Number"); numberCheckBox->setChecked(true); // // name check box // nameCheckBox = new QCheckBox("Name"); nameCheckBox->setChecked(true); // // position check box // positionCheckBox = new QCheckBox("Position"); positionCheckBox->setChecked(true); // // class check box // classCheckBox = new QCheckBox("Class"); classCheckBox->setChecked(true); // // area check box // areaCheckBox = new QCheckBox("Area"); areaCheckBox->setChecked(true); // // geography check box // geographyCheckBox = new QCheckBox("Geography"); geographyCheckBox->setChecked(true); // // region of interest check box // regionOfInterestCheckBox = new QCheckBox("Region Of Interest"); regionOfInterestCheckBox->setChecked(true); // // size check box // sizeCheckBox = new QCheckBox("Size"); sizeCheckBox->setChecked(true); // // statistic check box // statisticCheckBox = new QCheckBox("Statistic"); statisticCheckBox->setChecked(true); // // hemisphere check box // structureCheckBox = new QCheckBox("Structure"); structureCheckBox->setChecked(true); // // study name check box // studyNameCheckBox = new QCheckBox("Study Title"); studyNameCheckBox->setChecked(true); // // study name check box // studyPMIDCheckBox = new QCheckBox("Study PMID"); studyPMIDCheckBox->setChecked(true); // // study data format check box // studyDataFormatCheckBox = new QCheckBox("Study Data Format"); studyDataFormatCheckBox->setChecked(true); // // study data type check box // studyDataTypeCheckBox = new QCheckBox("Study Data Type"); studyDataTypeCheckBox->setChecked(true); // // study stereotaxic space check box // studyStereotaxicSpaceCheckBox = new QCheckBox("Study Stereotaxic Space"); studyStereotaxicSpaceCheckBox->setChecked(true); // // study table number check box // studyTableNumberCheckBox = new QCheckBox("Study Table Number"); studyTableNumberCheckBox->setChecked(true); // // study table subheader check box // studyTableSubHeaderCheckBox = new QCheckBox("Study Table Subheader"); studyTableSubHeaderCheckBox->setChecked(true); // // study study figure number check box // studyFigureNumberCheckBox = new QCheckBox("Study Figure Number"); studyFigureNumberCheckBox->setChecked(true); // // study study figure panel check box // studyFigurePanelCheckBox = new QCheckBox("Study Figure Panel"); studyFigurePanelCheckBox->setChecked(true); // // study page reference number check box // studyPageReferenceNumberCheckBox = new QCheckBox("Study Page Number"); studyPageReferenceNumberCheckBox->setChecked(true); // // study page reference subheader check box // studyPageReferenceSubHeaderCheckBox = new QCheckBox("Study Page Subheader"); studyPageReferenceSubHeaderCheckBox->setChecked(true); // // study study page number check box // //studyPageNumberCheckBox = new QCheckBox("Study Page Number"); //studyPageNumberCheckBox->setChecked(true); // // comment check box // commentCheckBox = new QCheckBox("Comment"); commentCheckBox->setChecked(true); // // Group box for cell/foci attributes // QGroupBox* attrGroupBox = new QGroupBox(typeString + " Attributes"); QVBoxLayout* attrGroupLayout = new QVBoxLayout(attrGroupBox); attrGroupLayout->addLayout(toolButtonLayout); attrGroupLayout->addWidget(numberCheckBox); attrGroupLayout->addWidget(nameCheckBox); attrGroupLayout->addWidget(positionCheckBox); attrGroupLayout->addWidget(classCheckBox); attrGroupLayout->addWidget(areaCheckBox); attrGroupLayout->addWidget(geographyCheckBox); attrGroupLayout->addWidget(regionOfInterestCheckBox); attrGroupLayout->addWidget(sizeCheckBox); attrGroupLayout->addWidget(statisticCheckBox); attrGroupLayout->addWidget(structureCheckBox); attrGroupLayout->addWidget(studyNameCheckBox); attrGroupLayout->addWidget(studyPMIDCheckBox); attrGroupLayout->addWidget(studyDataFormatCheckBox); attrGroupLayout->addWidget(studyDataTypeCheckBox); attrGroupLayout->addWidget(studyStereotaxicSpaceCheckBox); attrGroupLayout->addWidget(studyTableNumberCheckBox); attrGroupLayout->addWidget(studyTableSubHeaderCheckBox); attrGroupLayout->addWidget(studyFigureNumberCheckBox); attrGroupLayout->addWidget(studyFigurePanelCheckBox); //attrGroupLayout->addWidget(studyPageNumberCheckBox); attrGroupLayout->addWidget(studyPageReferenceNumberCheckBox); attrGroupLayout->addWidget(studyPageReferenceSubHeaderCheckBox); attrGroupLayout->addWidget(commentCheckBox); // // Widget group for all attributes // allAttributesWidgetGroup = new WuQWidgetGroup(this); allAttributesWidgetGroup->addWidget(numberCheckBox); allAttributesWidgetGroup->addWidget(nameCheckBox); allAttributesWidgetGroup->addWidget(positionCheckBox); allAttributesWidgetGroup->addWidget(classCheckBox); allAttributesWidgetGroup->addWidget(areaCheckBox); allAttributesWidgetGroup->addWidget(geographyCheckBox); allAttributesWidgetGroup->addWidget(regionOfInterestCheckBox); allAttributesWidgetGroup->addWidget(sizeCheckBox); allAttributesWidgetGroup->addWidget(statisticCheckBox); allAttributesWidgetGroup->addWidget(structureCheckBox); allAttributesWidgetGroup->addWidget(studyNameCheckBox); allAttributesWidgetGroup->addWidget(studyPMIDCheckBox); allAttributesWidgetGroup->addWidget(studyDataFormatCheckBox); allAttributesWidgetGroup->addWidget(studyDataTypeCheckBox); allAttributesWidgetGroup->addWidget(studyStereotaxicSpaceCheckBox); allAttributesWidgetGroup->addWidget(studyTableNumberCheckBox); allAttributesWidgetGroup->addWidget(studyTableSubHeaderCheckBox); allAttributesWidgetGroup->addWidget(studyFigureNumberCheckBox); allAttributesWidgetGroup->addWidget(studyFigurePanelCheckBox); //allAttributesWidgetGroup->addWidget(studyPageNumberCheckBox); allAttributesWidgetGroup->addWidget(studyPageReferenceNumberCheckBox); allAttributesWidgetGroup->addWidget(studyPageReferenceSubHeaderCheckBox); allAttributesWidgetGroup->addWidget(commentCheckBox); // // Widget group for core items // coreAttributesWidgetGroup = new WuQWidgetGroup(this); coreAttributesWidgetGroup->addWidget(numberCheckBox); coreAttributesWidgetGroup->addWidget(nameCheckBox); coreAttributesWidgetGroup->addWidget(positionCheckBox); coreAttributesWidgetGroup->addWidget(classCheckBox); coreAttributesWidgetGroup->addWidget(areaCheckBox); coreAttributesWidgetGroup->addWidget(geographyCheckBox); coreAttributesWidgetGroup->addWidget(regionOfInterestCheckBox); coreAttributesWidgetGroup->addWidget(structureCheckBox); coreAttributesWidgetGroup->addWidget(studyPMIDCheckBox); // // If doing a cell report, hide items specific to foci // if (fociFlag == false) { regionOfInterestCheckBox->hide(); geographyCheckBox->hide(); areaCheckBox->hide(); sizeCheckBox->hide(); statisticCheckBox->hide(); commentCheckBox->hide(); studyNameCheckBox->hide(); studyPMIDCheckBox->hide(); studyDataFormatCheckBox->hide(); studyDataTypeCheckBox->hide(); studyStereotaxicSpaceCheckBox->hide(); studyTableNumberCheckBox->hide(); studyTableSubHeaderCheckBox->hide(); studyFigureNumberCheckBox->hide(); studyFigurePanelCheckBox->hide(); //studyPageNumberCheckBox->hide(); studyPageReferenceNumberCheckBox->hide(); studyPageReferenceSubHeaderCheckBox->hide(); } return attrGroupBox; } /** * called when attributes all on button clicked. */\ void GuiCellAndFociReportDialog::slotAttributesAllOnToolButton() { allAttributesWidgetGroup->setAllCheckBoxesChecked(true); } /** * called when attributes all off button clicked. */ void GuiCellAndFociReportDialog::slotAttributesAllOffToolButton() { allAttributesWidgetGroup->setAllCheckBoxesChecked(false); } /** * called when attributes core on button clicked. */ void GuiCellAndFociReportDialog::slotAttributesCoreOnToolButton() { allAttributesWidgetGroup->setAllCheckBoxesChecked(false); coreAttributesWidgetGroup->setAllCheckBoxesChecked(true); } /** * create the sums section. */ QWidget* GuiCellAndFociReportDialog::createSumsSection() { // // All On button // QToolButton* allSumsAttributesOnToolButton = new QToolButton; allSumsAttributesOnToolButton->setText("All On"); QObject::connect(allSumsAttributesOnToolButton, SIGNAL(clicked()), this, SLOT(slotSumsAttributesAllOnToolButton())); // // All Off button // QToolButton* allSumsAttributesOffToolButton = new QToolButton; allSumsAttributesOffToolButton->setText("All Off"); QObject::connect(allSumsAttributesOffToolButton, SIGNAL(clicked()), this, SLOT(slotSumsAttributesAllOffToolButton())); // // Layout for tool buttons // QHBoxLayout* toolButtonLayout = new QHBoxLayout; toolButtonLayout->addWidget(allSumsAttributesOnToolButton); toolButtonLayout->addWidget(allSumsAttributesOffToolButton); toolButtonLayout->addStretch(); // // Group box for sums attributes // QGroupBox* sumsGroupBox = new QGroupBox("Sums Attributes"); QVBoxLayout* sumsGroupLayout = new QVBoxLayout(sumsGroupBox); sumsGroupLayout->addLayout(toolButtonLayout); sumsIDNumberCheckBox = new QCheckBox("SuMS ID Number"); sumsGroupLayout->addWidget(sumsIDNumberCheckBox); sumsIDNumberCheckBox->setChecked(false); sumsCheckBoxes.push_back(sumsIDNumberCheckBox); sumsRepeatNumberCheckBox = new QCheckBox("SuMS Repeat Number"); sumsGroupLayout->addWidget(sumsRepeatNumberCheckBox); sumsRepeatNumberCheckBox->setChecked(false); sumsCheckBoxes.push_back(sumsRepeatNumberCheckBox); sumsParentCellBaseIDCheckBox = new QCheckBox("SuMS Parent Cell Base ID"); sumsGroupLayout->addWidget(sumsParentCellBaseIDCheckBox); sumsParentCellBaseIDCheckBox->setChecked(false); sumsCheckBoxes.push_back(sumsParentCellBaseIDCheckBox); sumsVersionNumberCheckBox = new QCheckBox("SuMS Version Number"); sumsGroupLayout->addWidget(sumsVersionNumberCheckBox); sumsVersionNumberCheckBox->setChecked(false); sumsCheckBoxes.push_back(sumsVersionNumberCheckBox); sumsMSLIDCheckBox = new QCheckBox("SuMS MSL ID"); sumsGroupLayout->addWidget(sumsMSLIDCheckBox); sumsMSLIDCheckBox->setChecked(false); sumsCheckBoxes.push_back(sumsMSLIDCheckBox); sumsAttributeIDCheckBox = new QCheckBox("Attribute ID"); sumsGroupLayout->addWidget(sumsAttributeIDCheckBox); sumsAttributeIDCheckBox->setChecked(false); sumsCheckBoxes.push_back(sumsAttributeIDCheckBox); return sumsGroupBox; } /** * called when sums attributes all on button clicked. */ void GuiCellAndFociReportDialog::slotSumsAttributesAllOnToolButton() { const int num = static_cast(sumsCheckBoxes.size()); for (int i = 0; i < num; i++) { sumsCheckBoxes[i]->setChecked(true); } } /** * called when sums attributes all off button clicked. */ void GuiCellAndFociReportDialog::slotSumsAttributesAllOffToolButton() { const int num = static_cast(sumsCheckBoxes.size()); for (int i = 0; i < num; i++) { sumsCheckBoxes[i]->setChecked(false); } } /** * create the paint section. */ QWidget* GuiCellAndFociReportDialog::createPaintSection() { // // All On button // QToolButton* allPaintAttributesOnToolButton = new QToolButton; allPaintAttributesOnToolButton->setText("All On"); QObject::connect(allPaintAttributesOnToolButton, SIGNAL(clicked()), this, SLOT(slotPaintAttributesAllOnToolButton())); // // All Off button // QToolButton* allPaintAttributesOffToolButton = new QToolButton; allPaintAttributesOffToolButton->setText("All Off"); QObject::connect(allPaintAttributesOffToolButton, SIGNAL(clicked()), this, SLOT(slotPaintAttributesAllOffToolButton())); // // Layout for tool buttons // QHBoxLayout* toolButtonLayout = new QHBoxLayout; toolButtonLayout->addWidget(allPaintAttributesOnToolButton); toolButtonLayout->addWidget(allPaintAttributesOffToolButton); toolButtonLayout->addStretch(); PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); const int numCols = pf->getNumberOfColumns(); if (numCols <= 0) { return NULL; } // // Group box for paint attributes // QGroupBox* paintGroupBox = new QGroupBox("Paint Attributes"); QVBoxLayout* paintGroupLayout = new QVBoxLayout(paintGroupBox); paintGroupLayout->addLayout(toolButtonLayout); // // Add check boxes for paint columns // for (int i = 0; i < numCols; i++) { QCheckBox* pcb = new QCheckBox(pf->getColumnName(i)); paintGroupLayout->addWidget(pcb); pcb->setChecked(false); paintNameCheckBoxes.push_back(pcb); } return paintGroupBox; } /** * called when paint attributes all on button clicked. */ void GuiCellAndFociReportDialog::slotPaintAttributesAllOnToolButton() { const int num = static_cast(paintNameCheckBoxes.size()); for (int i = 0; i < num; i++) { paintNameCheckBoxes[i]->setChecked(true); } } /** * called when paint attributes all off button clicked. */ void GuiCellAndFociReportDialog::slotPaintAttributesAllOffToolButton() { const int num = static_cast(paintNameCheckBoxes.size()); for (int i = 0; i < num; i++) { paintNameCheckBoxes[i]->setChecked(false); } } /** * called when ok/cancel button pressed. */ void GuiCellAndFociReportDialog::done(int r) { if (r == QDialog::Accepted) { const BrainModelSurface* leftBMS = leftHemSelectionComboBox->getSelectedBrainModelSurface(); if (leftBMS == NULL) { QMessageBox::critical(this, "ERROR", "No left surface is selected."); } const BrainModelSurface* rightBMS = rightHemSelectionComboBox->getSelectedBrainModelSurface(); if (rightBMS == NULL) { QMessageBox::critical(this, "ERROR", "No right surface is selected."); } const BrainModelSurface* cerebellumBMS = cerebellumSelectionComboBox->getSelectedBrainModelSurface(); StudyMetaDataFile* studyMetaDataFile = theMainWindow->getBrainSet()->getStudyMetaDataFile(); // // Get the fiducial foci file // CellProjectionFile* cf = NULL; if (fociFlag) { cf = theMainWindow->getBrainSet()->getFociProjectionFile(); } else { cf = theMainWindow->getBrainSet()->getCellProjectionFile(); } if (cf != NULL) { const int numCells = cf->getNumberOfCellProjections(); if (numCells > 0) { int numTableColumns = 0; std::vector columnTitle; int numberColumn = -1; if (checked(numberCheckBox)) { columnTitle.push_back("Number"); numberColumn = numTableColumns++; } int nameColumn = -1; if (checked(nameCheckBox)) { columnTitle.push_back("Name"); nameColumn = numTableColumns++; } int positionColumn = -1; if (checked(positionCheckBox)) { columnTitle.push_back("X"); columnTitle.push_back("Y"); columnTitle.push_back("Z"); positionColumn = numTableColumns; numTableColumns += 3; } int classColumn = -1; if (checked(classCheckBox)) { columnTitle.push_back("Class"); classColumn = numTableColumns++; } int areaColumn = -1; if (checked(areaCheckBox)) { columnTitle.push_back("Area"); areaColumn = numTableColumns++; } int geographyColumn = -1; if (checked(geographyCheckBox)) { columnTitle.push_back("Geography"); geographyColumn = numTableColumns++; } int hemisphereColumn = -1; if (checked(structureCheckBox)) { columnTitle.push_back("Structure"); hemisphereColumn = numTableColumns++; } int regionOfInterestColumn = -1; if (checked(regionOfInterestCheckBox)) { columnTitle.push_back("ROI"); regionOfInterestColumn = numTableColumns++; } int sizeColumn = -1; if (checked(sizeCheckBox)) { columnTitle.push_back("Size"); sizeColumn = numTableColumns++; } int statisticColumn = -1; if (checked(statisticCheckBox)) { columnTitle.push_back("Statistic"); statisticColumn = numTableColumns++; } int commentColumn = -1; if (checked(commentCheckBox)) { columnTitle.push_back("Comment"); commentColumn = numTableColumns++; } int studyNameColumn = -1; if (checked(studyNameCheckBox)) { columnTitle.push_back("Study Title"); studyNameColumn = numTableColumns++; } int studyPMIDColumn = -1; if (checked(studyPMIDCheckBox)) { columnTitle.push_back("Study PMID"); studyPMIDColumn = numTableColumns++; } int studyDataFormatColumn = -1; if (checked(studyDataFormatCheckBox)) { columnTitle.push_back("Study Data Format"); studyDataFormatColumn = numTableColumns++; } int studyDataTypeColumn = -1; if (checked(studyDataTypeCheckBox)) { columnTitle.push_back("Study Data Type"); studyDataTypeColumn = numTableColumns++; } int stereotaxicSpaceColumn = -1; if (checked(studyStereotaxicSpaceCheckBox)) { columnTitle.push_back("Study Stereotaxic Space"); stereotaxicSpaceColumn = numTableColumns++; } int studyTableNumberColumn = -1; if (checked(studyTableNumberCheckBox)) { columnTitle.push_back("Study Table Number"); studyTableNumberColumn = numTableColumns++; } int studyTableSubHeaderColumn = -1; if (checked(studyTableSubHeaderCheckBox)) { columnTitle.push_back("Study Table Subheader"); studyTableSubHeaderColumn = numTableColumns++; } int studyFigureNumberColumn = -1; if (checked(studyFigureNumberCheckBox)) { columnTitle.push_back("Study Figure Number"); studyFigureNumberColumn = numTableColumns++; } int studyFigurePanelColumn = -1; if (checked(studyFigurePanelCheckBox)) { columnTitle.push_back("Study Figure Panel"); studyFigurePanelColumn = numTableColumns++; } //int studyPageNumberColumn = -1; //if (checked(studyPageNumberCheckBox)) { // columnTitle.push_back("Study Page Number"); // studyPageNumberColumn = numTableColumns++; //} int studyPageReferenceNumberColumn = -1; if (checked(studyPageReferenceNumberCheckBox)) { columnTitle.push_back("Study Page Number"); studyPageReferenceNumberColumn = numTableColumns++; } int studyPageReferenceSubheaderColumn = -1; if (checked(studyPageReferenceSubHeaderCheckBox)) { columnTitle.push_back("Study Page Subheader"); studyPageReferenceSubheaderColumn = numTableColumns++; } int sumsIDNumberColumn = -1; if (checked(sumsIDNumberCheckBox)) { columnTitle.push_back("SuMS ID Number"); sumsIDNumberColumn = numTableColumns++; } int sumsRepeatNumberColumn = -1; if (checked(sumsRepeatNumberCheckBox)) { columnTitle.push_back("SuMS Repeat Number"); sumsRepeatNumberColumn = numTableColumns++; } int sumsParentCellBaseIDColumn = -1; if (checked(sumsParentCellBaseIDCheckBox)) { columnTitle.push_back("Sums Parent Cell Base ID"); sumsParentCellBaseIDColumn = numTableColumns++; } int sumsVersionNumberColumn = -1; if (checked(sumsVersionNumberCheckBox)) { columnTitle.push_back("SuMS Version Number"); sumsVersionNumberColumn = numTableColumns++; } int sumsMSLIDColumn = -1; if (checked(sumsMSLIDCheckBox)) { columnTitle.push_back("SuMS MSL ID"); sumsMSLIDColumn = numTableColumns++; } int sumsAttributeIDColumn = -1; if (checked(sumsAttributeIDCheckBox)) { columnTitle.push_back("Attribute ID"); sumsAttributeIDColumn = numTableColumns++; } // // See if paints are selected // PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); const int numPaintCols = pf->getNumberOfColumns(); bool havePaints = false; std::vector paintTableColumn; for (int j = 0; j < numPaintCols; j++) { int column = -1; if (paintNameCheckBoxes[j]->isChecked()) { columnTitle.push_back(pf->getColumnName(j)); column = numTableColumns++; havePaints = true; } paintTableColumn.push_back(column); } // // Determine node nearest to each cell // std::vector cellsNearestLeftNode(numCells, -1); std::vector cellsNearestRightNode(numCells, -1); std::vector cellsNearestCerebellumNode(numCells, -1); if (havePaints) { BrainModelSurfacePointLocator leftPointLocator(leftBMS, true); BrainModelSurfacePointLocator rightPointLocator(rightBMS, true); BrainModelSurfacePointLocator* cerebellumPointLocator = NULL; if (cerebellumBMS != NULL) { cerebellumPointLocator = new BrainModelSurfacePointLocator(cerebellumBMS, true); } for (int i = 0; i < numCells; i++) { const CellProjection* cp = cf->getCellProjection(i); float xyz[3]; cp->getXYZ(xyz); bool leftFlag = false; bool rightFlag = false; bool cerebellumFlag = false; switch (cp->getCellStructure()) { case Structure::STRUCTURE_TYPE_CORTEX_LEFT: leftFlag = true; break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT: rightFlag = true; break; case Structure::STRUCTURE_TYPE_CORTEX_BOTH: break; case Structure::STRUCTURE_TYPE_CEREBELLUM: cerebellumFlag = true; break; case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_LEFT: cerebellumFlag = true; break; case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_RIGHT: cerebellumFlag = true; break; case Structure::STRUCTURE_TYPE_CORTEX_LEFT_OR_CEREBELLUM: leftFlag = true; break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT_OR_CEREBELLUM: rightFlag = true; break; case Structure::STRUCTURE_TYPE_CEREBRUM_CEREBELLUM: case Structure::STRUCTURE_TYPE_SUBCORTICAL: case Structure::STRUCTURE_TYPE_ALL: case Structure::STRUCTURE_TYPE_INVALID: if (xyz[0] >= 0) { rightFlag = true; } else { leftFlag = true; } break; } if (rightFlag) { if (cp->getProjectedPosition(rightBMS->getCoordinateFile(), rightBMS->getTopologyFile(), rightBMS->getIsFiducialSurface(), rightBMS->getIsFlatSurface(), false, xyz)) { cellsNearestRightNode[i] = rightPointLocator.getNearestPoint(xyz); } } else if (rightFlag) { if (cp->getProjectedPosition(leftBMS->getCoordinateFile(), leftBMS->getTopologyFile(), leftBMS->getIsFiducialSurface(), leftBMS->getIsFlatSurface(), false, xyz)) { cellsNearestLeftNode[i] = leftPointLocator.getNearestPoint(xyz); } } else if (cerebellumFlag) { if (cerebellumBMS != NULL) { if (cp->getProjectedPosition(cerebellumBMS->getCoordinateFile(), cerebellumBMS->getTopologyFile(), cerebellumBMS->getIsFiducialSurface(), cerebellumBMS->getIsFlatSurface(), false, xyz)) { cellsNearestCerebellumNode[i] = cerebellumPointLocator->getNearestPoint(xyz); } } } } // for if (cerebellumPointLocator != NULL) { delete cerebellumPointLocator; } } // // Count number of cells for table // std::vector cellsForReport; for (int i = 0; i < numCells; i++) { const CellProjection* cd = cf->getCellProjection(i); bool useFocusFlag = true; if (includeDisplayedCellsOnlyCheckBox->isChecked()) { useFocusFlag = cd->getDisplayFlag(); } if (useFocusFlag) { cellsForReport.push_back(i); } } const int numCellsForTable = static_cast(cellsForReport.size()); if (numCellsForTable > 0) { // // Create the QString table // StringTable cellTable(numCellsForTable, numTableColumns); // // Set the column titles // for (int j = 0; j < static_cast(columnTitle.size()); j++) { cellTable.setColumnTitle(j, columnTitle[j]); } // // Handle columns that contain integer data so sorted correctly // if (numberColumn >= 0) { cellTable.setColumnMaxInteger(numberColumn, numCellsForTable); } // // Counts for missing items // int countFociLackMatchingStudyName = 0; int countFociLackMatchingPubMedID = 0; std::set fociLackMatchingStudyName; // // Process the cells // for (int ii = 0; ii < numCellsForTable; ii++) { const int tableRowNumber = ii; const int cellNumber = cellsForReport[ii]; const CellProjection* cd = cf->getCellProjection(cellNumber); // // Load cell data into the table // if (numberColumn >= 0) { cellTable.setElement(tableRowNumber, numberColumn, cellNumber); } if (nameColumn >= 0) { cellTable.setElement(tableRowNumber, nameColumn, cd->getName()); } if (positionColumn >= 0) { const float* xyz = cd->getXYZ(); cellTable.setElement(tableRowNumber, positionColumn, xyz[0]); cellTable.setElement(tableRowNumber, positionColumn + 1, xyz[1]); cellTable.setElement(tableRowNumber, positionColumn + 2, xyz[2]); } if (classColumn >= 0) { cellTable.setElement(tableRowNumber, classColumn, cd->getClassName()); } if (areaColumn >= 0) { cellTable.setElement(tableRowNumber, areaColumn, cd->getArea()); } if (geographyColumn >= 0) { cellTable.setElement(tableRowNumber, geographyColumn, cd->getGeography()); } if (regionOfInterestColumn >= 0) { cellTable.setElement(tableRowNumber, regionOfInterestColumn, cd->getRegionOfInterest()); } if (sizeColumn >= 0) { cellTable.setElement(tableRowNumber, sizeColumn, cd->getSize()); } if (statisticColumn >= 0) { cellTable.setElement(tableRowNumber, statisticColumn, cd->getStatistic()); } if (hemisphereColumn >= 0) { cellTable.setElement(tableRowNumber, hemisphereColumn, Structure::convertTypeToString(cd->getCellStructure())); } QString pubMedID; StudyMetaData* linkedStudyMetaData = NULL; const StudyMetaDataLinkSet smdls = cd->getStudyMetaDataLinkSet(); StudyMetaDataLink metaDataLink; if (smdls.getNumberOfStudyMetaDataLinks() > 0) { metaDataLink = smdls.getStudyMetaDataLink(0); pubMedID = metaDataLink.getPubMedID(); const int indx = studyMetaDataFile->getStudyIndexFromLink(metaDataLink); if (indx >= 0) { linkedStudyMetaData = studyMetaDataFile->getStudyMetaData(indx); } } if (studyNameColumn >= 0) { QString studyTitle; if (linkedStudyMetaData != NULL) { studyTitle = linkedStudyMetaData->getTitle(); } cellTable.setElement(tableRowNumber, studyNameColumn, studyTitle); } if (studyPMIDColumn >= 0) { //QString studyPMID; //if (linkedStudyMetaData != NULL) { // studyPMID = linkedStudyMetaData->getPubMedID(); //} //cellTable.setElement(tableRowNumber, studyPMIDColumn, studyPMID); cellTable.setElement(tableRowNumber, studyPMIDColumn, pubMedID); } if (cd->getName().isEmpty() == false) { int nameIndx = studyMetaDataFile->getStudyIndexFromName(cd->getName()); if (nameIndx >= 0) { int pmidIndex = -1; if (pubMedID.isEmpty() == false) { pmidIndex = studyMetaDataFile->getStudyIndexFromPubMedID(pubMedID); } if (nameIndx != pmidIndex) { countFociLackMatchingPubMedID++; fociLackMatchingStudyName.insert("Focus " + QString::number(cellNumber) + " " + cd->getName() + " Study Index=" + QString::number(pmidIndex+1) + ", Study With Same Name Uses Study Index=" + QString::number(nameIndx+1)); } } else { countFociLackMatchingStudyName++; fociLackMatchingStudyName.insert("No Study Name Matches " + QString::number(cellNumber) + " " + cd->getName()); } } if (studyDataFormatColumn >= 0) { QString dataFormat; if (linkedStudyMetaData != NULL) { dataFormat = linkedStudyMetaData->getStudyDataFormat(); } cellTable.setElement(tableRowNumber, studyDataFormatColumn, dataFormat); } if (studyDataTypeColumn >= 0) { QString dataType; if (linkedStudyMetaData != NULL) { dataType = linkedStudyMetaData->getStudyDataType(); } cellTable.setElement(tableRowNumber, studyDataTypeColumn, dataType); } if (stereotaxicSpaceColumn >= 0) { QString spaceName; if (linkedStudyMetaData != NULL) { spaceName = linkedStudyMetaData->getStereotaxicSpace(); } cellTable.setElement(tableRowNumber, stereotaxicSpaceColumn, spaceName); } if (studyTableNumberColumn >= 0) { QString txt = metaDataLink.getTableNumber(); cellTable.setElement(tableRowNumber, studyTableNumberColumn, txt); } if (studyTableSubHeaderColumn >= 0) { QString txt = metaDataLink.getTableSubHeaderNumber(); cellTable.setElement(tableRowNumber, studyTableSubHeaderColumn, txt); } if (studyFigureNumberColumn >= 0) { QString txt = metaDataLink.getFigureNumber(); cellTable.setElement(tableRowNumber, studyFigureNumberColumn, txt); } if (studyFigurePanelColumn >= 0) { QString txt = metaDataLink.getFigurePanelNumberOrLetter(); cellTable.setElement(tableRowNumber, studyFigurePanelColumn, txt); } //if (studyPageNumberColumn >= 0) { // QString txt = metaDataLink.getPageNumber(); // cellTable.setElement(tableRowNumber, studyPageNumberColumn, txt); //} if (studyPageReferenceNumberColumn >= 0) { QString txt = metaDataLink.getPageReferencePageNumber(); cellTable.setElement(tableRowNumber, studyPageReferenceNumberColumn, txt); } if (studyPageReferenceSubheaderColumn >= 0) { QString txt = metaDataLink.getPageReferenceSubHeaderNumber(); cellTable.setElement(tableRowNumber, studyPageReferenceSubheaderColumn, txt); } if (commentColumn >= 0) { cellTable.setElement(tableRowNumber, commentColumn, cd->getComment()); } if (sumsIDNumberColumn >= 0) { cellTable.setElement(tableRowNumber, sumsIDNumberColumn, cd->getSumsIDNumber()); } if (sumsRepeatNumberColumn >= 0) { cellTable.setElement(tableRowNumber, sumsRepeatNumberColumn, cd->getSumsRepeatNumber()); } if (sumsParentCellBaseIDColumn >= 0) { cellTable.setElement(tableRowNumber, sumsParentCellBaseIDColumn, cd->getSumsParentCellBaseID()); } if (sumsVersionNumberColumn >= 0) { cellTable.setElement(tableRowNumber, sumsVersionNumberColumn, cd->getSumsVersionNumber()); } if (sumsMSLIDColumn >= 0) { cellTable.setElement(tableRowNumber, sumsMSLIDColumn, cd->getSumsMSLID()); } if (sumsAttributeIDColumn >= 0) { cellTable.setElement(tableRowNumber, sumsAttributeIDColumn, cd->getAttributeID()); } // // Load paint into the table // if (havePaints) { int node = -1; if (cellsNearestLeftNode[cellNumber] >= 0) { node = cellsNearestLeftNode[cellNumber]; } else if (cellsNearestRightNode[cellNumber] >= 0) { node = cellsNearestRightNode[cellNumber]; } else if (cellsNearestCerebellumNode[cellNumber] >= 0) { node = cellsNearestCerebellumNode[cellNumber]; } if (node >= 0) { for (int j = 0; j < numPaintCols; j++) { if (paintNameCheckBoxes[j]->isChecked()) { const int paintIndex = pf->getPaint(node, j); const QString paintName = pf->getPaintNameFromIndex(paintIndex); cellTable.setElement(tableRowNumber, paintTableColumn[j], paintName); } } } } } // for (ii = 0; ii < numCells... // // Create and display the table dialog // const QString titleString(typeString + " Report "); resultsTableDialog = new QtTableDialog(theMainWindow, titleString, cellTable, true); resultsTableDialog->show(); resultsTableDialog->activateWindow(); QApplication::processEvents(); // // Missing name/pub med ID alerts // QString msg; if (countFociLackMatchingStudyName > 0) { if (msg.isEmpty() == false) { msg += "\n\n"; } msg += (QString::number(countFociLackMatchingStudyName) + " foci lack a matching study name."); } if (countFociLackMatchingPubMedID > 0) { if (msg.isEmpty() == false) { msg += "\n\n"; } msg += (QString::number(countFociLackMatchingPubMedID) + " foci have mismatched PMID in foci file and study file."); } if (msg.isEmpty() == false) { msg += ("\n\n" "Use 'Layers->Foci->Update Focus PubMed ID if Focus Name Matches Study Name'\n" "to correct mismatches."); WuQDataEntryDialog ded(resultsTableDialog); ded.setWindowTitle("Mismatched Foci"); ded.setTextAtTop(msg, true); QStringList namesStringList; for (std::set::iterator iter = fociLackMatchingStudyName.begin(); iter != fociLackMatchingStudyName.end(); iter++) { namesStringList += *iter; } ded.addListWidget("", namesStringList); ded.exec(); } } // if (numCellsForTable > 0) else { QString msg("There are no "); msg.append(typeString); msg.append(" meeting display criteria."); QMessageBox::critical(this, "ERROR", msg); } } // if (numCells > 0) else { QString msg("There are no "); msg.append(typeString); msg.append("."); QMessageBox::critical(this, "ERROR", msg); } } // if (cf != NULL) else { QString msg("There are no "); msg.append(typeString); msg.append("."); QMessageBox::critical(this, "ERROR", msg); } } // if (r == QDialog::done) QDialog::done(r); } /** * determine if a check box is shown and checked. */ bool GuiCellAndFociReportDialog::checked(const QCheckBox* cb) const { return (cb->isVisible() && cb->isChecked()); } caret-5.6.4~dfsg.1.orig/caret/GuiCellAndFociAttributeAssignmentDialog.h0000664000175000017500000000762511572067322025647 0ustar michaelmichael #ifndef __GUI_CELL_AND_FOCI_ATTRIBUTE_ASSIGNMENT_DIALOG_H__ #define __GUI_CELL_AND_FOCI_ATTRIBUTE_ASSIGNMENT_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "WuQDialog.h" class GuiBrainModelSelectionComboBox; class CellFile; class QAbstractButton; class QCheckBox; class QComboBox; class QDialogButtonBox; class QDoubleSpinBox; class QSpinBox; class QVBoxLayout; /// dialog for cell and foci attribute assignment class GuiCellAndFociAttributeAssignmentDialog : public WuQDialog { Q_OBJECT public: // constructor GuiCellAndFociAttributeAssignmentDialog(QWidget* parent, const bool fociFlag); // destructor ~GuiCellAndFociAttributeAssignmentDialog(); // update the dialog void updateDialog(); protected slots: // called when a button pressed void slotPushButton(QAbstractButton* buttonPressed); protected: // create the surface section QWidget* createSurfaceSection(); // create the assignement options section QWidget* createAssignmentSection(); // create the paint section QWidget* createPaintSection(); // update the paint column section void updatePaintColumnSection(); // determine if a check box is shown and checked bool checked(const QCheckBox* cb) const; /// perform assignment void performAssignment(); /// perform assignment using algorithm void performAssignmentUsingAlgorithm(); /// assignment method combo box QComboBox* assignmentMethodComboBox; /// assignment attribute combo box QComboBox* assignmentAttributeComboBox; /// paint name check boxes std::vector paintNameCheckBoxes; /// ignore "?" entries QCheckBox* ignorePaintQuestionEntriesCheckBox; /// layout for paint name checkboxes QVBoxLayout* paintNameCheckBoxesLayout; /// file type string (cell or foci) QString typeString; /// foci flag bool fociFlag; /// combo box for left hem surface selection GuiBrainModelSelectionComboBox* leftHemSelectionComboBox; /// left hem check box QCheckBox* leftHemSelectionCheckBox; /// combo box for right hem surface selection GuiBrainModelSelectionComboBox* rightHemSelectionComboBox; /// right hem check box QCheckBox* rightHemSelectionCheckBox; /// combo box for cerebellum surface selection GuiBrainModelSelectionComboBox* cerebellumSelectionComboBox; /// cerebellum check box QCheckBox* cerebellumSelectionCheckBox; /// maximum distance of focus from surface double spin box QDoubleSpinBox* maximumDistanceDoubleSpinBox; /// the dialog button box QDialogButtonBox* dialogButtonBox; /// attribute ID Spin Box QSpinBox* attributeIDSpinBox; }; #endif // __GUI_CELL_AND_FOCI_ATTRIBUTE_ASSIGNMENT_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiCellAndFociAttributeAssignmentDialog.cxx0000664000175000017500000006325011572067322026216 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include "BrainModelSurfaceCellAttributeAssignment.h" #include "BrainModelSurfacePointLocator.h" #include "BrainSet.h" #include "CellProjectionFile.h" #include "FileUtilities.h" #include "FociProjectionFile.h" #include "GuiBrainModelSelectionComboBox.h" #include "GuiCellAndFociAttributeAssignmentDialog.h" #include "GuiMainWindow.h" #include "MathUtilities.h" #include "PaintFile.h" #include "QtUtilities.h" #include "global_variables.h" /** * constructor. */ GuiCellAndFociAttributeAssignmentDialog::GuiCellAndFociAttributeAssignmentDialog(QWidget* parent, const bool fociFlagIn) : WuQDialog(parent) { fociFlag = fociFlagIn; typeString = "Cell"; if (fociFlag) { typeString = "Foci"; } setWindowTitle(typeString + " Attribute Assignment"); // // Layout for dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); // // Create surface section // dialogLayout->addWidget(createSurfaceSection()); // // Create assigment options section // dialogLayout->addWidget(createAssignmentSection()); // // Create the paint section // QWidget* paintWidget = createPaintSection(); if (paintWidget != NULL) { dialogLayout->addWidget(paintWidget); } dialogButtonBox = new QDialogButtonBox(QDialogButtonBox::Apply | QDialogButtonBox::Close); QObject::connect(dialogButtonBox, SIGNAL(clicked(QAbstractButton*)), this, SLOT(slotPushButton(QAbstractButton*))); dialogLayout->addWidget(dialogButtonBox); updateDialog(); } /** * destructor. */ GuiCellAndFociAttributeAssignmentDialog::~GuiCellAndFociAttributeAssignmentDialog() { } /** * update the dialog. */ void GuiCellAndFociAttributeAssignmentDialog::updateDialog() { leftHemSelectionComboBox->updateComboBox(); rightHemSelectionComboBox->updateComboBox(); cerebellumSelectionComboBox->updateComboBox(); updatePaintColumnSection(); } /** * create the surface section. */ QWidget* GuiCellAndFociAttributeAssignmentDialog::createSurfaceSection() { // // left hem selection combo box // leftHemSelectionCheckBox = new QCheckBox("Left"); leftHemSelectionCheckBox->setChecked(true); leftHemSelectionComboBox = new GuiBrainModelSelectionComboBox(false, true, false, "", 0, "left-hem", false, true, false); QObject::connect(leftHemSelectionCheckBox, SIGNAL(toggled(bool)), leftHemSelectionComboBox, SLOT(setEnabled(bool))); // // right hem selection combo box // rightHemSelectionCheckBox = new QCheckBox("Right"); rightHemSelectionCheckBox->setChecked(true); rightHemSelectionComboBox = new GuiBrainModelSelectionComboBox(false, true, false, "", 0, "right-hem", false, true, false); QObject::connect(rightHemSelectionCheckBox, SIGNAL(toggled(bool)), rightHemSelectionComboBox, SLOT(setEnabled(bool))); // // right hem selection combo box // cerebellumSelectionCheckBox = new QCheckBox("Cerebellum"); cerebellumSelectionCheckBox->setChecked(true); cerebellumSelectionComboBox = new GuiBrainModelSelectionComboBox(false, true, false, "", 0, "right-hem", false, true, false); QObject::connect(cerebellumSelectionCheckBox, SIGNAL(toggled(bool)), cerebellumSelectionComboBox, SLOT(setEnabled(bool))); BrainModelSurface* leftBMS = NULL; BrainModelSurface* rightBMS = NULL; BrainModelSurface* cerebellumBMS = NULL; const int numModels = theMainWindow->getBrainSet()->getNumberOfBrainModels(); for (int i = 0; i < numModels; i++) { BrainModelSurface* bms = theMainWindow->getBrainSet()->getBrainModelSurface(i); if (bms != NULL) { if (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FIDUCIAL) { if (bms->getStructure().getType() == Structure::STRUCTURE_TYPE_CORTEX_LEFT) { leftBMS = bms; } if (bms->getStructure().getType() == Structure::STRUCTURE_TYPE_CORTEX_RIGHT) { rightBMS = bms; } if (bms->getStructure().getType() == Structure::STRUCTURE_TYPE_CEREBELLUM) { cerebellumBMS = bms; } } } } if (leftBMS != NULL) { leftHemSelectionComboBox->setSelectedBrainModel(leftBMS); } if (rightBMS != NULL) { rightHemSelectionComboBox->setSelectedBrainModel(rightBMS); } if (cerebellumBMS != NULL) { cerebellumSelectionComboBox->setSelectedBrainModel(cerebellumBMS); } QLabel* maximumDistanceLabel = new QLabel("Maximum Distance of Focus from Surface"); maximumDistanceDoubleSpinBox = new QDoubleSpinBox; maximumDistanceDoubleSpinBox->setMinimum(0.0); maximumDistanceDoubleSpinBox->setMaximum(10000000000.0); maximumDistanceDoubleSpinBox->setDecimals(3); maximumDistanceDoubleSpinBox->setSingleStep(1.0); maximumDistanceDoubleSpinBox->setValue(100.0); QHBoxLayout* distanceLayout = new QHBoxLayout; distanceLayout->addWidget(maximumDistanceLabel); distanceLayout->addWidget(maximumDistanceDoubleSpinBox); distanceLayout->addStretch(); QGroupBox* gb = new QGroupBox("Surface Selection"); QGridLayout* gridLayout = new QGridLayout(gb); gridLayout->addWidget(leftHemSelectionCheckBox, 0, 0); gridLayout->addWidget(leftHemSelectionComboBox, 0, 1); gridLayout->addWidget(rightHemSelectionCheckBox, 1, 0); gridLayout->addWidget(rightHemSelectionComboBox, 1, 1); gridLayout->addWidget(cerebellumSelectionCheckBox, 2, 0); gridLayout->addWidget(cerebellumSelectionComboBox, 2, 1); gridLayout->addLayout(distanceLayout, 3, 0, 1, 2, Qt::AlignLeft); return gb; } /** * create the assignement options section. */ QWidget* GuiCellAndFociAttributeAssignmentDialog::createAssignmentSection() { // // Assignment Method // std::vector names; std::vector values; BrainModelSurfaceCellAttributeAssignment::getAssignmentNamesAndValues( names, values); QLabel* assignmentMethodLabel = new QLabel("Method"); assignmentMethodComboBox = new QComboBox; for (unsigned int i = 0; i < names.size(); i++) { assignmentMethodComboBox->addItem(names[i], static_cast(values[i])); } // // Attribute ID // QLabel* attributeIDLabel = new QLabel("Attribute ID"); attributeIDSpinBox = new QSpinBox; attributeIDSpinBox->setMinimum(-100000); attributeIDSpinBox->setMaximum( 100000); attributeIDSpinBox->setSingleStep(1); attributeIDSpinBox->setValue(-1); // // Attribute for assignment // QLabel* attributeLabel = new QLabel("Attribute"); std::vector attributeNames; std::vector attributeValues; BrainModelSurfaceCellAttributeAssignment::getAttributeNamesAndValues( attributeNames, attributeValues); assignmentAttributeComboBox = new QComboBox; for (unsigned int i = 0; i < names.size(); i++) { assignmentAttributeComboBox->addItem(attributeNames[i], static_cast(attributeValues[i])); } // // Group box for cell/foci attributes // QGroupBox* assGroupBox = new QGroupBox("Assignment"); QGridLayout* assGroupLayout = new QGridLayout(assGroupBox); assGroupLayout->addWidget(assignmentMethodLabel, 0, 0); assGroupLayout->addWidget(assignmentMethodComboBox, 0, 1); assGroupLayout->addWidget(attributeLabel, 1, 0); assGroupLayout->addWidget(assignmentAttributeComboBox, 1, 1); assGroupLayout->addWidget(attributeIDLabel, 2, 0); assGroupLayout->addWidget(attributeIDSpinBox, 2, 1); assGroupLayout->setColumnStretch(0, 0); assGroupLayout->setColumnStretch(1, 100); return assGroupBox; } /** * create the paint section. */ QWidget* GuiCellAndFociAttributeAssignmentDialog::createPaintSection() { // // Ignore "?" entries check box // ignorePaintQuestionEntriesCheckBox = new QCheckBox("Ignore \"?\" Paint Values"); // // Group box for paint attributes // QGroupBox* paintGroupBox = new QGroupBox("Paint Attributes"); QVBoxLayout* paintGroupLayout = new QVBoxLayout(paintGroupBox); paintGroupLayout->addWidget(ignorePaintQuestionEntriesCheckBox); // // Scroll view // QScrollArea* paintScrollView = new QScrollArea; paintGroupLayout->addWidget(paintScrollView); QWidget* paintScrollWidget = new QWidget; paintNameCheckBoxesLayout = new QVBoxLayout(paintScrollWidget); paintScrollView->setWidget(paintScrollWidget); paintScrollView->setWidgetResizable(true); return paintGroupBox; } /** * update the paint column section. */ void GuiCellAndFociAttributeAssignmentDialog::updatePaintColumnSection() { // // Add check boxes for paint columns // PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); const int numCols = pf->getNumberOfColumns(); for (int i = 0; i < numCols; i++) { QCheckBox* pcb = NULL; if (i < static_cast(paintNameCheckBoxes.size())) { pcb = paintNameCheckBoxes[i]; } else { pcb = new QCheckBox(pf->getColumnName(i)); paintNameCheckBoxesLayout->addWidget(pcb); pcb->setChecked(false); paintNameCheckBoxes.push_back(pcb); } pcb->setText(pf->getColumnName(i)); paintNameCheckBoxes[i]->show(); } for (int i = numCols; i < static_cast(paintNameCheckBoxes.size()); i++) { paintNameCheckBoxes[i]->hide(); } } /** * called when apply button pressed. */ void GuiCellAndFociAttributeAssignmentDialog::slotPushButton(QAbstractButton* buttonPressed) { if (buttonPressed == dialogButtonBox->button(QDialogButtonBox::Apply)) { //performAssignment(); performAssignmentUsingAlgorithm(); } else if (buttonPressed == dialogButtonBox->button(QDialogButtonBox::Close)) { close(); } } /** * perform assignment. */ void GuiCellAndFociAttributeAssignmentDialog::performAssignment() { /* if ((rightHemSelectionCheckBox->isChecked() == false) && (leftHemSelectionCheckBox->isChecked() == false) && (cerebellumSelectionCheckBox->isChecked() == false)) { QMessageBox::critical(this, "ERROR", "All surfaces are deselected."); return; } const BrainModelSurface* leftBMS = leftHemSelectionComboBox->getSelectedBrainModelSurface(); if (leftBMS == NULL) { QMessageBox::critical(this, "ERROR", "No left surface is selected."); return; } const BrainModelSurface* rightBMS = rightHemSelectionComboBox->getSelectedBrainModelSurface(); if (rightBMS == NULL) { QMessageBox::critical(this, "ERROR", "No right surface is selected."); return; } const BrainModelSurface* cerebellumBMS = cerebellumSelectionComboBox->getSelectedBrainModelSurface(); if (cerebellumBMS == NULL) { QMessageBox::critical(this, "ERROR", "No cerebellum surface is selected."); return; } if ((areaRadioButton->isChecked() == false) && (geographyRadioButton->isChecked() == false) && (regionOfInterestRadioButton->isChecked() == false)) { QMessageBox::critical(this, "ERROR", "One of Area, Geography, or Region of Interest must be selected."); return; } // // Get the foci projection file // CellProjectionFile* cf = NULL; if (fociFlag) { cf = theMainWindow->getBrainSet()->getFociProjectionFile(); } else { cf = theMainWindow->getBrainSet()->getCellProjectionFile(); } if (cf != NULL) { const int numCells = cf->getNumberOfCellProjections(); if (numCells > 0) { // // See if paints are selected // PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); const int numPaintCols = pf->getNumberOfColumns(); if (numPaintCols <= 0) { if (clearAttributesWithoutSettingCheckBox->isChecked() == false) { QMessageBox::critical(this, "ERROR", "There are no paint columns."); return; } } // // Determine node nearest to each cell // std::vector cellsNearestLeftNodeDistance(numCells, -1.0); std::vector cellsNearestRightNodeDistance(numCells, -1.0); std::vector cellsNearestCerebellumNodeDistance(numCells, -1.0); std::vector cellsNearestLeftNode(numCells, -1); std::vector cellsNearestRightNode(numCells, -1); std::vector cellsNearestCerebellumNode(numCells, -1); BrainModelSurfacePointLocator leftPointLocator(leftBMS, true); BrainModelSurfacePointLocator rightPointLocator(rightBMS, true); BrainModelSurfacePointLocator cerebellumPointLocator(cerebellumBMS, true); for (int i = 0; i < numCells; i++) { CellProjection* cp = cf->getCellProjection(i); float xyz[3]; cp->getXYZ(xyz); switch (cp->getCellStructure()) { case Structure::STRUCTURE_TYPE_CORTEX_LEFT: case Structure::STRUCTURE_TYPE_CORTEX_LEFT_OR_CEREBELLUM: if (cp->getProjectedPosition(leftBMS->getCoordinateFile(), leftBMS->getTopologyFile(), leftBMS->getIsFiducialSurface(), leftBMS->getIsFlatSurface(), false, xyz)) { cellsNearestLeftNode[i] = leftPointLocator.getNearestPoint(xyz); cellsNearestLeftNodeDistance[i] = MathUtilities::distance3D(xyz, leftBMS->getCoordinateFile()->getCoordinate(cellsNearestLeftNode[i])); } break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT: case Structure::STRUCTURE_TYPE_CORTEX_RIGHT_OR_CEREBELLUM: if (cp->getProjectedPosition(rightBMS->getCoordinateFile(), rightBMS->getTopologyFile(), rightBMS->getIsFiducialSurface(), rightBMS->getIsFlatSurface(), false, xyz)) { cellsNearestRightNode[i] = rightPointLocator.getNearestPoint(xyz); cellsNearestRightNodeDistance[i] = MathUtilities::distance3D(xyz, rightBMS->getCoordinateFile()->getCoordinate(cellsNearestRightNode[i])); } break; case Structure::STRUCTURE_TYPE_CORTEX_BOTH: case Structure::STRUCTURE_TYPE_CEREBELLUM: case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_LEFT: case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_RIGHT: if (cp->getProjectedPosition(cerebellumBMS->getCoordinateFile(), cerebellumBMS->getTopologyFile(), cerebellumBMS->getIsFiducialSurface(), cerebellumBMS->getIsFlatSurface(), false, xyz)) { cellsNearestCerebellumNode[i] = cerebellumPointLocator.getNearestPoint(xyz); cellsNearestCerebellumNodeDistance[i] = MathUtilities::distance3D(xyz, cerebellumBMS->getCoordinateFile()->getCoordinate(cellsNearestCerebellumNode[i])); } break; case Structure::STRUCTURE_TYPE_INVALID: break; } } // // Is right hem deselected // if (rightHemSelectionCheckBox->isChecked() == false) { std::fill(cellsNearestRightNode.begin(), cellsNearestRightNode.end(), -1); } if (leftHemSelectionCheckBox->isChecked() == false) { std::fill(cellsNearestLeftNode.begin(), cellsNearestLeftNode.end(), -1); } if (cerebellumSelectionCheckBox->isChecked() == false) { std::fill(cellsNearestCerebellumNode.begin(), cellsNearestCerebellumNode.end(), -1); } const float maximumDistance = maximumDistanceDoubleSpinBox->value(); // // Process the cells // for (int i = 0; i < numCells; i++) { // // Load cell data into the table // CellProjection* cd = cf->getCellProjection(i); QString valueString; if (areaRadioButton->isChecked()) { valueString = cd->getArea(); } else if (geographyRadioButton->isChecked()) { valueString = cd->getGeography(); } else if (regionOfInterestRadioButton->isChecked()) { valueString = cd->getRegionOfInterest(); } if (appendToCurrentValuesCheckBox->isChecked() == false) { valueString = ""; } if (clearAttributesWithoutSettingCheckBox->isChecked()) { valueString = ""; } else { // // Load paint into the table // int node = -1; float distance = 100000000.0; if (cellsNearestLeftNode[i] >= 0) { node = cellsNearestLeftNode[i]; distance = cellsNearestLeftNodeDistance[i]; } else if (cellsNearestRightNode[i] >= 0) { node = cellsNearestRightNode[i]; distance = cellsNearestRightNodeDistance[i]; } else if (cellsNearestCerebellumNode[i] >= 0) { node = cellsNearestCerebellumNode[i]; distance = cellsNearestCerebellumNodeDistance[i]; } if ((node >= 0) && (distance <= maximumDistance)) { for (int j = 0; j < numPaintCols; j++) { if (paintNameCheckBoxes[j]->isChecked()) { const int paintIndex = pf->getPaint(node, j); QString paintName = pf->getPaintNameFromIndex(paintIndex); if (valueString.isEmpty() == false) { valueString += "; "; } if (ignorePaintQuestionEntriesCheckBox->isChecked()) { if (paintName.startsWith("?")) { paintName = " "; } } valueString += paintName; } } } } if (areaRadioButton->isChecked()) { cd->setArea(valueString); } else if (geographyRadioButton->isChecked()) { cd->setGeography(valueString); } else if (regionOfInterestRadioButton->isChecked()) { cd->setRegionOfInterest(valueString); } } // for (i = 0; i < numCells... } // if (numCells > 0) else { QString msg("There are no "); msg.append(typeString); msg.append("."); QMessageBox::critical(this, "ERROR", msg); return; } } // if (cf != NULL) else { QString msg("There are no "); msg.append(typeString); msg.append("."); QMessageBox::critical(this, "ERROR", msg); return; } */ } /** * perform assignment using algorithm. */ void GuiCellAndFociAttributeAssignmentDialog::performAssignmentUsingAlgorithm() { BrainSet* brainSet = theMainWindow->getBrainSet(); BrainModelSurface* leftSurface = leftHemSelectionComboBox->getSelectedBrainModelSurface(); if (leftHemSelectionCheckBox->isChecked() == false) { leftSurface = NULL; } BrainModelSurface* rightSurface = rightHemSelectionComboBox->getSelectedBrainModelSurface(); if (rightHemSelectionCheckBox->isChecked() == false) { rightSurface = NULL; } BrainModelSurface* cerebellumSurface = cerebellumSelectionComboBox->getSelectedBrainModelSurface(); if (cerebellumSelectionCheckBox->isChecked() == false) { cerebellumSurface = NULL; } PaintFile* paintFile = brainSet->getPaintFile(); std::vector paintColumnSelected; const int numPaintColumns = static_cast(paintNameCheckBoxes.size()); for (int i = 0; i < numPaintColumns; i++) { paintColumnSelected.push_back(paintNameCheckBoxes[i]->isChecked()); } BrainModelSurfaceCellAttributeAssignment::ASSIGN_ATTRIBUTE attribute = static_cast( assignmentAttributeComboBox->itemData( assignmentAttributeComboBox->currentIndex()).toInt()); BrainModelSurfaceCellAttributeAssignment::ASSIGNMENT_METHOD assignmentMethod = static_cast( assignmentMethodComboBox->itemData( assignmentMethodComboBox->currentIndex()).toInt()); BrainModelSurfaceCellAttributeAssignment assignment(brainSet, leftSurface, rightSurface, cerebellumSurface, brainSet->getFociProjectionFile(), paintFile, paintColumnSelected, maximumDistanceDoubleSpinBox->value(), attribute, assignmentMethod, QString::number(attributeIDSpinBox->value()), ignorePaintQuestionEntriesCheckBox->isChecked()); try { assignment.execute(); } catch (BrainModelAlgorithmException& e) { QMessageBox::critical(this, "ERROR", e.whatQString()); } } /** * determine if a check box is shown and checked. */ bool GuiCellAndFociAttributeAssignmentDialog::checked(const QCheckBox* cb) const { return (cb->isVisible() && cb->isChecked()); } caret-5.6.4~dfsg.1.orig/caret/GuiCategoryComboBox.h0000664000175000017500000000314111572067322021702 0ustar michaelmichael #ifndef __GUI_CATEGORY_COMBO_BOX_H__ #define __GUI_CATEGORY_COMBO_BOX_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "Category.h" #include "Species.h" /// class for species selection combo box class GuiCategoryComboBox : public QComboBox { Q_OBJECT public: // constructor GuiCategoryComboBox(QWidget* parent = 0); // destructor ~GuiCategoryComboBox(); // get selected category Category getSelectedCategory() const; // set the category void setSelectedCategory(const Category& s); protected: /// set the current item made protected to prevent user from calling it void setCurrentIndex(int indx); }; #endif // __GUI_CATEGORY_COMBO_BOX_H__ caret-5.6.4~dfsg.1.orig/caret/GuiCategoryComboBox.cxx0000664000175000017500000000415011572067322022256 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "GuiCategoryComboBox.h" /** * constructor. */ GuiCategoryComboBox::GuiCategoryComboBox(QWidget* parent) : QComboBox(parent) { std::vector types; std::vector names; Category::getAllCategoryTypesAndNames(types, names); int defaultIndex = 0; for (unsigned int i = 0; i < names.size(); i++) { addItem(names[i], static_cast(types[i])); if (types[i] == Category::TYPE_INDIVIDUAL) { defaultIndex = i; } } setCurrentIndex(defaultIndex); } /** * destructor. */ GuiCategoryComboBox::~GuiCategoryComboBox() { } /** * get selected category. */ Category GuiCategoryComboBox::getSelectedCategory() const { Category category; const int indx = currentIndex(); if (indx >= 0) { category = static_cast(itemData(indx).toInt()); } return category; } /** * set the category. */ void GuiCategoryComboBox::setSelectedCategory(const Category& c) { const int indx = findData(static_cast(c.getType())); if (indx >= 0) { setCurrentIndex(indx); } } /** * set the current item made protected to prevent user from calling it. */ void GuiCategoryComboBox::setCurrentIndex(int indx) { QComboBox::setCurrentIndex(indx); } caret-5.6.4~dfsg.1.orig/caret/GuiCaretTipsDialog.h0000664000175000017500000000407211572067322021516 0ustar michaelmichael #ifndef __CARET_TIPS_DIALOG_H__ #define __CARET_TIPS_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "CaretTips.h" #include "WuQDialog.h" class QCheckBox; class QPushButton; class QTextEdit; /// dialog for displaying caret tips class GuiCaretTipsDialog : public WuQDialog { Q_OBJECT public: // constructor GuiCaretTipsDialog(QWidget* parent); // destructor ~GuiCaretTipsDialog(); protected slots: // called when previous tip button pressed void slotPreviousTipPushButton(); // called when next tip button pressed void slotNextTipPushButton(); // called when more info button pressed void slotMoreInfoPushButton(); // called when tips at startup toggled void slotShowTipsAtStartupCheckBox(bool showTips); protected: /// show a tip void showTip(const int tipNumber); /// text edit for tips QTextEdit* tipsTextEdit; /// more info push button QPushButton* moreInfoTipPushButton; /// the caret tips CaretTips caretTips; /// show tips at caret startup QCheckBox* showTipsAtCaretStartupCheckBox; }; #endif // __CARET_TIPS_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiCaretTipsDialog.cxx0000664000175000017500000001471511572067322022076 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include "BrainSet.h" #include "GuiCaretTipsDialog.h" #include "GuiMainWindow.h" #include "PreferencesFile.h" #include "QtUtilities.h" #include "global_variables.h" /** * constructor. */ GuiCaretTipsDialog::GuiCaretTipsDialog(QWidget* parent) : WuQDialog(parent) { // // Set title of dialog // setWindowTitle("Caret Tips"); // // text edit for displaying tips // tipsTextEdit = new QTextEdit; tipsTextEdit->setReadOnly(true); // // previous tip push button // QPushButton* previousTipPushButton = new QPushButton("Previous"); previousTipPushButton->setAutoDefault(false); QObject::connect(previousTipPushButton, SIGNAL(clicked()), this, SLOT(slotPreviousTipPushButton())); // // previous tip push button // QPushButton* nextTipPushButton = new QPushButton("Next"); nextTipPushButton->setAutoDefault(false); QObject::connect(nextTipPushButton, SIGNAL(clicked()), this, SLOT(slotNextTipPushButton())); // // previous tip push button // moreInfoTipPushButton = new QPushButton("More Info..."); moreInfoTipPushButton->setAutoDefault(false); QObject::connect(moreInfoTipPushButton, SIGNAL(clicked()), this, SLOT(slotMoreInfoPushButton())); // // Make buttons same size and place in layout // QtUtilities::makeButtonsSameSize(previousTipPushButton, nextTipPushButton, moreInfoTipPushButton); QHBoxLayout* tipsButtonsLayout = new QHBoxLayout; tipsButtonsLayout->addWidget(previousTipPushButton); tipsButtonsLayout->addWidget(nextTipPushButton); tipsButtonsLayout->addWidget(moreInfoTipPushButton); // // Group box and layout for tips and selection // QGroupBox* tipsGroupBox = new QGroupBox("Tips"); QVBoxLayout* tipsLayout = new QVBoxLayout(tipsGroupBox); tipsLayout->addWidget(tipsTextEdit); tipsLayout->addLayout(tipsButtonsLayout); // // Show tips at caret startup check box // showTipsAtCaretStartupCheckBox = new QCheckBox("Show Tips After First Spec File Loaded"); int dummy; bool startupFlag; PreferencesFile* preferencesFile = theMainWindow->getBrainSet()->getPreferencesFile(); preferencesFile->getCaretTips(dummy, startupFlag); showTipsAtCaretStartupCheckBox->setChecked(startupFlag); QObject::connect(showTipsAtCaretStartupCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShowTipsAtStartupCheckBox(bool))); // // Get the layout and add widgets to it // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->addWidget(tipsGroupBox); dialogLayout->addWidget(showTipsAtCaretStartupCheckBox); // // Dialog buttons // QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); buttonBox->button(QDialogButtonBox::Close)->setAutoDefault(false); dialogLayout->addWidget(buttonBox); QObject::connect(buttonBox, SIGNAL(rejected()), this, SLOT(close())); slotNextTipPushButton(); } /** * destructor. */ GuiCaretTipsDialog::~GuiCaretTipsDialog() { } /** * called when tips at startup toggled. */ void GuiCaretTipsDialog::slotShowTipsAtStartupCheckBox(bool showTips) { bool dummy; int tipNumber; PreferencesFile* preferencesFile = theMainWindow->getBrainSet()->getPreferencesFile(); preferencesFile->getCaretTips(tipNumber, dummy); preferencesFile->setCaretTips(tipNumber, showTips); try { preferencesFile->writeFile(preferencesFile->getFileName()); } catch (FileException&) { } } /** * show a tip. */ void GuiCaretTipsDialog::showTip(const int tipNumber) { QString tip, helpPage; caretTips.getTip(tipNumber, tip, helpPage); tipsTextEdit->setText(tip); moreInfoTipPushButton->setEnabled(helpPage.isEmpty() == false); } /** * called when previous tip button pressed. */ void GuiCaretTipsDialog::slotPreviousTipPushButton() { int tipNumber; bool dummy; PreferencesFile* preferencesFile = theMainWindow->getBrainSet()->getPreferencesFile(); preferencesFile->getCaretTips(tipNumber, dummy); tipNumber--; if (tipNumber < 0) { tipNumber = caretTips.getNumberOfCaretTips() - 1; } preferencesFile->setCaretTips(tipNumber, dummy); try { preferencesFile->writeFile(preferencesFile->getFileName()); } catch (FileException&) { } showTip(tipNumber); } /** * called when next tip button pressed. */ void GuiCaretTipsDialog::slotNextTipPushButton() { int tipNumber; bool dummy; PreferencesFile* preferencesFile = theMainWindow->getBrainSet()->getPreferencesFile(); preferencesFile->getCaretTips(tipNumber, dummy); tipNumber++; if (tipNumber >= caretTips.getNumberOfCaretTips()) { tipNumber = 0; } preferencesFile->setCaretTips(tipNumber, dummy); try { preferencesFile->writeFile(preferencesFile->getFileName()); } catch (FileException&) { } showTip(tipNumber); } /** * called when more info button pressed. */ void GuiCaretTipsDialog::slotMoreInfoPushButton() { int tipNumber; bool dummy; PreferencesFile* preferencesFile = theMainWindow->getBrainSet()->getPreferencesFile(); preferencesFile->getCaretTips(tipNumber, dummy); QString tip, helpPage; caretTips.getTip(tipNumber, tip, helpPage); if (helpPage.isEmpty() == false) { theMainWindow->showHelpViewerDialog(helpPage); } } caret-5.6.4~dfsg.1.orig/caret/GuiCaretCommandWidget.h0000664000175000017500000003123611572067322022203 0ustar michaelmichael #ifndef __GUI_CARET_COMMAND_WIDGET_H__ #define __GUI_CARET_COMMAND_WIDGET_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include "ScriptBuilderParameters.h" class CommandBase; class QCheckBox; class QComboBox; class QDoubleSpinBox; class QGridLayout; class QLineEdit; class QSpinBox; class QTextEdit; //============================================================================= /// class for parameters class GuiCaretCommandParameter : public QObject { Q_OBJECT public: /// columns for grid layout enum GRID_COLUMN { /// column for check box GRID_COLUMN_CHECK_BOX, /// column for description GRID_COLUMN_DESCRIPTION, /// column for value GRID_COLUMN_VALUE }; // constructor GuiCaretCommandParameter(const ScriptBuilderParameters::Parameter* parameter); // destructor virtual ~GuiCaretCommandParameter(); // get parameter value as text for the GUI QStringList getParameterForGUI(bool& parameterValidOut) const; /// get the optional switch QString getOptionalSwitch() const { return optionalSwitch; } // set the checkbox void setChecked(const bool b); // set parameter value from text virtual void setParameterValueFromText(const QString& s) = 0; // see if parameter can be blanks virtual bool getParameterAllowedToBeEmpty() const { return false; } // get description of parameter QString getParameterDescription() const { return parameterDescription; } // create a parameter static GuiCaretCommandParameter* createParameter( const ScriptBuilderParameters::Parameter* parameter, QGridLayout* gridLayout); signals: // emitted when data is modified void signalDataModified(); protected: // add widgets to the grid void addWidgetsToGridLayout(QGridLayout* gridLayout, QWidget* descriptionWidget, QWidget* valueWidget); // get parameter value as text virtual QStringList getParameterValueAsText() const = 0; // set the parameter description void setParameterDescription(const QString& parameterDescriptionIn); /// checkbox displayed if an optional parameter QCheckBox* optionCheckBox; /// description of parameter QString parameterDescription; /// the optional switch QString optionalSwitch; }; //============================================================================= /// class for float parameter class GuiCaretCommandParameterFloat : public GuiCaretCommandParameter { Q_OBJECT public: // constructor GuiCaretCommandParameterFloat(const ScriptBuilderParameters::Parameter* parameter, QGridLayout* gridLayout); // destructor virtual ~GuiCaretCommandParameterFloat(); // get parameter value as text QStringList getParameterValueAsText() const; // set parameter value from text void setParameterValueFromText(const QString& s); protected: // double spin box for float value QDoubleSpinBox* doubleSpinBox; }; //============================================================================= /// class for int parameter class GuiCaretCommandParameterInt : public GuiCaretCommandParameter { Q_OBJECT public: // constructor GuiCaretCommandParameterInt(const ScriptBuilderParameters::Parameter* parameter, QGridLayout* gridLayout); // destructor virtual ~GuiCaretCommandParameterInt(); // get parameter value as text QStringList getParameterValueAsText() const; // set parameter value from text void setParameterValueFromText(const QString& s); protected: // spin box for int value QSpinBox* spinBox; }; //============================================================================= /// class for boolean parameter class GuiCaretCommandParameterBoolean : public GuiCaretCommandParameter { Q_OBJECT public: // constructor GuiCaretCommandParameterBoolean(const ScriptBuilderParameters::Parameter* parameter, QGridLayout* gridLayout); // destructor virtual ~GuiCaretCommandParameterBoolean(); // get parameter value as text QStringList getParameterValueAsText() const; // set parameter value from text void setParameterValueFromText(const QString& s); protected: // combo box for boolean value QComboBox* comboBox; }; //============================================================================= /// class for data file parameter class GuiCaretCommandParameterFile : public GuiCaretCommandParameter { Q_OBJECT public: // constructor GuiCaretCommandParameterFile(const ScriptBuilderParameters::Parameter* parameter, QGridLayout* gridLayout, const bool multipleSelectionFlagIn); // destructor virtual ~GuiCaretCommandParameterFile(); // get parameter value as text QStringList getParameterValueAsText() const; // set parameter value from text void setParameterValueFromText(const QString& s); protected slots: // called when push button pressed void slotPushButtonPressed(); protected: // line edit for file name QLineEdit* fileNameLineEdit; /// the file filters QStringList fileFilters; /// allows multiple selections bool multipleSelectionFlag; }; //============================================================================= /// class for data directory parameter class GuiCaretCommandParameterDirectory : public GuiCaretCommandParameter { Q_OBJECT public: // constructor GuiCaretCommandParameterDirectory(const ScriptBuilderParameters::Parameter* parameter, QGridLayout* gridLayout); // destructor virtual ~GuiCaretCommandParameterDirectory(); // get parameter value as text QStringList getParameterValueAsText() const; // set parameter value from text void setParameterValueFromText(const QString& s); protected slots: // called when push button pressed void slotPushButtonPressed(); protected: // line edit for directory name QLineEdit* directoryNameLineEdit; }; //============================================================================= /// class for data string parameter class GuiCaretCommandParameterString : public GuiCaretCommandParameter { Q_OBJECT public: // constructor GuiCaretCommandParameterString(const ScriptBuilderParameters::Parameter* parameter, QGridLayout* gridLayout); // destructor virtual ~GuiCaretCommandParameterString(); // get parameter value as text QStringList getParameterValueAsText() const; // set parameter value from text void setParameterValueFromText(const QString& s); protected: // line edit for text QLineEdit* lineEdit; }; //============================================================================= /// class for data variable parameter list class GuiCaretCommandParameterVariableList : public GuiCaretCommandParameter { Q_OBJECT public: // constructor GuiCaretCommandParameterVariableList(const ScriptBuilderParameters::Parameter* parameter, QGridLayout* gridLayout); // destructor virtual ~GuiCaretCommandParameterVariableList(); // see if parameter can be blanks virtual bool getParameterAllowedToBeEmpty() const { return true; } // get parameter value as text QStringList getParameterValueAsText() const; // set parameter value from text void setParameterValueFromText(const QString& s); protected slots: // called when add file button is selected void slotAddFileButton(); protected: /// text edit for text QTextEdit* textEdit; }; //============================================================================= /// class for data item list class GuiCaretCommandParameterDataItemList : public GuiCaretCommandParameter { Q_OBJECT public: // constructor GuiCaretCommandParameterDataItemList(const ScriptBuilderParameters::Parameter* parameter, QGridLayout* gridLayout); // destructor virtual ~GuiCaretCommandParameterDataItemList(); // get parameter value as text QStringList getParameterValueAsText() const; // set parameter value from text void setParameterValueFromText(const QString& s); protected: /// combo box for items QComboBox* comboBox; /// values for combo box std::vector dataValues; }; //============================================================================= /// class for structure class GuiCaretCommandParameterStructure : public GuiCaretCommandParameter { Q_OBJECT public: // constructor GuiCaretCommandParameterStructure(const ScriptBuilderParameters::Parameter* parameter, QGridLayout* gridLayout); // destructor virtual ~GuiCaretCommandParameterStructure(); // get parameter value as text QStringList getParameterValueAsText() const; // set parameter value from text void setParameterValueFromText(const QString& s); protected: /// combo box for items QComboBox* comboBox; /// values for combo box std::vector comboBoxValues; }; //============================================================================= /// class for a single command in a widget class GuiCaretCommandWidget : public QGroupBox { Q_OBJECT public: // constructor GuiCaretCommandWidget(CommandBase* commandIn, const bool showCommentOption); // destructor ~GuiCaretCommandWidget(); // get the command switch and parameters for the GUI void getCommandLineForGUI(QString& commandSwitchOut, QStringList& commandParametersOut, QString& commandShortDescriptionOut, bool& lastParameterIsVariableListFlag) const; // get the command switch and parameters for executing command void getCommandLineForCommandExecution(QString& commandSwitchOut, QStringList& commandParametersOut, QString& commandShortDescriptionOut, QString& errorMessageOut) const; /// get the comment QString getComment() const; /// get the command CommandBase* getCommand() { return command; } // set the comment void setComment(const QString& s); // set the parameters void setParameters(const QStringList& parametersIn); signals: // emitted when data is modified void signalDataModified(); protected: /// the parameters std::vector commandParameters; /// comment line edit QLineEdit* commentLineEdit; /// the command switch QString commandSwitch; /// the command CommandBase* command; /// the command short description QString commandShortDescription; }; #endif // __GUI_CARET_COMMAND_WIDGET_H__ caret-5.6.4~dfsg.1.orig/caret/GuiCaretCommandWidget.cxx0000664000175000017500000011024311572067322022552 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "CommandBase.h" #include "CommandScriptComment.h" #include "DebugControl.h" #include "FileFilters.h" #include "GuiCaretCommandWidget.h" #include "ProgramParameters.h" #include "QtUtilities.h" #include "StringUtilities.h" #include "Structure.h" #include "WuQFileDialog.h" #include "WuQWidgetGroup.h" //============================================================================= //============================================================================= //============================================================================= /** * constructor. */ GuiCaretCommandWidget::GuiCaretCommandWidget(CommandBase* commandIn, const bool showCommentOptionIn) : QGroupBox("") { command = commandIn; commandSwitch = command->getOperationSwitch(); commandShortDescription = command->getShortDescription(); // // No comment line if command is script comment // bool showCommentOption = showCommentOptionIn; if (dynamic_cast(command) != NULL) { showCommentOption = false; } // // Set "this" group box title // setTitle(commandIn->getShortDescription() + " Parameters"); // // Comment // commentLineEdit = new QLineEdit; QObject::connect(commentLineEdit, SIGNAL(textChanged(const QString&)), this, SIGNAL(signalDataModified())); QLabel* commentLabel = new QLabel("Comment"); QHBoxLayout* commentLayout = new QHBoxLayout; commentLayout->addWidget(commentLabel); commentLayout->addWidget(commentLineEdit); commentLayout->setStretchFactor(commentLabel, 0); commentLayout->setStretchFactor(commentLineEdit, 1000); // // Layout parameters // ScriptBuilderParameters parameters; command->getScriptBuilderParameters(parameters); QGridLayout* gridLayout = new QGridLayout; gridLayout->setColumnStretch(GuiCaretCommandParameter::GRID_COLUMN_CHECK_BOX, 0); gridLayout->setColumnStretch(GuiCaretCommandParameter::GRID_COLUMN_DESCRIPTION, 0); gridLayout->setColumnStretch(GuiCaretCommandParameter::GRID_COLUMN_VALUE, 1000); for (int i = 0; i < parameters.getNumberOfParameters(); i++) { GuiCaretCommandParameter* gccp = GuiCaretCommandParameter::createParameter(parameters.getParameter(i), gridLayout); QObject::connect(gccp, SIGNAL(signalDataModified()), this, SIGNAL(signalDataModified())); commandParameters.push_back(gccp); } // // Hide comment? // if (showCommentOption == false) { commentLabel->hide(); commentLineEdit->hide(); } // // Layout widgets // QVBoxLayout* widgetLayout = new QVBoxLayout(this); widgetLayout->addLayout(commentLayout); widgetLayout->addLayout(gridLayout); widgetLayout->addStretch(); } /** * destructor. */ GuiCaretCommandWidget::~GuiCaretCommandWidget() { if (command != NULL) { delete command; command = NULL; } } /** * get the command switch and parameters. */ void GuiCaretCommandWidget::getCommandLineForGUI(QString& commandSwitchOut, QStringList& commandParametersOut, QString& commandShortDescriptionOut, bool& lastParameterIsVariableListFlag) const { lastParameterIsVariableListFlag = false; commandSwitchOut = commandSwitch; commandShortDescriptionOut = commandShortDescription; commandParametersOut.clear(); int numParams = static_cast(commandParameters.size()); for (int i = 0; i < numParams; i++) { bool paramValidFlag = false; const QStringList param = commandParameters[i]->getParameterForGUI(paramValidFlag); if (paramValidFlag) { commandParametersOut += param; if (i == (numParams - 1)) { if (dynamic_cast(commandParameters[i]) != NULL) { lastParameterIsVariableListFlag = true; } } } } } /** * get the command switch and parameters. */ void GuiCaretCommandWidget::getCommandLineForCommandExecution(QString& commandSwitchOut, QStringList& commandParametersOut, QString& commandShortDescriptionOut, QString& errorMessageOut) const { errorMessageOut = ""; commandSwitchOut = commandSwitch; commandShortDescriptionOut = commandShortDescription; commandParametersOut.clear(); int numParams = static_cast(commandParameters.size()); for (int i = 0; i < numParams; i++) { bool paramValidFlag = false; const QStringList param = commandParameters[i]->getParameterForGUI(paramValidFlag); if (paramValidFlag) { if (param.isEmpty()) { if (commandParameters[i]->getParameterAllowedToBeEmpty() == false) { if (errorMessageOut.isEmpty() == false) { errorMessageOut += "\n"; } errorMessageOut += ("Parameter \"" + commandParameters[i]->getParameterDescription() + "\" is missing its value."); } // // Empty parameters goes in double quotes // //param = "\"\""; } // // Is last parameter variable list parameter? // if (i == (numParams - 1)) { if (dynamic_cast(commandParameters[i]) != NULL) { // // Split up variable list // //QStringList sl; //StringUtilities::tokenStringsWithQuotes(param, sl); if (param.count() == 1) { const QString p = param.at(0).trimmed(); if (p.isEmpty() == false) { commandParametersOut += param; } } else { commandParametersOut += param; } } else { commandParametersOut += param; } } else { commandParametersOut += param; } } } } /** * get the comment. */ QString GuiCaretCommandWidget::getComment() const { return commentLineEdit->text(); } /** * set the comment. */ void GuiCaretCommandWidget::setComment(const QString& s) { commentLineEdit->setText(s); } /** * set the parameters. */ void GuiCaretCommandWidget::setParameters(const QStringList& parametersIn) { QStringList parameters = parametersIn; const int numParamGUI = static_cast(commandParameters.size()); // // Look for and set any optional parameters first // for (int i = 0; i < numParamGUI; i++) { GuiCaretCommandParameter* cmdParam = commandParameters[i]; const QString optSwitch = cmdParam->getOptionalSwitch(); if (optSwitch.isEmpty() == false) { for (int j = 0; j < parameters.count(); j++) { if (parameters.at(j) == optSwitch) { cmdParam->setChecked(true); const int nextJ = j + 1; if (nextJ < parameters.count()) { cmdParam->setParameterValueFromText(parametersIn.at(nextJ)); parameters.removeAt(nextJ); } parameters.removeAt(j); break; } } } } // // Set required parameters last // const int num = std::min(numParamGUI, static_cast(parameters.count())); for (int i = 0; i < num; i++) { GuiCaretCommandParameter* cmdParam = commandParameters[i]; if (cmdParam->getOptionalSwitch().isEmpty()) { // // If parameter is variable list, use all // remaining parameters // GuiCaretCommandParameterVariableList* varListParam = dynamic_cast(cmdParam); if (varListParam != NULL) { QString str = ""; while (i < static_cast(parameters.count())) { if (str.isEmpty() == false) { str += " "; } str += parametersIn.at(i); i++; } cmdParam->setParameterValueFromText(str); } else { cmdParam->setParameterValueFromText(parametersIn.at(i)); } } } } //============================================================================= //============================================================================= //============================================================================= /** * constructor. */ GuiCaretCommandParameter::GuiCaretCommandParameter(const ScriptBuilderParameters::Parameter* parameter) { optionalSwitch = parameter->getOptionalSwitch(); optionCheckBox = NULL; } /** * destructor. */ GuiCaretCommandParameter::~GuiCaretCommandParameter() { } /** * add widgets to the grid. */ void GuiCaretCommandParameter::addWidgetsToGridLayout(QGridLayout* gridLayout, QWidget* descriptionWidget, QWidget* valueWidget) { const int rowNumber = gridLayout->rowCount(); if (optionalSwitch.isEmpty() == false) { optionCheckBox = new QCheckBox(""); gridLayout->addWidget(optionCheckBox, rowNumber, GRID_COLUMN_CHECK_BOX); } gridLayout->addWidget(descriptionWidget, rowNumber, GRID_COLUMN_DESCRIPTION); gridLayout->addWidget(valueWidget, rowNumber, GRID_COLUMN_VALUE); if (optionCheckBox != NULL) { WuQWidgetGroup* wg = new WuQWidgetGroup(optionCheckBox); wg->addWidget(descriptionWidget); wg->addWidget(valueWidget); QObject::connect(optionCheckBox, SIGNAL(toggled(bool)), wg, SLOT(setEnabled(bool))); wg->setEnabled(optionCheckBox->isChecked()); } } /** * set the checkbox. */ void GuiCaretCommandParameter::setChecked(const bool b) { if (optionCheckBox != NULL) { optionCheckBox->setChecked(b); } } /** * get parameter value as text for the GUI. */ QStringList GuiCaretCommandParameter::getParameterForGUI(bool& parameterValidOut) const { QStringList cmdParams; parameterValidOut = true; if (optionCheckBox != NULL) { if (optionCheckBox->isChecked()) { cmdParams += optionalSwitch; } else { parameterValidOut = false; } } if (parameterValidOut) { const QStringList sl = getParameterValueAsText(); for (int i = 0; i < sl.count(); i++) { cmdParams += sl.at(i).trimmed(); } } return cmdParams; } /** * set the parameter description. */ void GuiCaretCommandParameter::setParameterDescription(const QString& parameterDescriptionIn) { parameterDescription = parameterDescriptionIn; } /** * create a parameter. */ GuiCaretCommandParameter* GuiCaretCommandParameter::createParameter(const ScriptBuilderParameters::Parameter* parameter, QGridLayout* gridLayout) { GuiCaretCommandParameter* commandParameter = NULL; switch (parameter->getType()) { case ScriptBuilderParameters::Parameter::TYPE_BOOLEAN: commandParameter = new GuiCaretCommandParameterBoolean(parameter, gridLayout); break; case ScriptBuilderParameters::Parameter::TYPE_DIRECTORY: commandParameter = new GuiCaretCommandParameterDirectory(parameter, gridLayout); break; case ScriptBuilderParameters::Parameter::TYPE_FILE: commandParameter = new GuiCaretCommandParameterFile(parameter, gridLayout, false); break; case ScriptBuilderParameters::Parameter::TYPE_FILE_MULTIPLE: commandParameter = new GuiCaretCommandParameterFile(parameter, gridLayout, true); break; case ScriptBuilderParameters::Parameter::TYPE_FLOAT: commandParameter = new GuiCaretCommandParameterFloat(parameter, gridLayout); break; case ScriptBuilderParameters::Parameter::TYPE_INT: commandParameter = new GuiCaretCommandParameterInt(parameter, gridLayout); break; case ScriptBuilderParameters::Parameter::TYPE_LIST_OF_ITEMS: commandParameter = new GuiCaretCommandParameterDataItemList(parameter, gridLayout); break; case ScriptBuilderParameters::Parameter::TYPE_STRING: commandParameter = new GuiCaretCommandParameterString(parameter, gridLayout); break; case ScriptBuilderParameters::Parameter::TYPE_VARIABLE_LIST_OF_PARAMETERS: commandParameter = new GuiCaretCommandParameterVariableList(parameter, gridLayout); break; case ScriptBuilderParameters::Parameter::TYPE_STRUCTURE: commandParameter = new GuiCaretCommandParameterStructure(parameter, gridLayout); break; default: { QLabel* label1 = new QLabel(parameter->getDescription()); QLabel* label2 = new QLabel("UNKNOWN PARAMETER TYPE"); commandParameter->addWidgetsToGridLayout(gridLayout, label1, label2); //const int rowNumber = gridLayout->rowCount(); //gridLayout->addWidget(label1, rowNumber, GRID_COLUMN_DESCRIPTION); //gridLayout->addWidget(label2, rowNumber, GRID_COLUMN_VALUE); } std::cout << "PROGRAM ERROR: Unsupported parameter type for." << std::endl; break; } if (commandParameter != NULL) { commandParameter->setParameterDescription(parameter->getDescription()); } return commandParameter; } //============================================================================= //============================================================================= //============================================================================= /** * constructor. */ GuiCaretCommandParameterFloat::GuiCaretCommandParameterFloat(const ScriptBuilderParameters::Parameter* parameter, QGridLayout* gridLayout) : GuiCaretCommandParameter(parameter) { QLabel* label = new QLabel(parameter->getDescription()); float defaultValue, minimumValue, maximumValue; parameter->getFloatParameters(defaultValue, minimumValue, maximumValue); doubleSpinBox = new QDoubleSpinBox; doubleSpinBox->setMinimum(minimumValue); doubleSpinBox->setMaximum(maximumValue); doubleSpinBox->setDecimals(3); doubleSpinBox->setValue(defaultValue); QObject::connect(doubleSpinBox, SIGNAL(valueChanged(double)), this, SIGNAL(signalDataModified())); addWidgetsToGridLayout(gridLayout, label, doubleSpinBox); //const int rowNumber = gridLayout->rowCount(); //gridLayout->addWidget(label, rowNumber, GRID_COLUMN_DESCRIPTION); //gridLayout->addWidget(doubleSpinBox, rowNumber, GRID_COLUMN_VALUE); } /** * destructor. */ GuiCaretCommandParameterFloat::~GuiCaretCommandParameterFloat() { } /** * get parameter value as text. */ QStringList GuiCaretCommandParameterFloat::getParameterValueAsText() const { const QString s = QString::number(doubleSpinBox->value(), 'f', 3); return QStringList(s); } /** * set parameter value from text. */ void GuiCaretCommandParameterFloat::setParameterValueFromText(const QString& s) { doubleSpinBox->setValue(s.toFloat()); } //============================================================================= //============================================================================= //============================================================================= /** * constructor. */ GuiCaretCommandParameterInt::GuiCaretCommandParameterInt(const ScriptBuilderParameters::Parameter* parameter, QGridLayout* gridLayout) : GuiCaretCommandParameter(parameter) { QLabel* label = new QLabel(parameter->getDescription()); int defaultValue, minimumValue, maximumValue; parameter->getIntParameters(defaultValue, minimumValue, maximumValue); spinBox = new QSpinBox; spinBox->setMinimum(minimumValue); spinBox->setMaximum(maximumValue); spinBox->setValue(defaultValue); QObject::connect(spinBox, SIGNAL(valueChanged(int)), this, SIGNAL(signalDataModified())); addWidgetsToGridLayout(gridLayout, label, spinBox); //const int rowNumber = gridLayout->rowCount(); //gridLayout->addWidget(label, rowNumber, GRID_COLUMN_DESCRIPTION); //gridLayout->addWidget(spinBox, rowNumber, GRID_COLUMN_VALUE); } /** * destructor. */ GuiCaretCommandParameterInt::~GuiCaretCommandParameterInt() { } /** * get parameter value as text. */ QStringList GuiCaretCommandParameterInt::getParameterValueAsText() const { const QString s = QString::number(spinBox->value()); return QStringList(s); } /** * set parameter value from text. */ void GuiCaretCommandParameterInt::setParameterValueFromText(const QString& s) { spinBox->setValue(s.toInt()); } //============================================================================= //============================================================================= //============================================================================= /** * constructor. */ GuiCaretCommandParameterBoolean::GuiCaretCommandParameterBoolean(const ScriptBuilderParameters::Parameter* parameter, QGridLayout* gridLayout) : GuiCaretCommandParameter(parameter) { QLabel* label = new QLabel(parameter->getDescription()); bool defaultValue; parameter->getBooleanParameters(defaultValue); comboBox = new QComboBox; comboBox->addItem("false"); comboBox->addItem("true"); QObject::connect(comboBox, SIGNAL(currentIndexChanged(int)), this, SIGNAL(signalDataModified())); if (defaultValue) { comboBox->setCurrentIndex(1); } else { comboBox->setCurrentIndex(0); } addWidgetsToGridLayout(gridLayout, label, comboBox); //const int rowNumber = gridLayout->rowCount(); //gridLayout->addWidget(label, rowNumber, GRID_COLUMN_DESCRIPTION); //gridLayout->addWidget(comboBox, rowNumber, GRID_COLUMN_VALUE); } /** * destructor. */ GuiCaretCommandParameterBoolean::~GuiCaretCommandParameterBoolean() { } /** * get parameter value as text. */ QStringList GuiCaretCommandParameterBoolean::getParameterValueAsText() const { QString s("false"); if (comboBox->currentIndex() == 1) { s = "true"; } return QStringList(s); } /** * set parameter value from text. */ void GuiCaretCommandParameterBoolean::setParameterValueFromText(const QString& s) { if (s.toLower().trimmed() == "true") { comboBox->setCurrentIndex(1); } else { comboBox->setCurrentIndex(0); } } //============================================================================= //============================================================================= //============================================================================= /** * constructor. */ GuiCaretCommandParameterFile::GuiCaretCommandParameterFile(const ScriptBuilderParameters::Parameter* parameter, QGridLayout* gridLayout, const bool multipleSelectionFlagIn) : GuiCaretCommandParameter(parameter) { multipleSelectionFlag = multipleSelectionFlagIn; QPushButton* pushButton = new QPushButton(parameter->getDescription() + "..."); pushButton->setAutoDefault(false); QObject::connect(pushButton, SIGNAL(clicked()), this, SLOT(slotPushButtonPressed())); fileNameLineEdit = new QLineEdit; QObject::connect(fileNameLineEdit, SIGNAL(textChanged(const QString&)), this, SIGNAL(signalDataModified())); addWidgetsToGridLayout(gridLayout, pushButton, fileNameLineEdit); //const int rowNumber = gridLayout->rowCount(); //gridLayout->addWidget(pushButton, rowNumber, GRID_COLUMN_DESCRIPTION); //gridLayout->addWidget(fileNameLineEdit, rowNumber, GRID_COLUMN_VALUE); QString defaultFileName; parameter->getFileParameters(fileFilters, defaultFileName); fileNameLineEdit->setText(defaultFileName); } /** * destructor. */ GuiCaretCommandParameterFile::~GuiCaretCommandParameterFile() { } /** * called when push button pressed. */ void GuiCaretCommandParameterFile::slotPushButtonPressed() { WuQFileDialog fd(fileNameLineEdit); fd.setModal(true); fd.setAcceptMode(WuQFileDialog::AcceptOpen); fd.setDirectory(QDir::currentPath()); if (multipleSelectionFlag) { fd.setFileMode(WuQFileDialog::ExistingFiles); } else { fd.setFileMode(WuQFileDialog::ExistingFile); } fd.setFilters(fileFilters); if (fd.exec() == WuQFileDialog::Accepted) { QString fileList; QStringList selectedFiles = fd.selectedFiles(); for (int i = 0; i < selectedFiles.count(); i++) { QString fileName = selectedFiles.at(i); QFileInfo fi(fileName); if (fi.absolutePath() == QDir::currentPath()) { fileName = fi.fileName(); } if (i > 0) { fileList += " "; } fileList += fileName; if (multipleSelectionFlag == false) { break; } } fileNameLineEdit->setText(fileList); } } /** * get parameter value as text. */ QStringList GuiCaretCommandParameterFile::getParameterValueAsText() const { if (fileNameLineEdit->text().size() >= 2) { if (fileNameLineEdit->text().startsWith('\"') && fileNameLineEdit->text().endsWith('\"')) { return QStringList(fileNameLineEdit->text()); } } return QStringList(fileNameLineEdit->text().split(' ', QString::SkipEmptyParts)); } /** * set parameter value from text. */ void GuiCaretCommandParameterFile::setParameterValueFromText(const QString& s) { fileNameLineEdit->setText(s); } //============================================================================= //============================================================================= //============================================================================= /** * constructor. */ GuiCaretCommandParameterDirectory::GuiCaretCommandParameterDirectory(const ScriptBuilderParameters::Parameter* parameter, QGridLayout* gridLayout) : GuiCaretCommandParameter(parameter) { QPushButton* pushButton = new QPushButton(parameter->getDescription() + "..."); pushButton->setAutoDefault(false); QObject::connect(pushButton, SIGNAL(clicked()), this, SLOT(slotPushButtonPressed())); directoryNameLineEdit = new QLineEdit; QObject::connect(directoryNameLineEdit, SIGNAL(textChanged(const QString&)), this, SIGNAL(signalDataModified())); addWidgetsToGridLayout(gridLayout, pushButton, directoryNameLineEdit); //const int rowNumber = gridLayout->rowCount(); //gridLayout->addWidget(pushButton, rowNumber, GRID_COLUMN_DESCRIPTION); //gridLayout->addWidget(directoryNameLineEdit, rowNumber, GRID_COLUMN_VALUE); } /** * destructor. */ GuiCaretCommandParameterDirectory::~GuiCaretCommandParameterDirectory() { } /** * called when push button pressed. */ void GuiCaretCommandParameterDirectory::slotPushButtonPressed() { WuQFileDialog fd(directoryNameLineEdit); fd.setModal(true); fd.setAcceptMode(WuQFileDialog::AcceptOpen); fd.setDirectory(QDir::currentPath()); fd.setFileMode(WuQFileDialog::DirectoryOnly); if (fd.exec() == WuQFileDialog::Accepted) { if (fd.selectedFiles().count() > 0) { const QString dirName = fd.selectedFiles().at(0); directoryNameLineEdit->setText(dirName); } } } /** * get parameter value as text. */ QStringList GuiCaretCommandParameterDirectory::getParameterValueAsText() const { return QStringList(directoryNameLineEdit->text()); } /** * set parameter value from text. */ void GuiCaretCommandParameterDirectory::setParameterValueFromText(const QString& s) { directoryNameLineEdit->setText(s); } //============================================================================= //============================================================================= //============================================================================= /** * constructor. */ GuiCaretCommandParameterDataItemList::GuiCaretCommandParameterDataItemList(const ScriptBuilderParameters::Parameter* parameter, QGridLayout* gridLayout) : GuiCaretCommandParameter(parameter) { QLabel* label = new QLabel(parameter->getDescription()); comboBox = new QComboBox; std::vector dataNames; parameter->getListOfItemParameters(dataValues, dataNames); for (unsigned int i = 0; i < dataNames.size(); i++) { comboBox->addItem(dataNames[i]); } QObject::connect(comboBox, SIGNAL(currentIndexChanged(int)), this, SIGNAL(signalDataModified())); addWidgetsToGridLayout(gridLayout, label, comboBox); //const int rowNumber = gridLayout->rowCount(); //gridLayout->addWidget(label, rowNumber, GRID_COLUMN_DESCRIPTION); //gridLayout->addWidget(comboBox, rowNumber, GRID_COLUMN_VALUE); } /** * destructor. */ GuiCaretCommandParameterDataItemList::~GuiCaretCommandParameterDataItemList() { } /** * get parameter value as text. */ QStringList GuiCaretCommandParameterDataItemList::getParameterValueAsText() const { const int indx = comboBox->currentIndex(); const QString s = dataValues[indx]; return QStringList(s); } /** * set parameter value from text. */ void GuiCaretCommandParameterDataItemList::setParameterValueFromText(const QString& s) { for (int i = 0; i < comboBox->count(); i++) { if (s == dataValues[i]) { comboBox->setCurrentIndex(i); break; } } } //============================================================================= //============================================================================= //============================================================================= /** * constructor. */ GuiCaretCommandParameterStructure::GuiCaretCommandParameterStructure(const ScriptBuilderParameters::Parameter* parameter, QGridLayout* gridLayout) : GuiCaretCommandParameter(parameter) { std::vector types; std::vector names; Structure::getAllTypesAndNames(types, names, false); comboBoxValues = names; QLabel* label = new QLabel(parameter->getDescription()); comboBox = new QComboBox; QObject::connect(comboBox, SIGNAL(currentIndexChanged(int)), this, SIGNAL(signalDataModified())); for (unsigned int i = 0; i < comboBoxValues.size(); i++) { comboBox->addItem(comboBoxValues[i]); } addWidgetsToGridLayout(gridLayout, label, comboBox); //const int rowNumber = gridLayout->rowCount(); //gridLayout->addWidget(label, rowNumber, GRID_COLUMN_DESCRIPTION); //gridLayout->addWidget(comboBox, rowNumber, GRID_COLUMN_VALUE); } /** * destructor. */ GuiCaretCommandParameterStructure::~GuiCaretCommandParameterStructure() { } /** * get parameter value as text. */ QStringList GuiCaretCommandParameterStructure::getParameterValueAsText() const { const int indx = comboBox->currentIndex(); const QString s = comboBoxValues[indx]; return QStringList(s); } /** * set parameter value from text. */ void GuiCaretCommandParameterStructure::setParameterValueFromText(const QString& s) { for (int i = 0; i < comboBox->count(); i++) { if (s == comboBoxValues[i]) { comboBox->setCurrentIndex(i); break; } } } //============================================================================= //============================================================================= //============================================================================= /** * constructor. */ GuiCaretCommandParameterString::GuiCaretCommandParameterString(const ScriptBuilderParameters::Parameter* parameter, QGridLayout* gridLayout) : GuiCaretCommandParameter(parameter) { QLabel* label = new QLabel(parameter->getDescription()); lineEdit = new QLineEdit; QString defaultValue; parameter->getStringParameters(defaultValue); lineEdit->setText(defaultValue); QObject::connect(lineEdit, SIGNAL(textChanged(const QString&)), this, SIGNAL(signalDataModified())); addWidgetsToGridLayout(gridLayout, label, lineEdit); //const int rowNumber = gridLayout->rowCount(); //gridLayout->addWidget(label, rowNumber, GRID_COLUMN_DESCRIPTION); //gridLayout->addWidget(lineEdit, rowNumber, GRID_COLUMN_VALUE); } /** * destructor. */ GuiCaretCommandParameterString::~GuiCaretCommandParameterString() { } /** * get parameter value as text. */ QStringList GuiCaretCommandParameterString::getParameterValueAsText() const { const QString s = lineEdit->text(); return QStringList(s); } /** * set parameter value from text. */ void GuiCaretCommandParameterString::setParameterValueFromText(const QString& s) { lineEdit->setText(s); } //============================================================================= //============================================================================= //============================================================================= /** * constructor. */ GuiCaretCommandParameterVariableList::GuiCaretCommandParameterVariableList(const ScriptBuilderParameters::Parameter* parameter, QGridLayout* gridLayout) : GuiCaretCommandParameter(parameter) { QLabel* label = new QLabel(parameter->getDescription()); QPushButton* addFilePushButton = new QPushButton("Add File..."); addFilePushButton->setAutoDefault(false); addFilePushButton->setFixedSize(addFilePushButton->sizeHint()); QObject::connect(addFilePushButton, SIGNAL(clicked()), this, SLOT(slotAddFileButton())); textEdit = new QTextEdit; QString defaultValue; parameter->getVariableListParameters(defaultValue); textEdit->setText(defaultValue); QObject::connect(textEdit, SIGNAL(textChanged()), this, SIGNAL(signalDataModified())); const int rowNumber = gridLayout->rowCount(); gridLayout->addWidget(label, rowNumber, GRID_COLUMN_DESCRIPTION); gridLayout->addWidget(addFilePushButton, rowNumber + 1, GRID_COLUMN_DESCRIPTION); gridLayout->addWidget(textEdit, rowNumber, GRID_COLUMN_VALUE, 2, 1); gridLayout->setRowStretch(rowNumber, 0); gridLayout->setRowStretch(rowNumber + 1, 0); gridLayout->setRowStretch(rowNumber + 2, 100); } /** * destructor. */ GuiCaretCommandParameterVariableList::~GuiCaretCommandParameterVariableList() { } /** * called when add file button is selected. */ void GuiCaretCommandParameterVariableList::slotAddFileButton() { QStringList allFileFilters; FileFilters::getAllFileFilters(allFileFilters); static QString lastFileFilter(FileFilters::getAnyFileFilter()); WuQFileDialog fd(textEdit); fd.setModal(true); fd.setAcceptMode(WuQFileDialog::AcceptOpen); fd.setDirectory(QDir::currentPath()); fd.setFileMode(WuQFileDialog::ExistingFiles); fd.setFilters(allFileFilters); fd.selectFilter(lastFileFilter); if (fd.exec() == WuQFileDialog::Accepted) { QString fileList; QStringList selectedFiles = fd.selectedFiles(); for (int i = 0; i < selectedFiles.count(); i++) { QString fileName = selectedFiles.at(i); QFileInfo fi(fileName); if (fi.absolutePath() == QDir::currentPath()) { fileName = fi.fileName(); } fileList += " "; fileList += fileName; } textEdit->setText(textEdit->toPlainText() + fileList); } } /** * get parameter value as text. */ QStringList GuiCaretCommandParameterVariableList::getParameterValueAsText() const { const QString s = textEdit->toPlainText(); QStringList sl; QString str; bool inDoubleQuoteFlag = false; // // Loop through the string keeping anything between double quotes intact // const int slen = s.length(); for (int i = 0; i < slen; i++) { const QChar c = s[i]; // // Beginning or end of double quote // if (c == '"') { str += c; if (inDoubleQuoteFlag) { // // String in double quotes is complete // sl += str; str = ""; inDoubleQuoteFlag = false; } else { // // Starting string in double quotes // inDoubleQuoteFlag = true; } } else if ((c == ' ') || (c == '\n') || (c == '\r')) { if (inDoubleQuoteFlag) { // // Keep blanks in double quotes // str += c; } else { if (str.isEmpty() == false) { // // Conclude string // sl += str; str = ""; } } } else { // // Add character to string // str += c; } } // // Use any remaining string at end of text // if (str.isEmpty() == false) { sl += str; } //QStringList sl = s.split(' ', QString::SkipEmptyParts); return sl; } /** * set parameter value from text. */ void GuiCaretCommandParameterVariableList::setParameterValueFromText(const QString& s) { textEdit->setText(s); } //============================================================================= //============================================================================= //============================================================================= //============================================================================= //============================================================================= //============================================================================= caret-5.6.4~dfsg.1.orig/caret/GuiCaretCommandScriptBuilderDialog.h0000664000175000017500000001356011572067322024653 0ustar michaelmichael #ifndef __GUI_CARET_COMMAND_SCRIPT_BUILDER_DIALOG_H__ #define __GUI_CARET_COMMAND_SCRIPT_BUILDER_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "WuQDialog.h" class CaretScriptFile; class CommandBase; class GuiCaretCommandWidget; class GuiCaretCommandContainerWidget; class QScrollArea; class QVBoxLayout; /// class for constructing and editing caret command scripts class GuiCaretCommandScriptBuilderDialog : public WuQDialog { Q_OBJECT public: // constructor GuiCaretCommandScriptBuilderDialog(QWidget* parent, const QString& caretHomeDirectory); // destructor ~GuiCaretCommandScriptBuilderDialog(); protected slots: // called when new button pressed void slotNewPushButton(); // called when open button pressed void slotOpenPushButton(); // called when run button pressed void slotRunPushButton(); // called when save button pressed void slotSavePushButton(); // called when close button pressed void slotClosePushButton(); // called when help button pressed void slotHelpPushButton(); // called to add a new command void slotAddCommand(GuiCaretCommandContainerWidget* addAfterWidget); // called to delete a command void slotDeleteCommand(GuiCaretCommandContainerWidget* deleteWidget); // called to move a command up one position void slotMoveCommandUp(GuiCaretCommandContainerWidget* ccw); // called to move a command down one position void slotMoveCommandDown(GuiCaretCommandContainerWidget* ccw); // called when data is modified void slotDataModified(); protected: // add initial command to the dialog void addInitialCommand(const QString& commandSwitch, const QString& commandComment, const QStringList& commandParameters); // delete a container widget void deleteContainerWidget(GuiCaretCommandContainerWidget* ccw); // get the container widgets void getContainerWidgets(std::vector& containerWidgetsOut); // get the command widgets void getCommandWidgets(std::vector& commandWidgetsOut); // place the commands into a script file void placeCommandsIntoScriptFile(CaretScriptFile& scriptFile); // scroll area containing commands QScrollArea* commandScrollArea; /// widget containing the command widgets QWidget* commandLayoutWidget; /// layout for commands QVBoxLayout* commandLayout; /// name of caret command program QString caretCommandProgramName; /// the available caret commands std::vector caretCommands; /// widgets that have been removed and need to be deleted std::vector widgetsThatNeedToBeDeleted; /// name of script in dialog QString scriptFileName; /// data in dialog is modified bool dataIsModified; }; /// class for a single operation class GuiCaretCommandContainerWidget : public QWidget { Q_OBJECT public: // constructor GuiCaretCommandContainerWidget(CommandBase* commandOperationIn, const bool showDeleteButton = true); // destructor ~GuiCaretCommandContainerWidget(); // get the widget GuiCaretCommandWidget* getCommandWidget() { return commandWidget; } // set the comment and parameters void setCommentAndParameters(const QString& commentIn, const QStringList& parametersIn); signals: /// add button was pressed signal void signalAddButtonPressed(GuiCaretCommandContainerWidget*); /// delete button was pressed signal void signalDeleteButtonPressed(GuiCaretCommandContainerWidget*); /// move up button was pressed signal void signalMoveUpButtonPressed(GuiCaretCommandContainerWidget*); /// move down button was pressed signal void signalMoveDownButtonPressed(GuiCaretCommandContainerWidget*); // emitted when data is modified void signalDataModified(); protected slots: // called when add button pressed void slotAddPushButton(); // called when delete button pressed void slotDeletePushButton(); // called when help button pressed void slotHelpPushButton(); // called when move up button pressed void slotMoveUpPushButton(); // called when move down button pressed void slotMoveDownPushButton(); protected: /// the command widget GuiCaretCommandWidget* commandWidget; /// the command's help text QString commandHelpText; }; #endif // __GUI_CARET_COMMAND_SCRIPT_BUILDER_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiCaretCommandScriptBuilderDialog.cxx0000664000175000017500000007327211572067322025234 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include "WuQFileDialog.h" #include #include #include #include #include #include "BrainSet.h" #include "CaretScriptFile.h" #include "CommandBase.h" #include "CommandScriptComment.h" #include "DebugControl.h" #include "FileFilters.h" #include "FileUtilities.h" #include "GuiCaretCommandDialog.h" #include "GuiCaretCommandScriptBuilderDialog.h" #include "GuiCaretCommandWidget.h" #include "GuiMainWindow.h" #include "QtTextEditDialog.h" #include "QtUtilities.h" #include "global_variables.h" /** * constructor. */ GuiCaretCommandScriptBuilderDialog::GuiCaretCommandScriptBuilderDialog(QWidget* parent, const QString& caretHomeDirectory) : WuQDialog(parent) { setWindowTitle("Caret Command Script Builder"); // // Set path/name of Caret program // caretCommandProgramName = ""; if (caretHomeDirectory.isEmpty() == false) { caretCommandProgramName = caretHomeDirectory; caretCommandProgramName.append("/"); caretCommandProgramName.append(BrainSet::getBinDirectoryName()); caretCommandProgramName.append("/"); } caretCommandProgramName.append("caret_command"); // // Scroll area for command widgets // commandLayoutWidget = new QWidget; commandLayout = new QVBoxLayout(commandLayoutWidget); commandLayout->setSpacing(5); commandScrollArea = new QScrollArea; commandScrollArea->setWidget(commandLayoutWidget); commandScrollArea->setWidgetResizable(true); // // New push button // QPushButton* newPushButton = new QPushButton("New..."); newPushButton->setAutoDefault(false); newPushButton->setFixedSize(newPushButton->sizeHint()); QObject::connect(newPushButton, SIGNAL(clicked()), this, SLOT(slotNewPushButton())); // // Open push button // QPushButton* openPushButton = new QPushButton("Open..."); openPushButton->setAutoDefault(false); openPushButton->setFixedSize(openPushButton->sizeHint()); QObject::connect(openPushButton, SIGNAL(clicked()), this, SLOT(slotOpenPushButton())); // // save push button // QPushButton* savePushButton = new QPushButton("Save..."); savePushButton->setAutoDefault(false); savePushButton->setFixedSize(savePushButton->sizeHint()); QObject::connect(savePushButton, SIGNAL(clicked()), this, SLOT(slotSavePushButton())); // // run push button // QPushButton* runPushButton = new QPushButton("Run..."); runPushButton->setAutoDefault(false); runPushButton->setFixedSize(runPushButton->sizeHint()); QObject::connect(runPushButton, SIGNAL(clicked()), this, SLOT(slotRunPushButton())); // // help push button // QPushButton* helpPushButton = new QPushButton("Help..."); helpPushButton->setAutoDefault(false); helpPushButton->setFixedSize(helpPushButton->sizeHint()); QObject::connect(helpPushButton, SIGNAL(clicked()), this, SLOT(slotHelpPushButton())); // // Close push button // QPushButton* closePushButton = new QPushButton("Close"); closePushButton->setAutoDefault(false); closePushButton->setFixedSize(closePushButton->sizeHint()); QObject::connect(closePushButton, SIGNAL(clicked()), this, SLOT(slotClosePushButton())); // // Size buttons // QtUtilities::makeButtonsSameSize(newPushButton, openPushButton, savePushButton, runPushButton, helpPushButton, closePushButton); // // Layout for buttons // QHBoxLayout* buttonsLayout1 = new QHBoxLayout; buttonsLayout1->addWidget(newPushButton); buttonsLayout1->addWidget(openPushButton); buttonsLayout1->addWidget(savePushButton); buttonsLayout1->addWidget(runPushButton); buttonsLayout1->addWidget(helpPushButton); buttonsLayout1->addWidget(closePushButton); // // Layout dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->addWidget(commandScrollArea); dialogLayout->addLayout(buttonsLayout1); // // Get commands and initialize command widgets // CommandBase::getAllCommandsSortedByDescription(caretCommands); // // add comment // CommandScriptComment commandComment; QStringList commandStringList; commandStringList.append("Enter comment describing script here."); addInitialCommand(commandComment.getOperationSwitch(), "", commandStringList); dataIsModified = false; } /** * destructor. */ GuiCaretCommandScriptBuilderDialog::~GuiCaretCommandScriptBuilderDialog() { const int numCommands = static_cast(caretCommands.size()); for (int i = 0; i < numCommands; i++) { delete caretCommands[i]; caretCommands[i] = NULL; } const int numWidgets = static_cast(widgetsThatNeedToBeDeleted.size()); for (int i = 0; i < numWidgets; i++) { delete widgetsThatNeedToBeDeleted[i]; widgetsThatNeedToBeDeleted[i] = NULL; } widgetsThatNeedToBeDeleted.clear(); } /** * called when new button pressed. */ void GuiCaretCommandScriptBuilderDialog::slotNewPushButton() { if (dataIsModified) { if (QMessageBox::question(this, "Confirm", "Current script has been modified but not saved. \n" "Create new script without saving current script?", (QMessageBox::Ok | QMessageBox::Cancel), QMessageBox::Cancel) == QMessageBox::Cancel) { return; } } // // Remove all widgets in script builder // std::vector containerWidgets; getContainerWidgets(containerWidgets); const int numToDelete = static_cast(containerWidgets.size()); for (int i = (numToDelete - 1); i >= 0; i--) { deleteContainerWidget(containerWidgets[i]); } // // add comment // CommandScriptComment commandComment; QStringList commandStringList; commandStringList.append("Enter comment describing script here."); addInitialCommand(commandComment.getOperationSwitch(), "", commandStringList); // // Data is unmodified // dataIsModified = false; scriptFileName = ""; } /** * called when open button pressed. */ void GuiCaretCommandScriptBuilderDialog::slotOpenPushButton() { if (dataIsModified) { if (QMessageBox::question(this, "Confirm", "Current script has been modified but not saved. \n" "Open new script without saving current script?", (QMessageBox::Ok | QMessageBox::Cancel), QMessageBox::Cancel) == QMessageBox::Cancel) { return; } } WuQFileDialog fd(this); fd.setAcceptMode(WuQFileDialog::AcceptOpen); fd.setDirectory("."); fd.setFileMode(WuQFileDialog::ExistingFile); fd.setFilter(FileFilters::getCaretScriptFileFilter()); fd.selectFilter(FileFilters::getCaretScriptFileFilter()); if ((fd.exec() == WuQFileDialog::Accepted) && (fd.selectedFiles().count() > 0)) { // // Get the name of the file // const QString scriptFileNameRead(fd.selectedFiles().at(0)); // // Read the script file // CaretScriptFile scriptFile; try { scriptFile.readFile(scriptFileNameRead); scriptFileName = scriptFileNameRead; } catch (FileException& e) { QMessageBox::critical(this, "ERROR", e.whatQString()); return; } // // Remove all widgets in script builder // std::vector containerWidgets; getContainerWidgets(containerWidgets); const int numToDelete = static_cast(containerWidgets.size()); for (int i = (numToDelete - 1); i >= 0; i--) { deleteContainerWidget(containerWidgets[i]); } // // Get the number of operations in the file // const int numOperations = scriptFile.getNumberOfCommandOperations(); if (numOperations > 0) { // // Loop through the operations // for (int i = 0; i < numOperations; i++) { // // get the operation // CaretScriptFile::CaretCommandOperation* operation = scriptFile.getCommandOperation(i); const QString commandSwitch = operation->getSwitch(); // // 1st operation is always comment // if (i == 0) { CommandScriptComment commandComment; if (commandSwitch != commandComment.getOperationSwitch()) { // // add comment // QStringList commandStringList; commandStringList.append("Enter comment describing script here."); addInitialCommand(commandComment.getOperationSwitch(), "", commandStringList); } } // // add the operation // addInitialCommand(commandSwitch, operation->getComment(), operation->getParametersForGUI()); } } // // data is unmodified // dataIsModified = false; } } /** * called when run button pressed. */ void GuiCaretCommandScriptBuilderDialog::slotRunPushButton() { if (dataIsModified) { if (QMessageBox::question(this, "Confirm", "Current script has been modified but not saved. \n" "and it is recommended to save the script prior\n" "to running it.\n" "Run without saving current script?", (QMessageBox::Ok | QMessageBox::Cancel), QMessageBox::Cancel) == QMessageBox::Cancel) { return; } } // // Too much text output may cause problems // const QString envVarName("CARET_DEBUG"); if (std::getenv(envVarName.toAscii().constData()) != NULL) { const QString msg = ("WARNING: The environment variable " + envVarName + " is on.\n" + "This may cause the caret_command program to hang if\n" + "there is too much printed output."); if (QMessageBox::question(this, "WARNING", msg, (QMessageBox::Ok | QMessageBox::Cancel), QMessageBox::Cancel) == QMessageBox::Cancel) { return; } } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); // // The script file // CaretScriptFile scriptFile; // // Put the commands into a script file // placeCommandsIntoScriptFile(scriptFile); // // Run the script file // QString commandsOutputText; try { scriptFile.runCommandsInFile(this, caretCommandProgramName, commandsOutputText); } catch (FileException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); return; } QApplication::beep(); QApplication::restoreOverrideCursor(); // // Display the results of the command // QtTextEditDialog* te = new QtTextEditDialog(this, true); te->setText(commandsOutputText); te->show(); } /** * called when save button pressed. */ void GuiCaretCommandScriptBuilderDialog::slotSavePushButton() { WuQFileDialog fd(this); fd.setAcceptMode(WuQFileDialog::AcceptSave); fd.setConfirmOverwrite(true); fd.setDirectory("."); fd.setFileMode(WuQFileDialog::AnyFile); fd.setFilter(FileFilters::getCaretScriptFileFilter()); fd.selectFilter(FileFilters::getCaretScriptFileFilter()); if (scriptFileName.isEmpty() == false) { fd.selectFile(FileUtilities::basename(scriptFileName)); } if ((fd.exec() == WuQFileDialog::Accepted) && (fd.selectedFiles().count() > 0)) { // // Get the name of the file // const QString scriptFileNameWrite(fd.selectedFiles().at(0)); // // The script file // CaretScriptFile scriptFile; // // Put the commands into a script file // placeCommandsIntoScriptFile(scriptFile); // // Write the script file // try { scriptFile.writeFile(scriptFileNameWrite); // // Clear data modified // dataIsModified = false; scriptFileName = scriptFileNameWrite; } catch (FileException& e) { QMessageBox::critical(this, "ERROR", e.whatQString()); } } } /** * place the commands into a script file. */ void GuiCaretCommandScriptBuilderDialog::placeCommandsIntoScriptFile(CaretScriptFile& scriptFile) { // // Get the command widgets // std::vector commandWidgets; getCommandWidgets(commandWidgets); // // Loop through the commands // const int num = static_cast(commandWidgets.size()); for (int i = 0; i < num; i++) { // // Get the command // QString commandSwitch; QString commandShortDescription; QStringList commandParameters; bool lastParameterIsVariableListFlag; commandWidgets[i]->getCommandLineForGUI(commandSwitch, commandParameters, commandShortDescription, lastParameterIsVariableListFlag); // // Add command to the file // CaretScriptFile::CaretCommandOperation* op = new CaretScriptFile::CaretCommandOperation(commandSwitch, commandParameters, lastParameterIsVariableListFlag, commandShortDescription, commandWidgets[i]->getComment()); scriptFile.addCommandOperation(op); } } /** * called when close button pressed. */ void GuiCaretCommandScriptBuilderDialog::slotClosePushButton() { close(); } /** * called when help button pressed. */ void GuiCaretCommandScriptBuilderDialog::slotHelpPushButton() { theMainWindow->showHelpViewerDialog("caret_scripting/CaretScripting.html"); } /** * get the caret command operations. */ void GuiCaretCommandScriptBuilderDialog::getCommandWidgets(std::vector& commandWidgetsOut) { commandWidgetsOut.clear(); std::vector containerWidgets; getContainerWidgets(containerWidgets); const int num = static_cast(containerWidgets.size()); for (int i = 0; i < num; i++) { commandWidgetsOut.push_back(containerWidgets[i]->getCommandWidget()); } } /** * get the container widgets. */ void GuiCaretCommandScriptBuilderDialog::getContainerWidgets(std::vector& containerWidgetsOut) { containerWidgetsOut.clear(); const int num = commandLayout->count(); for (int i = 0; i < num; i++) { QLayoutItem* item = commandLayout->itemAt(i); QWidget* widget = item->widget(); if (widget != NULL) { GuiCaretCommandContainerWidget* ccw = dynamic_cast(widget); if (ccw != NULL) { containerWidgetsOut.push_back(ccw); } } } } /** * add a command to the dialog. */ void GuiCaretCommandScriptBuilderDialog::addInitialCommand(const QString& commandSwitch, const QString& commandComment, const QStringList& commandParameters) { // // Loop through and find the desired command // bool commandFound = false; const int numCommands = static_cast(caretCommands.size()); for (int i = 0; i < numCommands; i++) { if (commandSwitch == caretCommands[i]->getOperationSwitch()) { // // Create the gui widget for the command // GuiCaretCommandContainerWidget* ccw = new GuiCaretCommandContainerWidget(caretCommands[i], true); ccw->setCommentAndParameters(commandComment, commandParameters); // // connect signals // QObject::connect(ccw, SIGNAL(signalAddButtonPressed(GuiCaretCommandContainerWidget*)), this, SLOT(slotAddCommand(GuiCaretCommandContainerWidget*))); QObject::connect(ccw, SIGNAL(signalDeleteButtonPressed(GuiCaretCommandContainerWidget*)), this, SLOT(slotDeleteCommand(GuiCaretCommandContainerWidget*))); QObject::connect(ccw, SIGNAL(signalMoveUpButtonPressed(GuiCaretCommandContainerWidget*)), this, SLOT(slotMoveCommandUp(GuiCaretCommandContainerWidget*))); QObject::connect(ccw, SIGNAL(signalMoveDownButtonPressed(GuiCaretCommandContainerWidget*)), this, SLOT(slotMoveCommandDown(GuiCaretCommandContainerWidget*))); QObject::connect(ccw, SIGNAL(signalDataModified()), this, SLOT(slotDataModified())); // // Add to the dialog // commandLayout->addWidget(ccw); commandLayoutWidget->updateGeometry(); //commandScrollArea->ensureWidgetVisible(ccw); commandFound = true; } } if (commandFound == false) { QMessageBox::critical(this, "ERROR", "Command " + commandSwitch + " not found."); } } /** * called when data is modified. */ void GuiCaretCommandScriptBuilderDialog::slotDataModified() { dataIsModified = true; } /** * called to add a new command. */ void GuiCaretCommandScriptBuilderDialog::slotAddCommand(GuiCaretCommandContainerWidget* addAfterWidget) { static QSize dialogSize(0, 0); static QString lastCommandSwitch; // // Choose the command // GuiCaretCommandDialog ccd(this, theMainWindow->getBrainSet()->getCaretHomeDirectory(), GuiCaretCommandDialog::DIALOG_MODE_COMMAND_SELECTOR_WITH_BEFORE_AFTER); if (dialogSize.width() > 0) { ccd.resize(dialogSize); } if (lastCommandSwitch.isEmpty() == false) { ccd.setSelectedCommand(lastCommandSwitch); } if (ccd.exec() == GuiCaretCommandDialog::Accepted) { // // Does new widget go after current widget? // const bool afterFlag = ccd.getAddAfterWidget(); // // Save dialog size // dialogSize = ccd.size(); // // Get the command switch // const QString commandSwitch = ccd.getSelectedCommandSwitch(); if (commandSwitch.isEmpty() == false) { lastCommandSwitch = commandSwitch; // // Loop through and find the desired command // CommandBase* command = NULL; const int numCommands = static_cast(caretCommands.size()); for (int i = 0; i < numCommands; i++) { if (commandSwitch == caretCommands[i]->getOperationSwitch()) { command = caretCommands[i]; break; } } if (command != NULL) { // // Create the gui widget for the command // GuiCaretCommandContainerWidget* ccw = new GuiCaretCommandContainerWidget(command); // // connect signals // QObject::connect(ccw, SIGNAL(signalAddButtonPressed(GuiCaretCommandContainerWidget*)), this, SLOT(slotAddCommand(GuiCaretCommandContainerWidget*))); QObject::connect(ccw, SIGNAL(signalDeleteButtonPressed(GuiCaretCommandContainerWidget*)), this, SLOT(slotDeleteCommand(GuiCaretCommandContainerWidget*))); QObject::connect(ccw, SIGNAL(signalMoveUpButtonPressed(GuiCaretCommandContainerWidget*)), this, SLOT(slotMoveCommandUp(GuiCaretCommandContainerWidget*))); QObject::connect(ccw, SIGNAL(signalMoveDownButtonPressed(GuiCaretCommandContainerWidget*)), this, SLOT(slotMoveCommandDown(GuiCaretCommandContainerWidget*))); QObject::connect(ccw, SIGNAL(signalDataModified()), this, SLOT(slotDataModified())); // // Add to the dialog after the widget that requested the add // int widgetIndex = commandLayout->indexOf(addAfterWidget); if (widgetIndex >= 0) { if (afterFlag) { if (widgetIndex >= (commandLayout->count() - 1)) { widgetIndex = -1; } else { widgetIndex++; } } commandLayout->insertWidget(widgetIndex, ccw); commandLayoutWidget->updateGeometry(); commandScrollArea->ensureWidgetVisible(ccw); } } } // // Data now modified // slotDataModified(); } } /** * called to delete a command. */ void GuiCaretCommandScriptBuilderDialog::slotDeleteCommand(GuiCaretCommandContainerWidget* deleteWidget) { if (QMessageBox::question(this, "CONFIRM", "Delete Command?", (QMessageBox::Ok | QMessageBox::Cancel), QMessageBox::Ok) == QMessageBox::Ok) { deleteContainerWidget(deleteWidget); // // Data now modified // slotDataModified(); } } /** * delete a container widget. */ void GuiCaretCommandScriptBuilderDialog::deleteContainerWidget(GuiCaretCommandContainerWidget* ccw) { // // Remove the widget from the gui // ccw->hide(); commandLayout->removeWidget(ccw); // use takeAt() ???? commandLayoutWidget->updateGeometry(); // // Delete later since this method called from "deleteWidget" // widgetsThatNeedToBeDeleted.push_back(ccw); } /** * called to move a command up one position. */ void GuiCaretCommandScriptBuilderDialog::slotMoveCommandUp(GuiCaretCommandContainerWidget* ccw) { const int widgetIndex = commandLayout->indexOf(ccw); if (widgetIndex > 0) { commandLayout->removeWidget(ccw); commandLayout->insertWidget(widgetIndex - 1, ccw); commandLayoutWidget->updateGeometry(); // // Data now modified // slotDataModified(); } } /** * called to move a command down one position. */ void GuiCaretCommandScriptBuilderDialog::slotMoveCommandDown(GuiCaretCommandContainerWidget* ccw) { const int widgetIndex = commandLayout->indexOf(ccw); if (widgetIndex < (commandLayout->count() - 1)) { commandLayout->removeWidget(ccw); commandLayout->insertWidget(widgetIndex + 1, ccw); commandLayoutWidget->updateGeometry(); // // Data now modified // slotDataModified(); } } //============================================================================= /** * constructor. */ GuiCaretCommandContainerWidget::GuiCaretCommandContainerWidget( CommandBase* commandOperationIn, const bool showDeleteButton) { // // Create the gui widget for the command // commandWidget = new GuiCaretCommandWidget(commandOperationIn, true); QObject::connect(commandWidget, SIGNAL(signalDataModified()), this, SIGNAL(signalDataModified())); // // Get the help text // commandHelpText = commandOperationIn->getHelpInformation(); // // Create the add button // QPushButton* addPushButton = new QPushButton("Add"); addPushButton->setToolTip("Add an operation after\n" "or before this operation."); addPushButton->setAutoDefault(false); QObject::connect(addPushButton, SIGNAL(clicked()), this, SLOT(slotAddPushButton())); // // Create the delete button // QPushButton* deletePushButton = new QPushButton("Del"); deletePushButton->setToolTip("Delete this operation."); deletePushButton->setAutoDefault(false); QObject::connect(deletePushButton, SIGNAL(clicked()), this, SLOT(slotDeletePushButton())); // // Create the help button // QPushButton* helpPushButton = new QPushButton("Help"); helpPushButton->setToolTip("Show help information\n" "about this command."); helpPushButton->setAutoDefault(false); QObject::connect(helpPushButton, SIGNAL(clicked()), this, SLOT(slotHelpPushButton())); // // Create the move up button // QPushButton* moveUpPushButton = new QPushButton("Up"); moveUpPushButton->setToolTip("Move this command\n" "up one position."); moveUpPushButton->setAutoDefault(false); QObject::connect(moveUpPushButton, SIGNAL(clicked()), this, SLOT(slotMoveUpPushButton())); // // Create the move down button // QPushButton* moveDownPushButton = new QPushButton("Down"); moveDownPushButton->setToolTip("Move this command\n" "up one position."); moveDownPushButton->setAutoDefault(false); QObject::connect(moveDownPushButton, SIGNAL(clicked()), this, SLOT(slotMoveDownPushButton())); // // Make buttons same size // QtUtilities::makeButtonsSameSize(addPushButton, deletePushButton, helpPushButton, moveUpPushButton, moveDownPushButton); // // Layout for buttons // QVBoxLayout* buttonsLayout = new QVBoxLayout; buttonsLayout->addWidget(addPushButton); buttonsLayout->addWidget(deletePushButton); buttonsLayout->addWidget(helpPushButton); buttonsLayout->addStretch(); buttonsLayout->addWidget(moveUpPushButton); buttonsLayout->addWidget(moveDownPushButton); // // Layout for widget // QHBoxLayout* widgetLayout = new QHBoxLayout(this); widgetLayout->addLayout(buttonsLayout); widgetLayout->addWidget(commandWidget); widgetLayout->setStretchFactor(buttonsLayout, 0); widgetLayout->setStretchFactor(commandWidget, 1000); if (showDeleteButton == false) { deletePushButton->hide(); } } /** * destructor. */ GuiCaretCommandContainerWidget::~GuiCaretCommandContainerWidget() { } /** * called when add button pressed. */ void GuiCaretCommandContainerWidget::slotAddPushButton() { emit signalAddButtonPressed(this); } /** * called when delete button pressed. */ void GuiCaretCommandContainerWidget::slotDeletePushButton() { emit signalDeleteButtonPressed(this); } /** * called when move up button pressed. */ void GuiCaretCommandContainerWidget::slotMoveUpPushButton() { emit signalMoveUpButtonPressed(this); } /** * called when move down button pressed. */ void GuiCaretCommandContainerWidget::slotMoveDownPushButton() { emit signalMoveDownButtonPressed(this); } /** * called when help button pressed. */ void GuiCaretCommandContainerWidget::slotHelpPushButton() { QtTextEditDialog* te = new QtTextEditDialog(this, true, false); te->setText(commandHelpText); te->show(); } /** * set the comment and parameters. */ void GuiCaretCommandContainerWidget::setCommentAndParameters(const QString& commentIn, const QStringList& parametersIn) { commandWidget->setComment(commentIn); commandWidget->setParameters(parametersIn); } caret-5.6.4~dfsg.1.orig/caret/GuiCaretCommandDialog.h0000664000175000017500000000742511572067322022162 0ustar michaelmichael #ifndef __GUI_CARET_COMMAND_DIALOG_H__ #define __GUI_CARET_COMMAND_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "WuQDialog.h" #include "ScriptBuilderParameters.h" class CommandBase; class GuiCaretCommandWidget; class ProgramParameters; class QListWidget; class QRadioButton; class QScrollArea; class QStackedWidget; class QTextEdit; //============================================================================= /// dialog for constructing a caret command operation class GuiCaretCommandDialog : public WuQDialog { Q_OBJECT public: // mode of dialog enum DIALOG_MODE { /// for command selection, modal, "exec()" to run DIALOG_MODE_COMMAND_SELECTOR, /// for command selection, modal, "exec()" to run with before after DIALOG_MODE_COMMAND_SELECTOR_WITH_BEFORE_AFTER, /// for executing commands, non-modal, "show()" to run DIALOG_MODE_EXECUTOR_NON_MODAL }; // constructor GuiCaretCommandDialog(QWidget* parent, const QString& caretHomeDirectory, const DIALOG_MODE dialogModeIn); // destructor ~GuiCaretCommandDialog(); // get the selected command (if command selector mode) QString getSelectedCommandSwitch() const; // get add after button selected (if before/after) bool getAddAfterWidget() const; // initialize to command void setSelectedCommand(const QString& commandSwitch); protected slots: // called when process command button is pressed void slotProcessCommandButton(); // called when a command is selected void slotCommandListWidgetSelection(int item); protected: // create the command parameters widget GuiCaretCommandWidget* createCommandParametersWidget(CommandBase* command); /// caret command executable QString caretCommandProgramName; /// operations list box QListWidget* commandsListWidget; /// command description text edit QTextEdit* commandDescriptionTextEdit; /// stacked widget for command parameters QStackedWidget* commandParametersStackedWidget; /// the currently selected command CommandBase* selectedCommand; /// needed for initializing commands ProgramParameters* params; /// mode of dialog DIALOG_MODE dialogMode; /// scroll area for parameters QScrollArea* commandParametersScrollArea; /// the caret commands std::vector caretCommands; /// the widgets for each command std::vector caretCommandWidgets; /// add after radio button QRadioButton* addAfterRadioButton; /// add before radio button QRadioButton* addBeforeRadioButton; }; #endif // __GUI_CARET_COMMAND_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiCaretCommandDialog.cxx0000664000175000017500000004655511572067322022544 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "BrainModelRunExternalProgram.h" #include "CommandBase.h" #include "DebugControl.h" #include "GuiCaretCommandWidget.h" #include "GuiCaretCommandDialog.h" #include "ProgramParameters.h" #include "QtTextEditDialog.h" #include "QtUtilities.h" /** * constructor. */ GuiCaretCommandDialog::GuiCaretCommandDialog(QWidget* parent, const QString& /*caretHomeDirectory*/, const DIALOG_MODE dialogModeIn) : WuQDialog(parent) { dialogMode = dialogModeIn; selectedCommand = NULL; switch (dialogMode) { case DIALOG_MODE_COMMAND_SELECTOR: case DIALOG_MODE_COMMAND_SELECTOR_WITH_BEFORE_AFTER: setWindowTitle("Caret Command Selector"); break; case DIALOG_MODE_EXECUTOR_NON_MODAL: setWindowTitle("Caret Command Executor"); break; } // // Set path/name of Caret program // caretCommandProgramName = ""; /* if (caretHomeDirectory.isEmpty() == false) { caretCommandProgramName = caretHomeDirectory; caretCommandProgramName.append("/"); caretCommandProgramName.append("bin"); caretCommandProgramName.append("/"); } */ caretCommandProgramName.append("caret_command"); // // List box for commands // commandsListWidget = new QListWidget; QObject::connect(commandsListWidget, SIGNAL(currentRowChanged(int)), this, SLOT(slotCommandListWidgetSelection(int))); commandsListWidget->setMinimumHeight(50); // // commands group box and layout // QGroupBox* commandsGroupBox = new QGroupBox("Commands"); QVBoxLayout* commandsLayout = new QVBoxLayout(commandsGroupBox); commandsLayout->addWidget(commandsListWidget); // // Group box for command description section // commandDescriptionTextEdit = new QTextEdit; commandDescriptionTextEdit->setLineWrapMode(QTextEdit::NoWrap); QGroupBox* commandDescriptionGroupBox = new QGroupBox("Command Description"); QVBoxLayout* commandDescriptionLayout = new QVBoxLayout(commandDescriptionGroupBox); commandDescriptionLayout->addWidget(commandDescriptionTextEdit); // // Stacked widget for commands // commandParametersStackedWidget = new QStackedWidget; commandParametersScrollArea = new QScrollArea; commandParametersScrollArea->setWidget(commandParametersStackedWidget); commandParametersScrollArea->setWidgetResizable(true); // // command/help row // QSplitter* commandHelpSplitter = new QSplitter; commandHelpSplitter->setOrientation(Qt::Horizontal); commandHelpSplitter->addWidget(commandsGroupBox); commandHelpSplitter->addWidget(commandDescriptionGroupBox); // // all widgets in dialog // QWidget* dialogWidgets = NULL; addAfterRadioButton = NULL; addBeforeRadioButton = NULL; switch (dialogMode) { case DIALOG_MODE_COMMAND_SELECTOR: dialogWidgets = commandHelpSplitter; break; case DIALOG_MODE_COMMAND_SELECTOR_WITH_BEFORE_AFTER: { // // Add after/before current operation radio buttons // addAfterRadioButton = new QRadioButton("Add After Current Operation"); addBeforeRadioButton = new QRadioButton("Add Before Current Operation"); // // Keep radio buttons mutually exclusive // QButtonGroup* buttGroup = new QButtonGroup(this); buttGroup->addButton(addAfterRadioButton); buttGroup->addButton(addBeforeRadioButton); addAfterRadioButton->setChecked(true); // // Place radio buttons into group box // QGroupBox* beforeAfterGroupBox = new QGroupBox("Add New Operation Location"); QVBoxLayout* beforeAfterLayout = new QVBoxLayout(beforeAfterGroupBox); beforeAfterLayout->addWidget(addAfterRadioButton); beforeAfterLayout->addWidget(addBeforeRadioButton); beforeAfterGroupBox->setFixedSize(beforeAfterGroupBox->sizeHint()); // // Put group box below operation selection // dialogWidgets = new QWidget; QVBoxLayout* layout = new QVBoxLayout(dialogWidgets); layout->addWidget(commandHelpSplitter); layout->addWidget(beforeAfterGroupBox); layout->addStretch(); } break; case DIALOG_MODE_EXECUTOR_NON_MODAL: // // Keep parameters visible // commandParametersScrollArea->setMinimumHeight(250); // // Splitter for top and bottom halves // QSplitter* horizontalSplitter = new QSplitter; horizontalSplitter->setOrientation(Qt::Vertical); horizontalSplitter->addWidget(commandHelpSplitter); horizontalSplitter->addWidget(commandParametersScrollArea); dialogWidgets = horizontalSplitter; break; } // // buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; switch (dialogMode) { case DIALOG_MODE_COMMAND_SELECTOR: case DIALOG_MODE_COMMAND_SELECTOR_WITH_BEFORE_AFTER: { // // // OK push button // QPushButton* okPushButton = new QPushButton("OK"); okPushButton->setAutoDefault(false); QObject::connect(okPushButton, SIGNAL(clicked()), this, SLOT(accept())); // // Cancel push button // QPushButton* cancelPushButton = new QPushButton("Cancel"); cancelPushButton->setAutoDefault(false); QObject::connect(cancelPushButton, SIGNAL(clicked()), this, SLOT(reject())); buttonsLayout->addWidget(okPushButton); buttonsLayout->addWidget(cancelPushButton); QtUtilities::makeButtonsSameSize(okPushButton, cancelPushButton); } break; case DIALOG_MODE_EXECUTOR_NON_MODAL: { // // Execute push button // QPushButton* executePushButton = new QPushButton("Execute Command"); executePushButton->setAutoDefault(false); QObject::connect(executePushButton, SIGNAL(clicked()), this, SLOT(slotProcessCommandButton())); // // Close push button // QPushButton* closePushButton = new QPushButton("Close"); closePushButton->setAutoDefault(false); QObject::connect(closePushButton, SIGNAL(clicked()), this, SLOT(close())); buttonsLayout->addWidget(executePushButton); buttonsLayout->addWidget(closePushButton); QtUtilities::makeButtonsSameSize(executePushButton, closePushButton); } break; } // // layout the widgets // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->addWidget(dialogWidgets); dialogLayout->addLayout(buttonsLayout); // // Need to prevent list widget from emitting signals until all is set up // commandsListWidget->blockSignals(true); char* argv[] = { "caret_command", "" }; params = new ProgramParameters(1, argv); // // Get commands and initialize command widgets // CommandBase::getAllCommandsSortedByDescription(caretCommands); const int numCommands = static_cast(caretCommands.size()); caretCommandWidgets.resize(numCommands, NULL); for (int i = 0; i < numCommands; i++) { // // Get help information // caretCommands[i]->setParameters(params); commandsListWidget->addItem(caretCommands[i]->getShortDescription()); // // Initialize widget for commands parameters and add to // parameters stacked widget // commandParametersStackedWidget->addWidget(new QWidget); } // // OK for signals // commandsListWidget->blockSignals(false); resize(800, 800); } /** * destructor. */ GuiCaretCommandDialog::~GuiCaretCommandDialog() { if (params != NULL) delete params; } /** * initialize to command. */ void GuiCaretCommandDialog::setSelectedCommand(const QString& commandSwitch) { const int numCommands = static_cast(caretCommands.size()); for (int i = 0; i < numCommands; i++) { if (caretCommands[i]->getOperationSwitch() == commandSwitch) { commandsListWidget->setCurrentRow(i); slotCommandListWidgetSelection(i); break; } } } /** * get add after button selected (if before/after). */ bool GuiCaretCommandDialog::getAddAfterWidget() const { bool addAfterFlag = false; if (addAfterRadioButton != NULL) { addAfterFlag = addAfterRadioButton->isChecked(); } return addAfterFlag; } /** * called when apply button is pressed. */ void GuiCaretCommandDialog::slotProcessCommandButton() { GuiCaretCommandWidget* guiCommandWidget = dynamic_cast(commandParametersStackedWidget->currentWidget()); if (guiCommandWidget != NULL) { QString errorMessage; QString commandSwitch; QString commandShortDescription; QStringList commandParameters; guiCommandWidget->getCommandLineForCommandExecution(commandSwitch, commandParameters, commandShortDescription, errorMessage); if (errorMessage.isEmpty() == false) { QMessageBox::critical(this, "ERROR", errorMessage); } else { commandParameters.insert(0, commandSwitch); const QString cmdText = caretCommandProgramName + " " + commandParameters.join(" "); const QString comment(guiCommandWidget->getComment()); if (DebugControl::getDebugOn()) { std::cout << "Comment: " << comment.toAscii().constData() << std::endl; std::cout << "Command: \"\"" << cmdText.toAscii().constData() << "\"\"" << std::endl; } // // Determine operations based upon mode // bool executeCommandFlag = true; // // Execute command ? // if (executeCommandFlag) { // // Too much text output may cause problems // const QString envVarName("CARET_DEBUG"); if (std::getenv(envVarName.toAscii().constData()) != NULL) { const QString msg = ("WARNING: The environment variable " + envVarName + " is on.\n" + "This may cause the caret_command program to hang if\n" + "there is too much printed output."); if (QMessageBox::question(this, "WARNING", msg, (QMessageBox::Ok | QMessageBox::Cancel)) != QMessageBox::Ok) { return; } } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); QString txt; if (DebugControl::getDebugOn()) { txt.append("Command \""); txt.append(caretCommandProgramName); if (commandParameters.isEmpty() == false) { txt.append(" "); txt.append(commandParameters.join(" ")); } txt.append("\"\n\n"); } // // Remove double quotes from any parameters // for (int m = 0; m < commandParameters.count(); m++) { // // Remove anything enclosed in double quotes unless // it contains a space // QString param = commandParameters[m]; if (param.startsWith("\"") && param.endsWith("\"")) { if (param.indexOf(" ") < 0) { const int len = param.length(); if (len >= 2) { param = param.mid(1, len - 2); commandParameters[m] = param; } } } } // // Run the program // BrainModelRunExternalProgram runProgram(caretCommandProgramName, commandParameters, true); try { runProgram.execute(); } catch (BrainModelAlgorithmException& /*e*/) { } txt.append(runProgram.getOutputText()); /* // // Create a new QProcess and add its arguments // QProcess process(this); // // Start execution of the command // process.start(caretCommandProgramName, commandParameters); if (!process.waitForStarted()) { QString msg("Error starting command: "); msg.append(caretCommandProgramName); QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", msg); return; } // // Wait until the program is complete // if (!process.waitForFinished(100000000)) { QString msg("Error waiting for command to finish: "); msg.append(caretCommandProgramName); QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", msg); return; } if (process.exitStatus() == QProcess::NormalExit) { if (process.exitCode() == 0) { txt.append("COMMAND SUCCESSFUL\n\n"); } else { executeErrorFlag = true; txt.append("COMMAND FAILED\n\n"); } } else { executeErrorFlag = true; txt.append("COMMAND FAILED\n\n"); } txt.append(process.readAll()); */ // // Display the results of the command // QtTextEditDialog* te = new QtTextEditDialog(this, true); te->setText(txt); te->show(); QApplication::beep(); QApplication::restoreOverrideCursor(); } } } } /** * called when a command is selected. */ void GuiCaretCommandDialog::slotCommandListWidgetSelection(int item) { // // Clear the selected command // selectedCommand = NULL; commandDescriptionTextEdit->setPlainText(""); // // Get the selected command // if ((item >= 0) && (item < static_cast(commandParametersStackedWidget->count()))) {\ if (caretCommandWidgets[item] == NULL) { caretCommandWidgets[item] = createCommandParametersWidget(caretCommands[item]); QWidget* w = commandParametersStackedWidget->widget(item); commandParametersStackedWidget->insertWidget(item, caretCommandWidgets[item]); delete w; } GuiCaretCommandWidget* guiCommandWidget = dynamic_cast(commandParametersStackedWidget->widget(item)); if (guiCommandWidget != NULL) { selectedCommand = guiCommandWidget->getCommand(); } if (selectedCommand != NULL) { // // Load the help information // const QString helpText = selectedCommand->getHelpInformation(); commandDescriptionTextEdit->setPlainText(helpText); // // Show the gui widget // commandParametersStackedWidget->setCurrentWidget(guiCommandWidget); } } // // Scroll to top of widget // commandParametersScrollArea->verticalScrollBar()->setSliderPosition(0); commandDescriptionTextEdit->verticalScrollBar()->setSliderPosition(0); } /** * create the command parameters widget. */ GuiCaretCommandWidget* GuiCaretCommandDialog::createCommandParametersWidget(CommandBase* command) { // // Get the commands parameters // ScriptBuilderParameters parameters; command->getScriptBuilderParameters(parameters); // // Add the parameters // /* const int numParams = parameters.getNumberOfParameters(); for (int i = 0; i < numParams; i++) { const ScriptBuilderParameters::Parameter* p = parameters.getParameter(i); std::cout << "Parameter: " << p->getDescription().toAscii().constData() << std::endl; } */ // // Create the command // bool showCommentEditor = false; switch (dialogMode) { case DIALOG_MODE_COMMAND_SELECTOR: case DIALOG_MODE_COMMAND_SELECTOR_WITH_BEFORE_AFTER: showCommentEditor = false; break; case DIALOG_MODE_EXECUTOR_NON_MODAL: showCommentEditor = false; break; } GuiCaretCommandWidget* guiCommand = new GuiCaretCommandWidget(command, showCommentEditor); return guiCommand; } /** * get the selected command (if command selector mode). */ QString GuiCaretCommandDialog::getSelectedCommandSwitch() const { QString switchOut; const int indx = commandsListWidget->currentRow(); if ((indx >= 0) && (indx < static_cast(caretCommands.size()))) { switchOut = caretCommands[indx]->getOperationSwitch(); } return switchOut; } caret-5.6.4~dfsg.1.orig/caret/GuiCaptureWindowImageDialog.h0000664000175000017500000001751211572067322023361 0ustar michaelmichael #ifndef __GUI_CAPTURE_WINDOW_IMAGE_DIALOG_H__ #define __GUI_CAPTURE_WINDOW_IMAGE_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModel.h" #include "WuQDialog.h" class GuiImageFormatComboBox; class QCheckBox; class QComboBox; class QLineEdit; class QPushButton; class QSpinBox; class QTabWidget; class WuQWidgetGroup; /// dialog for capturing images of caret windows class GuiCaptureWindowImageDialog : public WuQDialog { Q_OBJECT public: // constructor GuiCaptureWindowImageDialog(QWidget* parent); // destructor ~GuiCaptureWindowImageDialog(); // show the dialog virtual void show(); protected slots: // capture an image of the main window void slotCaptureImage(); // image file name selection void slotImageFileNameDialog(); // image capture type selected void slotWindowSelectionComboBox(int indx); // close the dialog void closeDialog(); // called when help button pressed void slotHelpPushButton(); protected: /// window to capture enum WINDOW { /// capture main window graphics area WINDOW_MAIN_GRAPHICS_AREA, /// capture part of main window graphics area using mouse WINDOW_MAIN_SELECT_PART_OF_GRAPHICS_AREA, /// capture viewing window 2 graphics area WINDOW_VIEWING_WINDOW_2_GRAPHICS_AREA, /// capture viewing window 3 graphics area WINDOW_VIEWING_WINDOW_3_GRAPHICS_AREA, /// capture viewing window 4 graphics area WINDOW_VIEWING_WINDOW_4_GRAPHICS_AREA, /// capture viewing window 5 graphics area WINDOW_VIEWING_WINDOW_5_GRAPHICS_AREA, /// capture viewing window 6 graphics area WINDOW_VIEWING_WINDOW_6_GRAPHICS_AREA, /// capture viewing window 7 graphics area WINDOW_VIEWING_WINDOW_7_GRAPHICS_AREA, /// capture viewing window 8 graphics area WINDOW_VIEWING_WINDOW_8_GRAPHICS_AREA, /// capture viewing window 9 graphics area WINDOW_VIEWING_WINDOW_9_GRAPHICS_AREA, /// capture viewing window 10 graphics area WINDOW_VIEWING_WINDOW_10_GRAPHICS_AREA, /// main window and open viewing window graphics areas WINDOW_MAIN_AND_OPEN_VIEWING_WINDOW_GRAPHICS, /// copy image from clipboard WINDOW_CLIPBOARD, /// capture image of desktop WINDOW_DESKTOP, /// capture display control dialog WINDOW_DISPLAY_CONTROL_DIALOG, /// capture draw border dialog WINDOW_DRAW_BORDER_DIALOG, /// capture identify dialog WINDOW_IDENTIFY_DIALOG, /// capture image capture dialog WINDOW_IMAGE_CAPTURE_DIALOG, /// main window including toolbar WINDOW_MAIN_WINDOW, /// main window toolbar WINDOW_MAIN_WINDOW_TOOLBAR, /// capture map stereotaxic focus dialog WINDOW_MAP_STEREOTAXIC_FOCUS_DIALOG, /// capture recording dialog WINDOW_RECORDING_DIALOG, /// capture study metadata editor dialog WINDOW_STUDY_METADATA_EDITOR_DIALOG, /// capture surface region of interest dialog WINDOW_SURFACE_REGION_OF_INTEREST_DIALOG, /// viewing window 2 including toolbar WINDOW_VIEWING_WINDOW_2, /// viewing window 2 toolbar WINDOW_VIEWING_WINDOW_2_TOOLBAR }; // create capture type group QWidget* createCaptureGroup(); // create capture options group QWidget* captureOptionsGroup(); // create image destination group QWidget* createImageDestinationGroup(); // create standard views group QWidget* createStandardViewsGroup(); // capture a normal image void captureNormalImage(); // capture images of standard view void captureStandardViewImages(); // capture an image of a viewing window (true if image valid) bool captureViewingWindowGraphicsArea(const BrainModel::BRAIN_MODEL_VIEW_NUMBER windowNumber, QImage& image); // load window selection combo box items void loadWindowSelectionComboBoxItems(); // capture image of a widget bool captureImageOfWidget(QWidget* w, QImage& image, const bool captureWidgetsWindowFlag); // capture image of main and viewing window graphics bool captureMainAndViewingWindowGraphics(QImage& image, const bool cropImagesFlag, const int cropMargin); // crop the image void cropImage(QImage& image, const int margin); /// capture push button QPushButton* capturePushButton; /// tab for std views vs image dest QTabWidget* tabWidget; /// combo box for window selection QComboBox* windowSelectionComboBox; /// multi image wrapping spin box QSpinBox* multiImageWrappingSpinBox; /// widget group for multi image wrapping widgets WuQWidgetGroup* multiImageWrappingWidgetGroup; /// capture and image destination group widget QWidget* captureAndDestinationWidget; /// standard view group widget QWidget* standardViewGroupWidget; /// copy to clipboard check box QCheckBox* copyToClipBoardCheckBox; /// add to spec file check box QCheckBox* addToSpecFileCheckBox; /// add to loaded images check box QCheckBox* addToLoadedImagesCheckBox; /// print image checkb box QCheckBox* printImageCheckBox; /// save to file check box QCheckBox* saveToFileCheckBox; /// save file name line edit QLineEdit* saveFileNameLineEdit; /// image format combo box GuiImageFormatComboBox* imageFormatComboBox; /// std view image file names line edit QLineEdit* medialViewLineEdit; /// std view image file names line edit QLineEdit* lateralViewLineEdit; /// std view image file names line edit QLineEdit* posteriorViewLineEdit; /// std view image file names line edit QLineEdit* anteriorViewLineEdit; /// std view image file names line edit QLineEdit* ventralViewLineEdit; /// std view image file names line edit QLineEdit* dorsalViewLineEdit; /// adjust captured image size check box QCheckBox* adjustCapturedImageSizeCheckBox; /// auto crop image check box QCheckBox* autoCropImageCheckBox; /// auto crop image margin spin box QSpinBox* autoCropImageMarginSpinBox; /// widget group for auto crop options WuQWidgetGroup* autoCropWidgetGroup; }; #endif // __GUI_CAPTURE_WINDOW_IMAGE_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiCaptureWindowImageDialog.cxx0000664000175000017500000013547011572067322023740 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 #include #include "BrainModelSurface.h" #include "BrainSet.h" #include "DebugControl.h" #include "FileUtilities.h" #include "GuiBrainModelOpenGL.h" #include "GuiBrainModelViewingWindow.h" #include "GuiCaptureWindowImageDialog.h" #include "GuiDisplayControlDialog.h" #include "GuiDrawBorderDialog.h" #include "GuiFilesModified.h" #include "GuiIdentifyDialog.h" #include "GuiImageResizeDialog.h" #include "GuiMainWindow.h" #include "GuiMapStereotaxicFocusDialog.h" #include "GuiImageFormatComboBox.h" #include "GuiRecordingDialog.h" #include "GuiStudyMetaDataFileEditorDialog.h" #include "GuiSurfaceRegionOfInterestDialog.h" #include "GuiToolBar.h" #include "ImageFile.h" #include "WuQFileDialog.h" #include "WuQWidgetGroup.h" #include "global_variables.h" /** * constructor. */ GuiCaptureWindowImageDialog::GuiCaptureWindowImageDialog(QWidget* parent) : WuQDialog(parent) { setWindowTitle("Capture Image of Window"); // // Create capture group // QWidget* captureTypeGroupWidget = createCaptureGroup(); // // Capture image options group // QWidget* captureOptionsGroupWidget = captureOptionsGroup(); // // Create the image destination group // QWidget*imageDestinationGroupWidget = createImageDestinationGroup(); // // Widget for capture and dest groups // captureAndDestinationWidget = new QWidget; QVBoxLayout* captureAndDestinationLayout = new QVBoxLayout(captureAndDestinationWidget); captureAndDestinationLayout->addWidget(captureTypeGroupWidget); captureAndDestinationLayout->addWidget(captureOptionsGroupWidget); captureAndDestinationLayout->addWidget(imageDestinationGroupWidget); // // Create standard views widget // standardViewGroupWidget = createStandardViewsGroup(); // // Tab widget for image dest vs std view // tabWidget = new QTabWidget; tabWidget->addTab(captureAndDestinationWidget, "Normal"); tabWidget->addTab(standardViewGroupWidget, "Standard Views"); // // Capture button // capturePushButton = new QPushButton("Capture"); capturePushButton->setAutoDefault(capturePushButton); QObject::connect(capturePushButton, SIGNAL(clicked()), this, SLOT(slotCaptureImage())); // // Help button // QPushButton* helpPushButton = new QPushButton("Help"); helpPushButton->setAutoDefault(helpPushButton); QObject::connect(helpPushButton, SIGNAL(clicked()), this, SLOT(slotHelpPushButton())); // // close button // QPushButton* closePushButton = new QPushButton("Close"); closePushButton->setAutoDefault(false); QObject::connect(closePushButton, SIGNAL(clicked()), this, SLOT(closeDialog())); // // Make buttons the same size // WuQWidgetGroup* buttonWidgetGroup = new WuQWidgetGroup(this); buttonWidgetGroup->addWidget(capturePushButton); buttonWidgetGroup->addWidget(helpPushButton); buttonWidgetGroup->addWidget(closePushButton); buttonWidgetGroup->resizeAllToLargestSizeHint(); // // Layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->addWidget(capturePushButton); buttonsLayout->addWidget(helpPushButton); buttonsLayout->addWidget(closePushButton); // // Layout for dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->addWidget(tabWidget); dialogLayout->addLayout(buttonsLayout); } /** * destructor. */ GuiCaptureWindowImageDialog::~GuiCaptureWindowImageDialog() { } /** * called when help button pressed. */ void GuiCaptureWindowImageDialog::slotHelpPushButton() { theMainWindow->showHelpViewerDialog("dialogs/capture_image_of_window_dialog.html"); } /** * load window selection combo box items. */ void GuiCaptureWindowImageDialog::loadWindowSelectionComboBoxItems() { windowSelectionComboBox->clear(); windowSelectionComboBox->addItem("Main Window Graphics Area", static_cast(WINDOW_MAIN_GRAPHICS_AREA)); windowSelectionComboBox->addItem("Select Part of Main Window Graphics Area With Mouse", static_cast(WINDOW_MAIN_SELECT_PART_OF_GRAPHICS_AREA)); windowSelectionComboBox->addItem("Viewing Window 2 Graphics Area", static_cast(WINDOW_VIEWING_WINDOW_2_GRAPHICS_AREA)); windowSelectionComboBox->addItem("Viewing Window 3 Graphics Area", static_cast(WINDOW_VIEWING_WINDOW_3_GRAPHICS_AREA)); windowSelectionComboBox->addItem("Viewing Window 4 Graphics Area", static_cast(WINDOW_VIEWING_WINDOW_4_GRAPHICS_AREA)); windowSelectionComboBox->addItem("Viewing Window 5 Graphics Area", static_cast(WINDOW_VIEWING_WINDOW_5_GRAPHICS_AREA)); windowSelectionComboBox->addItem("Viewing Window 6 Graphics Area", static_cast(WINDOW_VIEWING_WINDOW_6_GRAPHICS_AREA)); windowSelectionComboBox->addItem("Viewing Window 7 Graphics Area", static_cast(WINDOW_VIEWING_WINDOW_7_GRAPHICS_AREA)); windowSelectionComboBox->addItem("Viewing Window 8 Graphics Area", static_cast(WINDOW_VIEWING_WINDOW_8_GRAPHICS_AREA)); windowSelectionComboBox->addItem("Viewing Window 9 Graphics Area", static_cast(WINDOW_VIEWING_WINDOW_9_GRAPHICS_AREA)); windowSelectionComboBox->addItem("Viewing Window 10 Graphics Area", static_cast(WINDOW_VIEWING_WINDOW_10_GRAPHICS_AREA)); windowSelectionComboBox->addItem("Main Window and Open Viewing Window Graphics Areas", static_cast(WINDOW_MAIN_AND_OPEN_VIEWING_WINDOW_GRAPHICS)); windowSelectionComboBox->addItem("Clipboard", static_cast(WINDOW_CLIPBOARD)); windowSelectionComboBox->addItem("Desktop", static_cast(WINDOW_DESKTOP)); windowSelectionComboBox->addItem("Display Control Window", static_cast(WINDOW_DISPLAY_CONTROL_DIALOG)); windowSelectionComboBox->addItem("Draw Border Window", static_cast(WINDOW_DRAW_BORDER_DIALOG)); windowSelectionComboBox->addItem("Identify Window", static_cast(WINDOW_IDENTIFY_DIALOG)); windowSelectionComboBox->addItem("Image Capture Window", static_cast(WINDOW_IMAGE_CAPTURE_DIALOG)); windowSelectionComboBox->addItem("Main Window Including Toolbar", static_cast(WINDOW_MAIN_WINDOW)); windowSelectionComboBox->addItem("Main Window Toolbar", static_cast(WINDOW_MAIN_WINDOW_TOOLBAR)); windowSelectionComboBox->addItem("Map Stereotaxic Focus Window", static_cast(WINDOW_MAP_STEREOTAXIC_FOCUS_DIALOG)); windowSelectionComboBox->addItem("Recording Window", static_cast(WINDOW_RECORDING_DIALOG)); windowSelectionComboBox->addItem("Study Metadata Editor Window", static_cast(WINDOW_STUDY_METADATA_EDITOR_DIALOG)); windowSelectionComboBox->addItem("Surface Region of Interest Window", static_cast(WINDOW_SURFACE_REGION_OF_INTEREST_DIALOG)); windowSelectionComboBox->addItem("Viewing Window 2 Including Toolbar", static_cast(WINDOW_VIEWING_WINDOW_2)); windowSelectionComboBox->addItem("Viewing Window 2 Toolbar", static_cast(WINDOW_VIEWING_WINDOW_2_TOOLBAR)); } /** * create capture type group. */ QWidget* GuiCaptureWindowImageDialog::createCaptureGroup() { // // window selection combo box // windowSelectionComboBox = new QComboBox; loadWindowSelectionComboBoxItems(); windowSelectionComboBox->setToolTip( "Use this control to select the source of the\n" "captured image.\n" "\n" "When selecting part of the main window, move\n" "the mouse to one corner of the desired selection,\n" "hold down the left mouse button, drag the mouse\n" "to the opposite corner of the desired selection,\n" "and release the left mouse button.\n" "\n" "Images of most Caret dialogs and windows can be\n" "placed onto the computer's clipboard by using\n" "the context menu which is available by clicking\n" "the right mouse button (CONTROL-Mouse-Click on\n" "Mac OSX).\n" "\n" "NOTE: If capturing an image of a window, such as\n" "the Display Control or the Main Window and its\n" "Toolbar, make sure no other windows are obscuring\n" "the window being captured." ); QObject::connect(windowSelectionComboBox, SIGNAL(activated(int)), this, SLOT(slotWindowSelectionComboBox(int))); // // Wrapping for main and viewing window composite // QLabel* wrappingLabel = new QLabel(" Images Per Row "); multiImageWrappingSpinBox = new QSpinBox; multiImageWrappingSpinBox->setMinimum(1); multiImageWrappingSpinBox->setMaximum(10); multiImageWrappingSpinBox->setSingleStep(1); multiImageWrappingSpinBox->setValue(2); QHBoxLayout* wrappingLayout = new QHBoxLayout; wrappingLayout->addWidget(wrappingLabel); wrappingLayout->addWidget(multiImageWrappingSpinBox); wrappingLayout->addStretch(); multiImageWrappingWidgetGroup = new WuQWidgetGroup(this); multiImageWrappingWidgetGroup->addWidget(wrappingLabel); multiImageWrappingWidgetGroup->addWidget(multiImageWrappingSpinBox); // // Arrange image capture items // QGroupBox* capTypeGroupBox = new QGroupBox("Capture Image Of"); QVBoxLayout* captureTypeLayout = new QVBoxLayout(capTypeGroupBox); captureTypeLayout->addWidget(windowSelectionComboBox); captureTypeLayout->addLayout(wrappingLayout); return capTypeGroupBox; } /** * create capture options group. */ QWidget* GuiCaptureWindowImageDialog::captureOptionsGroup() { // // Adjust captured image size check box // adjustCapturedImageSizeCheckBox = new QCheckBox("Popup Dialog to Adjust Captured Image Size"); adjustCapturedImageSizeCheckBox->setToolTip( "Allow adjustment of the captured\n" "image prior to sending the image\n" "to its destination. If automatic \n" "cropping is selected, this operation\n" "is applied after the cropping."); adjustCapturedImageSizeCheckBox->setChecked(false); // // Auto crop check box // autoCropImageCheckBox = new QCheckBox("Automatically Crop Image"); autoCropImageCheckBox->setToolTip( "Remove background from around\n" "the sides of the image. This\n" "option is processed only if the\n" "catpured image is of the main\n" "or viewing window's graphics."); // // Auto crop margin spin box // autoCropImageMarginSpinBox = new QSpinBox; autoCropImageMarginSpinBox->setMinimum(0); autoCropImageMarginSpinBox->setMaximum(std::numeric_limits::max()); autoCropImageMarginSpinBox->setSingleStep(1); autoCropImageMarginSpinBox->setValue(10); QHBoxLayout* autoCropLayout = new QHBoxLayout; QLabel* maximumMarginLabel = new QLabel(" Margin"); autoCropLayout->addWidget(maximumMarginLabel); autoCropLayout->addWidget(autoCropImageMarginSpinBox); autoCropLayout->addStretch(); autoCropImageMarginSpinBox->setToolTip( "When autocropping, this number of pixels\n" "will remain on all sides of the object."); autoCropWidgetGroup = new WuQWidgetGroup(this); autoCropWidgetGroup->addWidget(autoCropImageCheckBox); autoCropWidgetGroup->addWidget(autoCropImageMarginSpinBox); autoCropWidgetGroup->addWidget(maximumMarginLabel); // // Enable margin spin box only if check box is checked // QObject::connect(autoCropImageCheckBox, SIGNAL(toggled(bool)), maximumMarginLabel, SLOT(setEnabled(bool))); QObject::connect(autoCropImageCheckBox, SIGNAL(toggled(bool)), autoCropImageMarginSpinBox, SLOT(setEnabled(bool))); autoCropImageCheckBox->setChecked(false); // // Arrange image capture items // QGroupBox* captureOptionsGroupBox = new QGroupBox("Capture Image Options"); QVBoxLayout* captureOptionsLayout = new QVBoxLayout(captureOptionsGroupBox); captureOptionsLayout->addWidget(autoCropImageCheckBox); captureOptionsLayout->addLayout(autoCropLayout); captureOptionsLayout->addWidget(adjustCapturedImageSizeCheckBox); return captureOptionsGroupBox; } /** * create image destination group. */ QWidget* GuiCaptureWindowImageDialog::createImageDestinationGroup() { // // image destination items // copyToClipBoardCheckBox = new QCheckBox("Copy to Clipboard"); addToSpecFileCheckBox = new QCheckBox("Add to Spec File"); addToSpecFileCheckBox->setChecked(true); addToLoadedImagesCheckBox = new QCheckBox("Add to Loaded Images"); printImageCheckBox = new QCheckBox("Print Image"); saveToFileCheckBox = new QCheckBox("Save to File"); saveFileNameLineEdit = new QLineEdit; saveFileNameLineEdit->setText("capture.jpg"); QPushButton* saveToFilePushButton = new QPushButton("Name..."); saveToFilePushButton->setAutoDefault(false); QObject::connect(saveToFilePushButton, SIGNAL(clicked()), this, SLOT(slotImageFileNameDialog())); QLabel* imageFormatLabel = new QLabel("Format"); imageFormatComboBox = new GuiImageFormatComboBox(GuiImageFormatComboBox::IMAGE_MODE_SAVE, GuiImageFormatComboBox::DISPLAY_IMAGE_FORMAT_NAMES); // // tooltips for image destination items // copyToClipBoardCheckBox->setToolTip( "Copy the image to the computer system's\n" "clipboard so that the image can be pasted\n" "into another program such as Photoshop or Word."); addToLoadedImagesCheckBox->setToolTip( "Copy the image to Caret's loaded images which\n" "can be viewed by selecting Image Viewing Window\n" "from the Window Menu."); printImageCheckBox->setToolTip( "Send the image to a printer."); saveToFileCheckBox->setToolTip( "Save the image to an image file."); // // Arrange file saving options // QGroupBox* fileSaveGroupBox = new QGroupBox("File Save Options"); QGridLayout* fileSaveGridLayout = new QGridLayout(fileSaveGroupBox); fileSaveGridLayout->addWidget(addToSpecFileCheckBox, 0, 1, 1, -1, Qt::AlignLeft); fileSaveGridLayout->addWidget(saveToFilePushButton, 1, 1, 1, 1); fileSaveGridLayout->addWidget(saveFileNameLineEdit, 1, 2, 1, 1); fileSaveGridLayout->addWidget(imageFormatLabel, 2, 1, 1, 1, Qt::AlignRight); fileSaveGridLayout->addWidget(imageFormatComboBox, 2, 2, 1, 1); QHBoxLayout* fileSaveLayout = new QHBoxLayout; fileSaveLayout->addWidget(new QLabel(" ")); fileSaveLayout->addWidget(fileSaveGroupBox); fileSaveLayout->addStretch(); // // Enabling of file save options // QObject::connect(saveToFileCheckBox, SIGNAL(toggled(bool)), fileSaveGroupBox, SLOT(setEnabled(bool))); saveToFileCheckBox->setChecked(false); fileSaveGroupBox->setEnabled(saveToFileCheckBox->isChecked()); // // Arrange image destination items // QGroupBox* imageDestGroupBox = new QGroupBox("Image Destination"); QVBoxLayout* imageDestinationLayout = new QVBoxLayout(imageDestGroupBox); imageDestinationLayout->addWidget(addToLoadedImagesCheckBox); imageDestinationLayout->addWidget(copyToClipBoardCheckBox); imageDestinationLayout->addWidget(printImageCheckBox); imageDestinationLayout->addWidget(saveToFileCheckBox); imageDestinationLayout->addLayout(fileSaveLayout); return imageDestGroupBox; } /** * create standard views group. */ QWidget* GuiCaptureWindowImageDialog::createStandardViewsGroup() { QLabel* medialLabel = new QLabel("Medial"); medialViewLineEdit = new QLineEdit; medialViewLineEdit->setText("medial.jpg"); QLabel* lateralLabel = new QLabel("Lateral"); lateralViewLineEdit = new QLineEdit; lateralViewLineEdit->setText("lateral.jpg"); QLabel* posteriorLabel = new QLabel("Posterior"); posteriorViewLineEdit = new QLineEdit; posteriorViewLineEdit->setText("posterior.jpg"); QLabel* anteriorLabel = new QLabel("Anterior"); anteriorViewLineEdit = new QLineEdit; anteriorViewLineEdit->setText("anterior.jpg"); QLabel* ventralLabel = new QLabel("Ventral"); ventralViewLineEdit = new QLineEdit; ventralViewLineEdit->setText("ventral.jpg"); QLabel* dorsalLabel = new QLabel("Dorsal"); dorsalViewLineEdit = new QLineEdit; dorsalViewLineEdit->setText("dorsal.jpg"); QGroupBox* stdViewGroupBox = new QGroupBox("Standard Views"); QGridLayout* stdViewGridLayout = new QGridLayout(stdViewGroupBox); stdViewGridLayout->addWidget(medialLabel, 0, 0); stdViewGridLayout->addWidget(medialViewLineEdit, 0, 1); stdViewGridLayout->addWidget(lateralLabel, 1, 0); stdViewGridLayout->addWidget(lateralViewLineEdit, 1, 1); stdViewGridLayout->addWidget(posteriorLabel, 2, 0); stdViewGridLayout->addWidget(posteriorViewLineEdit, 2, 1); stdViewGridLayout->addWidget(anteriorLabel, 3, 0); stdViewGridLayout->addWidget(anteriorViewLineEdit, 3, 1); stdViewGridLayout->addWidget(ventralLabel, 4, 0); stdViewGridLayout->addWidget(ventralViewLineEdit, 4, 1); stdViewGridLayout->addWidget(dorsalLabel, 5, 0); stdViewGridLayout->addWidget(dorsalViewLineEdit, 5, 1); stdViewGridLayout->setRowStretch(6, 100); return stdViewGroupBox; } /** * capture an image of the main window. */ void GuiCaptureWindowImageDialog::slotCaptureImage() { if (tabWidget->currentWidget() == captureAndDestinationWidget) { captureNormalImage(); } else { captureStandardViewImages(); } } /** * capture a normal image. */ void GuiCaptureWindowImageDialog::captureNormalImage() { if ((copyToClipBoardCheckBox->isChecked() == false) && (addToLoadedImagesCheckBox->isChecked() == false) && (printImageCheckBox->isChecked() == false) && (saveToFileCheckBox->isChecked() == false)) { QMessageBox::critical(this, "ERROR", "No Image Destination is selected."); return; } GuiBrainModelOpenGL* openGL = theMainWindow->getBrainModelOpenGL(); // // Get name for image file // const int imageQuality = 100; const QString format = imageFormatComboBox->getSelectedImageFormatName(); QString name = saveFileNameLineEdit->text(); if (name.isEmpty()) { if (saveToFileCheckBox->isChecked()) { QMessageBox::critical(this, "ERROR", "Image name is empty."); return; } } QString ext("."); ext.append(FileUtilities::filenameExtension(name)); if (ext != imageFormatComboBox->getSelectedImageFormatExtension()) { name.append(imageFormatComboBox->getSelectedImageFormatExtension()); } // // Get the window for selection // const int windowIndex = windowSelectionComboBox->currentIndex(); const WINDOW window = static_cast( windowSelectionComboBox->itemData(windowIndex).toInt()); // // Auto cropping is allowed for only some image capture windows // bool autoCroppingEnabledFlag = false; // // Capture the image // QImage image; switch (window) { case WINDOW_MAIN_GRAPHICS_AREA: openGL->captureImage(image); autoCroppingEnabledFlag = true; break; case WINDOW_MAIN_SELECT_PART_OF_GRAPHICS_AREA: if (openGL->getCaptureImageSubRegionValid() == false) { QMessageBox::critical(this, "ERROR", "No image region is selected.\n" "To select, move the mouse to one corner\n" "of the desired selection, hold down the left\n" "mouse button, drag the mouse to the opposite\n" "corner of the desired selection, and release\n" "the left mouse button."); return; } openGL->captureImageSubRegion(image); break; case WINDOW_VIEWING_WINDOW_2_GRAPHICS_AREA: case WINDOW_VIEWING_WINDOW_3_GRAPHICS_AREA: case WINDOW_VIEWING_WINDOW_4_GRAPHICS_AREA: case WINDOW_VIEWING_WINDOW_5_GRAPHICS_AREA: case WINDOW_VIEWING_WINDOW_6_GRAPHICS_AREA: case WINDOW_VIEWING_WINDOW_7_GRAPHICS_AREA: case WINDOW_VIEWING_WINDOW_8_GRAPHICS_AREA: case WINDOW_VIEWING_WINDOW_9_GRAPHICS_AREA: case WINDOW_VIEWING_WINDOW_10_GRAPHICS_AREA: { const int windowOffset = static_cast(window) - static_cast(WINDOW_VIEWING_WINDOW_2_GRAPHICS_AREA); const BrainModel::BRAIN_MODEL_VIEW_NUMBER windowNumber = static_cast( BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_2 + windowOffset); if (captureViewingWindowGraphicsArea(windowNumber, image) == false) { QMessageBox::critical(this, "ERROR", "Selected viewing window is not displayed."); return; } } autoCroppingEnabledFlag = true; break; case WINDOW_MAIN_AND_OPEN_VIEWING_WINDOW_GRAPHICS: captureMainAndViewingWindowGraphics(image, autoCropImageCheckBox->isChecked(), autoCropImageMarginSpinBox->value()); break; case WINDOW_CLIPBOARD: { QClipboard* clipboard = QApplication::clipboard(); image = clipboard->image(); if (image.isNull()) { QMessageBox::critical(this, "ERROR", "There is no image on the clipboard."); return; } } break; case WINDOW_DESKTOP: { // // Hide this dialog and wait // this->hide(); QApplication::processEvents(); QTime timer; timer.start(); const int maxTime = 1 * 1000; // milliseconds while (timer.elapsed() < maxTime); // // Redraw all caret windows // GuiBrainModelOpenGL::updateAllGL(); QApplication::processEvents(); // // Wait a little bit // QTime timer2; timer2.start(); while (timer2.elapsed() < maxTime); QApplication::processEvents(); // // Capture events // QString message; if (captureImageOfWidget(QApplication::desktop(), image, true) == false) { message = "Desktop window is not displayed."; } this->show(); if (message.isEmpty() == false) { QMessageBox::critical(this, "ERROR", message); } } break; case WINDOW_DISPLAY_CONTROL_DIALOG: if (captureImageOfWidget(theMainWindow->displayControlDialog, image, true) == false) { QMessageBox::critical(this, "ERROR", "Display Control window is not displayed."); return; } break; case WINDOW_DRAW_BORDER_DIALOG: if (captureImageOfWidget(theMainWindow->drawBorderDialog, image, true) == false) { QMessageBox::critical(this, "ERROR", "Draw Border window is not displayed."); return; } break; case WINDOW_IDENTIFY_DIALOG: if (captureImageOfWidget(theMainWindow->identifyDialog, image, true) == false) { QMessageBox::critical(this, "ERROR", "Identify window is not displayed."); return; } break; case WINDOW_IMAGE_CAPTURE_DIALOG: if (captureImageOfWidget(this, image, true) == false) { QMessageBox::critical(this, "ERROR", "Capture Image window is not displayed."); return; } break; case WINDOW_MAIN_WINDOW: if (captureImageOfWidget(theMainWindow, image, true) == false) { QMessageBox::critical(this, "ERROR", "Main Window is not displayed."); return; } break; case WINDOW_MAIN_WINDOW_TOOLBAR: if (captureImageOfWidget(theMainWindow->getToolBar(), image, false) == false) { QMessageBox::critical(this, "ERROR", "Main Window Toolbar is not displayed."); return; } break; case WINDOW_RECORDING_DIALOG: if (captureImageOfWidget(theMainWindow->recordingDialog, image, true) == false) { QMessageBox::critical(this, "ERROR", "Recording window is not displayed."); return; } break; case WINDOW_MAP_STEREOTAXIC_FOCUS_DIALOG: if (captureImageOfWidget(theMainWindow->mapStereotaxicFocusDialog, image, true) == false) { QMessageBox::critical(this, "ERROR", "Map Focus window is not displayed."); return; } break; case WINDOW_STUDY_METADATA_EDITOR_DIALOG: if (captureImageOfWidget(theMainWindow->studyMetaDataFileEditorDialog, image, true) == false) { QMessageBox::critical(this, "ERROR", "Study Metadata window is not displayed."); return; } break; case WINDOW_SURFACE_REGION_OF_INTEREST_DIALOG: if (captureImageOfWidget(theMainWindow->surfaceRegionOfInterestDialog, image, true) == false) { QMessageBox::critical(this, "ERROR", "Surface ROI window is not displayed."); return; } break; case WINDOW_VIEWING_WINDOW_2: if (captureImageOfWidget( theMainWindow->modelWindow[BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_2], image, true) == false) { QMessageBox::critical(this, "ERROR", "Viewing window 2 is not displayed."); return; } break; case WINDOW_VIEWING_WINDOW_2_TOOLBAR: { QWidget* w = NULL; if (theMainWindow->modelWindow[BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_2] != NULL) { w = theMainWindow->modelWindow[BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_2]->getToolBar(); } if (captureImageOfWidget(w, image, false) == false) { QMessageBox::critical(this, "ERROR", "Viewing Window 2 is not displayed."); return; } } break; } bool doCMYK = false; if (doCMYK) { for (int j = 0; j < image.height(); j++) { for (int i = 0; i < image.width(); i++) { QColor pixel = image.pixel(i, j); int r, g, b; pixel.getRgb(&r, &g, &b); int c = 255 - r; int m = 255 - g; int y = 255 - b; // pixel.setRgb(c, m, y); int k = std::min(c, std::min(m, y)); c = c - k; m = m - k; y = y - k; pixel.setRgb(c, m, y, k); image.setPixel(i, j, pixel.rgba()); } } } // // if auto cropping is selected // if (autoCropImageCheckBox->isChecked()) { if (autoCroppingEnabledFlag) { cropImage(image, autoCropImageMarginSpinBox->value()); } } // // Make adjustments to image size // if (adjustCapturedImageSizeCheckBox->isChecked()) { GuiImageResizeDialog resizeDialog(this, image); resizeDialog.exec(); } // // image file might be used // GuiFilesModified fm; ImageFile* img = NULL; // // should image be copied to the clipboard // if (copyToClipBoardCheckBox->isChecked()) { QApplication::clipboard()->setImage(image, QClipboard::Clipboard); } // // Should image be added to loaded images // if (addToLoadedImagesCheckBox->isChecked()) { img = new ImageFile(image); if (saveToFileCheckBox->isChecked()) { img->setFileName(name); } theMainWindow->getBrainSet(openGL->getModelViewNumber())->addImageFile(img); fm.setImagesModified(); } // // Should the image be printed // if (printImageCheckBox->isChecked()) { #ifdef Q_OS_WIN32 QTime timer; timer.start(); #endif // Q_OS_WIN32 QPrinter printer; QPrintDialog dialog(&printer, this); if (dialog.exec() == GuiCaptureWindowImageDialog::Accepted) { QPainter painter(&printer); painter.drawImage(0, 0, image); } #ifdef Q_OS_WIN32 if (timer.elapsed() < 2000) { QString msg = "If you did not see the Print Dialog, then printing\n" "will not work on your computer. This is a problem\n" "seen on Windows versions of Caret5 and there is no\n" "solution to this problem."; QMessageBox::critical(theMainWindow, "ERROR", msg); } #endif // Q_OS_WIN32 } // // Should image be saved to a file // if (saveToFileCheckBox->isChecked()) { // // Save the image // QImageWriter writer(name, format.toAscii()); if (writer.supportsOption(QImageIOHandler::Quality)) { if (format.compare("png", Qt::CaseInsensitive) == 0) { int qual = 1; writer.setQuality(qual); } else { writer.setQuality(imageQuality); } } if (writer.supportsOption(QImageIOHandler::CompressionRatio)) { writer.setCompression(1); } if (writer.write(image) == false) { //if (image.save(name, format.toAscii().constData(), imageQuality) == false) { QString msg("Unable to save: "); msg.append(name); QMessageBox::critical(this, "ERROR", msg); return; } // // Since image is saved to file image file is unmodified // if (img != NULL) { img->clearModified(); } // // Update spec file // if (addToSpecFileCheckBox->isChecked()) { theMainWindow->getBrainSet(openGL->getModelViewNumber())->addToSpecFile(SpecFile::getImageFileTag(), name); } } theMainWindow->fileModificationUpdate(fm); QMessageBox::information(capturePushButton, "Image Capture", "Image captured successfully."); } /** * crop the image. */ void GuiCaptureWindowImageDialog::cropImage(QImage& image, const int margin) { // // Get the background color // PreferencesFile* pf = theMainWindow->getBrainSet()->getPreferencesFile(); unsigned char r, g, b; pf->getSurfaceBackgroundColor(r, g, b); const int backgroundColor[3] = { r, g, b }; ImageFile::cropImageRemoveBackground(image, margin, backgroundColor); /* // // Get cropping bounds // int leftTopRightBottom[4]; ImageFile::findImageObject(image, backgroundColor, leftTopRightBottom); if (DebugControl::getDebugOn()) { std::cout << "cropping: " << leftTopRightBottom[0] << " " << leftTopRightBottom[1] << " " << leftTopRightBottom[2] << " " << leftTopRightBottom[3] << std::endl; } // // If cropping is valid // const int width = leftTopRightBottom[2] - leftTopRightBottom[0] + 1; const int height = leftTopRightBottom[3] - leftTopRightBottom[1] + 1; if ((width > 0) && (height > 0)) { image = image.copy(leftTopRightBottom[0], leftTopRightBottom[1], width, height); // // Process margin // if (margin > 0) { ImageFile::addMargin(image, margin, backgroundColor); // // Add margin // const int newWidth = width + margin * 2.0; const int newHeight = height + margin * 2.0; QRgb backgroundColorRGB = qRgba(r, g, b, 0); // // Insert image // ImageFile imageFile; imageFile.setImage(QImage(newWidth, newHeight, image.format())); imageFile.getImage()->fill(backgroundColorRGB); try { imageFile.insertImage(image, margin, margin); image = (*imageFile.getImage()); } catch (FileException&) { } } } */ } /** * capture image of main and viewing window graphics. */ bool GuiCaptureWindowImageDialog::captureMainAndViewingWindowGraphics(QImage& imageOut, const bool cropImagesFlag, const int cropMargin) { std::vector images; // // Capture images of all windows // for (int i = BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW; i < BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS; i++) { const BrainModel::BRAIN_MODEL_VIEW_NUMBER windowNumber = static_cast(i); if (i == BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) { QImage image; theMainWindow->getBrainModelOpenGL()->captureImage(image); images.push_back(image); } else { GuiBrainModelViewingWindow* viewWindow = theMainWindow->modelWindow[windowNumber]; if (viewWindow != NULL) { GuiBrainModelOpenGL* openGL = viewWindow->getBrainModelOpenGL(); QImage image; openGL->captureImage(image); images.push_back(image); } } } // // crop, if needed // const int numImages = static_cast(images.size()); for (int i = 0; i < numImages; i++) { // // Crop // if (cropImagesFlag) { cropImage(images[i], cropMargin); } } // // Get the background color // PreferencesFile* pf = theMainWindow->getBrainSet()->getPreferencesFile(); unsigned char r, g, b; pf->getSurfaceBackgroundColor(r, g, b); const int backgroundColor[3] = { r, g, b }; // // Combine all images into single image // ImageFile::combinePreservingAspectAndFillIfNeeded(images, multiImageWrappingSpinBox->value(), backgroundColor, imageOut); return true; } /** * capture image of a widget. */ bool GuiCaptureWindowImageDialog::captureImageOfWidget(QWidget* w, QImage& image, const bool captureWidgetsWindowFlag) { if (w != NULL) { if (captureWidgetsWindowFlag) { // // Try to pop up over all other windows since // QPixmap::grabWindow() does a screen capture. // QPixmap::grabWindow() is used because it will // get the entire window, including the operating // system unique frame. QPixmap::grabWidget() // gets only the widget without the window frame. // w->show(); w->activateWindow(); QApplication::processEvents(); image = QPixmap::grabWindow(w->winId()).toImage(); return true; //widget = w->window(); } image = QPixmap::grabWidget(w).toImage(); return true; } return false; } /** * capture an image of a viewing window (true if image valid). */ bool GuiCaptureWindowImageDialog::captureViewingWindowGraphicsArea( const BrainModel::BRAIN_MODEL_VIEW_NUMBER windowNumber, QImage& image) { GuiBrainModelViewingWindow* viewWindow = theMainWindow->modelWindow[windowNumber]; if (viewWindow != NULL) { GuiBrainModelOpenGL* openGL = viewWindow->getBrainModelOpenGL(); openGL->captureImage(image); return true; } return false; } /** * capture images of standard view. */ void GuiCaptureWindowImageDialog::captureStandardViewImages() { BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms == NULL) { QMessageBox::critical(this, "ERROR", "You must have a surface in the Main Window."); return; } const int imageQuality = 100; const QString format("jpg"); QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); GuiBrainModelOpenGL* openGL = theMainWindow->getBrainModelOpenGL(); QImage image; QString msg; // // Save view // bms->setToStandardView(BrainModelSurface::BRAIN_MODEL_VIEW_MAIN_WINDOW, BrainModelSurface::VIEW_MEDIAL); openGL->captureImage(image); if (image.save(medialViewLineEdit->text(), format.toAscii().constData(), imageQuality) == false) { msg.append(medialViewLineEdit->text()); } // // Save view // bms->setToStandardView(BrainModelSurface::BRAIN_MODEL_VIEW_MAIN_WINDOW, BrainModelSurface::VIEW_LATERAL); openGL->captureImage(image); if (image.save(lateralViewLineEdit->text(), format.toAscii().constData(), imageQuality) == false) { msg.append(lateralViewLineEdit->text()); } // // Save view // bms->setToStandardView(BrainModelSurface::BRAIN_MODEL_VIEW_MAIN_WINDOW, BrainModelSurface::VIEW_POSTERIOR); openGL->captureImage(image); if (image.save(posteriorViewLineEdit->text(), format.toAscii().constData(), imageQuality) == false) { msg.append(posteriorViewLineEdit->text()); } // // Save view // bms->setToStandardView(BrainModelSurface::BRAIN_MODEL_VIEW_MAIN_WINDOW, BrainModelSurface::VIEW_ANTERIOR); openGL->captureImage(image); if (image.save(anteriorViewLineEdit->text(), format.toAscii().constData(), imageQuality) == false) { msg.append(anteriorViewLineEdit->text()); } // // Save view // bms->setToStandardView(BrainModelSurface::BRAIN_MODEL_VIEW_MAIN_WINDOW, BrainModelSurface::VIEW_VENTRAL); openGL->captureImage(image); if (image.save(ventralViewLineEdit->text(), format.toAscii().constData(), imageQuality) == false) { msg.append(ventralViewLineEdit->text()); } // // Save view // bms->setToStandardView(BrainModelSurface::BRAIN_MODEL_VIEW_MAIN_WINDOW, BrainModelSurface::VIEW_DORSAL); openGL->captureImage(image); if (image.save(dorsalViewLineEdit->text(), format.toAscii().constData(), imageQuality) == false) { msg.append(dorsalViewLineEdit->text()); } QApplication::restoreOverrideCursor(); if (msg.isEmpty() == false) { QString msg2("Unable to save images: \n"); msg2.append(msg); QMessageBox::critical(this, "ERROR", msg2); return; } } /** * image file name selection. */ void GuiCaptureWindowImageDialog::slotImageFileNameDialog() { WuQFileDialog fd(this); fd.setWindowTitle("Image File Name"); fd.setModal(true); fd.setAcceptMode(WuQFileDialog::AcceptSave); fd.setFilters(imageFormatComboBox->getAllFileFilters()); fd.setDirectory(QDir::currentPath()); fd.setFileMode(WuQFileDialog::AnyFile); fd.selectFilter(imageFormatComboBox->getSelectedImageFormatFilter()); fd.selectFilter("(*.jpg)"); fd.selectFile(saveFileNameLineEdit->text()); if (fd.exec() == WuQFileDialog::Accepted) { QString fn(fd.selectedFiles().at(0)); if (FileUtilities::dirname(fn) == QDir::currentPath()) { saveFileNameLineEdit->setText(FileUtilities::basename(fn)); } else { saveFileNameLineEdit->setText(fn); } } } /** * close the dialog. */ void GuiCaptureWindowImageDialog::closeDialog() { GuiBrainModelOpenGL* openGL = theMainWindow->getBrainModelOpenGL(); if (openGL->getMouseMode() == GuiBrainModelOpenGL::MOUSE_MODE_IMAGE_SUBREGION) { openGL->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_VIEW); } WuQDialog::close(); } /** * show the dialog. */ void GuiCaptureWindowImageDialog::show() { slotWindowSelectionComboBox(windowSelectionComboBox->currentIndex()); WuQDialog::show(); } /** * image capture type selected. */ void GuiCaptureWindowImageDialog::slotWindowSelectionComboBox(int indx) { const WINDOW window = static_cast( windowSelectionComboBox->itemData(indx).toInt()); GuiBrainModelOpenGL* openGL = theMainWindow->getBrainModelOpenGL(); if (window == WINDOW_MAIN_SELECT_PART_OF_GRAPHICS_AREA) { openGL->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_IMAGE_SUBREGION); } else { if (openGL->getMouseMode() == GuiBrainModelOpenGL::MOUSE_MODE_IMAGE_SUBREGION) { openGL->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_VIEW); } } // // Enable options based upon window being captured // bool automaticCroppingEnabledFlag = false; bool multiImageWrappingEnabledFlag = false; switch (window) { case WINDOW_MAIN_GRAPHICS_AREA: automaticCroppingEnabledFlag = true; break; case WINDOW_MAIN_SELECT_PART_OF_GRAPHICS_AREA: break; case WINDOW_VIEWING_WINDOW_2_GRAPHICS_AREA: case WINDOW_VIEWING_WINDOW_3_GRAPHICS_AREA: case WINDOW_VIEWING_WINDOW_4_GRAPHICS_AREA: case WINDOW_VIEWING_WINDOW_5_GRAPHICS_AREA: case WINDOW_VIEWING_WINDOW_6_GRAPHICS_AREA: case WINDOW_VIEWING_WINDOW_7_GRAPHICS_AREA: case WINDOW_VIEWING_WINDOW_8_GRAPHICS_AREA: case WINDOW_VIEWING_WINDOW_9_GRAPHICS_AREA: case WINDOW_VIEWING_WINDOW_10_GRAPHICS_AREA: automaticCroppingEnabledFlag = true; break; case WINDOW_MAIN_AND_OPEN_VIEWING_WINDOW_GRAPHICS: automaticCroppingEnabledFlag = true; multiImageWrappingEnabledFlag = true; break; case WINDOW_CLIPBOARD: break; case WINDOW_DESKTOP: break; case WINDOW_DISPLAY_CONTROL_DIALOG: break; case WINDOW_DRAW_BORDER_DIALOG: break; case WINDOW_IDENTIFY_DIALOG: break; case WINDOW_IMAGE_CAPTURE_DIALOG: break; case WINDOW_MAIN_WINDOW: break; case WINDOW_MAIN_WINDOW_TOOLBAR: break; case WINDOW_MAP_STEREOTAXIC_FOCUS_DIALOG: break; case WINDOW_RECORDING_DIALOG: break; case WINDOW_STUDY_METADATA_EDITOR_DIALOG: break; case WINDOW_SURFACE_REGION_OF_INTEREST_DIALOG: break; case WINDOW_VIEWING_WINDOW_2: break; case WINDOW_VIEWING_WINDOW_2_TOOLBAR: break; } multiImageWrappingWidgetGroup->setEnabled(multiImageWrappingEnabledFlag); autoCropWidgetGroup->setEnabled(automaticCroppingEnabledFlag); autoCropImageCheckBox->setChecked(autoCropImageCheckBox->isChecked()); GuiBrainModelOpenGL::updateAllGL(); } caret-5.6.4~dfsg.1.orig/caret/GuiBrainSetAndModelSelectionControl.h0000664000175000017500000000467011572067322025026 0ustar michaelmichael #ifndef __GUI_BRAIN_SET_AND_MODEL_SELECTION_CONTROL_H__ #define __GUI_BRAIN_SET_AND_MODEL_SELECTION_CONTROL_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include class BrainSet; class BrainModel; /// this class encapsulates a control for selecting a brain set and model class GuiBrainSetAndModelSelectionControl : public QComboBox { Q_OBJECT public: // constructor GuiBrainSetAndModelSelectionControl(QWidget* parent = 0); // destructor ~GuiBrainSetAndModelSelectionControl(); // get the selected brain set BrainSet* getSelectedBrainSet(); // get the selected brain model BrainModel* getSelectedBrainModel(); /// see if all fiducial is selected bool getAllFiducialSelected() const { return ((currentIndex() == allFiducialIndex) && (allFiducialIndex >= 0)); } // update the control void updateControl(BrainSet* selectedBrain = NULL, BrainModel* selectedModel = NULL); protected: /// the brain sets for each selection std::vector theBrainSets; /// the brain models for each selection std::vector theBrainModels; /// the brain set for the first fiducial surface BrainSet* firstFiducialBrainSet; /// the brain model of the first fiducial surface BrainModel* firstFiducialModel; /// index of all fiducial surface(s) item int allFiducialIndex; }; #endif // __GUI_BRAIN_SET_AND_MODEL_SELECTION_CONTROL_H__ caret-5.6.4~dfsg.1.orig/caret/GuiBrainSetAndModelSelectionControl.cxx0000664000175000017500000001121611572067322025373 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModel.h" #include "BrainSet.h" #include "FileUtilities.h" #include "GuiBrainSetAndModelSelectionControl.h" #include "GuiMainWindow.h" #include "global_variables.h" /** * constructor. */ GuiBrainSetAndModelSelectionControl::GuiBrainSetAndModelSelectionControl(QWidget* parent) : QComboBox(parent) { firstFiducialBrainSet = NULL; firstFiducialModel = NULL; allFiducialIndex = -1; //updateControl(); } /** * destructor. */ GuiBrainSetAndModelSelectionControl::~GuiBrainSetAndModelSelectionControl() { } /** * get the selected brain set. */ BrainSet* GuiBrainSetAndModelSelectionControl::getSelectedBrainSet() { const int selItem = currentIndex(); if ((selItem >= 0) && (selItem < static_cast(theBrainSets.size()))) { return theBrainSets[selItem]; } return NULL; } /** * get the selected model. */ BrainModel* GuiBrainSetAndModelSelectionControl::getSelectedBrainModel() { const int selItem = currentIndex(); if ((selItem >= 0) && (selItem < static_cast(theBrainModels.size()))) { return theBrainModels[selItem]; } return NULL; } /** * update the control. */ void GuiBrainSetAndModelSelectionControl::updateControl(BrainSet* selectedBrain, BrainModel* selectedModel) { // // Save the current selection // BrainSet* currentBrainSet = getSelectedBrainSet(); BrainModel* currentBrainModel = getSelectedBrainModel(); if ((selectedBrain != NULL) && (selectedModel != NULL)) { currentBrainSet = selectedBrain; currentBrainModel = selectedModel; } // // clear out the control // bool allFiducialWasSelected = false; if (currentIndex() >= 0) { allFiducialWasSelected = (currentIndex() == allFiducialIndex); } clear(); theBrainSets.clear(); theBrainModels.clear(); firstFiducialBrainSet = NULL; firstFiducialModel = NULL; int fiducialCount = 0; allFiducialIndex = -1; // // When GUI is being constructed, "theMainWindow" will be NULL // if (theMainWindow == NULL) { return; } // // Get all of the loaded brain sets // std::vector allBrains; theMainWindow->getAllBrainSets(allBrains); // // Load up the control // const bool multipleBrainSetsFlag = (allBrains.size() > 1); int defaultIndex = 0; for (unsigned int i = 0; i < allBrains.size(); i++) { BrainSet* bs = allBrains[i]; const QString structAbbrevName = bs->getStructure().getTypeAsAbbreviatedString(); for (int j = 0; j < bs->getNumberOfBrainModels(); j++) { BrainModel* bm = bs->getBrainModel(j); theBrainSets.push_back(bs); theBrainModels.push_back(bm); QString name; if (multipleBrainSetsFlag) { name.append(structAbbrevName); name.append("-"); } name.append(bm->getDescriptiveName()); addItem(name); if ((bs == currentBrainSet) && (bm == currentBrainModel)) { defaultIndex = theBrainSets.size() - 1; } } // // Look for fiducial surfaces // if (bs->getActiveFiducialSurface() != NULL) { if (firstFiducialModel == NULL) { firstFiducialModel = bs->getActiveFiducialSurface(); firstFiducialBrainSet = bs; } fiducialCount++; } } if (fiducialCount > 1) { theBrainSets.push_back(firstFiducialBrainSet); theBrainModels.push_back(firstFiducialModel); addItem("ALL FIDUCIAL SURFACES"); allFiducialIndex = count() - 1; if (allFiducialWasSelected) { defaultIndex = allFiducialIndex; } } if (defaultIndex < count()) { setCurrentIndex(defaultIndex); } } caret-5.6.4~dfsg.1.orig/caret/GuiBrainModelViewingWindow.h0000664000175000017500000000627011572067322023237 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_BRAIN_VIEWING_WINDOW_H__ #define __GUI_BRAIN_VIEWING_WINDOW_H__ #include #include "WuQDialog.h" class GuiMainWindow; class GuiToolBar; #include "GuiBrainModelOpenGL.h" /// Main Window that is placed in the dialog to allow a toolbar class GuiBrainModelViewingMainWindow : public QMainWindow { Q_OBJECT public: /// Constructor GuiBrainModelViewingMainWindow(QWidget* parent, GuiMainWindow* caretMainWindow, const BrainModel::BRAIN_MODEL_VIEW_NUMBER svn, const char* name = 0); /// Destructor ~GuiBrainModelViewingMainWindow(); /// initialize the toolbar void initializeToolBar(); /// get the toolbar GuiToolBar* getToolBar() { return toolBar; } /// get the brain model OpenGL GuiBrainModelOpenGL* getBrainModelOpenGL() { return brainModelOpenGL; } private: /// the toolbar GuiToolBar* toolBar; /// OpenGL Renderer GuiBrainModelOpenGL* brainModelOpenGL; friend class GuiBrainModelViewingWindow; }; /// /// Dialog used to display additional brain models /// class GuiBrainModelViewingWindow : public WuQDialog { Q_OBJECT public: /// Constructor GuiBrainModelViewingWindow(QWidget* parent, GuiMainWindow* caretMainWindowIn, const BrainModel::BRAIN_MODEL_VIEW_NUMBER svn); /// Destructor ~GuiBrainModelViewingWindow(); /// initialize the toolbar void initializeToolBar(); /// display the brain model in the window void displayBrainModelInWindow(BrainModel* bm); /// Get the Brain Model OpenGL widget in the main window GuiBrainModelOpenGL* getBrainModelOpenGL() { return viewingMainWindow->brainModelOpenGL; } /// Get the toolbar GuiToolBar* getToolBar() { return viewingMainWindow->getToolBar(); } private: /// the viewing main window GuiBrainModelViewingMainWindow* viewingMainWindow; /// the caret main window in this dialog GuiMainWindow* mainWindow; /// the window number BrainModel::BRAIN_MODEL_VIEW_NUMBER windowNumber; }; #endif caret-5.6.4~dfsg.1.orig/caret/GuiBrainModelViewingWindow.cxx0000664000175000017500000001054011572067322023605 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainModel.h" #include "GuiBrainModelViewingWindow.h" #include "GuiMainWindow.h" #include "GuiToolBar.h" #include "global_variables.h" /** * Viewing Window Constructor. */ GuiBrainModelViewingMainWindow::GuiBrainModelViewingMainWindow(QWidget* /*parent*/, GuiMainWindow* mainWindowIn, const BrainModel::BRAIN_MODEL_VIEW_NUMBER svn, const char* /*name*/) : QMainWindow(0) { // // Create the openGL area // Pass the main window's OpenGL widget so that display lists are shared // brainModelOpenGL = new GuiBrainModelOpenGL(this, mainWindowIn->getBrainModelOpenGL(), "brainModelOpenGL", svn); setCentralWidget(brainModelOpenGL); // // Create the toolbar // toolBar = new GuiToolBar(this, mainWindowIn, brainModelOpenGL, svn); addToolBar(toolBar); } /** * Main Window Destructor. */ GuiBrainModelViewingMainWindow::~GuiBrainModelViewingMainWindow() { } /** * initialize the toolbar. Performed after window is created so that the toolbar * is created with a small model selection combo box that is expandable. */ void GuiBrainModelViewingMainWindow::initializeToolBar() { toolBar->loadModelComboBox(); toolBar->updateViewControls(); } /*--------------------------------------------------------------------------------------*/ /** * The Constructor. */ GuiBrainModelViewingWindow::GuiBrainModelViewingWindow(QWidget* parent, GuiMainWindow* caretMainWindowIn, const BrainModel::BRAIN_MODEL_VIEW_NUMBER svn) : WuQDialog(parent) { setAttribute(Qt::WA_DeleteOnClose); mainWindow = caretMainWindowIn; windowNumber = svn; setWindowTitle(QString("Viewing Window %1").arg(svn+1)); // // Layout for the dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setSpacing(5); // // Create the viewing main window in this dialog // viewingMainWindow = new GuiBrainModelViewingMainWindow(this, caretMainWindowIn, svn); this->resize(400, 300); viewingMainWindow->setMinimumSize(200, 200); dialogLayout->addWidget(viewingMainWindow); // // Close Button // QHBoxLayout* buttons = new QHBoxLayout; dialogLayout->addLayout(buttons); QPushButton* close = new QPushButton("Close", this); close->setAutoDefault(false); close->setFixedSize(close->sizeHint()); QObject::connect(close, SIGNAL(clicked()), this, SLOT(close())); buttons->addWidget(close); } /** * The Destructor. */ GuiBrainModelViewingWindow::~GuiBrainModelViewingWindow() { mainWindow->removeViewingWindow(windowNumber); } /** * initialize the toolbar. Performed after window is created so that the toolbar * is created with a small model selection combo box that is expandable. */ void GuiBrainModelViewingWindow::initializeToolBar() { viewingMainWindow->initializeToolBar(); } /** * display the brain model in the window. */ void GuiBrainModelViewingWindow::displayBrainModelInWindow(BrainModel* bm) { GuiToolBar* toolbar = viewingMainWindow->getToolBar(); if (toolbar != NULL) { toolbar->setModelSelection(bm->getBrainModelIndex()); } } caret-5.6.4~dfsg.1.orig/caret/GuiBrainModelSurfaceSelectionComboBox.h0000664000175000017500000000415011572067322025321 0ustar michaelmichael #ifndef __GUI_BRAIN_MODEL_SURFACE_SELECTION_COMBO_BOX_H__ #define __GUI_BRAIN_MODEL_SURFACE_SELECTION_COMBO_BOX_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainModelSurface.h" /// class for selecting a surface class GuiBrainModelSurfaceSelectionComboBox : public QComboBox { Q_OBJECT public: // constructor GuiBrainModelSurfaceSelectionComboBox( const BrainModelSurface::SURFACE_TYPES surfaceTypeIn); // constructor GuiBrainModelSurfaceSelectionComboBox( const std::vector surfaceTypesIn); // destructor ~GuiBrainModelSurfaceSelectionComboBox(); // get the selected surface BrainModelSurface* getSelectedBrainModelSurface(); // set the selected surface void setSelectedBrainModelSurface(const BrainModelSurface* bms); // update the combo box void updateComboBox(); protected: /// brain model surfaces in combo box std::vector brainModelSurfaces; /// surfaces types allowed in combo box std::vector allowedSurfaceTypes; }; #endif // __GUI_BRAIN_MODEL_SURFACE_SELECTION_COMBO_BOX_H__ caret-5.6.4~dfsg.1.orig/caret/GuiBrainModelSurfaceSelectionComboBox.cxx0000664000175000017500000000520511572067322025676 0ustar michaelmichael/* * GuiBrainModelSurfaceSelectionComboBox.cxx * caret * * Created by John Harwell on 8/28/08. * Copyright 2008 Washington University School of Medicine. All rights reserved. * */ #include #include "BrainSet.h" #include "GuiBrainModelSurfaceSelectionComboBox.h" #include "GuiMainWindow.h" #include "global_variables.h" /** * constructor. */ GuiBrainModelSurfaceSelectionComboBox::GuiBrainModelSurfaceSelectionComboBox( const BrainModelSurface::SURFACE_TYPES surfaceTypeIn) { allowedSurfaceTypes.push_back(surfaceTypeIn); updateComboBox(); } /** * constructor. */ GuiBrainModelSurfaceSelectionComboBox::GuiBrainModelSurfaceSelectionComboBox( const std::vector surfaceTypesIn) { allowedSurfaceTypes = surfaceTypesIn; updateComboBox(); } /** * destructor. */ GuiBrainModelSurfaceSelectionComboBox::~GuiBrainModelSurfaceSelectionComboBox() { } /** * get the selected surface. */ BrainModelSurface* GuiBrainModelSurfaceSelectionComboBox::getSelectedBrainModelSurface() { const int indx = currentIndex(); if ((indx >= 0) && (indx < static_cast(brainModelSurfaces.size()))) { return brainModelSurfaces[indx]; } return NULL; } /** * set the selected surface. */ void GuiBrainModelSurfaceSelectionComboBox::setSelectedBrainModelSurface(const BrainModelSurface* bms) { for (int i = 0; i < static_cast(brainModelSurfaces.size()); i++) { if (brainModelSurfaces[i] == bms) { setCurrentIndex(i); break; } } } /** * update the combo box. */ void GuiBrainModelSurfaceSelectionComboBox::updateComboBox() { blockSignals(true); BrainModelSurface* currentBMS = getSelectedBrainModelSurface(); brainModelSurfaces.clear(); clear(); int defaultIndex = 0; BrainSet* bs = theMainWindow->getBrainSet(); const int numBrainModels = bs->getNumberOfBrainModels(); for (int i = 0; i < numBrainModels; i++) { BrainModelSurface* bms = bs->getBrainModelSurface(i); if (bms != NULL) { const BrainModelSurface::SURFACE_TYPES surfaceType = bms->getSurfaceType(); if (std::find(allowedSurfaceTypes.begin(), allowedSurfaceTypes.end(), surfaceType) != allowedSurfaceTypes.end()) { if (bms == currentBMS) { defaultIndex = count(); } addItem(bms->getDescriptiveName()); brainModelSurfaces.push_back(bms); } } } if (defaultIndex < count()) { setCurrentIndex(defaultIndex); } blockSignals(false); } caret-5.6.4~dfsg.1.orig/caret/GuiBrainModelSelectionComboBox.h0000664000175000017500000001263611572067322024020 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_BRAIN_MODEL_SELECTION_COMBO_BOX_H__ #define __GUI_BRAIN_MODEL_SELECTION_COMBO_BOX_H__ #include #include #include "BrainModelSurface.h" #include "Structure.h" class BrainModel; class BrainModelContours; class BrainModelVolume; /// Combo box for selecting brain models class GuiBrainModelSelectionComboBox : public QComboBox { public: /// index for "addNewName" if it is not blank enum { ADD_NEW_INDEX = 1000000 }; /// options for creating selection combo box enum OPTIONS { /// show contours OPTION_SHOW_CONTOURS = 1, /// show all surfaces OPTION_SHOW_SURFACES_ALL = 2, /// show flat surfaces only OPTION_SHOW_SURFACES_FLAT = 4, /// show fiducial surfaces only OPTION_SHOW_SURFACES_FIDUCIAL = 8, /// show hull surfaces only OPTION_SHOW_SURFACES_HULL = 16, /// show volumes OPTION_SHOW_VOLUMES = 32, /// show "Add New" OPTION_SHOW_ADD_NEW = 64 }; /// Constructor GuiBrainModelSelectionComboBox(const int options, const QString& addNewNameIn = "", QWidget* parent = 0); /// Constructor GuiBrainModelSelectionComboBox(const bool showContoursIn, const bool showSurfacesIn, const bool showVolumesIn, const QString& addNewNameIn, QWidget* parent = 0, const char* name = 0, const bool flatSurfacesOnlyIn = false, const bool fiducialSurfacesOnlyIn = false, const bool hullSurfacesOnlyIn = false); /// Destructor ~GuiBrainModelSelectionComboBox(); /// limit surface to this structure void setSurfaceStructureRequirement(const Structure::STRUCTURE_TYPE limitToStructureIn); /// get the selected brain model BrainModel* getSelectedBrainModel() const; /// get the selected brain model contours BrainModelContours* getSelectedBrainModelContours() const; /// get the selected brain model surface BrainModelSurface* getSelectedBrainModelSurface() const; /// get the selected brain model volume BrainModelVolume* getSelectedBrainModelVolume() const; /// See if "add new" is the selected item bool getAddNewSelected() const; /// get the selected model index int getSelectedBrainModelIndex() const; /// set the selected brain model index void setSelectedBrainModelIndex(const int bmi); /// set the selected brain model void setSelectedBrainModel(const BrainModel* bm); /// set the selected brain model to the last surface of the specified type void setSelectedBrainModelToLastSurfaceOfType(const BrainModelSurface::SURFACE_TYPES st); /// set the selected brain model to the first surface of type and structure /// if structure type is invalid it is ignored void setSelectedBrainModelToFirstSurfaceOfType(const BrainModelSurface::SURFACE_TYPES surfaceType, const Structure::STRUCTURE_TYPE structureType = Structure::STRUCTURE_TYPE_INVALID); /// update the items in the combo box void updateComboBox(); private: /// converts combo box indices to brain model indices std::vector brainModelIndices; /// points to brain models in combo box std::vector brainModelPointers; /// index of the add new name int addNewIndex; /// show only this structure Structure::STRUCTURE_TYPE limitToStructure; /// contains contours bool showContours; /// contains surfaces bool showSurfaces; /// contains volumes bool showVolumes; /// name for add new QString addNewName; /// limit surfaces to flat surfaces bool flatSurfacesOnly; /// limit surface to fiducial surfaces bool fiducialSurfacesOnly; /// limit surface to hull surfaces bool hullSurfacesOnly; }; #endif // __GUI_BRAIN_MODEL_SELECTION_COMBO_BOX_H__ caret-5.6.4~dfsg.1.orig/caret/GuiBrainModelSelectionComboBox.cxx0000664000175000017500000003216711572067322024374 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelContours.h" #include "BrainModelVolume.h" #include "BrainSet.h" #include "GuiBrainModelSelectionComboBox.h" #include "GuiMainWindow.h" #include "global_variables.h" /** * Constructor. */ GuiBrainModelSelectionComboBox::GuiBrainModelSelectionComboBox(const int options, const QString& addNewNameIn, QWidget* parent) : QComboBox(parent) { showContours = (options & OPTION_SHOW_CONTOURS); showSurfaces = (options & OPTION_SHOW_SURFACES_ALL); showVolumes = (options & OPTION_SHOW_VOLUMES); if (options & OPTION_SHOW_ADD_NEW) { addNewName = addNewNameIn; } addNewIndex = -1; flatSurfacesOnly = (options & OPTION_SHOW_SURFACES_FLAT); fiducialSurfacesOnly = (options & OPTION_SHOW_SURFACES_FIDUCIAL); hullSurfacesOnly = (options & OPTION_SHOW_SURFACES_HULL); if (flatSurfacesOnly || fiducialSurfacesOnly || hullSurfacesOnly) { showSurfaces = true; } limitToStructure = Structure::STRUCTURE_TYPE_INVALID; updateComboBox(); } /** * Constructor. * If "addNewName" has 1 or more characters, it is added at the end of the combo box. */ GuiBrainModelSelectionComboBox::GuiBrainModelSelectionComboBox(const bool showContoursIn, const bool showSurfacesIn, const bool showVolumesIn, const QString& addNewNameIn, QWidget* parent, const char* name, const bool flatSurfacesOnlyIn, const bool fiducialSurfacesOnlyIn, const bool hullSurfacesOnlyIn) : QComboBox(parent) { setObjectName(name); showContours = showContoursIn; showSurfaces = showSurfacesIn; showVolumes = showVolumesIn; addNewName = addNewNameIn; addNewIndex = -1; flatSurfacesOnly = flatSurfacesOnlyIn; fiducialSurfacesOnly = fiducialSurfacesOnlyIn; hullSurfacesOnly = hullSurfacesOnlyIn; limitToStructure = Structure::STRUCTURE_TYPE_INVALID; updateComboBox(); } /** * Destructor */ GuiBrainModelSelectionComboBox::~GuiBrainModelSelectionComboBox() { } /** * limit surface to this structure. */ void GuiBrainModelSelectionComboBox::setSurfaceStructureRequirement(const Structure::STRUCTURE_TYPE limitToStructureIn) { limitToStructure = limitToStructureIn; } /** * Update the items in the combo box. */ void GuiBrainModelSelectionComboBox::updateComboBox() { // // Find out what is currently selected. // BrainModel* currentBrainModel = NULL; int defaultItemIndex = -1; if (getAddNewSelected()) { //defaultItemIndex = ADD_NEW_INDEX; } else { if (count() > 0) { currentBrainModel = brainModelPointers[currentIndex()]; } } // // clear the combo box and indices/pointers // clear(); brainModelIndices.clear(); brainModelPointers.clear(); BrainSet* brainSet = theMainWindow->getBrainSet(); if (brainSet == NULL) { return; } // // load models into the combo box // int firstValidModelIndex = -1; const int numModels = brainSet->getNumberOfBrainModels(); for (int i = 0; i < numModels; i++) { BrainModel* bm = brainSet->getBrainModel(i); bool useIt = false; switch(bm->getModelType()) { case BrainModel::BRAIN_MODEL_CONTOURS: useIt = showContours; break; case BrainModel::BRAIN_MODEL_SURFACE: useIt = showSurfaces; if (useIt) { const BrainModelSurface* bms = brainSet->getBrainModelSurface(i); if (flatSurfacesOnly) { if ((bms->getSurfaceType() != BrainModelSurface::SURFACE_TYPE_FLAT) && (bms->getSurfaceType() != BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR)) { useIt = false; } } if (fiducialSurfacesOnly) { if (bms->getSurfaceType() != BrainModelSurface::SURFACE_TYPE_FIDUCIAL) { useIt = false; } } if (hullSurfacesOnly) { if (bms->getSurfaceType() != BrainModelSurface::SURFACE_TYPE_HULL) { useIt = false; } } if (useIt) { switch (limitToStructure) { case Structure::STRUCTURE_TYPE_CORTEX_LEFT: if (bms->getStructure().getType() != Structure::STRUCTURE_TYPE_CORTEX_LEFT) { useIt = false; } break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT: if (bms->getStructure().getType() != Structure::STRUCTURE_TYPE_CORTEX_RIGHT) { useIt = false; } break; case Structure::STRUCTURE_TYPE_CORTEX_BOTH: break; case Structure::STRUCTURE_TYPE_CEREBELLUM: if (bms->getStructure().getType() != Structure::STRUCTURE_TYPE_CEREBELLUM) { useIt = false; } break; case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_LEFT: break; case Structure::STRUCTURE_TYPE_CEREBELLUM_OR_CORTEX_RIGHT: break; case Structure::STRUCTURE_TYPE_CORTEX_LEFT_OR_CEREBELLUM: break; case Structure::STRUCTURE_TYPE_CORTEX_RIGHT_OR_CEREBELLUM: break; case Structure::STRUCTURE_TYPE_CEREBRUM_CEREBELLUM: case Structure::STRUCTURE_TYPE_SUBCORTICAL: case Structure::STRUCTURE_TYPE_ALL: case Structure::STRUCTURE_TYPE_INVALID: break; } } } break; case BrainModel::BRAIN_MODEL_VOLUME: useIt = showVolumes; break; case BrainModel::BRAIN_MODEL_SURFACE_AND_VOLUME: break; } if (useIt) { if (bm == currentBrainModel) { defaultItemIndex = i; } if (firstValidModelIndex < 0) { firstValidModelIndex = i; } addItem(bm->getDescriptiveName()); brainModelIndices.push_back(i); brainModelPointers.push_back(bm); } } // // See if there is a default item // if (defaultItemIndex < 0) { if ((firstValidModelIndex >= 0) && (firstValidModelIndex < count())) { defaultItemIndex = firstValidModelIndex; } } // // Add the "Add New" selection if the add new name is not empty // addNewIndex = -1; if (addNewName.isEmpty() == false) { addNewIndex = count(); addItem(addNewName); brainModelIndices.push_back(ADD_NEW_INDEX); brainModelPointers.push_back(NULL); if (defaultItemIndex < 0) { defaultItemIndex = addNewIndex; } } // // Set to default item // setSelectedBrainModelIndex(defaultItemIndex); } /** * get the selected brain model index. * Returns -1 if there is no selection. * Returns ADD_NEW_INDEX if the addNewName was set in the constructor. */ int GuiBrainModelSelectionComboBox::getSelectedBrainModelIndex() const { if (count() > 0) { if (addNewIndex >= 0) { if (currentIndex() == addNewIndex) { return ADD_NEW_INDEX; } } return brainModelIndices[currentIndex()]; } return -1; } /** * See if "add new" is the selected item */ bool GuiBrainModelSelectionComboBox::getAddNewSelected() const { if (count() > 0) { if (addNewIndex >= 0) { if (currentIndex() == addNewIndex) { return true; } } } return false; } /** * get the selected brain model. */ BrainModel* GuiBrainModelSelectionComboBox::getSelectedBrainModel() const { const int index = getSelectedBrainModelIndex(); if (index == ADD_NEW_INDEX) { return NULL; } if (index >= 0) { return theMainWindow->getBrainSet()->getBrainModel(index); } return NULL; } /** * get the selected brain model contours */ BrainModelContours* GuiBrainModelSelectionComboBox::getSelectedBrainModelContours() const { BrainModel* bm = getSelectedBrainModel(); if (bm != NULL) { return dynamic_cast(bm); } return NULL; } /** * get the selected brain model surface */ BrainModelSurface* GuiBrainModelSelectionComboBox::getSelectedBrainModelSurface() const { BrainModel* bm = getSelectedBrainModel(); if (bm != NULL) { return dynamic_cast(bm); } return NULL; } /** * get the selected brain model volume */ BrainModelVolume* GuiBrainModelSelectionComboBox::getSelectedBrainModelVolume() const { BrainModel* bm = getSelectedBrainModel(); if (bm != NULL) { return dynamic_cast(bm); } return NULL; } /** * set the combo box to show the model with the specified index. * Pass ADD_NEW_INDEX to set the add new label. */ void GuiBrainModelSelectionComboBox::setSelectedBrainModelIndex(const int bmi) { if (bmi == ADD_NEW_INDEX) { setCurrentIndex(addNewIndex); } else { for (int i = 0; i < static_cast(brainModelIndices.size()); i++) { if (bmi == brainModelIndices[i]) { setCurrentIndex(i); break; } } } } /** * Set the selected brain model. */ void GuiBrainModelSelectionComboBox::setSelectedBrainModel(const BrainModel* bm) { for (int i = 0; i < static_cast(brainModelPointers.size()); i++) { if (brainModelPointers[i] == bm) { setCurrentIndex(i); } } } /** * set the selected brain model to the first surface of the specified type. */ void GuiBrainModelSelectionComboBox::setSelectedBrainModelToLastSurfaceOfType( const BrainModelSurface::SURFACE_TYPES st) { if (st == BrainModelSurface::SURFACE_TYPE_FIDUCIAL) { setSelectedBrainModel(theMainWindow->getBrainSet()->getActiveFiducialSurface()); } else { for (int i = (static_cast(brainModelIndices.size()) - 1); i >= 0; i--) { const int modelNumber = brainModelIndices[i]; BrainModel* bm = brainModelPointers[i]; if (bm->getModelType() == BrainModel::BRAIN_MODEL_SURFACE) { BrainModelSurface* bms = dynamic_cast(bm); if (bms->getSurfaceType() == st) { setSelectedBrainModelIndex(modelNumber); break; } } } } } /** * set the selected brain model to the first surface of type and structure. */ void GuiBrainModelSelectionComboBox::setSelectedBrainModelToFirstSurfaceOfType( const BrainModelSurface::SURFACE_TYPES surfaceType, const Structure::STRUCTURE_TYPE structureType) { for (int i = 0; i < static_cast(brainModelIndices.size()); i++) { const int modelNumber = brainModelIndices[i]; BrainModel* bm = brainModelPointers[i]; if (bm != NULL) { if (bm->getModelType() == BrainModel::BRAIN_MODEL_SURFACE) { BrainModelSurface* bms = dynamic_cast(bm); if (bms->getSurfaceType() == surfaceType) { if (structureType != Structure::STRUCTURE_TYPE_INVALID) { if (bms->getStructure().getType() == structureType) { setSelectedBrainModelIndex(modelNumber); break; } } else { setSelectedBrainModelIndex(modelNumber); break; } } } } } } caret-5.6.4~dfsg.1.orig/caret/GuiBrainModelOpenGLPopupMenu.h0000664000175000017500000001157411572067322023437 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_BRAIN_MODEL_OPENGL_POPUP_MENU_H__ #define __GUI_BRAIN_MODEL_OPENGL_POPUP_MENU_H__ #include #include #include "BrainModelOpenGLSelectedItem.h" #include "GuiBrainModelOpenGL.h" /// Menu popped up with right click in OpenGL widget class GuiBrainModelOpenGLPopupMenu : public QMenu { Q_OBJECT public: /// Constructor GuiBrainModelOpenGLPopupMenu(GuiBrainModelOpenGL* brainModelOpenGLIn); /// Destructor ~GuiBrainModelOpenGLPopupMenu(); /// set the selected items void setSelectedItems(const std::vector& itemsIn); private slots: /// caled for view mode void slotViewMode(); /// called for transformation axes void slotTransformationAxes(); /// called to remove ID symbols void slotClearIDSymbols(); /// called when this menu is about to popup void slotAboutToShow(); /// called to id a node void slotNodeID(); /// called when a border ID is selected void slotBorderID(); /// called when a border delete is selected void slotBorderDelete(); /// called when a border is projected void slotBorderProject(); /// called when a cell ID is selected void slotCellID(); /// called when a cell delete is selected void slotCellDelete(); /// called when a focus ID is selected void slotFocusID(); /// called when a focus delete is selected void slotFocusDelete(); /// called when focus edit is selected void slotFocusEdit(); /// called to show/not show borders void slotShowBorders(); /// called to show/not show cells void slotShowCells(); /// called to show/not show foci void slotShowFoci(); /// called to display a brain model void displayBrainModel(QAction* action); private: /// Create the brain model sub menu void createBrainModelSubMenu(); // create the mouse mode sub menu //void createMouseModeSubMenu(); /// create the color key sub menu void createColorKeySubMenu(); /// parent brain model opengl widget GuiBrainModelOpenGL* brainModelOpenGL; /// selected items std::vector selectedItems; /// selected node BrainModelOpenGLSelectedItem *selectedNode; /// selected border (first) BrainModelOpenGLSelectedItem *selectedBorder1; /// selected border (second) BrainModelOpenGLSelectedItem *selectedBorder2; /// selected cell BrainModelOpenGLSelectedItem *selectedCellProjection; /// selected cut BrainModelOpenGLSelectedItem *selectedCut; /// selected foci BrainModelOpenGLSelectedItem *selectedFocusProjection; /// selected palette metric BrainModelOpenGLSelectedItem *selectedPaletteMetric; /// selected palette shape BrainModelOpenGLSelectedItem *selectedPaletteShape; /// selected contour BrainModelOpenGLSelectedItem *selectedContour; /// selected contour cell BrainModelOpenGLSelectedItem *selectedContourCell; /// selected voxel underlay BrainModelOpenGLSelectedItem *selectedVoxelUnderlay; /// selected voxel overlay secondary BrainModelOpenGLSelectedItem *selectedVoxelOverlaySecondary; /// selected voxel overlay primary BrainModelOpenGLSelectedItem *selectedVoxelOverlayPrimary; /// selected voxel functiona cloud BrainModelOpenGLSelectedItem* selectedVoxelFunctionalCloud; /// selected transformation axes BrainModelOpenGLSelectedItem* selectedTransformationAxes; /// the brain model sub menu QMenu* brainModelSubMenu; }; #endif // __GUI_BRAIN_MODEL_OPENGL_POPUP_MENU_H__ caret-5.6.4~dfsg.1.orig/caret/GuiBrainModelOpenGLPopupMenu.cxx0000664000175000017500000006475311572067322024021 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "ArealEstimationFile.h" #include "BrainSet.h" #include "BrainModelBorderSet.h" #include "BrainModelContours.h" #include "BrainModelIdentification.h" #include "BrainModelSurface.h" #include "CellProjectionFile.h" #include "ContourCellFile.h" #include "CutsFile.h" #include "DisplaySettingsBorders.h" #include "DisplaySettingsCells.h" #include "DisplaySettingsContours.h" #include "DisplaySettingsCuts.h" #include "DisplaySettingsFoci.h" #include "DisplaySettingsSurface.h" #include "FociProjectionFile.h" #include "GuiBrainModelOpenGL.h" #include "GuiBrainModelOpenGLPopupMenu.h" #include "GuiIdentifyDialog.h" #include "GuiMainWindow.h" #include "GuiMainWindowLayersActions.h" #include "GuiMainWindowLayersMenu.h" #include "GuiMainWindowSurfaceActions.h" #include "GuiMapStereotaxicFocusDialog.h" #include "GuiMouseModePopupMenu.h" #include "GuiToolBar.h" #include "GuiSetViewDialog.h" #include "PaintFile.h" #include "ProbabilisticAtlasFile.h" #include "global_variables.h" /** * Constructor. */ GuiBrainModelOpenGLPopupMenu::GuiBrainModelOpenGLPopupMenu(GuiBrainModelOpenGL* brainModelOpenGLIn) : QMenu(0) { QObject::connect(this, SIGNAL(aboutToShow()), this, SLOT(slotAboutToShow())); brainModelOpenGL = brainModelOpenGLIn; selectedItems.clear(); //QT4setCheckable(true); setSelectedItems(selectedItems); } /** * Destructor. */ GuiBrainModelOpenGLPopupMenu::~GuiBrainModelOpenGLPopupMenu() { } /** * create the color key sub menu. */ void GuiBrainModelOpenGLPopupMenu::createColorKeySubMenu() { BrainSet* bs = brainModelOpenGL->getBrainSet(); const bool haveArealEst = (bs->getArealEstimationFile()->empty() == false); const bool haveBorders = (bs->getBorderSet()->getNumberOfBorders() > 0); const bool haveCells = (bs->getCellProjectionFile()->getNumberOfCellProjections() > 0); const bool haveFoci = (bs->getFociProjectionFile()->getNumberOfCellProjections() > 0); const bool havePaint = (bs->getPaintFile()->empty() == false); const bool haveProbAtlas = (bs->getProbabilisticAtlasSurfaceFile()->empty() == false); const bool havePaintVolume = (bs->getNumberOfVolumePaintFiles() > 0); const bool haveProbAtlasVolume = (bs->getNumberOfVolumeProbAtlasFiles() > 0); if (haveArealEst || haveBorders || haveCells || haveFoci || havePaint || haveProbAtlas || havePaintVolume || haveProbAtlasVolume) { QMenu* colorKeyMenu = addMenu("Color Keys"); if (haveArealEst) { colorKeyMenu->addAction("Areal Estimation", theMainWindow, SLOT(displayArealEstimationColorKey())); } if (haveBorders) { colorKeyMenu->addAction("Borders", theMainWindow, SLOT(displayBorderColorKey())); } if (haveCells) { colorKeyMenu->addAction("Cells", theMainWindow, SLOT(displayCellColorKey())); } if (haveFoci) { colorKeyMenu->addAction("Foci", theMainWindow, SLOT(displayFociColorKey())); } if (havePaint) { colorKeyMenu->addAction("Paint", theMainWindow, SLOT(displayPaintColorKey())); } if (haveProbAtlas) { colorKeyMenu->addAction("Probabilistic Atlas", theMainWindow, SLOT(displayProbabilisticAtlasColorKey())); } if (havePaintVolume) { colorKeyMenu->addAction("Volume Paint", theMainWindow, SLOT(displayVolumePaintColorKey())); } if (haveProbAtlasVolume) { colorKeyMenu->addAction("Volume Probabilistic Atlas", theMainWindow, SLOT(displayVolumeProbabilisticAtlasColorKey())); } } } /** * Create the brain model sub menu */ void GuiBrainModelOpenGLPopupMenu::createBrainModelSubMenu() { brainModelSubMenu = NULL; const int numModels = brainModelOpenGL->getBrainSet()->getNumberOfBrainModels(); if (numModels > 0) { brainModelSubMenu = addMenu("Show Brain Model"); QObject::connect(brainModelSubMenu, SIGNAL(triggered(QAction*)), this, SLOT(displayBrainModel(QAction*))); // // Insert view mode // for (int i = 0; i < numModels; i++) { const BrainModel* bm = brainModelOpenGL->getBrainSet()->getBrainModel(i); QAction* action = brainModelSubMenu->addAction(bm->getDescriptiveName()); action->setData(i); } } } /** * called to display a brain model. */ void GuiBrainModelOpenGLPopupMenu::displayBrainModel(QAction* action) { const int item = action->data().toInt(); if (item >= 0) { brainModelOpenGL->setDisplayedBrainModelIndex(item); // // Update the toolbars // GuiToolBar::updateAllToolBars(false); brainModelOpenGL->updateGL(); } } /** * Create the mouse mode sub menu. */ /* void GuiBrainModelOpenGLPopupMenu::createMouseModeSubMenu() { GuiMainWindowLayersActions* layersActions = theMainWindow->getLayersActions(); GuiMainWindowSurfaceActions* surfaceActions = theMainWindow->getSurfaceActions(); const BrainModelContours* contours = brainModelOpenGL->getDisplayedBrainModelContours(); const BrainModelSurface* surface = brainModelOpenGL->getDisplayedBrainModelSurface(); // const bool volumeDisplayed = (brainModelOpenGL->getDisplayedBrainModelVolume() != NULL); bool bordersDisplayed = false; bool cellsDisplayed = false; bool cutsDisplayed = false; bool fociDisplayed = false; BrainModelSurface::SURFACE_TYPES surfaceType = BrainModelSurface::SURFACE_TYPE_UNKNOWN; if (surface != NULL) { surfaceType = surface->getSurfaceType(); DisplaySettingsBorders* dsb = brainModelOpenGL->getBrainSet()->getDisplaySettingsBorders(); if (dsb->getDisplayBorders()) { BrainModelBorderSet* bmbs = brainModelOpenGL->getBrainSet()->getBorderSet(); BorderFile bf; bmbs->copyBordersToBorderFile(surface, bf); if (bf.getNumberOfBorders() > 0) { bordersDisplayed = true; } } DisplaySettingsCells* dsc = brainModelOpenGL->getBrainSet()->getDisplaySettingsCells(); if (dsc->getDisplayCells()) { const CellProjectionFile* cf = brainModelOpenGL->getBrainSet()->getCellProjectionFile(); if (cf != NULL) { if (cf->getNumberOfCellProjections() > 0) { cellsDisplayed = true; } } } DisplaySettingsFoci* dsf = brainModelOpenGL->getBrainSet()->getDisplaySettingsFoci(); if (dsf->getDisplayCells()) { const FociProjectionFile* ff = brainModelOpenGL->getBrainSet()->getFociProjectionFile(); if (ff != NULL) { if (ff->getNumberOfCellProjections()) { fociDisplayed = true; } } } DisplaySettingsCuts* dst = brainModelOpenGL->getBrainSet()->getDisplaySettingsCuts(); if (dst->getDisplayCuts()) { const CutsFile * cf = brainModelOpenGL->getBrainSet()->getCutsFile(); if (cf != NULL) { if (cf->getNumberOfBorders() > 0) { cutsDisplayed = true; } } } } QMenu* mouseMenu = addMenu("Set Mouse Mode"); // // Insert view mode // mouseMenu->addAction("View Mode", this, SLOT(slotViewMode())); // // Insert border items // if (surface != NULL) { mouseMenu->addSeparator(); mouseMenu->addAction(layersActions->getBordersDrawAction()); mouseMenu->addAction(layersActions->getBorderDrawUpdateAction()); if (bordersDisplayed) { mouseMenu->addAction(layersActions->getBordersDeleteWithMouseAction()); mouseMenu->addAction(layersActions->getBordersDeletePointWithMouseAction()); mouseMenu->addAction(layersActions->getBordersMovePointWithMouseAction()); mouseMenu->addAction(layersActions->getBordersRenameWithMouseAction()); mouseMenu->addAction(layersActions->getBordersReverseWithMouseAction()); } } // // Insert cell items // if (surface != NULL) { mouseMenu->addSeparator(); mouseMenu->addAction(layersActions->getCellsAddAction()); if (cellsDisplayed) { mouseMenu->addAction(layersActions->getCellsDeleteUsingMouseAction()); } } if (contours != NULL) { mouseMenu->addSeparator(); DisplaySettingsContours* dsc = brainModelOpenGL->getBrainSet()->getDisplaySettingsContours(); const ContourFile* cf = contours->getContourFile(); const ContourCellFile* cells = brainModelOpenGL->getBrainSet()->getContourCellFile(); mouseMenu->addAction(layersActions->getContourDrawAction()); if (cf->getNumberOfContours() > 0) { mouseMenu->addAction(layersActions->getContourDeleteAction()); mouseMenu->addAction(layersActions->getContourMergeAction()); mouseMenu->addAction(layersActions->getContourMovePointAction()); mouseMenu->addAction(layersActions->getContourDeletePointAction()); mouseMenu->addAction(layersActions->getContourReverseAction()); } mouseMenu->addAction(layersActions->getContourCellsAddAction()); if (cells != NULL) { if (cells->getNumberOfCells() > 0) { if (dsc->getDisplayContourCells()) { mouseMenu->addAction(layersActions->getContourCellsDeleteWithMouseAction()); mouseMenu->addAction(layersActions->getContourCellsMoveWithMouseAction()); } } } } // // Insert cut items // if (surface != NULL) { mouseMenu->addSeparator(); mouseMenu->addAction(surfaceActions->getCutsDrawAction()); if (cutsDisplayed) { mouseMenu->addAction(surfaceActions->getCutsDeleteWithMouseAction()); } } // // Insert foci items // if (fociDisplayed) { mouseMenu->addSeparator(); mouseMenu->addAction(layersActions->getFociDeleteUsingMouseAction()); } if (surface != NULL) { mouseMenu->addSeparator(); mouseMenu->addAction("Transformation Axes", this, SLOT(slotTransformationAxes())); } } */ /** * called for transformation axes. */ void GuiBrainModelOpenGLPopupMenu::slotTransformationAxes() { brainModelOpenGL->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_TRANSFORMATION_MATRIX_AXES); } /** * caled for view mode. */ void GuiBrainModelOpenGLPopupMenu::slotViewMode() { brainModelOpenGL->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_VIEW); } /** * Called when this menu is about to be popped up */ void GuiBrainModelOpenGLPopupMenu::slotAboutToShow() { clear(); GuiMainWindowLayersActions* layersActions = theMainWindow->getLayersActions(); // // Only main window gets mouse modes // if (brainModelOpenGL->isMainWindowOpenGL()) { //createMouseModeSubMenu(); QMenu* mouseMenu = new GuiMouseModePopupMenu(brainModelOpenGL, true, brainModelOpenGL); mouseMenu->setTitle("Mouse Mode"); addMenu(mouseMenu); } // // Create the brain model sub menu // createBrainModelSubMenu(); // // Color Keys // createColorKeySubMenu(); const BrainModelSurface* surface = brainModelOpenGL->getDisplayedBrainModelSurface(); addSeparator(); addAction("Clear Node ID Symbols", this, SLOT(slotClearIDSymbols())); addAction(layersActions->getBordersClearHighlightingAction()); addAction(layersActions->getFociClearHighlightingAction()); if (selectedNode != NULL) { addAction("Identify Node Under Mouse", this, SLOT(slotNodeID())); } if (selectedBorder1 != NULL) { addAction("Identify Border Under Mouse", this, SLOT(slotBorderID())); } if (selectedCellProjection != NULL) { addAction("Identify Cell Under Mouse", this, SLOT(slotCellID())); } if (selectedFocusProjection != NULL) { addAction("Identify Focus Under Mouse", this, SLOT(slotFocusID())); if (brainModelOpenGL->isMainWindowOpenGL()) { const BrainModelSurface* bms = brainModelOpenGL->getDisplayedBrainModelSurface(); if (bms != NULL) { if ((bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_RAW) || (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FIDUCIAL)) { addAction("Edit Focus Under Mouse", this, SLOT(slotFocusEdit())); } } } } if ((selectedBorder1 != NULL) || (selectedCellProjection != NULL) || (selectedFocusProjection != NULL)) { addSeparator(); if (selectedBorder1 != NULL) { addAction("Delete Border Under Mouse", this, SLOT(slotBorderDelete())); } if (selectedCellProjection != NULL) { addAction("Delete Cell Under Mouse", this, SLOT(slotCellDelete())); } if (selectedFocusProjection != NULL) { addAction("Delete Focus Under Mouse", this, SLOT(slotFocusDelete())); } } // // Project border under mouse // if (selectedBorder1 != NULL) { addSeparator(); addAction("Project Border Under Mouse", this, SLOT(slotBorderProject())); } // // Create the show submenu // if (surface != NULL) { bool addedMenuItem = false; BrainModelBorderSet* bmbs = brainModelOpenGL->getBrainSet()->getBorderSet(); if ((bmbs->getNumberOfBorders() > 0) || (brainModelOpenGL->getBrainSet()->getCellProjectionFile()->getNumberOfCellProjections() > 0) || (brainModelOpenGL->getBrainSet()->getFociProjectionFile()->getNumberOfCellProjections() > 0)) { addSeparator(); } if (bmbs->getNumberOfBorders() > 0) { QAction* borderAction = addAction("Show Borders", this, SLOT(slotShowBorders())); DisplaySettingsBorders* dsb = brainModelOpenGL->getBrainSet()->getDisplaySettingsBorders(); borderAction->setCheckable(true); borderAction->setChecked(dsb->getDisplayBorders()); addedMenuItem = true; } if (brainModelOpenGL->getBrainSet()->getCellProjectionFile()->getNumberOfCellProjections() > 0) { QAction* cellAction = addAction("Show Cells", this, SLOT(slotShowCells())); DisplaySettingsCells* dsc = brainModelOpenGL->getBrainSet()->getDisplaySettingsCells(); cellAction->setCheckable(true); cellAction->setChecked(dsc->getDisplayCells()); addedMenuItem = true; } if (brainModelOpenGL->getBrainSet()->getFociProjectionFile()->getNumberOfCellProjections() > 0) { QAction* fociAction = addAction("Show Foci", this, SLOT(slotShowFoci())); DisplaySettingsCells* dsc = brainModelOpenGL->getBrainSet()->getDisplaySettingsFoci(); fociAction->setCheckable(true); fociAction->setChecked(dsc->getDisplayCells()); addedMenuItem = true; } } } /** * called to remove ID symbols. */ void GuiBrainModelOpenGLPopupMenu::slotClearIDSymbols() { brainModelOpenGL->getBrainSet()->clearNodeHighlightSymbols(); GuiBrainModelOpenGL::updateAllGL(); } /** * Called when a border ID is selected. */ void GuiBrainModelOpenGLPopupMenu::slotBorderID() { if (selectedBorder1 != NULL) { BrainModelIdentification* bmi = brainModelOpenGL->getBrainSet()->getBrainModelIdentification(); const QString idString = bmi->getIdentificationTextForBorder(brainModelOpenGL->getOpenGLDrawing(), true, true); if (idString.isEmpty() == false) { GuiIdentifyDialog* id = theMainWindow->getIdentifyDialog(true); id->appendHtml(idString); } /* GuiIdentifyDialog* id = theMainWindow->getIdentifyDialog(true); id->displayBorder(*selectedBorder1, brainModelOpenGL->getModelViewNumber()); if (selectedBorder2 != NULL) { id->displayBorder(*selectedBorder2, brainModelOpenGL->getModelViewNumber()); } */ } } /** * Called when a border delete is selected. */ void GuiBrainModelOpenGLPopupMenu::slotBorderDelete() { if (selectedBorder1 != NULL) { BrainModelBorderSet* bmbs = brainModelOpenGL->getBrainSet()->getBorderSet(); bmbs->deleteBorder(selectedBorder1->getItemIndex2()); GuiBrainModelOpenGL::updateAllGL(); } } /** * called when a border is projected. */ void GuiBrainModelOpenGLPopupMenu::slotBorderProject() { if (selectedBorder1 != NULL) { BrainModelBorderSet* bmbs = brainModelOpenGL->getBrainSet()->getBorderSet(); BrainModelSurface* bms = brainModelOpenGL->getDisplayedBrainModelSurface(); bmbs->projectBorders(bms, true, selectedBorder1->getItemIndex2(), selectedBorder1->getItemIndex2()); GuiBrainModelOpenGL::updateAllGL(); } } /** * Called when a cell ID is selected. */ void GuiBrainModelOpenGLPopupMenu::slotCellID() { if (selectedCellProjection != NULL) { BrainModelIdentification* bmi = brainModelOpenGL->getBrainSet()->getBrainModelIdentification(); const QString idString = bmi->getIdentificationTextForCell(brainModelOpenGL->getOpenGLDrawing(), true, true); if (idString.isEmpty() == false) { GuiIdentifyDialog* id = theMainWindow->getIdentifyDialog(true); id->appendHtml(idString); } //GuiIdentifyDialog* id = theMainWindow->getIdentifyDialog(true); //id->displayCell(*selectedCellProjection, brainModelOpenGL->getModelViewNumber()); } } /** * Called when a cell delete is selected. */ void GuiBrainModelOpenGLPopupMenu::slotCellDelete() { if (selectedCellProjection != NULL) { brainModelOpenGL->getBrainSet()->deleteCell(selectedCellProjection->getItemIndex1()); GuiBrainModelOpenGL::updateAllGL(); } } /** * Called when a focus ID is selected. */ void GuiBrainModelOpenGLPopupMenu::slotFocusID() { if (selectedFocusProjection != NULL) { BrainModelIdentification* bmi = brainModelOpenGL->getBrainSet()->getBrainModelIdentification(); const QString idString = bmi->getIdentificationTextForFocus(brainModelOpenGL->getOpenGLDrawing(), true, true); if (idString.isEmpty() == false) { GuiIdentifyDialog* id = theMainWindow->getIdentifyDialog(true); id->appendHtml(idString); } //GuiIdentifyDialog* id = theMainWindow->getIdentifyDialog(true); //id->displayFocus(brainModelOpenGL->getDisplayedBrainModelSurface(), // *selectedFocusProjection, // brainModelOpenGL->getModelViewNumber()); } } /** * Called when a focus delete is selected. */ void GuiBrainModelOpenGLPopupMenu::slotFocusDelete() { if (selectedFocusProjection != NULL) { brainModelOpenGL->getBrainSet()->deleteFocus(selectedFocusProjection->getItemIndex1()); GuiBrainModelOpenGL::updateAllGL(); } } /** * Called when a focus edit is selected. */ void GuiBrainModelOpenGLPopupMenu::slotFocusEdit() { if (selectedFocusProjection != NULL) { GuiMapStereotaxicFocusDialog* sfd = theMainWindow->getMapStereotaxicFocusDialog(true); sfd->editFocus(selectedFocusProjection->getItemIndex1()); } } /** * Called to ID a node */ void GuiBrainModelOpenGLPopupMenu::slotNodeID() { if (selectedNode != NULL) { const int nodeNum = selectedNode->getItemIndex1(); if (nodeNum >= 0) { BrainSetNodeAttribute* bna = brainModelOpenGL->getBrainSet()->getNodeAttributes(nodeNum); if (bna->getHighlighting() == BrainSetNodeAttribute::HIGHLIGHT_NODE_NONE) { bna->setHighlighting(BrainSetNodeAttribute::HIGHLIGHT_NODE_LOCAL); //GuiIdentifyDialog* id = theMainWindow->getIdentifyDialog(true); //BrainModelSurface* surface = brainModelOpenGL->getDisplayedBrainModelSurface(); //id->displayNode(*selectedNode, brainModelOpenGL->getModelViewNumber(), surface); BrainModelIdentification* bmi = brainModelOpenGL->getBrainSet()->getBrainModelIdentification(); const QString idString = bmi->getIdentificationTextForNode(brainModelOpenGL->getOpenGLDrawing(), true, true); if (idString.isEmpty() == false) { GuiIdentifyDialog* id = theMainWindow->getIdentifyDialog(true); id->appendHtml(idString); } } else { bna->setHighlighting(BrainSetNodeAttribute::HIGHLIGHT_NODE_NONE); } brainModelOpenGL->getBrainSet()->clearAllDisplayLists(); } } GuiBrainModelOpenGL::updateAllGL(); } /** * called to show/not show borders. */ void GuiBrainModelOpenGLPopupMenu::slotShowBorders() { DisplaySettingsBorders* dsb = brainModelOpenGL->getBrainSet()->getDisplaySettingsBorders(); dsb->setDisplayBorders(! dsb->getDisplayBorders()); dsb->determineDisplayedBorders(); theMainWindow->updateDisplayControlDialog(); GuiBrainModelOpenGL::updateAllGL(); } /** * called to show/not show cells. */ void GuiBrainModelOpenGLPopupMenu::slotShowCells() { DisplaySettingsCells* dsc = brainModelOpenGL->getBrainSet()->getDisplaySettingsCells(); dsc->setDisplayCells(! dsc->getDisplayCells()); theMainWindow->updateDisplayControlDialog(); GuiBrainModelOpenGL::updateAllGL(); } /** * called to show/not show foci. */ void GuiBrainModelOpenGLPopupMenu::slotShowFoci() { DisplaySettingsCells* dsc = brainModelOpenGL->getBrainSet()->getDisplaySettingsFoci(); dsc->setDisplayCells(! dsc->getDisplayCells()); theMainWindow->updateDisplayControlDialog(); GuiBrainModelOpenGL::updateAllGL(); } /** * set the selected items. */ void GuiBrainModelOpenGLPopupMenu::setSelectedItems(const std::vector& itemsIn) { selectedItems = itemsIn; selectedNode = NULL; selectedBorder1 = NULL; selectedBorder2 = NULL; selectedCellProjection = NULL; selectedCut = NULL; selectedFocusProjection = NULL; selectedPaletteMetric = NULL; selectedPaletteShape = NULL; selectedContour = NULL; selectedContourCell = NULL; selectedVoxelUnderlay = NULL; selectedVoxelOverlaySecondary = NULL; selectedVoxelOverlayPrimary = NULL; selectedVoxelFunctionalCloud = NULL; selectedTransformationAxes = NULL; for (unsigned int i = 0; i < selectedItems.size(); i++) { switch (selectedItems[i].getItemType()) { case BrainModelOpenGLSelectedItem::ITEM_TYPE_NONE: break; case BrainModelOpenGLSelectedItem::ITEM_TYPE_TILE: break; case BrainModelOpenGLSelectedItem::ITEM_TYPE_LINK: break; case BrainModelOpenGLSelectedItem::ITEM_TYPE_NODE: selectedNode = &selectedItems[i]; break; case BrainModelOpenGLSelectedItem::ITEM_TYPE_BORDER: if (selectedBorder1 == NULL) { selectedBorder1 = &selectedItems[i]; } else if (selectedBorder2 == NULL) { selectedBorder2 = &selectedItems[i]; } break; case BrainModelOpenGLSelectedItem::ITEM_TYPE_VOLUME_BORDER: break; case BrainModelOpenGLSelectedItem::ITEM_TYPE_BORDER_PROJ: break; case BrainModelOpenGLSelectedItem::ITEM_TYPE_CELL_PROJECTION: selectedCellProjection = &selectedItems[i]; break; case BrainModelOpenGLSelectedItem::ITEM_TYPE_VOLUME_CELL: break; case BrainModelOpenGLSelectedItem::ITEM_TYPE_CONTOUR: selectedContour = &selectedItems[i]; break; case BrainModelOpenGLSelectedItem::ITEM_TYPE_CONTOUR_CELL: selectedContourCell = &selectedItems[i]; break; case BrainModelOpenGLSelectedItem::ITEM_TYPE_CUT: selectedCut = &selectedItems[i]; break; case BrainModelOpenGLSelectedItem::ITEM_TYPE_FOCUS_PROJECTION: selectedFocusProjection = &selectedItems[i]; break; case BrainModelOpenGLSelectedItem::ITEM_TYPE_VOLUME_FOCI: break; case BrainModelOpenGLSelectedItem::ITEM_TYPE_PALETTE_METRIC: selectedPaletteMetric = &selectedItems[i]; break; case BrainModelOpenGLSelectedItem::ITEM_TYPE_PALETTE_SHAPE: selectedPaletteShape = &selectedItems[i]; break; case BrainModelOpenGLSelectedItem::ITEM_TYPE_VOXEL_UNDERLAY: selectedVoxelUnderlay = &selectedItems[i]; break; case BrainModelOpenGLSelectedItem::ITEM_TYPE_VOXEL_OVERLAY_SECONDARY: selectedVoxelOverlaySecondary = &selectedItems[i]; break; case BrainModelOpenGLSelectedItem::ITEM_TYPE_VOXEL_OVERLAY_PRIMARY: selectedVoxelOverlayPrimary = &selectedItems[i]; break; case BrainModelOpenGLSelectedItem::ITEM_TYPE_VOXEL_FUNCTIONAL_CLOUD: selectedVoxelFunctionalCloud = &selectedItems[i]; break; case BrainModelOpenGLSelectedItem::ITEM_TYPE_TRANSFORMATION_MATRIX_AXES: selectedTransformationAxes = &selectedItems[i]; break; case BrainModelOpenGLSelectedItem::ITEM_TYPE_VTK_MODEL: break; case BrainModelOpenGLSelectedItem::ITEM_TYPE_TRANSFORM_CELL: break; case BrainModelOpenGLSelectedItem::ITEM_TYPE_TRANSFORM_FOCI: break; case BrainModelOpenGLSelectedItem::ITEM_TYPE_TRANSFORM_CONTOUR: break; case BrainModelOpenGLSelectedItem::ITEM_TYPE_TRANSFORM_CONTOUR_CELL: break; } } } caret-5.6.4~dfsg.1.orig/caret/GuiBrainModelOpenGLMouseEvent.h0000664000175000017500000000417211572067322023575 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_BRAIN_MODEL_OPENGL_MOUSE_EVENT_H__ #define __GUI_BRAIN_MODEL_OPENGL_MOUSE_EVENT_H__ /// Class contains information about a mouse event class GuiBrainModelOpenGLMouseEvent { public: /// event type (cannot use name "MOUSE_EVENT" because it is a MFC type) enum BMO_MOUSE_EVENT { MOUSE_LEFT_CLICK, MOUSE_LEFT_PRESS, MOUSE_LEFT_RELEASE, MOUSE_LEFT_SHIFT_PRESS, MOUSE_LEFT_CONTROL_PRESS, MOUSE_LEFT_MOVE, MOUSE_LEFT_SHIFT_MOVE, MOUSE_LEFT_CONTROL_MOVE, MOUSE_LEFT_ALT_MOVE }; /// Constructor GuiBrainModelOpenGLMouseEvent(const BMO_MOUSE_EVENT me, const int mx, const int my, const int dx, const int dy); /// Destructor ~GuiBrainModelOpenGLMouseEvent(); /// the mouse event BMO_MOUSE_EVENT event; /// current mouse X position int x; /// current mouse Y position int y; /// change in mouse X position int dx; /// change in mouse Y position int dy; }; #endif // __GUI_BRAIN_MODEL_OPENGL_MOUSE_EVENT_H__ caret-5.6.4~dfsg.1.orig/caret/GuiBrainModelOpenGLMouseEvent.cxx0000664000175000017500000000301311572067322024141 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "GuiBrainModelOpenGLMouseEvent.h" /** * Constructor. */ GuiBrainModelOpenGLMouseEvent::GuiBrainModelOpenGLMouseEvent(const BMO_MOUSE_EVENT mouseEvent, const int mouseX, const int mouseY, const int deltaX, const int deltaY) { event = mouseEvent; x = mouseX; y = mouseY; dx = deltaX; dy = deltaY; } /** * Destructor. */ GuiBrainModelOpenGLMouseEvent::~GuiBrainModelOpenGLMouseEvent() { } caret-5.6.4~dfsg.1.orig/caret/GuiBrainModelOpenGLKeyEvent.h0000664000175000017500000000377111572067322023241 0ustar michaelmichael #ifndef __GUI_BRAIN_MODEL_OPENGL_KEY_EVENT_H__ #define __GUI_BRAIN_MODEL_OPENGL_KEY_EVENT_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ /// class for processing a key event class GuiBrainModelOpenGLKeyEvent { public: /// Constructor GuiBrainModelOpenGLKeyEvent(const int keyIn, const bool shiftKeyDownIn, const bool altKeyDownIn, const bool controlKeyDownIn); /// Destructor ~GuiBrainModelOpenGLKeyEvent(); /// debug print void debug() const; /// set the key event has been used void setKeyEventUsed(const bool b) { keyEventUsed = b; } /// get the key event has been used bool getKeyEventUsed() const { return keyEventUsed; } /// the key code int key; /// shift key is down flag bool shiftKeyDown; /// alt key is down flag bool altKeyDown; /// control key is down bool controlKeyDown; /// ke event used flag bool keyEventUsed; }; #endif // __GUI_BRAIN_MODEL_OPENGL_KEY_EVENT_H__ caret-5.6.4~dfsg.1.orig/caret/GuiBrainModelOpenGLKeyEvent.cxx0000664000175000017500000000407311572067322023610 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include "DebugControl.h" #include "GuiBrainModelOpenGLKeyEvent.h" /** * Constructor. */ GuiBrainModelOpenGLKeyEvent::GuiBrainModelOpenGLKeyEvent(const int keyIn, const bool shiftKeyDownIn, const bool altKeyDownIn, const bool controlKeyDownIn) { key = keyIn; shiftKeyDown = shiftKeyDownIn; altKeyDown = altKeyDownIn; controlKeyDown = controlKeyDownIn; keyEventUsed = false; } /** * debug print. */ void GuiBrainModelOpenGLKeyEvent::debug() const { if (DebugControl::getDebugOn()) { std::cout << "Key Event: " << std::endl; std::cout << " Key: " << key << " "; //std::cout.setf(std::ios::hex); std::cout << std::hex << key << std::dec << std::endl; //std::cout.setf(std::ios::dec); std::cout << " Shift: " << shiftKeyDown << std::endl; std::cout << " Control: " << controlKeyDown << std::endl; std::cout << " Alt: " << altKeyDown << std::endl; std::cout << " Used: " << keyEventUsed << std::endl; } } /** * Destructor. */ GuiBrainModelOpenGLKeyEvent::~GuiBrainModelOpenGLKeyEvent() { } caret-5.6.4~dfsg.1.orig/caret/GuiBrainModelOpenGL.h0000664000175000017500000006567611572067322021602 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_GUI_BRAIN_SURFACE_OPENGL_H__ #define __VE_GUI_BRAIN_SURFACE_OPENGL_H__ #include #include #include "BrainModelOpenGL.h" #include "BrainModelVolume.h" class BrainModel; class BrainModelContours; class BrainModelSurface; class BrainModelSurfaceAndVolume; class BrainModelSurfaceNodeColoring; class BrainModelVolume; class CellFile; class ColorFile; class CoordinateFile; class DisplaySettingsCells; class GuiBrainModelOpenGLPopupMenu; class GuiBrainSetAndModelSelectionControl; class TopologyFile; class GuiBrainModelOpenGLKeyEvent; class GuiBrainModelOpenGLMouseEvent; /// OpenGL widget for surface display class GuiBrainModelOpenGL : public QGLWidget { Q_OBJECT public: /// Rotation axis enums. enum BRAIN_MODEL_ROTATION_AXIS { BRAIN_MODEL_ROTATION_AXIS_X, BRAIN_MODEL_ROTATION_AXIS_Y, BRAIN_MODEL_ROTATION_AXIS_Z, BRAIN_MODEL_ROTATION_AXIS_XY, BRAIN_MODEL_ROTATION_AXIS_OFF }; /// caret mouse modes enum MOUSE_MODES { MOUSE_MODE_NONE, MOUSE_MODE_VIEW, MOUSE_MODE_BORDER_DRAW, MOUSE_MODE_BORDER_DRAW_NEW, MOUSE_MODE_BORDER_DELETE, MOUSE_MODE_BORDER_DELETE_POINT, MOUSE_MODE_BORDER_INTERPOLATE, MOUSE_MODE_BORDER_INTERPOLATE_NEW, MOUSE_MODE_BORDER_MOVE_POINT, MOUSE_MODE_BORDER_REVERSE, MOUSE_MODE_BORDER_RENAME, MOUSE_MODE_BORDER_UPDATE, MOUSE_MODE_BORDER_UPDATE_NEW, MOUSE_MODE_CUT_DRAW, MOUSE_MODE_CUT_DELETE, MOUSE_MODE_FOCI_DELETE, MOUSE_MODE_CELL_ADD, MOUSE_MODE_CELL_DELETE, MOUSE_MODE_SURFACE_ROI_BORDER_SELECT, MOUSE_MODE_SURFACE_ROI_PAINT_INDEX_SELECT, MOUSE_MODE_SURFACE_ROI_METRIC_NODE_SELECT, MOUSE_MODE_SURFACE_ROI_GEODESIC_NODE_SELECT, MOUSE_MODE_ALIGN_STANDARD_ORIENTATION, MOUSE_MODE_ALIGN_STANDARD_ORIENTATION_FULL_HEM_FLATTEN, MOUSE_MODE_CONTOUR_SET_SCALE, MOUSE_MODE_CONTOUR_DRAW, MOUSE_MODE_CONTOUR_ALIGN, MOUSE_MODE_CONTOUR_ALIGN_REGION, MOUSE_MODE_CONTOUR_POINT_MOVE, MOUSE_MODE_CONTOUR_POINT_DELETE, MOUSE_MODE_CONTOUR_DELETE, MOUSE_MODE_CONTOUR_REVERSE, MOUSE_MODE_CONTOUR_MERGE, MOUSE_MODE_CONTOUR_CELL_ADD, MOUSE_MODE_CONTOUR_CELL_DELETE, MOUSE_MODE_CONTOUR_CELL_MOVE, MOUSE_MODE_VOLUME_SEGMENTATION_EDIT, MOUSE_MODE_EDIT_ADD_NODE, MOUSE_MODE_EDIT_ADD_TILE, MOUSE_MODE_EDIT_DELETE_TILE_BY_LINK, MOUSE_MODE_EDIT_DISCONNECT_NODE, MOUSE_MODE_EDIT_MOVE_NODE, MOUSE_MODE_SURFACE_ROI_SHAPE_NODE_SELECT, MOUSE_MODE_TRANSFORMATION_MATRIX_AXES, MOUSE_MODE_TRANSFORMATION_MATRIX_SET_TRANSLATE, MOUSE_MODE_VOLUME_PAINT_EDIT, MOUSE_MODE_IMAGE_SUBREGION, MOUSE_MODE_SURFACE_ROI_SULCAL_BORDER_NODE_START, MOUSE_MODE_SURFACE_ROI_SULCAL_BORDER_NODE_END }; /// Constructor GuiBrainModelOpenGL(QWidget* parent, GuiBrainModelOpenGL* sharedBrainModelOpenGL, const char* name, const BrainModel::BRAIN_MODEL_VIEW_NUMBER svn); /// Destructor ~GuiBrainModelOpenGL(); /// is this the main windows OpenGL widget bool isMainWindowOpenGL() const { return (viewingWindowIndex == BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW); } /// Get the surface/volume viewing index BrainModel::BRAIN_MODEL_VIEW_NUMBER getModelViewNumber() const { return viewingWindowIndex; } /// reset the linear object being drawn (border, contour, cut) void resetLinearObjectBeingDrawn(); /// get the mouse mode MOUSE_MODES getMouseMode() const { return mouseMode; } /// set the mouse mode void setMouseMode(const MOUSE_MODES mm); /// save the graphics window into the image file. /// returns true if an error occurs. bool saveImage(const QString& name, const QString& format, const bool addToSpecFile); /// Capture an image of the current graphics. void captureImage(QImage& image); /// Capture a portion of the image of the current graphics. void captureImageSubRegion(QImage& image); /// get image sub region valid bool getCaptureImageSubRegionValid() const; /// get the yoke status for this window bool getYokeView() const { return yokeView; } /// set the yoke status for this window void setYokeView(const bool yoke) { yokeView = yoke; } /// get the rotation axis BRAIN_MODEL_ROTATION_AXIS getRotationAxis() const { return rotationAxis; } /// set the rotation axis void setRotationAxis(const BRAIN_MODEL_ROTATION_AXIS axis) { rotationAxis = axis; } /// Update all graphics windows. When modelToUpdate is NULL all OpenGL /// windows are updated. If it is not NULL, the specified window and all /// windows "yoked" to it are updated. static void updateAllGL(GuiBrainModelOpenGL *modelToUpdate = NULL); /// get the minimum and maximum point size static void getPointSizeRange(float& minSize, float& maxSize); /// get the minimum and maximum line width static void getLineWidthRange(float& minSize, float& maxSize); /// get caption displayed in main window static QString getMainWindowCaption(); /// set caption displayed in main window static void setMainWindowCaption(const QString& s); /// Get the displayed brain model index int getDisplayedBrainModelIndex() const; /// Get the orthographic projection box extents void getOrthographicBox(double& orthoLeft, double& orthoRight, double& orthoBottom, double& orthoTop, double& orthoNear, double& orthoFar) const; /// Get the brain set for this OpenGL Widget BrainSet* getBrainSet(); /// Get the displayed brain model BrainModel* getDisplayedBrainModel(); /// Get the displayed brain model contours (returns NULL if a surface is not displayed) BrainModelContours* getDisplayedBrainModelContours(); /// Get the displayed brain model surface (returns NULL if a surface is not displayed) BrainModelSurface* getDisplayedBrainModelSurface(); /// Get the displayed brain model surface and volume (returns NULL if a surface is not displayed) BrainModelSurfaceAndVolume* getDisplayedBrainModelSurfaceAndVolume(); /// Get the displayed brain model volume (returns NULL if a volume is not displayed) BrainModelVolume* getDisplayedBrainModelVolume(); /// display the brain model volume (if there is one) void displayBrainModelVolume(); /// Get information about surface model in caret main window. static bool getCaretMainWindowModelInfo( BrainModelSurface*& mainCaretWindowModelSurface, GuiBrainModelOpenGL*& mainCaretWindowBrainModelOpenGL, int& modelViewIndex); /// Set the displayed brain model index void setDisplayedBrainModelIndex(const int newIndex); /// set the displayed brain model void setDisplayedBrainModel(const BrainModel* bm); /// Reset the displayed brain models in all windows static void setAllDisplayedBrainModelIndices(const int newIndex); /// Enable/Disable painting of the surface static void setPaintingEnabled(const bool flag) { paintingEnabled = flag; } /// get the BrainModelOpenGL object for a window (may be null if window closed) static GuiBrainModelOpenGL* getBrainModelOpenGLForWindow(const BrainModel::BRAIN_MODEL_VIEW_NUMBER n) { return allBrainSurfaceOpenGL[n]; } /// get main window center model coordinate (returns true if valid) static bool getMainWindowCenterModelCoordinate(float posOut[3]); /// get the opengl drawing object static BrainModelOpenGL* getOpenGLDrawing() { return openGL; } /// are viewing an oblique slice in a window static bool viewingObliqueSlice(); /// set the model selection control used for this BrainModelOpenGL model selection void setModelSelectionControl(class GuiBrainSetAndModelSelectionControl* msc) { modelSelectionControl = msc; } public slots: /// redraw window void slotRedrawWindow(); protected: /// initialize the OpenGL void initializeGL(); /// Draws the graphics (called when graphics need to be updated). void paintGL(); /// Sets the size of the OpenGL area. void resizeGL(int w, int h); /// Gets called by QT when mouse is moved with button down over OpenGL widget void mouseMoveEvent(QMouseEvent *me); /// Gets called by QT when mouse button is pressed over OpenGL widget void mousePressEvent(QMouseEvent *me); /// Get called by QT when mouse button is released over OpenGL widget void mouseReleaseEvent(QMouseEvent* me); /// Gets called by QT when a key is pressed void keyPressEvent(QKeyEvent* ke); /// Gets called by QT when a key is released void keyReleaseEvent(QKeyEvent* ke); private slots: private: /// create a display list containing a sphere void createSphereDisplayList(); /// convert window coords to model corods bool convertWindowToModelCoords(const int windowX, const int windowY, const bool useZBufferForWindowZ, float& modelX, float& modelY, float& modelZ); /// select (Identify) something in the brain model void selectBrainModelItem(const int x, const int y, const unsigned long selectionMaskIn, const bool identifyFlag = false); /// update the node display flags static void updateNodeDisplayFlags(const int numNodes); /// key processing for contours void keyContourView(GuiBrainModelOpenGLKeyEvent& ke); /// key processing for surface void keySurfaceView(GuiBrainModelOpenGLKeyEvent& ke); /// key processing for volume void keyVolumeView(GuiBrainModelOpenGLKeyEvent& ke); /// key processing for surface and volume void keySurfaceAndVolumeView(GuiBrainModelOpenGLKeyEvent& ke); /// key processing for translation axes void keyTranslationAxes(GuiBrainModelOpenGLKeyEvent& ke); /// route the mouse event to the proper handler void routeMouseEvent(const GuiBrainModelOpenGLMouseEvent& me); /// mouse processing for surface view mode void mouseSurfaceView(const GuiBrainModelOpenGLMouseEvent& me); /// mouse processing for surface and volume view mode void mouseSurfaceAndVolumeView(const GuiBrainModelOpenGLMouseEvent& me); /// mouse processing for border draw mode void mouseBorderDraw(const GuiBrainModelOpenGLMouseEvent& me); /// mouse processing for border draw mode NEW void mouseBorderDrawNew(const GuiBrainModelOpenGLMouseEvent& me); /// mouse processing for border delete mode void mouseBorderDelete(const GuiBrainModelOpenGLMouseEvent& me); /// mouse processing for border delete point mode void mouseBorderDeletePoint(const GuiBrainModelOpenGLMouseEvent& me); /// mouse processing for border move point void mouseBorderMovePoint(const GuiBrainModelOpenGLMouseEvent& me); /// mouse processing for border interpolate void mouseBorderInterpolate(const GuiBrainModelOpenGLMouseEvent& me); /// mouse processing for border interpolate NEW void mouseBorderInterpolateNew(const GuiBrainModelOpenGLMouseEvent& me); /// mouse processing for border reverse void mouseBorderReverse(const GuiBrainModelOpenGLMouseEvent& me); /// mouse processing for border rename void mouseBorderRename(const GuiBrainModelOpenGLMouseEvent& me); /// mouse processing for border update void mouseBorderUpdate(const GuiBrainModelOpenGLMouseEvent& me); /// mouse processing for border update NEW void mouseBorderUpdateNew(const GuiBrainModelOpenGLMouseEvent& me); /// mouse processing for draw cut mode void mouseCutDraw(const GuiBrainModelOpenGLMouseEvent& me); /// mouse processing for delete cut mode void mouseCutDelete(const GuiBrainModelOpenGLMouseEvent& me); /// mouse processing for delete foci void mouseFociDelete(const GuiBrainModelOpenGLMouseEvent& me); /// mouse processing for delete cell void mouseCellDelete(const GuiBrainModelOpenGLMouseEvent& me); /// mouse processing for roi border selection void mouseSurfaceRoiBorderSelect(const GuiBrainModelOpenGLMouseEvent& me); /// mouse processing for roi paint selection void mouseSurfaceRoiPaintSelect(const GuiBrainModelOpenGLMouseEvent& me); /// mouse processing for roi metric selection void mouseSurfaceRoiMetricSelect(const GuiBrainModelOpenGLMouseEvent& me); /// mouse processing for roi shape selection void mouseSurfaceRoiShapeSelect(const GuiBrainModelOpenGLMouseEvent& me); /// mouse processing for roi geodesic node selection void mouseSurfaceRoiGeodesicNodeSelect(const GuiBrainModelOpenGLMouseEvent& me); /// mouse processing for align surface to standard orientation void mouseAlignStandardOrientation(const GuiBrainModelOpenGLMouseEvent& me); /// mouse processing for align surface to standard orientation on flatten full hem void mouseAlignStandardOrientationFullHemFlatten(const GuiBrainModelOpenGLMouseEvent& me); /// mouse process for cell add mode void mouseCellAdd(const GuiBrainModelOpenGLMouseEvent& me); /// mouse process for volume transforms in view mode void mouseVolumeView(const GuiBrainModelOpenGLMouseEvent& me); /// mouse process for image subregion selection void mouseImageSubRegion(const GuiBrainModelOpenGLMouseEvent& me); /// mouse process for roi sulcal border start node void mouseSurfaceROISulcalBorderNodeStart(const GuiBrainModelOpenGLMouseEvent& me); /// mouse process for roi sulcal border end node void mouseSurfaceROISulcalBorderNodeEnd(const GuiBrainModelOpenGLMouseEvent& me); /// mouse process for contour transforms in view mode void mouseContourView(const GuiBrainModelOpenGLMouseEvent& me); /// mouse process for contour set scale void mouseContourSetScale(const GuiBrainModelOpenGLMouseEvent& me); /// mouse process for contour draw void mouseContourDraw(const GuiBrainModelOpenGLMouseEvent& me); /// mouse process for contour align void mouseContourAlign(const GuiBrainModelOpenGLMouseEvent& me); /// mouse process for contour region align void mouseContourAlignRegion(const GuiBrainModelOpenGLMouseEvent& me); /// mouse process for contour move point void mouseContourPointMove(const GuiBrainModelOpenGLMouseEvent& me); /// mouse process for contour delete point void mouseContourPointDelete(const GuiBrainModelOpenGLMouseEvent& me); /// mouse process for contour delete void mouseContourDelete(const GuiBrainModelOpenGLMouseEvent& me); /// mouse process for contour point reversal void mouseContourReverse(const GuiBrainModelOpenGLMouseEvent& me); /// mouse process for contour merge void mouseContourMerge(const GuiBrainModelOpenGLMouseEvent& me); /// mouse mode for contour cell add void mouseContourCellAdd(const GuiBrainModelOpenGLMouseEvent& me); /// mouse mode for contour cell delete void mouseContourCellDelete(const GuiBrainModelOpenGLMouseEvent& me); /// mouse mode for contour cell delete void mouseContourCellMove(const GuiBrainModelOpenGLMouseEvent& me); /// mouse mode for volume segmentation editing void mouseVolumeSegmentationEdit(const GuiBrainModelOpenGLMouseEvent& me); /// mouse mode for volume paint editing void mouseVolumePaintEdit(const GuiBrainModelOpenGLMouseEvent& me); /// mouse mode for adding a node void mouseAddNodes(const GuiBrainModelOpenGLMouseEvent& me); /// mouse mode for adding a tile void mouseAddTile(const GuiBrainModelOpenGLMouseEvent& me); /// mouse mode for deleting tile by clicking link void mouseDeleteTileByLink(const GuiBrainModelOpenGLMouseEvent& me); /// mouse mode for disconnect node void mouseDisconnectNode(const GuiBrainModelOpenGLMouseEvent& me); /// mouse mode for move node void mouseMoveNode(const GuiBrainModelOpenGLMouseEvent& me); /// mouse mode for setting translation axes translate void mouseTranslationAxesSetTranslate(const GuiBrainModelOpenGLMouseEvent& me); /// mouse mode for translation axes void mouseTranslationAxes(const GuiBrainModelOpenGLMouseEvent& me); /// Draw the linear object (typically used while drawing borders) void drawLinearObject(); /// Convert from border XYZ to screen XYZ void convertVolumeBorderLinkToScreenXY(const VolumeFile::VOLUME_AXIS axis, float xyz[3]); /// see if in view mode bool getInViewMode() const { return (mouseMode == MOUSE_MODE_VIEW); } /// width of OpenGL window int windowWidth[BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS]; /// height of OpenGL window int windowHeight[BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS]; /// rotation axis BRAIN_MODEL_ROTATION_AXIS rotationAxis; /// yoke view status bool yokeView; /// all graphics windows static GuiBrainModelOpenGL* allBrainSurfaceOpenGL[BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS]; /// index for this viewer in the BrainModel.h BrainModel::BRAIN_MODEL_VIEW_NUMBER viewingWindowIndex; /// the mouse mode MOUSE_MODES mouseMode; /// last X position of mouse int lastMouseX; /// last Y position of mouse int lastMouseY; /// X position of mouse when mouse button pressed int mousePressX; /// Y position of mouse when mouse button pressed int mousePressY; /// track minimum and maximum mouse movement (minX, minY, maxX, maxY) int mouseMovedBounds[4]; /// orthographic projection box for model double orthographicLeft[BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS]; double orthographicRight[BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS]; double orthographicBottom[BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS]; double orthographicTop[BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS]; double orthographicFar[BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS]; double orthographicNear[BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS]; /// selected node BrainModelOpenGLSelectedItem selectedNode; /// selected border (first) BrainModelOpenGLSelectedItem selectedBorder1; /// selected border (second) BrainModelOpenGLSelectedItem selectedBorder2; /// selected border (volume) BrainModelOpenGLSelectedItem selectedVolumeBorder; /// selected cell BrainModelOpenGLSelectedItem selectedCellProjection; /// selected volume cell BrainModelOpenGLSelectedItem selectedVolumeCell; /// selected transform cell BrainModelOpenGLSelectedItem selectedTransformCell; /// selected cut BrainModelOpenGLSelectedItem selectedCut; /// selected foci BrainModelOpenGLSelectedItem selectedFocusProjection; /// selected volume foci BrainModelOpenGLSelectedItem selectedVolumeFoci; /// selected transform foci BrainModelOpenGLSelectedItem selectedTransformFocus; /// selected palette metric BrainModelOpenGLSelectedItem selectedPaletteMetric; /// selected palette shape BrainModelOpenGLSelectedItem selectedPaletteShape; /// selected contour BrainModelOpenGLSelectedItem selectedContour; /// selected contour cell BrainModelOpenGLSelectedItem selectedContourCell; /// selected voxel underlay BrainModelOpenGLSelectedItem selectedVoxelUnderlay; /// selected voxel overlay secondary BrainModelOpenGLSelectedItem selectedVoxelOverlaySecondary; /// selected voxel overlay primary BrainModelOpenGLSelectedItem selectedVoxelOverlayPrimary; /// selected functional voxel (surface and volume cloud) BrainModelOpenGLSelectedItem selectedVoxelFunctionalCloud; /// selected surface tile BrainModelOpenGLSelectedItem selectedSurfaceTile; /// selected link (index 1 & 2 are nodes) BrainModelOpenGLSelectedItem selectedLink; /// selected transformation axes BrainModelOpenGLSelectedItem selectedTransformationAxes; /// selected vtk model BrainModelOpenGLSelectedItem selectedVtkModel; /// enable OpenGL drawing static bool paintingEnabled; /// linear (border, cut, contour) being drawn Border linearObjectBeingDrawn; /// resampling density of linear object being drawn float linearObjectBeingDrawnSampling; /// linear object augment border 1 BrainModelOpenGLSelectedItem linearObjectAugmentBorder1; /// linear object augment border 2 BrainModelOpenGLSelectedItem linearObjectAugmentBorder2; /// linear object augment border count int linearObjectAugmentBorderCount; /// draw linear object flag bool drawLinearObjectOnly; /// the popup menu shown with right mouse press GuiBrainModelOpenGLPopupMenu* popupMenu; /// border file number, border number, and border point number being moved int borderPointBeingMoved[3]; /// node numbers of tile being entered int newTileNodeNumbers[3]; /// counter for new tile nodes int newTileNodeCounter; /// model selection control GuiBrainSetAndModelSelectionControl* modelSelectionControl; /// volume slice axis //VolumeFile::VOLUME_AXIS volumeSliceAxis; /// volume slice coordinate //float volumeSliceCoordinate; /// a key was up last time bool keyUpLastTime; /// box for image subregion int imageSubRegionBox[4]; /// image subregion box valid bool imageSubRegionBoxValid; /// version number of OpenGL static float versionOfOpenGL; /// left mouse button pressonly static int leftMouseButtonPressMask; /// left mouse button + shift press static int leftShiftMouseButtonPressMask; /// left mouse button + control press static int leftControlMouseButtonPressMask; /// left mouse button only move static int leftMouseButtonMoveMask; /// left mouse button + shift move static int leftShiftMouseButtonMoveMask; /// left mouse button + control move static int leftControlMouseButtonMoveMask; /// left mouse button + alt move static int leftAltMouseButtonMoveMask; /// default orthographic window size static float defaultOrthoWindowSize; /// amount mouse must move to NOT be an ID node operation static int mouseMoveTolerance; /// OpenGL drawing static BrainModelOpenGL* openGL; /// min point size static float minPointSize; /// max point size static float maxPointSize; /// min line size static float minLineSize; /// max line size static float maxLineSize; }; #ifdef __GUI_BRAIN_SURFACE_OPENGL_INIT_STATIC__ BrainModelOpenGL* GuiBrainModelOpenGL::openGL = NULL; GuiBrainModelOpenGL* GuiBrainModelOpenGL::allBrainSurfaceOpenGL[BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; bool GuiBrainModelOpenGL::paintingEnabled = true; float GuiBrainModelOpenGL::versionOfOpenGL = 0.0; int GuiBrainModelOpenGL::leftMouseButtonPressMask = 0; int GuiBrainModelOpenGL::leftShiftMouseButtonPressMask = 0; int GuiBrainModelOpenGL::leftControlMouseButtonPressMask = 0; int GuiBrainModelOpenGL::leftMouseButtonMoveMask = 0; int GuiBrainModelOpenGL::leftShiftMouseButtonMoveMask = 0; int GuiBrainModelOpenGL::leftControlMouseButtonMoveMask = 0; int GuiBrainModelOpenGL::leftAltMouseButtonMoveMask = 0; float GuiBrainModelOpenGL::minPointSize = 0.0; float GuiBrainModelOpenGL::maxPointSize = 0.0; float GuiBrainModelOpenGL::minLineSize = 0.0; float GuiBrainModelOpenGL::maxLineSize = 0.0; float GuiBrainModelOpenGL::defaultOrthoWindowSize = 125.0; int GuiBrainModelOpenGL::mouseMoveTolerance = 2; #endif // __GUI_BRAIN_SURFACE_OPENGL_INIT_STATIC__ #endif caret-5.6.4~dfsg.1.orig/caret/GuiBrainModelOpenGL.cxx0000664000175000017500000111045211572067322022135 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ // // This file contains the class methods that create the OpenGL widget // for drawing a brain surface. // #include #include #include #ifdef Q_OS_WIN32 #define NOMINMAX #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "vtkMath.h" #define __GUI_BRAIN_SURFACE_OPENGL_INIT_STATIC__ #include "GuiBrainModelOpenGL.h" #undef __GUI_BRAIN_SURFACE_OPENGL_INIT_STATIC__ #include "BorderFile.h" #include "BrainModelBorderSet.h" #include "BrainModelContours.h" #include "BrainModelIdentification.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceAndVolume.h" #include "BrainModelSurfaceNodeColoring.h" #include "BrainModelVolume.h" #include "BrainSet.h" #include "BrainSetAutoLoaderManager.h" #include "CellFile.h" #include "CommunicatorClientAFNI.h" #include "CommunicatorClientFIV.h" #include "ContourCellFile.h" #include "CutsFile.h" #include "DebugControl.h" #include "DisplaySettingsBorders.h" #include "DisplaySettingsCoCoMac.h" #include "DisplaySettingsMetric.h" #include "DisplaySettingsSurface.h" #include "DisplaySettingsSurfaceShape.h" #include "DisplaySettingsVolume.h" #include "DisplaySettingsWustlRegion.h" #include "FileUtilities.h" #include "GuiAddCellsDialog.h" #include "GuiAlignSurfaceToStandardOrientationDialog.h" #include "GuiBordersCreateInterpolatedDialog.h" #include "GuiBorderDrawUpdateDialog.h" #include "GuiBorderOperationsDialog.h" #include "GuiBrainModelOpenGLKeyEvent.h" #include "GuiBrainModelOpenGLMouseEvent.h" #include "GuiBrainModelOpenGLPopupMenu.h" #include "GuiBrainSetAndModelSelectionControl.h" #include "GuiContourAlignmentDialog.h" #include "GuiContourDrawDialog.h" #include "GuiContourSetScaleDialog.h" #include "GuiDrawBorderDialog.h" #include "GuiFilesModified.h" #include "GuiFlattenFullHemisphereDialog.h" #include "GuiGraphWidget.h" #include "GuiGraphWidgetDialog.h" #include "GuiIdentifyDialog.h" #include "GuiMainWindow.h" #include "GuiMainWindowVolumeActions.h" #include "GuiRecordingDialog.h" #include "GuiSurfaceRegionOfInterestDialog.h" #include "GuiSurfaceRegionOfInterestDialogOLD.h" #include "GuiToolBar.h" #include "GuiTransformationMatrixDialog.h" #include "GuiVolumePaintEditorDialog.h" #include "GuiVolumeResizingDialog.h" #include "GuiVolumeSegmentationEditorDialog.h" #include "ImageFile.h" #include "MathUtilities.h" #include "MetricFile.h" #include "PaintFile.h" #include "SectionFile.h" #include "SurfaceShapeFile.h" #include "TopologyFile.h" #include "TopologyHelper.h" #include "TransformationMatrixFile.h" #include "VolumeFile.h" #include "VtkModelFile.h" #include "WustlRegionFile.h" #include "global_variables.h" #include "vtkTransform.h" // Prevent more than one window from painting simultaneously static QMutex paintMutex; /** * The Constructor. */ GuiBrainModelOpenGL::GuiBrainModelOpenGL(QWidget* parent, GuiBrainModelOpenGL* sharedBrainModelOpenGL, const char* name, const BrainModel::BRAIN_MODEL_VIEW_NUMBER svn) : QGLWidget(parent, sharedBrainModelOpenGL) { setObjectName(name); static bool firstTime = true; if (firstTime) { // // OpenGL drawing // openGL = NULL; // // Mouse button move masks // Note: On Macintoshes, Qt::ControlButton is the Apple key // leftMouseButtonMoveMask = Qt::NoModifier; leftShiftMouseButtonMoveMask = Qt::ShiftModifier; leftControlMouseButtonMoveMask = Qt::ControlModifier; leftAltMouseButtonMoveMask = Qt::AltModifier; // // Mouse button press masks // Note: On Macintoshes, Qt::ControlButton is the Apple key // leftMouseButtonPressMask = Qt::NoButton; leftShiftMouseButtonPressMask = Qt::ShiftModifier; leftControlMouseButtonPressMask = Qt::ControlModifier; firstTime = false; } drawLinearObjectOnly = false; imageSubRegionBoxValid = false; imageSubRegionBox[0] = 0; imageSubRegionBox[1] = 0; imageSubRegionBox[2] = 0; imageSubRegionBox[3] = 0; viewingWindowIndex = svn; allBrainSurfaceOpenGL[viewingWindowIndex] = this; mouseMode = MOUSE_MODE_VIEW; rotationAxis = BRAIN_MODEL_ROTATION_AXIS_XY; yokeView = false; borderPointBeingMoved[0] = -1; popupMenu = new GuiBrainModelOpenGLPopupMenu(this); keyUpLastTime = false; setFocusPolicy(Qt::StrongFocus); } /** * The Destructor. */ GuiBrainModelOpenGL::~GuiBrainModelOpenGL() { makeCurrent(); allBrainSurfaceOpenGL[viewingWindowIndex] = NULL; // // Delete the BrainModelOpenGL when all GuiBrainModelOpenGL are gone // bool allNull = true; for (int i = 0; i < BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS; i++) { if (allBrainSurfaceOpenGL[i] != NULL) { allNull = false; } } if (allNull) { delete openGL; openGL = NULL; } } /** *initialize the OpenGL. */ void GuiBrainModelOpenGL::initializeGL() { if (openGL == NULL) { openGL = new BrainModelOpenGL; float sizes[2]; glGetFloatv(GL_POINT_SIZE_RANGE, sizes); minPointSize = sizes[0]; maxPointSize = sizes[1]; glGetFloatv(GL_LINE_WIDTH_RANGE, sizes); minLineSize = sizes[0]; maxLineSize = sizes[1]; } openGL->initializeOpenGL(false); } /** * Reset the linear object being drawn (border, contour, cut). */ void GuiBrainModelOpenGL::resetLinearObjectBeingDrawn() { linearObjectBeingDrawn.clearLinks(); linearObjectAugmentBorderCount = 0; } /** * Called by QT to redraw the OpenGL widget. */ void GuiBrainModelOpenGL::paintGL() { // painting is typically disabled when loading the spec file since the progress dialog // may cause a paint event with only part of a coordinate files loaded. if (paintingEnabled == false) { return; } int viewport[4] = { 0, 0, windowWidth[viewingWindowIndex], windowHeight[viewingWindowIndex] }; // // Handle aux windows yoked to main window // if (viewingWindowIndex != BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) { if (getYokeView()) { BrainModelSurface* mainBMS = allBrainSurfaceOpenGL[BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW]->getDisplayedBrainModelSurface(); BrainModelSurface* bms = getDisplayedBrainModelSurface(); if ((mainBMS != NULL) && (bms != NULL)) { float translation[3]; mainBMS->getTranslation(BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW, translation); bms->setTranslation(viewingWindowIndex, translation); float scale[3]; mainBMS->getScaling(BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW, scale); bms->setScaling(viewingWindowIndex, scale); float matrix[16]; mainBMS->getRotationMatrix(BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW, matrix); bms->setRotationMatrix(viewingWindowIndex, matrix); } else if (bms != NULL) { // // See if oblique volume view in main window // BrainModelVolume* mainBMV = allBrainSurfaceOpenGL[BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW]->getDisplayedBrainModelVolume(); if (mainBMV != NULL) { if (mainBMV->getSelectedAxis(BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) == VolumeFile::VOLUME_AXIS_OBLIQUE) { float matrix[16]; mainBMV->getObliqueRotationMatrix(matrix); bms->setRotationMatrix(viewingWindowIndex, matrix); } } } } } std::vector specialNodes; if (mouseMode == MOUSE_MODE_EDIT_ADD_TILE) { for (int ti = 0; ti < newTileNodeCounter; ti++) { specialNodes.push_back(newTileNodeNumbers[ti]); } } openGL->setNodeSpecialHighlighting(specialNodes); openGL->setLinearObject(linearObjectBeingDrawn); openGL->setDrawLinearObjectOnly(drawLinearObjectOnly); BrainModel* bm = getDisplayedBrainModel(); BrainSet* bs = NULL; if (bm != NULL) { bs = bm->getBrainSet(); } if (bs == NULL) { bs = theMainWindow->getBrainSet(getModelViewNumber()); } openGL->setImageSubRegion(imageSubRegionBox, imageSubRegionBoxValid); bool drawAllFiducialFlag = false; if (modelSelectionControl != NULL) { drawAllFiducialFlag = modelSelectionControl->getAllFiducialSelected(); } if (drawAllFiducialFlag) { std::vector brainSets; theMainWindow->getAllBrainSets(brainSets); openGL->drawAllFiducialSurfaceBrainModels(brainSets, viewingWindowIndex, viewport, this); } else { openGL->drawBrainModel(bs, bm, viewingWindowIndex, viewport, this); } } /** * Called by QT when the OpenGL widget is resized. */ void GuiBrainModelOpenGL::resizeGL(int w, int h) { windowWidth[viewingWindowIndex] = w; windowHeight[viewingWindowIndex] = h; openGL->updateOrthoSize(viewingWindowIndex, w, h); } /** * Get the dimensions of the surface orthographic projection */ void GuiBrainModelOpenGL::getOrthographicBox(double& orthoLeft, double& orthoRight, double& orthoBottom, double& orthoTop, double& orthoNear, double& orthoFar) const { openGL->getOrthographicBox(viewingWindowIndex, orthoLeft, orthoRight, orthoBottom, orthoTop, orthoNear, orthoFar); } /** * Returns a pointer to the displayed model (NULL if not available) */ BrainModel* GuiBrainModelOpenGL::getDisplayedBrainModel() { if (theMainWindow != NULL) { const int numModels = theMainWindow->getBrainSet(getModelViewNumber())->getNumberOfBrainModels(); if (numModels > 0) { if (theMainWindow->getBrainSet(getModelViewNumber())->getDisplayedModelIndexForWindow(viewingWindowIndex) < numModels) { return theMainWindow->getBrainSet(getModelViewNumber())->getBrainModel(theMainWindow->getBrainSet(getModelViewNumber())->getDisplayedModelIndexForWindow(viewingWindowIndex)); } } } return NULL; } /** * Returns a pointer to the displayed surface (NULL if a surface is not displayed) */ BrainModelSurface* GuiBrainModelOpenGL::getDisplayedBrainModelSurface() { BrainModel* bm = getDisplayedBrainModel(); if (bm != NULL) { if (bm->getModelType() == BrainModel::BRAIN_MODEL_SURFACE) { BrainModelSurface* bms = dynamic_cast(bm); return bms; } } return NULL; } /** * Returns a pointer to the displayed surface and volume (NULL if a surface and volume is not displayed) */ BrainModelSurfaceAndVolume* GuiBrainModelOpenGL::getDisplayedBrainModelSurfaceAndVolume() { BrainModel* bm = getDisplayedBrainModel(); if (bm != NULL) { if (bm->getModelType() == BrainModel::BRAIN_MODEL_SURFACE_AND_VOLUME) { BrainModelSurfaceAndVolume* bms = dynamic_cast(bm); return bms; } } return NULL; } /** * Returns a pointer to the displayed contours (NULL if a surface is not displayed) */ BrainModelContours* GuiBrainModelOpenGL::getDisplayedBrainModelContours() { BrainModel* bm = getDisplayedBrainModel(); if (bm != NULL) { if (bm->getModelType() == BrainModel::BRAIN_MODEL_CONTOURS) { BrainModelContours* bms = dynamic_cast(bm); return bms; } } return NULL; } /** * Returns a pointer to the displayed volume (NULL if a volume is not displayed) */ BrainModelVolume* GuiBrainModelOpenGL::getDisplayedBrainModelVolume() { BrainModel* bm = getDisplayedBrainModel(); if (bm != NULL) { if (bm->getModelType() == BrainModel::BRAIN_MODEL_VOLUME) { BrainModelVolume* bmv = dynamic_cast(bm); return bmv; } } return NULL; } /** * Display the volume */ void GuiBrainModelOpenGL::displayBrainModelVolume() { for (int i = 0; i < theMainWindow->getBrainSet(getModelViewNumber())->getNumberOfBrainModels(); i++) { if (theMainWindow->getBrainSet(getModelViewNumber())->getBrainModelVolume(i) != NULL) { setDisplayedBrainModelIndex(i); break; } } } /** * Called when an Identify mouse click has been made on a brain model. */ void GuiBrainModelOpenGL::selectBrainModelItem(const int selectionX, const int selectionY, const unsigned long selectionMask, const bool identifyFlag) { makeCurrent(); // 9/13/2005 int viewport[4] = { 0, 0, windowWidth[viewingWindowIndex], windowHeight[viewingWindowIndex] }; BrainModel* bm = getDisplayedBrainModel(); BrainSet* bs = NULL; if (bm != NULL) { bs = bm->getBrainSet(); } if (bs == NULL) { bs = theMainWindow->getBrainSet(getModelViewNumber()); } if (identifyFlag) { BrainModel* allWindowBrainModels[BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS]; for (int i = 0; i < BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS; i++) { allWindowBrainModels[i] = NULL; if (allBrainSurfaceOpenGL[i] != NULL) { allWindowBrainModels[i] = allBrainSurfaceOpenGL[i]->getDisplayedBrainModel(); } } QString idText = openGL->identifyBrainModelItem(bs, bm, allWindowBrainModels, viewingWindowIndex, viewport, this, selectionMask, selectionX, selectionY, getInViewMode(), true, true); if (idText.isEmpty() == false) { GuiIdentifyDialog* id = theMainWindow->getIdentifyDialog(true); id->appendHtml(idText); } GuiToolBar::updateAllToolBars(false); } else { openGL->selectBrainModelItem(bs, bm, viewingWindowIndex, viewport, this, selectionMask, selectionX, selectionY, getInViewMode()); } selectedSurfaceTile = openGL->getSelectedSurfaceTile(); selectedNode = openGL->getSelectedNode(); selectedBorder1 = openGL->getSelectedBorder1(); selectedBorder2 = openGL->getSelectedBorder2(); selectedVolumeBorder = openGL->getSelectedVolumeBorder(); selectedCellProjection = openGL->getSelectedCellProjection(); selectedVolumeCell = openGL->getSelectedVolumeCell(); selectedCut = openGL->getSelectedCut(); selectedFocusProjection = openGL->getSelectedFocusProjection(); selectedVolumeFoci = openGL->getSelectedVolumeFoci(); selectedPaletteMetric = openGL->getSelectedPaletteMetric(); selectedPaletteShape = openGL->getSelectedPaletteShape(); selectedContour = openGL->getSelectedContour(); selectedContourCell = openGL->getSelectedContourCell(); selectedVoxelUnderlay = openGL->getSelectedVoxelUnderlay(); selectedVoxelOverlaySecondary = openGL->getSelectedVoxelOverlaySecondary(); selectedVoxelOverlayPrimary = openGL->getSelectedVoxelOverlayPrimary(); selectedVoxelFunctionalCloud = openGL->getSelectedVoxelFunctionalCloud(); selectedLink = openGL->getSelectedLink(); selectedTransformationAxes = openGL->getSelectedTransformationMatrixAxes(); selectedVtkModel = openGL->getSelectedVtkModel(); selectedTransformCell = openGL->getSelectedTransformationCell(); selectedTransformFocus = openGL->getSelectedTransformationFoci(); if (mouseMode == MOUSE_MODE_VIEW) { //bool cocomacFlag = false; if ((selectedNode.getItemIndex1() >= 0) && identifyFlag) { const int nodeNum = selectedNode.getItemIndex1(); if (nodeNum >= 0) { BrainSetNodeAttribute* bna = bs->getNodeAttributes(nodeNum); if (bna->getHighlighting() == BrainSetNodeAttribute::HIGHLIGHT_NODE_NONE) { bna->setHighlighting(BrainSetNodeAttribute::HIGHLIGHT_NODE_LOCAL); } else { bna->setHighlighting(BrainSetNodeAttribute::HIGHLIGHT_NODE_NONE); } bs->clearAllDisplayLists(); } } if ((selectedContour.getItemIndex1() >= 0) && (selectedContour.getItemIndex2() >= 0) && identifyFlag) { BrainModelContours* bmc = bs->getBrainModelContours(); if (bmc != NULL) { ContourFile* cf = bmc->getContourFile(); CaretContour* cc = cf->getContour(selectedContour.getItemIndex1()); cc->setHighlightFlag(selectedContour.getItemIndex2(), (! cc->getHighlightFlag(selectedContour.getItemIndex2()))); } } if (identifyFlag) { const int nodeNumber = selectedNode.getItemIndex1(); if (nodeNumber >= 0) { // // Pass it on to AFNI & FIV // theMainWindow->getAfniClientCommunicator()->sendNodeHighlightToAFNI(nodeNumber); theMainWindow->getFivClientCommunicator()->sendNodeHighlightToFIV(nodeNumber); } } // // In surface and volume, display ID for only node/voxel nearest viewer // /* if (getDisplayedBrainModelSurfaceAndVolume() != NULL) { if ((selectedNode.getItemIndex1() >= 0) && (selectedVoxelUnderlay.getItemIndex1() >= 0)) { if (selectedNode.getDepth() < selectedVoxelUnderlay.getDepth()) { selectedVoxelUnderlay.setItemIndex1(-1); } else { selectedNode.setItemIndex1(-1); } } } */ const BrainModelSurface* bms = getDisplayedBrainModelSurface(); if (bms == NULL) { bms = dynamic_cast(getDisplayedBrainModelSurfaceAndVolume()); } int modelIndex = -1; if (bms != NULL) { modelIndex = bms->getBrainModelIndex(); } /* if (selectionMask & BrainModelOpenGL::SELECTION_MASK_NODE) { // // Update node colors if displaying cocomac // BrainModelSurfaceNodeColoring* bsnc = theMainWindow->getBrainSet(getModelViewNumber())->getNodeColoring(); DisplaySettingsCoCoMac* dsc = theMainWindow->getBrainSet(getModelViewNumber())->getDisplaySettingsCoCoMac(); if ((bsnc->getPrimaryOverlay(modelIndex) == BrainModelSurfaceNodeColoring::OVERLAY_COCOMAC) || (bsnc->getSecondaryOverlay(modelIndex) == BrainModelSurfaceNodeColoring::OVERLAY_COCOMAC) || (bsnc->getUnderlay(modelIndex) == BrainModelSurfaceNodeColoring::UNDERLAY_COCOMAC)) { if (selectedNode.getItemIndex1() >= 0) { dsc->setSelectedNode(selectedNode.getItemIndex1()); cocomacFlag = true; } else { dsc->setSelectedNode(-1); } bsnc->assignColors(); updateAllGL(NULL); } else { dsc->setSelectedNode(-1); } } */ // // If axes selected in a view mode disable any node or voxel identification // /* if (mouseMode == MOUSE_MODE_VIEW) { if (selectedTransformationAxes.getItemIndex1() >= 0) { selectedNode.setItemIndex1(-1); selectedVoxelUnderlay.setItemIndex1(-1); selectedVoxelOverlaySecondary.setItemIndex1(-1); selectedVoxelOverlayPrimary.setItemIndex1(-1); selectedVoxelFunctionalCloud.setItemIndex1(-1); } } */ // // Metric graph plotting // if (selectedNode.getItemIndex1() >= 0) { //GuiIdentifyDialog* id = theMainWindow->getIdentifyDialog(true); BrainModelSurface* s = getDisplayedBrainModelSurface(); if (s == NULL) { s = dynamic_cast(getDisplayedBrainModelSurfaceAndVolume()); } if (s != NULL) { /* id->displayNode(s, getModelViewNumber(), selectedNode.getItemIndex1(), BrainSetNodeAttribute::HIGHLIGHT_NODE_LOCAL, true, cocomacFlag); */ DisplaySettingsMetric* dsm = theMainWindow->getBrainSet(getModelViewNumber())->getDisplaySettingsMetric(); if (dsm->getMDataPlotOnNodeID() != DisplaySettingsMetric::METRIC_DATA_PLOT_OFF) { if (theMainWindow->getBrainSet()->isASurfaceOverlayForAnySurface( BrainModelSurfaceOverlay::OVERLAY_METRIC)) { const MetricFile* mf = theMainWindow->getBrainSet(getModelViewNumber())->getMetricFile(); const int col = dsm->getFirstSelectedColumnForBrainModel(modelIndex); const int numCols = mf->getNumberOfColumns(); if ((col >= 0) && (col < numCols)) { GuiGraphWidgetDialog* graphDialog = new GuiGraphWidgetDialog("Metric Plot", this); graphDialog->setAttribute(Qt::WA_DeleteOnClose); GuiGraphWidget* graphWidget = graphDialog->getGraphWidget(); graphWidget->setLegends("Timepoints", "", "", "Functional Data"); std::vector dataYFloat(numCols); mf->getAllColumnValuesForNode(selectedNode.getItemIndex1(), &dataYFloat[0]); std::vector dataX(numCols); std::vector dataY(numCols); for (int i = 0; i < numCols; i++) { dataX[i] = i + 1; dataY[i] = dataYFloat[i]; } graphWidget->addData(dataX, dataY, QColor(255, 0, 0), GuiGraphWidget::DRAW_DATA_TYPE_LINES); if (dsm->getMDataPlotOnNodeID() == DisplaySettingsMetric::METRIC_DATA_PLOT_NODE_AND_NEIGHBORS){ const TopologyFile* tf = s->getTopologyFile(); if (tf != NULL) { const TopologyHelper* th = tf->getTopologyHelper(false, true, false); int numNeighbors; const int* neighbors = th->getNodeNeighbors(selectedNode.getItemIndex1(), numNeighbors); for (int i = 0; i < numNeighbors; i++) { std::vector dataYFloat(numCols); mf->getAllColumnValuesForNode(neighbors[i], &dataYFloat[0]); std::vector dataY(numCols); for (int i = 0; i < numCols; i++) { dataY[i] = dataYFloat[i]; } graphWidget->addData(dataX, dataY, QColor(255, 0, 0), GuiGraphWidget::DRAW_DATA_TYPE_LINES); } } } float minScale, maxScale; if (dsm->getDataPlotManualScaling(minScale, maxScale)) { graphWidget->setScaleYMinimum(minScale); graphWidget->setScaleYMaximum(maxScale); } graphDialog->show(); graphDialog->activateWindow(); } } } // // See if region and paint files are loaded // WustlRegionFile* wrf = theMainWindow->getBrainSet(getModelViewNumber())->getWustlRegionFile(); const int numTimeCourses = wrf->getNumberOfTimeCourses(); const int numPaintVolumes = theMainWindow->getBrainSet(getModelViewNumber())->getNumberOfVolumePaintFiles(); if ((numTimeCourses > 0) && (numPaintVolumes > 0)) { const int NUM_COLORS = 23; int colorCtr = 0; const int colors[NUM_COLORS][3] = { { 255, 0, 0 }, { 255, 0, 127 }, { 255, 0, 255 }, { 255, 127, 0 }, { 255, 127, 127 }, { 255, 127, 255 }, { 255, 255, 0 }, { 255, 255, 127 }, { 127, 0, 0 }, { 127, 0, 127 }, { 127, 0, 255 }, { 127, 127, 0 }, { 127, 127, 127 }, { 127, 127, 255 }, { 127, 255, 0 }, { 127, 255, 127 }, { 127, 255, 255 }, { 0, 127, 0 }, { 0, 127, 127 }, { 0, 127, 255 }, { 0, 255, 0 }, { 0, 255, 127 }, { 0, 255, 255 } }; // // If a popup graph should be displayed // const DisplaySettingsWustlRegion* dswr = theMainWindow->getBrainSet(getModelViewNumber())->getDisplaySettingsWustlRegion(); if (dswr->getPopupGraphEnabled()) { // // if a valid paint volume is selected // const int paintVolumeIndex = dswr->getSelectedPaintVolume(); if ((numPaintVolumes >= 0) && (paintVolumeIndex < numPaintVolumes)) { // // If fiducial surface is valid // BrainModelSurface* fiducial = theMainWindow->getBrainSet(getModelViewNumber())->getActiveFiducialSurface(); if (fiducial != NULL) { // // Get the fiducial coordinate // float xyz[3]; const CoordinateFile* cf = fiducial->getCoordinateFile(); cf->getCoordinate(selectedNode.getItemIndex1(), xyz); // // Get the paint volume // VolumeFile* paintVolume = theMainWindow->getBrainSet(getModelViewNumber())->getVolumePaintFile(paintVolumeIndex); // // Find the voxel containing the coordinate // int ijk[3]; float pcoords[3]; if (paintVolume->convertCoordinatesToVoxelIJK(xyz, ijk, pcoords) != 0) { // // Get the voxel // const float voxelFloat = paintVolume->getVoxel(ijk, 0); // // Convert voxel to int // const int roiNumber = static_cast(voxelFloat); // // Get the name of the ROI // if ((roiNumber >= 0) && (roiNumber < paintVolume->getNumberOfRegionNames())) { const QString regionName(paintVolume->getRegionNameFromIndex(roiNumber)); if (DebugControl::getDebugOn()) { std::cout << "Region name identified: " << regionName.toAscii().constData() << std::endl; } // // The graph widget // GuiGraphWidgetDialog* graph = NULL; GuiGraphWidget* graphWidget = NULL; QString graphTitle; // // Loop through the timecourses // for (int itc = 0; itc < numTimeCourses; itc++) { // // // bool useTC = false; switch (dswr->getTimeCourseSelection()) { case DisplaySettingsWustlRegion::TIME_COURSE_SELECTION_ALL: graphTitle = "All Time Courses"; useTC = true; break; case DisplaySettingsWustlRegion::TIME_COURSE_SELECTION_SINGLE: if (itc == dswr->getSelectedTimeCourse()) { useTC = true; } break; } // // Should this time course be displayed ? // if (useTC) { // // Get the index to the region // WustlRegionFile::TimeCourse* tc = wrf->getTimeCourse(itc); const WustlRegionFile::Region* region = tc->getRegionByName(regionName); if (region != NULL) { // // Get the selected case name // const QString caseName = dswr->getSelectedCaseName(); if (caseName.isEmpty() == false) { // // Get the region case // const WustlRegionFile::RegionCase* rc = region->getRegionCaseByName(caseName); if (rc != NULL) { // // Create the graph if it has not already been created // if (graph == NULL) { graph = new GuiGraphWidgetDialog("", this); graphWidget->setAttribute(Qt::WA_DeleteOnClose); graphWidget = graph->getGraphWidget(); if (graphTitle.isEmpty() == false) { graph->setWindowTitle(graphTitle); } else { graph->setWindowTitle(tc->getName()); } if (dswr->getGraphMode() == DisplaySettingsWustlRegion::GRAPH_MODE_USER_SCALE) { float minScale, maxScale; dswr->getUserScale(minScale, maxScale); graphWidget->setScaleYMinimum(minScale); graphWidget->setScaleYMaximum(maxScale); } } // if (graph == NULL) // // Get the time points // const std::vector dataYFloat = rc->getTimePoints(); std::vector dataX, dataY; for (int i = 0; i < static_cast(dataY.size()); i++) { dataX.push_back(i); dataY.push_back(dataYFloat[i]); } colorCtr++; if (colorCtr >= NUM_COLORS) { colorCtr = 0; } QColor qcolor(colors[colorCtr][0], colors[colorCtr][1], colors[colorCtr][2]); graphWidget->addData(dataX, dataY, qcolor, GuiGraphWidget::DRAW_DATA_TYPE_LINES); graphWidget->setLegends(regionName, "", "", caseName); } // if (rc != NULL) } // if (casename.empty() == false) } // if (region != NULL) } // if (useTC) } // for (int itc... if (graph != NULL) { graph->show(); graph->activateWindow(); } // if (roiNumber } } } } } } } } else if (selectedSurfaceTile.getItemIndex1() >= 0) { // // Node not found but tile is so pick a node from the tile // } /* if (selectedBorder1.getItemIndex1() >= 0) { GuiIdentifyDialog* id = theMainWindow->getIdentifyDialog(true); id->displayBorder(selectedBorder1, getModelViewNumber()); } if (selectedBorder2.getItemIndex1() >= 0) { GuiIdentifyDialog* id = theMainWindow->getIdentifyDialog(true); id->displayBorder(selectedBorder2, getModelViewNumber()); } if (selectedCellProjection.getItemIndex1() >= 0) { GuiIdentifyDialog* id = theMainWindow->getIdentifyDialog(true); id->displayCell(selectedCellProjection, getModelViewNumber()); } if (selectedVolumeCell.getItemIndex1() >= 0) { GuiIdentifyDialog* id = theMainWindow->getIdentifyDialog(true); id->displayVolumeCell(selectedVolumeCell, getModelViewNumber()); } if (selectedFocusProjection.getItemIndex1() >= 0) { GuiIdentifyDialog* id = theMainWindow->getIdentifyDialog(true); id->displayFocus(getDisplayedBrainModelSurface(), selectedFocusProjection, getModelViewNumber()); } if (selectedVolumeFoci.getItemIndex1() >= 0) { GuiIdentifyDialog* id = theMainWindow->getIdentifyDialog(true); id->displayVolumeFocus(selectedVolumeFoci, getModelViewNumber()); } if (selectedTransformCell.getItemIndex1() >= 0) { GuiIdentifyDialog* id = theMainWindow->getIdentifyDialog(true); id->displayTransformCell(selectedTransformCell, getModelViewNumber()); } if (selectedTransformFocus.getItemIndex1() >= 0) { GuiIdentifyDialog* id = theMainWindow->getIdentifyDialog(true); id->displayTransformFoci(selectedTransformFocus, getModelViewNumber()); } if (selectedPaletteMetric.getItemIndex1() >= 0) { GuiIdentifyDialog* id = theMainWindow->getIdentifyDialog(true); id->displayPalette(selectedPaletteMetric, getModelViewNumber()); } //if (selectedPaletteShape.getItemIndex1() >= 0) { // GuiIdentifyDialog* id = theMainWindow->getIdentifyDialog(true); // id->displayPalette(selectedPaletteShape, getModelViewNumber()); //} BrainModelVolume* bmv = theMainWindow->getBrainSet(getModelViewNumber())->getBrainModelVolume(-1); if (bmv != NULL) { if (selectedVoxelUnderlay.getItemIndex1() >= 0) { TransformationMatrix* tm = NULL; if (bmv->getSelectedAxis(viewingWindowIndex) == VolumeFile::VOLUME_AXIS_OBLIQUE) { tm = new TransformationMatrix; tm->setMatrix(bmv->getObliqueRotationMatrix()); } GuiIdentifyDialog* id = theMainWindow->getIdentifyDialog(true); id->displayVoxel(bmv->getUnderlayVolumeFile(), selectedVoxelUnderlay, tm, viewingWindowIndex); if (tm != NULL) { delete tm; tm = NULL; } } else if (selectedVoxelOverlaySecondary.getItemIndex1() >= 0) { GuiIdentifyDialog* id = theMainWindow->getIdentifyDialog(true); id->displayVoxel(bmv->getOverlaySecondaryVolumeFile(), selectedVoxelOverlaySecondary, NULL, getModelViewNumber()); } else if (selectedVoxelOverlayPrimary.getItemIndex1() >= 0) { GuiIdentifyDialog* id = theMainWindow->getIdentifyDialog(true); id->displayVoxel(bmv->getOverlayPrimaryVolumeFile(), selectedVoxelOverlayPrimary, NULL, getModelViewNumber()); } if (selectedVoxelFunctionalCloud.getItemIndex1() >= 0) { GuiIdentifyDialog* id = theMainWindow->getIdentifyDialog(true); id->displayVoxelCloudFunctional(selectedVoxelFunctionalCloud, getModelViewNumber()); } if (selectedVolumeBorder.getItemIndex1() >= 0) { GuiIdentifyDialog* id = theMainWindow->getIdentifyDialog(true); id->displayVolumeBorder(selectedVolumeBorder, getModelViewNumber()); } } // // If VTK model is selected // if (selectedVtkModel.getItemIndex1() >= 0) { GuiIdentifyDialog* id= theMainWindow->getIdentifyDialog(true); id->displayVtkModel(selectedVtkModel.getItemIndex1(), selectedVtkModel.getItemIndex2(), getModelViewNumber()); } BrainModelContours* bmc = theMainWindow->getBrainSet(getModelViewNumber())->getBrainModelContours(); if (bmc != NULL) { if (selectedContour.getItemIndex1() >= 0) { GuiIdentifyDialog* id = theMainWindow->getIdentifyDialog(true); id->displayContour(selectedContour, getModelViewNumber()); } if (selectedContourCell.getItemIndex1() >= 0) { GuiIdentifyDialog* id = theMainWindow->getIdentifyDialog(true); id->displayContourCell(selectedContourCell, getModelViewNumber()); } } */ } // if (mouseMode == VIEW_MODE) GuiBrainModelOpenGL::updateAllGL(); } /** * key processing for translation axes. */ void GuiBrainModelOpenGL::keyTranslationAxes(GuiBrainModelOpenGLKeyEvent& ke) { TransformationMatrixFile* tmf = theMainWindow->getBrainSet(getModelViewNumber())->getTransformationMatrixFile(); const int indx = tmf->getSelectedTransformationAxesIndex(); if ((indx < 0) || (indx >= tmf->getNumberOfMatrices())) { return; } if (keyUpLastTime) { GuiTransformationMatrixDialog* tmd = theMainWindow->getTransformMatrixEditor(); if (tmd != NULL) { tmd->axesEventInMainWindow(); } } TransformationMatrix* tm = tmf->getTransformationMatrix(indx); BrainModelSurface* bms = getDisplayedBrainModelSurface(); if (bms == NULL) { bms = getDisplayedBrainModelSurfaceAndVolume(); } vtkTransform* surfRotMatrix = NULL; if (bms != NULL) { surfRotMatrix = bms->getRotationTransformMatrix(viewingWindowIndex); } else { BrainModelVolume* bmv = getDisplayedBrainModelVolume(); if (bmv != NULL) { surfRotMatrix = bmv->getRotationTransformMatrix(viewingWindowIndex); } //std::cout << "ERROR: No surface but doing translation axes." << std::endl; } // // Panning and zooming // float dt[4] = { 0.0, 0.0, 0.0, 1.0 }; if ((ke.key == Qt::Key_Left) && ke.shiftKeyDown) { if (ke.altKeyDown) { dt[0] = -1; } else { dt[0] = -5; } } if ((ke.key == Qt::Key_Right) && ke.shiftKeyDown) { if (ke.altKeyDown) { dt[0] = 1; } else { dt[0] = 5; } } if ((ke.key == Qt::Key_Up) && ke.shiftKeyDown) { if (ke.altKeyDown) { dt[1] = 1; } else { dt[1] = 5; } } if ((ke.key == Qt::Key_Down) && ke.shiftKeyDown) { if (ke.altKeyDown) { dt[1] = -1; } else { dt[1] = -5; } } if ((ke.key == Qt::Key_Up) && (ke.controlKeyDown)) { if (ke.altKeyDown) { dt[2] = -1; } else { dt[2] = -5; } } if ((ke.key == Qt::Key_Down) && (ke.controlKeyDown)) { if (ke.altKeyDown) { dt[2] = 1; } else { dt[2] = 5; } } if ((dt[0] != 0.0) || (dt[1] != 0.0) || (dt[2] != 0.0)) { /* if (surfRotMatrix != NULL) { float dt2[4]; surfRotMatrix->MultiplyPoint(dt, dt2); dt[0] = dt2[0]; dt[1] = dt2[1]; dt[2] = dt2[2]; } tm->translate(dt[0], dt[1], dt[2]); */ const double txyz[3] = { dt[0], dt[1], dt[2] }; tm->translate(txyz, surfRotMatrix); theMainWindow->updateTransformationMatrixEditor(tm); updateAllGL(); ke.setKeyEventUsed(true); return; } // // Rotation // if ((ke.shiftKeyDown == false) && (ke.controlKeyDown == false)) { float rotX = 0.0, rotY = 0.0, rotZ = 0.0; if (ke.key == Qt::Key_Left) { if (ke.altKeyDown) { rotY = -1; } else { rotY = -5; } } if (ke.key == Qt::Key_Right) { if (ke.altKeyDown) { rotY = 1; } else { rotY = 5; } } if (ke.key == Qt::Key_Up) { if (ke.altKeyDown) { rotX = -1; } else { rotX = -5; } } if (ke.key == Qt::Key_Down) { if (ke.altKeyDown) { rotX = 1; } else { rotX = 5; } } if (ke.key == Qt::Key_PageUp) { if (ke.altKeyDown) { rotZ = 1; } else { rotZ = 5; } } if (ke.key == Qt::Key_PageDown) { if (ke.altKeyDown) { rotZ = -1; } else { rotZ = -5; } } if ((rotX != 0.0) || (rotY != 0.0) || (rotZ != 0.0)) { /* if (surfRotMatrix != NULL) { float dt[4] = { rotX, rotY, rotZ, 1.0 }; float dt2[4]; surfRotMatrix->MultiplyPoint(dt, dt2); rotX = dt2[0]; rotY = dt2[1]; rotZ = dt2[2]; } if (rotX != 0.0) { tm->rotateX(rotX); } if (rotY != 0.0) { tm->rotateY(rotY); } if (rotZ != 0.0) { tm->rotateZ(rotZ); } */ // // Alter the rotation angles using the surface viewing matrix // TransformationMatrix t2; if (surfRotMatrix != NULL) { t2.setMatrix(surfRotMatrix); } float r[3] = { rotX, rotY, rotZ }; t2.multiplyPoint(r); // // Create a matrix containing the rotations // TransformationMatrix t3; t3.rotateZ(r[2]); t3.rotateX(r[0]); t3.rotateY(r[1]); // // Remove translation from axes matrix, // Multiply axes matrix by rotation matrix // Add translation back to axes matrix // float tx, ty, tz; tm->getTranslation(tx, ty, tz); tm->translate(-tx, -ty, -tz); tm->preMultiply(t3); tm->translate(tx, ty, tz); theMainWindow->updateTransformationMatrixEditor(tm); updateAllGL(); ke.setKeyEventUsed(true); return; } // // Reset view // if (ke.key == Qt::Key_Home) { tm->identity(); theMainWindow->updateTransformationMatrixEditor(tm); ke.setKeyEventUsed(true); updateAllGL(); return; } } } /** * key processing for contours. */ void GuiBrainModelOpenGL::keyContourView(GuiBrainModelOpenGLKeyEvent& ke) { BrainModelContours* bmc = getDisplayedBrainModelContours(); if (bmc == NULL) { return; } // // Panning // float dt[3] = { 0, 0, 0 }; if ((ke.key == Qt::Key_Left) && ke.shiftKeyDown) { if (ke.altKeyDown) { dt[0] = -1; } else { dt[0] = -5; } } if ((ke.key == Qt::Key_Right) && ke.shiftKeyDown) { if (ke.altKeyDown) { dt[0] = 1; } else { dt[0] = 5; } } if ((ke.key == Qt::Key_Up) && ke.shiftKeyDown) { if (ke.altKeyDown) { dt[1] = 1; } else { dt[1] = 5; } } if ((ke.key == Qt::Key_Down) && ke.shiftKeyDown) { if (ke.altKeyDown) { dt[1] = -1; } else { dt[1] = -5; } } if ((dt[0] != 0.0) || (dt[1] != 0.0) || (dt[2] != 0.0)) { float translate[3]; bmc->getTranslation(viewingWindowIndex, translate); translate[0] += dt[0]; translate[1] += dt[1]; translate[2] = dt[2]; bmc->setTranslation(viewingWindowIndex, translate); updateAllGL(this); ke.setKeyEventUsed(true); return; } // // Do zooming // float dZoom = 0.0; if ((ke.key == Qt::Key_Up) && (ke.controlKeyDown)) { if (ke.altKeyDown) { dZoom = 1; } else { dZoom = 5; } } else if ((ke.key == Qt::Key_Down) && (ke.controlKeyDown)) { if (ke.altKeyDown) { dZoom = -1; } else { dZoom = -5; } } if (dZoom != 0.0) { float scale[3]; bmc->getScaling(viewingWindowIndex, scale); scale[0] += dZoom * scale[0] * 0.01; scale[1] += dZoom * scale[1] * 0.01; scale[0] = std::max(scale[0], 0.01f); scale[1] = std::max(scale[1], 0.01f); scale[2] = 1.0; bmc->setScaling(viewingWindowIndex, scale); ke.setKeyEventUsed(true); updateAllGL(this); return; } // // Reset view // if (ke.key == Qt::Key_Home) { bmc->setToStandardView(viewingWindowIndex, BrainModelSurface::VIEW_RESET); ke.setKeyEventUsed(true); updateAllGL(this); return; } } /** * key processing for surface. */ void GuiBrainModelOpenGL::keySurfaceView(GuiBrainModelOpenGLKeyEvent& ke) { BrainModelSurface* bms = getDisplayedBrainModelSurface(); DisplaySettingsSurface* dss = theMainWindow->getBrainSet(getModelViewNumber())->getDisplaySettingsSurface(); // // The Caret Main Window BrainModelSurface is used when yoking. It is NULL // if the Caret Main Window contains a volume or contours. When doing a yoked // surface, the transformations associated with the Caret Main Window are upated. // BrainModelSurface* mainWindowModelSurface = theMainWindow->getBrainModelSurface(); int mainWindowModelViewNumber = -1; bool yokeIt = false; if (mainWindowModelSurface != NULL) { mainWindowModelViewNumber = allBrainSurfaceOpenGL[BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW]->getModelViewNumber(); yokeIt = getYokeView(); } // // Panning // float dt[3] = { 0, 0, 0 }; if ((ke.key == Qt::Key_Left) && ke.shiftKeyDown) { if (ke.altKeyDown) { dt[0] = -1; } else { dt[0] = -5; } } if ((ke.key == Qt::Key_Right) && ke.shiftKeyDown) { if (ke.altKeyDown) { dt[0] = 1; } else { dt[0] = 5; } } if ((ke.key == Qt::Key_Up) && ke.shiftKeyDown) { if (ke.altKeyDown) { dt[1] = 1; } else { dt[1] = 5; } } if ((ke.key == Qt::Key_Down) && ke.shiftKeyDown) { if (ke.altKeyDown) { dt[1] = -1; } else { dt[1] = -5; } } if ((dt[0] != 0.0) || (dt[1] != 0.0) || (dt[2] != 0.0)) { float translate[3]; bms->getTranslation(viewingWindowIndex, translate); // // If yoked, use main window brain surface model for translation // if (yokeIt) { mainWindowModelSurface->getTranslation(mainWindowModelViewNumber, translate); } translate[0] += dt[0]; translate[1] += dt[1]; translate[2] = dt[2]; // // If yoked, use main window brain surface model for translation // if (yokeIt) { mainWindowModelSurface->setTranslation(mainWindowModelViewNumber, translate); } else { bms->setTranslation(viewingWindowIndex, translate); } if (viewingWindowIndex == BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) { theMainWindow->updateTransformationMatrixEditor(NULL); } updateAllGL(this); ke.setKeyEventUsed(true); return; } // // Do zooming // float dZoom = 0.0; if ((ke.key == Qt::Key_Up) && (ke.controlKeyDown)) { if (ke.altKeyDown) { dZoom = 1; } else { dZoom = 5; } } else if ((ke.key == Qt::Key_Down) && (ke.controlKeyDown)) { if (ke.altKeyDown) { dZoom = -1; } else { dZoom = -5; } } if (dZoom != 0.0) { switch (dss->getViewingProjection()) { case DisplaySettingsSurface::VIEWING_PROJECTION_ORTHOGRAPHIC: { float scale[3]; bms->getScaling(viewingWindowIndex, scale); // // If yoked, use main window brain surface model for scaling // if (yokeIt) { mainWindowModelSurface->getScaling(mainWindowModelViewNumber, scale); } scale[0] += dZoom * scale[0] * 0.01; scale[1] += dZoom * scale[1] * 0.01; scale[2] += dZoom * scale[2] * 0.01; scale[0] = std::max(scale[0], 0.01f); scale[1] = std::max(scale[1], 0.01f); scale[2] = std::max(scale[2], 0.01f); //if (scale < 0.01) scale = 0.01; // negative would flip surface // // If yoked, use main window brain surface model for scaling // if (yokeIt) { mainWindowModelSurface->setScaling(mainWindowModelViewNumber, scale); } else { bms->setScaling(viewingWindowIndex, scale); } } break; case DisplaySettingsSurface::VIEWING_PROJECTION_PERSPECTIVE: { float zoom = bms->getPerspectiveZooming(viewingWindowIndex); // // If yoked, use main window brain surface model for scaling // if (yokeIt) { zoom = mainWindowModelSurface->getPerspectiveZooming(mainWindowModelViewNumber); } zoom -= (dZoom * 5.0); if (yokeIt) { mainWindowModelSurface->setPerspectiveZooming(mainWindowModelViewNumber, zoom); } else { bms->setPerspectiveZooming(viewingWindowIndex, zoom); } } break; } if (viewingWindowIndex == BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) { theMainWindow->updateTransformationMatrixEditor(NULL); } ke.setKeyEventUsed(true); updateAllGL(this); return; } // // Rotation // if ((ke.shiftKeyDown == false) && (ke.controlKeyDown == false)) { float rotX = 0.0, rotY = 0.0, rotZ = 0.0; if (ke.key == Qt::Key_Left) { if (ke.altKeyDown) { rotY = 1; } else { rotY = 5; } } if (ke.key == Qt::Key_Right) { if (ke.altKeyDown) { rotY = -1; } else { rotY = -5; } } if (ke.key == Qt::Key_Up) { if (ke.altKeyDown) { rotX = 1; } else { rotX = 5; } } if (ke.key == Qt::Key_Down) { if (ke.altKeyDown) { rotX = -1; } else { rotX = -5; } } if (ke.key == Qt::Key_PageUp) { if (ke.altKeyDown) { rotZ = 1; } else { rotZ = 5; } } if (ke.key == Qt::Key_PageDown) { if (ke.altKeyDown) { rotZ = -1; } else { rotZ = -5; } } if ((rotX != 0.0) || (rotY != 0.0) || (rotZ != 0.0)) { vtkTransform* matrix = bms->getRotationTransformMatrix(viewingWindowIndex); // // If yoked, use main window brain surface model for rotation // if (yokeIt) { matrix = mainWindowModelSurface->getRotationTransformMatrix(mainWindowModelViewNumber); } if (rotX != 0.0) { matrix->RotateX(rotX); } if (rotY != 0.0) { matrix->RotateY(rotY); } if (rotZ != 0.0) { matrix->RotateZ(rotZ); } if (viewingWindowIndex == BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) { theMainWindow->updateTransformationMatrixEditor(NULL); } updateAllGL(this); ke.setKeyEventUsed(true); return; } } // // Reset view // if (ke.key == Qt::Key_Home) { bms->setToStandardView(viewingWindowIndex, BrainModelSurface::VIEW_RESET); if (viewingWindowIndex == BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) { theMainWindow->updateTransformationMatrixEditor(NULL); } ke.setKeyEventUsed(true); updateAllGL(this); return; } } /** * key processing for volume. */ void GuiBrainModelOpenGL::keyVolumeView(GuiBrainModelOpenGLKeyEvent& ke) { BrainModelVolume* bmv = getDisplayedBrainModelVolume(); VolumeFile* vf = bmv->getMasterVolumeFile(); const bool drawAll = (bmv->getSelectedAxis(viewingWindowIndex) == VolumeFile::VOLUME_AXIS_OBLIQUE); // // Panning // float dt[3] = { 0, 0, 0 }; if ((ke.key == Qt::Key_Left) && ke.shiftKeyDown) { if (ke.altKeyDown) { dt[0] = -1; } else { dt[0] = -5; } } if ((ke.key == Qt::Key_Right) && ke.shiftKeyDown) { if (ke.altKeyDown) { dt[0] = 1; } else { dt[0] = 5; } } if ((ke.key == Qt::Key_Up) && ke.shiftKeyDown) { if (ke.altKeyDown) { dt[1] = 1; } else { dt[1] = 5; } } if ((ke.key == Qt::Key_Down) && ke.shiftKeyDown) { if (ke.altKeyDown) { dt[1] = -1; } else { dt[1] = -5; } } if ((dt[0] != 0.0) || (dt[1] != 0.0) || (dt[2] != 0.0)) { float translate[3]; bmv->getTranslation(viewingWindowIndex, translate); translate[0] += dt[0]; translate[1] += dt[1]; translate[2] = dt[2]; bmv->setTranslation(viewingWindowIndex, translate); if (viewingWindowIndex == BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) { theMainWindow->updateTransformationMatrixEditor(NULL); } if (drawAll) { updateAllGL(); } else { updateAllGL(this); } ke.setKeyEventUsed(true); return; } // // Do zooming // float dZoom = 0.0; if ((ke.key == Qt::Key_Up) && (ke.controlKeyDown)) { if (ke.altKeyDown) { dZoom = 1; } else { dZoom = 5; } } else if ((ke.key == Qt::Key_Down) && (ke.controlKeyDown)) { if (ke.altKeyDown) { dZoom = -1; } else { dZoom = -5; } } if (dZoom != 0.0) { float scale[3]; bmv->getScaling(viewingWindowIndex, scale); scale[0] += dZoom * scale[0] * 0.01; scale[1] += dZoom * scale[1] * 0.01; scale[2] += dZoom * scale[2] * 0.01; scale[0] = std::max(scale[0], 0.01f); scale[1] = std::max(scale[1], 0.01f); scale[2] = std::max(scale[2], 0.01f); //if (scale < 0.01) scale = 0.01; // negative would flip surface bmv->setScaling(viewingWindowIndex, scale); if (viewingWindowIndex == BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) { theMainWindow->updateTransformationMatrixEditor(NULL); } if (drawAll) { updateAllGL(); } else { updateAllGL(this); } ke.setKeyEventUsed(true); return; } if (vf != NULL) { // // get dimensions of volume // int dim[3]; vf->getDimensions(dim); if ((ke.key == Qt::Key_PageUp) || (ke.key == Qt::Key_PageDown)) { // // Get the current slices displayed // int orthogonalSlices[3]; bmv->getSelectedOrthogonalSlices(viewingWindowIndex, orthogonalSlices); int obliqueSlices[3]; bmv->getSelectedObliqueSlices(obliqueSlices); int obliqueSliceOffsets[3]; bmv->getSelectedObliqueSliceOffsets(viewingWindowIndex, obliqueSliceOffsets); // // Change the selected slices // int indx = -1; switch (bmv->getSelectedAxis(viewingWindowIndex)) { case VolumeFile::VOLUME_AXIS_X: indx = 0; break; case VolumeFile::VOLUME_AXIS_Y: indx = 1; break; case VolumeFile::VOLUME_AXIS_Z: indx = 2; break; case VolumeFile::VOLUME_AXIS_ALL: break; case VolumeFile::VOLUME_AXIS_OBLIQUE: indx = 3; break; case VolumeFile::VOLUME_AXIS_OBLIQUE_X: indx = 4; break; case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: indx = 5; break; case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: indx = 6; break; case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } if ((indx >= 0) && (indx <= 2)) { int delta = -1; if (ke.key == Qt::Key_PageUp) { delta = 1; } orthogonalSlices[indx] += delta; orthogonalSlices[indx] = std::max(0, orthogonalSlices[indx]); orthogonalSlices[indx] = std::min(dim[indx] - 1, orthogonalSlices[indx]); bmv->setSelectedOrthogonalSlices(viewingWindowIndex, orthogonalSlices); } else if (indx == 3) { } else if ((indx >= 4) && (indx <= 6)) { int delta = -1; if (ke.key == Qt::Key_PageUp) { delta = 1; } if (indx == 4) { obliqueSliceOffsets[0] += delta; } else if (indx == 5) { obliqueSliceOffsets[1] += delta; } else if (indx == 6) { obliqueSliceOffsets[2] += delta; } bmv->setSelectedObliqueSliceOffsets(viewingWindowIndex, obliqueSliceOffsets); } // // Update the toolbars // GuiToolBar::updateAllToolBars(false); // // Update the display // if (drawAll) { updateAllGL(); } else { updateAllGL(this); } ke.setKeyEventUsed(true); return; } } // // Reset view // if (ke.key == Qt::Key_Home) { bmv->resetViewingTransform(viewingWindowIndex); if (viewingWindowIndex == BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) { theMainWindow->updateTransformationMatrixEditor(NULL); } if (drawAll) { updateAllGL(); } else { updateAllGL(this); } ke.setKeyEventUsed(true); return; } } /** * key processing for surface and volume. */ void GuiBrainModelOpenGL::keySurfaceAndVolumeView(GuiBrainModelOpenGLKeyEvent& ke) { BrainModelSurfaceAndVolume* bmsv = getDisplayedBrainModelSurfaceAndVolume(); DisplaySettingsSurface* dss = theMainWindow->getBrainSet(getModelViewNumber())->getDisplaySettingsSurface(); // // Panning // float dt[3] = { 0, 0, 0 }; if ((ke.key == Qt::Key_Left) && ke.shiftKeyDown) { if (ke.altKeyDown) { dt[0] = -1; } else { dt[0] = -5; } } if ((ke.key == Qt::Key_Right) && ke.shiftKeyDown) { if (ke.altKeyDown) { dt[0] = 1; } else { dt[0] = 5; } } if ((ke.key == Qt::Key_Up) && ke.shiftKeyDown) { if (ke.altKeyDown) { dt[1] = 1; } else { dt[1] = 5; } } if ((ke.key == Qt::Key_Down) && ke.shiftKeyDown) { if (ke.altKeyDown) { dt[1] = -1; } else { dt[1] = -5; } } if ((dt[0] != 0.0) || (dt[1] != 0.0) || (dt[2] != 0.0)) { float translate[3]; bmsv->getTranslation(viewingWindowIndex, translate); translate[0] += dt[0]; translate[1] += dt[1]; translate[2] = dt[2]; bmsv->setTranslation(viewingWindowIndex, translate); if (viewingWindowIndex == BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) { theMainWindow->updateTransformationMatrixEditor(NULL); } updateAllGL(this); ke.setKeyEventUsed(true); return; } // // Rotation // if ((ke.shiftKeyDown == false) && (ke.controlKeyDown == false)) { float rotX = 0.0, rotY = 0.0, rotZ = 0.0; if (ke.key == Qt::Key_Left) { if (ke.altKeyDown) { rotY = -1; } else { rotY = -5; } } if (ke.key == Qt::Key_Right) { if (ke.altKeyDown) { rotY = 1; } else { rotY = 5; } } if (ke.key == Qt::Key_Up) { if (ke.altKeyDown) { rotX = 1; } else { rotX = 5; } } if (ke.key == Qt::Key_Down) { if (ke.altKeyDown) { rotX = -1; } else { rotX = -5; } } if (ke.key == Qt::Key_PageUp) { if (ke.altKeyDown) { rotZ = 1; } else { rotZ = 5; } } if (ke.key == Qt::Key_PageDown) { if (ke.altKeyDown) { rotZ = -1; } else { rotZ = -5; } } if ((rotX != 0.0) || (rotY != 0.0) || (rotZ != 0.0)) { vtkTransform* matrix = bmsv->getRotationTransformMatrix(viewingWindowIndex); if (rotX != 0.0) { matrix->RotateX(rotX); } if (rotY != 0.0) { matrix->RotateY(rotY); } if (rotZ != 0.0) { matrix->RotateZ(rotZ); } if (viewingWindowIndex == BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) { theMainWindow->updateTransformationMatrixEditor(NULL); } updateAllGL(this); ke.setKeyEventUsed(true); return; } } // // Do zooming // float dZoom = 0.0; if ((ke.key == Qt::Key_Up) && (ke.controlKeyDown)) { if (ke.altKeyDown) { dZoom = 1; } else { dZoom = 5; } } else if ((ke.key == Qt::Key_Down) && (ke.controlKeyDown)) { if (ke.altKeyDown) { dZoom = -1; } else { dZoom = -5; } } if (dZoom != 0.0) { switch (dss->getViewingProjection()) { case DisplaySettingsSurface::VIEWING_PROJECTION_ORTHOGRAPHIC: { float scale[3]; bmsv->getScaling(viewingWindowIndex, scale); scale[0] += dZoom * scale[0] * 0.01; scale[1] += dZoom * scale[1] * 0.01; scale[2] += dZoom * scale[2] * 0.01; scale[0] = std::max(scale[0], 0.01f); scale[1] = std::max(scale[1], 0.01f); scale[2] = std::max(scale[2], 0.01f); //if (scale < 0.01) scale = 0.01; // negative would flip surface bmsv->setScaling(viewingWindowIndex, scale); } break; case DisplaySettingsSurface::VIEWING_PROJECTION_PERSPECTIVE: { float zoom = bmsv->getPerspectiveZooming(viewingWindowIndex); zoom -= (dZoom * 5.0); bmsv->setPerspectiveZooming(viewingWindowIndex, zoom); } break; } if (viewingWindowIndex == BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) { theMainWindow->updateTransformationMatrixEditor(NULL); } updateAllGL(this); ke.setKeyEventUsed(true); return; } // // Reset view // if (ke.key == Qt::Key_Home) { bmsv->setToStandardView(viewingWindowIndex, BrainModelSurfaceAndVolume::VIEW_RESET); if (viewingWindowIndex == BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) { theMainWindow->updateTransformationMatrixEditor(NULL); } updateAllGL(this); ke.setKeyEventUsed(true); return; } } /** * Gets called by QT when a key is released. */ void GuiBrainModelOpenGL::keyReleaseEvent(QKeyEvent* /*ke*/) { keyUpLastTime = true; } /** * Called by QT when a key is pressed. */ void GuiBrainModelOpenGL::keyPressEvent(QKeyEvent* ke) { GuiBrainModelOpenGLKeyEvent kv(ke->key(), (ke->modifiers() & Qt::ShiftModifier), (ke->modifiers() & Qt::AltModifier), (ke->modifiers() & Qt::ControlModifier)); kv.debug(); if (kv.controlKeyDown && (kv.key >= Qt::Key_F1) && (kv.key <= Qt::Key_F15)) { const int modelIndex = kv.key - Qt::Key_F1; if ((modelIndex >= 0) && (modelIndex < theMainWindow->getBrainSet(getModelViewNumber())->getNumberOfBrainModels())) { setDisplayedBrainModelIndex(modelIndex); // // Update the toolbars // GuiToolBar::updateAllToolBars(false); updateGL(); } kv.setKeyEventUsed(true); } if (kv.getKeyEventUsed() == false) { switch(getMouseMode()) { case GuiBrainModelOpenGL::MOUSE_MODE_NONE: break; case GuiBrainModelOpenGL::MOUSE_MODE_VIEW: break; case GuiBrainModelOpenGL::MOUSE_MODE_BORDER_DRAW: break; case MOUSE_MODE_BORDER_DRAW_NEW: break; case GuiBrainModelOpenGL::MOUSE_MODE_BORDER_DELETE: break; case GuiBrainModelOpenGL::MOUSE_MODE_BORDER_DELETE_POINT: break; case GuiBrainModelOpenGL::MOUSE_MODE_BORDER_INTERPOLATE: break; case MOUSE_MODE_BORDER_INTERPOLATE_NEW: break; case GuiBrainModelOpenGL::MOUSE_MODE_BORDER_MOVE_POINT: break; case GuiBrainModelOpenGL::MOUSE_MODE_BORDER_REVERSE: break; case GuiBrainModelOpenGL::MOUSE_MODE_BORDER_UPDATE: break; case MOUSE_MODE_BORDER_UPDATE_NEW: break; case GuiBrainModelOpenGL::MOUSE_MODE_BORDER_RENAME: break; case GuiBrainModelOpenGL::MOUSE_MODE_CUT_DRAW: break; case GuiBrainModelOpenGL::MOUSE_MODE_CUT_DELETE: break; case GuiBrainModelOpenGL::MOUSE_MODE_FOCI_DELETE: break; case GuiBrainModelOpenGL::MOUSE_MODE_CELL_ADD: break; case GuiBrainModelOpenGL::MOUSE_MODE_CELL_DELETE: break; case GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_BORDER_SELECT: break; case GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_PAINT_INDEX_SELECT: break; case GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_METRIC_NODE_SELECT: break; case GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_SHAPE_NODE_SELECT: break; case GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_GEODESIC_NODE_SELECT: break; case GuiBrainModelOpenGL::MOUSE_MODE_ALIGN_STANDARD_ORIENTATION: break; case MOUSE_MODE_ALIGN_STANDARD_ORIENTATION_FULL_HEM_FLATTEN: break; case GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_SET_SCALE: break; case GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_DRAW: break; case GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_ALIGN: break; case GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_ALIGN_REGION: break; case GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_POINT_MOVE: break; case GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_POINT_DELETE: break; case GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_DELETE: break; case GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_REVERSE: break; case GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_MERGE: break; case GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_CELL_ADD: break; case GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_CELL_DELETE: break; case GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_CELL_MOVE: break; case GuiBrainModelOpenGL::MOUSE_MODE_VOLUME_SEGMENTATION_EDIT: break; case GuiBrainModelOpenGL::MOUSE_MODE_EDIT_ADD_NODE: break; case GuiBrainModelOpenGL::MOUSE_MODE_EDIT_ADD_TILE: break; case GuiBrainModelOpenGL::MOUSE_MODE_EDIT_DELETE_TILE_BY_LINK: break; case GuiBrainModelOpenGL::MOUSE_MODE_EDIT_DISCONNECT_NODE: break; case GuiBrainModelOpenGL::MOUSE_MODE_EDIT_MOVE_NODE: break; case GuiBrainModelOpenGL::MOUSE_MODE_TRANSFORMATION_MATRIX_AXES: keyTranslationAxes(kv); break; case GuiBrainModelOpenGL::MOUSE_MODE_TRANSFORMATION_MATRIX_SET_TRANSLATE: break; case GuiBrainModelOpenGL::MOUSE_MODE_VOLUME_PAINT_EDIT: break; case GuiBrainModelOpenGL::MOUSE_MODE_IMAGE_SUBREGION: break; case GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_SULCAL_BORDER_NODE_START: break; case GuiBrainModelOpenGL::MOUSE_MODE_SURFACE_ROI_SULCAL_BORDER_NODE_END: break; } } if (kv.getKeyEventUsed() == false) { if (getDisplayedBrainModelSurfaceAndVolume() != NULL) { keySurfaceAndVolumeView(kv); } else if (getDisplayedBrainModelSurface() != NULL) { keySurfaceView(kv); } else if (getDisplayedBrainModelVolume() != NULL) { keyVolumeView(kv); } else if (getDisplayedBrainModelContours() != NULL) { keyContourView(kv); } } if (kv.getKeyEventUsed() == false) { // // Key processing with no modifiers - standard views // int modelNum = viewingWindowIndex; BrainModelSurface* bms = getDisplayedBrainModelSurfaceAndVolume(); if (bms == NULL) { bms = getDisplayedBrainModelSurface(); if (bms != NULL) { if (viewingWindowIndex != BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) { if (getYokeView()) { bms = allBrainSurfaceOpenGL[BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW]->getDisplayedBrainModelSurface(); modelNum = BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW; } } } } if (bms != NULL) { switch (kv.key) { case Qt::Key_A: bms->setToStandardView(modelNum, BrainModelSurface::VIEW_ANTERIOR); kv.setKeyEventUsed(true); break; case Qt::Key_D: bms->setToStandardView(modelNum, BrainModelSurface::VIEW_DORSAL); kv.setKeyEventUsed(true); break; case Qt::Key_L: bms->setToStandardView(modelNum, BrainModelSurface::VIEW_LATERAL); kv.setKeyEventUsed(true); break; case Qt::Key_M: bms->setToStandardView(modelNum, BrainModelSurface::VIEW_MEDIAL); kv.setKeyEventUsed(true); break; case Qt::Key_P: bms->setToStandardView(modelNum, BrainModelSurface::VIEW_POSTERIOR); kv.setKeyEventUsed(true); break; case Qt::Key_R: bms->setToStandardView(modelNum, BrainModelSurface::VIEW_RESET); kv.setKeyEventUsed(true); break; case Qt::Key_V: bms->setToStandardView(modelNum, BrainModelSurface::VIEW_VENTRAL); kv.setKeyEventUsed(true); break; } updateAllGL(this); } } keyUpLastTime = false; if (kv.getKeyEventUsed()) { ke->accept(); } else { ke->ignore(); } } /** * Change the mouse mode */ void GuiBrainModelOpenGL::setMouseMode(const GuiBrainModelOpenGL::MOUSE_MODES mm) { // // Ignore mouse mode commands for all but main window // if (isMainWindowOpenGL() == false) { if (mm != MOUSE_MODE_VIEW) { return; } } bool needReDrawFlag = false; newTileNodeNumbers[0] = -1; newTileNodeNumbers[1] = -1; newTileNodeNumbers[2] = -1; newTileNodeCounter = 0; const MOUSE_MODES oldMouseMode = mouseMode; if ((mouseMode == MOUSE_MODE_BORDER_DRAW) || (mouseMode == MOUSE_MODE_BORDER_DRAW_NEW) || (mouseMode == MOUSE_MODE_BORDER_MOVE_POINT)) { QApplication::restoreOverrideCursor(); } mouseMode = mm; if (linearObjectBeingDrawn.getNumberOfLinks() > 0) { needReDrawFlag = true; } resetLinearObjectBeingDrawn(); theMainWindow->getToolBar()->updateMouseModeComboBox(); theMainWindow->updateStatusBarLabel(); if (mouseMode == MOUSE_MODE_TRANSFORMATION_MATRIX_AXES) { needReDrawFlag = true; } else if (oldMouseMode == MOUSE_MODE_TRANSFORMATION_MATRIX_AXES) { TransformationMatrixFile* tmf = theMainWindow->getBrainSet(getModelViewNumber())->getTransformationMatrixFile(); tmf->setSelectedTransformationAxesIndex(-1); needReDrawFlag = true; } if (mouseMode != MOUSE_MODE_IMAGE_SUBREGION) { imageSubRegionBoxValid = false; } else if (mouseMode == MOUSE_MODE_IMAGE_SUBREGION) { imageSubRegionBoxValid = getCaptureImageSubRegionValid(); } if (needReDrawFlag) { updateAllGL(); } } /** * Called by QT when the mouse button pressed. */ void GuiBrainModelOpenGL::mousePressEvent(QMouseEvent* me) { const bool splashImageWasOn = theMainWindow->getBrainSet(getModelViewNumber())->getDisplaySplashImage(); theMainWindow->getBrainSet(getModelViewNumber())->setDisplaySplashImage(false); Qt::KeyboardModifiers bs = me->modifiers(); Qt::MouseButton button = me->button(); const int mouseX = me->x(); const int mouseY = me->y(); if (button == Qt::LeftButton) { // // Create the mouse event // GuiBrainModelOpenGLMouseEvent::BMO_MOUSE_EVENT theEvent = GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE; bool validMode = false; // // Mouse moved with just left button down // if (bs == leftMouseButtonPressMask) { validMode = true; theEvent = GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS; } // // Mouse moved with control key and left mouse button down // else if (bs == leftControlMouseButtonPressMask) { validMode = true; theEvent = GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS; } // // Mouse moved with shift key and left mouse button down // else if (bs == leftShiftMouseButtonPressMask) { validMode = true; theEvent = GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS; } // // If valid mouse/key combination // if (validMode) { // // Process the mouse event // GuiBrainModelOpenGLMouseEvent mouseEvent(theEvent, mouseX, mouseY, 0, 0); routeMouseEvent(mouseEvent); } } else if (button == Qt::RightButton) { if (getDisplayedBrainModelSurface() != NULL) { // // Perform an ID operation // Change the mouse mode to prevent identification from occurring. // const MOUSE_MODES savedMouseMode = mouseMode; mouseMode = MOUSE_MODE_NONE; selectBrainModelItem(mouseX, mouseY, BrainModelOpenGL::SELECTION_MASK_ALL); mouseMode = savedMouseMode; // // Find the identified items // std::vector items; if (selectedNode.getItemIndex1() >= 0) items.push_back(selectedNode); if (selectedBorder1.getItemIndex1() >= 0) items.push_back(selectedBorder1); if (selectedBorder2.getItemIndex1() >= 0) items.push_back(selectedBorder2); if (selectedCellProjection.getItemIndex1() >= 0) items.push_back(selectedCellProjection); if (selectedVolumeCell.getItemIndex1() >= 0) items.push_back(selectedVolumeCell); if (selectedCut.getItemIndex1() >= 0) items.push_back(selectedCut); if (selectedFocusProjection.getItemIndex1() >= 0) items.push_back(selectedFocusProjection); if (selectedVolumeFoci.getItemIndex1() >= 0) items.push_back(selectedVolumeFoci); if (selectedPaletteMetric.getItemIndex1() >= 0) items.push_back(selectedPaletteMetric); if (selectedPaletteShape.getItemIndex1() >= 0) items.push_back(selectedPaletteShape); if (selectedContour.getItemIndex1() >= 0) items.push_back(selectedContour); if (selectedContourCell.getItemIndex1() >= 0) items.push_back(selectedContourCell); if (selectedVoxelUnderlay.getItemIndex1() >= 0) items.push_back(selectedVoxelUnderlay); if (selectedVoxelOverlaySecondary.getItemIndex1() >= 0) items.push_back(selectedVoxelOverlaySecondary); if (selectedVoxelOverlayPrimary.getItemIndex1() >= 0) items.push_back(selectedVoxelOverlayPrimary); if (selectedVoxelFunctionalCloud.getItemIndex1() >= 0) items.push_back(selectedVoxelFunctionalCloud); if (selectedLink.getItemIndex1() >= 0) items.push_back(selectedLink); if (selectedTransformationAxes.getItemIndex1() >= 0) items.push_back(selectedTransformationAxes); if (selectedVtkModel.getItemIndex1() >= 0) items.push_back(selectedVtkModel); if (selectedTransformCell.getItemIndex1() >= 0) items.push_back(selectedTransformCell); if (selectedTransformFocus.getItemIndex1() >= 0) items.push_back(selectedTransformFocus); // // Update and popup the popup menu // popupMenu->setSelectedItems(items); popupMenu->exec(QCursor::pos()); updateGL(); } } lastMouseX = mouseX; lastMouseY = mouseY; mousePressX = mouseX; mousePressY = mouseY; mouseMovedBounds[0] = mouseX; mouseMovedBounds[1] = mouseY; mouseMovedBounds[2] = mouseX; mouseMovedBounds[3] = mouseY; if (splashImageWasOn) { updateAllGL(NULL); } } /** * Called by QT when the mouse button is released. */ void GuiBrainModelOpenGL::mouseReleaseEvent(QMouseEvent* me) { const int x = me->x(); const int y = me->y(); mouseMovedBounds[0] = std::min(mouseMovedBounds[0], x); mouseMovedBounds[1] = std::min(mouseMovedBounds[1], y); mouseMovedBounds[2] = std::max(mouseMovedBounds[2], x); mouseMovedBounds[3] = std::max(mouseMovedBounds[3], y); if ((me->button() == Qt::LeftButton) && (me->button() == Qt::LeftButton)) { // // // Perform an ID operation if the minimum and maximum position of the mouse // while the mouse button was held down is very small. // const int dx = static_cast(fabs(static_cast(mouseMovedBounds[0] - mouseMovedBounds[2]))); const int dy = static_cast(fabs(static_cast(mouseMovedBounds[1] - mouseMovedBounds[3]))); if ((dx <= mouseMoveTolerance) && (dy <= mouseMoveTolerance)) { // // Create the mouse event // GuiBrainModelOpenGLMouseEvent mouseEvent( GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK, x, y, 0, 0); routeMouseEvent(mouseEvent); } else { // // Create the mouse event // GuiBrainModelOpenGLMouseEvent mouseEvent( GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE, x, y, 0, 0); routeMouseEvent(mouseEvent); } } } /** * Convert window coords to model coords */ bool GuiBrainModelOpenGL::convertWindowToModelCoords(const int windowX, const int windowY, const bool useZBufferForWindowZ, float& modelX, float& modelY, float& modelZ) { GLdouble winx, winy, winz, objx, objy, objz; GLint* selectionViewport = openGL->getSelectionViewport(viewingWindowIndex); winx = windowX; winy = selectionViewport[3] - windowY; winz = 0.0; if (useZBufferForWindowZ) { updateAllGL(this); GLfloat zDepth = 0.0; glReadPixels(windowX, selectionViewport[3] - windowY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &zDepth); winz = zDepth; } if(gluUnProject(winx, winy, winz, openGL->getSelectionModelviewMatrix(viewingWindowIndex), openGL->getSelectionProjectionMatrix(viewingWindowIndex), selectionViewport, &objx, &objy, &objz) == GL_FALSE) { std::cerr << "PROGRAM ERROR: gluUnProject failed!" << std::endl; modelX = 0; modelY = 0; modelZ = 0; return false; } modelX = objx; modelY = objy; modelZ = objz; return true; } /** * Called by QT when the mouse is moved with the mouse button held down. */ void GuiBrainModelOpenGL::mouseMoveEvent(QMouseEvent* me) { Qt::KeyboardModifiers bs = me->modifiers(); Qt::MouseButtons button = me->buttons(); const int x = me->x(); const int y = me->y(); if (DebugControl::getDebugOn()) { std::cout << "Button State: " << (int)bs << std::endl; std::cout << "Button " << (int)button << std::endl; } mouseMovedBounds[0] = std::min(mouseMovedBounds[0], x); mouseMovedBounds[1] = std::min(mouseMovedBounds[1], y); mouseMovedBounds[2] = std::max(mouseMovedBounds[2], x); mouseMovedBounds[3] = std::max(mouseMovedBounds[3], y); const int dx = static_cast(fabs(static_cast(mouseMovedBounds[0] - mouseMovedBounds[2]))); const int dy = static_cast(fabs(static_cast(mouseMovedBounds[1] - mouseMovedBounds[3]))); bool doIt = true; if (mouseMode == MOUSE_MODE_VIEW) { // // Ignore very small movements in view mode to allow ID operation // if ((dx <= mouseMoveTolerance) && (dy <= mouseMoveTolerance)) { doIt = false; } } if (doIt) { //QT4if (bs & leftMouseButtonMoveMask) { if (button == Qt::LeftButton) { // // Create the mouse event // GuiBrainModelOpenGLMouseEvent::BMO_MOUSE_EVENT theEvent = GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE; bool validMode = false; // // Mouse moved with just left button down // if (bs == leftMouseButtonMoveMask) { validMode = true; theEvent = GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE; } // // Mouse moved with control key and left mouse button down // else if (bs == leftControlMouseButtonMoveMask) { validMode = true; theEvent = GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE; } // // Mouse moved with shift key and left mouse button down // else if (bs == leftShiftMouseButtonMoveMask) { validMode = true; theEvent = GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE; } // // Mouse moved with alt key and left mouse button down // else if (bs == leftAltMouseButtonMoveMask) { validMode = true; theEvent = GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE; } // // If valid mouse/key combination // if (validMode) { // // Compute change in mouse position // PreferencesFile* pf = theMainWindow->getBrainSet(getModelViewNumber())->getPreferencesFile(); const float multiplier = pf->getMouseSpeed(); const int dx = static_cast((x - lastMouseX) * multiplier); const int dy = static_cast((lastMouseY - y) * multiplier); // origin at top // // Process the mouse event // GuiBrainModelOpenGLMouseEvent mouseEvent(theEvent, x, y, dx, dy); routeMouseEvent(mouseEvent); } } } lastMouseX = x; lastMouseY = y; } /** * Get the brain set for this OpenGL Widget. */ BrainSet* GuiBrainModelOpenGL::getBrainSet() { return theMainWindow->getBrainSet(getModelViewNumber()); } /** * Get the index of the brain model displayed in this widget */ int GuiBrainModelOpenGL::getDisplayedBrainModelIndex() const { return theMainWindow->getBrainSet(getModelViewNumber())->getDisplayedModelIndexForWindow(viewingWindowIndex); } /** * Set the index of the surface displayed in this widget */ void GuiBrainModelOpenGL::setDisplayedBrainModelIndex(const int newIndex) { if (newIndex < theMainWindow->getBrainSet(getModelViewNumber())->getNumberOfBrainModels()) { theMainWindow->getBrainSet(getModelViewNumber())->setDisplayedModelIndexForWindow(viewingWindowIndex, newIndex); const BrainModelSurface* bms = theMainWindow->getBrainSet(getModelViewNumber())->getBrainModelSurface(newIndex); if (bms != NULL) { bool flatFlag = false; switch (bms->getSurfaceType()) { case BrainModelSurface::SURFACE_TYPE_RAW: break; case BrainModelSurface::SURFACE_TYPE_FIDUCIAL: break; case BrainModelSurface::SURFACE_TYPE_INFLATED: break; case BrainModelSurface::SURFACE_TYPE_VERY_INFLATED: break; case BrainModelSurface::SURFACE_TYPE_SPHERICAL: break; case BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL: break; case BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL: break; case BrainModelSurface::SURFACE_TYPE_FLAT: flatFlag = true; break; case BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR: flatFlag = true; break; case BrainModelSurface::SURFACE_TYPE_HULL: break; case BrainModelSurface::SURFACE_TYPE_UNKNOWN: break; case BrainModelSurface::SURFACE_TYPE_UNSPECIFIED: break; } if (flatFlag) { setRotationAxis(BRAIN_MODEL_ROTATION_AXIS_OFF); } else if (getRotationAxis() == BRAIN_MODEL_ROTATION_AXIS_OFF) { setRotationAxis(BRAIN_MODEL_ROTATION_AXIS_XY); } GuiToolBar::updateAllToolBars(false); } } } /** * Set the brain model displayed in this widget */ void GuiBrainModelOpenGL::setDisplayedBrainModel(const BrainModel* bm) { for (int i = 0; i < theMainWindow->getBrainSet(getModelViewNumber())->getNumberOfBrainModels(); i++) { if (theMainWindow->getBrainSet(getModelViewNumber())->getBrainModel(i) == bm) { setDisplayedBrainModelIndex(i); break; } } } /** * Set the index of the surface displayed in all widgets */ void GuiBrainModelOpenGL::setAllDisplayedBrainModelIndices(const int newIndex) { for (int i = 0; i < BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS; i++) { if (allBrainSurfaceOpenGL[i] != NULL) { allBrainSurfaceOpenGL[i]->setDisplayedBrainModelIndex(newIndex); } } } /** * Redraws OpenGL windows. If "modelToUpdate" is NULL, all windows are redrawn. * If "modelToUpdate" is not NULL, the specified window and any windows yoked to * it are redrawn. */ void GuiBrainModelOpenGL::updateAllGL(GuiBrainModelOpenGL *modelToUpdate) { bool updatedMainWindow = false; if (modelToUpdate != NULL) { modelToUpdate->updateGL(); bool updateAllYoked = false; // // Is this the main window // if (modelToUpdate->viewingWindowIndex == BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) { updateAllYoked = true; updatedMainWindow = true; } else { // // See if this model is yoked // if (modelToUpdate->getYokeView()) { updateAllYoked = true; // // update the main window too // allBrainSurfaceOpenGL[BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW]->updateGL(); updatedMainWindow = true; } } if (updateAllYoked) { // // Update all yoked view except one that was drawing at beginning of method. // for (int i = BrainModel::BRAIN_MODEL_VIEW_AUX_WINDOW_2; i < BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS; i++) { if (allBrainSurfaceOpenGL[i] != NULL) { if (allBrainSurfaceOpenGL[i]->getYokeView()) { if (allBrainSurfaceOpenGL[i] != modelToUpdate) { allBrainSurfaceOpenGL[i]->updateGL(); } } } } } } else { // // Update all models. // for (int i = 0; i < BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS; i++) { if (allBrainSurfaceOpenGL[i] != NULL) { allBrainSurfaceOpenGL[i]->updateGL(); } } updatedMainWindow = true; } // // See if recording is turned on // if (updatedMainWindow) { GuiRecordingDialog* rd = theMainWindow->getRecordingDialog(false); if (rd->getRecordingOn()) { #ifdef Q_OS_WIN32 // // Kludge for windows: If lighting is off (and Caret always draws flat // surfaces with lighting off) the captured images are screwed up. So, make this // flat surface "fiducial" so that its captured image will look normal and // restore the surface type after capturing the image. // BrainModelSurface::SURFACE_TYPES oldSurfaceType = BrainModelSurface::SURFACE_TYPE_UNKNOWN; bool surfaceModified = false; BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { if ((bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FLAT) || (bms->getSurfaceType() == BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR)) { oldSurfaceType = bms->getSurfaceType(); surfaceModified = bms->getCoordinateFile()->getModified(); bms->setSurfaceType(BrainModelSurface::SURFACE_TYPE_FIDUCIAL); } } #endif // Q_OS_WIN32 // // Capture image of main window // QImage image; allBrainSurfaceOpenGL[BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW]->captureImage(image); rd->addImageToRecording(image); #ifdef Q_OS_WIN32 if (oldSurfaceType != BrainModelSurface::SURFACE_TYPE_UNKNOWN) { bms->setSurfaceType(oldSurfaceType); if (surfaceModified == false) { bms->getCoordinateFile()->clearModified(); } } #endif // Q_OS_WIN32 } } // // Clear display lists for any surface that are not displayed // for (int j = 0; j < theMainWindow->getBrainSet(BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW)->getNumberOfBrainModels(); j++) { BrainModelSurface* bms = theMainWindow->getBrainSet(BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW)->getBrainModelSurface(j); if (bms != NULL) { bool found = false; for (int i = 0; i < BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS; i++) { if (allBrainSurfaceOpenGL[i] != NULL) { if (allBrainSurfaceOpenGL[i]->getDisplayedBrainModelSurface() == bms) { found = true; break; } } } if (found == false) { CoordinateFile* cf = bms->getCoordinateFile(); cf->clearDisplayList(); } } } } /** * Save graphics window to image file. * See QImageIO::outputFormats for "format" values. */ bool GuiBrainModelOpenGL::saveImage(const QString& name, const QString& format, const bool addToSpecFile) { // PreferencesFile* pf = theMainWindow->getBrainSet()->getPreferencesFile(); const int imageQuality = 100; // 0 = highly compressed, 100 = uncompressed high quality QImage image; captureImage(image); if (image.save(name, format.toAscii().constData(), imageQuality) == false) { return true; } ImageFile* img = new ImageFile(image); img->setFileName(name); theMainWindow->getBrainSet(getModelViewNumber())->addImageFile(img); if (addToSpecFile) { theMainWindow->getBrainSet(getModelViewNumber())->addToSpecFile(SpecFile::getImageFileTag(), name); } img->clearModified(); // // Files have changed // GuiFilesModified fm; fm.setImagesModified(); theMainWindow->fileModificationUpdate(fm); return false; } /** * get image sub region valid. */ bool GuiBrainModelOpenGL::getCaptureImageSubRegionValid() const { //if (imageSubRegionBoxValid) { const int x1 = std::min(imageSubRegionBox[0], imageSubRegionBox[2]) + 1; const int x2 = std::max(imageSubRegionBox[0], imageSubRegionBox[2]) - 1; const int y1 = std::min(imageSubRegionBox[1], imageSubRegionBox[3]) + 1; const int y2 = std::max(imageSubRegionBox[1], imageSubRegionBox[3]) - 1; // // Width and height of image (do not include subregion lines) // const int w = x2 - x1; const int h = y2 - y1; // // valid if image has width and height // if ((w > 0) && (h > 0)) { return true; } //} return false; } /** * Capture a portion of the image of the current graphics. */ void GuiBrainModelOpenGL::captureImageSubRegion(QImage& image) { // // Capture the image bug turn off the subregion box so it does not show up in image // //openGL->setImageSubRegion(imageSubRegionBox, false); //updateGL(); captureImage(image); //openGL->setImageSubRegion(imageSubRegionBox, imageSubRegionBoxValid); if (imageSubRegionBoxValid) { // // Extent of image // const int x1 = std::min(imageSubRegionBox[0], imageSubRegionBox[2]) + 1; const int x2 = std::max(imageSubRegionBox[0], imageSubRegionBox[2]) - 1; const int y1 = std::min(imageSubRegionBox[1], imageSubRegionBox[3]) + 1; const int y2 = std::max(imageSubRegionBox[1], imageSubRegionBox[3]) - 1; // // Width and height of image (do not include subregion lines) // const int w = x2 - x1; const int h = y2 - y1; if ((w <= 0) || (h <= 0)) { return; } // // Image origin is at top but subregion has origin at bottom // const int windowHeight = height(); const int ypos = windowHeight - (y1 + h); // // Crop the image // image = image.copy(x1, ypos, w, h); } //ImageFile* img = new ImageFile(image); //img->setFileName("subregion.jpg"); //theMainWindow->getBrainSet(getModelViewNumber())->addImageFile(img); } /** * Capture an image of the current graphics. */ void GuiBrainModelOpenGL::captureImage(QImage& image) { PreferencesFile* pf = theMainWindow->getBrainSet(getModelViewNumber())->getPreferencesFile(); // // Display lists do not work during screen capture - do not know why. // So disable display lists, capture image, re-enable display lists. // const bool displayListsValid = pf->getDisplayListsEnabled(); if (displayListsValid) { theMainWindow->getBrainSet(getModelViewNumber())->clearAllDisplayLists(); pf->setDisplayListsEnabled(false); } switch(pf->getImageCaptureType()) { case PreferencesFile::IMAGE_CAPTURE_PIXMAP: { image = renderPixmap().toImage(); } break; case PreferencesFile::IMAGE_CAPTURE_OPENGL_BUFFER: { updateGL(); image = grabFrameBuffer(); } break; } // // Re-enable display lists // if (displayListsValid) { pf->setDisplayListsEnabled(true); } } /** * Returns information about the BrainModelSurface displayed in the caret main window. * If contours or a volume is displayed in the caret main window, false is returned. * true is returned if a surface is in the caret main mindow. * mainCaretWindowModelSurface - Will contain the surface in the caret main window. * NULL if surface not in caret main window. * mainCaretWindowBrainModelOpenGL - Will contain the GuiGrainModelOpenGL widget in * - the caret main window (always valid). * modelViewIndex - surface model index viewed in caret main window. */ bool GuiBrainModelOpenGL::getCaretMainWindowModelInfo( BrainModelSurface*& mainCaretWindowModelSurface, GuiBrainModelOpenGL*& mainCaretWindowBrainModelOpenGL, int& modelViewIndex) { mainCaretWindowBrainModelOpenGL = allBrainSurfaceOpenGL[BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW]; mainCaretWindowModelSurface = mainCaretWindowBrainModelOpenGL->getDisplayedBrainModelSurface(); if (mainCaretWindowModelSurface != NULL) { modelViewIndex = mainCaretWindowBrainModelOpenGL->getModelViewNumber(); return true; } return false; } /** * Route the mouse event to the appropriate handler. */ void GuiBrainModelOpenGL::routeMouseEvent(const GuiBrainModelOpenGLMouseEvent& me) { // // Is this the main window // if (viewingWindowIndex == BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) { switch(mouseMode) { case MOUSE_MODE_NONE: break; case MOUSE_MODE_VIEW: { const BrainModel* bm = getDisplayedBrainModel(); if (bm != NULL) { switch(bm->getModelType()) { case BrainModel::BRAIN_MODEL_CONTOURS: mouseContourView(me); break; case BrainModel::BRAIN_MODEL_SURFACE: mouseSurfaceView(me); break; case BrainModel::BRAIN_MODEL_VOLUME: mouseVolumeView(me); break; case BrainModel::BRAIN_MODEL_SURFACE_AND_VOLUME: mouseSurfaceAndVolumeView(me); break; } } } break; case MOUSE_MODE_BORDER_DRAW: mouseBorderDraw(me); break; case MOUSE_MODE_BORDER_DRAW_NEW: mouseBorderDrawNew(me); break; case MOUSE_MODE_BORDER_DELETE: mouseBorderDelete(me); break; case MOUSE_MODE_BORDER_DELETE_POINT: mouseBorderDeletePoint(me); break; case MOUSE_MODE_BORDER_INTERPOLATE: mouseBorderInterpolate(me); break; case MOUSE_MODE_BORDER_INTERPOLATE_NEW: mouseBorderInterpolateNew(me); break; case MOUSE_MODE_BORDER_MOVE_POINT: mouseBorderMovePoint(me); break; case MOUSE_MODE_BORDER_REVERSE: mouseBorderReverse(me); break; case MOUSE_MODE_BORDER_RENAME: mouseBorderRename(me); break; case MOUSE_MODE_BORDER_UPDATE: mouseBorderUpdate(me); break; case MOUSE_MODE_BORDER_UPDATE_NEW: mouseBorderUpdateNew(me); break; case MOUSE_MODE_CUT_DRAW: mouseCutDraw(me); break; case MOUSE_MODE_CUT_DELETE: mouseCutDelete(me); break; case MOUSE_MODE_FOCI_DELETE: mouseFociDelete(me); break; case MOUSE_MODE_CELL_DELETE: mouseCellDelete(me); break; case MOUSE_MODE_SURFACE_ROI_BORDER_SELECT: mouseSurfaceRoiBorderSelect(me); break; case MOUSE_MODE_SURFACE_ROI_PAINT_INDEX_SELECT: mouseSurfaceRoiPaintSelect(me); break; case MOUSE_MODE_SURFACE_ROI_METRIC_NODE_SELECT: mouseSurfaceRoiMetricSelect(me); break; case MOUSE_MODE_SURFACE_ROI_GEODESIC_NODE_SELECT: mouseSurfaceRoiGeodesicNodeSelect(me); break; case MOUSE_MODE_ALIGN_STANDARD_ORIENTATION: mouseAlignStandardOrientation(me); break; case MOUSE_MODE_ALIGN_STANDARD_ORIENTATION_FULL_HEM_FLATTEN: mouseAlignStandardOrientationFullHemFlatten(me); break; case MOUSE_MODE_CELL_ADD: mouseCellAdd(me); break; case MOUSE_MODE_CONTOUR_SET_SCALE: mouseContourSetScale(me); break; case MOUSE_MODE_CONTOUR_DRAW: mouseContourDraw(me); break; case MOUSE_MODE_CONTOUR_ALIGN: mouseContourAlign(me); break; case MOUSE_MODE_CONTOUR_ALIGN_REGION: mouseContourAlignRegion(me); break; case MOUSE_MODE_CONTOUR_POINT_MOVE: mouseContourPointMove(me); break; case MOUSE_MODE_CONTOUR_POINT_DELETE: mouseContourPointDelete(me); break; case MOUSE_MODE_CONTOUR_DELETE: mouseContourDelete(me); break; case MOUSE_MODE_CONTOUR_REVERSE: mouseContourReverse(me); break; case MOUSE_MODE_CONTOUR_MERGE: mouseContourMerge(me); break; case MOUSE_MODE_CONTOUR_CELL_ADD: mouseContourCellAdd(me); break; case MOUSE_MODE_CONTOUR_CELL_DELETE: mouseContourCellDelete(me); break; case MOUSE_MODE_CONTOUR_CELL_MOVE: mouseContourCellMove(me); break; case MOUSE_MODE_VOLUME_SEGMENTATION_EDIT: mouseVolumeSegmentationEdit(me); break; case MOUSE_MODE_EDIT_ADD_NODE: mouseAddNodes(me); break; case MOUSE_MODE_EDIT_ADD_TILE: mouseAddTile(me); break; case MOUSE_MODE_EDIT_DELETE_TILE_BY_LINK: mouseDeleteTileByLink(me); break; case MOUSE_MODE_EDIT_DISCONNECT_NODE: mouseDisconnectNode(me); break; case MOUSE_MODE_EDIT_MOVE_NODE: mouseMoveNode(me); break; case MOUSE_MODE_SURFACE_ROI_SHAPE_NODE_SELECT: mouseSurfaceRoiShapeSelect(me); break; case MOUSE_MODE_TRANSFORMATION_MATRIX_SET_TRANSLATE: mouseTranslationAxesSetTranslate(me); break; case MOUSE_MODE_TRANSFORMATION_MATRIX_AXES: mouseTranslationAxes(me); break; case MOUSE_MODE_VOLUME_PAINT_EDIT: mouseVolumePaintEdit(me); break; case MOUSE_MODE_IMAGE_SUBREGION: mouseImageSubRegion(me); break; case MOUSE_MODE_SURFACE_ROI_SULCAL_BORDER_NODE_START: mouseSurfaceROISulcalBorderNodeStart(me); break; case MOUSE_MODE_SURFACE_ROI_SULCAL_BORDER_NODE_END: mouseSurfaceROISulcalBorderNodeEnd(me); break; } } else { // // Viewing windows always rotate/scale/pan surface // const BrainModel* bm = getDisplayedBrainModel(); if (bm != NULL) { switch(bm->getModelType()) { case BrainModel::BRAIN_MODEL_CONTOURS: mouseContourView(me); break; case BrainModel::BRAIN_MODEL_SURFACE: mouseSurfaceView(me); break; case BrainModel::BRAIN_MODEL_VOLUME: mouseVolumeView(me); break; case BrainModel::BRAIN_MODEL_SURFACE_AND_VOLUME: mouseSurfaceAndVolumeView(me); break; } } } } /** * mouse processing for surface view mode */ void GuiBrainModelOpenGL::mouseSurfaceAndVolumeView(const GuiBrainModelOpenGLMouseEvent& me) { BrainModelSurfaceAndVolume* bmsv = getDisplayedBrainModelSurfaceAndVolume(); // // Biggest change in mouse axis // const int biggestChange = (abs(me.dy) > abs(me.dx)) ? me.dy : me.dx; switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: // // Perform auto loading // { BrainSet* bs = theMainWindow->getBrainSet(getModelViewNumber()); BrainSetAutoLoaderManager* autoLoader = bs->getAutoLoaderManager(); if (autoLoader->getAnyAutoLoaderSelected()) { selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_NODE, false); if (selectedNode.getItemIndex1() >= 0) { QString errorMessage = autoLoader->processAutoLoading(selectedNode.getItemIndex1()); GuiFilesModified fm; fm.setMetricModified(); fm.setVolumeModified(); theMainWindow->fileModificationUpdate(fm); if (errorMessage.isEmpty() == false) { QMessageBox::critical(this, "ERROR", errorMessage); } } else { selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_VOXEL_UNDERLAY, false); if (selectedVoxelUnderlay.getItemIndex1() >= 0) { int ijk[3] = { selectedVoxelUnderlay.getItemIndex1(), selectedVoxelUnderlay.getItemIndex2(), selectedVoxelUnderlay.getItemIndex3() }; float xyz[3]; BrainModelVolume* bmv = bs->getBrainModelVolume(); if (bmv != NULL) { VolumeFile* vf = bmv->getUnderlayVolumeFile(); if (vf != NULL) { vf->getVoxelCoordinate(ijk, xyz); QString errorMessage = autoLoader->processAutoLoading(xyz); GuiFilesModified fm; fm.setMetricModified(); theMainWindow->fileModificationUpdate(fm); if (errorMessage.isEmpty() == false) { QMessageBox::critical(this, "ERROR", errorMessage); } } } } } GuiFilesModified fm; fm.setMetricModified(); fm.setVolumeModified(); theMainWindow->fileModificationUpdate(fm); } } // // Perform an ID operation // selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_ALL, true); // // If transformation axis selected, switch to transform axes mouse mode // if (isMainWindowOpenGL()) { if (selectedTransformationAxes.getItemIndex1() >= 0) { setMouseMode(MOUSE_MODE_TRANSFORMATION_MATRIX_AXES); TransformationMatrixFile* tmf = theMainWindow->getBrainSet(getModelViewNumber())->getTransformationMatrixFile(); const int indx = selectedTransformationAxes.getItemIndex1(); if ((indx >= 0) && (indx < tmf->getNumberOfMatrices())) { tmf->setSelectedTransformationAxesIndex(indx); } } } // // Update all GL so that green/blue ID node symbols show up in all windows // GuiBrainModelOpenGL::updateAllGL(); break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: { vtkTransform* matrix = bmsv->getRotationTransformMatrix(viewingWindowIndex); switch(rotationAxis) { case BRAIN_MODEL_ROTATION_AXIS_X: matrix->RotateX(biggestChange); //me.dy); break; case BRAIN_MODEL_ROTATION_AXIS_Y: matrix->RotateY(-biggestChange); //-me.dx); break; case BRAIN_MODEL_ROTATION_AXIS_Z: matrix->RotateZ(-biggestChange); //-me.dx); break; case BRAIN_MODEL_ROTATION_AXIS_XY: matrix->RotateX(me.dy); matrix->RotateY(-me.dx); break; case BRAIN_MODEL_ROTATION_AXIS_OFF: break; } if (viewingWindowIndex == BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) { theMainWindow->updateTransformationMatrixEditor(NULL); } updateAllGL(this); } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: { float translate[3]; bmsv->getTranslation(viewingWindowIndex, translate); translate[0] += me.dx; translate[1] += me.dy; translate[2] = 0.0; bmsv->setTranslation(viewingWindowIndex, translate); if (viewingWindowIndex == BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) { theMainWindow->updateTransformationMatrixEditor(NULL); } updateAllGL(this); } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: { float scale[3]; bmsv->getScaling(viewingWindowIndex, scale); //scale += me.dy * scale * 0.01; scale[0] += biggestChange * scale[0] * 0.01; scale[1] += biggestChange * scale[1] * 0.01; scale[2] += biggestChange * scale[2] * 0.01; scale[0] = std::max(scale[0], 0.01f); scale[1] = std::max(scale[1], 0.01f); scale[2] = std::max(scale[2], 0.01f); //if (scale < 0.01) scale = 0.01; // negative would flip surface bmsv->setScaling(viewingWindowIndex, scale); if (viewingWindowIndex == BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) { theMainWindow->updateTransformationMatrixEditor(NULL); } updateAllGL(this); } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse processing for surface view mode */ void GuiBrainModelOpenGL::mouseSurfaceView(const GuiBrainModelOpenGLMouseEvent& me) { BrainModelSurface* bms = getDisplayedBrainModelSurface(); BrainSet* bs = theMainWindow->getBrainSet(getModelViewNumber()); DisplaySettingsSurface* dss = bs->getDisplaySettingsSurface(); // // The Caret Main Window BrainModelSurface is used when yoking. It is NULL // if the Caret Main Window contains a volume or contours. When doing a yoked // surface, the transformations associated with the Caret Main Window are upated. // BrainModelSurface* mainWindowModelSurface = theMainWindow->getBrainModelSurface(); int mainWindowModelViewNumber = -1; bool yokeSurfaceFlag = false; if (mainWindowModelSurface != NULL) { mainWindowModelViewNumber = allBrainSurfaceOpenGL[BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW]->getModelViewNumber(); yokeSurfaceFlag = getYokeView(); } // // See if yoke to oblique volume view in main window // bool yokeVolumeFlag = false; BrainModelVolume* bmv = theMainWindow->getBrainModelVolume(); vtkTransform* volumeObliqueRotationMatrix = NULL; if (bmv != NULL) { if (bmv->getSelectedAxis(BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) == VolumeFile::VOLUME_AXIS_OBLIQUE) { yokeVolumeFlag = getYokeView(); volumeObliqueRotationMatrix = bmv->getObliqueRotationMatrix(); } } // // Biggest change in mouse axis // const int biggestChange = (abs(me.dy) > abs(me.dx)) ? me.dy : me.dx; switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: { //BrainSetAutoLoaderManager* autoLoader = bs->getAutoLoaderManager(); //if (autoLoader->getAnyAutoLoaderSelected()) { // selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_NODE, false); // if (selectedNode.getItemIndex1() >= 0) { // QString errorMessage = // autoLoader->processAutoLoading(selectedNode.getItemIndex1()); // GuiFilesModified fm; // fm.setMetricModified(); // fm.setVolumeModified(); // theMainWindow->fileModificationUpdate(fm); // if (errorMessage.isEmpty() == false) { // QMessageBox::critical(this, "ERROR", errorMessage); // } // } // GuiFilesModified fm; // fm.setMetricModified(); // fm.setVolumeModified(); // theMainWindow->fileModificationUpdate(fm); //} // // Perform an ID operation // QTime timer; timer.start(); selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_ALL, true); int total_time = timer.elapsed(); std::cout << "id time:" << total_time << std::endl; BrainSetAutoLoaderManager* autoLoader = bs->getAutoLoaderManager(); if (autoLoader->getAnyAutoLoaderSelected()) { if (selectedNode.getItemIndex1() >= 0) { QString errorMessage = autoLoader->processAutoLoading(selectedNode.getItemIndex1()); GuiFilesModified fm; fm.setMetricModified(); fm.setVolumeModified(); theMainWindow->fileModificationUpdate(fm); if (errorMessage.isEmpty() == false) { QMessageBox::critical(this, "ERROR", errorMessage); } } GuiFilesModified fm; fm.setMetricModified(); fm.setVolumeModified(); theMainWindow->fileModificationUpdate(fm); } // // Adjust transformation axes only in main window // if (selectedTransformationAxes.getItemIndex1() >= 0) { if (isMainWindowOpenGL()) { if (getMouseMode() != MOUSE_MODE_TRANSFORMATION_MATRIX_AXES) { setMouseMode(MOUSE_MODE_TRANSFORMATION_MATRIX_AXES); TransformationMatrixFile* tmf = theMainWindow->getBrainSet(getModelViewNumber())->getTransformationMatrixFile(); const int indx = selectedTransformationAxes.getItemIndex1(); if ((indx >= 0) && (indx < tmf->getNumberOfMatrices())) { tmf->setSelectedTransformationAxesIndex(indx); } } else { setMouseMode(MOUSE_MODE_VIEW); } } } // // Update all GL so that green/blue ID node symbols show up in all windows // updateAllGL(NULL); } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: { vtkTransform* matrix = bms->getRotationTransformMatrix(viewingWindowIndex); // // If yoked, use main window brain surface model for rotation // if (yokeSurfaceFlag) { matrix = mainWindowModelSurface->getRotationTransformMatrix(mainWindowModelViewNumber); } // // If yoke to volume in oblique view in main window // if (yokeVolumeFlag) { matrix = volumeObliqueRotationMatrix; } switch(rotationAxis) { case BRAIN_MODEL_ROTATION_AXIS_X: matrix->RotateX(biggestChange); //me.dy); break; case BRAIN_MODEL_ROTATION_AXIS_Y: matrix->RotateY(-biggestChange); //-me.dx); break; case BRAIN_MODEL_ROTATION_AXIS_Z: matrix->RotateZ(-biggestChange); //-me.dx); break; case BRAIN_MODEL_ROTATION_AXIS_XY: matrix->RotateX(me.dy); matrix->RotateY(-me.dx); break; case BRAIN_MODEL_ROTATION_AXIS_OFF: break; } if (viewingWindowIndex == BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) { theMainWindow->updateTransformationMatrixEditor(NULL); } updateAllGL(this); } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: { float translate[3]; bms->getTranslation(viewingWindowIndex, translate); // // If yoked, use main window brain surface model for translation // if (yokeSurfaceFlag) { mainWindowModelSurface->getTranslation(mainWindowModelViewNumber, translate); } translate[0] += me.dx; translate[1] += me.dy; translate[2] = 0.0; // // If yoked, use main window brain surface model for translation // if (yokeSurfaceFlag) { mainWindowModelSurface->setTranslation(mainWindowModelViewNumber, translate); } else { bms->setTranslation(viewingWindowIndex, translate); } if (viewingWindowIndex == BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) { theMainWindow->updateTransformationMatrixEditor(NULL); } updateAllGL(this); } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: switch (dss->getViewingProjection()) { case DisplaySettingsSurface::VIEWING_PROJECTION_ORTHOGRAPHIC: { float scale[3]; bms->getScaling(viewingWindowIndex, scale); // // If yoked, use main window brain surface model for scaling // if (yokeSurfaceFlag) { mainWindowModelSurface->getScaling(mainWindowModelViewNumber, scale); } scale[0] += biggestChange * scale[0] * 0.01; scale[1] += biggestChange * scale[1] * 0.01; scale[2] += biggestChange * scale[2] * 0.01; scale[0] = std::max(scale[0], 0.01f); scale[1] = std::max(scale[1], 0.01f); scale[2] = std::max(scale[2], 0.01f); //if (scale < 0.01) scale = 0.01; // negative would flip surface // // If yoked, use main window brain surface model for scaling // if (yokeSurfaceFlag) { mainWindowModelSurface->setScaling(mainWindowModelViewNumber, scale); } else { bms->setScaling(viewingWindowIndex, scale); } } break; case DisplaySettingsSurface::VIEWING_PROJECTION_PERSPECTIVE: { float zoom = bms->getPerspectiveZooming(viewingWindowIndex); // // If yoked, use main window brain surface model for scaling // if (yokeSurfaceFlag) { zoom = mainWindowModelSurface->getPerspectiveZooming(mainWindowModelViewNumber); } zoom -= biggestChange * 1.0; if (yokeSurfaceFlag) { mainWindowModelSurface->setPerspectiveZooming(mainWindowModelViewNumber, zoom); } else { bms->setPerspectiveZooming(viewingWindowIndex, zoom); } } break; } if (viewingWindowIndex == BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) { theMainWindow->updateTransformationMatrixEditor(NULL); } updateAllGL(this); case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse processing for border update NEW. */ void GuiBrainModelOpenGL::mouseBorderUpdateNew(const GuiBrainModelOpenGLMouseEvent& me) { BrainModelSurface* bms = getDisplayedBrainModelSurface(); if (bms == NULL) { return; } GuiBorderOperationsDialog* borderOperationsDialog = theMainWindow->getBorderOperationsDialog(false); if (borderOperationsDialog == NULL) { return; } BrainModelBorderSet::UPDATE_BORDER_MODE borderUpdateMode = BrainModelBorderSet::UPDATE_BORDER_MODE_NONE; float sampling; bool twoDimFlag; bool autoProjectYesFlag; borderOperationsDialog->getBorderUpdateParameters( borderUpdateMode, sampling, twoDimFlag, autoProjectYesFlag); switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: if (linearObjectBeingDrawn.getNumberOfLinks() > 1) { const int numLinks = linearObjectBeingDrawn.getNumberOfLinks(); if (numLinks > 1) { BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); QString errorMessage; bmbs->updateBorder(bms, borderUpdateMode, &linearObjectBeingDrawn, sampling, autoProjectYesFlag, errorMessage); if (errorMessage.isEmpty() == false) { QMessageBox::critical(this, "ERROR", errorMessage); } } } resetLinearObjectBeingDrawn(); theMainWindow->getBrainSet()->assignBorderColors(); updateAllGL(); break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: { float modelXYZ[3]; bool modelXYZValid = false; bool doThreeD = (twoDimFlag == false); if (doThreeD) { // // Interpolate point within a tile // int viewport[4] = { 0, 0, windowWidth[viewingWindowIndex], windowHeight[viewingWindowIndex] }; float tilePos[3]; BrainSet* bs = bms->getBrainSet(); if (bs == NULL) { bs = theMainWindow->getBrainSet(getModelViewNumber()); } if (openGL->getSurfacePointAtDisplayXY(bs, bms, viewingWindowIndex, viewport, me.x, me.y, tilePos)) { if (DebugControl::getDebugOn()) { std::cout << "Pos in tile: " << tilePos[0] << " " << tilePos[1] << " " << tilePos[2] << std::endl; } modelXYZ[0] = tilePos[0]; modelXYZ[1] = tilePos[1]; modelXYZ[2] = tilePos[2]; modelXYZValid = true; } } else { // // Convert the window coordinate to a surface coordinate // convertWindowToModelCoords(me.x, me.y, false, modelXYZ[0], modelXYZ[1], modelXYZ[2]); if (DebugControl::getDebugOn()) { std::cout << "Window: (" << me.x << ", " << me.y << ")" << " Model: (" << modelXYZ[0] << ", " << modelXYZ[1] << ", " << modelXYZ[2] << ")" << std::endl; } modelXYZ[2] = 0.0; modelXYZValid = true; } if (modelXYZValid) { linearObjectBeingDrawn.addBorderLink(modelXYZ, 0); if (linearObjectBeingDrawn.getNumberOfLinks() > 2) { //int dummy = 0; //linearObjectBeingDrawn.resampleBorderToDensity(dbd->getResampling(), 2, dummy); } } if (doThreeD) { drawLinearObjectOnly = false; } else { drawLinearObjectOnly = true; } updateGL(); drawLinearObjectOnly = false; } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: { // // Allow rotation but only if drawing border in 3D mode // bool doThreeD = (twoDimFlag == false); if ((bms != NULL) && doThreeD) { vtkTransform* matrix = bms->getRotationTransformMatrix(viewingWindowIndex); // // Biggest change in mouse axis // const int biggestChange = (abs(me.dy) > abs(me.dx)) ? me.dy : me.dx; switch(rotationAxis) { case BRAIN_MODEL_ROTATION_AXIS_X: matrix->RotateX(biggestChange); //me.dy); break; case BRAIN_MODEL_ROTATION_AXIS_Y: matrix->RotateY(-biggestChange); //-me.dx); break; case BRAIN_MODEL_ROTATION_AXIS_Z: matrix->RotateZ(-biggestChange); //-me.dx); break; case BRAIN_MODEL_ROTATION_AXIS_XY: matrix->RotateX(me.dy); matrix->RotateY(-me.dx); break; case BRAIN_MODEL_ROTATION_AXIS_OFF: break; } if (viewingWindowIndex == BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) { theMainWindow->updateTransformationMatrixEditor(NULL); } updateAllGL(this); } } break; } } /** * mouse processing for border update */ void GuiBrainModelOpenGL::mouseBorderUpdate(const GuiBrainModelOpenGLMouseEvent& me) { BrainModelSurface* bms = getDisplayedBrainModelSurface(); if (bms == NULL) { return; } GuiBorderDrawUpdateDialog* borderDrawUpdateDialog = theMainWindow->getDrawBorderUpdateDialog(); if (borderDrawUpdateDialog == NULL) { return; } switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: if (linearObjectBeingDrawn.getNumberOfLinks() > 1) { const int numLinks = linearObjectBeingDrawn.getNumberOfLinks(); if (numLinks > 1) { BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); QString errorMessage; bmbs->updateBorder(bms, borderDrawUpdateDialog->getBorderUpdateMode(), &linearObjectBeingDrawn, borderDrawUpdateDialog->getResampling(), borderDrawUpdateDialog->getAutoProjectBorder(), errorMessage); if (errorMessage.isEmpty() == false) { QMessageBox::critical(this, "ERROR", errorMessage); } } } resetLinearObjectBeingDrawn(); theMainWindow->getBrainSet()->assignBorderColors(); updateAllGL(); break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: { float modelXYZ[3]; bool modelXYZValid = false; bool doThreeD = borderDrawUpdateDialog->getThreeDimensional(); if (doThreeD) { // // Interpolate point within a tile // int viewport[4] = { 0, 0, windowWidth[viewingWindowIndex], windowHeight[viewingWindowIndex] }; float tilePos[3]; BrainSet* bs = bms->getBrainSet(); if (bs == NULL) { bs = theMainWindow->getBrainSet(getModelViewNumber()); } if (openGL->getSurfacePointAtDisplayXY(bs, bms, viewingWindowIndex, viewport, me.x, me.y, tilePos)) { if (DebugControl::getDebugOn()) { std::cout << "Pos in tile: " << tilePos[0] << " " << tilePos[1] << " " << tilePos[2] << std::endl; } modelXYZ[0] = tilePos[0]; modelXYZ[1] = tilePos[1]; modelXYZ[2] = tilePos[2]; modelXYZValid = true; } } else { // // Convert the window coordinate to a surface coordinate // convertWindowToModelCoords(me.x, me.y, false, modelXYZ[0], modelXYZ[1], modelXYZ[2]); if (DebugControl::getDebugOn()) { std::cout << "Window: (" << me.x << ", " << me.y << ")" << " Model: (" << modelXYZ[0] << ", " << modelXYZ[1] << ", " << modelXYZ[2] << ")" << std::endl; } modelXYZ[2] = 0.0; modelXYZValid = true; } if (modelXYZValid) { linearObjectBeingDrawn.addBorderLink(modelXYZ, 0); if (linearObjectBeingDrawn.getNumberOfLinks() > 2) { //int dummy = 0; //linearObjectBeingDrawn.resampleBorderToDensity(dbd->getResampling(), 2, dummy); } } if (doThreeD) { drawLinearObjectOnly = false; } else { drawLinearObjectOnly = true; } updateGL(); drawLinearObjectOnly = false; } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: { // // Allow rotation but only if drawing border in 3D mode // bool doThreeD = borderDrawUpdateDialog->getThreeDimensional(); if ((bms != NULL) && doThreeD) { vtkTransform* matrix = bms->getRotationTransformMatrix(viewingWindowIndex); // // Biggest change in mouse axis // const int biggestChange = (abs(me.dy) > abs(me.dx)) ? me.dy : me.dx; switch(rotationAxis) { case BRAIN_MODEL_ROTATION_AXIS_X: matrix->RotateX(biggestChange); //me.dy); break; case BRAIN_MODEL_ROTATION_AXIS_Y: matrix->RotateY(-biggestChange); //-me.dx); break; case BRAIN_MODEL_ROTATION_AXIS_Z: matrix->RotateZ(-biggestChange); //-me.dx); break; case BRAIN_MODEL_ROTATION_AXIS_XY: matrix->RotateX(me.dy); matrix->RotateY(-me.dx); break; case BRAIN_MODEL_ROTATION_AXIS_OFF: break; } if (viewingWindowIndex == BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) { theMainWindow->updateTransformationMatrixEditor(NULL); } updateAllGL(this); } } break; } } /** * mouse processing for border draw mode. */ void GuiBrainModelOpenGL::mouseBorderDrawNew(const GuiBrainModelOpenGLMouseEvent& me) { GuiBorderOperationsDialog* borderOperationsDialog = theMainWindow->getBorderOperationsDialog(false); if (borderOperationsDialog == NULL) { return; } VolumeFile* paintVolumeForVoxelAssignment = NULL; QString borderName; float borderSampling; int borderColorIndex; int surfacePaintAssignmentColumnNumber; int surfacePaintNameAssignmentIndex; int paintVolumeSliceThickness; bool closedBorderFlag; bool twoDimFlag; bool autoProjectYesFlag; borderOperationsDialog->getBorderDrawingParameters(borderName, borderSampling, borderColorIndex, surfacePaintAssignmentColumnNumber, surfacePaintNameAssignmentIndex, paintVolumeForVoxelAssignment, paintVolumeSliceThickness, closedBorderFlag, twoDimFlag, autoProjectYesFlag); BrainModelSurface* bms = getDisplayedBrainModelSurface(); BrainModelVolume* bmv = getDisplayedBrainModelVolume(); switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: if (linearObjectBeingDrawn.getNumberOfLinks() > 1) { int dummy = 0; linearObjectBeingDrawn.resampleBorderToDensity(borderSampling, 2, dummy); const int numLinks = linearObjectBeingDrawn.getNumberOfLinks(); if (numLinks > 1) { // // Is this a volume // if (bmv != NULL) { const VolumeFile::VOLUME_AXIS volumeSliceAxis = bmv->getSelectedAxis(0); const VolumeFile* vf = bmv->getMasterVolumeFile(); if (vf != NULL) { float origin[3], spacing[3]; vf->getOrigin(origin); vf->getSpacing(spacing); int slices[3]; bmv->getSelectedOrthogonalSlices(0, slices); float volumeSliceCoordinate = 0.0; switch (volumeSliceAxis) { case VolumeFile::VOLUME_AXIS_X: volumeSliceCoordinate = slices[0] * spacing[0] + origin[0]; break; case VolumeFile::VOLUME_AXIS_Y: volumeSliceCoordinate = slices[1] * spacing[1] + origin[1]; break; case VolumeFile::VOLUME_AXIS_Z: volumeSliceCoordinate = slices[2] * spacing[2] + origin[2]; break; case VolumeFile::VOLUME_AXIS_ALL: case VolumeFile::VOLUME_AXIS_OBLIQUE: case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } for (int i = 0; i < numLinks; i++) { float xyzIn[3]; linearObjectBeingDrawn.getLinkXYZ(i, xyzIn); float xyzOut[3]; switch (volumeSliceAxis) { case VolumeFile::VOLUME_AXIS_X: xyzOut[0] = volumeSliceCoordinate; xyzOut[1] = xyzIn[0]; xyzOut[2] = xyzIn[1]; break; case VolumeFile::VOLUME_AXIS_Y: xyzOut[0] = xyzIn[0]; xyzOut[1] = volumeSliceCoordinate; xyzOut[2] = xyzIn[1]; break; case VolumeFile::VOLUME_AXIS_Z: xyzOut[0] = xyzIn[0]; xyzOut[1] = xyzIn[1]; xyzOut[2] = volumeSliceCoordinate; break; case VolumeFile::VOLUME_AXIS_ALL: case VolumeFile::VOLUME_AXIS_OBLIQUE: case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } linearObjectBeingDrawn.setLinkXYZ(i, xyzOut); } } else { QMessageBox::critical(this, "ERROR", "At least one volume must be displayed as\n" "an overlay or underlay to draw a border."); resetLinearObjectBeingDrawn(); updateAllGL(); return; } } Border border = linearObjectBeingDrawn; resetLinearObjectBeingDrawn(); if (borderName.isEmpty()) { borderName = "No-Name"; } border.setName(borderName); border.setBorderColorIndex(borderColorIndex); float lastXYZ[3]; if (closedBorderFlag) { if (border.getNumberOfLinks() > 0) { border.getLinkXYZ(0, lastXYZ); border.addBorderLink(lastXYZ); } if (DebugControl::getDebugOn()) { const int numB = border.getNumberOfLinks(); std::cout << "Border drawn has " << numB << " links." << std::endl; for (int i = 0; i < numB; i++) { const float* xyz = border.getLinkXYZ(i); std::cout << i << ": " << xyz[0] << ", " << xyz[1] << ", " << xyz[2] << std::endl; } } } int dummy = 0; border.resampleBorderToDensity(borderSampling, 2, dummy); if (bmv != NULL) { BorderFile* bf = theMainWindow->getBrainSet()->getVolumeBorderFile(); bf->addBorder(border); // // Assigning voxels within closed border // if (paintVolumeForVoxelAssignment != NULL) { paintVolumeForVoxelAssignment->assignVoxelsWithinBorder( bmv->getSelectedAxis(0), borderName, &border, paintVolumeSliceThickness); } } else if (bms != NULL) { BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); BrainModelBorder* b = new BrainModelBorder(theMainWindow->getBrainSet(), &border, bms->getSurfaceType()); bmbs->addBorder(b); if (autoProjectYesFlag) { const int borderNumber = bmbs->getNumberOfBorders() - 1; if (borderNumber >= 0) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); bmbs->projectBorders(bms, true, borderNumber, borderNumber); QApplication::restoreOverrideCursor(); } } // // If assigning nodes // if ((surfacePaintAssignmentColumnNumber >= 0) && (surfacePaintNameAssignmentIndex >= 0)) { PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); // // Assign the nodes within the closed border. // const int numNodes = theMainWindow->getBrainSet()->getNumberOfNodes(); std::vector insideFlags(numNodes, false); const CoordinateFile* cf = bms->getCoordinateFile(); const float* coords = cf->getCoordinate(0); // // Drawing a 3D border ? // if (twoDimFlag == false) { BrainModelOpenGL* openGL = GuiBrainModelOpenGL::getOpenGLDrawing(); border.pointsInsideBorder3D(openGL->getSelectionModelviewMatrix(0), openGL->getSelectionProjectionMatrix(0), openGL->getSelectionViewport(0), coords, numNodes, insideFlags); } else { border.pointsInsideBorder2D(coords, numNodes, insideFlags); } for (int j = 0; j < numNodes; j++) { if (insideFlags[j]) { pf->setPaint(j, surfacePaintAssignmentColumnNumber, surfacePaintNameAssignmentIndex); } } } } // // Border File has changed // DisplaySettingsBorders* dsb = theMainWindow->getBrainSet()->getDisplaySettingsBorders(); dsb->setDisplayBorders(true); GuiFilesModified fm; fm.setAreaColorModified(); fm.setBorderColorModified(); fm.setBorderModified(); fm.setPaintModified(); theMainWindow->fileModificationUpdate(fm); } } resetLinearObjectBeingDrawn(); updateAllGL(); break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: if (bmv != NULL) { // // Augment volume border being drawn with links from an existing border // selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_VOLUME_BORDER); if (DebugControl::getDebugOn()) { std::cout << "Selected Augment Border: " << selectedVolumeBorder.getItemIndex1() << " " << selectedVolumeBorder.getItemIndex2() << std::endl; } if (selectedVolumeBorder.getItemIndex1() >= 0) { if (linearObjectAugmentBorderCount == 0) { linearObjectAugmentBorder1 = selectedVolumeBorder; QApplication::setOverrideCursor(QCursor(Qt::CrossCursor)); linearObjectAugmentBorderCount++; } else { linearObjectAugmentBorder2 = selectedVolumeBorder; QApplication::restoreOverrideCursor(); const int borderNum = linearObjectAugmentBorder1.getItemIndex1(); if (borderNum != linearObjectAugmentBorder1.getItemIndex1()) { QMessageBox::warning(this, "Border Selection Error", "You have tried to augment with two different " "borders! Reselect both links."); } else { const int linkStart = linearObjectAugmentBorder1.getItemIndex2(); const int linkEnd = linearObjectAugmentBorder2.getItemIndex2(); BorderFile* bf = theMainWindow->getBrainSet(getModelViewNumber())->getVolumeBorderFile(); Border* b = bf->getBorder(borderNum); const int totalLinks = b->getNumberOfLinks(); if (linkStart < linkEnd) { for (int i = linkStart; i >= 0; i--) { linearObjectBeingDrawn.addBorderLink(b->getLinkXYZ(i)); } for (int i = totalLinks - 1; i >= linkEnd; i--) { linearObjectBeingDrawn.addBorderLink(b->getLinkXYZ(i)); } } else { for (int i = linkStart; i >= linkEnd; i--) { linearObjectBeingDrawn.addBorderLink(b->getLinkXYZ(i)); } } } linearObjectAugmentBorderCount = 0; } } } else { // // Augment surface border being drawn with links from an existing border // selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_BORDER); if (DebugControl::getDebugOn()) { std::cout << "Selected Augment Border: " << selectedBorder1.getItemIndex1() << " " << selectedBorder1.getItemIndex2() << " " << selectedBorder1.getItemIndex3() << std::endl; } if (selectedBorder1.getItemIndex1() >= 0) { if (linearObjectAugmentBorderCount == 0) { linearObjectAugmentBorder1 = selectedBorder1; QApplication::setOverrideCursor(QCursor(Qt::CrossCursor)); linearObjectAugmentBorderCount++; } else { linearObjectAugmentBorder2 = selectedBorder1; QApplication::restoreOverrideCursor(); const int borderNum = linearObjectAugmentBorder1.getItemIndex2(); if (borderNum != linearObjectAugmentBorder1.getItemIndex2()) { QMessageBox::warning(this, "Border Selection Error", "You have tried to augment with two different " "borders! Reselect both links."); } else { const int linkStart = linearObjectAugmentBorder1.getItemIndex3(); const int linkEnd = linearObjectAugmentBorder2.getItemIndex3(); BrainModelBorderSet* bmbs = theMainWindow->getBrainSet(getModelViewNumber())->getBorderSet(); BrainModelBorder* b = bmbs->getBorder(borderNum); const int totalLinks = b->getNumberOfBorderLinks(); const int brainModelIndex = getDisplayedBrainModelIndex(); if (linkStart < linkEnd) { for (int i = linkStart; i >= 0; i--) { BrainModelBorderLink* link = b->getBorderLink(i); linearObjectBeingDrawn.addBorderLink(link->getLinkPosition(brainModelIndex)); } for (int i = totalLinks - 1; i >= linkEnd; i--) { BrainModelBorderLink* link = b->getBorderLink(i); linearObjectBeingDrawn.addBorderLink(link->getLinkPosition(brainModelIndex)); } } else { for (int i = linkStart; i >= linkEnd; i--) { BrainModelBorderLink* link = b->getBorderLink(i); linearObjectBeingDrawn.addBorderLink(link->getLinkPosition(brainModelIndex)); } } } linearObjectAugmentBorderCount = 0; } } } updateGL(); break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: { float modelXYZ[3]; bool modelXYZValid = false; bool doThreeD = (twoDimFlag == false); if (bmv != NULL) { doThreeD = false; } if (doThreeD) { // // Find the surface 3d position under the cursor // if (bms != NULL) { // // Interpolate point within a tile // int viewport[4] = { 0, 0, windowWidth[viewingWindowIndex], windowHeight[viewingWindowIndex] }; float tilePos[3]; BrainSet* bs = NULL; if (bms != NULL) { bs = bms->getBrainSet(); } if (bs == NULL) { bs = theMainWindow->getBrainSet(getModelViewNumber()); } if (openGL->getSurfacePointAtDisplayXY(bs, bms, viewingWindowIndex, viewport, me.x, me.y, tilePos)) { if (DebugControl::getDebugOn()) { std::cout << "Pos in tile: " << tilePos[0] << " " << tilePos[1] << " " << tilePos[2] << std::endl; } modelXYZ[0] = tilePos[0]; modelXYZ[1] = tilePos[1]; modelXYZ[2] = tilePos[2]; modelXYZValid = true; } } } else { // // Convert the window coordinate to a surface coordinate // convertWindowToModelCoords(me.x, me.y, false, modelXYZ[0], modelXYZ[1], modelXYZ[2]); if (DebugControl::getDebugOn()) { std::cout << "Window: (" << me.x << ", " << me.y << ")" << " Model: (" << modelXYZ[0] << ", " << modelXYZ[1] << ", " << modelXYZ[2] << ")" << std::endl; } modelXYZ[2] = 0.0; modelXYZValid = true; } if (modelXYZValid) { linearObjectBeingDrawn.addBorderLink(modelXYZ, 0); if (linearObjectBeingDrawn.getNumberOfLinks() > 2) { //int dummy = 0; //linearObjectBeingDrawn.resampleBorderToDensity(dbd->getResampling(), 2, dummy); } } if (doThreeD) { drawLinearObjectOnly = false; } else { drawLinearObjectOnly = true; } updateGL(); drawLinearObjectOnly = false; } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: { bool doThreeD = (twoDimFlag == false); if ((bms != NULL) && doThreeD) { vtkTransform* matrix = bms->getRotationTransformMatrix(viewingWindowIndex); // // Biggest change in mouse axis // const int biggestChange = (abs(me.dy) > abs(me.dx)) ? me.dy : me.dx; switch(rotationAxis) { case BRAIN_MODEL_ROTATION_AXIS_X: matrix->RotateX(biggestChange); //me.dy); break; case BRAIN_MODEL_ROTATION_AXIS_Y: matrix->RotateY(-biggestChange); //-me.dx); break; case BRAIN_MODEL_ROTATION_AXIS_Z: matrix->RotateZ(-biggestChange); //-me.dx); break; case BRAIN_MODEL_ROTATION_AXIS_XY: matrix->RotateX(me.dy); matrix->RotateY(-me.dx); break; case BRAIN_MODEL_ROTATION_AXIS_OFF: break; } if (viewingWindowIndex == BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) { theMainWindow->updateTransformationMatrixEditor(NULL); } updateAllGL(this); } } break; } } /** * mouse processing for border draw mode */ void GuiBrainModelOpenGL::mouseBorderDraw(const GuiBrainModelOpenGLMouseEvent& me) { BrainModelVolume* bmv = getDisplayedBrainModelVolume(); switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: if (linearObjectBeingDrawn.getNumberOfLinks() > 1) { int dummy = 0; GuiDrawBorderDialog* dbd = theMainWindow->getDrawBorderDialog(false); linearObjectBeingDrawn.resampleBorderToDensity(dbd->getResampling(), 2, dummy); const int numLinks = linearObjectBeingDrawn.getNumberOfLinks(); if (numLinks > 1) { // // Is this a volume // if (bmv != NULL) { const VolumeFile::VOLUME_AXIS volumeSliceAxis = bmv->getSelectedAxis(0); const VolumeFile* vf = bmv->getMasterVolumeFile(); if (vf != NULL) { float origin[3], spacing[3]; vf->getOrigin(origin); vf->getSpacing(spacing); int slices[3]; bmv->getSelectedOrthogonalSlices(0, slices); float volumeSliceCoordinate = 0.0; switch (volumeSliceAxis) { case VolumeFile::VOLUME_AXIS_X: volumeSliceCoordinate = slices[0] * spacing[0] + origin[0]; break; case VolumeFile::VOLUME_AXIS_Y: volumeSliceCoordinate = slices[1] * spacing[1] + origin[1]; break; case VolumeFile::VOLUME_AXIS_Z: volumeSliceCoordinate = slices[2] * spacing[2] + origin[2]; break; case VolumeFile::VOLUME_AXIS_ALL: case VolumeFile::VOLUME_AXIS_OBLIQUE: case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } for (int i = 0; i < numLinks; i++) { float xyzIn[3]; linearObjectBeingDrawn.getLinkXYZ(i, xyzIn); float xyzOut[3]; switch (volumeSliceAxis) { case VolumeFile::VOLUME_AXIS_X: xyzOut[0] = volumeSliceCoordinate; xyzOut[1] = xyzIn[0]; xyzOut[2] = xyzIn[1]; break; case VolumeFile::VOLUME_AXIS_Y: xyzOut[0] = xyzIn[0]; xyzOut[1] = volumeSliceCoordinate; xyzOut[2] = xyzIn[1]; break; case VolumeFile::VOLUME_AXIS_Z: xyzOut[0] = xyzIn[0]; xyzOut[1] = xyzIn[1]; xyzOut[2] = volumeSliceCoordinate; break; case VolumeFile::VOLUME_AXIS_ALL: case VolumeFile::VOLUME_AXIS_OBLIQUE: case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } linearObjectBeingDrawn.setLinkXYZ(i, xyzOut); } } else { QMessageBox::critical(this, "ERROR", "At least one volume must be displayed as\n" "an overlay or underlay to draw a border."); resetLinearObjectBeingDrawn(); updateGL(); return; } } dbd->createNewBorder(getDisplayedBrainModel(), linearObjectBeingDrawn); resetLinearObjectBeingDrawn(); updateGL(); } } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: if (bmv != NULL) { // // Augment volume border being drawn with links from an existing border // selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_VOLUME_BORDER); if (DebugControl::getDebugOn()) { std::cout << "Selected Augment Border: " << selectedVolumeBorder.getItemIndex1() << " " << selectedVolumeBorder.getItemIndex2() << std::endl; } if (selectedVolumeBorder.getItemIndex1() >= 0) { if (linearObjectAugmentBorderCount == 0) { linearObjectAugmentBorder1 = selectedVolumeBorder; QApplication::setOverrideCursor(QCursor(Qt::CrossCursor)); linearObjectAugmentBorderCount++; } else { linearObjectAugmentBorder2 = selectedVolumeBorder; QApplication::restoreOverrideCursor(); const int borderNum = linearObjectAugmentBorder1.getItemIndex1(); if (borderNum != linearObjectAugmentBorder1.getItemIndex1()) { QMessageBox::warning(this, "Border Selection Error", "You have tried to augment with two different " "borders! Reselect both links."); } else { const int linkStart = linearObjectAugmentBorder1.getItemIndex2(); const int linkEnd = linearObjectAugmentBorder2.getItemIndex2(); BorderFile* bf = theMainWindow->getBrainSet(getModelViewNumber())->getVolumeBorderFile(); Border* b = bf->getBorder(borderNum); const int totalLinks = b->getNumberOfLinks(); if (linkStart < linkEnd) { for (int i = linkStart; i >= 0; i--) { linearObjectBeingDrawn.addBorderLink(b->getLinkXYZ(i)); } for (int i = totalLinks - 1; i >= linkEnd; i--) { linearObjectBeingDrawn.addBorderLink(b->getLinkXYZ(i)); } } else { for (int i = linkStart; i >= linkEnd; i--) { linearObjectBeingDrawn.addBorderLink(b->getLinkXYZ(i)); } } } linearObjectAugmentBorderCount = 0; } } } else { // // Augment surface border being drawn with links from an existing border // selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_BORDER); if (DebugControl::getDebugOn()) { std::cout << "Selected Augment Border: " << selectedBorder1.getItemIndex1() << " " << selectedBorder1.getItemIndex2() << " " << selectedBorder1.getItemIndex3() << std::endl; } if (selectedBorder1.getItemIndex1() >= 0) { if (linearObjectAugmentBorderCount == 0) { linearObjectAugmentBorder1 = selectedBorder1; QApplication::setOverrideCursor(QCursor(Qt::CrossCursor)); linearObjectAugmentBorderCount++; } else { linearObjectAugmentBorder2 = selectedBorder1; QApplication::restoreOverrideCursor(); const int borderNum = linearObjectAugmentBorder1.getItemIndex2(); if (borderNum != linearObjectAugmentBorder1.getItemIndex2()) { QMessageBox::warning(this, "Border Selection Error", "You have tried to augment with two different " "borders! Reselect both links."); } else { const int linkStart = linearObjectAugmentBorder1.getItemIndex3(); const int linkEnd = linearObjectAugmentBorder2.getItemIndex3(); BrainModelBorderSet* bmbs = theMainWindow->getBrainSet(getModelViewNumber())->getBorderSet(); BrainModelBorder* b = bmbs->getBorder(borderNum); const int totalLinks = b->getNumberOfBorderLinks(); const int brainModelIndex = getDisplayedBrainModelIndex(); if (linkStart < linkEnd) { for (int i = linkStart; i >= 0; i--) { BrainModelBorderLink* link = b->getBorderLink(i); linearObjectBeingDrawn.addBorderLink(link->getLinkPosition(brainModelIndex)); } for (int i = totalLinks - 1; i >= linkEnd; i--) { BrainModelBorderLink* link = b->getBorderLink(i); linearObjectBeingDrawn.addBorderLink(link->getLinkPosition(brainModelIndex)); } } else { for (int i = linkStart; i >= linkEnd; i--) { BrainModelBorderLink* link = b->getBorderLink(i); linearObjectBeingDrawn.addBorderLink(link->getLinkPosition(brainModelIndex)); } } //int dummy = 0; //GuiDrawBorderDialog* dbd = theMainWindow->getDrawBorderDialog(false); //linearObjectBeingDrawn.resampleBorderToDensity(dbd->getResampling(), 2, // dummy); } linearObjectAugmentBorderCount = 0; } } } updateGL(); break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: { GuiDrawBorderDialog* dbd = theMainWindow->getDrawBorderDialog(false); float modelXYZ[3]; bool modelXYZValid = false; bool doThreeD = dbd->getThreeDimensional(); if (bmv != NULL) { doThreeD = false; } if (doThreeD) { // // Find the surface 3d position under the cursor // BrainModelSurface* bms = getDisplayedBrainModelSurface(); if (bms != NULL) { /* selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_NODE); const int nodeNum = selectedNode.getItemIndex1(); if (nodeNum >= 0) { const CoordinateFile* cf = bms->getCoordinateFile(); cf->getCoordinate(nodeNum, modelXYZ); modelXYZValid = true; if (DebugControl::getDebugOn()) { std::cout << "Node: " << nodeNum << "XYZ: " << modelXYZ[0] << " " << modelXYZ[1] << " " << modelXYZ[2] << std::endl; } } */ // // Interpolate point within a tile // int viewport[4] = { 0, 0, windowWidth[viewingWindowIndex], windowHeight[viewingWindowIndex] }; float tilePos[3]; BrainSet* bs = NULL; if (bms != NULL) { bs = bms->getBrainSet(); } if (bs == NULL) { bs = theMainWindow->getBrainSet(getModelViewNumber()); } if (openGL->getSurfacePointAtDisplayXY(bs, bms, viewingWindowIndex, viewport, me.x, me.y, tilePos)) { if (DebugControl::getDebugOn()) { std::cout << "Pos in tile: " << tilePos[0] << " " << tilePos[1] << " " << tilePos[2] << std::endl; } modelXYZ[0] = tilePos[0]; modelXYZ[1] = tilePos[1]; modelXYZ[2] = tilePos[2]; modelXYZValid = true; } } } else { // // Convert the window coordinate to a surface coordinate // convertWindowToModelCoords(me.x, me.y, false, modelXYZ[0], modelXYZ[1], modelXYZ[2]); if (DebugControl::getDebugOn()) { std::cout << "Window: (" << me.x << ", " << me.y << ")" << " Model: (" << modelXYZ[0] << ", " << modelXYZ[1] << ", " << modelXYZ[2] << ")" << std::endl; } modelXYZ[2] = 0.0; modelXYZValid = true; } if (modelXYZValid) { linearObjectBeingDrawn.addBorderLink(modelXYZ, 0); if (linearObjectBeingDrawn.getNumberOfLinks() > 2) { //int dummy = 0; //linearObjectBeingDrawn.resampleBorderToDensity(dbd->getResampling(), 2, dummy); } } if (doThreeD) { drawLinearObjectOnly = false; } else { drawLinearObjectOnly = true; } updateGL(); drawLinearObjectOnly = false; } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: { // // Allow rotation but only if drawing border in 3D mode // GuiDrawBorderDialog* dbd = theMainWindow->getDrawBorderDialog(false); BrainModelSurface* bms = getDisplayedBrainModelSurface(); bool doThreeD = dbd->getThreeDimensional(); if ((bms != NULL) && doThreeD) { vtkTransform* matrix = bms->getRotationTransformMatrix(viewingWindowIndex); // // Biggest change in mouse axis // const int biggestChange = (abs(me.dy) > abs(me.dx)) ? me.dy : me.dx; switch(rotationAxis) { case BRAIN_MODEL_ROTATION_AXIS_X: matrix->RotateX(biggestChange); //me.dy); break; case BRAIN_MODEL_ROTATION_AXIS_Y: matrix->RotateY(-biggestChange); //-me.dx); break; case BRAIN_MODEL_ROTATION_AXIS_Z: matrix->RotateZ(-biggestChange); //-me.dx); break; case BRAIN_MODEL_ROTATION_AXIS_XY: matrix->RotateX(me.dy); matrix->RotateY(-me.dx); break; case BRAIN_MODEL_ROTATION_AXIS_OFF: break; } if (viewingWindowIndex == BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) { theMainWindow->updateTransformationMatrixEditor(NULL); } updateAllGL(this); } } break; } } /** * mouse processing for border delete mode */ void GuiBrainModelOpenGL::mouseBorderDelete(const GuiBrainModelOpenGLMouseEvent& me) { switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: if (getDisplayedBrainModelSurface() != NULL) { selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_BORDER); if (DebugControl::getDebugOn()) { std::cout << "Selected Border: " << selectedBorder1.getItemIndex1() << " " << selectedBorder1.getItemIndex2() << " " << selectedBorder1.getItemIndex3() << std::endl; } if (selectedBorder1.getItemIndex1() >= 0) { BrainModelBorderSet* bmbs = theMainWindow->getBrainSet(getModelViewNumber())->getBorderSet(); bmbs->deleteBorder(selectedBorder1.getItemIndex2()); } } else if (getDisplayedBrainModelVolume() != NULL) { selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_VOLUME_BORDER); if (DebugControl::getDebugOn()) { std::cout << "Selected Border: " << selectedVolumeBorder.getItemIndex1() << " " << selectedVolumeBorder.getItemIndex2() << std::endl; } if (selectedVolumeBorder.getItemIndex1() >= 0) { BorderFile* bf = theMainWindow->getBrainSet(getModelViewNumber())->getVolumeBorderFile(); bf->removeBorder(selectedVolumeBorder.getItemIndex1()); } } updateAllGL(NULL); break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse processing for border delete point mode */ void GuiBrainModelOpenGL::mouseBorderDeletePoint(const GuiBrainModelOpenGLMouseEvent& me) { switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: if (getDisplayedBrainModelSurface() != NULL) { selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_BORDER); if (DebugControl::getDebugOn()) { std::cout << "Selected Border: " << selectedBorder1.getItemIndex1() << " " << selectedBorder1.getItemIndex2() << " " << selectedBorder1.getItemIndex3() << std::endl; } if (selectedBorder1.getItemIndex1() >= 0) { BrainModelBorderSet* bmbs = theMainWindow->getBrainSet(getModelViewNumber())->getBorderSet(); BrainModelBorder* b = bmbs->getBorder(selectedBorder1.getItemIndex2()); b->deleteBorderLink(selectedBorder1.getItemIndex3()); } } else if (getDisplayedBrainModelVolume() != NULL) { selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_VOLUME_BORDER); if (DebugControl::getDebugOn()) { std::cout << "Selected Border: " << selectedVolumeBorder.getItemIndex1() << " " << selectedVolumeBorder.getItemIndex2() << std::endl; } if (selectedVolumeBorder.getItemIndex1() >= 0) { BorderFile* bf = theMainWindow->getBrainSet(getModelViewNumber())->getVolumeBorderFile(); Border* b = bf->getBorder(selectedVolumeBorder.getItemIndex1()); b->removeLink(selectedVolumeBorder.getItemIndex2()); } } updateAllGL(NULL); break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse processing for border interpolate. */ void GuiBrainModelOpenGL::mouseBorderInterpolate(const GuiBrainModelOpenGLMouseEvent& me) { switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: if (getDisplayedBrainModelSurface() != NULL) { selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_BORDER); if (DebugControl::getDebugOn()) { std::cout << "Selected Border: " << selectedBorder1.getItemIndex1() << " " << selectedBorder1.getItemIndex2() << " " << selectedBorder1.getItemIndex3() << std::endl; } if (selectedBorder1.getItemIndex1() >= 0) { GuiBordersCreateInterpolatedDialog* cid = theMainWindow->getBordersCreateInterpolatedDialog(false); cid->updateBorderSelection(GuiBordersCreateInterpolatedDialog::INTERPOLATE_BORDER_1, selectedBorder1.getItemIndex2()); } } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: if (getDisplayedBrainModelSurface() != NULL) { selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_BORDER); if (DebugControl::getDebugOn()) { std::cout << "Selected Border: " << selectedBorder1.getItemIndex1() << " " << selectedBorder1.getItemIndex2() << " " << selectedBorder1.getItemIndex3() << std::endl; } if (selectedBorder1.getItemIndex1() >= 0) { GuiBordersCreateInterpolatedDialog* cid = theMainWindow->getBordersCreateInterpolatedDialog(false); cid->updateBorderSelection(GuiBordersCreateInterpolatedDialog::INTERPOLATE_BORDER_2, selectedBorder1.getItemIndex2()); } } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse processing for border interpolate NEW. */ void GuiBrainModelOpenGL::mouseBorderInterpolateNew(const GuiBrainModelOpenGLMouseEvent& me) { GuiBorderOperationsDialog* borderOperationsDialog = theMainWindow->getBorderOperationsDialog(false); if (borderOperationsDialog == NULL) { return; } switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: if (getDisplayedBrainModelSurface() != NULL) { selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_BORDER); if (DebugControl::getDebugOn()) { std::cout << "Selected Border: " << selectedBorder1.getItemIndex1() << " " << selectedBorder1.getItemIndex2() << " " << selectedBorder1.getItemIndex3() << std::endl; } if (selectedBorder1.getItemIndex1() >= 0) { borderOperationsDialog->setSelectedInterpolatedBorders( 0, selectedBorder1.getItemIndex2()); } } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: if (getDisplayedBrainModelSurface() != NULL) { selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_BORDER); if (DebugControl::getDebugOn()) { std::cout << "Selected Border: " << selectedBorder1.getItemIndex1() << " " << selectedBorder1.getItemIndex2() << " " << selectedBorder1.getItemIndex3() << std::endl; } if (selectedBorder1.getItemIndex1() >= 0) { borderOperationsDialog->setSelectedInterpolatedBorders( 1, selectedBorder1.getItemIndex2()); } } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse processing for border move point */ void GuiBrainModelOpenGL::mouseBorderMovePoint(const GuiBrainModelOpenGLMouseEvent& me) { switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: borderPointBeingMoved[0] = -1; QApplication::restoreOverrideCursor(); break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: if (getDisplayedBrainModelSurface() != NULL) { selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_BORDER); if (selectedBorder1.getItemIndex1() >= 0) { borderPointBeingMoved[0] = selectedBorder1.getItemIndex1(); borderPointBeingMoved[1] = selectedBorder1.getItemIndex2(); borderPointBeingMoved[2] = selectedBorder1.getItemIndex3(); QApplication::setOverrideCursor(QCursor(Qt::CrossCursor)); } } else if (getDisplayedBrainModelVolume() != NULL) { selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_VOLUME_BORDER); if (selectedVolumeBorder.getItemIndex1() >= 0) { borderPointBeingMoved[0] = selectedVolumeBorder.getItemIndex1(); borderPointBeingMoved[1] = selectedVolumeBorder.getItemIndex2(); borderPointBeingMoved[2] = selectedVolumeBorder.getItemIndex3(); QApplication::setOverrideCursor(QCursor(Qt::CrossCursor)); } } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: QApplication::restoreOverrideCursor(); break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: if (borderPointBeingMoved[0] >= 0) { if (getDisplayedBrainModelSurface() != NULL) { BrainModelBorderSet* bmbs = theMainWindow->getBrainSet(getModelViewNumber())->getBorderSet(); BrainModelBorder* b = bmbs->getBorder(borderPointBeingMoved[1]); if (b != NULL) { BrainModelBorderLink* link = b->getBorderLink(borderPointBeingMoved[2]); if (link != NULL) { float pos[3]; link->getLinkPosition(borderPointBeingMoved[0], pos); float dummy; convertWindowToModelCoords(me.x, me.y, false, pos[0], pos[1], dummy); link->setLinkPosition(borderPointBeingMoved[0], pos); updateGL(); } } } else if (getDisplayedBrainModelVolume() != NULL) { BorderFile* bf = theMainWindow->getBrainSet(getModelViewNumber())->getVolumeBorderFile(); Border* b = bf->getBorder(borderPointBeingMoved[0]); BrainModelVolume* bmv = getDisplayedBrainModelVolume(); const VolumeFile::VOLUME_AXIS volumeSliceAxis = bmv->getSelectedAxis(0); const VolumeFile* vf = bmv->getMasterVolumeFile(); float origin[3], spacing[3]; vf->getOrigin(origin); vf->getSpacing(spacing); int slices[3]; bmv->getSelectedOrthogonalSlices(0, slices); float volumeSliceCoordinate = 0.0; switch (volumeSliceAxis) { case VolumeFile::VOLUME_AXIS_X: volumeSliceCoordinate = slices[0] * spacing[0] + origin[0]; break; case VolumeFile::VOLUME_AXIS_Y: volumeSliceCoordinate = slices[1] * spacing[1] + origin[1]; break; case VolumeFile::VOLUME_AXIS_Z: volumeSliceCoordinate = slices[2] * spacing[2] + origin[2]; break; case VolumeFile::VOLUME_AXIS_ALL: case VolumeFile::VOLUME_AXIS_OBLIQUE: case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } if (b != NULL) { float xyz[3]; b->getLinkXYZ(borderPointBeingMoved[1], xyz); float dummy; float newX, newY; convertWindowToModelCoords(me.x, me.y, false, newX, newY, dummy); switch (volumeSliceAxis) { case VolumeFile::VOLUME_AXIS_X: xyz[0] = volumeSliceCoordinate; xyz[1] = newX; xyz[2] = newY; break; case VolumeFile::VOLUME_AXIS_Y: xyz[0] = newX; xyz[1] = volumeSliceCoordinate; xyz[2] = newY; break; case VolumeFile::VOLUME_AXIS_Z: xyz[0] = newX; xyz[1] = newY; xyz[2] = volumeSliceCoordinate; break; case VolumeFile::VOLUME_AXIS_ALL: case VolumeFile::VOLUME_AXIS_OBLIQUE: case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } b->setLinkXYZ(borderPointBeingMoved[1], xyz); updateGL(); } } } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse processing for border reverse */ void GuiBrainModelOpenGL::mouseBorderReverse(const GuiBrainModelOpenGLMouseEvent& me) { switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: if (getDisplayedBrainModelSurface() != NULL) { selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_BORDER); if (selectedBorder1.getItemIndex1() >= 0) { BrainModelBorderSet* bmbs = theMainWindow->getBrainSet(getModelViewNumber())->getBorderSet(); BrainModelBorder* b = bmbs->getBorder(selectedBorder1.getItemIndex2()); b->reverseLinks(); updateAllGL(NULL); } } else if (getDisplayedBrainModelVolume() != NULL) { selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_VOLUME_BORDER); if (selectedVolumeBorder.getItemIndex1() >= 0) { BorderFile* bf = theMainWindow->getBrainSet(getModelViewNumber())->getVolumeBorderFile(); Border* b = bf->getBorder(selectedVolumeBorder.getItemIndex1()); b->reverseBorderLinks(); } } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse processing for border rename */ void GuiBrainModelOpenGL::mouseBorderRename(const GuiBrainModelOpenGLMouseEvent& me) { switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: if (getDisplayedBrainModelSurface() != NULL) { selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_BORDER); if (selectedBorder1.getItemIndex1() >= 0) { BrainModelBorderSet* bmbs = theMainWindow->getBrainSet(getModelViewNumber())->getBorderSet(); BrainModelBorder* b = bmbs->getBorder(selectedBorder1.getItemIndex2()); bool ok = false; QString newName = QInputDialog::getText(this, "Rename Border", "Border Name", QLineEdit::Normal, b->getName(), &ok); if (ok && (newName.isEmpty() == false)) { b->setName(newName); theMainWindow->getBrainSet(getModelViewNumber())->assignBorderColors(); } } } else if (getDisplayedBrainModelVolume() != NULL) { selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_VOLUME_BORDER); if (selectedVolumeBorder.getItemIndex1() >= 0) { BorderFile* bf = theMainWindow->getBrainSet(getModelViewNumber())->getVolumeBorderFile(); Border* b = bf->getBorder(selectedVolumeBorder.getItemIndex1()); bool ok = false; QString newName = QInputDialog::getText(this, "Rename Border", "Border Name", QLineEdit::Normal, b->getName(), &ok); if (ok && (newName.isEmpty() == false)) { b->setName(newName); theMainWindow->getBrainSet(getModelViewNumber())->assignBorderColors(); } } } updateAllGL(NULL); break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse processing for draw cut mode */ void GuiBrainModelOpenGL::mouseCutDraw(const GuiBrainModelOpenGLMouseEvent& me) { switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: if (linearObjectBeingDrawn.getNumberOfLinks() > 1) { int dummy = 0; linearObjectBeingDrawn.resampleBorderToDensity(5.0, 2, dummy); if (linearObjectBeingDrawn.getNumberOfLinks() > 1) { BrainModel* bm = getDisplayedBrainModel(); if (bm->getModelType() == BrainModel::BRAIN_MODEL_SURFACE) { CutsFile* bf = theMainWindow->getBrainSet(getModelViewNumber())->getCutsFile(); bf->addBorder(linearObjectBeingDrawn); } GuiFilesModified fm; fm.setCutModified(); theMainWindow->fileModificationUpdate(fm); resetLinearObjectBeingDrawn(); updateGL(); } } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: { // // Convert the window coordinate to a surface coordinate // float modelXYZ[3]; convertWindowToModelCoords(me.x, me.y, false, modelXYZ[0], modelXYZ[1], modelXYZ[2]); if (DebugControl::getDebugOn()) { std::cout << "Window: (" << me.x << ", " << me.y << ")" << " Model: (" << modelXYZ[0] << ", " << modelXYZ[1] << ", " << modelXYZ[2] << ")" << std::endl; } modelXYZ[2] = 0.0; linearObjectBeingDrawn.addBorderLink(modelXYZ, 0); //if (linearObjectBeingDrawn.getNumberOfLinks() > 2) { // int dummy = 0; // linearObjectBeingDrawn.resampleBorderToDensity(5.0, 2, dummy); //} drawLinearObjectOnly = true; updateGL(); drawLinearObjectOnly = false; } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse processing for delete cut mode */ void GuiBrainModelOpenGL::mouseCutDelete(const GuiBrainModelOpenGLMouseEvent& me) { switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_CUT); if (DebugControl::getDebugOn()) { std::cout << "Selected Cut: " << selectedCut.getItemIndex1() << " " << selectedCut.getItemIndex2() <= 0) { CutsFile* bf = theMainWindow->getBrainSet(getModelViewNumber())->getCutsFile(); bf->removeBorder(selectedCut.getItemIndex1()); GuiFilesModified fm; fm.setCutModified(); theMainWindow->fileModificationUpdate(fm); updateGL(); } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse processing for delete foci */ void GuiBrainModelOpenGL::mouseFociDelete(const GuiBrainModelOpenGLMouseEvent& me) { switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_FOCUS_PROJECTION); if (DebugControl::getDebugOn()) { std::cout << "Selected Foci: " << selectedFocusProjection.getItemIndex1() << std::endl; } if (selectedFocusProjection.getItemIndex1() >= 0) { theMainWindow->getBrainSet(getModelViewNumber())->deleteFocus(selectedFocusProjection.getItemIndex1()); updateAllGL(NULL); } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse processing for delete cell */ void GuiBrainModelOpenGL::mouseCellDelete(const GuiBrainModelOpenGLMouseEvent& me) { switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_CELL_PROJECTION); if (DebugControl::getDebugOn()) { std::cout << "Selected Cell: " << selectedCellProjection.getItemIndex1() << std::endl; } if (selectedCellProjection.getItemIndex1() >= 0) { theMainWindow->getBrainSet(getModelViewNumber())->deleteCell(selectedCellProjection.getItemIndex1()); updateAllGL(NULL); } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse processing for roi border selection */ void GuiBrainModelOpenGL::mouseSurfaceRoiBorderSelect(const GuiBrainModelOpenGLMouseEvent& me) { switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_BORDER); if (selectedBorder1.getItemIndex1() >= 0) { GuiSurfaceRegionOfInterestDialog* roi = theMainWindow->getSurfaceRegionOfInterestDialog(false); if (roi != NULL) { BrainModelBorderSet* bmbs = theMainWindow->getBrainSet(getModelViewNumber())->getBorderSet(); BrainModelBorder* b = bmbs->getBorder(selectedBorder1.getItemIndex2()); roi->setBorderNameForQuery(b->getName()); } GuiSurfaceRegionOfInterestDialogOLD* roiOLD = theMainWindow->getSurfaceRegionOfInterestDialogOLD(false); if (roiOLD != NULL) { BrainModelBorderSet* bmbs = theMainWindow->getBrainSet(getModelViewNumber())->getBorderSet(); BrainModelBorder* b = bmbs->getBorder(selectedBorder1.getItemIndex2()); roiOLD->setBorderNameForQuery(b->getName()); } } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse processing for roi paint selection */ void GuiBrainModelOpenGL::mouseSurfaceRoiPaintSelect(const GuiBrainModelOpenGLMouseEvent& me) { switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_NODE); if (selectedNode.getItemIndex1() >= 0) { GuiSurfaceRegionOfInterestDialog* roi = theMainWindow->getSurfaceRegionOfInterestDialog(false); if (roi != NULL) { PaintFile* pf = theMainWindow->getBrainSet(getModelViewNumber())->getPaintFile(); const int index = roi->getQueryPaintColumn(); if ((index >= 0) && (index < pf->getNumberOfColumns())) { roi->setPaintIndexForQuery(pf->getPaint(selectedNode.getItemIndex1(), index)); } } GuiSurfaceRegionOfInterestDialogOLD* roiOLD = theMainWindow->getSurfaceRegionOfInterestDialogOLD(false); if (roiOLD != NULL) { PaintFile* pf = theMainWindow->getBrainSet(getModelViewNumber())->getPaintFile(); const int index = roiOLD->getQueryPaintColumn(); if ((index >= 0) && (index < pf->getNumberOfColumns())) { roiOLD->setPaintIndexForQuery(pf->getPaint(selectedNode.getItemIndex1(), index)); } } } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse processing for roi metric selection */ void GuiBrainModelOpenGL::mouseSurfaceRoiMetricSelect(const GuiBrainModelOpenGLMouseEvent& me) { switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_NODE); if (selectedNode.getItemIndex1() >= 0) { GuiSurfaceRegionOfInterestDialog* roi = theMainWindow->getSurfaceRegionOfInterestDialog(false); if (roi != NULL) { roi->setMetricNodeForQuery(selectedNode.getItemIndex1()); } GuiSurfaceRegionOfInterestDialogOLD* roiOLD = theMainWindow->getSurfaceRegionOfInterestDialogOLD(false); if (roiOLD != NULL) { roiOLD->setMetricNodeForQuery(selectedNode.getItemIndex1()); } } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse processing for roi shape selection */ void GuiBrainModelOpenGL::mouseSurfaceRoiShapeSelect(const GuiBrainModelOpenGLMouseEvent& me) { switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_NODE); if (selectedNode.getItemIndex1() >= 0) { GuiSurfaceRegionOfInterestDialog* roi = theMainWindow->getSurfaceRegionOfInterestDialog(false); if (roi != NULL) { roi->setShapeNodeForQuery(selectedNode.getItemIndex1()); } GuiSurfaceRegionOfInterestDialogOLD* roiOLD = theMainWindow->getSurfaceRegionOfInterestDialogOLD(false); if (roiOLD != NULL) { roiOLD->setShapeNodeForQuery(selectedNode.getItemIndex1()); } } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse processing for roi geodesic node selection */ void GuiBrainModelOpenGL::mouseSurfaceRoiGeodesicNodeSelect(const GuiBrainModelOpenGLMouseEvent& me) { switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_NODE); if (selectedNode.getItemIndex1() >= 0) { GuiSurfaceRegionOfInterestDialog* roi = theMainWindow->getSurfaceRegionOfInterestDialog(false); if (roi != NULL) { roi->setNodeForGeodesicQuery(selectedNode.getItemIndex1()); } GuiSurfaceRegionOfInterestDialogOLD* roiOLD = theMainWindow->getSurfaceRegionOfInterestDialogOLD(false); if (roiOLD != NULL) { roiOLD->setNodeForGeodesicQuery(selectedNode.getItemIndex1()); } } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse processing for align surface to standard orientation */ void GuiBrainModelOpenGL::mouseAlignStandardOrientation(const GuiBrainModelOpenGLMouseEvent& me) { switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_NODE); if (selectedNode.getItemIndex1() >= 0) { GuiAlignSurfaceToStandardOrientationDialog* assod = theMainWindow->getAlignSurfaceToStandardOrientationDialog(); if (assod != NULL) { assod->setVentralTipNode(selectedNode.getItemIndex1()); } } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_NODE); if (selectedNode.getItemIndex1() >= 0) { GuiAlignSurfaceToStandardOrientationDialog* assod = theMainWindow->getAlignSurfaceToStandardOrientationDialog(); if (assod != NULL) { assod->setMedialTipNode(selectedNode.getItemIndex1()); } } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse processing for align surface to standard orientation during flatten full hem */ void GuiBrainModelOpenGL::mouseAlignStandardOrientationFullHemFlatten(const GuiBrainModelOpenGLMouseEvent& me) { switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_NODE); if (selectedNode.getItemIndex1() >= 0) { GuiFlattenFullHemisphereDialog* flattenFullHemDialog = theMainWindow->getFlattenFullHemisphereDialog(false); if (flattenFullHemDialog != NULL) { flattenFullHemDialog->setCentralSulcusVentralTip(selectedNode.getItemIndex1()); } } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_NODE); if (selectedNode.getItemIndex1() >= 0) { GuiFlattenFullHemisphereDialog* flattenFullHemDialog = theMainWindow->getFlattenFullHemisphereDialog(false); if (flattenFullHemDialog != NULL) { flattenFullHemDialog->setCentralSulcusDorsalMedialTip(selectedNode.getItemIndex1()); } } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse process for cell add mode. */ void GuiBrainModelOpenGL::mouseCellAdd(const GuiBrainModelOpenGLMouseEvent& me) { switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_NODE); if (selectedNode.getItemIndex1() >= 0) { GuiAddCellsDialog* acd = theMainWindow->getAddCellsDialog(false); if (acd != NULL) { acd->addCellAtNodeNumber(selectedNode.getItemIndex1()); } } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse process for volume transforms in view mode. */ void GuiBrainModelOpenGL::mouseVolumeView(const GuiBrainModelOpenGLMouseEvent& me) { BrainModelVolume* bmv = getDisplayedBrainModelVolume(); const bool drawAll = (bmv->getSelectedAxis(viewingWindowIndex) == VolumeFile::VOLUME_AXIS_OBLIQUE); // // Biggest change in mouse axis // const int biggestChange = (abs(me.dy) > abs(me.dx)) ? me.dy : me.dx; switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: { BrainSet* bs = theMainWindow->getBrainSet(getModelViewNumber()); BrainSetAutoLoaderManager* autoLoader = bs->getAutoLoaderManager(); if (autoLoader->getAnyAutoLoaderSelected()) { selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_VOXEL_UNDERLAY, false); if (selectedVoxelUnderlay.getItemIndex1() >= 0) { int ijk[3] = { selectedVoxelUnderlay.getItemIndex1(), selectedVoxelUnderlay.getItemIndex2(), selectedVoxelUnderlay.getItemIndex3() }; float xyz[3]; VolumeFile* vf = bmv->getUnderlayVolumeFile(); if (vf != NULL) { vf->getVoxelCoordinate(ijk, xyz); QString errorMessage = autoLoader->processAutoLoading(xyz); GuiFilesModified fm; fm.setMetricModified(); fm.setVolumeModified(); theMainWindow->fileModificationUpdate(fm); if (errorMessage.isEmpty() == false) { QMessageBox::critical(this, "ERROR", errorMessage); } } } GuiFilesModified fm; fm.setMetricModified(); fm.setVolumeModified(); theMainWindow->fileModificationUpdate(fm); } } // // Perform an ID operation // selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_ALL, true); // // Was a node selected // if (selectedNode.getItemIndex1() > 0) { getBrainSet()->setDisplayCrossForNode(selectedNode.getItemIndex1(), getDisplayedBrainModelSurface()); } // // See if any voxels were selected // if (selectedVoxelUnderlay.getItemIndex1() > 0) { BrainModelVolume* bmv = theMainWindow->getBrainSet(getModelViewNumber())->getBrainModelVolume(-1); if (bmv != NULL) { VolumeFile* vf = bmv->getUnderlayVolumeFile(); if (vf != NULL) { float origin[3]; float spacing[3]; vf->getOrigin(origin); vf->getSpacing(spacing); // // Set the selected voxel // const int slices[3] = { selectedVoxelUnderlay.getItemIndex1(), selectedVoxelUnderlay.getItemIndex2(), selectedVoxelUnderlay.getItemIndex3() }; const int sliceOffsets[3] = { selectedVoxelUnderlay.getItemIndex4(), selectedVoxelUnderlay.getItemIndex5(), selectedVoxelUnderlay.getItemIndex6() }; bool selectOrthogonalSlices = true; switch (bmv->getSelectedAxis(viewingWindowIndex)) { case VolumeFile::VOLUME_AXIS_X: case VolumeFile::VOLUME_AXIS_Y: case VolumeFile::VOLUME_AXIS_Z: case VolumeFile::VOLUME_AXIS_ALL: { // // Don't change slices if viewing montage // //const DisplaySettingsVolume* dsv = theMainWindow->getBrainSet(getModelViewNumber())->getDisplaySettingsVolume(); //if (dsv->getMontageViewSelected()) { // selectOrthogonalSlices = false; //} } break; case VolumeFile::VOLUME_AXIS_OBLIQUE: selectOrthogonalSlices = false; break; case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: bmv->setSelectedObliqueSliceOffsets(viewingWindowIndex, sliceOffsets); selectOrthogonalSlices = false; break; case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } if (selectOrthogonalSlices) { // // Montage View ? // DisplaySettingsVolume* dsv = theMainWindow->getBrainSet(getModelViewNumber())->getDisplaySettingsVolume(); if (dsv->getMontageViewSelected()) { // // Place selected slice in center of montage // int rows, cols, increment; dsv->getMontageViewSettings(rows, cols, increment); const int centerRow = (rows / 2); const int centerCol = (cols / 2); const int offset = (centerRow * cols + centerCol) * increment; int topLeftSlice[3] = { slices[0], slices[1], slices[2] }; switch (bmv->getSelectedAxis(viewingWindowIndex)) { case VolumeFile::VOLUME_AXIS_X: topLeftSlice[0] -= offset; topLeftSlice[0] = std::max(topLeftSlice[0], 0); break; case VolumeFile::VOLUME_AXIS_Y: topLeftSlice[1] -= offset; topLeftSlice[1] = std::max(topLeftSlice[1], 0); break; case VolumeFile::VOLUME_AXIS_Z: topLeftSlice[2] -= offset; topLeftSlice[2] = std::max(topLeftSlice[2], 0); break; case VolumeFile::VOLUME_AXIS_ALL: case VolumeFile::VOLUME_AXIS_OBLIQUE: case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } bmv->setSelectedOrthogonalSlices(viewingWindowIndex, topLeftSlice); } else { bmv->setSelectedOrthogonalSlices(viewingWindowIndex, slices); // // If main window or yoked to main window // update selected slices in the main and yoked windows // if ((viewingWindowIndex == BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) || getYokeView()) { for (int i = 0; i < BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS; i++) { if (allBrainSurfaceOpenGL[i] != NULL) { BrainModelVolume* bmv2 = allBrainSurfaceOpenGL[i]->getDisplayedBrainModelVolume(); if (bmv2 != NULL) { if ((i == BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) || allBrainSurfaceOpenGL[i]->getYokeView()) { bmv2->setSelectedOrthogonalSlices(i, slices); } } } } } } } } } } // // If transformation axis selected, switch to transform axes mouse mode // if (isMainWindowOpenGL()) { if (selectedTransformationAxes.getItemIndex1() >= 0) { setMouseMode(MOUSE_MODE_TRANSFORMATION_MATRIX_AXES); TransformationMatrixFile* tmf = theMainWindow->getBrainSet(getModelViewNumber())->getTransformationMatrixFile(); const int indx = selectedTransformationAxes.getItemIndex1(); if ((indx >= 0) && (indx < tmf->getNumberOfMatrices())) { tmf->setSelectedTransformationAxesIndex(indx); } } } // // Update toolbar all GL so that green/blue ID node symbols show up in all windows // GuiToolBar::updateAllToolBars(false); GuiBrainModelOpenGL::updateAllGL(); break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: { GuiMainWindowVolumeActions* volumeActions = theMainWindow->getVolumeActions(); if (bmv->getSelectedAxis(viewingWindowIndex) == VolumeFile::VOLUME_AXIS_OBLIQUE) { vtkTransform* matrix = bmv->getObliqueRotationMatrix(); matrix->RotateX(me.dy); matrix->RotateY(-me.dx); } else if (volumeActions->getTranformRotationChecked()) { bmv->addToDisplayRotation(viewingWindowIndex, -biggestChange); } else { if (bmv->getSelectedAxis(viewingWindowIndex) == VolumeFile::VOLUME_AXIS_ALL) { BrainModelSurface* bms = theMainWindow->getBrainSet(getModelViewNumber())->getActiveFiducialSurface(); if (bms != NULL) { vtkTransform* matrix = bms->getRotationTransformMatrix(viewingWindowIndex); matrix->RotateX(me.dy); matrix->RotateY(-me.dx); } } } if (viewingWindowIndex == BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) { theMainWindow->updateTransformationMatrixEditor(NULL); } if (drawAll) { updateAllGL(); } else { updateAllGL(this); } } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: { float translate[3]; bmv->getTranslation(viewingWindowIndex, translate); translate[0] += me.dx; translate[1] += me.dy; translate[2] = 0.0; bmv->setTranslation(viewingWindowIndex, translate); if (viewingWindowIndex == BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) { theMainWindow->updateTransformationMatrixEditor(NULL); } if (drawAll) { updateAllGL(); } else { updateAllGL(this); } } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: { float scale[3]; bmv->getScaling(viewingWindowIndex, scale); //scale += me.dy * scale * 0.01; scale[0] += biggestChange * scale[0] * 0.01; scale[1] += biggestChange * scale[1] * 0.01; scale[2] += biggestChange * scale[2] * 0.01; scale[0] = std::max(scale[0], 0.01f); scale[1] = std::max(scale[1], 0.01f); scale[2] = std::max(scale[2], 0.01f); //if (scale < 0.01) scale = 0.01; // negative would flip surface bmv->setScaling(viewingWindowIndex, scale); if (viewingWindowIndex == BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) { theMainWindow->updateTransformationMatrixEditor(NULL); } if (drawAll) { updateAllGL(); } else { updateAllGL(this); } } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse process for contour transforms in view mode. */ void GuiBrainModelOpenGL::mouseContourView(const GuiBrainModelOpenGLMouseEvent& me) { // // Biggest change in mouse axis // const int biggestChange = (abs(me.dy) > abs(me.dx)) ? me.dy : me.dx; BrainModelContours* bmc = getDisplayedBrainModelContours(); if (bmc == NULL) { return; } switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: // // Perform and ID operation // selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_ALL, true); break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: { vtkTransform* matrix = bmc->getRotationTransformMatrix(viewingWindowIndex); matrix->RotateZ(-biggestChange); //-me.dx); if (viewingWindowIndex == BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) { theMainWindow->updateTransformationMatrixEditor(NULL); } updateAllGL(this); } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: { float translate[3]; bmc->getTranslation(viewingWindowIndex, translate); const float multiplier = 0.10; translate[0] += me.dx * multiplier; translate[1] += me.dy * multiplier; translate[2] = 0.0; bmc->setTranslation(viewingWindowIndex, translate); if (viewingWindowIndex == BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) { theMainWindow->updateTransformationMatrixEditor(NULL); } updateAllGL(this); } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: { float scale[3]; bmc->getScaling(viewingWindowIndex, scale); //scale += me.dy * scale * 0.01; scale[0] += biggestChange * scale[0] * 0.01; scale[1] += biggestChange * scale[1] * 0.01; scale[2] += biggestChange * scale[2] * 0.01; scale[0] = std::max(scale[0], 0.0001f); scale[1] = std::max(scale[1], 0.0001f); scale[2] = std::max(scale[2], 0.0001f); //if (scale < 0.01) scale = 0.01; // negative would flip surface bmc->setScaling(viewingWindowIndex, scale); if (viewingWindowIndex == BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW) { theMainWindow->updateTransformationMatrixEditor(NULL); } updateAllGL(this); } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse process for contour set scale. */ void GuiBrainModelOpenGL::mouseContourSetScale(const GuiBrainModelOpenGLMouseEvent& me) { GuiContourSetScaleDialog* ssd = theMainWindow->getContourSetScaleDialog(false); if (ssd != NULL) { // // Convert mouse position to model coordinates // float modelX = me.x; float modelY = me.y; float modelZ = 0.0; convertWindowToModelCoords(me.x, me.y, false, modelX, modelY, modelZ); switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: ssd->setScaleStartPoint(modelX, modelY); break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: ssd->setScaleEndPoint(modelX, modelY); break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } } /** * mouse process for contour draw. */ void GuiBrainModelOpenGL::mouseContourDraw(const GuiBrainModelOpenGLMouseEvent& me) { switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: if (linearObjectBeingDrawn.getNumberOfLinks() > 1) { // // Get the contour model // BrainModelContours* bmc = getDisplayedBrainModelContours(); if (bmc != NULL) { // // Get the contour drawing dialog // GuiContourDrawDialog* cdd = theMainWindow->getContourDrawDialog(false); // // Create the contour // CaretContour cc; if (cdd != NULL) { cc.setSectionNumber(cdd->getSectionNumber()); } // // Resample to contour spacing // if (cdd != NULL) { int newNumLinks; linearObjectBeingDrawn.resampleBorderToDensity(cdd->getPointSpacing(), 2, newNumLinks); } // // Create the new contour // ContourFile* cf = bmc->getContourFile(); float z = cc.getSectionNumber(); const float spacing = cf->getSectionSpacing(); if (spacing != 0.0) { z *= spacing; } const int numPoints = linearObjectBeingDrawn.getNumberOfLinks(); for (int i = 0; i < numPoints; i++) { const float* xyz = linearObjectBeingDrawn.getLinkXYZ(i); cc.addPoint(xyz[0], xyz[1], z); } cf->addContour(cc); // // If single sections, set to the section just drawn // if (cf->getSectionType() == ContourFile::SECTION_TYPE_SINGLE) { cf->setMinimumSelectedSection(cdd->getSectionNumber()); cf->setMaximumSelectedSection(cdd->getSectionNumber()); } } // // Update main window // GuiFilesModified fm; fm.setContourModified(); theMainWindow->fileModificationUpdate(fm); resetLinearObjectBeingDrawn(); updateGL(); } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: { // // Convert the window coordinate to a surface coordinate // float modelXYZ[3]; convertWindowToModelCoords(me.x, me.y, false, modelXYZ[0], modelXYZ[1], modelXYZ[2]); if (DebugControl::getDebugOn()) { std::cout << "Window: (" << me.x << ", " << me.y << ")" << " Model: (" << modelXYZ[0] << ", " << modelXYZ[1] << ", " << modelXYZ[2] << ")" << std::endl; } modelXYZ[2] = 0.0; linearObjectBeingDrawn.addBorderLink(modelXYZ, 0); /* if (linearObjectBeingDrawn.getNumberOfLinks() > 2) { // // Resample to contour spacing // GuiContourDrawDialog* cdd = theMainWindow->getContourDrawDialog(false); if (cdd != NULL) { int newNumLinks; linearObjectBeingDrawn.resampleBorderToDensity(cdd->getPointSpacing(), 2, newNumLinks); } } */ drawLinearObjectOnly = true; updateGL(); drawLinearObjectOnly = false; } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse process for contour align. */ void GuiBrainModelOpenGL::mouseContourAlign(const GuiBrainModelOpenGLMouseEvent& me) { BrainModelContours* bmc = getDisplayedBrainModelContours(); switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: { vtkTransform* matrix = bmc->getAlignmentRotationTransformMatrix(); matrix->RotateZ(-me.dx * 0.10); updateAllGL(this); } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: { float translate[3]; bmc->getAlignmentTranslation(translate); float multiplier = 0.1; // 0.5 #ifdef OS_MACX multiplier = 0.10; #endif translate[0] += me.dx * multiplier; translate[1] += me.dy * multiplier; translate[2] = 0.0; bmc->setAlignmentTranslation(translate); updateAllGL(this); } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: { float scale = bmc->getAlignmentScaling(); scale += me.dy * scale * 0.01; if (scale < 0.01) scale = 0.01; // negative would flip surface bmc->setAlignmentScaling(scale); updateAllGL(this); } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse process for contour region align. */ void GuiBrainModelOpenGL::mouseContourAlignRegion(const GuiBrainModelOpenGLMouseEvent& me) { BrainModelContours* bmc = getDisplayedBrainModelContours(); GuiContourAlignmentDialog* cad = theMainWindow->getContourAlignmentDialog(false); const int sectionNumber = cad->getAlignmentSectionNumber(); // // Convert mouse position to contour coordinates // float modelXYZ[3]; convertWindowToModelCoords(me.x, me.y, false, modelXYZ[0], modelXYZ[1], modelXYZ[2]); if (DebugControl::getDebugOn()) { std::cout << "Window: (" << me.x << ", " << me.y << ")" << " Model: (" << modelXYZ[0] << ", " << modelXYZ[1] << ", " << modelXYZ[2] << ")" << std::endl; } modelXYZ[2] = 0.0; switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: // // Clear the region and Set the start of the region // { bmc->resetAlignmentRegionBox(); bmc->setAlignmentRegionBoxStart(modelXYZ); updateGL(); } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: // // Select contour points within the region // { bmc->setAlignmentRegionBoxEnd(modelXYZ); float bounds[4]; bmc->getAlignmentRegionBox(bounds); ContourFile* contours = bmc->getContourFile(); contours->setSpecialFlags(sectionNumber, sectionNumber, bounds); ContourCellFile* contourCells = theMainWindow->getBrainSet(getModelViewNumber())->getContourCellFile(); contourCells->setSpecialFlags(sectionNumber, sectionNumber, bounds); updateGL(); } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: // // Reset contour region and clear selected contour points // { bmc->resetAlignmentRegionBox(); ContourFile* contours = bmc->getContourFile(); contours->clearSpecialFlags(); ContourCellFile* contourCells = theMainWindow->getBrainSet(getModelViewNumber())->getContourCellFile(); contourCells->clearAllSpecialFlags(); updateGL(); } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: // // Switch to alignment mode and clear the region // bmc->resetAlignmentRegionBox(); setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_ALIGN); updateGL(); break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: // // Set the end point of the region // { bmc->setAlignmentRegionBoxEnd(modelXYZ); updateGL(); } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse process for contour move point. */ void GuiBrainModelOpenGL::mouseContourPointMove(const GuiBrainModelOpenGLMouseEvent& me) { static int contourNumber = -1; static int pointNumber = -1; switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: contourNumber = -1; pointNumber = -1; selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_CONTOUR); if ((selectedContour.getItemIndex1() >= 0) && (selectedContour.getItemIndex2() >= 0)) { BrainModelContours* bmc = theMainWindow->getBrainModelContours(); if (bmc == NULL) { return; } contourNumber = selectedContour.getItemIndex1(); pointNumber = selectedContour.getItemIndex2(); } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: if ((contourNumber >= 0) && (pointNumber >= 0)) { BrainModelContours* bmc = theMainWindow->getBrainModelContours(); if (bmc == NULL) { return; } ContourFile* cf = bmc->getContourFile(); if (contourNumber < cf->getNumberOfContours()) { CaretContour* cc = cf->getContour(contourNumber); const int numPoints = cc->getNumberOfPoints(); if (pointNumber < numPoints) { float x, y, z; convertWindowToModelCoords(me.x, me.y, false, x, y, z); cc->setPointXY(pointNumber, x, y); } } updateAllGL(NULL); } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse process for contour delete point. */ void GuiBrainModelOpenGL::mouseContourPointDelete(const GuiBrainModelOpenGLMouseEvent& me) { switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_CONTOUR); if ((selectedContour.getItemIndex1() >= 0) && (selectedContour.getItemIndex2() >= 0)) { BrainModelContours* bmc = theMainWindow->getBrainModelContours(); if (bmc == NULL) { return; } ContourFile* cf = bmc->getContourFile(); CaretContour* cc = cf->getContour(selectedContour.getItemIndex1()); cc->deletePoint(selectedContour.getItemIndex2()); updateAllGL(NULL); } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse process for contour delete. */ void GuiBrainModelOpenGL::mouseContourDelete(const GuiBrainModelOpenGLMouseEvent& me) { switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_CONTOUR); if ((selectedContour.getItemIndex1() >= 0) && (selectedContour.getItemIndex2() >= 0)) { BrainModelContours* bmc = theMainWindow->getBrainModelContours(); if (bmc == NULL) { return; } ContourFile* cf = bmc->getContourFile(); cf->deleteContour(selectedContour.getItemIndex1()); updateAllGL(NULL); } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse process for contour reverse. */ void GuiBrainModelOpenGL::mouseContourReverse(const GuiBrainModelOpenGLMouseEvent& me) { switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_CONTOUR); if ((selectedContour.getItemIndex1() >= 0) && (selectedContour.getItemIndex2() >= 0)) { BrainModelContours* bmc = theMainWindow->getBrainModelContours(); if (bmc == NULL) { return; } ContourFile* cf = bmc->getContourFile(); CaretContour* contour = cf->getContour(selectedContour.getItemIndex1()); if (cf != NULL) { contour->reversePointOrder(); updateAllGL(NULL); } } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse process for contour delete. */ void GuiBrainModelOpenGL::mouseContourMerge(const GuiBrainModelOpenGLMouseEvent& me) { static int contourOne = -1; switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_CONTOUR); if ((selectedContour.getItemIndex1() >= 0) && (selectedContour.getItemIndex2() >= 0)) { BrainModelContours* bmc = theMainWindow->getBrainModelContours(); if (bmc == NULL) { return; } ContourFile* cf = bmc->getContourFile(); if (selectedContour.getItemIndex1() < cf->getNumberOfContours()) { contourOne = selectedContour.getItemIndex1(); } } else { QApplication::beep(); } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_CONTOUR); if ((selectedContour.getItemIndex1() >= 0) && (selectedContour.getItemIndex2() >= 0)) { BrainModelContours* bmc = theMainWindow->getBrainModelContours(); if (bmc == NULL) { return; } ContourFile* cf = bmc->getContourFile(); if (selectedContour.getItemIndex1() < cf->getNumberOfContours()) { if (contourOne < cf->getNumberOfContours()) { cf->mergeContours(contourOne, selectedContour.getItemIndex1()); GuiFilesModified fm; fm.setContourModified(); theMainWindow->fileModificationUpdate(fm); updateAllGL(NULL); } } } else { QApplication::beep(); } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse process for contour cell add mode. */ void GuiBrainModelOpenGL::mouseContourCellAdd(const GuiBrainModelOpenGLMouseEvent& me) { switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: { GuiAddCellsDialog* acd = theMainWindow->getAddContourCellsDialog(false); if (acd != NULL) { float modelXYZ[3]; convertWindowToModelCoords(me.x, me.y, false, modelXYZ[0], modelXYZ[1], modelXYZ[2]); if (DebugControl::getDebugOn()) { std::cout << "Window: (" << me.x << ", " << me.y << ")" << " Model: (" << modelXYZ[0] << ", " << modelXYZ[1] << ", " << modelXYZ[2] << ")" << std::endl; } BrainModelContours* bmc = theMainWindow->getBrainSet(getModelViewNumber())->getBrainModelContours(-1); if (bmc != NULL) { ContourFile* cf = bmc->getContourFile(); if (cf != NULL) { modelXYZ[2] = cf->getSectionSpacing() * cf->getMinimumSelectedSection(); acd->addContourCellAtXYZ(modelXYZ, cf->getMinimumSelectedSection()); } } } } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse processing for delete contour cell */ void GuiBrainModelOpenGL::mouseContourCellDelete(const GuiBrainModelOpenGLMouseEvent& me) { switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_CONTOUR_CELL); if (DebugControl::getDebugOn()) { std::cout << "Selected Contour Cell: " << selectedContourCell.getItemIndex1() << std::endl; } if (selectedContourCell.getItemIndex1() >= 0) { ContourCellFile* cf = theMainWindow->getBrainSet(getModelViewNumber())->getContourCellFile(); cf->deleteCell(selectedContourCell.getItemIndex1()); updateAllGL(NULL); } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse processing for delete contour cell */ void GuiBrainModelOpenGL::mouseContourCellMove(const GuiBrainModelOpenGLMouseEvent& me) { static int contourCellNumber = -1; switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_CONTOUR_CELL); if (DebugControl::getDebugOn()) { std::cout << "Selected Contour Cell: " << selectedContourCell.getItemIndex1() << std::endl; } if (selectedContourCell.getItemIndex1() >= 0) { contourCellNumber = selectedContourCell.getItemIndex1(); updateGL(); } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: contourCellNumber = -1; break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: { ContourCellFile* cf = theMainWindow->getBrainSet(getModelViewNumber())->getContourCellFile(); if ((contourCellNumber >= 0) && (contourCellNumber < cf->getNumberOfCells())) { CellData* cell = cf->getCell(contourCellNumber); float xyz[3]; cell->getXYZ(xyz); float x, y, z; convertWindowToModelCoords(me.x, me.y, false, x, y, z); xyz[0] = x; xyz[1] = y; // ignore Z cell->setXYZ(xyz); updateGL(); } } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse process for roi sulcal border start node. */ void GuiBrainModelOpenGL::mouseSurfaceROISulcalBorderNodeStart(const GuiBrainModelOpenGLMouseEvent& me) { switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_NODE); if (selectedNode.getItemIndex1() >= 0) { GuiSurfaceRegionOfInterestDialog* roi = theMainWindow->getSurfaceRegionOfInterestDialog(false); if (roi != NULL) { roi->setCreateLinearBorderStartNode(selectedNode.getItemIndex1()); } GuiSurfaceRegionOfInterestDialogOLD* roiOLD = theMainWindow->getSurfaceRegionOfInterestDialogOLD(false); if (roiOLD != NULL) { roiOLD->setCreateBorderOpenStartNode(selectedNode.getItemIndex1()); } } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse process for roi sulcal border end node. */ void GuiBrainModelOpenGL::mouseSurfaceROISulcalBorderNodeEnd(const GuiBrainModelOpenGLMouseEvent& me) { switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_NODE); if (selectedNode.getItemIndex1() >= 0) { GuiSurfaceRegionOfInterestDialog* roi = theMainWindow->getSurfaceRegionOfInterestDialog(false); if (roi != NULL) { roi->setCreateLinearBorderEndNode(selectedNode.getItemIndex1()); } GuiSurfaceRegionOfInterestDialogOLD* roiOLD = theMainWindow->getSurfaceRegionOfInterestDialogOLD(false); if (roiOLD != NULL) { roiOLD->setCreateBorderOpenEndNode(selectedNode.getItemIndex1()); } } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse process for image subregion selection. */ void GuiBrainModelOpenGL::mouseImageSubRegion(const GuiBrainModelOpenGLMouseEvent& me) { bool redraw = false; const int x = me.x; const int y = windowHeight[viewingWindowIndex] - me.y; switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: imageSubRegionBoxValid = true; imageSubRegionBox[0] = x; imageSubRegionBox[1] = y; imageSubRegionBox[2] = x; imageSubRegionBox[3] = y; redraw = true; break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: //imageSubRegionBoxValid = false; break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: imageSubRegionBox[2] = x; imageSubRegionBox[3] = y; redraw = true; break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } if (redraw) { updateGL(); } } /** * mouse processing for volume paint editing */ void GuiBrainModelOpenGL::mouseVolumePaintEdit(const GuiBrainModelOpenGLMouseEvent& me) { switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: { // // Make sure we are looking at a volume // BrainModelVolume* bmv = getDisplayedBrainModelVolume(); if (bmv != NULL) { // // See if a paint volume is selected // VolumeFile* paintVolume = bmv->getSelectedVolumePaintFile(); if (paintVolume != NULL) { // // Get the paint volume editing dialog // GuiVolumePaintEditorDialog* volumePaintEditorDialog = theMainWindow->getVolumePaintEditorDialog(false); if (volumePaintEditorDialog != NULL) { // // Tell rending that a paint is being edited so that // voxels with value 0 will be reported // openGL->setEditingPaintVolumeFlag(true); // // Process voxel selection // if (paintVolume == bmv->getOverlayPrimaryVolumeFile()) { selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_VOXEL_OVERLAY_PRIMARY); if (selectedVoxelOverlayPrimary.getItemIndex1() >= 0) { volumePaintEditorDialog->processVoxel( selectedVoxelOverlayPrimary.getItemIndex1(), selectedVoxelOverlayPrimary.getItemIndex2(), selectedVoxelOverlayPrimary.getItemIndex3(), static_cast(selectedVoxelOverlayPrimary.getItemIndex4())); } } else if (paintVolume == bmv->getOverlaySecondaryVolumeFile()) { selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_VOXEL_OVERLAY_SECONDARY); if (selectedVoxelOverlaySecondary.getItemIndex1() >= 0) { volumePaintEditorDialog->processVoxel( selectedVoxelOverlaySecondary.getItemIndex1(), selectedVoxelOverlaySecondary.getItemIndex2(), selectedVoxelOverlaySecondary.getItemIndex3(), static_cast(selectedVoxelOverlaySecondary.getItemIndex4())); } } else if (paintVolume == bmv->getUnderlayVolumeFile()) { selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_VOXEL_UNDERLAY); if (selectedVoxelUnderlay.getItemIndex1() >= 0) { volumePaintEditorDialog->processVoxel( selectedVoxelUnderlay.getItemIndex1(), selectedVoxelUnderlay.getItemIndex2(), selectedVoxelUnderlay.getItemIndex3(), static_cast(selectedVoxelUnderlay.getItemIndex4())); } } // // Tell rending that a paint is NO longer being edited // openGL->setEditingPaintVolumeFlag(false); } } } } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse processing for volume segmentation editing */ void GuiBrainModelOpenGL::mouseVolumeSegmentationEdit(const GuiBrainModelOpenGLMouseEvent& me) { switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: { // // Make sure we are looking at a volume // BrainModelVolume* bmv = getDisplayedBrainModelVolume(); if (bmv != NULL) { // // See if a segmentation volume is selected // VolumeFile* segmentVolume = bmv->getSelectedVolumeSegmentationFile(); if (segmentVolume != NULL) { // // Get the segmentation volume editing dialog // GuiVolumeSegmentationEditorDialog* volumeSegmentationEditorDialog = theMainWindow->getVolumeSegmentationEditorDialog(false); if (volumeSegmentationEditorDialog != NULL) { // // Tell rending that a segmentation is being edited so that // voxels with value 0 will be reported // openGL->setEditingSegmentationVolumeFlag(true); // // Process voxel selection // if (segmentVolume == bmv->getOverlayPrimaryVolumeFile()) { selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_VOXEL_OVERLAY_PRIMARY); if (selectedVoxelOverlayPrimary.getItemIndex1() >= 0) { volumeSegmentationEditorDialog->processVoxel( selectedVoxelOverlayPrimary.getItemIndex1(), selectedVoxelOverlayPrimary.getItemIndex2(), selectedVoxelOverlayPrimary.getItemIndex3(), static_cast(selectedVoxelOverlayPrimary.getItemIndex4())); } } else if (segmentVolume == bmv->getOverlaySecondaryVolumeFile()) { selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_VOXEL_OVERLAY_SECONDARY); if (selectedVoxelOverlaySecondary.getItemIndex1() >= 0) { volumeSegmentationEditorDialog->processVoxel( selectedVoxelOverlaySecondary.getItemIndex1(), selectedVoxelOverlaySecondary.getItemIndex2(), selectedVoxelOverlaySecondary.getItemIndex3(), static_cast(selectedVoxelOverlaySecondary.getItemIndex4())); } } else if (segmentVolume == bmv->getUnderlayVolumeFile()) { selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_VOXEL_UNDERLAY); if (selectedVoxelUnderlay.getItemIndex1() >= 0) { volumeSegmentationEditorDialog->processVoxel( selectedVoxelUnderlay.getItemIndex1(), selectedVoxelUnderlay.getItemIndex2(), selectedVoxelUnderlay.getItemIndex3(), static_cast(selectedVoxelUnderlay.getItemIndex4())); } } // // Tell rending that a segmentation is NO longer being edited // openGL->setEditingSegmentationVolumeFlag(false); } } } } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse mode for adding a node. */ void GuiBrainModelOpenGL::mouseAddNodes(const GuiBrainModelOpenGLMouseEvent& me) { switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: { // // Add a node assuming viewing X/Y plane. // BrainModelSurface* bms = getDisplayedBrainModelSurface(); if (bms != NULL) { float x, y, z; convertWindowToModelCoords(me.x, me.y, false, x, y, z); theMainWindow->getBrainSet(getModelViewNumber())->addNodes(1); CoordinateFile* cf = bms->getCoordinateFile(); const int lastNode = cf->getNumberOfCoordinates() - 1; if (lastNode >= 0) { cf->setCoordinate(lastNode, x, y, 0.0f); } updateAllGL(); } } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse mode for adding a tile. */ void GuiBrainModelOpenGL::mouseAddTile(const GuiBrainModelOpenGLMouseEvent& me) { switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: { BrainModelSurface* bms = getDisplayedBrainModelSurface(); if (bms != NULL) { selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_NODE); const int nodeNumber = selectedNode.getItemIndex1(); if (nodeNumber >= 0) { if (newTileNodeCounter < 3) { newTileNodeNumbers[newTileNodeCounter] = nodeNumber; newTileNodeCounter++; if (newTileNodeCounter == 3) { TopologyFile* tf = bms->getTopologyFile(); if (tf == NULL) { tf = new TopologyFile; theMainWindow->getBrainSet(getModelViewNumber())->addTopologyFile(tf); bms->setTopologyFile(tf); } tf->addTile(newTileNodeNumbers); newTileNodeCounter = 0; } } else { newTileNodeCounter = 0; } theMainWindow->getBrainSet(getModelViewNumber())->clearAllDisplayLists(); updateAllGL(); } else { QApplication::beep(); } } } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse mode for deleting tile by clicking link. */ void GuiBrainModelOpenGL::mouseDeleteTileByLink(const GuiBrainModelOpenGLMouseEvent& me) { switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: { BrainModelSurface* bms = getDisplayedBrainModelSurface(); if (bms != NULL) { selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_LINK); const int nodeNumber1 = selectedLink.getItemIndex1(); const int nodeNumber2 = selectedLink.getItemIndex2(); TopologyFile* tf = bms->getTopologyFile(); if (tf != NULL) { tf->deleteTilesWithEdge(nodeNumber1, nodeNumber2); } updateAllGL(); } } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse mode for disconnect node. */ void GuiBrainModelOpenGL::mouseDisconnectNode(const GuiBrainModelOpenGLMouseEvent& me) { switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: { BrainModelSurface* bms = getDisplayedBrainModelSurface(); if (bms != NULL) { selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_NODE); const int nodeNumber = selectedNode.getItemIndex1(); if (nodeNumber >= 0) { TopologyFile* tf = bms->getTopologyFile(); if (tf != NULL) { const int numNodes = tf->getNumberOfNodes(); if (nodeNumber < numNodes) { std::vector nodesToDelete(numNodes, false); nodesToDelete[nodeNumber] = true; tf->deleteTilesWithMarkedNodes(nodesToDelete); } } updateAllGL(); } } } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse mode for setting transformation matrix translate. */ void GuiBrainModelOpenGL::mouseTranslationAxesSetTranslate(const GuiBrainModelOpenGLMouseEvent& me) { selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_ALL); switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: { GuiTransformationMatrixDialog* tmd = theMainWindow->getTransformMatrixEditor(); if (tmd != NULL) { // // Find the identified items // bool validXYZ = false; float x, y, z; float depth = std::numeric_limits::max(); if (selectedNode.getItemIndex1() >= 0) { const BrainModelSurface* bms = getDisplayedBrainModelSurface(); if (bms != NULL) { const int node = selectedNode.getItemIndex1(); if ((node >= 0) && (node < bms->getNumberOfNodes())) { const CoordinateFile* cf = bms->getCoordinateFile(); if (selectedNode.getDepth() < depth) { cf->getCoordinate(node, x, y, z); depth = selectedNode.getDepth(); validXYZ = true; } } } } BrainModelVolume* bmv = getDisplayedBrainModelVolume(); if (bmv != NULL) { VolumeFile* vf = NULL; int ijk[3] = { -1, -1, -1 }; float vd = std::numeric_limits::max(); if (selectedVoxelUnderlay.getItemIndex1() >= 0) { vf = bmv->getUnderlayVolumeFile(); if (vf != NULL) { if (vf != NULL) { ijk[0] = selectedVoxelUnderlay.getItemIndex1(); ijk[1] = selectedVoxelUnderlay.getItemIndex2(); ijk[2] = selectedVoxelUnderlay.getItemIndex3(); vd = selectedVoxelUnderlay.getDepth(); } } } if (selectedVoxelOverlaySecondary.getItemIndex1() >= 0) { vf = bmv->getOverlaySecondaryVolumeFile(); if (vf != NULL) { if (vf != NULL) { ijk[0] = selectedVoxelOverlaySecondary.getItemIndex1(); ijk[1] = selectedVoxelOverlaySecondary.getItemIndex2(); ijk[2] = selectedVoxelOverlaySecondary.getItemIndex3(); vd = selectedVoxelOverlaySecondary.getDepth(); } } } if (selectedVoxelOverlayPrimary.getItemIndex1() >= 0) { vf = bmv->getOverlayPrimaryVolumeFile(); if (vf != NULL) { if (vf != NULL) { ijk[0] = selectedVoxelOverlayPrimary.getItemIndex1(); ijk[1] = selectedVoxelOverlayPrimary.getItemIndex2(); ijk[2] = selectedVoxelOverlayPrimary.getItemIndex3(); vd = selectedVoxelOverlayPrimary.getDepth(); } } } if (ijk[0] >= 0) { float s[3], o[3]; vf->getOrigin(o); vf->getSpacing(s); if (vd < depth) { x = o[0] + s[0] * ijk[0]; y = o[1] + s[1] * ijk[1]; z = o[2] + s[2] * ijk[2]; depth = vd; validXYZ = true; } } } if (selectedVtkModel.getItemIndex1() >= 0) { const int modelNum = selectedVtkModel.getItemIndex1(); const int tileNum = selectedVtkModel.getItemIndex2(); if ((modelNum >= 0) && (modelNum < theMainWindow->getBrainSet(getModelViewNumber())->getNumberOfVtkModelFiles())) { const VtkModelFile* vmf = theMainWindow->getBrainSet(getModelViewNumber())->getVtkModelFile(modelNum); float xyz[3]; vmf->getTriangleCoordinate(tileNum, xyz); if (selectedVtkModel.getDepth() < depth) { x = xyz[0]; y = xyz[1]; z = xyz[2]; depth = selectedVtkModel.getDepth(); validXYZ = true; } } } // // If transformation axis selected, switch to transform axes mouse mode // if ((selectedTransformationAxes.getItemIndex1() >= 0) && (selectedTransformationAxes.getDepth() < depth)) { setMouseMode(MOUSE_MODE_TRANSFORMATION_MATRIX_AXES); TransformationMatrixFile* tmf = theMainWindow->getBrainSet(getModelViewNumber())->getTransformationMatrixFile(); const int indx = selectedTransformationAxes.getItemIndex1(); if ((indx >= 0) && (indx < tmf->getNumberOfMatrices())) { tmf->setSelectedTransformationAxesIndex(indx); } updateAllGL(); return; } else if (validXYZ) { tmd->setTranslation(x, y, z); } } } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse mode for translation axes. */ void GuiBrainModelOpenGL::mouseTranslationAxes(const GuiBrainModelOpenGLMouseEvent& me) { TransformationMatrixFile* tmf = theMainWindow->getBrainSet(getModelViewNumber())->getTransformationMatrixFile(); const int indx = tmf->getSelectedTransformationAxesIndex(); if ((indx < 0) || (indx >= tmf->getNumberOfMatrices())) { return; } TransformationMatrix* tm = tmf->getTransformationMatrix(indx); BrainModelSurface* bms = getDisplayedBrainModelSurface(); if (bms == NULL) { bms = getDisplayedBrainModelSurfaceAndVolume(); } vtkTransform* surfRotMatrix = NULL; if (bms != NULL) { surfRotMatrix = bms->getRotationTransformMatrix(viewingWindowIndex); } else { BrainModelVolume* bmv = getDisplayedBrainModelVolume(); if (bmv != NULL) { surfRotMatrix = bmv->getRotationTransformMatrix(viewingWindowIndex); } //std::cout << "ERROR: No surface but doing translation axes." << std::endl; } switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: { selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_TRANSFORMATION_MATRIX_AXES); const int newItem = selectedTransformationAxes.getItemIndex1(); if (newItem == indx) { setMouseMode(MOUSE_MODE_VIEW); } else if ((newItem >= 0) && (newItem < tmf->getNumberOfMatrices())) { tmf->setSelectedTransformationAxesIndex(newItem); updateAllGL(); } } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: { GuiTransformationMatrixDialog* tmd = theMainWindow->getTransformMatrixEditor(); if (tmd != NULL) { tmd->axesEventInMainWindow(); } } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: { //vtkTransform* matrix = dss->getTransformationAxesRotationMatrix(); float rotX = -me.dy; float rotY = me.dx; float rotZ = 0.0; if ((rotX != 0.0) || (rotY != 0.0)) { /* // works if surface NOT rotated TransformationMatrix t1; t1.rotateZ(rotZ); t1.rotateX(rotX); t1.rotateY(rotY); tm->multiply(t1); */ /* // works if surface is rotated but NOT if surface is translated TransformationMatrix t2; if (surfRotMatrix != NULL) { t2.setMatrix(surfRotMatrix); } float r[3] = { rotX, rotY, rotZ }; t2.multiplyPoint(r); std::cout << "rot: " << rotX << ", " << rotY << ", " << rotZ << std::endl; std::cout << "r[]: " << r[0] << ", " << r[1] << ", " << r[2] << std::endl; std::cout << std::endl; TransformationMatrix t3; t3.rotateZ(r[2]); t3.rotateX(r[0]); t3.rotateY(r[1]); tm->multiply(t3); */ // // Alter the rotation angles using the surface viewing matrix // TransformationMatrix t2; if (surfRotMatrix != NULL) { t2.setMatrix(surfRotMatrix); } float r[3] = { rotX, rotY, rotZ }; t2.multiplyPoint(r); // // Create a matrix containing the rotations // TransformationMatrix t3; t3.rotateZ(r[2]); t3.rotateX(r[0]); t3.rotateY(r[1]); // // Remove translation from axes matrix, // Multiply axes matrix by rotation matrix // Add translation back to axes matrix // float tx, ty, tz; tm->getTranslation(tx, ty, tz); tm->translate(-tx, -ty, -tz); tm->preMultiply(t3); tm->translate(tx, ty, tz); theMainWindow->updateTransformationMatrixEditor(tm); updateAllGL(); } } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: { /* float dt[4] = { me.dx, me.dy, 0.0, 1.0 }; if (surfRotMatrix != NULL) { float dt2[4]; surfRotMatrix->MultiplyPoint(dt, dt2); dt[0] = dt2[0]; dt[1] = dt2[1]; dt[2] = dt2[2]; } tm->translate(dt[0], dt[1], dt[2]); */ const double txyz[3] = { me.dx, me.dy, 0.0 }; tm->translate(txyz, surfRotMatrix); theMainWindow->updateTransformationMatrixEditor(tm); updateAllGL(); } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: { /* float dt[4] = { 0.0, 0.0, -me.dy, 1.0 }; if (surfRotMatrix != NULL) { float dt2[4]; surfRotMatrix->MultiplyPoint(dt, dt2); dt[0] = dt2[0]; dt[1] = dt2[1]; dt[2] = dt2[2]; } tm->translate(dt[0], dt[1], dt[2]); */ const double txyz[3] = { 0.0, 0.0, -me.dy }; tm->translate(txyz, surfRotMatrix); theMainWindow->updateTransformationMatrixEditor(tm); updateAllGL(); } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * mouse mode for move node. */ void GuiBrainModelOpenGL::mouseMoveNode(const GuiBrainModelOpenGLMouseEvent& me) { static int nodeNumber = -1; switch(me.event) { case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CLICK: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_PRESS: selectBrainModelItem(me.x, me.y, BrainModelOpenGL::SELECTION_MASK_NODE); nodeNumber = selectedNode.getItemIndex1(); break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_RELEASE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_PRESS: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_MOVE: if (nodeNumber >= 0) { BrainModelSurface* bms = getDisplayedBrainModelSurface(); if (bms != NULL) { CoordinateFile* cf = bms->getCoordinateFile(); if (nodeNumber < cf->getNumberOfCoordinates()) { float x, y, z, zorig; cf->getCoordinate(nodeNumber, x, y, zorig); convertWindowToModelCoords(me.x, me.y, false, x, y, z); cf->setCoordinate(nodeNumber, x, y, zorig); updateGL(); } } } break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_SHIFT_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_CONTROL_MOVE: break; case GuiBrainModelOpenGLMouseEvent::MOUSE_LEFT_ALT_MOVE: break; } } /** * get the maximum point size. */ void GuiBrainModelOpenGL::getPointSizeRange(float& minSize, float& maxSize) { minSize = minPointSize; maxSize = maxPointSize; } /** * get the maximum line width. */ void GuiBrainModelOpenGL::getLineWidthRange(float& minSize, float& maxSize) { minSize = minLineSize; maxSize = maxLineSize; } /** * get caption displayed in main window. */ QString GuiBrainModelOpenGL::getMainWindowCaption() { return openGL->getMainWindowCaption(); } /** * set caption displayed in main window. */ void GuiBrainModelOpenGL::setMainWindowCaption(const QString& s) { openGL->setMainWindowCaption(s); } /** * get main window center model coordinate (returns true if valid). */ bool GuiBrainModelOpenGL::getMainWindowCenterModelCoordinate(float posOut[3]) { return allBrainSurfaceOpenGL[BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW]->convertWindowToModelCoords( allBrainSurfaceOpenGL[BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW]->windowWidth[BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW] / 2, allBrainSurfaceOpenGL[BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW]->windowHeight[BrainModel::BRAIN_MODEL_VIEW_MAIN_WINDOW] / 2, true, posOut[0], posOut[1], posOut[2]); } /** * are viewing an oblique slice in a window. */ bool GuiBrainModelOpenGL::viewingObliqueSlice() { for (int i = 0; i < BrainModel::NUMBER_OF_BRAIN_MODEL_VIEW_WINDOWS; i++) { if (allBrainSurfaceOpenGL[i] != NULL) { BrainModelVolume* bmv = allBrainSurfaceOpenGL[i]->getDisplayedBrainModelVolume(); if (bmv != NULL) { switch (bmv->getSelectedAxis(i)) { case VolumeFile::VOLUME_AXIS_X: break; case VolumeFile::VOLUME_AXIS_Y: break; case VolumeFile::VOLUME_AXIS_Z: break; case VolumeFile::VOLUME_AXIS_ALL: break; case VolumeFile::VOLUME_AXIS_OBLIQUE: break; case VolumeFile::VOLUME_AXIS_OBLIQUE_X: case VolumeFile::VOLUME_AXIS_OBLIQUE_Y: case VolumeFile::VOLUME_AXIS_OBLIQUE_Z: case VolumeFile::VOLUME_AXIS_OBLIQUE_ALL: return true; break; case VolumeFile::VOLUME_AXIS_UNKNOWN: break; } } } } return false; } /** * redraw window. */ void GuiBrainModelOpenGL::slotRedrawWindow() { updateAllGL(this); qApp->processEvents(); } caret-5.6.4~dfsg.1.orig/caret/GuiBordersCreateInterpolatedDialog.h0000664000175000017500000000524211572067322024717 0ustar michaelmichael #ifndef __GUI_BORDERS_CREATE_INTERPOLATED_DIALOG_H__ #define __GUI_BORDERS_CREATE_INTERPOLATED_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "WuQDialog.h" class QDoubleSpinBox; class QLabel; class QLineEdit; class QSpinBox; /// dialog for creating interpolated borders class GuiBordersCreateInterpolatedDialog : public WuQDialog { Q_OBJECT public: // interpolate border selection enum INTERPOLATE_BORDER { // first border for interpolation INTERPOLATE_BORDER_1, // second border for interpolation INTERPOLATE_BORDER_2 }; // constructor GuiBordersCreateInterpolatedDialog(QWidget* parent); // destructor ~GuiBordersCreateInterpolatedDialog(); // called to update a border selection void updateBorderSelection(const INTERPOLATE_BORDER interpolateBorderChoice, const int borderIndex); protected slots: /// called when Apply button pressed void slotApplyPushButton(); /// set the mouse mode for picking borders void slotSetMouseModeForThisDialog(); protected: /// sampling double spin box QDoubleSpinBox* samplingDoubleSpinBox; /// name prefix line edit QLineEdit* namePrefixLineEdit; /// number of interpolated borders spin box QSpinBox* numberOfInterplatedBordersSpinBox; /// label for first border number and name QLabel* firstBorderNumberAndNameLabel; /// label for second border number and name QLabel* secondBorderNumberAndNameLabel; /// index of first border int firstBorderIndex; /// index of second border int secondBorderIndex; }; #endif // __GUI_BORDERS_CREATE_INTERPOLATED_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiBordersCreateInterpolatedDialog.cxx0000664000175000017500000002274211572067322025276 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include "BorderColorFile.h" #include "BrainModelBorderSet.h" #include "BrainSet.h" #include "GuiBordersCreateInterpolatedDialog.h" #include "GuiBrainModelOpenGL.h" #include "GuiColorSelectionDialog.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "global_variables.h" /** * constructor. */ GuiBordersCreateInterpolatedDialog::GuiBordersCreateInterpolatedDialog(QWidget* parent) : WuQDialog(parent) { setWindowTitle("Create Interpolated Borders."); // // first border label // const int numberAndNameLength = 30; QLabel* firstBorderLabel = new QLabel("Border 1 (left click): "); firstBorderNumberAndNameLabel = new QLabel(QString(' ', numberAndNameLength)); // // second border label // QLabel* secondBorderLabel = new QLabel("Border 2 (shift-left click): "); secondBorderNumberAndNameLabel = new QLabel(QString(' ', numberAndNameLength)); // // Name prefix // QLabel* namePrefixLabel = new QLabel("Name Prefix"); namePrefixLineEdit = new QLineEdit; namePrefixLineEdit->setText("LANDMARK.Interpolated"); namePrefixLineEdit->setMinimumWidth(300); // // Sampling // QLabel* samplingLabel = new QLabel("Sampling"); samplingDoubleSpinBox = new QDoubleSpinBox; samplingDoubleSpinBox->setMinimum(0.0); samplingDoubleSpinBox->setMaximum(1000000.0); samplingDoubleSpinBox->setSingleStep(1.0); samplingDoubleSpinBox->setDecimals(2); samplingDoubleSpinBox->setValue(1.0); // // Number of interpolated borders // QLabel* numberOfInterpolatedBordersLabel = new QLabel("Number of Interpolated Borders"); numberOfInterplatedBordersSpinBox = new QSpinBox; numberOfInterplatedBordersSpinBox->setMinimum(1); numberOfInterplatedBordersSpinBox->setMaximum(100000); numberOfInterplatedBordersSpinBox->setSingleStep(1); numberOfInterplatedBordersSpinBox->setValue(2); // // Row numbers for widgets // int numberOfRows = 0; const int border1Row = numberOfRows++; const int border2Row = numberOfRows++; const int namePrefixRow = numberOfRows++; const int samplingRow = numberOfRows++; const int interpolateRow = numberOfRows++; // // Grid layout for items // QGridLayout* gridLayout = new QGridLayout; gridLayout->addWidget(firstBorderLabel, border1Row, 0, 1, 1); gridLayout->addWidget(firstBorderNumberAndNameLabel, border1Row, 1, 1, 1); gridLayout->addWidget(secondBorderLabel, border2Row, 0, 1, 1); gridLayout->addWidget(secondBorderNumberAndNameLabel, border2Row, 1, 1, 1); gridLayout->addWidget(namePrefixLabel, namePrefixRow, 0, 1, 1); gridLayout->addWidget(namePrefixLineEdit, namePrefixRow, 1, 1, 1); gridLayout->addWidget(samplingLabel, samplingRow, 0, 1, 1); gridLayout->addWidget(samplingDoubleSpinBox, samplingRow, 1, 1, 1); gridLayout->addWidget(numberOfInterpolatedBordersLabel, interpolateRow, 0, 1, 1); gridLayout->addWidget(numberOfInterplatedBordersSpinBox, interpolateRow, 1, 1, 1); // // Enable mouse button // QPushButton* enableMousePushButton = new QPushButton("Enable Mouse"); enableMousePushButton->setFixedSize(enableMousePushButton->sizeHint()); enableMousePushButton->setAutoDefault(false); QObject::connect(enableMousePushButton, SIGNAL(clicked()), this, SLOT(slotSetMouseModeForThisDialog())); // // Get the dialogs layout // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->addLayout(gridLayout); dialogLayout->addWidget(enableMousePushButton); dialogLayout->addStretch(); // // Dialog buttons // QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Apply | QDialogButtonBox::Close); dialogLayout->addWidget(buttonBox); QPushButton* applyButton = buttonBox->button(QDialogButtonBox::Apply); QObject::connect(applyButton, SIGNAL(clicked()), this, SLOT(slotApplyPushButton())); QObject::connect(buttonBox, SIGNAL(rejected()), this, SLOT(close())); } /** * destructor. */ GuiBordersCreateInterpolatedDialog::~GuiBordersCreateInterpolatedDialog() { } /** * called to update a border selection. */ void GuiBordersCreateInterpolatedDialog::updateBorderSelection(const INTERPOLATE_BORDER interpolateBorderChoice, const int borderIndex) { // // Get index and name of border // BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); const BrainModelBorder* b = bmbs->getBorder(borderIndex); const QString labelValue(QString::number(borderIndex) + " " + b->getName()); switch (interpolateBorderChoice) { case INTERPOLATE_BORDER_1: firstBorderIndex = borderIndex; firstBorderNumberAndNameLabel->setText(labelValue); break; case INTERPOLATE_BORDER_2: secondBorderIndex = borderIndex; secondBorderNumberAndNameLabel->setText(labelValue); break; } } /** * called when Apply button pressed. */ void GuiBordersCreateInterpolatedDialog::slotApplyPushButton() { // // Interpolate the borders // const QString borderName(namePrefixLineEdit->text()); QString errorMessage; BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); bmbs->createInterpolatedBorders(theMainWindow->getBrainModelSurface(), firstBorderIndex, secondBorderIndex, borderName, numberOfInterplatedBordersSpinBox->value(), samplingDoubleSpinBox->value(), errorMessage); if (errorMessage.isEmpty() == false) { QMessageBox::critical(this, "ERROR", errorMessage); return; } // // Find the matching color // bool borderColorMatch = false; BorderColorFile* borderColorFile = theMainWindow->getBrainSet()->getBorderColorFile(); const int borderColorIndex = borderColorFile->getColorIndexByName(borderName, borderColorMatch); // // Border color may need to be created // bool createBorderColor = false; if ((borderColorIndex >= 0) && (borderColorMatch == true)) { createBorderColor = false; } else if ((borderColorIndex >= 0) && (borderColorMatch == false)) { QString msg("Use border color \""); msg.append(borderColorFile->getColorNameByIndex(borderColorIndex)); msg.append("\" for border "); msg.append(borderName); msg.append(" ?"); QString noButton("No, define color "); noButton.append(borderName); if (QMessageBox::information(this, "Use Partially Matching Color", msg, (QMessageBox::Yes | QMessageBox::No), QMessageBox::No) == QMessageBox::No) { createBorderColor = true; } } else { createBorderColor = true; } if (createBorderColor) { QString title("Create Border Color: "); title.append(borderName); GuiColorSelectionDialog* csd = new GuiColorSelectionDialog(this, title, false, false, false, false); csd->exec(); // // Add new border color // float pointSize = 2.0, lineSize = 1.0; unsigned char r, g, b, a; ColorFile::ColorStorage::SYMBOL symbol; csd->getColorInformation(r, g, b, a, pointSize, lineSize, symbol); borderColorFile->addColor(borderName, r, g, b, a, pointSize, lineSize, symbol); } GuiFilesModified fm; fm.setBorderModified(); fm.setBorderColorModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } /** * set the mouse mode for picking borders. */ void GuiBordersCreateInterpolatedDialog::slotSetMouseModeForThisDialog() { theMainWindow->getBrainModelOpenGL()->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_BORDER_INTERPOLATE); } caret-5.6.4~dfsg.1.orig/caret/GuiBorderProjectionDialog.h0000664000175000017500000000313611572067322023072 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_GUI_BORDER_PROJECTION_DIALOG_H__ #define __VE_GUI_BORDER_PROJECTION_DIALOG_H__ #include "WuQDialog.h" class QRadioButton; /// This class creates the border projection dialog. class GuiBorderProjectionDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiBorderProjectionDialog(QWidget* parent); /// Destructor ~GuiBorderProjectionDialog(); private: /// called by QDialog when accept/reject signal is emitted void done(int r); /// projection method nearest button QRadioButton* nearestNodeButton; /// projection method nearest button QRadioButton* nearestTileButton; }; #endif // __VE_GUI_BORDER_PROJECTION_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiBorderProjectionDialog.cxx0000664000175000017500000000762411572067322023453 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include "BorderFileProjector.h" #include "BorderProjectionFile.h" #include "BrainModelBorderSet.h" #include "BrainSet.h" #include "GuiBrainModelOpenGL.h" #include "GuiBorderProjectionDialog.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "QtUtilities.h" #include "global_variables.h" /** * Constructor */ GuiBorderProjectionDialog::GuiBorderProjectionDialog(QWidget* parent) : WuQDialog(parent) { setModal(true); setWindowTitle("Border Projection"); QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(5); // // Projection method buttons // QGroupBox* projGroupBox = new QGroupBox("Projection Method"); dialogLayout->addWidget(projGroupBox); nearestNodeButton = new QRadioButton("Nearest Node"); nearestTileButton = new QRadioButton("Nearest Tile"); QVBoxLayout* projGroupLayout = new QVBoxLayout(projGroupBox); projGroupLayout->addWidget(nearestNodeButton); projGroupLayout->addWidget(nearestTileButton); QButtonGroup* buttGroup = new QButtonGroup(this); buttGroup->addButton(nearestNodeButton); buttGroup->addButton(nearestTileButton); nearestTileButton->setChecked(true); // // Buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; dialogLayout->addLayout(buttonsLayout); buttonsLayout->setSpacing(5); QPushButton* ok = new QPushButton("OK"); QObject::connect(ok, SIGNAL(clicked()), this, SLOT(accept())); buttonsLayout->addWidget(ok); QPushButton* close = new QPushButton("Cancel"); QObject::connect(close, SIGNAL(clicked()), this, SLOT(reject())); buttonsLayout->addWidget(close); QtUtilities::makeButtonsSameSize(ok, close); } /** * Destructor */ GuiBorderProjectionDialog::~GuiBorderProjectionDialog() { } /** * called by QDialog when accept/reject signal is emitted. */ void GuiBorderProjectionDialog::done(int r) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); if (r == QDialog::Accepted) { GuiBrainModelOpenGL* openGL = theMainWindow->getBrainModelOpenGL(); BrainModelSurface* bms = openGL->getDisplayedBrainModelSurface(); if (bms != NULL) { // // Project borders used by this surface // BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); bmbs->projectBorders(bms, nearestTileButton->isChecked()); // // Notify that borders have been changed. // GuiFilesModified fm; fm.setBorderModified(); theMainWindow->fileModificationUpdate(fm); // // Update all displayed surfaces // GuiBrainModelOpenGL::updateAllGL(NULL); } } // // Call parent' method to close dialog. // QDialog::done(r); QApplication::restoreOverrideCursor(); } caret-5.6.4~dfsg.1.orig/caret/GuiBorderOperationsDialog.h0000664000175000017500000005034711572067322023107 0ustar michaelmichael #ifndef __GUI_BORDER_OPERATIONS_DIALOG_H__ #define __GUI_BORDER_OPERATIONS_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelBorderSet.h" #include "WuQMultiPageDialog.h" class BordersPageCreateFlatAnalysisGridBorders; class BordersPageCreateFlatGridBorders; class BordersPageCreateInterpolatedBorders; class BordersPageCreateLandmarks; class BordersPageDrawNew; class BordersPageEditAttributes; class BordersPageUpdateExisting; class GuiBrainModelSelectionComboBox; class GuiBrainModelSurfaceSelectionComboBox; class GuiColorFileEditorWidget; class GuiNodeAttributeColumnSelectionComboBox; class GuiStereotaxicSpaceComboBox; class GuiVolumeFileSelectionComboBox; class QCheckBox; class QComboBox; class QDoubleSpinBox; class QGroupBox; class QLabel; class QLineEdit; class QRadioButton; class QSpinBox; class VolumeFile; /// dialog for border operations class GuiBorderOperationsDialog : public WuQMultiPageDialog { Q_OBJECT public: // constructor GuiBorderOperationsDialog(QWidget* parent); // destructor ~GuiBorderOperationsDialog(); // get border drawing parameters void getBorderDrawingParameters(QString& borderNameOut, float& samplingOut, int& borderColorIndexOut, int& surfacePaintAssignmentColumnNumberOut, int& surfacePaintNameAssignmentIndexOut, VolumeFile* &paintVolumeForVoxelAssignmentOut, int& paintVolumeSliceThicknessOut, bool& closedBorderFlagOut, bool& twoDimFlagOut, bool& autoProjectYesFlagOut) const; // get border update parameters void getBorderUpdateParameters(BrainModelBorderSet::UPDATE_BORDER_MODE& borderUpdateModeOut, float& samplingOut, bool& twoDimFlagOut, bool& autoProjectYesFlagOut) const; // set selected interpolated borders void setSelectedInterpolatedBorders(const int borderNumber, const int borderIndex); // show the draw borders page void showPageDrawBorders(); // show the update borders page void showPageUpdateBorders(); // show the create landmark borders page void showPageCreateLandmarkBorders(const bool checkCreateFlattenLandmarks, const bool checkCreateRegistrationLandmarks, const BrainModelSurface* fiducialSurface = NULL, const BrainModelSurface* inflatedSurface = NULL, const BrainModelSurface* veryInflatedSurface = NULL, const BrainModelSurface* sphericalSurface = NULL); public slots: /// called when close push button clicked bool close(); protected slots: // called to convert volume to fiducial borders void slotConvertVolumeToFiducialBorders(); // called to create lat/lon spherical borders void slotLatLonSphericalBorders(); // called to move border points with mouse void slotMoveBorderPointWithMouse(); // called to rename borders with mouse void slotRenameBordersWithMouse(); // called to reverse borders with mouse void slotReverseBordersWithMouse(); // called to orient borders clockwise void slotOrientBordersClockwise(); // called to reverse displayed borders void slotReverseDisplayedBorders(); // called to delete all borders void slotDeleteAllBorders(); // called to delete borders not displayed void slotDeleteBordersNotDisplayed(); // called to delete borders with mouse void slotDeleteBordersWithMouse(); // called to delete border points with mouse void slotDeleteBorderPointsWithMouse(); // called to delete border points outside surface void slotDeleteBorderPointsOutsideSurface(); // called to resample displayed borders void slotResampleDisplayedBorders(); protected: /// page for drawing borders BordersPageDrawNew* pageBordersDrawNew; /// page for updating borders BordersPageUpdateExisting* pageBordersDrawUpdate; /// page for creating landmark borders BordersPageCreateLandmarks* pageCreateLandmarkBorders; /// page for interpolated borders BordersPageCreateInterpolatedBorders* pageInterpolatedBorders; }; //============================================================================= /// page for draw new borders class BordersPageDrawNew : public WuQMultiPageDialogPage { Q_OBJECT public: // constructor BordersPageDrawNew(); // destructor virtual ~BordersPageDrawNew(); // apply the pages settings virtual void applyPage(); // create the page virtual QWidget* createPage(); // update the page virtual void updatePage(); // see if the page is valid virtual bool getPageValid() const; // get border drawing parameters void getBorderDrawingParameters(QString& borderNameOut, float& samplingOut, int& borderColorIndexOut, int& surfacePaintAssignmentColumnNumberOut, int& surfacePaintNameAssignmentIndexOut, VolumeFile* &paintVolumeForVoxelAssignmentOut, int& paintVolumeSliceThicknessOut, bool& closedBorderFlagOut, bool& twoDimFlagOut, bool& autoProjectYesFlagOut) const; protected slots: // called when name push button clicked void slotNamePushButton(); private slots: // called when type changed void slotTypeChanged(); protected: // create the closed border assignment widget QWidget* createClosedBorderNodeVoxelAssignmentWidget(); /// name line edit QLineEdit* nameLineEdit; /// sampling double spin box QDoubleSpinBox* samplingDoubleSpinBox; /// type closed radio button QRadioButton* typeClosedRadioButton; /// type open radio button QRadioButton* typeOpenRadioButton; /// dimension 2D radio button QRadioButton* dimension2DRadioButton; /// dimension 2D Auto Project radio button QRadioButton* dimension2DAutoProjectRadioButton; /// dimension 3D radio button QRadioButton* dimension3DRadioButton; /// index of border color int borderColorIndex; /// assign nodes within closed border check box QGroupBox* assignNodesInsideBorderGroupBox; /// node voxel assignment widget QWidget* nodeVoxelAssignmentWidget; /// paint column selection GuiNodeAttributeColumnSelectionComboBox* paintColumnComboBox; /// name of column line edit QLineEdit* paintColumnNameLineEdit; /// paint column number for assignment int paintAssignmentColumnNumber; /// index of paint that is assigned int paintNameAssignmentIndex; /// paint volume selection control GuiVolumeFileSelectionComboBox* paintVolumeSelectionControl; /// paint volume slice thickness control QComboBox* paintVolumeSliceThicknessComboBox; /// paint volume assignment group box QGroupBox* assignVoxelsInsideBorderGroupBox; /// paint volume for voxel assignment VolumeFile* paintVolumeForVoxelAssignment; }; //============================================================================= /// page for updating borders class BordersPageUpdateExisting : public WuQMultiPageDialogPage { Q_OBJECT public: // constructor BordersPageUpdateExisting(); // destructor virtual ~BordersPageUpdateExisting(); // apply the pages settings virtual void applyPage(); // create the page virtual QWidget* createPage(); // update the page virtual void updatePage(); // see if the page is valid virtual bool getPageValid() const; // get border update parameters void getBorderUpdateParameters(BrainModelBorderSet::UPDATE_BORDER_MODE& borderUpdateModeOut, float& samplingOut, bool& twoDimFlagOut, bool& autoProjectYesFlagOut) const; protected: /// mode extend radio button QRadioButton* extendBorderModeRadioButton; /// mode replace segment radio button QRadioButton* replaceSegmentInBorderModeRadioButton; /// mode erase radio button QRadioButton* eraseBorderModeRadioButton; /// sampling double spin box QDoubleSpinBox* samplingDoubleSpinBox; /// dimension 2D radio button QRadioButton* dimension2DRadioButton; /// dimension 2D Auto Project radio button QRadioButton* dimension2DAutoProjectRadioButton; /// dimension 3D radio button QRadioButton* dimension3DRadioButton; }; //============================================================================= /// page for updating borders class BordersPageProjection : public WuQMultiPageDialogPage { Q_OBJECT public: // constructor BordersPageProjection(); // destructor virtual ~BordersPageProjection(); // apply the pages settings virtual void applyPage(); // create the page virtual QWidget* createPage(); // update the page virtual void updatePage(); // see if the page is valid virtual bool getPageValid() const; protected: /// project to nearest node radio button QRadioButton* nearestNodeRadioButton; /// project to nearest tile radio button QRadioButton* nearestTileRadioButton; }; //============================================================================= /// page for editing border colors class BordersPageEditColors : public WuQMultiPageDialogPage { Q_OBJECT public: // constructor BordersPageEditColors(); // destructor virtual ~BordersPageEditColors(); // apply the pages settings virtual void applyPage(); // create the page virtual QWidget* createPage(); // update the page virtual void updatePage(); // see if the page is valid virtual bool getPageValid() const; protected slots: /// called if colors changed void slotColorsChanged(); protected: /// the color editor GuiColorFileEditorWidget* colorEditorWidget; }; //============================================================================= /// page for create borders from paint regions class BordersPageCreateFromPaintRegions : public WuQMultiPageDialogPage { Q_OBJECT public: // constructor BordersPageCreateFromPaintRegions(); // destructor virtual ~BordersPageCreateFromPaintRegions(); // apply the pages settings virtual void applyPage(); // create the page virtual QWidget* createPage(); // update the page virtual void updatePage(); // see if the page is valid virtual bool getPageValid() const; protected slots: /// called when paint column selection made void slotPaintColumnComboBox(int); protected: /// paint column selection GuiNodeAttributeColumnSelectionComboBox* paintColumnComboBox; /// name for borders QLineEdit* borderNameLineEdit; }; //============================================================================= /// page for create flat grid borders class BordersPageCreateFlatGridBorders : public WuQMultiPageDialogPage { Q_OBJECT public: // constructor BordersPageCreateFlatGridBorders(); // destructor virtual ~BordersPageCreateFlatGridBorders(); // apply the pages settings virtual void applyPage(); // create the page virtual QWidget* createPage(); // update the page virtual void updatePage(); // see if the page is valid virtual bool getPageValid() const; protected: /// grid spacing double spin box QDoubleSpinBox* gridSpacingDoubleSpinBox; /// points per grid square double spin box QSpinBox* pointsPerGridSquareSpinBox; /// limit the points to the surface QCheckBox* restrictPointsToSurfaceCheckBox; }; //============================================================================= /// page for create flat analysis grid borders class BordersPageCreateFlatAnalysisGridBorders : public WuQMultiPageDialogPage { Q_OBJECT public: // constructor BordersPageCreateFlatAnalysisGridBorders(); // destructor virtual ~BordersPageCreateFlatAnalysisGridBorders(); // apply the pages settings virtual void applyPage(); // create the page virtual QWidget* createPage(); // update the page virtual void updatePage(); // see if the page is valid virtual bool getPageValid() const; protected slots: // called when update grid extent push button pressed void slotUpdateGridExtentPushButton(); protected: /// x min double spin box QDoubleSpinBox* xMinDoubleSpinBox; /// x max double spin box QDoubleSpinBox* xMaxDoubleSpinBox; /// y min double spin box QDoubleSpinBox* yMinDoubleSpinBox; /// y max double spin box QDoubleSpinBox* yMaxDoubleSpinBox; /// spacing double spin box QDoubleSpinBox* spacingDoubleSpinBox; /// limit the points to the surface QCheckBox* restrictPointsToSurfaceCheckBox; }; //============================================================================= /// page for create interpolated borders class BordersPageCreateInterpolatedBorders : public WuQMultiPageDialogPage { Q_OBJECT public: // constructor BordersPageCreateInterpolatedBorders(); // destructor virtual ~BordersPageCreateInterpolatedBorders(); // apply the pages settings virtual void applyPage(); // create the page virtual QWidget* createPage(); // update the page virtual void updatePage(); // see if the page is valid virtual bool getPageValid() const; // set selected borders void setSelectedBorders(const int borderNumber, const int borderIndex); protected slots: /// called to enable mouse mode void slotEnableMousePushButton(); protected: /// index of first border int border1Index; /// index of second border int border2Index; /// border 1 name label QLabel* border1NameLabel; /// border 2 name label QLabel* border2NameLabel; /// name prefix line edit QLineEdit* namePrefixLineEdit; /// sampling double spin box QDoubleSpinBox* samplingDoubleSpinBox; /// number of interpolated borders spin box QSpinBox* numberOfInterplatedBordersSpinBox; }; //============================================================================= /// page for create edit attributes class BordersPageEditAttributes : public WuQMultiPageDialogPage { Q_OBJECT public: // constructor BordersPageEditAttributes(); // destructor virtual ~BordersPageEditAttributes(); // apply the pages settings virtual void applyPage(); // create the page virtual QWidget* createPage(); // update the page virtual void updatePage(); // see if the page is valid virtual bool getPageValid() const; protected: }; //============================================================================= /// page for create landmark borders class BordersPageCreateLandmarks : public WuQMultiPageDialogPage { Q_OBJECT public: // constructor BordersPageCreateLandmarks(); // destructor virtual ~BordersPageCreateLandmarks(); // apply the pages settings virtual void applyPage(); // create the page virtual QWidget* createPage(); // update the page virtual void updatePage(); // see if the page is valid virtual bool getPageValid() const; // set initialize settings void initializePage(const bool checkCreateFlattenLandmarks, const bool checkCreateRegistrationLandmarks, const BrainModelSurface* fiducialSurface = NULL, const BrainModelSurface* inflatedSurface = NULL, const BrainModelSurface* veryInflatedSurface = NULL, const BrainModelSurface* sphericalSurface = NULL); protected: /// stereotaxic space combo box GuiStereotaxicSpaceComboBox* stereotaxicSpaceComboBox; /// anatomical volume selection combo box GuiVolumeFileSelectionComboBox* anatomicalVolumeComboBox; /// fiducial surface selection combo box GuiBrainModelSurfaceSelectionComboBox* fiducialSurfaceComboBox; /// inflated surface selection combo box GuiBrainModelSurfaceSelectionComboBox* inflatedSurfaceComboBox; /// very inflated surface selection combo box GuiBrainModelSurfaceSelectionComboBox* veryInflatedSurfaceComboBox; /// ellipsoid surface selection combo box GuiBrainModelSurfaceSelectionComboBox* ellipsoidSurfaceComboBox; /// surface shape depth column combo box GuiNodeAttributeColumnSelectionComboBox* shapeDepthColumnComboBox; /// paint geography column combo box GuiNodeAttributeColumnSelectionComboBox* paintGeographyColumnComboBox; /// create flatten landmarks check box QCheckBox* createFlattenLandmarksCheckBox; /// create registration landmarks check box QCheckBox* createRegistrationLandmarksCheckBox; }; #endif // __GUI_BORDER_OPERATIONS_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiBorderOperationsDialog.cxx0000664000175000017500000023457011572067322023464 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "AreaColorFile.h" #include "BorderColorFile.h" #include "BorderProjectionFile.h" #include "BrainModelOpenGL.h" #include "GuiBrainModelSelectionComboBox.h" #include "GuiBrainModelSurfaceSelectionComboBox.h" #include "BrainModelSurface.h" #include "BrainModelSurfaceBorderLandmarkIdentification.h" #include "BrainModelSurfacePaintToBorderConverter.h" #include "BrainSet.h" #include "DisplaySettingsBorders.h" #include "GuiBorderOperationsDialog.h" #include "GuiColorFileEditorWidget.h" #include "GuiColorSelectionDialog.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "GuiMainWindowLayersActions.h" #include "GuiNameSelectionDialog.h" #include "GuiNodeAttributeColumnSelectionComboBox.h" #include "GuiStereotaxicSpaceComboBox.h" #include "GuiVolumeFileSelectionComboBox.h" #include "PaintFile.h" #include "SurfaceShapeFile.h" #include "VocabularyFile.h" #include "VolumeFile.h" #include "WuQMessageBox.h" #include "global_variables.h" //============================================================================ /** * constructor. */ GuiBorderOperationsDialog::GuiBorderOperationsDialog(QWidget* parent) : WuQMultiPageDialog(WuQMultiPageDialog::PAGE_CREATION_WHEN_DISPLAYED, 2, parent) { setWindowTitle("Border Operations"); // // Create and Modify operations // QToolButton* convertVolumeBordersToFiducialToolButton = createToolButton("VF", "Convert Volume Borders to Fiducial Borders", this, SLOT(slotConvertVolumeToFiducialBorders())); QToolButton* createLatLonToolButton = createToolButton("LL", "Create Lon/Lon Spherical Borders", this, SLOT(slotLatLonSphericalBorders())); QToolButton* movePointsToolButton = createToolButton("MV", "Move Border Points With Mouse.", this, SLOT(slotMoveBorderPointWithMouse())); QToolButton* renameWithMouseToolButton = createToolButton("RN", "Rename Borders With Mouse.", this, SLOT(slotRenameBordersWithMouse())); QToolButton* resampleDisplayedToolButton = createToolButton("RS", "Resample Displayed Borders.", this, SLOT(slotResampleDisplayedBorders())); QToolButton* orientClockwiseToolButton = createToolButton("CW", "Orient Borders Clockwise.", this, SLOT(slotOrientBordersClockwise())); QToolButton* reverseDisplayedToolButton = createToolButton("RD", "Reverse Displayed Borders.", this, SLOT(slotReverseDisplayedBorders())); QToolButton* reversePointsToolButton = createToolButton("RB", "Reverse Border Points With Mouse.", this, SLOT(slotReverseBordersWithMouse())); QGroupBox* modifyGroupBox = new QGroupBox("Modify"); QHBoxLayout* modifyGroupLayout = new QHBoxLayout(modifyGroupBox); modifyGroupLayout->addWidget(convertVolumeBordersToFiducialToolButton); modifyGroupLayout->addWidget(createLatLonToolButton); modifyGroupLayout->addWidget(movePointsToolButton); modifyGroupLayout->addWidget(renameWithMouseToolButton); modifyGroupLayout->addWidget(resampleDisplayedToolButton); modifyGroupLayout->addWidget(orientClockwiseToolButton); modifyGroupLayout->addWidget(reverseDisplayedToolButton); modifyGroupLayout->addWidget(reversePointsToolButton); // // Delete operations // QToolButton* deleteAllToolButton = createToolButton( "DA", "Delete All Borders.", this, SLOT(slotDeleteAllBorders())); QToolButton* deleteNotDisplayedToolButton = createToolButton( "DN", "Delete Borders Not Displayed on Main Window Surface.", this, SLOT(slotDeleteBordersNotDisplayed())); QToolButton* deleteWithMouseToolButton = createToolButton( "DB", "Delete Borders With Mouse.", this, SLOT(slotDeleteBordersWithMouse())); QToolButton* deletePointsWithMouseToolButton = createToolButton( "DP", "Delete Border Points With Mouse.", this, SLOT(slotDeleteBorderPointsWithMouse())); QToolButton* deleteOutsideSurfaceToolButton = createToolButton( "DO", "Delete Border Points Outside Flat Surface.", this, SLOT(slotDeleteBorderPointsOutsideSurface())); QGroupBox* deleteGroupBox = new QGroupBox("Delete"); QHBoxLayout* deleteGroupLayout = new QHBoxLayout(deleteGroupBox); deleteGroupLayout->addWidget(deleteAllToolButton); deleteGroupLayout->addWidget(deleteNotDisplayedToolButton); deleteGroupLayout->addWidget(deleteWithMouseToolButton); deleteGroupLayout->addWidget(deletePointsWithMouseToolButton); deleteGroupLayout->addWidget(deleteOutsideSurfaceToolButton); // // Setup Toolbar // addWidgetToToolBar(0, modifyGroupBox); addWidgetToToolBar(0, deleteGroupBox); addPage("Create Borders From Paint Regions", new BordersPageCreateFromPaintRegions); addPage("Create Flat Analysis Grid Borders", new BordersPageCreateFlatAnalysisGridBorders); addPage("Create Flat Grid Borders", new BordersPageCreateFlatGridBorders); pageInterpolatedBorders = new BordersPageCreateInterpolatedBorders; addPage("Create Interpolated Borders", pageInterpolatedBorders); pageCreateLandmarkBorders = new BordersPageCreateLandmarks; addPage("Create Flattening and Registration Landmark Borders", pageCreateLandmarkBorders); pageBordersDrawNew = new BordersPageDrawNew; addPage("Draw New Borders", pageBordersDrawNew); pageBordersDrawUpdate = new BordersPageUpdateExisting; addPage("Draw Update Existing Borders", pageBordersDrawUpdate); //addPage("Edit Attributes", // new BordersPageEditAttributes); addPage("Edit Colors", new BordersPageEditColors); addPage("Project Borders", new BordersPageProjection); setDefaultPage(pageBordersDrawNew); } /** * destructor. */ GuiBorderOperationsDialog::~GuiBorderOperationsDialog() { } /** * show the draw borders page. */ void GuiBorderOperationsDialog::showPageDrawBorders() { showPage(pageBordersDrawNew); } /** * show the update borders page. */ void GuiBorderOperationsDialog::showPageUpdateBorders() { showPage(pageBordersDrawUpdate); } /** * show the create landmark borders page. */ void GuiBorderOperationsDialog::showPageCreateLandmarkBorders( const bool checkCreateFlattenLandmarks, const bool checkCreateRegistrationLandmarks, const BrainModelSurface* fiducialSurface, const BrainModelSurface* inflatedSurface, const BrainModelSurface* veryInflatedSurface, const BrainModelSurface* sphericalSurface) { showPage(pageCreateLandmarkBorders); pageCreateLandmarkBorders->initializePage(checkCreateFlattenLandmarks, checkCreateRegistrationLandmarks, fiducialSurface, inflatedSurface, veryInflatedSurface, sphericalSurface); } /** * called when close push button clicked. */ bool GuiBorderOperationsDialog::close() { if ((theMainWindow->getBrainModelOpenGL()->getMouseMode() == GuiBrainModelOpenGL::MOUSE_MODE_BORDER_DRAW_NEW) || (theMainWindow->getBrainModelOpenGL()->getMouseMode() == GuiBrainModelOpenGL::MOUSE_MODE_BORDER_UPDATE_NEW)) { theMainWindow->getBrainModelOpenGL()->setMouseMode( GuiBrainModelOpenGL::MOUSE_MODE_VIEW); } return WuQMultiPageDialog::close(); } /** * called to convert volume to fiducial borders. */ void GuiBorderOperationsDialog::slotConvertVolumeToFiducialBorders() { theMainWindow->getLayersActions()->slotBordersVolumeToBordersFiducial(); } /** * called to create lat/lon spherical borders. */ void GuiBorderOperationsDialog::slotLatLonSphericalBorders() { theMainWindow->getLayersActions()->slotBordersCreateSpherical(); } /** * called to move border points with mouse */ void GuiBorderOperationsDialog::slotMoveBorderPointWithMouse() { theMainWindow->getLayersActions()->slotBordersMovePointWithMouse(); } /** * called to rename borders with mouse */ void GuiBorderOperationsDialog::slotRenameBordersWithMouse() { theMainWindow->getLayersActions()->slotBordersRenameWithMouse(); } /** * called to reverse borders with mouse */ void GuiBorderOperationsDialog::slotReverseBordersWithMouse() { theMainWindow->getLayersActions()->slotBordersReverseWithMouse(); } /** * called to orient borders clockwise */ void GuiBorderOperationsDialog::slotOrientBordersClockwise() { theMainWindow->getLayersActions()->slotBordersOrientDisplayedClockwise(); } /** * called to reverse displayed borders */ void GuiBorderOperationsDialog::slotReverseDisplayedBorders() { theMainWindow->getLayersActions()->slotBordersReverseDisplayed(); } /** * called to delete all borders */ void GuiBorderOperationsDialog::slotDeleteAllBorders() { theMainWindow->getLayersActions()->slotBordersDeleteAll(); } /** * called to delete borders not displayed. */ void GuiBorderOperationsDialog::slotDeleteBordersNotDisplayed() { BrainModel* bm = theMainWindow->getBrainModelSurface(); if (bm != NULL) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); bmbs->deleteBordersNotDisplayedOnBrainModel(bm); GuiFilesModified fm; fm.setBorderModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } } /** * called to resample borders. */ void GuiBorderOperationsDialog::slotResampleDisplayedBorders() { theMainWindow->getLayersActions()->slotBordersResampleDisplayed(); } /** * called to delete borders with mouse */ void GuiBorderOperationsDialog::slotDeleteBordersWithMouse() { theMainWindow->getLayersActions()->slotBordersDeleteWithMouse(); } /** * called to delete border points with mouse */ void GuiBorderOperationsDialog::slotDeleteBorderPointsWithMouse() { theMainWindow->getLayersActions()->slotBordersDeletePointWithMouse(); } /** * called to delete border points outside surface */ void GuiBorderOperationsDialog::slotDeleteBorderPointsOutsideSurface() { theMainWindow->getLayersActions()->slotBordersDeletePointsOutsideSurface(); } /** * get border drawing parameters. */ void GuiBorderOperationsDialog::getBorderDrawingParameters(QString& borderNameOut, float& samplingOut, int& borderColorIndexOut, int& surfacePaintAssignmentColumnNumberOut, int& surfacePaintNameAssignmentIndexOut, VolumeFile* &paintVolumeForVoxelAssignmentOut, int& paintVolumeSliceThicknessOut, bool& closedBorderFlagOut, bool& twoDimFlagOut, bool& autoProjectYesFlagOut) const { pageBordersDrawNew->getBorderDrawingParameters(borderNameOut, samplingOut, borderColorIndexOut, surfacePaintAssignmentColumnNumberOut, surfacePaintNameAssignmentIndexOut, paintVolumeForVoxelAssignmentOut, paintVolumeSliceThicknessOut, closedBorderFlagOut, twoDimFlagOut, autoProjectYesFlagOut); } /** * get border update parameters. */ void GuiBorderOperationsDialog::getBorderUpdateParameters( BrainModelBorderSet::UPDATE_BORDER_MODE& borderUpdateModeOut, float& samplingOut, bool& twoDimFlagOut, bool& autoProjectYesFlagOut) const { pageBordersDrawUpdate->getBorderUpdateParameters( borderUpdateModeOut, samplingOut, twoDimFlagOut, autoProjectYesFlagOut); } /** * set selected interpolated borders. */ void GuiBorderOperationsDialog::setSelectedInterpolatedBorders(const int borderNumber, const int borderIndex) { pageInterpolatedBorders->setSelectedBorders(borderNumber, borderIndex); } //============================================================================ //============================================================================ //============================================================================ /** * constructor. */ BordersPageDrawNew::BordersPageDrawNew() { } /** * destructor. */ BordersPageDrawNew::~BordersPageDrawNew() { } /** * apply the pages settings. */ void BordersPageDrawNew::applyPage() { theMainWindow->getBrainModelOpenGL()->resetLinearObjectBeingDrawn(); const QString borderName = nameLineEdit->text().trimmed(); if (borderName.isEmpty()) { WuQMessageBox::critical(this, "ERROR", "Border name is missing."); return; } BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); BrainModelVolume* bmv = theMainWindow->getBrainModelVolume(); if (bms != NULL) { // // Make sure a flat or compressed medial wall surface is not rotated // if (dimension2DRadioButton->isChecked()) { bool haveFlatSurface = false; switch (bms->getSurfaceType()) { case BrainModelSurface::SURFACE_TYPE_RAW: case BrainModelSurface::SURFACE_TYPE_FIDUCIAL: case BrainModelSurface::SURFACE_TYPE_INFLATED: case BrainModelSurface::SURFACE_TYPE_VERY_INFLATED: case BrainModelSurface::SURFACE_TYPE_SPHERICAL: case BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL: break; case BrainModelSurface::SURFACE_TYPE_COMPRESSED_MEDIAL_WALL: case BrainModelSurface::SURFACE_TYPE_FLAT: case BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR: haveFlatSurface = true; break; case BrainModelSurface::SURFACE_TYPE_HULL: case BrainModelSurface::SURFACE_TYPE_UNKNOWN: case BrainModelSurface::SURFACE_TYPE_UNSPECIFIED: break; } if (haveFlatSurface) { float matrix[16]; bms->getRotationMatrix(0, matrix); if ((matrix[0] != 1.0) || (matrix[5] != 1.0) || (matrix[10] != 1.0)) { if (QMessageBox::warning(this, "WARNING", "The flat surface appears to be rotated which will\n" "prevent the border from being drawn correctly.\n" "Would you like to remove the rotation?", (QMessageBox::Yes | QMessageBox::No), QMessageBox::Yes) == QMessageBox::Yes) { // // Setting the view to dorsal resets the rotation matrix without // affecting the translate and scaling. // bms->setToStandardView(0, BrainModelSurface::VIEW_DORSAL); GuiBrainModelOpenGL::updateAllGL(theMainWindow->getBrainModelOpenGL()); } } } } } // // Find the matching color // bool borderColorMatch = false; BorderColorFile* borderColorFile = theMainWindow->getBrainSet()->getBorderColorFile(); borderColorIndex = borderColorFile->getColorIndexByName(borderName, borderColorMatch); // // Border color may need to be created // bool createBorderColor = false; if ((borderColorIndex >= 0) && (borderColorMatch == true)) { createBorderColor = false; } else if ((borderColorIndex >= 0) && (borderColorMatch == false)) { QString msg("Use border color \""); msg.append(borderColorFile->getColorNameByIndex(borderColorIndex)); msg.append("\" for border "); msg.append(borderName); msg.append(" ?"); QString noButton("No, define color "); noButton.append(borderName); QMessageBox msgBox(this); msgBox.setWindowTitle("Use Partially Matching Color"); msgBox.setText(msg); QPushButton* yesPushButton = msgBox.addButton("Yes", QMessageBox::ActionRole); QPushButton* noPushButton = msgBox.addButton(noButton, QMessageBox::ActionRole); msgBox.exec(); if (msgBox.clickedButton() == yesPushButton) { createBorderColor = false; } else if (msgBox.clickedButton() == noPushButton) { createBorderColor = true; } } else { createBorderColor = true; } if (createBorderColor) { QString title("Create Border Color: "); title.append(borderName); GuiColorSelectionDialog* csd = new GuiColorSelectionDialog(this, title, false, false, false, false); csd->exec(); // // Add new border color // float pointSize = 2.0, lineSize = 1.0; unsigned char r, g, b, a; ColorFile::ColorStorage::SYMBOL symbol; csd->getColorInformation(r, g, b, a, pointSize, lineSize, symbol); borderColorFile->addColor(borderName, r, g, b, a, pointSize, lineSize, symbol); borderColorIndex = borderColorFile->getNumberOfColors() - 1; } bool doAreaColorFlag = false; // // Initialize do not assign paint // paintAssignmentColumnNumber = -1; paintNameAssignmentIndex = -1; // // Is there a surface in the main window and assigning nodes // if ((bms != NULL) && typeClosedRadioButton->isChecked() && assignNodesInsideBorderGroupBox->isChecked()) { doAreaColorFlag = true; // // Get column number for assignment // PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); paintAssignmentColumnNumber = paintColumnComboBox->currentIndex(); // // Does column need to be created? // if ((paintAssignmentColumnNumber < 0) || (paintAssignmentColumnNumber >= pf->getNumberOfColumns()) || (paintColumnComboBox->getNewSelected())) { pf->addColumns(1); paintAssignmentColumnNumber = pf->getNumberOfColumns() - 1; paintColumnComboBox->setCurrentIndex(paintAssignmentColumnNumber); } // // Set name of column // const QString columnName = paintColumnNameLineEdit->text(); pf->setColumnName(paintAssignmentColumnNumber, columnName); // // paint index for node assignment // paintNameAssignmentIndex = pf->addPaintName(borderName); } // // If there is a volume in the main window and assigning voxels // paintVolumeForVoxelAssignment = NULL; if ((bmv != NULL) && typeClosedRadioButton->isChecked() && assignVoxelsInsideBorderGroupBox->isChecked()) { paintVolumeForVoxelAssignment = paintVolumeSelectionControl->getSelectedVolumeFile(); if (paintVolumeForVoxelAssignment != NULL) { doAreaColorFlag = true; } } if (doAreaColorFlag) { // // Find the matching color // bool areaColorMatch = false; AreaColorFile* areaColorFile = theMainWindow->getBrainSet()->getAreaColorFile(); const int areaColorIndex = areaColorFile->getColorIndexByName(borderName, areaColorMatch); // // Area color may need to be created // if (areaColorMatch == false) { QString msg("Matching area color \""); msg.append(borderName); msg.append("\" not found"); QString borderButton("Use Border Color"); QString defineButton("Define Area Color "); int result = -1; if (areaColorIndex >= 0) { QString partialMatchButton("Use "); partialMatchButton.append(areaColorFile->getColorNameByIndex(areaColorIndex)); QMessageBox msgBox(this); msgBox.setWindowTitle("Set Area Color"); msgBox.setText(msg); QPushButton* useColorPushButton = msgBox.addButton(borderButton, QMessageBox::ActionRole); QPushButton* defineColorPushButton = msgBox.addButton(defineButton, QMessageBox::ActionRole); QPushButton* usePartialColorPushButton = msgBox.addButton(partialMatchButton, QMessageBox::ActionRole); msgBox.exec(); if (msgBox.clickedButton() == useColorPushButton) { result = 0; } else if (msgBox.clickedButton() == defineColorPushButton) { result = 1; } else if (msgBox.clickedButton() == usePartialColorPushButton) { result = 2; } } else { QMessageBox msgBox(this); msgBox.setWindowTitle("Set Area Color"); msgBox.setText(msg); QPushButton* useColorPushButton = msgBox.addButton(borderButton, QMessageBox::ActionRole); QPushButton* defineColorPushButton = msgBox.addButton(defineButton, QMessageBox::ActionRole); msgBox.exec(); if (msgBox.clickedButton() == useColorPushButton) { result = 0; } else if (msgBox.clickedButton() == defineColorPushButton) { result = 1; } } if (result == 0) { // // Copy border color to area color // unsigned char r, g, b, a; borderColorFile->getColorByIndex(borderColorIndex, r, g, b, a); float pointSize, lineSize; borderColorFile->getPointLineSizeByIndex(borderColorIndex, pointSize, lineSize); areaColorFile->addColor(borderName, r, g, b, a, pointSize, lineSize); } else if (result == 1) { // // define the area color // QString title("Create Area Color: "); title.append(borderName); GuiColorSelectionDialog* csd = new GuiColorSelectionDialog(this, title, false, false, false, false); csd->exec(); // // Add new area color // float pointSize = 2.0, lineSize = 1.0; unsigned char r, g, b, a; ColorFile::ColorStorage::SYMBOL symbol; csd->getColorInformation(r, g, b, a, pointSize, lineSize, symbol); areaColorFile->addColor(borderName, r, g, b, a, pointSize, lineSize, symbol); } else if (result == 2) { // // do nothing so that partially matching color is used // } } } theMainWindow->getBrainModelOpenGL()->setMouseMode( GuiBrainModelOpenGL::MOUSE_MODE_BORDER_DRAW_NEW); } /** * create the page. */ QWidget* BordersPageDrawNew::createPage() { // // Name // QPushButton* namePushButton = new QPushButton("Name..."); QObject::connect(namePushButton, SIGNAL(clicked()), this, SLOT(slotNamePushButton())); nameLineEdit = new QLineEdit; // // Sampling // QLabel* samplingLabel = new QLabel("Sampling (mm)"); samplingDoubleSpinBox = new QDoubleSpinBox; samplingDoubleSpinBox->setMinimum(0.01); samplingDoubleSpinBox->setMaximum(9999999.0); samplingDoubleSpinBox->setDecimals(2); samplingDoubleSpinBox->setSingleStep(0.5); samplingDoubleSpinBox->setValue(2.0); // // Type // typeClosedRadioButton = new QRadioButton("Closed (Boundary)"); typeOpenRadioButton = new QRadioButton("Open"); QButtonGroup* typeButtGroup = new QButtonGroup(this); typeButtGroup->addButton(typeClosedRadioButton); typeButtGroup->addButton(typeOpenRadioButton); QObject::connect(typeButtGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotTypeChanged())); QGroupBox* typeGroupBox = new QGroupBox("Type"); QVBoxLayout* typeLayout = new QVBoxLayout(typeGroupBox); typeLayout->addWidget(typeClosedRadioButton); typeLayout->addWidget(typeOpenRadioButton); typeOpenRadioButton->setChecked(true); // // Dimension // dimension2DRadioButton = new QRadioButton("2D (Flat)"); dimension2DRadioButton->setToolTip("Draw border on a flat surface."); dimension2DAutoProjectRadioButton = new QRadioButton("2D (Flat, Auto Project)"); dimension2DAutoProjectRadioButton->setToolTip("Draw border on a flat surface and\n" "project border to all other surfaces."); dimension3DRadioButton = new QRadioButton("3D"); dimension3DRadioButton->setToolTip("Draw border on any surface and\n" "project to all other surfaces."); QButtonGroup* dimButtGroup = new QButtonGroup(this); dimButtGroup->addButton(dimension2DRadioButton); dimButtGroup->addButton(dimension2DAutoProjectRadioButton); dimButtGroup->addButton(dimension3DRadioButton); QGroupBox* dimGroupBox = new QGroupBox("Dimensions"); QVBoxLayout* dimLayout = new QVBoxLayout(dimGroupBox); dimLayout->addWidget(dimension2DRadioButton); dimLayout->addWidget(dimension2DAutoProjectRadioButton); dimLayout->addWidget(dimension3DRadioButton); dimension3DRadioButton->setChecked(true); // // Layout for name and sampling // QGridLayout* nameSamplingGridLayout = new QGridLayout; nameSamplingGridLayout->addWidget(namePushButton, 0, 0); nameSamplingGridLayout->addWidget(nameLineEdit, 0, 1, 1, 2); nameSamplingGridLayout->addWidget(samplingLabel, 1, 0); nameSamplingGridLayout->addWidget(samplingDoubleSpinBox, 1, 1); // // Layout for type/dim/project // QHBoxLayout* typeDimProjectLayout = new QHBoxLayout; typeDimProjectLayout->addWidget(typeGroupBox); typeDimProjectLayout->addWidget(dimGroupBox); typeDimProjectLayout->addStretch(); // // Node/Voxel Assignment // nodeVoxelAssignmentWidget = createClosedBorderNodeVoxelAssignmentWidget(); QWidget* w = new QWidget; QVBoxLayout* layout = new QVBoxLayout(w); layout->addLayout(nameSamplingGridLayout); layout->addLayout(typeDimProjectLayout); layout->addWidget(nodeVoxelAssignmentWidget); slotTypeChanged(); return w; } /** * called when type changed. */ void BordersPageDrawNew::slotTypeChanged() { nodeVoxelAssignmentWidget->setEnabled(typeClosedRadioButton->isChecked()); } /** * create the closed border assignment widget. */ QWidget* BordersPageDrawNew::createClosedBorderNodeVoxelAssignmentWidget() { // // Paint Column Selection // QLabel* paintColumnLabel = new QLabel("Paint Column"); paintColumnComboBox = new GuiNodeAttributeColumnSelectionComboBox( theMainWindow->getBrainSet()->getPaintFile(), true, false, false); // // Name of paint column // QLabel* paintColumnNameLabel = new QLabel("Column Name"); paintColumnNameLineEdit = new QLineEdit; // // Connect paint column selection to column name line edit // QObject::connect(paintColumnComboBox, SIGNAL(itemNameSelected(const QString&)), paintColumnNameLineEdit, SLOT(setText(const QString&))); // // Widget for node assignment // QWidget* nodeAssignmentWidget = new QWidget; QGridLayout* gridLayout = new QGridLayout(nodeAssignmentWidget); gridLayout->addWidget(paintColumnLabel, 1, 0); gridLayout->addWidget(paintColumnComboBox, 1, 1); gridLayout->addWidget(paintColumnNameLabel, 2, 0); gridLayout->addWidget(paintColumnNameLineEdit, 2, 1); // // Assign nodes group box // assignNodesInsideBorderGroupBox = new QGroupBox("Assign Paint Identifier to Nodes Inside Border"); assignNodesInsideBorderGroupBox->setCheckable(true); assignNodesInsideBorderGroupBox->setChecked(false); QVBoxLayout* assignNodesLayout = new QVBoxLayout(assignNodesInsideBorderGroupBox); assignNodesLayout->addWidget(nodeAssignmentWidget); QObject::connect(assignNodesInsideBorderGroupBox, SIGNAL(toggled(bool)), nodeAssignmentWidget, SLOT(setEnabled(bool))); //----------------------------------------------------------------- // // assign voxels paint volume // QLabel* paintVolumeLabel = new QLabel("Paint Volume"); paintVolumeSelectionControl = new GuiVolumeFileSelectionComboBox( VolumeFile::VOLUME_TYPE_PAINT); // // Thickness selection // QLabel* ThicknessLabel = new QLabel("Thickness"); paintVolumeSliceThicknessComboBox = new QComboBox; paintVolumeSliceThicknessComboBox->addItem("Current Slice"); paintVolumeSliceThicknessComboBox->addItem("+/- 1 Slice"); paintVolumeSliceThicknessComboBox->addItem("+/- 2 Slices"); paintVolumeSliceThicknessComboBox->addItem("+/- 3 Slices"); paintVolumeSliceThicknessComboBox->addItem("+/- 4 Slices"); paintVolumeSliceThicknessComboBox->addItem("+/- 5 Slices"); // // Assign voxels group box // assignVoxelsInsideBorderGroupBox = new QGroupBox("Assign Paint Identifier to Voxels Inside Border"); assignVoxelsInsideBorderGroupBox->setCheckable(true); assignVoxelsInsideBorderGroupBox->setChecked(false); QGridLayout* assignVoxelsLayout = new QGridLayout(assignVoxelsInsideBorderGroupBox); assignVoxelsLayout->addWidget(paintVolumeLabel, 0, 0); assignVoxelsLayout->addWidget(paintVolumeSelectionControl, 0, 1); assignVoxelsLayout->addWidget(ThicknessLabel, 1, 0); assignVoxelsLayout->addWidget(paintVolumeSliceThicknessComboBox, 1, 1); // // Tab widget for node and voxel assignment // QTabWidget* assignNodeVoxelTabWidget = new QTabWidget; assignNodeVoxelTabWidget->addTab(assignNodesInsideBorderGroupBox, "Assign Nodes"); assignNodeVoxelTabWidget->addTab(assignVoxelsInsideBorderGroupBox, "Assign Voxels"); return assignNodeVoxelTabWidget; } /** * called when name push button clicked. */ void BordersPageDrawNew::slotNamePushButton() { static GuiNameSelectionDialog::LIST_ITEMS_TYPE itemForDisplay = GuiNameSelectionDialog::LIST_BORDER_COLORS_ALPHA; GuiNameSelectionDialog nsd(this, GuiNameSelectionDialog::LIST_ALL, itemForDisplay); if (nsd.exec() == QDialog::Accepted) { itemForDisplay = nsd.getSelectedItemType(); QString name(nsd.getNameSelected()); if (name.isEmpty() == false) { nameLineEdit->setText(name); if (name.toUpper() == "MEDIAL.WALL") { typeClosedRadioButton->setChecked(true); } else if ((name.toLower().endsWith("cut")) || (name.indexOf("LANDMARK") >= 0)) { typeOpenRadioButton->setChecked(true); } } } } /** * update the page. */ void BordersPageDrawNew::updatePage() { paintColumnComboBox->updateComboBox(); paintColumnNameLineEdit->setText(paintColumnComboBox->getCurrentLabel()); } /** * see if the page is valid. */ bool BordersPageDrawNew::getPageValid() const { return true; } /** * get border drawing parameters. */ void BordersPageDrawNew::getBorderDrawingParameters(QString& borderNameOut, float& samplingOut, int& borderColorIndexOut, int& surfacePaintAssignmentColumnNumberOut, int& surfacePaintNameAssignmentIndexOut, VolumeFile* &paintVolumeForVoxelAssignmentOut, int& paintVolumeSliceThicknessOut, bool& closedBorderFlagOut, bool& twoDimFlagOut, bool& autoProjectYesFlagOut) const { borderNameOut = nameLineEdit->text(); borderColorIndexOut = borderColorIndex; samplingOut = samplingDoubleSpinBox->value(); closedBorderFlagOut = typeClosedRadioButton->isChecked(); twoDimFlagOut = (dimension2DRadioButton->isChecked() || dimension2DAutoProjectRadioButton->isChecked()); autoProjectYesFlagOut = (dimension2DAutoProjectRadioButton->isChecked() || dimension3DRadioButton->isChecked()); surfacePaintAssignmentColumnNumberOut = paintAssignmentColumnNumber; surfacePaintNameAssignmentIndexOut = paintNameAssignmentIndex; paintVolumeForVoxelAssignmentOut = paintVolumeForVoxelAssignment; paintVolumeSliceThicknessOut = paintVolumeSliceThicknessComboBox->currentIndex(); } //============================================================================ //============================================================================ //============================================================================ /** * constructor. */ BordersPageUpdateExisting::BordersPageUpdateExisting() { } /** * destructor. */ BordersPageUpdateExisting::~BordersPageUpdateExisting() { } /** * apply the pages settings. */ void BordersPageUpdateExisting::applyPage() { theMainWindow->getBrainModelOpenGL()->setMouseMode( GuiBrainModelOpenGL::MOUSE_MODE_BORDER_UPDATE_NEW); } /** * create the page. */ QWidget* BordersPageUpdateExisting::createPage() { //------------------------------------------------------------------------- // // Mode radio buttons // extendBorderModeRadioButton = new QRadioButton("Extend From Either End"); extendBorderModeRadioButton->setToolTip("Extend a border by starting near\n" "one end of the border and continuing\n" "to the border's new end."); replaceSegmentInBorderModeRadioButton = new QRadioButton("Replace Segment"); replaceSegmentInBorderModeRadioButton->setToolTip("Correct a border by starting over\n" "a point in the border, drawing the\n" "correct new segment, and concluding\n" "over a point in the border."); eraseBorderModeRadioButton = new QRadioButton("Erase Segment From End"); eraseBorderModeRadioButton->setToolTip("Remove the end from a border by\n" "starting at an end of the border\n" "and continue along the border to\n" "what should be the new end point."); // // Button Group to keep mode radio buttons mutually exclusive // QButtonGroup* modeButtGroup = new QButtonGroup(this); modeButtGroup->addButton(eraseBorderModeRadioButton); modeButtGroup->addButton(extendBorderModeRadioButton); modeButtGroup->addButton(replaceSegmentInBorderModeRadioButton); replaceSegmentInBorderModeRadioButton->setChecked(true); // // Group box and layout for mode // QGroupBox* modeGroupBox = new QGroupBox("Mode"); QVBoxLayout* modeLayout = new QVBoxLayout(modeGroupBox); modeLayout->addWidget(eraseBorderModeRadioButton); modeLayout->addWidget(extendBorderModeRadioButton); modeLayout->addWidget(replaceSegmentInBorderModeRadioButton); // // Sampling // QLabel* samplingLabel = new QLabel("Sampling (mm)"); samplingDoubleSpinBox = new QDoubleSpinBox; samplingDoubleSpinBox->setMinimum(0.01); samplingDoubleSpinBox->setMaximum(9999999.0); samplingDoubleSpinBox->setDecimals(2); samplingDoubleSpinBox->setSingleStep(0.5); samplingDoubleSpinBox->setValue(2.0); QGroupBox* samplingGroupBox = new QGroupBox("Misc"); QHBoxLayout* samplingLayout = new QHBoxLayout(samplingGroupBox); samplingLayout->addWidget(samplingLabel); samplingLayout->addWidget(samplingDoubleSpinBox); // // Dimension // dimension2DRadioButton = new QRadioButton("2D (Flat)"); dimension2DRadioButton->setToolTip("Update a flat surface border"); dimension2DAutoProjectRadioButton = new QRadioButton("2D (Flat, Auto Project)"); dimension2DAutoProjectRadioButton->setToolTip("Update flat surface border and\n" "project to all other surfaces."); dimension3DRadioButton = new QRadioButton("3D"); dimension3DRadioButton->setToolTip("Update 3D border and project\n" "to all other surfaces."); QButtonGroup* dimButtGroup = new QButtonGroup(this); dimButtGroup->addButton(dimension2DRadioButton); dimButtGroup->addButton(dimension2DAutoProjectRadioButton); dimButtGroup->addButton(dimension3DRadioButton); QGroupBox* dimGroupBox = new QGroupBox("Dimensions"); QVBoxLayout* dimLayout = new QVBoxLayout(dimGroupBox); dimLayout->addWidget(dimension2DRadioButton); dimLayout->addWidget(dimension2DAutoProjectRadioButton); dimLayout->addWidget(dimension3DRadioButton); dimension3DRadioButton->setChecked(true); // // Layout for dimensions, auto project, and sampling // QHBoxLayout* row2Layout = new QHBoxLayout; row2Layout->addWidget(samplingGroupBox); row2Layout->addWidget(dimGroupBox); QWidget* w = new QWidget; QVBoxLayout* layout = new QVBoxLayout(w); layout->addWidget(modeGroupBox); layout->addLayout(row2Layout); return w; } /** * get border update parameters. */ void BordersPageUpdateExisting::getBorderUpdateParameters( BrainModelBorderSet::UPDATE_BORDER_MODE& borderUpdateModeOut, float& samplingOut, bool& twoDimFlagOut, bool& autoProjectYesFlagOut) const { borderUpdateModeOut = BrainModelBorderSet::UPDATE_BORDER_MODE_NONE; if (replaceSegmentInBorderModeRadioButton->isChecked()) { borderUpdateModeOut = BrainModelBorderSet::UPDATE_BORDER_MODE_REPLACE_SEGMENT_IN_MIDDLE_OF_BORDER; } else if (eraseBorderModeRadioButton->isChecked()) { borderUpdateModeOut = BrainModelBorderSet::UPDATE_BORDER_MODE_ERASE; } else if (extendBorderModeRadioButton->isChecked()) { borderUpdateModeOut = BrainModelBorderSet::UPDATE_BORDER_MODE_EXTEND_BORDER_FROM_END; } samplingOut = samplingDoubleSpinBox->value(); twoDimFlagOut = dimension2DRadioButton->isChecked(); autoProjectYesFlagOut = (dimension2DAutoProjectRadioButton->isChecked() || dimension3DRadioButton->isChecked()); } /** * update the page. */ void BordersPageUpdateExisting::updatePage() { } /** * see if the page is valid. */ bool BordersPageUpdateExisting::getPageValid() const { return true; //(theMainWindow->getBrainSet()->getBorderSet()->getNumberOfBorders() > 0); } //============================================================================ //============================================================================ //============================================================================ /** * constructor. */ BordersPageProjection::BordersPageProjection() { } /** * destructor. */ BordersPageProjection::~BordersPageProjection() { } /** * apply the pages settings. */ void BordersPageProjection::applyPage() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); GuiBrainModelOpenGL* openGL = theMainWindow->getBrainModelOpenGL(); BrainModelSurface* bms = openGL->getDisplayedBrainModelSurface(); if (bms != NULL) { // // Project borders used by this surface // BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); bmbs->projectBorders(bms, nearestTileRadioButton->isChecked()); // // Notify that borders have been changed. // GuiFilesModified fm; fm.setBorderModified(); theMainWindow->fileModificationUpdate(fm); // // Update all displayed surfaces // GuiBrainModelOpenGL::updateAllGL(NULL); } QApplication::restoreOverrideCursor(); } /** * create the page. */ QWidget* BordersPageProjection::createPage() { nearestNodeRadioButton = new QRadioButton("Nearest Node"); nearestTileRadioButton = new QRadioButton("Nearest Tile"); QButtonGroup* buttGroup = new QButtonGroup(this); buttGroup->addButton(nearestNodeRadioButton); buttGroup->addButton(nearestTileRadioButton); nearestTileRadioButton->setChecked(true); QGroupBox* projGroupBox = new QGroupBox("Projection Method"); QVBoxLayout* projGroupLayout = new QVBoxLayout(projGroupBox); projGroupLayout->addWidget(nearestNodeRadioButton); projGroupLayout->addWidget(nearestTileRadioButton); projGroupLayout->addStretch(); return projGroupBox; } /** * update the page. */ void BordersPageProjection::updatePage() { } /** * see if the page is valid. */ bool BordersPageProjection::getPageValid() const { return true; //(theMainWindow->getBrainSet()->getBorderSet()->getNumberOfBorders() > 0); } //============================================================================ //============================================================================ //============================================================================ /** * constructor. */ BordersPageEditColors::BordersPageEditColors() { colorEditorWidget = NULL; } /** * destructor. */ BordersPageEditColors::~BordersPageEditColors() { } /** * apply the pages settings. */ void BordersPageEditColors::applyPage() { colorEditorWidget->applySlot(); } /** * create the page. */ QWidget* BordersPageEditColors::createPage() { colorEditorWidget = new GuiColorFileEditorWidget(NULL, theMainWindow->getBrainSet()->getBorderColorFile(), true, true, false, false); QObject::connect(colorEditorWidget, SIGNAL(redrawRequested()), this, SLOT(slotColorsChanged())); QWidget* w = new QWidget; QVBoxLayout* layout = new QVBoxLayout(w); layout->addWidget(colorEditorWidget); layout->addStretch(); return colorEditorWidget; } /** * called if colors changed. */ void BordersPageEditColors::slotColorsChanged() { GuiFilesModified fm; fm.setBorderColorModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } /** * update the page. */ void BordersPageEditColors::updatePage() { if (colorEditorWidget != NULL) { colorEditorWidget->updateColorEditor(); } } /** * see if the page is valid. */ bool BordersPageEditColors::getPageValid() const { return true; } //============================================================================ //============================================================================ //============================================================================ /** * constructor. */ BordersPageCreateFromPaintRegions::BordersPageCreateFromPaintRegions() { paintColumnComboBox = NULL; } /** * destructor. */ BordersPageCreateFromPaintRegions::~BordersPageCreateFromPaintRegions() { } /** * apply the pages settings. */ void BordersPageCreateFromPaintRegions::applyPage() { BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { BrainSet* bs = theMainWindow->getBrainSet(); const int columnNumber = paintColumnComboBox->currentIndex(); PaintFile* pf = bs->getPaintFile(); if ((columnNumber >= 0) && (columnNumber < pf->getNumberOfColumns())) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); BrainModelSurfacePaintToBorderConverter ptb(bs, bms, pf, columnNumber); try { ptb.execute(); } catch (BrainModelAlgorithmException& e) { QApplication::restoreOverrideCursor(); WuQMessageBox::critical(theMainWindow, "ERROR", e.whatQString()); } DisplaySettingsBorders* dsb = bs->getDisplaySettingsBorders(); dsb->setDisplayBorders(true); GuiFilesModified fm; fm.setBorderModified(); fm.setBorderColorModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } } } /** * create the page. */ QWidget* BordersPageCreateFromPaintRegions::createPage() { QLabel* paintColumnLabel = new QLabel("Paint Column"); paintColumnComboBox = new GuiNodeAttributeColumnSelectionComboBox( theMainWindow->getBrainSet()->getPaintFile(), false, false, false); QObject::connect(paintColumnComboBox, SIGNAL(itemSelected(int)), this, SLOT(slotPaintColumnComboBox(int))); QLabel* borderNameLabel = new QLabel("Border Name"); borderNameLineEdit = new QLineEdit; // // Layout // QWidget* w = new QWidget; QGridLayout* gridLayout = new QGridLayout(w); gridLayout->addWidget(paintColumnLabel, 0, 0); gridLayout->addWidget(paintColumnComboBox, 0, 1); gridLayout->addWidget(borderNameLabel, 1, 0); gridLayout->addWidget(borderNameLineEdit, 1, 1); return w; } /** * called when paint column selection made. */ void BordersPageCreateFromPaintRegions::slotPaintColumnComboBox(int item) { const PaintFile* pf = theMainWindow->getBrainSet()->getPaintFile(); if ((item >= 0) && (item < pf->getNumberOfColumns())) { borderNameLineEdit->setText(pf->getColumnName(item)); } } /** * update the page. */ void BordersPageCreateFromPaintRegions::updatePage() { if (paintColumnComboBox != NULL) { paintColumnComboBox->updateComboBox(); if (borderNameLineEdit->text().isEmpty()) { borderNameLineEdit->setText(paintColumnComboBox->currentText()); } } } /** * see if the page is valid. */ bool BordersPageCreateFromPaintRegions::getPageValid() const { /* const bool valid = (theMainWindow->getBrainSet()->getPaintFile()->getNumberOfColumns() > 0); return valid; */ return true; } //============================================================================ //============================================================================ //============================================================================ /** * constructor. */ BordersPageCreateFlatGridBorders::BordersPageCreateFlatGridBorders() { } /** * destructor. */ BordersPageCreateFlatGridBorders::~BordersPageCreateFlatGridBorders() { } /** * apply the pages settings. */ void BordersPageCreateFlatGridBorders::applyPage() { BrainModelSurface* bms = theMainWindow->getBrainModelOpenGL()->getDisplayedBrainModelSurface(); if (bms != NULL) { // // See if a flat surface is in the main window // if (bms->getIsFlatSurface() == false) { WuQMessageBox::critical(theMainWindow, "Surface Type", "The surface in the main window must be flat for this operation !!!"); return; } BorderFile borderFile; QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); bms->createFlatGridBorders(borderFile, gridSpacingDoubleSpinBox->value(), pointsPerGridSquareSpinBox->value()); theMainWindow->getBrainSet()->deleteAllBorders(); BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); bmbs->copyBordersFromBorderFile(bms, &borderFile); if (restrictPointsToSurfaceCheckBox->isChecked()) { theMainWindow->getLayersActions()->slotBordersDeletePointsOutsideSurface(); } BorderColorFile* colorFile = theMainWindow->getBrainSet()->getBorderColorFile(); colorFile->addColorIfItDoesNotExist("GridX", 255, 0, 0); colorFile->addColorIfItDoesNotExist("GridY", 0, 255, 0); theMainWindow->getBrainSet()->assignBorderColors(); DisplaySettingsBorders* dsb = theMainWindow->getBrainSet()->getDisplaySettingsBorders(); dsb->setDisplayBorders(true); GuiFilesModified fm; fm.setBorderModified(); fm.setBorderColorModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } } /** * create the page. */ QWidget* BordersPageCreateFlatGridBorders::createPage() { // // Grid spacing // QLabel* gridSpacingLabel = new QLabel("Grid Spacing (mm)"); gridSpacingDoubleSpinBox = new QDoubleSpinBox; gridSpacingDoubleSpinBox->setMinimum(0.01); gridSpacingDoubleSpinBox->setMaximum(500000.0); gridSpacingDoubleSpinBox->setSingleStep(1); gridSpacingDoubleSpinBox->setDecimals(2); gridSpacingDoubleSpinBox->setValue(50.0); // // Points per grid square // QLabel* pointsPerGridSquareLabel = new QLabel("Point Per Grid Square"); pointsPerGridSquareSpinBox = new QSpinBox; pointsPerGridSquareSpinBox->setMinimum(0); pointsPerGridSquareSpinBox->setMaximum(50000); pointsPerGridSquareSpinBox->setSingleStep(1); pointsPerGridSquareSpinBox->setValue(5); // // Restrict points to surface check box // restrictPointsToSurfaceCheckBox = new QCheckBox("Restrict Points to Surface"); restrictPointsToSurfaceCheckBox->setChecked(true); QWidget* w = new QWidget; QGridLayout* layout = new QGridLayout(w); layout->addWidget(gridSpacingLabel, 0, 0); layout->addWidget(gridSpacingDoubleSpinBox, 0, 1); layout->addWidget(pointsPerGridSquareLabel, 1, 0); layout->addWidget(pointsPerGridSquareSpinBox, 1, 1); layout->addWidget(restrictPointsToSurfaceCheckBox, 2, 0, 1, 2); return w; } /** * update the page. */ void BordersPageCreateFlatGridBorders::updatePage() { } /** * see if the page is valid. */ bool BordersPageCreateFlatGridBorders::getPageValid() const { return true; } //============================================================================ //============================================================================ //============================================================================ /** * constructor. */ BordersPageCreateFlatAnalysisGridBorders::BordersPageCreateFlatAnalysisGridBorders() { } /** * destructor. */ BordersPageCreateFlatAnalysisGridBorders::~BordersPageCreateFlatAnalysisGridBorders() { } /** * called when update grid extent push button pressed. */ void BordersPageCreateFlatAnalysisGridBorders::slotUpdateGridExtentPushButton() { BrainModelSurface* bms = theMainWindow->getBrainModelOpenGL()->getDisplayedBrainModelSurface(); if (bms != NULL) { float bounds[6]; bms->getBounds(bounds); xMinDoubleSpinBox->setValue(bounds[0]); xMaxDoubleSpinBox->setValue(bounds[1]); yMinDoubleSpinBox->setValue(bounds[2]); yMaxDoubleSpinBox->setValue(bounds[3]); } } /** * apply the pages settings. */ void BordersPageCreateFlatAnalysisGridBorders::applyPage() { BrainModelSurface* bms = theMainWindow->getBrainModelOpenGL()->getDisplayedBrainModelSurface(); if (bms != NULL) { // // See if a flat surface is in the main window // BrainModelSurface::SURFACE_TYPES st = bms->getSurfaceType(); if ((st != BrainModelSurface::SURFACE_TYPE_FLAT) && (st != BrainModelSurface::SURFACE_TYPE_FLAT_LOBAR)) { if (QMessageBox::critical(theMainWindow, "Surface Type", "The surface in the main window must be flat for this operation.\n" "Do you want to continue?", QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) { return; } } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); float bounds[4]; bounds[0] = xMinDoubleSpinBox->value(); bounds[1] = xMaxDoubleSpinBox->value(); bounds[2] = yMinDoubleSpinBox->value(); bounds[3] = yMaxDoubleSpinBox->value(); const float spacing = spacingDoubleSpinBox->value(); BorderFile borderFile; bms->createFlatGridBordersForAnalysis(borderFile, bounds, spacing); theMainWindow->getBrainSet()->deleteAllBorders(); BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); bmbs->copyBordersFromBorderFile(bms, &borderFile); if (restrictPointsToSurfaceCheckBox->isChecked()) { theMainWindow->getLayersActions()->slotBordersDeletePointsOutsideSurface(); } BorderColorFile* colorFile = theMainWindow->getBrainSet()->getBorderColorFile(); colorFile->addColorIfItDoesNotExist("Grid", 255, 0, 0); theMainWindow->getBrainSet()->assignBorderColors(); DisplaySettingsBorders* dsb = theMainWindow->getBrainSet()->getDisplaySettingsBorders(); dsb->setDisplayBorders(true); GuiFilesModified fm; fm.setBorderModified(); fm.setBorderColorModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); QApplication::restoreOverrideCursor(); } } /** * create the page. */ QWidget* BordersPageCreateFlatAnalysisGridBorders::createPage() { // // X-Min // QLabel* xMinLabel = new QLabel("X-Min"); xMinDoubleSpinBox = new QDoubleSpinBox; xMinDoubleSpinBox->setMinimum(-5000000.0); xMinDoubleSpinBox->setMaximum(5000000.0); xMinDoubleSpinBox->setSingleStep(1); xMinDoubleSpinBox->setDecimals(3); xMinDoubleSpinBox->setValue(10.0); // // X-Max // QLabel* xMaxLabel = new QLabel("X-Max"); xMaxDoubleSpinBox = new QDoubleSpinBox; xMaxDoubleSpinBox->setMinimum(-5000000.0); xMaxDoubleSpinBox->setMaximum(5000000.0); xMaxDoubleSpinBox->setSingleStep(1); xMaxDoubleSpinBox->setDecimals(3); xMaxDoubleSpinBox->setValue(10.0); // // Y-Min // QLabel* yMinLabel = new QLabel("Y-Min"); yMinDoubleSpinBox = new QDoubleSpinBox; yMinDoubleSpinBox->setMinimum(-5000000.0); yMinDoubleSpinBox->setMaximum(5000000.0); yMinDoubleSpinBox->setSingleStep(1); yMinDoubleSpinBox->setDecimals(3); yMinDoubleSpinBox->setValue(10.0); // // Y-Max // QLabel* yMaxLabel = new QLabel("Y-Max"); yMaxDoubleSpinBox = new QDoubleSpinBox; yMaxDoubleSpinBox->setMinimum(-5000000.0); yMaxDoubleSpinBox->setMaximum(5000000.0); yMaxDoubleSpinBox->setSingleStep(1); yMaxDoubleSpinBox->setDecimals(3); yMaxDoubleSpinBox->setValue(10.0); // // spacing // QLabel* spacingLabel = new QLabel("Spacing (mm)"); spacingDoubleSpinBox = new QDoubleSpinBox; spacingDoubleSpinBox->setMinimum(0.01); spacingDoubleSpinBox->setMaximum(5000000.0); spacingDoubleSpinBox->setSingleStep(1); spacingDoubleSpinBox->setDecimals(3); spacingDoubleSpinBox->setValue(10.0); // // Restrict points to surface check box // restrictPointsToSurfaceCheckBox = new QCheckBox("Restrict Points to Surface"); restrictPointsToSurfaceCheckBox->setChecked(true); QPushButton* updateGridExtentPushButton = new QPushButton("Update Grid Extent"); updateGridExtentPushButton->setAutoDefault(false); updateGridExtentPushButton->setFixedSize(updateGridExtentPushButton->sizeHint()); QObject::connect(updateGridExtentPushButton, SIGNAL(clicked()), this, SLOT(slotUpdateGridExtentPushButton())); QWidget* w = new QWidget; QGridLayout* layout = new QGridLayout(w); layout->addWidget(xMinLabel, 0, 0); layout->addWidget(xMinDoubleSpinBox, 0, 1); layout->addWidget(xMaxLabel, 1, 0); layout->addWidget(xMaxDoubleSpinBox, 1, 1); layout->addWidget(yMinLabel, 2, 0); layout->addWidget(yMinDoubleSpinBox, 2, 1); layout->addWidget(yMaxLabel, 3, 0); layout->addWidget(yMaxDoubleSpinBox, 3, 1); layout->addWidget(spacingLabel, 4, 0); layout->addWidget(spacingDoubleSpinBox, 4, 1); layout->addWidget(restrictPointsToSurfaceCheckBox, 5, 0, 1, 2); layout->addWidget(updateGridExtentPushButton, 6, 0); slotUpdateGridExtentPushButton(); return w; } /** * update the page. */ void BordersPageCreateFlatAnalysisGridBorders::updatePage() { } /** * see if the page is valid. */ bool BordersPageCreateFlatAnalysisGridBorders::getPageValid() const { return true; } //============================================================================ //============================================================================ //============================================================================ /** * constructor. */ BordersPageCreateInterpolatedBorders::BordersPageCreateInterpolatedBorders() { border1Index = -1; border2Index = -1; } /** * destructor. */ BordersPageCreateInterpolatedBorders::~BordersPageCreateInterpolatedBorders() { } /** * apply the pages settings. */ void BordersPageCreateInterpolatedBorders::applyPage() { BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); const int numBorders = bmbs->getNumberOfBorders(); if ((border1Index < 0) || (border1Index >= numBorders) || (border2Index < 0) || (border2Index >= numBorders)) { WuQMessageBox::critical(this, "ERROR", "Borders selected are invalid. Reselect."); return; } // // Interpolate the borders // const QString borderName(namePrefixLineEdit->text()); QString errorMessage; bmbs->createInterpolatedBorders(theMainWindow->getBrainModelSurface(), border1Index, border2Index, borderName, numberOfInterplatedBordersSpinBox->value(), samplingDoubleSpinBox->value(), errorMessage); if (errorMessage.isEmpty() == false) { WuQMessageBox::critical(this, "ERROR", errorMessage); return; } // // Find the matching color // bool borderColorMatch = false; BorderColorFile* borderColorFile = theMainWindow->getBrainSet()->getBorderColorFile(); const int borderColorIndex = borderColorFile->getColorIndexByName(borderName, borderColorMatch); // // Border color may need to be created // bool createBorderColor = false; if ((borderColorIndex >= 0) && (borderColorMatch == true)) { createBorderColor = false; } else if ((borderColorIndex >= 0) && (borderColorMatch == false)) { QString msg("Use border color \""); msg.append(borderColorFile->getColorNameByIndex(borderColorIndex)); msg.append("\" for border "); msg.append(borderName); msg.append(" ?"); QString noButton("No, define color "); noButton.append(borderName); if (QMessageBox::information(this, "Use Partially Matching Color", msg, (QMessageBox::Yes | QMessageBox::No), QMessageBox::No) == QMessageBox::No) { createBorderColor = true; } } else { createBorderColor = true; } if (createBorderColor) { QString title("Create Border Color: "); title.append(borderName); GuiColorSelectionDialog* csd = new GuiColorSelectionDialog(this, title, false, false, false, false); csd->exec(); // // Add new border color // float pointSize = 2.0, lineSize = 1.0; unsigned char r, g, b, a; ColorFile::ColorStorage::SYMBOL symbol; csd->getColorInformation(r, g, b, a, pointSize, lineSize, symbol); borderColorFile->addColor(borderName, r, g, b, a, pointSize, lineSize, symbol); } GuiFilesModified fm; fm.setBorderModified(); fm.setBorderColorModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); } /** * create the page. */ QWidget* BordersPageCreateInterpolatedBorders::createPage() { const int minWidth = 300; // // Border 1 Labels // QLabel* border1Label = new QLabel("Border 1 (left click): "); border1NameLabel = new QLabel(""); border1NameLabel->setMinimumWidth(minWidth); // // Border 2 Labels // QLabel* border2Label = new QLabel("Border 2 (left click): "); border2NameLabel = new QLabel(""); border2NameLabel->setMinimumWidth(minWidth); // // Name prefix // QLabel* namePrefixLabel = new QLabel("Name Prefix"); namePrefixLineEdit = new QLineEdit; namePrefixLineEdit->setMinimumWidth(minWidth); namePrefixLineEdit->setText("LANDMARK.Interpolated"); // // Sampling // QLabel* samplingLabel = new QLabel("Sampling"); samplingDoubleSpinBox = new QDoubleSpinBox; samplingDoubleSpinBox->setMinimum(0.001); samplingDoubleSpinBox->setMaximum(500000.0); samplingDoubleSpinBox->setSingleStep(1); samplingDoubleSpinBox->setDecimals(2); samplingDoubleSpinBox->setValue(1.0); // // Number of interpolated borders // QLabel* numberOfInterplatedBordersLabel = new QLabel("Number of Interpolated Borders"); numberOfInterplatedBordersSpinBox = new QSpinBox; numberOfInterplatedBordersSpinBox->setMinimum(1); numberOfInterplatedBordersSpinBox->setMaximum(100000); numberOfInterplatedBordersSpinBox->setSingleStep(1); numberOfInterplatedBordersSpinBox->setValue(1); // // Enable mouse push button // QPushButton* enableMousePushButton = new QPushButton("Enable Mouse"); enableMousePushButton->setAutoDefault(false); enableMousePushButton->setFixedSize(enableMousePushButton->sizeHint()); QObject::connect(enableMousePushButton, SIGNAL(clicked()), this, SLOT(slotEnableMousePushButton())); QWidget* w = new QWidget; QGridLayout* layout = new QGridLayout(w); layout->addWidget(border1Label, 0, 0); layout->addWidget(border1NameLabel, 0, 1); layout->addWidget(border2Label, 1, 0); layout->addWidget(border2NameLabel, 1, 1); layout->addWidget(namePrefixLabel, 2, 0); layout->addWidget(namePrefixLineEdit, 2, 1); layout->addWidget(samplingLabel, 3, 0); layout->addWidget(samplingDoubleSpinBox, 3, 1); layout->addWidget(numberOfInterplatedBordersLabel, 4, 0); layout->addWidget(numberOfInterplatedBordersSpinBox, 4, 1); layout->addWidget(enableMousePushButton, 5, 0, 1, 2); return w; } /** * called to enable mouse mode. */ void BordersPageCreateInterpolatedBorders::slotEnableMousePushButton() { theMainWindow->getBrainModelOpenGL()->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_BORDER_INTERPOLATE_NEW); } /** * set selected borders. */ void BordersPageCreateInterpolatedBorders::setSelectedBorders(const int borderNumber, const int borderIndex) { // // Get index and name of border // BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); const BrainModelBorder* b = bmbs->getBorder(borderIndex); const QString labelValue(QString::number(borderIndex) + " " + b->getName()); switch (borderNumber) { case 0: border1Index = borderIndex; border1NameLabel->setText(labelValue); break; case 1: border2Index = borderIndex; border2NameLabel->setText(labelValue); break; } } /** * update the page. */ void BordersPageCreateInterpolatedBorders::updatePage() { theMainWindow->getBrainModelOpenGL()->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_BORDER_INTERPOLATE_NEW); } /** * see if the page is valid. */ bool BordersPageCreateInterpolatedBorders::getPageValid() const { return true; } //============================================================================ //============================================================================ //============================================================================ /** * constructor. */ BordersPageEditAttributes::BordersPageEditAttributes() { } /** * destructor. */ BordersPageEditAttributes::~BordersPageEditAttributes() { } /** * apply the pages settings. */ void BordersPageEditAttributes::applyPage() { } /** * create the page. */ QWidget* BordersPageEditAttributes::createPage() { QLabel* label = new QLabel("Attributes"); QWidget* w = new QWidget; QVBoxLayout* layout = new QVBoxLayout(w); layout->addWidget(label); return w; } /** * update the page. */ void BordersPageEditAttributes::updatePage() { } /** * see if the page is valid. */ bool BordersPageEditAttributes::getPageValid() const { return true; } //============================================================================ //============================================================================ //============================================================================ /** * constructor. */ BordersPageCreateLandmarks::BordersPageCreateLandmarks() { } /** * destructor. */ BordersPageCreateLandmarks::~BordersPageCreateLandmarks() { } /** * set checkboxes for operations. */ void BordersPageCreateLandmarks::initializePage(const bool checkCreateFlattenLandmarks, const bool checkCreateRegistrationLandmarks, const BrainModelSurface* fiducialSurface, const BrainModelSurface* inflatedSurface, const BrainModelSurface* veryInflatedSurface, const BrainModelSurface* sphericalSurface) { createFlattenLandmarksCheckBox->setChecked(checkCreateFlattenLandmarks); createRegistrationLandmarksCheckBox->setChecked(checkCreateRegistrationLandmarks); fiducialSurfaceComboBox->setSelectedBrainModelSurface(fiducialSurface); inflatedSurfaceComboBox->setSelectedBrainModelSurface(inflatedSurface); veryInflatedSurfaceComboBox->setSelectedBrainModelSurface(veryInflatedSurface); ellipsoidSurfaceComboBox->setSelectedBrainModelSurface(sphericalSurface); } /** * apply the pages settings. */ void BordersPageCreateLandmarks::applyPage() { BrainSet* bs = theMainWindow->getBrainSet(); int operationMask = 0; if (createFlattenLandmarksCheckBox->isChecked()) { operationMask |= BrainModelSurfaceBorderLandmarkIdentification::OPERATION_ID_FLATTENING_LANDMARKS; } if (createRegistrationLandmarksCheckBox->isChecked()) { operationMask |= BrainModelSurfaceBorderLandmarkIdentification::OPERATION_ID_REGISTRATION_LANDMARKS; } BorderProjectionFile borderProjectionFile; BrainModelSurfaceBorderLandmarkIdentification landmark(bs, stereotaxicSpaceComboBox->getSelectedStereotaxicSpace(), anatomicalVolumeComboBox->getSelectedVolumeFile(), fiducialSurfaceComboBox->getSelectedBrainModelSurface(), inflatedSurfaceComboBox->getSelectedBrainModelSurface(), veryInflatedSurfaceComboBox->getSelectedBrainModelSurface(), ellipsoidSurfaceComboBox->getSelectedBrainModelSurface(), bs->getSurfaceShapeFile(), shapeDepthColumnComboBox->currentIndex(), bs->getPaintFile(), paintGeographyColumnComboBox->currentIndex(), bs->getAreaColorFile(), &borderProjectionFile, bs->getBorderColorFile(), bs->getVocabularyFile(), operationMask); try { WuQDialog::showWaitCursor(); landmark.execute(); BrainModelBorderSet* bmbs = bs->getBorderSet(); bmbs->copyBordersFromBorderProjectionFile(&borderProjectionFile); bmbs->setAllBordersModifiedStatus(false); bmbs->setProjectionsModified(true); DisplaySettingsBorders* dsb = bs->getDisplaySettingsBorders(); dsb->setDisplayBorders(true); GuiFilesModified fm; fm.setAreaColorModified(); fm.setBorderModified(); fm.setBorderColorModified(); fm.setPaintModified(), fm.setVocabularyModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(); WuQDialog::showNormalCursor(); WuQMessageBox::information(this, "OK", "Borders generated successfully.\n" "Data files need to be saved. See\n" "File Menu->Manage Loaded Files."); } catch (BrainModelAlgorithmException& e) { WuQDialog::showNormalCursor(); WuQMessageBox::critical(this, "ERROR", e.whatQString()); } } /** * create the page. */ QWidget* BordersPageCreateLandmarks::createPage() { const int maxWidth = 400; // // Create flatten landmarks check box // createFlattenLandmarksCheckBox = new QCheckBox("Create Flattening Landmarks"); createFlattenLandmarksCheckBox->setChecked(true); // // Create flatten landmarks check box // createRegistrationLandmarksCheckBox = new QCheckBox("Create Registration Landmarks"); createRegistrationLandmarksCheckBox->setChecked(true); // // stereotaxic space // QLabel* stereotaxicSpaceLabel = new QLabel("Stereotaxic Space"); stereotaxicSpaceComboBox = new GuiStereotaxicSpaceComboBox; stereotaxicSpaceComboBox->setMaximumWidth(maxWidth); // // anatomical volume // QLabel* anatomicalVolumeLabel = new QLabel("Anatomical Volume"); anatomicalVolumeComboBox = new GuiVolumeFileSelectionComboBox( VolumeFile::VOLUME_TYPE_ANATOMY); anatomicalVolumeComboBox->setMaximumWidth(maxWidth); anatomicalVolumeComboBox->setToolTip( "If the anatomical volume contains ONLY the corpus callosum\n" "the name MUST contain both the words \"corpus\" and \"callosum\""); // // fiducial surface // QLabel* fiducialSurfaceLabel = new QLabel("Fiducial Surface"); fiducialSurfaceComboBox = new GuiBrainModelSurfaceSelectionComboBox( BrainModelSurface::SURFACE_TYPE_FIDUCIAL); fiducialSurfaceComboBox->setMaximumWidth(maxWidth); // // inflated surface // QLabel* inflatedSurfaceLabel = new QLabel("Inflated Surface"); inflatedSurfaceComboBox = new GuiBrainModelSurfaceSelectionComboBox( BrainModelSurface::SURFACE_TYPE_INFLATED); inflatedSurfaceComboBox->setMaximumWidth(maxWidth); // // very inflated surface // QLabel* veryInflatedSurfaceLabel = new QLabel("Very Inflated Surface"); veryInflatedSurfaceComboBox = new GuiBrainModelSurfaceSelectionComboBox( BrainModelSurface::SURFACE_TYPE_VERY_INFLATED); veryInflatedSurfaceComboBox->setMaximumWidth(maxWidth); // // ellipsoid surface // std::vector sphereEllipsoidTypes; sphereEllipsoidTypes.push_back(BrainModelSurface::SURFACE_TYPE_ELLIPSOIDAL); sphereEllipsoidTypes.push_back(BrainModelSurface::SURFACE_TYPE_SPHERICAL); QLabel* ellipsoidSurfaceLabel = new QLabel("Sphere/Ellipsoid Surface"); ellipsoidSurfaceComboBox = new GuiBrainModelSurfaceSelectionComboBox( sphereEllipsoidTypes); ellipsoidSurfaceComboBox->setMaximumWidth(maxWidth); // // paint geography column // QLabel* paintGeographyLabel = new QLabel("Paint Geography Column"); paintGeographyColumnComboBox = new GuiNodeAttributeColumnSelectionComboBox( GUI_NODE_FILE_TYPE_PAINT, false, false, false); paintGeographyColumnComboBox->setMaximumWidth(maxWidth); // // surface shape depth column // QLabel* surfaceShapeDepthLabel = new QLabel("Shape Depth Column"); shapeDepthColumnComboBox = new GuiNodeAttributeColumnSelectionComboBox( GUI_NODE_FILE_TYPE_SURFACE_SHAPE, false, false, false); shapeDepthColumnComboBox->setMaximumWidth(maxWidth); QWidget* w = new QWidget; QGridLayout* layout = new QGridLayout(w); layout->addWidget(createFlattenLandmarksCheckBox, 0, 0, 1, 2); layout->addWidget(createRegistrationLandmarksCheckBox, 1, 0, 1, 2); layout->addWidget(stereotaxicSpaceLabel, 2, 0); layout->addWidget(stereotaxicSpaceComboBox, 2, 1); layout->addWidget(anatomicalVolumeLabel, 3, 0); layout->addWidget(anatomicalVolumeComboBox, 3, 1); layout->addWidget(fiducialSurfaceLabel, 4, 0); layout->addWidget(fiducialSurfaceComboBox, 4, 1); layout->addWidget(inflatedSurfaceLabel, 5, 0); layout->addWidget(inflatedSurfaceComboBox, 5, 1); layout->addWidget(veryInflatedSurfaceLabel, 6, 0); layout->addWidget(veryInflatedSurfaceComboBox, 6, 1); layout->addWidget(ellipsoidSurfaceLabel, 7, 0); layout->addWidget(ellipsoidSurfaceComboBox, 7, 1); layout->addWidget(paintGeographyLabel, 8, 0); layout->addWidget(paintGeographyColumnComboBox, 8, 1); layout->addWidget(surfaceShapeDepthLabel, 9, 0); layout->addWidget(shapeDepthColumnComboBox, 9, 1); layout->setColumnStretch(0, 0); layout->setColumnStretch(0, 1); return w; } /** * update the page. */ void BordersPageCreateLandmarks::updatePage() { BrainSet* bs = theMainWindow->getBrainSet(); stereotaxicSpaceComboBox->setSelectedStereotaxicSpace(bs->getStereotaxicSpace()); anatomicalVolumeComboBox->updateComboBox(); fiducialSurfaceComboBox->updateComboBox(); inflatedSurfaceComboBox->updateComboBox(); veryInflatedSurfaceComboBox->updateComboBox(); ellipsoidSurfaceComboBox->updateComboBox(); shapeDepthColumnComboBox->updateComboBox(); const int depthColumn = bs->getSurfaceShapeFile()->getColumnWithName( SurfaceShapeFile::sulcalDepthColumnName); if (depthColumn >= 0) { shapeDepthColumnComboBox->setCurrentIndex(depthColumn); } paintGeographyColumnComboBox->updateComboBox(); const int geographyColumn = bs->getPaintFile()->getColumnWithName( PaintFile::columnNameGeography); if (geographyColumn >= 0) { paintGeographyColumnComboBox->setCurrentIndex(geographyColumn); } } /** * see if the page is valid. */ bool BordersPageCreateLandmarks::getPageValid() const { return true; } caret-5.6.4~dfsg.1.orig/caret/GuiBorderNamesListBoxSelectionDialog.h0000664000175000017500000000302011572067322025164 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_BORDER_NAMES_LIST_BOX_SELECTION_DIALOG_H__ #define __GUI_BORDER_NAMES_LIST_BOX_SELECTION_DIALOG_H__ #include "QtListBoxSelectionDialog.h" /// This class creates a list box for selecting border names class GuiBorderNamesListBoxSelectionDialog : public QtListBoxSelectionDialog { Q_OBJECT public: /// constructor GuiBorderNamesListBoxSelectionDialog(QWidget* parent, const QString& defaultBorderName = ""); /// destructor ~GuiBorderNamesListBoxSelectionDialog(); private: }; #endif // __GUI_BORDER_NAMES_LIST_BOX_SELECTION_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiBorderNamesListBoxSelectionDialog.cxx0000664000175000017500000000365511572067322025555 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "BrainModelBorderSet.h" #include "BrainSet.h" #include "GuiBorderNamesListBoxSelectionDialog.h" #include "GuiMainWindow.h" #include "global_variables.h" /** * Constructor. */ GuiBorderNamesListBoxSelectionDialog::GuiBorderNamesListBoxSelectionDialog(QWidget* parent, const QString& defaultBorderName) : QtListBoxSelectionDialog(parent, "Border Name Selection") { std::vector names; BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); bmbs->getAllBorderNames(names, false); QString nameToFind(defaultBorderName); std::vector::iterator iter = std::find(names.begin(), names.end(), defaultBorderName); int defaultIndex = 0; if (iter != names.end()) { defaultIndex = iter - names.begin(); } setListBoxContents(names, defaultIndex); } /** * Destructor. */ GuiBorderNamesListBoxSelectionDialog::~GuiBorderNamesListBoxSelectionDialog() { } caret-5.6.4~dfsg.1.orig/caret/GuiBorderDrawUpdateDialog.h0000664000175000017500000000523211572067322023015 0ustar michaelmichael #ifndef __GUI_BORDER_DRAW_UPDATE_DIALOG_H__ #define __GUI_BORDER_DRAW_UPDATE_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "BrainModelBorderSet.h" #include "WuQDialog.h" class QAbstractButton; class QCheckBox; class QDialogButtonBox; class QDoubleSpinBox; class QRadioButton; /// dialog for drawing border updates class GuiBorderDrawUpdateDialog : public WuQDialog { Q_OBJECT public: // constructor GuiBorderDrawUpdateDialog(QWidget* parent = 0); // destructor ~GuiBorderDrawUpdateDialog(); // get the resampling density float getResampling() const; // get the 3D flag bool getThreeDimensional() const; // get the auto project border flag bool getAutoProjectBorder() const; // get the update mode BrainModelBorderSet::UPDATE_BORDER_MODE getBorderUpdateMode() const; protected slots: // called when standard button pressed void slotStandardButtonPressed(QAbstractButton*); protected: /// dialog button box QDialogButtonBox* dialogButtonBox; /// resampling spin box QDoubleSpinBox* resamplingDoubleSpinBox; /// dimension two radio button QRadioButton* dimensionTwoRadioButton; /// dimension three radio button QRadioButton* dimensionThreeRadioButton; /// auto project YES check box QRadioButton* autoProjectYesRadioButton; /// auto project NO check box QRadioButton* autoProjectNoRadioButton; /// radio button QRadioButton* replaceSegmentInBorderModeRadioButton; /// radio button QRadioButton* extendBorderModeRadioButton; /// radio button QRadioButton* eraseBorderModeRadioButton; }; #endif // __GUI_BORDER_DRAW_UPDATE_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiBorderDrawUpdateDialog.cxx0000664000175000017500000001745111572067322023376 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include "GuiBorderDrawUpdateDialog.h" #include "GuiBrainModelOpenGL.h" #include "GuiMainWindow.h" #include "global_variables.h" /** * constructor. */ GuiBorderDrawUpdateDialog::GuiBorderDrawUpdateDialog(QWidget* parent) : WuQDialog(parent) { setWindowTitle("Draw Border Update"); //------------------------------------------------------------------------- // // Resampling Double Spin Box // resamplingDoubleSpinBox = new QDoubleSpinBox; resamplingDoubleSpinBox->setMinimum(0.001); resamplingDoubleSpinBox->setMaximum(10000000); resamplingDoubleSpinBox->setSingleStep(1.0); resamplingDoubleSpinBox->setDecimals(2); resamplingDoubleSpinBox->setValue(2.0); QGroupBox* resamplingGroupBox = new QGroupBox("Resampling"); QVBoxLayout* resamplingLayout = new QVBoxLayout(resamplingGroupBox); resamplingLayout->addWidget(resamplingDoubleSpinBox); //------------------------------------------------------------------------- // // Dimension Radio Buttons // dimensionTwoRadioButton = new QRadioButton("2D (Flat)"); dimensionThreeRadioButton = new QRadioButton("3D"); // // Button Group to keep radio buttons mutually exclusive // QButtonGroup* dimButtGroup = new QButtonGroup(this); dimButtGroup->addButton(dimensionTwoRadioButton); dimButtGroup->addButton(dimensionThreeRadioButton); // // Group box and layout for dimension // QGroupBox* dimensionGroupBox = new QGroupBox("Dimensions"); QVBoxLayout* dimensionLayout = new QVBoxLayout(dimensionGroupBox); dimensionLayout->addWidget(dimensionTwoRadioButton); dimensionLayout->addWidget(dimensionThreeRadioButton); //------------------------------------------------------------------------- // // Auto Project Radio Buttons // autoProjectYesRadioButton = new QRadioButton("Yes"); autoProjectNoRadioButton = new QRadioButton("No"); // // Button Group to keep project radio buttons mutually exclusive // QButtonGroup* projectButtGroup = new QButtonGroup(this); projectButtGroup->addButton(autoProjectYesRadioButton); projectButtGroup->addButton(autoProjectNoRadioButton); // // Group box and layout for auto project // QGroupBox* autoProjectGroupBox = new QGroupBox("Auto Project"); QVBoxLayout* autoProjectLayout = new QVBoxLayout(autoProjectGroupBox); autoProjectLayout->addWidget(autoProjectYesRadioButton); autoProjectLayout->addWidget(autoProjectNoRadioButton); //------------------------------------------------------------------------- // // Mode radio buttons // extendBorderModeRadioButton = new QRadioButton("Extend From Either End"); replaceSegmentInBorderModeRadioButton = new QRadioButton("Replace Segment"); eraseBorderModeRadioButton = new QRadioButton("Erase Segment"); // // Button Group to keep mode radio buttons mutually exclusive // QButtonGroup* modeButtGroup = new QButtonGroup(this); modeButtGroup->addButton(eraseBorderModeRadioButton); modeButtGroup->addButton(extendBorderModeRadioButton); modeButtGroup->addButton(replaceSegmentInBorderModeRadioButton); // // Group box and layout for mode // QGroupBox* modeGroupBox = new QGroupBox("Mode"); QVBoxLayout* modeLayout = new QVBoxLayout(modeGroupBox); modeLayout->addWidget(eraseBorderModeRadioButton); modeLayout->addWidget(extendBorderModeRadioButton); modeLayout->addWidget(replaceSegmentInBorderModeRadioButton); //------------------------------------------------------------------------- // // Dialog buttons // dialogButtonBox = new QDialogButtonBox(QDialogButtonBox::Apply | QDialogButtonBox::Close | QDialogButtonBox::Help); QObject::connect(dialogButtonBox, SIGNAL(clicked(QAbstractButton*)), this, SLOT(slotStandardButtonPressed(QAbstractButton*))); //------------------------------------------------------------------------- // // Layout for dialog // QHBoxLayout* contentLayout = new QHBoxLayout; contentLayout->addWidget(dimensionGroupBox); contentLayout->addWidget(autoProjectGroupBox); QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->addWidget(modeGroupBox); dialogLayout->addLayout(contentLayout); dialogLayout->addWidget(resamplingGroupBox); dialogLayout->addWidget(dialogButtonBox); //------------------------------------------------------------------------- // // Initialize // dimensionThreeRadioButton->setChecked(true); autoProjectYesRadioButton->setChecked(true); } /** * destructor. */ GuiBorderDrawUpdateDialog::~GuiBorderDrawUpdateDialog() { } /** * called when standard button pressed. */ void GuiBorderDrawUpdateDialog::slotStandardButtonPressed(QAbstractButton* buttonPressed) { if (buttonPressed == dialogButtonBox->button(QDialogButtonBox::Apply)) { if (getBorderUpdateMode() == BrainModelBorderSet::UPDATE_BORDER_MODE_NONE) { QMessageBox::critical(this, "ERROR", "You must select a mode."); return; } theMainWindow->getBrainModelOpenGL()->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_BORDER_UPDATE); } else if (buttonPressed == dialogButtonBox->button(QDialogButtonBox::Close)) { theMainWindow->getBrainModelOpenGL()->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_VIEW); close(); } else if (buttonPressed == dialogButtonBox->button(QDialogButtonBox::Help)) { theMainWindow->showHelpViewerDialog("dialogs/draw_border_update_dialog.html"); } } /** * get the resampling density. */ float GuiBorderDrawUpdateDialog::getResampling() const { return resamplingDoubleSpinBox->value(); } /** * get the 3D flag. */ bool GuiBorderDrawUpdateDialog::getThreeDimensional() const { return dimensionThreeRadioButton->isChecked(); } /** * get the auto project border flag. */ bool GuiBorderDrawUpdateDialog::getAutoProjectBorder() const { return autoProjectYesRadioButton->isChecked(); } /** * get the update mode. */ BrainModelBorderSet::UPDATE_BORDER_MODE GuiBorderDrawUpdateDialog::getBorderUpdateMode() const { BrainModelBorderSet::UPDATE_BORDER_MODE borderMode = BrainModelBorderSet::UPDATE_BORDER_MODE_NONE; if (replaceSegmentInBorderModeRadioButton->isChecked()) { borderMode = BrainModelBorderSet::UPDATE_BORDER_MODE_REPLACE_SEGMENT_IN_MIDDLE_OF_BORDER; } else if (eraseBorderModeRadioButton->isChecked()) { borderMode = BrainModelBorderSet::UPDATE_BORDER_MODE_ERASE; } else if (extendBorderModeRadioButton->isChecked()) { borderMode = BrainModelBorderSet::UPDATE_BORDER_MODE_EXTEND_BORDER_FROM_END; } return borderMode; } caret-5.6.4~dfsg.1.orig/caret/GuiBorderComparisonDialog.h0000664000175000017500000000341611572067322023071 0ustar michaelmichael #ifndef __GUI_BORDER_COMPARISON_DIALOG_H__ #define __GUI_BORDER_COMPARISON_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include "WuQDialog.h" class QLineEdit; /// dialog for comparing borders class GuiBorderComparisonDialog : public WuQDialog { Q_OBJECT public: /// constructor GuiBorderComparisonDialog(QWidget* parent); /// destructor ~GuiBorderComparisonDialog(); protected slots: /// called when apply button is pressed void slotApplyButton(); /// called when border file A button is pressed void slotButtonBorderFileA(); /// called when border file B button is pressed void slotButtonBorderFileB(); protected: /// line edit for border file A name QLineEdit* borderFileALineEdit; /// line edit for border file B name QLineEdit* borderFileBLineEdit; }; #endif // __GUI_BORDER_COMPARISON_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiBorderComparisonDialog.cxx0000664000175000017500000001711311572067322023443 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include "BorderFile.h" #include "GuiBorderComparisonDialog.h" #include "MathUtilities.h" #include "QtTextEditDialog.h" #include "QtUtilities.h" #include "SpecFile.h" #include "WuQFileDialog.h" /** * constructor. */ GuiBorderComparisonDialog::GuiBorderComparisonDialog(QWidget* parent) : WuQDialog(parent) { setWindowTitle("Border Comparison"); // // Layout for dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(3); dialogLayout->setSpacing(3); // // Grid layout for file section // QGridLayout* fileGridLayout = new QGridLayout; fileGridLayout->setMargin(3); fileGridLayout->setColumnStretch(0, 0); fileGridLayout->setColumnStretch(1, 100); dialogLayout->addLayout(fileGridLayout); // // File A button and line edit // QPushButton* fileAButton = new QPushButton("Border File A..."); QObject::connect(fileAButton, SIGNAL(clicked()), this, SLOT(slotButtonBorderFileA())); fileAButton->setAutoDefault(false); fileGridLayout->addWidget(fileAButton, 0, 0); borderFileALineEdit = new QLineEdit; borderFileALineEdit->setMinimumWidth(300); fileGridLayout->addWidget(borderFileALineEdit, 0, 1); // // File B button and line edit // QPushButton* fileBButton = new QPushButton("Border File B..."); QObject::connect(fileBButton, SIGNAL(clicked()), this, SLOT(slotButtonBorderFileB())); fileBButton->setAutoDefault(false); fileGridLayout->addWidget(fileBButton, 1, 0); borderFileBLineEdit = new QLineEdit; borderFileBLineEdit->setMinimumWidth(300); fileGridLayout->addWidget(borderFileBLineEdit, 1, 1); // // Layout for buttons // QHBoxLayout* buttonLayout = new QHBoxLayout; buttonLayout->setSpacing(3); dialogLayout->addLayout(buttonLayout); // // Apply button // QPushButton* applyButton = new QPushButton("Apply"); buttonLayout->addWidget(applyButton); applyButton->setAutoDefault(false); QObject::connect(applyButton, SIGNAL(clicked()), this, SLOT(slotApplyButton())); // // Close button // QPushButton* closeButton = new QPushButton("Close"); buttonLayout->addWidget(closeButton); closeButton->setAutoDefault(false); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); // // Make buttons the same size // QtUtilities::makeButtonsSameSize(applyButton, closeButton); } /** * destructor. */ GuiBorderComparisonDialog::~GuiBorderComparisonDialog() { } /** * called when apply button is pressed. */ void GuiBorderComparisonDialog::slotApplyButton() { // // See if border entered // const QString fileNameA = borderFileALineEdit->text(); if (fileNameA.isEmpty()) { QMessageBox::critical(this, "ERROR", "Border file A not specified."); return; } const QString fileNameB = borderFileBLineEdit->text(); if (fileNameB.isEmpty()) { QMessageBox::critical(this, "ERROR", "Border file B not specified."); return; } // // Read the border files // BorderFile fileA; try { fileA.readFile(fileNameA); } catch (FileException& e) { QMessageBox::critical(this, "ERROR", e.whatQString()); return; } BorderFile fileB; try { fileB.readFile(fileNameB); } catch (FileException& e) { QMessageBox::critical(this, "ERROR", e.whatQString()); return; } // // Make sure there are borders // const int num = fileA.getNumberOfBorders(); if (num <= 0) { QMessageBox::critical(this, "ERROR", "File A contains 0 borders."); return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); // // string stream used for comparison messages // std::ostringstream str; // // loop through border file A's borders // for (int i = 0; i < num; i++) { // // Get border from file A and its name // Border* borderA = fileA.getBorder(i); const QString name(borderA->getName()); // // If border A has links // const int numLinks = borderA->getNumberOfLinks(); if (numLinks > 0) { // // Get border from other file with name of border from file A // Border* borderB = fileB.getBorderByName(name); if (borderB != NULL) { // // Make sure number of links match // if (borderB->getNumberOfLinks() == numLinks) { // // compute average distance between links // double sum = 0.0; for (int j = 0; j < numLinks; j++) { sum += MathUtilities::distance3D(borderA->getLinkXYZ(j), borderB->getLinkXYZ(j)); } str << name.toAscii().constData() << " average distance between points " << (sum / static_cast(numLinks)) << "."; } else { str << name.toAscii().constData() << " has different number of links in file B"; } } else { str << name.toAscii().constData() << " not found in file border file B."; } } else { str << name.toAscii().constData() << " has no links - ignored."; } str << "\n\n"; } QApplication::beep(); QApplication::restoreOverrideCursor(); // // Display results // QtTextEditDialog* te = new QtTextEditDialog(this, true); te->setText(str.str().c_str()); te->show(); } /** * called when border file A button is pressed. */ void GuiBorderComparisonDialog::slotButtonBorderFileA() { WuQFileDialog fd(this); fd.setModal(true); fd.setDirectory(QDir::currentPath()); fd.setWindowTitle("Choose Border File"); fd.setFileMode(WuQFileDialog::ExistingFile); fd.setFilter(QString("Border Files (*%1)").arg(SpecFile::getBorderFileExtension())); if (fd.exec() == QDialog::Accepted) { borderFileALineEdit->setText(fd.selectedFiles().at(0)); } } /** * called when border file B button is pressed. */ void GuiBorderComparisonDialog::slotButtonBorderFileB() { WuQFileDialog fd(this); fd.setModal(true); fd.setDirectory(QDir::currentPath()); fd.setWindowTitle("Choose Border File"); fd.setFileMode(WuQFileDialog::ExistingFile); fd.setFilter(QString("Border Files (*%1)").arg(SpecFile::getBorderFileExtension())); if (fd.exec() == QDialog::Accepted) { borderFileBLineEdit->setText(fd.selectedFiles().at(0)); } } caret-5.6.4~dfsg.1.orig/caret/GuiBorderAttributesDialog.h0000664000175000017500000001222211572067322023100 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_GUI_BORDER_ATTRIBUTES_DIALOG_H__ #define __VE_GUI_BORDER_ATTRIBUTES_DIALOG_H__ #include #include #include "BorderFile.h" #include "BorderProjectionFile.h" #include "WuQDialog.h" class QCheckBox; class QLineEdit; /// This class creates the border attributes editor dialog class GuiBorderAttributesDialog : public WuQDialog { Q_OBJECT public: /// border file type enum BORDER_FILE_TYPE { /// border file BORDER_FILE_TYPE_BORDER, /// border projection file BORDER_FILE_TYPE_BORDER_PROJECTION, /// border brain model border set BORDER_FILE_TYPE_BORDER_SET }; /// storage for unique border attributes class BorderAttributes { public: /// name of border QString name; /// border sampling; float sampling; /// border variance float variance; /// border topography float topography; /// border uncertainty float uncertainty; /// index in file int fileIndex; /// number of links in the border int numberOfLinks; /// retain this border bool retain; /// constructor BorderAttributes(const QString& nameIn, const int fileIndexIn, const int numberOfLinksIn, const float samplingIn, const float varianceIn, const float topographyIn, const float uncertaintyIn) { name = nameIn; fileIndex = fileIndexIn, numberOfLinks = numberOfLinksIn; sampling = samplingIn; variance = varianceIn; topography = topographyIn; uncertainty = uncertaintyIn; retain = true; } bool operator<(const BorderAttributes& ba) const { if (name == ba.name) { return (fileIndex < ba.fileIndex); } return (name < ba.name); } }; /// Constructor for use with borders loaded in Caret GuiBorderAttributesDialog(QWidget* parent); /// Constructor for use with borders in a border or border projection file GuiBorderAttributesDialog(QWidget* parent, const QString fileNameIn, const BORDER_FILE_TYPE borderFileTypeIn, const bool showVarianceTopographyUncertaintyFlagIn = true); /// Destructor ~GuiBorderAttributesDialog(); protected slots: /// called when ok/canel buttons pressed void done(int r); protected: /// process the brain model border set borders void processBrainModelBorderSetBorders(); /// process the border file void processBorderFile(); /// process the border projection file void processBorderProjectionFile(); /// create the dialog void createDialog(); /// storage for the unique borders std::vector attributes; /// retain check boxes std::vector retainCheckBoxes; /// name line edits std::vector nameLineEdits; /// sampling line edits std::vector samplingLineEdits; /// variance line edits std::vector varianceLineEdits; /// topography line edits std::vector topographyLineEdits; /// uncertainty line edits std::vector uncertaintyLineEdits; /// border file type BORDER_FILE_TYPE borderFileType; /// name of border file QString fileName; /// border file BorderFile borderFile; /// border projection file BorderProjectionFile borderProjectionFile; /// show topography and undertainty bool showTopographyUncertaintyFlag; }; #endif // __VE_GUI_BORDER_ATTRIBUTES_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiBorderAttributesDialog.cxx0000664000175000017500000004204011572067322023454 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include "BrainModelBorderSet.h" #include "BrainSet.h" #include "GuiBorderAttributesDialog.h" #include "GuiBrainModelOpenGL.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "QtUtilities.h" #include "global_variables.h" /** * Constructor. */ GuiBorderAttributesDialog::GuiBorderAttributesDialog(QWidget* parent) : WuQDialog(parent) { setModal(true); showTopographyUncertaintyFlag = true; borderFileType = BORDER_FILE_TYPE_BORDER_SET; BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); const int numBorders = bmbs->getNumberOfBorders(); for (int j = 0; j < numBorders; j++) { BrainModelBorder* b = bmbs->getBorder(j); BorderAttributes ba(b->getName(), j, b->getNumberOfBorderLinks(), b->getSamplingDensity(), b->getVariance(), b->getTopography(), b->getArealUncertainty()); attributes.push_back(ba); } createDialog(); } /** * Constructor for use with borders in a border or border projection file. */ GuiBorderAttributesDialog::GuiBorderAttributesDialog(QWidget* parent, const QString fileNameIn, const BORDER_FILE_TYPE borderFileTypeIn, const bool showTopographyUncertaintyFlagIn) : WuQDialog(parent) { setModal(true); showTopographyUncertaintyFlag = showTopographyUncertaintyFlagIn; borderFileType = borderFileTypeIn; fileName = fileNameIn; switch (borderFileType) { case BORDER_FILE_TYPE_BORDER: { try { borderFile.readFile(fileName); const int numBorders = borderFile.getNumberOfBorders(); for (int i = 0; i < numBorders; i++) { Border* b = borderFile.getBorder(i); BorderAttributes ba(b->getName(), i, b->getNumberOfLinks(), b->getSamplingDensity(), b->getVariance(), b->getTopographyValue(), b->getArealUncertainty()); attributes.push_back(ba); } } catch (FileException& e) { } } break; case BORDER_FILE_TYPE_BORDER_PROJECTION: try { borderProjectionFile.readFile(fileName); const int numBorders = borderProjectionFile.getNumberOfBorderProjections(); for (int i = 0; i < numBorders; i++) { BorderProjection* b = borderProjectionFile.getBorderProjection(i); QString name; float center[3]; float samplingDensity; float variance; float topography; float arealUncertainty; b->getData(name, center, samplingDensity, variance, topography, arealUncertainty); BorderAttributes ba(name, i, b->getNumberOfLinks(), samplingDensity, variance, topography, arealUncertainty); attributes.push_back(ba); } } catch (FileException& e) { std::cout << "ERROR: " << e.whatQString().toAscii().constData() << std::endl; return; } break; case BORDER_FILE_TYPE_BORDER_SET: break; } createDialog(); } /** * create the dialog. */ void GuiBorderAttributesDialog::createDialog() { std::sort(attributes.begin(), attributes.end()); setWindowTitle("Edit Border Attributes"); // // Layout for dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(5); // // Grid columns // const int numAttributes = static_cast(attributes.size()); int numColumns = 0; const int RETAIN_COLUMN = numColumns++; const int NAME_COLUMN = numColumns++; const int INDEX_COLUMN = numColumns++; const int LINKS_COLUMN = numColumns++; const int SAMPLING_COLUMN = numColumns++; const int VARIANCE_COLUMN = numColumns++; const int TOPOGRAPHY_COLUMN = numColumns++; const int UNCERTAINTY_COLUMN = numColumns++; int rowNumber = 0; // // widget and layout in the scrollview // QWidget* svWidget = new QWidget; QGridLayout* gridLayout = new QGridLayout(svWidget); gridLayout->setMargin(3); gridLayout->setSpacing(3); // // column titles // gridLayout->addWidget(new QLabel("Keep"), rowNumber, RETAIN_COLUMN, Qt::AlignLeft); gridLayout->addWidget(new QLabel("Name"), rowNumber, NAME_COLUMN);//, Qt::AlignLeft); gridLayout->addWidget(new QLabel("File\nIndex"), rowNumber, INDEX_COLUMN, Qt::AlignLeft); gridLayout->addWidget(new QLabel("Number Of\nLinks"), rowNumber, LINKS_COLUMN, Qt::AlignLeft); gridLayout->addWidget(new QLabel("Sampling"), rowNumber, SAMPLING_COLUMN, Qt::AlignLeft); gridLayout->addWidget(new QLabel("Variance"), rowNumber, VARIANCE_COLUMN, Qt::AlignLeft); if (showTopographyUncertaintyFlag) { gridLayout->addWidget(new QLabel("Topography"), rowNumber, TOPOGRAPHY_COLUMN, Qt::AlignLeft); gridLayout->addWidget(new QLabel("Uncertainty"), rowNumber, UNCERTAINTY_COLUMN, Qt::AlignLeft); } rowNumber++; gridLayout->setColumnStretch(RETAIN_COLUMN, 0); gridLayout->setColumnStretch(NAME_COLUMN, 1000); gridLayout->setColumnStretch(INDEX_COLUMN, 0); gridLayout->setColumnStretch(LINKS_COLUMN, 0); gridLayout->setColumnStretch(SAMPLING_COLUMN, 0); gridLayout->setColumnStretch(VARIANCE_COLUMN, 0); if (showTopographyUncertaintyFlag) { gridLayout->setColumnStretch(TOPOGRAPHY_COLUMN, 0); gridLayout->setColumnStretch(UNCERTAINTY_COLUMN, 0); } const int lineEditNumberWidth = 60; // // Border data // for (int i = 0; i < numAttributes; i++) { // // Retain checkbox // QCheckBox* checkBox = new QCheckBox(""); checkBox->setChecked(true); gridLayout->addWidget(checkBox, rowNumber, RETAIN_COLUMN, Qt::AlignLeft); retainCheckBoxes.push_back(checkBox); // // Name line edit // QLineEdit* nameLE = new QLineEdit; nameLE->setText(attributes[i].name); nameLE->setMinimumWidth(200); gridLayout->addWidget(nameLE, rowNumber, NAME_COLUMN); //, Qt::AlignLeft); nameLineEdits.push_back(nameLE); // // Index label // QLabel* indexLabel = new QLabel(QString::number(attributes[i].fileIndex)); gridLayout->addWidget(indexLabel, rowNumber, INDEX_COLUMN, Qt::AlignLeft); // // Number of Links // QLabel* linksLabel = new QLabel(QString::number(attributes[i].numberOfLinks)); gridLayout->addWidget(linksLabel, rowNumber, LINKS_COLUMN, Qt::AlignLeft); // // Sampling line edit // QLineEdit* samplingLE = new QLineEdit; samplingLE->setMaximumWidth(lineEditNumberWidth); samplingLE->setText(QString::number(attributes[i].sampling, 'f', 2)); gridLayout->addWidget(samplingLE, rowNumber, SAMPLING_COLUMN, Qt::AlignLeft); samplingLineEdits.push_back(samplingLE); // // Variance line edit // QLineEdit* varianceLE = new QLineEdit; varianceLE->setMaximumWidth(lineEditNumberWidth); varianceLE->setText(QString::number(attributes[i].variance, 'f', 2)); gridLayout->addWidget(varianceLE, rowNumber, VARIANCE_COLUMN, Qt::AlignLeft); varianceLineEdits.push_back(varianceLE); if (showTopographyUncertaintyFlag) { // // Topography line edit // QLineEdit* topographyLE = new QLineEdit; topographyLE->setMaximumWidth(lineEditNumberWidth); topographyLE->setText(QString::number(attributes[i].topography, 'f', 2)); gridLayout->addWidget(topographyLE, rowNumber, TOPOGRAPHY_COLUMN, Qt::AlignLeft); topographyLineEdits.push_back(topographyLE); // // Uncertainty line edit // QLineEdit* uncertaintyLE = new QLineEdit; uncertaintyLE->setMaximumWidth(lineEditNumberWidth); uncertaintyLE->setText(QString::number(attributes[i].uncertainty, 'f', 2)); gridLayout->addWidget(uncertaintyLE, rowNumber, UNCERTAINTY_COLUMN, Qt::AlignLeft); uncertaintyLineEdits.push_back(uncertaintyLE); } rowNumber++; } // // Scroll View for all selections // QScrollArea* sv = new QScrollArea(this); sv->setWidget(svWidget); sv->setWidgetResizable(true); dialogLayout->addWidget(sv); // // Set the minimum size for the scroll area // /* int minWidth = svWidget->sizeHint().width() + 10; if (minWidth > 600) minWidth = 600; sv->setMinimumWidth(minWidth); int minHeight = svWidget->sizeHint().height(); if (minHeight > 200) minHeight = 200; sv->setMinimumHeight(minHeight); */ // // Buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(5); dialogLayout->addLayout(buttonsLayout); QPushButton* okButton = new QPushButton("OK"); QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); buttonsLayout->addWidget(okButton); QPushButton* cancelButton = new QPushButton("Cancel"); QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); buttonsLayout->addWidget(cancelButton); QtUtilities::makeButtonsSameSize(okButton, cancelButton); } /** * Destructor. */ GuiBorderAttributesDialog::~GuiBorderAttributesDialog() { } /** * process the border file. */ void GuiBorderAttributesDialog::processBorderFile() { const int numAtt = static_cast(attributes.size()); const int numBorders = borderFile.getNumberOfBorders(); std::vector deleteBorderFlag(numBorders, false); for (int i = 0; i < numAtt; i++) { const int borderIndex = attributes[i].fileIndex; if (retainCheckBoxes[i]->isChecked()) { deleteBorderFlag[borderIndex] = false; QString name; float center[3]; float samplingDensity; float variance; float topography; float arealUncertainty; Border* b = borderFile.getBorder(borderIndex); b->getData(name, center, samplingDensity, variance, topography, arealUncertainty); name = nameLineEdits[i]->text(); samplingDensity = samplingLineEdits[i]->text().toFloat(); variance = varianceLineEdits[i]->text().toFloat(); if (showTopographyUncertaintyFlag) { topography = topographyLineEdits[i]->text().toFloat(); arealUncertainty = uncertaintyLineEdits[i]->text().toFloat(); } b->setData(name, center, samplingDensity, variance, topography, arealUncertainty); } else { deleteBorderFlag[borderIndex] = true; } } for (int i = (numBorders - 1); i >= 0; i--) { if (deleteBorderFlag[i]) { borderFile.removeBorder(i); } } try { borderFile.writeFile(fileName); } catch (FileException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); } } /** * process the border projection file. */ void GuiBorderAttributesDialog::processBorderProjectionFile() { const int numAtt = static_cast(attributes.size()); const int numBorders = borderProjectionFile.getNumberOfBorderProjections(); std::vector deleteBorderFlag(numBorders, false); for (int i = 0; i < numAtt; i++) { const int borderIndex = attributes[i].fileIndex; if (retainCheckBoxes[i]->isChecked()) { deleteBorderFlag[borderIndex] = false; QString name; float center[3]; float samplingDensity; float variance; float topography; float arealUncertainty; BorderProjection* b = borderProjectionFile.getBorderProjection(borderIndex); b->getData(name, center, samplingDensity, variance, topography, arealUncertainty); name = nameLineEdits[i]->text(); samplingDensity = samplingLineEdits[i]->text().toFloat(); variance = varianceLineEdits[i]->text().toFloat(); if (showTopographyUncertaintyFlag) { topography = topographyLineEdits[i]->text().toFloat(); arealUncertainty = uncertaintyLineEdits[i]->text().toFloat(); } b->setData(name, center, samplingDensity, variance, topography, arealUncertainty); } else { deleteBorderFlag[borderIndex] = true; } } for (int i = (numBorders - 1); i >= 0; i--) { if (deleteBorderFlag[i]) { borderProjectionFile.removeBorderProjection(i); } } try { borderProjectionFile.writeFile(fileName); } catch (FileException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); } } /** * process the brain model border set borders. */ void GuiBorderAttributesDialog::processBrainModelBorderSetBorders() { BrainModelBorderSet* bmbs = theMainWindow->getBrainSet()->getBorderSet(); const int numAtt = static_cast(attributes.size()); const int numBorders = bmbs->getNumberOfBorders(); std::vector deleteBorderFlag(numBorders, false); for (int i = 0; i < numAtt; i++) { const int borderIndex = attributes[i].fileIndex; if (retainCheckBoxes[i]->isChecked()) { deleteBorderFlag[borderIndex] = false; BrainModelBorder* b = bmbs->getBorder(borderIndex); b->setName(nameLineEdits[i]->text()); b->setSamplingDensity(samplingLineEdits[i]->text().toFloat()); b->setVariance(varianceLineEdits[i]->text().toFloat()); if (showTopographyUncertaintyFlag) { b->setTopography(topographyLineEdits[i]->text().toFloat()); b->setArealUncertainty(uncertaintyLineEdits[i]->text().toFloat()); } } else { deleteBorderFlag[borderIndex] = true; } } for (int i = (numBorders - 1); i >= 0; i--) { if (deleteBorderFlag[i]) { bmbs->deleteBorder(i); } } GuiFilesModified fm; fm.setBorderModified(); theMainWindow->fileModificationUpdate(fm); GuiBrainModelOpenGL::updateAllGL(NULL); } /** * Apply button slot. */ void GuiBorderAttributesDialog::done(int r) { if (r == GuiBorderAttributesDialog::Accepted) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); switch (borderFileType) { case BORDER_FILE_TYPE_BORDER: processBorderFile(); break; case BORDER_FILE_TYPE_BORDER_PROJECTION: processBorderProjectionFile(); break; case BORDER_FILE_TYPE_BORDER_SET: processBrainModelBorderSetBorders(); break; } QApplication::restoreOverrideCursor(); } WuQDialog::done(r); } caret-5.6.4~dfsg.1.orig/caret/GuiBatchCommandDialog.h0000664000175000017500000000362411572067322022142 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_BATCH_COMMAND_DIALOG_H__ #define __GUI_BATCH_COMMAND_DIALOG_H__ #include "WuQDialog.h" class QLineEdit; /// Dialog for running batch commands class GuiBatchCommandDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiBatchCommandDialog(QWidget* parent, const QString& directoryToRunIn, const QString& commandIn, const QString& commandFileNameIn = ""); /// Destructor ~GuiBatchCommandDialog(); protected slots: /// called to select command file name void slotCommandFilePushButton(); protected: /// Called when OK or Cancel button pressed void done(int r); /// directory in which command should be run QString directory; /// command that is to be run QString command; /// command file name line edit QLineEdit* commandFileNameLineEdit; }; #endif // __GUI_BATCH_COMMAND_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiBatchCommandDialog.cxx0000664000175000017500000001625111572067322022515 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #ifndef Q_OS_WIN32 #include #include #endif // ifndef Q_OS_WIN32 #include #include #include #include #include #include #include #include #include #include #include "DateAndTime.h" #include "DebugControl.h" #include "GuiBatchCommandDialog.h" #include "QtUtilities.h" #include "WuQFileDialog.h" /** * Constructor. */ GuiBatchCommandDialog::GuiBatchCommandDialog(QWidget* parent, const QString& directoryToRunIn, const QString& commandIn, const QString& commandFileNameIn) : WuQDialog(parent) { setWindowTitle("Caret Batch Command"); // // Directory in which to run command file // directory = directoryToRunIn; command = commandIn; // // Command file name // QString commandFileName(commandFileNameIn); if (commandFileName.isEmpty()) { commandFileName = "caret_command"; } #ifdef Q_OS_WIN32 commandFileName.append(".bat"); #else commandFileName.append(".sh"); #endif // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // Command File Name // QGroupBox* commandFileGroupBox = new QGroupBox("Command File Name"); dialogLayout->addWidget(commandFileGroupBox); QHBoxLayout* commandFileGroupLayout = new QHBoxLayout(commandFileGroupBox); QPushButton* commandFilePushButton = new QPushButton("Select..."); commandFileGroupLayout->addWidget(commandFilePushButton); commandFilePushButton->setAutoDefault(false); commandFilePushButton->setFixedSize(commandFilePushButton->sizeHint()); QObject::connect(commandFilePushButton, SIGNAL(clicked()), this, SLOT(slotCommandFilePushButton())); commandFileNameLineEdit = new QLineEdit; commandFileGroupLayout->addWidget(commandFileNameLineEdit); commandFileNameLineEdit->setMinimumWidth(300); commandFileNameLineEdit->setText(commandFileName); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); dialogLayout->addLayout(buttonsLayout); // // OK button // QPushButton* okButton = new QPushButton("OK"); okButton->setAutoDefault(false); buttonsLayout->addWidget(okButton); QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); // // Cancel button // QPushButton* cancelButton = new QPushButton("Cancel"); cancelButton->setAutoDefault(false); buttonsLayout->addWidget(cancelButton); QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); QtUtilities::makeButtonsSameSize(okButton, cancelButton); } /** * Destructor. */ GuiBatchCommandDialog::~GuiBatchCommandDialog() { } /** * Called to select the command file name. */ void GuiBatchCommandDialog::slotCommandFilePushButton() { // // Create a file dialog to select the command file. // WuQFileDialog commandFileNameDialog(this); commandFileNameDialog.setModal(true); commandFileNameDialog.setWindowTitle("Choose Command File"); commandFileNameDialog.setFileMode(WuQFileDialog::AnyFile); #ifdef Q_OS_WIN32 const QString filter("Command File (*.bat)"); #else const QString filter("Command File (*.sh)"); #endif commandFileNameDialog.setFilter(filter); if (commandFileNameDialog.exec() == QDialog::Accepted) { commandFileNameLineEdit->setText(commandFileNameDialog.selectedFiles().at(0)); } } /** * Called when OK or Cancel button pressed. */ void GuiBatchCommandDialog::done(int r) { if (r == QDialog::Accepted) { if (DebugControl::getDebugOn()) { std::cout << std::endl << command.toAscii().constData() << std::endl; } // // Make sure command exists // if (command.isEmpty()) { QMessageBox::critical(this, "Error", "PROGRAM ERROR: command is empty."); return; } // // See if command file exists and, if so, warn user // const QString commandFileName(commandFileNameLineEdit->text()); if (QFile::exists(commandFileName)) { QString msg("Command file "); msg.append(commandFileName); msg.append(" exits. Overwrite it?"); if (QMessageBox::warning(this, "Warning", msg, (QMessageBox::Yes | QMessageBox::No), QMessageBox::No) == QMessageBox::No) { return; } } // // Open up the command file // QFile file(commandFileName); if (file.open(QIODevice::WriteOnly)) { QTextStream stream(&file); stream.setRealNumberNotation(QTextStream::FixedNotation); stream.setRealNumberPrecision(6); #ifdef Q_OS_WIN32 stream << "REM Created at " << DateAndTime::getDateAndTimeAsString() << "\n"; stream << "\n"; #else stream << "#!/bin/sh \n"; stream << "# Created at " << DateAndTime::getDateAndTimeAsString() << "\n"; stream << "\n"; #endif if (directory.isEmpty() == false) { stream << "cd " << directory << "\n"; } stream << "\n"; stream << command; stream << "\n"; file.close(); #ifndef Q_OS_WIN32 // // Make command file executable and readable by all // Writable by user // chmod(commandFileName.toAscii().constData(), S_IRUSR + S_IWUSR + S_IXUSR + S_IRGRP + S_IXGRP + S_IROTH + S_IXOTH); #endif // #ifndef Q_OS_WIN32 } else { QString msg("Unable to open for writing: "); QFileInfo fileInfo(commandFileName); if (fileInfo.exists() && (fileInfo.isWritable() == false)) { msg = "File exists and is not writable: "; } msg.append(commandFileName); QMessageBox::critical(this, "Error", msg); return; } } QDialog::done(r); } caret-5.6.4~dfsg.1.orig/caret/GuiAverageCoordinateDialog.h0000664000175000017500000000455211572067322023205 0ustar michaelmichael#ifndef __GUI_AVERAGE_COORDINATE_DIALOG_H__ #define __GUI_AVERAGE_COORDINATE_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "WuQDialog.h" class QCheckBox; class QLineEdit; class QListWidget; /// class for creating average coordinate files class GuiAverageCoordinateDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiAverageCoordinateDialog(QWidget* parent); /// Destructor ~GuiAverageCoordinateDialog(); protected slots: /// called when apply button is pressed void slotApplyButton(); /// called when add button is pressed void slotAddButton(); /// called when remove button is pressed void slotRemoveButton(); /// called to select output coordinate file name void slotOutputCoordinateButton(); protected: /// Load the coordinate file list box void loadCoordinateFileListBox(); /// list box of input coordinate files QListWidget* inputListWidget; /// the name of the coordinate files std::vector coordinateFileNames; /// output coordinate file name line edit QLineEdit* outputCoordinateFileLineEdit; /// create shape check box QCheckBox* createShapeCheckBox; /// create shape file name QLineEdit* shapeFileNameLineEdit; /// create shape column name QLineEdit* shapeColumnNameLineEdit; }; #endif // __GUI_AVERAGE_COORDINATE_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiAverageCoordinateDialog.cxx0000664000175000017500000003143411572067322023557 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include "CoordinateFile.h" #include "FileFilters.h" #include "FileUtilities.h" #include "GuiAverageCoordinateDialog.h" #include "GuiFileDialogWithInstructions.h" #include "QtUtilities.h" #include "SpecFile.h" #include "StringUtilities.h" #include "SurfaceShapeFile.h" #include "WuQFileDialog.h" /** * Constructor. */ GuiAverageCoordinateDialog::GuiAverageCoordinateDialog(QWidget* parent) : WuQDialog(parent) { setWindowTitle("Average Coordinates"); const int lineEditWidth = 400; // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // Group box for input coordinate files // QGroupBox* inputGroupBox = new QGroupBox("Input Coordinate Files"); dialogLayout->addWidget(inputGroupBox); QVBoxLayout* inputGroupLayout = new QVBoxLayout(inputGroupBox); // // list box for input coordinate files // inputListWidget = new QListWidget; inputGroupLayout->addWidget(inputListWidget); inputListWidget->setSelectionMode(QListWidget::ExtendedSelection); // // Buttons for adding/removing coordinate files // QHBoxLayout* inputButtonBoxLayout = new QHBoxLayout; inputGroupLayout->addLayout(inputButtonBoxLayout); // // Add coordinate files button // QPushButton* addButton = new QPushButton("Add..."); inputButtonBoxLayout->addWidget(addButton); addButton->setAutoDefault(false); QObject::connect(addButton, SIGNAL(clicked()), this, SLOT(slotAddButton())); // // Remove coordinate files button // QPushButton* removeButton = new QPushButton("Remove..."); inputButtonBoxLayout->addWidget(removeButton); removeButton->setAutoDefault(false); QObject::connect(removeButton, SIGNAL(clicked()), this, SLOT(slotRemoveButton())); // // Make Add/Remove buttons the same size // QtUtilities::makeButtonsSameSize(addButton, removeButton); // // Group box for output coordinate file // QGroupBox* outputGroupBox = new QGroupBox("Output Coordinate File"); dialogLayout->addWidget(outputGroupBox); QHBoxLayout* outputGroupLayout = new QHBoxLayout(outputGroupBox); // // Button to select output coordinate file // QPushButton* outputCoordinateButton = new QPushButton("Select..."); outputGroupLayout->addWidget(outputCoordinateButton); outputCoordinateButton->setAutoDefault(false); outputCoordinateButton->setFixedSize(outputCoordinateButton->sizeHint()); QObject::connect(outputCoordinateButton, SIGNAL(clicked()), this, SLOT(slotOutputCoordinateButton())); // // Line edit for output coordinate file name // outputCoordinateFileLineEdit = new QLineEdit; outputGroupLayout->addWidget(outputCoordinateFileLineEdit); outputCoordinateFileLineEdit->setMinimumWidth(lineEditWidth); outputCoordinateFileLineEdit->setText("average.coord"); // // Group box for surface shape file // QGroupBox* shapeGroupBox = new QGroupBox("Surface Shape"); dialogLayout->addWidget(shapeGroupBox); QVBoxLayout* shapeGroupLayout = new QVBoxLayout(shapeGroupBox); // // Enable shape check box // createShapeCheckBox = new QCheckBox("Create Sample Standard Deviation"); shapeGroupLayout->addWidget(createShapeCheckBox); createShapeCheckBox->setChecked(true); // // Grid for file and column name // QWidget* shapeGridWidget = new QWidget; shapeGroupLayout->addWidget(shapeGridWidget); QGridLayout* shapeGridLayout = new QGridLayout(shapeGridWidget); shapeGridLayout->setSpacing(5); // // file name label and line edit // shapeGridLayout->addWidget(new QLabel("File Name "), 0, 0); shapeFileNameLineEdit = new QLineEdit; shapeFileNameLineEdit->setText("avg_coord_uncertainty.surface_shape"); shapeFileNameLineEdit->setMinimumWidth(lineEditWidth); shapeGridLayout->addWidget(shapeFileNameLineEdit, 0, 1); // // column name label and line edit // shapeGridLayout->addWidget(new QLabel("Column Name "), 1, 0); shapeColumnNameLineEdit = new QLineEdit; shapeColumnNameLineEdit->setText("SHAPE_STANDARD_UNCERTAINTY"); shapeColumnNameLineEdit->setMinimumWidth(lineEditWidth); shapeGridLayout->addWidget(shapeColumnNameLineEdit, 1, 1); // // Enable shape grid when checkbox is enabled // QObject::connect(createShapeCheckBox, SIGNAL(toggled(bool)), shapeGridWidget, SLOT(setEnabled(bool))); shapeGridWidget->setEnabled(createShapeCheckBox->isChecked()); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; dialogLayout->addLayout(buttonsLayout); buttonsLayout->setSpacing(2); // // Apply button // QPushButton* applyButton = new QPushButton("Apply"); applyButton->setAutoDefault(false); buttonsLayout->addWidget(applyButton); QObject::connect(applyButton, SIGNAL(clicked()), this, SLOT(slotApplyButton())); // // Close button connects to QDialogs close() slot. // QPushButton* closeButton = new QPushButton("Close"); closeButton->setAutoDefault(false); buttonsLayout->addWidget(closeButton); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); QtUtilities::makeButtonsSameSize(applyButton, closeButton); } /** * Destructor. */ GuiAverageCoordinateDialog::~GuiAverageCoordinateDialog() { } /** * called to select output coordinate file name. */ void GuiAverageCoordinateDialog::slotOutputCoordinateButton() { WuQFileDialog outputCoordinateFileDialog(this); outputCoordinateFileDialog.setDirectory(QDir::currentPath()); outputCoordinateFileDialog.setModal(true); outputCoordinateFileDialog.setWindowTitle("Choose Coordinate File"); outputCoordinateFileDialog.setFileMode(WuQFileDialog::AnyFile); outputCoordinateFileDialog.setFilter(FileFilters::getCoordinateGenericFileFilter()); if (outputCoordinateFileDialog.exec() == QDialog::Accepted) { outputCoordinateFileLineEdit->setText(outputCoordinateFileDialog.selectedFiles().at(0)); } } /** * called when add button is pressed. */ void GuiAverageCoordinateDialog::slotAddButton() { QString instructions = "To select multiple coordinate files, hold down the CTRL key while selecting " "coordinate file names with the mouse (Macintosh users should hold down " "the Apple key)."; GuiFileDialogWithInstructions openCoordinateFileDialog(this, instructions, "chooseCoordinateFile", true); openCoordinateFileDialog.setWindowTitle("Choose Coordinate File"); openCoordinateFileDialog.setFileMode(GuiFileDialogWithInstructions::ExistingFiles); openCoordinateFileDialog.setFilters(QStringList(FileFilters::getCoordinateGenericFileFilter())); openCoordinateFileDialog.selectFilter(FileFilters::getCoordinateGenericFileFilter()); if (openCoordinateFileDialog.exec() == QDialog::Accepted) { QStringList list = openCoordinateFileDialog.selectedFiles(); QStringList::Iterator it = list.begin(); while( it != list.end() ) { QString filename((*it)); coordinateFileNames.push_back(filename); ++it; } } loadCoordinateFileListBox(); } /** * Load the coordinate file list box */ void GuiAverageCoordinateDialog::loadCoordinateFileListBox() { inputListWidget->clear(); for (int i = 0; i < static_cast(coordinateFileNames.size()); i++) { inputListWidget->addItem(FileUtilities::basename(coordinateFileNames[i])); } } /** * called when remove button is pressed. */ void GuiAverageCoordinateDialog::slotRemoveButton() { for (int i = static_cast(coordinateFileNames.size()) - 1; i >= 0; i--) { const QListWidgetItem* item = inputListWidget->item(i); if (item != NULL) { if (inputListWidget->isItemSelected(item)) { coordinateFileNames.erase(coordinateFileNames.begin() + i); } } } loadCoordinateFileListBox(); } /** * called when apply button is pressed. */ void GuiAverageCoordinateDialog::slotApplyButton() { // // Verify valid data entered // if (coordinateFileNames.empty()) { QMessageBox::critical(this, "ERROR", "No input coordinate file are selected."); return; } QString outputFileName(outputCoordinateFileLineEdit->text()); if (outputFileName.length() <= 0) { QMessageBox::critical(this, "ERROR", "No output coordinate file specified."); return; } // // The surface shape file // SurfaceShapeFile* ssf = NULL; const QString shapeFileName(shapeFileNameLineEdit->text()); const QString shapeColumnName(shapeColumnNameLineEdit->text()); if (createShapeCheckBox->isChecked()) { if (shapeFileName.isEmpty()) { QMessageBox::critical(this, "ERROR", "No surface shape file specified."); return; } if (shapeColumnName.isEmpty()) { QMessageBox::critical(this, "ERROR", "No surface shape column name specified."); return; } ssf = new SurfaceShapeFile; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); // // Read the coordinate files // std::vector coordinateFiles; for (int i = 0; i < static_cast(coordinateFileNames.size()); i++) { CoordinateFile* c = new CoordinateFile; try { c->readFile(coordinateFileNames[i]); coordinateFiles.push_back(c); } catch (FileException& e) { for (int i = 0; i < static_cast(coordinateFiles.size()); i++) { delete coordinateFiles[i]; } QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "File Read Error", e.whatQString()); return; } } // // Create the average coordinate file // CoordinateFile averageCoordinateFile; try { CoordinateFile::createAverageCoordinateFile(coordinateFiles, averageCoordinateFile, ssf); } catch (FileException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); return; } // // Write the coordinate file // try { // // Add the file extension, if needed // const QString ext(SpecFile::getCoordinateFileExtension()); if (StringUtilities::endsWith(outputFileName, ext) == false) { outputFileName.append(ext); } averageCoordinateFile.writeFile(outputFileName); } catch (FileException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); if (ssf != NULL) { delete ssf; ssf = NULL; } return; } // // Write the surface shape file // if (ssf != NULL) { const int column = ssf->getNumberOfColumns() - 1; if (column >= 0) { ssf->setColumnName(column, shapeColumnName); } try { ssf->writeFile(shapeFileName); } catch (FileException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", e.whatQString()); return; } delete ssf; ssf = NULL; } // // Free memory // for (int i = 0; i < static_cast(coordinateFiles.size()); i++) { delete coordinateFiles[i]; } QApplication::restoreOverrideCursor(); // // Let the user know the file was created. // QMessageBox::information(this, "Success", "Average Coordinate File Created"); } caret-5.6.4~dfsg.1.orig/caret/GuiAverageBorderDialog.h0000664000175000017500000000435311572067322022332 0ustar michaelmichael#ifndef __GUI_AVERAGE_BORDER_DIALOG_H__ #define __GUI_AVERAGE_BORDER_DIALOG_H__ /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include "WuQDialog.h" class QCheckBox; class QLineEdit; class QListWidget; class QDoubleSpinBox; /// class for creating average border files class GuiAverageBorderDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiAverageBorderDialog(QWidget* parent); /// Destructor ~GuiAverageBorderDialog(); protected slots: /// called when apply button is pressed void slotApplyButton(); /// called when add button is pressed void slotAddButton(); /// called when remove button is pressed void slotRemoveButton(); /// called to select output border file name void slotOutputBorderButton(); protected: /// Load the border file list box void loadBorderFileListBox(); /// list box of input border files QListWidget* inputListWidget; /// resampling float spin box QDoubleSpinBox* resamplingDoubleSpinBox; /// the name of the border files std::vector borderFileNames; /// output border file name line edit QLineEdit* outputBorderFileLineEdit; /// sphere check box QCheckBox* sphereCheckBox; }; #endif // __GUI_AVERAGE_BORDER_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiAverageBorderDialog.cxx0000664000175000017500000002435711572067322022713 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include "BorderFile.h" #include "FileFilters.h" #include "FileUtilities.h" #include "GuiAverageBorderDialog.h" #include "GuiFileDialogWithInstructions.h" #include "QtUtilities.h" #include "WuQFileDialog.h" #include "StringUtilities.h" /** * Constructor. */ GuiAverageBorderDialog::GuiAverageBorderDialog(QWidget* parent) : WuQDialog(parent) { setWindowTitle("Average Borders"); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // Group box for input border files // QGroupBox* inputGroupBox = new QGroupBox("Input Border Files"); dialogLayout->addWidget(inputGroupBox); QVBoxLayout* inputGroupLayout = new QVBoxLayout(inputGroupBox); // // list box for input border files // inputListWidget = new QListWidget; inputListWidget->setSelectionMode(QListWidget::ExtendedSelection); inputGroupLayout->addWidget(inputListWidget); // // Buttons for adding/removing border files // QHBoxLayout* inputButtonBoxLayout = new QHBoxLayout; inputGroupLayout->addLayout(inputButtonBoxLayout); // // Add border files button // QPushButton* addButton = new QPushButton("Add..."); inputButtonBoxLayout->addWidget(addButton); addButton->setAutoDefault(false); QObject::connect(addButton, SIGNAL(clicked()), this, SLOT(slotAddButton())); // // Remove border files button // QPushButton* removeButton = new QPushButton("Remove..."); inputButtonBoxLayout->addWidget(removeButton); removeButton->setAutoDefault(false); QObject::connect(removeButton, SIGNAL(clicked()), this, SLOT(slotRemoveButton())); // // Make Add/Remove buttons the same size // QtUtilities::makeButtonsSameSize(addButton, removeButton); // // Group box for output border file // QGroupBox* outputGroupBox = new QGroupBox("Output Border File"); dialogLayout->addWidget(outputGroupBox); QHBoxLayout* outputGroupLayout = new QHBoxLayout(outputGroupBox); // // Button to select output border file // QPushButton* outputBorderButton = new QPushButton("Select..."); outputGroupLayout->addWidget(outputBorderButton); outputBorderButton->setAutoDefault(false); outputBorderButton->setFixedSize(outputBorderButton->sizeHint()); QObject::connect(outputBorderButton, SIGNAL(clicked()), this, SLOT(slotOutputBorderButton())); // // Line edit for output border file name // outputBorderFileLineEdit = new QLineEdit; outputGroupLayout->addWidget(outputBorderFileLineEdit); outputBorderFileLineEdit->setMinimumWidth(200); // // Group box for resampling // QGroupBox* resampleGroupBox = new QGroupBox("Resampling"); dialogLayout->addWidget(resampleGroupBox); QVBoxLayout* resampleGroupLayout = new QVBoxLayout(resampleGroupBox); // // Resampling distance // QHBoxLayout* distHBoxLayout = new QHBoxLayout; resampleGroupLayout->addLayout(distHBoxLayout); distHBoxLayout->addWidget(new QLabel("Distance (mm) ")); resamplingDoubleSpinBox = new QDoubleSpinBox; resamplingDoubleSpinBox->setMinimum(0.0); resamplingDoubleSpinBox->setMaximum(100000.0); resamplingDoubleSpinBox->setSingleStep(1.0); resamplingDoubleSpinBox->setDecimals(2); resamplingDoubleSpinBox->setValue(10.0); distHBoxLayout->addWidget(resamplingDoubleSpinBox); // // Sphere check box // sphereCheckBox = new QCheckBox("Project to Sphere"); resampleGroupLayout->addWidget(sphereCheckBox); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; dialogLayout->addLayout(buttonsLayout); buttonsLayout->setSpacing(2); // // Apply button // QPushButton* applyButton = new QPushButton("Apply"); applyButton->setAutoDefault(false); buttonsLayout->addWidget(applyButton); QObject::connect(applyButton, SIGNAL(clicked()), this, SLOT(slotApplyButton())); // // Close button connects to QDialogs close() slot. // QPushButton* closeButton = new QPushButton("Close"); closeButton->setAutoDefault(false); buttonsLayout->addWidget(closeButton); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); QtUtilities::makeButtonsSameSize(applyButton, closeButton); } /** * Destructor. */ GuiAverageBorderDialog::~GuiAverageBorderDialog() { } /** * called to select output border file name. */ void GuiAverageBorderDialog::slotOutputBorderButton() { WuQFileDialog outputBorderFileDialog(this); outputBorderFileDialog.setModal(true); outputBorderFileDialog.setWindowTitle("Choose Border File"); outputBorderFileDialog.setFileMode(WuQFileDialog::AnyFile); outputBorderFileDialog.setFilter(FileFilters::getBorderGenericFileFilter()); if (outputBorderFileDialog.exec() == QDialog::Accepted) { outputBorderFileLineEdit->setText(outputBorderFileDialog.selectedFiles().at(0)); } } /** * called when add button is pressed. */ void GuiAverageBorderDialog::slotAddButton() { QString instructions = "To select multiple border files, hold down the CTRL key while selecting " "border file names with the mouse (Macintosh users should hold down " "the Apple key)."; GuiFileDialogWithInstructions openBorderFileDialog(this, instructions, "chooseBorderFile", true); openBorderFileDialog.setWindowTitle("Choose Border File"); openBorderFileDialog.setFileMode(GuiFileDialogWithInstructions::ExistingFiles); openBorderFileDialog.setFilters(QStringList(FileFilters::getBorderGenericFileFilter())); openBorderFileDialog.selectFilter(FileFilters::getBorderGenericFileFilter()); if (openBorderFileDialog.exec() == QDialog::Accepted) { QStringList list = openBorderFileDialog.selectedFiles(); QStringList::Iterator it = list.begin(); while( it != list.end() ) { QString filename((*it)); borderFileNames.push_back(filename); ++it; } } loadBorderFileListBox(); } /** * Load the border file list box */ void GuiAverageBorderDialog::loadBorderFileListBox() { inputListWidget->clear(); for (int i = 0; i < static_cast(borderFileNames.size()); i++) { inputListWidget->addItem(FileUtilities::basename(borderFileNames[i])); } } /** * called when remove button is pressed. */ void GuiAverageBorderDialog::slotRemoveButton() { for (int i = static_cast(borderFileNames.size()) - 1; i >= 0; i--) { const QListWidgetItem* item = inputListWidget->item(i); if (item != NULL) { if (inputListWidget->isItemSelected(item)) { borderFileNames.erase(borderFileNames.begin() + i); } } } loadBorderFileListBox(); } /** * called when apply button is pressed. */ void GuiAverageBorderDialog::slotApplyButton() { // // Verify valid data entered // if (borderFileNames.empty()) { QMessageBox::critical(this, "ERROR", "No input border file are selected."); return; } QString outputFileName(outputBorderFileLineEdit->text()); if (outputFileName.length() <= 0) { QMessageBox::critical(this, "ERROR", "No output border file specified."); return; } const float resampling = resamplingDoubleSpinBox->value(); if (resampling <= 0.0) { QMessageBox::critical(this, "ERROR", "Resampling must be greater than zero"); return; } // // Read the border files // std::vector borderFiles; for (int i = 0; i < static_cast(borderFileNames.size()); i++) { BorderFile* b = new BorderFile; try { b->readFile(borderFileNames[i]); borderFiles.push_back(b); } catch (FileException& e) { for (int i = 0; i < static_cast(borderFiles.size()); i++) { delete borderFiles[i]; } QMessageBox::critical(this, "File Read Error", e.whatQString()); return; } } // // // BorderFile averageBorderFile; try { BorderFile::createAverageBorderFile(borderFiles, resampling, sphereCheckBox->isChecked(), averageBorderFile); } catch (FileException& e) { QMessageBox::critical(this, "ERROR", e.whatQString()); return; } // // Write the border file // try { // // Add the file extension, if needed // const QString ext(".border"); if (StringUtilities::endsWith(outputFileName, ext) == false) { outputFileName.append(ext); } averageBorderFile.writeFile(outputFileName); } catch (FileException& e) { QMessageBox::critical(this, "ERROR", e.whatQString()); return; } // // Free memory // for (int i = 0; i < static_cast(borderFiles.size()); i++) { delete borderFiles[i]; } // // Let the user know the file was created. // QMessageBox::information(this, "Success", "Average Border File Created"); } caret-5.6.4~dfsg.1.orig/caret/GuiAutomaticRotationDialog.h0000664000175000017500000000465111572067322023271 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_GUI_AUTOMATIC_ROTATION_DIALOG_H__ #define __VE_GUI_AUTOMATIC_ROTATION_DIALOG_H__ #include "WuQDialog.h" class QPushButton; class QRadioButton; class QDoubleSpinBox; /// Dialog for automatic rotation class GuiAutomaticRotationDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiAutomaticRotationDialog(QWidget* parent); /// Destructor ~GuiAutomaticRotationDialog(); private slots: /// called when an start button is pressed void startButtonSlot(); /// called when stop button is pressed void stopButtonSlot(); /// called when close button is pressed void closeButtonSlot(); private: /// X axis radio button QRadioButton* xAxisRadioButton; /// Y axis radio button QRadioButton* yAxisRadioButton; /// Z axis radio button QRadioButton* zAxisRadioButton; /// Total fixed rotation spin box QDoubleSpinBox* fixedRotationSpinBox; /// Rotation increment spin box QDoubleSpinBox* incrementRotationSpinBox; /// the start pushbutton QPushButton* startButton; /// the stop pushbutton QPushButton* stopButton; /// fixed total rotation radio button QRadioButton* fixedTotalRadioButton; /// continuous rotation radio button QRadioButton* continuousTotalRadioButton; /// continue rotating flag bool continueRotatingFlag; }; #endif // __VE_GUI_AUTOMATIC_ROTATION_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiAutomaticRotationDialog.cxx0000664000175000017500000002141411572067322023640 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include "GuiAutomaticRotationDialog.h" #include "GuiBrainModelOpenGL.h" #include "GuiMainWindow.h" #include "BrainModelSurface.h" #include #include "QtUtilities.h" #include "global_variables.h" #include "vtkTransform.h" /** * Constructor */ GuiAutomaticRotationDialog::GuiAutomaticRotationDialog(QWidget* parent) : WuQDialog(parent) { setWindowTitle("Automatic Rotation"); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // X, Y, and Z Axis Radio buttons // xAxisRadioButton = new QRadioButton("X Axis"); yAxisRadioButton = new QRadioButton("Y Axis"); zAxisRadioButton = new QRadioButton("Z Axis"); QGroupBox* axisGroupBox = new QGroupBox("Axis"); dialogLayout->addWidget(axisGroupBox); QVBoxLayout* axisGroupLayout = new QVBoxLayout(axisGroupBox); axisGroupLayout->addWidget(xAxisRadioButton); axisGroupLayout->addWidget(yAxisRadioButton); axisGroupLayout->addWidget(zAxisRadioButton); // // Button Group for axis selection // QButtonGroup* axisButtonGroup= new QButtonGroup(this); axisButtonGroup->addButton(xAxisRadioButton, 0); axisButtonGroup->addButton(yAxisRadioButton, 1); axisButtonGroup->addButton(zAxisRadioButton, 2); yAxisRadioButton->setChecked(true); // // Total Rotation Group Box // QGroupBox* totalGroupBox = new QGroupBox("Total Rotation"); QGridLayout* totalGroupLayout = new QGridLayout(totalGroupBox); dialogLayout->addWidget(totalGroupBox); // // Button group for radio buttons so mutually exclusive // QButtonGroup* buttGroup = new QButtonGroup(this); // // FixedTotal Rotation // fixedTotalRadioButton = new QRadioButton("Fixed (Degrees) "); totalGroupLayout->addWidget(fixedTotalRadioButton, 0, 0); buttGroup->addButton(fixedTotalRadioButton, 0); fixedRotationSpinBox = new QDoubleSpinBox; fixedRotationSpinBox->setMinimum(0.0); fixedRotationSpinBox->setMaximum(100000.0); fixedRotationSpinBox->setSingleStep(10.0); fixedRotationSpinBox->setDecimals(3); totalGroupLayout->addWidget(fixedRotationSpinBox, 0, 1); fixedRotationSpinBox->setValue(360); // // Continuous Rotation // continuousTotalRadioButton = new QRadioButton("Continuous "); totalGroupLayout->addWidget(continuousTotalRadioButton, 1, 0); buttGroup->addButton(continuousTotalRadioButton, 1); // // Default to fixed rotation // fixedTotalRadioButton->setChecked(true); // // Rotation Increment Group Box // QGroupBox* incrementGroupBox = new QGroupBox("Rotation Increment"); QGridLayout* incrementGridLayout = new QGridLayout(incrementGroupBox); dialogLayout->addWidget(incrementGroupBox); // // Rotation Increment // incrementGridLayout->addWidget(new QLabel("Increment (Degrees) "), 0, 0); incrementRotationSpinBox = new QDoubleSpinBox; incrementRotationSpinBox->setMinimum(-360.0); incrementRotationSpinBox->setMaximum(360.0); incrementRotationSpinBox->setSingleStep(1.0); incrementRotationSpinBox->setDecimals(3); incrementGridLayout->addWidget(incrementRotationSpinBox, 0, 1); incrementRotationSpinBox->setValue(5); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout1 = new QHBoxLayout; dialogLayout->addLayout(buttonsLayout1); buttonsLayout1->setSpacing(2); // // Start pushbutton // startButton = new QPushButton("Start"); startButton->setAutoDefault(false); buttonsLayout1->addWidget(startButton); QObject::connect(startButton, SIGNAL(clicked()), this, SLOT(startButtonSlot())); // // Stop pushbutton // stopButton = new QPushButton("Stop"); stopButton->setEnabled(false); stopButton->setAutoDefault(false); buttonsLayout1->addWidget(stopButton); QObject::connect(stopButton, SIGNAL(clicked()), this, SLOT(stopButtonSlot())); // // Force buttons to be same size // QtUtilities::makeButtonsSameSize(startButton, stopButton); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout2 = new QHBoxLayout; dialogLayout->addLayout(buttonsLayout2); buttonsLayout2->setSpacing(2); // // Close button connects to QDialogs close() slot. // QPushButton* closeButton = new QPushButton("Close"); closeButton->setAutoDefault(false); closeButton->setFixedSize(closeButton->sizeHint()); buttonsLayout2->addWidget(closeButton); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(closeButtonSlot())); } /** * Destructor */ GuiAutomaticRotationDialog::~GuiAutomaticRotationDialog() { } /** * Called when close button is pressed. */ void GuiAutomaticRotationDialog::closeButtonSlot() { stopButtonSlot(); close(); } /** * Called when stop button is pressed. */ void GuiAutomaticRotationDialog::stopButtonSlot() { continueRotatingFlag = false; } /** * Called when apply button is pressed. */ void GuiAutomaticRotationDialog::startButtonSlot() { continueRotatingFlag = true; stopButton->setEnabled(true); startButton->setEnabled(false); // // Get the total rotation and increment // const float totalRotation = fixedRotationSpinBox->value(); float rotationIncrement = incrementRotationSpinBox->value(); // // Get the rotation axis // char axis = 'x'; if (xAxisRadioButton->isChecked()) { axis = 'x'; } else if (yAxisRadioButton->isChecked()) { axis = 'y'; } else if (zAxisRadioButton->isChecked()) { axis = 'z'; } // // Get the surface in the caret main window // BrainModelSurface* mainWindowModelSurface = NULL; GuiBrainModelOpenGL* mainWindowBrainModelOpenGL = NULL; int mainWindowModelViewNumber = -1; if (GuiBrainModelOpenGL::getCaretMainWindowModelInfo(mainWindowModelSurface, mainWindowBrainModelOpenGL, mainWindowModelViewNumber)) { // // Rotate the surface until finished // const float posRotationIncrement = fabs(rotationIncrement); float rotationSum = 0.0; vtkTransform* matrix = mainWindowModelSurface->getRotationTransformMatrix(mainWindowModelViewNumber); GuiBrainModelOpenGL::updateAllGL(mainWindowBrainModelOpenGL); while (continueRotatingFlag) { if (fixedTotalRadioButton->isChecked()) { const float maxRotation = totalRotation - rotationSum; if (posRotationIncrement > maxRotation) { if (rotationIncrement < 0.0) { rotationIncrement = maxRotation; } else { rotationIncrement = maxRotation; } } } switch(axis) { case 'x': matrix->RotateX(rotationIncrement); break; case 'y': matrix->RotateY(rotationIncrement); break; case 'z': matrix->RotateZ(rotationIncrement); break; } qApp->processEvents(); GuiBrainModelOpenGL::updateAllGL(mainWindowBrainModelOpenGL); if (fixedTotalRadioButton->isChecked()) { rotationSum += posRotationIncrement; if (rotationSum > totalRotation) { continueRotatingFlag = false; } } } theMainWindow->speakText("Automatic rotation completed.", false); } stopButton->setEnabled(false); startButton->setEnabled(true); } caret-5.6.4~dfsg.1.orig/caret/GuiApplyDeformationMapDialog.h0000664000175000017500000001242311572067322023532 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_APPLY_DEFORMATION_MAP_DIALOG_H__ #define __GUI_APPLY_DEFORMATION_MAP_DIALOG_H__ #include #include "WuQDialog.h" #include "DeformationMapFile.h" class BrainSet; class DeformationMapFile; class QCheckBox; class QComboBox; class QLabel; class QLineEdit; class QPushButton; class QRadioButton; class QDoubleSpinBox; /// Class for dialog that applies a deformation map class GuiApplyDeformationMapDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiApplyDeformationMapDialog(QWidget* parent, Qt::WindowFlags = 0); /// Destructor ~GuiApplyDeformationMapDialog(); private slots: /// called when apply button is pressed void slotApplyButton(); /// called when deformation map button is pressed void slotDeformationMapButton(); /// called when file pushbutton is pressed void slotFileButton(); /// called when deformed file pushbutton is pressed void slotDeformedFileButton(); /// called when source directory pushbutton is pressed void slotSourceDirectoryButton(); /// called when target directory pushbutton is pressed void slotTargetDirectoryButton(); /// called when atlas topo file button is pressed void slotAtlasTopoFileButton(); /// called when iniv topo file button is pressed void slotIndivTopoFileButton(); /// called when deformed topo file button is pressed void slotDeformedTopoFileButton(); /// called when a file type is selected void slotFileTypeComboBox(int item); private: enum FILE_DIALOG_TYPE { FILE_DIALOG_ATLAS_TOPO_FILE, FILE_DIALOG_DATA_FILE, FILE_DIALOG_DEFORMED_FILE, FILE_DIALOG_INDIV_TOPO_FILE, FILE_DIALOG_DEFORMED_TOPO_FILE }; /// data file dialog for data file and deformed file void dataFileDialog(const FILE_DIALOG_TYPE fdt); /// set the deformed file name void setDeformedFileName(const FILE_DIALOG_TYPE fdt); /// read the spec files bool readBrains(QString& errorMessage); /// deformation map file name line edit QLineEdit* deformationMapFileLineEdit; /// deformed column name prefix line edit QLineEdit* deformedColumnNamePrefixLineEdit; /// date file name line edit QLineEdit* dataFileNameLineEdit; /// deformed file name line edit QLineEdit* deformedFileNameLineEdit; /// file type combo box QComboBox* fileTypeComboBox; /// the File push button QPushButton* filePushButton; /// the deformed file push button QPushButton* deformedFilePushButton; /// the source brain set needed for some deformations BrainSet* sourceBrainSet; /// the target brain set needed for some deformations BrainSet* targetBrainSet; /// the deformation map file DeformationMapFile deformationMapFile; /// source directory pushbutton QPushButton* sourceDirectoryPushButton; /// target directory pushbutton QPushButton* targetDirectoryPushButton; /// directory line edit; QLineEdit* sourceDirectoryLineEdit; /// directory line edit; QLineEdit* targetDirectoryLineEdit; /// atlas topo file push button QPushButton* atlasTopoFilePushButton; /// atlas topo file line edit QLineEdit* atlasTopoFileLineEdit; /// indiv topo file push button QPushButton* indivTopoFilePushButton; /// indiv topo file line edit QLineEdit* indivTopoFileLineEdit; /// deformed topo file push button QPushButton* deformedTopoFilePushButton; /// deformed topo file line edit QLineEdit* deformedTopoFileLineEdit; /// flat coord max edge length QDoubleSpinBox* flatCoordMaxEdgeLengthDoubleSpinBox; /// flat coord max edge length label QLabel* flatCoordMaxEdgeLengthLabel; /// metric nearest node radio button QRadioButton* metricNearestNodeRadioButton; /// metric average tile nodes radio button QRadioButton* metricAverageTileNodesRadioButton; /// smooth deformed coord files QCheckBox* smoothCoordsOneIterationCheckBox; }; #endif // __GUI_APPLY_DEFORMATION_MAP_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiApplyDeformationMapDialog.cxx0000664000175000017500000015121011572067322024103 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include "BrainModelSurfaceDeformDataFile.h" #include "BrainSet.h" #include "FileFilters.h" #include "FileUtilities.h" #include "GuiApplyDeformationMapDialog.h" #include "GuiMainWindow.h" #include "DeformationMapFile.h" #include #include "QtUtilities.h" #include "SpecFile.h" #include "StringUtilities.h" #include "WuQFileDialog.h" #include "global_variables.h" /** * Constructor */ GuiApplyDeformationMapDialog::GuiApplyDeformationMapDialog(QWidget* parent, Qt::WindowFlags f) : WuQDialog(parent, f) { // // initialize some variables // sourceBrainSet = NULL; targetBrainSet = NULL; const int lineEditWidth = 400; setWindowTitle("Apply Deformation Map"); // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // Create a group widget to hold all deformation map fileitems // QGroupBox* defMapGroupBox = new QGroupBox("Deformation Map File"); dialogLayout->addWidget(defMapGroupBox); QGridLayout* defMapGridLayout = new QGridLayout(defMapGroupBox); // // Deformation map push button and line edit // QPushButton* deformationMapPushButton = new QPushButton("Deformation Map File..."); defMapGridLayout->addWidget(deformationMapPushButton, 0, 0); deformationMapPushButton->setAutoDefault(false); QObject::connect(deformationMapPushButton, SIGNAL(clicked()), this, SLOT(slotDeformationMapButton())); deformationMapFileLineEdit = new QLineEdit; defMapGridLayout->addWidget(deformationMapFileLineEdit, 0, 1); deformationMapFileLineEdit->setMinimumWidth(lineEditWidth); deformationMapFileLineEdit->setReadOnly(true); const QString defMapName(theMainWindow->getBrainSet()->getDeformationMapFileName()); if (defMapName.isEmpty() == false) { deformationMapFileLineEdit->setText(defMapName); } // // Source directory // sourceDirectoryPushButton = new QPushButton("Individual Directory..."); defMapGridLayout->addWidget(sourceDirectoryPushButton, 1, 0); sourceDirectoryPushButton->setAutoDefault(false); sourceDirectoryPushButton->setEnabled(false); QObject::connect(sourceDirectoryPushButton, SIGNAL(clicked()), this, SLOT(slotSourceDirectoryButton())); sourceDirectoryLineEdit = new QLineEdit; defMapGridLayout->addWidget(sourceDirectoryLineEdit, 1, 1); sourceDirectoryLineEdit->setMinimumWidth(lineEditWidth); //sourceDirectoryLineEdit->setReadOnly(true); // // target directory // targetDirectoryPushButton = new QPushButton("Atlas Directory..."); defMapGridLayout->addWidget(targetDirectoryPushButton, 2, 0); targetDirectoryPushButton->setAutoDefault(false); targetDirectoryPushButton->setEnabled(false); QObject::connect(targetDirectoryPushButton, SIGNAL(clicked()), this, SLOT(slotTargetDirectoryButton())); targetDirectoryLineEdit = new QLineEdit; defMapGridLayout->addWidget(targetDirectoryLineEdit, 2, 1); targetDirectoryLineEdit->setMinimumWidth(lineEditWidth); //targetDirectoryLineEdit->setReadOnly(true); // // Create a group widget to hold all data file items // QGroupBox* dataFileGroupBox = new QGroupBox("Data File"); dialogLayout->addWidget(dataFileGroupBox); QGridLayout* dataFileGridLayout = new QGridLayout(dataFileGroupBox); // // File Type label and combo box // dataFileGridLayout->addWidget(new QLabel("File Type"), 0, 0); fileTypeComboBox = new QComboBox; dataFileGridLayout->addWidget(fileTypeComboBox, 0, 1); QObject::connect(fileTypeComboBox, SIGNAL(activated(int)), this, SLOT(slotFileTypeComboBox(int))); // // Load the file type combo box // fileTypeComboBox->addItem("Areal Estimation", static_cast(BrainModelSurfaceDeformDataFile::DATA_FILE_AREAL_ESTIMATION)); fileTypeComboBox->addItem("Atlas (Probabilistic)", static_cast(BrainModelSurfaceDeformDataFile::DATA_FILE_ATLAS)); fileTypeComboBox->addItem("Border - Flat", static_cast(BrainModelSurfaceDeformDataFile::DATA_FILE_BORDER_FLAT)); fileTypeComboBox->addItem("Border - Spherical", static_cast(BrainModelSurfaceDeformDataFile::DATA_FILE_BORDER_SPHERICAL)); fileTypeComboBox->addItem("Border Projection", static_cast(BrainModelSurfaceDeformDataFile::DATA_FILE_BORDER_PROJECTION)); fileTypeComboBox->addItem("Cell", static_cast(BrainModelSurfaceDeformDataFile::DATA_FILE_CELL)); fileTypeComboBox->addItem("Cell Projection", static_cast(BrainModelSurfaceDeformDataFile::DATA_FILE_CELL_PROJECTION)); fileTypeComboBox->addItem("Coordinate File (3D)", static_cast(BrainModelSurfaceDeformDataFile::DATA_FILE_COORDINATE)); fileTypeComboBox->addItem("Coordinate File (FLAT)", static_cast(BrainModelSurfaceDeformDataFile::DATA_FILE_COORDINATE_FLAT)); fileTypeComboBox->addItem("Foci", static_cast(BrainModelSurfaceDeformDataFile::DATA_FILE_FOCI)); fileTypeComboBox->addItem("Foci Projection", static_cast(BrainModelSurfaceDeformDataFile::DATA_FILE_FOCI_PROJECTION)); fileTypeComboBox->addItem("Lat/Long", static_cast(BrainModelSurfaceDeformDataFile::DATA_FILE_LAT_LON)); fileTypeComboBox->addItem("Metric", static_cast(BrainModelSurfaceDeformDataFile::DATA_FILE_METRIC)); fileTypeComboBox->addItem("Paint", static_cast(BrainModelSurfaceDeformDataFile::DATA_FILE_PAINT)); fileTypeComboBox->addItem("RGB Paint", static_cast(BrainModelSurfaceDeformDataFile::DATA_FILE_RGB_PAINT)); fileTypeComboBox->addItem("Surface Shape", static_cast(BrainModelSurfaceDeformDataFile::DATA_FILE_SHAPE)); fileTypeComboBox->addItem("Topography", static_cast(BrainModelSurfaceDeformDataFile::DATA_FILE_TOPOGRAPHY)); // // Atlas topo file // atlasTopoFilePushButton = new QPushButton("Target Closed Topo File..."); dataFileGridLayout->addWidget(atlasTopoFilePushButton, 1, 0); atlasTopoFilePushButton->setAutoDefault(false); atlasTopoFilePushButton->setEnabled(false); QObject::connect(atlasTopoFilePushButton, SIGNAL(clicked()), this, SLOT(slotAtlasTopoFileButton())); atlasTopoFileLineEdit = new QLineEdit; dataFileGridLayout->addWidget(atlasTopoFileLineEdit, 1, 1); atlasTopoFileLineEdit->setMinimumWidth(lineEditWidth); atlasTopoFileLineEdit->setReadOnly(true); // // File push button and line edit // filePushButton = new QPushButton("Data File..."); dataFileGridLayout->addWidget(filePushButton, 2, 0); filePushButton->setAutoDefault(false); filePushButton->setEnabled(false); QObject::connect(filePushButton, SIGNAL(clicked()), this, SLOT(slotFileButton())); dataFileNameLineEdit = new QLineEdit; dataFileGridLayout->addWidget(dataFileNameLineEdit, 2, 1); dataFileNameLineEdit->setMinimumWidth(lineEditWidth); dataFileNameLineEdit->setReadOnly(true); // // Deformed file push button and line edit // deformedFilePushButton = new QPushButton("Deformed File..."); dataFileGridLayout->addWidget(deformedFilePushButton, 3, 0); deformedFilePushButton->setAutoDefault(false); deformedFilePushButton->setEnabled(false); QObject::connect(deformedFilePushButton, SIGNAL(clicked()), this, SLOT(slotDeformedFileButton())); deformedFileNameLineEdit = new QLineEdit; dataFileGridLayout->addWidget(deformedFileNameLineEdit, 3, 1); deformedFileNameLineEdit->setMinimumWidth(lineEditWidth); deformedFileNameLineEdit->setReadOnly(false); // // indiv topo button and line edit // indivTopoFilePushButton = new QPushButton("Source Cut Topo File..."); dataFileGridLayout->addWidget(indivTopoFilePushButton, 4, 0); indivTopoFilePushButton->setAutoDefault(false); indivTopoFilePushButton->setEnabled(false); QObject::connect(indivTopoFilePushButton, SIGNAL(clicked()), this, SLOT(slotIndivTopoFileButton())); indivTopoFileLineEdit = new QLineEdit; dataFileGridLayout->addWidget(indivTopoFileLineEdit, 4, 1); indivTopoFileLineEdit->setMinimumWidth(lineEditWidth); indivTopoFileLineEdit->setReadOnly(true); // // deformed topo button and line edit // deformedTopoFilePushButton = new QPushButton("Deformed Topo File..."); dataFileGridLayout->addWidget(deformedTopoFilePushButton, 5, 0); deformedTopoFilePushButton->setAutoDefault(false); deformedTopoFilePushButton->setEnabled(false); QObject::connect(deformedTopoFilePushButton, SIGNAL(clicked()), this, SLOT(slotDeformedTopoFileButton())); deformedTopoFileLineEdit = new QLineEdit; dataFileGridLayout->addWidget(deformedTopoFileLineEdit, 5, 1); deformedTopoFileLineEdit->setMinimumWidth(lineEditWidth); deformedTopoFileLineEdit->setReadOnly(false); // // Flat coord max edge length // flatCoordMaxEdgeLengthLabel = new QLabel("Flat Max Edge Length"); dataFileGridLayout->addWidget(flatCoordMaxEdgeLengthLabel, 6, 0); flatCoordMaxEdgeLengthDoubleSpinBox = new QDoubleSpinBox; flatCoordMaxEdgeLengthDoubleSpinBox->setMinimum(0.0); flatCoordMaxEdgeLengthDoubleSpinBox->setMaximum(10000.0); flatCoordMaxEdgeLengthDoubleSpinBox->setSingleStep(1.0); flatCoordMaxEdgeLengthDoubleSpinBox->setDecimals(2); dataFileGridLayout->addWidget(flatCoordMaxEdgeLengthDoubleSpinBox, 6, 1); flatCoordMaxEdgeLengthDoubleSpinBox->setValue(10.0); // // column prefix // QLabel* deformedColumnNamePrefixLabel = new QLabel("Column Prefix"); dataFileGridLayout->addWidget(deformedColumnNamePrefixLabel, 7, 0); deformedColumnNamePrefixLineEdit = new QLineEdit; dataFileGridLayout->addWidget(deformedColumnNamePrefixLineEdit, 7, 1); // // Metric data deformation method // QGroupBox* metricGroupBox = new QGroupBox("Metric Deformation"); dialogLayout->addWidget(metricGroupBox); QVBoxLayout* metricGroupLayout = new QVBoxLayout(metricGroupBox); metricNearestNodeRadioButton = new QRadioButton("Nearest Node"); metricGroupLayout->addWidget(metricNearestNodeRadioButton); metricAverageTileNodesRadioButton = new QRadioButton("Average of Tile's Nodes"); metricGroupLayout->addWidget(metricAverageTileNodesRadioButton); metricGroupBox->setFixedHeight(metricGroupBox->sizeHint().height()); QButtonGroup* metricButtonGroup = new QButtonGroup(this); metricButtonGroup->addButton(metricNearestNodeRadioButton, 0); metricButtonGroup->addButton(metricAverageTileNodesRadioButton, 1); // // Smooth Coordinate files option // smoothCoordsOneIterationCheckBox = new QCheckBox("Smooth One Iteration (Except Flat)"); smoothCoordsOneIterationCheckBox->setChecked(true); // // Coordinate file options // QGroupBox* coordGroupBox = new QGroupBox("Coordinate Data File Deformation Options"); QVBoxLayout* coordGroupLayout = new QVBoxLayout(coordGroupBox); coordGroupLayout->addWidget(smoothCoordsOneIterationCheckBox); dialogLayout->addWidget(coordGroupBox); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; dialogLayout->addLayout(buttonsLayout); buttonsLayout->setSpacing(2); // // Apply button // QPushButton* applyButton = new QPushButton("Apply"); applyButton->setAutoDefault(false); buttonsLayout->addWidget(applyButton); QObject::connect(applyButton, SIGNAL(clicked()), this, SLOT(slotApplyButton())); // // Close button // QPushButton* closeButton = new QPushButton("Close"); closeButton->setAutoDefault(false); buttonsLayout->addWidget(closeButton); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); QtUtilities::makeButtonsSameSize(applyButton, closeButton); slotFileTypeComboBox(fileTypeComboBox->currentIndex()); } /** * Destructor */ GuiApplyDeformationMapDialog::~GuiApplyDeformationMapDialog() { } /** * called when a file type is selected. */ void GuiApplyDeformationMapDialog::slotFileTypeComboBox(int item) { // // default labels and enabled // bool enableFlatItems = false; // // If valid def map loaded // if (filePushButton->isEnabled()) { // // Read the brain sets if needed // switch(item) { case BrainModelSurfaceDeformDataFile::DATA_FILE_AREAL_ESTIMATION: case BrainModelSurfaceDeformDataFile::DATA_FILE_ATLAS: case BrainModelSurfaceDeformDataFile::DATA_FILE_COORDINATE: break; case BrainModelSurfaceDeformDataFile::DATA_FILE_COORDINATE_FLAT: enableFlatItems = true; break; case BrainModelSurfaceDeformDataFile::DATA_FILE_LAT_LON: case BrainModelSurfaceDeformDataFile::DATA_FILE_METRIC: case BrainModelSurfaceDeformDataFile::DATA_FILE_PAINT: case BrainModelSurfaceDeformDataFile::DATA_FILE_RGB_PAINT: case BrainModelSurfaceDeformDataFile::DATA_FILE_SHAPE: case BrainModelSurfaceDeformDataFile::DATA_FILE_TOPOGRAPHY: case BrainModelSurfaceDeformDataFile::DATA_FILE_BORDER_FLAT: case BrainModelSurfaceDeformDataFile::DATA_FILE_BORDER_SPHERICAL: case BrainModelSurfaceDeformDataFile::DATA_FILE_BORDER_PROJECTION: case BrainModelSurfaceDeformDataFile::DATA_FILE_CELL: case BrainModelSurfaceDeformDataFile::DATA_FILE_CELL_PROJECTION: case BrainModelSurfaceDeformDataFile::DATA_FILE_FOCI: case BrainModelSurfaceDeformDataFile::DATA_FILE_FOCI_PROJECTION: break; } atlasTopoFilePushButton->setEnabled(enableFlatItems); atlasTopoFileLineEdit->setEnabled(enableFlatItems); indivTopoFilePushButton->setEnabled(enableFlatItems); indivTopoFileLineEdit->setEnabled(enableFlatItems); deformedTopoFilePushButton->setEnabled(enableFlatItems); deformedTopoFileLineEdit->setEnabled(enableFlatItems); flatCoordMaxEdgeLengthDoubleSpinBox->setEnabled(enableFlatItems); flatCoordMaxEdgeLengthLabel->setEnabled(enableFlatItems); if (enableFlatItems) { filePushButton->setText("Source Flat Coord File..."); deformedFilePushButton->setText("Deformed Coord File..."); } else { filePushButton->setText("Data File..."); deformedFilePushButton->setText("Deformed File..."); } } } /** * called when source directory pushbutton is pressed. */ void GuiApplyDeformationMapDialog::slotSourceDirectoryButton() { WuQFileDialog fd(this); fd.setModal(true); fd.setAcceptMode(WuQFileDialog::AcceptOpen); fd.setDirectory(QDir::currentPath()); fd.setWindowTitle("Select Source Directory"); fd.setFileMode(WuQFileDialog::DirectoryOnly); // // Popup the dialog // if (fd.exec() == QDialog::Accepted) { const QString name(fd.directory().absolutePath()); sourceDirectoryLineEdit->setText(name); deformationMapFile.setSourceDirectory(name); } } /** * called when target directory pushbutton is pressed. */ void GuiApplyDeformationMapDialog::slotTargetDirectoryButton() { WuQFileDialog fd(this); fd.setModal(true); fd.setAcceptMode(WuQFileDialog::AcceptOpen); fd.setDirectory(QDir::currentPath()); fd.setWindowTitle("Select Target Directory"); fd.setFileMode(WuQFileDialog::DirectoryOnly); // // Popup the dialog // if (fd.exec() == QDialog::Accepted) { const QString name(fd.directory().absolutePath()); targetDirectoryLineEdit->setText(name); deformationMapFile.setTargetDirectory(name); } } /** * called when apply button is pressed. */ void GuiApplyDeformationMapDialog::slotApplyButton() { const QString dataFileName(dataFileNameLineEdit->text()); const QString deformedFileName(deformedFileNameLineEdit->text()); const QString indivTopoFileName(indivTopoFileLineEdit->text()); const QString indivDeformTopoFileName(deformedTopoFileLineEdit->text()); const QString atlasTopoFileName(atlasTopoFileLineEdit->text()); QString errorMessage; if (deformationMapFile.empty()) { errorMessage.append("Is deformation map file valid ?\n"); } if (dataFileName.isEmpty()) { errorMessage.append("You must select a data file for deformation\n"); } if (deformedFileName.isEmpty()) { errorMessage.append("You must select the output name for the deformed file.\n"); } // // Set deformed column name prefix // deformationMapFile.setDeformedColumnNamePrefix(deformedColumnNamePrefixLineEdit->text()); // // Get file type // const int itemIndex = fileTypeComboBox->currentIndex(); const BrainModelSurfaceDeformDataFile::DATA_FILE_TYPE dft = static_cast( fileTypeComboBox->itemData(itemIndex).toInt()); switch(dft) { case BrainModelSurfaceDeformDataFile::DATA_FILE_AREAL_ESTIMATION: case BrainModelSurfaceDeformDataFile::DATA_FILE_ATLAS: case BrainModelSurfaceDeformDataFile::DATA_FILE_COORDINATE: break; case BrainModelSurfaceDeformDataFile::DATA_FILE_COORDINATE_FLAT: if (indivTopoFileName.isEmpty()) { errorMessage.append("You must select an individual's topo file.\n"); } if (indivDeformTopoFileName.isEmpty()) { errorMessage.append("You must select the name for the deformed indiv topo file.\n"); } if (atlasTopoFileName.isEmpty()) { errorMessage.append("You must select the atlas topology file.\n"); } break; case BrainModelSurfaceDeformDataFile::DATA_FILE_LAT_LON: case BrainModelSurfaceDeformDataFile::DATA_FILE_METRIC: case BrainModelSurfaceDeformDataFile::DATA_FILE_PAINT: case BrainModelSurfaceDeformDataFile::DATA_FILE_RGB_PAINT: case BrainModelSurfaceDeformDataFile::DATA_FILE_SHAPE: case BrainModelSurfaceDeformDataFile::DATA_FILE_TOPOGRAPHY: case BrainModelSurfaceDeformDataFile::DATA_FILE_BORDER_FLAT: case BrainModelSurfaceDeformDataFile::DATA_FILE_BORDER_SPHERICAL: case BrainModelSurfaceDeformDataFile::DATA_FILE_BORDER_PROJECTION: case BrainModelSurfaceDeformDataFile::DATA_FILE_CELL: case BrainModelSurfaceDeformDataFile::DATA_FILE_CELL_PROJECTION: case BrainModelSurfaceDeformDataFile::DATA_FILE_FOCI: case BrainModelSurfaceDeformDataFile::DATA_FILE_FOCI_PROJECTION: break; } if (errorMessage.isEmpty() == false) { QMessageBox::critical(this, "Deform Error", errorMessage); return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); const QString savedDirectory(QDir::currentPath()); if (deformationMapFile.getFileVersion() >= 2) { // // Deformation map file is modified is source or target directories are changed. // if (deformationMapFile.getModified()) { try { deformationMapFile.writeFile(deformationMapFile.getFileName()); } catch (FileException& e) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "ERROR", "Unable to update deformation map file with\n" "individual and/or atlas directory changes."); return; } } QString msg; if (QFile::exists(deformationMapFile.getSourceDirectory()) == false) { msg.append("Individual directory is invalid. Change the\n" "individual directory to the directory containing\n" "the individual spec file."); } if (QFile::exists(deformationMapFile.getTargetDirectory()) == false) { msg.append("Atlas directory is invalid. Change the\n" "atlas directory to the directory containing\n" "the atlas spec file."); } if (msg.isEmpty() == false) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "Directory Error", msg); return; } } // // Read the brain sets if needed // switch(dft) { case BrainModelSurfaceDeformDataFile::DATA_FILE_AREAL_ESTIMATION: case BrainModelSurfaceDeformDataFile::DATA_FILE_ATLAS: case BrainModelSurfaceDeformDataFile::DATA_FILE_COORDINATE: case BrainModelSurfaceDeformDataFile::DATA_FILE_COORDINATE_FLAT: case BrainModelSurfaceDeformDataFile::DATA_FILE_LAT_LON: case BrainModelSurfaceDeformDataFile::DATA_FILE_METRIC: case BrainModelSurfaceDeformDataFile::DATA_FILE_PAINT: case BrainModelSurfaceDeformDataFile::DATA_FILE_RGB_PAINT: case BrainModelSurfaceDeformDataFile::DATA_FILE_SHAPE: case BrainModelSurfaceDeformDataFile::DATA_FILE_TOPOGRAPHY: break; case BrainModelSurfaceDeformDataFile::DATA_FILE_BORDER_FLAT: case BrainModelSurfaceDeformDataFile::DATA_FILE_BORDER_SPHERICAL: case BrainModelSurfaceDeformDataFile::DATA_FILE_BORDER_PROJECTION: case BrainModelSurfaceDeformDataFile::DATA_FILE_CELL: case BrainModelSurfaceDeformDataFile::DATA_FILE_CELL_PROJECTION: case BrainModelSurfaceDeformDataFile::DATA_FILE_FOCI: case BrainModelSurfaceDeformDataFile::DATA_FILE_FOCI_PROJECTION: { if (readBrains(errorMessage)) { QDir::setCurrent(savedDirectory); QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "Deform Error", errorMessage); return; } } } const QString savedOutputSpecFileName(deformationMapFile.getOutputSpecFileName()); if (deformationMapFile.getFileVersion() >= 2) { // // Prepend with path // QString name(deformationMapFile.getTargetDirectory()); name.append("/"); name.append(deformationMapFile.getOutputSpecFileName()); deformationMapFile.setOutputSpecFileName(name); } // // set metric deformation // if (metricNearestNodeRadioButton->isChecked()) { deformationMapFile.setMetricDeformationType(DeformationMapFile::METRIC_DEFORM_NEAREST_NODE); } else if (metricAverageTileNodesRadioButton->isChecked()) { deformationMapFile.setMetricDeformationType(DeformationMapFile::METRIC_DEFORM_AVERAGE_TILE_NODES); } // // If this is true, the command will try to read data files from // the source directory listed in the deformation map file and // write the deformed files into the target directory listed in // the deformation map file. // const bool useSourceAndTargetPaths = false; // // Deform the data file // try { switch(dft) { case BrainModelSurfaceDeformDataFile::DATA_FILE_AREAL_ESTIMATION: case BrainModelSurfaceDeformDataFile::DATA_FILE_LAT_LON: case BrainModelSurfaceDeformDataFile::DATA_FILE_RGB_PAINT: case BrainModelSurfaceDeformDataFile::DATA_FILE_TOPOGRAPHY: BrainModelSurfaceDeformDataFile::deformNodeAttributeFile(&deformationMapFile, dft, useSourceAndTargetPaths, dataFileName, deformedFileName); break; case BrainModelSurfaceDeformDataFile::DATA_FILE_ATLAS: case BrainModelSurfaceDeformDataFile::DATA_FILE_METRIC: case BrainModelSurfaceDeformDataFile::DATA_FILE_PAINT: case BrainModelSurfaceDeformDataFile::DATA_FILE_SHAPE: BrainModelSurfaceDeformDataFile::deformGiftiNodeDataFile(&deformationMapFile, dft, useSourceAndTargetPaths, dataFileName, deformedFileName); break; case BrainModelSurfaceDeformDataFile::DATA_FILE_COORDINATE: { QString deformedFileName2(deformedFileName); BrainModelSurfaceDeformDataFile::deformCoordinateFile(&deformationMapFile, dataFileName, deformedFileName2, smoothCoordsOneIterationCheckBox->isChecked(), useSourceAndTargetPaths); } break; case BrainModelSurfaceDeformDataFile::DATA_FILE_COORDINATE_FLAT: BrainModelSurfaceDeformDataFile::deformFlatCoordinateFile( &deformationMapFile, atlasTopoFileName, useSourceAndTargetPaths, dataFileName, indivTopoFileName, deformedFileName, indivDeformTopoFileName, flatCoordMaxEdgeLengthDoubleSpinBox->value()); break; case BrainModelSurfaceDeformDataFile::DATA_FILE_BORDER_FLAT: case BrainModelSurfaceDeformDataFile::DATA_FILE_BORDER_SPHERICAL: case BrainModelSurfaceDeformDataFile::DATA_FILE_BORDER_PROJECTION: BrainModelSurfaceDeformDataFile::deformBorderFile( sourceBrainSet, targetBrainSet, &deformationMapFile, useSourceAndTargetPaths, dft, dataFileName, deformedFileName); break; case BrainModelSurfaceDeformDataFile::DATA_FILE_CELL: BrainModelSurfaceDeformDataFile::deformCellOrFociFile( sourceBrainSet, targetBrainSet, &deformationMapFile, useSourceAndTargetPaths, dataFileName, false, deformedFileName); break; case BrainModelSurfaceDeformDataFile::DATA_FILE_CELL_PROJECTION: BrainModelSurfaceDeformDataFile::deformCellOrFociProjectionFile( sourceBrainSet, targetBrainSet, &deformationMapFile, useSourceAndTargetPaths, dataFileName, false, deformedFileName); break; case BrainModelSurfaceDeformDataFile::DATA_FILE_FOCI: BrainModelSurfaceDeformDataFile::deformCellOrFociFile( sourceBrainSet, targetBrainSet, &deformationMapFile, useSourceAndTargetPaths, dataFileName, true, deformedFileName); case BrainModelSurfaceDeformDataFile::DATA_FILE_FOCI_PROJECTION: BrainModelSurfaceDeformDataFile::deformCellOrFociProjectionFile( sourceBrainSet, targetBrainSet, &deformationMapFile, useSourceAndTargetPaths, dataFileName, true, deformedFileName); break; } } catch (BrainModelAlgorithmException& e) { QDir::setCurrent(savedDirectory); QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "Deform Error", e.whatQString()); // // Restore output spec file name // if (deformationMapFile.getFileVersion() >= 2) { deformationMapFile.setOutputSpecFileName(savedOutputSpecFileName); } return; } // // Restore output spec file name // if (deformationMapFile.getFileVersion() >= 2) { deformationMapFile.setOutputSpecFileName(savedOutputSpecFileName); } QDir::setCurrent(savedDirectory); QApplication::restoreOverrideCursor(); QMessageBox::information(this, "Deform Successful", "File successfully deformed."); } /** * called when deformation map button is pressed. */ void GuiApplyDeformationMapDialog::slotDeformationMapButton() { // // Create the file dialog // WuQFileDialog fd(this); fd.setDirectory(QDir::currentPath()); fd.setModal(true); fd.setAcceptMode(WuQFileDialog::AcceptOpen); fd.setWindowTitle("Select Deformation Map File"); fd.setFileMode(WuQFileDialog::ExistingFile); //QString fileFilter("Deformation Map File (*"); //fileFilter.append(SpecFile::getDeformationMapFileExtension()); //fileFilter.append(")"); fd.setFilter(FileFilters::getDeformationMapFileFilter()); fd.selectFilter(FileFilters::getDeformationMapFileFilter()); // // Popup the dialog // if ((fd.exec() == QDialog::Accepted) && (fd.selectedFiles().count() > 0)) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); // // Since deformation map file may have changed delete the source and target // brain sets if they are loaded. // if (sourceBrainSet != NULL) { delete sourceBrainSet; } if (targetBrainSet != NULL) { delete targetBrainSet; } // // Disable file buttons and clear deformation map file name // sourceDirectoryPushButton->setEnabled(false); targetDirectoryPushButton->setEnabled(false); filePushButton->setEnabled(false); deformedFilePushButton->setEnabled(false); deformationMapFileLineEdit->setText(""); atlasTopoFilePushButton->setEnabled(false); indivTopoFilePushButton->setEnabled(false); deformedTopoFilePushButton->setEnabled(false); // // Read the deformation map file // try { deformationMapFile.readFile(fd.selectedFiles().at(0)); } catch (FileException& e) { QMessageBox::critical(this, "Deformation Map File Read Error", e.whatQString()); return; } QApplication::restoreOverrideCursor(); // // Set column prefix // deformedColumnNamePrefixLineEdit->setText(deformationMapFile.getDeformedColumnNamePrefix()); // // Enable file buttons and display deformation map file name // filePushButton->setEnabled(true); deformedFilePushButton->setEnabled(true); deformationMapFileLineEdit->setText(fd.selectedFiles().at(0)); // // Load source directory // bool needSourceDirectory = false; if (deformationMapFile.getFileVersion() >= 2) { sourceDirectoryLineEdit->setText(deformationMapFile.getSourceDirectory()); sourceDirectoryPushButton->setEnabled(true); if (QFile::exists(deformationMapFile.getSourceDirectory()) == false) { needSourceDirectory = true; } } else { sourceDirectoryLineEdit->setText(""); } sourceDirectoryLineEdit->setModified(false); // // Load target directory // bool needTargetDirectory = false; if (deformationMapFile.getFileVersion() >= 2) { targetDirectoryLineEdit->setText(deformationMapFile.getTargetDirectory()); targetDirectoryPushButton->setEnabled(true); if (QFile::exists(deformationMapFile.getTargetDirectory()) == false) { needTargetDirectory = true; } } else { targetDirectoryLineEdit->setText(""); } targetDirectoryLineEdit->setModified(false); // // Load the atlas closed topology file // if (needTargetDirectory == false) { QString topoName(deformationMapFile.getTargetClosedTopoFileName()); if (deformationMapFile.getFileVersion() >= 2) { QString tempName(deformationMapFile.getTargetDirectory()); tempName.append(QDir::separator()); tempName.append(topoName); topoName = tempName; } if (QFile::exists(topoName)) { atlasTopoFileLineEdit->setText(topoName); } } QString message; if (needSourceDirectory) { message.append("Individual directory is invalid. Please set it to the DIRECTORY\n" "containing the individual spec file.\n"); } if (needTargetDirectory) { message.append("Atlas directory is invalid. Please set it to the DIRECTORY\n" "containing the atlas spec file."); } if (message.isEmpty() == false) { QMessageBox::critical(this, "ERROR", message); } slotFileTypeComboBox(fileTypeComboBox->currentIndex()); if (deformationMapFile.getMetricDeformationType() == DeformationMapFile::METRIC_DEFORM_AVERAGE_TILE_NODES) { metricAverageTileNodesRadioButton->setChecked(true); } else { metricNearestNodeRadioButton->setChecked(true); } smoothCoordsOneIterationCheckBox->setChecked(deformationMapFile.getSmoothDeformedSurfacesFlag()); } } /** * called when indiv topo file button is pressed. */ void GuiApplyDeformationMapDialog::slotIndivTopoFileButton() { dataFileDialog(FILE_DIALOG_INDIV_TOPO_FILE); } /** * called when deformed topo file button is pressed. */ void GuiApplyDeformationMapDialog::slotDeformedTopoFileButton() { dataFileDialog(FILE_DIALOG_DEFORMED_TOPO_FILE); } /** * called when atlas topo file button is pressed. */ void GuiApplyDeformationMapDialog::slotAtlasTopoFileButton() { dataFileDialog(FILE_DIALOG_ATLAS_TOPO_FILE); } /** * called when file button is pressed. */ void GuiApplyDeformationMapDialog::slotFileButton() { dataFileDialog(FILE_DIALOG_DATA_FILE); } /** * called when deformed file button is pressed. */ void GuiApplyDeformationMapDialog::slotDeformedFileButton() { dataFileDialog(FILE_DIALOG_DEFORMED_FILE); } /** * data file dialog for data file and deformed file. */ void GuiApplyDeformationMapDialog::dataFileDialog(const FILE_DIALOG_TYPE fdt) { // // Set file filter based upon data file type // QString fileType; QString fileExtension; QString fileExtension2; const int itemIndex = fileTypeComboBox->currentIndex(); switch(static_cast(fileTypeComboBox->itemData(itemIndex).toInt())) { case BrainModelSurfaceDeformDataFile::DATA_FILE_AREAL_ESTIMATION: fileType = "Areal Estimation File"; fileExtension = SpecFile::getArealEstimationFileExtension(); break; case BrainModelSurfaceDeformDataFile::DATA_FILE_ATLAS: fileType = "Atlas File"; fileExtension = SpecFile::getProbabilisticAtlasFileExtension(); fileExtension2 = SpecFile::getProbabilisticAtlasFileExtension() + SpecFile::getPaintFileExtension(); break; case BrainModelSurfaceDeformDataFile::DATA_FILE_BORDER_FLAT: fileType = "Flat Border File"; fileExtension = SpecFile::getBorderFileExtension(); break; case BrainModelSurfaceDeformDataFile::DATA_FILE_BORDER_SPHERICAL: fileType = "Spherical Border File"; fileExtension = SpecFile::getBorderFileExtension(); break; case BrainModelSurfaceDeformDataFile::DATA_FILE_BORDER_PROJECTION: fileType = "Border Projection File"; fileExtension = SpecFile::getBorderProjectionFileExtension(); break; case BrainModelSurfaceDeformDataFile::DATA_FILE_CELL: fileType = "Cell File"; fileExtension = SpecFile::getCellFileExtension(); break; case BrainModelSurfaceDeformDataFile::DATA_FILE_CELL_PROJECTION: fileType = "Cell Projection File"; fileExtension = SpecFile::getCellProjectionFileExtension(); break; case BrainModelSurfaceDeformDataFile::DATA_FILE_COORDINATE: fileType = "Coordinate File"; fileExtension = SpecFile::getCoordinateFileExtension(); break; case BrainModelSurfaceDeformDataFile::DATA_FILE_COORDINATE_FLAT: fileType = "Flat Coordinate File"; fileExtension = SpecFile::getCoordinateFileExtension(); break; case BrainModelSurfaceDeformDataFile::DATA_FILE_FOCI: fileType = "Foci File"; fileExtension = SpecFile::getFociFileExtension(); break; case BrainModelSurfaceDeformDataFile::DATA_FILE_FOCI_PROJECTION: fileType = "Foci Projection File"; fileExtension = SpecFile::getFociProjectionFileExtension(); break; case BrainModelSurfaceDeformDataFile::DATA_FILE_LAT_LON: fileType = "Lat/Long File"; fileExtension = SpecFile::getLatLonFileExtension(); break; case BrainModelSurfaceDeformDataFile::DATA_FILE_METRIC: fileType = "Metric File"; fileExtension = SpecFile::getMetricFileExtension(); break; case BrainModelSurfaceDeformDataFile::DATA_FILE_PAINT: fileType = "Paint File"; fileExtension = SpecFile::getPaintFileExtension(); break; case BrainModelSurfaceDeformDataFile::DATA_FILE_RGB_PAINT: fileType = "RGB Paint File"; fileExtension = SpecFile::getRgbPaintFileExtension(); break; case BrainModelSurfaceDeformDataFile::DATA_FILE_SHAPE: fileType = "Surface Shape File"; fileExtension = SpecFile::getSurfaceShapeFileExtension(); break; case BrainModelSurfaceDeformDataFile::DATA_FILE_TOPOGRAPHY: fileType = "Topography File"; fileExtension = SpecFile::getTopographyFileExtension(); break; } // // Create the file dialog and override file type/ext in some cases // WuQFileDialog fd(this); fd.setModal(true); fd.setDirectory(QDir::currentPath()); fd.setAcceptMode(WuQFileDialog::AcceptOpen); switch(fdt) { case FILE_DIALOG_ATLAS_TOPO_FILE: fileType = "Topology File"; fileExtension = SpecFile::getTopoFileExtension(); fd.setWindowTitle("Select Target Topo File For Deformation"); fd.setFileMode(WuQFileDialog::ExistingFile); break; case FILE_DIALOG_DATA_FILE: fd.setWindowTitle("Select Data File For Deformation"); fd.setFileMode(WuQFileDialog::ExistingFile); break; case FILE_DIALOG_DEFORMED_FILE: fd.setWindowTitle("Select Deformed Data File (Output File)"); fd.setFileMode(WuQFileDialog::AnyFile); break; case FILE_DIALOG_INDIV_TOPO_FILE: fileType = "Topology File"; fileExtension = SpecFile::getTopoFileExtension(); fd.setWindowTitle("Select Source Topo File For Deformation"); fd.setFileMode(WuQFileDialog::ExistingFile); break; case FILE_DIALOG_DEFORMED_TOPO_FILE: fileType = "Topology File"; fileExtension = SpecFile::getTopoFileExtension(); fd.setWindowTitle("Select Deformed Topology File (Output File)"); fd.setFileMode(WuQFileDialog::AnyFile); break; } // // Create the file filter // QString filter(fileType); filter.append(" (*"); filter.append(fileExtension); if (fileExtension2.isEmpty() == false) { filter.append(" *"); filter.append(fileExtension2); } filter.append(")"); fd.setFilter(filter); // // Popup the dialog // if (fd.exec() == QDialog::Accepted) { if (fd.selectedFiles().count() > 0) { const QString fileName(fd.selectedFiles().at(0)); switch(fdt) { case FILE_DIALOG_ATLAS_TOPO_FILE: atlasTopoFileLineEdit->setText(fileName); break; case FILE_DIALOG_DATA_FILE: dataFileNameLineEdit->setText(fileName); setDeformedFileName(fdt); break; case FILE_DIALOG_DEFORMED_FILE: deformedFileNameLineEdit->setText(fileName); break; case FILE_DIALOG_INDIV_TOPO_FILE: indivTopoFileLineEdit->setText(fileName); setDeformedFileName(fdt); break; case FILE_DIALOG_DEFORMED_TOPO_FILE: deformedTopoFileLineEdit->setText(fileName); break; } } } } /** * Set the deformed file name using the input data file name and deformation map file. */ void GuiApplyDeformationMapDialog::setDeformedFileName(const FILE_DIALOG_TYPE fdt) { // // Name of deformation map file and data file that is to be deformed // const QString dmfName(deformationMapFileLineEdit->text()); QString filename; QLineEdit* lineEdit = NULL; switch (fdt) { case FILE_DIALOG_ATLAS_TOPO_FILE: break; case FILE_DIALOG_DATA_FILE: filename = dataFileNameLineEdit->text(); lineEdit = deformedFileNameLineEdit; break; case FILE_DIALOG_DEFORMED_FILE: break; case FILE_DIALOG_INDIV_TOPO_FILE: filename = indivTopoFileLineEdit->text(); lineEdit = deformedTopoFileLineEdit; break; case FILE_DIALOG_DEFORMED_TOPO_FILE: break; } if (lineEdit == NULL) { return; } // // Create the deformed file name // QString outputSpecFileName; if (deformationMapFile.getFileVersion() >= 2) { outputSpecFileName = deformationMapFile.getTargetDirectory(); outputSpecFileName.append("/"); outputSpecFileName.append(FileUtilities::basename(deformationMapFile.getOutputSpecFileName())); } else { outputSpecFileName.append(deformationMapFile.getOutputSpecFileName()); } QString defName = BrainModelSurfaceDeformDataFile::createDeformedFileName(filename, outputSpecFileName, deformationMapFile.getDeformedFileNamePrefix(), deformationMapFile.getNumberOfNodes(), false); const QString fileDir(FileUtilities::dirname(defName)); if (fileDir.isEmpty() == false) { if (fileDir != ".") { if (QFile::exists(fileDir) == false) { defName = FileUtilities::basename(defName); QString msg("Deformation output directory not found: "); msg.append(fileDir); msg.append("\n"); msg.append("Output file location defaults to current directory."); QMessageBox::information(this, "File Info", msg); } } } // // Put deformed name into line edit // lineEdit->setText(defName); } /** * Read in the source and target brains needed for some deformations */ bool GuiApplyDeformationMapDialog::readBrains(QString& errorMessage) { /* * Force rereading of brains since users may have changed * items in the Apply deformation map dialog. */ if (sourceBrainSet != NULL) { delete sourceBrainSet; sourceBrainSet = NULL; } if (targetBrainSet != NULL) { delete targetBrainSet; targetBrainSet = NULL; } errorMessage = ""; const QString savedDirectory(QDir::currentPath()); // // Does the source brain set need to be created // if (sourceBrainSet == NULL) { // // Read in the source spec file // bool sourceSpecMissing = true; SpecFile sourceSpecFile; try { QString specFileName; if (deformationMapFile.getFileVersion() >= 2) { specFileName.append(deformationMapFile.getSourceDirectory()); specFileName.append("/"); } specFileName.append(deformationMapFile.getSourceSpecFileName()); sourceSpecFile.readFile(specFileName); sourceSpecMissing = false; } catch (FileException& e) { QDir::setCurrent(deformationMapFile.getSourceDirectory()); errorMessage = e.whatQString(); return true; } // // Select the deformation files // sourceSpecFile.setDeformationSelectedFiles( deformationMapFile.getSourceClosedTopoFileName(), deformationMapFile.getSourceCutTopoFileName(), deformationMapFile.getSourceFiducialCoordFileName(), deformationMapFile.getSourceSphericalCoordFileName(), deformationMapFile.getSourceFlatCoordFileName(), "", true, //sourceSpecMissing, sourceSpecFile.getStructure()); // // Read in the source brain set // std::vector errorMessages; sourceBrainSet = new BrainSet; sourceBrainSet->readSpecFile(BrainSet::SPEC_FILE_READ_MODE_NORMAL, sourceSpecFile, deformationMapFile.getSourceSpecFileName(), errorMessages, NULL, NULL); if (errorMessages.empty() == false) { if (sourceSpecMissing) { errorMessages.push_back("Source spec file was not found.\n" "Tried to load data files.\n"); } errorMessage = StringUtilities::combine(errorMessages, "\n"); delete sourceBrainSet; sourceBrainSet = NULL; return true; } // // Read in the deformed coordinate file // if (deformationMapFile.getInverseDeformationFlag() == false) { QString coordFileName; BrainModelSurface::SURFACE_TYPES surfaceType = BrainModelSurface::SURFACE_TYPE_UNKNOWN; switch(deformationMapFile.getFlatOrSphereSelection()) { case DeformationMapFile::DEFORMATION_TYPE_FLAT: coordFileName = deformationMapFile.getSourceDeformedFlatCoordFileName(); surfaceType = BrainModelSurface::SURFACE_TYPE_FLAT; break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: coordFileName = deformationMapFile.getSourceDeformedSphericalCoordFileName(); surfaceType = BrainModelSurface::SURFACE_TYPE_SPHERICAL; break; } if (coordFileName.isEmpty()) { errorMessage = "Deformed source coordinate file is missing."; delete sourceBrainSet; sourceBrainSet = NULL; return true; } try { sourceBrainSet->readCoordinateFile(coordFileName, surfaceType, false, true, false); } catch (FileException& e) { errorMessage = e.whatQString(); delete sourceBrainSet; sourceBrainSet = NULL; return true; } } } QDir::setCurrent(savedDirectory); // // Does the target brain set need to be created // if (targetBrainSet == NULL) { // // Read in the target spec file // bool targetSpecMissing = true; SpecFile targetSpecFile; try { QString specFileName; if (deformationMapFile.getFileVersion() >= 2) { specFileName.append(deformationMapFile.getTargetDirectory()); specFileName.append("/"); } specFileName.append(deformationMapFile.getTargetSpecFileName()); targetSpecFile.readFile(specFileName); targetSpecMissing = false; } catch (FileException& e) { QDir::setCurrent(deformationMapFile.getSourceDirectory()); errorMessage = e.whatQString(); return true; } // // Select the deformation files // targetSpecFile.setDeformationSelectedFiles( deformationMapFile.getTargetClosedTopoFileName(), deformationMapFile.getTargetCutTopoFileName(), deformationMapFile.getTargetFiducialCoordFileName(), deformationMapFile.getTargetSphericalCoordFileName(), deformationMapFile.getTargetFlatCoordFileName(), "", true, //targetSpecMissing, targetSpecFile.getStructure()); // // Read in the target brain set // std::vector errorMessages; targetBrainSet = new BrainSet; targetBrainSet->readSpecFile(BrainSet::SPEC_FILE_READ_MODE_NORMAL, targetSpecFile, deformationMapFile.getTargetSpecFileName(), errorMessages, NULL, NULL); if (errorMessages.empty() == false) { if (targetSpecMissing) { errorMessages.push_back("Target spec file was not found.\n" "Tried to load data files.\n"); } errorMessage = StringUtilities::combine(errorMessages, "\n"); delete targetBrainSet; targetBrainSet = NULL; return true; } // // Read in the deformed coordinate file // if (deformationMapFile.getInverseDeformationFlag()) { QString coordFileName; BrainModelSurface::SURFACE_TYPES surfaceType = BrainModelSurface::SURFACE_TYPE_UNKNOWN; switch(deformationMapFile.getFlatOrSphereSelection()) { case DeformationMapFile::DEFORMATION_TYPE_FLAT: coordFileName = deformationMapFile.getSourceDeformedFlatCoordFileName(); surfaceType = BrainModelSurface::SURFACE_TYPE_FLAT; break; case DeformationMapFile::DEFORMATION_TYPE_SPHERE: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_MULTI_STAGE_VECTOR: case DeformationMapFile::DEFORMATION_TYPE_SPHERE_SINGLE_STAGE_VECTOR: coordFileName = deformationMapFile.getSourceDeformedSphericalCoordFileName(); surfaceType = BrainModelSurface::SURFACE_TYPE_SPHERICAL; break; } if (coordFileName.isEmpty()) { errorMessage = "Deformed source coordinate file is missing."; delete sourceBrainSet; sourceBrainSet = NULL; return true; } try { targetBrainSet->readCoordinateFile(coordFileName, surfaceType, false, true, false); } catch (FileException& e) { errorMessage = e.whatQString(); delete sourceBrainSet; sourceBrainSet = NULL; return true; } } } QDir::setCurrent(savedDirectory); return false; } caret-5.6.4~dfsg.1.orig/caret/GuiAlignSurfaceToStandardOrientationDialog.h0000664000175000017500000000352611572067322026366 0ustar michaelmichael #ifndef __GUI_ALIGN_SURFACE_TO_STANDARD_ORIENTATION_DIALOG_H__ #define __GUI_ALIGN_SURFACE_TO_STANDARD_ORIENTATION_DIALOG_H__ #include "WuQDialog.h" class GuiBrainModelSelectionComboBox; class QCheckBox; class QLabel; /// class for dialog used to align a surface to standard orientation class GuiAlignSurfaceToStandardOrientationDialog : public WuQDialog { Q_OBJECT public: /// Constructor GuiAlignSurfaceToStandardOrientationDialog(QWidget* parent); /// Destructor ~GuiAlignSurfaceToStandardOrientationDialog(); /// called to set medial tip node void setMedialTipNode(const int node); /// called to set medial tip node void setVentralTipNode(const int node); private slots: /// called when align sphere check box is toggled void slotAlignSphereCheckBox(bool onoff); /// called when apply pushbutton is pressed void slotApplyPushButton(); /// called when reset pushbutton is pressed void slotResetPushButton(); private: /// dorsal tip x label QLabel* medialTipXLabel; /// dorsal tip y label QLabel* medialTipYLabel; /// ventral tip x label QLabel* ventralTipXLabel; /// ventral tip y label QLabel* ventralTipYLabel; /// align sphere check box QCheckBox* alignSphereCheckBox; /// generate lat/lon check box QCheckBox* sphereLatLonCheckBox; /// scale to fiducial area check box QCheckBox* scaleSurfaceCheckBox; /// sphere selection combo box GuiBrainModelSelectionComboBox* sphereSurfaceComboBox; /// medial tip node int medialTipNode; /// ventral tip node int ventralTipNode; }; #endif // __GUI_ALIGN_SURFACE_TO_STANDARD_ORIENTATION_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiAlignSurfaceToStandardOrientationDialog.cxx0000664000175000017500000002275211572067322026743 0ustar michaelmichael /*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include "BrainSet.h" #include "GuiAlignSurfaceToStandardOrientationDialog.h" #include "GuiBrainModelOpenGL.h" #include "GuiBrainModelSelectionComboBox.h" #include "GuiMainWindow.h" #include "QtUtilities.h" #include "global_variables.h" /** * Constructor */ GuiAlignSurfaceToStandardOrientationDialog::GuiAlignSurfaceToStandardOrientationDialog( QWidget* parent) : WuQDialog(parent) { setAttribute(Qt::WA_DeleteOnClose); setWindowTitle("Align Surface(s) to Standard Orientation"); medialTipNode = -1; ventralTipNode = -1; // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); // // Grid for ventral and dorsal-medial tips // QGroupBox* centralSulcusGroupBox = new QGroupBox("Central Sulcus Tips"); dialogLayout->addWidget(centralSulcusGroupBox); QGridLayout* centralSulcusGridLayout = new QGridLayout(centralSulcusGroupBox); // // Column headers // centralSulcusGridLayout->addWidget(new QLabel("Central Sulcus Tip"), 0, 0); centralSulcusGridLayout->addWidget(new QLabel("Mouse"), 0, 1); centralSulcusGridLayout->addWidget(new QLabel("X"), 0, 2); centralSulcusGridLayout->addWidget(new QLabel("Y"), 0, 3); // // Ventral tip // centralSulcusGridLayout->addWidget(new QLabel("Ventral"), 1, 0); centralSulcusGridLayout->addWidget(new QLabel("Left Click"), 1, 1); ventralTipXLabel = new QLabel(" "); ventralTipYLabel = new QLabel(" "); centralSulcusGridLayout->addWidget(ventralTipXLabel, 1, 2); centralSulcusGridLayout->addWidget(ventralTipYLabel, 1, 3); // // Medial tip // centralSulcusGridLayout->addWidget(new QLabel("Dorsal-Medial"), 2, 0); centralSulcusGridLayout->addWidget(new QLabel("Shift Left Click"), 2, 1); medialTipXLabel = new QLabel(" "); medialTipYLabel = new QLabel(" "); centralSulcusGridLayout->addWidget(medialTipXLabel, 2, 2); centralSulcusGridLayout->addWidget(medialTipYLabel, 2, 3); // // Surface scaling box // QGroupBox* scaleGroupBox = new QGroupBox("Surface Scaling"); QVBoxLayout* scaleGroupBoxLayout = new QVBoxLayout(scaleGroupBox); dialogLayout->addWidget(scaleGroupBox); // // Scale to fiducial area check box // scaleSurfaceCheckBox = new QCheckBox("Scale to Fiducial Area"); scaleGroupBoxLayout->addWidget(scaleSurfaceCheckBox); scaleSurfaceCheckBox->setChecked(true); // // vertical group box for spherical surface // QGroupBox* sphereGroupBox = new QGroupBox("Spherical Surface"); QVBoxLayout* sphereGroupBoxLayout = new QVBoxLayout(sphereGroupBox); dialogLayout->addWidget(sphereGroupBox); // // Align sphere check box // alignSphereCheckBox = new QCheckBox("Align Sphere"); sphereGroupBoxLayout->addWidget(alignSphereCheckBox); alignSphereCheckBox->setChecked(true); QObject::connect(alignSphereCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotAlignSphereCheckBox(bool))); // // Generate Lat/Lon check box // sphereLatLonCheckBox = new QCheckBox("Generate Lat/Lon on Sphere"); sphereGroupBoxLayout->addWidget(sphereLatLonCheckBox); sphereLatLonCheckBox->setChecked(true); // // Brain Mode surface combo box // sphereSurfaceComboBox = new GuiBrainModelSelectionComboBox(false, true, false, "", 0, "sphereSurfaceComboBox"); sphereGroupBoxLayout->addWidget(sphereSurfaceComboBox); sphereSurfaceComboBox->setSelectedBrainModelToLastSurfaceOfType(BrainModelSurface::SURFACE_TYPE_SPHERICAL); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; buttonsLayout->setSpacing(2); dialogLayout->addLayout(buttonsLayout); // // Apply button // QPushButton* applyButton = new QPushButton("Apply"); applyButton->setAutoDefault(false); buttonsLayout->addWidget(applyButton); QObject::connect(applyButton, SIGNAL(clicked()), this, SLOT(slotApplyPushButton())); // // Reset button // QPushButton* resetButton = new QPushButton("Reset"); resetButton->setAutoDefault(false); buttonsLayout->addWidget(resetButton); QObject::connect(resetButton, SIGNAL(clicked()), this, SLOT(slotResetPushButton())); // // Close button // QPushButton* closeButton = new QPushButton("Close"); closeButton->setAutoDefault(false); buttonsLayout->addWidget(closeButton); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); QtUtilities::makeButtonsSameSize(applyButton, resetButton, closeButton); // // initialize some dialog items // slotAlignSphereCheckBox(alignSphereCheckBox->isChecked()); slotResetPushButton(); // // Register dialog with main window // theMainWindow->setAlignSurfaceToStandardOrientationDialog(this); } /** * Destructor */ GuiAlignSurfaceToStandardOrientationDialog::~GuiAlignSurfaceToStandardOrientationDialog() { // // Unregister dialog with main window // theMainWindow->setAlignSurfaceToStandardOrientationDialog(NULL); } /** * called when align sphere checkbox is pressed */ void GuiAlignSurfaceToStandardOrientationDialog::slotAlignSphereCheckBox(bool onoff) { sphereLatLonCheckBox->setEnabled(onoff); sphereSurfaceComboBox->setEnabled(onoff); } /** * called when apply pushbutton is pressed. */ void GuiAlignSurfaceToStandardOrientationDialog::slotApplyPushButton() { if ((medialTipNode < 0) || (ventralTipNode < 0)) { QMessageBox::critical(this, "Missing Nodes", "You must select both medial-dorsal and ventral node points of central sulcus"); return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); const bool scaleSurface = scaleSurfaceCheckBox->isChecked(); BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms != NULL) { bms->alignToStandardOrientation(ventralTipNode, medialTipNode, false, scaleSurface); if (alignSphereCheckBox->isChecked()) { bms = sphereSurfaceComboBox->getSelectedBrainModelSurface(); if (bms != NULL) { bms->alignToStandardOrientation(ventralTipNode, medialTipNode, sphereLatLonCheckBox->isChecked(), scaleSurface); } } theMainWindow->getBrainSet()->applyAllProjectedFiles(); GuiBrainModelOpenGL::updateAllGL(NULL); } QApplication::restoreOverrideCursor(); } /** * called when reset pushbutton is pressed. */ void GuiAlignSurfaceToStandardOrientationDialog::slotResetPushButton() { sphereSurfaceComboBox->updateComboBox(); setMedialTipNode(-1); setVentralTipNode(-1); theMainWindow->getBrainModelOpenGL()->setMouseMode( GuiBrainModelOpenGL::MOUSE_MODE_ALIGN_STANDARD_ORIENTATION); } /** * called to set medial tip node. */ void GuiAlignSurfaceToStandardOrientationDialog::setMedialTipNode(const int node) { medialTipNode = node; BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); QString xValue, yValue; if (bms != NULL) { int numNodes = bms->getNumberOfNodes(); if ((node >= 0) && (node < numNodes)) { CoordinateFile* cf = bms->getCoordinateFile(); float xyz[3]; cf->getCoordinate(node, xyz); xValue = QString::number(xyz[0], 'f', 1); yValue = QString::number(xyz[1], 'f', 1); } } medialTipXLabel->setText(xValue); medialTipYLabel->setText(yValue); } /** * called to set medial tip node. */ void GuiAlignSurfaceToStandardOrientationDialog::setVentralTipNode(const int node) { ventralTipNode = node; BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); QString xValue, yValue; if (bms != NULL) { int numNodes = bms->getNumberOfNodes(); if ((node >= 0) && (node < numNodes)) { CoordinateFile* cf = bms->getCoordinateFile(); float xyz[3]; cf->getCoordinate(node, xyz); xValue = QString::number(xyz[0], 'f', 1); yValue = QString::number(xyz[1], 'f', 1); } } ventralTipXLabel->setText(xValue); ventralTipYLabel->setText(yValue); } caret-5.6.4~dfsg.1.orig/caret/GuiAddCellsDialog.h0000664000175000017500000000723711572067322021301 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __GUI_ADD_CELLS_DIALOG_H__ #define __GUI_ADD_CELLS_DIALOG_H__ #include #include "WuQDialog.h" class QCheckBox; class QComboBox; class QLineEdit; class QTextEdit; /// Dialog for adding cells to a surface class GuiAddCellsDialog : public WuQDialog { Q_OBJECT public: /// dialog mode (adding surface cells or contour cells) enum DIALOG_MODE { DIALOG_MODE_ADD_CELLS, DIALOG_MODE_ADD_CONTOUR_CELLS }; /// Constructor GuiAddCellsDialog(const DIALOG_MODE dm, QWidget* parent = 0, bool modalFlag = false, Qt::WindowFlags f = 0); /// Destructor ~GuiAddCellsDialog(); /// add a cell at the specified node number void addCellAtNodeNumber(const int nodeNumber); /// add a contour cell at the specified position and section number void addContourCellAtXYZ(const float xyz[3], const int sectionNumber); /// update the file dialog due to file changes void updateDialog(); private slots: /// Called when apply button is pressed void slotApplyButton(); /// Called when button name choose is pressed void slotNameButton(); /// Called when button comment choose is pressed void slotClassButton(); /// Called when comment combo box item is selected void slotCommentComboBox(int item); /// Called when text is changed in the cell name line edit void slotCellNameChanged(); /// Called when text is changed in the cell class name line edit void slotCellClassNameChanged(); private: /// update for cell projections void updateCellProjectionMode(); /// update contour cells void updateContourCellMode(); /// Get the name of the class. Returns true if it is missing. bool getCellClass(); /// Get the name, the class, and the color. Returns true if an item is missing. bool getNameAndColor(); /// mode of dialog DIALOG_MODE dialogMode; /// cell name line edit QLineEdit* nameLineEdit; /// class name line edit QLineEdit* classLineEdit; /// comment selection combo box QComboBox* commentComboBox; /// comment text edit QTextEdit* commentTextEdit; /// auto project cells check box QCheckBox* autoProjectCellsCheckBox; /// name of the cell QString cellName; /// name of the cell's class QString cellClassName; /// color index for the cell int cellColorIndex; /// name of cell has changed in line edit bool cellNameChanged; /// name of cell class has changed in line edit bool cellClassNameChanged; }; #endif // __GUI_ADD_CELLS_DIALOG_H__ caret-5.6.4~dfsg.1.orig/caret/GuiAddCellsDialog.cxx0000664000175000017500000005432411572067322021653 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include #include #include #include #include #include #include #include #include "BrainSet.h" #include "CellColorFile.h" #include "CellFile.h" #include "CellFileProjector.h" #include "CellProjectionFile.h" #include "ContourCellColorFile.h" #include "ContourCellFile.h" #include "DebugControl.h" #include "DisplaySettingsCells.h" #include "DisplaySettingsContours.h" #include "DisplaySettingsSection.h" #include "GuiAddCellsDialog.h" #include "GuiBrainModelOpenGL.h" #include "GuiColorSelectionDialog.h" #include "GuiFilesModified.h" #include "GuiMainWindow.h" #include "GuiNameSelectionDialog.h" #include "QtListBoxSelectionDialog.h" #include "QtUtilities.h" #include "SectionFile.h" #include "global_variables.h" /** * Constructor. */ GuiAddCellsDialog::GuiAddCellsDialog(const DIALOG_MODE dm, QWidget* parent, bool modalFlag, Qt::WindowFlags f) : WuQDialog(parent, f) { setModal(modalFlag); dialogMode = dm; cellNameChanged = true; cellClassNameChanged = true; // // Vertical box for all items in dialog // QVBoxLayout* dialogLayout = new QVBoxLayout(this); dialogLayout->setMargin(5); dialogLayout->setSpacing(2); switch (dialogMode) { case DIALOG_MODE_ADD_CELLS: setWindowTitle("Add Cells"); break; case DIALOG_MODE_ADD_CONTOUR_CELLS: setWindowTitle("Add Contour Cells"); break; } // // Group box for cell data // QGroupBox* cellDataGroup = new QGroupBox("Cell Data"); QVBoxLayout* cellDataGroupLayout = new QVBoxLayout(cellDataGroup); dialogLayout->addWidget(cellDataGroup); // // Grid for labels, line edits, and pushbuttons // QGridLayout* cellGridLayout = new QGridLayout; cellDataGroupLayout->addLayout(cellGridLayout); // // label, line edit, and push button for cell name // cellGridLayout->addWidget(new QLabel("Name"), 0, 0); nameLineEdit = new QLineEdit; cellGridLayout->addWidget(nameLineEdit, 0, 1); QObject::connect(nameLineEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotCellNameChanged())); QPushButton* namePushButton = new QPushButton("Choose..."); cellGridLayout->addWidget(namePushButton, 0, 2); namePushButton->setAutoDefault(false); namePushButton->setFixedSize(namePushButton->sizeHint()); QObject::connect(namePushButton, SIGNAL(clicked()), this, SLOT(slotNameButton())); // // label, line edit, and push button for cell class // cellGridLayout->addWidget(new QLabel("Class"), 1, 0); classLineEdit = new QLineEdit; cellGridLayout->addWidget(classLineEdit, 1, 1); QObject::connect(classLineEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotCellClassNameChanged())); QPushButton* classPushButton = new QPushButton("Choose..."); cellGridLayout->addWidget(classPushButton, 1, 2); classPushButton->setAutoDefault(false); classPushButton->setFixedSize(namePushButton->sizeHint()); QObject::connect(classPushButton, SIGNAL(clicked()), this, SLOT(slotClassButton())); switch (dialogMode) { case DIALOG_MODE_ADD_CELLS: // // Auto project check box // autoProjectCellsCheckBox = new QCheckBox("Project Cells Automatically"); cellDataGroupLayout->addWidget(autoProjectCellsCheckBox); break; case DIALOG_MODE_ADD_CONTOUR_CELLS: break; } // // Comment label and combo box // QHBoxLayout* commentBoxLayout = new QHBoxLayout; cellDataGroupLayout->addLayout(commentBoxLayout); QLabel* commentLabel = new QLabel("Comment "); commentBoxLayout->addWidget(commentLabel); commentComboBox = new QComboBox; commentBoxLayout->addWidget(commentComboBox); QObject::connect(commentComboBox, SIGNAL(activated(int)), this, SLOT(slotCommentComboBox(int))); commentBoxLayout->setStretchFactor(commentLabel, 0); commentBoxLayout->setStretchFactor(commentComboBox, 100); // // comment text edit // commentTextEdit = new QTextEdit; cellDataGroupLayout->addWidget(commentTextEdit); commentTextEdit->setReadOnly(false); // // Horizontal layout for buttons // QHBoxLayout* buttonsLayout = new QHBoxLayout; dialogLayout->addLayout(buttonsLayout); buttonsLayout->setSpacing(2); // // Apply button // QPushButton* applyButton = new QPushButton("Apply"); applyButton->setAutoDefault(false); buttonsLayout->addWidget(applyButton); QObject::connect(applyButton, SIGNAL(clicked()), this, SLOT(slotApplyButton())); // // Close button connects to QDialogs close() slot. // QPushButton* closeButton = new QPushButton("Close"); closeButton->setAutoDefault(false); buttonsLayout->addWidget(closeButton); QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); QtUtilities::makeButtonsSameSize(applyButton, closeButton); updateDialog(); slotCommentComboBox(commentComboBox->count() - 1); } /** * Destructor. */ GuiAddCellsDialog::~GuiAddCellsDialog() { } /** * Called to add a contour cell at the specified position and section */ void GuiAddCellsDialog::addContourCellAtXYZ(const float xyz[3], const int sectionNumber) { if (DebugControl::getDebugOn()) { std::cout << "Adding cell at xyz " << "(" << xyz[0] << ", " << xyz[1] << "," << xyz[2] << ")" << std::endl; } // // See if name needs to be obtained // if (cellNameChanged) { if (getNameAndColor()) { return; } } // // See if class name needs to be obtained // if (cellClassNameChanged) { if (getCellClass()) { return; } } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); // // Get the cell file // ContourCellFile* cf = theMainWindow->getBrainSet()->getContourCellFile(); // // Get the comment number // int commentNumber = commentComboBox->currentIndex(); // // Comment number greater than number of comments is "none" // Comment number equal to number of comments is "new comment" // bool newCommentFlag = false; if (commentNumber > cf->getNumberOfStudyInfo()) { commentNumber = -1; } else { if (commentNumber == cf->getNumberOfStudyInfo()) { CellStudyInfo csi; commentNumber = cf->addStudyInfo(csi); commentComboBox->setCurrentIndex(commentNumber); newCommentFlag = true; } // // Get and store the comment text // CellStudyInfo csi; csi.setTitle(commentTextEdit->document()->toPlainText()); cf->setStudyInfo(commentNumber, csi); } // // Create the cell // CellData cd(cellName, xyz[0], xyz[1], xyz[2], sectionNumber, cellClassName, commentNumber, cellColorIndex); cd.setColorIndex(cellColorIndex); cf->addCell(cd); // // Display Cells and notify about cell changed // DisplaySettingsContours* dsc = theMainWindow->getBrainSet()->getDisplaySettingsContours(); dsc->setDisplayContourCells(true); GuiFilesModified fm; fm.setContourCellModified(); fm.setContourCellColorModified(); theMainWindow->fileModificationUpdate(fm); if (newCommentFlag) { updateDialog(); } // Update all displayed surfaces // // GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); } /** * Called to add a cell at the specified node number */ void GuiAddCellsDialog::addCellAtNodeNumber(const int nodeNumber) { if (DebugControl::getDebugOn()) { std::cout << "Adding cell at node " << nodeNumber << std::endl; } QString errorMessage; // // Check to see that a fiducial surface is available. // const BrainModelSurface* bms = theMainWindow->getBrainModelSurface(); if (bms == NULL) { errorMessage.append("There is no fiducial surface in the main window."); } else if (bms->getSurfaceType() != BrainModelSurface::SURFACE_TYPE_FIDUCIAL) { errorMessage.append("There is no fiducial surface in the main window."); } // // Is there an error ? // if (errorMessage.isEmpty() == false) { QMessageBox::critical(this, "Cell Error", errorMessage); return; } // // See if name needs to be obtained // if (cellNameChanged) { if (getNameAndColor()) { return; } } // // See if class name needs to be obtained // if (cellClassNameChanged) { if (getCellClass()) { return; } } // // Is there an error ? // if (errorMessage.isEmpty() == false) { QMessageBox::critical(this, "Cell Error", errorMessage); return; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); // // Get the position of the node // float x, y, z; const CoordinateFile* coordFile = bms->getCoordinateFile(); coordFile->getCoordinate(nodeNumber, x, y, z); // // Get the cell file // CellProjectionFile* cpf = theMainWindow->getBrainSet()->getCellProjectionFile(); // // Get the comment number // int commentNumber = commentComboBox->currentIndex(); // // Comment number greater than number of comments is "none" // Comment number equal to number of comments is "new comment" // bool newCommentFlag = false; if (commentNumber > cpf->getNumberOfStudyInfo()) { commentNumber = -1; } else { if (commentNumber == cpf->getNumberOfStudyInfo()) { CellStudyInfo csi; commentNumber = cpf->addStudyInfo(csi); commentComboBox->setCurrentIndex(commentNumber); newCommentFlag = true; } // // Get and store the comment text // CellStudyInfo csi; csi.setTitle(commentTextEdit->document()->toPlainText()); cpf->setStudyInfo(commentNumber, csi); } // // Get the displayed section number // int sectionNumber = 0; SectionFile* sectionFile = theMainWindow->getBrainSet()->getSectionFile(); DisplaySettingsSection* dss = theMainWindow->getBrainSet()->getDisplaySettingsSection(); if (sectionFile != NULL) { const int column = dss->getSelectedDisplayColumn(-1, -1); if ((column >= 0) && (column < sectionFile->getNumberOfColumns())) { sectionNumber = sectionFile->getSection(nodeNumber, column); } } int cellNumber = -1; // // Create the cell // CellData cd(cellName, x, y, z, sectionNumber, cellClassName, commentNumber, cellColorIndex); cd.setColorIndex(cellColorIndex); CellProjection cp; cp.copyData(cd); cpf->addCellProjection(cp); cellNumber = cpf->getNumberOfCellProjections() - 1; // // If cells should be automatically projected // if (autoProjectCellsCheckBox->isChecked()) { // // Create the cell file projector (cell same as cells) // CellFileProjector projector(bms); // // Project the new cell // projector.projectFile(cpf, cellNumber, CellFileProjector::PROJECTION_TYPE_FLIP_TO_MATCH_HEMISPHERE, 0.0, false, NULL); } // // Display Cells and notify about cell changed // DisplaySettingsCells* dsc = theMainWindow->getBrainSet()->getDisplaySettingsCells(); dsc->setDisplayCells(true); GuiFilesModified fm; fm.setCellModified(); fm.setCellColorModified(); theMainWindow->fileModificationUpdate(fm); if (newCommentFlag) { updateDialog(); } // Update all displayed surfaces // // GuiBrainModelOpenGL::updateAllGL(NULL); QApplication::restoreOverrideCursor(); } /** * update for cell projections. */ void GuiAddCellsDialog::updateCellProjectionMode() { CellProjectionFile* cpf = theMainWindow->getBrainSet()->getCellProjectionFile(); int currentCommentNumber = commentComboBox->currentIndex(); commentComboBox->clear(); if (currentCommentNumber >= cpf->getNumberOfStudyInfo()) { currentCommentNumber = -1; } const int numComments = cpf->getNumberOfStudyInfo(); for (int i = 0; i < numComments; i++) { const CellStudyInfo* cci = cpf->getStudyInfo(i); QString s(cci->getTitle()); if (s.length() > 30) { s.resize(30); } QString qs(QString::number(i)); qs.append(" - "); qs.append(s); commentComboBox->addItem(qs); } commentComboBox->addItem("New"); commentComboBox->addItem("None"); if ((commentComboBox->count() == 2) || (currentCommentNumber < 0)) { currentCommentNumber = commentComboBox->count() - 1; commentTextEdit->clear(); } commentTextEdit->setEnabled(false); // // load the comment's text // slotCommentComboBox(currentCommentNumber); } /** * update contour cells. */ void GuiAddCellsDialog::updateContourCellMode() { CellFile* cf = theMainWindow->getBrainSet()->getContourCellFile(); if (cf == NULL) { std::cout << "PROGRAM ERROR: NULL Cell File in GuiAddCellsDialog::updateDialog()" << std::endl; return; } int currentCommentNumber = commentComboBox->currentIndex(); commentComboBox->clear(); if (cf != NULL) { if (currentCommentNumber >= cf->getNumberOfStudyInfo()) { currentCommentNumber = -1; } const int numComments = cf->getNumberOfStudyInfo(); for (int i = 0; i < numComments; i++) { const CellStudyInfo* cci = cf->getStudyInfo(i); QString s(cci->getTitle()); if (s.length() > 30) { s.resize(30); } QString qs(QString::number(i)); qs.append(" - "); qs.append(s); commentComboBox->addItem(qs); } } commentComboBox->addItem("New"); commentComboBox->addItem("None"); if ((commentComboBox->count() == 2) || (currentCommentNumber < 0)) { currentCommentNumber = commentComboBox->count() - 1; commentTextEdit->clear(); } commentTextEdit->setEnabled(false); // // load the comment's text // slotCommentComboBox(currentCommentNumber); } /** * Update the dialog due to file changes. */ void GuiAddCellsDialog::updateDialog() { switch (dialogMode) { case DIALOG_MODE_ADD_CELLS: updateCellProjectionMode(); break; case DIALOG_MODE_ADD_CONTOUR_CELLS: updateContourCellMode(); break; } } /** * Get the class. Returns true if missing. */ bool GuiAddCellsDialog::getCellClass() { // // Get the class name // cellClassName = classLineEdit->text(); if (cellClassName.isEmpty()) { QMessageBox::critical(this, "Cell Error", "You must enter a class name."); return true; } cellClassNameChanged = false; return false; } /** * Get the name and the color. Returns true if an item is missing. */ bool GuiAddCellsDialog::getNameAndColor() { QString errorMessage; // // Get the name of the cell // cellName = nameLineEdit->text(); if (cellName.isEmpty()) { QMessageBox::critical(this, "Cell Error", "You must enter a cell name."); return true; } // // Find the matching color // bool colorMatch = false; ColorFile* colorFile = NULL; switch (dialogMode) { case DIALOG_MODE_ADD_CELLS: colorFile = theMainWindow->getBrainSet()->getCellColorFile(); break; case DIALOG_MODE_ADD_CONTOUR_CELLS: colorFile = theMainWindow->getBrainSet()->getContourCellColorFile(); break; } if (colorFile == NULL) { std::cout << "PROGRAM ERROR: NULL Color File in GuiAddCellsDialog::getNameAndColor()" << std::endl; return true; } cellColorIndex = colorFile->getColorIndexByName(cellName, colorMatch); // // Cell color may need to be created // bool createColor = false; if ((cellColorIndex >= 0) && (colorMatch == true)) { createColor = false; } else if ((cellColorIndex >= 0) && (colorMatch == false)) { QString msg("Use cell color \""); msg.append(colorFile->getColorNameByIndex(cellColorIndex)); msg.append("\" for cell "); msg.append(cellName); msg.append(" ?"); QString noButton("No, define color "); noButton.append(cellName); if (QMessageBox::question(this, "Use Partially Matching Color", msg, (QMessageBox::Yes | QMessageBox::No), QMessageBox::No) == QMessageBox::No) { createColor = true; } } else { createColor = true; } if (createColor) { QString title("Create Cell Color "); title.append(cellName); GuiColorSelectionDialog* csd = new GuiColorSelectionDialog(this, title, true, true, false, true); csd->exec(); // // Add new cell color // float pointSize = 2.0, lineSize = 1.0; unsigned char r, g, b, a; ColorFile::ColorStorage::SYMBOL symbol; csd->getColorInformation(r, g, b, a, pointSize, lineSize, symbol); colorFile->addColor(cellName, r, g, b, a, pointSize, lineSize, symbol); cellColorIndex = colorFile->getNumberOfColors() - 1; } cellNameChanged = false; return false; } /** * Called when apply button is pressed. */ void GuiAddCellsDialog::slotApplyButton() { if (getNameAndColor()) { return; } if (getCellClass()) { return; } switch (dialogMode) { case DIALOG_MODE_ADD_CELLS: theMainWindow->getBrainModelOpenGL()->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_CELL_ADD); break; case DIALOG_MODE_ADD_CONTOUR_CELLS: theMainWindow->getBrainModelOpenGL()->setMouseMode(GuiBrainModelOpenGL::MOUSE_MODE_CONTOUR_CELL_ADD); break; } } /** * Called when button name choose is pressed. */ void GuiAddCellsDialog::slotNameButton() { GuiNameSelectionDialog nsd(this); if (nsd.exec() == QDialog::Accepted) { const QString name(nsd.getNameSelected()); if (name.isEmpty() == false) { nameLineEdit->setText(name); cellNameChanged = true; } } } /** * Called when button comment choose is pressed. */ void GuiAddCellsDialog::slotClassButton() { int numClasses = 0; std::vector classNames; switch (dialogMode) { case DIALOG_MODE_ADD_CELLS: { CellProjectionFile* cf = theMainWindow->getBrainSet()->getCellProjectionFile(); numClasses = cf->getNumberOfCellClasses(); for (int i = 0; i < numClasses; i++) { classNames.push_back(cf->getCellClassNameByIndex(i)); } } break; case DIALOG_MODE_ADD_CONTOUR_CELLS: { CellFile* cf = theMainWindow->getBrainSet()->getContourCellFile(); numClasses = cf->getNumberOfCellClasses(); for (int i = 0; i < numClasses; i++) { classNames.push_back(cf->getCellClassNameByIndex(i)); } } break; } if (classNames.size() > 0) { QtListBoxSelectionDialog lbsd(this, "Cell Classes", "", classNames, 0); if (lbsd.exec() == QDialog::Accepted) { classLineEdit->setText(lbsd.getSelectedText()); cellClassNameChanged = true; } } else { QMessageBox::information(this, "No Classes", "Cell File has no classes"); } } /** * Called when comment combo box item is selected. */ void GuiAddCellsDialog::slotCommentComboBox(int itemNumber) { commentComboBox->setCurrentIndex(itemNumber); commentTextEdit->setPlainText(""); switch (dialogMode) { case DIALOG_MODE_ADD_CELLS: { CellProjectionFile* cf = theMainWindow->getBrainSet()->getCellProjectionFile(); if (cf != NULL) { if (itemNumber < cf->getNumberOfStudyInfo()) { const CellStudyInfo* csi = cf->getStudyInfo(itemNumber); commentTextEdit->setPlainText(csi->getTitle()); } } } break; case DIALOG_MODE_ADD_CONTOUR_CELLS: { CellFile* cf = theMainWindow->getBrainSet()->getContourCellFile(); if (cf != NULL) { if (itemNumber < cf->getNumberOfStudyInfo()) { const CellStudyInfo* csi = cf->getStudyInfo(itemNumber); commentTextEdit->setPlainText(csi->getTitle()); } } } break; } if (itemNumber < (commentComboBox->count() - 1)) { commentTextEdit->setEnabled(true); } else { commentTextEdit->setEnabled(false); } } /** * Called when cell name line edit is changed. */ void GuiAddCellsDialog::slotCellNameChanged() { cellNameChanged = true; } /** * Called when cell class name line edit is changed. */ void GuiAddCellsDialog::slotCellClassNameChanged() { cellClassNameChanged = true; } caret-5.6.4~dfsg.1.orig/caret/CommunicatorClientFIV.h0000664000175000017500000000357311572067322022204 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_COMMUNICATOR_CLIENT_FIV_H__ #define __VE_COMMUNICATOR_CLIENT_FIV_H__ #include "CommunicatorClientBase.h" #include "CoordinateFile.h" #include "TransformationMatrixFile.h" /// This class is used to communicate with the FIV program. class CommunicatorClientFIV : public CommunicatorClientBase { Q_OBJECT public: /// Constructor CommunicatorClientFIV(); /// Destructor ~CommunicatorClientFIV(); /// send a node highlight to FIV void sendNodeHighlightToFIV(const int nodeNumber); public slots: /// called when the socket is successfully connected //void socketConnected(); private: /// create the control message void createControlMessage(); /// Get message from the CommunicatorClientBase void processReceivedMessage(const QString& msg); /// process a voxel highlight request from FIV void processVoxelHighlightFromFIV(const int i, const int j, const int k); }; #endif caret-5.6.4~dfsg.1.orig/caret/CommunicatorClientFIV.cxx0000664000175000017500000001306211572067322022551 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include "CommunicatorClientFIV.h" #include "DebugControl.h" #include "GuiBrainModelOpenGL.h" #include "GuiIdentifyDialog.h" #include "GuiMainWindow.h" #include "StringUtilities.h" #include "global_variables.h" /** * Constructor. */ CommunicatorClientFIV::CommunicatorClientFIV() : CommunicatorClientBase("FIV", "localhost", 6440, // control port 6445, // data port true, // request updates true, // allow data port editing true) // allow request updates editing { // // Create the control message and assign it to the base communicator // createControlMessage(); } /** * Destructor. */ CommunicatorClientFIV::~CommunicatorClientFIV() { } /** * Create the first message that is to be sent to the program that we are connecting to */ void CommunicatorClientFIV::createControlMessage() { // // Create string to send to FIV to give data port and other info. // Multiple strings are separated with '\n'. // QString msg; // // IOCHAN means use this for the data channel // char str[256]; sprintf(str, "TAL_PORT tcp:%s:%d", hostName.toAscii().constData(), dataPortNumber); msg.append(str); msg.append("\n"); setControlMessage(msg); } /** * Receive the messages from the FIV program */ void CommunicatorClientFIV::processReceivedMessage(const QString& msg) { // // Incoming data may have more than one message with the messages // separated by a newline. // std::vector messages; StringUtilities::token(msg, "\n", messages); for (unsigned int i = 0; i < messages.size(); i++) { if (DebugControl::getDebugOn()) std::cout << "FIV Message: " << messages[i].toAscii().constData() << std::endl; std::vector tokens; StringUtilities::token(messages[i], " \t\n", tokens); if (tokens.size() > 0) { if (tokens[0] == "TAL_XYZ") { if (tokens.size() > 3) { processVoxelHighlightFromFIV(tokens[1].toInt(), tokens[2].toInt(), tokens[3].toInt()); } } } } } /** * Process a voxel highlight request from FIV. */ void CommunicatorClientFIV::processVoxelHighlightFromFIV(const int i, const int j, const int k) { if (DebugControl::getDebugOn()) std::cout << "Voxel highlight: " << i << " " << j << " " << k << std::endl; BrainModelSurface* bms = theMainWindow->getBrainSet()->getActiveFiducialSurface(); if (bms == NULL) { QMessageBox::critical(theMainWindow, "FIV Comm Error", "There is no Fiducial Coordinate file which is needed for\n" "successful communication with FIV. The coordinate file\n" "must be in Talairach Space."); return; } const CoordinateFile* cf = bms->getCoordinateFile(); const int nodeNumber = cf->getCoordinateIndexClosestToPoint(i, j, k); if (DebugControl::getDebugOn()) std::cout << "closest node " << nodeNumber << std::endl; if (nodeNumber > 0) { theMainWindow->identifyNodeFromRemoteProgram(nodeNumber); } } /** * Send a voxel highlight to FIV by converting a node position to a voxel position. */ void CommunicatorClientFIV::sendNodeHighlightToFIV(const int nodeNumber) { if (socket->state() == QTcpSocket::ConnectedState) { BrainModelSurface* bms = theMainWindow->getBrainSet()->getActiveFiducialSurface(); if (bms == NULL) { QMessageBox::critical(theMainWindow, "FIV Comm Error", "There is no Fiducial Coordinate file which is needed for\n" "successful communication with FIV. The coordinate file\n" "must be in Talairach Space."); return; } const CoordinateFile* cf = bms->getCoordinateFile(); if ((nodeNumber >= 0) && (nodeNumber < cf->getNumberOfCoordinates())) { float x, y, z; cf->getCoordinate(nodeNumber, x, y, z); int i = static_cast(x); int j = static_cast(y); int k = static_cast(z); std::ostringstream str; str << "TAL_XYZ " << i << " " << j << " " << k << std::ends; sendMessage(str.str().c_str()); } } } caret-5.6.4~dfsg.1.orig/caret/CommunicatorClientBase.h0000664000175000017500000001207211572067322022424 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_COMMUNICATOR_CLIENT_BASE_H__ #define __VE_COMMUNICATOR_CLIENT_BASE_H__ #include #include #include /// This base class is used for communicating with other programs /// via sockets. You may not instatiate this class, you must derive /// from it. class CommunicatorClientBase : public QObject { Q_OBJECT public: /// get the host name QString getHostName() const { return hostName; } /// set the host name void setHostName(const QString& name) { hostName = name; } /// get the control port number int getControlPortNumber() const { return controlPortNumber; } /// set the control port number void setControlPortNumber(const int portNumber) { controlPortNumber = portNumber; } /// get the data port number int getDataPortNumber() const { return dataPortNumber; } /// set the control port number void setDataPortNumber(const int portNumber) { dataPortNumber = portNumber; } /// get the request updates flag bool getRequestUpdates() const { return requestUpdates; } /// set the request updates flag void setRequestUpdates(const bool getUpdates) { requestUpdates = getUpdates; } /// get the control message QString getControlMessage() const { return controlMessage; } /// set the control message void setControlMessage(const QString& msg) { controlMessage = msg; } /// destructor virtual ~CommunicatorClientBase(); /// print the status of the socket void printSocketStatus(); public slots: /// open a connection void openConnection(); /// close a connection void closeConnection(); signals: /// signal emitted when the connection is successfully made void socketConnectionEstablished(); private slots: /// open the data channel void openDataChannel(); /// called when the socket successfully connects void socketConnectedSlot(); /// called when the socket connection is closed void socketConnectionClosedSlot(); /// called when the socket has data to be read void socketReadyForReadingSlot(); /// called when the socket has an error void socketErrorSlot(QAbstractSocket::SocketError error); protected: enum CONNECTION_STATUS { CONNECTION_OPENING_CONTROL_PORT, CONNECTION_SENDING_CONTROL_INFORMATION, CONNECTION_OPENING_DATA_PORT, CONNECTION_DATA_PORT_OPEN, CONNECTION_CLOSED }; /// Constructor CommunicatorClientBase(const QString& programNameIn, const QString& defaultHostName, const int defaultControlPort, const int defaultDataPort, const bool defaultRequestUpdates, const bool allowUserToEditDataPort, const bool allowUserToEditRequestUpdates); /// Process a received message. This method must be implemented /// by the deriving class. virtual void processReceivedMessage(const QString& msg) = 0; /// send a message over the socket void sendMessage(const QString& message); /// the connection status CONNECTION_STATUS connectionStatus; /// name of program connecting to QString programName; /// the host name QString hostName; /// the control port number int controlPortNumber; /// the data port number int dataPortNumber; /// request updates flag bool requestUpdates; /// socket used for communication QTcpSocket* socket; /// control message that is sent when establishing a connection QString controlMessage; private: /// display the data port for user editing in the connection dialog bool displayDataPortInConnectDialog; /// display the request updates checkbox for user editing in the connection dialog bool displayRequestUpdatesInConnectDialog; }; #endif caret-5.6.4~dfsg.1.orig/caret/CommunicatorClientBase.cxx0000664000175000017500000002624511572067322023006 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include "CommunicatorClientBase.h" #include "DebugControl.h" #include "GuiCommunicatorClientConnectDialog.h" #include "GuiMainWindow.h" #include "global_variables.h" /** * Constructor. * programName - name of programm connecting to (eg. AFNI). * defaultHostName - the name of the host to connect. * defaultControlPort - the control port of the program connecting to. * defaultDataPort - the data port of the program connecting to. * defaultRequestUpdates - request other program send updates back. * allowUserToEditDataPort - allow the user to change the data port. * allowUserToEditRequestUpdates - allow user to choose to receive updates. */ CommunicatorClientBase::CommunicatorClientBase(const QString& programNameIn, const QString& defaultHostName, const int defaultControlPort, const int defaultDataPort, const bool defaultRequestUpdates, const bool allowUserToEditDataPort, const bool allowUserToEditRequestUpdates) { programName = programNameIn; hostName = defaultHostName; controlPortNumber = defaultControlPort; dataPortNumber = defaultDataPort; requestUpdates = defaultRequestUpdates; displayDataPortInConnectDialog = allowUserToEditDataPort, displayRequestUpdatesInConnectDialog = allowUserToEditRequestUpdates; connectionStatus = CONNECTION_CLOSED; // // Create a socket // socket = new QTcpSocket(this); // // Setup some of the sockets signals // QObject::connect(socket, SIGNAL(connected()), this, SLOT(socketConnectedSlot())); QObject::connect(socket, SIGNAL(disconnected()), this, SLOT(socketConnectionClosedSlot())); QObject::connect(socket, SIGNAL(readyRead()), this, SLOT(socketReadyForReadingSlot())); QObject::connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketErrorSlot(QAbstractSocket::SocketError))); // // Setup signals available to deriving class // QObject::connect(socket, SIGNAL(connected()), this, SIGNAL(socketConnectionEstablished())); } /** * Destructor. */ CommunicatorClientBase::~CommunicatorClientBase() { } /** * open a connection */ void CommunicatorClientBase::openConnection() { // // Allow user to modify communication parameters // GuiCommunicatorClientConnectDialog* cccd = new GuiCommunicatorClientConnectDialog(theMainWindow, programName, hostName, controlPortNumber, dataPortNumber, requestUpdates, displayDataPortInConnectDialog, displayRequestUpdatesInConnectDialog); // // Did user press OK button ? // if (cccd->exec() == QDialog::Accepted) { // // Get the parameters from the dialog // hostName = cccd->getHostName(); controlPortNumber = cccd->getControlPort(); if (displayDataPortInConnectDialog) { dataPortNumber = cccd->getDataPort(); } if (displayRequestUpdatesInConnectDialog) { requestUpdates = cccd->getRequestUpdates(); } // // Connection Status // connectionStatus = CONNECTION_OPENING_CONTROL_PORT; // // Try connecting to the host // if (DebugControl::getDebugOn()) std::cout << "Trying to connect to " << hostName.toAscii().constData() << " on port " << controlPortNumber << std::endl; socket->connectToHost(hostName, controlPortNumber); } } /** * Print the status of the socket. */ void CommunicatorClientBase::printSocketStatus() { if (DebugControl::getDebugOn() == false) { return; } std::cout << "Checking connection, status: "; switch(socket->state()) { case QAbstractSocket::UnconnectedState: std::cout << " idle" << std::endl; break; case QAbstractSocket::HostLookupState: std::cout << " host lookup" << std::endl; break; case QAbstractSocket::ConnectingState: std::cout << " connecting" << std::endl; break; case QAbstractSocket::ConnectedState: std::cout << " connected" << std::endl; break; case QAbstractSocket::BoundState: std::cout << " bound" << std::endl; break; case QAbstractSocket::ClosingState: std::cout << " closing" << std::endl; break; case QAbstractSocket::ListeningState: std::cout << " listening" << std::endl; break; default: std::cout << " unknown" << std::endl; break; } } /** * Close a connection. */ void CommunicatorClientBase::closeConnection() { if (socket != NULL) { socket->close(); } connectionStatus = CONNECTION_CLOSED; } /** * Called when the socket achieves a connection. */ void CommunicatorClientBase::socketConnectedSlot() { if (DebugControl::getDebugOn()) std::cout << "Socket has connected" << std::endl; printSocketStatus(); // // Connection Status // if (connectionStatus == CONNECTION_OPENING_CONTROL_PORT) { // // send control information, flush, and close control channel. // connectionStatus = CONNECTION_SENDING_CONTROL_INFORMATION; sendMessage(controlMessage); socket->flush(); socket->close(); // // Allow server time to set up data channel and then connect with data channel. // QTimer::singleShot(3000, this, SLOT(openDataChannel())); } else if (connectionStatus == CONNECTION_OPENING_DATA_PORT) { connectionStatus = CONNECTION_DATA_PORT_OPEN; if (DebugControl::getDebugOn()) std::cout << "Data channel now open" << std::endl; } } /** * Called to open data channel. */ void CommunicatorClientBase::openDataChannel() { if (connectionStatus == CONNECTION_SENDING_CONTROL_INFORMATION) { // // Reopen socket on the data port // if (DebugControl::getDebugOn()) std::cout << "Trying to connect to " << hostName.toAscii().constData() << " on port " << dataPortNumber << std::endl; socket->connectToHost(hostName, dataPortNumber); connectionStatus = CONNECTION_OPENING_DATA_PORT; } } /** * Called when the socket is closed. */ void CommunicatorClientBase::socketConnectionClosedSlot() { if (DebugControl::getDebugOn()) std::cout << "Socket has closed connection" << std::endl; // // After control information is received, server closes connection. // if (connectionStatus == CONNECTION_SENDING_CONTROL_INFORMATION) { // // Reopen socket on the data port // //if (DebugControl::getDebugOn()) std::cout << "Trying to connect to " << hostName << " on port " << dataPortNumber << std::endl; //socket->connectToHost(hostName, dataPortNumber); //connectionStatus = CONNECTION_OPENING_DATA_PORT; } else { connectionStatus = CONNECTION_CLOSED; } } /** * Called when the socket has data for reading. */ void CommunicatorClientBase::socketReadyForReadingSlot() { const int BUF_SIZE = 4096; char data[BUF_SIZE+1]; if (DebugControl::getDebugOn()) std::cout << "Socket has data for reading" << std::endl; while (socket->bytesAvailable() > 0) { const int numBytes = socket->bytesAvailable() ; if (DebugControl::getDebugOn()) std::cout << "Bytes for reading: " << numBytes << std::endl; socket->read(data, BUF_SIZE); data[numBytes] = '\0'; if (DebugControl::getDebugOn()) std::cout << " Read data: " << data << std::endl; processReceivedMessage(data); } } /** * Called when the socket has an error. */ void CommunicatorClientBase::socketErrorSlot(QAbstractSocket::SocketError errorCode) { QString msg("Communication error:"); switch(errorCode) { case QTcpSocket::ConnectionRefusedError: msg.append(" connection refused"); break; case QTcpSocket::RemoteHostClosedError: msg.append(" remote host closed error"); break; case QTcpSocket::HostNotFoundError: msg.append(" host not found"); break; case QTcpSocket::SocketAccessError: msg.append(" socket access error"); break; case QTcpSocket::SocketResourceError: msg.append(" socket resource error"); break; case QTcpSocket::SocketTimeoutError: msg.append(" socket timeout error"); break; case QTcpSocket::DatagramTooLargeError: msg.append(" datagram too large error"); break; case QTcpSocket::NetworkError: msg.append(" network error"); break; case QTcpSocket::AddressInUseError: msg.append(" address in use error"); break; case QTcpSocket::SocketAddressNotAvailableError: msg.append(" socket address not available error"); break; case QTcpSocket::UnsupportedSocketOperationError: msg.append(" unsupported socket operation error"); break; case QTcpSocket::UnknownSocketError: msg.append(" unknown socket error"); break; case QTcpSocket::SslHandshakeFailedError: msg.append(" SSL Handshake Failed error"); break; case QTcpSocket::ProxyAuthenticationRequiredError: msg.append(" proxy authentication required error"); break; case QTcpSocket::UnfinishedSocketOperationError: msg.append(" unfinished socket operation error"); break; } if (DebugControl::getDebugOn()) std::cout << msg.toAscii().constData() << std::endl; QMessageBox::critical(theMainWindow, "Communication Error", msg); } /** * Send a message over the socket */ void CommunicatorClientBase::sendMessage(const QString& message) { //std::cout << std::endl << "Sending message to server: " << message << std::endl << std::endl; // Note: Include zero at end of string when setting length socket->write(message.toAscii().constData(), (message.length() + 1)); } caret-5.6.4~dfsg.1.orig/caret/CommunicatorClientAFNI.h0000664000175000017500000000442311572067322022270 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #ifndef __VE_COMMUNICATOR_CLIENT_AFNI_H__ #define __VE_COMMUNICATOR_CLIENT_AFNI_H__ #include "CommunicatorClientBase.h" #include "CoordinateFile.h" #include "TransformationMatrixFile.h" /// This class is used to communicate with the AFNI program. class CommunicatorClientAFNI : public CommunicatorClientBase { Q_OBJECT public: /// Constructor CommunicatorClientAFNI(); /// Destructor ~CommunicatorClientAFNI(); /// send a node highlight to AFNI void sendNodeHighlightToAFNI(const int nodeNumber); public slots: /// called when the socket is successfully connected //void socketConnected(); private: /// create the control message void createControlMessage(); /// Find the transformation matrix for the AFNI .HEAD file. void findTransformationMatrix(const QString& afniHeadFileName); /// Get message from the CommunicatorClientBase void processReceivedMessage(const QString& msg); /// process a voxel highlight request from AFNI void processVoxelHighlightFromAFNI(const int i, const int j, const int k); /// Coordinate file for converting between voxel and surface spaces CoordinateFile coordinateFile; /// Transformation matrix used for converting between voxel and surface spaces. TransformationMatrix transformMatrix; }; #endif caret-5.6.4~dfsg.1.orig/caret/CommunicatorClientAFNI.cxx0000664000175000017500000001764711572067322022657 0ustar michaelmichael/*LICENSE_START*/ /* * Copyright 1995-2002 Washington University School of Medicine * * http://brainmap.wustl.edu * * This file is part of CARET. * * CARET is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * CARET is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CARET; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*LICENSE_END*/ #include #include #include #include #include "CommunicatorClientAFNI.h" #include "DebugControl.h" #include "GuiBrainModelOpenGL.h" #include "GuiIdentifyDialog.h" #include "GuiMainWindow.h" #include "FileUtilities.h" #include "StringUtilities.h" #include "global_variables.h" /** * Constructor. */ CommunicatorClientAFNI::CommunicatorClientAFNI() : CommunicatorClientBase("AFNI", "localhost", 7955, // control port 8009, // data port true, // request updates true, // allow data port editing true) // allow request updates editing { // // Create the control message and assign it to the base communicator // createControlMessage(); } /** * Destructor. */ CommunicatorClientAFNI::~CommunicatorClientAFNI() { } /** * Create the first message that is to be sent to the program that we are connecting to */ void CommunicatorClientAFNI::createControlMessage() { // // Create string to send to AFNI to give data port and other info. // Multiple strings are separated with '\n'. // QString msg; // // PONAME means use this string for informative messages // msg.append("PONAME Caret5-to-AFNI"); msg.append("\n"); // // IOCHAN means use this for the data channel // char str[256]; sprintf(str, "tcp:%s:%d", hostName.toAscii().constData(), dataPortNumber); msg.append("IOCHAN "); msg.append(str); msg.append("\n"); // // Do not request acknowlegements // msg.append("NO_ACK"); msg.append("\n"); if (requestUpdates) { // // Request volume crosshair updates // msg.append("DSET_IJK_DELTA"); msg.append("\n"); // // Request notification when structural volume changes // msg.append("UNDERLAY_DELTA"); msg.append("\n"); } setControlMessage(msg); } /** * Receive the messages from the AFNI program */ void CommunicatorClientAFNI::processReceivedMessage(const QString& msg) { // // Incoming data may have more than one message with the messages // separated by a newline. // std::vector messages; StringUtilities::token(msg, "\n", messages); for (unsigned int i = 0; i < messages.size(); i++) { if (DebugControl::getDebugOn()) std::cout << "AFNI Message: " << messages[i].toAscii().constData() << std::endl; std::vector tokens; StringUtilities::token(messages[i], " \t\n", tokens); if (tokens.size() > 0) { if (tokens[0] == "UNDERLAY") { if (tokens.size() > 1) { findTransformationMatrix(tokens[1]); } else { } } else if (tokens[0] == "DSET_IJK") { if (tokens.size() > 3) { processVoxelHighlightFromAFNI(tokens[1].toInt(), tokens[2].toInt(), tokens[3].toInt()); } } } } } /** * Find the appropriate transformation matrix for the AFNI .HEAD file. */ void CommunicatorClientAFNI::findTransformationMatrix(const QString& afniHeadFileNameIn) { if (afniHeadFileNameIn.isEmpty()) { return; } const QString fileName(FileUtilities::basename(afniHeadFileNameIn)); bool foundTransformationMatrix = false; bool foundCoordinateFile = false; QString coordFileName; TransformationMatrixFile* tmf = theMainWindow->getBrainSet()->getTransformationMatrixFile(); for (int i = 0; i < tmf->getNumberOfMatrices(); i++) { TransformationMatrix* tm = tmf->getTransformationMatrix(i); if (tm->getMatrixTargetVolumeFileName() == fileName) { if (DebugControl::getDebugOn()) std::cout << "Found proper transformation matrix" << std::endl; foundTransformationMatrix = true; transformMatrix = *tm; coordFileName = tm->getMatrixFiducialCoordFileName(); for (int i = 0; i < theMainWindow->getBrainSet()->getNumberOfBrainModels(); i++) { BrainModel* bm = theMainWindow->getBrainSet()->getBrainModel(i); if (bm->getModelType() == BrainModel::BRAIN_MODEL_SURFACE) { BrainModelSurface* bms = dynamic_cast(bm); CoordinateFile* cf = bms->getCoordinateFile(); if (FileUtilities::basename(cf->getFileName()) == coordFileName) { foundCoordinateFile = true; coordinateFile = *cf; if (DebugControl::getDebugOn()) std::cout << "Found coordinate file" << std::endl; } } } break; } } if (foundTransformationMatrix == false) { QString msg("Unable to find a transformation matrix for volume "); msg.append(fileName); QMessageBox::critical(theMainWindow, "AFNI Communication Error", msg); } else if (foundCoordinateFile == false) { QString msg("Coordinate file needed for AFNI communication not loaded "); msg.append(coordFileName); QMessageBox::critical(theMainWindow, "AFNI Communication Error", msg); } } /** * Process a voxel highlight request from AFNI. */ void CommunicatorClientAFNI::processVoxelHighlightFromAFNI(const int i, const int j, const int k) { if (DebugControl::getDebugOn()) std::cout << "Voxel highlight: " << i << " " << j << " " << k << std::endl; double p[4] = { i, j, k, 1.0 }; transformMatrix.inverseMultiplyPoint(p); if (DebugControl::getDebugOn()) std::cout << "coordinate: " << p[0] << " " << p[1] << " " << p[2] << std::endl; if (coordinateFile.getNumberOfCoordinates() > 0) { const int nodeNumber = coordinateFile.getCoordinateIndexClosestToPoint(p[0], p[1], p[2]); if (DebugControl::getDebugOn()) std::cout << "closest node " << nodeNumber << std::endl; if (nodeNumber > 0) { theMainWindow->identifyNodeFromRemoteProgram(nodeNumber); } } } /** * Send a voxel highlight to AFNI by converting a node position to a voxel position. */ void CommunicatorClientAFNI::sendNodeHighlightToAFNI(const int nodeNumber) { if (socket->state() == QTcpSocket::ConnectedState) { if ((coordinateFile.getNumberOfCoordinates() > 0) && (nodeNumber < coordinateFile.getNumberOfCoordinates())) { float x, y, z; coordinateFile.getCoordinate(nodeNumber, x, y, z); double p[4] = { x, y, z, 1.0 }; transformMatrix.multiplyPoint(p); int i = static_cast(p[0]); int j = static_cast(p[1]); int k = static_cast(p[2]); if ((i >= 0) && (j >= 0) && (k >= 0)) { std::ostringstream str; str << "DSET_IJK_SET " << i << " " << j << " " << k << std::ends; sendMessage(str.str().c_str()); } } } } caret-5.6.4~dfsg.1.orig/caret/.project0000664000175000017500000000467211572067322017337 0ustar michaelmichael caret org.eclipse.wst.common.project.facet.core.builder org.eclipse.cdt.managedbuilder.core.genmakebuilder clean,full,incremental, ?name? org.eclipse.cdt.make.core.append_environment true org.eclipse.cdt.make.core.autoBuildTarget all org.eclipse.cdt.make.core.buildArguments org.eclipse.cdt.make.core.buildCommand make org.eclipse.cdt.make.core.cleanBuildTarget clean org.eclipse.cdt.make.core.contents org.eclipse.cdt.make.core.activeConfigSettings org.eclipse.cdt.make.core.enableAutoBuild false org.eclipse.cdt.make.core.enableCleanBuild true org.eclipse.cdt.make.core.enableFullBuild true org.eclipse.cdt.make.core.fullBuildTarget all org.eclipse.cdt.make.core.stopOnError true org.eclipse.cdt.make.core.useDefaultBuildCmd true org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder org.eclipse.cdt.core.cnature org.eclipse.cdt.core.ccnature org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature org.eclipse.wst.common.project.facet.core.nature caret-5.6.4~dfsg.1.orig/caret/.cproject0000664000175000017500000002070211572067322017472 0ustar michaelmichael make all true true true caret-5.6.4~dfsg.1.orig/build_dos_gcc.bat0000755000175000017500000000066711572067322020043 0ustar michaelmichaelcd caret_common mingw32-make cd .. cd caret_statistics mingw32-make cd .. cd caret_widgets mingw32-make cd .. cd caret_uniformize mingw32-make cd .. cd caret_files mingw32-make cd .. cd caret_vtk4_classes mingw32-make cd .. cd caret_brain_set mingw32-make cd .. cd caret_command_operations mingw32-make cd .. cd caret mingw32-make cd .. cd caret_command mingw32-make cd .. cd caret_edit mingw32-make cd .. caret-5.6.4~dfsg.1.orig/Makefile.john0000664000175000017500000000531111572067322017156 0ustar michaelmichaelSHELL = /bin/sh PROGS = caret \ caret_command \ caret_edit LIBS = \ caret_statistics \ caret_common \ caret_files \ caret_brain_set \ caret_command_operations \ caret_uniformize \ caret_widgets \ caret_vtk4_classes DIRS = $(LIBS) $(PROGS) all: @echo "" @echo "" @echo "Use \"make qmake-static\" to create the makefiles with static libraries." @echo "Use \"make qmake-dynamic\" to create the makefiles with dynamic libraries." @echo "Use \"make build\" to build the libraries and executables." @echo "Use \"make clean\" to remove executables, libraries, and objects." @echo "" @echo "Use \"make doc\" to build the Doxygen generated documentation." @echo "" doc: doxygen Doxyfile build: @for i in ${DIRS} ; do \ echo "making " $$i ; \ cd $$i ; \ make ; \ cd .. ; \ done build8: @for i in ${DIRS} ; do \ echo "making " $$i ; \ cd $$i ; \ make -j 8; \ cd .. ; \ done build4: @for i in ${DIRS} ; do \ echo "making " $$i ; \ cd $$i ; \ make -j 4; \ cd .. ; \ done build2: @for i in ${DIRS} ; do \ echo "making " $$i ; \ cd $$i ; \ make -j 2; \ cd .. ; \ done clean: @for i in ${DIRS} ; do \ echo "cleaning " $$i ; \ cd $$i ; \ make clean ; \ cd .. ; \ done qmake-static: @for i in ${LIBS} ; do \ echo "creating makefile for static libs with qmake for " $$i ; \ cd $$i ; \ qmake ; \ cd .. ; \ done @for i in ${PROGS} ; do \ echo "creating makefile with qmake for " $$i ; \ cd $$i ; \ qmake ; \ cd .. ; \ done qmake-dynamic: @for i in ${LIBS} ; do \ echo "creating makefile for dynamic libs with qmake for " $$i ; \ cd $$i ; \ qmake "CONFIG+=dll"; \ cd .. ; \ done @for i in ${PROGS} ; do \ echo "creating makefile with qmake for " $$i ; \ cd $$i ; \ qmake ; \ cd .. ; \ done rebuild: make qmake-static make build rebuild8: make qmake-static make build8 rebuild4: make qmake-static make build4 rebuild2: make qmake-static make build2 check_env: @cnt="" @if [ "${VTK_INC_DIR}" == "" ]; then \ echo "Environment variable VTK_INC_DIR not set" ; \ cnt="1" ; \ fi ; @if [ "${VTK_LIB_DIR}" == "" ]; then \ echo "Environment variable VTK_LIB_DIR not set" ; \ cnt="1" ; \ fi ; @if [ "${NETCDF_INC_DIR}" == "" ]; then \ echo "Environment variable NETCDF_INC_DIR not set" ; \ cnt="1" ; \ fi ; @if [ "${NETCDF_LIB_DIR}" == "" ]; then \ echo "Environment variable NETCDF_LIB_DIR not set" ; \ cnt="1" ; \ fi ; # @if [ "$cnt" != "" ]; then \ # echo "Required environment variables are not set" ; \ # fi ; test: echo "Testing" ; \ cd testing ; \ ./run_test.sh ; \ cd .. ; caret-5.6.4~dfsg.1.orig/Makefile0000664000175000017500000001343311572067322016225 0ustar michaelmichaelSHELL = /bin/sh PROGS_CMD = caret_command PROGS_GUI = \ caret \ caret_edit PROGS = $(PROGS_CMD) \ $(PROGS_GUI) UBUNTULIBS = \ caret_statistics \ caret_common \ caret_files \ caret_brain_set \ caret_command_operations \ caret_uniformize \ caret_widgets \ caret_cifti LIBS = $(UBUNTULIBS) caret_vtk4_classes DIRS = $(LIBS) $(PROGS) DIRS_NO_GUI = $(LIBS) $(PROGS_CMD) UBUNTUDIRS = $(UBUNTULIBS) $(PROGS) all: @echo "" @echo "" @echo "Use \"make qmake-debug\"\n to create the makefiles with static libraries for debug." @echo "Use \"make qmake-debug-dynamic\"\n to create the makefiles with dynamic libraries for debug." @echo "Use \"make qmake-profile\"\n to create the makefiles with static libraries for profiling/debugging." @echo "Use \"make qmake-profile-dynamic\" \n to create the makefiles with dynamic libraries for profiling/debugging." @echo "Use \"make qmake-release\"\n to create the makefiles with static libraries for release." @echo "Use \"make qmake-release-dynamic\"\n to create the makefiles with dynamic libraries for release." @echo "Use \"make build\"\n to build the libraries and executables." @echo "Use \"make clean\"\n to remove executables, libraries, and objects." @echo "" @echo "Use \"make doc\" to build the Doxygen generated documentation." @echo "" doc: doxygen Doxyfile build: @for i in ${DIRS} ; do \ echo "making " $$i ; \ cd $$i ; \ make ; \ cd .. ; \ done build16: @for i in ${DIRS} ; do \ echo "making " $$i ; \ cd $$i ; \ make -j 16; \ cd .. ; \ done build8: @for i in ${DIRS} ; do \ echo "making " $$i ; \ cd $$i ; \ make -j 8; \ cd .. ; \ done build4: @for i in ${DIRS} ; do \ echo "making " $$i ; \ cd $$i ; \ make -j 4; \ cd .. ; \ done build2: @for i in ${DIRS} ; do \ echo "making " $$i ; \ cd $$i ; \ make -j 2; \ cd .. ; \ done build-no-gui: @for i in ${DIRS_NO_GUI} ; do \ echo "making " $$i ; \ cd $$i ; \ make ; \ cd .. ; \ done build4-no-gui: @for i in ${DIRS_NO_GUI} ; do \ echo "making " $$i ; \ cd $$i ; \ make -j 4; \ cd .. ; \ done clean: @for i in ${DIRS} ; do \ echo "cleaning " $$i ; \ cd $$i ; \ make clean ; \ cd .. ; \ done distclean: @for i in ${DIRS} ; do \ echo "cleaning " $$i ; \ cd $$i ; \ make distclean ; \ cd .. ; \ done qmake-debug: @for i in ${LIBS} ; do \ echo "creating debug makefile for static libs with qmake for " $$i ; \ cd $$i ; \ qmake "CONFIG += debug"; \ cd .. ; \ done @for i in ${PROGS} ; do \ echo "creating debug makefile with qmake for " $$i ; \ cd $$i ; \ qmake "CONFIG += debug"; \ cd .. ; \ done qmake-debug-dynamic: @for i in ${LIBS} ; do \ echo "creating makefile for static libs with qmake for " $$i ; \ cd $$i ; \ qmake "CONFIG += debug dll"; \ cd .. ; \ done @for i in ${PROGS} ; do \ echo "creating makefile with qmake for " $$i ; \ cd $$i ; \ qmake "CONFIG += debug dll"; \ cd .. ; \ done qmake-release: @for i in ${LIBS} ; do \ echo "creating makefile for static libs with qmake for " $$i ; \ cd $$i ; \ qmake "CONFIG -= debug" "CONFIG += release"; \ cd .. ; \ done @for i in ${PROGS} ; do \ echo "creating makefile with qmake for " $$i ; \ cd $$i ; \ qmake "CONFIG -= debug" "CONFIG += release"; \ cd .. ; \ done qmake-release-dynamic: @for i in ${LIBS} ; do \ echo "creating makefile for dynamic libs with qmake for " $$i ; \ cd $$i ; \ qmake "CONFIG -= debug" "CONFIG += release dll" "CONFIG -= staticlib"; \ cd .. ; \ done @for i in ${PROGS} ; do \ echo "creating makefile with qmake for " $$i ; \ cd $$i ; \ qmake "CONFIG -= debug" "CONFIG += release dll"; \ cd .. ; \ done qmake-profile: @for i in ${LIBS} ; do \ echo "creating makefile for dynamic libs with qmake for " $$i ; \ cd $$i ; \ qmake "CONFIG += debug profile"; \ cd .. ; \ done @for i in ${PROGS} ; do \ echo "creating makefile with qmake for " $$i ; \ cd $$i ; \ qmake "CONFIG += debug profile"; \ cd .. ; \ done qmake-profile-dynamic: @for i in ${LIBS} ; do \ echo "creating makefile for dynamic libs with qmake for " $$i ; \ cd $$i ; \ qmake "CONFIG += debug profile dll" "CONFIG -= staticlib"; \ cd .. ; \ done @for i in ${PROGS} ; do \ echo "creating makefile with qmake for " $$i ; \ cd $$i ; \ qmake "CONFIG += debug profile dll"; \ cd .. ; \ done ubuntu: @for i in ${UBUNTULIBS} ; do \ echo "creating makefile for dynamic libs with qmake for " $$i ; \ cd $$i ; \ qmake "CONFIG -= debug" "CONFIG += release ubuntu dll"; \ cd .. ; \ done @for i in ${PROGS} ; do \ echo "creating makefile with qmake for " $$i ; \ cd $$i ; \ qmake "CONFIG -= debug" "CONFIG += release ubuntu dll"; \ cd .. ; \ done rebuild: make qmake-debug make build rebuild16: make qmake-debug make build16 rebuild8: make qmake-debug make build8 rebuild4: make qmake-debug make build4 rebuild2: make qmake-debug make build2 check_env: @cnt="" @if [ "${VTK_INC_DIR}" == "" ]; then \ echo "Environment variable VTK_INC_DIR not set" ; \ cnt="1" ; \ fi ; @if [ "${VTK_LIB_DIR}" == "" ]; then \ echo "Environment variable VTK_LIB_DIR not set" ; \ cnt="1" ; \ fi ; @if [ "${NETCDF_INC_DIR}" == "" ]; then \ echo "Environment variable NETCDF_INC_DIR not set" ; \ cnt="1" ; \ fi ; @if [ "${NETCDF_LIB_DIR}" == "" ]; then \ echo "Environment variable NETCDF_LIB_DIR not set" ; \ cnt="1" ; \ fi ; # @if [ "$cnt" != "" ]; then \ # echo "Required environment variables are not set" ; \ # fi ; test: echo "Testing" ; \ cd testing ; \ ./run_test.sh ; \ cd .. ; caret-5.6.4~dfsg.1.orig/Doxyfile0000664000175000017500000000105111572067322016264 0ustar michaelmichaelPROJECT_NAME = Caret5 OUTPUT_DIRECTORY = /home/jschindl/c5doc OUTPUT_LANGUAGE = English EXTRACT_ALL = YES EXTRACT_PRIVATE = YES HAVE_DOT = YES CALL_GRAPH = YES CALLER_GRAPH = YES INPUT = ./caret \ ./caret_brain_set \ ./caret_command \ ./caret_command_operations \ ./caret_common \ ./caret_edit \ ./caret_files \ ./caret_statistics \ ./caret_uniformize \ ./caret_widgets FILE_PATTERNS = *.h *.cxx caret-5.6.4~dfsg.1.orig/.hgtags0000664000175000017500000000020011572067322016027 0ustar michaelmichaelc35e710c9015e8d4f4d81b6a71518f3fb6dc680d Caret5.615 3f109909a623cc7d2e3d2fbd5726747763fad607 Version 5.62, Released 28 Feb 2011 caret-5.6.4~dfsg.1.orig/.hgignore0000664000175000017500000000150411572067322016364 0ustar michaelmichaelsyntax: glob *.user *.o *.obj callgrind* *.so *.a *.exe *.app *.swp *.metadata *.zip moc*.cpp *.diff core caret/zip_it.sh caret_command/zip_it.sh caret/caret5 caret/caret caret/Makefile caret_command/caret_command caret_command/caret_command_exe caret_edit/caret_edit caret_brain_set/Makefile caret_brain_set/caret_brain_set caret_command/Makefile caret_command_operations/Makefile caret_command_operations/caret_command_operations caret_common/Makefile caret_common/caret_common caret_edit/Makefile caret_files/Makefile caret_files/caret_files caret_statistics/Makefile caret_statistics/caret_statistics caret_uniformize/Makefile caret_uniformize/caret_uniformize caret_vtk4_classes/Makefile caret_vtk4_classes/caret_vtk4_classes caret_widgets/Makefile caret_widgets/caret_widgets .git #ignore kdev projects .cproject *.kdev4 .project caret-5.6.4~dfsg.1.orig/.gitignore0000664000175000017500000000115611572067322016554 0ustar michaelmichael.hgignore *.o *.a moc_* *.pro.user caret/Makefile caret/caret5.app/ caret_brain_set/Makefile caret_command/Makefile caret_command/caret_command.app/ caret_command_operations/Makefile caret_common/Makefile caret_edit/Makefile caret_edit/caret_edit.app/ caret_files/Makefile caret_statistics/Makefile caret_uniformize/Makefile caret_vtk4_classes/Makefile caret_widgets/Makefile caret_cifti/Makefile caret_widgets/caret_widgets .git caret/caret5 caret_command/caret_command caret_edit/caret_edit #ignore kdev projects .cproject *.kdev4 .project *.vcxproj* *.filters debug release *.pdb *.suo *.sdf ipch *.opensdf *.cxx~ *.h~

  • L6D?]?+Ln=#q> 6>p,/P3>?Z?!3=oοҁj>>%? $BR3*J ܯ>͔l>+=BYM`y)?3t?[=E*P(x>&u>1N<|JHb>Ͼ3QT`7qH>#F>νTP=&>$?2V('>a>Wa|>,bT,Ųw+J6?KK>?vx:ǽ|?dfWu0TX-f=%[zLb?" k`'NU/=JݼU9 fs*2n>+ſ3qO3gX: "BS?D>Aͣ~tؕ=/?ob>MPL>zVcZs?Eho~ Ï>=_̾r'Ӿ?->হ3ž ?->Q~?dr4>?'x0+{>?ifM?!n>1?_Խ̾Ѝ,8e?_>2iU>?NsgeρpZq 0>"d? 1Q?)=~Ȍ':?E?*=q]Q'(=>"?rz+^=w>?,/@;5ѻf? ?->xaƁ\>8ν%оػ? &3Ʊ>59F>}5"$(Khb>waa_Uװ|92;2E^kZr|= aq5]>p$t4>=Y׀޵E4v]>*(s"Ŀ'MvUP>ݐ=Eugm4Y>> ֢ :Ps=>!?~=~n>]>GA?jW[>d|1> V?C=C/p,n;( ]{N!=pBw%ǂ0g?b?  SƥjC5?"jD?(=^.=ΏܾPU?) ?$>!IϾ;6?~D? >߭j􌓿>,a.6m2P f >澵4!m?9L0><66^i/w=e?=?>j!>=b?M.bX 5RS=PٱSAY@N>w}{qxbaB >= :~cðK+ȼS!:XY"[Ћ=]>:t:.EZpc>4?MP/;!Se޾@->o?K=vjf :>v,44@SF5gܿ) 犿e(1Rn?4UG ?2?Fe?;?>'NcY6?iF??MZf?/aR@?.a%;m>YoeF<A,D3x;G%&íuS^k>&v> =*E"+{>9־꠩ʵU? V>5ƽLQ#b;9$:=ѐѾɿ$0;=տJؿ6G?,Qgs>LJAˎ7]?jD4QUe>FоP>I'I?>wB>sA"&o<> >_>pB$I^$b>+=>i%Ǿw =>Z=9#>>+?ef{G>˸&J<޾.?BS>)ICZKx` [>{>oe>rf^T>W(=ZWKUǾ>\=[I-k>P>aW?zXC > G=<#^1=z?Fc=6>L%Jo!>/'=2>}& l?`#>ST>UC:Y{E=>m/* >gd02Rzw;R+T\_ Wڽ%=!x܁e=Z">66?i/P,=!9>_̾<8Lq={=E6gs_;dxxD~>Ҟ,>{>JFB, +>>V>f+ԾyM>mpݜ1=<>zܽ >6hҽt>[:> :>`=K<>=st6>14Hs>5>l>I3>bE>X}>>*9 =5+>ߏB>j. bDA8>>f4C&u>?)|>8??Y>/l h>M ־<5 G3罎w 5hO [*0Iь>ue=fb? >?"'Yֈ>>ޥ>o?u7>h>>m P=>{=>ԇ(硾:>m>y>Ir}8ݾ`>5>W>#?9S~<2UYk/=sھ[)Ƶ;EṬ?>X`? s0>XM?4>?/#@=>S>h>V2FQ QS1=puJs>('=i<>{~` >>TG>\F>எ>˓G>o~=pmP?@ĠC >ˉ>uW>* l;q?11??6"lz ?0>'?i_h?5P??:Py?>}R? PA]>$-LNҿ>>O=?j׀'>6LO鎨%Մp=D=9ؾ} #ߍ.KX;i`J?{6?X?߾|R>pr">scT}=D>Vj's"ޘ>އ=T>o .襋Wھw}>HLj'G}>/.AIݿل/=lNzw?+&|>F=ſe^Ɋ>8 P_,0*~A=!m3>4>?Q7LWFپ?;??([lvٲ?^?c?1)Uܚ<4?>?8$>'[>>)J>@)=;w^>rԁ%j~M%F t"=c{о '>u=,M!/L@>~=+9>S}ѫ=6*ј龲?>=:?\3eXeR(Ve><#!S+>w=|?һ?n=(]HPPVn,='3jƾ=>j* &T>;>d>p?E9ྟ>/M>f?I-<>JV>,?2`p;k$̽_F\>" Fݾ?1@h?*?O)0Cn?#W? ?GxCNDuſ (?E>m]1>ľ>Jb?~d=@n?"?<?FM^O^?F?Nl?k`@>I:???;Ui H)"`+ ~{&'9< tOU>I(t U>xlO=/39~>t懽A3v=pao>;L>i'N?@p;?>?2f>&Rz?N_\iN]ڕ=&.sjq=<]+>ncFSaٲh=i;jb ="j#>URc>õ>_ ?y2>k;2>=-s?BDA>7>>?M".8=e%Z>9>~>{=^??('g=g>DF=ň?fD0;OTU>FihƽMPQj=?&#շ>pz~?2{|??i?9C?lv!?l ]?,Ml>"[=+N>Ĉ촺Bl!B7>HA>rC?c>ϳ?is>Zf>>l?CJfoC?C]?Z?vv>m?>K?`8mXv>9>uS>j?A:@S=U[Wɿ<'.?[WP8mfyV=kJ/$`z}=x =3=bA@tɾҜx=ֿ3bb9뿗~? 0}=?mrp >,>b=%?P)(>d))>Jœ0<γ3&<,w!={u>q?jQy>7a}> d>b >l߾ߒ>0V>Gԁ>m J>.|F1> u( >ln%&H>B;o^c>˾=w2? nѸ>3ľw >`b=Ds>qL^T=$m?>}2㾊c9ihBX{'t>oF:x =ˉ׾Kt>SYRS>>d$=l>RY&1`>V <{>Q>Y>7l>v4a2>S 3>_(_S>ǂ (P==~m?>y%䐗>T?>W!jD>DR?8a? 2?}.AN6=>[?:;?>?Zd&=֧>Ve>?:!&;؇=q2>E[>K(>.>?;MgMXǾ97 {>l7<@jq3v[ݿj=:=fQ۾Yj>Z >'>q9?m& '8>C>+ 5?[Q>[>~kƽm?o*Th?ٸ]=$c??L\=҉>z25r?me 4}>l>Z?ٿ$G>#gSơ>څ˿9 :?mԒDީ0>xQe*>>4=?h~HG)=>NY?ueX>>j=;LQ} >]$==/;>$H69>Y` >_=}2 G?(-x??v2Cwsm=gҸv> yB?&,6>#TX?>܃<?4Ex>>E,>Ӟ> d?l>>w<*K?(M>Hd-ٗ>xv>-‹h>O<&G?.ؿ$?Y+?یSM!6;x4?%,Е>2nki۾kf?xRqO>¥a>,G?f=u%;? `AD>]F>9ŏ>*tD:>RnAӢA=;iѿM>RH5=%Fj<>R[p=*(qiST?*dKŢ>;vǾ>=&J'Ծ4?>( =$yĿT> _H> ־ n>1P=J?hbLGA=O7!?bVYG1=Z*?=#m|V=^=lN?]cdLo> ' C_?CzpЩ N'ʾw?75Ti>\aR d 6>,?D_?"?ȡ輾nBa9o?Ȟ: ;`(4? ^ʀ4ԭg7׽r;!>m N)>t3b?þf9#>ܿ=!?D忪? п?MJ>z%&>?OxA\==,犾,?SSPո• >[&?]Hװœ=K"?2S m Y??0=&XЖ?xb!sK>~↼X¤?a l_F>GEо:?濫]?ӐA>,:o ?\YC}h\"? ǹ>{?2w=$ xt l@?b#^=>]qmK${?fri>??|F6Ž> -?z}@=Ǿ@ >DC>PYhVq? S/=c7b?g._W<]}|> Tjl=?\o`> 2 *]J>dqZ>RŠy??J0G=Ѿ"bx?@X=3=!h_?t7 Ɠ>=>Y=?>NeE>Z=NR^t?pH >=?bܿ >%>!?d=9>E:j?pRiq?7U>?3@Rp߾d?4/2@u˟S?N>fp"?AW?ZKq׾y>=%? ^ ?`??X?p Tr~Ĝ?Z]o&gG?N 40#O; ᾌµ?q,xۤ)s?M7??ڂʲf>VXD?W?ZU=ܾ7 >ݏq?2> >y*ƽ?;q?C?;:(?fp8??{?-)P???V?-IϾ>Ц=θ?0>(~>Eg޾R?VtD g>A>?u<Z?Q@>~?Ǘ@ʾ >&=s6?ˁ^t>`k> x?HQDr>Nr=?>no_>.I,e ?Z1'ݾ|r?4>W?0@#R=d?k>א?exPx| ?3>C?ᾈz=@׾^}?.P|=i.brn? Fc\>w)LG>oQ&??jGu!Mi>ʀ?gaF1$#? r>h?Kek@O=M?wHy)? f?VAY,OhUt.?,c? 5?@IX0w?@?U?"9\x(H?#>?n>Ux Ⱦ??>w9>>r^W>K_>+g?9a :s$=|>?C;9{=<( >]0'?2b.$A^о???qTp8=?H?)\?T/<䓾c'k>Э0 v= k?ZU U]1Hjo=١d?e`1n A?AK?1?czor>>?`n`),?9?P?l j Fq3>>?0a8Щ>@-?O?e8>=>?Z?1>=}>!?_$>ς 4h>(F>|??4++>v\p>\>Mb?F|(Bm]=qG>θ>F?4m͡t%>>E`?q lUar=ǟ!P38z>. >xh>{>T q?o{S>@?9(?$5?K&\=dϾ ȿ }V>~ 8d =XrK࿎Ry t`<=tqX>T&@=+`z @s ̃s=7 5[L>Na?>V'߿=gE>,>}*>>|TS>һ>C[ 'c?-.?>=Ŝ ?u_><<4S?o@ 8V>>N>ʘ?@`9ߘ>y>W>]?>-+1(>>F5?L)?Т?^775d>N⾬օ? K3=&lL%?)*-P`>`Ve+>&u>"'G? mFX>⏾$:i?ADx d*>YHfӾ?+P<>|b?u?/L?"E">GD,>B? t?m]N\S?WY??gT9-"?.o?nk?< G2z?*s.?q?4Ӟjy]>'?4->f@\=)ܿ,ѦH<>}ia˛>OGP"?&)>|뾫>W??`|uV=C>c?s? c<_% ENJ?HV>.˾bK?S .>ʾ2 m+?D_*>OFс8?/udD0`\?^?X?ul*F?3D ?|9?"PYe<b̒?l[lOm<><R? 888Wzqx>+>HR{-?XsN=A?N'?S.?9?@?A?h-g6pL=R>.8=ݭ?@Ex3f>xս"D ?GP >\1>$w6=?>??sƗ?,KA&ij~??iE>V.Z3hE C>.=l??KT=%X>.>T1?U`B /^=3>G?#>Jlf^R>3q?_->L9z!R"~<=K>X1{ր 6v>]>웄=vu8?=[>>);/c?\?T_)>B5%>!?=l><= }F>x?HN>Y`0QFM>?*>.g>͒?MUa>ęk!=꾀&}>/꾢g>ſəݽ=>򪿴=!?O??tKł=2>]?W?VP L>Ã??`?ݔs>`6>ݺ ?D?>Az x>H?>LY> >c= >>a>u='\/>=`<ӕ?$x ^>8,6HK>V #Ƙ,p>>b>@ p?K>>P7 >BAn0žp>پc1_r 6_lf>d2 [.ʾAҾFN>U]C`bԾέqy>ݾX]"R>&?]Zm>cs> ??r<]*N<?4"&WMD3J>z>?nY? I}>p eq>{Xy>-B)B>?> |pP(??2UUe6Wڲ?V{=>d>r??CB<R K<"!ҽ? o8A=wޔ> ?`>g'@hsB$GIeV2?-?!?_< Z/f_G>ތi>l@?Clkbg,k>>j?5H\ĿsyL>5>$?D/TY>nc292׾O?}~lduN>>>H8<ِ*>\* [kVwV=cZnޘ>c_Z !ٗĵW>mY=0>1꼾 9'>=L7I>6dF0KY>8 6 >=?Hnj=?>5?9ϫ؋3X2 >r(>>G>eH*=)>K>=sH(%n>e===`Jb.brKB=O!I>Wi^r\yO ?T#uUsH]?}(x(FѽO*Uڭ3_=>2MNOs(žB>~/>@24js>8T?>A =efjOE ~8=7uQ|~~>E8:s;eAܔg;>cs I ?<"ſ1#v8>>ȣ?CV2*X]/>4>,a? \\>9> )V>`> >ls?3|@?4tI"Sʸ P₿xĽ43? 287> >7,zڡ5P"6?NM?`>=L[C7>Za[?eq?ŗ? r8EES~>6??C?ya=)~ <>\?>??.Cn9>ϒ?Q?A?9=K$>V?y?OU?1tM:`Q/>n?cZ??YzjP5J2%=g=v?Sُ.78?3?>{JW`P%i?}k??a!%ZX?'??b S)Iz_OWl>b>'3='>04 =>?t8 :;w=g:>?>u(fCc"y=0b>Fù>lE` U&>'U???bRV̌>=:?rL@??_VX>?\@4?/k8(]P>!;>?VvqL ZOL>K?%*s*hX>{?~?>)2w.` S ?(p `bziFq&3~ ? pÇ3(\Unb>h fľ?cþn>3WμKfIE1wP>ɟL楾>g>Q?.3ѐAJ3% 5v>JEk쾛 -x6=cv%=翵j- 8yր>Rٿۦο%1J!o.>CK+ jj"Ծ^($>?!_ݵ1νy>ީ?ÿ7~Ndg?? |ZyZX=)>? I{|m>,>ÜR@>U|3k?#!LLnJ {53U?"QboM:}?qڿ_gxf==e&?у?%?AsT-pVV> R>\?D9T|]r޿?Yٺ^<h >1쿮Tum=yj>ƿ ]dhkEx>s̥}8-ˣ??<"\>uu*D=h>gT>ξtQQ =?-?eXd=oDlO?9_?cxx|> ?>%Hg^au?/?ּl=f>,Sk]v(#ͿDe??U=(t*w͊6=jR?lz 4q >?7X*qzվ)o?m_ABA?ϧѣ=>?LhH#=V:>)?8־(a8h;%=G??[ NK}S 22??f͝U[0WΝR?"?.ý~#UR?S5?݃>ly5sP~=w?*9hF>ndH;>)|b= BU<# >6X=QD忔eb^?YY?)>}h˼JP>/](=rz Էxv0uu=v>F>\/ޔ Ӫ=W?T?Uݫ؂6=?r? R+-w>UT?iݠ?`u:oݾ ?Ɇ˾Q o:zB{?ǿ{D61DTruQ_?,V>h{*ˣ59d7>We~=mx#1;d>U>ɼ9cɼ qm>7{>+o=Sj >|ͽjB}>>u>!>>y5\E[[&=焩?Q/|dվjD? _6Cu>874)\t@>D{go>r0 &/3 _[?3% D<>QQ4@$vld>Rο/ؾ;)Ef*=L%\ٿԍH\y{=i>K!ұ?.>?P?F)>P=8>>jb>ʂʾS!<? 9v>і󼷝,P i>M>?VDؿ9V!>k׾ep? = $3#w>6߾yW>GԾE>FV!=>[6{>$Mr($\>o>3?9vJDP?>&>/ ? ]v2>D>r;=#Gcz5 {B>e?=>F3[ lT>=-/NʿľB~G>~J>$B< O߿2lB->3>@>@R@i#`>.#} ["-=V+? r SRÖAMg?-->? *>ʱO/SX>J![>?UҿDF7=_?ȿ.@;yBK4='?AĹk>矾|\~;7+Ъ"?ʿ2<9q=s?vBJ??QA.=5r?]S?M^&$^Wd?9?a|ԾsXЁ,g?Jr2?O#[>A=N> ˿#%J8 =]ɒCCK=) Ƚ7뾎y%LgS4"iު?i?շgmjt{K"AF׸hM\׌w#8=/Jb>&鼾X@B=>,is‹*\Ri=!= XfhYvKIA&cb3fkZпJ. [\z?>unq[_=³4CD(@]=aޭi Ye;s=2f:贾\1%Fǀھ+>>¾$5/$\XE= Dg8Ǿ{}=J>%DVph>S3Fy̾Q}xJ8>-> ~.}a;U^Gf@s*nV>8c(%[[j >{c oV=}s>+޾y%A)o1I> (S;Pؙז hWGP{=W)~\L\Y>+OtGnpzGy:xnRBJu>6(x0Lm4>KD_,v[&P=֨3` ?Zݾ8/bV>5EN,Ͽ3eJ>!GI)x髿]k>w)cڇ^MݾXkV ]>n>BϿcxkܾ0UHa`.a [W*I04"g>7b #?<`=sK=Ob W5?\4xX: H7Ծa>l>m P* pd>[-A?kGA^B=t.=2@heRTuZ\>>/od8j poT>+/#w=Z_j>Vq] Q޵WYX?ք>B-M 6/xcOM> `">OvL zwFEAVFW2PiE>x%T4>BthI-b)?:=>`?+xL==E L+h?lWB=$&zղ H8?j>>bZG>À>)=Rۥa[)Hp ⽁h0]/?!yWۘ>}Pޒ"O"%W9ӿ*ϿWZ?C0>>u9-e>J=e?2ƿC>i?S+w= Rʿ#L"t8)Ad =yCt?AH>m1jH˖6j?(!> ?3 <0 ?6? ?{l>=f0?f[꿆_ >w?\r>4y {?F>X?X>;_?c^>?[2T:!:~=9.ſZ/F>SB=x>iA=r ]/:==Q)c=<)ӿH>6 t0z,D]>R>ͽߦYv?].>5EAž¾*d?uOT>O8ܿ?j?!> _> NO?A՗>©P=z#â{h0$g>t>m=X>'">"F=q+@R?q>M$>>=Ϳi?} >5? o?&ApvrV1b= ?U? .Aiwv `->>ZtH7Z=[>>0ـ =>>$>> gU>?c?+ Y>ܡ񿬃#>??/6lN>>?HZ?WKք=tPj>>]>P>ԯqŇ>~>Pw>1+>i΅ÿз)>8?P0m{92>ڥ>FJ񾞞??JK>=쉱Eп'>H?Ȭ=1ԪP;zO=fs>z_? =ӿ־6:\ ? 1>Z\4EIst_[(x;? ?e־1濳S&( >`t?5|_ W0> -?3'M@bQYdyO'L@J4TXO-׾ׄ? m? _S<??E$kDiL'οHsNQR_1L1(8>~̀GѿՃR-w>JlT:Ծ-` u=6P>4+H24?C}>}[P&(Gh+Z?y>A)E J?Js>[n<>6v=oʿD`e'C>C=Y]տ=n>LbDs=Q?]?=Cֿs>%!>޲u=.v7A[`>QνF9I^[]Y?Rb ?&*>9D9?Cbǿf?Dn>,E1)z K=.guSZ`%p򾁀 {V*3.㾫=֙HlU_@>?> _ùgc>Y ?N`=|pPo>E?h+˿o|>erV#:K>l>?}G#:;}@S:X B4\R=X뉾y?8ֿȆB> >?fZ-i#>&=, 9H޽G>11q4HLrAw輙>F)'WK@W8)JA@._$B>->_ k?R8i>jot>B$>:4?KQ+>i>Y`>&?e:(x sM?P??ս5]>>l>$P'XS>> Aھj ͝Y?] _? zcm {>NYs>z R=~ ?.]Ѿѿ8-0Ҋ¾^?`g?7?>*)`꾧Q?K?^>`>qpi>> ?d)Lv=[d>B[;%?"톇lc~|=T?ᗿ),dFtn?/bN2y~?ʣ>G<oc=mT? բ-CW>aJ>n0y_=Fv ?Mk?-> {%_<2?EM;Qv|to]=2m?_1>oe YL[ ?|>=yXO A)?d?\׾=?ff8>h?%PvZ>`/> X?Li>GG>?IvqX_㾸⠾)<(mr [!JDhI@\'Wז> +?RGVEo>~?0Xx1n>#?( =`!*?=߁T5c:<-WH}!t?R?C=bau?^I?ʗ>iU ƨ?b?;?>Ci1Q>=s?4< $iΆ5>+?tXB3]N"J!o=ʞo>RP$?Fw ?GK?9>:~l ܂?5?<#иܾm? tve4@١;s>4/ }QV0(H?-r.P콵=c3v R6A-M? B^K\Go0=~??Ƽ/T=9p.?g? *Yy=H?*?U= jn)=?=?=ھ4` |+?dI?Ҷc>\0$4U`1dZWʾyd=8l@,dD`V #}d哿 lBV ˎsd=1[`4 (fGVhy=ۅ;b(xi(KV>'D?oCȿ`>l]>?i6S>F>;7b= S=S?3cg,=uC$6$-=ƨ>Կn@=_Ud?N$?=@=QG=>uCG7mHb= >4?b=8hQ$>R&}N(=ʖ-?W=Shkr>:v*^ȣQJ۽qG,7!"= H1Y>VD\( 2? I 1>sB>ZNH>̒οCJn۽;Xm=4<ޠ>=5B=ԉH?>B\p𥻾g=ƾ6">^1P<@L-f.FHD?;OafZ/h>{?/5=oIJ< =4PjR[W? d!?-sB<&>C mr|-s>1f>?=C=q~oVl/UT>?C%-?}XBBBBBB[+ij>U;{g=bBB)s`oP-Z^}x(=L>m/^>*d> ׺>(RD=J^)>x7>>BO">?.t~8z=fsXRXھx8b0,> q!Gۘ_7pGBz>Ң>f:>0J +'/3v>Rλ!G>؄Tl>8W >X pԾ׺,(v=Q}k܁ jY=Ь>L6?u}C=L `OL E->^渽P1>T@@:b r>#=qi>Oa[>G3"w>9:!>}&1=&>,'?q@S>7=>>=y>DHI-|C ? >4>$qί>%=A1>C|Á8??f>>9?uQA=Qe ·?:>j@[=J `R?!2/>?v:ʾی?+h>u?yo,p=g~_>u>dN>u|ЯU?0{>h?J'a ト%?N?)?f ԗ)>r?8v? ?Oxў=Q?Z?*ܐ?p?]Rr>J DN;hO_N>kk+<ռ>Q e)>=wu>#ⱡ(>=k>Voҽ,R>UW>rdP>=}?$>r?:e'Az+D?> ?oA?UZ?%>?ky ?u[7>CBB z>a>">ƿ>aw}3Ӻ $n2>S`Lȝk-i# ?e>g>:+I(>>>EJ*?(K+?=?"k!P=]?ӕ>J>{>6D?/">?)z5P?+ >ב?e{^?+T?q7?*KN`d;E>W=oY>A;>>2.>L<2ȾvJ?4/??2(~?5?h?7bA`pѾm^?3b??4DQ}пo;>EZ>B?'gDƘnZWhM{5>\dbDc>xh;,Tõ)oϳ(z>>B;?18br>ⵀ>R>B?.h+Egj>'>>GD"?F?#?SQ<?U?`;.?g;> ?θ> J^?$5>EY.C=R| =EHUƾJ=$fAA?>fs>?=8 ??$?@=}N M?`?=?f],D?N+?.?U{{W?$z?|_?)LU:W?I?rNH?-tI 1?h?p?I4?zJ9s=r? ??a ۽8Ba9Z'B̌ d>}ןԁ>=?(>sg0}2@EVsX"?Iq?4F?[n*פ=P?!U?L#?> .=b>7]=Q 9>m-06u =a>h9lhK=ȭi{>e6ɮ~=ѷ}>Ԣ8Lܩc?08;?[F?F7,+8??y?1s?\%2hd$IV^Se>VGPg =r-ݫ%,=ЦBA 0-78lN]>0LLT7;v>rF|D=_nǾ#><)$޼;>-O|?GR)w=͑ ?d>I?;?2?\u4voT.UR=0֮z ">RP??Z!N?R??Q?|<_?L]?Ue^?u8Ȉ׎\?:?8tT?i?ϻ:I>>O3? ??$yPs<ž3{>?~xg&g^ھغ=e?}K> `k{>%?>== XG^>~B3=qU>3>ݔ?,v--*{@7fԌEbΔe%@ L=\6i>_Ov.>ƹy|?!e ½=jo>V@X,@1H/>>}? ”>\"%?fk׽o>.<=8Tx>W>>>|=J?AM=MHl>e E..ݽaEW)Nv8Qs<.Se>Y^;q? KO6Q@B> $= Ti?84>cCZF'Q1r>:#? GL-^{>=JM>ۙ,>W? KI>K:?d!k?>==?ao2? ?ODS? ;>LJA>^%B=8?)`=rǏ9^>5>\>>F3?(}x":ؾcI>i^HhU>,r|? ki">0?`4`=^=eQ&>5=O C<;Ց >WAߵ=F=lӾT>޶px<`mJ.ÿ>I Q"?=A,>C>?8y/=?*0? ?|xǺ>gn?6?q?si<"P>ؐ?B>v?V?%4Ͷ=ӆ a9TX>#@)=Mus>!]?)??(?zl?>|>u\>;?P5>K0>tO>&}5?2l)>:?>?oP{P\<)#_gK>hQ>#K>d?@N >X?>@?yYg ">T>>?/#K8*>/w%?;oq>r=Wn]?ʰ>B `K?Y} (uj>8> )=a?bQ>w)~x>eA6s>o >0s͎?S =ƚN±8>ۺ4p[Q> о{>8>$.ZLf> Pa >dv)򦱾،?>[V1_#>Xʾ$>ik>V9׺%>ՈbPh> ľvP>+o8JN>bry>5D.GA= ݿ's>l5HPV>y r>5?&pO>`iFÿt>H?z>JYr>`>Ζ?4ZǸ>K>~?5K2п|W=ϳ0ЫaF컀e>UE_F>omꧾ ?NZ>JJؾ >XyɨX>Zx<Q ? +fTA=<>.ݗhϳn'Ѕ'>P>RL>?A9>m>i>*?=f؜8=7T >qz>RS`^*>1þ)>&BKQD=S1*g*!S>pv}J(T=I-ܾ?i< >/v`=9Xw? O> Qpr>u[~0>5*@/>a W\=-i=YxdE?#P=Ԏ="Dc?M@xڞ=!=K`~?"8>R#c[>KUR^>b\W>[΄>y? ^>?R˸'ҽ7>cŽ?Qe=H&>?eb=W=(xz?$ $xS=>2?kr=ىYF?%>+ 8>ߓ?P?-U?ʤh>a?>n??SX =>>?XVW?|̿?.x?$8~?|ޜ> `c3zKT\>y`_?;P+EC w>56?mz=Rr>{?^3>s =agF?Kx1\> 9>uK!?vr@k>Z=nؐX?FSU>>hwFC>=u\K/? TX>$me?@8?ė5?}eD|=C|ÿv>ݯN~>#b?T?X`=彽Wq/?%g4W]>7S?҄> k>W &W? (?d4WC>zP-Q>nz1<?t??}6 - =ӿ2n?`! _Ӕ@h=)l@b'6>ە~SN=+ۅ>>\B?Fh^g=SvN?;L<=^:ٮ>*|EB>Er8ISQ?M^P>g>pP=%W?mb9?><=h?fC5Û.>!=Ң?hN=xK:Jkq;=l2~> !i?!Am#>,<;X?L7a`$>@:2ݾ?6A>"1Iɿ#?" Qɔu>s˫?J?^@?QO=;f ?:l=mҾ!=>q>8N὾?)I"?;C><,K=񙻾S?wڶ,ʝ&u;r{?\fZ< H6j?'P@?)-q?w匜w=]=u6?t]s#%h=?}R?|F="ݾ;?%E <2>DD\? d ڮ=x<23Z?_f Z>ɝg=z6?~>t#><{پsaV?nЁ/{>nFn\?d>tt>>&+ؤ??~X HؾS&? >c? K=c,:?B43@>DVh?.潇>oo?qQ>hy ?z n>z?H?[>>Y?Q7>;=?ץ>-iHmeBl?[럐|+?'>U?[ ւG~?'>!?o۾}=GNfw?%)Լ ⠾q?Rve_?]?a??R} ?HO^?R]2?]n? h=?Uj?il@?j!?Қj4?q}?ol?2?8l ?M>Ge=͸ _9Ɏ?A]>=p=7u t? =t@?0iē?5#rZoW Aպ,)X>i?>k>`?_X>>(?y4?>?5p$Z4>7>0s?O%Y?s>f=)?%k? > |? hǿ ?9? ?, g,>h>s/?Z ȾD>Dp>L?2Y8?? ?fO2}pn0?\>7?];T#??M?'{? A5{%{?2k? ?a<0 >Lu(?G=)`N:?4z}>@y?vr4Ic?\=ls?l~!?S?D?ɡU)v޽Y%?X*gB0">rm{龢?!vNGL*rE=y9e0>?]%.0M-cE=xT?l>>eL>6'?Ui?f)g>z>K8?_?XZl'I>]>?S9 R04c?d>[>@g>R;FL?Aw"=9߾nD?NKA,艽r->.=DV? @('2>U>?bPH-l=Ӄ)md?/[Xėվh????Ms^7[¾"?;?'?D4վۢY?X?f? # p?2=??( b?e=rfՍ?Ftqɀ>܋=Eg@-??,9w>nC??Z!?{? FT>I?5?xE?m?AP]~=>??8)?9|]QF !%?900!t>TkŰ >iGS&>^ ?%پ S?)>s3=?xϥ)?2?5?>& :?C? S?TE>R 徒%?Nb?D$?A2A8*ަ=gܾއjr>Q3hB>>>7a?.?ր>.\)8?i0Ͽ`0;:?qw?yB?3YE<,?6?o?ѿ"o?=#??d?i܅wa>G?B>$.?0Q??7b!g>?R>XPY Q>=-Z=L?Ds>%퍾ej>D9 ]|>a%=Z=H?p">z>>ǟ?^ӑ=VS?#?g?ʮd}?5&?|?h`W?H>C> >!?*N`=WV?H;.?A?sB?vz>;?/z >#"b?%?|c?'0髾?U?l1?YG=P/>J>sY?bucL<>j=?> PB)<b>4>ޜ?@mEc>&> >=P?>7$Z¼o>ac?5 >\:,e2y>3>=>h?{46%(>4>%>h?_aư·>>}>6?9<>cp=/K> οʟ>>u;/>@3%։>>P?H>hReAf=d#>6!? >&I_?>g?t>aذw>'t?q"> jZ+Y4&.Mg?zK>?ueQ\R5]>Sr?a(kV<^?"ծfQ`j4>Ye|T:=6龴>]pR(ֻ  >  >K͖ܽ C> >hH-[?> =h=ֻy>dGþi t>Ql>E? ?fE?m2B>f>?I!>mr?L?z?V2>j?J-旽4]=>*KsҽR0>.'><>ȬLӾ tae=Q>ӧT?9h>e%W>ө*?>\ʄCϾR-Q?NbETc`"W>oLJGڌھQ>37"8qܿ95?]~`Tdͼd>bG3-<́>aRaf~xپ>26)>}>/Z?Gy+ M>q->ڼ?HIf9GsÎ>ڿr<=r6:v 46?OӾ]J~_@-վu>7fc-#H>M/>?\j`w# LIО?'&UT$0>=Hڌ3>lNV;>4V]]>Jo9S>Ҭu~嬾v>Cj<7C >.w7ҾU>fw& '=T/H^pJ8=K=o^ȿ#$î`>li^ў` -;3~=%q*(r"esw>D_5Y.>Q`a>Df/nz>r>9 <^>Q cg˿8hki쾼oz\>22">zW?> 1>G-"4z>$h>l5=>0>e^=>ѽ$S=߅QGJ>??B?K g>JL>)WoLq^?d?s?-lNɈDDF;0?YSH8Hb6OW?u?t?'g%LTC>6 ?=:J0wg?>؏?Bxɿu?Q +zDA?0 MkS=o`W*c~Coe=?>%t?*I,qg> 08G>R3=;Y/4%m?Z?0>IǿyYO -=p>?F+mof:=ۥ=>?06cr3 =yҿ?a$Jf&j?,?(<>Ͼ{<>=i#R7lMS\GhM>^?⋻BSzo>sDz_LYu)Plat>.뿴j/m='ѿWȽq>e>6ջ@+>>?&5 ω߇L=>?0|71cz7>2G|Hž'-<;'>^_M<E?p> R.,?g2Q=<֫>eD}Px?`F pU{?_Կ hn>_de>g(谿)J>$e%>OVˎs/>U?%v >Gv`>̾?Js? >^LQNJ|a#B?JpqG=qTs|g`?Y5?m>:`wTRؽ>i?V޽[?-"u4>= $>=>ER=ɻk?\? .1Q= Í=tp31E>G*;f}x?"̿Xj96b>0>u9?j{517^>4MD;*? FVGF5:;>c>pl?kkn{O'A ;1b?*u%L*sAMDnw??Ek?=_*cGQ%>8?޾~dQB?@A? zO$E` ?c@M?WAHvJT͖?I?Kp5>,is>$t?Hg=G =U>xz>-n>0y>:?;?|Y-E?i¾R{7D+I? A ymؾ?Ď|z;GHW a^=܃=>>YObE 蚉>L&>Z?^xoƗ pk>Y?K >9󿡘|?.K>U'Ͽ(@'$u<$[=7?)ǿf?M0% =%>?sщSR9 -D8>ByW?:EfZ  .ֻW꼔[=>R>yL/%a=QCI8氾 Z_+оJw>J?)Xy*mʾ |?e'Sq%>^ͅw=ض?\>ª;4 ^)=>﮾T>:$FX:TJ>-u>8dcZ>>7i>T6&T>x>>et#m >i>_>,m9{f>%|>&?i?$"]+ S/=#P?=u2 XF >?8DJr>%t2Dq=_DVa='& #(X;Ln3k,,,ʼn-;lQ5 ej&c>hWm"LHIܺ=&eu>xg;C'W>"uk\}>`^9lfyO>=*?.t?R ɿ~>??? >߹0os>9ZdT޽U"6 É>,E>dw> 4PINXڬ?gƿG,y>dѿR Կ:ٿpH>mQv6DD.Ӿ]1w@>cVgb^>"%> hgY_̾s6?Ǭk4 ,>=4Y,(_OH>W_19`=">c$e^=ΰ2u >2 ?|R>7/0;e==Rjfʒsq6F1>Ą0?ar> ?nj~@JX<:+ Cd Jv>=k>A@p.MXC>=`>bII `>k=Oo >{N,>?Q?䂿K^>>W?-GZ?52Q#dK=N?%n? ib7(+d>GZK=јEO>r~D9.Ht>V"%]>e>W=)K@ = WL>/H:A;=rߖ7oFz4qlm?%9?O/ 8HԿ>a5xٛ)(oԀpg{ǾƵb龐Q0=@ȿY\Rl" == v6"+| ŝV=4/$cɜ|8o%c5*V2xK>nϧ?-gPh3՗6e?"?rsq &yGUֽۭ:gwx?B:Ux.}8=KdGԮɼFp܇&_!pa"IRs=c=jHs58D=j)+N9tg*> 97 qH+>r>b???T7Xeq^-:9< ׿k3j=@ݾľ=3TQ4lOj>zV6H=MyZ2z_j >fwh )g8lFR׾3B/u>E3Hشr)҂=^+tqw?D>}p߿иǿ6?iR?!~/ls56͑%!a ݱ9PY#^gF,u ߾ޘzpF۾_eؾm1?h"?NRL?3?=2>H!¾p?>q#OmV=r)龔~ߓvC̿+Ef>ife004v)%p‚=<6ҿTkK끾K?>f*>>WjQfzٻ¿Z~VXHm.bg>~s` ʿ7h8qVwPc,>Q><* z}?4-?;v43f2#<A%X pCiD?1<+оbn?Wx= 9)L?J{x=Sr $F? kE=ۥ]HϿA?ɿr=;OZsik\~= <0>^)Z>d˾CS߾.%Ti>THٶ#Z:˿B%ŗUC=vNqh>\>ӍdEB^5>SZ=ŵR;I *>> Z=ÿFA?IO=U׽1]pt?Gjj= &7@˿?`i]=蒫>DC~B9G^?||?v?0W*I^K+ҕ?f>?#^y_I5?>ʨe?'tX oI47=->;ؑLag=C9N>F׿=v;+Z{2Ç] 9T^c}ֶ["LD@? ? ?+m(H:[;>zD5<`E*>*>3>ڑS]cE@ؾfB>V6=%n>",z8<9֌3a}A=4 V=t> ?7PZ >;ɿ8j ,e>F>>R5?KC>x.? ؾbϨ r&> V=嗿2&>>o#F>qa>0E>q;>ӾJ$=p?>%>->ESmti>#k r!@$>XO.&,;$X=UeW]mQKG);'>$>l=,>>nYr /@Թ">i8B? 3==Lh#P-ݵwF>UTT=ބj> 3fӾ2j?P'>tܲt2D?*܅4>t=s`J֏+?i{g=>>3v?@fQb>e4>. ?H==ރ^>{>S?;i-=s>AD>q.?'\>'?]O7?l|ȻG?1%>1??,fMv@1>hO qW== 2s),@'w?-=r>7)>B(ѽM>re?|-> >&? ?-.>Z{9>jw?;\?Pg8$>t[W>%1? ? N0#=!?z?/j>IŚcqX?hW:?,Z>).> =!>>>ž?3i1>DM89>Qt>or&?B=6^)t=_}ts3DM"= SAn`#$>a=Y4#SFοy׾?9?=L  )=`ƾ/j_)6 BL?M)?=Șp{k#>b?h;k*@*QPC??xM\y3(>!,B>!z˾:A?!+ffj֯3쿅@Qξy>:?Y7XEVe%վ"Ё{_dJ77?o? X}F=8 ~>7<=ڬT/}E>@<<>>?ZF-A=0iY>#=E ?X w2u6>?YR#QO@=?}=?rNa4rKm?(Q?v=g!WY<^&2 {AĽ(TBԻ^><+^.0P A4=4J>J? ?=|=";a>>$q.?5$Ue cA2h> dزB^DV/{ )bW4}G<>nŽ(Nbݸd=J]Y CtO=$z>i?Qm]~B+d`=z>X?É"p羌+?u ?.">-A XHa>ϓ>.bܾZ-5i>>>U*?Yvʊ>Z1b>G>&x?h"?Qi=|3>C>?~=~|ڣ4?*!>wپ R&0n`?.?Q~>/xFsP??wF>y6°ᵾ68>BN>%<'.0@,ҢN[JW_>V>lƃ<-0V=i'.<<`Ť n0c\=-x>QG+ZVu=PLv^0`=|#vaұ3=LUKGhZi=㠄N0hܿqTȭ=٥4ZUhkӊ̫=i^+g0+/4({/B $ '?'H=E ɿMɿSdy=?bPv:-K=9;@?$ J3`l MZ= 験۾ga̿p OY110/w#y=ag>HEX=L؇az_ M7=O d>%>`s^ <쾁 ѿp"9e`NY?,UڼLQ쾪">>אھYDc`Ԭ5nBP Z=>UP=-s%A n6%5>rrIJÿCY?Rw=f,urAX}V=?$? >T񢿚V5z?y>+4a?H]>3 >f劾ɒ7l`X=>s %? gՑ>ɛ>y0Q{1;ca>j?hNZeP;_F>?\>Ê~l k3t>'V?UX^YX??=ed0>?5oXY?E]?>qTkH;a?\E$?;>Ӏ'뾾kr?6?) >|6vɽ0#}k, 'w-uD v. H=w R% Mq0>"1@h(>EwC׶I8uW[c-,?Χ>u~J&B[/lL?Ev> ھuyazo>꾦n>?zc$>@'>%fS> y>K> $5&Nsbƒ?U?>jPu`j]ƛ *:?bzf>?L>)Q?@CҾ+Q7#so]5G-pl4x5Ip6Pl&I{q'"SUYqsƿIvy/6?Kx?+(>G5OϨ[U>?tOMa,;lK2o쿢K=7]>i;)pn">$?-?e,=~ֿ`=? (?@i?_>seOI=> ?y^Qe>hz>ʬ?i<9[OV~F|> 8>(?P<γ\#̾$ſ;5x|HA׽G=B TQl>?)s? F=+9eȾC*>??\Ffu6R ϝoJ?Tɗ?ˎ>ilZݠAk>jjd=>:gQ$p3Ts>$6Y7E hp53>˄Y75;<8?N^?lv>n$}}?[d?q?~DTD?nfE?s!>ϕO-$כ?(@^?K RFؾU>g A_W=a,>?N磾"rl=ÿ WͿ$fg漀龴qRVym>P> ؼe$丿 }*=.>fI?{=d`x V>gb 6d >ĵ>{֦^}TMUU"_b[N>5kW#*R s]n: Vbת^qο+ʆl* '،=o<.@J"އ>9>kP+ ҿz2s?$Aտ>Sirer>w*}>HA>jտY=j>k'.K{@;"Hb>B/>]~Fƿ(ٶ  :d>Z{ LsGiދRBN?3L[l?;??J]l@>*Xu2Q)IG >|aL4\tPu?;uGcALvw"ͿvoO渾Ec>Nq&Ą{?Hپ5 sG7]?<4U4?[=Pjg%1?8z[a?!bF?=KYU<<>?!?P!)BBBBk6f,f~=X֑mDw>A;.w=zG$e?'f0B|&x)@=f<jeK?E?B6=tqDf M+?g۞>:H>]5?2?>?9;2?(W>?3n`_J>>*? @yO?hq?3p?s,p >3U>X>B/90>>F>`^0Dz>#>pߜ> J0q4?>]>dx`d傾|> >r@¾֝s?>ם?0u?Z?oY#'_?{* ->=`=1>I.hqK;?P'>1n>>'#49H=޾Y>6}2)>r=GO>90 3͚>n>xGo? }?+>ɝg?+.Q*e?>>D > JMd8A]Y ? z:>:?Y/@PX#?o>?j-#?bx>!?1XD1ngH?b`?2\?z?Q4HTl>1zo&,A?*`Z>\⾳K>-_b>G>(P?=T˰? >d=I,>=?AVM?5">>#>ĸ~ag?1\>?5hϾj?h#>?z?9O_=OŵG6Q?Zbg>ؽt`g?k>m+>9/Q>>=>sм;3h)꾾8C?+J>?}8{P?z>n?PpB>(='>Mֽa?"%>?G*XdE!޿EXp"}<ƿ+>($R#=> D_>Z2 > tJ~u>Wi arz(Ľ?k?@?dHˢ?B>?ON?F*?":;?H[;?U*?.i?UFɥ`h>ŋ>* S8 c>=^>Nݺp􊾚?O~?(\?JRc`|=" >JJHWx I=ib2?D ?"w?HXM8:>FБz5P>HaFi0B>ЩX>>Ud?3+\@x>D(<_&lO=}>Z)ҕJB]???+m\4H?TI?5J^?^B,Ҿ??p~?+ q?t?U%W?lH̜R/G?Y?Z"?!E=#‘S~t?j 軆>S=> Z2=<6??0'Pe>׾-;IbĿ0XFAx?߾<%;:y' = L(]1wGv>#ֿ/-:_>}D>0ҽS=-'T|R 7q>5V $sT>g=}>A=Žz> pcqgf=O;>_)$?s>ω?%m^ I>>? L:q־þ>=A17;= t6;%>?ăɫpƾd=p[l?Ak_>4;캶= Lc[>=Օy?(⺮a cw>nPӫQN%>m%$l,?DQ?:?m[ɾlg?D?9?j|?(Mw?W~?J=ϫm<$io =?I{{=K˾}2th Q=>h@?* ]gzڎ>X/ w?=>q6[3D=>0)? =?.e?*?_fǰ۾N?Z>]?R-`V7I?g\)?U??8nRJ??<?1`^?bq?V-0?#i۱c= t`ɚ"==ٽCU9=nW۾ij> P#3<>[?"A> zuK> e=rK>@y?;^1?)?b'H2xBU缘$O >">=ur>ShW>O>t?0>4>'(X?1me >"d=w>2&?]=0mʾk? >9X?V1us=j@$m->[\*\~>R߻H?*ۦ'<ɧY>~'ῢ=>E!? 7>n?uPzQ?;>_?OC ҞT;?>r?R4pt9>#?>2#?i:>?@K??4=37>bVt?,a;=N >]=#?T6h|><6?<}=xQC>}k>&?$63Ѿx?t>#?Sspܱ?>zS3<6ͿV=]vhn8ଽuC>3<Ͻ `w>n)0xj=>q+?&ز?*϶sv^q8>#˜="L>ꪟ$N>,>E̅)w? 0C#>ZJ귙?10D= V=2C~?yGSe> ENJqXw>l8]=Sc>lr\?BK #D¾[>a.X~3>\8a*ʽ>wL??o? ?۔? }8u)>rҾۿ8' >Vyu^>}QA3=gHi>kan?4Lpч{>sZ>5\?0YTT~>(h˿E6=arD{`> tL.?6>Jʼ=KJ:>0钾Xſ)=}ҥ=@E=6<㣩>;VK;>2d=ʜV??=jm1>D/O*ٌ>^d,\Gcm>]?ɣ[c>"C>82|(y>>¿^Z;<?_? W}>|5>p>6 ?56#vҬ>9>8}=?`p?$!/n>6]}>=`=b>M1=Ad|>ֿ"{pf}wҀ>Snܾդ>=B.>k pfD>Sc,>H0ZO8> *E`h&>  1>7X*P=I?5 >9>.u><?qb Ta>()>qU>I>w 1ο)=翎?%l?d??@eM#B?Hþ>/l<] >qv=1=Ǿ3UG>æa9>M>Q1=?#>>>X?ROx!>l> ׾3Z?C5Ӛ==jY?Pu#_)==UE4?:="e?9!'*ձ>,<=׍־V?AԽ=>a)4=Q=+?꾊l?,1?J=1U½?D=/.CC=>i?3lx_>P>0u. D?JbQ?Q==Q"%dֲu<;ھKϾ>G،#MP* >3= }P??Z!8=V> 뚾?)p/=D}MU>O >K[>$?mN>;hI>':?Q9`> ? >?Xw/>L6>@=?7h轾>D>V=?3(">)e=z:l?FJZ` )>}8>)=r?}pt>d)Z>\!= ?֫ȅnē>,YuO?;2L >Ksҽs]%8?'V`>1e >J?S]=>&?=>l!?%5m>s!`>\=?lYx0>_/co?<'\Ѿl >$Lt>F=D .?N7H>Z>+g>QnF?gmvT=ܔx3w?"4R?),4:? 5>1s>\]_?x_P>3D="l[?WD F9=W?h>}C1?lΨX=12}q;=rQ8> n>b=}5PN>Ϊ=&D??Go͸D֏gJT>Hb;% D>ɩ ʾK=xa?CNþՀ׾Ģw>O;Q?]9u۽i4֡=&99?>`X>=븀Yq~?n4?>G?8?&˸ί>mxļྪl?I>X>?qf>$%<@Q?E9n@>e4>Bݾ L?p/Sҙ~=K/?9$balP-=ǹ;h@?I49_e>=DA?lˎ^k]>XS=iPZ?c;??cZƽ#?o6kb>=W)?oL )=l'b?*~r@[A=gܾ1Xu ?k'1@~a? >>sž9?{@N65p>QE|p>}ǟ==m¿4?Z2<>bd&˾N?CH Hg=\/+ ?*v=K@RYQ?;^?@e~D=j"ӿ ?o >b銼?MD6 >@( ?zI>DQHԇ?<䗿2@2> I#D9B?'cЁ~>>@u1?2Q? >p>![?ql? p=ា> KNij?jR!&oSd >"dc?d$n_<,"?Pzle  5>bc=Ah?jcM?w}@!>> 4cI?q Z?>w?.@yw=2@?/b >^v"̒?cgrW?oq~?jmZ?7|?fp?vLmr?xyEP?K.?ϒ? >@I#>l'W?+=H>td?2~üоB7aV>1 0NvTq> iTq=J?iN#Y>y>o?2 ߙ3?!i>?'-3X!Y'D>aX=#?Cdu7??>r?FVg> N=?۔P.׽sYRL?t^S̽N*>I4? Md2*!>ߨA??g`h$.=׈lH?E;0 Ծ>şM=%~?~?>GI?t?rVŰ?Ua?)q?f?Vuw?-x澖3][? L,* M& > լQMc/mѦ?O]c0>Q=?ڃRb^>Ə$3?YYS>DH?4D60='.sF?-jlMeHM0>lo5e^?C#!ְ->fk'?gA?"B?z0?e/?Tz?M?4!p־ $[>?/HF~PG{|> -?)& *䨾?MsJ}_ag©?&pw]=Sf[Ⱦq?,l?tX?v2n??=fh_>&z?>\Fm>)Ms?(u>G==ȩ3O'? },?"iVq?j ?f0ib>>D?n3rĠB??bkq߼uUz=6?<|ȾJ^=&Pak? Rm;;S뾛?U' nɰ:\?+ڶ?6r7>S?EB?пQ.uH L\W?0p~1=$i׾*$&?5YA/b=n>裔?FK._2Gs(??[?n?wGpr39??v?0M7FI$G۾ya=> >?> A)>A)>{+>M ?eZ\#'=c=hQ">Ц?S@ &j> > (? JdlY4>Q>F?{pcEU>=.?x%iTLByh?Z!?G?"h`#<8?@>S??Z?s?c7>>?7/?^?/>>c??L7f'me==CX?X\7C>!=?W_:x<򶾊&&?xlf^?l~Sm?*A??ve很> =?eec %-XX/? hEWp^滽2 ٮ>m>%>už䟿 ? R ݺ>=g)?sy((=S??/ ? )?kr6~V`>>@>>4?QQ0U>׀=<ϧ?֑?Xe=&?7?S?|>VZicV+?\٥?>?9W=?4G??'\:!DN+??b4?9c"Yl_tش|? #>k?7?!X?n9???uB@zMf>צߺL۾ 5"?tN><”4?W ʼ4?Y?R?9" ^9>.?)'> <<>A?>y'1B>o?)"!>ŋ+0lh6=k,> 9E=/4>>?!@>K!x~?"?}wu?IHucSw<}&1=6;GA?-;@qV>z>>]?xz>,?>'$?7?J>7ab |TZ`^?(VLbO\Y;5 >@\E=~k=?S﮾K? H/.Lh#>۵9P"h>shjؕN=0̼Yh>1?+z?xq?-j' Oy ?'XD>jK)x>`  >>@_?Ae>܇oH>?8|?.?5C_b?k"???Vnu%I?!?^E?p.=B?q?;?\4)?"J?TK? 2`oP=|9=c?J\bB^G&;ةz`U>-cKTv>5/<>/>|#?d׿J`> >'`*xE?#):>2ҿ$U)򿚞Ğ>ɾ J=ؿcI>߽=+""><ɿ)M(+Pƿ>-"&kʽ"6D7>r=IrS@i*d9=>6~=Wܿ0C31n$Ҹ)`&=oT.ׄ2Q{<|>W? >dB-a+uރ>3n>S%=+o9T84y$}0^idF׽ր>?_X:=S-C?&>Ym> R"NAϽl>2P_>FlZڈ>#H>"YI3>>Ѽ4?=K-U?˾6? 5>,j)_>*>_>=~PD.?h?">U>o5Jk![>k?H}MGR*oY >oTSd5>ۺw A{<×8wv>޼QJ]򌾚b*I>C7D]ff>GMl!=2[>Pa>G_ *c盿Ҧd1\*>9>M>|qw#>>eR?=Q 7x;}̿N#?eǫTg5{:F)"> La4 =k&lT>O"LE@>>^(78 $=!*R=!>1C&Q;2{ۥ,0>8kzu=jʿ&?AYHy|؝vy?ۨ羞v7/>bq̚>M>6}5k0>AD*>cIaak3*q>G{J<p>ʿK\[^Ă낡cn>H*.g] tQU>u0 V,gqli9K>F=>ʾ`>}gӽR|8\>43Y>łC]*=:Oe<5<7g 5/7mg=l+> ?]brLӾ<0 >?tsFN?W>3r?O Ny<߷ Q9=V?Mg> =!wNk[?Z pD+Z><2#gbR%sPz> >}$?h<<ܭ~k'!jۃ?8fI>w> x_$?GtG?">*j3W=kɿ[b0Hr!>4?"XF1:">?ASeSH\;?l?tak?~%=?<(>}cOv>Q{&5b>4ü'-?(HD4d:v=Ɔ*J?뼿gc +=T94-=W>\2ٖ>"<?,R/>I,? Z]nT>%SֿnF|?ix-AT>B>)K>%9 E@q<? K;%>\=@ty?ph~R+]nY?@?5{ P<.?oi?Q/?}:?˰?uC\>jn =xWW?=GL>Cپ uk=TAƿÓ}5)= y G miJ9?O?¾%"ZԾ +iۿkYu=t=>4TqOV=>؇>.2B#!g ~D<ȦHrY>ν%Ԧ_gsԿ>>,>gX|k]!_>KV2pNr"7O>n@] jI4cD1/F>!a%pN|qX=ܿedc2~~v>C}8q^,y{tz,#=Ͽ8KWܼ?܅¾ vff>гp=>pIMf>$=gjJ'@-=iz;$:H3=;Vs޿",&X=#:X=*:Дdy vFk3[&N6$?`EN-L {5R]Nt:?R~?_|g4!̸V&1| \꾜 Ⱦ[=pFgduþ7~x:/Tf0<=8,c(; zHB2~&ZJ? jX>x3>XmZyy6y;bj<#/џB ,>? *Y,E; =Χ9*gSbBz$E,ApK='Ͽ W#Z(ȶ>՝?eF=.jNp! ͧ>?O-mnjuV;>>̽*%o>d??*[2=>>?NQO)d3 >Mx>?B5P?9s~o^>@(_>m?& ȿT"%2,ӂ=ag?J?V.% +\"ٿ)n!>|B9B+hZ/;">hpCZx>y>yꥃTzGK>L?7?˿6~ `=?__?ƿ1dr>Z,>>)qS& ⾢*N>?Ke: g=G辖&ܫ&=䊿2Ӧ$ ۜRz>>lӾ(9gk(e>n¿k洿`N\_>d-3¿ }|-> c\ KY$==C<>>#c9~6g0?G%?&տVlDm >I>voȰ#eM?iɛaTt M- DcZ)dZ%=S?K R"<> /srf3=*(5??!vj``<=>j{Hl ibDFơb~;>ԽwþׂM=AQdAENz ?k*|rTpa)(_c_lr߹V<>sB=ؿ̚T"<<:0;=MP+ϋ7_0Li>>??>&x<3&=z?^\?j3ot\]-྆"?@8?w[[Mr%'? .?g駾%-k$z!>L?k_ڝ!J&Dt{?NsK@yisYľ̾*Nc>`R>Qz>خ=#hjJt:>l>5;?Tu'ij>n4Fx =T==*ao;Z7>`㊼7H R>5ӾV^tQ'=q'Gs5I>Gޔªyh±!>jb>ЩX$a Y`=𿁉fomoqY*4&i?>Qʿ+|= (U^%BMʰ=s-=4`JPz?'>!)=;ySIK'D䮾K??*_֑4Z??UNg,*iᄅ6>?5± qT~1x)>?˾Zۅ#u!?h ?fG>7iJ<=8'gB >7O۾p>=`GF>a )@ƽշ??)>gnv/p8=g>c6'Diue>?&x=CC>Rc̿ݐCK?D0?D/?=x=n]~Sik"%Բ`xrܾEF߾ DY^[l< z8`i>gg "=qm¾vOo@=\}@\pU;xys=$G=`Xɾ$>=+>*^_kT㾆mν^qwy]_HH?>} -uO( ?X>r2> RC0x/@E?=]T~FkJpG(Ի @Z\zQ* DsPt1`KWuK˾ c_TS]C=ݽԦ>_*Sti]=E 4>}^_ [ϖᾍ<6.[}N ?;R? HX!>!;7h+xFHb]WhdJ併J/M>0hUp9ATH^=s2<8<1?=ݿ:GNYS>%3fzy5?b㿒n>7W=ʈj/F` l>+>=Vnֿ*^j߿VCN:Oq!S;WŽ T&WV3㤿cF?M>B =-#` h<y?/U>{U>C>~N4+>Q" G,?K==dTFVz *}="r4eqFI?w*ڔ>4qeS@Ȭ?I+;>1oʾ0jF_?Kjo>ݾ>Nb*o=5s@M+Ц⿼@kAѿd๿cXa=ΣC!OCB&>(Ro_<_@qѿr`>̾Aإ.+/?<>]iӽ.?d_?o&W>[n駾z>o?ҿ̖? >>%,*?8ї>>>`h?7>&?:C?.mA?>zJ>? z?>|>)b>*-e?9>U=&y>@H? @߿.>\>QZEY?>$c??(xf?u*>[>>J/B? Z>1JM>gd>;?0>\>b?(4 5?b>ȓ>z>.?RP'IaȨ?F?d5hml8mR?#>?>)?Q/>r~>>3 MUH??\>ӾOp7Hz???R?>>E>t?V >n/>>w>!>k%Y->>ү>5c >;=>E1>5>+lU?2jU>? Of>laP<>gI=kQ=,> $?;B>K?K]hpg=Zv?p?{1B(ds?8?T=*eQ1? ?dH,Jǿ@ ˾?3?J=m;mSo#~9o>U>Z=?W0(֮?A\?=ث K< [|;z(rLWX>\2sm]=w4>z;tY)>$Ut>$(>=Vſl6==ǟT`E{=$>o<%"-о7>_F>?4A#Ri> c?IPBZdэ?Mj?oއ >S Vh¾P=mR >7WO=t4lDdǽ\>{:@i'2VǾ7P?&Ή>V?:>10H+0= >Q?Nr5/pN\)X?3U>qAMSɬ?+>?KG5 ;X?7=l ǿB ;7=Z+Z>4?[Qg\>Q˿Rt:O=[ )Nf>N>{?SھbtΒ-^??:*;K)_5%G?X?7=Ώ:⹾5 >M4?U^rq?&=eK #V?ӿg<4C<@n>n|?N; C-Ž V? `IץYdŸ>pXwNl؜^.\>:!?&@Y]ռԆjrz0'<۾n𻿍+N(Cnj0%Bt`S[O?֑?k?2*o02R??:d?k Hkf?_#?=%8e/>"׽/ŋ?!;Gm> 0|ȿ>M3TtѮ<ñ? /w<\3c>0b.jADPS >{;uUb(>1Nǿ3|>zI>z.N->FVu!迉`Q> C*I\js;>7׾Ŀn Bt#x>LѿҿS<>:m,^o KWYy>i'W[> )^"Iw6kD>@|R>pmZE>~>o%_BKn7v¯>lP 6l>&势6Hγ>0ju>LM>`_?fɾ7M= C=4i)s0.`M>???] | ߀jB>j?O? <(tC9=嗾`R \ݩ=JzBGÜgH`0=XDоG+gQ?ێ>pB= ھXyYѿ,=O="BǓ?M=_Խ f?9gxk~t>M5>+9?QFow>k>M?Y{پfAj̾dG̼q\΁{T)?$Tz%cg0ߨ?Lv?>Ote?{?? ˯Őb:&?y?]?)] t>?Ef-"7?U?{? TX˩Žȅ ?,-? G>H>C?w:?;=ou?TL>?/>>i>l?UVUsT|>g+?,q?,>t>O?'? =بm-N_UH=rO?I[6z[?4YhnVG;A?9nH+4`1E>_?wgA.-^㿋J0 e5:=~hn2 ==_?H?Y>>}gKa=ܖ?)B?=ޗJِ~н3=FU6|῵x,> Vꅿ,NKbP.n>:Rgv:Ծ_>?yq+F*"/2u >C8Ƚt=pξ۫"$=JY>ؿ HV~󀿅N=O?~"Y17*??#?u@=w?O?Tv?-"n3J'k?_?D?!.,-R?4@i?G2Yψp?@?)񷽲f4Gq3}p 󛽠4>NAȿ"x}<`=U ?Yy?{=K=X-+Ο?9m?6&@ ?xQ$f!cпc࿁?-I9P"Z#}`R#}ݭSq[j@4[Օ_뿁a ) p_$*=??lbF|=?0v?pe>b $qf,=lґ>s??fD= JZ=~[Q)0)8R!`'j=G¿%ڌSW*==?r38?1Χ&3C>?IEZ>n>=*ؿUX<`Ü>Ež\hST0.Z>:Ӿ$-^нeV#:}?`v=w-^2UҀ6= ?>rWO%N&gZDLp-ୀSm~V<p"-變'sǂ\ss;}N7DIzxi[_w/?k ?Q~?;]x4?t?ɱd?D@>h Z=P [> ݇yK8Pv?Glڴ\ύۂ?iQ?ǭ?nVXq.?r?Mq?Y:[(?F[U5> ??R:;B1PAĞ#?#H>˸>_FP+=^ ;3l^-I+i>)rGTe?zү?d~?=9R<ҽag辫=>08^bܾhx1+c>)dc[#W-b?)> }0?R2Cl=RipF?F1 =~ 8 |?-1=n6Z+R>Q%`G?F,>p?/sLCk[%?L?i?T=$7¾J?>q?# ߱?>?'"co?J?nn>~Z?;!?KiD?v?erC#?>&? #?DEغ=qDk*c=?a1;f=遾ƾޤr|+? w>G>L04>6>8>#X.d> =`(_>J&"'U?H? R?POëA6?bD?.?y1#M?f?4q?}=.?wm3.j?yx0`uO3>E=T>=zHm$>p=^>z4վ\? >>cgھn>;G>h>ޚo/5>Ի>.F>azuPe _>>U^>fnT([n>M>l*>AhZ뾌ߋ>@!=}c>8*(߾l ?Y>?>(T?$?d \>?#[/LCiM?>ç?$s?TFN>S=>?H=\(>پM0L?=h >u> 9>~{b?">?$7xY?Ib>,?syHYɽI޾] >1='|>٧`ԾyO?t{$?K8?oǵh@ XJ>>'{>!>I@KoмVS>S}ps\5R]F0D=K]wu>J>o/ >HLuՑf>_G>H?@ﴨ<,XF+&fBp( 0=(ſR0f6y 3=Xx10 N{z=N8 A|N`;vHǿK*WPƽ^Dpy 4CaÝ^ `ľ2xsfy2/f?XX?'f>׺?rQ9? [>gM>?> ps;h?8*g?"?Rއ*"+qɿGAm+l<.I$>1A->\q24>UOmmSŽm($>W:;w}&ﳿM辏@%H= N%)># >hu@ [-=?3u~>יZGT>\f=ɏ̊>i>F|lh!0#<Ծ]vӄ=p[=$_)Կ= ??~j'>c|PȊ=o<` ?%.T>=~($|p>?|۽̧=gA|>ed0=q潙>p> o=bEQv=z쩽ڃ>>+H?Rp+x5>Hl? B;b~lR=%߾DTQ"=,(X;{m# >dȽ V =qO>rּi?˿ffU >)4J>f>pkW=:=K>Iw?2 ?"dͣ?>dc=/># X?ĘkK?t?ik\}R?/(nWNo/>OW+?~V`|W]>]ﻀ0޾>TKG?=)EZ;>- g0?uS8о+?X?$?ѽذK?D?m"? .1:=r&[fs>m jQ|_>%$[ ?.`'%:>F2=Ke#>4O<{egr>:ݾpc>f>;?(,̽O=BW>õˁ=/>!x<O>\m\>*> ?D,dX>l??j?K?D߽΋=?8>s/_?=OI>Tq<ҶO>-">=?V8jb?/?\0Cʆv2>_>d?y1GV>.!?)?Tf!7=_?*4>kݐ?Az?p??ʾc?a>'?Vo^ Ѧ?b ?Toz? M!?C?2? 7>?1? ?]Ҁ,q>Z?!t>?*/aO>^2?9(0?h?Hn4aF!}?'> t?bnL羝>-E>p?!dޠgB> žS>d=IYR7vy>I_P<z{{)?b~]_0O=ʬVU?_-?1\}>U2}?"c)ˀ`2>xνM?;?>B+=v > O? g~y%>FG݇؄>lb?߿E$?IE>ڴu>XXl>[-{m>!f>7bHL=g{?+*і)->8=?o>$c\>x$m>b%ԩH>i~?0 >>'?yol>.>?=D5?e .>㾺ֿ{>sT?)=8?o?(z>+?œ->k>>->.:?|DMLQ>ELM> >;Z!<>p\>M#f>6D > c>2 >7*Ra0^TO? }AS_'/8yľJ0?΁%x:GB>e=]x?w26`G^s>k/=?H 2s<>U?:?Rs?(H1%a>J=o?u ?3Dd >'B>>>&?Hd>AQ"=^sHu<> M->Q h@q.=+4;NW?$Th=(>EW]ί>aFw&*(=(>P<ѽ?F俒B>0W{? v>?㿃?8Po2=~N=[|?Aw=Xw؝I>y= 쳾|u >8EXK>Rᾥ?&=q5S=/>z<_˜?,90U=0>=+?y!%]r\[">[nP[ V>TxXY>6"x> dc=}Ϳ5>$1KT.=k=b<Ҫ?55OP>,RcN >ALN=,kn#X>R*TPhF>"s=s.??8.[B?vTj)>rj?E,ovd?*!B>'T-h?VicD>ga&?k=Q ?K\@Z>Hs!?<8Ag=폴L!>i&>!uN>!6 ?_-/x <.n%>lU +<&c92>sZg?6>i Խhw?hx4k5>=hW?LHZhY>:1>Օ>F,4>F?tD<|?FR =Wd~?"fpa>K+l3iw>ZyQ:EɣDў>x``>hTG>at?i?im\#?H]?RG?ֈ?­?f}彇6 aF>Y<"E$Ⱦ R>.;1  :="*0 >TZt o?\v",>4 ?JOֺ?|t=Xu?ea}с?̣> d?{lԀщQypI 9? )d'a>!>?:4>A=L5?Z(<(̭>w'?>N?B$>?P*s*>?>o? V?_~>rf?"uѕpqz>6 9΅S?5G<]=`$=`?a6WFR¼Q>B=c?HR@F=3$6?&6P2>!> ?ޞ[=]ʾƽ?fdUPYֽV?:->vB?&('v>a?70@>*?J*$=Σ>.Q??n'>h=]0\d?h?uXo?xdWB?Y,?P8?$?cz?`#= /?mݼl=\L@1 IZ{?`==I+ 8?/VTv",=υ %b9?as`¹A=Dz0Ŀ|2><~y>Oa=?>}>=CF_?{0b- ?>?߱K!?(lELt>V3}K?$%L=b ?v |4龀 >^,ܻ?k^iIhi+>A=ƣ?0!?<?w6n?z5 L`i>ʊ=?&v^ =0s1?a[ɪ=iEtH|t> Sɾ1=up~?L'xJ羃_>P>:տ?4\]>qt:4D?[@hJB)>{<4?=axg>~%Z?abɫ?A1w6%=Zk?_ZH%w<5 ?({t}(?`þ=%>!=ʎ?m2K>?̧~½U>h#̼? /7>?V>},?!FS?(>?CQ=Lu>1r0?/zڐ?ҿ@s?:-ྒྷ" \?$3(>]3Wӿ/>=_L%ѰG?IgbPQ3?O]b ~ ,ی>ʿyg-f$/)?_r"_sk¿!?G`M?TTh?O?p Ab ?q ?-v]d0? I*^_y^D"c>llhM/^?.g:]$ҽuXF?Ï?`T?+pU;=m >>m?Dt^61,>)J?LIi8޾$wvžs?d]gP|;*? Lejai0e=vR7$8\>'BG8, _? 3/?d?8>?=TIإ>`R?>S?*dq%K>aq\>?? 8&le?}?oF?˟5! x>? XC?ga2K> =j?iY&Z ']J/?.q"RT{4Ѿ.H?1$|j$KӾh?ǤP p g\"?U>4Pmݾ}R?nz Bh?lC>!PUuQM?q8 &dV}?1?#w:)+c>FtK>? s??Xud3? 9>?? Gdk!w???n7Dd¾|1?[? J,?pˌ뾎V:B?_?{=ڈ̨ʾѳ>V>W?&Bv$l> )=?F(ςq>z>u0?8P¾>cme>0m?mQ 4==0h?-ΠD5:??A4?5 ?G(g] H> MI3Nw?m,`2 X>Iz%=;??OO`7VŹq2?x?F?X?Q?vb~ >ې=?Zbxƒ_4i9뾑Y>.O/;(>q=a?q(|K=qT>;>7?gKL=A?>?G#=ܽ5?Yv>Ц?Z~U܏?5??6^ u y?H??%??]]v6 ;xF?^ֽD>=,?UŤ֨Z ;E@$? 6?|=du?D?@ r>)>YjL4+?SF 뾦@B?H?\=G>=^h >c?'q?F?3ݾ$>蝌?S?rMQ~{??r?7~Qq>?D;?l, >?k,}0U<6>J=?G]x.xS=)>>w?iC(c?K>T>>֝?8'T>[?'g?h?`˾gӳ>f?OZE=9?V`?Y\?NnY dX>ك>?oDVo>U->W?cp>uݛO>L!>4?8?l?8Ia:c[gǾ羐g>Mґ >ʽ~1v>"W>e{о>nϬ'>q==;?'h{>.lӾc7=ٱ10N>74ξY > , >P>?2> Ԕ/;+>= 6>;6z11R>1?RsP>9֫>dŗSz=2 x>c#>(x>͉ϽR? M@T>>>e|>)=8H]=$>'ĠEsd|^Af>Yҿ ?QH~> +R>MU>z>/њ_CMiɌ]tP>}H>"r>/EgCH>>?D~yf">׾>@[:>cb=k+"1>ru? 2>?}>㕣?OjNhM>,Կ2d(_5=jʾ'4>f > >̼?*K=>? W`3-= 潹,K>Wգ=iH%J>Qd>R 6ٿٿIUMy-d>+5n6ɸ_ 6{ !>ͿH@hN^>pVg>ޯ Ͼd˿bq">O١QPƻjZs>]SczZGSC>E>?{0/{}l<2CGJs_O; <>?ʧ>sˈP갾&?2~1?@>w* =YCRΉy>*>gX}(y>)*[>ucp$#>Z>Y:b2I>q08?dc^3{j H$(]> ?yVuFM?Cy?ɿ>mqKm>y?QV#>Oa>z6Rѷh R#, > (?@L 60> TZ>%{ڃTDgG T= ?ab]G>l?ӽ޵a] Fᦾe,>9?h#>Ï_">>j ڿ2?$vZ:>2vuN/ZgA? aK{>B-ڡ׿B| r)>!h?a~p"=ć>\SK'o=u,>hQ쿚% o=T|i= 0y>4%?`p35q/>-&3=տ}-KJEU]ټ끽gsR,=x¿Ua>ВTP=Y޿m&Az:?)Wq>3_&_:6c_>y>6u)JBi0_ۧ󡾰TiU;{{0˾AtǾh2m"?kǾY$gpO 7ޜ ׼/蠸ξ+ؾS#>-a={>Cˡ+pU>7zpԾ.s;>P!q{S=˰˟IT J|p<+;ny VrpX|M r`P/Km۾%l?&l8<꿜1:T>^B=b9|^d=^>?:3>l>p"XuSN7 5={uˍax)7==̿ #n?+=jOʿ"a(%h4כ9*=@rx>,:9-5A?e.K>c?+G_M=&U;i>Yf?5HGL\c>)@%ۿKyޅ[F '>#4>,mWfIwӇ5_)>;=kv>h̿b!ޤ%>?5?-ֿ >i\>Ɩ?V7 q(>;ο@4'N~z>Fi-ߨ뾗zN>sI/6 xX6eפ>??)nz!Z$d>^҉>s>Toy{Ӎ)=s~=}0=[A- -=]^J>8u>( ?F=O==;>VZ>?*o?0q&9PW> "?.?CRv001<I؄@?,?cDb⺾ |>?Cٿ9v h\ݾd*J䮾]_TFzm>a]ֿOˣ/ӕ>yxտ87+SPI>5j><)|@8z-?5~?!U:Tھ>>@B?EH/or`>لYaL~fyپ/뎾vN>=<>w9*kqɿ^K>tjX=R(1&>Rb>h<)r) fʴ=>?>I& ͬϾ8=y>>+fDU*ːl>?qrr /<??^;BOv ݽ=xͿoF˗8߿ ˒>>wwOT_#= >r뿕ckK*ѾU>?H?*,`RLǼnG>><8]lX#'7k>g?;OCe`ʳq㾂h< <҆ O տuu_Rܳ+*(=Ŕ)T2Y1e9ɸȊ=rM&+$Q]H=>{̿/>^?HR?hjnt\;Nk<>?|-~RTklJ=-=@x>5DA;?>EĿ膾4=py]O:@+=&:IY^3 =q㨾Q>Q"Լ <ˁs^e -5}?2?uaþ{h1$"->ȣ?M' Y\Օ<׌uPטЛHSĽk bgRX=fDu!`^6OM=Lm<>F}u}> ߿FͿ^1==ߠd_y;<=e.MN7Y2;qv/>3,"G=d q.0*Ϡb>'/ A30Qƾ.n">HûPQ'$)DU>='ֿͭzh?4qP?FVg'?:n?juN4= I\xU0IID=ԙ缽]q>wO-mYخXT>xEVڌ>E&پADO>od4㾐!>>v?WK>[>Ɂ>>es>[hp&Yc>х>7܃#Mշ?o?rКI/=Q]=;=O>~Į/?~v >%(>R:x)%?fp>Se>QlծS?TC]=0lDMjEF>z"p;>?%w3zx3<2ƾϿGܾMOj@F ԿH얾 3.M򽬀As=8?t9=֕>S0YY˾}SnG}?p5Tl¾x~þ2<?mIR>v>m?iؿ4=3=<*9?|↓q=j#=$᾵M4Lz@0侣PnBIᄇL09X׿~|Β >Z^`KP+ q>澭+9/3<'ch20S=E@UFg*>W -5/=qoDV"%;]W~T40e6fw]G=Φ¿+X꯿<@X=AedQ>bTE=MIRy/>\@ݘſi꿬l ֿJ6>ݾ4PDB,>)P2xT> ʟk۾|?>^=!0ٿ澌? _$>[Kƿ#\$ʛ>W< d*K=>s.X@h>vI=Ԇjak:>M=ASX(I9Y$V>Hrnҿ2]0, T Ծ2#<;qb$ ޾H?]kv>?G,o0?L&>0>?$^h>)Zeʿ+t'?7Ŀ>faտTO?Co >WLm(ӿ SV?P>>=S v<>Fz>߽U21 ?,^?K@?e:€(?L >>n>ڿ=m\=꾓˾1y?'矿=>+A] >흻=>O>~ <}(?8h>bԑ< ̾p)=?"_>q<2},0 ?8> =]վ?\Ϳ>L܇=R"⾺G$??>_خx?L> !Lj?X>7<\Nl7@ 0>p _7?W<=>sᇿ;&?/>s>H?ה!?\FZ>U>ܠSh?n >=>)ԕ!?~-8>C5`nR?U*>E`=G>0ЫO?q~ c>>? )(P?Ğ>Z?'?&(an a>>XL>ޔ?$q???x3*нO>p$?.?1ݾo}u?}_ E=?J? VE?nz>^>I>Ѿ)&Ax???>'V]S??>ygj羆%?Ib?>ʻ?₿I>P^8>Zy=?}ŧ~>1>!`?wh??R>%^?,Mf?~J@LϾ+%>? /Pp0??Ou~/f_?j7&?8m>wke#1> 8>}(cpX>?Nf?H*UG>>.>/- ,L?8.?ܩ>P7Jfi>,? : NsaVڿ ♕>?K$?_g?>>+ݺsDV>I>Ɏ>=y>Jw}>3>F?DC=2_f˿" s.1>Ri*Rc>mν辔,0_Y>@:2>'X:BlMot~2=C0~п‡K>A^tDm8l*!?p?=Ҿ2=?? < e= ?/K?>C9\4>?8" pd@99?>5&Aߨ==ݱ߾ѝg~ xAྀ̾eR>4>;9^} >R>p=J<'9>u≠üA9*?rubss*6K[i p>/,(v\Vt.>8ol E?`?¾`=u?h?co>B>~%? >Xҥ>4 >QȽIN.l>b>ǖJ𾋟n7>O>+?f4KN ʬGR>}_#f͏ZEg<=v?2R&CJI8!K?R8:?>P ><ڽpd(F⪟Vijc?a0?mP"YxH*K˿{DyZy秿z`p(=s"J/=gs?DzULRD?x+?oy߽Nd^=&x>EDBrqM<==jn0>=ҟI>:=ăM=IAJ>:m<⵾ 6]SUԺ>ܾ?qDlvGfܽ*N>m9?j{f0AUH=Yھd[@!Qs=ڍ?}:@_R?f?̡Z>g_j]f]KUx `־1⛿&}}Y f;}S3\X<ʡJobtMg<@.R+VS7'Y>v{?qK]Z G>A?O*WdZ=l? ? [=Y=?(h?i>T k%y4|t>?ν`/ƧE=?Rq?V%j'>@wG> 7H5?Aw*>R> !ܾ={>PbԾX! =Qlۿ"[ٿT 5ܥ=u=`$$>%?&?Sr=:2#~=?H*? >;T㾃p&? ?=0pvu̍ei<^տ66Z|>'BD_*3-YέV\a?v\O?Q>#[<pҾO>4?Bp,+27oʸQST,? X:@v>2DU㗿l̿'jv>Gm/俁C=f? |?ғ?NO{>Lf-_8@ھb ;c~&1> $;J=K 7׀M$N$˦l??߆U?5l"?_z?>|E]*=ϴ-LPiym﷿lU4ѠܾE{B-%5l WY=&\3CCgj8{>!?? ?6d=8{>w???D8鎻jlJ,g>A-=IsOu!>(e=KA 7qr)_$M)}> B꾠6 BM!+^>,=Vuo >YM>/=33z)FͿBZWXcIL<>s?T=u6@6D_z:> .2&}>ѽJ!!_+nF `9)WK-b_6zR0tJm۾&[!E-`@L>2K 5XPvj >tQli`S<~=OS?%G|1$?I\Bd>蹱5; ?\l=$5?NW? >x>(Aо~$!:>s/׾9u羸, 0Fg>=s1߾~9$XGg7?D]n?GO?D'oN!?3?wQL.#&??vGõ>>B$>z?Ad?A+]> Ɋ"L޼:?'(A>O>QKZ=0>L8?=)i> Ƶ=m9Te=iȆ?%+=7rKYXT?/4>\=l̾;vMU?c]?)?o1 WI:?b[u?* ?qbap?!M>?A]?`DX?G.?2N9(?S2? ?E+X;9>b>+b>B4?u9dypxn[ȿ#9h jQ'Yw \Ť>ֶ>큽y>=j oe>,&/j#Q=sb:>T#S*coFyg>e>H>HKe>>: 0<"?b$1=۾&t=7JS־P뒾ffG!D[屎>7>NM>"ē?$Q]>\=i>úo=%V Ƿ=I Q>>Ԁ=?ԍaS!??><2> _?'>I3@j) J ={ySǨ>'9d PS>_-q? aQԾ,=øT8` FYg=\T*>=1Ѿ>_r' 'i=}=e?=^^Hp Qg^>O*=X澝yl>B ŭu`[ )|< `?{aKbÿ~^I5b>0:IJjD?9/?+^?eժGK>@>Ω?,mɗ8>$=ecg>%`Pmʾ'vƚN>@j 1IA~ɭ>(Rȣ>f=~rz>D~ݾ~G;>TUX ˾2>(b*,? @8~\*̻4"&.@>{t?9K <0s >xGμp.>hH.Us>|x?= 7 Q>Ih *%7>kY>>,MD= m;?'9>M?Tq[E>~9>q>;ڔ?-I ?}7?s??PJ??^}?MF?wJPBW>>h0?2k˜@g8:T> ݺ'7>Q'?ھz9=!ݠ>G(@׾&?>"`?,?~mO?\C?J][?Kj~p??/E?*?m>F=jf> =)V> ^>u1"K?7mexN%>9`|?&]cJ >nL@n8?C?d?.n?9b`0>Ĝ>[?HT=[6?u,|?Z^?b83<`? ">?^yW?a?>k3?]e8hγ-,=UO1?5H}UPyW='=LTz>[O_h` >/1?1NKxZھ>2>}:C?`kܾ~=ƾ<^? LNS =E?>.}W>*$> ,?,>|>Q>mp罡;?"%eS?NS?:?硔=C??wG?l;??wp?$fqy#}ڷ>lkT: >vO?%/RK?3?U@ts>&>& =>??"?!>+>* ?).?1&|#>*>2r?|˚ ]>X>g?;^y>n?;|?Ï?+>Ala??s~?=?&? o?-,!]NHbxmc>?wF =1>3}? ѳʻ^Ⱦ uʰ>t!}bp.ʪ0>\?:$Gϩi>>0V??u7_阾q;??:>g?7ʿ3?A4?:r?d䓾>>?0܌d>Fo>?:>:?O 1DQiesw\v v>&#V:H>=]9?eg ӽ;]>gLH?Qe >l>?l@@R"r>'\Ѿ:m?)Uaf +>ǂM?1? ?~wD_=%I0-rUM\f`aa9ܾp3M>qs?Ũ???cؿF?Ta?D ϐCmc>>:?0?n>EzeQ>u?}??s*аmL4>X>?Kk]fؽJ>k>?:>6"? >2?rhПf0?>C?eәag>>a>Y%?-0X 5:~>Q=?@V\j=գ>}&>j?%[yY>HAh. (>௣?_ރ5>IY>L+?Z^{>qx>orh2C>>8L>z?%Жx>*?1>y?wbbpӉ>'>ɬ>;.?HݵP`= N/>^N0h;E>=?n 0^G?->??c&> ž:(K=Ջb!>a>(>'$?ߤ(c>@rK>J彽L$?R&}> D>Yh<γW?cT>&Wu> =K?rx"t"=?%-~A!5CK>y}Pٰ;BPre&1>w>>>f>&$Zu>n"!K>l>+y&R>f-T='N>>.?]7S>rd?Naq,(= ؾ/?#?1H= >-|٣?7$k?#BW>i۽?@Xh=4;,?|=!h=13?;u'B?UAXZí?>j?\7OOs?>fE?j;!Rz?&][>?T =`2侄L8>J=?:>?ƽ'>Vυu?Mu"Z>N=?c#=RH%[?:1@Ҫ֋ca==s? *c6=pʽو? dvֈ~ul>##y -c>W`o=K+><-?'@9?-Ydy٥=|eǿU->"t3>4>->>Y?>?AS>/q? >z?3׿D]B?P.E?Mk=ڮm[ѿl`=1l ľTP6N>xZk>,HN>qj<<>G>->?k,o؈<)ɓ'>{la>O>Y@~4<@n$5O?SSFz<~G.GVa<4>i?M=C>?3uOc>˻?8 >h?e> >8=, o?1q>H>=&?V.#֠&p&Ŀ>IR׷̻M1w[׾>[P>G?>]l?~>9z^($ I>8ypf[u!<զo?>\n4aEU݃LJ>?+=?? >b? SwC?"̴:> o} _>` *&">8!>5q ?[uS>2;\Ur?9-t%>I۽>?,俘?x?QP?XC?WհeMOwO>4qժW2>U;>wIk?5ģy>>?D£Ջ V>΋;>T?˹W?13<??9=H?¤v{ ?`R?秺=|= F?ko>(ɽ?<) [A>$R? U?h<?%~m {>?5\W,naJ v?KdIZ%5=4/}-E?F}x}I>Y>,<\?D@Q> =HX?Qni,?UV?UX?yQ??Iv<,?AԾe>H> i?Emn>b:*E$?j{UV>?cnr;?3\?'B??33M?B?$]_?L@`=eg#?nID/(OG>eb=pJ?:3$7H>+=? &>N??a;J>A?$[ӟ4>[|5ē?{g=l?bWfdP.1=2#>Xs?U6<>< =>ԁ=YM?s=W& ez*?Jh2\>q"p?[ |=5 A?rF澘Q>=Kw?'6 T`qe>Ž?+ (J2]?>n7?2 ;??>\?jH[Xm>z[__?83j<" ?隿pdNӾ0* ?N>iʼI? ]?)xҾF>es<ݽ7P?,ŇI.<h?;# _m<<?Q^M=>7&?tޠ HS/EG?!>>s-?n .⏟]g(*ϼŀ=??2'W1%|>ݷ?5?>y% >x>X?$b ?q!9=3r>?&|9?!V&񷿣5?OOr?? ƈ>~>c?s.ξ<=pe?{]\ɱ@%=YW?|Hǹ־s ?i0[vQF_h@?<.ZpT=^do?+~b:chO,ZT???8UڽI齿4 ?@ ܽ0FA?glz?(1f>{B>?-e?` t^\_@x?/I bbHTŹ=mc=?;?B~=F>E?I]?bN?96=??k?apR\(6g0证V+?FhBh=ʾ.i%?+40>9~>fot?>DL=?sF?t`?_`Se8&>[A:>H(=?mSP6ܳ=/?SW?3 hv6z?9^?-5?\~=y=*\?sF;`=hQ>,>-v?N>Tmr=l?i?(?r'e <:? ?C?'@=㛾aؾ'>@-(?Ǜ?^@ ?H>bj?.I?q?E*Ǔ=ܵ>%=U?g~=?f?=?} (Tl=a;A:BxK?cA'F=S?C>&?+[h :7i>KL> ?5X^iY>ۥ>0?M>%? ?ו@)p>S??@?! l>G>>'?zQ B:>{ R>݈]>Ϻ#?q;y8@>~>{z>^?W BRC>f>>?y> >m?O5?ƿ>u>>?{E|?'?u꾝w>&>?SI?FD~UT>Q?' ?O?`ԙ ->VE>Q ?>~t?sd>rx>=X=>>Çe>}A>?(>@|Ƌ=7?jD?|?T?&(??m?WX?&ZP?_!?cC?&\->>/z>R?BoV@xf>yy?Jf?D?:ҿ X>?0?w@?Cf9';>*$?#R>=Y>s?LU>zbmwAe>ÇFaRT`OM>bFL^T.P>'`X0,F<4?"Y>ީ? '?!?W0< >X>>?`??mxO?ߵ?m0S2{>pr>u>J?=DHL9ϙ r<q;ZbF"Pվ@u?U`K( ^پ{ejЁ>Z2H a>d1>U]>>9;#!U>bU"CX8]4*`9=㾳qۥ.1=/=bdض0h.m=nK'5 ^h[>jM[=_zl-(]L(Qi~8>vT8>U7>P?DvEY>>'j>)=[O!D,.=>#>,ґ h;;*z(p>p d^>džzN8Ьs>_>+V<)+R{>=X>,j-oJĺ=% ?^_cͣOm=U y>WyK[CqB>@:t&O F?4V?j>}I+t;p;2Hs> 0=ʴ>1=I?`GX>?>©>:?2G x(>/خ>=[{? sy]+>S("F?#P2 ٯ(w%>dI=?+@'b198>>a?D91t==oW>Ԍ yW*>-=׽>!4s>k8?JP>! 56>OifV?~5?JfFSCfcNruPT=Hc#>u0{D̿Uv?%Q/> zeClW0?>0(_Z2?cT3*aAc*=bt>ח_:i>"#MH?xLÏ7p3=ǨC/4xS>tbXҦp>ZJ.U}_->> ,g?'f0:Op$~L?>uj?zHB,Ax?0c1n??]>)E~̿Q0?'Z1>3~o俤JsvV}V=T1 |>ۿ~~Mr>KUi)>T쿉>>=AW;濤4o>>&|>⿃j[ >ྻı#J\>@k:* |x>݋J> +6K* ޾W :&y~U쾉=+?fབF2>(?G|S>;^5z LX?+zV>,Qۿ[ fT>S=HISHTtCDȂhP>-)?JǿVp .l=ھ)+=>ϼ[B/ew1߇x t=l+&ƈKXrY5;daԿ5O'!K\`n39(~'c t=V|ľ&+/)->22 ,Yen^-=k)V\)<@-*x񽴺R.S=ezq7/R=3,(vG1AQ ]?0?.|R9'Ơ? ?7"YyDSp 9> ^=F>3:+5Է(r>$Y;MϿ^lҞG??(ͧ?;C[{u?J?q "| .t>*? `($>kK(1?w\*E ʵAc?!7?x c*Ҿxɾ@/0= hч,ǿZg2?2?rWTz?0G?"X.@e_)_`.ؼޙ>AT=:yR ֶh'cő>y>cZɿ;۟,0]ڌ!8z|988q%ÿ{9Kj#:PL;Y>]ּ&`D%}l/>K9?y|x Ӿҍ#!lw>æ>hbO;#o澕=5Q>ο:c"u/W= ?6AP49eh$տd+`WR?ANӿ<6۾~Zc~!M=c2뢾SK^.!1#we䤾*Nn tžhB}N܏uXZվFk,ǜbcؾVzX`UJe?_]NB07Hv}a`>BLCԾ{T5 ;;"WqS#M[P]6[(Z jFR`ݿ8ĿLW: `'Ὂ◾}~\c(Z<2:`=`"OV#⾭;ز[澞:ĹN>=UaJpʿ[ pޏTn EQ&\-=t>Jl;AT|29BG_NU&K>= 3H$gh'޿Y%(om+Oྜs"a0=!r29A=%KM>S|17> 5ɧavdR>o>'ew8\0M>F}xwbؿ_QPU<{˿%蒾vg?NA-ӜJÿ9؄⨿f<b>mpE5١ ((>q4=6z>Ԅ}銾M龇^=Z8`qC=}|>i ;? =Љ013~c~k=ДS־Gھs?R=KŤ.5>lV!>\,yoCMkZ>N;K3rҾ?GЍA0#"ݿ,nܿr?Ͳr;8K ̿ԿVjj4sI<1ܼ,3\Cxkg^tǿ9od STɸ}5\:'cÿ%ſ6$龾,wVY7KS+>0YhǾ3r`Wk>-c-۶?)G|u)=Ӻ.k=?ֿ5=◾`>bؾ!<ަ>0=#(*{ =c٩=[8>Pv@u{`^J7>*=© >CQ=dV~_W _~=>AJM;K>e>kϿ p=0>a5bj>"'<Ϟp)?y->r=e4I(?Je =>V*=Bq}aRn>)H7;?K_-q>,>W ȿx?ſ>>6Y$X! ;.H$)ῆQّ Ƌ<%J= O>wyo;> PT>ؽ|,AfYX=+0-Yi¿\Bx=MUp$o&%"@S=xh,=gV?ӿa>Zq(F1&wO?cQ&$a>c~g$1_?ү>K¾$atR{]?~0>J"M`?x-ˣ>8?ik? r>nsؙ6k?)g>a~=:˾6т#@6~J>O=gnse4? >>#>`p}? J>Nk!y=Ll֡@[>yMrF<%ֿx@1¿?=d>O',A>eߤ>J>I=?N-۾=ԥ>P>?տw=H>tkj>q>nmנܼG>M4>d>z=4!:>Y>ᰫ6~}/=>Hw'?>ۧv? ??? ?5:?*?p $F>|?&!?v?YоQ>U>?))%vqeAῸ}.=lD^A_dQ;?DD?iK=u|'9=a >)Ld"LRn=FV&Y'1UqN=F]sK~=`>qN >Z9 a>[kn? VR>b?>NU4jj=[ˣ>zc (p?޾TD_ =O_G+w ?8?Xt:pAXY7>B>)9m!>Ttm>Tq>ʒ+qCYA=A%[K]'=\R*g=!=uCM]C>q2>sؾ>r } >r> >4aH|C.>IJ ?[?~J>_|7?aF=2?v %?>v?u)>}?4?=6$@'p,>>ۓhH@|<- =>G1{>!^ >lL>mWT~>om>%jv:x%}Al>zl>F>Q?-\k+>}>+Jk[>